Merge pull request #1 from 86Box/master

update fork
This commit is contained in:
richardg867
2020-01-13 13:52:00 -03:00
committed by GitHub
687 changed files with 175532 additions and 68125 deletions

31
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View 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.

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

@@ -1,3 +1,4 @@
src/*.o
src/*.exe
src/*.res
src/NUL

View File

@@ -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!
[![Visit our IRC channel](https://kiwiirc.com/buttons/irc.rol.im/softhistory.png)](https://kiwiirc.com/client/irc.rol.im/?nick=86box|?#softhistory)
[![Visit our IRC channel](https://kiwiirc.com/buttons/irc.ringoflightning.net/softhistory.png)](https://kiwiirc.com/client/irc.ringoflightning.net/?nick=86box|?#softhistory)
[![Visit our Discord server](https://discordapp.com/api/guilds/262614059009048590/embed.png)](https://discord.gg/Es3TnUH)
[![Visit our Discord server](https://discordapp.com/api/guilds/262614059009048590/embed.png)](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 |
|:-------:|:---------:|:------------:|
|[![Build Status](http://ci.86box.net/job/86Box/badge/icon)](http://ci.86box.net/job/86Box)|[![Build Status](http://ci.86box.net/job/86Box-Optimized/badge/icon)](http://ci.86box.net/job/86Box-Optimized)|[![Build Status](http://ci.86box.net/job/86Box-Dev/badge/icon)](http://ci.86box.net/job/86Box-Dev)
| Regular | Debug | Optimized | Experimental |
|:-------:|:-----:|:---------:|:------------:|
|[![Build Status](http://ci.86box.net/job/86Box/badge/icon)](http://ci.86box.net/job/86Box)|[![Build Status](http://ci.86box.net/job/86Box-Debug/badge/icon)](http://ci.86box.net/job/86Box-Debug)|[![Build Status](http://ci.86box.net/job/86Box-Optimized/badge/icon)](http://ci.86box.net/job/86Box-Optimized)|[![Build Status](http://ci.86box.net/job/86Box-Dev/badge/icon)](http://ci.86box.net/job/86Box-Dev)
### 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
---------

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

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

View 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 */

View File

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

View File

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

@@ -0,0 +1,171 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Implementation of the 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
View 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
View 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
View 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
View 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
View 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
View 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
};

View File

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

File diff suppressed because it is too large Load Diff

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

View File

@@ -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, &section->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));
}

View File

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

View File

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

View File

@@ -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();

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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