31
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
31
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
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]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
src/*.o
|
||||
src/*.exe
|
||||
src/*.res
|
||||
src/NUL
|
||||
|
||||
51
README.md
51
README.md
@@ -10,66 +10,67 @@ information, see the `LICENSE` file.
|
||||
|
||||
The project maintainer is OBattler.
|
||||
|
||||
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).
|
||||
|
||||
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!
|
||||
|
||||
[](https://kiwiirc.com/client/irc.rol.im/?nick=86box|?#softhistory)
|
||||
[](https://kiwiirc.com/client/irc.ringoflightning.net/?nick=86box|?#softhistory)
|
||||
|
||||
[](https://discord.gg/Es3TnUH)
|
||||
[](https://discord.gg/QXK9XTv)
|
||||
|
||||
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.
|
||||
|
||||
Building
|
||||
--------
|
||||
In order to compile 86Box from this repository, please follow this step-by-step
|
||||
guide:
|
||||
1. Download the development environment from http://tinyurl.com/de86box.
|
||||
Afterwards, extract it to your desired location. Of course, also clone
|
||||
the repository in your desired location. Downloading ZIPs is not recommended,
|
||||
as it makes it more inconvenient to keep the code up-to-date. To avoid
|
||||
issues, make sure neither path has spaces in it.
|
||||
2. In the extracted environment folder, you will find a script called
|
||||
`mingw32_shell.bat`. Launch it. There are other shell launching scripts
|
||||
in there, but you should not use them.
|
||||
3. Once launched, run `pacman -Syuu` in order to update the environment.
|
||||
Depending on the state of the downloaded DE, you may need to run it twice
|
||||
(once initially, and then again after re-entering the environment). Make sure
|
||||
to keep the enviroment up-to-date by re-running the command periodically.
|
||||
4. Once the environment is fully updated, `cd` into your cloned `86box\src`
|
||||
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.
|
||||
3. Once launched, run `pacman -Syu` in order to update the environment. You may need to do this twice, just follow the on-screen instructions. Make sure you re-run `pacman -Syu` periodically to keep the environment up-to-date.
|
||||
4. Run the following command to install all of the dependencies: `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 mingw-w64-i686-ghostscript`. Additionally, you will need to download the developer's pack of WinPcap [from here](https://www.winpcap.org/devel.htm), and extract it into `<MSYS2 root>\mingw32\`.
|
||||
5. Once the environment is fully updated and all dependencies are installed, `cd` into your cloned `86box\src`
|
||||
directory.
|
||||
5. Run `make -jN -fmakefile.mingw` to start the actual compilation process.
|
||||
6. Run `make -jN -f win/makefile.mingw` to start the actual compilation process.
|
||||
Substitute `N` with the number of threads you want to use for the compilation
|
||||
process. The optimal number depends entirely on your processor, and it is
|
||||
up to you to determine the optimal number. A good starting point is the total
|
||||
number of threads (AKA Logical Processors) you have available.
|
||||
6. If the compilation succeeded (which it almost always should), you will find
|
||||
7. If the compilation succeeded (which it almost always should), you will find
|
||||
`86Box.exe` in the src directory.
|
||||
7. In order to test your fresh build, replace the `86Box.exe` in your current
|
||||
8. In order to test your fresh build, replace the `86Box.exe` in your current
|
||||
86Box enviroment 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 ROM set from http://tinyurl.com/rs20180320.
|
||||
8. Enjoy using and testing the emulator! :)
|
||||
http://ci.86box.net, and the ROM set from https://tinyurl.com/rs20191022.
|
||||
9. Enjoy using and testing the emulator! :)
|
||||
|
||||
If you encounter issues at any step or have additional questions, please join
|
||||
the IRC channel and wait patiently for someone to help you.
|
||||
the IRC channel or the appropriate channel on our Discord server and wait patiently for someone to help you.
|
||||
|
||||
Nightly builds
|
||||
--------------
|
||||
For your convenience, we compile a number of 86Box builds per revision on our
|
||||
Jenkins instance.
|
||||
|
||||
| Regular | Optimized | Experimental |
|
||||
|:-------:|:---------:|:------------:|
|
||||
|[](http://ci.86box.net/job/86Box)|[](http://ci.86box.net/job/86Box-Optimized)|[](http://ci.86box.net/job/86Box-Dev)
|
||||
| Regular | Debug | Optimized | Experimental |
|
||||
|:-------:|:-----:|:---------:|:------------:|
|
||||
|[](http://ci.86box.net/job/86Box)|[](http://ci.86box.net/job/86Box-Debug)|[](http://ci.86box.net/job/86Box-Optimized)|[](http://ci.86box.net/job/86Box-Dev)
|
||||
|
||||
### 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
|
||||
certain unfinished features enabled. These builds are not optimized.
|
||||
with certain unfinished features enabled. These builds are not optimized for maximum performance.
|
||||
|
||||
Donations
|
||||
---------
|
||||
|
||||
BIN
nvr/430vx.nvr
BIN
nvr/430vx.nvr
Binary file not shown.
BIN
nvr/440fx.nvr
BIN
nvr/440fx.nvr
Binary file not shown.
BIN
nvr/586mc1.nvr
BIN
nvr/586mc1.nvr
Binary file not shown.
BIN
nvr/acer386.nvr
BIN
nvr/acer386.nvr
Binary file not shown.
BIN
nvr/acerm3a.nvr
BIN
nvr/acerm3a.nvr
Binary file not shown.
BIN
nvr/acerv35n.nvr
BIN
nvr/acerv35n.nvr
Binary file not shown.
BIN
nvr/adgold.bin
BIN
nvr/adgold.bin
Binary file not shown.
BIN
nvr/ami286.nvr
BIN
nvr/ami286.nvr
Binary file not shown.
BIN
nvr/ami386.nvr
BIN
nvr/ami386.nvr
Binary file not shown.
Binary file not shown.
BIN
nvr/ami486.nvr
BIN
nvr/ami486.nvr
Binary file not shown.
BIN
nvr/at.nvr
BIN
nvr/at.nvr
Binary file not shown.
BIN
nvr/award286.nvr
BIN
nvr/award286.nvr
Binary file not shown.
BIN
nvr/cmdpc30.nvr
BIN
nvr/cmdpc30.nvr
Binary file not shown.
BIN
nvr/dell200.nvr
BIN
nvr/dell200.nvr
Binary file not shown.
Binary file not shown.
BIN
nvr/dtk386.nvr
BIN
nvr/dtk386.nvr
Binary file not shown.
BIN
nvr/dtk486.nvr
BIN
nvr/dtk486.nvr
Binary file not shown.
BIN
nvr/endeavor.nvr
BIN
nvr/endeavor.nvr
Binary file not shown.
BIN
nvr/europc.nvr
BIN
nvr/europc.nvr
Binary file not shown.
BIN
nvr/hot-433.nvr
BIN
nvr/hot-433.nvr
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
nvr/kn97.nvr
BIN
nvr/kn97.nvr
Binary file not shown.
BIN
nvr/mb500n.nvr
BIN
nvr/mb500n.nvr
Binary file not shown.
BIN
nvr/megapc.nvr
BIN
nvr/megapc.nvr
Binary file not shown.
Binary file not shown.
BIN
nvr/p54tp4xe.nvr
BIN
nvr/p54tp4xe.nvr
Binary file not shown.
BIN
nvr/p55t2p4.nvr
BIN
nvr/p55t2p4.nvr
Binary file not shown.
BIN
nvr/p55tp4n.nvr
BIN
nvr/p55tp4n.nvr
Binary file not shown.
BIN
nvr/p55tp4xe.nvr
BIN
nvr/p55tp4xe.nvr
Binary file not shown.
BIN
nvr/p55tvp4.nvr
BIN
nvr/p55tvp4.nvr
Binary file not shown.
BIN
nvr/p55va.nvr
BIN
nvr/p55va.nvr
Binary file not shown.
BIN
nvr/p5sp4.nvr
BIN
nvr/p5sp4.nvr
Binary file not shown.
BIN
nvr/pc1512.nvr
BIN
nvr/pc1512.nvr
Binary file not shown.
BIN
nvr/pc1640.nvr
BIN
nvr/pc1640.nvr
Binary file not shown.
@@ -1 +0,0 @@
|
||||
<06>#<23><11>!<02><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><19><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
Binary file not shown.
BIN
nvr/pc2086.nvr
BIN
nvr/pc2086.nvr
Binary file not shown.
BIN
nvr/pc3086.nvr
BIN
nvr/pc3086.nvr
Binary file not shown.
BIN
nvr/plato.nvr
BIN
nvr/plato.nvr
Binary file not shown.
BIN
nvr/px386.nvr
BIN
nvr/px386.nvr
Binary file not shown.
BIN
nvr/r418.nvr
BIN
nvr/r418.nvr
Binary file not shown.
BIN
nvr/revenge.nvr
BIN
nvr/revenge.nvr
Binary file not shown.
BIN
nvr/sis496.nvr
BIN
nvr/sis496.nvr
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
nvr/thor.nvr
BIN
nvr/thor.nvr
Binary file not shown.
Binary file not shown.
BIN
nvr/win486.nvr
BIN
nvr/win486.nvr
Binary file not shown.
47
src/86box.h
47
src/86box.h
@@ -8,13 +8,13 @@
|
||||
*
|
||||
* Main include file for the application.
|
||||
*
|
||||
* Version: @(#)86box.h 1.0.23 2018/05/25
|
||||
* Version: @(#)86box.h 1.0.36 2019/12/05
|
||||
*
|
||||
* Authors: Miran Grca, <mgrca8@gmail.com>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*f Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2016-2019 Miran Grca.
|
||||
* Copyright 2017-2019 Fred N. van Kempen.
|
||||
*/
|
||||
#ifndef EMU_86BOX_H
|
||||
# define EMU_86BOX_H
|
||||
@@ -29,8 +29,13 @@
|
||||
/* Version info. */
|
||||
#define EMU_NAME "86Box"
|
||||
#define EMU_NAME_W L"86Box"
|
||||
#define EMU_VERSION "2.00"
|
||||
#define EMU_VERSION_W L"2.00"
|
||||
#ifdef RELEASE_BUILD
|
||||
#define EMU_VERSION "2.07"
|
||||
#define EMU_VERSION_W L"2.07"
|
||||
#else
|
||||
#define EMU_VERSION "2.10"
|
||||
#define EMU_VERSION_W L"2.10"
|
||||
#endif
|
||||
|
||||
/* Filename and pathname info. */
|
||||
#define CONFIG_FILE L"86box.cfg"
|
||||
@@ -92,11 +97,12 @@ extern int vid_cga_contrast, /* (C) video */
|
||||
force_43, /* (C) video */
|
||||
gfxcard; /* (C) graphics/video card */
|
||||
extern int serial_enabled[], /* (C) enable serial ports */
|
||||
lpt_enabled, /* (C) enable LPT ports */
|
||||
bugger_enabled; /* (C) enable ISAbugger */
|
||||
bugger_enabled, /* (C) enable ISAbugger */
|
||||
isamem_type[], /* (C) enable ISA mem cards */
|
||||
isartc_type; /* (C) enable ISA RTC card */
|
||||
extern int sound_is_float, /* (C) sound uses FP values */
|
||||
GAMEBLASTER, /* (C) sound option */
|
||||
GUS, /* (C) sound option */
|
||||
GUS, GUSMAX, /* (C) sound option */
|
||||
SSI2001, /* (C) sound option */
|
||||
voodoo_enabled; /* (C) video option */
|
||||
extern uint32_t mem_size; /* (C) memory size */
|
||||
@@ -104,10 +110,17 @@ extern int cpu_manufacturer, /* (C) cpu manufacturer */
|
||||
cpu, /* (C) cpu type */
|
||||
cpu_use_dynarec, /* (C) cpu uses/needs Dyna */
|
||||
enable_external_fpu; /* (C) enable external FPU */
|
||||
extern int enable_sync; /* (C) enable time sync */
|
||||
extern int time_sync; /* (C) enable time sync */
|
||||
extern int network_type; /* (C) net provider type */
|
||||
extern int network_card; /* (C) net interface num */
|
||||
extern char network_host[512]; /* (C) host network intf */
|
||||
extern char network_host[522]; /* (C) host network intf */
|
||||
extern int hdd_format_type; /* (C) hard disk file format */
|
||||
#ifdef USE_DISCORD
|
||||
extern int enable_discord; /* (C) enable Discord integration */
|
||||
#endif
|
||||
|
||||
extern int is_pentium; /* TODO: Move back to cpu/cpu.h when it's figured out,
|
||||
how to remove that hack from the ET4000/W32p. */
|
||||
|
||||
|
||||
#ifdef ENABLE_LOG_TOGGLES
|
||||
@@ -123,7 +136,9 @@ extern int nic_do_log;
|
||||
extern wchar_t exe_path[1024]; /* path (dir) of executable */
|
||||
extern wchar_t usr_path[1024]; /* path (dir) of user data */
|
||||
extern wchar_t cfg_path[1024]; /* full path of config file */
|
||||
#ifndef USE_NEW_DYNAREC
|
||||
extern FILE *stdlog; /* file to log output to */
|
||||
#endif
|
||||
extern int scrnsz_x, /* current screen size, X */
|
||||
scrnsz_y; /* current screen size, Y */
|
||||
extern int efscrnsz_y;
|
||||
@@ -158,6 +173,16 @@ extern void pc_thread(void *param);
|
||||
extern void pc_start(void);
|
||||
extern void pc_onesec(void);
|
||||
|
||||
extern uint16_t get_last_addr(void);
|
||||
|
||||
/* This is for external subtraction of cycles;
|
||||
should be in cpu.c but I put it here to avoid
|
||||
having to include cpu.c everywhere. */
|
||||
extern void sub_cycles(int c);
|
||||
|
||||
extern double isa_timing;
|
||||
extern int io_delay;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# settings, so we can avoid changing the main one for all of
|
||||
# our local setups.
|
||||
#
|
||||
# Version: @(#)Makefile.local 1.0.15 2018/07/19
|
||||
# Version: @(#)Makefile.local 1.0.22 2019/10/20
|
||||
#
|
||||
# Author: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
#
|
||||
@@ -35,13 +35,15 @@ STUFF :=
|
||||
# -DENABLE_VRAM_DUMP enables Video Ram dumping.
|
||||
# -DENABLE_LOG_BREAKPOINT enables extra logging.
|
||||
# Root logging:
|
||||
# -DENABLE_APM_LOG=N sets logging level at N.
|
||||
# -DENABLE_BUGGER_LOG=N sets logging level at N.
|
||||
# -DENABLE_CONFIG_LOG=N sets logging level at N.
|
||||
# -DENABLE_DEVICE_LOG=N sets logging level at N.
|
||||
# -DENABLE_KEYBOARD_AMSTRAD_LOG=N sets logging level at N.
|
||||
# -DENABLE_KEYBOARD_AT_LOG=N sets logging level at N.
|
||||
# -DENABLE_KEYBOARD_LOG=N sets logging level at N.
|
||||
# -DENABLE_IO_LOG=N sets logging level at N.
|
||||
# -DENABLE_PIIX_LOG=N sets logging level at N.
|
||||
# -DENABLE_ISAMEM_LOG=N sets logging level at N.
|
||||
# -DENABLE_ISARTC_LOG=N sets logging level at N.
|
||||
# -DENABLE_KEYBOARD_AT_LOG=N sets logging level at N.
|
||||
# -DENABLE_MEM_LOG=N sets logging level at N.
|
||||
# -DENABLE_MOUSE_LOG=N sets logging level at N.
|
||||
# -DENABLE_MOUSE_BUS_LOG=N sets logging level at N.
|
||||
@@ -51,26 +53,33 @@ STUFF :=
|
||||
# -DENABLE_PC_LOG=N sets logging level at N.
|
||||
# -DENABLE_PCI_LOG=N sets logging level at N.
|
||||
# -DENABLE_PIC_LOG=N sets logging level at N.
|
||||
# -DENABLE_PIIX_LOG=N sets logging level at N.
|
||||
# -DENABLE_ROM_LOG=N sets logging level at N.
|
||||
# -DENABLE_SERIAL_LOG=N sets logging level at N.
|
||||
# -DENABLE_VNC_LOG=N sets logging level at N.
|
||||
# -DENABLE_VNC_KEYMAP_LOG=N sets logging level at N.
|
||||
# cdrom/ logging:
|
||||
# -DENABLE_CDROM_LOG=N sets logging level at N.
|
||||
# -DENABLE_CDROM_DOSBOX_LOG=N sets logging level at N.
|
||||
# -DENABLE_CDROM_IMAGE_LOG=N sets logging level at N.
|
||||
# cpu/ logging:
|
||||
# -DENABLE_386_LOG=N sets logging level at N.
|
||||
# -DENABLE_386_DYNAREC_LOG=N sets logging level at N.
|
||||
# -DENABLE_808X_LOG=N sets logging level at N.
|
||||
# -DENABLE_FPU_LOG=N sets logging level at N.
|
||||
# -DENABLE_X86SEG_LOG=N sets logging level at N.
|
||||
# cpu_new/ logging:
|
||||
# -DENABLE_386_COMMON_LOG=N sets logging level at N.
|
||||
# chipset/ logging:
|
||||
# -DENABLE_NEAT_LOG=N sets logging level at N.
|
||||
# disk/ logging:
|
||||
# -DENABLE_ESDI_AT_LOG=N sets logging level at N.
|
||||
# -DENABLE_ESDI_MCA_LOG=N sets logging level at N.
|
||||
# -DENABLE_HDC_LOG=N sets logging level at N.
|
||||
# -DENABLE_HDD_IMAGE_LOG=N sets logging level at N.
|
||||
# -DENABLE_IDE_LOG=N sets logging level at N.
|
||||
# -DENABLE_MFM_AT_LOG=N sets logging level at N.
|
||||
# -DENABLE_MFM_XT_LOG=N sets logging level at N.
|
||||
# -DENABLE_SFF_LOG=N sets logging level at N.
|
||||
# -DENABLE_ST506_AT_LOG=N sets logging level at N.
|
||||
# -DENABLE_ST506_XT_LOG=N sets logging level at N.
|
||||
# -DENABLE_XTA_LOG=N sets logging level at N.
|
||||
# -DENABLE_ZIP_LOG=N sets logging level at N.
|
||||
# floppy/ logging:
|
||||
@@ -82,29 +91,33 @@ STUFF :=
|
||||
# -DENABLE_IMD_LOG=N sets logging level at N.
|
||||
# -DENABLE_IMG_LOG=N sets logging level at N.
|
||||
# -DENABLE_JSON_LOG=N sets logging level at N.
|
||||
# -DENABLE_MFM_LOG=N sets logging level at N.
|
||||
# -DENABLE_TD0_LOG=N sets logging level at N.
|
||||
# machine/ logging:
|
||||
# -DENABLE_AMSTRAD_LOG=N sets logging level at N.
|
||||
# -DENABLE_EUROPC_LOG=N sets logging level at N.
|
||||
# -DENABLE_M24VID_LOG=N sets logging level at N.
|
||||
# -DENABLE_MACHINE_LOG=N sets logging level at N.
|
||||
# -DENABLE_PS1_HDC_LOG=N sets logging level at N.
|
||||
# -DENABLE_PS2_MCA_LOG=N sets logging level at N.
|
||||
# -DENABLE_TANDY_LOG=N sets logging level at N.
|
||||
# -DENABLE_T1000_LOG=N sets logging level at N.
|
||||
# -DENABLE_T3100E_LOG=N sets logging level at N.
|
||||
# -DENABLE_TANDY_LOG=N sets logging level at N.
|
||||
# network/ logging:
|
||||
# -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_PCAP_LOG=N sets logging level at N.
|
||||
# -DENABLE_SLIRP_LOG=N sets logging level at N.
|
||||
# -DENABLE_WD_LOG=N sets logging level at N.
|
||||
# scsi/ logging:
|
||||
# -DENABLE_AHA154X_LOG=N sets logging level at N.
|
||||
# -DENABLE_BUSLOGIC_LOG=N sets logging level at N.
|
||||
# -DENABLE_NCR5380_LOG=N sets logging level at N.
|
||||
# -DENABLE_NCR53C810_LOG=N sets logging level at N.
|
||||
# -DENABLE_SCSI_LOG=N sets logging level at N.
|
||||
# -DENABLE_SCSI_BUS_LOG=N sets logging level at N.
|
||||
# -DENABLE_SCSI_CDROM_LOG=N sets logging level at N.
|
||||
# -DENABLE_SCSI_DISK_LOG=N sets logging level at N.
|
||||
# -DENABLE_NCR5380_LOG=N sets logging level at N.
|
||||
# -DENABLE_NCR53C8XX_LOG=N sets logging level at N.
|
||||
# -DENABLE_X54X_LOG=N sets logging level at N.
|
||||
# sound/ logging:
|
||||
# -DENABLE_ADLIB_LOG=N sets logging level at N.
|
||||
@@ -118,20 +131,26 @@ STUFF :=
|
||||
# video/ logging:
|
||||
# -DENABLE_ATI28800_LOG=N sets logging level at N.
|
||||
# -DENABLE_MACH64_LOG=N sets logging level at N.
|
||||
# -DENABLE_COMPAQ_CGA_LOG=N sets logging level at N.
|
||||
# -DENABLE_ET4000W32_LOG=N sets logging level at N.
|
||||
# -DENABLE_NV_RIVA_LOG=N sets logging level at N.
|
||||
# -DENABLE_NVIDIA_LOG=N sets logging level at N.
|
||||
# -DENABLE_HT216_LOG=N sets logging level at N.
|
||||
# -DENABLE_ICD2061_LOG=N sets logging level at N.
|
||||
# -DENABLE_IM1024_LOG=N sets logging level at N.
|
||||
# -DENABLE_PGC_LOG=N sets logging level at N.
|
||||
# -DENABLE_S3_VIRGE_LOG=N sets logging level at N.
|
||||
# -DENABLE_VID_TABLE_LOG=N sets logging level at N.
|
||||
# -DENABLE_VOODOO_LOG=N sets logging level at N.
|
||||
# -DENABLE_VRAM_DUMP=N sets logging level at N.
|
||||
# win/ logging:
|
||||
# -DENABLE_WIN_LOG=N sets logging level at N.
|
||||
# -DENABLE_D2D_LOG=N sets logging level at N.
|
||||
# -DENABLE_DDRAW_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_BREAKPOINT=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_WIN_LOG=N sets logging level at N.
|
||||
# -DENABLE_SETTINGS_LOG=N sets logging level at N.
|
||||
EXTRAS :=
|
||||
|
||||
|
||||
|
||||
149
src/apm.c
Normal file
149
src/apm.c
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Advanced Power Management emulation.
|
||||
*
|
||||
* Version: @(#)apm.c 1.0.0 2019/05/12
|
||||
*
|
||||
* 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>
|
||||
#define HAVE_STDARG_H
|
||||
#include "86box.h"
|
||||
#include "cpu/cpu.h"
|
||||
#include "device.h"
|
||||
#include "io.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t cmd,
|
||||
stat;
|
||||
} apm_t;
|
||||
|
||||
|
||||
#ifdef ENABLE_APM_LOG
|
||||
int apm_do_log = ENABLE_APM_LOG;
|
||||
|
||||
|
||||
static void
|
||||
apm_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (apm_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define apm_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
apm_out(uint16_t port, uint8_t val, void *p)
|
||||
{
|
||||
apm_t *apm = (apm_t *) p;
|
||||
|
||||
apm_log("[%04X:%08X] APM write: %04X = %02X (BX = %04X, CX = %04X)\n", CS, cpu_state.pc, port, val, BX, CX);
|
||||
|
||||
port &= 0x0001;
|
||||
|
||||
if (port == 0x0000) {
|
||||
apm->cmd = val;
|
||||
|
||||
switch (apm->cmd) {
|
||||
case 0x07: /* Set Power State */
|
||||
if (CH == 0x00) switch (CX) {
|
||||
case 0x0000:
|
||||
#ifdef ENABLE_APM_LOG
|
||||
apm_log("APM Set Power State: APM Enabled\n");
|
||||
#endif
|
||||
break;
|
||||
case 0x0001:
|
||||
#ifdef ENABLE_APM_LOG
|
||||
apm_log("APM Set Power State: Standby\n");
|
||||
#endif
|
||||
break;
|
||||
case 0x0002:
|
||||
#ifdef ENABLE_APM_LOG
|
||||
apm_log("APM Set Power State: Suspend\n");
|
||||
#endif
|
||||
break;
|
||||
case 0x0003: /* Off */
|
||||
#ifdef ENABLE_APM_LOG
|
||||
apm_log("APM Set Power State: Off\n");
|
||||
#endif
|
||||
exit(-1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else
|
||||
apm->stat = val;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
apm_in(uint16_t port, void *p)
|
||||
{
|
||||
apm_t *apm = (apm_t *) p;
|
||||
|
||||
apm_log("[%04X:%08X] APM read: %04X = FF\n", CS, cpu_state.pc, port);
|
||||
|
||||
port &= 0x0001;
|
||||
|
||||
if (port == 0x0000)
|
||||
return apm->cmd;
|
||||
else
|
||||
return apm->stat;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
apm_close(void *p)
|
||||
{
|
||||
apm_t *dev = (apm_t *)p;
|
||||
|
||||
free(dev);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
*apm_init(const device_t *info)
|
||||
{
|
||||
apm_t *apm = (apm_t *) malloc(sizeof(apm_t));
|
||||
memset(apm, 0, sizeof(apm_t));
|
||||
|
||||
io_sethandler(0x00b2, 0x0002, apm_in, NULL, NULL, apm_out, NULL, NULL, apm);
|
||||
|
||||
return apm;
|
||||
}
|
||||
|
||||
|
||||
const device_t apm_device =
|
||||
{
|
||||
"Advanced Power Management",
|
||||
0,
|
||||
0,
|
||||
apm_init,
|
||||
apm_close,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
43
src/apm.h
Normal file
43
src/apm.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* 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 ISA Bus (de)Bugger expansion card
|
||||
* sold as a DIY kit in the late 1980's in The Netherlands.
|
||||
* This card was a assemble-yourself 8bit ISA addon card for
|
||||
* PC and AT systems that had several tools to aid in low-
|
||||
* level debugging (mostly for faulty BIOSes, bootloaders
|
||||
* and system kernels...)
|
||||
*
|
||||
* Definitions for the Advanced Power Management emulation.
|
||||
*
|
||||
* Version: @(#)apm.h 1.0.0 2019/05/12
|
||||
*
|
||||
* Authors: Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2019 Miran Grca.
|
||||
*/
|
||||
#ifndef APM_H
|
||||
# define APM_H
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Global variables. */
|
||||
extern const device_t apm_device;
|
||||
|
||||
|
||||
/* Functions. */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /*APM_H*/
|
||||
121
src/apm_new.c
Normal file
121
src/apm_new.c
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Advanced Power Management emulation.
|
||||
*
|
||||
* Version: @(#)apm.c 1.0.0 2019/05/12
|
||||
*
|
||||
* 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>
|
||||
#define HAVE_STDARG_H
|
||||
#include "86box.h"
|
||||
#include "cpu_new/cpu.h"
|
||||
#include "device.h"
|
||||
#include "io.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t cmd,
|
||||
stat;
|
||||
} apm_t;
|
||||
|
||||
|
||||
#ifdef ENABLE_APM_LOG
|
||||
int apm_do_log = ENABLE_APM_LOG;
|
||||
|
||||
|
||||
static void
|
||||
apm_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (apm_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define apm_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
apm_out(uint16_t port, uint8_t val, void *p)
|
||||
{
|
||||
apm_t *apm = (apm_t *) p;
|
||||
|
||||
apm_log("[%04X:%08X] APM write: %04X = %02X (BX = %04X, CX = %04X)\n", CS, cpu_state.pc, port, val, BX, CX);
|
||||
|
||||
port &= 0x0001;
|
||||
|
||||
if (port == 0x0000) apm->cmd = val;
|
||||
else apm->stat = val;
|
||||
|
||||
smi_line = 1;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
apm_in(uint16_t port, void *p)
|
||||
{
|
||||
apm_t *apm = (apm_t *) p;
|
||||
|
||||
apm_log("[%04X:%08X] APM read: %04X = FF\n", CS, cpu_state.pc, port);
|
||||
|
||||
port &= 0x0001;
|
||||
|
||||
if (port == 0x0000)
|
||||
return apm->cmd;
|
||||
else
|
||||
return apm->stat;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
apm_close(void *p)
|
||||
{
|
||||
apm_t *dev = (apm_t *)p;
|
||||
|
||||
free(dev);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
*apm_init(const device_t *info)
|
||||
{
|
||||
apm_t *apm = (apm_t *) malloc(sizeof(apm_t));
|
||||
memset(apm, 0, sizeof(apm_t));
|
||||
|
||||
io_sethandler(0x00b2, 0x0002, apm_in, NULL, NULL, apm_out, NULL, NULL, apm);
|
||||
|
||||
return apm;
|
||||
}
|
||||
|
||||
|
||||
const device_t apm_device =
|
||||
{
|
||||
"Advanced Power Management",
|
||||
0,
|
||||
0,
|
||||
apm_init,
|
||||
apm_close,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
14
src/bugger.c
14
src/bugger.c
@@ -44,7 +44,7 @@
|
||||
* configuration register (CTRL_SPCFG bit set) but have to
|
||||
* remember that stuff first...
|
||||
*
|
||||
* Version: @(#)bugger.c 1.0.12 2018/04/29
|
||||
* Version: @(#)bugger.c 1.0.13 2018/10/17
|
||||
*
|
||||
* Author: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Copyright 1989-2018 Fred N. van Kempen.
|
||||
@@ -93,22 +93,22 @@ extern void ui_sb_bugui(char *__str);
|
||||
|
||||
#ifdef ENABLE_BUGGER_LOG
|
||||
int bugger_do_log = ENABLE_BUGGER_LOG;
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
bugger_log(const char *format, ...)
|
||||
bugger_log(const char *fmt, ...)
|
||||
{
|
||||
#ifdef ENABLE_BUGGER_LOG
|
||||
va_list ap;
|
||||
|
||||
if (bugger_do_log) {
|
||||
va_start(ap, format);
|
||||
pclog_ex(format, ap);
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
#define bugger_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
|
||||
/* Update the system's UI with the actual Bugger status. */
|
||||
|
||||
203
src/cassette/cassette.c
Normal file
203
src/cassette/cassette.c
Normal file
@@ -0,0 +1,203 @@
|
||||
/************************************************************************
|
||||
|
||||
PCEM: IBM 5150 Cassette support
|
||||
|
||||
Copyright (C) 2019 John Elliott <seasip.webmaster@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include "../86box.h"
|
||||
#include "../device.h"
|
||||
#include "../cpu/cpu.h"
|
||||
#include "../machine/machine.h"
|
||||
#include "../ppi.h"
|
||||
#include "../ui.h"
|
||||
#include "../plat.h"
|
||||
#include "pzx.h"
|
||||
#include "cassette.h"
|
||||
|
||||
typedef struct cassette_t
|
||||
{
|
||||
uint8_t motor; /* Motor status */
|
||||
pzxfile_t pzx;
|
||||
int cycles_last; /* Cycle count at last cassette poll */
|
||||
|
||||
} cassette_t;
|
||||
|
||||
wchar_t cassettefn[256];
|
||||
|
||||
static cassette_t *st_cas;
|
||||
|
||||
|
||||
#ifdef ENABLE_CASSETTE_LOG
|
||||
int cassette_do_log = ENABLE_CASSETTE_LOG;
|
||||
|
||||
|
||||
static void
|
||||
cassette_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (cassette_do_log)
|
||||
{
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define cassette_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
|
||||
/* The PCEM CPU uses IBM cycles (4.77MHz). PZX uses Spectrum cycles (3.5MHz)
|
||||
* so scale accordingly. */
|
||||
static int32_t
|
||||
pzx_cycles(int32_t pc)
|
||||
{
|
||||
double d = pc;
|
||||
|
||||
return (int32_t)(((d * 3.5) / 4.772728) + 0.5);
|
||||
}
|
||||
|
||||
void
|
||||
cassette_eject(void)
|
||||
{
|
||||
if (st_cas->pzx.input) {
|
||||
pzx_close(&st_cas->pzx);
|
||||
}
|
||||
cassettefn[0] = 0;
|
||||
}
|
||||
|
||||
void
|
||||
cassette_load(wchar_t *fn)
|
||||
{
|
||||
FILE *fp;
|
||||
unsigned char magic[8];
|
||||
|
||||
if (!fn)
|
||||
return;
|
||||
|
||||
fp = plat_fopen(fn, L"rb");
|
||||
if (!fp) {
|
||||
/* Warn user? */
|
||||
cassette_log("Failed to open cassette input %s\n", fn);
|
||||
return;
|
||||
}
|
||||
memset(magic, 0, sizeof(magic));
|
||||
fread(magic, 1, sizeof(magic), fp);
|
||||
|
||||
/* Check for PZX signature. In due course support could be added for
|
||||
* other formats like TZX */
|
||||
if (!memcmp(magic, "PZXT", 4)) {
|
||||
wchar_t *result;
|
||||
|
||||
result = pzx_open(&st_cas->pzx, fp);
|
||||
|
||||
if (result) {
|
||||
cassette_log("Failed to open %s as PZX: %s\n",
|
||||
fn, result);
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
wcscpy(cassettefn, fn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t
|
||||
cassette_input(void)
|
||||
{
|
||||
int ticks;
|
||||
|
||||
/* While motor is off, result is loopback */
|
||||
if (!st_cas->motor)
|
||||
return ppispeakon;
|
||||
/* If there is no tapefile open don't try to extract data */
|
||||
if (st_cas->pzx.input == NULL)
|
||||
return 0;
|
||||
/* Otherwise see how many ticks there have been since the last input */
|
||||
if (st_cas->cycles_last == -1)
|
||||
st_cas->cycles_last = cycles;
|
||||
if (cycles <= st_cas->cycles_last)
|
||||
ticks = (st_cas->cycles_last - cycles);
|
||||
else
|
||||
ticks = (st_cas->cycles_last + (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed / 100) - cycles);
|
||||
st_cas->cycles_last = cycles;
|
||||
|
||||
return pzx_advance(&st_cas->pzx, pzx_cycles(ticks));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
cassette_set_motor(uint8_t on)
|
||||
{
|
||||
if (on && !st_cas->motor) {
|
||||
cassette_log("Start cassette motor\n");
|
||||
st_cas->cycles_last = -1;
|
||||
}
|
||||
if (st_cas->motor && !on) {
|
||||
cassette_log("Stop cassette motor\n");
|
||||
st_cas->cycles_last = -1;
|
||||
}
|
||||
st_cas->motor = on;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
*cassette_init(const device_t *info)
|
||||
{
|
||||
cassette_t *cas = (cassette_t *)malloc(sizeof(cassette_t));
|
||||
memset(cas, 0, sizeof(cassette_t));
|
||||
pzx_init(&cas->pzx);
|
||||
|
||||
st_cas = cas;
|
||||
return cas;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
cassette_close(void *p)
|
||||
{
|
||||
cassette_t *cas = (cassette_t *)p;
|
||||
|
||||
pzx_close(&cas->pzx);
|
||||
|
||||
free(cas);
|
||||
}
|
||||
|
||||
|
||||
const device_t cassette_device = {
|
||||
"IBM PC 5150 Cassette",
|
||||
0,
|
||||
0,
|
||||
cassette_init,
|
||||
cassette_close,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
30
src/cassette/cassette.h
Normal file
30
src/cassette/cassette.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/************************************************************************
|
||||
|
||||
PCEM: IBM 5150 cassette support
|
||||
|
||||
Copyright (C) 2019 John Elliott <seasip.webmaster@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*************************************************************************/
|
||||
|
||||
extern wchar_t cassettefn[256];
|
||||
|
||||
extern const device_t cassette_device;
|
||||
|
||||
uint8_t cassette_input(void);
|
||||
void cassette_set_motor(uint8_t on);
|
||||
void cassette_eject(void);
|
||||
void cassette_load(wchar_t *filename);
|
||||
414
src/cassette/pzx.c
Normal file
414
src/cassette/pzx.c
Normal file
@@ -0,0 +1,414 @@
|
||||
/************************************************************************
|
||||
|
||||
PCEM: IBM 5150 Cassette support
|
||||
|
||||
Copyright (C) 2019 John Elliott <seasip.webmaster@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include "../86box.h"
|
||||
#include "../ui.h"
|
||||
#include "pzx.h"
|
||||
|
||||
/* This module is intended to abstract all the details of a PZX file and
|
||||
* emit its contents as a bitstream in a form suitable for PCEM. Similar
|
||||
* modules could be written to add support for other tape formats such as TZX,
|
||||
* TAP or CSW. */
|
||||
|
||||
|
||||
#ifdef ENABLE_PZX_LOG
|
||||
int pzx_do_log = ENABLE_PZX_LOG;
|
||||
|
||||
|
||||
static void
|
||||
pzx_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (pzx_do_log)
|
||||
{
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define pzx_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
static uint32_t
|
||||
peek2(uint8_t *data)
|
||||
{
|
||||
return (((uint32_t)data[1]) << 8) | data[0];
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
peek4(uint8_t *data)
|
||||
{
|
||||
return (((uint32_t)data[3]) << 24) |
|
||||
(((uint32_t)data[2]) << 16) |
|
||||
(((uint32_t)data[1]) << 8) | data[0];
|
||||
}
|
||||
|
||||
/* Cue up the next pulse definition from the current PULS block. */
|
||||
static void
|
||||
pzx_parse_pulse(pzxfile_t *pzx)
|
||||
{
|
||||
pzx->puls_duration = peek2(pzx->curblock + pzx->puls_ptr);
|
||||
pzx->puls_ptr += 2;
|
||||
if (pzx->puls_duration > 0x8000) {
|
||||
pzx->puls_count = pzx->puls_duration & 0x7FFF;
|
||||
pzx->puls_duration = peek2(pzx->curblock + pzx->puls_ptr);
|
||||
pzx->puls_ptr += 2;
|
||||
}
|
||||
if (pzx->puls_duration >= 0x8000) {
|
||||
pzx->puls_duration &= 0x7FFF;
|
||||
pzx->puls_duration <<= 16;
|
||||
pzx->puls_duration |= peek2(pzx->curblock + pzx->puls_ptr);
|
||||
pzx->puls_ptr += 2;
|
||||
}
|
||||
if (!pzx->puls_count) pzx->puls_count = 1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
pzx_init(pzxfile_t *pzx)
|
||||
{
|
||||
memset(pzx, 0, sizeof(pzxfile_t));
|
||||
pzx->state = PZX_CLOSED;
|
||||
}
|
||||
|
||||
/* Load the next block from a PZX-format file.
|
||||
*
|
||||
* Returns block if successful, NULL if end of file or error
|
||||
* Caller must free the block with free(). */
|
||||
uint8_t
|
||||
*pzx_load_block(FILE *fp)
|
||||
{
|
||||
uint8_t block_header[8];
|
||||
uint8_t *block_data;
|
||||
uint32_t block_len;
|
||||
|
||||
/* The first 8 bytes of a PZX block are fixed: the first 4 give
|
||||
* the ID, the second 4 the length (excluding the header itself) */
|
||||
if (fread(block_header, 1, 8, fp) < 8)
|
||||
return NULL; /* EoF */
|
||||
|
||||
block_len = peek4(block_header + 4);
|
||||
block_data = malloc(8 + block_len);
|
||||
if (!block_data) return NULL;
|
||||
memcpy(block_data, block_header, 8);
|
||||
if (!block_len) { /* Block is only the header */
|
||||
/* CAS_LOG(("Loaded PZX block: %-4.4s\n", block_data)); */
|
||||
return block_data;
|
||||
}
|
||||
if (fread(block_data + 8, 1, block_len, fp) < block_len) {
|
||||
free(block_data); /* Unexpected EoF */
|
||||
return NULL;
|
||||
}
|
||||
/* CAS_LOG(("Loaded PZX block: %-4.4s\n", block_data)); */
|
||||
return block_data;
|
||||
}
|
||||
|
||||
|
||||
/* Search the current file for PZX version headers and check they're all 1.x */
|
||||
static wchar_t
|
||||
*pzx_check_version(FILE *fp)
|
||||
{
|
||||
uint8_t *block;
|
||||
static wchar_t message[80];
|
||||
|
||||
rewind(fp);
|
||||
while ((block = pzx_load_block(fp))) {
|
||||
if (!memcmp(block, "PZXT", 4)) {
|
||||
pzx_log("PZX version %d.%d\n", block[8], block[9]);
|
||||
if (block[8] != 1) {
|
||||
swprintf(message, 80, L"Unsupported PZX version %d.%d\n", block[8], block[9]);
|
||||
free(block);
|
||||
return message;
|
||||
}
|
||||
}
|
||||
free(block);
|
||||
}
|
||||
rewind(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
wchar_t
|
||||
*pzx_open(pzxfile_t *pzx, FILE *fp)
|
||||
{
|
||||
wchar_t *result;
|
||||
|
||||
rewind(fp);
|
||||
/* Check that this file is compatible */
|
||||
result = pzx_check_version(fp);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
pzx->level = 0;
|
||||
pzx->state = PZX_IDLE;
|
||||
pzx->input = fp;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
pzx_close(pzxfile_t *pzx)
|
||||
{
|
||||
if (pzx->input) {
|
||||
fclose(pzx->input);
|
||||
pzx->input = NULL;
|
||||
}
|
||||
if (pzx->curblock) {
|
||||
free(pzx->curblock);
|
||||
pzx->curblock = NULL;
|
||||
}
|
||||
pzx->state = PZX_CLOSED;
|
||||
}
|
||||
|
||||
/* Read the next block of type DATA, PAUS or PULS */
|
||||
int
|
||||
pzx_next_block(pzxfile_t *pzx)
|
||||
{
|
||||
long pos;
|
||||
|
||||
pos = ftell(pzx->input);
|
||||
while (pzx->state == PZX_IDLE) {
|
||||
uint8_t *blk;
|
||||
|
||||
/* In idle state there should be no current block. But
|
||||
* make sure of that */
|
||||
if (pzx->curblock) {
|
||||
free(pzx->curblock);
|
||||
pzx->curblock = NULL;
|
||||
}
|
||||
|
||||
/* Load the next block */
|
||||
blk = pzx_load_block(pzx->input);
|
||||
|
||||
/* If that didn't load we've reached the end of file; wrap to
|
||||
* beginning. */
|
||||
if (!blk) {
|
||||
rewind(pzx->input);
|
||||
blk = pzx_load_block(pzx->input);
|
||||
if (!blk) { /* Couldn't even load first block */
|
||||
pzx_close(pzx);
|
||||
return 0;
|
||||
}
|
||||
/* Have we read the whole file and come back to where
|
||||
* we were? */
|
||||
if (ftell(pzx->input) == pos) {
|
||||
free(blk);
|
||||
pzx_close(pzx);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* We have loaded the next block. What is it? */
|
||||
if (!memcmp(blk, "PULS", 4)) {
|
||||
pzx->state = PZX_IN_PULS;
|
||||
pzx->curblock = blk;
|
||||
pzx->puls_len = 8 + peek4(blk + 4);
|
||||
pzx->puls_ptr = 8;
|
||||
pzx->puls_count = 0;
|
||||
pzx->puls_remain = 0;
|
||||
pzx->puls_duration = 0;
|
||||
pzx->level = 0;
|
||||
pzx_log("Beginning PULS block\n");
|
||||
}
|
||||
else if (!memcmp(blk, "PAUS", 4)) {
|
||||
pzx->state = PZX_IN_PAUS;
|
||||
pzx->curblock = blk;
|
||||
pzx->paus_remain = peek4(blk + 8);
|
||||
pzx->level = (pzx->paus_remain >> 31);
|
||||
pzx->paus_remain &= 0x7FFFFFFF;
|
||||
pzx_log("Beginning PAUS block, duration=%d\n",
|
||||
pzx->paus_remain);
|
||||
}
|
||||
else if (!memcmp(blk, "DATA", 4)) {
|
||||
pzx->state = PZX_IN_DATA;
|
||||
pzx->curblock = blk;
|
||||
pzx->data_bits = peek4(blk + 8);
|
||||
pzx->level = (pzx->data_bits >> 31);
|
||||
pzx->data_bits &= 0x7FFFFFFF;
|
||||
pzx->data_tail = peek2(blk + 12);
|
||||
pzx->data_p0 = blk[14];
|
||||
pzx->data_p1 = blk[15];
|
||||
pzx->data_p = 0;
|
||||
pzx->data_w = 16;
|
||||
pzx->data_remain = 0;
|
||||
pzx->data_ptr = 16 + 2 * (pzx->data_p0 + pzx->data_p1);
|
||||
pzx->data_mask = 0x80;
|
||||
pzx_log("Beginning DATA block, length=%d p0=%d p1=%d"
|
||||
" data_ptr=%d\n",
|
||||
pzx->data_bits,
|
||||
pzx->data_p0, pzx->data_p1,
|
||||
pzx->data_ptr);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
pzx_endblock(pzxfile_t *pzx)
|
||||
{
|
||||
if (pzx->curblock)
|
||||
free(pzx->curblock);
|
||||
pzx->curblock = NULL;
|
||||
pzx->state = PZX_IDLE;
|
||||
}
|
||||
|
||||
/* PAUS is easy - just run the timer down */
|
||||
static int
|
||||
pzx_advance_paus(pzxfile_t *pzx, int time)
|
||||
{
|
||||
if (pzx->paus_remain > time) {
|
||||
pzx->paus_remain -= time;
|
||||
return 0;
|
||||
}
|
||||
time -= pzx->paus_remain;
|
||||
pzx_endblock(pzx);
|
||||
return time;
|
||||
}
|
||||
|
||||
static int
|
||||
pzx_advance_puls(pzxfile_t *pzx, int time)
|
||||
{
|
||||
/* At the start of a pulse sequence? */
|
||||
if (pzx->puls_count == 0) {
|
||||
pzx_parse_pulse(pzx);
|
||||
pzx->puls_remain = pzx->puls_duration;
|
||||
}
|
||||
/* Does sample trigger a pulse change? If not, that's easy. */
|
||||
if (time < pzx->puls_remain) {
|
||||
pzx->puls_remain -= time;
|
||||
return 0;
|
||||
}
|
||||
/* Sample does trigger a pulse change */
|
||||
time -= pzx->puls_remain;
|
||||
/* If there's another pulse in the current sequence, that's
|
||||
* straightforward; just flip the level and continue */
|
||||
--pzx->puls_count;
|
||||
pzx->level = !pzx->level;
|
||||
if (pzx->puls_count) {
|
||||
pzx->puls_remain = pzx->puls_duration;
|
||||
return time;
|
||||
}
|
||||
/* If we've reached the end of the pulse sequence, there may be
|
||||
* another one */
|
||||
if (pzx->puls_ptr < pzx->puls_len) {
|
||||
return time;
|
||||
}
|
||||
/* If there isn't another one, it's the end of the block */
|
||||
pzx_endblock(pzx);
|
||||
return time;
|
||||
}
|
||||
|
||||
/* Decode a DATA block */
|
||||
static int
|
||||
pzx_advance_data(pzxfile_t *pzx, int time)
|
||||
{
|
||||
uint8_t bit;
|
||||
|
||||
/* Reached end of data? */
|
||||
if (pzx->data_bits == 0) {
|
||||
/* Time interval is covered by the tail bit */
|
||||
if (pzx->data_tail > time) {
|
||||
pzx->data_tail -= time;
|
||||
return 0;
|
||||
}
|
||||
/* Have run out of block */
|
||||
time -= pzx->data_tail;
|
||||
pzx_endblock(pzx);
|
||||
return time;
|
||||
}
|
||||
/* No more time remaining on the current bit? */
|
||||
if (pzx->data_p < 1 && !pzx->data_remain) {
|
||||
bit = pzx->curblock[pzx->data_ptr] & pzx->data_mask;
|
||||
pzx->data_mask >>= 1;
|
||||
if (!pzx->data_mask) {
|
||||
pzx->data_mask = 0x80;
|
||||
++pzx->data_ptr;
|
||||
}
|
||||
--pzx->data_bits;
|
||||
|
||||
if (bit) {
|
||||
pzx->data_p = pzx->data_p1;
|
||||
pzx->data_w = 16 + 2 * pzx->data_p0;
|
||||
pzx->data_remain = 0;
|
||||
} else {
|
||||
pzx->data_p = pzx->data_p0;
|
||||
pzx->data_w = 16;
|
||||
pzx->data_remain = 0;
|
||||
}
|
||||
}
|
||||
/* See if we've started processing the current waveform. If not,
|
||||
* load its first element (assuming that there is one) */
|
||||
if (!pzx->data_remain) {
|
||||
if (pzx->data_p) {
|
||||
pzx->data_remain = peek2(pzx->curblock + pzx->data_w);
|
||||
pzx->data_w += 2;
|
||||
pzx->data_p--;
|
||||
}
|
||||
}
|
||||
if (pzx->data_remain > time) {
|
||||
/* Time advance is contained within current wave */
|
||||
pzx->data_remain -= time;
|
||||
return 0;
|
||||
} else { /* Move on to next element of wave / next bit / next block */
|
||||
time -= pzx->data_remain;
|
||||
pzx->data_remain = 0;
|
||||
pzx->level = !pzx->level;
|
||||
}
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
int
|
||||
pzx_advance(pzxfile_t *pzx, int time)
|
||||
{
|
||||
if (pzx->state == PZX_CLOSED)
|
||||
return 0; /* No tape loaded */
|
||||
|
||||
while (time) {
|
||||
switch (pzx->state)
|
||||
{
|
||||
case PZX_IDLE:
|
||||
if (!pzx_next_block(pzx)) return 0;
|
||||
break;
|
||||
case PZX_IN_PULS:
|
||||
time = pzx_advance_puls(pzx, time);
|
||||
break;
|
||||
case PZX_IN_PAUS:
|
||||
time = pzx_advance_paus(pzx, time);
|
||||
break;
|
||||
case PZX_IN_DATA:
|
||||
time = pzx_advance_data(pzx, time);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return pzx->level;
|
||||
}
|
||||
|
||||
|
||||
|
||||
71
src/cassette/pzx.h
Normal file
71
src/cassette/pzx.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/************************************************************************
|
||||
|
||||
PCEM: IBM 5150 cassette support
|
||||
|
||||
Copyright (C) 2019 John Elliott <seasip.webmaster@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*************************************************************************/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PZX_CLOSED, /* File is not open */
|
||||
PZX_IDLE, /* File is open, no block loaded */
|
||||
PZX_IN_PULS, /* File is open, current block is a PULS block */
|
||||
PZX_IN_DATA, /* File is open, current block is a DATA block */
|
||||
PZX_IN_PAUS, /* File is open, current block is a PAUS block */
|
||||
} PZX_STATE;
|
||||
|
||||
|
||||
typedef struct pzxfile_t
|
||||
{
|
||||
FILE *input; /* Input PZX file */
|
||||
uint8_t *curblock; /* Currently-loaded block, if any */
|
||||
int level; /* Current signal level */
|
||||
PZX_STATE state; /* State machine current status */
|
||||
/* State variables for PULS */
|
||||
uint32_t puls_ptr; /* Pointer within PULS block */
|
||||
uint32_t puls_len; /* Length of PULS block */
|
||||
uint32_t puls_count; /* Count of pulses */
|
||||
uint32_t puls_duration; /* Duration of each pulse */
|
||||
uint32_t puls_remain; /* Time remaining in this pulse */
|
||||
/* State variables for PAUS */
|
||||
uint32_t paus_remain; /* Time remaining in this pause */
|
||||
/* State variables for DATA */
|
||||
uint32_t data_ptr; /* Pointer within DATA block */
|
||||
uint32_t data_bits; /* Count of bits */
|
||||
uint16_t data_tail; /* Length of pulse after last bit */
|
||||
uint8_t data_mask; /* Mask for current bit */
|
||||
uint8_t data_p0; /* Length of 0 encoding */
|
||||
uint8_t data_p1; /* Length of 1 encoding */
|
||||
int data_p; /* Current sequence being emitted */
|
||||
uint32_t data_w; /* Current waveform */
|
||||
uint32_t data_remain; /* Current data pulse time remaining */
|
||||
} pzxfile_t;
|
||||
|
||||
uint8_t *pzx_load_block(FILE *fp);
|
||||
|
||||
/* Initialise structure */
|
||||
void pzx_init(pzxfile_t *pzx);
|
||||
|
||||
/* Open file for input */
|
||||
wchar_t *pzx_open(pzxfile_t *pzx, FILE *fp);
|
||||
|
||||
/* Close file */
|
||||
void pzx_close(pzxfile_t *pzx);
|
||||
|
||||
/* Advance by 'time' samples (3.5MHz sample rate) and return current state */
|
||||
int pzx_advance(pzxfile_t *pzx, int time);
|
||||
3849
src/cdrom/cdrom.c
3849
src/cdrom/cdrom.c
File diff suppressed because it is too large
Load Diff
@@ -6,14 +6,13 @@
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Implementation of the CD-ROM drive with SCSI(-like)
|
||||
* commands, for both ATAPI and SCSI usage.
|
||||
* Generic CD-ROM drive core header.
|
||||
*
|
||||
* Version: @(#)cdrom.h 1.0.13 2018/06/18
|
||||
* Version: @(#)cdrom.h 1.0.18 2019/09/26
|
||||
*
|
||||
* Author: Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2016,2017 Miran Grca.
|
||||
* Copyright 2016-2019 Miran Grca.
|
||||
*/
|
||||
#ifndef EMU_CDROM_H
|
||||
#define EMU_CDROM_H
|
||||
@@ -23,26 +22,38 @@
|
||||
|
||||
#define CD_STATUS_EMPTY 0
|
||||
#define CD_STATUS_DATA_ONLY 1
|
||||
#define CD_STATUS_PLAYING 2
|
||||
#define CD_STATUS_PAUSED 3
|
||||
#define CD_STATUS_PAUSED 2
|
||||
#define CD_STATUS_PLAYING 3
|
||||
#define CD_STATUS_STOPPED 4
|
||||
#define CD_STATUS_PLAYING_COMPLETED 5
|
||||
|
||||
#define CDROM_PHASE_IDLE 0x00
|
||||
#define CDROM_PHASE_COMMAND 0x01
|
||||
#define CDROM_PHASE_COMPLETE 0x02
|
||||
#define CDROM_PHASE_DATA_IN 0x03
|
||||
#define CDROM_PHASE_DATA_IN_DMA 0x04
|
||||
#define CDROM_PHASE_DATA_OUT 0x05
|
||||
#define CDROM_PHASE_DATA_OUT_DMA 0x06
|
||||
#define CDROM_PHASE_ERROR 0x80
|
||||
/* Medium changed flag. */
|
||||
#define CD_STATUS_MEDIUM_CHANGED 0x80
|
||||
|
||||
#define CD_TRACK_AUDIO 0x08
|
||||
#define CD_TRACK_MODE2 0x04
|
||||
|
||||
#define CD_READ_DATA 0
|
||||
#define CD_READ_AUDIO 1
|
||||
#define CD_READ_RAW 2
|
||||
|
||||
#define CD_TOC_NORMAL 0
|
||||
#define CD_TOC_SESSION 1
|
||||
#define CD_TOC_RAW 2
|
||||
|
||||
#define BUF_SIZE 32768
|
||||
|
||||
#define CDROM_IMAGE 200
|
||||
|
||||
#define CDROM_TIME (5LL * 100LL * (1LL << TIMER_SHIFT))
|
||||
/* This is so that if/when this is changed to something else,
|
||||
changing this one define will be enough. */
|
||||
#define CDROM_EMPTY !dev->host_drive
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
CDROM_BUS_DISABLED = 0,
|
||||
CDROM_BUS_ATAPI = 4,
|
||||
@@ -51,138 +62,105 @@ enum {
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
int (*ready)(uint8_t id);
|
||||
int (*medium_changed)(uint8_t id);
|
||||
int (*media_type_id)(uint8_t id);
|
||||
/* To shut up the GCC compilers. */
|
||||
struct cdrom;
|
||||
|
||||
int (*audio_callback)(uint8_t id, int16_t *output, int len);
|
||||
void (*audio_stop)(uint8_t id);
|
||||
int (*readtoc)(uint8_t id, uint8_t *b, uint8_t starttrack, int msf, int maxlen, int single);
|
||||
int (*readtoc_session)(uint8_t id, uint8_t *b, int msf, int maxlen);
|
||||
int (*readtoc_raw)(uint8_t id, uint8_t *b, int maxlen);
|
||||
uint8_t (*getcurrentsubchannel)(uint8_t id, uint8_t *b, int msf);
|
||||
int (*readsector_raw)(uint8_t id, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type, int cdrom_sector_flags, int *len);
|
||||
uint8_t (*playaudio)(uint8_t id, uint32_t pos, uint32_t len, int ismsf);
|
||||
void (*pause)(uint8_t id);
|
||||
void (*resume)(uint8_t id);
|
||||
uint32_t (*size)(uint8_t id);
|
||||
int (*status)(uint8_t id);
|
||||
void (*stop)(uint8_t id);
|
||||
void (*exit)(uint8_t id);
|
||||
} CDROM;
|
||||
|
||||
typedef struct {
|
||||
int host_drive;
|
||||
int prev_host_drive;
|
||||
uint8_t attr, track,
|
||||
index,
|
||||
abs_m, abs_s, abs_f,
|
||||
rel_m, rel_s, rel_f;
|
||||
} subchannel_t;
|
||||
|
||||
unsigned int bus_type; /* 0 = ATAPI, 1 = SCSI */
|
||||
typedef struct {
|
||||
int number;
|
||||
uint8_t attr, m, s, f;
|
||||
} track_info_t;
|
||||
|
||||
uint8_t speed, ide_channel,
|
||||
bus_mode; /* Bit 0 = PIO suported;
|
||||
/* Define the various CD-ROM drive operations (ops). */
|
||||
typedef struct {
|
||||
void (*get_tracks)(struct cdrom *dev, int *first, int *last);
|
||||
void (*get_track_info)(struct cdrom *dev, uint32_t track, int end, track_info_t *ti);
|
||||
void (*get_subchannel)(struct cdrom *dev, uint32_t lba, subchannel_t *subc);
|
||||
int (*sector_size)(struct cdrom *dev, uint32_t lba);
|
||||
int (*read_sector)(struct cdrom *dev, int type, uint8_t *b, uint32_t lba);
|
||||
int (*track_type)(struct cdrom *dev, uint32_t lba);
|
||||
void (*exit)(struct cdrom *dev);
|
||||
} cdrom_ops_t;
|
||||
|
||||
typedef struct cdrom {
|
||||
uint8_t id,
|
||||
res, res0, /* Reserved for other ID's. */
|
||||
res1,
|
||||
ide_channel, scsi_device_id,
|
||||
bus_type, /* 0 = ATAPI, 1 = SCSI */
|
||||
bus_mode, /* Bit 0 = PIO suported;
|
||||
Bit 1 = DMA supportd. */
|
||||
cd_status, /* Struct variable reserved for
|
||||
media status. */
|
||||
speed, cur_speed;
|
||||
|
||||
unsigned int scsi_device_id, sound_on;
|
||||
} cdrom_drive_t;
|
||||
FILE* img_fp;
|
||||
void *priv;
|
||||
|
||||
typedef struct {
|
||||
mode_sense_pages_t ms_pages_saved;
|
||||
wchar_t image_path[1024],
|
||||
prev_image_path[1024];
|
||||
|
||||
CDROM *handler;
|
||||
cdrom_drive_t *drv;
|
||||
uint32_t sound_on, cdrom_capacity,
|
||||
pad, seek_pos,
|
||||
seek_diff, cd_end;
|
||||
|
||||
uint8_t previous_command,
|
||||
error, features,
|
||||
status, phase,
|
||||
id, *buffer,
|
||||
atapi_cdb[16],
|
||||
current_cdb[16],
|
||||
sense[256];
|
||||
int host_drive, prev_host_drive,
|
||||
cd_buflen;
|
||||
|
||||
const cdrom_ops_t *ops;
|
||||
|
||||
void *image;
|
||||
|
||||
void (*insert)(void *p);
|
||||
void (*close)(void *p);
|
||||
uint32_t (*get_volume)(void *p, int channel);
|
||||
uint32_t (*get_channel)(void *p, int channel);
|
||||
|
||||
uint16_t request_length, max_transfer_len;
|
||||
int16_t cd_buffer[BUF_SIZE];
|
||||
|
||||
int media_status, is_dma,
|
||||
packet_status, requested_blocks,
|
||||
current_page_len, current_page_pos,
|
||||
mode_select_phase, do_page_save,
|
||||
total_length, written_length,
|
||||
callback, data_pos,
|
||||
cd_status, prev_status,
|
||||
unit_attention, request_pos,
|
||||
total_read, cur_speed,
|
||||
block_total, all_blocks_total,
|
||||
old_len, block_descriptor_len,
|
||||
init_length, last_subchannel_pos,
|
||||
cd_buflen, cd_state,
|
||||
handler_inited, disc_changed;
|
||||
|
||||
uint32_t sector_pos, sector_len,
|
||||
seek_pos, seek_diff,
|
||||
pos, packet_len,
|
||||
cdb_len, cd_end,
|
||||
cdrom_capacity;
|
||||
|
||||
uint64_t current_page_code;
|
||||
} cdrom_t;
|
||||
|
||||
typedef struct {
|
||||
int image_is_iso;
|
||||
wchar_t image_path[1024],
|
||||
*prev_image_path;
|
||||
FILE* image;
|
||||
} cdrom_image_t;
|
||||
|
||||
|
||||
extern cdrom_t *cdrom[CDROM_NUM];
|
||||
extern cdrom_drive_t cdrom_drives[CDROM_NUM];
|
||||
extern cdrom_image_t cdrom_image[CDROM_NUM];
|
||||
extern uint8_t atapi_cdrom_drives[8];
|
||||
extern uint8_t scsi_cdrom_drives[16];
|
||||
|
||||
#define cdrom_sense_error dev->sense[0]
|
||||
#define cdrom_sense_key dev->sense[2]
|
||||
#define cdrom_asc dev->sense[12]
|
||||
#define cdrom_ascq dev->sense[13]
|
||||
#define cdrom_drive cdrom_drives[id].host_drive
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length, void *priv);
|
||||
extern int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length, void *priv);
|
||||
extern void (*ide_bus_master_set_irq)(int channel, void *priv);
|
||||
extern void *ide_bus_master_priv[2];
|
||||
|
||||
extern uint32_t cdrom_mode_sense_get_channel(cdrom_t *dev, int channel);
|
||||
extern uint32_t cdrom_mode_sense_get_volume(cdrom_t *dev, int channel);
|
||||
extern void build_atapi_cdrom_map(void);
|
||||
extern void build_scsi_cdrom_map(void);
|
||||
extern int cdrom_CDROM_PHASE_to_scsi(cdrom_t *dev);
|
||||
extern int cdrom_atapi_phase_to_scsi(cdrom_t *dev);
|
||||
extern void cdrom_command(cdrom_t *dev, uint8_t *cdb);
|
||||
extern void cdrom_phase_callback(cdrom_t *dev);
|
||||
extern uint32_t cdrom_read(uint8_t channel, int length);
|
||||
extern void cdrom_write(uint8_t channel, uint32_t val, int length);
|
||||
extern cdrom_t cdrom[CDROM_NUM];
|
||||
|
||||
extern int cdrom_lba_to_msf_accurate(int lba);
|
||||
extern double cdrom_seek_time(cdrom_t *dev);
|
||||
extern void cdrom_stop(cdrom_t *dev);
|
||||
extern int cdrom_audio_callback(cdrom_t *dev, int16_t *output, int len);
|
||||
extern uint8_t cdrom_audio_play(cdrom_t *dev, uint32_t pos, uint32_t len, int ismsf);
|
||||
extern void cdrom_audio_pause_resume(cdrom_t *dev, uint8_t resume);
|
||||
extern uint8_t cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, int msf);
|
||||
extern int cdrom_read_toc(cdrom_t *dev, unsigned char *b, int type,
|
||||
unsigned char start_track, int msf, int max_len);
|
||||
extern int cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, int sector, int ismsf,
|
||||
int cdrom_sector_type, int cdrom_sector_flags, int *len);
|
||||
extern void cdrom_seek(cdrom_t *dev, uint32_t pos);
|
||||
|
||||
extern void cdrom_close_handler(uint8_t id);
|
||||
extern void cdrom_close(void);
|
||||
extern void cdrom_reset(cdrom_t *dev);
|
||||
extern void cdrom_set_signature(cdrom_t *dev);
|
||||
extern void cdrom_request_sense_for_scsi(cdrom_t *dev, uint8_t *buffer, uint8_t alloc_length);
|
||||
extern void cdrom_update_cdb(uint8_t *cdb, int lba_pos, int number_of_blocks);
|
||||
extern void cdrom_insert(cdrom_t *dev);
|
||||
extern void cdrom_insert(uint8_t id);
|
||||
extern void cdrom_eject(uint8_t id);
|
||||
extern void cdrom_reload(uint8_t id);
|
||||
|
||||
extern int cdrom_image_open(cdrom_t *dev, const wchar_t *fn);
|
||||
extern void cdrom_image_close(cdrom_t *dev);
|
||||
extern void cdrom_image_reset(cdrom_t *dev);
|
||||
|
||||
extern void cdrom_update_cdb(uint8_t *cdb, int lba_pos,
|
||||
int number_of_blocks);
|
||||
|
||||
extern int find_cdrom_for_scsi_id(uint8_t scsi_id);
|
||||
extern int cdrom_read_capacity(cdrom_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len);
|
||||
|
||||
extern void cdrom_close(void);
|
||||
extern void cdrom_global_init(void);
|
||||
extern void cdrom_global_reset(void);
|
||||
extern void cdrom_hard_reset(void);
|
||||
extern void scsi_cdrom_drive_reset(int c);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -1,655 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2015 The DOSBox Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* Modified for use with PCem by bit */
|
||||
|
||||
#define _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#ifdef _WIN32
|
||||
//FIXME: should not be needed. */
|
||||
# define _GNU_SOURCE
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <cctype>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <limits.h> //GCC 2.95
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <sys/stat.h>
|
||||
#include "../plat.h"
|
||||
#include "cdrom_dosbox.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <libgen.h>
|
||||
#else
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define MAX_LINE_LENGTH 512
|
||||
#define MAX_FILENAME_LENGTH 256
|
||||
#define CROSS_LEN 512
|
||||
|
||||
#define safe_strncpy(a,b,n) do { strncpy((a),(b),(n)-1); (a)[(n)-1] = 0; } while (0)
|
||||
|
||||
CDROM_Interface_Image::BinaryFile::BinaryFile(const char *filename, bool &error)
|
||||
{
|
||||
memset(fn, 0, sizeof(fn));
|
||||
strcpy(fn, filename);
|
||||
file = fopen64(fn, "rb");
|
||||
if (file == NULL)
|
||||
error = true;
|
||||
else
|
||||
error = false;
|
||||
}
|
||||
|
||||
CDROM_Interface_Image::BinaryFile::~BinaryFile()
|
||||
{
|
||||
fclose(file);
|
||||
file = NULL;
|
||||
memset(fn, 0, sizeof(fn));
|
||||
}
|
||||
|
||||
bool CDROM_Interface_Image::BinaryFile::read(Bit8u *buffer, uint64_t seek, uint64_t count)
|
||||
{
|
||||
fseeko64(file, seek, SEEK_SET);
|
||||
fread(buffer, 1, count, file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint64_t CDROM_Interface_Image::BinaryFile::getLength()
|
||||
{
|
||||
fseeko64(file, 0, SEEK_END);
|
||||
return ftello64(file);
|
||||
}
|
||||
|
||||
CDROM_Interface_Image::CDROM_Interface_Image()
|
||||
{
|
||||
// printf("CDROM_Interface_Image constructor\n");
|
||||
}
|
||||
|
||||
CDROM_Interface_Image::~CDROM_Interface_Image()
|
||||
{
|
||||
// printf("CDROM_Interface_Image destructor\n");
|
||||
ClearTracks();
|
||||
}
|
||||
|
||||
void CDROM_Interface_Image::InitNewMedia()
|
||||
{
|
||||
}
|
||||
|
||||
bool CDROM_Interface_Image::SetDevice(char* path, int forceCD)
|
||||
{
|
||||
(void)forceCD;
|
||||
if (LoadCueSheet(path)) return true;
|
||||
if (LoadIsoFile(path)) return true;
|
||||
|
||||
// print error message on dosbox console
|
||||
//printf("Could not load image file: %s\n", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CDROM_Interface_Image::GetUPC(unsigned char& attr, char* upc)
|
||||
{
|
||||
attr = 0;
|
||||
strcpy(upc, this->mcn.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDROM_Interface_Image::GetAudioTracks(int& stTrack, int& end, TMSF& leadOut)
|
||||
{
|
||||
stTrack = 1;
|
||||
end = (int)(tracks.size() - 1);
|
||||
FRAMES_TO_MSF(tracks[tracks.size() - 1].start + 150, &leadOut.min, &leadOut.sec, &leadOut.fr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDROM_Interface_Image::GetAudioTrackInfo(int track, int& track_number, TMSF& start, unsigned char& attr)
|
||||
{
|
||||
if (track < 1 || track > (int)tracks.size()) return false;
|
||||
FRAMES_TO_MSF(tracks[track - 1].start + 150, &start.min, &start.sec, &start.fr);
|
||||
track_number = tracks[track - 1].track_number;
|
||||
attr = tracks[track - 1].attr;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDROM_Interface_Image::GetAudioSub(int sector, unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos)
|
||||
{
|
||||
int cur_track = GetTrack(sector);
|
||||
if (cur_track < 1) return false;
|
||||
track = (unsigned char)cur_track;
|
||||
attr = tracks[track - 1].attr;
|
||||
index = 1;
|
||||
FRAMES_TO_MSF(sector + 150, &absPos.min, &absPos.sec, &absPos.fr);
|
||||
/* FRAMES_TO_MSF(sector - tracks[track - 1].start + 150, &relPos.min, &relPos.sec, &relPos.fr); */
|
||||
/* Note by Kotori: Yes, the absolute position should be adjusted by 150, but not the relative position. */
|
||||
FRAMES_TO_MSF(sector - tracks[track - 1].start, &relPos.min, &relPos.sec, &relPos.fr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDROM_Interface_Image::GetMediaTrayStatus(bool& mediaPresent, bool& mediaChanged, bool& trayOpen)
|
||||
{
|
||||
mediaPresent = true;
|
||||
mediaChanged = false;
|
||||
trayOpen = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDROM_Interface_Image::ReadSectors(PhysPt buffer, bool raw, unsigned long sector, unsigned long num)
|
||||
{
|
||||
int sectorSize = raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE;
|
||||
Bitu buflen = num * sectorSize;
|
||||
Bit8u* buf = new Bit8u[buflen];
|
||||
|
||||
bool success = true; //Gobliiins reads 0 sectors
|
||||
for(unsigned long i = 0; i < num; i++) {
|
||||
success = ReadSector(&buf[i * sectorSize], raw, sector + i);
|
||||
if (!success) break;
|
||||
}
|
||||
|
||||
memcpy((void*)buffer, buf, buflen);
|
||||
delete[] buf;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool CDROM_Interface_Image::LoadUnloadMedia(bool unload)
|
||||
{
|
||||
(void)unload;
|
||||
return true;
|
||||
}
|
||||
|
||||
int CDROM_Interface_Image::GetTrack(unsigned int sector)
|
||||
{
|
||||
vector<Track>::iterator i = tracks.begin();
|
||||
vector<Track>::iterator end = tracks.end() - 1;
|
||||
|
||||
while(i != end) {
|
||||
Track &curr = *i;
|
||||
Track &next = *(i + 1);
|
||||
if (curr.start <= sector && sector < next.start) return curr.number;
|
||||
i++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool CDROM_Interface_Image::ReadSector(Bit8u *buffer, bool raw, unsigned long sector)
|
||||
{
|
||||
uint64_t length;
|
||||
|
||||
int track = GetTrack(sector) - 1;
|
||||
if (track < 0) return false;
|
||||
|
||||
uint64_t s = (uint64_t) sector;
|
||||
uint64_t seek = tracks[track].skip + ((s - tracks[track].start) * tracks[track].sectorSize);
|
||||
if (tracks[track].mode2)
|
||||
length = (raw ? RAW_SECTOR_SIZE : 2336);
|
||||
else
|
||||
length = (raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE);
|
||||
if (tracks[track].sectorSize != RAW_SECTOR_SIZE && raw) return false;
|
||||
if (tracks[track].sectorSize == RAW_SECTOR_SIZE && !tracks[track].mode2 && !raw) seek += 16;
|
||||
if (tracks[track].mode2 && !raw) seek += 24;
|
||||
|
||||
return tracks[track].file->read(buffer, seek, length);
|
||||
}
|
||||
|
||||
bool CDROM_Interface_Image::ReadSectorSub(Bit8u *buffer, unsigned long sector)
|
||||
{
|
||||
int track = GetTrack(sector) - 1;
|
||||
if (track < 0) return false;
|
||||
|
||||
uint64_t s = (uint64_t) sector;
|
||||
uint64_t seek = tracks[track].skip + ((s - tracks[track].start) * tracks[track].sectorSize);
|
||||
if (tracks[track].sectorSize != 2448) return false;
|
||||
|
||||
return tracks[track].file->read(buffer, seek, 2448);
|
||||
}
|
||||
|
||||
int CDROM_Interface_Image::GetSectorSize(unsigned long sector)
|
||||
{
|
||||
int track = GetTrack(sector) - 1;
|
||||
if (track < 0) return 0;
|
||||
|
||||
return tracks[track].sectorSize;
|
||||
}
|
||||
|
||||
bool CDROM_Interface_Image::IsMode2(unsigned long sector)
|
||||
{
|
||||
int track = GetTrack(sector) - 1;
|
||||
if (track < 0) return false;
|
||||
|
||||
if (tracks[track].mode2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int CDROM_Interface_Image::GetMode2Form(unsigned long sector)
|
||||
{
|
||||
int track = GetTrack(sector) - 1;
|
||||
if (track < 0) return false;
|
||||
|
||||
return tracks[track].form;
|
||||
}
|
||||
|
||||
bool CDROM_Interface_Image::LoadIsoFile(char* filename)
|
||||
{
|
||||
tracks.clear();
|
||||
|
||||
// data track
|
||||
Track track = {0, 0, 0, 0, 0, 0, 0, 0, false, NULL};
|
||||
bool error;
|
||||
track.file = new BinaryFile(filename, error);
|
||||
if (error) {
|
||||
delete track.file;
|
||||
return false;
|
||||
}
|
||||
track.number = 1;
|
||||
track.track_number = 1;//IMPORTANT: This is needed.
|
||||
track.attr = DATA_TRACK;//data
|
||||
track.form = 0;
|
||||
|
||||
// try to detect iso type
|
||||
if (CanReadPVD(track.file, COOKED_SECTOR_SIZE, false)) {
|
||||
track.sectorSize = COOKED_SECTOR_SIZE;
|
||||
track.mode2 = false;
|
||||
} else if (CanReadPVD(track.file, RAW_SECTOR_SIZE, false)) {
|
||||
track.sectorSize = RAW_SECTOR_SIZE;
|
||||
track.mode2 = false;
|
||||
} else if (CanReadPVD(track.file, 2324, true)) {
|
||||
track.sectorSize = 2324;
|
||||
track.form = 2;
|
||||
track.mode2 = true;
|
||||
} else if (CanReadPVD(track.file, 2336, true)) {
|
||||
track.sectorSize = 2336;
|
||||
track.mode2 = true;
|
||||
} else if (CanReadPVD(track.file, RAW_SECTOR_SIZE, true)) {
|
||||
track.sectorSize = RAW_SECTOR_SIZE;
|
||||
track.mode2 = true;
|
||||
} else {
|
||||
/* Unknown mode: Assume regular 2048-byte sectors, this is needed so Apple Rhapsody ISO's can be mounted. */
|
||||
track.sectorSize = COOKED_SECTOR_SIZE;
|
||||
track.mode2 = false;
|
||||
}
|
||||
|
||||
track.length = track.file->getLength() / track.sectorSize;
|
||||
tracks.push_back(track);
|
||||
|
||||
// leadout track
|
||||
track.number = 2;
|
||||
track.track_number = 0xAA;
|
||||
track.attr = 0x16; /* Was 0x00 but I believe 0x16 is appropriate. */
|
||||
track.start = track.length;
|
||||
track.length = 0;
|
||||
track.file = NULL;
|
||||
tracks.push_back(track);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDROM_Interface_Image::CanReadPVD(TrackFile *file, uint64_t sectorSize, bool mode2)
|
||||
{
|
||||
Bit8u pvd[COOKED_SECTOR_SIZE];
|
||||
uint64_t seek = 16 * sectorSize; // first vd is located at sector 16
|
||||
if (sectorSize == RAW_SECTOR_SIZE && !mode2) seek += 16;
|
||||
if (mode2) seek += 24;
|
||||
file->read(pvd, seek, COOKED_SECTOR_SIZE);
|
||||
// pvd[0] = descriptor type, pvd[1..5] = standard identifier, pvd[6] = iso version (+8 for High Sierra)
|
||||
return ((pvd[0] == 1 && !strncmp((char*)(&pvd[1]), "CD001", 5) && pvd[6] == 1) ||
|
||||
(pvd[8] == 1 && !strncmp((char*)(&pvd[9]), "CDROM", 5) && pvd[14] == 1));
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static string dirname(char * file) {
|
||||
char * sep = strrchr(file, '\\');
|
||||
if (sep == NULL)
|
||||
sep = strrchr(file, '/');
|
||||
if (sep == NULL)
|
||||
return "";
|
||||
else {
|
||||
int len = (int)(sep - file);
|
||||
char tmp[MAX_FILENAME_LENGTH];
|
||||
safe_strncpy(tmp, file, len+1);
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool CDROM_Interface_Image::LoadCueSheet(char *cuefile)
|
||||
{
|
||||
Track track = {0, 0, 0, 0, 0, 0, 0, 0, false, NULL};
|
||||
tracks.clear();
|
||||
uint64_t shift = 0;
|
||||
uint64_t currPregap = 0;
|
||||
uint64_t totalPregap = 0;
|
||||
uint64_t prestart = 0;
|
||||
bool success;
|
||||
bool canAddTrack = false;
|
||||
char tmp[MAX_FILENAME_LENGTH]; // dirname can change its argument
|
||||
safe_strncpy(tmp, cuefile, MAX_FILENAME_LENGTH);
|
||||
string pathname(dirname(tmp));
|
||||
ifstream in;
|
||||
in.open(cuefile, ios::in);
|
||||
if (in.fail()) return false;
|
||||
|
||||
while(!in.eof()) {
|
||||
// get next line
|
||||
char buf[MAX_LINE_LENGTH];
|
||||
in.getline(buf, MAX_LINE_LENGTH);
|
||||
if (in.fail() && !in.eof()) return false; // probably a binary file
|
||||
istringstream line(buf);
|
||||
|
||||
string command;
|
||||
GetCueKeyword(command, line);
|
||||
|
||||
if (command == "TRACK") {
|
||||
if (canAddTrack) success = AddTrack(track, shift, prestart, totalPregap, currPregap);
|
||||
else success = true;
|
||||
|
||||
track.start = 0;
|
||||
track.skip = 0;
|
||||
currPregap = 0;
|
||||
prestart = 0;
|
||||
|
||||
line >> track.number;
|
||||
track.track_number = track.number;
|
||||
string type;
|
||||
GetCueKeyword(type, line);
|
||||
|
||||
track.form = 0;
|
||||
|
||||
if (type == "AUDIO") {
|
||||
track.sectorSize = RAW_SECTOR_SIZE;
|
||||
track.attr = AUDIO_TRACK;
|
||||
track.mode2 = false;
|
||||
} else if (type == "MODE1/2048") {
|
||||
track.sectorSize = COOKED_SECTOR_SIZE;
|
||||
track.attr = DATA_TRACK;
|
||||
track.mode2 = false;
|
||||
} else if (type == "MODE1/2352") {
|
||||
track.sectorSize = RAW_SECTOR_SIZE;
|
||||
track.attr = DATA_TRACK;
|
||||
track.mode2 = false;
|
||||
} else if (type == "MODE2/2048") {
|
||||
track.form = 1;
|
||||
track.sectorSize = 2048;
|
||||
track.attr = DATA_TRACK;
|
||||
track.mode2 = true;
|
||||
} else if (type == "MODE2/2324") {
|
||||
track.form = 2;
|
||||
track.sectorSize = 2324;
|
||||
track.attr = DATA_TRACK;
|
||||
track.mode2 = true;
|
||||
} else if (type == "MODE2/2336") {
|
||||
track.sectorSize = 2336;
|
||||
track.attr = DATA_TRACK;
|
||||
track.mode2 = true;
|
||||
} else if (type == "MODE2/2352") {
|
||||
track.form = 1; /* Assume this is XA Mode 2 Form 1. */
|
||||
track.sectorSize = RAW_SECTOR_SIZE;
|
||||
track.attr = DATA_TRACK;
|
||||
track.mode2 = true;
|
||||
} else if (type == "CDG/2448") {
|
||||
track.sectorSize = 2448;
|
||||
track.attr = DATA_TRACK;
|
||||
track.mode2 = true;
|
||||
} else if (type == "CDI/2336") {
|
||||
track.sectorSize = 2336;
|
||||
track.attr = DATA_TRACK;
|
||||
track.mode2 = true;
|
||||
} else if (type == "CDI/2352") {
|
||||
track.sectorSize = RAW_SECTOR_SIZE;
|
||||
track.attr = DATA_TRACK;
|
||||
track.mode2 = true;
|
||||
} else success = false;
|
||||
|
||||
canAddTrack = true;
|
||||
}
|
||||
else if (command == "INDEX") {
|
||||
uint64_t index;
|
||||
line >> index;
|
||||
uint64_t frame;
|
||||
success = GetCueFrame(frame, line);
|
||||
|
||||
if (index == 1) track.start = frame;
|
||||
else if (index == 0) prestart = frame;
|
||||
// ignore other indices
|
||||
}
|
||||
else if (command == "FILE") {
|
||||
if (canAddTrack) success = AddTrack(track, shift, prestart, totalPregap, currPregap);
|
||||
else success = true;
|
||||
canAddTrack = false;
|
||||
|
||||
string filename;
|
||||
GetCueString(filename, line);
|
||||
GetRealFileName(filename, pathname);
|
||||
string type;
|
||||
GetCueKeyword(type, line);
|
||||
|
||||
track.file = NULL;
|
||||
bool error = true;
|
||||
if (type == "BINARY") {
|
||||
track.file = new BinaryFile(filename.c_str(), error);
|
||||
}
|
||||
if (error) {
|
||||
delete track.file;
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
else if (command == "PREGAP") success = GetCueFrame(currPregap, line);
|
||||
else if (command == "CATALOG") success = GetCueString(mcn, line);
|
||||
// ignored commands
|
||||
else if (command == "CDTEXTFILE" || command == "FLAGS" || command == "ISRC"
|
||||
|| command == "PERFORMER" || command == "POSTGAP" || command == "REM"
|
||||
|| command == "SONGWRITER" || command == "TITLE" || command == "") success = true;
|
||||
// failure
|
||||
else success = false;
|
||||
|
||||
if (!success) return false;
|
||||
}
|
||||
// add last track
|
||||
if (!AddTrack(track, shift, prestart, totalPregap, currPregap)) return false;
|
||||
|
||||
// add leadout track
|
||||
track.number++;
|
||||
track.track_number = 0xAA;
|
||||
// track.attr = 0;//sync with load iso
|
||||
track.attr = 0x16; /* Was 0x00 but I believe 0x16 is appropriate. */
|
||||
// track.attr = last_attr | 0x02;
|
||||
track.start = 0;
|
||||
track.length = 0;
|
||||
track.file = NULL;
|
||||
if(!AddTrack(track, shift, 0, totalPregap, 0)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDROM_Interface_Image::AddTrack(Track &curr, uint64_t &shift, uint64_t prestart, uint64_t &totalPregap, uint64_t currPregap)
|
||||
{
|
||||
// frames between index 0(prestart) and 1(curr.start) must be skipped
|
||||
uint64_t skip;
|
||||
if (prestart > 0) {
|
||||
if (prestart > curr.start) return false;
|
||||
skip = curr.start - prestart;
|
||||
} else skip = 0;
|
||||
|
||||
// first track (track number must be 1)
|
||||
if (tracks.empty()) {
|
||||
if (curr.number != 1) return false;
|
||||
curr.skip = skip * curr.sectorSize;
|
||||
curr.start += currPregap;
|
||||
totalPregap = currPregap;
|
||||
tracks.push_back(curr);
|
||||
return true;
|
||||
}
|
||||
|
||||
Track &prev = *(tracks.end() - 1);
|
||||
|
||||
// current track consumes data from the same file as the previous
|
||||
if (prev.file == curr.file) {
|
||||
curr.start += shift;
|
||||
prev.length = curr.start + totalPregap - prev.start - skip;
|
||||
curr.skip += prev.skip + (prev.length * prev.sectorSize) + (skip * curr.sectorSize);
|
||||
totalPregap += currPregap;
|
||||
curr.start += totalPregap;
|
||||
// current track uses a different file as the previous track
|
||||
} else {
|
||||
uint64_t tmp = prev.file->getLength() - ((uint64_t) prev.skip);
|
||||
prev.length = tmp / ((uint64_t) prev.sectorSize);
|
||||
if (tmp % prev.sectorSize != 0) prev.length++; // padding
|
||||
|
||||
curr.start += prev.start + prev.length + currPregap;
|
||||
curr.skip = skip * curr.sectorSize;
|
||||
shift += prev.start + prev.length;
|
||||
totalPregap = currPregap;
|
||||
}
|
||||
|
||||
// error checks
|
||||
if (curr.number <= 1) return false;
|
||||
if (prev.number + 1 != curr.number) return false;
|
||||
if (curr.start < prev.start + prev.length) return false;
|
||||
#if 0
|
||||
/* curr.length is unsigned, so... --FvK */
|
||||
if (curr.length < 0) return false;
|
||||
#endif
|
||||
|
||||
tracks.push_back(curr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDROM_Interface_Image::HasDataTrack(void)
|
||||
{
|
||||
//Data track has attribute 0x14
|
||||
for(track_it it = tracks.begin(); it != tracks.end(); it++) {
|
||||
if ((*it).attr == DATA_TRACK) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CDROM_Interface_Image::HasAudioTracks(void)
|
||||
{
|
||||
for(track_it it = tracks.begin(); it != tracks.end(); it++) {
|
||||
if ((*it).attr == AUDIO_TRACK) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CDROM_Interface_Image::GetRealFileName(string &filename, string &pathname)
|
||||
{
|
||||
// check if file exists
|
||||
struct stat test;
|
||||
if (stat(filename.c_str(), &test) == 0) return true;
|
||||
|
||||
// check if file with path relative to cue file exists
|
||||
string tmpstr(pathname + "/" + filename);
|
||||
if (stat(tmpstr.c_str(), &test) == 0) {
|
||||
filename = tmpstr;
|
||||
return true;
|
||||
}
|
||||
#if defined (_WIN32) || defined(OS2)
|
||||
//Nothing
|
||||
#else
|
||||
//Consider the possibility that the filename has a windows directory seperator (inside the CUE file)
|
||||
//which is common for some commercial rereleases of DOS games using DOSBox
|
||||
|
||||
string copy = filename;
|
||||
size_t l = copy.size();
|
||||
for (size_t i = 0; i < l;i++) {
|
||||
if(copy[i] == '\\') copy[i] = '/';
|
||||
}
|
||||
|
||||
if (stat(copy.c_str(), &test) == 0) {
|
||||
filename = copy;
|
||||
return true;
|
||||
}
|
||||
|
||||
tmpstr = pathname + "/" + copy;
|
||||
if (stat(tmpstr.c_str(), &test) == 0) {
|
||||
filename = tmpstr;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CDROM_Interface_Image::GetCueKeyword(string &keyword, istream &in)
|
||||
{
|
||||
in >> keyword;
|
||||
for(Bitu i = 0; i < keyword.size(); i++) keyword[i] = toupper(keyword[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDROM_Interface_Image::GetCueFrame(uint64_t &frames, istream &in)
|
||||
{
|
||||
string msf;
|
||||
in >> msf;
|
||||
int min, sec, fr;
|
||||
bool success = sscanf(msf.c_str(), "%d:%d:%d", &min, &sec, &fr) == 3;
|
||||
frames = MSF_TO_FRAMES(min, sec, fr);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool CDROM_Interface_Image::GetCueString(string &str, istream &in)
|
||||
{
|
||||
int pos = (int)in.tellg();
|
||||
in >> str;
|
||||
if (str[0] == '\"') {
|
||||
if (str[str.size() - 1] == '\"') {
|
||||
str.assign(str, 1, str.size() - 2);
|
||||
} else {
|
||||
in.seekg(pos, ios::beg);
|
||||
char buffer[MAX_FILENAME_LENGTH];
|
||||
in.getline(buffer, MAX_FILENAME_LENGTH, '\"'); // skip
|
||||
in.getline(buffer, MAX_FILENAME_LENGTH, '\"');
|
||||
str = buffer;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDROM_Interface_Image::ClearTracks()
|
||||
{
|
||||
vector<Track>::iterator i = tracks.begin();
|
||||
vector<Track>::iterator end = tracks.end();
|
||||
|
||||
TrackFile* last = NULL;
|
||||
while(i != end) {
|
||||
Track &curr = *i;
|
||||
if (curr.file != last) {
|
||||
delete curr.file;
|
||||
last = curr.file;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
tracks.clear();
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2015 The DOSBox Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* Modified for use with PCem by bit */
|
||||
|
||||
#ifndef __CDROM_INTERFACE__
|
||||
#define __CDROM_INTERFACE__
|
||||
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include <stdint.h>
|
||||
typedef signed int Bits;
|
||||
typedef unsigned int Bitu;
|
||||
typedef int8_t Bit8s;
|
||||
typedef uint8_t Bit8u;
|
||||
typedef int16_t Bit16s;
|
||||
typedef uint16_t Bit16u;
|
||||
typedef int32_t Bit32s;
|
||||
typedef uint32_t Bit32u;
|
||||
|
||||
typedef size_t PhysPt;
|
||||
|
||||
#define RAW_SECTOR_SIZE 2352
|
||||
#define COOKED_SECTOR_SIZE 2048
|
||||
|
||||
#define DATA_TRACK 0x14
|
||||
#define AUDIO_TRACK 0x10
|
||||
|
||||
#define CD_FPS 75
|
||||
#define FRAMES_TO_MSF(f, M,S,F) { \
|
||||
int value = f; \
|
||||
*(F) = value%CD_FPS; \
|
||||
value /= CD_FPS; \
|
||||
*(S) = value%60; \
|
||||
value /= 60; \
|
||||
*(M) = value; \
|
||||
}
|
||||
#define MSF_TO_FRAMES(M, S, F) ((M)*60*CD_FPS+(S)*CD_FPS+(F))
|
||||
|
||||
|
||||
typedef struct SMSF {
|
||||
unsigned char min;
|
||||
unsigned char sec;
|
||||
unsigned char fr;
|
||||
} TMSF;
|
||||
|
||||
typedef struct SCtrl {
|
||||
Bit8u out[4]; // output channel
|
||||
Bit8u vol[4]; // channel volume
|
||||
} TCtrl;
|
||||
|
||||
extern int CDROM_GetMountType(char* path, int force);
|
||||
|
||||
class CDROM_Interface
|
||||
{
|
||||
public:
|
||||
// CDROM_Interface (void);
|
||||
virtual ~CDROM_Interface (void) {};
|
||||
|
||||
virtual bool SetDevice (char* path, int forceCD) = 0;
|
||||
|
||||
virtual bool GetUPC (unsigned char& attr, char* upc) = 0;
|
||||
|
||||
virtual bool GetAudioTracks (int& stTrack, int& end, TMSF& leadOut) = 0;
|
||||
virtual bool GetAudioTrackInfo (int track, int& number, TMSF& start, unsigned char& attr) = 0;
|
||||
virtual bool GetAudioSub (int sector, unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos) = 0;
|
||||
virtual bool GetMediaTrayStatus (bool& mediaPresent, bool& mediaChanged, bool& trayOpen) = 0;
|
||||
|
||||
virtual bool ReadSectors (PhysPt buffer, bool raw, unsigned long sector, unsigned long num) = 0;
|
||||
|
||||
virtual bool LoadUnloadMedia (bool unload) = 0;
|
||||
|
||||
virtual void InitNewMedia (void) {};
|
||||
};
|
||||
|
||||
class CDROM_Interface_Image : public CDROM_Interface
|
||||
{
|
||||
private:
|
||||
class TrackFile {
|
||||
public:
|
||||
virtual bool read(Bit8u *buffer, uint64_t seek, uint64_t count) = 0;
|
||||
virtual uint64_t getLength() = 0;
|
||||
virtual ~TrackFile() { };
|
||||
};
|
||||
|
||||
class BinaryFile : public TrackFile {
|
||||
public:
|
||||
BinaryFile(const char *filename, bool &error);
|
||||
~BinaryFile();
|
||||
bool read(Bit8u *buffer, uint64_t seek, uint64_t count);
|
||||
uint64_t getLength();
|
||||
private:
|
||||
BinaryFile();
|
||||
char fn[260];
|
||||
FILE *file;
|
||||
};
|
||||
|
||||
struct Track {
|
||||
int number;
|
||||
int track_number;
|
||||
int attr;
|
||||
int form;
|
||||
uint64_t start;
|
||||
uint64_t length;
|
||||
uint64_t skip;
|
||||
uint64_t sectorSize;
|
||||
bool mode2;
|
||||
TrackFile *file;
|
||||
};
|
||||
|
||||
public:
|
||||
CDROM_Interface_Image ();
|
||||
virtual ~CDROM_Interface_Image (void);
|
||||
void InitNewMedia (void);
|
||||
bool SetDevice (char* path, int forceCD);
|
||||
bool GetUPC (unsigned char& attr, char* upc);
|
||||
bool GetAudioTracks (int& stTrack, int& end, TMSF& leadOut);
|
||||
bool GetAudioTrackInfo (int track, int& number, TMSF& start, unsigned char& attr);
|
||||
bool GetAudioSub (int sector, unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos);
|
||||
bool GetMediaTrayStatus (bool& mediaPresent, bool& mediaChanged, bool& trayOpen);
|
||||
bool ReadSectors (PhysPt buffer, bool raw, unsigned long sector, unsigned long num);
|
||||
bool LoadUnloadMedia (bool unload);
|
||||
bool ReadSector (Bit8u *buffer, bool raw, unsigned long sector);
|
||||
bool ReadSectorSub (Bit8u *buffer, unsigned long sector);
|
||||
int GetSectorSize (unsigned long sector);
|
||||
bool IsMode2 (unsigned long sector);
|
||||
int GetMode2Form (unsigned long sector);
|
||||
bool HasDataTrack (void);
|
||||
bool HasAudioTracks (void);
|
||||
|
||||
int GetTrack (unsigned int sector);
|
||||
|
||||
private:
|
||||
// player
|
||||
static void CDAudioCallBack(Bitu len);
|
||||
|
||||
void ClearTracks();
|
||||
bool LoadIsoFile(char *filename);
|
||||
bool CanReadPVD(TrackFile *file, uint64_t sectorSize, bool mode2);
|
||||
// cue sheet processing
|
||||
bool LoadCueSheet(char *cuefile);
|
||||
bool GetRealFileName(std::string& filename, std::string& pathname);
|
||||
bool GetCueKeyword(std::string &keyword, std::istream &in);
|
||||
bool GetCueFrame(uint64_t &frames, std::istream &in);
|
||||
bool GetCueString(std::string &str, std::istream &in);
|
||||
bool AddTrack(Track &curr, uint64_t &shift, uint64_t prestart, uint64_t &totalPregap, uint64_t currPregap);
|
||||
|
||||
std::vector<Track> tracks;
|
||||
typedef std::vector<Track>::iterator track_it;
|
||||
std::string mcn;
|
||||
};
|
||||
|
||||
void cdrom_image_log(const char *format, ...);
|
||||
|
||||
#endif /* __CDROM_INTERFACE__ */
|
||||
295
src/cdrom/cdrom_image.c
Normal file
295
src/cdrom/cdrom_image.c
Normal file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* CD-ROM image support.
|
||||
*
|
||||
* Version: @(#)cdrom_image.c 1.0.11 2019/03/06
|
||||
*
|
||||
* Author: RichardG867,
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* bit,
|
||||
*
|
||||
* Copyright 2015-2019 Richardg867.
|
||||
* Copyright 2015-2019 Miran Grca.
|
||||
* Copyright 2017-2019 bit.
|
||||
*/
|
||||
#define __USE_LARGEFILE64
|
||||
#define _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include "../86box.h"
|
||||
#include "../config.h"
|
||||
#include "../plat.h"
|
||||
#include "../scsi/scsi_device.h"
|
||||
#include "cdrom_image_backend.h"
|
||||
#include "cdrom.h"
|
||||
#include "cdrom_image.h"
|
||||
|
||||
|
||||
#ifdef ENABLE_CDROM_IMAGE_LOG
|
||||
int cdrom_image_do_log = ENABLE_CDROM_IMAGE_LOG;
|
||||
|
||||
|
||||
void
|
||||
cdrom_image_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (cdrom_image_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define cdrom_image_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
|
||||
/* 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)
|
||||
|
||||
|
||||
static void
|
||||
image_get_tracks(cdrom_t *dev, int *first, int *last)
|
||||
{
|
||||
cd_img_t *img = (cd_img_t *)dev->image;
|
||||
TMSF tmsf;
|
||||
|
||||
cdi_get_audio_tracks(img, first, last, &tmsf);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
image_get_track_info(cdrom_t *dev, uint32_t track, int end, track_info_t *ti)
|
||||
{
|
||||
cd_img_t *img = (cd_img_t *)dev->image;
|
||||
TMSF tmsf;
|
||||
|
||||
cdi_get_audio_track_info(img, end, track, &ti->number, &tmsf, &ti->attr);
|
||||
|
||||
ti->m = tmsf.min;
|
||||
ti->s = tmsf.sec;
|
||||
ti->f = tmsf.fr;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
image_get_subchannel(cdrom_t *dev, uint32_t lba, subchannel_t *subc)
|
||||
{
|
||||
cd_img_t *img = (cd_img_t *)dev->image;
|
||||
TMSF rel_pos, abs_pos;
|
||||
|
||||
cdi_get_audio_sub(img, lba, &subc->attr, &subc->track, &subc->index,
|
||||
&rel_pos, &abs_pos);
|
||||
|
||||
subc->abs_m = abs_pos.min;
|
||||
subc->abs_s = abs_pos.sec;
|
||||
subc->abs_f = abs_pos.fr;
|
||||
|
||||
subc->rel_m = rel_pos.min;
|
||||
subc->rel_s = rel_pos.sec;
|
||||
subc->rel_f = rel_pos.fr;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
image_get_capacity(cdrom_t *dev)
|
||||
{
|
||||
cd_img_t *img = (cd_img_t *)dev->image;
|
||||
int first_track, last_track;
|
||||
int number, c;
|
||||
unsigned char attr;
|
||||
TMSF tmsf;
|
||||
uint32_t lb = 0;
|
||||
uint32_t address;
|
||||
|
||||
if (!img)
|
||||
return 0;
|
||||
|
||||
cdi_get_audio_tracks(img, &first_track, &last_track, &tmsf);
|
||||
|
||||
for (c = 0; c <= last_track; c++) {
|
||||
cdi_get_audio_track_info(img, 0, c + 1, &number, &tmsf, &attr);
|
||||
address = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; /* Do the - 150 here as well. */
|
||||
if (address > lb)
|
||||
lb = address;
|
||||
}
|
||||
|
||||
return lb;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
image_is_track_audio(cdrom_t *dev, uint32_t pos, int ismsf)
|
||||
{
|
||||
cd_img_t *img = (cd_img_t *)dev->image;
|
||||
uint8_t attr;
|
||||
TMSF tmsf;
|
||||
int m, s, f;
|
||||
int number;
|
||||
|
||||
if (!img || (dev->cd_status == CD_STATUS_DATA_ONLY))
|
||||
return 0;
|
||||
|
||||
if (ismsf) {
|
||||
m = (pos >> 16) & 0xff;
|
||||
s = (pos >> 8) & 0xff;
|
||||
f = pos & 0xff;
|
||||
pos = MSFtoLBA(m, s, f) - 150;
|
||||
}
|
||||
|
||||
/* GetTrack requires LBA. */
|
||||
cdi_get_audio_track_info(img, 0, cdi_get_track(img, pos), &number, &tmsf, &attr);
|
||||
|
||||
return attr == AUDIO_TRACK;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
image_sector_size(struct cdrom *dev, uint32_t lba)
|
||||
{
|
||||
cd_img_t *img = (cd_img_t *)dev->image;
|
||||
|
||||
return cdi_get_sector_size(img, lba);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
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);
|
||||
dev->cd_status = CD_STATUS_EMPTY;
|
||||
|
||||
if (img) {
|
||||
cdi_close(img);
|
||||
dev->image = NULL;
|
||||
}
|
||||
|
||||
dev->ops = NULL;
|
||||
}
|
||||
|
||||
|
||||
static const cdrom_ops_t cdrom_image_ops = {
|
||||
image_get_tracks,
|
||||
image_get_track_info,
|
||||
image_get_subchannel,
|
||||
image_sector_size,
|
||||
image_read_sector,
|
||||
image_track_type,
|
||||
image_exit
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
image_open_abort(cdrom_t *dev)
|
||||
{
|
||||
cdrom_image_close(dev);
|
||||
dev->ops = NULL;
|
||||
dev->host_drive = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cdrom_image_open(cdrom_t *dev, const wchar_t *fn)
|
||||
{
|
||||
cd_img_t *img;
|
||||
|
||||
wcscpy(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);
|
||||
|
||||
memset(img, 0, sizeof(cd_img_t));
|
||||
dev->image = img;
|
||||
|
||||
/* Open the image. */
|
||||
if (!cdi_set_device(img, fn))
|
||||
return image_open_abort(dev);
|
||||
|
||||
/* All good, reset state. */
|
||||
if (! wcscasecmp(plat_get_extension((wchar_t *) fn), L"ISO"))
|
||||
dev->cd_status = CD_STATUS_DATA_ONLY;
|
||||
else
|
||||
dev->cd_status = CD_STATUS_STOPPED;
|
||||
dev->seek_pos = 0;
|
||||
dev->cd_buflen = 0;
|
||||
dev->cdrom_capacity = image_get_capacity(dev);
|
||||
cdrom_image_log("CD-ROM capacity: %i sectors (%i bytes)\n", dev->cdrom_capacity, dev->cdrom_capacity << 11);
|
||||
|
||||
/* Attach this handler to the drive. */
|
||||
dev->ops = &cdrom_image_ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cdrom_image_close(cdrom_t *dev)
|
||||
{
|
||||
cdrom_image_log("CDROM: image_close(%ls)\n", dev->image_path);
|
||||
|
||||
if (dev && dev->ops && dev->ops->exit)
|
||||
dev->ops->exit(dev);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
980
src/cdrom/cdrom_image_backend.c
Normal file
980
src/cdrom/cdrom_image_backend.c
Normal file
@@ -0,0 +1,980 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* CD-ROM image file handling module, translated to C from
|
||||
* cdrom_dosbox.cpp.
|
||||
*
|
||||
* Version: @(#)cdrom_image_backend.c 1.0.2 2020/01/11
|
||||
*
|
||||
* Authors: Miran Grca, <mgrca8@gmail.com>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* The DOSBox Team, <unknown>
|
||||
*
|
||||
* Copyright 2016-2020 Miran Grca.
|
||||
* Copyright 2017-2020 Fred N. van Kempen.
|
||||
* Copyright 2002-2020 The DOSBox Team.
|
||||
*/
|
||||
#define _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#include <stdarg.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <ctype.h>
|
||||
#ifdef _WIN32
|
||||
# include <string.h>
|
||||
#else
|
||||
# include <libgen.h>
|
||||
#endif
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include "../86box.h"
|
||||
#include "../plat.h"
|
||||
#include "cdrom_image_backend.h"
|
||||
|
||||
|
||||
#define CDROM_BCD(x) (((x) % 10) | (((x) / 10) << 4))
|
||||
|
||||
#define MAX_LINE_LENGTH 512
|
||||
#define MAX_FILENAME_LENGTH 256
|
||||
#define CROSS_LEN 512
|
||||
|
||||
|
||||
#ifdef ENABLE_CDROM_IMAGE_BACKEND_LOG
|
||||
int cdrom_image_backend_do_log = ENABLE_CDROM_IMAGE_BACKEND_LOG;
|
||||
|
||||
|
||||
void
|
||||
cdrom_image_backend_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (cdrom_image_backend_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define cdrom_image_backend_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
|
||||
/* Binary file functions. */
|
||||
static int
|
||||
bin_read(void *p, uint8_t *buffer, uint64_t seek, size_t count)
|
||||
{
|
||||
track_file_t *tf = (track_file_t *) p;
|
||||
|
||||
cdrom_image_backend_log("CDROM: binary_read(%08lx, pos=%" PRIu64 " count=%lu\n",
|
||||
tf->file, seek, count);
|
||||
|
||||
if (tf->file == NULL)
|
||||
return 0;
|
||||
|
||||
fseeko64(tf->file, seek, SEEK_SET);
|
||||
|
||||
if (fread(buffer, count, 1, tf->file) != 1) {
|
||||
#ifdef ENABLE_cdrom_image_backend_log
|
||||
cdrom_image_backend_log("CDROM: binary_read failed!\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static uint64_t
|
||||
bin_get_length(void *p)
|
||||
{
|
||||
off64_t len;
|
||||
track_file_t *tf = (track_file_t *) p;
|
||||
|
||||
cdrom_image_backend_log("CDROM: binary_length(%08lx)\n", bf->file);
|
||||
|
||||
if (tf->file == NULL)
|
||||
return 0;
|
||||
|
||||
fseeko64(tf->file, 0, SEEK_END);
|
||||
len = ftello64(tf->file);
|
||||
cdrom_image_backend_log("CDROM: binary_length(%08lx) = %" PRIu64 "\n", tf->file, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
bin_close(void *p)
|
||||
{
|
||||
track_file_t *tf = (track_file_t *) p;
|
||||
|
||||
if (tf == NULL)
|
||||
return;
|
||||
|
||||
if (tf->file != NULL) {
|
||||
fclose(tf->file);
|
||||
tf->file = NULL;
|
||||
}
|
||||
|
||||
memset(tf->fn, 0x00, sizeof(tf->fn));
|
||||
|
||||
free(p);
|
||||
}
|
||||
|
||||
|
||||
static track_file_t *
|
||||
bin_init(const wchar_t *filename, int *error)
|
||||
{
|
||||
track_file_t *tf = (track_file_t *) malloc(sizeof(track_file_t));
|
||||
|
||||
memset(tf->fn, 0x00, sizeof(tf->fn));
|
||||
wcscpy(tf->fn, filename);
|
||||
tf->file = plat_fopen64(tf->fn, L"rb");
|
||||
cdrom_image_backend_log("CDROM: binary_open(%ls) = %08lx\n", tf->fn, tf->file);
|
||||
|
||||
*error = (tf->file == NULL);
|
||||
|
||||
/* Set the function pointers. */
|
||||
if (!*error) {
|
||||
tf->read = bin_read;
|
||||
tf->get_length = bin_get_length;
|
||||
tf->close = bin_close;
|
||||
}
|
||||
|
||||
return tf;
|
||||
}
|
||||
|
||||
|
||||
static track_file_t *
|
||||
track_file_init(const wchar_t *filename, int *error)
|
||||
{
|
||||
/* Current we only support .BIN files, either combined or one per
|
||||
track. In the future, more is planned. */
|
||||
return bin_init(filename, error);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
track_file_close(track_t *trk)
|
||||
{
|
||||
if (trk == NULL)
|
||||
return;
|
||||
|
||||
if (trk->file == NULL)
|
||||
return;
|
||||
|
||||
trk->file->close(trk->file);
|
||||
trk->file = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Root functions. */
|
||||
static void
|
||||
cdi_clear_tracks(cd_img_t *cdi)
|
||||
{
|
||||
int i;
|
||||
track_file_t *last = NULL;
|
||||
track_t *cur = NULL;
|
||||
|
||||
if ((cdi->tracks == NULL) || (cdi->tracks_num == 0))
|
||||
return;
|
||||
|
||||
for (i = 0; i < cdi->tracks_num; i++) {
|
||||
cur = &cdi->tracks[i];
|
||||
|
||||
if (cur->file != last) {
|
||||
track_file_close(cur);
|
||||
last = cur->file;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now free the array. */
|
||||
free(cdi->tracks);
|
||||
cdi->tracks = NULL;
|
||||
|
||||
/* Mark that there's no tracks. */
|
||||
cdi->tracks_num = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cdi_close(cd_img_t *cdi)
|
||||
{
|
||||
cdi_clear_tracks(cdi);
|
||||
free(cdi);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cdi_set_device(cd_img_t *cdi, const wchar_t *path)
|
||||
{
|
||||
if (cdi_load_cue(cdi, path))
|
||||
return 1;
|
||||
|
||||
if (cdi_load_iso(cdi, path))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* TODO: This never returns anything other than 1, should it even be an int? */
|
||||
int
|
||||
cdi_get_audio_tracks(cd_img_t *cdi, int *st_track, int *end, TMSF *lead_out)
|
||||
{
|
||||
*st_track = 1;
|
||||
*end = cdi->tracks_num - 1;
|
||||
FRAMES_TO_MSF(cdi->tracks[*end].start + 150, &lead_out->min, &lead_out->sec, &lead_out->fr);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* This replaces both Info and EndInfo, they are specified by a variable. */
|
||||
int
|
||||
cdi_get_audio_track_info(cd_img_t *cdi, int end, int track, int *track_num, TMSF *start, uint8_t *attr)
|
||||
{
|
||||
track_t *trk = &cdi->tracks[track - 1];
|
||||
int pos = trk->start + 150;
|
||||
|
||||
if ((track < 1) || (track > cdi->tracks_num))
|
||||
return 0;
|
||||
|
||||
pos = trk->start + 150;
|
||||
|
||||
FRAMES_TO_MSF(pos, &start->min, &start->sec, &start->fr);
|
||||
*track_num = trk->track_number;
|
||||
*attr = trk->attr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cdi_get_track(cd_img_t *cdi, uint32_t sector)
|
||||
{
|
||||
int i;
|
||||
track_t *cur, *next;
|
||||
|
||||
/* There must be at least two tracks - data and lead out. */
|
||||
if (cdi->tracks_num < 2)
|
||||
return -1;
|
||||
|
||||
/* This has a problem - the code skips the last track, which is
|
||||
lead out - is that correct? */
|
||||
for (i = 0; i < (cdi->tracks_num - 1); i++) {
|
||||
cur = &cdi->tracks[i];
|
||||
next = &cdi->tracks[i + 1];
|
||||
if ((cur->start <= sector) && (sector < next->start))
|
||||
return cur->number;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* TODO: See if track start is adjusted by 150 or not. */
|
||||
int
|
||||
cdi_get_audio_sub(cd_img_t *cdi, uint32_t sector, uint8_t *attr, uint8_t *track, uint8_t *index, TMSF *rel_pos, TMSF *abs_pos)
|
||||
{
|
||||
int cur_track = cdi_get_track(cdi, sector);
|
||||
track_t *trk;
|
||||
|
||||
if (cur_track < 1)
|
||||
return 0;
|
||||
|
||||
*track = (uint8_t) cur_track;
|
||||
trk = &cdi->tracks[*track - 1];
|
||||
*attr = trk->attr;
|
||||
*index = 1;
|
||||
|
||||
FRAMES_TO_MSF(sector + 150, &abs_pos->min, &abs_pos->sec, &abs_pos->fr);
|
||||
|
||||
/* Absolute position should be adjusted by 150, not the relative ones. */
|
||||
FRAMES_TO_MSF(sector - trk->start, &rel_pos->min, &rel_pos->sec, &rel_pos->fr);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector)
|
||||
{
|
||||
size_t length;
|
||||
int track = cdi_get_track(cdi, sector) - 1;
|
||||
uint64_t sect = (uint64_t) sector, seek;
|
||||
track_t *trk;
|
||||
int track_is_raw, ret;
|
||||
int raw_size, cooked_size;
|
||||
uint64_t offset = 0ULL;
|
||||
int m = 0, s = 0, f = 0;
|
||||
|
||||
if (track < 0)
|
||||
return 0;
|
||||
|
||||
trk = &cdi->tracks[track];
|
||||
track_is_raw = ((trk->sector_size == RAW_SECTOR_SIZE) || (trk->sector_size == 2448));
|
||||
if (raw && !track_is_raw)
|
||||
return 0;
|
||||
seek = trk->skip + ((sect - trk->start) * trk->sector_size);
|
||||
|
||||
if (track_is_raw)
|
||||
raw_size = trk->sector_size;
|
||||
else
|
||||
raw_size = 2448;
|
||||
|
||||
if (trk->mode2 && (trk->form != 1)) {
|
||||
if (trk->form == 2)
|
||||
cooked_size = (track_is_raw ? 2328 : trk->sector_size); /* Both 2324 + ECC and 2328 variants are valid. */
|
||||
else
|
||||
cooked_size = 2336;
|
||||
} else
|
||||
cooked_size = COOKED_SECTOR_SIZE;
|
||||
|
||||
length = (raw ? raw_size : cooked_size);
|
||||
|
||||
if (trk->mode2 && (trk->form >= 1))
|
||||
offset = 24ULL;
|
||||
else
|
||||
offset = 16ULL;
|
||||
|
||||
if (raw && !track_is_raw) {
|
||||
memset(buffer, 0x00, 2448);
|
||||
ret = trk->file->read(trk->file, buffer + offset, seek, length);
|
||||
if (!ret)
|
||||
return 0;
|
||||
/* Construct the rest of the raw sector. */
|
||||
memset(buffer + 1, 0xff, 10);
|
||||
buffer += 12;
|
||||
FRAMES_TO_MSF(sector + 150, &m, &s, &f);
|
||||
/* These have to be BCD. */
|
||||
buffer[12] = CDROM_BCD(m & 0xff);
|
||||
buffer[13] = CDROM_BCD(s & 0xff);
|
||||
buffer[14] = CDROM_BCD(f & 0xff);
|
||||
buffer[15] = trk->mode2 ? 2 : 1; /* Data, should reflect the actual sector type. */
|
||||
return 1;
|
||||
} else if (!raw && track_is_raw)
|
||||
return trk->file->read(trk->file, buffer, seek + offset, length);
|
||||
else
|
||||
return trk->file->read(trk->file, buffer, seek, length);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cdi_read_sectors(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector, uint32_t num)
|
||||
{
|
||||
int sector_size, success = 1;
|
||||
uint8_t buf_len, *buf;
|
||||
uint32_t i;
|
||||
|
||||
/* TODO: This fails to account for Mode 2. Shouldn't we have a function
|
||||
to get sector size? */
|
||||
sector_size = raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE;
|
||||
buf_len = num * sector_size;
|
||||
buf = (uint8_t *) malloc(buf_len * sizeof(uint8_t));
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
success = cdi_read_sector(cdi, &buf[i * sector_size], raw, sector + i);
|
||||
if (!success)
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy((void *) buffer, buf, buf_len);
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
/* TODO: Do CUE+BIN images with a sector size of 2448 even exist? */
|
||||
int
|
||||
cdi_read_sector_sub(cd_img_t *cdi, uint8_t *buffer, uint32_t sector)
|
||||
{
|
||||
int track = cdi_get_track(cdi, sector) - 1;
|
||||
track_t *trk;
|
||||
uint64_t s = (uint64_t) sector, seek;
|
||||
|
||||
if (track < 0)
|
||||
return 0;
|
||||
|
||||
trk = &cdi->tracks[track];
|
||||
seek = trk->skip + ((s - trk->start) * trk->sector_size);
|
||||
if (trk->sector_size != 2448)
|
||||
return 0;
|
||||
|
||||
return trk->file->read(trk->file, buffer, seek, 2448);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cdi_get_sector_size(cd_img_t *cdi, uint32_t sector)
|
||||
{
|
||||
int track = cdi_get_track(cdi, sector) - 1;
|
||||
track_t *trk;
|
||||
|
||||
if (track < 0)
|
||||
return 0;
|
||||
|
||||
trk = &cdi->tracks[track];
|
||||
return trk->sector_size;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cdi_is_mode2(cd_img_t *cdi, uint32_t sector)
|
||||
{
|
||||
int track = cdi_get_track(cdi, sector) - 1;
|
||||
track_t *trk;
|
||||
|
||||
if (track < 0)
|
||||
return 0;
|
||||
|
||||
trk = &cdi->tracks[track];
|
||||
|
||||
return !!(trk->mode2);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cdi_get_mode2_form(cd_img_t *cdi, uint32_t sector)
|
||||
{
|
||||
int track = cdi_get_track(cdi, sector) - 1;
|
||||
track_t *trk;
|
||||
|
||||
if (track < 0)
|
||||
return 0;
|
||||
|
||||
trk = &cdi->tracks[track];
|
||||
|
||||
return trk->form;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
cdi_can_read_pvd(track_file_t *file, uint64_t sector_size, int mode2, int form)
|
||||
{
|
||||
uint8_t pvd[COOKED_SECTOR_SIZE];
|
||||
uint64_t seek = 16ULL * sector_size; /* First VD is located at sector 16. */
|
||||
|
||||
if ((!mode2 || (form == 0)) && (sector_size == RAW_SECTOR_SIZE))
|
||||
seek += 16;
|
||||
if (mode2 && (form >= 1))
|
||||
seek += 24;
|
||||
|
||||
file->read(file, pvd, seek, COOKED_SECTOR_SIZE);
|
||||
|
||||
return ((pvd[0] == 1 && !strncmp((char*)(&pvd[1]), "CD001", 5) && pvd[6] == 1) ||
|
||||
(pvd[8] == 1 && !strncmp((char*)(&pvd[9]), "CDROM", 5) && pvd[14] == 1));
|
||||
}
|
||||
|
||||
|
||||
/* This reallocates the array and returns the pointer to the last track. */
|
||||
static void
|
||||
cdi_track_push_back(cd_img_t *cdi, track_t *trk)
|
||||
{
|
||||
/* This has to be done so situations in which realloc would misbehave
|
||||
can be detected and reported to the user. */
|
||||
if ((cdi->tracks != NULL) && (cdi->tracks_num == 0))
|
||||
fatal("CD-ROM Image: Non-null tracks array at 0 loaded tracks\n");
|
||||
if ((cdi->tracks == NULL) && (cdi->tracks_num != 0))
|
||||
fatal("CD-ROM Image: Null tracks array at non-zero loaded tracks\n");
|
||||
|
||||
cdi->tracks = realloc(cdi->tracks, (cdi->tracks_num + 1) * sizeof(track_t));
|
||||
memcpy(&(cdi->tracks[cdi->tracks_num]), trk, sizeof(track_t));
|
||||
cdi->tracks_num++;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cdi_load_iso(cd_img_t *cdi, const wchar_t *filename)
|
||||
{
|
||||
int error;
|
||||
track_t trk;
|
||||
|
||||
cdi->tracks = NULL;
|
||||
cdi->tracks_num = 0;
|
||||
|
||||
memset(&trk, 0, sizeof(track_t));
|
||||
|
||||
/* Data track (shouldn't there be a lead in track?). */
|
||||
trk.file = bin_init(filename, &error);
|
||||
if (error) {
|
||||
if (trk.file != NULL)
|
||||
trk.file->close(trk.file);
|
||||
return 0;
|
||||
}
|
||||
trk.number = 1;
|
||||
trk.track_number = 1;
|
||||
trk.attr = DATA_TRACK;
|
||||
|
||||
/* Try to detect ISO type. */
|
||||
trk.form = 0;
|
||||
trk.mode2 = 0;
|
||||
/* TODO: Merge the first and last cases since they result in the same thing. */
|
||||
if (cdi_can_read_pvd(trk.file, RAW_SECTOR_SIZE, 0, 0))
|
||||
trk.sector_size = RAW_SECTOR_SIZE;
|
||||
else if (cdi_can_read_pvd(trk.file, 2336, 1, 0)) {
|
||||
trk.sector_size = 2336;
|
||||
trk.mode2 = 1;
|
||||
} else if (cdi_can_read_pvd(trk.file, 2324, 1, 2)) {
|
||||
trk.sector_size = 2324;
|
||||
trk.mode2 = 1;
|
||||
trk.form = 2;
|
||||
} else if (cdi_can_read_pvd(trk.file, RAW_SECTOR_SIZE, 1, 0)) {
|
||||
trk.sector_size = RAW_SECTOR_SIZE;
|
||||
trk.mode2 = 1;
|
||||
} else {
|
||||
/* We use 2048 mode 1 as the default. */
|
||||
trk.sector_size = COOKED_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
trk.length = trk.file->get_length(trk.file) / trk.sector_size;
|
||||
cdi_track_push_back(cdi, &trk);
|
||||
|
||||
/* Lead out track. */
|
||||
trk.number = 2;
|
||||
trk.track_number = 0xAA;
|
||||
trk.attr = 0x16; /* Was originally 0x00, but I believe 0x16 is appropriate. */
|
||||
trk.start = trk.length;
|
||||
trk.length = 0;
|
||||
trk.file = NULL;
|
||||
cdi_track_push_back(cdi, &trk);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
cdi_cue_get_buffer(char *str, char **line, int up)
|
||||
{
|
||||
char *s = *line;
|
||||
char *p = str;
|
||||
int quote = 0;
|
||||
int done = 0;
|
||||
int space = 1;
|
||||
|
||||
/* Copy to local buffer until we have end of string or whitespace. */
|
||||
while (! done) {
|
||||
switch(*s) {
|
||||
case '\0':
|
||||
if (quote) {
|
||||
/* Ouch, unterminated string.. */
|
||||
return 0;
|
||||
}
|
||||
done = 1;
|
||||
break;
|
||||
|
||||
case '\"':
|
||||
quote ^= 1;
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
case '\t':
|
||||
if (space)
|
||||
break;
|
||||
|
||||
if (! quote) {
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
/*FALLTHROUGH*/
|
||||
|
||||
default:
|
||||
if (up && islower((int) *s))
|
||||
*p++ = toupper((int) *s);
|
||||
else
|
||||
*p++ = *s;
|
||||
space = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (! done)
|
||||
s++;
|
||||
}
|
||||
*p = '\0';
|
||||
|
||||
*line = s;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
cdi_cue_get_keyword(char **dest, char **line)
|
||||
{
|
||||
char temp[1024];
|
||||
int success;
|
||||
|
||||
success = cdi_cue_get_buffer(temp, line, 1);
|
||||
if (success)
|
||||
*dest = temp;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
/* Get a string from the input line, handling quotes properly. */
|
||||
static uint64_t
|
||||
cdi_cue_get_number(char **line)
|
||||
{
|
||||
char temp[128];
|
||||
uint64_t num;
|
||||
|
||||
if (!cdi_cue_get_buffer(temp, line, 0))
|
||||
return 0;
|
||||
|
||||
if (sscanf(temp, "%" PRIu64, &num) != 1)
|
||||
return 0;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
cdi_cue_get_frame(uint64_t *frames, char **line)
|
||||
{
|
||||
char temp[128];
|
||||
int min, sec, fr;
|
||||
int success;
|
||||
|
||||
success = cdi_cue_get_buffer(temp, line, 0);
|
||||
if (! success) return 0;
|
||||
|
||||
success = sscanf(temp, "%d:%d:%d", &min, &sec, &fr) == 3;
|
||||
if (! success) return 0;
|
||||
|
||||
*frames = MSF_TO_FRAMES(min, sec, fr);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
cdi_add_track(cd_img_t *cdi, track_t *cur, uint64_t *shift, uint64_t prestart, uint64_t *total_pregap, uint64_t cur_pregap)
|
||||
{
|
||||
/* Frames between index 0 (prestart) and 1 (current track start) must be skipped. */
|
||||
uint64_t skip, temp;
|
||||
track_t *prev = NULL;
|
||||
|
||||
if (prestart > 0) {
|
||||
if (prestart > cur->start)
|
||||
return 0;
|
||||
skip = cur->start - prestart;
|
||||
} else
|
||||
skip = 0ULL;
|
||||
|
||||
if ((cdi->tracks != NULL) && (cdi->tracks_num != 0))
|
||||
prev = &cdi->tracks[cdi->tracks_num - 1];
|
||||
|
||||
/* First track (track number must be 1). */
|
||||
if (cdi->tracks_num == 0) {
|
||||
/* I guess this makes sure the structure is not filled with invalid data. */
|
||||
if (cur->number != 1)
|
||||
return 0;
|
||||
cur->skip = skip * cur->sector_size;
|
||||
cur->start += cur_pregap;
|
||||
*total_pregap = cur_pregap;
|
||||
cdi_track_push_back(cdi, cur);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Current track consumes data from the same file as the previous. */
|
||||
if (prev->file == cur->file) {
|
||||
cur->start += *shift;
|
||||
prev->length = cur->start + *total_pregap - prev->start - skip;
|
||||
cur->skip += prev->skip + (prev->length * prev->sector_size) + (skip * cur->sector_size);
|
||||
*total_pregap += cur_pregap;
|
||||
cur->start += *total_pregap;
|
||||
} else {
|
||||
temp = prev->file->get_length(prev->file) - ((uint64_t) prev->skip);
|
||||
prev->length = temp / ((uint64_t) prev->sector_size);
|
||||
if ((temp % prev->sector_size) != 0)
|
||||
prev->length++; /* Padding. */
|
||||
|
||||
cur->start += prev->start + prev->length + cur_pregap;
|
||||
cur->skip = skip * cur->sector_size;
|
||||
*shift += prev->start + prev->length;
|
||||
*total_pregap = cur_pregap;
|
||||
}
|
||||
|
||||
/* Error checks. */
|
||||
if (cur->number <= 1)
|
||||
return 0;
|
||||
if ((prev->number + 1) != cur->number)
|
||||
return 0;
|
||||
if (cur->start < (prev->start + prev->length))
|
||||
return 0;
|
||||
|
||||
cdi_track_push_back(cdi, cur);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cdi_load_cue(cd_img_t *cdi, const wchar_t *cuefile)
|
||||
{
|
||||
track_t trk;
|
||||
wchar_t pathname[MAX_FILENAME_LENGTH], filename[MAX_FILENAME_LENGTH];
|
||||
wchar_t temp[MAX_FILENAME_LENGTH];
|
||||
uint64_t shift = 0ULL, prestart = 0ULL;
|
||||
uint64_t cur_pregap = 0ULL, total_pregap = 0ULL;
|
||||
uint64_t frame = 0ULL, index;
|
||||
int i, success;
|
||||
int error, can_add_track = 0;
|
||||
FILE *fp;
|
||||
char buf[MAX_LINE_LENGTH], ansi[MAX_FILENAME_LENGTH];
|
||||
char *line, *command;
|
||||
char *type;
|
||||
|
||||
cdi->tracks = NULL;
|
||||
cdi->tracks_num = 0;
|
||||
|
||||
memset(&trk, 0, sizeof(track_t));
|
||||
|
||||
/* Get a copy of the filename into pathname, we need it later. */
|
||||
memset(pathname, 0, MAX_FILENAME_LENGTH * sizeof(wchar_t));
|
||||
plat_get_dirname(pathname, cuefile);
|
||||
|
||||
/* Open the file. */
|
||||
fp = plat_fopen((wchar_t *) cuefile, L"r");
|
||||
if (fp == NULL)
|
||||
return 0;
|
||||
|
||||
success = 0;
|
||||
|
||||
for (;;) {
|
||||
line = buf;
|
||||
|
||||
/* Read a line from the cuesheet file. */
|
||||
if (feof(fp) || fgets(buf, sizeof(buf), fp) == NULL || ferror(fp))
|
||||
break;
|
||||
|
||||
/* Do two iterations to make sure to nuke even if it's \r\n or \n\r,
|
||||
but do checks to make sure we're not nuking other bytes. */
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (strlen(buf) > 0) {
|
||||
if (buf[strlen(buf) - 1] == '\n')
|
||||
buf[strlen(buf) - 1] = '\0'; /* nuke trailing newline */
|
||||
else if (buf[strlen(buf) - 1] == '\r')
|
||||
buf[strlen(buf) - 1] = '\0'; /* nuke trailing newline */
|
||||
}
|
||||
}
|
||||
|
||||
success = cdi_cue_get_keyword(&command, &line);
|
||||
|
||||
if (!strcmp(command, "TRACK")) {
|
||||
if (can_add_track)
|
||||
success = cdi_add_track(cdi, &trk, &shift, prestart, &total_pregap, cur_pregap);
|
||||
else
|
||||
success = 1;
|
||||
|
||||
trk.start = 0;
|
||||
trk.skip = 0;
|
||||
cur_pregap = 0;
|
||||
prestart = 0;
|
||||
|
||||
trk.number = cdi_cue_get_number(&line);
|
||||
trk.track_number = trk.number;
|
||||
success = cdi_cue_get_keyword(&type, &line);
|
||||
if (!success)
|
||||
break;
|
||||
|
||||
trk.form = 0;
|
||||
trk.mode2 = 0;
|
||||
|
||||
if (!strcmp(type, "AUDIO")) {
|
||||
trk.sector_size = RAW_SECTOR_SIZE;
|
||||
trk.attr = AUDIO_TRACK;
|
||||
} else if (!strcmp(type, "MODE1/2048")) {
|
||||
trk.sector_size = COOKED_SECTOR_SIZE;
|
||||
trk.attr = DATA_TRACK;
|
||||
} else if (!strcmp(type, "MODE1/2352")) {
|
||||
trk.sector_size = RAW_SECTOR_SIZE;
|
||||
trk.attr = DATA_TRACK;
|
||||
} else if (!strcmp(type, "MODE1/2448")) {
|
||||
trk.sector_size = 2448;
|
||||
trk.attr = DATA_TRACK;
|
||||
} else if (!strcmp(type, "MODE2/2048")) {
|
||||
trk.form = 1;
|
||||
trk.sector_size = COOKED_SECTOR_SIZE;
|
||||
trk.attr = DATA_TRACK;
|
||||
trk.mode2 = 1;
|
||||
} else if (!strcmp(type, "MODE2/2324")) {
|
||||
trk.form = 2;
|
||||
trk.sector_size = 2324;
|
||||
trk.attr = DATA_TRACK;
|
||||
trk.mode2 = 1;
|
||||
} else if (!strcmp(type, "MODE2/2328")) {
|
||||
trk.form = 2;
|
||||
trk.sector_size = 2328;
|
||||
trk.attr = DATA_TRACK;
|
||||
trk.mode2 = 1;
|
||||
} else if (!strcmp(type, "MODE2/2336")) {
|
||||
trk.sector_size = 2336;
|
||||
trk.attr = DATA_TRACK;
|
||||
trk.mode2 = 1;
|
||||
} else if (!strcmp(type, "MODE2/2352")) {
|
||||
trk.form = 1; /* Assume this is XA Mode 2 Form 1. */
|
||||
trk.sector_size = RAW_SECTOR_SIZE;
|
||||
trk.attr = DATA_TRACK;
|
||||
trk.mode2 = 1;
|
||||
} else if (!strcmp(type, "MODE2/2448")) {
|
||||
trk.form = 1; /* Assume this is XA Mode 2 Form 1. */
|
||||
trk.sector_size = 2448;
|
||||
trk.attr = DATA_TRACK;
|
||||
trk.mode2 = 1;
|
||||
} else if (!strcmp(type, "CDG/2448")) {
|
||||
trk.sector_size = 2448;
|
||||
trk.attr = DATA_TRACK;
|
||||
trk.mode2 = 1;
|
||||
} else if (!strcmp(type, "CDI/2336")) {
|
||||
trk.sector_size = 2336;
|
||||
trk.attr = DATA_TRACK;
|
||||
trk.mode2 = 1;
|
||||
} else if (!strcmp(type, "CDI/2352")) {
|
||||
trk.sector_size = RAW_SECTOR_SIZE;
|
||||
trk.attr = DATA_TRACK;
|
||||
trk.mode2 = 1;
|
||||
} else
|
||||
success = 0;
|
||||
|
||||
can_add_track = 1;
|
||||
} else if (!strcmp(command, "INDEX")) {
|
||||
index = cdi_cue_get_number(&line);
|
||||
success = cdi_cue_get_frame(&frame, &line);
|
||||
|
||||
switch(index) {
|
||||
case 0:
|
||||
prestart = frame;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
trk.start = frame;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* ignore other indices */
|
||||
break;
|
||||
}
|
||||
} else if (!strcmp(command, "FILE")) {
|
||||
if (can_add_track)
|
||||
success = cdi_add_track(cdi, &trk, &shift, prestart, &total_pregap, cur_pregap);
|
||||
else
|
||||
success = 1;
|
||||
can_add_track = 0;
|
||||
|
||||
memset(ansi, 0, MAX_FILENAME_LENGTH * sizeof(char));
|
||||
memset(filename, 0, MAX_FILENAME_LENGTH * sizeof(wchar_t));
|
||||
|
||||
success = cdi_cue_get_buffer(ansi, &line, 0);
|
||||
if (!success)
|
||||
break;
|
||||
success = cdi_cue_get_keyword(&type, &line);
|
||||
if (!success)
|
||||
break;
|
||||
|
||||
trk.file = NULL;
|
||||
error = 1;
|
||||
|
||||
if (!strcmp(type, "BINARY")) {
|
||||
memset(temp, 0, MAX_FILENAME_LENGTH * sizeof(wchar_t));
|
||||
mbstowcs(temp, ansi, sizeof_w(temp));
|
||||
plat_append_filename(filename, pathname, temp);
|
||||
trk.file = track_file_init(filename, &error);
|
||||
}
|
||||
if (error) {
|
||||
#ifdef ENABLE_cdrom_image_backend_log
|
||||
cdrom_image_backend_log("CUE: cannot open fille '%ls' in cue sheet!\n",
|
||||
filename);
|
||||
#endif
|
||||
if (trk.file != NULL) {
|
||||
trk.file->close(trk.file);
|
||||
trk.file = NULL;
|
||||
}
|
||||
success = 0;
|
||||
}
|
||||
} else if (!strcmp(command, "PREGAP"))
|
||||
success = cdi_cue_get_frame(&cur_pregap, &line);
|
||||
else if (!strcmp(command, "CATALOG") || !strcmp(command, "CDTEXTFILE") || !strcmp(command, "FLAGS") || !strcmp(command, "ISRC") ||
|
||||
!strcmp(command, "PERFORMER") || !strcmp(command, "POSTGAP") || !strcmp(command, "REM") ||
|
||||
!strcmp(command, "SONGWRITER") || !strcmp(command, "TITLE") || !strcmp(command, "")) {
|
||||
/* Ignored commands. */
|
||||
success = 1;
|
||||
} else {
|
||||
#ifdef ENABLE_cdrom_image_backend_log
|
||||
cdrom_image_backend_log("CUE: unsupported command '%s' in cue sheet!\n",
|
||||
command.c_str());
|
||||
#endif
|
||||
success = 0;
|
||||
}
|
||||
|
||||
if (!success)
|
||||
break;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
if (!success)
|
||||
return 0;
|
||||
|
||||
/* Add last track. */
|
||||
if (!cdi_add_track(cdi, &trk, &shift, prestart, &total_pregap, cur_pregap))
|
||||
return 0;
|
||||
|
||||
/* Add lead out track. */
|
||||
trk.number++;
|
||||
trk.track_number = 0xAA;
|
||||
trk.attr = 0x16; /* Was 0x00 but I believe 0x16 is appropriate. */
|
||||
trk.start = 0;
|
||||
trk.length = 0;
|
||||
trk.file = NULL;
|
||||
if (!cdi_add_track(cdi, &trk, &shift, 0, &total_pregap, 0))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cdi_has_data_track(cd_img_t *cdi)
|
||||
{
|
||||
int i;
|
||||
|
||||
if ((cdi == NULL) || (cdi->tracks == NULL))
|
||||
return 0;
|
||||
|
||||
/* Data track has attribute 0x14. */
|
||||
for (i = 0; i < cdi->tracks_num; i++) {
|
||||
if (cdi->tracks[i].attr == DATA_TRACK)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cdi_has_audio_track(cd_img_t *cdi)
|
||||
{
|
||||
int i;
|
||||
|
||||
if ((cdi == NULL) || (cdi->tracks == NULL))
|
||||
return 0;
|
||||
|
||||
/* Audio track has attribute 0x14. */
|
||||
for (i = 0; i < cdi->tracks_num; i++) {
|
||||
if (cdi->tracks[i].attr == AUDIO_TRACK)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
93
src/cdrom/cdrom_image_backend.h
Normal file
93
src/cdrom/cdrom_image_backend.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* CD-ROM image file handling module header , translated to C
|
||||
* from cdrom_dosbox.h.
|
||||
*
|
||||
* Version: @(#)cdrom_image_backend.h 1.0.1 2019/12/21
|
||||
*
|
||||
* Authors: Miran Grca, <mgrca8@gmail.com>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* The DOSBox Team, <unknown>
|
||||
*
|
||||
* Copyright 2016-2019 Miran Grca.
|
||||
* Copyright 2017-2019 Fred N. van Kempen.
|
||||
* Copyright 2002-2019 The DOSBox Team.
|
||||
*/
|
||||
#ifndef CDROM_IMAGE_BACKEND_H
|
||||
#define CDROM_IMAGE_BACKEND_H
|
||||
|
||||
#define RAW_SECTOR_SIZE 2352
|
||||
#define COOKED_SECTOR_SIZE 2048
|
||||
|
||||
#define DATA_TRACK 0x14
|
||||
#define AUDIO_TRACK 0x10
|
||||
|
||||
#define CD_FPS 75
|
||||
#define FRAMES_TO_MSF(f, M,S,F) { \
|
||||
uint64_t value = f; \
|
||||
*(F) = (value%CD_FPS) & 0xff; \
|
||||
value /= CD_FPS; \
|
||||
*(S) = (value%60) & 0xff; \
|
||||
value /= 60; \
|
||||
*(M) = value & 0xff; \
|
||||
}
|
||||
#define MSF_TO_FRAMES(M, S, F) ((M)*60*CD_FPS+(S)*CD_FPS+(F))
|
||||
|
||||
|
||||
typedef struct SMSF {
|
||||
uint8_t min;
|
||||
uint8_t sec;
|
||||
uint8_t fr;
|
||||
} TMSF;
|
||||
|
||||
/* Track file struct. */
|
||||
typedef struct {
|
||||
int (*read)(void *p, uint8_t *buffer, uint64_t seek, size_t count);
|
||||
uint64_t (*get_length)(void *p);
|
||||
void (*close)(void *p);
|
||||
|
||||
wchar_t fn[260];
|
||||
FILE *file;
|
||||
} track_file_t;
|
||||
|
||||
typedef struct {
|
||||
int number, track_number, attr, sector_size,
|
||||
mode2, form;
|
||||
uint64_t start, length,
|
||||
skip;
|
||||
track_file_t *file;
|
||||
} track_t;
|
||||
|
||||
typedef struct {
|
||||
int tracks_num;
|
||||
track_t *tracks;
|
||||
} cd_img_t;
|
||||
|
||||
|
||||
/* Binary file functions. */
|
||||
extern void cdi_close(cd_img_t *cdi);
|
||||
extern int cdi_set_device(cd_img_t *cdi, const wchar_t *path);
|
||||
extern int cdi_get_audio_tracks(cd_img_t *cdi, int *st_track, int *end, TMSF *lead_out);
|
||||
extern int cdi_get_audio_track_info(cd_img_t *cdi, int end, int track, int *track_num, TMSF *start, uint8_t *attr);
|
||||
extern int cdi_get_track(cd_img_t *cdi, uint32_t sector);
|
||||
extern int cdi_get_audio_sub(cd_img_t *cdi, uint32_t sector, uint8_t *attr, uint8_t *track, uint8_t *index, TMSF *rel_pos, TMSF *abs_pos);
|
||||
extern int cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector);
|
||||
extern int cdi_read_sectors(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector, uint32_t num);
|
||||
extern int cdi_read_sector_sub(cd_img_t *cdi, uint8_t *buffer, uint32_t sector);
|
||||
extern int cdi_get_sector_size(cd_img_t *cdi, uint32_t sector);
|
||||
extern int cdi_is_mode2(cd_img_t *cdi, uint32_t sector);
|
||||
extern int cdi_get_mode2_form(cd_img_t *cdi, uint32_t sector);
|
||||
extern int cdi_load_iso(cd_img_t *cdi, const wchar_t *filename);
|
||||
extern int cdi_load_cue(cd_img_t *cdi, const wchar_t *cuefile);
|
||||
extern int cdi_has_data_track(cd_img_t *cdi);
|
||||
extern int cdi_has_audio_track(cd_img_t *cdi);
|
||||
|
||||
|
||||
|
||||
#endif /* ! CDROM_IMAGE_BACKEND_H */
|
||||
@@ -1,161 +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 CD-ROM null interface for unmounted
|
||||
* guest CD-ROM drives.
|
||||
*
|
||||
* Version: @(#)cdrom_null.c 1.0.7 2018/03/26
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2008-2016 Sarah Walker.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include "../86box.h"
|
||||
#include "../scsi/scsi.h"
|
||||
#include "cdrom.h"
|
||||
|
||||
|
||||
static CDROM null_cdrom;
|
||||
|
||||
|
||||
static int
|
||||
null_ready(uint8_t id)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/* Always return 0, the contents of a null CD-ROM drive never change. */
|
||||
static int
|
||||
null_medium_changed(uint8_t id)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
null_getcurrentsubchannel(uint8_t id, uint8_t *b, int msf)
|
||||
{
|
||||
return(0x13);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
null_readsector_raw(uint8_t id, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type, int cdrom_sector_flags, int *len)
|
||||
{
|
||||
*len = 0;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
null_readtoc(uint8_t id, uint8_t *b, uint8_t starttrack, int msf, int maxlen, int single)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
null_readtoc_session(uint8_t id, uint8_t *b, int msf, int maxlen)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
null_readtoc_raw(uint8_t id, uint8_t *b, int maxlen)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
static uint32_t
|
||||
null_size(uint8_t id)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
null_status(uint8_t id)
|
||||
{
|
||||
return(CD_STATUS_EMPTY);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cdrom_null_reset(uint8_t id)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void cdrom_set_null_handler(uint8_t id);
|
||||
|
||||
int
|
||||
cdrom_null_open(uint8_t id)
|
||||
{
|
||||
cdrom_set_null_handler(id);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
null_close(uint8_t id)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void null_exit(uint8_t id)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
null_media_type_id(uint8_t id)
|
||||
{
|
||||
return(0x70);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cdrom_set_null_handler(uint8_t id)
|
||||
{
|
||||
cdrom[id]->handler = &null_cdrom;
|
||||
cdrom_drives[id].host_drive = 0;
|
||||
memset(cdrom_image[id].image_path, 0, sizeof(cdrom_image[id].image_path));
|
||||
}
|
||||
|
||||
|
||||
static CDROM null_cdrom = {
|
||||
null_ready,
|
||||
null_medium_changed,
|
||||
null_media_type_id,
|
||||
NULL,
|
||||
NULL,
|
||||
null_readtoc,
|
||||
null_readtoc_session,
|
||||
null_readtoc_raw,
|
||||
null_getcurrentsubchannel,
|
||||
null_readsector_raw,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
null_size,
|
||||
null_status,
|
||||
NULL,
|
||||
null_exit
|
||||
};
|
||||
@@ -1,28 +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 CD-ROM null interface for unmounted
|
||||
* guest CD-ROM drives.
|
||||
*
|
||||
* Version: @(#)cdrom_null.h 1.0.4 2018/03/31
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* Copyright 2008-2018 Sarah Walker.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
*/
|
||||
#ifndef EMU_CDROM_NULL_H
|
||||
#define EMU_CDROM_NULL_H
|
||||
|
||||
|
||||
extern int cdrom_null_open(uint8_t id);
|
||||
extern void cdrom_null_reset(uint8_t id);
|
||||
extern void null_close(uint8_t id);
|
||||
|
||||
|
||||
#endif /*EMU_CDROM_NULL_H*/
|
||||
171
src/chipset/acc2168.c
Normal file
171
src/chipset/acc2168.c
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Implementation of the ACC 2168 chipset
|
||||
* used by the Packard Bell Legend 760 Supreme (PB410A or PB430).
|
||||
*
|
||||
* Version: @(#)acc2168.c 1.0.1 2019/10/19
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
*
|
||||
* Copyright 2019 Sarah Walker.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include "../86box.h"
|
||||
#include "../cpu/cpu.h"
|
||||
#include "../timer.h"
|
||||
#include "../device.h"
|
||||
#include "../keyboard.h"
|
||||
#include "../io.h"
|
||||
#include "../mem.h"
|
||||
#include "../mouse.h"
|
||||
#include "../port_92.h"
|
||||
#include "../sio.h"
|
||||
#include "../disk/hdc.h"
|
||||
#include "../video/video.h"
|
||||
#include "../video/vid_ht216.h"
|
||||
#include "chipset.h"
|
||||
|
||||
|
||||
typedef struct acc2168_t
|
||||
{
|
||||
int reg_idx;
|
||||
uint8_t regs[256];
|
||||
uint8_t port_78;
|
||||
} acc2168_t;
|
||||
|
||||
|
||||
static void
|
||||
acc2168_shadow_recalc(acc2168_t *dev)
|
||||
{
|
||||
if (dev->regs[0x02] & 8) {
|
||||
switch (dev->regs[0x02] & 0x30) {
|
||||
case 0x00:
|
||||
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL);
|
||||
break;
|
||||
case 0x10:
|
||||
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
|
||||
break;
|
||||
case 0x20:
|
||||
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY);
|
||||
break;
|
||||
case 0x30:
|
||||
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTANY);
|
||||
break;
|
||||
}
|
||||
} else
|
||||
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY);
|
||||
|
||||
if (dev->regs[0x02] & 4) {
|
||||
switch (dev->regs[0x02] & 0x30) {
|
||||
case 0x00:
|
||||
mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL);
|
||||
break;
|
||||
case 0x10:
|
||||
mem_set_mem_state(0xe0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
|
||||
break;
|
||||
case 0x20:
|
||||
mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY);
|
||||
break;
|
||||
case 0x30:
|
||||
mem_set_mem_state(0xe0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTANY);
|
||||
break;
|
||||
}
|
||||
} else
|
||||
mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY);
|
||||
}
|
||||
|
||||
|
||||
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 (dev->reg_idx) {
|
||||
case 0x02:
|
||||
acc2168_shadow_recalc(dev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
const device_t acc2168_device = {
|
||||
"ACC 2168",
|
||||
0,
|
||||
0,
|
||||
acc2168_init, acc2168_close, NULL,
|
||||
NULL, NULL, NULL,
|
||||
NULL
|
||||
};
|
||||
97
src/chipset/acer_m3a.c
Normal file
97
src/chipset/acer_m3a.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* 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.
|
||||
*
|
||||
* Version: @(#)acer_m3a.c 1.0.0 2019/05/13
|
||||
*
|
||||
* 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.h"
|
||||
#include "../mem.h"
|
||||
#include "../io.h"
|
||||
#include "../rom.h"
|
||||
#include "../pci.h"
|
||||
#include "../device.h"
|
||||
#include "../keyboard.h"
|
||||
#include "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
|
||||
};
|
||||
146
src/chipset/ali1429.c
Normal file
146
src/chipset/ali1429.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Implementation of the ALi M-1429/1431 chipset.
|
||||
*
|
||||
* Version: @(#)ali1429.c 1.0.9 2019/10/09
|
||||
*
|
||||
* Authors: Sarah Walker, <tommowalker@tommowalker.co.uk>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2008-2019 Sarah Walker.
|
||||
* Copyright 2016-2019 Miran Grca.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include "../86box.h"
|
||||
#include "../cpu/cpu.h"
|
||||
#include "../timer.h"
|
||||
#include "../io.h"
|
||||
#include "../mem.h"
|
||||
#include "../device.h"
|
||||
#include "../keyboard.h"
|
||||
#include "../floppy/fdd.h"
|
||||
#include "../floppy/fdc.h"
|
||||
#include "../disk/hdc.h"
|
||||
#include "../disk/hdc_ide.h"
|
||||
#include "../timer.h"
|
||||
#include "../port_92.h"
|
||||
#include "chipset.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t cur_reg,
|
||||
regs[256];
|
||||
} ali1429_t;
|
||||
|
||||
|
||||
static void
|
||||
ali1429_recalc(ali1429_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 (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);
|
||||
}
|
||||
|
||||
flushmmucache();
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ali1429_write(uint16_t port, uint8_t val, void *priv)
|
||||
{
|
||||
ali1429_t *dev = (ali1429_t *) priv;
|
||||
|
||||
if (port & 1) {
|
||||
dev->regs[dev->cur_reg] = val;
|
||||
|
||||
switch (dev->cur_reg) {
|
||||
case 0x13:
|
||||
ali1429_recalc(dev);
|
||||
break;
|
||||
case 0x14:
|
||||
ali1429_recalc(dev);
|
||||
break;
|
||||
}
|
||||
} else
|
||||
dev->cur_reg = val;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
ali1429_read(uint16_t port, void *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];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ali1429_close(void *priv)
|
||||
{
|
||||
ali1429_t *dev = (ali1429_t *) priv;
|
||||
|
||||
free(dev);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ali1429_init(const device_t *info)
|
||||
{
|
||||
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;
|
||||
|
||||
io_sethandler(0x0022, 0x0002, ali1429_read, NULL, NULL, ali1429_write, NULL, NULL, dev);
|
||||
|
||||
ali1429_recalc(dev);
|
||||
|
||||
device_add(&port_92_device);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
const device_t ali1429_device = {
|
||||
"ALi-M1429",
|
||||
0,
|
||||
0,
|
||||
ali1429_init, ali1429_close, NULL,
|
||||
NULL, NULL, NULL,
|
||||
NULL
|
||||
};
|
||||
68
src/chipset/chipset.h
Normal file
68
src/chipset/chipset.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Handling of the emulated chipsets.
|
||||
*
|
||||
* Version: @(#)machine.h 1.0.0 2019/05/13
|
||||
*
|
||||
* Authors: Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2019 Miran Grca.
|
||||
*/
|
||||
#ifndef EMU_CHIPSET_H
|
||||
# define EMU_CHIPSET_H
|
||||
|
||||
|
||||
/* ACC */
|
||||
extern const device_t acc2168_device;
|
||||
|
||||
/* Acer M3A and V35N */
|
||||
extern const device_t acerm3a_device;
|
||||
|
||||
/* ALi */
|
||||
extern const device_t ali1429_device;
|
||||
|
||||
/* Headland */
|
||||
extern const device_t headland_device;
|
||||
extern const device_t headland_386_device;
|
||||
|
||||
/* Intel 4x0xX */
|
||||
extern const device_t i420tx_device;
|
||||
extern const device_t i430lx_device;
|
||||
extern const device_t i430nx_device;
|
||||
extern const device_t i430fx_device;
|
||||
extern const device_t i430fx_pb640_device;
|
||||
extern const device_t i430hx_device;
|
||||
extern const device_t i430vx_device;
|
||||
#if defined(DEV_BRANCH) && defined(USE_I686)
|
||||
extern const device_t i440fx_device;
|
||||
#endif
|
||||
|
||||
/* NEAT */
|
||||
extern const device_t neat_device;
|
||||
|
||||
/* OPTi */
|
||||
extern const device_t opti495_device;
|
||||
|
||||
/* SCAT */
|
||||
extern const device_t scat_device;
|
||||
extern const device_t scat_4_device;
|
||||
extern const device_t scat_sx_device;
|
||||
|
||||
/* SiS */
|
||||
extern const device_t sis_85c471_device;
|
||||
extern const device_t sis_85c496_device;
|
||||
#if defined(DEV_BRANCH) && defined(USE_SIS_85C50X)
|
||||
extern const device_t sis_85c50x_device;
|
||||
#endif
|
||||
|
||||
/* WD */
|
||||
extern const device_t wd76c10_device;
|
||||
|
||||
|
||||
#endif /*EMU_CHIPSET_H*/
|
||||
635
src/chipset/headland.c
Normal file
635
src/chipset/headland.c
Normal file
@@ -0,0 +1,635 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* 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 HEADLAND AT286 chipset.
|
||||
*
|
||||
* Version: @(#)headland.c 1.0.1 2019/10/19
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Original by GreatPsycho for PCem.
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2010-2019 Sarah Walker.
|
||||
* Copyright 2017-2019 Fred N. van Kempen.
|
||||
* Copyright 2017-2019 Miran Grca.
|
||||
* Copyright 2017-2019 GreatPsycho.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include "../86box.h"
|
||||
#include "../cpu/cpu.h"
|
||||
#include "../cpu/x86.h"
|
||||
#include "../timer.h"
|
||||
#include "../io.h"
|
||||
#include "../mem.h"
|
||||
#include "../rom.h"
|
||||
#include "../device.h"
|
||||
#include "../keyboard.h"
|
||||
#include "../floppy/fdd.h"
|
||||
#include "../floppy/fdc.h"
|
||||
#include "../port_92.h"
|
||||
#include "chipset.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8_t valid, pad;
|
||||
uint16_t mr;
|
||||
|
||||
struct headland_t * headland;
|
||||
} headland_mr_t;
|
||||
|
||||
|
||||
typedef struct headland_t {
|
||||
uint8_t type;
|
||||
|
||||
uint8_t cri;
|
||||
uint8_t cr[8];
|
||||
|
||||
uint8_t indx;
|
||||
uint8_t regs[256];
|
||||
|
||||
uint8_t ems_mar;
|
||||
|
||||
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 upper_mapping[24];
|
||||
} headland_t;
|
||||
|
||||
|
||||
/* TODO - Headland chipset's memory address mapping emulation isn't fully implemented yet,
|
||||
so memory configuration is hardcoded now. */
|
||||
static const int mem_conf_cr0[41] = {
|
||||
0x00, 0x00, 0x20, 0x40, 0x60, 0xA0, 0x40, 0xE0,
|
||||
0xA0, 0xC0, 0xE0, 0xE0, 0xC0, 0xE0, 0xE0, 0xE0,
|
||||
0xE0, 0x20, 0x40, 0x40, 0xA0, 0xC0, 0xE0, 0xE0,
|
||||
0xC0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0,
|
||||
0x20, 0x40, 0x60, 0x60, 0xC0, 0xE0, 0xE0, 0xE0,
|
||||
0xE0
|
||||
};
|
||||
static const int mem_conf_cr1[41] = {
|
||||
0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40,
|
||||
0x00, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00,
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
|
||||
0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00,
|
||||
0x40
|
||||
};
|
||||
|
||||
|
||||
static uint32_t
|
||||
get_addr(headland_t *dev, uint32_t addr, headland_mr_t *mr)
|
||||
{
|
||||
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))
|
||||
addr -= 0x60000;
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
set_global_EMS_state(headland_t *dev, int state)
|
||||
{
|
||||
uint32_t base_addr, virt_addr;
|
||||
int i;
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
flushmmucache();
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
memmap_state_update(headland_t *dev)
|
||||
{
|
||||
uint32_t addr;
|
||||
int i;
|
||||
|
||||
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);
|
||||
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);
|
||||
mem_mapping_set_exec(&dev->mid_mapping, ram + 0xA0000);
|
||||
if (mem_size > 1024) {
|
||||
mem_mapping_set_addr(&dev->high_mapping, 0x160000, (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);
|
||||
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);
|
||||
mem_mapping_set_exec(&dev->high_mapping, ram + 0x100000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set_global_EMS_state(dev, dev->cr[0] & 3);
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
if (dev->ems_mar & 0x80)
|
||||
dev->ems_mar++;
|
||||
break;
|
||||
|
||||
case 0x01ed:
|
||||
dev->cri = val;
|
||||
break;
|
||||
|
||||
case 0x01ee:
|
||||
dev->ems_mar = val;
|
||||
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;
|
||||
|
||||
case 1:
|
||||
dev->cr[1] = (val & 0xbf) | mem_conf_cr1[(mem_size > 640 ? mem_size : mem_size - 128) >> 9];
|
||||
memmap_state_update(dev);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
case 5:
|
||||
dev->cr[dev->cri] = val;
|
||||
memmap_state_update(dev);
|
||||
break;
|
||||
|
||||
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);
|
||||
}
|
||||
break;
|
||||
|
||||
case 6:
|
||||
if (dev->cr[4] & 0x80) {
|
||||
dev->cr[dev->cri] = (val & 0xfe) | (mem_size > 8192 ? 1 : 0);
|
||||
memmap_state_update(dev);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
if (dev->ems_mar & 0x80)
|
||||
dev->ems_mar++;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
hl_read(uint16_t addr, void *priv)
|
||||
{
|
||||
headland_t *dev = (headland_t *)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)
|
||||
dev->ems_mar++;
|
||||
break;
|
||||
|
||||
case 0x01ed:
|
||||
ret = dev->cri;
|
||||
break;
|
||||
|
||||
case 0x01ee:
|
||||
ret = dev->ems_mar;
|
||||
break;
|
||||
|
||||
case 0x01ef:
|
||||
switch(dev->cri) {
|
||||
case 0:
|
||||
ret = (dev->cr[0] & 0x1f) | mem_conf_cr0[(mem_size > 640 ? mem_size : mem_size - 128) >> 9];
|
||||
break;
|
||||
|
||||
case 1:
|
||||
ret = (dev->cr[1] & 0xbf) | mem_conf_cr1[(mem_size > 640 ? mem_size : mem_size - 128) >> 9];
|
||||
break;
|
||||
|
||||
case 6:
|
||||
if (dev->cr[4] & 0x80)
|
||||
ret = (dev->cr[6] & 0xfe) | (mem_size > 8192 ? 1 : 0);
|
||||
else
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = dev->cr[dev->cri];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static uint16_t
|
||||
hl_readw(uint16_t addr, void *priv)
|
||||
{
|
||||
headland_t *dev = (headland_t *)priv;
|
||||
uint16_t ret = 0xffff;
|
||||
|
||||
switch(addr) {
|
||||
case 0x01ec:
|
||||
ret = dev->ems_mr[dev->ems_mar & 0x3f].mr | ((dev->cr[4] & 0x80) ? 0xf000 : 0xfc00);
|
||||
if (dev->ems_mar & 0x80)
|
||||
dev->ems_mar++;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
mem_read_b(uint32_t addr, void *priv)
|
||||
{
|
||||
headland_mr_t *mr = (headland_mr_t *) priv;
|
||||
headland_t *dev = mr->headland;
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
addr = get_addr(dev, addr, mr);
|
||||
if (addr < ((uint32_t)mem_size << 10))
|
||||
ret = ram[addr];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static uint16_t
|
||||
mem_read_w(uint32_t addr, void *priv)
|
||||
{
|
||||
headland_mr_t *mr = (headland_mr_t *) priv;
|
||||
headland_t *dev = mr->headland;
|
||||
uint16_t ret = 0xffff;
|
||||
|
||||
addr = get_addr(dev, addr, mr);
|
||||
if (addr < ((uint32_t)mem_size << 10))
|
||||
ret = *(uint16_t *)&ram[addr];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static uint32_t
|
||||
mem_read_l(uint32_t addr, void *priv)
|
||||
{
|
||||
headland_mr_t *mr = (headland_mr_t *) priv;
|
||||
headland_t *dev = mr->headland;
|
||||
uint32_t ret = 0xffffffff;
|
||||
|
||||
addr = get_addr(dev, addr, mr);
|
||||
if (addr < ((uint32_t)mem_size << 10))
|
||||
ret = *(uint32_t *)&ram[addr];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
mem_write_b(uint32_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
headland_mr_t *mr = (headland_mr_t *) priv;
|
||||
headland_t *dev = mr->headland;
|
||||
|
||||
addr = get_addr(dev, addr, mr);
|
||||
if (addr < ((uint32_t)mem_size << 10))
|
||||
ram[addr] = val;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
mem_write_w(uint32_t addr, uint16_t val, void *priv)
|
||||
{
|
||||
headland_mr_t *mr = (headland_mr_t *) priv;
|
||||
headland_t *dev = mr->headland;
|
||||
|
||||
addr = get_addr(dev, addr, mr);
|
||||
if (addr < ((uint32_t)mem_size << 10))
|
||||
*(uint16_t *)&ram[addr] = val;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
mem_write_l(uint32_t addr, uint32_t val, void *priv)
|
||||
{
|
||||
headland_mr_t *mr = (headland_mr_t *) priv;
|
||||
headland_t *dev = mr->headland;
|
||||
|
||||
addr = get_addr(dev, addr, mr);
|
||||
if (addr < ((uint32_t)mem_size << 10))
|
||||
*(uint32_t *)&ram[addr] = val;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
headland_close(void *priv)
|
||||
{
|
||||
headland_t *dev = (headland_t *)priv;
|
||||
|
||||
free(dev);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
headland_init(const device_t *info)
|
||||
{
|
||||
headland_t *dev;
|
||||
int ht386;
|
||||
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;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
dev->cr[i] = 0x00;
|
||||
dev->cr[0] = 0x04;
|
||||
|
||||
if (ht386) {
|
||||
dev->cr[4] = 0x20;
|
||||
|
||||
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(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;
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
dev->ems_mr[i].valid = 1;
|
||||
dev->ems_mr[i].mr = 0x00;
|
||||
dev->ems_mr[i].headland = dev;
|
||||
}
|
||||
|
||||
/* Turn off mem.c mappings. */
|
||||
mem_mapping_disable(&ram_low_mapping);
|
||||
mem_mapping_disable(&ram_mid_mapping);
|
||||
mem_mapping_disable(&ram_high_mapping);
|
||||
|
||||
mem_mapping_add(&dev->low_mapping, 0, 0x40000,
|
||||
mem_read_b, mem_read_w, mem_read_l,
|
||||
mem_write_b, mem_write_w, mem_write_l,
|
||||
ram, MEM_MAPPING_INTERNAL, &dev->null_mr);
|
||||
|
||||
if (mem_size > 640) {
|
||||
mem_mapping_add(&dev->mid_mapping, 0xa0000, 0x60000,
|
||||
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);
|
||||
}
|
||||
|
||||
if (mem_size > 1024) {
|
||||
mem_mapping_add(&dev->high_mapping, 0x100000, ((mem_size-1024)*1024),
|
||||
mem_read_b, mem_read_w, mem_read_l,
|
||||
mem_write_b, mem_write_w, mem_write_l,
|
||||
ram + 0x100000, MEM_MAPPING_INTERNAL, &dev->null_mr);
|
||||
mem_mapping_enable(&dev->high_mapping);
|
||||
}
|
||||
|
||||
for (i = 0; i < 24; i++) {
|
||||
mem_mapping_add(&dev->upper_mapping[i],
|
||||
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_MAPPING_INTERNAL, &dev->null_mr);
|
||||
mem_mapping_enable(&dev->upper_mapping[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
dev->ems_mr[i].mr = 0x00;
|
||||
mem_mapping_add(&dev->ems_mapping[i],
|
||||
((i & 31) + ((i & 31) >= 24 ? 24 : 16)) << 14, 0x04000,
|
||||
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]);
|
||||
}
|
||||
|
||||
memmap_state_update(dev);
|
||||
|
||||
return(dev);
|
||||
}
|
||||
|
||||
|
||||
const device_t headland_device = {
|
||||
"Headland 286",
|
||||
0,
|
||||
0,
|
||||
headland_init, headland_close, NULL,
|
||||
NULL, NULL, NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
const device_t headland_386_device = {
|
||||
"Headland 386",
|
||||
0,
|
||||
32,
|
||||
headland_init, headland_close, NULL,
|
||||
NULL, NULL, NULL,
|
||||
NULL
|
||||
};
|
||||
452
src/chipset/intel_4x0.c
Normal file
452
src/chipset/intel_4x0.c
Normal file
@@ -0,0 +1,452 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* 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 PCISet chips from 420TX to 440FX.
|
||||
*
|
||||
* Version: @(#)intel_4x0.c 1.0.2 2019/10/21
|
||||
*
|
||||
* 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.h"
|
||||
#include "../cpu/cpu.h"
|
||||
#include "../mem.h"
|
||||
#include "../io.h"
|
||||
#include "../rom.h"
|
||||
#include "../pci.h"
|
||||
#include "../device.h"
|
||||
#include "../keyboard.h"
|
||||
#include "chipset.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
INTEL_420TX,
|
||||
INTEL_430LX,
|
||||
INTEL_430NX,
|
||||
INTEL_430FX,
|
||||
INTEL_430FX_PB640,
|
||||
INTEL_430HX,
|
||||
INTEL_430VX
|
||||
#if defined(DEV_BRANCH) && defined(USE_I686)
|
||||
,INTEL_440FX
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t regs[256];
|
||||
int type;
|
||||
} i4x0_t;
|
||||
static void
|
||||
i4x0_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_INTERNAL | MEM_WRITE_EXTANY);
|
||||
break;
|
||||
case 2:
|
||||
mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_INTERNAL);
|
||||
break;
|
||||
case 3:
|
||||
mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
|
||||
break;
|
||||
}
|
||||
flushmmucache_nopc();
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
i4x0_write(int func, int addr, uint8_t val, void *priv)
|
||||
{
|
||||
i4x0_t *dev = (i4x0_t *) priv;
|
||||
|
||||
if (func)
|
||||
return;
|
||||
|
||||
if ((addr >= 0x10) && (addr < 0x4f))
|
||||
return;
|
||||
|
||||
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*/
|
||||
if (dev->type >= INTEL_430FX) {
|
||||
if (dev->type == INTEL_430FX_PB640)
|
||||
val &= 0x06;
|
||||
else
|
||||
val &= 0x02;
|
||||
} else
|
||||
val &= 0x42;
|
||||
val |= 0x04;
|
||||
break;
|
||||
case 0x05:
|
||||
if (dev->type >= INTEL_430FX)
|
||||
val = 0;
|
||||
else
|
||||
val &= 0x01;
|
||||
break;
|
||||
|
||||
case 0x06: /*Status*/
|
||||
val = 0;
|
||||
break;
|
||||
case 0x07:
|
||||
if (dev->type >= INTEL_430HX) {
|
||||
val &= 0x80;
|
||||
val |= 0x02;
|
||||
} else {
|
||||
val = 0x02;
|
||||
if (dev->type == INTEL_430FX_PB640)
|
||||
val |= 0x20;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x52: /*Cache Control Register*/
|
||||
#if defined(DEV_BRANCH) && defined(USE_I686)
|
||||
if (dev->type < INTEL_440FX) {
|
||||
#endif
|
||||
cpu_cache_ext_enabled = (val & 0x01);
|
||||
cpu_update_waitstates();
|
||||
#if defined(DEV_BRANCH) && defined(USE_I686)
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0x59: /*PAM0*/
|
||||
if ((dev->regs[0x59] ^ val) & 0xf0) {
|
||||
i4x0_map(0xf0000, 0x10000, val >> 4);
|
||||
shadowbios = (val & 0x10);
|
||||
}
|
||||
break;
|
||||
case 0x5a: /*PAM1*/
|
||||
if ((dev->regs[0x5a] ^ val) & 0x0f)
|
||||
i4x0_map(0xc0000, 0x04000, val & 0xf);
|
||||
if ((dev->regs[0x5a] ^ val) & 0xf0)
|
||||
i4x0_map(0xc4000, 0x04000, val >> 4);
|
||||
break;
|
||||
case 0x5b: /*PAM2*/
|
||||
if ((dev->regs[0x5b] ^ val) & 0x0f)
|
||||
i4x0_map(0xc8000, 0x04000, val & 0xf);
|
||||
if ((dev->regs[0x5b] ^ val) & 0xf0)
|
||||
i4x0_map(0xcc000, 0x04000, val >> 4);
|
||||
break;
|
||||
case 0x5c: /*PAM3*/
|
||||
if ((dev->regs[0x5c] ^ val) & 0x0f)
|
||||
i4x0_map(0xd0000, 0x04000, val & 0xf);
|
||||
if ((dev->regs[0x5c] ^ val) & 0xf0)
|
||||
i4x0_map(0xd4000, 0x04000, val >> 4);
|
||||
break;
|
||||
case 0x5d: /*PAM4*/
|
||||
if ((dev->regs[0x5d] ^ val) & 0x0f)
|
||||
i4x0_map(0xd8000, 0x04000, val & 0xf);
|
||||
if ((dev->regs[0x5d] ^ val) & 0xf0)
|
||||
i4x0_map(0xdc000, 0x04000, val >> 4);
|
||||
break;
|
||||
case 0x5e: /*PAM5*/
|
||||
if ((dev->regs[0x5e] ^ val) & 0x0f)
|
||||
i4x0_map(0xe0000, 0x04000, val & 0xf);
|
||||
if ((dev->regs[0x5e] ^ val) & 0xf0)
|
||||
i4x0_map(0xe4000, 0x04000, val >> 4);
|
||||
break;
|
||||
case 0x5f: /*PAM6*/
|
||||
if ((dev->regs[0x5f] ^ val) & 0x0f)
|
||||
i4x0_map(0xe8000, 0x04000, val & 0xf);
|
||||
if ((dev->regs[0x5f] ^ val) & 0xf0)
|
||||
i4x0_map(0xec000, 0x04000, val >> 4);
|
||||
break;
|
||||
case 0x72: /*SMRAM*/
|
||||
if ((dev->type >= INTEL_430FX) && ((dev->regs[0x72] ^ val) & 0x48))
|
||||
i4x0_map(0xa0000, 0x20000, ((val & 0x48) == 0x48) ? 3 : 0);
|
||||
else if ((dev->type < INTEL_430FX) && ((dev->regs[0x72] ^ val) & 0x20))
|
||||
i4x0_map(0xa0000, 0x20000, ((val & 0x20) == 0x20) ? 3 : 0);
|
||||
break;
|
||||
}
|
||||
|
||||
dev->regs[addr] = val;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
i4x0_read(int func, int addr, void *priv)
|
||||
{
|
||||
i4x0_t *dev = (i4x0_t *) priv;
|
||||
|
||||
if (func)
|
||||
return 0xff;
|
||||
|
||||
return dev->regs[addr];
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
i4x0_reset(void *priv)
|
||||
{
|
||||
i4x0_t *i4x0 = (i4x0_t *)priv;
|
||||
|
||||
i4x0_write(0, 0x59, 0x00, priv);
|
||||
if (i4x0->type >= INTEL_430FX)
|
||||
i4x0_write(0, 0x72, 0x02, priv);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
i4x0_close(void *p)
|
||||
{
|
||||
i4x0_t *i4x0 = (i4x0_t *)p;
|
||||
|
||||
free(i4x0);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
*i4x0_init(const device_t *info)
|
||||
{
|
||||
i4x0_t *i4x0 = (i4x0_t *) malloc(sizeof(i4x0_t));
|
||||
memset(i4x0, 0, sizeof(i4x0_t));
|
||||
|
||||
i4x0->type = info->local;
|
||||
|
||||
i4x0->regs[0x00] = 0x86; i4x0->regs[0x01] = 0x80; /*Intel*/
|
||||
switch(i4x0->type) {
|
||||
case INTEL_420TX:
|
||||
i4x0->regs[0x02] = 0x83; i4x0->regs[0x03] = 0x04; /*82424TX/ZX*/
|
||||
i4x0->regs[0x08] = 0x03; /*A3 stepping*/
|
||||
i4x0->regs[0x50] = 0x80;
|
||||
i4x0->regs[0x52] = 0x40; /*256kb PLB cache*/
|
||||
break;
|
||||
case INTEL_430LX:
|
||||
i4x0->regs[0x02] = 0xa3; i4x0->regs[0x03] = 0x04; /*82434LX/NX*/
|
||||
i4x0->regs[0x08] = 0x03; /*A3 stepping*/
|
||||
i4x0->regs[0x50] = 0x80;
|
||||
i4x0->regs[0x52] = 0x40; /*256kb PLB cache*/
|
||||
break;
|
||||
case INTEL_430NX:
|
||||
i4x0->regs[0x02] = 0xa3; i4x0->regs[0x03] = 0x04; /*82434LX/NX*/
|
||||
i4x0->regs[0x08] = 0x10; /*A0 stepping*/
|
||||
i4x0->regs[0x50] = 0xA0;
|
||||
i4x0->regs[0x52] = 0x44; /*256kb PLB cache*/
|
||||
i4x0->regs[0x66] = i4x0->regs[0x67] = 0x02;
|
||||
break;
|
||||
case INTEL_430FX:
|
||||
case INTEL_430FX_PB640:
|
||||
i4x0->regs[0x02] = 0x2d; i4x0->regs[0x03] = 0x12; /*SB82437FX-66*/
|
||||
if (i4x0->type == INTEL_430FX_PB640)
|
||||
i4x0->regs[0x08] = 0x02; /*???? stepping*/
|
||||
else
|
||||
i4x0->regs[0x08] = 0x00; /*A0 stepping*/
|
||||
i4x0->regs[0x52] = 0x40; /*256kb PLB cache*/
|
||||
break;
|
||||
case INTEL_430HX:
|
||||
i4x0->regs[0x02] = 0x50; i4x0->regs[0x03] = 0x12; /*82439HX*/
|
||||
i4x0->regs[0x08] = 0x00; /*A0 stepping*/
|
||||
i4x0->regs[0x51] = 0x20;
|
||||
i4x0->regs[0x52] = 0xB5; /*512kb cache*/
|
||||
i4x0->regs[0x56] = 0x52; /*DRAM control*/
|
||||
i4x0->regs[0x59] = 0x40;
|
||||
i4x0->regs[0x5A] = i4x0->regs[0x5B] = i4x0->regs[0x5C] = i4x0->regs[0x5D] = 0x44;
|
||||
i4x0->regs[0x5E] = i4x0->regs[0x5F] = 0x44;
|
||||
i4x0->regs[0x65] = i4x0->regs[0x66] = i4x0->regs[0x67] = 0x02;
|
||||
i4x0->regs[0x68] = 0x11;
|
||||
break;
|
||||
case INTEL_430VX:
|
||||
i4x0->regs[0x02] = 0x30; i4x0->regs[0x03] = 0x70; /*82437VX*/
|
||||
i4x0->regs[0x08] = 0x00; /*A0 stepping*/
|
||||
i4x0->regs[0x52] = 0x42; /*256kb PLB cache*/
|
||||
i4x0->regs[0x53] = 0x14;
|
||||
i4x0->regs[0x56] = 0x52; /*DRAM control*/
|
||||
i4x0->regs[0x67] = 0x11;
|
||||
i4x0->regs[0x69] = 0x03;
|
||||
i4x0->regs[0x70] = 0x20;
|
||||
i4x0->regs[0x74] = 0x0e;
|
||||
i4x0->regs[0x78] = 0x23;
|
||||
break;
|
||||
#if defined(DEV_BRANCH) && defined(USE_I686)
|
||||
case INTEL_440FX:
|
||||
i4x0->regs[0x02] = 0x37; i4x0->regs[0x03] = 0x12; /*82441FX*/
|
||||
i4x0->regs[0x08] = 0x02; /*A0 stepping*/
|
||||
i4x0->regs[0x2c] = 0xf4;
|
||||
i4x0->regs[0x2d] = 0x1a;
|
||||
i4x0->regs[0x2f] = 0x11;
|
||||
i4x0->regs[0x51] = 0x01;
|
||||
i4x0->regs[0x53] = 0x80;
|
||||
i4x0->regs[0x58] = 0x10;
|
||||
i4x0->regs[0x5a] = i4x0->regs[0x5b] = i4x0->regs[0x5c] = i4x0->regs[0x5d] = 0x11;
|
||||
i4x0->regs[0x5e] = 0x11;
|
||||
i4x0->regs[0x5f] = 0x31;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
i4x0->regs[0x04] = 0x06; i4x0->regs[0x05] = 0x00;
|
||||
#if defined(DEV_BRANCH) && defined(USE_I686)
|
||||
if (i4x0->type == INTEL_440FX)
|
||||
i4x0->regs[0x06] = 0x80;
|
||||
#endif
|
||||
if (i4x0->type == INTEL_430FX)
|
||||
i4x0->regs[0x07] = 0x82;
|
||||
#if defined(DEV_BRANCH) && defined(USE_I686)
|
||||
else if (i4x0->type != INTEL_440FX)
|
||||
#else
|
||||
else
|
||||
#endif
|
||||
i4x0->regs[0x07] = 0x02;
|
||||
i4x0->regs[0x0b] = 0x06;
|
||||
if (i4x0->type >= INTEL_430FX)
|
||||
i4x0->regs[0x57] = 0x01;
|
||||
else
|
||||
i4x0->regs[0x57] = 0x31;
|
||||
i4x0->regs[0x60] = i4x0->regs[0x61] = i4x0->regs[0x62] = i4x0->regs[0x63] = 0x02;
|
||||
i4x0->regs[0x64] = 0x02;
|
||||
if (i4x0->type >= INTEL_430FX)
|
||||
i4x0->regs[0x72] = 0x02;
|
||||
|
||||
#if defined(DEV_BRANCH) && defined(USE_I686)
|
||||
if (i4x0->type == INTEL_440FX) {
|
||||
cpu_cache_ext_enabled = 1;
|
||||
cpu_update_waitstates();
|
||||
}
|
||||
#endif
|
||||
|
||||
pci_add_card(0, i4x0_read, i4x0_write, i4x0);
|
||||
|
||||
return i4x0;
|
||||
}
|
||||
|
||||
|
||||
const device_t i420tx_device =
|
||||
{
|
||||
"Intel 82424TX",
|
||||
DEVICE_PCI,
|
||||
INTEL_420TX,
|
||||
i4x0_init,
|
||||
i4x0_close,
|
||||
i4x0_reset,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
const device_t i430lx_device =
|
||||
{
|
||||
"Intel 82434LX",
|
||||
DEVICE_PCI,
|
||||
INTEL_430LX,
|
||||
i4x0_init,
|
||||
i4x0_close,
|
||||
i4x0_reset,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
const device_t i430nx_device =
|
||||
{
|
||||
"Intel 82434NX",
|
||||
DEVICE_PCI,
|
||||
INTEL_430NX,
|
||||
i4x0_init,
|
||||
i4x0_close,
|
||||
i4x0_reset,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
const device_t i430fx_device =
|
||||
{
|
||||
"Intel SB82437FX-66",
|
||||
DEVICE_PCI,
|
||||
INTEL_430FX,
|
||||
i4x0_init,
|
||||
i4x0_close,
|
||||
i4x0_reset,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
const device_t i430fx_pb640_device =
|
||||
{
|
||||
"Intel SB82437FX-66 (PB640)",
|
||||
DEVICE_PCI,
|
||||
INTEL_430FX_PB640,
|
||||
i4x0_init,
|
||||
i4x0_close,
|
||||
i4x0_reset,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
const device_t i430hx_device =
|
||||
{
|
||||
"Intel 82439HX",
|
||||
DEVICE_PCI,
|
||||
INTEL_430HX,
|
||||
i4x0_init,
|
||||
i4x0_close,
|
||||
i4x0_reset,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
const device_t i430vx_device =
|
||||
{
|
||||
"Intel 82437VX",
|
||||
DEVICE_PCI,
|
||||
INTEL_430VX,
|
||||
i4x0_init,
|
||||
i4x0_close,
|
||||
i4x0_reset,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
#if defined(DEV_BRANCH) && defined(USE_I686)
|
||||
const device_t i440fx_device =
|
||||
{
|
||||
"Intel 82441FX",
|
||||
DEVICE_PCI,
|
||||
INTEL_440FX,
|
||||
i4x0_init,
|
||||
i4x0_close,
|
||||
i4x0_reset,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
#endif
|
||||
861
src/chipset/neat.c
Normal file
861
src/chipset/neat.c
Normal file
@@ -0,0 +1,861 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Emulation of C&T CS8121 ("NEAT") 82C206/211/212/215 chipset.
|
||||
*
|
||||
* Note: The datasheet mentions that the chipset supports up to 8MB
|
||||
* of DRAM. This is intepreted as 'being able to refresh up to
|
||||
* 8MB of DRAM chips', because it works fine with bus-based
|
||||
* memory expansion.
|
||||
*
|
||||
* Version: @(#)m_at_neat.c 1.0.5 2018/10/22
|
||||
*
|
||||
* Author: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
* Copyright 2018 Fred N. van Kempen.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include "../86box.h"
|
||||
#include "../device.h"
|
||||
#include "../timer.h"
|
||||
#include "../floppy/fdd.h"
|
||||
#include "../floppy/fdc.h"
|
||||
#include "../keyboard.h"
|
||||
#include "../io.h"
|
||||
#include "../mem.h"
|
||||
#include "../nmi.h"
|
||||
#include "chipset.h"
|
||||
|
||||
#define NEAT_DEBUG 0
|
||||
|
||||
|
||||
#define EMS_MAXPAGE 4
|
||||
#define EMS_PGSIZE 16384
|
||||
|
||||
|
||||
/* CS8221 82C211 controller registers. */
|
||||
#define REG_RA0 0x60 /* PROCCLK selector */
|
||||
# define RA0_MASK 0x34 /* RR11 X1XR */
|
||||
# define RA0_READY 0x01 /* local bus READY timeout */
|
||||
# define RA0_RDYNMIEN 0x04 /* local bus READY tmo NMI enable */
|
||||
# define RA0_PROCCLK 0x10 /* PROCCLK=BCLK (1) or CLK2IN (0) */
|
||||
# define RA0_ALTRST 0x20 /* alternate CPU reset (1) */
|
||||
# define RA0_REV 0xc0 /* chip revision ID */
|
||||
# define RA0_REV_SH 6
|
||||
# define RA0_REV_ID 2 /* faked revision# for 82C211 */
|
||||
|
||||
#define REG_RA1 0x61 /* Command Delay */
|
||||
# define RA1_MASK 0xff /* 1111 1111 */
|
||||
# define RA1_BUSDLY 0x03 /* AT BUS command delay */
|
||||
# define RA1_BUSDLY_SH 0
|
||||
# define RA1_BUS8DLY 0x0c /* AT BUS 8bit command delay */
|
||||
# define RA1_BUS8DLY_SH 2
|
||||
# define RA1_MEMDLY 0x30 /* AT BUS 16bit memory delay */
|
||||
# define RA1_MEMDLY_SH 4
|
||||
# define RA1_QUICKEN 0x40 /* Quick Mode enable */
|
||||
# define RA1_HOLDDLY 0x80 /* Hold Time Delay */
|
||||
|
||||
#define REG_RA2 0x62 /* Wait State / BCLK selector */
|
||||
# define RA2_MASK 0x3f /* XX11 1111 */
|
||||
# define RA2_BCLK 0x03 /* BCLK select */
|
||||
# define RA2_BCLK_SH 0
|
||||
# define BCLK_IN2 0 /* BCLK = CLK2IN/2 */
|
||||
# define BCLK_IN 1 /* BCLK = CLK2IN */
|
||||
# define BCLK_AT 2 /* BCLK = ATCLK */
|
||||
# define RA2_AT8WS 0x0c /* AT 8-bit wait states */
|
||||
# define RA2_AT8WS_SH 2
|
||||
# define AT8WS_2 0 /* 2 wait states */
|
||||
# define AT8WS_3 1 /* 3 wait states */
|
||||
# define AT8WS_4 2 /* 4 wait states */
|
||||
# define AT8WS_5 4 /* 5 wait states */
|
||||
# define RA2_ATWS 0x30 /* AT 16-bit wait states */
|
||||
# define RA2_ATWS_SH 4
|
||||
# define ATWS_2 0 /* 2 wait states */
|
||||
# define ATWS_3 1 /* 3 wait states */
|
||||
# define ATWS_4 2 /* 4 wait states */
|
||||
# define ATWS_5 4 /* 5 wait states */
|
||||
|
||||
/* CS8221 82C212 controller registers. */
|
||||
#define REG_RB0 0x64 /* Version ID */
|
||||
# define RB0_MASK 0x60 /* R11X XXXX */
|
||||
# define RB0_REV 0x60 /* Chip revsion number */
|
||||
# define RB0_REV_SH 5
|
||||
# define RB0_REV_ID 2 /* faked revision# for 82C212 */
|
||||
# define RB0_VERSION 0x80 /* Chip version (0=82C212) */
|
||||
|
||||
#define REG_RB1 0x65 /* ROM configuration */
|
||||
# define RB1_MASK 0xff /* 1111 1111 */
|
||||
# define RB1_ROMF0 0x01 /* ROM F0000 enabled (0) */
|
||||
# define RB1_ROME0 0x02 /* ROM E0000 disabled (1) */
|
||||
# define RB1_ROMD0 0x04 /* ROM D0000 disabled (1) */
|
||||
# define RB1_ROMC0 0x08 /* ROM C0000 disabled (1) */
|
||||
# define RB1_SHADOWF0 0x10 /* Shadow F0000 R/W (0) */
|
||||
# define RB1_SHADOWE0 0x20 /* Shadow E0000 R/W (0) */
|
||||
# define RB1_SHADOWD0 0x40 /* Shadow D0000 R/W (0) */
|
||||
# define RB1_SHADOWC0 0x80 /* Shadow C0000 R/W (0) */
|
||||
|
||||
#define REG_RB2 0x66 /* Memory Enable 1 */
|
||||
# define RB2_MASK 0x80 /* 1XXX XXXX */
|
||||
# define RB2_TOP128 0x80 /* top 128K is on sysboard (1) */
|
||||
|
||||
#define REG_RB3 0x67 /* Memory Enable 2 */
|
||||
# define RB3_MASK 0xff /* 1111 1111 */
|
||||
# define RB3_SHENB0 0x01 /* enable B0000-B3FFF shadow (1) */
|
||||
# define RB3_SHENB4 0x02 /* enable B4000-B7FFF shadow (1) */
|
||||
# define RB3_SHENB8 0x04 /* enable B8000-BBFFF shadow (1) */
|
||||
# define RB3_SHENBC 0x08 /* enable BC000-BFFFF shadow (1) */
|
||||
# define RB3_SHENA0 0x10 /* enable A0000-A3FFF shadow (1) */
|
||||
# define RB3_SHENA4 0x20 /* enable A4000-A7FFF shadow (1) */
|
||||
# define RB3_SHENA8 0x40 /* enable A8000-ABFFF shadow (1) */
|
||||
# define RB3_SHENAC 0x80 /* enable AC000-AFFFF shadow (1) */
|
||||
|
||||
#define REG_RB4 0x68 /* Memory Enable 3 */
|
||||
# define RB4_MASK 0xff /* 1111 1111 */
|
||||
# define RB4_SHENC0 0x01 /* enable C0000-C3FFF shadow (1) */
|
||||
# define RB4_SHENC4 0x02 /* enable C4000-C7FFF shadow (1) */
|
||||
# define RB4_SHENC8 0x04 /* enable C8000-CBFFF shadow (1) */
|
||||
# define RB4_SHENCC 0x08 /* enable CC000-CFFFF shadow (1) */
|
||||
# define RB4_SHEND0 0x10 /* enable D0000-D3FFF shadow (1) */
|
||||
# define RB4_SHEND4 0x20 /* enable D4000-D7FFF shadow (1) */
|
||||
# define RB4_SHEND8 0x40 /* enable D8000-DBFFF shadow (1) */
|
||||
# define RB4_SHENDC 0x80 /* enable DC000-DFFFF shadow (1) */
|
||||
|
||||
#define REG_RB5 0x69 /* Memory Enable 4 */
|
||||
# define RB5_MASK 0xff /* 1111 1111 */
|
||||
# define RB5_SHENE0 0x01 /* enable E0000-E3FFF shadow (1) */
|
||||
# define RB5_SHENE4 0x02 /* enable E4000-E7FFF shadow (1) */
|
||||
# define RB5_SHENE8 0x04 /* enable E8000-EBFFF shadow (1) */
|
||||
# define RB5_SHENEC 0x08 /* enable EC000-EFFFF shadow (1) */
|
||||
# define RB5_SHENF0 0x10 /* enable F0000-F3FFF shadow (1) */
|
||||
# define RB5_SHENF4 0x20 /* enable F4000-F7FFF shadow (1) */
|
||||
# define RB5_SHENF8 0x40 /* enable F8000-FBFFF shadow (1) */
|
||||
# define RB5_SHENFC 0x80 /* enable FC000-FFFFF shadow (1) */
|
||||
|
||||
#define REG_RB6 0x6a /* Bank 0/1 Enable */
|
||||
# define RB6_MASK 0xe0 /* 111R RRRR */
|
||||
# define RB6_BANKS 0x20 /* #banks used (1=two) */
|
||||
# define RB6_RTYPE 0xc0 /* DRAM chip size used */
|
||||
# define RTYPE_SH 6
|
||||
# define RTYPE_NONE 0 /* Disabled */
|
||||
# define RTYPE_MIXED 1 /* 64K/256K mixed (for 640K) */
|
||||
# define RTYPE_256K 2 /* 256K (default) */
|
||||
# define RTYPE_1M 3 /* 1M */
|
||||
|
||||
#define REG_RB7 0x6b /* DRAM configuration */
|
||||
# define RB7_MASK 0xff /* 1111 1111 */
|
||||
# define RB7_ROMWS 0x03 /* ROM access wait states */
|
||||
# define RB7_ROMWS_SH 0
|
||||
# define ROMWS_0 0 /* 0 wait states */
|
||||
# define ROMWS_1 1 /* 1 wait states */
|
||||
# define ROMWS_2 2 /* 2 wait states */
|
||||
# define ROMWS_3 3 /* 3 wait states (default) */
|
||||
# define RB7_EMSWS 0x0c /* EMS access wait states */
|
||||
# define RB7_EMSWS_SH 2
|
||||
# define EMSWS_0 0 /* 0 wait states */
|
||||
# define EMSWS_1 1 /* 1 wait states */
|
||||
# define EMSWS_2 2 /* 2 wait states */
|
||||
# define EMSWS_3 3 /* 3 wait states (default) */
|
||||
# define RB7_EMSEN 0x10 /* enable EMS (1=on) */
|
||||
# define RB7_RAMWS 0x20 /* RAM access wait state (1=1ws) */
|
||||
# define RB7_UMAREL 0x40 /* relocate 640-1024K to 1M */
|
||||
# define RB7_PAGEEN 0x80 /* enable Page/Interleaved mode */
|
||||
|
||||
#define REG_RB8 0x6c /* Bank 2/3 Enable */
|
||||
# define RB8_MASK 0xf0 /* 1111 RRRR */
|
||||
# define RB8_4WAY 0x10 /* enable 4-way interleave mode */
|
||||
# define RB8_BANKS 0x20 /* enable 2 banks (1) */
|
||||
# define RB8_RTYPE 0xc0 /* DRAM chip size used */
|
||||
# define RB8_RTYPE_SH 6
|
||||
|
||||
#define REG_RB9 0x6d /* EMS base address */
|
||||
# define RB9_MASK 0xff /* 1111 1111 */
|
||||
# define RB9_BASE 0x0f /* I/O base address selection */
|
||||
# define RB9_BASE_SH 0
|
||||
# define RB9_FRAME 0xf0 /* frame address selection */
|
||||
# define RB9_FRAME_SH 4
|
||||
|
||||
#define REG_RB10 0x6e /* EMS address extension */
|
||||
# define RB10_MASK 0xff /* 1111 1111 */
|
||||
# define RB10_P3EXT 0x03 /* page 3 extension */
|
||||
# define RB10_P3EXT_SH 0
|
||||
# define PEXT_0M 0 /* page is at 0-2M */
|
||||
# define PEXT_2M 1 /* page is at 2-4M */
|
||||
# define PEXT_4M 2 /* page is at 4-6M */
|
||||
# define PEXT_6M 3 /* page is at 6-8M */
|
||||
# define RB10_P2EXT 0x0c /* page 2 extension */
|
||||
# define RB10_P2EXT_SH 2
|
||||
# define RB10_P1EXT 0x30 /* page 1 extension */
|
||||
# define RB10_P1EXT_SH 4
|
||||
# define RB10_P0EXT 0xc0 /* page 0 extension */
|
||||
# define RB10_P0EXT_SH 6
|
||||
|
||||
#define REG_RB11 0x6f /* Miscellaneous */
|
||||
# define RB11_MASK 0xe6 /* 111R R11R */
|
||||
# define RB11_GA20 0x02 /* gate for A20 */
|
||||
# define RB11_RASTMO 0x04 /* enable RAS timeout counter */
|
||||
# define RB11_EMSLEN 0xe0 /* EMS memory chunk size */
|
||||
# define RB11_EMSLEN_SH 5
|
||||
|
||||
typedef struct {
|
||||
int8_t enabled; /* 1=ENABLED */
|
||||
char pad;
|
||||
uint16_t page; /* selected page in EMS block */
|
||||
uint32_t start; /* start of EMS in RAM */
|
||||
uint8_t *addr; /* start addr in EMS RAM */
|
||||
mem_mapping_t mapping; /* mapping entry for page */
|
||||
} emspage_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t regs[128]; /* all the CS8221 registers */
|
||||
uint8_t indx; /* programmed index into registers */
|
||||
|
||||
char pad;
|
||||
|
||||
uint16_t ems_base, /* configured base address */
|
||||
ems_oldbase;
|
||||
uint32_t ems_frame, /* configured frame address */
|
||||
ems_oldframe;
|
||||
uint16_t ems_size, /* EMS size in KB */
|
||||
ems_pages; /* EMS size in pages */
|
||||
emspage_t ems[EMS_MAXPAGE]; /* EMS page registers */
|
||||
} neat_t;
|
||||
|
||||
|
||||
#ifdef ENABLE_NEAT_LOG
|
||||
int neat_do_log = ENABLE_NEAT_LOG;
|
||||
|
||||
|
||||
static void
|
||||
neat_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (neat_do_log)
|
||||
{
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define neat_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
|
||||
/* Read one byte from paged RAM. */
|
||||
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;
|
||||
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));
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/* Read one word from paged RAM. */
|
||||
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;
|
||||
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));
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/* Write one byte to paged RAM. */
|
||||
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);
|
||||
|
||||
/* Write the data. */
|
||||
*(uint8_t *)(dev->ems[vpage].addr + (addr - map->base)) = 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);
|
||||
|
||||
/* Write the data. */
|
||||
*(uint16_t *)(dev->ems[vpage].addr + (addr - map->base)) = val;
|
||||
}
|
||||
|
||||
/* Re-calculate the active-page physical address. */
|
||||
static void
|
||||
ems_recalc(neat_t *dev, emspage_t *ems)
|
||||
{
|
||||
if (ems->page >= dev->ems_pages) {
|
||||
/* That page does not exist. */
|
||||
ems->enabled = 0;
|
||||
}
|
||||
|
||||
/* Pre-calculate the page address in EMS RAM. */
|
||||
ems->addr = ram + ems->start + (ems->page * EMS_PGSIZE);
|
||||
|
||||
if (ems->enabled) {
|
||||
/* Update the EMS RAM address for this page. */
|
||||
mem_mapping_set_exec(&ems->mapping, ems->addr);
|
||||
|
||||
/* Enable this page. */
|
||||
mem_mapping_enable(&ems->mapping);
|
||||
|
||||
#if NEAT_DEBUG > 1
|
||||
neat_log("NEAT EMS: page %d set to %08lx, %sabled)\n",
|
||||
ems->page, ems->addr-ram, ems->enabled?"en":"dis");
|
||||
#endif
|
||||
} else {
|
||||
/* Disable this page. */
|
||||
mem_mapping_disable(&ems->mapping);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ems_write(uint16_t port, uint8_t val, void *priv)
|
||||
{
|
||||
neat_t *dev = (neat_t *)priv;
|
||||
emspage_t *ems;
|
||||
int vpage;
|
||||
|
||||
#if NEAT_DEBUG > 1
|
||||
neat_log("NEAT: ems_write(%04x, %02x)\n", port, val);
|
||||
#endif
|
||||
|
||||
/* Get the viewport page number. */
|
||||
vpage = (port / EMS_PGSIZE);
|
||||
ems = &dev->ems[vpage];
|
||||
|
||||
switch(port & 0x000f) {
|
||||
case 0x0008:
|
||||
case 0x0009:
|
||||
ems->enabled = !!(val & 0x80);
|
||||
ems->page &= 0x0180; /* clear lower bits */
|
||||
ems->page |= (val & 0x7f); /* add new bits */
|
||||
ems_recalc(dev, ems);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
ems_read(uint16_t port, void *priv)
|
||||
{
|
||||
neat_t *dev = (neat_t *)priv;
|
||||
uint8_t ret = 0xff;
|
||||
int vpage;
|
||||
|
||||
/* Get the viewport page number. */
|
||||
vpage = (port / EMS_PGSIZE);
|
||||
|
||||
switch(port & 0x000f) {
|
||||
case 0x0008: /* page number register */
|
||||
ret = dev->ems[vpage].page & 0x7f;
|
||||
if (dev->ems[vpage].enabled)
|
||||
ret |= 0x80;
|
||||
break;
|
||||
}
|
||||
|
||||
#if NEAT_DEBUG > 1
|
||||
neat_log("NEAT: ems_read(%04x) = %02x\n", port, ret);
|
||||
#endif
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/* Initialize the EMS module. */
|
||||
static void
|
||||
ems_init(neat_t *dev, int en)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Remove if needed. */
|
||||
if (! en) {
|
||||
if (dev->ems_base > 0) for (i = 0; i < EMS_MAXPAGE; i++) {
|
||||
/* Disable for now. */
|
||||
mem_mapping_disable(&dev->ems[i].mapping);
|
||||
|
||||
/* Remove I/O handler. */
|
||||
io_removehandler(dev->ems_base + (i * EMS_PGSIZE), 2,
|
||||
ems_read,NULL,NULL, ems_write,NULL,NULL, dev);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_NEAT_LOG
|
||||
neat_log("NEAT: EMS disabled\n");
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get configured I/O address. */
|
||||
i = (dev->regs[REG_RB9] & RB9_BASE) >> RB9_BASE_SH;
|
||||
dev->ems_base = 0x0208 + (0x10 * i);
|
||||
|
||||
/* Get configured frame address. */
|
||||
i = (dev->regs[REG_RB9] & RB9_FRAME) >> RB9_FRAME_SH;
|
||||
dev->ems_frame = 0xC0000 + (EMS_PGSIZE * i);
|
||||
|
||||
/*
|
||||
* For each supported page (we can have a maximum of 4),
|
||||
* create, initialize and disable the mappings, and set
|
||||
* up the I/O control handler.
|
||||
*/
|
||||
for (i = 0; i < EMS_MAXPAGE; i++) {
|
||||
/* Create and initialize a page mapping. */
|
||||
mem_mapping_add(&dev->ems[i].mapping,
|
||||
dev->ems_frame + (EMS_PGSIZE*i), EMS_PGSIZE,
|
||||
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);
|
||||
|
||||
/* Disable for now. */
|
||||
mem_mapping_disable(&dev->ems[i].mapping);
|
||||
|
||||
/* Set up an I/O port handler. */
|
||||
io_sethandler(dev->ems_base + (i * EMS_PGSIZE), 2,
|
||||
ems_read,NULL,NULL, ems_write,NULL,NULL, dev);
|
||||
|
||||
/*
|
||||
* TODO: update the 'high_mem' mapping to reflect that we now
|
||||
* have NN MB less extended memory available..
|
||||
*/
|
||||
}
|
||||
|
||||
neat_log("NEAT: EMS enabled, I/O=%04xH, Frame=%05XH\n",
|
||||
dev->ems_base, dev->ems_frame);
|
||||
}
|
||||
|
||||
static void
|
||||
neat_write(uint16_t port, uint8_t val, void *priv)
|
||||
{
|
||||
neat_t *dev = (neat_t *)priv;
|
||||
uint8_t xval, *reg;
|
||||
int i;
|
||||
|
||||
#if NEAT_DEBUG > 2
|
||||
neat_log("NEAT: write(%04x, %02x)\n", port, val);
|
||||
#endif
|
||||
|
||||
switch (port) {
|
||||
case 0x22:
|
||||
dev->indx = val;
|
||||
break;
|
||||
|
||||
case 0x23:
|
||||
reg = &dev->regs[dev->indx];
|
||||
xval = *reg ^ val;
|
||||
switch (dev->indx) {
|
||||
case REG_RA0:
|
||||
val &= RA0_MASK;
|
||||
*reg = (*reg & ~RA0_MASK) | val | \
|
||||
(RA0_REV_ID << RA0_REV_SH);
|
||||
#if NEAT_DEBUG > 1
|
||||
neat_log("NEAT: RA0=%02x(%02x)\n", val, *reg);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case REG_RA1:
|
||||
val &= RA1_MASK;
|
||||
*reg = (*reg & ~RA1_MASK) | val;
|
||||
#if NEAT_DEBUG > 1
|
||||
neat_log("NEAT: RA1=%02x(%02x)\n", val, *reg);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case REG_RA2:
|
||||
val &= RA2_MASK;
|
||||
*reg = (*reg & ~RA2_MASK) | val;
|
||||
#if NEAT_DEBUG > 1
|
||||
neat_log("NEAT: RA2=%02x(%02x)\n", val, *reg);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case REG_RB0:
|
||||
val &= RB0_MASK;
|
||||
*reg = (*reg & ~RB0_MASK) | val | \
|
||||
(RB0_REV_ID << RB0_REV_SH);
|
||||
#if NEAT_DEBUG > 1
|
||||
neat_log("NEAT: RB0=%02x(%02x)\n", val, *reg);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case REG_RB1:
|
||||
val &= RB1_MASK;
|
||||
*reg = (*reg & ~RB1_MASK) | val;
|
||||
#if NEAT_DEBUG > 1
|
||||
neat_log("NEAT: RB1=%02x(%02x)\n", val, *reg);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case REG_RB2:
|
||||
val &= RB2_MASK;
|
||||
*reg = (*reg & ~RB2_MASK) | val;
|
||||
#if NEAT_DEBUG > 1
|
||||
neat_log("NEAT: RB2=%02x(%02x)\n", val, *reg);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case REG_RB3:
|
||||
val &= RB3_MASK;
|
||||
*reg = (*reg & ~RB3_MASK) | val;
|
||||
#if NEAT_DEBUG > 1
|
||||
neat_log("NEAT: RB3=%02x(%02x)\n", val, *reg);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case REG_RB4:
|
||||
val &= RB4_MASK;
|
||||
*reg = (*reg & ~RB4_MASK) | val;
|
||||
#if NEAT_DEBUG > 1
|
||||
neat_log("NEAT: RB4=%02x(%02x)\n", val, *reg);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case REG_RB5:
|
||||
val &= RB5_MASK;
|
||||
*reg = (*reg & ~RB5_MASK) | val;
|
||||
#if NEAT_DEBUG > 1
|
||||
neat_log("NEAT: RB5=%02x(%02x)\n", val, *reg);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case REG_RB6:
|
||||
val &= RB6_MASK;
|
||||
*reg = (*reg & ~RB6_MASK) | val;
|
||||
#if NEAT_DEBUG > 1
|
||||
neat_log("NEAT: RB6=%02x(%02x)\n", val, *reg);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case REG_RB7:
|
||||
val &= RB7_MASK;
|
||||
*reg = (*reg & ~RB7_MASK) | val;
|
||||
#if NEAT_DEBUG > 1
|
||||
neat_log("NEAT: RB7=%02x(%02x)\n", val, *reg);
|
||||
#endif
|
||||
if (val & RB7_EMSEN)
|
||||
ems_init(dev, 1);
|
||||
else if (xval & RB7_EMSEN)
|
||||
ems_init(dev, 0);
|
||||
|
||||
if (xval & RB7_UMAREL) {
|
||||
if (val & RB7_UMAREL)
|
||||
mem_remap_top(384);
|
||||
else
|
||||
mem_remap_top(0);
|
||||
}
|
||||
break;
|
||||
|
||||
case REG_RB8:
|
||||
val &= RB8_MASK;
|
||||
*reg = (*reg & ~RB8_MASK) | val;
|
||||
#if NEAT_DEBUG > 1
|
||||
neat_log("NEAT: RB8=%02x(%02x)\n", val, *reg);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case REG_RB9:
|
||||
val &= RB9_MASK;
|
||||
*reg = (*reg & ~RB9_MASK) | val;
|
||||
#if NEAT_DEBUG > 1
|
||||
neat_log("NEAT: RB9=%02x(%02x)\n", val, *reg);
|
||||
#endif
|
||||
if (dev->regs[REG_RB7] & RB7_EMSEN) {
|
||||
ems_init(dev, 0);
|
||||
ems_init(dev, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case REG_RB10:
|
||||
val &= RB10_MASK;
|
||||
*reg = (*reg & ~RB10_MASK) | val;
|
||||
#if NEAT_DEBUG > 1
|
||||
neat_log("NEAT: RB10=%02x(%02x)\n", val, *reg);
|
||||
#endif
|
||||
|
||||
dev->ems[3].start = ((val & RB10_P3EXT) >> RB10_P3EXT_SH) << 21;
|
||||
dev->ems[2].start = ((val & RB10_P2EXT) >> RB10_P2EXT_SH) << 21;
|
||||
dev->ems[1].start = ((val & RB10_P1EXT) >> RB10_P1EXT_SH) << 21;
|
||||
dev->ems[0].start = ((val & RB10_P0EXT) >> RB10_P0EXT_SH) << 21;
|
||||
for (i = 0; i < EMS_MAXPAGE; i++)
|
||||
ems_recalc(dev, &dev->ems[i]);
|
||||
break;
|
||||
|
||||
case REG_RB11:
|
||||
val &= RB11_MASK;
|
||||
*reg = (*reg & ~RB11_MASK) | val;
|
||||
#if NEAT_DEBUG > 1
|
||||
neat_log("NEAT: RB11=%02x(%02x)\n", val, *reg);
|
||||
#endif
|
||||
i = (val & RB11_EMSLEN) >> RB11_EMSLEN_SH;
|
||||
switch(i) {
|
||||
case 0: /* "less than 2MB" */
|
||||
dev->ems_size = 512;
|
||||
break;
|
||||
|
||||
case 1: /* 1 MB */
|
||||
case 2: /* 2 MB */
|
||||
case 3: /* 3 MB */
|
||||
case 4: /* 4 MB */
|
||||
case 5: /* 5 MB */
|
||||
case 6: /* 6 MB */
|
||||
case 7: /* 7 MB */
|
||||
dev->ems_size = i << 10;
|
||||
break;
|
||||
}
|
||||
dev->ems_pages = (dev->ems_size << 10) / EMS_PGSIZE;
|
||||
if (dev->regs[REG_RB7] & RB7_EMSEN) {
|
||||
neat_log("NEAT: EMS %iKB (%i pages)\n",
|
||||
dev->ems_size, dev->ems_pages);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
neat_log("NEAT: inv write to reg %02x (%02x)\n",
|
||||
dev->indx, val);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
neat_read(uint16_t port, void *priv)
|
||||
{
|
||||
neat_t *dev = (neat_t *)priv;
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
switch (port) {
|
||||
case 0x22:
|
||||
ret = dev->indx;
|
||||
break;
|
||||
|
||||
case 0x23:
|
||||
ret = dev->regs[dev->indx];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#if NEAT_DEBUG > 2
|
||||
neat_log("NEAT: read(%04x) = %02x\n", port, ret);
|
||||
#endif
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
neat_close(void *priv)
|
||||
{
|
||||
neat_t *dev = (neat_t *) priv;
|
||||
|
||||
free(dev);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
neat_init(const device_t *info)
|
||||
{
|
||||
neat_t *dev;
|
||||
int i;
|
||||
|
||||
/* Create an instance. */
|
||||
dev = (neat_t *)malloc(sizeof(neat_t));
|
||||
memset(dev, 0x00, sizeof(neat_t));
|
||||
|
||||
/* Initialize some of the registers to specific defaults. */
|
||||
for (i = REG_RA0; i <= REG_RB11; i++) {
|
||||
dev->indx = i;
|
||||
neat_write(0x0023, 0x00, dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Based on the value of mem_size, we have to set up
|
||||
* a proper DRAM configuration (so that EMS works.)
|
||||
*
|
||||
* TODO: We might also want to set 'valid' waitstate
|
||||
* bits, based on our cpu speed.
|
||||
*/
|
||||
i = 0;
|
||||
switch(mem_size) {
|
||||
case 512: /* 512KB */
|
||||
/* 256K, 0, 0, 0 */
|
||||
dev->regs[REG_RB6] &= ~RB6_BANKS; /* one bank */
|
||||
dev->regs[REG_RB6] |= (RTYPE_256K<<RTYPE_SH); /* 256K */
|
||||
dev->regs[REG_RB8] &= ~RB8_BANKS; /* one bank */
|
||||
dev->regs[REG_RB8] |= (RTYPE_NONE<<RTYPE_SH); /* NONE */
|
||||
i = 2;
|
||||
break;
|
||||
|
||||
case 640: /* 640KB */
|
||||
/* 256K, 64K, 0, 0 */
|
||||
dev->regs[REG_RB6] |= RB6_BANKS; /* two banks */
|
||||
dev->regs[REG_RB6] |= (RTYPE_MIXED<<RTYPE_SH); /* mixed */
|
||||
dev->regs[REG_RB8] &= ~RB8_BANKS; /* one bank */
|
||||
dev->regs[REG_RB8] |= (RTYPE_NONE<<RTYPE_SH); /* NONE */
|
||||
i = 4;
|
||||
break;
|
||||
|
||||
case 1024: /* 1MB */
|
||||
/* 256K, 256K, 0, 0 */
|
||||
dev->regs[REG_RB6] |= RB6_BANKS; /* two banks */
|
||||
dev->regs[REG_RB6] |= (RTYPE_256K<<RTYPE_SH); /* 256K */
|
||||
dev->regs[REG_RB8] &= ~RB8_BANKS; /* one bank */
|
||||
dev->regs[REG_RB8] |= (RTYPE_NONE<<RTYPE_SH); /* NONE */
|
||||
i = 5;
|
||||
break;
|
||||
|
||||
case 1536: /* 1.5MB */
|
||||
/* 256K, 256K, 256K, 0 */
|
||||
dev->regs[REG_RB6] |= RB6_BANKS; /* two banks */
|
||||
dev->regs[REG_RB6] |= (RTYPE_256K<<RTYPE_SH); /* 256K */
|
||||
dev->regs[REG_RB8] &= ~RB8_BANKS; /* one bank */
|
||||
dev->regs[REG_RB8] |= (RTYPE_256K<<RTYPE_SH); /* 256K */
|
||||
i = 7;
|
||||
break;
|
||||
|
||||
case 1664: /* 1.64MB */
|
||||
/* 256K, 64K, 256K, 256K */
|
||||
dev->regs[REG_RB6] |= RB6_BANKS; /* two banks */
|
||||
dev->regs[REG_RB6] |= (RTYPE_MIXED<<RTYPE_SH); /* mixed */
|
||||
dev->regs[REG_RB8] |= RB8_BANKS; /* two banks */
|
||||
dev->regs[REG_RB8] |= (RTYPE_256K<<RTYPE_SH); /* 256K */
|
||||
i = 10;
|
||||
break;
|
||||
|
||||
case 2048: /* 2MB */
|
||||
#if 1
|
||||
/* 256K, 256K, 256K, 256K */
|
||||
dev->regs[REG_RB6] |= RB6_BANKS; /* two banks */
|
||||
dev->regs[REG_RB6] |= (RTYPE_256K<<RTYPE_SH); /* 256K */
|
||||
dev->regs[REG_RB8] |= RB8_BANKS; /* two banks */
|
||||
dev->regs[REG_RB8] |= (RTYPE_256K<<RTYPE_SH); /* 256K */
|
||||
dev->regs[REG_RB8] |= RB8_4WAY; /* 4way intl */
|
||||
i = 11;
|
||||
#else
|
||||
/* 1M, 0, 0, 0 */
|
||||
dev->regs[REG_RB6] &= ~RB6_BANKS; /* one bank */
|
||||
dev->regs[REG_RB6] |= (RTYPE_1M<<RTYPE_SH); /* 1M */
|
||||
dev->regs[REG_RB8] &= ~RB8_BANKS; /* one bank */
|
||||
dev->regs[REG_RB8] |= (RTYPE_NONE<<RTYPE_SH); /* NONE */
|
||||
i = 3;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 3072: /* 3MB */
|
||||
/* 256K, 256K, 1M, 0 */
|
||||
dev->regs[REG_RB6] |= RB6_BANKS; /* two banks */
|
||||
dev->regs[REG_RB6] |= (RTYPE_256K<<RTYPE_SH); /* 256K */
|
||||
dev->regs[REG_RB8] &= ~RB8_BANKS; /* one bank */
|
||||
dev->regs[REG_RB8] |= (RTYPE_1M<<RTYPE_SH); /* 1M */
|
||||
i = 8;
|
||||
break;
|
||||
|
||||
case 4096: /* 4MB */
|
||||
/* 1M, 1M, 0, 0 */
|
||||
dev->regs[REG_RB6] |= RB6_BANKS; /* two banks */
|
||||
dev->regs[REG_RB6] |= (RTYPE_1M<<RTYPE_SH); /* 1M */
|
||||
dev->regs[REG_RB8] &= ~RB8_BANKS; /* one bank */
|
||||
dev->regs[REG_RB8] |= (RTYPE_NONE<<RTYPE_SH); /* NONE */
|
||||
i = 6;
|
||||
break;
|
||||
|
||||
case 4224: /* 4.64MB */
|
||||
/* 256K, 64K, 1M, 1M */
|
||||
dev->regs[REG_RB6] |= RB6_BANKS; /* two banks */
|
||||
dev->regs[REG_RB6] |= (RTYPE_MIXED<<RTYPE_SH); /* mixed */
|
||||
dev->regs[REG_RB8] |= RB8_BANKS; /* two banks */
|
||||
dev->regs[REG_RB8] |= (RTYPE_1M<<RTYPE_SH); /* 1M */
|
||||
i = 12;
|
||||
break;
|
||||
|
||||
case 5120: /* 5MB */
|
||||
/* 256K, 256K, 1M, 1M */
|
||||
dev->regs[REG_RB6] |= RB6_BANKS; /* two banks */
|
||||
dev->regs[REG_RB6] |= (RTYPE_256K<<RTYPE_SH); /* 256K */
|
||||
dev->regs[REG_RB8] |= RB8_BANKS; /* two banks */
|
||||
dev->regs[REG_RB8] |= (RTYPE_1M<<RTYPE_SH); /* 1M */
|
||||
i = 13;
|
||||
break;
|
||||
|
||||
case 6144: /* 6MB */
|
||||
/* 1M, 1M, 1M, 0 */
|
||||
dev->regs[REG_RB6] |= RB6_BANKS; /* two banks */
|
||||
dev->regs[REG_RB6] |= (RTYPE_1M<<RTYPE_SH); /* 1M */
|
||||
dev->regs[REG_RB8] &= ~RB8_BANKS; /* one bank */
|
||||
dev->regs[REG_RB8] |= (RTYPE_1M<<RTYPE_SH); /* 1M */
|
||||
i = 9;
|
||||
break;
|
||||
|
||||
case 8192: /* 8MB */
|
||||
/* 1M, 1M, 1M, 1M */
|
||||
dev->regs[REG_RB6] |= RB6_BANKS; /* two banks */
|
||||
dev->regs[REG_RB6] |= (RTYPE_1M<<RTYPE_SH); /* 1M */
|
||||
dev->regs[REG_RB8] |= RB8_BANKS; /* two banks */
|
||||
dev->regs[REG_RB8] |= (RTYPE_1M<<RTYPE_SH); /* 1M */
|
||||
dev->regs[REG_RB8] |= RB8_4WAY; /* 4way intl */
|
||||
i = 14;
|
||||
break;
|
||||
|
||||
default:
|
||||
neat_log("NEAT: **INVALID DRAM SIZE %iKB !**\n", mem_size);
|
||||
}
|
||||
if (i > 0) {
|
||||
neat_log("NEAT: using DRAM mode #%i (mem=%iKB)\n", i, mem_size);
|
||||
}
|
||||
|
||||
/* Set up an I/O handler for the chipset. */
|
||||
io_sethandler(0x0022, 2,
|
||||
neat_read,NULL,NULL, neat_write,NULL,NULL, dev);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
const device_t neat_device = {
|
||||
"C&T CS8121 (NEAT)",
|
||||
0,
|
||||
0,
|
||||
neat_init, neat_close, NULL,
|
||||
NULL, NULL, NULL,
|
||||
NULL
|
||||
};
|
||||
@@ -254,94 +254,116 @@ SeeAlso: #P0178,#P0187
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include "../86box.h"
|
||||
#include "../cpu/cpu.h"
|
||||
#include "../timer.h"
|
||||
#include "../io.h"
|
||||
#include "../device.h"
|
||||
#include "../keyboard.h"
|
||||
#include "../mem.h"
|
||||
#include "../floppy/fdd.h"
|
||||
#include "../floppy/fdc.h"
|
||||
#include "machine.h"
|
||||
#include "chipset.h"
|
||||
|
||||
|
||||
static uint8_t optiregs[0x10];
|
||||
static int optireg;
|
||||
|
||||
|
||||
static void opti495_write(uint16_t addr, uint8_t val, void *p)
|
||||
typedef struct
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x22:
|
||||
optireg=val;
|
||||
break;
|
||||
case 0x24:
|
||||
if (optireg>=0x20 && optireg<=0x2C)
|
||||
{
|
||||
optiregs[optireg-0x20]=val;
|
||||
if (optireg == 0x21)
|
||||
{
|
||||
cpu_cache_ext_enabled = val & 0x10;
|
||||
cpu_update_waitstates();
|
||||
}
|
||||
if (optireg == 0x22)
|
||||
{
|
||||
shadowbios = !(val & 0x80);
|
||||
shadowbios_write = val & 0x80;
|
||||
if (shadowbios)
|
||||
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED);
|
||||
else
|
||||
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
uint8_t cur_reg,
|
||||
regs[16],
|
||||
scratch[2];
|
||||
} opti495_t;
|
||||
|
||||
|
||||
static void
|
||||
opti495_write(uint16_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
opti495_t *dev = (opti495_t *) priv;
|
||||
|
||||
switch (addr) {
|
||||
case 0x22:
|
||||
dev->cur_reg = 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);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xe1:
|
||||
case 0xe2:
|
||||
dev->scratch[addr - 0xe1] = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t opti495_read(uint16_t addr, void *p)
|
||||
static uint8_t
|
||||
opti495_read(uint16_t addr, void *priv)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x24:
|
||||
if (optireg>=0x20 && optireg<=0x2C) return optiregs[optireg-0x20];
|
||||
break;
|
||||
}
|
||||
return 0xFF;
|
||||
uint8_t ret = 0xff;
|
||||
opti495_t *dev = (opti495_t *) priv;
|
||||
|
||||
switch (addr) {
|
||||
case 0x24:
|
||||
if ((dev->cur_reg >= 0x20) && (dev->cur_reg <= 0x2C))
|
||||
ret = dev->regs[dev->cur_reg - 0x20];
|
||||
break;
|
||||
case 0xe1:
|
||||
case 0xe2:
|
||||
ret = dev->scratch[addr - 0xe1];
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void opti495_init(void)
|
||||
static void
|
||||
opti495_close(void *priv)
|
||||
{
|
||||
io_sethandler(0x0022, 0x0001, opti495_read, NULL, NULL, opti495_write, NULL, NULL, NULL);
|
||||
io_sethandler(0x0024, 0x0001, opti495_read, NULL, NULL, opti495_write, NULL, NULL, NULL);
|
||||
optiregs[0x22-0x20] = 0x80;
|
||||
opti495_t *dev = (opti495_t *) priv;
|
||||
|
||||
free(dev);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
machine_at_opti495_init(const machine_t *model)
|
||||
static void *
|
||||
opti495_init(const device_t *info)
|
||||
{
|
||||
machine_at_common_ide_init(model);
|
||||
opti495_t *dev = (opti495_t *) malloc(sizeof(opti495_t));
|
||||
memset(dev, 0, sizeof(opti495_t));
|
||||
|
||||
device_add(&keyboard_at_device);
|
||||
device_add(&fdc_at_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);
|
||||
|
||||
opti495_init();
|
||||
dev->scratch[0] = dev->scratch[1] = 0xff;
|
||||
|
||||
io_sethandler(0x00e1, 0x0002, opti495_read, NULL, NULL, opti495_write, NULL, NULL, dev);
|
||||
|
||||
dev->regs[0x22 - 0x20] = 0x80;
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
machine_at_opti495_ami_init(const machine_t *model)
|
||||
{
|
||||
machine_at_common_ide_init(model);
|
||||
|
||||
device_add(&keyboard_at_ami_device);
|
||||
device_add(&fdc_at_device);
|
||||
|
||||
opti495_init();
|
||||
}
|
||||
const device_t opti495_device = {
|
||||
"OPTi 82C495",
|
||||
0,
|
||||
0,
|
||||
opti495_init, opti495_close, NULL,
|
||||
NULL, NULL, NULL,
|
||||
NULL
|
||||
};
|
||||
1597
src/chipset/scat.c
Normal file
1597
src/chipset/scat.c
Normal file
File diff suppressed because it is too large
Load Diff
293
src/chipset/sis_85c471.c
Normal file
293
src/chipset/sis_85c471.c
Normal file
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Emulation of the SiS 85c471 chip.
|
||||
*
|
||||
* SiS sis85c471 Super I/O Chip
|
||||
* Used by DTK PKM-0038S E-2
|
||||
*
|
||||
* Version: @(#)sis_85c471.c 1.0.2 2019/10/21
|
||||
*
|
||||
* 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.h"
|
||||
#include "../cpu/cpu.h"
|
||||
#include "../mem.h"
|
||||
#include "../io.h"
|
||||
#include "../lpt.h"
|
||||
#include "../rom.h"
|
||||
#include "../pci.h"
|
||||
#include "../device.h"
|
||||
#include "../disk/hdc_ide.h"
|
||||
#include "../keyboard.h"
|
||||
#include "../timer.h"
|
||||
#include "../port_92.h"
|
||||
#include "../serial.h"
|
||||
#include "../machine/machine.h"
|
||||
#include "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
|
||||
};
|
||||
342
src/chipset/sis_85c496.c
Normal file
342
src/chipset/sis_85c496.c
Normal file
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* 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 85c496/85c497 chip.
|
||||
*
|
||||
* Version: @(#)sis_85c496.c 1.0.2 2019/10/21
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2008-2019 Sarah Walker.
|
||||
* Copyright 2019 Miran Grca.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include "../86box.h"
|
||||
#include "../cpu/cpu.h"
|
||||
#include "../mem.h"
|
||||
#include "../io.h"
|
||||
#include "../rom.h"
|
||||
#include "../pci.h"
|
||||
#include "../device.h"
|
||||
#include "../keyboard.h"
|
||||
#include "../timer.h"
|
||||
#include "../port_92.h"
|
||||
#include "../disk/hdc_ide.h"
|
||||
#include "../machine/machine.h"
|
||||
#include "chipset.h"
|
||||
|
||||
|
||||
typedef struct sis_85c496_t
|
||||
{
|
||||
uint8_t cur_reg,
|
||||
regs[127],
|
||||
pci_conf[256];
|
||||
port_92_t * port_92;
|
||||
} sis_85c496_t;
|
||||
|
||||
|
||||
static void
|
||||
sis_85c497_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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
sis_85c497_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;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sis_85c496_recalcmapping(sis_85c496_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 (dev->pci_conf[0x44] & (1 << i)) {
|
||||
shadowbios |= (base >= 0xe0000) && (dev->pci_conf[0x45] & 0x02);
|
||||
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);
|
||||
} else
|
||||
mem_set_mem_state(base, 0x8000, MEM_READ_EXTANY | MEM_WRITE_EXTANY);
|
||||
}
|
||||
|
||||
flushmmucache();
|
||||
}
|
||||
|
||||
|
||||
/* 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_85c496_t *dev = (sis_85c496_t *) priv;
|
||||
uint8_t old = dev->pci_conf[addr];
|
||||
uint8_t valxor;
|
||||
|
||||
if ((addr >= 4 && addr < 8) || addr >= 0x40)
|
||||
dev->pci_conf[addr] = val;
|
||||
|
||||
valxor = old ^ val;
|
||||
|
||||
switch (addr) {
|
||||
case 0x42: /*Cache configure*/
|
||||
cpu_cache_ext_enabled = (val & 0x01);
|
||||
cpu_update_waitstates();
|
||||
break;
|
||||
|
||||
case 0x44: /*Shadow configure*/
|
||||
if (valxor & 0xff)
|
||||
sis_85c496_recalcmapping(dev);
|
||||
break;
|
||||
case 0x45: /*Shadow configure*/
|
||||
if (valxor & 0x03)
|
||||
sis_85c496_recalcmapping(dev);
|
||||
break;
|
||||
|
||||
case 0x56:
|
||||
if (valxor & 0x02) {
|
||||
port_92_remove(dev->port_92);
|
||||
if (val & 0x02)
|
||||
port_92_add(dev->port_92);
|
||||
pclog("Port 92: %sabled\n", (val & 0x02) ? "En" : "Dis");
|
||||
}
|
||||
break;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
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:
|
||||
if (valxor & 0x60) {
|
||||
port_92_set_features(dev->port_92, !!(val & 0x20), !!(val & 0x40));
|
||||
pclog("[Port 92] Set features: %sreset, %sA20\n", !!(val & 0x20) ? "" : "no ", !!(val & 0x40) ? "" : "no ");
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x82:
|
||||
sis_85c497_write(0x22, val, priv);
|
||||
break;
|
||||
|
||||
case 0xc0:
|
||||
if (val & 0x80)
|
||||
pci_set_irq_routing(PCI_INTA, val & 0xf);
|
||||
else
|
||||
pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED);
|
||||
break;
|
||||
case 0xc1:
|
||||
if (val & 0x80)
|
||||
pci_set_irq_routing(PCI_INTB, val & 0xf);
|
||||
else
|
||||
pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED);
|
||||
break;
|
||||
case 0xc2:
|
||||
if (val & 0x80)
|
||||
pci_set_irq_routing(PCI_INTC, val & 0xf);
|
||||
else
|
||||
pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED);
|
||||
break;
|
||||
case 0xc3:
|
||||
if (val & 0x80)
|
||||
pci_set_irq_routing(PCI_INTD, val & 0xf);
|
||||
else
|
||||
pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
sis_85c496_read(int func, int addr, void *priv)
|
||||
{
|
||||
sis_85c496_t *dev = (sis_85c496_t *) priv;
|
||||
|
||||
switch (addr) {
|
||||
case 0x82: /*Port 22h Mirror*/
|
||||
return inb(0x22);
|
||||
case 0x70: /*Port 70h Mirror*/
|
||||
return inb(0x70);
|
||||
}
|
||||
|
||||
return dev->pci_conf[addr];
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sis_85c497_reset(sis_85c496_t *dev)
|
||||
{
|
||||
memset(dev->regs, 0, sizeof(dev->regs));
|
||||
|
||||
dev->regs[0x01] = 0xc0;
|
||||
dev->regs[0x71] = 0x01;
|
||||
dev->regs[0x72] = 0xff;
|
||||
|
||||
io_removehandler(0x0022, 0x0002,
|
||||
sis_85c497_read, NULL, NULL, sis_85c497_write, NULL, NULL, dev);
|
||||
io_sethandler(0x0022, 0x0002,
|
||||
sis_85c497_read, NULL, NULL, sis_85c497_write, NULL, NULL, dev);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sis_85c496_reset(void *priv)
|
||||
{
|
||||
sis_85c496_t *dev = (sis_85c496_t *) priv;
|
||||
|
||||
sis_85c497_reset(dev);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sis_85c496_close(void *p)
|
||||
{
|
||||
sis_85c496_t *sis_85c496 = (sis_85c496_t *)p;
|
||||
|
||||
free(sis_85c496);
|
||||
}
|
||||
|
||||
|
||||
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));
|
||||
|
||||
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->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[0x0b] = 0x06;
|
||||
|
||||
dev->pci_conf[0x0e] = 0x00; /*Single function device*/
|
||||
|
||||
dev->pci_conf[0xd0] = 0x78; /* ROM at E0000-FFFFF, Flash enable. */
|
||||
dev->pci_conf[0xd1] = 0xff;
|
||||
|
||||
pci_add_card(5, sis_85c496_read, sis_85c496_write, dev);
|
||||
|
||||
sis_85c497_reset(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_85c496_recalcmapping(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
|
||||
};
|
||||
441
src/chipset/sis_85c50x.c
Normal file
441
src/chipset/sis_85c50x.c
Normal file
@@ -0,0 +1,441 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Implementation of the SiS 85c501/85c503 chip.
|
||||
*
|
||||
* Version: @(#)sis_85c50x.c 1.0.1 2019/10/19
|
||||
*
|
||||
* 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.h"
|
||||
#include "../mem.h"
|
||||
#include "../io.h"
|
||||
#include "../rom.h"
|
||||
#include "../pci.h"
|
||||
#include "../device.h"
|
||||
#include "../keyboard.h"
|
||||
#include "../port_92.h"
|
||||
#include "chipset.h"
|
||||
|
||||
|
||||
typedef struct sis_85c501_t
|
||||
{
|
||||
/* 85c501 */
|
||||
uint8_t turbo_reg;
|
||||
|
||||
/* 85c503 */
|
||||
|
||||
/* Registers */
|
||||
uint8_t pci_conf[2][256];
|
||||
|
||||
/* 85c50x ISA */
|
||||
uint8_t cur_reg,
|
||||
regs[39];
|
||||
} sis_85c50x_t;
|
||||
|
||||
|
||||
static void
|
||||
sis_85c501_recalcmapping(sis_85c50x_t *dev)
|
||||
{
|
||||
int c, d;
|
||||
uint32_t base;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
flushmmucache();
|
||||
shadowbios = 1;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sis_85c501_write(int func, int addr, uint8_t val, void *priv)
|
||||
{
|
||||
sis_85c50x_t *dev = (sis_85c50x_t *) priv;
|
||||
|
||||
if (func)
|
||||
return;
|
||||
|
||||
if ((addr >= 0x10) && (addr < 0x4f))
|
||||
return;
|
||||
|
||||
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;
|
||||
break;
|
||||
case 0x05:
|
||||
val &= 0x01;
|
||||
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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
dev->pci_conf[0][addr] = val;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sis_85c503_write(int func, int addr, uint8_t val, void *priv)
|
||||
{
|
||||
sis_85c50x_t *dev = (sis_85c50x_t *) priv;
|
||||
|
||||
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;
|
||||
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);
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
dev->pci_conf[1][addr] = val;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sis_85c50x_reset(void *priv)
|
||||
{
|
||||
sis_85c50x_t *dev = (sis_85c50x_t *) priv;
|
||||
|
||||
uint8_t val = 0;
|
||||
|
||||
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_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;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sis_85c50x_close(void *priv)
|
||||
{
|
||||
sis_85c50x_t *dev = (sis_85c50x_t *) priv;
|
||||
|
||||
free(dev);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
sis_85c50x_init(const device_t *info)
|
||||
{
|
||||
sis_85c50x_t *dev = (sis_85c50x_t *) malloc(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);
|
||||
|
||||
sis_85c50x_setup(dev);
|
||||
sis_85c50x_isa_reset(dev);
|
||||
|
||||
device_add(&port_92_pci_device);
|
||||
|
||||
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
|
||||
};
|
||||
292
src/chipset/wd76c10.c
Normal file
292
src/chipset/wd76c10.c
Normal file
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Implementation of the WD76C10 System Controller chip.
|
||||
*
|
||||
* Version: @(#)wd76c10.c 1.0.1 2019/10/19
|
||||
*
|
||||
* Authors: Sarah Walker, <tommowalker@tommowalker.co.uk>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
* Copyright 2008-2019 Sarah Walker.
|
||||
* Copyright 2016-2019 Miran Grca.
|
||||
* Copyright 2017-2019 Fred N. van Kempen.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include "../86box.h"
|
||||
#include "../device.h"
|
||||
#include "../timer.h"
|
||||
#include "../io.h"
|
||||
#include "../keyboard.h"
|
||||
#include "../mem.h"
|
||||
#include "../port_92.h"
|
||||
#include "../serial.h"
|
||||
#include "../floppy/fdd.h"
|
||||
#include "../floppy/fdc.h"
|
||||
#include "../video/vid_paradise.h"
|
||||
#include "chipset.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
|
||||
uint16_t reg_0092;
|
||||
uint16_t reg_2072;
|
||||
uint16_t reg_2872;
|
||||
uint16_t reg_5872;
|
||||
|
||||
uint16_t reg_f872;
|
||||
|
||||
serial_t *uart[2];
|
||||
|
||||
fdc_t *fdc;
|
||||
|
||||
mem_mapping_t extram_mapping;
|
||||
uint8_t extram[65536];
|
||||
} wd76c10_t;
|
||||
|
||||
|
||||
static uint16_t
|
||||
wd76c10_read(uint16_t port, void *priv)
|
||||
{
|
||||
wd76c10_t *dev = (wd76c10_t *)priv;
|
||||
int16_t ret = 0xffff;
|
||||
|
||||
switch (port) {
|
||||
case 0x2072:
|
||||
ret = dev->reg_2072;
|
||||
break;
|
||||
|
||||
case 0x2872:
|
||||
ret = dev->reg_2872;
|
||||
break;
|
||||
|
||||
case 0x5872:
|
||||
ret = dev->reg_5872;
|
||||
break;
|
||||
|
||||
case 0xf872:
|
||||
ret = dev->reg_f872;
|
||||
break;
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
wd76c10_write(uint16_t port, uint16_t val, void *priv)
|
||||
{
|
||||
wd76c10_t *dev = (wd76c10_t *)priv;
|
||||
|
||||
switch (port) {
|
||||
case 0x2072:
|
||||
dev->reg_2072 = val;
|
||||
|
||||
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 0x2872:
|
||||
dev->reg_2872 = val;
|
||||
|
||||
fdc_remove(dev->fdc);
|
||||
if (! (val & 1))
|
||||
fdc_set_base(dev->fdc, 0x03f0);
|
||||
break;
|
||||
|
||||
case 0x5872:
|
||||
dev->reg_5872 = val;
|
||||
break;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
wd76c10_t *dev = (wd76c10_t *)priv;
|
||||
|
||||
free(dev);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
wd76c10_init(const device_t *info)
|
||||
{
|
||||
wd76c10_t *dev;
|
||||
|
||||
dev = (wd76c10_t *) malloc(sizeof(wd76c10_t));
|
||||
memset(dev, 0x00, sizeof(wd76c10_t));
|
||||
dev->type = info->local;
|
||||
|
||||
dev->fdc = (fdc_t *)device_add(&fdc_at_device);
|
||||
|
||||
dev->uart[0] = device_add_inst(&i8250_device, 1);
|
||||
dev->uart[1] = device_add_inst(&i8250_device, 2);
|
||||
|
||||
device_add(&port_92_word_device);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
return(dev);
|
||||
}
|
||||
|
||||
|
||||
const device_t wd76c10_device = {
|
||||
"WD 76C10",
|
||||
0,
|
||||
0,
|
||||
wd76c10_init, wd76c10_close, NULL,
|
||||
NULL, NULL, NULL,
|
||||
NULL
|
||||
};
|
||||
456
src/config.c
456
src/config.c
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
@@ -8,16 +8,18 @@
|
||||
*
|
||||
* Configuration file handler.
|
||||
*
|
||||
* Version: @(#)config.c 1.0.48 2018/05/25
|
||||
* Version: @(#)config.c 1.0.66 2019/12/21
|
||||
*
|
||||
* Authors: Sarah Walker,
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Overdoze,
|
||||
* David Hrdlička, <hrdlickadavid@outlook.com>
|
||||
*
|
||||
* Copyright 2008-2018 Sarah Walker.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2008-2019 Sarah Walker.
|
||||
* Copyright 2016-2019 Miran Grca.
|
||||
* Copyright 2017-2019 Fred N. van Kempen.
|
||||
* Copyright 2018,2019 David Hrdlička.
|
||||
*
|
||||
* NOTE: Forcing config files to be in Unicode encoding breaks
|
||||
* it on Windows XP, and possibly also Vista. Use the
|
||||
@@ -34,8 +36,11 @@
|
||||
#include "86box.h"
|
||||
#include "cpu/cpu.h"
|
||||
#include "device.h"
|
||||
#include "timer.h"
|
||||
#include "nvr.h"
|
||||
#include "config.h"
|
||||
#include "isamem.h"
|
||||
#include "isartc.h"
|
||||
#include "lpt.h"
|
||||
#include "disk/hdd.h"
|
||||
#include "disk/hdc.h"
|
||||
@@ -47,13 +52,12 @@
|
||||
#include "mouse.h"
|
||||
#include "network/network.h"
|
||||
#include "scsi/scsi.h"
|
||||
#include "scsi/scsi_device.h"
|
||||
#include "cdrom/cdrom.h"
|
||||
#include "disk/zip.h"
|
||||
#include "sound/sound.h"
|
||||
#include "sound/midi.h"
|
||||
#include "sound/snd_dbopl.h"
|
||||
#include "sound/snd_mpu401.h"
|
||||
#include "sound/snd_opl.h"
|
||||
#include "sound/sound.h"
|
||||
#include "video/video.h"
|
||||
#include "plat.h"
|
||||
@@ -107,22 +111,22 @@ static list_t config_head;
|
||||
|
||||
#ifdef ENABLE_CONFIG_LOG
|
||||
int config_do_log = ENABLE_CONFIG_LOG;
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
config_log(const char *format, ...)
|
||||
config_log(const char *fmt, ...)
|
||||
{
|
||||
#ifdef ENABLE_CONFIG_LOG
|
||||
va_list ap;
|
||||
|
||||
if (config_do_log) {
|
||||
va_start(ap, format);
|
||||
pclog_ex(format, ap);
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
#define config_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
|
||||
static section_t *
|
||||
@@ -203,7 +207,7 @@ create_section(char *name)
|
||||
section_t *ns = malloc(sizeof(section_t));
|
||||
|
||||
memset(ns, 0x00, sizeof(section_t));
|
||||
strncpy(ns->name, name, sizeof(ns->name));
|
||||
memcpy(ns->name, name, strlen(name) + 1);
|
||||
list_add(&ns->list, &config_head);
|
||||
|
||||
return(ns);
|
||||
@@ -216,7 +220,7 @@ create_entry(section_t *section, char *name)
|
||||
entry_t *ne = malloc(sizeof(entry_t));
|
||||
|
||||
memset(ne, 0x00, sizeof(entry_t));
|
||||
strncpy(ne->name, name, sizeof(ne->name));
|
||||
memcpy(ne->name, name, strlen(name) + 1);
|
||||
list_add(&ne->list, §ion->entry_head);
|
||||
|
||||
return(ne);
|
||||
@@ -480,6 +484,10 @@ load_general(void)
|
||||
*/
|
||||
plat_langid = config_get_hex16(cat, "language", 0x0409);
|
||||
#endif
|
||||
|
||||
#if USE_DISCORD
|
||||
enable_discord = !!config_get_int(cat, "enable_discord", 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -512,26 +520,43 @@ load_machine(void)
|
||||
if (machine >= machine_count())
|
||||
machine = machine_count() - 1;
|
||||
|
||||
romset = machine_getromset();
|
||||
cpu_manufacturer = config_get_int(cat, "cpu_manufacturer", 0);
|
||||
cpu = config_get_int(cat, "cpu", 0);
|
||||
cpu_waitstates = config_get_int(cat, "cpu_waitstates", 0);
|
||||
|
||||
mem_size = config_get_int(cat, "mem_size", 4096);
|
||||
|
||||
#if 0
|
||||
if (mem_size < (((machines[machine].flags & MACHINE_AT) &&
|
||||
(machines[machine].ram_granularity < 128)) ? machines[machine].min_ram*1024 : machines[machine].min_ram))
|
||||
mem_size = (((machines[machine].flags & MACHINE_AT) && (machines[machine].ram_granularity < 128)) ? machines[machine].min_ram*1024 : machines[machine].min_ram);
|
||||
if (mem_size > 1048576)
|
||||
#endif
|
||||
|
||||
if (mem_size > 1048576)
|
||||
mem_size = 1048576;
|
||||
|
||||
cpu_use_dynarec = !!config_get_int(cat, "cpu_use_dynarec", 0);
|
||||
|
||||
enable_external_fpu = !!config_get_int(cat, "cpu_enable_fpu", 0);
|
||||
|
||||
enable_sync = !!config_get_int(cat, "enable_sync", 1);
|
||||
p = config_get_string(cat, "time_sync", NULL);
|
||||
if (p != NULL) {
|
||||
if (!strcmp(p, "disabled"))
|
||||
time_sync = TIME_SYNC_DISABLED;
|
||||
else
|
||||
if (!strcmp(p, "local"))
|
||||
time_sync = TIME_SYNC_ENABLED;
|
||||
else
|
||||
if (!strcmp(p, "utc") || !strcmp(p, "gmt"))
|
||||
time_sync = TIME_SYNC_ENABLED | TIME_SYNC_UTC;
|
||||
else
|
||||
time_sync = TIME_SYNC_ENABLED;
|
||||
} else
|
||||
time_sync = !!config_get_int(cat, "enable_sync", 1);
|
||||
|
||||
/* Remove this after a while.. */
|
||||
config_delete_var(cat, "nvr_path");
|
||||
config_delete_var(cat, "enable_sync");
|
||||
}
|
||||
|
||||
|
||||
@@ -542,9 +567,9 @@ load_video(void)
|
||||
char *cat = "Video";
|
||||
char *p;
|
||||
|
||||
if (machines[machine].fixed_gfxcard) {
|
||||
if (machines[machine].flags & MACHINE_VIDEO_FIXED) {
|
||||
config_delete_var(cat, "gfxcard");
|
||||
gfxcard = GFX_INTERNAL;
|
||||
gfxcard = VID_INTERNAL;
|
||||
} else {
|
||||
p = config_get_string(cat, "gfxcard", NULL);
|
||||
if (p == NULL) {
|
||||
@@ -624,20 +649,18 @@ load_sound(void)
|
||||
else
|
||||
midi_device_current = 0;
|
||||
|
||||
p = config_get_string(cat, "midi_in_device", NULL);
|
||||
if (p != NULL)
|
||||
midi_input_device_current = midi_in_device_get_from_internal_name(p);
|
||||
else
|
||||
midi_input_device_current = 0;
|
||||
|
||||
mpu401_standalone_enable = !!config_get_int(cat, "mpu401_standalone", 0);
|
||||
|
||||
SSI2001 = !!config_get_int(cat, "ssi2001", 0);
|
||||
GAMEBLASTER = !!config_get_int(cat, "gameblaster", 0);
|
||||
GUS = !!config_get_int(cat, "gus", 0);
|
||||
|
||||
memset(temp, '\0', sizeof(temp));
|
||||
p = config_get_string(cat, "opl_type", "dbopl");
|
||||
strcpy(temp, p);
|
||||
if (!strcmp(temp, "nukedopl") || !strcmp(temp, "1"))
|
||||
opl_type = 1;
|
||||
else
|
||||
opl_type = 0;
|
||||
|
||||
|
||||
memset(temp, '\0', sizeof(temp));
|
||||
p = config_get_string(cat, "sound_type", "float");
|
||||
strcpy(temp, p);
|
||||
@@ -703,28 +726,30 @@ load_ports(void)
|
||||
{
|
||||
char *cat = "Ports (COM & LPT)";
|
||||
char *p;
|
||||
char temp[512];
|
||||
int c, d;
|
||||
|
||||
serial_enabled[0] = !!config_get_int(cat, "serial1_enabled", 1);
|
||||
serial_enabled[1] = !!config_get_int(cat, "serial2_enabled", 1);
|
||||
lpt_enabled = !!config_get_int(cat, "lpt_enabled", 1);
|
||||
for (c = 0; c < 2; c++) {
|
||||
sprintf(temp, "serial%d_enabled", c + 1);
|
||||
serial_enabled[c] = !!config_get_int(cat, temp, 1);
|
||||
}
|
||||
|
||||
p = (char *)config_get_string(cat, "lpt1_device", NULL);
|
||||
if (p != NULL)
|
||||
strcpy(lpt_device_names[0], p);
|
||||
else
|
||||
strcpy(lpt_device_names[0], "none");
|
||||
for (c = 0; c < 3; c++) {
|
||||
sprintf(temp, "lpt%d_enabled", c + 1);
|
||||
lpt_ports[c].enabled = !!config_get_int(cat, temp, (c == 0) ? 1 : 0);
|
||||
|
||||
p = (char *)config_get_string(cat, "lpt2_device", NULL);
|
||||
if (p != NULL)
|
||||
strcpy(lpt_device_names[1], p);
|
||||
else
|
||||
strcpy(lpt_device_names[1], "none");
|
||||
sprintf(temp, "lpt%d_device", c + 1);
|
||||
p = (char *) config_get_string(cat, temp, "none");
|
||||
lpt_ports[c].device = lpt_device_get_from_internal_name(p);
|
||||
}
|
||||
|
||||
p = (char *)config_get_string(cat, "lpt3_device", NULL);
|
||||
if (p != NULL)
|
||||
strcpy(lpt_device_names[2], p);
|
||||
else
|
||||
strcpy(lpt_device_names[2], "none");
|
||||
/* Legacy config compatibility. */
|
||||
d = config_get_int(cat, "lpt_enabled", 2);
|
||||
if (d < 2) {
|
||||
for (c = 0; c < 3; c++)
|
||||
lpt_ports[c].enabled = d;
|
||||
}
|
||||
config_delete_var(cat, "lpt_enabled");
|
||||
}
|
||||
|
||||
|
||||
@@ -734,41 +759,48 @@ load_other_peripherals(void)
|
||||
{
|
||||
char *cat = "Other peripherals";
|
||||
char *p;
|
||||
|
||||
char temp[512];
|
||||
int c;
|
||||
|
||||
p = config_get_string(cat, "scsicard", NULL);
|
||||
if (p != NULL)
|
||||
scsi_card_current = scsi_card_get_from_internal_name(p);
|
||||
else
|
||||
scsi_card_current = 0;
|
||||
|
||||
if (hdc_name) {
|
||||
free(hdc_name);
|
||||
hdc_name = NULL;
|
||||
}
|
||||
p = config_get_string(cat, "hdc", NULL);
|
||||
if (p == NULL) {
|
||||
p = config_get_string(cat, "hdd_controller", NULL);
|
||||
if (p != NULL)
|
||||
config_delete_var(cat, "hdd_controller");
|
||||
}
|
||||
if (p == NULL) {
|
||||
if (machines[machine].flags & MACHINE_HDC) {
|
||||
hdc_name = (char *) malloc((strlen("internal") + 1) * sizeof(char));
|
||||
strcpy(hdc_name, "internal");
|
||||
p = (char *)malloc((strlen("internal")+1)*sizeof(char));
|
||||
strcpy(p, "internal");
|
||||
} else {
|
||||
hdc_name = (char *) malloc((strlen("none") + 1) * sizeof(char));
|
||||
strcpy(hdc_name, "none");
|
||||
p = (char *)malloc((strlen("none")+1)*sizeof(char));
|
||||
strcpy(p, "none");
|
||||
}
|
||||
} else {
|
||||
hdc_name = (char *) malloc((strlen(p) + 1) * sizeof(char));
|
||||
strcpy(hdc_name, p);
|
||||
}
|
||||
config_set_string(cat, "hdc", hdc_name);
|
||||
if (!strcmp(p, "mfm_xt"))
|
||||
hdc_current = hdc_get_from_internal_name("st506_xt");
|
||||
else if (!strcmp(p, "mfm_xt_dtc5150x"))
|
||||
hdc_current = hdc_get_from_internal_name("st506_xt_dtc5150x");
|
||||
else if (!strcmp(p, "mfm_at"))
|
||||
hdc_current = hdc_get_from_internal_name("st506_at");
|
||||
else
|
||||
hdc_current = hdc_get_from_internal_name(p);
|
||||
|
||||
ide_ter_enabled = !!config_get_int(cat, "ide_ter", 0);
|
||||
ide_qua_enabled = !!config_get_int(cat, "ide_qua", 0);
|
||||
|
||||
bugger_enabled = !!config_get_int(cat, "bugger_enabled", 0);
|
||||
|
||||
for (c = 0; c < ISAMEM_MAX; c++) {
|
||||
sprintf(temp, "isamem%d_type", c);
|
||||
|
||||
p = config_get_string(cat, temp, "none");
|
||||
isamem_type[c] = isamem_get_from_internal_name(p);
|
||||
}
|
||||
|
||||
p = config_get_string(cat, "isartc_type", "none");
|
||||
isartc_type = isartc_get_from_internal_name(p);
|
||||
}
|
||||
|
||||
|
||||
@@ -784,8 +816,6 @@ load_hard_disks(void)
|
||||
wchar_t *wp;
|
||||
uint32_t max_spt, max_hpc, max_tracks;
|
||||
uint32_t board = 0, dev = 0;
|
||||
/* FIXME: Remove in a month. */
|
||||
int lun;
|
||||
|
||||
memset(temp, '\0', sizeof(temp));
|
||||
for (c=0; c<HDD_NUM; c++) {
|
||||
@@ -802,18 +832,23 @@ load_hard_disks(void)
|
||||
break;
|
||||
|
||||
case HDD_BUS_MFM:
|
||||
max_spt = 17; /* 26 for RLL */
|
||||
max_spt = 26; /* 26 for RLL */
|
||||
max_hpc = 15;
|
||||
max_tracks = 1023;
|
||||
break;
|
||||
|
||||
case HDD_BUS_ESDI:
|
||||
case HDD_BUS_XTA:
|
||||
max_spt = 63;
|
||||
max_hpc = 16;
|
||||
max_tracks = 1023;
|
||||
break;
|
||||
|
||||
case HDD_BUS_ESDI:
|
||||
max_spt = 99;
|
||||
max_hpc = 16;
|
||||
max_tracks = 266305;
|
||||
break;
|
||||
|
||||
case HDD_BUS_IDE:
|
||||
max_spt = 63;
|
||||
max_hpc = 16;
|
||||
@@ -856,13 +891,6 @@ load_hard_disks(void)
|
||||
config_delete_var(cat, temp);
|
||||
|
||||
/* IDE */
|
||||
// FIXME: Remove in a month.
|
||||
sprintf(temp, "hdd_%02i_xtide_channel", c+1);
|
||||
if (hdd[c].bus == HDD_BUS_IDE)
|
||||
hdd[c].ide_channel = !!config_get_int(cat, temp, c & 1);
|
||||
else
|
||||
config_delete_var(cat, temp);
|
||||
|
||||
sprintf(temp, "hdd_%02i_ide_channel", c+1);
|
||||
if (hdd[c].bus == HDD_BUS_IDE) {
|
||||
sprintf(tmp2, "%01u:%01u", c>>1, c&1);
|
||||
@@ -888,21 +916,6 @@ load_hard_disks(void)
|
||||
} else
|
||||
config_delete_var(cat, temp);
|
||||
|
||||
/* FIXME: Remove in a month. */
|
||||
sprintf(temp, "hdd_%02i_scsi_location", c+1);
|
||||
if (hdd[c].bus == HDD_BUS_SCSI) {
|
||||
p = config_get_string(cat, temp, NULL);
|
||||
|
||||
if (p) {
|
||||
sscanf(p, "%02i:%02i",
|
||||
(int *)&hdd[c].scsi_id, (int *)&lun);
|
||||
|
||||
if (hdd[c].scsi_id > 15)
|
||||
hdd[c].scsi_id = 15;
|
||||
}
|
||||
}
|
||||
config_delete_var(cat, temp);
|
||||
|
||||
memset(hdd[c].fn, 0x00, sizeof(hdd[c].fn));
|
||||
memset(hdd[c].prev_fn, 0x00, sizeof(hdd[c].prev_fn));
|
||||
sprintf(temp, "hdd_%02i_fn", c+1);
|
||||
@@ -941,10 +954,6 @@ load_hard_disks(void)
|
||||
sprintf(temp, "hdd_%02i_scsi_id", c+1);
|
||||
config_delete_var(cat, temp);
|
||||
|
||||
/* FIXME: Remove in a month. */
|
||||
sprintf(temp, "hdd_%02i_scsi_location", c+1);
|
||||
config_delete_var(cat, temp);
|
||||
|
||||
sprintf(temp, "hdd_%02i_fn", c+1);
|
||||
config_delete_var(cat, temp);
|
||||
}
|
||||
@@ -1039,64 +1048,49 @@ load_other_removable_devices(void)
|
||||
char s[512];
|
||||
unsigned int board = 0, dev = 0;
|
||||
wchar_t *wp;
|
||||
int c;
|
||||
/* FIXME: Remove in a month. */
|
||||
int lun;
|
||||
int c, d = 0;
|
||||
|
||||
memset(temp, 0x00, sizeof(temp));
|
||||
for (c=0; c<CDROM_NUM; c++) {
|
||||
sprintf(temp, "cdrom_%02i_host_drive", c+1);
|
||||
cdrom_drives[c].host_drive = config_get_int(cat, temp, 0);
|
||||
cdrom_drives[c].prev_host_drive = cdrom_drives[c].host_drive;
|
||||
cdrom[c].host_drive = config_get_int(cat, temp, 0);
|
||||
cdrom[c].prev_host_drive = cdrom[c].host_drive;
|
||||
|
||||
sprintf(temp, "cdrom_%02i_parameters", c+1);
|
||||
p = config_get_string(cat, temp, NULL);
|
||||
if (p != NULL)
|
||||
sscanf(p, "%01u, %s", &cdrom_drives[c].sound_on, s);
|
||||
sscanf(p, "%01u, %s", &d, s);
|
||||
else
|
||||
sscanf("0, none", "%01u, %s", &cdrom_drives[c].sound_on, s);
|
||||
cdrom_drives[c].bus_type = hdd_string_to_bus(s, 1);
|
||||
sscanf("0, none", "%01u, %s", &d, s);
|
||||
cdrom[c].sound_on = d;
|
||||
cdrom[c].bus_type = hdd_string_to_bus(s, 1);
|
||||
|
||||
sprintf(temp, "cdrom_%02i_speed", c+1);
|
||||
cdrom_drives[c].speed = config_get_int(cat, temp, 8);
|
||||
cdrom[c].speed = config_get_int(cat, temp, 8);
|
||||
|
||||
/* Default values, needed for proper operation of the Settings dialog. */
|
||||
cdrom_drives[c].ide_channel = cdrom_drives[c].scsi_device_id = c + 2;
|
||||
cdrom[c].ide_channel = cdrom[c].scsi_device_id = c + 2;
|
||||
|
||||
sprintf(temp, "cdrom_%02i_ide_channel", c+1);
|
||||
if (cdrom_drives[c].bus_type == CDROM_BUS_ATAPI) {
|
||||
if (cdrom[c].bus_type == CDROM_BUS_ATAPI) {
|
||||
sprintf(tmp2, "%01u:%01u", (c+2)>>1, (c+2)&1);
|
||||
p = config_get_string(cat, temp, tmp2);
|
||||
sscanf(p, "%01u:%01u", &board, &dev);
|
||||
board &= 3;
|
||||
dev &= 1;
|
||||
cdrom_drives[c].ide_channel = (board<<1)+dev;
|
||||
cdrom[c].ide_channel = (board<<1)+dev;
|
||||
|
||||
if (cdrom_drives[c].ide_channel > 7)
|
||||
cdrom_drives[c].ide_channel = 7;
|
||||
if (cdrom[c].ide_channel > 7)
|
||||
cdrom[c].ide_channel = 7;
|
||||
} else {
|
||||
sprintf(temp, "cdrom_%02i_scsi_id", c+1);
|
||||
if (cdrom_drives[c].bus_type == CDROM_BUS_SCSI) {
|
||||
cdrom_drives[c].scsi_device_id = config_get_int(cat, temp, c+2);
|
||||
if (cdrom[c].bus_type == CDROM_BUS_SCSI) {
|
||||
cdrom[c].scsi_device_id = config_get_int(cat, temp, c+2);
|
||||
|
||||
if (cdrom_drives[c].scsi_device_id > 15)
|
||||
cdrom_drives[c].scsi_device_id = 15;
|
||||
if (cdrom[c].scsi_device_id > 15)
|
||||
cdrom[c].scsi_device_id = 15;
|
||||
} else
|
||||
config_delete_var(cat, temp);
|
||||
|
||||
/* FIXME: Remove in a month. */
|
||||
sprintf(temp, "cdrom_%02i_scsi_location", c+1);
|
||||
if (cdrom_drives[c].bus_type == CDROM_BUS_SCSI) {
|
||||
p = config_get_string(cat, temp, NULL);
|
||||
if (p) {
|
||||
sscanf(p, "%02u:%02u",
|
||||
&cdrom_drives[c].scsi_device_id, &lun);
|
||||
|
||||
if (cdrom_drives[c].scsi_device_id > 15)
|
||||
cdrom_drives[c].scsi_device_id = 15;
|
||||
}
|
||||
}
|
||||
config_delete_var(cat, temp);
|
||||
}
|
||||
|
||||
sprintf(temp, "cdrom_%02i_image_path", c+1);
|
||||
@@ -1116,20 +1110,20 @@ load_other_removable_devices(void)
|
||||
* with the EXE path. Just strip
|
||||
* that off for now...
|
||||
*/
|
||||
wcsncpy(cdrom_image[c].image_path, &wp[wcslen(usr_path)], sizeof_w(cdrom_image[c].image_path));
|
||||
wcsncpy(cdrom[c].image_path, &wp[wcslen(usr_path)], sizeof_w(cdrom[c].image_path));
|
||||
} else
|
||||
#endif
|
||||
wcsncpy(cdrom_image[c].image_path, wp, sizeof_w(cdrom_image[c].image_path));
|
||||
wcsncpy(cdrom[c].image_path, wp, sizeof_w(cdrom[c].image_path));
|
||||
|
||||
if (cdrom_drives[c].host_drive < 'A')
|
||||
cdrom_drives[c].host_drive = 0;
|
||||
if (cdrom[c].host_drive && (cdrom[c].host_drive != 200))
|
||||
cdrom[c].host_drive = 0;
|
||||
|
||||
if ((cdrom_drives[c].host_drive == 0x200) &&
|
||||
(wcslen(cdrom_image[c].image_path) == 0))
|
||||
cdrom_drives[c].host_drive = 0;
|
||||
if ((cdrom[c].host_drive == 0x200) &&
|
||||
(wcslen(cdrom[c].image_path) == 0))
|
||||
cdrom[c].host_drive = 0;
|
||||
|
||||
/* If the CD-ROM is disabled, delete all its variables. */
|
||||
if (cdrom_drives[c].bus_type == CDROM_BUS_DISABLED) {
|
||||
if (cdrom[c].bus_type == CDROM_BUS_DISABLED) {
|
||||
sprintf(temp, "cdrom_%02i_host_drive", c+1);
|
||||
config_delete_var(cat, temp);
|
||||
|
||||
@@ -1142,10 +1136,6 @@ load_other_removable_devices(void)
|
||||
sprintf(temp, "cdrom_%02i_scsi_id", c+1);
|
||||
config_delete_var(cat, temp);
|
||||
|
||||
/* FIXME: Remove in a month. */
|
||||
sprintf(temp, "cdrom_%02i_scsi_location", c+1);
|
||||
config_delete_var(cat, temp);
|
||||
|
||||
sprintf(temp, "cdrom_%02i_image_path", c+1);
|
||||
config_delete_var(cat, temp);
|
||||
}
|
||||
@@ -1187,20 +1177,6 @@ load_other_removable_devices(void)
|
||||
zip_drives[c].scsi_device_id = 15;
|
||||
} else
|
||||
config_delete_var(cat, temp);
|
||||
|
||||
/* FIXME: Remove in a month. */
|
||||
sprintf(temp, "zip_%02i_scsi_location", c+1);
|
||||
if (zip_drives[c].bus_type == CDROM_BUS_SCSI) {
|
||||
p = config_get_string(cat, temp, NULL);
|
||||
if (p) {
|
||||
sscanf(p, "%02u:%02u",
|
||||
&zip_drives[c].scsi_device_id, &lun);
|
||||
|
||||
if (zip_drives[c].scsi_device_id > 15)
|
||||
zip_drives[c].scsi_device_id = 15;
|
||||
}
|
||||
}
|
||||
config_delete_var(cat, temp);
|
||||
}
|
||||
|
||||
sprintf(temp, "zip_%02i_image_path", c+1);
|
||||
@@ -1239,10 +1215,6 @@ load_other_removable_devices(void)
|
||||
sprintf(temp, "zip_%02i_scsi_id", c+1);
|
||||
config_delete_var(cat, temp);
|
||||
|
||||
/* FIXME: Remove in a month. */
|
||||
sprintf(temp, "zip_%02i_scsi_location", c+1);
|
||||
config_delete_var(cat, temp);
|
||||
|
||||
sprintf(temp, "zip_%02i_image_path", c+1);
|
||||
config_delete_var(cat, temp);
|
||||
}
|
||||
@@ -1262,8 +1234,7 @@ config_load(void)
|
||||
config_log("Loading config file '%ls'..\n", cfg_path);
|
||||
|
||||
memset(hdd, 0, sizeof(hard_disk_t));
|
||||
memset(cdrom_drives, 0, sizeof(cdrom_drive_t) * CDROM_NUM);
|
||||
memset(cdrom_image, 0, sizeof(cdrom_image_t) * CDROM_NUM);
|
||||
memset(cdrom, 0, sizeof(cdrom_t) * CDROM_NUM);
|
||||
#ifdef USE_IOCTL
|
||||
memset(cdrom_ioctl, 0, sizeof(cdrom_ioctl_t) * CDROM_NUM);
|
||||
#endif
|
||||
@@ -1276,19 +1247,16 @@ config_load(void)
|
||||
#endif
|
||||
scale = 1;
|
||||
machine = machine_get_machine_from_internal_name("ibmpc");
|
||||
gfxcard = GFX_CGA;
|
||||
gfxcard = video_get_video_from_internal_name("cga");
|
||||
vid_api = plat_vidapi("default");
|
||||
enable_sync = 1;
|
||||
time_sync = TIME_SYNC_ENABLED;
|
||||
joystick_type = 7;
|
||||
if (hdc_name) {
|
||||
free(hdc_name);
|
||||
hdc_name = NULL;
|
||||
}
|
||||
hdc_name = (char *) malloc((strlen("none")+1) * sizeof(char));
|
||||
strcpy(hdc_name, "none");
|
||||
hdc_current = hdc_get_from_internal_name("none");
|
||||
serial_enabled[0] = 1;
|
||||
serial_enabled[1] = 1;
|
||||
lpt_enabled = 1;
|
||||
lpt_ports[0].enabled = 1;
|
||||
lpt_ports[1].enabled = 0;
|
||||
lpt_ports[2].enabled = 0;
|
||||
for (i = 0; i < FDD_NUM; i++) {
|
||||
if (i < 2)
|
||||
fdd_set_type(i, 2);
|
||||
@@ -1299,7 +1267,9 @@ config_load(void)
|
||||
fdd_set_check_bpb(i, 1);
|
||||
}
|
||||
mem_size = 640;
|
||||
opl_type = 0;
|
||||
isartc_type = 0;
|
||||
for (i = 0; i < ISAMEM_MAX; i++)
|
||||
isamem_type[i] = 0;
|
||||
|
||||
config_log("Config file not present or invalid!\n");
|
||||
return;
|
||||
@@ -1416,6 +1386,13 @@ save_general(void)
|
||||
config_set_hex16(cat, "language", plat_langid);
|
||||
#endif
|
||||
|
||||
#if USE_DISCORD
|
||||
if (enable_discord)
|
||||
config_set_int(cat, "enable_discord", enable_discord);
|
||||
else
|
||||
config_delete_var(cat, "enable_discord");
|
||||
#endif
|
||||
|
||||
delete_section_if_empty(cat);
|
||||
}
|
||||
|
||||
@@ -1455,10 +1432,13 @@ save_machine(void)
|
||||
else
|
||||
config_set_int(cat, "cpu_enable_fpu", enable_external_fpu);
|
||||
|
||||
if (enable_sync == 1)
|
||||
config_delete_var(cat, "enable_sync");
|
||||
else
|
||||
config_set_int(cat, "enable_sync", enable_sync);
|
||||
if (time_sync & TIME_SYNC_ENABLED)
|
||||
if (time_sync & TIME_SYNC_UTC)
|
||||
config_set_string(cat, "time_sync", "utc");
|
||||
else
|
||||
config_set_string(cat, "time_sync", "local");
|
||||
else
|
||||
config_set_string(cat, "time_sync", "disabled");
|
||||
|
||||
delete_section_if_empty(cat);
|
||||
}
|
||||
@@ -1471,7 +1451,7 @@ save_video(void)
|
||||
char *cat = "Video";
|
||||
|
||||
config_set_string(cat, "gfxcard",
|
||||
video_get_internal_name(video_old_to_new(gfxcard)));
|
||||
video_get_internal_name(gfxcard));
|
||||
|
||||
if (voodoo_enabled == 0)
|
||||
config_delete_var(cat, "voodoo");
|
||||
@@ -1492,13 +1472,10 @@ save_input_devices(void)
|
||||
|
||||
config_set_string(cat, "mouse_type", mouse_get_internal_name(mouse_type));
|
||||
|
||||
if ((joystick_type == 0) || (joystick_type == 7)) {
|
||||
if (joystick_type == 7)
|
||||
config_delete_var(cat, "joystick_type");
|
||||
else
|
||||
config_set_int(cat, "joystick_type", joystick_type);
|
||||
if (joystick_type == 7) {
|
||||
config_delete_var(cat, "joystick_type");
|
||||
|
||||
for (c=0; c<16; c++) {
|
||||
for (c = 0; c < 16; c++) {
|
||||
sprintf(tmp2, "joystick_%i_nr", c);
|
||||
config_delete_var(cat, tmp2);
|
||||
|
||||
@@ -1518,7 +1495,7 @@ save_input_devices(void)
|
||||
} else {
|
||||
config_set_int(cat, "joystick_type", joystick_type);
|
||||
|
||||
for (c=0; c<joystick_get_max_joysticks(joystick_type); c++) {
|
||||
for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) {
|
||||
sprintf(tmp2, "joystick_%i_nr", c);
|
||||
config_set_int(cat, tmp2, joystick_state[c].plat_joystick_nr);
|
||||
|
||||
@@ -1560,6 +1537,11 @@ save_sound(void)
|
||||
else
|
||||
config_set_string(cat, "midi_device", midi_device_get_internal_name(midi_device_current));
|
||||
|
||||
if (!strcmp(midi_in_device_get_internal_name(midi_input_device_current), "none"))
|
||||
config_delete_var(cat, "midi_in_device");
|
||||
else
|
||||
config_set_string(cat, "midi_in_device", midi_in_device_get_internal_name(midi_input_device_current));
|
||||
|
||||
if (mpu401_standalone_enable == 0)
|
||||
config_delete_var(cat, "mpu401_standalone");
|
||||
else
|
||||
@@ -1580,11 +1562,6 @@ save_sound(void)
|
||||
else
|
||||
config_set_int(cat, "gus", GUS);
|
||||
|
||||
if (opl_type == 0)
|
||||
config_delete_var(cat, "opl_type");
|
||||
else
|
||||
config_set_string(cat, "opl_type", (opl_type == 1) ? "nukedopl" : "dbopl");
|
||||
|
||||
if (sound_is_float == 1)
|
||||
config_delete_var(cat, "sound_type");
|
||||
else
|
||||
@@ -1631,36 +1608,32 @@ static void
|
||||
save_ports(void)
|
||||
{
|
||||
char *cat = "Ports (COM & LPT)";
|
||||
char temp[512];
|
||||
int c, d;
|
||||
|
||||
if (serial_enabled[0])
|
||||
config_delete_var(cat, "serial1_enabled");
|
||||
else
|
||||
config_set_int(cat, "serial1_enabled", serial_enabled[0]);
|
||||
for (c = 0; c < 2; c++) {
|
||||
sprintf(temp, "serial%d_enabled", c + 1);
|
||||
if (serial_enabled[c])
|
||||
config_delete_var(cat, temp);
|
||||
else
|
||||
config_set_int(cat, temp, serial_enabled[c]);
|
||||
}
|
||||
|
||||
if (serial_enabled[1])
|
||||
config_delete_var(cat, "serial2_enabled");
|
||||
else
|
||||
config_set_int(cat, "serial2_enabled", serial_enabled[1]);
|
||||
for (c = 0; c < 3; c++) {
|
||||
sprintf(temp, "lpt%d_enabled", c + 1);
|
||||
d = (c == 0) ? 1 : 0;
|
||||
if (lpt_ports[c].enabled == d)
|
||||
config_delete_var(cat, temp);
|
||||
else
|
||||
config_set_int(cat, temp, lpt_ports[c].enabled);
|
||||
|
||||
if (lpt_enabled)
|
||||
config_delete_var(cat, "lpt_enabled");
|
||||
else
|
||||
config_set_int(cat, "lpt_enabled", lpt_enabled);
|
||||
|
||||
if (!strcmp(lpt_device_names[0], "none"))
|
||||
config_delete_var(cat, "lpt1_device");
|
||||
else
|
||||
config_set_string(cat, "lpt1_device", lpt_device_names[0]);
|
||||
|
||||
if (!strcmp(lpt_device_names[1], "none"))
|
||||
config_delete_var(cat, "lpt2_device");
|
||||
else
|
||||
config_set_string(cat, "lpt2_device", lpt_device_names[1]);
|
||||
|
||||
if (!strcmp(lpt_device_names[2], "none"))
|
||||
config_delete_var(cat, "lpt3_device");
|
||||
else
|
||||
config_set_string(cat, "lpt3_device", lpt_device_names[2]);
|
||||
sprintf(temp, "lpt%d_device", c + 1);
|
||||
if (lpt_ports[c].device == 0)
|
||||
config_delete_var(cat, temp);
|
||||
else
|
||||
config_set_string(cat, temp,
|
||||
(char *) lpt_device_get_internal_name(lpt_ports[c].device));
|
||||
}
|
||||
|
||||
delete_section_if_empty(cat);
|
||||
}
|
||||
@@ -1671,6 +1644,8 @@ static void
|
||||
save_other_peripherals(void)
|
||||
{
|
||||
char *cat = "Other peripherals";
|
||||
char temp[512];
|
||||
int c;
|
||||
|
||||
if (scsi_card_current == 0)
|
||||
config_delete_var(cat, "scsicard");
|
||||
@@ -1678,7 +1653,8 @@ save_other_peripherals(void)
|
||||
config_set_string(cat, "scsicard",
|
||||
scsi_card_get_internal_name(scsi_card_current));
|
||||
|
||||
config_set_string(cat, "hdc", hdc_name);
|
||||
config_set_string(cat, "hdc",
|
||||
hdc_get_internal_name(hdc_current));
|
||||
|
||||
if (ide_ter_enabled == 0)
|
||||
config_delete_var(cat, "ide_ter");
|
||||
@@ -1695,6 +1671,21 @@ save_other_peripherals(void)
|
||||
else
|
||||
config_set_int(cat, "bugger_enabled", bugger_enabled);
|
||||
|
||||
for (c = 0; c < ISAMEM_MAX; c++) {
|
||||
sprintf(temp, "isamem%d_type", c);
|
||||
if (isamem_type[c] == 0)
|
||||
config_delete_var(cat, temp);
|
||||
else
|
||||
config_set_string(cat, temp,
|
||||
(char *) isamem_get_internal_name(isamem_type[c]));
|
||||
}
|
||||
|
||||
if (isartc_type == 0)
|
||||
config_delete_var(cat, "isartc_type");
|
||||
else
|
||||
config_set_string(cat, "isartc_type",
|
||||
isartc_get_internal_name(isartc_type));
|
||||
|
||||
delete_section_if_empty(cat);
|
||||
}
|
||||
|
||||
@@ -1704,7 +1695,7 @@ static void
|
||||
save_hard_disks(void)
|
||||
{
|
||||
char *cat = "Hard disks";
|
||||
char temp[24], tmp2[64];
|
||||
char temp[32], tmp2[64];
|
||||
char *p;
|
||||
int c;
|
||||
|
||||
@@ -1824,51 +1815,50 @@ save_other_removable_devices(void)
|
||||
|
||||
for (c=0; c<CDROM_NUM; c++) {
|
||||
sprintf(temp, "cdrom_%02i_host_drive", c+1);
|
||||
if ((cdrom_drives[c].bus_type == 0) ||
|
||||
(cdrom_drives[c].host_drive < 'A') || ((cdrom_drives[c].host_drive > 'Z') && (cdrom_drives[c].host_drive != 200))) {
|
||||
if ((cdrom[c].bus_type == 0) || (cdrom[c].host_drive != 200)) {
|
||||
config_delete_var(cat, temp);
|
||||
} else {
|
||||
config_set_int(cat, temp, cdrom_drives[c].host_drive);
|
||||
config_set_int(cat, temp, cdrom[c].host_drive);
|
||||
}
|
||||
|
||||
sprintf(temp, "cdrom_%02i_speed", c+1);
|
||||
if ((cdrom_drives[c].bus_type == 0) || (cdrom_drives[c].speed == 8)) {
|
||||
if ((cdrom[c].bus_type == 0) || (cdrom[c].speed == 8)) {
|
||||
config_delete_var(cat, temp);
|
||||
} else {
|
||||
config_set_int(cat, temp, cdrom_drives[c].speed);
|
||||
config_set_int(cat, temp, cdrom[c].speed);
|
||||
}
|
||||
|
||||
sprintf(temp, "cdrom_%02i_parameters", c+1);
|
||||
if (cdrom_drives[c].bus_type == 0) {
|
||||
if (cdrom[c].bus_type == 0) {
|
||||
config_delete_var(cat, temp);
|
||||
} else {
|
||||
sprintf(tmp2, "%u, %s", cdrom_drives[c].sound_on,
|
||||
hdd_bus_to_string(cdrom_drives[c].bus_type, 1));
|
||||
sprintf(tmp2, "%u, %s", cdrom[c].sound_on,
|
||||
hdd_bus_to_string(cdrom[c].bus_type, 1));
|
||||
config_set_string(cat, temp, tmp2);
|
||||
}
|
||||
|
||||
sprintf(temp, "cdrom_%02i_ide_channel", c+1);
|
||||
if (cdrom_drives[c].bus_type != CDROM_BUS_ATAPI)
|
||||
if (cdrom[c].bus_type != CDROM_BUS_ATAPI)
|
||||
config_delete_var(cat, temp);
|
||||
else {
|
||||
sprintf(tmp2, "%01u:%01u", cdrom_drives[c].ide_channel>>1,
|
||||
cdrom_drives[c].ide_channel & 1);
|
||||
sprintf(tmp2, "%01u:%01u", cdrom[c].ide_channel>>1,
|
||||
cdrom[c].ide_channel & 1);
|
||||
config_set_string(cat, temp, tmp2);
|
||||
}
|
||||
|
||||
sprintf(temp, "cdrom_%02i_scsi_id", c + 1);
|
||||
if (cdrom_drives[c].bus_type != CDROM_BUS_SCSI) {
|
||||
if (cdrom[c].bus_type != CDROM_BUS_SCSI) {
|
||||
config_delete_var(cat, temp);
|
||||
} else {
|
||||
config_set_int(cat, temp, cdrom_drives[c].scsi_device_id);
|
||||
config_set_int(cat, temp, cdrom[c].scsi_device_id);
|
||||
}
|
||||
|
||||
sprintf(temp, "cdrom_%02i_image_path", c + 1);
|
||||
if ((cdrom_drives[c].bus_type == 0) ||
|
||||
(wcslen(cdrom_image[c].image_path) == 0)) {
|
||||
if ((cdrom[c].bus_type == 0) ||
|
||||
(wcslen(cdrom[c].image_path) == 0)) {
|
||||
config_delete_var(cat, temp);
|
||||
} else {
|
||||
config_set_wstring(cat, temp, cdrom_image[c].image_path);
|
||||
config_set_wstring(cat, temp, cdrom[c].image_path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1939,7 +1929,7 @@ config_dump(void)
|
||||
while (sec != NULL) {
|
||||
entry_t *ent;
|
||||
|
||||
if (sec->name && sec->name[0])
|
||||
if (sec->name[0])
|
||||
config_log("[%s]\n", sec->name);
|
||||
|
||||
ent = (entry_t *)sec->entry_head.next;
|
||||
@@ -2182,7 +2172,7 @@ config_set_string(char *head, char *name, char *val)
|
||||
if (ent == NULL)
|
||||
ent = create_entry(section, name);
|
||||
|
||||
strncpy(ent->data, val, sizeof(ent->data));
|
||||
memcpy(ent->data, val, sizeof(ent->data));
|
||||
mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata));
|
||||
}
|
||||
|
||||
|
||||
110
src/config.h
110
src/config.h
@@ -27,6 +27,116 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
typedef struct {
|
||||
uint8_t id,
|
||||
uint8_t bus_type, /* Bus type: IDE, SCSI, etc. */
|
||||
bus, :4, /* ID of the bus (for example, for IDE,
|
||||
0 = primary, 1 = secondary, etc. */
|
||||
bus_id, :4, /* ID of the device on the bus */
|
||||
uint8_t type, /* Type flags, interpretation depends
|
||||
on the device */
|
||||
uint8_t is_image; /* This is only used for CD-ROM:
|
||||
0 = Image;
|
||||
1 = Host drive */
|
||||
|
||||
wchar_t path[1024]; /* Name of current image file or
|
||||
host drive */
|
||||
|
||||
uint32_t spt, /* Physical geometry parameters */
|
||||
hpc,
|
||||
tracks;
|
||||
} storage_cfg_t;
|
||||
|
||||
typedef struct {
|
||||
/* General configuration */
|
||||
int vid_resize, /* Window is resizable or not */
|
||||
vid_renderer, /* Renderer */
|
||||
vid_fullscreen_scale, /* Full screen scale type */
|
||||
vid_fullscreen_start, /* Start emulator in full screen */
|
||||
vid_force_43, /* Force 4:3 display ratio in windowed mode */
|
||||
vid_scale, /* Windowed mode scale */
|
||||
vid_overscan, /* EGA/(S)VGA overscan enabled */
|
||||
vid_cga_contrast, /* CGA alternate contrast enabled */
|
||||
vid_grayscale, /* Video is grayscale */
|
||||
vid_grayscale_type, /* Video grayscale type */
|
||||
vid_invert_display, /* Invert display */
|
||||
rctrl_is_lalt, /* Right CTRL is left ALT */
|
||||
update_icons, /* Update status bar icons */
|
||||
window_remember, /* Remember window position and size */
|
||||
window_w, /* Window coordinates */
|
||||
window_h,
|
||||
window_x,
|
||||
window_y,
|
||||
sound_gain; /* Sound gain */
|
||||
#ifdef USE_LANGUAGE
|
||||
uint16_t language_id; /* Language ID (0x0409 = English (US)) */
|
||||
#endif
|
||||
|
||||
/* Machine cateogory */
|
||||
int machine, /* Machine */
|
||||
cpu_manufacturer, /* CPU manufacturer */
|
||||
cpu, /* CPU */
|
||||
#ifdef USE_DYNAREC
|
||||
cpu_use_dynarec, /* CPU recompiler enabled */
|
||||
#endif
|
||||
wait_states, /* CPU wait states */
|
||||
enable_external_fpu, /* FPU enabled */
|
||||
time_sync; /* Time sync enabled */
|
||||
uint32_t mem_size; /* Memory size */
|
||||
|
||||
/* Video category */
|
||||
int video_card, /* Video card */
|
||||
voodoo_enabled; /* Voodoo enabled */
|
||||
|
||||
/* Input devices category */
|
||||
int mouse_type, /* Mouse type */
|
||||
joystick_type; /* Joystick type */
|
||||
|
||||
/* Sound category */
|
||||
int sound_card, /* Sound card */
|
||||
midi_device, /* Midi device */
|
||||
mpu_401, /* Standalone MPU-401 enabled */
|
||||
ssi_2001_enabled, /* SSI-2001 enabled */
|
||||
game_blaster_enabled, /* Game blaster enabled */
|
||||
gus_enabled, /* Gravis Ultrasound enabled */
|
||||
opl_type, /* OPL emulation type */
|
||||
sound_is_float; /* Sound is 32-bit float or 16-bit integer */
|
||||
|
||||
/* Network category */
|
||||
int network_type, /* Network type (SLiRP or PCap) */
|
||||
network_card; /* Network card */
|
||||
char network_host[520]; /* PCap device */
|
||||
|
||||
/* Ports category */
|
||||
char parallel_devices[3][32]; /* LPT device names */
|
||||
#ifdef USE_SERIAL_DEVICES
|
||||
char serial_devices[2][32]; /* Serial device names */
|
||||
#endif
|
||||
int serial_enabled[2], /* Serial ports 1 and 2 enabled */
|
||||
parallel_enabled[3]; /* LPT1, LPT2, LPT3 enabled */
|
||||
|
||||
/* Other peripherals category */
|
||||
int hdc, /* Hard disk controller */
|
||||
scsi_card, /* SCSI controller */
|
||||
ide_ter_enabled, /* Tertiary IDE controller enabled */
|
||||
ide_qua_enabled, /* Quaternary IDE controller enabled */
|
||||
bugger_enabled, /* ISA bugger device enabled */
|
||||
isa_rtc_type, /* ISA RTC card */
|
||||
isa_mem_type[ISAMEM_MAX]; /* ISA memory boards */
|
||||
|
||||
/* Hard disks category */
|
||||
storage_cfg_t hdd[HDD_NUM]; /* Hard disk drives */
|
||||
|
||||
/* Floppy drives category */
|
||||
storage_cfg_t fdd[FDD_NUM]; /* Floppy drives */
|
||||
|
||||
/* Other removable devices category */
|
||||
storage_cfg_t cdrom[CDROM_NUM], /* CD-ROM drives */
|
||||
storage_cfg_t rdisk[ZIP_NUM]; /* Removable disk drives */
|
||||
} config_t;
|
||||
#endif
|
||||
|
||||
extern void config_load(void);
|
||||
extern void config_save(void);
|
||||
extern void config_write(wchar_t *fn);
|
||||
|
||||
128
src/cpu/386.c
128
src/cpu/386.c
@@ -11,13 +11,13 @@
|
||||
#define HAVE_STDARG_H
|
||||
#include "../86box.h"
|
||||
#include "cpu.h"
|
||||
#include "../timer.h"
|
||||
#include "x86.h"
|
||||
#include "x87.h"
|
||||
#include "../nmi.h"
|
||||
#include "../mem.h"
|
||||
#include "../pic.h"
|
||||
#include "../pit.h"
|
||||
#include "../timer.h"
|
||||
#include "../floppy/fdd.h"
|
||||
#include "../floppy/fdc.h"
|
||||
#include "386_common.h"
|
||||
@@ -27,53 +27,30 @@
|
||||
|
||||
extern int codegen_flags_changed;
|
||||
|
||||
extern int nmi_enable;
|
||||
int cpl_override = 0, fpucount = 0;
|
||||
int tempc, oldcpl, optype, inttype, oddeven = 0;
|
||||
int stack32, timetolive;
|
||||
|
||||
int inscounts[256];
|
||||
uint32_t oldpc2;
|
||||
uint16_t oldcs;
|
||||
|
||||
int trap;
|
||||
|
||||
uint16_t flags,eflags;
|
||||
uint32_t oldds,oldss,olddslimit,oldsslimit,olddslimitw,oldsslimitw;
|
||||
uint32_t use32;
|
||||
uint32_t oldds, oldss, olddslimit, oldsslimit,
|
||||
olddslimitw, oldsslimitw;
|
||||
uint32_t *eal_r, *eal_w;
|
||||
uint32_t oxpc, cr2, cr3, cr4;
|
||||
uint32_t dr[8];
|
||||
uint32_t rmdat32;
|
||||
uint32_t backupregs[16];
|
||||
|
||||
x86seg gdt,ldt,idt,tr;
|
||||
x86seg _cs,_ds,_es,_ss,_fs,_gs;
|
||||
x86seg _oldds;
|
||||
|
||||
|
||||
|
||||
extern int cpl_override;
|
||||
|
||||
extern int fpucount;
|
||||
uint16_t rds;
|
||||
uint16_t ea_rseg;
|
||||
|
||||
int cgate32;
|
||||
|
||||
uint32_t cr2, cr3, cr4;
|
||||
uint32_t dr[8];
|
||||
|
||||
uint32_t rmdat32;
|
||||
#define rmdat rmdat32
|
||||
#define fetchdat rmdat32
|
||||
uint32_t backupregs[16];
|
||||
extern int oddeven;
|
||||
int inttype;
|
||||
|
||||
|
||||
uint32_t oldcs2;
|
||||
uint32_t oldecx;
|
||||
|
||||
uint32_t *eal_r, *eal_w;
|
||||
|
||||
uint16_t *mod1add[2][8];
|
||||
uint32_t *mod1seg[8];
|
||||
|
||||
uint32_t rmdat;
|
||||
|
||||
#define fetch_ea_16(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_16_long(rmdat); if (cpu_state.abrt) return 0; }
|
||||
#define fetch_ea_32(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_32_long(rmdat); } if (cpu_state.abrt) return 0
|
||||
|
||||
|
||||
#include "x86_flags.h"
|
||||
|
||||
#define getbytef() ((uint8_t)(fetchdat)); cpu_state.pc++
|
||||
@@ -88,7 +65,7 @@ uint32_t testr[9];
|
||||
extern int dontprint;
|
||||
|
||||
#undef NOTRM
|
||||
#define NOTRM if (!(msw & 1) || (eflags & VM_FLAG))\
|
||||
#define NOTRM if (!(msw & 1) || (cpu_state.eflags & VM_FLAG))\
|
||||
{ \
|
||||
x86_int(6); \
|
||||
return 0; \
|
||||
@@ -102,7 +79,7 @@ extern int dontprint;
|
||||
#include "x86_ops.h"
|
||||
|
||||
#undef NOTRM
|
||||
#define NOTRM if (!(msw & 1) || (eflags & VM_FLAG))\
|
||||
#define NOTRM if (!(msw & 1) || (cpu_state.eflags & VM_FLAG))\
|
||||
{ \
|
||||
x86_int(6); \
|
||||
break; \
|
||||
@@ -111,13 +88,11 @@ extern int dontprint;
|
||||
|
||||
#ifdef ENABLE_386_LOG
|
||||
int x386_do_log = ENABLE_386_LOG;
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
x386_log(const char *fmt, ...)
|
||||
{
|
||||
#ifdef ENABLE_386_LOG
|
||||
va_list ap;
|
||||
|
||||
if (x386_do_log) {
|
||||
@@ -125,60 +100,54 @@ x386_log(const char *fmt, ...)
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
#define x386_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
|
||||
void exec386(int cycs)
|
||||
{
|
||||
uint8_t temp;
|
||||
int vector, tempi, cycdiff, oldcyc;
|
||||
int ins_cycles;
|
||||
uint32_t addr;
|
||||
int tempi;
|
||||
int cycdiff;
|
||||
int oldcyc;
|
||||
|
||||
cycles+=cycs;
|
||||
/* output=3; */
|
||||
while (cycles>0)
|
||||
{
|
||||
int cycle_period = (timer_count >> TIMER_SHIFT) + 1;
|
||||
int cycle_period = (timer_target - (uint32_t)tsc) + 1;
|
||||
|
||||
x86_was_reset = 0;
|
||||
cycdiff=0;
|
||||
oldcyc=cycles;
|
||||
timer_start_period(cycles << TIMER_SHIFT);
|
||||
while (cycdiff < cycle_period)
|
||||
{
|
||||
/* testr[0]=EAX; testr[1]=EBX; testr[2]=ECX; testr[3]=EDX;
|
||||
testr[4]=ESI; testr[5]=EDI; testr[6]=EBP; testr[7]=ESP;*/
|
||||
/* testr[8]=flags;*/
|
||||
/* oldcs2=oldcs; */
|
||||
/* oldpc2=oldpc; */
|
||||
ins_cycles = cycles;
|
||||
|
||||
oldcs=CS;
|
||||
cpu_state.oldpc = cpu_state.pc;
|
||||
oldcpl=CPL;
|
||||
oldcpl=CPL;
|
||||
cpu_state.op32 = use32;
|
||||
|
||||
x86_was_reset = 0;
|
||||
|
||||
dontprint=0;
|
||||
|
||||
cpu_state.ea_seg = &_ds;
|
||||
cpu_state.ea_seg = &cpu_state.seg_ds;
|
||||
cpu_state.ssegs = 0;
|
||||
|
||||
fetchdat = fastreadl(cs + cpu_state.pc);
|
||||
|
||||
if (!cpu_state.abrt)
|
||||
{
|
||||
trap = flags & T_FLAG;
|
||||
{
|
||||
opcode = fetchdat & 0xFF;
|
||||
fetchdat >>= 8;
|
||||
fetchdat >>= 8;
|
||||
trap = cpu_state.flags & T_FLAG;
|
||||
|
||||
cpu_state.pc++;
|
||||
x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat);
|
||||
if (x86_was_reset)
|
||||
break;
|
||||
if(x86_was_reset) break;
|
||||
if(x86_was_reset)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!use32) cpu_state.pc &= 0xffff;
|
||||
@@ -205,6 +174,10 @@ dontprint=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ins_cycles -= cycles;
|
||||
tsc += ins_cycles;
|
||||
|
||||
cycdiff=oldcyc-cycles;
|
||||
|
||||
if (trap)
|
||||
@@ -218,13 +191,13 @@ dontprint=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
writememw(ss,(SP-2)&0xFFFF,flags);
|
||||
writememw(ss,(SP-2)&0xFFFF,cpu_state.flags);
|
||||
writememw(ss,(SP-4)&0xFFFF,CS);
|
||||
writememw(ss,(SP-6)&0xFFFF,cpu_state.pc);
|
||||
SP-=6;
|
||||
addr = (1 << 2) + idt.base;
|
||||
flags&=~I_FLAG;
|
||||
flags&=~T_FLAG;
|
||||
cpu_state.flags&=~I_FLAG;
|
||||
cpu_state.flags&=~T_FLAG;
|
||||
cpu_state.pc=readmemw(0,addr);
|
||||
loadcs(readmemw(0,addr+2));
|
||||
}
|
||||
@@ -241,26 +214,26 @@ dontprint=0;
|
||||
nmi = 0;
|
||||
}
|
||||
}
|
||||
else if ((flags&I_FLAG) && pic_intpending)
|
||||
else if ((cpu_state.flags & I_FLAG) && pic_intpending)
|
||||
{
|
||||
temp=picinterrupt();
|
||||
if (temp!=0xFF)
|
||||
vector = picinterrupt();
|
||||
if (vector != -1)
|
||||
{
|
||||
flags_rebuild();
|
||||
if (msw&1)
|
||||
{
|
||||
pmodeint(temp,0);
|
||||
pmodeint(vector,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
writememw(ss,(SP-2)&0xFFFF,flags);
|
||||
writememw(ss,(SP-2)&0xFFFF,cpu_state.flags);
|
||||
writememw(ss,(SP-4)&0xFFFF,CS);
|
||||
writememw(ss,(SP-6)&0xFFFF,cpu_state.pc);
|
||||
SP-=6;
|
||||
addr = (temp << 2) + idt.base;
|
||||
flags&=~I_FLAG;
|
||||
flags&=~T_FLAG;
|
||||
oxpc=cpu_state.pc;
|
||||
addr = (vector << 2) + idt.base;
|
||||
cpu_state.flags&=~I_FLAG;
|
||||
cpu_state.flags&=~T_FLAG;
|
||||
oxpc = cpu_state.pc;
|
||||
cpu_state.pc=readmemw(0,addr);
|
||||
loadcs(readmemw(0,addr+2));
|
||||
}
|
||||
@@ -277,8 +250,7 @@ dontprint=0;
|
||||
}
|
||||
}
|
||||
|
||||
tsc += cycdiff;
|
||||
|
||||
timer_end_period(cycles << TIMER_SHIFT);
|
||||
if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc))
|
||||
timer_process();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
/* Copyright holders: Sarah Walker
|
||||
see COPYING for more details
|
||||
*/
|
||||
extern void cpu_386_flags_extract();
|
||||
extern void cpu_386_flags_rebuild();
|
||||
@@ -8,16 +8,14 @@
|
||||
*
|
||||
* Common 386 CPU code.
|
||||
*
|
||||
* Version: @(#)386_common.h 1.0.0 2017/05/30
|
||||
* Version: @(#)386_common.h 1.0.1 2019/02/19
|
||||
*
|
||||
* Author: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* Copyright 2008-2017 Sarah Walker.
|
||||
* Copyright 2016-2017 Miran Grca.
|
||||
* Copyright 2008-2019 Sarah Walker.
|
||||
* Copyright 2016-2019 Miran Grca.
|
||||
*/
|
||||
|
||||
extern uint16_t ea_rseg;
|
||||
|
||||
#undef readmemb
|
||||
#undef writememb
|
||||
|
||||
@@ -32,7 +30,7 @@ extern uint16_t ea_rseg;
|
||||
#define writememq(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 7)) writememql(s,a,v); else *(uint64_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v
|
||||
|
||||
|
||||
#define check_io_perm(port) if (msw&1 && ((CPL > IOPL) || (eflags&VM_FLAG))) \
|
||||
#define check_io_perm(port) if (msw&1 && ((CPL > IOPL) || (cpu_state.eflags&VM_FLAG))) \
|
||||
{ \
|
||||
int tempi = checkio(port); \
|
||||
if (cpu_state.abrt) return 1; \
|
||||
@@ -43,46 +41,91 @@ extern uint16_t ea_rseg;
|
||||
} \
|
||||
}
|
||||
|
||||
#define checkio_perm(port) if (msw&1 && ((CPL > IOPL) || (eflags&VM_FLAG))) \
|
||||
{ \
|
||||
tempi = checkio(port); \
|
||||
if (cpu_state.abrt) break; \
|
||||
if (tempi) \
|
||||
{ \
|
||||
x86gpf("checkio_perm(): no permission",0); \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
#define SEG_CHECK_READ(seg) \
|
||||
do \
|
||||
{ \
|
||||
if ((seg)->base == 0xffffffff) \
|
||||
{ \
|
||||
x86gpf("Segment can't read", 0);\
|
||||
return 1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SEG_CHECK_WRITE(seg) \
|
||||
do \
|
||||
{ \
|
||||
if ((seg)->base == 0xffffffff) \
|
||||
{ \
|
||||
x86gpf("Segment can't write", 0);\
|
||||
return 1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_READ(chseg, low, high) \
|
||||
if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || ((msw & 1) && !(eflags & VM_FLAG) && (((chseg)->access & 10) == 8))) \
|
||||
if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || ((msw & 1) && !(cpu_state.eflags & VM_FLAG) && (((chseg)->access & 10) == 8))) \
|
||||
{ \
|
||||
x86gpf("Limit check (READ)", 0); \
|
||||
return 1; \
|
||||
} \
|
||||
if (msw&1 && !(eflags&VM_FLAG) && !((chseg)->access & 0x80)) \
|
||||
if (msw&1 && !(cpu_state.eflags&VM_FLAG) && !((chseg)->access & 0x80)) \
|
||||
{ \
|
||||
if ((chseg) == &_ss) \
|
||||
if ((chseg) == &cpu_state.seg_ss) \
|
||||
x86ss(NULL,(chseg)->seg & 0xfffc); \
|
||||
else \
|
||||
x86np("Read from seg not present", (chseg)->seg & 0xfffc); \
|
||||
return 1; \
|
||||
}
|
||||
} \
|
||||
if (cr0 >> 31) { \
|
||||
(void) mmutranslatereal((chseg)->base + low, 0); \
|
||||
(void) mmutranslatereal((chseg)->base + high, 0); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
}
|
||||
|
||||
#define CHECK_WRITE(chseg, low, high) \
|
||||
if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || !((chseg)->access & 2) || ((msw & 1) && !(eflags & VM_FLAG) && ((chseg)->access & 8))) \
|
||||
#define CHECK_READ_REP(chseg, low, high) \
|
||||
if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high)) \
|
||||
{ \
|
||||
x86gpf("Limit check (READ)", 0); \
|
||||
break; \
|
||||
} \
|
||||
if (msw&1 && !(cpu_state.eflags&VM_FLAG) && !((chseg)->access & 0x80)) \
|
||||
{ \
|
||||
if ((chseg) == &cpu_state.seg_ss) \
|
||||
x86ss(NULL,(chseg)->seg & 0xfffc); \
|
||||
else \
|
||||
x86np("Read from seg not present", (chseg)->seg & 0xfffc); \
|
||||
break; \
|
||||
} \
|
||||
if (cr0 >> 31) { \
|
||||
(void) mmutranslatereal((chseg)->base + low, 0); \
|
||||
(void) mmutranslatereal((chseg)->base + high, 0); \
|
||||
if (cpu_state.abrt) \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define CHECK_WRITE_COMMON(chseg, low, high) \
|
||||
if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || !((chseg)->access & 2) || ((msw & 1) && !(cpu_state.eflags & VM_FLAG) && ((chseg)->access & 8))) \
|
||||
{ \
|
||||
x86gpf("Limit check (WRITE)", 0); \
|
||||
return 1; \
|
||||
} \
|
||||
if (msw&1 && !(eflags&VM_FLAG) && !((chseg)->access & 0x80)) \
|
||||
if (msw&1 && !(cpu_state.eflags&VM_FLAG) && !((chseg)->access & 0x80)) \
|
||||
{ \
|
||||
if ((chseg) == &_ss) \
|
||||
if ((chseg) == &cpu_state.seg_ss) \
|
||||
x86ss(NULL,(chseg)->seg & 0xfffc); \
|
||||
else \
|
||||
x86np("Write to seg not present", (chseg)->seg & 0xfffc); \
|
||||
return 1; \
|
||||
}
|
||||
}
|
||||
|
||||
#define CHECK_WRITE(chseg, low, high) \
|
||||
CHECK_WRITE_COMMON(chseg, low, high) \
|
||||
if (cr0 >> 31) { \
|
||||
(void) mmutranslatereal((chseg)->base + low, 1); \
|
||||
(void) mmutranslatereal((chseg)->base + high, 1); \
|
||||
if (cpu_state.abrt) \
|
||||
return 1; \
|
||||
}
|
||||
|
||||
#define CHECK_WRITE_REP(chseg, low, high) \
|
||||
if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high)) \
|
||||
@@ -90,17 +133,23 @@ extern uint16_t ea_rseg;
|
||||
x86gpf("Limit check (WRITE REP)", 0); \
|
||||
break; \
|
||||
} \
|
||||
if (msw&1 && !(eflags&VM_FLAG) && !((chseg)->access & 0x80)) \
|
||||
if (msw&1 && !(cpu_state.eflags&VM_FLAG) && !((chseg)->access & 0x80)) \
|
||||
{ \
|
||||
if ((chseg) == &_ss) \
|
||||
if ((chseg) == &cpu_state.seg_ss) \
|
||||
x86ss(NULL,(chseg)->seg & 0xfffc); \
|
||||
else \
|
||||
x86np("Write (REP) to seg not present", (chseg)->seg & 0xfffc); \
|
||||
break; \
|
||||
}
|
||||
} \
|
||||
if (cr0 >> 31) { \
|
||||
(void) mmutranslatereal((chseg)->base + low, 1); \
|
||||
(void) mmutranslatereal((chseg)->base + high, 1); \
|
||||
if (cpu_state.abrt) \
|
||||
break; \
|
||||
}
|
||||
|
||||
|
||||
#define NOTRM if (!(msw & 1) || (eflags & VM_FLAG))\
|
||||
#define NOTRM if (!(msw & 1) || (cpu_state.eflags & VM_FLAG))\
|
||||
{ \
|
||||
x86_int(6); \
|
||||
return 1; \
|
||||
@@ -165,6 +214,17 @@ static __inline uint32_t fastreadl(uint32_t a)
|
||||
return val;
|
||||
}
|
||||
|
||||
static __inline void *get_ram_ptr(uint32_t a)
|
||||
{
|
||||
if ((a >> 12) == pccache)
|
||||
return &pccache2[a];
|
||||
else
|
||||
{
|
||||
uint8_t *t = getpccache(a);
|
||||
return &t[a];
|
||||
}
|
||||
}
|
||||
|
||||
static __inline uint8_t getbyte()
|
||||
{
|
||||
cpu_state.pc++;
|
||||
@@ -204,7 +264,6 @@ static __inline uint16_t geteaw()
|
||||
{
|
||||
if (cpu_mod == 3)
|
||||
return cpu_state.regs[cpu_rm].w;
|
||||
/* cycles-=3; */
|
||||
if (eal_r)
|
||||
return *(uint16_t *)eal_r;
|
||||
return readmemw(easeg, cpu_state.eaaddr);
|
||||
@@ -214,7 +273,6 @@ static __inline uint32_t geteal()
|
||||
{
|
||||
if (cpu_mod == 3)
|
||||
return cpu_state.regs[cpu_rm].l;
|
||||
/* cycles-=3; */
|
||||
if (eal_r)
|
||||
return *eal_r;
|
||||
return readmeml(easeg, cpu_state.eaaddr);
|
||||
@@ -241,15 +299,24 @@ static __inline uint32_t geteal_mem()
|
||||
return readmeml(easeg,cpu_state.eaaddr);
|
||||
}
|
||||
|
||||
static __inline int seteaq_cwc(void)
|
||||
{
|
||||
CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __inline void seteaq(uint64_t v)
|
||||
{
|
||||
if (seteaq_cwc())
|
||||
return;
|
||||
writememql(easeg, cpu_state.eaaddr, v);
|
||||
}
|
||||
|
||||
#define seteab(v) if (cpu_mod!=3) { if (eal_w) *(uint8_t *)eal_w=v; else writememb386l(easeg,cpu_state.eaaddr,v); } else if (cpu_rm&4) cpu_state.regs[cpu_rm&3].b.h=v; else cpu_state.regs[cpu_rm].b.l=v
|
||||
#define seteaw(v) if (cpu_mod!=3) { if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg,cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].w=v
|
||||
#define seteal(v) if (cpu_mod!=3) { if (eal_w) *eal_w=v; else writememll(easeg,cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].l=v
|
||||
|
||||
#define seteab(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); if (eal_w) *(uint8_t *)eal_w=v; else { writememb386l(easeg,cpu_state.eaaddr,v); } } else if (cpu_rm&4) cpu_state.regs[cpu_rm&3].b.h=v; else cpu_state.regs[cpu_rm].b.l=v
|
||||
#define seteaw(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 1); if (eal_w) *(uint16_t *)eal_w=v; else { writememwl(easeg,cpu_state.eaaddr,v); } } else cpu_state.regs[cpu_rm].w=v
|
||||
#define seteal(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); if (eal_w) *eal_w=v; else { writememll(easeg,cpu_state.eaaddr,v); } } else cpu_state.regs[cpu_rm].l=v
|
||||
|
||||
|
||||
#define seteab_mem(v) if (eal_w) *(uint8_t *)eal_w=v; else writememb386l(easeg,cpu_state.eaaddr,v);
|
||||
#define seteaw_mem(v) if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg,cpu_state.eaaddr,v);
|
||||
#define seteal_mem(v) if (eal_w) *eal_w=v; else writememll(easeg,cpu_state.eaaddr,v);
|
||||
@@ -258,9 +325,3 @@ static __inline void seteaq(uint64_t v)
|
||||
#define getwordf() ((uint16_t)(fetchdat)); cpu_state.pc+=2
|
||||
#define getbyte2f() ((uint8_t)(fetchdat>>8)); cpu_state.pc++
|
||||
#define getword2f() ((uint16_t)(fetchdat>>8)); cpu_state.pc+=2
|
||||
|
||||
|
||||
#define rmdat rmdat32
|
||||
#define fetchdat rmdat32
|
||||
|
||||
void x86_int(int num);
|
||||
|
||||
@@ -34,53 +34,18 @@ uint32_t cpu_cur_status = 0;
|
||||
int cpu_reps, cpu_reps_latched;
|
||||
int cpu_notreps, cpu_notreps_latched;
|
||||
|
||||
int inrecomp = 0;
|
||||
int inrecomp = 0, cpu_block_end = 0;
|
||||
int cpu_recomp_blocks, cpu_recomp_full_ins, cpu_new_blocks;
|
||||
int cpu_recomp_blocks_latched, cpu_recomp_ins_latched, cpu_recomp_full_ins_latched, cpu_new_blocks_latched;
|
||||
|
||||
int cpu_block_end = 0;
|
||||
|
||||
int nmi_enable = 1;
|
||||
|
||||
int inscounts[256];
|
||||
uint32_t oldpc2;
|
||||
|
||||
int trap;
|
||||
|
||||
|
||||
|
||||
int cpl_override=0;
|
||||
|
||||
int fpucount=0;
|
||||
uint16_t rds;
|
||||
uint16_t ea_rseg;
|
||||
|
||||
int cgate32;
|
||||
|
||||
uint32_t rmdat32;
|
||||
uint32_t backupregs[16];
|
||||
int oddeven=0;
|
||||
int inttype;
|
||||
|
||||
|
||||
uint32_t oldcs2;
|
||||
uint32_t oldecx;
|
||||
|
||||
uint32_t *eal_r, *eal_w;
|
||||
|
||||
uint16_t *mod1add[2][8];
|
||||
uint32_t *mod1seg[8];
|
||||
|
||||
|
||||
#ifdef ENABLE_386_DYNAREC_LOG
|
||||
int x386_dynarec_do_log = ENABLE_386_DYNAREC_LOG;
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
void
|
||||
x386_dynarec_log(const char *fmt, ...)
|
||||
{
|
||||
#ifdef ENABLE_386_DYNAREC_LOG
|
||||
va_list ap;
|
||||
|
||||
if (x386_dynarec_do_log) {
|
||||
@@ -88,15 +53,16 @@ x386_dynarec_log(const char *fmt, ...)
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
#define x86_dynarec_log (fmt, ...)
|
||||
#endif
|
||||
|
||||
|
||||
static __inline void fetch_ea_32_long(uint32_t rmdat)
|
||||
{
|
||||
eal_r = eal_w = NULL;
|
||||
easeg = cpu_state.ea_seg->base;
|
||||
ea_rseg = cpu_state.ea_seg->seg;
|
||||
if (cpu_rm == 4)
|
||||
{
|
||||
uint8_t sib = rmdat >> 8;
|
||||
@@ -122,8 +88,7 @@ static __inline void fetch_ea_32_long(uint32_t rmdat)
|
||||
else if ((sib & 6) == 4 && !cpu_state.ssegs)
|
||||
{
|
||||
easeg = ss;
|
||||
ea_rseg = SS;
|
||||
cpu_state.ea_seg = &_ss;
|
||||
cpu_state.ea_seg = &cpu_state.seg_ss;
|
||||
}
|
||||
if (((sib >> 3) & 7) != 4)
|
||||
cpu_state.eaaddr += cpu_state.regs[(sib >> 3) & 7].l << (sib >> 6);
|
||||
@@ -136,8 +101,7 @@ static __inline void fetch_ea_32_long(uint32_t rmdat)
|
||||
if (cpu_rm == 5 && !cpu_state.ssegs)
|
||||
{
|
||||
easeg = ss;
|
||||
ea_rseg = SS;
|
||||
cpu_state.ea_seg = &_ss;
|
||||
cpu_state.ea_seg = &cpu_state.seg_ss;
|
||||
}
|
||||
if (cpu_mod == 1)
|
||||
{
|
||||
@@ -169,7 +133,6 @@ static __inline void fetch_ea_16_long(uint32_t rmdat)
|
||||
{
|
||||
eal_r = eal_w = NULL;
|
||||
easeg = cpu_state.ea_seg->base;
|
||||
ea_rseg = cpu_state.ea_seg->seg;
|
||||
if (!cpu_mod && cpu_rm == 6)
|
||||
{
|
||||
cpu_state.eaaddr = getword();
|
||||
@@ -192,8 +155,7 @@ static __inline void fetch_ea_16_long(uint32_t rmdat)
|
||||
if (mod1seg[cpu_rm] == &ss && !cpu_state.ssegs)
|
||||
{
|
||||
easeg = ss;
|
||||
ea_rseg = SS;
|
||||
cpu_state.ea_seg = &_ss;
|
||||
cpu_state.ea_seg = &cpu_state.seg_ss;
|
||||
}
|
||||
cpu_state.eaaddr &= 0xFFFF;
|
||||
}
|
||||
@@ -233,7 +195,9 @@ void x86_int(int num)
|
||||
cpu_state.abrt = 0;
|
||||
softresetx86();
|
||||
cpu_set_edx();
|
||||
#ifdef ENABLE_386_DYNAREC_LOG
|
||||
x386_dynarec_log("Triple fault in real mode - reset\n");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
x86_int(8);
|
||||
@@ -242,22 +206,22 @@ void x86_int(int num)
|
||||
{
|
||||
if (stack32)
|
||||
{
|
||||
writememw(ss,ESP-2,flags);
|
||||
writememw(ss,ESP-2,cpu_state.flags);
|
||||
writememw(ss,ESP-4,CS);
|
||||
writememw(ss,ESP-6,cpu_state.pc);
|
||||
ESP-=6;
|
||||
}
|
||||
else
|
||||
{
|
||||
writememw(ss,((SP-2)&0xFFFF),flags);
|
||||
writememw(ss,((SP-2)&0xFFFF),cpu_state.flags);
|
||||
writememw(ss,((SP-4)&0xFFFF),CS);
|
||||
writememw(ss,((SP-6)&0xFFFF),cpu_state.pc);
|
||||
SP-=6;
|
||||
}
|
||||
|
||||
flags&=~I_FLAG;
|
||||
flags&=~T_FLAG;
|
||||
oxpc=cpu_state.pc;
|
||||
cpu_state.flags&=~I_FLAG;
|
||||
cpu_state.flags&=~T_FLAG;
|
||||
oxpc=cpu_state.pc;
|
||||
cpu_state.pc=readmemw(0,addr);
|
||||
loadcs(readmemw(0,addr+2));
|
||||
}
|
||||
@@ -287,22 +251,22 @@ void x86_int_sw(int num)
|
||||
{
|
||||
if (stack32)
|
||||
{
|
||||
writememw(ss,ESP-2,flags);
|
||||
writememw(ss,ESP-2,cpu_state.flags);
|
||||
writememw(ss,ESP-4,CS);
|
||||
writememw(ss,ESP-6,cpu_state.pc);
|
||||
ESP-=6;
|
||||
}
|
||||
else
|
||||
{
|
||||
writememw(ss,((SP-2)&0xFFFF),flags);
|
||||
writememw(ss,((SP-2)&0xFFFF),cpu_state.flags);
|
||||
writememw(ss,((SP-4)&0xFFFF),CS);
|
||||
writememw(ss,((SP-6)&0xFFFF),cpu_state.pc);
|
||||
SP-=6;
|
||||
}
|
||||
|
||||
flags&=~I_FLAG;
|
||||
flags&=~T_FLAG;
|
||||
oxpc=cpu_state.pc;
|
||||
cpu_state.flags&=~I_FLAG;
|
||||
cpu_state.flags&=~T_FLAG;
|
||||
oxpc=cpu_state.pc;
|
||||
cpu_state.pc=readmemw(0,addr);
|
||||
loadcs(readmemw(0,addr+2));
|
||||
cycles -= timing_int_rm;
|
||||
@@ -326,16 +290,28 @@ int x86_int_sw_rm(int num)
|
||||
|
||||
if (cpu_state.abrt) return 1;
|
||||
|
||||
writememw(ss,((SP-2)&0xFFFF),flags); if (cpu_state.abrt) {x386_dynarec_log("abrt5\n"); return 1; }
|
||||
writememw(ss,((SP-2)&0xFFFF),cpu_state.flags);
|
||||
if (cpu_state.abrt) {
|
||||
#ifdef ENABLE_386_DYNAREC_LOG
|
||||
x386_dynarec_log("abrt5\n");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
writememw(ss,((SP-4)&0xFFFF),CS);
|
||||
writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); if (cpu_state.abrt) {x386_dynarec_log("abrt6\n"); return 1; }
|
||||
writememw(ss,((SP-6)&0xFFFF),cpu_state.pc);
|
||||
if (cpu_state.abrt) {
|
||||
#ifdef ENABLE_386_DYNAREC_LOG
|
||||
x386_dynarec_log("abrt6\n");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
SP-=6;
|
||||
|
||||
eflags &= ~VIF_FLAG;
|
||||
flags &= ~T_FLAG;
|
||||
cpu_state.eflags &= ~VIF_FLAG;
|
||||
cpu_state.flags &= ~T_FLAG;
|
||||
cpu_state.pc = new_pc;
|
||||
loadcs(new_cs);
|
||||
oxpc=cpu_state.pc;
|
||||
oxpc=cpu_state.pc;
|
||||
|
||||
cycles -= timing_int_rm;
|
||||
trap = 0;
|
||||
@@ -419,6 +395,8 @@ static void prefetch_run(int instr_cycles, int bytes, int modrm, int reads, int
|
||||
}
|
||||
|
||||
prefetch_prefixes = 0;
|
||||
if (prefetch_bytes > 16)
|
||||
prefetch_bytes = 16;
|
||||
}
|
||||
|
||||
static void prefetch_flush()
|
||||
@@ -521,6 +499,216 @@ int oldi;
|
||||
uint32_t testr[9];
|
||||
int dontprint=0;
|
||||
|
||||
void enter_smm()
|
||||
{
|
||||
uint32_t smram_state = smbase + 0xfe00;
|
||||
uint32_t old_cr0 = cr0;
|
||||
uint32_t old_flags = cpu_state.flags | ((uint32_t)cpu_state.eflags << 16);
|
||||
|
||||
cr0 &= ~0x8000000d;
|
||||
cpu_state.flags = 2;
|
||||
cpu_state.eflags = 0;
|
||||
|
||||
in_smm = 1;
|
||||
smi_latched = 1;
|
||||
|
||||
mem_writel_phys(smram_state + 0xf8, smbase);
|
||||
mem_writel_phys(smram_state + 0x128, cr4);
|
||||
mem_writel_phys(smram_state + 0x130, cpu_state.seg_es.limit);
|
||||
mem_writel_phys(smram_state + 0x134, cpu_state.seg_es.base);
|
||||
mem_writel_phys(smram_state + 0x138, cpu_state.seg_es.access);
|
||||
mem_writel_phys(smram_state + 0x13c, cpu_state.seg_cs.limit);
|
||||
mem_writel_phys(smram_state + 0x140, cpu_state.seg_cs.base);
|
||||
mem_writel_phys(smram_state + 0x144, cpu_state.seg_cs.access);
|
||||
mem_writel_phys(smram_state + 0x148, cpu_state.seg_ss.limit);
|
||||
mem_writel_phys(smram_state + 0x14c, cpu_state.seg_ss.base);
|
||||
mem_writel_phys(smram_state + 0x150, cpu_state.seg_ss.access);
|
||||
mem_writel_phys(smram_state + 0x154, cpu_state.seg_ds.limit);
|
||||
mem_writel_phys(smram_state + 0x158, cpu_state.seg_ds.base);
|
||||
mem_writel_phys(smram_state + 0x15c, cpu_state.seg_ds.access);
|
||||
mem_writel_phys(smram_state + 0x160, cpu_state.seg_fs.limit);
|
||||
mem_writel_phys(smram_state + 0x164, cpu_state.seg_fs.base);
|
||||
mem_writel_phys(smram_state + 0x168, cpu_state.seg_fs.access);
|
||||
mem_writel_phys(smram_state + 0x16c, cpu_state.seg_gs.limit);
|
||||
mem_writel_phys(smram_state + 0x170, cpu_state.seg_gs.base);
|
||||
mem_writel_phys(smram_state + 0x174, cpu_state.seg_gs.access);
|
||||
mem_writel_phys(smram_state + 0x178, ldt.limit);
|
||||
mem_writel_phys(smram_state + 0x17c, ldt.base);
|
||||
mem_writel_phys(smram_state + 0x180, ldt.access);
|
||||
mem_writel_phys(smram_state + 0x184, gdt.limit);
|
||||
mem_writel_phys(smram_state + 0x188, gdt.base);
|
||||
mem_writel_phys(smram_state + 0x18c, gdt.access);
|
||||
mem_writel_phys(smram_state + 0x190, idt.limit);
|
||||
mem_writel_phys(smram_state + 0x194, idt.base);
|
||||
mem_writel_phys(smram_state + 0x198, idt.access);
|
||||
mem_writel_phys(smram_state + 0x19c, tr.limit);
|
||||
mem_writel_phys(smram_state + 0x1a0, tr.base);
|
||||
mem_writel_phys(smram_state + 0x1a4, tr.access);
|
||||
|
||||
mem_writel_phys(smram_state + 0x1a8, cpu_state.seg_es.seg);
|
||||
mem_writel_phys(smram_state + 0x1ac, cpu_state.seg_cs.seg);
|
||||
mem_writel_phys(smram_state + 0x1b0, cpu_state.seg_ss.seg);
|
||||
mem_writel_phys(smram_state + 0x1b4, cpu_state.seg_ds.seg);
|
||||
mem_writel_phys(smram_state + 0x1b8, cpu_state.seg_fs.seg);
|
||||
mem_writel_phys(smram_state + 0x1bc, cpu_state.seg_gs.seg);
|
||||
mem_writel_phys(smram_state + 0x1c0, ldt.seg);
|
||||
mem_writel_phys(smram_state + 0x1c4, tr.seg);
|
||||
|
||||
mem_writel_phys(smram_state + 0x1c8, dr[7]);
|
||||
mem_writel_phys(smram_state + 0x1cc, dr[6]);
|
||||
mem_writel_phys(smram_state + 0x1d0, EAX);
|
||||
mem_writel_phys(smram_state + 0x1d4, ECX);
|
||||
mem_writel_phys(smram_state + 0x1d8, EDX);
|
||||
mem_writel_phys(smram_state + 0x1dc, EBX);
|
||||
mem_writel_phys(smram_state + 0x1e0, ESP);
|
||||
mem_writel_phys(smram_state + 0x1e4, EBP);
|
||||
mem_writel_phys(smram_state + 0x1e8, ESI);
|
||||
mem_writel_phys(smram_state + 0x1ec, EDI);
|
||||
mem_writel_phys(smram_state + 0x1f0, cpu_state.pc);
|
||||
mem_writel_phys(smram_state + 0x1d0, old_flags);
|
||||
mem_writel_phys(smram_state + 0x1f8, cr3);
|
||||
mem_writel_phys(smram_state + 0x1fc, old_cr0);
|
||||
|
||||
ds = es = fs_seg = gs = ss = 0;
|
||||
|
||||
DS = ES = FS = GS = SS = 0;
|
||||
|
||||
cpu_state.seg_ds.limit = cpu_state.seg_es.limit = cpu_state.seg_fs.limit = cpu_state.seg_gs.limit
|
||||
= cpu_state.seg_ss.limit = 0xffffffff;
|
||||
|
||||
cpu_state.seg_ds.limit_high = cpu_state.seg_es.limit_high = cpu_state.seg_fs.limit_high
|
||||
= cpu_state.seg_gs.limit_high = cpu_state.seg_ss.limit_high = 0xffffffff;
|
||||
|
||||
cpu_state.seg_ds.limit_low = cpu_state.seg_es.limit_low = cpu_state.seg_fs.limit_low
|
||||
= cpu_state.seg_gs.limit_low = cpu_state.seg_ss.limit_low = 0;
|
||||
|
||||
cpu_state.seg_ds.access = cpu_state.seg_es.access = cpu_state.seg_fs.access
|
||||
= cpu_state.seg_gs.access = cpu_state.seg_ss.access = 0x93;
|
||||
|
||||
cpu_state.seg_ds.checked = cpu_state.seg_es.checked = cpu_state.seg_fs.checked
|
||||
= cpu_state.seg_gs.checked = cpu_state.seg_ss.checked = 1;
|
||||
|
||||
CS = 0x3000;
|
||||
cs = smbase;
|
||||
cpu_state.seg_cs.limit = cpu_state.seg_cs.limit_high = 0xffffffff;
|
||||
cpu_state.seg_cs.limit_low = 0;
|
||||
cpu_state.seg_cs.access = 0x93;
|
||||
cpu_state.seg_cs.checked = 1;
|
||||
|
||||
cr4 = 0;
|
||||
dr[7] = 0x400;
|
||||
cpu_state.pc = 0x8000;
|
||||
|
||||
nmi_mask = 0;
|
||||
}
|
||||
|
||||
void leave_smm()
|
||||
{
|
||||
uint32_t smram_state = smbase + 0xfe00;
|
||||
|
||||
smbase = mem_readl_phys(smram_state + 0xf8);
|
||||
cr4 = mem_readl_phys(smram_state + 0x128);
|
||||
|
||||
cpu_state.seg_es.limit = cpu_state.seg_es.limit_high = mem_readl_phys(smram_state + 0x130);
|
||||
cpu_state.seg_es.base = mem_readl_phys(smram_state + 0x134);
|
||||
cpu_state.seg_es.limit_low = cpu_state.seg_es.base;
|
||||
cpu_state.seg_es.access = mem_readl_phys(smram_state + 0x138);
|
||||
|
||||
cpu_state.seg_cs.limit = cpu_state.seg_cs.limit_high = mem_readl_phys(smram_state + 0x13c);
|
||||
cpu_state.seg_cs.base = mem_readl_phys(smram_state + 0x140);
|
||||
cpu_state.seg_cs.limit_low = cpu_state.seg_cs.base;
|
||||
cpu_state.seg_cs.access = mem_readl_phys(smram_state + 0x144);
|
||||
|
||||
cpu_state.seg_ss.limit = cpu_state.seg_ss.limit_high = mem_readl_phys(smram_state + 0x148);
|
||||
cpu_state.seg_ss.base = mem_readl_phys(smram_state + 0x14c);
|
||||
cpu_state.seg_ss.limit_low = cpu_state.seg_ss.base;
|
||||
cpu_state.seg_ss.access = mem_readl_phys(smram_state + 0x150);
|
||||
|
||||
cpu_state.seg_ds.limit = cpu_state.seg_ds.limit_high = mem_readl_phys(smram_state + 0x154);
|
||||
cpu_state.seg_ds.base = mem_readl_phys(smram_state + 0x158);
|
||||
cpu_state.seg_ds.limit_low = cpu_state.seg_ds.base;
|
||||
cpu_state.seg_ds.access = mem_readl_phys(smram_state + 0x15c);
|
||||
|
||||
cpu_state.seg_fs.limit = cpu_state.seg_fs.limit_high = mem_readl_phys(smram_state + 0x160);
|
||||
cpu_state.seg_fs.base = mem_readl_phys(smram_state + 0x164);
|
||||
cpu_state.seg_fs.limit_low = cpu_state.seg_fs.base;
|
||||
cpu_state.seg_fs.access = mem_readl_phys(smram_state + 0x168);
|
||||
|
||||
cpu_state.seg_gs.limit = cpu_state.seg_gs.limit_high = mem_readl_phys(smram_state + 0x16c);
|
||||
cpu_state.seg_gs.base = mem_readl_phys(smram_state + 0x170);
|
||||
cpu_state.seg_gs.limit_low = cpu_state.seg_gs.base;
|
||||
cpu_state.seg_gs.access = mem_readl_phys(smram_state + 0x174);
|
||||
|
||||
ldt.limit = ldt.limit_high = mem_readl_phys(smram_state + 0x178);
|
||||
ldt.base = mem_readl_phys(smram_state + 0x17c);
|
||||
ldt.limit_low = ldt.base;
|
||||
ldt.access = mem_readl_phys(smram_state + 0x180);
|
||||
|
||||
gdt.limit = gdt.limit_high = mem_readl_phys(smram_state + 0x184);
|
||||
gdt.base = mem_readl_phys(smram_state + 0x188);
|
||||
gdt.limit_low = gdt.base;
|
||||
gdt.access = mem_readl_phys(smram_state + 0x18c);
|
||||
|
||||
idt.limit = idt.limit_high = mem_readl_phys(smram_state + 0x190);
|
||||
idt.base = mem_readl_phys(smram_state + 0x194);
|
||||
idt.limit_low = idt.base;
|
||||
idt.access = mem_readl_phys(smram_state + 0x198);
|
||||
|
||||
tr.limit = tr.limit_high = mem_readl_phys(smram_state + 0x19c);
|
||||
tr.base = mem_readl_phys(smram_state + 0x1a0);
|
||||
tr.limit_low = tr.base;
|
||||
tr.access = mem_readl_phys(smram_state + 0x1a4);
|
||||
|
||||
ES = mem_readl_phys(smram_state + 0x1a8);
|
||||
CS = mem_readl_phys(smram_state + 0x1ac);
|
||||
SS = mem_readl_phys(smram_state + 0x1b0);
|
||||
DS = mem_readl_phys(smram_state + 0x1b4);
|
||||
FS = mem_readl_phys(smram_state + 0x1b8);
|
||||
GS = mem_readl_phys(smram_state + 0x1bc);
|
||||
ldt.seg = mem_readl_phys(smram_state + 0x1c0);
|
||||
tr.seg = mem_readl_phys(smram_state + 0x1c4);
|
||||
|
||||
dr[7] = mem_readl_phys(smram_state + 0x1c8);
|
||||
dr[6] = mem_readl_phys(smram_state + 0x1cc);
|
||||
EAX = mem_readl_phys(smram_state + 0x1d0);
|
||||
ECX = mem_readl_phys(smram_state + 0x1d4);
|
||||
EDX = mem_readl_phys(smram_state + 0x1d8);
|
||||
EBX = mem_readl_phys(smram_state + 0x1dc);
|
||||
ESP = mem_readl_phys(smram_state + 0x1e0);
|
||||
EBP = mem_readl_phys(smram_state + 0x1e4);
|
||||
ESI = mem_readl_phys(smram_state + 0x1e8);
|
||||
EDI = mem_readl_phys(smram_state + 0x1ec);
|
||||
|
||||
cpu_state.pc = mem_readl_phys(smram_state + 0x1f0);
|
||||
uint32_t new_flags = mem_readl_phys(smram_state + 0x1f4);
|
||||
cpu_state.flags = new_flags & 0xffff;
|
||||
cpu_state.eflags = new_flags >> 16;
|
||||
cr3 = mem_readl_phys(smram_state + 0x1f8);
|
||||
cr0 = mem_readl_phys(smram_state + 0x1fc);
|
||||
|
||||
cpu_state.seg_cs.access &= ~0x60;
|
||||
cpu_state.seg_cs.access |= cpu_state.seg_ss.access & 0x60; //cpl is dpl of ss
|
||||
|
||||
if((cr0 & 1) && !(cpu_state.eflags&VM_FLAG))
|
||||
{
|
||||
cpu_state.seg_cs.checked = CS ? 1 : 0;
|
||||
cpu_state.seg_ds.checked = DS ? 1 : 0;
|
||||
cpu_state.seg_es.checked = ES ? 1 : 0;
|
||||
cpu_state.seg_fs.checked = FS ? 1 : 0;
|
||||
cpu_state.seg_gs.checked = GS ? 1 : 0;
|
||||
cpu_state.seg_ss.checked = SS ? 1 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cpu_state.seg_cs.checked = cpu_state.seg_ds.checked = cpu_state.seg_es.checked
|
||||
= cpu_state.seg_fs.checked = cpu_state.seg_gs.checked = cpu_state.seg_ss.checked = 1;
|
||||
}
|
||||
|
||||
in_smm = 0;
|
||||
|
||||
nmi_mask = 1;
|
||||
}
|
||||
|
||||
#define OP_TABLE(name) ops_ ## name
|
||||
#define CLOCK_CYCLES(c) cycles -= (c)
|
||||
#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c)
|
||||
@@ -528,14 +716,14 @@ int dontprint=0;
|
||||
#include "386_ops.h"
|
||||
|
||||
|
||||
#define CACHE_ON() (!(cr0 & (1 << 30)) /*&& (cr0 & 1)*/ && !(flags & T_FLAG))
|
||||
#define CACHE_ON() (!(cr0 & (1 << 30)) /*&& (cr0 & 1)*/ && !(cpu_state.flags & T_FLAG))
|
||||
|
||||
#ifdef USE_DYNAREC
|
||||
static int cycles_main = 0;
|
||||
|
||||
void exec386_dynarec(int cycs)
|
||||
{
|
||||
uint8_t temp;
|
||||
int vector;
|
||||
uint32_t addr;
|
||||
int tempi;
|
||||
int cycdiff;
|
||||
@@ -552,7 +740,6 @@ void exec386_dynarec(int cycs)
|
||||
cycles += cyc_period;
|
||||
cycles_start = cycles;
|
||||
|
||||
timer_start_period(cycles << TIMER_SHIFT);
|
||||
while (cycles>0)
|
||||
{
|
||||
oldcs = CS;
|
||||
@@ -571,18 +758,18 @@ void exec386_dynarec(int cycs)
|
||||
{
|
||||
oldcs=CS;
|
||||
cpu_state.oldpc = cpu_state.pc;
|
||||
oldcpl=CPL;
|
||||
oldcpl = CPL;
|
||||
cpu_state.op32 = use32;
|
||||
|
||||
cpu_state.ea_seg = &_ds;
|
||||
cpu_state.ea_seg = &cpu_state.seg_ds;
|
||||
cpu_state.ssegs = 0;
|
||||
|
||||
fetchdat = fastreadl(cs + cpu_state.pc);
|
||||
if (!cpu_state.abrt)
|
||||
{
|
||||
trap = flags & T_FLAG;
|
||||
opcode = fetchdat & 0xFF;
|
||||
fetchdat >>= 8;
|
||||
opcode = fetchdat & 0xFF;
|
||||
fetchdat >>= 8;
|
||||
trap = cpu_state.flags & T_FLAG;
|
||||
|
||||
cpu_state.pc++;
|
||||
x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat);
|
||||
@@ -599,6 +786,10 @@ void exec386_dynarec(int cycs)
|
||||
ss=oldss;
|
||||
ssegs=0;
|
||||
}*/
|
||||
|
||||
if (in_smm && smi_line && is_pentium)
|
||||
CPU_BLOCK_END();
|
||||
|
||||
if (cpu_state.abrt)
|
||||
CPU_BLOCK_END();
|
||||
if (trap)
|
||||
@@ -621,7 +812,7 @@ void exec386_dynarec(int cycs)
|
||||
int hash = HASH(phys_addr);
|
||||
codeblock_t *block = codeblock_hash[hash];
|
||||
int valid_block = 0;
|
||||
trap = 0;
|
||||
trap = 0;
|
||||
|
||||
if (block && !cpu_state.abrt)
|
||||
{
|
||||
@@ -718,18 +909,18 @@ inrecomp=0;
|
||||
{
|
||||
oldcs=CS;
|
||||
cpu_state.oldpc = cpu_state.pc;
|
||||
oldcpl=CPL;
|
||||
oldcpl = CPL;
|
||||
cpu_state.op32 = use32;
|
||||
|
||||
cpu_state.ea_seg = &_ds;
|
||||
cpu_state.ea_seg = &cpu_state.seg_ds;
|
||||
cpu_state.ssegs = 0;
|
||||
|
||||
fetchdat = fastreadl(cs + cpu_state.pc);
|
||||
if (!cpu_state.abrt)
|
||||
{
|
||||
trap = flags & T_FLAG;
|
||||
opcode = fetchdat & 0xFF;
|
||||
fetchdat >>= 8;
|
||||
{
|
||||
opcode = fetchdat & 0xFF;
|
||||
fetchdat >>= 8;
|
||||
trap = cpu_state.flags & T_FLAG;
|
||||
|
||||
cpu_state.pc++;
|
||||
|
||||
@@ -749,6 +940,9 @@ inrecomp=0;
|
||||
hit, as host block size is only 2kB*/
|
||||
if ((cpu_state.pc - start_pc) > 1000)
|
||||
CPU_BLOCK_END();
|
||||
|
||||
if (in_smm && smi_line && is_pentium)
|
||||
CPU_BLOCK_END();
|
||||
|
||||
if (trap)
|
||||
CPU_BLOCK_END();
|
||||
@@ -788,20 +982,20 @@ inrecomp=0;
|
||||
{
|
||||
oldcs=CS;
|
||||
cpu_state.oldpc = cpu_state.pc;
|
||||
oldcpl=CPL;
|
||||
oldcpl = CPL;
|
||||
cpu_state.op32 = use32;
|
||||
|
||||
cpu_state.ea_seg = &_ds;
|
||||
cpu_state.ea_seg = &cpu_state.seg_ds;
|
||||
cpu_state.ssegs = 0;
|
||||
|
||||
codegen_endpc = (cs + cpu_state.pc) + 8;
|
||||
fetchdat = fastreadl(cs + cpu_state.pc);
|
||||
|
||||
if (!cpu_state.abrt)
|
||||
{
|
||||
trap = flags & T_FLAG;
|
||||
opcode = fetchdat & 0xFF;
|
||||
fetchdat >>= 8;
|
||||
{
|
||||
opcode = fetchdat & 0xFF;
|
||||
fetchdat >>= 8;
|
||||
trap = cpu_state.flags & T_FLAG;
|
||||
|
||||
cpu_state.pc++;
|
||||
|
||||
@@ -819,7 +1013,10 @@ inrecomp=0;
|
||||
hit, as host block size is only 2kB*/
|
||||
if ((cpu_state.pc - start_pc) > 1000)
|
||||
CPU_BLOCK_END();
|
||||
|
||||
|
||||
if (in_smm && smi_line && is_pentium)
|
||||
CPU_BLOCK_END();
|
||||
|
||||
if (trap)
|
||||
CPU_BLOCK_END();
|
||||
|
||||
@@ -858,21 +1055,29 @@ inrecomp=0;
|
||||
cpu_state.abrt = 0;
|
||||
CS = oldcs;
|
||||
cpu_state.pc = cpu_state.oldpc;
|
||||
#ifdef ENABLE_386_DYNAREC_LOG
|
||||
x386_dynarec_log("Double fault %i\n", ins);
|
||||
#endif
|
||||
pmodeint(8, 0);
|
||||
if (cpu_state.abrt)
|
||||
{
|
||||
cpu_state.abrt = 0;
|
||||
softresetx86();
|
||||
cpu_set_edx();
|
||||
#ifdef ENABLE_386_DYNAREC_LOG
|
||||
x386_dynarec_log("Triple fault - reset\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (in_smm && smi_line && is_pentium)
|
||||
{
|
||||
enter_smm();
|
||||
}
|
||||
|
||||
if (trap)
|
||||
{
|
||||
|
||||
flags_rebuild();
|
||||
if (msw&1)
|
||||
{
|
||||
@@ -880,13 +1085,13 @@ inrecomp=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
writememw(ss,(SP-2)&0xFFFF,flags);
|
||||
writememw(ss,(SP-2)&0xFFFF,cpu_state.flags);
|
||||
writememw(ss,(SP-4)&0xFFFF,CS);
|
||||
writememw(ss,(SP-6)&0xFFFF,cpu_state.pc);
|
||||
SP-=6;
|
||||
addr = (1 << 2) + idt.base;
|
||||
flags&=~I_FLAG;
|
||||
flags&=~T_FLAG;
|
||||
cpu_state.flags&=~I_FLAG;
|
||||
cpu_state.flags&=~T_FLAG;
|
||||
cpu_state.pc=readmemw(0,addr);
|
||||
loadcs(readmemw(0,addr+2));
|
||||
}
|
||||
@@ -903,35 +1108,37 @@ inrecomp=0;
|
||||
nmi = 0;
|
||||
}
|
||||
}
|
||||
else if ((flags&I_FLAG) && pic_intpending)
|
||||
else if ((cpu_state.flags&I_FLAG) && pic_intpending)
|
||||
{
|
||||
temp=picinterrupt();
|
||||
if (temp!=0xFF)
|
||||
vector=picinterrupt();
|
||||
if (vector!=-1)
|
||||
{
|
||||
CPU_BLOCK_END();
|
||||
flags_rebuild();
|
||||
if (msw&1)
|
||||
{
|
||||
pmodeint(temp,0);
|
||||
pmodeint(vector,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
writememw(ss,(SP-2)&0xFFFF,flags);
|
||||
writememw(ss,(SP-2)&0xFFFF,cpu_state.flags);
|
||||
writememw(ss,(SP-4)&0xFFFF,CS);
|
||||
writememw(ss,(SP-6)&0xFFFF,cpu_state.pc);
|
||||
SP-=6;
|
||||
addr=temp<<2;
|
||||
flags&=~I_FLAG;
|
||||
flags&=~T_FLAG;
|
||||
oxpc=cpu_state.pc;
|
||||
addr=vector<<2;
|
||||
cpu_state.flags&=~I_FLAG;
|
||||
cpu_state.flags&=~T_FLAG;
|
||||
oxpc=cpu_state.pc;
|
||||
cpu_state.pc=readmemw(0,addr);
|
||||
loadcs(readmemw(0,addr+2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
timer_end_period(cycles << TIMER_SHIFT);
|
||||
cycles_main -= (cycles_start - cycles);
|
||||
if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc))
|
||||
timer_process();
|
||||
|
||||
cycles_main -= (cycles_start - cycles);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
@@ -23,14 +24,10 @@
|
||||
#include "386_common.h"
|
||||
|
||||
|
||||
extern uint16_t *mod1add[2][8];
|
||||
extern uint32_t *mod1seg[8];
|
||||
|
||||
static __inline void fetch_ea_32_long(uint32_t rmdat)
|
||||
{
|
||||
eal_r = eal_w = NULL;
|
||||
easeg = cpu_state.ea_seg->base;
|
||||
ea_rseg = cpu_state.ea_seg->seg;
|
||||
if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC)
|
||||
{
|
||||
uint32_t addr = easeg + cpu_state.eaaddr;
|
||||
@@ -46,7 +43,6 @@ static __inline void fetch_ea_16_long(uint32_t rmdat)
|
||||
{
|
||||
eal_r = eal_w = NULL;
|
||||
easeg = cpu_state.ea_seg->base;
|
||||
ea_rseg = cpu_state.ea_seg->seg;
|
||||
if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC)
|
||||
{
|
||||
uint32_t addr = easeg + cpu_state.eaaddr;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* 286/386+ instruction handlers list.
|
||||
*
|
||||
* Version: @(#)386_ops.h 1.0.3 2018/05/21
|
||||
* Version: @(#)386_ops.h 1.0.5 2018/10/17
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Sarah Walker, <tommowalker@tommowalker.co.uk>
|
||||
@@ -176,6 +176,14 @@ static int internal_illegal(char *s)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_386_DYNAREC_LOG
|
||||
extern void x386_dynarec_log(const char *fmt, ...);
|
||||
#else
|
||||
#ifndef x386_dynarec_log
|
||||
#define x386_dynarec_log(fmt, ...)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "x86seg.h"
|
||||
#if defined(DEV_BRANCH) && defined(USE_AMD_K)
|
||||
# include "x86_ops_amd.h"
|
||||
@@ -643,7 +651,7 @@ const OpFn OP_TABLE(pentium_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w,
|
||||
/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16,
|
||||
/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL,
|
||||
|
||||
/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -665,7 +673,7 @@ const OpFn OP_TABLE(pentium_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l,
|
||||
/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16,
|
||||
/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16,
|
||||
|
||||
/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -687,7 +695,7 @@ const OpFn OP_TABLE(pentium_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w,
|
||||
/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32,
|
||||
/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL,
|
||||
|
||||
/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -709,7 +717,7 @@ const OpFn OP_TABLE(pentium_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l,
|
||||
/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32,
|
||||
/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32,
|
||||
|
||||
/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -734,7 +742,7 @@ const OpFn OP_TABLE(pentiummmx_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w,
|
||||
/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16,
|
||||
/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL,
|
||||
|
||||
/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -756,7 +764,7 @@ const OpFn OP_TABLE(pentiummmx_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l,
|
||||
/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16,
|
||||
/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16,
|
||||
|
||||
/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -778,7 +786,7 @@ const OpFn OP_TABLE(pentiummmx_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w,
|
||||
/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32,
|
||||
/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL,
|
||||
|
||||
/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -800,7 +808,7 @@ const OpFn OP_TABLE(pentiummmx_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l,
|
||||
/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32,
|
||||
/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32,
|
||||
|
||||
/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -826,7 +834,7 @@ const OpFn OP_TABLE(k6_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w,
|
||||
/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16,
|
||||
/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL,
|
||||
|
||||
/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -848,7 +856,7 @@ const OpFn OP_TABLE(k6_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l,
|
||||
/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16,
|
||||
/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16,
|
||||
|
||||
/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -870,7 +878,7 @@ const OpFn OP_TABLE(k6_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w,
|
||||
/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32,
|
||||
/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL,
|
||||
|
||||
/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -892,7 +900,7 @@ const OpFn OP_TABLE(k6_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l,
|
||||
/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32,
|
||||
/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32,
|
||||
|
||||
/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -902,6 +910,7 @@ const OpFn OP_TABLE(k6_0f)[1024] =
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86)
|
||||
const OpFn OP_TABLE(c6x86mx_0f)[1024] =
|
||||
{
|
||||
/*16-bit data, 16-bit addr*/
|
||||
@@ -918,7 +927,7 @@ const OpFn OP_TABLE(c6x86mx_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w,
|
||||
/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16,
|
||||
/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL,
|
||||
|
||||
/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -940,7 +949,7 @@ const OpFn OP_TABLE(c6x86mx_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l,
|
||||
/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16,
|
||||
/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16,
|
||||
|
||||
/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -962,7 +971,7 @@ const OpFn OP_TABLE(c6x86mx_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w,
|
||||
/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32,
|
||||
/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL,
|
||||
|
||||
/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -984,7 +993,7 @@ const OpFn OP_TABLE(c6x86mx_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l,
|
||||
/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32,
|
||||
/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32,
|
||||
|
||||
/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -992,6 +1001,7 @@ const OpFn OP_TABLE(c6x86mx_0f)[1024] =
|
||||
/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32,
|
||||
/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef DEV_BRANCH
|
||||
#ifdef USE_I686
|
||||
@@ -1011,7 +1021,7 @@ const OpFn OP_TABLE(pentiumpro_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w,
|
||||
/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16,
|
||||
/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL,
|
||||
|
||||
/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -1033,7 +1043,7 @@ const OpFn OP_TABLE(pentiumpro_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l,
|
||||
/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16,
|
||||
/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16,
|
||||
|
||||
/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -1055,7 +1065,7 @@ const OpFn OP_TABLE(pentiumpro_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w,
|
||||
/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32,
|
||||
/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL,
|
||||
|
||||
/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -1077,7 +1087,7 @@ const OpFn OP_TABLE(pentiumpro_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l,
|
||||
/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32,
|
||||
/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32,
|
||||
|
||||
/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -1103,7 +1113,7 @@ const OpFn OP_TABLE(pentium2_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w,
|
||||
/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16,
|
||||
/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL,
|
||||
|
||||
/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -1125,7 +1135,7 @@ const OpFn OP_TABLE(pentium2_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l,
|
||||
/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16,
|
||||
/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16,
|
||||
|
||||
/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -1147,7 +1157,7 @@ const OpFn OP_TABLE(pentium2_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w,
|
||||
/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32,
|
||||
/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL,
|
||||
|
||||
/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -1169,7 +1179,7 @@ const OpFn OP_TABLE(pentium2_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l,
|
||||
/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32,
|
||||
/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32,
|
||||
|
||||
/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -1195,7 +1205,7 @@ const OpFn OP_TABLE(pentium2d_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w,
|
||||
/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,opFXSAVESTOR_a16,opIMUL_w_w_a16,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,opFXSAVESTOR_a16,opIMUL_w_w_a16,
|
||||
/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL,
|
||||
|
||||
/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -1217,7 +1227,7 @@ const OpFn OP_TABLE(pentium2d_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l,
|
||||
/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,opFXSAVESTOR_a16,opIMUL_l_l_a16,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,opFXSAVESTOR_a16,opIMUL_l_l_a16,
|
||||
/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16,
|
||||
|
||||
/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -1239,7 +1249,7 @@ const OpFn OP_TABLE(pentium2d_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w,
|
||||
/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,opFXSAVESTOR_a32,opIMUL_w_w_a32,
|
||||
/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,opFXSAVESTOR_a32,opIMUL_w_w_a32,
|
||||
/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL,
|
||||
|
||||
/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
@@ -1261,7 +1271,7 @@ const OpFn OP_TABLE(pentium2d_0f)[1024] =
|
||||
|
||||
/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l,
|
||||
/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,opFXSAVESTOR_a32,opIMUL_l_l_a32,
|
||||
/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,opFXSAVESTOR_a32,opIMUL_l_l_a32,
|
||||
/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32,
|
||||
|
||||
/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI,
|
||||
|
||||
5919
src/cpu/808x.c
5919
src/cpu/808x.c
File diff suppressed because it is too large
Load Diff
@@ -42,7 +42,7 @@
|
||||
|
||||
#ifdef __amd64__
|
||||
#include "codegen_x86-64.h"
|
||||
#elif defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _WIN32
|
||||
#elif defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 || defined _M_X64
|
||||
#include "codegen_x86.h"
|
||||
#else
|
||||
#error Dynamic recompiler not implemented on your platform
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#ifdef __amd64__
|
||||
#include "codegen_ops_x86-64.h"
|
||||
#elif defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _WIN32
|
||||
#elif defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 || defined _M_X64
|
||||
#include "codegen_ops_x86.h"
|
||||
#endif
|
||||
|
||||
|
||||
@@ -5,12 +5,12 @@ static uint32_t ropNOP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32
|
||||
|
||||
static uint32_t ropCLD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
|
||||
{
|
||||
CLEAR_BITS((uintptr_t)&flags, D_FLAG);
|
||||
CLEAR_BITS((uintptr_t)&cpu_state.flags, D_FLAG);
|
||||
return op_pc;
|
||||
}
|
||||
static uint32_t ropSTD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
|
||||
{
|
||||
SET_BITS((uintptr_t)&flags, D_FLAG);
|
||||
SET_BITS((uintptr_t)&cpu_state.flags, D_FLAG);
|
||||
return op_pc;
|
||||
}
|
||||
|
||||
@@ -18,14 +18,14 @@ static uint32_t ropCLI(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32
|
||||
{
|
||||
if (!IOPLp && (cr4 & (CR4_VME | CR4_PVI)))
|
||||
return 0;
|
||||
CLEAR_BITS((uintptr_t)&flags, I_FLAG);
|
||||
CLEAR_BITS((uintptr_t)&cpu_state.flags, I_FLAG);
|
||||
return op_pc;
|
||||
}
|
||||
static uint32_t ropSTI(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
|
||||
{
|
||||
if (!IOPLp && (cr4 & (CR4_VME | CR4_PVI)))
|
||||
return 0;
|
||||
SET_BITS((uintptr_t)&flags, I_FLAG);
|
||||
SET_BITS((uintptr_t)&cpu_state.flags, I_FLAG);
|
||||
return op_pc;
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ static uint32_t ropFF_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint
|
||||
STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc);
|
||||
LOAD_STACK_TO_EA(-2);
|
||||
host_reg = LOAD_REG_IMM(op_pc + 1);
|
||||
MEM_STORE_ADDR_EA_W(&_ss, host_reg);
|
||||
MEM_STORE_ADDR_EA_W(&cpu_state.seg_ss, host_reg);
|
||||
SP_MODIFY(-2);
|
||||
|
||||
host_reg = LOAD_VAR_W((uintptr_t)&codegen_temp);
|
||||
@@ -168,7 +168,7 @@ static uint32_t ropFF_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint
|
||||
host_reg = LOAD_HOST_REG(host_reg);
|
||||
STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc);
|
||||
LOAD_STACK_TO_EA(-2);
|
||||
MEM_STORE_ADDR_EA_W(&_ss, host_reg);
|
||||
MEM_STORE_ADDR_EA_W(&cpu_state.seg_ss, host_reg);
|
||||
SP_MODIFY(-2);
|
||||
return op_pc + 1;
|
||||
}
|
||||
@@ -245,7 +245,7 @@ static uint32_t ropFF_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint
|
||||
STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc);
|
||||
LOAD_STACK_TO_EA(-4);
|
||||
host_reg = LOAD_REG_IMM(op_pc + 1);
|
||||
MEM_STORE_ADDR_EA_L(&_ss, host_reg);
|
||||
MEM_STORE_ADDR_EA_L(&cpu_state.seg_ss, host_reg);
|
||||
SP_MODIFY(-4);
|
||||
|
||||
host_reg = LOAD_VAR_L((uintptr_t)&codegen_temp);
|
||||
@@ -261,7 +261,7 @@ static uint32_t ropFF_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint
|
||||
host_reg = LOAD_HOST_REG(host_reg);
|
||||
STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc);
|
||||
LOAD_STACK_TO_EA(-4);
|
||||
MEM_STORE_ADDR_EA_L(&_ss, host_reg);
|
||||
MEM_STORE_ADDR_EA_L(&cpu_state.seg_ss, host_reg);
|
||||
SP_MODIFY(-4);
|
||||
return op_pc + 1;
|
||||
}
|
||||
|
||||
@@ -588,16 +588,16 @@ static uint32_t ropMOV_seg_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32,
|
||||
switch (fetchdat & 0x38)
|
||||
{
|
||||
case 0x00: /*ES*/
|
||||
LOAD_SEG(host_reg, &_es);
|
||||
LOAD_SEG(host_reg, &cpu_state.seg_es);
|
||||
break;
|
||||
case 0x18: /*DS*/
|
||||
LOAD_SEG(host_reg, &_ds);
|
||||
LOAD_SEG(host_reg, &cpu_state.seg_ds);
|
||||
break;
|
||||
case 0x20: /*FS*/
|
||||
LOAD_SEG(host_reg, &_fs);
|
||||
LOAD_SEG(host_reg, &cpu_state.seg_fs);
|
||||
break;
|
||||
case 0x28: /*GS*/
|
||||
LOAD_SEG(host_reg, &_gs);
|
||||
LOAD_SEG(host_reg, &cpu_state.seg_gs);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -644,13 +644,13 @@ static uint32_t ropL ## seg(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, u
|
||||
STORE_REG_TARGET_W_RELEASE(host_reg, dest_reg); \
|
||||
} \
|
||||
\
|
||||
if (&rseg == &_ss) \
|
||||
if (&rseg == &cpu_state.seg_ss) \
|
||||
CPU_BLOCK_END(); /*Instruction might change stack size, so end block here*/ \
|
||||
return op_pc + 1; \
|
||||
}
|
||||
|
||||
ropLseg(DS, _ds)
|
||||
ropLseg(ES, _es)
|
||||
ropLseg(FS, _fs)
|
||||
ropLseg(GS, _gs)
|
||||
ropLseg(SS, _ss)
|
||||
ropLseg(DS, cpu_state.seg_ds)
|
||||
ropLseg(ES, cpu_state.seg_es)
|
||||
ropLseg(FS, cpu_state.seg_fs)
|
||||
ropLseg(GS, cpu_state.seg_gs)
|
||||
ropLseg(SS, cpu_state.seg_ss)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user