Merge branch 'master' into feature/mtrr

This commit is contained in:
Jasmine Iwanek
2022-07-27 13:15:49 -04:00
1193 changed files with 300370 additions and 100547 deletions

90
.ci/AppImageBuilder.yml Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
cmake
pkgconfig
ninja
freetype
libsdl2
libpng
FAudio
rtmidi
qt5
wget

24
.ci/dependencies_msys.txt Normal file
View 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
View 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
View 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
View 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

View File

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

View File

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

View File

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

@@ -0,0 +1,2 @@
patreon: 86box
custom: ["https://paypal.me/86Box"]

14
.github/pull_request_template.md vendored Normal file
View 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
View 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
View 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
View File

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

@@ -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
View 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
View 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"
}
]
}

View File

@@ -1,56 +1,57 @@
86Box
=====
**86Box** is a hypervisor and IBM PC system emulator that specializes in
running old operating systems and software designed for IBM PC systems and
compatibles from 1981 through fairly recent system designs based on the
PCI bus.
[![Build Status](http://ci.86box.net/job/86Box/badge/icon)](http://ci.86box.net/job/86Box)
86Box is released under the GNU General Public License, version 2. For more
information, see the `LICENSE` file.
**86Box** is a low level x86 emulator that runs older operating systems and software designed for IBM PC systems and compatibles from 1981 through fairly recent system designs based on the PCI bus.
The project maintainer is OBattler.
Features
--------
* Easy to use interface inspired by mainstream hypervisor software
* Low level emulation of 8086-based processors up to the Pentium with focus on accuracy
* Great range of customizability of virtual machines
* Many available systems, such as the very first IBM PC 5150 from 1981, or the more obscure IBM PS/2 line of systems based on the Micro Channel Architecture
* Lots of supported peripherals including video adapters, sound cards, network adapters, hard disk controllers, and SCSI adapters
* MIDI output to Windows built-in MIDI support, FluidSynth, or emulated Roland synthesizers
* Supports running MS-DOS, older Windows versions, OS/2, many Linux distributions, or vintage systems such as BeOS or NEXTSTEP, and applications for these systems
If you need a configuration manager for 86Box, use the [86Box Manager](https://github.com/86Box/86BoxManager), our
officially endorsed 86Box configuration manager, developed by Overdoze (daviunic).
System requirements and recommendations
---------------------------------------
* Intel Core 2 or AMD Athlon 64 processor
* Windows version: Windows 7 Service Pack 1, Windows 8.1 or Windows 10
* Linux version: Ubuntu 16.04, Debian 9.0 or other distributions from 2016 onwards
* 4 GB of RAM
Community
---------
We operate an IRC channel and a Discord server for discussing anything related
to retro computing and, of course, 86Box. We look forward to hearing from you!
Performance may vary depending on both host and guest configuration. Most emulation logic is executed in a single thread, therefore generally systems with better IPC (instructions per clock) should be able to emulate higher clock speeds.
[![Visit our IRC channel](https://kiwiirc.com/buttons/irc.ringoflightning.net/softhistory.png)](https://kiwiirc.com/client/irc.ringoflightning.net/?nick=86box|?#softhistory)
It is also recommended to use a manager application with 86Box for easier handling of multiple virtual machines.
* [86Box Manager](https://github.com/86Box/86BoxManager) by [Overdoze](https://github.com/daviunic) (Windows only)
* [86Box Manager Lite](https://github.com/insanemal/86box_manager_py) by [Insanemal](https://github.com/insanemal)
* [WinBox for 86Box](https://github.com/86Box/WinBox-for-86Box) by Laci bá' (Windows only)
[![Visit our Discord server](https://discordapp.com/api/guilds/262614059009048590/embed.png)](https://discord.gg/QXK9XTv)
However, it is also possible to use 86Box on its own with the `--vmpath`/`-P` command line option.
Getting started
---------------
See [this](https://86box.github.io/gettingstarted) page on our website for a quick guide that should help you get started with the emulator.
See [our documentation](https://86box.readthedocs.io/en/latest/index.html) for an overview of the emulator's features and user interface.
Building
--------
See the [build guide](doc/build.md).
Community
---------
We operate an IRC channel and a Discord server for discussing 86Box, its development and anything related to retro computing. We look forward to hearing from you!
Automatic builds
--------------
For your convenience, we compile a number of 86Box builds per revision on our
Jenkins instance.
[![Visit our IRC channel](https://kiwiirc.com/buttons/irc.ringoflightning.net/86Box.png)](https://kiwiirc.com/client/irc.ringoflightning.net/?nick=86box|?#86Box)
| Regular | Debug | Optimized | Experimental |
|:-------:|:-----:|:---------:|:------------:|
|[![Build Status](http://ci.86box.net/job/86Box/badge/icon)](http://ci.86box.net/job/86Box)|[![Build Status](http://ci.86box.net/job/86Box-Debug/badge/icon)](http://ci.86box.net/job/86Box-Debug)|[![Build Status](http://ci.86box.net/job/86Box-Optimized/badge/icon)](http://ci.86box.net/job/86Box-Optimized)|[![Build Status](http://ci.86box.net/job/86Box-Dev/badge/icon)](http://ci.86box.net/job/86Box-Dev)
[![Visit our Discord server](https://discordapp.com/api/guilds/262614059009048590/embed.png)](https://discord.gg/QXK9XTv)
### Legend
* **Regular** builds are compiled using the settings in the building guide
above. Use these if you don't know which build to use.
* **Debug** builds are same as regular builds but include debug symbols.
If you don't need them, you don't need to use this build.
* **Optimized** builds have the same feature set as regular builds, but are
optimized for every modern Intel and AMD processor architecture, which might
improve the emulator's performance in certain scenarios.
* **Experimental (Dev)** builds are similar to regular builds but are compiled
with certain unfinished features enabled. These builds are not optimized for maximum performance.
Licensing
---------
86Box is released under the [GNU General Public License, version 2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.html) or later. For more information, see the `COPYING` file in the root of the repository.
The emulator can also optionally make use of [munt](https://github.com/munt/munt), [FluidSynth](https://www.fluidsynth.org/), [Ghostscript](https://www.ghostscript.com/) and [Discord Game SDK](https://discord.com/developers/docs/game-sdk/sdk-starter-guide), which are distributed under their respective licenses.
Donations
---------
We do not charge you for the emulator but donations are still welcome:
https://paypal.me/86Box.
You can also support the project on Patreon:
https://www.patreon.com/86box.

75
bumpversion.sh Normal file
View 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)"'/'

View 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)

View 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)

View 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)

View 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
View 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()

View 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)

View 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?

View 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?

View 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?

View File

@@ -1 +0,0 @@
This directory contains 86Box documentation.

View File

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

File diff suppressed because it is too large Load Diff

209
src/CMakeLists.txt Normal file
View 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()

View File

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

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View 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()

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

685
src/chipset/ali1621.c Normal file
View 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
View 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
View 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
View 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
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

406
src/chipset/umc_8886.c Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View 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