mirror of
https://github.com/86Box/86Box.git
synced 2026-02-23 09:58:19 -07:00
Merge branch 'master' into feature/mtrr
This commit is contained in:
90
.ci/AppImageBuilder.yml
Normal file
90
.ci/AppImageBuilder.yml
Normal file
@@ -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, <richardg867@gmail.com>
|
||||
#
|
||||
# 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
|
||||
335
.ci/Jenkinsfile
vendored
Normal file
335
.ci/Jenkinsfile
vendored
Normal file
@@ -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, <richardg867@gmail.com>
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1085
.ci/build.sh
Normal file
1085
.ci/build.sh
Normal file
File diff suppressed because it is too large
Load Diff
10
.ci/dependencies_macports.txt
Normal file
10
.ci/dependencies_macports.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
cmake
|
||||
pkgconfig
|
||||
ninja
|
||||
freetype
|
||||
libsdl2
|
||||
libpng
|
||||
FAudio
|
||||
rtmidi
|
||||
qt5
|
||||
wget
|
||||
24
.ci/dependencies_msys.txt
Normal file
24
.ci/dependencies_msys.txt
Normal file
@@ -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
|
||||
160
.ci/static2dll.sh
Normal file
160
.ci/static2dll.sh
Normal file
@@ -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, <richardg867@gmail.com>
|
||||
#
|
||||
# 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
|
||||
18
.clang-format
Normal file
18
.clang-format
Normal file
@@ -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
|
||||
38
.editorconfig
Normal file
38
.editorconfig
Normal file
@@ -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
|
||||
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -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!
|
||||
|
||||
3
.github/ISSUE_TEMPLATE/config.yml
vendored
3
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -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.
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -2,7 +2,7 @@
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: feature request
|
||||
labels: feature
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
2
.github/funding.yml
vendored
Normal file
2
.github/funding.yml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
patreon: 86box
|
||||
custom: ["https://paypal.me/86Box"]
|
||||
14
.github/pull_request_template.md
vendored
Normal file
14
.github/pull_request_template.md
vendored
Normal file
@@ -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._
|
||||
58
.github/workflows/c-cpp.yml
vendored
Normal file
58
.github/workflows/c-cpp.yml
vendored
Normal file
@@ -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
|
||||
291
.github/workflows/cmake.yml
vendored
Normal file
291
.github/workflows/cmake.yml
vendored
Normal file
@@ -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/**
|
||||
51
.gitignore
vendored
51
.gitignore
vendored
@@ -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
|
||||
|
||||
10
AUTHORS
10
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.
|
||||
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.
|
||||
|
||||
201
CMakeLists.txt
Normal file
201
CMakeLists.txt
Normal file
@@ -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, <hrdlickadavid@outlook.com>
|
||||
#
|
||||
# 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$<$<CONFIG:Debug>: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$<$<CONFIG:Debug>:Debug>DLL")
|
||||
set(STATIC_BUILD ON)
|
||||
elseif()
|
||||
# Regular triplet, use dynamic linking
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>: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("$<$<CONFIG:Debug>: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)
|
||||
45
CMakePresets.json
Normal file
45
CMakePresets.json
Normal file
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
73
README.md
73
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.
|
||||
[](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.
|
||||
|
||||
[](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)
|
||||
|
||||
[](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.
|
||||
[](https://kiwiirc.com/client/irc.ringoflightning.net/?nick=86box|?#86Box)
|
||||
|
||||
| Regular | Debug | Optimized | Experimental |
|
||||
|:-------:|:-----:|:---------:|:------------:|
|
||||
|[](http://ci.86box.net/job/86Box)|[](http://ci.86box.net/job/86Box-Debug)|[](http://ci.86box.net/job/86Box-Optimized)|[](http://ci.86box.net/job/86Box-Dev)
|
||||
[](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.
|
||||
|
||||
75
bumpversion.sh
Normal file
75
bumpversion.sh
Normal file
@@ -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, <richardg867@gmail.com>
|
||||
#
|
||||
# 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/(<release version=")[^"]+(" date=")[^"]+/\1'"$newversion"'\2'"$(date +%Y-%m-%d)"'/'
|
||||
20
cmake/flags-gcc-aarch64.cmake
Normal file
20
cmake/flags-gcc-aarch64.cmake
Normal file
@@ -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 AArch64 (ARM64) targets.
|
||||
#
|
||||
# Authors: David Hrdlička, <hrdlickadavid@outlook.com>
|
||||
#
|
||||
# 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)
|
||||
20
cmake/flags-gcc-armv7.cmake
Normal file
20
cmake/flags-gcc-armv7.cmake
Normal file
@@ -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, <hrdlickadavid@outlook.com>
|
||||
#
|
||||
# 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)
|
||||
20
cmake/flags-gcc-i686.cmake
Normal file
20
cmake/flags-gcc-i686.cmake
Normal file
@@ -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, <hrdlickadavid@outlook.com>
|
||||
#
|
||||
# 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)
|
||||
20
cmake/flags-gcc-x86_64.cmake
Normal file
20
cmake/flags-gcc-x86_64.cmake
Normal file
@@ -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, <hrdlickadavid@outlook.com>
|
||||
#
|
||||
# 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)
|
||||
35
cmake/flags-gcc.cmake
Normal file
35
cmake/flags-gcc.cmake
Normal file
@@ -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, <hrdlickadavid@outlook.com>
|
||||
#
|
||||
# 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()
|
||||
22
cmake/llvm-macos-aarch64.cmake
Normal file
22
cmake/llvm-macos-aarch64.cmake
Normal file
@@ -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, <hrdlickadavid@outlook.com>
|
||||
# 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)
|
||||
30
cmake/llvm-win32-aarch64.cmake
Normal file
30
cmake/llvm-win32-aarch64.cmake
Normal file
@@ -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, <hrdlickadavid@outlook.com>
|
||||
#
|
||||
# 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?
|
||||
30
cmake/llvm-win32-i686.cmake
Normal file
30
cmake/llvm-win32-i686.cmake
Normal file
@@ -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, <hrdlickadavid@outlook.com>
|
||||
#
|
||||
# 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?
|
||||
30
cmake/llvm-win32-x86_64.cmake
Normal file
30
cmake/llvm-win32-x86_64.cmake
Normal file
@@ -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, <hrdlickadavid@outlook.com>
|
||||
#
|
||||
# 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?
|
||||
@@ -1 +0,0 @@
|
||||
This directory contains 86Box documentation.
|
||||
38
doc/build.md
38
doc/build.md
@@ -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.
|
||||
1383
src/86box.c
Normal file
1383
src/86box.c
Normal file
File diff suppressed because it is too large
Load Diff
209
src/CMakeLists.txt
Normal file
209
src/CMakeLists.txt
Normal file
@@ -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, <hrdlickadavid@outlook.com>
|
||||
# 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}/$<TARGET_FILE_NAME:86Box>\" \"\" \"\")"
|
||||
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 $<TARGET_PDB_FILE:86Box>
|
||||
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 "$<TARGET_FILE_DIR:86Box>/$<TARGET_FILE_BASE_NAME:86Box>.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()
|
||||
@@ -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
|
||||
|
||||
1326
src/acpi.c
1326
src/acpi.c
File diff suppressed because it is too large
Load Diff
76
src/apm.c
76
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
|
||||
};
|
||||
|
||||
27
src/arch_detect.c
Normal file
27
src/arch_detect.c
Normal file
@@ -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, <hrdlickadavid@outlook.com>
|
||||
*
|
||||
* 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
|
||||
16
src/cdrom/CMakeLists.txt
Normal file
16
src/cdrom/CMakeLists.txt
Normal file
@@ -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, <hrdlickadavid@outlook.com>
|
||||
#
|
||||
# Copyright 2020,2021 David Hrdlička.
|
||||
#
|
||||
|
||||
add_library(cdrom OBJECT cdrom.c cdrom_image_backend.c cdrom_image.c)
|
||||
1189
src/cdrom/cdrom.c
1189
src/cdrom/cdrom.c
File diff suppressed because it is too large
Load Diff
@@ -8,8 +8,6 @@
|
||||
*
|
||||
* CD-ROM image support.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Author: RichardG867,
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* bit,
|
||||
@@ -18,9 +16,6 @@
|
||||
* Copyright 2015-2019 Miran Grca.
|
||||
* Copyright 2017-2019 bit.
|
||||
*/
|
||||
#define __USE_LARGEFILE64
|
||||
#define _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
411
src/chipset/82c100.c
Normal file
411
src/chipset/82c100.c
Normal file
@@ -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, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2021 Miran Grca.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#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
|
||||
};
|
||||
26
src/chipset/CMakeLists.txt
Normal file
26
src/chipset/CMakeLists.txt
Normal file
@@ -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, <hrdlickadavid@outlook.com>
|
||||
#
|
||||
# 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()
|
||||
@@ -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, <http://pcem-emulator.co.uk/>
|
||||
* Tiseno100
|
||||
*
|
||||
* Copyright 2019 Sarah Walker.
|
||||
* Copyright 2021 Tiseno100.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/timer.h>
|
||||
#include <86box/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
|
||||
};
|
||||
|
||||
@@ -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, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2019 Miran Grca.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.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/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
|
||||
};
|
||||
@@ -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, <tommowalker@tommowalker.co.uk>
|
||||
* Authors: Tiseno100,
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2008-2019 Sarah Walker.
|
||||
* Copyright 2016-2019 Miran Grca.
|
||||
* Copyright 2020,2021 Tiseno100.
|
||||
* Copyright 2021,2021 Miran Grca.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
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 <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/timer.h>
|
||||
#include <86box/io.h>
|
||||
#include <86box/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
|
||||
};
|
||||
|
||||
641
src/chipset/ali1489.c
Normal file
641
src/chipset/ali1489.c
Normal file
@@ -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, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2020,2021 Tiseno100.
|
||||
* Copyright 2020,2021 Miran Grca.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/timer.h>
|
||||
#include <86box/io.h>
|
||||
#include <86box/device.h>
|
||||
|
||||
#include <86box/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
|
||||
};
|
||||
391
src/chipset/ali1531.c
Normal file
391
src/chipset/ali1531.c
Normal file
@@ -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 <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include <86box/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
|
||||
};
|
||||
656
src/chipset/ali1541.c
Normal file
656
src/chipset/ali1541.c
Normal file
@@ -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, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2021 Miran Grca.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include <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
|
||||
};
|
||||
1600
src/chipset/ali1543.c
Normal file
1600
src/chipset/ali1543.c
Normal file
File diff suppressed because it is too large
Load Diff
685
src/chipset/ali1621.c
Normal file
685
src/chipset/ali1621.c
Normal file
@@ -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, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2021 Miran Grca.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include <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
|
||||
};
|
||||
512
src/chipset/ali6117.c
Normal file
512
src/chipset/ali6117.c
Normal file
@@ -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, <richardg867@gmail.com>
|
||||
*
|
||||
* Copyright 2020 RichardG.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#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
|
||||
};
|
||||
375
src/chipset/contaq_82c59x.c
Normal file
375
src/chipset/contaq_82c59x.c
Normal file
@@ -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, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2021 Miran Grca.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/timer.h>
|
||||
#include <86box/io.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/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
|
||||
};
|
||||
190
src/chipset/cs4031.c
Normal file
190
src/chipset/cs4031.c
Normal file
@@ -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 <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/timer.h>
|
||||
#include <86box/io.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/mem.h>
|
||||
#include <86box/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
|
||||
};
|
||||
@@ -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
|
||||
};
|
||||
.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
|
||||
};
|
||||
|
||||
163
src/chipset/et6000.c
Normal file
163
src/chipset/et6000.c
Normal file
@@ -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 <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/timer.h>
|
||||
#include <86box/io.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/mem.h>
|
||||
#include <86box/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
|
||||
};
|
||||
259
src/chipset/gc100.c
Normal file
259
src/chipset/gc100.c
Normal file
@@ -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, <webmaster.crrc@yahoo.it>
|
||||
*
|
||||
* Copyright 2020-2021 EngiNerd.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include <86box/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
|
||||
};
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
/* Intel 82335 SX emulation, used by the Phoenix 386 clone. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#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);
|
||||
}
|
||||
415
src/chipset/ims8848.c
Normal file
415
src/chipset/ims8848.c
Normal file
@@ -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, <mgrca8@gmail.com>
|
||||
* Tiseno100,
|
||||
*
|
||||
* Copyright 2021 Miran Grca.
|
||||
* Copyright 2021 Tiseno100.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/io.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/mem.h>
|
||||
#include <86box/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
|
||||
};
|
||||
@@ -19,11 +19,13 @@
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#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
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
211
src/chipset/intel_82335.c
Normal file
211
src/chipset/intel_82335.c
Normal file
@@ -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 <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/timer.h>
|
||||
#include <86box/io.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/mem.h>
|
||||
#include <86box/chipset.h>
|
||||
|
||||
/* 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
|
||||
};
|
||||
821
src/chipset/intel_i450kx.c
Normal file
821
src/chipset/intel_i450kx.c
Normal file
@@ -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 <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/timer.h>
|
||||
#include <86box/io.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/mem.h>
|
||||
#include <86box/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
|
||||
};
|
||||
@@ -25,10 +25,7 @@
|
||||
#include <wchar.h>
|
||||
#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
|
||||
};
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#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
|
||||
};
|
||||
|
||||
@@ -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 <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -26,13 +26,8 @@
|
||||
#include <wchar.h>
|
||||
#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
|
||||
};
|
||||
|
||||
171
src/chipset/olivetti_eva.c
Normal file
171
src/chipset/olivetti_eva.c
Normal file
@@ -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 <webmaster.crrc@yahoo.it>
|
||||
*
|
||||
* Copyright 2020-2021 EngiNerd
|
||||
*/
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/timer.h>
|
||||
#include <86box/io.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/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
|
||||
};
|
||||
317
src/chipset/opti283.c
Normal file
317
src/chipset/opti283.c
Normal file
@@ -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, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2021 Tiseno100.
|
||||
* Copyright 2021 Miran Grca.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/timer.h>
|
||||
#include <86box/io.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/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
|
||||
};
|
||||
161
src/chipset/opti291.c
Normal file
161
src/chipset/opti291.c
Normal file
@@ -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 <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/timer.h>
|
||||
#include <86box/io.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/mem.h>
|
||||
#include <86box/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
|
||||
};
|
||||
226
src/chipset/opti391.c
Normal file
226
src/chipset/opti391.c
Normal file
@@ -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, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2021 Miran Grca.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/timer.h>
|
||||
#include <86box/io.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/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
|
||||
};
|
||||
@@ -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, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2008-2020 Tiseno100.
|
||||
* Copyright 2016-2020 Miran Grca.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@@ -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
|
||||
};
|
||||
|
||||
268
src/chipset/opti499.c
Normal file
268
src/chipset/opti499.c
Normal file
@@ -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, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2008-2020 Tiseno100.
|
||||
* Copyright 2016-2020 Miran Grca.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/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
|
||||
};
|
||||
@@ -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, <mgrca8@gmail.com>
|
||||
* Tiseno100
|
||||
*
|
||||
* Copyright 2020 plant/nerd73.
|
||||
* Copyright 2020 Miran Grca.
|
||||
* Copyright 2021 Tiseno100.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@@ -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
|
||||
};
|
||||
|
||||
324
src/chipset/opti822.c
Normal file
324
src/chipset/opti822.c
Normal file
@@ -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 <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/timer.h>
|
||||
#include <86box/io.h>
|
||||
#include <86box/device.h>
|
||||
|
||||
#include <86box/mem.h>
|
||||
#include <86box/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
|
||||
};
|
||||
301
src/chipset/opti895.c
Normal file
301
src/chipset/opti895.c
Normal file
@@ -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, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2008-2020 Tiseno100.
|
||||
* Copyright 2016-2020 Miran Grca.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/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
|
||||
};
|
||||
1355
src/chipset/scamp.c
1355
src/chipset/scamp.c
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
};
|
||||
|
||||
754
src/chipset/sis_5511.c
Normal file
754
src/chipset/sis_5511.c
Normal file
@@ -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 <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/io.h>
|
||||
#include <86box/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
|
||||
};
|
||||
756
src/chipset/sis_5571.c
Normal file
756
src/chipset/sis_5571.c
Normal file
@@ -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 <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/io.h>
|
||||
#include <86box/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
|
||||
};
|
||||
@@ -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
|
||||
};
|
||||
.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
|
||||
};
|
||||
|
||||
@@ -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, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2019 Miran Grca.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/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
|
||||
};
|
||||
@@ -10,74 +10,113 @@
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* Authors: Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2008-2019 Sarah Walker.
|
||||
* Copyright 2019 Miran Grca.
|
||||
* Copyright 2019,2020 Miran Grca.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#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
|
||||
};
|
||||
|
||||
416
src/chipset/sis_85c4xx.c
Normal file
416
src/chipset/sis_85c4xx.c
Normal file
@@ -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, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2019,2020 Miran Grca.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include "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
|
||||
};
|
||||
@@ -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, <http://pcem-emulator.co.uk/>
|
||||
* Authors: Tiseno100,
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2019 Miran Grca.
|
||||
* Copyright 2020,2021 Tiseno100.
|
||||
* Copyright 2020,2021 Miran Grca.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#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
|
||||
};
|
||||
|
||||
1142
src/chipset/stpc.c
Normal file
1142
src/chipset/stpc.c
Normal file
File diff suppressed because it is too large
Load Diff
406
src/chipset/umc_8886.c
Normal file
406
src/chipset/umc_8886.c
Normal file
@@ -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, <mgrca8@gmail.com>
|
||||
*
|
||||
* 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 <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/timer.h>
|
||||
#include <86box/io.h>
|
||||
#include <86box/device.h>
|
||||
|
||||
#include <86box/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
|
||||
};
|
||||
431
src/chipset/umc_hb4.c
Normal file
431
src/chipset/umc_hb4.c
Normal file
@@ -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, <mgrca8@gmail.com>
|
||||
*
|
||||
* 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 <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include "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
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
1716
src/chipset/via_pipc.c
Normal file
1716
src/chipset/via_pipc.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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.
|
||||
*
|
||||
* <This file is part of the 86Box distribution.>
|
||||
*
|
||||
* 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, <http://pcem-emulator.co.uk/>
|
||||
* Copyright(C) 2020 Tiseno100
|
||||
* Copyright(C) 2020 Melissa Goad
|
||||
* Copyright(C) 2020 Miran Grca
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.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/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
|
||||
};
|
||||
415
src/chipset/via_vt82c49x.c
Normal file
415
src/chipset/via_vt82c49x.c
Normal file
@@ -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, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2020 Tiseno100.
|
||||
* Copyright 2020 Miran Grca.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/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
|
||||
};
|
||||
231
src/chipset/via_vt82c505.c
Normal file
231
src/chipset/via_vt82c505.c
Normal file
@@ -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, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2020 Tiseno100.
|
||||
* Copyright 2020 Miran Grca.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#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
|
||||
};
|
||||
@@ -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, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* Melissa Goad, <mszoopers@protonmail.com>
|
||||
*
|
||||
* Copyright 2008-2020 Sarah Walker.
|
||||
* Copyright 2016-2020 Miran Grca.
|
||||
* Copyright 2020 Melissa Goad.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include <86box/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
|
||||
};
|
||||
@@ -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, <http://pcem-emulator.co.uk/>
|
||||
|
||||
Copyright 2020 Tiseno100 <Implemented the 596B overlay>
|
||||
Copyright 2020 Sarah Walker <Main 586B code>
|
||||
Copyright 2020 Miran Grca <Author>
|
||||
Copyright 2020 Melissa Goad <Port to 86Box>
|
||||
|
||||
TODO:
|
||||
- The SMBus must be checked and implemented properly
|
||||
- Fix Documentation errors
|
||||
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include <86box/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
|
||||
217
src/chipset/vl82c480.c
Normal file
217
src/chipset/vl82c480.c
Normal file
@@ -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, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2020 Miran Grca.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/timer.h>
|
||||
#include <86box/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
|
||||
};
|
||||
@@ -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, <tommowalker@tommowalker.co.uk>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Copyright 2021 Tiseno100
|
||||
*
|
||||
* Copyright 2008-2019 Sarah Walker.
|
||||
* Copyright 2016-2019 Miran Grca.
|
||||
* Copyright 2017-2019 Fred N. van Kempen.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include <86box/device.h>
|
||||
#include "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
|
||||
};
|
||||
|
||||
31
src/codegen/CMakeLists.txt
Normal file
31
src/codegen/CMakeLists.txt
Normal file
@@ -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, <hrdlickadavid@outlook.com>
|
||||
#
|
||||
# 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()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user