Merge branch 'master' into pc98x1

This commit is contained in:
TC1995
2024-07-10 19:41:43 +02:00
856 changed files with 81878 additions and 66645 deletions

View File

@@ -66,6 +66,7 @@
#include <86box/bugger.h>
#include <86box/postcard.h>
#include <86box/unittester.h>
#include <86box/novell_cardkey.h>
#include <86box/isamem.h>
#include <86box/isartc.h>
#include <86box/lpt.h>
@@ -170,9 +171,10 @@ int video_filter_method = 1; /* (C) video *
int video_vsync = 0; /* (C) video */
int video_framerate = -1; /* (C) video */
char video_shader[512] = { '\0' }; /* (C) video */
bool serial_passthrough_enabled[SERIAL_MAX] = { 0, 0, 0, 0 }; /* (C) activation and kind of
pass-through for serial ports */
bool serial_passthrough_enabled[SERIAL_MAX] = { 0, 0, 0, 0, 0, 0, 0 }; /* (C) activation and kind of
pass-through for serial ports */
int bugger_enabled = 0; /* (C) enable ISAbugger */
int novell_keycard_enabled = 0; /* (C) enable Novell NetWare 2.x key card emulation. */
int postcard_enabled = 0; /* (C) enable POST card */
int unittester_enabled = 0; /* (C) enable unit tester device */
int isamem_type[ISAMEM_MAX] = { 0, 0, 0, 0 }; /* (C) enable ISA mem cards */
@@ -181,6 +183,7 @@ int gfxcard[2] = { 0, 0 }; /* (C) graphic
int show_second_monitors = 1; /* (C) show non-primary monitors */
int sound_is_float = 1; /* (C) sound uses FP values */
int voodoo_enabled = 0; /* (C) video option */
int lba_enhancer_enabled = 0; /* (C) enable Vision Systems LBA Enhancer */
int ibm8514_standalone_enabled = 0; /* (C) video option */
int xga_standalone_enabled = 0; /* (C) video option */
uint32_t mem_size = 0; /* (C) memory size (Installed on
@@ -203,6 +206,12 @@ int video_fullscreen_scale_maximized = 0; /* (C) Whether
also apply when maximized. */
int do_auto_pause = 0; /* (C) Auto-pause the emulator on focus
loss */
char uuid[MAX_UUID_LEN] = { '\0' }; /* (C) UUID or machine identifier */
int other_ide_present = 0; /* IDE controllers from non-IDE cards are
present */
int other_scsi_present = 0; /* SCSI controllers from non-SCSI cards are
present */
/* Statistics. */
extern int mmuflush;
@@ -345,12 +354,14 @@ fatal(const char *fmt, ...)
if ((sp = strchr(temp, '\n')) != NULL)
*sp = '\0';
do_pause(2);
ui_msgbox(MBX_ERROR | MBX_FATAL | MBX_ANSI, temp);
/* Cleanly terminate all of the emulator's components so as
to avoid things like threads getting stuck. */
do_stop();
ui_msgbox(MBX_ERROR | MBX_FATAL | MBX_ANSI, temp);
fflush(stdlog);
exit(-1);
@@ -387,12 +398,14 @@ fatal_ex(const char *fmt, va_list ap)
if ((sp = strchr(temp, '\n')) != NULL)
*sp = '\0';
do_pause(2);
ui_msgbox(MBX_ERROR | MBX_FATAL | MBX_ANSI, temp);
/* Cleanly terminate all of the emulator's components so as
to avoid things like threads getting stuck. */
do_stop();
ui_msgbox(MBX_ERROR | MBX_FATAL | MBX_ANSI, temp);
fflush(stdlog);
}
@@ -951,12 +964,12 @@ pc_init_modules(void)
/* Load the ROMs for the selected machine. */
if (!machine_available(machine)) {
swprintf(temp, sizeof_w(temp), plat_get_string(IDS_2063), machine_getname());
swprintf(temp, sizeof_w(temp), plat_get_string(STRING_HW_NOT_AVAILABLE_MACHINE), machine_getname());
c = 0;
machine = -1;
while (machine_get_internal_name_ex(c) != NULL) {
if (machine_available(c)) {
ui_msgbox_header(MBX_INFO, (wchar_t *) IDS_2129, temp);
ui_msgbox_header(MBX_INFO, plat_get_string(STRING_HW_NOT_AVAILABLE_TITLE), temp);
machine = c;
config_save();
break;
@@ -973,12 +986,12 @@ pc_init_modules(void)
if (!video_card_available(gfxcard[0])) {
memset(tempc, 0, sizeof(tempc));
device_get_name(video_card_getdevice(gfxcard[0]), 0, tempc);
swprintf(temp, sizeof_w(temp), plat_get_string(IDS_2064), tempc);
swprintf(temp, sizeof_w(temp), plat_get_string(STRING_HW_NOT_AVAILABLE_VIDEO), tempc);
c = 0;
while (video_get_internal_name(c) != NULL) {
gfxcard[0] = -1;
if (video_card_available(c)) {
ui_msgbox_header(MBX_INFO, (wchar_t *) IDS_2129, temp);
ui_msgbox_header(MBX_INFO, plat_get_string(STRING_HW_NOT_AVAILABLE_TITLE), temp);
gfxcard[0] = c;
config_save();
break;
@@ -994,8 +1007,8 @@ pc_init_modules(void)
if (!video_card_available(gfxcard[1])) {
char tempc[512] = { 0 };
device_get_name(video_card_getdevice(gfxcard[1]), 0, tempc);
swprintf(temp, sizeof_w(temp), plat_get_string(IDS_2163), tempc);
ui_msgbox_header(MBX_INFO, (wchar_t *) IDS_2129, temp);
swprintf(temp, sizeof_w(temp), plat_get_string(STRING_HW_NOT_AVAILABLE_VIDEO2), tempc);
ui_msgbox_header(MBX_INFO, plat_get_string(STRING_HW_NOT_AVAILABLE_TITLE), temp);
gfxcard[1] = 0;
}
@@ -1076,18 +1089,22 @@ pc_reset_hard_close(void)
/* Close all the memory mappings. */
mem_close();
suppress_overscan = 0;
/* Turn off timer processing to avoid potential segmentation faults. */
timer_close();
suppress_overscan = 0;
lpt_devices_close();
#ifdef UNCOMMENT_LATER
lpt_close();
#endif
nvr_save();
nvr_close();
mouse_close();
lpt_devices_close();
device_close_all();
scsi_device_close_all();
@@ -1128,6 +1145,9 @@ pc_reset_hard_init(void)
* modules that are.
*/
/* Reset the IDE and SCSI presences */
other_ide_present = other_scsi_present = 0;
/* Mark ACPI as unavailable */
acpi_enabled = 0;
@@ -1167,13 +1187,14 @@ pc_reset_hard_init(void)
/* note: PLIP LPT side has to be initialized before the network side */
lpt_devices_init();
/* Reset and reconfigure the Network Card layer. */
network_reset();
/* Reset and reconfigure the serial ports. */
/* note: SLIP COM side has to be initialized before the network side */
serial_standalone_init();
serial_passthrough_init();
/* Reset and reconfigure the Network Card layer. */
network_reset();
/*
* Reset the mouse, this will attach it to any port needed.
*/
@@ -1227,6 +1248,12 @@ pc_reset_hard_init(void)
if (unittester_enabled)
device_add(&unittester_device);
if (lba_enhancer_enabled)
device_add(&lba_enhancer_device);
if (novell_keycard_enabled)
device_add(&novell_keycard_device);
if (IS_ARCH(machine, MACHINE_BUS_PCI)) {
pci_register_cards();
device_reset_all(DEVICE_PCI);
@@ -1279,17 +1306,17 @@ update_mouse_msg(void)
mbstowcs(wcpu, cpu_s->name, strlen(cpu_s->name) + 1);
#ifdef _WIN32
swprintf(mouse_msg[0], sizeof_w(mouse_msg[0]), L"%%i%%%% - %ls",
plat_get_string(IDS_2077));
plat_get_string(STRING_MOUSE_CAPTURE));
swprintf(mouse_msg[1], sizeof_w(mouse_msg[1]), L"%%i%%%% - %ls",
(mouse_get_buttons() > 2) ? plat_get_string(IDS_2078) : plat_get_string(IDS_2079));
(mouse_get_buttons() > 2) ? plat_get_string(STRING_MOUSE_RELEASE) : plat_get_string(STRING_MOUSE_RELEASE_MMB));
wcsncpy(mouse_msg[2], L"%i%%", sizeof_w(mouse_msg[2]));
#else
swprintf(mouse_msg[0], sizeof_w(mouse_msg[0]), L"%ls v%ls - %%i%%%% - %ls - %ls/%ls - %ls",
EMU_NAME_W, EMU_VERSION_FULL_W, wmachine, wcpufamily, wcpu,
plat_get_string(IDS_2077));
plat_get_string(STRING_MOUSE_CAPTURE));
swprintf(mouse_msg[1], sizeof_w(mouse_msg[1]), L"%ls v%ls - %%i%%%% - %ls - %ls/%ls - %ls",
EMU_NAME_W, EMU_VERSION_FULL_W, wmachine, wcpufamily, wcpu,
(mouse_get_buttons() > 2) ? plat_get_string(IDS_2078) : plat_get_string(IDS_2079));
(mouse_get_buttons() > 2) ? plat_get_string(STRING_MOUSE_RELEASE) : plat_get_string(STRING_MOUSE_RELEASE_MMB));
swprintf(mouse_msg[2], sizeof_w(mouse_msg[2]), L"%ls v%ls - %%i%%%% - %ls - %ls/%ls",
EMU_NAME_W, EMU_VERSION_FULL_W, wmachine, wcpufamily, wcpu);
#endif

View File

@@ -21,7 +21,7 @@ endif()
add_executable(86Box 86box.c config.c log.c random.c timer.c io.c acpi.c apm.c
dma.c ddma.c nmi.c pic.c pit.c pit_fast.c port_6x.c port_92.c ppi.c pci.c
mca.c usb.c fifo.c fifo8.c device.c nvr.c nvr_at.c nvr_ps2.c
machine_status.c ini.c)
machine_status.c ini.c cJSON.c)
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
add_compile_definitions(_FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE=1 _LARGEFILE64_SOURCE=1)
@@ -57,12 +57,16 @@ if(DISCORD)
target_sources(86Box PRIVATE discord.c)
endif()
if(DEBUGREGS486)
add_compile_definitions(USE_DEBUG_REGS_486)
endif()
if(VNC)
find_package(LibVNCServer)
if(LibVNCServer_FOUND)
add_compile_definitions(USE_VNC)
add_library(vnc OBJECT vnc.c vnc_keymap.c)
target_link_libraries(86Box vnc LibVNCServer::vncserver)
target_link_libraries(86Box vnc LibVNCServer::vncserver)
if(WIN32)
target_link_libraries(86Box ws2_32)
endif()
@@ -226,8 +230,6 @@ endif()
if (QT)
add_subdirectory(qt)
elseif(WIN32)
add_subdirectory(win)
else()
add_compile_definitions(USE_SDL_UI)
add_subdirectory(unix)

View File

@@ -1,200 +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.
#
# Prefix for localizing the general Makefile.mingw for local
# settings, so we can avoid changing the main one for all of
# our local setups.
#
# Authors: Fred N. van Kempen, <decwiz@yahoo.com>
#
#########################################################################
# Anything here will override defaults in Makefile.MinGW. #
#########################################################################
# Name of the executable.
#PROG := 86box.exe
# Various compile-time options.
# -DROM_TRACE=0xc800 traces ROM access from segment C800
# -DIO_TRACE=0x66 traces I/O on port 0x66
# -DIO_CATCH enables I/O range catch logs
STUFF :=
# Add feature selections here.
# -DANSI_CFG forces the config file to ANSI encoding.
# Root logging:
# -DENABLE_ACPI_LOG=N sets logging level at N.
# -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_DDMA_LOG=N sets logging level at N.
# -DENABLE_DEVICE_LOG=N sets logging level at N.
# -DENABLE_DMA_LOG=N sets logging level at N.
# -DENABLE_IO_LOG=N sets logging level at N.
# -DENABLE_IOAPIC_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_KEYBOARD_XT_LOG=N sets logging level at N.
# -DENABLE_LM75_LOG=N sets logging level at N.
# -DENABLE_LM78_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.
# -DENABLE_MOUSE_PS2_LOG=N sets logging level at N.
# -DENABLE_MOUSE_SERIAL_LOG=N sets logging level at N.
# -DENABLE_NVR_LOG=N sets logging level at N.
# -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_PIT_LOG=N sets logging level at N.
# -DENABLE_POSTCARD_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_SMBUS_LOG=N sets logging level at N.
# -DENABLE_SMBUS_PIIX4_LOG=N sets logging level at N.
# -DENABLE_SPD_LOG=N sets logging level at N.
# -DENABLE_USB_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_IMAGE_LOG=N sets logging level at N.
# -DENABLE_CDROM_IMAGE_BACKEND_LOG=N sets logging level at N.
# chipset/ logging:
# -DENABLE_I420EX_LOG=N sets logging level at N.
# -DENABLE_NEAT_LOG=N sets logging level at N.
# -DENABLE_OPTI495_LOG=N sets logging level at N.
# -DENABLE_OPTI895_LOG=N sets logging level at N.
# -DENABLE_PIIX_LOG=N sets logging level at N.
# -DENABLE_SIO_LOG=N sets logging level at N.
# -DENABLE_SIS_85C496_LOG=N sets logging level at N.
# codegen/, codegen_new/, cpu/ logging:
# -DENABLE_X86SEG_LOG=N sets logging level at N.
# cpu/ logging:
# -DENABLE_386_LOG=N sets logging level at N.
# -DENABLE_386_COMMON_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_CPU_LOG=N sets logging level at N.
# -DENABLE_FPU_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_MO_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:
# -DENABLE_D86F_LOG=N sets logging level at N.
# -DENABLE_FDC_LOG=N sets logging level at N.
# -DENABLE_FDD_LOG=N sets logging level at N.
# -DENABLE_FDI_LOG=N sets logging level at N.
# -DENABLE_FDI2RAW_LOG=N sets logging level at N.
# -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.
# 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_NE2K_LOG=N sets logging level at N.
# -DENABLE_PCAP_LOG=N sets logging level at N.
# -DENABLE_PCNET_LOG=N sets logging level at N.
# -DENABLE_SLIRP_LOG=N sets logging level at N.
# -DENABLE_WD_LOG=N sets logging level at N.
# printer/ logging:
# -DENABLE_ESCP_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_NCR53C8XX_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_SPOCK_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.
# -DENABLE_AUDIOPCI_LOG=N sets logging level at N.
# -DENABLE_EMU8K_LOG=N sets logging level at N.
# -DENABLE_MPU401_LOG=N sets logging level at N.
# -DENABLE_PAS16_LOG=N sets logging level at N.
# -DENABLE_SB_LOG=N sets logging level at N.
# -DENABLE_SB_DSP_LOG=N sets logging level at N.
# -DENABLE_SOUND_LOG=N sets logging level at N.
# 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_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_VIDEO_LOG=N sets logging level at N.
# -DENABLE_VOODOO_LOG=N sets logging level at N.
# win/ logging:
# -DENABLE_WIN_LOG=N sets logging level at N.
# -DENABLE_DISCORD_LOG=N sets logging level at N.
# -DENABLE_DYNLD_LOG=N sets logging level at N.
# -DENABLE_JOYSTICK_LOG=N sets logging level at N.
# -DENABLE_SDL_LOG=N sets logging level at N.
# -DENABLE_SETTINGS_LOG=N sets logging level at N.
EXTRAS :=
AUTODEP := n
DEBUG := n
OPTIM := n
X64 := n
RELEASE := n
USB := n
VNC := n
RDP := n
DEV_BUILD := n
DEV_BRANCH := n
CIRRUS := n
NE1000 := n
NV_RIVA := n
OPENAL := y
FLUIDSYNTH := y
MUNT := y
PAS16 := n
DYNAREC := y
#########################################################################
# Include the master Makefile.MinGW for the rest. #
#########################################################################
include win/Makefile.mingw
# End of Makefile.local.

File diff suppressed because it is too large Load Diff

3129
src/cJSON.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -13,4 +13,4 @@
# Copyright 2020-2021 David Hrdlička.
#
add_library(cdrom OBJECT cdrom.c cdrom_image_backend.c cdrom_image_viso.c cdrom_image.c cdrom_mitsumi.c)
add_library(cdrom OBJECT cdrom.c cdrom_image_backend.c cdrom_image_viso.c cdrom_image.c cdrom_ioctl.c cdrom_mitsumi.c)

View File

@@ -1524,8 +1524,9 @@ static void
read_sector_to_buffer(cdrom_t *dev, uint8_t *rbuf, uint32_t msf, uint32_t lba, int mode2, int len)
{
uint8_t *bb = rbuf;
const int offset = (!!(mode2 & 0x03)) ? 24 : 16;
dev->ops->read_sector(dev, CD_READ_DATA, rbuf + 16, lba);
dev->ops->read_sector(dev, CD_READ_DATA, rbuf + offset, lba);
/* Sync bytes */
bb[0] = 0;
@@ -1960,7 +1961,7 @@ cdrom_hard_reset(void)
dev->cd_status = CD_STATUS_EMPTY;
if (dev->host_drive == 200) {
if (strlen(dev->image_path) > 0) {
#ifdef _WIN32
if ((strlen(dev->image_path) >= 1) && (dev->image_path[strlen(dev->image_path) - 1] == '/'))
dev->image_path[strlen(dev->image_path) - 1] = '\\';
@@ -1970,7 +1971,10 @@ cdrom_hard_reset(void)
dev->image_path[strlen(dev->image_path) - 1] = '/';
#endif
cdrom_image_open(dev, dev->image_path);
if ((strlen(dev->image_path) != 0) && (strstr(dev->image_path, "ioctl://") == dev->image_path))
cdrom_ioctl_open(dev, dev->image_path);
else
cdrom_image_open(dev, dev->image_path);
}
}
}
@@ -2019,16 +2023,12 @@ cdrom_eject(uint8_t id)
cdrom_t *dev = &cdrom[id];
/* This entire block should be in cdrom.c/cdrom_eject(dev*) ... */
if (dev->host_drive == 0) {
if (strlen(dev->image_path) == 0) {
/* Switch from empty to empty. Do nothing. */
return;
}
if (dev->host_drive == 200)
strcpy(dev->prev_image_path, dev->image_path);
dev->prev_host_drive = dev->host_drive;
dev->host_drive = 0;
strcpy(dev->prev_image_path, dev->image_path);
dev->ops->exit(dev);
dev->ops = NULL;
@@ -2047,7 +2047,7 @@ cdrom_reload(uint8_t id)
{
cdrom_t *dev = &cdrom[id];
if ((dev->host_drive == dev->prev_host_drive) || (dev->prev_host_drive == 0) || (dev->host_drive != 0)) {
if ((strcmp(dev->image_path, dev->prev_image_path) == 0) || (strlen(dev->prev_image_path) == 0) || (strlen(dev->image_path) > 0)) {
/* Switch from empty to empty. Do nothing. */
return;
}
@@ -2057,26 +2057,29 @@ cdrom_reload(uint8_t id)
dev->ops = NULL;
memset(dev->image_path, 0, sizeof(dev->image_path));
if (dev->prev_host_drive == 200) {
if (strlen(dev->image_path) > 0) {
/* Reload a previous image. */
strcpy(dev->image_path, dev->prev_image_path);
if (strlen(dev->prev_image_path) > 0)
strcpy(dev->image_path, dev->prev_image_path);
#ifdef _WIN32
if ((strlen(dev->image_path) >= 1) && (dev->image_path[strlen(dev->image_path) - 1] == '/'))
dev->image_path[strlen(dev->image_path) - 1] = '\\';
if (strlen(dev->prev_image_path) > 0) {
if ((strlen(dev->image_path) >= 1) && (dev->image_path[strlen(dev->image_path) - 1] == '/'))
dev->image_path[strlen(dev->image_path) - 1] = '\\';
}
#else
if ((strlen(dev->image_path) >= 1) && (dev->image_path[strlen(dev->image_path) - 1] == '\\'))
dev->image_path[strlen(dev->image_path) - 1] = '/';
if (strlen(dev->prev_image_path) > 0) {
if ((strlen(dev->image_path) >= 1) && (dev->image_path[strlen(dev->image_path) - 1] == '\\'))
dev->image_path[strlen(dev->image_path) - 1] = '/';
}
#endif
cdrom_image_open(dev, dev->image_path);
if ((strlen(dev->image_path) != 0) && (strstr(dev->image_path, "ioctl://") == dev->image_path))
cdrom_ioctl_open(dev, dev->image_path);
else
cdrom_image_open(dev, dev->image_path);
cdrom_insert(id);
if (strlen(dev->image_path) == 0)
dev->host_drive = 0;
else
dev->host_drive = 200;
}
plat_cdrom_ui_update(id, 1);

View File

@@ -97,6 +97,9 @@ image_get_subchannel(cdrom_t *dev, uint32_t lba, subchannel_t *subc)
subc->rel_m = rel_pos.min;
subc->rel_s = rel_pos.sec;
subc->rel_f = rel_pos.fr;
cdrom_image_log("image_get_subchannel(): %02X, %02X, %02i, %02i:%02i:%02i, %02i:%02i:%02i\n",
subc->attr, subc->track, subc->index, subc->abs_m, subc->abs_s, subc->abs_f, subc->rel_m, subc->rel_s, subc->rel_f);
}
static int
@@ -217,6 +220,12 @@ image_track_type(cdrom_t *dev, uint32_t lba)
return 0;
}
static int
image_ext_medium_changed(cdrom_t *dev)
{
return 0;
}
static void
image_exit(cdrom_t *dev)
{
@@ -241,6 +250,7 @@ static const cdrom_ops_t cdrom_image_ops = {
image_sector_size,
image_read_sector,
image_track_type,
image_ext_medium_changed,
image_exit
};
@@ -249,7 +259,6 @@ image_open_abort(cdrom_t *dev)
{
cdrom_image_close(dev);
dev->ops = NULL;
dev->host_drive = 0;
dev->image_path[0] = 0;
return 1;
}

View File

@@ -70,12 +70,12 @@ cdrom_image_backend_log(const char *fmt, ...)
static int
bin_read(void *priv, uint8_t *buffer, uint64_t seek, size_t count)
{
track_file_t *tf = (track_file_t *) priv;
track_file_t *tf;
cdrom_image_backend_log("CDROM: binary_read(%08lx, pos=%" PRIu64 " count=%lu\n",
tf->fp, seek, count);
if (tf->fp == NULL)
if ((tf = (track_file_t *) priv)->fp == NULL)
return 0;
if (fseeko64(tf->fp, seek, SEEK_SET) == -1) {
@@ -98,16 +98,15 @@ bin_read(void *priv, uint8_t *buffer, uint64_t seek, size_t count)
static uint64_t
bin_get_length(void *priv)
{
off64_t len;
track_file_t *tf = (track_file_t *) priv;
track_file_t *tf;
cdrom_image_backend_log("CDROM: binary_length(%08lx)\n", tf->fp);
if (tf->fp == NULL)
if ((tf = (track_file_t *) priv)->fp == NULL)
return 0;
fseeko64(tf->fp, 0, SEEK_END);
len = ftello64(tf->fp);
const off64_t len = ftello64(tf->fp);
cdrom_image_backend_log("CDROM: binary_length(%08lx) = %" PRIu64 "\n", tf->fp, len);
return len;
@@ -248,26 +247,20 @@ cdi_set_device(cd_img_t *cdi, const char *path)
return 0;
}
/* TODO: This never returns anything other than 1, should it even be an int? */
int
void
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;
}
/* TODO: This never returns anything other than 1, should it even be an int? */
int
void
cdi_get_audio_tracks_lba(cd_img_t *cdi, int *st_track, int *end, uint32_t *lead_out)
{
*st_track = 1;
*end = cdi->tracks_num - 1;
*lead_out = cdi->tracks[*end].start;
return 1;
}
int
@@ -286,12 +279,11 @@ int
cdi_get_audio_track_info(cd_img_t *cdi, UNUSED(int end), int track, int *track_num, TMSF *start, uint8_t *attr)
{
const 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;
const int pos = trk->start + 150;
FRAMES_TO_MSF(pos, &start->min, &start->sec, &start->fr);
@@ -320,9 +312,6 @@ cdi_get_audio_track_info_lba(cd_img_t *cdi, UNUSED(int end), int track, int *tra
int
cdi_get_track(cd_img_t *cdi, uint32_t sector)
{
const track_t *cur;
const track_t *next;
/* There must be at least two tracks - data and lead out. */
if (cdi->tracks_num < 2)
return -1;
@@ -330,8 +319,8 @@ cdi_get_track(cd_img_t *cdi, uint32_t sector)
/* This has a problem - the code skips the last track, which is
lead out - is that correct? */
for (int i = 0; i < (cdi->tracks_num - 1); i++) {
cur = &cdi->tracks[i];
next = &cdi->tracks[i + 1];
const track_t *cur = &cdi->tracks[i];
const track_t *next = &cdi->tracks[i + 1];
/* Take into account cue sheets that do not start on sector 0. */
if ((i == 0) && (sector < cur->start))
@@ -348,16 +337,15 @@ cdi_get_track(cd_img_t *cdi, uint32_t sector)
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);
const track_t *trk;
const int cur_track = cdi_get_track(cdi, sector);
if (cur_track < 1)
return 0;
*track = (uint8_t) cur_track;
trk = &cdi->tracks[*track - 1];
*attr = trk->attr;
*index = 1;
*track = (uint8_t) cur_track;
const track_t *trk = &cdi->tracks[*track - 1];
*attr = trk->attr;
*index = 1;
FRAMES_TO_MSF(sector + 150, &abs_pos->min, &abs_pos->sec, &abs_pos->fr);
@@ -370,16 +358,11 @@ cdi_get_audio_sub(cd_img_t *cdi, uint32_t sector, uint8_t *attr, uint8_t *track,
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;
uint64_t seek;
track_t *trk;
int track_is_raw;
int ret;
const int track = cdi_get_track(cdi, sector) - 1;
const uint64_t sect = (uint64_t) sector;
int raw_size;
int cooked_size;
uint64_t offset = 0ULL;
uint64_t offset;
int m = 0;
int s = 0;
int f = 0;
@@ -387,10 +370,10 @@ cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector)
if (track < 0)
return 0;
trk = &cdi->tracks[track];
track_is_raw = ((trk->sector_size == RAW_SECTOR_SIZE) || (trk->sector_size == 2448));
const track_t *trk = &cdi->tracks[track];
const int track_is_raw = ((trk->sector_size == RAW_SECTOR_SIZE) || (trk->sector_size == 2448));
seek = trk->skip + ((sect - trk->start) * trk->sector_size);
const uint64_t seek = trk->skip + ((sect - trk->start) * trk->sector_size);
if (track_is_raw)
raw_size = trk->sector_size;
@@ -405,7 +388,7 @@ cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector)
} else
cooked_size = COOKED_SECTOR_SIZE;
length = (raw ? raw_size : cooked_size);
const size_t length = (raw ? raw_size : cooked_size);
if (trk->mode2 && (trk->form >= 1))
offset = 24ULL;
@@ -414,7 +397,7 @@ cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector)
if (raw && !track_is_raw) {
memset(buffer, 0x00, 2448);
ret = trk->file->read(trk->file, buffer + offset, seek, length);
const int ret = trk->file->read(trk->file, buffer + offset, seek, length);
if (!ret)
return 0;
/* Construct the rest of the raw sector. */
@@ -422,32 +405,28 @@ cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector)
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[0] = CDROM_BCD(m & 0xff);
buffer[1] = CDROM_BCD(s & 0xff);
buffer[2] = CDROM_BCD(f & 0xff);
/* Data, should reflect the actual sector type. */
buffer[15] = trk->mode2 ? 2 : 1;
buffer[3] = trk->mode2 ? 2 : 1;
return 1;
} else if (!raw && track_is_raw)
return trk->file->read(trk->file, buffer, seek + offset, length);
else {
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;
int success = 1;
uint8_t *buf;
uint32_t buf_len;
/* 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));
const int sector_size = raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE;
const uint32_t buf_len = num * sector_size;
uint8_t *buf = (uint8_t *) malloc(buf_len * sizeof(uint8_t));
for (uint32_t i = 0; i < num; i++) {
success = cdi_read_sector(cdi, &buf[i * sector_size], raw, sector + i);
@@ -455,7 +434,9 @@ cdi_read_sectors(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector, uint3
break;
/* Based on the DOSBox patch, but check all 8 bytes and makes sure it's not an
audio track. */
if (raw && sector < cdi->tracks[0].length && !cdi->tracks[0].mode2 && (cdi->tracks[0].attr != AUDIO_TRACK) && *(uint64_t *) &(buf[i * sector_size + 2068]))
if (raw && (sector < cdi->tracks[0].length) &&
!cdi->tracks[0].mode2 && (cdi->tracks[0].attr != AUDIO_TRACK) &&
*(uint64_t *) &(buf[(i * sector_size) + 2068]))
return 0;
}
@@ -470,16 +451,13 @@ cdi_read_sectors(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector, uint3
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;
uint64_t seek;
const int track = cdi_get_track(cdi, sector) - 1;
if (track < 0)
return 0;
trk = &cdi->tracks[track];
seek = trk->skip + ((s - trk->start) * trk->sector_size);
const track_t *trk = &cdi->tracks[track];
const uint64_t seek = trk->skip + (((uint64_t) sector - trk->start) * trk->sector_size);
if (trk->sector_size != 2448)
return 0;
@@ -489,26 +467,24 @@ cdi_read_sector_sub(cd_img_t *cdi, uint8_t *buffer, uint32_t sector)
int
cdi_get_sector_size(cd_img_t *cdi, uint32_t sector)
{
int track = cdi_get_track(cdi, sector) - 1;
const track_t *trk;
const int track = cdi_get_track(cdi, sector) - 1;
if (track < 0)
return 0;
trk = &cdi->tracks[track];
const track_t *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;
const track_t *trk;
const int track = cdi_get_track(cdi, sector) - 1;
if (track < 0)
return 0;
trk = &cdi->tracks[track];
const track_t *trk = &cdi->tracks[track];
return !!(trk->mode2);
}
@@ -516,13 +492,12 @@ cdi_is_mode2(cd_img_t *cdi, uint32_t sector)
int
cdi_get_mode2_form(cd_img_t *cdi, uint32_t sector)
{
int track = cdi_get_track(cdi, sector) - 1;
const track_t *trk;
const int track = cdi_get_track(cdi, sector) - 1;
if (track < 0)
return 0;
trk = &cdi->tracks[track];
const track_t *trk = &cdi->tracks[track];
return trk->form;
}
@@ -533,10 +508,13 @@ 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;
if (sector_size == RAW_SECTOR_SIZE) {
if (mode2 && (form > 0))
seek += 24;
else
seek += 16;
} else if (form > 0)
seek += 8;
file->read(file, pvd, seek, COOKED_SECTOR_SIZE);
@@ -591,7 +569,7 @@ cdi_load_iso(cd_img_t *cdi, const char *filename)
/* 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)) {
@@ -601,9 +579,22 @@ cdi_load_iso(cd_img_t *cdi, const char *filename)
trk.sector_size = 2324;
trk.mode2 = 1;
trk.form = 2;
} else if (cdi_can_read_pvd(trk.file, 2328, 1, 2)) {
trk.sector_size = 2328;
trk.mode2 = 1;
trk.form = 2;
} else if (cdi_can_read_pvd(trk.file, 2336, 1, 1)) {
trk.sector_size = 2336;
trk.mode2 = 1;
trk.form = 1;
trk.skip = 8;
} else if (cdi_can_read_pvd(trk.file, RAW_SECTOR_SIZE, 1, 0)) {
trk.sector_size = RAW_SECTOR_SIZE;
trk.mode2 = 1;
} else if (cdi_can_read_pvd(trk.file, RAW_SECTOR_SIZE, 1, 1)) {
trk.sector_size = RAW_SECTOR_SIZE;
trk.mode2 = 1;
trk.form = 1;
} else {
/* We use 2048 mode 1 as the default. */
trk.sector_size = COOKED_SECTOR_SIZE;
@@ -711,9 +702,9 @@ static int
cdi_cue_get_frame(uint64_t *frames, char **line)
{
char temp[128];
int min;
int sec;
int fr;
int min = 0;
int sec = 0;
int fr = 0;
int success;
success = cdi_cue_get_buffer(temp, line, 0);
@@ -754,17 +745,12 @@ 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;
uint64_t temp;
track_t *prev = NULL;
/* Skip *MUST* be calculated even if prestart is 0. */
if (prestart >= 0) {
if (prestart > cur->start)
return 0;
skip = cur->start - prestart;
} else
skip = 0ULL;
if (prestart > cur->start)
return 0;
const uint64_t skip = cur->start - prestart;
if ((cdi->tracks != NULL) && (cdi->tracks_num != 0))
prev = &cdi->tracks[cdi->tracks_num - 1];
@@ -779,6 +765,8 @@ cdi_add_track(cd_img_t *cdi, track_t *cur, uint64_t *shift, uint64_t prestart, u
if (cur->number != 1)
return 0;
cur->skip = skip * cur->sector_size;
if ((cur->sector_size != RAW_SECTOR_SIZE) && (cur->form > 0))
cur->skip += 8;
cur->start += cur_pregap;
*total_pregap = cur_pregap;
cdi_track_push_back(cdi, cur);
@@ -793,7 +781,7 @@ cdi_add_track(cd_img_t *cdi, track_t *cur, uint64_t *shift, uint64_t prestart, u
*total_pregap += cur_pregap;
cur->start += *total_pregap;
} else {
temp = prev->file->get_length(prev->file) - (prev->skip);
const uint64_t temp = prev->file->get_length(prev->file) - (prev->skip);
prev->length = temp / ((uint64_t) prev->sector_size);
if ((temp % prev->sector_size) != 0)
prev->length++;
@@ -801,6 +789,8 @@ cdi_add_track(cd_img_t *cdi, track_t *cur, uint64_t *shift, uint64_t prestart, u
cur->start += prev->start + prev->length + cur_pregap;
cur->skip = skip * cur->sector_size;
if ((cur->sector_size != RAW_SECTOR_SIZE) && (cur->form > 0))
cur->skip += 8;
*shift += prev->start + prev->length;
*total_pregap = cur_pregap;
}
@@ -823,8 +813,6 @@ cdi_load_cue(cd_img_t *cdi, const char *cuefile)
{
track_t trk;
char pathname[MAX_FILENAME_LENGTH];
char filename[MAX_FILENAME_LENGTH];
char temp[MAX_FILENAME_LENGTH];
uint64_t shift = 0ULL;
uint64_t prestart = 0ULL;
uint64_t cur_pregap = 0ULL;
@@ -836,7 +824,6 @@ cdi_load_cue(cd_img_t *cdi, const char *cuefile)
int can_add_track = 0;
FILE *fp;
char buf[MAX_LINE_LENGTH];
char ansi[MAX_FILENAME_LENGTH];
char *line;
char *command;
char *type;
@@ -877,7 +864,7 @@ cdi_load_cue(cd_img_t *cdi, const char *cuefile)
}
}
success = cdi_cue_get_keyword(&command, &line);
(void) cdi_cue_get_keyword(&command, &line);
if (!strcmp(command, "TRACK")) {
if (can_add_track)
@@ -931,6 +918,7 @@ cdi_load_cue(cd_img_t *cdi, const char *cuefile)
trk.attr = DATA_TRACK;
trk.mode2 = 1;
} else if (!strcmp(type, "MODE2/2336")) {
trk.form = 1;
trk.sector_size = 2336;
trk.attr = DATA_TRACK;
trk.mode2 = 1;
@@ -980,6 +968,9 @@ cdi_load_cue(cd_img_t *cdi, const char *cuefile)
break;
}
} else if (!strcmp(command, "FILE")) {
char filename[MAX_FILENAME_LENGTH];
char ansi[MAX_FILENAME_LENGTH];
if (can_add_track)
success = cdi_add_track(cdi, &trk, &shift, prestart, &total_pregap, cur_pregap);
else
@@ -1002,7 +993,6 @@ cdi_load_cue(cd_img_t *cdi, const char *cuefile)
error = 1;
if (!strcmp(type, "BINARY")) {
memset(temp, 0, MAX_FILENAME_LENGTH * sizeof(char));
path_append_filename(filename, pathname, ansi);
trk.file = track_file_init(filename, &error);
}

View File

@@ -46,28 +46,35 @@
# define S_ISDIR(m) (((m) &S_IFMT) == S_IFDIR)
#endif
#define VISO_SKIP(p, n) \
{ \
memset(p, 0x00, n); \
p += n; \
#ifdef _WIN32
# define stat _stat64
typedef struct __stat64 stat_t;
#else
typedef struct stat stat_t;
#endif
#define VISO_SKIP(p, n) \
{ \
memset((p), 0x00, (n)); \
(p) += (n); \
}
#define VISO_TIME_VALID(t) ((t) > 0)
/* ISO 9660 defines "both endian" data formats, which
are stored as little endian followed by big endian. */
#define VISO_LBE_16(p, x) \
{ \
*((uint16_t *) p) = cpu_to_le16(x); \
p += 2; \
*((uint16_t *) p) = cpu_to_be16(x); \
p += 2; \
#define VISO_LBE_16(p, x) \
{ \
*((uint16_t *) (p)) = cpu_to_le16((x)); \
(p) += 2; \
*((uint16_t *) (p)) = cpu_to_be16((x)); \
(p) += 2; \
}
#define VISO_LBE_32(p, x) \
{ \
*((uint32_t *) p) = cpu_to_le32(x); \
p += 4; \
*((uint32_t *) p) = cpu_to_be32(x); \
p += 4; \
#define VISO_LBE_32(p, x) \
{ \
*((uint32_t *) (p)) = cpu_to_le32((x)); \
(p) += 4; \
*((uint32_t *) (p)) = cpu_to_be32((x)); \
(p) += 4; \
}
#define VISO_SECTOR_SIZE COOKED_SECTOR_SIZE
@@ -106,7 +113,7 @@ typedef struct _viso_entry_ {
};
uint16_t pt_idx;
struct stat stats;
stat_t stats;
struct _viso_entry_ *parent, *next, *next_dir, *first_child;
@@ -496,10 +503,6 @@ viso_fill_dir_record(uint8_t *data, viso_entry_t *entry, viso_t *viso, int type)
*p++ = 0; /* extended attribute length */
VISO_SKIP(p, 8); /* sector offset */
VISO_LBE_32(p, entry->stats.st_size); /* size (filled in later if this is a directory) */
#ifdef _WIN32
if (entry->stats.st_mtime < 0)
pclog("VISO: Warning: Windows returned st_mtime %lld on file [%s]\n", (long long) entry->stats.st_mtime, entry->path);
#endif
p += viso_fill_time(p, entry->stats.st_mtime, viso->format, 0); /* time */
*p++ = S_ISDIR(entry->stats.st_mode) ? 0x02 : 0x00; /* flags */
@@ -671,9 +674,9 @@ viso_read(void *priv, uint8_t *buffer, uint64_t seek, size_t count)
/* Handle reads in a sector by sector basis. */
while (count > 0) {
/* Determine the current sector, offset and remainder. */
uint32_t sector = seek / viso->sector_size;
uint32_t sector_offset = seek % viso->sector_size;
uint32_t sector_remain = MIN(count, viso->sector_size - sector_offset);
size_t sector = seek / viso->sector_size;
size_t sector_offset = seek % viso->sector_size;
size_t sector_remain = MIN(count, viso->sector_size - sector_offset);
/* Handle sector. */
if (sector < viso->metadata_sectors) {
@@ -830,7 +833,7 @@ viso_init(const char *dirname, int *error)
strcpy(dir->path, dirname);
if (stat(dirname, &dir->stats) != 0) {
/* Use a blank structure if stat failed. */
memset(&dir->stats, 0x00, sizeof(struct stat));
memset(&dir->stats, 0x00, sizeof(stat_t));
}
if (!S_ISDIR(dir->stats.st_mode)) /* root is not a directory */
goto end;
@@ -879,7 +882,7 @@ viso_init(const char *dirname, int *error)
/* Stat the current directory or parent directory. */
if (stat(children_count ? dir->parent->path : dir->path, &entry->stats) != 0) {
/* Use a blank structure if stat failed. */
memset(&entry->stats, 0x00, sizeof(struct stat));
memset(&entry->stats, 0x00, sizeof(stat_t));
}
/* Set basename. */
@@ -909,7 +912,7 @@ viso_init(const char *dirname, int *error)
/* Stat this child. */
if (stat(entry->path, &entry->stats) != 0) {
/* Use a blank structure if stat failed. */
memset(&entry->stats, 0x00, sizeof(struct stat));
memset(&entry->stats, 0x00, sizeof(stat_t));
}
/* Handle file size and El Torito boot code. */
@@ -1432,7 +1435,7 @@ next_entry:
/* Allocate entry map for sector->file lookups. */
size_t orig_sector_size = viso->sector_size;
while (1) {
cdrom_image_viso_log("VISO: Allocating entry map for %d %d-byte sectors\n", viso->entry_map_size, viso->sector_size);
cdrom_image_viso_log("VISO: Allocating entry map for %zu %zu-byte sectors\n", viso->entry_map_size, viso->sector_size);
viso->entry_map = (viso_entry_t **) calloc(viso->entry_map_size, sizeof(viso_entry_t *));
if (viso->entry_map) {
/* Successfully allocated. */
@@ -1444,7 +1447,7 @@ next_entry:
/* If we don't have enough memory, double the sector size. */
viso->sector_size *= 2;
if (viso->sector_size == 0) /* give up if sectors become too large */
if ((viso->sector_size < VISO_SECTOR_SIZE) || (viso->sector_size > (1 << 30))) /* give up if sectors become too large */
goto end;
/* Go through files, recalculating the entry map size. */
@@ -1515,10 +1518,10 @@ next_entry:
entry->data_offset = ((uint64_t) viso->all_sectors) * viso->sector_size;
/* Determine how many sectors this file will take. */
uint32_t size = entry->stats.st_size / viso->sector_size;
size_t size = entry->stats.st_size / viso->sector_size;
if (entry->stats.st_size % viso->sector_size)
size++; /* round up to the next sector */
cdrom_image_viso_log("[%08X] %s => %" PRIu32 " + %" PRIu32 " sectors\n", entry, entry->path, viso->all_sectors, size);
cdrom_image_viso_log("[%08X] %s => %zu + %zu sectors\n", entry, entry->path, viso->all_sectors, size);
/* Allocate sectors to this file. */
viso->all_sectors += size;
@@ -1537,13 +1540,13 @@ next_entry:
viso_pwrite(data, viso->vol_size_offsets[i], 8, 1, viso->tf.fp);
/* Metadata processing is finished, read it back to memory. */
cdrom_image_viso_log("VISO: Reading back %d %d-byte sectors of metadata\n", viso->metadata_sectors, viso->sector_size);
cdrom_image_viso_log("VISO: Reading back %zu %zu-byte sectors of metadata\n", viso->metadata_sectors, viso->sector_size);
viso->metadata = (uint8_t *) calloc(viso->metadata_sectors, viso->sector_size);
if (!viso->metadata)
goto end;
fseeko64(viso->tf.fp, 0, SEEK_SET);
uint64_t metadata_size = viso->metadata_sectors * viso->sector_size;
uint64_t metadata_remain = metadata_size;
size_t metadata_size = viso->metadata_sectors * viso->sector_size;
size_t metadata_remain = metadata_size;
while (metadata_remain > 0)
metadata_remain -= fread(viso->metadata + (metadata_size - metadata_remain), 1, MIN(metadata_remain, viso->sector_size), viso->tf.fp);

278
src/cdrom/cdrom_ioctl.c Normal file
View File

@@ -0,0 +1,278 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* 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 passthrough support.
*
*
*
* Authors: TheCollector1995, <mariogplayer@gmail.com>,
* Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2023 TheCollector1995.
* Copyright 2023 Miran Grca.
*/
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/config.h>
#include <86box/path.h>
#include <86box/plat.h>
#include <86box/plat_cdrom.h>
#include <86box/scsi_device.h>
#include <86box/cdrom.h>
#ifdef ENABLE_CDROM_IOCTL_LOG
int cdrom_ioctl_do_log = ENABLE_CDROM_IOCTL_LOG;
void
cdrom_ioctl_log(const char *fmt, ...)
{
va_list ap;
if (cdrom_ioctl_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define cdrom_ioctl_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
ioctl_get_tracks(UNUSED(cdrom_t *dev), int *first, int *last)
{
TMSF tmsf;
plat_cdrom_get_audio_tracks(first, last, &tmsf);
}
static void
ioctl_get_track_info(UNUSED(cdrom_t *dev), uint32_t track, int end, track_info_t *ti)
{
TMSF tmsf;
plat_cdrom_get_audio_track_info(end, track, &ti->number, &tmsf, &ti->attr);
ti->m = tmsf.min;
ti->s = tmsf.sec;
ti->f = tmsf.fr;
}
static void
ioctl_get_subchannel(UNUSED(cdrom_t *dev), uint32_t lba, subchannel_t *subc)
{
TMSF rel_pos;
TMSF abs_pos;
if ((dev->cd_status == CD_STATUS_PLAYING) || (dev->cd_status == CD_STATUS_PAUSED)) {
const uint32_t trk = plat_cdrom_get_track_start(lba, &subc->attr, &subc->track);
FRAMES_TO_MSF(lba + 150, &abs_pos.min, &abs_pos.sec, &abs_pos.fr);
/* Absolute position should be adjusted by 150, not the relative ones. */
FRAMES_TO_MSF(lba - trk, &rel_pos.min, &rel_pos.sec, &rel_pos.fr);
subc->index = 1;
} else
plat_cdrom_get_audio_sub(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;
cdrom_ioctl_log("ioctl_get_subchannel(): %02X, %02X, %02i, %02i:%02i:%02i, %02i:%02i:%02i\n",
subc->attr, subc->track, subc->index, subc->abs_m, subc->abs_s, subc->abs_f, subc->rel_m, subc->rel_s, subc->rel_f);
}
static int
ioctl_get_capacity(UNUSED(cdrom_t *dev))
{
int ret;
ret = plat_cdrom_get_last_block();
cdrom_ioctl_log("GetCapacity=%x.\n", ret);
return ret;
}
static int
ioctl_is_track_audio(cdrom_t *dev, uint32_t pos, int ismsf)
{
int m;
int s;
int f;
if (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. */
return plat_cdrom_is_track_audio(pos);
}
static int
ioctl_is_track_pre(UNUSED(cdrom_t *dev), uint32_t lba)
{
return plat_cdrom_is_track_pre(lba);
}
static int
ioctl_sector_size(UNUSED(cdrom_t *dev), uint32_t lba)
{
cdrom_ioctl_log("LBA=%x.\n", lba);
return plat_cdrom_get_sector_size(lba);
}
static int
ioctl_read_sector(UNUSED(cdrom_t *dev), int type, uint8_t *b, uint32_t lba)
{
switch (type) {
case CD_READ_DATA:
cdrom_ioctl_log("cdrom_ioctl_read_sector(): Data.\n");
return plat_cdrom_read_sector(b, 0, lba);
case CD_READ_AUDIO:
cdrom_ioctl_log("cdrom_ioctl_read_sector(): Audio.\n");
return plat_cdrom_read_sector(b, 1, lba);
case CD_READ_RAW:
cdrom_ioctl_log("cdrom_ioctl_read_sector(): Raw.\n");
return plat_cdrom_read_sector(b, 1, lba);
default:
cdrom_ioctl_log("cdrom_ioctl_read_sector(): Unknown CD read type.\n");
break;
}
return 0;
}
static int
ioctl_track_type(cdrom_t *dev, uint32_t lba)
{
int ret = 0;
if (ioctl_is_track_audio(dev, lba, 0))
ret = CD_TRACK_AUDIO;
cdrom_ioctl_log("cdrom_ioctl_track_type(): %i\n", ret);
return ret;
}
static int
ioctl_ext_medium_changed(cdrom_t *dev)
{
int ret;
if ((dev->cd_status == CD_STATUS_PLAYING) || (dev->cd_status == CD_STATUS_PAUSED))
ret = 0;
else
ret = plat_cdrom_ext_medium_changed();
if (ret == 1) {
dev->cd_status = CD_STATUS_STOPPED;
dev->cdrom_capacity = ioctl_get_capacity(dev);
} else if (ret == -1)
dev->cd_status = CD_STATUS_EMPTY;
return ret;
}
static void
ioctl_exit(cdrom_t *dev)
{
cdrom_ioctl_log("CDROM: ioctl_exit(%s)\n", dev->image_path);
dev->cd_status = CD_STATUS_EMPTY;
plat_cdrom_close();
dev->ops = NULL;
}
static const cdrom_ops_t cdrom_ioctl_ops = {
ioctl_get_tracks,
ioctl_get_track_info,
ioctl_get_subchannel,
ioctl_is_track_pre,
ioctl_sector_size,
ioctl_read_sector,
ioctl_track_type,
ioctl_ext_medium_changed,
ioctl_exit
};
static int
cdrom_ioctl_open_abort(cdrom_t *dev)
{
cdrom_ioctl_close(dev);
dev->ops = NULL;
dev->image_path[0] = 0;
return 1;
}
int
cdrom_ioctl_open(cdrom_t *dev, const char *drv)
{
const char *actual_drv = &(drv[8]);
/* Make sure to not STRCPY if the two are pointing
at the same place. */
if (drv != dev->image_path)
strcpy(dev->image_path, drv);
/* Open the image. */
if (strstr(drv, "ioctl://") != drv)
return cdrom_ioctl_open_abort(dev);
cdrom_ioctl_log("actual_drv = %s\n", actual_drv);
int i = plat_cdrom_set_drive(actual_drv);
if (!i)
return cdrom_ioctl_open_abort(dev);
/* All good, reset state. */
dev->cd_status = CD_STATUS_STOPPED;
dev->is_dir = 0;
dev->seek_pos = 0;
dev->cd_buflen = 0;
dev->cdrom_capacity = ioctl_get_capacity(dev);
cdrom_ioctl_log("CD-ROM capacity: %i sectors (%" PRIi64 " bytes)\n",
dev->cdrom_capacity, ((uint64_t) dev->cdrom_capacity) << 11ULL);
/* Attach this handler to the drive. */
dev->ops = &cdrom_ioctl_ops;
return 0;
}
void
cdrom_ioctl_close(cdrom_t *dev)
{
cdrom_ioctl_log("CDROM: ioctl_close(%s)\n", dev->image_path);
if (dev && dev->ops && dev->ops->exit)
dev->ops->exit(dev);
}

View File

@@ -147,14 +147,18 @@ mitsumi_cdrom_log(const char *fmt, ...)
# define mitsumi_cdrom_log(fmt, ...)
#endif
static int
mitsumi_cdrom_is_ready(const cdrom_t *dev)
{
return (dev->image_path[0] != 0x00);
}
static void
mitsumi_cdrom_reset(mcd_t *dev)
{
cdrom_t cdrom;
cdrom.host_drive = 0;
dev->stat = cdrom.host_drive ? (STAT_READY | STAT_CHANGE) : 0;
dev->stat = mitsumi_cdrom_is_ready(&cdrom) ? (STAT_READY | STAT_CHANGE) : 0;
dev->cmdrd_count = 0;
dev->cmdbuf_count = 0;
dev->buf_count = 0;
@@ -344,18 +348,18 @@ mitsumi_cdrom_out(uint16_t port, uint8_t val, void *priv)
break;
}
if (!dev->cmdrd_count)
dev->stat = cdrom.host_drive ? (STAT_READY | (dev->change ? STAT_CHANGE : 0)) : 0;
dev->stat = mitsumi_cdrom_is_ready(&cdrom) ? (STAT_READY | (dev->change ? STAT_CHANGE : 0)) : 0;
return;
}
dev->cmd = val;
dev->cmdbuf_idx = 0;
dev->cmdrd_count = 0;
dev->cmdbuf_count = 1;
dev->cmdbuf[0] = cdrom.host_drive ? (STAT_READY | (dev->change ? STAT_CHANGE : 0)) : 0;
dev->cmdbuf[0] = mitsumi_cdrom_is_ready(&cdrom) ? (STAT_READY | (dev->change ? STAT_CHANGE : 0)) : 0;
dev->data = 0;
switch (val) {
case CMD_GET_INFO:
if (cdrom.host_drive) {
if (mitsumi_cdrom_is_ready(&cdrom)) {
cdrom_get_track_buffer(&cdrom, &(dev->cmdbuf[1]));
dev->cmdbuf_count = 10;
dev->readcount = 0;
@@ -365,7 +369,7 @@ mitsumi_cdrom_out(uint16_t port, uint8_t val, void *priv)
}
break;
case CMD_GET_Q:
if (cdrom.host_drive) {
if (mitsumi_cdrom_is_ready(&cdrom)) {
cdrom_get_q(&cdrom, &(dev->cmdbuf[1]), &dev->cur_toc_track, dev->mode & MODE_GET_TOC);
dev->cmdbuf_count = 11;
dev->readcount = 0;
@@ -391,7 +395,7 @@ mitsumi_cdrom_out(uint16_t port, uint8_t val, void *priv)
break;
case CMD_READ1X:
case CMD_READ2X:
if (cdrom.host_drive) {
if (mitsumi_cdrom_is_ready(&cdrom)) {
dev->readcount = 0;
dev->drvmode = (val == CMD_READ1X) ? DRV_MODE_CDDA : DRV_MODE_READ;
dev->cmdrd_count = 6;

View File

@@ -14,13 +14,15 @@
#
add_library(chipset OBJECT 82c100.c acc2168.c cs8230.c ali1429.c ali1435.c ali1489.c
ali1531.c ali1541.c ali1543.c ali1621.c ali6117.c headland.c ims8848.c intel_82335.c
ali1531.c ali1541.c ali1543.c ali1621.c ali6117.c ali1409.c headland.c ims8848.c intel_82335.c
compaq_386.c contaq_82c59x.c cs4031.c intel_420ex.c intel_4x0.c intel_i450kx.c
intel_sio.c intel_piix.c ../ioapic.c neat.c opti283.c opti291.c opti391.c opti495.c
opti602.c opti822.c opti895.c opti5x7.c scamp.c scat.c sis_85c310.c sis_85c4xx.c
sis_85c496.c sis_85c50x.c sis_5511.c sis_5571.c via_vt82c49x.c via_vt82c505.c
sis_85c310.c sis_85c4xx.c sis_85c496.c sis_85c50x.c gc100.c stpc.c umc_8886.c
umc_hb4.c via_apollo.c via_pipc.c vl82c480.c wd76c10.c)
sis_85c496.c sis_85c50x.c sis_5511.c sis_5571.c sis_5581.c sis_5591.c sis_5600.c
sis_5511_h2p.c sis_5571_h2p.c sis_5581_h2p.c sis_5591_h2p.c sis_5600_h2p.c
sis_5513_p2i.c sis_5513_ide.c sis_5572_usb.c sis_5595_pmu.c sis_55xx.c via_vt82c49x.c
via_vt82c505.c sis_85c310.c sis_85c4xx.c sis_85c496.c sis_85c50x.c gc100.c stpc.c
umc_8886.c umc_hb4.c umc_8890.c via_apollo.c via_pipc.c vl82c480.c wd76c10.c)
if(OLIVETTI)
target_sources(chipset PRIVATE olivetti_eva.c)

199
src/chipset/ali1409.c Normal file
View File

@@ -0,0 +1,199 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* 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 M1409 chipset.
*
* Note: This chipset has no datasheet, everything were done via
* reverse engineering.
*
*
*
* Authors: Jose Phillips, <jose@latinol.com>
* Sarah Walker, <https://pcem-emulator.co.uk/>
*
* Copyright 2024 Jose Phillips.
* Copyright 2008-2018 Sarah Walker.
*/
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include "cpu.h"
#include <86box/timer.h>
#include <86box/io.h>
#include <86box/device.h>
#include <86box/apm.h>
#include <86box/mem.h>
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/smram.h>
#include <86box/chipset.h>
#ifdef ENABLE_ALI1409_LOG
int ali1409_do_log = ENABLE_ALI1409_LOG;
static void
ali1409_log(const char *fmt, ...)
{
va_list ap;
if (ali1409_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define ali1409_log(fmt, ...)
#endif
typedef struct ali_1409_t {
uint8_t is_g;
uint8_t index;
uint8_t cfg_locked;
uint8_t reg_57h;
uint8_t regs[256];
uint8_t last_reg;
} ali1409_t;
static void
ali1409_write(uint16_t addr, uint8_t val, void *priv)
{
ali1409_t *dev = (ali1409_t *) priv;
ali1409_log ("INPUT:addr %02x ,Value %02x \n" , addr , val);
if (addr & 1) {
if (dev->cfg_locked) {
if (dev->last_reg == 0x14 && val == 0x09)
dev->cfg_locked = 0;
dev->last_reg = val;
return;
}
if (dev->index == 0xff && val == 0xff)
dev->cfg_locked = 1;
else {
ali1409_log("Write reg %02x %02x %08x\n", dev->index, val, cs);
dev->regs[dev->index] = val;
switch (dev->index) {
case 0xa:
switch ((val >> 4) & 3) {
case 0:
mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
break;
case 1:
mem_set_mem_state(0xe0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL);
break;
case 2:
mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL);
break;
case 3:
mem_set_mem_state(0xe0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
break;
}
break;
case 0xb:
switch ((val >> 4) & 3) {
case 0:
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY);
break;
case 1:
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTANY);
break;
case 2:
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTANY| MEM_WRITE_INTERNAL);
break;
case 3:
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
break;
}
break;
}
}
} else
dev->index = val;
}
static uint8_t
ali1409_read(uint16_t addr, void *priv)
{
ali1409_log ("reading at %02X\n",addr);
const ali1409_t *dev = (ali1409_t *) priv;
uint8_t ret = 0xff;
if (dev->cfg_locked)
ret = 0xff;
if (addr & 1) {
if ((dev->index >= 0xc0 || dev->index == 0x20) && cpu_iscyrix)
ret = 0xff;
ret = dev->regs[dev->index];
} else
ret = dev->index;
return ret;
}
static void
ali1409_close(void *priv)
{
ali1409_t *dev = (ali1409_t *) priv;
free(dev);
}
static void *
ali1409_init(const device_t *info)
{
ali1409_t *dev = (ali1409_t *) malloc(sizeof(ali1409_t));
memset(dev, 0, sizeof(ali1409_t));
dev->cfg_locked = 1;
/* M1409 Ports:
22h Index Port
23h Data Port
*/
ali1409_log ("Bus speed: %i",cpu_busspeed);
io_sethandler(0x0022, 0x0002, ali1409_read, NULL, NULL, ali1409_write, NULL, NULL, dev);
io_sethandler(0x037f, 0x0001, ali1409_read, NULL, NULL, ali1409_write, NULL, NULL, dev);
io_sethandler(0x03f3, 0x0001, ali1409_read, NULL, NULL, ali1409_write, NULL, NULL, dev);
return dev;
}
const device_t ali1409_device = {
.name = "ALi M1409",
.internal_name = "ali1409",
.flags = 0,
.local = 0,
.init = ali1409_init,
.close = ali1409_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -197,6 +197,7 @@ ali1533_write(int func, int addr, uint8_t val, void *priv)
case 0x44: /* Set IRQ Line for Primary IDE if it's on native mode */
dev->pci_conf[addr] = val & 0xdf;
soft_reset_pci = !!(val & 0x80);
pci_set_mirq_level(PCI_MIRQ0, !(val & 0x10));
pci_set_mirq_level(PCI_MIRQ2, !(val & 0x10));
ali1543_log("INTAJ = IRQ %i\n", ali1533_irq_routing[val & 0x0f]);
pci_set_mirq_routing(PCI_MIRQ0, ali1533_irq_routing[val & 0x0f]);
@@ -412,11 +413,13 @@ ali1533_write(int func, int addr, uint8_t val, void *priv)
case 0x74: /* USB IRQ Routing - we cheat and use MIRQ4 */
dev->pci_conf[addr] = val & 0xdf;
/* TODO: MIRQ level/edge control - if bit 4 = 1, it's level */
pci_set_mirq_level(PCI_MIRQ4, !(val & 0x10));
pci_set_mirq_routing(PCI_MIRQ4, ali1533_irq_routing[val & 0x0f]);
break;
case 0x75: /* Set IRQ Line for Secondary IDE if it's on native mode */
dev->pci_conf[addr] = val & 0x1f;
pci_set_mirq_level(PCI_MIRQ1, !(val & 0x10));
pci_set_mirq_level(PCI_MIRQ3, !(val & 0x10));
ali1543_log("INTBJ = IRQ %i\n", ali1533_irq_routing[val & 0x0f]);
pci_set_mirq_routing(PCI_MIRQ1, ali1533_irq_routing[val & 0x0f]);
@@ -704,7 +707,7 @@ ali5229_chip_reset(ali1543_t *dev)
ali5229_write(0, 0x09, 0xfa, dev);
ali5229_write(0, 0x52, 0x00, dev);
ali5229_write(0, 0x50, 0x00, dev);
ali5229_write(0, 0x50, 0x02, dev);
sff_set_slot(dev->ide_controller[0], dev->ide_slot);
sff_set_slot(dev->ide_controller[1], dev->ide_slot);
@@ -717,7 +720,7 @@ static void
ali5229_write(int func, int addr, uint8_t val, void *priv)
{
ali1543_t *dev = (ali1543_t *) priv;
ali1543_log("M5229: dev->ide_conf[%02x] = %02x\n", addr, val);
ali1543_log("M5229: [W] dev->ide_conf[%02x] = %02x\n", addr, val);
if (func > 0)
return;
@@ -756,6 +759,10 @@ ali5229_write(int func, int addr, uint8_t val, void *priv)
ali5229_ide_irq_handler(dev);
break;
case 0x0d: /* LT - Latency Timer */
dev->ide_conf[addr] = val;
break;
/* Primary Base Address */
case 0x10:
case 0x11:
@@ -776,9 +783,9 @@ ali5229_write(int func, int addr, uint8_t val, void *priv)
/* Datasheet erratum: the PCI BAR's actually have different sizes. */
if (addr == 0x20)
dev->ide_conf[addr] = (val & 0xe0) | 0x01;
else if ((addr & 0x43) == 0x00)
else if ((addr & 0x07) == 0x00)
dev->ide_conf[addr] = (val & 0xf8) | 0x01;
else if ((addr & 0x43) == 0x40)
else if ((addr & 0x07) == 0x04)
dev->ide_conf[addr] = (val & 0xfc) | 0x01;
else
dev->ide_conf[addr] = val;
@@ -887,13 +894,15 @@ ali5229_read(int func, int addr, void *priv)
if (dev->ide_dev_enable && (func == 0)) {
ret = dev->ide_conf[addr];
if ((addr == 0x09) && !(dev->ide_conf[0x50] & 0x02))
ret &= 0x0f;
ret = (ret & 0x0f) | 0x80;
else if (addr == 0x50)
ret = (ret & 0xfe) | (dev->ide_dev_enable ? 0x01 : 0x00);
else if (addr == 0x75)
ret = ide_read_ali_75();
else if (addr == 0x76)
ret = ide_read_ali_76();
ali1543_log("M5229: [R] dev->ide_conf[%02x] = %02x\n", addr, ret);
}
return ret;

View File

@@ -471,7 +471,8 @@ ali6117_init(const device_t *info)
dev->local = info->local;
device_add(&ide_isa_device);
if (!(dev->local & 0x08))
device_add(&ide_isa_device);
ali6117_setup(dev);

View File

@@ -493,16 +493,40 @@ i4x0_write(int func, int addr, uint8_t val, void *priv)
case 0x52: /* Cache Control Register */
switch (dev->type) {
default:
/*
420TX/ZX:
Bit 7-6: 0, 0 = 64 kB,
0, 1 = 128 kB,
1, 0 = 256 kB,
1, 1 = 512 kB.
Bit 5: 1 = L2 cache present, 0 = L2 cache absent.
Bit 1: 1 = Write back cache, 0 = write through cache.
Bit 0: 1 = L2 cache enable, 0 = L2 cache disable.
*/
case INTEL_420TX:
case INTEL_420ZX:
case INTEL_430NX:
regs[0x52] = (regs[0x52] & 0xe0) | (val & 0x1f);
cpu_cache_ext_enabled = val & 0x01;
cpu_update_waitstates();
break;
case INTEL_430LX:
regs[0x52] = (regs[0x52] & 0xe0) | (val & 0x1b);
cpu_cache_ext_enabled = val & 0x01;
cpu_update_waitstates();
break;
case INTEL_430FX:
case INTEL_430VX:
case INTEL_430TX:
regs[0x52] = (val & 0xfb);
regs[0x52] = (regs[0x52] & 0x04) | (val & 0xfb);
cpu_cache_ext_enabled = ((val & 0x03) == 0x01);
cpu_update_waitstates();
break;
case INTEL_430NX:
case INTEL_430HX:
regs[0x52] = val;
cpu_cache_ext_enabled = ((val & 0x03) == 0x01);
cpu_update_waitstates();
break;
case INTEL_440FX:
regs[0x52] = val;
break;
@@ -1630,7 +1654,7 @@ i4x0_init(const device_t *info)
0x00 = None, 0x01 = 64 kB, 0x41 = 128 kB, 0x81 = 256 kB, 0xc1 = 512 kB,
If bit 0 is set, then if bit 2 is also set, the cache is write back,
otherwise it's write through. */
regs[0x52] = 0xc3; /* 512 kB writeback cache */
regs[0x52] = 0xe0; /* 512 kB writeback cache */
regs[0x57] = 0x31;
regs[0x59] = 0x0f;
regs[0x60] = regs[0x61] = regs[0x62] = regs[0x63] = 0x02;

View File

@@ -646,7 +646,8 @@ neat_read(uint16_t port, void *priv)
break;
case 0x23:
ret = dev->regs[dev->indx];
if ((dev->indx >= 0x60) && (dev->indx <= 0x6f))
ret = dev->regs[dev->indx];
break;
default:

View File

@@ -66,15 +66,17 @@ typedef struct ems_page_t {
} ems_page_t;
typedef struct scat_t {
int type;
uint8_t max_reg;
uint8_t reg_2xA;
int indx;
uint8_t regs[256];
uint8_t reg_2xA;
uint8_t regs[256];
uint32_t xms_bound;
int external_is_RAS;
int type;
int indx;
int external_is_RAS;
ems_page_t null_page;
ems_page_t page[32];
@@ -1233,7 +1235,8 @@ scat_in(uint16_t port, void *priv)
break;
default:
ret = dev->regs[dev->indx];
if (dev->indx <= dev->max_reg)
ret = dev->regs[dev->indx];
break;
}
break;
@@ -1393,6 +1396,8 @@ scat_init(const device_t *info)
sx = (dev->type == 32) ? 1 : 0;
dev->max_reg = sx ? 0x64 : 0x4f;
for (uint32_t i = 0; i < sizeof(dev->regs); i++)
dev->regs[i] = 0xff;

View File

@@ -25,9 +25,10 @@
#include <86box/device.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/mem.h>
#include <86box/nvr.h>
#include <86box/apm.h>
#include <86box/acpi.h>
#include <86box/hdd.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
@@ -41,7 +42,7 @@
#include <86box/port_92.h>
#include <86box/smram.h>
#include <86box/spd.h>
#include <86box/sis_55xx.h>
#include <86box/chipset.h>
#ifdef ENABLE_SIS_5511_LOG
@@ -63,573 +64,53 @@ sis_5511_log(const char *fmt, ...)
#endif
typedef struct sis_5511_t {
uint8_t index;
uint8_t nb_slot;
uint8_t sb_slot;
uint8_t pad;
uint8_t nb_slot;
uint8_t sb_slot;
uint8_t regs[16];
uint8_t states[7];
void *h2p;
uint8_t slic_regs[4096];
void *p2i;
void *ide;
uint8_t pci_conf[256];
uint8_t pci_conf_sb[2][256];
mem_mapping_t slic_mapping;
sff8038i_t *bm[2];
smram_t *smram;
port_92_t *port_92;
void *pit;
nvr_t *nvr;
uint8_t (*pit_read_reg)(void *priv, uint8_t reg);
sis_55xx_common_t *sis;
} sis_5511_t;
static void
sis_5511_shadow_recalc(sis_5511_t *dev)
sis_5511_write(int func, int addr, uint8_t val, void *priv)
{
int state;
uint32_t base;
for (uint8_t i = 0x80; i <= 0x86; i++) {
if (i == 0x86) {
if ((dev->states[i & 0x0f] ^ dev->pci_conf[i]) & 0xa0) {
state = (dev->pci_conf[i] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
state |= (dev->pci_conf[i] & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
mem_set_mem_state_both(0xf0000, 0x10000, state);
sis_5511_log("000F0000-000FFFFF\n");
}
} else {
base = ((i & 0x07) << 15) + 0xc0000;
if ((dev->states[i & 0x0f] ^ dev->pci_conf[i]) & 0xa0) {
state = (dev->pci_conf[i] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
state |= (dev->pci_conf[i] & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
mem_set_mem_state_both(base, 0x4000, state);
sis_5511_log("%08X-%08X\n", base, base + 0x3fff);
}
if ((dev->states[i & 0x0f] ^ dev->pci_conf[i]) & 0x0a) {
state = (dev->pci_conf[i] & 0x08) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
state |= (dev->pci_conf[i] & 0x02) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
mem_set_mem_state_both(base + 0x4000, 0x4000, state);
sis_5511_log("%08X-%08X\n", base + 0x4000, base + 0x7fff);
}
}
dev->states[i & 0x0f] = dev->pci_conf[i];
}
flushmmucache_nopc();
}
static void
sis_5511_smram_recalc(sis_5511_t *dev)
{
smram_disable_all();
switch (dev->pci_conf[0x65] >> 6) {
case 0:
smram_enable(dev->smram, 0x000e0000, 0x000e0000, 0x8000, dev->pci_conf[0x65] & 0x10, 1);
break;
case 1:
smram_enable(dev->smram, 0x000e0000, 0x000a0000, 0x8000, dev->pci_conf[0x65] & 0x10, 1);
break;
case 2:
smram_enable(dev->smram, 0x000e0000, 0x000b0000, 0x8000, dev->pci_conf[0x65] & 0x10, 1);
break;
default:
break;
}
flushmmucache();
}
static void
sis_5511_write(UNUSED(int func), int addr, uint8_t val, void *priv)
{
sis_5511_t *dev = (sis_5511_t *) priv;
const sis_5511_t *dev = (sis_5511_t *) priv;
sis_5511_log("SiS 5511: [W] dev->pci_conf[%02X] = %02X\n", addr, val);
if (func == 0x00) switch (addr) {
case 0x07: /* Status - High Byte */
dev->pci_conf[addr] &= 0xb0;
break;
case 0x50:
dev->pci_conf[addr] = val;
cpu_cache_ext_enabled = !!(val & 0x40);
cpu_update_waitstates();
break;
case 0x51:
dev->pci_conf[addr] = val & 0xfe;
break;
case 0x52:
dev->pci_conf[addr] = val & 0x3f;
break;
case 0x53:
case 0x54:
dev->pci_conf[addr] = val;
break;
case 0x55:
dev->pci_conf[addr] = val & 0xf8;
break;
case 0x56 ... 0x59:
dev->pci_conf[addr] = val;
break;
case 0x5a:
/* TODO: Fast Gate A20 Emulation and Fast Reset Emulation on the KBC.
The former (bit 7) means the chipset intercepts D1h to 64h and 00h to 60h.
The latter (bit 6) means the chipset intercepts all odd FXh to 64h.
Bit 5 sets fast reset latency. This should be fixed on the other SiS
chipsets as well. */
dev->pci_conf[addr] = val;
break;
case 0x5b:
dev->pci_conf[addr] = val & 0xf7;
break;
case 0x5c:
dev->pci_conf[addr] = val & 0xcf;
break;
case 0x5d:
dev->pci_conf[addr] = val;
break;
case 0x5e:
dev->pci_conf[addr] = val & 0xfe;
break;
case 0x5f:
dev->pci_conf[addr] = val & 0xfe;
break;
case 0x60:
dev->pci_conf[addr] = val & 0x3e;
if ((dev->pci_conf[0x68] & 1) && (val & 2)) {
smi_raise();
dev->pci_conf[0x69] |= 1;
}
break;
case 0x61 ... 0x64:
dev->pci_conf[addr] = val;
break;
case 0x65:
dev->pci_conf[addr] = val & 0xd0;
sis_5511_smram_recalc(dev);
break;
case 0x66:
dev->pci_conf[addr] = val & 0x7f;
break;
case 0x67:
case 0x68:
dev->pci_conf[addr] = val;
break;
case 0x69:
dev->pci_conf[addr] &= val;
break;
case 0x6a ... 0x6e:
dev->pci_conf[addr] = val;
break;
case 0x6f:
dev->pci_conf[addr] = val & 0x3f;
break;
case 0x70: /* DRAM Bank Register 0-0 */
case 0x72: /* DRAM Bank Register 0-1 */
case 0x74: /* DRAM Bank Register 1-0 */
case 0x76: /* DRAM Bank Register 1-1 */
case 0x78: /* DRAM Bank Register 2-0 */
case 0x7a: /* DRAM Bank Register 2-1 */
case 0x7c: /* DRAM Bank Register 3-0 */
case 0x7e: /* DRAM Bank Register 3-1 */
spd_write_drbs(dev->pci_conf, 0x70, 0x7e, 0x82);
break;
case 0x71: /* DRAM Bank Register 0-0 */
dev->pci_conf[addr] = val;
break;
case 0x75: /* DRAM Bank Register 1-0 */
case 0x79: /* DRAM Bank Register 2-0 */
case 0x7d: /* DRAM Bank Register 3-0 */
dev->pci_conf[addr] = val & 0x7f;
break;
case 0x73: /* DRAM Bank Register 0-1 */
case 0x77: /* DRAM Bank Register 1-1 */
case 0x7b: /* DRAM Bank Register 2-1 */
case 0x7f: /* DRAM Bank Register 3-1 */
dev->pci_conf[addr] = val & 0x83;
break;
case 0x80 ... 0x85:
dev->pci_conf[addr] = val & 0xee;
sis_5511_shadow_recalc(dev);
break;
case 0x86:
dev->pci_conf[addr] = val & 0xe8;
sis_5511_shadow_recalc(dev);
break;
case 0x90 ... 0x93: /* 5512 General Purpose Register Index */
dev->pci_conf[addr] = val;
break;
default:
break;
}
}
static void
sis_5511_slic_write(uint32_t addr, uint8_t val, void *priv)
{
sis_5511_t *dev = (sis_5511_t *) priv;
addr &= 0x00000fff;
switch (addr) {
case 0x00000000:
case 0x00000008: /* 0x00000008 is a SiS 5512 register. */
dev->slic_regs[addr] = val;
break;
case 0x00000010:
case 0x00000018:
case 0x00000028:
case 0x00000038:
dev->slic_regs[addr] = val & 0x01;
break;
case 0x00000030:
dev->slic_regs[addr] = val & 0x0f;
mem_mapping_set_addr(&dev->slic_mapping,
(((uint32_t) (val & 0x0f)) << 28) | 0x0fc00000, 0x00001000);
break;
}
if (func == 0x00)
sis_5511_host_to_pci_write(addr, val, dev->h2p);
}
static uint8_t
sis_5511_read(UNUSED(int func), int addr, void *priv)
sis_5511_read(int func, int addr, void *priv)
{
const sis_5511_t *dev = (sis_5511_t *) priv;
uint8_t ret = 0xff;
if (func == 0x00)
ret = dev->pci_conf[addr];
ret = sis_5511_host_to_pci_read(addr, dev->h2p);
sis_5511_log("SiS 5511: [R] dev->pci_conf[%02X] = %02X\n", addr, ret);
return ret;
}
static uint8_t
sis_5511_slic_read(uint32_t addr, void *priv)
{
sis_5511_t *dev = (sis_5511_t *) priv;
uint8_t ret = 0xff;
addr &= 0x00000fff;
switch (addr) {
case 0x00000008: /* 0x00000008 is a SiS 5512 register. */
ret = dev->slic_regs[addr];
break;
}
return ret;
}
void
sis_5513_pci_to_isa_write(int addr, uint8_t val, sis_5511_t *dev)
{
sis_5511_log("SiS 5513 P2I: [W] dev->pci_conf_sb[0][%02X] = %02X\n", addr, val);
switch (addr) {
case 0x04: /* Command */
dev->pci_conf_sb[0][addr] = val & 0x0f;
break;
case 0x07: /* Status */
dev->pci_conf_sb[0][addr] = (dev->pci_conf_sb[0][addr] & 0x06) & ~(val & 0x30);
break;
case 0x40: /* BIOS Control Register */
dev->pci_conf_sb[0][addr] = val & 0x3f;
break;
case 0x41: /* INTA# Remapping Control Register */
case 0x42: /* INTB# Remapping Control Register */
case 0x43: /* INTC# Remapping Control Register */
case 0x44: /* INTD# Remapping Control Register */
dev->pci_conf_sb[0][addr] = val & 0x8f;
pci_set_irq_routing(addr & 0x07, (val & 0x80) ? PCI_IRQ_DISABLED : (val & 0x0f));
break;
case 0x48: /* ISA Master/DMA Memory Cycle Control Register 1 */
case 0x49: /* ISA Master/DMA Memory Cycle Control Register 2 */
case 0x4a: /* ISA Master/DMA Memory Cycle Control Register 3 */
case 0x4b: /* ISA Master/DMA Memory Cycle Control Register 4 */
dev->pci_conf_sb[0][addr] = val;
break;
case 0x60: /* MIRQ0 Remapping Control Register */
case 0x61: /* MIRQ1 Remapping Control Register */
sis_5511_log("Set MIRQ routing: MIRQ%i -> %02X\n", addr & 0x01, val);
dev->pci_conf_sb[0][addr] = val & 0xcf;
if (val & 0x80)
pci_set_mirq_routing(PCI_MIRQ0 + (addr & 0x01), PCI_IRQ_DISABLED);
else
pci_set_mirq_routing(PCI_MIRQ0 + (addr & 0x01), val & 0xf);
break;
case 0x62: /* On-board Device DMA Control Register */
dev->pci_conf_sb[0][addr] = val;
break;
case 0x63: /* IDEIRQ Remapping Control Register */
sis_5511_log("Set MIRQ routing: IDEIRQ -> %02X\n", val);
dev->pci_conf_sb[0][addr] = val & 0x8f;
if (val & 0x80)
pci_set_mirq_routing(PCI_MIRQ2, PCI_IRQ_DISABLED);
else
pci_set_mirq_routing(PCI_MIRQ2, val & 0xf);
break;
case 0x64: /* GPIO0 Control Register */
dev->pci_conf_sb[0][addr] = val & 0xef;
break;
case 0x65:
dev->pci_conf_sb[0][addr] = val & 0x80;
break;
case 0x66: /* GPIO0 Output Mode Control Register */
case 0x67: /* GPIO0 Output Mode Control Register */
dev->pci_conf_sb[0][addr] = val;
break;
case 0x6a: /* GPIO Status Register */
dev->pci_conf_sb[0][addr] |= (val & 0x10);
dev->pci_conf_sb[0][addr] &= ~(val & 0x01);
break;
default:
break;
}
}
static void
sis_5513_ide_irq_handler(sis_5511_t *dev)
{
if (dev->pci_conf_sb[1][0x09] & 0x01) {
/* Primary IDE is native. */
sis_5511_log("Primary IDE IRQ mode: Native, Native\n");
sff_set_irq_mode(dev->bm[0], IRQ_MODE_SIS_551X);
} else {
/* Primary IDE is legacy. */
sis_5511_log("Primary IDE IRQ mode: IRQ14, IRQ15\n");
sff_set_irq_mode(dev->bm[0], IRQ_MODE_LEGACY);
}
if (dev->pci_conf_sb[1][0x09] & 0x04) {
/* Secondary IDE is native. */
sis_5511_log("Secondary IDE IRQ mode: Native, Native\n");
sff_set_irq_mode(dev->bm[1], IRQ_MODE_SIS_551X);
} else {
/* Secondary IDE is legacy. */
sis_5511_log("Secondary IDE IRQ mode: IRQ14, IRQ15\n");
sff_set_irq_mode(dev->bm[1], IRQ_MODE_LEGACY);
}
}
static void
sis_5513_ide_handler(sis_5511_t *dev)
{
uint8_t ide_io_on = dev->pci_conf_sb[1][0x04] & 0x01;
uint16_t native_base_pri_addr = (dev->pci_conf_sb[1][0x11] | dev->pci_conf_sb[1][0x10] << 8) & 0xfffe;
uint16_t native_side_pri_addr = (dev->pci_conf_sb[1][0x15] | dev->pci_conf_sb[1][0x14] << 8) & 0xfffe;
uint16_t native_base_sec_addr = (dev->pci_conf_sb[1][0x19] | dev->pci_conf_sb[1][0x18] << 8) & 0xfffe;
uint16_t native_side_sec_addr = (dev->pci_conf_sb[1][0x1c] | dev->pci_conf_sb[1][0x1b] << 8) & 0xfffe;
uint16_t current_pri_base;
uint16_t current_pri_side;
uint16_t current_sec_base;
uint16_t current_sec_side;
/* Primary Channel Programming */
current_pri_base = (!(dev->pci_conf_sb[1][0x09] & 1)) ? 0x01f0 : native_base_pri_addr;
current_pri_side = (!(dev->pci_conf_sb[1][0x09] & 1)) ? 0x03f6 : native_side_pri_addr;
/* Secondary Channel Programming */
current_sec_base = (!(dev->pci_conf_sb[1][0x09] & 4)) ? 0x0170 : native_base_sec_addr;
current_sec_side = (!(dev->pci_conf_sb[1][0x09] & 4)) ? 0x0376 : native_side_sec_addr;
sis_5511_log("sis_5513_ide_handler(): Disabling primary IDE...\n");
ide_pri_disable();
sis_5511_log("sis_5513_ide_handler(): Disabling secondary IDE...\n");
ide_sec_disable();
if (ide_io_on) {
/* Primary Channel Setup */
if (dev->pci_conf_sb[1][0x4a] & 0x02) {
sis_5511_log("sis_5513_ide_handler(): Primary IDE base now %04X...\n", current_pri_base);
ide_set_base(0, current_pri_base);
sis_5511_log("sis_5513_ide_handler(): Primary IDE side now %04X...\n", current_pri_side);
ide_set_side(0, current_pri_side);
sis_5511_log("sis_5513_ide_handler(): Enabling primary IDE...\n");
ide_pri_enable();
sis_5511_log("SiS 5513 PRI: BASE %04x SIDE %04x\n", current_pri_base, current_pri_side);
}
/* Secondary Channel Setup */
if (dev->pci_conf_sb[1][0x4a] & 0x04) {
sis_5511_log("sis_5513_ide_handler(): Secondary IDE base now %04X...\n", current_sec_base);
ide_set_base(1, current_sec_base);
sis_5511_log("sis_5513_ide_handler(): Secondary IDE side now %04X...\n", current_sec_side);
ide_set_side(1, current_sec_side);
sis_5511_log("sis_5513_ide_handler(): Enabling secondary IDE...\n");
ide_sec_enable();
sis_5511_log("SiS 5513: BASE %04x SIDE %04x\n", current_sec_base, current_sec_side);
}
}
sff_bus_master_handler(dev->bm[0], ide_io_on,
((dev->pci_conf_sb[1][0x20] & 0xf0) | (dev->pci_conf_sb[1][0x21] << 8)) + 0);
sff_bus_master_handler(dev->bm[1], ide_io_on,
((dev->pci_conf_sb[1][0x20] & 0xf0) | (dev->pci_conf_sb[1][0x21] << 8)) + 8);
}
void
sis_5513_ide_write(int addr, uint8_t val, sis_5511_t *dev)
{
sis_5511_log("SiS 5513 IDE: [W] dev->pci_conf_sb[1][%02X] = %02X\n", addr, val);
switch (addr) {
case 0x04: /* Command low byte */
dev->pci_conf_sb[1][addr] = val & 0x05;
sis_5513_ide_handler(dev);
break;
case 0x06: /* Status low byte */
dev->pci_conf_sb[1][addr] = val & 0x20;
break;
case 0x07: /* Status high byte */
dev->pci_conf_sb[1][addr] = (dev->pci_conf_sb[1][addr] & 0x06) & ~(val & 0x38);
break;
case 0x09: /* Programming Interface Byte */
dev->pci_conf_sb[1][addr] = (dev->pci_conf_sb[1][addr] & 0x8a) | (val & 0x05);
sis_5513_ide_irq_handler(dev);
sis_5513_ide_handler(dev);
break;
case 0x0d: /* Latency Timer */
dev->pci_conf_sb[1][addr] = val;
break;
/* Primary Base Address */
case 0x10:
case 0x11:
case 0x14:
case 0x15:
fallthrough;
/* Secondary Base Address */
case 0x18:
case 0x19:
case 0x1c:
case 0x1d:
fallthrough;
/* Bus Mastering Base Address */
case 0x20:
case 0x21:
if (addr == 0x20)
dev->pci_conf_sb[1][addr] = (val & 0xe0) | 0x01;
else
dev->pci_conf_sb[1][addr] = val;
sis_5513_ide_handler(dev);
break;
case 0x30: /* Expansion ROM Base Address */
case 0x31: /* Expansion ROM Base Address */
case 0x32: /* Expansion ROM Base Address */
case 0x33: /* Expansion ROM Base Address */
dev->pci_conf_sb[1][addr] = val;
break;
case 0x40: /* IDE Primary Channel/Master Drive Data Recovery Time Control */
case 0x42: /* IDE Primary Channel/Slave Drive Data Recovery Time Control */
case 0x44: /* IDE Secondary Channel/Master Drive Data Recovery Time Control */
case 0x46: /* IDE Secondary Channel/Slave Drive Data Recovery Time Control */
case 0x48: /* IDE Command Recovery Time Control */
dev->pci_conf_sb[1][addr] = val & 0x0f;
break;
case 0x41: /* IDE Primary Channel/Master Drive DataActive Time Control */
case 0x43: /* IDE Primary Channel/Slave Drive Data Active Time Control */
case 0x45: /* IDE Secondary Channel/Master Drive Data Active Time Control */
case 0x47: /* IDE Secondary Channel/Slave Drive Data Active Time Control */
case 0x49: /* IDE Command Active Time Control */
dev->pci_conf_sb[1][addr] = val & 0x07;
break;
case 0x4a: /* IDE General Control Register 0 */
dev->pci_conf_sb[1][addr] = val & 0x9e;
sis_5513_ide_handler(dev);
break;
case 0x4b: /* IDE General Control Register 1 */
dev->pci_conf_sb[1][addr] = val & 0xef;
break;
case 0x4c: /* Prefetch Count of Primary Channel (Low Byte) */
case 0x4d: /* Prefetch Count of Primary Channel (High Byte) */
case 0x4e: /* Prefetch Count of Secondary Channel (Low Byte) */
case 0x4f: /* Prefetch Count of Secondary Channel (High Byte) */
dev->pci_conf_sb[1][addr] = val;
break;
default:
break;
}
}
static void
sis_5513_write(int func, int addr, uint8_t val, void *priv)
{
sis_5511_t *dev = (sis_5511_t *) priv;
const sis_5511_t *dev = (sis_5511_t *) priv;
switch (func) {
default:
break;
case 0:
sis_5513_pci_to_isa_write(addr, val, dev);
break;
case 1:
sis_5513_ide_write(addr, val, dev);
break;
}
sis_5511_log("SiS 5513: [W] dev->pci_conf[%02X] = %02X\n", addr, val);
if (func == 0x00)
sis_5513_pci_to_isa_write(addr, val, dev->p2i);
else if (func == 0x01)
sis_5513_ide_write(addr, val, dev->ide);
}
static uint8_t
@@ -638,281 +119,21 @@ sis_5513_read(int func, int addr, void *priv)
const sis_5511_t *dev = (sis_5511_t *) priv;
uint8_t ret = 0xff;
if (func == 0x00) {
switch (addr) {
default:
ret = dev->pci_conf_sb[func][addr];
break;
case 0x4c ... 0x4f:
ret = pic_read_icw(0, addr & 0x03);
break;
case 0x50 ... 0x53:
ret = pic_read_icw(1, addr & 0x03);
break;
case 0x54 ... 0x55:
ret = pic_read_ocw(0, addr & 0x01);
break;
case 0x56 ... 0x57:
ret = pic_read_ocw(1, addr & 0x01);
break;
case 0x58 ... 0x5f:
ret = dev->pit_read_reg(dev->pit, addr & 0x07);
break;
}
if (func == 0x00)
ret = sis_5513_pci_to_isa_read(addr, dev->p2i);
else if (func == 0x01)
ret = sis_5513_ide_read(addr, dev->ide);
sis_5511_log("SiS 5513 P2I: [R] dev->pci_conf_sb[0][%02X] = %02X\n", addr, ret);
} else if (func == 0x01) {
if (addr == 0x3d)
ret = (((dev->pci_conf_sb[0x01][0x4b] & 0xc0) == 0xc0) ||
(dev->pci_conf_sb[0x01][0x09] & 0x05)) ? PCI_INTA : 0x00;
else
ret = dev->pci_conf_sb[func][addr];
sis_5511_log("SiS 5513 IDE: [R] dev->pci_conf_sb[1][%02X] = %02X\n", addr, ret);
}
sis_5511_log("SiS 5513: [R] dev->pci_conf[%02X] = %02X\n", addr, ret);
return ret;
}
static void
sis_5513_isa_write(uint16_t addr, uint8_t val, void *priv)
{
sis_5511_t *dev = (sis_5511_t *) priv;
switch (addr) {
case 0x22:
dev->index = val - 0x50;
break;
case 0x23:
sis_5511_log("SiS 5513 ISA: [W] dev->regs[%02X] = %02X\n", dev->index + 0x50, val);
switch (dev->index) {
case 0x00:
dev->regs[dev->index] = val & 0xed;
switch (val >> 6) {
case 0:
cpu_set_isa_speed(7159091);
break;
case 1:
cpu_set_isa_pci_div(4);
break;
case 2:
cpu_set_isa_pci_div(3);
break;
default:
break;
}
nvr_bank_set(0, !!(val & 0x08), dev->nvr);
break;
case 0x01:
dev->regs[dev->index] = val & 0xf4;
break;
case 0x03:
dev->regs[dev->index] = val & 3;
break;
case 0x04: /* BIOS Register */
dev->regs[dev->index] = val;
break;
case 0x05:
dev->regs[dev->index] = val;
outb(0x70, val);
break;
case 0x08:
case 0x09:
case 0x0a:
case 0x0b:
dev->regs[dev->index] = val;
break;
default:
break;
}
break;
default:
break;
}
}
static uint8_t
sis_5513_isa_read(uint16_t addr, void *priv)
{
const sis_5511_t *dev = (sis_5511_t *) priv;
uint8_t ret = 0xff;
if (addr == 0x23) {
if (dev->index == 0x05)
ret = inb(0x70);
else
ret = dev->regs[dev->index];
sis_5511_log("SiS 5513 ISA: [R] dev->regs[%02X] = %02X\n", dev->index + 0x50, ret);
}
return ret;
}
static void
sis_5511_reset(void *priv)
{
sis_5511_t *dev = (sis_5511_t *) priv;
/* SiS 5511 */
dev->pci_conf[0x00] = 0x39;
dev->pci_conf[0x01] = 0x10;
dev->pci_conf[0x02] = 0x11;
dev->pci_conf[0x03] = 0x55;
dev->pci_conf[0x04] = 0x07;
dev->pci_conf[0x05] = dev->pci_conf[0x06] = 0x00;
dev->pci_conf[0x07] = 0x02;
dev->pci_conf[0x08] = 0x00;
dev->pci_conf[0x09] = dev->pci_conf[0x0a] = 0x00;
dev->pci_conf[0x0b] = 0x06;
dev->pci_conf[0x50] = dev->pci_conf[0x51] = 0x00;
dev->pci_conf[0x52] = 0x20;
dev->pci_conf[0x53] = dev->pci_conf[0x54] = 0x00;
dev->pci_conf[0x55] = dev->pci_conf[0x56] = 0x00;
dev->pci_conf[0x57] = dev->pci_conf[0x58] = 0x00;
dev->pci_conf[0x59] = dev->pci_conf[0x5a] = 0x00;
dev->pci_conf[0x5b] = dev->pci_conf[0x5c] = 0x00;
dev->pci_conf[0x5d] = dev->pci_conf[0x5e] = 0x00;
dev->pci_conf[0x5f] = dev->pci_conf[0x60] = 0x00;
dev->pci_conf[0x61] = dev->pci_conf[0x62] = 0xff;
dev->pci_conf[0x63] = 0xff;
dev->pci_conf[0x64] = dev->pci_conf[0x65] = 0x00;
dev->pci_conf[0x66] = 0x00;
dev->pci_conf[0x67] = 0xff;
dev->pci_conf[0x68] = dev->pci_conf[0x69] = 0x00;
dev->pci_conf[0x6a] = 0x00;
dev->pci_conf[0x6b] = dev->pci_conf[0x6c] = 0xff;
dev->pci_conf[0x6d] = dev->pci_conf[0x6e] = 0xff;
dev->pci_conf[0x6f] = 0x00;
dev->pci_conf[0x70] = dev->pci_conf[0x72] = 0x04;
dev->pci_conf[0x74] = dev->pci_conf[0x76] = 0x04;
dev->pci_conf[0x78] = dev->pci_conf[0x7a] = 0x04;
dev->pci_conf[0x7c] = dev->pci_conf[0x7e] = 0x04;
dev->pci_conf[0x71] = dev->pci_conf[0x75] = 0x00;
dev->pci_conf[0x73] = dev->pci_conf[0x77] = 0x80;
dev->pci_conf[0x79] = dev->pci_conf[0x7d] = 0x00;
dev->pci_conf[0x7b] = dev->pci_conf[0x7f] = 0x80;
dev->pci_conf[0x80] = dev->pci_conf[0x81] = 0x00;
dev->pci_conf[0x82] = dev->pci_conf[0x83] = 0x00;
dev->pci_conf[0x84] = dev->pci_conf[0x85] = 0x00;
dev->pci_conf[0x86] = 0x00;
cpu_cache_ext_enabled = 0;
cpu_update_waitstates();
sis_5511_smram_recalc(dev);
sis_5511_shadow_recalc(dev);
flushmmucache();
memset(dev->slic_regs, 0x00, 4096 * sizeof(uint8_t));
dev->slic_regs[0x18] = 0x0f;
mem_mapping_set_addr(&dev->slic_mapping, 0xffc00000, 0x00001000);
/* SiS 5513 */
dev->pci_conf_sb[0][0x00] = 0x39;
dev->pci_conf_sb[0][0x01] = 0x10;
dev->pci_conf_sb[0][0x02] = 0x08;
dev->pci_conf_sb[0][0x03] = 0x00;
dev->pci_conf_sb[0][0x04] = 0x07;
dev->pci_conf_sb[0][0x05] = dev->pci_conf_sb[0][0x06] = 0x00;
dev->pci_conf_sb[0][0x07] = 0x02;
dev->pci_conf_sb[0][0x08] = dev->pci_conf_sb[0][0x09] = 0x00;
dev->pci_conf_sb[0][0x0a] = 0x01;
dev->pci_conf_sb[0][0x0b] = 0x06;
dev->pci_conf_sb[0][0x0e] = 0x80;
dev->pci_conf_sb[0][0x40] = 0x00;
dev->pci_conf_sb[0][0x41] = dev->pci_conf_sb[0][0x42] = 0x80;
dev->pci_conf_sb[0][0x43] = dev->pci_conf_sb[0][0x44] = 0x80;
dev->pci_conf_sb[0][0x48] = dev->pci_conf_sb[0][0x49] = 0x00;
dev->pci_conf_sb[0][0x4a] = dev->pci_conf_sb[0][0x4b] = 0x00;
dev->pci_conf_sb[0][0x60] = dev->pci_conf_sb[0][0x61] = 0x80;
dev->pci_conf_sb[0][0x62] = 0x00;
dev->pci_conf_sb[0][0x63] = 0x80;
dev->pci_conf_sb[0][0x64] = 0x00;
dev->pci_conf_sb[0][0x65] = 0x00;
dev->pci_conf_sb[0][0x66] = dev->pci_conf_sb[0][0x67] = 0x00;
dev->pci_conf_sb[0][0x68] = dev->pci_conf_sb[0][0x69] = 0x00;
dev->pci_conf_sb[0][0x6a] = 0x04;
pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED);
pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED);
pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED);
pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED);
pci_set_mirq_routing(PCI_MIRQ0, PCI_IRQ_DISABLED);
pci_set_mirq_routing(PCI_MIRQ1, PCI_IRQ_DISABLED);
pci_set_mirq_routing(PCI_MIRQ2, PCI_IRQ_DISABLED);
dev->regs[0x00] = dev->regs[0x01] = 0x00;
dev->regs[0x03] = dev->regs[0x04] = 0x00;
dev->regs[0x05] = 0x00;
dev->regs[0x08] = dev->regs[0x09] = 0x00;
dev->regs[0x0a] = dev->regs[0x0b] = 0x00;
cpu_set_isa_speed(7159091);
nvr_bank_set(0, 0, dev->nvr);
/* SiS 5513 IDE Controller */
dev->pci_conf_sb[1][0x00] = 0x39;
dev->pci_conf_sb[1][0x01] = 0x10;
dev->pci_conf_sb[1][0x02] = 0x13;
dev->pci_conf_sb[1][0x03] = 0x55;
dev->pci_conf_sb[1][0x04] = dev->pci_conf_sb[1][0x05] = 0x00;
dev->pci_conf_sb[1][0x06] = dev->pci_conf_sb[1][0x07] = 0x00;
dev->pci_conf_sb[1][0x08] = 0x00;
dev->pci_conf_sb[1][0x09] = 0x8a;
dev->pci_conf_sb[1][0x0a] = dev->pci_conf_sb[1][0x0b] = 0x01;
dev->pci_conf_sb[1][0x0c] = dev->pci_conf_sb[1][0x0d] = 0x00;
dev->pci_conf_sb[1][0x0e] = 0x80;
dev->pci_conf_sb[1][0x0f] = 0x00;
dev->pci_conf_sb[1][0x10] = 0xf1;
dev->pci_conf_sb[1][0x11] = 0x01;
dev->pci_conf_sb[1][0x14] = 0xf5;
dev->pci_conf_sb[1][0x15] = 0x03;
dev->pci_conf_sb[1][0x18] = 0x71;
dev->pci_conf_sb[1][0x19] = 0x01;
dev->pci_conf_sb[1][0x1c] = 0x75;
dev->pci_conf_sb[1][0x1d] = 0x03;
dev->pci_conf_sb[1][0x20] = 0x01;
dev->pci_conf_sb[1][0x21] = 0xf0;
dev->pci_conf_sb[1][0x22] = dev->pci_conf_sb[1][0x23] = 0x00;
dev->pci_conf_sb[1][0x24] = dev->pci_conf_sb[1][0x25] = 0x00;
dev->pci_conf_sb[1][0x26] = dev->pci_conf_sb[1][0x27] = 0x00;
dev->pci_conf_sb[1][0x28] = dev->pci_conf_sb[1][0x29] = 0x00;
dev->pci_conf_sb[1][0x2a] = dev->pci_conf_sb[1][0x2b] = 0x00;
dev->pci_conf_sb[1][0x2c] = dev->pci_conf_sb[1][0x2d] = 0x00;
dev->pci_conf_sb[1][0x2e] = dev->pci_conf_sb[1][0x2f] = 0x00;
dev->pci_conf_sb[1][0x30] = dev->pci_conf_sb[1][0x31] = 0x00;
dev->pci_conf_sb[1][0x32] = dev->pci_conf_sb[1][0x33] = 0x00;
dev->pci_conf_sb[1][0x40] = dev->pci_conf_sb[1][0x41] = 0x00;
dev->pci_conf_sb[1][0x42] = dev->pci_conf_sb[1][0x43] = 0x00;
dev->pci_conf_sb[1][0x44] = dev->pci_conf_sb[1][0x45] = 0x00;
dev->pci_conf_sb[1][0x46] = dev->pci_conf_sb[1][0x47] = 0x00;
dev->pci_conf_sb[1][0x48] = dev->pci_conf_sb[1][0x49] = 0x00;
dev->pci_conf_sb[1][0x4a] = 0x06;
dev->pci_conf_sb[1][0x4b] = 0x00;
dev->pci_conf_sb[1][0x4c] = dev->pci_conf_sb[1][0x4d] = 0x00;
dev->pci_conf_sb[1][0x4e] = dev->pci_conf_sb[1][0x4f] = 0x00;
sis_5513_ide_irq_handler(dev);
sis_5513_ide_handler(dev);
sff_bus_master_reset(dev->bm[0]);
sff_bus_master_reset(dev->bm[1]);
}
static void
sis_5511_close(void *priv)
{
sis_5511_t *dev = (sis_5511_t *) priv;
smram_del(dev->smram);
free(dev);
}
@@ -920,53 +141,18 @@ static void *
sis_5511_init(UNUSED(const device_t *info))
{
sis_5511_t *dev = (sis_5511_t *) calloc(1, sizeof(sis_5511_t));
uint8_t pit_is_fast = (((pit_mode == -1) && is486) || (pit_mode == 1));
/* Device 0: SiS 5511 */
pci_add_card(PCI_ADD_NORTHBRIDGE, sis_5511_read, sis_5511_write, dev, &dev->nb_slot);
/* Device 1: SiS 5513 */
pci_add_card(PCI_ADD_SOUTHBRIDGE, sis_5513_read, sis_5513_write, dev, &dev->sb_slot);
/* SLiC Memory Mapped Registers */
mem_mapping_add(&dev->slic_mapping,
0xffc00000, 0x00001000,
sis_5511_slic_read,
NULL,
NULL,
sis_5511_slic_write,
NULL,
NULL,
NULL, MEM_MAPPING_EXTERNAL,
dev);
dev->sis = device_add(&sis_55xx_common_device);
/* Ports 22h-23h: SiS 5513 ISA */
io_sethandler(0x0022, 0x0002, sis_5513_isa_read, NULL, NULL, sis_5513_isa_write, NULL, NULL, dev);
dev->h2p = device_add_linked(&sis_5511_h2p_device, dev->sis);
/* MIRQ */
pci_enable_mirq(0);
pci_enable_mirq(1);
/* IDEIRQ */
pci_enable_mirq(2);
/* Port 92h */
dev->port_92 = device_add(&port_92_device);
/* SFF IDE */
dev->bm[0] = device_add_inst(&sff8038i_device, 1);
dev->bm[1] = device_add_inst(&sff8038i_device, 2);
/* SMRAM */
dev->smram = smram_add();
/* PIT */
dev->pit = device_find_first_priv(DEVICE_PIT);
dev->pit_read_reg = pit_is_fast ? pitf_read_reg : pit_read_reg;
/* NVR */
dev->nvr = device_add(&at_mb_nvr_device);
sis_5511_reset(dev);
dev->p2i = device_add_linked(&sis_5513_p2i_device, dev->sis);
dev->ide = device_add_linked(&sis_5513_ide_device, dev->sis);
return dev;
}
@@ -978,7 +164,7 @@ const device_t sis_5511_device = {
.local = 0,
.init = sis_5511_init,
.close = sis_5511_close,
.reset = sis_5511_reset,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,

461
src/chipset/sis_5511_h2p.c Normal file
View File

@@ -0,0 +1,461 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Implementation of the SiS 5511 Host to PCI bridge.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2024 Miran Grca.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/dma.h>
#include <86box/mem.h>
#include <86box/nvr.h>
#include <86box/hdd.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/hdc_ide_sff8038i.h>
#include <86box/pci.h>
#include <86box/pic.h>
#include <86box/pit.h>
#include <86box/pit_fast.h>
#include <86box/plat.h>
#include <86box/plat_unused.h>
#include <86box/port_92.h>
#include <86box/smram.h>
#include <86box/spd.h>
#include <86box/apm.h>
#include <86box/ddma.h>
#include <86box/acpi.h>
#include <86box/smbus.h>
#include <86box/spd.h>
#include <86box/sis_55xx.h>
#include <86box/chipset.h>
#include <86box/usb.h>
#include <86box/agpgart.h>
#ifdef ENABLE_SIS_5511_HOST_TO_PCI_LOG
int sis_5511_host_to_pci_do_log = ENABLE_SIS_5511_HOST_TO_PCI_LOG;
static void
sis_5511_host_to_pci_log(const char *fmt, ...)
{
va_list ap;
if (sis_5511_host_to_pci_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define sis_5511_host_to_pci_log(fmt, ...)
#endif
typedef struct sis_5511_host_to_pci_t {
uint8_t pci_conf[256];
uint8_t states[7];
uint8_t slic_regs[4096];
sis_55xx_common_t *sis;
smram_t *smram;
mem_mapping_t slic_mapping;
} sis_5511_host_to_pci_t;
static void
sis_5511_shadow_recalc(sis_5511_host_to_pci_t *dev)
{
int state;
uint32_t base;
for (uint8_t i = 0x80; i <= 0x86; i++) {
if (i == 0x86) {
if ((dev->states[i & 0x0f] ^ dev->pci_conf[i]) & 0xa0) {
state = (dev->pci_conf[i] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
state |= (dev->pci_conf[i] & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
mem_set_mem_state_both(0xf0000, 0x10000, state);
sis_5511_host_to_pci_log("000F0000-000FFFFF\n");
}
} else {
base = ((i & 0x07) << 15) + 0xc0000;
if ((dev->states[i & 0x0f] ^ dev->pci_conf[i]) & 0xa0) {
state = (dev->pci_conf[i] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
state |= (dev->pci_conf[i] & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
mem_set_mem_state_both(base, 0x4000, state);
sis_5511_host_to_pci_log("%08X-%08X\n", base, base + 0x3fff);
}
if ((dev->states[i & 0x0f] ^ dev->pci_conf[i]) & 0x0a) {
state = (dev->pci_conf[i] & 0x08) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
state |= (dev->pci_conf[i] & 0x02) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
mem_set_mem_state_both(base + 0x4000, 0x4000, state);
sis_5511_host_to_pci_log("%08X-%08X\n", base + 0x4000, base + 0x7fff);
}
}
dev->states[i & 0x0f] = dev->pci_conf[i];
}
flushmmucache_nopc();
}
static void
sis_5511_smram_recalc(sis_5511_host_to_pci_t *dev)
{
smram_disable_all();
switch (dev->pci_conf[0x65] >> 6) {
case 0:
smram_enable(dev->smram, 0x000e0000, 0x000e0000, 0x8000, dev->pci_conf[0x65] & 0x10, 1);
break;
case 1:
smram_enable(dev->smram, 0x000e0000, 0x000a0000, 0x8000, dev->pci_conf[0x65] & 0x10, 1);
break;
case 2:
smram_enable(dev->smram, 0x000e0000, 0x000b0000, 0x8000, dev->pci_conf[0x65] & 0x10, 1);
break;
default:
break;
}
flushmmucache();
}
void
sis_5511_host_to_pci_write(int addr, uint8_t val, void *priv)
{
sis_5511_host_to_pci_t *dev = (sis_5511_host_to_pci_t *) priv;
sis_5511_host_to_pci_log("SiS 5511 H2P: [W] dev->pci_conf[%02X] = %02X\n", addr, val);
switch (addr) {
default:
break;
case 0x07: /* Status - High Byte */
dev->pci_conf[addr] &= 0xb0;
break;
case 0x50:
dev->pci_conf[addr] = val;
cpu_cache_ext_enabled = !!(val & 0x40);
cpu_update_waitstates();
break;
case 0x51:
dev->pci_conf[addr] = val & 0xfe;
break;
case 0x52:
dev->pci_conf[addr] = val & 0x3f;
break;
case 0x53:
case 0x54:
dev->pci_conf[addr] = val;
break;
case 0x55:
dev->pci_conf[addr] = val & 0xf8;
break;
case 0x56 ... 0x59:
dev->pci_conf[addr] = val;
break;
case 0x5a:
/* TODO: Fast Gate A20 Emulation and Fast Reset Emulation on the KBC.
The former (bit 7) means the chipset intercepts D1h to 64h and 00h to 60h.
The latter (bit 6) means the chipset intercepts all odd FXh to 64h.
Bit 5 sets fast reset latency. This should be fixed on the other SiS
chipsets as well. */
dev->pci_conf[addr] = val;
break;
case 0x5b:
dev->pci_conf[addr] = val & 0xf7;
break;
case 0x5c:
dev->pci_conf[addr] = val & 0xcf;
break;
case 0x5d:
dev->pci_conf[addr] = val;
break;
case 0x5e:
dev->pci_conf[addr] = val & 0xfe;
break;
case 0x5f:
dev->pci_conf[addr] = val & 0xfe;
break;
case 0x60:
dev->pci_conf[addr] = val & 0x3e;
if ((dev->pci_conf[0x68] & 1) && (val & 2)) {
smi_raise();
dev->pci_conf[0x69] |= 1;
}
break;
case 0x61 ... 0x64:
dev->pci_conf[addr] = val;
break;
case 0x65:
dev->pci_conf[addr] = val & 0xd0;
sis_5511_smram_recalc(dev);
break;
case 0x66:
dev->pci_conf[addr] = val & 0x7f;
break;
case 0x67:
case 0x68:
dev->pci_conf[addr] = val;
break;
case 0x69:
dev->pci_conf[addr] &= val;
break;
case 0x6a ... 0x6e:
dev->pci_conf[addr] = val;
break;
case 0x6f:
dev->pci_conf[addr] = val & 0x3f;
break;
case 0x70: /* DRAM Bank Register 0-0 */
case 0x72: /* DRAM Bank Register 0-1 */
case 0x74: /* DRAM Bank Register 1-0 */
case 0x76: /* DRAM Bank Register 1-1 */
case 0x78: /* DRAM Bank Register 2-0 */
case 0x7a: /* DRAM Bank Register 2-1 */
case 0x7c: /* DRAM Bank Register 3-0 */
case 0x7e: /* DRAM Bank Register 3-1 */
spd_write_drbs(dev->pci_conf, 0x70, 0x7e, 0x82);
break;
case 0x71: /* DRAM Bank Register 0-0 */
dev->pci_conf[addr] = val;
break;
case 0x75: /* DRAM Bank Register 1-0 */
case 0x79: /* DRAM Bank Register 2-0 */
case 0x7d: /* DRAM Bank Register 3-0 */
dev->pci_conf[addr] = val & 0x7f;
break;
case 0x73: /* DRAM Bank Register 0-1 */
case 0x77: /* DRAM Bank Register 1-1 */
case 0x7b: /* DRAM Bank Register 2-1 */
case 0x7f: /* DRAM Bank Register 3-1 */
dev->pci_conf[addr] = val & 0x83;
break;
case 0x80 ... 0x85:
dev->pci_conf[addr] = val & 0xee;
sis_5511_shadow_recalc(dev);
break;
case 0x86:
dev->pci_conf[addr] = val & 0xe8;
sis_5511_shadow_recalc(dev);
break;
case 0x90 ... 0x93: /* 5512 General Purpose Register Index */
dev->pci_conf[addr] = val;
break;
}
}
uint8_t
sis_5511_host_to_pci_read(int addr, void *priv)
{
const sis_5511_host_to_pci_t *dev = (sis_5511_host_to_pci_t *) priv;
uint8_t ret = 0xff;
ret = dev->pci_conf[addr];
sis_5511_host_to_pci_log("SiS 5511 H2P: [R] dev->pci_conf[%02X] = %02X\n", addr, ret);
return ret;
}
static void
sis_5511_slic_write(uint32_t addr, uint8_t val, void *priv)
{
sis_5511_host_to_pci_t *dev = (sis_5511_host_to_pci_t *) priv;
addr &= 0x00000fff;
switch (addr) {
case 0x00000000:
case 0x00000008: /* 0x00000008 is a SiS 5512 register. */
dev->slic_regs[addr] = val;
break;
case 0x00000010:
case 0x00000018:
case 0x00000028:
case 0x00000038:
dev->slic_regs[addr] = val & 0x01;
break;
case 0x00000030:
dev->slic_regs[addr] = val & 0x0f;
mem_mapping_set_addr(&dev->slic_mapping,
(((uint32_t) (val & 0x0f)) << 28) | 0x0fc00000, 0x00001000);
break;
}
}
static uint8_t
sis_5511_slic_read(uint32_t addr, void *priv)
{
sis_5511_host_to_pci_t *dev = (sis_5511_host_to_pci_t *) priv;
uint8_t ret = 0xff;
addr &= 0x00000fff;
switch (addr) {
case 0x00000008: /* 0x00000008 is a SiS 5512 register. */
ret = dev->slic_regs[addr];
break;
}
return ret;
}
static void
sis_5511_host_to_pci_reset(void *priv)
{
sis_5511_host_to_pci_t *dev = (sis_5511_host_to_pci_t *) priv;
dev->pci_conf[0x00] = 0x39;
dev->pci_conf[0x01] = 0x10;
dev->pci_conf[0x02] = 0x11;
dev->pci_conf[0x03] = 0x55;
dev->pci_conf[0x04] = 0x07;
dev->pci_conf[0x05] = dev->pci_conf[0x06] = 0x00;
dev->pci_conf[0x07] = 0x02;
dev->pci_conf[0x08] = 0x00;
dev->pci_conf[0x09] = dev->pci_conf[0x0a] = 0x00;
dev->pci_conf[0x0b] = 0x06;
dev->pci_conf[0x50] = dev->pci_conf[0x51] = 0x00;
dev->pci_conf[0x52] = 0x20;
dev->pci_conf[0x53] = dev->pci_conf[0x54] = 0x00;
dev->pci_conf[0x55] = dev->pci_conf[0x56] = 0x00;
dev->pci_conf[0x57] = dev->pci_conf[0x58] = 0x00;
dev->pci_conf[0x59] = dev->pci_conf[0x5a] = 0x00;
dev->pci_conf[0x5b] = dev->pci_conf[0x5c] = 0x00;
dev->pci_conf[0x5d] = dev->pci_conf[0x5e] = 0x00;
dev->pci_conf[0x5f] = dev->pci_conf[0x60] = 0x00;
dev->pci_conf[0x61] = dev->pci_conf[0x62] = 0xff;
dev->pci_conf[0x63] = 0xff;
dev->pci_conf[0x64] = dev->pci_conf[0x65] = 0x00;
dev->pci_conf[0x66] = 0x00;
dev->pci_conf[0x67] = 0xff;
dev->pci_conf[0x68] = dev->pci_conf[0x69] = 0x00;
dev->pci_conf[0x6a] = 0x00;
dev->pci_conf[0x6b] = dev->pci_conf[0x6c] = 0xff;
dev->pci_conf[0x6d] = dev->pci_conf[0x6e] = 0xff;
dev->pci_conf[0x6f] = 0x00;
dev->pci_conf[0x70] = dev->pci_conf[0x72] = 0x04;
dev->pci_conf[0x74] = dev->pci_conf[0x76] = 0x04;
dev->pci_conf[0x78] = dev->pci_conf[0x7a] = 0x04;
dev->pci_conf[0x7c] = dev->pci_conf[0x7e] = 0x04;
dev->pci_conf[0x71] = dev->pci_conf[0x75] = 0x00;
dev->pci_conf[0x73] = dev->pci_conf[0x77] = 0x80;
dev->pci_conf[0x79] = dev->pci_conf[0x7d] = 0x00;
dev->pci_conf[0x7b] = dev->pci_conf[0x7f] = 0x80;
dev->pci_conf[0x80] = dev->pci_conf[0x81] = 0x00;
dev->pci_conf[0x82] = dev->pci_conf[0x83] = 0x00;
dev->pci_conf[0x84] = dev->pci_conf[0x85] = 0x00;
dev->pci_conf[0x86] = 0x00;
cpu_cache_ext_enabled = 0;
cpu_update_waitstates();
sis_5511_smram_recalc(dev);
sis_5511_shadow_recalc(dev);
flushmmucache();
memset(dev->slic_regs, 0x00, 4096 * sizeof(uint8_t));
dev->slic_regs[0x18] = 0x0f;
mem_mapping_set_addr(&dev->slic_mapping, 0xffc00000, 0x00001000);
}
static void
sis_5511_host_to_pci_close(void *priv)
{
sis_5511_host_to_pci_t *dev = (sis_5511_host_to_pci_t *) priv;
smram_del(dev->smram);
free(dev);
}
static void *
sis_5511_host_to_pci_init(UNUSED(const device_t *info))
{
sis_5511_host_to_pci_t *dev = (sis_5511_host_to_pci_t *) calloc(1, sizeof(sis_5511_host_to_pci_t));
dev->sis = device_get_common_priv();
/* SLiC Memory Mapped Registers */
mem_mapping_add(&dev->slic_mapping,
0xffc00000, 0x00001000,
sis_5511_slic_read,
NULL,
NULL,
sis_5511_slic_write,
NULL,
NULL,
NULL, MEM_MAPPING_EXTERNAL,
dev);
/* SMRAM */
dev->smram = smram_add();
sis_5511_host_to_pci_reset(dev);
return dev;
}
const device_t sis_5511_h2p_device = {
.name = "SiS 5511 Host to PCI bridge",
.internal_name = "sis_5511_host_to_pci",
.flags = DEVICE_PCI,
.local = 0x00,
.init = sis_5511_host_to_pci_init,
.close = sis_5511_host_to_pci_close,
.reset = sis_5511_host_to_pci_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

505
src/chipset/sis_5513_ide.c Normal file
View File

@@ -0,0 +1,505 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* 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 5513 IDE controller.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2024 Miran Grca.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/dma.h>
#include <86box/mem.h>
#include <86box/nvr.h>
#include <86box/hdd.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/hdc_ide_sff8038i.h>
#include <86box/pci.h>
#include <86box/pic.h>
#include <86box/pit.h>
#include <86box/pit_fast.h>
#include <86box/plat.h>
#include <86box/plat_unused.h>
#include <86box/port_92.h>
#include <86box/smram.h>
#include <86box/spd.h>
#include <86box/apm.h>
#include <86box/ddma.h>
#include <86box/acpi.h>
#include <86box/smbus.h>
#include <86box/sis_55xx.h>
#include <86box/chipset.h>
#ifdef ENABLE_SIS_5513_IDE_LOG
int sis_5513_ide_do_log = ENABLE_SIS_5513_IDE_LOG;
static void
sis_5513_ide_log(const char *fmt, ...)
{
va_list ap;
if (sis_5513_ide_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define sis_5513_ide_log(fmt, ...)
#endif
typedef struct sis_5513_ide_t {
uint8_t rev;
uint8_t pci_conf[256];
sis_55xx_common_t *sis;
} sis_5513_ide_t;
static void
sis_5513_ide_irq_handler(sis_5513_ide_t *dev)
{
if (dev->pci_conf[0x09] & 0x01) {
/* Primary IDE is native. */
sis_5513_ide_log("Primary IDE IRQ mode: Native, Native\n");
sff_set_irq_mode(dev->sis->bm[0], IRQ_MODE_SIS_551X);
} else {
/* Primary IDE is legacy. */
sis_5513_ide_log("Primary IDE IRQ mode: IRQ14, IRQ15\n");
sff_set_irq_mode(dev->sis->bm[0], IRQ_MODE_LEGACY);
}
if (dev->pci_conf[0x09] & 0x04) {
/* Secondary IDE is native. */
sis_5513_ide_log("Secondary IDE IRQ mode: Native, Native\n");
sff_set_irq_mode(dev->sis->bm[1], IRQ_MODE_SIS_551X);
} else {
/* Secondary IDE is legacy. */
sis_5513_ide_log("Secondary IDE IRQ mode: IRQ14, IRQ15\n");
sff_set_irq_mode(dev->sis->bm[1], IRQ_MODE_LEGACY);
}
}
static void
sis_5513_ide_handler(sis_5513_ide_t *dev)
{
uint8_t ide_io_on = dev->pci_conf[0x04] & 0x01;
uint16_t native_base_pri_addr = (dev->pci_conf[0x11] | dev->pci_conf[0x10] << 8) & 0xfffe;
uint16_t native_side_pri_addr = (dev->pci_conf[0x15] | dev->pci_conf[0x14] << 8) & 0xfffe;
uint16_t native_base_sec_addr = (dev->pci_conf[0x19] | dev->pci_conf[0x18] << 8) & 0xfffe;
uint16_t native_side_sec_addr = (dev->pci_conf[0x1c] | dev->pci_conf[0x1b] << 8) & 0xfffe;
uint16_t current_pri_base;
uint16_t current_pri_side;
uint16_t current_sec_base;
uint16_t current_sec_side;
/* Primary Channel Programming */
current_pri_base = (!(dev->pci_conf[0x09] & 1)) ? 0x01f0 : native_base_pri_addr;
current_pri_side = (!(dev->pci_conf[0x09] & 1)) ? 0x03f6 : native_side_pri_addr;
/* Secondary Channel Programming */
current_sec_base = (!(dev->pci_conf[0x09] & 4)) ? 0x0170 : native_base_sec_addr;
current_sec_side = (!(dev->pci_conf[0x09] & 4)) ? 0x0376 : native_side_sec_addr;
sis_5513_ide_log("sis_5513_ide_handler(): Disabling primary IDE...\n");
ide_pri_disable();
sis_5513_ide_log("sis_5513_ide_handler(): Disabling secondary IDE...\n");
ide_sec_disable();
if (ide_io_on) {
/* Primary Channel Setup */
if (dev->pci_conf[0x4a] & 0x02) {
sis_5513_ide_log("sis_5513_ide_handler(): Primary IDE base now %04X...\n", current_pri_base);
ide_set_base(0, current_pri_base);
sis_5513_ide_log("sis_5513_ide_handler(): Primary IDE side now %04X...\n", current_pri_side);
ide_set_side(0, current_pri_side);
sis_5513_ide_log("sis_5513_ide_handler(): Enabling primary IDE...\n");
ide_pri_enable();
sis_5513_ide_log("SiS 5513 PRI: BASE %04x SIDE %04x\n", current_pri_base, current_pri_side);
}
/* Secondary Channel Setup */
if (dev->pci_conf[0x4a] & 0x04) {
sis_5513_ide_log("sis_5513_ide_handler(): Secondary IDE base now %04X...\n", current_sec_base);
ide_set_base(1, current_sec_base);
sis_5513_ide_log("sis_5513_ide_handler(): Secondary IDE side now %04X...\n", current_sec_side);
ide_set_side(1, current_sec_side);
sis_5513_ide_log("sis_5513_ide_handler(): Enabling secondary IDE...\n");
ide_sec_enable();
sis_5513_ide_log("SiS 5513: BASE %04x SIDE %04x\n", current_sec_base, current_sec_side);
}
}
sff_bus_master_handler(dev->sis->bm[0], ide_io_on,
((dev->pci_conf[0x20] & 0xf0) | (dev->pci_conf[0x21] << 8)) + 0);
sff_bus_master_handler(dev->sis->bm[1], ide_io_on,
((dev->pci_conf[0x20] & 0xf0) | (dev->pci_conf[0x21] << 8)) + 8);
}
void
sis_5513_ide_write(int addr, uint8_t val, void *priv)
{
sis_5513_ide_t *dev = (sis_5513_ide_t *) priv;
sis_5513_ide_log("SiS 5513 IDE: [W] dev->pci_conf[%02X] = %02X\n", addr, val);
switch (addr) {
case 0x04: /* Command low byte */
dev->pci_conf[addr] = val & 0x05;
sis_5513_ide_handler(dev);
break;
case 0x06: /* Status low byte */
dev->pci_conf[addr] = val & 0x20;
break;
case 0x07: /* Status high byte */
dev->pci_conf[addr] = (dev->pci_conf[addr] & 0x06) & ~(val & 0x38);
break;
case 0x09: /* Programming Interface Byte */
switch (dev->rev) {
case 0xd0:
if (dev->sis->ide_bits_1_3_writable)
val |= 0x0a;
fallthrough;
case 0x00:
case 0xd1:
val &= 0xbf;
fallthrough;
case 0xc0:
switch (val & 0x0a) {
case 0x00:
dev->pci_conf[addr] = (dev->pci_conf[addr] & 0x85) | (val & 0x4a);
break;
case 0x02:
dev->pci_conf[addr] = (dev->pci_conf[addr] & 0x84) | (val & 0x4b);
break;
case 0x08:
dev->pci_conf[addr] = (dev->pci_conf[addr] & 0x81) | (val & 0x4e);
break;
case 0x0a:
dev->pci_conf[addr] = (dev->pci_conf[addr] & 0x80) | (val & 0x4f);
break;
}
break;
}
sis_5513_ide_irq_handler(dev);
sis_5513_ide_handler(dev);
break;
case 0x0d: /* Latency Timer */
dev->pci_conf[addr] = val;
break;
/* Primary Base Address */
case 0x10 ... 0x11:
case 0x14 ... 0x15:
fallthrough;
/* Secondary Base Address */
case 0x18 ... 0x19:
case 0x1c ... 0x1d:
fallthrough;
/* Bus Mastering Base Address */
case 0x20 ... 0x21:
if (addr == 0x20)
dev->pci_conf[addr] = (val & 0xe0) | 0x01;
else if ((addr & 0x07) == 0x00)
dev->pci_conf[addr] = (val & 0xf8) | 0x01;
else if ((addr & 0x07) == 0x04)
dev->pci_conf[addr] = (val & 0xfc) | 0x01;
else
dev->pci_conf[addr] = val;
sis_5513_ide_handler(dev);
break;
case 0x2c ... 0x2f:
if (dev->rev >= 0xd0)
dev->pci_conf[addr] = val;
break;
case 0x30 ... 0x33: /* Expansion ROM Base Address */
#ifdef DATASHEET
dev->pci_conf[addr] = val;
#else
if (dev->rev == 0x00)
dev->pci_conf[addr] = val;
#endif
break;
case 0x40: /* IDE Primary Channel/Master Drive Data Recovery Time Control */
if (dev->rev >= 0xd0)
dev->pci_conf[addr] = val & 0xcf;
else
dev->pci_conf[addr] = val & 0x0f;
break;
case 0x42: /* IDE Primary Channel/Slave Drive Data Recovery Time Control */
case 0x44: /* IDE Secondary Channel/Master Drive Data Recovery Time Control */
case 0x46: /* IDE Secondary Channel/Slave Drive Data Recovery Time Control */
case 0x48: /* IDE Command Recovery Time Control */
dev->pci_conf[addr] = val & 0x0f;
break;
case 0x41: /* IDE Primary Channel/Master Drive DataActive Time Control */
case 0x43: /* IDE Primary Channel/Slave Drive Data Active Time Control */
case 0x45: /* IDE Secondary Channel/Master Drive Data Active Time Control */
case 0x47: /* IDE Secondary Channel/Slave Drive Data Active Time Control */
if (dev->rev >= 0xd0)
dev->pci_conf[addr] = val & 0xe7;
else
dev->pci_conf[addr] = val & 0x07;
break;
case 0x49: /* IDE Command Active Time Control */
dev->pci_conf[addr] = val & 0x07;
break;
case 0x4a: /* IDE General Control Register 0 */
switch (dev->rev) {
case 0x00:
dev->pci_conf[addr] = val & 0x9e;
break;
case 0xc0:
dev->pci_conf[addr] = val & 0xaf;
break;
case 0xd0:
dev->pci_conf[addr] = val;
break;
}
sis_5513_ide_handler(dev);
break;
case 0x4b: /* IDE General Control Register 1 */
if (dev->rev >= 0xc0)
dev->pci_conf[addr] = val;
else
dev->pci_conf[addr] = val & 0xef;
break;
case 0x4c: /* Prefetch Count of Primary Channel (Low Byte) */
case 0x4d: /* Prefetch Count of Primary Channel (High Byte) */
case 0x4e: /* Prefetch Count of Secondary Channel (Low Byte) */
case 0x4f: /* Prefetch Count of Secondary Channel (High Byte) */
dev->pci_conf[addr] = val;
break;
case 0x50:
case 0x51:
if (dev->rev >= 0xd0)
dev->pci_conf[addr] = val;
break;
case 0x52:
if (dev->rev >= 0xd0)
dev->pci_conf[addr] = val & 0x0f;
break;
default:
break;
}
}
uint8_t
sis_5513_ide_read(int addr, void *priv)
{
const sis_5513_ide_t *dev = (sis_5513_ide_t *) priv;
uint8_t ret = 0xff;
switch (addr) {
default:
ret = dev->pci_conf[addr];
break;
case 0x09:
ret = dev->pci_conf[addr];
if (dev->rev >= 0xc0) {
if (dev->pci_conf[0x09] & 0x40)
ret |= ((dev->pci_conf[0x4a] & 0x06) << 3);
if ((dev->rev == 0xd0) && dev->sis->ide_bits_1_3_writable)
ret |= 0x0a;
}
break;
case 0x3d:
if (dev->rev >= 0xc0)
ret = (dev->pci_conf[0x09] & 0x05) ? PCI_INTA : 0x00;
else
ret = (((dev->pci_conf[0x4b] & 0xc0) == 0xc0) ||
(dev->pci_conf[0x09] & 0x05)) ? PCI_INTA : 0x00;
break;
}
sis_5513_ide_log("SiS 5513 IDE: [R] dev->pci_conf[%02X] = %02X\n", addr, ret);
return ret;
}
static void
sis_5513_ide_reset(void *priv)
{
sis_5513_ide_t *dev = (sis_5513_ide_t *) priv;
dev->pci_conf[0x00] = 0x39;
dev->pci_conf[0x01] = 0x10;
dev->pci_conf[0x02] = 0x13;
dev->pci_conf[0x03] = 0x55;
dev->pci_conf[0x04] = dev->pci_conf[0x05] = 0x00;
dev->pci_conf[0x06] = dev->pci_conf[0x07] = 0x00;
dev->pci_conf[0x08] = (dev->rev == 0xd1) ? 0xd0 : dev->rev;
dev->pci_conf[0x09] = 0x8a;
dev->pci_conf[0x0a] = dev->pci_conf[0x0b] = 0x01;
dev->pci_conf[0x0c] = dev->pci_conf[0x0d] = 0x00;
dev->pci_conf[0x0e] = 0x80;
dev->pci_conf[0x0f] = 0x00;
dev->pci_conf[0x10] = 0xf1;
dev->pci_conf[0x11] = 0x01;
dev->pci_conf[0x14] = 0xf5;
dev->pci_conf[0x15] = 0x03;
dev->pci_conf[0x18] = 0x71;
dev->pci_conf[0x19] = 0x01;
dev->pci_conf[0x1c] = 0x75;
dev->pci_conf[0x1d] = 0x03;
dev->pci_conf[0x20] = 0x01;
dev->pci_conf[0x21] = 0xf0;
dev->pci_conf[0x22] = dev->pci_conf[0x23] = 0x00;
dev->pci_conf[0x24] = dev->pci_conf[0x25] = 0x00;
dev->pci_conf[0x26] = dev->pci_conf[0x27] = 0x00;
dev->pci_conf[0x28] = dev->pci_conf[0x29] = 0x00;
dev->pci_conf[0x2a] = dev->pci_conf[0x2b] = 0x00;
switch (dev->rev) {
case 0x00:
case 0xd0:
case 0xd1:
dev->pci_conf[0x2c] = dev->pci_conf[0x2d] = 0x00;
break;
case 0xc0:
#ifdef DATASHEET
dev->pci_conf[0x2c] = dev->pci_conf[0x2d] = 0x00;
#else
/* The only Linux lspci listing I could find of this chipset,
shows a subsystem of 0058:0000. */
dev->pci_conf[0x2c] = 0x58;
dev->pci_conf[0x2d] = 0x00;
#endif
break;
}
dev->pci_conf[0x2e] = dev->pci_conf[0x2f] = 0x00;
dev->pci_conf[0x30] = dev->pci_conf[0x31] = 0x00;
dev->pci_conf[0x32] = dev->pci_conf[0x33] = 0x00;
dev->pci_conf[0x40] = dev->pci_conf[0x41] = 0x00;
dev->pci_conf[0x42] = dev->pci_conf[0x43] = 0x00;
dev->pci_conf[0x44] = dev->pci_conf[0x45] = 0x00;
dev->pci_conf[0x46] = dev->pci_conf[0x47] = 0x00;
dev->pci_conf[0x48] = dev->pci_conf[0x49] = 0x00;
dev->pci_conf[0x4a] = 0x06;
dev->pci_conf[0x4b] = 0x00;
dev->pci_conf[0x4c] = dev->pci_conf[0x4d] = 0x00;
dev->pci_conf[0x4e] = dev->pci_conf[0x4f] = 0x00;
sis_5513_ide_irq_handler(dev);
sis_5513_ide_handler(dev);
sff_bus_master_reset(dev->sis->bm[0]);
sff_bus_master_reset(dev->sis->bm[1]);
}
static void
sis_5513_ide_close(void *priv)
{
sis_5513_ide_t *dev = (sis_5513_ide_t *) priv;
free(dev);
}
static void *
sis_5513_ide_init(UNUSED(const device_t *info))
{
sis_5513_ide_t *dev = (sis_5513_ide_t *) calloc(1, sizeof(sis_5513_ide_t));
dev->rev = info->local;
dev->sis = device_get_common_priv();
/* SFF IDE */
dev->sis->bm[0] = device_add_inst(&sff8038i_device, 1);
dev->sis->bm[1] = device_add_inst(&sff8038i_device, 2);
sis_5513_ide_reset(dev);
return dev;
}
const device_t sis_5513_ide_device = {
.name = "SiS 5513 IDE controller",
.internal_name = "sis_5513_ide",
.flags = DEVICE_PCI,
.local = 0x00,
.init = sis_5513_ide_init,
.close = sis_5513_ide_close,
.reset = sis_5513_ide_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t sis_5572_ide_device = {
.name = "SiS 5572 IDE controller",
.internal_name = "sis_5572_ide",
.flags = DEVICE_PCI,
.local = 0xc0,
.init = sis_5513_ide_init,
.close = sis_5513_ide_close,
.reset = sis_5513_ide_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t sis_5582_ide_device = {
.name = "SiS 5582 IDE controller",
.internal_name = "sis_5582_ide",
.flags = DEVICE_PCI,
.local = 0xd0,
.init = sis_5513_ide_init,
.close = sis_5513_ide_close,
.reset = sis_5513_ide_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t sis_5591_5600_ide_device = {
.name = "SiS 5591/(5)600 IDE controller",
.internal_name = "sis_5591_5600_ide",
.flags = DEVICE_PCI,
.local = 0xd1, /* D0, but we need to distinguish them. */
.init = sis_5513_ide_init,
.close = sis_5513_ide_close,
.reset = sis_5513_ide_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

1383
src/chipset/sis_5513_p2i.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

458
src/chipset/sis_5571_h2p.c Normal file
View File

@@ -0,0 +1,458 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Implementation of the SiS 5571 Host to PCI bridge.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2024 Miran Grca.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/dma.h>
#include <86box/mem.h>
#include <86box/nvr.h>
#include <86box/hdd.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/hdc_ide_sff8038i.h>
#include <86box/pci.h>
#include <86box/pic.h>
#include <86box/pit.h>
#include <86box/pit_fast.h>
#include <86box/plat.h>
#include <86box/plat_unused.h>
#include <86box/port_92.h>
#include <86box/smram.h>
#include <86box/spd.h>
#include <86box/apm.h>
#include <86box/ddma.h>
#include <86box/acpi.h>
#include <86box/smbus.h>
#include <86box/spd.h>
#include <86box/sis_55xx.h>
#include <86box/chipset.h>
#include <86box/usb.h>
#include <86box/agpgart.h>
#ifdef ENABLE_SIS_5571_HOST_TO_PCI_LOG
int sis_5571_host_to_pci_do_log = ENABLE_SIS_5571_HOST_TO_PCI_LOG;
static void
sis_5571_host_to_pci_log(const char *fmt, ...)
{
va_list ap;
if (sis_5571_host_to_pci_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define sis_5571_host_to_pci_log(fmt, ...)
#endif
typedef struct sis_5571_host_to_pci_t {
uint8_t pci_conf[256];
uint8_t states[7];
sis_55xx_common_t *sis;
smram_t *smram;
} sis_5571_host_to_pci_t;
static void
sis_5571_shadow_recalc(sis_5571_host_to_pci_t *dev)
{
int state;
uint32_t base;
for (uint8_t i = 0x70; i <= 0x76; i++) {
if (i == 0x76) {
if ((dev->states[i & 0x0f] ^ dev->pci_conf[i]) & 0xa0) {
state = (dev->pci_conf[i] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
state |= (dev->pci_conf[i] & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
mem_set_mem_state_both(0xf0000, 0x10000, state);
sis_5571_host_to_pci_log("000F0000-000FFFFF\n");
}
} else {
base = ((i & 0x07) << 15) + 0xc0000;
if ((dev->states[i & 0x0f] ^ dev->pci_conf[i]) & 0xa0) {
state = (dev->pci_conf[i] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
state |= (dev->pci_conf[i] & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
mem_set_mem_state_both(base, 0x4000, state);
sis_5571_host_to_pci_log("%08X-%08X\n", base, base + 0x3fff);
}
if ((dev->states[i & 0x0f] ^ dev->pci_conf[i]) & 0x0a) {
state = (dev->pci_conf[i] & 0x08) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
state |= (dev->pci_conf[i] & 0x02) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
mem_set_mem_state_both(base + 0x4000, 0x4000, state);
sis_5571_host_to_pci_log("%08X-%08X\n", base + 0x4000, base + 0x7fff);
}
}
dev->states[i & 0x0f] = dev->pci_conf[i];
}
flushmmucache_nopc();
}
static void
sis_5571_smram_recalc(sis_5571_host_to_pci_t *dev)
{
smram_disable_all();
switch (dev->pci_conf[0xa3] >> 6) {
case 0:
smram_enable(dev->smram, 0x000e0000, 0x000e0000, 0x8000, dev->pci_conf[0xa3] & 0x10, 1);
break;
case 1:
smram_enable(dev->smram, 0x000e0000, 0x000a0000, 0x8000, dev->pci_conf[0xa3] & 0x10, 1);
break;
case 2:
smram_enable(dev->smram, 0x000e0000, 0x000b0000, 0x8000, dev->pci_conf[0xa3] & 0x10, 1);
break;
case 3:
smram_enable(dev->smram, 0x000a0000, 0x000a0000, 0x10000, dev->pci_conf[0xa3] & 0x10, 1);
break;
default:
break;
}
flushmmucache();
}
void
sis_5571_host_to_pci_write(int addr, uint8_t val, void *priv)
{
sis_5571_host_to_pci_t *dev = (sis_5571_host_to_pci_t *) priv;
sis_5571_host_to_pci_log("SiS 5571 H2P: [W] dev->pci_conf[%02X] = %02X\n", addr, val);
switch (addr) {
default:
break;
case 0x04: /* Command - low byte */
case 0x05: /* Command - high byte */
dev->pci_conf[addr] = (dev->pci_conf[addr] & 0xfd) | (val & 0x02);
break;
case 0x07: /* Status - High Byte */
dev->pci_conf[addr] &= ~(val & 0xb8);
break;
case 0x0d: /* Master latency timer */
dev->pci_conf[addr] = val;
break;
case 0x50: /* Host Interface and DRAM arbiter */
dev->pci_conf[addr] = val & 0xec;
break;
case 0x51: /* CACHE */
dev->pci_conf[addr] = val;
cpu_cache_ext_enabled = !!(val & 0x40);
cpu_update_waitstates();
break;
case 0x52:
dev->pci_conf[addr] = val & 0xd0;
break;
case 0x53: /* DRAM */
dev->pci_conf[addr] = val & 0xfe;
break;
case 0x54: /* FP/EDO */
dev->pci_conf[addr] = val;
break;
case 0x55:
dev->pci_conf[addr] = val & 0xe0;
break;
case 0x56: /* MDLE delay */
dev->pci_conf[addr] = val & 0x07;
break;
case 0x57: /* SDRAM */
dev->pci_conf[addr] = val & 0xf8;
break;
case 0x59: /* Buffer strength and current rating */
dev->pci_conf[addr] = val;
break;
case 0x5a:
dev->pci_conf[addr] = val & 0x03;
break;
/* Undocumented - DRAM bank registers, the exact layout is currently unknown. */
case 0x60 ... 0x6b:
dev->pci_conf[addr] = val;
break;
case 0x70 ... 0x75:
dev->pci_conf[addr] = val & 0xee;
sis_5571_shadow_recalc(dev);
break;
case 0x76:
dev->pci_conf[addr] = val & 0xe8;
sis_5571_shadow_recalc(dev);
break;
case 0x77: /* Characteristics of non-cacheable area */
dev->pci_conf[addr] = val & 0x0f;
break;
case 0x78: /* Allocation of Non-Cacheable area #1 */
case 0x79: /* NCA1REG2 */
case 0x7a: /* Allocation of Non-Cacheable area #2 */
case 0x7b: /* NCA2REG2 */
dev->pci_conf[addr] = val;
break;
case 0x80: /* PCI master characteristics */
dev->pci_conf[addr] = val & 0xfe;
break;
case 0x81:
dev->pci_conf[addr] = val & 0xcc;
break;
case 0x82:
dev->pci_conf[addr] = val;
break;
case 0x83: /* CPU to PCI characteristics */
dev->pci_conf[addr] = val;
/* TODO: Implement Fast A20 and Fast reset stuff on the KBC already! */
break;
case 0x84 ... 0x86:
dev->pci_conf[addr] = val;
break;
case 0x87: /* Miscellanea */
dev->pci_conf[addr] = val & 0xf8;
break;
case 0x90: /* PMU control register */
case 0x91: /* Address trap for green function */
case 0x92:
dev->pci_conf[addr] = val;
break;
case 0x93: /* STPCLK# and APM SMI control */
dev->pci_conf[addr] = val;
if ((dev->pci_conf[0x9b] & 0x01) && (val & 0x02)) {
smi_raise();
dev->pci_conf[0x9d] |= 0x01;
}
break;
case 0x94: /* 6x86 and Green function control */
dev->pci_conf[addr] = val & 0xf8;
break;
case 0x95: /* Test mode control */
case 0x96: /* Time slot and Programmable 10-bit I/O port definition */
dev->pci_conf[addr] = val & 0xfb;
break;
case 0x97: /* programmable 10-bit I/O port address */
case 0x98: /* Programmable 16-bit I/O port */
case 0x99 ... 0x9c:
dev->pci_conf[addr] = val;
break;
case 0x9d:
dev->pci_conf[addr] &= val;
break;
case 0x9e: /* STPCLK# Assertion Timer */
case 0x9f: /* STPCLK# De-assertion Timer */
case 0xa0 ... 0xa2:
dev->pci_conf[addr] = val;
break;
case 0xa3: /* SMRAM access control and Power supply control */
dev->pci_conf[addr] = val & 0xd0;
sis_5571_smram_recalc(dev);
break;
}
}
uint8_t
sis_5571_host_to_pci_read(int addr, void *priv)
{
const sis_5571_host_to_pci_t *dev = (sis_5571_host_to_pci_t *) priv;
uint8_t ret = 0xff;
ret = dev->pci_conf[addr];
sis_5571_host_to_pci_log("SiS 5571 H2P: [R] dev->pci_conf[%02X] = %02X\n", addr, ret);
return ret;
}
static void
sis_5571_host_to_pci_reset(void *priv)
{
sis_5571_host_to_pci_t *dev = (sis_5571_host_to_pci_t *) priv;
dev->pci_conf[0x00] = 0x39;
dev->pci_conf[0x01] = 0x10;
dev->pci_conf[0x02] = 0x71;
dev->pci_conf[0x03] = 0x55;
dev->pci_conf[0x04] = 0x05;
dev->pci_conf[0x05] = 0x00;
dev->pci_conf[0x06] = 0x00;
dev->pci_conf[0x07] = 0x02;
dev->pci_conf[0x08] = 0x00;
dev->pci_conf[0x09] = 0x00;
dev->pci_conf[0x0a] = 0x00;
dev->pci_conf[0x0b] = 0x06;
dev->pci_conf[0x0c] = 0x00;
dev->pci_conf[0x0d] = 0x00;
dev->pci_conf[0x0e] = 0x00;
dev->pci_conf[0x0f] = 0x00;
dev->pci_conf[0x50] = 0x00;
dev->pci_conf[0x51] = 0x00;
dev->pci_conf[0x52] = 0x00;
dev->pci_conf[0x53] = 0x00;
dev->pci_conf[0x54] = 0x54;
dev->pci_conf[0x55] = 0x54;
dev->pci_conf[0x56] = 0x03;
dev->pci_conf[0x57] = 0x00;
dev->pci_conf[0x58] = 0x00;
dev->pci_conf[0x59] = 0x00;
dev->pci_conf[0x5a] = 0x00;
/* Undocumented DRAM bank registers. */
dev->pci_conf[0x60] = dev->pci_conf[0x62] = 0x04;
dev->pci_conf[0x64] = dev->pci_conf[0x66] = 0x04;
dev->pci_conf[0x68] = dev->pci_conf[0x6a] = 0x04;
dev->pci_conf[0x61] = dev->pci_conf[0x65] = 0x00;
dev->pci_conf[0x63] = dev->pci_conf[0x67] = 0x80;
dev->pci_conf[0x69] = 0x00;
dev->pci_conf[0x6b] = 0x80;
dev->pci_conf[0x70] = 0x00;
dev->pci_conf[0x71] = 0x00;
dev->pci_conf[0x72] = 0x00;
dev->pci_conf[0x73] = 0x00;
dev->pci_conf[0x74] = 0x00;
dev->pci_conf[0x75] = 0x00;
dev->pci_conf[0x76] = 0x00;
dev->pci_conf[0x77] = 0x00;
dev->pci_conf[0x78] = 0x00;
dev->pci_conf[0x79] = 0x00;
dev->pci_conf[0x7a] = 0x00;
dev->pci_conf[0x7b] = 0x00;
dev->pci_conf[0x80] = 0x00;
dev->pci_conf[0x81] = 0x00;
dev->pci_conf[0x82] = 0x00;
dev->pci_conf[0x83] = 0x00;
dev->pci_conf[0x84] = 0x00;
dev->pci_conf[0x85] = 0x00;
dev->pci_conf[0x86] = 0x00;
dev->pci_conf[0x87] = 0x00;
dev->pci_conf[0x8c] = 0x00;
dev->pci_conf[0x8d] = 0x00;
dev->pci_conf[0x8e] = 0x00;
dev->pci_conf[0x8f] = 0x00;
dev->pci_conf[0x90] = 0x00;
dev->pci_conf[0x91] = 0x00;
dev->pci_conf[0x92] = 0x00;
dev->pci_conf[0x93] = 0x00;
dev->pci_conf[0x93] = 0x00;
dev->pci_conf[0x94] = 0x00;
dev->pci_conf[0x95] = 0x00;
dev->pci_conf[0x96] = 0x00;
dev->pci_conf[0x97] = 0x00;
dev->pci_conf[0x98] = 0x00;
dev->pci_conf[0x99] = 0x00;
dev->pci_conf[0x9a] = 0x00;
dev->pci_conf[0x9b] = 0x00;
dev->pci_conf[0x9c] = 0x00;
dev->pci_conf[0x9d] = 0x00;
dev->pci_conf[0x9e] = 0xff;
dev->pci_conf[0x9f] = 0xff;
dev->pci_conf[0xa0] = 0xff;
dev->pci_conf[0xa1] = 0x00;
dev->pci_conf[0xa2] = 0xff;
dev->pci_conf[0xa3] = 0x00;
cpu_cache_ext_enabled = 0;
cpu_update_waitstates();
sis_5571_smram_recalc(dev);
sis_5571_shadow_recalc(dev);
flushmmucache();
}
static void
sis_5571_host_to_pci_close(void *priv)
{
sis_5571_host_to_pci_t *dev = (sis_5571_host_to_pci_t *) priv;
smram_del(dev->smram);
free(dev);
}
static void *
sis_5571_host_to_pci_init(UNUSED(const device_t *info))
{
sis_5571_host_to_pci_t *dev = (sis_5571_host_to_pci_t *) calloc(1, sizeof(sis_5571_host_to_pci_t));
dev->sis = device_get_common_priv();
/* SMRAM */
dev->smram = smram_add();
sis_5571_host_to_pci_reset(dev);
return dev;
}
const device_t sis_5571_h2p_device = {
.name = "SiS 5571 Host to PCI bridge",
.internal_name = "sis_5571_host_to_pci",
.flags = DEVICE_PCI,
.local = 0x00,
.init = sis_5571_host_to_pci_init,
.close = sis_5571_host_to_pci_close,
.reset = sis_5571_host_to_pci_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

772
src/chipset/sis_5571_old.c Normal file
View File

@@ -0,0 +1,772 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Implementation of the SiS 5571 Chipset.
*
*
*
* Authors: Tiseno100,
*
* Copyright 2021 Tiseno100.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/dma.h>
#include <86box/mem.h>
#include <86box/pci.h>
#include <86box/pic.h>
#include <86box/plat_unused.h>
#include <86box/port_92.h>
#include <86box/hdc_ide.h>
#include <86box/hdc_ide_sff8038i.h>
#include <86box/smram.h>
#include <86box/usb.h>
#include <86box/chipset.h>
/* Shadow RAM */
#define LSB_READ ((dev->pci_conf[0x70 + (cur_reg & 0x07)] & 0x08) ? MEM_READ_INTERNAL : MEM_READ_EXTANY)
#define LSB_WRITE ((dev->pci_conf[0x70 + (cur_reg & 0x07)] & 0x02) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)
#define MSB_READ ((dev->pci_conf[0x70 + (cur_reg & 0x07)] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY)
#define MSB_WRITE ((dev->pci_conf[0x70 + (cur_reg & 0x07)] & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)
#define SYSTEM_READ ((dev->pci_conf[0x76] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY)
#define SYSTEM_WRITE ((dev->pci_conf[0x76] & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)
/* IDE Flags (1 Native / 0 Compatibility)*/
#define PRIMARY_COMP_NAT_SWITCH (dev->pci_conf_sb[1][9] & 1)
#define SECONDARY_COMP_NAT_SWITCH (dev->pci_conf_sb[1][9] & 4)
#define PRIMARY_NATIVE_BASE (dev->pci_conf_sb[1][0x11] << 8) | (dev->pci_conf_sb[1][0x10] & 0xf8)
#define PRIMARY_NATIVE_SIDE (((dev->pci_conf_sb[1][0x15] << 8) | (dev->pci_conf_sb[1][0x14] & 0xfc)) + 2)
#define SECONDARY_NATIVE_BASE (dev->pci_conf_sb[1][0x19] << 8) | (dev->pci_conf_sb[1][0x18] & 0xf8)
#define SECONDARY_NATIVE_SIDE (((dev->pci_conf_sb[1][0x1d] << 8) | (dev->pci_conf_sb[1][0x1c] & 0xfc)) + 2)
#define BUS_MASTER_BASE ((dev->pci_conf_sb[1][0x20] & 0xf0) | (dev->pci_conf_sb[1][0x21] << 8))
#ifdef ENABLE_SIS_5571_LOG
int sis_5571_do_log = ENABLE_SIS_5571_LOG;
static void
sis_5571_log(const char *fmt, ...)
{
va_list ap;
if (sis_5571_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define sis_5571_log(fmt, ...)
#endif
typedef struct sis_5571_t {
uint8_t nb_slot;
uint8_t sb_slot;
uint8_t pad;
uint8_t usb_irq_state;
uint8_t pci_conf[256];
uint8_t pci_conf_sb[3][256];
port_92_t *port_92;
sff8038i_t *ide_drive[2];
smram_t *smram;
usb_t *usb;
} sis_5571_t;
static void
sis_5571_shadow_recalc(int cur_reg, sis_5571_t *dev)
{
if (cur_reg != 0x76) {
mem_set_mem_state_both(0xc0000 + (0x8000 * (cur_reg & 0x07)), 0x4000, LSB_READ | LSB_WRITE);
mem_set_mem_state_both(0xc4000 + (0x8000 * (cur_reg & 0x07)), 0x4000, MSB_READ | MSB_WRITE);
} else
mem_set_mem_state_both(0xf0000, 0x10000, SYSTEM_READ | SYSTEM_WRITE);
flushmmucache_nopc();
}
static void
sis_5571_smm_recalc(sis_5571_t *dev)
{
smram_disable_all();
switch ((dev->pci_conf[0xa3] & 0xc0) >> 6) {
case 0x00:
smram_enable(dev->smram, 0xe0000, 0xe0000, 0x8000, (dev->pci_conf[0xa3] & 0x10), 1);
break;
case 0x01:
smram_enable(dev->smram, 0xe0000, 0xa0000, 0x8000, (dev->pci_conf[0xa3] & 0x10), 1);
break;
case 0x02:
smram_enable(dev->smram, 0xe0000, 0xb0000, 0x8000, (dev->pci_conf[0xa3] & 0x10), 1);
break;
case 0x03:
smram_enable(dev->smram, 0xa0000, 0xa0000, 0x10000, (dev->pci_conf[0xa3] & 0x10), 1);
break;
default:
break;
}
flushmmucache();
}
void
sis_5571_ide_handler(sis_5571_t *dev)
{
ide_pri_disable();
ide_sec_disable();
if (dev->pci_conf_sb[1][4] & 1) {
if (dev->pci_conf_sb[1][0x4a] & 4) {
ide_set_base(0, PRIMARY_COMP_NAT_SWITCH ? PRIMARY_NATIVE_BASE : 0x1f0);
ide_set_side(0, PRIMARY_COMP_NAT_SWITCH ? PRIMARY_NATIVE_SIDE : 0x3f6);
ide_pri_enable();
}
if (dev->pci_conf_sb[1][0x4a] & 2) {
ide_set_base(1, SECONDARY_COMP_NAT_SWITCH ? SECONDARY_NATIVE_BASE : 0x170);
ide_set_side(1, SECONDARY_COMP_NAT_SWITCH ? SECONDARY_NATIVE_SIDE : 0x376);
ide_sec_enable();
}
}
}
void
sis_5571_bm_handler(sis_5571_t *dev)
{
sff_bus_master_handler(dev->ide_drive[0], dev->pci_conf_sb[1][4] & 4, BUS_MASTER_BASE);
sff_bus_master_handler(dev->ide_drive[1], dev->pci_conf_sb[1][4] & 4, BUS_MASTER_BASE + 8);
}
static void
memory_pci_bridge_write(UNUSED(int func), int addr, uint8_t val, void *priv)
{
sis_5571_t *dev = (sis_5571_t *) priv;
switch (addr) {
case 0x04: /* Command - low byte */
case 0x05: /* Command - high byte */
dev->pci_conf[addr] |= val;
break;
case 0x06: /* Status - Low Byte */
dev->pci_conf[addr] &= val;
break;
case 0x07: /* Status - High Byte */
dev->pci_conf[addr] &= val & 0xbe;
break;
case 0x0d: /* Master latency timer */
dev->pci_conf[addr] = val;
break;
case 0x50: /* Host Interface and DRAM arbiter */
dev->pci_conf[addr] = val & 0xec;
break;
case 0x51: /* CACHE */
dev->pci_conf[addr] = val;
cpu_cache_ext_enabled = !!(val & 0x40);
cpu_update_waitstates();
break;
case 0x52:
dev->pci_conf[addr] = val & 0xd0;
break;
case 0x53: /* DRAM */
dev->pci_conf[addr] = val & 0xfe;
break;
case 0x54: /* FP/EDO */
dev->pci_conf[addr] = val;
break;
case 0x55:
dev->pci_conf[addr] = val & 0xe0;
break;
case 0x56: /* MDLE delay */
case 0x57: /* SDRAM */
dev->pci_conf[addr] = val & 0xf8;
break;
case 0x59: /* Buffer strength and current rating */
dev->pci_conf[addr] = val;
break;
case 0x5a:
dev->pci_conf[addr] = val & 0x03;
break;
case 0x60: /* Undocumented */
case 0x61: /* Undocumented */
case 0x62: /* Undocumented */
case 0x63: /* Undocumented */
case 0x64: /* Undocumented */
case 0x65: /* Undocumented */
case 0x66: /* Undocumented */
case 0x67: /* Undocumented */
case 0x68: /* Undocumented */
case 0x69: /* Undocumented */
case 0x6a: /* Undocumented */
case 0x6b: /* Undocumented */
dev->pci_conf[addr] = val;
break;
case 0x70:
case 0x71:
case 0x72:
case 0x73:
case 0x74:
case 0x75:
case 0x76: /* Attribute of shadow RAM for BIOS area */
dev->pci_conf[addr] = val & ((addr != 0x76) ? 0xee : 0xe8);
sis_5571_shadow_recalc(addr, dev);
sis_5571_smm_recalc(dev);
break;
case 0x77: /* Characteristics of non-cacheable area */
dev->pci_conf[addr] = val & 0x0f;
break;
case 0x78: /* Allocation of Non-Cacheable area #1 */
case 0x79: /* NCA1REG2 */
case 0x7a: /* Allocation of Non-Cacheable area #2 */
case 0x7b: /* NCA2REG2 */
dev->pci_conf[addr] = val;
break;
case 0x80: /* PCI master characteristics */
dev->pci_conf[addr] = val & 0xfe;
break;
case 0x81:
dev->pci_conf[addr] = val & 0xcc;
break;
case 0x82:
dev->pci_conf[addr] = val;
break;
case 0x83: /* CPU to PCI characteristics */
dev->pci_conf[addr] = val;
port_92_set_features(dev->port_92, !!(val & 0x40), !!(val & 0x80));
break;
case 0x84:
case 0x85:
case 0x86:
dev->pci_conf[addr] = val;
break;
case 0x87: /* Miscellanea */
dev->pci_conf[addr] = val & 0xf8;
break;
case 0x90: /* PMU control register */
case 0x91: /* Address trap for green function */
case 0x92:
dev->pci_conf[addr] = val;
break;
case 0x93: /* STPCLK# and APM SMI control */
dev->pci_conf[addr] = val;
if ((dev->pci_conf[0x9b] & 1) && !!(val & 2)) {
smi_raise();
dev->pci_conf[0x9d] |= 1;
}
break;
case 0x94: /* 6x86 and Green function control */
dev->pci_conf[addr] = val & 0xf8;
break;
case 0x95: /* Test mode control */
case 0x96: /* Time slot and Programmable 10-bit I/O port definition */
dev->pci_conf[addr] = val & 0xfb;
break;
case 0x97: /* programmable 10-bit I/O port address */
case 0x98: /* Programmable 16-bit I/O port */
case 0x99:
case 0x9a:
case 0x9b:
case 0x9c:
dev->pci_conf[addr] = val;
break;
case 0x9d:
dev->pci_conf[addr] &= val;
break;
case 0x9e: /* STPCLK# Assertion Timer */
case 0x9f: /* STPCLK# De-assertion Timer */
case 0xa0:
case 0xa1:
case 0xa2:
dev->pci_conf[addr] = val;
break;
case 0xa3: /* SMRAM access control and Power supply control */
dev->pci_conf[addr] = val & 0xd0;
sis_5571_smm_recalc(dev);
break;
default:
break;
}
sis_5571_log("SiS5571: dev->pci_conf[%02x] = %02x\n", addr, val);
}
static uint8_t
memory_pci_bridge_read(UNUSED(int func), int addr, void *priv)
{
const sis_5571_t *dev = (sis_5571_t *) priv;
sis_5571_log("SiS5571: dev->pci_conf[%02x] (%02x)\n", addr, dev->pci_conf[addr]);
return dev->pci_conf[addr];
}
static void
pci_isa_bridge_write(int func, int addr, uint8_t val, void *priv)
{
sis_5571_t *dev = (sis_5571_t *) priv;
switch (func) {
case 0: /* Bridge */
switch (addr) {
case 0x04: /* Command */
dev->pci_conf_sb[0][addr] |= val & 0x0f;
break;
case 0x06: /* Status */
dev->pci_conf_sb[0][addr] &= val;
break;
case 0x40: /* BIOS Control Register */
dev->pci_conf_sb[0][addr] = val & 0x3f;
break;
case 0x41: /* INTA# Remapping Control Register */
case 0x42: /* INTB# Remapping Control Register */
case 0x43: /* INTC# Remapping Control Register */
case 0x44: /* INTD# Remapping Control Register */
dev->pci_conf_sb[0][addr] = val & 0x8f;
pci_set_irq_routing((addr & 0x07), !(val & 0x80) ? (val & 0x0f) : PCI_IRQ_DISABLED);
break;
case 0x45:
dev->pci_conf_sb[0][addr] = val & 0xec;
switch ((val & 0xc0) >> 6) {
case 0:
cpu_set_isa_speed(7159091);
break;
case 1:
cpu_set_isa_pci_div(4);
break;
case 2:
cpu_set_isa_pci_div(3);
break;
default:
break;
}
break;
case 0x46:
dev->pci_conf_sb[0][addr] = val & 0xec;
break;
case 0x47: /* DMA Clock and Wait State Control Register */
dev->pci_conf_sb[0][addr] = val & 0x3e;
break;
case 0x48: /* ISA Master/DMA Memory Cycle Control Register 1 */
case 0x49: /* ISA Master/DMA Memory Cycle Control Register 2 */
case 0x4a: /* ISA Master/DMA Memory Cycle Control Register 3 */
case 0x4b: /* ISA Master/DMA Memory Cycle Control Register 4 */
dev->pci_conf_sb[0][addr] = val;
break;
case 0x4c:
case 0x4d:
case 0x4e:
case 0x4f:
case 0x50:
case 0x51:
case 0x52:
case 0x53:
case 0x54:
case 0x55:
case 0x56:
case 0x57:
case 0x58:
case 0x59:
case 0x5a:
case 0x5b:
case 0x5c:
case 0x5d:
case 0x5e:
dev->pci_conf_sb[0][addr] = val;
break;
case 0x5f:
dev->pci_conf_sb[0][addr] = val & 0x3f;
break;
case 0x60:
dev->pci_conf_sb[0][addr] = val;
break;
case 0x61: /* MIRQ Remapping Control Register */
dev->pci_conf_sb[0][addr] = val;
pci_set_mirq_routing(PCI_MIRQ0, !(val & 0x80) ? (val & 0x0f) : PCI_IRQ_DISABLED);
break;
case 0x62: /* On-board Device DMA Control Register */
dev->pci_conf_sb[0][addr] = val & 0x0f;
dma_set_drq((val & 0x07), 1);
break;
case 0x63: /* IDEIRQ Remapping Control Register */
dev->pci_conf_sb[0][addr] = val & 0x8f;
if (val & 0x80) {
sff_set_irq_line(dev->ide_drive[0], val & 0x0f);
sff_set_irq_line(dev->ide_drive[1], val & 0x0f);
}
break;
case 0x64: /* GPIO Control Register */
dev->pci_conf_sb[0][addr] = val & 0xef;
break;
case 0x65:
dev->pci_conf_sb[0][addr] = val & 0x1b;
break;
case 0x66: /* GPIO Output Mode Control Register */
case 0x67: /* GPIO Output Mode Control Register */
dev->pci_conf_sb[0][addr] = val;
break;
case 0x68: /* USBIRQ Remapping Control Register */
dev->pci_conf_sb[0][addr] = val & 0x1b;
break;
case 0x69:
dev->pci_conf_sb[0][addr] = val;
break;
case 0x6a:
dev->pci_conf_sb[0][addr] = val & 0xfc;
break;
case 0x6b:
dev->pci_conf_sb[0][addr] = val;
break;
case 0x6c:
dev->pci_conf_sb[0][addr] = val & 0x03;
break;
case 0x6e: /* Software-Controlled Interrupt Request, Channels 7-0 */
case 0x6f: /* Software-Controlled Interrupt Request, channels 15-8 */
dev->pci_conf_sb[0][addr] = val;
break;
case 0x70:
dev->pci_conf_sb[0][addr] = val & 0xde;
break;
case 0x71: /* Type-F DMA Control Register */
dev->pci_conf_sb[0][addr] = val & 0xfe;
break;
case 0x72: /* SMI Triggered By IRQ/GPIO Control */
case 0x73: /* SMI Triggered By IRQ/GPIO Control */
dev->pci_conf_sb[0][addr] = (addr == 0x72) ? val & 0xfe : val;
break;
case 0x74: /* System Standby Timer Reload, System Standby State Exit And Throttling State Exit Control */
case 0x75: /* System Standby Timer Reload, System Standby State Exit And Throttling State Exit Control */
case 0x76: /* Monitor Standby Timer Reload And Monitor Standby State ExitControl */
case 0x77: /* Monitor Standby Timer Reload And Monitor Standby State ExitControl */
dev->pci_conf_sb[0][addr] = val;
break;
default:
break;
}
sis_5571_log("SiS5571-SB: dev->pci_conf[%02x] = %02x\n", addr, val);
break;
case 1: /* IDE Controller */
switch (addr) {
case 0x04: /* Command low byte */
dev->pci_conf_sb[1][addr] = val & 0x05;
sis_5571_ide_handler(dev);
sis_5571_bm_handler(dev);
break;
case 0x07: /* Status high byte */
dev->pci_conf_sb[1][addr] &= val;
break;
case 0x09: /* Programming Interface Byte */
dev->pci_conf_sb[1][addr] = val & 0xcf;
sis_5571_ide_handler(dev);
break;
case 0x0d: /* Latency Time */
case 0x10: /* Primary Channel Base Address Register */
case 0x11: /* Primary Channel Base Address Register */
case 0x12: /* Primary Channel Base Address Register */
case 0x13: /* Primary Channel Base Address Register */
case 0x14: /* Primary Channel Base Address Register */
case 0x15: /* Primary Channel Base Address Register */
case 0x16: /* Primary Channel Base Address Register */
case 0x17: /* Primary Channel Base Address Register */
case 0x18: /* Secondary Channel Base Address Register */
case 0x19: /* Secondary Channel Base Address Register */
case 0x1a: /* Secondary Channel Base Address Register */
case 0x1b: /* Secondary Channel Base Address Register */
case 0x1c: /* Secondary Channel Base Address Register */
case 0x1d: /* Secondary Channel Base Address Register */
case 0x1e: /* Secondary Channel Base Address Register */
case 0x1f: /* Secondary Channel Base Address Register */
dev->pci_conf_sb[1][addr] = val;
sis_5571_ide_handler(dev);
break;
case 0x20: /* Bus Master IDE Control Register Base Address */
case 0x21: /* Bus Master IDE Control Register Base Address */
case 0x22: /* Bus Master IDE Control Register Base Address */
case 0x23: /* Bus Master IDE Control Register Base Address */
dev->pci_conf_sb[1][addr] = val;
sis_5571_bm_handler(dev);
break;
case 0x30: /* Expansion ROM Base Address */
case 0x31: /* Expansion ROM Base Address */
case 0x32: /* Expansion ROM Base Address */
case 0x33: /* Expansion ROM Base Address */
case 0x40: /* IDE Primary Channel/Master Drive Data Recovery Time Control */
case 0x41: /* IDE Primary Channel/Master Drive DataActive Time Control */
case 0x42: /* IDE Primary Channel/Slave Drive Data Recovery Time Control */
case 0x43: /* IDE Primary Channel/Slave Drive Data Active Time Control */
case 0x44: /* IDE Secondary Channel/Master Drive Data Recovery Time Control */
case 0x45: /* IDE Secondary Channel/Master Drive Data Active Time Control */
case 0x46: /* IDE Secondary Channel/Slave Drive Data Recovery Time Control */
case 0x47: /* IDE Secondary Channel/Slave Drive Data Active Time Control */
case 0x48: /* IDE Command Recovery Time Control */
case 0x49: /* IDE Command Active Time Control */
dev->pci_conf_sb[1][addr] = val;
break;
case 0x4a: /* IDE General Control Register 0 */
dev->pci_conf_sb[1][addr] = val & 0xaf;
sis_5571_ide_handler(dev);
break;
case 0x4b: /* IDE General Control register 1 */
case 0x4c: /* Prefetch Count of Primary Channel (Low Byte) */
case 0x4d: /* Prefetch Count of Primary Channel (High Byte) */
case 0x4e: /* Prefetch Count of Secondary Channel (Low Byte) */
case 0x4f: /* Prefetch Count of Secondary Channel (High Byte) */
dev->pci_conf_sb[1][addr] = val;
break;
default:
break;
}
sis_5571_log("SiS5571-IDE: dev->pci_conf[%02x] = %02x\n", addr, val);
break;
case 2: /* USB Controller */
switch (addr) {
case 0x04: /* Command - Low Byte */
dev->pci_conf_sb[2][addr] = val;
ohci_update_mem_mapping(dev->usb, dev->pci_conf_sb[2][0x11], dev->pci_conf_sb[2][0x12], dev->pci_conf_sb[2][0x13], dev->pci_conf_sb[2][4] & 1);
break;
case 0x05: /* Command - High Byte */
dev->pci_conf_sb[2][addr] = val & 0x03;
break;
case 0x06: /* Status - Low Byte */
dev->pci_conf_sb[2][addr] &= val & 0xc0;
break;
case 0x07: /* Status - High Byte */
dev->pci_conf_sb[2][addr] &= val;
break;
case 0x10: /* Memory Space Base Address Register */
case 0x11: /* Memory Space Base Address Register */
case 0x12: /* Memory Space Base Address Register */
case 0x13: /* Memory Space Base Address Register */
dev->pci_conf_sb[2][addr] = val & ((addr == 0x11) ? 0x0f : 0xff);
ohci_update_mem_mapping(dev->usb, dev->pci_conf_sb[2][0x11], dev->pci_conf_sb[2][0x12], dev->pci_conf_sb[2][0x13], dev->pci_conf_sb[2][4] & 1);
break;
case 0x14: /* IO Space Base Address Register */
case 0x15: /* IO Space Base Address Register */
case 0x16: /* IO Space Base Address Register */
case 0x17: /* IO Space Base Address Register */
case 0x3c: /* Interrupt Line */
dev->pci_conf_sb[2][addr] = val;
break;
default:
break;
}
sis_5571_log("SiS5571-USB: dev->pci_conf[%02x] = %02x\n", addr, val);
break;
default:
break;
}
}
static uint8_t
pci_isa_bridge_read(int func, int addr, void *priv)
{
const sis_5571_t *dev = (sis_5571_t *) priv;
switch (func) {
case 0:
sis_5571_log("SiS5571-SB: dev->pci_conf[%02x] (%02x)\n", addr, dev->pci_conf_sb[0][addr]);
return dev->pci_conf_sb[0][addr];
case 1:
sis_5571_log("SiS5571-IDE: dev->pci_conf[%02x] (%02x)\n", addr, dev->pci_conf_sb[1][addr]);
return dev->pci_conf_sb[1][addr];
case 2:
sis_5571_log("SiS5571-USB: dev->pci_conf[%02x] (%02x)\n", addr, dev->pci_conf_sb[2][addr]);
return dev->pci_conf_sb[2][addr];
default:
return 0xff;
}
}
static void
sis_5571_reset(void *priv)
{
sis_5571_t *dev = (sis_5571_t *) priv;
/* Memory/PCI Bridge */
dev->pci_conf[0x00] = 0x39;
dev->pci_conf[0x01] = 0x10;
dev->pci_conf[0x02] = 0x71;
dev->pci_conf[0x03] = 0x55;
dev->pci_conf[0x04] = 0xfd;
dev->pci_conf[0x0b] = 0x06;
dev->pci_conf[0x9e] = 0xff;
dev->pci_conf[0x9f] = 0xff;
dev->pci_conf[0xa2] = 0xff;
/* PCI to ISA bridge */
dev->pci_conf_sb[0][0x00] = 0x39;
dev->pci_conf_sb[0][0x01] = 0x10;
dev->pci_conf_sb[0][0x02] = 0x08;
dev->pci_conf_sb[0][0x04] = 0xfd;
dev->pci_conf_sb[0][0x08] = 0x01;
dev->pci_conf_sb[0][0x0a] = 0x01;
dev->pci_conf_sb[0][0x0b] = 0x06;
/* IDE Controller */
dev->pci_conf_sb[1][0x00] = 0x39;
dev->pci_conf_sb[1][0x01] = 0x10;
dev->pci_conf_sb[1][0x02] = 0x13;
dev->pci_conf_sb[1][0x03] = 0x55;
dev->pci_conf_sb[1][0x08] = 0xc0;
dev->pci_conf_sb[1][0x0a] = 0x01;
dev->pci_conf_sb[1][0x0b] = 0x01;
dev->pci_conf_sb[1][0x0e] = 0x80;
dev->pci_conf_sb[1][0x4a] = 0x06;
sff_set_slot(dev->ide_drive[0], dev->sb_slot);
sff_set_slot(dev->ide_drive[1], dev->sb_slot);
sff_bus_master_reset(dev->ide_drive[0]);
sff_bus_master_reset(dev->ide_drive[1]);
/* USB Controller */
dev->pci_conf_sb[2][0x00] = 0x39;
dev->pci_conf_sb[2][0x01] = 0x10;
dev->pci_conf_sb[2][0x02] = 0x01;
dev->pci_conf_sb[2][0x03] = 0x70;
dev->pci_conf_sb[2][0x08] = 0xb0;
dev->pci_conf_sb[2][0x09] = 0x10;
dev->pci_conf_sb[2][0x0a] = 0x03;
dev->pci_conf_sb[2][0x0b] = 0xc0;
dev->pci_conf_sb[2][0x0e] = 0x80;
dev->pci_conf_sb[2][0x14] = 0x01;
dev->pci_conf_sb[2][0x3d] = 0x01;
}
static void
sis_5571_close(void *priv)
{
sis_5571_t *dev = (sis_5571_t *) priv;
smram_del(dev->smram);
free(dev);
}
static void *
sis_5571_init(UNUSED(const device_t *info))
{
sis_5571_t *dev = (sis_5571_t *) malloc(sizeof(sis_5571_t));
memset(dev, 0x00, sizeof(sis_5571_t));
pci_add_card(PCI_ADD_NORTHBRIDGE, memory_pci_bridge_read, memory_pci_bridge_write, dev, &dev->nb_slot);
pci_add_card(PCI_ADD_SOUTHBRIDGE, pci_isa_bridge_read, pci_isa_bridge_write, dev, &dev->sb_slot);
/* MIRQ */
pci_enable_mirq(0);
/* Port 92 & SMRAM */
dev->port_92 = device_add(&port_92_pci_device);
dev->smram = smram_add();
/* SFF IDE */
dev->ide_drive[0] = device_add_inst(&sff8038i_device, 1);
dev->ide_drive[1] = device_add_inst(&sff8038i_device, 2);
/* USB */
dev->usb = device_add(&usb_device);
sis_5571_reset(dev);
return dev;
}
const device_t sis_5571_device = {
.name = "SiS 5571",
.internal_name = "sis_5571",
.flags = DEVICE_PCI,
.local = 0,
.init = sis_5571_init,
.close = sis_5571_close,
.reset = sis_5571_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

323
src/chipset/sis_5572_usb.c Normal file
View File

@@ -0,0 +1,323 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* 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 5572 USB controller.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2024 Miran Grca.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/dma.h>
#include <86box/mem.h>
#include <86box/nvr.h>
#include <86box/hdd.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/hdc_ide_sff8038i.h>
#include <86box/pci.h>
#include <86box/pic.h>
#include <86box/pit.h>
#include <86box/pit_fast.h>
#include <86box/plat.h>
#include <86box/plat_unused.h>
#include <86box/port_92.h>
#include <86box/smram.h>
#include <86box/spd.h>
#include <86box/apm.h>
#include <86box/ddma.h>
#include <86box/acpi.h>
#include <86box/smbus.h>
#include <86box/sis_55xx.h>
#include <86box/chipset.h>
#include <86box/usb.h>
#ifdef ENABLE_SIS_5572_USB_LOG
int sis_5572_usb_do_log = ENABLE_SIS_5572_USB_LOG;
static void
sis_5572_usb_log(const char *fmt, ...)
{
va_list ap;
if (sis_5572_usb_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define sis_5572_usb_log(fmt, ...)
#endif
typedef struct sis_5572_usb_t {
uint8_t rev;
uint8_t usb_unk_regs[256];
uint8_t pci_conf[256];
uint16_t usb_unk_base;
usb_t *usb;
sis_55xx_common_t *sis;
} sis_5572_usb_t;
/* SiS 5572 unknown I/O port (second USB PCI BAR). */
static void
sis_5572_usb_unk_write(uint16_t addr, uint8_t val, void *priv)
{
sis_5572_usb_t *dev = (sis_5572_usb_t *) priv;
addr = (addr - dev->usb_unk_base) & 0x07;
sis_5572_usb_log("SiS 5572 USB UNK: [W] dev->usb_unk_regs[%02X] = %02X\n", addr, val);
dev->usb_unk_regs[addr] = val;
}
static uint8_t
sis_5572_usb_unk_read(uint16_t addr, void *priv)
{
const sis_5572_usb_t *dev = (sis_5572_usb_t *) priv;
uint8_t ret = 0xff;
addr = (addr - dev->usb_unk_base) & 0x07;
ret = dev->usb_unk_regs[addr & 0x07];
sis_5572_usb_log("SiS 5572 USB UNK: [R] dev->usb_unk_regs[%02X] = %02X\n", addr, ret);
return ret;
}
void
sis_5572_usb_write(int addr, uint8_t val, void *priv)
{
sis_5572_usb_t *dev = (sis_5572_usb_t *) priv;
sis_5572_usb_log("SiS 5572 USB: [W] dev->pci_conf[%02X] = %02X\n", addr, val);
if (dev->sis->usb_enabled) switch (addr) {
default:
break;
case 0x04: /* Command - Low Byte */
if (dev->rev == 0xb0)
dev->pci_conf[addr] = val & 0x47;
else
dev->pci_conf[addr] = val & 0x57;
if (dev->usb_unk_base != 0x0000) {
io_removehandler(dev->usb_unk_base, 0x0002,
sis_5572_usb_unk_read, NULL, NULL,
sis_5572_usb_unk_write, NULL, NULL, dev);
if (dev->pci_conf[0x04] & 0x01)
io_sethandler(dev->usb_unk_base, 0x0002,
sis_5572_usb_unk_read, NULL, NULL,
sis_5572_usb_unk_write, NULL, NULL, dev);
}
ohci_update_mem_mapping(dev->usb,
dev->pci_conf[0x11], dev->pci_conf[0x12],
dev->pci_conf[0x13], dev->pci_conf[0x04] & 0x02);
break;
case 0x05: /* Command - High Byte */
dev->pci_conf[addr] = val & 0x01;
break;
case 0x07: /* Status - High Byte */
dev->pci_conf[addr] &= ~(val & 0xf9);
break;
case 0x0d: /* Latency Timer */
dev->pci_conf[addr] = val;
break;
case 0x11 ... 0x13: /* Memory Space Base Address Register */
dev->pci_conf[addr] = val & ((addr == 0x11) ? 0xf0 : 0xff);
ohci_update_mem_mapping(dev->usb,
dev->pci_conf[0x11], dev->pci_conf[0x12],
dev->pci_conf[0x13], dev->pci_conf[4] & 0x02);
break;
case 0x14 ... 0x15: /* IO Space Base Address Register */
if (dev->rev == 0xb0) {
if (dev->usb_unk_base != 0x0000) {
io_removehandler(dev->usb_unk_base, 0x0002,
sis_5572_usb_unk_read, NULL, NULL,
sis_5572_usb_unk_write, NULL, NULL, dev);
}
dev->pci_conf[addr] = val;
dev->usb_unk_base = (dev->pci_conf[0x14] & 0xf8) |
(dev->pci_conf[0x15] << 8);
if (dev->usb_unk_base != 0x0000) {
io_sethandler(dev->usb_unk_base, 0x0002,
sis_5572_usb_unk_read, NULL, NULL,
sis_5572_usb_unk_write, NULL, NULL, dev);
}
}
break;
case 0x2c ... 0x2f:
if (dev->rev == 0x11)
dev->pci_conf[addr] = val;
break;
case 0x3c: /* Interrupt Line */
dev->pci_conf[addr] = val;
break;
}
}
uint8_t
sis_5572_usb_read(int addr, void *priv)
{
const sis_5572_usb_t *dev = (sis_5572_usb_t *) priv;
uint8_t ret = 0xff;
if (dev->sis->usb_enabled) {
ret = dev->pci_conf[addr];
sis_5572_usb_log("SiS 5572 USB: [R] dev->pci_conf[%02X] = %02X\n", addr, ret);
}
return ret;
}
static void
sis_5572_usb_reset(void *priv)
{
sis_5572_usb_t *dev = (sis_5572_usb_t *) priv;
dev->pci_conf[0x00] = 0x39;
dev->pci_conf[0x01] = 0x10;
dev->pci_conf[0x02] = 0x01;
dev->pci_conf[0x03] = 0x70;
dev->pci_conf[0x04] = dev->pci_conf[0x05] = 0x00;
dev->pci_conf[0x06] = (dev->rev == 0xb0) ? 0x00 : 0x80;
dev->pci_conf[0x07] = 0x02;
dev->pci_conf[0x08] = dev->rev;
dev->pci_conf[0x09] = 0x10;
dev->pci_conf[0x0a] = 0x03;
dev->pci_conf[0x0b] = 0x0c;
dev->pci_conf[0x0c] = dev->pci_conf[0x0d] = 0x00;
dev->pci_conf[0x0e] = 0x80 /* 0x10 - Datasheet erratum - header type 0x10 is invalid! */;
dev->pci_conf[0x0f] = 0x00;
dev->pci_conf[0x10] = 0x00;
dev->pci_conf[0x11] = 0x00;
dev->pci_conf[0x12] = 0x00;
dev->pci_conf[0x13] = 0x00;
if (dev->rev == 0xb0) {
dev->pci_conf[0x14] = 0x01;
dev->pci_conf[0x15] = 0x00;
dev->pci_conf[0x16] = 0x00;
dev->pci_conf[0x17] = 0x00;
} else if (dev->rev == 0x11) {
dev->pci_conf[0x2c] = 0x00;
dev->pci_conf[0x2d] = 0x00;
dev->pci_conf[0x2e] = 0x00;
dev->pci_conf[0x2f] = 0x00;
}
dev->pci_conf[0x3c] = 0x00;
dev->pci_conf[0x3d] = PCI_INTA;
dev->pci_conf[0x3e] = 0x00;
dev->pci_conf[0x3f] = 0x00;
if (dev->rev == 0xb0) {
ohci_update_mem_mapping(dev->usb,
dev->pci_conf[0x11], dev->pci_conf[0x12],
dev->pci_conf[0x13], dev->pci_conf[0x04] & 0x02);
if (dev->usb_unk_base != 0x0000) {
io_removehandler(dev->usb_unk_base, 0x0002,
sis_5572_usb_unk_read, NULL, NULL,
sis_5572_usb_unk_write, NULL, NULL, dev);
}
dev->usb_unk_base = 0x0000;
memset(dev->usb_unk_regs, 0x00, sizeof(dev->usb_unk_regs));
}
}
static void
sis_5572_usb_close(void *priv)
{
sis_5572_usb_t *dev = (sis_5572_usb_t *) priv;
free(dev);
}
static void *
sis_5572_usb_init(UNUSED(const device_t *info))
{
sis_5572_usb_t *dev = (sis_5572_usb_t *) calloc(1, sizeof(sis_5572_usb_t));
dev->rev = info->local;
dev->sis = device_get_common_priv();
/* USB */
dev->usb = device_add(&usb_device);
sis_5572_usb_reset(dev);
return dev;
}
const device_t sis_5572_usb_device = {
.name = "SiS 5572 USB controller",
.internal_name = "sis_5572_usb",
.flags = DEVICE_PCI,
.local = 0xb0,
.init = sis_5572_usb_init,
.close = sis_5572_usb_close,
.reset = sis_5572_usb_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t sis_5582_usb_device = {
.name = "SiS 5582 USB controller",
.internal_name = "sis_5582_usb",
.flags = DEVICE_PCI,
.local = 0xe0,
.init = sis_5572_usb_init,
.close = sis_5572_usb_close,
.reset = sis_5572_usb_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t sis_5595_usb_device = {
.name = "SiS 5595 USB controller",
.internal_name = "sis_5595_usb",
.flags = DEVICE_PCI,
.local = 0x11,
.init = sis_5572_usb_init,
.close = sis_5572_usb_close,
.reset = sis_5572_usb_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

184
src/chipset/sis_5581.c Normal file
View File

@@ -0,0 +1,184 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* 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 5581/5582 Pentium PCI/ISA Chipset.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2024 Miran Grca.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/mem.h>
#include <86box/nvr.h>
#include <86box/apm.h>
#include <86box/acpi.h>
#include <86box/hdd.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/hdc_ide_sff8038i.h>
#include <86box/pci.h>
#include <86box/pic.h>
#include <86box/pit.h>
#include <86box/pit_fast.h>
#include <86box/plat.h>
#include <86box/plat_unused.h>
#include <86box/port_92.h>
#include <86box/smram.h>
#include <86box/spd.h>
#include <86box/sis_55xx.h>
#include <86box/chipset.h>
#ifdef ENABLE_SIS_5581_LOG
int sis_5581_do_log = ENABLE_SIS_5581_LOG;
static void
sis_5581_log(const char *fmt, ...)
{
va_list ap;
if (sis_5581_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define sis_5581_log(fmt, ...)
#endif
typedef struct sis_5581_t {
uint8_t nb_slot;
uint8_t sb_slot;
void *h2p;
void *p2i;
void *ide;
void *usb;
sis_55xx_common_t *sis;
} sis_5581_t;
static void
sis_5581_write(int func, int addr, uint8_t val, void *priv)
{
const sis_5581_t *dev = (sis_5581_t *) priv;
sis_5581_log("SiS 5581: [W] dev->pci_conf[%02X] = %02X\n", addr, val);
if (func == 0x00)
sis_5581_host_to_pci_write(addr, val, dev->h2p);
}
static uint8_t
sis_5581_read(int func, int addr, void *priv)
{
const sis_5581_t *dev = (sis_5581_t *) priv;
uint8_t ret = 0xff;
if (func == 0x00)
ret = sis_5581_host_to_pci_read(addr, dev->h2p);
sis_5581_log("SiS 5581: [R] dev->pci_conf[%02X] = %02X\n", addr, ret);
return ret;
}
static void
sis_5582_write(int func, int addr, uint8_t val, void *priv)
{
const sis_5581_t *dev = (sis_5581_t *) priv;
sis_5581_log("SiS 5582: [W] dev->pci_conf[%02X] = %02X\n", addr, val);
switch (func) {
case 0x00:
sis_5513_pci_to_isa_write(addr, val, dev->p2i);
break;
case 0x01:
sis_5513_ide_write(addr, val, dev->ide);
break;
case 0x02:
sis_5572_usb_write(addr, val, dev->usb);
break;
}
}
static uint8_t
sis_5582_read(int func, int addr, void *priv)
{
const sis_5581_t *dev = (sis_5581_t *) priv;
uint8_t ret = 0xff;
switch (func) {
case 0x00:
ret = sis_5513_pci_to_isa_read(addr, dev->p2i);
break;
case 0x01:
ret = sis_5513_ide_read(addr, dev->ide);
break;
case 0x02:
ret = sis_5572_usb_read(addr, dev->usb);
break;
}
sis_5581_log("SiS 5582: [R] dev->pci_conf[%02X] = %02X\n", addr, ret);
return ret;
}
static void
sis_5581_close(void *priv)
{
sis_5581_t *dev = (sis_5581_t *) priv;
free(dev);
}
static void *
sis_5581_init(UNUSED(const device_t *info))
{
sis_5581_t *dev = (sis_5581_t *) calloc(1, sizeof(sis_5581_t));
/* Device 0: SiS 5581 */
pci_add_card(PCI_ADD_NORTHBRIDGE, sis_5581_read, sis_5581_write, dev, &dev->nb_slot);
/* Device 1: SiS 5582 */
pci_add_card(PCI_ADD_SOUTHBRIDGE, sis_5582_read, sis_5582_write, dev, &dev->sb_slot);
dev->sis = device_add(&sis_55xx_common_device);
dev->p2i = device_add_linked(&sis_5582_p2i_device, dev->sis);
dev->h2p = device_add_linked(&sis_5581_h2p_device, dev->sis);
dev->ide = device_add_linked(&sis_5582_ide_device, dev->sis);
dev->usb = device_add_linked(&sis_5582_usb_device, dev->sis);
return dev;
}
const device_t sis_5581_device = {
.name = "SiS 5581",
.internal_name = "sis_5581",
.flags = DEVICE_PCI,
.local = 0,
.init = sis_5581_init,
.close = sis_5581_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

552
src/chipset/sis_5581_h2p.c Normal file
View File

@@ -0,0 +1,552 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* 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 5581 Host to PCI bridge.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2024 Miran Grca.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/dma.h>
#include <86box/mem.h>
#include <86box/nvr.h>
#include <86box/hdd.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/hdc_ide_sff8038i.h>
#include <86box/pci.h>
#include <86box/pic.h>
#include <86box/pit.h>
#include <86box/pit_fast.h>
#include <86box/plat.h>
#include <86box/plat_unused.h>
#include <86box/port_92.h>
#include <86box/smram.h>
#include <86box/spd.h>
#include <86box/apm.h>
#include <86box/ddma.h>
#include <86box/acpi.h>
#include <86box/smbus.h>
#include <86box/sis_55xx.h>
#include <86box/chipset.h>
#include <86box/usb.h>
#ifdef ENABLE_SIS_5581_HOST_TO_PCI_LOG
int sis_5581_host_to_pci_do_log = ENABLE_SIS_5581_HOST_TO_PCI_LOG;
static void
sis_5581_host_to_pci_log(const char *fmt, ...)
{
va_list ap;
if (sis_5581_host_to_pci_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define sis_5581_host_to_pci_log(fmt, ...)
#endif
typedef struct {
uint8_t installed;
uint8_t code;
uint32_t phys_size;
} ram_bank_t;
typedef struct sis_5581_io_trap_t {
void *priv;
void *trap;
uint8_t flags, mask;
uint8_t *sts_reg, sts_mask;
uint16_t addr;
} sis_5581_io_trap_t;
typedef struct sis_5581_host_to_pci_t {
uint8_t pci_conf[256];
uint8_t states[7];
ram_bank_t ram_banks[3];
sis_5581_io_trap_t io_traps[10];
sis_55xx_common_t *sis;
smram_t *smram;
} sis_5581_host_to_pci_t;
static uint8_t bank_codes[7] = { 0x00, 0x20, 0x24, 0x22, 0x26, 0x2a, 0x2b };
static uint32_t bank_sizes[7] = { 0x00800000, /* 8 MB */
0x01000000, /* 16 MB */
0x02000000, /* 32 MB */
0x04000000, /* 64 MB */
0x08000000, /* 128 MB */
0x10000000, /* 256 MB */
0x20000000 }; /* 512 MB */
static void
sis_5581_shadow_recalc(sis_5581_host_to_pci_t *dev)
{
int state;
uint32_t base;
for (uint8_t i = 0x70; i <= 0x76; i++) {
if (i == 0x76) {
if ((dev->states[i & 0x0f] ^ dev->pci_conf[i]) & 0xa0) {
state = (dev->pci_conf[i] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
state |= (dev->pci_conf[i] & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
mem_set_mem_state_both(0xf0000, 0x10000, state);
sis_5581_host_to_pci_log("000F0000-000FFFFF\n");
}
} else {
base = ((i & 0x07) << 15) + 0xc0000;
if ((dev->states[i & 0x0f] ^ dev->pci_conf[i]) & 0xa0) {
state = (dev->pci_conf[i] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
state |= (dev->pci_conf[i] & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
mem_set_mem_state_both(base, 0x4000, state);
sis_5581_host_to_pci_log("%08X-%08X\n", base, base + 0x3fff);
}
if ((dev->states[i & 0x0f] ^ dev->pci_conf[i]) & 0x0a) {
state = (dev->pci_conf[i] & 0x08) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
state |= (dev->pci_conf[i] & 0x02) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
mem_set_mem_state_both(base + 0x4000, 0x4000, state);
sis_5581_host_to_pci_log("%08X-%08X\n", base + 0x4000, base + 0x7fff);
}
}
dev->states[i & 0x0f] = dev->pci_conf[i];
}
flushmmucache_nopc();
}
static void
sis_5581_trap_io(UNUSED(int size), UNUSED(uint16_t addr), UNUSED(uint8_t write), UNUSED(uint8_t val),
void *priv)
{
sis_5581_io_trap_t *trap = (sis_5581_io_trap_t *) priv;
sis_5581_host_to_pci_t *dev = (sis_5581_host_to_pci_t *) trap->priv;
trap->sts_reg[0x04] |= trap->sts_mask;
if (trap->sts_reg[0x00] & trap->sts_mask)
acpi_sis5582_pmu_event(dev->sis->acpi);
}
static void
sis_5581_trap_io_mask(int size, uint16_t addr, uint8_t write, uint8_t val, void *priv)
{
sis_5581_io_trap_t *trap = (sis_5581_io_trap_t *) priv;
if ((addr & trap->mask) == (trap->addr & trap->mask))
sis_5581_trap_io(size, addr, write, val, priv);
}
static void
sis_5581_trap_update_devctl(sis_5581_host_to_pci_t *dev, uint8_t trap_id, uint8_t enable,
uint8_t flags, uint8_t mask, uint8_t *sts_reg, uint8_t sts_mask,
uint16_t addr, uint16_t size)
{
sis_5581_io_trap_t *trap = &dev->io_traps[trap_id];
/* Set up Device I/O traps dynamically. */
if (enable && !trap->trap) {
trap->priv = (void *) dev;
trap->flags = flags;
trap->mask = mask;
trap->addr = addr;
if (flags & 0x08)
trap->trap = io_trap_add(sis_5581_trap_io_mask, trap);
else
trap->trap = io_trap_add(sis_5581_trap_io, trap);
trap->sts_reg = sts_reg;
trap->sts_mask = sts_mask;
}
/* Remap I/O trap. */
io_trap_remap(trap->trap, enable, addr, size);
}
static void
sis_5581_trap_update(void *priv)
{
sis_5581_host_to_pci_t *dev = (sis_5581_host_to_pci_t *) priv;
uint8_t trap_id = 0;
uint8_t *fregs = dev->pci_conf;
uint16_t temp;
uint8_t mask;
uint8_t on;
on = fregs[0x9a];
temp = ((fregs[0x96] & 0x02) | (fregs[0x97] << 2)) & 0x03ff;
mask = ~((1 << ((fregs[0x96] >> 3) & 0x07)) - 1);
sis_5581_trap_update_devctl(dev, trap_id++,
on & 0x40, 0x08, mask, &(fregs[0x9c]), 0x40, temp, 0x80);
temp = fregs[0x98] | (fregs[0x99] << 8);
mask = 0xff;
sis_5581_trap_update_devctl(dev, trap_id++,
on & 0x20, 0x08, mask, &(fregs[0x9c]), 0x20, temp, 0x80);
sis_5581_trap_update_devctl(dev, trap_id++,
on & 0x10, 0x00, 0xff, &(fregs[0x9c]), 0x10, 0x378, 0x08);
sis_5581_trap_update_devctl(dev, trap_id++,
on & 0x10, 0x00, 0xff, &(fregs[0x9c]), 0x10, 0x278, 0x08);
sis_5581_trap_update_devctl(dev, trap_id++,
on & 0x08, 0x00, 0xff, &(fregs[0x9c]), 0x08, 0x3f8, 0x08);
sis_5581_trap_update_devctl(dev, trap_id++,
on & 0x04, 0x00, 0xff, &(fregs[0x9c]), 0x04, 0x2f8, 0x08);
sis_5581_trap_update_devctl(dev, trap_id++,
on & 0x02, 0x00, 0xff, &(fregs[0x9c]), 0x02, 0x1f0, 0x08);
sis_5581_trap_update_devctl(dev, trap_id++,
on & 0x01, 0x00, 0xff, &(fregs[0x9c]), 0x01, 0x170, 0x08);
on = fregs[0x9b];
sis_5581_trap_update_devctl(dev, trap_id++,
on & 0x08, 0x00, 0xff, &(fregs[0x9d]), 0x08, 0x064, 0x01);
sis_5581_trap_update_devctl(dev, trap_id++,
on & 0x08, 0x00, 0xff, &(fregs[0x9d]), 0x08, 0x060, 0x01);
}
static void
sis_5581_smram_recalc(sis_5581_host_to_pci_t *dev)
{
smram_disable_all();
switch (dev->pci_conf[0xa3] >> 6) {
case 0:
smram_enable(dev->smram, 0x000e0000, 0x000e0000, 0x8000, dev->pci_conf[0xa3] & 0x10, 1);
break;
case 1:
smram_enable(dev->smram, 0x000e0000, 0x000a0000, 0x8000, dev->pci_conf[0xa3] & 0x10, 1);
break;
case 2:
smram_enable(dev->smram, 0x000e0000, 0x000b0000, 0x8000, dev->pci_conf[0xa3] & 0x10, 1);
break;
case 3:
smram_enable(dev->smram, 0x000a0000, 0x000a0000, 0x10000, dev->pci_conf[0xa3] & 0x10, 1);
break;
default:
break;
}
flushmmucache();
}
void
sis_5581_host_to_pci_write(int addr, uint8_t val, void *priv)
{
sis_5581_host_to_pci_t *dev = (sis_5581_host_to_pci_t *) priv;
sis_5581_host_to_pci_log("SiS 5581 H2P: [W] dev->pci_conf[%02X] = %02X\n", addr, val);
switch (addr) {
default:
break;
case 0x04: /* Command - Low Byte */
dev->pci_conf[addr] = (dev->pci_conf[addr] & 0xfc) | (val & 0x03);
break;
case 0x05: /* Command - High Byte */
dev->pci_conf[addr] = val & 0x02;
break;
case 0x07: /* Status - High Byte */
dev->pci_conf[addr] &= ~(val & 0xb8);
break;
case 0x0d: /* Master latency timer */
case 0x50:
case 0x54:
case 0x56 ... 0x57:
case 0x59:
dev->pci_conf[addr] = val;
break;
case 0x51:
dev->pci_conf[addr] = val;
cpu_cache_ext_enabled = !!(val & 0x40);
cpu_update_waitstates();
break;
case 0x52:
dev->pci_conf[addr] = val & 0xeb;
break;
case 0x53:
case 0x55:
dev->pci_conf[addr] = val & 0xfe;
break;
case 0x58:
dev->pci_conf[addr] = val & 0xfc;
break;
case 0x5a:
dev->pci_conf[addr] = val & 0x03;
break;
case 0x60 ... 0x62:
dev->pci_conf[addr] = dev->ram_banks[addr & 0x0f].code | 0xc0;
break;
case 0x63:
dev->pci_conf[addr] = dev->ram_banks[0].installed |
(dev->ram_banks[1].installed << 1) |
(dev->ram_banks[2].installed << 2);
break;
case 0x70 ... 0x75:
dev->pci_conf[addr] = val & 0xee;
sis_5581_shadow_recalc(dev);
break;
case 0x76:
dev->pci_conf[addr] = val & 0xe8;
sis_5581_shadow_recalc(dev);
break;
case 0x77: /* Characteristics of non-cacheable area */
dev->pci_conf[addr] = val & 0x0f;
break;
case 0x78: /* Allocation of Non-Cacheable area #1 */
case 0x79: /* NCA1REG2 */
case 0x7a: /* Allocation of Non-Cacheable area #2 */
case 0x7b: /* NCA2REG2 */
dev->pci_conf[addr] = val;
break;
case 0x80: /* PCI master characteristics */
dev->pci_conf[addr] = val & 0xfe;
break;
case 0x81:
dev->pci_conf[addr] = val & 0xde;
break;
case 0x82:
dev->pci_conf[addr] = val;
break;
case 0x83: /* CPU to PCI characteristics */
dev->pci_conf[addr] = val;
/* TODO: Implement Fast A20 and Fast reset stuff on the KBC already! */
break;
case 0x84 ... 0x86:
case 0x88 ... 0x8b:
dev->pci_conf[addr] = val;
break;
case 0x87: /* Miscellanea */
dev->pci_conf[addr] = val & 0xfe;
break;
case 0x8c ... 0x92:
case 0x9e ... 0xa2:
dev->pci_conf[addr] = val;
break;
case 0x93:
dev->pci_conf[addr] = val;
if (val & 0x02) {
dev->pci_conf[0x9d] |= 0x01;
if (dev->pci_conf[0x9b] & 0x01)
acpi_sis5582_pmu_event(dev->sis->acpi);
}
break;
case 0x94:
dev->pci_conf[addr] = val & 0xf8;
break;
case 0x95:
dev->pci_conf[addr] = val & 0xfb;
break;
case 0x96:
dev->pci_conf[addr] = val & 0xfb;
sis_5581_trap_update(dev);
break;
case 0x97 ... 0x9b:
dev->pci_conf[addr] = val;
sis_5581_trap_update(dev);
break;
case 0x9c ... 0x9d:
dev->pci_conf[addr] &= ~val;
break;
case 0xa3:
dev->pci_conf[addr] = val;
sis_5581_smram_recalc(dev);
break;
}
}
uint8_t
sis_5581_host_to_pci_read(int addr, void *priv)
{
const sis_5581_host_to_pci_t *dev = (sis_5581_host_to_pci_t *) priv;
uint8_t ret = 0xff;
ret = dev->pci_conf[addr];
sis_5581_host_to_pci_log("SiS 5581 H2P: [R] dev->pci_conf[%02X] = %02X\n", addr, ret);
return ret;
}
static void
sis_5581_host_to_pci_reset(void *priv)
{
sis_5581_host_to_pci_t *dev = (sis_5581_host_to_pci_t *) priv;
dev->pci_conf[0x00] = 0x39;
dev->pci_conf[0x01] = 0x10;
dev->pci_conf[0x02] = 0x97;
dev->pci_conf[0x03] = 0x55;
dev->pci_conf[0x04] = 0x05;
dev->pci_conf[0x05] = dev->pci_conf[0x06] = 0x00;
dev->pci_conf[0x07] = 0x02;
dev->pci_conf[0x08] = 0x02;
dev->pci_conf[0x09] = dev->pci_conf[0x0a] = 0x00;
dev->pci_conf[0x0b] = 0x06;
dev->pci_conf[0x0c] = 0x00;
dev->pci_conf[0x0d] = 0xff;
dev->pci_conf[0x0e] = dev->pci_conf[0x0f] = 0x00;
dev->pci_conf[0x50] = dev->pci_conf[0x51] = 0x00;
dev->pci_conf[0x52] = 0x00;
dev->pci_conf[0x53] = 0x38;
dev->pci_conf[0x54] = 0x54;
dev->pci_conf[0x55] = 0x00;
dev->pci_conf[0x56] = 0x80;
dev->pci_conf[0x57] = dev->pci_conf[0x58] = 0x00;
dev->pci_conf[0x59] = dev->pci_conf[0x5a] = 0x00;
dev->pci_conf[0x60] = dev->pci_conf[0x61] = 0x00;
dev->pci_conf[0x62] = 0x00;
dev->pci_conf[0x63] = 0xff;
dev->pci_conf[0x70] = dev->pci_conf[0x71] = 0x00;
dev->pci_conf[0x72] = dev->pci_conf[0x73] = 0x00;
dev->pci_conf[0x74] = dev->pci_conf[0x75] = 0x00;
dev->pci_conf[0x76] = dev->pci_conf[0x77] = 0x00;
dev->pci_conf[0x78] = dev->pci_conf[0x79] = 0x00;
dev->pci_conf[0x7a] = dev->pci_conf[0x7b] = 0x00;
dev->pci_conf[0x80] = dev->pci_conf[0x81] = 0x00;
dev->pci_conf[0x82] = dev->pci_conf[0x83] = 0x00;
dev->pci_conf[0x84] = dev->pci_conf[0x85] = 0x00;
dev->pci_conf[0x86] = dev->pci_conf[0x87] = 0x00;
dev->pci_conf[0x88] = dev->pci_conf[0x89] = 0x00;
dev->pci_conf[0x8a] = dev->pci_conf[0x8b] = 0x00;
dev->pci_conf[0x90] = dev->pci_conf[0x91] = 0x00;
dev->pci_conf[0x92] = dev->pci_conf[0x93] = 0x00;
dev->pci_conf[0x94] = dev->pci_conf[0x95] = 0x00;
dev->pci_conf[0x96] = dev->pci_conf[0x97] = 0x00;
dev->pci_conf[0x98] = dev->pci_conf[0x99] = 0x00;
dev->pci_conf[0x9a] = dev->pci_conf[0x9b] = 0x00;
dev->pci_conf[0x9c] = dev->pci_conf[0x9d] = 0x00;
dev->pci_conf[0x9e] = dev->pci_conf[0x9f] = 0xff;
dev->pci_conf[0xa0] = 0xff;
dev->pci_conf[0xa1] = 0x00;
dev->pci_conf[0xa2] = 0xff;
dev->pci_conf[0xa3] = 0x00;
cpu_cache_ext_enabled = 0;
cpu_update_waitstates();
sis_5581_shadow_recalc(dev);
sis_5581_trap_update(dev);
sis_5581_smram_recalc(dev);
}
static void
sis_5581_host_to_pci_close(void *priv)
{
sis_5581_host_to_pci_t *dev = (sis_5581_host_to_pci_t *) priv;
smram_del(dev->smram);
free(dev);
}
static void *
sis_5581_host_to_pci_init(UNUSED(const device_t *info))
{
sis_5581_host_to_pci_t *dev = (sis_5581_host_to_pci_t *) calloc(1, sizeof(sis_5581_host_to_pci_t));
uint32_t total_mem = mem_size << 10;
ram_bank_t *rb;
dev->sis = device_get_common_priv();
/* Calculate the physical RAM banks. */
for (uint8_t i = 0; i < 3; i++) {
rb = &(dev->ram_banks[i]);
uint32_t size = 0x00000000;
uint8_t index = 0;
for (int8_t j = 6; j >= 0; j--) {
uint32_t *bs = &(bank_sizes[j]);
if (*bs <= total_mem) {
size = *bs;
index = j;
break;
}
}
if (size != 0x00000000) {
rb->installed = 1;
rb->code = bank_codes[index];
rb->phys_size = size;
total_mem -= size;
} else
rb->installed = 0;
}
/* SMRAM */
dev->smram = smram_add();
sis_5581_host_to_pci_reset(dev);
return dev;
}
const device_t sis_5581_h2p_device = {
.name = "SiS 5581 Host to PCI bridge",
.internal_name = "sis_5581_host_to_pci",
.flags = DEVICE_PCI,
.local = 0x00,
.init = sis_5581_host_to_pci_init,
.close = sis_5581_host_to_pci_close,
.reset = sis_5581_host_to_pci_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

210
src/chipset/sis_5591.c Normal file
View File

@@ -0,0 +1,210 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Implementation of the SiS 5591/5592 Pentium PCI/ISA Chipset.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2024 Miran Grca.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/mem.h>
#include <86box/nvr.h>
#include <86box/apm.h>
#include <86box/acpi.h>
#include <86box/hdd.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/hdc_ide_sff8038i.h>
#include <86box/pci.h>
#include <86box/pic.h>
#include <86box/pit.h>
#include <86box/pit_fast.h>
#include <86box/plat.h>
#include <86box/plat_unused.h>
#include <86box/port_92.h>
#include <86box/smram.h>
#include <86box/spd.h>
#include <86box/sis_55xx.h>
#include <86box/chipset.h>
#ifdef ENABLE_SIS_5591_LOG
int sis_5591_do_log = ENABLE_SIS_5591_LOG;
static void
sis_5591_log(const char *fmt, ...)
{
va_list ap;
if (sis_5591_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define sis_5591_log(fmt, ...)
#endif
typedef struct sis_5591_t {
uint8_t nb_slot;
uint8_t sb_slot;
void *h2p;
void *p2i;
void *ide;
void *usb;
void *pmu;
sis_55xx_common_t *sis;
} sis_5591_t;
static void
sis_5591_write(int func, int addr, uint8_t val, void *priv)
{
const sis_5591_t *dev = (sis_5591_t *) priv;
sis_5591_log("SiS 5591: [W] dev->pci_conf[%02X] = %02X\n", addr, val);
if (func == 0x00)
sis_5591_host_to_pci_write(addr, val, dev->h2p);
else if (func == 0x01)
sis_5513_ide_write(addr, val, dev->ide);
}
static uint8_t
sis_5591_read(int func, int addr, void *priv)
{
const sis_5591_t *dev = (sis_5591_t *) priv;
uint8_t ret = 0xff;
if (func == 0x00)
ret = sis_5591_host_to_pci_read(addr, dev->h2p);
else if (func == 0x01)
ret = sis_5513_ide_read(addr, dev->ide);
sis_5591_log("SiS 5591: [R] dev->pci_conf[%02X] = %02X\n", addr, ret);
return ret;
}
static void
sis_5595_write(int func, int addr, uint8_t val, void *priv)
{
const sis_5591_t *dev = (sis_5591_t *) priv;
sis_5591_log("SiS 5595: [W] dev->pci_conf[%02X] = %02X\n", addr, val);
switch (func) {
case 0x00:
sis_5513_pci_to_isa_write(addr, val, dev->p2i);
break;
case 0x01:
sis_5595_pmu_write(addr, val, dev->pmu);
break;
case 0x02:
sis_5572_usb_write(addr, val, dev->usb);
break;
}
}
static uint8_t
sis_5595_read(int func, int addr, void *priv)
{
const sis_5591_t *dev = (sis_5591_t *) priv;
uint8_t ret = 0xff;
switch (func) {
case 0x00:
ret = sis_5513_pci_to_isa_read(addr, dev->p2i);
break;
case 0x01:
ret = sis_5595_pmu_read(addr, dev->pmu);
break;
case 0x02:
ret = sis_5572_usb_read(addr, dev->usb);
break;
}
sis_5591_log("SiS 5592: [R] dev->pci_conf[%02X] = %02X\n", addr, ret);
return ret;
}
static void
sis_5591_close(void *priv)
{
sis_5591_t *dev = (sis_5591_t *) priv;
free(dev);
}
static void *
sis_5591_init(UNUSED(const device_t *info))
{
sis_5591_t *dev = (sis_5591_t *) calloc(1, sizeof(sis_5591_t));
/* Device 0: SiS 5591 */
pci_add_card(PCI_ADD_NORTHBRIDGE, sis_5591_read, sis_5591_write, dev, &dev->nb_slot);
/* Device 1: SiS 5595 */
pci_add_card(PCI_ADD_SOUTHBRIDGE, sis_5595_read, sis_5595_write, dev, &dev->sb_slot);
dev->sis = device_add(&sis_55xx_common_device);
dev->ide = device_add_linked(&sis_5591_5600_ide_device, dev->sis);
if (info->local)
dev->p2i = device_add_linked(&sis_5595_1997_p2i_device, dev->sis);
else
dev->p2i = device_add_linked(&sis_5595_p2i_device, dev->sis);
dev->h2p = device_add_linked(&sis_5591_h2p_device, dev->sis);
dev->usb = device_add_linked(&sis_5595_usb_device, dev->sis);
if (info->local)
dev->pmu = device_add_linked(&sis_5595_1997_pmu_device, dev->sis);
else
dev->pmu = device_add_linked(&sis_5595_pmu_device, dev->sis);
return dev;
}
const device_t sis_5591_1997_device = {
.name = "SiS 5591 (1997)",
.internal_name = "sis_5591_1997",
.flags = DEVICE_PCI,
.local = 1,
.init = sis_5591_init,
.close = sis_5591_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t sis_5591_device = {
.name = "SiS 5591",
.internal_name = "sis_5591",
.flags = DEVICE_PCI,
.local = 0,
.init = sis_5591_init,
.close = sis_5591_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

493
src/chipset/sis_5591_h2p.c Normal file
View File

@@ -0,0 +1,493 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* 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 5591 Host to PCI bridge.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2024 Miran Grca.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/dma.h>
#include <86box/mem.h>
#include <86box/nvr.h>
#include <86box/hdd.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/hdc_ide_sff8038i.h>
#include <86box/pci.h>
#include <86box/pic.h>
#include <86box/pit.h>
#include <86box/pit_fast.h>
#include <86box/plat.h>
#include <86box/plat_unused.h>
#include <86box/port_92.h>
#include <86box/smram.h>
#include <86box/spd.h>
#include <86box/apm.h>
#include <86box/ddma.h>
#include <86box/acpi.h>
#include <86box/smbus.h>
#include <86box/sis_55xx.h>
#include <86box/chipset.h>
#include <86box/usb.h>
#include <86box/agpgart.h>
#ifdef ENABLE_SIS_5591_HOST_TO_PCI_LOG
int sis_5591_host_to_pci_do_log = ENABLE_SIS_5591_HOST_TO_PCI_LOG;
static void
sis_5591_host_to_pci_log(const char *fmt, ...)
{
va_list ap;
if (sis_5591_host_to_pci_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define sis_5591_host_to_pci_log(fmt, ...)
#endif
typedef struct {
uint8_t installed;
uint8_t code;
uint32_t phys_size;
} ram_bank_t;
typedef struct sis_5591_host_to_pci_t {
uint8_t pci_conf[256];
uint8_t states[7];
uint8_t states_bus[7];
ram_bank_t ram_banks[3];
sis_55xx_common_t *sis;
smram_t *smram;
agpgart_t *agpgart;
} sis_5591_host_to_pci_t;
static uint8_t bank_codes[6] = { 0x00, 0x20, 0x24, 0x22, 0x26, 0x2a };
static uint32_t bank_sizes[6] = { 0x00800000, /* 8 MB */
0x01000000, /* 16 MB */
0x02000000, /* 32 MB */
0x04000000, /* 64 MB */
0x08000000, /* 128 MB */
0x10000000 }; /* 256 MB */
static void
sis_5591_shadow_recalc(sis_5591_host_to_pci_t *dev)
{
uint32_t base;
uint32_t state;
uint8_t val;
for (uint8_t i = 0x70; i <= 0x76; i++) {
if (i == 0x76) {
val = dev->pci_conf[i];
if ((dev->states[i & 0x0f] ^ val) & 0xa0) {
state = (val & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
state |= (val & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
mem_set_mem_state_cpu_both(0xf0000, 0x10000, state);
sis_5591_host_to_pci_log("000F0000-000FFFFF\n");
dev->states[i & 0x0f] = val;
}
if (!(dev->pci_conf[0x76] & 0x08))
val &= 0x5f;
if ((dev->states_bus[i & 0x0f] ^ val) & 0xa0) {
state = (val & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
state |= (val & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
mem_set_mem_state_bus_both(0xf0000, 0x10000, state);
sis_5591_host_to_pci_log("000F0000-000FFFFF\n");
dev->states_bus[i & 0x0f] = val;
}
} else {
base = ((i & 0x07) << 15) + 0xc0000;
val = dev->pci_conf[i];
if ((dev->states[i & 0x0f] ^ val) & 0xa0) {
state = (val & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
state |= (val & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
mem_set_mem_state_cpu_both(base, 0x4000, state);
sis_5591_host_to_pci_log("%08X-%08X\n", base, base + 0x3fff);
dev->states[i & 0x0f] = (dev->states[i & 0x0f] & 0x0f) | (val & 0xf0);
}
if ((dev->states[i & 0x0f] ^ val) & 0x0a) {
state = (val & 0x08) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
state |= (val & 0x02) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
mem_set_mem_state_cpu_both(base + 0x4000, 0x4000, state);
sis_5591_host_to_pci_log("%08X-%08X\n", base + 0x4000, base + 0x7fff);
dev->states[i & 0x0f] = (dev->states[i & 0x0f] & 0xf0) | (val & 0x0f);
}
if (!(dev->pci_conf[0x76] & 0x08))
val &= 0x55;
if ((dev->states_bus[i & 0x0f] ^ val) & 0xa0) {
state = (val & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
state |= (val & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
mem_set_mem_state_bus_both(base, 0x4000, state);
sis_5591_host_to_pci_log("%08X-%08X\n", base, base + 0x3fff);
dev->states_bus[i & 0x0f] = (dev->states_bus[i & 0x0f] & 0x0f) | (val & 0xf0);
}
if ((dev->states_bus[i & 0x0f] ^ val) & 0x0a) {
state = (val & 0x08) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
state |= (val & 0x02) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
mem_set_mem_state_bus_both(base + 0x4000, 0x4000, state);
sis_5591_host_to_pci_log("%08X-%08X\n", base + 0x4000, base + 0x7fff);
dev->states_bus[i & 0x0f] = (dev->states_bus[i & 0x0f] & 0xf0) | (val & 0x0f);
}
}
}
flushmmucache_nopc();
}
static void
sis_5591_smram_recalc(sis_5591_host_to_pci_t *dev)
{
smram_disable_all();
switch (dev->pci_conf[0x68] >> 6) {
case 0:
smram_enable(dev->smram, 0x000e0000, 0x000e0000, 0x8000, dev->pci_conf[0x68] & 0x10, 1);
break;
case 1:
smram_enable(dev->smram, 0x000e0000, 0x000a0000, 0x8000, dev->pci_conf[0x68] & 0x10, 1);
break;
case 2:
smram_enable(dev->smram, 0x000e0000, 0x000b0000, 0x8000, dev->pci_conf[0x68] & 0x10, 1);
break;
case 3:
smram_enable(dev->smram, 0x000a0000, 0x000a0000, 0x10000, dev->pci_conf[0x68] & 0x10, 1);
break;
default:
break;
}
flushmmucache();
}
static void
sis_5591_mask_bar(uint8_t *regs, void *agpgart)
{
uint32_t bar;
uint32_t sizes[8] = { 0x00400000, 0x00800000, 0x01000000, 0x02000000, 0x04000000, 0x08000000,
0x10000000, 0x00000000 } ;
/* Make sure the aperture's base is aligned to its size. */
bar = (regs[0x13] << 24) | (regs[0x12] << 16);
bar &= (sizes[(regs[0x94] >> 4) & 0x07] | 0xf0000000);
regs[0x12] = (bar >> 16) & 0xff;
regs[0x13] = (bar >> 24) & 0xff;
if (!agpgart)
return;
/* Map aperture and GART. */
agpgart_set_aperture(agpgart,
bar,
sizes[(regs[0x94] >> 4) & 0x07],
!!(regs[0x94] & 0x02));
if (regs[0x94] & 0x01)
agpgart_set_gart(agpgart, (regs[0x91] << 8) | (regs[0x92] << 16) | (regs[0x93] << 24));
else
agpgart_set_gart(agpgart, 0x00000000);
}
void
sis_5591_host_to_pci_write(int addr, uint8_t val, void *priv)
{
sis_5591_host_to_pci_t *dev = (sis_5591_host_to_pci_t *) priv;
sis_5591_host_to_pci_log("SiS 5591 H2P: [W] dev->pci_conf[%02X] = %02X\n", addr, val);
switch (addr) {
default:
break;
case 0x04: /* Command - Low Byte */
dev->pci_conf[addr] = (dev->pci_conf[addr] & 0xfd) | (val & 0x02);
break;
case 0x05: /* Command - High Byte */
dev->pci_conf[addr] = val & 0x03;
break;
case 0x07: /* Status - High Byte */
dev->pci_conf[addr] &= ~(val & 0xf0);
break;
case 0x12:
dev->pci_conf[addr] = val & 0xc0;
sis_5591_mask_bar(dev->pci_conf, dev->agpgart);
break;
case 0x13:
dev->pci_conf[addr] = val;
sis_5591_mask_bar(dev->pci_conf, dev->agpgart);
break;
case 0x51:
dev->pci_conf[addr] = val;
cpu_cache_ext_enabled = !!(val & 0x80);
cpu_update_waitstates();
break;
case 0x60 ... 0x62:
dev->pci_conf[addr] = dev->ram_banks[addr & 0x0f].code | 0xc0;
break;
case 0x63:
dev->pci_conf[addr] = dev->ram_banks[0].installed |
(dev->ram_banks[1].installed << 1) |
(dev->ram_banks[2].installed << 2);
break;
case 0x68:
dev->pci_conf[addr] = val;
sis_5591_smram_recalc(dev);
break;
case 0x70 ... 0x75:
dev->pci_conf[addr] = val & 0xee;
sis_5591_shadow_recalc(dev);
break;
case 0x76:
dev->pci_conf[addr] = val & 0xe8;
sis_5591_shadow_recalc(dev);
break;
case 0x0d: /* Master latency timer */
case 0x50:
case 0x52:
case 0x54 ... 0x5a:
case 0x5c ... 0x5f:
case 0x64 ... 0x65:
case 0x69 ... 0x6c:
case 0x77 ... 0x7b:
case 0x80 ... 0x8d:
case 0x90:
case 0x97 ... 0xab:
case 0xb0:
case 0xc8 ... 0xcb:
case 0xd4 ... 0xda:
case 0xe0 ... 0xe3:
case 0xef:
dev->pci_conf[addr] = val;
break;
case 0x91 ... 0x93:
dev->pci_conf[addr] = val;
sis_5591_mask_bar(dev->pci_conf, dev->agpgart);
break;
case 0x94:
dev->pci_conf[addr] = val & 0x7f;
sis_5591_mask_bar(dev->pci_conf, dev->agpgart);
break;
case 0xb2:
dev->pci_conf[addr] &= ~(val & 0x01);
break;
}
}
uint8_t
sis_5591_host_to_pci_read(int addr, void *priv)
{
const sis_5591_host_to_pci_t *dev = (sis_5591_host_to_pci_t *) priv;
uint8_t ret = 0xff;
ret = dev->pci_conf[addr];
sis_5591_host_to_pci_log("SiS 5591 H2P: [R] dev->pci_conf[%02X] = %02X\n", addr, ret);
return ret;
}
static void
sis_5591_host_to_pci_reset(void *priv)
{
sis_5591_host_to_pci_t *dev = (sis_5591_host_to_pci_t *) priv;
dev->pci_conf[0x00] = 0x39;
dev->pci_conf[0x01] = 0x10;
dev->pci_conf[0x02] = 0x91;
dev->pci_conf[0x03] = 0x55;
dev->pci_conf[0x04] = 0x05;
dev->pci_conf[0x05] = 0x00;
dev->pci_conf[0x06] = 0x10;
dev->pci_conf[0x07] = 0x02;
dev->pci_conf[0x08] = 0x02;
dev->pci_conf[0x09] = dev->pci_conf[0x0a] = 0x00;
dev->pci_conf[0x0b] = 0x06;
dev->pci_conf[0x0c] = 0x00;
dev->pci_conf[0x0d] = 0xff;
dev->pci_conf[0x0e] = 0x80;
dev->pci_conf[0x0f] = 0x00;
dev->pci_conf[0x10] = dev->pci_conf[0x11] = 0x00;
dev->pci_conf[0x12] = dev->pci_conf[0x13] = 0x00;
dev->pci_conf[0x34] = 0xc0;
dev->pci_conf[0x50] = 0x00;
dev->pci_conf[0x51] = 0x18;
dev->pci_conf[0x52] = dev->pci_conf[0x54] = 0x00;
dev->pci_conf[0x55] = 0x0e;
dev->pci_conf[0x56] = 0x40;
dev->pci_conf[0x57] = 0x00;
dev->pci_conf[0x58] = 0x50;
dev->pci_conf[0x59] = dev->pci_conf[0x5a] = 0x00;
dev->pci_conf[0x5c] = dev->pci_conf[0x5d] = 0x00;
dev->pci_conf[0x5e] = dev->pci_conf[0x5f] = 0x00;
dev->pci_conf[0x60] = dev->pci_conf[0x61] = 0x00;
dev->pci_conf[0x62] = 0x00;
dev->pci_conf[0x63] = 0xff;
dev->pci_conf[0x64] = dev->pci_conf[0x65] = 0x00;
dev->pci_conf[0x68] = dev->pci_conf[0x69] = 0x00;
dev->pci_conf[0x6a] = dev->pci_conf[0x6b] = 0x00;
dev->pci_conf[0x6c] = 0x00;
dev->pci_conf[0x70] = dev->pci_conf[0x71] = 0x00;
dev->pci_conf[0x72] = dev->pci_conf[0x73] = 0x00;
dev->pci_conf[0x74] = dev->pci_conf[0x75] = 0x00;
dev->pci_conf[0x76] = dev->pci_conf[0x77] = 0x00;
dev->pci_conf[0x78] = dev->pci_conf[0x79] = 0x00;
dev->pci_conf[0x7a] = dev->pci_conf[0x7b] = 0x00;
dev->pci_conf[0x80] = dev->pci_conf[0x81] = 0x00;
dev->pci_conf[0x82] = dev->pci_conf[0x83] = 0x00;
dev->pci_conf[0x84] = dev->pci_conf[0x85] = 0xff;
dev->pci_conf[0x86] = 0xff;
dev->pci_conf[0x87] = 0x00;
dev->pci_conf[0x88] = dev->pci_conf[0x89] = 0x00;
dev->pci_conf[0x8a] = dev->pci_conf[0x8b] = 0x00;
dev->pci_conf[0x8c] = dev->pci_conf[0x8d] = 0x00;
dev->pci_conf[0x90] = dev->pci_conf[0x91] = 0x00;
dev->pci_conf[0x92] = dev->pci_conf[0x93] = 0x00;
dev->pci_conf[0x94] = dev->pci_conf[0x97] = 0x00;
dev->pci_conf[0x98] = dev->pci_conf[0x99] = 0x00;
dev->pci_conf[0x9a] = dev->pci_conf[0x9b] = 0x00;
dev->pci_conf[0x9c] = dev->pci_conf[0x9d] = 0x00;
dev->pci_conf[0x9e] = dev->pci_conf[0x9f] = 0x00;
dev->pci_conf[0xa0] = dev->pci_conf[0xa1] = 0x00;
dev->pci_conf[0xa2] = dev->pci_conf[0xa3] = 0x00;
dev->pci_conf[0xa4] = dev->pci_conf[0xa5] = 0x00;
dev->pci_conf[0xa6] = dev->pci_conf[0xa7] = 0x00;
dev->pci_conf[0xa8] = dev->pci_conf[0xa9] = 0x00;
dev->pci_conf[0xaa] = dev->pci_conf[0xab] = 0x00;
dev->pci_conf[0xb0] = dev->pci_conf[0xb2] = 0x00;
dev->pci_conf[0xc0] = 0x02;
dev->pci_conf[0xc1] = 0x00;
dev->pci_conf[0xc2] = 0x10;
dev->pci_conf[0xc3] = 0x00;
dev->pci_conf[0xc4] = 0x03;
dev->pci_conf[0xc5] = 0x02;
dev->pci_conf[0xc6] = 0x00;
dev->pci_conf[0xc7] = 0x1f;
dev->pci_conf[0xc8] = dev->pci_conf[0xc9] = 0x00;
dev->pci_conf[0xca] = dev->pci_conf[0xcb] = 0x00;
dev->pci_conf[0xd4] = dev->pci_conf[0xd5] = 0x00;
dev->pci_conf[0xd6] = dev->pci_conf[0xd7] = 0x00;
dev->pci_conf[0xd8] = dev->pci_conf[0xd9] = 0x00;
dev->pci_conf[0xda] = 0x00;
dev->pci_conf[0xe0] = dev->pci_conf[0xe1] = 0x00;
dev->pci_conf[0xe2] = dev->pci_conf[0xe3] = 0x00;
dev->pci_conf[0xef] = 0x00;
sis_5591_mask_bar(dev->pci_conf, dev->agpgart);
cpu_cache_ext_enabled = 0;
cpu_update_waitstates();
sis_5591_shadow_recalc(dev);
sis_5591_smram_recalc(dev);
}
static void
sis_5591_host_to_pci_close(void *priv)
{
sis_5591_host_to_pci_t *dev = (sis_5591_host_to_pci_t *) priv;
smram_del(dev->smram);
free(dev);
}
static void *
sis_5591_host_to_pci_init(UNUSED(const device_t *info))
{
sis_5591_host_to_pci_t *dev = (sis_5591_host_to_pci_t *) calloc(1, sizeof(sis_5591_host_to_pci_t));
uint32_t total_mem = mem_size << 10;
ram_bank_t *rb;
dev->sis = device_get_common_priv();
/* Calculate the physical RAM banks. */
for (uint8_t i = 0; i < 3; i++) {
rb = &(dev->ram_banks[i]);
uint32_t size = 0x00000000;
uint8_t index = 0;
for (int8_t j = 5; j >= 0; j--) {
uint32_t *bs = &(bank_sizes[j]);
if (*bs <= total_mem) {
size = *bs;
index = j;
break;
}
}
if (size != 0x00000000) {
rb->installed = 1;
rb->code = bank_codes[index];
rb->phys_size = size;
total_mem -= size;
} else
rb->installed = 0;
}
/* SMRAM */
dev->smram = smram_add();
device_add(&sis_5xxx_agp_device);
dev->agpgart = device_add(&agpgart_device);
sis_5591_host_to_pci_reset(dev);
return dev;
}
const device_t sis_5591_h2p_device = {
.name = "SiS 5591 Host to PCI bridge",
.internal_name = "sis_5591_host_to_pci",
.flags = DEVICE_PCI,
.local = 0x00,
.init = sis_5591_host_to_pci_init,
.close = sis_5591_host_to_pci_close,
.reset = sis_5591_host_to_pci_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

454
src/chipset/sis_5595_pmu.c Normal file
View File

@@ -0,0 +1,454 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* 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 5572 USB controller.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2024 Miran Grca.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/dma.h>
#include <86box/mem.h>
#include <86box/nvr.h>
#include <86box/hdd.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/hdc_ide_sff8038i.h>
#include <86box/pci.h>
#include <86box/pic.h>
#include <86box/pit.h>
#include <86box/pit_fast.h>
#include <86box/plat.h>
#include <86box/plat_unused.h>
#include <86box/port_92.h>
#include <86box/smram.h>
#include <86box/spd.h>
#include <86box/apm.h>
#include <86box/ddma.h>
#include <86box/acpi.h>
#include <86box/smbus.h>
#include <86box/sis_55xx.h>
#include <86box/chipset.h>
#include <86box/usb.h>
#ifdef ENABLE_SIS_5595_PMU_LOG
int sis_5595_pmu_do_log = ENABLE_SIS_5595_PMU_LOG;
static void
sis_5595_pmu_log(const char *fmt, ...)
{
va_list ap;
if (sis_5595_pmu_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define sis_5595_pmu_log(fmt, ...)
#endif
typedef struct sis_5595_pmu_io_trap_t {
void *priv;
void *trap;
uint8_t flags, mask;
uint8_t *sts_reg, sts_mask;
uint16_t addr;
} sis_5595_pmu_io_trap_t;
typedef struct sis_5595_pmu_t {
uint8_t is_1997;
uint8_t pci_conf[256];
sis_5595_pmu_io_trap_t io_traps[22];
sis_55xx_common_t *sis;
} sis_5595_pmu_t;
static void
sis_5595_pmu_trap_io(UNUSED(int size), UNUSED(uint16_t addr), UNUSED(uint8_t write), UNUSED(uint8_t val),
void *priv)
{
sis_5595_pmu_io_trap_t *trap = (sis_5595_pmu_io_trap_t *) priv;
sis_5595_pmu_t *dev = (sis_5595_pmu_t *) trap->priv;
trap->sts_reg[0x04] |= trap->sts_mask;
if (trap->sts_reg[0x00] & trap->sts_mask)
acpi_sis5595_pmu_event(dev->sis->acpi);
if (trap->sts_reg[0x20] & trap->sts_mask)
acpi_update_irq(dev->sis->acpi);
}
static void
sis_5595_pmu_trap_io_ide(int size, uint16_t addr, uint8_t write, uint8_t val, void *priv)
{
sis_5595_pmu_io_trap_t *trap = (sis_5595_pmu_io_trap_t *) priv;
/* IDE traps are per drive, not per channel. */
if (ide_drives[trap->flags & 0x03]->selected)
sis_5595_pmu_trap_io(size, addr, write, val, priv);
}
static void
sis_5595_pmu_trap_io_mask(int size, uint16_t addr, uint8_t write, uint8_t val, void *priv)
{
sis_5595_pmu_io_trap_t *trap = (sis_5595_pmu_io_trap_t *) priv;
if ((addr & trap->mask) == (trap->addr & trap->mask))
sis_5595_pmu_trap_io(size, addr, write, val, priv);
}
static void
sis_5595_pmu_trap_io_ide_bm(int size, uint16_t addr, uint8_t write, uint8_t val, void *priv)
{
sis_5595_pmu_io_trap_t *trap = (sis_5595_pmu_io_trap_t *) priv;
sis_5595_pmu_t *dev = (sis_5595_pmu_t *) trap->priv;
if (trap->flags & 0x01) {
dev->pci_conf[0x67] |= 0x01;
dev->pci_conf[0x64] |= 0x08;
} else {
dev->pci_conf[0x67] |= 0x02;
dev->pci_conf[0x64] |= 0x10;
}
acpi_sis5595_pmu_event(dev->sis->acpi);
}
static void
sis_5595_pmu_trap_update_devctl(sis_5595_pmu_t *dev, uint8_t trap_id, uint8_t enable,
uint8_t flags, uint8_t mask, uint8_t *sts_reg, uint8_t sts_mask,
uint16_t addr, uint16_t size)
{
sis_5595_pmu_io_trap_t *trap = &dev->io_traps[trap_id];
/* Set up Device I/O traps dynamically. */
if (enable && !trap->trap) {
trap->priv = (void *) dev;
trap->flags = flags;
trap->mask = mask;
trap->addr = addr;
if (flags & 0x10)
trap->trap = io_trap_add(sis_5595_pmu_trap_io_ide_bm, trap);
else if (flags & 0x08)
trap->trap = io_trap_add(sis_5595_pmu_trap_io_mask, trap);
else if (flags & 0x04)
trap->trap = io_trap_add(sis_5595_pmu_trap_io_ide, trap);
else
trap->trap = io_trap_add(sis_5595_pmu_trap_io, trap);
trap->sts_reg = sts_reg;
trap->sts_mask = sts_mask;
}
/* Remap I/O trap. */
io_trap_remap(trap->trap, enable, addr, size);
}
static void
sis_5595_pmu_trap_update(void *priv)
{
sis_5595_pmu_t *dev = (sis_5595_pmu_t *) priv;
uint8_t trap_id = 0;
uint8_t *fregs = dev->pci_conf;
uint16_t temp;
uint8_t mask;
uint8_t on;
temp = (fregs[0x7e] | (fregs[0x7f] << 8)) & 0xffe0;
sis_5595_pmu_trap_update_devctl(dev, trap_id++,
fregs[0x7e] & 0x08, 0x10, 0xff, NULL, 0xff, temp, 0x08);
sis_5595_pmu_trap_update_devctl(dev, trap_id++,
fregs[0x7e] & 0x04, 0x10, 0xff, NULL, 0xff, temp + 8, 0x08);
on = fregs[0x63] | fregs[0x83];
sis_5595_pmu_trap_update_devctl(dev, trap_id++,
on & 0x02, 0x04, 0xff, &(fregs[0x63]), 0x02, 0x1f0, 0x08);
sis_5595_pmu_trap_update_devctl(dev, trap_id++,
on & 0x01, 0x06, 0xff, &(fregs[0x63]), 0x01, 0x170, 0x08);
on = fregs[0x62] | fregs[0x82];
sis_5595_pmu_trap_update_devctl(dev, trap_id++,
on & 0x80, 0x00, 0xff, &(fregs[0x62]), 0x80, 0x064, 0x01);
sis_5595_pmu_trap_update_devctl(dev, trap_id++,
on & 0x80, 0x00, 0xff, &(fregs[0x62]), 0x80, 0x060, 0x01);
sis_5595_pmu_trap_update_devctl(dev, trap_id++,
on & 0x40, 0x00, 0xff, &(fregs[0x62]), 0x40, 0x3f8, 0x08);
sis_5595_pmu_trap_update_devctl(dev, trap_id++,
on & 0x20, 0x00, 0xff, &(fregs[0x62]), 0x20, 0x2f8, 0x08);
sis_5595_pmu_trap_update_devctl(dev, trap_id++,
on & 0x10, 0x00, 0xff, &(fregs[0x62]), 0x10, 0x378, 0x08);
sis_5595_pmu_trap_update_devctl(dev, trap_id++,
on & 0x10, 0x00, 0xff, &(fregs[0x62]), 0x10, 0x278, 0x08);
temp = (fregs[0x5c] | (fregs[0x5d] << 8)) & 0x03ff;
mask = fregs[0x5d] >> 2;
sis_5595_pmu_trap_update_devctl(dev, trap_id++,
on & 0x04, 0x08, mask, &(fregs[0x62]), 0x04, temp, 0x40);
temp = fregs[0x5e] | (fregs[0x5f] << 8);
if (dev->is_1997) {
mask = fregs[0x4d] & 0x1f;
sis_5595_pmu_trap_update_devctl(dev, trap_id++,
on & 0x02, 0x08, mask, &(fregs[0x62]), 0x02, temp, 0x20);
} else {
mask = fregs[0x4d];
sis_5595_pmu_trap_update_devctl(dev, trap_id++,
on & 0x02, 0x08, mask, &(fregs[0x62]), 0x02, temp, 0x100);
}
on = fregs[0x61] | fregs[0x81];
sis_5595_pmu_trap_update_devctl(dev, trap_id++,
on & 0x40, 0x00, 0xff, &(fregs[0x61]), 0x40, 0x3b0, 0x30);
switch ((fregs[0x4c] >> 6) & 0x03) {
case 0x00:
temp = 0xf40;
break;
case 0x01:
temp = 0xe80;
break;
case 0x02:
temp = 0x604;
break;
default:
temp = 0x530;
break;
}
sis_5595_pmu_trap_update_devctl(dev, trap_id++,
on & 0x10, 0x00, 0xff, &(fregs[0x61]), 0x10, temp, 0x08);
switch ((fregs[0x4c] >> 4) & 0x03) {
case 0x00:
temp = 0x280;
break;
case 0x01:
temp = 0x260;
break;
case 0x02:
temp = 0x240;
break;
default:
temp = 0x220;
break;
}
sis_5595_pmu_trap_update_devctl(dev, trap_id++,
on & 0x08, 0x00, 0xff, &(fregs[0x61]), 0x08, temp, 0x14);
switch ((fregs[0x4c] >> 2) & 0x03) {
case 0x00:
temp = 0x330;
break;
case 0x01:
temp = 0x320;
break;
case 0x02:
temp = 0x310;
break;
default:
temp = 0x300;
break;
}
sis_5595_pmu_trap_update_devctl(dev, trap_id++,
on & 0x04, 0x00, 0xff, &(fregs[0x61]), 0x04, temp, 0x04);
sis_5595_pmu_trap_update_devctl(dev, trap_id++,
on & 0x02, 0x00, 0xff, &(fregs[0x61]), 0x02, 0x200, 0x08);
sis_5595_pmu_trap_update_devctl(dev, trap_id++,
on & 0x02, 0x00, 0xff, &(fregs[0x61]), 0x02, 0x388, 0x04);
on = fregs[0x60] | fregs[0x80];
sis_5595_pmu_trap_update_devctl(dev, trap_id++,
on & 0x20, 0x00, 0xff, &(fregs[0x60]), 0x20, 0x3f0, 0x08);
sis_5595_pmu_trap_update_devctl(dev, trap_id++,
on & 0x20, 0x00, 0xff, &(fregs[0x60]), 0x20, 0x370, 0x08);
sis_5595_pmu_trap_update_devctl(dev, trap_id++,
on & 0x10, 0x05, 0xff, &(fregs[0x60]), 0x10, 0x1f0, 0x08);
sis_5595_pmu_trap_update_devctl(dev, trap_id++,
on & 0x08, 0x07, 0xff, &(fregs[0x60]), 0x08, 0x170, 0x08);
}
void
sis_5595_pmu_write(int addr, uint8_t val, void *priv)
{
sis_5595_pmu_t *dev = (sis_5595_pmu_t *) priv;
sis_5595_pmu_log("SiS 5595 PMU: [W] dev->pci_conf[%02X] = %02X\n", addr, val);
if (dev->sis->usb_enabled) switch (addr) {
default:
break;
case 0x40 ... 0x4b:
case 0x50 ... 0x5b:
case 0x68 ... 0x7b:
case 0x7d:
dev->pci_conf[addr] = val;
break;
case 0x4c ... 0x4d:
case 0x5c ... 0x63:
case 0x7e ... 0x7f:
case 0x80 ... 0x83:
dev->pci_conf[addr] = val;
sis_5595_pmu_trap_update(dev);
break;
case 0x64 ... 0x67:
dev->pci_conf[addr] &= ~val;
break;
case 0x7c:
dev->pci_conf[addr] = val;
if (val & 0x02) {
dev->pci_conf[0x64] |= 0x04;
if (dev->pci_conf[0x60] & 0x04)
acpi_sis5595_pmu_event(dev->sis->acpi);
}
break;
}
}
uint8_t
sis_5595_pmu_read(int addr, void *priv)
{
const sis_5595_pmu_t *dev = (sis_5595_pmu_t *) priv;
uint8_t ret = 0xff;
ret = dev->pci_conf[addr];
sis_5595_pmu_log("SiS 5595 PMU: [R] dev->pci_conf[%02X] = %02X\n", addr, ret);
return ret;
}
static void
sis_5595_pmu_reset(void *priv)
{
sis_5595_pmu_t *dev = (sis_5595_pmu_t *) priv;
dev->pci_conf[0x00] = 0x39;
dev->pci_conf[0x01] = 0x10;
dev->pci_conf[0x02] = 0x09;
dev->pci_conf[0x03] = 0x00;
dev->pci_conf[0x04] = dev->pci_conf[0x05] = 0x00;
dev->pci_conf[0x06] = 0x00;
dev->pci_conf[0x07] = 0x02;
dev->pci_conf[0x08] = dev->pci_conf[0x09] = 0x00;
dev->pci_conf[0x0a] = 0x00;
dev->pci_conf[0x0b] = 0xff;
dev->pci_conf[0x0c] = dev->pci_conf[0x0d] = 0x00;
dev->pci_conf[0x0e] = 0x80;
dev->pci_conf[0x0f] = 0x00;
dev->pci_conf[0x40] = dev->pci_conf[0x41] = 0x00;
dev->pci_conf[0x42] = dev->pci_conf[0x43] = 0x00;
dev->pci_conf[0x44] = dev->pci_conf[0x45] = 0x00;
dev->pci_conf[0x46] = dev->pci_conf[0x47] = 0x00;
dev->pci_conf[0x48] = dev->pci_conf[0x49] = 0x00;
dev->pci_conf[0x4a] = dev->pci_conf[0x4b] = 0x00;
dev->pci_conf[0x4c] = dev->pci_conf[0x4d] = 0x00;
dev->pci_conf[0x4e] = dev->pci_conf[0x4f] = 0x00;
dev->pci_conf[0x50] = dev->pci_conf[0x51] = 0x00;
dev->pci_conf[0x52] = dev->pci_conf[0x53] = 0x00;
dev->pci_conf[0x54] = dev->pci_conf[0x55] = 0x00;
dev->pci_conf[0x56] = dev->pci_conf[0x57] = 0x00;
dev->pci_conf[0x58] = dev->pci_conf[0x59] = 0x00;
dev->pci_conf[0x5a] = dev->pci_conf[0x5b] = 0x00;
dev->pci_conf[0x5c] = dev->pci_conf[0x5d] = 0x00;
dev->pci_conf[0x5e] = dev->pci_conf[0x5f] = 0x00;
dev->pci_conf[0x60] = dev->pci_conf[0x61] = 0x00;
dev->pci_conf[0x62] = dev->pci_conf[0x63] = 0x00;
dev->pci_conf[0x64] = dev->pci_conf[0x65] = 0x00;
dev->pci_conf[0x66] = dev->pci_conf[0x67] = 0x00;
dev->pci_conf[0x68] = dev->pci_conf[0x69] = 0x00;
dev->pci_conf[0x6a] = dev->pci_conf[0x6b] = 0x00;
dev->pci_conf[0x6c] = dev->pci_conf[0x6d] = 0x00;
dev->pci_conf[0x6e] = dev->pci_conf[0x6f] = 0x00;
dev->pci_conf[0x70] = dev->pci_conf[0x71] = 0x00;
dev->pci_conf[0x72] = dev->pci_conf[0x73] = 0x00;
dev->pci_conf[0x74] = dev->pci_conf[0x75] = 0x00;
dev->pci_conf[0x76] = dev->pci_conf[0x77] = 0x00;
dev->pci_conf[0x78] = dev->pci_conf[0x79] = 0x00;
dev->pci_conf[0x7a] = dev->pci_conf[0x7b] = 0x00;
dev->pci_conf[0x7c] = dev->pci_conf[0x7d] = 0x00;
dev->pci_conf[0x7e] = dev->pci_conf[0x7f] = 0x00;
dev->pci_conf[0x80] = dev->pci_conf[0x81] = 0x00;
dev->pci_conf[0x82] = dev->pci_conf[0x83] = 0x00;
sis_5595_pmu_trap_update(dev);
acpi_update_irq(dev->sis->acpi);
}
static void
sis_5595_pmu_close(void *priv)
{
sis_5595_pmu_t *dev = (sis_5595_pmu_t *) priv;
free(dev);
}
static void *
sis_5595_pmu_init(UNUSED(const device_t *info))
{
sis_5595_pmu_t *dev = (sis_5595_pmu_t *) calloc(1, sizeof(sis_5595_pmu_t));
dev->sis = device_get_common_priv();
dev->sis->pmu_regs = dev->pci_conf;
dev->is_1997 = info->local;
sis_5595_pmu_reset(dev);
return dev;
}
const device_t sis_5595_1997_pmu_device = {
.name = "SiS 5595 (1997) PMU",
.internal_name = "sis_5595_1997_pmu",
.flags = DEVICE_PCI,
.local = 0x01,
.init = sis_5595_pmu_init,
.close = sis_5595_pmu_close,
.reset = sis_5595_pmu_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t sis_5595_pmu_device = {
.name = "SiS 5595 PMU",
.internal_name = "sis_5595_pmu",
.flags = DEVICE_PCI,
.local = 0x00,
.init = sis_5595_pmu_init,
.close = sis_5595_pmu_close,
.reset = sis_5595_pmu_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

96
src/chipset/sis_55xx.c Normal file
View File

@@ -0,0 +1,96 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Implementation of the SiS 55xx common structure.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2024 Miran Grca.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/dma.h>
#include <86box/mem.h>
#include <86box/nvr.h>
#include <86box/hdd.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/hdc_ide_sff8038i.h>
#include <86box/pci.h>
#include <86box/pic.h>
#include <86box/pit.h>
#include <86box/pit_fast.h>
#include <86box/plat.h>
#include <86box/plat_unused.h>
#include <86box/port_92.h>
#include <86box/smram.h>
#include <86box/spd.h>
#include <86box/apm.h>
#include <86box/ddma.h>
#include <86box/acpi.h>
#include <86box/smbus.h>
#include <86box/sis_55xx.h>
#include <86box/chipset.h>
#include <86box/usb.h>
#ifdef ENABLE_SIS_55XX_COMMON_LOG
int sis_55xx_common_do_log = ENABLE_SIS_55XX_COMMON_LOG;
static void
sis_55xx_common_log(const char *fmt, ...)
{
va_list ap;
if (sis_55xx_common_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define sis_55xx_common_log(fmt, ...)
#endif
static void
sis_55xx_common_close(void *priv)
{
sis_55xx_common_t *dev = (sis_55xx_common_t *) priv;
free(dev);
}
static void *
sis_55xx_common_init(UNUSED(const device_t *info))
{
sis_55xx_common_t *dev = (sis_55xx_common_t *) calloc(1, sizeof(sis_55xx_common_t));
return dev;
}
const device_t sis_55xx_common_device = {
.name = "SiS 55xx Common Structure",
.internal_name = "sis_55xx_common",
.flags = DEVICE_PCI,
.local = 0x00,
.init = sis_55xx_common_init,
.close = sis_55xx_common_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

210
src/chipset/sis_5600.c Normal file
View File

@@ -0,0 +1,210 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Implementation of the SiS (5)600 Pentium PCI/ISA Chipset.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2024 Miran Grca.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/mem.h>
#include <86box/nvr.h>
#include <86box/apm.h>
#include <86box/acpi.h>
#include <86box/hdd.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/hdc_ide_sff8038i.h>
#include <86box/pci.h>
#include <86box/pic.h>
#include <86box/pit.h>
#include <86box/pit_fast.h>
#include <86box/plat.h>
#include <86box/plat_unused.h>
#include <86box/port_92.h>
#include <86box/smram.h>
#include <86box/spd.h>
#include <86box/sis_55xx.h>
#include <86box/chipset.h>
#ifdef ENABLE_SIS_5600_LOG
int sis_5600_do_log = ENABLE_SIS_5600_LOG;
static void
sis_5600_log(const char *fmt, ...)
{
va_list ap;
if (sis_5600_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define sis_5600_log(fmt, ...)
#endif
typedef struct sis_5600_t {
uint8_t nb_slot;
uint8_t sb_slot;
void *h2p;
void *p2i;
void *ide;
void *usb;
void *pmu;
sis_55xx_common_t *sis;
} sis_5600_t;
static void
sis_5600_write(int func, int addr, uint8_t val, void *priv)
{
const sis_5600_t *dev = (sis_5600_t *) priv;
sis_5600_log("SiS 5600: [W] dev->pci_conf[%02X] = %02X\n", addr, val);
if (func == 0x00)
sis_5600_host_to_pci_write(addr, val, dev->h2p);
else if (func == 0x01)
sis_5513_ide_write(addr, val, dev->ide);
}
static uint8_t
sis_5600_read(int func, int addr, void *priv)
{
const sis_5600_t *dev = (sis_5600_t *) priv;
uint8_t ret = 0xff;
if (func == 0x00)
ret = sis_5600_host_to_pci_read(addr, dev->h2p);
else if (func == 0x01)
ret = sis_5513_ide_read(addr, dev->ide);
sis_5600_log("SiS 5600: [R] dev->pci_conf[%02X] = %02X\n", addr, ret);
return ret;
}
static void
sis_5595_write(int func, int addr, uint8_t val, void *priv)
{
const sis_5600_t *dev = (sis_5600_t *) priv;
sis_5600_log("SiS 5595: [W] dev->pci_conf[%02X] = %02X\n", addr, val);
switch (func) {
case 0x00:
sis_5513_pci_to_isa_write(addr, val, dev->p2i);
break;
case 0x01:
sis_5595_pmu_write(addr, val, dev->pmu);
break;
case 0x02:
sis_5572_usb_write(addr, val, dev->usb);
break;
}
}
static uint8_t
sis_5595_read(int func, int addr, void *priv)
{
const sis_5600_t *dev = (sis_5600_t *) priv;
uint8_t ret = 0xff;
switch (func) {
case 0x00:
ret = sis_5513_pci_to_isa_read(addr, dev->p2i);
break;
case 0x01:
ret = sis_5595_pmu_read(addr, dev->pmu);
break;
case 0x02:
ret = sis_5572_usb_read(addr, dev->usb);
break;
}
sis_5600_log("SiS 5602: [R] dev->pci_conf[%02X] = %02X\n", addr, ret);
return ret;
}
static void
sis_5600_close(void *priv)
{
sis_5600_t *dev = (sis_5600_t *) priv;
free(dev);
}
static void *
sis_5600_init(UNUSED(const device_t *info))
{
sis_5600_t *dev = (sis_5600_t *) calloc(1, sizeof(sis_5600_t));
/* Device 0: SiS 5600 */
pci_add_card(PCI_ADD_NORTHBRIDGE, sis_5600_read, sis_5600_write, dev, &dev->nb_slot);
/* Device 1: SiS 5595 */
pci_add_card(PCI_ADD_SOUTHBRIDGE, sis_5595_read, sis_5595_write, dev, &dev->sb_slot);
dev->sis = device_add(&sis_55xx_common_device);
dev->ide = device_add_linked(&sis_5591_5600_ide_device, dev->sis);
if (info->local)
dev->p2i = device_add_linked(&sis_5595_1997_p2i_device, dev->sis);
else
dev->p2i = device_add_linked(&sis_5595_p2i_device, dev->sis);
dev->h2p = device_add_linked(&sis_5600_h2p_device, dev->sis);
dev->usb = device_add_linked(&sis_5595_usb_device, dev->sis);
if (info->local)
dev->pmu = device_add_linked(&sis_5595_1997_pmu_device, dev->sis);
else
dev->pmu = device_add_linked(&sis_5595_pmu_device, dev->sis);
return dev;
}
const device_t sis_5600_1997_device = {
.name = "SiS (5)600 (1997)",
.internal_name = "sis_5600_1997",
.flags = DEVICE_PCI,
.local = 1,
.init = sis_5600_init,
.close = sis_5600_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t sis_5600_device = {
.name = "SiS (5)600",
.internal_name = "sis_5600",
.flags = DEVICE_PCI,
.local = 0,
.init = sis_5600_init,
.close = sis_5600_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

434
src/chipset/sis_5600_h2p.c Normal file
View File

@@ -0,0 +1,434 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* 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 (5)600 Host to PCI bridge.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2024 Miran Grca.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/dma.h>
#include <86box/mem.h>
#include <86box/nvr.h>
#include <86box/hdd.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/hdc_ide_sff8038i.h>
#include <86box/pci.h>
#include <86box/pic.h>
#include <86box/pit.h>
#include <86box/pit_fast.h>
#include <86box/plat.h>
#include <86box/plat_unused.h>
#include <86box/port_92.h>
#include <86box/smram.h>
#include <86box/spd.h>
#include <86box/apm.h>
#include <86box/ddma.h>
#include <86box/acpi.h>
#include <86box/smbus.h>
#include <86box/sis_55xx.h>
#include <86box/chipset.h>
#include <86box/usb.h>
#include <86box/agpgart.h>
#ifdef ENABLE_SIS_5600_HOST_TO_PCI_LOG
int sis_5600_host_to_pci_do_log = ENABLE_SIS_5600_HOST_TO_PCI_LOG;
static void
sis_5600_host_to_pci_log(const char *fmt, ...)
{
va_list ap;
if (sis_5600_host_to_pci_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define sis_5600_host_to_pci_log(fmt, ...)
#endif
typedef struct {
uint8_t installed;
uint8_t code;
uint32_t phys_size;
} ram_bank_t;
typedef struct sis_5600_host_to_pci_t {
uint8_t pci_conf[256];
uint8_t states[7];
ram_bank_t ram_banks[3];
sis_55xx_common_t *sis;
smram_t *smram;
agpgart_t *agpgart;
} sis_5600_host_to_pci_t;
static uint8_t bank_codes[7] = { 0x00, 0x20, 0x24, 0x22, 0x26, 0x2a, 0x2b };
static uint32_t bank_sizes[7] = { 0x00800000, /* 8 MB */
0x01000000, /* 16 MB */
0x02000000, /* 32 MB */
0x04000000, /* 64 MB */
0x08000000, /* 128 MB */
0x10000000, /* 256 MB */
0x20000000 }; /* 512 MB */
static void
sis_5600_shadow_recalc(sis_5600_host_to_pci_t *dev)
{
int state;
uint32_t base;
for (uint8_t i = 0; i < 8; i++) {
base = 0x000c0000 + (i << 14);
state = (dev->pci_conf[0x70] & (1 << i)) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
state |= (dev->pci_conf[0x72] & (1 << i)) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
if (((dev->pci_conf[0x70] ^ dev->states[0]) & (1 << i)) ||
((dev->pci_conf[0x72] ^ dev->states[2]) & (1 << i))) {
mem_set_mem_state_both(base, 0x4000, state);
sis_5600_host_to_pci_log("%08X-%08X\n", base, base + 0x3fff);
}
}
for (uint8_t i = 0; i < 4; i++) {
base = 0x000e0000 + (i << 14);
state = (dev->pci_conf[0x71] & (1 << i)) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
state |= (dev->pci_conf[0x73] & (1 << i)) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
if (((dev->pci_conf[0x71] ^ dev->states[1]) & (1 << i)) ||
((dev->pci_conf[0x73] ^ dev->states[3]) & (1 << i))) {
mem_set_mem_state_both(base, 0x4000, state);
sis_5600_host_to_pci_log("%08X-%08X\n", base, base + 0x3fff);
}
}
base = 0x000f0000;
state = (dev->pci_conf[0x71] & (1 << 4)) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
state |= (dev->pci_conf[0x73] & (1 << 4)) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
if (((dev->pci_conf[0x71] ^ dev->states[1]) & (1 << 4)) ||
((dev->pci_conf[0x73] ^ dev->states[3]) & (1 << 4))) {
mem_set_mem_state_both(base, 0x10000, state);
sis_5600_host_to_pci_log("%08X-%08X\n", base, base + 0xffff);
}
for (uint8_t i = 0; i < 4; i++)
dev->states[i] = dev->pci_conf[0x70 + i];
flushmmucache_nopc();
}
static void
sis_5600_smram_recalc(sis_5600_host_to_pci_t *dev)
{
smram_disable_all();
switch (dev->pci_conf[0x6a] >> 6) {
case 0:
smram_enable(dev->smram, 0x000e0000, 0x000e0000, 0x8000, dev->pci_conf[0x6a] & 0x10, 1);
break;
case 1:
smram_enable(dev->smram, 0x000e0000, 0x000a0000, 0x8000, dev->pci_conf[0x6a] & 0x10, 1);
break;
case 2:
smram_enable(dev->smram, 0x000e0000, 0x000b0000, 0x8000, dev->pci_conf[0x6a] & 0x10, 1);
break;
case 3:
smram_enable(dev->smram, 0x000a0000, 0x000a0000, 0x10000, dev->pci_conf[0x6a] & 0x10, 1);
break;
default:
break;
}
flushmmucache();
}
static void
sis_5600_mask_bar(uint8_t *regs, void *agpgart)
{
uint32_t bar;
uint32_t sizes[8] = { 0x00400000, 0x00800000, 0x01000000, 0x02000000, 0x04000000, 0x08000000,
0x10000000, 0x00000000 } ;
/* Make sure the aperture's base is aligned to its size. */
bar = (regs[0x13] << 24) | (regs[0x12] << 16);
bar &= (sizes[(regs[0x94] >> 4) & 0x07] | 0xf0000000);
regs[0x12] = (bar >> 16) & 0xff;
regs[0x13] = (bar >> 24) & 0xff;
if (!agpgart)
return;
/* Map aperture and GART. */
agpgart_set_aperture(agpgart,
bar,
sizes[(regs[0x94] >> 4) & 0x07],
!!(regs[0x94] & 0x02));
if (regs[0x94] & 0x01)
agpgart_set_gart(agpgart, (regs[0x91] << 8) | (regs[0x92] << 16) | (regs[0x93] << 24));
else
agpgart_set_gart(agpgart, 0x00000000);
}
void
sis_5600_host_to_pci_write(int addr, uint8_t val, void *priv)
{
sis_5600_host_to_pci_t *dev = (sis_5600_host_to_pci_t *) priv;
sis_5600_host_to_pci_log("SiS 5600 H2P: [W] dev->pci_conf[%02X] = %02X\n", addr, val);
switch (addr) {
default:
break;
case 0x04: /* Command - Low Byte */
dev->pci_conf[addr] = (dev->pci_conf[addr] & 0xfd) | (val & 0x02);
break;
case 0x05: /* Command - High Byte */
dev->pci_conf[addr] = val & 0x03;
break;
case 0x07: /* Status - High Byte */
dev->pci_conf[addr] = (dev->pci_conf[addr] & ~(val & 0x70)) | (val & 0x01);
break;
case 0x0d: /* Master latency timer */
case 0x50 ... 0x5a:
case 0x64 ... 0x69:
case 0x6b ... 0x6c:
case 0x74 ... 0x75:
case 0x77 ... 0x80:
case 0x82 ... 0x8f:
case 0x97 ... 0x9b:
case 0xc8 ... 0xcb:
case 0xd4 ... 0xd8:
case 0xda:
case 0xe0:
case 0xe2 ... 0xe3:
dev->pci_conf[addr] = val;
break;
case 0x12:
dev->pci_conf[addr] = val & 0xc0;
sis_5600_mask_bar(dev->pci_conf, dev->agpgart);
break;
case 0x13:
dev->pci_conf[addr] = val;
sis_5600_mask_bar(dev->pci_conf, dev->agpgart);
break;
case 0x60 ... 0x62:
dev->pci_conf[addr] = dev->ram_banks[addr & 0x0f].code | 0xc0;
break;
case 0x63:
dev->pci_conf[addr] = dev->ram_banks[0].installed |
(dev->ram_banks[1].installed << 1) |
(dev->ram_banks[2].installed << 2);
break;
case 0x6a:
dev->pci_conf[addr] = val;
sis_5600_smram_recalc(dev);
break;
case 0x70 ... 0x73:
dev->pci_conf[addr] = val;
sis_5600_shadow_recalc(dev);
break;
case 0x91 ... 0x93:
dev->pci_conf[addr] = val;
sis_5600_mask_bar(dev->pci_conf, dev->agpgart);
break;
case 0x94:
dev->pci_conf[addr] = val & 0x7f;
sis_5600_mask_bar(dev->pci_conf, dev->agpgart);
break;
}
}
uint8_t
sis_5600_host_to_pci_read(int addr, void *priv)
{
const sis_5600_host_to_pci_t *dev = (sis_5600_host_to_pci_t *) priv;
uint8_t ret = 0xff;
ret = dev->pci_conf[addr];
sis_5600_host_to_pci_log("SiS 5600 H2P: [R] dev->pci_conf[%02X] = %02X\n", addr, ret);
return ret;
}
static void
sis_5600_host_to_pci_reset(void *priv)
{
sis_5600_host_to_pci_t *dev = (sis_5600_host_to_pci_t *) priv;
dev->pci_conf[0x00] = 0x39;
dev->pci_conf[0x01] = 0x10;
dev->pci_conf[0x02] = 0x00;
dev->pci_conf[0x03] = 0x56;
dev->pci_conf[0x04] = 0x05;
dev->pci_conf[0x05] = 0x00;
dev->pci_conf[0x06] = 0x10;
dev->pci_conf[0x07] = 0x02;
dev->pci_conf[0x08] = 0x10;
dev->pci_conf[0x09] = dev->pci_conf[0x0a] = 0x00;
dev->pci_conf[0x0b] = 0x06;
dev->pci_conf[0x0c] = 0x00;
dev->pci_conf[0x0d] = 0xff;
dev->pci_conf[0x0e] = 0x80;
dev->pci_conf[0x0f] = 0x00;
dev->pci_conf[0x10] = dev->pci_conf[0x11] = 0x00;
dev->pci_conf[0x12] = dev->pci_conf[0x13] = 0x00;
dev->pci_conf[0x34] = 0xc0;
dev->pci_conf[0x50] = dev->pci_conf[0x51] = 0x02;
dev->pci_conf[0x52] = dev->pci_conf[0x53] = 0x00;
dev->pci_conf[0x54] = dev->pci_conf[0x55] = 0x00;
dev->pci_conf[0x56] = dev->pci_conf[0x57] = 0x00;
dev->pci_conf[0x58] = dev->pci_conf[0x59] = 0x00;
dev->pci_conf[0x5a] = 0x00;
dev->pci_conf[0x60] = dev->pci_conf[0x61] = 0x00;
dev->pci_conf[0x62] = 0x00;
dev->pci_conf[0x63] = 0xff;
dev->pci_conf[0x64] = dev->pci_conf[0x65] = 0x00;
dev->pci_conf[0x66] = dev->pci_conf[0x67] = 0x00;
dev->pci_conf[0x68] = dev->pci_conf[0x69] = 0x00;
dev->pci_conf[0x6a] = dev->pci_conf[0x6b] = 0x00;
dev->pci_conf[0x6c] = 0x00;
dev->pci_conf[0x70] = dev->pci_conf[0x71] = 0x00;
dev->pci_conf[0x72] = dev->pci_conf[0x73] = 0x00;
dev->pci_conf[0x74] = dev->pci_conf[0x75] = 0x00;
dev->pci_conf[0x77] = 0x00;
dev->pci_conf[0x78] = dev->pci_conf[0x79] = 0x00;
dev->pci_conf[0x7a] = dev->pci_conf[0x7b] = 0x00;
dev->pci_conf[0x7c] = dev->pci_conf[0x7d] = 0x00;
dev->pci_conf[0x7e] = dev->pci_conf[0x7f] = 0x00;
dev->pci_conf[0x80] = 0x00;
dev->pci_conf[0x82] = dev->pci_conf[0x83] = 0x00;
dev->pci_conf[0x84] = dev->pci_conf[0x85] = 0xff;
dev->pci_conf[0x86] = 0xff;
dev->pci_conf[0x87] = 0x00;
dev->pci_conf[0x88] = dev->pci_conf[0x89] = 0x00;
dev->pci_conf[0x8a] = dev->pci_conf[0x8b] = 0x00;
dev->pci_conf[0x8c] = 0x00;
dev->pci_conf[0x8d] = 0x62;
dev->pci_conf[0x8e] = dev->pci_conf[0x8f] = 0x00;
dev->pci_conf[0x90] = dev->pci_conf[0x91] = 0x00;
dev->pci_conf[0x92] = dev->pci_conf[0x93] = 0x00;
dev->pci_conf[0x94] = dev->pci_conf[0x97] = 0x00;
dev->pci_conf[0x98] = dev->pci_conf[0x99] = 0x00;
dev->pci_conf[0x9a] = dev->pci_conf[0x9b] = 0x00;
dev->pci_conf[0xc0] = 0x02;
dev->pci_conf[0xc1] = 0x00;
dev->pci_conf[0xc2] = 0x10;
dev->pci_conf[0xc3] = 0x00;
dev->pci_conf[0xc4] = 0x03;
dev->pci_conf[0xc5] = 0x02;
dev->pci_conf[0xc6] = 0x00;
dev->pci_conf[0xc7] = 0x1f;
dev->pci_conf[0xc8] = dev->pci_conf[0xc9] = 0x00;
dev->pci_conf[0xca] = dev->pci_conf[0xcb] = 0x00;
dev->pci_conf[0xd4] = dev->pci_conf[0xd5] = 0x00;
dev->pci_conf[0xd6] = dev->pci_conf[0xd7] = 0x00;
dev->pci_conf[0xd8] = dev->pci_conf[0xda] = 0x00;
dev->pci_conf[0xe0] = 0x00;
dev->pci_conf[0xe2] = dev->pci_conf[0xe3] = 0x00;
sis_5600_mask_bar(dev->pci_conf, dev->agpgart);
cpu_cache_ext_enabled = 1;
cpu_update_waitstates();
sis_5600_shadow_recalc(dev);
sis_5600_smram_recalc(dev);
}
static void
sis_5600_host_to_pci_close(void *priv)
{
sis_5600_host_to_pci_t *dev = (sis_5600_host_to_pci_t *) priv;
smram_del(dev->smram);
free(dev);
}
static void *
sis_5600_host_to_pci_init(UNUSED(const device_t *info))
{
sis_5600_host_to_pci_t *dev = (sis_5600_host_to_pci_t *) calloc(1, sizeof(sis_5600_host_to_pci_t));
uint32_t total_mem = mem_size << 10;
ram_bank_t *rb;
dev->sis = device_get_common_priv();
/* Calculate the physical RAM banks. */
for (uint8_t i = 0; i < 3; i++) {
rb = &(dev->ram_banks[i]);
uint32_t size = 0x00000000;
uint8_t index = 0;
for (int8_t j = 6; j >= 0; j--) {
uint32_t *bs = &(bank_sizes[j]);
if (*bs <= total_mem) {
size = *bs;
index = j;
break;
}
}
if (size != 0x00000000) {
rb->installed = 1;
rb->code = bank_codes[index];
rb->phys_size = size;
total_mem -= size;
} else
rb->installed = 0;
}
/* SMRAM */
dev->smram = smram_add();
device_add(&sis_5xxx_agp_device);
dev->agpgart = device_add(&agpgart_device);
sis_5600_host_to_pci_reset(dev);
return dev;
}
const device_t sis_5600_h2p_device = {
.name = "SiS (5)600 Host to PCI bridge",
.internal_name = "sis_5600_host_to_pci",
.flags = DEVICE_PCI,
.local = 0x00,
.init = sis_5600_host_to_pci_init,
.close = sis_5600_host_to_pci_close,
.reset = sis_5600_host_to_pci_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -388,8 +388,7 @@ sis_85c49x_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv)
break;
case 0x67: /* Miscellaneous Control */
dev->pci_conf[addr] = val & 0xf9;
if (valxor & 0x60)
port_92_set_features(dev->port_92, !!(val & 0x20), !!(val & 0x40));
cpu_cpurst_on_sr = ((val & 0xa0) == 0x80) && !(dev->pci_conf[0xc6] & 0x08);
break;
/* 86C497 Specific Registers (80h ~ FFh) */
@@ -480,6 +479,8 @@ sis_85c49x_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv)
break;
case 0xc6: /* 85C497 Post / INIT Configuration */
dev->pci_conf[addr] = val & 0x0f;
cpu_cpurst_on_sr = ((dev->pci_conf[0x67] & 0xa0) == 0x80) && !(val & 0x08);
soft_reset_pci = !!(val & 0x04);
break;
case 0xc8:
case 0xc9:
@@ -608,12 +609,18 @@ sis_85c496_reset(void *priv)
sis_85c49x_pci_write(0, 0xd0, 0x78, dev);
sis_85c49x_pci_write(0, 0xd4, 0x00, dev);
dev->pci_conf[0x67] = 0x00;
dev->pci_conf[0xc6] = 0x00;
ide_pri_disable();
ide_sec_disable();
nvr_bank_set(0, 0, dev->nvr);
sis_85c497_isa_reset(dev);
cpu_cpurst_on_sr = 0;
soft_reset_pci = 0;
}
static void

View File

@@ -174,9 +174,7 @@ sis_85c4xx_out(uint16_t port, uint8_t val, void *priv)
case 0x23:
if ((dev->cur_reg >= dev->reg_base) && (dev->cur_reg <= dev->reg_last)) {
valxor = val ^ dev->regs[rel_reg];
if (rel_reg == 0x19)
dev->regs[rel_reg] &= ~val;
else if (rel_reg == 0x00)
if (rel_reg == 0x00)
dev->regs[rel_reg] = (dev->regs[rel_reg] & 0x1f) | (val & 0xe0);
else
dev->regs[rel_reg] = val;

View File

@@ -6,15 +6,13 @@
*
* This file is part of the 86Box distribution.
*
* Implementation of the SiS 85C50x Chipset.
* Implementation of the SiS 85C50x and 550x Chipsets.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Tiseno100,
*
*
* Authors: Tiseno100,
* Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2020-2021 Tiseno100.
* Copyright 2020-2021 Miran Grca.
* Copyright 2020-2024 Miran Grca.
* Copyright 2020-2024 Tiseno100.
*/
#include <stdarg.h>
#include <stdio.h>
@@ -27,16 +25,21 @@
#include <86box/device.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/apm.h>
#include <86box/machine.h>
#include <86box/pic.h>
#include <86box/pit.h>
#include <86box/pit_fast.h>
#include <86box/plat_unused.h>
#include <86box/mem.h>
#include <86box/nvr.h>
#include <86box/smram.h>
#include <86box/pci.h>
#include <86box/port_92.h>
#include <86box/spd.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/keyboard.h>
#include <86box/chipset.h>
#ifdef ENABLE_SIS_85C50X_LOG
@@ -58,17 +61,23 @@ sis_85c50x_log(const char *fmt, ...)
#endif
typedef struct sis_85c50x_t {
uint8_t index;
uint8_t nb_slot;
uint8_t sb_slot;
uint8_t pad;
uint8_t index;
uint8_t nb_slot;
uint8_t sb_slot;
uint8_t type;
uint8_t pci_conf[256];
uint8_t pci_conf_sb[256];
uint8_t regs[256];
uint8_t pci_conf[256];
uint8_t pci_conf_sb[256];
uint8_t pci_conf_ide[256];
uint8_t regs[256];
uint32_t states[13];
smram_t *smram[2];
port_92_t *port_92;
void *pit;
nvr_t *nvr;
uint8_t (*pit_read_reg)(void *priv, uint8_t reg);
} sis_85c50x_t;
static void
@@ -77,23 +86,59 @@ sis_85c50x_shadow_recalc(sis_85c50x_t *dev)
uint32_t base;
uint32_t can_read;
uint32_t can_write;
uint32_t state;
can_read = (dev->pci_conf[0x53] & 0x40) ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
can_write = (dev->pci_conf[0x53] & 0x20) ? MEM_WRITE_EXTANY : MEM_WRITE_INTERNAL;
if (!can_read)
can_write = MEM_WRITE_EXTANY;
mem_set_mem_state_both(0xf0000, 0x10000, can_read | can_write);
shadowbios = 1;
shadowbios_write = 1;
state = can_read | can_write;
if (dev->states[12] != state) {
mem_set_mem_state_both(0x000f0000, 0x00010000, state);
sis_85c50x_log("F0000-FFFFF: R%c, W%c\n",
(dev->pci_conf[0x53] & 0x40) ? 'I' : 'E',
(dev->pci_conf[0x53] & 0x20) ? 'P' : 'I');
dev->states[12] = state;
}
for (uint8_t i = 0; i < 4; i++) {
base = 0xe0000 + (i << 14);
mem_set_mem_state_both(base, 0x4000, (dev->pci_conf[0x54] & (1 << (7 - i))) ? (can_read | can_write) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY));
base = 0xd0000 + (i << 14);
mem_set_mem_state_both(base, 0x4000, (dev->pci_conf[0x55] & (1 << (7 - i))) ? (can_read | can_write) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY));
base = 0xc0000 + (i << 14);
mem_set_mem_state_both(base, 0x4000, (dev->pci_conf[0x56] & (1 << (7 - i))) ? (can_read | can_write) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY));
base = 0x000e0000 + (i << 14);
state = (dev->pci_conf[0x54] & (0x80 >> i)) ?
(can_read | can_write) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY);
if (dev->states[8 + i] != state) {
mem_set_mem_state_both(base, 0x00004000, state);
sis_85c50x_log("%05X-%05X: R%c, W%c\n", base, base + 0x3fff,
(dev->pci_conf[0x543 & (0x80 >> i)) ?
((dev->pci_conf[0x54] & 0x40) ? 'I' : 'D') : 'E',
(dev->pci_conf[0x54] & (0x80 >> i)) ?
((dev->pci_conf[0x53] & 0x20) ? 'P' : 'I') : 'E');
dev->states[8 + i] = state;
}
base = 0x000d0000 + (i << 14);
state = (dev->pci_conf[0x55] & (0x80 >> i)) ?
(can_read | can_write) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY);
if (dev->states[4 + i] != state) {
mem_set_mem_state_both(base, 0x00004000, state);
sis_85c50x_log("%05X-%05X: R%c, W%c\n", base, base + 0x3fff,
(dev->pci_conf[0x55] & (0x80 >> i)) ?
((dev->pci_conf[0x53] & 0x40) ? 'I' : 'D') : 'E',
(dev->pci_conf[0x55] & (0x80 >> i)) ?
((dev->pci_conf[0x53] & 0x20) ? 'P' : 'I') : 'E');
dev->states[4 + i] = state;
}
base = 0x000c0000 + (i << 14);
state = (dev->pci_conf[0x56] & (0x80 >> i)) ?
(can_read | can_write) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY);
if (dev->states[i] != state) {
mem_set_mem_state_both(base, 0x00004000, state);
sis_85c50x_log("%05X-%05X: R%c, W%c\n", base, base + 0x3fff,
(dev->pci_conf[0x56] & (0x80 >> i)) ?
((dev->pci_conf[0x53] & 0x40) ? 'I' : 'D') : 'E',
(dev->pci_conf[0x56] & (0x80 >> i)) ?
((dev->pci_conf[0x53] & 0x20) ? 'P' : 'I') : 'E');
dev->states[i] = state;
}
}
flushmmucache_nopc();
@@ -117,27 +162,35 @@ sis_85c50x_smm_recalc(sis_85c50x_t *dev)
break;
case 0x01:
host_base |= 0x000b0000;
sis_85c50x_log("SiS 50x SMRAM: %08X-%08X -> 000B0000-000BFFFF\n", host_base, host_base + 0x10000 - 1);
sis_85c50x_log("SiS 50x SMRAM: %08X-%08X -> 000B0000-000BFFFF\n",
host_base, host_base + 0x10000 - 1);
smram_enable(dev->smram[0], host_base, 0xb0000, 0x10000, (dev->pci_conf[0x65] & 0x10), 1);
smram_enable(dev->smram[1], host_base ^ 0x00100000, 0xb0000, 0x10000, (dev->pci_conf[0x65] & 0x10), 1);
smram_enable(dev->smram[1], host_base ^ 0x00100000, 0xb0000,
0x10000, (dev->pci_conf[0x65] & 0x10), 1);
break;
case 0x02:
host_base |= 0x000a0000;
sis_85c50x_log("SiS 50x SMRAM: %08X-%08X -> 000A0000-000AFFFF\n", host_base, host_base + 0x10000 - 1);
sis_85c50x_log("SiS 50x SMRAM: %08X-%08X -> 000A0000-000AFFFF\n",
host_base, host_base + 0x10000 - 1);
smram_enable(dev->smram[0], host_base, 0xa0000, 0x10000, (dev->pci_conf[0x65] & 0x10), 1);
smram_enable(dev->smram[1], host_base ^ 0x00100000, 0xa0000, 0x10000, (dev->pci_conf[0x65] & 0x10), 1);
smram_enable(dev->smram[1], host_base ^ 0x00100000, 0xa0000,
0x10000, (dev->pci_conf[0x65] & 0x10), 1);
break;
case 0x04:
host_base |= 0x000a0000;
sis_85c50x_log("SiS 50x SMRAM: %08X-%08X -> 000A0000-000AFFFF\n", host_base, host_base + 0x8000 - 1);
sis_85c50x_log("SiS 50x SMRAM: %08X-%08X -> 000A0000-000AFFFF\n",
host_base, host_base + 0x8000 - 1);
smram_enable(dev->smram[0], host_base, 0xa0000, 0x8000, (dev->pci_conf[0x65] & 0x10), 1);
smram_enable(dev->smram[1], host_base ^ 0x00100000, 0xa0000, 0x8000, (dev->pci_conf[0x65] & 0x10), 1);
smram_enable(dev->smram[1], host_base ^ 0x00100000, 0xa0000,
0x8000, (dev->pci_conf[0x65] & 0x10), 1);
break;
case 0x06:
host_base |= 0x000b0000;
sis_85c50x_log("SiS 50x SMRAM: %08X-%08X -> 000B0000-000BFFFF\n", host_base, host_base + 0x8000 - 1);
sis_85c50x_log("SiS 50x SMRAM: %08X-%08X -> 000B0000-000BFFFF\n",
host_base, host_base + 0x8000 - 1);
smram_enable(dev->smram[0], host_base, 0xb0000, 0x8000, (dev->pci_conf[0x65] & 0x10), 1);
smram_enable(dev->smram[1], host_base ^ 0x00100000, 0xa0000, 0x8000, (dev->pci_conf[0x65] & 0x10), 1);
smram_enable(dev->smram[1], host_base ^ 0x00100000, 0xa0000,
0x8000, (dev->pci_conf[0x65] & 0x10), 1);
break;
default:
break;
@@ -160,7 +213,10 @@ sis_85c50x_write(int func, int addr, uint8_t val, void *priv)
dev->pci_conf[addr] = ((dev->pci_conf[addr] & 0xf9) & ~(val & 0xf8)) | (val & 0x06);
break;
case 0x50:
dev->pci_conf[addr] = val;
if (dev->type & 1)
dev->pci_conf[addr] = val & 0xf7;
else
dev->pci_conf[addr] = val;
break;
case 0x51: /* Cache */
dev->pci_conf[addr] = val;
@@ -176,8 +232,6 @@ sis_85c50x_write(int func, int addr, uint8_t val, void *priv)
case 0x56:
dev->pci_conf[addr] = val;
sis_85c50x_shadow_recalc(dev);
if (addr == 0x54)
sis_85c50x_smm_recalc(dev);
break;
case 0x57:
case 0x58:
@@ -204,6 +258,7 @@ sis_85c50x_write(int func, int addr, uint8_t val, void *priv)
break;
case 0x5b:
dev->pci_conf[addr] = val;
kbc_at_set_fast_reset(!!(val & 0x40));
break;
case 0x60: /* SMI */
if ((dev->pci_conf[0x68] & 0x01) && !(dev->pci_conf[addr] & 0x02) && (val & 0x02)) {
@@ -223,6 +278,31 @@ sis_85c50x_write(int func, int addr, uint8_t val, void *priv)
case 0x69:
dev->pci_conf[addr] &= ~val;
break;
case 0x70 ... 0x77:
if (dev->type & 1)
spd_write_drbs(dev->pci_conf, 0x70, 0x77, 2);
break;
case 0x78:
case 0x7c ... 0x7e:
if (dev->type & 1)
dev->pci_conf[addr] = val;
break;
case 0x79:
if (dev->type & 1) {
spd_write_drbs(dev->pci_conf, 0xf8, 0xff, 4);
dev->pci_conf[addr] = 0x00;
for (uint8_t i = 0; i < 8; i++)
if (dev->pci_conf[0xf8 + i] & 0x80) dev->pci_conf[addr] |= (1 << i);
}
break;
case 0x7a:
if (dev->type & 1)
dev->pci_conf[addr] = val & 0xfe;
break;
case 0x7b:
if (dev->type & 1)
dev->pci_conf[addr] = val & 0xe0;
break;
default:
break;
@@ -235,14 +315,33 @@ sis_85c50x_read(int func, int addr, void *priv)
const sis_85c50x_t *dev = (sis_85c50x_t *) priv;
uint8_t ret = 0xff;
if (func == 0x00)
ret = dev->pci_conf[addr];
if (func == 0x00) {
if (addr >= 0xf8)
ret = 0x00;
else
ret = dev->pci_conf[addr];
}
sis_85c50x_log("85C501: [R] (%02X, %02X) = %02X\n", func, addr, ret);
return ret;
}
static void
sis_85c50x_ide_recalc(sis_85c50x_t *dev)
{
ide_pri_disable();
ide_set_base(0, (dev->pci_conf_ide[0x40] & 0x80) ? 0x0170 : 0x01f0);
ide_set_side(0, (dev->pci_conf_ide[0x40] & 0x80) ? 0x0376 : 0x03f6);
ide_pri_enable();
ide_sec_disable();
ide_set_base(1, (dev->pci_conf_ide[0x40] & 0x80) ? 0x01f0 : 0x0170);
ide_set_side(1, (dev->pci_conf_ide[0x40] & 0x80) ? 0x03f6 : 0x0376);
if (dev->pci_conf_ide[0x41] & 0x01)
ide_sec_enable();
}
static void
sis_85c50x_sb_write(int func, int addr, uint8_t val, void *priv)
{
@@ -250,38 +349,46 @@ sis_85c50x_sb_write(int func, int addr, uint8_t val, void *priv)
sis_85c50x_log("85C503: [W] (%02X, %02X) = %02X\n", func, addr, val);
if (func == 0x00)
switch (addr) {
case 0x04: /* Command */
dev->pci_conf_sb[addr] = val & 0x0f;
break;
case 0x07: /* Status */
dev->pci_conf_sb[addr] &= ~(val & 0x30);
break;
case 0x40: /* BIOS Control Register */
dev->pci_conf_sb[addr] = val & 0x3f;
break;
case 0x41:
case 0x42:
case 0x43:
case 0x44:
/* INTA/B/C/D# Remapping Control Register */
dev->pci_conf_sb[addr] = val & 0x8f;
if (val & 0x80)
pci_set_irq_routing(PCI_INTA + (addr - 0x41), PCI_IRQ_DISABLED);
else
pci_set_irq_routing(PCI_INTA + (addr - 0x41), val & 0xf);
break;
case 0x48: /* ISA Master/DMA Memory Cycle Control Register 1 */
case 0x49: /* ISA Master/DMA Memory Cycle Control Register 2 */
case 0x4a: /* ISA Master/DMA Memory Cycle Control Register 3 */
case 0x4b: /* ISA Master/DMA Memory Cycle Control Register 4 */
dev->pci_conf_sb[addr] = val;
break;
if (func == 0x00) switch (addr) {
case 0x04: /* Command */
dev->pci_conf_sb[addr] = val & 0x0f;
break;
case 0x07: /* Status */
dev->pci_conf_sb[addr] &= ~(val & 0x30);
break;
case 0x40: /* BIOS Control Register */
dev->pci_conf_sb[addr] = val & 0x3f;
break;
case 0x41:
case 0x42:
case 0x43:
case 0x44:
/* INTA/B/C/D# Remapping Control Register */
dev->pci_conf_sb[addr] = val & 0x8f;
if (val & 0x80)
pci_set_irq_routing(PCI_INTA + (addr - 0x41), PCI_IRQ_DISABLED);
else
pci_set_irq_routing(PCI_INTA + (addr - 0x41), val & 0xf);
break;
case 0x48: /* ISA Master/DMA Memory Cycle Control Register 1 */
case 0x49: /* ISA Master/DMA Memory Cycle Control Register 2 */
case 0x4a: /* ISA Master/DMA Memory Cycle Control Register 3 */
case 0x4b: /* ISA Master/DMA Memory Cycle Control Register 4 */
dev->pci_conf_sb[addr] = val;
break;
default:
break;
}
default:
break;
} else if ((dev->type & 2) && !(dev->regs[0x81] & 0x02) && (func == 0x01)) switch (addr) {
case 0x40:
case 0x41:
dev->pci_conf_ide[addr] = val;
sis_85c50x_ide_recalc(dev);
break;
default:
break;
}
}
static uint8_t
@@ -290,8 +397,42 @@ sis_85c50x_sb_read(int func, int addr, void *priv)
const sis_85c50x_t *dev = (sis_85c50x_t *) priv;
uint8_t ret = 0xff;
if (func == 0x00)
ret = dev->pci_conf_sb[addr];
if (func == 0x00) switch (addr) {
default:
ret = dev->pci_conf_sb[addr];
break;
case 0x4c ... 0x4f:
if (dev->type & 2)
ret = pic_read_icw(0, addr & 0x03);
else
ret = dev->pci_conf_sb[addr];
break;
case 0x50 ... 0x53:
if (dev->type & 2)
ret = pic_read_icw(1, addr & 0x03);
else
ret = dev->pci_conf_sb[addr];
break;
case 0x54 ... 0x55:
if (dev->type & 2)
ret = pic_read_ocw(0, addr & 0x01);
else
ret = dev->pci_conf_sb[addr];
break;
case 0x56 ... 0x57:
if (dev->type & 2)
ret = pic_read_ocw(1, addr & 0x01);
else
ret = dev->pci_conf_sb[addr];
break;
case 0x58 ... 0x5f:
if (dev->type & 2)
ret = dev->pit_read_reg(dev->pit, addr & 0x07);
else
ret = dev->pci_conf_sb[addr];
break;
} else if ((dev->type & 2) && !(dev->regs[0x81] & 0x02) && (func == 0x01))
ret = dev->pci_conf_ide[addr];
sis_85c50x_log("85C503: [W] (%02X, %02X) = %02X\n", func, addr, ret);
@@ -313,10 +454,39 @@ sis_85c50x_isa_write(uint16_t addr, uint8_t val, void *priv)
case 0x23:
switch (dev->index) {
case 0x80:
dev->regs[dev->index] = val & 0xe7;
if (dev->type & 2) {
dev->regs[dev->index] = val;
nvr_bank_set(0, !!(val & 0x08), dev->nvr);
} else
dev->regs[dev->index] = val & 0xe7;
switch (val >> 6) {
case 0:
cpu_set_isa_speed(7159091);
break;
case 1:
cpu_set_isa_pci_div(4);
break;
case 2:
cpu_set_isa_pci_div(3);
break;
default:
break;
}
break;
case 0x81:
dev->regs[dev->index] = val & 0xf4;
if (dev->type & 2)
dev->regs[dev->index] = val & 0xf6;
else
dev->regs[dev->index] = val & 0xf4;
break;
case 0x82:
if (dev->type & 2)
dev->regs[dev->index] = val;
break;
case 0x83:
if (dev->type & 2)
dev->regs[dev->index] = val & 0x03;
break;
case 0x84:
case 0x88:
@@ -394,6 +564,12 @@ sis_85c50x_reset(void *priv)
sis_85c50x_write(0, 0x68, 0x00, dev);
sis_85c50x_write(0, 0x69, 0xff, dev);
if (dev->type & 1) {
for (uint8_t i = 0; i < 8; i++)
dev->pci_conf[0x70 + i] = 0x00;
dev->pci_conf[0x79] = 0x00;
}
/* South Bridge (SiS 85C503) */
dev->pci_conf_sb[0x00] = 0x39;
dev->pci_conf_sb[0x01] = 0x10;
@@ -407,10 +583,51 @@ sis_85c50x_reset(void *priv)
dev->pci_conf_sb[0x09] = 0x00;
dev->pci_conf_sb[0x0a] = 0x01;
dev->pci_conf_sb[0x0b] = 0x06;
if (dev->type & 2)
dev->pci_conf_sb[0x0e] = 0x80;
sis_85c50x_sb_write(0, 0x41, 0x80, dev);
sis_85c50x_sb_write(0, 0x42, 0x80, dev);
sis_85c50x_sb_write(0, 0x43, 0x80, dev);
sis_85c50x_sb_write(0, 0x44, 0x80, dev);
if (dev->type & 2) {
/* IDE (SiS 5503) */
dev->pci_conf_ide[0x00] = 0x39;
dev->pci_conf_ide[0x01] = 0x10;
dev->pci_conf_ide[0x02] = 0x01;
dev->pci_conf_ide[0x03] = 0x06;
dev->pci_conf_ide[0x04] = 0x89;
dev->pci_conf_ide[0x05] = 0x00;
dev->pci_conf_ide[0x06] = 0x00;
dev->pci_conf_ide[0x07] = 0x00;
dev->pci_conf_ide[0x08] = 0x00;
dev->pci_conf_ide[0x09] = 0x00;
dev->pci_conf_ide[0x0a] = 0x01;
dev->pci_conf_ide[0x0b] = 0x01;
dev->pci_conf_ide[0x0c] = 0x00;
dev->pci_conf_ide[0x0d] = 0x00;
dev->pci_conf_ide[0x0e] = 0x80;
dev->pci_conf_ide[0x0f] = 0x00;
dev->pci_conf_ide[0x10] = 0x71;
dev->pci_conf_ide[0x11] = 0x01;
dev->pci_conf_ide[0x14] = 0xf1;
dev->pci_conf_ide[0x15] = 0x01;
dev->pci_conf_ide[0x18] = 0x71;
dev->pci_conf_ide[0x19] = 0x03;
dev->pci_conf_ide[0x1c] = 0xf1;
dev->pci_conf_ide[0x1d] = 0x03;
dev->pci_conf_ide[0x20] = 0x01;
dev->pci_conf_ide[0x24] = 0x01;
dev->pci_conf_ide[0x40] = 0x00;
dev->pci_conf_ide[0x41] = 0x40;
sis_85c50x_ide_recalc(dev);
}
cpu_set_isa_speed(7159091);
if (dev->type & 2)
nvr_bank_set(0, 0, dev->nvr);
}
static void
@@ -426,8 +643,10 @@ sis_85c50x_close(void *priv)
static void *
sis_85c50x_init(UNUSED(const device_t *info))
{
sis_85c50x_t *dev = (sis_85c50x_t *) malloc(sizeof(sis_85c50x_t));
memset(dev, 0x00, sizeof(sis_85c50x_t));
sis_85c50x_t *dev = (sis_85c50x_t *) calloc(1, sizeof(sis_85c50x_t));
uint8_t pit_is_fast = (((pit_mode == -1) && is486) || (pit_mode == 1));
dev->type = info->local;
/* 501/502 (Northbridge) */
pci_add_card(PCI_ADD_NORTHBRIDGE, sis_85c50x_read, sis_85c50x_write, dev, &dev->nb_slot);
@@ -441,6 +660,17 @@ sis_85c50x_init(UNUSED(const device_t *info))
dev->port_92 = device_add(&port_92_device);
if (dev->type & 2) {
/* PIT */
dev->pit = device_find_first_priv(DEVICE_PIT);
dev->pit_read_reg = pit_is_fast ? pitf_read_reg : pit_read_reg;
/* NVR */
dev->nvr = device_add(&at_mb_nvr_device);
device_add(&ide_pci_2ch_device);
}
sis_85c50x_reset(dev);
return dev;
@@ -459,3 +689,45 @@ const device_t sis_85c50x_device = {
.force_redraw = NULL,
.config = NULL
};
const device_t sis_550x_85c503_device = {
.name = "SiS 550x",
.internal_name = "sis_550x",
.flags = DEVICE_PCI,
.local = 1,
.init = sis_85c50x_init,
.close = sis_85c50x_close,
.reset = sis_85c50x_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t sis_85c50x_5503_device = {
.name = "SiS 85C50x",
.internal_name = "sis_85c50x",
.flags = DEVICE_PCI,
.local = 2,
.init = sis_85c50x_init,
.close = sis_85c50x_close,
.reset = sis_85c50x_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t sis_550x_device = {
.name = "SiS 550x",
.internal_name = "sis_550x",
.flags = DEVICE_PCI,
.local = 3,
.init = sis_85c50x_init,
.close = sis_85c50x_close,
.reset = sis_85c50x_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -79,17 +79,14 @@
#include <86box/timer.h>
#include <86box/io.h>
#include <86box/device.h>
#include <86box/hdd.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/pic.h>
#include <86box/pci.h>
#include <86box/port_92.h>
#include <86box/chipset.h>
#define IDE_BIT 0x01
#ifdef ENABLE_UMC_8886_LOG
int umc_8886_do_log = ENABLE_UMC_8886_LOG;
@@ -108,18 +105,6 @@ umc_8886_log(const char *fmt, ...)
# define umc_8886_log(fmt, ...)
#endif
/* PCI IRQ Flags */
#define INTA (PCI_INTA + (2 * !(addr & 1)))
#define INTB (PCI_INTB + (2 * !(addr & 1)))
#define IRQRECALCA (((val & 0xf0) != 0) ? ((val & 0xf0) >> 4) : PCI_IRQ_DISABLED)
#define IRQRECALCB (((val & 0x0f) != 0) ? (val & 0x0f) : PCI_IRQ_DISABLED)
/* Disable Internal IDE Flag needed for the AF or BF Southbridge variant */
#define HAS_IDE dev->has_ide
/* Southbridge Revision */
#define SB_ID dev->sb_id
typedef struct umc_8886_t {
uint8_t max_func; /* Last function number */
uint8_t pci_slot;
@@ -128,19 +113,54 @@ typedef struct umc_8886_t {
uint8_t pci_conf_sb[2][256]; /* PCI Registers */
uint16_t sb_id; /* Southbridge Revision */
int has_ide; /* Check if Southbridge Revision is AF or F */
uint16_t sb_id; /* Southbridge Revision */
uint16_t ide_id; /* IDE Revision */
int has_ide; /* Check if Southbridge Revision is F, AF, or BF */
} umc_8886_t;
static void
umc_8886_ide_handler(int status)
umc_8886_ide_handler(umc_8886_t *dev)
{
ide_pri_disable();
ide_sec_disable();
if (status) {
ide_pri_enable();
ide_sec_enable();
if (dev->pci_conf_sb[1][0x04] & 0x01) {
if (dev->pci_conf_sb[1][0x40] & 0x80)
ide_pri_enable();
if (dev->pci_conf_sb[1][0x40] & 0x40)
ide_sec_enable();
}
}
static void
umc_8886_bus_recalc(umc_8886_t *dev)
{
switch (dev->pci_conf_sb[0x00][0xa4] & 0x03) {
case 0x00:
cpu_set_pci_speed(cpu_busspeed / 2);
break;
case 0x01:
cpu_set_pci_speed(cpu_busspeed);
break;
case 0x02:
cpu_set_pci_speed((cpu_busspeed * 2) / 3);
break;
}
switch (dev->pci_conf_sb[0x00][0x56] & 0x03) {
default:
break;
case 0x00:
cpu_set_isa_pci_div(3);
break;
case 0x01:
cpu_set_isa_pci_div(4);
break;
case 0x02:
cpu_set_isa_pci_div(2);
break;
}
}
@@ -148,6 +168,7 @@ static void
umc_8886_write(int func, int addr, uint8_t val, void *priv)
{
umc_8886_t *dev = (umc_8886_t *) priv;
int irq_routing;
if (func <= dev->max_func)
switch (func) {
@@ -155,8 +176,17 @@ umc_8886_write(int func, int addr, uint8_t val, void *priv)
umc_8886_log("UM8886: dev->regs[%02x] = %02x POST %02x\n", addr, val, inb(0x80));
switch (addr) {
case 0x04:
case 0x05:
case 0x04 ... 0x05:
case 0x0c ... 0x0d:
case 0x40 ... 0x42:
case 0x45:
case 0x50 ... 0x55:
case 0x57:
case 0x70 ... 0x76:
case 0x80 ... 0x82:
case 0x90 ... 0x92:
case 0xa0 ... 0xa1:
case 0xa5 ... 0xa8:
dev->pci_conf_sb[func][addr] = val;
break;
@@ -164,72 +194,34 @@ umc_8886_write(int func, int addr, uint8_t val, void *priv)
dev->pci_conf_sb[func][addr] &= ~(val & 0xf9);
break;
case 0x0c:
case 0x0d:
dev->pci_conf_sb[func][addr] = val;
break;
case 0x40:
case 0x41:
case 0x42:
dev->pci_conf_sb[func][addr] = val;
break;
case 0x43:
dev->pci_conf_sb[func][addr] = val;
irq_routing = (dev->pci_conf_sb[func][0x46] & 0x01) ? (val >> 8) :
PCI_IRQ_DISABLED;
pci_set_irq_routing(PCI_INTA, irq_routing);
irq_routing = (dev->pci_conf_sb[func][0x46] & 0x02) ? (val & 0x0f) :
PCI_IRQ_DISABLED;
pci_set_irq_routing(PCI_INTB, irq_routing);
break;
case 0x44:
dev->pci_conf_sb[func][addr] = val;
pci_set_irq_routing(INTA, IRQRECALCA);
pci_set_irq_routing(INTB, IRQRECALCB);
irq_routing = (dev->pci_conf_sb[func][0x46] & 0x04) ? (val >> 8) :
PCI_IRQ_DISABLED;
pci_set_irq_routing(PCI_INTC, irq_routing);
irq_routing = (dev->pci_conf_sb[func][0x46] & 0x08) ? (val & 0x0f) :
PCI_IRQ_DISABLED;
pci_set_irq_routing(PCI_INTD, irq_routing);
break;
case 0x45:
dev->pci_conf_sb[func][addr] = val;
break;
case 0x46:
case 0x46: /* Bits 3-0 = 0 = IRQ disabled, 1 = IRQ enabled. */
case 0x47: /* Bits 3-0 = 0 = IRQ edge-triggered, 1 = IRQ level-triggered. */
/* Bit 6 seems to be the IRQ/SMI# toggle, 1 = IRQ, 0 = SMI#. */
dev->pci_conf_sb[func][addr] = val;
break;
case 0x47:
dev->pci_conf_sb[func][addr] = val;
break;
case 0x50:
case 0x51:
case 0x52:
case 0x53:
case 0x54:
case 0x55:
dev->pci_conf_sb[func][addr] = val;
break;
case 0x56:
dev->pci_conf_sb[func][addr] = val;
switch (val & 3) {
case 0:
cpu_set_isa_pci_div(3);
break;
case 1:
cpu_set_isa_pci_div(4);
break;
case 2:
cpu_set_isa_pci_div(2);
break;
default:
break;
}
break;
case 0x57:
case 0x70 ... 0x76:
case 0x80:
case 0x81:
case 0x90 ... 0x92:
case 0xa0 ... 0xa1:
dev->pci_conf_sb[func][addr] = val;
umc_8886_bus_recalc(dev);
break;
case 0xa2:
@@ -243,7 +235,6 @@ umc_8886_write(int func, int addr, uint8_t val, void *priv)
picint(1 << ((dev->pci_conf_sb[0][0x46] & 0x80) ? 15 : 10));
else
smi_raise();
dev->pci_conf_sb[0][0xa3] |= 0x04;
}
dev->pci_conf_sb[func][addr] = val;
@@ -251,11 +242,7 @@ umc_8886_write(int func, int addr, uint8_t val, void *priv)
case 0xa4:
dev->pci_conf_sb[func][addr] = val;
cpu_set_pci_speed(cpu_busspeed / ((val & 1) ? 1 : 2));
break;
case 0xa5 ... 0xa8:
dev->pci_conf_sb[func][addr] = val;
umc_8886_bus_recalc(dev);
break;
default:
@@ -269,7 +256,8 @@ umc_8886_write(int func, int addr, uint8_t val, void *priv)
switch (addr) {
case 0x04:
dev->pci_conf_sb[func][addr] = val;
umc_8886_ide_handler(val & 1);
if (dev->ide_id == 0x673a)
umc_8886_ide_handler(dev);
break;
case 0x07:
@@ -277,9 +265,17 @@ umc_8886_write(int func, int addr, uint8_t val, void *priv)
break;
case 0x3c:
case 0x41 ... 0x4b:
case 0x54 ... 0x59:
if (dev->ide_id == 0x673a)
dev->pci_conf_sb[func][addr] = val;
break;
case 0x40:
case 0x41:
dev->pci_conf_sb[func][addr] = val;
if (dev->ide_id == 0x673a) {
dev->pci_conf_sb[func][addr] = val;
umc_8886_ide_handler(dev);
}
break;
default:
@@ -311,54 +307,79 @@ umc_8886_reset(void *priv)
memset(dev->pci_conf_sb[0], 0x00, sizeof(dev->pci_conf_sb[0]));
memset(dev->pci_conf_sb[1], 0x00, sizeof(dev->pci_conf_sb[1]));
dev->pci_conf_sb[0][0] = 0x60; /* UMC */
dev->pci_conf_sb[0][1] = 0x10;
dev->pci_conf_sb[0][2] = (SB_ID & 0xff); /* 8886xx */
dev->pci_conf_sb[0][3] = ((SB_ID >> 8) & 0xff);
dev->pci_conf_sb[0][4] = 0x0f;
dev->pci_conf_sb[0][7] = 2;
dev->pci_conf_sb[0][8] = 0x0e;
dev->pci_conf_sb[0][0x00] = 0x60; /* UMC */
dev->pci_conf_sb[0][0x01] = 0x10;
dev->pci_conf_sb[0][0x02] = (dev->sb_id & 0xff); /* 8886xx */
dev->pci_conf_sb[0][0x03] = ((dev->sb_id >> 8) & 0xff);
dev->pci_conf_sb[0][0x04] = 0x0f;
dev->pci_conf_sb[0][0x07] = 0x02;
dev->pci_conf_sb[0][0x08] = 0x0e;
dev->pci_conf_sb[0][0x09] = 0x00;
dev->pci_conf_sb[0][0x0a] = 0x01;
dev->pci_conf_sb[0][0x0b] = 0x06;
dev->pci_conf_sb[0][0x40] = 1;
dev->pci_conf_sb[0][0x41] = 6;
dev->pci_conf_sb[0][0x42] = 8;
dev->pci_conf_sb[0][0x43] = 0x9a;
dev->pci_conf_sb[0][0x44] = 0xbc;
dev->pci_conf_sb[0][0x45] = 4;
dev->pci_conf_sb[0][0x40] = 0x01;
dev->pci_conf_sb[0][0x41] = 0x06;
dev->pci_conf_sb[0][0x42] = 0x08;
dev->pci_conf_sb[0][0x43] = 0x00;
dev->pci_conf_sb[0][0x44] = 0x00;
dev->pci_conf_sb[0][0x45] = 0x04;
dev->pci_conf_sb[0][0x46] = 0x00;
dev->pci_conf_sb[0][0x47] = 0x40;
dev->pci_conf_sb[0][0x50] = 1;
dev->pci_conf_sb[0][0x51] = 3;
dev->pci_conf_sb[0][0x50] = 0x01;
dev->pci_conf_sb[0][0x51] = 0x03;
dev->pci_conf_sb[0][0x56] = dev->pci_conf_sb[0][0x57] = 0x00;
dev->pci_conf_sb[0][0x70] = dev->pci_conf_sb[0][0x71] = 0x00;
dev->pci_conf_sb[0][0x72] = dev->pci_conf_sb[0][0x73] = 0x00;
dev->pci_conf_sb[0][0x74] = dev->pci_conf_sb[0][0x76] = 0x00;
dev->pci_conf_sb[0][0x82] = 0x00;
dev->pci_conf_sb[0][0x90] = dev->pci_conf_sb[0][0x91] = 0x00;
dev->pci_conf_sb[0][0xa0] = dev->pci_conf_sb[0][0xa2] = 0x00;
dev->pci_conf_sb[0][0xa4] = 0x00;
dev->pci_conf_sb[0][0xa8] = 0x20;
if (HAS_IDE) {
dev->pci_conf_sb[1][0] = 0x60; /* UMC */
dev->pci_conf_sb[1][1] = 0x10;
if (dev->has_ide) {
dev->pci_conf_sb[1][0x00] = 0x60; /* UMC */
dev->pci_conf_sb[1][0x01] = 0x10;
dev->pci_conf_sb[1][0x02] = (dev->ide_id & 0xff); /* 8886xx IDE */
dev->pci_conf_sb[1][0x03] = ((dev->ide_id >> 8) & 0xff);
dev->pci_conf_sb[1][0x04] = 0x05; /* Start with Internal IDE Enabled */
dev->pci_conf_sb[1][0x08] = 0x10;
dev->pci_conf_sb[1][0x09] = 0x8f;
dev->pci_conf_sb[1][0x0a] = dev->pci_conf_sb[1][0x0b] = 0x01;
dev->pci_conf_sb[1][0x10] = 0xf1;
dev->pci_conf_sb[1][0x11] = 0x01;
dev->pci_conf_sb[1][0x14] = 0xf5;
dev->pci_conf_sb[1][0x15] = 0x03;
dev->pci_conf_sb[1][0x18] = 0x71;
dev->pci_conf_sb[1][0x19] = 0x01;
dev->pci_conf_sb[1][0x1c] = 0x75;
dev->pci_conf_sb[1][0x1d] = 0x03;
dev->pci_conf_sb[1][0x20] = 0x01;
dev->pci_conf_sb[1][0x21] = 0x10;
dev->pci_conf_sb[1][2] = 0x3a; /* 8886BF IDE */
dev->pci_conf_sb[1][3] = 0x67;
if (dev->ide_id == 0x673a) {
dev->pci_conf_sb[1][0x40] = 0xc0;
dev->pci_conf_sb[1][0x41] = 0x00;
dev->pci_conf_sb[1][0x42] = dev->pci_conf_sb[1][0x43] = 0x00;
dev->pci_conf_sb[1][0x44] = dev->pci_conf_sb[1][0x45] = 0x00;
dev->pci_conf_sb[1][0x46] = dev->pci_conf_sb[1][0x47] = 0x00;
dev->pci_conf_sb[1][0x48] = dev->pci_conf_sb[1][0x49] = 0x00;
dev->pci_conf_sb[1][0x4a] = dev->pci_conf_sb[1][0x4b] = 0x00;
dev->pci_conf_sb[1][0x54] = dev->pci_conf_sb[1][0x55] = 0x00;
dev->pci_conf_sb[1][0x56] = dev->pci_conf_sb[1][0x57] = 0x00;
dev->pci_conf_sb[1][0x58] = dev->pci_conf_sb[1][0x59] = 0x00;
dev->pci_conf_sb[1][4] = 1; /* Start with Internal IDE Enabled */
umc_8886_ide_handler(dev);
dev->pci_conf_sb[1][8] = 0x10;
dev->pci_conf_sb[1][0x09] = 0x0f;
dev->pci_conf_sb[1][0x0a] = dev->pci_conf_sb[1][0x0b] = 1;
umc_8886_ide_handler(1);
picintc(1 << 14);
picintc(1 << 15);
}
}
for (uint8_t i = 1; i < 5; i++) /* Disable all IRQ interrupts */
pci_set_irq_routing(i, PCI_IRQ_DISABLED);
cpu_set_isa_pci_div(3);
cpu_set_pci_speed(cpu_busspeed / 2);
umc_8886_bus_recalc(dev);
}
static void
@@ -375,17 +396,28 @@ umc_8886_init(const device_t *info)
umc_8886_t *dev = (umc_8886_t *) malloc(sizeof(umc_8886_t));
memset(dev, 0, sizeof(umc_8886_t));
dev->has_ide = !!(info->local == 0x886a);
pci_add_card(PCI_ADD_SOUTHBRIDGE, umc_8886_read, umc_8886_write, dev, &dev->pci_slot); /* Device 12: UMC 8886xx */
/* Add IDE if UM8886AF variant */
if (HAS_IDE)
device_add(&ide_pci_2ch_device);
dev->max_func = (HAS_IDE) ? 1 : 0;
/* Device 12: UMC 8886xx */
pci_add_card(PCI_ADD_SOUTHBRIDGE, umc_8886_read, umc_8886_write, dev, &dev->pci_slot);
/* Get the Southbridge Revision */
SB_ID = info->local;
dev->sb_id = info->local & 0xffff;
/* IDE Revision */
dev->ide_id = info->local >> 16;
dev->has_ide = (dev->ide_id != 0x0000);
dev->max_func = 0;
/* Add IDE if this is the UM8886AF or UM8886BF. */
if (dev->ide_id == 0x673a) {
/* UM8886BF */
device_add(&ide_pci_2ch_device);
dev->max_func = 1;
} else if (dev->ide_id == 0x1001) {
/* UM8886AF */
device_add(&ide_um8673f_device);
}
umc_8886_reset(dev);
@@ -396,7 +428,7 @@ const device_t umc_8886f_device = {
.name = "UMC 8886F",
.internal_name = "umc_8886f",
.flags = DEVICE_PCI,
.local = 0x8886,
.local = 0x00008886,
.init = umc_8886_init,
.close = umc_8886_close,
.reset = umc_8886_reset,
@@ -407,10 +439,24 @@ const device_t umc_8886f_device = {
};
const device_t umc_8886af_device = {
.name = "UMC 8886AF/8886BF",
.name = "UMC 8886AF",
.internal_name = "umc_8886af",
.flags = DEVICE_PCI,
.local = 0x886a,
.local = 0x1001886a,
.init = umc_8886_init,
.close = umc_8886_close,
.reset = umc_8886_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t umc_8886bf_device = {
.name = "UMC 8886BF",
.internal_name = "umc_8886bf",
.flags = DEVICE_PCI,
.local = 0x673a888a,
.init = umc_8886_init,
.close = umc_8886_close,
.reset = umc_8886_reset,

241
src/chipset/umc_8890.c Normal file
View File

@@ -0,0 +1,241 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Implementation of the UMC 8890 Chipset.
*
* Note: This chipset has no datasheet, everything were done via
* reverse engineering the BIOS of various machines using it.
*
* Authors: Tiseno100,
* Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2021 Tiseno100.
* Copyright 2021-2024 Miran Grca.
*/
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include "cpu.h"
#include <86box/timer.h>
#include <86box/io.h>
#include <86box/device.h>
#include <86box/apm.h>
#include <86box/mem.h>
#include <86box/pci.h>
#include <86box/port_92.h>
#include <86box/smram.h>
#include <86box/chipset.h>
#ifdef ENABLE_UMC_8890_LOG
int umc_8890_do_log = ENABLE_UMC_8890_LOG;
static void
umc_8890_log(const char *fmt, ...)
{
va_list ap;
if (umc_8890_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define umc_8890_log(fmt, ...)
#endif
typedef struct umc_8890_t {
uint8_t pci_slot;
uint8_t pci_conf[256]; /* PCI Registers */
int mem_state[2];
uint32_t smram_base;
smram_t *smram; /* SMRAM Handler */
} umc_8890_t;
static void
um8890_shadow(umc_8890_t *dev)
{
uint8_t flag;
uint16_t state;
flag = (dev->pci_conf[0x5f] & 0x0c) >> 2;
state = (flag & 1) ? (MEM_READ_INTERNAL | ((flag & 2) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL)) :
(MEM_READ_EXTANY | MEM_WRITE_EXTANY);
if ((dev->mem_state[1] ^ dev->pci_conf[0x5f]) & 0x0c) {
mem_set_mem_state_both(0xe0000, 0x10000, state);
dev->mem_state[1] = (dev->mem_state[1] & 0xf0) | (dev->pci_conf[0x5f] & 0x0f);
}
flag = (dev->pci_conf[0x5f] & 0xc0) >> 6;
state = (flag & 1) ? (MEM_READ_INTERNAL | ((flag & 2) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL)) :
(MEM_READ_EXTANY | MEM_WRITE_EXTANY);
if ((dev->mem_state[1] ^ dev->pci_conf[0x5f]) & 0xc0) {
mem_set_mem_state_both(0xf0000, 0x10000, state);
dev->mem_state[1] = (dev->mem_state[1] & 0x0f) | (dev->pci_conf[0x5f] & 0xf0);
}
for (uint8_t i = 0; i < 8; i++) {
state = (dev->pci_conf[0x5d] & (1 << i)) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) :
(MEM_READ_EXTANY | MEM_WRITE_EXTANY);
if ((dev->mem_state[0] ^ dev->pci_conf[0x5d]) & (1 << i)) {
mem_set_mem_state_both(0xc0000 + (i << 14), 0x4000, state);
dev->mem_state[0] = (dev->mem_state[0] & ~(1 << i)) | (dev->pci_conf[0x5d] & (1 << i));
}
}
flushmmucache_nopc();
}
static void
um8890_smram(umc_8890_t *dev)
{
smram_disable_all();
/* Bit 4, if set, enables SMRAM access outside SMM. SMRAM appears to be always enabled
in SMM, and is always set to A0000-BFFFF. */
smram_enable(dev->smram, 0x000a0000, 0x000a0000, 0x20000, dev->pci_conf[0x65] & 0x10, 1);
}
static void
um8890_write(int func, int addr, uint8_t val, void *priv)
{
umc_8890_t *dev = (umc_8890_t *)priv;
if (func == 0) switch (addr) {
case 0x04 ... 0x05:
case 0x0c ... 0x0d:
case 0x40 ... 0x5b:
case 0x60 ... 0x63:
case 0x66 ... 0xff:
dev->pci_conf[addr] = val;
break;
case 0x07:
dev->pci_conf[addr] &= ~(val & 0xf9);
break;
case 0x5c ... 0x5f:
dev->pci_conf[addr] = val;
um8890_shadow(dev);
break;
/* Register 64h, 16-bit:
Bit 12: SMRAM enabled outside SMM (1 = yes, 0 = no);
Bit 10: ???? (set by Award BIOS);
Bits 7- 0: SMM handler offset to SMBASE, shifted to the right by 14.
*/
case 0x64: case 0x65:
dev->pci_conf[addr] = val;
if (addr == 0x65)
um8890_smram(dev);
break;
}
umc_8890_log("UM8890: dev->regs[%02x] = %02x POST: %02x\n", addr, dev->pci_conf[addr], inb(0x80));
}
static uint8_t
um8890_read(int func, int addr, void *priv)
{
umc_8890_t *dev = (umc_8890_t *)priv;
uint8_t ret = 0xff;
if (func == 0)
ret = dev->pci_conf[addr];
return ret;
}
static void
umc_8890_reset(void *priv)
{
umc_8890_t *dev = (umc_8890_t *)priv;
memset(dev->pci_conf, 0x00, sizeof(dev->pci_conf));
/* Defaults */
dev->pci_conf[0x00] = 0x60; /* UMC */
dev->pci_conf[0x01] = 0x10;
dev->pci_conf[0x02] = 0x91; /* 8891F */
dev->pci_conf[0x03] = 0x88;
dev->pci_conf[0x07] = 0x02;
dev->pci_conf[0x08] = 0x01;
dev->pci_conf[0x09] = 0x00;
dev->pci_conf[0x0a] = 0x00;
dev->pci_conf[0x0b] = 0x06;
dev->pci_conf[0x5c] = 0x00;
dev->pci_conf[0x5d] = 0x00;
dev->pci_conf[0x5e] = 0x00;
dev->pci_conf[0x5f] = 0x00;
dev->pci_conf[0x64] = 0x00;
dev->pci_conf[0x65] = 0x00;
um8890_shadow(dev);
um8890_smram(dev);
}
static void
umc_8890_close(void *priv)
{
umc_8890_t *dev = (umc_8890_t *)priv;
smram_del(dev->smram);
free(dev);
}
static void *
umc_8890_init(const device_t *info)
{
umc_8890_t *dev = (umc_8890_t *) calloc(1, sizeof(umc_8890_t));
/* Device 0: UMC 8890 */
pci_add_card(PCI_ADD_NORTHBRIDGE, um8890_read, um8890_write, dev, &dev->pci_slot);
/* Port 92 */
device_add(&port_92_pci_device);
dev->smram = smram_add();
umc_8890_reset(dev);
return dev;
}
const device_t umc_8890_device = {
.name = "UMC 8890(8891BF/8892BF)",
.internal_name = "umc_8890",
.flags = DEVICE_PCI,
.local = 0x886a,
.init = umc_8890_init,
.close = umc_8890_close,
.reset = umc_8890_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -14,13 +14,11 @@
* Note 2: Additional information were also used from all
* around the web.
*
*
*
* Authors: Tiseno100,
* Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2021 Tiseno100.
* Copyright 2021 Miran Grca.
* Copyright 2021-2024 Miran Grca.
*/
/*
@@ -75,15 +73,24 @@
Bit 3: CC000-CFFFF Read Enable
Bit 2: C8000-CBFFF Read Enable
Bit 1: C0000-C7FFF Read Enable
Bit 0: Enable C0000-DFFFF Shadow Segment Bits
Bit 0: E0000-EFFFF Read Enable
Register 55:
Bit 7: E0000-FFFF Read Enable
Bit 7: F0000-FFFF Read Enable
Bit 6: Shadow Write Status (1: Write Protect/0: Write)
Register 56h & 57h: DRAM Bank 0 Configuration
Register 58h & 59h: DRAM Bank 1 Configuration
Register 5A:
Bit 2: Detrubo
Register 5C:
Bits 7-0: SMRAM base A27-A20
Register 5D:
Bits 3-0: SMRAM base A31-A28
Register 60:
Bit 5: If set and SMRAM is enabled, data cycles go to PCI and code cycles go to DRAM
Bit 0: SMRAM Local Access Enable - if set, SMRAM is also enabled outside SMM
@@ -129,14 +136,15 @@ hb4_log(const char *fmt, ...)
#endif
typedef struct hb4_t {
uint8_t shadow;
uint8_t shadow_read;
uint8_t shadow_write;
uint8_t pci_slot;
uint8_t pci_conf[256]; /* PCI Registers */
int mem_state[9];
smram_t *smram[3]; /* SMRAM Handlers */
uint32_t smram_base;
smram_t *smram; /* SMRAM Handler */
} hb4_t;
static int shadow_bios[4] = { (MEM_READ_EXTANY | MEM_WRITE_INTERNAL), (MEM_READ_EXTANY | MEM_WRITE_EXTANY),
@@ -167,7 +175,8 @@ hb4_shadow_bios_low(hb4_t *dev)
{
int state;
state = shadow_bios[(dev->pci_conf[0x55] >> 6) & (dev->shadow | 0x01)];
/* Erratum in Vogons' datasheet: Register 55h bit 7 in fact controls E0000-FFFFF. */
state = shadow_bios[dev->pci_conf[0x55] >> 6];
if (state != dev->mem_state[7]) {
mem_set_mem_state_both(0xe0000, 0x10000, state);
@@ -185,7 +194,8 @@ hb4_shadow_main(hb4_t *dev)
int n = 0;
for (uint8_t i = 0; i < 6; i++) {
state = shadow_read[dev->shadow && ((dev->pci_conf[0x54] >> (i + 2)) & 0x01)] | shadow_write[(dev->pci_conf[0x55] >> 6) & 0x01];
state = shadow_read[(dev->pci_conf[0x54] >> (i + 2)) & 0x01] |
shadow_write[(dev->pci_conf[0x55] >> 6) & 0x01];
if (state != dev->mem_state[i + 1]) {
n++;
@@ -202,7 +212,8 @@ hb4_shadow_video(hb4_t *dev)
{
int state;
state = shadow_read[dev->shadow && ((dev->pci_conf[0x54] >> 1) & 0x01)] | shadow_write[(dev->pci_conf[0x55] >> 6) & 0x01];
state = shadow_read[(dev->pci_conf[0x54] >> 1) & 0x01] |
shadow_write[(dev->pci_conf[0x55] >> 6) & 0x01];
if (state != dev->mem_state[0]) {
mem_set_mem_state_both(0xc0000, 0x8000, state);
@@ -232,22 +243,26 @@ static void
hb4_smram(hb4_t *dev)
{
smram_disable_all();
if (dev->smram_base != 0x00000000)
umc_smram_recalc(dev->smram_base >> 12, 0);
dev->smram_base = ((uint32_t) dev->pci_conf[0x5c]) << 20;
dev->smram_base |= ((uint32_t) (dev->pci_conf[0x5d] & 0x0f)) << 28;
dev->smram_base |= 0x000a0000;
/* Bit 0, if set, enables SMRAM access outside SMM. SMRAM appears to be always enabled
in SMM, and is always set to A0000-BFFFF. */
smram_enable(dev->smram[0], 0x000a0000, 0x000a0000, 0x20000, dev->pci_conf[0x60] & 0x01, 1);
/* There's a mirror of the SMRAM at 0E0A0000, mapped to A0000. */
smram_enable(dev->smram[1], 0x0e0a0000, 0x000a0000, 0x20000, dev->pci_conf[0x60] & 0x01, 1);
/* There's another mirror of the SMRAM at 4E0A0000, mapped to A0000. */
smram_enable(dev->smram[2], 0x4e0a0000, 0x000a0000, 0x20000, dev->pci_conf[0x60] & 0x01, 1);
smram_enable(dev->smram, dev->smram_base, 0x000a0000, 0x20000, dev->pci_conf[0x60] & 0x01, 1);
/* Bit 5 seems to set data to go to PCI and code to DRAM. The Samsung SPC7700P-LW uses
this. */
if (dev->pci_conf[0x60] & 0x20) {
if (dev->pci_conf[0x60] & 0x01)
mem_set_mem_state_smram_ex(0, 0x000a0000, 0x20000, 0x02);
mem_set_mem_state_smram_ex(1, 0x000a0000, 0x20000, 0x02);
mem_set_mem_state_smram_ex(0, dev->smram_base, 0x20000, 0x02);
mem_set_mem_state_smram_ex(1, dev->smram_base, 0x20000, 0x02);
}
umc_smram_recalc(dev->smram_base >> 12, 1);
}
static void
@@ -278,38 +293,27 @@ hb4_write(UNUSED(int func), int addr, uint8_t val, void *priv)
cpu_update_waitstates();
break;
case 0x51:
case 0x52:
case 0x51 ... 0x53:
dev->pci_conf[addr] = val;
break;
case 0x53:
dev->pci_conf[addr] = val;
hb4_log("HB53: %02X\n", val);
break;
case 0x55:
dev->shadow_read = (val & 0x80);
dev->shadow_write = (val & 0x40);
dev->pci_conf[addr] = val;
hb4_shadow(dev);
break;
case 0x54:
dev->shadow = (val & 0x01) << 1;
case 0x54 ... 0x55:
dev->pci_conf[addr] = val;
hb4_shadow(dev);
break;
case 0x56 ... 0x5f:
case 0x56 ... 0x5b:
case 0x5e ... 0x5f:
dev->pci_conf[addr] = val;
break;
case 0x5c ... 0x5d:
case 0x60:
dev->pci_conf[addr] = val;
hb4_smram(dev);
break;
case 0x61:
case 0x61 ... 0x62:
dev->pci_conf[addr] = val;
break;
@@ -336,30 +340,35 @@ hb4_reset(void *priv)
hb4_t *dev = (hb4_t *) priv;
memset(dev->pci_conf, 0x00, sizeof(dev->pci_conf));
dev->pci_conf[0] = 0x60; /* UMC */
dev->pci_conf[1] = 0x10;
dev->pci_conf[2] = 0x81; /* 8881x */
dev->pci_conf[3] = 0x88;
dev->pci_conf[7] = 2;
dev->pci_conf[8] = 4;
dev->pci_conf[0x00] = 0x60; /* UMC */
dev->pci_conf[0x01] = 0x10;
dev->pci_conf[0x02] = 0x81; /* 8881x */
dev->pci_conf[0x03] = 0x88;
dev->pci_conf[0x07] = 0x02;
dev->pci_conf[0x08] = 0x04;
dev->pci_conf[0x09] = 0x00;
dev->pci_conf[0x0a] = 0x00;
dev->pci_conf[0x0b] = 0x06;
dev->pci_conf[0x51] = 1;
dev->pci_conf[0x52] = 1;
dev->pci_conf[0x5a] = 4;
dev->pci_conf[0x5c] = 0xc0;
dev->pci_conf[0x50] = 0x00;
dev->pci_conf[0x51] = 0x00;
dev->pci_conf[0x52] = 0x01;
dev->pci_conf[0x53] = 0x00;
dev->pci_conf[0x54] = 0x00;
dev->pci_conf[0x55] = 0x00;
dev->pci_conf[0x56] = 0x00;
dev->pci_conf[0x57] = 0x00;
dev->pci_conf[0x58] = 0x00;
dev->pci_conf[0x59] = 0x00;
dev->pci_conf[0x5a] = 0x04;
dev->pci_conf[0x5c] = 0x00;
dev->pci_conf[0x5d] = 0x20;
dev->pci_conf[0x5f] = 0xff;
dev->pci_conf[0x60] = 0x00;
dev->pci_conf[0x61] = 0x00;
dev->pci_conf[0x62] = 0x00;
hb4_write(0, 0x54, 0x00, dev);
hb4_write(0, 0x55, 0x00, dev);
hb4_write(0, 0x60, 0x80, dev);
hb4_shadow(dev);
hb4_smram(dev);
cpu_cache_ext_enabled = 0;
cpu_update_waitstates();
@@ -372,6 +381,7 @@ hb4_close(void *priv)
{
hb4_t *dev = (hb4_t *) priv;
smram_del(dev->smram);
free(dev);
}
@@ -387,10 +397,9 @@ hb4_init(UNUSED(const device_t *info))
device_add(&port_92_pci_device);
/* SMRAM */
dev->smram[0] = smram_add();
dev->smram[1] = smram_add();
dev->smram[2] = smram_add();
dev->smram = smram_add();
dev->smram_base = 0x000a0000;
hb4_reset(dev);
return dev;

View File

@@ -444,7 +444,7 @@ via_apollo_host_bridge_write(int func, int addr, uint8_t val, void *priv)
apollo_smram_map(dev, 0, 0x000a0000, 0x00020000, 0);
break;
}
else
else if (dev->id == VIA_595)
switch (val & 0x03) {
case 0x00:
apollo_smram_map(dev, 1, 0x000a0000, 0x00020000, 0);
@@ -468,6 +468,12 @@ via_apollo_host_bridge_write(int func, int addr, uint8_t val, void *priv)
default:
break;
}
else {
smram_enable(dev->smram, 0x000a0000, 0x000a0000, 0x00020000,
(dev->pci_conf[0x6d] & 0x10) && (dev->pci_conf[0x63] & 0x01),
dev->pci_conf[0x63] & 0x01);
flushmmucache();
}
break;
case 0x65:
if (dev->id == VIA_585)
@@ -532,6 +538,13 @@ via_apollo_host_bridge_write(int func, int addr, uint8_t val, void *priv)
dev->pci_conf[0x6d] = (dev->pci_conf[0x6d] & ~0x7f) | (val & 0x7f);
else
dev->pci_conf[0x6d] = val;
if (dev->id == VIA_585) {
smram_disable_all();
smram_enable(dev->smram, 0x000a0000, 0x000a0000, 0x00020000,
(dev->pci_conf[0x6d] & 0x10) && (dev->pci_conf[0x63] & 0x01),
dev->pci_conf[0x63] & 0x01);
flushmmucache();
}
break;
case 0x6e:
if ((dev->id == VIA_595) || (dev->id == VIA_694))

View File

@@ -84,6 +84,7 @@ typedef struct
uint8_t bios_states[8];
uint8_t high_bios_states[8];
uint8_t mem_pages[1024];
uint8_t ram_state[4192];
uint16_t toggle, cpuclk, fpu_ctl, mem_ctl,
split_sa, sh_wp, hmwpb, npmdmt,
@@ -225,6 +226,34 @@ wd76c10_write_ramw(uint32_t addr, uint16_t val, void *priv)
mem_write_ramw(addr, val, priv);
}
static void
wd76c10_set_mem_state(wd76c10_t *dev, uint32_t base, uint32_t size, uint32_t access, uint8_t present)
{
mem_set_mem_state_both(base, size, access);
for (uint32_t i = base; i < (base + size); i += 4096)
dev->ram_state[i >> 12] = present;
}
static void
wd76c10_recalc_exec(wd76c10_t *dev, uint32_t base, uint32_t size)
{
uint32_t logical_addr = wd76c10_calc_addr(dev, base);
void *exec;
if (logical_addr != WD76C10_ADDR_INVALID)
exec = &(ram[logical_addr]);
else
exec = NULL;
for (uint32_t i = base; i < (base + size); i += 4096)
if (dev->ram_state[i >> 12])
_mem_exec[i >> 12] = exec;
if (cpu_use_exec)
flushmmucache_nopc();
}
static void
wd76c10_banks_recalc(wd76c10_t *dev)
{
@@ -235,6 +264,9 @@ wd76c10_banks_recalc(wd76c10_t *dev)
bit = i + 12;
rb->enable = (dev->split_sa >> bit) & 0x01;
rb->virt_addr = ((uint32_t) dev->bank_bases[i]) << 17;
if (cpu_use_exec)
wd76c10_recalc_exec(dev, rb->virt_addr, rb->virt_size);
}
}
@@ -245,8 +277,12 @@ wd76c10_split_recalc(wd76c10_t *dev)
uint32_t split_size = ((sp_size - 1) * 65536);
ram_bank_t *rb = &(dev->ram_banks[4]);
if (rb->enable && (rb->virt_size != 0x00000000))
mem_set_mem_state(rb->virt_addr, rb->virt_size, MEM_READ_EXTANY | MEM_WRITE_EXTANY);
if (rb->enable && (rb->virt_size != 0x00000000)) {
wd76c10_set_mem_state(dev, rb->virt_addr, rb->virt_size, MEM_READ_EXTANY | MEM_WRITE_EXTANY, 0);
if (cpu_use_exec)
wd76c10_recalc_exec(dev, rb->virt_addr, rb->virt_size);
}
rb->virt_addr = ((uint32_t) ((dev->split_sa >> 2) & 0x3f)) << 19;
switch (sp_size) {
case 0x00:
@@ -257,8 +293,12 @@ wd76c10_split_recalc(wd76c10_t *dev)
break;
}
rb->enable = !!sp_size;
if (rb->enable && (rb->virt_size != 0x00000000))
mem_set_mem_state(rb->virt_addr, rb->virt_size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
if (rb->enable && (rb->virt_size != 0x00000000)) {
wd76c10_set_mem_state(dev, rb->virt_addr, rb->virt_size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL, 1);
if (cpu_use_exec)
wd76c10_recalc_exec(dev, rb->virt_addr, rb->virt_size);
}
}
static void
@@ -284,10 +324,13 @@ wd76c10_dis_mem_recalc(wd76c10_t *dev)
}
dev->mem_top = mem_top;
if (cpu_use_exec)
wd76c10_recalc_exec(dev, 128 * 1024, (640 - 128) * 1024);
}
static void
wd76c10_shadow_ram_do_recalc(uint8_t *new_st, uint8_t *old_st, uint8_t min, uint8_t max, uint32_t addr)
wd76c10_shadow_ram_do_recalc(wd76c10_t *dev, uint8_t *new_st, uint8_t *old_st, uint8_t min, uint8_t max, uint32_t addr)
{
uint32_t base = 0x00000000;
int flags = 0;
@@ -300,7 +343,9 @@ wd76c10_shadow_ram_do_recalc(uint8_t *new_st, uint8_t *old_st, uint8_t min, uint
((new_st[i] & 0x04) ? MEM_READ_ROMCS : MEM_READ_EXTERNAL);
flags |= (new_st[i] & 0x02) ? MEM_WRITE_INTERNAL :
((new_st[i] & 0x04) ? MEM_WRITE_ROMCS : MEM_WRITE_EXTERNAL);
mem_set_mem_state_both(base, 0x00004000, flags);
wd76c10_set_mem_state(dev, base, 0x00004000, flags, new_st[i] & 0x01);
if (cpu_use_exec)
wd76c10_recalc_exec(dev, base, 0x000040000);
}
}
}
@@ -366,11 +411,11 @@ wd76c10_shadow_ram_recalc(wd76c10_t *dev)
break;
}
wd76c10_shadow_ram_do_recalc(vbios_states, dev->vbios_states, 0, 4, 0x000c0000);
wd76c10_shadow_ram_do_recalc(bios_states, dev->bios_states, 0, 8, 0x000e0000);
wd76c10_shadow_ram_do_recalc(dev, vbios_states, dev->vbios_states, 0, 4, 0x000c0000);
wd76c10_shadow_ram_do_recalc(dev, bios_states, dev->bios_states, 0, 8, 0x000e0000);
/* This is not shadowed, but there is a CSPROM# (= ROMCS#) toggle. */
wd76c10_shadow_ram_do_recalc(high_bios_states, dev->high_bios_states, 0, 8, 0x00fe0000);
wd76c10_shadow_ram_do_recalc(dev, high_bios_states, dev->high_bios_states, 0, 8, 0x00fe0000);
flushmmucache_nopc();
}
@@ -385,9 +430,15 @@ wd76c10_high_mem_wp_recalc(wd76c10_t *dev)
/* ACCESS_NORMAL means both ACCESS_BUS and ACCESS_CPU are set. */
mem_set_wp(dev->hmwp_base, size, ACCESS_NORMAL, 0);
if (cpu_use_exec)
wd76c10_recalc_exec(dev, dev->hmwp_base, size);
size = 0x01000000 - base;
mem_set_wp(base, size, ACCESS_NORMAL, hm_wp);
if (cpu_use_exec)
wd76c10_recalc_exec(dev, base, size);
dev->hmwp_base = base;
}
@@ -399,7 +450,10 @@ wd76c10_pf_loc_reset(wd76c10_t *dev)
for (uint8_t i = 0x031; i <= 0x03b; i++) {
dev->mem_pages[i] = 0xff;
base = ((uint32_t) i) << 14;
mem_set_mem_state(base, 0x00004000, MEM_READ_EXTANY | MEM_WRITE_EXTANY);
wd76c10_set_mem_state(dev, base, 0x00004000, MEM_READ_EXTANY | MEM_WRITE_EXTANY, 0);
if (cpu_use_exec)
wd76c10_recalc_exec(dev, base, 0x00004000);
}
/* Re-apply any ROMCS#, etc. flags. */
@@ -419,9 +473,13 @@ wd76c10_pf_loc_recalc(wd76c10_t *dev)
dev->mem_pages[i] = ems_page;
base = ((uint32_t) i) << 14;
dev->ems_pages[ems_page].virt = base;
if ((ems_en >= 0x02) && dev->ems_pages[ems_page].enabled)
mem_set_mem_state(dev->ems_pages[ems_page].virt, 0x00004000,
MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
if ((ems_en >= 0x02) && dev->ems_pages[ems_page].enabled) {
wd76c10_set_mem_state(dev, dev->ems_pages[ems_page].virt,
0x00004000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL, 1);
if (cpu_use_exec)
wd76c10_recalc_exec(dev, dev->ems_pages[ems_page].virt, 0x00004000);
}
}
}
@@ -436,6 +494,9 @@ wd76c10_low_pages_recalc(wd76c10_t *dev)
dev->mem_pages[i] = ems_page;
base = ((uint32_t) i) << 14;
dev->ems_pages[ems_page].virt = base;
if (cpu_use_exec)
wd76c10_recalc_exec(dev, dev->ems_pages[ems_page].virt, 0x00004000);
}
}
@@ -948,6 +1009,8 @@ wd76c10_init(const device_t *info)
mem_mapping_disable(&ram_high_mapping);
mem_mapping_enable(&dev->ram_mapping);
memset(dev->ram_state, 0x00, sizeof(dev->ram_state));
return dev;
}

View File

@@ -12,6 +12,7 @@
#include "x86_flags.h"
#include "x86seg_common.h"
#include "x86seg.h"
#include "x87_sf.h"
#include "x87.h"
#include "386_common.h"
#include "cpu.h"

View File

@@ -671,9 +671,10 @@ ropFCHS(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeb
ropFLD##name(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \
{ \
static double fp_imm = v; \
static uint64_t *fptr = (uint64_t *) &fp_imm; \
\
FP_ENTER(); \
FP_LOAD_IMM_Q(*(uint64_t *) &fp_imm); \
FP_LOAD_IMM_Q(*fptr); \
\
return op_pc; \
}

View File

@@ -4434,7 +4434,7 @@ FP_COMPARE_REG(int dst, int src)
addbyte((uint8_t) cpu_state_offset(npxs) + 1);
addbyte(0x80); /*AND CL, ~(C0|C2|C3)*/
addbyte(0xe1);
addbyte((~(C0 | C2 | C3)) >> 8);
addbyte((~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)) >> 8);
if (src) {
addbyte(0xf3); /*MOVQ XMM0, ST[RBX*8]*/
@@ -4467,7 +4467,7 @@ FP_COMPARE_REG(int dst, int src)
addbyte(0x9f); /*LAHF*/
addbyte(0x80); /*AND AH, (C0|C2|C3)*/
addbyte(0xe4);
addbyte((C0 | C2 | C3) >> 8);
addbyte((FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3) >> 8);
addbyte(0x08); /*OR CL, AH*/
addbyte(0xe1);
addbyte(0x88); /*MOV [npxs+1], CL*/
@@ -4493,7 +4493,7 @@ FP_COMPARE_MEM(void)
addbyte((uint8_t) cpu_state_offset(ST));
addbyte(0x80); /*AND CL, ~(C0|C2|C3)*/
addbyte(0xe1);
addbyte((~(C0 | C2 | C3)) >> 8);
addbyte((~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)) >> 8);
addbyte(0x66); /*COMISD XMM0, XMM1*/
addbyte(0x0f);
addbyte(0x2f);
@@ -4501,7 +4501,7 @@ FP_COMPARE_MEM(void)
addbyte(0x9f); /*LAHF*/
addbyte(0x80); /*AND AH, (C0|C2|C3)*/
addbyte(0xe4);
addbyte((C0 | C2 | C3) >> 8);
addbyte((FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3) >> 8);
addbyte(0x08); /*OR CL, AH*/
addbyte(0xe1);
addbyte(0x88); /*MOV [npxs+1], CL*/

View File

@@ -2911,7 +2911,7 @@ FP_COMPARE_S(void)
addbyte(0xe2);
addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/
addbyte(0xe3);
addbyte((~(C0 | C2 | C3)) >> 8);
addbyte((~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)) >> 8);
addbyte(0xd8); /*FCOMP [ESP]*/
addbyte(0x04 | 0x18);
addbyte(0x24);
@@ -2919,7 +2919,7 @@ FP_COMPARE_S(void)
addbyte(0xe0);
addbyte(0x80); /*AND AH, (C0|C2|C3)*/
addbyte(0xe4);
addbyte((C0 | C2 | C3) >> 8);
addbyte((FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3) >> 8);
addbyte(0x08); /*OR BL, AH*/
addbyte(0xe3);
addbyte(0x88); /*MOV [npxs+1], BL*/
@@ -2943,7 +2943,7 @@ FP_COMPARE_S(void)
addbyte(0xe2);
addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/
addbyte(0xe3);
addbyte((~(C0 | C2 | C3)) >> 8);
addbyte((~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)) >> 8);
addbyte(0xd8); /*FCOMP [ESP]*/
addbyte(0x04 | 0x18);
addbyte(0x24);
@@ -2951,7 +2951,7 @@ FP_COMPARE_S(void)
addbyte(0xe0);
addbyte(0x80); /*AND AH, (C0|C2|C3)*/
addbyte(0xe4);
addbyte((C0 | C2 | C3) >> 8);
addbyte((FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3) >> 8);
addbyte(0x08); /*OR BL, AH*/
addbyte(0xe3);
addbyte(0x88); /*MOV [npxs+1], BL*/
@@ -2980,7 +2980,7 @@ FP_COMPARE_D(void)
addbyte(0xe2);
addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/
addbyte(0xe3);
addbyte((~(C0 | C2 | C3)) >> 8);
addbyte((~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)) >> 8);
addbyte(0xdc); /*FCOMP [ESP]*/
addbyte(0x04 | 0x18);
addbyte(0x24);
@@ -2988,7 +2988,7 @@ FP_COMPARE_D(void)
addbyte(0xe0);
addbyte(0x80); /*AND AH, (C0|C2|C3)*/
addbyte(0xe4);
addbyte((C0 | C2 | C3) >> 8);
addbyte((FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3) >> 8);
addbyte(0x08); /*OR BL, AH*/
addbyte(0xe3);
addbyte(0x88); /*MOV [npxs+1], BL*/
@@ -3016,7 +3016,7 @@ FP_COMPARE_D(void)
addbyte(0xe2);
addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/
addbyte(0xe3);
addbyte((~(C0 | C2 | C3)) >> 8);
addbyte((~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)) >> 8);
addbyte(0xdc); /*FCOMP [ESP]*/
addbyte(0x04 | 0x18);
addbyte(0x24);
@@ -3024,7 +3024,7 @@ FP_COMPARE_D(void)
addbyte(0xe0);
addbyte(0x80); /*AND AH, (C0|C2|C3)*/
addbyte(0xe4);
addbyte((C0 | C2 | C3) >> 8);
addbyte((FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3) >> 8);
addbyte(0x08); /*OR BL, AH*/
addbyte(0xe3);
addbyte(0x88); /*MOV [npxs+1], BL*/
@@ -3050,7 +3050,7 @@ FP_COMPARE_IW(void)
addbyte(0xe2);
addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/
addbyte(0xe3);
addbyte((~(C0 | C2 | C3)) >> 8);
addbyte((~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)) >> 8);
addbyte(0xde); /*FCOMP [ESP]*/
addbyte(0x04 | 0x18);
addbyte(0x24);
@@ -3058,7 +3058,7 @@ FP_COMPARE_IW(void)
addbyte(0xe0);
addbyte(0x80); /*AND AH, (C0|C2|C3)*/
addbyte(0xe4);
addbyte((C0 | C2 | C3) >> 8);
addbyte((FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3) >> 8);
addbyte(0x08); /*OR BL, AH*/
addbyte(0xe3);
addbyte(0x88); /*MOV [npxs+1], BL*/
@@ -3082,7 +3082,7 @@ FP_COMPARE_IW(void)
addbyte(0xe2);
addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/
addbyte(0xe3);
addbyte((~(C0 | C2 | C3)) >> 8);
addbyte((~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)) >> 8);
addbyte(0xde); /*FCOMP [ESP]*/
addbyte(0x04 | 0x18);
addbyte(0x24);
@@ -3090,7 +3090,7 @@ FP_COMPARE_IW(void)
addbyte(0xe0);
addbyte(0x80); /*AND AH, (C0|C2|C3)*/
addbyte(0xe4);
addbyte((C0 | C2 | C3) >> 8);
addbyte((FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3) >> 8);
addbyte(0x08); /*OR BL, AH*/
addbyte(0xe3);
addbyte(0x88); /*MOV [npxs+1], BL*/
@@ -3115,7 +3115,7 @@ FP_COMPARE_IL(void)
addbyte(0xe2);
addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/
addbyte(0xe3);
addbyte((~(C0 | C2 | C3)) >> 8);
addbyte((~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)) >> 8);
addbyte(0xda); /*FCOMP [ESP]*/
addbyte(0x04 | 0x18);
addbyte(0x24);
@@ -3123,7 +3123,7 @@ FP_COMPARE_IL(void)
addbyte(0xe0);
addbyte(0x80); /*AND AH, (C0|C2|C3)*/
addbyte(0xe4);
addbyte((C0 | C2 | C3) >> 8);
addbyte((FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3) >> 8);
addbyte(0x08); /*OR BL, AH*/
addbyte(0xe3);
addbyte(0x88); /*MOV [npxs+1], BL*/
@@ -3147,7 +3147,7 @@ FP_COMPARE_IL(void)
addbyte(0xe2);
addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/
addbyte(0xe3);
addbyte((~(C0 | C2 | C3)) >> 8);
addbyte((~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)) >> 8);
addbyte(0xda); /*FCOMP [ESP]*/
addbyte(0x04 | 0x18);
addbyte(0x24);
@@ -3155,7 +3155,7 @@ FP_COMPARE_IL(void)
addbyte(0xe0);
addbyte(0x80); /*AND AH, (C0|C2|C3)*/
addbyte(0xe4);
addbyte((C0 | C2 | C3) >> 8);
addbyte((FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3) >> 8);
addbyte(0x08); /*OR BL, AH*/
addbyte(0xe3);
addbyte(0x88); /*MOV [npxs+1], BL*/
@@ -3250,7 +3250,7 @@ FP_COMPARE_REG(int dst, int src)
addbyte((uint8_t) cpu_state_offset(ST[(cpu_state.TOP + dst) & 7]));
addbyte(0x80); /*AND CL, ~(C0|C2|C3)*/
addbyte(0xe1);
addbyte((~(C0 | C2 | C3)) >> 8);
addbyte((~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)) >> 8);
addbyte(0xdc); /*FCOMP ST[src][EBP]*/
addbyte(0x5d);
addbyte((uint8_t) cpu_state_offset(ST[(cpu_state.TOP + src) & 7]));
@@ -3258,7 +3258,7 @@ FP_COMPARE_REG(int dst, int src)
addbyte(0xe0);
addbyte(0x80); /*AND AH, (C0|C2|C3)*/
addbyte(0xe4);
addbyte((C0 | C2 | C3) >> 8);
addbyte((FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3) >> 8);
addbyte(0x08); /*OR CL, AH*/
addbyte(0xe1);
addbyte(0x88); /*MOV [npxs+1], CL*/
@@ -3286,7 +3286,7 @@ FP_COMPARE_REG(int dst, int src)
addbyte(0xe2);
addbyte(0x80); /*AND CL, ~(C0|C2|C3)*/
addbyte(0xe1);
addbyte((~(C0 | C2 | C3)) >> 8);
addbyte((~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)) >> 8);
if (src) {
addbyte(0xdd); /*FLD ST[EBX*8]*/
@@ -3312,7 +3312,7 @@ FP_COMPARE_REG(int dst, int src)
addbyte(0xe0);
addbyte(0x80); /*AND AH, (C0|C2|C3)*/
addbyte(0xe4);
addbyte((C0 | C2 | C3) >> 8);
addbyte((FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3) >> 8);
addbyte(0x08); /*OR CL, AH*/
addbyte(0xe1);
addbyte(0x88); /*MOV [npxs+1], CL*/

View File

@@ -13,6 +13,7 @@
# include "x86_ops.h"
# include "x86seg_common.h"
# include "x86seg.h"
# include "x87_sf.h"
# include "x87.h"
# include <86box/mem.h>
# include <86box/plat_unused.h>

View File

@@ -51,6 +51,7 @@
# include "x86_ops.h"
# include "x86seg_common.h"
# include "x86seg.h"
# include "x87_sf.h"
# include "x87.h"
/*ex*/
# include <86box/nmi.h>

View File

@@ -15,6 +15,7 @@
# include "x86.h"
# include "x86seg_common.h"
# include "x86seg.h"
# include "x87_sf.h"
# include "x87.h"
# if defined(__linux__) || defined(__APPLE__)

View File

@@ -15,6 +15,7 @@
# include "x86.h"
# include "x86seg_common.h"
# include "x86seg.h"
# include "x87_sf.h"
# include "x87.h"
# if defined(__linux__) || defined(__APPLE__)

View File

@@ -9,6 +9,7 @@
# include "x86.h"
# include "x86seg_common.h"
# include "x86seg.h"
# include "x87_sf.h"
# include "x87.h"
# include "386_common.h"
# include "codegen.h"
@@ -648,10 +649,10 @@ codegen_FTST(codeblock_t *block, uop_t *uop)
host_arm64_FSUB_D(block, REG_V_TEMP, REG_V_TEMP, REG_V_TEMP);
host_arm64_MOVZ_IMM(block, dest_reg, 0);
host_arm64_FCMP_D(block, src_reg_a, REG_V_TEMP);
host_arm64_ORR_IMM(block, REG_TEMP, dest_reg, C3);
host_arm64_ORR_IMM(block, REG_TEMP2, dest_reg, C0);
host_arm64_ORR_IMM(block, REG_TEMP, dest_reg, FPU_SW_C3);
host_arm64_ORR_IMM(block, REG_TEMP2, dest_reg, FPU_SW_C0);
host_arm64_CSEL_EQ(block, dest_reg, REG_TEMP, dest_reg);
host_arm64_ORR_IMM(block, REG_TEMP, dest_reg, C0 | C2 | C3);
host_arm64_ORR_IMM(block, REG_TEMP, dest_reg, FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3);
host_arm64_CSEL_CC(block, dest_reg, REG_TEMP2, dest_reg);
host_arm64_CSEL_VS(block, dest_reg, REG_TEMP, dest_reg);
} else
@@ -690,10 +691,10 @@ codegen_FCOM(codeblock_t *block, uop_t *uop)
if (REG_IS_W(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) {
host_arm64_MOVZ_IMM(block, dest_reg, 0);
host_arm64_FCMP_D(block, src_reg_a, src_reg_b);
host_arm64_ORR_IMM(block, REG_TEMP, dest_reg, C3);
host_arm64_ORR_IMM(block, REG_TEMP2, dest_reg, C0);
host_arm64_ORR_IMM(block, REG_TEMP, dest_reg, FPU_SW_C3);
host_arm64_ORR_IMM(block, REG_TEMP2, dest_reg, FPU_SW_C0);
host_arm64_CSEL_EQ(block, dest_reg, REG_TEMP, dest_reg);
host_arm64_ORR_IMM(block, REG_TEMP, dest_reg, C0 | C2 | C3);
host_arm64_ORR_IMM(block, REG_TEMP, dest_reg, FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3);
host_arm64_CSEL_CC(block, dest_reg, REG_TEMP2, dest_reg);
host_arm64_CSEL_VS(block, dest_reg, REG_TEMP, dest_reg);
} else

View File

@@ -10,6 +10,7 @@
# include "x86.h"
# include "x86seg_common.h"
# include "x86seg.h"
# include "x87_sf.h"
# include "x87.h"
# include "386_common.h"
# include "codegen.h"
@@ -718,9 +719,9 @@ codegen_FTST(codeblock_t *block, uop_t *uop)
host_arm_VCMP_D(block, src_reg_a, REG_D_TEMP);
host_arm_MOV_IMM(block, dest_reg, 0);
host_arm_VMRS_APSR(block);
host_arm_ORREQ_IMM(block, dest_reg, dest_reg, C3);
host_arm_ORRCC_IMM(block, dest_reg, dest_reg, C0);
host_arm_ORRVS_IMM(block, dest_reg, dest_reg, C0 | C2 | C3);
host_arm_ORREQ_IMM(block, dest_reg, dest_reg, FPU_SW_C3);
host_arm_ORRCC_IMM(block, dest_reg, dest_reg, FPU_SW_C0);
host_arm_ORRVS_IMM(block, dest_reg, dest_reg, FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3);
} else
fatal("codegen_FTST %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real);
@@ -758,9 +759,9 @@ codegen_FCOM(codeblock_t *block, uop_t *uop)
host_arm_VCMP_D(block, src_reg_a, src_reg_b);
host_arm_MOV_IMM(block, dest_reg, 0);
host_arm_VMRS_APSR(block);
host_arm_ORREQ_IMM(block, dest_reg, dest_reg, C3);
host_arm_ORRCC_IMM(block, dest_reg, dest_reg, C0);
host_arm_ORRVS_IMM(block, dest_reg, dest_reg, C0 | C2 | C3);
host_arm_ORREQ_IMM(block, dest_reg, dest_reg, FPU_SW_C3);
host_arm_ORRCC_IMM(block, dest_reg, dest_reg, FPU_SW_C0);
host_arm_ORRVS_IMM(block, dest_reg, dest_reg, FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3);
} else
fatal("codegen_FCOM %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real);

View File

@@ -9,6 +9,7 @@
# include "x86.h"
# include "x86seg_common.h"
# include "x86seg.h"
# include "x87_sf.h"
# include "x87.h"
# include "386_common.h"
# include "codegen.h"
@@ -672,7 +673,7 @@ codegen_FTST(codeblock_t *block, uop_t *uop)
host_x86_XOR32_REG_REG(block, REG_EAX, REG_EAX);
host_x86_COMISD_XREG_XREG(block, src_reg_a, REG_XMM_TEMP);
host_x86_LAHF(block);
host_x86_AND16_REG_IMM(block, REG_EAX, C0 | C2 | C3);
host_x86_AND16_REG_IMM(block, REG_EAX, FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3);
if (dest_reg != REG_EAX) {
host_x86_MOV16_REG_REG(block, dest_reg, REG_EAX);
host_x86_MOV32_REG_REG(block, REG_EAX, REG_ECX);
@@ -720,7 +721,7 @@ codegen_FCOM(codeblock_t *block, uop_t *uop)
host_x86_XOR32_REG_REG(block, REG_EAX, REG_EAX);
host_x86_COMISD_XREG_XREG(block, src_reg_a, src_reg_b);
host_x86_LAHF(block);
host_x86_AND16_REG_IMM(block, REG_EAX, C0 | C2 | C3);
host_x86_AND16_REG_IMM(block, REG_EAX, FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3);
if (dest_reg != REG_EAX) {
host_x86_MOV16_REG_REG(block, dest_reg, REG_EAX);
host_x86_MOV32_REG_REG(block, REG_EAX, REG_ECX);

View File

@@ -10,6 +10,7 @@
# include "x86_ops.h"
# include "x86seg_common.h"
# include "x86seg.h"
# include "x87_sf.h"
# include "386_common.h"
# include "codegen.h"
# include "codegen_allocator.h"
@@ -677,7 +678,7 @@ codegen_FTST(codeblock_t *block, uop_t *uop)
host_x86_XOR32_REG_REG(block, REG_EAX, REG_EAX);
host_x86_COMISD_XREG_XREG(block, src_reg_a, REG_XMM_TEMP);
host_x86_LAHF(block);
host_x86_AND16_REG_IMM(block, REG_EAX, C0 | C2 | C3);
host_x86_AND16_REG_IMM(block, REG_EAX, FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3);
if (dest_reg != REG_EAX) {
host_x86_MOV16_REG_REG(block, dest_reg, REG_EAX);
host_x86_MOV32_REG_REG(block, REG_EAX, REG_ECX);
@@ -725,7 +726,7 @@ codegen_FCOM(codeblock_t *block, uop_t *uop)
host_x86_XOR32_REG_REG(block, REG_EAX, REG_EAX);
host_x86_COMISD_XREG_XREG(block, src_reg_a, src_reg_b);
host_x86_LAHF(block);
host_x86_AND16_REG_IMM(block, REG_EAX, C0 | C2 | C3);
host_x86_AND16_REG_IMM(block, REG_EAX, FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3);
if (dest_reg != REG_EAX) {
host_x86_MOV16_REG_REG(block, dest_reg, REG_EAX);
host_x86_MOV32_REG_REG(block, REG_EAX, REG_ECX);

View File

@@ -12,6 +12,7 @@
#include "x86_ops.h"
#include "x86seg_common.h"
#include "x86seg.h"
#include "x87_sf.h"
#include "x87.h"
#include "386_common.h"

View File

@@ -9,6 +9,7 @@
#include "x86seg_common.h"
#include "x86seg.h"
#include "386_common.h"
#include "x87_sf.h"
#include "x87.h"
#include "codegen.h"
#include "codegen_accumulate.h"
@@ -59,7 +60,7 @@ ropFCOM(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint3
uop_FP_ENTER(ir);
uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(src_reg));
uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0 | C2 | C3));
uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3));
uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W);
return op_pc;
@@ -71,7 +72,7 @@ ropFCOMP(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fet
uop_FP_ENTER(ir);
uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(src_reg));
uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0 | C2 | C3));
uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3));
uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W);
fpu_POP(block, ir);
@@ -82,7 +83,7 @@ ropFCOMPP(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fe
{
uop_FP_ENTER(ir);
uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(1));
uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0 | C2 | C3));
uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3));
uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W);
fpu_POP2(block, ir);
@@ -269,7 +270,7 @@ ropFUCOM(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint
uop_FP_ENTER(ir);
uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(src_reg));
uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0 | C2 | C3));
uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3));
uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W);
return op_pc;
@@ -281,7 +282,7 @@ ropFUCOMP(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fe
uop_FP_ENTER(ir);
uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(src_reg));
uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0 | C2 | C3));
uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3));
uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W);
fpu_POP(block, ir);
@@ -292,7 +293,7 @@ ropFUCOMPP(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t f
{
uop_FP_ENTER(ir);
uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(1));
uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0 | C2 | C3));
uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3));
uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W);
fpu_POP2(block, ir);
@@ -328,7 +329,7 @@ ropFUCOMPP(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t f
codegen_check_seg_read(block, ir, target_seg); \
load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \
uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D); \
uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0 | C2 | C3)); \
uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)); \
uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W); \
\
return op_pc + 1; \
@@ -344,7 +345,7 @@ ropFUCOMPP(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t f
codegen_check_seg_read(block, ir, target_seg); \
load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \
uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D); \
uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0 | C2 | C3)); \
uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)); \
uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W); \
fpu_POP(block, ir); \
\
@@ -460,7 +461,7 @@ ropF_arith_mem(d, uop_MEM_LOAD_DOUBLE)
uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \
uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \
uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D); \
uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0 | C2 | C3)); \
uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)); \
uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W); \
\
return op_pc + 1; \
@@ -477,7 +478,7 @@ ropF_arith_mem(d, uop_MEM_LOAD_DOUBLE)
uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \
uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \
uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D); \
uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0 | C2 | C3)); \
uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)); \
uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W); \
fpu_POP(block, ir); \
\
@@ -600,7 +601,7 @@ ropFTST(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint3
{
uop_FP_ENTER(ir);
uop_FTST(ir, IREG_temp0_W, IREG_ST(0));
uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0 | C2 | C3));
uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3));
uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W);
return op_pc;

View File

@@ -9,6 +9,7 @@
#include "x86seg_common.h"
#include "x86seg.h"
#include "386_common.h"
#include "x87_sf.h"
#include "x87.h"
#include "codegen.h"
#include "codegen_accumulate.h"

View File

@@ -9,6 +9,7 @@
#include "x86seg_common.h"
#include "x86seg.h"
#include "386_common.h"
#include "x87_sf.h"
#include "x87.h"
#include "codegen.h"
#include "codegen_accumulate.h"

View File

@@ -9,6 +9,7 @@
#include "x86seg_common.h"
#include "x86seg.h"
#include "386_common.h"
#include "x87_sf.h"
#include "x87.h"
#include "codegen.h"
#include "codegen_accumulate.h"

View File

@@ -77,6 +77,7 @@
#include <86box/plat_dir.h>
#include <86box/ui.h>
#include <86box/snd_opl.h>
#include <86box/version.h>
static int cx;
static int cy;
@@ -139,8 +140,6 @@ load_general(void)
rctrl_is_lalt = ini_section_get_int(cat, "rctrl_is_lalt", 0);
update_icons = ini_section_get_int(cat, "update_icons", 1);
status_icons_fullscreen = !!ini_section_get_int(cat, "status_icons_fullscreen", 0);
window_remember = ini_section_get_int(cat, "window_remember", 0);
if (!window_remember && !(vid_resize & 2))
@@ -211,6 +210,12 @@ load_general(void)
ini_section_delete_var(cat, "window_coordinates");
do_auto_pause = ini_section_get_int(cat, "do_auto_pause", 0);
p = ini_section_get_string(cat, "uuid", NULL);
if (p != NULL)
strncpy(uuid, p, sizeof(uuid) - 1);
else
strncpy(uuid, "", sizeof(uuid) - 1);
}
/* Load monitor section. */
@@ -309,9 +314,10 @@ load_machine(void)
}
}
cpu_override = ini_section_get_int(cat, "cpu_override", 0);
cpu_f = NULL;
p = ini_section_get_string(cat, "cpu_family", NULL);
cpu_override = ini_section_get_int(cat, "cpu_override", 0);
cpu_override_interpreter = ini_section_get_int(cat, "cpu_override_interpreter", 0);
cpu_f = NULL;
p = ini_section_get_string(cat, "cpu_family", NULL);
if (p) {
/* Migrate CPU family changes. */
if ((!strcmp(machines[machine].internal_name, "deskpro386") ||
@@ -427,8 +433,11 @@ load_video(void)
free_p = 1;
}
gfxcard[0] = video_get_video_from_internal_name(p);
if (free_p)
if (free_p) {
free(p);
p = NULL;
free_p = 0;
}
}
if (((gfxcard[0] == VID_INTERNAL) && machine_has_flags(machine, MACHINE_VIDEO_8514A)) ||
@@ -665,9 +674,9 @@ load_network(void)
if (nc->net_type == NET_TYPE_PCAP) {
if ((network_dev_to_id(p) == -1) || (network_ndev == 1)) {
if (network_ndev == 1)
ui_msgbox_header(MBX_ERROR, (wchar_t *) IDS_2095, (wchar_t *) IDS_2130);
ui_msgbox_header(MBX_ERROR, plat_get_string(STRING_PCAP_ERROR_NO_DEVICES), plat_get_string(STRING_PCAP_ERROR_DESC));
else if (network_dev_to_id(p) == -1)
ui_msgbox_header(MBX_ERROR, (wchar_t *) IDS_2096, (wchar_t *) IDS_2130);
ui_msgbox_header(MBX_ERROR, plat_get_string(STRING_PCAP_ERROR_INVALID_DEVICE), plat_get_string(STRING_PCAP_ERROR_DESC));
strcpy(nc->host_dev_name, "none");
} else
strncpy(nc->host_dev_name, p, sizeof(nc->host_dev_name) - 1);
@@ -712,9 +721,9 @@ load_network(void)
if (nc->net_type == NET_TYPE_PCAP) {
if ((network_dev_to_id(p) == -1) || (network_ndev == 1)) {
if (network_ndev == 1)
ui_msgbox_header(MBX_ERROR, (wchar_t *) IDS_2095, (wchar_t *) IDS_2130);
ui_msgbox_header(MBX_ERROR, plat_get_string(STRING_PCAP_ERROR_NO_DEVICES), plat_get_string(STRING_PCAP_ERROR_DESC));
else if (network_dev_to_id(p) == -1)
ui_msgbox_header(MBX_ERROR, (wchar_t *) IDS_2096, (wchar_t *) IDS_2130);
ui_msgbox_header(MBX_ERROR, plat_get_string(STRING_PCAP_ERROR_INVALID_DEVICE), plat_get_string(STRING_PCAP_ERROR_DESC));
strcpy(nc->host_dev_name, "none");
} else
strncpy(nc->host_dev_name, p, sizeof(nc->host_dev_name) - 1);
@@ -739,7 +748,6 @@ load_ports(void)
char *p;
char temp[512];
int c;
int d;
memset(temp, 0, sizeof(temp));
@@ -762,14 +770,6 @@ load_ports(void)
p = ini_section_get_string(cat, temp, "none");
lpt_ports[c].device = lpt_device_get_from_internal_name(p);
}
/* Legacy config compatibility. */
d = ini_section_get_int(cat, "lpt_enabled", 2);
if (d < 2) {
for (c = 0; c < PARALLEL_MAX; c++)
lpt_ports[c].enabled = d;
}
ini_section_delete_var(cat, "lpt_enabled");
}
/* Load "Storage Controllers" section. */
@@ -784,7 +784,7 @@ load_storage_controllers(void)
int min = 0;
int free_p = 0;
for (c = min; c < SCSI_BUS_MAX; c++) {
for (c = min; c < SCSI_CARD_MAX; c++) {
sprintf(temp, "scsicard_%d", c + 1);
p = ini_section_get_string(cat, temp, NULL);
@@ -795,10 +795,31 @@ load_storage_controllers(void)
}
p = ini_section_get_string(cat, "fdc", NULL);
#if 1
if (p != NULL)
fdc_type = fdc_card_get_from_internal_name(p);
else
fdc_type = FDC_INTERNAL;
#else
if (p == NULL) {
if (machine_has_flags(machine, MACHINE_FDC)) {
p = (char *) malloc((strlen("internal") + 1) * sizeof(char));
strcpy(p, "internal");
} else {
p = (char *) malloc((strlen("none") + 1) * sizeof(char));
strcpy(p, "none");
}
free_p = 1;
}
fdc_type = fdc_card_get_from_internal_name(p);
if (free_p) {
free(p);
p = NULL;
free_p = 0;
}
#endif
p = ini_section_get_string(cat, "hdc", NULL);
if (p == NULL) {
@@ -835,6 +856,7 @@ load_storage_controllers(void)
if (free_p) {
free(p);
p = NULL;
free_p = 0;
}
ide_ter_enabled = !!ini_section_get_int(cat, "ide_ter", 0);
@@ -878,6 +900,8 @@ load_storage_controllers(void)
path_normalize(cart_fns[c]);
}
}
lba_enhancer_enabled = !!ini_section_get_int(cat, "lba_enhancer_enabled", 0);
}
/* Load "Hard Disks" section. */
@@ -1176,8 +1200,7 @@ load_floppy_and_cdrom_drives(void)
memset(temp, 0x00, sizeof(temp));
for (c = 0; c < CDROM_NUM; c++) {
sprintf(temp, "cdrom_%02i_host_drive", c + 1);
cdrom[c].host_drive = ini_section_get_int(cat, temp, 0);
cdrom[c].prev_host_drive = cdrom[c].host_drive;
ini_section_delete_var(cat, temp);
sprintf(temp, "cdrom_%02i_parameters", c + 1);
p = ini_section_get_string(cat, temp, NULL);
@@ -1264,12 +1287,6 @@ load_floppy_and_cdrom_drives(void)
path_normalize(cdrom[c].image_path);
}
if (cdrom[c].host_drive && (cdrom[c].host_drive != 200))
cdrom[c].host_drive = 0;
if ((cdrom[c].host_drive == 0x200) && (strlen(cdrom[c].image_path) == 0))
cdrom[c].host_drive = 0;
for (int i = 0; i < MAX_PREV_IMAGES; i++) {
cdrom[c].image_history[i] = (char *) calloc((MAX_IMAGE_PATH_LEN + 1) << 1, sizeof(char));
sprintf(temp, "cdrom_%02i_image_history_%02i", c + 1, i + 1);
@@ -1290,9 +1307,6 @@ load_floppy_and_cdrom_drives(void)
/* If the CD-ROM is disabled, delete all its variables. */
if (cdrom[c].bus_type == CDROM_BUS_DISABLED) {
sprintf(temp, "cdrom_%02i_host_drive", c + 1);
ini_section_delete_var(cat, temp);
sprintf(temp, "cdrom_%02i_parameters", c + 1);
ini_section_delete_var(cat, temp);
@@ -1423,9 +1437,6 @@ load_other_removable_devices(void)
/* If the ZIP drive is disabled, delete all its variables. */
if (zip_drives[c].bus_type == ZIP_BUS_DISABLED) {
sprintf(temp, "zip_%02i_host_drive", c + 1);
ini_section_delete_var(cat, temp);
sprintf(temp, "zip_%02i_parameters", c + 1);
ini_section_delete_var(cat, temp);
@@ -1539,9 +1550,6 @@ load_other_removable_devices(void)
/* If the MO drive is disabled, delete all its variables. */
if (mo_drives[c].bus_type == MO_BUS_DISABLED) {
sprintf(temp, "mo_%02i_host_drive", c + 1);
ini_section_delete_var(cat, temp);
sprintf(temp, "mo_%02i_parameters", c + 1);
ini_section_delete_var(cat, temp);
@@ -1570,9 +1578,10 @@ load_other_peripherals(void)
char *p;
char temp[512];
bugger_enabled = !!ini_section_get_int(cat, "bugger_enabled", 0);
postcard_enabled = !!ini_section_get_int(cat, "postcard_enabled", 0);
unittester_enabled = !!ini_section_get_int(cat, "unittester_enabled", 0);
bugger_enabled = !!ini_section_get_int(cat, "bugger_enabled", 0);
postcard_enabled = !!ini_section_get_int(cat, "postcard_enabled", 0);
unittester_enabled = !!ini_section_get_int(cat, "unittester_enabled", 0);
novell_keycard_enabled = !!ini_section_get_int(cat, "novell_keycard_enabled", 0);
for (uint8_t c = 0; c < ISAMEM_MAX; c++) {
sprintf(temp, "isamem%d_type", c);
@@ -1618,6 +1627,8 @@ config_load(void)
dpi_scale = 1;
do_auto_pause = 0;
cpu_override_interpreter = 0;
fpu_type = fpu_get_type(cpu_f, cpu, "none");
gfxcard[0] = video_get_video_from_internal_name("cga");
vid_api = plat_vidapi("default");
@@ -1859,11 +1870,6 @@ save_general(void)
else
ini_section_delete_var(cat, "open_dir_usr_path");
if (status_icons_fullscreen)
ini_section_set_int(cat, "status_icons_fullscreen", status_icons_fullscreen);
else
ini_section_delete_var(cat, "status_icons_fullscreen");
if (video_framerate != -1)
ini_section_set_int(cat, "video_gl_framerate", video_framerate);
else
@@ -1882,6 +1888,20 @@ save_general(void)
else
ini_section_delete_var(cat, "do_auto_pause");
char cpu_buf[128] = { 0 };
plat_get_cpu_string(cpu_buf, 128);
ini_section_set_string(cat, "host_cpu", cpu_buf);
if (EMU_BUILD_NUM != 0)
ini_section_set_int(cat, "emu_build_num", EMU_BUILD_NUM);
else
ini_section_delete_var(cat, "emu_build_num");
if (strnlen(uuid, sizeof(uuid) - 1) > 0)
ini_section_set_string(cat, "uuid", uuid);
else
ini_section_delete_var(cat, "uuid");
ini_delete_section_if_empty(config, cat);
}
@@ -1931,6 +1951,10 @@ save_machine(void)
ini_section_set_int(cat, "cpu_override", cpu_override);
else
ini_section_delete_var(cat, "cpu_override");
if (cpu_override_interpreter)
ini_section_set_int(cat, "cpu_override_interpreter", cpu_override_interpreter);
else
ini_section_delete_var(cat, "cpu_override_interpreter");
/* Downgrade compatibility with the previous CPU model system. */
ini_section_delete_var(cat, "cpu_manufacturer");
@@ -2264,7 +2288,7 @@ save_storage_controllers(void)
ini_section_delete_var(cat, "scsicard");
for (c = 0; c < SCSI_BUS_MAX; c++) {
for (c = 0; c < SCSI_CARD_MAX; c++) {
sprintf(temp, "scsicard_%d", c + 1);
if (scsi_card_current[c] == 0)
@@ -2348,6 +2372,11 @@ save_storage_controllers(void)
else
ini_section_set_string(cat, temp, cart_fns[c]);
}
if (lba_enhancer_enabled == 0)
ini_section_delete_var(cat, "lba_enhancer_enabled");
else
ini_section_set_int(cat, "lba_enhancer_enabled", 1);
}
/* Save "Other Peripherals" section. */
@@ -2372,6 +2401,11 @@ save_other_peripherals(void)
else
ini_section_set_int(cat, "unittester_enabled", unittester_enabled);
if (novell_keycard_enabled == 0)
ini_section_delete_var(cat, "novell_keycard_enabled");
else
ini_section_set_int(cat, "novell_keycard_enabled", novell_keycard_enabled);
for (uint8_t c = 0; c < ISAMEM_MAX; c++) {
sprintf(temp, "isamem%d_type", c);
if (isamem_type[c] == 0)
@@ -2550,10 +2584,7 @@ save_floppy_and_cdrom_drives(void)
for (c = 0; c < CDROM_NUM; c++) {
sprintf(temp, "cdrom_%02i_host_drive", c + 1);
if ((cdrom[c].bus_type == 0) || (cdrom[c].host_drive != 200))
ini_section_delete_var(cat, temp);
else
ini_section_set_int(cat, temp, cdrom[c].host_drive);
ini_section_delete_var(cat, temp);
sprintf(temp, "cdrom_%02i_speed", c + 1);
if ((cdrom[c].bus_type == 0) || (cdrom[c].speed == 8))

View File

@@ -15,6 +15,7 @@
#include "x86.h"
#include "x86_ops.h"
#include "x86seg_common.h"
#include "x87_sf.h"
#include "x87.h"
#include <86box/io.h>
#include <86box/nmi.h>
@@ -25,6 +26,7 @@
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/machine.h>
#include <86box/plat_fallthrough.h>
#include <86box/gdbstub.h>
#ifndef OPS_286_386
# define OPS_286_386
@@ -210,11 +212,11 @@ fetch_ea_16_long(uint32_t rmdat)
#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c)
#define CHECK_READ_CS(size) \
if ((cpu_state.pc < cpu_state.seg_cs.limit_low) || \
((cpu_state.pc + size - 1) > cpu_state.seg_cs.limit_high)) \
x86gpf("Limit check (READ)", 0); \
if (msw & 1 && !(cpu_state.eflags & VM_FLAG) && !(cpu_state.seg_cs.access & 0x80)) \
x86np("Read from seg not present", cpu_state.seg_cs.seg & 0xfffc); \
else if ((cpu_state.pc < cpu_state.seg_cs.limit_low) || \
((cpu_state.pc + size - 1) > cpu_state.seg_cs.limit_high)) \
x86gpf("Limit check (READ CS)", 0);
#include "386_ops.h"
@@ -259,14 +261,19 @@ exec386_2386(int32_t cycs)
fetchdat = fastreadl_fetch(cs + cpu_state.pc);
ol = opcode_length[fetchdat & 0xff];
CHECK_READ_CS(MIN(ol, 4));
if ((ol == 3) && opcode_has_modrm[fetchdat & 0xff] && (((fetchdat >> 14) & 0x03) == 0x03))
ol = 2;
if (cpu_16bitbus) {
CHECK_READ_CS(MIN(ol, 2));
} else {
CHECK_READ_CS(MIN(ol, 4));
}
ins_fetch_fault = cpu_386_check_instruction_fault();
if (!cpu_state.abrt && ins_fetch_fault) {
x86gen();
/* Breakpoint fault has priority over other faults. */
if (ins_fetch_fault) {
ins_fetch_fault = 0;
/* No instructions executed at this point. */
goto block_ended;
cpu_state.abrt = 1;
}
if (!cpu_state.abrt) {
@@ -279,7 +286,11 @@ exec386_2386(int32_t cycs)
trap |= !!(cpu_state.flags & T_FLAG);
cpu_state.pc++;
x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat);
cpu_state.eflags &= ~(RF_FLAG);
if (opcode == 0xf0)
in_lock = 1;
x86_2386_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat);
in_lock = 0;
if (x86_was_reset)
break;
}
@@ -296,7 +307,6 @@ exec386_2386(int32_t cycs)
if (cpu_end_block_after_ins)
cpu_end_block_after_ins--;
block_ended:
if (cpu_state.abrt) {
flags_rebuild();
tempi = cpu_state.abrt & ABRT_MASK;
@@ -319,8 +329,6 @@ block_ended:
#endif
}
}
if (!x86_was_reset && ins_fetch_fault)
x86gen(); /* This is supposed to be the first one serviced by the processor according to the manual. */
} else if (trap) {
flags_rebuild();
if (trap & 2) dr[6] |= 0x8000;

View File

@@ -14,6 +14,7 @@
#include <86box/timer.h>
#include "x86.h"
#include "x86seg_common.h"
#include "x87_sf.h"
#include "x87.h"
#include <86box/nmi.h>
#include <86box/mem.h>
@@ -50,6 +51,8 @@ uint32_t dr[8];
uint32_t use32;
int stack32;
int cpu_init = 0;
uint32_t *eal_r;
uint32_t *eal_w;
@@ -103,6 +106,28 @@ uint32_t backupregs[16];
x86seg _oldds;
int opcode_has_modrm[256] = {
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*00*/
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*10*/
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*20*/
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*30*/
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*40*/
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/
0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, /*60*/
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*70*/
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*80*/
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*90*/
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*a0*/
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*b0*/
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*d0*/
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*e0*/
0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, /*f0*/
};
int opcode_length[256] = { 3, 3, 3, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 1, 3, /* 0x0x */
3, 3, 3, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, /* 0x1x */
3, 3, 3, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, /* 0x2x */
@@ -120,6 +145,53 @@ int opcode_length[256] = { 3, 3, 3, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 1, 3, /*
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 1, 1, 1, 1, /* 0xex */
1, 1, 1, 1, 1, 1, 3, 3, 1, 1, 1, 1, 1, 1, 3, 3 }; /* 0xfx */
/* 0 = no, 1 = always, 2 = depends on second opcode, 3 = depends on mod/rm */
int lock_legal[256] = { 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 2, /* 0x0x */
1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, /* 0x1x */
1, 1, 1, 1, 1, 1, 4, 0, 1, 1, 1, 1, 1, 1, 4, 0, /* 0x2x */
1, 1, 1, 1, 1, 1, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, /* 0x3x */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x4x */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x5x */
0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x6x */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x7x */
3, 3, 3, 3, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x8x */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x9x */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xax */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xbx */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xcx */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xdx */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xex */
0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3 }; /* 0xfx */
int lock_legal_0f[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0x */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x1x */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x2x */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x3x */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x4x */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x5x */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x6x */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x7x */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x8x */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x9x */
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, /* 0xax */
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, /* 0xbx */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xcx */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xdx */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xex */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* 0xfx */
/* (modrm >> 3) & 0x07 */
int lock_legal_ba[8] = { 0, 0, 0, 0, 1, 1, 1, 1 };
/* Also applies to 81, 82, and 83 */
int lock_legal_80[8] = { 1, 1, 1, 1, 1, 1, 1, 0 };
/* Also applies to F7 */
int lock_legal_f6[8] = { 0, 0, 1, 1, 0, 0, 0, 0 };
/* Also applies to FF */
int lock_legal_fe[8] = { 1, 1, 0, 0, 0, 0, 0, 0 };
uint32_t addr64;
uint32_t addr64_2;
uint32_t addr64a[8];
@@ -128,9 +200,9 @@ uint32_t addr64a_2[8];
static pc_timer_t *cpu_fast_off_timer = NULL;
static double cpu_fast_off_period = 0.0;
#define AMD_SYSCALL_EIP (msr.star & 0xFFFFFFFF)
#define AMD_SYSCALL_SB ((msr.star >> 32) & 0xFFFF)
#define AMD_SYSRET_SB ((msr.star >> 48) & 0xFFFF)
#define AMD_SYSCALL_EIP (msr.amd_star & 0xFFFFFFFF)
#define AMD_SYSCALL_SB ((msr.amd_star >> 32) & 0xFFFF)
#define AMD_SYSRET_SB ((msr.amd_star >> 48) & 0xFFFF)
/* These #define's and enum have been borrowed from Bochs. */
/* SMM feature masks */
@@ -376,6 +448,52 @@ x386_common_log(const char *fmt, ...)
# define x386_common_log(fmt, ...)
#endif
int
is_lock_legal(uint32_t fetchdat)
{
int legal = 1;
if (is386) {
fetch_dat_t fetch_dat;
fetch_dat.fd = fetchdat;
legal = lock_legal[fetch_dat.b[0]];
if (legal == 1)
legal = 1; // ((fetch_dat.b[1] >> 6) != 0x03); /* reg is illegal */
else if (legal == 2) {
legal = lock_legal_0f[fetch_dat.b[1]];
if (legal == 1)
legal = ((fetch_dat.b[2] >> 6) != 0x03); /* reg,reg is illegal */
else if (legal == 3) {
legal = lock_legal_ba[(fetch_dat.b[2] >> 3) & 0x07];
if (legal == 1)
legal = ((fetch_dat.b[2] >> 6) != 0x03); /* reg,imm is illegal */
}
} else if (legal == 3) switch(fetch_dat.b[0]) {
case 0x80 ... 0x83:
legal = lock_legal_80[(fetch_dat.b[1] >> 3) & 0x07];
if (legal == 1)
legal = ((fetch_dat.b[1] >> 6) != 0x03); /* reg is illegal */
break;
case 0xf6 ... 0xf7:
legal = lock_legal_f6[(fetch_dat.b[1] >> 3) & 0x07];
if (legal == 1)
legal = ((fetch_dat.b[1] >> 6) != 0x03); /* reg is illegal */
break;
case 0xfe ... 0xff:
legal = lock_legal_fe[(fetch_dat.b[1] >> 3) & 0x07];
if (legal == 1)
legal = ((fetch_dat.b[1] >> 6) != 0x03); /* reg is illegal */
break;
default:
legal = 0;
break;
}
}
return legal;
}
/*Prefetch emulation is a fairly simplistic model:
- All instruction bytes must be fetched before it starts.
- Cycles used for non-instruction memory accesses are counted and subtracted
@@ -1412,7 +1530,7 @@ x86_int(int num)
cpu_state.pc = cpu_state.oldpc;
if (msw & 1)
is486 ? pmodeint(num, 0) : pmodeint_2386(num, 0);
cpu_use_exec ? pmodeint(num, 0) : pmodeint_2386(num, 0);
else {
addr = (num << 2) + idt.base;
@@ -1445,7 +1563,7 @@ x86_int(int num)
oxpc = cpu_state.pc;
#endif
cpu_state.pc = readmemw(0, addr);
is486 ? loadcs(readmemw(0, addr + 2)) : loadcs_2386(readmemw(0, addr + 2));
cpu_use_exec ? loadcs(readmemw(0, addr + 2)) : loadcs_2386(readmemw(0, addr + 2));
}
}
@@ -1462,7 +1580,7 @@ x86_int_sw(int num)
cycles -= timing_int;
if (msw & 1)
is486 ? pmodeint(num, 1) : pmodeint_2386(num, 1);
cpu_use_exec ? pmodeint(num, 1) : pmodeint_2386(num, 1);
else {
addr = (num << 2) + idt.base;
@@ -1487,12 +1605,15 @@ x86_int_sw(int num)
oxpc = cpu_state.pc;
#endif
cpu_state.pc = readmemw(0, addr);
is486 ? loadcs(readmemw(0, addr + 2)) : loadcs_2386(readmemw(0, addr + 2));
cpu_use_exec ? loadcs(readmemw(0, addr + 2)) : loadcs_2386(readmemw(0, addr + 2));
cycles -= timing_int_rm;
}
}
trap &= ~1;
if (cpu_use_exec)
trap = 0;
else
trap &= ~1;
CPU_BLOCK_END();
}
@@ -1529,13 +1650,16 @@ x86_int_sw_rm(int num)
cpu_state.eflags &= ~VIF_FLAG;
cpu_state.flags &= ~T_FLAG;
cpu_state.pc = new_pc;
is486 ? loadcs(new_cs) : loadcs_2386(new_cs);
cpu_use_exec ? loadcs(new_cs) : loadcs_2386(new_cs);
#ifndef USE_NEW_DYNAREC
oxpc = cpu_state.pc;
#endif
cycles -= timing_int_rm;
trap &= ~1;
if (cpu_use_exec)
trap = 0;
else
trap &= ~1;
CPU_BLOCK_END();
return 0;
@@ -1552,6 +1676,13 @@ checkio(uint32_t port, int mask)
{
uint32_t t;
if (!(tr.access & 0x08)) {
if ((CPL) > (IOPL))
return 1;
return 0;
}
cpl_override = 1;
t = readmemw(tr.base, 0x66);

View File

@@ -49,6 +49,82 @@
# define do_mmut_wb(s, a, b) do_mmutranslate_2386((s) + (a), b, 1, 1)
# define do_mmut_ww(s, a, b) do_mmutranslate_2386((s) + (a), b, 2, 1)
# define do_mmut_wl(s, a, b) do_mmutranslate_2386((s) + (a), b, 4, 1)
#elif defined(USE_DEBUG_REGS_486)
# define readmemb_n(s, a, b) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (dr[7] & 0xFF)) ? readmembl_no_mmut((s) + (a), b) : *(uint8_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a))))
# define readmemw_n(s, a, b) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (dr[7] & 0xFF) || (((s) + (a)) & 1)) ? readmemwl_no_mmut((s) + (a), b) : *(uint16_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uint32_t) ((s) + (a))))
# define readmeml_n(s, a, b) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (dr[7] & 0xFF) || (((s) + (a)) & 3)) ? readmemll_no_mmut((s) + (a), b) : *(uint32_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uint32_t) ((s) + (a))))
# define readmemb(s, a) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (dr[7] & 0xFF)) ? readmembl((s) + (a)) : *(uint8_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a))))
# define readmemw(s, a) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (dr[7] & 0xFF) || (((s) + (a)) & 1)) ? readmemwl((s) + (a)) : *(uint16_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uint32_t) ((s) + (a))))
# define readmeml(s, a) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (dr[7] & 0xFF) || (((s) + (a)) & 3)) ? readmemll((s) + (a)) : *(uint32_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uint32_t) ((s) + (a))))
# define readmemq(s, a) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (dr[7] & 0xFF) || (((s) + (a)) & 7)) ? readmemql((s) + (a)) : *(uint64_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a))))
# define writememb_n(s, a, b, v) \
if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (dr[7] & 0xFF)) \
writemembl_no_mmut((s) + (a), b, v); \
else \
*(uint8_t *) (writelookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a))) = v
# define writememw_n(s, a, b, v) \
if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 1) || (dr[7] & 0xFF)) \
writememwl_no_mmut((s) + (a), b, v); \
else \
*(uint16_t *) (writelookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a))) = v
# define writememl_n(s, a, b, v) \
if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 3) || (dr[7] & 0xFF)) \
writememll_no_mmut((s) + (a), b, v); \
else \
*(uint32_t *) (writelookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a))) = v
# define writememb(s, a, v) \
if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (dr[7] & 0xFF)) \
writemembl((s) + (a), v); \
else \
*(uint8_t *) (writelookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a))) = v
# define writememw(s, a, v) \
if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 1) || (dr[7] & 0xFF)) \
writememwl((s) + (a), v); \
else \
*(uint16_t *) (writelookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a))) = v
# define writememl(s, a, v) \
if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 3) || (dr[7] & 0xFF)) \
writememll((s) + (a), v); \
else \
*(uint32_t *) (writelookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a))) = v
# define writememq(s, a, v) \
if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 7) || (dr[7] & 0xFF)) \
writememql((s) + (a), v); \
else \
*(uint64_t *) (writelookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a))) = v
# define do_mmut_rb(s, a, b) \
if (readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (dr[7] & 0xFF)) \
do_mmutranslate((s) + (a), b, 1, 0)
# define do_mmut_rw(s, a, b) \
if (readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 1) || (dr[7] & 0xFF)) \
do_mmutranslate((s) + (a), b, 2, 0)
# define do_mmut_rl(s, a, b) \
if (readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 3) || (dr[7] & 0xFF)) \
do_mmutranslate((s) + (a), b, 4, 0)
# define do_mmut_rb2(s, a, b) \
old_rl2 = readlookup2[(uint32_t) ((s) + (a)) >> 12]; \
if (old_rl2 == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (dr[7] & 0xFF)) \
do_mmutranslate((s) + (a), b, 1, 0)
# define do_mmut_rw2(s, a, b) \
old_rl2 = readlookup2[(uint32_t) ((s) + (a)) >> 12]; \
if (old_rl2 == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 1) || (dr[7] & 0xFF)) \
do_mmutranslate((s) + (a), b, 2, 0)
# define do_mmut_rl2(s, a, b) \
old_rl2 = readlookup2[(uint32_t) ((s) + (a)) >> 12]; \
if (old_rl2 == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 3) || (dr[7] & 0xFF)) \
do_mmutranslate((s) + (a), b, 4, 0)
# define do_mmut_wb(s, a, b) \
if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (dr[7] & 0xFF)) \
do_mmutranslate((s) + (a), b, 1, 1)
# define do_mmut_ww(s, a, b) \
if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 1) || (dr[7] & 0xFF)) \
do_mmutranslate((s) + (a), b, 2, 1)
# define do_mmut_wl(s, a, b) \
if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 3) || (dr[7] & 0xFF)) \
do_mmutranslate((s) + (a), b, 4, 1)
#else
# define readmemb_n(s, a, b) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF) ? readmembl_no_mmut((s) + (a), b) : *(uint8_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a))))
# define readmemw_n(s, a, b) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 1)) ? readmemwl_no_mmut((s) + (a), b) : *(uint16_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uint32_t) ((s) + (a))))
@@ -225,19 +301,37 @@ int checkio(uint32_t port, int mask);
static __inline uint8_t
fastreadb(uint32_t a)
{
return readmembl_2386(a);
uint8_t ret;
read_type = 1;
ret = readmembl_2386(a);
read_type = 4;
if (cpu_state.abrt)
return 0;
return ret;
}
static __inline uint16_t
fastreadw(uint32_t a)
{
return readmemwl_2386(a);
uint16_t ret;
read_type = 1;
ret = readmemwl_2386(a);
read_type = 4;
if (cpu_state.abrt)
return 0;
return ret;
}
static __inline uint32_t
fastreadl(uint32_t a)
{
return readmemll_2386(a);
uint32_t ret;
read_type = 1;
ret = readmemll_2386(a);
read_type = 4;
if (cpu_state.abrt)
return 0;
return ret;
}
#else
static __inline uint8_t
@@ -245,6 +339,11 @@ fastreadb(uint32_t a)
{
uint8_t *t;
# ifdef USE_DEBUG_REGS_486
read_type = 1;
mem_debug_check_addr(a, read_type);
read_type = 4;
# endif
if ((a >> 12) == pccache)
# if (defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)
return *((uint8_t *) (((uintptr_t) &pccache2[a] & 0x00000000ffffffffULL) | ((uintptr_t) &pccache2[0] & 0xffffffff00000000ULL)));
@@ -268,6 +367,12 @@ fastreadw(uint32_t a)
{
uint8_t *t;
uint16_t val;
# ifdef USE_DEBUG_REGS_486
read_type = 1;
mem_debug_check_addr(a, read_type);
mem_debug_check_addr(a + 1, read_type);
read_type = 4;
# endif
if ((a & 0xFFF) > 0xFFE) {
val = fastreadb(a);
val |= (fastreadb(a + 1) << 8);
@@ -297,6 +402,14 @@ fastreadl(uint32_t a)
{
uint8_t *t;
uint32_t val;
# ifdef USE_DEBUG_REGS_486
int i;
read_type = 1;
for (i = 0; i < 4; i++) {
mem_debug_check_addr(a + i, read_type);
}
read_type = 4;
# endif
if ((a & 0xFFF) < 0xFFD) {
if ((a >> 12) != pccache) {
t = getpccache(a);
@@ -336,37 +449,48 @@ get_ram_ptr(uint32_t a)
}
}
extern int opcode_has_modrm[256];
extern int opcode_length[256];
#ifdef OPS_286_386
static __inline uint16_t
fastreadw_fetch(uint32_t a)
{
uint16_t val;
uint16_t ret;
if ((a & 0xFFF) > 0xFFE) {
val = fastreadb(a);
if (opcode_length[val & 0xff] > 1)
val |= ((uint16_t) fastreadb(a + 1) << 8);
return val;
ret = fastreadb(a);
if (!cpu_state.abrt && (opcode_length[ret & 0xff] > 1))
ret |= ((uint16_t) fastreadb(a + 1) << 8);
} else if (cpu_state.abrt)
ret = 0;
else {
read_type = 1;
ret = readmemwl_2386(a);
read_type = 4;
}
return readmemwl_2386(a);
return ret;
}
static __inline uint32_t
fastreadl_fetch(uint32_t a)
{
uint32_t val;
uint32_t ret;
if (cpu_16bitbus || ((a & 0xFFF) > 0xFFC)) {
val = fastreadw_fetch(a);
if (opcode_length[val & 0xff] > 2)
val |= ((uint32_t) fastreadw(a + 2) << 16);
return val;
ret = fastreadw_fetch(a);
if (!cpu_state.abrt && (opcode_length[ret & 0xff] > 2))
ret |= ((uint32_t) fastreadw(a + 2) << 16);
} else if (cpu_state.abrt)
ret = 0;
else {
read_type = 1;
ret = readmemll_2386(a);
read_type = 4;
}
return readmemll_2386(a);
return ret;
}
#else
static __inline uint16_t
@@ -374,6 +498,12 @@ fastreadw_fetch(uint32_t a)
{
uint8_t *t;
uint16_t val;
# ifdef USE_DEBUG_REGS_486
read_type = 1;
mem_debug_check_addr(a, read_type);
mem_debug_check_addr(a + 1, read_type);
read_type = 4;
# endif
if ((a & 0xFFF) > 0xFFE) {
val = fastreadb(a);
if (opcode_length[val & 0xff] > 1)
@@ -404,6 +534,14 @@ fastreadl_fetch(uint32_t a)
{
uint8_t *t;
uint32_t val;
# ifdef USE_DEBUG_REGS_486
int i;
read_type = 1;
for (i = 0; i < 4; i++) {
mem_debug_check_addr(a + i, read_type);
}
read_type = 4;
# endif
if ((a & 0xFFF) < 0xFFD) {
if ((a >> 12) != pccache) {
t = getpccache(a);

View File

@@ -19,6 +19,7 @@
#include "x86_ops.h"
#include "x86seg_common.h"
#include "x86seg.h"
#include "x87_sf.h"
#include "x87.h"
#include <86box/io.h>
#include <86box/mem.h>
@@ -28,6 +29,7 @@
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/machine.h>
#include <86box/plat_fallthrough.h>
#include <86box/gdbstub.h>
#ifdef USE_DYNAREC
# include "codegen.h"
@@ -224,7 +226,11 @@ fetch_ea_16_long(uint32_t rmdat)
#include "386_ops.h"
#define CACHE_ON() (!(cr0 & (1 << 30)) && !(cpu_state.flags & T_FLAG))
#ifdef USE_DEBUG_REGS_486
# define CACHE_ON() (!(cr0 & (1 << 30)) && !(cpu_state.flags & T_FLAG) && !(dr[7] & 0xFF))
#else
# define CACHE_ON() (!(cr0 & (1 << 30)) && !(cpu_state.flags & T_FLAG))
#endif
#ifdef USE_DYNAREC
int32_t cycles_main = 0;
@@ -269,7 +275,11 @@ exec386_dynarec_int(void)
cpu_block_end = 0;
x86_was_reset = 0;
# ifdef USE_DEBUG_REGS_486
if (trap & 2) {
# else
if (trap == 2) {
# endif
/* Handle the T bit in the new TSS first. */
CPU_BLOCK_END();
goto block_ended;
@@ -286,6 +296,13 @@ exec386_dynarec_int(void)
cpu_state.ea_seg = &cpu_state.seg_ds;
cpu_state.ssegs = 0;
# ifdef USE_DEBUG_REGS_486
if (UNLIKELY(cpu_386_check_instruction_fault())) {
x86gen();
goto block_ended;
}
# endif
fetchdat = fastreadl_fetch(cs + cpu_state.pc);
# ifdef ENABLE_386_DYNAREC_LOG
if (in_smm)
@@ -296,9 +313,16 @@ exec386_dynarec_int(void)
opcode = fetchdat & 0xFF;
fetchdat >>= 8;
# ifdef USE_DEBUG_REGS_486
trap |= !!(cpu_state.flags & T_FLAG);
# else
trap = cpu_state.flags & T_FLAG;
# endif
cpu_state.pc++;
# ifdef USE_DEBUG_REGS_486
cpu_state.eflags &= ~(RF_FLAG);
# endif
x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat);
}
@@ -307,6 +331,16 @@ exec386_dynarec_int(void)
cpu_state.pc &= 0xffff;
# endif
# ifdef USE_DEBUG_REGS_486
if (!cpu_state.abrt) {
if (!rf_flag_no_clear) {
cpu_state.eflags &= ~RF_FLAG;
}
rf_flag_no_clear = 0;
}
# endif
if (((cs + cpu_state.pc) >> 12) != pccache)
CPU_BLOCK_END();
@@ -316,6 +350,9 @@ exec386_dynarec_int(void)
CPU_BLOCK_END();
}
if (cpu_init)
CPU_BLOCK_END();
if (cpu_state.abrt)
CPU_BLOCK_END();
if (smi_line)
@@ -330,7 +367,14 @@ exec386_dynarec_int(void)
block_ended:
if (!cpu_state.abrt && trap) {
# ifdef USE_DEBUG_REGS_486
//pclog("Debug trap 0x%X\n", trap);
if (trap & 2) dr[6] |= 0x8000;
if (trap & 1) dr[6] |= 0x4000;
# else
dr[6] |= (trap == 2) ? 0x8000 : 0x4000;
# endif
trap = 0;
# ifndef USE_NEW_DYNAREC
oldcs = CS;
@@ -373,7 +417,8 @@ exec386_dynarec_dyn(void)
int byte_offset = (phys_addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK;
uint64_t byte_mask = 1ULL << (PAGE_BYTE_MASK_MASK & 0x3f);
if ((page->code_present_mask & mask) || (page->byte_code_present_mask[byte_offset] & byte_mask))
if ((page->code_present_mask & mask) ||
((page->mem != page_ff) && (page->byte_code_present_mask[byte_offset] & byte_mask)))
# else
if (page->code_present_mask[(phys_addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] & mask)
# endif
@@ -550,6 +595,9 @@ exec386_dynarec_dyn(void)
# endif
CPU_BLOCK_END();
if (cpu_init)
CPU_BLOCK_END();
if ((cpu_state.flags & T_FLAG) || (trap == 2))
CPU_BLOCK_END();
if (smi_line)
@@ -647,6 +695,9 @@ exec386_dynarec_dyn(void)
# endif
CPU_BLOCK_END();
if (cpu_init)
CPU_BLOCK_END();
if (cpu_state.flags & T_FLAG)
CPU_BLOCK_END();
if (smi_line)
@@ -726,6 +777,11 @@ exec386_dynarec(int32_t cycs)
exec386_dynarec_dyn();
}
if (cpu_init) {
cpu_init = 0;
resetx86();
}
if (cpu_state.abrt) {
flags_rebuild();
tempi = cpu_state.abrt & ABRT_MASK;
@@ -842,6 +898,13 @@ exec386(int32_t cycs)
cpu_state.ea_seg = &cpu_state.seg_ds;
cpu_state.ssegs = 0;
#ifdef USE_DEBUG_REGS_486
if (UNLIKELY(cpu_386_check_instruction_fault())) {
x86gen();
goto block_ended;
}
#endif
fetchdat = fastreadl_fetch(cs + cpu_state.pc);
if (!cpu_state.abrt) {
@@ -851,9 +914,16 @@ exec386(int32_t cycs)
#endif
opcode = fetchdat & 0xFF;
fetchdat >>= 8;
#ifdef USE_DEBUG_REGS_486
trap |= !!(cpu_state.flags & T_FLAG);
#else
trap = cpu_state.flags & T_FLAG;
#endif
cpu_state.pc++;
#ifdef USE_DEBUG_REGS_486
cpu_state.eflags &= ~(RF_FLAG);
#endif
x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat);
if (x86_was_reset)
break;
@@ -871,6 +941,9 @@ exec386(int32_t cycs)
if (cpu_end_block_after_ins)
cpu_end_block_after_ins--;
#ifdef USE_DEBUG_REGS_486
block_ended:
#endif
if (cpu_state.abrt) {
flags_rebuild();
tempi = cpu_state.abrt & ABRT_MASK;
@@ -895,12 +968,21 @@ exec386(int32_t cycs)
}
} else if (trap) {
flags_rebuild();
#ifdef USE_DEBUG_REGS_486
if (trap & 1)
dr[6] |= 0x4000;
if (trap & 2)
dr[6] |= 0x8000;
#endif
trap = 0;
#ifndef USE_NEW_DYNAREC
oldcs = CS;
#endif
cpu_state.oldpc = cpu_state.pc;
#ifndef USE_DEBUG_REGS_486
dr[6] |= 0x4000;
#endif
x86_int(1);
}

View File

@@ -15,6 +15,7 @@
#include "x86_ops.h"
#include "x86seg_common.h"
#include "x86seg.h"
#include "x87_sf.h"
#include "x87.h"
#include "x86_flags.h"
#include <86box/io.h>
@@ -24,6 +25,7 @@
#include <86box/gdbstub.h>
#include "codegen.h"
#include <86box/plat_unused.h>
#include <86box/plat_fallthrough.h>
#define CPU_BLOCK_END() cpu_block_end = 1

View File

@@ -186,7 +186,11 @@ extern void x386_dynarec_log(const char *fmt, ...);
#else
# include "x86_ops_flag.h"
#endif
#include "x86_ops_fpu.h"
#ifdef OPS_286_386
# include "x86_ops_fpu_2386.h"
#else
# include "x86_ops_fpu.h"
#endif
#include "x86_ops_inc_dec.h"
#include "x86_ops_int.h"
#include "x86_ops_io.h"
@@ -216,7 +220,11 @@ extern void x386_dynarec_log(const char *fmt, ...);
#endif
#include "x86_ops_mul.h"
#include "x86_ops_pmode.h"
#include "x86_ops_prefix.h"
#ifdef OPS_286_386
# include "x86_ops_prefix_2386.h"
#else
# include "x86_ops_prefix.h"
#endif
#ifdef IS_DYNAREC
# include "x86_ops_rep_dyn.h"
#else

View File

@@ -56,7 +56,6 @@ static uint32_t *opseg[4];
static x86seg *_opseg[4];
static int noint = 0;
static int in_lock = 0;
static int cpu_alu_op, pfq_size;
static uint32_t cpu_src = 0, cpu_dest = 0;
@@ -545,7 +544,6 @@ reset_808x(int hard)
{
biu_cycles = 0;
in_rep = 0;
in_lock = 0;
completed = 1;
repeating = 0;
clear_lock = 0;
@@ -787,6 +785,7 @@ seteaq(uint64_t val)
complicates compiling. */
#define FPU_8087
#define tempc tempc_fpu
#include "x87_sf.h"
#include "x87.h"
#include "x87_ops.h"
#undef tempc
@@ -3198,31 +3197,66 @@ execx86(int cycs)
if (!hasfpu)
geteaw();
else
switch (opcode) {
case 0xD8:
ops_fpu_8087_d8[(rmdat >> 3) & 0x1f]((uint32_t) rmdat);
break;
case 0xD9:
ops_fpu_8087_d9[rmdat & 0xff]((uint32_t) rmdat);
break;
case 0xDA:
ops_fpu_8087_da[rmdat & 0xff]((uint32_t) rmdat);
break;
case 0xDB:
ops_fpu_8087_db[rmdat & 0xff]((uint32_t) rmdat);
break;
case 0xDC:
ops_fpu_8087_dc[(rmdat >> 3) & 0x1f]((uint32_t) rmdat);
break;
case 0xDD:
ops_fpu_8087_dd[rmdat & 0xff]((uint32_t) rmdat);
break;
case 0xDE:
ops_fpu_8087_de[rmdat & 0xff]((uint32_t) rmdat);
break;
case 0xDF:
ops_fpu_8087_df[rmdat & 0xff]((uint32_t) rmdat);
break;
if (fpu_softfloat) {
switch (opcode) {
case 0xD8:
ops_sf_fpu_8087_d8[(rmdat >> 3) & 0x1f](rmdat);
break;
case 0xD9:
ops_sf_fpu_8087_d9[rmdat & 0xff](rmdat);
break;
case 0xDA:
ops_sf_fpu_8087_da[rmdat & 0xff](rmdat);
break;
case 0xDB:
ops_sf_fpu_8087_db[rmdat & 0xff](rmdat);
break;
case 0xDC:
ops_sf_fpu_8087_dc[(rmdat >> 3) & 0x1f](rmdat);
break;
case 0xDD:
ops_sf_fpu_8087_dd[rmdat & 0xff](rmdat);
break;
case 0xDE:
ops_sf_fpu_8087_de[rmdat & 0xff](rmdat);
break;
case 0xDF:
ops_sf_fpu_8087_df[rmdat & 0xff](rmdat);
break;
default:
break;
}
} else {
switch (opcode) {
case 0xD8:
ops_fpu_8087_d8[(rmdat >> 3) & 0x1f](rmdat);
break;
case 0xD9:
ops_fpu_8087_d9[rmdat & 0xff](rmdat);
break;
case 0xDA:
ops_fpu_8087_da[rmdat & 0xff](rmdat);
break;
case 0xDB:
ops_fpu_8087_db[rmdat & 0xff](rmdat);
break;
case 0xDC:
ops_fpu_8087_dc[(rmdat >> 3) & 0x1f](rmdat);
break;
case 0xDD:
ops_fpu_8087_dd[rmdat & 0xff](rmdat);
break;
case 0xDE:
ops_fpu_8087_de[rmdat & 0xff](rmdat);
break;
case 0xDF:
ops_fpu_8087_df[rmdat & 0xff](rmdat);
break;
default:
break;
}
}
cpu_state.pc = tempw; /* Do this as the x87 code advances it, which is needed on
the 286+ core, but not here. */

View File

@@ -23,16 +23,19 @@ endif()
if(CYRIX_6X86)
target_compile_definitions(cpu PRIVATE USE_CYRIX_6X86)
add_library(ct686 OBJECT codegen_timing_686.c)
target_link_libraries(86Box ct686)
endif()
if(DYNAREC)
target_sources(cpu PRIVATE 386_dynarec_ops.c)
add_library(cgt OBJECT codegen_timing_486.c codegen_timing_686.c
add_library(cgt OBJECT codegen_timing_486.c
codegen_timing_common.c codegen_timing_k6.c
codegen_timing_pentium.c codegen_timing_p6.c
codegen_timing_winchip.c codegen_timing_winchip2.c)
endif()
add_subdirectory(softfloat)
target_link_libraries(86Box softfloat)
add_subdirectory(softfloat3e)
target_link_libraries(86Box softfloat3e)

View File

@@ -9,6 +9,7 @@
#include "x86.h"
#include "x86_ops.h"
#include "x87_sf.h"
#include "x87.h"
#include "codegen.h"
#include "codegen_ops.h"

View File

@@ -19,6 +19,7 @@
#include "x86.h"
#include "x86_ops.h"
#include "x87_sf.h"
#include "x87.h"
#include "codegen.h"
#include "codegen_timing_common.h"

View File

@@ -12,6 +12,7 @@
#include "x86.h"
#include "x86_ops.h"
#include "x86seg_common.h"
#include "x87_sf.h"
#include "x87.h"
#include "386_common.h"
#include "codegen.h"

View File

@@ -13,6 +13,7 @@
#include "x86.h"
#include "x86_ops.h"
#include "x86seg_common.h"
#include "x87_sf.h"
#include "x87.h"
#include "386_common.h"
#include "codegen.h"

View File

@@ -21,6 +21,7 @@
#include "x86.h"
#include "x86_ops.h"
#include "x87_sf.h"
#include "x87.h"
#include "codegen.h"
#include "codegen_ops.h"

View File

@@ -9,6 +9,7 @@
#include "x86.h"
#include "x86_ops.h"
#include "x87_sf.h"
#include "x87.h"
#include "codegen.h"
#include "codegen_ops.h"

View File

@@ -18,6 +18,7 @@
#include "x86.h"
#include "x86_ops.h"
#include "x87_sf.h"
#include "x87.h"
#include "codegen.h"
#include "codegen_ops.h"

File diff suppressed because it is too large Load Diff

View File

@@ -21,8 +21,6 @@
#ifndef EMU_CPU_H
#define EMU_CPU_H
#include "softfloat/softfloat.h"
enum {
FPU_NONE,
FPU_8087,
@@ -175,6 +173,7 @@ typedef struct {
#define VIP_FLAG 0x0010 /* in EFLAGS */
#define VID_FLAG 0x0020 /* in EFLAGS */
#define EM_FLAG 0x00004 /* in CR0 */
#define WP_FLAG 0x10000 /* in CR0 */
#define CR4_VME (1 << 0) /* Virtual 8086 Mode Extensions */
@@ -227,101 +226,97 @@ typedef union {
} MMX_REG;
typedef struct {
/* IDT WinChip and WinChip 2 MSR's */
uint32_t tr1; /* 0x00000002, 0x0000000e */
uint32_t tr12; /* 0x00000002, 0x0000000e */
uint32_t cesr; /* 0x00000011 */
/* IBM 386SLC/486SLC/486BL MSRs */
uint64_t ibm_por; /* 0x00001000 - 386SLC and later */
uint64_t ibm_crcr; /* 0x00001001 - 386SLC and later */
uint64_t ibm_por2; /* 0x00001002 - 486SLC and later */
uint64_t ibm_pcr; /* 0x00001004 - 486BL3 */
/* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's */
uint64_t apic_base; /* 0x0000001b - Should the Pentium not also have this? */
/* IDT WinChip C6/2/VIA Cyrix III MSRs */
uint32_t fcr; /* 0x00000107 (IDT), 0x00001107 (VIA) */
uint64_t fcr2; /* 0x00000108 (IDT), 0x00001108 (VIA) */
uint64_t fcr3; /* 0x00000108 (IDT), 0x00001108 (VIA) */
uint64_t mcr[8]; /* 0x00000110 - 0x00000117 (IDT) */
uint32_t mcr_ctrl; /* 0x00000120 (IDT) */
/* Weird long MSR's used by the Hyper-V BIOS. */
uint64_t ecx20; /* 0x00000020, really 0x40000020, but we filter out the top 18 bits
like a real Deschutes does. */
/* AMD K5/K6 MSRs */
uint64_t amd_aar; /* 0x00000082 - all K5 */
uint64_t amd_hwcr; /* 0x00000083 - all K5 and all K6 */
uint64_t amd_watmcr; /* 0x00000085 - K5 Model 1 and later */
uint64_t amd_wapmrr; /* 0x00000086 - K5 Model 1 and later */
/* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's */
uint64_t ecx79; /* 0x00000079 */
uint64_t amd_efer; /* 0xc0000080 - all K5 and all K6 */
uint64_t amd_star; /* 0xc0000081 - K6-2 and later */
uint64_t amd_whcr; /* 0xc0000082 - all K5 and all K6 */
uint64_t amd_uwccr; /* 0xc0000085 - K6-2C and later */
uint64_t amd_epmr; /* 0xc0000086 - K6-III+/2+ only */
uint64_t amd_psor; /* 0xc0000087 - K6-2C and later */
uint64_t amd_pfir; /* 0xc0000088 - K6-2C and later */
uint64_t amd_l2aar; /* 0xc0000089 - K6-III and later */
/* AMD K5, 5k86, K6, K6-2, K6-2C, K6-3, K6-2P, and K6-3P MSR's */
uint64_t ecx83; /* 0x00000083 - AMD K5 and K6 MSR's. */
/* Pentium/Pentium MMX MSRs */
uint64_t mcar; /* 0x00000000 - also on K5 and (R/W) K6 */
uint64_t mctr; /* 0x00000001 - also on K5 and (R/W) K6 */
uint32_t tr1; /* 0x00000002 - also on WinChip C6/2 */
uint32_t tr2; /* 0x00000004 - reserved on PMMX */
uint32_t tr3; /* 0x00000005 */
uint32_t tr4; /* 0x00000006 */
uint32_t tr5; /* 0x00000007 */
uint32_t tr6; /* 0x00000008 */
uint32_t tr7; /* 0x00000009 */
uint32_t tr9; /* 0x0000000b */
uint32_t tr10; /* 0x0000000c */
uint32_t tr11; /* 0x0000000d */
uint32_t tr12; /* 0x0000000e - also on WinChip C6/2 and K6 */
uint32_t cesr; /* 0x00000011 - also on WinChip C6/2 and Cx6x86MX */
uint64_t pmc[2]; /* 0x00000012, 0x00000013 - also on WinChip C6/2 and Cx6x86MX */
uint32_t fp_last_xcpt; /* 0x8000001b - undocumented */
uint32_t probe_ctl; /* 0x8000001d - undocumented */
uint32_t ecx8000001e; /* 0x8000001e - undocumented */
uint32_t ecx8000001f; /* 0x8000001f - undocumented */
/* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's */
uint64_t ecx8x[4]; /* 0x00000088 - 0x0000008b */
uint64_t ia32_pmc[8]; /* 0x000000c1 - 0x000000c8 */
uint64_t mtrr_cap; /* 0x000000fe */
/* Pentium Pro/II MSRs */
uint64_t apic_base; /* 0x0000001b */
uint32_t test_ctl; /* 0x00000033 */
uint64_t bios_updt; /* 0x00000079 */
/* IDT WinChip and WinChip 2 MSR's that are also on the VIA Cyrix III */
uint32_t fcr; /* 0x00000107 (IDT), 0x00001107 (VIA) */
uint64_t fcr2; /* 0x00000108 (IDT), 0x00001108 (VIA) */
uint64_t fcr3; /* 0x00000108 (IDT), 0x00001108 (VIA) */
uint64_t bbl_cr_dx[4]; /* 0x00000088 - 0x0000008b */
uint64_t perfctr[2]; /* 0x000000c1, 0x000000c2 */
uint64_t mtrr_cap; /* 0x000000fe */
/* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's */
uint64_t ecx116; /* 0x00000116 */
uint64_t ecx11x[4]; /* 0x00000118 - 0x0000011b */
uint64_t ecx11e; /* 0x0000011e */
uint64_t bbl_cr_addr; /* 0x00000116 */
uint64_t bbl_cr_decc; /* 0x00000118 */
uint64_t bbl_cr_ctl; /* 0x00000119 */
uint64_t bbl_cr_trig; /* 0x0000011a */
uint64_t bbl_cr_busy; /* 0x0000011b */
uint64_t bbl_cr_ctl3; /* 0x0000011e */
/* Pentium II Klamath and Pentium II Deschutes MSR's */
uint16_t sysenter_cs; /* 0x00000174 - SYSENTER/SYSEXIT MSR's */
uint32_t sysenter_esp; /* 0x00000175 - SYSENTER/SYSEXIT MSR's */
uint32_t sysenter_eip; /* 0x00000176 - SYSENTER/SYSEXIT MSR's */
uint16_t sysenter_cs; /* 0x00000174 - Pentium II and later */
uint32_t sysenter_esp; /* 0x00000175 - Pentium II and later */
uint32_t sysenter_eip; /* 0x00000176 - Pentium II and later */
/* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's */
uint64_t mcg_ctl; /* 0x0000017b - Machine Check Architecture */
uint64_t ecx186; /* 0x00000186, 0x00000187 */
uint64_t ecx187; /* 0x00000186, 0x00000187 */
uint64_t mcg_ctl; /* 0x0000017b */
uint64_t evntsel[2]; /* 0x00000186, 0x00000187 */
/* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's */
uint64_t debug_ctl; /* 0x000001d9 - Debug Registers Control */
uint64_t ecx1e0; /* 0x000001e0 */
uint32_t debug_ctl; /* 0x000001d9 */
uint32_t rob_cr_bkuptmpdr6; /* 0x000001e0 */
/* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's that are also
on the VIA Cyrix III */
uint64_t mtrr_physbase[8]; /* 0x00000200 - 0x0000020f */
/* MTTR-related MSRs also present on the VIA Cyrix III */
uint64_t mtrr_physbase[8]; /* 0x00000200 - 0x0000020f (ECX & 0) */
uint64_t mtrr_physmask[8]; /* 0x00000200 - 0x0000020f (ECX & 1) */
uint64_t mtrr_fix64k_8000; /* 0x00000250 */
uint64_t mtrr_fix16k_8000; /* 0x00000258 */
uint64_t mtrr_fix16k_a000; /* 0x00000259 */
uint64_t mtrr_fix4k[8]; /* 0x00000268 - 0x0000026f */
uint64_t mtrr_deftype; /* 0x000002ff */
/* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's */
uint64_t pat; /* 0x00000277 */
/* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's that are also
on the VIA Cyrix III */
uint64_t mtrr_deftype; /* 0x000002ff */
/* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's */
uint64_t mca_ctl[5]; /* 0x00000400, 0x00000404, 0x00000408, 0x0000040c, 0x00000410 - Machine Check Architecture */
uint64_t pat; /* 0x00000277 - Pentium II Deschutes and later */
uint64_t mca_ctl[5]; /* 0x00000400, 0x00000404, 0x00000408, 0x0000040c, 0x00000410 */
uint64_t ecx570; /* 0x00000570 */
/* IBM 386SLC, 486SLC, and 486BL MSR's */
uint64_t ibm_por; /* 0x00001000 - Processor Operation Register */
uint64_t ibm_crcr; /* 0x00001001 - Cache Region Control Register */
/* IBM 486SLC and 486BL MSR's */
uint64_t ibm_por2; /* 0x00001002 - Processor Operation Register */
/* AMD K5, 5k86, K6, K6-2, K6-2C, K6-3, K6-2P, and K6-3P MSR's */
uint64_t amd_efer; /* 0xc0000080 */
/* AMD K6-2, K6-2C, K6-3, K6-2P, and K6-3P MSR's */
uint64_t star; /* 0xc0000081 */
/* AMD K5, 5k86, K6, K6-2, K6-2C, K6-3, K6-2P, and K6-3P MSR's */
uint64_t amd_whcr; /* 0xc0000082 */
/* AMD K6-2C, K6-3, K6-2P, and K6-3P MSR's */
uint64_t amd_uwccr; /* 0xc0000085 */
/* AMD K6-2P and K6-3P MSR's */
uint64_t amd_epmr; /* 0xc0000086 */
/* AMD K6-2C, K6-3, K6-2P, and K6-3P MSR's */
uint64_t amd_psor; /* 0xc0000087, 0xc0000088 */
uint64_t amd_pfir; /* 0xc0000087, 0xc0000088 */
/* K6-3, K6-2P, and K6-3P MSR's */
uint64_t amd_l2aar; /* 0xc0000089 */
/* Other/Unclassified MSRs */
uint64_t ecx20; /* 0x00000020, really 0x40000020, but we filter out the top 18 bits
like a real Deschutes does. */
} msr_t;
typedef struct {
@@ -410,22 +405,6 @@ typedef struct {
uint32_t _smbase;
} cpu_state_t;
typedef struct {
uint16_t cwd;
uint16_t swd;
uint16_t tag;
uint16_t foo;
uint32_t fip;
uint32_t fdp;
uint16_t fcs;
uint16_t fds;
floatx80 st_space[8];
unsigned char tos;
unsigned char align1;
unsigned char align2;
unsigned char align3;
} fpu_state_t;
#define in_smm cpu_state._in_smm
#define smi_line cpu_state._smi_line
@@ -506,7 +485,6 @@ COMPILE_TIME_ASSERT(sizeof(cpu_state_t) <= 128)
/* Global variables. */
extern cpu_state_t cpu_state;
extern fpu_state_t fpu_state;
extern const cpu_family_t cpu_families[];
extern cpu_family_t *cpu_f;
@@ -587,7 +565,6 @@ extern double bus_timing;
extern double isa_timing;
extern double pci_timing;
extern double agp_timing;
extern uint64_t pmc[2];
extern uint16_t temp_seg_data[4];
extern uint16_t cs_msr;
extern uint32_t esp_msr;
@@ -597,8 +574,6 @@ extern uint32_t eip_msr;
extern uint64_t amd_efer;
extern uint64_t star;
#define FPU_CW_Reserved_Bits (0xe0c0)
#define cr0 cpu_state.CR0.l
#define msw cpu_state.CR0.w
extern uint32_t cr2;
@@ -768,6 +743,11 @@ void cyrix_write_seg_descriptor(uint32_t addr, x86seg *seg);
#define SMHR_VALID (1 << 0)
#define SMHR_ADDR_MASK (0xfffffffc)
typedef union {
uint32_t fd;
uint8_t b[4];
} fetch_dat_t;
typedef struct {
struct {
uint32_t base;
@@ -822,4 +802,16 @@ extern void prefetch_flush(void);
extern void prefetch_run(int instr_cycles, int bytes, int modrm, int reads, int reads_l, int writes, int writes_l, int ea32);
extern int lock_legal[256];
extern int lock_legal_0f[256];
extern int lock_legal_ba[8];
extern int lock_legal_80[8];
extern int lock_legal_f6[8];
extern int lock_legal_fe[8];
extern int in_lock;
extern int cpu_override_interpreter;
extern int is_lock_legal(uint32_t fetchdat);
#endif /*EMU_CPU_H*/

View File

@@ -1009,12 +1009,92 @@ const cpu_family_t cpu_families[] = {
.name = "i386SX",
.internal_name = "i386sx",
.cpus = (const CPU[]) {
{"16", CPU_386SX, fpus_80386, 16000000, 1, 5000, 0x2308, 0, 0, 0, 3,3,3,3, 2},
{"20", CPU_386SX, fpus_80386, 20000000, 1, 5000, 0x2308, 0, 0, 0, 4,4,3,3, 3},
{"25", CPU_386SX, fpus_80386, 25000000, 1, 5000, 0x2308, 0, 0, 0, 4,4,3,3, 3},
{"33", CPU_386SX, fpus_80386, 33333333, 1, 5000, 0x2308, 0, 0, 0, 6,6,3,3, 4},
{"40", CPU_386SX, fpus_80386, 40000000, 1, 5000, 0x2308, 0, 0, 0, 7,7,3,3, 5},
{"", 0}
{
.name = "16",
.cpu_type = CPU_386SX,
.fpus = fpus_80386,
.rspeed = 16000000,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x2308,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 3,
.mem_write_cycles = 3,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 2
},
{
.name = "20",
.cpu_type = CPU_386SX,
.fpus = fpus_80386,
.rspeed = 20000000,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x2308,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 4,
.mem_write_cycles = 4,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 3
},
{
.name = "25",
.cpu_type = CPU_386SX,
.fpus = fpus_80386,
.rspeed = 25000000,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x2308,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 4,
.mem_write_cycles = 4,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 3
},
{
.name = "33",
.cpu_type = CPU_386SX,
.fpus = fpus_80386,
.rspeed = 33333333,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x2308,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 6,
.mem_write_cycles = 6,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 4
},
{
.name = "40",
.cpu_type = CPU_386SX,
.fpus = fpus_80386,
.rspeed = 40000000,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x2308,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 7,
.mem_write_cycles = 7,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 5
},
{ .name = "", 0 }
}
}, {
.package = CPU_PKG_386SX,
@@ -1022,12 +1102,92 @@ const cpu_family_t cpu_families[] = {
.name = "Am386SX",
.internal_name = "am386sx",
.cpus = (const CPU[]) {
{"16", CPU_386SX, fpus_80386, 16000000, 1, 5000, 0x2308, 0, 0, 0, 3,3,3,3, 2},
{"20", CPU_386SX, fpus_80386, 20000000, 1, 5000, 0x2308, 0, 0, 0, 4,4,3,3, 3},
{"25", CPU_386SX, fpus_80386, 25000000, 1, 5000, 0x2308, 0, 0, 0, 4,4,3,3, 3},
{"33", CPU_386SX, fpus_80386, 33333333, 1, 5000, 0x2308, 0, 0, 0, 6,6,3,3, 4},
{"40", CPU_386SX, fpus_80386, 40000000, 1, 5000, 0x2308, 0, 0, 0, 7,7,3,3, 5},
{"", 0}
{
.name = "16",
.cpu_type = CPU_386SX,
.fpus = fpus_80386,
.rspeed = 16000000,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x2308,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 3,
.mem_write_cycles = 3,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 2
},
{
.name = "20",
.cpu_type = CPU_386SX,
.fpus = fpus_80386,
.rspeed = 20000000,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x2308,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 4,
.mem_write_cycles = 4,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 3
},
{
.name = "25",
.cpu_type = CPU_386SX,
.fpus = fpus_80386,
.rspeed = 25000000,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x2308,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 4,
.mem_write_cycles = 4,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 3
},
{
.name = "33",
.cpu_type = CPU_386SX,
.fpus = fpus_80386,
.rspeed = 33333333,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x2308,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 6,
.mem_write_cycles = 6,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 4
},
{
.name = "40",
.cpu_type = CPU_386SX,
.fpus = fpus_80386,
.rspeed = 40000000,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x2308,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 7,
.mem_write_cycles = 7,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 5
},
{ .name = "", 0 }
}
}, {
.package = CPU_PKG_386DX,
@@ -1035,12 +1195,92 @@ const cpu_family_t cpu_families[] = {
.name = "i386DX",
.internal_name = "i386dx",
.cpus = (const CPU[]) {
{"16", CPU_386DX, fpus_80386, 16000000, 1, 5000, 0x0308, 0, 0, 0, 3,3,3,3, 2},
{"20", CPU_386DX, fpus_80386, 20000000, 1, 5000, 0x0308, 0, 0, 0, 4,4,3,3, 3},
{"25", CPU_386DX, fpus_80386, 25000000, 1, 5000, 0x0308, 0, 0, 0, 4,4,3,3, 3},
{"33", CPU_386DX, fpus_80386, 33333333, 1, 5000, 0x0308, 0, 0, 0, 6,6,3,3, 4},
{"40", CPU_386DX, fpus_80386, 40000000, 1, 5000, 0x0308, 0, 0, 0, 7,7,3,3, 5},
{"", 0}
{
.name = "16",
.cpu_type = CPU_386DX,
.fpus = fpus_80386,
.rspeed = 16000000,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x0308,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 3,
.mem_write_cycles = 3,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 2
},
{
.name = "20",
.cpu_type = CPU_386DX,
.fpus = fpus_80386,
.rspeed = 20000000,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x0308,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 4,
.mem_write_cycles = 4,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 3
},
{
.name = "25",
.cpu_type = CPU_386DX,
.fpus = fpus_80386,
.rspeed = 25000000,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x0308,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 4,
.mem_write_cycles = 4,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 3
},
{
.name = "33",
.cpu_type = CPU_386DX,
.fpus = fpus_80386,
.rspeed = 33333333,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x0308,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 6,
.mem_write_cycles = 6,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 4
},
{
.name = "40",
.cpu_type = CPU_386DX,
.fpus = fpus_80386,
.rspeed = 40000000,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x0308,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 7,
.mem_write_cycles = 7,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 5
},
{ .name = "", 0 }
}
}, {
.package = CPU_PKG_386DX_DESKPRO386,
@@ -1048,10 +1288,58 @@ const cpu_family_t cpu_families[] = {
.name = "i386DX",
.internal_name = "i386dx_deskpro386",
.cpus = (const CPU[]) {
{"16", CPU_386DX, fpus_80286, 16000000, 1, 5000, 0x0308, 0, 0, 0, 3,3,3,3, 2},
{"20", CPU_386DX, fpus_80386, 20000000, 1, 5000, 0x0308, 0, 0, 0, 4,4,3,3, 3},
{"25", CPU_386DX, fpus_80386, 25000000, 1, 5000, 0x0308, 0, 0, 0, 4,4,3,3, 3},
{"", 0}
{
.name = "16",
.cpu_type = CPU_386DX,
.fpus = fpus_80286,
.rspeed = 16000000,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x0308,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 3,
.mem_write_cycles = 3,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 2
},
{
.name = "20",
.cpu_type = CPU_386DX,
.fpus = fpus_80386,
.rspeed = 20000000,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x0308,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 4,
.mem_write_cycles = 4,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 3
},
{
.name = "25",
.cpu_type = CPU_386DX,
.fpus = fpus_80386,
.rspeed = 25000000,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x0308,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 4,
.mem_write_cycles = 4,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 3
},
{ .name = "", 0 }
}
}, {
.package = CPU_PKG_386DX,
@@ -1059,10 +1347,58 @@ const cpu_family_t cpu_families[] = {
.name = "RapidCAD",
.internal_name = "rapidcad",
.cpus = (const CPU[]) {
{"25", CPU_RAPIDCAD, fpus_internal, 25000000, 1, 5000, 0x0340, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3, 3},
{"33", CPU_RAPIDCAD, fpus_internal, 33333333, 1, 5000, 0x0340, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4},
{"40", CPU_RAPIDCAD, fpus_internal, 40000000, 1, 5000, 0x0340, 0, 0, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5},
{"", 0}
{
.name = "25",
.cpu_type = CPU_RAPIDCAD,
.fpus = fpus_internal,
.rspeed = 25000000,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x0340,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = CPU_SUPPORTS_DYNAREC,
.mem_read_cycles = 4,
.mem_write_cycles = 4,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 3
},
{
.name = "33",
.cpu_type = CPU_RAPIDCAD,
.fpus = fpus_internal,
.rspeed = 33333333,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x0340,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = CPU_SUPPORTS_DYNAREC,
.mem_read_cycles = 6,
.mem_write_cycles = 6,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 4
},
{
.name = "40",
.cpu_type = CPU_RAPIDCAD,
.fpus = fpus_internal,
.rspeed = 40000000,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x0340,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = CPU_SUPPORTS_DYNAREC,
.mem_read_cycles = 7,
.mem_write_cycles = 7,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 5
},
{ .name = "", 0 }
}
}, {
.package = CPU_PKG_386DX,
@@ -1070,10 +1406,58 @@ const cpu_family_t cpu_families[] = {
.name = "Am386DX",
.internal_name = "am386dx",
.cpus = (const CPU[]) {
{"25", CPU_386DX, fpus_80386, 25000000, 1, 5000, 0x0308, 0, 0, 0, 4,4,3,3, 3},
{"33", CPU_386DX, fpus_80386, 33333333, 1, 5000, 0x0308, 0, 0, 0, 6,6,3,3, 4},
{"40", CPU_386DX, fpus_80386, 40000000, 1, 5000, 0x0308, 0, 0, 0, 7,7,3,3, 5},
{"", 0}
{
.name = "25",
.cpu_type = CPU_386DX,
.fpus = fpus_80386,
.rspeed = 25000000,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x0308,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 4,
.mem_write_cycles = 4,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 3
},
{
.name = "33",
.cpu_type = CPU_386DX,
.fpus = fpus_80386,
.rspeed = 33333333,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x0308,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 6,
.mem_write_cycles = 6,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 4
},
{
.name = "40",
.cpu_type = CPU_386DX,
.fpus = fpus_80386,
.rspeed = 40000000,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x0308,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 7,
.mem_write_cycles = 7,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 5
},
{ .name = "", 0 }
}
}, {
.package = CPU_PKG_M6117,
@@ -1081,9 +1465,41 @@ const cpu_family_t cpu_families[] = {
.name = "M6117",
.internal_name = "m6117",
.cpus = (const CPU[]) { /* All timings and edx_reset values assumed. */
{"33", CPU_386SX, fpus_none, 33333333, 1, 5000, 0x2309, 0, 0, 0, 6,6,3,3, 4},
{"40", CPU_386SX, fpus_none, 40000000, 1, 5000, 0x2309, 0, 0, 0, 7,7,3,3, 5},
{"", 0}
{
.name = "33",
.cpu_type = CPU_386SX,
.fpus = fpus_none,
.rspeed = 33333333,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x2309,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 6,
.mem_write_cycles = 6,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 4
},
{
.name = "40",
.cpu_type = CPU_386SX,
.fpus = fpus_none,
.rspeed = 40000000,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x2309,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 7,
.mem_write_cycles = 7,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 5
},
{ .name = "", 0 }
}
}, {
.package = CPU_PKG_386SLC_IBM,
@@ -1175,10 +1591,58 @@ const cpu_family_t cpu_families[] = {
.name = "Cx486DLC",
.internal_name = "cx486dlc",
.cpus = (const CPU[]) {
{"25", CPU_486DLC, fpus_80386, 25000000, 1, 5000, 0x401, 0, 0x0001, 0, 4, 4,3,3, 3},
{"33", CPU_486DLC, fpus_80386, 33333333, 1, 5000, 0x401, 0, 0x0001, 0, 6, 6,3,3, 4},
{"40", CPU_486DLC, fpus_80386, 40000000, 1, 5000, 0x401, 0, 0x0001, 0, 7, 7,3,3, 5},
{"", 0}
{
.name = "25",
.cpu_type = CPU_486DLC,
.fpus = fpus_80386,
.rspeed = 25000000,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x401,
.cpuid_model = 0,
.cyrix_id = 0x0001,
.cpu_flags = 0,
.mem_read_cycles = 4,
.mem_write_cycles = 4,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 3
},
{
.name = "33",
.cpu_type = CPU_486DLC,
.fpus = fpus_80386,
.rspeed = 33333333,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x401,
.cpuid_model = 0,
.cyrix_id = 0x0001,
.cpu_flags = 0,
.mem_read_cycles = 6,
.mem_write_cycles = 6,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 4
},
{
.name = "40",
.cpu_type = CPU_486DLC,
.fpus = fpus_80386,
.rspeed = 40000000,
.multi = 1,
.voltage = 5000,
.edx_reset = 0x401,
.cpuid_model = 0,
.cyrix_id = 0x0001,
.cpu_flags = 0,
.mem_read_cycles = 7,
.mem_write_cycles = 7,
.cache_read_cycles = 3,
.cache_write_cycles = 3,
.atclk_div = 5
},
{ .name = "", 0 }
}
}, {
.package = CPU_PKG_386DX,
@@ -1186,11 +1650,75 @@ const cpu_family_t cpu_families[] = {
.name = "Cx486DRx2",
.internal_name = "cx486drx2",
.cpus = (const CPU[]) {
{"32", CPU_486DLC, fpus_80386, 32000000, 2, 5000, 0x407, 0, 0x0007, 0, 6, 6,6,6, 4},
{"40", CPU_486DLC, fpus_80386, 40000000, 2, 5000, 0x407, 0, 0x0007, 0, 8, 8,6,6, 6},
{"50", CPU_486DLC, fpus_80386, 50000000, 2, 5000, 0x407, 0, 0x0007, 0, 8, 8,6,6, 6},
{"66", CPU_486DLC, fpus_80386, 66666666, 2, 5000, 0x407, 0, 0x0007, 0, 12,12,6,6, 8},
{"", 0}
{
.name = "32",
.cpu_type = CPU_486DLC,
.fpus = fpus_80386,
.rspeed = 32000000,
.multi = 2,
.voltage = 5000,
.edx_reset = 0x407,
.cpuid_model = 0,
.cyrix_id = 0x0007,
.cpu_flags = 0,
.mem_read_cycles = 6,
.mem_write_cycles = 6,
.cache_read_cycles = 6,
.cache_write_cycles = 6,
.atclk_div = 4
},
{
.name = "40",
.cpu_type = CPU_486DLC,
.fpus = fpus_80386,
.rspeed = 40000000,
.multi = 2,
.voltage = 5000,
.edx_reset = 0x407,
.cpuid_model = 0,
.cyrix_id = 0x0007,
.cpu_flags = 0,
.mem_read_cycles = 8,
.mem_write_cycles = 8,
.cache_read_cycles = 6,
.cache_write_cycles = 6,
.atclk_div = 6
},
{
.name = "50",
.cpu_type = CPU_486DLC,
.fpus = fpus_80386,
.rspeed = 50000000,
.multi = 2,
.voltage = 5000,
.edx_reset = 0x407,
.cpuid_model = 0,
.cyrix_id = 0x0007,
.cpu_flags = 0,
.mem_read_cycles = 8,
.mem_write_cycles = 8,
.cache_read_cycles = 6,
.cache_write_cycles = 6,
.atclk_div = 6
},
{
.name = "66",
.cpu_type = CPU_486DLC,
.fpus = fpus_80386,
.rspeed = 66666666,
.multi = 2,
.voltage = 5000,
.edx_reset = 0x407,
.cpuid_model = 0,
.cyrix_id = 0x0007,
.cpu_flags = 0,
.mem_read_cycles = 12,
.mem_write_cycles = 12,
.cache_read_cycles = 6,
.cache_write_cycles = 6,
.atclk_div = 8
},
{ .name = "", 0 }
}
}, {
.package = CPU_PKG_SOCKET1,
@@ -1398,9 +1926,9 @@ const cpu_family_t cpu_families[] = {
.name = "Am5x86",
.internal_name = "am5x86",
.cpus = (const CPU[]) {
{"P75", CPU_ENH_Am486DX, fpus_internal, 133333333, 4.0, 5000, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 16},
{"P75+", CPU_ENH_Am486DX, fpus_internal, 150000000, 3.0, 5000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 28,28,12,12, 20},/*The rare P75+ was indeed a triple-clocked 150 MHz according to research*/
{"P90", CPU_ENH_Am486DX, fpus_internal, 160000000, 4.0, 5000, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 28,28,12,12, 20},/*160 MHz on a 40 MHz bus was a common overclock and "5x86/P90" was used by a number of BIOSes to refer to that configuration*/
{"133 (P75)", CPU_ENH_Am486DX, fpus_internal, 133333333, 4.0, 5000, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 16},
{"150 (P75+)", CPU_ENH_Am486DX, fpus_internal, 150000000, 3.0, 5000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 28,28,12,12, 20},/*The rare P75+ was indeed a triple-clocked 150 MHz according to research*/
{"160 (P90)", CPU_ENH_Am486DX, fpus_internal, 160000000, 4.0, 5000, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 28,28,12,12, 20},/*160 MHz on a 40 MHz bus was a common overclock and "5x86/P90" was used by a number of BIOSes to refer to that configuration*/
{"", 0}
}
}, {
@@ -1625,23 +2153,7 @@ const cpu_family_t cpu_families[] = {
{
.package = CPU_PKG_SOCKET5_7,
.manufacturer = "AMD",
.name = "K5 (5k86)",
.internal_name = "k5_5k86",
.cpus = (const CPU[]) {
{"75 (P75)", CPU_K5, fpus_internal, 75000000, 1.5, 3520, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9},
{"90 (P90)", CPU_K5, fpus_internal, 90000000, 1.5, 3520, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 21/2},
{"100 (P100)", CPU_K5, fpus_internal, 100000000, 1.5, 3520, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 12},
{"90 (PR120)", CPU_5K86, fpus_internal, 120000000, 2.0, 3520, 0x511, 0x511, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14},
{"100 (PR133)", CPU_5K86, fpus_internal, 133333333, 2.0, 3520, 0x514, 0x514, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16},
{"105 (PR150)", CPU_5K86, fpus_internal, 150000000, 2.5, 3520, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2},
{"116.5 (PR166)", CPU_5K86, fpus_internal, 166666666, 2.5, 3520, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20},
{"133 (PR200)", CPU_5K86, fpus_internal, 200000000, 3.0, 3520, 0x534, 0x534, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24},
{"", 0}
}
}, {
.package = CPU_PKG_SOCKET5_7,
.manufacturer = "AMD",
.name = "K5 (SSA/5)",
.name = "K5 (Model 0)",
.internal_name = "k5_ssa5",
.cpus = (const CPU[]) {
{"75 (PR75)", CPU_K5, fpus_internal, 75000000, 1.5, 3520, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9},
@@ -1649,6 +2161,19 @@ const cpu_family_t cpu_families[] = {
{"100 (PR100)", CPU_K5, fpus_internal, 100000000, 1.5, 3520, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 12},
{"", 0}
}
}, {
.package = CPU_PKG_SOCKET5_7,
.manufacturer = "AMD",
.name = "K5 (Model 1/2/3)",
.internal_name = "k5_5k86",
.cpus = (const CPU[]) {
{"90 (PR120)", CPU_5K86, fpus_internal, 120000000, 2.0, 3520, 0x511, 0x511, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14},
{"100 (PR133)", CPU_5K86, fpus_internal, 133333333, 2.0, 3520, 0x514, 0x514, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16},
{"105 (PR150)", CPU_5K86, fpus_internal, 150000000, 2.5, 3520, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2},
{"116.7 (PR166)", CPU_5K86, fpus_internal, 166666666, 2.5, 3520, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20},
{"133 (PR200)", CPU_5K86, fpus_internal, 200000000, 3.0, 3520, 0x534, 0x534, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24},
{"", 0}
}
},
#endif
{
@@ -1784,12 +2309,12 @@ const cpu_family_t cpu_families[] = {
.name = "Cx6x86",
.internal_name = "cx6x86",
.cpus = (const CPU[]) {
{"P90", CPU_Cx6x86, fpus_internal, 80000000, 2.0, 3520, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8, 8, 6, 6, 10},
{"PR120+", CPU_Cx6x86, fpus_internal, 100000000, 2.0, 3520, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 12},
{"PR133+", CPU_Cx6x86, fpus_internal, 110000000, 2.0, 3520, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 14},
{"PR150+", CPU_Cx6x86, fpus_internal, 120000000, 2.0, 3520, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14},
{"PR166+", CPU_Cx6x86, fpus_internal, 133333333, 2.0, 3520, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16},
{"PR200+", CPU_Cx6x86, fpus_internal, 150000000, 2.0, 3520, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 18},
{"80 (PR90+)", CPU_Cx6x86, fpus_internal, 80000000, 2.0, 3520, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8, 8, 6, 6, 10},
{"100 (PR120+)", CPU_Cx6x86, fpus_internal, 100000000, 2.0, 3520, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 12},
{"110 (PR133+)", CPU_Cx6x86, fpus_internal, 110000000, 2.0, 3520, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 14},
{"120 (PR150+)", CPU_Cx6x86, fpus_internal, 120000000, 2.0, 3520, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14},
{"133 (PR166+)", CPU_Cx6x86, fpus_internal, 133333333, 2.0, 3520, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16},
{"150 (PR200+)", CPU_Cx6x86, fpus_internal, 150000000, 2.0, 3520, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 18},
{"", 0}
}
}, {
@@ -1798,10 +2323,10 @@ const cpu_family_t cpu_families[] = {
.name = "Cx6x86L",
.internal_name = "cx6x86l",
.cpus = (const CPU[]) {
{"PR133+", CPU_Cx6x86L, fpus_internal, 110000000, 2.0, 2800, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 14},
{"PR150+", CPU_Cx6x86L, fpus_internal, 120000000, 2.0, 2800, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14},
{"PR166+", CPU_Cx6x86L, fpus_internal, 133333333, 2.0, 2800, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16},
{"PR200+", CPU_Cx6x86L, fpus_internal, 150000000, 2.0, 2800, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 18},
{"110 (PR133+)", CPU_Cx6x86L, fpus_internal, 110000000, 2.0, 2800, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 14},
{"120 (PR150+)", CPU_Cx6x86L, fpus_internal, 120000000, 2.0, 2800, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14},
{"133 (PR166+)", CPU_Cx6x86L, fpus_internal, 133333333, 2.0, 2800, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16},
{"150 (PR200+)", CPU_Cx6x86L, fpus_internal, 150000000, 2.0, 2800, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 18},
{"", 0}
}
}, {
@@ -1810,10 +2335,10 @@ const cpu_family_t cpu_families[] = {
.name = "Cx6x86MX",
.internal_name = "cx6x86mx",
.cpus = (const CPU[]) {
{"PR166", CPU_Cx6x86MX, fpus_internal, 133333333, 2.0, 2900, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16},
{"PR200", CPU_Cx6x86MX, fpus_internal, 166666666, 2.5, 2900, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20},
{"PR233", CPU_Cx6x86MX, fpus_internal, 187500000, 2.5, 2900, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 45/2},
{"PR266", CPU_Cx6x86MX, fpus_internal, 208333333, 2.5, 2700, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17, 7, 7, 25},
{"133 (PR166)", CPU_Cx6x86MX, fpus_internal, 133333333, 2.0, 2900, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16},
{"166 (PR200)", CPU_Cx6x86MX, fpus_internal, 166666666, 2.5, 2900, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20},
{"187.5 (PR233)", CPU_Cx6x86MX, fpus_internal, 187500000, 2.5, 2900, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 45/2},
{"208.3 (PR266)", CPU_Cx6x86MX, fpus_internal, 208333333, 2.5, 2700, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17, 7, 7, 25},
{"", 0}
}
}, {
@@ -1822,11 +2347,11 @@ const cpu_family_t cpu_families[] = {
.name = "MII",
.internal_name = "mii",
.cpus = (const CPU[]) {
{"PR300", CPU_Cx6x86MX, fpus_internal, 233333333, 3.5, 2900, 0x601, 0x601, 0x0852, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,11,11, 28},
{"PR333", CPU_Cx6x86MX, fpus_internal, 250000000, 3.0, 2900, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 23,23, 9, 9, 30},
{"PR366", CPU_Cx6x86MX, fpus_internal, 250000000, 2.5, 2900, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 23,23, 7, 7, 30},
{"PR400", CPU_Cx6x86MX, fpus_internal, 285000000, 3.0, 2900, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27, 9, 9, 34},
{"PR433", CPU_Cx6x86MX, fpus_internal, 300000000, 3.0, 2900, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27, 9, 9, 36},
{"233 (PR300)", CPU_Cx6x86MX, fpus_internal, 233333333, 3.5, 2900, 0x601, 0x601, 0x0852, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,11,11, 28},
{"250/83 (PR333)", CPU_Cx6x86MX, fpus_internal, 250000000, 3.0, 2900, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 23,23, 9, 9, 30},
{"250/100 (PR366)", CPU_Cx6x86MX, fpus_internal, 250000000, 2.5, 2900, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 23,23, 7, 7, 30},
{"285 (PR400)", CPU_Cx6x86MX, fpus_internal, 285000000, 3.0, 2900, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27, 9, 9, 34},
{"300 (PR433)", CPU_Cx6x86MX, fpus_internal, 300000000, 3.0, 2900, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27, 9, 9, 36},
{"", 0}
}
},

View File

@@ -1,51 +0,0 @@
#ifndef EMU_SF_CONFIG_H
#define EMU_SF_CONFIG_H
#include <stdint.h>
typedef int8_t flag;
typedef uint8_t uint8;
typedef int8_t int8;
typedef uint16_t uint16;
typedef int16_t int16;
typedef uint32_t uint32;
typedef int32_t int32;
typedef uint64_t uint64;
typedef int64_t int64;
/*----------------------------------------------------------------------------
| Each of the following `typedef's defines a type that holds integers
| of _exactly_ the number of bits specified. For instance, for most
| implementation of C, `bits16' and `sbits16' should be `typedef'ed to
| `unsigned short int' and `signed short int' (or `short int'), respectively.
*----------------------------------------------------------------------------*/
typedef uint8_t bits8;
typedef int8_t sbits8;
typedef uint16_t bits16;
typedef int16_t sbits16;
typedef uint32_t bits32;
typedef int32_t sbits32;
typedef uint64_t bits64;
typedef int64_t sbits64;
typedef uint8_t Bit8u;
typedef int8_t Bit8s;
typedef uint16_t Bit16u;
typedef int16_t Bit16s;
typedef uint32_t Bit32u;
typedef int32_t Bit32s;
typedef uint64_t Bit64u;
typedef int64_t Bit64s;
/*----------------------------------------------------------------------------
| The `LIT64' macro takes as its argument a textual integer literal and
| if necessary ``marks'' the literal as having a 64-bit integer type.
| For example, the GNU C Compiler (`gcc') requires that 64-bit literals be
| appended with the letters `LL' standing for `long long', which is `gcc's
| name for the 64-bit integer type. Some compilers may allow `LIT64' to be
| defined as the identity macro: `#define LIT64( a ) a'.
*----------------------------------------------------------------------------*/
#define BX_CONST64(a) a##LL
#define BX_CPP_INLINE static __inline
#endif /*EMU_SF_CONFIG_H*/

View File

@@ -1,496 +0,0 @@
/*============================================================================
This C header file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic
Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*============================================================================
* Adapted for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#ifndef _SOFTFLOAT_COMPARE_H_
#define _SOFTFLOAT_COMPARE_H_
#include "softfloat.h"
// ======= float32 ======= //
typedef int (*float32_compare_method)(float32, float32, struct float_status_t *status);
// 0x00
BX_CPP_INLINE int float32_eq_ordered_quiet(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation == float_relation_equal);
}
// 0x01
BX_CPP_INLINE int float32_lt_ordered_signalling(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_two(a, b, status);
return (relation == float_relation_less);
}
// 0x02
BX_CPP_INLINE int float32_le_ordered_signalling(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_two(a, b, status);
return (relation == float_relation_less) || (relation == float_relation_equal);
}
// 0x03
BX_CPP_INLINE int float32_unordered_quiet(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation == float_relation_unordered);
}
// 0x04
BX_CPP_INLINE int float32_neq_unordered_quiet(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation != float_relation_equal);
}
// 0x05
BX_CPP_INLINE int float32_nlt_unordered_signalling(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_two(a, b, status);
return (relation != float_relation_less);
}
// 0x06
BX_CPP_INLINE int float32_nle_unordered_signalling(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_two(a, b, status);
return (relation != float_relation_less) && (relation != float_relation_equal);
}
// 0x07
BX_CPP_INLINE int float32_ordered_quiet(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation != float_relation_unordered);
}
// 0x08
BX_CPP_INLINE int float32_eq_unordered_quiet(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation == float_relation_equal) || (relation == float_relation_unordered);
}
// 0x09
BX_CPP_INLINE int float32_nge_unordered_signalling(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_two(a, b, status);
return (relation == float_relation_less) || (relation == float_relation_unordered);
}
// 0x0a
BX_CPP_INLINE int float32_ngt_unordered_signalling(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_two(a, b, status);
return (relation != float_relation_greater);
}
// 0x0b
BX_CPP_INLINE int float32_false_quiet(float32 a, float32 b, struct float_status_t *status)
{
float32_compare_quiet(a, b, status);
return 0;
}
// 0x0c
BX_CPP_INLINE int float32_neq_ordered_quiet(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation != float_relation_equal) && (relation != float_relation_unordered);
}
// 0x0d
BX_CPP_INLINE int float32_ge_ordered_signalling(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_two(a, b, status);
return (relation == float_relation_greater) || (relation == float_relation_equal);
}
// 0x0e
BX_CPP_INLINE int float32_gt_ordered_signalling(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_two(a, b, status);
return (relation == float_relation_greater);
}
// 0x0f
BX_CPP_INLINE int float32_true_quiet(float32 a, float32 b, struct float_status_t *status)
{
float32_compare_quiet(a, b, status);
return 1;
}
// 0x10
BX_CPP_INLINE int float32_eq_ordered_signalling(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_two(a, b, status);
return (relation == float_relation_equal);
}
// 0x11
BX_CPP_INLINE int float32_lt_ordered_quiet(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation == float_relation_less);
}
// 0x12
BX_CPP_INLINE int float32_le_ordered_quiet(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation == float_relation_less) || (relation == float_relation_equal);
}
// 0x13
BX_CPP_INLINE int float32_unordered_signalling(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_two(a, b, status);
return (relation == float_relation_unordered);
}
// 0x14
BX_CPP_INLINE int float32_neq_unordered_signalling(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_two(a, b, status);
return (relation != float_relation_equal);
}
// 0x15
BX_CPP_INLINE int float32_nlt_unordered_quiet(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation != float_relation_less);
}
// 0x16
BX_CPP_INLINE int float32_nle_unordered_quiet(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation != float_relation_less) && (relation != float_relation_equal);
}
// 0x17
BX_CPP_INLINE int float32_ordered_signalling(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_two(a, b, status);
return (relation != float_relation_unordered);
}
// 0x18
BX_CPP_INLINE int float32_eq_unordered_signalling(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_two(a, b, status);
return (relation == float_relation_equal) || (relation == float_relation_unordered);
}
// 0x19
BX_CPP_INLINE int float32_nge_unordered_quiet(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation == float_relation_less) || (relation == float_relation_unordered);
}
// 0x1a
BX_CPP_INLINE int float32_ngt_unordered_quiet(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation != float_relation_greater);
}
// 0x1b
BX_CPP_INLINE int float32_false_signalling(float32 a, float32 b, struct float_status_t *status)
{
float32_compare_two(a, b, status);
return 0;
}
// 0x1c
BX_CPP_INLINE int float32_neq_ordered_signalling(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_two(a, b, status);
return (relation != float_relation_equal) && (relation != float_relation_unordered);
}
// 0x1d
BX_CPP_INLINE int float32_ge_ordered_quiet(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation == float_relation_greater) || (relation == float_relation_equal);
}
// 0x1e
BX_CPP_INLINE int float32_gt_ordered_quiet(float32 a, float32 b, struct float_status_t *status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation == float_relation_greater);
}
// 0x1f
BX_CPP_INLINE int float32_true_signalling(float32 a, float32 b, struct float_status_t *status)
{
float32_compare_two(a, b, status);
return 1;
}
// ======= float64 ======= //
typedef int (*float64_compare_method)(float64, float64, struct float_status_t *status);
// 0x00
BX_CPP_INLINE int float64_eq_ordered_quiet(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation == float_relation_equal);
}
// 0x01
BX_CPP_INLINE int float64_lt_ordered_signalling(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_two(a, b, status);
return (relation == float_relation_less);
}
// 0x02
BX_CPP_INLINE int float64_le_ordered_signalling(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_two(a, b, status);
return (relation == float_relation_less) || (relation == float_relation_equal);
}
// 0x03
BX_CPP_INLINE int float64_unordered_quiet(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation == float_relation_unordered);
}
// 0x04
BX_CPP_INLINE int float64_neq_unordered_quiet(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation != float_relation_equal);
}
// 0x05
BX_CPP_INLINE int float64_nlt_unordered_signalling(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_two(a, b, status);
return (relation != float_relation_less);
}
// 0x06
BX_CPP_INLINE int float64_nle_unordered_signalling(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_two(a, b, status);
return (relation != float_relation_less) && (relation != float_relation_equal);
}
// 0x07
BX_CPP_INLINE int float64_ordered_quiet(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation != float_relation_unordered);
}
// 0x08
BX_CPP_INLINE int float64_eq_unordered_quiet(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation == float_relation_equal) || (relation == float_relation_unordered);
}
// 0x09
BX_CPP_INLINE int float64_nge_unordered_signalling(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_two(a, b, status);
return (relation == float_relation_less) || (relation == float_relation_unordered);
}
// 0x0a
BX_CPP_INLINE int float64_ngt_unordered_signalling(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_two(a, b, status);
return (relation != float_relation_greater);
}
// 0x0b
BX_CPP_INLINE int float64_false_quiet(float64 a, float64 b, struct float_status_t *status)
{
float64_compare_quiet(a, b, status);
return 0;
}
// 0x0c
BX_CPP_INLINE int float64_neq_ordered_quiet(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation != float_relation_equal) && (relation != float_relation_unordered);
}
// 0x0d
BX_CPP_INLINE int float64_ge_ordered_signalling(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_two(a, b, status);
return (relation == float_relation_greater) || (relation == float_relation_equal);
}
// 0x0e
BX_CPP_INLINE int float64_gt_ordered_signalling(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_two(a, b, status);
return (relation == float_relation_greater);
}
// 0x0f
BX_CPP_INLINE int float64_true_quiet(float64 a, float64 b, struct float_status_t *status)
{
float64_compare_quiet(a, b, status);
return 1;
}
// 0x10
BX_CPP_INLINE int float64_eq_ordered_signalling(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_two(a, b, status);
return (relation == float_relation_equal);
}
// 0x11
BX_CPP_INLINE int float64_lt_ordered_quiet(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation == float_relation_less);
}
// 0x12
BX_CPP_INLINE int float64_le_ordered_quiet(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation == float_relation_less) || (relation == float_relation_equal);
}
// 0x13
BX_CPP_INLINE int float64_unordered_signalling(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_two(a, b, status);
return (relation == float_relation_unordered);
}
// 0x14
BX_CPP_INLINE int float64_neq_unordered_signalling(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_two(a, b, status);
return (relation != float_relation_equal);
}
// 0x15
BX_CPP_INLINE int float64_nlt_unordered_quiet(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation != float_relation_less);
}
// 0x16
BX_CPP_INLINE int float64_nle_unordered_quiet(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation != float_relation_less) && (relation != float_relation_equal);
}
// 0x17
BX_CPP_INLINE int float64_ordered_signalling(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_two(a, b, status);
return (relation != float_relation_unordered);
}
// 0x18
BX_CPP_INLINE int float64_eq_unordered_signalling(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_two(a, b, status);
return (relation == float_relation_equal) || (relation == float_relation_unordered);
}
// 0x19
BX_CPP_INLINE int float64_nge_unordered_quiet(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation == float_relation_less) || (relation == float_relation_unordered);
}
// 0x1a
BX_CPP_INLINE int float64_ngt_unordered_quiet(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation != float_relation_greater);
}
// 0x1b
BX_CPP_INLINE int float64_false_signalling(float64 a, float64 b, struct float_status_t *status)
{
float64_compare_two(a, b, status);
return 0;
}
// 0x1c
BX_CPP_INLINE int float64_neq_ordered_signalling(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_two(a, b, status);
return (relation != float_relation_equal) && (relation != float_relation_unordered);
}
// 0x1d
BX_CPP_INLINE int float64_ge_ordered_quiet(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation == float_relation_greater) || (relation == float_relation_equal);
}
// 0x1e
BX_CPP_INLINE int float64_gt_ordered_quiet(float64 a, float64 b, struct float_status_t *status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation == float_relation_greater);
}
// 0x1f
BX_CPP_INLINE int float64_true_signalling(float64 a, float64 b, struct float_status_t *status)
{
float64_compare_two(a, b, status);
return 1;
}
#endif

View File

@@ -1,686 +0,0 @@
/*============================================================================
This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal notice) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*============================================================================
* Adapted for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#ifndef _SOFTFLOAT_MACROS_H_
#define _SOFTFLOAT_MACROS_H_
/*----------------------------------------------------------------------------
| Shifts `a' right by the number of bits given in `count'. If any nonzero
| bits are shifted off, they are ``jammed'' into the least significant bit of
| the result by setting the least significant bit to 1. The value of `count'
| can be arbitrarily large; in particular, if `count' is greater than 16, the
| result will be either 0 or 1, depending on whether `a' is zero or nonzero.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit16u shift16RightJamming(Bit16u a, int count)
{
Bit16u z;
if (count == 0) {
z = a;
}
else if (count < 16) {
z = (a>>count) | ((a<<((-count) & 15)) != 0);
}
else {
z = (a != 0);
}
return z;
}
/*----------------------------------------------------------------------------
| Shifts `a' right by the number of bits given in `count'. If any nonzero
| bits are shifted off, they are ``jammed'' into the least significant bit of
| the result by setting the least significant bit to 1. The value of `count'
| can be arbitrarily large; in particular, if `count' is greater than 32, the
| result will be either 0 or 1, depending on whether `a' is zero or nonzero.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit32u shift32RightJamming(Bit32u a, int count)
{
Bit32u z;
if (count == 0) {
z = a;
}
else if (count < 32) {
z = (a>>count) | ((a<<((-count) & 31)) != 0);
}
else {
z = (a != 0);
}
return z;
}
/*----------------------------------------------------------------------------
| Shifts `a' right by the number of bits given in `count'. If any nonzero
| bits are shifted off, they are ``jammed'' into the least significant bit of
| the result by setting the least significant bit to 1. The value of `count'
| can be arbitrarily large; in particular, if `count' is greater than 64, the
| result will be either 0 or 1, depending on whether `a' is zero or nonzero.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit64u shift64RightJamming(Bit64u a, int count)
{
Bit64u z;
if (count == 0) {
z = a;
}
else if (count < 64) {
z = (a>>count) | ((a << ((-count) & 63)) != 0);
}
else {
z = (a != 0);
}
return z;
}
/*----------------------------------------------------------------------------
| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by 64
| _plus_ the number of bits given in `count'. The shifted result is at most
| 64 nonzero bits; this is stored at the location pointed to by `z0Ptr'. The
| bits shifted off form a second 64-bit result as follows: The _last_ bit
| shifted off is the most-significant bit of the extra result, and the other
| 63 bits of the extra result are all zero if and only if _all_but_the_last_
| bits shifted off were all zero. This extra result is stored in the location
| pointed to by `z1Ptr'. The value of `count' can be arbitrarily large.
| (This routine makes more sense if `a0' and `a1' are considered to form
| a fixed-point value with binary point between `a0' and `a1'. This fixed-
| point value is shifted right by the number of bits given in `count', and
| the integer part of the result is returned at the location pointed to by
| `z0Ptr'. The fractional part of the result may be slightly corrupted as
| described above, and is returned at the location pointed to by `z1Ptr'.)
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void shift64ExtraRightJamming(Bit64u a0, Bit64u a1, int count, Bit64u *z0Ptr, Bit64u *z1Ptr)
{
Bit64u z0, z1;
int negCount = (-count) & 63;
if (count == 0) {
z1 = a1;
z0 = a0;
}
else if (count < 64) {
z1 = (a0<<negCount) | (a1 != 0);
z0 = a0>>count;
}
else {
if (count == 64) {
z1 = a0 | (a1 != 0);
}
else {
z1 = ((a0 | a1) != 0);
}
z0 = 0;
}
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Adds the 128-bit value formed by concatenating `a0' and `a1' to the 128-bit
| value formed by concatenating `b0' and `b1'. Addition is modulo 2^128, so
| any carry out is lost. The result is broken into two 64-bit pieces which
| are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void add128(Bit64u a0, Bit64u a1, Bit64u b0, Bit64u b1, Bit64u *z0Ptr, Bit64u *z1Ptr)
{
Bit64u z1 = a1 + b1;
*z1Ptr = z1;
*z0Ptr = a0 + b0 + (z1 < a1);
}
/*----------------------------------------------------------------------------
| Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the
| 128-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo
| 2^128, so any borrow out (carry out) is lost. The result is broken into two
| 64-bit pieces which are stored at the locations pointed to by `z0Ptr' and
| `z1Ptr'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void
sub128(Bit64u a0, Bit64u a1, Bit64u b0, Bit64u b1, Bit64u *z0Ptr, Bit64u *z1Ptr)
{
*z1Ptr = a1 - b1;
*z0Ptr = a0 - b0 - (a1 < b1);
}
/*----------------------------------------------------------------------------
| Multiplies `a' by `b' to obtain a 128-bit product. The product is broken
| into two 64-bit pieces which are stored at the locations pointed to by
| `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void mul64To128(Bit64u a, Bit64u b, Bit64u *z0Ptr, Bit64u *z1Ptr)
{
Bit32u aHigh, aLow, bHigh, bLow;
Bit64u z0, zMiddleA, zMiddleB, z1;
aLow = (Bit32u) a;
aHigh = (Bit32u)(a>>32);
bLow = (Bit32u) b;
bHigh = (Bit32u)(b>>32);
z1 = ((Bit64u) aLow) * bLow;
zMiddleA = ((Bit64u) aLow) * bHigh;
zMiddleB = ((Bit64u) aHigh) * bLow;
z0 = ((Bit64u) aHigh) * bHigh;
zMiddleA += zMiddleB;
z0 += (((Bit64u) (zMiddleA < zMiddleB))<<32) + (zMiddleA>>32);
zMiddleA <<= 32;
z1 += zMiddleA;
z0 += (z1 < zMiddleA);
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Returns an approximation to the 64-bit integer quotient obtained by dividing
| `b' into the 128-bit value formed by concatenating `a0' and `a1'. The
| divisor `b' must be at least 2^63. If q is the exact quotient truncated
| toward zero, the approximation returned lies between q and q + 2 inclusive.
| If the exact quotient q is larger than 64 bits, the maximum positive 64-bit
| unsigned integer is returned.
*----------------------------------------------------------------------------*/
#ifdef USE_estimateDiv128To64
static Bit64u estimateDiv128To64(Bit64u a0, Bit64u a1, Bit64u b)
{
Bit64u b0, b1;
Bit64u rem0, rem1, term0, term1;
Bit64u z;
if (b <= a0) return BX_CONST64(0xFFFFFFFFFFFFFFFF);
b0 = b>>32;
z = (b0<<32 <= a0) ? BX_CONST64(0xFFFFFFFF00000000) : (a0 / b0)<<32;
mul64To128(b, z, &term0, &term1);
sub128(a0, a1, term0, term1, &rem0, &rem1);
while (((Bit64s) rem0) < 0) {
z -= BX_CONST64(0x100000000);
b1 = b<<32;
add128(rem0, rem1, b0, b1, &rem0, &rem1);
}
rem0 = (rem0<<32) | (rem1>>32);
z |= (b0<<32 <= rem0) ? 0xFFFFFFFF : rem0 / b0;
return z;
}
#endif
/*----------------------------------------------------------------------------
| Returns an approximation to the square root of the 32-bit significand given
| by `a'. Considered as an integer, `a' must be at least 2^31. If bit 0 of
| `aExp' (the least significant bit) is 1, the integer returned approximates
| 2^31*sqrt(`a'/2^31), where `a' is considered an integer. If bit 0 of `aExp'
| is 0, the integer returned approximates 2^31*sqrt(`a'/2^30). In either
| case, the approximation returned lies strictly within +/-2 of the exact
| value.
*----------------------------------------------------------------------------*/
#ifdef USE_estimateSqrt32
static Bit32u estimateSqrt32(Bit16s aExp, Bit32u a)
{
static const Bit16u sqrtOddAdjustments[] = {
0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0,
0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67
};
static const Bit16u sqrtEvenAdjustments[] = {
0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E,
0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002
};
Bit32u z;
int index = (a>>27) & 15;
if (aExp & 1) {
z = 0x4000 + (a>>17) - sqrtOddAdjustments[index];
z = ((a / z)<<14) + (z<<15);
a >>= 1;
}
else {
z = 0x8000 + (a>>17) - sqrtEvenAdjustments[index];
z = a / z + z;
z = (0x20000 <= z) ? 0xFFFF8000 : (z<<15);
if (z <= a) return (Bit32u) (((Bit32s) a)>>1);
}
return ((Bit32u) ((((Bit64u) a)<<31) / z)) + (z>>1);
}
#endif
static const int countLeadingZeros8[] = {
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
#ifdef FLOAT16
/*----------------------------------------------------------------------------
| Returns the number of leading 0 bits before the most-significant 1 bit of
| `a'. If `a' is zero, 16 is returned.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int countLeadingZeros16(Bit16u a)
{
int shiftCount = 0;
if (a < 0x100) {
shiftCount += 8;
a <<= 8;
}
shiftCount += countLeadingZeros8[a>>8];
return shiftCount;
}
#endif
/*----------------------------------------------------------------------------
| Returns the number of leading 0 bits before the most-significant 1 bit of
| `a'. If `a' is zero, 32 is returned.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int countLeadingZeros32(Bit32u a)
{
int shiftCount = 0;
if (a < 0x10000) {
shiftCount += 16;
a <<= 16;
}
if (a < 0x1000000) {
shiftCount += 8;
a <<= 8;
}
shiftCount += countLeadingZeros8[a>>24];
return shiftCount;
}
/*----------------------------------------------------------------------------
| Returns the number of leading 0 bits before the most-significant 1 bit of
| `a'. If `a' is zero, 64 is returned.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int countLeadingZeros64(Bit64u a)
{
int shiftCount = 0;
if (a < BX_CONST64(0x100000000)) {
shiftCount += 32;
}
else {
a >>= 32;
}
shiftCount += countLeadingZeros32((Bit32u)(a));
return shiftCount;
}
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
| number of bits given in `count'. Any bits shifted off are lost. The value
| of `count' can be arbitrarily large; in particular, if `count' is greater
| than 128, the result will be 0. The result is broken into two 64-bit pieces
| which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void shift128Right(Bit64u a0, Bit64u a1, int count, Bit64u *z0Ptr, Bit64u *z1Ptr)
{
Bit64u z0, z1;
int negCount = (-count) & 63;
if (count == 0) {
z1 = a1;
z0 = a0;
}
else if (count < 64) {
z1 = (a0<<negCount) | (a1>>count);
z0 = a0>>count;
}
else {
z1 = (count < 128) ? (a0>>(count & 63)) : 0;
z0 = 0;
}
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
| number of bits given in `count'. If any nonzero bits are shifted off, they
| are ``jammed'' into the least significant bit of the result by setting the
| least significant bit to 1. The value of `count' can be arbitrarily large;
| in particular, if `count' is greater than 128, the result will be either
| 0 or 1, depending on whether the concatenation of `a0' and `a1' is zero or
| nonzero. The result is broken into two 64-bit pieces which are stored at
| the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void shift128RightJamming(Bit64u a0, Bit64u a1, int count, Bit64u *z0Ptr, Bit64u *z1Ptr)
{
Bit64u z0, z1;
int negCount = (-count) & 63;
if (count == 0) {
z1 = a1;
z0 = a0;
}
else if (count < 64) {
z1 = (a0<<negCount) | (a1>>count) | ((a1<<negCount) != 0);
z0 = a0>>count;
}
else {
if (count == 64) {
z1 = a0 | (a1 != 0);
}
else if (count < 128) {
z1 = (a0>>(count & 63)) | (((a0<<negCount) | a1) != 0);
}
else {
z1 = ((a0 | a1) != 0);
}
z0 = 0;
}
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the
| number of bits given in `count'. Any bits shifted off are lost. The value
| of `count' must be less than 64. The result is broken into two 64-bit
| pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void shortShift128Left(Bit64u a0, Bit64u a1, int count, Bit64u *z0Ptr, Bit64u *z1Ptr)
{
*z1Ptr = a1<<count;
*z0Ptr = (count == 0) ? a0 : (a0<<count) | (a1>>((-count) & 63));
}
/*----------------------------------------------------------------------------
| Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the
| 192-bit value formed by concatenating `b0', `b1', and `b2'. Addition is
| modulo 2^192, so any carry out is lost. The result is broken into three
| 64-bit pieces which are stored at the locations pointed to by `z0Ptr',
| `z1Ptr', and `z2Ptr'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void add192(
Bit64u a0,
Bit64u a1,
Bit64u a2,
Bit64u b0,
Bit64u b1,
Bit64u b2,
Bit64u *z0Ptr,
Bit64u *z1Ptr,
Bit64u *z2Ptr
)
{
Bit64u z0, z1, z2;
unsigned carry0, carry1;
z2 = a2 + b2;
carry1 = (z2 < a2);
z1 = a1 + b1;
carry0 = (z1 < a1);
z0 = a0 + b0;
z1 += carry1;
z0 += (z1 < carry1);
z0 += carry0;
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Subtracts the 192-bit value formed by concatenating `b0', `b1', and `b2'
| from the 192-bit value formed by concatenating `a0', `a1', and `a2'.
| Subtraction is modulo 2^192, so any borrow out (carry out) is lost. The
| result is broken into three 64-bit pieces which are stored at the locations
| pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void sub192(
Bit64u a0,
Bit64u a1,
Bit64u a2,
Bit64u b0,
Bit64u b1,
Bit64u b2,
Bit64u *z0Ptr,
Bit64u *z1Ptr,
Bit64u *z2Ptr
)
{
Bit64u z0, z1, z2;
unsigned borrow0, borrow1;
z2 = a2 - b2;
borrow1 = (a2 < b2);
z1 = a1 - b1;
borrow0 = (a1 < b1);
z0 = a0 - b0;
z0 -= (z1 < borrow1);
z1 -= borrow1;
z0 -= borrow0;
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1'
| is equal to the 128-bit value formed by concatenating `b0' and `b1'.
| Otherwise, returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int eq128(Bit64u a0, Bit64u a1, Bit64u b0, Bit64u b1)
{
return (a0 == b0) && (a1 == b1);
}
/*----------------------------------------------------------------------------
| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
| than or equal to the 128-bit value formed by concatenating `b0' and `b1'.
| Otherwise, returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int le128(Bit64u a0, Bit64u a1, Bit64u b0, Bit64u b1)
{
return (a0 < b0) || ((a0 == b0) && (a1 <= b1));
}
/*----------------------------------------------------------------------------
| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
| than the 128-bit value formed by concatenating `b0' and `b1'. Otherwise,
| returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int lt128(Bit64u a0, Bit64u a1, Bit64u b0, Bit64u b1)
{
return (a0 < b0) || ((a0 == b0) && (a1 < b1));
}
#endif /* FLOATX80 */
/*----------------------------------------------------------------------------
| Multiplies the 128-bit value formed by concatenating `a0' and `a1' by
| `b' to obtain a 192-bit product. The product is broken into three 64-bit
| pieces which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and
| `z2Ptr'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void mul128By64To192(
Bit64u a0,
Bit64u a1,
Bit64u b,
Bit64u *z0Ptr,
Bit64u *z1Ptr,
Bit64u *z2Ptr
)
{
Bit64u z0, z1, z2, more1;
mul64To128(a1, b, &z1, &z2);
mul64To128(a0, b, &z0, &more1);
add128(z0, more1, 0, z1, &z0, &z1);
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
#ifdef FLOAT128
/*----------------------------------------------------------------------------
| Multiplies the 128-bit value formed by concatenating `a0' and `a1' to the
| 128-bit value formed by concatenating `b0' and `b1' to obtain a 256-bit
| product. The product is broken into four 64-bit pieces which are stored at
| the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void mul128To256(
Bit64u a0,
Bit64u a1,
Bit64u b0,
Bit64u b1,
Bit64u *z0Ptr,
Bit64u *z1Ptr,
Bit64u *z2Ptr,
Bit64u *z3Ptr
)
{
Bit64u z0, z1, z2, z3;
Bit64u more1, more2;
mul64To128(a1, b1, &z2, &z3);
mul64To128(a1, b0, &z1, &more2);
add128(z1, more2, 0, z2, &z1, &z2);
mul64To128(a0, b0, &z0, &more1);
add128(z0, more1, 0, z1, &z0, &z1);
mul64To128(a0, b1, &more1, &more2);
add128(more1, more2, 0, z2, &more1, &z2);
add128(z0, z1, 0, more1, &z0, &z1);
*z3Ptr = z3;
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' right
| by 64 _plus_ the number of bits given in `count'. The shifted result is
| at most 128 nonzero bits; these are broken into two 64-bit pieces which are
| stored at the locations pointed to by `z0Ptr' and `z1Ptr'. The bits shifted
| off form a third 64-bit result as follows: The _last_ bit shifted off is
| the most-significant bit of the extra result, and the other 63 bits of the
| extra result are all zero if and only if _all_but_the_last_ bits shifted off
| were all zero. This extra result is stored in the location pointed to by
| `z2Ptr'. The value of `count' can be arbitrarily large.
| (This routine makes more sense if `a0', `a1', and `a2' are considered
| to form a fixed-point value with binary point between `a1' and `a2'. This
| fixed-point value is shifted right by the number of bits given in `count',
| and the integer part of the result is returned at the locations pointed to
| by `z0Ptr' and `z1Ptr'. The fractional part of the result may be slightly
| corrupted as described above, and is returned at the location pointed to by
| `z2Ptr'.)
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void shift128ExtraRightJamming(
Bit64u a0,
Bit64u a1,
Bit64u a2,
int count,
Bit64u *z0Ptr,
Bit64u *z1Ptr,
Bit64u *z2Ptr
)
{
Bit64u z0, z1, z2;
int negCount = (-count) & 63;
if (count == 0) {
z2 = a2;
z1 = a1;
z0 = a0;
}
else {
if (count < 64) {
z2 = a1<<negCount;
z1 = (a0<<negCount) | (a1>>count);
z0 = a0>>count;
}
else {
if (count == 64) {
z2 = a1;
z1 = a0;
}
else {
a2 |= a1;
if (count < 128) {
z2 = a0<<negCount;
z1 = a0>>(count & 63);
}
else {
z2 = (count == 128) ? a0 : (a0 != 0);
z1 = 0;
}
}
z0 = 0;
}
z2 |= (a2 != 0);
}
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
#endif /* FLOAT128 */
#endif

View File

@@ -1,558 +0,0 @@
/*============================================================================
This C source file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic
Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*============================================================================
* This code is based on QEMU patch by Peter Maydell
* Adapted for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#include "softfloat.h"
#include "softfloat-round-pack.h"
/*----------------------------------------------------------------------------
| Primitive arithmetic functions, including multi-word arithmetic, and
| division and square root approximations. (Can be specialized to target
| if desired).
*----------------------------------------------------------------------------*/
#include "softfloat-macros.h"
/*----------------------------------------------------------------------------
| Functions and definitions to determine: (1) whether tininess for underflow
| is detected before or after rounding by default, (2) what (if anything)
| happens when exceptions are raised, (3) how signaling NaNs are distinguished
| from quiet NaNs, (4) the default generated quiet NaNs, and (5) how NaNs
| are propagated from function inputs to output. These details are target-
| specific.
*----------------------------------------------------------------------------*/
#include "softfloat-specialize.h"
/*----------------------------------------------------------------------------
| Takes three single-precision floating-point values `a', `b' and `c', one of
| which is a NaN, and returns the appropriate NaN result. If any of `a',
| `b' or `c' is a signaling NaN, the invalid exception is raised.
| The input infzero indicates whether a*b was 0*inf or inf*0 (in which case
| obviously c is a NaN, and whether to propagate c or some other NaN is
| implementation defined).
*----------------------------------------------------------------------------*/
static float32 propagateFloat32MulAddNaN(float32 a, float32 b, float32 c, struct float_status_t *status)
{
int aIsNaN = float32_is_nan(a);
int bIsNaN = float32_is_nan(b);
int aIsSignalingNaN = float32_is_signaling_nan(a);
int bIsSignalingNaN = float32_is_signaling_nan(b);
int cIsSignalingNaN = float32_is_signaling_nan(c);
a |= 0x00400000;
b |= 0x00400000;
c |= 0x00400000;
if (aIsSignalingNaN | bIsSignalingNaN | cIsSignalingNaN)
float_raise(status, float_flag_invalid);
// operate according to float_first_operand_nan mode
if (aIsSignalingNaN | aIsNaN) {
return a;
}
else {
return (bIsSignalingNaN | bIsNaN) ? b : c;
}
}
/*----------------------------------------------------------------------------
| Takes three double-precision floating-point values `a', `b' and `c', one of
| which is a NaN, and returns the appropriate NaN result. If any of `a',
| `b' or `c' is a signaling NaN, the invalid exception is raised.
| The input infzero indicates whether a*b was 0*inf or inf*0 (in which case
| obviously c is a NaN, and whether to propagate c or some other NaN is
| implementation defined).
*----------------------------------------------------------------------------*/
static float64 propagateFloat64MulAddNaN(float64 a, float64 b, float64 c, struct float_status_t *status)
{
int aIsNaN = float64_is_nan(a);
int bIsNaN = float64_is_nan(b);
int aIsSignalingNaN = float64_is_signaling_nan(a);
int bIsSignalingNaN = float64_is_signaling_nan(b);
int cIsSignalingNaN = float64_is_signaling_nan(c);
a |= BX_CONST64(0x0008000000000000);
b |= BX_CONST64(0x0008000000000000);
c |= BX_CONST64(0x0008000000000000);
if (aIsSignalingNaN | bIsSignalingNaN | cIsSignalingNaN)
float_raise(status, float_flag_invalid);
// operate according to float_first_operand_nan mode
if (aIsSignalingNaN | aIsNaN) {
return a;
}
else {
return (bIsSignalingNaN | bIsNaN) ? b : c;
}
}
/*----------------------------------------------------------------------------
| Returns the result of multiplying the single-precision floating-point values
| `a' and `b' then adding 'c', with no intermediate rounding step after the
| multiplication. The operation is performed according to the IEC/IEEE
| Standard for Binary Floating-Point Arithmetic 754-2008.
| The flags argument allows the caller to select negation of the
| addend, the intermediate product, or the final result. (The difference
| between this and having the caller do a separate negation is that negating
| externally will flip the sign bit on NaNs.)
*----------------------------------------------------------------------------*/
float32 float32_muladd(float32 a, float32 b, float32 c, int flags, struct float_status_t *status)
{
int aSign, bSign, cSign, zSign;
Bit16s aExp, bExp, cExp, pExp, zExp;
Bit32u aSig, bSig, cSig;
int pInf, pZero, pSign;
Bit64u pSig64, cSig64, zSig64;
Bit32u pSig;
int shiftcount;
aSig = extractFloat32Frac(a);
aExp = extractFloat32Exp(a);
aSign = extractFloat32Sign(a);
bSig = extractFloat32Frac(b);
bExp = extractFloat32Exp(b);
bSign = extractFloat32Sign(b);
cSig = extractFloat32Frac(c);
cExp = extractFloat32Exp(c);
cSign = extractFloat32Sign(c);
/* It is implementation-defined whether the cases of (0,inf,qnan)
* and (inf,0,qnan) raise InvalidOperation or not (and what QNaN
* they return if they do), so we have to hand this information
* off to the target-specific pick-a-NaN routine.
*/
if (((aExp == 0xff) && aSig) ||
((bExp == 0xff) && bSig) ||
((cExp == 0xff) && cSig)) {
return propagateFloat32MulAddNaN(a, b, c, status);
}
if (get_denormals_are_zeros(status)) {
if (aExp == 0) aSig = 0;
if (bExp == 0) bSig = 0;
if (cExp == 0) cSig = 0;
}
int infzero = ((aExp == 0 && aSig == 0 && bExp == 0xff && bSig == 0) ||
(aExp == 0xff && aSig == 0 && bExp == 0 && bSig == 0));
if (infzero) {
float_raise(status, float_flag_invalid);
return float32_default_nan;
}
if (flags & float_muladd_negate_c) {
cSign ^= 1;
}
/* Work out the sign and type of the product */
pSign = aSign ^ bSign;
if (flags & float_muladd_negate_product) {
pSign ^= 1;
}
pInf = (aExp == 0xff) || (bExp == 0xff);
pZero = ((aExp | aSig) == 0) || ((bExp | bSig) == 0);
if (cExp == 0xff) {
if (pInf && (pSign ^ cSign)) {
/* addition of opposite-signed infinities => InvalidOperation */
float_raise(status, float_flag_invalid);
return float32_default_nan;
}
/* Otherwise generate an infinity of the same sign */
if ((aSig && aExp == 0) || (bSig && bExp == 0)) {
float_raise(status, float_flag_denormal);
}
return packFloat32(cSign, 0xff, 0);
}
if (pInf) {
if ((aSig && aExp == 0) || (bSig && bExp == 0) || (cSig && cExp == 0)) {
float_raise(status, float_flag_denormal);
}
return packFloat32(pSign, 0xff, 0);
}
if (pZero) {
if (cExp == 0) {
if (cSig == 0) {
/* Adding two exact zeroes */
if (pSign == cSign) {
zSign = pSign;
} else if (get_float_rounding_mode(status) == float_round_down) {
zSign = 1;
} else {
zSign = 0;
}
return packFloat32(zSign, 0, 0);
}
/* Exact zero plus a denormal */
float_raise(status, float_flag_denormal);
if (get_flush_underflow_to_zero(status)) {
float_raise(status, float_flag_underflow | float_flag_inexact);
return packFloat32(cSign, 0, 0);
}
}
/* Zero plus something non-zero */
return packFloat32(cSign, cExp, cSig);
}
if (aExp == 0) {
float_raise(status, float_flag_denormal);
normalizeFloat32Subnormal(aSig, &aExp, &aSig);
}
if (bExp == 0) {
float_raise(status, float_flag_denormal);
normalizeFloat32Subnormal(bSig, &bExp, &bSig);
}
/* Calculate the actual result a * b + c */
/* Multiply first; this is easy. */
/* NB: we subtract 0x7e where float32_mul() subtracts 0x7f
* because we want the true exponent, not the "one-less-than"
* flavour that roundAndPackFloat32() takes.
*/
pExp = aExp + bExp - 0x7e;
aSig = (aSig | 0x00800000) << 7;
bSig = (bSig | 0x00800000) << 8;
pSig64 = (Bit64u)aSig * bSig;
if ((Bit64s)(pSig64 << 1) >= 0) {
pSig64 <<= 1;
pExp--;
}
zSign = pSign;
/* Now pSig64 is the significand of the multiply, with the explicit bit in
* position 62.
*/
if (cExp == 0) {
if (!cSig) {
/* Throw out the special case of c being an exact zero now */
pSig = (Bit32u) shift64RightJamming(pSig64, 32);
return roundAndPackFloat32(zSign, pExp - 1, pSig, status);
}
float_raise(status, float_flag_denormal);
normalizeFloat32Subnormal(cSig, &cExp, &cSig);
}
cSig64 = (Bit64u)cSig << 39;
cSig64 |= BX_CONST64(0x4000000000000000);
int expDiff = pExp - cExp;
if (pSign == cSign) {
/* Addition */
if (expDiff > 0) {
/* scale c to match p */
cSig64 = shift64RightJamming(cSig64, expDiff);
zExp = pExp;
} else if (expDiff < 0) {
/* scale p to match c */
pSig64 = shift64RightJamming(pSig64, -expDiff);
zExp = cExp;
} else {
/* no scaling needed */
zExp = cExp;
}
/* Add significands and make sure explicit bit ends up in posn 62 */
zSig64 = pSig64 + cSig64;
if ((Bit64s)zSig64 < 0) {
zSig64 = shift64RightJamming(zSig64, 1);
} else {
zExp--;
}
zSig64 = shift64RightJamming(zSig64, 32);
return roundAndPackFloat32(zSign, zExp, zSig64, status);
} else {
/* Subtraction */
if (expDiff > 0) {
cSig64 = shift64RightJamming(cSig64, expDiff);
zSig64 = pSig64 - cSig64;
zExp = pExp;
} else if (expDiff < 0) {
pSig64 = shift64RightJamming(pSig64, -expDiff);
zSig64 = cSig64 - pSig64;
zExp = cExp;
zSign ^= 1;
} else {
zExp = pExp;
if (cSig64 < pSig64) {
zSig64 = pSig64 - cSig64;
} else if (pSig64 < cSig64) {
zSig64 = cSig64 - pSig64;
zSign ^= 1;
} else {
/* Exact zero */
return packFloat32(get_float_rounding_mode(status) == float_round_down, 0, 0);
}
}
--zExp;
/* Do the equivalent of normalizeRoundAndPackFloat32() but
* starting with the significand in a Bit64u.
*/
shiftcount = countLeadingZeros64(zSig64) - 1;
zSig64 <<= shiftcount;
zExp -= shiftcount;
zSig64 = shift64RightJamming(zSig64, 32);
return roundAndPackFloat32(zSign, zExp, zSig64, status);
}
}
/*----------------------------------------------------------------------------
| Returns the result of multiplying the double-precision floating-point values
| `a' and `b' then adding 'c', with no intermediate rounding step after the
| multiplication. The operation is performed according to the IEC/IEEE
| Standard for Binary Floating-Point Arithmetic 754-2008.
| The flags argument allows the caller to select negation of the
| addend, the intermediate product, or the final result. (The difference
| between this and having the caller do a separate negation is that negating
| externally will flip the sign bit on NaNs.)
*----------------------------------------------------------------------------*/
float64 float64_muladd(float64 a, float64 b, float64 c, int flags, struct float_status_t *status)
{
int aSign, bSign, cSign, zSign;
Bit16s aExp, bExp, cExp, pExp, zExp;
Bit64u aSig, bSig, cSig;
int pInf, pZero, pSign;
Bit64u pSig0, pSig1, cSig0, cSig1, zSig0, zSig1;
int shiftcount;
aSig = extractFloat64Frac(a);
aExp = extractFloat64Exp(a);
aSign = extractFloat64Sign(a);
bSig = extractFloat64Frac(b);
bExp = extractFloat64Exp(b);
bSign = extractFloat64Sign(b);
cSig = extractFloat64Frac(c);
cExp = extractFloat64Exp(c);
cSign = extractFloat64Sign(c);
/* It is implementation-defined whether the cases of (0,inf,qnan)
* and (inf,0,qnan) raise InvalidOperation or not (and what QNaN
* they return if they do), so we have to hand this information
* off to the target-specific pick-a-NaN routine.
*/
if (((aExp == 0x7ff) && aSig) ||
((bExp == 0x7ff) && bSig) ||
((cExp == 0x7ff) && cSig)) {
return propagateFloat64MulAddNaN(a, b, c, status);
}
if (get_denormals_are_zeros(status)) {
if (aExp == 0) aSig = 0;
if (bExp == 0) bSig = 0;
if (cExp == 0) cSig = 0;
}
int infzero = ((aExp == 0 && aSig == 0 && bExp == 0x7ff && bSig == 0) ||
(aExp == 0x7ff && aSig == 0 && bExp == 0 && bSig == 0));
if (infzero) {
float_raise(status, float_flag_invalid);
return float64_default_nan;
}
if (flags & float_muladd_negate_c) {
cSign ^= 1;
}
/* Work out the sign and type of the product */
pSign = aSign ^ bSign;
if (flags & float_muladd_negate_product) {
pSign ^= 1;
}
pInf = (aExp == 0x7ff) || (bExp == 0x7ff);
pZero = ((aExp | aSig) == 0) || ((bExp | bSig) == 0);
if (cExp == 0x7ff) {
if (pInf && (pSign ^ cSign)) {
/* addition of opposite-signed infinities => InvalidOperation */
float_raise(status, float_flag_invalid);
return float64_default_nan;
}
/* Otherwise generate an infinity of the same sign */
if ((aSig && aExp == 0) || (bSig && bExp == 0)) {
float_raise(status, float_flag_denormal);
}
return packFloat64(cSign, 0x7ff, 0);
}
if (pInf) {
if ((aSig && aExp == 0) || (bSig && bExp == 0) || (cSig && cExp == 0)) {
float_raise(status, float_flag_denormal);
}
return packFloat64(pSign, 0x7ff, 0);
}
if (pZero) {
if (cExp == 0) {
if (cSig == 0) {
/* Adding two exact zeroes */
if (pSign == cSign) {
zSign = pSign;
} else if (get_float_rounding_mode(status) == float_round_down) {
zSign = 1;
} else {
zSign = 0;
}
return packFloat64(zSign, 0, 0);
}
/* Exact zero plus a denormal */
float_raise(status, float_flag_denormal);
if (get_flush_underflow_to_zero(status)) {
float_raise(status, float_flag_underflow | float_flag_inexact);
return packFloat64(cSign, 0, 0);
}
}
/* Zero plus something non-zero */
return packFloat64(cSign, cExp, cSig);
}
if (aExp == 0) {
float_raise(status, float_flag_denormal);
normalizeFloat64Subnormal(aSig, &aExp, &aSig);
}
if (bExp == 0) {
float_raise(status, float_flag_denormal);
normalizeFloat64Subnormal(bSig, &bExp, &bSig);
}
/* Calculate the actual result a * b + c */
/* Multiply first; this is easy. */
/* NB: we subtract 0x3fe where float64_mul() subtracts 0x3ff
* because we want the true exponent, not the "one-less-than"
* flavour that roundAndPackFloat64() takes.
*/
pExp = aExp + bExp - 0x3fe;
aSig = (aSig | BX_CONST64(0x0010000000000000))<<10;
bSig = (bSig | BX_CONST64(0x0010000000000000))<<11;
mul64To128(aSig, bSig, &pSig0, &pSig1);
if ((Bit64s)(pSig0 << 1) >= 0) {
shortShift128Left(pSig0, pSig1, 1, &pSig0, &pSig1);
pExp--;
}
zSign = pSign;
/* Now [pSig0:pSig1] is the significand of the multiply, with the explicit
* bit in position 126.
*/
if (cExp == 0) {
if (!cSig) {
/* Throw out the special case of c being an exact zero now */
shift128RightJamming(pSig0, pSig1, 64, &pSig0, &pSig1);
return roundAndPackFloat64(zSign, pExp - 1, pSig1, status);
}
float_raise(status, float_flag_denormal);
normalizeFloat64Subnormal(cSig, &cExp, &cSig);
}
cSig0 = cSig << 10;
cSig1 = 0;
cSig0 |= BX_CONST64(0x4000000000000000);
int expDiff = pExp - cExp;
if (pSign == cSign) {
/* Addition */
if (expDiff > 0) {
/* scale c to match p */
shift128RightJamming(cSig0, cSig1, expDiff, &cSig0, &cSig1);
zExp = pExp;
} else if (expDiff < 0) {
/* scale p to match c */
shift128RightJamming(pSig0, pSig1, -expDiff, &pSig0, &pSig1);
zExp = cExp;
} else {
/* no scaling needed */
zExp = cExp;
}
/* Add significands and make sure explicit bit ends up in posn 126 */
add128(pSig0, pSig1, cSig0, cSig1, &zSig0, &zSig1);
if ((Bit64s)zSig0 < 0) {
shift128RightJamming(zSig0, zSig1, 1, &zSig0, &zSig1);
} else {
zExp--;
}
shift128RightJamming(zSig0, zSig1, 64, &zSig0, &zSig1);
return roundAndPackFloat64(zSign, zExp, zSig1, status);
} else {
/* Subtraction */
if (expDiff > 0) {
shift128RightJamming(cSig0, cSig1, expDiff, &cSig0, &cSig1);
sub128(pSig0, pSig1, cSig0, cSig1, &zSig0, &zSig1);
zExp = pExp;
} else if (expDiff < 0) {
shift128RightJamming(pSig0, pSig1, -expDiff, &pSig0, &pSig1);
sub128(cSig0, cSig1, pSig0, pSig1, &zSig0, &zSig1);
zExp = cExp;
zSign ^= 1;
} else {
zExp = pExp;
if (lt128(cSig0, cSig1, pSig0, pSig1)) {
sub128(pSig0, pSig1, cSig0, cSig1, &zSig0, &zSig1);
} else if (lt128(pSig0, pSig1, cSig0, cSig1)) {
sub128(cSig0, cSig1, pSig0, pSig1, &zSig0, &zSig1);
zSign ^= 1;
} else {
/* Exact zero */
return packFloat64(get_float_rounding_mode(status) == float_round_down, 0, 0);
}
}
--zExp;
/* Do the equivalent of normalizeRoundAndPackFloat64() but
* starting with the significand in a pair of Bit64u.
*/
if (zSig0) {
shiftcount = countLeadingZeros64(zSig0) - 1;
shortShift128Left(zSig0, zSig1, shiftcount, &zSig0, &zSig1);
if (zSig1) {
zSig0 |= 1;
}
zExp -= shiftcount;
} else {
shiftcount = countLeadingZeros64(zSig1) - 1;
zSig0 = zSig1 << shiftcount;
zExp -= (shiftcount + 64);
}
return roundAndPackFloat64(zSign, zExp, zSig0, status);
}
}

View File

@@ -1,896 +0,0 @@
/*============================================================================
This C source file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic
Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
#define FLOAT128
/*============================================================================
* Adapted for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#include "softfloat.h"
#include "softfloat-round-pack.h"
/*----------------------------------------------------------------------------
| Primitive arithmetic functions, including multi-word arithmetic, and
| division and square root approximations. (Can be specialized to target
| if desired).
*----------------------------------------------------------------------------*/
#include "softfloat-macros.h"
/*----------------------------------------------------------------------------
| Functions and definitions to determine: (1) whether tininess for underflow
| is detected before or after rounding by default, (2) what (if anything)
| happens when exceptions are raised, (3) how signaling NaNs are distinguished
| from quiet NaNs, (4) the default generated quiet NaNs, and (5) how NaNs
| are propagated from function inputs to output. These details are target-
| specific.
*----------------------------------------------------------------------------*/
#include "softfloat-specialize.h"
/*----------------------------------------------------------------------------
| Takes a 64-bit fixed-point value `absZ' with binary point between bits 6
| and 7, and returns the properly rounded 32-bit integer corresponding to the
| input. If `zSign' is 1, the input is negated before being converted to an
| integer. Bit 63 of `absZ' must be zero. Ordinarily, the fixed-point input
| is simply rounded to an integer, with the inexact exception raised if the
| input cannot be represented exactly as an integer. However, if the fixed-
| point input is too large, the invalid exception is raised and the integer
| indefinite value is returned.
*----------------------------------------------------------------------------*/
Bit32s roundAndPackInt32(int zSign, Bit64u exactAbsZ, struct float_status_t *status)
{
int roundingMode = get_float_rounding_mode(status);
int roundNearestEven = (roundingMode == float_round_nearest_even);
int roundIncrement = 0x40;
if (! roundNearestEven) {
if (roundingMode == float_round_to_zero) roundIncrement = 0;
else {
roundIncrement = 0x7F;
if (zSign) {
if (roundingMode == float_round_up) roundIncrement = 0;
}
else {
if (roundingMode == float_round_down) roundIncrement = 0;
}
}
}
int roundBits = (int)(exactAbsZ & 0x7F);
Bit64u absZ = (exactAbsZ + roundIncrement)>>7;
absZ &= ~(((roundBits ^ 0x40) == 0) & roundNearestEven);
Bit32s z = (Bit32s) absZ;
if (zSign) z = -z;
if ((absZ>>32) || (z && ((z < 0) ^ zSign))) {
float_raise(status, float_flag_invalid);
return (Bit32s)(int32_indefinite);
}
if (roundBits) {
float_raise(status, float_flag_inexact);
if ((absZ << 7) > exactAbsZ)
set_float_rounding_up(status);
}
return z;
}
/*----------------------------------------------------------------------------
| Takes the 128-bit fixed-point value formed by concatenating `absZ0' and
| `absZ1', with binary point between bits 63 and 64 (between the input words),
| and returns the properly rounded 64-bit integer corresponding to the input.
| If `zSign' is 1, the input is negated before being converted to an integer.
| Ordinarily, the fixed-point input is simply rounded to an integer, with
| the inexact exception raised if the input cannot be represented exactly as
| an integer. However, if the fixed-point input is too large, the invalid
| exception is raised and the integer indefinite value is returned.
*----------------------------------------------------------------------------*/
Bit64s roundAndPackInt64(int zSign, Bit64u absZ0, Bit64u absZ1, struct float_status_t *status)
{
Bit64s z;
int roundingMode = get_float_rounding_mode(status);
int roundNearestEven = (roundingMode == float_round_nearest_even);
int increment = ((Bit64s) absZ1 < 0);
if (! roundNearestEven) {
if (roundingMode == float_round_to_zero) increment = 0;
else {
if (zSign) {
increment = (roundingMode == float_round_down) && absZ1;
}
else {
increment = (roundingMode == float_round_up) && absZ1;
}
}
}
Bit64u exactAbsZ0 = absZ0;
if (increment) {
++absZ0;
if (absZ0 == 0) goto overflow;
absZ0 &= ~(((Bit64u) (absZ1<<1) == 0) & roundNearestEven);
}
z = absZ0;
if (zSign) z = -z;
if (z && ((z < 0) ^ zSign)) {
overflow:
float_raise(status, float_flag_invalid);
return (Bit64s)(int64_indefinite);
}
if (absZ1) {
float_raise(status, float_flag_inexact);
if (absZ0 > exactAbsZ0)
set_float_rounding_up(status);
}
return z;
}
/*----------------------------------------------------------------------------
| Takes the 128-bit fixed-point value formed by concatenating `absZ0' and
| `absZ1', with binary point between bits 63 and 64 (between the input words),
| and returns the properly rounded 64-bit unsigned integer corresponding to the
| input. Ordinarily, the fixed-point input is simply rounded to an integer,
| with the inexact exception raised if the input cannot be represented exactly
| as an integer. However, if the fixed-point input is too large, the invalid
| exception is raised and the largest unsigned integer is returned.
*----------------------------------------------------------------------------*/
Bit64u roundAndPackUint64(int zSign, Bit64u absZ0, Bit64u absZ1, struct float_status_t *status)
{
int roundingMode = get_float_rounding_mode(status);
int roundNearestEven = (roundingMode == float_round_nearest_even);
int increment = ((Bit64s) absZ1 < 0);
if (!roundNearestEven) {
if (roundingMode == float_round_to_zero) {
increment = 0;
} else if (absZ1) {
if (zSign) {
increment = (roundingMode == float_round_down) && absZ1;
} else {
increment = (roundingMode == float_round_up) && absZ1;
}
}
}
if (increment) {
++absZ0;
if (absZ0 == 0) {
float_raise(status, float_flag_invalid);
return uint64_indefinite;
}
absZ0 &= ~(((Bit64u) (absZ1<<1) == 0) & roundNearestEven);
}
if (zSign && absZ0) {
float_raise(status, float_flag_invalid);
return uint64_indefinite;
}
if (absZ1) {
float_raise(status, float_flag_inexact);
}
return absZ0;
}
#ifdef FLOAT16
/*----------------------------------------------------------------------------
| Normalizes the subnormal half-precision floating-point value represented
| by the denormalized significand `aSig'. The normalized exponent and
| significand are stored at the locations pointed to by `zExpPtr' and
| `zSigPtr', respectively.
*----------------------------------------------------------------------------*/
void normalizeFloat16Subnormal(Bit16u aSig, Bit16s *zExpPtr, Bit16u *zSigPtr)
{
int shiftCount = countLeadingZeros16(aSig) - 5;
*zSigPtr = aSig<<shiftCount;
*zExpPtr = 1 - shiftCount;
}
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and significand `zSig', and returns the proper half-precision floating-
| point value corresponding to the abstract input. Ordinarily, the abstract
| value is simply rounded and packed into the half-precision format, with
| the inexact exception raised if the abstract input cannot be represented
| exactly. However, if the abstract value is too large, the overflow and
| inexact exceptions are raised and an infinity or maximal finite value is
| returned. If the abstract value is too small, the input value is rounded to
| a subnormal number, and the underflow and inexact exceptions are raised if
| the abstract input cannot be represented exactly as a subnormal single-
| precision floating-point number.
| The input significand `zSig' has its binary point between bits 14
| and 13, which is 4 bits to the left of the usual location. This shifted
| significand must be normalized or smaller. If `zSig' is not normalized,
| `zExp' must be 0; in that case, the result returned is a subnormal number,
| and it must not require rounding. In the usual case that `zSig' is
| normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
| The handling of underflow and overflow follows the IEC/IEEE Standard for
| Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
float16 roundAndPackFloat16(int zSign, Bit16s zExp, Bit16u zSig, struct float_status_t *status)
{
Bit16s roundIncrement, roundBits, roundMask;
int roundingMode = get_float_rounding_mode(status);
int roundNearestEven = (roundingMode == float_round_nearest_even);
roundIncrement = 8;
roundMask = 0xF;
if (! roundNearestEven) {
if (roundingMode == float_round_to_zero) roundIncrement = 0;
else {
roundIncrement = roundMask;
if (zSign) {
if (roundingMode == float_round_up) roundIncrement = 0;
}
else {
if (roundingMode == float_round_down) roundIncrement = 0;
}
}
}
roundBits = zSig & roundMask;
if (0x1D <= (Bit16u) zExp) {
if ((0x1D < zExp)
|| ((zExp == 0x1D) && ((Bit16s) (zSig + roundIncrement) < 0)))
{
float_raise(status, float_flag_overflow);
if (roundBits || float_exception_masked(status, float_flag_overflow)) {
float_raise(status, float_flag_inexact);
}
return packFloat16(zSign, 0x1F, 0) - (roundIncrement == 0);
}
if (zExp < 0) {
int isTiny = (zExp < -1) || (zSig + roundIncrement < 0x8000);
zSig = shift16RightJamming(zSig, -zExp);
zExp = 0;
roundBits = zSig & roundMask;
if (isTiny) {
if(get_flush_underflow_to_zero(status)) {
float_raise(status, float_flag_underflow | float_flag_inexact);
return packFloat16(zSign, 0, 0);
}
// signal the #P according to roundBits calculated AFTER denormalization
if (roundBits || !float_exception_masked(status, float_flag_underflow)) {
float_raise(status, float_flag_underflow);
}
}
}
}
if (roundBits) float_raise(status, float_flag_inexact);
Bit16u zSigRound = ((zSig + roundIncrement) & ~roundMask) >> 4;
zSigRound &= ~(((roundBits ^ 0x10) == 0) & roundNearestEven);
if (zSigRound == 0) zExp = 0;
return packFloat16(zSign, zExp, zSigRound);
}
#endif
/*----------------------------------------------------------------------------
| Normalizes the subnormal single-precision floating-point value represented
| by the denormalized significand `aSig'. The normalized exponent and
| significand are stored at the locations pointed to by `zExpPtr' and
| `zSigPtr', respectively.
*----------------------------------------------------------------------------*/
void normalizeFloat32Subnormal(Bit32u aSig, Bit16s *zExpPtr, Bit32u *zSigPtr)
{
int shiftCount = countLeadingZeros32(aSig) - 8;
*zSigPtr = aSig<<shiftCount;
*zExpPtr = 1 - shiftCount;
}
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and significand `zSig', and returns the proper single-precision floating-
| point value corresponding to the abstract input. Ordinarily, the abstract
| value is simply rounded and packed into the single-precision format, with
| the inexact exception raised if the abstract input cannot be represented
| exactly. However, if the abstract value is too large, the overflow and
| inexact exceptions are raised and an infinity or maximal finite value is
| returned. If the abstract value is too small, the input value is rounded to
| a subnormal number, and the underflow and inexact exceptions are raised if
| the abstract input cannot be represented exactly as a subnormal single-
| precision floating-point number.
| The input significand `zSig' has its binary point between bits 30
| and 29, which is 7 bits to the left of the usual location. This shifted
| significand must be normalized or smaller. If `zSig' is not normalized,
| `zExp' must be 0; in that case, the result returned is a subnormal number,
| and it must not require rounding. In the usual case that `zSig' is
| normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
| The handling of underflow and overflow follows the IEC/IEEE Standard for
| Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
float32 roundAndPackFloat32(int zSign, Bit16s zExp, Bit32u zSig, struct float_status_t *status)
{
Bit32s roundIncrement, roundBits;
const Bit32s roundMask = 0x7F;
int roundingMode = get_float_rounding_mode(status);
int roundNearestEven = (roundingMode == float_round_nearest_even);
roundIncrement = 0x40;
if (! roundNearestEven) {
if (roundingMode == float_round_to_zero) roundIncrement = 0;
else {
roundIncrement = roundMask;
if (zSign) {
if (roundingMode == float_round_up) roundIncrement = 0;
}
else {
if (roundingMode == float_round_down) roundIncrement = 0;
}
}
}
roundBits = zSig & roundMask;
if (0xFD <= (Bit16u) zExp) {
if ((0xFD < zExp)
|| ((zExp == 0xFD) && ((Bit32s) (zSig + roundIncrement) < 0)))
{
float_raise(status, float_flag_overflow);
if (roundBits || float_exception_masked(status, float_flag_overflow)) {
float_raise(status, float_flag_inexact);
if (roundIncrement != 0) set_float_rounding_up(status);
}
return packFloat32(zSign, 0xFF, 0) - (roundIncrement == 0);
}
if (zExp < 0) {
int isTiny = (zExp < -1) || (zSig + roundIncrement < 0x80000000);
if (isTiny) {
if (!float_exception_masked(status, float_flag_underflow)) {
float_raise(status, float_flag_underflow);
zExp += 192; // bias unmasked underflow
}
}
if (zExp < 0) {
zSig = shift32RightJamming(zSig, -zExp);
zExp = 0;
roundBits = zSig & roundMask;
if (isTiny) {
// masked underflow
if(get_flush_underflow_to_zero(status)) {
float_raise(status, float_flag_underflow | float_flag_inexact);
return packFloat32(zSign, 0, 0);
}
if (roundBits) float_raise(status, float_flag_underflow);
}
}
}
}
Bit32u zSigRound = ((zSig + roundIncrement) & ~roundMask) >> 7;
zSigRound &= ~(((roundBits ^ 0x40) == 0) & roundNearestEven);
if (zSigRound == 0) zExp = 0;
if (roundBits) {
float_raise(status, float_flag_inexact);
if ((zSigRound << 7) > zSig) set_float_rounding_up(status);
}
return packFloat32(zSign, zExp, zSigRound);
}
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and significand `zSig', and returns the proper single-precision floating-
| point value corresponding to the abstract input. This routine is just like
| `roundAndPackFloat32' except that `zSig' does not have to be normalized.
| Bit 31 of `zSig' must be zero, and `zExp' must be 1 less than the ``true''
| floating-point exponent.
*----------------------------------------------------------------------------*/
float32 normalizeRoundAndPackFloat32(int zSign, Bit16s zExp, Bit32u zSig, struct float_status_t *status)
{
int shiftCount = countLeadingZeros32(zSig) - 1;
return roundAndPackFloat32(zSign, zExp - shiftCount, zSig<<shiftCount, status);
}
/*----------------------------------------------------------------------------
| Normalizes the subnormal double-precision floating-point value represented
| by the denormalized significand `aSig'. The normalized exponent and
| significand are stored at the locations pointed to by `zExpPtr' and
| `zSigPtr', respectively.
*----------------------------------------------------------------------------*/
void normalizeFloat64Subnormal(Bit64u aSig, Bit16s *zExpPtr, Bit64u *zSigPtr)
{
int shiftCount = countLeadingZeros64(aSig) - 11;
*zSigPtr = aSig<<shiftCount;
*zExpPtr = 1 - shiftCount;
}
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and significand `zSig', and returns the proper double-precision floating-
| point value corresponding to the abstract input. Ordinarily, the abstract
| value is simply rounded and packed into the double-precision format, with
| the inexact exception raised if the abstract input cannot be represented
| exactly. However, if the abstract value is too large, the overflow and
| inexact exceptions are raised and an infinity or maximal finite value is
| returned. If the abstract value is too small, the input value is rounded
| to a subnormal number, and the underflow and inexact exceptions are raised
| if the abstract input cannot be represented exactly as a subnormal double-
| precision floating-point number.
| The input significand `zSig' has its binary point between bits 62
| and 61, which is 10 bits to the left of the usual location. This shifted
| significand must be normalized or smaller. If `zSig' is not normalized,
| `zExp' must be 0; in that case, the result returned is a subnormal number,
| and it must not require rounding. In the usual case that `zSig' is
| normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
| The handling of underflow and overflow follows the IEC/IEEE Standard for
| Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
float64 roundAndPackFloat64(int zSign, Bit16s zExp, Bit64u zSig, struct float_status_t *status)
{
Bit16s roundIncrement, roundBits;
const Bit16s roundMask = 0x3FF;
int roundingMode = get_float_rounding_mode(status);
int roundNearestEven = (roundingMode == float_round_nearest_even);
roundIncrement = 0x200;
if (! roundNearestEven) {
if (roundingMode == float_round_to_zero) roundIncrement = 0;
else {
roundIncrement = roundMask;
if (zSign) {
if (roundingMode == float_round_up) roundIncrement = 0;
}
else {
if (roundingMode == float_round_down) roundIncrement = 0;
}
}
}
roundBits = (Bit16s)(zSig & roundMask);
if (0x7FD <= (Bit16u) zExp) {
if ((0x7FD < zExp)
|| ((zExp == 0x7FD)
&& ((Bit64s) (zSig + roundIncrement) < 0)))
{
float_raise(status, float_flag_overflow);
if (roundBits || float_exception_masked(status, float_flag_overflow)) {
float_raise(status, float_flag_inexact);
if (roundIncrement != 0) set_float_rounding_up(status);
}
return packFloat64(zSign, 0x7FF, 0) - (roundIncrement == 0);
}
if (zExp < 0) {
int isTiny = (zExp < -1) || (zSig + roundIncrement < BX_CONST64(0x8000000000000000));
if (isTiny) {
if (!float_exception_masked(status, float_flag_underflow)) {
float_raise(status, float_flag_underflow);
zExp += 1536; // bias unmasked underflow
}
}
if (zExp < 0) {
zSig = shift64RightJamming(zSig, -zExp);
zExp = 0;
roundBits = (Bit16s)(zSig & roundMask);
if (isTiny) {
// masked underflow
if(get_flush_underflow_to_zero(status)) {
float_raise(status, float_flag_underflow | float_flag_inexact);
return packFloat64(zSign, 0, 0);
}
if (roundBits) float_raise(status, float_flag_underflow);
}
}
}
}
Bit64u zSigRound = (zSig + roundIncrement)>>10;
zSigRound &= ~(((roundBits ^ 0x200) == 0) & roundNearestEven);
if (zSigRound == 0) zExp = 0;
if (roundBits) {
float_raise(status, float_flag_inexact);
if ((zSigRound << 10) > zSig) set_float_rounding_up(status);
}
return packFloat64(zSign, zExp, zSigRound);
}
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and significand `zSig', and returns the proper double-precision floating-
| point value corresponding to the abstract input. This routine is just like
| `roundAndPackFloat64' except that `zSig' does not have to be normalized.
| Bit 63 of `zSig' must be zero, and `zExp' must be 1 less than the ``true''
| floating-point exponent.
*----------------------------------------------------------------------------*/
float64 normalizeRoundAndPackFloat64(int zSign, Bit16s zExp, Bit64u zSig, struct float_status_t *status)
{
int shiftCount = countLeadingZeros64(zSig) - 1;
return roundAndPackFloat64(zSign, zExp - shiftCount, zSig<<shiftCount, status);
}
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| Normalizes the subnormal extended double-precision floating-point value
| represented by the denormalized significand `aSig'. The normalized exponent
| and significand are stored at the locations pointed to by `zExpPtr' and
| `zSigPtr', respectively.
*----------------------------------------------------------------------------*/
void normalizeFloatx80Subnormal(Bit64u aSig, Bit32s *zExpPtr, Bit64u *zSigPtr)
{
int shiftCount = countLeadingZeros64(aSig);
*zSigPtr = aSig<<shiftCount;
*zExpPtr = 1 - shiftCount;
}
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and extended significand formed by the concatenation of `zSig0' and `zSig1',
| and returns the proper extended double-precision floating-point value
| corresponding to the abstract input. Ordinarily, the abstract value is
| rounded and packed into the extended double-precision format, with the
| inexact exception raised if the abstract input cannot be represented
| exactly. However, if the abstract value is too large, the overflow and
| inexact exceptions are raised and an infinity or maximal finite value is
| returned. If the abstract value is too small, the input value is rounded to
| a subnormal number, and the underflow and inexact exceptions are raised if
| the abstract input cannot be represented exactly as a subnormal extended
| double-precision floating-point number.
| If `roundingPrecision' is 32 or 64, the result is rounded to the same
| number of bits as single or double precision, respectively. Otherwise, the
| result is rounded to the full precision of the extended double-precision
| format.
| The input significand must be normalized or smaller. If the input
| significand is not normalized, `zExp' must be 0; in that case, the result
| returned is a subnormal number, and it must not require rounding. The
| handling of underflow and overflow follows the IEC/IEEE Standard for Binary
| Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
floatx80 SoftFloatRoundAndPackFloatx80(int roundingPrecision,
int zSign, Bit32s zExp, Bit64u zSig0, Bit64u zSig1, struct float_status_t *status)
{
Bit64u roundIncrement, roundMask, roundBits;
int increment;
Bit64u zSigExact; /* support rounding-up response */
Bit8u roundingMode = get_float_rounding_mode(status);
int roundNearestEven = (roundingMode == float_round_nearest_even);
if (roundingPrecision == 64) {
roundIncrement = BX_CONST64(0x0000000000000400);
roundMask = BX_CONST64(0x00000000000007FF);
}
else if (roundingPrecision == 32) {
roundIncrement = BX_CONST64(0x0000008000000000);
roundMask = BX_CONST64(0x000000FFFFFFFFFF);
}
else goto precision80;
zSig0 |= (zSig1 != 0);
if (! roundNearestEven) {
if (roundingMode == float_round_to_zero) roundIncrement = 0;
else {
roundIncrement = roundMask;
if (zSign) {
if (roundingMode == float_round_up) roundIncrement = 0;
}
else {
if (roundingMode == float_round_down) roundIncrement = 0;
}
}
}
roundBits = zSig0 & roundMask;
if (0x7FFD <= (Bit32u) (zExp - 1)) {
if ((0x7FFE < zExp)
|| ((zExp == 0x7FFE) && (zSig0 + roundIncrement < zSig0)))
{
goto overflow;
}
if (zExp <= 0) {
int isTiny = (zExp < 0) || (zSig0 <= zSig0 + roundIncrement);
zSig0 = shift64RightJamming(zSig0, 1 - zExp);
zSigExact = zSig0;
zExp = 0;
roundBits = zSig0 & roundMask;
if (isTiny) {
if (roundBits || (zSig0 && !float_exception_masked(status, float_flag_underflow)))
float_raise(status, float_flag_underflow);
}
zSig0 += roundIncrement;
if ((Bit64s) zSig0 < 0) zExp = 1;
roundIncrement = roundMask + 1;
if (roundNearestEven && (roundBits<<1 == roundIncrement))
roundMask |= roundIncrement;
zSig0 &= ~roundMask;
if (roundBits) {
float_raise(status, float_flag_inexact);
if (zSig0 > zSigExact) set_float_rounding_up(status);
}
return packFloatx80(zSign, zExp, zSig0);
}
}
if (roundBits) float_raise(status, float_flag_inexact);
zSigExact = zSig0;
zSig0 += roundIncrement;
if (zSig0 < roundIncrement) {
// Basically scale by shifting right and keep overflow
++zExp;
zSig0 = BX_CONST64(0x8000000000000000);
zSigExact >>= 1; // must scale also, or else later tests will fail
}
roundIncrement = roundMask + 1;
if (roundNearestEven && (roundBits<<1 == roundIncrement))
roundMask |= roundIncrement;
zSig0 &= ~roundMask;
if (zSig0 > zSigExact) set_float_rounding_up(status);
if (zSig0 == 0) zExp = 0;
return packFloatx80(zSign, zExp, zSig0);
precision80:
increment = ((Bit64s) zSig1 < 0);
if (! roundNearestEven) {
if (roundingMode == float_round_to_zero) increment = 0;
else {
if (zSign) {
increment = (roundingMode == float_round_down) && zSig1;
}
else {
increment = (roundingMode == float_round_up) && zSig1;
}
}
}
if (0x7FFD <= (Bit32u) (zExp - 1)) {
if ((0x7FFE < zExp)
|| ((zExp == 0x7FFE)
&& (zSig0 == BX_CONST64(0xFFFFFFFFFFFFFFFF))
&& increment))
{
roundMask = 0;
overflow:
float_raise(status, float_flag_overflow | float_flag_inexact);
if ((roundingMode == float_round_to_zero)
|| (zSign && (roundingMode == float_round_up))
|| (! zSign && (roundingMode == float_round_down)))
{
return packFloatx80(zSign, 0x7FFE, ~roundMask);
}
set_float_rounding_up(status);
return packFloatx80(zSign, 0x7FFF, BX_CONST64(0x8000000000000000));
}
if (zExp <= 0) {
int isTiny = (zExp < 0) || (! increment)
|| (zSig0 < BX_CONST64(0xFFFFFFFFFFFFFFFF));
shift64ExtraRightJamming(zSig0, zSig1, 1 - zExp, &zSig0, &zSig1);
zExp = 0;
if (isTiny) {
if (zSig1 || (zSig0 && !float_exception_masked(status, float_flag_underflow)))
float_raise(status, float_flag_underflow);
}
if (zSig1) float_raise(status, float_flag_inexact);
if (roundNearestEven) increment = ((Bit64s) zSig1 < 0);
else {
if (zSign) {
increment = (roundingMode == float_round_down) && zSig1;
} else {
increment = (roundingMode == float_round_up) && zSig1;
}
}
if (increment) {
zSigExact = zSig0++;
zSig0 &= ~(((Bit64u) (zSig1<<1) == 0) & roundNearestEven);
if (zSig0 > zSigExact) set_float_rounding_up(status);
if ((Bit64s) zSig0 < 0) zExp = 1;
}
return packFloatx80(zSign, zExp, zSig0);
}
}
if (zSig1) float_raise(status, float_flag_inexact);
if (increment) {
zSigExact = zSig0++;
if (zSig0 == 0) {
zExp++;
zSig0 = BX_CONST64(0x8000000000000000);
zSigExact >>= 1; // must scale also, or else later tests will fail
}
else {
zSig0 &= ~(((Bit64u) (zSig1<<1) == 0) & roundNearestEven);
}
if (zSig0 > zSigExact) set_float_rounding_up(status);
}
else {
if (zSig0 == 0) zExp = 0;
}
return packFloatx80(zSign, zExp, zSig0);
}
floatx80 roundAndPackFloatx80(int roundingPrecision,
int zSign, Bit32s zExp, Bit64u zSig0, Bit64u zSig1, struct float_status_t *status)
{
struct float_status_t *round_status = status;
floatx80 result = SoftFloatRoundAndPackFloatx80(roundingPrecision, zSign, zExp, zSig0, zSig1, status);
// bias unmasked undeflow
if (status->float_exception_flags & ~status->float_exception_masks & float_flag_underflow) {
float_raise(round_status, float_flag_underflow);
return SoftFloatRoundAndPackFloatx80(roundingPrecision, zSign, zExp + 0x6000, zSig0, zSig1, status = round_status);
}
// bias unmasked overflow
if (status->float_exception_flags & ~status->float_exception_masks & float_flag_overflow) {
float_raise(round_status, float_flag_overflow);
return SoftFloatRoundAndPackFloatx80(roundingPrecision, zSign, zExp - 0x6000, zSig0, zSig1, status = round_status);
}
return result;
}
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent
| `zExp', and significand formed by the concatenation of `zSig0' and `zSig1',
| and returns the proper extended double-precision floating-point value
| corresponding to the abstract input. This routine is just like
| `roundAndPackFloatx80' except that the input significand does not have to be
| normalized.
*----------------------------------------------------------------------------*/
floatx80 normalizeRoundAndPackFloatx80(int roundingPrecision,
int zSign, Bit32s zExp, Bit64u zSig0, Bit64u zSig1, struct float_status_t *status)
{
if (zSig0 == 0) {
zSig0 = zSig1;
zSig1 = 0;
zExp -= 64;
}
int shiftCount = countLeadingZeros64(zSig0);
shortShift128Left(zSig0, zSig1, shiftCount, &zSig0, &zSig1);
zExp -= shiftCount;
return
roundAndPackFloatx80(roundingPrecision, zSign, zExp, zSig0, zSig1, status);
}
#endif
#ifdef FLOAT128
/*----------------------------------------------------------------------------
| Normalizes the subnormal quadruple-precision floating-point value
| represented by the denormalized significand formed by the concatenation of
| `aSig0' and `aSig1'. The normalized exponent is stored at the location
| pointed to by `zExpPtr'. The most significant 49 bits of the normalized
| significand are stored at the location pointed to by `zSig0Ptr', and the
| least significant 64 bits of the normalized significand are stored at the
| location pointed to by `zSig1Ptr'.
*----------------------------------------------------------------------------*/
void normalizeFloat128Subnormal(
Bit64u aSig0, Bit64u aSig1, Bit32s *zExpPtr, Bit64u *zSig0Ptr, Bit64u *zSig1Ptr)
{
int shiftCount;
if (aSig0 == 0) {
shiftCount = countLeadingZeros64(aSig1) - 15;
if (shiftCount < 0) {
*zSig0Ptr = aSig1 >>(-shiftCount);
*zSig1Ptr = aSig1 << (shiftCount & 63);
}
else {
*zSig0Ptr = aSig1 << shiftCount;
*zSig1Ptr = 0;
}
*zExpPtr = - shiftCount - 63;
}
else {
shiftCount = countLeadingZeros64(aSig0) - 15;
shortShift128Left(aSig0, aSig1, shiftCount, zSig0Ptr, zSig1Ptr);
*zExpPtr = 1 - shiftCount;
}
}
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and extended significand formed by the concatenation of `zSig0', `zSig1',
| and `zSig2', and returns the proper quadruple-precision floating-point value
| corresponding to the abstract input. Ordinarily, the abstract value is
| simply rounded and packed into the quadruple-precision format, with the
| inexact exception raised if the abstract input cannot be represented
| exactly. However, if the abstract value is too large, the overflow and
| inexact exceptions are raised and an infinity or maximal finite value is
| returned. If the abstract value is too small, the input value is rounded to
| a subnormal number, and the underflow and inexact exceptions are raised if
| the abstract input cannot be represented exactly as a subnormal quadruple-
| precision floating-point number.
| The input significand must be normalized or smaller. If the input
| significand is not normalized, `zExp' must be 0; in that case, the result
| returned is a subnormal number, and it must not require rounding. In the
| usual case that the input significand is normalized, `zExp' must be 1 less
| than the ``true'' floating-point exponent. The handling of underflow and
| overflow follows the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
float128 roundAndPackFloat128(
int zSign, Bit32s zExp, Bit64u zSig0, Bit64u zSig1, Bit64u zSig2, struct float_status_t *status)
{
int increment = ((Bit64s) zSig2 < 0);
if (0x7FFD <= (Bit32u) zExp) {
if ((0x7FFD < zExp)
|| ((zExp == 0x7FFD)
&& eq128(BX_CONST64(0x0001FFFFFFFFFFFF),
BX_CONST64(0xFFFFFFFFFFFFFFFF), zSig0, zSig1)
&& increment))
{
float_raise(status, float_flag_overflow | float_flag_inexact);
return packFloat128Four(zSign, 0x7FFF, 0, 0);
}
if (zExp < 0) {
int isTiny = (zExp < -1)
|| ! increment
|| lt128(zSig0, zSig1,
BX_CONST64(0x0001FFFFFFFFFFFF),
BX_CONST64(0xFFFFFFFFFFFFFFFF));
shift128ExtraRightJamming(
zSig0, zSig1, zSig2, -zExp, &zSig0, &zSig1, &zSig2);
zExp = 0;
if (isTiny && zSig2) float_raise(status, float_flag_underflow);
increment = ((Bit64s) zSig2 < 0);
}
}
if (zSig2) float_raise(status, float_flag_inexact);
if (increment) {
add128(zSig0, zSig1, 0, 1, &zSig0, &zSig1);
zSig1 &= ~((zSig2 + zSig2 == 0) & 1);
}
else {
if ((zSig0 | zSig1) == 0) zExp = 0;
}
return packFloat128Four(zSign, zExp, zSig0, zSig1);
}
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and significand formed by the concatenation of `zSig0' and `zSig1', and
| returns the proper quadruple-precision floating-point value corresponding
| to the abstract input. This routine is just like `roundAndPackFloat128'
| except that the input significand has fewer bits and does not have to be
| normalized. In all cases, `zExp' must be 1 less than the ``true'' floating-
| point exponent.
*----------------------------------------------------------------------------*/
float128 normalizeRoundAndPackFloat128(
int zSign, Bit32s zExp, Bit64u zSig0, Bit64u zSig1, struct float_status_t *status)
{
Bit64u zSig2;
if (zSig0 == 0) {
zSig0 = zSig1;
zSig1 = 0;
zExp -= 64;
}
int shiftCount = countLeadingZeros64(zSig0) - 15;
if (0 <= shiftCount) {
zSig2 = 0;
shortShift128Left(zSig0, zSig1, shiftCount, &zSig0, &zSig1);
}
else {
shift128ExtraRightJamming(
zSig0, zSig1, 0, -shiftCount, &zSig0, &zSig1, &zSig2);
}
zExp -= shiftCount;
return roundAndPackFloat128(zSign, zExp, zSig0, zSig1, zSig2, status);
}
#endif

View File

@@ -1,309 +0,0 @@
/*============================================================================
This C source file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic
Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*============================================================================
* Adapted for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#ifndef _SOFTFLOAT_ROUND_PACK_H_
#define _SOFTFLOAT_ROUND_PACK_H_
#include "softfloat.h"
/*----------------------------------------------------------------------------
| Takes a 64-bit fixed-point value `absZ' with binary point between bits 6
| and 7, and returns the properly rounded 32-bit integer corresponding to the
| input. If `zSign' is 1, the input is negated before being converted to an
| integer. Bit 63 of `absZ' must be zero. Ordinarily, the fixed-point input
| is simply rounded to an integer, with the inexact exception raised if the
| input cannot be represented exactly as an integer. However, if the fixed-
| point input is too large, the invalid exception is raised and the integer
| indefinite value is returned.
*----------------------------------------------------------------------------*/
Bit32s roundAndPackInt32(int zSign, Bit64u absZ, struct float_status_t *status);
/*----------------------------------------------------------------------------
| Takes the 128-bit fixed-point value formed by concatenating `absZ0' and
| `absZ1', with binary point between bits 63 and 64 (between the input words),
| and returns the properly rounded 64-bit integer corresponding to the input.
| If `zSign' is 1, the input is negated before being converted to an integer.
| Ordinarily, the fixed-point input is simply rounded to an integer, with
| the inexact exception raised if the input cannot be represented exactly as
| an integer. However, if the fixed-point input is too large, the invalid
| exception is raised and the integer indefinite value is returned.
*----------------------------------------------------------------------------*/
Bit64s roundAndPackInt64(int zSign, Bit64u absZ0, Bit64u absZ1, struct float_status_t *status);
/*----------------------------------------------------------------------------
| Takes the 128-bit fixed-point value formed by concatenating `absZ0' and
| `absZ1', with binary point between bits 63 and 64 (between the input words),
| and returns the properly rounded 64-bit unsigned integer corresponding to the
| input. Ordinarily, the fixed-point input is simply rounded to an integer,
| with the inexact exception raised if the input cannot be represented exactly
| as an integer. However, if the fixed-point input is too large, the invalid
| exception is raised and the largest unsigned integer is returned.
*----------------------------------------------------------------------------*/
Bit64u roundAndPackUint64(int zSign, Bit64u absZ0, Bit64u absZ1, struct float_status_t *status);
#ifdef FLOAT16
/*----------------------------------------------------------------------------
| Normalizes the subnormal half-precision floating-point value represented
| by the denormalized significand `aSig'. The normalized exponent and
| significand are stored at the locations pointed to by `zExpPtr' and
| `zSigPtr', respectively.
*----------------------------------------------------------------------------*/
void normalizeFloat16Subnormal(Bit16u aSig, Bit16s *zExpPtr, Bit16u *zSigPtr);
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and significand `zSig', and returns the proper half-precision floating-
| point value corresponding to the abstract input. Ordinarily, the abstract
| value is simply rounded and packed into the half-precision format, with
| the inexact exception raised if the abstract input cannot be represented
| exactly. However, if the abstract value is too large, the overflow and
| inexact exceptions are raised and an infinity or maximal finite value is
| returned. If the abstract value is too small, the input value is rounded to
| a subnormal number, and the underflow and inexact exceptions are raised if
| the abstract input cannot be represented exactly as a subnormal single-
| precision floating-point number.
| The input significand `zSig' has its binary point between bits 14
| and 13, which is 4 bits to the left of the usual location. This shifted
| significand must be normalized or smaller. If `zSig' is not normalized,
| `zExp' must be 0; in that case, the result returned is a subnormal number,
| and it must not require rounding. In the usual case that `zSig' is
| normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
| The handling of underflow and overflow follows the IEC/IEEE Standard for
| Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
float16 roundAndPackFloat16(int zSign, Bit16s zExp, Bit16u zSig, struct float_status_t *status);
#endif
/*----------------------------------------------------------------------------
| Normalizes the subnormal single-precision floating-point value represented
| by the denormalized significand `aSig'. The normalized exponent and
| significand are stored at the locations pointed to by `zExpPtr' and
| `zSigPtr', respectively.
*----------------------------------------------------------------------------*/
void normalizeFloat32Subnormal(Bit32u aSig, Bit16s *zExpPtr, Bit32u *zSigPtr);
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and significand `zSig', and returns the proper single-precision floating-
| point value corresponding to the abstract input. Ordinarily, the abstract
| value is simply rounded and packed into the single-precision format, with
| the inexact exception raised if the abstract input cannot be represented
| exactly. However, if the abstract value is too large, the overflow and
| inexact exceptions are raised and an infinity or maximal finite value is
| returned. If the abstract value is too small, the input value is rounded to
| a subnormal number, and the underflow and inexact exceptions are raised if
| the abstract input cannot be represented exactly as a subnormal single-
| precision floating-point number.
| The input significand `zSig' has its binary point between bits 30
| and 29, which is 7 bits to the left of the usual location. This shifted
| significand must be normalized or smaller. If `zSig' is not normalized,
| `zExp' must be 0; in that case, the result returned is a subnormal number,
| and it must not require rounding. In the usual case that `zSig' is
| normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
| The handling of underflow and overflow follows the IEC/IEEE Standard for
| Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
float32 roundAndPackFloat32(int zSign, Bit16s zExp, Bit32u zSig, struct float_status_t *status);
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and significand `zSig', and returns the proper single-precision floating-
| point value corresponding to the abstract input. This routine is just like
| `roundAndPackFloat32' except that `zSig' does not have to be normalized.
| Bit 31 of `zSig' must be zero, and `zExp' must be 1 less than the ``true''
| floating-point exponent.
*----------------------------------------------------------------------------*/
float32 normalizeRoundAndPackFloat32(int zSign, Bit16s zExp, Bit32u zSig, struct float_status_t *status);
/*----------------------------------------------------------------------------
| Normalizes the subnormal double-precision floating-point value represented
| by the denormalized significand `aSig'. The normalized exponent and
| significand are stored at the locations pointed to by `zExpPtr' and
| `zSigPtr', respectively.
*----------------------------------------------------------------------------*/
void normalizeFloat64Subnormal(Bit64u aSig, Bit16s *zExpPtr, Bit64u *zSigPtr);
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and significand `zSig', and returns the proper double-precision floating-
| point value corresponding to the abstract input. Ordinarily, the abstract
| value is simply rounded and packed into the double-precision format, with
| the inexact exception raised if the abstract input cannot be represented
| exactly. However, if the abstract value is too large, the overflow and
| inexact exceptions are raised and an infinity or maximal finite value is
| returned. If the abstract value is too small, the input value is rounded
| to a subnormal number, and the underflow and inexact exceptions are raised
| if the abstract input cannot be represented exactly as a subnormal double-
| precision floating-point number.
| The input significand `zSig' has its binary point between bits 62
| and 61, which is 10 bits to the left of the usual location. This shifted
| significand must be normalized or smaller. If `zSig' is not normalized,
| `zExp' must be 0; in that case, the result returned is a subnormal number,
| and it must not require rounding. In the usual case that `zSig' is
| normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
| The handling of underflow and overflow follows the IEC/IEEE Standard for
| Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
float64 roundAndPackFloat64(int zSign, Bit16s zExp, Bit64u zSig, struct float_status_t *status);
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and significand `zSig', and returns the proper double-precision floating-
| point value corresponding to the abstract input. This routine is just like
| `roundAndPackFloat64' except that `zSig' does not have to be normalized.
| Bit 63 of `zSig' must be zero, and `zExp' must be 1 less than the ``true''
| floating-point exponent.
*----------------------------------------------------------------------------*/
float64 normalizeRoundAndPackFloat64(int zSign, Bit16s zExp, Bit64u zSig, struct float_status_t *status);
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| Normalizes the subnormal extended double-precision floating-point value
| represented by the denormalized significand `aSig'. The normalized exponent
| and significand are stored at the locations pointed to by `zExpPtr' and
| `zSigPtr', respectively.
*----------------------------------------------------------------------------*/
void normalizeFloatx80Subnormal(Bit64u aSig, Bit32s *zExpPtr, Bit64u *zSigPtr);
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and extended significand formed by the concatenation of `zSig0' and `zSig1',
| and returns the proper extended double-precision floating-point value
| corresponding to the abstract input. Ordinarily, the abstract value is
| rounded and packed into the extended double-precision format, with the
| inexact exception raised if the abstract input cannot be represented
| exactly. However, if the abstract value is too large, the overflow and
| inexact exceptions are raised and an infinity or maximal finite value is
| returned. If the abstract value is too small, the input value is rounded to
| a subnormal number, and the underflow and inexact exceptions are raised if
| the abstract input cannot be represented exactly as a subnormal extended
| double-precision floating-point number.
| If `roundingPrecision' is 32 or 64, the result is rounded to the same
| number of bits as single or double precision, respectively. Otherwise, the
| result is rounded to the full precision of the extended double-precision
| format.
| The input significand must be normalized or smaller. If the input
| significand is not normalized, `zExp' must be 0; in that case, the result
| returned is a subnormal number, and it must not require rounding. The
| handling of underflow and overflow follows the IEC/IEEE Standard for Binary
| Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
floatx80 roundAndPackFloatx80(int roundingPrecision,
int zSign, Bit32s zExp, Bit64u zSig0, Bit64u zSig1, struct float_status_t *status);
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent
| `zExp', and significand formed by the concatenation of `zSig0' and `zSig1',
| and returns the proper extended double-precision floating-point value
| corresponding to the abstract input. This routine is just like
| `roundAndPackFloatx80' except that the input significand does not have to be
| normalized.
*----------------------------------------------------------------------------*/
floatx80 normalizeRoundAndPackFloatx80(int roundingPrecision,
int zSign, Bit32s zExp, Bit64u zSig0, Bit64u zSig1, struct float_status_t *status);
#endif // FLOATX80
#ifdef FLOAT128
/*----------------------------------------------------------------------------
| Normalizes the subnormal quadruple-precision floating-point value
| represented by the denormalized significand formed by the concatenation of
| `aSig0' and `aSig1'. The normalized exponent is stored at the location
| pointed to by `zExpPtr'. The most significant 49 bits of the normalized
| significand are stored at the location pointed to by `zSig0Ptr', and the
| least significant 64 bits of the normalized significand are stored at the
| location pointed to by `zSig1Ptr'.
*----------------------------------------------------------------------------*/
void normalizeFloat128Subnormal(
Bit64u aSig0, Bit64u aSig1, Bit32s *zExpPtr, Bit64u *zSig0Ptr, Bit64u *zSig1Ptr);
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and extended significand formed by the concatenation of `zSig0', `zSig1',
| and `zSig2', and returns the proper quadruple-precision floating-point value
| corresponding to the abstract input. Ordinarily, the abstract value is
| simply rounded and packed into the quadruple-precision format, with the
| inexact exception raised if the abstract input cannot be represented
| exactly. However, if the abstract value is too large, the overflow and
| inexact exceptions are raised and an infinity or maximal finite value is
| returned. If the abstract value is too small, the input value is rounded to
| a subnormal number, and the underflow and inexact exceptions are raised if
| the abstract input cannot be represented exactly as a subnormal quadruple-
| precision floating-point number.
| The input significand must be normalized or smaller. If the input
| significand is not normalized, `zExp' must be 0; in that case, the result
| returned is a subnormal number, and it must not require rounding. In the
| usual case that the input significand is normalized, `zExp' must be 1 less
| than the ``true'' floating-point exponent. The handling of underflow and
| overflow follows the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
float128 roundAndPackFloat128(
int zSign, Bit32s zExp, Bit64u zSig0, Bit64u zSig1, Bit64u zSig2, struct float_status_t *status);
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and significand formed by the concatenation of `zSig0' and `zSig1', and
| returns the proper quadruple-precision floating-point value corresponding
| to the abstract input. This routine is just like `roundAndPackFloat128'
| except that the input significand has fewer bits and does not have to be
| normalized. In all cases, `zExp' must be 1 less than the ``true'' floating-
| point exponent.
*----------------------------------------------------------------------------*/
float128 normalizeRoundAndPackFloat128(
int zSign, Bit32s zExp, Bit64u zSig0, Bit64u zSig1, struct float_status_t *status);
#endif // FLOAT128
#endif

View File

@@ -1,187 +0,0 @@
/*============================================================================
This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
#define FLOAT128
/*============================================================================
* Adapted for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#include "softfloat.h"
#include "softfloat-specialize.h"
/*----------------------------------------------------------------------------
| Takes two single-precision floating-point values `a' and `b', one of which
| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
| signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
float32 propagateFloat32NaN(float32 a, float32 b, struct float_status_t *status)
{
int aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = float32_is_nan(a);
aIsSignalingNaN = float32_is_signaling_nan(a);
bIsNaN = float32_is_nan(b);
bIsSignalingNaN = float32_is_signaling_nan(b);
a |= 0x00400000;
b |= 0x00400000;
if (aIsSignalingNaN | bIsSignalingNaN) float_raise(status, float_flag_invalid);
if (get_float_nan_handling_mode(status) == float_larger_significand_nan) {
if (aIsSignalingNaN) {
if (bIsSignalingNaN) goto returnLargerSignificand;
return bIsNaN ? b : a;
}
else if (aIsNaN) {
if (bIsSignalingNaN | ! bIsNaN) return a;
returnLargerSignificand:
if ((Bit32u) (a<<1) < (Bit32u) (b<<1)) return b;
if ((Bit32u) (b<<1) < (Bit32u) (a<<1)) return a;
return (a < b) ? a : b;
}
else {
return b;
}
} else {
return (aIsSignalingNaN | aIsNaN) ? a : b;
}
}
/*----------------------------------------------------------------------------
| Takes two double-precision floating-point values `a' and `b', one of which
| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
| signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
float64 propagateFloat64NaN(float64 a, float64 b, struct float_status_t *status)
{
int aIsNaN = float64_is_nan(a);
int aIsSignalingNaN = float64_is_signaling_nan(a);
int bIsNaN = float64_is_nan(b);
int bIsSignalingNaN = float64_is_signaling_nan(b);
a |= BX_CONST64(0x0008000000000000);
b |= BX_CONST64(0x0008000000000000);
if (aIsSignalingNaN | bIsSignalingNaN) float_raise(status, float_flag_invalid);
if (get_float_nan_handling_mode(status) == float_larger_significand_nan) {
if (aIsSignalingNaN) {
if (bIsSignalingNaN) goto returnLargerSignificand;
return bIsNaN ? b : a;
}
else if (aIsNaN) {
if (bIsSignalingNaN | ! bIsNaN) return a;
returnLargerSignificand:
if ((Bit64u) (a<<1) < (Bit64u) (b<<1)) return b;
if ((Bit64u) (b<<1) < (Bit64u) (a<<1)) return a;
return (a < b) ? a : b;
}
else {
return b;
}
} else {
return (aIsSignalingNaN | aIsNaN) ? a : b;
}
}
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| Takes two extended double-precision floating-point values `a' and `b', one
| of which is a NaN, and returns the appropriate NaN result. If either `a' or
| `b' is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
floatx80 propagateFloatx80NaN(floatx80 a, floatx80 b, struct float_status_t *status)
{
int aIsNaN = floatx80_is_nan(a);
int aIsSignalingNaN = floatx80_is_signaling_nan(a);
int bIsNaN = floatx80_is_nan(b);
int bIsSignalingNaN = floatx80_is_signaling_nan(b);
a.fraction |= BX_CONST64(0xC000000000000000);
b.fraction |= BX_CONST64(0xC000000000000000);
if (aIsSignalingNaN | bIsSignalingNaN) float_raise(status, float_flag_invalid);
if (aIsSignalingNaN) {
if (bIsSignalingNaN) goto returnLargerSignificand;
return bIsNaN ? b : a;
}
else if (aIsNaN) {
if (bIsSignalingNaN | ! bIsNaN) return a;
returnLargerSignificand:
if (a.fraction < b.fraction) return b;
if (b.fraction < a.fraction) return a;
return (a.exp < b.exp) ? a : b;
}
else {
return b;
}
}
#endif /* FLOATX80 */
#ifdef FLOAT128
/*----------------------------------------------------------------------------
| Takes two quadruple-precision floating-point values `a' and `b', one of
| which is a NaN, and returns the appropriate NaN result. If either `a' or
| `b' is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
float128 propagateFloat128NaN(float128 a, float128 b, struct float_status_t *status)
{
int aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = float128_is_nan(a);
aIsSignalingNaN = float128_is_signaling_nan(a);
bIsNaN = float128_is_nan(b);
bIsSignalingNaN = float128_is_signaling_nan(b);
a.hi |= BX_CONST64(0x0000800000000000);
b.hi |= BX_CONST64(0x0000800000000000);
if (aIsSignalingNaN | bIsSignalingNaN) float_raise(status, float_flag_invalid);
if (aIsSignalingNaN) {
if (bIsSignalingNaN) goto returnLargerSignificand;
return bIsNaN ? b : a;
}
else if (aIsNaN) {
if (bIsSignalingNaN | !bIsNaN) return a;
returnLargerSignificand:
if (lt128(a.hi<<1, a.lo, b.hi<<1, b.lo)) return b;
if (lt128(b.hi<<1, b.lo, a.hi<<1, a.lo)) return a;
return (a.hi < b.hi) ? a : b;
}
else {
return b;
}
}
/*----------------------------------------------------------------------------
| The pattern for a default generated quadruple-precision NaN.
*----------------------------------------------------------------------------*/
const float128 float128_default_nan =
packFloat128(float128_default_nan_hi, float128_default_nan_lo);
#endif /* FLOAT128 */

View File

@@ -1,789 +0,0 @@
/*============================================================================
This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
#ifndef _SOFTFLOAT_SPECIALIZE_H_
#define _SOFTFLOAT_SPECIALIZE_H_
#include "softfloat.h"
/*============================================================================
* Adapted for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#define int16_indefinite ((Bit16s)0x8000)
#define int32_indefinite ((Bit32s)0x80000000)
#define int64_indefinite BX_CONST64(0x8000000000000000)
#define uint16_indefinite (0xffff)
#define uint32_indefinite (0xffffffff)
#define uint64_indefinite BX_CONST64(0xffffffffffffffff)
/*----------------------------------------------------------------------------
| Internal canonical NaN format.
*----------------------------------------------------------------------------*/
typedef struct {
int sign;
Bit64u hi, lo;
} commonNaNT;
#ifdef FLOAT16
/*----------------------------------------------------------------------------
| The pattern for a default generated half-precision NaN.
*----------------------------------------------------------------------------*/
extern const float16 float16_default_nan;
#define float16_fraction extractFloat16Frac
#define float16_exp extractFloat16Exp
#define float16_sign extractFloat16Sign
/*----------------------------------------------------------------------------
| Returns the fraction bits of the half-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit16u extractFloat16Frac(float16 a)
{
return a & 0x3FF;
}
/*----------------------------------------------------------------------------
| Returns the exponent bits of the half-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit16s extractFloat16Exp(float16 a)
{
return (a>>10) & 0x1F;
}
/*----------------------------------------------------------------------------
| Returns the sign bit of the half-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int extractFloat16Sign(float16 a)
{
return a>>15;
}
/*----------------------------------------------------------------------------
| Packs the sign `zSign', exponent `zExp', and significand `zSig' into a
| single-precision floating-point value, returning the result. After being
| shifted into the proper positions, the three fields are simply added
| together to form the result. This means that any integer portion of `zSig'
| will be added into the exponent. Since a properly normalized significand
| will have an integer portion equal to 1, the `zExp' input should be 1 less
| than the desired result exponent whenever `zSig' is a complete, normalized
| significand.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float16 packFloat16(int zSign, int zExp, Bit16u zSig)
{
return (((Bit16u) zSign)<<15) + (((Bit16u) zExp)<<10) + zSig;
}
/*----------------------------------------------------------------------------
| Returns 1 if the half-precision floating-point value `a' is a NaN;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int float16_is_nan(float16 a)
{
return (0xF800 < (Bit16u) (a<<1));
}
/*----------------------------------------------------------------------------
| Returns 1 if the half-precision floating-point value `a' is a signaling
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int float16_is_signaling_nan(float16 a)
{
return (((a>>9) & 0x3F) == 0x3E) && (a & 0x1FF);
}
/*----------------------------------------------------------------------------
| Returns 1 if the half-precision floating-point value `a' is denormal;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int float16_is_denormal(float16 a)
{
return (extractFloat16Exp(a) == 0) && (extractFloat16Frac(a) != 0);
}
/*----------------------------------------------------------------------------
| Convert float16 denormals to zero.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float16 float16_denormal_to_zero(float16 a)
{
if (float16_is_denormal(a)) a &= 0x8000;
return a;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the half-precision floating-point NaN
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
| exception is raised.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE commonNaNT float16ToCommonNaN(float16 a, struct float_status_t *status)
{
commonNaNT z;
if (float16_is_signaling_nan(a)) float_raise(status, float_flag_invalid);
z.sign = a>>15;
z.lo = 0;
z.hi = ((Bit64u) a)<<54;
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the half-
| precision floating-point format.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float16 commonNaNToFloat16(commonNaNT a)
{
return (((Bit16u) a.sign)<<15) | 0x7E00 | (Bit16u)(a.hi>>54);
}
#endif
/*----------------------------------------------------------------------------
| Commonly used single-precision floating point constants
*----------------------------------------------------------------------------*/
extern const float32 float32_negative_inf;
extern const float32 float32_positive_inf;
extern const float32 float32_negative_zero;
extern const float32 float32_positive_zero;
extern const float32 float32_negative_one;
extern const float32 float32_positive_one;
extern const float32 float32_max_float;
extern const float32 float32_min_float;
/*----------------------------------------------------------------------------
| The pattern for a default generated single-precision NaN.
*----------------------------------------------------------------------------*/
extern const float32 float32_default_nan;
#define float32_fraction extractFloat32Frac
#define float32_exp extractFloat32Exp
#define float32_sign extractFloat32Sign
#define FLOAT32_EXP_BIAS 0x7F
/*----------------------------------------------------------------------------
| Returns the fraction bits of the single-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit32u extractFloat32Frac(float32 a)
{
return a & 0x007FFFFF;
}
/*----------------------------------------------------------------------------
| Returns the exponent bits of the single-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit16s extractFloat32Exp(float32 a)
{
return (a>>23) & 0xFF;
}
/*----------------------------------------------------------------------------
| Returns the sign bit of the single-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int extractFloat32Sign(float32 a)
{
return a>>31;
}
/*----------------------------------------------------------------------------
| Packs the sign `zSign', exponent `zExp', and significand `zSig' into a
| single-precision floating-point value, returning the result. After being
| shifted into the proper positions, the three fields are simply added
| together to form the result. This means that any integer portion of `zSig'
| will be added into the exponent. Since a properly normalized significand
| will have an integer portion equal to 1, the `zExp' input should be 1 less
| than the desired result exponent whenever `zSig' is a complete, normalized
| significand.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float32 packFloat32(int zSign, Bit16s zExp, Bit32u zSig)
{
return (((Bit32u) zSign)<<31) + (((Bit32u) zExp)<<23) + zSig;
}
/*----------------------------------------------------------------------------
| Returns 1 if the single-precision floating-point value `a' is a NaN;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int float32_is_nan(float32 a)
{
return (0xFF000000 < (Bit32u) (a<<1));
}
/*----------------------------------------------------------------------------
| Returns 1 if the single-precision floating-point value `a' is a signaling
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int float32_is_signaling_nan(float32 a)
{
return (((a>>22) & 0x1FF) == 0x1FE) && (a & 0x003FFFFF);
}
/*----------------------------------------------------------------------------
| Returns 1 if the single-precision floating-point value `a' is denormal;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int float32_is_denormal(float32 a)
{
return (extractFloat32Exp(a) == 0) && (extractFloat32Frac(a) != 0);
}
/*----------------------------------------------------------------------------
| Convert float32 denormals to zero.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float32 float32_denormal_to_zero(float32 a)
{
if (float32_is_denormal(a)) a &= 0x80000000;
return a;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the single-precision floating-point NaN
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
| exception is raised.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE commonNaNT float32ToCommonNaN(float32 a, struct float_status_t *status)
{
commonNaNT z;
if (float32_is_signaling_nan(a)) float_raise(status, float_flag_invalid);
z.sign = a>>31;
z.lo = 0;
z.hi = ((Bit64u) a)<<41;
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the single-
| precision floating-point format.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float32 commonNaNToFloat32(commonNaNT a)
{
return (((Bit32u) a.sign)<<31) | 0x7FC00000 | (Bit32u)(a.hi>>41);
}
/*----------------------------------------------------------------------------
| Takes two single-precision floating-point values `a' and `b', one of which
| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
| signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
float32 propagateFloat32NaN(float32 a, float32 b, struct float_status_t *status);
/*----------------------------------------------------------------------------
| Takes single-precision floating-point NaN `a' and returns the appropriate
| NaN result. If `a' is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float32 propagateFloat32NaNOne(float32 a, struct float_status_t *status)
{
if (float32_is_signaling_nan(a))
float_raise(status, float_flag_invalid);
return a | 0x00400000;
}
/*----------------------------------------------------------------------------
| Commonly used single-precision floating point constants
*----------------------------------------------------------------------------*/
extern const float64 float64_negative_inf;
extern const float64 float64_positive_inf;
extern const float64 float64_negative_zero;
extern const float64 float64_positive_zero;
extern const float64 float64_negative_one;
extern const float64 float64_positive_one;
extern const float64 float64_max_float;
extern const float64 float64_min_float;
/*----------------------------------------------------------------------------
| The pattern for a default generated double-precision NaN.
*----------------------------------------------------------------------------*/
extern const float64 float64_default_nan;
#define float64_fraction extractFloat64Frac
#define float64_exp extractFloat64Exp
#define float64_sign extractFloat64Sign
#define FLOAT64_EXP_BIAS 0x3FF
/*----------------------------------------------------------------------------
| Returns the fraction bits of the double-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit64u extractFloat64Frac(float64 a)
{
return a & BX_CONST64(0x000FFFFFFFFFFFFF);
}
/*----------------------------------------------------------------------------
| Returns the exponent bits of the double-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit16s extractFloat64Exp(float64 a)
{
return (Bit16s)(a>>52) & 0x7FF;
}
/*----------------------------------------------------------------------------
| Returns the sign bit of the double-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int extractFloat64Sign(float64 a)
{
return (int)(a>>63);
}
/*----------------------------------------------------------------------------
| Packs the sign `zSign', exponent `zExp', and significand `zSig' into a
| double-precision floating-point value, returning the result. After being
| shifted into the proper positions, the three fields are simply added
| together to form the result. This means that any integer portion of `zSig'
| will be added into the exponent. Since a properly normalized significand
| will have an integer portion equal to 1, the `zExp' input should be 1 less
| than the desired result exponent whenever `zSig' is a complete, normalized
| significand.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float64 packFloat64(int zSign, Bit16s zExp, Bit64u zSig)
{
return (((Bit64u) zSign)<<63) + (((Bit64u) zExp)<<52) + zSig;
}
/*----------------------------------------------------------------------------
| Returns 1 if the double-precision floating-point value `a' is a NaN;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int float64_is_nan(float64 a)
{
return (BX_CONST64(0xFFE0000000000000) < (Bit64u) (a<<1));
}
/*----------------------------------------------------------------------------
| Returns 1 if the double-precision floating-point value `a' is a signaling
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int float64_is_signaling_nan(float64 a)
{
return (((a>>51) & 0xFFF) == 0xFFE) && (a & BX_CONST64(0x0007FFFFFFFFFFFF));
}
/*----------------------------------------------------------------------------
| Returns 1 if the double-precision floating-point value `a' is denormal;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int float64_is_denormal(float64 a)
{
return (extractFloat64Exp(a) == 0) && (extractFloat64Frac(a) != 0);
}
/*----------------------------------------------------------------------------
| Convert float64 denormals to zero.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float64 float64_denormal_to_zero(float64 a)
{
if (float64_is_denormal(a)) a &= ((Bit64u)(1) << 63);
return a;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the double-precision floating-point NaN
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
| exception is raised.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE commonNaNT float64ToCommonNaN(float64 a, struct float_status_t *status)
{
commonNaNT z;
if (float64_is_signaling_nan(a)) float_raise(status, float_flag_invalid);
z.sign = (int)(a>>63);
z.lo = 0;
z.hi = a<<12;
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the double-
| precision floating-point format.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float64 commonNaNToFloat64(commonNaNT a)
{
return (((Bit64u) a.sign)<<63) | BX_CONST64(0x7FF8000000000000) | (a.hi>>12);
}
/*----------------------------------------------------------------------------
| Takes two double-precision floating-point values `a' and `b', one of which
| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
| signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
float64 propagateFloat64NaN(float64 a, float64 b, struct float_status_t *status);
/*----------------------------------------------------------------------------
| Takes double-precision floating-point NaN `a' and returns the appropriate
| NaN result. If `a' is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float64 propagateFloat64NaNOne(float64 a, struct float_status_t *status)
{
if (float64_is_signaling_nan(a))
float_raise(status, float_flag_invalid);
return a | BX_CONST64(0x0008000000000000);
}
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| The pattern for a default generated extended double-precision NaN. The
| `high' and `low' values hold the most- and least-significant bits,
| respectively.
*----------------------------------------------------------------------------*/
#define floatx80_default_nan_exp 0xFFFF
#define floatx80_default_nan_fraction BX_CONST64(0xC000000000000000)
#define floatx80_fraction extractFloatx80Frac
#define floatx80_exp extractFloatx80Exp
#define floatx80_sign extractFloatx80Sign
#define FLOATX80_EXP_BIAS 0x3FFF
/*----------------------------------------------------------------------------
| Returns the fraction bits of the extended double-precision floating-point
| value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit64u extractFloatx80Frac(floatx80 a)
{
return a.fraction;
}
/*----------------------------------------------------------------------------
| Returns the exponent bits of the extended double-precision floating-point
| value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit32s extractFloatx80Exp(floatx80 a)
{
return a.exp & 0x7FFF;
}
/*----------------------------------------------------------------------------
| Returns the sign bit of the extended double-precision floating-point value
| `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int extractFloatx80Sign(floatx80 a)
{
return a.exp>>15;
}
/*----------------------------------------------------------------------------
| Packs the sign `zSign', exponent `zExp', and significand `zSig' into an
| extended double-precision floating-point value, returning the result.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE floatx80 packFloatx80(int zSign, Bit32s zExp, Bit64u zSig)
{
floatx80 z;
z.fraction = zSig;
z.exp = (zSign << 15) + zExp;
return z;
}
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point value `a' is a
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int floatx80_is_nan(floatx80 a)
{
// return ((a.exp & 0x7FFF) == 0x7FFF) && (Bit64s) (a.fraction<<1);
return ((a.exp & 0x7FFF) == 0x7FFF) && (((Bit64s) (a.fraction<<1)) != 0);
}
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point value `a' is a
| signaling NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int floatx80_is_signaling_nan(floatx80 a)
{
Bit64u aLow = a.fraction & ~BX_CONST64(0x4000000000000000);
return ((a.exp & 0x7FFF) == 0x7FFF) &&
((Bit64u) (aLow<<1)) && (a.fraction == aLow);
}
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point value `a' is an
| unsupported; otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int floatx80_is_unsupported(floatx80 a)
{
return ((a.exp & 0x7FFF) && !(a.fraction & BX_CONST64(0x8000000000000000)));
}
/*----------------------------------------------------------------------------
| Returns the result of converting the extended double-precision floating-
| point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the
| invalid exception is raised.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE commonNaNT floatx80ToCommonNaN(floatx80 a, struct float_status_t *status)
{
commonNaNT z;
if (floatx80_is_signaling_nan(a)) float_raise(status, float_flag_invalid);
z.sign = a.exp >> 15;
z.lo = 0;
z.hi = a.fraction << 1;
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the extended
| double-precision floating-point format.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE floatx80 commonNaNToFloatx80(commonNaNT a)
{
floatx80 z;
z.fraction = BX_CONST64(0xC000000000000000) | (a.hi>>1);
z.exp = (((Bit16u) a.sign)<<15) | 0x7FFF;
return z;
}
/*----------------------------------------------------------------------------
| Takes two extended double-precision floating-point values `a' and `b', one
| of which is a NaN, and returns the appropriate NaN result. If either `a' or
| `b' is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
floatx80 propagateFloatx80NaN(floatx80 a, floatx80 b, struct float_status_t *status);
/*----------------------------------------------------------------------------
| Takes extended double-precision floating-point NaN `a' and returns the
| appropriate NaN result. If `a' is a signaling NaN, the invalid exception
| is raised.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE floatx80 propagateFloatx80NaNOne(floatx80 a, struct float_status_t *status)
{
if (floatx80_is_signaling_nan(a))
float_raise(status, float_flag_invalid);
a.fraction |= BX_CONST64(0xC000000000000000);
return a;
}
#endif /* FLOATX80 */
#ifdef FLOAT128
#include "softfloat-macros.h"
/*----------------------------------------------------------------------------
| The pattern for a default generated quadruple-precision NaN. The `high' and
| `low' values hold the most- and least-significant bits, respectively.
*----------------------------------------------------------------------------*/
#define float128_default_nan_hi BX_CONST64(0xFFFF800000000000)
#define float128_default_nan_lo BX_CONST64(0x0000000000000000)
#define float128_exp extractFloat128Exp
/*----------------------------------------------------------------------------
| Returns the least-significant 64 fraction bits of the quadruple-precision
| floating-point value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit64u extractFloat128Frac1(float128 a)
{
return a.lo;
}
/*----------------------------------------------------------------------------
| Returns the most-significant 48 fraction bits of the quadruple-precision
| floating-point value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit64u extractFloat128Frac0(float128 a)
{
return a.hi & BX_CONST64(0x0000FFFFFFFFFFFF);
}
/*----------------------------------------------------------------------------
| Returns the exponent bits of the quadruple-precision floating-point value
| `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit32s extractFloat128Exp(float128 a)
{
return ((Bit32s)(a.hi>>48)) & 0x7FFF;
}
/*----------------------------------------------------------------------------
| Returns the sign bit of the quadruple-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int extractFloat128Sign(float128 a)
{
return (int)(a.hi >> 63);
}
/*----------------------------------------------------------------------------
| Packs the sign `zSign', the exponent `zExp', and the significand formed
| by the concatenation of `zSig0' and `zSig1' into a quadruple-precision
| floating-point value, returning the result. After being shifted into the
| proper positions, the three fields `zSign', `zExp', and `zSig0' are simply
| added together to form the most significant 32 bits of the result. This
| means that any integer portion of `zSig0' will be added into the exponent.
| Since a properly normalized significand will have an integer portion equal
| to 1, the `zExp' input should be 1 less than the desired result exponent
| whenever `zSig0' and `zSig1' concatenated form a complete, normalized
| significand.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float128 packFloat128Four(int zSign, Bit32s zExp, Bit64u zSig0, Bit64u zSig1)
{
float128 z;
z.lo = zSig1;
z.hi = (((Bit64u) zSign)<<63) + (((Bit64u) zExp)<<48) + zSig0;
return z;
}
/*----------------------------------------------------------------------------
| Packs two 64-bit precision integers into into the quadruple-precision
| floating-point value, returning the result.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float128 packFloat128(Bit64u zHi, Bit64u zLo)
{
float128 z;
z.lo = zLo;
z.hi = zHi;
return z;
}
#ifdef _MSC_VER
#define PACK_FLOAT_128(hi,lo) { lo, hi }
#else
#define PACK_FLOAT_128(hi,lo) packFloat128(BX_CONST64(hi),BX_CONST64(lo))
#endif
/*----------------------------------------------------------------------------
| Returns 1 if the quadruple-precision floating-point value `a' is a NaN;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int float128_is_nan(float128 a)
{
return (BX_CONST64(0xFFFE000000000000) <= (Bit64u) (a.hi<<1))
&& (a.lo || (a.hi & BX_CONST64(0x0000FFFFFFFFFFFF)));
}
/*----------------------------------------------------------------------------
| Returns 1 if the quadruple-precision floating-point value `a' is a
| signaling NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int float128_is_signaling_nan(float128 a)
{
return (((a.hi>>47) & 0xFFFF) == 0xFFFE)
&& (a.lo || (a.hi & BX_CONST64(0x00007FFFFFFFFFFF)));
}
/*----------------------------------------------------------------------------
| Returns the result of converting the quadruple-precision floating-point NaN
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
| exception is raised.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE commonNaNT float128ToCommonNaN(float128 a, struct float_status_t *status)
{
commonNaNT z;
if (float128_is_signaling_nan(a)) float_raise(status, float_flag_invalid);
z.sign = (int)(a.hi>>63);
shortShift128Left(a.hi, a.lo, 16, &z.hi, &z.lo);
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the quadruple-
| precision floating-point format.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float128 commonNaNToFloat128(commonNaNT a)
{
float128 z;
shift128Right(a.hi, a.lo, 16, &z.hi, &z.lo);
z.hi |= (((Bit64u) a.sign)<<63) | BX_CONST64(0x7FFF800000000000);
return z;
}
/*----------------------------------------------------------------------------
| Takes two quadruple-precision floating-point values `a' and `b', one of
| which is a NaN, and returns the appropriate NaN result. If either `a' or
| `b' is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
float128 propagateFloat128NaN(float128 a, float128 b, struct float_status_t *status);
/*----------------------------------------------------------------------------
| The pattern for a default generated quadruple-precision NaN.
*----------------------------------------------------------------------------*/
extern const float128 float128_default_nan;
#endif /* FLOAT128 */
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,488 +0,0 @@
/*============================================================================
This C header file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic
Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*============================================================================
* Adapted for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#include "config.h" /* generated by configure script from config.h.in */
#ifndef _SOFTFLOAT_H_
#define _SOFTFLOAT_H_
#define FLOAT16
#define FLOATX80
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point types.
*----------------------------------------------------------------------------*/
#ifdef FLOAT16
typedef Bit16u float16;
#endif
typedef Bit32u float32;
typedef Bit64u float64;
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point class.
*----------------------------------------------------------------------------*/
typedef enum {
float_zero,
float_SNaN,
float_QNaN,
float_negative_inf,
float_positive_inf,
float_denormal,
float_normalized
} float_class_t;
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point NaN operands handling mode.
*----------------------------------------------------------------------------*/
enum float_nan_handling_mode_t {
float_larger_significand_nan = 0, // this mode used by x87 FPU
float_first_operand_nan = 1 // this mode used by SSE
};
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point rounding mode.
*----------------------------------------------------------------------------*/
enum float_round_t {
float_round_nearest_even = 0,
float_round_down = 1,
float_round_up = 2,
float_round_to_zero = 3
};
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point exception flags.
*----------------------------------------------------------------------------*/
enum float_exception_flag_t {
float_flag_invalid = 0x01,
float_flag_denormal = 0x02,
float_flag_divbyzero = 0x04,
float_flag_overflow = 0x08,
float_flag_underflow = 0x10,
float_flag_inexact = 0x20
};
extern const unsigned float_all_exceptions_mask;
#ifdef FLOATX80
#define RAISE_SW_C1 0x0200
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point ordering relations
*----------------------------------------------------------------------------*/
enum {
float_relation_less = -1,
float_relation_equal = 0,
float_relation_greater = 1,
float_relation_unordered = 2
};
/*----------------------------------------------------------------------------
| Options to indicate which negations to perform in float*_muladd()
| Using these differs from negating an input or output before calling
| the muladd function in that this means that a NaN doesn't have its
| sign bit inverted before it is propagated.
*----------------------------------------------------------------------------*/
enum {
float_muladd_negate_c = 1,
float_muladd_negate_product = 2,
float_muladd_negate_result = float_muladd_negate_c | float_muladd_negate_product
};
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point status structure.
*----------------------------------------------------------------------------*/
struct float_status_t
{
#ifdef FLOATX80
int float_rounding_precision; /* floatx80 only */
#endif
int float_rounding_mode;
int float_exception_flags;
int float_exception_masks;
int float_suppress_exception;
int float_nan_handling_mode; /* flag register */
int flush_underflow_to_zero; /* flag register */
int denormals_are_zeros; /* flag register */
};
/*----------------------------------------------------------------------------
| Routine to raise any or all of the software IEC/IEEE floating-point
| exception flags.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void float_raise(struct float_status_t *status, int flags)
{
status->float_exception_flags |= flags;
}
/*----------------------------------------------------------------------------
| Returns raised IEC/IEEE floating-point exception flags.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int get_exception_flags(const struct float_status_t *status)
{
return status->float_exception_flags & ~status->float_suppress_exception;
}
/*----------------------------------------------------------------------------
| Routine to check if any or all of the software IEC/IEEE floating-point
| exceptions are masked.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int float_exception_masked(const struct float_status_t *status, int flag)
{
return status->float_exception_masks & flag;
}
/*----------------------------------------------------------------------------
| Returns current floating point rounding mode specified by status word.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int get_float_rounding_mode(const struct float_status_t *status)
{
return status->float_rounding_mode;
}
/*----------------------------------------------------------------------------
| Returns current floating point precision (floatx80 only).
*----------------------------------------------------------------------------*/
#ifdef FLOATX80
BX_CPP_INLINE int get_float_rounding_precision(const struct float_status_t *status)
{
return status->float_rounding_precision;
}
#endif
/*----------------------------------------------------------------------------
| Returns current floating point NaN operands handling mode specified
| by status word.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int get_float_nan_handling_mode(const struct float_status_t *status)
{
return status->float_nan_handling_mode;
}
/*----------------------------------------------------------------------------
| Raise floating point precision lost up flag (floatx80 only).
*----------------------------------------------------------------------------*/
#ifdef FLOATX80
BX_CPP_INLINE void set_float_rounding_up(struct float_status_t *status)
{
status->float_exception_flags |= RAISE_SW_C1;
}
#endif
/*----------------------------------------------------------------------------
| Returns 1 if the <denormals-are-zeros> feature is supported;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int get_denormals_are_zeros(const struct float_status_t *status)
{
return status->denormals_are_zeros;
}
/*----------------------------------------------------------------------------
| Returns 1 if the <flush-underflow-to-zero> feature is supported;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int get_flush_underflow_to_zero(const struct float_status_t *status)
{
return status->flush_underflow_to_zero;
}
/*----------------------------------------------------------------------------
| Software IEC/IEEE integer-to-floating-point conversion routines.
*----------------------------------------------------------------------------*/
float32 int32_to_float32(Bit32s, struct float_status_t *status);
float64 int32_to_float64(Bit32s);
float32 int64_to_float32(Bit64s, struct float_status_t *status);
float64 int64_to_float64(Bit64s, struct float_status_t *status);
float32 uint32_to_float32(Bit32u, struct float_status_t *status);
float64 uint32_to_float64(Bit32u);
float32 uint64_to_float32(Bit64u, struct float_status_t *status);
float64 uint64_to_float64(Bit64u, struct float_status_t *status);
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision conversion routines.
*----------------------------------------------------------------------------*/
Bit32s float32_to_int32(float32, struct float_status_t *status);
Bit32s float32_to_int32_round_to_zero(float32, struct float_status_t *status);
Bit64s float32_to_int64(float32, struct float_status_t *status);
Bit64s float32_to_int64_round_to_zero(float32, struct float_status_t *status);
Bit32u float32_to_uint32(float32, struct float_status_t *status);
Bit32u float32_to_uint32_round_to_zero(float32, struct float_status_t *status);
Bit64u float32_to_uint64(float32, struct float_status_t *status);
Bit64u float32_to_uint64_round_to_zero(float32, struct float_status_t *status);
float64 float32_to_float64(float32, struct float_status_t *status);
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision operations.
*----------------------------------------------------------------------------*/
float32 float32_round_to_int(float32, Bit8u scale, struct float_status_t *status);
float32 float32_add(float32, float32, struct float_status_t *status);
float32 float32_sub(float32, float32, struct float_status_t *status);
float32 float32_mul(float32, float32, struct float_status_t *status);
float32 float32_div(float32, float32, struct float_status_t *status);
float32 float32_sqrt(float32, struct float_status_t *status);
float32 float32_frc(float32, struct float_status_t *status);
float32 float32_muladd(float32, float32, float32, int flags, struct float_status_t *status);
float32 float32_scalef(float32, float32, struct float_status_t *status);
int float32_compare(float32, float32, int quiet, struct float_status_t *status);
BX_CPP_INLINE float32 float32_round_to_int_one(float32 a, struct float_status_t *status)
{
return float32_round_to_int(a, 0, status);
}
BX_CPP_INLINE float32 float32_fmadd(float32 a, float32 b, float32 c, struct float_status_t *status)
{
return float32_muladd(a, b, c, 0, status);
}
BX_CPP_INLINE float32 float32_fmsub(float32 a, float32 b, float32 c, struct float_status_t *status)
{
return float32_muladd(a, b, c, float_muladd_negate_c, status);
}
BX_CPP_INLINE float32 float32_fnmadd(float32 a, float32 b, float32 c, struct float_status_t *status)
{
return float32_muladd(a, b, c, float_muladd_negate_product, status);
}
BX_CPP_INLINE float32 float32_fnmsub(float32 a, float32 b, float32 c, struct float_status_t *status)
{
return float32_muladd(a, b, c, float_muladd_negate_result, status);
}
BX_CPP_INLINE int float32_compare_two(float32 a, float32 b, struct float_status_t *status)
{
return float32_compare(a, b, 0, status);
}
BX_CPP_INLINE int float32_compare_quiet(float32 a, float32 b, struct float_status_t *status)
{
return float32_compare(a, b, 1, status);
}
float_class_t float32_class(float32);
float32 float32_min(float32 a, float32 b, struct float_status_t *status);
float32 float32_max(float32 a, float32 b, struct float_status_t *status);
float32 float32_minmax(float32 a, float32 b, int is_max, int is_abs, struct float_status_t *status);
float32 float32_getexp(float32 a, struct float_status_t *status);
float32 float32_getmant(float32 a, struct float_status_t *status, int sign_ctrl, int interv);
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision conversion routines.
*----------------------------------------------------------------------------*/
Bit32s float64_to_int32(float64, struct float_status_t *status);
Bit32s float64_to_int32_round_to_zero(float64, struct float_status_t *status);
Bit64s float64_to_int64(float64, struct float_status_t *status);
Bit64s float64_to_int64_round_to_zero(float64, struct float_status_t *status);
Bit32u float64_to_uint32(float64, struct float_status_t *status);
Bit32u float64_to_uint32_round_to_zero(float64, struct float_status_t *status);
Bit64u float64_to_uint64(float64, struct float_status_t *status);
Bit64u float64_to_uint64_round_to_zero(float64, struct float_status_t *status);
float32 float64_to_float32(float64, struct float_status_t *status);
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision operations.
*----------------------------------------------------------------------------*/
float64 float64_round_to_int(float64, Bit8u scale, struct float_status_t *status);
float64 float64_add(float64, float64, struct float_status_t *status);
float64 float64_sub(float64, float64, struct float_status_t *status);
float64 float64_mul(float64, float64, struct float_status_t *status);
float64 float64_div(float64, float64, struct float_status_t *status);
float64 float64_sqrt(float64, struct float_status_t *status);
float64 float64_frc(float64, struct float_status_t *status);
float64 float64_muladd(float64, float64, float64, int flags, struct float_status_t *status);
float64 float64_scalef(float64, float64, struct float_status_t *status);
int float64_compare(float64, float64, int quiet, struct float_status_t *status);
BX_CPP_INLINE float64 float64_round_to_int_one(float64 a, struct float_status_t *status)
{
return float64_round_to_int(a, 0, status);
}
BX_CPP_INLINE float64 float64_fmadd(float64 a, float64 b, float64 c, struct float_status_t *status)
{
return float64_muladd(a, b, c, 0, status);
}
BX_CPP_INLINE float64 float64_fmsub(float64 a, float64 b, float64 c, struct float_status_t *status)
{
return float64_muladd(a, b, c, float_muladd_negate_c, status);
}
BX_CPP_INLINE float64 float64_fnmadd(float64 a, float64 b, float64 c, struct float_status_t *status)
{
return float64_muladd(a, b, c, float_muladd_negate_product, status);
}
BX_CPP_INLINE float64 float64_fnmsub(float64 a, float64 b, float64 c, struct float_status_t *status)
{
return float64_muladd(a, b, c, float_muladd_negate_result, status);
}
BX_CPP_INLINE int float64_compare_two(float64 a, float64 b, struct float_status_t *status)
{
return float64_compare(a, b, 0, status);
}
BX_CPP_INLINE int float64_compare_quiet(float64 a, float64 b, struct float_status_t *status)
{
return float64_compare(a, b, 1, status);
}
float_class_t float64_class(float64);
float64 float64_min(float64 a, float64 b, struct float_status_t *status);
float64 float64_max(float64 a, float64 b, struct float_status_t *status);
float64 float64_minmax(float64 a, float64 b, int is_max, int is_abs, struct float_status_t *status);
float64 float64_getexp(float64 a, struct float_status_t *status);
float64 float64_getmant(float64 a, struct float_status_t *status, int sign_ctrl, int interv);
#ifdef FLOAT16
float32 float16_to_float32(float16, struct float_status_t *status);
float16 float32_to_float16(float32, struct float_status_t *status);
float_class_t float16_class(float16);
#endif
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point types.
*----------------------------------------------------------------------------*/
#ifdef BX_BIG_ENDIAN
typedef struct floatx80 { // leave alignment to compiler
Bit16u exp;
Bit64u fraction;
}; floatx80
#else
typedef struct floatx80 {
Bit64u fraction;
Bit16u exp;
} floatx80;
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE integer-to-floating-point conversion routines.
*----------------------------------------------------------------------------*/
floatx80 int32_to_floatx80(Bit32s);
floatx80 int64_to_floatx80(Bit64s);
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision conversion routines.
*----------------------------------------------------------------------------*/
floatx80 float32_to_floatx80(float32, struct float_status_t *status);
floatx80 float64_to_floatx80(float64, struct float_status_t *status);
Bit32s floatx80_to_int32(floatx80, struct float_status_t *status);
Bit32s floatx80_to_int32_round_to_zero(floatx80, struct float_status_t *status);
Bit64s floatx80_to_int64(floatx80, struct float_status_t *status);
Bit64s floatx80_to_int64_round_to_zero(floatx80, struct float_status_t *status);
float32 floatx80_to_float32(floatx80, struct float_status_t *status);
float64 floatx80_to_float64(floatx80, struct float_status_t *status);
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision operations.
*----------------------------------------------------------------------------*/
floatx80 floatx80_round_to_int(floatx80, struct float_status_t *status);
floatx80 floatx80_add(floatx80, floatx80, struct float_status_t *status);
floatx80 floatx80_sub(floatx80, floatx80, struct float_status_t *status);
floatx80 floatx80_mul(floatx80, floatx80, struct float_status_t *status);
floatx80 floatx80_div(floatx80, floatx80, struct float_status_t *status);
floatx80 floatx80_sqrt(floatx80, struct float_status_t *status);
float_class_t floatx80_class(floatx80);
#ifdef __cplusplus
}
#endif
#endif /* FLOATX80 */
#ifdef FLOAT128
#ifdef BX_BIG_ENDIAN
typedef struct float128 {
Bit64u hi, lo;
} float128;
#else
typedef struct float128 {
Bit64u lo, hi;
} float128;
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE quadruple-precision conversion routines.
*----------------------------------------------------------------------------*/
float128 floatx80_to_float128(floatx80 a, struct float_status_t *status);
floatx80 float128_to_floatx80(float128 a, struct float_status_t *status);
float128 int64_to_float128(Bit64s a);
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision operations.
*----------------------------------------------------------------------------*/
floatx80 floatx80_128_mul(floatx80 a, float128 b, struct float_status_t *status);
/*----------------------------------------------------------------------------
| Software IEC/IEEE quadruple-precision operations.
*----------------------------------------------------------------------------*/
float128 float128_add(float128 a, float128 b, struct float_status_t *status);
float128 float128_sub(float128 a, float128 b, struct float_status_t *status);
float128 float128_mul(float128 a, float128 b, struct float_status_t *status);
float128 float128_div(float128 a, float128 b, struct float_status_t *status);
#ifdef __cplusplus
}
#endif
#endif /* FLOAT128 */
#endif

View File

@@ -1,129 +0,0 @@
/*============================================================================
This C source file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic
Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*============================================================================
* Adapted for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#include "softfloat.h"
#ifdef FLOAT16
#include "softfloat-round-pack.h"
#include "softfloat-specialize.h"
#include "softfloat-macros.h"
/*----------------------------------------------------------------------------
| Determine half-precision floating-point number class
*----------------------------------------------------------------------------*/
float_class_t float16_class(float16 a)
{
Bit16s aExp = extractFloat16Exp(a);
Bit16u aSig = extractFloat16Frac(a);
int aSign = extractFloat16Sign(a);
if(aExp == 0x1F) {
if (aSig == 0)
return (aSign) ? float_negative_inf : float_positive_inf;
return (aSig & 0x200) ? float_QNaN : float_SNaN;
}
if(aExp == 0) {
if (aSig == 0) return float_zero;
return float_denormal;
}
return float_normalized;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the half-precision floating-point value
| `a' to the single-precision floating-point format. The conversion is
| performed according to the IEC/IEEE Standard for Binary Floating-Point
| Arithmetic.
*----------------------------------------------------------------------------*/
float32 float16_to_float32(float16 a, struct float_status_t *status)
{
Bit16u aSig = extractFloat16Frac(a);
Bit16s aExp = extractFloat16Exp(a);
int aSign = extractFloat16Sign(a);
if (aExp == 0x1F) {
if (aSig) return commonNaNToFloat32(float16ToCommonNaN(a, status));
return packFloat32(aSign, 0xFF, 0);
}
if (aExp == 0) {
// ignore denormals_are_zeros flag
if (aSig == 0) return packFloat32(aSign, 0, 0);
float_raise(status, float_flag_denormal);
normalizeFloat16Subnormal(aSig, &aExp, &aSig);
--aExp;
}
return packFloat32(aSign, aExp + 0x70, ((Bit32u) aSig)<<13);
}
/*----------------------------------------------------------------------------
| Returns the result of converting the single-precision floating-point value
| `a' to the half-precision floating-point format. The conversion is
| performed according to the IEC/IEEE Standard for Binary Floating-Point
| Arithmetic.
*----------------------------------------------------------------------------*/
float16 float32_to_float16(float32 a, struct float_status_t *status)
{
Bit32u aSig = extractFloat32Frac(a);
Bit16s aExp = extractFloat32Exp(a);
int aSign = extractFloat32Sign(a);
if (aExp == 0xFF) {
if (aSig) return commonNaNToFloat16(float32ToCommonNaN(a, status));
return packFloat16(aSign, 0x1F, 0);
}
if (aExp == 0) {
if (get_denormals_are_zeros(status)) aSig = 0;
if (aSig == 0) return packFloat16(aSign, 0, 0);
float_raise(status, float_flag_denormal);
}
aSig = shift32RightJamming(aSig, 9);
Bit16u zSig = (Bit16u) aSig;
if (aExp || zSig) {
zSig |= 0x4000;
aExp -= 0x71;
}
return roundAndPackFloat16(aSign, aExp, zSig, status);
}
#endif

View File

@@ -1,367 +0,0 @@
/*============================================================================
This source file is an extension to the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b, written for Bochs (x86 achitecture simulator)
floating point emulation.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*============================================================================
* Written for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#include "softfloatx80.h"
#include "softfloat-round-pack.h"
#include "softfloat-macros.h"
const floatx80 Const_QNaN = packFloatx80(0, floatx80_default_nan_exp, floatx80_default_nan_fraction);
const floatx80 Const_Z = packFloatx80(0, 0x0000, 0);
const floatx80 Const_1 = packFloatx80(0, 0x3fff, BX_CONST64(0x8000000000000000));
const floatx80 Const_L2T = packFloatx80(0, 0x4000, BX_CONST64(0xd49a784bcd1b8afe));
const floatx80 Const_L2E = packFloatx80(0, 0x3fff, BX_CONST64(0xb8aa3b295c17f0bc));
const floatx80 Const_PI = packFloatx80(0, 0x4000, BX_CONST64(0xc90fdaa22168c235));
const floatx80 Const_LG2 = packFloatx80(0, 0x3ffd, BX_CONST64(0x9a209a84fbcff799));
const floatx80 Const_LN2 = packFloatx80(0, 0x3ffe, BX_CONST64(0xb17217f7d1cf79ac));
const floatx80 Const_INF = packFloatx80(0, 0x7fff, BX_CONST64(0x8000000000000000));
/*----------------------------------------------------------------------------
| Commonly used single-precision floating point constants
*----------------------------------------------------------------------------*/
const float32 float32_negative_inf = 0xff800000;
const float32 float32_positive_inf = 0x7f800000;
const float32 float32_negative_zero = 0x80000000;
const float32 float32_positive_zero = 0x00000000;
const float32 float32_negative_one = 0xbf800000;
const float32 float32_positive_one = 0x3f800000;
const float32 float32_max_float = 0x7f7fffff;
const float32 float32_min_float = 0xff7fffff;
/*----------------------------------------------------------------------------
| The pattern for a default generated single-precision NaN.
*----------------------------------------------------------------------------*/
const float32 float32_default_nan = 0xffc00000;
/*----------------------------------------------------------------------------
| Commonly used single-precision floating point constants
*----------------------------------------------------------------------------*/
const float64 float64_negative_inf = BX_CONST64(0xfff0000000000000);
const float64 float64_positive_inf = BX_CONST64(0x7ff0000000000000);
const float64 float64_negative_zero = BX_CONST64(0x8000000000000000);
const float64 float64_positive_zero = BX_CONST64(0x0000000000000000);
const float64 float64_negative_one = BX_CONST64(0xbff0000000000000);
const float64 float64_positive_one = BX_CONST64(0x3ff0000000000000);
const float64 float64_max_float = BX_CONST64(0x7fefffffffffffff);
const float64 float64_min_float = BX_CONST64(0xffefffffffffffff);
/*----------------------------------------------------------------------------
| The pattern for a default generated double-precision NaN.
*----------------------------------------------------------------------------*/
const float64 float64_default_nan = BX_CONST64(0xFFF8000000000000);
/*----------------------------------------------------------------------------
| Returns the result of converting the extended double-precision floating-
| point value `a' to the 16-bit two's complement integer format. The
| conversion is performed according to the IEC/IEEE Standard for Binary
| Floating-Point Arithmetic - which means in particular that the conversion
| is rounded according to the current rounding mode. If `a' is a NaN or the
| conversion overflows, the integer indefinite value is returned.
*----------------------------------------------------------------------------*/
Bit16s floatx80_to_int16(floatx80 a, struct float_status_t *status)
{
if (floatx80_is_unsupported(a)) {
float_raise(status, float_flag_invalid);
return int16_indefinite;
}
Bit32s v32 = floatx80_to_int32(a, status);
if ((v32 > 32767) || (v32 < -32768)) {
status->float_exception_flags = float_flag_invalid; // throw away other flags
return int16_indefinite;
}
return (Bit16s) v32;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the extended double-precision floating-
| point value `a' to the 16-bit two's complement integer format. The
| conversion is performed according to the IEC/IEEE Standard for Binary
| Floating-Point Arithmetic, except that the conversion is always rounded
| toward zero. If `a' is a NaN or the conversion overflows, the integer
| indefinite value is returned.
*----------------------------------------------------------------------------*/
Bit16s floatx80_to_int16_round_to_zero(floatx80 a, struct float_status_t *status)
{
if (floatx80_is_unsupported(a)) {
float_raise(status, float_flag_invalid);
return int16_indefinite;
}
Bit32s v32 = floatx80_to_int32_round_to_zero(a, status);
if ((v32 > 32767) || (v32 < -32768)) {
status->float_exception_flags = float_flag_invalid; // throw away other flags
return int16_indefinite;
}
return (Bit16s) v32;
}
/*----------------------------------------------------------------------------
| Separate the source extended double-precision floating point value `a'
| into its exponent and significand, store the significant back to the
| 'a' and return the exponent. The operation performed is a superset of
| the IEC/IEEE recommended logb(x) function.
*----------------------------------------------------------------------------*/
floatx80 floatx80_extract(floatx80 *a, struct float_status_t *status)
{
/*----------------------------------------------------------------------------
| The pattern for a default generated extended double-precision NaN.
*----------------------------------------------------------------------------*/
const floatx80 floatx80_default_nan = packFloatx80(0, floatx80_default_nan_exp, floatx80_default_nan_fraction);
Bit64u aSig = extractFloatx80Frac(*a);
Bit32s aExp = extractFloatx80Exp(*a);
int aSign = extractFloatx80Sign(*a);
if (floatx80_is_unsupported(*a))
{
float_raise(status, float_flag_invalid);
*a = floatx80_default_nan;
return *a;
}
if (aExp == 0x7FFF) {
if ((Bit64u) (aSig<<1))
{
*a = propagateFloatx80NaNOne(*a, status);
return *a;
}
return packFloatx80(0, 0x7FFF, BX_CONST64(0x8000000000000000));
}
if (aExp == 0)
{
if (aSig == 0) {
float_raise(status, float_flag_divbyzero);
*a = packFloatx80(aSign, 0, 0);
return packFloatx80(1, 0x7FFF, BX_CONST64(0x8000000000000000));
}
float_raise(status, float_flag_denormal);
normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
}
a->exp = (aSign << 15) + 0x3FFF;
a->fraction = aSig;
return int32_to_floatx80(aExp - 0x3FFF);
}
/*----------------------------------------------------------------------------
| Scales extended double-precision floating-point value in operand `a' by
| value `b'. The function truncates the value in the second operand 'b' to
| an integral value and adds that value to the exponent of the operand 'a'.
| The operation performed according to the IEC/IEEE Standard for Binary
| Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
floatx80 floatx80_scale(floatx80 a, floatx80 b, struct float_status_t *status)
{
/*----------------------------------------------------------------------------
| The pattern for a default generated extended double-precision NaN.
*----------------------------------------------------------------------------*/
const floatx80 floatx80_default_nan = packFloatx80(0, floatx80_default_nan_exp, floatx80_default_nan_fraction);
Bit32s aExp, bExp;
Bit64u aSig, bSig;
// handle unsupported extended double-precision floating encodings
if (floatx80_is_unsupported(a) || floatx80_is_unsupported(b))
{
float_raise(status, float_flag_invalid);
return floatx80_default_nan;
}
aSig = extractFloatx80Frac(a);
aExp = extractFloatx80Exp(a);
int aSign = extractFloatx80Sign(a);
bSig = extractFloatx80Frac(b);
bExp = extractFloatx80Exp(b);
int bSign = extractFloatx80Sign(b);
if (aExp == 0x7FFF) {
if ((Bit64u) (aSig<<1) || ((bExp == 0x7FFF) && (Bit64u) (bSig<<1)))
{
return propagateFloatx80NaN(a, b, status);
}
if ((bExp == 0x7FFF) && bSign) {
float_raise(status, float_flag_invalid);
return floatx80_default_nan;
}
if (bSig && (bExp == 0)) float_raise(status, float_flag_denormal);
return a;
}
if (bExp == 0x7FFF) {
if ((Bit64u) (bSig<<1)) return propagateFloatx80NaN(a, b, status);
if ((aExp | aSig) == 0) {
if (! bSign) {
float_raise(status, float_flag_invalid);
return floatx80_default_nan;
}
return a;
}
if (aSig && (aExp == 0)) float_raise(status, float_flag_denormal);
if (bSign) return packFloatx80(aSign, 0, 0);
return packFloatx80(aSign, 0x7FFF, BX_CONST64(0x8000000000000000));
}
if (aExp == 0) {
if (bSig && (bExp == 0)) float_raise(status, float_flag_denormal);
if (aSig == 0) return a;
float_raise(status, float_flag_denormal);
normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
if (bExp < 0x3FFF)
return normalizeRoundAndPackFloatx80(80, aSign, aExp, aSig, 0, status);
}
if (bExp == 0) {
if (bSig == 0) return a;
float_raise(status, float_flag_denormal);
normalizeFloatx80Subnormal(bSig, &bExp, &bSig);
}
if (bExp > 0x400E) {
/* generate appropriate overflow/underflow */
return roundAndPackFloatx80(80, aSign,
bSign ? -0x3FFF : 0x7FFF, aSig, 0, status);
}
if (bExp < 0x3FFF) return a;
int shiftCount = 0x403E - bExp;
bSig >>= shiftCount;
Bit32s scale = (Bit32s) bSig;
if (bSign) scale = -scale; /* -32768..32767 */
return
roundAndPackFloatx80(80, aSign, aExp+scale, aSig, 0, status);
}
/*----------------------------------------------------------------------------
| Determine extended-precision floating-point number class.
*----------------------------------------------------------------------------*/
float_class_t floatx80_class(floatx80 a)
{
Bit32s aExp = extractFloatx80Exp(a);
Bit64u aSig = extractFloatx80Frac(a);
if(aExp == 0) {
if (aSig == 0)
return float_zero;
/* denormal or pseudo-denormal */
return float_denormal;
}
/* valid numbers have the MS bit set */
if (!(aSig & BX_CONST64(0x8000000000000000)))
return float_SNaN; /* report unsupported as SNaNs */
if(aExp == 0x7fff) {
int aSign = extractFloatx80Sign(a);
if (((Bit64u) (aSig<< 1)) == 0)
return (aSign) ? float_negative_inf : float_positive_inf;
return (aSig & BX_CONST64(0x4000000000000000)) ? float_QNaN : float_SNaN;
}
return float_normalized;
}
/*----------------------------------------------------------------------------
| Compare between two extended precision floating point numbers. Returns
| 'float_relation_equal' if the operands are equal, 'float_relation_less' if
| the value 'a' is less than the corresponding value `b',
| 'float_relation_greater' if the value 'a' is greater than the corresponding
| value `b', or 'float_relation_unordered' otherwise.
*----------------------------------------------------------------------------*/
int floatx80_compare(floatx80 a, floatx80 b, int quiet, struct float_status_t *status)
{
float_class_t aClass = floatx80_class(a);
float_class_t bClass = floatx80_class(b);
if (aClass == float_SNaN || bClass == float_SNaN)
{
/* unsupported reported as SNaN */
float_raise(status, float_flag_invalid);
return float_relation_unordered;
}
if (aClass == float_QNaN || bClass == float_QNaN) {
if (! quiet) float_raise(status, float_flag_invalid);
return float_relation_unordered;
}
if (aClass == float_denormal || bClass == float_denormal) {
float_raise(status, float_flag_denormal);
}
int aSign = extractFloatx80Sign(a);
int bSign = extractFloatx80Sign(b);
if (aClass == float_zero) {
if (bClass == float_zero) return float_relation_equal;
return bSign ? float_relation_greater : float_relation_less;
}
if (bClass == float_zero || aSign != bSign) {
return aSign ? float_relation_less : float_relation_greater;
}
Bit64u aSig = extractFloatx80Frac(a);
Bit32s aExp = extractFloatx80Exp(a);
Bit64u bSig = extractFloatx80Frac(b);
Bit32s bExp = extractFloatx80Exp(b);
if (aClass == float_denormal)
normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
if (bClass == float_denormal)
normalizeFloatx80Subnormal(bSig, &bExp, &bSig);
if (aExp == bExp && aSig == bSig)
return float_relation_equal;
int less_than =
aSign ? ((bExp < aExp) || ((bExp == aExp) && (bSig < aSig)))
: ((aExp < bExp) || ((aExp == bExp) && (aSig < bSig)));
if (less_than) return float_relation_less;
return float_relation_greater;
}
int floatx80_compare_two(floatx80 a, floatx80 b, struct float_status_t *status)
{
return floatx80_compare(a, b, 0, status);
}
int floatx80_compare_quiet(floatx80 a, floatx80 b, struct float_status_t *status)
{
return floatx80_compare(a, b, 1, status);
}

View File

@@ -1,121 +0,0 @@
/*============================================================================
This source file is an extension to the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b, written for Bochs (x86 achitecture simulator)
floating point emulation.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*============================================================================
* Written for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#ifndef _SOFTFLOATX80_EXTENSIONS_H_
#define _SOFTFLOATX80_EXTENSIONS_H_
#include "softfloat.h"
#include "softfloat-specialize.h"
/*----------------------------------------------------------------------------
| Software IEC/IEEE integer-to-floating-point conversion routines.
*----------------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif
Bit16s floatx80_to_int16(floatx80, struct float_status_t *status);
Bit16s floatx80_to_int16_round_to_zero(floatx80, struct float_status_t *status);
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision operations.
*----------------------------------------------------------------------------*/
floatx80 floatx80_extract(floatx80 *a, struct float_status_t *status);
floatx80 floatx80_scale(floatx80 a, floatx80 b, struct float_status_t *status);
int floatx80_remainder(floatx80 a, floatx80 b, floatx80 *r, Bit64u *q, struct float_status_t *status);
int floatx80_ieee754_remainder(floatx80 a, floatx80 b, floatx80 *r, Bit64u *q, struct float_status_t *status);
floatx80 f2xm1(floatx80 a, struct float_status_t *status);
floatx80 fyl2x(floatx80 a, floatx80 b, struct float_status_t *status);
floatx80 fyl2xp1(floatx80 a, floatx80 b, struct float_status_t *status);
floatx80 fpatan(floatx80 a, floatx80 b, struct float_status_t *status);
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision trigonometric functions.
*----------------------------------------------------------------------------*/
int fsincos(floatx80 a, floatx80 *sin_a, floatx80 *cos_a, struct float_status_t *status);
int fsin(floatx80 *a, struct float_status_t *status);
int fcos(floatx80 *a, struct float_status_t *status);
int ftan(floatx80 *a, struct float_status_t *status);
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision compare.
*----------------------------------------------------------------------------*/
int floatx80_compare(floatx80, floatx80, int quiet, struct float_status_t *status);
int floatx80_compare_two(floatx80 a, floatx80 b, struct float_status_t *status);
int floatx80_compare_quiet(floatx80 a, floatx80 b, struct float_status_t *status);
#ifdef __cplusplus
}
#endif
/*-----------------------------------------------------------------------------
| Calculates the absolute value of the extended double-precision floating-point
| value `a'. The operation is performed according to the IEC/IEEE Standard
| for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
#ifdef __cplusplus
BX_CPP_INLINE floatx80& floatx80_abs(floatx80 &reg)
#else
BX_CPP_INLINE floatx80 floatx80_abs(floatx80 reg)
#endif
{
reg.exp &= 0x7FFF;
return reg;
}
/*-----------------------------------------------------------------------------
| Changes the sign of the extended double-precision floating-point value 'a'.
| The operation is performed according to the IEC/IEEE Standard for Binary
| Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
#ifdef __cplusplus
BX_CPP_INLINE floatx80& floatx80_chs(floatx80 &reg)
#else
BX_CPP_INLINE floatx80 floatx80_chs(floatx80 reg)
#endif
{
reg.exp ^= 0x8000;
return reg;
}
/*-----------------------------------------------------------------------------
| Commonly used extended double-precision floating-point constants.
*----------------------------------------------------------------------------*/
extern const floatx80 Const_Z;
extern const floatx80 Const_1;
extern const floatx80 Const_L2T;
extern const floatx80 Const_L2E;
extern const floatx80 Const_PI;
extern const floatx80 Const_LG2;
extern const floatx80 Const_LN2;
extern const floatx80 Const_INF;
#endif

View File

@@ -0,0 +1,57 @@
#
# 86Box A hypervisor and IBM PC system emulator that specializes in
# running old operating systems and software designed for IBM
# PC systems and compatibles from 1981 through fairly recent
# system designs based on the PCI bus.
#
# This file is part of the 86Box distribution.
#
# CMake build script.
#
# Authors: David Hrdlička, <hrdlickadavid@outlook.com>
#
# Copyright 2020-2021 David Hrdlička.
#
add_library(softfloat3e OBJECT primitives.c softfloat-specialize.c
extF80_addsub.cc extF80_class.cc extF80_compare.cc
extF80_div.cc extF80_extract.cc extF80_mul.cc extF80_rem.cc extF80_roundToInt.cc
extF80_scale.cc extF80_sqrt.cc extF80_to_f16.cc extF80_to_f32.cc extF80_to_f64.cc
extF80_to_f128.cc extF80_to_i32.cc extF80_to_i32_r_minMag.cc extF80_to_i64.cc
extF80_to_i64_r_minMag.cc extF80_to_ui32.cc extF80_to_ui32_r_minMag.cc extF80_to_ui64.cc
extF80_to_ui64_r_minMag.cc f16_addsub.c f16_class.c f16_compare.c f16_div.c f16_getExp.c
f16_getMant.c f16_minmax.c f16_mul.c f16_mulAdd.c f16_range.c f16_roundToInt.c
f16_sqrt.c f16_to_extF80.cc f16_to_f32.c f16_to_f64.c f16_to_i32.c f16_to_i32_r_minMag.c
f16_to_i64.c f16_to_i64_r_minMag.c f16_to_ui32.c f16_to_ui32_r_minMag.c f16_to_ui64.c
f16_to_ui64_r_minMag.c f32_addsub.c f32_class.c f32_compare.c f32_div.c f32_frc.c
f32_getExp.c f32_getMant.c f32_minmax.c f32_mul.c f32_mulAdd.c f32_range.c
f32_roundToInt.c f32_scalef.c f32_sqrt.c f32_to_extF80.cc f32_to_f16.c f32_to_f64.c
f32_to_f128.cc f32_to_i32.c f32_to_i32_r_minMag.c f32_to_i64.c f32_to_i64_r_minMag.c
f32_to_ui32.c f32_to_ui32_r_minMag.c f32_to_ui64.c f32_to_ui64_r_minMag.c f64_addsub.c
f64_class.c f64_compare.c f64_div.c f64_frc.c f64_getExp.c f64_getMant.c f64_minmax.c
f64_mul.c f64_mulAdd.c f64_range.c f64_roundToInt.c f64_scalef.c f64_sqrt.c f64_to_extF80.cc
f64_to_f16.c f64_to_f32.c f64_to_f128.cc f64_to_i32.c f64_to_i32_r_minMag.c f64_to_i64.c
f64_to_i64_r_minMag.c f64_to_ui32.c f64_to_ui32_r_minMag.c f64_to_ui64.c f64_to_ui64_r_minMag.c
f128_addsub.cc f128_div.cc f128_mul.cc f128_mulAdd.cc f128_roundToInt.cc f128_to_extF80.cc
f128_to_f32.cc f128_to_f64.cc f128_to_i32.cc f128_to_i32_r_minMag.cc f128_to_i64.cc
f128_to_i64_r_minMag.cc f128_to_ui32.cc f128_to_ui32_r_minMag.cc f128_to_ui64.cc
f128_to_ui64_r_minMag.cc i32_to_extF80.cc i32_to_f16.c i32_to_f32.c i32_to_f64.c
i32_to_f128.cc i64_to_extF80.cc i64_to_f16.c i64_to_f32.c i64_to_f64.c i64_to_f128.cc
isNaN.cc isSignalingNaN.cc s_add128.cc s_add256M.c s_addMagsExtF80.cc s_addMagsF16.c
s_addMagsF32.c s_addMagsF64.c s_addMagsF128.cc s_approxRecip_1Ks.c s_approxRecipSqrt_1Ks.c
s_approxRecipSqrt32_1.c s_commonNaNToExtF80UI.cc s_commonNaNToF16UI.c s_commonNaNToF32UI.c
s_commonNaNToF64UI.c s_commonNaNToF128UI.cc s_countLeadingZeros8.c s_countLeadingZeros16.c
s_countLeadingZeros32.c s_countLeadingZeros64.c s_eq128.c s_le128.c s_lt128.c
s_mul64ByShifted32To128.cc s_mul64To128.cc s_mul128By32.cc s_mul128To256M.cc
s_normRoundPackToExtF80.cc s_normRoundPackToF16.c s_normRoundPackToF32.c s_normRoundPackToF64.c
s_normRoundPackToF128.cc s_normSubnormalExtF80Sig.cc s_normSubnormalF16Sig.c
s_normSubnormalF32Sig.c s_normSubnormalF64Sig.c s_normSubnormalF128Sig.cc s_packToExtF80.cc
s_propagateNaNExtF80UI.cc s_propagateNaNF16UI.c s_propagateNaNF32UI.c s_propagateNaNF64UI.c
s_propagateNaNF128UI.cc s_roundPackToExtF80.cc s_roundPackToF16.c s_roundPackToF32.c
s_roundPackToF64.c s_roundPackToF128.cc s_roundToI32.c s_roundToI64.c s_roundToUI32.c
s_roundToUI64.c s_shiftRightJam32.c s_shiftRightJam64.c s_shiftRightJam64Extra.c
s_shiftRightJam256M.c s_shortShiftLeft128.cc s_shortShiftRight128.cc s_shortShiftRightJam64.c
s_shortShiftRightJam64Extra.c s_sub128.cc s_sub256M.c s_subMagsExtF80.cc s_subMagsF16.c
s_subMagsF32.c s_subMagsF64.c s_subMagsF128.cc ui32_to_extF80.cc ui32_to_f16.c ui32_to_f32.c
ui32_to_f64.c ui32_to_f128.cc ui64_to_extF80.cc ui64_to_f16.c ui64_to_f32.c ui64_to_f64.c
ui64_to_f128.cc f2xm1.cc fpatan.cc fprem.cc fsincos.cc fyl2x.cc poly.cc consts.cc)

View File

@@ -0,0 +1,37 @@
License for Berkeley SoftFloat Release 3e
John R. Hauser
2018 January 20
The following applies to the whole of SoftFloat Release 3e as well as to
each source file individually.
Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the
University of California. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions, and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the University nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,49 @@
<HTML>
<HEAD>
<TITLE>Berkeley SoftFloat Package Overview</TITLE>
</HEAD>
<BODY>
<H1>Package Overview for Berkeley SoftFloat Release 3e</H1>
<P>
John R. Hauser<BR>
2018 January 20<BR>
</P>
<P>
Berkeley SoftFloat is a software implementation of binary floating-point that
conforms to the IEEE Standard for Floating-Point Arithmetic.
SoftFloat is distributed in the form of C source code.
Building the SoftFloat sources generates a library file (typically
<CODE>softfloat.a</CODE> or <CODE>libsoftfloat.a</CODE>) containing the
floating-point subroutines.
</P>
<P>
The SoftFloat package is documented in the following files in the
<CODE>doc</CODE> subdirectory:
<BLOCKQUOTE>
<TABLE>
<TR>
<TD><A HREF="doc/SoftFloat.html"><NOBR><CODE>SoftFloat.html</CODE></NOBR></A></TD>
<TD>Documentation for using the SoftFloat functions.</TD>
</TR>
<TR>
<TD><A HREF="doc/SoftFloat-source.html"><NOBR><CODE>SoftFloat-source.html</CODE></NOBR></A></TD>
<TD>Documentation for building SoftFloat.</TD>
</TR>
<TR>
<TD><A HREF="doc/SoftFloat-history.html"><NOBR><CODE>SoftFloat-history.html</CODE></A><CODE>&nbsp;&nbsp;&nbsp;</CODE></NOBR></TD>
<TD>History of the major changes to SoftFloat.</TD>
</TR>
</TABLE>
</BLOCKQUOTE>
Other files in the package comprise the source code for SoftFloat.
</P>
</BODY>

View File

@@ -0,0 +1,21 @@
Package Overview for Berkeley SoftFloat Release 3e
John R. Hauser
2018 January 20
Berkeley SoftFloat is a software implementation of binary floating-point
that conforms to the IEEE Standard for Floating-Point Arithmetic. SoftFloat
is distributed in the form of C source code. Building the SoftFloat sources
generates a library file (typically "softfloat.a" or "libsoftfloat.a")
containing the floating-point subroutines.
The SoftFloat package is documented in the following files in the "doc"
subdirectory:
SoftFloat.html Documentation for using the SoftFloat functions.
SoftFloat-source.html Documentation for building SoftFloat.
SoftFloat-history.html History of the major changes to SoftFloat.
Other files in the package comprise the source code for SoftFloat.

View File

@@ -0,0 +1,14 @@
#ifndef EMU_SF_CONFIG_H
#define EMU_SF_CONFIG_H
/*----------------------------------------------------------------------------
| The `LIT64' macro takes as its argument a textual integer literal and
| if necessary ``marks'' the literal as having a 64-bit integer type.
| For example, the GNU C Compiler (`gcc') requires that 64-bit literals be
| appended with the letters `LL' standing for `long long', which is `gcc's
| name for the 64-bit integer type. Some compilers may allow `LIT64' to be
| defined as the identity macro: `#define LIT64( a ) a'.
*----------------------------------------------------------------------------*/
#define BX_CONST64(a) a##LL
#endif /*EMU_SF_CONFIG_H*/

View File

@@ -0,0 +1,51 @@
/*============================================================================
This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic
Package, Release 3e, by John R. Hauser.
Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of
California. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions, and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions, and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the University nor the names of its contributors may
be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=============================================================================*/
#include <stdio.h>
#include <stdint.h>
#include <86box/86box.h>
#include "../cpu.h"
#include "softfloat-specialize.h"
const floatx80 Const_QNaN = packFloatx80(0, floatx80_default_nan_exp, floatx80_default_nan_fraction);
const floatx80 Const_Z = packFloatx80(0, 0x0000, 0);
const floatx80 Const_1 = packFloatx80(0, 0x3fff, BX_CONST64(0x8000000000000000));
const floatx80 Const_L2T = packFloatx80(0, 0x4000, BX_CONST64(0xd49a784bcd1b8afe));
const floatx80 Const_L2E = packFloatx80(0, 0x3fff, BX_CONST64(0xb8aa3b295c17f0bc));
const floatx80 Const_PI = packFloatx80(0, 0x4000, BX_CONST64(0xc90fdaa22168c235));
const floatx80 Const_LG2 = packFloatx80(0, 0x3ffd, BX_CONST64(0x9a209a84fbcff799));
const floatx80 Const_LN2 = packFloatx80(0, 0x3ffe, BX_CONST64(0xb17217f7d1cf79ac));
const floatx80 Const_INF = packFloatx80(0, 0x7fff, BX_CONST64(0x8000000000000000));

View File

@@ -0,0 +1,258 @@
<HTML>
<HEAD>
<TITLE>Berkeley SoftFloat History</TITLE>
</HEAD>
<BODY>
<H1>History of Berkeley SoftFloat, to Release 3e</H1>
<P>
John R. Hauser<BR>
2018 January 20<BR>
</P>
<H3>Release 3e (2018 January)</H3>
<UL>
<LI>
Changed the default numeric code for optional rounding mode <CODE>odd</CODE>
(round to odd, also known as <EM>jamming</EM>) from 5 to 6.
<LI>
Modified the behavior of rounding mode <CODE>odd</CODE> when rounding to an
integer value (either conversion to an integer format or a
&lsquo;<CODE>roundToInt</CODE>&rsquo; function).
Previously, for those cases only, rounding mode <CODE>odd</CODE> acted the same
as rounding to minimum magnitude.
Now all operations are rounded consistently.
<LI>
Fixed some errors in the specialization code modeling Intel x86 floating-point,
specifically the integers returned on invalid operations and the propagation of
NaN payloads in a few rare cases.
<LI>
Added specialization code modeling ARM floating-point, conforming to VFPv2 or
later.
<LI>
Added an example target for ARM processors.
<LI>
Fixed a minor bug whereby function <CODE>f16_to_ui64</CODE> might return a
different integer than expected in the case that the floating-point operand is
negative.
<LI>
Added example target-specific optimization for GCC, employing GCC instrinsics
and support for <NOBR>128-bit</NOBR> integer arithmetic.
<LI>
Made other minor improvements.
</UL>
<H3>Release 3d (2017 August)</H3>
<UL>
<LI>
Fixed bugs in the square root functions for <NOBR>64-bit</NOBR>
double-precision, <NOBR>80-bit</NOBR> double-extended-precision, and
<NOBR>128-bit</NOBR> quadruple-precision.
For <NOBR>64-bit</NOBR> double-precision (<CODE>f64_sqrt</CODE>), the result
could sometimes be off by <NOBR>1 unit</NOBR> in the last place
(<NOBR>1 ulp</NOBR>) from what it should be.
For the larger formats, the square root could be wrong in a large portion of
the less-significant bits.
(A bug in <CODE>f128_sqrt</CODE> was first reported by Alexei Sibidanov.)
</UL>
<H3>Release 3c (2017 February)</H3>
<UL>
<LI>
Added optional rounding mode <CODE>odd</CODE> (round to odd, also known as
<EM>jamming</EM>).
<LI>
Corrected the documentation concerning non-canonical representations in
<NOBR>80-bit</NOBR> double-extended-precision.
</UL>
<H3>Release 3b (2016 July)</H3>
<UL>
<LI>
Implemented the common <NOBR>16-bit</NOBR> &ldquo;half-precision&rdquo;
floating-point format (<CODE>float16_t</CODE>).
<LI>
Made the integer values returned on invalid conversions to integer formats
be determined by the port-specific specialization instead of being the same for
all ports.
<LI>
Added preprocessor macro <CODE>THREAD_LOCAL</CODE> to allow the floating-point
state (modes and exception flags) to be made per-thread.
<LI>
Modified the provided Makefiles to allow some options to be overridden from the
<CODE>make</CODE> command.
<LI>
Made other minor improvements.
</UL>
<H3>Release 3a (2015 October)</H3>
<UL>
<LI>
Replaced the license text supplied by the University of California, Berkeley.
</UL>
<H3>Release 3 (2015 February)</H3>
<UL>
<LI>
Complete rewrite, funded by the University of California, Berkeley, and
consequently having a different use license than earlier releases.
Major changes included renaming most types and functions, upgrading some
algorithms, restructuring the source files, and making SoftFloat into a true
library.
<LI>
Added functions to convert between floating-point and unsigned integers, both
<NOBR>32-bit</NOBR> and <NOBR>64-bit</NOBR> (<CODE>uint32_t</CODE> and
<CODE>uint64_t</CODE>).
<LI>
Added functions for fused multiply-add, for all supported floating-point
formats except <NOBR>80-bit</NOBR> double-extended-precision.
<LI>
Added support for a fifth rounding mode, <CODE>near_maxMag</CODE> (round to
nearest, with ties to maximum magnitude, away from zero).
<LI>
Dropped the <CODE>timesoftfloat</CODE> program (now part of the Berkeley
TestFloat package).
</UL>
<H3>Release 2c (2015 January)</H3>
<UL>
<LI>
Fixed mistakes affecting some <NOBR>64-bit</NOBR> processors.
<LI>
Further improved the documentation and the wording for the legal restrictions
on using SoftFloat releases <NOBR>through 2c</NOBR> (not applicable to
<NOBR>Release 3</NOBR> or later).
</UL>
<H3>Release 2b (2002 May)</H3>
<UL>
<LI>
Made minor updates to the documentation, including improved wording for the
legal restrictions on using SoftFloat.
</UL>
<H3>Release 2a (1998 December)</H3>
<UL>
<LI>
Added functions to convert between <NOBR>64-bit</NOBR> integers
(<CODE>int64</CODE>) and all supported floating-point formats.
<LI>
Fixed a bug in all <NOBR>64-bit</NOBR>-version square root functions except
<CODE>float32_sqrt</CODE> that caused the result sometimes to be off by
<NOBR>1 unit</NOBR> in the last place (<NOBR>1 ulp</NOBR>) from what it should
be.
(Bug discovered by Paul Donahue.)
<LI>
Improved the Makefiles.
</UL>
<H3>Release 2 (1997 June)</H3>
<UL>
<LI>
Created the <NOBR>64-bit</NOBR> (<CODE>bits64</CODE>) version, adding the
<CODE>floatx80</CODE> and <CODE>float128</CODE> formats.
<LI>
Changed the source directory structure, splitting the sources into a
<CODE>bits32</CODE> and a <CODE>bits64</CODE> version.
Renamed <CODE>environment.h</CODE> to <CODE>milieu.h</CODE> to avoid confusion
with environment variables.
<LI>
Fixed a small error that caused <CODE>float64_round_to_int</CODE> often to
round the wrong way in nearest/even mode when the operand was between
2<SUP>20</SUP> and 2<SUP>21</SUP> and halfway between two integers.
</UL>
<H3>Release 1a (1996 July)</H3>
<UL>
<LI>
Corrected a mistake that caused borderline underflow cases not to raise the
underflow flag when they should have.
(Problem reported by Doug Priest.)
<LI>
Added the <CODE>float_detect_tininess</CODE> variable to control whether
tininess is detected before or after rounding.
</UL>
<H3>Release 1 (1996 July)</H3>
<UL>
<LI>
Original release, based on work done for the International Computer Science
Institute (ICSI) in Berkeley, California.
</UL>
</BODY>

View File

@@ -0,0 +1,686 @@
<HTML>
<HEAD>
<TITLE>Berkeley SoftFloat Source Documentation</TITLE>
</HEAD>
<BODY>
<H1>Berkeley SoftFloat Release 3e: Source Documentation</H1>
<P>
John R. Hauser<BR>
2018 January 20<BR>
</P>
<H2>Contents</H2>
<BLOCKQUOTE>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0>
<COL WIDTH=25>
<COL WIDTH=*>
<TR><TD COLSPAN=2>1. Introduction</TD></TR>
<TR><TD COLSPAN=2>2. Limitations</TD></TR>
<TR><TD COLSPAN=2>3. Acknowledgments and License</TD></TR>
<TR><TD COLSPAN=2>4. SoftFloat Package Directory Structure</TD></TR>
<TR><TD COLSPAN=2>5. Issues for Porting SoftFloat to a New Target</TD></TR>
<TR>
<TD></TD>
<TD>5.1. Standard Headers <CODE>&lt;stdbool.h&gt;</CODE> and
<CODE>&lt;stdint.h&gt;</CODE></TD>
</TR>
<TR><TD></TD><TD>5.2. Specializing Floating-Point Behavior</TD></TR>
<TR><TD></TD><TD>5.3. Macros for Build Options</TD></TR>
<TR><TD></TD><TD>5.4. Adapting a Template Target Directory</TD></TR>
<TR>
<TD></TD><TD>5.5. Target-Specific Optimization of Primitive Functions</TD>
</TR>
<TR><TD COLSPAN=2>6. Testing SoftFloat</TD></TR>
<TR>
<TD COLSPAN=2>7. Providing SoftFloat as a Common Library for Applications</TD>
</TR>
<TR><TD COLSPAN=2>8. Contact Information</TD></TR>
</TABLE>
</BLOCKQUOTE>
<H2>1. Introduction</H2>
<P>
This document gives information needed for compiling and/or porting Berkeley
SoftFloat, a library of C functions implementing binary floating-point
conforming to the IEEE Standard for Floating-Point Arithmetic.
For basic documentation about SoftFloat refer to
<A HREF="SoftFloat.html"><NOBR><CODE>SoftFloat.html</CODE></NOBR></A>.
</P>
<P>
The source code for SoftFloat is intended to be relatively machine-independent
and should be compilable with any ISO-Standard C compiler that also supports
<NOBR>64-bit</NOBR> integers.
SoftFloat has been successfully compiled with the GNU C Compiler
(<CODE>gcc</CODE>) for several platforms.
</P>
<P>
<NOBR>Release 3</NOBR> of SoftFloat was a complete rewrite relative to
<NOBR>Release 2</NOBR> or earlier.
Changes to the interface of SoftFloat functions are documented in
<A HREF="SoftFloat.html"><NOBR><CODE>SoftFloat.html</CODE></NOBR></A>.
The current version of SoftFloat is <NOBR>Release 3e</NOBR>.
</P>
<H2>2. Limitations</H2>
<P>
SoftFloat assumes the computer has an addressable byte size of either 8 or
<NOBR>16 bits</NOBR>.
(Nearly all computers in use today have <NOBR>8-bit</NOBR> bytes.)
</P>
<P>
SoftFloat is written in C and is designed to work with other C code.
The C compiler used must conform at a minimum to the 1989 ANSI standard for the
C language (same as the 1990 ISO standard) and must in addition support basic
arithmetic on <NOBR>64-bit</NOBR> integers.
Earlier releases of SoftFloat included implementations of <NOBR>32-bit</NOBR>
single-precision and <NOBR>64-bit</NOBR> double-precision floating-point that
did not require <NOBR>64-bit</NOBR> integers, but this option is not supported
starting with <NOBR>Release 3</NOBR>.
Since 1999, ISO standards for C have mandated compiler support for
<NOBR>64-bit</NOBR> integers.
A compiler conforming to the 1999 C Standard or later is recommended but not
strictly required.
</P>
<P>
<NOBR>C Standard</NOBR> header files <CODE>&lt;stdbool.h&gt;</CODE> and
<CODE>&lt;stdint.h&gt;</CODE> are required for defining standard Boolean and
integer types.
If these headers are not supplied with the C compiler, minimal substitutes must
be provided.
SoftFloat&rsquo;s dependence on these headers is detailed later in
<NOBR>section 5.1</NOBR>, <I>Standard Headers <CODE>&lt;stdbool.h&gt;</CODE>
and <CODE>&lt;stdint.h&gt;</CODE></I>.
</P>
<H2>3. Acknowledgments and License</H2>
<P>
The SoftFloat package was written by me, <NOBR>John R.</NOBR> Hauser.
<NOBR>Release 3</NOBR> of SoftFloat was a completely new implementation
supplanting earlier releases.
The project to create <NOBR>Release 3</NOBR> (now <NOBR>through 3e</NOBR>) was
done in the employ of the University of California, Berkeley, within the
Department of Electrical Engineering and Computer Sciences, first for the
Parallel Computing Laboratory (Par Lab) and then for the ASPIRE Lab.
The work was officially overseen by Prof. Krste Asanovic, with funding provided
by these sources:
<BLOCKQUOTE>
<TABLE>
<COL>
<COL WIDTH=10>
<COL>
<TR>
<TD VALIGN=TOP><NOBR>Par Lab:</NOBR></TD>
<TD></TD>
<TD>
Microsoft (Award #024263), Intel (Award #024894), and U.C. Discovery
(Award #DIG07-10227), with additional support from Par Lab affiliates Nokia,
NVIDIA, Oracle, and Samsung.
</TD>
</TR>
<TR>
<TD VALIGN=TOP><NOBR>ASPIRE Lab:</NOBR></TD>
<TD></TD>
<TD>
DARPA PERFECT program (Award #HR0011-12-2-0016), with additional support from
ASPIRE industrial sponsor Intel and ASPIRE affiliates Google, Nokia, NVIDIA,
Oracle, and Samsung.
</TD>
</TR>
</TABLE>
</BLOCKQUOTE>
</P>
<P>
The following applies to the whole of SoftFloat <NOBR>Release 3e</NOBR> as well
as to each source file individually.
</P>
<P>
Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the
University of California.
All rights reserved.
</P>
<P>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
<OL>
<LI>
<P>
Redistributions of source code must retain the above copyright notice, this
list of conditions, and the following disclaimer.
</P>
<LI>
<P>
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions, and the following disclaimer in the documentation and/or
other materials provided with the distribution.
</P>
<LI>
<P>
Neither the name of the University nor the names of its contributors may be
used to endorse or promote products derived from this software without specific
prior written permission.
</P>
</OL>
</P>
<P>
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS &ldquo;AS IS&rdquo;,
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE
DISCLAIMED.
IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</P>
<H2>4. SoftFloat Package Directory Structure</H2>
<P>
Because SoftFloat is targeted to multiple platforms, its source code is
slightly scattered between target-specific and target-independent directories
and files.
The supplied directory structure is as follows:
<BLOCKQUOTE>
<PRE>
doc
source
include
8086
8086-SSE
ARM-VFPv2
ARM-VFPv2-defaultNaN
build
template-FAST_INT64
template-not-FAST_INT64
Linux-386-GCC
Linux-386-SSE2-GCC
Linux-x86_64-GCC
Linux-ARM-VFPv2-GCC
Win32-MinGW
Win32-SSE2-MinGW
Win64-MinGW-w64
</PRE>
</BLOCKQUOTE>
The majority of the SoftFloat sources are provided in the <CODE>source</CODE>
directory.
The <CODE>include</CODE> subdirectory contains several header files
(unsurprisingly), while the other subdirectories of <CODE>source</CODE> contain
source files that specialize the floating-point behavior to match particular
processor families:
<BLOCKQUOTE>
<DL>
<DT><CODE>8086</CODE></DT>
<DD>
Intel&rsquo;s older, 8087-derived floating-point, extended to all supported
floating-point types
</DD>
<DT><CODE>8086-SSE</CODE></DT>
<DD>
Intel&rsquo;s x86 processors with Streaming SIMD Extensions (SSE) and later
compatible extensions, having 8087 behavior for <NOBR>80-bit</NOBR>
double-extended-precision (<CODE>extFloat80_t</CODE>) and SSE behavior for
other floating-point types
</DD>
<DT><CODE>ARM-VFPv2</CODE></DT>
<DD>
ARM&rsquo;s VFPv2 or later floating-point, with NaN payload propagation
</DD>
<DT><CODE>ARM-VFPv2-defaultNaN</CODE></DT>
<DD>
ARM&rsquo;s VFPv2 or later floating-point, with the &ldquo;default NaN&rdquo;
option
</DD>
</DL>
</BLOCKQUOTE>
If other specializations are attempted, these would be expected to be other
subdirectories of <CODE>source</CODE> alongside the ones listed above.
Specialization is covered later, in <NOBR>section 5.2</NOBR>, <I>Specializing
Floating-Point Behavior</I>.
</P>
<P>
The <CODE>build</CODE> directory is intended to contain a subdirectory for each
target platform for which a build of the SoftFloat library may be created.
For each build target, the target&rsquo;s subdirectory is where all derived
object files and the completed SoftFloat library (typically
<CODE>softfloat.a</CODE> or <CODE>libsoftfloat.a</CODE>) are created.
The two <CODE>template</CODE> subdirectories are not actual build targets but
contain sample files for creating new target directories.
(The meaning of <CODE>FAST_INT64</CODE> will be explained later.)
</P>
<P>
Ignoring the <CODE>template</CODE> directories, the supplied target directories
are intended to follow a naming system of
<NOBR><CODE>&lt;<I>execution-environment</I>&gt;-&lt;<I>compiler</I>&gt;</CODE></NOBR>.
For the example targets,
<NOBR><CODE>&lt;<I>execution-environment</I>&gt;</CODE></NOBR> is
<NOBR><CODE>Linux-386</CODE></NOBR>, <NOBR><CODE>Linux-386-SSE2</CODE></NOBR>,
<NOBR><CODE>Linux-x86_64</CODE></NOBR>,
<NOBR><CODE>Linux-ARM-VFPv2</CODE></NOBR>, <CODE>Win32</CODE>,
<NOBR><CODE>Win32-SSE2</CODE></NOBR>, or <CODE>Win64</CODE>, and
<NOBR><CODE>&lt;<I>compiler</I>&gt;</CODE></NOBR> is <CODE>GCC</CODE>,
<CODE>MinGW</CODE>, or <NOBR><CODE>MinGW-w64</CODE></NOBR>.
</P>
<P>
All of the supplied target directories are merely examples that may or may not
be correct for compiling on any particular system.
Despite requests, there are currently no plans to include and maintain in the
SoftFloat package the build files needed for a great many users&rsquo;
compilation environments, which can span a huge range of operating systems,
compilers, and other tools.
</P>
<P>
As supplied, each target directory contains two files:
<BLOCKQUOTE>
<PRE>
Makefile
platform.h
</PRE>
</BLOCKQUOTE>
The provided <CODE>Makefile</CODE> is written for GNU <CODE>make</CODE>.
A build of SoftFloat for the specific target is begun by executing the
<CODE>make</CODE> command with the target directory as the current directory.
A completely different build tool can be used if an appropriate
<CODE>Makefile</CODE> equivalent is created.
</P>
<P>
The <CODE>platform.h</CODE> header file exists to provide a location for
additional C declarations specific to the build target.
Every C source file of SoftFloat contains a <CODE>#include</CODE> for
<CODE>platform.h</CODE>.
In many cases, the contents of <CODE>platform.h</CODE> can be as simple as one
or two lines of code.
At the other extreme, to get maximal performance from SoftFloat, it may be
desirable to include in header <CODE>platform.h</CODE> (directly or via
<CODE>#include</CODE>) declarations for numerous target-specific optimizations.
Such possibilities are discussed in the next section, <I>Issues for Porting
SoftFloat to a New Target</I>.
If the target&rsquo;s compiler or library has bugs or other shortcomings,
workarounds for these issues may also be possible with target-specific
declarations in <CODE>platform.h</CODE>, avoiding the need to modify the main
SoftFloat sources.
</P>
<H2>5. Issues for Porting SoftFloat to a New Target</H2>
<H3>5.1. Standard Headers <CODE>&lt;stdbool.h&gt;</CODE> and <CODE>&lt;stdint.h&gt;</CODE></H3>
<P>
The SoftFloat sources make use of standard headers
<CODE>&lt;stdbool.h&gt;</CODE> and <CODE>&lt;stdint.h&gt;</CODE>, which have
been part of the ISO C Standard Library since 1999.
With any recent compiler, these standard headers are likely to be supported,
even if the compiler does not claim complete conformance to the latest ISO C
Standard.
For older or nonstandard compilers, substitutes for
<CODE>&lt;stdbool.h&gt;</CODE> and <CODE>&lt;stdint.h&gt;</CODE> may need to be
created.
SoftFloat depends on these names from <CODE>&lt;stdbool.h&gt;</CODE>:
<BLOCKQUOTE>
<PRE>
bool
true
false
</PRE>
</BLOCKQUOTE>
and on these names from <CODE>&lt;stdint.h&gt;</CODE>:
<BLOCKQUOTE>
<PRE>
uint16_t
uint32_t
uint64_t
int32_t
int64_t
UINT64_C
INT64_C
uint_least8_t
uint_fast8_t
uint_fast16_t
uint_fast32_t
uint_fast64_t
int_fast8_t
int_fast16_t
int_fast32_t
int_fast64_t
</PRE>
</BLOCKQUOTE>
</P>
<H3>5.2. Specializing Floating-Point Behavior</H3>
<P>
The IEEE Floating-Point Standard allows for some flexibility in a conforming
implementation, particularly concerning NaNs.
The SoftFloat <CODE>source</CODE> directory is supplied with some
<I>specialization</I> subdirectories containing possible definitions for this
implementation-specific behavior.
For example, the <CODE>8086</CODE> and <NOBR><CODE>8086-SSE</CODE></NOBR>
subdirectories have source files that specialize SoftFloat&rsquo;s behavior to
match that of Intel&rsquo;s x86 line of processors.
The files in a specialization subdirectory must determine:
<UL>
<LI>
whether tininess for underflow is detected before or after rounding by default;
<LI>
how signaling NaNs are distinguished from quiet NaNs;
<LI>
what (if anything) special happens when exceptions are raised;
<LI>
the default generated quiet NaNs;
<LI>
how NaNs are propagated from function inputs to output; and
<LI>
the integer results returned when conversions to integer type raise the
<I>invalid</I> exception.
</UL>
</P>
<P>
As provided, the build process for a target expects to involve exactly
<EM>one</EM> specialization directory that defines <EM>all</EM> of these
implementation-specific details for the target.
A specialization directory such as <CODE>8086</CODE> is expected to contain a
header file called <CODE>specialize.h</CODE>, together with whatever other
source files are needed to complete the specialization.
</P>
<P>
A new build target may use an existing specialization, such as the ones
provided by the <CODE>8086</CODE> and <NOBR><CODE>8086-SSE</CODE></NOBR>
subdirectories.
If a build target needs a new specialization, different from any existing ones,
it is recommended that a new specialization directory be created for this
purpose.
The <CODE>specialize.h</CODE> header file from any of the provided
specialization subdirectories can be used as a model for what definitions are
needed.
</P>
<H3>5.3. Macros for Build Options</H3>
<P>
The SoftFloat source files adapt the floating-point implementation according to
several C preprocessor macros:
<BLOCKQUOTE>
<DL>
<DT><CODE>LITTLEENDIAN</CODE>
<DD>
Must be defined for little-endian machines; must not be defined for big-endian
machines.
<DT><CODE>INLINE</CODE>
<DD>
Specifies the sequence of tokens used to indicate that a C function should be
inlined.
If macro <CODE>INLINE_LEVEL</CODE> is defined with a value of 1 or higher, this
macro must be defined; otherwise, this macro is ignored and need not be
defined.
For compilers that conform to the C Standard&rsquo;s rules for inline
functions, this macro can be defined as the single keyword <CODE>inline</CODE>.
For other compilers that follow a convention pre-dating the standardization of
<CODE>inline</CODE>, this macro may need to be defined to <CODE>extern</CODE>
<CODE>inline</CODE>.
<DT><CODE>THREAD_LOCAL</CODE>
<DD>
Can be defined to a sequence of tokens that, when appearing at the start of a
variable declaration, indicates to the C compiler that the variable is
<I>per-thread</I>, meaning that each execution thread gets its own separate
instance of the variable.
This macro is used in header <CODE>softfloat.h</CODE> in the declarations of
variables <CODE>softfloat_roundingMode</CODE>,
<CODE>softfloat_detectTininess</CODE>, <CODE>extF80_roundingPrecision</CODE>,
and <CODE>softfloat_exceptionFlags</CODE>.
If macro <CODE>THREAD_LOCAL</CODE> is left undefined, these variables will
default to being ordinary global variables.
Depending on the compiler, possible valid definitions of this macro include
<CODE>_Thread_local</CODE> and <CODE>__thread</CODE>.
</DL>
<DL>
<DT><CODE>SOFTFLOAT_ROUND_ODD</CODE>
<DD>
Can be defined to enable support for optional rounding mode
<CODE>softfloat_round_odd</CODE>.
</DL>
<DL>
<DT><CODE>INLINE_LEVEL</CODE>
<DD>
Can be defined to an integer to determine the degree of inlining requested of
the compiler.
Larger numbers request that more inlining be done.
If this macro is not defined or is defined to a value less <NOBR>than 1</NOBR>
(zero or negative), no inlining is requested.
The maximum effective value is no higher <NOBR>than 5</NOBR>.
Defining this macro to a value greater than 5 is the same as defining it
<NOBR>to 5</NOBR>.
<DT><CODE>SOFTFLOAT_FAST_INT64</CODE>
<DD>
Can be defined to indicate that the build target&rsquo;s implementation of
<NOBR>64-bit</NOBR> arithmetic is efficient.
For newer <NOBR>64-bit</NOBR> processors, this macro should usually be defined.
For very small microprocessors whose buses and registers are <NOBR>8-bit</NOBR>
or <NOBR>16-bit</NOBR> in size, this macro should usually not be defined.
Whether this macro should be defined for a <NOBR>32-bit</NOBR> processor may
depend on the target machine and the applications that will use SoftFloat.
<DT><CODE>SOFTFLOAT_FAST_DIV32TO16</CODE>
<DD>
Can be defined to indicate that the target&rsquo;s division operator
<NOBR>in C</NOBR> (written as <CODE>/</CODE>) is reasonably efficient for
dividing a <NOBR>32-bit</NOBR> unsigned integer by a <NOBR>16-bit</NOBR>
unsigned integer.
Setting this macro may affect the performance of function <CODE>f16_div</CODE>.
<DT><CODE>SOFTFLOAT_FAST_DIV64TO32</CODE>
<DD>
Can be defined to indicate that the target&rsquo;s division operator
<NOBR>in C</NOBR> (written as <CODE>/</CODE>) is reasonably efficient for
dividing a <NOBR>64-bit</NOBR> unsigned integer by a <NOBR>32-bit</NOBR>
unsigned integer.
Setting this macro may affect the performance of division, remainder, and
square root operations other than <CODE>f16_div</CODE>.
</DL>
</BLOCKQUOTE>
</P>
<P>
Following the usual custom <NOBR>for C</NOBR>, for most of these macros (all
except <CODE>INLINE</CODE>, <CODE>THREAD_LOCAL</CODE>, and
<CODE>INLINE_LEVEL</CODE>), the content of any definition is irrelevant;
what matters is a macro&rsquo;s effect on <CODE>#ifdef</CODE> directives.
</P>
<P>
It is recommended that any definitions of macros <CODE>LITTLEENDIAN</CODE>,
<CODE>INLINE</CODE>, and <CODE>THREAD_LOCAL</CODE> be made in a build
target&rsquo;s <CODE>platform.h</CODE> header file, because these macros are
expected to be determined inflexibly by the target machine and compiler.
The other five macros select options and control optimization, and thus might
be better located in the target&rsquo;s Makefile (or its equivalent).
</P>
<H3>5.4. Adapting a Template Target Directory</H3>
<P>
In the <CODE>build</CODE> directory, two <CODE>template</CODE> subdirectories
provide models for new target directories.
Two different templates exist because different functions are needed in the
SoftFloat library depending on whether macro <CODE>SOFTFLOAT_FAST_INT64</CODE>
is defined.
If macro <CODE>SOFTFLOAT_FAST_INT64</CODE> will be defined,
<NOBR><CODE>template-FAST_INT64</CODE></NOBR> is the template to use;
otherwise, <NOBR><CODE>template-not-FAST_INT64</CODE></NOBR> is the appropriate
template.
A new target directory can be created by copying the correct template directory
and editing the files inside.
To avoid confusion, it would be wise to refrain from editing the files within a
template directory directly.
</P>
<H3>5.5. Target-Specific Optimization of Primitive Functions</H3>
<P>
Header file <CODE>primitives.h</CODE> (in directory
<CODE>source/include</CODE>) declares macros and functions for numerous
underlying arithmetic operations upon which many of SoftFloat&rsquo;s
floating-point functions are ultimately built.
The SoftFloat sources include implementations of all of these functions/macros,
written as standard C code, so a complete and correct SoftFloat library can be
created using only the supplied code for all functions.
However, for many targets, SoftFloat&rsquo;s performance can be improved by
substituting target-specific implementations of some of the functions/macros
declared in <CODE>primitives.h</CODE>.
</P>
<P>
For example, <CODE>primitives.h</CODE> declares a function called
<CODE>softfloat_countLeadingZeros32</CODE> that takes an unsigned
<NOBR>32-bit</NOBR> integer as an argument and returns the number of the
integer&rsquo;s most-significant bits that are zeros.
While the SoftFloat sources include an implementation of this function written
in <NOBR>standard C</NOBR>, many processors can perform this same function
directly in only one or two machine instructions.
An alternative, target-specific implementation that maps to those instructions
is likely to be more efficient than the generic C code from the SoftFloat
package.
</P>
<P>
A build target can replace the supplied version of any function or macro of
<CODE>primitives.h</CODE> by defining a macro with the same name in the
target&rsquo;s <CODE>platform.h</CODE> header file.
For this purpose, it may be helpful for <CODE>platform.h</CODE> to
<CODE>#include</CODE> header file <CODE>primitiveTypes.h</CODE>, which defines
types used for arguments and results of functions declared in
<CODE>primitives.h</CODE>.
When a desired replacement implementation is a function, not a macro, it is
sufficient for <CODE>platform.h</CODE> to include the line
<BLOCKQUOTE>
<PRE>
#define &lt;<I>function-name</I>&gt; &lt;<I>function-name</I>&gt;
</PRE>
</BLOCKQUOTE>
where <NOBR><CODE>&lt;<I>function-name</I>&gt;</CODE></NOBR> is the name of the
function.
This technically defines <NOBR><CODE>&lt;<I>function-name</I>&gt;</CODE></NOBR>
as a macro, but one that resolves to the same name, which may then be a
function.
(A preprocessor that conforms to the C Standard is required to limit recursive
macro expansion from being applied more than once.)
</P>
<P>
The supplied header file <CODE>opts-GCC.h</CODE> (in directory
<CODE>source/include</CODE>) provides an example of target-specific
optimization for the GCC compiler.
Each GCC target example in the <CODE>build</CODE> directory has
<BLOCKQUOTE>
<CODE>#include "opts-GCC.h"</CODE>
</BLOCKQUOTE>
in its <CODE>platform.h</CODE> header file.
Before <CODE>opts-GCC.h</CODE> is included, the following macros must be
defined (or not) to control which features are invoked:
<BLOCKQUOTE>
<DL>
<DT><CODE>SOFTFLOAT_BUILTIN_CLZ</CODE></DT>
<DD>
If defined, SoftFloat&rsquo;s internal
&lsquo;<CODE>countLeadingZeros</CODE>&rsquo; functions use intrinsics
<CODE>__builtin_clz</CODE> and <CODE>__builtin_clzll</CODE>.
</DD>
<DT><CODE>SOFTFLOAT_INTRINSIC_INT128</CODE></DT>
<DD>
If defined, SoftFloat makes use of GCC&rsquo;s nonstandard <NOBR>128-bit</NOBR>
integer type <CODE>__int128</CODE>.
</DD>
</DL>
</BLOCKQUOTE>
On some machines, these improvements are observed to increase the speeds of
<CODE>f64_mul</CODE> and <CODE>f128_mul</CODE> by around 20 to 25%, although
other functions receive less dramatic boosts, or none at all.
Results can vary greatly across different platforms.
</P>
<H2>6. Testing SoftFloat</H2>
<P>
SoftFloat can be tested using the <CODE>testsoftfloat</CODE> program by the
same author.
This program is part of the Berkeley TestFloat package available at the Web
page
<A HREF="http://www.jhauser.us/arithmetic/TestFloat.html"><NOBR><CODE>http://www.jhauser.us/arithmetic/TestFloat.html</CODE></NOBR></A>.
The TestFloat package also has a program called <CODE>timesoftfloat</CODE> that
measures the speed of SoftFloat&rsquo;s floating-point functions.
</P>
<H2>7. Providing SoftFloat as a Common Library for Applications</H2>
<P>
Header file <CODE>softfloat.h</CODE> defines the SoftFloat interface as seen by
clients.
If the SoftFloat library will be made a common library for programs on a
system, the supplied <CODE>softfloat.h</CODE> has a couple of deficiencies for
this purpose:
<UL>
<LI>
As supplied, <CODE>softfloat.h</CODE> depends on another header,
<CODE>softfloat_types.h</CODE>, that is not intended for public use but which
must also be visible to the programmer&rsquo;s compiler.
<LI>
More troubling, at the time <CODE>softfloat.h</CODE> is included in a C source
file, macros <CODE>SOFTFLOAT_FAST_INT64</CODE> and <CODE>THREAD_LOCAL</CODE>
must be defined, or not defined, consistent with how these macro were defined
when the SoftFloat library was built.
</UL>
In the situation that new programs may regularly <CODE>#include</CODE> header
file <CODE>softfloat.h</CODE>, it is recommended that a custom, self-contained
version of this header file be created that eliminates these issues.
</P>
<H2>8. Contact Information</H2>
<P>
At the time of this writing, the most up-to-date information about SoftFloat
and the latest release can be found at the Web page
<A HREF="http://www.jhauser.us/arithmetic/SoftFloat.html"><NOBR><CODE>http://www.jhauser.us/arithmetic/SoftFloat.html</CODE></NOBR></A>.
</P>
</BODY>

Some files were not shown because too many files have changed in this diff Show More