* debug: Remove directory.
* pic/*: New files.
* floppy/*: New files.
* cmos/*: New files.
* unmapped/*: New files.
* dma/*: New files.
* pit/*: New files.
* cpu/x86.h: Rename to sid-x86-cpu-wrapper.h.
* cpu/x86.cc: Rename to sid-x86-cpu-wrapper.cc.
* cpu/x86-memory-modes.cc: Rename to sid-x86-memory-modes.cc.
* memory/*: Move to cpu/memory/*.
* fpu/*: Move to cpu/fpu/*.
* bochs.h: Change #include's to reflect new and moved files.
Add sid expansions for A20ADDR(x), BX_INP(addr, len),
BX_OUTP(addr, val, len), BX_RAISE_HLDA(),
BX_SET_ENABLE_A20(enabled), BX_GET_ENABLE_A20(), and
BX_NULL_TIMER_HANDLE.
* components.cxx: Add support for cmos, dma, pic, pit, floppy,
unmapped.
* config.h.in: Set BX_SUPPORT_TASKING, BX_DMA_FLOPPY_IO and
BX_SUPPORT_A20 to 1 by default.
Set SMF macros to 0 for cmos, dma, pic, pit, floppy and unmapped
components.
* configure.in: Add pic, pit, cmos, dma, floppy, and unmapped
Makefiles to AC_OUTPUT.
* cpu/exception-sid.cc: Remove. Merge differences into
cpu/exception.cc.
* cpu/cpu-sid.h: Remove. Merge differences into cpu/cpu.h.
* cpu/cpu-sid.cc: Remove. Merge differences into cpu/cpu.cc.
* cpu/init-sid.cc: Remove. Merge differences into cpu/init.cc.
* cpu/soft_int-sid.cc: Remove.
* cpu/debugstuff-sid.cc: Remove. Merge differences into
cpu/debugstuff.cc.
* cpu/ctrl_xfer32-sid.cc: Remove.
* cpu/fetchdecode-sid.cc: Remove.
* cpu/Makefile.am: Remove references to removed files.
(SUBDIRS) Add memory and fpu.
(SUBLIBS) Add memory/libmemory.la and fpu/libfpu.la.
(INCLUDES) Add memory and fpu directories.
* cpu/cpu.cc: Remove BX_HRQ related FIXME's.
Add interrupt pin support.
* cpu/debugstuff.cc (BX_SUPPORT_SID): Add implementations of
dbg_get_reg, dbg_set_reg, and dbg_get_eflags for when
BX_DEBUGGER isn't defined.
* cpu/io.cc: Remove #if 0's -- no longer needed.
* cpu/io_pro.cc: Likewise.
* gui/x-gui.cc: Change title bar messages.
* keyboard/keyboard.cc: Change keyboard to remove serial delay
pin.
* keyboard/sid-keyboard-wrapper.cc: Add a20-related pins.
Remove serial-delay pin.
Add cmos accessor.
Add trigger-irq pin.
* keyboard/sid-keyboard-wrapper.h: Likewise.
* vga/sid-vga-wrapper.cc: Rename buses from eg. 3b4 to 0x3b4.
Import imagemmap code from generic.cxx.
* vga/vga.cc: Cap number of rows at BX_MAX_TEXT_LINES.
* Makefile.am (SUBDIRLIST): Add pic, pit, cmos, dma, floppy,
unmapped.
Removed fpu, memory.
(SUBLIBLIST): Likewise.
(INCLUDES): Likewise.
+2002-02-14 Thomas Fitzsimmons <fitzsim@redhat.com>
+
+ * debug/debug.h: Move to top-level bochs directory.
+ * debug: Remove directory.
+ * pic/*: New files.
+ * floppy/*: New files.
+ * cmos/*: New files.
+ * unmapped/*: New files.
+ * dma/*: New files.
+ * pit/*: New files.
+ * cpu/x86.h: Rename to sid-x86-cpu-wrapper.h.
+ * cpu/x86.cc: Rename to sid-x86-cpu-wrapper.cc.
+ * cpu/x86-memory-modes.cc: Rename to sid-x86-memory-modes.cc.
+ * memory/*: Move to cpu/memory/*.
+ * fpu/*: Move to cpu/fpu/*.
+ * bochs.h: Change #include's to reflect new and moved files.
+ Add sid expansions for A20ADDR(x), BX_INP(addr, len),
+ BX_OUTP(addr, val, len), BX_RAISE_HLDA(),
+ BX_SET_ENABLE_A20(enabled), BX_GET_ENABLE_A20(), and
+ BX_NULL_TIMER_HANDLE.
+ * components.cxx: Add support for cmos, dma, pic, pit, floppy,
+ unmapped.
+ * config.h.in: Set BX_SUPPORT_TASKING, BX_DMA_FLOPPY_IO and
+ BX_SUPPORT_A20 to 1 by default.
+ Set SMF macros to 0 for cmos, dma, pic, pit, floppy and unmapped
+ components.
+ * configure.in: Add pic, pit, cmos, dma, floppy, and unmapped
+ Makefiles to AC_OUTPUT.
+ * cpu/exception-sid.cc: Remove. Merge differences into
+ cpu/exception.cc.
+ * cpu/cpu-sid.h: Remove. Merge differences into cpu/cpu.h.
+ * cpu/cpu-sid.cc: Remove. Merge differences into cpu/cpu.cc.
+ * cpu/init-sid.cc: Remove. Merge differences into cpu/init.cc.
+ * cpu/soft_int-sid.cc: Remove.
+ * cpu/debugstuff-sid.cc: Remove. Merge differences into
+ cpu/debugstuff.cc.
+ * cpu/ctrl_xfer32-sid.cc: Remove.
+ * cpu/fetchdecode-sid.cc: Remove.
+ * cpu/Makefile.am: Remove references to removed files.
+ (SUBDIRS) Add memory and fpu.
+ (SUBLIBS) Add memory/libmemory.la and fpu/libfpu.la.
+ (INCLUDES) Add memory and fpu directories.
+ * cpu/cpu.cc: Remove BX_HRQ related FIXME's.
+ Add interrupt pin support.
+ * cpu/debugstuff.cc (BX_SUPPORT_SID): Add implementations of
+ dbg_get_reg, dbg_set_reg, and dbg_get_eflags for when
+ BX_DEBUGGER isn't defined.
+ * cpu/io.cc: Remove #if 0's -- no longer needed.
+ * cpu/io_pro.cc: Likewise.
+ * gui/x-gui.cc: Change title bar messages.
+ * keyboard/keyboard.cc: Change keyboard to remove serial delay
+ pin.
+ * keyboard/sid-keyboard-wrapper.cc: Add a20-related pins.
+ Remove serial-delay pin.
+ Add cmos accessor.
+ Add trigger-irq pin.
+ * keyboard/sid-keyboard-wrapper.h: Likewise.
+ * vga/sid-vga-wrapper.cc: Rename buses from eg. 3b4 to 0x3b4.
+ Import imagemmap code from generic.cxx.
+ * vga/vga.cc: Cap number of rows at BX_MAX_TEXT_LINES.
+ * Makefile.am (SUBDIRLIST): Add pic, pit, cmos, dma, floppy,
+ unmapped.
+ Removed fpu, memory.
+ (SUBLIBLIST): Likewise.
+ (INCLUDES): Likewise.
+
2002-01-29 Thomas Fitzsimmons <fitzsim@redhat.com>
* Makefile.am (SUBDIRLIST): Add keyboard.
pkglib_LTLIBRARIES = libx86.la
if SIDTARGET_X86
-SUBDIRLIST = vga gui keyboard fpu cpu memory .
-SUBLIBLIST = vga/libvga.la gui/libgui.la keyboard/libkeyboard.la fpu/libfpu.la cpu/libcpu.la memory/libmemory.la
+SUBDIRLIST = vga gui keyboard pic pit cmos dma floppy unmapped cpu .
+SUBLIBLIST = vga/libvga.la gui/libgui.la keyboard/libkeyboard.la pic/libpic.la pit/libpit.la cmos/libcmos.la dma/libdma.la floppy/libfloppy.la unmapped/libunmapped.la cpu/libcpu.la
else
SUBDIRLIST =
SUBLIBLIST =
SUBDIRS = $(SUBDIRLIST)
-INCLUDES = -I$(top_builddir)/.. -I$(top_builddir)/../../include -I$(srcdir)/../../include -I$(srcdir)/vga -I$(srcdir)/gui -I$(srcdir)/keyboard -I$(srcdir)/cpu -I$(srcdir)/memory -I$(srcdir)/../memory
+INCLUDES = -I$(top_builddir)/.. -I$(top_builddir)/../../include -I$(srcdir)/../../include -I$(srcdir)/vga -I$(srcdir)/gui -I$(srcdir)/keyboard -I$(srcdir)/pic -I$(srcdir)/pit -I$(srcdir)/cmos -I$(srcdir)/dma -I$(srcdir)/floppy -I$(srcdir)/unmapped -I$(srcdir)/cpu -I$(srcdir)/cpu/memory -I$(srcdir)/../memory
libx86_la_SOURCES = components.cxx
libx86_la_LDFLAGS = -module -no-undefined
libx86_la_DEPENDENCIES = $(SUBLIBLIST)
AUTOHEADER = echo "Not running autoheader"
-
ACLOCAL_AMFLAGS = -I ../../config
pkglib_LTLIBRARIES = libx86.la
-@SIDTARGET_X86_TRUE@SUBDIRLIST = @SIDTARGET_X86_TRUE@vga gui keyboard fpu cpu memory .
+@SIDTARGET_X86_TRUE@SUBDIRLIST = @SIDTARGET_X86_TRUE@vga gui keyboard pic pit cmos dma floppy unmapped cpu .
@SIDTARGET_X86_FALSE@SUBDIRLIST =
-@SIDTARGET_X86_TRUE@SUBLIBLIST = @SIDTARGET_X86_TRUE@vga/libvga.la gui/libgui.la keyboard/libkeyboard.la fpu/libfpu.la cpu/libcpu.la memory/libmemory.la
+@SIDTARGET_X86_TRUE@SUBLIBLIST = @SIDTARGET_X86_TRUE@vga/libvga.la gui/libgui.la keyboard/libkeyboard.la pic/libpic.la pit/libpit.la cmos/libcmos.la dma/libdma.la floppy/libfloppy.la unmapped/libunmapped.la cpu/libcpu.la
@SIDTARGET_X86_FALSE@SUBLIBLIST =
SUBDIRS = $(SUBDIRLIST)
-INCLUDES = -I$(top_builddir)/.. -I$(top_builddir)/../../include -I$(srcdir)/../../include -I$(srcdir)/vga -I$(srcdir)/gui -I$(srcdir)/keyboard -I$(srcdir)/cpu -I$(srcdir)/memory -I$(srcdir)/../memory
+INCLUDES = -I$(top_builddir)/.. -I$(top_builddir)/../../include -I$(srcdir)/../../include -I$(srcdir)/vga -I$(srcdir)/gui -I$(srcdir)/keyboard -I$(srcdir)/pic -I$(srcdir)/pit -I$(srcdir)/cmos -I$(srcdir)/dma -I$(srcdir)/floppy -I$(srcdir)/unmapped -I$(srcdir)/cpu -I$(srcdir)/cpu/memory -I$(srcdir)/../memory
libx86_la_SOURCES = components.cxx
libx86_la_LDFLAGS = -module -no-undefined
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
GZIP_ENV = --best
-DIST_SUBDIRS = vga gui keyboard fpu cpu memory .
+DIST_SUBDIRS = vga gui keyboard pic pit cmos dma floppy unmapped cpu .
DEP_FILES = .deps/components.P
SOURCES = $(libx86_la_SOURCES)
OBJECTS = $(libx86_la_OBJECTS)
that new bochs releases can be easily incorporated. The design looks
something like this:
-+-----------------------------------------------------+
-| |
-| x86_cpu object (see cpu/x86.h) |<---+
-| |<-+ |
-| +---------------------------------------------+ | | |
-| | sid_cpu_c object (see cpu/cpu-sid.h) | | | |
-| | | | | |
-| | x86_cpu * ------------------------------------+ |
-| | | | |
-| +---------------------------------------------+ | |
-| +---------------------------------------------+ | |
-| | sid_mem_c object (see memory/memory-sid.h) | | |
-| | | | |
-| | x86_cpu * --------------------------------------+
-| | | |
-| +---------------------------------------------+ |
-+-----------------------------------------------------+
++---------------------------------------------------------+
+| |
+| x86_cpu object (cpu/sid-x86-cpu-wrapper.h) |<---+
+| |<-+ |
+| +-------------------------------------------------+ | | |
+| | bx_cpu_c object (cpu/cpu.h) | | | |
+| | | | | |
+| | x86_cpu * ----------------------------------------+ |
+| | | | |
+| +-------------------------------------------------+ | |
+| +-------------------------------------------------+ | |
+| | sid_mem_c object (cpu/memory/sid-bochs-memory.h)| | |
+| | | | |
+| | x86_cpu * ------------------------------------------+
+| | | |
+| +-------------------------------------------------+ |
++---------------------------------------------------------+
The sid_cpu_c class inherits from bx_cpu_c which is the main bochs cpu
class. Likewise, sid_mem_c inherits from bx_mem_c, the main bochs
#if BX_SUPPORT_SID
# include "config.h" /* generated by configure script from config.h.in */
-# include "debug/debug.h"
+# include "debug.h"
# include "bxversion.h"
#else
# include "config.h" /* generated by configure script from config.h.in */
#else
#define BX_VGA_MEM_READ(addr) (bx_devices.vga->mem_read(addr))
#define BX_VGA_MEM_WRITE(addr, val) bx_devices.vga->mem_write(addr, val)
-#endif
+#endif // BX_SUPPORT_SID
#if BX_SUPPORT_A20
+#if BX_SUPPORT_SID
+# define A20ADDR(x) ( (x) & x86_cpu_component->a20_mask )
+#else
# define A20ADDR(x) ( (x) & bx_pc_system.a20_mask )
+#endif
#else
# define A20ADDR(x) (x)
#endif
//
// #define BX_INP(addr, len) bx_pc_system.inp(addr, len)
// #define BX_OUTP(addr, val, len) bx_pc_system.outp(addr, val, len)
+#if BX_SUPPORT_SID
+// CAUTION: only use one of 1, 2, or 4 for len
+#define BX_INP(addr, len) x86_cpu_component->read_io_memory_##len (addr)
+#define BX_OUTP(addr, val, len) x86_cpu_component->write_io_memory_##len (addr, val)
+#else
#define BX_INP(addr, len) bx_devices.inp(addr, len)
#define BX_OUTP(addr, val, len) bx_devices.outp(addr, val, len)
+#endif
+#if BX_SUPPORT_SID
+#define BX_RAISE_HLDA() x86_cpu_component->drive_hold_acknowledge_pin()
+#else
#define BX_HRQ (bx_pc_system.HRQ)
#define BX_RAISE_HLDA() bx_pc_system.raise_HLDA()
+#endif
#if BX_SUPPORT_SID
#define BX_TICK1()
#else
#define BX_MEM(x) (bx_mem_array[x])
#endif
#if BX_SUPPORT_SID
-#define BX_SET_ENABLE_A20(enabled)
-#define BX_GET_ENABLE_A20() 0
+#define BX_SET_ENABLE_A20(enabled) kbd_component->drive_enable_a20_pin(enabled)
+#define BX_GET_ENABLE_A20() kbd_component->sense_a20_enabled_pin()
#else
#define BX_SET_ENABLE_A20(enabled) bx_pc_system.set_enable_a20(enabled)
#define BX_GET_ENABLE_A20() bx_pc_system.get_enable_a20()
#if BX_PROVIDE_CPU_MEMORY==1
#if BX_SUPPORT_SID
-#include "cpu/cpu-sid.h"
+#include "cpu/cpu.h"
#else
# include "cpu/cpu.h"
#endif
#if BX_SUPPORT_SID
-#include "memory/memory-sid.h"
+#include "cpu/memory/sid-bochs-memory.h"
#else
#include "memory/memory.h"
#endif
#if BX_SUPPORT_SID
#include "vga/vga.h"
#include "keyboard/keyboard.h"
+#include "pic/pic.h"
+#include "pit/pit.h"
+#include "dma/dma.h"
+#include "cmos/cmos.h"
+#include "floppy/floppy.h"
+#include "unmapped/unmapped.h"
#else
#include "pc_system.h"
#include "instrument.h"
+#if BX_SUPPORT_SID
+#define BX_NULL_TIMER_HANDLE 10000 /* set uninitialized timer handles to this */
+#endif
+
#endif /* BX_BOCHS_H */
--- /dev/null
+## Process this with automake to create Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(top_builddir)/../../include -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../../../include -I$(srcdir)/../cpu
+
+noinst_LTLIBRARIES = libcmos.la
+
+libcmos_la_SOURCES = sid-cmos-wrapper.cc sid-cmos-wrapper.h cmos.cc cmos.h
+
+libcmos_la_LDFLAGS = -no-undefined
--- /dev/null
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+APIC_OBJS = @APIC_OBJS@
+AR = @AR@
+AS = @AS@
+AS_DYNAMIC_INCS = @AS_DYNAMIC_INCS@
+AS_DYNAMIC_OBJS = @AS_DYNAMIC_OBJS@
+BX_LOADER_OBJS = @BX_LOADER_OBJS@
+BX_SPLIT_HD_SUPPORT = @BX_SPLIT_HD_SUPPORT@
+CC = @CC@
+CDROM_OBJS = @CDROM_OBJS@
+CD_UP_ONE = @CD_UP_ONE@
+CD_UP_TWO = @CD_UP_TWO@
+CFP = @CFP@
+COMMAND_SEPARATOR = @COMMAND_SEPARATOR@
+CPP_SUFFIX = @CPP_SUFFIX@
+CXX = @CXX@
+CXXFP = @CXXFP@
+DASH = @DASH@
+DEBUGGER_VAR = @DEBUGGER_VAR@
+DISASM_VAR = @DISASM_VAR@
+DLLTOOL = @DLLTOOL@
+DYNAMIC_VAR = @DYNAMIC_VAR@
+EXE = @EXE@
+EXEEXT = @EXEEXT@
+EXTERNAL_DEPENDENCY = @EXTERNAL_DEPENDENCY@
+FPU_GLUE_OBJ = @FPU_GLUE_OBJ@
+FPU_VAR = @FPU_VAR@
+GUI_LINK_OPTS = @GUI_LINK_OPTS@
+GUI_LINK_OPTS_TERM = @GUI_LINK_OPTS_TERM@
+GUI_OBJS = @GUI_OBJS@
+GZIP = @GZIP@
+INLINE_VAR = @INLINE_VAR@
+INSTRUMENT_DIR = @INSTRUMENT_DIR@
+INSTRUMENT_VAR = @INSTRUMENT_VAR@
+IOAPIC_OBJS = @IOAPIC_OBJS@
+IODEV_LIB_VAR = @IODEV_LIB_VAR@
+LD = @LD@
+LIBTOOL = @LIBTOOL@
+LINK = @LINK@
+LN_S = @LN_S@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MAKELIB = @MAKELIB@
+NE2K_OBJS = @NE2K_OBJS@
+NM = @NM@
+NONINLINE_VAR = @NONINLINE_VAR@
+OBJDUMP = @OBJDUMP@
+OFP = @OFP@
+PACKAGE = @PACKAGE@
+PCI_OBJ = @PCI_OBJ@
+PRIMARY_TARGET = @PRIMARY_TARGET@
+RANLIB = @RANLIB@
+READLINE_LIB = @READLINE_LIB@
+RFB_LIBS = @RFB_LIBS@
+RMCOMMAND = @RMCOMMAND@
+SB16_OBJS = @SB16_OBJS@
+SLASH = @SLASH@
+SUFFIX_LINE = @SUFFIX_LINE@
+TAR = @TAR@
+VERSION = @VERSION@
+VIDEO_OBJS = @VIDEO_OBJS@
+sidtarget_arm = @sidtarget_arm@
+sidtarget_m32r = @sidtarget_m32r@
+sidtarget_m68k = @sidtarget_m68k@
+sidtarget_mips = @sidtarget_mips@
+sidtarget_ppc = @sidtarget_ppc@
+sidtarget_x86 = @sidtarget_x86@
+sidtarget_xstormy16 = @sidtarget_xstormy16@
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(top_builddir)/../../include -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../../../include -I$(srcdir)/../cpu
+
+noinst_LTLIBRARIES = libcmos.la
+
+libcmos_la_SOURCES = sid-cmos-wrapper.cc sid-cmos-wrapper.h cmos.cc cmos.h
+
+libcmos_la_LDFLAGS = -no-undefined
+mkinstalldirs = $(SHELL) $(top_srcdir)/../../config/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_LIBS = @X_LIBS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+libcmos_la_LIBADD =
+libcmos_la_OBJECTS = sid-cmos-wrapper.lo cmos.lo
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+DIST_COMMON = Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+GZIP_ENV = --best
+DEP_FILES = .deps/cmos.P .deps/sid-cmos-wrapper.P
+SOURCES = $(libcmos_la_SOURCES)
+OBJECTS = $(libcmos_la_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .cc .lo .o .s
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --foreign cmos/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLTLIBRARIES:
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+
+distclean-noinstLTLIBRARIES:
+
+maintainer-clean-noinstLTLIBRARIES:
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.s.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+libcmos.la: $(libcmos_la_OBJECTS) $(libcmos_la_DEPENDENCIES)
+ $(CXXLINK) $(libcmos_la_LDFLAGS) $(libcmos_la_OBJECTS) $(libcmos_la_LIBADD) $(LIBS)
+.cc.o:
+ $(CXXCOMPILE) -c $<
+.cc.lo:
+ $(LTCXXCOMPILE) -c $<
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = cmos
+
+distdir: $(DISTFILES)
+ here=`cd $(top_builddir) && pwd`; \
+ top_distdir=`cd $(top_distdir) && pwd`; \
+ distdir=`cd $(distdir) && pwd`; \
+ cd $(top_srcdir) \
+ && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --foreign cmos/Makefile
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+ -rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+ @echo '$(COMPILE) -c $<'; \
+ $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.c
+ @echo '$(LTCOMPILE) -c $<'; \
+ $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+
+%.o: %.cc
+ @echo '$(CXXCOMPILE) -c $<'; \
+ $(CXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.cc
+ @echo '$(LTCXXCOMPILE) -c $<'; \
+ $(LTCXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LTLIBRARIES)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-noinstLTLIBRARIES mostlyclean-compile \
+ mostlyclean-libtool mostlyclean-tags mostlyclean-depend \
+ mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-noinstLTLIBRARIES clean-compile clean-libtool \
+ clean-tags clean-depend clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-noinstLTLIBRARIES distclean-compile \
+ distclean-libtool distclean-tags distclean-depend \
+ distclean-generic clean-am
+ -rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-noinstLTLIBRARIES \
+ maintainer-clean-compile maintainer-clean-libtool \
+ maintainer-clean-tags maintainer-clean-depend \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLTLIBRARIES distclean-noinstLTLIBRARIES \
+clean-noinstLTLIBRARIES maintainer-clean-noinstLTLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-libtool distclean-libtool \
+clean-libtool maintainer-clean-libtool tags mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir \
+mostlyclean-depend distclean-depend clean-depend \
+maintainer-clean-depend info-am info dvi-am dvi check check-am \
+installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+
+
+#include "bochs.h"
+#if BX_SUPPORT_SID
+#define LOG_THIS
+#include "sid-cmos-wrapper.h"
+#else
+#define LOG_THIS bx_cmos.
+
+bx_cmos_c bx_cmos;
+#endif
+
+#if BX_USE_CMOS_SMF
+#define this (&bx_cmos)
+#endif
+
+
+// check that BX_NUM_CMOS_REGS is 64 or 128
+#if (BX_NUM_CMOS_REGS == 64)
+#elif (BX_NUM_CMOS_REGS == 128)
+#else
+#error "Invalid BX_NUM_CMOS_REGS value in config.h"
+#endif
+
+
+bx_cmos_c::bx_cmos_c(void)
+{
+#if BX_SUPPORT_SID
+ bx_dbg.cmos = 1;
+#endif
+ setprefix("[CMOS]");
+ settype(CMOSLOG);
+ BX_DEBUG(("Init.\n"));
+}
+
+bx_cmos_c::~bx_cmos_c(void)
+{
+ // nothing for now
+ BX_DEBUG(("Exit.\n"));
+}
+
+
+#if BX_SUPPORT_SID
+void
+bx_cmos_c::init(cmos *cmos_comp)
+#else
+ void
+bx_cmos_c::init(bx_devices_c *d)
+#endif
+{
+ unsigned i;
+
+ // CMOS RAM & RTC
+
+#if BX_SUPPORT_SID
+ cmos_component = cmos_comp;
+ cmos_component->drive_periodic_timer_control_pin (0, 0);
+ cmos_component->drive_one_second_timer_control_pin (0, 0);
+#else
+ BX_CMOS_THIS devices = d;
+
+ BX_CMOS_THIS devices->register_io_read_handler(this,
+ read_handler, 0x0070,
+ "CMOS RAM");
+ BX_CMOS_THIS devices->register_io_read_handler(this,
+ read_handler,
+ 0x0071,
+ "CMOS RAM");
+ BX_CMOS_THIS devices->register_io_write_handler(this,
+ write_handler,
+ 0x0070, "CMOS RAM");
+ BX_CMOS_THIS devices->register_io_write_handler(this,
+ write_handler,
+ 0x0071, "CMOS RAM");
+ BX_CMOS_THIS devices->register_irq(8, "CMOS RTC");
+
+ BX_CMOS_THIS s.periodic_timer_index =
+ bx_pc_system.register_timer(this, periodic_timer_handler,
+ 1000000, 1,0); // continuous, not-active
+ BX_CMOS_THIS s.one_second_timer_index =
+ bx_pc_system.register_timer(this, one_second_timer_handler,
+ 1000000, 1,0); // continuous, not-active
+#endif
+
+ for (i=0; i<BX_NUM_CMOS_REGS; i++) {
+ BX_CMOS_THIS s.reg[i] = 0;
+ }
+
+#if BX_SUPPORT_SID
+ s.timeval = cmos_component->get_time();
+#else
+#if BX_USE_SPECIFIED_TIME0 == 0
+ // ??? this will not be correct for using an image file.
+ // perhaps take values in CMOS and work backwards to find
+ // s.timeval from values read in.
+ BX_CMOS_THIS s.timeval = time(NULL);
+#else
+ BX_CMOS_THIS s.timeval = BX_USE_SPECIFIED_TIME0;
+#endif
+
+ if (bx_options.cmos.time0 == 1)
+ BX_CMOS_THIS s.timeval = time(NULL);
+ else if (bx_options.cmos.time0 != 0)
+ BX_CMOS_THIS s.timeval = bx_options.cmos.time0;
+#endif // BX_SUPPORT_SID
+
+ BX_INFO(("Setting initial clock to: %s",
+ ctime(&(BX_CMOS_THIS s.timeval)) ));
+
+ update_clock();
+
+#if BX_SUPPORT_SID==0
+ // load CMOS from image file if requested.
+ if (bx_options.cmos.cmosImage) {
+ // CMOS image file requested
+ int fd, ret;
+ struct stat stat_buf;
+
+ fd = open(bx_options.cmos.path, O_RDONLY
+#ifdef O_BINARY
+ | O_BINARY
+#endif
+ );
+ if (fd < 0) {
+ BX_PANIC(("trying to open cmos image file '%s'\n",
+ bx_options.cmos.path));
+ }
+ ret = fstat(fd, &stat_buf);
+ if (ret) {
+ BX_PANIC(("CMOS: could not fstat() image file.\n"));
+ }
+ if (stat_buf.st_size != BX_NUM_CMOS_REGS) {
+ BX_PANIC(("CMOS: image file not same size as BX_NUM_CMOS_REGS.\n"));
+ }
+
+ ret = ::read(fd, (bx_ptr_t) BX_CMOS_THIS s.reg, BX_NUM_CMOS_REGS);
+ if (ret != BX_NUM_CMOS_REGS) {
+ BX_PANIC(("CMOS: error reading cmos file.\n"));
+ }
+ close(fd);
+ BX_INFO(("successfuly read from image file '%s'.\n",
+ bx_options.cmos.path));
+ }
+ else {
+ // CMOS values generated
+ BX_CMOS_THIS s.reg[0x0a] = 0x26;
+ BX_CMOS_THIS s.reg[0x0b] = 0x02;
+ BX_CMOS_THIS s.reg[0x0c] = 0x00;
+ BX_CMOS_THIS s.reg[0x0d] = 0x80;
+ }
+#endif // BX_SUPPORT_SID
+}
+
+#if BX_SUPPORT_SID
+void
+bx_cmos_c::load_cmos_image(std::string path)
+{
+ // load CMOS from image
+ int fd, ret;
+ struct stat stat_buf;
+
+ fd = open(path.c_str(), O_RDONLY
+#ifdef O_BINARY
+ | O_BINARY
+#endif
+ );
+ if (fd < 0)
+ {
+ BX_PANIC(("trying to open cmos image file '%s'\n", path.c_str()));
+ }
+ ret = fstat(fd, &stat_buf);
+ if (ret)
+ {
+ BX_PANIC(("CMOS: could not fstat() image file.\n"));
+ }
+ if (stat_buf.st_size != BX_NUM_CMOS_REGS)
+ {
+ BX_PANIC(("CMOS: image file not same size as BX_NUM_CMOS_REGS.\n"));
+ }
+
+ ret = ::read(fd, (bx_ptr_t) BX_CMOS_THIS s.reg, BX_NUM_CMOS_REGS);
+ if (ret != BX_NUM_CMOS_REGS)
+ {
+ BX_PANIC(("CMOS: error reading cmos file.\n"));
+ }
+ close(fd);
+ BX_INFO(("successfuly read from image file '%s'.\n", path.c_str()));
+}
+
+void
+bx_cmos_c::generate_cmos_values(void)
+{
+#if BX_SUPPORT_SID
+ BX_CMOS_THIS s.reg[0x2d] |= 0x20; // system boot sequence A:, C:
+#endif
+ // CMOS values generated
+ BX_CMOS_THIS s.reg[0x0a] = 0x26;
+ BX_CMOS_THIS s.reg[0x0b] = 0x02;
+ BX_CMOS_THIS s.reg[0x0c] = 0x00;
+ BX_CMOS_THIS s.reg[0x0d] = 0x80;
+}
+#endif // BX_SUPPORT_SID
+
+ void
+bx_cmos_c::reset(void)
+{
+ BX_CMOS_THIS s.cmos_mem_address = 0;
+
+ // RESET affects the following registers:
+ // CRA: no effects
+ // CRB: bits 4,5,6 forced to 0
+ // CRC: bits 4,5,6,7 forced to 0
+ // CRD: no effects
+ BX_CMOS_THIS s.reg[0x0b] &= 0x8f;
+ BX_CMOS_THIS s.reg[0x0c] = 0;
+
+#if BX_SUPPORT_SID
+ if (cmos_component)
+ cmos_component->drive_one_second_timer_control_pin(1000000, 1);
+ else
+ {
+ cerr << "cmos: Drive init pin before other cmos pins." << endl;
+ exit(1);
+ }
+#else
+ // One second timer for updating clock & alarm functions
+ bx_pc_system.activate_timer(BX_CMOS_THIS s.one_second_timer_index,
+ 1000000, 1);
+#endif
+
+ // handle periodic interrupt rate select
+ BX_CMOS_THIS CRA_change();
+}
+
+ void
+bx_cmos_c::CRA_change(void)
+{
+ unsigned nibble;
+
+ // Periodic Interrupt timer
+ nibble = BX_CMOS_THIS s.reg[0x0a] & 0x0f;
+ if (nibble == 0) {
+ // No Periodic Interrupt Rate when 0, deactivate timer
+#if BX_SUPPORT_SID
+ if (cmos_component)
+ cmos_component->drive_periodic_timer_control_pin(0, 0);
+ else
+ {
+ cerr << "cmos: Drive init pin before other cmos pins." << endl;
+ exit(1);
+ }
+#else
+ bx_pc_system.deactivate_timer(BX_CMOS_THIS s.periodic_timer_index);
+#endif
+ BX_CMOS_THIS s.periodic_interval_usec = (Bit32u) -1; // max value
+ }
+ else {
+ // values 0001b and 0010b are the same as 1000b and 1001b
+ if (nibble <= 2)
+ nibble += 7;
+ BX_CMOS_THIS s.periodic_interval_usec = (unsigned) (1000000.0L /
+ (32768.0L / (1 << (nibble - 1))));
+
+ // if Periodic Interrupt Enable bit set, activate timer
+ if ( BX_CMOS_THIS s.reg[0x0b] & 0x40 )
+#if BX_SUPPORT_SID
+ if (cmos_component)
+ cmos_component->drive_periodic_timer_control_pin(BX_CMOS_THIS s.periodic_interval_usec, 1);
+ else
+ {
+ cerr << "cmos: Drive init pin before other cmos pins." << endl;
+ exit(1);
+ }
+#else
+ bx_pc_system.activate_timer(BX_CMOS_THIS s.periodic_timer_index,
+ BX_CMOS_THIS s.periodic_interval_usec, 1);
+#endif
+ else
+#if BX_SUPPORT_SID
+ if (cmos_component)
+ cmos_component->drive_periodic_timer_control_pin(0, 0);
+ else
+ {
+ cerr << "cmos: Drive init pin before other cmos pins." << endl;
+ exit(1);
+ }
+#else
+ bx_pc_system.deactivate_timer(BX_CMOS_THIS s.periodic_timer_index);
+#endif
+ }
+}
+
+
+ // static IO port read callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ Bit32u
+bx_cmos_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_CMOS_SMF
+ bx_cmos_c *class_ptr = (bx_cmos_c *) this_ptr;
+
+ return( class_ptr->read(address, io_len) );
+}
+
+ Bit32u
+bx_cmos_c::read(Bit32u address, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif
+ Bit8u ret8;
+
+ if (io_len > 1)
+ BX_PANIC(("cmos: io read from address %08x len=%u\n",
+ (unsigned) address, (unsigned) io_len));
+
+ if (bx_dbg.cmos)
+ BX_INFO(("CMOS read of CMOS register 0x%x\n",
+ (unsigned) BX_CMOS_THIS s.cmos_mem_address));
+
+
+ switch (address) {
+ case 0x0071:
+ if (BX_CMOS_THIS s.cmos_mem_address >= BX_NUM_CMOS_REGS) {
+ BX_PANIC(("unsupported cmos io read, register(0x%02x)!\n",
+ (unsigned) BX_CMOS_THIS s.cmos_mem_address));
+ }
+
+ ret8 = BX_CMOS_THIS s.reg[BX_CMOS_THIS s.cmos_mem_address];
+ // all bits of Register C are cleared after a read occurs.
+ if (BX_CMOS_THIS s.cmos_mem_address == 0x0c)
+ BX_CMOS_THIS s.reg[0x0c] = 0x00;
+ return(ret8);
+ break;
+
+ default:
+ BX_PANIC(("unsupported cmos read, address=%0x%x!\n",
+ (unsigned) address));
+ return(0);
+ break;
+ }
+}
+
+
+ // static IO port write callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ void
+bx_cmos_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_CMOS_SMF
+ bx_cmos_c *class_ptr = (bx_cmos_c *) this_ptr;
+
+ class_ptr->write(address, value, io_len);
+}
+
+ void
+bx_cmos_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_CMOS_SMF
+
+ if (io_len > 1)
+ BX_PANIC(("cmos: io write to address %08x len=%u\n",
+ (unsigned) address, (unsigned) io_len));
+
+ if (bx_dbg.cmos)
+ BX_INFO(("CMOS write to address: 0x%x = 0x%x\n",
+ (unsigned) address, (unsigned) value));
+
+
+ switch (address) {
+ case 0x0070:
+#if (BX_NUM_CMOS_REGS == 64)
+ BX_CMOS_THIS s.cmos_mem_address = value & 0x3F;
+#else
+ BX_CMOS_THIS s.cmos_mem_address = value & 0x7F;
+#endif
+ break;
+
+ case 0x0071:
+ if (BX_CMOS_THIS s.cmos_mem_address >= BX_NUM_CMOS_REGS) {
+ BX_PANIC(("unsupported cmos io write, register(0x%02x)=%02x!\n",
+ (unsigned) BX_CMOS_THIS s.cmos_mem_address, (unsigned) value));
+ return;
+ }
+ switch (BX_CMOS_THIS s.cmos_mem_address) {
+ case 0x00: // seconds
+ case 0x01: // seconds alarm
+ case 0x02: // minutes
+ case 0x03: // minutes alarm
+ case 0x04: // hours
+ case 0x05: // hours alarm
+ case 0x06: // day of the week
+ case 0x07: // day of the month
+ case 0x08: // month
+ case 0x09: // year
+ //BX_INFO(("write reg %02xh: value = %02xh\n",
+ // (unsigned) BX_CMOS_THIS s.cmos_mem_address, (unsigned) value);
+ BX_CMOS_THIS s.reg[BX_CMOS_THIS s.cmos_mem_address] = value;
+ return;
+ break;
+
+ case 0x0a: // Control Register A
+ // bit 7: Update in Progress (read-only)
+ // 1 = signifies time registers will be updated within 244us
+ // 0 = time registers will not occur before 244us
+ // note: this bit reads 0 when CRB bit 7 is 1
+ // bit 6..4: Divider Chain Control
+ // 000 oscillator disabled
+ // 001 oscillator disabled
+ // 010 Normal operation
+ // 011 TEST
+ // 100 TEST
+ // 101 TEST
+ // 110 Divider Chain RESET
+ // 111 Divider Chain RESET
+ // bit 3..0: Periodic Interrupt Rate Select
+ // 0000 None
+ // 0001 3.90625 ms
+ // 0010 7.8125 ms
+ // 0011 122.070 us
+ // 0100 244.141 us
+ // 0101 488.281 us
+ // 0110 976.562 us
+ // 0111 1.953125 ms
+ // 1000 3.90625 ms
+ // 1001 7.8125 ms
+ // 1010 15.625 ms
+ // 1011 31.25 ms
+ // 1100 62.5 ms
+ // 1101 125 ms
+ // 1110 250 ms
+ // 1111 500 ms
+
+ unsigned dcc;
+ dcc = (value >> 4) & 0x07;
+ if (dcc != 0x02) {
+ BX_PANIC(("cmos: CRA: divider chain control 0x%x\n", dcc));
+ }
+ BX_CMOS_THIS s.reg[0x0a] = value & 0x7f;
+ BX_CMOS_THIS CRA_change();
+ return;
+ break;
+
+ case 0x0b: // Control Register B
+ // bit 0: Daylight Savings Enable
+ // 1 = enable daylight savings
+ // 0 = disable daylight savings
+ // bit 1: 24/12 houre mode
+ // 1 = 24 hour format
+ // 0 = 12 hour format
+ // bit 2: Data Mode
+ // 1 = binary format
+ // 0 = BCD format
+ // bit 3: "square wave enable"
+ // Not supported and always read as 0
+ // bit 4: Update Ended Interrupt Enable
+ // 1 = enable generation of update ended interrupt
+ // 0 = disable
+ // bit 5: Alarm Interrupt Enable
+ // 1 = enable generation of alarm interrupt
+ // 0 = disable
+ // bit 6: Periodic Interrupt Enable
+ // 1 = enable generation of periodic interrupt
+ // 0 = disable
+ // bit 7: Set mode
+ // 1 = user copy of time is "frozen" allowing time registers
+ // to be accessed without regard for an occurance of an update
+ // 0 = time updates occur normally
+
+ // can not handle binary or 12-hour mode yet.
+ if (value & 0x04)
+ BX_PANIC(("cmos: write status reg B, binary format enabled.\n"));
+ if ( !(value & 0x02) )
+ BX_PANIC(("cmos: write status reg B, 12 hour mode enabled.\n"));
+
+ value &= 0xf7; // bit3 always 0
+ // Note: setting bit 7 clears bit 4
+ if (value & 0x80)
+ value &= 0xef;
+
+ unsigned prev_CRB;
+ prev_CRB = BX_CMOS_THIS s.reg[0x0b];
+ BX_CMOS_THIS s.reg[0x0b] = value;
+ if ( (prev_CRB & 0x40) != (value & 0x40) ) {
+ // Periodic Interrupt Enabled changed
+ if (prev_CRB & 0x40) {
+ // transition from 1 to 0, deactivate timer
+#if BX_SUPPORT_SID
+ if (cmos_component)
+ cmos_component->drive_periodic_timer_control_pin(0, 0);
+ else
+ {
+ cerr << "cmos: Drive init pin before other cmos pins." << endl;
+ exit(1);
+ }
+#else
+ bx_pc_system.deactivate_timer(
+ BX_CMOS_THIS s.periodic_timer_index);
+#endif
+ }
+ else {
+ // transition from 0 to 1
+ // if rate select is not 0, activate timer
+ if ( (BX_CMOS_THIS s.reg[0x0a] & 0x0f) != 0 ) {
+#if BX_SUPPORT_SID
+ if (cmos_component)
+ cmos_component->drive_periodic_timer_control_pin(BX_CMOS_THIS s.periodic_interval_usec, 1);
+ else
+ {
+ cerr << "cmos: Drive init pin before other cmos pins." << endl;
+ exit(1);
+ }
+#else
+ bx_pc_system.activate_timer(
+ BX_CMOS_THIS s.periodic_timer_index,
+ BX_CMOS_THIS s.periodic_interval_usec, 1);
+#endif
+ }
+ }
+ }
+ return;
+ break;
+
+ case 0x0c: // Control Register C
+ case 0x0d: // Control Register D
+ BX_PANIC(("cmos: write to control register 0x%x (read-only)\n",
+ BX_CMOS_THIS s.cmos_mem_address));
+ break;
+
+ case 0x0e: // diagnostic status
+ BX_INFO(("write register 0Eh: %02x\n", (unsigned) value));;
+ break;
+
+ case 0x0f: // shutdown status
+ switch (value) {
+ case 0x00: /* proceed with normal POST (soft reset) */
+ if (bx_dbg.reset)
+ BX_INFO(("Reg 0F set to 0: shutdown action = normal POST\n"));;
+ break;
+ case 0x02: /* shutdown after memory test */
+ if (bx_dbg.reset)
+ BX_INFO(("Reg 0Fh: request to change shutdown action"
+ " to shutdown after memory test\n"));
+ break;
+ case 0x03:
+ BX_INFO(("Reg 0Fh(03) : Shutdown after memory test !\n"));;
+ break;
+ case 0x04: /* jump to disk bootstrap routine */
+ BX_INFO(("Reg 0Fh: request to change shutdown action "
+ "to jump to disk bootstrap routine.\n"));
+ break;
+ case 0x06:
+ BX_INFO(("Reg 0Fh(06) : Shutdown after memory test !\n"));;
+ break;
+ case 0x09: /* return to BIOS extended memory block move
+ (interrupt 15h, func 87h was in progress) */
+ if (bx_dbg.reset)
+ BX_INFO(("Reg 0Fh: request to change shutdown action "
+ "to return to BIOS extended memory block move.\n"));
+ break;
+ case 0x0a: /* jump to DWORD pointer at 40:67 */
+ if (bx_dbg.reset)
+ BX_INFO(("Reg 0Fh: request to change shutdown action"
+ " to jump to DWORD at 40:67\n"));
+ break;
+ default:
+ BX_PANIC(("unsupported cmos io write to reg F, case %x!\n",
+ (unsigned) value));
+ break;
+ }
+ break;
+
+ default:
+ BX_INFO(("write reg %02xh: value = %02xh\n",
+ (unsigned) BX_CMOS_THIS s.cmos_mem_address, (unsigned) value));
+ break;
+ }
+
+ BX_CMOS_THIS s.reg[BX_CMOS_THIS s.cmos_mem_address] = value;
+ break;
+ }
+}
+
+
+ void
+bx_cmos_c::checksum_cmos(void)
+{
+ unsigned i;
+ Bit16u sum;
+
+ sum = 0;
+ for (i=0x10; i<=0x2d; i++) {
+ sum += BX_CMOS_THIS s.reg[i];
+ }
+ BX_CMOS_THIS s.reg[0x2e] = (sum >> 8) & 0xff; /* checksum high */
+ BX_CMOS_THIS s.reg[0x2f] = (sum & 0xff); /* checksum low */
+}
+
+#if BX_SUPPORT_SID
+void
+bx_cmos_c::periodic_timer_handler(void)
+{
+ // if periodic interrupts are enabled, trip IRQ 8, and
+ // update status register C
+ if (s.reg[0x0b] & 0x40)
+ {
+ s.reg[0x0c] |= 0xc0; // Interrupt Request, Periodic Int
+ if (cmos_component)
+ cmos_component->drive_trigger_irq_pin();
+ else
+ {
+ cerr << "cmos: Drive init pin before other cmos pins." << endl;
+ exit(1);
+ }
+ }
+}
+
+void
+bx_cmos_c::one_second_timer_handler(void)
+{
+ // update internal time/date buffer
+ s.timeval++;
+
+ // Dont update CMOS user copy of time/date if CRB bit7 is 1
+ // Nothing else do to
+ if (s.reg[0x0b] & 0x80)
+ return;
+
+ update_clock();
+
+ // if update interrupts are enabled, trip IRQ 8, and
+ // update status register C
+ if (s.reg[0x0b] & 0x10)
+ {
+ s.reg[0x0c] |= 0x90; // Interrupt Request, Update Ended
+ if (cmos_component)
+ cmos_component->drive_trigger_irq_pin();
+ else
+ {
+ cerr << "cmos: Drive init pin before other cmos pins." << endl;
+ exit(1);
+ }
+ }
+
+ // compare CMOS user copy of time/date to alarm time/date here
+ if (s.reg[0x0b] & 0x20)
+ {
+ // Alarm interrupts enabled
+ Boolean alarm_match = 1;
+ if ((s.reg[0x01] & 0xc0) != 0xc0)
+ {
+ // seconds alarm not in dont care mode
+ if (s.reg[0x00] != s.reg[0x01])
+ alarm_match = 0;
+ }
+ if ((s.reg[0x03] & 0xc0) != 0xc0)
+ {
+ // minutes alarm not in dont care mode
+ if (s.reg[0x02] != s.reg[0x03])
+ alarm_match = 0;
+ }
+ if ((s.reg[0x05] & 0xc0) != 0xc0)
+ {
+ // hours alarm not in dont care mode
+ if (s.reg[0x04] != s.reg[0x05])
+ alarm_match = 0;
+ }
+ if (alarm_match)
+ {
+ s.reg[0x0c] |= 0xa0; // Interrupt Request, Alarm Int
+ if (cmos_component)
+ cmos_component->drive_trigger_irq_pin();
+ else
+ {
+ cerr << "cmos: Drive init pin before other cmos pins." << endl;
+ exit(1);
+ }
+ }
+ }
+}
+#else
+ void
+bx_cmos_c::periodic_timer_handler(void *this_ptr)
+{
+ bx_cmos_c *class_ptr = (bx_cmos_c *) this_ptr;
+
+ // if periodic interrupts are enabled, trip IRQ 8, and
+ // update status register C
+ if (class_ptr->s.reg[0x0b] & 0x40) {
+ class_ptr->s.reg[0x0c] |= 0xc0; // Interrupt Request, Periodic Int
+ class_ptr->devices->pic->trigger_irq(8);
+ }
+}
+
+ void
+bx_cmos_c::one_second_timer_handler(void *this_ptr)
+{
+ bx_cmos_c *class_ptr = (bx_cmos_c *) this_ptr;
+
+ // update internal time/date buffer
+ class_ptr->s.timeval++;
+
+ // Dont update CMOS user copy of time/date if CRB bit7 is 1
+ // Nothing else do to
+ if (class_ptr->s.reg[0x0b] & 0x80)
+ return;
+
+ class_ptr->update_clock();
+
+ // if update interrupts are enabled, trip IRQ 8, and
+ // update status register C
+ if (class_ptr->s.reg[0x0b] & 0x10) {
+ class_ptr->s.reg[0x0c] |= 0x90; // Interrupt Request, Update Ended
+ class_ptr->devices->pic->trigger_irq(8);
+ }
+
+ // compare CMOS user copy of time/date to alarm time/date here
+ if (class_ptr->s.reg[0x0b] & 0x20) {
+ // Alarm interrupts enabled
+ Boolean alarm_match = 1;
+ if ( (class_ptr->s.reg[0x01] & 0xc0) != 0xc0 ) {
+ // seconds alarm not in dont care mode
+ if (class_ptr->s.reg[0x00] != class_ptr->s.reg[0x01])
+ alarm_match = 0;
+ }
+ if ( (class_ptr->s.reg[0x03] & 0xc0) != 0xc0 ) {
+ // minutes alarm not in dont care mode
+ if (class_ptr->s.reg[0x02] != class_ptr->s.reg[0x03])
+ alarm_match = 0;
+ }
+ if ( (class_ptr->s.reg[0x05] & 0xc0) != 0xc0 ) {
+ // hours alarm not in dont care mode
+ if (class_ptr->s.reg[0x04] != class_ptr->s.reg[0x05])
+ alarm_match = 0;
+ }
+ if (alarm_match) {
+ class_ptr->s.reg[0x0c] |= 0xa0; // Interrupt Request, Alarm Int
+ class_ptr->devices->pic->trigger_irq(8);
+ }
+ }
+}
+#endif
+
+
+ void
+bx_cmos_c::update_clock()
+{
+ struct tm *time_calendar;
+ unsigned year, month, day, century;
+ Bit8u val_bcd;
+
+ time_calendar = localtime(& BX_CMOS_THIS s.timeval);
+
+ // update seconds
+ val_bcd =
+ ((time_calendar->tm_sec / 10) << 4) |
+ (time_calendar->tm_sec % 10);
+ BX_CMOS_THIS s.reg[0x00] = val_bcd;
+
+ // update minutes
+ val_bcd =
+ ((time_calendar->tm_min / 10) << 4) |
+ (time_calendar->tm_min % 10);
+ BX_CMOS_THIS s.reg[0x02] = val_bcd;
+
+ // update hours
+ val_bcd =
+ ((time_calendar->tm_hour / 10) << 4) |
+ (time_calendar->tm_hour % 10);
+ BX_CMOS_THIS s.reg[0x04] = val_bcd;
+
+ // update day of the week
+ day = time_calendar->tm_wday + 1; // 0..6 to 1..7
+ BX_CMOS_THIS s.reg[0x06] = ((day / 10) << 4) | (day % 10);
+
+ // update day of the month
+ day = time_calendar->tm_mday;
+ BX_CMOS_THIS s.reg[0x07] = ((day / 10) << 4) | (day % 10);
+
+ // update month
+ month = time_calendar->tm_mon + 1;
+ BX_CMOS_THIS s.reg[0x08] = ((month / 10) << 4) | (month % 10);
+
+ // update year
+ year = time_calendar->tm_year % 100;
+ BX_CMOS_THIS s.reg[0x09] = ((year / 10) << 4) | (year % 10);
+
+ // update century
+ century = (time_calendar->tm_year / 100) + 19;
+ BX_CMOS_THIS s.reg[0x32] = ((century / 10) << 4) | (century % 10);
+}
--- /dev/null
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+
+#if BX_SUPPORT_SID
+#include <string>
+#endif
+
+
+#if BX_USE_CMOS_SMF
+# define BX_CMOS_SMF static
+# define BX_CMOS_THIS bx_cmos.
+#else
+# define BX_CMOS_SMF
+# define BX_CMOS_THIS this->
+#endif
+
+
+#if BX_SUPPORT_SID
+class cmos;
+#endif
+class bx_cmos_c : public logfunctions {
+public:
+ bx_cmos_c(void);
+ ~bx_cmos_c(void);
+
+#if BX_SUPPORT_SID
+ BX_CMOS_SMF void init(cmos *cmos_comp);
+#else
+ BX_CMOS_SMF void init(bx_devices_c *);
+#endif
+ BX_CMOS_SMF void checksum_cmos(void);
+ BX_CMOS_SMF void reset(void);
+
+ struct {
+ int periodic_timer_index;
+ Bit32u periodic_interval_usec;
+ int one_second_timer_index;
+ time_t timeval;
+ Bit8u cmos_mem_address;
+
+ Bit8u reg[BX_NUM_CMOS_REGS];
+ } s; // state information
+
+private:
+#if BX_SUPPORT_SID
+ cmos *cmos_component;
+#else
+ bx_devices_c *devices;
+#endif
+
+ static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+ static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+#if BX_SUPPORT_SID
+ public:
+#endif // BX_SUPPORT_SID
+#if !BX_USE_CMOS_SMF
+ Bit32u read(Bit32u address, unsigned io_len);
+ void write(Bit32u address, Bit32u value, unsigned len);
+#endif
+
+#if BX_SUPPORT_SID
+ void periodic_timer_handler(void);
+ void one_second_timer_handler(void);
+ void load_cmos_image(std::string path);
+ void generate_cmos_values(void);
+#else
+public:
+ static void periodic_timer_handler(void *);
+ static void one_second_timer_handler(void *);
+#endif
+private:
+ BX_CMOS_SMF void update_clock(void);
+ BX_CMOS_SMF void CRA_change(void);
+ };
+
+
+#if BX_SUPPORT_SID
+extern bx_cmos_c bx_cmos;
+#endif
--- /dev/null
+// sid-cmos-wrapper.cc - SID import of the bochs cmos component. -*- C++ -*-
+
+// Copyright (C) 1999, 2000, 2001, 2002 Red Hat.
+// This file is part of SID and is licensed under the GPL.
+// See the file COPYING.SID for conditions for redistribution.
+
+#include "sid-cmos-wrapper.h"
+
+cmos::cmos ()
+ : init_pin(this, & cmos::init),
+ reset_pin(this, & cmos::reset),
+ image_load_pin(this, & cmos::image_load),
+ periodic_timer_pin(this, & cmos::periodic_timer),
+ one_second_timer_pin(this, & cmos::one_second_timer),
+ register_0x10 (& this->register_bus, host_int_4(0x10), little_int_1(0xff),
+ true, true, this, & cmos::set_register_0x10, & cmos::get_register_0x10),
+ register_0x14 (& this->register_bus, host_int_4(0x14), little_int_1(0xff),
+ true, true, this, & cmos::set_register_0x14, & cmos::get_register_0x14),
+ ports_0x70_0x71_bus(this, & cmos::read_port_0x70_0x71, & cmos::write_port_0x70_0x71),
+ cmos_irq_number(8), use_host_time(true), start_time(917385580), use_image_file(false)
+{
+ add_pin("trigger-irq", & this->trigger_irq_pin);
+
+ add_pin("periodic-timer-control", & this->periodic_timer_control_pin);
+ add_pin("one-second-timer-control", & this->one_second_timer_control_pin);
+
+ add_pin("init", & this->init_pin);
+ add_pin("reset", & this->reset_pin);
+ add_pin("image-load", & this->image_load_pin);
+ add_pin("periodic-timer", & this->periodic_timer_pin);
+ add_pin("one-second-timer", & this->one_second_timer_pin);
+ add_pin("host-time", & this->host_time_pin);
+ add_pin("time-query", & this->time_query_pin);
+
+ add_bus("ports-0x70-0x71", & this->ports_0x70_0x71_bus);
+ add_bus("registers", & this->register_bus);
+
+ add_attribute("image-file", & this->image_file_path, "setting");
+ add_attribute("use-image-file?", & this->use_image_file, "setting");
+ add_attribute("irq-number", & this->cmos_irq_number, "setting");
+ add_attribute("use-host-time?", & this->use_host_time, "setting");
+ add_attribute("start-time", & this->start_time, "setting");
+}
+
+void
+cmos::init(host_int_4)
+{
+ bx_cmos.init(this);
+ bx_cmos.checksum_cmos();
+}
+
+void
+cmos::reset(host_int_4)
+{
+ bx_cmos.reset();
+}
+
+void
+cmos::image_load(host_int_4)
+{
+ if (use_image_file)
+ bx_cmos.load_cmos_image(image_file_path);
+ else
+ bx_cmos.generate_cmos_values();
+}
+
+void
+cmos::periodic_timer(host_int_4)
+{
+ bx_cmos.periodic_timer_handler();
+}
+
+void
+cmos::one_second_timer(host_int_4)
+{
+ bx_cmos.one_second_timer_handler();
+}
+
+void
+cmos::drive_trigger_irq_pin(void)
+{
+ trigger_irq_pin.drive(cmos_irq_number);
+}
+
+void
+cmos::drive_periodic_timer_control_pin(host_int_4 value, bool regular)
+{
+ host_int_4 code = value | (regular << 31);
+
+ periodic_timer_control_pin.drive(code);
+}
+
+void
+cmos::drive_one_second_timer_control_pin(host_int_4 value, bool regular)
+{
+ host_int_4 code = value | (regular << 31);
+
+ one_second_timer_control_pin.drive(code);
+}
+
+host_int_4
+cmos::get_time(void)
+{
+ static host_int_4 host_start_time = host_time_pin.sense();
+
+ time_query_pin.drive(1);
+
+ if (use_host_time)
+ return host_time_pin.sense();
+ else
+ return start_time + (host_time_pin.sense() - host_start_time);
+}
+
+bus::status
+cmos::read_port_0x70_0x71 (host_int_4 addr, little_int_1 mask, little_int_1 & data)
+{
+ addr += 0x70;
+ data = bx_cmos.read(addr, 1);
+ return bus::ok;
+}
+
+bus::status
+cmos::write_port_0x70_0x71 (host_int_4 addr, little_int_1 mask, little_int_1 data)
+{
+ addr += 0x70;
+ bx_cmos.write(addr, data, 1);
+ return bus::ok;
+}
+
+void
+cmos::set_register_0x10 (little_int_1 data, little_int_1 mask)
+{
+ bx_cmos.s.reg[0x10] = data;
+}
+
+little_int_1
+cmos::get_register_0x10 (void)
+{
+ return bx_cmos.s.reg[0x10];
+}
+
+void
+cmos::set_register_0x14 (little_int_1 data, little_int_1 mask)
+{
+ bx_cmos.s.reg[0x14] = data;
+}
+
+little_int_1
+cmos::get_register_0x14 (void)
+{
+ return bx_cmos.s.reg[0x14];
+}
--- /dev/null
+// sid-cmos-wrapper.h - SID import of the bochs cmos component. -*- C++ -*-
+
+// Copyright (C) 1999, 2000, 2001, 2002 Red Hat.
+// This file is part of SID and is licensed under the GPL.
+// See the file COPYING.SID for conditions for redistribution.
+
+#ifndef SID_CMOS_WRAPPER_DEF_H
+#define SID_CMOS_WRAPPER_DEF_H 1
+
+#include <sidtypes.h>
+#include <sidcomp.h>
+#include <sidcomputil.h>
+#include <sidpinutil.h>
+#include <sidbusutil.h>
+#include <sidattrutil.h>
+#include <sidcpuutil.h>
+#include <sidpinattrutil.h>
+#include <sidmiscutil.h>
+#include <sidwatchutil.h>
+#include <sidso.h>
+
+#include "bochs.h"
+
+using sid::component;
+using sid::bus;
+using sid::host_int_4;
+using sid::little_int_1;
+using sidutil::callback_word_bus;
+using sidutil::callback_pin;
+using sidutil::output_pin;
+using sidutil::input_pin;
+using sidutil::callback_control_register;
+using sidutil::control_register_bus;
+using sidutil::fixed_control_register;
+
+class cmos : public sidutil::fixed_pin_map_component,
+ public sidutil::no_accessor_component,
+ public sidutil::fixed_attribute_map_component,
+ public sidutil::no_relation_component,
+ public sidutil::fixed_bus_map_component
+{
+public:
+ cmos();
+ ~cmos() throw() {};
+
+ void init(host_int_4);
+ void reset(host_int_4);
+ void image_load(host_int_4);
+ void periodic_timer(host_int_4);
+ void one_second_timer(host_int_4);
+
+ void drive_trigger_irq_pin(void);
+ void drive_periodic_timer_control_pin(host_int_4 value, bool regular);
+ void drive_one_second_timer_control_pin(host_int_4 value, bool regular);
+ host_int_4 get_time(void);
+
+protected:
+
+ callback_pin<cmos> init_pin;
+ callback_pin<cmos> reset_pin;
+ callback_pin<cmos> image_load_pin;
+ callback_pin<cmos> periodic_timer_pin;
+ callback_pin<cmos> one_second_timer_pin;
+ input_pin host_time_pin;
+
+ output_pin trigger_irq_pin;
+ output_pin periodic_timer_control_pin;
+ output_pin one_second_timer_control_pin;
+ output_pin time_query_pin;
+
+ bus::status read_port_0x70_0x71 (host_int_4 addr, little_int_1 mask, little_int_1 & data);
+ bus::status write_port_0x70_0x71 (host_int_4 addr, little_int_1 mask, little_int_1 data);
+
+ callback_word_bus<cmos, little_int_1> ports_0x70_0x71_bus;
+
+ // register_bus must be declared before the control_registers
+ // because member constructors are called in the order in which
+ // they're declared
+ control_register_bus<little_int_1> register_bus;
+
+ void set_register_0x10 (little_int_1 data, little_int_1 mask);
+ little_int_1 get_register_0x10 (void);
+
+ void set_register_0x14 (little_int_1 data, little_int_1 mask);
+ little_int_1 get_register_0x14 (void);
+
+ callback_control_register<little_int_1, cmos> register_0x10;
+ callback_control_register<little_int_1, cmos> register_0x14;
+
+ bool use_image_file;
+ std::string image_file_path;
+ host_int_4 cmos_irq_number;
+ bool use_host_time;
+ host_int_4 start_time;
+ bx_cmos_c bx_cmos;
+};
+#endif // SID_CMOS_WRAPPER_DEF_H
#include <vector>
#include <string>
-#include "x86.h"
+#include "sid-x86-cpu-wrapper.h"
#include "sid-vga-wrapper.h"
#if HAVE_X11_XOS_H
#include "x-gui.h"
#endif
+#include "sid-cmos-wrapper.h"
+#include "sid-dma-wrapper.h"
#include "sid-keyboard-wrapper.h"
+#include "sid-pic-wrapper.h"
+#include "sid-pit-wrapper.h"
+#include "sid-floppy-wrapper.h"
+#include "sid-unmapped-wrapper.h"
using std::vector;
using std::string;
#if HAVE_X11_XOS_H
types.push_back("sid-io-vga-x");
#endif
+ types.push_back("hw-cmos-x86");
+ types.push_back("hw-dma-x86");
types.push_back("hw-input-keyboard");
+ types.push_back("hw-interrupt-x86");
+ types.push_back("hw-timer-x86");
+ types.push_back("hw-disk-floppy");
+ types.push_back("hw-bochs-misc");
#endif
return types;
else if(typeName == "sid-io-vga-x")
return new x_gui();
#endif
+ else if(typeName == "hw-cmos-x86")
+ return new cmos();
+ else if(typeName == "hw-dma-x86")
+ return new dma();
else if(typeName == "hw-input-keyboard")
return new keyboard();
+ else if(typeName == "hw-interrupt-x86")
+ return new pic();
+ else if(typeName == "hw-timer-x86")
+ return new pit();
+ else if(typeName == "hw-disk-floppy")
+ return new floppy();
+ else if(typeName == "hw-bochs-misc")
+ return new unmapped();
}
catch (...) { }
#endif
return;
}
#endif
- keyboard *d4 = dynamic_cast<keyboard *>(c);
+ cmos *d4 = dynamic_cast<cmos *>(c);
if(d4)
{
delete d4;
return;
}
+ dma *d5 = dynamic_cast<dma *>(c);
+ if(d5)
+ {
+ delete d5;
+ return;
+ }
+ keyboard *d6 = dynamic_cast<keyboard *>(c);
+ if(d6)
+ {
+ delete d6;
+ return;
+ }
+ pic *d7 = dynamic_cast<pic *>(c);
+ if(d7)
+ {
+ delete d7;
+ return;
+ }
+ pit *d8 = dynamic_cast<pit *>(c);
+ if(d8)
+ {
+ delete d8;
+ return;
+ }
+ floppy *d9 = dynamic_cast<floppy *>(c);
+ if(d9)
+ {
+ delete d9;
+ return;
+ }
+ unmapped *d10 = dynamic_cast<unmapped *>(c);
+ if(d10)
+ {
+ delete d10;
+ return;
+ }
#endif
}
// 1 = use settable A20 line. (normal)
// 0 = A20 is like the rest of the address lines
-#define BX_SUPPORT_A20 0
+#define BX_SUPPORT_A20 1
// Processor Instructions Per Second
// To find out what value to use for the 'ips' directive
// you're environment doesn't require it, you can change
// it to 0.
-#define BX_DMA_FLOPPY_IO 0
+#define BX_DMA_FLOPPY_IO 1
// Default number of Megs of memory to emulate. The
// then set this to 0.
//
-#define BX_SUPPORT_TASKING 0
+#define BX_SUPPORT_TASKING 1
// CPU level emulation. Default level is set in
// multiple instances of a device class
#define BX_USE_HD_SMF 1 // Hard drive
-#define BX_USE_CMOS_SMF 1 // CMOS
-#define BX_USE_DMA_SMF 1 // DMA
-#define BX_USE_FD_SMF 1 // Floppy
+#define BX_USE_CMOS_SMF 0 // CMOS
+#define BX_USE_DMA_SMF 0 // DMA
+#define BX_USE_FD_SMF 0 // Floppy
#define BX_USE_KEY_SMF 0 // Keyboard
#define BX_USE_PAR_SMF 1 // Parallel
-#define BX_USE_PIC_SMF 1 // PIC
-#define BX_USE_PIT_SMF 1 // PIT
+#define BX_USE_PIC_SMF 0 // PIC
+#define BX_USE_PIT_SMF 0 // PIT
#define BX_USE_SER_SMF 1 // Serial
-#define BX_USE_UM_SMF 1 // Unmapped
+#define BX_USE_UM_SMF 0 // Unmapped
#define BX_USE_VGA_SMF 0 // VGA
#define BX_USE_SB16_SMF 1 // Sound (SB 16)
#define BX_USE_DEV_SMF 1 // System Devices (port92)
echo $ac_n "checking ARM family support""... $ac_c" 1>&6
-echo "configure:5677: checking ARM family support" >&5
+echo "configure:5734: checking ARM family support" >&5
echo "$ac_t""$sidtarget_arm" 1>&6
echo $ac_n "checking X86 family support""... $ac_c" 1>&6
-echo "configure:5691: checking X86 family support" >&5
+echo "configure:5748: checking X86 family support" >&5
echo "$ac_t""$sidtarget_x86" 1>&6
echo $ac_n "checking MIPS family support""... $ac_c" 1>&6
-echo "configure:5705: checking MIPS family support" >&5
+echo "configure:5778: checking MIPS family support" >&5
echo "$ac_t""$sidtarget_mips" 1>&6
echo $ac_n "checking M32R family support""... $ac_c" 1>&6
-echo "configure:5719: checking M32R family support" >&5
+echo "configure:5792: checking M32R family support" >&5
echo "$ac_t""$sidtarget_m32r" 1>&6
echo $ac_n "checking M68K family support""... $ac_c" 1>&6
-echo "configure:5733: checking M68K family support" >&5
+echo "configure:5806: checking M68K family support" >&5
echo "$ac_t""$sidtarget_m68k" 1>&6
echo $ac_n "checking PPC family support""... $ac_c" 1>&6
-echo "configure:5747: checking PPC family support" >&5
+echo "configure:5836: checking PPC family support" >&5
echo "$ac_t""$sidtarget_ppc" 1>&6
echo $ac_n "checking Sanyo Xstormy16 family support""... $ac_c" 1>&6
-echo "configure:5761: checking Sanyo Xstormy16 family support" >&5
+echo "configure:5927: checking Sanyo Xstormy16 family support" >&5
ac_given_srcdir=$srcdir
ac_given_INSTALL="$INSTALL"
-trap 'rm -fr `echo "Makefile vga/Makefile gui/Makefile keyboard/Makefile cpu/Makefile memory/Makefile fpu/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+trap 'rm -fr `echo "Makefile vga/Makefile gui/Makefile keyboard/Makefile pic/Makefile pit/Makefile cmos/Makefile dma/Makefile floppy/Makefile unmapped/Makefile cpu/Makefile cpu/memory/Makefile cpu/fpu/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
EOF
cat >> $CONFIG_STATUS <<EOF
cat >> $CONFIG_STATUS <<EOF
-CONFIG_FILES=\${CONFIG_FILES-"Makefile vga/Makefile gui/Makefile keyboard/Makefile cpu/Makefile memory/Makefile fpu/Makefile"}
+CONFIG_FILES=\${CONFIG_FILES-"Makefile vga/Makefile gui/Makefile keyboard/Makefile pic/Makefile pit/Makefile cmos/Makefile dma/Makefile floppy/Makefile unmapped/Makefile cpu/Makefile cpu/memory/Makefile cpu/fpu/Makefile"}
EOF
cat >> $CONFIG_STATUS <<\EOF
for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
dnl Perform --target/--enable-targets processing.
CY_SIDTARGET_CHECK
-AC_OUTPUT(Makefile vga/Makefile gui/Makefile keyboard/Makefile cpu/Makefile memory/Makefile fpu/Makefile)
+AC_OUTPUT(Makefile vga/Makefile gui/Makefile keyboard/Makefile pic/Makefile pit/Makefile cmos/Makefile dma/Makefile floppy/Makefile unmapped/Makefile cpu/Makefile cpu/memory/Makefile cpu/fpu/Makefile)
AUTOMAKE_OPTIONS = foreign
-## sid/include in build tree bochs/cpu component/bochs sid/include in src tree bochs/memory
-INCLUDES = -I$(top_builddir)/../../include -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../../../include -I$(srcdir)/../memory -I$(srcdir)/../debug
+SUBDIRS = memory fpu
-noinst_LTLIBRARIES = libcpu.la
+SUBLIBS = memory/libmemory.la fpu/libfpu.la
+
+INCLUDES = -I$(top_builddir)/../../include -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../../../include -I$(srcdir)/memory
-libcpu_la_SOURCES = exception-sid.cc cpu.cc cpu.h cpu-sid.h cpu-sid.cc init-sid.cc state_file.h main-hack.cc x86.cc access.cc ctrl_xfer8.cc flag_ctrl.cc mult32.cc shift16.cc ctrl_xfer_pro.cc flag_ctrl_pro.cc mult8.cc shift32.cc arith16.cc data_xfer16.cc init.cc paging.cc shift8.cc arith32.cc data_xfer32.cc io.cc proc_ctrl.cc soft_int.cc soft_int-sid.cc arith8.cc data_xfer8.cc io_pro.cc protect_ctrl.cc stack16.cc bcd.cc debugstuff.cc debugstuff-sid.cc lazy_flags.cc protect_ctrl_pro.cc stack32.cc bit.cc decode16.cc logical16.cc resolve16.cc stack_pro.cc decode32.cc logical32.cc resolve32.cc string.cc ctrl_xfer16.cc exception.cc logical8.cc segment_ctrl.cc tasking.cc ctrl_xfer32.cc ctrl_xfer32-sid.cc fetchdecode.cc fetchdecode-sid.cc mult16.cc segment_ctrl_pro.cc vm8086.cc lazy_flags.h x86.h x86-memory-modes.cc
+noinst_LTLIBRARIES = libcpu.la
+libcpu_la_SOURCES = cpu.cc cpu.h state_file.h main-hack.cc sid-x86-cpu-wrapper.cc access.cc ctrl_xfer8.cc flag_ctrl.cc mult32.cc shift16.cc ctrl_xfer_pro.cc flag_ctrl_pro.cc mult8.cc shift32.cc arith16.cc data_xfer16.cc init.cc paging.cc shift8.cc arith32.cc data_xfer32.cc io.cc proc_ctrl.cc soft_int.cc arith8.cc data_xfer8.cc io_pro.cc protect_ctrl.cc stack16.cc bcd.cc debugstuff.cc lazy_flags.cc protect_ctrl_pro.cc stack32.cc bit.cc decode16.cc logical16.cc resolve16.cc stack_pro.cc decode32.cc logical32.cc resolve32.cc string.cc ctrl_xfer16.cc exception.cc logical8.cc segment_ctrl.cc tasking.cc ctrl_xfer32.cc fetchdecode.cc mult16.cc segment_ctrl_pro.cc vm8086.cc lazy_flags.h sid-x86-cpu-wrapper.h sid-x86-memory-modes.cc
libcpu_la_LDFLAGS = -no-undefined
+libcpu_la_LIBADD = $(SUBLIBS)
+libcpu_la_DEPENDENCIES = $(SUBLIBS)
AUTOMAKE_OPTIONS = foreign
-INCLUDES = -I$(top_builddir)/../../include -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../../../include -I$(srcdir)/../memory -I$(srcdir)/../debug
+SUBDIRS = memory fpu
-noinst_LTLIBRARIES = libcpu.la
+SUBLIBS = memory/libmemory.la fpu/libfpu.la
+
+INCLUDES = -I$(top_builddir)/../../include -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../../../include -I$(srcdir)/memory
-libcpu_la_SOURCES = exception-sid.cc cpu.cc cpu.h cpu-sid.h cpu-sid.cc init-sid.cc state_file.h main-hack.cc x86.cc access.cc ctrl_xfer8.cc flag_ctrl.cc mult32.cc shift16.cc ctrl_xfer_pro.cc flag_ctrl_pro.cc mult8.cc shift32.cc arith16.cc data_xfer16.cc init.cc paging.cc shift8.cc arith32.cc data_xfer32.cc io.cc proc_ctrl.cc soft_int.cc soft_int-sid.cc arith8.cc data_xfer8.cc io_pro.cc protect_ctrl.cc stack16.cc bcd.cc debugstuff.cc debugstuff-sid.cc lazy_flags.cc protect_ctrl_pro.cc stack32.cc bit.cc decode16.cc logical16.cc resolve16.cc stack_pro.cc decode32.cc logical32.cc resolve32.cc string.cc ctrl_xfer16.cc exception.cc logical8.cc segment_ctrl.cc tasking.cc ctrl_xfer32.cc ctrl_xfer32-sid.cc fetchdecode.cc fetchdecode-sid.cc mult16.cc segment_ctrl_pro.cc vm8086.cc lazy_flags.h x86.h x86-memory-modes.cc
+noinst_LTLIBRARIES = libcpu.la
+libcpu_la_SOURCES = cpu.cc cpu.h state_file.h main-hack.cc sid-x86-cpu-wrapper.cc access.cc ctrl_xfer8.cc flag_ctrl.cc mult32.cc shift16.cc ctrl_xfer_pro.cc flag_ctrl_pro.cc mult8.cc shift32.cc arith16.cc data_xfer16.cc init.cc paging.cc shift8.cc arith32.cc data_xfer32.cc io.cc proc_ctrl.cc soft_int.cc arith8.cc data_xfer8.cc io_pro.cc protect_ctrl.cc stack16.cc bcd.cc debugstuff.cc lazy_flags.cc protect_ctrl_pro.cc stack32.cc bit.cc decode16.cc logical16.cc resolve16.cc stack_pro.cc decode32.cc logical32.cc resolve32.cc string.cc ctrl_xfer16.cc exception.cc logical8.cc segment_ctrl.cc tasking.cc ctrl_xfer32.cc fetchdecode.cc mult16.cc segment_ctrl_pro.cc vm8086.cc lazy_flags.h sid-x86-cpu-wrapper.h sid-x86-memory-modes.cc
libcpu_la_LDFLAGS = -no-undefined
+libcpu_la_LIBADD = $(SUBLIBS)
+libcpu_la_DEPENDENCIES = $(SUBLIBS)
mkinstalldirs = $(SHELL) $(top_srcdir)/../../config/mkinstalldirs
CONFIG_HEADER = ../config.h
CONFIG_CLEAN_FILES =
X_LIBS = @X_LIBS@
X_EXTRA_LIBS = @X_EXTRA_LIBS@
X_PRE_LIBS = @X_PRE_LIBS@
-libcpu_la_LIBADD =
-libcpu_la_OBJECTS = exception-sid.lo cpu.lo cpu-sid.lo init-sid.lo \
-main-hack.lo x86.lo access.lo ctrl_xfer8.lo flag_ctrl.lo mult32.lo \
-shift16.lo ctrl_xfer_pro.lo flag_ctrl_pro.lo mult8.lo shift32.lo \
-arith16.lo data_xfer16.lo init.lo paging.lo shift8.lo arith32.lo \
-data_xfer32.lo io.lo proc_ctrl.lo soft_int.lo soft_int-sid.lo arith8.lo \
-data_xfer8.lo io_pro.lo protect_ctrl.lo stack16.lo bcd.lo debugstuff.lo \
-debugstuff-sid.lo lazy_flags.lo protect_ctrl_pro.lo stack32.lo bit.lo \
-decode16.lo logical16.lo resolve16.lo stack_pro.lo decode32.lo \
-logical32.lo resolve32.lo string.lo ctrl_xfer16.lo exception.lo \
-logical8.lo segment_ctrl.lo tasking.lo ctrl_xfer32.lo \
-ctrl_xfer32-sid.lo fetchdecode.lo fetchdecode-sid.lo mult16.lo \
-segment_ctrl_pro.lo vm8086.lo x86-memory-modes.lo
+libcpu_la_OBJECTS = cpu.lo main-hack.lo sid-x86-cpu-wrapper.lo \
+access.lo ctrl_xfer8.lo flag_ctrl.lo mult32.lo shift16.lo \
+ctrl_xfer_pro.lo flag_ctrl_pro.lo mult8.lo shift32.lo arith16.lo \
+data_xfer16.lo init.lo paging.lo shift8.lo arith32.lo data_xfer32.lo \
+io.lo proc_ctrl.lo soft_int.lo arith8.lo data_xfer8.lo io_pro.lo \
+protect_ctrl.lo stack16.lo bcd.lo debugstuff.lo lazy_flags.lo \
+protect_ctrl_pro.lo stack32.lo bit.lo decode16.lo logical16.lo \
+resolve16.lo stack_pro.lo decode32.lo logical32.lo resolve32.lo \
+string.lo ctrl_xfer16.lo exception.lo logical8.lo segment_ctrl.lo \
+tasking.lo ctrl_xfer32.lo fetchdecode.lo mult16.lo segment_ctrl_pro.lo \
+vm8086.lo sid-x86-memory-modes.lo
CXXFLAGS = @CXXFLAGS@
CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
GZIP_ENV = --best
DEP_FILES = .deps/access.P .deps/arith16.P .deps/arith32.P \
-.deps/arith8.P .deps/bcd.P .deps/bit.P .deps/cpu-sid.P .deps/cpu.P \
-.deps/ctrl_xfer16.P .deps/ctrl_xfer32-sid.P .deps/ctrl_xfer32.P \
-.deps/ctrl_xfer8.P .deps/ctrl_xfer_pro.P .deps/data_xfer16.P \
-.deps/data_xfer32.P .deps/data_xfer8.P .deps/debugstuff-sid.P \
-.deps/debugstuff.P .deps/decode16.P .deps/decode32.P \
-.deps/exception-sid.P .deps/exception.P .deps/fetchdecode-sid.P \
+.deps/arith8.P .deps/bcd.P .deps/bit.P .deps/cpu.P .deps/ctrl_xfer16.P \
+.deps/ctrl_xfer32.P .deps/ctrl_xfer8.P .deps/ctrl_xfer_pro.P \
+.deps/data_xfer16.P .deps/data_xfer32.P .deps/data_xfer8.P \
+.deps/debugstuff.P .deps/decode16.P .deps/decode32.P .deps/exception.P \
.deps/fetchdecode.P .deps/flag_ctrl.P .deps/flag_ctrl_pro.P \
-.deps/init-sid.P .deps/init.P .deps/io.P .deps/io_pro.P \
-.deps/lazy_flags.P .deps/logical16.P .deps/logical32.P .deps/logical8.P \
-.deps/main-hack.P .deps/mult16.P .deps/mult32.P .deps/mult8.P \
-.deps/paging.P .deps/proc_ctrl.P .deps/protect_ctrl.P \
-.deps/protect_ctrl_pro.P .deps/resolve16.P .deps/resolve32.P \
-.deps/segment_ctrl.P .deps/segment_ctrl_pro.P .deps/shift16.P \
-.deps/shift32.P .deps/shift8.P .deps/soft_int-sid.P .deps/soft_int.P \
-.deps/stack16.P .deps/stack32.P .deps/stack_pro.P .deps/string.P \
-.deps/tasking.P .deps/vm8086.P .deps/x86-memory-modes.P .deps/x86.P
+.deps/init.P .deps/io.P .deps/io_pro.P .deps/lazy_flags.P \
+.deps/logical16.P .deps/logical32.P .deps/logical8.P .deps/main-hack.P \
+.deps/mult16.P .deps/mult32.P .deps/mult8.P .deps/paging.P \
+.deps/proc_ctrl.P .deps/protect_ctrl.P .deps/protect_ctrl_pro.P \
+.deps/resolve16.P .deps/resolve32.P .deps/segment_ctrl.P \
+.deps/segment_ctrl_pro.P .deps/shift16.P .deps/shift32.P .deps/shift8.P \
+.deps/sid-x86-cpu-wrapper.P .deps/sid-x86-memory-modes.P \
+.deps/soft_int.P .deps/stack16.P .deps/stack32.P .deps/stack_pro.P \
+.deps/string.P .deps/tasking.P .deps/vm8086.P
SOURCES = $(libcpu_la_SOURCES)
OBJECTS = $(libcpu_la_OBJECTS)
.cc.lo:
$(LTCXXCOMPILE) -c $<
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+
+@SET_MAKE@
+
+all-recursive install-data-recursive install-exec-recursive \
+installdirs-recursive install-recursive uninstall-recursive \
+check-recursive installcheck-recursive info-recursive dvi-recursive:
+ @set fnord $(MAKEFLAGS); amf=$$2; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ @set fnord $(MAKEFLAGS); amf=$$2; \
+ dot_seen=no; \
+ rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
+ rev="$$subdir $$rev"; \
+ test "$$subdir" = "." && dot_seen=yes; \
+ done; \
+ test "$$dot_seen" = "no" && rev=". $$rev"; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+
tags: TAGS
ID: $(HEADERS) $(SOURCES) $(LISP)
here=`pwd` && cd $(srcdir) \
&& mkid -f$$here/ID $$unique $(LISP)
-TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
tags=; \
here=`pwd`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
list='$(SOURCES) $(HEADERS)'; \
unique=`for i in $$list; do echo $$i; done | \
awk ' { files[$$0] = 1; } \
|| cp -p $$d/$$file $(distdir)/$$file || :; \
fi; \
done
+ for subdir in $(SUBDIRS); do \
+ if test "$$subdir" = .; then :; else \
+ test -d $(distdir)/$$subdir \
+ || mkdir $(distdir)/$$subdir \
+ || exit 1; \
+ chmod 777 $(distdir)/$$subdir; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \
+ || exit 1; \
+ fi; \
+ done
DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
>> .deps/$(*F).P; \
rm -f .deps/$(*F).pp
info-am:
-info: info-am
+info: info-recursive
dvi-am:
-dvi: dvi-am
+dvi: dvi-recursive
check-am: all-am
-check: check-am
+check: check-recursive
installcheck-am:
-installcheck: installcheck-am
+installcheck: installcheck-recursive
install-exec-am:
-install-exec: install-exec-am
+install-exec: install-exec-recursive
install-data-am:
-install-data: install-data-am
+install-data: install-data-recursive
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-install: install-am
+install: install-recursive
uninstall-am:
-uninstall: uninstall-am
+uninstall: uninstall-recursive
all-am: Makefile $(LTLIBRARIES)
-all-redirect: all-am
+all-redirect: all-recursive
install-strip:
$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
-installdirs:
+installdirs: installdirs-recursive
+installdirs-am:
mostlyclean-generic:
mostlyclean-libtool mostlyclean-tags mostlyclean-depend \
mostlyclean-generic
-mostlyclean: mostlyclean-am
+mostlyclean: mostlyclean-recursive
clean-am: clean-noinstLTLIBRARIES clean-compile clean-libtool \
clean-tags clean-depend clean-generic mostlyclean-am
-clean: clean-am
+clean: clean-recursive
distclean-am: distclean-noinstLTLIBRARIES distclean-compile \
distclean-libtool distclean-tags distclean-depend \
distclean-generic clean-am
-rm -f libtool
-distclean: distclean-am
+distclean: distclean-recursive
maintainer-clean-am: maintainer-clean-noinstLTLIBRARIES \
maintainer-clean-compile maintainer-clean-libtool \
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
-maintainer-clean: maintainer-clean-am
+maintainer-clean: maintainer-clean-recursive
.PHONY: mostlyclean-noinstLTLIBRARIES distclean-noinstLTLIBRARIES \
clean-noinstLTLIBRARIES maintainer-clean-noinstLTLIBRARIES \
mostlyclean-compile distclean-compile clean-compile \
maintainer-clean-compile mostlyclean-libtool distclean-libtool \
-clean-libtool maintainer-clean-libtool tags mostlyclean-tags \
+clean-libtool maintainer-clean-libtool install-data-recursive \
+uninstall-data-recursive install-exec-recursive \
+uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \
+all-recursive check-recursive installcheck-recursive info-recursive \
+dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \
+maintainer-clean-recursive tags tags-recursive mostlyclean-tags \
distclean-tags clean-tags maintainer-clean-tags distdir \
mostlyclean-depend distclean-depend clean-depend \
maintainer-clean-depend info-am info dvi-am dvi check check-am \
installcheck-am installcheck install-exec-am install-exec \
install-data-am install-data install-am install uninstall-am uninstall \
-all-redirect all-am all installdirs mostlyclean-generic \
+all-redirect all-am all installdirs-am installdirs mostlyclean-generic \
distclean-generic clean-generic maintainer-clean-generic clean \
mostlyclean distclean maintainer-clean
+++ /dev/null
-// cpu-sid.cc - override some important bx_cpu_c member functions. -*- C++ -*-
-//
-// Copyright (C) 2001 Red Hat.
-//
-// Copyright (C) 2001 MandrakeSoft S.A.
-//
-// MandrakeSoft S.A.
-// 43, rue d'Aboukir
-// 75002 Paris - France
-// http://www.linux-mandrake.com/
-// http://www.mandrakesoft.com/
-//
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-#include "bochs.h"
-#define LOG_THIS BX_CPU_THIS_PTR
-
-static Bit8u *sid_prefetch_data = NULL;
-
-void
-sid_cpu_c::cpu_loop(Bit32s max_instr_count)
-{
- unsigned ret;
- BxInstruction_t i;
- unsigned maxisize;
- Bit8u *fetch_ptr;
- Boolean is_32;
-
- static int num_loops = 0;
-#if BX_DEBUGGER
- BX_CPU_THIS_PTR break_point = 0;
-#ifdef MAGIC_BREAKPOINT
- BX_CPU_THIS_PTR magic_break = 0;
-#endif // MAGIC_BREAKPOINT
- BX_CPU_THIS_PTR stop_reason = STOP_NO_REASON;
-#endif // BX_DEBUGGER
-
- (void) setjmp( BX_CPU_THIS_PTR jmp_buf_env );
-
- BX_CPU_THIS_PTR prev_eip = EIP; // commit new EIP
- BX_CPU_THIS_PTR prev_esp = ESP; // commit new ESP
-
-#if X86_CPU_DEBUG
- printf("At top of main loop, EIP = %p, ESP = %p\n", EIP, ESP);
-#endif
-
-main_cpu_loop:
-
- // ???
- BX_CPU_THIS_PTR EXT = 0;
- BX_CPU_THIS_PTR errorno = 0;
-
- // First check on events which occurred for previous instructions
- // (traps) and ones which are asynchronous to the CPU
- // (hardware interrupts).
- if (BX_CPU_THIS_PTR async_event)
- goto handle_async_event;
-
-async_events_processed:
-
- // Now we can handle things which are synchronous to instruction
- // execution.
- if (BX_CPU_THIS_PTR eflags.rf) {
- BX_CPU_THIS_PTR eflags.rf = 0;
- }
-#if BX_X86_DEBUGGER
- else {
- // only bother comparing if any breakpoints enabled
- if ( BX_CPU_THIS_PTR dr7 & 0x000000ff ) {
- Bit32u iaddr =
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base +
- BX_CPU_THIS_PTR prev_eip;
- Bit32u dr6_bits;
- if ( (dr6_bits = hwdebug_compare(iaddr, 1, BX_HWDebugInstruction,
- BX_HWDebugInstruction)) ) {
- // Add to the list of debug events thus far.
- BX_CPU_THIS_PTR debug_trap |= dr6_bits;
- BX_CPU_THIS_PTR async_event = 1;
- // If debug events are not inhibited on this boundary,
- // fire off a debug fault. Otherwise handle it on the next
- // boundary. (becomes a trap)
- if ( !(BX_CPU_THIS_PTR inhibit_mask & BX_INHIBIT_DEBUG) ) {
- // Commit debug events to DR6
- BX_CPU_THIS_PTR dr6 = BX_CPU_THIS_PTR debug_trap;
- exception(BX_DB_EXCEPTION, 0, 0); // no error, not interrupt
- }
- }
- }
- }
-#endif
-
- // We have ignored processing of external interrupts and
- // debug events on this boundary. Reset the mask so they
- // will be processed on the next boundary.
- BX_CPU_THIS_PTR inhibit_mask = 0;
-
-
-#if BX_DEBUGGER
- {
- Bit32u debug_eip = BX_CPU_THIS_PTR prev_eip;
- if ( dbg_is_begin_instr_bpoint(
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
- debug_eip,
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base + debug_eip,
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b) ) {
- return;
- }
- }
-#endif // #if BX_DEBUGGER
-
-
- is_32 = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b;
-
- if (BX_CPU_THIS_PTR bytesleft == 0) {
- prefetch();
- }
- fetch_ptr = BX_CPU_THIS_PTR fetch_ptr;
-
- maxisize = 16;
- if (BX_CPU_THIS_PTR bytesleft < 16)
- maxisize = BX_CPU_THIS_PTR bytesleft;
-
- ret = FetchDecode(fetch_ptr, &i, maxisize, is_32);
-
-#if X86_CPU_DEBUG
- printf("FetchDecode returned: %d\n", ret);
- printf("Current opcode: %p, with length: %d, EIP = %p\n", i.b1, i.ilen, this->eip);
-#endif
-
- if (ret) {
- if (i.ResolveModrm) {
- // call method on sid_cpu_c object
- BX_CPU_CALL_METHOD_FROM_SID(i.ResolveModrm, (&i));
- }
- BX_CPU_THIS_PTR fetch_ptr += i.ilen;
- BX_CPU_THIS_PTR bytesleft -= i.ilen;
-fetch_decode_OK:
-
- if (i.rep_used && (i.attr & BxRepeatable)) {
-repeat_loop:
- if (i.attr & BxRepeatableZF) {
- if (i.as_32) {
- if (ECX != 0) {
- BX_CPU_CALL_METHOD_FROM_SID(i.execute_sid, (&i));
- ECX -= 1;
- }
- if ((i.rep_used==0xf3) && (get_ZF()==0)) goto repeat_done;
- if ((i.rep_used==0xf2) && (get_ZF()!=0)) goto repeat_done;
- if (ECX == 0) goto repeat_done;
- goto repeat_not_done;
- }
- else {
- if (CX != 0) {
- BX_CPU_CALL_METHOD_FROM_SID(i.execute_sid, (&i));
- CX -= 1;
- }
- if ((i.rep_used==0xf3) && (get_ZF()==0)) goto repeat_done;
- if ((i.rep_used==0xf2) && (get_ZF()!=0)) goto repeat_done;
- if (CX == 0) goto repeat_done;
- goto repeat_not_done;
- }
- }
- else { // normal repeat, no concern for ZF
- if (i.as_32) {
- if (ECX != 0) {
- BX_CPU_CALL_METHOD_FROM_SID(i.execute_sid, (&i));
- ECX -= 1;
- }
- if (ECX == 0) goto repeat_done;
- goto repeat_not_done;
- }
- else { // 16bit addrsize
- if (CX != 0) {
- BX_CPU_CALL_METHOD_FROM_SID(i.execute_sid, (&i));
- CX -= 1;
- }
- if (CX == 0) goto repeat_done;
- goto repeat_not_done;
- }
- }
- // shouldn't get here from above
-repeat_not_done:
-#ifdef REGISTER_IADDR
- REGISTER_IADDR(BX_CPU_THIS_PTR eip + BX_CPU_THIS_PTR sregs[BX_SREG_CS].cache.u.segment.base);
-#endif
-
-#if BX_DEBUGGER == 0
- if (BX_CPU_THIS_PTR async_event) {
- invalidate_prefetch_q();
- goto debugger_check;
- }
- goto repeat_loop;
-#else /* if BX_DEBUGGER == 1 */
- invalidate_prefetch_q();
- goto debugger_check;
-#endif
-
-
-repeat_done:
- BX_CPU_THIS_PTR eip += i.ilen;
- }
- else {
- // non repeating instruction
- BX_CPU_THIS_PTR eip += i.ilen;
- BX_CPU_CALL_METHOD_FROM_SID(i.execute_sid, (&i));
- }
-
- BX_CPU_THIS_PTR prev_eip = EIP; // commit new EIP
- BX_CPU_THIS_PTR prev_esp = ESP; // commit new ESP
-#ifdef REGISTER_IADDR
- REGISTER_IADDR(BX_CPU_THIS_PTR eip + BX_CPU_THIS_PTR sregs[BX_SREG_CS].cache.u.segment.base);
-#endif
-
-debugger_check:
-
- // The CHECK_MAX_INSTRUCTIONS macro allows cpu_loop to execute a few
- // instructions and then return so that the other processors have a chance
- // to run. Every time sid pulses the step pin, cpu_loop executes once
- CHECK_MAX_INSTRUCTIONS(max_instr_count);
-
-#if BX_DEBUGGER
- // BW vm mode switch support is in dbg_is_begin_instr_bpoint
- // note instr generating exceptions never reach this point.
-
- // (mch) Read/write, time break point support
- if (BX_CPU_THIS_PTR break_point) {
- switch (BX_CPU_THIS_PTR break_point) {
- case BREAK_POINT_TIME:
- BX_CPU_THIS_PTR info("[%lld] Caught time breakpoint\n", bx_pc_system.time_ticks());
- BX_CPU_THIS_PTR stop_reason = STOP_TIME_BREAK_POINT;
- return;
- case BREAK_POINT_READ:
- BX_CPU_THIS_PTR info("[%lld] Caught read watch point\n", bx_pc_system.time_ticks());
- BX_CPU_THIS_PTR stop_reason = STOP_READ_WATCH_POINT;
- return;
- case BREAK_POINT_WRITE:
- BX_CPU_THIS_PTR info("[%lld] Caught write watch point\n", bx_pc_system.time_ticks());
- BX_CPU_THIS_PTR stop_reason = STOP_WRITE_WATCH_POINT;
- return;
- default:
- BX_PANIC(("Weird break point condition"));
- }
- }
-#ifdef MAGIC_BREAKPOINT
- // (mch) Magic break point support
- if (BX_CPU_THIS_PTR magic_break) {
- if (bx_dbg.magic_break_enabled) {
- BX_CPU_THIS_PTR info("Stopped on MAGIC BREAKPOINT\n");
- BX_CPU_THIS_PTR stop_reason = STOP_MAGIC_BREAK_POINT;
- return;
- } else {
- BX_CPU_THIS_PTR magic_break = 0;
- BX_CPU_THIS_PTR stop_reason = STOP_NO_REASON;
- BX_CPU_THIS_PTR info("Ignoring MAGIC BREAKPOINT\n");
- }
- }
-#endif
- if (BX_CPU_THIS_PTR trace) {
- BX_CPU_THIS_PTR stop_reason = STOP_TRACE;
- return;
- }
-#endif
-
-#if BX_DEBUGGER
- {
- Bit32u debug_eip = BX_CPU_THIS_PTR prev_eip;
- if ( dbg_is_end_instr_bpoint(
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
- debug_eip,
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base + debug_eip,
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b) ) {
- return;
- }
- }
-#endif // #if BX_DEBUGGER
- goto main_cpu_loop;
- }
- else {
- unsigned remain, j;
- static Bit8u FetchBuffer[16];
- Bit8u *temp_ptr;
-
- // read all leftover bytes in current page
- for (j=0; j<BX_CPU_THIS_PTR bytesleft; j++) {
- FetchBuffer[j] = *fetch_ptr++;
- }
-
- // get remaining bytes for prefetch in next page
- // prefetch() needs eip current
- BX_CPU_THIS_PTR eip += BX_CPU_THIS_PTR bytesleft;
- remain = BX_CPU_THIS_PTR bytesleft;
- prefetch();
-
- if (BX_CPU_THIS_PTR bytesleft < 16) {
- // make sure (bytesleft - remain) below doesn't go negative
- BX_PANIC(("fetch_decode: bytesleft==0 after prefetch\n"));
- }
- temp_ptr = fetch_ptr = BX_CPU_THIS_PTR fetch_ptr;
-
- // read leftover bytes in next page
- for (; j<16; j++) {
- FetchBuffer[j] = *temp_ptr++;
- }
-
- ret = FetchDecode(FetchBuffer, &i, 16, is_32);
-
-#if X86_CPU_DEBUG
- printf("Just returned from prefetch...\n");
- printf("FetchDecode returned: %d\n", ret);
- printf("Current opcode: %p, with length: %d, EIP = %p, prev_eip = %p\n", i.b1, i.ilen, this->eip, this->prev_eip);
-#endif
-
- if (ret==0)
- BX_PANIC(("fetchdecode: cross boundary: ret==0\n"));
- if (i.ResolveModrm) {
- BX_CPU_CALL_METHOD_FROM_SID(i.ResolveModrm, (&i));
- }
- remain = i.ilen - remain;
-
- // note: eip has already been advanced to beginning of page
- BX_CPU_THIS_PTR fetch_ptr = fetch_ptr + remain;
- BX_CPU_THIS_PTR bytesleft -= remain;
- //BX_CPU_THIS_PTR eip += remain;
- BX_CPU_THIS_PTR eip = BX_CPU_THIS_PTR prev_eip;
- goto fetch_decode_OK;
- }
-
-
-
- //
- // This area is where we process special conditions and events.
- //
-
-handle_async_event:
-
- if (BX_CPU_THIS_PTR debug_trap & 0x80000000) {
- // I made up the bitmask above to mean HALT state.
-#if BX_SMP_PROCESSORS==1
-#else /* BX_SMP_PROCESSORS != 1 */
- // for multiprocessor simulation, even if this CPU is halted we still
- // must give the others a chance to simulate. If an interrupt has
- // arrived, then clear the HALT condition; otherwise just return from
- // the CPU loop with stop_reason STOP_CPU_HALTED.
- if (BX_CPU_THIS_PTR INTR && BX_CPU_THIS_PTR eflags.if_) {
- // interrupt ends the HALT condition
- BX_CPU_THIS_PTR debug_trap = 0; // clear traps for after resume
- BX_CPU_THIS_PTR inhibit_mask = 0; // clear inhibits for after resume
- //bx_printf ("halt condition has been cleared in %s\n", name);
- } else {
- // HALT condition remains, return so other CPUs have a chance
-#if BX_DEBUGGER
- BX_CPU_THIS_PTR stop_reason = STOP_CPU_HALTED;
-#endif
- return;
- }
-#endif
- }
-
-
- // Priority 1: Hardware Reset and Machine Checks
- // RESET
- // Machine Check
- // (bochs doesn't support these)
-
- // Priority 2: Trap on Task Switch
- // T flag in TSS is set
- if (BX_CPU_THIS_PTR debug_trap & 0x00008000) {
- BX_CPU_THIS_PTR dr6 |= BX_CPU_THIS_PTR debug_trap;
- exception(BX_DB_EXCEPTION, 0, 0); // no error, not interrupt
- }
-
- // Priority 3: External Hardware Interventions
- // FLUSH
- // STOPCLK
- // SMI
- // INIT
- // (bochs doesn't support these)
-
- // Priority 4: Traps on Previous Instruction
- // Breakpoints
- // Debug Trap Exceptions (TF flag set or data/IO breakpoint)
- if ( BX_CPU_THIS_PTR debug_trap &&
- !(BX_CPU_THIS_PTR inhibit_mask & BX_INHIBIT_DEBUG) ) {
- // A trap may be inhibited on this boundary due to an instruction
- // which loaded SS. If so we clear the inhibit_mask below
- // and don't execute this code until the next boundary.
- // Commit debug events to DR6
- BX_CPU_THIS_PTR dr6 |= BX_CPU_THIS_PTR debug_trap;
- exception(BX_DB_EXCEPTION, 0, 0); // no error, not interrupt
- }
-
- // Priority 5: External Interrupts
- // NMI Interrupts
- // Maskable Hardware Interrupts
- if (BX_CPU_THIS_PTR inhibit_mask & BX_INHIBIT_INTERRUPTS) {
- // Processing external interrupts is inhibited on this
- // boundary because of certain instructions like STI.
- // inhibit_mask is cleared below, in which case we will have
- // an opportunity to check interrupts on the next instruction
- // boundary.
- }
- else if (BX_CPU_THIS_PTR INTR && BX_CPU_THIS_PTR eflags.if_ && BX_DBG_ASYNC_INTR) {
- Bit8u vector;
-
- // NOTE: similar code in ::take_irq()
-#if BX_SUPPORT_APIC
- if (BX_CPU_THIS_PTR int_from_local_apic)
- vector = BX_CPU_THIS_PTR local_apic.acknowledge_int ();
- else
- vector = BX_IAC(); // may set INTR with next interrupt
-#else
-#if 0 // FIXME: this will eventually be included
- // if no local APIC, always acknowledge the PIC.
- vector = BX_IAC(); // may set INTR with next interrupt
-#endif
-#endif
- //if (bx_dbg.interrupts) BX_INFO(("decode: interrupt %u\n",
- // (unsigned) vector));
- BX_CPU_THIS_PTR errorno = 0;
- BX_CPU_THIS_PTR EXT = 1; /* external event */
- interrupt(vector, 0, 0, 0);
- BX_INSTR_HWINTERRUPT(vector, BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, BX_CPU_THIS_PTR eip);
- }
-#if 0 // FIXME: this will eventually be included
- else if (BX_HRQ && BX_DBG_ASYNC_DMA) {
- // NOTE: similar code in ::take_dma()
- // assert Hold Acknowledge (HLDA) and go into a bus hold state
- BX_RAISE_HLDA();
- }
-#endif
- // Priority 6: Faults from fetching next instruction
- // Code breakpoint fault
- // Code segment limit violation (priority 7 on 486/Pentium)
- // Code page fault (priority 7 on 486/Pentium)
- // (handled in main decode loop)
-
- // Priority 7: Faults from decoding next instruction
- // Instruction length > 15 bytes
- // Illegal opcode
- // Coprocessor not available
- // (handled in main decode loop etc)
-
- // Priority 8: Faults on executing an instruction
- // Floating point execution
- // Overflow
- // Bound error
- // Invalid TSS
- // Segment not present
- // Stack fault
- // General protection
- // Data page fault
- // Alignment check
- // (handled by rest of the code)
-
-
- if (BX_CPU_THIS_PTR eflags.tf) {
- // TF is set before execution of next instruction. Schedule
- // a debug trap (#DB) after execution. After completion of
- // next instruction, the code above will invoke the trap.
- BX_CPU_THIS_PTR debug_trap |= 0x00004000; // BS flag in DR6
- }
-#if 0 // FIXME: this will eventually be included
- if ( !(BX_CPU_THIS_PTR INTR ||
- BX_CPU_THIS_PTR debug_trap ||
- BX_HRQ ||
- BX_CPU_THIS_PTR eflags.tf) )
- BX_CPU_THIS_PTR async_event = 0;
- goto async_events_processed;
-#endif
-}
-
-// boundaries of consideration:
-//
-// * physical memory boundary: 1024k (1Megabyte) (increments of...)
-// * A20 boundary: 1024k (1Megabyte)
-// * page boundary: 4k
-// * ROM boundary: 2k (dont care since we are only reading)
-// * segment boundary: any
-
-
-
- void
-sid_cpu_c::prefetch(void)
-{
- // cs:eIP
- // prefetch QSIZE byte quantity aligned on corresponding boundary
- Bit32u new_linear_addr;
- Bit32u new_phy_addr;
- Bit32u temp_eip, temp_limit;
-
- temp_eip = BX_CPU_THIS_PTR eip;
- temp_limit = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled;
-
- new_linear_addr = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base + temp_eip;
- BX_CPU_THIS_PTR prev_linear_page = new_linear_addr & 0xfffff000;
- if (temp_eip > temp_limit) {
- BX_PANIC(("prefetch: EIP > CS.limit\n"));
- }
-
-#if BX_SUPPORT_PAGING
- if (BX_CPU_THIS_PTR cr0.pg) {
- // aligned block guaranteed to be all in one page, same A20 address
- new_phy_addr = itranslate_linear(new_linear_addr, CPL==3);
- new_phy_addr = A20ADDR(new_phy_addr);
- }
- else {
-#endif // BX_SUPPORT_PAGING
- new_phy_addr = A20ADDR(new_linear_addr);
-#if BX_SUPPORT_PAGING
- }
-#endif // BX_SUPPORT_PAGING
-
- // max physical address as confined by page boundary
- BX_CPU_THIS_PTR prev_phy_page = new_phy_addr & 0xfffff000;
- BX_CPU_THIS_PTR max_phy_addr = BX_CPU_THIS_PTR prev_phy_page | 0x00000fff;
-
- // check if segment boundary comes into play
- //if ((temp_limit - temp_eip) < 4096) {
- // }
-
- BX_CPU_THIS_PTR bytesleft = 16;
-
- if(!sid_prefetch_data)
- sid_prefetch_data = new Bit8u[16];
-
-#if X86_CPU_DEBUG
- printf("Prefetching 16 new bytes from %p...\n", new_phy_addr);
-#endif
-
- BX_CPU_THIS_PTR mem->read_physical(this, new_phy_addr, 16, (void *)sid_prefetch_data);
-
- BX_CPU_THIS_PTR fetch_ptr = sid_prefetch_data;
-}
-
-
- // If control has transfered locally, it is possible the prefetch Q is
- // still valid. This would happen for repeat instructions, and small
- // branches.
- void
-sid_cpu_c::revalidate_prefetch_q(void)
-{
- Bit32u new_linear_addr, new_linear_page, new_linear_offset;
- Bit32u new_phy_addr;
-
- new_linear_addr = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base + BX_CPU_THIS_PTR eip;
-
- new_linear_page = new_linear_addr & 0xfffff000;
- if (new_linear_page == BX_CPU_THIS_PTR prev_linear_page) {
- // same linear address, old linear->physical translation valid
- new_linear_offset = new_linear_addr & 0x00000fff;
- new_phy_addr = BX_CPU_THIS_PTR prev_phy_page | new_linear_offset;
-
- BX_CPU_THIS_PTR bytesleft = 16;
-
- if(!sid_prefetch_data)
- sid_prefetch_data = new Bit8u[16];
-
-#if X86_CPU_DEBUG
- printf("Revalidating prefetch: Prefetching 16 new bytes from %p...\n", new_phy_addr);
-#endif
-
- BX_CPU_THIS_PTR mem->read_physical(this, new_phy_addr, 16, (void *)sid_prefetch_data);
-
- BX_CPU_THIS_PTR fetch_ptr = sid_prefetch_data;
- }
- else {
- BX_CPU_THIS_PTR bytesleft = 0; // invalidate prefetch Q
- }
-}
+++ /dev/null
-// cpu-sid.h - declaration of the sid_cpu_c class. -*- C++ -*-
-//
-// Copyright (C) 2001 Red Hat.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-#ifndef __CPU_SID_H__
-#define __CPU_SID_H__
-
-// The CHECK_MAX_INSTRUCTIONS macro allows cpu_loop to execute a few
-// instructions and then return so that the other processors have a chance to
-// run. This is used only when simulating multiple processors.
-//
-// If maximum instructions have been executed, return. A count less
-// than zero means run forever.
-#define CHECK_MAX_INSTRUCTIONS(count) \
- if (count >= 0) { \
- count--; if (count == 0) return; \
- }
-
-#define NEED_CPU_REG_SHORTCUTS 1
-
-#include "cpu.h"
-
-class x86_cpu;
-
-class sid_cpu_c : public BX_CPU_C {
- public:
- x86_cpu *sid_cpu;
-
- void init (sid_mem_c *addrspace);
- void interrupt(Bit8u vector, Boolean is_INT, Boolean is_error_code,
- Bit16u error_code);
- void set_INTR(Boolean value);
- void cpu_loop(Bit32s max_instr_count);
- void prefetch(void);
- void revalidate_prefetch_q(void);
-
- Bit32u dbg_get_eflags(void);
- Bit32u dbg_get_reg(unsigned reg);
- Boolean dbg_set_reg(unsigned reg, Bit32u val);
- void JCC_Jd(BxInstruction_t *i);
- void INT3(BxInstruction_t *i);
- void INT_Ib(BxInstruction_t *i);
- unsigned FetchDecode(Bit8u *iptr, BxInstruction_t *instruction,
- unsigned remain, Boolean is_32);
-};
-
-typedef void (sid_cpu_c::*SidExecutePtr_t)(BxInstruction_t *);
-
-# define BX_CPU_CALL_METHOD_FROM_SID(func, args) \
- (this->*((SidExecutePtr_t) (func))) args
-
-extern sid_cpu_c bx_cpu;
-
-#endif // __CPU_SID_H__
#include "bochs.h"
#define LOG_THIS BX_CPU_THIS_PTR
+#if BX_SUPPORT_SID
+#include "sid-x86-cpu-wrapper.h"
+#endif
#if BX_USE_CPU_SMF
#define this (BX_CPU(0))
#endif
};
#endif
+#if BX_SUPPORT_SID
+static Bit8u *sid_prefetch_data = NULL;
+#endif
#if BX_SMP_PROCESSORS==1
-#if BX_SUPPORT_SID
-sid_cpu_c bx_cpu;
-sid_mem_c bx_mem;
-#else
+#if BX_SUPPORT_SID==0
// single processor simulation, so there's one of everything
BX_CPU_C bx_cpu;
BX_MEM_C bx_mem;
if (BX_CPU_THIS_PTR bytesleft < 16)
maxisize = BX_CPU_THIS_PTR bytesleft;
ret = FetchDecode(fetch_ptr, &i, maxisize, is_32);
+#if BX_SUPPORT_SID
+#if X86_CPU_DEBUG
+ // fprintf(stderr, "FetchDecode returned: %d\n", ret);
+ if (ret)
+ {
+ for (int deb = 0; deb < i.ilen; deb++)
+ printf("%c", *(fetch_ptr + deb));
+ }
+ // if (ret)
+ // printf("Current opcode: %p, with length: %d, EIP = %p\n", i.b1, i.ilen, this->eip);
+#endif // X86_CPU_DEBUG
+#endif // BX_SUPPORT_SID
if (ret) {
if (i.ResolveModrm) {
// call method on BX_CPU_C object
debugger_check:
+#if BX_SUPPORT_SID
+ CHECK_MAX_INSTRUCTIONS(max_instr_count);
+#else
#if (BX_SMP_PROCESSORS>1 && BX_DEBUGGER==0)
// The CHECK_MAX_INSTRUCTIONS macro allows cpu_loop to execute a few
// instructions and then return so that the other processors have a chance
// functionality.
CHECK_MAX_INSTRUCTIONS(max_instr_count);
#endif
+#endif
#if BX_DEBUGGER
// BW vm mode switch support is in dbg_is_begin_instr_bpoint
FetchBuffer[j] = *temp_ptr++;
}
ret = FetchDecode(FetchBuffer, &i, 16, is_32);
+#if BX_SUPPORT_SID
+#if X86_CPU_DEBUG
+ // fprintf(stderr, "Prefetch: FetchDecode returned: %d\n", ret);
+ if (ret)
+ {
+ for (int deb = 0; deb < i.ilen; deb++)
+ printf("%c", *(fetch_ptr + deb));
+ }
+ // printf("Current opcode: %p, with length: %d, EIP = %p\n", i.b1, i.ilen, this->eip);
+#endif // X86_CPU_DEBUG
+#endif // BX_SUPPORT_SID
+
if (ret==0)
BX_PANIC(("fetchdecode: cross boundary: ret==0\n"));
if (i.ResolveModrm) {
if (BX_CPU_THIS_PTR debug_trap & 0x80000000) {
// I made up the bitmask above to mean HALT state.
#if BX_SMP_PROCESSORS==1
+#if BX_SUPPORT_SID
+ // XXX: not tested yet:
+ if (!(BX_CPU_THIS_PTR INTR && BX_CPU_THIS_PTR eflags.if_))
+ {
+ x86_cpu_component->yield();
+ }
+#else
// for one processor, pass the time as quickly as possible until
// an interrupt wakes up the CPU.
while (1) {
}
BX_TICK1();
}
+#endif
#else /* BX_SMP_PROCESSORS != 1 */
// for multiprocessor simulation, even if this CPU is halted we still
// must give the others a chance to simulate. If an interrupt has
else
vector = BX_IAC(); // may set INTR with next interrupt
#else
-#if 0 // FIXME: look into this later
+#if BX_SUPPORT_SID
+ x86_cpu_component->drive_interrupt_acknowledge_pin();
+ vector = x86_cpu_component->interrupt_acknowledged();
+#else
// if no local APIC, always acknowledge the PIC.
vector = BX_IAC(); // may set INTR with next interrupt
#endif
interrupt(vector, 0, 0, 0);
BX_INSTR_HWINTERRUPT(vector, BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, BX_CPU_THIS_PTR eip);
}
-#if 0 // FIXME: look into this later
else if (BX_HRQ && BX_DBG_ASYNC_DMA) {
// NOTE: similar code in ::take_dma()
// assert Hold Acknowledge (HLDA) and go into a bus hold state
BX_RAISE_HLDA();
}
-#endif
+
// Priority 6: Faults from fetching next instruction
// Code breakpoint fault
// Code segment limit violation (priority 7 on 486/Pentium)
// next instruction, the code above will invoke the trap.
BX_CPU_THIS_PTR debug_trap |= 0x00004000; // BS flag in DR6
}
-#if 0 // FIXME: look into this later
+
if ( !(BX_CPU_THIS_PTR INTR ||
BX_CPU_THIS_PTR debug_trap ||
BX_HRQ ||
BX_CPU_THIS_PTR eflags.tf) )
BX_CPU_THIS_PTR async_event = 0;
-#endif
+
goto async_events_processed;
}
#endif // #if BX_DYNAMIC_TRANSLATION == 0
}
#endif // BX_SUPPORT_PAGING
+#if BX_SUPPORT_SID
+ // max physical address as confined by page boundary
+ BX_CPU_THIS_PTR prev_phy_page = new_phy_addr & 0xfffff000;
+ BX_CPU_THIS_PTR max_phy_addr = BX_CPU_THIS_PTR prev_phy_page | 0x00000fff;
+
+ if(!sid_prefetch_data)
+ sid_prefetch_data = new Bit8u[16];
+
+ BX_CPU_THIS_PTR mem->read_physical(this, new_phy_addr, 16, (void *)sid_prefetch_data);
+
+ BX_CPU_THIS_PTR bytesleft = 16;
+ BX_CPU_THIS_PTR fetch_ptr = sid_prefetch_data;
+#else
if ( new_phy_addr >= BX_CPU_THIS_PTR mem->len ) {
// don't take this out if dynamic translation enabled,
// otherwise you must make a check to see if bytesleft is 0 after
BX_CPU_THIS_PTR bytesleft = (BX_CPU_THIS_PTR max_phy_addr - new_phy_addr) + 1;
BX_CPU_THIS_PTR fetch_ptr = &BX_CPU_THIS_PTR mem->vector[new_phy_addr];
+#endif
}
// same linear address, old linear->physical translation valid
new_linear_offset = new_linear_addr & 0x00000fff;
new_phy_addr = BX_CPU_THIS_PTR prev_phy_page | new_linear_offset;
+#if BX_SUPPORT_SID
+ if(!sid_prefetch_data)
+ sid_prefetch_data = new Bit8u[16];
+
+ BX_CPU_THIS_PTR mem->read_physical(this, new_phy_addr, 16, (void *)sid_prefetch_data);
+
+ BX_CPU_THIS_PTR bytesleft = 16;
+ BX_CPU_THIS_PTR fetch_ptr = sid_prefetch_data;
+#else
BX_CPU_THIS_PTR bytesleft = (BX_CPU_THIS_PTR max_phy_addr - new_phy_addr) + 1;
BX_CPU_THIS_PTR fetch_ptr = &BX_CPU_THIS_PTR mem->vector[new_phy_addr];
+#endif
}
else {
BX_CPU_THIS_PTR bytesleft = 0; // invalidate prefetch Q
typedef void * (*BxVoidFPtr_t)(void);
class BX_CPU_C;
#if BX_SUPPORT_SID
-class sid_cpu_c;
+class x86_cpu;
#endif
typedef struct BxInstruction_tag {
#else
void (BX_CPU_C::*ResolveModrm)(BxInstruction_tag *);
void (BX_CPU_C::*execute)(BxInstruction_tag *);
-#if BX_SUPPORT_SID
- void (sid_cpu_c::*execute_sid)(BxInstruction_tag *);
-#endif
#endif
#if BX_DYNAMIC_TRANSLATION
typedef void (*BxDTShim_t)(void);
#if BX_SUPPORT_SID
-class sid_mem_c;
+class sid_bx_mem_c;
#else
class BX_MEM_C;
#endif
#endif
#if BX_SUPPORT_SID
- sid_mem_c *mem;
+ x86_cpu *x86_cpu_component;
+ sid_bx_mem_c *mem;
#else
// pointer to the address space that this processor uses.
BX_MEM_C *mem;
#endif
-
+
Boolean EXT; /* 1 if processing external interrupt or exception
* or if not related to current instruction,
* 0 if current CS:IP caused exception */
volatile Boolean async_event;
volatile Boolean INTR;
+#if BX_SUPPORT_SID
+ Boolean BX_HRQ;
+#endif
// for accessing registers by index number
Bit16u *_16bit_base_reg[8];
Bit16u *_16bit_index_reg[8];
BX_CPU_C();
~BX_CPU_C(void);
#if BX_SUPPORT_SID
- void init (sid_mem_c *addrspace);
+ void init (x86_cpu *x86_cpu_comp, sid_bx_mem_c *addrspace);
#else
void init (BX_MEM_C *addrspace);
#endif
BX_SMF void REP(void (*)(void));
BX_SMF void REP_ZF(void (*)(void), unsigned rep_prefix);
+#if BX_SUPPORT_SID
+ BX_SMF Boolean dbg_set_reg(unsigned reg, Bit32u val);
+ BX_SMF Bit32u dbg_get_reg(unsigned reg);
+ BX_SMF Bit32u dbg_get_eflags(void);
+#else
#if BX_DEBUGGER
BX_SMF void dbg_take_irq(void);
BX_SMF void dbg_force_interrupt(unsigned vector);
BX_SMF Boolean dbg_is_end_instr_bpoint(Bit32u cs, Bit32u eip,
Bit32u laddr, Bit32u is_32);
#endif
+#endif
#if BX_DEBUGGER || BX_DISASM || BX_INSTRUMENTATION
BX_SMF void dbg_xlate_linear2phy(Bit32u linear, Bit32u *phy, Boolean *valid);
#endif
BX_SMF void TLB_clear(void);
BX_SMF void TLB_init(void);
BX_SMF void set_INTR(Boolean value);
+#if BX_SUPPORT_SID
+ void set_HRQ(Boolean value);
+#endif
BX_SMF char *strseg(bx_segment_reg_t *seg);
BX_SMF void interrupt(Bit8u vector, Boolean is_INT, Boolean is_error_code,
Bit16u error_code);
#define BX_HWDebugMemRW 0x03
#endif
-#if BX_SUPPORT_SID
-#else
+
+#if BX_SUPPORT_SID==0
#if BX_SMP_PROCESSORS==1
// single processor simulation, so there's one of everything
extern BX_CPU_C bx_cpu;
+++ /dev/null
-// Copyright (C) 2001 MandrakeSoft S.A.
-//
-// MandrakeSoft S.A.
-// 43, rue d'Aboukir
-// 75002 Paris - France
-// http://www.linux-mandrake.com/
-// http://www.mandrakesoft.com/
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-
-
-#define NEED_CPU_REG_SHORTCUTS 1
-#include "bochs.h"
-#define LOG_THIS BX_CPU_THIS_PTR
-
-
-
-
-
-#if 0
- void
-BX_CPU_C::RETnear32_Iw(BxInstruction_t *i)
-{
- Bit16u imm16;
- Bit32u temp_ESP;
- Bit32u return_EIP;
-
-#if BX_DEBUGGER
- BX_CPU_THIS_PTR show_flag |= Flag_ret;
-#endif
-
- if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) /* 32bit stack */
- temp_ESP = ESP;
- else
- temp_ESP = SP;
-
- imm16 = i->Iw;
-
- invalidate_prefetch_q();
-
-
- if (protected_mode()) {
- if ( !can_pop(4) ) {
- BX_PANIC(("retnear_iw: can't pop EIP\n"));
- /* ??? #SS(0) -or #GP(0) */
- }
-
- access_linear(BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.base + temp_ESP + 0,
- 4, CPL==3, BX_READ, &return_EIP);
-
- if (protected_mode() &&
- (return_EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) ) {
- BX_DEBUG(("retnear_iw: EIP > limit\n"));
- exception(BX_GP_EXCEPTION, 0, 0);
- }
-
- /* Pentium book says imm16 is number of words ??? */
- if ( !can_pop(4 + imm16) ) {
- BX_PANIC(("retnear_iw: can't release bytes from stack\n"));
- /* #GP(0) -or #SS(0) ??? */
- }
-
- BX_CPU_THIS_PTR eip = return_EIP;
- if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) /* 32bit stack */
- ESP += 4 + imm16; /* ??? should it be 2*imm16 ? */
- else
- SP += 4 + imm16;
- }
- else {
- pop_32(&return_EIP);
- BX_CPU_THIS_PTR eip = return_EIP;
- if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) /* 32bit stack */
- ESP += imm16; /* ??? should it be 2*imm16 ? */
- else
- SP += imm16;
- }
-
- BX_INSTR_UCNEAR_BRANCH(BX_INSTR_IS_RET, BX_CPU_THIS_PTR eip);
-}
-
- void
-BX_CPU_C::RETnear32(BxInstruction_t *i)
-{
- Bit32u temp_ESP;
- Bit32u return_EIP;
-
-#if BX_DEBUGGER
- BX_CPU_THIS_PTR show_flag |= Flag_ret;
-#endif
-
- invalidate_prefetch_q();
-
- if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) /* 32bit stack */
- temp_ESP = ESP;
- else
- temp_ESP = SP;
-
-
- if (protected_mode()) {
- if ( !can_pop(4) ) {
- BX_PANIC(("retnear: can't pop EIP\n"));
- /* ??? #SS(0) -or #GP(0) */
- }
-
- access_linear(BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.base + temp_ESP + 0,
- 4, CPL==3, BX_READ, &return_EIP);
-
- if ( return_EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled ) {
- BX_PANIC(("retnear: EIP > limit\n"));
- //exception(BX_GP_EXCEPTION, 0, 0);
- }
- BX_CPU_THIS_PTR eip = return_EIP;
- if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) /* 32bit stack */
- ESP += 4;
- else
- SP += 4;
- }
- else {
- pop_32(&return_EIP);
- BX_CPU_THIS_PTR eip = return_EIP;
- }
-
- BX_INSTR_UCNEAR_BRANCH(BX_INSTR_IS_RET, BX_CPU_THIS_PTR eip);
-}
-
- void
-BX_CPU_C::RETfar32_Iw(BxInstruction_t *i)
-{
- Bit32u eip, ecs_raw;
- Bit16s imm16;
-
-#if BX_DEBUGGER
- BX_CPU_THIS_PTR show_flag |= Flag_ret;
-#endif
- /* ??? is imm16, number of bytes/words depending on operandsize ? */
-
- imm16 = i->Iw;
-
- invalidate_prefetch_q();
-
-#if BX_CPU_LEVEL >= 2
- if (protected_mode()) {
- BX_CPU_THIS_PTR return_protected(i, imm16);
- goto done;
- }
-#endif
-
-
- pop_32(&eip);
- pop_32(&ecs_raw);
- BX_CPU_THIS_PTR eip = eip;
- load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], (Bit16u) ecs_raw);
- if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
- ESP += imm16;
- else
- SP += imm16;
-
-done:
- BX_INSTR_FAR_BRANCH(BX_INSTR_IS_RET,
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, BX_CPU_THIS_PTR eip);
- return;
-}
-
- void
-BX_CPU_C::RETfar32(BxInstruction_t *i)
-{
- Bit32u eip, ecs_raw;
-
-#if BX_DEBUGGER
- BX_CPU_THIS_PTR show_flag |= Flag_ret;
-#endif
-
- invalidate_prefetch_q();
-
-#if BX_CPU_LEVEL >= 2
- if ( protected_mode() ) {
- BX_CPU_THIS_PTR return_protected(i, 0);
- goto done;
- }
-#endif
-
-
- pop_32(&eip);
- pop_32(&ecs_raw); /* 32bit pop, MSW discarded */
- BX_CPU_THIS_PTR eip = eip;
- load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], (Bit16u) ecs_raw);
-
-done:
- BX_INSTR_FAR_BRANCH(BX_INSTR_IS_RET,
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, BX_CPU_THIS_PTR eip);
- return;
-}
-
-
-
- void
-BX_CPU_C::CALL_Ad(BxInstruction_t *i)
-{
- Bit32u new_EIP;
- Bit32s disp32;
-
-#if BX_DEBUGGER
- BX_CPU_THIS_PTR show_flag |= Flag_call;
-#endif
-
- disp32 = i->Id;
- invalidate_prefetch_q();
-
- new_EIP = EIP + disp32;
-
- if ( protected_mode() ) {
- if ( new_EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled ) {
- BX_PANIC(("call_av: offset outside of CS limits\n"));
- exception(BX_GP_EXCEPTION, 0, 0);
- }
- }
-
- /* push 32 bit EA of next instruction */
- push_32(BX_CPU_THIS_PTR eip);
- BX_CPU_THIS_PTR eip = new_EIP;
-
- BX_INSTR_UCNEAR_BRANCH(BX_INSTR_IS_CALL, BX_CPU_THIS_PTR eip);
-}
-
- void
-BX_CPU_C::CALL32_Ap(BxInstruction_t *i)
-{
- Bit16u cs_raw;
- Bit32u disp32;
-
-#if BX_DEBUGGER
- BX_CPU_THIS_PTR show_flag |= Flag_call;
-#endif
-
- disp32 = i->Id;
- cs_raw = i->Iw2;
- invalidate_prefetch_q();
-
- if (protected_mode()) {
- BX_CPU_THIS_PTR call_protected(i, cs_raw, disp32);
- goto done;
- }
- push_32(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
- push_32(BX_CPU_THIS_PTR eip);
- BX_CPU_THIS_PTR eip = disp32;
- load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
-
-done:
- BX_INSTR_FAR_BRANCH(BX_INSTR_IS_CALL,
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, BX_CPU_THIS_PTR eip);
- return;
-}
-
- void
-BX_CPU_C::CALL_Ed(BxInstruction_t *i)
-{
- Bit32u temp_ESP;
- Bit32u op1_32;
-
-#if BX_DEBUGGER
- BX_CPU_THIS_PTR show_flag |= Flag_call;
-#endif
-
- if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
- temp_ESP = ESP;
- else
- temp_ESP = SP;
-
-
- /* op1_32 is a register or memory reference */
- if (i->mod == 0xc0) {
- op1_32 = BX_READ_32BIT_REG(i->rm);
- }
- else {
- read_virtual_dword(i->seg, i->rm_addr, &op1_32);
- }
- invalidate_prefetch_q();
-
- if (protected_mode()) {
- if (op1_32 > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
- BX_DEBUG(("call_ev: EIP out of CS limits! at %s:%d\n"));
- exception(BX_GP_EXCEPTION, 0, 0);
- }
- if ( !can_push(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache, temp_ESP, 4) ) {
- BX_PANIC(("call_ev: can't push EIP\n"));
- }
- }
-
- push_32(BX_CPU_THIS_PTR eip);
-
- BX_CPU_THIS_PTR eip = op1_32;
-
- BX_INSTR_UCNEAR_BRANCH(BX_INSTR_IS_CALL, BX_CPU_THIS_PTR eip);
-}
-
- void
-BX_CPU_C::CALL32_Ep(BxInstruction_t *i)
-{
- Bit16u cs_raw;
- Bit32u op1_32;
-
-#if BX_DEBUGGER
- BX_CPU_THIS_PTR show_flag |= Flag_call;
-#endif
-
- /* op1_32 is a register or memory reference */
- if (i->mod == 0xc0) {
- BX_PANIC(("CALL_Ep: op1 is a register\n"));
- }
-
- /* pointer, segment address pair */
- read_virtual_dword(i->seg, i->rm_addr, &op1_32);
- read_virtual_word(i->seg, i->rm_addr+4, &cs_raw);
- invalidate_prefetch_q();
-
- if ( protected_mode() ) {
- BX_CPU_THIS_PTR call_protected(i, cs_raw, op1_32);
- goto done;
- }
-
- push_32(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
- push_32(BX_CPU_THIS_PTR eip);
-
- BX_CPU_THIS_PTR eip = op1_32;
- load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
-
-done:
- BX_INSTR_FAR_BRANCH(BX_INSTR_IS_CALL,
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, BX_CPU_THIS_PTR eip);
- return;
-}
-
-
- void
-BX_CPU_C::JMP_Jd(BxInstruction_t *i)
-{
- Bit32u new_EIP;
-
- invalidate_prefetch_q();
-
- new_EIP = EIP + (Bit32s) i->Id;
-
-#if BX_CPU_LEVEL >= 2
- if (protected_mode()) {
- if ( new_EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled ) {
- BX_PANIC(("jmp_jv: offset outside of CS limits\n"));
- exception(BX_GP_EXCEPTION, 0, 0);
- }
- }
-#endif
-
- BX_CPU_THIS_PTR eip = new_EIP;
- BX_INSTR_UCNEAR_BRANCH(BX_INSTR_IS_JMP, new_EIP);
-}
-#endif
-
- void
-sid_cpu_c::JCC_Jd(BxInstruction_t *i)
-{
- Boolean condition = 0;
-
- switch (i->b1 & 0x0f) {
- case 0x00: /* JO */ condition = get_OF(); break;
- case 0x01: /* JNO */ condition = !get_OF(); break;
- case 0x02: /* JB */ condition = get_CF(); break;
- case 0x03: /* JNB */ condition = !get_CF(); break;
- case 0x04: /* JZ */ condition = get_ZF(); break;
- case 0x05: /* JNZ */ condition = !get_ZF(); break;
- case 0x06: /* JBE */ condition = get_CF() || get_ZF(); break;
- case 0x07: /* JNBE */ condition = !get_CF() && !get_ZF(); break;
- case 0x08: /* JS */ condition = get_SF(); break;
- case 0x09: /* JNS */ condition = !get_SF(); break;
- case 0x0A: /* JP */ condition = get_PF(); break;
- case 0x0B: /* JNP */ condition = !get_PF(); break;
- case 0x0C: /* JL */ condition = get_SF() != get_OF(); break;
- case 0x0D: /* JNL */ condition = get_SF() == get_OF(); break;
- case 0x0E: /* JLE */ condition = get_ZF() || (get_SF() != get_OF());
- break;
- case 0x0F: /* JNLE */ condition = (get_SF() == get_OF()) &&
- !get_ZF();
- break;
- }
-
- if (condition) {
- Bit32u new_EIP;
-
- new_EIP = EIP + (Bit32s) i->Id;
-#if BX_CPU_LEVEL >= 2
- if (protected_mode()) {
- if ( new_EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled ) {
- BX_PANIC(("jo_routine: offset outside of CS limits\n"));
- exception(BX_GP_EXCEPTION, 0, 0);
- }
- }
-#endif
- EIP = new_EIP;
- BX_INSTR_CNEAR_BRANCH_TAKEN(new_EIP);
- revalidate_prefetch_q();
- }
-#if BX_INSTRUMENTATION
- else {
- BX_INSTR_CNEAR_BRANCH_NOT_TAKEN();
- }
-#endif
-}
-#if 0
- void
-BX_CPU_C::JMP_Ap(BxInstruction_t *i)
-{
- Bit32u disp32;
- Bit16u cs_raw;
-
- invalidate_prefetch_q();
-
- if (i->os_32) {
- disp32 = i->Id;
- }
- else {
- disp32 = i->Iw;
- }
- cs_raw = i->Iw2;
-
-#if BX_CPU_LEVEL >= 2
- if (protected_mode()) {
- BX_CPU_THIS_PTR jump_protected(i, cs_raw, disp32);
- goto done;
- }
-#endif
-
- load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
- BX_CPU_THIS_PTR eip = disp32;
-
-done:
- BX_INSTR_FAR_BRANCH(BX_INSTR_IS_JMP,
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, BX_CPU_THIS_PTR eip);
- return;
-}
-
-
-
-
- void
-BX_CPU_C::JMP_Ed(BxInstruction_t *i)
-{
- Bit32u new_EIP;
- Bit32u op1_32;
-
- /* op1_32 is a register or memory reference */
- if (i->mod == 0xc0) {
- op1_32 = BX_READ_32BIT_REG(i->rm);
- }
- else {
- /* pointer, segment address pair */
- read_virtual_dword(i->seg, i->rm_addr, &op1_32);
- }
-
- invalidate_prefetch_q();
- new_EIP = op1_32;
-
-#if BX_CPU_LEVEL >= 2
- if (protected_mode()) {
- if (new_EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
- BX_PANIC(("jmp_ev: IP out of CS limits!\n"));
- exception(BX_GP_EXCEPTION, 0, 0);
- }
- }
-#endif
-
- BX_CPU_THIS_PTR eip = new_EIP;
-
- BX_INSTR_UCNEAR_BRANCH(BX_INSTR_IS_JMP, new_EIP);
-}
-
- /* Far indirect jump */
-
- void
-BX_CPU_C::JMP32_Ep(BxInstruction_t *i)
-{
- Bit16u cs_raw;
- Bit32u op1_32;
-
- /* op1_32 is a register or memory reference */
- if (i->mod == 0xc0) {
- /* far indirect must specify a memory address */
- BX_PANIC(("JMP_Ep(): op1 is a register\n"));
- }
-
- /* pointer, segment address pair */
- read_virtual_dword(i->seg, i->rm_addr, &op1_32);
- read_virtual_word(i->seg, i->rm_addr+4, &cs_raw);
- invalidate_prefetch_q();
-
- if ( protected_mode() ) {
- BX_CPU_THIS_PTR jump_protected(i, cs_raw, op1_32);
- goto done;
- }
-
- BX_CPU_THIS_PTR eip = op1_32;
- load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
-
-done:
- BX_INSTR_FAR_BRANCH(BX_INSTR_IS_JMP,
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, BX_CPU_THIS_PTR eip);
- return;
-}
-
- void
-BX_CPU_C::IRET32(BxInstruction_t *i)
-{
- Bit32u eip, ecs_raw, eflags;
-
-#if BX_DEBUGGER
- BX_CPU_THIS_PTR show_flag |= Flag_iret;
- BX_CPU_THIS_PTR show_eip = BX_CPU_THIS_PTR eip;
-#endif
-
- invalidate_prefetch_q();
-
- if (v8086_mode()) {
- // IOPL check in stack_return_from_v86()
- stack_return_from_v86(i);
- goto done;
- }
-
-#if BX_CPU_LEVEL >= 2
- if (BX_CPU_THIS_PTR cr0.pe) {
- iret_protected(i);
- goto done;
- }
-#endif
-
-
- pop_32(&eip);
- pop_32(&ecs_raw);
- pop_32(&eflags);
-
- load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], (Bit16u) ecs_raw);
- BX_CPU_THIS_PTR eip = eip;
- write_eflags(eflags, /* change IOPL? */ 1, /* change IF? */ 1, 0, 1);
-
-done:
- BX_INSTR_FAR_BRANCH(BX_INSTR_IS_IRET,
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, BX_CPU_THIS_PTR eip);
- return;
-}
-#endif
+++ /dev/null
-// Copyright (C) 2001 MandrakeSoft S.A.
-//
-// MandrakeSoft S.A.
-// 43, rue d'Aboukir
-// 75002 Paris - France
-// http://www.linux-mandrake.com/
-// http://www.mandrakesoft.com/
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-
-
-
-#define NEED_CPU_REG_SHORTCUTS 1
-#include "bochs.h"
-#define LOG_THIS BX_CPU_THIS_PTR
-
-#if BX_DEBUGGER
-
- void
-BX_CPU_C::debug(Bit32u offset)
-{
- BX_INFO(("| EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n",
- (unsigned) EAX, (unsigned) EBX, (unsigned) ECX, (unsigned) EDX));
- BX_INFO(("| ESP=%08x EBP=%08x ESI=%08x EDI=%08x\n",
- (unsigned) ESP, (unsigned) EBP, (unsigned) ESI, (unsigned) EDI));
- BX_INFO(("| IOPL=%1u %s %s %s %s %s %s %s %s\n",
- BX_CPU_THIS_PTR eflags.iopl,
- BX_CPU_THIS_PTR get_OF() ? "OV" : "NV",
- BX_CPU_THIS_PTR eflags.df ? "DW" : "UP",
- BX_CPU_THIS_PTR eflags.if_ ? "EI" : "DI",
- BX_CPU_THIS_PTR get_SF() ? "NG" : "PL",
- BX_CPU_THIS_PTR get_ZF() ? "ZR" : "NZ",
- BX_CPU_THIS_PTR get_AF() ? "AC" : "NA",
- BX_CPU_THIS_PTR get_PF() ? "PE" : "PO",
- BX_CPU_THIS_PTR get_CF() ? "CY" : "NC"));
- BX_INFO(("| SEG selector base limit G D\n"));
- BX_INFO(("| SEG sltr(index|ti|rpl) base limit G D\n"));
- BX_INFO(("| DS:%04x( %04x| %01u| %1u) %08x %08x %1u %1u\n",
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.index,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.ti,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.rpl,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.base,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.limit,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.g,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.d_b));
- BX_INFO(("| ES:%04x( %04x| %01u| %1u) %08x %08x %1u %1u\n",
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.index,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.ti,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.rpl,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.base,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.limit,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.g,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.d_b));
- BX_INFO(("| FS:%04x( %04x| %01u| %1u) %08x %08x %1u %1u\n",
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.index,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.ti,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.rpl,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.base,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.limit,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.g,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.d_b));
- BX_INFO(("| GS:%04x( %04x| %01u| %1u) %08x %08x %1u %1u\n",
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.index,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.ti,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.rpl,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.base,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.limit,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.g,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.d_b));
- BX_INFO(("| SS:%04x( %04x| %01u| %1u) %08x %08x %1u %1u\n",
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.index,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.ti,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.rpl,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.base,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.g,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b));
- BX_INFO(("| CS:%04x( %04x| %01u| %1u) %08x %08x %1u %1u\n",
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.index,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.ti,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.rpl,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g,
- (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b));
- BX_INFO(("| EIP=%08x (%08x)\n", (unsigned) BX_CPU_THIS_PTR eip,
- (unsigned) BX_CPU_THIS_PTR prev_eip));
-
-#if 0
- /* (mch) Hack to display the area round EIP and prev_EIP */
- char buf[100];
- sprintf(buf, "%04x:%08x ", BX_CPU_THIS_PTR sregs[BX_SREG_CS].selector.value, BX_CPU_THIS_PTR eip);
- for (int i = 0; i < 8; i++) {
- Bit8u data;
- BX_CPU_THIS_PTR read_virtual_byte(BX_SREG_CS, BX_CPU_THIS_PTR eip + i, &data);
- sprintf(buf+strlen(buf), "%02x ", data);
- }
- sprintf(buf+strlen(buf), "\n");
- BX_INFO((buf));
-
- sprintf(buf, "%04x:%08x ", BX_CPU_THIS_PTR sregs[BX_SREG_CS].selector.value, BX_CPU_THIS_PTR prev_eip);
- for (int i = 0; i < 8; i++) {
- Bit8u data;
- BX_CPU_THIS_PTR read_virtual_byte(BX_SREG_CS, BX_CPU_THIS_PTR prev_eip + i, &data);
- sprintf(buf+strlen(buf), "%02x ", data);
- }
- sprintf(buf+strlen(buf), "\n");
- BX_INFO((buf));
-#endif
-
-
-#if BX_DISASM
- Boolean valid;
- Bit32u phy_addr;
- Bit8u instr_buf[32];
- char char_buf[256];
- unsigned isize;
-
- dbg_xlate_linear2phy(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base + offset,
- &phy_addr, &valid);
- if (valid) {
- BX_CPU_THIS_PTR mem->dbg_fetch_mem(phy_addr, 16, instr_buf);
- isize = bx_disassemble.disasm(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b,
- instr_buf, char_buf);
- for (unsigned j=0; j<isize; j++)
- BX_INFO((">> %02x\n", (unsigned) instr_buf[j]));
- BX_INFO((">> : %s\n", char_buf));
- }
- else {
- BX_INFO(("(instruction unavailable) page not present\n"));
- }
-#else
- UNUSED(offset);
-#endif // #if BX_DISASM
-}
-
-#endif // BX_DEBUGGER
-
-
- Bit32u
-sid_cpu_c::dbg_get_reg(unsigned reg)
-{
- Bit32u return_val32;
-
- switch (reg) {
- case BX_DBG_REG_EAX: return(EAX);
- case BX_DBG_REG_ECX: return(ECX);
- case BX_DBG_REG_EDX: return(EDX);
- case BX_DBG_REG_EBX: return(EBX);
- case BX_DBG_REG_ESP: return(ESP);
- case BX_DBG_REG_EBP: return(EBP);
- case BX_DBG_REG_ESI: return(ESI);
- case BX_DBG_REG_EDI: return(EDI);
- case BX_DBG_REG_EIP: return(EIP);
- case BX_DBG_REG_EFLAGS:
- return_val32 = dbg_get_eflags();
- return(return_val32);
- case BX_DBG_REG_CS: return(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
- case BX_DBG_REG_SS: return(BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value);
- case BX_DBG_REG_DS: return(BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value);
- case BX_DBG_REG_ES: return(BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value);
- case BX_DBG_REG_FS: return(BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value);
- case BX_DBG_REG_GS: return(BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value);
- default:
- BX_PANIC(("get_reg: request for unknown register\n"));
- return(0);
- }
-}
-
- Boolean
-sid_cpu_c::dbg_set_reg(unsigned reg, Bit32u val)
-{
- // returns 1=OK, 0=can't change
- bx_segment_reg_t *seg;
- Bit32u current_sys_bits;
-
- switch (reg) {
- case BX_DBG_REG_EAX: EAX = val; return(1);
- case BX_DBG_REG_ECX: ECX = val; return(1);
- case BX_DBG_REG_EDX: EDX = val; return(1);
- case BX_DBG_REG_EBX: EBX = val; return(1);
- case BX_DBG_REG_ESP: ESP = val; return(1);
- case BX_DBG_REG_EBP: EBP = val; return(1);
- case BX_DBG_REG_ESI: ESI = val; return(1);
- case BX_DBG_REG_EDI: EDI = val; return(1);
- case BX_DBG_REG_EIP: EIP = val; return(1);
- case BX_DBG_REG_EFLAGS:
-#if 0
- BX_INFO(("dbg_set_reg: can not handle eflags yet.\n"));
- if ( val & 0xffff0000 ) {
- BX_INFO(("dbg_set_reg: can not set upper 16 bits of eflags.\n"));
- return(0);
- }
- // make sure none of the system bits are being changed
- current_sys_bits = (BX_CPU_THIS_PTR eflags.nt << 14) |
- (BX_CPU_THIS_PTR eflags.iopl << 12) |
- (BX_CPU_THIS_PTR eflags.tf << 8);
- if ( current_sys_bits != (val & 0x0000f100) ) {
- BX_INFO(("dbg_set_reg: can not modify NT, IOPL, or TF.\n"));
- return(0);
- }
-#endif
- BX_CPU_THIS_PTR set_CF(val & 0x01); val >>= 2;
- BX_CPU_THIS_PTR set_PF(val & 0x01); val >>= 2;
- BX_CPU_THIS_PTR set_AF(val & 0x01); val >>= 2;
- BX_CPU_THIS_PTR set_ZF(val & 0x01); val >>= 1;
- BX_CPU_THIS_PTR set_SF(val & 0x01); val >>= 2;
- BX_CPU_THIS_PTR eflags.if_ = val & 0x01; val >>= 1;
- BX_CPU_THIS_PTR eflags.df = val & 0x01; val >>= 1;
- BX_CPU_THIS_PTR set_OF(val & 0x01);
- if (BX_CPU_THIS_PTR eflags.if_)
- BX_CPU_THIS_PTR async_event = 1;
- return(1);
- case BX_DBG_REG_CS:
- seg = &BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS];
- break;
- case BX_DBG_REG_SS:
- seg = &BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS];
- break;
- case BX_DBG_REG_DS:
- seg = &BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS];
- break;
- case BX_DBG_REG_ES:
- seg = &BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES];
- break;
- case BX_DBG_REG_FS:
- seg = &BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS];
- break;
- case BX_DBG_REG_GS:
- seg = &BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS];
- break;
- default:
- BX_PANIC(("dbg_set_reg: unrecognized register ID (%u)\n", reg));
- return(0);
- }
-
- if (BX_CPU_THIS_PTR real_mode()) {
- seg->selector.value = val;
- seg->cache.valid = 1;
- seg->cache.p = 1;
- seg->cache.dpl = 0;
- seg->cache.segment = 1; // regular segment
- if (reg == BX_DBG_REG_CS) {
- seg->cache.u.segment.executable = 1; // code segment
- }
- else {
- seg->cache.u.segment.executable = 0; // data segment
- }
- seg->cache.u.segment.c_ed = 0; // expand up/non-conforming
- seg->cache.u.segment.r_w = 1; // writeable
- seg->cache.u.segment.a = 1; // accessed
- seg->cache.u.segment.base = val << 4;
- seg->cache.u.segment.limit = 0xffff;
- seg->cache.u.segment.limit_scaled = 0xffff;
- seg->cache.u.segment.g = 0; // byte granular
- seg->cache.u.segment.d_b = 0; // default 16bit size
- seg->cache.u.segment.avl = 0;
- return(1); // ok
- }
-
- return(0); // can't change when not in real mode
-}
-#if BX_DEBUGGER
- unsigned
-BX_CPU_C::dbg_query_pending(void)
-{
- unsigned ret = 0;
-
- if ( BX_HRQ ) { // DMA Hold Request
- ret |= BX_DBG_PENDING_DMA;
- }
-
- if ( BX_CPU_THIS_PTR INTR && BX_CPU_THIS_PTR eflags.if_ ) {
- ret |= BX_DBG_PENDING_IRQ;
- }
-
- return(ret);
-}
-
-#endif // BX_DEBUGGER
-
- Bit32u
-sid_cpu_c::dbg_get_eflags(void)
-{
- Bit32u val32;
-
- val32 =
- (BX_CPU_THIS_PTR get_CF()) |
- (BX_CPU_THIS_PTR eflags.bit1 << 1) |
- ((BX_CPU_THIS_PTR get_PF()) << 2) |
- (BX_CPU_THIS_PTR eflags.bit3 << 3) |
- ((BX_CPU_THIS_PTR get_AF()>0) << 4) |
- (BX_CPU_THIS_PTR eflags.bit5 << 5) |
- ((BX_CPU_THIS_PTR get_ZF()>0) << 6) |
- ((BX_CPU_THIS_PTR get_SF()>0) << 7) |
- (BX_CPU_THIS_PTR eflags.tf << 8) |
- (BX_CPU_THIS_PTR eflags.if_ << 9) |
- (BX_CPU_THIS_PTR eflags.df << 10) |
- ((BX_CPU_THIS_PTR get_OF()>0) << 11) |
- (BX_CPU_THIS_PTR eflags.iopl << 12) |
- (BX_CPU_THIS_PTR eflags.nt << 14) |
- (BX_CPU_THIS_PTR eflags.bit15 << 15) |
- (BX_CPU_THIS_PTR eflags.rf << 16) |
- (BX_CPU_THIS_PTR eflags.vm << 17);
-#if BX_CPU_LEVEL >= 4
- val32 |= (BX_CPU_THIS_PTR eflags.ac << 18);
- //val32 |= (BX_CPU_THIS_PTR eflags.vif << 19);
- //val32 |= (BX_CPU_THIS_PTR eflags.vip << 20);
- val32 |= (BX_CPU_THIS_PTR eflags.id << 21);
-#endif
- return(val32);
-}
-
-#if BX_DEBUGGER
- Bit32u
-BX_CPU_C::dbg_get_descriptor_l(bx_descriptor_t *d)
-{
- Bit32u val;
-
- if (d->valid == 0) {
- return(0);
- }
-
- if (d->segment) {
- val = ((d->u.segment.base & 0xffff) << 16) |
- (d->u.segment.limit & 0xffff);
- return(val);
- }
- else {
- switch (d->type) {
- case 0: // Reserved (not yet defined)
- BX_ERROR(( "#get_descriptor_l(): type %d not finished\n", d->type ));
- return(0);
-
- case 1: // available 16bit TSS
- val = ((d->u.tss286.base & 0xffff) << 16) |
- (d->u.tss286.limit & 0xffff);
- return(val);
-
- case 2: // LDT
- val = ((d->u.ldt.base & 0xffff) << 16) |
- d->u.ldt.limit;
- return(val);
-
- case 9: // available 32bit TSS
- val = ((d->u.tss386.base & 0xffff) << 16) |
- (d->u.tss386.limit & 0xffff);
- return(val);
-
- default:
- BX_ERROR(( "#get_descriptor_l(): type %d not finished\n", d->type ));
- return(0);
- }
- }
-}
-
- Bit32u
-BX_CPU_C::dbg_get_descriptor_h(bx_descriptor_t *d)
-{
- Bit32u val;
-
- if (d->valid == 0) {
- return(0);
- }
-
- if (d->segment) {
- val = (d->u.segment.base & 0xff000000) |
- ((d->u.segment.base >> 16) & 0x000000ff) |
- (d->u.segment.executable << 11) |
- (d->u.segment.c_ed << 10) |
- (d->u.segment.r_w << 9) |
- (d->u.segment.a << 8) |
- (d->segment << 12) |
- (d->dpl << 13) |
- (d->p << 15) |
- (d->u.segment.limit & 0xf0000) |
- (d->u.segment.avl << 20) |
- (d->u.segment.d_b << 22) |
- (d->u.segment.g << 23);
- return(val);
- }
- else {
- switch (d->type) {
- case 0: // Reserved (not yet defined)
- BX_ERROR(( "#get_descriptor_h(): type %d not finished\n", d->type ));
- return(0);
-
- case 1: // available 16bit TSS
- val = ((d->u.tss286.base >> 16) & 0xff) |
- (d->type << 8) |
- (d->dpl << 13) |
- (d->p << 15);
- return(val);
-
- case 2: // LDT
- val = ((d->u.ldt.base >> 16) & 0xff) |
- (d->type << 8) |
- (d->dpl << 13) |
- (d->p << 15) |
- (d->u.ldt.base & 0xff000000);
- return(val);
-
- case 9: // available 32bit TSS
- val = ((d->u.tss386.base >> 16) & 0xff) |
- (d->type << 8) |
- (d->dpl << 13) |
- (d->p << 15) |
- (d->u.tss386.limit & 0xf0000) |
- (d->u.tss386.avl << 20) |
- (d->u.tss386.g << 23) |
- (d->u.tss386.base & 0xff000000);
- return(val);
-
- default:
- BX_ERROR(( "#get_descriptor_h(): type %d not finished\n", d->type ));
- return(0);
- }
- }
-}
-
- Boolean
-BX_CPU_C::dbg_get_sreg(bx_dbg_sreg_t *sreg, unsigned sreg_no)
-{
- if (sreg_no > 5)
- return(0);
- sreg->sel = BX_CPU_THIS_PTR sregs[sreg_no].selector.value;
- sreg->des_l = dbg_get_descriptor_l(&BX_CPU_THIS_PTR sregs[sreg_no].cache);
- sreg->des_h = dbg_get_descriptor_h(&BX_CPU_THIS_PTR sregs[sreg_no].cache);
- sreg->valid = BX_CPU_THIS_PTR sregs[sreg_no].cache.valid;
- return(1);
-}
-
- Boolean
-BX_CPU_C::dbg_get_cpu(bx_dbg_cpu_t *cpu)
-{
- cpu->eax = EAX;
- cpu->ebx = EBX;
- cpu->ecx = ECX;
- cpu->edx = EDX;
-
- cpu->ebp = EBP;
- cpu->esi = ESI;
- cpu->edi = EDI;
- cpu->esp = ESP;
-
- cpu->eflags = dbg_get_eflags();
- cpu->eip = BX_CPU_THIS_PTR eip;
-
- cpu->cs.sel = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value;
- cpu->cs.des_l = dbg_get_descriptor_l(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache);
- cpu->cs.des_h = dbg_get_descriptor_h(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache);
- cpu->cs.valid = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid;
-
- cpu->ss.sel = BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value;
- cpu->ss.des_l = dbg_get_descriptor_l(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache);
- cpu->ss.des_h = dbg_get_descriptor_h(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache);
- cpu->ss.valid = BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid;
-
- cpu->ds.sel = BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value;
- cpu->ds.des_l = dbg_get_descriptor_l(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache);
- cpu->ds.des_h = dbg_get_descriptor_h(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache);
- cpu->ds.valid = BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.valid;
-
- cpu->es.sel = BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value;
- cpu->es.des_l = dbg_get_descriptor_l(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache);
- cpu->es.des_h = dbg_get_descriptor_h(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache);
- cpu->es.valid = BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.valid;
-
- cpu->fs.sel = BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value;
- cpu->fs.des_l = dbg_get_descriptor_l(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache);
- cpu->fs.des_h = dbg_get_descriptor_h(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache);
- cpu->fs.valid = BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.valid;
-
- cpu->gs.sel = BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value;
- cpu->gs.des_l = dbg_get_descriptor_l(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache);
- cpu->gs.des_h = dbg_get_descriptor_h(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache);
- cpu->gs.valid = BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.valid;
-
-
- cpu->ldtr.sel = BX_CPU_THIS_PTR ldtr.selector.value;
- cpu->ldtr.des_l = dbg_get_descriptor_l(&BX_CPU_THIS_PTR ldtr.cache);
- cpu->ldtr.des_h = dbg_get_descriptor_h(&BX_CPU_THIS_PTR ldtr.cache);
- cpu->ldtr.valid = BX_CPU_THIS_PTR ldtr.cache.valid;
-
- cpu->tr.sel = BX_CPU_THIS_PTR tr.selector.value;
- cpu->tr.des_l = dbg_get_descriptor_l(&BX_CPU_THIS_PTR tr.cache);
- cpu->tr.des_h = dbg_get_descriptor_h(&BX_CPU_THIS_PTR tr.cache);
- cpu->tr.valid = BX_CPU_THIS_PTR tr.cache.valid;
-
- cpu->gdtr.base = BX_CPU_THIS_PTR gdtr.base;
- cpu->gdtr.limit = BX_CPU_THIS_PTR gdtr.limit;
-
- cpu->idtr.base = BX_CPU_THIS_PTR idtr.base;
- cpu->idtr.limit = BX_CPU_THIS_PTR idtr.limit;
-
- cpu->dr0 = BX_CPU_THIS_PTR dr0;
- cpu->dr1 = BX_CPU_THIS_PTR dr1;
- cpu->dr2 = BX_CPU_THIS_PTR dr2;
- cpu->dr3 = BX_CPU_THIS_PTR dr3;
- cpu->dr6 = BX_CPU_THIS_PTR dr6;
- cpu->dr7 = BX_CPU_THIS_PTR dr7;
-
- cpu->tr3 = 0;
- cpu->tr4 = 0;
- cpu->tr5 = 0;
- cpu->tr6 = 0;
- cpu->tr7 = 0;
-
- // cr0:32=pg,cd,nw,am,wp,ne,ts,em,mp,pe
- cpu->cr0 = BX_CPU_THIS_PTR cr0.val32;
- cpu->cr1 = 0;
- cpu->cr2 = BX_CPU_THIS_PTR cr2;
- cpu->cr3 = BX_CPU_THIS_PTR cr3;
- cpu->cr4 = 0;
-
- cpu->inhibit_mask = BX_CPU_THIS_PTR inhibit_mask;
-
- return(1);
-}
-
- Boolean
-BX_CPU_C::dbg_set_cpu(bx_dbg_cpu_t *cpu)
-{
- // returns 1=OK, 0=Error
- Bit32u val;
- Bit32u type;
-
- // =================================================
- // Do checks first, before setting any CPU registers
- // =================================================
-
- // CS, SS, DS, ES, FS, GS descriptor checks
- if (!cpu->cs.valid) {
- BX_ERROR(( "Error: CS not valid\n" ));
- return(0); // error
- }
- if ( (cpu->cs.des_h & 0x1000) == 0 ) {
- BX_ERROR(( "Error: CS not application type\n" ));
- return(0); // error
- }
- if ( (cpu->cs.des_h & 0x0800) == 0 ) {
- BX_ERROR(( "Error: CS not executable\n" ));
- return(0); // error
- }
-
- if (!cpu->ss.valid) {
- BX_ERROR(( "Error: SS not valid\n" ));
- return(0); // error
- }
- if ( (cpu->ss.des_h & 0x1000) == 0 ) {
- BX_ERROR(( "Error: SS not application type\n" ));
- return(0); // error
- }
-
- if (cpu->ds.valid) {
- if ( (cpu->ds.des_h & 0x1000) == 0 ) {
- BX_ERROR(( "Error: DS not application type\n" ));
- return(0); // error
- }
- }
-
- if (cpu->es.valid) {
- if ( (cpu->es.des_h & 0x1000) == 0 ) {
- BX_ERROR(( "Error: ES not application type\n" ));
- return(0); // error
- }
- }
-
- if (cpu->fs.valid) {
- if ( (cpu->fs.des_h & 0x1000) == 0 ) {
- BX_ERROR(( "Error: FS not application type\n" ));
- return(0); // error
- }
- }
-
- if (cpu->gs.valid) {
- if ( (cpu->gs.des_h & 0x1000) == 0 ) {
- BX_ERROR(( "Error: GS not application type\n" ));
- return(0); // error
- }
- }
-
- if (cpu->ldtr.valid) {
- if ( cpu->ldtr.des_h & 0x1000 ) {
- BX_ERROR(( "Error: LDTR not system type\n" ));
- return(0); // error
- }
- if ( ((cpu->ldtr.des_h >> 8) & 0x0f) != 2 ) {
- BX_ERROR(( "Error: LDTR descriptor type not LDT\n" ));
- return(0); // error
- }
- }
-
- if (cpu->tr.valid) {
- if ( cpu->tr.des_h & 0x1000 ) {
- BX_ERROR(( "Error: TR not system type\n"));
- return(0); // error
- }
- type = (cpu->tr.des_h >> 8) & 0x0f;
-
- if ( (type != 1) && (type != 9) ) {
- BX_ERROR(( "Error: TR descriptor type not TSS\n" ));
- return(0); // error
- }
- }
-
- // =============
- // end of checks
- // =============
-
- EAX = cpu->eax;
- EBX = cpu->ebx;
- ECX = cpu->ecx;
- EDX = cpu->edx;
- EBP = cpu->ebp;
- ESI = cpu->esi;
- EDI = cpu->edi;
- ESP = cpu->esp;
-
- // eflags
- val = cpu->eflags;
- BX_CPU_THIS_PTR set_CF(val & 0x01); val >>= 2;
- BX_CPU_THIS_PTR set_PF(val & 0x01); val >>= 2;
- BX_CPU_THIS_PTR set_AF(val & 0x01); val >>= 2;
- BX_CPU_THIS_PTR set_ZF(val & 0x01); val >>= 1;
- BX_CPU_THIS_PTR set_SF(val & 0x01); val >>= 1;
- BX_CPU_THIS_PTR eflags.tf = val & 0x01; val >>= 1;
- BX_CPU_THIS_PTR eflags.if_ = val & 0x01; val >>= 1;
- BX_CPU_THIS_PTR eflags.df = val & 0x01; val >>= 1;
- BX_CPU_THIS_PTR set_OF(val & 0x01); val >>= 1;
- BX_CPU_THIS_PTR eflags.iopl = val & 0x03; val >>= 2;
- BX_CPU_THIS_PTR eflags.nt = val & 0x01; val >>= 2;
- BX_CPU_THIS_PTR eflags.rf = val & 0x01; val >>= 1;
- BX_CPU_THIS_PTR eflags.vm = val & 0x01; val >>= 1;
-#if BX_CPU_LEVEL >= 4
- BX_CPU_THIS_PTR eflags.ac = val & 0x01; val >>= 1;
- //BX_CPU_THIS_PTR eflags.vif = val & 0x01;
- val >>= 1;
- //BX_CPU_THIS_PTR eflags.vip = val & 0x01;
- val >>= 1;
- BX_CPU_THIS_PTR eflags.id = val & 0x01;
-#endif
-
- BX_CPU_THIS_PTR eip = cpu->eip;
-
-
-
- // CS:
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value = cpu->cs.sel;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.index = cpu->cs.sel >> 3;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.ti = (cpu->cs.sel >> 2) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.rpl = cpu->cs.sel & 0x03;
-
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = cpu->cs.valid;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.p = (cpu->cs.des_h >> 15) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.dpl = (cpu->cs.des_h >> 13) & 0x03;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment = (cpu->cs.des_h >> 12) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.type = (cpu->cs.des_h >> 8) & 0x0f;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.executable = (cpu->cs.des_h >> 11) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.c_ed = (cpu->cs.des_h >> 10) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.r_w = (cpu->cs.des_h >> 9) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.a = (cpu->cs.des_h >> 8) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base = (cpu->cs.des_l >> 16);
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base |= (cpu->cs.des_h & 0xff) << 16;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base |= (cpu->cs.des_h & 0xff000000);
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit = (cpu->cs.des_l & 0xffff);
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit |= (cpu->cs.des_h & 0x000f0000);
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g = (cpu->cs.des_h >> 23) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b = (cpu->cs.des_h >> 22) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.avl = (cpu->cs.des_h >> 20) & 0x01;
- if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g)
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled =
- (BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit << 12) | 0x0fff;
- else
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled =
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit;
-
-
- // SS:
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value = cpu->ss.sel;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.index = cpu->ss.sel >> 3;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.ti = (cpu->ss.sel >> 2) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.rpl = cpu->ss.sel & 0x03;
-
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid = cpu->ss.valid;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.p = (cpu->ss.des_h >> 15) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.dpl = (cpu->ss.des_h >> 13) & 0x03;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.segment = (cpu->ss.des_h >> 12) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.type = (cpu->ss.des_h >> 8) & 0x0f;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.executable = (cpu->ss.des_h >> 11) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.c_ed = (cpu->ss.des_h >> 10) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.r_w = (cpu->ss.des_h >> 9) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.a = (cpu->ss.des_h >> 8) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.base = (cpu->ss.des_l >> 16);
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.base |= (cpu->ss.des_h & 0xff) << 16;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.base |= (cpu->ss.des_h & 0xff000000);
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit = (cpu->ss.des_l & 0xffff);
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit |= (cpu->ss.des_h & 0x000f0000);
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.g = (cpu->ss.des_h >> 23) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b = (cpu->ss.des_h >> 22) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.avl = (cpu->ss.des_h >> 20) & 0x01;
- if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.g)
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit_scaled =
- (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit << 12) | 0x0fff;
- else
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit_scaled =
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit;
-
-
- // DS:
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value = cpu->ds.sel;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.index = cpu->ds.sel >> 3;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.ti = (cpu->ds.sel >> 2) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.rpl = cpu->ds.sel & 0x03;
-
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.valid = cpu->ds.valid;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.p = (cpu->ds.des_h >> 15) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.dpl = (cpu->ds.des_h >> 13) & 0x03;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.segment = (cpu->ds.des_h >> 12) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.type = (cpu->ds.des_h >> 8) & 0x0f;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.executable = (cpu->ds.des_h >> 11) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.c_ed = (cpu->ds.des_h >> 10) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.r_w = (cpu->ds.des_h >> 9) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.a = (cpu->ds.des_h >> 8) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.base = (cpu->ds.des_l >> 16);
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.base |= (cpu->ds.des_h & 0xff) << 16;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.base |= (cpu->ds.des_h & 0xff000000);
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.limit = (cpu->ds.des_l & 0xffff);
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.limit |= (cpu->ds.des_h & 0x000f0000);
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.g = (cpu->ds.des_h >> 23) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.d_b = (cpu->ds.des_h >> 22) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.avl = (cpu->ds.des_h >> 20) & 0x01;
- if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.g)
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.limit_scaled =
- (BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.limit << 12) | 0x0fff;
- else
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.limit_scaled =
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.limit;
-
-
-
- // ES:
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value = cpu->es.sel;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.index = cpu->es.sel >> 3;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.ti = (cpu->es.sel >> 2) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.rpl = cpu->es.sel & 0x03;
-
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.valid = cpu->es.valid;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.p = (cpu->es.des_h >> 15) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.dpl = (cpu->es.des_h >> 13) & 0x03;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.segment = (cpu->es.des_h >> 12) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.type = (cpu->es.des_h >> 8) & 0x0f;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.executable = (cpu->es.des_h >> 11) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.c_ed = (cpu->es.des_h >> 10) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.r_w = (cpu->es.des_h >> 9) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.a = (cpu->es.des_h >> 8) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.base = (cpu->es.des_l >> 16);
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.base |= (cpu->es.des_h & 0xff) << 16;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.base |= (cpu->es.des_h & 0xff000000);
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.limit = (cpu->es.des_l & 0xffff);
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.limit |= (cpu->es.des_h & 0x000f0000);
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.g = (cpu->es.des_h >> 23) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.d_b = (cpu->es.des_h >> 22) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.avl = (cpu->es.des_h >> 20) & 0x01;
- if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.g)
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.limit_scaled =
- (BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.limit << 12) | 0x0fff;
- else
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.limit_scaled =
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.limit;
-
-
- // FS:
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value = cpu->fs.sel;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.index = cpu->fs.sel >> 3;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.ti = (cpu->fs.sel >> 2) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.rpl = cpu->fs.sel & 0x03;
-
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.valid = cpu->fs.valid;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.p = (cpu->fs.des_h >> 15) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.dpl = (cpu->fs.des_h >> 13) & 0x03;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.segment = (cpu->fs.des_h >> 12) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.type = (cpu->fs.des_h >> 8) & 0x0f;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.executable = (cpu->fs.des_h >> 11) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.c_ed = (cpu->fs.des_h >> 10) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.r_w = (cpu->fs.des_h >> 9) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.a = (cpu->fs.des_h >> 8) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.base = (cpu->fs.des_l >> 16);
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.base |= (cpu->fs.des_h & 0xff) << 16;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.base |= (cpu->fs.des_h & 0xff000000);
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.limit = (cpu->fs.des_l & 0xffff);
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.limit |= (cpu->fs.des_h & 0x000f0000);
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.g = (cpu->fs.des_h >> 23) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.d_b = (cpu->fs.des_h >> 22) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.avl = (cpu->fs.des_h >> 20) & 0x01;
- if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.g)
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.limit_scaled =
- (BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.limit << 12) | 0x0fff;
- else
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.limit_scaled =
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.limit;
-
-
- // GS:
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value = cpu->gs.sel;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.index = cpu->gs.sel >> 3;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.ti = (cpu->gs.sel >> 2) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.rpl = cpu->gs.sel & 0x03;
-
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.valid = cpu->gs.valid;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.p = (cpu->gs.des_h >> 15) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.dpl = (cpu->gs.des_h >> 13) & 0x03;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.segment = (cpu->gs.des_h >> 12) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.type = (cpu->gs.des_h >> 8) & 0x0f;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.executable = (cpu->gs.des_h >> 11) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.c_ed = (cpu->gs.des_h >> 10) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.r_w = (cpu->gs.des_h >> 9) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.a = (cpu->gs.des_h >> 8) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.base = (cpu->gs.des_l >> 16);
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.base |= (cpu->gs.des_h & 0xff) << 16;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.base |= (cpu->gs.des_h & 0xff000000);
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.limit = (cpu->gs.des_l & 0xffff);
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.limit |= (cpu->gs.des_h & 0x000f0000);
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.g = (cpu->gs.des_h >> 23) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.d_b = (cpu->gs.des_h >> 22) & 0x01;
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.avl = (cpu->gs.des_h >> 20) & 0x01;
- if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.g)
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.limit_scaled =
- (BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.limit << 12) | 0x0fff;
- else
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.limit_scaled =
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.limit;
-
- // LDTR:
- BX_CPU_THIS_PTR ldtr.selector.value = cpu->ldtr.sel;
- BX_CPU_THIS_PTR ldtr.selector.index = cpu->ldtr.sel >> 3;
- BX_CPU_THIS_PTR ldtr.selector.ti = (cpu->ldtr.sel >> 2) & 0x01;
- BX_CPU_THIS_PTR ldtr.selector.rpl = cpu->ldtr.sel & 0x03;
-
- BX_CPU_THIS_PTR ldtr.cache.valid = cpu->ldtr.valid;
- BX_CPU_THIS_PTR ldtr.cache.p = (cpu->ldtr.des_h >> 15) & 0x01;
- BX_CPU_THIS_PTR ldtr.cache.dpl = (cpu->ldtr.des_h >> 13) & 0x03;
- BX_CPU_THIS_PTR ldtr.cache.segment = (cpu->ldtr.des_h >> 12) & 0x01;
- BX_CPU_THIS_PTR ldtr.cache.type = (cpu->ldtr.des_h >> 8) & 0x0f;
- BX_CPU_THIS_PTR ldtr.cache.u.ldt.base = (cpu->ldtr.des_l >> 16);
- BX_CPU_THIS_PTR ldtr.cache.u.ldt.base |= (cpu->ldtr.des_h & 0xff) << 16;
- BX_CPU_THIS_PTR ldtr.cache.u.ldt.base |= (cpu->ldtr.des_h & 0xff000000);
- BX_CPU_THIS_PTR ldtr.cache.u.ldt.limit = (cpu->ldtr.des_l & 0xffff);
-
- // TR
- type = (cpu->tr.des_h >> 8) & 0x0f;
- BX_CPU_THIS_PTR tr.selector.value = cpu->tr.sel;
- BX_CPU_THIS_PTR tr.selector.index = cpu->tr.sel >> 3;
- BX_CPU_THIS_PTR tr.selector.ti = (cpu->tr.sel >> 2) & 0x01;
- BX_CPU_THIS_PTR tr.selector.rpl = cpu->tr.sel & 0x03;
-
- BX_CPU_THIS_PTR tr.cache.valid = cpu->tr.valid;
- BX_CPU_THIS_PTR tr.cache.p = (cpu->tr.des_h >> 15) & 0x01;
- BX_CPU_THIS_PTR tr.cache.dpl = (cpu->tr.des_h >> 13) & 0x03;
- BX_CPU_THIS_PTR tr.cache.segment = (cpu->tr.des_h >> 12) & 0x01;
- BX_CPU_THIS_PTR tr.cache.type = type;
- if (type == 1) { // 286 TSS
- BX_CPU_THIS_PTR tr.cache.u.tss286.base = (cpu->tr.des_l >> 16);
- BX_CPU_THIS_PTR tr.cache.u.tss286.base |= (cpu->tr.des_h & 0xff) << 16;
- BX_CPU_THIS_PTR tr.cache.u.tss286.limit = (cpu->tr.des_l & 0xffff);
- }
- else { // type == 9, 386 TSS
- BX_CPU_THIS_PTR tr.cache.u.tss386.base = (cpu->tr.des_l >> 16);
- BX_CPU_THIS_PTR tr.cache.u.tss386.base |= (cpu->tr.des_h & 0xff) << 16;
- BX_CPU_THIS_PTR tr.cache.u.tss386.base |= (cpu->tr.des_h & 0xff000000);
- BX_CPU_THIS_PTR tr.cache.u.tss386.limit = (cpu->tr.des_l & 0xffff);
- BX_CPU_THIS_PTR tr.cache.u.tss386.limit |= (cpu->tr.des_h & 0x000f0000);
- BX_CPU_THIS_PTR tr.cache.u.tss386.g = (cpu->tr.des_h >> 23) & 0x01;
- BX_CPU_THIS_PTR tr.cache.u.tss386.avl = (cpu->tr.des_h >> 20) & 0x01;
- }
-
-
- // gdtr
- BX_CPU_THIS_PTR gdtr.base = cpu->gdtr.base;
- BX_CPU_THIS_PTR gdtr.limit = cpu->gdtr.limit;
-
- // idtr
- BX_CPU_THIS_PTR idtr.base = cpu->idtr.base;
- BX_CPU_THIS_PTR idtr.limit = cpu->idtr.limit;
-
-
- BX_CPU_THIS_PTR dr0 = cpu->dr0;
- BX_CPU_THIS_PTR dr1 = cpu->dr1;
- BX_CPU_THIS_PTR dr2 = cpu->dr2;
- BX_CPU_THIS_PTR dr3 = cpu->dr3;
- BX_CPU_THIS_PTR dr6 = cpu->dr6;
- BX_CPU_THIS_PTR dr7 = cpu->dr7;
-
- // BX_CPU_THIS_PTR tr3 = cpu->tr3;
- // BX_CPU_THIS_PTR tr4 = cpu->tr4;
- // BX_CPU_THIS_PTR tr5 = cpu->tr5;
- // BX_CPU_THIS_PTR tr6 = cpu->tr6;
- // BX_CPU_THIS_PTR tr7 = cpu->tr7;
-
-
- // cr0, cr1, cr2, cr3, cr4
- SetCR0(cpu->cr0);
- BX_CPU_THIS_PTR cr1 = cpu->cr1;
- BX_CPU_THIS_PTR cr2 = cpu->cr2;
- BX_CPU_THIS_PTR cr3 = cpu->cr3;
-#if BX_CPU_LEVEL >= 5
- BX_CPU_THIS_PTR cr4 = cpu->cr4;
-#endif
-
- BX_CPU_THIS_PTR inhibit_mask = cpu->inhibit_mask;
-
- //
- // flush cached items, prefetch, paging, etc
- //
- BX_CPU_THIS_PTR CR3_change(cpu->cr3);
- BX_CPU_THIS_PTR invalidate_prefetch_q();
- BX_CPU_THIS_PTR async_event = 1;
-
- return(1);
-}
-
-#if BX_SIM_ID == 0
-# define BX_DBG_NULL_CALLBACK bx_dbg_null_callback0
-#else
-# define BX_DBG_NULL_CALLBACK bx_dbg_null_callback1
-#endif
- void
-BX_DBG_NULL_CALLBACK(unsigned val)
-{
- // bochs uses the pc_system variables, so this function is
- // a stub for notification by the debugger, that a change
- // occurred.
- UNUSED(val);
-}
-
- void
-#if BX_SIM_ID == 0
-bx_dbg_init_cpu_mem_env0(bx_dbg_callback_t *callback, int argc, char *argv[])
-#else
-bx_dbg_init_cpu_mem_env1(bx_dbg_callback_t *callback, int argc, char *argv[])
-#endif
-{
- UNUSED(argc);
- UNUSED(argv);
-
-#if 0
-#warning hardcoding BX_CPU_THIS_PTR mem[0] and cpu[0]
- callback->setphymem = BX_MEM(0)->dbg_set_mem;
- callback->getphymem = BX_MEM(0)->dbg_fetch_mem;
- callback->xlate_linear2phy = BX_CPU(0)->dbg_xlate_linear2phy;
- callback->set_reg = BX_CPU(0)->dbg_set_reg;
- callback->get_reg = BX_CPU(0)->dbg_get_reg;
- callback->get_sreg = BX_CPU(0)->dbg_get_sreg;
- callback->get_cpu = BX_CPU(0)->dbg_get_cpu;
- callback->set_cpu = BX_CPU(0)->dbg_set_cpu;
- callback->dirty_page_tbl_size = sizeof(BX_MEM(0)->dbg_dirty_pages);
- callback->dirty_page_tbl = BX_MEM(0)->dbg_dirty_pages;
- callback->atexit = BX_CPU(0)->atexit;
- callback->query_pending = BX_CPU(0)->dbg_query_pending;
- callback->execute = BX_CPU(0)->cpu_loop;
- callback->take_irq = BX_CPU(0)->dbg_take_irq;
- callback->take_dma = BX_CPU(0)->dbg_take_dma;
- callback->reset_cpu = BX_CPU(0)->reset;
- callback->init_mem = BX_MEM(0)->init_memory;
- callback->load_ROM = BX_MEM(0)->load_ROM;
- callback->set_A20 = NULL;
- callback->set_NMI = BX_DBG_NULL_CALLBACK;
- callback->set_RESET = BX_DBG_NULL_CALLBACK;
- callback->set_INTR = BX_CPU(0)->set_INTR;
- callback->force_interrupt = BX_CPU(0)->dbg_force_interrupt;
-
-#if BX_INSTRUMENTATION
- callback->instr_start = bx_instr_start;
- callback->instr_stop = bx_instr_stop;
- callback->instr_reset = bx_instr_reset;
- callback->instr_print = bx_instr_print;
-#endif
-#if BX_USE_LOADER
- callback->loader = bx_dbg_loader;
-#endif
- callback->crc32 = BX_MEM(0)->dbg_crc32;
-#endif
-}
-
-
-
- void
-BX_CPU_C::atexit(void)
-{
- if (protected_mode()) BX_INFO(("protected mode\n" ));
- else if (v8086_mode()) BX_INFO(("v8086 mode\n" ));
- else BX_INFO(("real mode\n"));
- BX_INFO(("CS.d_b = %u bit\n",
- BX_CPU_THIS_PTR sregs[BX_SREG_CS].cache.u.segment.d_b ? 32 : 16 ));
- if (protected_mode()) BX_INFO(("protected mode\n"));
- else if (v8086_mode()) BX_INFO(("v8086 mode\n"));
- else BX_INFO(("real mode\n"));
- BX_INFO(("CS.d_b = %u bit\n",
- BX_CPU_THIS_PTR sregs[BX_SREG_CS].cache.u.segment.d_b ? 32 : 16));
- BX_INFO(("SS.d_b = %u bit\n",
- BX_CPU_THIS_PTR sregs[BX_SREG_SS].cache.u.segment.d_b ? 32 : 16));
-
- debug(BX_CPU_THIS_PTR prev_eip);
-}
-#endif // #if BX_DEBUGGER
#endif // #if BX_DISASM
}
+#if BX_SUPPORT_SID
+ Bit32u
+BX_CPU_C::dbg_get_reg(unsigned reg)
+{
+ Bit32u return_val32;
+
+ switch (reg) {
+ case BX_DBG_REG_EAX: return(EAX);
+ case BX_DBG_REG_ECX: return(ECX);
+ case BX_DBG_REG_EDX: return(EDX);
+ case BX_DBG_REG_EBX: return(EBX);
+ case BX_DBG_REG_ESP: return(ESP);
+ case BX_DBG_REG_EBP: return(EBP);
+ case BX_DBG_REG_ESI: return(ESI);
+ case BX_DBG_REG_EDI: return(EDI);
+ case BX_DBG_REG_EIP: return(EIP);
+ case BX_DBG_REG_EFLAGS:
+ return_val32 = dbg_get_eflags();
+ return(return_val32);
+ case BX_DBG_REG_CS: return(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
+ case BX_DBG_REG_SS: return(BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value);
+ case BX_DBG_REG_DS: return(BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value);
+ case BX_DBG_REG_ES: return(BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value);
+ case BX_DBG_REG_FS: return(BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value);
+ case BX_DBG_REG_GS: return(BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value);
+ default:
+ BX_PANIC(("get_reg: request for unknown register\n"));
+ return(0);
+ }
+}
+
+ Boolean
+BX_CPU_C::dbg_set_reg(unsigned reg, Bit32u val)
+{
+ // returns 1=OK, 0=can't change
+ bx_segment_reg_t *seg;
+ Bit32u current_sys_bits;
+
+ switch (reg) {
+ case BX_DBG_REG_EAX: EAX = val; return(1);
+ case BX_DBG_REG_ECX: ECX = val; return(1);
+ case BX_DBG_REG_EDX: EDX = val; return(1);
+ case BX_DBG_REG_EBX: EBX = val; return(1);
+ case BX_DBG_REG_ESP: ESP = val; return(1);
+ case BX_DBG_REG_EBP: EBP = val; return(1);
+ case BX_DBG_REG_ESI: ESI = val; return(1);
+ case BX_DBG_REG_EDI: EDI = val; return(1);
+ case BX_DBG_REG_EIP: EIP = val; return(1);
+ case BX_DBG_REG_EFLAGS:
+ BX_INFO(("dbg_set_reg: can not handle eflags yet.\n"));
+ if ( val & 0xffff0000 ) {
+ BX_INFO(("dbg_set_reg: can not set upper 16 bits of eflags.\n"));
+ return(0);
+ }
+ // make sure none of the system bits are being changed
+ current_sys_bits = (BX_CPU_THIS_PTR eflags.nt << 14) |
+ (BX_CPU_THIS_PTR eflags.iopl << 12) |
+ (BX_CPU_THIS_PTR eflags.tf << 8);
+ if ( current_sys_bits != (val & 0x0000f100) ) {
+ BX_INFO(("dbg_set_reg: can not modify NT, IOPL, or TF.\n"));
+ return(0);
+ }
+ BX_CPU_THIS_PTR set_CF(val & 0x01); val >>= 2;
+ BX_CPU_THIS_PTR set_PF(val & 0x01); val >>= 2;
+ BX_CPU_THIS_PTR set_AF(val & 0x01); val >>= 2;
+ BX_CPU_THIS_PTR set_ZF(val & 0x01); val >>= 1;
+ BX_CPU_THIS_PTR set_SF(val & 0x01); val >>= 2;
+ BX_CPU_THIS_PTR eflags.if_ = val & 0x01; val >>= 1;
+ BX_CPU_THIS_PTR eflags.df = val & 0x01; val >>= 1;
+ BX_CPU_THIS_PTR set_OF(val & 0x01);
+ if (BX_CPU_THIS_PTR eflags.if_)
+ BX_CPU_THIS_PTR async_event = 1;
+ return(1);
+ case BX_DBG_REG_CS:
+ seg = &BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS];
+ break;
+ case BX_DBG_REG_SS:
+ seg = &BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS];
+ break;
+ case BX_DBG_REG_DS:
+ seg = &BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS];
+ break;
+ case BX_DBG_REG_ES:
+ seg = &BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES];
+ break;
+ case BX_DBG_REG_FS:
+ seg = &BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS];
+ break;
+ case BX_DBG_REG_GS:
+ seg = &BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS];
+ break;
+ default:
+ BX_PANIC(("dbg_set_reg: unrecognized register ID (%u)\n", reg));
+ return(0);
+ }
+
+ if (BX_CPU_THIS_PTR real_mode()) {
+ seg->selector.value = val;
+ seg->cache.valid = 1;
+ seg->cache.p = 1;
+ seg->cache.dpl = 0;
+ seg->cache.segment = 1; // regular segment
+ if (reg == BX_DBG_REG_CS) {
+ seg->cache.u.segment.executable = 1; // code segment
+ }
+ else {
+ seg->cache.u.segment.executable = 0; // data segment
+ }
+ seg->cache.u.segment.c_ed = 0; // expand up/non-conforming
+ seg->cache.u.segment.r_w = 1; // writeable
+ seg->cache.u.segment.a = 1; // accessed
+ seg->cache.u.segment.base = val << 4;
+ seg->cache.u.segment.limit = 0xffff;
+ seg->cache.u.segment.limit_scaled = 0xffff;
+ seg->cache.u.segment.g = 0; // byte granular
+ seg->cache.u.segment.d_b = 0; // default 16bit size
+ seg->cache.u.segment.avl = 0;
+ return(1); // ok
+ }
+
+ return(0); // can't change when not in real mode
+}
+ Bit32u
+BX_CPU_C::dbg_get_eflags(void)
+{
+ Bit32u val32;
+
+ val32 =
+ (BX_CPU_THIS_PTR get_CF()) |
+ (BX_CPU_THIS_PTR eflags.bit1 << 1) |
+ ((BX_CPU_THIS_PTR get_PF()) << 2) |
+ (BX_CPU_THIS_PTR eflags.bit3 << 3) |
+ ((BX_CPU_THIS_PTR get_AF()>0) << 4) |
+ (BX_CPU_THIS_PTR eflags.bit5 << 5) |
+ ((BX_CPU_THIS_PTR get_ZF()>0) << 6) |
+ ((BX_CPU_THIS_PTR get_SF()>0) << 7) |
+ (BX_CPU_THIS_PTR eflags.tf << 8) |
+ (BX_CPU_THIS_PTR eflags.if_ << 9) |
+ (BX_CPU_THIS_PTR eflags.df << 10) |
+ ((BX_CPU_THIS_PTR get_OF()>0) << 11) |
+ (BX_CPU_THIS_PTR eflags.iopl << 12) |
+ (BX_CPU_THIS_PTR eflags.nt << 14) |
+ (BX_CPU_THIS_PTR eflags.bit15 << 15) |
+ (BX_CPU_THIS_PTR eflags.rf << 16) |
+ (BX_CPU_THIS_PTR eflags.vm << 17);
+#if BX_CPU_LEVEL >= 4
+ val32 |= (BX_CPU_THIS_PTR eflags.ac << 18);
+ //val32 |= (BX_CPU_THIS_PTR eflags.vif << 19);
+ //val32 |= (BX_CPU_THIS_PTR eflags.vip << 20);
+ val32 |= (BX_CPU_THIS_PTR eflags.id << 21);
+#endif
+ return(val32);
+}
+#else // BX_SUPPORT_SID
#if BX_DEBUGGER
Bit32u
BX_CPU_C::dbg_get_reg(unsigned reg)
}
#endif // #if BX_DEBUGGER
+#endif // BX_SUPPORT_SID
void
BX_CPU_C::atexit(void)
#include "bochs.h"
#define LOG_THIS BX_CPU_THIS_PTR
-#if BX_USE_CPU_SMF
+
+
+#if 0
static Bit16u *aaa[8] = {
& BX,
& BX,
(Bit16u *) & BX_CPU_THIS_PTR empty_register,
(Bit16u *) & BX_CPU_THIS_PTR empty_register
};
-#endif // BX_USE_CPU_SMF
+#endif
+
+++ /dev/null
-// exception-sid.cc - override the bochs cpu interrupt member function. -*- C++ -*-
-//
-// Copyright (C) 2001 Red Hat.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-
-
-#define NEED_CPU_REG_SHORTCUTS 1
-#include "bochs.h"
-#define LOG_THIS BX_CPU_THIS_PTR
-
-#include "x86.h"
-
- void
-sid_cpu_c::interrupt(Bit8u vector, Boolean is_INT, Boolean is_error_code,
- Bit16u error_code)
-{
- if (vector == 0x80)
- {
- int temp = this->gen_reg[0].erx;
- this->sid_cpu->do_syscall();
-#if X86_CPU_DEBUG
- printf("Syscall number: %d was executed with the following return value: %d\n", temp, this->gen_reg[0].erx);
-#endif
- }
- else if (vector == 0x03)
- {
- // INT3 was encountered -- trap to debugger
- this->sid_cpu->do_breakpoint();
- }
- else
- {
- BX_CPU_C::interrupt(vector, is_INT, is_error_code, error_code);
- }
-}
#define LOG_THIS BX_CPU_THIS_PTR
+#if BX_SUPPORT_SID
+#include "sid-x86-cpu-wrapper.h"
+#endif
/* Exception classes. These are used as indexes into the 'is_exception_OK'
BX_CPU_C::interrupt(Bit8u vector, Boolean is_INT, Boolean is_error_code,
Bit16u error_code)
{
+#if BX_SUPPORT_SID
+ bx_dbg.interrupts = 1;
+ if (!x86_cpu_component->hardware_mode())
+ {
+ // Use 0x80 as the syscall interrupt number.
+ if (vector == 0x80)
+ {
+ int temp = this->gen_reg[0].erx;
+ x86_cpu_component->do_syscall();
+#if X86_CPU_DEBUG
+ printf("Syscall number: %d was executed with the following return value: %d\n", temp, this->gen_reg[0].erx);
+#endif
+ return;
+ }
+ else if (vector == 0x03)
+ {
+ // INT3 was encountered -- trap to debugger.
+ x86_cpu_component->do_breakpoint();
+ return;
+ }
+ // If not performing a syscall, or trapping to the debugger,
+ // fall through to generic interrupt handling.
+ }
+#endif
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_intsig;
#if BX_DEBUG_LINUX
+++ /dev/null
-// fetchdecode-sid.cc - override the bochs cpu fetchdecode member function. -*- C++ -*-
-//
-// Copyright (C) 2001 Red Hat.
-//
-// Copyright (C) 2001 MandrakeSoft S.A.
-//
-// MandrakeSoft S.A.
-// 43, rue d'Aboukir
-// 75002 Paris - France
-// http://www.linux-mandrake.com/
-// http://www.mandrakesoft.com/
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-
-#define NEED_CPU_REG_SHORTCUTS 1
-#include "bochs.h"
-#define LOG_THIS BX_CPU_THIS_PTR
-
-
-///////////////////////////
-// prefix bytes
-// opcode bytes
-// modrm/sib
-// address displacement
-// immediate constant
-///////////////////////////
-
-
-
-// sign extended to osize:
-// 6a push ib
-// 6b imul gvevib
-// 70..7f jo..jnle
-// 83 G1 0..7 ADD..CMP Evib
-
-// is 6b imul_gvevib sign extended? don't think
-// I'm sign extending it properly in old decode/execute
-
-//check all the groups. Make sure to add duplicates rather
-// than error.
-
-// mark instructions as changing control transfer, then
-// don't always load from fetch_ptr, etc.
-
-// cant use immediate as another because of Group3 where
-// some have immediate and some don't, and those won't
-// be picked up by logic until indirection.
-
-// get attr and execute ptr at same time
-
-// maybe move 16bit only i's like MOV_EwSw, MOV_SwEw
-// to 32 bit modules.
-
-// use 0F as a prefix too?
-
-
-
-#if 0
-void BxResolveError(BxInstruction_t *);
-#endif
-
-#if BX_DYNAMIC_TRANSLATION
-// For 16-bit address mode, this matrix describes the registers
-// used to formulate the offset, indexed by the RM field.
-// This info is needed by the dynamic translation code for dataflow.
-static unsigned BxMemRegsUsed16[8] = {
- (1<<3) | (1<<6), // BX + SI
- (1<<3) | (1<<7), // BX + DI
- (1<<5) | (1<<6), // BP + SI
- (1<<5) | (1<<7), // BP + DI
- (1<<6), // SI
- (1<<7), // DI
- (1<<5), // BP
- (1<<3) // BX
- };
-#endif
-
-static BxExecutePtr_t BxResolve16Mod0[8] = {
- &BX_CPU_C::Resolve16Mod0Rm0,
- &BX_CPU_C::Resolve16Mod0Rm1,
- &BX_CPU_C::Resolve16Mod0Rm2,
- &BX_CPU_C::Resolve16Mod0Rm3,
- &BX_CPU_C::Resolve16Mod0Rm4,
- &BX_CPU_C::Resolve16Mod0Rm5,
- NULL, // d16, no registers used
- &BX_CPU_C::Resolve16Mod0Rm7
- };
-
-static BxExecutePtr_t BxResolve16Mod1or2[8] = {
- &BX_CPU_C::Resolve16Mod1or2Rm0,
- &BX_CPU_C::Resolve16Mod1or2Rm1,
- &BX_CPU_C::Resolve16Mod1or2Rm2,
- &BX_CPU_C::Resolve16Mod1or2Rm3,
- &BX_CPU_C::Resolve16Mod1or2Rm4,
- &BX_CPU_C::Resolve16Mod1or2Rm5,
- &BX_CPU_C::Resolve16Mod1or2Rm6,
- &BX_CPU_C::Resolve16Mod1or2Rm7
- };
-
-static BxExecutePtr_t BxResolve32Mod0[8] = {
- &BX_CPU_C::Resolve32Mod0Rm0,
- &BX_CPU_C::Resolve32Mod0Rm1,
- &BX_CPU_C::Resolve32Mod0Rm2,
- &BX_CPU_C::Resolve32Mod0Rm3,
- NULL, // escape to 2-byte
- NULL, // d32, no registers used
- &BX_CPU_C::Resolve32Mod0Rm6,
- &BX_CPU_C::Resolve32Mod0Rm7
- };
-
-static BxExecutePtr_t BxResolve32Mod1or2[8] = {
- &BX_CPU_C::Resolve32Mod1or2Rm0,
- &BX_CPU_C::Resolve32Mod1or2Rm1,
- &BX_CPU_C::Resolve32Mod1or2Rm2,
- &BX_CPU_C::Resolve32Mod1or2Rm3,
- NULL, // escape to 2-byte
- &BX_CPU_C::Resolve32Mod1or2Rm5,
- &BX_CPU_C::Resolve32Mod1or2Rm6,
- &BX_CPU_C::Resolve32Mod1or2Rm7
- };
-
-static BxExecutePtr_t BxResolve32Mod0Base[8] = {
- &BX_CPU_C::Resolve32Mod0Base0,
- &BX_CPU_C::Resolve32Mod0Base1,
- &BX_CPU_C::Resolve32Mod0Base2,
- &BX_CPU_C::Resolve32Mod0Base3,
- &BX_CPU_C::Resolve32Mod0Base4,
- &BX_CPU_C::Resolve32Mod0Base5,
- &BX_CPU_C::Resolve32Mod0Base6,
- &BX_CPU_C::Resolve32Mod0Base7,
- };
-
-static BxExecutePtr_t BxResolve32Mod1or2Base[8] = {
- &BX_CPU_C::Resolve32Mod1or2Base0,
- &BX_CPU_C::Resolve32Mod1or2Base1,
- &BX_CPU_C::Resolve32Mod1or2Base2,
- &BX_CPU_C::Resolve32Mod1or2Base3,
- &BX_CPU_C::Resolve32Mod1or2Base4,
- &BX_CPU_C::Resolve32Mod1or2Base5,
- &BX_CPU_C::Resolve32Mod1or2Base6,
- &BX_CPU_C::Resolve32Mod1or2Base7,
- };
-
-typedef struct BxOpcodeInfo_t {
- Bit16u Attr;
- SidExecutePtr_t ExecutePtr;
- struct BxOpcodeInfo_t *AnotherArray;
-} BxOpcodeInfo_t;
-
-static BxOpcodeInfo_t BxOpcodeInfoG1EbIb[8] = {
- /* 0 */ { BxImmediate_Ib, &BX_CPU_C::ADD_EbIb },
- /* 1 */ { BxImmediate_Ib, &BX_CPU_C::OR_EbIb },
- /* 2 */ { BxImmediate_Ib, &BX_CPU_C::ADC_EbIb },
- /* 3 */ { BxImmediate_Ib, &BX_CPU_C::SBB_EbIb },
- /* 4 */ { BxImmediate_Ib, &BX_CPU_C::AND_EbIb },
- /* 5 */ { BxImmediate_Ib, &BX_CPU_C::SUB_EbIb },
- /* 6 */ { BxImmediate_Ib, &BX_CPU_C::XOR_EbIb },
- /* 7 */ { BxImmediate_Ib, &BX_CPU_C::CMP_EbIb }
- };
-
-static BxOpcodeInfo_t BxOpcodeInfoG1Ew[8] = {
- // attributes defined in main area
- /* 0 */ { 0, &BX_CPU_C::ADD_EwIw },
- /* 1 */ { 0, &BX_CPU_C::OR_EwIw },
- /* 2 */ { 0, &BX_CPU_C::ADC_EwIw },
- /* 3 */ { 0, &BX_CPU_C::SBB_EwIw },
- /* 4 */ { 0, &BX_CPU_C::AND_EwIw },
- /* 5 */ { 0, &BX_CPU_C::SUB_EwIw },
- /* 6 */ { 0, &BX_CPU_C::XOR_EwIw },
- /* 7 */ { 0, &BX_CPU_C::CMP_EwIw }
- };
-
-static BxOpcodeInfo_t BxOpcodeInfoG1Ed[8] = {
- // attributes defined in main area
- /* 0 */ { 0, &BX_CPU_C::ADD_EdId },
- /* 1 */ { 0, &BX_CPU_C::OR_EdId },
- /* 2 */ { 0, &BX_CPU_C::ADC_EdId },
- /* 3 */ { 0, &BX_CPU_C::SBB_EdId },
- /* 4 */ { 0, &BX_CPU_C::AND_EdId },
- /* 5 */ { 0, &BX_CPU_C::SUB_EdId },
- /* 6 */ { 0, &BX_CPU_C::XOR_EdId },
- /* 7 */ { 0, &BX_CPU_C::CMP_EdId }
- };
-
-static BxOpcodeInfo_t BxOpcodeInfoG2Eb[8] = {
- // attributes defined in main area
- /* 0 */ { 0, &BX_CPU_C::ROL_Eb },
- /* 1 */ { 0, &BX_CPU_C::ROR_Eb },
- /* 2 */ { 0, &BX_CPU_C::RCL_Eb },
- /* 3 */ { 0, &BX_CPU_C::RCR_Eb },
- /* 4 */ { 0, &BX_CPU_C::SHL_Eb },
- /* 5 */ { 0, &BX_CPU_C::SHR_Eb },
- /* 6 */ { 0, &BX_CPU_C::SHL_Eb },
- /* 7 */ { 0, &BX_CPU_C::SAR_Eb }
- };
-
-static BxOpcodeInfo_t BxOpcodeInfoG2Ew[8] = {
- // attributes defined in main area
- /* 0 */ { 0, &BX_CPU_C::ROL_Ew },
- /* 1 */ { 0, &BX_CPU_C::ROR_Ew },
- /* 2 */ { 0, &BX_CPU_C::RCL_Ew },
- /* 3 */ { 0, &BX_CPU_C::RCR_Ew },
- /* 4 */ { 0, &BX_CPU_C::SHL_Ew },
- /* 5 */ { 0, &BX_CPU_C::SHR_Ew },
- /* 6 */ { 0, &BX_CPU_C::SHL_Ew },
- /* 7 */ { 0, &BX_CPU_C::SAR_Ew }
- };
-
-static BxOpcodeInfo_t BxOpcodeInfoG2Ed[8] = {
- // attributes defined in main area
- /* 0 */ { 0, &BX_CPU_C::ROL_Ed },
- /* 1 */ { 0, &BX_CPU_C::ROR_Ed },
- /* 2 */ { 0, &BX_CPU_C::RCL_Ed },
- /* 3 */ { 0, &BX_CPU_C::RCR_Ed },
- /* 4 */ { 0, &BX_CPU_C::SHL_Ed },
- /* 5 */ { 0, &BX_CPU_C::SHR_Ed },
- /* 6 */ { 0, &BX_CPU_C::SHL_Ed },
- /* 7 */ { 0, &BX_CPU_C::SAR_Ed }
- };
-
-static BxOpcodeInfo_t BxOpcodeInfoG3Eb[8] = {
- /* 0 */ { BxImmediate_Ib, &BX_CPU_C::TEST_EbIb },
- /* 1 */ { BxImmediate_Ib, &BX_CPU_C::TEST_EbIb },
- /* 2 */ { 0, &BX_CPU_C::NOT_Eb },
- /* 3 */ { 0, &BX_CPU_C::NEG_Eb },
- /* 4 */ { 0, &BX_CPU_C::MUL_ALEb },
- /* 5 */ { 0, &BX_CPU_C::IMUL_ALEb },
- /* 6 */ { 0, &BX_CPU_C::DIV_ALEb },
- /* 7 */ { 0, &BX_CPU_C::IDIV_ALEb }
- };
-
-static BxOpcodeInfo_t BxOpcodeInfoG3Ew[8] = {
- /* 0 */ { BxImmediate_Iw, &BX_CPU_C::TEST_EwIw },
- /* 1 */ { BxImmediate_Iw, &BX_CPU_C::TEST_EwIw },
- /* 2 */ { 0, &BX_CPU_C::NOT_Ew },
- /* 3 */ { 0, &BX_CPU_C::NEG_Ew },
- /* 4 */ { 0, &BX_CPU_C::MUL_AXEw },
- /* 5 */ { 0, &BX_CPU_C::IMUL_AXEw },
- /* 6 */ { 0, &BX_CPU_C::DIV_AXEw },
- /* 7 */ { 0, &BX_CPU_C::IDIV_AXEw }
- };
-
-static BxOpcodeInfo_t BxOpcodeInfoG3Ed[8] = {
- /* 0 */ { BxImmediate_Iv, &BX_CPU_C::TEST_EdId },
- /* 1 */ { BxImmediate_Iv, &BX_CPU_C::TEST_EdId },
- /* 2 */ { 0, &BX_CPU_C::NOT_Ed },
- /* 3 */ { 0, &BX_CPU_C::NEG_Ed },
- /* 4 */ { 0, &BX_CPU_C::MUL_EAXEd },
- /* 5 */ { 0, &BX_CPU_C::IMUL_EAXEd },
- /* 6 */ { 0, &BX_CPU_C::DIV_EAXEd },
- /* 7 */ { 0, &BX_CPU_C::IDIV_EAXEd }
- };
-
-static BxOpcodeInfo_t BxOpcodeInfoG4[8] = {
- /* 0 */ { 0, &BX_CPU_C::INC_Eb },
- /* 1 */ { 0, &BX_CPU_C::DEC_Eb },
- /* 2 */ { 0, &BX_CPU_C::BxError },
- /* 3 */ { 0, &BX_CPU_C::BxError },
- /* 4 */ { 0, &BX_CPU_C::BxError },
- /* 5 */ { 0, &BX_CPU_C::BxError },
- /* 6 */ { 0, &BX_CPU_C::BxError },
- /* 7 */ { 0, &BX_CPU_C::BxError }
- };
-
-static BxOpcodeInfo_t BxOpcodeInfoG5w[8] = {
- // attributes defined in main area
- /* 0 */ { 0, &BX_CPU_C::INC_Ew },
- /* 1 */ { 0, &BX_CPU_C::DEC_Ew },
- /* 2 */ { 0, &BX_CPU_C::CALL_Ew },
- /* 3 */ { 0, &BX_CPU_C::CALL16_Ep },
- /* 4 */ { 0, &BX_CPU_C::JMP_Ew },
- /* 5 */ { 0, &BX_CPU_C::JMP16_Ep },
- /* 6 */ { 0, &BX_CPU_C::PUSH_Ew },
- /* 7 */ { 0, &BX_CPU_C::BxError }
- };
-
-static BxOpcodeInfo_t BxOpcodeInfoG5d[8] = {
- // attributes defined in main area
- /* 0 */ { 0, &BX_CPU_C::INC_Ed },
- /* 1 */ { 0, &BX_CPU_C::DEC_Ed },
- /* 2 */ { 0, &BX_CPU_C::CALL_Ed },
- /* 3 */ { 0, &BX_CPU_C::CALL32_Ep },
- /* 4 */ { 0, &BX_CPU_C::JMP_Ed },
- /* 5 */ { 0, &BX_CPU_C::JMP32_Ep },
- /* 6 */ { 0, &BX_CPU_C::PUSH_Ed },
- /* 7 */ { 0, &BX_CPU_C::BxError }
- };
-
-static BxOpcodeInfo_t BxOpcodeInfoG6[8] = {
- // attributes defined in main area
- /* 0 */ { 0, &BX_CPU_C::SLDT_Ew },
- /* 1 */ { 0, &BX_CPU_C::STR_Ew },
- /* 2 */ { 0, &BX_CPU_C::LLDT_Ew },
- /* 3 */ { 0, &BX_CPU_C::LTR_Ew },
- /* 4 */ { 0, &BX_CPU_C::VERR_Ew },
- /* 5 */ { 0, &BX_CPU_C::VERW_Ew },
- /* 6 */ { 0, &BX_CPU_C::BxError },
- /* 7 */ { 0, &BX_CPU_C::BxError }
- };
-
-static BxOpcodeInfo_t BxOpcodeInfoG7[8] = {
- /* 0 */ { 0, &BX_CPU_C::SGDT_Ms },
- /* 1 */ { 0, &BX_CPU_C::SIDT_Ms },
- /* 2 */ { 0, &BX_CPU_C::LGDT_Ms },
- /* 3 */ { 0, &BX_CPU_C::LIDT_Ms },
- /* 4 */ { 0, &BX_CPU_C::SMSW_Ew },
- /* 5 */ { 0, &BX_CPU_C::BxError },
- /* 6 */ { 0, &BX_CPU_C::LMSW_Ew },
- /* 7 */ { 0, &BX_CPU_C::INVLPG }
- };
-
-
-static BxOpcodeInfo_t BxOpcodeInfoG8EvIb[8] = {
- /* 0 */ { 0, &BX_CPU_C::BxError },
- /* 1 */ { 0, &BX_CPU_C::BxError },
- /* 2 */ { 0, &BX_CPU_C::BxError },
- /* 3 */ { 0, &BX_CPU_C::BxError },
- /* 4 */ { BxImmediate_Ib, &BX_CPU_C::BT_EvIb },
- /* 5 */ { BxImmediate_Ib, &BX_CPU_C::BTS_EvIb },
- /* 6 */ { BxImmediate_Ib, &BX_CPU_C::BTR_EvIb },
- /* 7 */ { BxImmediate_Ib, &BX_CPU_C::BTC_EvIb }
- };
-
-static BxOpcodeInfo_t BxOpcodeInfoG9[8] = {
- /* 0 */ { 0, &BX_CPU_C::BxError },
- /* 1 */ { 0, &BX_CPU_C::CMPXCHG8B },
- /* 2 */ { 0, &BX_CPU_C::BxError },
- /* 3 */ { 0, &BX_CPU_C::BxError },
- /* 4 */ { 0, &BX_CPU_C::BxError },
- /* 5 */ { 0, &BX_CPU_C::BxError },
- /* 6 */ { 0, &BX_CPU_C::BxError },
- /* 7 */ { 0, &BX_CPU_C::BxError }
- };
-
-
-// 512 entries for 16bit mode
-// 512 entries for 32bit mode
-
-static BxOpcodeInfo_t BxOpcodeInfo[512*2] = {
- // 512 entries for 16bit mode
- /* 00 */ { BxAnother, &BX_CPU_C::ADD_EbGb },
- /* 01 */ { BxAnother, &BX_CPU_C::ADD_EwGw },
- /* 02 */ { BxAnother, &BX_CPU_C::ADD_GbEb },
- /* 03 */ { BxAnother, &BX_CPU_C::ADD_GwEw },
- /* 04 */ { BxImmediate_Ib, &BX_CPU_C::ADD_ALIb },
- /* 05 */ { BxImmediate_Iv, &BX_CPU_C::ADD_AXIw },
- /* 06 */ { 0, &BX_CPU_C::PUSH_ES },
- /* 07 */ { 0, &BX_CPU_C::POP_ES },
- /* 08 */ { BxAnother, &BX_CPU_C::OR_EbGb },
- /* 09 */ { BxAnother, &BX_CPU_C::OR_EwGw },
- /* 0A */ { BxAnother, &BX_CPU_C::OR_GbEb },
- /* 0B */ { BxAnother, &BX_CPU_C::OR_GwEw },
- /* 0C */ { BxImmediate_Ib, &BX_CPU_C::OR_ALIb },
- /* 0D */ { BxImmediate_Iv, &BX_CPU_C::OR_AXIw },
- /* 0E */ { 0, &BX_CPU_C::PUSH_CS },
- /* 0F */ { BxAnother, &BX_CPU_C::BxError }, // 2-byte escape
- /* 10 */ { BxAnother, &BX_CPU_C::ADC_EbGb },
- /* 11 */ { BxAnother, &BX_CPU_C::ADC_EwGw },
- /* 12 */ { BxAnother, &BX_CPU_C::ADC_GbEb },
- /* 13 */ { BxAnother, &BX_CPU_C::ADC_GwEw },
- /* 14 */ { BxImmediate_Ib, &BX_CPU_C::ADC_ALIb },
- /* 15 */ { BxImmediate_Iv, &BX_CPU_C::ADC_AXIw },
- /* 16 */ { 0, &BX_CPU_C::PUSH_SS },
- /* 17 */ { 0, &BX_CPU_C::POP_SS },
- /* 18 */ { BxAnother, &BX_CPU_C::SBB_EbGb },
- /* 19 */ { BxAnother, &BX_CPU_C::SBB_EwGw },
- /* 1A */ { BxAnother, &BX_CPU_C::SBB_GbEb },
- /* 1B */ { BxAnother, &BX_CPU_C::SBB_GwEw },
- /* 1C */ { BxImmediate_Ib, &BX_CPU_C::SBB_ALIb },
- /* 1D */ { BxImmediate_Iv, &BX_CPU_C::SBB_AXIw },
- /* 1E */ { 0, &BX_CPU_C::PUSH_DS },
- /* 1F */ { 0, &BX_CPU_C::POP_DS },
- /* 20 */ { BxAnother, &BX_CPU_C::AND_EbGb },
- /* 21 */ { BxAnother, &BX_CPU_C::AND_EwGw },
- /* 22 */ { BxAnother, &BX_CPU_C::AND_GbEb },
- /* 23 */ { BxAnother, &BX_CPU_C::AND_GwEw },
- /* 24 */ { BxImmediate_Ib, &BX_CPU_C::AND_ALIb },
- /* 25 */ { BxImmediate_Iv, &BX_CPU_C::AND_AXIw },
- /* 26 */ { BxPrefix | BxAnother, &BX_CPU_C::BxError }, // ES:
- /* 27 */ { 0, &BX_CPU_C::DAA },
- /* 28 */ { BxAnother, &BX_CPU_C::SUB_EbGb },
- /* 29 */ { BxAnother, &BX_CPU_C::SUB_EwGw },
- /* 2A */ { BxAnother, &BX_CPU_C::SUB_GbEb },
- /* 2B */ { BxAnother, &BX_CPU_C::SUB_GwEw },
- /* 2C */ { BxImmediate_Ib, &BX_CPU_C::SUB_ALIb },
- /* 2D */ { BxImmediate_Iv, &BX_CPU_C::SUB_AXIw },
- /* 2E */ { BxPrefix | BxAnother, &BX_CPU_C::BxError }, // CS:
- /* 2F */ { 0, &BX_CPU_C::DAS },
- /* 30 */ { BxAnother, &BX_CPU_C::XOR_EbGb },
- /* 31 */ { BxAnother, &BX_CPU_C::XOR_EwGw },
- /* 32 */ { BxAnother, &BX_CPU_C::XOR_GbEb },
- /* 33 */ { BxAnother, &BX_CPU_C::XOR_GwEw },
- /* 34 */ { BxImmediate_Ib, &BX_CPU_C::XOR_ALIb },
- /* 35 */ { BxImmediate_Iv, &BX_CPU_C::XOR_AXIw },
- /* 36 */ { BxPrefix | BxAnother, &BX_CPU_C::BxError }, // SS:
- /* 37 */ { 0, &BX_CPU_C::AAA },
- /* 38 */ { BxAnother, &BX_CPU_C::CMP_EbGb },
- /* 39 */ { BxAnother, &BX_CPU_C::CMP_EwGw },
- /* 3A */ { BxAnother, &BX_CPU_C::CMP_GbEb },
- /* 3B */ { BxAnother, &BX_CPU_C::CMP_GwEw },
- /* 3C */ { BxImmediate_Ib, &BX_CPU_C::CMP_ALIb },
- /* 3D */ { BxImmediate_Iv, &BX_CPU_C::CMP_AXIw },
- /* 3E */ { BxPrefix | BxAnother, &BX_CPU_C::BxError }, // DS:
- /* 3F */ { 0, &BX_CPU_C::AAS },
- /* 40 */ { 0, &BX_CPU_C::INC_RX },
- /* 41 */ { 0, &BX_CPU_C::INC_RX },
- /* 42 */ { 0, &BX_CPU_C::INC_RX },
- /* 43 */ { 0, &BX_CPU_C::INC_RX },
- /* 44 */ { 0, &BX_CPU_C::INC_RX },
- /* 45 */ { 0, &BX_CPU_C::INC_RX },
- /* 46 */ { 0, &BX_CPU_C::INC_RX },
- /* 47 */ { 0, &BX_CPU_C::INC_RX },
- /* 48 */ { 0, &BX_CPU_C::DEC_RX },
- /* 49 */ { 0, &BX_CPU_C::DEC_RX },
- /* 4A */ { 0, &BX_CPU_C::DEC_RX },
- /* 4B */ { 0, &BX_CPU_C::DEC_RX },
- /* 4C */ { 0, &BX_CPU_C::DEC_RX },
- /* 4D */ { 0, &BX_CPU_C::DEC_RX },
- /* 4E */ { 0, &BX_CPU_C::DEC_RX },
- /* 4F */ { 0, &BX_CPU_C::DEC_RX },
- /* 50 */ { 0, &BX_CPU_C::PUSH_RX },
- /* 51 */ { 0, &BX_CPU_C::PUSH_RX },
- /* 52 */ { 0, &BX_CPU_C::PUSH_RX },
- /* 53 */ { 0, &BX_CPU_C::PUSH_RX },
- /* 54 */ { 0, &BX_CPU_C::PUSH_RX },
- /* 55 */ { 0, &BX_CPU_C::PUSH_RX },
- /* 56 */ { 0, &BX_CPU_C::PUSH_RX },
- /* 57 */ { 0, &BX_CPU_C::PUSH_RX },
- /* 58 */ { 0, &BX_CPU_C::POP_RX },
- /* 59 */ { 0, &BX_CPU_C::POP_RX },
- /* 5A */ { 0, &BX_CPU_C::POP_RX },
- /* 5B */ { 0, &BX_CPU_C::POP_RX },
- /* 5C */ { 0, &BX_CPU_C::POP_RX },
- /* 5D */ { 0, &BX_CPU_C::POP_RX },
- /* 5E */ { 0, &BX_CPU_C::POP_RX },
- /* 5F */ { 0, &BX_CPU_C::POP_RX },
- /* 60 */ { 0, &BX_CPU_C::PUSHAD16 },
- /* 61 */ { 0, &BX_CPU_C::POPAD16 },
- /* 62 */ { BxAnother, &BX_CPU_C::BOUND_GvMa },
- /* 63 */ { BxAnother, &BX_CPU_C::ARPL_EwGw },
- /* 64 */ { BxPrefix | BxAnother, &BX_CPU_C::BxError }, // FS:
- /* 65 */ { BxPrefix | BxAnother, &BX_CPU_C::BxError }, // GS:
- /* 66 */ { BxPrefix | BxAnother, &BX_CPU_C::BxError }, // OS:
- /* 67 */ { BxPrefix | BxAnother, &BX_CPU_C::BxError }, // AS:
- /* 68 */ { BxImmediate_Iv, &BX_CPU_C::PUSH_Iw },
- /* 69 */ { BxAnother | BxImmediate_Iv, &BX_CPU_C::IMUL_GwEwIw },
- /* 6A */ { BxImmediate_Ib_SE, &BX_CPU_C::PUSH_Iw },
- /* 6B */ { BxAnother | BxImmediate_Ib_SE, &BX_CPU_C::IMUL_GwEwIw },
- /* 6C */ { BxRepeatable, &BX_CPU_C::INSB_YbDX },
- /* 6D */ { BxRepeatable, &BX_CPU_C::INSW_YvDX },
- /* 6E */ { BxRepeatable, &BX_CPU_C::OUTSB_DXXb },
- /* 6F */ { BxRepeatable, &BX_CPU_C::OUTSW_DXXv },
- /* 70 */ { BxImmediate_BrOff8, &BX_CPU_C::JCC_Jw },
- /* 71 */ { BxImmediate_BrOff8, &BX_CPU_C::JCC_Jw },
- /* 72 */ { BxImmediate_BrOff8, &BX_CPU_C::JCC_Jw },
- /* 73 */ { BxImmediate_BrOff8, &BX_CPU_C::JCC_Jw },
- /* 74 */ { BxImmediate_BrOff8, &BX_CPU_C::JCC_Jw },
- /* 75 */ { BxImmediate_BrOff8, &BX_CPU_C::JCC_Jw },
- /* 76 */ { BxImmediate_BrOff8, &BX_CPU_C::JCC_Jw },
- /* 77 */ { BxImmediate_BrOff8, &BX_CPU_C::JCC_Jw },
- /* 78 */ { BxImmediate_BrOff8, &BX_CPU_C::JCC_Jw },
- /* 79 */ { BxImmediate_BrOff8, &BX_CPU_C::JCC_Jw },
- /* 7A */ { BxImmediate_BrOff8, &BX_CPU_C::JCC_Jw },
- /* 7B */ { BxImmediate_BrOff8, &BX_CPU_C::JCC_Jw },
- /* 7C */ { BxImmediate_BrOff8, &BX_CPU_C::JCC_Jw },
- /* 7D */ { BxImmediate_BrOff8, &BX_CPU_C::JCC_Jw },
- /* 7E */ { BxImmediate_BrOff8, &BX_CPU_C::JCC_Jw },
- /* 7F */ { BxImmediate_BrOff8, &BX_CPU_C::JCC_Jw },
- /* 80 */ { BxAnother | BxGroup1, NULL, BxOpcodeInfoG1EbIb },
- /* 81 */ { BxAnother | BxGroup1 | BxImmediate_Iv, NULL, BxOpcodeInfoG1Ew },
- /* 82 */ { BxAnother | BxGroup1, NULL, BxOpcodeInfoG1EbIb },
- /* 83 */ { BxAnother | BxGroup1 | BxImmediate_Ib_SE, NULL, BxOpcodeInfoG1Ew },
- /* 84 */ { BxAnother, &BX_CPU_C::TEST_EbGb },
- /* 85 */ { BxAnother, &BX_CPU_C::TEST_EwGw },
- /* 86 */ { BxAnother, &BX_CPU_C::XCHG_EbGb },
- /* 87 */ { BxAnother, &BX_CPU_C::XCHG_EwGw },
- /* 88 */ { BxAnother, &BX_CPU_C::MOV_EbGb },
- /* 89 */ { BxAnother, &BX_CPU_C::MOV_EwGw },
- /* 8A */ { BxAnother, &BX_CPU_C::MOV_GbEb },
- /* 8B */ { BxAnother, &BX_CPU_C::MOV_GwEw },
- /* 8C */ { BxAnother, &BX_CPU_C::MOV_EwSw },
- /* 8D */ { BxAnother, &BX_CPU_C::LEA_GwM },
- /* 8E */ { BxAnother, &BX_CPU_C::MOV_SwEw },
- /* 8F */ { BxAnother, &BX_CPU_C::POP_Ew },
- /* 90 */ { 0, &BX_CPU_C::NOP },
- /* 91 */ { 0, &BX_CPU_C::XCHG_RXAX },
- /* 92 */ { 0, &BX_CPU_C::XCHG_RXAX },
- /* 93 */ { 0, &BX_CPU_C::XCHG_RXAX },
- /* 94 */ { 0, &BX_CPU_C::XCHG_RXAX },
- /* 95 */ { 0, &BX_CPU_C::XCHG_RXAX },
- /* 96 */ { 0, &BX_CPU_C::XCHG_RXAX },
- /* 97 */ { 0, &BX_CPU_C::XCHG_RXAX },
- /* 98 */ { 0, &BX_CPU_C::CBW },
- /* 99 */ { 0, &BX_CPU_C::CWD },
- /* 9A */ { BxImmediate_IvIw, &BX_CPU_C::CALL16_Ap },
- /* 9B */ { 0, &BX_CPU_C::FWAIT },
- /* 9C */ { 0, &BX_CPU_C::PUSHF_Fv },
- /* 9D */ { 0, &BX_CPU_C::POPF_Fv },
- /* 9E */ { 0, &BX_CPU_C::SAHF },
- /* 9F */ { 0, &BX_CPU_C::LAHF },
- /* A0 */ { BxImmediate_O, &BX_CPU_C::MOV_ALOb },
- /* A1 */ { BxImmediate_O, &BX_CPU_C::MOV_AXOw },
- /* A2 */ { BxImmediate_O, &BX_CPU_C::MOV_ObAL },
- /* A3 */ { BxImmediate_O, &BX_CPU_C::MOV_OwAX },
- /* A4 */ { BxRepeatable, &BX_CPU_C::MOVSB_XbYb },
- /* A5 */ { BxRepeatable, &BX_CPU_C::MOVSW_XvYv },
- /* A6 */ { BxRepeatable | BxRepeatableZF, &BX_CPU_C::CMPSB_XbYb },
- /* A7 */ { BxRepeatable | BxRepeatableZF, &BX_CPU_C::CMPSW_XvYv },
- /* A8 */ { BxImmediate_Ib, &BX_CPU_C::TEST_ALIb },
- /* A9 */ { BxImmediate_Iv, &BX_CPU_C::TEST_AXIw },
- /* AA */ { BxRepeatable, &BX_CPU_C::STOSB_YbAL },
- /* AB */ { BxRepeatable, &BX_CPU_C::STOSW_YveAX },
- /* AC */ { BxRepeatable, &BX_CPU_C::LODSB_ALXb },
- /* AD */ { BxRepeatable, &BX_CPU_C::LODSW_eAXXv },
- /* AE */ { BxRepeatable | BxRepeatableZF, &BX_CPU_C::SCASB_ALXb },
- /* AF */ { BxRepeatable | BxRepeatableZF, &BX_CPU_C::SCASW_eAXXv },
- /* B0 */ { BxImmediate_Ib, &BX_CPU_C::MOV_RLIb },
- /* B1 */ { BxImmediate_Ib, &BX_CPU_C::MOV_RLIb },
- /* B2 */ { BxImmediate_Ib, &BX_CPU_C::MOV_RLIb },
- /* B3 */ { BxImmediate_Ib, &BX_CPU_C::MOV_RLIb },
- /* B4 */ { BxImmediate_Ib, &BX_CPU_C::MOV_RHIb },
- /* B5 */ { BxImmediate_Ib, &BX_CPU_C::MOV_RHIb },
- /* B6 */ { BxImmediate_Ib, &BX_CPU_C::MOV_RHIb },
- /* B7 */ { BxImmediate_Ib, &BX_CPU_C::MOV_RHIb },
- /* B8 */ { BxImmediate_Iv, &BX_CPU_C::MOV_RXIw },
- /* B9 */ { BxImmediate_Iv, &BX_CPU_C::MOV_RXIw },
- /* BA */ { BxImmediate_Iv, &BX_CPU_C::MOV_RXIw },
- /* BB */ { BxImmediate_Iv, &BX_CPU_C::MOV_RXIw },
- /* BC */ { BxImmediate_Iv, &BX_CPU_C::MOV_RXIw },
- /* BD */ { BxImmediate_Iv, &BX_CPU_C::MOV_RXIw },
- /* BE */ { BxImmediate_Iv, &BX_CPU_C::MOV_RXIw },
- /* BF */ { BxImmediate_Iv, &BX_CPU_C::MOV_RXIw },
- /* C0 */ { BxAnother | BxGroup2 | BxImmediate_Ib, NULL, BxOpcodeInfoG2Eb },
- /* C1 */ { BxAnother | BxGroup2 | BxImmediate_Ib, NULL, BxOpcodeInfoG2Ew },
- /* C2 */ { BxImmediate_Iw, &BX_CPU_C::RETnear16_Iw },
- /* C3 */ { 0, &BX_CPU_C::RETnear16 },
- /* C4 */ { BxAnother, &BX_CPU_C::LES_GvMp },
- /* C5 */ { BxAnother, &BX_CPU_C::LDS_GvMp },
- /* C6 */ { BxAnother | BxImmediate_Ib, &BX_CPU_C::MOV_EbIb },
- /* C7 */ { BxAnother | BxImmediate_Iv, &BX_CPU_C::MOV_EwIw },
- /* C8 */ { BxImmediate_IwIb, &BX_CPU_C::ENTER_IwIb },
- /* C9 */ { 0, &BX_CPU_C::LEAVE },
- /* CA */ { BxImmediate_Iw, &BX_CPU_C::RETfar16_Iw },
- /* CB */ { 0, &BX_CPU_C::RETfar16 },
- /* CC */ { 0, &sid_cpu_c::INT3 },
- /* CD */ { BxImmediate_Ib, &sid_cpu_c::INT_Ib },
- /* CE */ { 0, &BX_CPU_C::INTO },
- /* CF */ { 0, &BX_CPU_C::IRET16 },
- /* D0 */ { BxAnother | BxGroup2, NULL, BxOpcodeInfoG2Eb },
- /* D1 */ { BxAnother | BxGroup2, NULL, BxOpcodeInfoG2Ew },
- /* D2 */ { BxAnother | BxGroup2, NULL, BxOpcodeInfoG2Eb },
- /* D3 */ { BxAnother | BxGroup2, NULL, BxOpcodeInfoG2Ew },
- /* D4 */ { BxImmediate_Ib, &BX_CPU_C::AAM },
- /* D5 */ { BxImmediate_Ib, &BX_CPU_C::AAD },
- /* D6 */ { 0, &BX_CPU_C::SALC },
- /* D7 */ { 0, &BX_CPU_C::XLAT },
- /* D8 */ { BxAnother, &BX_CPU_C::ESC0 },
- /* D9 */ { BxAnother, &BX_CPU_C::ESC1 },
- /* DA */ { BxAnother, &BX_CPU_C::ESC2 },
- /* DB */ { BxAnother, &BX_CPU_C::ESC3 },
- /* DC */ { BxAnother, &BX_CPU_C::ESC4 },
- /* DD */ { BxAnother, &BX_CPU_C::ESC5 },
- /* DE */ { BxAnother, &BX_CPU_C::ESC6 },
- /* DF */ { BxAnother, &BX_CPU_C::ESC7 },
- /* E0 */ { BxImmediate_BrOff8, &BX_CPU_C::LOOPNE_Jb },
- /* E1 */ { BxImmediate_BrOff8, &BX_CPU_C::LOOPE_Jb },
- /* E2 */ { BxImmediate_BrOff8, &BX_CPU_C::LOOP_Jb },
- /* E3 */ { BxImmediate_BrOff8, &BX_CPU_C::JCXZ_Jb },
- /* E4 */ { BxImmediate_Ib, &BX_CPU_C::IN_ALIb },
- /* E5 */ { BxImmediate_Ib, &BX_CPU_C::IN_eAXIb },
- /* E6 */ { BxImmediate_Ib, &BX_CPU_C::OUT_IbAL },
- /* E7 */ { BxImmediate_Ib, &BX_CPU_C::OUT_IbeAX },
- /* E8 */ { BxImmediate_BrOff16, &BX_CPU_C::CALL_Aw },
- /* E9 */ { BxImmediate_BrOff16, &BX_CPU_C::JMP_Jw },
- /* EA */ { BxImmediate_IvIw, &BX_CPU_C::JMP_Ap },
- /* EB */ { BxImmediate_BrOff8, &BX_CPU_C::JMP_Jw },
- /* EC */ { 0, &BX_CPU_C::IN_ALDX },
- /* ED */ { 0, &BX_CPU_C::IN_eAXDX },
- /* EE */ { 0, &BX_CPU_C::OUT_DXAL },
- /* EF */ { 0, &BX_CPU_C::OUT_DXeAX },
- /* F0 */ { BxPrefix | BxAnother, &BX_CPU_C::BxError }, // LOCK
- /* F1 */ { 0, &BX_CPU_C::INT1 },
- /* F2 */ { BxPrefix | BxAnother, &BX_CPU_C::BxError }, // REPNE/REPNZ
- /* F3 */ { BxPrefix | BxAnother, &BX_CPU_C::BxError }, // REP, REPE/REPZ
- /* F4 */ { 0, &BX_CPU_C::HLT },
- /* F5 */ { 0, &BX_CPU_C::CMC },
- /* F6 */ { BxAnother | BxGroup3, NULL, BxOpcodeInfoG3Eb },
- /* F7 */ { BxAnother | BxGroup3, NULL, BxOpcodeInfoG3Ew },
- /* F8 */ { 0, &BX_CPU_C::CLC },
- /* F9 */ { 0, &BX_CPU_C::STC },
- /* FA */ { 0, &BX_CPU_C::CLI },
- /* FB */ { 0, &BX_CPU_C::STI },
- /* FC */ { 0, &BX_CPU_C::CLD },
- /* FD */ { 0, &BX_CPU_C::STD },
- /* FE */ { BxAnother | BxGroup4, NULL, BxOpcodeInfoG4 },
- /* FF */ { BxAnother | BxGroup5, NULL, BxOpcodeInfoG5w },
-
- /* 0F 00 */ { BxAnother | BxGroup6, NULL, BxOpcodeInfoG6 },
- /* 0F 01 */ { BxAnother | BxGroup7, NULL, BxOpcodeInfoG7 },
- /* 0F 02 */ { BxAnother, &BX_CPU_C::LAR_GvEw },
- /* 0F 03 */ { BxAnother, &BX_CPU_C::LSL_GvEw },
- /* 0F 04 */ { 0, &BX_CPU_C::BxError },
- /* 0F 05 */ { 0, &BX_CPU_C::LOADALL },
- /* 0F 06 */ { 0, &BX_CPU_C::CLTS },
- /* 0F 07 */ { 0, &BX_CPU_C::BxError },
- /* 0F 08 */ { 0, &BX_CPU_C::INVD },
- /* 0F 09 */ { 0, &BX_CPU_C::WBINVD },
- /* 0F 0A */ { 0, &BX_CPU_C::BxError },
- /* 0F 0B */ { 0, &BX_CPU_C::BxError },
- /* 0F 0C */ { 0, &BX_CPU_C::BxError },
- /* 0F 0D */ { 0, &BX_CPU_C::BxError },
- /* 0F 0E */ { 0, &BX_CPU_C::BxError },
- /* 0F 0F */ { 0, &BX_CPU_C::BxError },
- /* 0F 10 */ { 0, &BX_CPU_C::BxError },
- /* 0F 11 */ { 0, &BX_CPU_C::BxError },
- /* 0F 12 */ { 0, &BX_CPU_C::BxError },
- /* 0F 13 */ { 0, &BX_CPU_C::BxError },
- /* 0F 14 */ { 0, &BX_CPU_C::BxError },
- /* 0F 15 */ { 0, &BX_CPU_C::BxError },
- /* 0F 16 */ { 0, &BX_CPU_C::BxError },
- /* 0F 17 */ { 0, &BX_CPU_C::BxError },
- /* 0F 18 */ { 0, &BX_CPU_C::BxError },
- /* 0F 19 */ { 0, &BX_CPU_C::BxError },
- /* 0F 1A */ { 0, &BX_CPU_C::BxError },
- /* 0F 1B */ { 0, &BX_CPU_C::BxError },
- /* 0F 1C */ { 0, &BX_CPU_C::BxError },
- /* 0F 1D */ { 0, &BX_CPU_C::BxError },
- /* 0F 1E */ { 0, &BX_CPU_C::BxError },
- /* 0F 1F */ { 0, &BX_CPU_C::BxError },
- /* 0F 20 */ { BxAnother, &BX_CPU_C::MOV_RdCd },
- /* 0F 21 */ { BxAnother, &BX_CPU_C::MOV_RdDd },
- /* 0F 22 */ { BxAnother, &BX_CPU_C::MOV_CdRd },
- /* 0F 23 */ { BxAnother, &BX_CPU_C::MOV_DdRd },
- /* 0F 24 */ { BxAnother, &BX_CPU_C::MOV_RdTd },
- /* 0F 25 */ { 0, &BX_CPU_C::BxError },
- /* 0F 26 */ { BxAnother, &BX_CPU_C::MOV_TdRd },
- /* 0F 27 */ { 0, &BX_CPU_C::BxError },
- /* 0F 28 */ { 0, &BX_CPU_C::BxError },
- /* 0F 29 */ { 0, &BX_CPU_C::BxError },
- /* 0F 2A */ { 0, &BX_CPU_C::BxError },
- /* 0F 2B */ { 0, &BX_CPU_C::BxError },
- /* 0F 2C */ { 0, &BX_CPU_C::BxError },
- /* 0F 2D */ { 0, &BX_CPU_C::BxError },
- /* 0F 2E */ { 0, &BX_CPU_C::BxError },
- /* 0F 2F */ { 0, &BX_CPU_C::BxError },
- /* 0F 30 */ { 0, &BX_CPU_C::WRMSR },
- /* 0F 31 */ { 0, &BX_CPU_C::RDTSC },
- /* 0F 32 */ { 0, &BX_CPU_C::RDMSR },
- /* 0F 33 */ { 0, &BX_CPU_C::BxError },
- /* 0F 34 */ { 0, &BX_CPU_C::BxError },
- /* 0F 35 */ { 0, &BX_CPU_C::BxError },
- /* 0F 36 */ { 0, &BX_CPU_C::BxError },
- /* 0F 37 */ { 0, &BX_CPU_C::BxError },
- /* 0F 38 */ { 0, &BX_CPU_C::BxError },
- /* 0F 39 */ { 0, &BX_CPU_C::BxError },
- /* 0F 3A */ { 0, &BX_CPU_C::BxError },
- /* 0F 3B */ { 0, &BX_CPU_C::BxError },
- /* 0F 3C */ { 0, &BX_CPU_C::BxError },
- /* 0F 3D */ { 0, &BX_CPU_C::BxError },
- /* 0F 3E */ { 0, &BX_CPU_C::BxError },
- /* 0F 3F */ { 0, &BX_CPU_C::BxError },
- /* 0F 40 */ { BxAnother, &BX_CPU_C::CMOV_GwEw },
- /* 0F 41 */ { BxAnother, &BX_CPU_C::CMOV_GwEw },
- /* 0F 42 */ { BxAnother, &BX_CPU_C::CMOV_GwEw },
- /* 0F 43 */ { BxAnother, &BX_CPU_C::CMOV_GwEw },
- /* 0F 44 */ { BxAnother, &BX_CPU_C::CMOV_GwEw },
- /* 0F 45 */ { BxAnother, &BX_CPU_C::CMOV_GwEw },
- /* 0F 46 */ { BxAnother, &BX_CPU_C::CMOV_GwEw },
- /* 0F 47 */ { BxAnother, &BX_CPU_C::CMOV_GwEw },
- /* 0F 48 */ { BxAnother, &BX_CPU_C::CMOV_GwEw },
- /* 0F 49 */ { BxAnother, &BX_CPU_C::CMOV_GwEw },
- /* 0F 4A */ { BxAnother, &BX_CPU_C::CMOV_GwEw },
- /* 0F 4B */ { BxAnother, &BX_CPU_C::CMOV_GwEw },
- /* 0F 4C */ { BxAnother, &BX_CPU_C::CMOV_GwEw },
- /* 0F 4D */ { BxAnother, &BX_CPU_C::CMOV_GwEw },
- /* 0F 4E */ { BxAnother, &BX_CPU_C::CMOV_GwEw },
- /* 0F 4F */ { BxAnother, &BX_CPU_C::CMOV_GwEw },
- /* 0F 50 */ { 0, &BX_CPU_C::BxError },
- /* 0F 51 */ { 0, &BX_CPU_C::BxError },
- /* 0F 52 */ { 0, &BX_CPU_C::BxError },
- /* 0F 53 */ { 0, &BX_CPU_C::BxError },
- /* 0F 54 */ { 0, &BX_CPU_C::BxError },
- /* 0F 55 */ { 0, &BX_CPU_C::BxError },
- /* 0F 56 */ { 0, &BX_CPU_C::BxError },
- /* 0F 57 */ { 0, &BX_CPU_C::BxError },
- /* 0F 58 */ { 0, &BX_CPU_C::BxError },
- /* 0F 59 */ { 0, &BX_CPU_C::BxError },
- /* 0F 5A */ { 0, &BX_CPU_C::BxError },
- /* 0F 5B */ { 0, &BX_CPU_C::BxError },
- /* 0F 5C */ { 0, &BX_CPU_C::BxError },
- /* 0F 5D */ { 0, &BX_CPU_C::BxError },
- /* 0F 5E */ { 0, &BX_CPU_C::BxError },
- /* 0F 5F */ { 0, &BX_CPU_C::BxError },
- /* 0F 60 */ { 0, &BX_CPU_C::BxError },
- /* 0F 61 */ { 0, &BX_CPU_C::BxError },
- /* 0F 62 */ { 0, &BX_CPU_C::BxError },
- /* 0F 63 */ { 0, &BX_CPU_C::BxError },
- /* 0F 64 */ { 0, &BX_CPU_C::BxError },
- /* 0F 65 */ { 0, &BX_CPU_C::BxError },
- /* 0F 66 */ { 0, &BX_CPU_C::BxError },
- /* 0F 67 */ { 0, &BX_CPU_C::BxError },
- /* 0F 68 */ { 0, &BX_CPU_C::BxError },
- /* 0F 69 */ { 0, &BX_CPU_C::BxError },
- /* 0F 6A */ { 0, &BX_CPU_C::BxError },
- /* 0F 6B */ { 0, &BX_CPU_C::BxError },
- /* 0F 6C */ { 0, &BX_CPU_C::BxError },
- /* 0F 6D */ { 0, &BX_CPU_C::BxError },
- /* 0F 6E */ { 0, &BX_CPU_C::BxError },
- /* 0F 6F */ { 0, &BX_CPU_C::BxError },
- /* 0F 70 */ { 0, &BX_CPU_C::BxError },
- /* 0F 71 */ { 0, &BX_CPU_C::BxError },
- /* 0F 72 */ { 0, &BX_CPU_C::BxError },
- /* 0F 73 */ { 0, &BX_CPU_C::BxError },
- /* 0F 74 */ { 0, &BX_CPU_C::BxError },
- /* 0F 75 */ { 0, &BX_CPU_C::BxError },
- /* 0F 76 */ { 0, &BX_CPU_C::BxError },
- /* 0F 77 */ { 0, &BX_CPU_C::BxError },
- /* 0F 78 */ { 0, &BX_CPU_C::BxError },
- /* 0F 79 */ { 0, &BX_CPU_C::BxError },
- /* 0F 7A */ { 0, &BX_CPU_C::BxError },
- /* 0F 7B */ { 0, &BX_CPU_C::BxError },
- /* 0F 7C */ { 0, &BX_CPU_C::BxError },
- /* 0F 7D */ { 0, &BX_CPU_C::BxError },
- /* 0F 7E */ { 0, &BX_CPU_C::BxError },
- /* 0F 7F */ { 0, &BX_CPU_C::BxError },
- /* 0F 80 */ { BxImmediate_BrOff16, &BX_CPU_C::JCC_Jw },
- /* 0F 81 */ { BxImmediate_BrOff16, &BX_CPU_C::JCC_Jw },
- /* 0F 82 */ { BxImmediate_BrOff16, &BX_CPU_C::JCC_Jw },
- /* 0F 83 */ { BxImmediate_BrOff16, &BX_CPU_C::JCC_Jw },
- /* 0F 84 */ { BxImmediate_BrOff16, &BX_CPU_C::JCC_Jw },
- /* 0F 85 */ { BxImmediate_BrOff16, &BX_CPU_C::JCC_Jw },
- /* 0F 86 */ { BxImmediate_BrOff16, &BX_CPU_C::JCC_Jw },
- /* 0F 87 */ { BxImmediate_BrOff16, &BX_CPU_C::JCC_Jw },
- /* 0F 88 */ { BxImmediate_BrOff16, &BX_CPU_C::JCC_Jw },
- /* 0F 89 */ { BxImmediate_BrOff16, &BX_CPU_C::JCC_Jw },
- /* 0F 8A */ { BxImmediate_BrOff16, &BX_CPU_C::JCC_Jw },
- /* 0F 8B */ { BxImmediate_BrOff16, &BX_CPU_C::JCC_Jw },
- /* 0F 8C */ { BxImmediate_BrOff16, &BX_CPU_C::JCC_Jw },
- /* 0F 8D */ { BxImmediate_BrOff16, &BX_CPU_C::JCC_Jw },
- /* 0F 8E */ { BxImmediate_BrOff16, &BX_CPU_C::JCC_Jw },
- /* 0F 8F */ { BxImmediate_BrOff16, &BX_CPU_C::JCC_Jw },
- /* 0F 90 */ { BxAnother, &BX_CPU_C::SETO_Eb },
- /* 0F 91 */ { BxAnother, &BX_CPU_C::SETNO_Eb },
- /* 0F 92 */ { BxAnother, &BX_CPU_C::SETB_Eb },
- /* 0F 93 */ { BxAnother, &BX_CPU_C::SETNB_Eb },
- /* 0F 94 */ { BxAnother, &BX_CPU_C::SETZ_Eb },
- /* 0F 95 */ { BxAnother, &BX_CPU_C::SETNZ_Eb },
- /* 0F 96 */ { BxAnother, &BX_CPU_C::SETBE_Eb },
- /* 0F 97 */ { BxAnother, &BX_CPU_C::SETNBE_Eb },
- /* 0F 98 */ { BxAnother, &BX_CPU_C::SETS_Eb },
- /* 0F 99 */ { BxAnother, &BX_CPU_C::SETNS_Eb },
- /* 0F 9A */ { BxAnother, &BX_CPU_C::SETP_Eb },
- /* 0F 9B */ { BxAnother, &BX_CPU_C::SETNP_Eb },
- /* 0F 9C */ { BxAnother, &BX_CPU_C::SETL_Eb },
- /* 0F 9D */ { BxAnother, &BX_CPU_C::SETNL_Eb },
- /* 0F 9E */ { BxAnother, &BX_CPU_C::SETLE_Eb },
- /* 0F 9F */ { BxAnother, &BX_CPU_C::SETNLE_Eb },
- /* 0F A0 */ { 0, &BX_CPU_C::PUSH_FS },
- /* 0F A1 */ { 0, &BX_CPU_C::POP_FS },
- /* 0F A2 */ { 0, &BX_CPU_C::CPUID },
- /* 0F A3 */ { BxAnother, &BX_CPU_C::BT_EvGv },
- /* 0F A4 */ { BxAnother | BxImmediate_Ib, &BX_CPU_C::SHLD_EwGw },
- /* 0F A5 */ { BxAnother, &BX_CPU_C::SHLD_EwGw },
- /* 0F A6 */ { 0, &BX_CPU_C::CMPXCHG_XBTS },
- /* 0F A7 */ { 0, &BX_CPU_C::CMPXCHG_IBTS },
- /* 0F A8 */ { 0, &BX_CPU_C::PUSH_GS },
- /* 0F A9 */ { 0, &BX_CPU_C::POP_GS },
- /* 0F AA */ { 0, &BX_CPU_C::RSM },
- /* 0F AB */ { BxAnother, &BX_CPU_C::BTS_EvGv },
- /* 0F AC */ { BxAnother | BxImmediate_Ib, &BX_CPU_C::SHRD_EwGw },
- /* 0F AD */ { BxAnother, &BX_CPU_C::SHRD_EwGw },
- /* 0F AE */ { 0, &BX_CPU_C::BxError },
- /* 0F AF */ { BxAnother, &BX_CPU_C::IMUL_GwEw },
- /* 0F B0 */ { BxAnother, &BX_CPU_C::CMPXCHG_EbGb },
- /* 0F B1 */ { BxAnother, &BX_CPU_C::CMPXCHG_EwGw },
- /* 0F B2 */ { BxAnother, &BX_CPU_C::LSS_GvMp },
- /* 0F B3 */ { BxAnother, &BX_CPU_C::BTR_EvGv },
- /* 0F B4 */ { BxAnother, &BX_CPU_C::LFS_GvMp },
- /* 0F B5 */ { BxAnother, &BX_CPU_C::LGS_GvMp },
- /* 0F B6 */ { BxAnother, &BX_CPU_C::MOVZX_GwEb },
- /* 0F B7 */ { BxAnother, &BX_CPU_C::MOVZX_GwEw },
- /* 0F B8 */ { 0, &BX_CPU_C::BxError },
- /* 0F B9 */ { 0, &BX_CPU_C::BxError },
- /* 0F BA */ { BxAnother | BxGroup8, NULL, BxOpcodeInfoG8EvIb },
- /* 0F BB */ { BxAnother, &BX_CPU_C::BTC_EvGv },
- /* 0F BC */ { BxAnother, &BX_CPU_C::BSF_GvEv },
- /* 0F BD */ { BxAnother, &BX_CPU_C::BSR_GvEv },
- /* 0F BE */ { BxAnother, &BX_CPU_C::MOVSX_GwEb },
- /* 0F BF */ { BxAnother, &BX_CPU_C::MOVSX_GwEw },
- /* 0F C0 */ { BxAnother, &BX_CPU_C::XADD_EbGb },
- /* 0F C1 */ { BxAnother, &BX_CPU_C::XADD_EwGw },
- /* 0F C2 */ { 0, &BX_CPU_C::BxError },
- /* 0F C3 */ { 0, &BX_CPU_C::BxError },
- /* 0F C4 */ { 0, &BX_CPU_C::BxError },
- /* 0F C5 */ { 0, &BX_CPU_C::BxError },
- /* 0F C6 */ { 0, &BX_CPU_C::BxError },
- /* 0F C7 */ { BxAnother | BxGroup9, NULL, BxOpcodeInfoG9 },
- /* 0F C8 */ { 0, &BX_CPU_C::BSWAP_EAX },
- /* 0F C9 */ { 0, &BX_CPU_C::BSWAP_ECX },
- /* 0F CA */ { 0, &BX_CPU_C::BSWAP_EDX },
- /* 0F CB */ { 0, &BX_CPU_C::BSWAP_EBX },
- /* 0F CC */ { 0, &BX_CPU_C::BSWAP_ESP },
- /* 0F CD */ { 0, &BX_CPU_C::BSWAP_EBP },
- /* 0F CE */ { 0, &BX_CPU_C::BSWAP_ESI },
- /* 0F CF */ { 0, &BX_CPU_C::BSWAP_EDI },
- /* 0F D0 */ { 0, &BX_CPU_C::BxError },
- /* 0F D1 */ { 0, &BX_CPU_C::BxError },
- /* 0F D2 */ { 0, &BX_CPU_C::BxError },
- /* 0F D3 */ { 0, &BX_CPU_C::BxError },
- /* 0F D4 */ { 0, &BX_CPU_C::BxError },
- /* 0F D5 */ { 0, &BX_CPU_C::BxError },
- /* 0F D6 */ { 0, &BX_CPU_C::BxError },
- /* 0F D7 */ { 0, &BX_CPU_C::BxError },
- /* 0F D8 */ { 0, &BX_CPU_C::BxError },
- /* 0F D9 */ { 0, &BX_CPU_C::BxError },
- /* 0F DA */ { 0, &BX_CPU_C::BxError },
- /* 0F DB */ { 0, &BX_CPU_C::BxError },
- /* 0F DC */ { 0, &BX_CPU_C::BxError },
- /* 0F DD */ { 0, &BX_CPU_C::BxError },
- /* 0F DE */ { 0, &BX_CPU_C::BxError },
- /* 0F DF */ { 0, &BX_CPU_C::BxError },
- /* 0F E0 */ { 0, &BX_CPU_C::BxError },
- /* 0F E1 */ { 0, &BX_CPU_C::BxError },
- /* 0F E2 */ { 0, &BX_CPU_C::BxError },
- /* 0F E3 */ { 0, &BX_CPU_C::BxError },
- /* 0F E4 */ { 0, &BX_CPU_C::BxError },
- /* 0F E5 */ { 0, &BX_CPU_C::BxError },
- /* 0F E6 */ { 0, &BX_CPU_C::BxError },
- /* 0F E7 */ { 0, &BX_CPU_C::BxError },
- /* 0F E8 */ { 0, &BX_CPU_C::BxError },
- /* 0F E9 */ { 0, &BX_CPU_C::BxError },
- /* 0F EA */ { 0, &BX_CPU_C::BxError },
- /* 0F EB */ { 0, &BX_CPU_C::BxError },
- /* 0F EC */ { 0, &BX_CPU_C::BxError },
- /* 0F ED */ { 0, &BX_CPU_C::BxError },
- /* 0F EE */ { 0, &BX_CPU_C::BxError },
- /* 0F EF */ { 0, &BX_CPU_C::BxError },
- /* 0F F0 */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F F1 */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F F2 */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F F3 */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F F4 */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F F5 */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F F6 */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F F7 */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F F8 */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F F9 */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F FA */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F FB */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F FC */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F FD */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F FE */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F FF */ { 0, &BX_CPU_C::UndefinedOpcode },
-
- // 512 entries for 32bit mod
- /* 00 */ { BxAnother, &BX_CPU_C::ADD_EbGb },
- /* 01 */ { BxAnother, &BX_CPU_C::ADD_EdGd },
- /* 02 */ { BxAnother, &BX_CPU_C::ADD_GbEb },
- /* 03 */ { BxAnother, &BX_CPU_C::ADD_GdEd },
- /* 04 */ { BxImmediate_Ib, &BX_CPU_C::ADD_ALIb },
- /* 05 */ { BxImmediate_Iv, &BX_CPU_C::ADD_EAXId },
- /* 06 */ { 0, &BX_CPU_C::PUSH_ES },
- /* 07 */ { 0, &BX_CPU_C::POP_ES },
- /* 08 */ { BxAnother, &BX_CPU_C::OR_EbGb },
- /* 09 */ { BxAnother, &BX_CPU_C::OR_EdGd },
- /* 0A */ { BxAnother, &BX_CPU_C::OR_GbEb },
- /* 0B */ { BxAnother, &BX_CPU_C::OR_GdEd },
- /* 0C */ { BxImmediate_Ib, &BX_CPU_C::OR_ALIb },
- /* 0D */ { BxImmediate_Iv, &BX_CPU_C::OR_EAXId },
- /* 0E */ { 0, &BX_CPU_C::PUSH_CS },
- /* 0F */ { BxAnother, &BX_CPU_C::BxError }, // 2-byte escape
- /* 10 */ { BxAnother, &BX_CPU_C::ADC_EbGb },
- /* 11 */ { BxAnother, &BX_CPU_C::ADC_EdGd },
- /* 12 */ { BxAnother, &BX_CPU_C::ADC_GbEb },
- /* 13 */ { BxAnother, &BX_CPU_C::ADC_GdEd },
- /* 14 */ { BxImmediate_Ib, &BX_CPU_C::ADC_ALIb },
- /* 15 */ { BxImmediate_Iv, &BX_CPU_C::ADC_EAXId },
- /* 16 */ { 0, &BX_CPU_C::PUSH_SS },
- /* 17 */ { 0, &BX_CPU_C::POP_SS },
- /* 18 */ { BxAnother, &BX_CPU_C::SBB_EbGb },
- /* 19 */ { BxAnother, &BX_CPU_C::SBB_EdGd },
- /* 1A */ { BxAnother, &BX_CPU_C::SBB_GbEb },
- /* 1B */ { BxAnother, &BX_CPU_C::SBB_GdEd },
- /* 1C */ { BxImmediate_Ib, &BX_CPU_C::SBB_ALIb },
- /* 1D */ { BxImmediate_Iv, &BX_CPU_C::SBB_EAXId },
- /* 1E */ { 0, &BX_CPU_C::PUSH_DS },
- /* 1F */ { 0, &BX_CPU_C::POP_DS },
- /* 20 */ { BxAnother, &BX_CPU_C::AND_EbGb },
- /* 21 */ { BxAnother, &BX_CPU_C::AND_EdGd },
- /* 22 */ { BxAnother, &BX_CPU_C::AND_GbEb },
- /* 23 */ { BxAnother, &BX_CPU_C::AND_GdEd },
- /* 24 */ { BxImmediate_Ib, &BX_CPU_C::AND_ALIb },
- /* 25 */ { BxImmediate_Iv, &BX_CPU_C::AND_EAXId },
- /* 26 */ { BxPrefix | BxAnother, &BX_CPU_C::BxError }, // ES:
- /* 27 */ { 0, &BX_CPU_C::DAA },
- /* 28 */ { BxAnother, &BX_CPU_C::SUB_EbGb },
- /* 29 */ { BxAnother, &BX_CPU_C::SUB_EdGd },
- /* 2A */ { BxAnother, &BX_CPU_C::SUB_GbEb },
- /* 2B */ { BxAnother, &BX_CPU_C::SUB_GdEd },
- /* 2C */ { BxImmediate_Ib, &BX_CPU_C::SUB_ALIb },
- /* 2D */ { BxImmediate_Iv, &BX_CPU_C::SUB_EAXId },
- /* 2E */ { BxPrefix | BxAnother, &BX_CPU_C::BxError }, // CS:
- /* 2F */ { 0, &BX_CPU_C::DAS },
- /* 30 */ { BxAnother, &BX_CPU_C::XOR_EbGb },
- /* 31 */ { BxAnother, &BX_CPU_C::XOR_EdGd },
- /* 32 */ { BxAnother, &BX_CPU_C::XOR_GbEb },
- /* 33 */ { BxAnother, &BX_CPU_C::XOR_GdEd },
- /* 34 */ { BxImmediate_Ib, &BX_CPU_C::XOR_ALIb },
- /* 35 */ { BxImmediate_Iv, &BX_CPU_C::XOR_EAXId },
- /* 36 */ { BxPrefix | BxAnother, &BX_CPU_C::BxError }, // SS:
- /* 37 */ { 0, &BX_CPU_C::AAA },
- /* 38 */ { BxAnother, &BX_CPU_C::CMP_EbGb },
- /* 39 */ { BxAnother, &BX_CPU_C::CMP_EdGd },
- /* 3A */ { BxAnother, &BX_CPU_C::CMP_GbEb },
- /* 3B */ { BxAnother, &BX_CPU_C::CMP_GdEd },
- /* 3C */ { BxImmediate_Ib, &BX_CPU_C::CMP_ALIb },
- /* 3D */ { BxImmediate_Iv, &BX_CPU_C::CMP_EAXId },
- /* 3E */ { BxPrefix | BxAnother, &BX_CPU_C::BxError }, // DS:
- /* 3F */ { 0, &BX_CPU_C::AAS },
- /* 40 */ { 0, &BX_CPU_C::INC_ERX },
- /* 41 */ { 0, &BX_CPU_C::INC_ERX },
- /* 42 */ { 0, &BX_CPU_C::INC_ERX },
- /* 43 */ { 0, &BX_CPU_C::INC_ERX },
- /* 44 */ { 0, &BX_CPU_C::INC_ERX },
- /* 45 */ { 0, &BX_CPU_C::INC_ERX },
- /* 46 */ { 0, &BX_CPU_C::INC_ERX },
- /* 47 */ { 0, &BX_CPU_C::INC_ERX },
- /* 48 */ { 0, &BX_CPU_C::DEC_ERX },
- /* 49 */ { 0, &BX_CPU_C::DEC_ERX },
- /* 4A */ { 0, &BX_CPU_C::DEC_ERX },
- /* 4B */ { 0, &BX_CPU_C::DEC_ERX },
- /* 4C */ { 0, &BX_CPU_C::DEC_ERX },
- /* 4D */ { 0, &BX_CPU_C::DEC_ERX },
- /* 4E */ { 0, &BX_CPU_C::DEC_ERX },
- /* 4F */ { 0, &BX_CPU_C::DEC_ERX },
- /* 50 */ { 0, &BX_CPU_C::PUSH_ERX },
- /* 51 */ { 0, &BX_CPU_C::PUSH_ERX },
- /* 52 */ { 0, &BX_CPU_C::PUSH_ERX },
- /* 53 */ { 0, &BX_CPU_C::PUSH_ERX },
- /* 54 */ { 0, &BX_CPU_C::PUSH_ERX },
- /* 55 */ { 0, &BX_CPU_C::PUSH_ERX },
- /* 56 */ { 0, &BX_CPU_C::PUSH_ERX },
- /* 57 */ { 0, &BX_CPU_C::PUSH_ERX },
- /* 58 */ { 0, &BX_CPU_C::POP_ERX },
- /* 59 */ { 0, &BX_CPU_C::POP_ERX },
- /* 5A */ { 0, &BX_CPU_C::POP_ERX },
- /* 5B */ { 0, &BX_CPU_C::POP_ERX },
- /* 5C */ { 0, &BX_CPU_C::POP_ERX },
- /* 5D */ { 0, &BX_CPU_C::POP_ERX },
- /* 5E */ { 0, &BX_CPU_C::POP_ERX },
- /* 5F */ { 0, &BX_CPU_C::POP_ERX },
- /* 60 */ { 0, &BX_CPU_C::PUSHAD32 },
- /* 61 */ { 0, &BX_CPU_C::POPAD32 },
- /* 62 */ { BxAnother, &BX_CPU_C::BOUND_GvMa },
- /* 63 */ { BxAnother, &BX_CPU_C::ARPL_EwGw },
- /* 64 */ { BxPrefix | BxAnother, &BX_CPU_C::BxError }, // FS:
- /* 65 */ { BxPrefix | BxAnother, &BX_CPU_C::BxError }, // GS:
- /* 66 */ { BxPrefix | BxAnother, &BX_CPU_C::BxError }, // OS:
- /* 67 */ { BxPrefix | BxAnother, &BX_CPU_C::BxError }, // AS:
- /* 68 */ { BxImmediate_Iv, &BX_CPU_C::PUSH_Id },
- /* 69 */ { BxAnother | BxImmediate_Iv, &BX_CPU_C::IMUL_GdEdId },
- /* 6A */ { BxImmediate_Ib_SE, &BX_CPU_C::PUSH_Id },
- /* 6B */ { BxAnother | BxImmediate_Ib_SE, &BX_CPU_C::IMUL_GdEdId },
- /* 6C */ { BxRepeatable, &BX_CPU_C::INSB_YbDX },
- /* 6D */ { BxRepeatable, &BX_CPU_C::INSW_YvDX },
- /* 6E */ { BxRepeatable, &BX_CPU_C::OUTSB_DXXb },
- /* 6F */ { BxRepeatable, &BX_CPU_C::OUTSW_DXXv },
- /* 70 */ { BxImmediate_BrOff8, &sid_cpu_c::JCC_Jd },
- /* 71 */ { BxImmediate_BrOff8, &sid_cpu_c::JCC_Jd },
- /* 72 */ { BxImmediate_BrOff8, &sid_cpu_c::JCC_Jd },
- /* 73 */ { BxImmediate_BrOff8, &sid_cpu_c::JCC_Jd },
- /* 74 */ { BxImmediate_BrOff8, &sid_cpu_c::JCC_Jd },
- /* 75 */ { BxImmediate_BrOff8, &sid_cpu_c::JCC_Jd },
- /* 76 */ { BxImmediate_BrOff8, &sid_cpu_c::JCC_Jd },
- /* 77 */ { BxImmediate_BrOff8, &sid_cpu_c::JCC_Jd },
- /* 78 */ { BxImmediate_BrOff8, &sid_cpu_c::JCC_Jd },
- /* 79 */ { BxImmediate_BrOff8, &sid_cpu_c::JCC_Jd },
- /* 7A */ { BxImmediate_BrOff8, &sid_cpu_c::JCC_Jd },
- /* 7B */ { BxImmediate_BrOff8, &sid_cpu_c::JCC_Jd },
- /* 7C */ { BxImmediate_BrOff8, &sid_cpu_c::JCC_Jd },
- /* 7D */ { BxImmediate_BrOff8, &sid_cpu_c::JCC_Jd },
- /* 7E */ { BxImmediate_BrOff8, &sid_cpu_c::JCC_Jd },
- /* 7F */ { BxImmediate_BrOff8, &sid_cpu_c::JCC_Jd },
- /* 80 */ { BxAnother | BxGroup1, NULL, BxOpcodeInfoG1EbIb },
- /* 81 */ { BxAnother | BxGroup1 | BxImmediate_Iv, NULL, BxOpcodeInfoG1Ed },
- /* 82 */ { BxAnother | BxGroup1, NULL, BxOpcodeInfoG1EbIb },
- /* 83 */ { BxAnother | BxGroup1 | BxImmediate_Ib_SE, NULL, BxOpcodeInfoG1Ed },
- /* 84 */ { BxAnother, &BX_CPU_C::TEST_EbGb },
- /* 85 */ { BxAnother, &BX_CPU_C::TEST_EdGd },
- /* 86 */ { BxAnother, &BX_CPU_C::XCHG_EbGb },
- /* 87 */ { BxAnother, &BX_CPU_C::XCHG_EdGd },
- /* 88 */ { BxAnother, &BX_CPU_C::MOV_EbGb },
- /* 89 */ { BxAnother, &BX_CPU_C::MOV_EdGd },
- /* 8A */ { BxAnother, &BX_CPU_C::MOV_GbEb },
- /* 8B */ { BxAnother, &BX_CPU_C::MOV_GdEd },
- /* 8C */ { BxAnother, &BX_CPU_C::MOV_EwSw },
- /* 8D */ { BxAnother, &BX_CPU_C::LEA_GdM },
- /* 8E */ { BxAnother, &BX_CPU_C::MOV_SwEw },
- /* 8F */ { BxAnother, &BX_CPU_C::POP_Ed },
- /* 90 */ { 0, &BX_CPU_C::NOP },
- /* 91 */ { 0, &BX_CPU_C::XCHG_ERXEAX },
- /* 92 */ { 0, &BX_CPU_C::XCHG_ERXEAX },
- /* 93 */ { 0, &BX_CPU_C::XCHG_ERXEAX },
- /* 94 */ { 0, &BX_CPU_C::XCHG_ERXEAX },
- /* 95 */ { 0, &BX_CPU_C::XCHG_ERXEAX },
- /* 96 */ { 0, &BX_CPU_C::XCHG_ERXEAX },
- /* 97 */ { 0, &BX_CPU_C::XCHG_ERXEAX },
- /* 98 */ { 0, &BX_CPU_C::CWDE },
- /* 99 */ { 0, &BX_CPU_C::CDQ },
- /* 9A */ { BxImmediate_IvIw, &BX_CPU_C::CALL32_Ap },
- /* 9B */ { 0, &BX_CPU_C::FWAIT },
- /* 9C */ { 0, &BX_CPU_C::PUSHF_Fv },
- /* 9D */ { 0, &BX_CPU_C::POPF_Fv },
- /* 9E */ { 0, &BX_CPU_C::SAHF },
- /* 9F */ { 0, &BX_CPU_C::LAHF },
- /* A0 */ { BxImmediate_O, &BX_CPU_C::MOV_ALOb },
- /* A1 */ { BxImmediate_O, &BX_CPU_C::MOV_EAXOd },
- /* A2 */ { BxImmediate_O, &BX_CPU_C::MOV_ObAL },
- /* A3 */ { BxImmediate_O, &BX_CPU_C::MOV_OdEAX },
- /* A4 */ { BxRepeatable, &BX_CPU_C::MOVSB_XbYb },
- /* A5 */ { BxRepeatable, &BX_CPU_C::MOVSW_XvYv },
- /* A6 */ { BxRepeatable | BxRepeatableZF, &BX_CPU_C::CMPSB_XbYb },
- /* A7 */ { BxRepeatable | BxRepeatableZF, &BX_CPU_C::CMPSW_XvYv },
- /* A8 */ { BxImmediate_Ib, &BX_CPU_C::TEST_ALIb },
- /* A9 */ { BxImmediate_Iv, &BX_CPU_C::TEST_EAXId },
- /* AA */ { BxRepeatable, &BX_CPU_C::STOSB_YbAL },
- /* AB */ { BxRepeatable, &BX_CPU_C::STOSW_YveAX },
- /* AC */ { BxRepeatable, &BX_CPU_C::LODSB_ALXb },
- /* AD */ { BxRepeatable, &BX_CPU_C::LODSW_eAXXv },
- /* AE */ { BxRepeatable | BxRepeatableZF, &BX_CPU_C::SCASB_ALXb },
- /* AF */ { BxRepeatable | BxRepeatableZF, &BX_CPU_C::SCASW_eAXXv },
- /* B0 */ { BxImmediate_Ib, &BX_CPU_C::MOV_RLIb },
- /* B1 */ { BxImmediate_Ib, &BX_CPU_C::MOV_RLIb },
- /* B2 */ { BxImmediate_Ib, &BX_CPU_C::MOV_RLIb },
- /* B3 */ { BxImmediate_Ib, &BX_CPU_C::MOV_RLIb },
- /* B4 */ { BxImmediate_Ib, &BX_CPU_C::MOV_RHIb },
- /* B5 */ { BxImmediate_Ib, &BX_CPU_C::MOV_RHIb },
- /* B6 */ { BxImmediate_Ib, &BX_CPU_C::MOV_RHIb },
- /* B7 */ { BxImmediate_Ib, &BX_CPU_C::MOV_RHIb },
- /* B8 */ { BxImmediate_Iv, &BX_CPU_C::MOV_ERXId },
- /* B9 */ { BxImmediate_Iv, &BX_CPU_C::MOV_ERXId },
- /* BA */ { BxImmediate_Iv, &BX_CPU_C::MOV_ERXId },
- /* BB */ { BxImmediate_Iv, &BX_CPU_C::MOV_ERXId },
- /* BC */ { BxImmediate_Iv, &BX_CPU_C::MOV_ERXId },
- /* BD */ { BxImmediate_Iv, &BX_CPU_C::MOV_ERXId },
- /* BE */ { BxImmediate_Iv, &BX_CPU_C::MOV_ERXId },
- /* BF */ { BxImmediate_Iv, &BX_CPU_C::MOV_ERXId },
- /* C0 */ { BxAnother | BxGroup2 | BxImmediate_Ib, NULL, BxOpcodeInfoG2Eb },
- /* C1 */ { BxAnother | BxGroup2 | BxImmediate_Ib, NULL, BxOpcodeInfoG2Ed },
- /* C2 */ { BxImmediate_Iw, &BX_CPU_C::RETnear32_Iw },
- /* C3 */ { 0, &BX_CPU_C::RETnear32 },
- /* C4 */ { BxAnother, &BX_CPU_C::LES_GvMp },
- /* C5 */ { BxAnother, &BX_CPU_C::LDS_GvMp },
- /* C6 */ { BxAnother | BxImmediate_Ib, &BX_CPU_C::MOV_EbIb },
- /* C7 */ { BxAnother | BxImmediate_Iv, &BX_CPU_C::MOV_EdId },
- /* C8 */ { BxImmediate_IwIb, &BX_CPU_C::ENTER_IwIb },
- /* C9 */ { 0, &BX_CPU_C::LEAVE },
- /* CA */ { BxImmediate_Iw, &BX_CPU_C::RETfar32_Iw },
- /* CB */ { 0, &BX_CPU_C::RETfar32 },
- /* CC */ { 0, &sid_cpu_c::INT3 },
- /* CD */ { BxImmediate_Ib, &sid_cpu_c::INT_Ib },
- /* CE */ { 0, &BX_CPU_C::INTO },
- /* CF */ { 0, &BX_CPU_C::IRET32 },
- /* D0 */ { BxAnother | BxGroup2, NULL, BxOpcodeInfoG2Eb },
- /* D1 */ { BxAnother | BxGroup2, NULL, BxOpcodeInfoG2Ed },
- /* D2 */ { BxAnother | BxGroup2, NULL, BxOpcodeInfoG2Eb },
- /* D3 */ { BxAnother | BxGroup2, NULL, BxOpcodeInfoG2Ed },
- /* D4 */ { BxImmediate_Ib, &BX_CPU_C::AAM },
- /* D5 */ { BxImmediate_Ib, &BX_CPU_C::AAD },
- /* D6 */ { 0, &BX_CPU_C::SALC },
- /* D7 */ { 0, &BX_CPU_C::XLAT },
- /* D8 */ { BxAnother, &BX_CPU_C::ESC0 },
- /* D9 */ { BxAnother, &BX_CPU_C::ESC1 },
- /* DA */ { BxAnother, &BX_CPU_C::ESC2 },
- /* DB */ { BxAnother, &BX_CPU_C::ESC3 },
- /* DC */ { BxAnother, &BX_CPU_C::ESC4 },
- /* DD */ { BxAnother, &BX_CPU_C::ESC5 },
- /* DE */ { BxAnother, &BX_CPU_C::ESC6 },
- /* DF */ { BxAnother, &BX_CPU_C::ESC7 },
- /* E0 */ { BxImmediate_BrOff8, &BX_CPU_C::LOOPNE_Jb },
- /* E1 */ { BxImmediate_BrOff8, &BX_CPU_C::LOOPE_Jb },
- /* E2 */ { BxImmediate_BrOff8, &BX_CPU_C::LOOP_Jb },
- /* E3 */ { BxImmediate_BrOff8, &BX_CPU_C::JCXZ_Jb },
- /* E4 */ { BxImmediate_Ib, &BX_CPU_C::IN_ALIb },
- /* E5 */ { BxImmediate_Ib, &BX_CPU_C::IN_eAXIb },
- /* E6 */ { BxImmediate_Ib, &BX_CPU_C::OUT_IbAL },
- /* E7 */ { BxImmediate_Ib, &BX_CPU_C::OUT_IbeAX },
- /* E8 */ { BxImmediate_BrOff32, &BX_CPU_C::CALL_Ad },
- /* E9 */ { BxImmediate_BrOff32, &BX_CPU_C::JMP_Jd },
- /* EA */ { BxImmediate_IvIw, &BX_CPU_C::JMP_Ap },
- /* EB */ { BxImmediate_BrOff8, &BX_CPU_C::JMP_Jd },
- /* EC */ { 0, &BX_CPU_C::IN_ALDX },
- /* ED */ { 0, &BX_CPU_C::IN_eAXDX },
- /* EE */ { 0, &BX_CPU_C::OUT_DXAL },
- /* EF */ { 0, &BX_CPU_C::OUT_DXeAX },
- /* F0 */ { BxPrefix | BxAnother, &BX_CPU_C::BxError }, // LOCK:
- /* F1 */ { 0, &BX_CPU_C::INT1 },
- /* F2 */ { BxPrefix | BxAnother, &BX_CPU_C::BxError }, // REPNE/REPNZ
- /* F3 */ { BxPrefix | BxAnother, &BX_CPU_C::BxError }, // REP,REPE/REPZ
- /* F4 */ { 0, &BX_CPU_C::HLT },
- /* F5 */ { 0, &BX_CPU_C::CMC },
- /* F6 */ { BxAnother | BxGroup3, NULL, BxOpcodeInfoG3Eb },
- /* F7 */ { BxAnother | BxGroup3, NULL, BxOpcodeInfoG3Ed },
- /* F8 */ { 0, &BX_CPU_C::CLC },
- /* F9 */ { 0, &BX_CPU_C::STC },
- /* FA */ { 0, &BX_CPU_C::CLI },
- /* FB */ { 0, &BX_CPU_C::STI },
- /* FC */ { 0, &BX_CPU_C::CLD },
- /* FD */ { 0, &BX_CPU_C::STD },
- /* FE */ { BxAnother | BxGroup4, NULL, BxOpcodeInfoG4 },
- /* FF */ { BxAnother | BxGroup5, NULL, BxOpcodeInfoG5d },
-
- /* 0F 00 */ { BxAnother | BxGroup6, NULL, BxOpcodeInfoG6 },
- /* 0F 01 */ { BxAnother | BxGroup7, NULL, BxOpcodeInfoG7 },
- /* 0F 02 */ { BxAnother, &BX_CPU_C::LAR_GvEw },
- /* 0F 03 */ { BxAnother, &BX_CPU_C::LSL_GvEw },
- /* 0F 04 */ { 0, &BX_CPU_C::BxError },
- /* 0F 05 */ { 0, &BX_CPU_C::LOADALL },
- /* 0F 06 */ { 0, &BX_CPU_C::CLTS },
- /* 0F 07 */ { 0, &BX_CPU_C::BxError },
- /* 0F 08 */ { 0, &BX_CPU_C::INVD },
- /* 0F 09 */ { 0, &BX_CPU_C::WBINVD },
- /* 0F 0A */ { 0, &BX_CPU_C::BxError },
- /* 0F 0B */ { 0, &BX_CPU_C::BxError },
- /* 0F 0C */ { 0, &BX_CPU_C::BxError },
- /* 0F 0D */ { 0, &BX_CPU_C::BxError },
- /* 0F 0E */ { 0, &BX_CPU_C::BxError },
- /* 0F 0F */ { 0, &BX_CPU_C::BxError },
- /* 0F 10 */ { 0, &BX_CPU_C::BxError },
- /* 0F 11 */ { 0, &BX_CPU_C::BxError },
- /* 0F 12 */ { 0, &BX_CPU_C::BxError },
- /* 0F 13 */ { 0, &BX_CPU_C::BxError },
- /* 0F 14 */ { 0, &BX_CPU_C::BxError },
- /* 0F 15 */ { 0, &BX_CPU_C::BxError },
- /* 0F 16 */ { 0, &BX_CPU_C::BxError },
- /* 0F 17 */ { 0, &BX_CPU_C::BxError },
- /* 0F 18 */ { 0, &BX_CPU_C::BxError },
- /* 0F 19 */ { 0, &BX_CPU_C::BxError },
- /* 0F 1A */ { 0, &BX_CPU_C::BxError },
- /* 0F 1B */ { 0, &BX_CPU_C::BxError },
- /* 0F 1C */ { 0, &BX_CPU_C::BxError },
- /* 0F 1D */ { 0, &BX_CPU_C::BxError },
- /* 0F 1E */ { 0, &BX_CPU_C::BxError },
- /* 0F 1F */ { 0, &BX_CPU_C::BxError },
- /* 0F 20 */ { BxAnother, &BX_CPU_C::MOV_RdCd },
- /* 0F 21 */ { BxAnother, &BX_CPU_C::MOV_RdDd },
- /* 0F 22 */ { BxAnother, &BX_CPU_C::MOV_CdRd },
- /* 0F 23 */ { BxAnother, &BX_CPU_C::MOV_DdRd },
- /* 0F 24 */ { BxAnother, &BX_CPU_C::MOV_RdTd },
- /* 0F 25 */ { 0, &BX_CPU_C::BxError },
- /* 0F 26 */ { BxAnother, &BX_CPU_C::MOV_TdRd },
- /* 0F 27 */ { 0, &BX_CPU_C::BxError },
- /* 0F 28 */ { 0, &BX_CPU_C::BxError },
- /* 0F 29 */ { 0, &BX_CPU_C::BxError },
- /* 0F 2A */ { 0, &BX_CPU_C::BxError },
- /* 0F 2B */ { 0, &BX_CPU_C::BxError },
- /* 0F 2C */ { 0, &BX_CPU_C::BxError },
- /* 0F 2D */ { 0, &BX_CPU_C::BxError },
- /* 0F 2E */ { 0, &BX_CPU_C::BxError },
- /* 0F 2F */ { 0, &BX_CPU_C::BxError },
- /* 0F 30 */ { 0, &BX_CPU_C::WRMSR },
- /* 0F 31 */ { 0, &BX_CPU_C::RDTSC },
- /* 0F 32 */ { 0, &BX_CPU_C::RDMSR },
- /* 0F 33 */ { 0, &BX_CPU_C::BxError },
- /* 0F 34 */ { 0, &BX_CPU_C::BxError },
- /* 0F 35 */ { 0, &BX_CPU_C::BxError },
- /* 0F 36 */ { 0, &BX_CPU_C::BxError },
- /* 0F 37 */ { 0, &BX_CPU_C::BxError },
- /* 0F 38 */ { 0, &BX_CPU_C::BxError },
- /* 0F 39 */ { 0, &BX_CPU_C::BxError },
- /* 0F 3A */ { 0, &BX_CPU_C::BxError },
- /* 0F 3B */ { 0, &BX_CPU_C::BxError },
- /* 0F 3C */ { 0, &BX_CPU_C::BxError },
- /* 0F 3D */ { 0, &BX_CPU_C::BxError },
- /* 0F 3E */ { 0, &BX_CPU_C::BxError },
- /* 0F 3F */ { 0, &BX_CPU_C::BxError },
- /* 0F 40 */ { BxAnother, &BX_CPU_C::CMOV_GdEd },
- /* 0F 41 */ { BxAnother, &BX_CPU_C::CMOV_GdEd },
- /* 0F 42 */ { BxAnother, &BX_CPU_C::CMOV_GdEd },
- /* 0F 43 */ { BxAnother, &BX_CPU_C::CMOV_GdEd },
- /* 0F 44 */ { BxAnother, &BX_CPU_C::CMOV_GdEd },
- /* 0F 45 */ { BxAnother, &BX_CPU_C::CMOV_GdEd },
- /* 0F 46 */ { BxAnother, &BX_CPU_C::CMOV_GdEd },
- /* 0F 47 */ { BxAnother, &BX_CPU_C::CMOV_GdEd },
- /* 0F 48 */ { BxAnother, &BX_CPU_C::CMOV_GdEd },
- /* 0F 49 */ { BxAnother, &BX_CPU_C::CMOV_GdEd },
- /* 0F 4A */ { BxAnother, &BX_CPU_C::CMOV_GdEd },
- /* 0F 4B */ { BxAnother, &BX_CPU_C::CMOV_GdEd },
- /* 0F 4C */ { BxAnother, &BX_CPU_C::CMOV_GdEd },
- /* 0F 4D */ { BxAnother, &BX_CPU_C::CMOV_GdEd },
- /* 0F 4E */ { BxAnother, &BX_CPU_C::CMOV_GdEd },
- /* 0F 4F */ { BxAnother, &BX_CPU_C::CMOV_GdEd },
- /* 0F 50 */ { 0, &BX_CPU_C::BxError },
- /* 0F 51 */ { 0, &BX_CPU_C::BxError },
- /* 0F 52 */ { 0, &BX_CPU_C::BxError },
- /* 0F 53 */ { 0, &BX_CPU_C::BxError },
- /* 0F 54 */ { 0, &BX_CPU_C::BxError },
- /* 0F 55 */ { 0, &BX_CPU_C::BxError },
- /* 0F 56 */ { 0, &BX_CPU_C::BxError },
- /* 0F 57 */ { 0, &BX_CPU_C::BxError },
- /* 0F 58 */ { 0, &BX_CPU_C::BxError },
- /* 0F 59 */ { 0, &BX_CPU_C::BxError },
- /* 0F 5A */ { 0, &BX_CPU_C::BxError },
- /* 0F 5B */ { 0, &BX_CPU_C::BxError },
- /* 0F 5C */ { 0, &BX_CPU_C::BxError },
- /* 0F 5D */ { 0, &BX_CPU_C::BxError },
- /* 0F 5E */ { 0, &BX_CPU_C::BxError },
- /* 0F 5F */ { 0, &BX_CPU_C::BxError },
- /* 0F 60 */ { 0, &BX_CPU_C::BxError },
- /* 0F 61 */ { 0, &BX_CPU_C::BxError },
- /* 0F 62 */ { 0, &BX_CPU_C::BxError },
- /* 0F 63 */ { 0, &BX_CPU_C::BxError },
- /* 0F 64 */ { 0, &BX_CPU_C::BxError },
- /* 0F 65 */ { 0, &BX_CPU_C::BxError },
- /* 0F 66 */ { 0, &BX_CPU_C::BxError },
- /* 0F 67 */ { 0, &BX_CPU_C::BxError },
- /* 0F 68 */ { 0, &BX_CPU_C::BxError },
- /* 0F 69 */ { 0, &BX_CPU_C::BxError },
- /* 0F 6A */ { 0, &BX_CPU_C::BxError },
- /* 0F 6B */ { 0, &BX_CPU_C::BxError },
- /* 0F 6C */ { 0, &BX_CPU_C::BxError },
- /* 0F 6D */ { 0, &BX_CPU_C::BxError },
- /* 0F 6E */ { 0, &BX_CPU_C::BxError },
- /* 0F 6F */ { 0, &BX_CPU_C::BxError },
- /* 0F 70 */ { 0, &BX_CPU_C::BxError },
- /* 0F 71 */ { 0, &BX_CPU_C::BxError },
- /* 0F 72 */ { 0, &BX_CPU_C::BxError },
- /* 0F 73 */ { 0, &BX_CPU_C::BxError },
- /* 0F 74 */ { 0, &BX_CPU_C::BxError },
- /* 0F 75 */ { 0, &BX_CPU_C::BxError },
- /* 0F 76 */ { 0, &BX_CPU_C::BxError },
- /* 0F 77 */ { 0, &BX_CPU_C::BxError },
- /* 0F 78 */ { 0, &BX_CPU_C::BxError },
- /* 0F 79 */ { 0, &BX_CPU_C::BxError },
- /* 0F 7A */ { 0, &BX_CPU_C::BxError },
- /* 0F 7B */ { 0, &BX_CPU_C::BxError },
- /* 0F 7C */ { 0, &BX_CPU_C::BxError },
- /* 0F 7D */ { 0, &BX_CPU_C::BxError },
- /* 0F 7E */ { 0, &BX_CPU_C::BxError },
- /* 0F 7F */ { 0, &BX_CPU_C::BxError },
- /* 0F 80 */ { BxImmediate_BrOff32, &sid_cpu_c::JCC_Jd },
- /* 0F 81 */ { BxImmediate_BrOff32, &sid_cpu_c::JCC_Jd },
- /* 0F 82 */ { BxImmediate_BrOff32, &sid_cpu_c::JCC_Jd },
- /* 0F 83 */ { BxImmediate_BrOff32, &sid_cpu_c::JCC_Jd },
- /* 0F 84 */ { BxImmediate_BrOff32, &sid_cpu_c::JCC_Jd },
- /* 0F 85 */ { BxImmediate_BrOff32, &sid_cpu_c::JCC_Jd },
- /* 0F 86 */ { BxImmediate_BrOff32, &sid_cpu_c::JCC_Jd },
- /* 0F 87 */ { BxImmediate_BrOff32, &sid_cpu_c::JCC_Jd },
- /* 0F 88 */ { BxImmediate_BrOff32, &sid_cpu_c::JCC_Jd },
- /* 0F 89 */ { BxImmediate_BrOff32, &sid_cpu_c::JCC_Jd },
- /* 0F 8A */ { BxImmediate_BrOff32, &sid_cpu_c::JCC_Jd },
- /* 0F 8B */ { BxImmediate_BrOff32, &sid_cpu_c::JCC_Jd },
- /* 0F 8C */ { BxImmediate_BrOff32, &sid_cpu_c::JCC_Jd },
- /* 0F 8D */ { BxImmediate_BrOff32, &sid_cpu_c::JCC_Jd },
- /* 0F 8E */ { BxImmediate_BrOff32, &sid_cpu_c::JCC_Jd },
- /* 0F 8F */ { BxImmediate_BrOff32, &sid_cpu_c::JCC_Jd },
- /* 0F 90 */ { BxAnother, &BX_CPU_C::SETO_Eb },
- /* 0F 91 */ { BxAnother, &BX_CPU_C::SETNO_Eb },
- /* 0F 92 */ { BxAnother, &BX_CPU_C::SETB_Eb },
- /* 0F 93 */ { BxAnother, &BX_CPU_C::SETNB_Eb },
- /* 0F 94 */ { BxAnother, &BX_CPU_C::SETZ_Eb },
- /* 0F 95 */ { BxAnother, &BX_CPU_C::SETNZ_Eb },
- /* 0F 96 */ { BxAnother, &BX_CPU_C::SETBE_Eb },
- /* 0F 97 */ { BxAnother, &BX_CPU_C::SETNBE_Eb },
- /* 0F 98 */ { BxAnother, &BX_CPU_C::SETS_Eb },
- /* 0F 99 */ { BxAnother, &BX_CPU_C::SETNS_Eb },
- /* 0F 9A */ { BxAnother, &BX_CPU_C::SETP_Eb },
- /* 0F 9B */ { BxAnother, &BX_CPU_C::SETNP_Eb },
- /* 0F 9C */ { BxAnother, &BX_CPU_C::SETL_Eb },
- /* 0F 9D */ { BxAnother, &BX_CPU_C::SETNL_Eb },
- /* 0F 9E */ { BxAnother, &BX_CPU_C::SETLE_Eb },
- /* 0F 9F */ { BxAnother, &BX_CPU_C::SETNLE_Eb },
- /* 0F A0 */ { 0, &BX_CPU_C::PUSH_FS },
- /* 0F A1 */ { 0, &BX_CPU_C::POP_FS },
- /* 0F A2 */ { 0, &BX_CPU_C::CPUID },
- /* 0F A3 */ { BxAnother, &BX_CPU_C::BT_EvGv },
- /* 0F A4 */ { BxAnother | BxImmediate_Ib, &BX_CPU_C::SHLD_EdGd },
- /* 0F A5 */ { BxAnother, &BX_CPU_C::SHLD_EdGd },
- /* 0F A6 */ { 0, &BX_CPU_C::CMPXCHG_XBTS },
- /* 0F A7 */ { 0, &BX_CPU_C::CMPXCHG_IBTS },
- /* 0F A8 */ { 0, &BX_CPU_C::PUSH_GS },
- /* 0F A9 */ { 0, &BX_CPU_C::POP_GS },
- /* 0F AA */ { 0, &BX_CPU_C::RSM },
- /* 0F AB */ { BxAnother, &BX_CPU_C::BTS_EvGv },
- /* 0F AC */ { BxAnother | BxImmediate_Ib, &BX_CPU_C::SHRD_EdGd },
- /* 0F AD */ { BxAnother, &BX_CPU_C::SHRD_EdGd },
- /* 0F AE */ { 0, &BX_CPU_C::BxError },
- /* 0F AF */ { BxAnother, &BX_CPU_C::IMUL_GdEd },
- /* 0F B0 */ { BxAnother, &BX_CPU_C::CMPXCHG_EbGb },
- /* 0F B1 */ { BxAnother, &BX_CPU_C::CMPXCHG_EdGd },
- /* 0F B2 */ { BxAnother, &BX_CPU_C::LSS_GvMp },
- /* 0F B3 */ { BxAnother, &BX_CPU_C::BTR_EvGv },
- /* 0F B4 */ { BxAnother, &BX_CPU_C::LFS_GvMp },
- /* 0F B5 */ { BxAnother, &BX_CPU_C::LGS_GvMp },
- /* 0F B6 */ { BxAnother, &BX_CPU_C::MOVZX_GdEb },
- /* 0F B7 */ { BxAnother, &BX_CPU_C::MOVZX_GdEw },
- /* 0F B8 */ { 0, &BX_CPU_C::BxError },
- /* 0F B9 */ { 0, &BX_CPU_C::BxError },
- /* 0F BA */ { BxAnother | BxGroup8, NULL, BxOpcodeInfoG8EvIb },
- /* 0F BB */ { BxAnother, &BX_CPU_C::BTC_EvGv },
- /* 0F BC */ { BxAnother, &BX_CPU_C::BSF_GvEv },
- /* 0F BD */ { BxAnother, &BX_CPU_C::BSR_GvEv },
- /* 0F BE */ { BxAnother, &BX_CPU_C::MOVSX_GdEb },
- /* 0F BF */ { BxAnother, &BX_CPU_C::MOVSX_GdEw },
- /* 0F C0 */ { BxAnother, &BX_CPU_C::XADD_EbGb },
- /* 0F C1 */ { BxAnother, &BX_CPU_C::XADD_EdGd },
- /* 0F C2 */ { 0, &BX_CPU_C::BxError },
- /* 0F C3 */ { 0, &BX_CPU_C::BxError },
- /* 0F C4 */ { 0, &BX_CPU_C::BxError },
- /* 0F C5 */ { 0, &BX_CPU_C::BxError },
- /* 0F C6 */ { 0, &BX_CPU_C::BxError },
- /* 0F C7 */ { BxAnother | BxGroup9, NULL, BxOpcodeInfoG9 },
- /* 0F C8 */ { 0, &BX_CPU_C::BSWAP_EAX },
- /* 0F C9 */ { 0, &BX_CPU_C::BSWAP_ECX },
- /* 0F CA */ { 0, &BX_CPU_C::BSWAP_EDX },
- /* 0F CB */ { 0, &BX_CPU_C::BSWAP_EBX },
- /* 0F CC */ { 0, &BX_CPU_C::BSWAP_ESP },
- /* 0F CD */ { 0, &BX_CPU_C::BSWAP_EBP },
- /* 0F CE */ { 0, &BX_CPU_C::BSWAP_ESI },
- /* 0F CF */ { 0, &BX_CPU_C::BSWAP_EDI },
- /* 0F D0 */ { 0, &BX_CPU_C::BxError },
- /* 0F D1 */ { 0, &BX_CPU_C::BxError },
- /* 0F D2 */ { 0, &BX_CPU_C::BxError },
- /* 0F D3 */ { 0, &BX_CPU_C::BxError },
- /* 0F D4 */ { 0, &BX_CPU_C::BxError },
- /* 0F D5 */ { 0, &BX_CPU_C::BxError },
- /* 0F D6 */ { 0, &BX_CPU_C::BxError },
- /* 0F D7 */ { 0, &BX_CPU_C::BxError },
- /* 0F D8 */ { 0, &BX_CPU_C::BxError },
- /* 0F D9 */ { 0, &BX_CPU_C::BxError },
- /* 0F DA */ { 0, &BX_CPU_C::BxError },
- /* 0F DB */ { 0, &BX_CPU_C::BxError },
- /* 0F DC */ { 0, &BX_CPU_C::BxError },
- /* 0F DD */ { 0, &BX_CPU_C::BxError },
- /* 0F DE */ { 0, &BX_CPU_C::BxError },
- /* 0F DF */ { 0, &BX_CPU_C::BxError },
- /* 0F E0 */ { 0, &BX_CPU_C::BxError },
- /* 0F E1 */ { 0, &BX_CPU_C::BxError },
- /* 0F E2 */ { 0, &BX_CPU_C::BxError },
- /* 0F E3 */ { 0, &BX_CPU_C::BxError },
- /* 0F E4 */ { 0, &BX_CPU_C::BxError },
- /* 0F E5 */ { 0, &BX_CPU_C::BxError },
- /* 0F E6 */ { 0, &BX_CPU_C::BxError },
- /* 0F E7 */ { 0, &BX_CPU_C::BxError },
- /* 0F E8 */ { 0, &BX_CPU_C::BxError },
- /* 0F E9 */ { 0, &BX_CPU_C::BxError },
- /* 0F EA */ { 0, &BX_CPU_C::BxError },
- /* 0F EB */ { 0, &BX_CPU_C::BxError },
- /* 0F EC */ { 0, &BX_CPU_C::BxError },
- /* 0F ED */ { 0, &BX_CPU_C::BxError },
- /* 0F EE */ { 0, &BX_CPU_C::BxError },
- /* 0F EF */ { 0, &BX_CPU_C::BxError },
- /* 0F F0 */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F F1 */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F F2 */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F F3 */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F F4 */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F F5 */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F F6 */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F F7 */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F F8 */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F F9 */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F FA */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F FB */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F FC */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F FD */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F FE */ { 0, &BX_CPU_C::UndefinedOpcode },
- /* 0F FF */ { 0, &BX_CPU_C::UndefinedOpcode },
- };
-
-
-
-
- unsigned
-sid_cpu_c::FetchDecode(Bit8u *iptr, BxInstruction_t *instruction,
- unsigned remain, Boolean is_32)
-{
- // remain must be at least 1
-
- unsigned b1, b2, ilen=1, attr;
- unsigned imm_mode, offset;
-
- instruction->os_32 = instruction->as_32 = is_32;
- instruction->ResolveModrm = NULL;
- instruction->seg = BX_SEG_REG_NULL;
- instruction->rep_used = 0;
-
-fetch_b1:
- b1 = *iptr++;
-
-another_byte:
- offset = instruction->os_32 << 9; // * 512
- instruction->attr = attr = BxOpcodeInfo[b1+offset].Attr;
-
- if (attr & BxAnother) {
- if (attr & BxPrefix) {
- switch (b1) {
- case 0x66: // OpSize
- instruction->os_32 = !is_32;
- if (ilen < remain) {
- ilen++;
- goto fetch_b1;
- }
- return(0);
-
- case 0x67: // AddrSize
- instruction->as_32 = !is_32;
- if (ilen < remain) {
- ilen++;
- goto fetch_b1;
- }
- return(0);
-
- case 0xf2: // REPNE/REPNZ
- case 0xf3: // REP/REPE/REPZ
- instruction->rep_used = b1;
- if (ilen < remain) {
- ilen++;
- goto fetch_b1;
- }
- return(0);
- break;
-
- case 0x2e: // CS:
- instruction->seg = BX_SEG_REG_CS;
- ilen++; goto fetch_b1;
- break;
- case 0x26: // ES:
- instruction->seg = BX_SEG_REG_ES;
- ilen++; goto fetch_b1;
- break;
- case 0x36: // SS:
- instruction->seg = BX_SEG_REG_SS;
- ilen++; goto fetch_b1;
- break;
- case 0x3e: // DS:
- instruction->seg = BX_SEG_REG_DS;
- ilen++; goto fetch_b1;
- break;
- case 0x64: // FS:
- instruction->seg = BX_SEG_REG_FS;
- ilen++; goto fetch_b1;
- break;
- case 0x65: // GS:
- instruction->seg = BX_SEG_REG_GS;
- ilen++; goto fetch_b1;
- break;
- case 0xf0: // LOCK:
- ilen++; goto fetch_b1;
- break;
-
- default:
-BX_PANIC(("fetch_decode: prefix default = 0x%02x\n", b1));
- }
- }
- // opcode requires another byte
- if (ilen < remain) {
- ilen++;
- b2 = *iptr++;
- if (b1 == 0x0f) {
- // 2-byte prefix
- b1 = 0x100 | b2;
- goto another_byte;
- }
- }
- else
- return(0);
-
- // Parse mod-nnn-rm and related bytes
- unsigned rm;
- instruction->modrm = b2;
- rm =
- instruction->rm = b2 & 0x07;
- instruction->mod = b2 & 0xc0; // leave unshifted
- instruction->nnn = (b2 >> 3) & 0x07;
- if (instruction->mod == 0xc0) { // mod == 11b
- goto modrm_done;
- }
- if (instruction->as_32) {
- // 32-bit addressing modes; note that mod==11b handled above
- if (rm != 4) { // no s-i-b byte
-#if BX_DYNAMIC_TRANSLATION
- instruction->DTMemRegsUsed = 1<<rm; // except for mod=00b rm=100b
-#endif
- if (instruction->mod == 0x00) { // mod == 00b
- instruction->ResolveModrm = BxResolve32Mod0[rm];
-#if BX_DYNAMIC_TRANSLATION
- instruction->DTResolveModrm = (BxVoidFPtr_t) BxDTResolve32Mod0[rm];
-#endif
- if (BX_NULL_SEG_REG(instruction->seg))
- instruction->seg = BX_SEG_REG_DS;
- if (rm == 5) {
- if ((ilen+3) < remain) {
- Bit32u imm32u;
- imm32u = *iptr++;
- imm32u |= (*iptr++) << 8;
- imm32u |= (*iptr++) << 16;
- imm32u |= (*iptr++) << 24;
- instruction->rm_addr = imm32u;
- ilen += 4;
-#if BX_DYNAMIC_TRANSLATION
- instruction->DTMemRegsUsed = 0;
-#endif
- goto modrm_done;
- }
- else {
- return(0);
- }
- }
- // mod==00b, rm!=4, rm!=5
- goto modrm_done;
- }
- if (instruction->mod == 0x40) { // mod == 01b
- instruction->ResolveModrm = BxResolve32Mod1or2[rm];
-#if BX_DYNAMIC_TRANSLATION
- instruction->DTResolveModrm = (BxVoidFPtr_t) BxDTResolve32Mod1or2[rm];
-#endif
- if (BX_NULL_SEG_REG(instruction->seg))
- instruction->seg = BX_CPU_THIS_PTR sreg_mod01_rm32[rm];
-get_8bit_displ:
- if (ilen < remain) {
- // 8 sign extended to 32
- instruction->displ32u = (Bit8s) *iptr++;
- ilen++;
- goto modrm_done;
- }
- else {
- return(0);
- }
- }
- // (mod == 0x80) mod == 10b
- instruction->ResolveModrm = BxResolve32Mod1or2[rm];
-#if BX_DYNAMIC_TRANSLATION
- instruction->DTResolveModrm = (BxVoidFPtr_t) BxDTResolve32Mod1or2[rm];
-#endif
- if (BX_NULL_SEG_REG(instruction->seg))
- instruction->seg = BX_CPU_THIS_PTR sreg_mod10_rm32[rm];
-get_32bit_displ:
- if ((ilen+3) < remain) {
- Bit32u imm32u;
- imm32u = *iptr++;
- imm32u |= (*iptr++) << 8;
- imm32u |= (*iptr++) << 16;
- imm32u |= (*iptr++) << 24;
- instruction->displ32u = imm32u;
- ilen += 4;
- goto modrm_done;
- }
- else {
- return(0);
- }
- }
- else { // mod!=11b, rm==4, s-i-b byte follows
- unsigned sib, base;
- if (ilen < remain) {
- sib = *iptr++;
- ilen++;
- }
- else {
- return(0);
- }
- instruction->sib = sib;
- base =
- instruction->base = sib & 0x07; sib >>= 3;
- instruction->index = sib & 0x07; sib >>= 3;
- instruction->scale = sib;
-#if BX_DYNAMIC_TRANSLATION
- if (instruction->index == 0x04) // 100b
- instruction->DTMemRegsUsed = 0;
- else
- instruction->DTMemRegsUsed = 1<<instruction->index;
-#endif
- if (instruction->mod == 0x00) { // mod==00b, rm==4
- instruction->ResolveModrm = BxResolve32Mod0Base[base];
-#if BX_DYNAMIC_TRANSLATION
- instruction->DTResolveModrm = (BxVoidFPtr_t) BxDTResolve32Mod0Base[base];
-#endif
- if (BX_NULL_SEG_REG(instruction->seg))
- instruction->seg = BX_CPU_THIS_PTR sreg_mod0_base32[base];
- if (instruction->base == 0x05) {
- goto get_32bit_displ;
- }
- // mod==00b, rm==4, base!=5
-#if BX_DYNAMIC_TRANSLATION
- instruction->DTMemRegsUsed |= 1<<base;
-#endif
- goto modrm_done;
- }
-#if BX_DYNAMIC_TRANSLATION
- // for remaining 32bit cases
- instruction->DTMemRegsUsed |= 1<<base;
-#endif
- if (instruction->mod == 0x40) { // mod==01b, rm==4
- instruction->ResolveModrm = BxResolve32Mod1or2Base[base];
-#if BX_DYNAMIC_TRANSLATION
- instruction->DTResolveModrm = (BxVoidFPtr_t) BxDTResolve32Mod1or2Base[base];
-#endif
- if (BX_NULL_SEG_REG(instruction->seg))
- instruction->seg = BX_CPU_THIS_PTR sreg_mod1or2_base32[base];
- goto get_8bit_displ;
- }
- // (instruction->mod == 0x80), mod==10b, rm==4
- instruction->ResolveModrm = BxResolve32Mod1or2Base[base];
-#if BX_DYNAMIC_TRANSLATION
- instruction->DTResolveModrm = (BxVoidFPtr_t) BxDTResolve32Mod1or2Base[base];
-#endif
- if (BX_NULL_SEG_REG(instruction->seg))
- instruction->seg = BX_CPU_THIS_PTR sreg_mod1or2_base32[base];
- goto get_32bit_displ;
- }
- }
- else {
- // 16-bit addressing modes, mod==11b handled above
- if (instruction->mod == 0x40) { // mod == 01b
- instruction->ResolveModrm = BxResolve16Mod1or2[rm];
-#if BX_DYNAMIC_TRANSLATION
- instruction->DTResolveModrm = (BxVoidFPtr_t) BxDTResolve16Mod1or2[rm];
-#endif
- if (BX_NULL_SEG_REG(instruction->seg))
- instruction->seg = BX_CPU_THIS_PTR sreg_mod01_rm16[rm];
-#if BX_DYNAMIC_TRANSLATION
- instruction->DTMemRegsUsed = BxMemRegsUsed16[rm];
-#endif
- if (ilen < remain) {
- // 8 sign extended to 16
- instruction->displ16u = (Bit8s) *iptr++;
- ilen++;
- goto modrm_done;
- }
- else {
- return(0);
- }
- }
- if (instruction->mod == 0x80) { // mod == 10b
- instruction->ResolveModrm = BxResolve16Mod1or2[rm];
-#if BX_DYNAMIC_TRANSLATION
- instruction->DTResolveModrm = (BxVoidFPtr_t) BxDTResolve16Mod1or2[rm];
-#endif
- if (BX_NULL_SEG_REG(instruction->seg))
- instruction->seg = BX_CPU_THIS_PTR sreg_mod10_rm16[rm];
-#if BX_DYNAMIC_TRANSLATION
- instruction->DTMemRegsUsed = BxMemRegsUsed16[rm];
-#endif
- if ((ilen+1) < remain) {
- Bit16u displ16u;
- displ16u = *iptr++;
- displ16u |= (*iptr++) << 8;
- instruction->displ16u = displ16u;
- ilen += 2;
- goto modrm_done;
- }
- else {
- return(0);
- }
- }
- // mod must be 00b at this point
- instruction->ResolveModrm = BxResolve16Mod0[rm];
-#if BX_DYNAMIC_TRANSLATION
- instruction->DTResolveModrm = (BxVoidFPtr_t) BxDTResolve16Mod0[rm];
-#endif
- if (BX_NULL_SEG_REG(instruction->seg))
- instruction->seg = BX_CPU_THIS_PTR sreg_mod00_rm16[rm];
- if (rm == 0x06) {
- if ((ilen+1) < remain) {
- Bit16u displ16u;
- displ16u = *iptr++;
- displ16u |= (*iptr++) << 8;
- instruction->rm_addr = displ16u;
- ilen += 2;
- goto modrm_done;
- }
- else {
- return(0);
- }
- }
- // mod=00b rm!=6
-#if BX_DYNAMIC_TRANSLATION
- instruction->DTMemRegsUsed = BxMemRegsUsed16[rm];
-#endif
- }
-
-modrm_done:
- if (attr & BxGroupN) {
- BxOpcodeInfo_t *OpcodeInfoPtr;
-
- OpcodeInfoPtr = BxOpcodeInfo[b1+offset].AnotherArray;
- instruction->execute_sid = OpcodeInfoPtr[instruction->nnn].ExecutePtr;
- // get additional attributes from group table
- attr |= OpcodeInfoPtr[instruction->nnn].Attr;
- instruction->attr = attr;
-#if BX_DYNAMIC_TRANSLATION
- instruction->DTAttr = 0; // for now
-#endif
- }
- else {
- instruction->execute_sid = BxOpcodeInfo[b1+offset].ExecutePtr;
-#if BX_DYNAMIC_TRANSLATION
- instruction->DTAttr = BxDTOpcodeInfo[b1+offset].DTAttr;
- instruction->DTFPtr = BxDTOpcodeInfo[b1+offset].DTASFPtr;
-#endif
- }
- }
- else {
- // Opcode does not require a MODRM byte.
- // Note that a 2-byte opcode (0F XX) will jump to before
- // the if() above after fetching the 2nd byte, so this path is
- // taken in all cases if a modrm byte is NOT required.
- instruction->execute_sid = BxOpcodeInfo[b1+offset].ExecutePtr;
-#if BX_DYNAMIC_TRANSLATION
- instruction->DTAttr = BxDTOpcodeInfo[b1+offset].DTAttr;
- instruction->DTFPtr = BxDTOpcodeInfo[b1+offset].DTASFPtr;
-#endif
- }
-
-
- imm_mode = attr & BxImmediate;
-
- if (imm_mode) {
- switch (imm_mode) {
- case BxImmediate_Ib:
- if (ilen < remain) {
- instruction->Ib = *iptr;
- ilen++;
- }
- else {
- return(0);
- }
- break;
- case BxImmediate_Ib_SE: // Sign extend to OS size
- if (ilen < remain) {
- Bit8s temp8s;
- temp8s = *iptr;
- if (instruction->os_32)
- instruction->Id = (Bit32s) temp8s;
- else
- instruction->Iw = (Bit16s) temp8s;
- ilen++;
- }
- else {
- return(0);
- }
- break;
- case BxImmediate_Iv: // same as BxImmediate_BrOff32
- case BxImmediate_IvIw: // CALL_Ap
- if (instruction->os_32) {
- if ((ilen+3) < remain) {
- Bit32u imm32u;
- imm32u = *iptr++;
- imm32u |= (*iptr++) << 8;
- imm32u |= (*iptr++) << 16;
- imm32u |= (*iptr) << 24;
- instruction->Id = imm32u;
- ilen += 4;
- }
- else {
- return(0);
- }
- }
- else {
- if ((ilen+1) < remain) {
- Bit16u imm16u;
- imm16u = *iptr++;
- imm16u |= (*iptr) << 8;
- instruction->Iw = imm16u;
- ilen += 2;
- }
- else {
- return(0);
- }
- }
- if (imm_mode != BxImmediate_IvIw)
- break;
- iptr++;
- // Get Iw for BxImmediate_IvIw
- if ((ilen+1) < remain) {
- Bit16u imm16u;
- imm16u = *iptr++;
- imm16u |= (*iptr) << 8;
- instruction->Iw2 = imm16u;
- ilen += 2;
- }
- else {
- return(0);
- }
- break;
- case BxImmediate_O:
- if (instruction->as_32) {
- // fetch 32bit address into Id
- if ((ilen+3) < remain) {
- Bit32u imm32u;
- imm32u = *iptr++;
- imm32u |= (*iptr++) << 8;
- imm32u |= (*iptr++) << 16;
- imm32u |= (*iptr) << 24;
- instruction->Id = imm32u;
- ilen += 4;
- }
- else {
- return(0);
- }
- }
- else {
- // fetch 16bit address into Id
- if ((ilen+1) < remain) {
- Bit32u imm32u;
- imm32u = *iptr++;
- imm32u |= (*iptr) << 8;
- instruction->Id = imm32u;
- ilen += 2;
- }
- else {
- return(0);
- }
- }
- break;
- case BxImmediate_Iw:
- case BxImmediate_IwIb:
- if ((ilen+1) < remain) {
- Bit16u imm16u;
- imm16u = *iptr++;
- imm16u |= (*iptr) << 8;
- instruction->Iw = imm16u;
- ilen += 2;
- }
- else {
- return(0);
- }
- if (imm_mode == BxImmediate_Iw) break;
- iptr++;
- if (ilen < remain) {
- instruction->Ib2 = *iptr;
- ilen++;
- }
- else {
- return(0);
- }
- break;
- case BxImmediate_BrOff8:
- if (ilen < remain) {
- Bit8s temp8s;
- temp8s = *iptr;
- instruction->Id = temp8s;
- ilen++;
- }
- else {
- return(0);
- }
- break;
- case BxImmediate_BrOff16:
- if ((ilen+1) < remain) {
- Bit16u imm16u;
- imm16u = *iptr++;
- imm16u |= (*iptr) << 8;
- instruction->Id = (Bit16s) imm16u;
- ilen += 2;
- }
- else {
- return(0);
- }
- break;
- default:
-BX_INFO(("b1 was %x\n", b1));
- BX_PANIC(("fetchdecode: imm_mode = %u\n", imm_mode));
- }
- }
-
- instruction->b1 = b1;
- instruction->ilen = ilen;
- //instruction->flags_in = 0; // for now
- //instruction->flags_out = 0; // for now
- return(1);
-}
-#if 0
- void
-BX_CPU_C::BxError(BxInstruction_t *i)
-{
- // extern void dump_core();
- BX_INFO(("BxError: instruction with op1=0x%x\n", i->b1));
- BX_INFO(("nnn was %u\n", i->nnn));
-
- BX_INFO(("WARNING: Encountered an unknown instruction (signalling illegal instruction):\n"));
- // dump_core();
-
- BX_CPU_THIS_PTR UndefinedOpcode(i);
-}
-
- void
-BX_CPU_C::BxResolveError(BxInstruction_t *i)
-{
- BX_PANIC(("BxResolveError: instruction with op1=0x%x\n", i->b1));
-}
-#endif
--- /dev/null
+## Process this with automake to create Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(srcdir)/../.. -I$(srcdir) -I$(srcdir)/stubs -DUSE_WITH_CPU_SIM -DPARANOID -DNO_ASSEMBLER
+
+noinst_LTLIBRARIES = libfpu.la
+
+libfpu_la_SOURCES = fpu.cc wmFPUemu_glue.cc fpu_entry.c errors.c reg_ld_str.c load_store.c fpu_arith.c fpu_aux.c fpu_etc.c fpu_tags.c fpu_trig.c poly_atan.c poly_l2.c poly_2xm1.c poly_sin.c poly_tan.c reg_add_sub.c reg_compare.c reg_constant.c reg_convert.c reg_divide.c reg_mul.c reg_u_add.c reg_u_div.c reg_u_mul.c reg_u_sub.c div_small.c reg_norm.c reg_round.c wm_shrx.c wm_sqrt.c div_Xsig.c polynom_Xsig.c round_Xsig.c shr_Xsig.c mul_Xsig.c
+
+libfpu_la_LDFLAGS = -no-undefined
--- /dev/null
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ../..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+APIC_OBJS = @APIC_OBJS@
+AR = @AR@
+AS = @AS@
+AS_DYNAMIC_INCS = @AS_DYNAMIC_INCS@
+AS_DYNAMIC_OBJS = @AS_DYNAMIC_OBJS@
+BX_LOADER_OBJS = @BX_LOADER_OBJS@
+BX_SPLIT_HD_SUPPORT = @BX_SPLIT_HD_SUPPORT@
+CC = @CC@
+CDROM_OBJS = @CDROM_OBJS@
+CD_UP_ONE = @CD_UP_ONE@
+CD_UP_TWO = @CD_UP_TWO@
+CFP = @CFP@
+COMMAND_SEPARATOR = @COMMAND_SEPARATOR@
+CPP_SUFFIX = @CPP_SUFFIX@
+CXX = @CXX@
+CXXFP = @CXXFP@
+DASH = @DASH@
+DEBUGGER_VAR = @DEBUGGER_VAR@
+DISASM_VAR = @DISASM_VAR@
+DLLTOOL = @DLLTOOL@
+DYNAMIC_VAR = @DYNAMIC_VAR@
+EXE = @EXE@
+EXEEXT = @EXEEXT@
+EXTERNAL_DEPENDENCY = @EXTERNAL_DEPENDENCY@
+FPU_GLUE_OBJ = @FPU_GLUE_OBJ@
+FPU_VAR = @FPU_VAR@
+GUI_LINK_OPTS = @GUI_LINK_OPTS@
+GUI_LINK_OPTS_TERM = @GUI_LINK_OPTS_TERM@
+GUI_OBJS = @GUI_OBJS@
+GZIP = @GZIP@
+INLINE_VAR = @INLINE_VAR@
+INSTRUMENT_DIR = @INSTRUMENT_DIR@
+INSTRUMENT_VAR = @INSTRUMENT_VAR@
+IOAPIC_OBJS = @IOAPIC_OBJS@
+IODEV_LIB_VAR = @IODEV_LIB_VAR@
+LD = @LD@
+LIBTOOL = @LIBTOOL@
+LINK = @LINK@
+LN_S = @LN_S@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MAKELIB = @MAKELIB@
+NE2K_OBJS = @NE2K_OBJS@
+NM = @NM@
+NONINLINE_VAR = @NONINLINE_VAR@
+OBJDUMP = @OBJDUMP@
+OFP = @OFP@
+PACKAGE = @PACKAGE@
+PCI_OBJ = @PCI_OBJ@
+PRIMARY_TARGET = @PRIMARY_TARGET@
+RANLIB = @RANLIB@
+READLINE_LIB = @READLINE_LIB@
+RFB_LIBS = @RFB_LIBS@
+RMCOMMAND = @RMCOMMAND@
+SB16_OBJS = @SB16_OBJS@
+SLASH = @SLASH@
+SUFFIX_LINE = @SUFFIX_LINE@
+TAR = @TAR@
+VERSION = @VERSION@
+VIDEO_OBJS = @VIDEO_OBJS@
+sidtarget_arm = @sidtarget_arm@
+sidtarget_m32r = @sidtarget_m32r@
+sidtarget_m68k = @sidtarget_m68k@
+sidtarget_mips = @sidtarget_mips@
+sidtarget_ppc = @sidtarget_ppc@
+sidtarget_x86 = @sidtarget_x86@
+sidtarget_xstormy16 = @sidtarget_xstormy16@
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(srcdir)/../.. -I$(srcdir) -I$(srcdir)/stubs -DUSE_WITH_CPU_SIM -DPARANOID -DNO_ASSEMBLER
+
+noinst_LTLIBRARIES = libfpu.la
+
+libfpu_la_SOURCES = fpu.cc wmFPUemu_glue.cc fpu_entry.c errors.c reg_ld_str.c load_store.c fpu_arith.c fpu_aux.c fpu_etc.c fpu_tags.c fpu_trig.c poly_atan.c poly_l2.c poly_2xm1.c poly_sin.c poly_tan.c reg_add_sub.c reg_compare.c reg_constant.c reg_convert.c reg_divide.c reg_mul.c reg_u_add.c reg_u_div.c reg_u_mul.c reg_u_sub.c div_small.c reg_norm.c reg_round.c wm_shrx.c wm_sqrt.c div_Xsig.c polynom_Xsig.c round_Xsig.c shr_Xsig.c mul_Xsig.c
+
+libfpu_la_LDFLAGS = -no-undefined
+mkinstalldirs = $(SHELL) $(top_srcdir)/../../config/mkinstalldirs
+CONFIG_HEADER = ../../config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I../..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_LIBS = @X_LIBS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+libfpu_la_LIBADD =
+libfpu_la_OBJECTS = fpu.lo wmFPUemu_glue.lo fpu_entry.lo errors.lo \
+reg_ld_str.lo load_store.lo fpu_arith.lo fpu_aux.lo fpu_etc.lo \
+fpu_tags.lo fpu_trig.lo poly_atan.lo poly_l2.lo poly_2xm1.lo \
+poly_sin.lo poly_tan.lo reg_add_sub.lo reg_compare.lo reg_constant.lo \
+reg_convert.lo reg_divide.lo reg_mul.lo reg_u_add.lo reg_u_div.lo \
+reg_u_mul.lo reg_u_sub.lo div_small.lo reg_norm.lo reg_round.lo \
+wm_shrx.lo wm_sqrt.lo div_Xsig.lo polynom_Xsig.lo round_Xsig.lo \
+shr_Xsig.lo mul_Xsig.lo
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+DIST_COMMON = README Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+GZIP_ENV = --best
+DEP_FILES = .deps/div_Xsig.P .deps/div_small.P .deps/errors.P \
+.deps/fpu.P .deps/fpu_arith.P .deps/fpu_aux.P .deps/fpu_entry.P \
+.deps/fpu_etc.P .deps/fpu_tags.P .deps/fpu_trig.P .deps/load_store.P \
+.deps/mul_Xsig.P .deps/poly_2xm1.P .deps/poly_atan.P .deps/poly_l2.P \
+.deps/poly_sin.P .deps/poly_tan.P .deps/polynom_Xsig.P \
+.deps/reg_add_sub.P .deps/reg_compare.P .deps/reg_constant.P \
+.deps/reg_convert.P .deps/reg_divide.P .deps/reg_ld_str.P \
+.deps/reg_mul.P .deps/reg_norm.P .deps/reg_round.P .deps/reg_u_add.P \
+.deps/reg_u_div.P .deps/reg_u_mul.P .deps/reg_u_sub.P \
+.deps/round_Xsig.P .deps/shr_Xsig.P .deps/wmFPUemu_glue.P \
+.deps/wm_shrx.P .deps/wm_sqrt.P
+SOURCES = $(libfpu_la_SOURCES)
+OBJECTS = $(libfpu_la_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .cc .lo .o .s
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --foreign cpu/fpu/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLTLIBRARIES:
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+
+distclean-noinstLTLIBRARIES:
+
+maintainer-clean-noinstLTLIBRARIES:
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.s.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+libfpu.la: $(libfpu_la_OBJECTS) $(libfpu_la_DEPENDENCIES)
+ $(CXXLINK) $(libfpu_la_LDFLAGS) $(libfpu_la_OBJECTS) $(libfpu_la_LIBADD) $(LIBS)
+.cc.o:
+ $(CXXCOMPILE) -c $<
+.cc.lo:
+ $(LTCXXCOMPILE) -c $<
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = cpu/fpu
+
+distdir: $(DISTFILES)
+ here=`cd $(top_builddir) && pwd`; \
+ top_distdir=`cd $(top_distdir) && pwd`; \
+ distdir=`cd $(distdir) && pwd`; \
+ cd $(top_srcdir) \
+ && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --foreign cpu/fpu/Makefile
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+ -rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+ @echo '$(COMPILE) -c $<'; \
+ $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.c
+ @echo '$(LTCOMPILE) -c $<'; \
+ $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+
+%.o: %.cc
+ @echo '$(CXXCOMPILE) -c $<'; \
+ $(CXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.cc
+ @echo '$(LTCXXCOMPILE) -c $<'; \
+ $(LTCXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LTLIBRARIES)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-noinstLTLIBRARIES mostlyclean-compile \
+ mostlyclean-libtool mostlyclean-tags mostlyclean-depend \
+ mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-noinstLTLIBRARIES clean-compile clean-libtool \
+ clean-tags clean-depend clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-noinstLTLIBRARIES distclean-compile \
+ distclean-libtool distclean-tags distclean-depend \
+ distclean-generic clean-am
+ -rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-noinstLTLIBRARIES \
+ maintainer-clean-compile maintainer-clean-libtool \
+ maintainer-clean-tags maintainer-clean-depend \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLTLIBRARIES distclean-noinstLTLIBRARIES \
+clean-noinstLTLIBRARIES maintainer-clean-noinstLTLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-libtool distclean-libtool \
+clean-libtool maintainer-clean-libtool tags mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir \
+mostlyclean-depend distclean-depend clean-depend \
+maintainer-clean-depend info-am info dvi-am dvi check check-am \
+installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+Portable i387 emulator
+
+22 Nov 99 Version 2.02:
+
+First pseudo-portable version for little-endian machines.
+
+Beginning of big-endian support provided through the pre-processor
+symbol BIG_ENDIAN.
+
+Some of the code in fpu_entry.c and get_address.c is still in a
+non-portable form and these two files still contain assembler code.
+
+
--- /dev/null
+ +---------------------------------------------------------------------------+
+ | wm-FPU-emu an FPU emulator for 80386 and 80486SX microprocessors. |
+ | |
+ | Copyright (C) 1992,1993,1994,1995,1996,1997,1999 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@melbpc.org.au |
+ | |
+ | This program is free software; you can redistribute it and/or modify |
+ | it under the terms of the GNU General Public License version 2 as |
+ | published by the Free Software Foundation. |
+ | |
+ | This program is distributed in the hope that it will be useful, |
+ | but WITHOUT ANY WARRANTY; without even the implied warranty of |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
+ | GNU General Public License for more details. |
+ | |
+ | You should have received a copy of the GNU General Public License |
+ | along with this program; if not, write to the Free Software |
+ | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
+ | |
+ +---------------------------------------------------------------------------+
+
+
+
+wm-FPU-emu is an FPU emulator for Linux. It is derived from wm-emu387
+which was my 80387 emulator for early versions of djgpp (gcc under
+msdos); wm-emu387 was in turn based upon emu387 which was written by
+DJ Delorie for djgpp. The interface to the Linux kernel is based upon
+the original Linux math emulator by Linus Torvalds.
+
+My target FPU for wm-FPU-emu is that described in the Intel486
+Programmer's Reference Manual (1992 edition). Unfortunately, numerous
+facets of the functioning of the FPU are not well covered in the
+Reference Manual. The information in the manual has been supplemented
+with measurements on real 80486's. Unfortunately, it is simply not
+possible to be sure that all of the peculiarities of the 80486 have
+been discovered, so there is always likely to be obscure differences
+in the detailed behaviour of the emulator and a real 80486.
+
+wm-FPU-emu does not implement all of the behaviour of the 80486 FPU,
+but is very close. See "Limitations" later in this file for a list of
+some differences.
+
+Please report bugs, etc to me at:
+ billm@melbpc.org.au
+or b.metzenthen@medoto.unimelb.edu.au
+
+For more information on the emulator and on floating point topics, see
+my web pages, currently at http://www.suburbia.net/~billm/
+
+
+--Bill Metzenthen
+ December 1999
+
+
+----------------------- Internals of wm-FPU-emu -----------------------
+
+Numeric algorithms:
+(1) Add, subtract, and multiply. Nothing remarkable in these.
+(2) Divide has been tuned to get reasonable performance. The algorithm
+ is not the obvious one which most people seem to use, but is designed
+ to take advantage of the characteristics of the 80386. I expect that
+ it has been invented many times before I discovered it, but I have not
+ seen it. It is based upon one of those ideas which one carries around
+ for years without ever bothering to check it out.
+(3) The sqrt function has been tuned to get good performance. It is based
+ upon Newton's classic method. Performance was improved by capitalizing
+ upon the properties of Newton's method, and the code is once again
+ structured taking account of the 80386 characteristics.
+(4) The trig, log, and exp functions are based in each case upon quasi-
+ "optimal" polynomial approximations. My definition of "optimal" was
+ based upon getting good accuracy with reasonable speed.
+(5) The argument reducing code for the trig function effectively uses
+ a value of pi which is accurate to more than 128 bits. As a consequence,
+ the reduced argument is accurate to more than 64 bits for arguments up
+ to a few pi, and accurate to more than 64 bits for most arguments,
+ even for arguments approaching 2^63. This is far superior to an
+ 80486, which uses a value of pi which is accurate to 66 bits.
+
+The code of the emulator is complicated slightly by the need to
+account for a limited form of re-entrancy. Normally, the emulator will
+emulate each FPU instruction to completion without interruption.
+However, it may happen that when the emulator is accessing the user
+memory space, swapping may be needed. In this case the emulator may be
+temporarily suspended while disk i/o takes place. During this time
+another process may use the emulator, thereby perhaps changing static
+variables. The code which accesses user memory is confined to five
+files:
+ fpu_entry.c
+ reg_ld_str.c
+ load_store.c
+ get_address.c
+ errors.c
+As from version 1.12 of the emulator, no static variables are used
+(apart from those in the kernel's per-process tables). The emulator is
+therefore now fully re-entrant, rather than having just the restricted
+form of re-entrancy which is required by the Linux kernel.
+
+----------------------- Limitations of wm-FPU-emu -----------------------
+
+There are a number of differences between the current wm-FPU-emu
+(version 2.05) and the 80486 FPU (apart from bugs). The differences
+are fewer than those which applied to the 1.xx series of the emulator.
+Some of the more important differences are listed below:
+
+The Roundup flag does not have much meaning for the transcendental
+functions and its 80486 value with these functions is likely to differ
+from its emulator value.
+
+In a few rare cases the Underflow flag obtained with the emulator will
+be different from that obtained with an 80486. This occurs when the
+following conditions apply simultaneously:
+(a) the operands have a higher precision than the current setting of the
+ precision control (PC) flags.
+(b) the underflow exception is masked.
+(c) the magnitude of the exact result (before rounding) is less than 2^-16382.
+(d) the magnitude of the final result (after rounding) is exactly 2^-16382.
+(e) the magnitude of the exact result would be exactly 2^-16382 if the
+ operands were rounded to the current precision before the arithmetic
+ operation was performed.
+If all of these apply, the emulator will set the Underflow flag but a real
+80486 will not.
+
+NOTE: Certain formats of Extended Real are UNSUPPORTED. They are
+unsupported by the 80486. They are the Pseudo-NaNs, Pseudoinfinities,
+and Unnormals. None of these will be generated by an 80486 or by the
+emulator. Do not use them. The emulator treats them differently in
+detail from the way an 80486 does.
+
+Self modifying code can cause the emulator to fail. An example of such
+code is:
+ movl %esp,[%ebx]
+ fld1
+The FPU instruction may be (usually will be) loaded into the pre-fetch
+queue of the CPU before the mov instruction is executed. If the
+destination of the 'movl' overlaps the FPU instruction then the bytes
+in the prefetch queue and memory will be inconsistent when the FPU
+instruction is executed. The emulator will be invoked but will not be
+able to find the instruction which caused the device-not-present
+exception. For this case, the emulator cannot emulate the behaviour of
+an 80486DX.
+
+Handling of the address size override prefix byte (0x67) has not been
+extensively tested yet. A major problem exists because using it in
+vm86 mode can cause a general protection fault. Address offsets
+greater than 0xffff appear to be illegal in vm86 mode but are quite
+acceptable (and work) in real mode. A small test program developed to
+check the addressing, and which runs successfully in real mode,
+crashes dosemu under Linux and also brings Windows down with a general
+protection fault message when run under the MS-DOS prompt of Windows
+3.1. (The program simply reads data from a valid address).
+
+The emulator supports 16-bit protected mode, with one difference from
+an 80486DX. A 80486DX will allow some floating point instructions to
+write a few bytes below the lowest address of the stack. The emulator
+will not allow this in 16-bit protected mode: no instructions are
+allowed to write outside the bounds set by the protection.
+
+----------------------- Performance of wm-FPU-emu -----------------------
+
+Speed.
+-----
+
+The speed of floating point computation with the emulator will depend
+upon instruction mix. Relative performance is best for the instructions
+which require most computation. The simple instructions are adversely
+affected by the FPU instruction trap overhead.
+
+
+Timing: Some simple timing tests have been made on the emulator functions.
+The times include load/store instructions. All times are in microseconds
+measured on a 33MHz 386 with 64k cache. The Turbo C tests were under
+ms-dos, the next two columns are for emulators running with the djgpp
+ms-dos extender. The final column is for wm-FPU-emu in Linux 0.97,
+using libm4.0 (hard).
+
+function Turbo C djgpp 1.06 WM-emu387 wm-FPU-emu
+
+ + 60.5 154.8 76.5 139.4
+ - 61.1-65.5 157.3-160.8 76.2-79.5 142.9-144.7
+ * 71.0 190.8 79.6 146.6
+ / 61.2-75.0 261.4-266.9 75.3-91.6 142.2-158.1
+
+ sin() 310.8 4692.0 319.0 398.5
+ cos() 284.4 4855.2 308.0 388.7
+ tan() 495.0 8807.1 394.9 504.7
+ atan() 328.9 4866.4 601.1 419.5-491.9
+
+ sqrt() 128.7 crashed 145.2 227.0
+ log() 413.1-419.1 5103.4-5354.21 254.7-282.2 409.4-437.1
+ exp() 479.1 6619.2 469.1 850.8
+
+
+The performance under Linux is improved by the use of look-ahead code.
+The following results show the improvement which is obtained under
+Linux due to the look-ahead code. Also given are the times for the
+original Linux emulator with the 4.1 'soft' lib.
+
+ [ Linus' note: I changed look-ahead to be the default under linux, as
+ there was no reason not to use it after I had edited it to be
+ disabled during tracing ]
+
+ wm-FPU-emu w original w
+ look-ahead 'soft' lib
+ + 106.4 190.2
+ - 108.6-111.6 192.4-216.2
+ * 113.4 193.1
+ / 108.8-124.4 700.1-706.2
+
+ sin() 390.5 2642.0
+ cos() 381.5 2767.4
+ tan() 496.5 3153.3
+ atan() 367.2-435.5 2439.4-3396.8
+
+ sqrt() 195.1 4732.5
+ log() 358.0-387.5 3359.2-3390.3
+ exp() 619.3 4046.4
+
+
+These figures are now somewhat out-of-date. The emulator has become
+progressively slower for most functions as more of the 80486 features
+have been implemented.
+
+
+----------------------- Accuracy of wm-FPU-emu -----------------------
+
+
+The accuracy of the emulator is in almost all cases equal to or better
+than that of an Intel 80486 FPU.
+
+The results of the basic arithmetic functions (+,-,*,/), and fsqrt
+match those of an 80486 FPU. They are the best possible; the error for
+these never exceeds 1/2 an lsb. The fprem and fprem1 instructions
+return exact results; they have no error.
+
+
+The following table compares the emulator accuracy for the sqrt(),
+trig and log functions against the Turbo C "emulator". For this table,
+each function was tested at about 400 points. Ideal worst-case results
+would be 64 bits. The reduced Turbo C accuracy of cos() and tan() for
+arguments greater than pi/4 can be thought of as being related to the
+precision of the argument x; e.g. an argument of pi/2-(1e-10) which is
+accurate to 64 bits can result in a relative accuracy in cos() of
+about 64 + log2(cos(x)) = 31 bits.
+
+
+Function Tested x range Worst result Turbo C
+ (relative bits)
+
+sqrt(x) 1 .. 2 64.1 63.2
+atan(x) 1e-10 .. 200 64.2 62.8
+cos(x) 0 .. pi/2-(1e-10) 64.4 (x <= pi/4) 62.4
+ 64.1 (x = pi/2-(1e-10)) 31.9
+sin(x) 1e-10 .. pi/2 64.0 62.8
+tan(x) 1e-10 .. pi/2-(1e-10) 64.0 (x <= pi/4) 62.1
+ 64.1 (x = pi/2-(1e-10)) 31.9
+exp(x) 0 .. 1 63.1 ** 62.9
+log(x) 1+1e-6 .. 2 63.8 ** 62.1
+
+** The accuracy for exp() and log() is low because the FPU (emulator)
+does not compute them directly; two operations are required.
+
+
+The emulator passes the "paranoia" tests (compiled with gcc 2.3.3 or
+later) for 'float' variables (24 bit precision numbers) when precision
+control is set to 24, 53 or 64 bits, and for 'double' variables (53
+bit precision numbers) when precision control is set to 53 bits (a
+properly performing FPU cannot pass the 'paranoia' tests for 'double'
+variables when precision control is set to 64 bits).
+
+The code for reducing the argument for the trig functions (fsin, fcos,
+fptan and fsincos) has been improved and now effectively uses a value
+for pi which is accurate to more than 128 bits precision. As a
+consequence, the accuracy of these functions for large arguments has
+been dramatically improved (and is now very much better than an 80486
+FPU). There is also now no degradation of accuracy for fcos and fptan
+for operands close to pi/2. Measured results are (note that the
+definition of accuracy has changed slightly from that used for the
+above table):
+
+Function Tested x range Worst result
+ (absolute bits)
+
+cos(x) 0 .. 9.22e+18 62.0
+sin(x) 1e-16 .. 9.22e+18 62.1
+tan(x) 1e-16 .. 9.22e+18 61.8
+
+It is possible with some effort to find very large arguments which
+give much degraded precision. For example, the integer number
+ 8227740058411162616.0
+is within about 10e-7 of a multiple of pi. To find the tan (for
+example) of this number to 64 bits precision it would be necessary to
+have a value of pi which had about 150 bits precision. The FPU
+emulator computes the result to about 42.6 bits precision (the correct
+result is about -9.739715e-8). On the other hand, an 80486 FPU returns
+0.01059, which in relative terms is hopelessly inaccurate.
+
+For arguments close to critical angles (which occur at multiples of
+pi/2) the emulator is more accurate than an 80486 FPU. For very large
+arguments, the emulator is far more accurate.
+
+
+Prior to version 1.20 of the emulator, the accuracy of the results for
+the transcendental functions (in their principal range) was not as
+good as the results from an 80486 FPU. From version 1.20, the accuracy
+has been considerably improved and these functions now give measured
+worst-case results which are better than the worst-case results given
+by an 80486 FPU.
+
+The following table gives the measured results for the emulator. The
+number of randomly selected arguments in each case is about half a
+million. The group of three columns gives the frequency of the given
+accuracy in number of times per million, thus the second of these
+columns shows that an accuracy of between 63.80 and 63.89 bits was
+found at a rate of 133 times per one million measurements for fsin.
+The results show that the fsin, fcos and fptan instructions return
+results which are in error (i.e. less accurate than the best possible
+result (which is 64 bits)) for about one per cent of all arguments
+between -pi/2 and +pi/2. The other instructions have a lower
+frequency of results which are in error. The last two columns give
+the worst accuracy which was found (in bits) and the approximate value
+of the argument which produced it.
+
+ frequency (per M)
+ ------------------- ---------------
+instr arg range # tests 63.7 63.8 63.9 worst at arg
+ bits bits bits bits
+----- ------------ ------- ---- ---- ----- ----- --------
+fsin (0,pi/2) 547756 0 133 10673 63.89 0.451317
+fcos (0,pi/2) 547563 0 126 10532 63.85 0.700801
+fptan (0,pi/2) 536274 11 267 10059 63.74 0.784876
+fpatan 4 quadrants 517087 0 8 1855 63.88 0.435121 (4q)
+fyl2x (0,20) 541861 0 0 1323 63.94 1.40923 (x)
+fyl2xp1 (-.293,.414) 520256 0 0 5678 63.93 0.408542 (x)
+f2xm1 (-1,1) 538847 4 481 6488 63.79 0.167709
+
+
+Tests performed on an 80486 FPU showed results of lower accuracy. The
+following table gives the results which were obtained with an AMD
+486DX2/66 (other tests indicate that an Intel 486DX produces
+identical results). The tests were basically the same as those used
+to measure the emulator (the values, being random, were in general not
+the same). The total number of tests for each instruction are given
+at the end of the table, in case each about 100k tests were performed.
+Another line of figures at the end of the table shows that most of the
+instructions return results which are in error for more than 10
+percent of the arguments tested.
+
+The numbers in the body of the table give the approx number of times a
+result of the given accuracy in bits (given in the left-most column)
+was obtained per one million arguments. For three of the instructions,
+two columns of results are given: * The second column for f2xm1 gives
+the number cases where the results of the first column were for a
+positive argument, this shows that this instruction gives better
+results for positive arguments than it does for negative. * In the
+cases of fcos and fptan, the first column gives the results when all
+cases where arguments greater than 1.5 were removed from the results
+given in the second column. Unlike the emulator, an 80486 FPU returns
+results of relatively poor accuracy for these instructions when the
+argument approaches pi/2. The table does not show those cases when the
+accuracy of the results were less than 62 bits, which occurs quite
+often for fsin and fptan when the argument approaches pi/2. This poor
+accuracy is discussed above in relation to the Turbo C "emulator", and
+the accuracy of the value of pi.
+
+
+bits f2xm1 f2xm1 fpatan fcos fcos fyl2x fyl2xp1 fsin fptan fptan
+62.0 0 0 0 0 437 0 0 0 0 925
+62.1 0 0 10 0 894 0 0 0 0 1023
+62.2 14 0 0 0 1033 0 0 0 0 945
+62.3 57 0 0 0 1202 0 0 0 0 1023
+62.4 385 0 0 10 1292 0 23 0 0 1178
+62.5 1140 0 0 119 1649 0 39 0 0 1149
+62.6 2037 0 0 189 1620 0 16 0 0 1169
+62.7 5086 14 0 646 2315 10 101 35 39 1402
+62.8 8818 86 0 984 3050 59 287 131 224 2036
+62.9 11340 1355 0 2126 4153 79 605 357 321 1948
+63.0 15557 4750 0 3319 5376 246 1281 862 808 2688
+63.1 20016 8288 0 4620 6628 511 2569 1723 1510 3302
+63.2 24945 11127 10 6588 8098 1120 4470 2968 2990 4724
+63.3 25686 12382 69 8774 10682 1906 6775 4482 5474 7236
+63.4 29219 14722 79 11109 12311 3094 9414 7259 8912 10587
+63.5 30458 14936 393 13802 15014 5874 12666 9609 13762 15262
+63.6 32439 16448 1277 17945 19028 10226 15537 14657 19158 20346
+63.7 35031 16805 4067 23003 23947 18910 20116 21333 25001 26209
+63.8 33251 15820 7673 24781 25675 24617 25354 24440 29433 30329
+63.9 33293 16833 18529 28318 29233 31267 31470 27748 29676 30601
+
+Per cent with error:
+ 30.9 3.2 18.5 9.8 13.1 11.6 17.4
+Total arguments tested:
+ 70194 70099 101784 100641 100641 101799 128853 114893 102675 102675
+
+
+------------------------- Contributors -------------------------------
+
+A number of people have contributed to the development of the
+emulator, often by just reporting bugs, sometimes with suggested
+fixes, and a few kind people have provided me with access in one way
+or another to an 80486 machine. Contributors include (to those people
+who I may have forgotten, please forgive me):
+
+Linus Torvalds
+Tommy.Thorn@daimi.aau.dk
+Andrew.Tridgell@anu.edu.au
+Nick Holloway, alfie@dcs.warwick.ac.uk
+Hermano Moura, moura@dcs.gla.ac.uk
+Jon Jagger, J.Jagger@scp.ac.uk
+Lennart Benschop
+Brian Gallew, geek+@CMU.EDU
+Thomas Staniszewski, ts3v+@andrew.cmu.edu
+Martin Howell, mph@plasma.apana.org.au
+M Saggaf, alsaggaf@athena.mit.edu
+Peter Barker, PETER@socpsy.sci.fau.edu
+tom@vlsivie.tuwien.ac.at
+Dan Russel, russed@rpi.edu
+Daniel Carosone, danielce@ee.mu.oz.au
+cae@jpmorgan.com
+Hamish Coleman, t933093@minyos.xx.rmit.oz.au
+Bruce Evans, bde@kralizec.zeta.org.au
+Timo Korvola, Timo.Korvola@hut.fi
+Rick Lyons, rick@razorback.brisnet.org.au
+Rick, jrs@world.std.com
+
+...and numerous others who responded to my request for help with
+a real 80486.
+
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | control_w.h |
+ | |
+ | Copyright (C) 1992,1993 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#ifndef _CONTROLW_H_
+#define _CONTROLW_H_
+
+#ifdef __ASSEMBLY__
+#define _Const_(x) $##x
+#else
+#define _Const_(x) x
+#endif
+
+#define CW_RC _Const_(0x0C00) /* rounding control */
+#define CW_PC _Const_(0x0300) /* precision control */
+
+#define CW_Precision Const_(0x0020) /* loss of precision mask */
+#define CW_Underflow Const_(0x0010) /* underflow mask */
+#define CW_Overflow Const_(0x0008) /* overflow mask */
+#define CW_ZeroDiv Const_(0x0004) /* divide by zero mask */
+#define CW_Denormal Const_(0x0002) /* denormalized operand mask */
+#define CW_Invalid Const_(0x0001) /* invalid operation mask */
+
+#define CW_Exceptions _Const_(0x003f) /* all masks */
+
+#define RC_RND _Const_(0x0000)
+#define RC_DOWN _Const_(0x0400)
+#define RC_UP _Const_(0x0800)
+#define RC_CHOP _Const_(0x0C00)
+
+/* p 15-5: Precision control bits affect only the following:
+ ADD, SUB(R), MUL, DIV(R), and SQRT */
+#define PR_24_BITS _Const_(0x000)
+#define PR_53_BITS _Const_(0x200)
+#define PR_64_BITS _Const_(0x300)
+#define PR_RESERVED_BITS _Const_(0x100)
+/* FULL_PRECISION simulates all exceptions masked */
+#define FULL_PRECISION (PR_64_BITS | RC_RND | 0x3f)
+
+#endif /* _CONTROLW_H_ */
--- /dev/null
+ .file "div_Xsig.S"
+/*---------------------------------------------------------------------------+
+ | div_Xsig.S |
+ | |
+ | Division subroutine for 96 bit quantities |
+ | |
+ | Copyright (C) 1994,1995 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | Divide the 96 bit quantity pointed to by a, by that pointed to by b, and |
+ | put the 96 bit result at the location d. |
+ | |
+ | The result may not be accurate to 96 bits. It is intended for use where |
+ | a result better than 64 bits is required. The result should usually be |
+ | good to at least 94 bits. |
+ | The returned result is actually divided by one half. This is done to |
+ | prevent overflow. |
+ | |
+ | .aaaaaaaaaaaaaa / .bbbbbbbbbbbbb -> .dddddddddddd |
+ | |
+ | void div_Xsig(Xsig *a, Xsig *b, Xsig *dest) |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "fpu_emu.h"
+
+
+#define XsigLL(x) (x)
+#define XsigL(x) 4(x)
+#define XsigH(x) 8(x)
+
+
+#ifndef NON_REENTRANT_FPU
+/*
+ Local storage on the stack:
+ Accumulator: FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0
+ */
+#define FPU_accum_3 -4(%ebp)
+#define FPU_accum_2 -8(%ebp)
+#define FPU_accum_1 -12(%ebp)
+#define FPU_accum_0 -16(%ebp)
+#define FPU_result_3 -20(%ebp)
+#define FPU_result_2 -24(%ebp)
+#define FPU_result_1 -28(%ebp)
+
+#else
+.data
+/*
+ Local storage in a static area:
+ Accumulator: FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0
+ */
+ .align 4,0
+FPU_accum_3:
+ .long 0
+FPU_accum_2:
+ .long 0
+FPU_accum_1:
+ .long 0
+FPU_accum_0:
+ .long 0
+FPU_result_3:
+ .long 0
+FPU_result_2:
+ .long 0
+FPU_result_1:
+ .long 0
+#endif /* NON_REENTRANT_FPU */
+
+
+.text
+ENTRY(div_Xsig)
+ pushl %ebp
+ movl %esp,%ebp
+#ifndef NON_REENTRANT_FPU
+ subl $28,%esp
+#endif /* NON_REENTRANT_FPU */
+
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi /* pointer to num */
+ movl PARAM2,%ebx /* pointer to denom */
+
+#ifdef PARANOID
+ testl $0x80000000, XsigH(%ebx) /* Divisor */
+ je L_bugged
+#endif /* PARANOID */
+
+
+/*---------------------------------------------------------------------------+
+ | Divide: Return arg1/arg2 to arg3. |
+ | |
+ | The maximum returned value is (ignoring exponents) |
+ | .ffffffff ffffffff |
+ | ------------------ = 1.ffffffff fffffffe |
+ | .80000000 00000000 |
+ | and the minimum is |
+ | .80000000 00000000 |
+ | ------------------ = .80000000 00000001 (rounded) |
+ | .ffffffff ffffffff |
+ | |
+ +---------------------------------------------------------------------------*/
+
+ /* Save extended dividend in local register */
+
+ /* Divide by 2 to prevent overflow */
+ clc
+ movl XsigH(%esi),%eax
+ rcrl %eax
+ movl %eax,FPU_accum_3
+ movl XsigL(%esi),%eax
+ rcrl %eax
+ movl %eax,FPU_accum_2
+ movl XsigLL(%esi),%eax
+ rcrl %eax
+ movl %eax,FPU_accum_1
+ movl $0,%eax
+ rcrl %eax
+ movl %eax,FPU_accum_0
+
+ movl FPU_accum_2,%eax /* Get the current num */
+ movl FPU_accum_3,%edx
+
+/*----------------------------------------------------------------------*/
+/* Initialization done.
+ Do the first 32 bits. */
+
+ /* We will divide by a number which is too large */
+ movl XsigH(%ebx),%ecx
+ addl $1,%ecx
+ jnc LFirst_div_not_1
+
+ /* here we need to divide by 100000000h,
+ i.e., no division at all.. */
+ mov %edx,%eax
+ jmp LFirst_div_done
+
+LFirst_div_not_1:
+ divl %ecx /* Divide the numerator by the augmented
+ denom ms dw */
+
+LFirst_div_done:
+ movl %eax,FPU_result_3 /* Put the result in the answer */
+
+ mull XsigH(%ebx) /* mul by the ms dw of the denom */
+
+ subl %eax,FPU_accum_2 /* Subtract from the num local reg */
+ sbbl %edx,FPU_accum_3
+
+ movl FPU_result_3,%eax /* Get the result back */
+ mull XsigL(%ebx) /* now mul the ls dw of the denom */
+
+ subl %eax,FPU_accum_1 /* Subtract from the num local reg */
+ sbbl %edx,FPU_accum_2
+ sbbl $0,FPU_accum_3
+ je LDo_2nd_32_bits /* Must check for non-zero result here */
+
+#ifdef PARANOID
+ jb L_bugged_1
+#endif /* PARANOID */
+
+ /* need to subtract another once of the denom */
+ incl FPU_result_3 /* Correct the answer */
+
+ movl XsigL(%ebx),%eax
+ movl XsigH(%ebx),%edx
+ subl %eax,FPU_accum_1 /* Subtract from the num local reg */
+ sbbl %edx,FPU_accum_2
+
+#ifdef PARANOID
+ sbbl $0,FPU_accum_3
+ jne L_bugged_1 /* Must check for non-zero result here */
+#endif /* PARANOID */
+
+/*----------------------------------------------------------------------*/
+/* Half of the main problem is done, there is just a reduced numerator
+ to handle now.
+ Work with the second 32 bits, FPU_accum_0 not used from now on */
+LDo_2nd_32_bits:
+ movl FPU_accum_2,%edx /* get the reduced num */
+ movl FPU_accum_1,%eax
+
+ /* need to check for possible subsequent overflow */
+ cmpl XsigH(%ebx),%edx
+ jb LDo_2nd_div
+ ja LPrevent_2nd_overflow
+
+ cmpl XsigL(%ebx),%eax
+ jb LDo_2nd_div
+
+LPrevent_2nd_overflow:
+/* The numerator is greater or equal, would cause overflow */
+ /* prevent overflow */
+ subl XsigL(%ebx),%eax
+ sbbl XsigH(%ebx),%edx
+ movl %edx,FPU_accum_2
+ movl %eax,FPU_accum_1
+
+ incl FPU_result_3 /* Reflect the subtraction in the answer */
+
+#ifdef PARANOID
+ je L_bugged_2 /* Can't bump the result to 1.0 */
+#endif /* PARANOID */
+
+LDo_2nd_div:
+ cmpl $0,%ecx /* augmented denom msw */
+ jnz LSecond_div_not_1
+
+ /* %ecx == 0, we are dividing by 1.0 */
+ mov %edx,%eax
+ jmp LSecond_div_done
+
+LSecond_div_not_1:
+ divl %ecx /* Divide the numerator by the denom ms dw */
+
+LSecond_div_done:
+ movl %eax,FPU_result_2 /* Put the result in the answer */
+
+ mull XsigH(%ebx) /* mul by the ms dw of the denom */
+
+ subl %eax,FPU_accum_1 /* Subtract from the num local reg */
+ sbbl %edx,FPU_accum_2
+
+#ifdef PARANOID
+ jc L_bugged_2
+#endif /* PARANOID */
+
+ movl FPU_result_2,%eax /* Get the result back */
+ mull XsigL(%ebx) /* now mul the ls dw of the denom */
+
+ subl %eax,FPU_accum_0 /* Subtract from the num local reg */
+ sbbl %edx,FPU_accum_1 /* Subtract from the num local reg */
+ sbbl $0,FPU_accum_2
+
+#ifdef PARANOID
+ jc L_bugged_2
+#endif /* PARANOID */
+
+ jz LDo_3rd_32_bits
+
+#ifdef PARANOID
+ cmpl $1,FPU_accum_2
+ jne L_bugged_2
+#endif /* PARANOID */
+
+ /* need to subtract another once of the denom */
+ movl XsigL(%ebx),%eax
+ movl XsigH(%ebx),%edx
+ subl %eax,FPU_accum_0 /* Subtract from the num local reg */
+ sbbl %edx,FPU_accum_1
+ sbbl $0,FPU_accum_2
+
+#ifdef PARANOID
+ jc L_bugged_2
+ jne L_bugged_2
+#endif /* PARANOID */
+
+ addl $1,FPU_result_2 /* Correct the answer */
+ adcl $0,FPU_result_3
+
+#ifdef PARANOID
+ jc L_bugged_2 /* Must check for non-zero result here */
+#endif /* PARANOID */
+
+/*----------------------------------------------------------------------*/
+/* The division is essentially finished here, we just need to perform
+ tidying operations.
+ Deal with the 3rd 32 bits */
+LDo_3rd_32_bits:
+ /* We use an approximation for the third 32 bits.
+ To take account of the 3rd 32 bits of the divisor
+ (call them del), we subtract del * (a/b) */
+
+ movl FPU_result_3,%eax /* a/b */
+ mull XsigLL(%ebx) /* del */
+
+ subl %edx,FPU_accum_1
+
+ /* A borrow indicates that the result is negative */
+ jnb LTest_over
+
+ movl XsigH(%ebx),%edx
+ addl %edx,FPU_accum_1
+
+ subl $1,FPU_result_2 /* Adjust the answer */
+ sbbl $0,FPU_result_3
+
+ /* The above addition might not have been enough, check again. */
+ movl FPU_accum_1,%edx /* get the reduced num */
+ cmpl XsigH(%ebx),%edx /* denom */
+ jb LDo_3rd_div
+
+ movl XsigH(%ebx),%edx
+ addl %edx,FPU_accum_1
+
+ subl $1,FPU_result_2 /* Adjust the answer */
+ sbbl $0,FPU_result_3
+ jmp LDo_3rd_div
+
+LTest_over:
+ movl FPU_accum_1,%edx /* get the reduced num */
+
+ /* need to check for possible subsequent overflow */
+ cmpl XsigH(%ebx),%edx /* denom */
+ jb LDo_3rd_div
+
+ /* prevent overflow */
+ subl XsigH(%ebx),%edx
+ movl %edx,FPU_accum_1
+
+ addl $1,FPU_result_2 /* Reflect the subtraction in the answer */
+ adcl $0,FPU_result_3
+
+LDo_3rd_div:
+ movl FPU_accum_0,%eax
+ movl FPU_accum_1,%edx
+ divl XsigH(%ebx)
+
+ movl %eax,FPU_result_1 /* Rough estimate of third word */
+
+ movl PARAM3,%esi /* pointer to answer */
+
+ movl FPU_result_1,%eax
+ movl %eax,XsigLL(%esi)
+ movl FPU_result_2,%eax
+ movl %eax,XsigL(%esi)
+ movl FPU_result_3,%eax
+ movl %eax,XsigH(%esi)
+
+L_exit:
+ popl %ebx
+ popl %edi
+ popl %esi
+
+ leave
+ ret
+
+
+#ifdef PARANOID
+/* The logic is wrong if we got here */
+L_bugged:
+ pushl EX_INTERNAL|0x240
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_bugged_1:
+ pushl EX_INTERNAL|0x241
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_bugged_2:
+ pushl EX_INTERNAL|0x242
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+#endif /* PARANOID */
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | div_Xsig.S |
+ | |
+ | Division subroutine for 96 bit quantities |
+ | |
+ | Copyright (C) 1994,1995,1999 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@melbpc.org.au |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | Divide the 96 bit quantity pointed to by a, by that pointed to by b, and |
+ | put the 96 bit result at the location d. |
+ | |
+ | The result may not be accurate to 96 bits. It is intended for use where |
+ | a result better than 64 bits is required. The result should usually be |
+ | good to at least 94 bits. |
+ | The returned result is actually divided by one half. This is done to |
+ | prevent overflow. |
+ | |
+ | .aaaaaaaaaaaaaa / .bbbbbbbbbbbbb -> .dddddddddddd |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "fpu_emu.h"
+#include "poly.h"
+
+
+void div_Xsig(const Xsig *aa, const Xsig *b, Xsig *dest)
+{
+ Xsig a = *aa, xpr, result;
+ u32 prodh, prodl, den, wd;
+ u64 num, prod;
+
+#ifdef PARANOID
+ if ( (b->msw & 0x80000000) == 0 )
+ {
+ EXCEPTION(EX_INTERNAL|0x240);
+ return;
+ }
+#endif
+
+ /* Shift a right */
+ a.lsw >>= 1;
+ if ( a.midw & 1 )
+ a.lsw |= 0x80000000;
+ a.midw >>= 1;
+ if ( a.msw & 1 )
+ a.midw |= 0x80000000;
+ a.msw >>= 1;
+
+ num = a.msw;
+ num <<= 32;
+ num |= a.midw;
+
+ den = b->msw + 1;
+ if ( den )
+ {
+ result.msw = num / den;
+ }
+ else
+ result.msw = a.msw;
+
+ xpr = *b;
+ mul32_Xsig(&xpr, result.msw);
+ a.msw -= xpr.msw;
+ wd = a.midw;
+ a.midw -= xpr.midw;
+ if ( a.midw > wd )
+ a.msw --;
+ wd = a.lsw;
+ a.lsw -= xpr.lsw;
+ if ( a.lsw > wd )
+ {
+ a.midw --;
+ if ( a.midw == 0xffffffff )
+ a.msw --;
+ }
+
+#ifdef PARANOID
+ if ( a.msw > 1 )
+ {
+ EXCEPTION(EX_INTERNAL|0x241);
+ }
+#endif
+
+ while ( (a.msw != 0) || (a.midw > b->msw) )
+ {
+ wd = a.midw;
+ a.midw -= b->msw;
+ if ( a.midw > wd )
+ a.msw --;
+ wd = a.lsw;
+ a.lsw -= b->midw;
+ if ( a.lsw > wd )
+ {
+ a.midw --;
+ if ( a.midw == 0xffffffff )
+ a.msw --;
+ }
+ result.msw ++;
+ }
+
+ /* Whew! result.msw is now done. */
+
+ num = a.midw;
+ num <<= 32;
+ num |= a.lsw;
+
+ if ( den )
+ {
+ result.midw = num / den;
+ }
+ else
+ result.midw = a.midw;
+
+ prod = result.midw;
+ prod *= b->msw;
+ a.midw -= prod >> 32;
+ prodl = prod;
+ wd = a.lsw;
+ a.lsw -= prodl;
+ if ( a.lsw > wd )
+ a.midw --;
+
+ prod = result.midw;
+ prod *= b->midw;
+ prodh = prod >> 32;
+ wd = a.lsw;
+ a.lsw -= prodh;
+ if ( a.lsw > wd )
+ a.midw --;
+
+#ifdef PARANOID
+ if ( a.midw > 1 )
+ {
+ EXCEPTION(EX_INTERNAL|0x242);
+ }
+#endif
+
+ while ( (a.midw != 0) || (a.lsw > b->msw) )
+ {
+ wd = a.lsw;
+ a.lsw -= b->msw;
+ if ( a.lsw > wd )
+ a.midw --;
+ result.midw ++;
+ }
+
+
+ /* Now result.msw is done, the lsw is next... */
+
+ num = a.lsw;
+ num <<= 32;
+
+ if ( den )
+ {
+ result.lsw = num / den;
+ }
+ else
+ result.lsw = a.lsw;
+
+ prod = result.lsw;
+ prod *= b->msw;
+ a.lsw -= prod >> 32;
+
+#ifdef PARANOID
+ if ( a.lsw > 2 )
+ {
+ EXCEPTION(EX_INTERNAL|0x243);
+ }
+#endif
+
+ result.lsw -= a.lsw;
+
+ /* Hey! we're done. */
+
+ *dest = result;
+
+}
+
--- /dev/null
+ .file "div_small.S"
+/*---------------------------------------------------------------------------+
+ | div_small.S |
+ | |
+ | Divide a 64 bit integer by a 32 bit integer & return remainder. |
+ | |
+ | Copyright (C) 1992,1995 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | unsigned long FPU_div_small(unsigned long long *x, unsigned long y) |
+ +---------------------------------------------------------------------------*/
+
+#include "fpu_emu.h"
+
+.text
+ENTRY(FPU_div_small)
+ pushl %ebp
+ movl %esp,%ebp
+
+ pushl %esi
+
+ movl PARAM1,%esi /* pointer to num */
+ movl PARAM2,%ecx /* The denominator */
+
+ movl 4(%esi),%eax /* Get the current num msw */
+ xorl %edx,%edx
+ divl %ecx
+
+ movl %eax,4(%esi)
+
+ movl (%esi),%eax /* Get the num lsw */
+ divl %ecx
+
+ movl %eax,(%esi)
+
+ movl %edx,%eax /* Return the remainder in eax */
+
+ popl %esi
+
+ leave
+ ret
+
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | div_small.S |
+ | |
+ | Divide a 64 bit integer by a 32 bit integer & return remainder. |
+ | |
+ | Copyright (C) 1992,1995,1999 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@melbpc.org.au |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+
+#include "fpu_emu.h"
+
+u32 FPU_div_small(u64 *x, u32 y)
+{
+ u32 retval;
+
+ retval = *x % y;
+
+ *x /= y;
+
+ return retval;
+}
+
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | errors.c |
+ | |
+ | The error handling functions for wm-FPU-emu |
+ | |
+ | Copyright (C) 1992,1993,1994,1996 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@jacobi.maths.monash.edu.au |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | Note: |
+ | The file contains code which accesses user memory. |
+ | Emulator static data may change when user memory is accessed, due to |
+ | other processes using the emulator while swapping is in progress. |
+ +---------------------------------------------------------------------------*/
+
+#include <linux/signal.h>
+#include <asm/uaccess.h>
+#include <stdio.h>
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "exception.h"
+#include "status_w.h"
+#include "control_w.h"
+#include "reg_constant.h"
+#include "version.h"
+
+/* */
+#undef PRINT_MESSAGES
+/* */
+
+
+#ifndef USE_WITH_CPU_SIM
+void Un_impl(void)
+{
+ u_char byte1, FPU_modrm;
+ u32 address = FPU_ORIG_EIP;
+
+ RE_ENTRANT_CHECK_OFF;
+ /* No need to verify_area(), we have previously fetched these bytes. */
+ printk("Unimplemented FPU Opcode at eip=%p : ", (void *) address);
+ if ( FPU_CS == __USER_CS )
+ {
+ while ( 1 )
+ {
+ FPU_get_user(byte1, (u_char *) address);
+ if ( (byte1 & 0xf8) == 0xd8 ) break;
+ printk("[%02x]", byte1);
+ address++;
+ }
+ printk("%02x ", byte1);
+ FPU_get_user(FPU_modrm, 1 + (u_char *) address);
+
+ if (FPU_modrm >= 0300)
+ printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
+ else
+ printk("/%d\n", (FPU_modrm >> 3) & 7);
+ }
+ else
+ {
+ printk("cs selector = %04x\n", FPU_CS);
+ }
+
+ RE_ENTRANT_CHECK_ON;
+
+ EXCEPTION(EX_Invalid);
+
+}
+#endif
+
+
+/*
+ Called for opcodes which are illegal and which are known to result in a
+ SIGILL with a real 80486.
+ */
+void FPU_illegal(void)
+{
+ math_abort(FPU_info,SIGILL);
+}
+
+
+
+#ifndef USE_WITH_CPU_SIM
+void FPU_printall(void)
+{
+ int i;
+ static const char *tag_desc[] = { "Valid", "Zero", "ERROR", "Empty",
+ "DeNorm", "Inf", "NaN" };
+ u_char byte1, FPU_modrm;
+ u32 address = FPU_ORIG_EIP;
+
+ RE_ENTRANT_CHECK_OFF;
+ /* No need to verify_area(), we have previously fetched these bytes. */
+ printk("At %p:", (void *) address);
+ if ( FPU_CS == __USER_CS )
+ {
+#define MAX_PRINTED_BYTES 20
+ for ( i = 0; i < MAX_PRINTED_BYTES; i++ )
+ {
+ FPU_get_user(byte1, (u_char *) address);
+ if ( (byte1 & 0xf8) == 0xd8 )
+ {
+ printk(" %02x", byte1);
+ break;
+ }
+ printk(" [%02x]", byte1);
+ address++;
+ }
+ if ( i == MAX_PRINTED_BYTES )
+ printk(" [more..]\n");
+ else
+ {
+ FPU_get_user(FPU_modrm, 1 + (u_char *) address);
+
+ if (FPU_modrm >= 0300)
+ printk(" %02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
+ else
+ printk(" /%d, mod=%d rm=%d\n",
+ (FPU_modrm >> 3) & 7, (FPU_modrm >> 6) & 3, FPU_modrm & 7);
+ }
+ }
+ else
+ {
+ printk("%04x\n", FPU_CS);
+ }
+
+ partial_status = status_word();
+
+
+ printk(" SW: b=%d st=%ld es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n",
+ partial_status & 0x8000 ? 1 : 0, /* busy */
+ (partial_status & 0x3800) >> 11, /* stack top pointer */
+ partial_status & 0x80 ? 1 : 0, /* Error summary status */
+ partial_status & 0x40 ? 1 : 0, /* Stack flag */
+ partial_status & SW_C3?1:0, partial_status & SW_C2?1:0, /* cc */
+ partial_status & SW_C1?1:0, partial_status & SW_C0?1:0, /* cc */
+ partial_status & SW_Precision?1:0, partial_status & SW_Underflow?1:0,
+ partial_status & SW_Overflow?1:0, partial_status & SW_Zero_Div?1:0,
+ partial_status & SW_Denorm_Op?1:0, partial_status & SW_Invalid?1:0);
+
+printk(" CW: ic=%d rc=%ld%ld pc=%ld%ld iem=%d ef=%d%d%d%d%d%d\n",
+ control_word & 0x1000 ? 1 : 0,
+ (control_word & 0x800) >> 11, (control_word & 0x400) >> 10,
+ (control_word & 0x200) >> 9, (control_word & 0x100) >> 8,
+ control_word & 0x80 ? 1 : 0,
+ control_word & SW_Precision?1:0, control_word & SW_Underflow?1:0,
+ control_word & SW_Overflow?1:0, control_word & SW_Zero_Div?1:0,
+ control_word & SW_Denorm_Op?1:0, control_word & SW_Invalid?1:0);
+
+ for ( i = 0; i < 8; i++ )
+ {
+ FPU_REG *r = &st(i);
+ u_char tagi = FPU_gettagi(i);
+ switch (tagi)
+ {
+ case TAG_Empty:
+ continue;
+ break;
+ case TAG_Zero:
+ case TAG_Special:
+ tagi = FPU_Special(r);
+ case TAG_Valid:
+ printk("st(%d) %c .%04lx %04lx %04lx %04lx e%+-6d ", i,
+ getsign(r) ? '-' : '+',
+ (s32)(r->sigh >> 16),
+ (s32)(r->sigh & 0xFFFF),
+ (s32)(r->sigl >> 16),
+ (s32)(r->sigl & 0xFFFF),
+ exponent(r) - EXP_BIAS + 1);
+ break;
+ default:
+ printk("Whoops! Error in errors.c: tag%d is %d ", i, tagi);
+ continue;
+ break;
+ }
+ printk("%s\n", tag_desc[(int) (unsigned) tagi]);
+ }
+
+ RE_ENTRANT_CHECK_ON;
+
+}
+#endif
+
+static struct {
+ int type;
+ const char *name;
+} exception_names[] = {
+ { EX_StackOver, "stack overflow" },
+ { EX_StackUnder, "stack underflow" },
+ { EX_Precision, "loss of precision" },
+ { EX_Underflow, "underflow" },
+ { EX_Overflow, "overflow" },
+ { EX_ZeroDiv, "divide by zero" },
+ { EX_Denormal, "denormalized operand" },
+ { EX_Invalid, "invalid operation" },
+ { EX_INTERNAL, "INTERNAL BUG in "FPU_VERSION },
+ { 0, NULL }
+};
+
+/*
+ EX_INTERNAL is always given with a code which indicates where the
+ error was detected.
+
+ Internal error types:
+ 0x14 in fpu_etc.c
+ 0x1nn in a *.c file:
+ 0x101 in reg_add_sub.c
+ 0x102 in reg_mul.c
+ 0x104 in poly_atan.c
+ 0x105 in reg_mul.c
+ 0x107 in fpu_trig.c
+ 0x108 in reg_compare.c
+ 0x109 in reg_compare.c
+ 0x110 in reg_add_sub.c
+ 0x111 in fpe_entry.c
+ 0x112 in fpu_trig.c
+ 0x113 in errors.c
+ 0x115 in fpu_trig.c
+ 0x116 in fpu_trig.c
+ 0x117 in fpu_trig.c
+ 0x118 in fpu_trig.c
+ 0x119 in fpu_trig.c
+ 0x120 in poly_atan.c
+ 0x121 in reg_compare.c
+ 0x122 in reg_compare.c
+ 0x123 in reg_compare.c
+ 0x125 in fpu_trig.c
+ 0x126 in fpu_entry.c
+ 0x127 in poly_2xm1.c
+ 0x128 in fpu_entry.c
+ 0x129 in fpu_entry.c
+ 0x130 in get_address.c
+ 0x131 in get_address.c
+ 0x132 in get_address.c
+ 0x133 in get_address.c
+ 0x140 in load_store.c
+ 0x141 in load_store.c
+ 0x150 in poly_sin.c
+ 0x151 in poly_sin.c
+ 0x160 in reg_ld_str.c
+ 0x161 in reg_ld_str.c
+ 0x162 in reg_ld_str.c
+ 0x163 in reg_ld_str.c
+ 0x164 in reg_ld_str.c
+ 0x170 in fpu_tags.c
+ 0x171 in fpu_tags.c
+ 0x172 in fpu_tags.c
+ 0x180 in reg_convert.c
+ 0x2nn in an *.S file:
+ 0x201 in reg_u_add.S
+ 0x202 in reg_u_div.S
+ 0x203 in reg_u_div.S
+ 0x204 in reg_u_div.S
+ 0x205 in reg_u_mul.S
+ 0x206 in reg_u_sub.S
+ 0x207 in wm_sqrt.S
+ 0x208 in reg_div.S
+ 0x209 in reg_u_sub.S
+ 0x210 in reg_u_sub.S
+ 0x211 in reg_u_sub.S
+ 0x212 in reg_u_sub.S
+ 0x213 in wm_sqrt.S
+ 0x214 in wm_sqrt.S
+ 0x215 in wm_sqrt.S
+ 0x220 in reg_norm.S
+ 0x221 in reg_norm.S
+ 0x230 in reg_round.S
+ 0x231 in reg_round.S
+ 0x232 in reg_round.S
+ 0x233 in reg_round.S
+ 0x234 in reg_round.S
+ 0x235 in reg_round.S
+ 0x236 in reg_round.S
+ 0x240 in div_Xsig.S
+ 0x241 in div_Xsig.S
+ 0x242 in div_Xsig.S
+ */
+
+void FPU_exception(int n)
+{
+ int i, int_type;
+
+ int_type = 0; /* Needed only to stop compiler warnings */
+ if ( n & EX_INTERNAL )
+ {
+ int_type = n - EX_INTERNAL;
+ n = EX_INTERNAL;
+ /* Set lots of exception bits! */
+ partial_status |= (SW_Exc_Mask | SW_Summary | SW_Backward);
+ }
+ else
+ {
+ /* Extract only the bits which we use to set the status word */
+ n &= (SW_Exc_Mask);
+ /* Set the corresponding exception bit */
+ partial_status |= n;
+ /* Set summary bits iff exception isn't masked */
+ if ( partial_status & ~control_word & CW_Exceptions )
+ partial_status |= (SW_Summary | SW_Backward);
+ if ( n & (SW_Stack_Fault | EX_Precision) )
+ {
+ if ( !(n & SW_C1) )
+ /* This bit distinguishes over- from underflow for a stack fault,
+ and roundup from round-down for precision loss. */
+ partial_status &= ~SW_C1;
+ }
+ }
+
+ RE_ENTRANT_CHECK_OFF;
+ if ( (~control_word & n & CW_Exceptions) || (n == EX_INTERNAL) )
+ {
+#ifdef PRINT_MESSAGES
+ /* My message from the sponsor */
+ printk(FPU_VERSION" "__DATE__" (C) W. Metzenthen.\n");
+#endif /* PRINT_MESSAGES */
+
+ /* Get a name string for error reporting */
+ for (i=0; exception_names[i].type; i++)
+ if ( (exception_names[i].type & n) == exception_names[i].type )
+ break;
+
+ if (exception_names[i].type)
+ {
+#ifdef PRINT_MESSAGES
+ printk("FP Exception: %s!\n", exception_names[i].name);
+#endif /* PRINT_MESSAGES */
+ }
+ else
+ printk("FPU emulator: Unknown Exception: 0x%04x!\n", n);
+
+ if ( n == EX_INTERNAL )
+ {
+ printk("FPU emulator: Internal error type 0x%04x\n", int_type);
+ FPU_printall();
+ }
+#ifdef PRINT_MESSAGES
+ else
+ FPU_printall();
+#endif /* PRINT_MESSAGES */
+
+ /*
+ * The 80486 generates an interrupt on the next non-control FPU
+ * instruction. So we need some means of flagging it.
+ * We use the ES (Error Summary) bit for this.
+ */
+ }
+ RE_ENTRANT_CHECK_ON;
+
+
+}
+
+
+/* Real operation attempted on a NaN. */
+/* Returns < 0 if the exception is unmasked */
+int real_1op_NaN(FPU_REG *a)
+{
+ int signalling, isNaN;
+
+ isNaN = (exponent(a) == EXP_OVER) && (a->sigh & 0x80000000);
+
+ /* The default result for the case of two "equal" NaNs (signs may
+ differ) is chosen to reproduce 80486 behaviour */
+ signalling = isNaN && !(a->sigh & 0x40000000);
+
+ if ( !signalling )
+ {
+ if ( !isNaN ) /* pseudo-NaN, or other unsupported? */
+ {
+ if ( control_word & CW_Invalid )
+ {
+ /* Masked response */
+ reg_copy(&CONST_QNaN, a);
+ }
+ EXCEPTION(EX_Invalid);
+ return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
+ }
+ return TAG_Special;
+ }
+
+ if ( control_word & CW_Invalid )
+ {
+ /* The masked response */
+ if ( !(a->sigh & 0x80000000) ) /* pseudo-NaN ? */
+ {
+ reg_copy(&CONST_QNaN, a);
+ }
+ /* ensure a Quiet NaN */
+ a->sigh |= 0x40000000;
+ }
+
+ EXCEPTION(EX_Invalid);
+
+ return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
+}
+
+
+/* Real operation attempted on two operands, one a NaN. */
+/* Returns < 0 if the exception is unmasked */
+int real_2op_NaN(FPU_REG const *b, u_char tagb,
+ int deststnr,
+ FPU_REG const *defaultNaN)
+{
+ FPU_REG *dest = &st(deststnr);
+ FPU_REG const *a = dest;
+ u_char taga = FPU_gettagi(deststnr);
+ FPU_REG const *x;
+ int signalling, unsupported;
+
+ if ( taga == TAG_Special )
+ taga = FPU_Special(a);
+ if ( tagb == TAG_Special )
+ tagb = FPU_Special(b);
+
+ /* TW_NaN is also used for unsupported data types. */
+ unsupported = ((taga == TW_NaN)
+ && !((exponent(a) == EXP_OVER) && (a->sigh & 0x80000000)))
+ || ((tagb == TW_NaN)
+ && !((exponent(b) == EXP_OVER) && (b->sigh & 0x80000000)));
+ if ( unsupported )
+ {
+ if ( control_word & CW_Invalid )
+ {
+ /* Masked response */
+ FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr);
+ }
+ EXCEPTION(EX_Invalid);
+ return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
+ }
+
+ if (taga == TW_NaN)
+ {
+ x = a;
+ if (tagb == TW_NaN)
+ {
+ signalling = !(a->sigh & b->sigh & 0x40000000);
+ if ( significand(b) > significand(a) )
+ x = b;
+ else if ( significand(b) == significand(a) )
+ {
+ /* The default result for the case of two "equal" NaNs (signs may
+ differ) is chosen to reproduce 80486 behaviour */
+ x = defaultNaN;
+ }
+ }
+ else
+ {
+ /* return the quiet version of the NaN in a */
+ signalling = !(a->sigh & 0x40000000);
+ }
+ }
+ else
+#ifdef PARANOID
+ if (tagb == TW_NaN)
+#endif /* PARANOID */
+ {
+ signalling = !(b->sigh & 0x40000000);
+ x = b;
+ }
+#ifdef PARANOID
+ else
+ {
+ signalling = 0;
+ EXCEPTION(EX_INTERNAL|0x113);
+ x = &CONST_QNaN;
+ }
+#endif /* PARANOID */
+
+ if ( (!signalling) || (control_word & CW_Invalid) )
+ {
+ if ( ! x )
+ x = b;
+
+ if ( !(x->sigh & 0x80000000) ) /* pseudo-NaN ? */
+ x = &CONST_QNaN;
+
+ FPU_copy_to_regi(x, TAG_Special, deststnr);
+
+ if ( !signalling )
+ return TAG_Special;
+
+ /* ensure a Quiet NaN */
+ dest->sigh |= 0x40000000;
+ }
+
+ EXCEPTION(EX_Invalid);
+
+ return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
+}
+
+
+/* Invalid arith operation on Valid registers */
+/* Returns < 0 if the exception is unmasked */
+asmlinkage int arith_invalid(int deststnr)
+{
+
+ EXCEPTION(EX_Invalid);
+
+ if ( control_word & CW_Invalid )
+ {
+ /* The masked response */
+ FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr);
+ }
+
+ return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Valid;
+
+}
+
+
+/* Divide a finite number by zero */
+asmlinkage int FPU_divide_by_zero(int deststnr, u_char sign)
+{
+ FPU_REG *dest = &st(deststnr);
+ int tag = TAG_Valid;
+
+ if ( control_word & CW_ZeroDiv )
+ {
+ /* The masked response */
+ FPU_copy_to_regi(&CONST_INF, TAG_Special, deststnr);
+ setsign(dest, sign);
+ tag = TAG_Special;
+ }
+
+ EXCEPTION(EX_ZeroDiv);
+
+ return (!(control_word & CW_ZeroDiv) ? FPU_Exception : 0) | tag;
+
+}
+
+
+/* This may be called often, so keep it lean */
+int set_precision_flag(int flags)
+{
+ if ( control_word & CW_Precision )
+ {
+ partial_status &= ~(SW_C1 & flags);
+ partial_status |= flags; /* The masked response */
+ return 0;
+ }
+ else
+ {
+ EXCEPTION(flags);
+ return 1;
+ }
+}
+
+
+/* This may be called often, so keep it lean */
+asmlinkage void set_precision_flag_up(void)
+{
+ if ( control_word & CW_Precision )
+ partial_status |= (SW_Precision | SW_C1); /* The masked response */
+ else
+ EXCEPTION(EX_Precision | SW_C1);
+}
+
+
+/* This may be called often, so keep it lean */
+asmlinkage void set_precision_flag_down(void)
+{
+ if ( control_word & CW_Precision )
+ { /* The masked response */
+ partial_status &= ~SW_C1;
+ partial_status |= SW_Precision;
+ }
+ else
+ EXCEPTION(EX_Precision);
+}
+
+
+asmlinkage int denormal_operand(void)
+{
+ if ( control_word & CW_Denormal )
+ { /* The masked response */
+ partial_status |= SW_Denorm_Op;
+ return TAG_Special;
+ }
+ else
+ {
+ EXCEPTION(EX_Denormal);
+ return TAG_Special | FPU_Exception;
+ }
+}
+
+
+asmlinkage int arith_overflow(FPU_REG *dest)
+{
+ int tag = TAG_Valid;
+
+ if ( control_word & CW_Overflow )
+ {
+ /* The masked response */
+ reg_copy(&CONST_INF, dest);
+ tag = TAG_Special;
+ }
+ else
+ {
+ /* Subtract the magic number from the exponent */
+ addexponent(dest, (-3 * (1 << 13)));
+ }
+
+ EXCEPTION(EX_Overflow);
+ if ( control_word & CW_Overflow )
+ {
+ /* The overflow exception is masked. */
+ /* By definition, precision is lost.
+ The roundup bit (C1) is also set because we have
+ "rounded" upwards to Infinity. */
+ EXCEPTION(EX_Precision | SW_C1);
+ return tag;
+ }
+
+ return tag;
+
+}
+
+
+asmlinkage int arith_round_overflow(FPU_REG *dest, u8 sign)
+{
+ int tag = TAG_Valid;
+ int largest;
+
+ if ( control_word & CW_Overflow )
+ {
+ /* The masked response */
+ /* The response here depends upon the rounding mode */
+ switch ( control_word & CW_RC )
+ {
+ case RC_CHOP: /* Truncate */
+ largest = 1;
+ break;
+ case RC_UP: /* Towards +infinity */
+ largest = (sign == SIGN_NEG);
+ break;
+ case RC_DOWN: /* Towards -infinity */
+ largest = (sign == SIGN_POS);
+ break;
+ default:
+ largest = 0;
+ break;
+ }
+ if ( ! largest )
+ {
+ reg_copy(&CONST_INF, dest);
+ tag = TAG_Special;
+ }
+ else
+ {
+ dest->exp = EXTENDED_Ebias+EXP_OVER-1;
+ switch ( control_word & CW_PC )
+ {
+ case 01:
+ case PR_64_BITS:
+ significand(dest) = BX_CONST64(0xffffffffffffffff);
+ break;
+ case PR_53_BITS:
+ significand(dest) = BX_CONST64(0xfffffffffffff800);
+ break;
+ case PR_24_BITS:
+ significand(dest) = BX_CONST64(0xffffff0000000000);
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* Subtract the magic number from the exponent */
+ addexponent(dest, (-3 * (1 << 13)));
+ largest = 0;
+ }
+
+ EXCEPTION(EX_Overflow);
+ if ( control_word & CW_Overflow )
+ {
+ /* The overflow exception is masked. */
+ if ( largest )
+ {
+ EXCEPTION(EX_Precision);
+ }
+ else
+ {
+ /* By definition, precision is lost.
+ The roundup bit (C1) is also set because we have
+ "rounded" upwards to Infinity. */
+ EXCEPTION(EX_Precision | SW_C1);
+ }
+ return tag;
+ }
+
+ return tag;
+
+}
+
+
+asmlinkage int arith_underflow(FPU_REG *dest)
+{
+ int tag = TAG_Valid;
+
+ if ( control_word & CW_Underflow )
+ {
+ /* The masked response */
+ if ( exponent16(dest) <= EXP_UNDER - 63 )
+ {
+ reg_copy(&CONST_Z, dest);
+ partial_status &= ~SW_C1; /* Round down. */
+ tag = TAG_Zero;
+ }
+ else
+ {
+ stdexp(dest);
+ }
+ }
+ else
+ {
+ /* Add the magic number to the exponent. */
+ addexponent(dest, (3 * (1 << 13)) + EXTENDED_Ebias);
+ }
+
+ EXCEPTION(EX_Underflow);
+ if ( control_word & CW_Underflow )
+ {
+ /* The underflow exception is masked. */
+ EXCEPTION(EX_Precision);
+ return tag;
+ }
+
+ return tag;
+
+}
+
+
+void FPU_stack_overflow(void)
+{
+
+ if ( control_word & CW_Invalid )
+ {
+ /* The masked response */
+ top--;
+ FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
+ }
+
+ EXCEPTION(EX_StackOver);
+
+ return;
+
+}
+
+
+void FPU_stack_underflow(void)
+{
+
+ if ( control_word & CW_Invalid )
+ {
+ /* The masked response */
+ FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
+ }
+
+ EXCEPTION(EX_StackUnder);
+
+ return;
+
+}
+
+
+void FPU_stack_underflow_i(int i)
+{
+
+ if ( control_word & CW_Invalid )
+ {
+ /* The masked response */
+ FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i);
+ }
+
+ EXCEPTION(EX_StackUnder);
+
+ return;
+
+}
+
+
+void FPU_stack_underflow_pop(int i)
+{
+
+ if ( control_word & CW_Invalid )
+ {
+ /* The masked response */
+ FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i);
+ FPU_pop();
+ }
+
+ EXCEPTION(EX_StackUnder);
+
+ return;
+
+}
+
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | exception.h |
+ | |
+ | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#ifndef _EXCEPTION_H_
+#define _EXCEPTION_H_
+
+
+#ifdef __ASSEMBLY__
+#define Const_(x) $##x
+#else
+#define Const_(x) x
+#endif
+
+#ifndef SW_C1
+#include "fpu_emu.h"
+#endif /* SW_C1 */
+
+#define FPU_BUSY Const_(0x8000) /* FPU busy bit (8087 compatibility) */
+#define EX_ErrorSummary Const_(0x0080) /* Error summary status */
+/* Special exceptions: */
+#define EX_INTERNAL Const_(0x8000) /* Internal error in wm-FPU-emu */
+#define EX_StackOver Const_(0x0041|SW_C1) /* stack overflow */
+#define EX_StackUnder Const_(0x0041) /* stack underflow */
+/* Exception flags: */
+#define EX_Precision Const_(0x0020) /* loss of precision */
+#define EX_Underflow Const_(0x0010) /* underflow */
+#define EX_Overflow Const_(0x0008) /* overflow */
+#define EX_ZeroDiv Const_(0x0004) /* divide by zero */
+#define EX_Denormal Const_(0x0002) /* denormalized operand */
+#define EX_Invalid Const_(0x0001) /* invalid operation */
+
+
+#define PRECISION_LOST_UP Const_((EX_Precision | SW_C1))
+#define PRECISION_LOST_DOWN Const_(EX_Precision)
+
+
+#ifndef __ASSEMBLY__
+
+#define EXCEPTION(x) FPU_exception(x)
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _EXCEPTION_H_ */
--- /dev/null
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+#include "bochs.h"
+
+#define LOG_THIS genlog->
+
+// Nomenclature used to signify argument types
+//
+// Es = single real
+// El = double real
+// Ea = 14/28 bytes 98/108b bytes (FRSTOR,FSAVE)???
+// Ew = word integer (2 bytes)
+// Ed = dword integer (4 bytes) (short int)
+// Et = extended real
+// Eb = packed BCD
+// Eq = quadword integer (8 bytes) (long integer)
+
+
+
+ void
+BX_CPU_C::ESC0(BxInstruction_t *i)
+{
+ if ( BX_CPU_THIS_PTR cr0.em || BX_CPU_THIS_PTR cr0.ts ) {
+ exception(BX_NM_EXCEPTION, 0, 0);
+ }
+#if BX_SUPPORT_FPU
+ fpu_execute(i);
+#else
+ BX_INFO(("ESC0 not implemented\n"));
+#endif
+}
+
+ void
+BX_CPU_C::ESC1(BxInstruction_t *i)
+{
+ if ( BX_CPU_THIS_PTR cr0.em || BX_CPU_THIS_PTR cr0.ts ) {
+ exception(BX_NM_EXCEPTION, 0, 0);
+ }
+#if BX_SUPPORT_FPU
+ fpu_execute(i);
+#else
+ BX_INFO(("ESC1 not implemented\n"));
+#endif
+}
+
+ void
+BX_CPU_C::ESC2(BxInstruction_t *i)
+{
+ if ( BX_CPU_THIS_PTR cr0.em || BX_CPU_THIS_PTR cr0.ts ) {
+ exception(BX_NM_EXCEPTION, 0, 0);
+ }
+#if BX_SUPPORT_FPU
+ fpu_execute(i);
+#else
+ BX_INFO(("ESC2 not implemented\n"));
+#endif
+}
+
+ void
+BX_CPU_C::ESC3(BxInstruction_t *i)
+{
+ if ( BX_CPU_THIS_PTR cr0.em || BX_CPU_THIS_PTR cr0.ts ) {
+ exception(BX_NM_EXCEPTION, 0, 0);
+ }
+
+//BX_DEBUG(( "CS:EIP = %04x:%08x\n",
+// BX_CPU.sregs[BX_SEG_REG_CS].selector.value, BX_CPU.prev_eip));
+
+#if BX_SUPPORT_FPU
+ fpu_execute(i);
+#else
+ BX_INFO(("ESC3 not implemented\n"));
+#endif
+}
+
+ void
+BX_CPU_C::ESC4(BxInstruction_t *i)
+{
+ if ( BX_CPU_THIS_PTR cr0.em || BX_CPU_THIS_PTR cr0.ts ) {
+ exception(BX_NM_EXCEPTION, 0, 0);
+ }
+#if BX_SUPPORT_FPU
+ fpu_execute(i);
+#else
+ BX_INFO(("ESC4 not implemented\n"));
+#endif
+}
+
+ void
+BX_CPU_C::ESC5(BxInstruction_t *i)
+{
+ if ( BX_CPU_THIS_PTR cr0.em || BX_CPU_THIS_PTR cr0.ts ) {
+ exception(BX_NM_EXCEPTION, 0, 0);
+ }
+#if BX_SUPPORT_FPU
+ fpu_execute(i);
+#else
+ BX_INFO(("ESC5 not implemented\n"));
+#endif
+}
+
+ void
+BX_CPU_C::ESC6(BxInstruction_t *i)
+{
+ if ( BX_CPU_THIS_PTR cr0.em || BX_CPU_THIS_PTR cr0.ts ) {
+ exception(BX_NM_EXCEPTION, 0, 0);
+ }
+#if BX_SUPPORT_FPU
+ fpu_execute(i);
+#else
+ BX_INFO(("ESC6 not implemented\n"));
+#endif
+}
+
+ void
+BX_CPU_C::ESC7(BxInstruction_t *i)
+{
+ if ( BX_CPU_THIS_PTR cr0.em || BX_CPU_THIS_PTR cr0.ts ) {
+ exception(BX_NM_EXCEPTION, 0, 0);
+ }
+#if BX_SUPPORT_FPU
+ fpu_execute(i);
+#else
+ BX_INFO(("ESC7 not implemented\n"));
+#endif
+}
+
+ void
+BX_CPU_C::FWAIT(BxInstruction_t *i)
+{
+#if BX_CPU_LEVEL < 3
+ // WAIT doesn't generate single steps on 8086.
+ // The same goes for prefix instructions, and instructions which
+ // modify segment registers. (pg4-16)
+ // single_step_event = 0;
+ BX_PANIC(("WAIT: not implemented for < 386\n"));
+#else // BX_CPU_LEVEL >= 3
+
+ if ( BX_CPU_THIS_PTR cr0.ts && BX_CPU_THIS_PTR cr0.mp ) {
+ exception(BX_NM_EXCEPTION, 0, 0); // no error
+ }
+#if BX_SUPPORT_FPU
+ fpu_execute(i);
+#else
+ BX_INFO(("FWAIT: no FPU\n"));
+#endif
+
+#endif
+}
+
+
+#if BX_SUPPORT_FPU==0
+ // if supporting FPU, this function in glue logic file
+ void
+BX_CPU_C::fpu_init(void)
+{
+}
+#endif
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | fpu_arith.c |
+ | |
+ | Code to implement the FPU register/register arithmetic instructions |
+ | |
+ | Copyright (C) 1992,1993,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#include "fpu_system.h"
+#include "fpu_emu.h"
+#include "control_w.h"
+#include "status_w.h"
+
+
+void fadd__()
+{
+ /* fadd st,st(i) */
+ int i = FPU_rm;
+ clear_C1();
+ FPU_add(&st(i), FPU_gettagi(i), 0, control_word);
+}
+
+
+void fmul__()
+{
+ /* fmul st,st(i) */
+ int i = FPU_rm;
+ clear_C1();
+ FPU_mul(&st(i), FPU_gettagi(i), 0, control_word);
+}
+
+
+
+void fsub__()
+{
+ /* fsub st,st(i) */
+ clear_C1();
+ FPU_sub(0, REGNO2PTR(FPU_rm), control_word);
+}
+
+
+void fsubr_()
+{
+ /* fsubr st,st(i) */
+ clear_C1();
+ FPU_sub(REV, REGNO2PTR(FPU_rm), control_word);
+}
+
+
+void fdiv__()
+{
+ /* fdiv st,st(i) */
+ clear_C1();
+ FPU_div(0, REGNO2PTR(FPU_rm), control_word);
+}
+
+
+void fdivr_()
+{
+ /* fdivr st,st(i) */
+ clear_C1();
+ FPU_div(REV, REGNO2PTR(FPU_rm), control_word);
+}
+
+
+
+void fadd_i()
+{
+ /* fadd st(i),st */
+ int i = FPU_rm;
+ clear_C1();
+ FPU_add(&st(i), FPU_gettagi(i), i, control_word);
+}
+
+
+void fmul_i()
+{
+ /* fmul st(i),st */
+ clear_C1();
+ FPU_mul(&st(0), FPU_gettag0(), FPU_rm, control_word);
+}
+
+
+void fsubri()
+{
+ /* fsubr st(i),st */
+ clear_C1();
+ FPU_sub(DEST_RM, REGNO2PTR(FPU_rm), control_word);
+}
+
+
+void fsub_i()
+{
+ /* fsub st(i),st */
+ clear_C1();
+ FPU_sub(REV|DEST_RM, REGNO2PTR(FPU_rm), control_word);
+}
+
+
+void fdivri()
+{
+ /* fdivr st(i),st */
+ clear_C1();
+ FPU_div(DEST_RM, REGNO2PTR(FPU_rm), control_word);
+}
+
+
+void fdiv_i()
+{
+ /* fdiv st(i),st */
+ clear_C1();
+ FPU_div(REV|DEST_RM, REGNO2PTR(FPU_rm), control_word);
+}
+
+
+
+void faddp_()
+{
+ /* faddp st(i),st */
+ int i = FPU_rm;
+ clear_C1();
+ if ( FPU_add(&st(i), FPU_gettagi(i), i, control_word) >= 0 )
+ FPU_pop();
+}
+
+
+void fmulp_()
+{
+ /* fmulp st(i),st */
+ clear_C1();
+ if ( FPU_mul(&st(0), FPU_gettag0(), FPU_rm, control_word) >= 0 )
+ FPU_pop();
+}
+
+
+
+void fsubrp()
+{
+ /* fsubrp st(i),st */
+ clear_C1();
+ if ( FPU_sub(DEST_RM, REGNO2PTR(FPU_rm), control_word) >= 0 )
+ FPU_pop();
+}
+
+
+void fsubp_()
+{
+ /* fsubp st(i),st */
+ clear_C1();
+ if ( FPU_sub(REV|DEST_RM, REGNO2PTR(FPU_rm), control_word) >= 0 )
+ FPU_pop();
+}
+
+
+void fdivrp()
+{
+ /* fdivrp st(i),st */
+ clear_C1();
+ if ( FPU_div(DEST_RM, REGNO2PTR(FPU_rm), control_word) >= 0 )
+ FPU_pop();
+}
+
+
+void fdivp_()
+{
+ /* fdivp st(i),st */
+ clear_C1();
+ if ( FPU_div(REV|DEST_RM, REGNO2PTR(FPU_rm), control_word) >= 0 )
+ FPU_pop();
+}
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | fpu_asm.h |
+ | |
+ | Copyright (C) 1992,1995,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@suburbia.net |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#ifndef _FPU_ASM_H_
+#define _FPU_ASM_H_
+
+#include <linux/linkage.h>
+
+#define EXCEPTION SYMBOL_NAME(FPU_exception)
+
+
+#define PARAM1 8(%ebp)
+#define PARAM2 12(%ebp)
+#define PARAM3 16(%ebp)
+#define PARAM4 20(%ebp)
+#define PARAM5 24(%ebp)
+#define PARAM6 28(%ebp)
+#define PARAM7 32(%ebp)
+
+#define SIGL_OFFSET 0
+#define EXP(x) 8(x)
+#define SIG(x) SIGL_OFFSET##(x)
+#define SIGL(x) SIGL_OFFSET##(x)
+#define SIGH(x) 4(x)
+
+#endif /* _FPU_ASM_H_ */
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | fpu_aux.c |
+ | |
+ | Code to implement some of the FPU auxiliary instructions. |
+ | |
+ | Copyright (C) 1992,1993,1994,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#include "fpu_system.h"
+#include "exception.h"
+#include "fpu_emu.h"
+#include "status_w.h"
+#include "control_w.h"
+
+
+static void fnop(void)
+{
+}
+
+void fclex(void)
+{
+ partial_status &= ~(SW_Backward|SW_Summary|SW_Stack_Fault|SW_Precision|
+ SW_Underflow|SW_Overflow|SW_Zero_Div|SW_Denorm_Op|
+ SW_Invalid);
+ no_ip_update = 1;
+}
+
+/* Needs to be externally visible */
+void finit()
+{
+ control_word = 0x037f;
+ partial_status = 0;
+ top = 0; /* We don't keep top in the status word internally. */
+ fpu_tag_word = 0xffff;
+ /* The behaviour is different from that detailed in
+ Section 15.1.6 of the Intel manual */
+ operand_address.offset = 0;
+ operand_address.selector = 0;
+ instruction_address.offset = 0;
+ instruction_address.selector = 0;
+ instruction_address.opcode = 0;
+ no_ip_update = 1;
+}
+
+/*
+ * These are nops on the i387..
+ */
+#define feni fnop
+#define fdisi fnop
+#define fsetpm fnop
+
+static FUNC const finit_table[] = {
+ feni, fdisi, fclex, finit,
+ fsetpm, FPU_illegal, FPU_illegal, FPU_illegal
+};
+
+void finit_()
+{
+ (finit_table[FPU_rm])();
+}
+
+
+static void fstsw_ax(void)
+{
+ SET_AX(status_word()); // KPL
+ no_ip_update = 1;
+}
+
+static FUNC const fstsw_table[] = {
+ fstsw_ax, FPU_illegal, FPU_illegal, FPU_illegal,
+ FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal
+};
+
+void fstsw_()
+{
+ (fstsw_table[FPU_rm])();
+}
+
+
+static FUNC const fp_nop_table[] = {
+ fnop, FPU_illegal, FPU_illegal, FPU_illegal,
+ FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal
+};
+
+void fp_nop()
+{
+ (fp_nop_table[FPU_rm])();
+}
+
+
+void fld_i_()
+{
+ FPU_REG *st_new_ptr;
+ int i;
+ u_char tag;
+
+ if ( STACK_OVERFLOW )
+ { FPU_stack_overflow(); return; }
+
+ /* fld st(i) */
+ i = FPU_rm;
+ if ( NOT_EMPTY(i) )
+ {
+ reg_copy(&st(i), st_new_ptr);
+ tag = FPU_gettagi(i);
+ push();
+ FPU_settag0(tag);
+ }
+ else
+ {
+ if ( control_word & CW_Invalid )
+ {
+ /* The masked response */
+ FPU_stack_underflow();
+ }
+ else
+ EXCEPTION(EX_StackUnder);
+ }
+
+}
+
+
+void fxch_i()
+{
+ /* fxch st(i) */
+ FPU_REG t;
+ int i = FPU_rm;
+ FPU_REG *st0_ptr = &st(0), *sti_ptr = &st(i);
+ s32 tag_word = fpu_tag_word;
+ int regnr = top & 7, regnri = ((regnr + i) & 7);
+ u_char st0_tag = (tag_word >> (regnr*2)) & 3;
+ u_char sti_tag = (tag_word >> (regnri*2)) & 3;
+
+ if ( st0_tag == TAG_Empty )
+ {
+ if ( sti_tag == TAG_Empty )
+ {
+ FPU_stack_underflow();
+ FPU_stack_underflow_i(i);
+ return;
+ }
+ if ( control_word & CW_Invalid )
+ {
+ /* Masked response */
+ FPU_copy_to_reg0(sti_ptr, sti_tag);
+ }
+ FPU_stack_underflow_i(i);
+ return;
+ }
+ if ( sti_tag == TAG_Empty )
+ {
+ if ( control_word & CW_Invalid )
+ {
+ /* Masked response */
+ FPU_copy_to_regi(st0_ptr, st0_tag, i);
+ }
+ FPU_stack_underflow();
+ return;
+ }
+ clear_C1();
+
+ reg_copy(st0_ptr, &t);
+ reg_copy(sti_ptr, st0_ptr);
+ reg_copy(&t, sti_ptr);
+
+ tag_word &= ~(3 << (regnr*2)) & ~(3 << (regnri*2));
+ tag_word |= (sti_tag << (regnr*2)) | (st0_tag << (regnri*2));
+ fpu_tag_word = tag_word;
+}
+
+
+void ffree_()
+{
+ /* ffree st(i) */
+ FPU_settagi(FPU_rm, TAG_Empty);
+}
+
+
+void ffreep()
+{
+ /* ffree st(i) + pop - unofficial code */
+ FPU_settagi(FPU_rm, TAG_Empty);
+ FPU_pop();
+}
+
+
+void fst_i_()
+{
+ /* fst st(i) */
+ FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
+}
+
+
+void fstp_i()
+{
+ /* fstp st(i) */
+ FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
+ FPU_pop();
+}
+
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | fpu_emu.h |
+ | |
+ | Copyright (C) 1992,1993,1994,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@suburbia.net |
+ | |
+ +---------------------------------------------------------------------------*/
+
+
+#ifndef _FPU_EMU_H_
+#define _FPU_EMU_H_
+
+/*
+ * Define PECULIAR_486 to get a closer approximation to 80486 behaviour,
+ * rather than behaviour which appears to be cleaner.
+ * This is a matter of opinion: for all I know, the 80486 may simply
+ * be complying with the IEEE spec. Maybe one day I'll get to see the
+ * spec...
+ */
+#define PECULIAR_486
+
+// change a pointer to an int, with type conversions that make it legal.
+// On machines with 64-bit pointers, compilers complain when you typecast
+// a 64-bit pointer into a 32-bit integer.
+#define PTR2INT(x) ((bx_ptr_equiv_t)(void *)(x))
+
+#ifdef __ASSEMBLY__
+#include "fpu_asm.h"
+#define Const(x) $##x
+#else
+#include <asm/types.h>
+#define Const(x) x
+#endif
+
+#define EXP_BIAS Const(0)
+#define EXP_OVER Const(0x4000) /* smallest invalid large exponent */
+#define EXP_UNDER Const(-0x3fff) /* largest invalid small exponent */
+#define EXP_WAY_UNDER Const(-0x6000) /* Below the smallest denormal, but
+ still a 16 bit nr. */
+#define EXP_Infinity EXP_OVER
+#define EXP_NaN EXP_OVER
+
+#define EXTENDED_Ebias Const(0x3fff)
+#define EXTENDED_Emin (-0x3ffe) /* smallest valid exponent */
+
+#define SIGN_POS Const(0)
+#define SIGN_NEG Const(0x80)
+
+#define SIGN_Positive Const(0)
+#define SIGN_Negative Const(0x8000)
+
+
+/* Keep the order TAG_Valid, TAG_Zero, TW_Denormal */
+/* The following fold to 2 (Special) in the Tag Word */
+#define TW_Denormal Const(4) /* De-normal */
+#define TW_Infinity Const(5) /* + or - infinity */
+#define TW_NaN Const(6) /* Not a Number */
+#define TW_Unsupported Const(7) /* Not supported by an 80486 */
+
+#define TAG_Valid Const(0) /* valid */
+#define TAG_Zero Const(1) /* zero */
+#define TAG_Special Const(2) /* De-normal, + or - infinity,
+ or Not a Number */
+#define TAG_Empty Const(3) /* empty */
+
+#define LOADED_DATA Const(10101) /* Special st() number to identify
+ loaded data (not on stack). */
+
+/* A few flags (must be >= 0x10). */
+#define REV 0x10
+#define DEST_RM 0x20
+#define LOADED 0x40
+
+#define FPU_Exception Const(0x80000000) /* Added to tag returns. */
+
+
+#ifndef __ASSEMBLY__
+
+#include "fpu_system.h"
+
+#include <asm/sigcontext.h> /* for struct _fpstate */
+#include <asm/math_emu.h>
+#include <linux/linkage.h>
+
+/*
+#define RE_ENTRANT_CHECKING
+ */
+
+#ifdef RE_ENTRANT_CHECKING
+extern u_char emulating;
+# define RE_ENTRANT_CHECK_OFF emulating = 0
+# define RE_ENTRANT_CHECK_ON emulating = 1
+#else
+# define RE_ENTRANT_CHECK_OFF
+# define RE_ENTRANT_CHECK_ON
+#endif /* ifdef RE_ENTRANT_CHECKING */
+
+#define FWAIT_OPCODE 0x9b
+#define OP_SIZE_PREFIX 0x66
+#define ADDR_SIZE_PREFIX 0x67
+#define PREFIX_CS 0x2e
+#define PREFIX_DS 0x3e
+#define PREFIX_ES 0x26
+#define PREFIX_SS 0x36
+#define PREFIX_FS 0x64
+#define PREFIX_GS 0x65
+#define PREFIX_REPE 0xf3
+#define PREFIX_REPNE 0xf2
+#define PREFIX_LOCK 0xf0
+#define PREFIX_CS_ 1
+#define PREFIX_DS_ 2
+#define PREFIX_ES_ 3
+#define PREFIX_FS_ 4
+#define PREFIX_GS_ 5
+#define PREFIX_SS_ 6
+#define PREFIX_DEFAULT 7
+
+struct address {
+ u32 offset;
+#ifdef EMU_BIG_ENDIAN
+ u32 empty:5;
+ u32 opcode:11;
+ u32 selector:16;
+#else
+ u32 selector:16;
+ u32 opcode:11;
+ u32 empty:5;
+#endif
+} GCC_ATTRIBUTE((packed));
+
+struct fpu__reg {
+#ifdef EMU_BIG_ENDIAN
+ u32 sigh;
+ u32 sigl;
+ s16 exp; /* Signed quantity used in internal arithmetic. */
+#else
+ u32 sigl;
+ u32 sigh;
+ s16 exp; /* Signed quantity used in internal arithmetic. */
+#endif
+} GCC_ATTRIBUTE((aligned(16), packed));
+
+#ifdef EMU_BIG_ENDIAN
+#define MAKE_REG(s,e,l,h) { h, l, \
+ ((EXTENDED_Ebias+(e)) | ((SIGN_##s != 0)*0x8000)) }
+#else
+#define MAKE_REG(s,e,l,h) { l, h, \
+ ((EXTENDED_Ebias+(e)) | ((SIGN_##s != 0)*0x8000)) }
+#endif
+
+typedef void (*FUNC)(void);
+typedef struct fpu__reg FPU_REG;
+typedef void (*FUNC_ST0)(FPU_REG *st0_ptr, u_char st0_tag);
+typedef struct { u_char address_size, operand_size, segment; }
+ GCC_ATTRIBUTE((packed)) overrides;
+/* This structure is 32 bits: */
+typedef struct { overrides override;
+ u_char default_mode; }
+ GCC_ATTRIBUTE((packed)) fpu_addr_modes;
+/* PROTECTED has a restricted meaning in the emulator; it is used
+ to signal that the emulator needs to do special things to ensure
+ that protection is respected in a segmented model. */
+#define PROTECTED 4
+#define SIXTEEN 1 /* We rely upon this being 1 (true) */
+#define VM86 SIXTEEN
+#define PM16 (SIXTEEN | PROTECTED)
+#define SEG32 PROTECTED
+extern u_char const data_sizes_16[32];
+
+#define register_base ((u_char *) registers )
+#define fpu_register(x) ( * ((FPU_REG *)( register_base + sizeof(FPU_REG) * (x & 7) )) )
+#define st(x) ( * ((FPU_REG *)( register_base + sizeof(FPU_REG) * ((top+x) & 7) )) )
+
+#define STACK_OVERFLOW (FPU_stackoverflow(&st_new_ptr))
+#define NOT_EMPTY(i) (!FPU_empty_i(i))
+
+#define NOT_EMPTY_ST0 (st0_tag ^ TAG_Empty)
+
+#define poppop() { FPU_pop(); FPU_pop(); }
+
+/* push() does not affect the tags */
+#define push() { top--; }
+
+#ifdef EMU_BIG_ENDIAN
+#define signbyte(a) (((u_char *)(a))[8])
+#else
+#define signbyte(a) (((u_char *)(a))[9])
+#endif
+#define getsign(a) (signbyte(a) & 0x80)
+#define setsign(a,b) { if (b) signbyte(a) |= 0x80; else signbyte(a) &= 0x7f; }
+#define copysign(a,b) { if (getsign(a)) signbyte(b) |= 0x80; \
+ else signbyte(b) &= 0x7f; }
+#define changesign(a) { signbyte(a) ^= 0x80; }
+#define setpositive(a) { signbyte(a) &= 0x7f; }
+#define setnegative(a) { signbyte(a) |= 0x80; }
+#define signpositive(a) ( (signbyte(a) & 0x80) == 0 )
+#define signnegative(a) (signbyte(a) & 0x80)
+
+#ifdef EMU_BIG_ENDIAN
+#define significand(x) ( ((u64 *)&((x)->sigh))[0] )
+#else
+#define significand(x) ( ((u64 *)&((x)->sigl))[0] )
+#endif
+
+BX_C_INLINE
+void reg_copy(FPU_REG const *x, FPU_REG *y)
+{
+ y->exp = x->exp;
+ significand(y) = significand(x);
+}
+
+#define exponent(x) (((x)->exp & 0x7fff) - EXTENDED_Ebias)
+#define setexponentpos(x,y) { (x)->exp = ((y) + EXTENDED_Ebias) & 0x7fff; }
+#define exponent16(x) (x)->exp
+#define setexponent16(x,y) { (x)->exp = (y); }
+#define addexponent(x,y) { (x)->exp += (y); }
+#define stdexp(x) { (x)->exp += EXTENDED_Ebias; }
+
+#define isdenormal(ptr) (exponent(ptr) == EXP_BIAS+EXP_UNDER)
+
+/*----- Prototypes for functions written in assembler -----*/
+/* extern void reg_move(FPU_REG *a, FPU_REG *b); */
+
+asmlinkage int FPU_normalize_nuo(FPU_REG *x, int bias);
+asmlinkage int FPU_u_sub(FPU_REG const *arg1, FPU_REG const *arg2,
+ FPU_REG *answ, u16 control_w, u_char sign,
+ s32 expa, s32 expb);
+asmlinkage int FPU_u_mul(FPU_REG const *arg1, FPU_REG const *arg2,
+ FPU_REG *answ, u16 control_w, u_char sign,
+ s32 expon);
+asmlinkage int FPU_u_div(FPU_REG const *arg1, FPU_REG const *arg2,
+ FPU_REG *answ, u16 control_w, u_char sign);
+asmlinkage int FPU_u_add(FPU_REG const *arg1, FPU_REG const *arg2,
+ FPU_REG *answ, u16 control_w, u_char sign,
+ s32 expa, s32 expb);
+asmlinkage int wm_sqrt(FPU_REG *n, int dummy1, int dummy2,
+ u16 control_w, u_char sign);
+asmlinkage u32 FPU_shrx(void *l, u32 x);
+asmlinkage u32 FPU_shrxs(void *v, u32 x);
+asmlinkage u32 FPU_div_small(u64 *x, u32 y);
+asmlinkage int FPU_round(FPU_REG *arg, u32 extent, int dummy,
+ u16 control_w, u_char sign);
+
+#ifndef MAKING_PROTO
+#include "fpu_proto.h"
+#endif
+
+#endif /* defined __ASSEMBLY__ */
+
+#endif /* !defined _FPU_EMU_H_ */
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | fpu_entry.c |
+ | |
+ | The entry functions for wm-FPU-emu |
+ | |
+ | Copyright (C) 1992,1993,1994,1996,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
+ | |
+ | See the files "README" and "COPYING" for further copyright and warranty |
+ | information. |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | Note: |
+ | The file contains code which accesses user memory. |
+ | Emulator static data may change when user memory is accessed, due to |
+ | other processes using the emulator while swapping is in progress. |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | math_emulate(), restore_i387_soft() and save_i387_soft() are the only |
+ | entry points for wm-FPU-emu. |
+ +---------------------------------------------------------------------------*/
+
+#include "fpu_system.h"
+#include "fpu_emu.h"
+#include "exception.h"
+#include "control_w.h"
+#include "status_w.h"
+
+#include <linux/signal.h>
+
+#include <asm/uaccess.h>
+#include <asm/desc.h>
+
+
+#define __BAD__ FPU_illegal /* Illegal on an 80486, causes SIGILL */
+
+#ifndef NO_UNDOC_CODE /* Un-documented FPU op-codes supported by default. */
+
+/* WARNING: These codes are not documented by Intel in their 80486 manual
+ and may not work on FPU clones or later Intel FPUs. */
+
+/* Changes to support the un-doc codes provided by Linus Torvalds. */
+
+#define _d9_d8_ fstp_i /* unofficial code (19) */
+#define _dc_d0_ fcom_st /* unofficial code (14) */
+#define _dc_d8_ fcompst /* unofficial code (1c) */
+#define _dd_c8_ fxch_i /* unofficial code (0d) */
+#define _de_d0_ fcompst /* unofficial code (16) */
+#define _df_c0_ ffreep /* unofficial code (07) ffree + pop */
+#define _df_c8_ fxch_i /* unofficial code (0f) */
+#define _df_d0_ fstp_i /* unofficial code (17) */
+#define _df_d8_ fstp_i /* unofficial code (1f) */
+
+static FUNC const st_instr_table[64] = {
+ fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, _df_c0_,
+ fmul__, fxch_i, __BAD__, __BAD__, fmul_i, _dd_c8_, fmulp_, _df_c8_,
+ fcom_st, fp_nop, __BAD__, __BAD__, _dc_d0_, fst_i_, _de_d0_, _df_d0_,
+ fcompst, _d9_d8_, __BAD__, __BAD__, _dc_d8_, fstp_i, fcompp, _df_d8_,
+ fsub__, FPU_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
+ fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
+ fdiv__, FPU_triga, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
+ fdivr_, FPU_trigb, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
+};
+
+#else /* Support only documented FPU op-codes */
+
+static FUNC const st_instr_table[64] = {
+ fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, __BAD__,
+ fmul__, fxch_i, __BAD__, __BAD__, fmul_i, __BAD__, fmulp_, __BAD__,
+ fcom_st, fp_nop, __BAD__, __BAD__, __BAD__, fst_i_, __BAD__, __BAD__,
+ fcompst, __BAD__, __BAD__, __BAD__, __BAD__, fstp_i, fcompp, __BAD__,
+ fsub__, FPU_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
+ fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
+ fdiv__, FPU_triga, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
+ fdivr_, FPU_trigb, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
+};
+
+#endif /* NO_UNDOC_CODE */
+
+
+#define _NONE_ 0 /* Take no special action */
+#define _REG0_ 1 /* Need to check for not empty st(0) */
+#define _REGI_ 2 /* Need to check for not empty st(0) and st(rm) */
+#define _REGi_ 0 /* Uses st(rm) */
+#define _PUSH_ 3 /* Need to check for space to push onto stack */
+#define _null_ 4 /* Function illegal or not implemented */
+#define _REGIi 5 /* Uses st(0) and st(rm), result to st(rm) */
+#define _REGIp 6 /* Uses st(0) and st(rm), result to st(rm) then pop */
+#define _REGIc 0 /* Compare st(0) and st(rm) */
+#define _REGIn 0 /* Uses st(0) and st(rm), but handle checks later */
+
+#ifndef NO_UNDOC_CODE
+
+/* Un-documented FPU op-codes supported by default. (see above) */
+
+static u_char const type_table[64] = {
+ _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _REGi_,
+ _REGI_, _REGIn, _null_, _null_, _REGIi, _REGI_, _REGIp, _REGI_,
+ _REGIc, _NONE_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
+ _REGIc, _REG0_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
+ _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
+ _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
+ _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
+ _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
+};
+
+#else /* Support only documented FPU op-codes */
+
+static u_char const type_table[64] = {
+ _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _null_,
+ _REGI_, _REGIn, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
+ _REGIc, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_,
+ _REGIc, _null_, _null_, _null_, _null_, _REG0_, _REGIc, _null_,
+ _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
+ _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
+ _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
+ _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
+};
+
+#endif /* NO_UNDOC_CODE */
+
+
+#ifndef USE_WITH_CPU_SIM
+
+
+#ifdef RE_ENTRANT_CHECKING
+u_char emulating=0;
+#endif /* RE_ENTRANT_CHECKING */
+
+static int valid_prefix(u_char *Byte, u_char **fpu_eip,
+ overrides *override);
+
+asmlinkage void math_emulate(long arg)
+{
+ u_char FPU_modrm, byte1;
+ unsigned short code;
+ fpu_addr_modes addr_modes;
+ int unmasked;
+ FPU_REG loaded_data;
+ FPU_REG *st0_ptr;
+ u_char loaded_tag, st0_tag;
+ void *data_address;
+ struct address data_sel_off;
+ struct address entry_sel_off;
+ u32 code_base = 0;
+ u32 code_limit = 0; /* Initialized to stop compiler warnings */
+ struct desc_struct code_descriptor;
+
+#ifdef RE_ENTRANT_CHECKING
+ if ( emulating )
+ {
+ printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
+ }
+ RE_ENTRANT_CHECK_ON;
+#endif /* RE_ENTRANT_CHECKING */
+
+ if (!current->used_math)
+ {
+ finit();
+ current->used_math = 1;
+ }
+
+ SETUP_DATA_AREA(arg);
+
+ FPU_ORIG_EIP = FPU_EIP;
+
+ if ( (FPU_EFLAGS & 0x00020000) != 0 )
+ {
+ /* Virtual 8086 mode */
+ addr_modes.default_mode = VM86;
+ FPU_EIP += code_base = FPU_CS << 4;
+ code_limit = code_base + 0xffff; /* Assumes code_base <= 0xffff0000 */
+ }
+ else if ( FPU_CS == __USER_CS && FPU_DS == __USER_DS )
+ {
+ addr_modes.default_mode = 0;
+ }
+ else if ( FPU_CS == __KERNEL_CS )
+ {
+ printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP);
+ panic("Math emulation needed in kernel");
+ }
+ else
+ {
+
+ if ( (FPU_CS & 4) != 4 ) /* Must be in the LDT */
+ {
+ /* Can only handle segmented addressing via the LDT
+ for now, and it must be 16 bit */
+ printk("FPU emulator: Unsupported addressing mode\n");
+ math_abort(FPU_info, SIGILL);
+ }
+
+ if ( SEG_D_SIZE(code_descriptor = LDT_DESCRIPTOR(FPU_CS)) )
+ {
+ /* The above test may be wrong, the book is not clear */
+ /* Segmented 32 bit protected mode */
+ addr_modes.default_mode = SEG32;
+ }
+ else
+ {
+ /* 16 bit protected mode */
+ addr_modes.default_mode = PM16;
+ }
+ FPU_EIP += code_base = SEG_BASE_ADDR(code_descriptor);
+ code_limit = code_base
+ + (SEG_LIMIT(code_descriptor)+1) * SEG_GRANULARITY(code_descriptor)
+ - 1;
+ if ( code_limit < code_base ) code_limit = 0xffffffff;
+ }
+
+ FPU_lookahead = 1;
+ if (current->flags & PF_PTRACED)
+ FPU_lookahead = 0;
+
+ if ( !valid_prefix(&byte1, (u_char **)&FPU_EIP,
+ &addr_modes.override) )
+ {
+ RE_ENTRANT_CHECK_OFF;
+ printk("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n"
+ "FPU emulator: self-modifying code! (emulation impossible)\n",
+ byte1);
+ RE_ENTRANT_CHECK_ON;
+ EXCEPTION(EX_INTERNAL|0x126);
+ math_abort(FPU_info,SIGILL);
+ }
+
+do_another_FPU_instruction:
+
+ no_ip_update = 0;
+
+ FPU_EIP++; /* We have fetched the prefix and first code bytes. */
+
+ if ( addr_modes.default_mode )
+ {
+ /* This checks for the minimum instruction bytes.
+ We also need to check any extra (address mode) code access. */
+ if ( FPU_EIP > code_limit )
+ math_abort(FPU_info,SIGSEGV);
+ }
+
+ if ( (byte1 & 0xf8) != 0xd8 )
+ {
+ if ( byte1 == FWAIT_OPCODE )
+ {
+ if (partial_status & SW_Summary)
+ goto do_the_FPU_interrupt;
+ else
+ goto FPU_fwait_done;
+ }
+#ifdef PARANOID
+ EXCEPTION(EX_INTERNAL|0x128);
+ math_abort(FPU_info,SIGILL);
+#endif /* PARANOID */
+ }
+
+ RE_ENTRANT_CHECK_OFF;
+ FPU_code_verify_area(1);
+ FPU_get_user(FPU_modrm, (u_char *) FPU_EIP);
+ RE_ENTRANT_CHECK_ON;
+ FPU_EIP++;
+
+ if (partial_status & SW_Summary)
+ {
+ /* Ignore the error for now if the current instruction is a no-wait
+ control instruction */
+ /* The 80486 manual contradicts itself on this topic,
+ but a real 80486 uses the following instructions:
+ fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex.
+ */
+ code = (FPU_modrm << 8) | byte1;
+ if ( ! ( (((code & 0xf803) == 0xe003) || /* fnclex, fninit, fnstsw */
+ (((code & 0x3003) == 0x3001) && /* fnsave, fnstcw, fnstenv,
+ fnstsw */
+ ((code & 0xc000) != 0xc000))) ) )
+ {
+ /*
+ * We need to simulate the action of the kernel to FPU
+ * interrupts here.
+ */
+ do_the_FPU_interrupt:
+
+ FPU_EIP = FPU_ORIG_EIP; /* Point to current FPU instruction. */
+
+ RE_ENTRANT_CHECK_OFF;
+ current->tss.trap_no = 16;
+ current->tss.error_code = 0;
+ send_sig(SIGFPE, current, 1);
+ return;
+ }
+ }
+
+ entry_sel_off.offset = FPU_ORIG_EIP;
+ entry_sel_off.selector = FPU_CS;
+ entry_sel_off.opcode = (byte1 << 8) | FPU_modrm;
+
+ FPU_rm = FPU_modrm & 7;
+
+ if ( FPU_modrm < 0300 )
+ {
+ /* All of these instructions use the mod/rm byte to get a data address */
+
+ if ( (addr_modes.default_mode & SIXTEEN)
+ ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX) )
+ data_address = FPU_get_address_16(FPU_modrm, (u32 *)&FPU_EIP, &data_sel_off,
+ addr_modes);
+ else
+ data_address = FPU_get_address(FPU_modrm, (u32 *)&FPU_EIP, &data_sel_off,
+ addr_modes);
+
+ if ( addr_modes.default_mode )
+ {
+ if ( FPU_EIP-1 > code_limit )
+ math_abort(FPU_info,SIGSEGV);
+ }
+
+ if ( !(byte1 & 1) )
+ {
+ unsigned short status1 = partial_status;
+
+ st0_ptr = &st(0);
+ st0_tag = FPU_gettag0();
+
+ /* Stack underflow has priority */
+ if ( NOT_EMPTY_ST0 )
+ {
+ if ( addr_modes.default_mode & PROTECTED )
+ {
+ /* This table works for 16 and 32 bit protected mode */
+ if ( access_limit < data_sizes_16[(byte1 >> 1) & 3] )
+ math_abort(FPU_info,SIGSEGV);
+ }
+
+ unmasked = 0; /* Do this here to stop compiler warnings. */
+ switch ( (byte1 >> 1) & 3 )
+ {
+ case 0:
+ unmasked = FPU_load_single((float *)data_address,
+ &loaded_data);
+ loaded_tag = unmasked & 0xff;
+ unmasked &= ~0xff;
+ break;
+ case 1:
+ loaded_tag = FPU_load_int32((s32 *)data_address, &loaded_data); // bbd: was (u32*)
+ break;
+ case 2:
+ unmasked = FPU_load_double((double *)data_address,
+ &loaded_data);
+ loaded_tag = unmasked & 0xff;
+ unmasked &= ~0xff;
+ break;
+ case 3:
+ default: /* Used here to suppress gcc warnings. */
+ loaded_tag = FPU_load_int16((short *)data_address, &loaded_data);
+ break;
+ }
+
+ /* No more access to user memory, it is safe
+ to use static data now */
+
+ /* NaN operands have the next priority. */
+ /* We have to delay looking at st(0) until after
+ loading the data, because that data might contain an SNaN */
+ if ( ((st0_tag == TAG_Special) && isNaN(st0_ptr)) ||
+ ((loaded_tag == TAG_Special) && isNaN(&loaded_data)) )
+ {
+ /* Restore the status word; we might have loaded a
+ denormal. */
+ partial_status = status1;
+ if ( (FPU_modrm & 0x30) == 0x10 )
+ {
+ /* fcom or fcomp */
+ EXCEPTION(EX_Invalid);
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
+ FPU_pop(); /* fcomp, masked, so we pop. */
+ }
+ else
+ {
+ if ( loaded_tag == TAG_Special )
+ loaded_tag = FPU_Special(&loaded_data);
+#ifdef PECULIAR_486
+ /* This is not really needed, but gives behaviour
+ identical to an 80486 */
+ if ( (FPU_modrm & 0x28) == 0x20 )
+ /* fdiv or fsub */
+ real_2op_NaN(&loaded_data, loaded_tag, 0, &loaded_data);
+ else
+#endif /* PECULIAR_486 */
+ /* fadd, fdivr, fmul, or fsubr */
+ real_2op_NaN(&loaded_data, loaded_tag, 0, st0_ptr);
+ }
+ goto reg_mem_instr_done;
+ }
+
+ if ( unmasked && !((FPU_modrm & 0x30) == 0x10) )
+ {
+ /* Is not a comparison instruction. */
+ if ( (FPU_modrm & 0x38) == 0x38 )
+ {
+ /* fdivr */
+ if ( (st0_tag == TAG_Zero) &&
+ ((loaded_tag == TAG_Valid)
+ || (loaded_tag == TAG_Special
+ && isdenormal(&loaded_data))) )
+ {
+ if ( FPU_divide_by_zero(0, getsign(&loaded_data))
+ < 0 )
+ {
+ /* We use the fact here that the unmasked
+ exception in the loaded data was for a
+ denormal operand */
+ /* Restore the state of the denormal op bit */
+ partial_status &= ~SW_Denorm_Op;
+ partial_status |= status1 & SW_Denorm_Op;
+ }
+ else
+ setsign(st0_ptr, getsign(&loaded_data));
+ }
+ }
+ goto reg_mem_instr_done;
+ }
+
+ switch ( (FPU_modrm >> 3) & 7 )
+ {
+ case 0: /* fadd */
+ clear_C1();
+ FPU_add(&loaded_data, loaded_tag, 0, control_word);
+ break;
+ case 1: /* fmul */
+ clear_C1();
+ FPU_mul(&loaded_data, loaded_tag, 0, control_word);
+ break;
+ case 2: /* fcom */
+ FPU_compare_st_data(&loaded_data, loaded_tag);
+ break;
+ case 3: /* fcomp */
+ if ( !FPU_compare_st_data(&loaded_data, loaded_tag)
+ && !unmasked )
+ FPU_pop();
+ break;
+ case 4: /* fsub */
+ clear_C1();
+ // bbd: loaded_data used to be typecast to an int, but
+ // this corrupted the pointer on 64-bit machines.
+ // Now FPU_sub and similar take a FPU_REG* here instead.
+ FPU_sub(LOADED|loaded_tag, &loaded_data, control_word);
+ break;
+ case 5: /* fsubr */
+ clear_C1();
+ FPU_sub(REV|LOADED|loaded_tag, &loaded_data, control_word);
+ break;
+ case 6: /* fdiv */
+ clear_C1();
+ FPU_div(LOADED|loaded_tag, &loaded_data, control_word);
+ break;
+ case 7: /* fdivr */
+ clear_C1();
+ if ( st0_tag == TAG_Zero )
+ partial_status = status1; /* Undo any denorm tag,
+ zero-divide has priority. */
+ FPU_div(REV|LOADED|loaded_tag, &loaded_data, control_word);
+ break;
+ }
+ }
+ else
+ {
+ if ( (FPU_modrm & 0x30) == 0x10 )
+ {
+ /* The instruction is fcom or fcomp */
+ EXCEPTION(EX_StackUnder);
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
+ FPU_pop(); /* fcomp */
+ }
+ else
+ FPU_stack_underflow();
+ }
+ reg_mem_instr_done:
+ operand_address = data_sel_off;
+ }
+ else
+ {
+ if ( !(no_ip_update =
+ FPU_load_store(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1,
+ addr_modes, data_address)) )
+ {
+ operand_address = data_sel_off;
+ }
+ }
+
+ }
+ else
+ {
+ /* None of these instructions access user memory */
+ u_char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
+
+#ifdef PECULIAR_486
+ /* This is supposed to be undefined, but a real 80486 seems
+ to do this: */
+ operand_address.offset = 0;
+ operand_address.selector = FPU_DS;
+#endif /* PECULIAR_486 */
+
+ st0_ptr = &st(0);
+ st0_tag = FPU_gettag0();
+ switch ( type_table[(int) instr_index] )
+ {
+ case _NONE_: /* also _REGIc: _REGIn */
+ break;
+ case _REG0_:
+ if ( !NOT_EMPTY_ST0 )
+ {
+ FPU_stack_underflow();
+ goto FPU_instruction_done;
+ }
+ break;
+ case _REGIi:
+ if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
+ {
+ FPU_stack_underflow_i(FPU_rm);
+ goto FPU_instruction_done;
+ }
+ break;
+ case _REGIp:
+ if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
+ {
+ FPU_stack_underflow_pop(FPU_rm);
+ goto FPU_instruction_done;
+ }
+ break;
+ case _REGI_:
+ if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
+ {
+ FPU_stack_underflow();
+ goto FPU_instruction_done;
+ }
+ break;
+ case _PUSH_: /* Only used by the fld st(i) instruction */
+ break;
+ case _null_:
+ FPU_illegal();
+ goto FPU_instruction_done;
+ default:
+ EXCEPTION(EX_INTERNAL|0x111);
+ goto FPU_instruction_done;
+ }
+ (*st_instr_table[(int) instr_index])();
+
+FPU_instruction_done:
+ ;
+ }
+
+ if ( ! no_ip_update )
+ instruction_address = entry_sel_off;
+
+FPU_fwait_done:
+
+ if (FPU_lookahead && !current->need_resched)
+ {
+ FPU_ORIG_EIP = FPU_EIP - code_base;
+ if ( valid_prefix(&byte1, (u_char **)&FPU_EIP,
+ &addr_modes.override) )
+ goto do_another_FPU_instruction;
+ }
+
+ if ( addr_modes.default_mode )
+ FPU_EIP -= code_base;
+
+ RE_ENTRANT_CHECK_OFF;
+}
+
+
+/* Support for prefix bytes is not yet complete. To properly handle
+ all prefix bytes, further changes are needed in the emulator code
+ which accesses user address space. Access to separate segments is
+ important for msdos emulation. */
+static int valid_prefix(u_char *Byte, u_char **fpu_eip,
+ overrides *override)
+{
+ u_char byte;
+ u_char *ip = *fpu_eip;
+
+ *override = (overrides) { 0, 0, PREFIX_DEFAULT }; /* defaults */
+
+ RE_ENTRANT_CHECK_OFF;
+ FPU_code_verify_area(1);
+ FPU_get_user(byte, ip);
+ RE_ENTRANT_CHECK_ON;
+
+ while ( 1 )
+ {
+ switch ( byte )
+ {
+ case ADDR_SIZE_PREFIX:
+ override->address_size = ADDR_SIZE_PREFIX;
+ goto do_next_byte;
+
+ case OP_SIZE_PREFIX:
+ override->operand_size = OP_SIZE_PREFIX;
+ goto do_next_byte;
+
+ case PREFIX_CS:
+ override->segment = PREFIX_CS_;
+ goto do_next_byte;
+ case PREFIX_ES:
+ override->segment = PREFIX_ES_;
+ goto do_next_byte;
+ case PREFIX_SS:
+ override->segment = PREFIX_SS_;
+ goto do_next_byte;
+ case PREFIX_FS:
+ override->segment = PREFIX_FS_;
+ goto do_next_byte;
+ case PREFIX_GS:
+ override->segment = PREFIX_GS_;
+ goto do_next_byte;
+ case PREFIX_DS:
+ override->segment = PREFIX_DS_;
+ goto do_next_byte;
+
+/* lock is not a valid prefix for FPU instructions,
+ let the cpu handle it to generate a SIGILL. */
+/* case PREFIX_LOCK: */
+
+ /* rep.. prefixes have no meaning for FPU instructions */
+ case PREFIX_REPE:
+ case PREFIX_REPNE:
+
+ do_next_byte:
+ ip++;
+ RE_ENTRANT_CHECK_OFF;
+ FPU_code_verify_area(1);
+ FPU_get_user(byte, ip);
+ RE_ENTRANT_CHECK_ON;
+ break;
+ case FWAIT_OPCODE:
+ *Byte = byte;
+ return 1;
+ default:
+ if ( (byte & 0xf8) == 0xd8 )
+ {
+ *Byte = byte;
+ *fpu_eip = ip;
+ return 1;
+ }
+ else
+ {
+ /* Not a valid sequence of prefix bytes followed by
+ an FPU instruction. */
+ *Byte = byte; /* Needed for error message. */
+ return 0;
+ }
+ }
+ }
+}
+
+
+void math_abort(struct info * info, unsigned int signal)
+{
+ FPU_EIP = FPU_ORIG_EIP;
+ current->tss.trap_no = 16;
+ current->tss.error_code = 0;
+ send_sig(signal,current,1);
+ RE_ENTRANT_CHECK_OFF;
+ __asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4));
+#ifdef PARANOID
+ printk("ERROR: wm-FPU-emu math_abort failed!\n");
+#endif /* PARANOID */
+}
+
+
+
+#define S387 ((struct i387_soft_struct *)s387)
+#define sstatus_word() \
+ ((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top))
+
+int restore_i387_soft(void *s387, struct _fpstate *buf)
+{
+ u_char *d = (u_char *)buf;
+ int offset, other, i, tags, regnr, tag, newtop;
+
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_READ, d, 7*4 + 8*10);
+ if (__copy_from_user(&S387->cwd, d, 7*4))
+ return -1;
+ RE_ENTRANT_CHECK_ON;
+
+ d += 7*4;
+
+ S387->ftop = (S387->swd >> SW_Top_Shift) & 7;
+ offset = (S387->ftop & 7) * 10;
+ other = 80 - offset;
+
+ RE_ENTRANT_CHECK_OFF;
+ /* Copy all registers in stack order. */
+ if (__copy_from_user(((u_char *)&S387->st_space)+offset, d, other))
+ return -1;
+ if ( offset )
+ if (__copy_from_user((u_char *)&S387->st_space, d+other, offset))
+ return -1;
+ RE_ENTRANT_CHECK_ON;
+
+ /* The tags may need to be corrected now. */
+ tags = S387->twd;
+ newtop = S387->ftop;
+ for ( i = 0; i < 8; i++ )
+ {
+ regnr = (i+newtop) & 7;
+ if ( ((tags >> ((regnr & 7)*2)) & 3) != TAG_Empty )
+ {
+ /* The loaded data over-rides all other cases. */
+ tag = FPU_tagof((FPU_REG *)((u_char *)S387->st_space + 10*regnr));
+ tags &= ~(3 << (regnr*2));
+ tags |= (tag & 3) << (regnr*2);
+ }
+ }
+ S387->twd = tags;
+
+ return 0;
+}
+
+
+int save_i387_soft(void *s387, struct _fpstate * buf)
+{
+ u_char *d = (u_char *)buf;
+ int offset = (S387->ftop & 7) * 10, other = 80 - offset;
+
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE, d, 7*4 + 8*10);
+#ifdef PECULIAR_486
+ S387->cwd &= ~0xe080;
+ /* An 80486 sets nearly all of the reserved bits to 1. */
+ S387->cwd |= 0xffff0040;
+ S387->swd = sstatus_word() | 0xffff0000;
+ S387->twd |= 0xffff0000;
+ S387->fcs &= ~0xf8000000;
+ S387->fos |= 0xffff0000;
+#endif /* PECULIAR_486 */
+ __copy_to_user(d, &S387->cwd, 7*4);
+ RE_ENTRANT_CHECK_ON;
+
+ d += 7*4;
+
+ RE_ENTRANT_CHECK_OFF;
+ /* Copy all registers in stack order. */
+ if (__copy_to_user(d, ((u_char *)&S387->st_space)+offset, other))
+ return -1;
+ if ( offset )
+ if (__copy_to_user(d+other, (u_char *)&S387->st_space, offset))
+ return -1
+ RE_ENTRANT_CHECK_ON;
+
+ return 1;
+}
+
+#else /* #ifndef USE_WITH_CPU_SIM */
+
+
+/* Note, this is a version of fpu_entry.c, modified to interface
+ * to a CPU simulator, rather than a kernel.
+ *
+ * Ported by Kevin Lawton Sep 20, 1999
+ */
+
+
+ asmlinkage void
+math_emulate2(fpu_addr_modes addr_modes,
+ u_char FPU_modrm,
+ u_char byte1,
+ void *data_address,
+ struct address data_sel_off,
+ struct address entry_sel_off)
+{
+ u16 code;
+ int unmasked;
+ FPU_REG loaded_data;
+ FPU_REG *st0_ptr;
+ u_char loaded_tag, st0_tag;
+
+
+ // assuming byte is 0xd8..0xdf or 0xdb==FWAIT
+
+ // lock is not a valid prefix for FPU instructions, +++
+ // let the cpu handle it to generate a SIGILL.
+
+
+ no_ip_update = 0;
+
+ if ( byte1 == FWAIT_OPCODE ) {
+ if (partial_status & SW_Summary)
+ goto do_the_FPU_interrupt;
+ else
+ goto FPU_fwait_done;
+ }
+
+ if (partial_status & SW_Summary) {
+ /* Ignore the error for now if the current instruction is a no-wait
+ control instruction */
+ /* The 80486 manual contradicts itself on this topic,
+ but a real 80486 uses the following instructions:
+ fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex.
+ */
+ code = (FPU_modrm << 8) | byte1;
+ if ( ! ( (((code & 0xf803) == 0xe003) || /* fnclex, fninit, fnstsw */
+ (((code & 0x3003) == 0x3001) && /* fnsave, fnstcw, fnstenv,
+ fnstsw */
+ ((code & 0xc000) != 0xc000))) ) ) {
+ /*
+ * We need to simulate the action of the kernel to FPU
+ * interrupts here.
+ */
+do_the_FPU_interrupt:
+
+ math_abort(FPU_info, SIGFPE);
+ }
+ }
+
+ entry_sel_off.opcode = (byte1 << 8) | FPU_modrm;
+
+ FPU_rm = FPU_modrm & 7;
+
+ if ( FPU_modrm < 0300 ) {
+ /* All of these instructions use the mod/rm byte to get a data address */
+
+ if ( !(byte1 & 1) ) {
+ u16 status1 = partial_status;
+
+ st0_ptr = &st(0);
+ st0_tag = FPU_gettag0();
+
+ /* Stack underflow has priority */
+ if ( NOT_EMPTY_ST0 ) {
+ if ( addr_modes.default_mode & PROTECTED )
+ {
+ /* This table works for 16 and 32 bit protected mode */
+ if ( access_limit < data_sizes_16[(byte1 >> 1) & 3] )
+ math_abort(FPU_info, SIGSEGV);
+ }
+
+ unmasked = 0; /* Do this here to stop compiler warnings. */
+ switch ( (byte1 >> 1) & 3 )
+ {
+ case 0:
+ unmasked = FPU_load_single((float *)data_address,
+ &loaded_data);
+ loaded_tag = unmasked & 0xff;
+ unmasked &= ~0xff;
+ break;
+ case 1:
+ loaded_tag = FPU_load_int32((s32 *)data_address, &loaded_data); // bbd: was (u32 *)
+ break;
+ case 2:
+ unmasked = FPU_load_double((double *)data_address,
+ &loaded_data);
+ loaded_tag = unmasked & 0xff;
+ unmasked &= ~0xff;
+ break;
+ case 3:
+ default: /* Used here to suppress gcc warnings. */
+ loaded_tag = FPU_load_int16((s16 *)data_address, &loaded_data);
+ break;
+ }
+
+ /* No more access to user memory, it is safe
+ to use static data now */
+
+ /* NaN operands have the next priority. */
+ /* We have to delay looking at st(0) until after
+ loading the data, because that data might contain an SNaN */
+ if ( ((st0_tag == TAG_Special) && isNaN(st0_ptr)) ||
+ ((loaded_tag == TAG_Special) && isNaN(&loaded_data)) )
+ {
+ /* Restore the status word; we might have loaded a
+ denormal. */
+ partial_status = status1;
+ if ( (FPU_modrm & 0x30) == 0x10 )
+ {
+ /* fcom or fcomp */
+ EXCEPTION(EX_Invalid);
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
+ FPU_pop(); /* fcomp, masked, so we pop. */
+ }
+ else
+ {
+ if ( loaded_tag == TAG_Special )
+ loaded_tag = FPU_Special(&loaded_data);
+#ifdef PECULIAR_486
+ /* This is not really needed, but gives behaviour
+ identical to an 80486 */
+ if ( (FPU_modrm & 0x28) == 0x20 )
+ /* fdiv or fsub */
+ real_2op_NaN(&loaded_data, loaded_tag, 0, &loaded_data);
+ else
+#endif /* PECULIAR_486 */
+ /* fadd, fdivr, fmul, or fsubr */
+ real_2op_NaN(&loaded_data, loaded_tag, 0, st0_ptr);
+ }
+ goto reg_mem_instr_done;
+ }
+
+ if ( unmasked && !((FPU_modrm & 0x30) == 0x10) )
+ {
+ /* Is not a comparison instruction. */
+ if ( (FPU_modrm & 0x38) == 0x38 )
+ {
+ /* fdivr */
+ if ( (st0_tag == TAG_Zero) &&
+ ((loaded_tag == TAG_Valid)
+ || (loaded_tag == TAG_Special
+ && isdenormal(&loaded_data))) )
+ {
+ if ( FPU_divide_by_zero(0, getsign(&loaded_data))
+ < 0 )
+ {
+ /* We use the fact here that the unmasked
+ exception in the loaded data was for a
+ denormal operand */
+ /* Restore the state of the denormal op bit */
+ partial_status &= ~SW_Denorm_Op;
+ partial_status |= status1 & SW_Denorm_Op;
+ }
+ else
+ setsign(st0_ptr, getsign(&loaded_data));
+ }
+ }
+ goto reg_mem_instr_done;
+ }
+
+ switch ( (FPU_modrm >> 3) & 7 )
+ {
+ case 0: /* fadd */
+ clear_C1();
+ FPU_add(&loaded_data, loaded_tag, 0, control_word);
+ break;
+ case 1: /* fmul */
+ clear_C1();
+ FPU_mul(&loaded_data, loaded_tag, 0, control_word);
+ break;
+ case 2: /* fcom */
+ FPU_compare_st_data(&loaded_data, loaded_tag);
+ break;
+ case 3: /* fcomp */
+ // bbd: used to typecase to int first, but this corrupted the
+ // pointer on 64 bit machines.
+ if ( !FPU_compare_st_data(&loaded_data, loaded_tag)
+ && !unmasked )
+ FPU_pop();
+ break;
+ case 4: /* fsub */
+ clear_C1();
+ FPU_sub(LOADED|loaded_tag, &loaded_data, control_word);
+ break;
+ case 5: /* fsubr */
+ clear_C1();
+ FPU_sub(REV|LOADED|loaded_tag, &loaded_data, control_word);
+ break;
+ case 6: /* fdiv */
+ clear_C1();
+ FPU_div(LOADED|loaded_tag, &loaded_data, control_word);
+ break;
+ case 7: /* fdivr */
+ clear_C1();
+ if ( st0_tag == TAG_Zero )
+ partial_status = status1; /* Undo any denorm tag,
+ zero-divide has priority. */
+ FPU_div(REV|LOADED|loaded_tag, &loaded_data, control_word);
+ break;
+ }
+ }
+ else
+ {
+ if ( (FPU_modrm & 0x30) == 0x10 )
+ {
+ /* The instruction is fcom or fcomp */
+ EXCEPTION(EX_StackUnder);
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
+ FPU_pop(); /* fcomp */
+ }
+ else
+ FPU_stack_underflow();
+ }
+ reg_mem_instr_done:
+ operand_address = data_sel_off;
+ }
+ else {
+ if ( !(no_ip_update =
+ FPU_load_store(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1,
+ addr_modes, data_address)) )
+ {
+ operand_address = data_sel_off;
+ }
+ }
+ }
+ else {
+ /* None of these instructions access user memory */
+ u_char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
+
+#ifdef PECULIAR_486
+ /* This is supposed to be undefined, but a real 80486 seems
+ to do this: */
+ operand_address.offset = 0;
+ operand_address.selector = FPU_DS;
+#endif /* PECULIAR_486 */
+
+ st0_ptr = &st(0);
+ st0_tag = FPU_gettag0();
+ switch ( type_table[(int) instr_index] )
+ {
+ case _NONE_: /* also _REGIc: _REGIn */
+ break;
+ case _REG0_:
+ if ( !NOT_EMPTY_ST0 )
+ {
+ FPU_stack_underflow();
+ goto FPU_instruction_done;
+ }
+ break;
+ case _REGIi:
+ if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
+ {
+ FPU_stack_underflow_i(FPU_rm);
+ goto FPU_instruction_done;
+ }
+ break;
+ case _REGIp:
+ if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
+ {
+ FPU_stack_underflow_pop(FPU_rm);
+ goto FPU_instruction_done;
+ }
+ break;
+ case _REGI_:
+ if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
+ {
+ FPU_stack_underflow();
+ goto FPU_instruction_done;
+ }
+ break;
+ case _PUSH_: /* Only used by the fld st(i) instruction */
+ break;
+ case _null_:
+ FPU_illegal();
+ goto FPU_instruction_done;
+ default:
+ EXCEPTION(EX_INTERNAL|0x111);
+ goto FPU_instruction_done;
+ }
+ (*st_instr_table[(int) instr_index])();
+
+FPU_instruction_done:
+ ;
+ }
+
+ if ( ! no_ip_update )
+ instruction_address = entry_sel_off;
+
+FPU_fwait_done:
+
+#ifdef DEBUG
+ FPU_printall();
+#endif /* DEBUG */
+#ifdef BX_NO_BLANK_LABELS
+ if(0);
+#endif
+}
+
+#endif /* #ifndef USE_WITH_CPU_SIM */
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | fpu_etc.c |
+ | |
+ | Implement a few FPU instructions. |
+ | |
+ | Copyright (C) 1992,1993,1994,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@suburbia.net |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#include "fpu_system.h"
+#include "exception.h"
+#include "fpu_emu.h"
+#include "status_w.h"
+#include "reg_constant.h"
+
+
+static void fchs(FPU_REG *st0_ptr, u_char st0tag)
+{
+ if ( st0tag ^ TAG_Empty )
+ {
+ signbyte(st0_ptr) ^= SIGN_NEG;
+ clear_C1();
+ }
+ else
+ FPU_stack_underflow();
+}
+
+
+static void fpu_fabs(FPU_REG *st0_ptr, u_char st0tag)
+{
+ if ( st0tag ^ TAG_Empty )
+ {
+ setpositive(st0_ptr);
+ clear_C1();
+ }
+ else
+ FPU_stack_underflow();
+}
+
+
+static void ftst_(FPU_REG *st0_ptr, u_char st0tag)
+{
+ switch (st0tag)
+ {
+ case TAG_Zero:
+ setcc(SW_C3);
+ break;
+ case TAG_Valid:
+ if (getsign(st0_ptr) == SIGN_POS)
+ setcc(0);
+ else
+ setcc(SW_C0);
+ break;
+ case TAG_Special:
+ switch ( FPU_Special(st0_ptr) )
+ {
+ case TW_Denormal:
+ if (getsign(st0_ptr) == SIGN_POS)
+ setcc(0);
+ else
+ setcc(SW_C0);
+ if ( denormal_operand() < 0 )
+ {
+#ifdef PECULIAR_486
+ /* This is weird! */
+ if (getsign(st0_ptr) == SIGN_POS)
+ setcc(SW_C3);
+#endif /* PECULIAR_486 */
+ return;
+ }
+ break;
+ case TW_NaN:
+ setcc(SW_C0|SW_C2|SW_C3); /* Operand is not comparable */
+ EXCEPTION(EX_Invalid);
+ break;
+ case TW_Infinity:
+ if (getsign(st0_ptr) == SIGN_POS)
+ setcc(0);
+ else
+ setcc(SW_C0);
+ break;
+ default:
+ setcc(SW_C0|SW_C2|SW_C3); /* Operand is not comparable */
+ EXCEPTION(EX_INTERNAL|0x14);
+ break;
+ }
+ break;
+ case TAG_Empty:
+ setcc(SW_C0|SW_C2|SW_C3);
+ EXCEPTION(EX_StackUnder);
+ break;
+ }
+}
+
+
+static void fxam(FPU_REG *st0_ptr, u_char st0tag)
+{
+ int c = 0;
+ switch (st0tag)
+ {
+ case TAG_Empty:
+ c = SW_C3|SW_C0;
+ break;
+ case TAG_Zero:
+ c = SW_C3;
+ break;
+ case TAG_Valid:
+ c = SW_C2;
+ break;
+ case TAG_Special:
+ switch ( FPU_Special(st0_ptr) )
+ {
+ case TW_Denormal:
+ c = SW_C2|SW_C3; /* Denormal */
+ break;
+ case TW_NaN:
+ /* We also use NaN for unsupported types. */
+ if ( (st0_ptr->sigh & 0x80000000) && (exponent(st0_ptr) == EXP_OVER) )
+ c = SW_C0;
+ break;
+ case TW_Infinity:
+ c = SW_C2|SW_C0;
+ break;
+ }
+ }
+ if ( getsign(st0_ptr) == SIGN_NEG )
+ c |= SW_C1;
+ setcc(c);
+}
+
+
+static FUNC_ST0 const fp_etc_table[] = {
+ fchs, fpu_fabs, (FUNC_ST0)FPU_illegal, (FUNC_ST0)FPU_illegal,
+ ftst_, fxam, (FUNC_ST0)FPU_illegal, (FUNC_ST0)FPU_illegal
+};
+
+void FPU_etc()
+{
+ (fp_etc_table[FPU_rm])(&st(0), FPU_gettag0());
+}
--- /dev/null
+#ifndef _FPU_PROTO_H
+#define _FPU_PROTO_H
+
+/* errors.c */
+extern void Un_impl(void);
+extern void FPU_illegal(void);
+extern void FPU_printall(void);
+asmlinkage void FPU_exception(int n);
+extern int real_1op_NaN(FPU_REG *a);
+extern int real_2op_NaN(FPU_REG const *b, u_char tagb, int deststnr,
+ FPU_REG const *defaultNaN);
+extern int arith_invalid(int deststnr);
+extern int FPU_divide_by_zero(int deststnr, u_char sign);
+extern int set_precision_flag(int flags);
+extern void set_precision_flag_up(void);
+extern void set_precision_flag_down(void);
+extern int denormal_operand(void);
+extern int arith_overflow(FPU_REG *dest);
+extern int arith_round_overflow(FPU_REG *dest, u8 sign);
+extern int arith_underflow(FPU_REG *dest);
+extern void FPU_stack_overflow(void);
+extern void FPU_stack_underflow(void);
+extern void FPU_stack_underflow_i(int i);
+extern void FPU_stack_underflow_pop(int i);
+/* fpu_arith.c */
+extern void fadd__(void);
+extern void fmul__(void);
+extern void fsub__(void);
+extern void fsubr_(void);
+extern void fdiv__(void);
+extern void fdivr_(void);
+extern void fadd_i(void);
+extern void fmul_i(void);
+extern void fsubri(void);
+extern void fsub_i(void);
+extern void fdivri(void);
+extern void fdiv_i(void);
+extern void faddp_(void);
+extern void fmulp_(void);
+extern void fsubrp(void);
+extern void fsubp_(void);
+extern void fdivrp(void);
+extern void fdivp_(void);
+/* fpu_aux.c */
+extern void fclex(void);
+extern void finit(void);
+extern void finit_(void);
+extern void fstsw_(void);
+extern void fp_nop(void);
+extern void fld_i_(void);
+extern void fxch_i(void);
+extern void ffree_(void);
+extern void ffreep(void);
+extern void fst_i_(void);
+extern void fstp_i(void);
+/* fpu_entry.c */
+extern void math_emulate(long arg);
+extern void math_abort(struct info *info, unsigned int signal);
+/* fpu_etc.c */
+extern void FPU_etc(void);
+/* fpu_tags.c */
+extern int FPU_gettag0(void);
+extern int FPU_gettagi(int stnr);
+extern int FPU_gettag(int regnr);
+extern void FPU_settag0(int tag);
+extern void FPU_settagi(int stnr, int tag);
+extern void FPU_settag(int regnr, int tag);
+extern int FPU_Special(FPU_REG const *ptr);
+extern int isNaN(FPU_REG const *ptr);
+extern void FPU_pop(void);
+extern int FPU_empty_i(int stnr);
+extern int FPU_stackoverflow(FPU_REG **st_new_ptr);
+extern void FPU_sync_tags(void);
+extern void FPU_copy_to_regi(FPU_REG const *r, u_char tag, int stnr);
+extern void FPU_copy_to_reg1(FPU_REG const *r, u_char tag);
+extern void FPU_copy_to_reg0(FPU_REG const *r, u_char tag);
+/* fpu_trig.c */
+extern void FPU_triga(void);
+extern void FPU_trigb(void);
+/* get_address.c */
+extern void *FPU_get_address(u_char FPU_modrm, u32 *fpu_eip,
+ struct address *addr, fpu_addr_modes addr_modes);
+extern void *FPU_get_address_16(u_char FPU_modrm, u32 *fpu_eip,
+ struct address *addr, fpu_addr_modes addr_modes);
+/* load_store.c */
+extern int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
+ void *data_address);
+/* poly_2xm1.c */
+extern int poly_2xm1(u_char sign, FPU_REG *arg, FPU_REG *result);
+/* poly_atan.c */
+extern void poly_atan(FPU_REG *st0_ptr, u_char st0_tag, FPU_REG *st1_ptr,
+ u_char st1_tag);
+/* poly_l2.c */
+extern void poly_l2(FPU_REG *st0_ptr, FPU_REG *st1_ptr, u_char st1_sign);
+extern int poly_l2p1(u_char s0, u_char s1, FPU_REG *r0, FPU_REG *r1,
+ FPU_REG *d);
+/* poly_sin.c */
+extern void poly_sine(FPU_REG *st0_ptr);
+extern void poly_cos(FPU_REG *st0_ptr);
+/* poly_tan.c */
+extern void poly_tan(FPU_REG *st0_ptr, int flag);
+/* reg_add_sub.c */
+extern int FPU_add(FPU_REG const *b, u_char tagb, int destrnr, u16 control_w);
+extern int FPU_sub(int flags, FPU_REG *rm, u16 control_w); // bbd: changed arg2 from int to FPU_REG*
+/* reg_compare.c */
+extern int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag);
+extern void fcom_st(void);
+extern void fcompst(void);
+extern void fcompp(void);
+extern void fucom_(void);
+extern void fucomp(void);
+extern void fucompp(void);
+/* reg_constant.c */
+extern void fconst(void);
+/* reg_ld_str.c */
+extern int FPU_load_extended(long double *s, int stnr);
+extern int FPU_load_double(double *dfloat, FPU_REG *loaded_data);
+extern int FPU_load_single(float *single, FPU_REG *loaded_data);
+extern int FPU_load_int64(s64 *_s);
+extern int FPU_load_int32(s32 *_s, FPU_REG *loaded_data);
+extern int FPU_load_int16(s16 *_s, FPU_REG *loaded_data);
+extern int FPU_load_bcd(u_char *s);
+extern int FPU_store_extended(FPU_REG *st0_ptr, u_char st0_tag,
+ long double *d);
+extern int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double *dfloat);
+extern int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float *single);
+extern int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, s64 *d);
+extern int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, s32 *d);
+extern int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, s16 *d);
+extern int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char *d);
+extern int FPU_round_to_int(FPU_REG *r, u_char tag);
+extern u_char *fldenv(fpu_addr_modes addr_modes, u_char *s);
+extern void frstor(fpu_addr_modes addr_modes, u_char *data_address);
+extern u_char *fstenv(fpu_addr_modes addr_modes, u_char *d);
+extern void fsave(fpu_addr_modes addr_modes, u_char *data_address);
+extern int FPU_tagof(FPU_REG *ptr);
+/* reg_mul.c */
+extern int FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w);
+
+extern int FPU_div(int flags, FPU_REG *regrm, int control_w); // bbd: changed arg2 from int to FPU_REG*
+/* reg_convert.c */
+extern int FPU_to_exp16(FPU_REG const *a, FPU_REG *x);
+#endif /* _FPU_PROTO_H */
+
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | fpu_system.h |
+ | |
+ | Copyright (C) 1992,1994,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@suburbia.net |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#ifndef _FPU_SYSTEM_H
+#define _FPU_SYSTEM_H
+
+#ifndef USE_WITH_CPU_SIM
+
+/* system dependent definitions */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+
+/* This sets the pointer FPU_info to point to the argument part
+ of the stack frame of math_emulate() */
+#define SETUP_DATA_AREA(arg) FPU_info = (struct info *) &arg
+
+#define LDT_DESCRIPTOR(s) (((struct desc_struct *)current->mm->segments)[(s) >> 3])
+#define SEG_D_SIZE(x) ((x).b & (3 << 21))
+#define SEG_G_BIT(x) ((x).b & (1 << 23))
+#define SEG_GRANULARITY(x) (((x).b & (1 << 23)) ? 4096 : 1)
+#define SEG_286_MODE(x) ((x).b & ( 0xff000000 | 0xf0000 | (1 << 23)))
+#define SEG_BASE_ADDR(s) (((s).b & 0xff000000) \
+ | (((s).b & 0xff) << 16) | ((s).a >> 16))
+#define SEG_LIMIT(s) (((s).b & 0xff0000) | ((s).a & 0xffff))
+#define SEG_EXECUTE_ONLY(s) (((s).b & ((1 << 11) | (1 << 9))) == (1 << 11))
+#define SEG_WRITE_PERM(s) (((s).b & ((1 << 11) | (1 << 9))) == (1 << 9))
+#define SEG_EXPAND_DOWN(s) (((s).b & ((1 << 11) | (1 << 10))) \
+ == (1 << 10))
+
+#define I387 (current->tss.i387)
+#define FPU_info (I387.soft.info)
+
+#define FPU_CS (*(u16 *) &(FPU_info->___cs))
+#define FPU_SS (*(u16 *) &(FPU_info->___ss))
+#define FPU_DS (*(u16 *) &(FPU_info->___ds))
+#define FPU_EAX (FPU_info->___eax)
+#define FPU_EFLAGS (FPU_info->___eflags)
+#define FPU_EIP (FPU_info->___eip)
+#define FPU_ORIG_EIP (FPU_info->___orig_eip)
+
+#define FPU_lookahead (I387.soft.lookahead)
+
+#define SET_AX(val16) *(s16 *) &FPU_EAX = val16
+
+/* nz if ip_offset and cs_selector are not to be set for the current
+ instruction. */
+#define no_ip_update (*(u_char *)&(I387.soft.no_update))
+#define FPU_rm (*(u_char *)&(I387.soft.rm))
+
+/* Number of bytes of data which can be legally accessed by the current
+ instruction. This only needs to hold a number <= 108, so a byte will do. */
+#define access_limit (*(u_char *)&(I387.soft.alimit))
+
+#define partial_status (I387.soft.swd)
+#define control_word (I387.soft.cwd)
+#define fpu_tag_word (I387.soft.twd)
+#define registers (I387.soft.st_space)
+#define top (I387.soft.ftop)
+
+#define instruction_address (*(struct address *)&I387.soft.fip)
+#define operand_address (*(struct address *)&I387.soft.foo)
+
+#define FPU_verify_area(x,y,z) if ( verify_area(x,y,z) ) \
+ math_abort(FPU_info,SIGSEGV)
+
+#undef FPU_IGNORE_CODE_SEGV
+#ifdef FPU_IGNORE_CODE_SEGV
+/* verify_area() is very expensive, and causes the emulator to run
+ about 20% slower if applied to the code. Anyway, errors due to bad
+ code addresses should be much rarer than errors due to bad data
+ addresses. */
+#define FPU_code_verify_area(z)
+#else
+/* A simpler test than verify_area() can probably be done for
+ FPU_code_verify_area() because the only possible error is to step
+ past the upper boundary of a legal code area. */
+#define FPU_code_verify_area(z) FPU_verify_area(VERIFY_READ,(void *)FPU_EIP,z)
+#endif
+
+#define FPU_get_user(x,y) get_user((x),(y))
+#define FPU_put_user(x,y) put_user((x),(y))
+
+#else /* USE_WITH_CPU_SIM */
+
+/* -----------------------------------------------------------
+ * Slimmed down version used to compile against a CPU simulator
+ * rather than a kernel (ported by Kevin Lawton)
+ * ------------------------------------------------------------ */
+
+/* Get data sizes from config.h generated from simulator's
+ * configure script
+ */
+#include "config.h"
+typedef Bit8u u8;
+typedef Bit8s s8;
+typedef Bit16u u16;
+typedef Bit16s s16;
+typedef Bit32u u32;
+typedef Bit32s s32;
+typedef Bit64u u64;
+typedef Bit64s s64;
+
+/* bbd: include ported linux headers after config.h for GCC_ATTRIBUTE macro */
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/math_emu.h>
+#include <linux/types.h>
+
+#ifndef WORDS_BIGENDIAN
+#error "WORDS_BIGENDIAN not defined in config.h"
+#elif WORDS_BIGENDIAN == 1
+#define EMU_BIG_ENDIAN 1
+#else
+/* Nothing needed. Lack of defining EMU_BIG_ENDIAN means
+ * small endian
+ */
+#endif
+
+
+extern unsigned fpu_get_user(void *ptr, unsigned len);
+extern void fpu_put_user(unsigned val, void *ptr, unsigned len);
+
+extern void fpu_verify_area(unsigned what, void *ptr, unsigned n);
+extern void math_emulate_init(void);
+extern unsigned fpu_get_ds(void);
+extern void fpu_set_ax(u16);
+
+#ifndef __ASSEMBLY__
+
+struct info {
+#ifdef BX_NO_EMPTY_STRUCTS
+ unsigned char donotindexme;
+#endif
+ };
+
+#define FPU_info ((struct info *) NULL)
+
+
+//
+// Minimal i387 structure, pruned from the linux headers. Only
+// the fields which were necessary are included.
+//
+typedef struct {
+ struct {
+ s32 cwd;
+ s32 swd;
+ s32 twd;
+ s32 fip;
+ s32 fcs;
+ s32 foo;
+ s32 fos;
+ u32 fill0; /* to make sure the following aligns on an 8byte boundary */
+ u64 st_space[16]; /* 8*16 bytes per FP-reg (aligned) = 128 bytes */
+ unsigned char ftop;
+ unsigned char no_update;
+ unsigned char rm;
+ unsigned char alimit;
+ } GCC_ATTRIBUTE((aligned(16), packed)) soft;
+ } i387_t;
+
+extern i387_t i387;
+
+
+#endif
+
+#define SIGSEGV 11
+
+#define I387 i387
+
+
+#define SET_AX(val16) fpu_set_ax(val16);
+
+#define no_ip_update (*(u_char *)&(I387.soft.no_update))
+#define FPU_rm (*(u_char *)&(I387.soft.rm))
+
+
+/* Number of bytes of data which can be legally accessed by the current
+ instruction. This only needs to hold a number <= 108, so a byte will do. */
+#define access_limit (*(u_char *)&(I387.soft.alimit))
+
+#define partial_status (I387.soft.swd)
+#define control_word (I387.soft.cwd)
+#define fpu_tag_word (I387.soft.twd)
+#define registers (I387.soft.st_space)
+#define top (I387.soft.ftop)
+
+#define instruction_address (*(struct address *)&I387.soft.fip)
+#define operand_address (*(struct address *)&I387.soft.foo)
+
+#define FPU_verify_area(x,y,z) fpu_verify_area(x,y,z)
+#define FPU_get_user(x,y) ((x) = fpu_get_user((y), sizeof(*(y))))
+#define FPU_put_user(val,ptr) fpu_put_user((val),(ptr),sizeof(*(ptr)))
+
+#define FPU_DS (fpu_get_ds())
+
+#endif /* USE_WITH_CPU_SIM */
+
+// bbd: Change a pointer to an int, with type conversions that make it legal.
+// First make it a void pointer, then convert to an integer of the same
+// size as the pointer. Otherwise, on machines with 64-bit pointers,
+// compilers complain when you typecast a 64-bit pointer into a 32-bit integer.
+#define PTR2INT(x) ((bx_ptr_equiv_t)(void *)(x))
+
+// bbd: Change an int to a pointer, with type conversions that make it legal.
+// Same strategy as PTR2INT: change to bx_ptr_equiv_t which is an integer
+// type of the same size as FPU_REG*. Then the conversion to pointer
+// is legal.
+#define REGNO2PTR(x) ((FPU_REG*)((bx_ptr_equiv_t)(x)))
+
+#endif
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | fpu_tags.c |
+ | |
+ | Set FPU register tags. |
+ | |
+ | Copyright (C) 1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@jacobi.maths.monash.edu.au |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "exception.h"
+
+
+void FPU_pop(void)
+{
+ fpu_tag_word |= 3 << ((top & 7)*2);
+ top++;
+}
+
+
+int FPU_gettag0(void)
+{
+ return (fpu_tag_word >> ((top & 7)*2)) & 3;
+}
+
+
+int FPU_gettagi(int stnr)
+{
+ return (fpu_tag_word >> (((top+stnr) & 7)*2)) & 3;
+}
+
+
+int FPU_gettag(int regnr)
+{
+ return (fpu_tag_word >> ((regnr & 7)*2)) & 3;
+}
+
+
+void FPU_settag0(int tag)
+{
+ int regnr = top;
+ regnr &= 7;
+ fpu_tag_word &= ~(3 << (regnr*2));
+ fpu_tag_word |= (tag & 3) << (regnr*2);
+}
+
+
+void FPU_settagi(int stnr, int tag)
+{
+ int regnr = stnr+top;
+ regnr &= 7;
+ fpu_tag_word &= ~(3 << (regnr*2));
+ fpu_tag_word |= (tag & 3) << (regnr*2);
+}
+
+
+void FPU_settag(int regnr, int tag)
+{
+ regnr &= 7;
+ fpu_tag_word &= ~(3 << (regnr*2));
+ fpu_tag_word |= (tag & 3) << (regnr*2);
+}
+
+
+int FPU_Special(FPU_REG const *ptr)
+{
+ int exp = exponent(ptr);
+
+ if ( exp == EXP_BIAS+EXP_UNDER )
+ return TW_Denormal;
+ else if ( exp != EXP_BIAS+EXP_OVER )
+ return TW_NaN;
+ else if ( (ptr->sigh == 0x80000000) && (ptr->sigl == 0) )
+ return TW_Infinity;
+ return TW_NaN;
+}
+
+
+int isNaN(FPU_REG const *ptr)
+{
+ return ( (exponent(ptr) == EXP_BIAS+EXP_OVER)
+ && !((ptr->sigh == 0x80000000) && (ptr->sigl == 0)) );
+}
+
+
+int FPU_empty_i(int stnr)
+{
+ int regnr = (top+stnr) & 7;
+
+ return ((fpu_tag_word >> (regnr*2)) & 3) == TAG_Empty;
+}
+
+
+int FPU_stackoverflow(FPU_REG **st_new_ptr)
+{
+ *st_new_ptr = &st(-1);
+
+ return ((fpu_tag_word >> (((top - 1) & 7)*2)) & 3) != TAG_Empty;
+}
+
+
+void FPU_copy_to_regi(FPU_REG const *r, u_char tag, int stnr)
+{
+ reg_copy(r, &st(stnr));
+ FPU_settagi(stnr, tag);
+}
+
+void FPU_copy_to_reg1(FPU_REG const *r, u_char tag)
+{
+ reg_copy(r, &st(1));
+ FPU_settagi(1, tag);
+}
+
+void FPU_copy_to_reg0(FPU_REG const *r, u_char tag)
+{
+ int regnr = top;
+ regnr &= 7;
+
+ reg_copy(r, &st(0));
+
+ fpu_tag_word &= ~(3 << (regnr*2));
+ fpu_tag_word |= (tag & 3) << (regnr*2);
+}
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | fpu_trig.c |
+ | |
+ | Implementation of the FPU "transcendental" functions. |
+ | |
+ | Copyright (C) 1992,1993,1994,1997,1999 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@melbpc.org.au |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#include "fpu_system.h"
+#include "exception.h"
+#include "fpu_emu.h"
+#include "status_w.h"
+#include "control_w.h"
+#include "reg_constant.h"
+
+static void rem_kernel(u64 st0, u64 *y, u64 st1, u64 q, int n);
+
+#define BETTER_THAN_486
+
+#define FCOS 4
+#define FPTAN 8
+
+/* Used only by fptan, fsin, fcos, and fsincos. */
+/* This routine produces very accurate results, similar to
+ using a value of pi with more than 128 bits precision. */
+/* Limited measurements show no results worse than 64 bit precision
+ except for the results for arguments close to 2^63, where the
+ precision of the result sometimes degrades to about 63.9 bits */
+static int trig_arg(FPU_REG *st0_ptr, int flags)
+{
+ FPU_REG tmp;
+ u_char tmptag;
+ u64 q;
+ int old_cw = control_word, saved_status = partial_status;
+ int tag, st0_tag = TAG_Valid;
+
+ if ( exponent(st0_ptr) >= 63 )
+ {
+ partial_status |= SW_C2; /* Reduction incomplete. */
+ return -1;
+ }
+
+ if ( flags & FPTAN )
+ st0_ptr->exp ++; /* Effectively base the following upon pi/4 */
+
+ control_word &= ~CW_RC;
+ control_word |= RC_CHOP;
+
+ setpositive(st0_ptr);
+ tag = FPU_u_div(st0_ptr,
+ &CONST_PI2,
+ &tmp, PR_64_BITS | RC_CHOP | 0x3f, SIGN_POS);
+
+ FPU_round_to_int(&tmp, tag); /* Fortunately, this can't overflow
+ to 2^64 */
+ q = significand(&tmp);
+
+ if ( q )
+ {
+ rem_kernel(significand(st0_ptr),
+ &significand(&tmp),
+ significand(&CONST_PI2),
+ q, exponent(st0_ptr) - exponent(&CONST_PI2));
+ setexponent16(&tmp, exponent(&CONST_PI2));
+ st0_tag = FPU_normalize_nuo(&tmp,
+ EXTENDED_Ebias); /* No underflow or overflow
+ is possible */
+
+ FPU_copy_to_reg0(&tmp, st0_tag);
+ }
+
+ if ( ((flags & FCOS) && !(q & 1)) || (!(flags & FCOS) && (q & 1)) )
+ {
+ st0_tag = FPU_sub(REV|LOADED|TAG_Valid, &CONST_PI2, FULL_PRECISION); //bbd: arg2 used to typecast to (int)
+
+#ifdef BETTER_THAN_486
+ /* So far, the results are exact but based upon a 64 bit
+ precision approximation to pi/2. The technique used
+ now is equivalent to using an approximation to pi/2 which
+ is accurate to about 128 bits. */
+ if ( (exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64) || (q > 1) )
+ {
+ /* This code gives the effect of having pi/2 to better than
+ 128 bits precision. */
+
+ significand(&tmp) = q + 1;
+ setexponent16(&tmp, 63);
+ FPU_normalize_nuo(&tmp,
+ EXTENDED_Ebias); /* No underflow or overflow
+ is possible */
+ tmptag =
+ FPU_u_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION, SIGN_POS,
+ exponent(&CONST_PI2extra) + exponent(&tmp));
+ setsign(&tmp, getsign(&CONST_PI2extra));
+ st0_tag = FPU_add(&tmp, tmptag, 0, FULL_PRECISION);
+ if ( signnegative(st0_ptr) && !(flags & FPTAN) )
+ {
+ /* CONST_PI2extra is negative, so the result of the addition
+ can be negative. This means that the argument is actually
+ in a different quadrant. The correction is always < pi/2,
+ so it can't overflow into yet another quadrant. */
+ /* The function is even, so we need just adjust the sign
+ and q. */
+ setpositive(st0_ptr);
+ q++;
+ }
+ }
+#endif /* BETTER_THAN_486 */
+ }
+#ifdef BETTER_THAN_486
+ else
+ {
+ /* So far, the results are exact but based upon a 64 bit
+ precision approximation to pi/2. The technique used
+ now is equivalent to using an approximation to pi/2 which
+ is accurate to about 128 bits. */
+ if ( ((q > 0)
+ && (exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64))
+ || (q > 1) )
+ {
+ /* This code gives the effect of having p/2 to better than
+ 128 bits precision. */
+
+ significand(&tmp) = q;
+ setexponent16(&tmp, 63);
+ FPU_normalize_nuo(&tmp,
+ EXTENDED_Ebias); /* No underflow or overflow
+ is possible.
+ This must return TAG_Valid */
+ tmptag = FPU_u_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION,
+ SIGN_POS,
+ exponent(&CONST_PI2extra) + exponent(&tmp));
+ setsign(&tmp, getsign(&CONST_PI2extra));
+ st0_tag = FPU_sub(LOADED|(tmptag & 0x0f), &tmp,
+ FULL_PRECISION);
+ if ( (exponent(st0_ptr) == exponent(&CONST_PI2)) &&
+ ((st0_ptr->sigh > CONST_PI2.sigh)
+ || ((st0_ptr->sigh == CONST_PI2.sigh)
+ && (st0_ptr->sigl > CONST_PI2.sigl))) )
+ {
+ /* CONST_PI2extra is negative, so the result of the
+ subtraction can be larger than pi/2. This means
+ that the argument is actually in a different quadrant.
+ The correction is always < pi/2, so it can't overflow
+ into yet another quadrant.
+ bbd: arg2 used to typecast to (int), corrupting 64-bit ptrs
+ */
+ st0_tag = FPU_sub(REV|LOADED|TAG_Valid, &CONST_PI2,
+ FULL_PRECISION);
+ q++;
+ }
+ }
+ }
+#endif /* BETTER_THAN_486 */
+
+ FPU_settag0(st0_tag);
+ control_word = old_cw;
+ partial_status = saved_status & ~SW_C2; /* Reduction complete. */
+
+ if ( flags & FPTAN )
+ {
+ st0_ptr->exp --;
+ return q & 7;
+ }
+
+ return (q & 3) | (flags & FCOS);
+}
+
+
+/* Convert a s32 to register */
+static void convert_l2reg(s32 const *arg, int deststnr)
+{
+ int tag;
+ s32 num = *arg;
+ u_char sign;
+ FPU_REG *dest = &st(deststnr);
+
+ if (num == 0)
+ {
+ FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
+ return;
+ }
+
+ if (num > 0)
+ { sign = SIGN_POS; }
+ else
+ { num = -num; sign = SIGN_NEG; }
+
+ dest->sigh = num;
+ dest->sigl = 0;
+ setexponent16(dest, 31);
+ tag = FPU_normalize_nuo(dest,
+ EXTENDED_Ebias); /* No underflow or overflow
+ is possible */
+ FPU_settagi(deststnr, tag);
+ setsign(dest, sign);
+ return;
+}
+
+
+static void single_arg_error(FPU_REG *st0_ptr, u_char st0_tag)
+{
+ if ( st0_tag == TAG_Empty )
+ FPU_stack_underflow(); /* Puts a QNaN in st(0) */
+ else if ( st0_tag == TW_NaN )
+ real_1op_NaN(st0_ptr); /* return with a NaN in st(0) */
+#ifdef PARANOID
+ else
+ EXCEPTION(EX_INTERNAL|0x0112);
+#endif /* PARANOID */
+}
+
+
+static void single_arg_2_error(FPU_REG *st0_ptr, u_char st0_tag)
+{
+ int isNaN;
+
+ switch ( st0_tag )
+ {
+ case TW_NaN:
+ isNaN = (exponent(st0_ptr) == EXP_OVER) && (st0_ptr->sigh & 0x80000000);
+ if ( isNaN && !(st0_ptr->sigh & 0x40000000) ) /* Signaling ? */
+ {
+ EXCEPTION(EX_Invalid);
+ if ( control_word & CW_Invalid )
+ {
+ /* The masked response */
+ /* Convert to a QNaN */
+ st0_ptr->sigh |= 0x40000000;
+ push();
+ FPU_copy_to_reg0(st0_ptr, TAG_Special);
+ }
+ }
+ else if ( isNaN )
+ {
+ /* A QNaN */
+ push();
+ FPU_copy_to_reg0(st0_ptr, TAG_Special);
+ }
+ else
+ {
+ /* pseudoNaN or other unsupported */
+ EXCEPTION(EX_Invalid);
+ if ( control_word & CW_Invalid )
+ {
+ /* The masked response */
+ FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
+ push();
+ FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
+ }
+ }
+ break; /* return with a NaN in st(0) */
+#ifdef PARANOID
+ default:
+ EXCEPTION(EX_INTERNAL|0x0112);
+#endif /* PARANOID */
+ }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+static void f2xm1(FPU_REG *st0_ptr, u_char tag)
+{
+ FPU_REG a;
+
+ clear_C1();
+
+ if ( tag == TAG_Valid )
+ {
+ /* For an 80486 FPU, the result is undefined if the arg is >= 1.0 */
+ if ( exponent(st0_ptr) < 0 )
+ {
+ denormal_arg:
+
+ FPU_to_exp16(st0_ptr, &a);
+
+ /* poly_2xm1(x) requires 0 < st(0) < 1. */
+ poly_2xm1(getsign(st0_ptr), &a, st0_ptr);
+ }
+ set_precision_flag_up(); /* 80486 appears to always do this */
+ return;
+ }
+
+ if ( tag == TAG_Zero )
+ return;
+
+ if ( tag == TAG_Special )
+ tag = FPU_Special(st0_ptr);
+
+ switch ( tag )
+ {
+ case TW_Denormal:
+ if ( denormal_operand() < 0 )
+ return;
+ goto denormal_arg;
+ case TW_Infinity:
+ if ( signnegative(st0_ptr) )
+ {
+ /* -infinity gives -1 (p16-10) */
+ FPU_copy_to_reg0(&CONST_1, TAG_Valid);
+ setnegative(st0_ptr);
+ }
+ return;
+ default:
+ single_arg_error(st0_ptr, tag);
+ }
+}
+
+
+static void fptan(FPU_REG *st0_ptr, u_char st0_tag)
+{
+ FPU_REG *st_new_ptr;
+ u32 q;
+ u_char arg_sign = getsign(st0_ptr);
+ int invert[] = { 0, 1, 1, 0, 0, 1, 1, 0 };
+
+ /* Stack underflow has higher priority */
+ if ( st0_tag == TAG_Empty )
+ {
+ FPU_stack_underflow(); /* Puts a QNaN in st(0) */
+ if ( control_word & CW_Invalid )
+ {
+ st_new_ptr = &st(-1);
+ push();
+ FPU_stack_underflow(); /* Puts a QNaN in the new st(0) */
+ }
+ return;
+ }
+
+ if ( STACK_OVERFLOW )
+ { FPU_stack_overflow(); return; }
+
+ if ( st0_tag == TAG_Valid )
+ {
+ if ( exponent(st0_ptr) > -40 )
+ {
+ if ( (q = trig_arg(st0_ptr, FPTAN)) == -1 )
+ {
+ /* Operand is out of range */
+ return;
+ }
+
+ poly_tan(st0_ptr, invert[q]);
+ setsign(st0_ptr, ((q & 2) != 0) ^ (arg_sign != 0));
+ set_precision_flag_up(); /* We do not really know if up or down */
+ }
+ else
+ {
+ /* For a small arg, the result == the argument */
+ /* Underflow may happen */
+
+ denormal_arg:
+
+ FPU_to_exp16(st0_ptr, st0_ptr);
+
+ st0_tag = FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign);
+ FPU_settag0(st0_tag);
+ }
+ push();
+ FPU_copy_to_reg0(&CONST_1, TAG_Valid);
+ return;
+ }
+
+ if ( st0_tag == TAG_Zero )
+ {
+ push();
+ FPU_copy_to_reg0(&CONST_1, TAG_Valid);
+ setcc(0);
+ return;
+ }
+
+ if ( st0_tag == TAG_Special )
+ st0_tag = FPU_Special(st0_ptr);
+
+ if ( st0_tag == TW_Denormal )
+ {
+ if ( denormal_operand() < 0 )
+ return;
+
+ goto denormal_arg;
+ }
+
+ if ( st0_tag == TW_Infinity )
+ {
+ /* The 80486 treats infinity as an invalid operand */
+ if ( arith_invalid(0) >= 0 )
+ {
+ st_new_ptr = &st(-1);
+ push();
+ arith_invalid(0);
+ }
+ return;
+ }
+
+ single_arg_2_error(st0_ptr, st0_tag);
+}
+
+
+static void fxtract(FPU_REG *st0_ptr, u_char st0_tag)
+{
+ FPU_REG *st_new_ptr;
+ u_char sign;
+ register FPU_REG *st1_ptr = st0_ptr; /* anticipate */
+
+ if ( STACK_OVERFLOW )
+ { FPU_stack_overflow(); return; }
+
+ clear_C1();
+
+ if ( st0_tag == TAG_Valid )
+ {
+ s32 e;
+
+ push();
+ sign = getsign(st1_ptr);
+ reg_copy(st1_ptr, st_new_ptr);
+ setexponent16(st_new_ptr, exponent(st_new_ptr));
+
+ denormal_arg:
+
+ e = exponent16(st_new_ptr);
+ convert_l2reg(&e, 1);
+ setexponentpos(st_new_ptr, 0);
+ setsign(st_new_ptr, sign);
+ FPU_settag0(TAG_Valid); /* Needed if arg was a denormal */
+ return;
+ }
+ else if ( st0_tag == TAG_Zero )
+ {
+ sign = getsign(st0_ptr);
+
+ if ( FPU_divide_by_zero(0, SIGN_NEG) < 0 )
+ return;
+
+ push();
+ FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
+ setsign(st_new_ptr, sign);
+ return;
+ }
+
+ if ( st0_tag == TAG_Special )
+ st0_tag = FPU_Special(st0_ptr);
+
+ if ( st0_tag == TW_Denormal )
+ {
+ if (denormal_operand() < 0 )
+ return;
+
+ push();
+ sign = getsign(st1_ptr);
+ FPU_to_exp16(st1_ptr, st_new_ptr);
+ goto denormal_arg;
+ }
+ else if ( st0_tag == TW_Infinity )
+ {
+ sign = getsign(st0_ptr);
+ setpositive(st0_ptr);
+ push();
+ FPU_copy_to_reg0(&CONST_INF, TAG_Special);
+ setsign(st_new_ptr, sign);
+ return;
+ }
+ else if ( st0_tag == TW_NaN )
+ {
+ if ( real_1op_NaN(st0_ptr) < 0 )
+ return;
+
+ push();
+ FPU_copy_to_reg0(st0_ptr, TAG_Special);
+ return;
+ }
+ else if ( st0_tag == TAG_Empty )
+ {
+ /* Is this the correct behaviour? */
+ if ( control_word & EX_Invalid )
+ {
+ FPU_stack_underflow();
+ push();
+ FPU_stack_underflow();
+ }
+ else
+ EXCEPTION(EX_StackUnder);
+ }
+#ifdef PARANOID
+ else
+ EXCEPTION(EX_INTERNAL | 0x119);
+#endif /* PARANOID */
+}
+
+
+static void fdecstp(void)
+{
+ clear_C1();
+ top--;
+}
+
+static void fincstp(void)
+{
+ clear_C1();
+ top++;
+}
+
+
+static void fsqrt_(FPU_REG *st0_ptr, u_char st0_tag)
+{
+ int expon;
+
+ clear_C1();
+
+ if ( st0_tag == TAG_Valid )
+ {
+ u_char tag;
+
+ if (signnegative(st0_ptr))
+ {
+ arith_invalid(0); /* sqrt(negative) is invalid */
+ return;
+ }
+
+ /* make st(0) in [1.0 .. 4.0) */
+ expon = exponent(st0_ptr);
+
+ denormal_arg:
+
+ setexponent16(st0_ptr, (expon & 1));
+
+ /* Do the computation, the sign of the result will be positive. */
+ tag = wm_sqrt(st0_ptr, 0, 0, control_word, SIGN_POS);
+ addexponent(st0_ptr, expon >> 1);
+ FPU_settag0(tag);
+ return;
+ }
+
+ if ( st0_tag == TAG_Zero )
+ return;
+
+ if ( st0_tag == TAG_Special )
+ st0_tag = FPU_Special(st0_ptr);
+
+ if ( st0_tag == TW_Infinity )
+ {
+ if ( signnegative(st0_ptr) )
+ arith_invalid(0); /* sqrt(-Infinity) is invalid */
+ return;
+ }
+ else if ( st0_tag == TW_Denormal )
+ {
+ if (signnegative(st0_ptr))
+ {
+ arith_invalid(0); /* sqrt(negative) is invalid */
+ return;
+ }
+
+ if ( denormal_operand() < 0 )
+ return;
+
+ FPU_to_exp16(st0_ptr, st0_ptr);
+
+ expon = exponent16(st0_ptr);
+
+ goto denormal_arg;
+ }
+
+ single_arg_error(st0_ptr, st0_tag);
+
+}
+
+
+static void frndint_(FPU_REG *st0_ptr, u_char st0_tag)
+{
+ int flags, tag;
+
+ if ( st0_tag == TAG_Valid )
+ {
+ u_char sign;
+
+ denormal_arg:
+
+ sign = getsign(st0_ptr);
+
+ if (exponent(st0_ptr) > 63)
+ return;
+
+ if ( st0_tag == TW_Denormal )
+ {
+ if (denormal_operand() < 0 )
+ return;
+ }
+
+ /* Fortunately, this can't overflow to 2^64 */
+ if ( (flags = FPU_round_to_int(st0_ptr, st0_tag)) )
+ set_precision_flag(flags);
+
+ setexponent16(st0_ptr, 63);
+ tag = FPU_normalize_nuo(st0_ptr,
+ EXTENDED_Ebias); /* No underflow or overflow
+ is possible */
+ setsign(st0_ptr, sign);
+ FPU_settag0(tag);
+ return;
+ }
+
+ if ( st0_tag == TAG_Zero )
+ return;
+
+ if ( st0_tag == TAG_Special )
+ st0_tag = FPU_Special(st0_ptr);
+
+ if ( st0_tag == TW_Denormal )
+ goto denormal_arg;
+ else if ( st0_tag == TW_Infinity )
+ return;
+ else
+ single_arg_error(st0_ptr, st0_tag);
+}
+
+
+static int fsin(FPU_REG *st0_ptr, u_char tag)
+{
+ u_char arg_sign = getsign(st0_ptr);
+
+ if ( tag == TAG_Valid )
+ {
+ u32 q;
+
+ if ( exponent(st0_ptr) > -40 )
+ {
+ if ( (q = trig_arg(st0_ptr, 0)) == -1 )
+ {
+ /* Operand is out of range */
+ return 1;
+ }
+
+ poly_sine(st0_ptr);
+
+ if (q & 2)
+ changesign(st0_ptr);
+
+ setsign(st0_ptr, getsign(st0_ptr) ^ arg_sign);
+
+ /* We do not really know if up or down */
+ set_precision_flag_up();
+ return 0;
+ }
+ else
+ {
+ /* For a small arg, the result == the argument */
+ set_precision_flag_up(); /* Must be up. */
+ return 0;
+ }
+ }
+
+ if ( tag == TAG_Zero )
+ {
+ setcc(0);
+ return 0;
+ }
+
+ if ( tag == TAG_Special )
+ tag = FPU_Special(st0_ptr);
+
+ if ( tag == TW_Denormal )
+ {
+ if ( denormal_operand() < 0 )
+ return 1;
+
+ /* For a small arg, the result == the argument */
+ /* Underflow may happen */
+ FPU_to_exp16(st0_ptr, st0_ptr);
+
+ tag = FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign);
+
+ FPU_settag0(tag);
+
+ return 0;
+ }
+ else if ( tag == TW_Infinity )
+ {
+ /* The 80486 treats infinity as an invalid operand */
+ arith_invalid(0);
+ return 1;
+ }
+ else
+ {
+ single_arg_error(st0_ptr, tag);
+ return 1;
+ }
+}
+
+
+static int f_cos(FPU_REG *st0_ptr, u_char tag)
+{
+ u_char st0_sign;
+
+ st0_sign = getsign(st0_ptr);
+
+ if ( tag == TAG_Valid )
+ {
+ u32 q;
+
+ if ( exponent(st0_ptr) > -40 )
+ {
+ if ( (exponent(st0_ptr) < 0)
+ || ((exponent(st0_ptr) == 0)
+ && (significand(st0_ptr) <= BX_CONST64(0xc90fdaa22168c234))) )
+ {
+ poly_cos(st0_ptr);
+
+ /* We do not really know if up or down */
+ set_precision_flag_down();
+
+ return 0;
+ }
+ else if ( (q = trig_arg(st0_ptr, FCOS)) != -1 )
+ {
+ poly_sine(st0_ptr);
+
+ if ((q+1) & 2)
+ changesign(st0_ptr);
+
+ /* We do not really know if up or down */
+ set_precision_flag_down();
+
+ return 0;
+ }
+ else
+ {
+ /* Operand is out of range */
+ return 1;
+ }
+ }
+ else
+ {
+ denormal_arg:
+
+ setcc(0);
+ FPU_copy_to_reg0(&CONST_1, TAG_Valid);
+#ifdef PECULIAR_486
+ set_precision_flag_down(); /* 80486 appears to do this. */
+#else
+ set_precision_flag_up(); /* Must be up. */
+#endif /* PECULIAR_486 */
+ return 0;
+ }
+ }
+ else if ( tag == TAG_Zero )
+ {
+ FPU_copy_to_reg0(&CONST_1, TAG_Valid);
+ setcc(0);
+ return 0;
+ }
+
+ if ( tag == TAG_Special )
+ tag = FPU_Special(st0_ptr);
+
+ if ( tag == TW_Denormal )
+ {
+ if ( denormal_operand() < 0 )
+ return 1;
+
+ goto denormal_arg;
+ }
+ else if ( tag == TW_Infinity )
+ {
+ /* The 80486 treats infinity as an invalid operand */
+ arith_invalid(0);
+ return 1;
+ }
+ else
+ {
+ single_arg_error(st0_ptr, tag); /* requires st0_ptr == &st(0) */
+ return 1;
+ }
+}
+
+
+static void fcos(FPU_REG *st0_ptr, u_char st0_tag)
+{
+ f_cos(st0_ptr, st0_tag);
+}
+
+
+static void fsincos(FPU_REG *st0_ptr, u_char st0_tag)
+{
+ FPU_REG *st_new_ptr;
+ FPU_REG arg;
+ u_char tag;
+
+ /* Stack underflow has higher priority */
+ if ( st0_tag == TAG_Empty )
+ {
+ FPU_stack_underflow(); /* Puts a QNaN in st(0) */
+ if ( control_word & CW_Invalid )
+ {
+ st_new_ptr = &st(-1);
+ push();
+ FPU_stack_underflow(); /* Puts a QNaN in the new st(0) */
+ }
+ return;
+ }
+
+ if ( STACK_OVERFLOW )
+ { FPU_stack_overflow(); return; }
+
+ if ( st0_tag == TAG_Special )
+ tag = FPU_Special(st0_ptr);
+ else
+ tag = st0_tag;
+
+ if ( tag == TW_NaN )
+ {
+ single_arg_2_error(st0_ptr, TW_NaN);
+ return;
+ }
+ else if ( tag == TW_Infinity )
+ {
+ /* The 80486 treats infinity as an invalid operand */
+ if ( arith_invalid(0) >= 0 )
+ {
+ /* Masked response */
+ push();
+ arith_invalid(0);
+ }
+ return;
+ }
+
+ reg_copy(st0_ptr, &arg);
+ if ( !fsin(st0_ptr, st0_tag) )
+ {
+ push();
+ FPU_copy_to_reg0(&arg, st0_tag);
+ f_cos(&st(0), st0_tag);
+ }
+ else
+ {
+ /* An error, so restore st(0) */
+ FPU_copy_to_reg0(&arg, st0_tag);
+ }
+}
+
+
+/*---------------------------------------------------------------------------*/
+/* The following all require two arguments: st(0) and st(1) */
+
+/* A lean, mean kernel for the fprem instructions. This relies upon
+ the division and rounding to an integer in do_fprem giving an
+ exact result. Because of this, rem_kernel() needs to deal only with
+ the least significant 64 bits, the more significant bits of the
+ result must be zero.
+ */
+static void rem_kernel(u64 st0, u64 *y, u64 st1, u64 q, int n)
+{
+ u64 x;
+
+#ifdef NO_ASSEMBLER
+ u64 work;
+
+ x = st0 << n;
+
+ work = (u32)st1;
+ work *= (u32)q;
+ x -= work;
+
+ work = st1 >> 32;
+ work *= (u32)q;
+ x -= work;
+
+ work = (u32)st1;
+ work *= q >> 32;
+ x -= work;
+
+#else
+ int dummy;
+
+ x = st0 << n;
+
+ /* Do the required multiplication and subtraction in the one operation */
+
+ /* lsw x -= lsw st1 * lsw q */
+ asm volatile ("mull %4; subl %%eax,%0; sbbl %%edx,%1"
+ :"=m" (((u32 *)&x)[0]), "=m" (((u32 *)&x)[1]),
+ "=a" (dummy)
+ :"2" (((u32 *)&st1)[0]), "m" (((u32 *)&q)[0])
+ :"%dx");
+ /* msw x -= msw st1 * lsw q */
+ asm volatile ("mull %3; subl %%eax,%0"
+ :"=m" (((u32 *)&x)[1]), "=a" (dummy)
+ :"1" (((u32 *)&st1)[1]), "m" (((u32 *)&q)[0])
+ :"%dx");
+ /* msw x -= lsw st1 * msw q */
+ asm volatile ("mull %3; subl %%eax,%0"
+ :"=m" (((u32 *)&x)[1]), "=a" (dummy)
+ :"1" (((u32 *)&st1)[0]), "m" (((u32 *)&q)[1])
+ :"%dx");
+#endif
+
+ *y = x;
+}
+
+
+/* Remainder of st(0) / st(1) */
+/* This routine produces exact results, i.e. there is never any
+ rounding or truncation, etc of the result. */
+static void do_fprem(FPU_REG *st0_ptr, u_char st0_tag, int round)
+{
+ FPU_REG *st1_ptr = &st(1);
+ u_char st1_tag = FPU_gettagi(1);
+
+ if ( !((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid)) )
+ {
+ FPU_REG tmp, st0, st1;
+ u_char st0_sign, st1_sign;
+ u_char tmptag;
+ int tag;
+ int old_cw;
+ int expdif;
+ s64 q;
+ u16 saved_status;
+ int cc;
+
+ fprem_valid:
+ /* Convert registers for internal use. */
+ st0_sign = FPU_to_exp16(st0_ptr, &st0);
+ st1_sign = FPU_to_exp16(st1_ptr, &st1);
+ expdif = exponent16(&st0) - exponent16(&st1);
+
+ old_cw = control_word;
+ cc = 0;
+
+ /* We want the status following the denorm tests, but don't want
+ the status changed by the arithmetic operations. */
+ saved_status = partial_status;
+ control_word &= ~CW_RC;
+ control_word |= RC_CHOP;
+
+ if ( expdif < 64 )
+ {
+ /* This should be the most common case */
+
+ if ( expdif > -2 )
+ {
+ u_char sign = st0_sign ^ st1_sign;
+ tag = FPU_u_div(&st0, &st1, &tmp,
+ PR_64_BITS | RC_CHOP | 0x3f,
+ sign);
+ setsign(&tmp, sign);
+
+ if ( exponent(&tmp) >= 0 )
+ {
+ FPU_round_to_int(&tmp, tag); /* Fortunately, this can't
+ overflow to 2^64 */
+ q = significand(&tmp);
+
+ rem_kernel(significand(&st0),
+ &significand(&tmp),
+ significand(&st1),
+ q, expdif);
+
+ setexponent16(&tmp, exponent16(&st1));
+ }
+ else
+ {
+ reg_copy(&st0, &tmp);
+ q = 0;
+ }
+
+ if ( (round == RC_RND) && (tmp.sigh & 0xc0000000) )
+ {
+ /* We may need to subtract st(1) once more,
+ to get a result <= 1/2 of st(1). */
+ u64 x;
+ expdif = exponent16(&st1) - exponent16(&tmp);
+ if ( expdif <= 1 )
+ {
+ if ( expdif == 0 )
+ x = significand(&st1) - significand(&tmp);
+ else /* expdif is 1 */
+ x = (significand(&st1) << 1) - significand(&tmp);
+ if ( (x < significand(&tmp)) ||
+ /* or equi-distant (from 0 & st(1)) and q is odd */
+ ((x == significand(&tmp)) && (q & 1) ) )
+ {
+ st0_sign = ! st0_sign;
+ significand(&tmp) = x;
+ q++;
+ }
+ }
+ }
+
+ if (q & 4) cc |= SW_C0;
+ if (q & 2) cc |= SW_C3;
+ if (q & 1) cc |= SW_C1;
+ }
+ else
+ {
+ control_word = old_cw;
+ setcc(0);
+ return;
+ }
+ }
+ else
+ {
+ /* There is a large exponent difference ( >= 64 ) */
+ /* To make much sense, the code in this section should
+ be done at high precision. */
+ int exp_1, N;
+ u_char sign;
+
+ /* prevent overflow here */
+ /* N is 'a number between 32 and 63' (p26-113) */
+ reg_copy(&st0, &tmp);
+ tmptag = st0_tag;
+ N = (expdif & 0x0000001f) + 32; /* This choice gives results
+ identical to an AMD 486 */
+ setexponent16(&tmp, N);
+ exp_1 = exponent16(&st1);
+ setexponent16(&st1, 0);
+ expdif -= N;
+
+ sign = getsign(&tmp) ^ st1_sign;
+ tag = FPU_u_div(&tmp, &st1, &tmp, PR_64_BITS | RC_CHOP | 0x3f,
+ sign);
+ setsign(&tmp, sign);
+
+ FPU_round_to_int(&tmp, tag); /* Fortunately, this can't
+ overflow to 2^64 */
+
+ rem_kernel(significand(&st0),
+ &significand(&tmp),
+ significand(&st1),
+ significand(&tmp),
+ exponent(&tmp)
+ );
+ setexponent16(&tmp, exp_1 + expdif);
+
+ /* It is possible for the operation to be complete here.
+ What does the IEEE standard say? The Intel 80486 manual
+ implies that the operation will never be completed at this
+ point, and the behaviour of a real 80486 confirms this.
+ */
+ if ( !(tmp.sigh | tmp.sigl) )
+ {
+ /* The result is zero */
+ control_word = old_cw;
+ partial_status = saved_status;
+ FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
+ setsign(&st0, st0_sign);
+#ifdef PECULIAR_486
+ setcc(SW_C2);
+#else
+ setcc(0);
+#endif /* PECULIAR_486 */
+ return;
+ }
+ cc = SW_C2;
+ }
+
+ control_word = old_cw;
+ partial_status = saved_status;
+ tag = FPU_normalize_nuo(&tmp, 0);
+ reg_copy(&tmp, st0_ptr);
+
+ /* The only condition to be looked for is underflow,
+ and it can occur here only if underflow is unmasked. */
+ if ( (exponent16(&tmp) <= EXP_UNDER) && (tag != TAG_Zero)
+ && !(control_word & CW_Underflow) )
+ {
+ setcc(cc);
+ tag = arith_underflow(st0_ptr);
+ setsign(st0_ptr, st0_sign);
+ FPU_settag0(tag);
+ return;
+ }
+ else if ( (exponent16(&tmp) > EXP_UNDER) || (tag == TAG_Zero) )
+ {
+ stdexp(st0_ptr);
+ setsign(st0_ptr, st0_sign);
+ }
+ else
+ {
+ tag = FPU_round(st0_ptr, 0, 0, FULL_PRECISION, st0_sign);
+ }
+ FPU_settag0(tag);
+ setcc(cc);
+
+ return;
+ }
+
+ if ( st0_tag == TAG_Special )
+ st0_tag = FPU_Special(st0_ptr);
+ if ( st1_tag == TAG_Special )
+ st1_tag = FPU_Special(st1_ptr);
+
+ if ( ((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
+ || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
+ || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal)) )
+ {
+ if ( denormal_operand() < 0 )
+ return;
+ goto fprem_valid;
+ }
+ else if ( (st0_tag == TAG_Empty) | (st1_tag == TAG_Empty) )
+ {
+ FPU_stack_underflow();
+ return;
+ }
+ else if ( st0_tag == TAG_Zero )
+ {
+ if ( st1_tag == TAG_Valid )
+ {
+ setcc(0); return;
+ }
+ else if ( st1_tag == TW_Denormal )
+ {
+ if ( denormal_operand() < 0 )
+ return;
+ setcc(0); return;
+ }
+ else if ( st1_tag == TAG_Zero )
+ { arith_invalid(0); return; } /* fprem(?,0) always invalid */
+ else if ( st1_tag == TW_Infinity )
+ { setcc(0); return; }
+ }
+ else if ( (st0_tag == TAG_Valid) || (st0_tag == TW_Denormal) )
+ {
+ if ( st1_tag == TAG_Zero )
+ {
+ arith_invalid(0); /* fprem(Valid,Zero) is invalid */
+ return;
+ }
+ else if ( st1_tag != TW_NaN )
+ {
+ if ( ((st0_tag == TW_Denormal) || (st1_tag == TW_Denormal))
+ && (denormal_operand() < 0) )
+ return;
+
+ if ( st1_tag == TW_Infinity )
+ {
+ /* fprem(Valid,Infinity) is o.k. */
+ setcc(0); return;
+ }
+ }
+ }
+ else if ( st0_tag == TW_Infinity )
+ {
+ if ( st1_tag != TW_NaN )
+ {
+ arith_invalid(0); /* fprem(Infinity,?) is invalid */
+ return;
+ }
+ }
+
+ /* One of the registers must contain a NaN if we got here. */
+
+#ifdef PARANOID
+ if ( (st0_tag != TW_NaN) && (st1_tag != TW_NaN) )
+ EXCEPTION(EX_INTERNAL | 0x118);
+#endif /* PARANOID */
+
+ real_2op_NaN(st1_ptr, st1_tag, 0, st1_ptr);
+
+}
+
+
+/* ST(1) <- ST(1) * log ST; pop ST */
+static void fyl2x(FPU_REG *st0_ptr, u_char st0_tag)
+{
+ FPU_REG *st1_ptr = &st(1), exponent;
+ u_char st1_tag = FPU_gettagi(1);
+ u_char sign;
+ int e, tag;
+
+ clear_C1();
+
+ if ( (st0_tag == TAG_Valid) && (st1_tag == TAG_Valid) )
+ {
+ both_valid:
+ /* Both regs are Valid or Denormal */
+ if ( signpositive(st0_ptr) )
+ {
+ if ( st0_tag == TW_Denormal )
+ FPU_to_exp16(st0_ptr, st0_ptr);
+ else
+ /* Convert st(0) for internal use. */
+ setexponent16(st0_ptr, exponent(st0_ptr));
+
+ if ( (st0_ptr->sigh == 0x80000000) && (st0_ptr->sigl == 0) )
+ {
+ /* Special case. The result can be precise. */
+ u_char esign;
+ e = exponent16(st0_ptr);
+ if ( e >= 0 )
+ {
+ exponent.sigh = e;
+ esign = SIGN_POS;
+ }
+ else
+ {
+ exponent.sigh = -e;
+ esign = SIGN_NEG;
+ }
+ exponent.sigl = 0;
+ setexponent16(&exponent, 31);
+ tag = FPU_normalize_nuo(&exponent, 0);
+ stdexp(&exponent);
+ setsign(&exponent, esign);
+ tag = FPU_mul(&exponent, tag, 1, FULL_PRECISION);
+ if ( tag >= 0 )
+ FPU_settagi(1, tag);
+ }
+ else
+ {
+ /* The usual case */
+ sign = getsign(st1_ptr);
+ if ( st1_tag == TW_Denormal )
+ FPU_to_exp16(st1_ptr, st1_ptr);
+ else
+ /* Convert st(1) for internal use. */
+ setexponent16(st1_ptr, exponent(st1_ptr));
+ poly_l2(st0_ptr, st1_ptr, sign);
+ }
+ }
+ else
+ {
+ /* negative */
+ if ( arith_invalid(1) < 0 )
+ return;
+ }
+
+ FPU_pop();
+
+ return;
+ }
+
+ if ( st0_tag == TAG_Special )
+ st0_tag = FPU_Special(st0_ptr);
+ if ( st1_tag == TAG_Special )
+ st1_tag = FPU_Special(st1_ptr);
+
+ if ( (st0_tag == TAG_Empty) || (st1_tag == TAG_Empty) )
+ {
+ FPU_stack_underflow_pop(1);
+ return;
+ }
+ else if ( (st0_tag <= TW_Denormal) && (st1_tag <= TW_Denormal) )
+ {
+ if ( st0_tag == TAG_Zero )
+ {
+ if ( st1_tag == TAG_Zero )
+ {
+ /* Both args zero is invalid */
+ if ( arith_invalid(1) < 0 )
+ return;
+ }
+ else
+ {
+ u_char sign;
+ sign = getsign(st1_ptr)^SIGN_NEG;
+ if ( FPU_divide_by_zero(1, sign) < 0 )
+ return;
+
+ setsign(st1_ptr, sign);
+ }
+ }
+ else if ( st1_tag == TAG_Zero )
+ {
+ /* st(1) contains zero, st(0) valid <> 0 */
+ /* Zero is the valid answer */
+ sign = getsign(st1_ptr);
+
+ if ( signnegative(st0_ptr) )
+ {
+ /* log(negative) */
+ if ( arith_invalid(1) < 0 )
+ return;
+ }
+ else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
+ return;
+ else
+ {
+ if ( exponent(st0_ptr) < 0 )
+ sign ^= SIGN_NEG;
+
+ FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
+ setsign(st1_ptr, sign);
+ }
+ }
+ else
+ {
+ /* One or both operands are denormals. */
+ if ( denormal_operand() < 0 )
+ return;
+ goto both_valid;
+ }
+ }
+ else if ( (st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
+ {
+ if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 )
+ return;
+ }
+ /* One or both arg must be an infinity */
+ else if ( st0_tag == TW_Infinity )
+ {
+ if ( (signnegative(st0_ptr)) || (st1_tag == TAG_Zero) )
+ {
+ /* log(-infinity) or 0*log(infinity) */
+ if ( arith_invalid(1) < 0 )
+ return;
+ }
+ else
+ {
+ u_char sign = getsign(st1_ptr);
+
+ if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) )
+ return;
+
+ FPU_copy_to_reg1(&CONST_INF, TAG_Special);
+ setsign(st1_ptr, sign);
+ }
+ }
+ /* st(1) must be infinity here */
+ else if ( ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal))
+ && ( signpositive(st0_ptr) ) )
+ {
+ if ( exponent(st0_ptr) >= 0 )
+ {
+ if ( (exponent(st0_ptr) == 0) &&
+ (st0_ptr->sigh == 0x80000000) &&
+ (st0_ptr->sigl == 0) )
+ {
+ /* st(0) holds 1.0 */
+ /* infinity*log(1) */
+ if ( arith_invalid(1) < 0 )
+ return;
+ }
+ /* else st(0) is positive and > 1.0 */
+ }
+ else
+ {
+ /* st(0) is positive and < 1.0 */
+
+ if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
+ return;
+
+ changesign(st1_ptr);
+ }
+ }
+ else
+ {
+ /* st(0) must be zero or negative */
+ if ( st0_tag == TAG_Zero )
+ {
+ /* This should be invalid, but a real 80486 is happy with it. */
+
+#ifndef PECULIAR_486
+ sign = getsign(st1_ptr);
+ if ( FPU_divide_by_zero(1, sign) < 0 )
+ return;
+#endif /* PECULIAR_486 */
+
+ changesign(st1_ptr);
+ }
+ else if ( arith_invalid(1) < 0 ) /* log(negative) */
+ return;
+ }
+
+ FPU_pop();
+}
+
+
+static void fpatan(FPU_REG *st0_ptr, u_char st0_tag)
+{
+ FPU_REG *st1_ptr = &st(1);
+ u_char st1_tag = FPU_gettagi(1);
+ int tag;
+
+ clear_C1();
+ if ( !((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid)) )
+ {
+ valid_atan:
+
+ poly_atan(st0_ptr, st0_tag, st1_ptr, st1_tag);
+
+ FPU_pop();
+
+ return;
+ }
+
+ if ( st0_tag == TAG_Special )
+ st0_tag = FPU_Special(st0_ptr);
+ if ( st1_tag == TAG_Special )
+ st1_tag = FPU_Special(st1_ptr);
+
+ if ( ((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
+ || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
+ || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal)) )
+ {
+ if ( denormal_operand() < 0 )
+ return;
+
+ goto valid_atan;
+ }
+ else if ( (st0_tag == TAG_Empty) || (st1_tag == TAG_Empty) )
+ {
+ FPU_stack_underflow_pop(1);
+ return;
+ }
+ else if ( (st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
+ {
+ if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) >= 0 )
+ FPU_pop();
+ return;
+ }
+ else if ( (st0_tag == TW_Infinity) || (st1_tag == TW_Infinity) )
+ {
+ u_char sign = getsign(st1_ptr);
+ if ( st0_tag == TW_Infinity )
+ {
+ if ( st1_tag == TW_Infinity )
+ {
+ if ( signpositive(st0_ptr) )
+ {
+ FPU_copy_to_reg1(&CONST_PI4, TAG_Valid);
+ }
+ else
+ {
+ setpositive(st1_ptr);
+ tag = FPU_u_add(&CONST_PI4, &CONST_PI2, st1_ptr,
+ FULL_PRECISION, SIGN_POS,
+ exponent(&CONST_PI4), exponent(&CONST_PI2));
+ if ( tag >= 0 )
+ FPU_settagi(1, tag);
+ }
+ }
+ else
+ {
+ if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) )
+ return;
+
+ if ( signpositive(st0_ptr) )
+ {
+ FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
+ setsign(st1_ptr, sign); /* An 80486 preserves the sign */
+ FPU_pop();
+ return;
+ }
+ else
+ {
+ FPU_copy_to_reg1(&CONST_PI, TAG_Valid);
+ }
+ }
+ }
+ else
+ {
+ /* st(1) is infinity, st(0) not infinity */
+ if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
+ return;
+
+ FPU_copy_to_reg1(&CONST_PI2, TAG_Valid);
+ }
+ setsign(st1_ptr, sign);
+ }
+ else if ( st1_tag == TAG_Zero )
+ {
+ /* st(0) must be valid or zero */
+ u_char sign = getsign(st1_ptr);
+
+ if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
+ return;
+
+ if ( signpositive(st0_ptr) )
+ {
+ /* An 80486 preserves the sign */
+ FPU_pop();
+ return;
+ }
+
+ FPU_copy_to_reg1(&CONST_PI, TAG_Valid);
+ setsign(st1_ptr, sign);
+ }
+ else if ( st0_tag == TAG_Zero )
+ {
+ /* st(1) must be TAG_Valid here */
+ u_char sign = getsign(st1_ptr);
+
+ if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) )
+ return;
+
+ FPU_copy_to_reg1(&CONST_PI2, TAG_Valid);
+ setsign(st1_ptr, sign);
+ }
+#ifdef PARANOID
+ else
+ EXCEPTION(EX_INTERNAL | 0x125);
+#endif /* PARANOID */
+
+ FPU_pop();
+ set_precision_flag_up(); /* We do not really know if up or down */
+}
+
+
+static void fprem(FPU_REG *st0_ptr, u_char st0_tag)
+{
+ do_fprem(st0_ptr, st0_tag, RC_CHOP);
+}
+
+
+static void fprem1(FPU_REG *st0_ptr, u_char st0_tag)
+{
+ do_fprem(st0_ptr, st0_tag, RC_RND);
+}
+
+
+static void fyl2xp1(FPU_REG *st0_ptr, u_char st0_tag)
+{
+ u_char sign, sign1;
+ FPU_REG *st1_ptr = &st(1), a, b;
+ u_char st1_tag = FPU_gettagi(1);
+
+ clear_C1();
+ if ( !((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid)) )
+ {
+ valid_yl2xp1:
+
+ sign = getsign(st0_ptr);
+ sign1 = getsign(st1_ptr);
+
+ FPU_to_exp16(st0_ptr, &a);
+ FPU_to_exp16(st1_ptr, &b);
+
+ if ( poly_l2p1(sign, sign1, &a, &b, st1_ptr) )
+ return;
+
+ FPU_pop();
+ return;
+ }
+
+ if ( st0_tag == TAG_Special )
+ st0_tag = FPU_Special(st0_ptr);
+ if ( st1_tag == TAG_Special )
+ st1_tag = FPU_Special(st1_ptr);
+
+ if ( ((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
+ || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
+ || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal)) )
+ {
+ if ( denormal_operand() < 0 )
+ return;
+
+ goto valid_yl2xp1;
+ }
+ else if ( (st0_tag == TAG_Empty) | (st1_tag == TAG_Empty) )
+ {
+ FPU_stack_underflow_pop(1);
+ return;
+ }
+ else if ( st0_tag == TAG_Zero )
+ {
+ switch ( st1_tag )
+ {
+ case TW_Denormal:
+ if ( denormal_operand() < 0 )
+ return;
+
+ case TAG_Zero:
+ case TAG_Valid:
+ setsign(st0_ptr, getsign(st0_ptr) ^ getsign(st1_ptr));
+ FPU_copy_to_reg1(st0_ptr, st0_tag);
+ break;
+
+ case TW_Infinity:
+ /* Infinity*log(1) */
+ if ( arith_invalid(1) < 0 )
+ return;
+ break;
+
+ case TW_NaN:
+ if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 )
+ return;
+ break;
+
+ default:
+#ifdef PARANOID
+ EXCEPTION(EX_INTERNAL | 0x116);
+ return;
+#endif /* PARANOID */
+ }
+ }
+ else if ( (st0_tag == TAG_Valid) || (st0_tag == TW_Denormal) )
+ {
+ switch ( st1_tag )
+ {
+ case TAG_Zero:
+ if ( signnegative(st0_ptr) )
+ {
+ if ( exponent(st0_ptr) >= 0 )
+ {
+ /* st(0) holds <= -1.0 */
+#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */
+ changesign(st1_ptr);
+#else
+ if ( arith_invalid(1) < 0 )
+ return;
+#endif /* PECULIAR_486 */
+ }
+ else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
+ return;
+ else
+ changesign(st1_ptr);
+ }
+ else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
+ return;
+ break;
+
+ case TW_Infinity:
+ if ( signnegative(st0_ptr) )
+ {
+ if ( (exponent(st0_ptr) >= 0) &&
+ !((st0_ptr->sigh == 0x80000000) &&
+ (st0_ptr->sigl == 0)) )
+ {
+ /* st(0) holds < -1.0 */
+#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */
+ changesign(st1_ptr);
+#else
+ if ( arith_invalid(1) < 0 ) return;
+#endif /* PECULIAR_486 */
+ }
+ else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
+ return;
+ else
+ changesign(st1_ptr);
+ }
+ else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
+ return;
+ break;
+
+ case TW_NaN:
+ if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 )
+ return;
+ }
+
+ }
+ else if ( st0_tag == TW_NaN )
+ {
+ if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 )
+ return;
+ }
+ else if ( st0_tag == TW_Infinity )
+ {
+ if ( st1_tag == TW_NaN )
+ {
+ if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 )
+ return;
+ }
+ else if ( signnegative(st0_ptr) )
+ {
+#ifndef PECULIAR_486
+ /* This should have higher priority than denormals, but... */
+ if ( arith_invalid(1) < 0 ) /* log(-infinity) */
+ return;
+#endif /* PECULIAR_486 */
+ if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) )
+ return;
+#ifdef PECULIAR_486
+ /* Denormal operands actually get higher priority */
+ if ( arith_invalid(1) < 0 ) /* log(-infinity) */
+ return;
+#endif /* PECULIAR_486 */
+ }
+ else if ( st1_tag == TAG_Zero )
+ {
+ /* log(infinity) */
+ if ( arith_invalid(1) < 0 )
+ return;
+ }
+
+ /* st(1) must be valid here. */
+
+ else if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) )
+ return;
+
+ /* The Manual says that log(Infinity) is invalid, but a real
+ 80486 sensibly says that it is o.k. */
+ else
+ {
+ u_char sign = getsign(st1_ptr);
+ FPU_copy_to_reg1(&CONST_INF, TAG_Special);
+ setsign(st1_ptr, sign);
+ }
+ }
+#ifdef PARANOID
+ else
+ {
+ EXCEPTION(EX_INTERNAL | 0x117);
+ return;
+ }
+#endif /* PARANOID */
+
+ FPU_pop();
+ return;
+
+}
+
+
+static void fscale(FPU_REG *st0_ptr, u_char st0_tag)
+{
+ FPU_REG *st1_ptr = &st(1);
+ u_char st1_tag = FPU_gettagi(1);
+ int old_cw = control_word;
+ u_char sign = getsign(st0_ptr);
+
+ clear_C1();
+ if ( !((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid)) )
+ {
+ s32 scale;
+ FPU_REG tmp;
+
+ /* Convert register for internal use. */
+ setexponent16(st0_ptr, exponent(st0_ptr));
+
+ valid_scale:
+
+ if ( exponent(st1_ptr) > 30 )
+ {
+ /* 2^31 is far too large, would require 2^(2^30) or 2^(-2^30) */
+
+ if ( signpositive(st1_ptr) )
+ {
+ EXCEPTION(EX_Overflow);
+ FPU_copy_to_reg0(&CONST_INF, TAG_Special);
+ }
+ else
+ {
+ EXCEPTION(EX_Underflow);
+ FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
+ }
+ setsign(st0_ptr, sign);
+ return;
+ }
+
+ control_word &= ~CW_RC;
+ control_word |= RC_CHOP;
+ reg_copy(st1_ptr, &tmp);
+ FPU_round_to_int(&tmp, st1_tag); /* This can never overflow here */
+ control_word = old_cw;
+ scale = signnegative(st1_ptr) ? -tmp.sigl : tmp.sigl;
+ scale += exponent16(st0_ptr);
+
+ setexponent16(st0_ptr, scale);
+
+ /* Use FPU_round() to properly detect under/overflow etc */
+ FPU_round(st0_ptr, 0, 0, control_word, sign);
+
+ return;
+ }
+
+ if ( st0_tag == TAG_Special )
+ st0_tag = FPU_Special(st0_ptr);
+ if ( st1_tag == TAG_Special )
+ st1_tag = FPU_Special(st1_ptr);
+
+ if ( (st0_tag == TAG_Valid) || (st0_tag == TW_Denormal) )
+ {
+ switch ( st1_tag )
+ {
+ case TAG_Valid:
+ /* st(0) must be a denormal */
+ if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
+ return;
+
+ FPU_to_exp16(st0_ptr, st0_ptr); /* Will not be left on stack */
+ goto valid_scale;
+
+ case TAG_Zero:
+ if ( st0_tag == TW_Denormal )
+ denormal_operand();
+ return;
+
+ case TW_Denormal:
+ denormal_operand();
+ return;
+
+ case TW_Infinity:
+ if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
+ return;
+
+ if ( signpositive(st1_ptr) )
+ FPU_copy_to_reg0(&CONST_INF, TAG_Special);
+ else
+ FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
+ setsign(st0_ptr, sign);
+ return;
+
+ case TW_NaN:
+ real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
+ return;
+ }
+ }
+ else if ( st0_tag == TAG_Zero )
+ {
+ switch ( st1_tag )
+ {
+ case TAG_Valid:
+ case TAG_Zero:
+ return;
+
+ case TW_Denormal:
+ denormal_operand();
+ return;
+
+ case TW_Infinity:
+ if ( signpositive(st1_ptr) )
+ arith_invalid(0); /* Zero scaled by +Infinity */
+ return;
+
+ case TW_NaN:
+ real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
+ return;
+ }
+ }
+ else if ( st0_tag == TW_Infinity )
+ {
+ switch ( st1_tag )
+ {
+ case TAG_Valid:
+ case TAG_Zero:
+ return;
+
+ case TW_Denormal:
+ denormal_operand();
+ return;
+
+ case TW_Infinity:
+ if ( signnegative(st1_ptr) )
+ arith_invalid(0); /* Infinity scaled by -Infinity */
+ return;
+
+ case TW_NaN:
+ real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
+ return;
+ }
+ }
+ else if ( st0_tag == TW_NaN )
+ {
+ if ( st1_tag != TAG_Empty )
+ { real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr); return; }
+ }
+
+#ifdef PARANOID
+ if ( !((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) )
+ {
+ EXCEPTION(EX_INTERNAL | 0x115);
+ return;
+ }
+#endif
+
+ /* At least one of st(0), st(1) must be empty */
+ FPU_stack_underflow();
+
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+static FUNC_ST0 const trig_table_a[] = {
+ f2xm1, fyl2x, fptan, fpatan,
+ fxtract, fprem1, (FUNC_ST0)fdecstp, (FUNC_ST0)fincstp
+};
+
+void FPU_triga(void)
+{
+ (trig_table_a[FPU_rm])(&st(0), FPU_gettag0());
+}
+
+
+static FUNC_ST0 const trig_table_b[] =
+ {
+ fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, (FUNC_ST0)fsin, fcos
+ };
+
+void FPU_trigb(void)
+{
+ (trig_table_b[FPU_rm])(&st(0), FPU_gettag0());
+}
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | get_address.c |
+ | |
+ | Get the effective address from an FPU instruction. |
+ | |
+ | Copyright (C) 1992,1993,1994,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@suburbia.net |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | Note: |
+ | The file contains code which accesses user memory. |
+ | Emulator static data may change when user memory is accessed, due to |
+ | other processes using the emulator while swapping is in progress. |
+ +---------------------------------------------------------------------------*/
+
+
+#include <linux/stddef.h>
+
+#include <asm/uaccess.h>
+#include <asm/desc.h>
+
+#include "fpu_system.h"
+#include "exception.h"
+#include "fpu_emu.h"
+
+
+#define FPU_WRITE_BIT 0x10
+
+static int reg_offset[] = {
+ offsetof(struct info,___eax),
+ offsetof(struct info,___ecx),
+ offsetof(struct info,___edx),
+ offsetof(struct info,___ebx),
+ offsetof(struct info,___esp),
+ offsetof(struct info,___ebp),
+ offsetof(struct info,___esi),
+ offsetof(struct info,___edi)
+};
+
+#define REG_(x) (*(s32 *)(reg_offset[(x)]+(u_char *) FPU_info))
+
+static int reg_offset_vm86[] = {
+ offsetof(struct info,___cs),
+ offsetof(struct info,___vm86_ds),
+ offsetof(struct info,___vm86_es),
+ offsetof(struct info,___vm86_fs),
+ offsetof(struct info,___vm86_gs),
+ offsetof(struct info,___ss),
+ offsetof(struct info,___vm86_ds)
+ };
+
+#define VM86_REG_(x) (*(unsigned short *) \
+ (reg_offset_vm86[((unsigned)x)]+(u_char *) FPU_info))
+
+/* These are dummy, fs and gs are not saved on the stack. */
+#define ___FS ___ds
+#define ___GS ___ds
+
+static int reg_offset_pm[] = {
+ offsetof(struct info,___cs),
+ offsetof(struct info,___ds),
+ offsetof(struct info,___es),
+ offsetof(struct info,___FS),
+ offsetof(struct info,___GS),
+ offsetof(struct info,___ss),
+ offsetof(struct info,___ds)
+ };
+
+#define PM_REG_(x) (*(unsigned short *) \
+ (reg_offset_pm[((unsigned)x)]+(u_char *) FPU_info))
+
+
+/* Decode the SIB byte. This function assumes mod != 0 */
+static int sib(int mod, u32 *fpu_eip)
+{
+ u_char ss,index,base;
+ s32 offset;
+
+ RE_ENTRANT_CHECK_OFF;
+ FPU_code_verify_area(1);
+ FPU_get_user(base, (u_char *) (*fpu_eip)); /* The SIB byte */
+ RE_ENTRANT_CHECK_ON;
+ (*fpu_eip)++;
+ ss = base >> 6;
+ index = (base >> 3) & 7;
+ base &= 7;
+
+ if ((mod == 0) && (base == 5))
+ offset = 0; /* No base register */
+ else
+ offset = REG_(base);
+
+ if (index == 4)
+ {
+ /* No index register */
+ /* A non-zero ss is illegal */
+ if ( ss )
+ EXCEPTION(EX_Invalid);
+ }
+ else
+ {
+ offset += (REG_(index)) << ss;
+ }
+
+ if (mod == 1)
+ {
+ /* 8 bit signed displacement */
+ s32 displacement;
+ RE_ENTRANT_CHECK_OFF;
+ FPU_code_verify_area(1);
+ FPU_get_user(displacement, (signed char *) (*fpu_eip));
+ offset += displacement;
+ RE_ENTRANT_CHECK_ON;
+ (*fpu_eip)++;
+ }
+ else if (mod == 2 || base == 5) /* The second condition also has mod==0 */
+ {
+ /* 32 bit displacement */
+ s32 displacement;
+ RE_ENTRANT_CHECK_OFF;
+ FPU_code_verify_area(4);
+ FPU_get_user(displacement, (s32 *) (*fpu_eip));
+ offset += displacement;
+ RE_ENTRANT_CHECK_ON;
+ (*fpu_eip) += 4;
+ }
+
+ return offset;
+}
+
+
+static u32 vm86_segment(u_char segment,
+ struct address *addr)
+{
+ segment--;
+#ifdef PARANOID
+ if ( segment > PREFIX_SS_ )
+ {
+ EXCEPTION(EX_INTERNAL|0x130);
+ math_abort(FPU_info,SIGSEGV);
+ }
+#endif /* PARANOID */
+ addr->selector = VM86_REG_(segment);
+ return (u32)VM86_REG_(segment) << 4;
+}
+
+
+/* This should work for 16 and 32 bit protected mode. */
+static s32 pm_address(u_char FPU_modrm, u_char segment,
+ struct address *addr, s32 offset)
+{
+ struct desc_struct descriptor;
+ u32 base_address, limit, address, seg_top;
+
+ segment--;
+
+#ifdef PARANOID
+ /* segment is unsigned, so this also detects if segment was 0: */
+ if ( segment > PREFIX_SS_ )
+ {
+ EXCEPTION(EX_INTERNAL|0x132);
+ math_abort(FPU_info,SIGSEGV);
+ }
+#endif /* PARANOID */
+
+ switch ( segment )
+ {
+ /* fs and gs aren't used by the kernel, so they still have their
+ user-space values. */
+ case PREFIX_FS_-1:
+ /* The cast is needed here to get gcc 2.8.0 to use a 16 bit register
+ in the assembler statement. */
+ __asm__("mov %%fs,%0":"=r" ((unsigned short)addr->selector));
+ break;
+ case PREFIX_GS_-1:
+ /* The cast is needed here to get gcc 2.8.0 to use a 16 bit register
+ in the assembler statement. */
+ __asm__("mov %%gs,%0":"=r" ((unsigned short)addr->selector));
+ break;
+ default:
+ addr->selector = PM_REG_(segment);
+ }
+
+ descriptor = LDT_DESCRIPTOR(PM_REG_(segment));
+ base_address = SEG_BASE_ADDR(descriptor);
+ address = base_address + offset;
+ limit = base_address
+ + (SEG_LIMIT(descriptor)+1) * SEG_GRANULARITY(descriptor) - 1;
+ if ( limit < base_address ) limit = 0xffffffff;
+
+ if ( SEG_EXPAND_DOWN(descriptor) )
+ {
+ if ( SEG_G_BIT(descriptor) )
+ seg_top = 0xffffffff;
+ else
+ {
+ seg_top = base_address + (1 << 20);
+ if ( seg_top < base_address ) seg_top = 0xffffffff;
+ }
+ access_limit =
+ (address <= limit) || (address >= seg_top) ? 0 :
+ ((seg_top-address) >= 255 ? 255 : seg_top-address);
+ }
+ else
+ {
+ access_limit =
+ (address > limit) || (address < base_address) ? 0 :
+ ((limit-address) >= 254 ? 255 : limit-address+1);
+ }
+ if ( SEG_EXECUTE_ONLY(descriptor) ||
+ (!SEG_WRITE_PERM(descriptor) && (FPU_modrm & FPU_WRITE_BIT)) )
+ {
+ access_limit = 0;
+ }
+ return address;
+}
+
+
+/*
+ MOD R/M byte: MOD == 3 has a special use for the FPU
+ SIB byte used iff R/M = 100b
+
+ 7 6 5 4 3 2 1 0
+ ..... ......... .........
+ MOD OPCODE(2) R/M
+
+
+ SIB byte
+
+ 7 6 5 4 3 2 1 0
+ ..... ......... .........
+ SS INDEX BASE
+
+*/
+
+void *FPU_get_address(u_char FPU_modrm, u32 *fpu_eip,
+ struct address *addr,
+ fpu_addr_modes addr_modes)
+{
+ u_char mod;
+ unsigned rm = FPU_modrm & 7;
+ s32 *cpu_reg_ptr;
+ int address = 0; /* Initialized just to stop compiler warnings. */
+
+ /* Memory accessed via the cs selector is write protected
+ in `non-segmented' 32 bit protected mode. */
+ if ( !addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT)
+ && (addr_modes.override.segment == PREFIX_CS_) )
+ {
+ math_abort(FPU_info,SIGSEGV);
+ }
+
+ addr->selector = FPU_DS; /* Default, for 32 bit non-segmented mode. */
+
+ mod = (FPU_modrm >> 6) & 3;
+
+ if (rm == 4 && mod != 3)
+ {
+ address = sib(mod, fpu_eip);
+ }
+ else
+ {
+ cpu_reg_ptr = & REG_(rm);
+ switch (mod)
+ {
+ case 0:
+ if (rm == 5)
+ {
+ /* Special case: disp32 */
+ RE_ENTRANT_CHECK_OFF;
+ FPU_code_verify_area(4);
+ FPU_get_user(address, (u32 *) (*fpu_eip));
+ (*fpu_eip) += 4;
+ RE_ENTRANT_CHECK_ON;
+ addr->offset = address;
+ return (void *) address;
+ }
+ else
+ {
+ address = *cpu_reg_ptr; /* Just return the contents
+ of the cpu register */
+ addr->offset = address;
+ return (void *) address;
+ }
+ case 1:
+ /* 8 bit signed displacement */
+ RE_ENTRANT_CHECK_OFF;
+ FPU_code_verify_area(1);
+ FPU_get_user(address, (signed char *) (*fpu_eip));
+ RE_ENTRANT_CHECK_ON;
+ (*fpu_eip)++;
+ break;
+ case 2:
+ /* 32 bit displacement */
+ RE_ENTRANT_CHECK_OFF;
+ FPU_code_verify_area(4);
+ FPU_get_user(address, (s32 *) (*fpu_eip));
+ (*fpu_eip) += 4;
+ RE_ENTRANT_CHECK_ON;
+ break;
+ case 3:
+ /* Not legal for the FPU */
+ EXCEPTION(EX_Invalid);
+ }
+ address += *cpu_reg_ptr;
+ }
+
+ addr->offset = address;
+
+ switch ( addr_modes.default_mode )
+ {
+ case 0:
+ break;
+ case VM86:
+ address += vm86_segment(addr_modes.override.segment, addr);
+ break;
+ case PM16:
+ case SEG32:
+ address = pm_address(FPU_modrm, addr_modes.override.segment,
+ addr, address);
+ break;
+ default:
+ EXCEPTION(EX_INTERNAL|0x133);
+ }
+
+ return (void *)address;
+}
+
+
+void *FPU_get_address_16(u_char FPU_modrm, u32 *fpu_eip,
+ struct address *addr,
+ fpu_addr_modes addr_modes)
+{
+ u_char mod;
+ unsigned rm = FPU_modrm & 7;
+ int address = 0; /* Default used for mod == 0 */
+
+ /* Memory accessed via the cs selector is write protected
+ in `non-segmented' 32 bit protected mode. */
+ if ( !addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT)
+ && (addr_modes.override.segment == PREFIX_CS_) )
+ {
+ math_abort(FPU_info,SIGSEGV);
+ }
+
+ addr->selector = FPU_DS; /* Default, for 32 bit non-segmented mode. */
+
+ mod = (FPU_modrm >> 6) & 3;
+
+ switch (mod)
+ {
+ case 0:
+ if (rm == 6)
+ {
+ /* Special case: disp16 */
+ RE_ENTRANT_CHECK_OFF;
+ FPU_code_verify_area(2);
+ FPU_get_user(address, (unsigned short *) (*fpu_eip));
+ (*fpu_eip) += 2;
+ RE_ENTRANT_CHECK_ON;
+ goto add_segment;
+ }
+ break;
+ case 1:
+ /* 8 bit signed displacement */
+ RE_ENTRANT_CHECK_OFF;
+ FPU_code_verify_area(1);
+ FPU_get_user(address, (signed char *) (*fpu_eip));
+ RE_ENTRANT_CHECK_ON;
+ (*fpu_eip)++;
+ break;
+ case 2:
+ /* 16 bit displacement */
+ RE_ENTRANT_CHECK_OFF;
+ FPU_code_verify_area(2);
+ FPU_get_user(address, (unsigned short *) (*fpu_eip));
+ (*fpu_eip) += 2;
+ RE_ENTRANT_CHECK_ON;
+ break;
+ case 3:
+ /* Not legal for the FPU */
+ EXCEPTION(EX_Invalid);
+ break;
+ }
+ switch ( rm )
+ {
+ case 0:
+ address += FPU_info->___ebx + FPU_info->___esi;
+ break;
+ case 1:
+ address += FPU_info->___ebx + FPU_info->___edi;
+ break;
+ case 2:
+ address += FPU_info->___ebp + FPU_info->___esi;
+ if ( addr_modes.override.segment == PREFIX_DEFAULT )
+ addr_modes.override.segment = PREFIX_SS_;
+ break;
+ case 3:
+ address += FPU_info->___ebp + FPU_info->___edi;
+ if ( addr_modes.override.segment == PREFIX_DEFAULT )
+ addr_modes.override.segment = PREFIX_SS_;
+ break;
+ case 4:
+ address += FPU_info->___esi;
+ break;
+ case 5:
+ address += FPU_info->___edi;
+ break;
+ case 6:
+ address += FPU_info->___ebp;
+ if ( addr_modes.override.segment == PREFIX_DEFAULT )
+ addr_modes.override.segment = PREFIX_SS_;
+ break;
+ case 7:
+ address += FPU_info->___ebx;
+ break;
+ }
+
+ add_segment:
+ address &= 0xffff;
+
+ addr->offset = address;
+
+ switch ( addr_modes.default_mode )
+ {
+ case 0:
+ break;
+ case VM86:
+ address += vm86_segment(addr_modes.override.segment, addr);
+ break;
+ case PM16:
+ case SEG32:
+ address = pm_address(FPU_modrm, addr_modes.override.segment,
+ addr, address);
+ break;
+ default:
+ EXCEPTION(EX_INTERNAL|0x131);
+ }
+
+ return (void *)address ;
+}
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | load_store.c |
+ | |
+ | This file contains most of the code to interpret the FPU instructions |
+ | which load and store from user memory. |
+ | |
+ | Copyright (C) 1992,1993,1994,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@suburbia.net |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | Note: |
+ | The file contains code which accesses user memory. |
+ | Emulator static data may change when user memory is accessed, due to |
+ | other processes using the emulator while swapping is in progress. |
+ +---------------------------------------------------------------------------*/
+
+#include <asm/uaccess.h>
+
+#include "fpu_system.h"
+#include "exception.h"
+#include "fpu_emu.h"
+#include "status_w.h"
+#include "control_w.h"
+
+
+#define _NONE_ 0 /* st0_ptr etc not needed */
+#define _REG0_ 1 /* Will be storing st(0) */
+#define _PUSH_ 3 /* Need to check for space to push onto stack */
+#define _null_ 4 /* Function illegal or not implemented */
+
+#define pop_0() { FPU_settag0(TAG_Empty); top++; }
+
+
+static u_char const type_table[32] = {
+ _PUSH_, _PUSH_, _PUSH_, _PUSH_,
+ _null_, _null_, _null_, _null_,
+ _REG0_, _REG0_, _REG0_, _REG0_,
+ _REG0_, _REG0_, _REG0_, _REG0_,
+ _NONE_, _null_, _NONE_, _PUSH_,
+ _NONE_, _PUSH_, _null_, _PUSH_,
+ _NONE_, _null_, _NONE_, _REG0_,
+ _NONE_, _REG0_, _NONE_, _REG0_
+ };
+
+u_char const data_sizes_16[32] = {
+ 4, 4, 8, 2, 0, 0, 0, 0,
+ 4, 4, 8, 2, 4, 4, 8, 2,
+ 14, 0, 94, 10, 2, 10, 0, 8,
+ 14, 0, 94, 10, 2, 10, 2, 8
+};
+
+u_char const data_sizes_32[32] = {
+ 4, 4, 8, 2, 0, 0, 0, 0,
+ 4, 4, 8, 2, 4, 4, 8, 2,
+ 28, 0,108, 10, 2, 10, 0, 8,
+ 28, 0,108, 10, 2, 10, 2, 8
+};
+
+int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
+ void *data_address)
+{
+ FPU_REG loaded_data;
+ FPU_REG *st0_ptr;
+ u_char st0_tag = TAG_Empty; /* This is just to stop a gcc warning. */
+ u_char loaded_tag;
+
+ st0_ptr = NULL; /* Initialized just to stop compiler warnings. */
+
+ if ( addr_modes.default_mode & PROTECTED )
+ {
+ if ( addr_modes.default_mode == SEG32 )
+ {
+ if ( access_limit < data_sizes_32[type] )
+ math_abort(FPU_info,SIGSEGV);
+ }
+ else if ( addr_modes.default_mode == PM16 )
+ {
+ if ( access_limit < data_sizes_16[type] )
+ math_abort(FPU_info,SIGSEGV);
+ }
+#ifdef PARANOID
+ else
+ EXCEPTION(EX_INTERNAL|0x140);
+#endif /* PARANOID */
+ }
+
+ switch ( type_table[type] )
+ {
+ case _NONE_:
+ break;
+ case _REG0_:
+ st0_ptr = &st(0); /* Some of these instructions pop after
+ storing */
+ st0_tag = FPU_gettag0();
+ break;
+ case _PUSH_:
+ {
+ if ( FPU_gettagi(-1) != TAG_Empty )
+ { FPU_stack_overflow(); return 0; }
+ top--;
+ st0_ptr = &st(0);
+ }
+ break;
+ case _null_:
+ FPU_illegal();
+ return 0;
+#ifdef PARANOID
+ default:
+ EXCEPTION(EX_INTERNAL|0x141);
+ return 0;
+#endif /* PARANOID */
+ }
+
+ switch ( type )
+ {
+ case 000: /* fld m32real */
+ clear_C1();
+ loaded_tag = FPU_load_single((float *)data_address, &loaded_data);
+ if ( (loaded_tag == TAG_Special)
+ && isNaN(&loaded_data)
+ && (real_1op_NaN(&loaded_data) < 0) )
+ {
+ top++;
+ break;
+ }
+ FPU_copy_to_reg0(&loaded_data, loaded_tag);
+ break;
+ case 001: /* fild m32int */
+ clear_C1();
+ loaded_tag = FPU_load_int32((s32 *)data_address, &loaded_data);
+ FPU_copy_to_reg0(&loaded_data, loaded_tag);
+ break;
+ case 002: /* fld m64real */
+ clear_C1();
+ loaded_tag = FPU_load_double((double *)data_address, &loaded_data);
+ if ( (loaded_tag == TAG_Special)
+ && isNaN(&loaded_data)
+ && (real_1op_NaN(&loaded_data) < 0) )
+ {
+ top++;
+ break;
+ }
+ FPU_copy_to_reg0(&loaded_data, loaded_tag);
+ break;
+ case 003: /* fild m16int */
+ clear_C1();
+ loaded_tag = FPU_load_int16((s16 *)data_address, &loaded_data);
+ FPU_copy_to_reg0(&loaded_data, loaded_tag);
+ break;
+ case 010: /* fst m32real */
+ clear_C1();
+ FPU_store_single(st0_ptr, st0_tag, (float *)data_address);
+ break;
+ case 011: /* fist m32int */
+ clear_C1();
+ FPU_store_int32(st0_ptr, st0_tag, (s32 *)data_address);
+ break;
+ case 012: /* fst m64real */
+ clear_C1();
+ FPU_store_double(st0_ptr, st0_tag, (double *)data_address);
+ break;
+ case 013: /* fist m16int */
+ clear_C1();
+ FPU_store_int16(st0_ptr, st0_tag, (s16 *)data_address);
+ break;
+ case 014: /* fstp m32real */
+ clear_C1();
+ if ( FPU_store_single(st0_ptr, st0_tag, (float *)data_address) )
+ pop_0(); /* pop only if the number was actually stored
+ (see the 80486 manual p16-28) */
+ break;
+ case 015: /* fistp m32int */
+ clear_C1();
+ if ( FPU_store_int32(st0_ptr, st0_tag, (s32 *)data_address) )
+ pop_0(); /* pop only if the number was actually stored
+ (see the 80486 manual p16-28) */
+ break;
+ case 016: /* fstp m64real */
+ clear_C1();
+ if ( FPU_store_double(st0_ptr, st0_tag, (double *)data_address) )
+ pop_0(); /* pop only if the number was actually stored
+ (see the 80486 manual p16-28) */
+ break;
+ case 017: /* fistp m16int */
+ clear_C1();
+ if ( FPU_store_int16(st0_ptr, st0_tag, (s16 *)data_address) )
+ pop_0(); /* pop only if the number was actually stored
+ (see the 80486 manual p16-28) */
+ break;
+ case 020: /* fldenv m14/28byte */
+ fldenv(addr_modes, (u_char *)data_address);
+ /* Ensure that the values just loaded are not changed by
+ fix-up operations. */
+ return 1;
+ case 022: /* frstor m94/108byte */
+ frstor(addr_modes, (u_char *)data_address);
+ /* Ensure that the values just loaded are not changed by
+ fix-up operations. */
+ return 1;
+ case 023: /* fbld m80dec */
+ clear_C1();
+ loaded_tag = FPU_load_bcd((u_char *)data_address);
+ FPU_settag0(loaded_tag);
+ break;
+ case 024: /* fldcw */
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_READ, data_address, 2);
+ FPU_get_user(control_word, (u16 *) data_address);
+ RE_ENTRANT_CHECK_ON;
+ if ( partial_status & ~control_word & CW_Exceptions )
+ partial_status |= (SW_Summary | SW_Backward);
+ else
+ partial_status &= ~(SW_Summary | SW_Backward);
+#ifdef PECULIAR_486
+ control_word |= 0x40; /* An 80486 appears to always set this bit */
+#endif /* PECULIAR_486 */
+ return 1;
+ case 025: /* fld m80real */
+ clear_C1();
+ loaded_tag = FPU_load_extended((long double *)data_address, 0);
+ FPU_settag0(loaded_tag);
+ break;
+ case 027: /* fild m64int */
+ clear_C1();
+ loaded_tag = FPU_load_int64((s64 *)data_address);
+ FPU_settag0(loaded_tag);
+ break;
+ case 030: /* fstenv m14/28byte */
+ fstenv(addr_modes, (u_char *)data_address);
+ return 1;
+ case 032: /* fsave */
+ fsave(addr_modes, (u_char *)data_address);
+ return 1;
+ case 033: /* fbstp m80dec */
+ clear_C1();
+ if ( FPU_store_bcd(st0_ptr, st0_tag, (u_char *)data_address) )
+ pop_0(); /* pop only if the number was actually stored
+ (see the 80486 manual p16-28) */
+ break;
+ case 034: /* fstcw m16int */
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,data_address,2);
+ FPU_put_user(control_word, (u16 *) data_address);
+ RE_ENTRANT_CHECK_ON;
+ return 1;
+ case 035: /* fstp m80real */
+ clear_C1();
+ if ( FPU_store_extended(st0_ptr, st0_tag, (long double *)data_address) )
+ pop_0(); /* pop only if the number was actually stored
+ (see the 80486 manual p16-28) */
+ break;
+ case 036: /* fstsw m2byte */
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,data_address,2);
+ FPU_put_user(status_word(),(u16 *) data_address);
+ RE_ENTRANT_CHECK_ON;
+ return 1;
+ case 037: /* fistp m64int */
+ clear_C1();
+ if ( FPU_store_int64(st0_ptr, st0_tag, (s64 *)data_address) )
+ pop_0(); /* pop only if the number was actually stored
+ (see the 80486 manual p16-28) */
+ break;
+ }
+ return 0;
+}
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | mul_Xsig.S |
+ | |
+ | Multiply a 12 byte fixed point number by another fixed point number. |
+ | |
+ | Copyright (C) 1992,1994,1995 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
+ | |
+ | Call from C as: |
+ | void mul32_Xsig(Xsig *x, unsigned b) |
+ | |
+ | void mul64_Xsig(Xsig *x, unsigned long long *b) |
+ | |
+ | void mul_Xsig_Xsig(Xsig *x, unsigned *b) |
+ | |
+ | The result is neither rounded nor normalized, and the ls bit or so may |
+ | be wrong. |
+ | |
+ +---------------------------------------------------------------------------*/
+ .file "mul_Xsig.S"
+
+
+#include "fpu_emu.h"
+
+.text
+ENTRY(mul32_Xsig)
+ pushl %ebp
+ movl %esp,%ebp
+ subl $16,%esp
+ pushl %esi
+
+ movl PARAM1,%esi
+ movl PARAM2,%ecx
+
+ xor %eax,%eax
+ movl %eax,-4(%ebp)
+ movl %eax,-8(%ebp)
+
+ movl (%esi),%eax /* lsl of Xsig */
+ mull %ecx /* msl of b */
+ movl %edx,-12(%ebp)
+
+ movl 4(%esi),%eax /* midl of Xsig */
+ mull %ecx /* msl of b */
+ addl %eax,-12(%ebp)
+ adcl %edx,-8(%ebp)
+ adcl $0,-4(%ebp)
+
+ movl 8(%esi),%eax /* msl of Xsig */
+ mull %ecx /* msl of b */
+ addl %eax,-8(%ebp)
+ adcl %edx,-4(%ebp)
+
+ movl -12(%ebp),%eax
+ movl %eax,(%esi)
+ movl -8(%ebp),%eax
+ movl %eax,4(%esi)
+ movl -4(%ebp),%eax
+ movl %eax,8(%esi)
+
+ popl %esi
+ leave
+ ret
+
+
+ENTRY(mul64_Xsig)
+ pushl %ebp
+ movl %esp,%ebp
+ subl $16,%esp
+ pushl %esi
+
+ movl PARAM1,%esi
+ movl PARAM2,%ecx
+
+ xor %eax,%eax
+ movl %eax,-4(%ebp)
+ movl %eax,-8(%ebp)
+
+ movl (%esi),%eax /* lsl of Xsig */
+ mull 4(%ecx) /* msl of b */
+ movl %edx,-12(%ebp)
+
+ movl 4(%esi),%eax /* midl of Xsig */
+ mull (%ecx) /* lsl of b */
+ addl %edx,-12(%ebp)
+ adcl $0,-8(%ebp)
+ adcl $0,-4(%ebp)
+
+ movl 4(%esi),%eax /* midl of Xsig */
+ mull 4(%ecx) /* msl of b */
+ addl %eax,-12(%ebp)
+ adcl %edx,-8(%ebp)
+ adcl $0,-4(%ebp)
+
+ movl 8(%esi),%eax /* msl of Xsig */
+ mull (%ecx) /* lsl of b */
+ addl %eax,-12(%ebp)
+ adcl %edx,-8(%ebp)
+ adcl $0,-4(%ebp)
+
+ movl 8(%esi),%eax /* msl of Xsig */
+ mull 4(%ecx) /* msl of b */
+ addl %eax,-8(%ebp)
+ adcl %edx,-4(%ebp)
+
+ movl -12(%ebp),%eax
+ movl %eax,(%esi)
+ movl -8(%ebp),%eax
+ movl %eax,4(%esi)
+ movl -4(%ebp),%eax
+ movl %eax,8(%esi)
+
+ popl %esi
+ leave
+ ret
+
+
+
+ENTRY(mul_Xsig_Xsig)
+ pushl %ebp
+ movl %esp,%ebp
+ subl $16,%esp
+ pushl %esi
+
+ movl PARAM1,%esi
+ movl PARAM2,%ecx
+
+ xor %eax,%eax
+ movl %eax,-4(%ebp)
+ movl %eax,-8(%ebp)
+
+ movl (%esi),%eax /* lsl of Xsig */
+ mull 8(%ecx) /* msl of b */
+ movl %edx,-12(%ebp)
+
+ movl 4(%esi),%eax /* midl of Xsig */
+ mull 4(%ecx) /* midl of b */
+ addl %edx,-12(%ebp)
+ adcl $0,-8(%ebp)
+ adcl $0,-4(%ebp)
+
+ movl 8(%esi),%eax /* msl of Xsig */
+ mull (%ecx) /* lsl of b */
+ addl %edx,-12(%ebp)
+ adcl $0,-8(%ebp)
+ adcl $0,-4(%ebp)
+
+ movl 4(%esi),%eax /* midl of Xsig */
+ mull 8(%ecx) /* msl of b */
+ addl %eax,-12(%ebp)
+ adcl %edx,-8(%ebp)
+ adcl $0,-4(%ebp)
+
+ movl 8(%esi),%eax /* msl of Xsig */
+ mull 4(%ecx) /* midl of b */
+ addl %eax,-12(%ebp)
+ adcl %edx,-8(%ebp)
+ adcl $0,-4(%ebp)
+
+ movl 8(%esi),%eax /* msl of Xsig */
+ mull 8(%ecx) /* msl of b */
+ addl %eax,-8(%ebp)
+ adcl %edx,-4(%ebp)
+
+ movl -12(%ebp),%edx
+ movl %edx,(%esi)
+ movl -8(%ebp),%edx
+ movl %edx,4(%esi)
+ movl -4(%ebp),%edx
+ movl %edx,8(%esi)
+
+ popl %esi
+ leave
+ ret
+
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | mul_Xsig.S |
+ | |
+ | Multiply a 12 byte fixed point number by another fixed point number. |
+ | |
+ | Copyright (C) 1992,1994,1995 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
+ | |
+ | |
+ | The result is neither rounded nor normalized, and the ls bit or so may |
+ | be wrong. |
+ | |
+ +---------------------------------------------------------------------------*/
+
+
+#include "fpu_emu.h"
+#include "poly.h"
+
+
+void mul32_Xsig(Xsig *x, const u32 ba)
+{
+ Xsig y;
+ u32 zl;
+ u64 b = ba, z;
+
+ z = b * x->lsw;
+ y.lsw = z >> 32;
+
+ z = b * x->midw;
+ y.midw = z >> 32;
+ zl = z;
+ y.lsw += zl;
+ if ( zl > y.lsw )
+ y.midw ++;
+
+ z = b * x->msw;
+ y.msw = z >> 32;
+ zl = z;
+ y.midw += zl;
+ if ( zl > y.midw )
+ y.msw ++;
+
+ *x = y;
+
+}
+
+
+void mul64_Xsig(Xsig *x, const u64 *b)
+{
+ Xsig yh, yl;
+
+ yh = *x;
+ yl = *x;
+ mul32_Xsig(&yh, (*b) >> 32);
+ mul32_Xsig(&yl, *b);
+
+ x->msw = yh.msw;
+ x->midw = yh.midw + yl.msw;
+ if ( yh.midw > x->midw )
+ x->msw ++;
+ x->lsw = yh.lsw + yl.midw;
+ if ( yh.lsw > x->lsw )
+ {
+ x->midw ++;
+ if ( x->midw == 0 )
+ x->msw ++;
+ }
+
+}
+
+
+void mul_Xsig_Xsig(Xsig *x, const Xsig *b)
+{
+ u32 yh;
+ u64 y, z;
+
+ y = b->lsw;
+ y *= x->msw;
+ yh = y >> 32;
+
+ z = b->msw;
+ z <<= 32;
+ z += b->midw;
+ mul64_Xsig(x, &z);
+
+ x->lsw += yh;
+ if ( yh > x->lsw )
+ {
+ x->midw ++;
+ if ( x->midw == 0 )
+ x->msw ++;
+ }
+}
+
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | poly.h |
+ | |
+ | Header file for the FPU-emu poly*.c source files. |
+ | |
+ | Copyright (C) 1994,1999 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@melbpc.org.au |
+ | |
+ | Declarations and definitions for functions operating on Xsig (12-byte |
+ | extended-significand) quantities. |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#ifndef _POLY_H
+#define _POLY_H
+
+/* This 12-byte structure is used to improve the accuracy of computation
+ of transcendental functions.
+ Intended to be used to get results better than 8-byte computation
+ allows. 9-byte would probably be sufficient.
+ */
+typedef struct {
+#ifdef EMU_BIG_ENDIAN
+ u32 msw;
+ u32 midw;
+ u32 lsw;
+#else
+ u32 lsw;
+ u32 midw;
+ u32 msw;
+#endif
+} GCC_ATTRIBUTE((packed)) Xsig;
+
+asmlinkage void mul64(u64 const *a, u64 const *b,
+ u64 *result);
+asmlinkage void polynomial_Xsig(Xsig *, const u64 *x,
+ const u64 terms[], const int n);
+
+asmlinkage void mul32_Xsig(Xsig *, const u32 mult);
+asmlinkage void mul64_Xsig(Xsig *, const u64 *mult);
+asmlinkage void mul_Xsig_Xsig(Xsig *dest, const Xsig *mult);
+
+asmlinkage void shr_Xsig(Xsig *, const int n);
+asmlinkage int round_Xsig(Xsig *);
+asmlinkage int norm_Xsig(Xsig *);
+asmlinkage void div_Xsig(const Xsig *x1, const Xsig *x2, Xsig *dest);
+
+/* Macro to extract the most significant 32 bits from a 64bit quantity */
+#ifdef EMU_BIG_ENDIAN
+#define LL_MSW(x) (((u32 *)&x)[0])
+#else
+#define LL_MSW(x) (((u32 *)&x)[1])
+#endif
+
+/* Macro to initialize an Xsig struct */
+#ifdef EMU_BIG_ENDIAN
+#define MK_XSIG(a,b,c) { a, b, c }
+#else
+#define MK_XSIG(a,b,c) { c, b, a }
+#endif
+
+/* Macro to access the 8 ms bytes of an Xsig as a 64bit quantity */
+#ifdef EMU_BIG_ENDIAN
+#define XSIG_LL(x) (*(u64 *)&x.msw)
+#else
+#define XSIG_LL(x) (*(u64 *)&x.midw)
+#endif
+
+
+/*
+ Need to run gcc with optimizations on to get these to
+ actually be in-line.
+ */
+
+/* Multiply two fixed-point 32 bit numbers, producing a 32 bit result.
+ The answer is the ms word of the product. */
+BX_C_INLINE
+u32 mul_32_32(const u32 arg1, const u32 arg2)
+{
+#ifdef NO_ASSEMBLER
+ return (((u64)arg1) * arg2) >> 32;
+#else
+/* Some versions of gcc make it difficult to stop eax from being clobbered.
+ Merely specifying that it is used doesn't work...
+ */
+ int retval;
+ asm volatile ("mull %2; movl %%edx,%%eax" \
+ :"=a" (retval) \
+ :"0" (arg1), "g" (arg2) \
+ :"dx");
+ return retval;
+#endif
+}
+
+
+/* Add the 12 byte Xsig x2 to Xsig dest, with no checks for overflow. */
+BX_C_INLINE
+void add_Xsig_Xsig(Xsig *dest, const Xsig *x2)
+{
+#ifdef NO_ASSEMBLER
+ dest->lsw += x2->lsw;
+ if ( dest->lsw < x2->lsw )
+ {
+ dest->midw ++;
+ if ( dest->midw == 0 )
+ dest->msw ++;
+ }
+ dest->midw += x2->midw;
+ if ( dest->midw < x2->midw )
+ {
+ dest->msw ++;
+ }
+ dest->msw += x2->msw;
+#else
+ asm volatile ("movl %1,%%edi; movl %2,%%esi;
+ movl (%%esi),%%eax; addl %%eax,(%%edi);
+ movl 4(%%esi),%%eax; adcl %%eax,4(%%edi);
+ movl 8(%%esi),%%eax; adcl %%eax,8(%%edi);"
+ :"=g" (*dest):"g" (dest), "g" (x2)
+ :"ax","si","di");
+#endif
+}
+
+
+/* Add the 12 byte Xsig x2 to Xsig dest, adjust exp if overflow occurs. */
+BX_C_INLINE
+void add_two_Xsig(Xsig *dest, const Xsig *x2, s32 *exp)
+{
+#ifdef NO_ASSEMBLER
+ int ovfl = 0;
+
+ dest->lsw += x2->lsw;
+ if ( dest->lsw < x2->lsw )
+ {
+ dest->midw ++;
+ if ( dest->midw == 0 )
+ {
+ dest->msw ++;
+ if ( dest->msw == 0 )
+ ovfl = 1;
+ }
+ }
+ dest->midw += x2->midw;
+ if ( dest->midw < x2->midw )
+ {
+ dest->msw ++;
+ if ( dest->msw == 0 )
+ ovfl = 1;
+ }
+ dest->msw += x2->msw;
+ if ( dest->msw < x2->msw )
+ ovfl = 1;
+ if ( ovfl )
+ {
+ (*exp) ++;
+ dest->lsw >>= 1;
+ if ( dest->midw & 1 )
+ dest->lsw |= 0x80000000;
+ dest->midw >>= 1;
+ if ( dest->msw & 1 )
+ dest->midw |= 0x80000000;
+ dest->msw >>= 1;
+ dest->msw |= 0x80000000;
+ }
+#else
+/* Note: the constraints in the asm statement didn't always work properly
+ with gcc 2.5.8. Changing from using edi to using ecx got around the
+ problem, but keep fingers crossed! */
+ asm volatile ("movl %2,%%ecx; movl %3,%%esi;
+ movl (%%esi),%%eax; addl %%eax,(%%ecx);
+ movl 4(%%esi),%%eax; adcl %%eax,4(%%ecx);
+ movl 8(%%esi),%%eax; adcl %%eax,8(%%ecx);
+ jnc 0f;
+ rcrl 8(%%ecx); rcrl 4(%%ecx); rcrl (%%ecx)
+ movl %4,%%ecx; incl (%%ecx)
+ movl $1,%%eax; jmp 1f;
+ 0: xorl %%eax,%%eax;
+ 1:"
+ :"=g" (*exp), "=g" (*dest)
+ :"g" (dest), "g" (x2), "g" (exp)
+ :"cx","si","ax");
+#endif
+}
+
+
+/* Negate the 12 byte Xsig */
+BX_C_INLINE
+void negate_Xsig(Xsig *x)
+{
+#ifdef NO_ASSEMBLER
+ x->lsw = ~x->lsw;
+ x->midw = ~x->midw;
+ x->msw = ~x->msw;
+ x->lsw ++;
+ if ( x->lsw == 0 )
+ {
+ x->midw ++;
+ if ( x->midw == 0 )
+ x->msw ++;
+ }
+#else
+/* Negate (subtract from 1.0) the 12 byte Xsig */
+/* This is faster in a loop on my 386 than using the "neg" instruction. */
+ asm volatile("movl %1,%%esi; "
+ "xorl %%ecx,%%ecx; "
+ "movl %%ecx,%%eax; subl (%%esi),%%eax; movl %%eax,(%%esi); "
+ "movl %%ecx,%%eax; sbbl 4(%%esi),%%eax; movl %%eax,4(%%esi); "
+ "movl %%ecx,%%eax; sbbl 8(%%esi),%%eax; movl %%eax,8(%%esi); "
+ :"=g" (*x):"g" (x):"si","ax","cx");
+#endif
+}
+
+
+#endif /* _POLY_H */
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | poly_2xm1.c |
+ | |
+ | Function to compute 2^x-1 by a polynomial approximation. |
+ | |
+ | Copyright (C) 1992,1993,1994,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "control_w.h"
+#include "poly.h"
+
+
+#define HIPOWER 11
+static const u64 lterms[HIPOWER] =
+{
+ BX_CONST64(0x0000000000000000), /* This term done separately as 12 bytes */
+ BX_CONST64(0xf5fdeffc162c7543),
+ BX_CONST64(0x1c6b08d704a0bfa6),
+ BX_CONST64(0x0276556df749cc21),
+ BX_CONST64(0x002bb0ffcf14f6b8),
+ BX_CONST64(0x0002861225ef751c),
+ BX_CONST64(0x00001ffcbfcd5422),
+ BX_CONST64(0x00000162c005d5f1),
+ BX_CONST64(0x0000000da96ccb1b),
+ BX_CONST64(0x0000000078d1b897),
+ BX_CONST64(0x000000000422b029)
+};
+
+static const Xsig hiterm = MK_XSIG(0xb17217f7, 0xd1cf79ab, 0xc8a39194);
+
+/* Four slices: 0.0 : 0.25 : 0.50 : 0.75 : 1.0,
+ These numbers are 2^(1/4), 2^(1/2), and 2^(3/4)
+ */
+static const Xsig shiftterm0 = MK_XSIG(0, 0, 0);
+static const Xsig shiftterm1 = MK_XSIG(0x9837f051, 0x8db8a96f, 0x46ad2318);
+static const Xsig shiftterm2 = MK_XSIG(0xb504f333, 0xf9de6484, 0x597d89b3);
+static const Xsig shiftterm3 = MK_XSIG(0xd744fcca, 0xd69d6af4, 0x39a68bb9);
+
+static const Xsig *shiftterm[] = { &shiftterm0, &shiftterm1,
+ &shiftterm2, &shiftterm3 };
+
+
+/*--- poly_2xm1() -----------------------------------------------------------+
+ | Requires st(0) which is TAG_Valid and < 1. |
+ +---------------------------------------------------------------------------*/
+int poly_2xm1(u_char sign, FPU_REG *arg, FPU_REG *result)
+{
+ s32 exponent, shift;
+ u64 Xll;
+ Xsig accumulator, Denom, argSignif;
+ u_char tag;
+
+ exponent = exponent16(arg);
+
+#ifdef PARANOID
+ if ( exponent >= 0 ) /* Don't want a |number| >= 1.0 */
+ {
+ /* Number negative, too large, or not Valid. */
+ EXCEPTION(EX_INTERNAL|0x127);
+ return 1;
+ }
+#endif /* PARANOID */
+
+ argSignif.lsw = 0;
+ XSIG_LL(argSignif) = Xll = significand(arg);
+
+ if ( exponent == -1 )
+ {
+ shift = (argSignif.msw & 0x40000000) ? 3 : 2;
+ /* subtract 0.5 or 0.75 */
+ exponent -= 2;
+ XSIG_LL(argSignif) <<= 2;
+ Xll <<= 2;
+ }
+ else if ( exponent == -2 )
+ {
+ shift = 1;
+ /* subtract 0.25 */
+ exponent--;
+ XSIG_LL(argSignif) <<= 1;
+ Xll <<= 1;
+ }
+ else
+ shift = 0;
+
+ if ( exponent < -2 )
+ {
+ /* Shift the argument right by the required places. */
+ if ( FPU_shrx(&Xll, -2-exponent) >= 0x80000000U )
+ Xll++; /* round up */
+ }
+
+ accumulator.lsw = accumulator.midw = accumulator.msw = 0;
+ polynomial_Xsig(&accumulator, &Xll, lterms, HIPOWER-1);
+ mul_Xsig_Xsig(&accumulator, &argSignif);
+ shr_Xsig(&accumulator, 3);
+
+ mul_Xsig_Xsig(&argSignif, &hiterm); /* The leading term */
+ add_two_Xsig(&accumulator, &argSignif, &exponent);
+
+ if ( shift )
+ {
+ /* The argument is large, use the identity:
+ f(x+a) = f(a) * (f(x) + 1) - 1;
+ */
+ shr_Xsig(&accumulator, - exponent);
+ accumulator.msw |= 0x80000000; /* add 1.0 */
+ mul_Xsig_Xsig(&accumulator, shiftterm[shift]);
+ accumulator.msw &= 0x3fffffff; /* subtract 1.0 */
+ exponent = 1;
+ }
+
+ if ( sign != SIGN_POS )
+ {
+ /* The argument is negative, use the identity:
+ f(-x) = -f(x) / (1 + f(x))
+ */
+ Denom.lsw = accumulator.lsw;
+ XSIG_LL(Denom) = XSIG_LL(accumulator);
+ if ( exponent < 0 )
+ shr_Xsig(&Denom, - exponent);
+ else if ( exponent > 0 )
+ {
+ /* exponent must be 1 here */
+ XSIG_LL(Denom) <<= 1;
+ if ( Denom.lsw & 0x80000000 )
+ XSIG_LL(Denom) |= 1;
+ (Denom.lsw) <<= 1;
+ }
+ Denom.msw |= 0x80000000; /* add 1.0 */
+ div_Xsig(&accumulator, &Denom, &accumulator);
+ }
+
+ /* Convert to 64 bit signed-compatible */
+ exponent += round_Xsig(&accumulator);
+
+ result = &st(0);
+ significand(result) = XSIG_LL(accumulator);
+ setexponent16(result, exponent);
+
+ tag = FPU_round(result, 1, 0, FULL_PRECISION, sign);
+
+ setsign(result, sign);
+ FPU_settag0(tag);
+
+ return 0;
+
+}
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | poly_atan.c |
+ | |
+ | Compute the arctan of a FPU_REG, using a polynomial approximation. |
+ | |
+ | Copyright (C) 1992,1993,1994,1997,1999 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@melbpc.org.au |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "status_w.h"
+#include "control_w.h"
+#include "poly.h"
+
+#define HIPOWERon 6 /* odd poly, negative terms */
+static const u64 oddnegterms[HIPOWERon] =
+{
+ BX_CONST64(0x0000000000000000), /* Dummy (not for - 1.0) */
+ BX_CONST64(0x015328437f756467),
+ BX_CONST64(0x0005dda27b73dec6),
+ BX_CONST64(0x0000226bf2bfb91a),
+ BX_CONST64(0x000000ccc439c5f7),
+ BX_CONST64(0x0000000355438407)
+} ;
+
+#define HIPOWERop 6 /* odd poly, positive terms */
+static const u64 oddplterms[HIPOWERop] =
+{
+/* BX_CONST64(0xaaaaaaaaaaaaaaab), transferred to fixedpterm[] */
+ BX_CONST64(0x0db55a71875c9ac2),
+ BX_CONST64(0x0029fce2d67880b0),
+ BX_CONST64(0x0000dfd3908b4596),
+ BX_CONST64(0x00000550fd61dab4),
+ BX_CONST64(0x0000001c9422b3f9),
+ BX_CONST64(0x000000003e3301e1)
+};
+
+static const u64 denomterm = BX_CONST64(0xebd9b842c5c53a0e);
+
+static const Xsig fixedpterm = MK_XSIG(0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa);
+
+static const Xsig pi_signif = MK_XSIG(0xc90fdaa2, 0x2168c234, 0xc4c6628b);
+
+
+/*--- poly_atan() -----------------------------------------------------------+
+ | |
+ +---------------------------------------------------------------------------*/
+void poly_atan(FPU_REG *st0_ptr, u_char st0_tag,
+ FPU_REG *st1_ptr, u_char st1_tag)
+{
+ u_char transformed, inverted,
+ sign1, sign2;
+ s32 exponent;
+ s32 dummy_exp;
+ Xsig accumulator, Numer, Denom, accumulatore, argSignif,
+ argSq, argSqSq;
+ u_char tag;
+
+ sign1 = getsign(st0_ptr);
+ sign2 = getsign(st1_ptr);
+ if ( st0_tag == TAG_Valid )
+ {
+ exponent = exponent(st0_ptr);
+ }
+ else
+ {
+ /* This gives non-compatible stack contents... */
+ FPU_to_exp16(st0_ptr, st0_ptr);
+ exponent = exponent16(st0_ptr);
+ }
+ if ( st1_tag == TAG_Valid )
+ {
+ exponent -= exponent(st1_ptr);
+ }
+ else
+ {
+ /* This gives non-compatible stack contents... */
+ FPU_to_exp16(st1_ptr, st1_ptr);
+ exponent -= exponent16(st1_ptr);
+ }
+
+ if ( (exponent < 0) || ((exponent == 0) &&
+ ((st0_ptr->sigh < st1_ptr->sigh) ||
+ ((st0_ptr->sigh == st1_ptr->sigh) &&
+ (st0_ptr->sigl < st1_ptr->sigl))) ) )
+ {
+ inverted = 1;
+ Numer.lsw = Denom.lsw = 0;
+ XSIG_LL(Numer) = significand(st0_ptr);
+ XSIG_LL(Denom) = significand(st1_ptr);
+ }
+ else
+ {
+ inverted = 0;
+ exponent = -exponent;
+ Numer.lsw = Denom.lsw = 0;
+ XSIG_LL(Numer) = significand(st1_ptr);
+ XSIG_LL(Denom) = significand(st0_ptr);
+ }
+ div_Xsig(&Numer, &Denom, &argSignif);
+ exponent += norm_Xsig(&argSignif);
+
+ if ( (exponent >= -1)
+ || ((exponent == -2) && (argSignif.msw > 0xd413ccd0)) )
+ {
+ /* The argument is greater than sqrt(2)-1 (=0.414213562...) */
+ /* Convert the argument by an identity for atan */
+ transformed = 1;
+
+ if ( exponent >= 0 )
+ {
+#ifdef PARANOID
+ if ( !( (exponent == 0) &&
+ (argSignif.lsw == 0) && (argSignif.midw == 0) &&
+ (argSignif.msw == 0x80000000) ) )
+ {
+ EXCEPTION(EX_INTERNAL|0x104); /* There must be a logic error */
+ return;
+ }
+#endif /* PARANOID */
+ argSignif.msw = 0; /* Make the transformed arg -> 0.0 */
+ }
+ else
+ {
+ Numer.lsw = Denom.lsw = argSignif.lsw;
+ XSIG_LL(Numer) = XSIG_LL(Denom) = XSIG_LL(argSignif);
+
+ if ( exponent < -1 )
+ shr_Xsig(&Numer, -1-exponent);
+ negate_Xsig(&Numer);
+
+ shr_Xsig(&Denom, -exponent);
+ Denom.msw |= 0x80000000;
+
+ div_Xsig(&Numer, &Denom, &argSignif);
+
+ exponent = -1 + norm_Xsig(&argSignif);
+ }
+ }
+ else
+ {
+ transformed = 0;
+ }
+
+ argSq.lsw = argSignif.lsw; argSq.midw = argSignif.midw;
+ argSq.msw = argSignif.msw;
+ mul_Xsig_Xsig(&argSq, &argSq);
+
+ argSqSq.lsw = argSq.lsw; argSqSq.midw = argSq.midw; argSqSq.msw = argSq.msw;
+ mul_Xsig_Xsig(&argSqSq, &argSqSq);
+
+ accumulatore.lsw = argSq.lsw;
+ XSIG_LL(accumulatore) = XSIG_LL(argSq);
+
+ shr_Xsig(&argSq, 2*(-1-exponent-1));
+ shr_Xsig(&argSqSq, 4*(-1-exponent-1));
+
+ /* Now have argSq etc with binary point at the left
+ .1xxxxxxxx */
+
+ /* Do the basic fixed point polynomial evaluation */
+ accumulator.msw = accumulator.midw = accumulator.lsw = 0;
+ polynomial_Xsig(&accumulator, &XSIG_LL(argSqSq),
+ oddplterms, HIPOWERop-1);
+ mul64_Xsig(&accumulator, &XSIG_LL(argSq));
+ negate_Xsig(&accumulator);
+ polynomial_Xsig(&accumulator, &XSIG_LL(argSqSq), oddnegterms, HIPOWERon-1);
+ negate_Xsig(&accumulator);
+ add_two_Xsig(&accumulator, &fixedpterm, &dummy_exp);
+
+ mul64_Xsig(&accumulatore, &denomterm);
+ shr_Xsig(&accumulatore, 1 + 2*(-1-exponent));
+ accumulatore.msw |= 0x80000000;
+
+ div_Xsig(&accumulator, &accumulatore, &accumulator);
+
+ mul_Xsig_Xsig(&accumulator, &argSignif);
+ mul_Xsig_Xsig(&accumulator, &argSq);
+
+ shr_Xsig(&accumulator, 3);
+ negate_Xsig(&accumulator);
+ add_Xsig_Xsig(&accumulator, &argSignif);
+
+ if ( transformed )
+ {
+ /* compute pi/4 - accumulator */
+ shr_Xsig(&accumulator, -1-exponent);
+ negate_Xsig(&accumulator);
+ add_Xsig_Xsig(&accumulator, &pi_signif);
+ exponent = -1;
+ }
+
+ if ( inverted )
+ {
+ /* compute pi/2 - accumulator */
+ shr_Xsig(&accumulator, -exponent);
+ negate_Xsig(&accumulator);
+ add_Xsig_Xsig(&accumulator, &pi_signif);
+ exponent = 0;
+ }
+
+ if ( sign1 )
+ {
+ /* compute pi - accumulator */
+ shr_Xsig(&accumulator, 1 - exponent);
+ negate_Xsig(&accumulator);
+ add_Xsig_Xsig(&accumulator, &pi_signif);
+ exponent = 1;
+ }
+
+ exponent += round_Xsig(&accumulator);
+
+ significand(st1_ptr) = XSIG_LL(accumulator);
+ setexponent16(st1_ptr, exponent);
+
+ tag = FPU_round(st1_ptr, 1, 0, FULL_PRECISION, sign2);
+ FPU_settagi(1, tag);
+
+
+ set_precision_flag_up(); /* We do not really know if up or down,
+ use this as the default. */
+
+}
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | poly_l2.c |
+ | |
+ | Compute the base 2 log of a FPU_REG, using a polynomial approximation. |
+ | |
+ | Copyright (C) 1992,1993,1994,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "control_w.h"
+#include "poly.h"
+
+
+static void log2_kernel(FPU_REG const *arg, u_char argsign,
+ Xsig *accum_result, s32 *expon);
+
+
+/*--- poly_l2() -------------------------------------------------------------+
+ | Base 2 logarithm by a polynomial approximation. |
+ +---------------------------------------------------------------------------*/
+void poly_l2(FPU_REG *st0_ptr, FPU_REG *st1_ptr, u_char st1_sign)
+{
+ s32 exponent, expon, expon_expon;
+ Xsig accumulator, expon_accum, yaccum;
+ u_char sign, argsign;
+ FPU_REG x;
+ int tag;
+
+ exponent = exponent16(st0_ptr);
+
+ /* From st0_ptr, make a number > sqrt(2)/2 and < sqrt(2) */
+ if ( st0_ptr->sigh > (unsigned)0xb504f334 )
+ {
+ /* Treat as sqrt(2)/2 < st0_ptr < 1 */
+ significand(&x) = - significand(st0_ptr);
+ setexponent16(&x, -1);
+ exponent++;
+ argsign = SIGN_NEG;
+ }
+ else
+ {
+ /* Treat as 1 <= st0_ptr < sqrt(2) */
+ x.sigh = st0_ptr->sigh - 0x80000000;
+ x.sigl = st0_ptr->sigl;
+ setexponent16(&x, 0);
+ argsign = SIGN_POS;
+ }
+ tag = FPU_normalize_nuo(&x, 0);
+
+ if ( tag == TAG_Zero )
+ {
+ expon = 0;
+ accumulator.msw = accumulator.midw = accumulator.lsw = 0;
+ }
+ else
+ {
+ log2_kernel(&x, argsign, &accumulator, &expon);
+ }
+
+ if ( exponent < 0 )
+ {
+ sign = SIGN_NEG;
+ exponent = -exponent;
+ }
+ else
+ sign = SIGN_POS;
+ expon_accum.msw = exponent; expon_accum.midw = expon_accum.lsw = 0;
+ if ( exponent )
+ {
+ expon_expon = 31 + norm_Xsig(&expon_accum);
+ shr_Xsig(&accumulator, expon_expon - expon);
+
+ if ( sign ^ argsign )
+ negate_Xsig(&accumulator);
+ add_Xsig_Xsig(&accumulator, &expon_accum);
+ }
+ else
+ {
+ expon_expon = expon;
+ sign = argsign;
+ }
+
+ yaccum.lsw = 0; XSIG_LL(yaccum) = significand(st1_ptr);
+ mul_Xsig_Xsig(&accumulator, &yaccum);
+
+ expon_expon += round_Xsig(&accumulator);
+
+ if ( accumulator.msw == 0 )
+ {
+ FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
+ return;
+ }
+
+ significand(st1_ptr) = XSIG_LL(accumulator);
+ setexponent16(st1_ptr, expon_expon + exponent16(st1_ptr) + 1);
+
+ tag = FPU_round(st1_ptr, 1, 0, FULL_PRECISION, sign ^ st1_sign);
+ FPU_settagi(1, tag);
+
+ set_precision_flag_up(); /* 80486 appears to always do this */
+
+ return;
+
+}
+
+
+/*--- poly_l2p1() -----------------------------------------------------------+
+ | Base 2 logarithm by a polynomial approximation. |
+ | log2(x+1) |
+ +---------------------------------------------------------------------------*/
+int poly_l2p1(u_char sign0, u_char sign1,
+ FPU_REG *st0_ptr, FPU_REG *st1_ptr, FPU_REG *dest)
+{
+ u_char tag;
+ s32 exponent;
+ Xsig accumulator, yaccum;
+
+ if ( exponent16(st0_ptr) < 0 )
+ {
+ log2_kernel(st0_ptr, sign0, &accumulator, &exponent);
+
+ yaccum.lsw = 0;
+ XSIG_LL(yaccum) = significand(st1_ptr);
+ mul_Xsig_Xsig(&accumulator, &yaccum);
+
+ exponent += round_Xsig(&accumulator);
+
+ exponent += exponent16(st1_ptr) + 1;
+ if ( exponent < EXP_WAY_UNDER ) exponent = EXP_WAY_UNDER;
+
+ significand(dest) = XSIG_LL(accumulator);
+ setexponent16(dest, exponent);
+
+ tag = FPU_round(dest, 1, 0, FULL_PRECISION, sign0 ^ sign1);
+ FPU_settagi(1, tag);
+
+ if ( tag == TAG_Valid )
+ set_precision_flag_up(); /* 80486 appears to always do this */
+ }
+ else
+ {
+ /* The magnitude of st0_ptr is far too large. */
+
+ if ( sign0 != SIGN_POS )
+ {
+ /* Trying to get the log of a negative number. */
+#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */
+ changesign(st1_ptr);
+#else
+ if ( arith_invalid(1) < 0 )
+ return 1;
+#endif /* PECULIAR_486 */
+ }
+
+ /* 80486 appears to do this */
+ if ( sign0 == SIGN_NEG )
+ set_precision_flag_down();
+ else
+ set_precision_flag_up();
+ }
+
+ if ( exponent(dest) <= EXP_UNDER )
+ EXCEPTION(EX_Underflow);
+
+ return 0;
+
+}
+
+
+
+
+#undef HIPOWER
+#define HIPOWER 10
+static const u64 logterms[HIPOWER] =
+{
+ BX_CONST64(0x2a8eca5705fc2ef0),
+ BX_CONST64(0xf6384ee1d01febce),
+ BX_CONST64(0x093bb62877cdf642),
+ BX_CONST64(0x006985d8a9ec439b),
+ BX_CONST64(0x0005212c4f55a9c8),
+ BX_CONST64(0x00004326a16927f0),
+ BX_CONST64(0x0000038d1d80a0e7),
+ BX_CONST64(0x0000003141cc80c6),
+ BX_CONST64(0x00000002b1668c9f),
+ BX_CONST64(0x000000002c7a46aa)
+};
+
+static const u32 leadterm = 0xb8000000;
+
+
+/*--- log2_kernel() ---------------------------------------------------------+
+ | Base 2 logarithm by a polynomial approximation. |
+ | log2(x+1) |
+ +---------------------------------------------------------------------------*/
+static void log2_kernel(FPU_REG const *arg, u_char argsign, Xsig *accum_result,
+ s32 *expon)
+{
+ s32 exponent, adj;
+ u64 Xsq;
+ Xsig accumulator, Numer, Denom, argSignif, arg_signif;
+
+ exponent = exponent16(arg);
+ Numer.lsw = Denom.lsw = 0;
+ XSIG_LL(Numer) = XSIG_LL(Denom) = significand(arg);
+ if ( argsign == SIGN_POS )
+ {
+ shr_Xsig(&Denom, 2 - (1 + exponent));
+ Denom.msw |= 0x80000000;
+ div_Xsig(&Numer, &Denom, &argSignif);
+ }
+ else
+ {
+ shr_Xsig(&Denom, 1 - (1 + exponent));
+ negate_Xsig(&Denom);
+ if ( Denom.msw & 0x80000000 )
+ {
+ div_Xsig(&Numer, &Denom, &argSignif);
+ exponent ++;
+ }
+ else
+ {
+ /* Denom must be 1.0 */
+ argSignif.lsw = Numer.lsw; argSignif.midw = Numer.midw;
+ argSignif.msw = Numer.msw;
+ }
+ }
+
+#ifndef PECULIAR_486
+ /* Should check here that |local_arg| is within the valid range */
+ if ( exponent >= -2 )
+ {
+ if ( (exponent > -2) ||
+ (argSignif.msw > (unsigned)0xafb0ccc0) )
+ {
+ /* The argument is too large */
+ }
+ }
+#endif /* PECULIAR_486 */
+
+ arg_signif.lsw = argSignif.lsw; XSIG_LL(arg_signif) = XSIG_LL(argSignif);
+ adj = norm_Xsig(&argSignif);
+ accumulator.lsw = argSignif.lsw; XSIG_LL(accumulator) = XSIG_LL(argSignif);
+ mul_Xsig_Xsig(&accumulator, &accumulator);
+ shr_Xsig(&accumulator, 2*(-1 - (1 + exponent + adj)));
+ Xsq = XSIG_LL(accumulator);
+ if ( accumulator.lsw & 0x80000000 )
+ Xsq++;
+
+ accumulator.msw = accumulator.midw = accumulator.lsw = 0;
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial_Xsig(&accumulator, &Xsq, logterms, HIPOWER-1);
+
+ mul_Xsig_Xsig(&accumulator, &argSignif);
+ shr_Xsig(&accumulator, 6 - adj);
+
+ mul32_Xsig(&arg_signif, leadterm);
+ add_two_Xsig(&accumulator, &arg_signif, &exponent);
+
+ *expon = exponent + 1;
+ accum_result->lsw = accumulator.lsw;
+ accum_result->midw = accumulator.midw;
+ accum_result->msw = accumulator.msw;
+
+}
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | poly_sin.c |
+ | |
+ | Computation of an approximation of the sin function and the cosine |
+ | function by a polynomial. |
+ | |
+ | Copyright (C) 1992,1993,1994,1997,1999 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@melbpc.org.au |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "control_w.h"
+#include "poly.h"
+
+
+#define N_COEFF_P 4
+#define N_COEFF_N 4
+
+static const u64 pos_terms_l[N_COEFF_P] =
+{
+ BX_CONST64(0xaaaaaaaaaaaaaaab),
+ BX_CONST64(0x00d00d00d00cf906),
+ BX_CONST64(0x000006b99159a8bb),
+ BX_CONST64(0x000000000d7392e6)
+};
+
+static const u64 neg_terms_l[N_COEFF_N] =
+{
+ BX_CONST64(0x2222222222222167),
+ BX_CONST64(0x0002e3bc74aab624),
+ BX_CONST64(0x0000000b09229062),
+ BX_CONST64(0x00000000000c7973)
+};
+
+
+
+#define N_COEFF_PH 4
+#define N_COEFF_NH 4
+static const u64 pos_terms_h[N_COEFF_PH] =
+{
+ BX_CONST64(0x0000000000000000),
+ BX_CONST64(0x05b05b05b05b0406),
+ BX_CONST64(0x000049f93edd91a9),
+ BX_CONST64(0x00000000c9c9ed62)
+};
+
+static const u64 neg_terms_h[N_COEFF_NH] =
+{
+ BX_CONST64(0xaaaaaaaaaaaaaa98),
+ BX_CONST64(0x001a01a01a019064),
+ BX_CONST64(0x0000008f76c68a77),
+ BX_CONST64(0x0000000000d58f5e)
+};
+
+
+/*--- poly_sine() -----------------------------------------------------------+
+ | |
+ +---------------------------------------------------------------------------*/
+void poly_sine(FPU_REG *st0_ptr)
+{
+ int exponent, echange;
+ Xsig accumulator, argSqrd, argTo4;
+ s32 fix_up, adj;
+ u64 fixed_arg;
+ FPU_REG result;
+
+ exponent = exponent(st0_ptr);
+
+ accumulator.lsw = accumulator.midw = accumulator.msw = 0;
+
+ /* Split into two ranges, for arguments below and above 1.0 */
+ /* The boundary between upper and lower is approx 0.88309101259 */
+ if ( (exponent < -1) || ((exponent == -1) && (st0_ptr->sigh <= 0xe21240aa)) )
+ {
+ /* The argument is <= 0.88309101259 */
+
+ argSqrd.msw = st0_ptr->sigh; argSqrd.midw = st0_ptr->sigl; argSqrd.lsw = 0;
+ mul64_Xsig(&argSqrd, &significand(st0_ptr));
+ shr_Xsig(&argSqrd, 2*(-1-exponent));
+ argTo4.msw = argSqrd.msw; argTo4.midw = argSqrd.midw;
+ argTo4.lsw = argSqrd.lsw;
+ mul_Xsig_Xsig(&argTo4, &argTo4);
+
+ polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_l,
+ N_COEFF_N-1);
+ mul_Xsig_Xsig(&accumulator, &argSqrd);
+ negate_Xsig(&accumulator);
+
+ polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_l,
+ N_COEFF_P-1);
+
+ shr_Xsig(&accumulator, 2); /* Divide by four */
+ accumulator.msw |= 0x80000000; /* Add 1.0 */
+
+ mul64_Xsig(&accumulator, &significand(st0_ptr));
+ mul64_Xsig(&accumulator, &significand(st0_ptr));
+ mul64_Xsig(&accumulator, &significand(st0_ptr));
+
+ /* Divide by four, FPU_REG compatible, etc */
+ exponent = 3*exponent;
+
+ /* The minimum exponent difference is 3 */
+ shr_Xsig(&accumulator, exponent(st0_ptr) - exponent);
+
+ negate_Xsig(&accumulator);
+ XSIG_LL(accumulator) += significand(st0_ptr);
+
+ echange = round_Xsig(&accumulator);
+
+ setexponentpos(&result, exponent(st0_ptr) + echange);
+ }
+ else
+ {
+ /* The argument is > 0.88309101259 */
+ /* We use sin(st(0)) = cos(pi/2-st(0)) */
+
+ fixed_arg = significand(st0_ptr);
+
+ if ( exponent == 0 )
+ {
+ /* The argument is >= 1.0 */
+
+ /* Put the binary point at the left. */
+ fixed_arg <<= 1;
+ }
+ /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */
+ fixed_arg = BX_CONST64(0x921fb54442d18469) - fixed_arg;
+ /* There is a special case which arises due to rounding, to fix here. */
+ if ( fixed_arg == BX_CONST64(0xffffffffffffffff))
+ fixed_arg = 0;
+
+ XSIG_LL(argSqrd) = fixed_arg; argSqrd.lsw = 0;
+ mul64_Xsig(&argSqrd, &fixed_arg);
+
+ XSIG_LL(argTo4) = XSIG_LL(argSqrd); argTo4.lsw = argSqrd.lsw;
+ mul_Xsig_Xsig(&argTo4, &argTo4);
+
+ polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_h,
+ N_COEFF_NH-1);
+ mul_Xsig_Xsig(&accumulator, &argSqrd);
+ negate_Xsig(&accumulator);
+
+ polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_h,
+ N_COEFF_PH-1);
+ negate_Xsig(&accumulator);
+
+ mul64_Xsig(&accumulator, &fixed_arg);
+ mul64_Xsig(&accumulator, &fixed_arg);
+
+ shr_Xsig(&accumulator, 3);
+ negate_Xsig(&accumulator);
+
+ add_Xsig_Xsig(&accumulator, &argSqrd);
+
+ shr_Xsig(&accumulator, 1);
+
+ accumulator.lsw |= 1; /* A zero accumulator here would cause problems */
+ negate_Xsig(&accumulator);
+
+ /* The basic computation is complete. Now fix the answer to
+ compensate for the error due to the approximation used for
+ pi/2
+ */
+
+ /* This has an exponent of -65 */
+ fix_up = 0x898cc517;
+ /* The fix-up needs to be improved for larger args */
+ if ( argSqrd.msw & 0xffc00000 )
+ {
+ /* Get about 32 bit precision in these: */
+ fix_up -= mul_32_32(0x898cc517, argSqrd.msw) / 6;
+ }
+ fix_up = mul_32_32(fix_up, LL_MSW(fixed_arg));
+
+ adj = accumulator.lsw; /* temp save */
+ accumulator.lsw -= fix_up;
+ if ( accumulator.lsw > adj )
+ XSIG_LL(accumulator) --;
+
+ echange = round_Xsig(&accumulator);
+
+ setexponentpos(&result, echange - 1);
+ }
+
+ significand(&result) = XSIG_LL(accumulator);
+ setsign(&result, getsign(st0_ptr));
+ FPU_copy_to_reg0(&result, TAG_Valid);
+
+#ifdef PARANOID
+ if ( (exponent(&result) >= 0)
+ && (significand(&result) > BX_CONST64(0x8000000000000000)) )
+ {
+ EXCEPTION(EX_INTERNAL|0x150);
+ }
+#endif /* PARANOID */
+
+}
+
+
+
+/*--- poly_cos() ------------------------------------------------------------+
+ | |
+ +---------------------------------------------------------------------------*/
+void poly_cos(FPU_REG *st0_ptr)
+{
+ FPU_REG result;
+ s32 exponent, exp2, echange;
+ Xsig accumulator, argSqrd, fix_up, argTo4;
+ u64 fixed_arg;
+
+#ifdef PARANOID
+ if ( (exponent(st0_ptr) > 0)
+ || ((exponent(st0_ptr) == 0)
+ && (significand(st0_ptr) > BX_CONST64(0xc90fdaa22168c234))) )
+ {
+ EXCEPTION(EX_Invalid);
+ FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
+ return;
+ }
+#endif /* PARANOID */
+
+ exponent = exponent(st0_ptr);
+
+ accumulator.lsw = accumulator.midw = accumulator.msw = 0;
+
+ if ( (exponent < -1) || ((exponent == -1) && (st0_ptr->sigh <= 0xb00d6f54)) )
+ {
+ /* arg is < 0.687705 */
+
+ argSqrd.msw = st0_ptr->sigh; argSqrd.midw = st0_ptr->sigl;
+ argSqrd.lsw = 0;
+ mul64_Xsig(&argSqrd, &significand(st0_ptr));
+
+ if ( exponent < -1 )
+ {
+ /* shift the argument right by the required places */
+ shr_Xsig(&argSqrd, 2*(-1-exponent));
+ }
+
+ argTo4.msw = argSqrd.msw; argTo4.midw = argSqrd.midw;
+ argTo4.lsw = argSqrd.lsw;
+ mul_Xsig_Xsig(&argTo4, &argTo4);
+
+ polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_h,
+ N_COEFF_NH-1);
+ mul_Xsig_Xsig(&accumulator, &argSqrd);
+ negate_Xsig(&accumulator);
+
+ polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_h,
+ N_COEFF_PH-1);
+ negate_Xsig(&accumulator);
+
+ mul64_Xsig(&accumulator, &significand(st0_ptr));
+ mul64_Xsig(&accumulator, &significand(st0_ptr));
+ shr_Xsig(&accumulator, -2*(1+exponent));
+
+ shr_Xsig(&accumulator, 3);
+ negate_Xsig(&accumulator);
+
+ add_Xsig_Xsig(&accumulator, &argSqrd);
+
+ shr_Xsig(&accumulator, 1);
+
+ /* It doesn't matter if accumulator is all zero here, the
+ following code will work ok */
+ negate_Xsig(&accumulator);
+
+ if ( accumulator.lsw & 0x80000000 )
+ XSIG_LL(accumulator) ++;
+ if ( accumulator.msw == 0 )
+ {
+ /* The result is 1.0 */
+ FPU_copy_to_reg0(&CONST_1, TAG_Valid);
+ return;
+ }
+ else
+ {
+ significand(&result) = XSIG_LL(accumulator);
+
+ /* will be a valid positive nr with expon = -1 */
+ setexponentpos(&result, -1);
+ }
+ }
+ else
+ {
+ fixed_arg = significand(st0_ptr);
+
+ if ( exponent == 0 )
+ {
+ /* The argument is >= 1.0 */
+
+ /* Put the binary point at the left. */
+ fixed_arg <<= 1;
+ }
+ /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */
+ fixed_arg = BX_CONST64(0x921fb54442d18469) - fixed_arg;
+ /* There is a special case which arises due to rounding, to fix here. */
+ if ( fixed_arg == BX_CONST64(0xffffffffffffffff))
+ fixed_arg = 0;
+
+ exponent = -1;
+ exp2 = -1;
+
+ /* A shift is needed here only for a narrow range of arguments,
+ i.e. for fixed_arg approx 2^-32, but we pick up more... */
+ if ( !(LL_MSW(fixed_arg) & 0xffff0000) )
+ {
+ fixed_arg <<= 16;
+ exponent -= 16;
+ exp2 -= 16;
+ }
+
+ XSIG_LL(argSqrd) = fixed_arg; argSqrd.lsw = 0;
+ mul64_Xsig(&argSqrd, &fixed_arg);
+
+ if ( exponent < -1 )
+ {
+ /* shift the argument right by the required places */
+ shr_Xsig(&argSqrd, 2*(-1-exponent));
+ }
+
+ argTo4.msw = argSqrd.msw; argTo4.midw = argSqrd.midw;
+ argTo4.lsw = argSqrd.lsw;
+ mul_Xsig_Xsig(&argTo4, &argTo4);
+
+ polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_l,
+ N_COEFF_N-1);
+ mul_Xsig_Xsig(&accumulator, &argSqrd);
+ negate_Xsig(&accumulator);
+
+ polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_l,
+ N_COEFF_P-1);
+
+ shr_Xsig(&accumulator, 2); /* Divide by four */
+ accumulator.msw |= 0x80000000; /* Add 1.0 */
+
+ mul64_Xsig(&accumulator, &fixed_arg);
+ mul64_Xsig(&accumulator, &fixed_arg);
+ mul64_Xsig(&accumulator, &fixed_arg);
+
+ /* Divide by four, FPU_REG compatible, etc */
+ exponent = 3*exponent;
+
+ /* The minimum exponent difference is 3 */
+ shr_Xsig(&accumulator, exp2 - exponent);
+
+ negate_Xsig(&accumulator);
+ XSIG_LL(accumulator) += fixed_arg;
+
+ /* The basic computation is complete. Now fix the answer to
+ compensate for the error due to the approximation used for
+ pi/2
+ */
+
+ /* This has an exponent of -65 */
+ XSIG_LL(fix_up) = BX_CONST64(0x898cc51701b839a2);
+ fix_up.lsw = 0;
+
+ /* The fix-up needs to be improved for larger args */
+ if ( argSqrd.msw & 0xffc00000 )
+ {
+ /* Get about 32 bit precision in these: */
+ fix_up.msw -= mul_32_32(0x898cc517, argSqrd.msw) / 2;
+ fix_up.msw += mul_32_32(0x898cc517, argTo4.msw) / 24;
+ }
+
+ exp2 += norm_Xsig(&accumulator);
+ shr_Xsig(&accumulator, 1); /* Prevent overflow */
+ exp2++;
+ shr_Xsig(&fix_up, 65 + exp2);
+
+ add_Xsig_Xsig(&accumulator, &fix_up);
+
+ echange = round_Xsig(&accumulator);
+
+ setexponentpos(&result, exp2 + echange);
+ significand(&result) = XSIG_LL(accumulator);
+ }
+
+ FPU_copy_to_reg0(&result, TAG_Valid);
+
+#ifdef PARANOID
+ if ( (exponent(&result) >= 0)
+ && (significand(&result) > BX_CONST64(0x8000000000000000)) )
+ {
+ EXCEPTION(EX_INTERNAL|0x151);
+ }
+#endif /* PARANOID */
+
+}
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | poly_tan.c |
+ | |
+ | Compute the tan of a FPU_REG, using a polynomial approximation. |
+ | |
+ | Copyright (C) 1992,1993,1994,1997,1999 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@melbpc.org.au |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "control_w.h"
+#include "poly.h"
+
+//#define DEBUG_POLY_TAN // ***********
+
+#define HiPOWERop 3 /* odd poly, positive terms */
+static const u64 oddplterm[HiPOWERop] =
+{
+ BX_CONST64(0x0000000000000000),
+ BX_CONST64(0x0051a1cf08fca228),
+ BX_CONST64(0x0000000071284ff7)
+};
+
+#define HiPOWERon 2 /* odd poly, negative terms */
+static const u64 oddnegterm[HiPOWERon] =
+{
+ BX_CONST64(0x1291a9a184244e80),
+ BX_CONST64(0x0000583245819c21)
+};
+
+#define HiPOWERep 2 /* even poly, positive terms */
+static const u64 evenplterm[HiPOWERep] =
+{
+ BX_CONST64(0x0e848884b539e888),
+ BX_CONST64(0x00003c7f18b887da)
+};
+
+#define HiPOWERen 2 /* even poly, negative terms */
+static const u64 evennegterm[HiPOWERen] =
+{
+ BX_CONST64(0xf1f0200fd51569cc),
+ BX_CONST64(0x003afb46105c4432)
+};
+
+static const u64 twothirds = BX_CONST64(0xaaaaaaaaaaaaaaab);
+
+
+/*--- poly_tan() ------------------------------------------------------------+
+ | |
+ +---------------------------------------------------------------------------*/
+void poly_tan(FPU_REG *st0_ptr, int invert)
+{
+ s32 exponent;
+ Xsig argSq, argSqSq, accumulatoro, accumulatore, accum,
+ argSignif;
+
+ exponent = exponent(st0_ptr);
+
+
+#ifdef PARANOID
+ if ( signnegative(st0_ptr) ) /* Can't hack a number < 0.0 */
+ { arith_invalid(0); return; } /* Need a positive number */
+#endif /* PARANOID */
+
+ if ( (exponent >= 0)
+ || ((exponent == -1) && (st0_ptr->sigh > 0xc90fdaa2)) )
+ {
+ EXCEPTION(0x250);
+ }
+ else
+ {
+ argSignif.lsw = 0;
+ XSIG_LL(accum) = XSIG_LL(argSignif) = significand(st0_ptr);
+
+ if ( exponent < -1 )
+ {
+ /* shift the argument right by the required places */
+ if ( FPU_shrx(&XSIG_LL(accum), -1-exponent) >= 0x80000000U )
+ XSIG_LL(accum) ++; /* round up */
+ }
+ }
+
+ XSIG_LL(argSq) = XSIG_LL(accum); argSq.lsw = accum.lsw;
+ mul_Xsig_Xsig(&argSq, &argSq);
+ XSIG_LL(argSqSq) = XSIG_LL(argSq); argSqSq.lsw = argSq.lsw;
+ mul_Xsig_Xsig(&argSqSq, &argSqSq);
+
+ /* Compute the negative terms for the numerator polynomial */
+ accumulatoro.msw = accumulatoro.midw = accumulatoro.lsw = 0;
+ polynomial_Xsig(&accumulatoro, &XSIG_LL(argSqSq), oddnegterm, HiPOWERon-1);
+ mul_Xsig_Xsig(&accumulatoro, &argSq);
+ negate_Xsig(&accumulatoro);
+ /* Add the positive terms */
+ polynomial_Xsig(&accumulatoro, &XSIG_LL(argSqSq), oddplterm, HiPOWERop-1);
+
+
+ /* Compute the positive terms for the denominator polynomial */
+ accumulatore.msw = accumulatore.midw = accumulatore.lsw = 0;
+ polynomial_Xsig(&accumulatore, &XSIG_LL(argSqSq), evenplterm, HiPOWERep-1);
+ mul_Xsig_Xsig(&accumulatore, &argSq);
+ negate_Xsig(&accumulatore);
+ /* Add the negative terms */
+ polynomial_Xsig(&accumulatore, &XSIG_LL(argSqSq), evennegterm, HiPOWERen-1);
+ /* Multiply by arg^2 */
+ mul64_Xsig(&accumulatore, &XSIG_LL(argSignif));
+ mul64_Xsig(&accumulatore, &XSIG_LL(argSignif));
+ /* de-normalize and divide by 2 */
+ shr_Xsig(&accumulatore, -2*(1+exponent) + 1);
+ negate_Xsig(&accumulatore); /* This does 1 - accumulator */
+
+ /* Now find the ratio. */
+ if ( accumulatore.msw == 0 )
+ {
+ /* accumulatoro must contain 1.0 here, (actually, 0) but it
+ really doesn't matter what value we use because it will
+ have negligible effect in later calculations
+ */
+ XSIG_LL(accum) = BX_CONST64(0x8000000000000000);
+ accum.lsw = 0;
+ }
+ else
+ {
+ div_Xsig(&accumulatoro, &accumulatore, &accum);
+ }
+
+ /* Multiply by 1/3 * arg^3 */
+ mul64_Xsig(&accum, &XSIG_LL(argSignif));
+ mul64_Xsig(&accum, &XSIG_LL(argSignif));
+ mul64_Xsig(&accum, &XSIG_LL(argSignif));
+ mul64_Xsig(&accum, &twothirds);
+ shr_Xsig(&accum, -2*(exponent+1));
+
+
+ /* tan(arg) = arg + accum */
+ add_two_Xsig(&accum, &argSignif, &exponent);
+
+ if ( invert )
+ {
+ /* accum now contains tan(pi/2 - arg).
+ Use tan(arg) = 1.0 / tan(pi/2 - arg)
+ */
+ accumulatoro.lsw = accumulatoro.midw = 0;
+ accumulatoro.msw = 0x80000000;
+ div_Xsig(&accumulatoro, &accum, &accum);
+ exponent = - exponent;
+ }
+
+
+ /* Transfer the result */
+ exponent += round_Xsig(&accum);
+ FPU_settag0(TAG_Valid);
+ significand(st0_ptr) = XSIG_LL(accum);
+ setexponent16(st0_ptr, exponent + EXTENDED_Ebias); /* Result is positive. */
+
+}
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | polynomial_Xsig.S |
+ | |
+ | Fixed point arithmetic polynomial evaluation. |
+ | |
+ | Copyright (C) 1992,1993,1994,1995,1999 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@melbpc.org.au |
+ | |
+ | Call from C as: |
+ | void polynomial_Xsig(Xsig *accum, unsigned long long *x, |
+ | unsigned long long terms[], int n) |
+ | |
+ | Computes: |
+ | terms[0] + (terms[1] + (terms[2] + ... + (terms[n]*x)*x)*x)*x) ... )*x |
+ | and adds the result to the 12 byte Xsig. |
+ | The terms[] are each 8 bytes, but all computation is performed to 12 byte |
+ | precision. |
+ | |
+ | This function must be used carefully: most overflow of intermediate |
+ | results is controlled, but overflow of the result is not. |
+ | |
+ +---------------------------------------------------------------------------*/
+ .file "polynomial_Xsig.S"
+
+#include "fpu_emu.h"
+
+
+#define TERM_SIZE $8
+#define SUM_MS -20(%ebp) /* sum ms long */
+#define SUM_MIDDLE -24(%ebp) /* sum middle long */
+#define SUM_LS -28(%ebp) /* sum ls long */
+#define ACCUM_MS -4(%ebp) /* accum ms long */
+#define ACCUM_MIDDLE -8(%ebp) /* accum middle long */
+#define ACCUM_LS -12(%ebp) /* accum ls long */
+#define OVERFLOWED -16(%ebp) /* addition overflow flag */
+
+.text
+ENTRY(polynomial_Xsig)
+ pushl %ebp
+ movl %esp,%ebp
+ subl $32,%esp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM2,%esi /* x */
+ movl PARAM3,%edi /* terms */
+
+ movl TERM_SIZE,%eax
+ mull PARAM4 /* n */
+ addl %eax,%edi
+
+ movl 4(%edi),%edx /* terms[n] */
+ movl %edx,SUM_MS
+ movl (%edi),%edx /* terms[n] */
+ movl %edx,SUM_MIDDLE
+ xor %eax,%eax
+ movl %eax,SUM_LS
+ movb %al,OVERFLOWED
+
+ subl TERM_SIZE,%edi
+ decl PARAM4
+ js L_accum_done
+
+L_accum_loop:
+ xor %eax,%eax
+ movl %eax,ACCUM_MS
+ movl %eax,ACCUM_MIDDLE
+
+ movl SUM_MIDDLE,%eax
+ mull (%esi) /* x ls long */
+ movl %edx,ACCUM_LS
+
+ movl SUM_LS,%eax
+ mull 4(%esi) /* x ms long */
+ addl %edx,ACCUM_LS
+ adcl $0,ACCUM_MIDDLE
+ adcl $0,ACCUM_MS
+
+ movl SUM_MIDDLE,%eax
+ mull 4(%esi) /* x ms long */
+ addl %eax,ACCUM_LS
+ adcl %edx,ACCUM_MIDDLE
+ adcl $0,ACCUM_MS
+
+ movl SUM_MS,%eax
+ mull (%esi) /* x ls long */
+ addl %eax,ACCUM_LS
+ adcl %edx,ACCUM_MIDDLE
+ adcl $0,ACCUM_MS
+
+ movl SUM_MS,%eax
+ mull 4(%esi) /* x ms long */
+ addl %eax,ACCUM_MIDDLE
+ adcl %edx,ACCUM_MS
+
+ testb $0xff,OVERFLOWED
+ jz L_no_overflow
+
+ movl (%esi),%eax
+ addl %eax,ACCUM_MIDDLE
+ movl 4(%esi),%eax
+ adcl %eax,ACCUM_MS /* This could overflow too */
+
+L_no_overflow:
+
+/*
+ * Now put the sum of next term and the accumulator
+ * into the sum register
+ */
+ movl ACCUM_LS,%eax
+// addl (%edi),%eax /* term ls long */
+ movl %eax,SUM_LS
+ movl ACCUM_MIDDLE,%eax
+// adcl (%edi),%eax /* term ls long */
+ addl (%edi),%eax /* term ls long */
+ movl %eax,SUM_MIDDLE
+ movl ACCUM_MS,%eax
+ adcl 4(%edi),%eax /* term ms long */
+ movl %eax,SUM_MS
+ sbbb %al,%al
+ movb %al,OVERFLOWED /* Used in the next iteration */
+
+ subl TERM_SIZE,%edi
+ decl PARAM4
+ jns L_accum_loop
+
+L_accum_done:
+ movl PARAM1,%edi /* accum */
+ movl SUM_LS,%eax
+ addl %eax,(%edi)
+ movl SUM_MIDDLE,%eax
+ adcl %eax,4(%edi)
+ movl SUM_MS,%eax
+ adcl %eax,8(%edi)
+
+ popl %ebx
+ popl %edi
+ popl %esi
+ leave
+ ret
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | polynomial_Xsig.c |
+ | |
+ | Fixed point arithmetic polynomial evaluation. |
+ | |
+ | Copyright (C) 1992,1993,1994,1995,1999 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@melbpc.org.au |
+ | |
+ | Computes: |
+ | terms[0] + (terms[1] + (terms[2] + ... + (terms[n]*x)*x)*x)*x) ... )*x |
+ | and adds the result to the 12 byte Xsig. |
+ | The terms[] are each 8 bytes, but all computation is performed to 12 byte |
+ | precision. |
+ | |
+ | This function must be used carefully: most overflow of intermediate |
+ | results is controlled, but overflow of the result is not. |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#include "fpu_emu.h"
+#include "poly.h"
+
+
+void polynomial_Xsig(Xsig *accum, const u64 *x, const u64 terms[], const int n)
+{
+ int i;
+ Xsig acc, Xprod;
+ u32 lprod;
+ u64 xlwr, xupr, prod;
+ char overflowed;
+
+ xlwr = (u32)(*x);
+ xupr = (u32)((*x) >> 32);
+
+ acc.msw = terms[n] >> 32;
+ acc.midw = terms[n];
+ acc.lsw = 0;
+ overflowed = 0;
+
+ for ( i = n-1; i >= 0; i-- )
+ {
+ /* Split the product into five parts to get a 16 byte result */
+
+ /* first word by first word */
+ prod = acc.msw * xupr;
+ Xprod.midw = prod;
+ Xprod.msw = prod >> 32;
+
+ /* first word by second word */
+ prod = acc.msw * xlwr;
+ Xprod.lsw = prod;
+ lprod = prod >> 32;
+ Xprod.midw += lprod;
+ if ( lprod > Xprod.midw )
+ Xprod.msw ++;
+
+ /* second word by first word */
+ prod = acc.midw * xupr;
+ Xprod.lsw += prod;
+ if ( (u32)prod > Xprod.lsw )
+ {
+ Xprod.midw ++;
+ if ( Xprod.midw == 0 )
+ Xprod.msw ++;
+ }
+ lprod = prod >> 32;
+ Xprod.midw += lprod;
+ if ( lprod > Xprod.midw )
+ Xprod.msw ++;
+
+ /* second word by second word */
+ prod = acc.midw * xlwr;
+ lprod = prod >> 32;
+ Xprod.lsw += lprod;
+ if ( lprod > Xprod.lsw )
+ {
+ Xprod.midw ++;
+ if ( Xprod.midw == 0 )
+ Xprod.msw ++;
+ }
+
+ /* third word by first word */
+ prod = acc.lsw * xupr;
+ lprod = prod >> 32;
+ Xprod.lsw += lprod;
+ if ( lprod > Xprod.lsw )
+ {
+ Xprod.midw ++;
+ if ( Xprod.midw == 0 )
+ Xprod.msw ++;
+ }
+
+ if ( overflowed )
+ {
+ Xprod.midw += xlwr;
+ if ( (u32)xlwr > Xprod.midw )
+ Xprod.msw ++;
+ Xprod.msw += xupr;
+ overflowed = 0; /* We don't check this addition for overflow */
+ }
+
+ acc.lsw = Xprod.lsw;
+ acc.midw = (u32)terms[i] + Xprod.midw;
+ acc.msw = (terms[i] >> 32) + Xprod.msw;
+ if ( Xprod.msw > acc.msw )
+ overflowed = 1;
+ if ( (u32)terms[i] > acc.midw )
+ {
+ acc.msw ++;
+ if ( acc.msw == 0 )
+ overflowed = 1;
+ }
+ }
+
+ /* We don't check the addition to accum for overflow */
+ accum->lsw += acc.lsw;
+ if ( acc.lsw > accum->lsw )
+ {
+ accum->midw ++;
+ if ( accum->midw == 0 )
+ accum->msw ++;
+ }
+ accum->midw += acc.midw;
+ if ( acc.midw > accum->midw )
+ {
+ accum->msw ++;
+ }
+ accum->msw += acc.msw;
+}
+
+
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | reg_add_sub.c |
+ | |
+ | Functions to add or subtract two registers and put the result in a third. |
+ | |
+ | Copyright (C) 1992,1993,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | For each function, the destination may be any FPU_REG, including one of |
+ | the source FPU_REGs. |
+ | Each function returns 0 if the answer is o.k., otherwise a non-zero |
+ | value is returned, indicating either an exception condition or an |
+ | internal error. |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_emu.h"
+#include "control_w.h"
+#include "fpu_system.h"
+
+static
+int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa,
+ FPU_REG const *b, u_char tagb, u_char signb,
+ FPU_REG *dest, int deststnr, u16 control_w);
+
+/*
+ Operates on st(0) and st(n), or on st(0) and temporary data.
+ The destination must be one of the source st(x).
+ */
+int FPU_add(FPU_REG const *b, u_char tagb, int deststnr, u16 control_w)
+{
+ FPU_REG *a = &st(0);
+ FPU_REG *dest = &st(deststnr);
+ u_char signb = getsign(b);
+ u_char taga = FPU_gettag0();
+ u_char signa = getsign(a);
+ u_char saved_sign = getsign(dest);
+ int diff, tag, expa, expb;
+
+ if ( !(taga | tagb) )
+ {
+ expa = exponent(a);
+ expb = exponent(b);
+
+ valid_add:
+ /* Both registers are valid */
+ if (!(signa ^ signb))
+ {
+ /* signs are the same */
+ tag = FPU_u_add(a, b, dest, control_w, signa, expa, expb);
+ }
+ else
+ {
+ /* The signs are different, so do a subtraction */
+ diff = expa - expb;
+ if (!diff)
+ {
+ diff = a->sigh - b->sigh; /* This works only if the ms bits
+ are identical. */
+ if (!diff)
+ {
+ diff = a->sigl > b->sigl;
+ if (!diff)
+ diff = -(a->sigl < b->sigl);
+ }
+ }
+
+ if (diff > 0)
+ {
+ tag = FPU_u_sub(a, b, dest, control_w, signa, expa, expb);
+ }
+ else if ( diff < 0 )
+ {
+ tag = FPU_u_sub(b, a, dest, control_w, signb, expb, expa);
+ }
+ else
+ {
+ FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
+ /* sign depends upon rounding mode */
+ setsign(dest, ((control_w & CW_RC) != RC_DOWN)
+ ? SIGN_POS : SIGN_NEG);
+ return TAG_Zero;
+ }
+ }
+
+ if ( tag < 0 )
+ {
+ setsign(dest, saved_sign);
+ return tag;
+ }
+ FPU_settagi(deststnr, tag);
+ return tag;
+ }
+
+ if ( taga == TAG_Special )
+ taga = FPU_Special(a);
+ if ( tagb == TAG_Special )
+ tagb = FPU_Special(b);
+
+ if ( ((taga == TAG_Valid) && (tagb == TW_Denormal))
+ || ((taga == TW_Denormal) && (tagb == TAG_Valid))
+ || ((taga == TW_Denormal) && (tagb == TW_Denormal)) )
+ {
+ FPU_REG x, y;
+
+ if ( denormal_operand() < 0 )
+ return FPU_Exception;
+
+ FPU_to_exp16(a, &x);
+ FPU_to_exp16(b, &y);
+ a = &x;
+ b = &y;
+ expa = exponent16(a);
+ expb = exponent16(b);
+ goto valid_add;
+ }
+
+ if ( (taga == TW_NaN) || (tagb == TW_NaN) )
+ {
+ if ( deststnr == 0 )
+ return real_2op_NaN(b, tagb, deststnr, a);
+ else
+ return real_2op_NaN(a, taga, deststnr, a);
+ }
+
+ return add_sub_specials(a, taga, signa, b, tagb, signb,
+ dest, deststnr, control_w);
+}
+
+
+/* Subtract b from a. (a-b) -> dest
+ bbd: arg2 used to be int type, but sometimes pointers were forced
+ in with typecasts. On Alphas pointers are 64 bits and ints are 32,
+ so when rm was cast back to a pointer...SEGFAULT. Pass the pointers
+ around instead, since they are always larger precision than the
+ register numbers. */
+int FPU_sub(int flags, FPU_REG *rm, u16 control_w)
+{
+ FPU_REG const *a, *b;
+ FPU_REG *dest;
+ u_char taga, tagb, signa, signb, saved_sign, sign;
+ int diff, tag, expa, expb, deststnr;
+
+ a = &st(0);
+ taga = FPU_gettag0();
+
+ deststnr = 0;
+ if ( flags & LOADED )
+ {
+ b = rm;
+ tagb = flags & 0x0f;
+ }
+ else
+ {
+ int rmint = PTR2INT(rm);
+ b = &st(rmint);
+ tagb = FPU_gettagi(rmint);
+
+ if ( flags & DEST_RM )
+ deststnr = rmint;
+ }
+
+ signa = getsign(a);
+ signb = getsign(b);
+
+ if ( flags & REV )
+ {
+ signa ^= SIGN_NEG;
+ signb ^= SIGN_NEG;
+ }
+
+ dest = &st(deststnr);
+ saved_sign = getsign(dest);
+
+ if ( !(taga | tagb) )
+ {
+ expa = exponent(a);
+ expb = exponent(b);
+
+ valid_subtract:
+ /* Both registers are valid */
+
+ diff = expa - expb;
+
+ if (!diff)
+ {
+ diff = a->sigh - b->sigh; /* Works only if ms bits are identical */
+ if (!diff)
+ {
+ diff = a->sigl > b->sigl;
+ if (!diff)
+ diff = -(a->sigl < b->sigl);
+ }
+ }
+
+ switch ( (((int)signa)*2 + signb) / SIGN_NEG )
+ {
+ case 0: /* P - P */
+ case 3: /* N - N */
+ if (diff > 0)
+ {
+ /* |a| > |b| */
+ tag = FPU_u_sub(a, b, dest, control_w, signa, expa, expb);
+ }
+ else if ( diff == 0 )
+ {
+ FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
+
+ /* sign depends upon rounding mode */
+ setsign(dest, ((control_w & CW_RC) != RC_DOWN)
+ ? SIGN_POS : SIGN_NEG);
+ return TAG_Zero;
+ }
+ else
+ {
+ sign = signa ^ SIGN_NEG;
+ tag = FPU_u_sub(b, a, dest, control_w, sign, expb, expa);
+ }
+ break;
+ case 1: /* P - N */
+ tag = FPU_u_add(a, b, dest, control_w, SIGN_POS, expa, expb);
+ break;
+ case 2: /* N - P */
+ tag = FPU_u_add(a, b, dest, control_w, SIGN_NEG, expa, expb);
+ break;
+#ifdef PARANOID
+ default:
+ EXCEPTION(EX_INTERNAL|0x111);
+ return -1;
+#endif
+ }
+ if ( tag < 0 )
+ {
+ setsign(dest, saved_sign);
+ return tag;
+ }
+ FPU_settagi(deststnr, tag);
+ return tag;
+ }
+
+ if ( taga == TAG_Special )
+ taga = FPU_Special(a);
+ if ( tagb == TAG_Special )
+ tagb = FPU_Special(b);
+
+ if ( ((taga == TAG_Valid) && (tagb == TW_Denormal))
+ || ((taga == TW_Denormal) && (tagb == TAG_Valid))
+ || ((taga == TW_Denormal) && (tagb == TW_Denormal)) )
+ {
+ FPU_REG x, y;
+
+ if ( denormal_operand() < 0 )
+ return FPU_Exception;
+
+ FPU_to_exp16(a, &x);
+ FPU_to_exp16(b, &y);
+ a = &x;
+ b = &y;
+ expa = exponent16(a);
+ expb = exponent16(b);
+
+ goto valid_subtract;
+ }
+
+ if ( (taga == TW_NaN) || (tagb == TW_NaN) )
+ {
+ FPU_REG const *d1, *d2;
+ if ( flags & REV )
+ {
+ d1 = b;
+ d2 = a;
+ }
+ else
+ {
+ d1 = a;
+ d2 = b;
+ }
+ if ( flags & LOADED )
+ return real_2op_NaN(b, tagb, deststnr, d1);
+ if ( flags & DEST_RM )
+ return real_2op_NaN(a, taga, deststnr, d2);
+ else
+ return real_2op_NaN(b, tagb, deststnr, d2);
+ }
+
+ return add_sub_specials(a, taga, signa, b, tagb, signb ^ SIGN_NEG,
+ dest, deststnr, control_w);
+}
+
+
+static
+int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa,
+ FPU_REG const *b, u_char tagb, u_char signb,
+ FPU_REG *dest, int deststnr, u16 control_w)
+{
+ if ( ((taga == TW_Denormal) || (tagb == TW_Denormal))
+ && (denormal_operand() < 0) )
+ return FPU_Exception;
+
+ if (taga == TAG_Zero)
+ {
+ if (tagb == TAG_Zero)
+ {
+ /* Both are zero, result will be zero. */
+ u_char different_signs = signa ^ signb;
+
+ FPU_copy_to_regi(a, TAG_Zero, deststnr);
+ if ( different_signs )
+ {
+ /* Signs are different. */
+ /* Sign of answer depends upon rounding mode. */
+ setsign(dest, ((control_w & CW_RC) != RC_DOWN)
+ ? SIGN_POS : SIGN_NEG);
+ }
+ else
+ setsign(dest, signa); /* signa may differ from the sign of a. */
+ return TAG_Zero;
+ }
+ else
+ {
+ reg_copy(b, dest);
+ if ( (tagb == TW_Denormal) && (b->sigh & 0x80000000) )
+ {
+ /* A pseudoDenormal, convert it. */
+ addexponent(dest, 1);
+ tagb = TAG_Valid;
+ }
+ else if ( tagb > TAG_Empty )
+ tagb = TAG_Special;
+ setsign(dest, signb); /* signb may differ from the sign of b. */
+ FPU_settagi(deststnr, tagb);
+ return tagb;
+ }
+ }
+ else if (tagb == TAG_Zero)
+ {
+ reg_copy(a, dest);
+ if ( (taga == TW_Denormal) && (a->sigh & 0x80000000) )
+ {
+ /* A pseudoDenormal */
+ addexponent(dest, 1);
+ taga = TAG_Valid;
+ }
+ else if ( taga > TAG_Empty )
+ taga = TAG_Special;
+ setsign(dest, signa); /* signa may differ from the sign of a. */
+ FPU_settagi(deststnr, taga);
+ return taga;
+ }
+ else if (taga == TW_Infinity)
+ {
+ if ( (tagb != TW_Infinity) || (signa == signb) )
+ {
+ FPU_copy_to_regi(a, TAG_Special, deststnr);
+ setsign(dest, signa); /* signa may differ from the sign of a. */
+ return taga;
+ }
+ /* Infinity-Infinity is undefined. */
+ return arith_invalid(deststnr);
+ }
+ else if (tagb == TW_Infinity)
+ {
+ FPU_copy_to_regi(b, TAG_Special, deststnr);
+ setsign(dest, signb); /* signb may differ from the sign of b. */
+ return tagb;
+ }
+
+#ifdef PARANOID
+ EXCEPTION(EX_INTERNAL|0x101);
+#endif
+
+ return FPU_Exception;
+}
+
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | reg_compare.c |
+ | |
+ | Compare two floating point registers |
+ | |
+ | Copyright (C) 1992,1993,1994,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | compare() is the core FPU_REG comparison function |
+ +---------------------------------------------------------------------------*/
+
+#include "fpu_system.h"
+#include "exception.h"
+#include "fpu_emu.h"
+#include "control_w.h"
+#include "status_w.h"
+
+
+static int compare(FPU_REG const *b, int tagb)
+{
+ int diff, exp0, expb;
+ u_char st0_tag;
+ FPU_REG *st0_ptr;
+ FPU_REG x, y;
+ u_char st0_sign, signb = getsign(b);
+
+ st0_ptr = &st(0);
+ st0_tag = FPU_gettag0();
+ st0_sign = getsign(st0_ptr);
+
+ if ( tagb == TAG_Special )
+ tagb = FPU_Special(b);
+ if ( st0_tag == TAG_Special )
+ st0_tag = FPU_Special(st0_ptr);
+
+ if ( ((st0_tag != TAG_Valid) && (st0_tag != TW_Denormal))
+ || ((tagb != TAG_Valid) && (tagb != TW_Denormal)) )
+ {
+ if ( st0_tag == TAG_Zero )
+ {
+ if ( tagb == TAG_Zero ) return COMP_A_eq_B;
+ if ( tagb == TAG_Valid )
+ return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
+ if ( tagb == TW_Denormal )
+ return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
+ | COMP_Denormal;
+ }
+ else if ( tagb == TAG_Zero )
+ {
+ if ( st0_tag == TAG_Valid )
+ return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
+ if ( st0_tag == TW_Denormal )
+ return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
+ | COMP_Denormal;
+ }
+
+ if ( st0_tag == TW_Infinity )
+ {
+ if ( (tagb == TAG_Valid) || (tagb == TAG_Zero) )
+ return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
+ else if ( tagb == TW_Denormal )
+ return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
+ | COMP_Denormal;
+ else if ( tagb == TW_Infinity )
+ {
+ /* The 80486 book says that infinities can be equal! */
+ return (st0_sign == signb) ? COMP_A_eq_B :
+ ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
+ }
+ /* Fall through to the NaN code */
+ }
+ else if ( tagb == TW_Infinity )
+ {
+ if ( (st0_tag == TAG_Valid) || (st0_tag == TAG_Zero) )
+ return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
+ if ( st0_tag == TW_Denormal )
+ return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
+ | COMP_Denormal;
+ /* Fall through to the NaN code */
+ }
+
+ /* The only possibility now should be that one of the arguments
+ is a NaN */
+ if ( (st0_tag == TW_NaN) || (tagb == TW_NaN) )
+ {
+ int signalling = 0, unsupported = 0;
+ if ( st0_tag == TW_NaN )
+ {
+ signalling = (st0_ptr->sigh & 0xc0000000) == 0x80000000;
+ unsupported = !((exponent(st0_ptr) == EXP_OVER)
+ && (st0_ptr->sigh & 0x80000000));
+ }
+ if ( tagb == TW_NaN )
+ {
+ signalling |= (b->sigh & 0xc0000000) == 0x80000000;
+ unsupported |= !((exponent(b) == EXP_OVER)
+ && (b->sigh & 0x80000000));
+ }
+ if ( signalling || unsupported )
+ return COMP_No_Comp | COMP_SNaN | COMP_NaN;
+ else
+ /* Neither is a signaling NaN */
+ return COMP_No_Comp | COMP_NaN;
+ }
+
+ EXCEPTION(EX_Invalid);
+ }
+
+ if (st0_sign != signb)
+ {
+ return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
+ | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
+ COMP_Denormal : 0);
+ }
+
+ if ( (st0_tag == TW_Denormal) || (tagb == TW_Denormal) )
+ {
+ FPU_to_exp16(st0_ptr, &x);
+ FPU_to_exp16(b, &y);
+ st0_ptr = &x;
+ b = &y;
+ exp0 = exponent16(st0_ptr);
+ expb = exponent16(b);
+ }
+ else
+ {
+ exp0 = exponent(st0_ptr);
+ expb = exponent(b);
+ }
+
+#ifdef PARANOID
+ if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
+ if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
+#endif /* PARANOID */
+
+ diff = exp0 - expb;
+ if ( diff == 0 )
+ {
+ diff = st0_ptr->sigh - b->sigh; /* Works only if ms bits are
+ identical */
+ if ( diff == 0 )
+ {
+ diff = st0_ptr->sigl > b->sigl;
+ if ( diff == 0 )
+ diff = -(st0_ptr->sigl < b->sigl);
+ }
+ }
+
+ if ( diff > 0 )
+ {
+ return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
+ | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
+ COMP_Denormal : 0);
+ }
+ if ( diff < 0 )
+ {
+ return ((st0_sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
+ | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
+ COMP_Denormal : 0);
+ }
+
+ return COMP_A_eq_B
+ | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
+ COMP_Denormal : 0);
+
+}
+
+
+/* This function requires that st(0) is not empty */
+int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
+{
+ int f, c;
+
+ c = compare(loaded_data, loaded_tag);
+
+ if (c & COMP_NaN)
+ {
+ EXCEPTION(EX_Invalid);
+ f = SW_C3 | SW_C2 | SW_C0;
+ }
+ else
+ switch (c & 7)
+ {
+ case COMP_A_lt_B:
+ f = SW_C0;
+ break;
+ case COMP_A_eq_B:
+ f = SW_C3;
+ break;
+ case COMP_A_gt_B:
+ f = 0;
+ break;
+ case COMP_No_Comp:
+ f = SW_C3 | SW_C2 | SW_C0;
+ break;
+#ifdef PARANOID
+ default:
+ EXCEPTION(EX_INTERNAL|0x121);
+ f = SW_C3 | SW_C2 | SW_C0;
+ break;
+#endif /* PARANOID */
+ }
+ setcc(f);
+ if (c & COMP_Denormal)
+ {
+ return denormal_operand() < 0;
+ }
+ return 0;
+}
+
+
+static int compare_st_st(int nr)
+{
+ int f, c;
+ FPU_REG *st_ptr;
+
+ if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
+ {
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ /* Stack fault */
+ EXCEPTION(EX_StackUnder);
+ return !(control_word & CW_Invalid);
+ }
+
+ st_ptr = &st(nr);
+ c = compare(st_ptr, FPU_gettagi(nr));
+ if (c & COMP_NaN)
+ {
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ EXCEPTION(EX_Invalid);
+ return !(control_word & CW_Invalid);
+ }
+ else
+ switch (c & 7)
+ {
+ case COMP_A_lt_B:
+ f = SW_C0;
+ break;
+ case COMP_A_eq_B:
+ f = SW_C3;
+ break;
+ case COMP_A_gt_B:
+ f = 0;
+ break;
+ case COMP_No_Comp:
+ f = SW_C3 | SW_C2 | SW_C0;
+ break;
+#ifdef PARANOID
+ default:
+ EXCEPTION(EX_INTERNAL|0x122);
+ f = SW_C3 | SW_C2 | SW_C0;
+ break;
+#endif /* PARANOID */
+ }
+ setcc(f);
+ if (c & COMP_Denormal)
+ {
+ return denormal_operand() < 0;
+ }
+ return 0;
+}
+
+
+static int compare_u_st_st(int nr)
+{
+ int f, c;
+ FPU_REG *st_ptr;
+
+ if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
+ {
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ /* Stack fault */
+ EXCEPTION(EX_StackUnder);
+ return !(control_word & CW_Invalid);
+ }
+
+ st_ptr = &st(nr);
+ c = compare(st_ptr, FPU_gettagi(nr));
+ if (c & COMP_NaN)
+ {
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ if (c & COMP_SNaN) /* This is the only difference between
+ un-ordered and ordinary comparisons */
+ {
+ EXCEPTION(EX_Invalid);
+ return !(control_word & CW_Invalid);
+ }
+ return 0;
+ }
+ else
+ switch (c & 7)
+ {
+ case COMP_A_lt_B:
+ f = SW_C0;
+ break;
+ case COMP_A_eq_B:
+ f = SW_C3;
+ break;
+ case COMP_A_gt_B:
+ f = 0;
+ break;
+ case COMP_No_Comp:
+ f = SW_C3 | SW_C2 | SW_C0;
+ break;
+#ifdef PARANOID
+ default:
+ EXCEPTION(EX_INTERNAL|0x123);
+ f = SW_C3 | SW_C2 | SW_C0;
+ break;
+#endif /* PARANOID */
+ }
+ setcc(f);
+ if (c & COMP_Denormal)
+ {
+ return denormal_operand() < 0;
+ }
+ return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+
+void fcom_st()
+{
+ /* fcom st(i) */
+ compare_st_st(FPU_rm);
+}
+
+
+void fcompst()
+{
+ /* fcomp st(i) */
+ if ( !compare_st_st(FPU_rm) )
+ FPU_pop();
+}
+
+
+void fcompp()
+{
+ /* fcompp */
+ if (FPU_rm != 1)
+ {
+ FPU_illegal();
+ return;
+ }
+ if ( !compare_st_st(1) )
+ poppop();
+}
+
+
+void fucom_()
+{
+ /* fucom st(i) */
+ compare_u_st_st(FPU_rm);
+
+}
+
+
+void fucomp()
+{
+ /* fucomp st(i) */
+ if ( !compare_u_st_st(FPU_rm) )
+ FPU_pop();
+}
+
+
+void fucompp()
+{
+ /* fucompp */
+ if (FPU_rm == 1)
+ {
+ if ( !compare_u_st_st(1) )
+ poppop();
+ }
+ else
+ FPU_illegal();
+}
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | reg_constant.c |
+ | |
+ | All of the constant FPU_REGs |
+ | |
+ | Copyright (C) 1992,1993,1994,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@suburbia.net |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#include "fpu_system.h"
+#include "fpu_emu.h"
+#include "status_w.h"
+#include "reg_constant.h"
+#include "control_w.h"
+
+
+
+FPU_REG const CONST_1 = MAKE_REG(POS, 0, 0x00000000, 0x80000000);
+FPU_REG const CONST_2 = MAKE_REG(POS, 1, 0x00000000, 0x80000000);
+FPU_REG const CONST_HALF = MAKE_REG(POS, -1, 0x00000000, 0x80000000);
+FPU_REG const CONST_L2T = MAKE_REG(POS, 1, 0xcd1b8afe, 0xd49a784b);
+FPU_REG const CONST_L2E = MAKE_REG(POS, 0, 0x5c17f0bc, 0xb8aa3b29);
+FPU_REG const CONST_PI = MAKE_REG(POS, 1, 0x2168c235, 0xc90fdaa2);
+// bbd: make CONST_PI2 non-const so that you can write "&CONST_PI2" when
+// calling a function. Otherwise you get const warnings. Surely there's
+// a better way.
+FPU_REG CONST_PI2 = MAKE_REG(POS, 0, 0x2168c235, 0xc90fdaa2);
+FPU_REG const CONST_PI4 = MAKE_REG(POS, -1, 0x2168c235, 0xc90fdaa2);
+FPU_REG const CONST_LG2 = MAKE_REG(POS, -2, 0xfbcff799, 0x9a209a84);
+FPU_REG const CONST_LN2 = MAKE_REG(POS, -1, 0xd1cf79ac, 0xb17217f7);
+
+/* Extra bits to take pi/2 to more than 128 bits precision. */
+FPU_REG const CONST_PI2extra = MAKE_REG(NEG, -66,
+ 0xfc8f8cbb, 0xece675d1);
+
+/* Only the sign (and tag) is used in internal zeroes */
+FPU_REG const CONST_Z = MAKE_REG(POS, EXP_UNDER, 0x0, 0x0);
+
+/* Only the sign and significand (and tag) are used in internal NaNs */
+/* The 80486 never generates one of these
+FPU_REG const CONST_SNAN = MAKE_REG(POS, EXP_OVER, 0x00000001, 0x80000000);
+ */
+/* This is the real indefinite QNaN */
+FPU_REG const CONST_QNaN = MAKE_REG(NEG, EXP_OVER, 0x00000000, 0xC0000000);
+
+/* Only the sign (and tag) is used in internal infinities */
+FPU_REG const CONST_INF = MAKE_REG(POS, EXP_OVER, 0x00000000, 0x80000000);
+
+
+static void fld_const(FPU_REG const *c, int adj, u_char tag)
+{
+ FPU_REG *st_new_ptr;
+
+ if ( STACK_OVERFLOW )
+ {
+ FPU_stack_overflow();
+ return;
+ }
+ push();
+ reg_copy(c, st_new_ptr);
+ st_new_ptr->sigl += adj; /* For all our fldxxx constants, we don't need to
+ borrow or carry. */
+ FPU_settag0(tag);
+ clear_C1();
+}
+
+/* A fast way to find out whether x is one of RC_DOWN or RC_CHOP
+ (and not one of RC_RND or RC_UP).
+ */
+#define DOWN_OR_CHOP(x) (x & RC_DOWN)
+
+static void fld1(int rc)
+{
+ fld_const(&CONST_1, 0, TAG_Valid);
+}
+
+static void fldl2t(int rc)
+{
+ fld_const(&CONST_L2T, (rc == RC_UP) ? 1 : 0, TAG_Valid);
+}
+
+static void fldl2e(int rc)
+{
+ fld_const(&CONST_L2E, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid);
+}
+
+static void fldpi(int rc)
+{
+ fld_const(&CONST_PI, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid);
+}
+
+static void fldlg2(int rc)
+{
+ fld_const(&CONST_LG2, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid);
+}
+
+static void fldln2(int rc)
+{
+ fld_const(&CONST_LN2, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid);
+}
+
+static void fldz(int rc)
+{
+ fld_const(&CONST_Z, 0, TAG_Zero);
+}
+
+typedef void (*FUNC_RC)(int);
+
+static FUNC_RC constants_table[] = {
+ fld1, fldl2t, fldl2e, fldpi, fldlg2, fldln2, fldz, (FUNC_RC)FPU_illegal
+};
+
+void fconst(void)
+{
+ (constants_table[FPU_rm])(control_word & CW_RC);
+}
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | reg_constant.h |
+ | |
+ | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#ifndef _REG_CONSTANT_H_
+#define _REG_CONSTANT_H_
+
+#include "fpu_emu.h"
+
+extern FPU_REG const CONST_1;
+extern FPU_REG const CONST_2;
+extern FPU_REG const CONST_HALF;
+extern FPU_REG const CONST_L2T;
+extern FPU_REG const CONST_L2E;
+extern FPU_REG const CONST_PI;
+// bbd: make CONST_PI2 non-const so that you can write "&CONST_PI2" when
+// calling a function. Otherwise you get const warnings. Surely there's
+// a better way.
+extern FPU_REG CONST_PI2;
+extern FPU_REG const CONST_PI2extra;
+extern FPU_REG const CONST_PI4;
+extern FPU_REG const CONST_LG2;
+extern FPU_REG const CONST_LN2;
+extern FPU_REG const CONST_Z;
+extern FPU_REG const CONST_PINF;
+extern FPU_REG const CONST_INF;
+extern FPU_REG const CONST_MINF;
+extern FPU_REG const CONST_QNaN;
+
+#endif /* _REG_CONSTANT_H_ */
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | reg_convert.c |
+ | |
+ | Convert register representation. |
+ | |
+ | Copyright (C) 1992,1993,1994,1996,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "fpu_emu.h"
+
+
+int FPU_to_exp16(FPU_REG const *a, FPU_REG *x)
+{
+ int sign = getsign(a);
+
+#ifndef EMU_BIG_ENDIAN
+ *(s64 *)&(x->sigl) = *(const s64 *)&(a->sigl);
+#else
+ *(s64 *)&(x->sigh) = *(const s64 *)&(a->sigh);
+#endif
+
+ /* Set up the exponent as a 16 bit quantity. */
+ setexponent16(x, exponent(a));
+
+ if ( exponent16(x) == EXP_UNDER )
+ {
+ /* The number is a de-normal or pseudodenormal. */
+ /* We only deal with the significand and exponent. */
+
+ if (x->sigh & 0x80000000)
+ {
+ /* Is a pseudodenormal. */
+ /* This is non-80486 behaviour because the number
+ loses its 'denormal' identity. */
+ addexponent(x, 1);
+ }
+ else
+ {
+ /* Is a denormal. */
+ addexponent(x, 1);
+ FPU_normalize_nuo(x, 0);
+ }
+ }
+
+ if ( !(x->sigh & 0x80000000) )
+ {
+ EXCEPTION(EX_INTERNAL | 0x180);
+ }
+
+ return sign;
+}
+
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | reg_divide.c |
+ | |
+ | Divide one FPU_REG by another and put the result in a destination FPU_REG.|
+ | |
+ | Copyright (C) 1996 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@jacobi.maths.monash.edu.au |
+ | |
+ | Return value is the tag of the answer, or-ed with FPU_Exception if |
+ | one was raised, or -1 on internal error. |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | The destination may be any FPU_REG, including one of the source FPU_REGs. |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_emu.h"
+#include "fpu_system.h"
+
+/*
+ Divide one register by another and put the result into a third register.
+bbd: arg2 used to be an int, see comments on FPU_sub.
+ */
+int FPU_div(int flags, FPU_REG *rm, int control_w)
+{
+ FPU_REG x, y;
+ FPU_REG const *a, *b, *st0_ptr, *st_ptr;
+ FPU_REG *dest;
+ u_char taga, tagb, signa, signb, sign, saved_sign;
+ int tag, deststnr;
+ int rmint = PTR2INT(rm);
+
+ if ( flags & DEST_RM )
+ deststnr = rmint;
+ else
+ deststnr = 0;
+
+ if ( flags & REV )
+ {
+ b = &st(0);
+ st0_ptr = b;
+ tagb = FPU_gettag0();
+ if ( flags & LOADED )
+ {
+ a = rm;
+ taga = flags & 0x0f;
+ }
+ else
+ {
+ a = &st(rmint);
+ st_ptr = a;
+ taga = FPU_gettagi(rmint);
+ }
+ }
+ else
+ {
+ a = &st(0);
+ st0_ptr = a;
+ taga = FPU_gettag0();
+ if ( flags & LOADED )
+ {
+ b = rm;
+ tagb = flags & 0x0f;
+ }
+ else
+ {
+ b = &st(rmint);
+ st_ptr = b;
+ tagb = FPU_gettagi(rmint);
+ }
+ }
+
+ signa = getsign(a);
+ signb = getsign(b);
+
+ sign = signa ^ signb;
+
+ dest = &st(deststnr);
+ saved_sign = getsign(dest);
+
+ if ( !(taga | tagb) )
+ {
+ /* Both regs Valid, this should be the most common case. */
+ reg_copy(a, &x);
+ reg_copy(b, &y);
+ setpositive(&x);
+ setpositive(&y);
+ tag = FPU_u_div(&x, &y, dest, control_w, sign);
+
+ if ( tag < 0 )
+ return tag;
+
+ FPU_settagi(deststnr, tag);
+ return tag;
+ }
+
+ if ( taga == TAG_Special )
+ taga = FPU_Special(a);
+ if ( tagb == TAG_Special )
+ tagb = FPU_Special(b);
+
+ if ( ((taga == TAG_Valid) && (tagb == TW_Denormal))
+ || ((taga == TW_Denormal) && (tagb == TAG_Valid))
+ || ((taga == TW_Denormal) && (tagb == TW_Denormal)) )
+ {
+ if ( denormal_operand() < 0 )
+ return FPU_Exception;
+
+ FPU_to_exp16(a, &x);
+ FPU_to_exp16(b, &y);
+ tag = FPU_u_div(&x, &y, dest, control_w, sign);
+ if ( tag < 0 )
+ return tag;
+
+ FPU_settagi(deststnr, tag);
+ return tag;
+ }
+ else if ( (taga <= TW_Denormal) && (tagb <= TW_Denormal) )
+ {
+ if ( tagb != TAG_Zero )
+ {
+ /* Want to find Zero/Valid */
+ if ( tagb == TW_Denormal )
+ {
+ if ( denormal_operand() < 0 )
+ return FPU_Exception;
+ }
+
+ /* The result is zero. */
+ FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
+ setsign(dest, sign);
+ return TAG_Zero;
+ }
+ /* We have an exception condition, either 0/0 or Valid/Zero. */
+ if ( taga == TAG_Zero )
+ {
+ /* 0/0 */
+ return arith_invalid(deststnr);
+ }
+ /* Valid/Zero */
+ return FPU_divide_by_zero(deststnr, sign);
+ }
+ /* Must have infinities, NaNs, etc */
+ else if ( (taga == TW_NaN) || (tagb == TW_NaN) )
+ {
+ if ( flags & LOADED )
+ return real_2op_NaN((FPU_REG *)rm, flags & 0x0f, 0, st0_ptr);
+
+ if ( flags & DEST_RM )
+ {
+ int tag;
+ tag = FPU_gettag0();
+ if ( tag == TAG_Special )
+ tag = FPU_Special(st0_ptr);
+ return real_2op_NaN(st0_ptr, tag, rmint, (flags & REV) ? st0_ptr : &st(rmint));
+ }
+ else
+ {
+ int tag;
+ tag = FPU_gettagi(rmint);
+ if ( tag == TAG_Special )
+ tag = FPU_Special(&st(rmint));
+ return real_2op_NaN(&st(rmint), tag, 0, (flags & REV) ? st0_ptr : &st(rmint));
+ }
+ }
+ else if (taga == TW_Infinity)
+ {
+ if (tagb == TW_Infinity)
+ {
+ /* infinity/infinity */
+ return arith_invalid(deststnr);
+ }
+ else
+ {
+ /* tagb must be Valid or Zero */
+ if ( (tagb == TW_Denormal) && (denormal_operand() < 0) )
+ return FPU_Exception;
+
+ /* Infinity divided by Zero or Valid does
+ not raise and exception, but returns Infinity */
+ FPU_copy_to_regi(a, TAG_Special, deststnr);
+ setsign(dest, sign);
+ return taga;
+ }
+ }
+ else if (tagb == TW_Infinity)
+ {
+ if ( (taga == TW_Denormal) && (denormal_operand() < 0) )
+ return FPU_Exception;
+
+ /* The result is zero. */
+ FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
+ setsign(dest, sign);
+ return TAG_Zero;
+ }
+#ifdef PARANOID
+ else
+ {
+ EXCEPTION(EX_INTERNAL|0x102);
+ return FPU_Exception;
+ }
+#endif /* PARANOID */
+
+}
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | reg_ld_str.c |
+ | |
+ | All of the functions which transfer data between user memory and FPU_REGs.|
+ | |
+ | Copyright (C) 1992,1993,1994,1996,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | Note: |
+ | The file contains code which accesses user memory. |
+ | Emulator static data may change when user memory is accessed, due to |
+ | other processes using the emulator while swapping is in progress. |
+ +---------------------------------------------------------------------------*/
+
+#include "fpu_emu.h"
+
+#include <asm/uaccess.h>
+
+#include "fpu_system.h"
+#include "exception.h"
+#include "reg_constant.h"
+#include "control_w.h"
+#include "status_w.h"
+
+
+#define DOUBLE_Emax 1023 /* largest valid exponent */
+#define DOUBLE_Ebias 1023
+#define DOUBLE_Emin (-1022) /* smallest valid exponent */
+
+#define SINGLE_Emax 127 /* largest valid exponent */
+#define SINGLE_Ebias 127
+#define SINGLE_Emin (-126) /* smallest valid exponent */
+
+
+static u_char normalize_no_excep(FPU_REG *r, int exp, int sign)
+{
+ u_char tag;
+
+ setexponent16(r, exp);
+
+ tag = FPU_normalize_nuo(r, 0);
+ stdexp(r);
+ if ( sign )
+ setnegative(r);
+
+ return tag;
+}
+
+
+int FPU_tagof(FPU_REG *ptr)
+{
+ int exp;
+
+ exp = exponent16(ptr) & 0x7fff;
+ if ( exp == 0 )
+ {
+ if ( !(ptr->sigh | ptr->sigl) )
+ {
+ return TAG_Zero;
+ }
+ /* The number is a de-normal or pseudodenormal. */
+ return TAG_Special;
+ }
+
+ if ( exp == 0x7fff )
+ {
+ /* Is an Infinity, a NaN, or an unsupported data type. */
+ return TAG_Special;
+ }
+
+ if ( !(ptr->sigh & 0x80000000) )
+ {
+ /* Unsupported data type. */
+ /* Valid numbers have the ms bit set to 1. */
+ /* Unnormal. */
+ return TAG_Special;
+ }
+
+ return TAG_Valid;
+}
+
+
+/* Get a long double from user memory */
+int FPU_load_extended(long double *s, int stnr)
+{
+ FPU_REG *sti_ptr = &st(stnr);
+
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_READ, s, 10);
+#ifndef USE_WITH_CPU_SIM
+ __copy_from_user(sti_ptr, s, 10);
+#else
+ FPU_get_user(sti_ptr->sigl, (u32*)(((u8*)s)+0));
+ FPU_get_user(sti_ptr->sigh, (u32*)(((u8*)s)+4));
+ FPU_get_user(sti_ptr->exp, (u16*)(((u8*)s)+8));
+#endif
+ RE_ENTRANT_CHECK_ON;
+
+ return FPU_tagof(sti_ptr);
+}
+
+
+/* Get a double from user memory */
+int FPU_load_double(double *dfloat, FPU_REG *loaded_data)
+{
+ int exp, tag, negative;
+ u32 m64, l64;
+
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_READ, dfloat, 8);
+ FPU_get_user(m64, 1 + (u32 *) dfloat);
+ FPU_get_user(l64, (u32 *) dfloat);
+ RE_ENTRANT_CHECK_ON;
+
+ negative = (m64 & 0x80000000) ? SIGN_Negative : SIGN_Positive;
+ exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias + EXTENDED_Ebias;
+ m64 &= 0xfffff;
+ if ( exp > DOUBLE_Emax + EXTENDED_Ebias )
+ {
+ /* Infinity or NaN */
+ if ((m64 == 0) && (l64 == 0))
+ {
+ /* +- infinity */
+ loaded_data->sigh = 0x80000000;
+ loaded_data->sigl = 0x00000000;
+ exp = EXP_Infinity + EXTENDED_Ebias;
+ tag = TAG_Special;
+ }
+ else
+ {
+ /* Must be a signaling or quiet NaN */
+ exp = EXP_NaN + EXTENDED_Ebias;
+ loaded_data->sigh = (m64 << 11) | 0x80000000;
+ loaded_data->sigh |= l64 >> 21;
+ loaded_data->sigl = l64 << 11;
+ tag = TAG_Special; /* The calling function must look for NaNs */
+ }
+ }
+ else if ( exp < DOUBLE_Emin + EXTENDED_Ebias )
+ {
+ /* Zero or de-normal */
+ if ((m64 == 0) && (l64 == 0))
+ {
+ /* Zero */
+ reg_copy(&CONST_Z, loaded_data);
+ exp = 0;
+ tag = TAG_Zero;
+ }
+ else
+ {
+ /* De-normal */
+ loaded_data->sigh = m64 << 11;
+ loaded_data->sigh |= l64 >> 21;
+ loaded_data->sigl = l64 << 11;
+
+ return normalize_no_excep(loaded_data, DOUBLE_Emin, negative)
+ | (denormal_operand() < 0 ? FPU_Exception : 0);
+ }
+ }
+ else
+ {
+ loaded_data->sigh = (m64 << 11) | 0x80000000;
+ loaded_data->sigh |= l64 >> 21;
+ loaded_data->sigl = l64 << 11;
+
+ tag = TAG_Valid;
+ }
+
+ setexponent16(loaded_data, exp | negative);
+
+ return tag;
+}
+
+
+/* Get a float from user memory */
+int FPU_load_single(float *single, FPU_REG *loaded_data)
+{
+ u32 m32;
+ int exp, tag, negative;
+
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_READ, single, 4);
+ FPU_get_user(m32, (u32 *) single);
+ RE_ENTRANT_CHECK_ON;
+
+ negative = (m32 & 0x80000000) ? SIGN_Negative : SIGN_Positive;
+
+ if (!(m32 & 0x7fffffff))
+ {
+ /* Zero */
+ reg_copy(&CONST_Z, loaded_data);
+ addexponent(loaded_data, negative);
+ return TAG_Zero;
+ }
+ exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias + EXTENDED_Ebias;
+ m32 = (m32 & 0x7fffff) << 8;
+ if ( exp < SINGLE_Emin + EXTENDED_Ebias )
+ {
+ /* De-normals */
+ loaded_data->sigh = m32;
+ loaded_data->sigl = 0;
+
+ return normalize_no_excep(loaded_data, SINGLE_Emin, negative)
+ | (denormal_operand() < 0 ? FPU_Exception : 0);
+ }
+ else if ( exp > SINGLE_Emax + EXTENDED_Ebias )
+ {
+ /* Infinity or NaN */
+ if ( m32 == 0 )
+ {
+ /* +- infinity */
+ loaded_data->sigh = 0x80000000;
+ loaded_data->sigl = 0x00000000;
+ exp = EXP_Infinity + EXTENDED_Ebias;
+ tag = TAG_Special;
+ }
+ else
+ {
+ /* Must be a signaling or quiet NaN */
+ exp = EXP_NaN + EXTENDED_Ebias;
+ loaded_data->sigh = m32 | 0x80000000;
+ loaded_data->sigl = 0;
+ tag = TAG_Special; /* The calling function must look for NaNs */
+ }
+ }
+ else
+ {
+ loaded_data->sigh = m32 | 0x80000000;
+ loaded_data->sigl = 0;
+ tag = TAG_Valid;
+ }
+
+ setexponent16(loaded_data, exp | negative); /* Set the sign. */
+
+ return tag;
+}
+
+
+/* Get a 64bit quantity from user memory */
+int FPU_load_int64(s64 *_s)
+{
+ s64 s;
+ int sign;
+ FPU_REG *st0_ptr = &st(0);
+
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_READ, _s, 8);
+#ifndef USE_WITH_CPU_SIM
+ copy_from_user(&s,_s,8);
+#else
+ {
+ u32 chunk0, chunk1;
+ FPU_get_user(chunk0, (u32*)(((u8*)_s)+0));
+ FPU_get_user(chunk1, (u32*)(((u8*)_s)+4));
+ s = chunk0;
+ s |= (((u64)chunk1) << 32);
+ }
+#endif
+ RE_ENTRANT_CHECK_ON;
+
+ if (s == 0)
+ {
+ reg_copy(&CONST_Z, st0_ptr);
+ return TAG_Zero;
+ }
+
+ if (s > 0)
+ sign = SIGN_Positive;
+ else
+ {
+ s = -s;
+ sign = SIGN_Negative;
+ }
+
+ significand(st0_ptr) = s;
+
+ return normalize_no_excep(st0_ptr, 63, sign);
+}
+
+
+/* Get a long from user memory */
+int FPU_load_int32(s32 *_s, FPU_REG *loaded_data)
+{
+ s32 s;
+ int negative;
+
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_READ, _s, 4);
+ FPU_get_user(s, _s);
+ RE_ENTRANT_CHECK_ON;
+
+ if (s == 0)
+ { reg_copy(&CONST_Z, loaded_data); return TAG_Zero; }
+
+ if (s > 0)
+ negative = SIGN_Positive;
+ else
+ {
+ s = -s;
+ negative = SIGN_Negative;
+ }
+
+ loaded_data->sigh = s;
+ loaded_data->sigl = 0;
+
+ return normalize_no_excep(loaded_data, 31, negative);
+}
+
+
+/* Get a short from user memory */
+int FPU_load_int16(s16 *_s, FPU_REG *loaded_data)
+{
+ int s, negative;
+
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_READ, _s, 2);
+ /* Cast as short to get the sign extended. */
+ FPU_get_user(s, _s);
+ RE_ENTRANT_CHECK_ON;
+
+ if (s == 0)
+ { reg_copy(&CONST_Z, loaded_data); return TAG_Zero; }
+
+ if (s > 0)
+ negative = SIGN_Positive;
+ else
+ {
+ s = -s;
+ negative = SIGN_Negative;
+ }
+
+ loaded_data->sigh = s << 16;
+ loaded_data->sigl = 0;
+
+ return normalize_no_excep(loaded_data, 15, negative);
+}
+
+
+/* Get a packed bcd array from user memory */
+int FPU_load_bcd(u_char *s)
+{
+ FPU_REG *st0_ptr = &st(0);
+ int pos;
+ u_char bcd;
+ s64 l=0;
+ int sign;
+
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_READ, s, 10);
+ RE_ENTRANT_CHECK_ON;
+ for ( pos = 8; pos >= 0; pos--)
+ {
+ l *= 10;
+ RE_ENTRANT_CHECK_OFF;
+ FPU_get_user(bcd, (u_char *) s+pos);
+ RE_ENTRANT_CHECK_ON;
+ l += bcd >> 4;
+ l *= 10;
+ l += bcd & 0x0f;
+ }
+
+ RE_ENTRANT_CHECK_OFF;
+ FPU_get_user(sign, (u_char *) s+9);
+ sign = sign & 0x80 ? SIGN_Negative : SIGN_Positive;
+ RE_ENTRANT_CHECK_ON;
+
+ if ( l == 0 )
+ {
+ reg_copy(&CONST_Z, st0_ptr);
+ addexponent(st0_ptr, sign); /* Set the sign. */
+ return TAG_Zero;
+ }
+ else
+ {
+ significand(st0_ptr) = l;
+ return normalize_no_excep(st0_ptr, 63, sign);
+ }
+}
+
+/*===========================================================================*/
+
+/* Put a long double into user memory */
+int FPU_store_extended(FPU_REG *st0_ptr, u_char st0_tag, long double *d)
+{
+ /*
+ The only exception raised by an attempt to store to an
+ extended format is the Invalid Stack exception, i.e.
+ attempting to store from an empty register.
+ */
+
+ if ( st0_tag != TAG_Empty )
+ {
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE, d, 10);
+
+ FPU_put_user(st0_ptr->sigl, (u32 *) d);
+ FPU_put_user(st0_ptr->sigh, (u32 *) ((u_char *)d + 4));
+ FPU_put_user(exponent16(st0_ptr), (u16 *) ((u_char *)d + 8));
+ RE_ENTRANT_CHECK_ON;
+
+ return 1;
+ }
+
+ /* Empty register (stack underflow) */
+ EXCEPTION(EX_StackUnder);
+ if ( control_word & CW_Invalid )
+ {
+ /* The masked response */
+ /* Put out the QNaN indefinite */
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,d,10);
+ FPU_put_user(0, (u32 *) d);
+ FPU_put_user(0xc0000000, 1 + (u32 *) d);
+ FPU_put_user(0xffff, 4 + (s16 *) d);
+ RE_ENTRANT_CHECK_ON;
+ return 1;
+ }
+ else
+ return 0;
+
+}
+
+
+/* Put a double into user memory */
+int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double *dfloat)
+{
+ u32 l[2];
+ u32 increment = 0; /* avoid gcc warnings */
+ int precision_loss;
+ int exp;
+ FPU_REG tmp;
+
+ if ( st0_tag == TAG_Valid )
+ {
+ reg_copy(st0_ptr, &tmp);
+ exp = exponent(&tmp);
+
+ if ( exp < DOUBLE_Emin ) /* It may be a denormal */
+ {
+ addexponent(&tmp, -DOUBLE_Emin + 52); /* largest exp to be 51 */
+
+ denormal_arg:
+
+ if ( (precision_loss = FPU_round_to_int(&tmp, st0_tag)) )
+ {
+#ifdef PECULIAR_486
+ /* Did it round to a non-denormal ? */
+ /* This behaviour might be regarded as peculiar, it appears
+ that the 80486 rounds to the dest precision, then
+ converts to decide underflow. */
+ if ( !((tmp.sigh == 0x00100000) && (tmp.sigl == 0) &&
+ (st0_ptr->sigl & 0x000007ff)) )
+#endif /* PECULIAR_486 */
+ {
+ EXCEPTION(EX_Underflow);
+ /* This is a special case: see sec 16.2.5.1 of
+ the 80486 book */
+ if ( !(control_word & CW_Underflow) )
+ return 0;
+ }
+ EXCEPTION(precision_loss);
+ if ( !(control_word & CW_Precision) )
+ return 0;
+ }
+ l[0] = tmp.sigl;
+ l[1] = tmp.sigh;
+ }
+ else
+ {
+ if ( tmp.sigl & 0x000007ff )
+ {
+ precision_loss = 1;
+ switch (control_word & CW_RC)
+ {
+ case RC_RND:
+ /* Rounding can get a little messy.. */
+ increment = ((tmp.sigl & 0x7ff) > 0x400) | /* nearest */
+ ((tmp.sigl & 0xc00) == 0xc00); /* odd -> even */
+ break;
+ case RC_DOWN: /* towards -infinity */
+ increment = signpositive(&tmp) ? 0 : tmp.sigl & 0x7ff;
+ break;
+ case RC_UP: /* towards +infinity */
+ increment = signpositive(&tmp) ? tmp.sigl & 0x7ff : 0;
+ break;
+ case RC_CHOP:
+ increment = 0;
+ break;
+ }
+
+ /* Truncate the mantissa */
+ tmp.sigl &= 0xfffff800;
+
+ if ( increment )
+ {
+ if ( tmp.sigl >= 0xfffff800 )
+ {
+ /* the sigl part overflows */
+ if ( tmp.sigh == 0xffffffff )
+ {
+ /* The sigh part overflows */
+ tmp.sigh = 0x80000000;
+ exp++;
+ if (exp >= EXP_OVER)
+ goto overflow;
+ }
+ else
+ {
+ tmp.sigh ++;
+ }
+ tmp.sigl = 0x00000000;
+ }
+ else
+ {
+ /* We only need to increment sigl */
+ tmp.sigl += 0x00000800;
+ }
+ }
+ }
+ else
+ precision_loss = 0;
+
+ l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
+ l[1] = ((tmp.sigh >> 11) & 0xfffff);
+
+ if ( exp > DOUBLE_Emax )
+ {
+ overflow:
+ EXCEPTION(EX_Overflow);
+ if ( !(control_word & CW_Overflow) )
+ return 0;
+ set_precision_flag_up();
+ if ( !(control_word & CW_Precision) )
+ return 0;
+
+ /* This is a special case: see sec 16.2.5.1 of the 80486 book */
+ /* Overflow to infinity */
+ l[0] = 0x00000000; /* Set to */
+ l[1] = 0x7ff00000; /* + INF */
+ }
+ else
+ {
+ if ( precision_loss )
+ {
+ if ( increment )
+ set_precision_flag_up();
+ else
+ set_precision_flag_down();
+ }
+ /* Add the exponent */
+ l[1] |= (((exp+DOUBLE_Ebias) & 0x7ff) << 20);
+ }
+ }
+ }
+ else if (st0_tag == TAG_Zero)
+ {
+ /* Number is zero */
+ l[0] = 0;
+ l[1] = 0;
+ }
+ else if ( st0_tag == TAG_Special )
+ {
+ st0_tag = FPU_Special(st0_ptr);
+ if ( st0_tag == TW_Denormal )
+ {
+ /* A denormal will always underflow. */
+#ifndef PECULIAR_486
+ /* An 80486 is supposed to be able to generate
+ a denormal exception here, but... */
+ /* Underflow has priority. */
+ if ( control_word & CW_Underflow )
+ denormal_operand();
+#endif /* PECULIAR_486 */
+ reg_copy(st0_ptr, &tmp);
+ goto denormal_arg;
+ }
+ else if (st0_tag == TW_Infinity)
+ {
+ l[0] = 0;
+ l[1] = 0x7ff00000;
+ }
+ else if (st0_tag == TW_NaN)
+ {
+ /* Is it really a NaN ? */
+ if ( (exponent(st0_ptr) == EXP_OVER)
+ && (st0_ptr->sigh & 0x80000000) )
+ {
+ /* See if we can get a valid NaN from the FPU_REG */
+ l[0] = (st0_ptr->sigl >> 11) | (st0_ptr->sigh << 21);
+ l[1] = ((st0_ptr->sigh >> 11) & 0xfffff);
+ if ( !(st0_ptr->sigh & 0x40000000) )
+ {
+ /* It is a signalling NaN */
+ EXCEPTION(EX_Invalid);
+ if ( !(control_word & CW_Invalid) )
+ return 0;
+ l[1] |= (0x40000000 >> 11);
+ }
+ l[1] |= 0x7ff00000;
+ }
+ else
+ {
+ /* It is an unsupported data type */
+ EXCEPTION(EX_Invalid);
+ if ( !(control_word & CW_Invalid) )
+ return 0;
+ l[0] = 0;
+ l[1] = 0xfff80000;
+ }
+ }
+ }
+ else if ( st0_tag == TAG_Empty )
+ {
+ /* Empty register (stack underflow) */
+ EXCEPTION(EX_StackUnder);
+ if ( control_word & CW_Invalid )
+ {
+ /* The masked response */
+ /* Put out the QNaN indefinite */
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8);
+ FPU_put_user(0, (u32 *) dfloat);
+ FPU_put_user(0xfff80000, 1 + (u32 *) dfloat);
+ RE_ENTRANT_CHECK_ON;
+ return 1;
+ }
+ else
+ return 0;
+ }
+ if ( getsign(st0_ptr) )
+ l[1] |= 0x80000000;
+
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8);
+ FPU_put_user(l[0], (u32 *)dfloat);
+ FPU_put_user(l[1], 1 + (u32 *)dfloat);
+ RE_ENTRANT_CHECK_ON;
+
+ return 1;
+}
+
+
+/* Put a float into user memory */
+int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float *single)
+{
+ s32 templ;
+ u32 increment = 0; /* avoid gcc warnings */
+ int precision_loss;
+ int exp;
+ FPU_REG tmp;
+
+ if ( st0_tag == TAG_Valid )
+ {
+
+ reg_copy(st0_ptr, &tmp);
+ exp = exponent(&tmp);
+
+ if ( exp < SINGLE_Emin )
+ {
+ addexponent(&tmp, -SINGLE_Emin + 23); /* largest exp to be 22 */
+
+ denormal_arg:
+
+ if ( (precision_loss = FPU_round_to_int(&tmp, st0_tag)) )
+ {
+#ifdef PECULIAR_486
+ /* Did it round to a non-denormal ? */
+ /* This behaviour might be regarded as peculiar, it appears
+ that the 80486 rounds to the dest precision, then
+ converts to decide underflow. */
+ if ( !((tmp.sigl == 0x00800000) &&
+ ((st0_ptr->sigh & 0x000000ff) || st0_ptr->sigl)) )
+#endif /* PECULIAR_486 */
+ {
+ EXCEPTION(EX_Underflow);
+ /* This is a special case: see sec 16.2.5.1 of
+ the 80486 book */
+ if ( !(control_word & CW_Underflow) )
+ return 0;
+ }
+ EXCEPTION(precision_loss);
+ if ( !(control_word & CW_Precision) )
+ return 0;
+ }
+ templ = tmp.sigl;
+ }
+ else
+ {
+ if ( tmp.sigl | (tmp.sigh & 0x000000ff) )
+ {
+ u32 sigh = tmp.sigh;
+ u32 sigl = tmp.sigl;
+
+ precision_loss = 1;
+ switch (control_word & CW_RC)
+ {
+ case RC_RND:
+ increment = ((sigh & 0xff) > 0x80) /* more than half */
+ || (((sigh & 0xff) == 0x80) && sigl) /* more than half */
+ || ((sigh & 0x180) == 0x180); /* round to even */
+ break;
+ case RC_DOWN: /* towards -infinity */
+ increment = signpositive(&tmp)
+ ? 0 : (sigl | (sigh & 0xff));
+ break;
+ case RC_UP: /* towards +infinity */
+ increment = signpositive(&tmp)
+ ? (sigl | (sigh & 0xff)) : 0;
+ break;
+ case RC_CHOP:
+ increment = 0;
+ break;
+ }
+
+ /* Truncate part of the mantissa */
+ tmp.sigl = 0;
+
+ if (increment)
+ {
+ if ( sigh >= 0xffffff00 )
+ {
+ /* The sigh part overflows */
+ tmp.sigh = 0x80000000;
+ exp++;
+ if ( exp >= EXP_OVER )
+ goto overflow;
+ }
+ else
+ {
+ tmp.sigh &= 0xffffff00;
+ tmp.sigh += 0x100;
+ }
+ }
+ else
+ {
+ tmp.sigh &= 0xffffff00; /* Finish the truncation */
+ }
+ }
+ else
+ precision_loss = 0;
+
+ templ = (tmp.sigh >> 8) & 0x007fffff;
+
+ if ( exp > SINGLE_Emax )
+ {
+ overflow:
+ EXCEPTION(EX_Overflow);
+ if ( !(control_word & CW_Overflow) )
+ return 0;
+ set_precision_flag_up();
+ if ( !(control_word & CW_Precision) )
+ return 0;
+
+ /* This is a special case: see sec 16.2.5.1 of the 80486 book. */
+ /* Masked response is overflow to infinity. */
+ templ = 0x7f800000;
+ }
+ else
+ {
+ if ( precision_loss )
+ {
+ if ( increment )
+ set_precision_flag_up();
+ else
+ set_precision_flag_down();
+ }
+ /* Add the exponent */
+ templ |= ((exp+SINGLE_Ebias) & 0xff) << 23;
+ }
+ }
+ }
+ else if (st0_tag == TAG_Zero)
+ {
+ templ = 0;
+ }
+ else if ( st0_tag == TAG_Special )
+ {
+ st0_tag = FPU_Special(st0_ptr);
+ if (st0_tag == TW_Denormal)
+ {
+ reg_copy(st0_ptr, &tmp);
+
+ /* A denormal will always underflow. */
+#ifndef PECULIAR_486
+ /* An 80486 is supposed to be able to generate
+ a denormal exception here, but... */
+ /* Underflow has priority. */
+ if ( control_word & CW_Underflow )
+ denormal_operand();
+#endif /* PECULIAR_486 */
+ goto denormal_arg;
+ }
+ else if (st0_tag == TW_Infinity)
+ {
+ templ = 0x7f800000;
+ }
+ else if (st0_tag == TW_NaN)
+ {
+ /* Is it really a NaN ? */
+ if ( (exponent(st0_ptr) == EXP_OVER) && (st0_ptr->sigh & 0x80000000) )
+ {
+ /* See if we can get a valid NaN from the FPU_REG */
+ templ = st0_ptr->sigh >> 8;
+ if ( !(st0_ptr->sigh & 0x40000000) )
+ {
+ /* It is a signalling NaN */
+ EXCEPTION(EX_Invalid);
+ if ( !(control_word & CW_Invalid) )
+ return 0;
+ templ |= (0x40000000 >> 8);
+ }
+ templ |= 0x7f800000;
+ }
+ else
+ {
+ /* It is an unsupported data type */
+ EXCEPTION(EX_Invalid);
+ if ( !(control_word & CW_Invalid) )
+ return 0;
+ templ = 0xffc00000;
+ }
+ }
+#ifdef PARANOID
+ else
+ {
+ EXCEPTION(EX_INTERNAL|0x164);
+ return 0;
+ }
+#endif
+ }
+ else if ( st0_tag == TAG_Empty )
+ {
+ /* Empty register (stack underflow) */
+ EXCEPTION(EX_StackUnder);
+ if ( control_word & EX_Invalid )
+ {
+ /* The masked response */
+ /* Put out the QNaN indefinite */
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,(void *)single,4);
+ FPU_put_user(0xffc00000, (u32 *) single);
+ RE_ENTRANT_CHECK_ON;
+ return 1;
+ }
+ else
+ return 0;
+ }
+#ifdef PARANOID
+ else
+ {
+ EXCEPTION(EX_INTERNAL|0x163);
+ return 0;
+ }
+#endif
+ if ( getsign(st0_ptr) )
+ templ |= 0x80000000;
+
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,(void *)single,4);
+ FPU_put_user(templ,(u32 *) single);
+ RE_ENTRANT_CHECK_ON;
+
+ return 1;
+}
+
+
+/* Put a 64bit quantity into user memory */
+int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, s64 *d)
+{
+ FPU_REG t;
+ s64 tll;
+ int precision_loss;
+
+ if ( st0_tag == TAG_Empty )
+ {
+ /* Empty register (stack underflow) */
+ EXCEPTION(EX_StackUnder);
+ goto invalid_operand;
+ }
+ else if ( st0_tag == TAG_Special )
+ {
+ st0_tag = FPU_Special(st0_ptr);
+ if ( (st0_tag == TW_Infinity) ||
+ (st0_tag == TW_NaN) )
+ {
+ EXCEPTION(EX_Invalid);
+ goto invalid_operand;
+ }
+ }
+
+ reg_copy(st0_ptr, &t);
+ precision_loss = FPU_round_to_int(&t, st0_tag);
+#ifndef EMU_BIG_ENDIAN
+ ((u32 *)&tll)[0] = t.sigl;
+ ((u32 *)&tll)[1] = t.sigh;
+#else
+ ((u32 *)&tll)[0] = t.sigh;
+ ((u32 *)&tll)[1] = t.sigl;
+#endif
+ if ( (precision_loss == 1) ||
+ ((t.sigh & 0x80000000) &&
+ !((t.sigh == 0x80000000) && (t.sigl == 0) &&
+ signnegative(&t))) )
+ {
+ EXCEPTION(EX_Invalid);
+ /* This is a special case: see sec 16.2.5.1 of the 80486 book */
+ invalid_operand:
+ if ( control_word & EX_Invalid )
+ {
+ /* Produce something like QNaN "indefinite" */
+ tll = BX_CONST64(0x8000000000000000);
+ }
+ else
+ return 0;
+ }
+ else
+ {
+ if ( precision_loss )
+ set_precision_flag(precision_loss);
+ if ( signnegative(&t) )
+ tll = - tll;
+ }
+
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,(void *)d,8);
+#ifndef USE_WITH_CPU_SIM
+ copy_to_user(d, &tll, 8);
+#else
+ FPU_put_user((u32) tll, (u32*)(((u8 *)d)+0));
+ FPU_put_user((u32) (tll>>32), (u32*)(((u8 *)d)+4));
+#endif
+ RE_ENTRANT_CHECK_ON;
+
+ return 1;
+}
+
+
+/* Put a long into user memory */
+int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, s32 *d)
+{
+ FPU_REG t;
+ int precision_loss;
+
+ if ( st0_tag == TAG_Empty )
+ {
+ /* Empty register (stack underflow) */
+ EXCEPTION(EX_StackUnder);
+ goto invalid_operand;
+ }
+ else if ( st0_tag == TAG_Special )
+ {
+ st0_tag = FPU_Special(st0_ptr);
+ if ( (st0_tag == TW_Infinity) ||
+ (st0_tag == TW_NaN) )
+ {
+ EXCEPTION(EX_Invalid);
+ goto invalid_operand;
+ }
+ }
+
+ reg_copy(st0_ptr, &t);
+ precision_loss = FPU_round_to_int(&t, st0_tag);
+ if (t.sigh ||
+ ((t.sigl & 0x80000000) &&
+ !((t.sigl == 0x80000000) && signnegative(&t))) )
+ {
+ EXCEPTION(EX_Invalid);
+ /* This is a special case: see sec 16.2.5.1 of the 80486 book */
+ invalid_operand:
+ if ( control_word & EX_Invalid )
+ {
+ /* Produce something like QNaN "indefinite" */
+ t.sigl = 0x80000000;
+ }
+ else
+ return 0;
+ }
+ else
+ {
+ if ( precision_loss )
+ set_precision_flag(precision_loss);
+ if ( signnegative(&t) )
+ t.sigl = -(s32)t.sigl;
+ }
+
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,d,4);
+ FPU_put_user(t.sigl, (u32 *) d);
+ RE_ENTRANT_CHECK_ON;
+
+ return 1;
+}
+
+
+/* Put a short into user memory */
+int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, s16 *d)
+{
+ FPU_REG t;
+ int precision_loss;
+
+ if ( st0_tag == TAG_Empty )
+ {
+ /* Empty register (stack underflow) */
+ EXCEPTION(EX_StackUnder);
+ goto invalid_operand;
+ }
+ else if ( st0_tag == TAG_Special )
+ {
+ st0_tag = FPU_Special(st0_ptr);
+ if ( (st0_tag == TW_Infinity) ||
+ (st0_tag == TW_NaN) )
+ {
+ EXCEPTION(EX_Invalid);
+ goto invalid_operand;
+ }
+ }
+
+ reg_copy(st0_ptr, &t);
+ precision_loss = FPU_round_to_int(&t, st0_tag);
+ if (t.sigh ||
+ ((t.sigl & 0xffff8000) &&
+ !((t.sigl == 0x8000) && signnegative(&t))) )
+ {
+ EXCEPTION(EX_Invalid);
+ /* This is a special case: see sec 16.2.5.1 of the 80486 book */
+ invalid_operand:
+ if ( control_word & EX_Invalid )
+ {
+ /* Produce something like QNaN "indefinite" */
+ t.sigl = 0x8000;
+ }
+ else
+ return 0;
+ }
+ else
+ {
+ if ( precision_loss )
+ set_precision_flag(precision_loss);
+ if ( signnegative(&t) )
+ t.sigl = -t.sigl;
+ }
+
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,d,2);
+ FPU_put_user((s16)t.sigl,(s16 *) d);
+ RE_ENTRANT_CHECK_ON;
+
+ return 1;
+}
+
+
+/* Put a packed bcd array into user memory */
+int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char *d)
+{
+ FPU_REG t;
+ u64 ll;
+ u_char b;
+ int i, precision_loss;
+ u_char sign = (getsign(st0_ptr) == SIGN_NEG) ? 0x80 : 0;
+
+ if ( st0_tag == TAG_Empty )
+ {
+ /* Empty register (stack underflow) */
+ EXCEPTION(EX_StackUnder);
+ goto invalid_operand;
+ }
+ else if ( st0_tag == TAG_Special )
+ {
+ st0_tag = FPU_Special(st0_ptr);
+ if ( (st0_tag == TW_Infinity) ||
+ (st0_tag == TW_NaN) )
+ {
+ EXCEPTION(EX_Invalid);
+ goto invalid_operand;
+ }
+ }
+
+ reg_copy(st0_ptr, &t);
+ precision_loss = FPU_round_to_int(&t, st0_tag);
+ ll = significand(&t);
+
+ /* Check for overflow, by comparing with 999999999999999999 decimal. */
+ if ( (t.sigh > 0x0de0b6b3) ||
+ ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff)) )
+ {
+ EXCEPTION(EX_Invalid);
+ /* This is a special case: see sec 16.2.5.1 of the 80486 book */
+ invalid_operand:
+ if ( control_word & CW_Invalid )
+ {
+ /* Produce the QNaN "indefinite" */
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,d,10);
+ for ( i = 0; i < 7; i++)
+ FPU_put_user(0, (u_char *) d+i); /* These bytes "undefined" */
+ FPU_put_user(0xc0, (u_char *) d+7); /* This byte "undefined" */
+ FPU_put_user(0xff, (u_char *) d+8);
+ FPU_put_user(0xff, (u_char *) d+9);
+ RE_ENTRANT_CHECK_ON;
+ return 1;
+ }
+ else
+ return 0;
+ }
+ else if ( precision_loss )
+ {
+ /* Precision loss doesn't stop the data transfer */
+ set_precision_flag(precision_loss);
+ }
+
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,d,10);
+ RE_ENTRANT_CHECK_ON;
+ for ( i = 0; i < 9; i++)
+ {
+ b = FPU_div_small(&ll, 10);
+ b |= (FPU_div_small(&ll, 10)) << 4;
+ RE_ENTRANT_CHECK_OFF;
+ FPU_put_user(b,(u_char *) d+i);
+ RE_ENTRANT_CHECK_ON;
+ }
+ RE_ENTRANT_CHECK_OFF;
+ FPU_put_user(sign,(u_char *) d+9);
+ RE_ENTRANT_CHECK_ON;
+
+ return 1;
+}
+
+/*===========================================================================*/
+
+/* r gets mangled such that sig is int, sign:
+ it is NOT normalized */
+/* The return value (in eax) is zero if the result is exact,
+ if bits are changed due to rounding, truncation, etc, then
+ a non-zero value is returned */
+/* Overflow is signalled by a non-zero return value (in eax).
+ In the case of overflow, the returned significand always has the
+ largest possible value */
+int FPU_round_to_int(FPU_REG *r, u_char tag)
+{
+ u_char very_big;
+ unsigned eax;
+
+ if (tag == TAG_Zero)
+ {
+ /* Make sure that zero is returned */
+ significand(r) = 0;
+ return 0; /* o.k. */
+ }
+
+ if (exponent(r) > 63)
+ {
+ r->sigl = r->sigh = ~0; /* The largest representable number */
+ return 1; /* overflow */
+ }
+
+#ifndef EMU_BIG_ENDIAN
+ eax = FPU_shrxs(&r->sigl, 63 - exponent(r));
+#else
+ eax = FPU_shrxs(&r->sigh, 63 - exponent(r));
+#endif
+ very_big = !(~(r->sigh) | ~(r->sigl)); /* test for 0xfff...fff */
+#define half_or_more (eax & 0x80000000)
+#define frac_part (eax)
+#define more_than_half ((eax & 0x80000001) == 0x80000001)
+ switch (control_word & CW_RC)
+ {
+ case RC_RND:
+ if ( more_than_half /* nearest */
+ || (half_or_more && (r->sigl & 1)) ) /* odd -> even */
+ {
+ if ( very_big ) return 1; /* overflow */
+ significand(r) ++;
+ return PRECISION_LOST_UP;
+ }
+ break;
+ case RC_DOWN:
+ if (frac_part && getsign(r))
+ {
+ if ( very_big ) return 1; /* overflow */
+ significand(r) ++;
+ return PRECISION_LOST_UP;
+ }
+ break;
+ case RC_UP:
+ if (frac_part && !getsign(r))
+ {
+ if ( very_big ) return 1; /* overflow */
+ significand(r) ++;
+ return PRECISION_LOST_UP;
+ }
+ break;
+ case RC_CHOP:
+ break;
+ }
+
+ return eax ? PRECISION_LOST_DOWN : 0;
+
+}
+
+/*===========================================================================*/
+
+u_char *fldenv(fpu_addr_modes addr_modes, u_char *s)
+{
+ u16 tag_word = 0;
+ u_char tag;
+ int i;
+
+ if ( (addr_modes.default_mode == VM86) ||
+ ((addr_modes.default_mode == PM16)
+ ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) )
+ {
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_READ, s, 0x0e);
+ FPU_get_user(control_word, (u16 *) s);
+ FPU_get_user(partial_status, (u16 *) (s+2));
+ FPU_get_user(tag_word, (u16 *) (s+4));
+ FPU_get_user(instruction_address.offset, (u16 *) (s+6));
+ FPU_get_user(instruction_address.selector, (u16 *) (s+8));
+ FPU_get_user(operand_address.offset, (u16 *) (s+0x0a));
+ FPU_get_user(operand_address.selector, (u16 *) (s+0x0c));
+ RE_ENTRANT_CHECK_ON;
+ s += 0x0e;
+ if ( addr_modes.default_mode == VM86 )
+ {
+ instruction_address.offset
+ += (instruction_address.selector & 0xf000) << 4;
+ operand_address.offset += (operand_address.selector & 0xf000) << 4;
+ }
+ }
+ else
+ {
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_READ, s, 0x1c);
+ FPU_get_user(control_word, (u16 *) s);
+ FPU_get_user(partial_status, (u16 *) (s+4));
+ FPU_get_user(tag_word, (u16 *) (s+8));
+ FPU_get_user(instruction_address.offset, (u32 *) (s+0x0c));
+ FPU_get_user(instruction_address.selector, (u16 *) (s+0x10));
+ FPU_get_user(instruction_address.opcode, (u16 *) (s+0x12));
+ FPU_get_user(operand_address.offset, (u32 *) (s+0x14));
+ FPU_get_user(operand_address.selector, (u32 *) (s+0x18));
+ RE_ENTRANT_CHECK_ON;
+ s += 0x1c;
+ }
+
+#ifdef PECULIAR_486
+ control_word &= ~0xe080;
+#endif /* PECULIAR_486 */
+
+ top = (partial_status >> SW_Top_Shift) & 7;
+
+ if ( partial_status & ~control_word & CW_Exceptions )
+ partial_status |= (SW_Summary | SW_Backward);
+ else
+ partial_status &= ~(SW_Summary | SW_Backward);
+
+ for ( i = 0; i < 8; i++ )
+ {
+ tag = tag_word & 3;
+ tag_word >>= 2;
+
+ if ( tag == TAG_Empty )
+ /* New tag is empty. Accept it */
+ FPU_settag(i, TAG_Empty);
+ else if ( FPU_gettag(i) == TAG_Empty )
+ {
+ /* Old tag is empty and new tag is not empty. New tag is determined
+ by old reg contents */
+ if ( exponent(&fpu_register(i)) == - EXTENDED_Ebias )
+ {
+ if ( !(fpu_register(i).sigl | fpu_register(i).sigh) )
+ FPU_settag(i, TAG_Zero);
+ else
+ FPU_settag(i, TAG_Special);
+ }
+ else if ( exponent(&fpu_register(i)) == 0x7fff - EXTENDED_Ebias )
+ {
+ FPU_settag(i, TAG_Special);
+ }
+ else if ( fpu_register(i).sigh & 0x80000000 )
+ FPU_settag(i, TAG_Valid);
+ else
+ FPU_settag(i, TAG_Special); /* An Un-normal */
+ }
+ /* Else old tag is not empty and new tag is not empty. Old tag
+ remains correct */
+ }
+
+ return s;
+}
+
+
+void frstor(fpu_addr_modes addr_modes, u_char *data_address)
+{
+ int i, regnr;
+ u_char *s = fldenv(addr_modes, data_address);
+ int offset = (top & 7) * sizeof(FPU_REG), other = 8*sizeof(FPU_REG) - offset;
+
+ /* Copy all registers in stack order. */
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_READ,s,80);
+#ifndef USE_WITH_CPU_SIM
+ __copy_from_user(register_base+offset, s, other);
+ if ( offset )
+ __copy_from_user(register_base, s+other, offset);
+#else
+ {
+ FPU_REG *fpu_reg_p;
+
+ fpu_reg_p = (FPU_REG *) (register_base+offset);
+ while (other>0) {
+ FPU_get_user(fpu_reg_p->sigl, (u32*)(s+0));
+ FPU_get_user(fpu_reg_p->sigh, (u32*)(s+4));
+ FPU_get_user(fpu_reg_p->exp, (u16*)(s+8));
+ fpu_reg_p++;
+ s += 10;
+ other -= sizeof(FPU_REG);
+ }
+ fpu_reg_p = (FPU_REG *) register_base;
+ while (offset>0) {
+ FPU_get_user(fpu_reg_p->sigl, (u32*)(s+0));
+ FPU_get_user(fpu_reg_p->sigh, (u32*)(s+4));
+ FPU_get_user(fpu_reg_p->exp, (u16*)(s+8));
+ fpu_reg_p++;
+ s += 10;
+ offset -= sizeof(FPU_REG);
+ }
+ }
+#endif
+ RE_ENTRANT_CHECK_ON;
+
+ for ( i = 0; i < 8; i++ )
+ {
+ regnr = (i+top) & 7;
+ if ( FPU_gettag(regnr) != TAG_Empty )
+ /* The loaded data over-rides all other cases. */
+ FPU_settag(regnr, FPU_tagof(&st(i)));
+ }
+
+}
+
+
+u_char *fstenv(fpu_addr_modes addr_modes, u_char *d)
+{
+ if ( (addr_modes.default_mode == VM86) ||
+ ((addr_modes.default_mode == PM16)
+ ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) )
+ {
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,d,14);
+#ifdef PECULIAR_486
+ FPU_put_user(control_word & ~0xe080, (u32 *) d);
+#else
+ FPU_put_user(control_word, (u16 *) d);
+#endif /* PECULIAR_486 */
+ FPU_put_user(status_word(), (u16 *) (d+2));
+ FPU_put_user(fpu_tag_word, (u16 *) (d+4));
+ FPU_put_user(instruction_address.offset, (u16 *) (d+6));
+ FPU_put_user(operand_address.offset, (u16 *) (d+0x0a));
+ if ( addr_modes.default_mode == VM86 )
+ {
+ FPU_put_user((instruction_address.offset & 0xf0000) >> 4,
+ (u16 *) (d+8));
+ FPU_put_user((operand_address.offset & 0xf0000) >> 4,
+ (u16 *) (d+0x0c));
+ }
+ else
+ {
+ FPU_put_user(instruction_address.selector, (u16 *) (d+8));
+ FPU_put_user(operand_address.selector, (u16 *) (d+0x0c));
+ }
+ RE_ENTRANT_CHECK_ON;
+ d += 0x0e;
+ }
+ else
+ {
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE, d, 7*4);
+#ifdef PECULIAR_486
+ control_word &= ~0xe080;
+ /* An 80486 sets nearly all of the reserved bits to 1. */
+ control_word |= 0xffff0040;
+ partial_status = status_word() | 0xffff0000;
+ fpu_tag_word |= 0xffff0000;
+ I387.soft.fcs &= ~0xf8000000;
+ I387.soft.fos |= 0xffff0000;
+#endif /* PECULIAR_486 */
+#ifndef USE_WITH_CPU_SIM
+ __copy_to_user(d, &control_word, 7*4);
+#else
+ FPU_put_user((u32) I387.soft.cwd, (u32*)(((u8 *)d)+0));
+ FPU_put_user((u32) I387.soft.swd, (u32*)(((u8 *)d)+4));
+ FPU_put_user((u32) I387.soft.twd, (u32*)(((u8 *)d)+8));
+ FPU_put_user((u32) I387.soft.fip, (u32*)(((u8 *)d)+12));
+ FPU_put_user((u32) I387.soft.fcs, (u32*)(((u8 *)d)+16));
+ FPU_put_user((u32) I387.soft.foo, (u32*)(((u8 *)d)+20));
+ FPU_put_user((u32) I387.soft.fos, (u32*)(((u8 *)d)+24));
+#endif
+ RE_ENTRANT_CHECK_ON;
+ d += 0x1c;
+ }
+
+ control_word |= CW_Exceptions;
+ partial_status &= ~(SW_Summary | SW_Backward);
+
+ return d;
+}
+
+
+void fsave(fpu_addr_modes addr_modes, u_char *data_address)
+{
+ u_char *d;
+ int offset = (top & 7) * sizeof(FPU_REG), other = 8*sizeof(FPU_REG) - offset;
+
+ d = fstenv(addr_modes, data_address);
+
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,d,80);
+
+ /* Copy all registers in stack order. */
+#ifndef USE_WITH_CPU_SIM
+ __copy_to_user(d, register_base+offset, other);
+ if ( offset )
+ __copy_to_user(d+other, register_base, offset);
+#else
+ {
+ FPU_REG *fpu_reg_p;
+
+ fpu_reg_p = (FPU_REG *) (register_base+offset);
+ while (other>0) {
+ FPU_put_user(fpu_reg_p->sigl, (u32*)(d+0));
+ FPU_put_user(fpu_reg_p->sigh, (u32*)(d+4));
+ FPU_put_user(fpu_reg_p->exp, (u16*)(d+8));
+ fpu_reg_p++;
+ d += 10;
+ other -= sizeof(FPU_REG);
+ }
+ fpu_reg_p = (FPU_REG *) register_base;
+ while (offset>0) {
+ FPU_put_user(fpu_reg_p->sigl, (u32*)(d+0));
+ FPU_put_user(fpu_reg_p->sigh, (u32*)(d+4));
+ FPU_put_user(fpu_reg_p->exp, (u16*)(d+8));
+ fpu_reg_p++;
+ d += 10;
+ offset -= sizeof(FPU_REG);
+ }
+ }
+#endif
+ RE_ENTRANT_CHECK_ON;
+
+ finit();
+}
+
+/*===========================================================================*/
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | reg_mul.c |
+ | |
+ | Multiply one FPU_REG by another, put the result in a destination FPU_REG. |
+ | |
+ | Copyright (C) 1992,1993,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
+ | |
+ | Returns the tag of the result if no exceptions or errors occurred. |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | The destination may be any FPU_REG, including one of the source FPU_REGs. |
+ +---------------------------------------------------------------------------*/
+
+#include "fpu_emu.h"
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_system.h"
+
+
+/*
+ Multiply two registers to give a register result.
+ The sources are st(deststnr) and (b,tagb,signb).
+ The destination is st(deststnr).
+ */
+/* This routine must be called with non-empty source registers */
+int FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w)
+{
+ FPU_REG *a = &st(deststnr);
+ FPU_REG *dest = a;
+ u_char taga = FPU_gettagi(deststnr);
+ u_char saved_sign = getsign(dest);
+ u_char sign = (getsign(a) ^ getsign(b));
+ int tag;
+
+
+ if ( !(taga | tagb) )
+ {
+ /* Both regs Valid, this should be the most common case. */
+
+ tag = FPU_u_mul(a, b, dest, control_w, sign, exponent(a) + exponent(b));
+ if ( tag < 0 )
+ {
+ setsign(dest, saved_sign);
+ return tag;
+ }
+ FPU_settagi(deststnr, tag);
+ return tag;
+ }
+
+ if ( taga == TAG_Special )
+ taga = FPU_Special(a);
+ if ( tagb == TAG_Special )
+ tagb = FPU_Special(b);
+
+ if ( ((taga == TAG_Valid) && (tagb == TW_Denormal))
+ || ((taga == TW_Denormal) && (tagb == TAG_Valid))
+ || ((taga == TW_Denormal) && (tagb == TW_Denormal)) )
+ {
+ FPU_REG x, y;
+ if ( denormal_operand() < 0 )
+ return FPU_Exception;
+
+ FPU_to_exp16(a, &x);
+ FPU_to_exp16(b, &y);
+ tag = FPU_u_mul(&x, &y, dest, control_w, sign,
+ exponent16(&x) + exponent16(&y));
+ if ( tag < 0 )
+ {
+ setsign(dest, saved_sign);
+ return tag;
+ }
+ FPU_settagi(deststnr, tag);
+ return tag;
+ }
+ else if ( (taga <= TW_Denormal) && (tagb <= TW_Denormal) )
+ {
+ if ( ((tagb == TW_Denormal) || (taga == TW_Denormal))
+ && (denormal_operand() < 0) )
+ return FPU_Exception;
+
+ /* Must have either both arguments == zero, or
+ one valid and the other zero.
+ The result is therefore zero. */
+ FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
+ /* The 80486 book says that the answer is +0, but a real
+ 80486 behaves this way.
+ IEEE-754 apparently says it should be this way. */
+ setsign(dest, sign);
+ return TAG_Zero;
+ }
+ /* Must have infinities, NaNs, etc */
+ else if ( (taga == TW_NaN) || (tagb == TW_NaN) )
+ {
+ return real_2op_NaN(b, tagb, deststnr, &st(0));
+ }
+ else if ( ((taga == TW_Infinity) && (tagb == TAG_Zero))
+ || ((tagb == TW_Infinity) && (taga == TAG_Zero)) )
+ {
+ return arith_invalid(deststnr); /* Zero*Infinity is invalid */
+ }
+ else if ( ((taga == TW_Denormal) || (tagb == TW_Denormal))
+ && (denormal_operand() < 0) )
+ {
+ return FPU_Exception;
+ }
+ else if (taga == TW_Infinity)
+ {
+ FPU_copy_to_regi(a, TAG_Special, deststnr);
+ setsign(dest, sign);
+ return TAG_Special;
+ }
+ else if (tagb == TW_Infinity)
+ {
+ FPU_copy_to_regi(b, TAG_Special, deststnr);
+ setsign(dest, sign);
+ return TAG_Special;
+ }
+
+#ifdef PARANOID
+ else
+ {
+ EXCEPTION(EX_INTERNAL|0x102);
+ return FPU_Exception;
+ }
+#endif /* PARANOID */
+
+}
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | reg_norm.S |
+ | |
+ | Copyright (C) 1992,1993,1994,1995,1997,1999 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@melbpc.org.au |
+ | |
+ | Normalize the value in a FPU_REG. |
+ | |
+ | Call from C as: |
+ | int FPU_normalize_nuo(FPU_REG *n, int bias) |
+ | |
+ | Return value is the tag of the answer. |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#include "fpu_emu.h"
+
+
+/* Normalise without reporting underflow or overflow */
+ENTRY(FPU_normalize_nuo)
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %ebx
+
+ movl PARAM1,%ebx
+
+ movl SIGH(%ebx),%edx
+ movl SIGL(%ebx),%eax
+
+ orl %edx,%edx /* ms bits */
+ js L_exit_nuo_valid /* Already normalized */
+ jnz L_nuo_shift_1 /* Shift left 1 - 31 bits */
+
+ orl %eax,%eax
+ jz L_exit_nuo_zero /* The contents are zero */
+
+ movl %eax,%edx
+ xorl %eax,%eax
+ subw $32,EXP(%ebx) /* This can cause an underflow */
+
+/* We need to shift left by 1 - 31 bits */
+L_nuo_shift_1:
+ bsrl %edx,%ecx /* get the required shift in %ecx */
+ subl $31,%ecx
+ negl %ecx
+ shld %cl,%eax,%edx
+ shl %cl,%eax
+ subw %cx,EXP(%ebx) /* This can cause an underflow */
+
+ movl %edx,SIGH(%ebx)
+ movl %eax,SIGL(%ebx)
+
+L_exit_nuo_valid:
+ movl PARAM2,%eax
+ addw %ax,EXP(%ebx)
+ movl TAG_Valid,%eax
+
+ popl %ebx
+ leave
+ ret
+
+L_exit_nuo_zero:
+ movw EXP_UNDER,EXP(%ebx)
+ movl PARAM2,%eax
+ addw %ax,EXP(%ebx)
+ movl TAG_Zero,%eax
+
+ popl %ebx
+ leave
+ ret
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | reg_norm.c |
+ | |
+ | Copyright (C) 1992,1993,1994,1995,1997,1999 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@melbpc.org.au |
+ | |
+ | Normalize the value in a FPU_REG. |
+ | |
+ | |
+ | Return value is the tag of the answer. |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#include "fpu_emu.h"
+
+
+
+int FPU_normalize_nuo(FPU_REG *x, int bias)
+{
+
+ if ( ! (x->sigh & 0x80000000) )
+ {
+ if ( x->sigh == 0 )
+ {
+ if ( x->sigl == 0 )
+ {
+ x->exp = EXP_UNDER;
+ return TAG_Zero;
+ }
+ x->sigh = x->sigl;
+ x->sigl = 0;
+ x->exp -= 32;
+ }
+ while ( !(x->sigh & 0x80000000) )
+ {
+ x->sigh <<= 1;
+ if ( x->sigl & 0x80000000 )
+ x->sigh |= 1;
+ x->sigl <<= 1;
+ x->exp --;
+ }
+ }
+
+ x->exp += bias;
+
+ return TAG_Valid;
+}
--- /dev/null
+ .file "reg_round.S"
+/*---------------------------------------------------------------------------+
+ | reg_round.S |
+ | |
+ | Rounding/truncation/etc for FPU basic arithmetic functions. |
+ | |
+ | Copyright (C) 1993,1995,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@suburbia.net |
+ | |
+ | This code has four possible entry points. |
+ | The following must be entered by a jmp instruction: |
+ | fpu_reg_round, fpu_reg_round_sqrt, and fpu_Arith_exit. |
+ | |
+ | The FPU_round entry point is intended to be used by C code. |
+ | From C, call as: |
+ | int FPU_round(FPU_REG *arg, unsigned int extent, unsigned int control_w) |
+ | |
+ | Return value is the tag of the answer, or-ed with FPU_Exception if |
+ | one was raised, or -1 on internal error. |
+ | |
+ | For correct "up" and "down" rounding, the argument must have the correct |
+ | sign. |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | Four entry points. |
+ | |
+ | Needed by both the fpu_reg_round and fpu_reg_round_sqrt entry points: |
+ | %eax:%ebx 64 bit significand |
+ | %edx 32 bit extension of the significand |
+ | %edi pointer to an FPU_REG for the result to be stored |
+ | stack calling function must have set up a C stack frame and |
+ | pushed %esi, %edi, and %ebx |
+ | |
+ | Needed just for the fpu_reg_round_sqrt entry point: |
+ | %cx A control word in the same format as the FPU control word. |
+ | Otherwise, PARAM4 must give such a value. |
+ | |
+ | |
+ | The significand and its extension are assumed to be exact in the |
+ | following sense: |
+ | If the significand by itself is the exact result then the significand |
+ | extension (%edx) must contain 0, otherwise the significand extension |
+ | must be non-zero. |
+ | If the significand extension is non-zero then the significand is |
+ | smaller than the magnitude of the correct exact result by an amount |
+ | greater than zero and less than one ls bit of the significand. |
+ | The significand extension is only required to have three possible |
+ | non-zero values: |
+ | less than 0x80000000 <=> the significand is less than 1/2 an ls |
+ | bit smaller than the magnitude of the |
+ | true exact result. |
+ | exactly 0x80000000 <=> the significand is exactly 1/2 an ls bit |
+ | smaller than the magnitude of the true |
+ | exact result. |
+ | greater than 0x80000000 <=> the significand is more than 1/2 an ls |
+ | bit smaller than the magnitude of the |
+ | true exact result. |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | The code in this module has become quite complex, but it should handle |
+ | all of the FPU flags which are set at this stage of the basic arithmetic |
+ | computations. |
+ | There are a few rare cases where the results are not set identically to |
+ | a real FPU. These require a bit more thought because at this stage the |
+ | results of the code here appear to be more consistent... |
+ | This may be changed in a future version. |
+ +---------------------------------------------------------------------------*/
+
+
+#include "fpu_emu.h"
+#include "exception.h"
+#include "control_w.h"
+
+/* Flags for FPU_bits_lost */
+#define LOST_DOWN $1
+#define LOST_UP $2
+
+/* Flags for FPU_denormal */
+#define DENORMAL $1
+#define UNMASKED_UNDERFLOW $2
+
+
+#ifndef NON_REENTRANT_FPU
+/* Make the code re-entrant by putting
+ local storage on the stack: */
+#define FPU_bits_lost (%esp)
+#define FPU_denormal 1(%esp)
+
+#else
+/* Not re-entrant, so we can gain speed by putting
+ local storage in a static area: */
+.data
+ .align 4,0
+FPU_bits_lost:
+ .byte 0
+FPU_denormal:
+ .byte 0
+#endif /* NON_REENTRANT_FPU */
+
+
+.text
+.globl fpu_reg_round
+.globl fpu_reg_round_sqrt
+.globl fpu_Arith_exit
+
+/* Entry point when called from C */
+ENTRY(FPU_round)
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%edi
+ movl SIGH(%edi),%eax
+ movl SIGL(%edi),%ebx
+ movl PARAM2,%edx
+
+fpu_reg_round: /* Normal entry point */
+ movl PARAM4,%ecx
+
+#ifndef NON_REENTRANT_FPU
+ pushl %ebx /* adjust the stack pointer */
+#endif /* NON_REENTRANT_FPU */
+
+#ifdef PARANOID
+/* Cannot use this here yet */
+/* orl %eax,%eax */
+/* jns L_entry_bugged */
+#endif /* PARANOID */
+
+ cmpw EXP_UNDER,EXP(%edi)
+ jle L_Make_denorm /* The number is a de-normal */
+
+ movb $0,FPU_denormal /* 0 -> not a de-normal */
+
+Denorm_done:
+ movb $0,FPU_bits_lost /* No bits yet lost in rounding */
+
+ movl %ecx,%esi
+ andl CW_PC,%ecx
+ cmpl PR_64_BITS,%ecx
+ je LRound_To_64
+
+ cmpl PR_53_BITS,%ecx
+ je LRound_To_53
+
+ cmpl PR_24_BITS,%ecx
+ je LRound_To_24
+
+#ifdef PECULIAR_486
+/* With the precision control bits set to 01 "(reserved)", a real 80486
+ behaves as if the precision control bits were set to 11 "64 bits" */
+ cmpl PR_RESERVED_BITS,%ecx
+ je LRound_To_64
+#ifdef PARANOID
+ jmp L_bugged_denorm_486
+#endif /* PARANOID */
+#else
+#ifdef PARANOID
+ jmp L_bugged_denorm /* There is no bug, just a bad control word */
+#endif /* PARANOID */
+#endif /* PECULIAR_486 */
+
+
+/* Round etc to 24 bit precision */
+LRound_To_24:
+ movl %esi,%ecx
+ andl CW_RC,%ecx
+ cmpl RC_RND,%ecx
+ je LRound_nearest_24
+
+ cmpl RC_CHOP,%ecx
+ je LCheck_truncate_24
+
+ cmpl RC_UP,%ecx /* Towards +infinity */
+ je LUp_24
+
+ cmpl RC_DOWN,%ecx /* Towards -infinity */
+ je LDown_24
+
+#ifdef PARANOID
+ jmp L_bugged_round24
+#endif /* PARANOID */
+
+LUp_24:
+ cmpb SIGN_POS,PARAM5
+ jne LCheck_truncate_24 /* If negative then up==truncate */
+
+ jmp LCheck_24_round_up
+
+LDown_24:
+ cmpb SIGN_POS,PARAM5
+ je LCheck_truncate_24 /* If positive then down==truncate */
+
+LCheck_24_round_up:
+ movl %eax,%ecx
+ andl $0x000000ff,%ecx
+ orl %ebx,%ecx
+ orl %edx,%ecx
+ jnz LDo_24_round_up
+ jmp L_Re_normalise
+
+LRound_nearest_24:
+ /* Do rounding of the 24th bit if needed (nearest or even) */
+ movl %eax,%ecx
+ andl $0x000000ff,%ecx
+ cmpl $0x00000080,%ecx
+ jc LCheck_truncate_24 /* less than half, no increment needed */
+
+ jne LGreater_Half_24 /* greater than half, increment needed */
+
+ /* Possibly half, we need to check the ls bits */
+ orl %ebx,%ebx
+ jnz LGreater_Half_24 /* greater than half, increment needed */
+
+ orl %edx,%edx
+ jnz LGreater_Half_24 /* greater than half, increment needed */
+
+ /* Exactly half, increment only if 24th bit is 1 (round to even) */
+ testl $0x00000100,%eax
+ jz LDo_truncate_24
+
+LGreater_Half_24: /* Rounding: increment at the 24th bit */
+LDo_24_round_up:
+ andl $0xffffff00,%eax /* Truncate to 24 bits */
+ xorl %ebx,%ebx
+ movb LOST_UP,FPU_bits_lost
+ addl $0x00000100,%eax
+ jmp LCheck_Round_Overflow
+
+LCheck_truncate_24:
+ movl %eax,%ecx
+ andl $0x000000ff,%ecx
+ orl %ebx,%ecx
+ orl %edx,%ecx
+ jz L_Re_normalise /* No truncation needed */
+
+LDo_truncate_24:
+ andl $0xffffff00,%eax /* Truncate to 24 bits */
+ xorl %ebx,%ebx
+ movb LOST_DOWN,FPU_bits_lost
+ jmp L_Re_normalise
+
+
+/* Round etc to 53 bit precision */
+LRound_To_53:
+ movl %esi,%ecx
+ andl CW_RC,%ecx
+ cmpl RC_RND,%ecx
+ je LRound_nearest_53
+
+ cmpl RC_CHOP,%ecx
+ je LCheck_truncate_53
+
+ cmpl RC_UP,%ecx /* Towards +infinity */
+ je LUp_53
+
+ cmpl RC_DOWN,%ecx /* Towards -infinity */
+ je LDown_53
+
+#ifdef PARANOID
+ jmp L_bugged_round53
+#endif /* PARANOID */
+
+LUp_53:
+ cmpb SIGN_POS,PARAM5
+ jne LCheck_truncate_53 /* If negative then up==truncate */
+
+ jmp LCheck_53_round_up
+
+LDown_53:
+ cmpb SIGN_POS,PARAM5
+ je LCheck_truncate_53 /* If positive then down==truncate */
+
+LCheck_53_round_up:
+ movl %ebx,%ecx
+ andl $0x000007ff,%ecx
+ orl %edx,%ecx
+ jnz LDo_53_round_up
+ jmp L_Re_normalise
+
+LRound_nearest_53:
+ /* Do rounding of the 53rd bit if needed (nearest or even) */
+ movl %ebx,%ecx
+ andl $0x000007ff,%ecx
+ cmpl $0x00000400,%ecx
+ jc LCheck_truncate_53 /* less than half, no increment needed */
+
+ jnz LGreater_Half_53 /* greater than half, increment needed */
+
+ /* Possibly half, we need to check the ls bits */
+ orl %edx,%edx
+ jnz LGreater_Half_53 /* greater than half, increment needed */
+
+ /* Exactly half, increment only if 53rd bit is 1 (round to even) */
+ testl $0x00000800,%ebx
+ jz LTruncate_53
+
+LGreater_Half_53: /* Rounding: increment at the 53rd bit */
+LDo_53_round_up:
+ movb LOST_UP,FPU_bits_lost
+ andl $0xfffff800,%ebx /* Truncate to 53 bits */
+ addl $0x00000800,%ebx
+ adcl $0,%eax
+ jmp LCheck_Round_Overflow
+
+LCheck_truncate_53:
+ movl %ebx,%ecx
+ andl $0x000007ff,%ecx
+ orl %edx,%ecx
+ jz L_Re_normalise
+
+LTruncate_53:
+ movb LOST_DOWN,FPU_bits_lost
+ andl $0xfffff800,%ebx /* Truncate to 53 bits */
+ jmp L_Re_normalise
+
+
+/* Round etc to 64 bit precision */
+LRound_To_64:
+ movl %esi,%ecx
+ andl CW_RC,%ecx
+ cmpl RC_RND,%ecx
+ je LRound_nearest_64
+
+ cmpl RC_CHOP,%ecx
+ je LCheck_truncate_64
+
+ cmpl RC_UP,%ecx /* Towards +infinity */
+ je LUp_64
+
+ cmpl RC_DOWN,%ecx /* Towards -infinity */
+ je LDown_64
+
+#ifdef PARANOID
+ jmp L_bugged_round64
+#endif /* PARANOID */
+
+LUp_64:
+ cmpb SIGN_POS,PARAM5
+ jne LCheck_truncate_64 /* If negative then up==truncate */
+
+ orl %edx,%edx
+ jnz LDo_64_round_up
+ jmp L_Re_normalise
+
+LDown_64:
+ cmpb SIGN_POS,PARAM5
+ je LCheck_truncate_64 /* If positive then down==truncate */
+
+ orl %edx,%edx
+ jnz LDo_64_round_up
+ jmp L_Re_normalise
+
+LRound_nearest_64:
+ cmpl $0x80000000,%edx
+ jc LCheck_truncate_64
+
+ jne LDo_64_round_up
+
+ /* Now test for round-to-even */
+ testb $1,%bl
+ jz LCheck_truncate_64
+
+LDo_64_round_up:
+ movb LOST_UP,FPU_bits_lost
+ addl $1,%ebx
+ adcl $0,%eax
+
+LCheck_Round_Overflow:
+ jnc L_Re_normalise
+
+ /* Overflow, adjust the result (significand to 1.0) */
+ rcrl $1,%eax
+ rcrl $1,%ebx
+ incw EXP(%edi)
+ jmp L_Re_normalise
+
+LCheck_truncate_64:
+ orl %edx,%edx
+ jz L_Re_normalise
+
+LTruncate_64:
+ movb LOST_DOWN,FPU_bits_lost
+
+L_Re_normalise:
+ testb $0xff,FPU_denormal
+ jnz Normalise_result
+
+L_Normalised:
+ movl TAG_Valid,%edx
+
+L_deNormalised:
+ cmpb LOST_UP,FPU_bits_lost
+ je L_precision_lost_up
+
+ cmpb LOST_DOWN,FPU_bits_lost
+ je L_precision_lost_down
+
+L_no_precision_loss:
+ /* store the result */
+
+L_Store_significand:
+ movl %eax,SIGH(%edi)
+ movl %ebx,SIGL(%edi)
+
+ cmpw EXP_OVER,EXP(%edi)
+ jge L_overflow
+
+ movl %edx,%eax
+
+ /* Convert the exponent to 80x87 form. */
+ addw EXTENDED_Ebias,EXP(%edi)
+ andw $0x7fff,EXP(%edi)
+
+fpu_reg_round_signed_special_exit:
+
+ cmpb SIGN_POS,PARAM5
+ je fpu_reg_round_special_exit
+
+ orw $0x8000,EXP(%edi) /* Negative sign for the result. */
+
+fpu_reg_round_special_exit:
+
+#ifndef NON_REENTRANT_FPU
+ popl %ebx /* adjust the stack pointer */
+#endif /* NON_REENTRANT_FPU */
+
+fpu_Arith_exit:
+ popl %ebx
+ popl %edi
+ popl %esi
+ leave
+ ret
+
+
+/*
+ * Set the FPU status flags to represent precision loss due to
+ * round-up.
+ */
+L_precision_lost_up:
+ push %edx
+ push %eax
+ call SYMBOL_NAME(set_precision_flag_up)
+ popl %eax
+ popl %edx
+ jmp L_no_precision_loss
+
+/*
+ * Set the FPU status flags to represent precision loss due to
+ * truncation.
+ */
+L_precision_lost_down:
+ push %edx
+ push %eax
+ call SYMBOL_NAME(set_precision_flag_down)
+ popl %eax
+ popl %edx
+ jmp L_no_precision_loss
+
+
+/*
+ * The number is a denormal (which might get rounded up to a normal)
+ * Shift the number right the required number of bits, which will
+ * have to be undone later...
+ */
+L_Make_denorm:
+ /* The action to be taken depends upon whether the underflow
+ exception is masked */
+ testb CW_Underflow,%cl /* Underflow mask. */
+ jz Unmasked_underflow /* Do not make a denormal. */
+
+ movb DENORMAL,FPU_denormal
+
+ pushl %ecx /* Save */
+ movw EXP_UNDER+1,%cx
+ subw EXP(%edi),%cx
+
+ cmpw $64,%cx /* shrd only works for 0..31 bits */
+ jnc Denorm_shift_more_than_63
+
+ cmpw $32,%cx /* shrd only works for 0..31 bits */
+ jnc Denorm_shift_more_than_32
+
+/*
+ * We got here without jumps by assuming that the most common requirement
+ * is for a small de-normalising shift.
+ * Shift by [1..31] bits
+ */
+ addw %cx,EXP(%edi)
+ orl %edx,%edx /* extension */
+ setne %ch /* Save whether %edx is non-zero */
+ xorl %edx,%edx
+ shrd %cl,%ebx,%edx
+ shrd %cl,%eax,%ebx
+ shr %cl,%eax
+ orb %ch,%dl
+ popl %ecx
+ jmp Denorm_done
+
+/* Shift by [32..63] bits */
+Denorm_shift_more_than_32:
+ addw %cx,EXP(%edi)
+ subb $32,%cl
+ orl %edx,%edx
+ setne %ch
+ orb %ch,%bl
+ xorl %edx,%edx
+ shrd %cl,%ebx,%edx
+ shrd %cl,%eax,%ebx
+ shr %cl,%eax
+ orl %edx,%edx /* test these 32 bits */
+ setne %cl
+ orb %ch,%bl
+ orb %cl,%bl
+ movl %ebx,%edx
+ movl %eax,%ebx
+ xorl %eax,%eax
+ popl %ecx
+ jmp Denorm_done
+
+/* Shift by [64..) bits */
+Denorm_shift_more_than_63:
+ cmpw $64,%cx
+ jne Denorm_shift_more_than_64
+
+/* Exactly 64 bit shift */
+ addw %cx,EXP(%edi)
+ xorl %ecx,%ecx
+ orl %edx,%edx
+ setne %cl
+ orl %ebx,%ebx
+ setne %ch
+ orb %ch,%cl
+ orb %cl,%al
+ movl %eax,%edx
+ xorl %eax,%eax
+ xorl %ebx,%ebx
+ popl %ecx
+ jmp Denorm_done
+
+Denorm_shift_more_than_64:
+ movw EXP_UNDER+1,EXP(%edi)
+/* This is easy, %eax must be non-zero, so.. */
+ movl $1,%edx
+ xorl %eax,%eax
+ xorl %ebx,%ebx
+ popl %ecx
+ jmp Denorm_done
+
+
+Unmasked_underflow:
+ movb UNMASKED_UNDERFLOW,FPU_denormal
+ jmp Denorm_done
+
+
+/* Undo the de-normalisation. */
+Normalise_result:
+ cmpb UNMASKED_UNDERFLOW,FPU_denormal
+ je Signal_underflow
+
+/* The number must be a denormal if we got here. */
+#ifdef PARANOID
+ /* But check it... just in case. */
+ cmpw EXP_UNDER+1,EXP(%edi)
+ jne L_norm_bugged
+#endif /* PARANOID */
+
+#ifdef PECULIAR_486
+ /*
+ * This implements a special feature of 80486 behaviour.
+ * Underflow will be signalled even if the number is
+ * not a denormal after rounding.
+ * This difference occurs only for masked underflow, and not
+ * in the unmasked case.
+ * Actual 80486 behaviour differs from this in some circumstances.
+ */
+ orl %eax,%eax /* ms bits */
+ js LPseudoDenormal /* Will be masked underflow */
+#else
+ orl %eax,%eax /* ms bits */
+ js L_Normalised /* No longer a denormal */
+#endif /* PECULIAR_486 */
+
+ jnz LDenormal_adj_exponent
+
+ orl %ebx,%ebx
+ jz L_underflow_to_zero /* The contents are zero */
+
+LDenormal_adj_exponent:
+ decw EXP(%edi)
+
+LPseudoDenormal:
+ testb $0xff,FPU_bits_lost /* bits lost == underflow */
+ movl TAG_Special,%edx
+ jz L_deNormalised
+
+ /* There must be a masked underflow */
+ push %eax
+ pushl EX_Underflow
+ call EXCEPTION
+ popl %eax
+ popl %eax
+ movl TAG_Special,%edx
+ jmp L_deNormalised
+
+
+/*
+ * The operations resulted in a number too small to represent.
+ * Masked response.
+ */
+L_underflow_to_zero:
+ push %eax
+ call SYMBOL_NAME(set_precision_flag_down)
+ popl %eax
+
+ push %eax
+ pushl EX_Underflow
+ call EXCEPTION
+ popl %eax
+ popl %eax
+
+/* Reduce the exponent to EXP_UNDER */
+ movw EXP_UNDER,EXP(%edi)
+ movl TAG_Zero,%edx
+ jmp L_Store_significand
+
+
+/* The operations resulted in a number too large to represent. */
+L_overflow:
+ pushw PARAM5
+ addw EXTENDED_Ebias,EXP(%edi) /* Set for unmasked response. */
+ push %edi
+ call SYMBOL_NAME(arith_round_overflow)
+ pop %edi
+ jmp fpu_reg_round_signed_special_exit
+
+
+Signal_underflow:
+ /* The number may have been changed to a non-denormal */
+ /* by the rounding operations. */
+ cmpw EXP_UNDER,EXP(%edi)
+ jle Do_unmasked_underflow
+
+ jmp L_Normalised
+
+Do_unmasked_underflow:
+ /* Increase the exponent by the magic number */
+ addw $(3*(1<<13)),EXP(%edi)
+ push %eax
+ pushl EX_Underflow
+ call EXCEPTION
+ popl %eax
+ popl %eax
+ jmp L_Normalised
+
+
+#ifdef PARANOID
+#ifdef PECULIAR_486
+L_bugged_denorm_486:
+ pushl EX_INTERNAL|0x236
+ call EXCEPTION
+ popl %ebx
+ jmp L_exception_exit
+#else
+L_bugged_denorm:
+ pushl EX_INTERNAL|0x230
+ call EXCEPTION
+ popl %ebx
+ jmp L_exception_exit
+#endif /* PECULIAR_486 */
+
+L_bugged_round24:
+ pushl EX_INTERNAL|0x231
+ call EXCEPTION
+ popl %ebx
+ jmp L_exception_exit
+
+L_bugged_round53:
+ pushl EX_INTERNAL|0x232
+ call EXCEPTION
+ popl %ebx
+ jmp L_exception_exit
+
+L_bugged_round64:
+ pushl EX_INTERNAL|0x233
+ call EXCEPTION
+ popl %ebx
+ jmp L_exception_exit
+
+L_norm_bugged:
+ pushl EX_INTERNAL|0x234
+ call EXCEPTION
+ popl %ebx
+ jmp L_exception_exit
+
+L_entry_bugged:
+ pushl EX_INTERNAL|0x235
+ call EXCEPTION
+ popl %ebx
+L_exception_exit:
+ mov $-1,%eax
+ jmp fpu_reg_round_special_exit
+#endif /* PARANOID */
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | reg_round.c |
+ | |
+ | Rounding/truncation/etc for FPU basic arithmetic functions. |
+ | |
+ | Copyright (C) 1993,1995,1997,1999 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@melbpc.org.au |
+ | |
+ | This code has four possible entry points. |
+ | The following must be entered by a jmp instruction: |
+ | fpu_reg_round, fpu_reg_round_sqrt, and fpu_Arith_exit. |
+ | |
+ | The FPU_round entry point is intended to be used by C code. |
+ | |
+ | Return value is the tag of the answer, or-ed with FPU_Exception if |
+ | one was raised, or -1 on internal error. |
+ | |
+ | For correct "up" and "down" rounding, the argument must have the correct |
+ | sign. |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | |
+ | The significand and its extension are assumed to be exact in the |
+ | following sense: |
+ | If the significand by itself is the exact result then the significand |
+ | extension (%edx) must contain 0, otherwise the significand extension |
+ | must be non-zero. |
+ | If the significand extension is non-zero then the significand is |
+ | smaller than the magnitude of the correct exact result by an amount |
+ | greater than zero and less than one ls bit of the significand. |
+ | The significand extension is only required to have three possible |
+ | non-zero values: |
+ | less than 0x80000000 <=> the significand is less than 1/2 an ls |
+ | bit smaller than the magnitude of the |
+ | true exact result. |
+ | exactly 0x80000000 <=> the significand is exactly 1/2 an ls bit |
+ | smaller than the magnitude of the true |
+ | exact result. |
+ | greater than 0x80000000 <=> the significand is more than 1/2 an ls |
+ | bit smaller than the magnitude of the |
+ | true exact result. |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | The code in this module has become quite complex, but it should handle |
+ | all of the FPU flags which are set at this stage of the basic arithmetic |
+ | computations. |
+ | There are a few rare cases where the results are not set identically to |
+ | a real FPU. These require a bit more thought because at this stage the |
+ | results of the code here appear to be more consistent... |
+ | This may be changed in a future version. |
+ +---------------------------------------------------------------------------*/
+
+
+#include "fpu_emu.h"
+#include "exception.h"
+#include "control_w.h"
+
+/* Flags for FPU_bits_lost */
+#define LOST_DOWN 1
+#define LOST_UP 2
+
+/* Flags for FPU_denormal */
+#define DENORMAL 1
+#define UNMASKED_UNDERFLOW 2
+
+
+int round_up_64(FPU_REG *x, u32 extent)
+{
+ x->sigl ++;
+ if ( x->sigl == 0 )
+ {
+ x->sigh ++;
+ if ( x->sigh == 0 )
+ {
+ x->sigh = 0x80000000;
+ x->exp ++;
+ }
+ }
+ return LOST_UP;
+}
+
+
+int truncate_64(FPU_REG *x, u32 extent)
+{
+ return LOST_DOWN;
+}
+
+
+int round_up_53(FPU_REG *x, u32 extent)
+{
+ x->sigl &= 0xfffff800;
+ x->sigl += 0x800;
+ if ( x->sigl == 0 )
+ {
+ x->sigh ++;
+ if ( x->sigh == 0 )
+ {
+ x->sigh = 0x80000000;
+ x->exp ++;
+ }
+ }
+ return LOST_UP;
+}
+
+
+int truncate_53(FPU_REG *x, u32 extent)
+{
+ x->sigl &= 0xfffff800;
+ return LOST_DOWN;
+}
+
+
+int round_up_24(FPU_REG *x, u32 extent)
+{
+ x->sigl = 0;
+ x->sigh &= 0xffffff00;
+ x->sigh += 0x100;
+ if ( x->sigh == 0 )
+ {
+ x->sigh = 0x80000000;
+ x->exp ++;
+ }
+ return LOST_UP;
+}
+
+
+int truncate_24(FPU_REG *x, u32 extent)
+{
+ x->sigl = 0;
+ x->sigh &= 0xffffff00;
+ return LOST_DOWN;
+}
+
+
+int FPU_round(FPU_REG *x, u32 extent, int dummy, u16 control_w, u8 sign)
+{
+ u64 work;
+ u32 leading;
+ s16 expon = x->exp;
+ int FPU_bits_lost = 0, FPU_denormal, shift, tag;
+
+ if ( expon <= EXP_UNDER )
+ {
+ /* A denormal or zero */
+ if ( control_w & CW_Underflow )
+ {
+ /* Underflow is masked. */
+ FPU_denormal = DENORMAL;
+ shift = EXP_UNDER+1 - expon;
+ if ( shift >= 64 )
+ {
+ if ( shift == 64 )
+ {
+ x->exp += 64;
+ if ( extent | x->sigl )
+ extent = x->sigh | 1;
+ else
+ extent = x->sigh;
+ }
+ else
+ {
+ x->exp = EXP_UNDER+1;
+ extent = 1;
+ }
+ significand(x) = 0;
+ }
+ else
+ {
+ x->exp += shift;
+ if ( shift >= 32 )
+ {
+ shift -= 32;
+ if ( shift )
+ {
+ extent |= x->sigl;
+ work = significand(x) >> shift;
+ if ( extent )
+ extent = work | 1;
+ else
+ extent = work;
+ x->sigl = x->sigh >>= shift;
+ }
+ else
+ {
+ if ( extent )
+ extent = x->sigl | 1;
+ else
+ extent = x->sigl;
+ x->sigl = x->sigh;
+ }
+ x->sigh = 0;
+ }
+ else
+ {
+ /* Shift by 1 to 32 places. */
+ work = x->sigl;
+ work <<= 32;
+ work |= extent;
+ work >>= shift;
+ if ( extent )
+ extent = 1;
+ extent |= work;
+ significand(x) >>= shift;
+ }
+ }
+ }
+ else
+ {
+ /* Unmasked underflow. */
+ FPU_denormal = UNMASKED_UNDERFLOW;
+ }
+ }
+ else
+ FPU_denormal = 0;
+
+ switch ( control_w & CW_PC )
+ {
+ case 01:
+#ifndef PECULIAR_486
+ /* With the precision control bits set to 01 "(reserved)", a real 80486
+ behaves as if the precision control bits were set to 11 "64 bits" */
+#ifdef PARANOID
+ EXCEPTION(EX_INTERNAL|0x236);
+ return -1;
+#endif
+#endif
+ /* Fall through to the 64 bit case. */
+ case PR_64_BITS:
+ if ( extent )
+ {
+ switch ( control_w & CW_RC )
+ {
+ case RC_RND: /* Nearest or even */
+ /* See if there is exactly half a ulp. */
+ if ( extent == 0x80000000 )
+ {
+ /* Round to even. */
+ if ( x->sigl & 0x1 )
+ /* Odd */
+ FPU_bits_lost = round_up_64(x, extent);
+ else
+ /* Even */
+ FPU_bits_lost = truncate_64(x, extent);
+ }
+ else if ( extent > 0x80000000 )
+ {
+ /* Greater than half */
+ FPU_bits_lost = round_up_64(x, extent);
+ }
+ else
+ {
+ /* Less than half */
+ FPU_bits_lost = truncate_64(x, extent);
+ }
+ break;
+
+ case RC_CHOP: /* Truncate */
+ FPU_bits_lost = truncate_64(x, extent);
+ break;
+
+ case RC_UP: /* Towards +infinity */
+ if ( sign == SIGN_POS)
+ {
+ FPU_bits_lost = round_up_64(x, extent);
+ }
+ else
+ {
+ FPU_bits_lost = truncate_64(x, extent);
+ }
+ break;
+
+ case RC_DOWN: /* Towards -infinity */
+ if ( sign != SIGN_POS)
+ {
+ FPU_bits_lost = round_up_64(x, extent);
+ }
+ else
+ {
+ FPU_bits_lost = truncate_64(x, extent);
+ }
+ break;
+
+ default:
+ EXCEPTION(EX_INTERNAL|0x231);
+ return -1;
+ }
+ }
+ break;
+
+ case PR_53_BITS:
+ leading = x->sigl & 0x7ff;
+ if ( extent || leading )
+ {
+ switch ( control_w & CW_RC )
+ {
+ case RC_RND: /* Nearest or even */
+ /* See if there is exactly half a ulp. */
+ if ( leading == 0x400 )
+ {
+ if ( extent == 0 )
+ {
+ /* Round to even. */
+ if ( x->sigl & 0x800 )
+ /* Odd */
+ FPU_bits_lost = round_up_53(x, extent);
+ else
+ /* Even */
+ FPU_bits_lost = truncate_53(x, extent);
+ }
+ else
+ {
+ /* Greater than half */
+ FPU_bits_lost = round_up_53(x, extent);
+ }
+ }
+ else if ( leading > 0x400 )
+ {
+ /* Greater than half */
+ FPU_bits_lost = round_up_53(x, extent);
+ }
+ else
+ {
+ /* Less than half */
+ FPU_bits_lost = truncate_53(x, extent);
+ }
+ break;
+
+ case RC_CHOP: /* Truncate */
+ FPU_bits_lost = truncate_53(x, extent);
+ break;
+
+ case RC_UP: /* Towards +infinity */
+ if ( sign == SIGN_POS)
+ {
+ FPU_bits_lost = round_up_53(x, extent);
+ }
+ else
+ {
+ FPU_bits_lost = truncate_53(x, extent);
+ }
+ break;
+
+ case RC_DOWN: /* Towards -infinity */
+ if ( sign != SIGN_POS)
+ {
+ FPU_bits_lost = round_up_53(x, extent);
+ }
+ else
+ {
+ FPU_bits_lost = truncate_53(x, extent);
+ }
+ break;
+
+ default:
+ EXCEPTION(EX_INTERNAL|0x231);
+ return -1;
+ }
+ }
+ break;
+
+ case PR_24_BITS:
+ leading = x->sigh & 0xff;
+ if ( leading || x->sigl || extent )
+ {
+ switch ( control_w & CW_RC )
+ {
+ case RC_RND: /* Nearest or even */
+ /* See if there is exactly half a ulp. */
+ if ( leading == 0x80 )
+ {
+ if ( (x->sigl == 0) && (extent == 0) )
+ {
+ /* Round to even. */
+ if ( x->sigh & 0x100 )
+ /* Odd */
+ FPU_bits_lost = round_up_24(x, extent);
+ else
+ /* Even */
+ FPU_bits_lost = truncate_24(x, extent);
+ }
+ else
+ {
+ /* Greater than half */
+ FPU_bits_lost = round_up_24(x, extent);
+ }
+ }
+ else if ( leading > 0x80 )
+ {
+ /* Greater than half */
+ FPU_bits_lost = round_up_24(x, extent);
+ }
+ else
+ {
+ /* Less than half */
+ FPU_bits_lost = truncate_24(x, extent);
+ }
+ break;
+
+ case RC_CHOP: /* Truncate */
+ FPU_bits_lost = truncate_24(x, extent);
+ break;
+
+ case RC_UP: /* Towards +infinity */
+ if ( sign == SIGN_POS)
+ {
+ FPU_bits_lost = round_up_24(x, extent);
+ }
+ else
+ {
+ FPU_bits_lost = truncate_24(x, extent);
+ }
+ break;
+
+ case RC_DOWN: /* Towards -infinity */
+ if ( sign != SIGN_POS)
+ {
+ FPU_bits_lost = round_up_24(x, extent);
+ }
+ else
+ {
+ FPU_bits_lost = truncate_24(x, extent);
+ }
+ break;
+
+ default:
+ EXCEPTION(EX_INTERNAL|0x231);
+ return -1;
+ }
+ }
+ break;
+
+ default:
+#ifdef PARANOID
+ EXCEPTION(EX_INTERNAL|0x230);
+ return -1;
+#endif
+ break;
+ }
+
+ tag = TAG_Valid;
+
+ if ( FPU_denormal )
+ {
+ /* Undo the de-normalisation. */
+ if ( FPU_denormal == UNMASKED_UNDERFLOW )
+ {
+ if ( x->exp <= EXP_UNDER )
+ {
+ /* Increase the exponent by the magic number */
+ x->exp += 3 * (1 << 13);
+ EXCEPTION(EX_Underflow);
+ }
+ }
+ else
+ {
+ if ( x->exp != EXP_UNDER+1 )
+ {
+ EXCEPTION(EX_INTERNAL|0x234);
+ }
+ if ( (x->sigh == 0) && (x->sigl == 0) )
+ {
+ /* Underflow to zero */
+ set_precision_flag_down();
+ EXCEPTION(EX_Underflow);
+ x->exp = EXP_UNDER;
+ tag = TAG_Zero;
+ FPU_bits_lost = 0; /* Stop another call to
+ set_precision_flag_down() */
+ }
+ else
+ {
+ if ( x->sigh & 0x80000000 )
+ {
+#ifdef PECULIAR_486
+ /*
+ * This implements a special feature of 80486 behaviour.
+ * Underflow will be signalled even if the number is
+ * not a denormal after rounding.
+ * This difference occurs only for masked underflow, and not
+ * in the unmasked case.
+ * Actual 80486 behaviour differs from this in some circumstances.
+ */
+ /* Will be masked underflow */
+#else
+ /* No longer a denormal */
+#endif
+ }
+ else
+#ifndef PECULIAR_486
+ {
+#endif
+ x->exp --;
+
+ if ( FPU_bits_lost )
+ {
+ /* There must be a masked underflow */
+ EXCEPTION(EX_Underflow);
+ }
+
+ tag = TAG_Special;
+#ifndef PECULIAR_486
+ }
+#endif
+ }
+ }
+ }
+
+
+ if ( FPU_bits_lost == LOST_UP )
+ set_precision_flag_up();
+ else if ( FPU_bits_lost == LOST_DOWN )
+ set_precision_flag_down();
+
+ if ( x->exp >= EXP_OVER )
+ {
+ x->exp += EXTENDED_Ebias;
+ tag = arith_round_overflow(x, sign);
+ }
+ else
+ {
+ x->exp += EXTENDED_Ebias;
+ x->exp &= 0x7fff;
+ }
+
+ if ( sign != SIGN_POS )
+ x->exp |= 0x8000;
+
+ return tag;
+
+}
+
+
+
--- /dev/null
+ .file "reg_u_add.S"
+/*---------------------------------------------------------------------------+
+ | reg_u_add.S |
+ | |
+ | Add two valid (TAG_Valid) FPU_REG numbers, of the same sign, and put the |
+ | result in a destination FPU_REG. |
+ | |
+ | Copyright (C) 1992,1993,1995,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
+ | |
+ | Call from C as: |
+ | int FPU_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, |
+ | int control_w) |
+ | Return value is the tag of the answer, or-ed with FPU_Exception if |
+ | one was raised, or -1 on internal error. |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*
+ | Kernel addition routine FPU_u_add(reg *arg1, reg *arg2, reg *answ).
+ | Takes two valid reg f.p. numbers (TAG_Valid), which are
+ | treated as unsigned numbers,
+ | and returns their sum as a TAG_Valid or TAG_Special f.p. number.
+ | The returned number is normalized.
+ | Basic checks are performed if PARANOID is defined.
+ */
+
+#include "exception.h"
+#include "fpu_emu.h"
+#include "control_w.h"
+
+.text
+ENTRY(FPU_u_add)
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi /* source 1 */
+ movl PARAM2,%edi /* source 2 */
+
+ movl PARAM6,%ecx
+ movl %ecx,%edx
+ subl PARAM7,%ecx /* exp1 - exp2 */
+ jge L_arg1_larger
+
+ /* num1 is smaller */
+ movl SIGL(%esi),%ebx
+ movl SIGH(%esi),%eax
+
+ movl %edi,%esi
+ movl PARAM7,%edx
+ negw %cx
+ jmp L_accum_loaded
+
+L_arg1_larger:
+ /* num1 has larger or equal exponent */
+ movl SIGL(%edi),%ebx
+ movl SIGH(%edi),%eax
+
+L_accum_loaded:
+ movl PARAM3,%edi /* destination */
+ movw %dx,EXP(%edi) /* Copy exponent to destination */
+
+ xorl %edx,%edx /* clear the extension */
+
+#ifdef PARANOID
+ testl $0x80000000,%eax
+ je L_bugged
+
+ testl $0x80000000,SIGH(%esi)
+ je L_bugged
+#endif /* PARANOID */
+
+/* The number to be shifted is in %eax:%ebx:%edx */
+ cmpw $32,%cx /* shrd only works for 0..31 bits */
+ jnc L_more_than_31
+
+/* less than 32 bits */
+ shrd %cl,%ebx,%edx
+ shrd %cl,%eax,%ebx
+ shr %cl,%eax
+ jmp L_shift_done
+
+L_more_than_31:
+ cmpw $64,%cx
+ jnc L_more_than_63
+
+ subb $32,%cl
+ jz L_exactly_32
+
+ shrd %cl,%eax,%edx
+ shr %cl,%eax
+ orl %ebx,%ebx
+ jz L_more_31_no_low /* none of the lowest bits is set */
+
+ orl $1,%edx /* record the fact in the extension */
+
+L_more_31_no_low:
+ movl %eax,%ebx
+ xorl %eax,%eax
+ jmp L_shift_done
+
+L_exactly_32:
+ movl %ebx,%edx
+ movl %eax,%ebx
+ xorl %eax,%eax
+ jmp L_shift_done
+
+L_more_than_63:
+ cmpw $65,%cx
+ jnc L_more_than_64
+
+ movl %eax,%edx
+ orl %ebx,%ebx
+ jz L_more_63_no_low
+
+ orl $1,%edx
+ jmp L_more_63_no_low
+
+L_more_than_64:
+ movl $1,%edx /* The shifted nr always at least one '1' */
+
+L_more_63_no_low:
+ xorl %ebx,%ebx
+ xorl %eax,%eax
+
+L_shift_done:
+ /* Now do the addition */
+ addl SIGL(%esi),%ebx
+ adcl SIGH(%esi),%eax
+ jnc L_round_the_result
+
+ /* Overflow, adjust the result */
+ rcrl $1,%eax
+ rcrl $1,%ebx
+ rcrl $1,%edx
+ jnc L_no_bit_lost
+
+ orl $1,%edx
+
+L_no_bit_lost:
+ incw EXP(%edi)
+
+L_round_the_result:
+ jmp fpu_reg_round /* Round the result */
+
+
+
+#ifdef PARANOID
+/* If we ever get here then we have problems! */
+L_bugged:
+ pushl EX_INTERNAL|0x201
+ call EXCEPTION
+ pop %ebx
+ movl $-1,%eax
+ jmp L_exit
+
+L_exit:
+ popl %ebx
+ popl %edi
+ popl %esi
+ leave
+ ret
+#endif /* PARANOID */
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | reg_u_add.c |
+ | |
+ | Add two valid (TAG_Valid) FPU_REG numbers, of the same sign, and put the |
+ | result in a destination FPU_REG. |
+ | |
+ | Copyright (C) 1992,1993,1995,1997,1999 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@melbpc.org.au |
+ | |
+ | Return value is the tag of the answer, or-ed with FPU_Exception if |
+ | one was raised, or -1 on internal error. |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*
+ | Kernel addition routine FPU_u_add(reg *arg1, reg *arg2, reg *answ).
+ | Takes two valid reg f.p. numbers (TAG_Valid), which are
+ | treated as unsigned numbers,
+ | and returns their sum as a TAG_Valid or TAG_Special f.p. number.
+ | The returned number is normalized.
+ | Basic checks are performed if PARANOID is defined.
+ */
+
+#include "exception.h"
+#include "fpu_emu.h"
+#include "control_w.h"
+
+
+int FPU_u_add(const FPU_REG *arg1, const FPU_REG *arg2, FPU_REG *answ,
+ u16 control_w, u_char sign, s32 expa, s32 expb)
+{
+ const FPU_REG *rtmp;
+ FPU_REG shifted;
+ u32 extent = 0;
+ int ediff = expa - expb, ed2, eflag, ovfl, carry;
+
+ if ( ediff < 0 )
+ {
+ ediff = -ediff;
+ rtmp = arg1;
+ arg1 = arg2;
+ arg2 = rtmp;
+ expa = expb;
+ }
+
+ /* Now we have exponent of arg1 >= exponent of arg2 */
+
+ answ->exp = expa;
+
+#ifdef PARANOID
+ if ( !(arg1->sigh & 0x80000000) || !(arg2->sigh & 0x80000000) )
+ {
+ EXCEPTION(EX_INTERNAL|0x201);
+ return -1;
+ }
+#endif
+
+ if ( ediff == 0 )
+ {
+ extent = 0;
+ shifted.sigl = arg2->sigl;
+ shifted.sigh = arg2->sigh;
+ }
+ else if ( ediff < 32 )
+ {
+ ed2 = 32 - ediff;
+ extent = arg2->sigl << ed2;
+ shifted.sigl = arg2->sigl >> ediff;
+ shifted.sigl |= (arg2->sigh << ed2);
+ shifted.sigh = arg2->sigh >> ediff;
+ }
+ else if ( ediff < 64 )
+ {
+ ediff -= 32;
+ if ( ! ediff )
+ {
+ eflag = 0;
+ extent = arg2->sigl;
+ shifted.sigl = arg2->sigh;
+ }
+ else
+ {
+ ed2 = 32 - ediff;
+ eflag = arg2->sigl;
+ if ( eflag )
+ extent |= 1;
+ extent = arg2->sigl >> ediff;
+ extent |= (arg2->sigh << ed2);
+ shifted.sigl = arg2->sigh >> ediff;
+ }
+ shifted.sigh = 0;
+ }
+ else
+ {
+ ediff -= 64;
+ if ( ! ediff )
+ {
+ eflag = arg2->sigl;
+ extent = arg2->sigh;
+ }
+ else
+ {
+ ed2 = 64 - ediff;
+ eflag = arg2->sigl | arg2->sigh;
+ extent = arg2->sigh >> ediff;
+ }
+ shifted.sigl = 0;
+ shifted.sigh = 0;
+ if ( eflag )
+ extent |= 1;
+ }
+
+ answ->sigh = arg1->sigh + shifted.sigh;
+ ovfl = shifted.sigh > answ->sigh;
+ answ->sigl = arg1->sigl + shifted.sigl;
+ if ( shifted.sigl > answ->sigl )
+ {
+ answ->sigh ++;
+ if ( answ->sigh == 0 )
+ ovfl = 1;
+ }
+ if ( ovfl )
+ {
+ carry = extent & 1;
+ extent >>= 1;
+ extent |= carry;
+ if ( answ->sigl & 1 )
+ extent |= 0x80000000;
+ answ->sigl >>= 1;
+ if ( answ->sigh & 1 )
+ answ->sigl |= 0x80000000;
+ answ->sigh >>= 1;
+ answ->sigh |= 0x80000000;
+ answ->exp ++;
+ }
+
+ return FPU_round(answ, extent, 0, control_w, sign);
+
+}
--- /dev/null
+ .file "reg_u_div.S"
+/*---------------------------------------------------------------------------+
+ | reg_u_div.S |
+ | |
+ | Divide one FPU_REG by another and put the result in a destination FPU_REG.|
+ | |
+ | Copyright (C) 1992,1993,1995,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | Call from C as: |
+ | int FPU_u_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest, |
+ | unsigned int control_word, char *sign) |
+ | |
+ | Does not compute the destination exponent, but does adjust it. |
+ | |
+ | Return value is the tag of the answer, or-ed with FPU_Exception if |
+ | one was raised, or -1 on internal error. |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "fpu_emu.h"
+#include "control_w.h"
+
+
+/* #define dSIGL(x) (x) */
+/* #define dSIGH(x) 4(x) */
+
+
+#ifndef NON_REENTRANT_FPU
+/*
+ Local storage on the stack:
+ Result: FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0
+ Overflow flag: ovfl_flag
+ */
+#define FPU_accum_3 -4(%ebp)
+#define FPU_accum_2 -8(%ebp)
+#define FPU_accum_1 -12(%ebp)
+#define FPU_accum_0 -16(%ebp)
+#define FPU_result_1 -20(%ebp)
+#define FPU_result_2 -24(%ebp)
+#define FPU_ovfl_flag -28(%ebp)
+
+#else
+.data
+/*
+ Local storage in a static area:
+ Result: FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0
+ Overflow flag: ovfl_flag
+ */
+ .align 4,0
+FPU_accum_3:
+ .long 0
+FPU_accum_2:
+ .long 0
+FPU_accum_1:
+ .long 0
+FPU_accum_0:
+ .long 0
+FPU_result_1:
+ .long 0
+FPU_result_2:
+ .long 0
+FPU_ovfl_flag:
+ .byte 0
+#endif /* NON_REENTRANT_FPU */
+
+#define REGA PARAM1
+#define REGB PARAM2
+#define DEST PARAM3
+
+.text
+ENTRY(FPU_u_div)
+ pushl %ebp
+ movl %esp,%ebp
+#ifndef NON_REENTRANT_FPU
+ subl $28,%esp
+#endif /* NON_REENTRANT_FPU */
+
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl REGA,%esi
+ movl REGB,%ebx
+ movl DEST,%edi
+
+ movw EXP(%esi),%dx
+ movw EXP(%ebx),%ax
+ .byte 0x0f,0xbf,0xc0 /* movsx %ax,%eax */
+ .byte 0x0f,0xbf,0xd2 /* movsx %dx,%edx */
+ subl %eax,%edx
+ addl EXP_BIAS,%edx
+
+ /* A denormal and a large number can cause an exponent underflow */
+ cmpl EXP_WAY_UNDER,%edx
+ jg xExp_not_underflow
+
+ /* Set to a really low value allow correct handling */
+ movl EXP_WAY_UNDER,%edx
+
+xExp_not_underflow:
+
+ movw %dx,EXP(%edi)
+
+#ifdef PARANOID
+/* testl $0x80000000, SIGH(%esi) // Dividend */
+/* je L_bugged */
+ testl $0x80000000, SIGH(%ebx) /* Divisor */
+ je L_bugged
+#endif /* PARANOID */
+
+/* Check if the divisor can be treated as having just 32 bits */
+ cmpl $0,SIGL(%ebx)
+ jnz L_Full_Division /* Can't do a quick divide */
+
+/* We should be able to zip through the division here */
+ movl SIGH(%ebx),%ecx /* The divisor */
+ movl SIGH(%esi),%edx /* Dividend */
+ movl SIGL(%esi),%eax /* Dividend */
+
+ cmpl %ecx,%edx
+ setaeb FPU_ovfl_flag /* Keep a record */
+ jb L_no_adjust
+
+ subl %ecx,%edx /* Prevent the overflow */
+
+L_no_adjust:
+ /* Divide the 64 bit number by the 32 bit denominator */
+ divl %ecx
+ movl %eax,FPU_result_2
+
+ /* Work on the remainder of the first division */
+ xorl %eax,%eax
+ divl %ecx
+ movl %eax,FPU_result_1
+
+ /* Work on the remainder of the 64 bit division */
+ xorl %eax,%eax
+ divl %ecx
+
+ testb $255,FPU_ovfl_flag /* was the num > denom ? */
+ je L_no_overflow
+
+ /* Do the shifting here */
+ /* increase the exponent */
+ incw EXP(%edi)
+
+ /* shift the mantissa right one bit */
+ stc /* To set the ms bit */
+ rcrl FPU_result_2
+ rcrl FPU_result_1
+ rcrl %eax
+
+L_no_overflow:
+ jmp LRound_precision /* Do the rounding as required */
+
+
+/*---------------------------------------------------------------------------+
+ | Divide: Return arg1/arg2 to arg3. |
+ | |
+ | This routine does not use the exponents of arg1 and arg2, but does |
+ | adjust the exponent of arg3. |
+ | |
+ | The maximum returned value is (ignoring exponents) |
+ | .ffffffff ffffffff |
+ | ------------------ = 1.ffffffff fffffffe |
+ | .80000000 00000000 |
+ | and the minimum is |
+ | .80000000 00000000 |
+ | ------------------ = .80000000 00000001 (rounded) |
+ | .ffffffff ffffffff |
+ | |
+ +---------------------------------------------------------------------------*/
+
+
+L_Full_Division:
+ /* Save extended dividend in local register */
+ movl SIGL(%esi),%eax
+ movl %eax,FPU_accum_2
+ movl SIGH(%esi),%eax
+ movl %eax,FPU_accum_3
+ xorl %eax,%eax
+ movl %eax,FPU_accum_1 /* zero the extension */
+ movl %eax,FPU_accum_0 /* zero the extension */
+
+ movl SIGL(%esi),%eax /* Get the current num */
+ movl SIGH(%esi),%edx
+
+/*----------------------------------------------------------------------*/
+/* Initialization done.
+ Do the first 32 bits. */
+
+ movb $0,FPU_ovfl_flag
+ cmpl SIGH(%ebx),%edx /* Test for imminent overflow */
+ jb LLess_than_1
+ ja LGreater_than_1
+
+ cmpl SIGL(%ebx),%eax
+ jb LLess_than_1
+
+LGreater_than_1:
+/* The dividend is greater or equal, would cause overflow */
+ setaeb FPU_ovfl_flag /* Keep a record */
+
+ subl SIGL(%ebx),%eax
+ sbbl SIGH(%ebx),%edx /* Prevent the overflow */
+ movl %eax,FPU_accum_2
+ movl %edx,FPU_accum_3
+
+LLess_than_1:
+/* At this point, we have a dividend < divisor, with a record of
+ adjustment in FPU_ovfl_flag */
+
+ /* We will divide by a number which is too large */
+ movl SIGH(%ebx),%ecx
+ addl $1,%ecx
+ jnc LFirst_div_not_1
+
+ /* here we need to divide by 100000000h,
+ i.e., no division at all.. */
+ mov %edx,%eax
+ jmp LFirst_div_done
+
+LFirst_div_not_1:
+ divl %ecx /* Divide the numerator by the augmented
+ denom ms dw */
+
+LFirst_div_done:
+ movl %eax,FPU_result_2 /* Put the result in the answer */
+
+ mull SIGH(%ebx) /* mul by the ms dw of the denom */
+
+ subl %eax,FPU_accum_2 /* Subtract from the num local reg */
+ sbbl %edx,FPU_accum_3
+
+ movl FPU_result_2,%eax /* Get the result back */
+ mull SIGL(%ebx) /* now mul the ls dw of the denom */
+
+ subl %eax,FPU_accum_1 /* Subtract from the num local reg */
+ sbbl %edx,FPU_accum_2
+ sbbl $0,FPU_accum_3
+ je LDo_2nd_32_bits /* Must check for non-zero result here */
+
+#ifdef PARANOID
+ jb L_bugged_1
+#endif /* PARANOID */
+
+ /* need to subtract another once of the denom */
+ incl FPU_result_2 /* Correct the answer */
+
+ movl SIGL(%ebx),%eax
+ movl SIGH(%ebx),%edx
+ subl %eax,FPU_accum_1 /* Subtract from the num local reg */
+ sbbl %edx,FPU_accum_2
+
+#ifdef PARANOID
+ sbbl $0,FPU_accum_3
+ jne L_bugged_1 /* Must check for non-zero result here */
+#endif /* PARANOID */
+
+/*----------------------------------------------------------------------*/
+/* Half of the main problem is done, there is just a reduced numerator
+ to handle now.
+ Work with the second 32 bits, FPU_accum_0 not used from now on */
+LDo_2nd_32_bits:
+ movl FPU_accum_2,%edx /* get the reduced num */
+ movl FPU_accum_1,%eax
+
+ /* need to check for possible subsequent overflow */
+ cmpl SIGH(%ebx),%edx
+ jb LDo_2nd_div
+ ja LPrevent_2nd_overflow
+
+ cmpl SIGL(%ebx),%eax
+ jb LDo_2nd_div
+
+LPrevent_2nd_overflow:
+/* The numerator is greater or equal, would cause overflow */
+ /* prevent overflow */
+ subl SIGL(%ebx),%eax
+ sbbl SIGH(%ebx),%edx
+ movl %edx,FPU_accum_2
+ movl %eax,FPU_accum_1
+
+ incl FPU_result_2 /* Reflect the subtraction in the answer */
+
+#ifdef PARANOID
+ je L_bugged_2 /* Can't bump the result to 1.0 */
+#endif /* PARANOID */
+
+LDo_2nd_div:
+ cmpl $0,%ecx /* augmented denom msw */
+ jnz LSecond_div_not_1
+
+ /* %ecx == 0, we are dividing by 1.0 */
+ mov %edx,%eax
+ jmp LSecond_div_done
+
+LSecond_div_not_1:
+ divl %ecx /* Divide the numerator by the denom ms dw */
+
+LSecond_div_done:
+ movl %eax,FPU_result_1 /* Put the result in the answer */
+
+ mull SIGH(%ebx) /* mul by the ms dw of the denom */
+
+ subl %eax,FPU_accum_1 /* Subtract from the num local reg */
+ sbbl %edx,FPU_accum_2
+
+#ifdef PARANOID
+ jc L_bugged_2
+#endif /* PARANOID */
+
+ movl FPU_result_1,%eax /* Get the result back */
+ mull SIGL(%ebx) /* now mul the ls dw of the denom */
+
+ subl %eax,FPU_accum_0 /* Subtract from the num local reg */
+ sbbl %edx,FPU_accum_1 /* Subtract from the num local reg */
+ sbbl $0,FPU_accum_2
+
+#ifdef PARANOID
+ jc L_bugged_2
+#endif /* PARANOID */
+
+ jz LDo_3rd_32_bits
+
+#ifdef PARANOID
+ cmpl $1,FPU_accum_2
+ jne L_bugged_2
+#endif /* PARANOID */
+
+ /* need to subtract another once of the denom */
+ movl SIGL(%ebx),%eax
+ movl SIGH(%ebx),%edx
+ subl %eax,FPU_accum_0 /* Subtract from the num local reg */
+ sbbl %edx,FPU_accum_1
+ sbbl $0,FPU_accum_2
+
+#ifdef PARANOID
+ jc L_bugged_2
+ jne L_bugged_2
+#endif /* PARANOID */
+
+ addl $1,FPU_result_1 /* Correct the answer */
+ adcl $0,FPU_result_2
+
+#ifdef PARANOID
+ jc L_bugged_2 /* Must check for non-zero result here */
+#endif /* PARANOID */
+
+/*----------------------------------------------------------------------*/
+/* The division is essentially finished here, we just need to perform
+ tidying operations.
+ Deal with the 3rd 32 bits */
+LDo_3rd_32_bits:
+ movl FPU_accum_1,%edx /* get the reduced num */
+ movl FPU_accum_0,%eax
+
+ /* need to check for possible subsequent overflow */
+ cmpl SIGH(%ebx),%edx /* denom */
+ jb LRound_prep
+ ja LPrevent_3rd_overflow
+
+ cmpl SIGL(%ebx),%eax /* denom */
+ jb LRound_prep
+
+LPrevent_3rd_overflow:
+ /* prevent overflow */
+ subl SIGL(%ebx),%eax
+ sbbl SIGH(%ebx),%edx
+ movl %edx,FPU_accum_1
+ movl %eax,FPU_accum_0
+
+ addl $1,FPU_result_1 /* Reflect the subtraction in the answer */
+ adcl $0,FPU_result_2
+ jne LRound_prep
+ jnc LRound_prep
+
+ /* This is a tricky spot, there is an overflow of the answer */
+ movb $255,FPU_ovfl_flag /* Overflow -> 1.000 */
+
+LRound_prep:
+/*
+ * Prepare for rounding.
+ * To test for rounding, we just need to compare 2*accum with the
+ * denom.
+ */
+ movl FPU_accum_0,%ecx
+ movl FPU_accum_1,%edx
+ movl %ecx,%eax
+ orl %edx,%eax
+ jz LRound_ovfl /* The accumulator contains zero. */
+
+ /* Multiply by 2 */
+ clc
+ rcll $1,%ecx
+ rcll $1,%edx
+ jc LRound_large /* No need to compare, denom smaller */
+
+ subl SIGL(%ebx),%ecx
+ sbbl SIGH(%ebx),%edx
+ jnc LRound_not_small
+
+ movl $0x70000000,%eax /* Denom was larger */
+ jmp LRound_ovfl
+
+LRound_not_small:
+ jnz LRound_large
+
+ movl $0x80000000,%eax /* Remainder was exactly 1/2 denom */
+ jmp LRound_ovfl
+
+LRound_large:
+ movl $0xff000000,%eax /* Denom was smaller */
+
+LRound_ovfl:
+/* We are now ready to deal with rounding, but first we must get
+ the bits properly aligned */
+ testb $255,FPU_ovfl_flag /* was the num > denom ? */
+ je LRound_precision
+
+ incw EXP(%edi)
+
+ /* shift the mantissa right one bit */
+ stc /* Will set the ms bit */
+ rcrl FPU_result_2
+ rcrl FPU_result_1
+ rcrl %eax
+
+/* Round the result as required */
+LRound_precision:
+ decw EXP(%edi) /* binary point between 1st & 2nd bits */
+
+ movl %eax,%edx
+ movl FPU_result_1,%ebx
+ movl FPU_result_2,%eax
+ jmp fpu_reg_round
+
+
+#ifdef PARANOID
+/* The logic is wrong if we got here */
+L_bugged:
+ pushl EX_INTERNAL|0x202
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_bugged_1:
+ pushl EX_INTERNAL|0x203
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_bugged_2:
+ pushl EX_INTERNAL|0x204
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_exit:
+ movl $-1,%eax
+ popl %ebx
+ popl %edi
+ popl %esi
+
+ leave
+ ret
+#endif /* PARANOID */
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | reg_u_div.c |
+ | |
+ | Divide one FPU_REG by another and put the result in a destination FPU_REG.|
+ | |
+ | Copyright (C) 1992,1993,1995,1997,1999 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@melbpc.org.au |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | |
+ | Does not compute the destination exponent, but does adjust it. |
+ | |
+ | Return value is the tag of the answer, or-ed with FPU_Exception if |
+ | one was raised, or -1 on internal error. |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "fpu_emu.h"
+#include "control_w.h"
+#include <asm/types.h>
+
+
+int FPU_u_div(const FPU_REG *a, const FPU_REG *b, FPU_REG *dest,
+ u16 control_w, u8 sign)
+{
+ s32 exp;
+ u32 divr32, rem, rat1, rat2, work32, accum3, prodh;
+ u64 work64, divr64, prod64, accum64;
+ u8 ovfl;
+
+ exp = (s32)a->exp - (s32)b->exp;
+
+ if ( exp < EXP_WAY_UNDER )
+ exp = EXP_WAY_UNDER;
+
+ dest->exp = exp;
+#ifdef PARANOID
+ if ( !(b->sigh & 0x80000000) )
+ {
+ EXCEPTION(EX_INTERNAL|0x202);
+ }
+#endif
+
+ work64 = significand(a);
+
+ /* We can save a lot of time if the divisor has all its lowest
+ 32 bits equal to zero. */
+ if ( b->sigl == 0 )
+ {
+ divr32 = b->sigh;
+ ovfl = a->sigh >= divr32;
+ rat1 = work64 / divr32;
+ rem = work64 % divr32;
+ work64 = rem;
+ work64 <<= 32;
+ rat2 = work64 / divr32;
+ rem = work64 % divr32;
+
+ work64 = rem;
+ work64 <<= 32;
+ rem = work64 / divr32;
+
+ if ( ovfl )
+ {
+ rem >>= 1;
+ if ( rat2 & 1 )
+ rem |= 0x80000000;
+ rat2 >>= 1;
+ if ( rat1 & 1 )
+ rat2 |= 0x80000000;
+ rat1 >>= 1;
+ rat1 |= 0x80000000;
+ dest->exp ++;
+ }
+ dest->sigh = rat1;
+ dest->sigl = rat2;
+
+ dest->exp --;
+ return FPU_round(dest, rem, 0, control_w, sign);
+ }
+
+ /* This may take a little time... */
+
+ accum64 = work64;
+ divr64 = significand(b);
+
+ if ( (ovfl = accum64 >= divr64) )
+ accum64 -= divr64;
+ divr32 = b->sigh+1;
+
+ if ( divr32 != 0 )
+ {
+ rat1 = accum64 / divr32;
+ }
+ else
+ rat1 = accum64 >> 32;
+ prod64 = rat1 * (u64)b->sigh;
+
+ accum64 -= prod64;
+ prod64 = rat1 * (u64)b->sigl;
+ accum3 = prod64;
+ if ( accum3 )
+ {
+ accum3 = -accum3;
+ accum64 --;
+ }
+ prodh = prod64 >> 32;
+ accum64 -= prodh;
+
+ work32 = accum64 >> 32;
+ if ( work32 )
+ {
+#ifdef PARANOID
+ if ( work32 != 1 )
+ {
+ EXCEPTION(EX_INTERNAL|0x203);
+ }
+#endif
+
+ /* Need to subtract the divisor once more. */
+ work32 = accum3;
+ accum3 = work32 - b->sigl;
+ if ( accum3 > work32 )
+ accum64 --;
+ rat1 ++;
+ accum64 -= b->sigh;
+
+#ifdef PARANOID
+ if ( (accum64 >> 32) )
+ {
+ EXCEPTION(EX_INTERNAL|0x203);
+ }
+#endif
+ }
+
+ /* Now we essentially repeat what we have just done, but shifted
+ 32 bits. */
+
+ accum64 <<= 32;
+ accum64 |= accum3;
+ if ( accum64 >= divr64 )
+ {
+ accum64 -= divr64;
+ rat1 ++;
+ }
+ if ( divr32 != 0 )
+ {
+ rat2 = accum64 / divr32;
+ }
+ else
+ rat2 = accum64 >> 32;
+ prod64 = rat2 * (u64)b->sigh;
+
+ accum64 -= prod64;
+ prod64 = rat2 * (u64)b->sigl;
+ accum3 = prod64;
+ if ( accum3 )
+ {
+ accum3 = -accum3;
+ accum64 --;
+ }
+ prodh = prod64 >> 32;
+ accum64 -= prodh;
+
+ work32 = accum64 >> 32;
+ if ( work32 )
+ {
+#ifdef PARANOID
+ if ( work32 != 1 )
+ {
+ EXCEPTION(EX_INTERNAL|0x203);
+ }
+#endif
+
+ /* Need to subtract the divisor once more. */
+ work32 = accum3;
+ accum3 = work32 - b->sigl;
+ if ( accum3 > work32 )
+ accum64 --;
+ rat2 ++;
+ if ( rat2 == 0 )
+ rat1 ++;
+ accum64 -= b->sigh;
+
+#ifdef PARANOID
+ if ( (accum64 >> 32) )
+ {
+ EXCEPTION(EX_INTERNAL|0x203);
+ }
+#endif
+ }
+
+ /* Tidy up the remainder */
+
+ accum64 <<= 32;
+ accum64 |= accum3;
+ if ( accum64 >= divr64 )
+ {
+ accum64 -= divr64;
+ rat2 ++;
+ if ( rat2 == 0 )
+ {
+ rat1 ++;
+#ifdef PARANOID
+ /* No overflow should be possible here */
+ if ( rat1 == 0 )
+ {
+ EXCEPTION(EX_INTERNAL|0x203);
+ }
+ }
+#endif
+ }
+
+ /* The basic division is done, now we must be careful with the
+ remainder. */
+
+ if ( ovfl )
+ {
+ if ( rat2 & 1 )
+ rem = 0x80000000;
+ else
+ rem = 0;
+ rat2 >>= 1;
+ if ( rat1 & 1 )
+ rat2 |= 0x80000000;
+ rat1 >>= 1;
+ rat1 |= 0x80000000;
+
+ if ( accum64 )
+ rem |= 0xff0000;
+
+ dest->exp ++;
+ }
+ else
+ {
+ /* Now we just need to know how large the remainder is
+ relative to half the divisor. */
+ if ( accum64 == 0 )
+ rem = 0;
+ else
+ {
+ accum3 = accum64 >> 32;
+ if ( accum3 & 0x80000000 )
+ {
+ /* The remainder is definitely larger than 1/2 divisor. */
+ rem = 0xff000000;
+ }
+ else
+ {
+ accum64 <<= 1;
+ if ( accum64 >= divr64 )
+ {
+ accum64 -= divr64;
+ if ( accum64 == 0 )
+ rem = 0x80000000;
+ else
+ rem = 0xff000000;
+ }
+ else
+ rem = 0x7f000000;
+ }
+ }
+ }
+
+ dest->sigh = rat1;
+ dest->sigl = rat2;
+
+ dest->exp --;
+ return FPU_round(dest, rem, 0, control_w, sign);
+
+}
+
--- /dev/null
+ .file "reg_u_mul.S"
+/*---------------------------------------------------------------------------+
+ | reg_u_mul.S |
+ | |
+ | Core multiplication routine |
+ | |
+ | Copyright (C) 1992,1993,1995,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | Basic multiplication routine. |
+ | Does not check the resulting exponent for overflow/underflow |
+ | |
+ | FPU_u_mul(FPU_REG *a, FPU_REG *b, FPU_REG *c, unsigned int cw); |
+ | |
+ | Internal working is at approx 128 bits. |
+ | Result is rounded to nearest 53 or 64 bits, using "nearest or even". |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "fpu_emu.h"
+#include "control_w.h"
+
+
+
+#ifndef NON_REENTRANT_FPU
+/* Local storage on the stack: */
+#define FPU_accum_0 -4(%ebp) /* ms word */
+#define FPU_accum_1 -8(%ebp)
+
+#else
+/* Local storage in a static area: */
+.data
+ .align 4,0
+FPU_accum_0:
+ .long 0
+FPU_accum_1:
+ .long 0
+#endif /* NON_REENTRANT_FPU */
+
+
+.text
+ENTRY(FPU_u_mul)
+ pushl %ebp
+ movl %esp,%ebp
+#ifndef NON_REENTRANT_FPU
+ subl $8,%esp
+#endif /* NON_REENTRANT_FPU */
+
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi
+ movl PARAM2,%edi
+
+#ifdef PARANOID
+ testl $0x80000000,SIGH(%esi)
+ jz L_bugged
+ testl $0x80000000,SIGH(%edi)
+ jz L_bugged
+#endif /* PARANOID */
+
+ xorl %ecx,%ecx
+ xorl %ebx,%ebx
+
+ movl SIGL(%esi),%eax
+ mull SIGL(%edi)
+ movl %eax,FPU_accum_0
+ movl %edx,FPU_accum_1
+
+ movl SIGL(%esi),%eax
+ mull SIGH(%edi)
+ addl %eax,FPU_accum_1
+ adcl %edx,%ebx
+/* adcl $0,%ecx // overflow here is not possible */
+
+ movl SIGH(%esi),%eax
+ mull SIGL(%edi)
+ addl %eax,FPU_accum_1
+ adcl %edx,%ebx
+ adcl $0,%ecx
+
+ movl SIGH(%esi),%eax
+ mull SIGH(%edi)
+ addl %eax,%ebx
+ adcl %edx,%ecx
+
+ /* Get the sum of the exponents. */
+ movl PARAM6,%eax
+ subl EXP_BIAS-1,%eax
+
+ /* Two denormals can cause an exponent underflow */
+ cmpl EXP_WAY_UNDER,%eax
+ jg Exp_not_underflow
+
+ /* Set to a really low value allow correct handling */
+ movl EXP_WAY_UNDER,%eax
+
+Exp_not_underflow:
+
+/* Have now finished with the sources */
+ movl PARAM3,%edi /* Point to the destination */
+ movw %ax,EXP(%edi)
+
+/* Now make sure that the result is normalized */
+ testl $0x80000000,%ecx
+ jnz LResult_Normalised
+
+ /* Normalize by shifting left one bit */
+ shll $1,FPU_accum_0
+ rcll $1,FPU_accum_1
+ rcll $1,%ebx
+ rcll $1,%ecx
+ decw EXP(%edi)
+
+LResult_Normalised:
+ movl FPU_accum_0,%eax
+ movl FPU_accum_1,%edx
+ orl %eax,%eax
+ jz L_extent_zero
+
+ orl $1,%edx
+
+L_extent_zero:
+ movl %ecx,%eax
+ jmp fpu_reg_round
+
+
+#ifdef PARANOID
+L_bugged:
+ pushl EX_INTERNAL|0x205
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_exit:
+ popl %ebx
+ popl %edi
+ popl %esi
+ leave
+ ret
+#endif /* PARANOID */
+
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | reg_u_mul.c |
+ | |
+ | Core multiplication routine |
+ | |
+ | Copyright (C) 1992,1993,1995,1997,1999 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@melbpc.org.au |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | Basic multiplication routine. |
+ | Does not check the resulting exponent for overflow/underflow |
+ | |
+ | Internal working is at approx 128 bits. |
+ | Result is rounded to nearest 53 or 64 bits, using "nearest or even". |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "fpu_emu.h"
+#include "control_w.h"
+
+
+int FPU_u_mul(const FPU_REG *a, const FPU_REG *b, FPU_REG *c, u16 cw,
+ u_char sign, int expon)
+{
+ u64 mu, ml, mi;
+ u32 lh, ll, th, tl;
+
+#ifdef PARANOID
+ if ( ! (a->sigh & 0x80000000) || ! (b->sigh & 0x80000000) )
+ {
+ EXCEPTION(EX_INTERNAL|0x205);
+ }
+#endif
+
+ ml = a->sigl;
+ ml *= b->sigl;
+ ll = ml;
+ lh = ml >> 32;
+
+ mu = a->sigh;
+ mu *= b->sigh;
+
+ mi = a->sigh;
+ mi *= b->sigl;
+ tl = mi;
+ th = mi >> 32;
+ lh += tl;
+ if ( tl > lh )
+ mu ++;
+ mu += th;
+
+ mi = a->sigl;
+ mi *= b->sigh;
+ tl = mi;
+ th = mi >> 32;
+ lh += tl;
+ if ( tl > lh )
+ mu ++;
+ mu += th;
+
+ ml = lh;
+ ml <<= 32;
+ ml += ll;
+
+ expon -= EXP_BIAS-1;
+ if ( expon <= EXP_WAY_UNDER )
+ expon = EXP_WAY_UNDER;
+
+ c->exp = expon;
+
+ if ( ! (mu & BX_CONST64(0x8000000000000000)) )
+ {
+ mu <<= 1;
+ if ( ml & BX_CONST64(0x8000000000000000) )
+ mu |= 1;
+ ml <<= 1;
+ c->exp --;
+ }
+
+ ll = ml;
+ lh = ml >> 32;
+
+ if ( ll )
+ lh |= 1;
+
+ c->sigl = mu;
+ c->sigh = mu >> 32;
+
+ return FPU_round(c, lh, 0, cw, sign);
+
+}
--- /dev/null
+ .file "reg_u_sub.S"
+/*---------------------------------------------------------------------------+
+ | reg_u_sub.S |
+ | |
+ | Core floating point subtraction routine. |
+ | |
+ | Copyright (C) 1992,1993,1995,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
+ | |
+ | Call from C as: |
+ | int FPU_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, |
+ | int control_w) |
+ | Return value is the tag of the answer, or-ed with FPU_Exception if |
+ | one was raised, or -1 on internal error. |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*
+ | Kernel subtraction routine FPU_u_sub(reg *arg1, reg *arg2, reg *answ).
+ | Takes two valid reg f.p. numbers (TAG_Valid), which are
+ | treated as unsigned numbers,
+ | and returns their difference as a TAG_Valid or TAG_Zero f.p.
+ | number.
+ | The first number (arg1) must be the larger.
+ | The returned number is normalized.
+ | Basic checks are performed if PARANOID is defined.
+ */
+
+#include "exception.h"
+#include "fpu_emu.h"
+#include "control_w.h"
+
+.text
+ENTRY(FPU_u_sub)
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi /* source 1 */
+ movl PARAM2,%edi /* source 2 */
+
+ movl PARAM6,%ecx
+ subl PARAM7,%ecx /* exp1 - exp2 */
+
+#ifdef PARANOID
+ /* source 2 is always smaller than source 1 */
+ js L_bugged_1
+
+ testl $0x80000000,SIGH(%edi) /* The args are assumed to be be normalized */
+ je L_bugged_2
+
+ testl $0x80000000,SIGH(%esi)
+ je L_bugged_2
+#endif /* PARANOID */
+
+/*--------------------------------------+
+ | Form a register holding the |
+ | smaller number |
+ +--------------------------------------*/
+ movl SIGH(%edi),%eax /* register ms word */
+ movl SIGL(%edi),%ebx /* register ls word */
+
+ movl PARAM3,%edi /* destination */
+ movl PARAM6,%edx
+ movw %dx,EXP(%edi) /* Copy exponent to destination */
+
+ xorl %edx,%edx /* register extension */
+
+/*--------------------------------------+
+ | Shift the temporary register |
+ | right the required number of |
+ | places. |
+ +--------------------------------------*/
+
+ cmpw $32,%cx /* shrd only works for 0..31 bits */
+ jnc L_more_than_31
+
+/* less than 32 bits */
+ shrd %cl,%ebx,%edx
+ shrd %cl,%eax,%ebx
+ shr %cl,%eax
+ jmp L_shift_done
+
+L_more_than_31:
+ cmpw $64,%cx
+ jnc L_more_than_63
+
+ subb $32,%cl
+ jz L_exactly_32
+
+ shrd %cl,%eax,%edx
+ shr %cl,%eax
+ orl %ebx,%ebx
+ jz L_more_31_no_low /* none of the lowest bits is set */
+
+ orl $1,%edx /* record the fact in the extension */
+
+L_more_31_no_low:
+ movl %eax,%ebx
+ xorl %eax,%eax
+ jmp L_shift_done
+
+L_exactly_32:
+ movl %ebx,%edx
+ movl %eax,%ebx
+ xorl %eax,%eax
+ jmp L_shift_done
+
+L_more_than_63:
+ cmpw $65,%cx
+ jnc L_more_than_64
+
+ /* Shift right by 64 bits */
+ movl %eax,%edx
+ orl %ebx,%ebx
+ jz L_more_63_no_low
+
+ orl $1,%edx
+ jmp L_more_63_no_low
+
+L_more_than_64:
+ jne L_more_than_65
+
+ /* Shift right by 65 bits */
+ /* Carry is clear if we get here */
+ movl %eax,%edx
+ rcrl %edx
+ jnc L_shift_65_nc
+
+ orl $1,%edx
+ jmp L_more_63_no_low
+
+L_shift_65_nc:
+ orl %ebx,%ebx
+ jz L_more_63_no_low
+
+ orl $1,%edx
+ jmp L_more_63_no_low
+
+L_more_than_65:
+ movl $1,%edx /* The shifted nr always at least one '1' */
+
+L_more_63_no_low:
+ xorl %ebx,%ebx
+ xorl %eax,%eax
+
+L_shift_done:
+L_subtr:
+/*------------------------------+
+ | Do the subtraction |
+ +------------------------------*/
+ xorl %ecx,%ecx
+ subl %edx,%ecx
+ movl %ecx,%edx
+ movl SIGL(%esi),%ecx
+ sbbl %ebx,%ecx
+ movl %ecx,%ebx
+ movl SIGH(%esi),%ecx
+ sbbl %eax,%ecx
+ movl %ecx,%eax
+
+#ifdef PARANOID
+ /* We can never get a borrow */
+ jc L_bugged
+#endif /* PARANOID */
+
+/*--------------------------------------+
+ | Normalize the result |
+ +--------------------------------------*/
+ testl $0x80000000,%eax
+ jnz L_round /* no shifting needed */
+
+ orl %eax,%eax
+ jnz L_shift_1 /* shift left 1 - 31 bits */
+
+ orl %ebx,%ebx
+ jnz L_shift_32 /* shift left 32 - 63 bits */
+
+/*
+ * A rare case, the only one which is non-zero if we got here
+ * is: 1000000 .... 0000
+ * -0111111 .... 1111 1
+ * --------------------
+ * 0000000 .... 0000 1
+ */
+
+ cmpl $0x80000000,%edx
+ jnz L_must_be_zero
+
+ /* Shift left 64 bits */
+ subw $64,EXP(%edi)
+ xchg %edx,%eax
+ jmp fpu_reg_round
+
+L_must_be_zero:
+#ifdef PARANOID
+ orl %edx,%edx
+ jnz L_bugged_3
+#endif /* PARANOID */
+
+ /* The result is zero */
+ movw $0,EXP(%edi) /* exponent */
+ movl $0,SIGL(%edi)
+ movl $0,SIGH(%edi)
+ movl TAG_Zero,%eax
+ jmp L_exit
+
+L_shift_32:
+ movl %ebx,%eax
+ movl %edx,%ebx
+ movl $0,%edx
+ subw $32,EXP(%edi) /* Can get underflow here */
+
+/* We need to shift left by 1 - 31 bits */
+L_shift_1:
+ bsrl %eax,%ecx /* get the required shift in %ecx */
+ subl $31,%ecx
+ negl %ecx
+ shld %cl,%ebx,%eax
+ shld %cl,%edx,%ebx
+ shl %cl,%edx
+ subw %cx,EXP(%edi) /* Can get underflow here */
+
+L_round:
+ jmp fpu_reg_round /* Round the result */
+
+
+#ifdef PARANOID
+L_bugged_1:
+ pushl EX_INTERNAL|0x206
+ call EXCEPTION
+ pop %ebx
+ jmp L_error_exit
+
+L_bugged_2:
+ pushl EX_INTERNAL|0x209
+ call EXCEPTION
+ pop %ebx
+ jmp L_error_exit
+
+L_bugged_3:
+ pushl EX_INTERNAL|0x210
+ call EXCEPTION
+ pop %ebx
+ jmp L_error_exit
+
+L_bugged_4:
+ pushl EX_INTERNAL|0x211
+ call EXCEPTION
+ pop %ebx
+ jmp L_error_exit
+
+L_bugged:
+ pushl EX_INTERNAL|0x212
+ call EXCEPTION
+ pop %ebx
+ jmp L_error_exit
+
+L_error_exit:
+ movl $-1,%eax
+
+#endif /* PARANOID */
+
+L_exit:
+ popl %ebx
+ popl %edi
+ popl %esi
+ leave
+ ret
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | reg_u_sub.c |
+ | |
+ | Core floating point subtraction routine. |
+ | |
+ | Copyright (C) 1992,1993,1995,1997,1999 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@melbpc.org.au |
+ | |
+ | Return value is the tag of the answer, or-ed with FPU_Exception if |
+ | one was raised, or -1 on internal error. |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*
+ | Kernel subtraction routine FPU_u_sub(reg *arg1, reg *arg2, reg *answ).
+ | Takes two valid reg f.p. numbers (TAG_Valid), which are
+ | treated as unsigned numbers,
+ | and returns their difference as a TAG_Valid or TAG_Zero f.p.
+ | number.
+ | The first number (arg1) must be the larger.
+ | The returned number is normalized.
+ | Basic checks are performed if PARANOID is defined.
+ */
+
+#include "exception.h"
+#include "fpu_emu.h"
+#include "control_w.h"
+
+
+
+int FPU_u_sub(const FPU_REG *arg1, const FPU_REG *arg2, FPU_REG *dest,
+ u16 control_w, u_char sign, int expa, int expb)
+{
+ FPU_REG shifted, answ;
+ u32 extent;
+ int ediff = expa - expb, ed2, borrow;
+
+#ifdef PARANOID
+ if ( ediff < 0 )
+ {
+ EXCEPTION(EX_INTERNAL|0x206);
+ return -1;
+ }
+#endif
+
+ answ.exp = expa;
+
+#ifdef PARANOID
+ if ( !(arg1->sigh & 0x80000000) || !(arg2->sigh & 0x80000000) )
+ {
+ EXCEPTION(EX_INTERNAL|0x209);
+ return -1;
+ }
+#endif
+
+ if ( ediff == 0 )
+ {
+ shifted.sigl = arg2->sigl;
+ shifted.sigh = arg2->sigh;
+ extent = 0;
+ }
+ else if ( ediff < 32 )
+ {
+ ed2 = 32 - ediff;
+ extent = arg2->sigl << ed2;
+ shifted.sigl = arg2->sigl >> ediff;
+ shifted.sigl |= (arg2->sigh << ed2);
+ shifted.sigh = arg2->sigh >> ediff;
+ }
+ else if ( ediff < 64 )
+ {
+ ediff -= 32;
+ if ( ! ediff )
+ {
+ extent = arg2->sigl;
+ shifted.sigl = arg2->sigh;
+ shifted.sigh = 0;
+ }
+ else
+ {
+ ed2 = 32 - ediff;
+ extent = arg2->sigl >> ediff;
+ extent |= (arg2->sigh << ed2);
+ if ( arg2->sigl << ed2 )
+ extent |= 1;
+ shifted.sigl = arg2->sigh >> ediff;
+ shifted.sigh = 0;
+ }
+ }
+ else
+ {
+ ediff -= 64;
+ if ( ! ediff )
+ {
+ extent = arg2->sigh;
+ if ( arg2->sigl )
+ extent |= 1;
+ shifted.sigl = 0;
+ shifted.sigh = 0;
+ }
+ else
+ {
+ if ( ediff < 32 )
+ {
+ extent = arg2->sigh >> ediff;
+ if ( arg2->sigl || (arg2->sigh << (32-ediff)) )
+ extent |= 1;
+ }
+ else
+ extent = 1;
+ shifted.sigl = 0;
+ shifted.sigh = 0;
+ }
+ }
+
+ extent = -extent;
+ borrow = extent;
+ answ.sigl = arg1->sigl - shifted.sigl;
+ if ( answ.sigl > arg1->sigl )
+ {
+ if ( borrow )
+ answ.sigl --;
+ borrow = 1;
+ }
+ else if ( borrow )
+ {
+ answ.sigl --;
+ if ( answ.sigl != 0xffffffff )
+ borrow = 0;
+ }
+ answ.sigh = arg1->sigh - shifted.sigh;
+ if ( answ.sigh > arg1->sigh )
+ {
+ if ( borrow )
+ answ.sigh --;
+ borrow = 1;
+ }
+ else if ( borrow )
+ {
+ answ.sigh --;
+ if ( answ.sigh != 0xffffffff )
+ borrow = 0;
+ }
+
+#ifdef PARANOID
+ if ( borrow )
+ {
+ /* This can only occur if the code is bugged */
+ EXCEPTION(EX_INTERNAL|0x212);
+ return -1;
+ }
+#endif
+
+ if ( answ.sigh & 0x80000000 )
+ {
+ /*
+ The simpler "*dest = answ" is broken in gcc
+ */
+ dest->exp = answ.exp;
+ dest->sigh = answ.sigh;
+ dest->sigl = answ.sigl;
+ return FPU_round(dest, extent, 0, control_w, sign);
+ }
+
+ if ( answ.sigh == 0 )
+ {
+ if ( answ.sigl )
+ {
+ answ.sigh = answ.sigl;
+ answ.sigl = extent;
+ extent = 0;
+ answ.exp -= 32;
+ }
+ else if ( extent )
+ {
+/*
+ * A rare case, the only one which is non-zero if we got here
+ * is: 1000000 .... 0000
+ * -0111111 .... 1111 1
+ * --------------------
+ * 0000000 .... 0000 1
+ */
+ if ( extent != 0x80000000 )
+ {
+ /* This can only occur if the code is bugged */
+ EXCEPTION(EX_INTERNAL|0x210);
+ return -1;
+ }
+ dest->sigh = extent;
+ dest->sigl = extent = 0;
+ dest->exp -= 64;
+ return FPU_round(dest, extent, 0, control_w, sign);
+ }
+ else
+ {
+ dest->exp = 0;
+ dest->sigh = dest->sigl = 0;
+ return TAG_Zero;
+ }
+ }
+
+ while ( !(answ.sigh & 0x80000000) )
+ {
+ answ.sigh <<= 1;
+ if ( answ.sigl & 0x80000000 )
+ answ.sigh |= 1;
+ answ.sigl <<= 1;
+ if ( extent & 0x80000000 )
+ answ.sigl |= 1;
+ extent <<= 1;
+ answ.exp --;
+ }
+
+ dest->exp = answ.exp;
+ dest->sigh = answ.sigh;
+ dest->sigl = answ.sigl;
+
+ return FPU_round(dest, extent, 0, control_w, sign);
+
+}
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | round_Xsig.S |
+ | |
+ | Copyright (C) 1992,1993,1994,1995 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
+ | |
+ | Normalize and round a 12 byte quantity. |
+ | Call from C as: |
+ | int round_Xsig(Xsig *n) |
+ | |
+ | Normalize a 12 byte quantity. |
+ | Call from C as: |
+ | int norm_Xsig(Xsig *n) |
+ | |
+ | Each function returns the size of the shift (nr of bits). |
+ | |
+ +---------------------------------------------------------------------------*/
+ .file "round_Xsig.S"
+
+#include "fpu_emu.h"
+
+
+.text
+ENTRY(round_Xsig)
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %ebx /* Reserve some space */
+ pushl %ebx
+ pushl %esi
+
+ movl PARAM1,%esi
+
+ movl 8(%esi),%edx
+ movl 4(%esi),%ebx
+ movl (%esi),%eax
+
+ movl $0,-4(%ebp)
+
+ orl %edx,%edx /* ms bits */
+ js L_round /* Already normalized */
+ jnz L_shift_1 /* Shift left 1 - 31 bits */
+
+ movl %ebx,%edx
+ movl %eax,%ebx
+ xorl %eax,%eax
+ movl $-32,-4(%ebp)
+
+/* We need to shift left by 1 - 31 bits */
+L_shift_1:
+ bsrl %edx,%ecx /* get the required shift in %ecx */
+ subl $31,%ecx
+ negl %ecx
+ subl %ecx,-4(%ebp)
+ shld %cl,%ebx,%edx
+ shld %cl,%eax,%ebx
+ shl %cl,%eax
+
+L_round:
+ testl $0x80000000,%eax
+ jz L_exit
+
+ addl $1,%ebx
+ adcl $0,%edx
+ jnz L_exit
+
+ movl $0x80000000,%edx
+ incl -4(%ebp)
+
+L_exit:
+ movl %edx,8(%esi)
+ movl %ebx,4(%esi)
+ movl %eax,(%esi)
+
+ movl -4(%ebp),%eax
+
+ popl %esi
+ popl %ebx
+ leave
+ ret
+
+
+
+
+ENTRY(norm_Xsig)
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %ebx /* Reserve some space */
+ pushl %ebx
+ pushl %esi
+
+ movl PARAM1,%esi
+
+ movl 8(%esi),%edx
+ movl 4(%esi),%ebx
+ movl (%esi),%eax
+
+ movl $0,-4(%ebp)
+
+ orl %edx,%edx /* ms bits */
+ js L_n_exit /* Already normalized */
+ jnz L_n_shift_1 /* Shift left 1 - 31 bits */
+
+ movl %ebx,%edx
+ movl %eax,%ebx
+ xorl %eax,%eax
+ movl $-32,-4(%ebp)
+
+ orl %edx,%edx /* ms bits */
+ js L_n_exit /* Normalized now */
+ jnz L_n_shift_1 /* Shift left 1 - 31 bits */
+
+ movl %ebx,%edx
+ movl %eax,%ebx
+ xorl %eax,%eax
+ addl $-32,-4(%ebp)
+ jmp L_n_exit /* Might not be normalized,
+ but shift no more. */
+
+/* We need to shift left by 1 - 31 bits */
+L_n_shift_1:
+ bsrl %edx,%ecx /* get the required shift in %ecx */
+ subl $31,%ecx
+ negl %ecx
+ subl %ecx,-4(%ebp)
+ shld %cl,%ebx,%edx
+ shld %cl,%eax,%ebx
+ shl %cl,%eax
+
+L_n_exit:
+ movl %edx,8(%esi)
+ movl %ebx,4(%esi)
+ movl %eax,(%esi)
+
+ movl -4(%ebp),%eax
+
+ popl %esi
+ popl %ebx
+ leave
+ ret
+
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | round_Xsig.c |
+ | |
+ | Copyright (C) 1992,1993,1994,1995,1999 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@melbpc.org.au |
+ | |
+ | Normalize and round a 12 byte quantity. |
+ | int round_Xsig(Xsig *n) |
+ | |
+ | Normalize a 12 byte quantity. |
+ | int norm_Xsig(Xsig *n) |
+ | |
+ | Each function returns the size of the shift (nr of bits). |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#include "fpu_emu.h"
+#include "poly.h"
+
+int round_Xsig(Xsig *x)
+{
+ int n = 0;
+
+ if ( x->msw == 0 )
+ {
+ x->msw = x->midw;
+ x->midw = x->lsw;
+ x->lsw = 0;
+ n = 32;
+ }
+ while ( !(x->msw & 0x80000000) )
+ {
+ x->msw <<= 1;
+ if ( x->midw & 0x80000000 ) x->msw |= 1;
+ x->midw <<= 1;
+ if ( x->lsw & 0x80000000 ) x->midw |= 1;
+ x->lsw <<= 1;
+ n++;
+ }
+ if ( x->lsw & 0x80000000 )
+ {
+ x->midw ++;
+ if ( x->midw == 0 )
+ x->msw ++;
+ if ( x->msw == 0 )
+ {
+ x->msw = 0x80000000;
+ n--;
+ }
+ }
+
+
+ return -n;
+}
+
+
+int norm_Xsig(Xsig *x)
+{
+ int n = 0;
+
+ if ( x->msw == 0 )
+ {
+ if ( x->midw == 0 )
+ {
+ x->msw = x->lsw;
+ x->midw = 0;
+ x->lsw = 0;
+ n = 64;
+ }
+ else
+ {
+ x->msw = x->midw;
+ x->midw = x->lsw;
+ x->lsw = 0;
+ n = 32;
+ }
+ }
+ while ( !(x->msw & 0x80000000) )
+ {
+ x->msw <<= 1;
+ if ( x->midw & 0x80000000 ) x->msw |= 1;
+ x->midw <<= 1;
+ if ( x->lsw & 0x80000000 ) x->midw |= 1;
+ x->lsw <<= 1;
+ n++;
+ }
+
+ return -n;
+}
+
+
+
+
+
--- /dev/null
+ .file "shr_Xsig.S"
+/*---------------------------------------------------------------------------+
+ | shr_Xsig.S |
+ | |
+ | 12 byte right shift function |
+ | |
+ | Copyright (C) 1992,1994,1995 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
+ | |
+ | Call from C as: |
+ | void shr_Xsig(Xsig *arg, unsigned nr) |
+ | |
+ | Extended shift right function. |
+ | Fastest for small shifts. |
+ | Shifts the 12 byte quantity pointed to by the first arg (arg) |
+ | right by the number of bits specified by the second arg (nr). |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#include "fpu_emu.h"
+
+.text
+ENTRY(shr_Xsig)
+ push %ebp
+ movl %esp,%ebp
+ pushl %esi
+ movl PARAM2,%ecx
+ movl PARAM1,%esi
+ cmpl $32,%ecx /* shrd only works for 0..31 bits */
+ jnc L_more_than_31
+
+/* less than 32 bits */
+ pushl %ebx
+ movl (%esi),%eax /* lsl */
+ movl 4(%esi),%ebx /* midl */
+ movl 8(%esi),%edx /* msl */
+ shrd %cl,%ebx,%eax
+ shrd %cl,%edx,%ebx
+ shr %cl,%edx
+ movl %eax,(%esi)
+ movl %ebx,4(%esi)
+ movl %edx,8(%esi)
+ popl %ebx
+ popl %esi
+ leave
+ ret
+
+L_more_than_31:
+ cmpl $64,%ecx
+ jnc L_more_than_63
+
+ subb $32,%cl
+ movl 4(%esi),%eax /* midl */
+ movl 8(%esi),%edx /* msl */
+ shrd %cl,%edx,%eax
+ shr %cl,%edx
+ movl %eax,(%esi)
+ movl %edx,4(%esi)
+ movl $0,8(%esi)
+ popl %esi
+ leave
+ ret
+
+L_more_than_63:
+ cmpl $96,%ecx
+ jnc L_more_than_95
+
+ subb $64,%cl
+ movl 8(%esi),%eax /* msl */
+ shr %cl,%eax
+ xorl %edx,%edx
+ movl %eax,(%esi)
+ movl %edx,4(%esi)
+ movl %edx,8(%esi)
+ popl %esi
+ leave
+ ret
+
+L_more_than_95:
+ xorl %eax,%eax
+ movl %eax,(%esi)
+ movl %eax,4(%esi)
+ movl %eax,8(%esi)
+ popl %esi
+ leave
+ ret
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | shr_Xsig.S |
+ | |
+ | 12 byte right shift function |
+ | |
+ | Copyright (C) 1992,1994,1995 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
+ | |
+ | |
+ | Extended shift right function. |
+ | Fastest for small shifts. |
+ | Shifts the 12 byte quantity pointed to by the first arg (arg) |
+ | right by the number of bits specified by the second arg (nr). |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#include "fpu_emu.h"
+#include "poly.h"
+
+void shr_Xsig(Xsig *arg, const int nr)
+{
+ int n = nr;
+
+ while ( n >= 32 )
+ {
+ arg->lsw = arg->midw;
+ arg->midw = arg->msw;
+ arg->msw = 0;
+ n -= 32;
+ }
+
+ if ( n <= 0 )
+ return;
+
+ arg->lsw = (arg->lsw >> n) | (arg->midw << (32-n));
+ arg->midw = (arg->midw >> n) | (arg->msw << (32-n));
+ arg->msw >>= n;
+
+}
+
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | status_w.h |
+ | |
+ | Copyright (C) 1992,1993 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#ifndef _STATUS_H_
+#define _STATUS_H_
+
+#include "fpu_emu.h" /* for definition of PECULIAR_486 */
+
+#ifdef __ASSEMBLY__
+#define Const__(x) $##x
+#else
+#define Const__(x) x
+#endif
+
+#define SW_Backward Const__(0x8000) /* backward compatibility */
+#define SW_C3 Const__(0x4000) /* condition bit 3 */
+#define SW_Top Const__(0x3800) /* top of stack */
+#define SW_Top_Shift Const__(11) /* shift for top of stack bits */
+#define SW_C2 Const__(0x0400) /* condition bit 2 */
+#define SW_C1 Const__(0x0200) /* condition bit 1 */
+#define SW_C0 Const__(0x0100) /* condition bit 0 */
+#define SW_Summary Const__(0x0080) /* exception summary */
+#define SW_Stack_Fault Const__(0x0040) /* stack fault */
+#define SW_Precision Const__(0x0020) /* loss of precision */
+#define SW_Underflow Const__(0x0010) /* underflow */
+#define SW_Overflow Const__(0x0008) /* overflow */
+#define SW_Zero_Div Const__(0x0004) /* divide by zero */
+#define SW_Denorm_Op Const__(0x0002) /* denormalized operand */
+#define SW_Invalid Const__(0x0001) /* invalid operation */
+
+#define SW_Exc_Mask Const__(0x27f) /* Status word exception bit mask */
+
+#ifndef __ASSEMBLY__
+
+#define COMP_A_gt_B 1
+#define COMP_A_eq_B 2
+#define COMP_A_lt_B 3
+#define COMP_No_Comp 4
+#define COMP_Denormal 0x20
+#define COMP_NaN 0x40
+#define COMP_SNaN 0x80
+
+#define status_word() \
+ ((partial_status & ~SW_Top & 0xffff) | ((top << SW_Top_Shift) & SW_Top))
+// bbd: use do {...} while (0) structure instead of using curly brackets
+// inside parens, which most compilers do not like.
+#define setcc(cc) do { \
+ partial_status &= ~(SW_C0|SW_C1|SW_C2|SW_C3); \
+ partial_status |= (cc) & (SW_C0|SW_C1|SW_C2|SW_C3); } while(0)
+
+#ifdef PECULIAR_486
+ /* Default, this conveys no information, but an 80486 does it. */
+ /* Clear the SW_C1 bit, "other bits undefined". */
+# define clear_C1() { partial_status &= ~SW_C1; }
+# else
+# define clear_C1()
+#endif /* PECULIAR_486 */
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _STATUS_H_ */
--- /dev/null
+#ifndef __ARCH_DESC_H
+#define __ARCH_DESC_H
+
+struct desc_struct {
+ unsigned long a,b;
+};
+
+extern struct desc_struct gdt_table[];
+extern struct desc_struct *idt, *gdt;
+
+struct Xgt_desc_struct {
+ unsigned short size;
+ unsigned long address GCC_ATTRIBUTE((packed));
+};
+
+#define idt_descr (*(struct Xgt_desc_struct *)((char *)&idt - 2))
+#define gdt_descr (*(struct Xgt_desc_struct *)((char *)&gdt - 2))
+
+/*
+ * Entry into gdt where to find first TSS. GDT layout:
+ * 0 - null
+ * 1 - not used
+ * 2 - kernel code segment
+ * 3 - kernel data segment
+ * 4 - user code segment
+ * 5 - user data segment
+ * 6 - not used
+ * 7 - not used
+ * 8 - APM BIOS support
+ * 9 - APM BIOS support
+ * 10 - APM BIOS support
+ * 11 - APM BIOS support
+ * 12 - TSS #0
+ * 13 - LDT #0
+ * 14 - TSS #1
+ * 15 - LDT #1
+ */
+#define FIRST_TSS_ENTRY 12
+#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1)
+#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))
+#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3))
+#define load_TR(n) __asm__ __volatile__("ltr %%ax": /* no output */ :"a" (_TSS(n)))
+#define load_ldt(n) __asm__ __volatile__("lldt %%ax": /* no output */ :"a" (_LDT(n)))
+#define store_TR(n) \
+__asm__("str %%ax\n\t" \
+ "subl %2,%%eax\n\t" \
+ "shrl $4,%%eax" \
+ :"=a" (n) \
+ :"0" (0),"i" (FIRST_TSS_ENTRY<<3))
+
+extern void set_intr_gate(unsigned int irq, void * addr);
+extern void set_ldt_desc(unsigned int n, void *addr, unsigned int size);
+extern void set_tss_desc(unsigned int n, void *addr);
+
+/*
+ * This is the ldt that every process will get unless we need
+ * something other than this.
+ */
+extern struct desc_struct default_ldt;
+
+#endif
--- /dev/null
+#ifndef _I386_MATH_EMU_H
+#define _I386_MATH_EMU_H
+
+// Don't really need anything in here.
+
+#endif
--- /dev/null
+#ifndef _ASMi386_SIGCONTEXT_H
+#define _ASMi386_SIGCONTEXT_H
+
+/*
+ * As documented in the iBCS2 standard..
+ *
+ * The first part of "struct _fpstate" is just the
+ * normal i387 hardware setup, the extra "status"
+ * word is used to save the coprocessor status word
+ * before entering the handler.
+ */
+struct _fpreg {
+ unsigned short significand[4];
+ unsigned short exponent;
+};
+
+struct _fpstate {
+ unsigned long cw,
+ sw,
+ tag,
+ ipoff,
+ cssel,
+ dataoff,
+ datasel;
+ struct _fpreg _st[8];
+ unsigned long status;
+};
+
+#if 0
+/* sigcontext is not needed by bochs, and it conflicts with some other
+ machine types (DEC OSF1) */
+struct sigcontext {
+ unsigned short gs, __gsh;
+ unsigned short fs, __fsh;
+ unsigned short es, __esh;
+ unsigned short ds, __dsh;
+ unsigned long edi;
+ unsigned long esi;
+ unsigned long ebp;
+ unsigned long esp;
+ unsigned long ebx;
+ unsigned long edx;
+ unsigned long ecx;
+ unsigned long eax;
+ unsigned long trapno;
+ unsigned long err;
+ unsigned long eip;
+ unsigned short cs, __csh;
+ unsigned long eflags;
+ unsigned long esp_at_signal;
+ unsigned short ss, __ssh;
+ struct _fpstate * fpstate;
+ unsigned long oldmask;
+ unsigned long cr2;
+};
+#endif
+
+
+#endif
--- /dev/null
+#ifndef _I386_TYPES_H
+#define _I386_TYPES_H
+
+#ifndef __ASSEMBLY__
+#endif
+
+#endif /* _I386_TYPES_H */
--- /dev/null
+#ifndef _I386_UACCESS_H
+#define _I386_UACCESS_H
+
+
+
+#endif
--- /dev/null
+#ifndef _LINUX_KERNEL_H
+#define _LINUX_KERNEL_H
+
+int printk(const char * fmt, ...)
+ GCC_ATTRIBUTE((format (printf, 1, 2)));
+
+#endif
--- /dev/null
+#ifndef _LINUX_LINKAGE_H
+#define _LINUX_LINKAGE_H
+
+#ifdef __cplusplus
+#define CPP_ASMLINKAGE extern "C"
+#else
+#define CPP_ASMLINKAGE
+#endif
+
+#if defined __i386__ && (__GNUC__ > 2 || __GNUC_MINOR__ > 7)
+#define asmlinkage CPP_ASMLINKAGE GCC_ATTRIBUTE((regparm(0)))
+#else
+#define asmlinkage CPP_ASMLINKAGE
+#endif
+
+#define SYMBOL_NAME_STR(X) #X
+#define SYMBOL_NAME(X) X
+#ifdef __STDC__
+#define SYMBOL_NAME_LABEL(X) X##:
+#else
+#define SYMBOL_NAME_LABEL(X) X/**/:
+#endif
+
+#ifdef __arm__
+#define __ALIGN .align 0
+#define __ALIGN_STR ".align 0"
+#else
+#ifdef __mc68000__
+#define __ALIGN .align 4
+#define __ALIGN_STR ".align 4"
+#else
+#if !defined(__i486__) && !defined(__i586__)
+#define __ALIGN .align 4,0x90
+#define __ALIGN_STR ".align 4,0x90"
+#else /* __i486__/__i586__ */
+#define __ALIGN .align 16,0x90
+#define __ALIGN_STR ".align 16,0x90"
+#endif /* __i486__/__i586__ */
+#endif /* __mc68000__ */
+#endif /* __arm__ */
+
+#ifdef __ASSEMBLY__
+
+#define ALIGN __ALIGN
+#define ALIGN_STR __ALIGN_STR
+
+#define ENTRY(name) \
+ .globl SYMBOL_NAME(name); \
+ ALIGN; \
+ SYMBOL_NAME_LABEL(name)
+
+#endif
+
+#endif
--- /dev/null
+#ifndef _LINUX_MM_H
+#define _LINUX_MM_H
+
+
+#define VERIFY_READ 0
+#define VERIFY_WRITE 1
+
+#endif
--- /dev/null
+#ifndef _ASMi386_SIGNAL_H
+#define _ASMi386_SIGNAL_H
+
+#define SIGILL 4
+#define SIGFPE 8
+#define SIGSEGV 11
+
+#endif
--- /dev/null
+#ifndef _LINUX_STDDEF_H
+#define _LINUX_STDDEF_H
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+
+#undef NULL
+#define NULL ((void *)0)
+
+#undef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+#endif
--- /dev/null
+#ifndef _LINUX_TYPES_H
+#define _LINUX_TYPES_H
+
+#ifndef __ASSEMBLY__
+
+#define u_char bx_u_char
+#define u_short bx_u_short
+#define u_int bx_u_int
+#define u_long bx_u_long
+#define unchar bx_unchar
+#define ushort bx_ushort
+#define uint bx_uint
+#define ulong bx_ulong
+
+/* bsd */
+typedef unsigned char u_char;
+typedef unsigned short u_short;
+typedef unsigned int u_int;
+typedef unsigned long u_long;
+
+/* sysv */
+typedef unsigned char unchar;
+typedef unsigned short ushort;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+#endif
+
+#endif /* _LINUX_TYPES_H */
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | version.h |
+ | |
+ | |
+ | Copyright (C) 1992,1993,1994,1996,1997,1999 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@melbpc.org.au |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#define FPU_VERSION "wm-FPU-emu version 2.05"
--- /dev/null
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+//
+// This is the glue logic needed to connect the wm-FPU-emu
+// FPU emulator written by Bill Metzenthen to bochs.
+//
+
+
+#include "bochs.h"
+extern "C" {
+#include "fpu_emu.h"
+#include "linux/signal.h"
+}
+
+#define LOG_THIS genlog->
+#if BX_USE_CPU_SMF
+#define this (BX_CPU(0))
+#endif
+
+// Use this to hold a pointer to the instruction since
+// we can't pass this to the FPU emulation routines, which
+// will ultimately call routines here.
+static BxInstruction_t *fpu_iptr = NULL;
+static BX_CPU_C *fpu_cpu_ptr = NULL;
+
+i387_t i387;
+
+extern "C" void
+math_emulate2(fpu_addr_modes addr_modes,
+ u_char FPU_modrm,
+ u_char byte1,
+ void *data_address,
+ struct address data_sel_off,
+ struct address entry_sel_off);
+
+extern "C" void printfp(char *s, FPU_REG *r);
+
+
+ // This is called by bochs upon reset
+ void
+BX_CPU_C::fpu_init(void)
+{
+ finit();
+}
+
+ void
+BX_CPU_C::fpu_execute(BxInstruction_t *i)
+{
+ fpu_addr_modes addr_modes;
+ void *data_address;
+ struct address data_sel_off;
+ struct address entry_sel_off;
+ Boolean is_32;
+
+ fpu_iptr = i;
+ fpu_cpu_ptr = this;
+
+#if 0
+ addr_modes.default_mode = VM86;
+ addr_modes.default_mode = 0; // FPU_CS == __USER_CS && FPU_DS == __USER_DS
+ addr_modes.default_mode = SEG32;
+ addr_modes.default_mode = PM16;
+#endif
+ if (protected_mode()) {
+ addr_modes.default_mode = SEG32;
+ }
+ else if (v8086_mode()) {
+ addr_modes.default_mode = VM86;
+ }
+ else {
+ // real mode, use vm86 for now
+ addr_modes.default_mode = VM86;
+ }
+
+
+ // Mark if instruction used opsize or addrsize prefixes
+ // Actually, addr_modes.override.address_size is not used,
+ // could delete that code.
+ is_32 = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b;
+ if (i->as_32 == is_32)
+ addr_modes.override.address_size = 0;
+ else
+ addr_modes.override.address_size = ADDR_SIZE_PREFIX;
+ if (i->os_32 == is_32)
+ addr_modes.override.operand_size = 0;
+ else
+ addr_modes.override.operand_size = OP_SIZE_PREFIX;
+
+ // For now set access_limit to max. It seems to be
+ // a number from 0..255 denoting how many bytes the
+ // current instruction can access according to its
+ // memory operand. 255 means >= 255.
+access_limit = 0xff;
+
+ // fill in orig eip here in offset
+ // fill in CS in selector
+ entry_sel_off.offset = BX_CPU_THIS_PTR prev_eip;
+ entry_sel_off.selector = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value;
+
+// should set these fields to 0 if mem operand not used
+ data_address = (void *) i->rm_addr;
+ data_sel_off.offset = i->rm_addr;
+ data_sel_off.selector = BX_CPU_THIS_PTR sregs[i->seg].selector.value;
+
+ math_emulate2(addr_modes, i->modrm, i->b1, data_address,
+ data_sel_off, entry_sel_off);
+}
+
+
+ unsigned
+fpu_get_ds(void)
+{
+ return(fpu_cpu_ptr->sregs[BX_SEG_REG_DS].selector.value);
+}
+
+ void
+fpu_set_ax(unsigned short val16)
+{
+// define to set AX in the current CPU -- not ideal.
+#undef AX
+#define AX (fpu_cpu_ptr->gen_reg[0].word.rx)
+ AX = val16;
+#undef AX
+//BX_DEBUG(( "fpu_set_ax(0x%04x)\n", (unsigned) val16));
+}
+
+ void
+fpu_verify_area(unsigned what, void *ptr, unsigned n)
+{
+ bx_segment_reg_t *seg;
+
+ seg = &fpu_cpu_ptr->sregs[fpu_iptr->seg];
+
+ if (what == VERIFY_READ) {
+ fpu_cpu_ptr->read_virtual_checks(seg, PTR2INT(ptr), n);
+ }
+ else { // VERIFY_WRITE
+ fpu_cpu_ptr->write_virtual_checks(seg, PTR2INT(ptr), n);
+ }
+//BX_DEBUG(( "verify_area: 0x%x\n", PTR2INT(ptr)));
+}
+
+
+ void
+FPU_printall(void)
+{
+ BX_PANIC(("FPU_printall\n"));
+}
+
+
+ unsigned
+fpu_get_user(void *ptr, unsigned len)
+{
+ Bit32u val32;
+ Bit16u val16;
+ Bit8u val8;
+
+ switch (len) {
+ case 1:
+ fpu_cpu_ptr->read_virtual_byte(fpu_iptr->seg, PTR2INT(ptr), &val8);
+ val32 = val8;
+ break;
+ case 2:
+ fpu_cpu_ptr->read_virtual_word(fpu_iptr->seg, PTR2INT(ptr), &val16);
+ val32 = val16;
+ break;
+ case 4:
+ fpu_cpu_ptr->read_virtual_dword(fpu_iptr->seg, PTR2INT(ptr), &val32);
+ break;
+ default:
+ BX_PANIC(("fpu_get_user: len=%u\n", len));
+ }
+ return(val32);
+}
+
+ void
+fpu_put_user(unsigned val, void *ptr, unsigned len)
+{
+ Bit32u val32;
+ Bit16u val16;
+ Bit8u val8;
+
+ switch (len) {
+ case 1:
+ val8 = val;
+ fpu_cpu_ptr->write_virtual_byte(fpu_iptr->seg, PTR2INT(ptr), &val8);
+ break;
+ case 2:
+ val16 = val;
+ fpu_cpu_ptr->write_virtual_word(fpu_iptr->seg, PTR2INT(ptr), &val16);
+ break;
+ case 4:
+ val32 = val;
+ fpu_cpu_ptr->write_virtual_dword(fpu_iptr->seg, PTR2INT(ptr), &val32);
+ break;
+ default:
+ BX_PANIC(("fpu_put_user: len=%u\n", len));
+ }
+}
+
+ void
+math_abort(struct info *info, unsigned int signal)
+{
+ UNUSED(info); // info is always passed NULL
+#if BX_CPU_LEVEL >= 4
+
+// values of signal:
+// SIGILL : opcodes which are illegal
+// SIGFPE : unmasked FP exception before WAIT or non-control instruction
+// SIGSEGV : access data beyond segment violation
+ switch (signal) {
+ case SIGFPE:
+ if (fpu_cpu_ptr->cr0.ne == 0) {
+ // MSDOS compatibility external interrupt (IRQ13)
+ BX_PANIC (("math_abort: MSDOS compatibility not supported yet\n"));
+ }
+ fpu_cpu_ptr->exception(BX_MF_EXCEPTION, 0, 0);
+ // execution does not reach here
+
+ case SIGILL:
+ BX_PANIC (("math_abort: SIGILL not implemented yet.\n"));
+ break;
+ case SIGSEGV:
+ BX_PANIC (("math_abort: SIGSEGV not implemented yet.\n"));
+ break;
+ }
+
+#else
+ UNUSED(signal);
+ BX_INFO(("math_abort: CPU<4 not supported yet\n"));
+#endif
+}
+
+ int
+printk(const char * fmt, ...)
+{
+ BX_INFO(("printk not complete: %s\n", fmt));
+ return(0); // for now
+}
--- /dev/null
+ .file "wm_shrx.S"
+/*---------------------------------------------------------------------------+
+ | wm_shrx.S |
+ | |
+ | 64 bit right shift functions |
+ | |
+ | Copyright (C) 1992,1995 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
+ | |
+ | Call from C as: |
+ | unsigned FPU_shrx(void *arg1, unsigned arg2) |
+ | and |
+ | unsigned FPU_shrxs(void *arg1, unsigned arg2) |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#include "fpu_emu.h"
+
+.text
+/*---------------------------------------------------------------------------+
+ | unsigned FPU_shrx(void *arg1, unsigned arg2) |
+ | |
+ | Extended shift right function. |
+ | Fastest for small shifts. |
+ | Shifts the 64 bit quantity pointed to by the first arg (arg1) |
+ | right by the number of bits specified by the second arg (arg2). |
+ | Forms a 96 bit quantity from the 64 bit arg and eax: |
+ | [ 64 bit arg ][ eax ] |
+ | shift right ---------> |
+ | The eax register is initialized to 0 before the shifting. |
+ | Results returned in the 64 bit arg and eax. |
+ +---------------------------------------------------------------------------*/
+
+ENTRY(FPU_shrx)
+ push %ebp
+ movl %esp,%ebp
+ pushl %esi
+ movl PARAM2,%ecx
+ movl PARAM1,%esi
+ cmpl $32,%ecx /* shrd only works for 0..31 bits */
+ jnc L_more_than_31
+
+/* less than 32 bits */
+ pushl %ebx
+ movl (%esi),%ebx /* lsl */
+ movl 4(%esi),%edx /* msl */
+ xorl %eax,%eax /* extension */
+ shrd %cl,%ebx,%eax
+ shrd %cl,%edx,%ebx
+ shr %cl,%edx
+ movl %ebx,(%esi)
+ movl %edx,4(%esi)
+ popl %ebx
+ popl %esi
+ leave
+ ret
+
+L_more_than_31:
+ cmpl $64,%ecx
+ jnc L_more_than_63
+
+ subb $32,%cl
+ movl (%esi),%eax /* lsl */
+ movl 4(%esi),%edx /* msl */
+ shrd %cl,%edx,%eax
+ shr %cl,%edx
+ movl %edx,(%esi)
+ movl $0,4(%esi)
+ popl %esi
+ leave
+ ret
+
+L_more_than_63:
+ cmpl $96,%ecx
+ jnc L_more_than_95
+
+ subb $64,%cl
+ movl 4(%esi),%eax /* msl */
+ shr %cl,%eax
+ xorl %edx,%edx
+ movl %edx,(%esi)
+ movl %edx,4(%esi)
+ popl %esi
+ leave
+ ret
+
+L_more_than_95:
+ xorl %eax,%eax
+ movl %eax,(%esi)
+ movl %eax,4(%esi)
+ popl %esi
+ leave
+ ret
+
+
+/*---------------------------------------------------------------------------+
+ | unsigned FPU_shrxs(void *arg1, unsigned arg2) |
+ | |
+ | Extended shift right function (optimized for small floating point |
+ | integers). |
+ | Shifts the 64 bit quantity pointed to by the first arg (arg1) |
+ | right by the number of bits specified by the second arg (arg2). |
+ | Forms a 96 bit quantity from the 64 bit arg and eax: |
+ | [ 64 bit arg ][ eax ] |
+ | shift right ---------> |
+ | The eax register is initialized to 0 before the shifting. |
+ | The lower 8 bits of eax are lost and replaced by a flag which is |
+ | set (to 0x01) if any bit, apart from the first one, is set in the |
+ | part which has been shifted out of the arg. |
+ | Results returned in the 64 bit arg and eax. |
+ +---------------------------------------------------------------------------*/
+ENTRY(FPU_shrxs)
+ push %ebp
+ movl %esp,%ebp
+ pushl %esi
+ pushl %ebx
+ movl PARAM2,%ecx
+ movl PARAM1,%esi
+ cmpl $64,%ecx /* shrd only works for 0..31 bits */
+ jnc Ls_more_than_63
+
+ cmpl $32,%ecx /* shrd only works for 0..31 bits */
+ jc Ls_less_than_32
+
+/* We got here without jumps by assuming that the most common requirement
+ is for small integers */
+/* Shift by [32..63] bits */
+ subb $32,%cl
+ movl (%esi),%eax /* lsl */
+ movl 4(%esi),%edx /* msl */
+ xorl %ebx,%ebx
+ shrd %cl,%eax,%ebx
+ shrd %cl,%edx,%eax
+ shr %cl,%edx
+ orl %ebx,%ebx /* test these 32 bits */
+ setne %bl
+ test $0x7fffffff,%eax /* and 31 bits here */
+ setne %bh
+ orw %bx,%bx /* Any of the 63 bit set ? */
+ setne %al
+ movl %edx,(%esi)
+ movl $0,4(%esi)
+ popl %ebx
+ popl %esi
+ leave
+ ret
+
+/* Shift by [0..31] bits */
+Ls_less_than_32:
+ movl (%esi),%ebx /* lsl */
+ movl 4(%esi),%edx /* msl */
+ xorl %eax,%eax /* extension */
+ shrd %cl,%ebx,%eax
+ shrd %cl,%edx,%ebx
+ shr %cl,%edx
+ test $0x7fffffff,%eax /* only need to look at eax here */
+ setne %al
+ movl %ebx,(%esi)
+ movl %edx,4(%esi)
+ popl %ebx
+ popl %esi
+ leave
+ ret
+
+/* Shift by [64..95] bits */
+Ls_more_than_63:
+ cmpl $96,%ecx
+ jnc Ls_more_than_95
+
+ subb $64,%cl
+ movl (%esi),%ebx /* lsl */
+ movl 4(%esi),%eax /* msl */
+ xorl %edx,%edx /* extension */
+ shrd %cl,%ebx,%edx
+ shrd %cl,%eax,%ebx
+ shr %cl,%eax
+ orl %ebx,%edx
+ setne %bl
+ test $0x7fffffff,%eax /* only need to look at eax here */
+ setne %bh
+ orw %bx,%bx
+ setne %al
+ xorl %edx,%edx
+ movl %edx,(%esi) /* set to zero */
+ movl %edx,4(%esi) /* set to zero */
+ popl %ebx
+ popl %esi
+ leave
+ ret
+
+Ls_more_than_95:
+/* Shift by [96..inf) bits */
+ xorl %eax,%eax
+ movl (%esi),%ebx
+ orl 4(%esi),%ebx
+ setne %al
+ xorl %ebx,%ebx
+ movl %ebx,(%esi)
+ movl %ebx,4(%esi)
+ popl %ebx
+ popl %esi
+ leave
+ ret
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | wm_shrx.c |
+ | |
+ | 64 bit right shift functions |
+ | |
+ | Copyright (C) 1992,1995,1999 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@melbpc.org.au |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | unsigned FPU_shrx(void *arg1, unsigned arg2) |
+ | |
+ | Extended shift right function. |
+ | Fastest for small shifts. |
+ | Shifts the 64 bit quantity pointed to by the first arg (arg1) |
+ | right by the number of bits specified by the second arg (arg2). |
+ | Forms a 96 bit quantity from the 64 bit arg and eax: |
+ | [ 64 bit arg ][ eax ] |
+ | shift right ---------> |
+ | The eax register is initialized to 0 before the shifting. |
+ | Results returned in the 64 bit arg and eax. |
+ +---------------------------------------------------------------------------*/
+
+
+#include "fpu_emu.h"
+
+unsigned FPU_shrx(void *arg1, u32 arg2)
+{
+ u32 x;
+
+ if ( arg2 >= 64 )
+ {
+ if ( arg2 >= 96 )
+ {
+ *(u64 *)arg1 = 0;
+ return 0;
+ }
+ arg2 -= 64;
+ x = (*(u64 *)arg1) >> 32;
+ *(u64 *)arg1 = 0;
+
+ if ( arg2 )
+ return x >> arg2;
+ else
+ return x;
+ }
+
+ if ( arg2 < 32 )
+ {
+ if ( arg2 == 0 )
+ return 0;
+
+ x = (*(u64 *)arg1) << (32 - arg2);
+ }
+ else if ( arg2 > 32 )
+ {
+ x = (*(u64 *)arg1) >> (arg2 - 32);
+ }
+ else
+ {
+ /* arg2 == 32 */
+ x = *(u64 *)arg1;
+ }
+
+ (*(u64 *)arg1) >>= arg2;
+
+ return x;
+
+}
+
+
+/*---------------------------------------------------------------------------+
+ | unsigned FPU_shrxs(void *arg1, unsigned arg2) |
+ | |
+ | Extended shift right function (optimized for small floating point |
+ | integers). |
+ | Shifts the 64 bit quantity pointed to by the first arg (arg1) |
+ | right by the number of bits specified by the second arg (arg2). |
+ | Forms a 96 bit quantity from the 64 bit arg and eax: |
+ | [ 64 bit arg ][ eax ] |
+ | shift right ---------> |
+ | The eax register is initialized to 0 before the shifting. |
+ | The lower 8 bits of eax are lost and replaced by a flag which is |
+ | set (to 0x01) if any bit, apart from the first one, is set in the |
+ | part which has been shifted out of the arg. |
+ | Results returned in the 64 bit arg and eax. |
+ +---------------------------------------------------------------------------*/
+
+unsigned FPU_shrxs(void *arg1, u32 arg2)
+{
+ u32 x, bits;
+ u64 lost;
+
+ if ( arg2 >= 64 )
+ {
+ if ( arg2 >= 96 )
+ {
+ bits = *(u64 *)arg1 != 0;
+ *(u64 *)arg1 = 0;
+ return bits ? 1 : 0;
+ }
+ arg2 -= 64;
+ lost = (*(u64 *)arg1) << (32 - arg2);
+ x = (*(u64 *)arg1) >> 32;
+ *(u64 *)arg1 = 0;
+
+ if ( arg2 )
+ x >>= arg2;
+
+ if ( lost )
+ x |= 1;
+
+ return x;
+ }
+
+ if ( arg2 < 32 )
+ {
+ if ( arg2 == 0 )
+ /* No bits are lost */
+ return 0;
+
+ /* No bits are lost */
+ x = (*(u64 *)arg1) << (32 - arg2);
+ }
+ else if ( arg2 > 32 )
+ {
+ bits = (*(u64 *)arg1);
+ bits <<= (64 - arg2);
+ x = (*(u64 *)arg1) >> (arg2 - 32);
+ if ( bits )
+ x |= 1;
+ }
+ else
+ {
+ /* arg2 == 32 */
+ /* No bits are lost */
+ x = *(u64 *)arg1;
+ }
+
+ (*(u64 *)arg1) >>= arg2;
+
+ if ( x & 0x7fffffff )
+ x |= 1;
+
+ return x;
+
+}
+
--- /dev/null
+ .file "wm_sqrt.S"
+/*---------------------------------------------------------------------------+
+ | wm_sqrt.S |
+ | |
+ | Fixed point arithmetic square root evaluation. |
+ | |
+ | Copyright (C) 1992,1993,1995,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@suburbia.net |
+ | |
+ | Call from C as: |
+ | int wm_sqrt(FPU_REG *n, unsigned int control_word) |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | wm_sqrt(FPU_REG *n, unsigned int control_word) |
+ | returns the square root of n in n. |
+ | |
+ | Use Newton's method to compute the square root of a number, which must |
+ | be in the range [1.0 .. 4.0), to 64 bits accuracy. |
+ | Does not check the sign or tag of the argument. |
+ | Sets the exponent, but not the sign or tag of the result. |
+ | |
+ | The guess is kept in %esi:%edi |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "fpu_emu.h"
+
+
+#ifndef NON_REENTRANT_FPU
+/* Local storage on the stack: */
+#define FPU_accum_3 -4(%ebp) /* ms word */
+#define FPU_accum_2 -8(%ebp)
+#define FPU_accum_1 -12(%ebp)
+#define FPU_accum_0 -16(%ebp)
+
+/*
+ * The de-normalised argument:
+ * sq_2 sq_1 sq_0
+ * b b b b b b b ... b b b b b b .... b b b b 0 0 0 ... 0
+ * ^ binary point here
+ */
+#define FPU_fsqrt_arg_2 -20(%ebp) /* ms word */
+#define FPU_fsqrt_arg_1 -24(%ebp)
+#define FPU_fsqrt_arg_0 -28(%ebp) /* ls word, at most the ms bit is set */
+
+#else
+/* Local storage in a static area: */
+.data
+ .align 4,0
+FPU_accum_3:
+ .long 0 /* ms word */
+FPU_accum_2:
+ .long 0
+FPU_accum_1:
+ .long 0
+FPU_accum_0:
+ .long 0
+
+/* The de-normalised argument:
+ sq_2 sq_1 sq_0
+ b b b b b b b ... b b b b b b .... b b b b 0 0 0 ... 0
+ ^ binary point here
+ */
+FPU_fsqrt_arg_2:
+ .long 0 /* ms word */
+FPU_fsqrt_arg_1:
+ .long 0
+FPU_fsqrt_arg_0:
+ .long 0 /* ls word, at most the ms bit is set */
+#endif /* NON_REENTRANT_FPU */
+
+
+.text
+ENTRY(wm_sqrt)
+ pushl %ebp
+ movl %esp,%ebp
+#ifndef NON_REENTRANT_FPU
+ subl $28,%esp
+#endif /* NON_REENTRANT_FPU */
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi
+
+ movl SIGH(%esi),%eax
+ movl SIGL(%esi),%ecx
+ xorl %edx,%edx
+
+/* We use a rough linear estimate for the first guess.. */
+
+ cmpw EXP_BIAS,EXP(%esi)
+ jnz sqrt_arg_ge_2
+
+ shrl $1,%eax /* arg is in the range [1.0 .. 2.0) */
+ rcrl $1,%ecx
+ rcrl $1,%edx
+
+sqrt_arg_ge_2:
+/* From here on, n is never accessed directly again until it is
+ replaced by the answer. */
+
+ movl %eax,FPU_fsqrt_arg_2 /* ms word of n */
+ movl %ecx,FPU_fsqrt_arg_1
+ movl %edx,FPU_fsqrt_arg_0
+
+/* Make a linear first estimate */
+ shrl $1,%eax
+ addl $0x40000000,%eax
+ movl $0xaaaaaaaa,%ecx
+ mull %ecx
+ shll %edx /* max result was 7fff... */
+ testl $0x80000000,%edx /* but min was 3fff... */
+ jnz sqrt_prelim_no_adjust
+
+ movl $0x80000000,%edx /* round up */
+
+sqrt_prelim_no_adjust:
+ movl %edx,%esi /* Our first guess */
+
+/* We have now computed (approx) (2 + x) / 3, which forms the basis
+ for a few iterations of Newton's method */
+
+ movl FPU_fsqrt_arg_2,%ecx /* ms word */
+
+/*
+ * From our initial estimate, three iterations are enough to get us
+ * to 30 bits or so. This will then allow two iterations at better
+ * precision to complete the process.
+ */
+
+/* Compute (g + n/g)/2 at each iteration (g is the guess). */
+ shrl %ecx /* Doing this first will prevent a divide */
+ /* overflow later. */
+
+ movl %ecx,%edx /* msw of the arg / 2 */
+ divl %esi /* current estimate */
+ shrl %esi /* divide by 2 */
+ addl %eax,%esi /* the new estimate */
+
+ movl %ecx,%edx
+ divl %esi
+ shrl %esi
+ addl %eax,%esi
+
+ movl %ecx,%edx
+ divl %esi
+ shrl %esi
+ addl %eax,%esi
+
+/*
+ * Now that an estimate accurate to about 30 bits has been obtained (in %esi),
+ * we improve it to 60 bits or so.
+ *
+ * The strategy from now on is to compute new estimates from
+ * guess := guess + (n - guess^2) / (2 * guess)
+ */
+
+/* First, find the square of the guess */
+ movl %esi,%eax
+ mull %esi
+/* guess^2 now in %edx:%eax */
+
+ movl FPU_fsqrt_arg_1,%ecx
+ subl %ecx,%eax
+ movl FPU_fsqrt_arg_2,%ecx /* ms word of normalized n */
+ sbbl %ecx,%edx
+ jnc sqrt_stage_2_positive
+
+/* Subtraction gives a negative result,
+ negate the result before division. */
+ notl %edx
+ notl %eax
+ addl $1,%eax
+ adcl $0,%edx
+
+ divl %esi
+ movl %eax,%ecx
+
+ movl %edx,%eax
+ divl %esi
+ jmp sqrt_stage_2_finish
+
+sqrt_stage_2_positive:
+ divl %esi
+ movl %eax,%ecx
+
+ movl %edx,%eax
+ divl %esi
+
+ notl %ecx
+ notl %eax
+ addl $1,%eax
+ adcl $0,%ecx
+
+sqrt_stage_2_finish:
+ sarl $1,%ecx /* divide by 2 */
+ rcrl $1,%eax
+
+ /* Form the new estimate in %esi:%edi */
+ movl %eax,%edi
+ addl %ecx,%esi
+
+ jnz sqrt_stage_2_done /* result should be [1..2) */
+
+#ifdef PARANOID
+/* It should be possible to get here only if the arg is ffff....ffff */
+ cmp $0xffffffff,FPU_fsqrt_arg_1
+ jnz sqrt_stage_2_error
+#endif /* PARANOID */
+
+/* The best rounded result. */
+ xorl %eax,%eax
+ decl %eax
+ movl %eax,%edi
+ movl %eax,%esi
+ movl $0x7fffffff,%eax
+ jmp sqrt_round_result
+
+#ifdef PARANOID
+sqrt_stage_2_error:
+ pushl EX_INTERNAL|0x213
+ call EXCEPTION
+#endif /* PARANOID */
+
+sqrt_stage_2_done:
+
+/* Now the square root has been computed to better than 60 bits. */
+
+/* Find the square of the guess. */
+ movl %edi,%eax /* ls word of guess */
+ mull %edi
+ movl %edx,FPU_accum_1
+
+ movl %esi,%eax
+ mull %esi
+ movl %edx,FPU_accum_3
+ movl %eax,FPU_accum_2
+
+ movl %edi,%eax
+ mull %esi
+ addl %eax,FPU_accum_1
+ adcl %edx,FPU_accum_2
+ adcl $0,FPU_accum_3
+
+/* movl %esi,%eax */
+/* mull %edi */
+ addl %eax,FPU_accum_1
+ adcl %edx,FPU_accum_2
+ adcl $0,FPU_accum_3
+
+/* guess^2 now in FPU_accum_3:FPU_accum_2:FPU_accum_1 */
+
+ movl FPU_fsqrt_arg_0,%eax /* get normalized n */
+ subl %eax,FPU_accum_1
+ movl FPU_fsqrt_arg_1,%eax
+ sbbl %eax,FPU_accum_2
+ movl FPU_fsqrt_arg_2,%eax /* ms word of normalized n */
+ sbbl %eax,FPU_accum_3
+ jnc sqrt_stage_3_positive
+
+/* Subtraction gives a negative result,
+ negate the result before division */
+ notl FPU_accum_1
+ notl FPU_accum_2
+ notl FPU_accum_3
+ addl $1,FPU_accum_1
+ adcl $0,FPU_accum_2
+
+#ifdef PARANOID
+ adcl $0,FPU_accum_3 /* This must be zero */
+ jz sqrt_stage_3_no_error
+
+sqrt_stage_3_error:
+ pushl EX_INTERNAL|0x207
+ call EXCEPTION
+
+sqrt_stage_3_no_error:
+#endif /* PARANOID */
+
+ movl FPU_accum_2,%edx
+ movl FPU_accum_1,%eax
+ divl %esi
+ movl %eax,%ecx
+
+ movl %edx,%eax
+ divl %esi
+
+ sarl $1,%ecx /* divide by 2 */
+ rcrl $1,%eax
+
+ /* prepare to round the result */
+
+ addl %ecx,%edi
+ adcl $0,%esi
+
+ jmp sqrt_stage_3_finished
+
+sqrt_stage_3_positive:
+ movl FPU_accum_2,%edx
+ movl FPU_accum_1,%eax
+ divl %esi
+ movl %eax,%ecx
+
+ movl %edx,%eax
+ divl %esi
+
+ sarl $1,%ecx /* divide by 2 */
+ rcrl $1,%eax
+
+ /* prepare to round the result */
+
+ notl %eax /* Negate the correction term */
+ notl %ecx
+ addl $1,%eax
+ adcl $0,%ecx /* carry here ==> correction == 0 */
+ adcl $0xffffffff,%esi
+
+ addl %ecx,%edi
+ adcl $0,%esi
+
+sqrt_stage_3_finished:
+
+/*
+ * The result in %esi:%edi:%eax should be good to about 90 bits here,
+ * and the rounding information here does not have sufficient accuracy
+ * in a few rare cases.
+ */
+ cmpl $0xffffffe0,%eax
+ ja sqrt_near_exact_x
+
+ cmpl $0x00000020,%eax
+ jb sqrt_near_exact
+
+ cmpl $0x7fffffe0,%eax
+ jb sqrt_round_result
+
+ cmpl $0x80000020,%eax
+ jb sqrt_get_more_precision
+
+sqrt_round_result:
+/* Set up for rounding operations */
+ movl %eax,%edx
+ movl %esi,%eax
+ movl %edi,%ebx
+ movl PARAM1,%edi
+ movw EXP_BIAS,EXP(%edi) /* Result is in [1.0 .. 2.0) */
+ jmp fpu_reg_round
+
+
+sqrt_near_exact_x:
+/* First, the estimate must be rounded up. */
+ addl $1,%edi
+ adcl $0,%esi
+
+sqrt_near_exact:
+/*
+ * This is an easy case because x^1/2 is monotonic.
+ * We need just find the square of our estimate, compare it
+ * with the argument, and deduce whether our estimate is
+ * above, below, or exact. We use the fact that the estimate
+ * is known to be accurate to about 90 bits.
+ */
+ movl %edi,%eax /* ls word of guess */
+ mull %edi
+ movl %edx,%ebx /* 2nd ls word of square */
+ movl %eax,%ecx /* ls word of square */
+
+ movl %edi,%eax
+ mull %esi
+ addl %eax,%ebx
+ addl %eax,%ebx
+
+#ifdef PARANOID
+ cmp $0xffffffb0,%ebx
+ jb sqrt_near_exact_ok
+
+ cmp $0x00000050,%ebx
+ ja sqrt_near_exact_ok
+
+ pushl EX_INTERNAL|0x214
+ call EXCEPTION
+
+sqrt_near_exact_ok:
+#endif /* PARANOID */
+
+ or %ebx,%ebx
+ js sqrt_near_exact_small
+
+ jnz sqrt_near_exact_large
+
+ or %ebx,%edx
+ jnz sqrt_near_exact_large
+
+/* Our estimate is exactly the right answer */
+ xorl %eax,%eax
+ jmp sqrt_round_result
+
+sqrt_near_exact_small:
+/* Our estimate is too small */
+ movl $0x000000ff,%eax
+ jmp sqrt_round_result
+
+sqrt_near_exact_large:
+/* Our estimate is too large, we need to decrement it */
+ subl $1,%edi
+ sbbl $0,%esi
+ movl $0xffffff00,%eax
+ jmp sqrt_round_result
+
+
+sqrt_get_more_precision:
+/* This case is almost the same as the above, except we start
+ with an extra bit of precision in the estimate. */
+ stc /* The extra bit. */
+ rcll $1,%edi /* Shift the estimate left one bit */
+ rcll $1,%esi
+
+ movl %edi,%eax /* ls word of guess */
+ mull %edi
+ movl %edx,%ebx /* 2nd ls word of square */
+ movl %eax,%ecx /* ls word of square */
+
+ movl %edi,%eax
+ mull %esi
+ addl %eax,%ebx
+ addl %eax,%ebx
+
+/* Put our estimate back to its original value */
+ stc /* The ms bit. */
+ rcrl $1,%esi /* Shift the estimate left one bit */
+ rcrl $1,%edi
+
+#ifdef PARANOID
+ cmp $0xffffff60,%ebx
+ jb sqrt_more_prec_ok
+
+ cmp $0x000000a0,%ebx
+ ja sqrt_more_prec_ok
+
+ pushl EX_INTERNAL|0x215
+ call EXCEPTION
+
+sqrt_more_prec_ok:
+#endif /* PARANOID */
+
+ or %ebx,%ebx
+ js sqrt_more_prec_small
+
+ jnz sqrt_more_prec_large
+
+ or %ebx,%ecx
+ jnz sqrt_more_prec_large
+
+/* Our estimate is exactly the right answer */
+ movl $0x80000000,%eax
+ jmp sqrt_round_result
+
+sqrt_more_prec_small:
+/* Our estimate is too small */
+ movl $0x800000ff,%eax
+ jmp sqrt_round_result
+
+sqrt_more_prec_large:
+/* Our estimate is too large */
+ movl $0x7fffff00,%eax
+ jmp sqrt_round_result
--- /dev/null
+/*---------------------------------------------------------------------------+
+ | wm_sqrt.c |
+ | |
+ | Fixed point arithmetic square root evaluation. |
+ | |
+ | Copyright (C) 1992,1993,1995,1997,1999 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@melbpc.org.au |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | returns the square root of n in n. |
+ | |
+ | Use Newton's method to compute the square root of a number, which must |
+ | be in the range [1.0 .. 4.0), to 64 bits accuracy. |
+ | Does not check the sign or tag of the argument. |
+ | Sets the exponent, but not the sign or tag of the result. |
+ | |
+ | The guess is kept in %esi:%edi |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "fpu_emu.h"
+
+/*
+ The following value indicates the trailing bits (of 96 bits)
+ which may be in error when the final Newton iteration is finished
+ (0x20 corresponds to the last 5 bits in error, i.e. 91 bits precision).
+ A check of the following code with more than 3 billion (3.0e9) random
+ and selected values showed that 0x10 was always a large enough value,
+ so 0x20 should be a conservative choice.
+ */
+#define ERR_MARGIN 0x20
+
+
+int wm_sqrt(FPU_REG *n, s32 dummy1, s32 dummy2, u16 control_w, u8 sign)
+{
+ u64 nn, guess, halfn, lowr, mid, upr, diff, uwork;
+ s64 work;
+ u32 ne, guess32, work32, diff32, mid32;
+ int shifted;
+
+ nn = significand(n);
+ ne = 0;
+ if ( exponent16(n) == EXP_BIAS )
+ {
+ /* Shift the argument right one position. */
+ if ( nn & 1 )
+ ne = 0x80000000;
+ nn >>= 1;
+ guess = n->sigh >> 2;
+ shifted = 1;
+ }
+ else
+ {
+ guess = n->sigh >> 1;
+ shifted = 0;
+ }
+
+ guess += 0x40000000;
+ guess *= 0xaaaaaaaa;
+ guess <<= 1;
+ guess32 = guess >> 32;
+ if ( !(guess32 & 0x80000000) )
+ guess32 = 0x80000000;
+ halfn = nn >> 1;
+
+ guess32 = halfn / guess32 + (guess32 >> 1);
+ guess32 = halfn / guess32 + (guess32 >> 1);
+ guess32 = halfn / guess32 + (guess32 >> 1);
+
+
+/*
+ * Now that an estimate accurate to about 30 bits has been obtained,
+ * we improve it to 60 bits or so.
+ *
+ * The strategy from now on is to compute new estimates from
+ * guess := guess + (n - guess^2) / (2 * guess)
+ */
+
+ work = guess32;
+ work = nn - work * guess32;
+ work <<= 28; /* 29 - 1 */
+ work /= guess32;
+ work <<= 3; /* 29 + 3 = 32 */
+ work += ((u64)guess32) << 32;
+
+ if ( work == 0 ) /* This happens in one or two special cases */
+ work = BX_CONST64(0xffffffffffffffff);
+
+ guess = work;
+
+ /* guess is now accurate to about 60 bits */
+
+
+ if ( work > 0 )
+ {
+#ifdef PARANOID
+ if ( (n->sigh != 0xffffffff) && (n->sigl != 0xffffffff) )
+ {
+ EXCEPTION(EX_INTERNAL|0x213);
+ }
+#endif
+ /* We know the answer here. */
+ return FPU_round(n, 0x7fffffff, 0, control_w, sign);
+ }
+
+ /* Refine the guess to significantly more than 64 bits. */
+
+ /* First, square the current guess. */
+
+ guess32 = guess >> 32;
+ work32 = guess;
+
+ /* lower 32 times lower 32 */
+ lowr = work32;
+ lowr *= work32;
+
+ /* lower 32 times upper 32 */
+ mid = guess32;
+ mid *= work32;
+
+ /* upper 32 times upper 32 */
+ upr = guess32;
+ upr *= guess32;
+
+ /* upper 32 bits of the middle product times 2 */
+ upr += mid >> (32-1);
+
+ /* lower 32 bits of the middle product times 2 */
+ work32 = mid << 1;
+
+ /* upper 32 bits of the lower product */
+ mid32 = lowr >> 32;
+ mid32 += work32;
+ if ( mid32 < work32 )
+ upr ++;
+
+ /* We now have the first 96 bits (truncated) of the square of the guess */
+
+ diff = upr - nn;
+ diff32 = mid32 - ne;
+ if ( diff32 > mid32 )
+ diff --;
+
+ if ( ((s64)diff) < 0 )
+ {
+ /* The difference is negative, negate it. */
+ diff32 = -((s32)diff32);
+ diff = ~diff;
+ if ( diff32 == 0 )
+ diff ++;
+#ifdef PARANOID
+ if ( (diff >> 32) != 0 )
+ {
+ EXCEPTION(EX_INTERNAL|0x207);
+ }
+#endif
+
+ diff <<= 32;
+ diff |= diff32;
+ work32 = diff / guess32;
+ work = work32;
+ work <<= 32;
+
+ diff = diff % guess32;
+ diff <<= 32;
+ work32 = diff / guess32;
+
+ work |= work32;
+
+ work >>= 1;
+ work32 = work >> 32;
+
+
+ guess += work32; /* The first 64 bits */
+ guess32 = work; /* The next 32 bits */
+ /* The guess should now be good to about 90 bits */
+ }
+ else
+ {
+ /* The difference is positive. */
+ diff <<= 32;
+ diff |= diff32;
+
+ work32 = diff / guess32;
+ work = work32;
+ work <<= 32;
+
+ diff = diff % guess32;
+ diff <<= 32;
+ work32 = diff / guess32;
+
+ work |= work32;
+
+ work >>= 1;
+ work32 = work >> 32;
+
+ guess32 = work; /* The last 32 bits (of 96) */
+ guess32 = -guess32;
+ if ( guess32 )
+ guess --;
+ guess -= work32; /* The first 64 bits */
+ /* The guess should now be good to about 90 bits */
+ }
+
+
+ setexponent16(n, 0);
+
+ if ( guess32 >= (u32) -ERR_MARGIN )
+ {
+ /* Nearly exact, we round the 64 bit result upward. */
+ guess ++;
+ }
+ else if ( (guess32 > ERR_MARGIN) &&
+ ((guess32 < 0x80000000-ERR_MARGIN)
+ || (guess32 > 0x80000000+ERR_MARGIN)) )
+ {
+ /* We have enough accuracy to decide rounding */
+ significand(n) = guess;
+ return FPU_round(n, guess32, 0, control_w, sign);
+ }
+
+ if ( (guess32 <= ERR_MARGIN) || (guess32 >= (u32) -ERR_MARGIN) )
+ {
+ /*
+ * This is an easy case because x^1/2 is monotonic.
+ * We need just find the square of our estimate, compare it
+ * with the argument, and deduce whether our estimate is
+ * above, below, or exact. We use the fact that the estimate
+ * is known to be accurate to about 90 bits.
+ */
+
+
+ /* We compute the lower 64 bits of the 128 bit product */
+ work32 = guess;
+ lowr = work32;
+ lowr *= work32;
+
+ uwork = guess >> 32;
+ work32 = guess;
+ uwork *= work32;
+ uwork <<= 33; /* 33 = 32+1 (for two times the product) */
+
+ lowr += uwork; /* We now have the 64 bits */
+
+ /* We need only look at bits 65..96 of the square of guess. */
+ if ( shifted )
+ work32 = lowr >> 31;
+ else
+ work32 = lowr >> 32;
+
+#ifdef PARANOID
+ if ( ((s32)work32 > 3*ERR_MARGIN) || ((s32)work32 < -3*ERR_MARGIN) )
+ {
+ EXCEPTION(EX_INTERNAL|0x214);
+ }
+#endif
+
+ significand(n) = guess;
+ if ( (s32)work32 > 0 )
+ {
+ /* guess is too large */
+ significand(n) --;
+ return FPU_round(n, 0xffffff00, 0, control_w, sign);
+ }
+ else if ( (s32)work32 < 0 )
+ {
+ /* guess is a little too small */
+ return FPU_round(n, 0x000000ff, 0, control_w, sign);
+ }
+
+ else if ( (u32)lowr != 0 )
+ {
+
+ /* guess is too large */
+ significand(n) --;
+ return FPU_round(n, 0xffffff00, 0, control_w, sign);
+ }
+
+ /* Our guess is precise. */
+ return FPU_round(n, 0, 0, control_w, sign);
+ }
+
+ /* Very similar to the case above, but the last bit is near 0.5.
+ We handle this just like the case above but we shift everything
+ by one bit. */
+
+
+ uwork = guess;
+ uwork <<= 1;
+ uwork |= 1; /* add the half bit */
+
+ /* We compute the lower 64 bits of the 128 bit product */
+ work32 = uwork;
+ lowr = work32;
+ lowr *= work32;
+
+ work32 = uwork >> 32;
+ uwork &= 0xffffffff;
+ uwork *= work32;
+ uwork <<= 33; /* 33 = 32+1 (for two times the product) */
+
+ lowr += uwork; /* We now have the 64 bits. The lowest 32 bits of lowr
+ are not all zero (the lsb is 1). */
+
+ /* We need only look at bits 65..96 of the square of guess. */
+ if ( shifted )
+ work32 = lowr >> 31;
+ else
+ work32 = lowr >> 32;
+
+#ifdef PARANOID
+ if ( ((s32)work32 > 4*3*ERR_MARGIN) || ((s32)work32 < -4*3*ERR_MARGIN) )
+ {
+ EXCEPTION(EX_INTERNAL|0x215);
+ }
+#endif
+
+ significand(n) = guess;
+ if ( (s32)work32 < 0 )
+ {
+ /* guess plus half bit is a little too small */
+ return FPU_round(n, 0x800000ff, 0, control_w, sign);
+ }
+ else /* Note that the lower 64 bits of the product are not all zero */
+ {
+ /* guess plus half bit is too large */
+ return FPU_round(n, 0x7fffff00, 0, control_w, sign);
+ }
+
+ /*
+ Note that the result of a square root cannot have precisely a half bit
+ of a least significant place (it is left as an exercise for the reader
+ to prove this! (hint: 65 bit*65 bit => n bits)).
+ */
+
+}
+
+++ /dev/null
-// Copyright (C) 2001 MandrakeSoft S.A.
-//
-// MandrakeSoft S.A.
-// 43, rue d'Aboukir
-// 75002 Paris - France
-// http://www.linux-mandrake.com/
-// http://www.mandrakesoft.com/
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-#include "bochs.h"
-#define LOG_THIS BX_CPU_THIS_PTR
-
- // sid_cpu_c constructor
-void sid_cpu_c::init(sid_mem_c *addrspace)
-{
- // To deal with initialization order problems inherent in C++, use
- // the macros SAFE_GET_IOFUNC and SAFE_GET_GENLOG to retrieve "io" and "genlog"
- // in all constructors or functions called by constructors. The macros
- // test for NULL and create the object if necessary, then return it.
- // Ensure that io and genlog get created, by making one reference to
- // each macro right here. All other code can call them directly.
- SAFE_GET_IOFUNC();
- SAFE_GET_GENLOG();
-
- BX_CPU_THIS_PTR set_INTR (0);
-#if BX_SUPPORT_APIC
- local_apic.init ();
-#endif
- setprefix("[CPU ]");
- // in SMP mode, the prefix of the CPU will be changed to [CPUn] in
- // bx_local_apic_c::set_id as soon as the apic ID is assigned.
-
- /* hack for the following fields. Its easier to decode mod-rm bytes if
- you can assume there's always a base & index register used. For
- modes which don't really use them, point to an empty (zeroed) register.
- */
- empty_register = 0;
-
- // 16bit address mode base register, used for mod-rm decoding
-
- _16bit_base_reg[0] = &gen_reg[BX_16BIT_REG_BX].word.rx;
- _16bit_base_reg[1] = &gen_reg[BX_16BIT_REG_BX].word.rx;
- _16bit_base_reg[2] = &gen_reg[BX_16BIT_REG_BP].word.rx;
- _16bit_base_reg[3] = &gen_reg[BX_16BIT_REG_BP].word.rx;
- _16bit_base_reg[4] = (Bit16u*) &empty_register;
- _16bit_base_reg[5] = (Bit16u*) &empty_register;
- _16bit_base_reg[6] = &gen_reg[BX_16BIT_REG_BP].word.rx;
- _16bit_base_reg[7] = &gen_reg[BX_16BIT_REG_BX].word.rx;
-
- // 16bit address mode index register, used for mod-rm decoding
- _16bit_index_reg[0] = &gen_reg[BX_16BIT_REG_SI].word.rx;
- _16bit_index_reg[1] = &gen_reg[BX_16BIT_REG_DI].word.rx;
- _16bit_index_reg[2] = &gen_reg[BX_16BIT_REG_SI].word.rx;
- _16bit_index_reg[3] = &gen_reg[BX_16BIT_REG_DI].word.rx;
- _16bit_index_reg[4] = &gen_reg[BX_16BIT_REG_SI].word.rx;
- _16bit_index_reg[5] = &gen_reg[BX_16BIT_REG_DI].word.rx;
- _16bit_index_reg[6] = (Bit16u*) &empty_register;
- _16bit_index_reg[7] = (Bit16u*) &empty_register;
-
- // for decoding instructions: access to seg reg's via index number
- sreg_mod00_rm16[0] = BX_SEG_REG_DS;
- sreg_mod00_rm16[1] = BX_SEG_REG_DS;
- sreg_mod00_rm16[2] = BX_SEG_REG_SS;
- sreg_mod00_rm16[3] = BX_SEG_REG_SS;
- sreg_mod00_rm16[4] = BX_SEG_REG_DS;
- sreg_mod00_rm16[5] = BX_SEG_REG_DS;
- sreg_mod00_rm16[6] = BX_SEG_REG_DS;
- sreg_mod00_rm16[7] = BX_SEG_REG_DS;
-
- sreg_mod01_rm16[0] = BX_SEG_REG_DS;
- sreg_mod01_rm16[1] = BX_SEG_REG_DS;
- sreg_mod01_rm16[2] = BX_SEG_REG_SS;
- sreg_mod01_rm16[3] = BX_SEG_REG_SS;
- sreg_mod01_rm16[4] = BX_SEG_REG_DS;
- sreg_mod01_rm16[5] = BX_SEG_REG_DS;
- sreg_mod01_rm16[6] = BX_SEG_REG_SS;
- sreg_mod01_rm16[7] = BX_SEG_REG_DS;
-
- sreg_mod10_rm16[0] = BX_SEG_REG_DS;
- sreg_mod10_rm16[1] = BX_SEG_REG_DS;
- sreg_mod10_rm16[2] = BX_SEG_REG_SS;
- sreg_mod10_rm16[3] = BX_SEG_REG_SS;
- sreg_mod10_rm16[4] = BX_SEG_REG_DS;
- sreg_mod10_rm16[5] = BX_SEG_REG_DS;
- sreg_mod10_rm16[6] = BX_SEG_REG_SS;
- sreg_mod10_rm16[7] = BX_SEG_REG_DS;
-
- // the default segment to use for a one-byte modrm with mod==01b
- // and rm==i
- //
- sreg_mod01_rm32[0] = BX_SEG_REG_DS;
- sreg_mod01_rm32[1] = BX_SEG_REG_DS;
- sreg_mod01_rm32[2] = BX_SEG_REG_DS;
- sreg_mod01_rm32[3] = BX_SEG_REG_DS;
- sreg_mod01_rm32[4] = BX_SEG_REG_NULL;
- // this entry should never be accessed
- // (escape to 2-byte)
- sreg_mod01_rm32[5] = BX_SEG_REG_SS;
- sreg_mod01_rm32[6] = BX_SEG_REG_DS;
- sreg_mod01_rm32[7] = BX_SEG_REG_DS;
-
- // the default segment to use for a one-byte modrm with mod==10b
- // and rm==i
- //
- sreg_mod10_rm32[0] = BX_SEG_REG_DS;
- sreg_mod10_rm32[1] = BX_SEG_REG_DS;
- sreg_mod10_rm32[2] = BX_SEG_REG_DS;
- sreg_mod10_rm32[3] = BX_SEG_REG_DS;
- sreg_mod10_rm32[4] = BX_SEG_REG_NULL;
- // this entry should never be accessed
- // (escape to 2-byte)
- sreg_mod10_rm32[5] = BX_SEG_REG_SS;
- sreg_mod10_rm32[6] = BX_SEG_REG_DS;
- sreg_mod10_rm32[7] = BX_SEG_REG_DS;
-
-
- // the default segment to use for a two-byte modrm with mod==00b
- // and base==i
- //
- sreg_mod0_base32[0] = BX_SEG_REG_DS;
- sreg_mod0_base32[1] = BX_SEG_REG_DS;
- sreg_mod0_base32[2] = BX_SEG_REG_DS;
- sreg_mod0_base32[3] = BX_SEG_REG_DS;
- sreg_mod0_base32[4] = BX_SEG_REG_SS;
- sreg_mod0_base32[5] = BX_SEG_REG_DS;
- sreg_mod0_base32[6] = BX_SEG_REG_DS;
- sreg_mod0_base32[7] = BX_SEG_REG_DS;
-
- // the default segment to use for a two-byte modrm with
- // mod==01b or mod==10b and base==i
- sreg_mod1or2_base32[0] = BX_SEG_REG_DS;
- sreg_mod1or2_base32[1] = BX_SEG_REG_DS;
- sreg_mod1or2_base32[2] = BX_SEG_REG_DS;
- sreg_mod1or2_base32[3] = BX_SEG_REG_DS;
- sreg_mod1or2_base32[4] = BX_SEG_REG_SS;
- sreg_mod1or2_base32[5] = BX_SEG_REG_SS;
- sreg_mod1or2_base32[6] = BX_SEG_REG_DS;
- sreg_mod1or2_base32[7] = BX_SEG_REG_DS;
-
-#if BX_DYNAMIC_TRANSLATION
- DTWrite8vShim = NULL;
- DTWrite16vShim = NULL;
- DTWrite32vShim = NULL;
- DTRead8vShim = NULL;
- DTRead16vShim = NULL;
- DTRead32vShim = NULL;
- DTReadRMW8vShim = (BxDTShim_t) DTASReadRMW8vShim;
- BX_DEBUG(( "DTReadRMW8vShim is %x\n", (unsigned) DTReadRMW8vShim ));
- BX_DEBUG(( "&DTReadRMW8vShim is %x\n", (unsigned) &DTReadRMW8vShim ));
- DTReadRMW16vShim = NULL;
- DTReadRMW32vShim = NULL;
- DTWriteRMW8vShim = (BxDTShim_t) DTASWriteRMW8vShim;
- DTWriteRMW16vShim = NULL;
- DTWriteRMW32vShim = NULL;
- DTSetFlagsOSZAPCPtr = (BxDTShim_t) DTASSetFlagsOSZAPC;
- DTIndBrHandler = (BxDTShim_t) DTASIndBrHandler;
- DTDirBrHandler = (BxDTShim_t) DTASDirBrHandler;
-#endif
-
- mem = addrspace;
- sprintf (name, "CPU %p", this);
-
- BX_INSTR_INIT();
- BX_DEBUG(( "Init.\n"));
-}
-
- void
-sid_cpu_c::set_INTR(Boolean value)
-{
- BX_CPU_THIS_PTR INTR = value;
- BX_CPU_THIS_PTR async_event = 0;
-}
#include "bochs.h"
#define LOG_THIS BX_CPU_THIS_PTR
+#if BX_SUPPORT_SID
+#include "sid-x86-cpu-wrapper.h"
+#endif
+
/* the device id and stepping id are loaded into DH & DL upon processor
startup. for device id: 3 = 80386, 4 = 80486. just make up a
}
#if BX_SUPPORT_SID
-void BX_CPU_C::init(sid_mem_c *addrspace)
+void BX_CPU_C::init(x86_cpu *x86_cpu_comp, sid_bx_mem_c *addrspace)
#else
void BX_CPU_C::init(BX_MEM_C *addrspace)
#endif
{
// BX_CPU_C constructor
BX_CPU_THIS_PTR set_INTR (0);
+#if BX_SUPPORT_SID
+ BX_CPU_THIS_PTR set_HRQ (0);
+#endif
+
#if BX_SUPPORT_APIC
local_apic.init ();
#endif
DTDirBrHandler = (BxDTShim_t) DTASDirBrHandler;
#endif
+#if BX_SUPPORT_SID
+ x86_cpu_component = x86_cpu_comp;
+#endif
mem = addrspace;
+ mem->init(x86_cpu_component);
+
sprintf (name, "CPU %p", this);
BX_INSTR_INIT();
BX_CPU_THIS_PTR EXT = 0;
//BX_INTR = 0;
-
+
#if BX_SUPPORT_PAGING
#if BX_USE_TLB
TLB_init();
BX_CPU_THIS_PTR INTR = value;
BX_CPU_THIS_PTR async_event = 1;
}
+
+#if BX_SUPPORT_SID
+void
+BX_CPU_C::set_HRQ(Boolean value)
+{
+ BX_CPU_THIS_PTR BX_HRQ = value;
+ if (value)
+ BX_CPU_THIS_PTR async_event = 1;
+}
+#endif
#define LOG_THIS BX_CPU_THIS_PTR
+#if BX_SUPPORT_SID
+#include "sid-x86-cpu-wrapper.h"
+#endif
void
BX_CPU_C::INSB_YbDX(BxInstruction_t *i)
{
-#if 0
Bit8u value8=0;
if (BX_CPU_THIS_PTR cr0.pe && (BX_CPU_THIS_PTR eflags.vm || (CPL>IOPL))) {
DI = DI + 1;
}
}
-#endif
}
void
BX_CPU_C::INSW_YvDX(BxInstruction_t *i)
// input word/doubleword from port to string
{
-#if 0
Bit32u edi;
unsigned int incr;
else
DI = DI + incr;
}
-#endif
}
void
BX_CPU_C::OUTSB_DXXb(BxInstruction_t *i)
{
-#if 0
unsigned seg;
Bit8u value8;
Bit32u esi;
else
SI += 1;
}
-#endif
}
void
BX_CPU_C::OUTSW_DXXv(BxInstruction_t *i)
// output word/doubleword string to port
{
-#if 0
unsigned seg;
Bit32u esi;
unsigned int incr;
else
SI = SI + incr;
}
-#endif
}
#include "bochs.h"
#define LOG_THIS BX_CPU_THIS_PTR
+#if BX_SUPPORT_SID
+#include "sid-x86-cpu-wrapper.h"
+#endif
Bit16u
BX_CPU_C::inp16(Bit16u addr)
{
-#if 0
Bit16u ret16;
if (BX_CPU_THIS_PTR cr0.pe && (BX_CPU_THIS_PTR eflags.vm || (CPL>IOPL))) {
ret16 = BX_INP(addr, 2);
return( ret16 );
-#endif
- return 0;
}
void
BX_CPU_C::outp16(Bit16u addr, Bit16u value)
{
-#if 0
/* If CPL <= IOPL, then all IO addresses are accessible.
* Otherwise, must check the IO permission map on >286.
* On the 286, there is no IO permissions map */
}
BX_OUTP(addr, value, 2);
-#endif
}
Bit32u
BX_CPU_C::inp32(Bit16u addr)
{
-#if 0
Bit32u ret32;
if (BX_CPU_THIS_PTR cr0.pe && (BX_CPU_THIS_PTR eflags.vm || (CPL>IOPL))) {
ret32 = BX_INP(addr, 4);
return( ret32 );
-#endif
- return 0;
}
void
BX_CPU_C::outp32(Bit16u addr, Bit32u value)
{
-#if 0
/* If CPL <= IOPL, then all IO addresses are accessible.
* Otherwise, must check the IO permission map on >286.
* On the 286, there is no IO permissions map */
}
BX_OUTP(addr, value, 4);
-#endif
}
Bit8u
BX_CPU_C::inp8(Bit16u addr)
{
-#if 0
Bit8u ret8;
if (BX_CPU_THIS_PTR cr0.pe && (BX_CPU_THIS_PTR eflags.vm || (CPL>IOPL))) {
ret8 = BX_INP(addr, 1);
return( ret8 );
-#endif
- return 0;
}
void
BX_CPU_C::outp8(Bit16u addr, Bit8u value)
{
-#if 0
/* If CPL <= IOPL, then all IO addresses are accessible.
* Otherwise, must check the IO permission map on >286.
* On the 286, there is no IO permissions map */
}
BX_OUTP(addr, value, 1);
-#endif
}
Boolean
BX_CPU_C::allow_io(Bit16u addr, unsigned len)
{
-#if 0
Bit16u io_base, permission16;
unsigned bit_index, i;
return(0);
permission16 >>= 1;
}
-#endif
return(1);
}
{ NULL, NULL, NULL, 0, 0, 0, 0 }, // SB16
"a", // boot drive
300000, // vga update interval
- 20, // default keyboard serial path delay (usec in bochs, msec in sid)
- 50000, // default floppy command delay (usec)
+ 250, // default keyboard serial path delay (usec)
+ 500, // default floppy command delay (usec)
500000, // default ips (instructions-per-second)
0, // default mouse_enabled
0, // default private_colormap
#endif
#if BX_SMP_PROCESSORS==1
+#if BX_SUPPORT_SID==0
BX_MEM(0)->init_memory(bx_options.memory.megs * 1024*1024);
BX_MEM(0)->load_ROM(bx_options.rom.path, bx_options.rom.address);
BX_MEM(0)->load_ROM(bx_options.vgarom.path, 0xc0000);
BX_CPU(0)->init (BX_MEM(0));
BX_CPU(0)->reset(BX_RESET_HARDWARE);
+#endif
#else
// SMP initialization
bx_mem_array[0] = new BX_MEM_C ();
void
bx_init_debug(void)
{
- bx_dbg.floppy = 0;
+ bx_dbg.floppy = 1;
bx_dbg.keyboard = 0;
bx_dbg.video = 0;
bx_dbg.disk = 0;
bx_pc_system.exit();
}
#endif
-
+#if BX_SUPPORT_SID==0
#if BX_DEBUGGER == 0
for (int cpu=0; cpu<BX_SMP_PROCESSORS; cpu++)
if (BX_CPU(cpu)) BX_CPU(cpu)->atexit();
#endif
-
+#endif
#if BX_PCI_SUPPORT
if (bx_options.i440FXSupport) {
bx_devices.pci->print_i440fx_state();
--- /dev/null
+## Process this with automake to create Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(top_builddir)/../../include -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../.. -I$(srcdir)/../../../../include
+
+noinst_LTLIBRARIES = libmemory.la
+
+libmemory_la_SOURCES = sid-bochs-memory.cc sid-bochs-memory.cc
+
+libmemory_la_LDFLAGS = -no-undefined
--- /dev/null
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ../..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+APIC_OBJS = @APIC_OBJS@
+AR = @AR@
+AS = @AS@
+AS_DYNAMIC_INCS = @AS_DYNAMIC_INCS@
+AS_DYNAMIC_OBJS = @AS_DYNAMIC_OBJS@
+BX_LOADER_OBJS = @BX_LOADER_OBJS@
+BX_SPLIT_HD_SUPPORT = @BX_SPLIT_HD_SUPPORT@
+CC = @CC@
+CDROM_OBJS = @CDROM_OBJS@
+CD_UP_ONE = @CD_UP_ONE@
+CD_UP_TWO = @CD_UP_TWO@
+CFP = @CFP@
+COMMAND_SEPARATOR = @COMMAND_SEPARATOR@
+CPP_SUFFIX = @CPP_SUFFIX@
+CXX = @CXX@
+CXXFP = @CXXFP@
+DASH = @DASH@
+DEBUGGER_VAR = @DEBUGGER_VAR@
+DISASM_VAR = @DISASM_VAR@
+DLLTOOL = @DLLTOOL@
+DYNAMIC_VAR = @DYNAMIC_VAR@
+EXE = @EXE@
+EXEEXT = @EXEEXT@
+EXTERNAL_DEPENDENCY = @EXTERNAL_DEPENDENCY@
+FPU_GLUE_OBJ = @FPU_GLUE_OBJ@
+FPU_VAR = @FPU_VAR@
+GUI_LINK_OPTS = @GUI_LINK_OPTS@
+GUI_LINK_OPTS_TERM = @GUI_LINK_OPTS_TERM@
+GUI_OBJS = @GUI_OBJS@
+GZIP = @GZIP@
+INLINE_VAR = @INLINE_VAR@
+INSTRUMENT_DIR = @INSTRUMENT_DIR@
+INSTRUMENT_VAR = @INSTRUMENT_VAR@
+IOAPIC_OBJS = @IOAPIC_OBJS@
+IODEV_LIB_VAR = @IODEV_LIB_VAR@
+LD = @LD@
+LIBTOOL = @LIBTOOL@
+LINK = @LINK@
+LN_S = @LN_S@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MAKELIB = @MAKELIB@
+NE2K_OBJS = @NE2K_OBJS@
+NM = @NM@
+NONINLINE_VAR = @NONINLINE_VAR@
+OBJDUMP = @OBJDUMP@
+OFP = @OFP@
+PACKAGE = @PACKAGE@
+PCI_OBJ = @PCI_OBJ@
+PRIMARY_TARGET = @PRIMARY_TARGET@
+RANLIB = @RANLIB@
+READLINE_LIB = @READLINE_LIB@
+RFB_LIBS = @RFB_LIBS@
+RMCOMMAND = @RMCOMMAND@
+SB16_OBJS = @SB16_OBJS@
+SLASH = @SLASH@
+SUFFIX_LINE = @SUFFIX_LINE@
+TAR = @TAR@
+VERSION = @VERSION@
+VIDEO_OBJS = @VIDEO_OBJS@
+sidtarget_arm = @sidtarget_arm@
+sidtarget_m32r = @sidtarget_m32r@
+sidtarget_m68k = @sidtarget_m68k@
+sidtarget_mips = @sidtarget_mips@
+sidtarget_ppc = @sidtarget_ppc@
+sidtarget_x86 = @sidtarget_x86@
+sidtarget_xstormy16 = @sidtarget_xstormy16@
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(top_builddir)/../../include -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../.. -I$(srcdir)/../../../../include
+
+noinst_LTLIBRARIES = libmemory.la
+
+libmemory_la_SOURCES = sid-bochs-memory.cc sid-bochs-memory.cc
+
+libmemory_la_LDFLAGS = -no-undefined
+mkinstalldirs = $(SHELL) $(top_srcdir)/../../config/mkinstalldirs
+CONFIG_HEADER = ../../config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I../..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_LIBS = @X_LIBS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+libmemory_la_LIBADD =
+libmemory_la_OBJECTS = sid-bochs-memory.lo sid-bochs-memory.lo
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON = Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+GZIP_ENV = --best
+DEP_FILES = .deps/sid-bochs-memory.P
+SOURCES = $(libmemory_la_SOURCES)
+OBJECTS = $(libmemory_la_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .cc .lo .o .s
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --foreign cpu/memory/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLTLIBRARIES:
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+
+distclean-noinstLTLIBRARIES:
+
+maintainer-clean-noinstLTLIBRARIES:
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.s.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+libmemory.la: $(libmemory_la_OBJECTS) $(libmemory_la_DEPENDENCIES)
+ $(CXXLINK) $(libmemory_la_LDFLAGS) $(libmemory_la_OBJECTS) $(libmemory_la_LIBADD) $(LIBS)
+.cc.o:
+ $(CXXCOMPILE) -c $<
+.cc.lo:
+ $(LTCXXCOMPILE) -c $<
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = cpu/memory
+
+distdir: $(DISTFILES)
+ here=`cd $(top_builddir) && pwd`; \
+ top_distdir=`cd $(top_distdir) && pwd`; \
+ distdir=`cd $(distdir) && pwd`; \
+ cd $(top_srcdir) \
+ && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --foreign cpu/memory/Makefile
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+ -rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+ @echo '$(COMPILE) -c $<'; \
+ $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.c
+ @echo '$(LTCOMPILE) -c $<'; \
+ $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+
+%.o: %.cc
+ @echo '$(CXXCOMPILE) -c $<'; \
+ $(CXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.cc
+ @echo '$(LTCXXCOMPILE) -c $<'; \
+ $(LTCXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LTLIBRARIES)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-noinstLTLIBRARIES mostlyclean-compile \
+ mostlyclean-libtool mostlyclean-tags mostlyclean-depend \
+ mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-noinstLTLIBRARIES clean-compile clean-libtool \
+ clean-tags clean-depend clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-noinstLTLIBRARIES distclean-compile \
+ distclean-libtool distclean-tags distclean-depend \
+ distclean-generic clean-am
+ -rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-noinstLTLIBRARIES \
+ maintainer-clean-compile maintainer-clean-libtool \
+ maintainer-clean-tags maintainer-clean-depend \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLTLIBRARIES distclean-noinstLTLIBRARIES \
+clean-noinstLTLIBRARIES maintainer-clean-noinstLTLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-libtool distclean-libtool \
+clean-libtool maintainer-clean-libtool tags mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir \
+mostlyclean-depend distclean-depend clean-depend \
+maintainer-clean-depend info-am info dvi-am dvi check check-am \
+installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+// sid-bochs-memory.cc - route bochs memory calls to sid cpu component. -*- C++ -*-
+//
+// Copyright (C) 2001 Red Hat.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#include "bochs.h"
+#include "sid-x86-cpu-wrapper.h"
+#define LOG_THIS this->
+
+void
+sid_bx_mem_c::init(x86_cpu *x86_cpu_comp)
+{
+ x86_cpu_component = x86_cpu_comp;
+}
+
+void
+sid_bx_mem_c::write_physical(BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data)
+{
+ Bit32u a20addr;
+
+ a20addr = A20ADDR(addr);
+
+ try
+ {
+ switch(len)
+ {
+ case 4:
+ {
+ Bit32u data32 = * ((Bit32u *) data);
+ x86_cpu_component->write_data_memory_4 (cpu->eip, a20addr, data32);
+ break;
+ }
+ case 2:
+ {
+ Bit16u data16 = * ((Bit16u *) data);
+ x86_cpu_component->write_data_memory_2 (cpu->eip, a20addr, data16);
+ break;
+ }
+ case 1:
+ {
+ Bit8u data8 = * ((Bit8u *) data);
+ x86_cpu_component->write_data_memory_1 (cpu->eip, a20addr, data8);
+ break;
+ }
+ default:
+ {
+ Bit8u data8;
+ Bit8u *data_ptr = (Bit8u *) data;
+
+ for (unsigned i = 0; i < len; i++)
+ {
+ data8 = * data_ptr;
+ x86_cpu_component->write_data_memory_1 (cpu->eip, a20addr, data8);
+ data_ptr++;
+ addr++;
+ a20addr = A20ADDR(addr);
+ }
+ break;
+ }
+ }
+ }
+ catch (sidutil::cpu_memory_fault e)
+ {
+ cerr << "[MEM ] caught cpu_memory_fault exeception" << endl;
+ cerr << "[MEM ] pc = " << setbase(16) << e.pc << endl;
+ cerr << "[MEM ] addr = " << e.address << endl;
+ cerr << "[MEM ] status: " << (e.status == sid::bus::ok ? "ok" :
+ (e.status == sid::bus::misaligned ? "misaligned" :
+ (e.status == sid::bus::unmapped ? "unmapped" : "unpermitted"))) << endl;
+
+ cerr << "[MEM ] operation: " << e.operation << setbase(10) << endl;
+ BX_PANIC(("sid_bx_mem_c::write_physical: error\n"));
+ }
+}
+
+void
+sid_bx_mem_c::read_physical(BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data)
+{
+
+ Bit32u a20addr;
+
+ a20addr = A20ADDR(addr);
+
+ try
+ {
+ switch (len)
+ {
+ case 4:
+ * ((Bit32u *) data) = x86_cpu_component->read_data_memory_4 (cpu->eip, a20addr);
+ break;
+ case 2:
+ * ((Bit16u *) data) = x86_cpu_component->read_data_memory_2 (cpu->eip, a20addr);
+ break;
+ case 1:
+ * ((Bit8u *) data) = x86_cpu_component->read_data_memory_1 (cpu->eip, a20addr);
+ break;
+ default:
+ Bit8u data8;
+ Bit8u * data_ptr = (Bit8u *) data;
+
+ for (unsigned i = 0; i < len; i++)
+ {
+ * data_ptr = x86_cpu_component->read_data_memory_1 (cpu->eip, a20addr);
+ data_ptr++;
+ addr++;
+ a20addr = A20ADDR(addr);
+ }
+ break;
+ }
+ }
+ catch (sidutil::cpu_memory_fault e)
+ {
+ cerr << "[MEM ] caught cpu_memory_fault exeception" << endl;
+ cerr << "[MEM ] pc = " << setbase(16) << e.pc << endl;
+ cerr << "[MEM ] addr = " << e.address << endl;
+ cerr << "[MEM ] status: " << (e.status == sid::bus::ok ? "ok" :
+ (e.status == sid::bus::misaligned ? "misaligned" :
+ (e.status == sid::bus::unmapped ? "unmapped" : "unpermitted"))) << endl;
+
+ cerr << "[MEM ] operation: " << e.operation << setbase(10) << endl;
+ BX_PANIC(("sid_bx_mem_c::read_physical: error\n"));
+ }
+}
--- /dev/null
+// sid-bochs-memory.h - declaration of the sid_bx_mem_c class. -*- C++ -*-
+//
+// Copyright (C) 2001 Red Hat.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#ifndef __SID_BX_MEMORY_H__
+#define __SID_BX_MEMORY_H__
+
+class x86_cpu;
+
+// This class takes bochs calls to read_physical and write_physical,
+// and calls the corresponding sid cpu read_data_memory and
+// write_data_memory functions.
+class sid_bx_mem_c : public logfunctions
+{
+public:
+ void init(x86_cpu *x86_cpu_comp);
+ void read_physical(BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data);
+ void write_physical(BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data);
+
+protected:
+ x86_cpu *x86_cpu_component;
+};
+#endif // __SID_BX_MEMORY_H__
BX_PANIC(("access_linear: paging not supported\n"));
}
+
void
BX_CPU_C::INVLPG(BxInstruction_t* i)
{}
--- /dev/null
+// sid-x86-cpu-wrapper.cc - member function implementations for the sid x86 cpu component. -*- C++ -*-
+//
+// Copyright (C) 2001 Red Hat.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#include "sid-x86-cpu-wrapper.h"
+
+x86_cpu::x86_cpu ()
+ : interrupt_pin(this, & x86_cpu::interrupt),
+ hold_request_pin(this, & x86_cpu::hold_request),
+ enable_a20_pin(this, & x86_cpu::enable_a20),
+ in_hardware_mode(false),
+ _a20_enabled(true),
+ a20_mask(0xffffffff),
+ memory_mode("default"),
+ blocking_on_syscall(false),
+ verbose_p(false),
+ io_memory_bus(0)
+{
+ bx_cpu.init(this, &bx_mem);
+
+ add_pin("interrupt", & this->interrupt_pin);
+ add_pin("interrupt-acknowledge", & this->interrupt_acknowledge_pin);
+ add_pin("interrupt-ack-response", & this->interrupt_acknowledge_response_pin);
+
+ add_pin("hold-request", & this->hold_request_pin);
+ add_pin("hold-acknowledge", & this->hold_acknowledge_pin);
+
+ add_pin("enable-a20", & this->enable_a20_pin);
+ add_pin("a20-enabled", & this->a20_enabled_pin);
+
+ add_accessor("io-memory", & this->io_memory_bus);
+
+ // set up registers for use by gloss component.
+ // see libgloss/i386/* for calling conventions
+ // and exception-sid.cc for handling of int 0x80
+ add_watchable_register (string("syscall-arg0"), &bx_cpu.gen_reg[0].erx);
+ add_watchable_register (string("syscall-arg1"), &bx_cpu.gen_reg[3].erx);
+ add_watchable_register (string("syscall-arg2"), &bx_cpu.gen_reg[1].erx);
+ add_watchable_register (string("syscall-arg3"), &bx_cpu.gen_reg[2].erx);
+ add_watchable_register (string("syscall-result"), &bx_cpu.gen_reg[0].erx);
+
+ add_watchable_register (string("syscall-trap"), &bx_cpu.gen_reg[0].erx);
+ add_watchable_register (string("syscall-error"), &syscall_error);
+
+ // set up debugging interface
+ // there are 16 integer registers
+ create_gdb_register_attrs (16, "4;5;8;9", & this->bx_cpu.eip);
+
+ add_attribute ("enable-warnings?", & this->warnings_enabled, "setting");
+ add_attribute ("hardware-mode?", & this->in_hardware_mode, "setting");
+ add_attribute ("memory-mode", & this->memory_mode, "setting");
+ add_attribute("verbose?", & this->verbose_p, "setting");
+}
+
+void
+x86_cpu::do_syscall()
+{
+ sid::host_int_4 tempAX = bx_cpu.gen_reg[0].erx;
+ sid::host_int_4 tempBX = bx_cpu.gen_reg[3].erx;
+ sid::host_int_4 tempCX = bx_cpu.gen_reg[1].erx;
+ sid::host_int_4 tempDX = bx_cpu.gen_reg[2].erx;
+
+ sidutil::cpu_trap_disposition whatnext = signal_trap(sidutil::cpu_trap_software, bx_cpu.gen_reg[0].erx);
+
+ switch (whatnext)
+ {
+ case sidutil::cpu_trap_unhandled:
+ cerr << "hw-cpu-x86: cpu syscall trap unhandled" << endl;
+ this->blocking_on_syscall = false;
+ return;
+ case sidutil::cpu_trap_reissue:
+ bx_cpu.gen_reg[0].erx = tempAX;
+ bx_cpu.gen_reg[3].erx = tempBX;
+ bx_cpu.gen_reg[1].erx = tempCX;
+ bx_cpu.gen_reg[2].erx = tempDX;
+ this->blocking_on_syscall = true;
+ return;
+ case sidutil::cpu_trap_skip:
+ /* fall-through */
+ case sidutil::cpu_trap_handled:
+ this->blocking_on_syscall = false;
+ return;
+ default:
+ abort ();
+ }
+ this->yield();
+ throw sidutil::cpu_exception();
+}
+
+void
+x86_cpu::do_breakpoint()
+{
+ sidutil::cpu_trap_disposition whatnext = signal_trap(sidutil::cpu_trap_breakpoint, 0);
+
+ switch (whatnext)
+ {
+ case sidutil::cpu_trap_unhandled:
+ cerr << "hw-cpu-x86: cpu breakpoint trap unhandled" << endl;
+ break;
+
+ case sidutil::cpu_trap_skip:
+ case sidutil::cpu_trap_handled:
+ case sidutil::cpu_trap_reissue:
+ break;
+
+ default:
+ abort();
+ }
+ this->yield();
+ throw sidutil::cpu_exception();
+}
+
+void
+x86_cpu::step_insns ()
+{
+ try
+ {
+ if (!this->blocking_on_syscall)
+ bx_cpu.cpu_loop(1);
+ else
+ do_syscall();
+ }
+ catch (sidutil::cpu_exception& t)
+ {
+ this->yield();
+ }
+
+ if (this->enable_step_trap_p)
+ this->signal_trap (sidutil::cpu_trap_stepped);
+}
+
+void
+x86_cpu::reset ()
+{
+ bx_cpu.reset(BX_RESET_HARDWARE);
+
+ if (!in_hardware_mode)
+ enter_protected_mode();
+}
+
+void
+x86_cpu::flush_icache ()
+{
+ bx_cpu.invalidate_prefetch_q();
+}
+
+void
+x86_cpu::set_pc (sid::host_int_4 value)
+{
+ // FIXME: this should check if we're using the extended (32-bit)
+ // instruction pointer or the 16-bit one
+ bx_cpu.eip = value - bx_cpu.sregs[BX_SEG_REG_CS].cache.u.segment.base;
+}
+
+string
+x86_cpu::dbg_get_reg(unsigned int reg)
+{
+ string attr;
+ sid::host_int_4 val;
+ val = bx_cpu.dbg_get_reg(reg + 10);
+
+ // Change to "target endian".
+ sid::little_int_4 v = val;
+ for (unsigned i = 0; i < 4; i++)
+ attr += v.read_byte (i);
+
+ if (verbose_p)
+ cerr << "dbg_get_reg: reg = " << reg << endl;
+
+ return attr;
+}
+
+sid::component::status
+x86_cpu::dbg_set_reg(unsigned int reg, const string &attr)
+{
+ // change from "target endian"
+ sid::little_int_4 v;
+ for (unsigned i = 0; i < 4; i++)
+ v.write_byte (i, attr[i]);
+ sid::host_int_4 val = v;
+
+ if (verbose_p)
+ {
+ cerr << "dbg_set_reg: reg = " << reg;
+ fprintf(stderr, " val = %p\n", val);
+ }
+
+ if(bx_cpu.dbg_set_reg(reg + 10, val))
+ return sid::component::ok;
+ else
+ return sid::component::bad_value;
+}
+
+void
+x86_cpu::interrupt(host_int_4 val)
+{
+ bx_cpu.set_INTR(val);
+}
+
+void
+x86_cpu::hold_request(host_int_4 val)
+{
+ bx_cpu.set_HRQ(val);
+}
+
+void
+x86_cpu::enable_a20(host_int_4 val)
+{
+ if (val)
+ {
+ _a20_enabled = true;
+ a20_mask = 0xffffffff;
+ }
+ else
+ {
+ _a20_enabled = false;
+ a20_mask = 0xffefffff;
+ }
+}
+
+host_int_4
+x86_cpu::a20_enabled(void)
+{
+ if(_a20_enabled)
+ return 1;
+ else
+ return 0;
+}
+
+bool
+x86_cpu::hardware_mode(void)
+{
+ return in_hardware_mode;
+}
+
+void
+x86_cpu::drive_interrupt_acknowledge_pin(void)
+{
+ interrupt_acknowledge_pin.drive(1);
+}
+
+host_int_1
+x86_cpu::interrupt_acknowledged(void)
+{
+ return interrupt_acknowledge_response_pin.sense();
+}
+
+void
+x86_cpu::drive_hold_acknowledge_pin(void)
+{
+ hold_acknowledge_pin.drive(1);
+}
+
+little_int_1
+x86_cpu::read_io_memory_1 (host_int_4 addr)
+{
+ little_int_1 val;
+ bus::status status;
+
+ status = io_memory_bus->read(addr, val);
+
+ if (status != bus::ok)
+ {
+ cerr << "[IOMEM ] operation: read_1" << endl;
+ cerr << "[IOMEM ] addr: " << setbase(16) << addr << setbase(10) << endl;
+ cerr << "[IOMEM ] val: " << setbase(16) << addr << setbase(10) << endl;
+ cerr << "[IOMEM ] status: " << (status == bus::misaligned ? "misaligned" :
+ (status == bus::unmapped ? "unmapped" : "unpermitted")) << endl;
+ // exit(0);
+ }
+ else
+ {
+ return val;
+ }
+}
+
+void
+x86_cpu::write_io_memory_1 (host_int_4 addr, little_int_1 value)
+{
+ bus::status status;
+
+ status = io_memory_bus->write(addr, value);
+
+ if (status != bus::ok)
+ {
+ cerr << "[IOMEM ] operation: write_1" << endl;
+ cerr << "[IOMEM ] addr: " << setbase(16) << addr << setbase(10) << endl;
+ cerr << "[IOMEM ] val: " << setbase(16) << value << setbase(10) << endl;
+ cerr << "[IOMEM ] status: " << (status == bus::misaligned ? "misaligned" :
+ (status == bus::unmapped ? "unmapped" : "unpermitted")) << endl;
+ // exit(0);
+ }
+}
+
+little_int_2
+x86_cpu::read_io_memory_2 (host_int_4 addr)
+{
+ little_int_2 val;
+ bus::status status;
+
+ status = io_memory_bus->read(addr, val);
+
+ if (status != bus::ok)
+ {
+ cerr << "[IOMEM ] operation: read_2" << endl;
+ cerr << "[IOMEM ] addr: " << setbase(16) << addr << setbase(10) << endl;
+ cerr << "[IOMEM ] val: " << setbase(16) << addr << setbase(10) << endl;
+ cerr << "[IOMEM ] status: " << (status == bus::misaligned ? "misaligned" :
+ (status == bus::unmapped ? "unmapped" : "unpermitted")) << endl;
+ // exit(0);
+ }
+ else
+ {
+ return val;
+ }
+}
+
+void
+x86_cpu::write_io_memory_2 (host_int_4 addr, little_int_2 value)
+{
+ bus::status status;
+
+ status = io_memory_bus->write(addr, value);
+
+ if (status != bus::ok)
+ {
+ cerr << "[IOMEM ] operation: write_2" << endl;
+ cerr << "[IOMEM ] addr: " << setbase(16) << addr << setbase(10) << endl;
+ cerr << "[IOMEM ] val: " << setbase(16) << value << setbase(10) << endl;
+ cerr << "[IOMEM ] status: " << (status == bus::misaligned ? "misaligned" :
+ (status == bus::unmapped ? "unmapped" : "unpermitted")) << endl;
+ // exit(0);
+ }
+}
+
+little_int_4
+x86_cpu::read_io_memory_4 (host_int_4 addr)
+{
+ little_int_4 val;
+ bus::status status;
+
+ status = io_memory_bus->read(addr, val);
+
+ if (status != bus::ok)
+ {
+ cerr << "[IOMEM ] operation: read_4" << endl;
+ cerr << "[IOMEM ] addr: " << setbase(16) << addr << setbase(10) << endl;
+ cerr << "[IOMEM ] val: " << setbase(16) << addr << setbase(10) << endl;
+ cerr << "[IOMEM ] status: " << (status == bus::misaligned ? "misaligned" :
+ (status == bus::unmapped ? "unmapped" : "unpermitted")) << endl;
+ // exit(0);
+ }
+ else
+ {
+ return val;
+ }
+}
+
+void
+x86_cpu::write_io_memory_4 (host_int_4 addr, little_int_4 value)
+{
+ bus::status status;
+
+ status = io_memory_bus->write(addr, value);
+
+ if (status != bus::ok)
+ {
+ cerr << "[IOMEM ] operation: write_4" << endl;
+ cerr << "[IOMEM ] addr: " << setbase(16) << addr << setbase(10) << endl;
+ cerr << "[IOMEM ] val: " << setbase(16) << value << setbase(10) << endl;
+ cerr << "[IOMEM ] status: " << (status == bus::misaligned ? "misaligned" :
+ (status == bus::unmapped ? "unmapped" : "unpermitted")) << endl;
+ // exit(0);
+ }
+}
+
--- /dev/null
+// sid-x86-cpu-wrapper.h - class declaration for the sid x86 cpu component. -*- C++ -*-
+//
+// Copyright (C) 2001 Red Hat.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#ifndef __X86_H__
+#define __X86_H__ 1
+#include <sidcomp.h>
+#include <sidcpuutil.h>
+
+#include "bochs.h"
+#include "sid-bochs-memory.h"
+#include "cpu.h"
+
+#define X86_CPU_DEBUG 0
+
+using sid::component;
+using sid::host_int_4;
+using sid::host_int_1;
+using sid::little_int_1;
+using sid::little_int_2;
+using sid::little_int_4;
+using sid::bus;
+using sidutil::callback_pin;
+using sidutil::output_pin;
+using sidutil::input_pin;
+
+class x86_cpu : public sidutil::basic_bi_endian_cpu
+{
+ friend void BX_CPU_C::INSB_YbDX(BxInstruction_t *i);
+ friend void BX_CPU_C::INSW_YvDX(BxInstruction_t *i);
+ friend void BX_CPU_C::OUTSB_DXXb(BxInstruction_t *i);
+ friend void BX_CPU_C::OUTSW_DXXv(BxInstruction_t *i);
+ friend Bit32u BX_CPU_C::inp32(Bit16u addr);
+ friend Bit16u BX_CPU_C::inp16(Bit16u addr);
+ friend Bit8u BX_CPU_C::inp8(Bit16u addr);
+ friend void BX_CPU_C::outp32(Bit16u addr, Bit32u value);
+ friend void BX_CPU_C::outp16(Bit16u addr, Bit16u value);
+ friend void BX_CPU_C::outp8(Bit16u addr, Bit8u value);
+
+ friend void sid_bx_mem_c::read_physical(BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data);
+ friend void sid_bx_mem_c::write_physical(BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data);
+
+public:
+ x86_cpu ();
+ ~x86_cpu () throw () {}
+
+ void do_syscall();
+ void do_breakpoint();
+
+ void step_insns ();
+ void reset ();
+ void flush_icache ();
+ void set_pc (sid::host_int_4 value);
+ string dbg_get_reg(unsigned int);
+ component::status dbg_set_reg(unsigned int, const string &);
+
+ void interrupt(host_int_4 val);
+ void hold_request(host_int_4 val);
+ void enable_a20(host_int_4 val);
+ host_int_4 a20_enabled(void);
+
+ bool hardware_mode(void);
+
+ void drive_hold_acknowledge_pin(void);
+
+ void drive_interrupt_acknowledge_pin(void);
+ host_int_1 interrupt_acknowledged(void);
+
+ host_int_4 a20_mask;
+protected:
+ bx_cpu_c bx_cpu;
+ sid_bx_mem_c bx_mem;
+
+ host_int_4 syscall_error;
+
+ bool warnings_enabled;
+ bool blocking_on_syscall;
+ bool verbose_p;
+
+ callback_pin<x86_cpu> interrupt_pin;
+ output_pin interrupt_acknowledge_pin;
+ input_pin interrupt_acknowledge_response_pin;
+
+ output_pin hold_acknowledge_pin;
+
+ callback_pin<x86_cpu> hold_request_pin;
+
+ callback_pin<x86_cpu> enable_a20_pin;
+ output_pin a20_enabled_pin;
+
+ little_int_1 read_io_memory_1 (host_int_4 addr);
+ void write_io_memory_1 (host_int_4 addr, little_int_1 value);
+
+ little_int_2 read_io_memory_2 (host_int_4 addr);
+ void write_io_memory_2 (host_int_4 addr, little_int_2 value);
+
+ little_int_4 read_io_memory_4 (host_int_4 addr);
+ void write_io_memory_4 (host_int_4 addr, little_int_4 value);
+
+ bus *io_memory_bus;
+
+ bool in_hardware_mode;
+ bool _a20_enabled;
+
+ string memory_mode;
+
+ void enter_protected_mode();
+};
+#endif // __X86_H__
-// x86-memory-modes.cc - set up protected mode. -*- C++ -*-
+// sid-x86-memory-modes.cc - set up protected mode. -*- C++ -*-
//
// Copyright (C) 2001 Red Hat.
//
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#include "x86.h"
+#include "sid-x86-cpu-wrapper.h"
void x86_cpu::enter_protected_mode()
{
+++ /dev/null
-// Copyright (C) 2001 MandrakeSoft S.A.
-//
-// MandrakeSoft S.A.
-// 43, rue d'Aboukir
-// 75002 Paris - France
-// http://www.linux-mandrake.com/
-// http://www.mandrakesoft.com/
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-
-
-
-
-
-
-
-#define NEED_CPU_REG_SHORTCUTS 1
-#include "bochs.h"
-#define LOG_THIS BX_CPU_THIS_PTR
-
-
-
-
-#if 0
- void
-BX_CPU_C::BOUND_GvMa(BxInstruction_t *i)
-{
-#if BX_CPU_LEVEL < 2
- BX_PANIC(("BOUND_GvMa: not supported on 8086!\n"));
-#else
-
- if (i->mod == 0xc0) {
- /* undefined opcode exception */
- BX_PANIC(("bound: op2 must be mem ref\n"));
- UndefinedOpcode(i);
- }
-
- if (i->os_32) {
- Bit32s bound_min, bound_max;
- Bit32s op1_32;
-
- op1_32 = BX_READ_32BIT_REG(i->nnn);
-
- read_virtual_dword(i->seg, i->rm_addr, (Bit32u *) &bound_min);
- read_virtual_dword(i->seg, i->rm_addr+4, (Bit32u *) &bound_max);
-
- /* ??? */
- if ( (op1_32 < bound_min) || (op1_32 > bound_max) ) {
- BX_INFO(("BOUND: fails bounds test\n"));
- exception(5, 0, 0);
- }
- }
- else {
- Bit16s bound_min, bound_max;
- Bit16s op1_16;
-
- op1_16 = BX_READ_16BIT_REG(i->nnn);
-
- read_virtual_word(i->seg, i->rm_addr, (Bit16u *) &bound_min);
- read_virtual_word(i->seg, i->rm_addr+2, (Bit16u *) &bound_max);
-
- /* ??? */
- if ( (op1_16 < bound_min) || (op1_16 > bound_max) ) {
- BX_INFO(("BOUND: fails bounds test\n"));
- exception(5, 0, 0);
- }
- }
-
-#endif
-}
-
- void
-BX_CPU_C::INT1(BxInstruction_t *i)
-{
- // This is an undocumented instrucion (opcode 0xf1)
- // which is useful for an ICE system.
-
-#if BX_DEBUGGER
- BX_CPU_THIS_PTR show_flag |= Flag_int;
-#endif
-
- interrupt(1, 1, 0, 0);
- BX_INSTR_FAR_BRANCH(BX_INSTR_IS_INT,
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
- BX_CPU_THIS_PTR eip);
-}
-#endif
-
- void
-sid_cpu_c::INT3(BxInstruction_t *i)
-{
- // INT 3 is not IOPL sensitive
-
-#if BX_DEBUGGER
- BX_CPU_THIS_PTR show_flag |= Flag_int;
-#endif
-
-//BX_PANIC(("INT3: bailing\n"));
- interrupt(3, 1, 0, 0);
- BX_INSTR_FAR_BRANCH(BX_INSTR_IS_INT,
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
- BX_CPU_THIS_PTR eip);
-}
-
-
- void
-sid_cpu_c::INT_Ib(BxInstruction_t *i)
-{
- Bit8u imm8;
-
-#if BX_DEBUGGER
- BX_CPU_THIS_PTR show_flag |= Flag_int;
-#endif
-
- imm8 = i->Ib;
-
- if (v8086_mode() && (IOPL<3)) {
- //BX_INFO(("int_ib: v8086: IOPL<3\n"));
- exception(BX_GP_EXCEPTION, 0, 0);
- }
-
-#ifdef SHOW_EXIT_STATUS
-if ( (imm8 == 0x21) && (AH == 0x4c) ) {
- BX_INFO(("INT 21/4C called AL=0x%02x, BX=0x%04x\n", (unsigned) AL, (unsigned) BX));
- }
-#endif
-
- interrupt(imm8, 1, 0, 0);
- BX_INSTR_FAR_BRANCH(BX_INSTR_IS_INT,
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
- BX_CPU_THIS_PTR eip);
-}
-#if 0
-
- void
-BX_CPU_C::INTO(BxInstruction_t *i)
-{
-
-#if BX_DEBUGGER
- BX_CPU_THIS_PTR show_flag |= Flag_int;
-#endif
-
- /* ??? is this IOPL sensitive ? */
- if (v8086_mode()) BX_PANIC(("soft_int: v8086 mode unsupported\n"));
-
- if (get_OF()) {
- interrupt(4, 1, 0, 0);
- BX_INSTR_FAR_BRANCH(BX_INSTR_IS_INT,
- BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
- BX_CPU_THIS_PTR eip);
- }
-}
-#endif
}
#endif
-
#endif // BX_SUPPORT_TASKING
}
void
-BX_CPU_C::stack_return_from_v86(BxInstruction_t *i)
+BX_CPU_C::stack_return_from_v86(void)
{
BX_INFO(("stack_return_from_v86:\n"));
v8086_message();
+++ /dev/null
-// x86.cc - member function implementations for the x86 sid component. -*- C++ -*-
-//
-// Copyright (C) 2001 Red Hat.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-#include "x86.h"
-
-x86_cpu::x86_cpu () :
- memory_mode("default"),
- blocking_on_syscall(false),
- verbose_p(false)
-{
- bx_mem.sid_cpu = this;
- bx_cpu.sid_cpu = this;
-
- bx_cpu.init(&bx_mem);
-
- // set up registers for use by gloss component.
- // see libgloss/i386/* for calling conventions
- // and exception-sid.cc for handling of int 0x80
- this->add_watchable_register (string("syscall-arg0"), &bx_cpu.gen_reg[0].erx);
- this->add_watchable_register (string("syscall-arg1"), &bx_cpu.gen_reg[3].erx);
- this->add_watchable_register (string("syscall-arg2"), &bx_cpu.gen_reg[1].erx);
- this->add_watchable_register (string("syscall-arg3"), &bx_cpu.gen_reg[2].erx);
- this->add_watchable_register (string("syscall-result"), &bx_cpu.gen_reg[0].erx);
-
- this->add_watchable_register (string("syscall-trap"), &bx_cpu.gen_reg[0].erx);
- this->add_watchable_register (string("syscall-error"), &syscall_error);
-
- // set up debugging interface
- // there are 16 integer registers
- create_gdb_register_attrs (16, "4;5;8;9", & this->bx_cpu.eip);
-
- this->add_attribute ("enable-warnings?", & warnings_enabled, "setting");
- this->add_attribute ("memory-mode", & memory_mode, "setting");
- this->add_attribute("verbose?", &this->verbose_p, "setting");
-}
-
-void x86_cpu::do_syscall()
-{
- sid::host_int_4 tempAX = bx_cpu.gen_reg[0].erx;
- sid::host_int_4 tempBX = bx_cpu.gen_reg[3].erx;
- sid::host_int_4 tempCX = bx_cpu.gen_reg[1].erx;
- sid::host_int_4 tempDX = bx_cpu.gen_reg[2].erx;
-
- sidutil::cpu_trap_disposition whatnext = signal_trap(sidutil::cpu_trap_software, bx_cpu.gen_reg[0].erx);
-
- switch (whatnext)
- {
- case sidutil::cpu_trap_unhandled:
- cerr << "hw-cpu-x86: cpu syscall trap unhandled" << endl;
- this->blocking_on_syscall = false;
- return;
- case sidutil::cpu_trap_reissue:
- bx_cpu.gen_reg[0].erx = tempAX;
- bx_cpu.gen_reg[3].erx = tempBX;
- bx_cpu.gen_reg[1].erx = tempCX;
- bx_cpu.gen_reg[2].erx = tempDX;
- this->blocking_on_syscall = true;
- return;
- case sidutil::cpu_trap_skip:
- /* fall-through */
- case sidutil::cpu_trap_handled:
- this->blocking_on_syscall = false;
- return;
- default:
- abort ();
- }
- this->yield();
- throw sidutil::cpu_exception();
-}
-
-void x86_cpu::do_breakpoint()
-{
- sidutil::cpu_trap_disposition whatnext = signal_trap(sidutil::cpu_trap_breakpoint, 0);
-
- switch (whatnext)
- {
- case sidutil::cpu_trap_unhandled:
- cerr << "hw-cpu-x86: cpu breakpoint trap unhandled" << endl;
- break;
-
- case sidutil::cpu_trap_skip:
- case sidutil::cpu_trap_handled:
- case sidutil::cpu_trap_reissue:
- break;
-
- default:
- abort();
- }
- this->yield();
- throw sidutil::cpu_exception();
-}
-
-void x86_cpu::step_insns () {
- try {
- if (!this->blocking_on_syscall)
- bx_cpu.cpu_loop(1);
- else
- do_syscall();
- }
- catch (sidutil::cpu_exception& t)
- {
- this->yield();
- }
-
- if (this->enable_step_trap_p)
- this->signal_trap (sidutil::cpu_trap_stepped);
-}
-
-void x86_cpu::reset () {
- bx_cpu.reset(BX_RESET_HARDWARE);
-
- enter_protected_mode();
-}
-
-void x86_cpu::flush_icache () {
- bx_cpu.invalidate_prefetch_q();
-}
-
-void x86_cpu::set_pc (sid::host_int_4 value) {
- // FIXME: this should check if we're using the extended (32-bit)
- // instruction pointer or the 16-bit one
- bx_cpu.eip = value - bx_cpu.sregs[BX_SEG_REG_CS].cache.u.segment.base;
-}
-
-string x86_cpu::dbg_get_reg(unsigned int reg)
-{
- string attr;
- sid::host_int_4 val;
- val = bx_cpu.dbg_get_reg(reg + 10);
-
- // Change to "target endian".
- sid::little_int_4 v = val;
- for (unsigned i = 0; i < 4; i++)
- attr += v.read_byte (i);
-
- if (verbose_p)
- cerr << "dbg_get_reg: reg = " << reg << endl;
-
- return attr;
-}
-
-sid::component::status x86_cpu::dbg_set_reg(unsigned int reg, const string &attr)
-{
- // change from "target endian"
- sid::little_int_4 v;
- for (unsigned i = 0; i < 4; i++)
- v.write_byte (i, attr[i]);
- sid::host_int_4 val = v;
-
- if (verbose_p)
- {
- cerr << "dbg_set_reg: reg = " << reg;
- fprintf(stderr, " val = %p\n", val);
- }
-
- if(bx_cpu.dbg_set_reg(reg + 10, val))
- return sid::component::ok;
- else
- return sid::component::bad_value;
-}
-
+++ /dev/null
-// x86.h - x86_cpu class declaration for the x86 sid component. -*- C++ -*-
-//
-// Copyright (C) 2001 Red Hat.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-#ifndef __X86_H__
-#define __X86_H__ 1
-#include "sidcomp.h"
-#include "sidcpuutil.h"
-#include "bochs.h"
-#include "memory-sid.h"
-#include "cpu-sid.h"
-
-#define X86_CPU_DEBUG 0
-
-class x86_cpu : public sidutil::basic_bi_endian_cpu {
- friend void sid_mem_c::read_physical(BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data);
- friend void sid_mem_c::write_physical(BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data);
- public:
- sid_cpu_c bx_cpu;
- sid_mem_c bx_mem;
-
- sid::host_int_4 syscall_error;
-
- bool warnings_enabled;
- bool blocking_on_syscall;
- bool verbose_p;
-
- x86_cpu ();
- ~x86_cpu () throw () {}
-
- void do_syscall();
- void do_breakpoint();
-
- void step_insns ();
- void reset ();
- void flush_icache ();
- void set_pc (sid::host_int_4 value);
- string dbg_get_reg(unsigned int);
- sid::component::status dbg_set_reg(unsigned int, const string &);
- private:
- string memory_mode;
-
- void enter_protected_mode();
-
-};
-
-#endif // __X86_H__
--- /dev/null
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+// if including from C parser, need basic types etc
+#include "config.h"
+#if BX_DEBUGGER
+#include "osdep.h"
+#endif
+#if BX_USE_LOADER
+#include "loader_misc.h"
+void bx_dbg_loader(char *path, bx_loader_misc_t *misc_ptr);
+#endif
+
+#if BX_DBG_ICOUNT_SIZE == 32
+ typedef Bit32u bx_dbg_icount_t;
+#elif BX_DBG_ICOUNT_SIZE == 64
+ typedef Bit64u bx_dbg_icount_t;
+#else
+# error "BX_DBG_ICOUNT_SIZE incorrect."
+#endif
+
+
+#define BX_DBG_NO_HANDLE 1000
+
+extern Bit32u dbg_cpu;
+
+unsigned long crc32(unsigned char *buf, int len);
+
+#if BX_DEBUGGER
+
+// some strict C declarations needed by the parser/lexer
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Flex defs
+extern int bxlex(void);
+extern char *bxtext; // Using the pointer option rather than array
+extern int bxwrap(void);
+void bx_add_lex_input(char *buf);
+
+// Yacc defs
+extern int bxparse(void);
+extern void bxerror(char *s);
+
+typedef struct {
+ Bit64s from;
+ Bit64s to;
+} bx_num_range;
+#define EMPTY_ARG (-1)
+
+bx_num_range make_num_range (Bit64s from, Bit64s to);
+char* bx_dbg_symbolic_address(Bit32u context, Bit32u eip, Bit32u base);
+void bx_dbg_symbol_command(char* filename, Boolean global, Bit32u offset);
+void bx_dbg_trace_on_command(void);
+void bx_dbg_trace_off_command(void);
+void bx_dbg_ptime_command(void);
+void bx_dbg_timebp_command(Boolean absolute, Bit64u time);
+void bx_dbg_diff_memory(void);
+void bx_dbg_always_check(Bit32u page_start, Boolean on);
+void bx_dbg_sync_memory(Boolean set);
+void bx_dbg_sync_cpu(Boolean set);
+void bx_dbg_fast_forward(Bit32u num);
+void bx_dbg_info_address(Bit32u seg_reg_num, Bit32u offset);
+#define MAX_CONCURRENT_BPS 5
+extern int timebp_timer;
+extern Bit64u timebp_queue[MAX_CONCURRENT_BPS];
+extern int timebp_queue_size;
+void bx_dbg_record_command(char*);
+void bx_dbg_playback_command(char*);
+void bx_dbg_modebp_command(char*); /* BW */
+void bx_dbg_where_command(void);
+void bx_dbg_print_string_command(Bit32u addr);
+void bx_dbg_show_command(char*); /* BW */
+void enter_playback_entry();
+void bx_dbg_print_stack_command(int nwords);
+void bx_dbg_watch(int read, Bit32u address);
+void bx_dbg_unwatch(int read, Bit32u address);
+void bx_dbg_continue_command(void);
+void bx_dbg_stepN_command(bx_dbg_icount_t count);
+void bx_dbg_set_command(char *p1, char *p2, char *p3);
+void bx_dbg_del_breakpoint_command(unsigned handle);
+void bx_dbg_vbreakpoint_command(Boolean specific, Bit32u cs, Bit32u eip);
+void bx_dbg_lbreakpoint_command(Boolean specific, Bit32u laddress);
+void bx_dbg_pbreakpoint_command(Boolean specific, Bit32u paddress);
+void bx_dbg_info_bpoints_command(void);
+void bx_dbg_quit_command(void);
+void bx_dbg_info_program_command(void);
+void bx_dbg_info_registers_command(void);
+void bx_dbg_info_dirty_command(void);
+void bx_dbg_info_idt_command(bx_num_range);
+void bx_dbg_info_gdt_command(bx_num_range);
+void bx_dbg_info_ldt_command(bx_num_range);
+void bx_dbg_info_tss_command(bx_num_range);
+void bx_dbg_info_control_regs_command(void);
+void bx_dbg_info_linux_command(void);
+void bx_dbg_examine_command(char *command, char *format, Boolean format_passed,
+ Bit32u addr, Boolean addr_passed, int simulator);
+void bx_dbg_setpmem_command(Bit32u addr, unsigned len, Bit32u val);
+void bx_dbg_set_symbol_command(char *symbol, Bit32u val);
+void bx_dbg_query_command(char *);
+void bx_dbg_take_command(char *, unsigned n);
+void bx_dbg_dump_cpu_command(void);
+void bx_dbg_set_cpu_command(void);
+void bx_dbg_disassemble_command(bx_num_range);
+void bx_dbg_instrument_command(char *);
+void bx_dbg_loader_command(char *);
+void bx_dbg_doit_command(unsigned);
+void bx_dbg_crc_command(Bit32u addr1, Bit32u addr2);
+void bx_dbg_maths_command(char *command, int data1, int data2);
+void bx_dbg_maths_expression_command(char *expr);
+void bx_dbg_v2l_command(unsigned seg_no, Bit32u offset);
+extern Boolean watchpoint_continue;
+void bx_dbg_linux_syscall ();
+
+#ifdef __cplusplus
+}
+#endif
+
+// the rest for C++
+#ifdef __cplusplus
+
+// (mch) Read/write watchpoint hack
+#define MAX_WRITE_WATCHPOINTS 16
+#define MAX_READ_WATCHPOINTS 16
+extern int num_write_watchpoints;
+extern Bit32u write_watchpoint[MAX_WRITE_WATCHPOINTS];
+extern int num_read_watchpoints;
+extern Bit32u read_watchpoint[MAX_READ_WATCHPOINTS];
+
+typedef enum {
+ STOP_NO_REASON = 0, STOP_TIME_BREAK_POINT, STOP_READ_WATCH_POINT, STOP_WRITE_WATCH_POINT, STOP_MAGIC_BREAK_POINT, STOP_TRACE, STOP_MODE_BREAK_POINT, STOP_CPU_HALTED
+} stop_reason_t;
+
+typedef enum {
+ BREAK_POINT_MAGIC, BREAK_POINT_READ, BREAK_POINT_WRITE, BREAK_POINT_TIME
+} break_point_t;
+#endif // __cplusplus
+#endif // BX_DEBUGGER
+#ifdef __cplusplus
+#define BX_DBG_REG_EAX 10
+#define BX_DBG_REG_ECX 11
+#define BX_DBG_REG_EDX 12
+#define BX_DBG_REG_EBX 13
+#define BX_DBG_REG_ESP 14
+#define BX_DBG_REG_EBP 15
+#define BX_DBG_REG_ESI 16
+#define BX_DBG_REG_EDI 17
+#define BX_DBG_REG_EIP 18
+#define BX_DBG_REG_EFLAGS 19
+#define BX_DBG_REG_CS 20
+#define BX_DBG_REG_SS 21
+#define BX_DBG_REG_DS 22
+#define BX_DBG_REG_ES 23
+#define BX_DBG_REG_FS 24
+#define BX_DBG_REG_GS 25
+#endif // __cplusplus
+#if BX_DEBUGGER
+#ifdef __cplusplus
+#define BX_DBG_PENDING_DMA 1
+#define BX_DBG_PENDING_IRQ 2
+
+
+
+
+void bx_dbg_exit(int code);
+#if BX_DBG_EXTENSIONS
+ int bx_dbg_extensions(char *command);
+#else
+#define bx_dbg_extensions(command) 0
+#endif
+
+
+//
+// code for guards...
+//
+
+#define BX_DBG_GUARD_INSTR_BEGIN 0x0001
+#define BX_DBG_GUARD_INSTR_END 0x0002
+#define BX_DBG_GUARD_EXCEP_BEGIN 0x0004
+#define BX_DBG_GUARD_EXCEP_END 0x0008
+#define BX_DBG_GUARD_INTER_BEGIN 0x0010
+#define BX_DBG_GUARD_INTER_END 0x0020
+#define BX_DBG_GUARD_INSTR_MAP 0x0040
+
+// following 3 go along with BX_DBG_GUARD_INSTR_BEGIN
+// to provide breakpointing
+#define BX_DBG_GUARD_IADDR_VIR 0x0080
+#define BX_DBG_GUARD_IADDR_LIN 0x0100
+#define BX_DBG_GUARD_IADDR_PHY 0x0200
+#define BX_DBG_GUARD_IADDR_ALL (BX_DBG_GUARD_IADDR_VIR | \
+ BX_DBG_GUARD_IADDR_LIN | \
+ BX_DBG_GUARD_IADDR_PHY)
+
+#define BX_DBG_GUARD_ICOUNT 0x0400
+#define BX_DBG_GUARD_CTRL_C 0x0800
+
+
+typedef struct {
+ unsigned long guard_for;
+
+ // instruction address breakpoints
+ struct {
+#if BX_DBG_SUPPORT_VIR_BPOINT
+ unsigned num_virtual;
+ struct {
+ Bit32u cs; // only use 16 bits
+ Bit32u eip;
+ unsigned bpoint_id;
+ } vir[BX_DBG_MAX_VIR_BPOINTS];
+#endif
+
+#if BX_DBG_SUPPORT_LIN_BPOINT
+ unsigned num_linear;
+ struct {
+ Bit32u addr;
+ unsigned bpoint_id;
+ } lin[BX_DBG_MAX_LIN_BPOINTS];
+#endif
+
+#if BX_DBG_SUPPORT_PHY_BPOINT
+ unsigned num_physical;
+ struct {
+ Bit32u addr;
+ unsigned bpoint_id;
+ } phy[BX_DBG_MAX_PHY_BPOINTS];
+#endif
+ } iaddr;
+
+ bx_dbg_icount_t icount; // stop after completing this many instructions
+
+ // user typed Ctrl-C, requesting simulator stop at next convient spot
+ volatile Boolean interrupt_requested;
+
+ // booleans to control whether simulator should report events
+ // to debug controller
+ struct {
+ Boolean irq;
+ Boolean a20;
+ Boolean io;
+ Boolean ucmem;
+ Boolean dma;
+ } report;
+
+ struct {
+ Boolean irq; // should process IRQs asynchronously
+ Boolean dma; // should process DMAs asynchronously
+ } async;
+
+#define BX_DBG_ASYNC_PENDING_A20 0x01
+#define BX_DBG_ASYNC_PENDING_RESET 0x02
+#define BX_DBG_ASYNC_PENDING_NMI 0x04
+
+ // Asynchronous changes which are pending. These are Q'd by
+ // the debugger, as the master simulator is notified of a pending
+ // async change. At the simulator's next point, where it checks for
+ // such events, it notifies the debugger with acknowlegement. This
+ // field contains a logically or'd list of all events which should
+ // be checked, and ack'd.
+ struct {
+ unsigned which; // logical OR of above constants
+ Boolean a20;
+ Boolean reset;
+ Boolean nmi;
+ } async_changes_pending;
+ } bx_guard_t;
+
+// working information for each simulator to update when a guard
+// is reached (found)
+typedef struct bx_guard_found_t {
+ unsigned long guard_found;
+ unsigned iaddr_index;
+ bx_dbg_icount_t icount; // number of completed instructions
+ Bit32u cs; // cs:eip and linear addr of instruction at guard point
+ Bit32u eip;
+ Bit32u laddr;
+ Boolean is_32bit_code; // CS seg size at guard point
+ Boolean ctrl_c; // simulator stopped due to Ctrl-C request
+ } bx_guard_found_t;
+
+extern bx_guard_t bx_guard;
+
+
+
+
+
+int bx_dbg_main(int argc, char *argv[]);
+void bx_dbg_user_input_loop(void);
+
+
+typedef struct {
+ Bit16u sel;
+ Bit32u des_l, des_h, valid;
+ } bx_dbg_sreg_t;
+
+typedef struct {
+ Bit32u eax;
+ Bit32u ebx;
+ Bit32u ecx;
+ Bit32u edx;
+ Bit32u ebp;
+ Bit32u esi;
+ Bit32u edi;
+ Bit32u esp;
+ Bit32u eflags;
+ Bit32u eip;
+ bx_dbg_sreg_t cs;
+ bx_dbg_sreg_t ss;
+ bx_dbg_sreg_t ds;
+ bx_dbg_sreg_t es;
+ bx_dbg_sreg_t fs;
+ bx_dbg_sreg_t gs;
+ bx_dbg_sreg_t ldtr;
+ bx_dbg_sreg_t tr;
+ struct { Bit32u base, limit; } gdtr;
+ struct { Bit32u base, limit; } idtr;
+ Bit32u dr0, dr1, dr2, dr3, dr6, dr7;
+ Bit32u tr3, tr4, tr5, tr6, tr7;
+ Bit32u cr0, cr1, cr2, cr3, cr4;
+ unsigned inhibit_mask;
+ } bx_dbg_cpu_t;
+
+
+
+
+typedef struct {
+ // call back functions specific to each simulator
+ Boolean (*setphymem)(Bit32u addr, unsigned len, Bit8u *buf);
+ Boolean (*getphymem)(Bit32u addr, unsigned len, Bit8u *buf);
+ void (*xlate_linear2phy)(Bit32u linear, Bit32u *phy, Boolean *valid);
+ Boolean (*set_reg)(unsigned reg, Bit32u val);
+ Bit32u (*get_reg)(unsigned reg);
+ Boolean (*get_sreg)(bx_dbg_sreg_t *sreg, unsigned sreg_no);
+ Boolean (*set_cpu)(bx_dbg_cpu_t *cpu);
+ Boolean (*get_cpu)(bx_dbg_cpu_t *cpu);
+ unsigned dirty_page_tbl_size;
+ unsigned char *dirty_page_tbl;
+ void (*atexit)(void);
+ unsigned (*query_pending)(void);
+ void (*execute)(void);
+ void (*take_irq)(void);
+ void (*take_dma)(void);
+ void (*reset_cpu)(unsigned source);
+ void (*init_mem)(int size_in_bytes);
+ void (*load_ROM)(const char *path, Bit32u romaddress);
+
+ // for asynchronous environment handling
+ void (*set_A20)(unsigned val);
+ void (*set_NMI)(unsigned val);
+ void (*set_RESET)(unsigned val);
+ void (*set_INTR)(unsigned val);
+ void (*force_interrupt)(unsigned vector);
+
+#if BX_INSTRUMENTATION
+ void (*instr_start)(void);
+ void (*instr_stop)(void);
+ void (*instr_reset)(void);
+ void (*instr_print)(void);
+#endif
+#if BX_USE_LOADER
+ void (*loader)(char *path, bx_loader_misc_t *misc_ptr);
+#endif
+ Boolean (*crc32)(unsigned long (*f)(unsigned char *buf, int len),
+ Bit32u addr1, Bit32u addr2, Bit32u *crc);
+ } bx_dbg_callback_t;
+
+extern bx_dbg_callback_t bx_dbg_callback[BX_NUM_SIMULATORS];
+
+void BX_SIM1_INIT(bx_dbg_callback_t *, int argc, char *argv[]);
+#ifdef BX_SIM2_INIT
+void BX_SIM2_INIT(bx_dbg_callback_t *, int argc, char *argv[]);
+#endif
+
+
+void bx_dbg_dma_report(Bit32u addr, unsigned len, unsigned what, Bit32u val);
+void bx_dbg_iac_report(unsigned vector, unsigned irq);
+void bx_dbg_a20_report(unsigned val);
+void bx_dbg_io_report(Bit32u addr, unsigned size, unsigned op, Bit32u val);
+void bx_dbg_ucmem_report(Bit32u addr, unsigned size, unsigned op, Bit32u val);
+
+Bit8u bx_dbg_ucmem_read(Bit32u addr);
+void bx_dbg_ucmem_write(Bit32u addr, Bit8u value);
+void bx_dbg_async_pin_request(unsigned what, Boolean val);
+void bx_dbg_async_pin_ack(unsigned what, Boolean val);
+Bit32u bx_dbg_inp(Bit16u addr, unsigned len);
+void bx_dbg_outp(Bit16u addr, Bit32u value, unsigned len);
+void bx_dbg_raise_HLDA(void);
+Bit8u bx_dbg_IAC(void);
+void bx_dbg_set_INTR(Boolean b);
+
+int bx_dbg_symbolic_output(void); /* BW */
+#endif // #ifdef __cplusplus
+#endif // #if BX_DEBUGGER
--- /dev/null
+## Process this with automake to create Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(top_builddir)/../../include -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../../../include -I$(srcdir)/../cpu
+
+noinst_LTLIBRARIES = libdma.la
+
+libdma_la_SOURCES = sid-dma-wrapper.cc sid-dma-wrapper.h dma.cc dma.h
+
+libdma_la_LDFLAGS = -no-undefined
--- /dev/null
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+APIC_OBJS = @APIC_OBJS@
+AR = @AR@
+AS = @AS@
+AS_DYNAMIC_INCS = @AS_DYNAMIC_INCS@
+AS_DYNAMIC_OBJS = @AS_DYNAMIC_OBJS@
+BX_LOADER_OBJS = @BX_LOADER_OBJS@
+BX_SPLIT_HD_SUPPORT = @BX_SPLIT_HD_SUPPORT@
+CC = @CC@
+CDROM_OBJS = @CDROM_OBJS@
+CD_UP_ONE = @CD_UP_ONE@
+CD_UP_TWO = @CD_UP_TWO@
+CFP = @CFP@
+COMMAND_SEPARATOR = @COMMAND_SEPARATOR@
+CPP_SUFFIX = @CPP_SUFFIX@
+CXX = @CXX@
+CXXFP = @CXXFP@
+DASH = @DASH@
+DEBUGGER_VAR = @DEBUGGER_VAR@
+DISASM_VAR = @DISASM_VAR@
+DLLTOOL = @DLLTOOL@
+DYNAMIC_VAR = @DYNAMIC_VAR@
+EXE = @EXE@
+EXEEXT = @EXEEXT@
+EXTERNAL_DEPENDENCY = @EXTERNAL_DEPENDENCY@
+FPU_GLUE_OBJ = @FPU_GLUE_OBJ@
+FPU_VAR = @FPU_VAR@
+GUI_LINK_OPTS = @GUI_LINK_OPTS@
+GUI_LINK_OPTS_TERM = @GUI_LINK_OPTS_TERM@
+GUI_OBJS = @GUI_OBJS@
+GZIP = @GZIP@
+INLINE_VAR = @INLINE_VAR@
+INSTRUMENT_DIR = @INSTRUMENT_DIR@
+INSTRUMENT_VAR = @INSTRUMENT_VAR@
+IOAPIC_OBJS = @IOAPIC_OBJS@
+IODEV_LIB_VAR = @IODEV_LIB_VAR@
+LD = @LD@
+LIBTOOL = @LIBTOOL@
+LINK = @LINK@
+LN_S = @LN_S@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MAKELIB = @MAKELIB@
+NE2K_OBJS = @NE2K_OBJS@
+NM = @NM@
+NONINLINE_VAR = @NONINLINE_VAR@
+OBJDUMP = @OBJDUMP@
+OFP = @OFP@
+PACKAGE = @PACKAGE@
+PCI_OBJ = @PCI_OBJ@
+PRIMARY_TARGET = @PRIMARY_TARGET@
+RANLIB = @RANLIB@
+READLINE_LIB = @READLINE_LIB@
+RFB_LIBS = @RFB_LIBS@
+RMCOMMAND = @RMCOMMAND@
+SB16_OBJS = @SB16_OBJS@
+SLASH = @SLASH@
+SUFFIX_LINE = @SUFFIX_LINE@
+TAR = @TAR@
+VERSION = @VERSION@
+VIDEO_OBJS = @VIDEO_OBJS@
+sidtarget_arm = @sidtarget_arm@
+sidtarget_m32r = @sidtarget_m32r@
+sidtarget_m68k = @sidtarget_m68k@
+sidtarget_mips = @sidtarget_mips@
+sidtarget_ppc = @sidtarget_ppc@
+sidtarget_x86 = @sidtarget_x86@
+sidtarget_xstormy16 = @sidtarget_xstormy16@
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(top_builddir)/../../include -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../../../include -I$(srcdir)/../cpu
+
+noinst_LTLIBRARIES = libdma.la
+
+libdma_la_SOURCES = sid-dma-wrapper.cc sid-dma-wrapper.h dma.cc dma.h
+
+libdma_la_LDFLAGS = -no-undefined
+mkinstalldirs = $(SHELL) $(top_srcdir)/../../config/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_LIBS = @X_LIBS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+libdma_la_LIBADD =
+libdma_la_OBJECTS = sid-dma-wrapper.lo dma.lo
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+DIST_COMMON = Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+GZIP_ENV = --best
+DEP_FILES = .deps/dma.P .deps/sid-dma-wrapper.P
+SOURCES = $(libdma_la_SOURCES)
+OBJECTS = $(libdma_la_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .cc .lo .o .s
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --foreign dma/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLTLIBRARIES:
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+
+distclean-noinstLTLIBRARIES:
+
+maintainer-clean-noinstLTLIBRARIES:
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.s.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+libdma.la: $(libdma_la_OBJECTS) $(libdma_la_DEPENDENCIES)
+ $(CXXLINK) $(libdma_la_LDFLAGS) $(libdma_la_OBJECTS) $(libdma_la_LIBADD) $(LIBS)
+.cc.o:
+ $(CXXCOMPILE) -c $<
+.cc.lo:
+ $(LTCXXCOMPILE) -c $<
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = dma
+
+distdir: $(DISTFILES)
+ here=`cd $(top_builddir) && pwd`; \
+ top_distdir=`cd $(top_distdir) && pwd`; \
+ distdir=`cd $(distdir) && pwd`; \
+ cd $(top_srcdir) \
+ && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --foreign dma/Makefile
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+ -rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+ @echo '$(COMPILE) -c $<'; \
+ $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.c
+ @echo '$(LTCOMPILE) -c $<'; \
+ $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+
+%.o: %.cc
+ @echo '$(CXXCOMPILE) -c $<'; \
+ $(CXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.cc
+ @echo '$(LTCXXCOMPILE) -c $<'; \
+ $(LTCXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LTLIBRARIES)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-noinstLTLIBRARIES mostlyclean-compile \
+ mostlyclean-libtool mostlyclean-tags mostlyclean-depend \
+ mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-noinstLTLIBRARIES clean-compile clean-libtool \
+ clean-tags clean-depend clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-noinstLTLIBRARIES distclean-compile \
+ distclean-libtool distclean-tags distclean-depend \
+ distclean-generic clean-am
+ -rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-noinstLTLIBRARIES \
+ maintainer-clean-compile maintainer-clean-libtool \
+ maintainer-clean-tags maintainer-clean-depend \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLTLIBRARIES distclean-noinstLTLIBRARIES \
+clean-noinstLTLIBRARIES maintainer-clean-noinstLTLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-libtool distclean-libtool \
+clean-libtool maintainer-clean-libtool tags mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir \
+mostlyclean-depend distclean-depend clean-depend \
+maintainer-clean-depend info-am info dvi-am dvi check check-am \
+installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+#include "bochs.h"
+#if BX_SUPPORT_SID
+#define LOG_THIS
+#else
+#define LOG_THIS bx_dma.
+#endif
+
+#define DMA_MODE_DEMAND 0
+#define DMA_MODE_SINGLE 1
+#define DMA_MODE_BLOCK 2
+#define DMA_MODE_CASCADE 3
+
+
+
+#if BX_SUPPORT_SID
+#include "sid-dma-wrapper.h"
+#else
+bx_dma_c bx_dma;
+#endif
+#if BX_USE_DMA_SMF
+#define this (&bx_dma)
+#endif
+
+
+
+bx_dma_c::bx_dma_c(void)
+{
+#if BX_SUPPORT_SID
+ bx_dbg.dma = 1;
+#endif
+ setprefix("[DMA ]");
+ settype(DMALOG);
+ BX_DEBUG(("Init.\n"));
+}
+
+bx_dma_c::~bx_dma_c(void)
+{
+ BX_DEBUG(("Exit.\n"));
+}
+
+
+#if BX_SUPPORT_SID
+void
+bx_dma_c::init(dma *dma_comp)
+#else
+ void
+bx_dma_c::init(bx_devices_c *d)
+#endif
+{
+ unsigned c;
+
+#if BX_SUPPORT_SID==0
+ BX_DMA_THIS devices = d;
+
+ /* 8237 DMA controller */
+
+ // 0000..000F
+ unsigned i;
+ for (i=0x0000; i<=0x000F; i++) {
+ BX_DMA_THIS devices->register_io_read_handler(this, read_handler,
+ i, "DMA controller");
+ BX_DMA_THIS devices->register_io_write_handler(this, write_handler,
+ i, "DMA controller");
+ }
+
+ // 00081..008D
+ for (i=0x0081; i<=0x008D; i++) {
+ BX_DMA_THIS devices->register_io_read_handler(this, read_handler,
+ i, "DMA controller");
+ BX_DMA_THIS devices->register_io_write_handler(this, write_handler,
+ i, "DMA controller");
+ }
+
+ // 0008F..008F
+ for (i=0x008F; i<=0x008F; i++) {
+ BX_DMA_THIS devices->register_io_read_handler(this, read_handler,
+ i, "DMA controller");
+ BX_DMA_THIS devices->register_io_write_handler(this, write_handler,
+ i, "DMA controller");
+ }
+
+ // 000C0..00DE
+ for (i=0x00C0; i<=0x00DE; i++) {
+ BX_DMA_THIS devices->register_io_read_handler(this, read_handler,
+ i, "DMA controller");
+ BX_DMA_THIS devices->register_io_write_handler(this, write_handler,
+ i, "DMA controller");
+ }
+#endif
+
+
+ BX_DMA_THIS s.mask[0] = 1; // channel 0 masked
+ BX_DMA_THIS s.mask[1] = 1; // channel 1 masked
+ BX_DMA_THIS s.mask[2] = 1; // channel 2 masked
+ BX_DMA_THIS s.mask[3] = 1; // channel 3 masked
+
+ BX_DMA_THIS s.flip_flop = 0; /* cleared */
+ BX_DMA_THIS s.status_reg = 0; // no requests, no terminal counts reached
+ for (c=0; c<4; c++) {
+ BX_DMA_THIS s.chan[c].mode.mode_type = 0; // demand mode
+ BX_DMA_THIS s.chan[c].mode.address_decrement = 0; // address increment
+ BX_DMA_THIS s.chan[c].mode.autoinit_enable = 0; // autoinit disable
+ BX_DMA_THIS s.chan[c].mode.transfer_type = 0; // verify
+ BX_DMA_THIS s.chan[c].base_address = 0;
+ BX_DMA_THIS s.chan[c].current_address = 0;
+ BX_DMA_THIS s.chan[c].base_count = 0;
+ BX_DMA_THIS s.chan[c].current_count = 0;
+ BX_DMA_THIS s.chan[c].page_reg = 0;
+ }
+#if BX_SUPPORT_SID
+ dma_component = dma_comp;
+#endif
+}
+
+
+
+ // index to find channel from register number (only [0],[1],[2],[6] used)
+ Bit8u channelindex[7] = {2, 3, 1, 0, 0, 0, 0};
+
+
+ // static IO port read callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ Bit32u
+bx_dma_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_DMA_SMF
+ bx_dma_c *class_ptr = (bx_dma_c *) this_ptr;
+
+ return( class_ptr->read(address, io_len) );
+}
+
+ /* 8237 DMA controller */
+ Bit32u
+bx_dma_c::read( Bit32u address, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_DMA_SMF
+
+ Bit8u retval;
+ Bit8u channel;
+
+ if (io_len > 1) {
+ BX_PANIC(("dma: io read from address %08x, len=%u\n",
+ (unsigned) address, (unsigned) io_len));
+ }
+
+ if (bx_dbg.dma)
+ BX_INFO(("dma: read addr=%04x\n", (unsigned) address));
+
+#if BX_DMA_FLOPPY_IO < 1
+ /* if we're not supporting DMA/floppy IO just return a bogus value */
+ return(0xff);
+#endif
+
+ switch (address) {
+ case 0x00: /* DMA-1 current address, channel 0 */
+ case 0x02: /* DMA-1 current address, channel 1 */
+ case 0x04: /* DMA-1 current address, channel 2 */
+ case 0x06: /* DMA-1 current address, channel 3 */
+ channel = address >> 1;
+ if (BX_DMA_THIS s.flip_flop==0) {
+ BX_DMA_THIS s.flip_flop = !BX_DMA_THIS s.flip_flop;
+ return(BX_DMA_THIS s.chan[channel].current_address & 0xff);
+ }
+ else {
+ BX_DMA_THIS s.flip_flop = !BX_DMA_THIS s.flip_flop;
+ return(BX_DMA_THIS s.chan[channel].current_address >> 8);
+ }
+
+ case 0x01: /* DMA-1 current count, channel 0 */
+ case 0x03: /* DMA-1 current count, channel 1 */
+ case 0x05: /* DMA-1 current count, channel 2 */
+ case 0x07: /* DMA-1 current count, channel 3 */
+ channel = address >> 1;
+ if (BX_DMA_THIS s.flip_flop==0) {
+ BX_DMA_THIS s.flip_flop = !BX_DMA_THIS s.flip_flop;
+ return(BX_DMA_THIS s.chan[channel].current_count & 0xff);
+ }
+ else {
+ BX_DMA_THIS s.flip_flop = !BX_DMA_THIS s.flip_flop;
+ return(BX_DMA_THIS s.chan[channel].current_count >> 8);
+ }
+
+ case 0x08: // DMA-1 Status Register
+ // bit 7: 1 = channel 3 request
+ // bit 6: 1 = channel 2 request
+ // bit 5: 1 = channel 1 request
+ // bit 4: 1 = channel 0 request
+ // bit 3: 1 = channel 3 has reached terminal count
+ // bit 2: 1 = channel 2 has reached terminal count
+ // bit 1: 1 = channel 1 has reached terminal count
+ // bit 0: 1 = channel 0 has reached terminal count
+ // reading this register clears lower 4 bits (hold flags)
+ retval = BX_DMA_THIS s.status_reg;
+ BX_DMA_THIS s.status_reg &= 0xf0;
+ return(retval);
+ break;
+ case 0x0d: // dma-1: temporary register
+ BX_PANIC(("dma-1: read of temporary register\n"));
+ // Note: write to 0x0D clears temporary register
+ return(0);
+ break;
+
+ case 0x0081: // DMA-1 page register, channel 2
+ case 0x0082: // DMA-1 page register, channel 3
+ case 0x0083: // DMA-1 page register, channel 1
+ case 0x0087: // DMA-1 page register, channel 0
+ channel = channelindex[address - 0x81];
+ return( BX_DMA_THIS s.chan[channel].page_reg );
+
+ case 0x0084: // ???
+ return(0);
+
+ case 0x0089: // DMA-2 page register, channel 6
+ case 0x008a: // DMA-2 page register, channel 7
+ case 0x008b: // DMA-2 page register, channel 5
+ case 0x008f: // DMA-2 page register, channel 4
+ channel = channelindex[address - 0x89] + 4;
+ BX_INFO(("dma: read: unsupported address=%04x (channel %d)\n",
+ (unsigned) address, channel));
+ return( 0x00 );
+
+ case 0x00c0:
+ case 0x00c2:
+ case 0x00c4:
+ case 0x00c6:
+ case 0x00c8:
+ case 0x00ca:
+ case 0x00cc:
+ case 0x00ce:
+ case 0x00d0:
+ case 0x00d2:
+ case 0x00d4:
+ case 0x00d6:
+ case 0x00d8:
+ case 0x00da:
+ case 0x00dc:
+ case 0x00de:
+ BX_INFO(("dma: read: unsupported address=%04x\n", (unsigned) address));
+ return(0x0000);
+ break;
+
+ default:
+ BX_PANIC(("dma: read: unsupported address=%04x\n", (unsigned) address));
+ return(0);
+ }
+}
+
+
+ // static IO port write callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ void
+bx_dma_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_DMA_SMF
+ bx_dma_c *class_ptr = (bx_dma_c *) this_ptr;
+
+ class_ptr->write(address, value, io_len);
+}
+
+
+ /* 8237 DMA controller */
+ void
+bx_dma_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_DMA_SMF
+ Bit8u set_mask_bit;
+ Bit8u channel;
+
+ if (io_len > 1) {
+ if ( (io_len == 2) && (address == 0x0b) ) {
+#if BX_USE_DMA_SMF
+ BX_DMA_THIS write_handler(NULL, address, value & 0xff, 1);
+ BX_DMA_THIS write_handler(NULL, address+1, value >> 8, 1);
+#else
+ BX_DMA_THIS write(address, value & 0xff, 1);
+ BX_DMA_THIS write(address+1, value >> 8, 1);
+#endif
+ return;
+ }
+
+ BX_PANIC(("dma: io write to address %08x, len=%u\n",
+ (unsigned) address, (unsigned) io_len));
+ }
+
+ if (bx_dbg.dma)
+ BX_INFO(("\ndma: write: address=%04x value=%02x\n",
+ (unsigned) address, (unsigned) value));
+
+#if BX_DMA_FLOPPY_IO < 1
+ /* if we're not supporting DMA/floppy IO just return */
+ return;
+#endif
+
+ switch (address) {
+ case 0x00:
+ case 0x02:
+ case 0x04:
+ case 0x06:
+ channel = address >> 1;
+ if (bx_dbg.dma)
+ BX_INFO((" DMA-1 base and current address, channel %d\n", channel));
+ if (BX_DMA_THIS s.flip_flop==0) { /* 1st byte */
+ BX_DMA_THIS s.chan[channel].base_address = value;
+ BX_DMA_THIS s.chan[channel].current_address = value;
+ }
+ else { /* 2nd byte */
+ BX_DMA_THIS s.chan[channel].base_address |= (value << 8);
+ BX_DMA_THIS s.chan[channel].current_address |= (value << 8);
+ if (bx_dbg.dma) {
+ BX_INFO((" base = %04x\n",
+ (unsigned) BX_DMA_THIS s.chan[channel].base_address));
+ BX_INFO((" curr = %04x\n",
+ (unsigned) BX_DMA_THIS s.chan[channel].current_address));
+ }
+ }
+ BX_DMA_THIS s.flip_flop = !BX_DMA_THIS s.flip_flop;
+ return;
+ break;
+
+ case 0x01:
+ case 0x03:
+ case 0x05:
+ case 0x07:
+ channel = address >> 1;
+ if (bx_dbg.dma)
+ BX_INFO((" DMA-1 base and current count, channel %d\n", channel));
+ if (BX_DMA_THIS s.flip_flop==0) { /* 1st byte */
+ BX_DMA_THIS s.chan[channel].base_count = value;
+ BX_DMA_THIS s.chan[channel].current_count = value;
+ }
+ else { /* 2nd byte */
+ BX_DMA_THIS s.chan[channel].base_count |= (value << 8);
+ BX_DMA_THIS s.chan[channel].current_count |= (value << 8);
+ if (bx_dbg.dma) {
+ BX_INFO((" base = %04x\n",
+ (unsigned) BX_DMA_THIS s.chan[channel].base_count));
+ BX_INFO((" curr = %04x\n",
+ (unsigned) BX_DMA_THIS s.chan[channel].current_count));
+ }
+ }
+ BX_DMA_THIS s.flip_flop = !BX_DMA_THIS s.flip_flop;
+ return;
+ break;
+
+ case 0x08: /* DMA-1: command register */
+ if (value != 0x04)
+ BX_INFO(("DMA: write to 0008: value(%02xh) not 04h\n",
+ (unsigned) value));
+ BX_DMA_THIS s.command_reg = value;
+ return;
+ break;
+
+ case 0x09: // DMA-1: request register
+ BX_INFO(("DMA-1: write to request register (%02x)\n", (unsigned) value));
+ // note: write to 0x0d clears this register
+ if (value & 0x04) {
+ // set request bit
+ }
+ else {
+ Bit8u channel;
+
+ // clear request bit
+ channel = value & 0x03;
+ BX_DMA_THIS s.status_reg &= ~(1 << (channel+4));
+ BX_INFO(("dma-1: cleared request bit for channel %u\n", (unsigned) channel));
+ }
+ return;
+ break;
+
+ case 0x0a:
+ set_mask_bit = value & 0x04;
+ channel = value & 0x03;
+ BX_DMA_THIS s.mask[channel] = (set_mask_bit > 0);
+ if (bx_dbg.dma)
+ BX_INFO(("DMA1: set_mask_bit=%u, channel=%u, mask now=%02xh\n",
+ (unsigned) set_mask_bit, (unsigned) channel, (unsigned) BX_DMA_THIS s.mask[channel]));
+ return;
+ break;
+
+ case 0x0b: /* dma-1 mode register */
+ channel = value & 0x03;
+ BX_DMA_THIS s.chan[channel].mode.mode_type = (value >> 6) & 0x03;
+ BX_DMA_THIS s.chan[channel].mode.address_decrement = (value >> 5) & 0x01;
+ BX_DMA_THIS s.chan[channel].mode.autoinit_enable = (value >> 4) & 0x01;
+ BX_DMA_THIS s.chan[channel].mode.transfer_type = (value >> 2) & 0x03;
+//BX_INFO(("DMA1: mode register[%u] = %02x\n",
+//(unsigned) channel, (unsigned) value));
+ if (bx_dbg.dma)
+ BX_INFO(("DMA1: mode register[%u] = %02x\n",
+ (unsigned) channel, (unsigned) value));
+ return;
+ break;
+
+ case 0x0c: /* dma-1 clear byte flip/flop */
+ if (bx_dbg.dma)
+ BX_INFO(("DMA1: clear flip/flop\n"));
+ BX_DMA_THIS s.flip_flop = 0;
+ return;
+ break;
+
+ case 0x0d: // dma-1: master disable
+ /* ??? */
+ BX_INFO(("dma: master disable\n"));
+ // writing any value to this port resets DMA controller 1
+ // same action as a hardware reset
+ // mask register is set (chan 0..3 disabled)
+ // command, status, request, temporary, and byte flip-flop are all cleared
+ BX_DMA_THIS s.mask[0] = 1;
+ BX_DMA_THIS s.mask[1] = 1;
+ BX_DMA_THIS s.mask[2] = 1;
+ BX_DMA_THIS s.mask[3] = 1;
+ BX_DMA_THIS s.command_reg = 0;
+ BX_DMA_THIS s.status_reg = 0;
+ BX_DMA_THIS s.request_reg = 0;
+ BX_DMA_THIS s.temporary_reg = 0;
+ BX_DMA_THIS s.flip_flop = 0;
+ return;
+ break;
+
+ case 0x0e: // dma-1: clear mask register
+ BX_INFO(("dma-1: clear mask register\n"));
+ BX_DMA_THIS s.mask[0] = 0;
+ BX_DMA_THIS s.mask[1] = 0;
+ BX_DMA_THIS s.mask[2] = 0;
+ BX_DMA_THIS s.mask[3] = 0;
+ return;
+ break;
+
+ case 0x0f: // dma-1: write all mask bits
+ BX_INFO(("dma-1: write all mask bits\n"));
+ BX_DMA_THIS s.mask[0] = value & 0x01; value >>= 1;
+ BX_DMA_THIS s.mask[1] = value & 0x01; value >>= 1;
+ BX_DMA_THIS s.mask[2] = value & 0x01; value >>= 1;
+ BX_DMA_THIS s.mask[3] = value & 0x01;
+ return;
+ break;
+
+ case 0x81: /* dma page register, channel 2 */
+ case 0x82: /* dma page register, channel 3 */
+ case 0x83: /* dma page register, channel 1 */
+ case 0x87: /* dma page register, channel 0 */
+ /* address bits A16-A23 for DMA channel */
+ channel = channelindex[address - 0x81];
+ BX_DMA_THIS s.chan[channel].page_reg = value;
+ if (bx_dbg.dma)
+ BX_INFO(("DMA1: page register %d = %02x\n", channel, (unsigned) value));
+ return;
+ break;
+
+ case 0x0084: // ???
+ return;
+ break;
+
+ //case 0xd0: /* DMA-2 command register */
+ // if (value != 0x04)
+ // BX_INFO(("DMA2: write command register: value(%02xh)!=04h\n",
+ // (unsigned) value));
+ // return;
+ // break;
+
+ case 0x00c0:
+ case 0x00c2:
+ case 0x00c4:
+ case 0x00c6:
+ case 0x00c8:
+ case 0x00ca:
+ case 0x00cc:
+ case 0x00ce:
+ case 0x00d0:
+ case 0x00d2:
+ case 0x00d4:
+ case 0x00d6:
+ case 0x00d8:
+ case 0x00da:
+ case 0x00dc:
+ case 0x00de:
+ BX_INFO(("DMA(ignored): write: %04xh = %04xh\n",
+ (unsigned) address, (unsigned) value));
+ return;
+ break;
+
+
+ default:
+ BX_INFO(("DMA(ignored): write: %04xh = %02xh\n",
+ (unsigned) address, (unsigned) value));
+ }
+}
+
+ void
+bx_dma_c::DRQ(unsigned channel, Boolean val)
+{
+ Bit32u dma_base, dma_roof;
+
+#if BX_SUPPORT_SB16
+ if ( (channel != 2) && (channel != (unsigned) BX_SB16_DMAL) )
+ BX_PANIC(("bx_dma_c::DRQ(): channel %d != 2 or %d (SB16) (\n",
+ channel, BX_SB16_DMAL));
+#else
+ if ( channel != 2 )
+ BX_PANIC(("bx_dma_c::DRQ(): channel %d != 2\n",
+ channel));
+#endif
+ if (!val) {
+ //BX_INFO(("bx_dma_c::DRQ(): val == 0\n"));
+ // clear bit in status reg
+ // deassert HRQ if not pending DRQ's ?
+ // etc.
+ BX_DMA_THIS s.status_reg &= ~(1 << (channel+4));
+ return;
+ }
+
+#if 0
+ BX_INFO(("BX_DMA_THIS s.mask[2]: %02x\n", (unsigned) BX_DMA_THIS s.mask[2]));
+ BX_INFO(("BX_DMA_THIS s.flip_flop: %u\n", (unsigned) BX_DMA_THIS s.flip_flop));
+ BX_INFO(("BX_DMA_THIS s.status_reg: %02x\n", (unsigned) BX_DMA_THIS s.status_reg));
+ BX_INFO(("mode_type: %02x\n", (unsigned) BX_DMA_THIS s.chan[channel].mode.mode_type));
+ BX_INFO(("address_decrement: %02x\n", (unsigned) BX_DMA_THIS s.chan[channel].mode.address_decrement));
+ BX_INFO(("autoinit_enable: %02x\n", (unsigned) BX_DMA_THIS s.chan[channel].mode.autoinit_enable));
+ BX_INFO(("transfer_type: %02x\n", (unsigned) BX_DMA_THIS s.chan[channel].mode.transfer_type));
+ BX_INFO((".base_address: %04x\n", (unsigned) BX_DMA_THIS s.chan[channel].base_address));
+ BX_INFO((".current_address: %04x\n", (unsigned) BX_DMA_THIS s.chan[channel].current_address));
+ BX_INFO((".base_count: %04x\n", (unsigned) BX_DMA_THIS s.chan[channel].base_count));
+ BX_INFO((".current_count: %04x\n", (unsigned) BX_DMA_THIS s.chan[channel].current_count));
+ BX_INFO((".page_reg: %02x\n", (unsigned) BX_DMA_THIS s.chan[channel].page_reg));
+#endif
+
+ BX_DMA_THIS s.status_reg |= (1 << (channel+4));
+
+ // if (BX_DMA_THIS s.mask[channel])
+ // BX_PANIC(("bx_dma_c::DRQ(): BX_DMA_THIS s.mask[] is set\n"));
+
+
+ if ( (BX_DMA_THIS s.chan[channel].mode.mode_type != DMA_MODE_SINGLE) &&
+ (BX_DMA_THIS s.chan[channel].mode.mode_type != DMA_MODE_DEMAND) )
+ BX_PANIC(("bx_dma_c::DRQ: mode_type(%02x) not handled\n",
+ (unsigned) BX_DMA_THIS s.chan[channel].mode.mode_type));
+ if (BX_DMA_THIS s.chan[channel].mode.address_decrement != 0)
+ BX_PANIC(("bx_dma_c::DRQ: address_decrement != 0\n"));
+ //if (BX_DMA_THIS s.chan[channel].mode.autoinit_enable != 0)
+ // BX_PANIC(("bx_dma_c::DRQ: autoinit_enable != 0\n"));
+
+ dma_base = (BX_DMA_THIS s.chan[channel].page_reg << 16) | BX_DMA_THIS s.chan[channel].base_address;
+ dma_roof = dma_base + BX_DMA_THIS s.chan[channel].base_count;
+ if ( (dma_base & 0xffff0000) != (dma_roof & 0xffff0000) ) {
+BX_INFO(("dma_base = %08x\n", (unsigned) dma_base));
+BX_INFO(("dma_base_count = %08x\n", (unsigned) BX_DMA_THIS s.chan[channel].base_count));
+BX_INFO(("dma_roof = %08x\n", (unsigned) dma_roof));
+ BX_PANIC(("dma: DMA request outside 64k boundary\n"));
+ }
+
+
+ //BX_INFO(("DRQ set up for single mode, increment, auto-init disabled, write\n"));
+ // should check mask register VS DREQ's in status register here?
+ // assert Hold ReQuest line to CPU
+#if BX_SUPPORT_SID
+ dma_component->drive_hold_request_pin(1);
+#else
+ bx_pc_system.set_HRQ(1);
+#endif
+}
+
+#if BX_SUPPORT_SID
+void
+bx_dma_c::raise_HLDA(void)
+#else
+ void
+bx_dma_c::raise_HLDA(bx_pc_system_c *pc_sys)
+#endif
+{
+ unsigned channel;
+ Bit32u phy_addr;
+ Boolean count_expired = 0;
+
+ // find highest priority channel
+ for (channel=0; channel<4; channel++) {
+ if ( (BX_DMA_THIS s.status_reg & (1 << (channel+4))) &&
+ (BX_DMA_THIS s.mask[channel]==0) ) {
+ break;
+ }
+ }
+ if (channel >= 4) {
+ // don't panic, just wait till they're unmasked
+ // BX_PANIC(("hlda: no unmasked requests\n"));
+ return;
+ }
+
+ //BX_INFO(("hlda: OK in response to DRQ(%u)\n", (unsigned) channel));
+ phy_addr = (BX_DMA_THIS s.chan[channel].page_reg << 16) |
+ BX_DMA_THIS s.chan[channel].current_address;
+
+#if BX_SUPPORT_SID==0
+ bx_pc_system.set_DACK(channel, 1);
+#endif
+ // check for expiration of count, so we can signal TC and DACK(n)
+ // at the same time.
+ if (BX_DMA_THIS s.chan[channel].mode.address_decrement==0) {
+ // address increment
+ BX_DMA_THIS s.chan[channel].current_address++;
+ BX_DMA_THIS s.chan[channel].current_count--;
+ if (BX_DMA_THIS s.chan[channel].current_count == 0xffff)
+ if (BX_DMA_THIS s.chan[channel].mode.autoinit_enable == 0) {
+ // count expired, done with transfer
+ // assert TC, deassert HRQ & DACK(n) lines
+ BX_DMA_THIS s.status_reg |= (1 << channel); // hold TC in status reg
+#if BX_SUPPORT_SID
+ dma_component->drive_terminal_count_pin(1);
+#else
+ bx_pc_system.set_TC(1);
+#endif
+ count_expired = 1;
+ } else {
+ // count expired, but in autoinit mode
+ // reload count and base address
+ BX_DMA_THIS s.chan[channel].current_address =
+ BX_DMA_THIS s.chan[channel].base_address;
+ BX_DMA_THIS s.chan[channel].current_count =
+ BX_DMA_THIS s.chan[channel].base_count;
+ }
+
+ }
+ else {
+ // address decrement
+ BX_PANIC(("hlda: decrement not implemented\n"));
+ }
+
+ if (BX_DMA_THIS s.chan[channel].mode.transfer_type == 1) { // write
+ // xfer from I/O to Memory
+#if BX_SUPPORT_SID
+ dma_component->drive_channel_pin(channel, phy_addr, 0);
+#else
+ pc_sys->dma_write8(phy_addr, channel);
+#endif
+ }
+ else if (BX_DMA_THIS s.chan[channel].mode.transfer_type == 2) { // read
+ // xfer from Memory to I/O
+#if BX_SUPPORT_SID
+ dma_component->drive_channel_pin(channel, phy_addr, 1);
+#else
+ pc_sys->dma_read8(phy_addr, channel);
+#endif
+ }
+ else {
+ BX_PANIC(("hlda: transfer_type of %u not handled\n",
+ (unsigned) BX_DMA_THIS s.chan[channel].mode.transfer_type));
+ }
+
+ if (count_expired) {
+#if BX_SUPPORT_SID
+ dma_component->drive_terminal_count_pin(0);
+ dma_component->drive_hold_request_pin(0);
+#else
+ bx_pc_system.set_TC(0); // clear TC, adapter card already notified
+ bx_pc_system.set_HRQ(0); // clear HRQ to CPU
+#endif
+#if BX_SUPPORT_SID==0
+ bx_pc_system.set_DACK(channel, 0); // clear DACK to adapter card
+#endif
+ }
+}
--- /dev/null
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+#ifndef _PCDMA_H
+#define _PCDMA_H
+
+
+#define BX_KBD_ELEMENTS 16
+#define BX_MOUSE_BUFF_SIZE 48
+
+
+#if BX_USE_DMA_SMF
+# define BX_DMA_SMF static
+# define BX_DMA_THIS bx_dma.
+#else
+# define BX_DMA_SMF
+# define BX_DMA_THIS this->
+#endif
+
+
+#if BX_SUPPORT_SID
+class dma;
+#endif
+
+class bx_dma_c : public logfunctions {
+public:
+
+ bx_dma_c();
+ ~bx_dma_c(void);
+
+#if BX_SUPPORT_SID
+ BX_DMA_SMF void init(dma *dma_comp);
+#else
+ BX_DMA_SMF void init(bx_devices_c *);
+#endif
+ BX_DMA_SMF void DRQ(unsigned channel, Boolean val);
+#if BX_SUPPORT_SID
+ BX_DMA_SMF void raise_HLDA(void);
+#else
+ BX_DMA_SMF void raise_HLDA(bx_pc_system_c *pc_sys);
+#endif
+
+private:
+
+ static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+ static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+#if BX_SUPPORT_SID
+ public:
+#endif
+#if !BX_USE_DMA_SMF
+ Bit32u read( Bit32u address, unsigned io_len);
+ void write(Bit32u address, Bit32u value, unsigned io_len);
+#endif
+#if BX_SUPPORT_SID
+ private:
+#endif
+ struct {
+ Boolean mask[4];
+ Boolean flip_flop;
+ Bit8u status_reg;
+ Bit8u command_reg;
+ Bit8u request_reg;
+ Bit8u temporary_reg;
+ struct {
+ struct {
+ Bit8u mode_type;
+ Bit8u address_decrement;
+ Bit8u autoinit_enable;
+ Bit8u transfer_type;
+ } mode;
+ Bit16u base_address;
+ Bit16u current_address;
+ Bit16u base_count;
+ Bit16u current_count;
+ Bit8u page_reg;
+ } chan[4]; /* DMA channels 0..3 */
+ } s; // state information
+
+#if BX_SUPPORT_SID==0
+ bx_devices_c *devices;
+#else
+ dma *dma_component;
+#endif
+ };
+
+#if BX_SUPPORT_SID==0
+extern bx_dma_c bx_dma;
+#endif
+
+#endif // #ifndef _PCDMA_H
--- /dev/null
+// sid-dma-wrapper.cc - SID import of the bochs dma component. -*- C++ -*-
+
+// Copyright (C) 1999, 2000, 2001, 2002 Red Hat.
+// This file is part of SID and is licensed under the GPL.
+// See the file COPYING.SID for conditions for redistribution.
+
+#include "sid-dma-wrapper.h"
+
+dma::dma ()
+ : init_pin(this, & dma::init),
+ hold_acknowledge_pin(this, & dma::hold_acknowledge),
+ ports_0x00_0x0f_bus(this, & dma::read_port_0x00_0x0f, & dma::write_port_0x00_0x0f),
+ ports_0x81_0x8d_bus(this, & dma::read_port_0x81_0x8d, & dma::write_port_0x81_0x8d),
+ port_0x8f_bus(this, & dma::read_port_0x8f, & dma::write_port_0x8f),
+ ports_0xc0_0xde_bus(this, & dma::read_port_0xc0_0xde, & dma::write_port_0xc0_0xde),
+ channels_bus(this, & dma::channel_read_request, & dma::channel_write_request)
+{
+ add_pin("hold-request", & this->hold_request_pin);
+ add_pin("terminal-count", & this->terminal_count_pin);
+
+ add_pin("init", & this->init_pin);
+ add_pin("hold-acknowledge", & this->hold_acknowledge_pin);
+
+ add_bus("ports-0x00-0x0f", & this->ports_0x00_0x0f_bus);
+ add_bus("ports-0x81-0x8d", & this->ports_0x81_0x8d_bus);
+ add_bus("port-0x8f", & this->port_0x8f_bus);
+ add_bus("ports-0xc0-0xde", & this->ports_0xc0_0xde_bus);
+ add_bus("channels", & this->channels_bus);
+
+ add_pin("read-write", & this->read_write_pin);
+
+ add_pin("channel-0", & this->channel_pin[0]);
+ add_pin("channel-1", & this->channel_pin[1]);
+ add_pin("channel-2", & this->channel_pin[2]);
+ add_pin("channel-3", & this->channel_pin[3]);
+ add_pin("channel-4", & this->channel_pin[4]);
+ add_pin("channel-5", & this->channel_pin[5]);
+ add_pin("channel-6", & this->channel_pin[6]);
+ add_pin("channel-7", & this->channel_pin[7]);
+}
+
+void
+dma::init(host_int_4)
+{
+ bx_dma.init(this);
+}
+
+void
+dma::hold_acknowledge(host_int_4)
+{
+ bx_dma.raise_HLDA();
+}
+
+void
+dma::drive_hold_request_pin(host_int_4 value)
+{
+ hold_request_pin.drive(value);
+}
+
+void
+dma::drive_terminal_count_pin(host_int_4 value)
+{
+ terminal_count_pin.drive(value);
+}
+
+void
+dma::drive_channel_pin(host_int_4 channel, host_int_4 value, bool read_mode)
+{
+ read_write_pin.drive(read_mode);
+
+ channel_pin[channel].drive(value);
+}
+
+bus::status
+dma::read_port_0x00_0x0f (host_int_4 addr, little_int_1 mask, little_int_1 & data)
+{
+ addr += 0x00;
+ data = bx_dma.read(addr, 1);
+ return bus::ok;
+}
+
+bus::status
+dma::write_port_0x00_0x0f (host_int_4 addr, little_int_1 mask, little_int_1 data)
+{
+ addr += 0x00;
+ bx_dma.write(addr, data, 1);
+ return bus::ok;
+}
+
+bus::status
+dma::read_port_0x81_0x8d (host_int_4 addr, little_int_1 mask, little_int_1 & data)
+{
+ addr += 0x81;
+ data = bx_dma.read(addr, 1);
+ return bus::ok;
+}
+
+bus::status
+dma::write_port_0x81_0x8d (host_int_4 addr, little_int_1 mask, little_int_1 data)
+{
+ addr += 0x81;
+ bx_dma.write(addr, data, 1);
+ return bus::ok;
+}
+
+bus::status
+dma::read_port_0x8f (host_int_4 addr, little_int_1 mask, little_int_1 & data)
+{
+ addr += 0x8f;
+ data = bx_dma.read(addr, 1);
+ return bus::ok;
+}
+
+bus::status
+dma::write_port_0x8f (host_int_4 addr, little_int_1 mask, little_int_1 data)
+{
+ addr += 0x8f;
+ bx_dma.write(addr, data, 1);
+ return bus::ok;
+}
+
+bus::status
+dma::read_port_0xc0_0xde (host_int_4 addr, little_int_1 mask, little_int_1 & data)
+{
+ addr += 0xc0;
+ data = bx_dma.read(addr, 1);
+ return bus::ok;
+}
+
+bus::status
+dma::write_port_0xc0_0xde (host_int_4 addr, little_int_1 mask, little_int_1 data)
+{
+ addr += 0xc0;
+ bx_dma.write(addr, data, 1);
+ return bus::ok;
+}
+
+bus::status
+dma::channel_read_request(host_int_4 channel, little_int_1 mask, little_int_1 &val)
+{
+ // not used
+ val = 0;
+ return bus::ok;
+}
+
+bus::status
+dma::channel_write_request(host_int_4 channel, little_int_1 mask, little_int_1 val)
+{
+ bx_dma.DRQ(channel, val);
+ return bus::ok;
+}
--- /dev/null
+// sid-dma-wrapper.h - SID import of the bochs dma component. -*- C++ -*-
+
+// Copyright (C) 1999, 2000, 2001, 2002 Red Hat.
+// This file is part of SID and is licensed under the GPL.
+// See the file COPYING.SID for conditions for redistribution.
+
+#ifndef SID_DMA_WRAPPER_DEF_H
+#define SID_DMA_WRAPPER_DEF_H 1
+
+#include <sidtypes.h>
+#include <sidcomp.h>
+#include <sidcomputil.h>
+#include <sidpinutil.h>
+#include <sidbusutil.h>
+#include <sidattrutil.h>
+#include <sidcpuutil.h>
+#include <sidpinattrutil.h>
+#include <sidmiscutil.h>
+#include <sidwatchutil.h>
+#include <sidso.h>
+
+#include "bochs.h"
+
+using sid::bus;
+using sid::component;
+using sid::host_int_4;
+using sid::little_int_1;
+using sidutil::callback_pin;
+using sidutil::callback_word_bus;
+using sidutil::output_pin;
+
+class dma : public sidutil::fixed_pin_map_component,
+ public sidutil::fixed_accessor_map_component,
+ public sidutil::fixed_attribute_map_component,
+ public sidutil::no_relation_component,
+ public sidutil::fixed_bus_map_component
+{
+public:
+ dma();
+ ~dma() throw() {};
+
+ void init(host_int_4);
+
+ void hold_acknowledge(host_int_4);
+
+ void drive_hold_request_pin(host_int_4 value);
+ void drive_terminal_count_pin(host_int_4 value);
+
+ void drive_channel_pin(host_int_4 channel, host_int_4 value, bool read_mode);
+protected:
+
+ output_pin hold_request_pin;
+ output_pin terminal_count_pin;
+
+ callback_pin<dma> init_pin;
+ callback_pin<dma> hold_acknowledge_pin;
+
+ // Some ports in these ranges are not valid DMA ports.
+ bus::status read_port_0x00_0x0f (host_int_4 addr, little_int_1 mask, little_int_1 & data);
+ bus::status write_port_0x00_0x0f (host_int_4 addr, little_int_1 mask, little_int_1 data);
+
+ bus::status read_port_0x81_0x8d (host_int_4 addr, little_int_1 mask, little_int_1 & data);
+ bus::status write_port_0x81_0x8d (host_int_4 addr, little_int_1 mask, little_int_1 data);
+
+ bus::status read_port_0x8f (host_int_4 addr, little_int_1 mask, little_int_1 & data);
+ bus::status write_port_0x8f (host_int_4 addr, little_int_1 mask, little_int_1 data);
+
+ bus::status read_port_0xc0_0xde (host_int_4 addr, little_int_1 mask, little_int_1 & data);
+ bus::status write_port_0xc0_0xde (host_int_4 addr, little_int_1 mask, little_int_1 data);
+
+ callback_word_bus<dma, little_int_1> ports_0x00_0x0f_bus;
+ callback_word_bus<dma, little_int_1> ports_0x81_0x8d_bus;
+ callback_word_bus<dma, little_int_1> port_0x8f_bus;
+ callback_word_bus<dma, little_int_1> ports_0xc0_0xde_bus;
+
+ bus::status channel_read_request(host_int_4 channel, little_int_1 mask, little_int_1 &val);
+ bus::status channel_write_request(host_int_4 channel, little_int_1 mask, little_int_1 val);
+
+ callback_word_bus<dma, little_int_1> channels_bus;
+
+ // read == 1, write == 0
+ output_pin read_write_pin;
+ output_pin channel_pin[8];
+
+ bx_dma_c bx_dma;
+};
+#endif // SID_DMA_WRAPPER_DEF_H
--- /dev/null
+## Process this with automake to create Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(top_builddir)/../../include -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../../../include -I$(srcdir)/../cpu
+
+noinst_LTLIBRARIES = libfloppy.la
+
+libfloppy_la_SOURCES = sid-floppy-wrapper.cc sid-floppy-wrapper.h floppy.cc floppy.h
+
+libfloppy_la_LDFLAGS = -no-undefined
--- /dev/null
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+APIC_OBJS = @APIC_OBJS@
+AR = @AR@
+AS = @AS@
+AS_DYNAMIC_INCS = @AS_DYNAMIC_INCS@
+AS_DYNAMIC_OBJS = @AS_DYNAMIC_OBJS@
+BX_LOADER_OBJS = @BX_LOADER_OBJS@
+BX_SPLIT_HD_SUPPORT = @BX_SPLIT_HD_SUPPORT@
+CC = @CC@
+CDROM_OBJS = @CDROM_OBJS@
+CD_UP_ONE = @CD_UP_ONE@
+CD_UP_TWO = @CD_UP_TWO@
+CFP = @CFP@
+COMMAND_SEPARATOR = @COMMAND_SEPARATOR@
+CPP_SUFFIX = @CPP_SUFFIX@
+CXX = @CXX@
+CXXFP = @CXXFP@
+DASH = @DASH@
+DEBUGGER_VAR = @DEBUGGER_VAR@
+DISASM_VAR = @DISASM_VAR@
+DLLTOOL = @DLLTOOL@
+DYNAMIC_VAR = @DYNAMIC_VAR@
+EXE = @EXE@
+EXEEXT = @EXEEXT@
+EXTERNAL_DEPENDENCY = @EXTERNAL_DEPENDENCY@
+FPU_GLUE_OBJ = @FPU_GLUE_OBJ@
+FPU_VAR = @FPU_VAR@
+GUI_LINK_OPTS = @GUI_LINK_OPTS@
+GUI_LINK_OPTS_TERM = @GUI_LINK_OPTS_TERM@
+GUI_OBJS = @GUI_OBJS@
+GZIP = @GZIP@
+INLINE_VAR = @INLINE_VAR@
+INSTRUMENT_DIR = @INSTRUMENT_DIR@
+INSTRUMENT_VAR = @INSTRUMENT_VAR@
+IOAPIC_OBJS = @IOAPIC_OBJS@
+IODEV_LIB_VAR = @IODEV_LIB_VAR@
+LD = @LD@
+LIBTOOL = @LIBTOOL@
+LINK = @LINK@
+LN_S = @LN_S@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MAKELIB = @MAKELIB@
+NE2K_OBJS = @NE2K_OBJS@
+NM = @NM@
+NONINLINE_VAR = @NONINLINE_VAR@
+OBJDUMP = @OBJDUMP@
+OFP = @OFP@
+PACKAGE = @PACKAGE@
+PCI_OBJ = @PCI_OBJ@
+PRIMARY_TARGET = @PRIMARY_TARGET@
+RANLIB = @RANLIB@
+READLINE_LIB = @READLINE_LIB@
+RFB_LIBS = @RFB_LIBS@
+RMCOMMAND = @RMCOMMAND@
+SB16_OBJS = @SB16_OBJS@
+SLASH = @SLASH@
+SUFFIX_LINE = @SUFFIX_LINE@
+TAR = @TAR@
+VERSION = @VERSION@
+VIDEO_OBJS = @VIDEO_OBJS@
+sidtarget_arm = @sidtarget_arm@
+sidtarget_m32r = @sidtarget_m32r@
+sidtarget_m68k = @sidtarget_m68k@
+sidtarget_mips = @sidtarget_mips@
+sidtarget_ppc = @sidtarget_ppc@
+sidtarget_x86 = @sidtarget_x86@
+sidtarget_xstormy16 = @sidtarget_xstormy16@
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(top_builddir)/../../include -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../../../include -I$(srcdir)/../cpu
+
+noinst_LTLIBRARIES = libfloppy.la
+
+libfloppy_la_SOURCES = sid-floppy-wrapper.cc sid-floppy-wrapper.h floppy.cc floppy.h
+
+libfloppy_la_LDFLAGS = -no-undefined
+mkinstalldirs = $(SHELL) $(top_srcdir)/../../config/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_LIBS = @X_LIBS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+libfloppy_la_LIBADD =
+libfloppy_la_OBJECTS = sid-floppy-wrapper.lo floppy.lo
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+DIST_COMMON = Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+GZIP_ENV = --best
+DEP_FILES = .deps/floppy.P .deps/sid-floppy-wrapper.P
+SOURCES = $(libfloppy_la_SOURCES)
+OBJECTS = $(libfloppy_la_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .cc .lo .o .s
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --foreign floppy/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLTLIBRARIES:
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+
+distclean-noinstLTLIBRARIES:
+
+maintainer-clean-noinstLTLIBRARIES:
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.s.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+libfloppy.la: $(libfloppy_la_OBJECTS) $(libfloppy_la_DEPENDENCIES)
+ $(CXXLINK) $(libfloppy_la_LDFLAGS) $(libfloppy_la_OBJECTS) $(libfloppy_la_LIBADD) $(LIBS)
+.cc.o:
+ $(CXXCOMPILE) -c $<
+.cc.lo:
+ $(LTCXXCOMPILE) -c $<
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = floppy
+
+distdir: $(DISTFILES)
+ here=`cd $(top_builddir) && pwd`; \
+ top_distdir=`cd $(top_distdir) && pwd`; \
+ distdir=`cd $(distdir) && pwd`; \
+ cd $(top_srcdir) \
+ && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --foreign floppy/Makefile
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+ -rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+ @echo '$(COMPILE) -c $<'; \
+ $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.c
+ @echo '$(LTCOMPILE) -c $<'; \
+ $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+
+%.o: %.cc
+ @echo '$(CXXCOMPILE) -c $<'; \
+ $(CXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.cc
+ @echo '$(LTCXXCOMPILE) -c $<'; \
+ $(LTCXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LTLIBRARIES)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-noinstLTLIBRARIES mostlyclean-compile \
+ mostlyclean-libtool mostlyclean-tags mostlyclean-depend \
+ mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-noinstLTLIBRARIES clean-compile clean-libtool \
+ clean-tags clean-depend clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-noinstLTLIBRARIES distclean-compile \
+ distclean-libtool distclean-tags distclean-depend \
+ distclean-generic clean-am
+ -rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-noinstLTLIBRARIES \
+ maintainer-clean-compile maintainer-clean-libtool \
+ maintainer-clean-tags maintainer-clean-depend \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLTLIBRARIES distclean-noinstLTLIBRARIES \
+clean-noinstLTLIBRARIES maintainer-clean-noinstLTLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-libtool distclean-libtool \
+clean-libtool maintainer-clean-libtool tags mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir \
+mostlyclean-depend distclean-depend clean-depend \
+maintainer-clean-depend info-am info dvi-am dvi check check-am \
+installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+extern "C" {
+#include <errno.h>
+}
+
+#include "bochs.h"
+#if BX_SUPPORT_SID
+#define LOG_THIS
+#include "sid-floppy-wrapper.h"
+#else // BX_SUPPORT_SID
+#define LOG_THIS bx_floppy.
+
+
+bx_floppy_ctrl_c bx_floppy;
+#endif // BX_SUPPORT_SID
+
+#if BX_USE_FD_SMF
+#define this (&bx_floppy)
+#endif
+
+
+
+/* for main status register */
+#define FD_MS_MRQ 0x80
+#define FD_MS_DIO 0x40
+#define FD_MS_NDMA 0x20
+#define FD_MS_BUSY 0x10
+#define FD_MS_ACTD 0x08
+#define FD_MS_ACTC 0x04
+#define FD_MS_ACTB 0x02
+#define FD_MS_ACTA 0x01
+
+#define FROM_FLOPPY 10
+#define TO_FLOPPY 11
+
+#define FLOPPY_DMA_CHAN floppy_component->dma_channel_number()
+
+
+
+bx_floppy_ctrl_c::bx_floppy_ctrl_c(void)
+{
+#if BX_SUPPORT_SID
+ bx_dbg.floppy = 1;
+#endif
+ setprefix("[FDD ]");
+ settype(FDLOG);
+ BX_DEBUG(("Init.\n"));
+}
+
+bx_floppy_ctrl_c::~bx_floppy_ctrl_c(void)
+{
+ // nothing for now
+ BX_DEBUG(("Exit.\n"));
+}
+
+
+#if BX_SUPPORT_SID
+void
+bx_floppy_ctrl_c::init(floppy *floppy_comp)
+#else
+ void
+bx_floppy_ctrl_c::init(bx_devices_c *d, bx_cmos_c *cmos)
+#endif
+{
+#if BX_SUPPORT_SID==0
+ BX_FD_THIS devices = d;
+
+ BX_FD_THIS devices->register_irq(6, "Floppy Drive");
+ for (unsigned addr=0x03F2; addr<=0x03F7; addr++) {
+ BX_FD_THIS devices->register_io_read_handler(this, read_handler,
+ addr, "Floppy Drive");
+ BX_FD_THIS devices->register_io_write_handler(this, write_handler,
+ addr, "Floppy Drive");
+ }
+
+
+ cmos->s.reg[0x10] = 0x00; /* start out with: no drive 0, no drive 1 */
+
+ BX_FD_THIS s.num_supported_floppies = 0;
+#endif
+
+ //
+ // Floppy A setup
+ //
+ BX_FD_THIS s.media[0].sectors_per_track = 0;
+ BX_FD_THIS s.media[0].tracks = 0;
+ BX_FD_THIS s.media[0].heads = 0;
+ BX_FD_THIS s.media[0].sectors = 0;
+ BX_FD_THIS s.media[0].type = BX_FLOPPY_NONE;
+ BX_FD_THIS s.media[0].fd = -1;
+ BX_FD_THIS s.media_present[0] = 0;
+
+
+#if BX_SUPPORT_SID==0
+ switch (bx_options.floppya.type) {
+ case BX_FLOPPY_NONE:
+ cmos->s.reg[0x10] = (cmos->s.reg[0x10] & 0x0f) | 0x00;
+ break;
+ case BX_FLOPPY_1_2:
+ cmos->s.reg[0x10] = (cmos->s.reg[0x10] & 0x0f) | 0x20;
+ break;
+ case BX_FLOPPY_720K:
+ cmos->s.reg[0x10] = (cmos->s.reg[0x10] & 0x0f) | 0x30;
+ break;
+ case BX_FLOPPY_1_44:
+ cmos->s.reg[0x10] = (cmos->s.reg[0x10] & 0x0f) | 0x40;
+ break;
+ case BX_FLOPPY_2_88:
+ cmos->s.reg[0x10] = (cmos->s.reg[0x10] & 0x0f) | 0x50;
+ break;
+ default:
+ BX_PANIC(( "unknown floppya type\n" ));
+ }
+
+ if (bx_options.floppya.type != BX_FLOPPY_NONE) {
+ BX_FD_THIS s.num_supported_floppies++;
+ if ( bx_options.floppya.initial_status == BX_INSERTED) {
+ if (evaluate_media(bx_options.floppya.type, bx_options.floppya.path,
+ & BX_FD_THIS s.media[0]))
+ BX_FD_THIS s.media_present[0] = 1;
+ }
+ }
+#endif
+
+
+ //
+ // Floppy B setup
+ //
+ BX_FD_THIS s.media[1].sectors_per_track = 0;
+ BX_FD_THIS s.media[1].tracks = 0;
+ BX_FD_THIS s.media[1].heads = 0;
+ BX_FD_THIS s.media[1].sectors = 0;
+ BX_FD_THIS s.media[1].type = BX_FLOPPY_NONE;
+ BX_FD_THIS s.media[1].fd = -1;
+ BX_FD_THIS s.media_present[1] = 0;
+
+#if BX_SUPPORT_SID==0
+ switch (bx_options.floppyb.type) {
+ case BX_FLOPPY_NONE:
+ cmos->s.reg[0x10] = (cmos->s.reg[0x10] & 0xf0) | 0x00;
+ break;
+ case BX_FLOPPY_1_2:
+ cmos->s.reg[0x10] = (cmos->s.reg[0x10] & 0xf0) | 0x02;
+ break;
+ case BX_FLOPPY_720K:
+ cmos->s.reg[0x10] = (cmos->s.reg[0x10] & 0xf0) | 0x03;
+ break;
+ case BX_FLOPPY_1_44:
+ cmos->s.reg[0x10] = (cmos->s.reg[0x10] & 0xf0) | 0x04;
+ break;
+ case BX_FLOPPY_2_88:
+ cmos->s.reg[0x10] = (cmos->s.reg[0x10] & 0xf0) | 0x05;
+ break;
+ default:
+ BX_PANIC(("unknown floppyb type\n"));
+ }
+
+ if (bx_options.floppyb.type != BX_FLOPPY_NONE) {
+ BX_FD_THIS s.num_supported_floppies++;
+ if ( bx_options.floppyb.initial_status == BX_INSERTED) {
+ if (evaluate_media(bx_options.floppyb.type, bx_options.floppyb.path,
+ & BX_FD_THIS s.media[1]))
+ BX_FD_THIS s.media_present[1] = 1;
+ }
+ }
+
+
+
+ /* CMOS Equipment Byte register */
+ if (BX_FD_THIS s.num_supported_floppies > 0)
+ cmos->s.reg[0x14] = (cmos->s.reg[0x14] & 0x3e) |
+ ((BX_FD_THIS s.num_supported_floppies-1) << 6) |
+ 1;
+ else
+ cmos->s.reg[0x14] = (cmos->s.reg[0x14] & 0x3e);
+#endif
+
+#if BX_SUPPORT_SID
+ floppy_component = floppy_comp;
+ floppy_component->drive_command_delay_control_pin(0, 0);
+#else
+
+ BX_FD_THIS s.floppy_timer_index =
+ bx_pc_system.register_timer( this, timer_handler,
+ bx_options.floppy_command_delay, 0,0);
+#endif
+
+ BX_INFO(("bx_options.floppy_command_delay = %u\n",
+ (unsigned) bx_options.floppy_command_delay));
+}
+
+
+
+ void
+bx_floppy_ctrl_c::reset(unsigned source)
+{
+ Bit32u i;
+
+ BX_FD_THIS s.data_rate = 0; /* 500 Kbps */
+
+ BX_FD_THIS s.command_complete = 1; /* waiting for new command */
+ BX_FD_THIS s.command_index = 0;
+ BX_FD_THIS s.command_size = 0;
+ BX_FD_THIS s.pending_command = 0;
+
+ BX_FD_THIS s.result_index = 0;
+ BX_FD_THIS s.result_size = 0;
+
+ /* data register ready, not in DMA mode */
+ BX_FD_THIS s.main_status_reg = FD_MS_MRQ;
+ BX_FD_THIS s.status_reg0 = 0;
+ BX_FD_THIS s.status_reg1 = 0;
+ BX_FD_THIS s.status_reg2 = 0;
+ BX_FD_THIS s.status_reg3 = 0;
+
+ // software reset (via DOR port 0x3f2 bit 2) does not change DOR
+ if (source == BX_RESET_HARDWARE) {
+ BX_FD_THIS s.DOR = 0x0c;
+ // motor off, drive 3..0
+ // DMA/INT enabled
+ // normal operation
+ // drive select 0
+
+ // DIR affected only by hard reset
+ BX_FD_THIS s.DIR |= 0x80; // disk changed
+ }
+
+ for (i=0; i<4; i++) {
+ BX_FD_THIS s.cylinder[i] = 0;
+ BX_FD_THIS s.head[i] = 0;
+ BX_FD_THIS s.sector[i] = 0;
+ }
+
+ BX_FD_THIS s.floppy_buffer_index = 0;
+
+}
+
+
+ // static IO port read callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ Bit32u
+bx_floppy_ctrl_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_FD_SMF
+ bx_floppy_ctrl_c *class_ptr = (bx_floppy_ctrl_c *) this_ptr;
+
+ return( class_ptr->read(address, io_len) );
+}
+
+
+ /* reads from the floppy io ports */
+ Bit32u
+bx_floppy_ctrl_c::read(Bit32u address, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_FD_SMF
+ Bit8u status, value;
+
+ if (io_len > 1)
+ BX_PANIC(("io read from address %08x, len=%u\n",
+ (unsigned) address, (unsigned) io_len));
+
+// ???
+//if (bx_cpu.cs.selector.value != 0xf000) {
+// BX_INFO(("BIOS: floppy: read access to port %04x\n", (unsigned) address);
+// }
+
+ if (bx_dbg.floppy)
+ BX_INFO(("read access to port %04x\n", (unsigned) address));
+
+ switch (address) {
+#if BX_DMA_FLOPPY_IO
+ case 0x3F2: // diskette controller digital output register
+ value = BX_FD_THIS s.DOR;
+ return(value);
+ break;
+
+ case 0x3F4: /* diskette controller main status register */
+ status = BX_FD_THIS s.main_status_reg;
+ return(status);
+ break;
+
+ case 0x3F5: /* diskette controller data */
+ if (BX_FD_THIS s.result_size == 0) {
+ BX_PANIC(("diskette controller:port3f5: no results to read\n"));
+ }
+
+ value = BX_FD_THIS s.result[BX_FD_THIS s.result_index++];
+ if (BX_FD_THIS s.result_index >= BX_FD_THIS s.result_size) {
+ BX_FD_THIS s.result_size = 0;
+ BX_FD_THIS s.result_index = 0;
+ BX_FD_THIS s.main_status_reg = FD_MS_MRQ;
+ }
+ return(value);
+ break;
+#endif // #if BX_DMA_FLOPPY_IO
+
+ case 0x3F6: // Reserved for future floppy controllers
+ // This address shared with the hard drive controller
+#if 0 // Change this when adding bochs hard drive component to sid.
+ value = BX_FD_THIS devices->hard_drive->read_handler(BX_FD_THIS devices->hard_drive, address, io_len);
+#else
+ value = 0;
+#endif
+ return( value );
+ break;
+
+ case 0x3F7: // diskette controller digital input register
+ // This address shared with the hard drive controller:
+ // Bit 7 : floppy
+ // Bits 6..0: hard drive
+#if 0 // Change this when adding bochs hard drive component to sid.
+ value = BX_FD_THIS devices->hard_drive->read_handler(BX_FD_THIS devices->hard_drive, address, io_len);
+#else
+ value = 0;
+#endif
+ value &= 0x7f;
+ // add in diskette change line
+ value |= (BX_FD_THIS s.DIR & 0x80);
+ return( value );
+ break;
+ }
+
+#if BX_DMA_FLOPPY_IO
+ BX_PANIC(("io_read: bailing\n"));
+ return(0);
+#endif // #if BX_DMA_FLOPPY_IO
+}
+
+
+ // static IO port write callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ void
+bx_floppy_ctrl_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_FD_SMF
+ bx_floppy_ctrl_c *class_ptr = (bx_floppy_ctrl_c *) this_ptr;
+
+ class_ptr->write(address, value, io_len);
+}
+
+ /* writes to the floppy io ports */
+ void
+bx_floppy_ctrl_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_FD_SMF
+ Bit8u dma_and_interrupt_enable;
+ Bit8u normal_operation, prev_normal_operation;
+ Bit8u drive_select;
+ Bit8u motor_on_drive0, motor_on_drive1;
+
+ if (io_len > 1)
+ BX_PANIC(("io write to address %08x, len=%u\n",
+ (unsigned) address, (unsigned) io_len));
+
+// ???
+//if (bx_cpu.cs.selector.value != 0xf000) {
+// BX_INFO(("BIOS: floppy: write access to port %04x, value=%02x\n",
+// (unsigned) address, (unsigned) value));
+// }
+
+ if (bx_dbg.floppy)
+ BX_INFO(("write access to port %04x, value=%02x\n",
+ (unsigned) address, (unsigned) value));
+
+ switch (address) {
+#if BX_DMA_FLOPPY_IO
+ case 0x3F2: /* diskette controller digital output register */
+ motor_on_drive1 = value & 0x20;
+ motor_on_drive0 = value & 0x10;
+ dma_and_interrupt_enable = value & 0x08;
+ if (!dma_and_interrupt_enable)
+ BX_DEBUG(("DMA and interrupt capabilities disabled\n"));
+ normal_operation = value & 0x04;
+ drive_select = value & 0x03;
+
+ prev_normal_operation = BX_FD_THIS s.DOR & 0x04;
+ BX_FD_THIS s.DOR = value;
+
+ if (prev_normal_operation==0 && normal_operation) {
+ // transition from RESET to NORMAL
+#if 0
+
+ BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
+ BX_FD_THIS s.pending_command = 0xfe; // RESET pending
+
+ bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index,
+ bx_options.floppy_command_delay, 0 );
+#endif
+ }
+ else if (prev_normal_operation && normal_operation==0) {
+ // transition from NORMAL to RESET
+ BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
+ BX_FD_THIS s.pending_command = 0xfe; // RESET pending
+
+#if BX_SUPPORT_SID
+ floppy_component->drive_command_delay_control_pin(bx_options.floppy_command_delay, 0);
+#else
+ bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index,
+ bx_options.floppy_command_delay, 0 );
+#endif
+ }
+ if (bx_dbg.floppy) {
+ BX_INFO(("io_write: digital output register\n"));
+ BX_INFO((" motor on, drive1 = %d\n", motor_on_drive1 > 0));
+ BX_INFO((" motor on, drive0 = %d\n", motor_on_drive0 > 0));
+ BX_INFO((" dma_and_interrupt_enable=%02x\n",
+ (unsigned) dma_and_interrupt_enable));
+ BX_INFO((" normal_operation=%02x\n",
+ (unsigned) normal_operation));
+ BX_INFO((" drive_select=%02x\n",
+ (unsigned) drive_select));
+ }
+ if (drive_select>1) {
+ BX_PANIC(("io_write: drive_select>1\n"));
+ }
+ break;
+
+ case 0x3f4: /* diskette controller data rate select register */
+ BX_PANIC(("io_write: data rate select register\n"));
+ break;
+
+ case 0x3F5: /* diskette controller data */
+ if (bx_dbg.floppy)
+ BX_INFO(("command = %02x\n", (unsigned) value));
+ if (BX_FD_THIS s.command_complete) {
+ if (BX_FD_THIS s.pending_command!=0)
+ BX_PANIC(("io: 3f5: receiving new comm, old one (%02x) pending\n",
+ (unsigned) BX_FD_THIS s.pending_command));
+ BX_FD_THIS s.command[0] = value;
+ BX_FD_THIS s.command_complete = 0;
+ BX_FD_THIS s.command_index = 1;
+ /* read/write command in progress */
+ BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_BUSY;
+ switch (value) {
+ case 0x03: /* specify */
+ BX_FD_THIS s.command_size = 3;
+ break;
+ case 0x04: // get status
+ BX_FD_THIS s.command_size = 2;
+ break;
+ case 0x07: /* recalibrate */
+ BX_FD_THIS s.command_size = 2;
+ break;
+ case 0x08: /* sense interrupt status */
+ BX_FD_THIS s.command_size = 1;
+ floppy_command();
+ BX_FD_THIS s.command_complete = 1;
+ break;
+ case 0x0f: /* seek */
+ BX_FD_THIS s.command_size = 3;
+ break;
+ case 0x4a: /* read ID */
+ BX_FD_THIS s.command_size = 2;
+ break;
+ case 0xc5: /* write normal data */
+ BX_FD_THIS s.command_size = 9;
+ break;
+ case 0xe6: /* read normal data */
+ BX_FD_THIS s.command_size = 9;
+ break;
+
+ case 0x13: // Configure command (Enhanced)
+ BX_FD_THIS s.command_size = 3;
+ break;
+
+ case 0x0e: // dump registers (Enhanced drives)
+ case 0x10: // Version command, standard controller returns 80h
+ case 0x18: // National Semiconductor version command; return 80h
+ // These commands are not implemented on the standard
+ // controller and return an error. They are available on
+ // the enhanced controller.
+ BX_FD_THIS s.command_size = 1;
+ BX_FD_THIS s.result[0] = 0x80;
+ BX_FD_THIS s.result_size = 1;
+ BX_FD_THIS s.result_index = 0;
+ BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY;
+ BX_FD_THIS s.command_complete = 1;
+ break;
+
+ default:
+ BX_PANIC(("io write:3f5: unsupported case 0x%02x\n",
+ (unsigned) value));
+ break;
+ }
+ }
+ else {
+ BX_FD_THIS s.command[BX_FD_THIS s.command_index++] =
+ value;
+ if (BX_FD_THIS s.command_index ==
+ BX_FD_THIS s.command_size) {
+ /* read/write command not in progress any more */
+ floppy_command();
+ BX_FD_THIS s.command_complete = 1;
+ }
+ }
+ if (bx_dbg.floppy)
+ BX_INFO(("io_write: diskette controller data\n"));
+ return;
+ break;
+#endif // #if BX_DMA_FLOPPY_IO
+
+ case 0x3F6: /* diskette controller (reserved) */
+ if (bx_dbg.floppy)
+ BX_INFO(("io_write: reserved register unsupported\n"));
+ // this address shared with the hard drive controller
+#if 0 // Change this when adding bochs hard drive component to sid.
+ BX_FD_THIS devices->hard_drive->write_handler(BX_FD_THIS devices->hard_drive, address, value, io_len);
+#endif
+ break;
+
+#if BX_DMA_FLOPPY_IO
+ case 0x3F7: /* diskette controller configuration control register */
+ if (bx_dbg.floppy)
+ BX_INFO(("io_write: config control register\n"));
+ BX_FD_THIS s.data_rate = value & 0x03;
+ if (bx_dbg.floppy)
+ switch (BX_FD_THIS s.data_rate) {
+ case 0: BX_INFO((" 500 Kbps\n")); break;
+ case 1: BX_INFO((" 300 Kbps\n")); break;
+ case 2: BX_INFO((" 250 Kbps\n")); break;
+ case 3: BX_INFO((" 1 Mbps\n")); break;
+ }
+ return;
+ break;
+
+ default:
+ BX_PANIC(("io_write: unknown port %04h\n", (unsigned) address));
+ break;
+#endif // #if BX_DMA_FLOPPY_IO
+ }
+}
+
+
+
+ void
+bx_floppy_ctrl_c::floppy_command(void)
+{
+#if BX_PROVIDE_CPU_MEMORY==0
+ BX_PANIC(("floppy_command(): uses DMA: not supported for"
+ " external environment\n"));
+#else
+ unsigned i;
+ Bit8u step_rate_time;
+ Bit8u head_unload_time;
+ Bit8u head_load_time;
+ Bit8u motor_on;
+ Bit8u head, drive, cylinder, sector, eot;
+ Bit8u sector_size, data_length;
+ Bit32u logical_sector;
+
+
+ if (bx_dbg.floppy) {
+ BX_INFO(("FLOPPY COMMAND: "));
+ for (i=0; i<BX_FD_THIS s.command_size; i++)
+ BX_INFO(("[%02x] ", (unsigned) BX_FD_THIS s.command[i]));
+ BX_INFO(("\n"));
+ }
+
+#if 0
+ /* execute phase of command is in progress (non DMA mode) */
+ BX_FD_THIS s.main_status_reg |= 20;
+#endif
+
+ switch (BX_FD_THIS s.command[0]) {
+ case 0x03: // specify
+//BX_INFO(("floppy_command specify\n"));
+ // execution: specified parameters are loaded
+ // result: no result bytes, no interrupt
+ step_rate_time = BX_FD_THIS s.command[1] >> 4;
+ head_unload_time = BX_FD_THIS s.command[1] & 0x0f;
+ head_load_time = BX_FD_THIS s.command[2] >> 1;
+ BX_FD_THIS s.main_status_reg = FD_MS_MRQ;
+ return;
+ break;
+
+ case 0x04: // get status
+ BX_FD_THIS s.result[0] = 0x00;
+ BX_FD_THIS s.result_size = 1;
+ BX_FD_THIS s.result_index = 0;
+ BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY;
+ return;
+ break;
+
+ case 0x07: // recalibrate
+//BX_INFO(("floppy_command recalibrate\n"));
+ drive = (BX_FD_THIS s.command[1] & 0x03);
+ BX_FD_THIS s.DOR &= 0xfc;
+ BX_FD_THIS s.DOR |= drive;
+ if (bx_dbg.floppy)
+ BX_INFO(("floppy_command(): recalibrate drive %u\n",
+ (unsigned) drive));
+ if (drive > 1)
+ BX_PANIC(("floppy_command(): drive > 1\n"));
+ //motor_on = BX_FD_THIS s.DOR & 0xf0;
+ motor_on = ( (BX_FD_THIS s.DOR>>(drive+4))
+ & 0x01 );
+ if (motor_on == 0) {
+ BX_INFO(("floppy_command(): recal drive with motor off\n"));
+ }
+ if (drive==0)
+ BX_FD_THIS s.DOR |= 0x10; // turn on MOTA
+ else
+ BX_FD_THIS s.DOR |= 0x20; // turn on MOTB
+ BX_FD_THIS s.cylinder[drive] = 0;
+
+#if BX_SUPPORT_SID
+ floppy_component->drive_command_delay_control_pin(bx_options.floppy_command_delay, 0);
+#else
+ bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index,
+ bx_options.floppy_command_delay, 0 );
+#endif
+ /* command head to track 0
+ * controller set to non-busy
+ * error condition noted in Status reg 0's equipment check bit
+ * seek end bit set to 1 in Status reg 0 regardless of outcome
+ */
+ /* data reg not ready, controller busy */
+ BX_FD_THIS s.main_status_reg = FD_MS_DIO | FD_MS_BUSY;
+ BX_FD_THIS s.pending_command = 0x07; // recalibrate pending
+ return;
+ break;
+
+ case 0x08: /* sense interrupt status */
+//BX_INFO(("floppy_command sense interrupt status\n"));
+ /* execution:
+ * get status
+ * result:
+ * no interupt
+ * byte0 = status reg0
+ * byte1 = current cylinder number (0 to 79)
+ */
+ /*BX_FD_THIS s.status_reg0 = ;*/
+ drive = BX_FD_THIS s.DOR & 0x03;
+ BX_FD_THIS s.result[0] = 0x20 | drive;
+ BX_FD_THIS s.result[1] = BX_FD_THIS s.cylinder[drive];
+ BX_FD_THIS s.result_size = 2;
+ BX_FD_THIS s.result_index = 0;
+
+ /* read ready */
+ BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY;
+ if (bx_dbg.floppy)
+ BX_INFO(("sense interrupt status\n"));
+ return;
+ break;
+
+ case 0x0f: /* seek */
+//BX_INFO(("floppy_command seek\n"));
+ /* command:
+ * byte0 = 0F
+ * byte1 = drive & head select
+ * byte2 = cylinder number
+ * execution:
+ * postion head over specified cylinder
+ * result:
+ * no result bytes, issues an interrupt
+ */
+ drive = BX_FD_THIS s.command[1] & 0x03;
+ BX_FD_THIS s.DOR &= 0xfc;
+ BX_FD_THIS s.DOR |= drive;
+
+ BX_FD_THIS s.head[drive] = (BX_FD_THIS s.command[1] >> 2) & 0x01;
+ BX_FD_THIS s.cylinder[drive] = BX_FD_THIS s.command[2];
+ if (drive > 1)
+ BX_PANIC(("floppy_command(): seek: drive>1\n"));
+ /* ??? should also check cylinder validity */
+
+#if BX_SUPPORT_SID
+ floppy_component->drive_command_delay_control_pin(bx_options.floppy_command_delay, 0);
+#else
+ bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index,
+ bx_options.floppy_command_delay, 0 );
+#endif
+ /* data reg not ready, controller busy */
+ BX_FD_THIS s.main_status_reg = FD_MS_DIO | FD_MS_BUSY;
+ BX_FD_THIS s.pending_command = 0x0f; /* seek pending */
+ return;
+ break;
+
+ case 0x13: // Configure
+ BX_DEBUG(("io: configure (mode=%02xh, pretrack=%02xh)\n",
+(unsigned)(BX_FD_THIS s.command[2]), (unsigned)(BX_FD_THIS s.command[3]) ));
+ BX_FD_THIS s.result_size = 0;
+ BX_FD_THIS s.result_index = 0;
+ BX_FD_THIS s.pending_command = 0;
+ BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY;
+ return;
+ break;
+
+ case 0x4a: // read ID
+//BX_INFO(("floppy_command read ID\n")); // ???
+ drive = BX_FD_THIS s.command[1] & 0x03;
+ BX_FD_THIS s.DOR &= 0xfc;
+ BX_FD_THIS s.DOR |= drive;
+
+ motor_on = (BX_FD_THIS s.DOR>>(drive+4)) & 0x01;
+ if (motor_on == 0)
+ BX_PANIC(("floppy_command(): 4a: motor not on\n"));
+ if (drive > 1)
+ BX_PANIC(("io: 4a: bad drive #\n"));
+ BX_FD_THIS s.result_size = 7;
+ BX_FD_THIS s.result_index = 0;
+ BX_FD_THIS s.result[0] = 0; /* ??? */
+ BX_FD_THIS s.result[1] = 0;
+ BX_FD_THIS s.result[2] = 0;
+ BX_FD_THIS s.result[3] = BX_FD_THIS s.cylinder[drive];
+ BX_FD_THIS s.result[4] = 0; /* head */
+ BX_FD_THIS s.result[5] = 0; /* sector at completion */
+ BX_FD_THIS s.result[6] = 2;
+#if BX_SUPPORT_SID
+ floppy_component->drive_command_delay_control_pin(bx_options.floppy_command_delay, 0);
+#else
+ bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index,
+ bx_options.floppy_command_delay, 0 );
+#endif
+ /* data reg not ready, controller busy */
+ BX_FD_THIS s.main_status_reg = FD_MS_DIO | FD_MS_BUSY;
+ BX_FD_THIS s.pending_command = 0x4a; /* read ID pending */
+ return;
+ break;
+
+
+ case 0xe6: // read normal data
+//BX_INFO(("floppy_command read normal data\n"));
+ case 0xc5: // write normal data
+//BX_INFO(("floppy_command write normal data\n"));
+ if ( (BX_FD_THIS s.DOR & 0x08) == 0 )
+ BX_PANIC(("read/write command with DMA and int disabled\n"));
+ drive = BX_FD_THIS s.command[1] & 0x03;
+ BX_FD_THIS s.DOR &= 0xfc;
+ BX_FD_THIS s.DOR |= drive;
+
+ motor_on = (BX_FD_THIS s.DOR>>(drive+4)) & 0x01;
+ if (motor_on == 0)
+ BX_PANIC(("floppy_command(): read/write: motor not on\n"));
+ head = BX_FD_THIS s.command[3] & 0x01;
+ cylinder = BX_FD_THIS s.command[2]; /* 0..79 depending */
+ sector = BX_FD_THIS s.command[4]; /* 1..36 depending */
+ eot = BX_FD_THIS s.command[6]; /* 1..36 depending */
+ sector_size = BX_FD_THIS s.command[5];
+ data_length = BX_FD_THIS s.command[8];
+ if (bx_dbg.floppy) {
+ BX_INFO(("\n\nread/write normal data\n"));
+ BX_INFO(("BEFORE\n"));
+ BX_INFO((" drive = %u\n", (unsigned) drive));
+ BX_INFO((" head = %u\n", (unsigned) head));
+ BX_INFO((" cylinder = %u\n", (unsigned) cylinder));
+ BX_INFO((" sector = %u\n", (unsigned) sector));
+ BX_INFO((" eot = %u\n", (unsigned) eot));
+ }
+ if (drive > 1)
+ BX_PANIC(("io: bad drive #\n"));
+ if (head > 1)
+ BX_PANIC(("io: bad head #\n"));
+
+ if ( BX_FD_THIS s.media_present[drive] == 0 ) {
+ // media not in drive, return error
+
+ BX_INFO(("attempt to read/write sector %u,"
+ " sectors/track=%u\n", (unsigned) sector,
+ (unsigned) BX_FD_THIS s.media[drive].sectors_per_track));
+ BX_FD_THIS s.result_size = 7;
+ BX_FD_THIS s.result_index = 0;
+ BX_FD_THIS s.result[0] = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive; // abnormal termination
+ BX_FD_THIS s.result[1] = 0x25; // 0010 0101
+ BX_FD_THIS s.result[2] = 0x31; // 0011 0001
+ BX_FD_THIS s.result[3] = BX_FD_THIS s.cylinder[drive];
+ BX_FD_THIS s.result[4] = BX_FD_THIS s.head[drive];
+ BX_FD_THIS s.result[5] = BX_FD_THIS s.sector[drive];
+ BX_FD_THIS s.result[6] = 2; // sector size = 512
+
+ BX_FD_THIS s.pending_command = 0;
+ BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY;
+#if BX_SUPPORT_SID
+ floppy_component->drive_trigger_irq_pin();
+#else
+ BX_FD_THIS devices->pic->trigger_irq(6);
+#endif
+ return;
+ }
+
+ if (sector_size != 0x02) { // 512 bytes
+ BX_PANIC(("sector_size not 512\n"));
+ }
+ if ( cylinder >= BX_FD_THIS s.media[drive].tracks ) {
+ BX_INFO(("\nio: normal read/write: params out of range\n"));
+ BX_INFO(("*** sector # %02xh\n", (unsigned) sector));
+ BX_INFO(("*** cylinder #%02xh\n", (unsigned) cylinder));
+ BX_INFO(("*** eot #%02xh\n", (unsigned) eot));
+ BX_INFO(("*** head #%02xh\n", (unsigned) head));
+ BX_PANIC(("bailing\n"));
+ return;
+ }
+
+ if (sector > BX_FD_THIS s.media[drive].sectors_per_track) {
+ // requested sector > last sector on track
+ BX_INFO(("attempt to read/write sector %u,"
+ " sectors/track=%u\n", (unsigned) sector,
+ (unsigned) BX_FD_THIS s.media[drive].sectors_per_track));
+ // set controller to where drive would have left off
+ // after it discovered the sector was past EOT
+ BX_FD_THIS s.cylinder[drive] = cylinder;
+ BX_FD_THIS s.head[drive] = head;
+ BX_FD_THIS s.sector[drive] = BX_FD_THIS s.media[drive].sectors_per_track;
+
+ BX_FD_THIS s.result_size = 7;
+
+ BX_FD_THIS s.result_index = 0;
+ // 0100 0HDD abnormal termination
+ BX_FD_THIS s.result[0] = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive;
+ // 1000 0101 end of cyl/NDAT/NID
+ BX_FD_THIS s.result[1] = 0x86;
+ // 0000 0000
+ BX_FD_THIS s.result[2] = 0x00;
+ BX_FD_THIS s.result[3] = BX_FD_THIS s.cylinder[drive];
+ BX_FD_THIS s.result[4] = BX_FD_THIS s.head[drive];
+ BX_FD_THIS s.result[5] = BX_FD_THIS s.sector[drive];
+ BX_FD_THIS s.result[6] = 2; // sector size = 512
+
+
+#if BX_SUPPORT_SID
+ floppy_component->drive_command_delay_control_pin(bx_options.floppy_command_delay, 0);
+#else
+ bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index,
+ bx_options.floppy_command_delay, 0 );
+#endif
+ /* data reg not ready, controller busy */
+ BX_FD_THIS s.main_status_reg = FD_MS_DIO | FD_MS_BUSY;
+ BX_FD_THIS s.pending_command = BX_FD_THIS s.command[0];
+ return;
+ }
+
+#if 0
+ if (eot != BX_FD_THIS s.media[drive].sectors_per_track)
+ BX_DEBUG(("io: bad eot #%02xh\n", (unsigned) eot));
+#endif
+
+ if (cylinder != BX_FD_THIS s.cylinder[drive])
+ BX_DEBUG(("io: cylinder request != current cylinder\n"));
+
+ logical_sector = (cylinder * 2 * BX_FD_THIS s.media[drive].sectors_per_track) +
+ (head * BX_FD_THIS s.media[drive].sectors_per_track) +
+ (sector - 1);
+
+ if (logical_sector >= BX_FD_THIS s.media[drive].sectors) {
+ BX_PANIC(("io: logical sector out of bounds\n"));
+ }
+
+ BX_FD_THIS s.cylinder[drive] = cylinder;
+ BX_FD_THIS s.sector[drive] = sector;
+ BX_FD_THIS s.head[drive] = head;
+
+ if (BX_FD_THIS s.command[0] == 0xe6) { // read
+ floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
+ 512, FROM_FLOPPY);
+ BX_FD_THIS s.floppy_buffer_index = 0;
+
+#if BX_SUPPORT_SID
+ floppy_component->channel_request(FLOPPY_DMA_CHAN, 1);
+#else
+ bx_pc_system.set_DRQ(FLOPPY_DMA_CHAN, 1);
+#endif
+
+ /* data reg not ready, controller busy */
+ BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY;
+ BX_FD_THIS s.pending_command = BX_FD_THIS s.command[0];
+ return;
+ }
+ else if (BX_FD_THIS s.command[0] == 0xc5) { // write
+ BX_FD_THIS s.floppy_buffer_index = 0;
+
+#if BX_SUPPORT_SID
+ floppy_component->channel_request(FLOPPY_DMA_CHAN, 1);
+#else
+ bx_pc_system.set_DRQ(FLOPPY_DMA_CHAN, 1);
+#endif
+
+ /* data reg not ready, controller busy */
+ BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY;
+ BX_FD_THIS s.pending_command = BX_FD_THIS s.command[0];
+ return;
+ }
+ else
+ BX_PANIC(("floppy_command(): unknown read/write command\n"));
+
+ return;
+ break;
+
+ default:
+ BX_PANIC(("floppy_command(): unknown function\n"));
+ }
+ BX_PANIC(("\nfloppy_command()\n"));
+#endif
+}
+
+ void
+bx_floppy_ctrl_c::floppy_xfer(Bit8u drive, Bit32u offset, Bit8u *buffer,
+ Bit32u bytes, Bit8u direction)
+{
+ int ret;
+
+ if (drive > 1)
+ BX_PANIC(("floppy_xfer: drive > 1\n"));
+
+ if (bx_dbg.floppy) {
+ BX_INFO(("drive=%u\n", (unsigned) drive));
+ BX_INFO(("offset=%u\n", (unsigned) offset));
+ BX_INFO(("bytes=%u\n", (unsigned) bytes));
+ BX_INFO(("direction=%s\n", (direction==FROM_FLOPPY)? "from" : "to"));
+ }
+
+#ifdef macintosh
+ if (strcmp(bx_options.floppya.path, SuperDrive))
+#endif
+ {
+ ret = lseek(BX_FD_THIS s.media[drive].fd, offset, SEEK_SET);
+ if (ret < 0) {
+ BX_PANIC(("could not perform lseek() on floppy image file\n"));
+ }
+ }
+
+ if (direction == FROM_FLOPPY) {
+#ifdef macintosh
+ if (!strcmp(bx_options.floppya.path, SuperDrive))
+ ret = fd_read((char *) buffer, offset, bytes);
+ else
+#endif
+ ret = ::read(BX_FD_THIS s.media[drive].fd, (bx_ptr_t) buffer, bytes);
+ if (ret < int(bytes)) {
+ /* ??? */
+ if (ret > 0) {
+ BX_INFO(("partial read() on floppy image returns %u/%u\n",
+ (unsigned) ret, (unsigned) bytes));
+ memset(buffer + ret, 0, bytes - ret);
+ }
+ else {
+ BX_INFO(("read() on floppy image returns 0\n"));
+ memset(buffer, 0, bytes);
+ }
+ }
+ }
+
+ else { // TO_FLOPPY
+#ifdef macintosh
+ if (!strcmp(bx_options.floppya.path, SuperDrive))
+ ret = fd_write((char *) buffer, offset, bytes);
+ else
+#endif
+ ret = ::write(BX_FD_THIS s.media[drive].fd, (bx_ptr_t) buffer, bytes);
+ if (ret < int(bytes)) {
+ BX_PANIC(("could not perform write() on floppy image file\n"));
+ }
+ }
+}
+
+
+
+ void
+bx_floppy_ctrl_c::timer_handler(void *this_ptr)
+{
+#if defined(SIMX86)
+ printf("Floppy timer\n");
+#endif
+
+ bx_floppy_ctrl_c *class_ptr = (bx_floppy_ctrl_c *) this_ptr;
+
+ class_ptr->timer();
+}
+
+ void
+bx_floppy_ctrl_c::timer()
+{
+ switch ( BX_FD_THIS s.pending_command ) {
+ case 0x07: // recal
+ BX_FD_THIS s.pending_command = 0;
+ /* write ready, not busy */
+ BX_FD_THIS s.main_status_reg = FD_MS_MRQ;
+#if BX_SUPPORT_SID
+ floppy_component->drive_trigger_irq_pin();
+#else
+ BX_FD_THIS devices->pic->trigger_irq(6);
+#endif
+ goto reset_changeline;
+ break;
+
+ case 0x0f: // seek
+ BX_FD_THIS s.pending_command = 0;
+ /* write ready, not busy */
+ BX_FD_THIS s.main_status_reg = FD_MS_MRQ;
+#if BX_SUPPORT_SID
+ floppy_component->drive_trigger_irq_pin();
+#else
+ BX_FD_THIS devices->pic->trigger_irq(6);
+#endif
+ goto reset_changeline;
+ break;
+
+
+ case 0x4a: /* read ID */
+ case 0xc5: // write normal data
+ case 0xe6: // read normal data
+ BX_FD_THIS s.pending_command = 0;
+ /* read ready, busy */
+ BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO;
+#if BX_SUPPORT_SID
+ floppy_component->drive_trigger_irq_pin();
+#else
+ BX_FD_THIS devices->pic->trigger_irq(6);
+#endif
+ break;
+
+ case 0xfe: // (contrived) RESET
+ reset(BX_RESET_SOFTWARE);
+ BX_FD_THIS s.pending_command = 0;
+ BX_FD_THIS s.main_status_reg = FD_MS_MRQ;
+#if BX_SUPPORT_SID
+ floppy_component->drive_trigger_irq_pin();
+#else
+ BX_FD_THIS devices->pic->trigger_irq(6);
+#endif
+ break;
+
+ default:
+ BX_PANIC(("floppy:timer(): unknown case %02x\n",
+ (unsigned) BX_FD_THIS s.pending_command));
+ }
+ return;
+
+reset_changeline:
+ unsigned drive = BX_FD_THIS s.DOR & 0x3;
+ if (drive > 1) return;
+ if (BX_FD_THIS s.media_present[drive])
+ BX_FD_THIS s.DIR &= ~0x80; // clear disk change line
+}
+
+#if BX_SUPPORT_SID
+void
+bx_floppy_ctrl_c::dma_write(Bit32u phy_addr)
+#else
+ void
+bx_floppy_ctrl_c::dma_write(Bit8u *data_byte)
+#endif
+{
+ // A DMA write is from I/O to Memory
+ // We need to return then next data byte from the floppy buffer
+ // to be transfered via the DMA to memory. (read block from floppy)
+
+
+#if BX_SUPPORT_SID
+ floppy_component->dma_write(phy_addr, s.floppy_buffer[s.floppy_buffer_index++]);
+#else
+ *data_byte = BX_FD_THIS s.floppy_buffer[BX_FD_THIS s.floppy_buffer_index++];
+#endif
+
+ if (BX_FD_THIS s.floppy_buffer_index >= 512) {
+ Bit8u drive;
+
+ drive = BX_FD_THIS s.DOR & 0x03;
+ increment_sector(); // increment to next sector before retrieving next one
+ BX_FD_THIS s.floppy_buffer_index = 0;
+#if BX_SUPPORT_SID
+ if (floppy_component->terminal_count()) {
+#else
+ if (bx_pc_system.TC) { // Terminal Count line, done
+#endif
+ BX_FD_THIS s.pending_command = 0;
+ BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY;
+ BX_FD_THIS s.result_size = 7;
+ BX_FD_THIS s.result_index = 0;
+ BX_FD_THIS s.result[0] = (BX_FD_THIS s.head[drive] << 2) | drive;
+ BX_FD_THIS s.result[1] = 0;
+ BX_FD_THIS s.result[2] = 0;
+ BX_FD_THIS s.result[3] = BX_FD_THIS s.cylinder[drive];
+ BX_FD_THIS s.result[4] = BX_FD_THIS s.head[drive];
+ BX_FD_THIS s.result[5] = BX_FD_THIS s.sector[drive];
+ BX_FD_THIS s.result[6] = 2;
+
+ if (bx_dbg.floppy) {
+ BX_INFO(("<<READ DONE>>\n"));
+ BX_INFO(("AFTER\n"));
+ BX_INFO((" drive = %u\n", (unsigned) drive));
+ BX_INFO((" head = %u\n", (unsigned) BX_FD_THIS s.head[drive]));
+ BX_INFO((" cylinder = %u\n", (unsigned) BX_FD_THIS s.cylinder[drive]));
+ BX_INFO((" sector = %u\n", (unsigned) BX_FD_THIS s.sector[drive]));
+ }
+
+#if BX_SUPPORT_SID
+ floppy_component->drive_trigger_irq_pin();
+ floppy_component->channel_request(FLOPPY_DMA_CHAN, 0);
+#else
+ BX_FD_THIS devices->pic->trigger_irq(6);
+ bx_pc_system.set_DRQ(FLOPPY_DMA_CHAN, 0);
+#endif
+ }
+ else { // more data to transfer
+ Bit32u logical_sector;
+ logical_sector = (BX_FD_THIS s.cylinder[drive] * 2 *
+ BX_FD_THIS s.media[drive].sectors_per_track) +
+ (BX_FD_THIS s.head[drive] *
+ BX_FD_THIS s.media[drive].sectors_per_track) +
+ (BX_FD_THIS s.sector[drive] - 1);
+ floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
+ 512, FROM_FLOPPY);
+ }
+ }
+}
+
+#if BX_SUPPORT_SID
+ void
+bx_floppy_ctrl_c::dma_read(Bit32u phy_addr)
+#else
+ void
+bx_floppy_ctrl_c::dma_read(Bit8u *data_byte)
+#endif
+{
+ // A DMA read is from Memory to I/O
+ // We need to write the data_byte which was already transfered from memory
+ // via DMA to I/O (write block to floppy)
+
+ Bit8u drive;
+ Bit32u logical_sector;
+
+#if BX_SUPPORT_SID
+ floppy_component->dma_read(phy_addr, & s.floppy_buffer[s.floppy_buffer_index++]);
+#else
+ BX_FD_THIS s.floppy_buffer[BX_FD_THIS s.floppy_buffer_index++] = *data_byte;
+#endif
+
+ if (BX_FD_THIS s.floppy_buffer_index >= 512) {
+ drive = BX_FD_THIS s.DOR & 0x03;
+ logical_sector = (BX_FD_THIS s.cylinder[drive] * 2 * BX_FD_THIS s.media[drive].sectors_per_track) +
+ (BX_FD_THIS s.head[drive] * BX_FD_THIS s.media[drive].sectors_per_track) +
+ (BX_FD_THIS s.sector[drive] - 1);
+ floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
+ 512, TO_FLOPPY);
+ increment_sector(); // increment to next sector after writing current one
+ BX_FD_THIS s.floppy_buffer_index = 0;
+#if BX_SUPPORT_SID
+ if (floppy_component->terminal_count()) {
+#else
+ if (bx_pc_system.TC) { // Terminal Count line, done
+#endif
+ BX_FD_THIS s.pending_command = 0;
+ BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY;
+ BX_FD_THIS s.result_size = 7;
+ BX_FD_THIS s.result_index = 0;
+ BX_FD_THIS s.result[0] = (BX_FD_THIS s.head[drive] << 2) | drive;
+ BX_FD_THIS s.result[1] = 0;
+ BX_FD_THIS s.result[2] = 0;
+ BX_FD_THIS s.result[3] = BX_FD_THIS s.cylinder[drive];
+ BX_FD_THIS s.result[4] = BX_FD_THIS s.head[drive];
+ BX_FD_THIS s.result[5] = BX_FD_THIS s.sector[drive];
+ BX_FD_THIS s.result[6] = 2;
+ if (bx_dbg.floppy) {
+ BX_INFO(("<<WRITE DONE>>\n"));
+ BX_INFO(("AFTER\n"));
+ BX_INFO((" drive = %u\n", (unsigned) drive));
+ BX_INFO((" head = %u\n", (unsigned) BX_FD_THIS s.head[drive]));
+ BX_INFO((" cylinder = %u\n", (unsigned) BX_FD_THIS s.cylinder[drive]));
+ BX_INFO((" sector = %u\n", (unsigned) BX_FD_THIS s.sector[drive]));
+ }
+
+#if BX_SUPPORT_SID
+ floppy_component->drive_trigger_irq_pin();
+ floppy_component->channel_request(FLOPPY_DMA_CHAN, 0);
+#else
+ BX_FD_THIS devices->pic->trigger_irq(6);
+ bx_pc_system.set_DRQ(FLOPPY_DMA_CHAN, 0);
+#endif
+ }
+ else { // more data to transfer
+ } // else
+ } // if BX_FD_THIS s.floppy_buffer_index >= 512
+}
+
+
+
+ void
+bx_floppy_ctrl_c::increment_sector(void)
+{
+ Bit8u drive;
+
+ drive = BX_FD_THIS s.DOR & 0x03;
+
+ // values after completion of data xfer
+ // ??? calculation depends on base_count being multiple of 512
+ BX_FD_THIS s.sector[drive] ++;
+ if (BX_FD_THIS s.sector[drive] > BX_FD_THIS s.media[drive].sectors_per_track) {
+ BX_FD_THIS s.sector[drive] -= BX_FD_THIS s.media[drive].sectors_per_track;
+ BX_FD_THIS s.head[drive] ++;
+ if (BX_FD_THIS s.head[drive] > 1) {
+ BX_FD_THIS s.head[drive] = 0;
+ BX_FD_THIS s.cylinder[drive] ++;
+ if (BX_FD_THIS s.cylinder[drive] >= BX_FD_THIS s.media[drive].tracks) {
+ // Set to 1 past last possible cylinder value.
+ // I notice if I set it to tracks-1, prama linux won't boot.
+ BX_FD_THIS s.cylinder[drive] = BX_FD_THIS s.media[drive].tracks;
+ BX_INFO(("increment_sector: clamping cylinder to max\n"));
+ }
+ }
+ }
+}
+
+ unsigned
+bx_floppy_ctrl_c::set_media_status(unsigned drive, unsigned status)
+{
+ char *path;
+ unsigned type;
+
+ // if setting to the current value, nothing to do
+ if (status == BX_FD_THIS s.media_present[drive])
+ return(status);
+
+ if (status == 0) {
+ // eject floppy
+ if (BX_FD_THIS s.media[drive].fd >= 0) {
+ close( BX_FD_THIS s.media[drive].fd );
+ BX_FD_THIS s.media[drive].fd = -1;
+ }
+ BX_FD_THIS s.media_present[drive] = 0;
+ BX_FD_THIS s.DIR |= 0x80; // disk changed line
+ return(0);
+ }
+ else {
+ // insert floppy
+ if (drive == 0) {
+ path = bx_options.floppya.path;
+ type = bx_options.floppya.type;
+ }
+ else {
+ path = bx_options.floppyb.path;
+ type = bx_options.floppyb.type;
+ }
+ if (evaluate_media(type, path, & BX_FD_THIS s.media[drive])) {
+ BX_FD_THIS s.media_present[drive] = 1;
+ BX_FD_THIS s.DIR |= 0x80; // disk changed line
+ return(1);
+ }
+ else {
+ BX_FD_THIS s.media_present[drive] = 0;
+ return(0);
+ }
+ }
+}
+
+ unsigned
+bx_floppy_ctrl_c::get_media_status(unsigned drive)
+{
+ return( BX_FD_THIS s.media_present[drive] );
+}
+
+#if BX_SUPPORT_SID
+ Boolean
+bx_floppy_ctrl_c::evaluate_media(unsigned type, const char *path, floppy_t *media)
+#else
+ Boolean
+bx_floppy_ctrl_c::evaluate_media(unsigned type, char *path, floppy_t *media)
+#endif
+{
+ struct stat stat_buf;
+ int ret;
+ char sTemp[1024];
+
+ if (type == BX_FLOPPY_NONE)
+ return(0);
+
+ // open media file (image file or device)
+#ifdef macintosh
+ media->fd = 0;
+ if (strcmp(bx_options.floppya.path, SuperDrive))
+#endif
+ media->fd = open(path, O_RDWR
+#ifdef O_BINARY
+ | O_BINARY
+#endif
+ );
+
+ if (media->fd < 0) {
+ BX_INFO(( "floppy open of %s:\n",path,strerror(errno) ));
+ return(0);
+ }
+
+#if BX_WITH_MACOS
+ if (!strcmp(bx_options.floppya.path, SuperDrive))
+ ret = fd_stat(&stat_buf);
+ else
+ ret = fstat(media->fd, &stat_buf);
+#elif BX_WITH_WIN32
+ stat_buf.st_mode = S_IFCHR;
+ // maybe replace with code that sets ret to -1 if the disk is not available
+ ret = 0;
+#else
+ // unix
+ ret = fstat(media->fd, &stat_buf);
+#endif
+ if (ret) {
+ BX_PANIC(("fstat()'ing floppy 0 drive image file returns error!\n"));
+ return(0);
+ }
+
+ if ( S_ISREG(stat_buf.st_mode) ) {
+ // regular file
+ switch (type) {
+ case BX_FLOPPY_720K: // 720K 3.5"
+ media->type = BX_FLOPPY_720K;
+ media->sectors_per_track = 9;
+ media->tracks = 80;
+ media->heads = 2;
+ break;
+ case BX_FLOPPY_1_2: // 1.2M 5.25"
+ media->type = BX_FLOPPY_1_2;
+ media->sectors_per_track = 15;
+ media->tracks = 80;
+ media->heads = 2;
+ break;
+ case BX_FLOPPY_1_44: // 1.44M 3.5"
+ media->type = BX_FLOPPY_1_44;
+ if (stat_buf.st_size <= 1474560) {
+ media->sectors_per_track = 18;
+ media->tracks = 80;
+ media->heads = 2;
+ }
+ else if (stat_buf.st_size == 1720320) {
+ media->sectors_per_track = 21;
+ media->tracks = 80;
+ media->heads = 2;
+ }
+ else if (stat_buf.st_size == 1763328) {
+ media->sectors_per_track = 21;
+ media->tracks = 82;
+ media->heads = 2;
+ }
+ else {
+ BX_INFO(("evaluate_media: file '%s' of unknown size %lu\n",
+ path, (unsigned long) stat_buf.st_size));
+ return(0);
+ }
+ break;
+ case BX_FLOPPY_2_88: // 2.88M 3.5"
+ media->type = BX_FLOPPY_2_88;
+ media->sectors_per_track = 36;
+ media->tracks = 80;
+ media->heads = 2;
+ break;
+ default:
+ BX_PANIC(("evaluate_media: unknown media type\n"));
+ }
+ media->sectors = media->heads * media->tracks * media->sectors_per_track;
+ return(1); // success
+ }
+
+ else if ( S_ISCHR(stat_buf.st_mode)
+#if BX_WITH_MACOS == 0
+#ifdef S_ISBLK
+ || S_ISBLK(stat_buf.st_mode)
+#endif
+#endif
+ ) {
+ // character or block device
+ // assume media is formatted to typical geometry for drive
+ switch (type) {
+ case BX_FLOPPY_720K: // 720K 3.5"
+ media->type = BX_FLOPPY_720K;
+ media->sectors_per_track = 9;
+ media->tracks = 80;
+ media->heads = 2;
+ break;
+ case BX_FLOPPY_1_2: // 1.2M 5.25"
+ media->type = BX_FLOPPY_1_2;
+ media->sectors_per_track = 15;
+ media->tracks = 80;
+ media->heads = 2;
+ break;
+ case BX_FLOPPY_1_44: // 1.44M 3.5"
+ media->type = BX_FLOPPY_1_44;
+ media->sectors_per_track = 18;
+ media->tracks = 80;
+ media->heads = 2;
+ break;
+ case BX_FLOPPY_2_88: // 2.88M 3.5"
+ media->type = BX_FLOPPY_2_88;
+ media->sectors_per_track = 36;
+ media->tracks = 80;
+ media->heads = 2;
+ break;
+ default:
+ BX_PANIC(("evaluate_media: unknown media type\n"));
+ }
+ media->sectors = media->heads * media->tracks * media->sectors_per_track;
+ return(1); // success
+ }
+ else {
+ // unknown file type
+ BX_INFO(("unknown mode type\n"));
+ return(0);
+ }
+}
+
+#if BX_SUPPORT_SID
+void
+bx_floppy_ctrl_c::call_evaluate_media(unsigned type, const char * path, unsigned floppy_num)
+{
+ if (evaluate_media(type, path, & BX_FD_THIS s.media[floppy_num]))
+ BX_FD_THIS s.media_present[floppy_num] = 1;
+}
+#endif
--- /dev/null
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+#define FROM_FLOPPY 10
+#define TO_FLOPPY 11
+
+
+#if BX_USE_FD_SMF
+# define BX_FD_SMF static
+# define BX_FD_THIS bx_floppy.
+#else
+# define BX_FD_SMF
+# define BX_FD_THIS this->
+#endif
+
+#if BX_SUPPORT_SID
+class floppy;
+#endif
+typedef struct {
+ int fd; /* file descriptor of floppy image file */
+ unsigned sectors_per_track; /* number of sectors/track */
+ unsigned sectors; /* number of formatted sectors on diskette */
+ unsigned tracks; /* number of tracks */
+ unsigned heads; /* number of heads */
+ unsigned type;
+ } floppy_t;
+
+class bx_floppy_ctrl_c : public logfunctions {
+public:
+
+ bx_floppy_ctrl_c(void);
+ ~bx_floppy_ctrl_c(void);
+#if BX_SUPPORT_SID
+ BX_FD_SMF void init(floppy *floppy_comp);
+#else
+ BX_FD_SMF void init(bx_devices_c *d, bx_cmos_c *cmos);
+#endif
+ BX_FD_SMF void reset(unsigned source);
+#if BX_SUPPORT_SID
+ BX_FD_SMF void dma_write(Bit32u phy_addr);
+ BX_FD_SMF void dma_read(Bit32u phy_addr);
+#else
+ BX_FD_SMF void dma_write(Bit8u *data_byte);
+ BX_FD_SMF void dma_read(Bit8u *data_byte);
+#endif
+ BX_FD_SMF unsigned set_media_status(unsigned drive, unsigned status);
+ BX_FD_SMF unsigned get_media_status(unsigned drive);
+
+private:
+
+ struct {
+ Bit8u data_rate;
+
+ Bit8u command[10]; /* largest command size ??? */
+ Bit8u command_index;
+ Bit8u command_size;
+ Boolean command_complete;
+ Bit8u pending_command;
+
+ Bit8u result[10];
+ Bit8u result_index;
+ Bit8u result_size;
+
+ Bit8u DOR; // Digital Ouput Register
+ Bit8u TDR; // Tape Drive Register
+ Bit8u cylinder[4]; // really only using 2 drives
+ Bit8u head[4]; // really only using 2 drives
+ Bit8u sector[4]; // really only using 2 drives
+
+ /* MAIN STATUS REGISTER
+ * b7: MRQ: main request 1=data register ready 0=data register not ready
+ * b6: DIO: data input/output:
+ * 1=controller->CPU (ready for data read)
+ * 0=CPU->controller (ready for data write)
+ * b5: NDMA: non-DMA mode: 1=controller not in DMA modes
+ * 0=controller in DMA mode
+ * b4: BUSY: instruction(device busy) 1=active 0=not active
+ * b3-0: ACTD, ACTC, ACTB, ACTA:
+ * drive D,C,B,A in positioning mode 1=active 0=not active
+ */
+ Bit8u main_status_reg;
+
+ Bit8u status_reg0;
+ Bit8u status_reg1;
+ Bit8u status_reg2;
+ Bit8u status_reg3;
+
+ floppy_t media[2];
+ unsigned num_supported_floppies;
+ Bit8u floppy_buffer[512+2]; // 2 extra for good measure
+ unsigned floppy_buffer_index;
+ int floppy_timer_index;
+ Boolean media_present[2];
+ Bit8u DIR; // Digital Input Register:
+ // b7: 0=diskette is present and has not been changed
+ // 1=diskette missing or changed
+ } s; // state information
+
+#if BX_SUPPORT_SID
+ floppy *floppy_component;
+#else
+ bx_devices_c *devices;
+#endif
+
+ static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+ static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+#if BX_SUPPORT_SID
+ public:
+#endif
+#if !BX_USE_FD_SMF
+ Bit32u read(Bit32u address, unsigned io_len);
+ void write(Bit32u address, Bit32u value, unsigned io_len);
+#endif
+#if BX_SUPPORT_SID
+ private:
+#endif
+ BX_FD_SMF void floppy_command(void);
+ BX_FD_SMF void floppy_xfer(Bit8u drive, Bit32u offset, Bit8u *buffer, Bit32u bytes, Bit8u direction);
+ static void timer_handler(void *);
+
+public:
+ BX_FD_SMF void timer(void);
+ BX_FD_SMF void increment_sector(void);
+#if BX_SUPPORT_SID
+ BX_FD_SMF void call_evaluate_media(unsigned type, const char * path, unsigned floppy_num);
+ BX_FD_SMF Boolean evaluate_media(unsigned type, const char *path, floppy_t *floppy);
+#else
+ BX_FD_SMF Boolean evaluate_media(unsigned type, char *path, floppy_t *floppy);
+#endif
+ };
+
+#if BX_SUPPORT_SID
+extern bx_floppy_ctrl_c bx_floppy;
+#endif
--- /dev/null
+// sid-floppy-wrapper.cc - SID import of the bochs floppy component. -*- C++ -*-
+
+// Copyright (C) 1999, 2000, 2001, 2002 Red Hat.
+// This file is part of SID and is licensed under the GPL.
+// See the file COPYING.SID for conditions for redistribution.
+
+#include "sid-floppy-wrapper.h"
+
+floppy::floppy ()
+ : init_pin(this, & floppy::init),
+ reset_pin(this, & floppy::reset),
+ command_delay_pin(this, & floppy::command_delay),
+ dma_channel_pin(this, & floppy::dma_channel),
+ ports_0x3f2_0x3f7_bus(this, & floppy::read_port_0x3f2_0x3f7, & floppy::write_port_0x3f2_0x3f7),
+ floppy_dma_channel(2), floppy_irq_number(6), floppy_a_type("1.44"), floppy_b_type("none"),
+ cmos_registers_bus(0), dma_channels_bus(0), dma_bus(0)
+{
+ add_pin("terminal-count", & this->terminal_count_pin);
+
+ add_pin("trigger-irq", & this->trigger_irq_pin);
+ add_pin("command-delay-control", & this->command_delay_control_pin);
+
+ add_pin("init", & this->init_pin);
+ add_pin("reset", & this->reset_pin);
+ add_pin("command-delay", & this->command_delay_pin);
+
+ add_bus("ports-0x3f2-0x3f7", & this->ports_0x3f2_0x3f7_bus);
+
+ add_accessor("cmos-registers", & this->cmos_registers_bus);
+ add_accessor("dma-channels", & this->dma_channels_bus);
+ add_accessor("dma", & this->dma_bus);
+
+ add_pin("read-write", & this->read_write_pin);
+ add_pin("dma-channel", & this->dma_channel_pin);
+
+ add_attribute("floppy-a-type", & this->floppy_a_type, "setting");
+ add_attribute("floppy-b-type", & this->floppy_b_type, "setting");
+
+ add_attribute("floppy-a-path", & this->floppy_a_path, "setting");
+ add_attribute("floppy-b-path", & this->floppy_b_path, "setting");
+
+ add_attribute("floppy-a-inserted?", & this->floppy_a_is_inserted, "setting");
+ add_attribute("floppy-b-inserted?", & this->floppy_b_is_inserted, "setting");
+
+ add_attribute("dma-channel", & this->floppy_dma_channel, "setting");
+ add_attribute("irq-number", & this->floppy_irq_number, "setting");
+}
+
+void
+floppy::init(host_int_4)
+{
+ host_int_1 num_floppies = 0;
+ host_int_1 bx_floppy_type = BX_FLOPPY_NONE;
+ little_int_1 old_register_value;
+ little_int_1 new_register_value;
+
+ bx_floppy.init(this);
+
+ // Check for floppy a:
+
+ // start out with no drive 0 and no drive 1
+ old_register_value = 0x0;
+
+ if (cmos_registers_bus)
+ cmos_registers_bus->write(host_int_4(0x10), old_register_value);
+
+ if (floppy_a_type == "none")
+ {
+ new_register_value = (old_register_value & 0x0f) | 0x00;
+ bx_floppy_type = BX_FLOPPY_NONE;
+ }
+ else if (floppy_a_type == "1.2")
+ {
+ new_register_value = (old_register_value & 0x0f) | 0x20;
+ bx_floppy_type = BX_FLOPPY_1_2;
+ }
+ else if (floppy_a_type == "720")
+ {
+ new_register_value = (old_register_value & 0x0f) | 0x30;
+ bx_floppy_type = BX_FLOPPY_720K;
+ }
+ else if (floppy_a_type == "1.44")
+ {
+ new_register_value = (old_register_value & 0x0f) | 0x40;
+ bx_floppy_type = BX_FLOPPY_1_44;
+ }
+ else if (floppy_a_type == "2.88")
+ {
+ new_register_value = (old_register_value & 0x0f) | 0x50;
+ bx_floppy_type = BX_FLOPPY_2_88;
+ }
+ else
+ cerr << "floppy: Invalid floppy a type." << endl;
+
+ if (bx_floppy_type != BX_FLOPPY_NONE)
+ {
+ num_floppies++;
+ if (floppy_a_is_inserted)
+ bx_floppy.call_evaluate_media(bx_floppy_type, floppy_a_path.c_str(), 0);
+ }
+
+ // Check for floppy b:
+ if (floppy_b_type == "none")
+ {
+ new_register_value = (new_register_value & 0xf0) | 0x00;
+ bx_floppy_type = BX_FLOPPY_NONE;
+ }
+ else if (floppy_b_type == "1.2")
+ {
+ new_register_value = (new_register_value & 0xf0) | 0x02;
+ bx_floppy_type = BX_FLOPPY_1_2;
+ }
+ else if (floppy_b_type == "720")
+ {
+ new_register_value = (new_register_value & 0xf0) | 0x03;
+ bx_floppy_type = BX_FLOPPY_720K;
+ }
+ else if (floppy_b_type == "1.44")
+ {
+ new_register_value = (new_register_value & 0xf0) | 0x04;
+ bx_floppy_type = BX_FLOPPY_1_44;
+ }
+ else if (floppy_b_type == "2.88")
+ {
+ new_register_value = (new_register_value & 0xf0) | 0x05;
+ bx_floppy_type = BX_FLOPPY_2_88;
+ }
+ else
+ cerr << "floppy: Invalid floppy b type." << endl;
+
+ if (bx_floppy_type != BX_FLOPPY_NONE)
+ {
+ num_floppies++;
+ if (floppy_b_is_inserted)
+ bx_floppy.call_evaluate_media(bx_floppy_type, floppy_b_path.c_str(), 1);
+ }
+
+ if (cmos_registers_bus)
+ {
+ cmos_registers_bus->write(host_int_4(0x10), new_register_value);
+
+ cmos_registers_bus->read(host_int_4(0x14), old_register_value);
+
+ if (num_floppies > 0)
+ {
+ new_register_value = (old_register_value & 0x3e) | ((num_floppies - 1) << 6) | 1;
+ cmos_registers_bus->write(host_int_4(0x14), new_register_value);
+ }
+ else
+ {
+ new_register_value = old_register_value & 0x3e;
+ cmos_registers_bus->write(host_int_4(0x14), new_register_value);
+ }
+ }
+}
+
+void
+floppy::reset(host_int_4)
+{
+ bx_floppy.reset(BX_RESET_HARDWARE);
+}
+
+void
+floppy::drive_trigger_irq_pin(void)
+{
+ trigger_irq_pin.drive(floppy_irq_number);
+}
+
+void
+floppy::drive_command_delay_control_pin(host_int_4 value, bool regular)
+{
+ host_int_4 code = value | (regular << 31);
+
+ command_delay_control_pin.drive(code);
+}
+
+void
+floppy::channel_request(host_int_4 channel, little_int_1 val)
+{
+ if (dma_channels_bus)
+ dma_channels_bus->write(channel, val);
+ else
+ cerr << "floppy: dma-channels bus not connected." << endl;
+}
+
+bool
+floppy::terminal_count(void)
+{
+ return terminal_count_pin.sense();
+}
+
+bus::status
+floppy::read_port_0x3f2_0x3f7 (host_int_4 addr, little_int_1 mask, little_int_1 & data)
+{
+ addr += 0x3f2;
+ data = bx_floppy.read(addr, 1);
+ return bus::ok;
+}
+
+bus::status
+floppy::write_port_0x3f2_0x3f7 (host_int_4 addr, little_int_1 mask, little_int_1 data)
+{
+ addr += 0x3f2;
+ bx_floppy.write(addr, data, 1);
+ return bus::ok;
+}
+
+host_int_4
+floppy::dma_channel_number(void)
+{
+ return floppy_dma_channel;
+}
+
+void
+floppy::dma_channel(host_int_4 phy_addr)
+{
+ if (read_write_pin.sense())
+ // read mode
+ bx_floppy.dma_read(phy_addr);
+ else
+ // write mode
+ bx_floppy.dma_write(phy_addr);
+}
+
+void
+floppy::dma_write(host_int_4 addr, little_int_1 data)
+{
+ dma_bus->write(addr, data);
+}
+
+void
+floppy::dma_read(host_int_4 addr, unsigned char *data)
+{
+ little_int_1 read_data;
+
+ dma_bus->read(addr, read_data);
+
+ *data = read_data;
+}
+
+void
+floppy::command_delay(host_int_4)
+{
+ bx_floppy.timer();
+}
--- /dev/null
+// sid-floppy-wrapper.h - SID import of the bochs floppy component. -*- C++ -*-
+
+// Copyright (C) 1999, 2000, 2001, 2002 Red Hat.
+// This file is part of SID and is licensed under the GPL.
+// See the file COPYING.SID for conditions for redistribution.
+
+#ifndef SID_FLOPPY_WRAPPER_DEF_H
+#define SID_FLOPPY_WRAPPER_DEF_H 1
+
+#include <sidtypes.h>
+#include <sidcomp.h>
+#include <sidcomputil.h>
+#include <sidpinutil.h>
+#include <sidbusutil.h>
+#include <sidattrutil.h>
+#include <sidcpuutil.h>
+#include <sidpinattrutil.h>
+#include <sidmiscutil.h>
+#include <sidwatchutil.h>
+#include <sidso.h>
+
+#include "bochs.h"
+
+using sid::component;
+using sid::bus;
+using sid::host_int_1;
+using sid::host_int_4;
+using sid::little_int_1;
+using sidutil::callback_word_bus;
+using sidutil::callback_pin;
+using sidutil::output_pin;
+using sidutil::input_pin;
+
+class floppy : public sidutil::fixed_pin_map_component,
+ public sidutil::fixed_accessor_map_component,
+ public sidutil::fixed_attribute_map_component,
+ public sidutil::no_relation_component,
+ public sidutil::fixed_bus_map_component
+{
+public:
+ floppy();
+ ~floppy() throw() {};
+
+ void init(host_int_4);
+ void reset(host_int_4);
+ void drive_trigger_irq_pin(void);
+ void drive_command_delay_control_pin(host_int_4 value, bool regular);
+ void channel_request(host_int_4 channel, little_int_1 val);
+ bool terminal_count(void);
+ host_int_4 dma_channel_number(void);
+ void dma_channel(host_int_4 phy_addr);
+ void dma_write(host_int_4 addr, little_int_1 data);
+ void dma_read(host_int_4 addr, unsigned char *data);
+ void command_delay(host_int_4);
+protected:
+
+ // read == 1, write == 0
+ input_pin read_write_pin;
+ callback_pin<floppy> dma_channel_pin;
+
+ input_pin terminal_count_pin;
+
+ callback_pin<floppy> command_delay_pin;
+ output_pin command_delay_control_pin;
+
+ output_pin trigger_irq_pin;
+
+ callback_pin<floppy> init_pin;
+ callback_pin<floppy> reset_pin;
+
+ bus::status read_port_0x3f2_0x3f7 (host_int_4 addr, little_int_1 mask, little_int_1 & data);
+ bus::status write_port_0x3f2_0x3f7 (host_int_4 addr, little_int_1 mask, little_int_1 data);
+
+ callback_word_bus<floppy, little_int_1> ports_0x3f2_0x3f7_bus;
+
+ bus *cmos_registers_bus;
+ bus *dma_channels_bus;
+ bus *dma_bus;
+
+ std::string floppy_a_type;
+ std::string floppy_b_type;
+
+ std::string floppy_a_path;
+ std::string floppy_b_path;
+
+ bool floppy_a_is_inserted;
+ bool floppy_b_is_inserted;
+
+ host_int_4 floppy_dma_channel;
+ host_int_4 floppy_irq_number;
+ bx_floppy_ctrl_c bx_floppy;
+};
+#endif // SID_FLOPPY_WRAPPER_DEF_H
int x, y; /* window position */
unsigned int border_width = 4; /* four pixels */
#if BX_CPU_LEVEL < 2
- char *window_name = "Bochs 8086 emulator, http://bochs.sourceforge.net/";
+ char *window_name = "SID Import of the Bochs 8086 Emulator";
#elif BX_CPU_LEVEL == 2
- char *window_name = "Bochs 80286 emulator, http://bochs.sourceforge.net/";
+ char *window_name = "SID Import of the Bochs 80286 Emulator";
#elif BX_CPU_LEVEL == 3
- char *window_name = "Bochs 80386 emulator, http://bochs.sourceforge.net/";
+ char *window_name = "SID Import of the Bochs 80386 Emulator";
#elif BX_CPU_LEVEL == 4
- char *window_name = "Bochs 80486 emulator, http://bochs.sourceforge.net/";
+ char *window_name = "SID Import of the Bochs 80486 Emulator";
#else
- char *window_name = "Bochs Pentium emulator, http://bochs.sourceforge.net/";
+ char *window_name = "SID Import of the Bochs Pentium Emulator";
#endif
- char *icon_name = "Bochs";
+ char *icon_name = "SID Bochs";
Pixmap icon_pixmap;
XSizeHints size_hints;
char *display_name = NULL;
dimension_x = x;
dimension_y = y;
}
- XFlush(bx_x_display);
dimensions_updated_pin.driven(0);
}
(char *) string,
1);
}
- XFlush(bx_x_display);
text_memory_updated_pin.driven(0);
}
}
bool private_colormap;
};
-#endif X_GUI_DEF_H
+#endif // X_GUI_DEF_H
+
#include "bochs.h"
+#if BX_SUPPORT_SID
#include "sid-keyboard-wrapper.h"
#define LOG_THIS
-
+#else
+#define LOG_THIS bx_keyboard.
+#endif
#define VERBOSE_KBD_DEBUG 0
#define MOUSE_MODE_STREAM 11
#define MOUSE_MODE_REMOTE 12
#define MOUSE_MODE_WRAP 13
-
+#if BX_SUPPORT_SID==0
+bx_keyb_c bx_keyboard;
+#endif
#if BX_USE_KEY_SMF
#define this (&bx_keyboard)
#endif
bx_keyb_c::bx_keyb_c(void)
{
+#if BX_SUPPORT_SID
+ bx_dbg.keyboard = 1;
+#endif
// constructor
// should zero out state info here???
memset( &s, 0, sizeof(s) );
BX_KEY_THIS s.controller_Q[i] = 0;
BX_KEY_THIS s.controller_Qsize = 0;
BX_KEY_THIS s.controller_Qsource = 0;
-#if BX_SUPPORT_SID==0
+#if BX_SUPPORT_SID
+ kbd_component = kbd_comp;
+#else
// mouse port installed on system board
cmos->s.reg[0x14] |= 0x04;
-#else
- kbd_component = kbd_comp;
#endif
BX_DEBUG(("Init.\n"));
}
if (bx_dbg.keyboard)
BX_INFO(("keyboard: 8-bit write to %04x = %02x\n", (unsigned)address, (unsigned)value));
+
+
//BX_DEBUG(("WRITE(%02x) = %02x\n", (unsigned) address,
// (unsigned) value));
retval = BX_KEY_THIS s.kbd_controller.irq1_requested | (BX_KEY_THIS s.kbd_controller.irq12_requested << 1);
BX_KEY_THIS s.kbd_controller.irq1_requested = 0;
BX_KEY_THIS s.kbd_controller.irq12_requested = 0;
-#if BX_SUPPORT_SID==0
+
if ( BX_KEY_THIS s.kbd_controller.timer_pending == 0 ) {
return(retval);
}
BX_KEY_THIS s.kbd_controller.timer_pending -= usec_delta;
return(retval);
}
-#endif
+
if (BX_KEY_THIS s.kbd_controller.outb) {
return(retval);
}
{
if (BX_KEY_THIS s.kbd_controller.timer_pending == 0) {
BX_KEY_THIS s.kbd_controller.timer_pending = bx_options.keyboard_serial_delay;
- kbd_component->drive_serial_delay_pin(bx_options.keyboard_serial_delay);
}
}
#ifndef _PCKEY_H
#define _PCKEY_H
+#if BX_SUPPORT_SID
#include "keysymbols.h"
class keyboard;
+#endif
+
#define BX_KBD_ELEMENTS 16
#define BX_MOUSE_BUFF_SIZE 48
# define BX_KEY_SMF
# define BX_KEY_THIS this->
#endif
-
+#if BX_SUPPORT_SID==0
+extern bx_keyb_c bx_keyboard;
+#endif
class bx_keyb_c : public logfunctions {
public:
bx_keyb_c(void);
case 8:
ret = 3;
break;
- };
+#if BX_SUPPORT_SID==0
+ default:
+#define LOG_THIS bx_keyboard.
+ BX_PANIC(("mouse: invalid resolution_cpmm"));
+#undef LOG_THIS
+#endif
+ };
return ret;
}
unsigned controller_Qsize;
unsigned controller_Qsource; // 0=keyboard, 1=mouse
} s; // State information for saving/loading
-#if BX_SUPPORT_SID==0
- bx_devices_c *devices;
-#else
+#if BX_SUPPORT_SID
keyboard *kbd_component;
+#else
+ bx_devices_c *devices;
#endif
BX_KEY_SMF void resetinternals(Boolean powerup);
BX_KEY_SMF void set_kbd_clock_enable(Bit8u value);
generate_scancode_pin(this, & keyboard::generate_scancode),
update_keyboard_pin(this, & keyboard::update_keyboard),
port_0x60_bus(this, & keyboard::read_port_0x60, & keyboard::write_port_0x60),
- port_0x64_bus(this, & keyboard::read_port_0x64, & keyboard::write_port_0x64)
+ port_0x64_bus(this, & keyboard::read_port_0x64, & keyboard::write_port_0x64),
+ cmos_registers_bus(0), timer_delta(100), keyboard_irq_number(1), have_mouse(false)
{
+ add_pin("trigger-irq", & this->trigger_irq_pin);
+ add_pin("enable-a20", & this->enable_a20_pin);
+ add_pin("a20-enabled", & this->a20_enabled_pin);
+
add_pin("init", & this->init_pin);
add_pin("generate-scancode", & this->generate_scancode_pin);
add_pin("update-keyboard", & this->update_keyboard_pin);
- add_pin("serial-delay", & this->serial_delay_pin);
add_bus("port-0x60", & this->port_0x60_bus);
add_bus("port-0x64", & this->port_0x64_bus);
+
+ add_attribute("timer-delta", & this->timer_delta, "setting");
+ add_attribute("keyboard-irq-number", & this->keyboard_irq_number, "setting");
+ add_attribute("have-mouse?", & this->have_mouse, "setting");
+
+ add_accessor("cmos-registers", & this->cmos_registers_bus);
}
void
keyboard::init(host_int_4)
{
bx_keyboard.init(this);
+ if (have_mouse)
+ {
+ // mouse port installed on system board
+ if (cmos_registers_bus)
+ {
+ little_int_1 old_register_value;
+ little_int_1 new_register_value;
+
+ cmos_registers_bus->read(host_int_4(0x14), old_register_value);
+ new_register_value = old_register_value | 0x04;
+ cmos_registers_bus->write(host_int_4(0x14), new_register_value);
+ }
+ }
}
void
void
keyboard::update_keyboard(host_int_4)
{
- bx_keyboard.periodic(0);
+ unsigned val = bx_keyboard.periodic(timer_delta);
+
+ if((val & 0x01))
+ trigger_irq_pin.drive(keyboard_irq_number);
}
void
-keyboard::drive_serial_delay_pin(host_int_4 delay)
+keyboard::drive_enable_a20_pin(host_int_4 value)
+{
+ enable_a20_pin.drive(value);
+}
+
+host_int_4
+keyboard::sense_a20_enabled_pin(void)
{
- // The serial-delay pin is intended to be connected to
- // a sid-sched component's N-control pin, and the
- // update-keyboard pin is intended to be connected to
- // the corresponding N-event pin. Since update-keyboard
- // should be driven regularly, we must ensure that the
- // the top bit (the regular? flag) of the code driven on
- // the serial-delay pin is 1.
- host_int_4 code = delay | 0x80000000;
- serial_delay_pin.drive(code);
+ return a20_enabled_pin.sense();
}
bus::status
using sidutil::callback_word_bus;
using sidutil::callback_pin;
using sidutil::output_pin;
+using sidutil::input_pin;
+using sidutil::word_bus;
+using sidutil::control_register_bus;
class keyboard : public sidutil::fixed_pin_map_component,
- public sidutil::no_accessor_component,
+ public sidutil::fixed_accessor_map_component,
public sidutil::fixed_attribute_map_component,
public sidutil::no_relation_component,
public sidutil::fixed_bus_map_component
void init(host_int_4);
void generate_scancode(host_int_4 code);
void update_keyboard(host_int_4);
-
- void drive_serial_delay_pin(host_int_4 delay);
-
+ void drive_enable_a20_pin(host_int_4 value);
+ host_int_4 sense_a20_enabled_pin(void);
protected:
+ output_pin trigger_irq_pin;
+ output_pin enable_a20_pin;
+ input_pin a20_enabled_pin;
+
callback_pin<keyboard> init_pin;
callback_pin<keyboard> generate_scancode_pin;
callback_pin<keyboard> update_keyboard_pin;
- output_pin serial_delay_pin;
-
bus::status read_port_0x60 (host_int_4 addr, little_int_1 mask, little_int_1 & data);
bus::status write_port_0x60 (host_int_4 addr, little_int_1 mask, little_int_1 data);
callback_word_bus<keyboard, little_int_1> port_0x60_bus;
callback_word_bus<keyboard, little_int_1> port_0x64_bus;
+ bus *cmos_registers_bus;
+
+ host_int_4 timer_delta;
+ host_int_4 keyboard_irq_number;
+ bool have_mouse;
+
bx_keyb_c bx_keyboard;
};
#endif // SID_KEYBOARD_WRAPPER_DEF_H
--- /dev/null
+## Process this with automake to create Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(top_builddir)/../../include -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../../../include -I$(srcdir)/../cpu
+
+noinst_LTLIBRARIES = libpic.la
+
+libpic_la_SOURCES = sid-pic-wrapper.cc sid-pic-wrapper.h pic.cc pic.h
+
+libpic_la_LDFLAGS = -no-undefined
--- /dev/null
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+APIC_OBJS = @APIC_OBJS@
+AR = @AR@
+AS = @AS@
+AS_DYNAMIC_INCS = @AS_DYNAMIC_INCS@
+AS_DYNAMIC_OBJS = @AS_DYNAMIC_OBJS@
+BX_LOADER_OBJS = @BX_LOADER_OBJS@
+BX_SPLIT_HD_SUPPORT = @BX_SPLIT_HD_SUPPORT@
+CC = @CC@
+CDROM_OBJS = @CDROM_OBJS@
+CD_UP_ONE = @CD_UP_ONE@
+CD_UP_TWO = @CD_UP_TWO@
+CFP = @CFP@
+COMMAND_SEPARATOR = @COMMAND_SEPARATOR@
+CPP_SUFFIX = @CPP_SUFFIX@
+CXX = @CXX@
+CXXFP = @CXXFP@
+DASH = @DASH@
+DEBUGGER_VAR = @DEBUGGER_VAR@
+DISASM_VAR = @DISASM_VAR@
+DLLTOOL = @DLLTOOL@
+DYNAMIC_VAR = @DYNAMIC_VAR@
+EXE = @EXE@
+EXEEXT = @EXEEXT@
+EXTERNAL_DEPENDENCY = @EXTERNAL_DEPENDENCY@
+FPU_GLUE_OBJ = @FPU_GLUE_OBJ@
+FPU_VAR = @FPU_VAR@
+GUI_LINK_OPTS = @GUI_LINK_OPTS@
+GUI_LINK_OPTS_TERM = @GUI_LINK_OPTS_TERM@
+GUI_OBJS = @GUI_OBJS@
+GZIP = @GZIP@
+INLINE_VAR = @INLINE_VAR@
+INSTRUMENT_DIR = @INSTRUMENT_DIR@
+INSTRUMENT_VAR = @INSTRUMENT_VAR@
+IOAPIC_OBJS = @IOAPIC_OBJS@
+IODEV_LIB_VAR = @IODEV_LIB_VAR@
+LD = @LD@
+LIBTOOL = @LIBTOOL@
+LINK = @LINK@
+LN_S = @LN_S@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MAKELIB = @MAKELIB@
+NE2K_OBJS = @NE2K_OBJS@
+NM = @NM@
+NONINLINE_VAR = @NONINLINE_VAR@
+OBJDUMP = @OBJDUMP@
+OFP = @OFP@
+PACKAGE = @PACKAGE@
+PCI_OBJ = @PCI_OBJ@
+PRIMARY_TARGET = @PRIMARY_TARGET@
+RANLIB = @RANLIB@
+READLINE_LIB = @READLINE_LIB@
+RFB_LIBS = @RFB_LIBS@
+RMCOMMAND = @RMCOMMAND@
+SB16_OBJS = @SB16_OBJS@
+SLASH = @SLASH@
+SUFFIX_LINE = @SUFFIX_LINE@
+TAR = @TAR@
+VERSION = @VERSION@
+VIDEO_OBJS = @VIDEO_OBJS@
+sidtarget_arm = @sidtarget_arm@
+sidtarget_m32r = @sidtarget_m32r@
+sidtarget_m68k = @sidtarget_m68k@
+sidtarget_mips = @sidtarget_mips@
+sidtarget_ppc = @sidtarget_ppc@
+sidtarget_x86 = @sidtarget_x86@
+sidtarget_xstormy16 = @sidtarget_xstormy16@
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(top_builddir)/../../include -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../../../include -I$(srcdir)/../cpu
+
+noinst_LTLIBRARIES = libpic.la
+
+libpic_la_SOURCES = sid-pic-wrapper.cc sid-pic-wrapper.h pic.cc pic.h
+
+libpic_la_LDFLAGS = -no-undefined
+mkinstalldirs = $(SHELL) $(top_srcdir)/../../config/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_LIBS = @X_LIBS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+libpic_la_LIBADD =
+libpic_la_OBJECTS = sid-pic-wrapper.lo pic.lo
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+DIST_COMMON = Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+GZIP_ENV = --best
+DEP_FILES = .deps/pic.P .deps/sid-pic-wrapper.P
+SOURCES = $(libpic_la_SOURCES)
+OBJECTS = $(libpic_la_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .cc .lo .o .s
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --foreign pic/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLTLIBRARIES:
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+
+distclean-noinstLTLIBRARIES:
+
+maintainer-clean-noinstLTLIBRARIES:
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.s.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+libpic.la: $(libpic_la_OBJECTS) $(libpic_la_DEPENDENCIES)
+ $(CXXLINK) $(libpic_la_LDFLAGS) $(libpic_la_OBJECTS) $(libpic_la_LIBADD) $(LIBS)
+.cc.o:
+ $(CXXCOMPILE) -c $<
+.cc.lo:
+ $(LTCXXCOMPILE) -c $<
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = pic
+
+distdir: $(DISTFILES)
+ here=`cd $(top_builddir) && pwd`; \
+ top_distdir=`cd $(top_distdir) && pwd`; \
+ distdir=`cd $(distdir) && pwd`; \
+ cd $(top_srcdir) \
+ && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --foreign pic/Makefile
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+ -rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+ @echo '$(COMPILE) -c $<'; \
+ $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.c
+ @echo '$(LTCOMPILE) -c $<'; \
+ $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+
+%.o: %.cc
+ @echo '$(CXXCOMPILE) -c $<'; \
+ $(CXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.cc
+ @echo '$(LTCXXCOMPILE) -c $<'; \
+ $(LTCXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LTLIBRARIES)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-noinstLTLIBRARIES mostlyclean-compile \
+ mostlyclean-libtool mostlyclean-tags mostlyclean-depend \
+ mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-noinstLTLIBRARIES clean-compile clean-libtool \
+ clean-tags clean-depend clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-noinstLTLIBRARIES distclean-compile \
+ distclean-libtool distclean-tags distclean-depend \
+ distclean-generic clean-am
+ -rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-noinstLTLIBRARIES \
+ maintainer-clean-compile maintainer-clean-libtool \
+ maintainer-clean-tags maintainer-clean-depend \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLTLIBRARIES distclean-noinstLTLIBRARIES \
+clean-noinstLTLIBRARIES maintainer-clean-noinstLTLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-libtool distclean-libtool \
+clean-libtool maintainer-clean-libtool tags mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir \
+mostlyclean-depend distclean-depend clean-depend \
+maintainer-clean-depend info-am info dvi-am dvi check check-am \
+installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+#include "bochs.h"
+#if BX_SUPPORT_SID
+#define LOG_THIS
+#else
+#define LOG_THIS bx_pic.
+
+
+
+bx_pic_c bx_pic;
+#endif
+#if BX_USE_PIC_SMF
+#define this (&bx_pic)
+#endif
+
+
+#if BX_SUPPORT_SID
+#include "sid-pic-wrapper.h"
+#endif
+
+
+bx_pic_c::bx_pic_c(void)
+{
+#if BX_SUPPORT_SID
+ bx_dbg.pic = 1;
+#endif
+ setprefix("[PIC ]");
+ settype(PICLOG);
+}
+
+bx_pic_c::~bx_pic_c(void)
+{
+ // nothing for now
+}
+
+
+#if BX_SUPPORT_SID
+void
+bx_pic_c::init(pic *pic_comp)
+#else
+ void
+bx_pic_c::init(bx_devices_c *d)
+#endif
+{
+#if BX_SUPPORT_SID==0
+ BX_PIC_THIS devices = d;
+
+ /* 8259 PIC (Programmable Interrupt Controller) */
+ BX_PIC_THIS devices->register_io_read_handler(this, read_handler, 0x0020, "8259 PIC");
+ BX_PIC_THIS devices->register_io_read_handler(this, read_handler, 0x0021, "8259 PIC");
+ BX_PIC_THIS devices->register_io_read_handler(this, read_handler, 0x00A0, "8259 PIC");
+ BX_PIC_THIS devices->register_io_read_handler(this, read_handler, 0x00A1, "8259 PIC");
+
+ BX_PIC_THIS devices->register_io_write_handler(this, write_handler, 0x0020, "8259 PIC");
+ BX_PIC_THIS devices->register_io_write_handler(this, write_handler, 0x0021, "8259 PIC");
+ BX_PIC_THIS devices->register_io_write_handler(this, write_handler, 0x00A0, "8259 PIC");
+ BX_PIC_THIS devices->register_io_write_handler(this, write_handler, 0x00A1, "8259 PIC");
+#endif
+
+
+ BX_PIC_THIS s.master_pic.single_PIC = 0;
+ BX_PIC_THIS s.master_pic.interrupt_offset = 0x08; /* IRQ0 = INT 0x08 */
+ /* slave PIC connected to IRQ2 of master */
+ BX_PIC_THIS s.master_pic.u.slave_connect_mask = 0x04;
+ BX_PIC_THIS s.master_pic.sfnm = 0; /* normal nested mode */
+ BX_PIC_THIS s.master_pic.buffered_mode = 0; /* unbuffered mode */
+ BX_PIC_THIS s.master_pic.master_slave = 0; /* no meaning, buffered_mode=0 */
+ BX_PIC_THIS s.master_pic.auto_eoi = 0; /* manual EOI from CPU */
+ BX_PIC_THIS s.master_pic.imr = 0xFF; /* all IRQ's initially masked */
+ BX_PIC_THIS s.master_pic.isr = 0x00; /* no IRQ's in service */
+ BX_PIC_THIS s.master_pic.irr = 0x00; /* no IRQ's requested */
+ BX_PIC_THIS s.master_pic.read_reg_select = 0; /* IRR */
+ BX_PIC_THIS s.master_pic.irq = 0;
+ BX_PIC_THIS s.master_pic.INT = 0;
+ BX_PIC_THIS s.master_pic.init.in_init = 0;
+ BX_PIC_THIS s.master_pic.init.requires_4 = 0;
+ BX_PIC_THIS s.master_pic.init.byte_expected = 0;
+ BX_PIC_THIS s.master_pic.special_mask = 0;
+
+ BX_PIC_THIS s.slave_pic.single_PIC = 0;
+ BX_PIC_THIS s.slave_pic.interrupt_offset = 0x70; /* IRQ8 = INT 0x70 */
+ BX_PIC_THIS s.slave_pic.u.slave_id = 0x02; /* slave PIC connected to IRQ2 of master */
+ BX_PIC_THIS s.slave_pic.sfnm = 0; /* normal nested mode */
+ BX_PIC_THIS s.slave_pic.buffered_mode = 0; /* unbuffered mode */
+ BX_PIC_THIS s.slave_pic.master_slave = 0; /* no meaning, buffered_mode=0 */
+ BX_PIC_THIS s.slave_pic.auto_eoi = 0; /* manual EOI from CPU */
+ BX_PIC_THIS s.slave_pic.imr = 0xFF; /* all IRQ's initially masked */
+ BX_PIC_THIS s.slave_pic.isr = 0x00; /* no IRQ's in service */
+ BX_PIC_THIS s.slave_pic.irr = 0x00; /* no IRQ's requested */
+ BX_PIC_THIS s.slave_pic.read_reg_select = 0; /* IRR */
+ BX_PIC_THIS s.slave_pic.irq = 0;
+ BX_PIC_THIS s.slave_pic.INT = 0;
+ BX_PIC_THIS s.slave_pic.init.in_init = 0;
+ BX_PIC_THIS s.slave_pic.init.requires_4 = 0;
+ BX_PIC_THIS s.slave_pic.init.byte_expected = 0;
+ BX_PIC_THIS s.slave_pic.special_mask = 0;
+
+ pic_component = pic_comp;
+}
+
+
+
+ // static IO port read callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ Bit32u
+bx_pic_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_PIC_SMF
+ bx_pic_c *class_ptr = (bx_pic_c *) this_ptr;
+
+ return( class_ptr->read(address, io_len) );
+}
+
+
+
+ Bit32u
+bx_pic_c::read(Bit32u address, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_PIC_SMF
+ if (io_len > 1)
+ BX_PANIC(("io read from port %04x, len=%u\n", (unsigned) address,
+ (unsigned) io_len));
+
+ BX_DEBUG(("IO read from %04x\n", (unsigned) address));
+
+ /*
+ 8259A PIC
+ */
+
+ switch (address) {
+ case 0x20:
+ if (BX_PIC_THIS s.master_pic.read_reg_select) { /* ISR */
+ if (bx_dbg.pic) BX_INFO(("read master ISR = %02x\n",
+ (unsigned) BX_PIC_THIS s.master_pic.isr));
+ return(BX_PIC_THIS s.master_pic.isr);
+ }
+ else { /* IRR */
+ if (bx_dbg.pic) BX_INFO(("read master IRR = %02x\n",
+ (unsigned) BX_PIC_THIS s.master_pic.irr));
+ return(BX_PIC_THIS s.master_pic.irr);
+ }
+ break;
+ case 0x21:
+ if (bx_dbg.pic) BX_INFO(("read master IMR = %02x\n",
+ (unsigned) BX_PIC_THIS s.master_pic.imr));
+ return(BX_PIC_THIS s.master_pic.imr);
+ break;
+ case 0xA0:
+ if (BX_PIC_THIS s.slave_pic.read_reg_select) { /* ISR */
+ if (bx_dbg.pic) BX_INFO(("read slave ISR = %02x\n",
+ (unsigned) BX_PIC_THIS s.slave_pic.isr));
+ return(BX_PIC_THIS s.slave_pic.isr);
+ }
+ else { /* IRR */
+ if (bx_dbg.pic) BX_INFO(("read slave IRR = %02x\n",
+ (unsigned) BX_PIC_THIS s.slave_pic.irr));
+ return(BX_PIC_THIS s.slave_pic.irr);
+ }
+ break;
+ case 0xA1:
+ if (bx_dbg.pic) BX_INFO(("read slave IMR = %02x\n",
+ (unsigned) BX_PIC_THIS s.slave_pic.imr));
+ return(BX_PIC_THIS s.slave_pic.imr);
+ break;
+ }
+
+ BX_PANIC(("io read to address %04x\n", (unsigned) address));
+ return(0); /* default if not found above */
+}
+
+
+ // static IO port write callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ void
+bx_pic_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_PIC_SMF
+ bx_pic_c *class_ptr = (bx_pic_c *) this_ptr;
+
+ class_ptr->write(address, value, io_len);
+}
+
+ void
+bx_pic_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_PIC_SMF
+ int irq;
+
+ if (io_len > 1)
+ BX_PANIC(("io write to port %04x, len=%u\n", (unsigned) address,
+ (unsigned) io_len));
+
+ if (bx_dbg.pic)
+ BX_INFO(("IO write to %04x = %02x\n",
+ (unsigned) address, (unsigned) value));
+
+ /*
+ 8259A PIC
+ */
+
+ switch (address) {
+ case 0x20:
+ if (value & 0x10) { /* initialization command 1 */
+ // (mch) Ignore...
+ // BX_INFO(("pic:master: init command 1 found %02x\n", (unsigned) value));
+ if (bx_dbg.pic) {
+ BX_INFO(("pic:master: init command 1 found\n"));
+ BX_INFO((" requires 4 = %u\n",
+ (unsigned) (value & 0x01) ));
+ BX_INFO((" cascade mode: [0=cascade,1=single] %u\n",
+ (unsigned) ((value & 0x02) >> 1)));
+ }
+ BX_PIC_THIS s.master_pic.init.in_init = 1;
+ BX_PIC_THIS s.master_pic.init.requires_4 = (value & 0x01);
+ BX_PIC_THIS s.master_pic.init.byte_expected = 2; /* operation command 2 */
+ BX_PIC_THIS s.master_pic.imr = 0xFF; /* all IRQ's initially masked */
+ BX_PIC_THIS s.master_pic.isr = 0x00; /* no IRQ's in service */
+ BX_PIC_THIS s.master_pic.irr = 0x00; /* no IRQ's requested */
+ BX_PIC_THIS s.master_pic.INT = 0; /* reprogramming clears previous INTR request */
+ if ( (value & 0x02) == 1 )
+ BX_PANIC(("pic:master: init command: single mode\n"));
+#if BX_SUPPORT_SID
+ pic_component->drive_interrupt_pin(0);
+#else
+ BX_SET_INTR(0);
+#endif
+ return;
+ }
+
+ if ( (value & 0x18) == 0x08 ) { /* OCW3 */
+ Bit8u special_mask, poll, read_op;
+
+ special_mask = (value & 0x60) >> 5;
+ poll = (value & 0x04) >> 2;
+ read_op = (value & 0x03);
+ if (poll)
+ BX_PANIC(("pic:master:OCW3: poll bit set\n"));
+ if (read_op == 0x02) /* read IRR */
+ BX_PIC_THIS s.master_pic.read_reg_select = 0;
+ else if (read_op == 0x03) /* read ISR */
+ BX_PIC_THIS s.master_pic.read_reg_select = 1;
+ if (special_mask == 0x02) { /* cancel special mask */
+ BX_PIC_THIS s.master_pic.special_mask = 0;
+ }
+ else if (special_mask == 0x03) { /* set specific mask */
+ BX_PIC_THIS s.master_pic.special_mask = 1;
+ service_master_pic();
+ }
+ return;
+ }
+
+ /* OCW2 */
+ switch (value) {
+ case 0x00: // Rotate in Auto-EOI mode
+ BX_PANIC(("PIC: Rotate in Auto-EOI mode command received.\n"));
+ case 0x0A: /* select read interrupt request register */
+ BX_PIC_THIS s.master_pic.read_reg_select = 0;
+ break;
+ case 0x0B: /* select read interrupt in-service register */
+ BX_PIC_THIS s.master_pic.read_reg_select = 1;
+ break;
+
+ case 0x20: /* end of interrupt command */
+ /* clear highest current in service bit */
+ for (irq=0; irq<=7; irq++) {
+ if (BX_PIC_THIS s.master_pic.isr & (1 << irq)) {
+ BX_PIC_THIS s.master_pic.isr &= ~(1 << irq);
+ break; /* out of for loop */
+ }
+ }
+ service_master_pic();
+ break;
+
+ case 0x60: /* specific EOI 0 */
+ case 0x61: /* specific EOI 1 */
+ case 0x62: /* specific EOI 2 */
+ case 0x63: /* specific EOI 3 */
+ case 0x64: /* specific EOI 4 */
+ case 0x65: /* specific EOI 5 */
+ case 0x66: /* specific EOI 6 */
+ case 0x67: /* specific EOI 7 */
+ BX_PIC_THIS s.master_pic.isr &= ~(1 << (value-0x60));
+ service_master_pic();
+ break;
+
+ // IRQ lowest priority commands
+ case 0xC0: // 0 7 6 5 4 3 2 1
+ case 0xC1: // 1 0 7 6 5 4 3 2
+ case 0xC2: // 2 1 0 7 6 5 4 3
+ case 0xC3: // 3 2 1 0 7 6 5 4
+ case 0xC4: // 4 3 2 1 0 7 6 5
+ case 0xC5: // 5 4 3 2 1 0 7 6
+ case 0xC6: // 6 5 4 3 2 1 0 7
+ case 0xC7: // 7 6 5 4 3 2 1 0
+ // ignore for now
+ BX_INFO(("IRQ lowest command 0x%x\n", value));
+ break;
+
+ default:
+ BX_PANIC(("PIC: write to port 20h = %02x\n", value));
+ } /* switch (value) */
+ break;
+
+ case 0x21:
+ /* initialization mode operation */
+ if (BX_PIC_THIS s.master_pic.init.in_init) {
+ switch (BX_PIC_THIS s.master_pic.init.byte_expected) {
+ case 2:
+ BX_PIC_THIS s.master_pic.interrupt_offset = value & 0xf8;
+ BX_PIC_THIS s.master_pic.init.byte_expected = 3;
+ if (bx_dbg.pic) {
+ BX_INFO(("pic:master: init command 2 = %02x\n", (unsigned) value));
+ BX_INFO((" offset = INT %02x\n",
+ BX_PIC_THIS s.master_pic.interrupt_offset));
+ }
+ return;
+ break;
+ case 3:
+ if (bx_dbg.pic)
+ BX_INFO(("pic:master: init command 3 = %02x\n", (unsigned) value));
+ if (BX_PIC_THIS s.master_pic.init.requires_4) {
+ BX_PIC_THIS s.master_pic.init.byte_expected = 4;
+ }
+ else {
+ BX_PIC_THIS s.master_pic.init.in_init = 0;
+ }
+ return;
+ break;
+ case 4:
+ if (bx_dbg.pic) {
+ BX_INFO(("pic:master: init command 4 = %02x\n", (unsigned) value));
+ if (value & 0x02) BX_INFO((" auto EOI\n"));
+ else BX_INFO(("normal EOI interrupt\n"));
+ }
+ if (value & 0x01) {
+ if (bx_dbg.pic)
+ BX_INFO((" 80x86 mode\n"));
+ } else
+ BX_PANIC((" not 80x86 mode\n"));
+ BX_PIC_THIS s.master_pic.init.in_init = 0;
+ return;
+ break;
+ default:
+ BX_PANIC(("pic:master expecting bad init command\n"));
+ }
+ }
+
+ /* normal operation */
+ if (bx_dbg.pic)
+ BX_INFO(("setting master pic IMR to %02x\n", value));
+ BX_PIC_THIS s.master_pic.imr = value;
+ service_master_pic();
+ return;
+ break;
+
+ case 0xA0:
+ if (value & 0x10) { /* initialization command 1 */
+ BX_DEBUG(("slave: init command 1 found\n"));
+ BX_DEBUG((" requires 4 = %u\n",
+ (unsigned) (value & 0x01) ));
+ BX_DEBUG((" cascade mode: [0=cascade,1=single] %u\n",
+ (unsigned) ((value & 0x02) >> 1)));
+ BX_PIC_THIS s.slave_pic.init.in_init = 1;
+ BX_PIC_THIS s.slave_pic.init.requires_4 = (value & 0x01);
+ BX_PIC_THIS s.slave_pic.init.byte_expected = 2; /* operation command 2 */
+ BX_PIC_THIS s.slave_pic.imr = 0xFF; /* all IRQ's initially masked */
+ BX_PIC_THIS s.slave_pic.isr = 0x00; /* no IRQ's in service */
+ BX_PIC_THIS s.slave_pic.irr = 0x00; /* no IRQ's requested */
+ BX_PIC_THIS s.slave_pic.INT = 0; /* reprogramming clears previous INTR request */
+ if ( (value & 0x02) == 1 )
+ BX_PANIC(("slave: init command: single mode\n"));
+ return;
+ }
+
+ if ( (value & 0x18) == 0x08 ) { /* OCW3 */
+ Bit8u special_mask, poll, read_op;
+
+ special_mask = (value & 0x60) >> 5;
+ poll = (value & 0x04) >> 2;
+ read_op = (value & 0x03);
+ if (poll)
+ BX_PANIC(("slave:OCW3: poll bit set\n"));
+ if (read_op == 0x02) /* read IRR */
+ BX_PIC_THIS s.slave_pic.read_reg_select = 0;
+ else if (read_op == 0x03) /* read ISR */
+ BX_PIC_THIS s.slave_pic.read_reg_select = 1;
+ if (special_mask == 0x02) { /* cancel special mask */
+ BX_PIC_THIS s.slave_pic.special_mask = 0;
+ }
+ else if (special_mask == 0x03) { /* set specific mask */
+ BX_PIC_THIS s.slave_pic.special_mask = 1;
+ service_slave_pic();
+ BX_ERROR(("slave: OCW3 not implemented (%02x)\n",
+ (unsigned) value));
+ }
+ return;
+ }
+
+ switch (value) {
+ case 0x0A: /* select read interrupt request register */
+ BX_PIC_THIS s.slave_pic.read_reg_select = 0;
+ break;
+ case 0x0B: /* select read interrupt in-service register */
+ BX_PIC_THIS s.slave_pic.read_reg_select = 1;
+ break;
+ case 0x20: /* end of interrupt command */
+ /* clear highest current in service bit */
+ for (irq=0; irq<=7; irq++) {
+ if (BX_PIC_THIS s.slave_pic.isr & (1 << irq)) {
+ BX_PIC_THIS s.slave_pic.isr &= ~(1 << irq);
+ break; /* out of for loop */
+ }
+ }
+ service_slave_pic();
+ break;
+
+ case 0x60: /* specific EOI 0 */
+ case 0x61: /* specific EOI 1 */
+ case 0x62: /* specific EOI 2 */
+ case 0x63: /* specific EOI 3 */
+ case 0x64: /* specific EOI 4 */
+ case 0x65: /* specific EOI 5 */
+ case 0x66: /* specific EOI 6 */
+ case 0x67: /* specific EOI 7 */
+ BX_PIC_THIS s.slave_pic.isr &= ~(1 << (value-0x60));
+ service_slave_pic();
+ break;
+
+ default:
+ BX_PANIC(("PIC: write to port A0h = %02x\n", value));
+ } /* switch (value) */
+ break;
+
+ case 0xA1:
+ /* initialization mode operation */
+ if (BX_PIC_THIS s.slave_pic.init.in_init) {
+ switch (BX_PIC_THIS s.slave_pic.init.byte_expected) {
+ case 2:
+ BX_PIC_THIS s.slave_pic.interrupt_offset = value & 0xf8;
+ BX_PIC_THIS s.slave_pic.init.byte_expected = 3;
+ if (bx_dbg.pic) {
+ BX_DEBUG(("slave: init command 2 = %02x\n", (unsigned) value));
+ BX_DEBUG((" offset = INT %02x\n",
+ BX_PIC_THIS s.slave_pic.interrupt_offset));
+ }
+ return;
+ break;
+ case 3:
+ BX_DEBUG(("slave: init command 3 = %02x\n", (unsigned) value));
+ if (BX_PIC_THIS s.slave_pic.init.requires_4) {
+ BX_PIC_THIS s.slave_pic.init.byte_expected = 4;
+ } else {
+ BX_PIC_THIS s.slave_pic.init.in_init = 0;
+ }
+ return;
+ break;
+ case 4:
+ if (bx_dbg.pic) {
+ BX_DEBUG(("slave: init command 4 = %02x\n", (unsigned) value));
+ if (value & 0x02) BX_INFO((" auto EOI\n"));
+ else BX_DEBUG(("normal EOI interrupt\n"));
+ }
+ if (value & 0x01) {
+ if (bx_dbg.pic)
+ BX_INFO((" 80x86 mode\n"));
+ } else BX_PANIC(("not 80x86 mode\n"));
+ BX_PIC_THIS s.slave_pic.init.in_init = 0;
+ return;
+ break;
+ default:
+ BX_PANIC(("slave: expecting bad init command\n"));
+ }
+ }
+
+ /* normal operation */
+ if (bx_dbg.pic)
+ BX_INFO(("setting slave pic IMR to %02x\n", value));
+ BX_PIC_THIS s.slave_pic.imr = value;
+ service_slave_pic();
+ return;
+ break;
+ } /* switch (address) */
+
+ return;
+}
+
+ void
+bx_pic_c::trigger_irq(unsigned irq_no)
+{
+#if BX_SUPPORT_APIC
+ // forward this function call to the ioapic too
+ BX_PIC_THIS devices->ioapic->trigger_irq (irq_no, -1);
+#endif
+
+ int irq_no_bitmask;
+
+#if BX_DEBUG
+ if ( irq_no > 15 )
+ BX_PANIC(("trigger_irq: irq out of range\n"));
+#endif
+
+ if (bx_dbg.pic)
+ BX_INFO(("trigger_irq(%d decimal)\n", (unsigned) irq_no));
+
+ if (irq_no <= 7) {
+ irq_no_bitmask = 1 << irq_no;
+ BX_PIC_THIS s.master_pic.irr |= irq_no_bitmask;
+ service_master_pic();
+ }
+ else { // irq = 8..15
+ irq_no_bitmask = 1 << (irq_no - 8);
+ BX_PIC_THIS s.slave_pic.irr |= irq_no_bitmask;
+ service_slave_pic();
+ }
+}
+
+ void
+bx_pic_c::untrigger_irq(unsigned irq_no)
+{
+#if BX_SUPPORT_APIC
+ // forward this function call to the ioapic too
+ BX_PIC_THIS devices->ioapic->untrigger_irq (irq_no, -1);
+#endif
+
+ int irq_no_bitmask;
+
+#if BX_DEBUG
+ if ( irq_no > 15 )
+ BX_PANIC(("untrigger_irq: irq out of range\n"));
+#endif
+
+ if (bx_dbg.pic)
+ BX_INFO(("untrigger_irq(%d decimal)\n", (unsigned) irq_no));
+
+ if (irq_no <= 7) {
+ irq_no_bitmask = 1 << irq_no;
+ if (BX_PIC_THIS s.master_pic.imr & irq_no_bitmask) {
+ BX_PIC_THIS s.master_pic.irr &= ~irq_no_bitmask;
+ }
+ }
+ else { // irq = 8..15
+ irq_no_bitmask = 1 << (irq_no - 8);
+ if (BX_PIC_THIS s.slave_pic.imr & irq_no_bitmask) {
+ BX_PIC_THIS s.slave_pic.irr &= ~irq_no_bitmask;
+ }
+ }
+}
+
+ /* */
+ void
+bx_pic_c::service_master_pic(void)
+{
+ Bit8u unmasked_requests;
+ int irq;
+ Bit8u isr, max_irq;
+
+ if (BX_PIC_THIS s.master_pic.INT) { /* last interrupt still not acknowleged */
+ return;
+ }
+
+ if (BX_PIC_THIS s.master_pic.special_mask) {
+ /* all priorities may be enabled. check all IRR bits except ones
+ * which have corresponding ISR bits set
+ */
+ max_irq = 7;
+ }
+ else { /* normal mode */
+ /* Find the highest priority IRQ that is enabled due to current ISR */
+ isr = BX_PIC_THIS s.master_pic.isr;
+ if (isr) {
+ max_irq = 0;
+ while ( (isr & 0x01) == 0 ) {
+ isr >>= 1;
+ max_irq++;
+ }
+ if (max_irq == 0 ) return; /* IRQ0 in-service, no other priorities allowed */
+ if (max_irq > 7) BX_PANIC(("error in service_master_pic()\n"));
+ }
+ else
+ max_irq = 7; /* 0..7 bits in ISR are cleared */
+ }
+
+
+ /* now, see if there are any higher priority requests */
+ if ((unmasked_requests = (BX_PIC_THIS s.master_pic.irr & ~BX_PIC_THIS s.master_pic.imr)) ) {
+ for (irq=0; irq<=max_irq; irq++) {
+ /* for special mode, since we're looking at all IRQ's, skip if
+ * current IRQ is already in-service
+ */
+ if ( BX_PIC_THIS s.master_pic.special_mask && ((BX_PIC_THIS s.master_pic.isr >> irq) & 0x01) )
+ continue;
+ if (unmasked_requests & (1 << irq)) {
+ BX_DEBUG(("signalling IRQ(%u)\n", (unsigned) irq));
+ BX_PIC_THIS s.master_pic.irr &= ~(1 << irq);
+ /*??? do for slave too: BX_PIC_THIS s.master_pic.isr |= (1 << irq);*/
+ BX_PIC_THIS s.master_pic.INT = 1;
+#if BX_SUPPORT_SID
+ pic_component->drive_interrupt_pin(1);
+#else
+ BX_SET_INTR(1);
+#endif
+ BX_PIC_THIS s.master_pic.irq = irq;
+ return;
+ } /* if (unmasked_requests & ... */
+ } /* for (irq=7 ... */
+ } /* if (unmasked_requests = ... */
+}
+
+
+ void
+bx_pic_c::service_slave_pic(void)
+{
+ Bit8u unmasked_requests;
+ int irq;
+ Bit8u isr, lowest_priority_irq;
+
+ if (BX_PIC_THIS s.slave_pic.INT) { /* last interrupt still not acknowleged */
+ return;
+ }
+
+ /* Find the highest priority IRQ that is enabled due to current ISR */
+ isr = BX_PIC_THIS s.slave_pic.isr;
+ if (isr) {
+ lowest_priority_irq = 0;
+ while ( !(isr & 0x01) ) {
+ isr >>= 1;
+ lowest_priority_irq++;
+ }
+ if (lowest_priority_irq > 7) BX_PANIC(("error in service_slave_pic()\n"));
+ }
+ else
+ lowest_priority_irq = 8;
+
+
+ /* now, see if there are any higher priority requests */
+ if ((unmasked_requests = (BX_PIC_THIS s.slave_pic.irr & ~BX_PIC_THIS s.slave_pic.imr)) ) {
+ for (irq=0; irq<lowest_priority_irq; irq++) {
+ if (unmasked_requests & (1 << irq)) {
+ if (bx_dbg.pic)
+ BX_DEBUG(("slave: signalling IRQ(%u)\n",
+ (unsigned) 8 + irq));
+ BX_PIC_THIS s.slave_pic.irr &= ~(1 << irq);
+ BX_PIC_THIS s.slave_pic.INT = 1;
+ BX_PIC_THIS s.master_pic.irr |= 0x04; /* request IRQ 2 on master pic */
+ BX_PIC_THIS s.slave_pic.irq = irq;
+ service_master_pic();
+ return;
+ } /* if (unmasked_requests & ... */
+ } /* for (irq=7 ... */
+ } /* if (unmasked_requests = ... */
+}
+
+
+ /* CPU handshakes with PIC after acknowledging interrupt */
+ Bit8u
+bx_pic_c::IAC(void)
+{
+ Bit8u vector;
+ Bit8u irq;
+
+#if BX_SUPPORT_SID
+ pic_component->drive_interrupt_pin(0);
+#else
+ BX_SET_INTR(0);
+#endif
+ BX_PIC_THIS s.master_pic.INT = 0;
+ BX_PIC_THIS s.master_pic.isr |= (1 << BX_PIC_THIS s.master_pic.irq);
+ BX_PIC_THIS s.master_pic.irr &= ~(1 << BX_PIC_THIS s.master_pic.irq);
+
+ if (BX_PIC_THIS s.master_pic.irq != 2) {
+ irq = BX_PIC_THIS s.master_pic.irq;
+ vector = irq + BX_PIC_THIS s.master_pic.interrupt_offset;
+ }
+ else { /* IRQ2 = slave pic IRQ8..15 */
+ BX_PIC_THIS s.slave_pic.INT = 0;
+ irq = BX_PIC_THIS s.slave_pic.irq;
+ vector = irq + BX_PIC_THIS s.slave_pic.interrupt_offset;
+ BX_PIC_THIS s.slave_pic.isr |= (1 << BX_PIC_THIS s.slave_pic.irq);
+ BX_PIC_THIS s.slave_pic.irr &= ~(1 << BX_PIC_THIS s.slave_pic.irq);
+ service_slave_pic();
+ irq += 8; // for debug printing purposes
+ }
+
+ service_master_pic();
+
+ BX_DBG_IAC_REPORT(vector, irq);
+ return(vector);
+}
+
+ void
+bx_pic_c::show_pic_state(void)
+{
+BX_INFO(("s.master_pic.imr = %02x\n", BX_PIC_THIS s.master_pic.imr));
+BX_INFO(("s.master_pic.isr = %02x\n", BX_PIC_THIS s.master_pic.isr));
+BX_INFO(("s.master_pic.irr = %02x\n", BX_PIC_THIS s.master_pic.irr));
+BX_INFO(("s.master_pic.irq = %02x\n", BX_PIC_THIS s.master_pic.irq));
+}
--- /dev/null
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+#if BX_USE_PIC_SMF
+# define BX_PIC_SMF static
+# define BX_PIC_THIS bx_pic.
+#else
+# define BX_PIC_SMF
+# define BX_PIC_THIS this->
+#endif
+
+#if BX_SUPPORT_SID
+class pic;
+#endif
+
+typedef struct {
+ Bit8u single_PIC; /* 0=cascaded PIC, 1=master only */
+ Bit8u interrupt_offset; /* programmable interrupt vector offset */
+ union {
+ Bit8u slave_connect_mask; /* for master, a bit for each interrupt line
+ 0=not connect to a slave, 1=connected */
+ Bit8u slave_id; /* for slave, id number of slave PIC */
+ } u;
+ Bit8u sfnm; /* specially fully nested mode: 0=no, 1=yes*/
+ Bit8u buffered_mode; /* 0=no buffered mode, 1=buffered mode */
+ Bit8u master_slave; /* master/slave: 0=slave PIC, 1=master PIC */
+ Bit8u auto_eoi; /* 0=manual EOI, 1=automatic EOI */
+ Bit8u imr; /* interrupt mask register, 1=masked */
+ Bit8u isr; /* in service register */
+ Bit8u irr; /* interrupt request register */
+ Bit8u read_reg_select; /* 0=IRR, 1=ISR */
+ Bit8u irq; /* current IRQ number */
+ Boolean INT; /* INT request pin of PIC */
+ struct {
+ Boolean in_init;
+ Boolean requires_4;
+ int byte_expected;
+ } init;
+ Boolean special_mask;
+ } bx_pic_t;
+
+
+class bx_pic_c : public logfunctions {
+
+public:
+ bx_pic_c(void);
+ ~bx_pic_c(void);
+#if BX_SUPPORT_SID
+ BX_PIC_SMF void init(pic *pic_comp);
+#else
+ BX_PIC_SMF void init(bx_devices_c *);
+#endif
+ BX_PIC_SMF void trigger_irq(unsigned irq_no);
+ BX_PIC_SMF void untrigger_irq(unsigned irq_no);
+ BX_PIC_SMF Bit8u IAC(void);
+
+private:
+ struct {
+ bx_pic_t master_pic;
+ bx_pic_t slave_pic;
+ } s;
+#if BX_SUPPORT_SID
+ pic *pic_component;
+#else
+ bx_devices_c *devices;
+#endif
+ static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+ static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+#if BX_SUPPORT_SID
+ public:
+#endif
+#if !BX_USE_PIC_SMF
+ Bit32u read(Bit32u address, unsigned io_len);
+ void write(Bit32u address, Bit32u value, unsigned io_len);
+#endif
+#if BX_SUPPORT_SID
+ private:
+#endif
+ BX_PIC_SMF void service_master_pic(void);
+ BX_PIC_SMF void service_slave_pic(void);
+ BX_PIC_SMF void show_pic_state(void);
+ };
+#if BX_SUPPORT_SID==0
+extern bx_pic_c bx_pic;
+#endif
--- /dev/null
+// sid-pic-wrapper.cc - SID import of the bochs pic component. -*- C++ -*-
+
+// Copyright (C) 1999, 2000, 2001, 2002 Red Hat.
+// This file is part of SID and is licensed under the GPL.
+// See the file COPYING.SID for conditions for redistribution.
+
+#include "sid-pic-wrapper.h"
+
+pic::pic ()
+ : init_pin(this, & pic::init),
+ trigger_irq_pin(this, & pic::trigger_irq),
+ untrigger_irq_pin(this, & pic::untrigger_irq),
+ interrupt_acknowledge_pin(this, & pic::interrupt_acknowledge),
+ ports_0x20_0x21_bus(this, & pic::read_port_0x20_0x21, & pic::write_port_0x20_0x21),
+ ports_0xa0_0xa1_bus(this, & pic::read_port_0xa0_0xa1, & pic::write_port_0xa0_0xa1)
+{
+ add_pin("interrupt", & this->interrupt_pin);
+
+ add_pin("interrupt-acknowledge", & this->interrupt_acknowledge_pin);
+ add_pin("interrupt-ack-response", & this->interrupt_acknowledge_response_pin);
+
+ add_pin("init", & this->init_pin);
+ add_pin("trigger-irq", & this->trigger_irq_pin);
+ add_pin("untrigger-irq", & this->untrigger_irq_pin);
+
+ add_bus("ports-0x20-0x21", & this->ports_0x20_0x21_bus);
+ add_bus("ports-0xa0-0xa1", & this->ports_0xa0_0xa1_bus);
+}
+
+void
+pic::init(host_int_4)
+{
+ bx_pic.init(this);
+}
+
+void
+pic::trigger_irq(host_int_4 irq_number)
+{
+ bx_pic.trigger_irq(irq_number);
+}
+
+void
+pic::untrigger_irq(host_int_4 irq_number)
+{
+ bx_pic.untrigger_irq(irq_number);
+}
+
+void
+pic::interrupt_acknowledge(host_int_4)
+{
+ interrupt_acknowledge_response_pin.drive(bx_pic.IAC());
+}
+
+void
+pic::drive_interrupt_pin(host_int_4 value)
+{
+ interrupt_pin.drive(value);
+}
+
+bus::status
+pic::read_port_0x20_0x21 (host_int_4 addr, little_int_1 mask, little_int_1 & data)
+{
+ addr += 0x20;
+ data = bx_pic.read(addr, 1);
+ return bus::ok;
+}
+
+bus::status
+pic::write_port_0x20_0x21 (host_int_4 addr, little_int_1 mask, little_int_1 data)
+{
+ addr += 0x20;
+ bx_pic.write(addr, data, 1);
+ return bus::ok;
+}
+
+bus::status
+pic::read_port_0xa0_0xa1 (host_int_4 addr, little_int_1 mask, little_int_1 & data)
+{
+ addr += 0xa0;
+ data = bx_pic.read(addr, 1);
+ return bus::ok;
+}
+
+bus::status
+pic::write_port_0xa0_0xa1 (host_int_4 addr, little_int_1 mask, little_int_1 data)
+{
+ addr += 0xa0;
+ bx_pic.write(addr, data, 1);
+ return bus::ok;
+}
--- /dev/null
+// sid-pic-wrapper.h - SID import of the bochs pic component. -*- C++ -*-
+
+// Copyright (C) 1999, 2000, 2001, 2002 Red Hat.
+// This file is part of SID and is licensed under the GPL.
+// See the file COPYING.SID for conditions for redistribution.
+
+#ifndef SID_PIC_WRAPPER_DEF_H
+#define SID_PIC_WRAPPER_DEF_H 1
+
+#include <sidtypes.h>
+#include <sidcomp.h>
+#include <sidcomputil.h>
+#include <sidpinutil.h>
+#include <sidbusutil.h>
+#include <sidattrutil.h>
+#include <sidcpuutil.h>
+#include <sidpinattrutil.h>
+#include <sidmiscutil.h>
+#include <sidwatchutil.h>
+#include <sidso.h>
+
+#include "bochs.h"
+
+using sid::component;
+using sid::bus;
+using sid::host_int_4;
+using sid::little_int_1;
+using sidutil::callback_word_bus;
+using sidutil::callback_pin;
+using sidutil::output_pin;
+
+class pic : public sidutil::fixed_pin_map_component,
+ public sidutil::no_accessor_component,
+ public sidutil::fixed_attribute_map_component,
+ public sidutil::no_relation_component,
+ public sidutil::fixed_bus_map_component
+{
+public:
+ pic();
+ ~pic() throw() {};
+
+ void init(host_int_4);
+ void trigger_irq(host_int_4 irq_number);
+ void untrigger_irq(host_int_4 irq_number);
+ void interrupt_acknowledge(host_int_4);
+
+ void drive_interrupt_pin(host_int_4 value);
+
+protected:
+
+ output_pin interrupt_pin;
+ output_pin interrupt_acknowledge_response_pin;
+
+ callback_pin<pic> interrupt_acknowledge_pin;
+ callback_pin<pic> init_pin;
+ callback_pin<pic> trigger_irq_pin;
+ callback_pin<pic> untrigger_irq_pin;
+
+ bus::status read_port_0x20_0x21 (host_int_4 addr, little_int_1 mask, little_int_1 & data);
+ bus::status write_port_0x20_0x21 (host_int_4 addr, little_int_1 mask, little_int_1 data);
+
+ bus::status read_port_0xa0_0xa1 (host_int_4 addr, little_int_1 mask, little_int_1 & data);
+ bus::status write_port_0xa0_0xa1 (host_int_4 addr, little_int_1 mask, little_int_1 data);
+
+ callback_word_bus<pic, little_int_1> ports_0x20_0x21_bus;
+ callback_word_bus<pic, little_int_1> ports_0xa0_0xa1_bus;
+
+ bx_pic_c bx_pic;
+};
+#endif // SID_PIC_WRAPPER_DEF_H
--- /dev/null
+## Process this with automake to create Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(top_builddir)/../../include -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../../../include -I$(srcdir)/../cpu
+
+noinst_LTLIBRARIES = libpit.la
+
+libpit_la_SOURCES = sid-pit-wrapper.cc sid-pit-wrapper.h pit.cc pit.h
+
+libpit_la_LDFLAGS = -no-undefined
--- /dev/null
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+APIC_OBJS = @APIC_OBJS@
+AR = @AR@
+AS = @AS@
+AS_DYNAMIC_INCS = @AS_DYNAMIC_INCS@
+AS_DYNAMIC_OBJS = @AS_DYNAMIC_OBJS@
+BX_LOADER_OBJS = @BX_LOADER_OBJS@
+BX_SPLIT_HD_SUPPORT = @BX_SPLIT_HD_SUPPORT@
+CC = @CC@
+CDROM_OBJS = @CDROM_OBJS@
+CD_UP_ONE = @CD_UP_ONE@
+CD_UP_TWO = @CD_UP_TWO@
+CFP = @CFP@
+COMMAND_SEPARATOR = @COMMAND_SEPARATOR@
+CPP_SUFFIX = @CPP_SUFFIX@
+CXX = @CXX@
+CXXFP = @CXXFP@
+DASH = @DASH@
+DEBUGGER_VAR = @DEBUGGER_VAR@
+DISASM_VAR = @DISASM_VAR@
+DLLTOOL = @DLLTOOL@
+DYNAMIC_VAR = @DYNAMIC_VAR@
+EXE = @EXE@
+EXEEXT = @EXEEXT@
+EXTERNAL_DEPENDENCY = @EXTERNAL_DEPENDENCY@
+FPU_GLUE_OBJ = @FPU_GLUE_OBJ@
+FPU_VAR = @FPU_VAR@
+GUI_LINK_OPTS = @GUI_LINK_OPTS@
+GUI_LINK_OPTS_TERM = @GUI_LINK_OPTS_TERM@
+GUI_OBJS = @GUI_OBJS@
+GZIP = @GZIP@
+INLINE_VAR = @INLINE_VAR@
+INSTRUMENT_DIR = @INSTRUMENT_DIR@
+INSTRUMENT_VAR = @INSTRUMENT_VAR@
+IOAPIC_OBJS = @IOAPIC_OBJS@
+IODEV_LIB_VAR = @IODEV_LIB_VAR@
+LD = @LD@
+LIBTOOL = @LIBTOOL@
+LINK = @LINK@
+LN_S = @LN_S@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MAKELIB = @MAKELIB@
+NE2K_OBJS = @NE2K_OBJS@
+NM = @NM@
+NONINLINE_VAR = @NONINLINE_VAR@
+OBJDUMP = @OBJDUMP@
+OFP = @OFP@
+PACKAGE = @PACKAGE@
+PCI_OBJ = @PCI_OBJ@
+PRIMARY_TARGET = @PRIMARY_TARGET@
+RANLIB = @RANLIB@
+READLINE_LIB = @READLINE_LIB@
+RFB_LIBS = @RFB_LIBS@
+RMCOMMAND = @RMCOMMAND@
+SB16_OBJS = @SB16_OBJS@
+SLASH = @SLASH@
+SUFFIX_LINE = @SUFFIX_LINE@
+TAR = @TAR@
+VERSION = @VERSION@
+VIDEO_OBJS = @VIDEO_OBJS@
+sidtarget_arm = @sidtarget_arm@
+sidtarget_m32r = @sidtarget_m32r@
+sidtarget_m68k = @sidtarget_m68k@
+sidtarget_mips = @sidtarget_mips@
+sidtarget_ppc = @sidtarget_ppc@
+sidtarget_x86 = @sidtarget_x86@
+sidtarget_xstormy16 = @sidtarget_xstormy16@
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(top_builddir)/../../include -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../../../include -I$(srcdir)/../cpu
+
+noinst_LTLIBRARIES = libpit.la
+
+libpit_la_SOURCES = sid-pit-wrapper.cc sid-pit-wrapper.h pit.cc pit.h
+
+libpit_la_LDFLAGS = -no-undefined
+mkinstalldirs = $(SHELL) $(top_srcdir)/../../config/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_LIBS = @X_LIBS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+libpit_la_LIBADD =
+libpit_la_OBJECTS = sid-pit-wrapper.lo pit.lo
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+DIST_COMMON = Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+GZIP_ENV = --best
+DEP_FILES = .deps/pit.P .deps/sid-pit-wrapper.P
+SOURCES = $(libpit_la_SOURCES)
+OBJECTS = $(libpit_la_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .cc .lo .o .s
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --foreign pit/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLTLIBRARIES:
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+
+distclean-noinstLTLIBRARIES:
+
+maintainer-clean-noinstLTLIBRARIES:
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.s.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+libpit.la: $(libpit_la_OBJECTS) $(libpit_la_DEPENDENCIES)
+ $(CXXLINK) $(libpit_la_LDFLAGS) $(libpit_la_OBJECTS) $(libpit_la_LIBADD) $(LIBS)
+.cc.o:
+ $(CXXCOMPILE) -c $<
+.cc.lo:
+ $(LTCXXCOMPILE) -c $<
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = pit
+
+distdir: $(DISTFILES)
+ here=`cd $(top_builddir) && pwd`; \
+ top_distdir=`cd $(top_distdir) && pwd`; \
+ distdir=`cd $(distdir) && pwd`; \
+ cd $(top_srcdir) \
+ && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --foreign pit/Makefile
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+ -rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+ @echo '$(COMPILE) -c $<'; \
+ $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.c
+ @echo '$(LTCOMPILE) -c $<'; \
+ $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+
+%.o: %.cc
+ @echo '$(CXXCOMPILE) -c $<'; \
+ $(CXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.cc
+ @echo '$(LTCXXCOMPILE) -c $<'; \
+ $(LTCXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LTLIBRARIES)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-noinstLTLIBRARIES mostlyclean-compile \
+ mostlyclean-libtool mostlyclean-tags mostlyclean-depend \
+ mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-noinstLTLIBRARIES clean-compile clean-libtool \
+ clean-tags clean-depend clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-noinstLTLIBRARIES distclean-compile \
+ distclean-libtool distclean-tags distclean-depend \
+ distclean-generic clean-am
+ -rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-noinstLTLIBRARIES \
+ maintainer-clean-compile maintainer-clean-libtool \
+ maintainer-clean-tags maintainer-clean-depend \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLTLIBRARIES distclean-noinstLTLIBRARIES \
+clean-noinstLTLIBRARIES maintainer-clean-noinstLTLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-libtool distclean-libtool \
+clean-libtool maintainer-clean-libtool tags mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir \
+mostlyclean-depend distclean-depend clean-depend \
+maintainer-clean-depend info-am info dvi-am dvi check check-am \
+installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+#include "bochs.h"
+#if BX_SUPPORT_SID
+#define LOG_THIS
+#else
+#define LOG_THIS bx_pit.
+#endif
+
+// NOTES ON THE 8253/8254 PIT MODES
+
+// MODE 0: Interrupt on Terminal Count
+// ===================================
+// Writing new count action:
+// loaded upon next CLK pulse. counting doesn't start until GATE=1
+// GATE 0..1 transition:
+// ???
+// GATE 1..0 transition:
+// counter expiration action:
+// wraps to FFFF
+// * OUT rises until new count val or new control word for mode 0 written
+
+// MODE 1: Programmable Monoflop
+// =============================
+// Writing new count action:
+// not effective for current process
+// GATE 0..1 transition:
+// loads counter
+// counter expiration action:
+// wraps to FFFF
+// NOTES:
+// OUT rises until new count val or new control word for mode 0 written
+
+// MODE 2: Rate Generator
+// ======================
+// Writing new count action:
+// ???
+// GATE 0..1 transition:
+// loads initial count val and starts counting
+// counter expiration action:
+// reloads after count expires
+// NOTES:
+// * after control word & initial count val N loaded, PIT starts
+// counting upon next CLK pulse.
+// * when counter reaches 1, OUT drops to a low level, for one
+// CLK cycle. (short peak pulse generated)
+// * afterwards, the initial count val is automatically reloaded
+// and the PIT restarts the same counting operation again.
+// * distance of two OUT pulses is N CLK cycles long.
+// * GATE=1 enables, GATE=0 disables counter.
+// * if GATE drops to low level during counting operation and rises
+// to high level later, PIT loads initial count value at the
+// rise and starts counting.
+// * PIT starts counting after last data byte written if GATE=1
+// * if the output is low when the gate goes low, the output is
+// immediately set high.
+
+// MODE 3: Square Wave Generator
+// =============================
+// Writing new count action:
+// ???
+// GATE 0..1 transition:
+// ???
+// counter expiration action:
+// reloads after count expires
+// NOTES:
+// * initially OUT at a high level
+// * drop of GATE to a low level while OUT low, raises OUT to a high level
+// * a rise from a low to a high level at GATE (trigger pulse),
+// loads the counter with the initial count value and starts
+// counting operation
+// * a new count value supplied during the course of an active
+// counting operation doesn't affect the current process.
+// At the end of the current half cycle, the PIT loads the new value
+// * if the GATE line goes low, count is temporarily halted until GATE
+// returns high
+// * if the OUT line is high when GATE goes low, OUT is forced low.
+// ??? different for odd/even counts
+
+// MODE 4: Software Triggered Pulse
+// ================================
+// Writing new count action:
+// ???
+// GATE 0..1 transition:
+// ???
+// counter expiration action:
+// wraps to FFFF
+// NOTES:
+
+// MODE 5: Hardware Triggered Pulse
+// ================================
+// Writing new count action:
+// ???
+// GATE 0..1 transition:
+// ???
+// counter expiration action:
+// wraps to FFFF
+// NOTES:
+
+
+
+#define BX_PIT_LATCH_MODE_LSB 10
+#define BX_PIT_LATCH_MODE_MSB 11
+#define BX_PIT_LATCH_MODE_16BIT 12
+
+
+#if BX_SUPPORT_SID==0
+bx_pit_c bx_pit;
+#endif
+#if BX_USE_PIT_SMF
+#define this (&bx_pit)
+#endif
+
+#ifdef OUT
+# undef OUT
+#endif
+
+
+bx_pit_c::bx_pit_c( void )
+{
+#if BX_SUPPORT_SID
+ bx_dbg.pit = 1;
+#endif
+ setprefix("[PIT ]");
+ settype(PITLOG);
+ memset(&s, 0, sizeof(s));
+
+ /* 8254 PIT (Programmable Interval Timer) */
+
+ BX_PIT_THIS s.timer_handle[1] = BX_NULL_TIMER_HANDLE;
+ BX_PIT_THIS s.timer_handle[2] = BX_NULL_TIMER_HANDLE;
+}
+
+bx_pit_c::~bx_pit_c( void )
+{
+}
+
+#if BX_SUPPORT_SID
+void
+bx_pit_c::init(void)
+#else
+ int
+bx_pit_c::init( bx_devices_c *d )
+#endif
+{
+#if BX_SUPPORT_SID==0
+ BX_PIT_THIS devices = d;
+
+ BX_PIT_THIS devices->register_irq(0, "8254 PIT");
+ BX_PIT_THIS devices->register_io_read_handler(this, read_handler, 0x0040, "8254 PIT");
+ BX_PIT_THIS devices->register_io_read_handler(this, read_handler, 0x0041, "8254 PIT");
+ BX_PIT_THIS devices->register_io_read_handler(this, read_handler, 0x0042, "8254 PIT");
+ BX_PIT_THIS devices->register_io_read_handler(this, read_handler, 0x0043, "8254 PIT");
+ BX_PIT_THIS devices->register_io_read_handler(this, read_handler, 0x0061, "8254 PIT");
+
+ BX_PIT_THIS devices->register_io_write_handler(this, write_handler, 0x0040, "8254 PIT");
+ BX_PIT_THIS devices->register_io_write_handler(this, write_handler, 0x0041, "8254 PIT");
+ BX_PIT_THIS devices->register_io_write_handler(this, write_handler, 0x0042, "8254 PIT");
+ BX_PIT_THIS devices->register_io_write_handler(this, write_handler, 0x0043, "8254 PIT");
+ BX_PIT_THIS devices->register_io_write_handler(this, write_handler, 0x0061, "8254 PIT");
+#endif
+ BX_PIT_THIS s.speaker_data_on = 0;
+ BX_PIT_THIS s.refresh_clock_div2 = 0;
+
+ BX_PIT_THIS s.timer[0].mode = 3; /* periodic rate generator */
+ BX_PIT_THIS s.timer[0].latch_mode = BX_PIT_LATCH_MODE_16BIT;
+ BX_PIT_THIS s.timer[0].input_latch_value = 0;
+ BX_PIT_THIS s.timer[0].input_latch_toggle = 0;
+ BX_PIT_THIS s.timer[0].output_latch_value = 0;
+ BX_PIT_THIS s.timer[0].output_latch_toggle = 0;
+ BX_PIT_THIS s.timer[0].output_latch_full = 0;
+ BX_PIT_THIS s.timer[0].counter_max = 0; /* 0xFFFF + 1 : (1193182 / 65535 = 18.2Hz) */
+ BX_PIT_THIS s.timer[0].counter = 0; /* 0xFFFF + 1 : (1193182 / 65535 = 18.2Hz) */
+ BX_PIT_THIS s.timer[0].bcd_mode = 0; /* binary counting mode */
+ BX_PIT_THIS s.timer[0].GATE = 1; /* GATE tied to + logic */
+ BX_PIT_THIS s.timer[0].OUT = 1;
+ BX_PIT_THIS s.timer[0].active = 0;
+
+ BX_PIT_THIS s.timer[1].mode = 3; /* periodic rate generator */
+ BX_PIT_THIS s.timer[1].latch_mode = BX_PIT_LATCH_MODE_16BIT;
+ BX_PIT_THIS s.timer[1].input_latch_value = 0;
+ BX_PIT_THIS s.timer[1].input_latch_toggle = 0;
+ BX_PIT_THIS s.timer[1].output_latch_value = 0;
+ BX_PIT_THIS s.timer[1].output_latch_toggle = 0;
+ BX_PIT_THIS s.timer[1].output_latch_full = 0;
+ BX_PIT_THIS s.timer[1].counter_max = 0; /* 0xFFFF + 1 : (1193182 / 65535 = 18.2Hz) */
+ BX_PIT_THIS s.timer[1].counter = 0; /* 0xFFFF + 1 : (1193182 / 65535 = 18.2Hz) */
+ BX_PIT_THIS s.timer[1].bcd_mode = 0; /* binary counting mode */
+ BX_PIT_THIS s.timer[1].GATE = 1; /* GATE tied to + logic */
+ BX_PIT_THIS s.timer[1].OUT = 1;
+ BX_PIT_THIS s.timer[1].active = 0;
+
+ BX_PIT_THIS s.timer[2].mode = 3; /* periodic rate generator */
+ BX_PIT_THIS s.timer[2].latch_mode = BX_PIT_LATCH_MODE_16BIT;
+ BX_PIT_THIS s.timer[2].input_latch_value = 0;
+ BX_PIT_THIS s.timer[2].input_latch_toggle = 0;
+ BX_PIT_THIS s.timer[2].output_latch_value = 0;
+ BX_PIT_THIS s.timer[2].output_latch_toggle = 0;
+ BX_PIT_THIS s.timer[2].output_latch_full = 0;
+ BX_PIT_THIS s.timer[2].counter_max = 0; /* 0xFFFF + 1 : (1193182 / 65535 = 18.2Hz) */
+ BX_PIT_THIS s.timer[2].counter = 0; /* 0xFFFF + 1 : (1193182 / 65535 = 18.2Hz) */
+ BX_PIT_THIS s.timer[2].bcd_mode = 0; /* binary counting mode */
+ BX_PIT_THIS s.timer[2].GATE = 0; /* timer2 gate controlled by port 61h bit 0 */
+ BX_PIT_THIS s.timer[2].OUT = 1;
+ BX_PIT_THIS s.timer[2].active = 0;
+#if BX_SUPPORT_SID==0
+ return(1);
+#endif
+}
+
+
+
+
+
+
+ // static IO port read callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ Bit32u
+bx_pit_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_PIT_SMF
+ bx_pit_c *class_ptr = (bx_pit_c *) this_ptr;
+
+ return( class_ptr->read(address, io_len) );
+}
+
+
+ Bit32u
+bx_pit_c::read( Bit32u address, unsigned int io_len )
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_PIT_SMF
+ if (io_len > 1)
+ BX_PANIC(("pit: io read from port %04x, len=%u\n", (unsigned) address,
+ (unsigned) io_len));
+
+ if (bx_dbg.pit)
+ BX_INFO(("pit: io read from port %04x\n", (unsigned) address));
+
+ switch (address) {
+ case 0x40: /* timer 0 - system ticks */
+ return( read_counter(0) );
+ break;
+
+ case 0x42: /* timer 2 read */
+ return( read_counter(2) );
+ break;
+
+ case 0x61:
+ /* AT, port 61h */
+ BX_PIT_THIS s.refresh_clock_div2 = !BX_PIT_THIS s.refresh_clock_div2;
+ return( (BX_PIT_THIS s.timer[2].OUT<<5) |
+ (BX_PIT_THIS s.refresh_clock_div2<<4) |
+ (BX_PIT_THIS s.speaker_data_on<<1) |
+ (BX_PIT_THIS s.timer[2].GATE) );
+ break;
+
+ default:
+ BX_PANIC(("pit: unsupported io read from port %04x\n", address));
+ }
+ return(0); /* keep compiler happy */
+}
+
+
+ // static IO port write callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ void
+bx_pit_c::write_handler(void *this_ptr, Bit32u address, Bit32u dvalue, unsigned io_len)
+{
+#if !BX_USE_PIT_SMF
+ bx_pit_c *class_ptr = (bx_pit_c *) this_ptr;
+
+ class_ptr->write(address, dvalue, io_len);
+}
+
+ void
+bx_pit_c::write( Bit32u address, Bit32u dvalue,
+ unsigned int io_len )
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_PIT_SMF
+ Bit8u command, mode, bcd_mode;
+ Bit8u value;
+
+ value = (Bit8u ) dvalue;
+
+ if (io_len > 1)
+ BX_PANIC(("pit: io write to port %04x, len=%u\n", (unsigned) address,
+ (unsigned) io_len));
+
+ if (bx_dbg.pit)
+ BX_INFO(("pit: write to port %04x = %02x\n",
+ (unsigned) address, (unsigned) value));
+
+ switch (address) {
+ case 0x40: /* timer 0: write count register */
+ write_count_reg( value, 0 );
+ break;
+
+ case 0x41: /* timer 1: write count register */
+ write_count_reg( value, 1 );
+ break;
+
+ case 0x42: /* timer 2: write count register */
+ write_count_reg( value, 2 );
+ break;
+
+ case 0x43: /* timer 0-2 mode control */
+ /* |7 6 5 4|3 2 1|0|
+ * |-------|-----|-|
+ * |command|mode |bcd/binary|
+ */
+ command = value >> 4;
+ mode = (value >> 1) & 0x07;
+ bcd_mode = value & 0x01;
+#if 0
+BX_INFO(("timer 0-2 mode control: comm:%02x mode:%02x bcd_mode:%u\n",
+ (unsigned) command, (unsigned) mode, (unsigned) bcd_mode));
+#endif
+
+ if ( (mode > 5) || (command > 0x0e) )
+ BX_PANIC(("pit: outp(43h)=%02xh out of range\n", (unsigned) value));
+ if (bcd_mode)
+ BX_PANIC(("pit: outp(43h)=%02xh: bcd mode unhandled\n",
+ (unsigned) bcd_mode));
+
+ switch (command) {
+ case 0x0: /* timer 0: counter latch */
+ latch( 0 );
+ break;
+
+ case 0x1: /* timer 0: LSB mode */
+ case 0x2: /* timer 0: MSB mode */
+ BX_PANIC(("pit: outp(43h): command %02xh unhandled\n",
+ (unsigned) command));
+ break;
+ case 0x3: /* timer 0: 16-bit mode */
+ BX_PIT_THIS s.timer[0].mode = mode;
+ BX_PIT_THIS s.timer[0].latch_mode = BX_PIT_LATCH_MODE_16BIT;
+ BX_PIT_THIS s.timer[0].input_latch_value = 0;
+ BX_PIT_THIS s.timer[0].input_latch_toggle = 0;
+ BX_PIT_THIS s.timer[0].bcd_mode = bcd_mode;
+ if ( (mode!=3 && mode!=2 && mode!=0) || bcd_mode!=0 )
+ BX_PANIC(("pit: outp(43h): comm 3, mode %02x, bcd %02x unhandled\n",
+ (unsigned) mode, bcd_mode));
+ break;
+ case 0x4: /* timer 1: counter latch */
+ latch( 1 );
+ break;
+
+ case 0x5: /* timer 1: LSB mode */
+ case 0x6: /* timer 1: MSB mode */
+ BX_INFO(("pit: outp(43h): command %02xh unhandled (ignored)\n",
+ (unsigned) command));
+ break;
+ case 0x7: /* timer 1: 16-bit mode */
+ BX_PIT_THIS s.timer[1].mode = mode;
+ BX_PIT_THIS s.timer[1].latch_mode = BX_PIT_LATCH_MODE_16BIT;
+ BX_PIT_THIS s.timer[1].input_latch_value = 0;
+ BX_PIT_THIS s.timer[1].input_latch_toggle = 0;
+ BX_PIT_THIS s.timer[1].bcd_mode = bcd_mode;
+ if ( (mode!=3 && mode!=2 && mode!=0) || bcd_mode!=0 )
+ BX_PANIC(("pit: outp(43h): comm 7, mode %02x, bcd %02x unhandled\n",
+ (unsigned) mode, bcd_mode));
+ break;
+ case 0x8: /* timer 2: counter latch */
+ latch( 2 );
+ break;
+
+ case 0x9: /* timer 2: LSB mode */
+ case 0xa: /* timer 2: MSB mode */
+ BX_PANIC(("pit: outp(43h): command %02xh unhandled\n",
+ (unsigned) command));
+ break;
+ case 0xb: /* timer 2: 16-bit mode */
+ BX_PIT_THIS s.timer[2].mode = mode;
+ BX_PIT_THIS s.timer[2].latch_mode = BX_PIT_LATCH_MODE_16BIT;
+ BX_PIT_THIS s.timer[2].input_latch_value = 0;
+ BX_PIT_THIS s.timer[2].input_latch_toggle = 0;
+ BX_PIT_THIS s.timer[2].bcd_mode = bcd_mode;
+ if ( (mode!=3 && mode!=2 && mode!=0) || bcd_mode!=0 )
+ BX_PANIC(("pit: outp(43h): comm Bh, mode %02x, bcd %02x unhandled\n",
+ (unsigned) mode, bcd_mode));
+ break;
+#if 0
+ case 0xd: /* general counter latch */
+ if (value & 0x08) /* select counter 2 */
+ latch( 2 );
+ if (value & 0x04) /* select counter 1 */
+ latch( 1 );
+ if (value & 0x02) /* select counter 0 */
+ latch( 0 );
+ break;
+
+ case 0xe: /* latch status of timers */
+ BX_PANIC(("pit: outp(43h): command %02xh unhandled\n",
+ (unsigned) command);
+ break;
+#endif
+ case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ BX_INFO(("pit: ignoring 8254 command %u\n", (unsigned) command));
+ break;
+
+ default: /* 0xc & 0xf */
+ BX_PANIC(("pit: outp(43h) command %1xh unhandled\n",
+ (unsigned) command));
+ break;
+ }
+ break;
+
+ case 0x61:
+ BX_PIT_THIS s.speaker_data_on = (value >> 1) & 0x01;
+/*??? only on AT+ */
+ set_GATE(2, value & 0x01);
+#if BX_CPU_LEVEL < 2
+ /* ??? XT: */
+ bx_kbd_port61h_write(value);
+#endif
+ break;
+
+ default:
+ BX_PANIC(("pit: unsupported io write to port %04x = %02x\n",
+ (unsigned) address, (unsigned) value));
+ }
+}
+
+
+
+
+ void
+bx_pit_c::write_count_reg( Bit8u value, unsigned timerid )
+{
+ Boolean xfer_complete;
+
+ switch ( BX_PIT_THIS s.timer[timerid].latch_mode ) {
+ case BX_PIT_LATCH_MODE_16BIT: /* write1=LSB, write2=MSB */
+ if (BX_PIT_THIS s.timer[timerid].input_latch_toggle==0) {
+ BX_PIT_THIS s.timer[timerid].input_latch_value = value;
+ BX_PIT_THIS s.timer[timerid].input_latch_toggle = 1;
+ xfer_complete = 0;
+ if (bx_dbg.pit)
+ BX_INFO(("pit: BX_PIT_THIS s.timer[timerid] write L = %02x\n", (unsigned) value));
+ }
+ else {
+ BX_PIT_THIS s.timer[timerid].input_latch_value |= (value << 8);
+ BX_PIT_THIS s.timer[timerid].input_latch_toggle = 0;
+ xfer_complete = 1;
+ if (bx_dbg.pit)
+ BX_INFO(("pit: BX_PIT_THIS s.timer[timerid] write H = %02x\n", (unsigned) value));
+ }
+ break;
+
+ case BX_PIT_LATCH_MODE_MSB: /* write1=MSB, LSB=0 */
+ BX_PIT_THIS s.timer[timerid].input_latch_value = (value << 8);
+ xfer_complete = 1;
+ if (bx_dbg.pit)
+ BX_INFO(("pit: BX_PIT_THIS s.timer[timerid] write H = %02x\n", (unsigned) value));
+ break;
+
+ case BX_PIT_LATCH_MODE_LSB: /* write1=LSB, MSB=0 */
+ BX_PIT_THIS s.timer[timerid].input_latch_value = value;
+ xfer_complete = 1;
+ if (bx_dbg.pit)
+ BX_INFO(("pit: BX_PIT_THIS s.timer[timerid] write L = %02x\n", (unsigned) value));
+ break;
+
+ default:
+ BX_PANIC(("write_count_reg: latch_mode unknown\n"));
+ xfer_complete = 0;
+ }
+
+ if (xfer_complete) {
+ BX_PIT_THIS s.timer[timerid].counter_max = BX_PIT_THIS s.timer[timerid].input_latch_value;
+
+ // reprogramming counter clears latch
+ BX_PIT_THIS s.timer[timerid].output_latch_full = 0;
+
+ // counter bounds
+ // mode minimum maximum
+ // 0 1 0
+ // 1 1 0
+ // 2 2 0
+ // 3 2 0
+ // 4 1 0
+ // 5 1 0
+ switch (BX_PIT_THIS s.timer[timerid].mode) {
+ case 0:
+ BX_PIT_THIS s.timer[timerid].counter = BX_PIT_THIS s.timer[timerid].counter_max;
+ BX_PIT_THIS s.timer[timerid].active = 1;
+ if (BX_PIT_THIS s.timer[timerid].GATE) {
+ BX_PIT_THIS s.timer[timerid].OUT = 0; // OUT pin starts low
+ start( timerid );
+ }
+ break;
+ case 1:
+ BX_PANIC(("pit:write_count_reg(%u): mode1 unsupported\n",
+ timerid));
+ break;
+ case 2:
+ if ( BX_PIT_THIS s.timer[timerid].counter_max == 1 )
+ BX_PANIC(("pit:write_count_reg(%u): mode %u counter_max=1\n",
+ timerid, (unsigned) BX_PIT_THIS s.timer[timerid].mode));
+ if ( BX_PIT_THIS s.timer[timerid].GATE && !BX_PIT_THIS s.timer[timerid].active ) {
+ // software triggered
+ BX_PIT_THIS s.timer[timerid].counter = BX_PIT_THIS s.timer[timerid].counter_max;
+ BX_PIT_THIS s.timer[timerid].active = 1;
+ BX_PIT_THIS s.timer[timerid].OUT = 1; // initially set high
+ start( timerid );
+ }
+ break;
+ case 3:
+ if ( BX_PIT_THIS s.timer[timerid].counter_max == 1 )
+ BX_PANIC(("pit:write_count_reg(%u): mode %u counter_max=1\n",
+ timerid, (unsigned) BX_PIT_THIS s.timer[timerid].mode));
+ BX_PIT_THIS s.timer[timerid].counter_max = BX_PIT_THIS s.timer[timerid].counter_max & 0xfffe;
+ if ( BX_PIT_THIS s.timer[timerid].GATE && !BX_PIT_THIS s.timer[timerid].active ) {
+ // software triggered
+ BX_PIT_THIS s.timer[timerid].counter = BX_PIT_THIS s.timer[timerid].counter_max;
+ BX_PIT_THIS s.timer[timerid].active = 1;
+ BX_PIT_THIS s.timer[timerid].OUT = 1; // initially set high
+ start( timerid );
+ }
+ break;
+ case 4:
+ BX_PANIC(("pit:write_count_reg(%u): mode4 unsupported\n",
+ timerid));
+ break;
+ case 5:
+ BX_PANIC(("pit:write_count_reg(%u): mode5 unsupported\n",
+ timerid));
+ break;
+ }
+ }
+}
+
+
+ Bit8u
+bx_pit_c::read_counter( unsigned timerid )
+{
+ Bit16u counter_value;
+ Bit8u retval;
+
+ if (BX_PIT_THIS s.timer[timerid].output_latch_full) { /* latched read */
+ counter_value = BX_PIT_THIS s.timer[timerid].output_latch_value;
+ }
+ else { /* direct unlatched read */
+ counter_value = BX_PIT_THIS s.timer[timerid].counter;
+BX_INFO(("CV=%04x\n", (unsigned) BX_PIT_THIS s.timer[timerid].counter));
+ }
+
+ switch (BX_PIT_THIS s.timer[timerid].latch_mode) {
+ case BX_PIT_LATCH_MODE_LSB:
+ retval = (Bit8u ) counter_value;
+ BX_PIT_THIS s.timer[timerid].output_latch_full = 0;
+ break;
+ case BX_PIT_LATCH_MODE_MSB:
+ retval = (Bit8u ) ( counter_value >> 8 );
+ BX_PIT_THIS s.timer[timerid].output_latch_full = 0;
+ break;
+ case BX_PIT_LATCH_MODE_16BIT:
+ if (BX_PIT_THIS s.timer[timerid].output_latch_toggle==0) { /* LSB 1st */
+ retval = (Bit8u ) counter_value;
+ }
+ else { /* MSB 2nd */
+ retval = (Bit8u ) ( counter_value >> 8 );
+ }
+ BX_PIT_THIS s.timer[timerid].output_latch_toggle = !BX_PIT_THIS s.timer[timerid].output_latch_toggle;
+ if (BX_PIT_THIS s.timer[timerid].output_latch_toggle == 0)
+ BX_PIT_THIS s.timer[timerid].output_latch_full = 0;
+ break;
+ default:
+ BX_PANIC(("pit: io read from port 40h: unknown latch mode\n"));
+ retval = 0; /* keep compiler happy */
+ }
+ return( retval );
+}
+
+
+ void
+bx_pit_c::latch( unsigned timerid )
+{
+ /* subsequent counter latch commands are ignored until value read out */
+ if (BX_PIT_THIS s.timer[timerid].output_latch_full) {
+ BX_INFO(("pit: pit(%u) latch: output latch full, ignoring\n",
+ timerid));
+ return;
+ }
+
+ BX_PIT_THIS s.timer[timerid].output_latch_value = BX_PIT_THIS s.timer[timerid].counter;
+
+ if (bx_dbg.pit)
+ BX_INFO(("pit: latch_value = %lu\n", BX_PIT_THIS s.timer[timerid].output_latch_value));
+ BX_PIT_THIS s.timer[timerid].output_latch_toggle = 0;
+ BX_PIT_THIS s.timer[timerid].output_latch_full = 1;
+}
+
+ void
+bx_pit_c::set_GATE(unsigned pit_id, unsigned value)
+{
+ // GATE's for Timer 0 & Timer 1 are tied high.
+ if (pit_id != 2)
+ BX_PANIC(("pit:set_GATE: pit_id != 2\n"));
+
+ value = (value > 0);
+
+ /* if no transition of GATE input line, then nothing to do */
+ if (value == BX_PIT_THIS s.timer[2].GATE)
+ return;
+
+ if (value) { /* PIT2: GATE transition from 0 to 1 */
+ BX_PIT_THIS s.timer[2].GATE = 1;
+ switch ( BX_PIT_THIS s.timer[2].mode ) {
+ case 0:
+ BX_PIT_THIS s.timer[2].counter = BX_PIT_THIS s.timer[2].counter_max;
+ if (BX_PIT_THIS s.timer[2].active) {
+ BX_PIT_THIS s.timer[2].OUT = 0;
+ }
+ start( 2 );
+ break;
+ case 2:
+ // begin counting, reload counter
+ BX_PIT_THIS s.timer[2].active = 1;
+ BX_PIT_THIS s.timer[2].OUT = 1;
+ BX_PIT_THIS s.timer[2].counter = BX_PIT_THIS s.timer[2].counter_max;
+ start( 2 );
+ break;
+ case 3:
+ // begin counting, reload counter
+ BX_PIT_THIS s.timer[2].active = 1;
+ BX_PIT_THIS s.timer[2].OUT = 1;
+ BX_PIT_THIS s.timer[2].counter = BX_PIT_THIS s.timer[2].counter_max;
+ start( 2 );
+ break;
+ case 1:
+ case 4:
+ case 5:
+ default:
+ BX_PANIC(("bx_pit_c::set_GATE: unhandled timer2 mode %u\n",
+ (unsigned) BX_PIT_THIS s.timer[2].mode));
+ }
+ }
+ else { // PIT2: GATE transition from 1 to 0, deactivate
+ BX_PIT_THIS s.timer[2].GATE = 0;
+ switch ( BX_PIT_THIS s.timer[2].mode ) {
+ case 0:
+ break;
+ case 2:
+ // 1) stops count, 2) OUT goes immediately high
+ BX_PIT_THIS s.timer[2].active = 0;
+ BX_PIT_THIS s.timer[2].OUT = 1;
+ break;
+ case 3:
+ // 1) stops count, 2) OUT goes immediately high
+ BX_PIT_THIS s.timer[2].active = 0;
+ BX_PIT_THIS s.timer[2].OUT = 1;
+ break;
+ case 1:
+ case 4:
+ case 5:
+ default:
+ BX_PANIC(("bx_pit_c::set_GATE: unhandled timer2 mode %u\n",
+ (unsigned) BX_PIT_THIS s.timer[2].mode));
+ }
+ }
+}
+
+
+ void
+bx_pit_c::start(unsigned timerid)
+{
+ unsigned long period_hz;
+
+ if (BX_PIT_THIS s.timer[timerid].counter_max == 0x0000) {
+ period_hz = 1193182 / 65536;
+ }
+ else {
+ period_hz = 1193182 / BX_PIT_THIS s.timer[timerid].counter_max;
+ }
+ BX_INFO(("timer%u period set to %lu hz\n", timerid, period_hz));
+
+
+ switch (BX_PIT_THIS s.timer[timerid].mode) {
+ case 0: /* single timeout */
+ break;
+ case 1: /* retriggerable one-shot */
+ BX_PANIC(("start: mode %u unhandled\n",
+ (unsigned) BX_PIT_THIS s.timer[timerid].mode));
+ break;
+ case 2: /* rate generator */
+ break;
+ case 3: /* square wave mode */
+ break;
+ case 4: /* software triggered strobe */
+ BX_PANIC(("start: mode %u unhandled\n",
+ (unsigned) BX_PIT_THIS s.timer[timerid].mode));
+ break;
+ case 5: /* hardware retriggerable strobe */
+ BX_PANIC(("start: mode %u unhandled\n",
+ (unsigned) BX_PIT_THIS s.timer[timerid].mode));
+ break;
+ default:
+ BX_PANIC(("start: timer%u has bad mode\n",
+ (unsigned) BX_PIT_THIS s.timer[timerid].mode));
+ }
+}
+
+
+#if BX_SUPPORT_SID==0
+
+ int
+bx_pit_c::SaveState( class state_file *fd )
+{
+ fd->write_check ("8254 start");
+ fd->write (&BX_PIT_THIS s, sizeof (BX_PIT_THIS s));
+ fd->write_check ("8254 end");
+ return(0);
+}
+
+
+ int
+bx_pit_c::LoadState( class state_file *fd )
+{
+ fd->read_check ("8254 start");
+ fd->read (&BX_PIT_THIS s, sizeof (BX_PIT_THIS s));
+ fd->read_check ("8254 end");
+ return(0);
+}
+
+#endif
+#if 0
+ void
+bx_kbd_port61h_write(Bit8u value)
+{
+// PcError("KBD_PORT61H_WRITE(): not implemented yet");
+ UNUSED( value );
+}
+#endif
+
+
+ Boolean
+bx_pit_c::periodic( Bit32u usec_delta )
+{
+ Boolean prev_timer0_out;
+
+ prev_timer0_out = BX_PIT_THIS s.timer[0].OUT;
+
+ for (unsigned i = 0; i < 3; i++) {
+ // is timer enabled and active?
+ if ( BX_PIT_THIS s.timer[i].GATE && BX_PIT_THIS s.timer[i].active ) {
+ switch ( BX_PIT_THIS s.timer[i].mode ) {
+ case 0: // Mode 0: Single Timeout
+ // wraps after count expires
+ if ( BX_PIT_THIS s.timer[i].counter == 0 ) {
+ // counter previously expired, wrap counter
+ BX_PIT_THIS s.timer[i].counter = 0xffff;
+ }
+ else if ( usec_delta >= BX_PIT_THIS s.timer[i].counter ) {
+ // counter expired
+ BX_PIT_THIS s.timer[i].counter = 0;
+ BX_PIT_THIS s.timer[i].OUT = 1;
+ }
+ else {
+ // decrement counter by elapsed useconds
+ BX_PIT_THIS s.timer[i].counter -= (Bit16u ) usec_delta;
+ }
+ break;
+
+ case 1: // Mode 1: Retriggerable One-Shot
+ // wraps after count expires
+ BX_PANIC(("bx_pit_c::periodic: bad mode: timer[%u], mode %u\n",
+ i, (unsigned) BX_PIT_THIS s.timer[i].mode));
+ break;
+
+ case 2: // Mode 2: Rate Generator
+ // reloads after count expires
+ // OUT is low when counter=1, high otherwise
+ // min count=2, max count=0
+ if ( BX_PIT_THIS s.timer[i].counter == 0 ) {
+ // max counter val, just wrap
+ BX_PIT_THIS s.timer[i].counter = 0xffff;
+ BX_PIT_THIS s.timer[i].OUT = 1;
+ }
+ else if ( BX_PIT_THIS s.timer[i].counter == 1 ) {
+ // counter previously expired, reload
+ BX_PIT_THIS s.timer[i].counter = BX_PIT_THIS s.timer[i].counter_max;
+ BX_PIT_THIS s.timer[i].OUT = 1;
+ }
+ else if ( (BX_PIT_THIS s.timer[i].counter == 2) ||
+ (usec_delta >= (Bit32u(BX_PIT_THIS s.timer[i].counter) - 1)) ) {
+ // in either case, counter will reach 1
+ BX_PIT_THIS s.timer[i].counter = 1;
+ BX_PIT_THIS s.timer[i].OUT = 0;
+ }
+ else {
+ // decrement counter by elapsed useconds
+ BX_PIT_THIS s.timer[i].counter -= (Bit16u ) usec_delta;
+ }
+ break;
+
+ case 3: // Mode 3: Square Wave Mode
+ // reloads after count expires
+ // min count=2, max count=0
+ if ( BX_PIT_THIS s.timer[i].counter == 0 ) {
+ // max count, dec by 2
+ BX_PIT_THIS s.timer[i].counter = 0xfffe;
+ }
+ else if ( (BX_PIT_THIS s.timer[i].counter <= 2) ||
+ ( (usec_delta*2) >= BX_PIT_THIS s.timer[i].counter ) ) {
+ // counter expired, reload
+ BX_PIT_THIS s.timer[i].counter = BX_PIT_THIS s.timer[i].counter_max;
+ BX_PIT_THIS s.timer[i].OUT = !BX_PIT_THIS s.timer[i].OUT;
+ //BX_INFO(("CV: reload t%u to %04x\n", (unsigned) i, (unsigned)
+ // BX_PIT_THIS s.timer[i].counter));
+ }
+ else {
+ // decrement counter by elapsed useconds
+ BX_PIT_THIS s.timer[i].counter -= (Bit16u ) ( 2*usec_delta );
+ //BX_INFO(("CV: dec count to %04x\n",
+ // (unsigned) BX_PIT_THIS s.timer[i].counter));
+ }
+ break;
+
+ case 4: // Mode 4: Software Triggered Strobe
+ // wraps after count expires
+ BX_PANIC(("bx_pit_c::periodic: bad mode: timer[%u], mode %u\n",
+ i, (unsigned) BX_PIT_THIS s.timer[i].mode));
+ break;
+
+ case 5: // Mode 5: Hardware Retriggerable Strobe
+ // wraps after count expires
+ BX_PANIC(("bx_pit_c::periodic: bad mode: timer[%u], mode %u\n",
+ i, (unsigned) BX_PIT_THIS s.timer[i].mode));
+ break;
+ default:
+ BX_PANIC(("bx_pit_c::periodic: bad mode: timer[%u], mode %u\n",
+ i, (unsigned) BX_PIT_THIS s.timer[i].mode));
+ break;
+ } // switch ( BX_PIT_THIS s.tim...
+ } // if ( BX_PIT_THIS s.timer[i]...
+ } // for (unsigned i...
+
+ // see if there's a rising edge on timer0's output to trigger an IRQ0.
+ if ( (prev_timer0_out==0) && (BX_PIT_THIS s.timer[0].OUT==1) )
+ return(1); // request IRQ 0
+ else
+ return(0);
+}
--- /dev/null
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#ifndef _BX_PIT_H
+#define _BX_PIT_H
+
+
+#if BX_USE_PIT_SMF
+# define BX_PIT_SMF static
+# define BX_PIT_THIS bx_pit.
+#else
+# define BX_PIT_SMF
+# define BX_PIT_THIS this->
+#endif
+
+#ifdef OUT
+# undef OUT
+#endif
+
+
+typedef struct {
+ Bit8u mode;
+ Bit8u latch_mode;
+ Bit16u input_latch_value;
+ Boolean input_latch_toggle;
+ Bit16u output_latch_value;
+ Boolean output_latch_toggle;
+ Boolean output_latch_full;
+ Bit16u counter_max;
+ Bit16u counter;
+ Boolean bcd_mode;
+ Boolean active;
+ Boolean GATE; // GATE input pin
+ Boolean OUT; // OUT output pin
+ } bx_pit_t;
+
+
+
+
+class bx_pit_c : public logfunctions {
+public:
+ bx_pit_c( void );
+ ~bx_pit_c( void );
+#if BX_SUPPORT_SID
+ BX_PIT_SMF void init(void);
+#else
+ BX_PIT_SMF int init( bx_devices_c *);
+#endif
+ BX_PIT_SMF Boolean periodic( Bit32u usec_delta );
+#if BX_SUPPORT_SID==0
+ BX_PIT_SMF int SaveState( class state_file *fd );
+ BX_PIT_SMF int LoadState( class state_file *fd );
+#endif
+private:
+
+ static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+ static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+#if BX_SUPPORT_SID
+ public:
+#endif
+#if !BX_USE_PIT_SMF
+ Bit32u read( Bit32u addr, unsigned int len );
+ void write( Bit32u addr, Bit32u Value, unsigned int len );
+#endif
+#if BX_SUPPORT_SID
+ private:
+#endif
+ struct {
+ bx_pit_t timer[3];
+ Bit8u speaker_data_on;
+ Boolean refresh_clock_div2;
+ int timer_handle[3];
+ } s;
+#if BX_SUPPORT_SID==0
+ bx_devices_c *devices;
+#endif
+ BX_PIT_SMF void write_count_reg( Bit8u value, unsigned timerid );
+ BX_PIT_SMF Bit8u read_counter( unsigned timerid );
+ BX_PIT_SMF void latch( unsigned timerid );
+ BX_PIT_SMF void set_GATE(unsigned pit_id, unsigned value);
+ BX_PIT_SMF void start(unsigned timerid);
+ };
+#if BX_SUPPORT_SID==0
+extern bx_pit_c bx_pit;
+#endif
+#endif // #ifndef _BX_PIT_H
--- /dev/null
+// sid-pit-wrapper.cc - SID import of the bochs pit component. -*- C++ -*-
+
+// Copyright (C) 1999, 2000, 2001, 2002 Red Hat.
+// This file is part of SID and is licensed under the GPL.
+// See the file COPYING.SID for conditions for redistribution.
+
+#include "sid-pit-wrapper.h"
+
+pit::pit ()
+ : init_pin(this, & pit::init),
+ update_pit_pin(this, & pit::update_pit),
+ ports_0x40_0x43_bus(this, & pit::read_port_0x40_0x43, & pit::write_port_0x40_0x43),
+ port_0x61_bus(this, & pit::read_port_0x61, & pit::write_port_0x61),
+ timer_delta(100), pit_irq_number(0)
+{
+ add_pin("trigger-irq", & this->trigger_irq_pin);
+
+ add_pin("init", & this->init_pin);
+ add_pin("update-pit", & this->update_pit_pin);
+
+ add_bus("ports-0x40-0x43", & this->ports_0x40_0x43_bus);
+ add_bus("port-0x61", & this->port_0x61_bus);
+
+ add_attribute("irq-number", & this->pit_irq_number, "setting");
+ add_attribute("timer-delta", & this->timer_delta, "setting");
+}
+
+void
+pit::init(host_int_4)
+{
+ bx_pit.init();
+}
+
+void
+pit::update_pit(host_int_4)
+{
+ if(bx_pit.periodic(timer_delta))
+ trigger_irq_pin.drive(pit_irq_number);
+}
+
+bus::status
+pit::read_port_0x40_0x43 (host_int_4 addr, little_int_1 mask, little_int_1 & data)
+{
+ addr += 0x40;
+ data = bx_pit.read(addr, 1);
+ return bus::ok;
+}
+
+bus::status
+pit::write_port_0x40_0x43 (host_int_4 addr, little_int_1 mask, little_int_1 data)
+{
+ addr += 0x40;
+ bx_pit.write(addr, data, 1);
+ return bus::ok;
+}
+
+bus::status
+pit::read_port_0x61 (host_int_4 addr, little_int_1 mask, little_int_1 & data)
+{
+ addr += 0x61;
+ data = bx_pit.read(addr, 1);
+ return bus::ok;
+}
+
+bus::status
+pit::write_port_0x61 (host_int_4 addr, little_int_1 mask, little_int_1 data)
+{
+ addr += 0x61;
+ bx_pit.write(addr, data, 1);
+ return bus::ok;
+}
--- /dev/null
+// sid-pit-wrapper.h - SID import of the bochs pit component. -*- C++ -*-
+
+// Copyright (C) 1999, 2000, 2001, 2002 Red Hat.
+// This file is part of SID and is licensed under the GPL.
+// See the file COPYING.SID for conditions for redistribution.
+
+#ifndef SID_PIT_WRAPPER_DEF_H
+#define SID_PIT_WRAPPER_DEF_H 1
+
+#include <sidtypes.h>
+#include <sidcomp.h>
+#include <sidcomputil.h>
+#include <sidpinutil.h>
+#include <sidbusutil.h>
+#include <sidattrutil.h>
+#include <sidcpuutil.h>
+#include <sidpinattrutil.h>
+#include <sidmiscutil.h>
+#include <sidwatchutil.h>
+#include <sidso.h>
+
+#include "bochs.h"
+
+using sid::component;
+using sid::bus;
+using sid::host_int_4;
+using sid::little_int_1;
+using sidutil::callback_word_bus;
+using sidutil::callback_pin;
+using sidutil::output_pin;
+
+class pit : public sidutil::fixed_pin_map_component,
+ public sidutil::no_accessor_component,
+ public sidutil::fixed_attribute_map_component,
+ public sidutil::no_relation_component,
+ public sidutil::fixed_bus_map_component
+{
+public:
+ pit();
+ ~pit() throw() {};
+
+ void init(host_int_4);
+ void update_pit(host_int_4);
+
+protected:
+
+ output_pin trigger_irq_pin;
+
+ callback_pin<pit> init_pin;
+ callback_pin<pit> update_pit_pin;
+
+ bus::status read_port_0x40_0x43 (host_int_4 addr, little_int_1 mask, little_int_1 & data);
+ bus::status write_port_0x40_0x43 (host_int_4 addr, little_int_1 mask, little_int_1 data);
+
+ bus::status read_port_0x61 (host_int_4 addr, little_int_1 mask, little_int_1 & data);
+ bus::status write_port_0x61 (host_int_4 addr, little_int_1 mask, little_int_1 data);
+
+ callback_word_bus<pit, little_int_1> ports_0x40_0x43_bus;
+ callback_word_bus<pit, little_int_1> port_0x61_bus;
+
+ host_int_4 timer_delta;
+ host_int_4 pit_irq_number;
+ bx_pit_c bx_pit;
+};
+#endif // SID_PIT_WRAPPER_DEF_H
--- /dev/null
+## Process this with automake to create Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(top_builddir)/../../include -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../../../include -I$(srcdir)/../cpu
+
+noinst_LTLIBRARIES = libunmapped.la
+
+libunmapped_la_SOURCES = sid-unmapped-wrapper.cc sid-unmapped-wrapper.h unmapped.cc unmapped.h
+
+libunmapped_la_LDFLAGS = -no-undefined
--- /dev/null
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+APIC_OBJS = @APIC_OBJS@
+AR = @AR@
+AS = @AS@
+AS_DYNAMIC_INCS = @AS_DYNAMIC_INCS@
+AS_DYNAMIC_OBJS = @AS_DYNAMIC_OBJS@
+BX_LOADER_OBJS = @BX_LOADER_OBJS@
+BX_SPLIT_HD_SUPPORT = @BX_SPLIT_HD_SUPPORT@
+CC = @CC@
+CDROM_OBJS = @CDROM_OBJS@
+CD_UP_ONE = @CD_UP_ONE@
+CD_UP_TWO = @CD_UP_TWO@
+CFP = @CFP@
+COMMAND_SEPARATOR = @COMMAND_SEPARATOR@
+CPP_SUFFIX = @CPP_SUFFIX@
+CXX = @CXX@
+CXXFP = @CXXFP@
+DASH = @DASH@
+DEBUGGER_VAR = @DEBUGGER_VAR@
+DISASM_VAR = @DISASM_VAR@
+DLLTOOL = @DLLTOOL@
+DYNAMIC_VAR = @DYNAMIC_VAR@
+EXE = @EXE@
+EXEEXT = @EXEEXT@
+EXTERNAL_DEPENDENCY = @EXTERNAL_DEPENDENCY@
+FPU_GLUE_OBJ = @FPU_GLUE_OBJ@
+FPU_VAR = @FPU_VAR@
+GUI_LINK_OPTS = @GUI_LINK_OPTS@
+GUI_LINK_OPTS_TERM = @GUI_LINK_OPTS_TERM@
+GUI_OBJS = @GUI_OBJS@
+GZIP = @GZIP@
+INLINE_VAR = @INLINE_VAR@
+INSTRUMENT_DIR = @INSTRUMENT_DIR@
+INSTRUMENT_VAR = @INSTRUMENT_VAR@
+IOAPIC_OBJS = @IOAPIC_OBJS@
+IODEV_LIB_VAR = @IODEV_LIB_VAR@
+LD = @LD@
+LIBTOOL = @LIBTOOL@
+LINK = @LINK@
+LN_S = @LN_S@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MAKELIB = @MAKELIB@
+NE2K_OBJS = @NE2K_OBJS@
+NM = @NM@
+NONINLINE_VAR = @NONINLINE_VAR@
+OBJDUMP = @OBJDUMP@
+OFP = @OFP@
+PACKAGE = @PACKAGE@
+PCI_OBJ = @PCI_OBJ@
+PRIMARY_TARGET = @PRIMARY_TARGET@
+RANLIB = @RANLIB@
+READLINE_LIB = @READLINE_LIB@
+RFB_LIBS = @RFB_LIBS@
+RMCOMMAND = @RMCOMMAND@
+SB16_OBJS = @SB16_OBJS@
+SLASH = @SLASH@
+SUFFIX_LINE = @SUFFIX_LINE@
+TAR = @TAR@
+VERSION = @VERSION@
+VIDEO_OBJS = @VIDEO_OBJS@
+sidtarget_arm = @sidtarget_arm@
+sidtarget_m32r = @sidtarget_m32r@
+sidtarget_m68k = @sidtarget_m68k@
+sidtarget_mips = @sidtarget_mips@
+sidtarget_ppc = @sidtarget_ppc@
+sidtarget_x86 = @sidtarget_x86@
+sidtarget_xstormy16 = @sidtarget_xstormy16@
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(top_builddir)/../../include -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../../../include -I$(srcdir)/../cpu
+
+noinst_LTLIBRARIES = libunmapped.la
+
+libunmapped_la_SOURCES = sid-unmapped-wrapper.cc sid-unmapped-wrapper.h unmapped.cc unmapped.h
+
+libunmapped_la_LDFLAGS = -no-undefined
+mkinstalldirs = $(SHELL) $(top_srcdir)/../../config/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_LIBS = @X_LIBS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+libunmapped_la_LIBADD =
+libunmapped_la_OBJECTS = sid-unmapped-wrapper.lo unmapped.lo
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+DIST_COMMON = Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+GZIP_ENV = --best
+DEP_FILES = .deps/sid-unmapped-wrapper.P .deps/unmapped.P
+SOURCES = $(libunmapped_la_SOURCES)
+OBJECTS = $(libunmapped_la_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .cc .lo .o .s
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --foreign unmapped/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLTLIBRARIES:
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+
+distclean-noinstLTLIBRARIES:
+
+maintainer-clean-noinstLTLIBRARIES:
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.s.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+libunmapped.la: $(libunmapped_la_OBJECTS) $(libunmapped_la_DEPENDENCIES)
+ $(CXXLINK) $(libunmapped_la_LDFLAGS) $(libunmapped_la_OBJECTS) $(libunmapped_la_LIBADD) $(LIBS)
+.cc.o:
+ $(CXXCOMPILE) -c $<
+.cc.lo:
+ $(LTCXXCOMPILE) -c $<
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = unmapped
+
+distdir: $(DISTFILES)
+ here=`cd $(top_builddir) && pwd`; \
+ top_distdir=`cd $(top_distdir) && pwd`; \
+ distdir=`cd $(distdir) && pwd`; \
+ cd $(top_srcdir) \
+ && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --foreign unmapped/Makefile
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+ -rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+ @echo '$(COMPILE) -c $<'; \
+ $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.c
+ @echo '$(LTCOMPILE) -c $<'; \
+ $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+
+%.o: %.cc
+ @echo '$(CXXCOMPILE) -c $<'; \
+ $(CXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.cc
+ @echo '$(LTCXXCOMPILE) -c $<'; \
+ $(LTCXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LTLIBRARIES)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-noinstLTLIBRARIES mostlyclean-compile \
+ mostlyclean-libtool mostlyclean-tags mostlyclean-depend \
+ mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-noinstLTLIBRARIES clean-compile clean-libtool \
+ clean-tags clean-depend clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-noinstLTLIBRARIES distclean-compile \
+ distclean-libtool distclean-tags distclean-depend \
+ distclean-generic clean-am
+ -rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-noinstLTLIBRARIES \
+ maintainer-clean-compile maintainer-clean-libtool \
+ maintainer-clean-tags maintainer-clean-depend \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLTLIBRARIES distclean-noinstLTLIBRARIES \
+clean-noinstLTLIBRARIES maintainer-clean-noinstLTLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-libtool distclean-libtool \
+clean-libtool maintainer-clean-libtool tags mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir \
+mostlyclean-depend distclean-depend clean-depend \
+maintainer-clean-depend info-am info dvi-am dvi check check-am \
+installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+// sid-unmapped-wrapper.cc - SID import of the bochs unmapped component. -*- C++ -*-
+
+// Copyright (C) 1999, 2000, 2001, 2002 Red Hat.
+// This file is part of SID and is licensed under the GPL.
+// See the file COPYING.SID for conditions for redistribution.
+
+#include "sid-unmapped-wrapper.h"
+
+unmapped::unmapped ()
+ : port_0xfff0_bus(this, & unmapped::read_port_0xfff0, & unmapped::write_port_0xfff0),
+ port_0x400_bus(this, & unmapped::read_port_0x400, & unmapped::write_port_0x400),
+ port_0x80_bus(this, & unmapped::read_port_0x80, & unmapped::write_port_0x80)
+{
+ add_bus("port-0xfff0", & this->port_0xfff0_bus);
+ add_bus("port-0x400", & this->port_0x400_bus);
+ add_bus("port-0x80", & this->port_0x80_bus);
+}
+
+bus::status
+unmapped::read_port_0xfff0 (host_int_4 addr, little_int_4 mask, little_int_4 & data)
+{
+ addr += 0xfff0;
+ data = bx_unmapped.read(addr, 1);
+ return bus::ok;
+}
+
+bus::status
+unmapped::write_port_0xfff0 (host_int_4 addr, little_int_4 mask, little_int_4 data)
+{
+ addr += 0xfff0;
+ bx_unmapped.write(addr, data, 1);
+ return bus::ok;
+}
+
+bus::status
+unmapped::read_port_0x400 (host_int_4 addr, little_int_4 mask, little_int_4 & data)
+{
+ addr += 0x400;
+ data = bx_unmapped.read(addr, 1);
+ return bus::ok;
+}
+
+bus::status
+unmapped::write_port_0x400 (host_int_4 addr, little_int_4 mask, little_int_4 data)
+{
+ addr += 0x400;
+ bx_unmapped.write(addr, data, 1);
+ return bus::ok;
+}
+
+bus::status
+unmapped::read_port_0x80 (host_int_4 addr, little_int_4 mask, little_int_4 & data)
+{
+ addr += 0x80;
+ data = bx_unmapped.read(addr, 1);
+ return bus::ok;
+}
+
+bus::status
+unmapped::write_port_0x80 (host_int_4 addr, little_int_4 mask, little_int_4 data)
+{
+ addr += 0x80;
+ bx_unmapped.write(addr, data, 1);
+ return bus::ok;
+}
--- /dev/null
+// sid-unmapped-wrapper.h - SID import of the bochs unmapped component. -*- C++ -*-
+
+// Copyright (C) 1999, 2000, 2001, 2002 Red Hat.
+// This file is part of SID and is licensed under the GPL.
+// See the file COPYING.SID for conditions for redistribution.
+
+#ifndef SID_UNMAPPED_WRAPPER_DEF_H
+#define SID_UNMAPPED_WRAPPER_DEF_H 1
+
+#include <sidtypes.h>
+#include <sidcomp.h>
+#include <sidcomputil.h>
+#include <sidpinutil.h>
+#include <sidbusutil.h>
+#include <sidattrutil.h>
+#include <sidcpuutil.h>
+#include <sidpinattrutil.h>
+#include <sidmiscutil.h>
+#include <sidwatchutil.h>
+#include <sidso.h>
+
+#include "bochs.h"
+
+using sid::component;
+using sid::bus;
+using sid::host_int_4;
+using sid::little_int_4;
+using sidutil::callback_word_bus;
+using sidutil::callback_pin;
+using sidutil::output_pin;
+
+class unmapped : public sidutil::fixed_pin_map_component,
+ public sidutil::no_accessor_component,
+ public sidutil::fixed_attribute_map_component,
+ public sidutil::no_relation_component,
+ public sidutil::fixed_bus_map_component
+{
+public:
+ unmapped();
+ ~unmapped() throw() {};
+
+protected:
+
+ bus::status read_port_0xfff0 (host_int_4 addr, little_int_4 mask, little_int_4 & data);
+ bus::status write_port_0xfff0 (host_int_4 addr, little_int_4 mask, little_int_4 data);
+
+ bus::status read_port_0x400 (host_int_4 addr, little_int_4 mask, little_int_4 & data);
+ bus::status write_port_0x400 (host_int_4 addr, little_int_4 mask, little_int_4 data);
+
+ bus::status read_port_0x80 (host_int_4 addr, little_int_4 mask, little_int_4 & data);
+ bus::status write_port_0x80 (host_int_4 addr, little_int_4 mask, little_int_4 data);
+
+ callback_word_bus<unmapped, little_int_4> port_0xfff0_bus;
+ callback_word_bus<unmapped, little_int_4> port_0x400_bus;
+ callback_word_bus<unmapped, little_int_4> port_0x80_bus;
+
+ bx_unmapped_c bx_unmapped;
+};
+#endif // SID_UNMAPPED_WRAPPER_DEF_H
--- /dev/null
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+#include "bochs.h"
+#if BX_SUPPORT_SID
+#define LOG_THIS
+#include "sid-unmapped-wrapper.h"
+#else
+#define LOG_THIS bx_unmapped.
+
+
+bx_unmapped_c bx_unmapped;
+#endif
+
+#if BX_USE_UM_SMF
+#define this (&bx_unmapped)
+#endif
+
+
+bx_unmapped_c::bx_unmapped_c(void)
+{
+ s.port80 = 0x00;
+ s.port8e = 0x00;
+
+ s.bios_message_i = 0;
+}
+
+bx_unmapped_c::~bx_unmapped_c(void)
+{
+ // nothing for now
+}
+
+#if BX_SUPPORT_SID
+void
+bx_unmapped_c::init(void)
+#else
+ void
+bx_unmapped_c::init(bx_devices_c *d)
+#endif
+{
+#if BX_SUPPORT_SID==0
+ BX_UM_THIS devices = d;
+
+ for (Bit32u addr=0; addr<0x10000; addr++) {
+ BX_UM_THIS devices->register_io_read_handler(this, read_handler,
+ addr, "Unmapped");
+ BX_UM_THIS devices->register_io_write_handler(this, write_handler,
+ addr, "Unmapped");
+ }
+#endif // BX_SUPPORT_SID==0
+}
+
+
+ // static IO port read callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ Bit32u
+bx_unmapped_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_UM_SMF
+ bx_unmapped_c *class_ptr = (bx_unmapped_c *) this_ptr;
+
+ return( class_ptr->read(address, io_len) );
+}
+
+ Bit32u
+bx_unmapped_c::read(Bit32u address, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_UM_SMF
+ UNUSED(io_len);
+
+ Bit32u retval;
+
+ // This function gets called for access to any IO ports which
+ // are not mapped to any device handler. Reads return 0
+
+ if (address >= 0x02e0 && address <= 0x02ef) {
+ retval = 0;
+ goto return_from_read;
+ }
+
+ switch (address) {
+ case 0x80:
+ retval = BX_UM_THIS s.port80;
+ break;
+ case 0x8e:
+ retval = BX_UM_THIS s.port8e;
+ break;
+#if BX_PORT_E9_HACK
+ // Unused port on ISA - this can be used by the emulated code
+ // to detect it is running inside Bochs and that the debugging
+ // features are available (write 0xFF or something on unused
+ // port 0x80, then read from 0xe9, if value is 0xe9, debug
+ // output is available) (see write() for that) -- Andreas and Emmanuel
+ case 0xe9:
+ retval = 0xe9;
+ break;
+#endif
+ case 0x03df:
+ retval = 0xffffffff;
+ BX_DEBUG(("unsupported IO read from port %04x (CGA)\n", address));
+ break;
+ case 0x023a:
+ case 0x02f8: /* UART */
+ case 0x02f9: /* UART */
+ case 0x02fb: /* UART */
+ case 0x02fc: /* UART */
+ case 0x02fd: /* UART */
+ case 0x02ea:
+ case 0x02eb:
+ case 0x03e8:
+ case 0x03e9:
+ case 0x03ea:
+ case 0x03eb:
+ case 0x03ec:
+ case 0x03ed:
+ case 0x03f8: /* UART */
+ case 0x03f9: /* UART */
+ case 0x03fb: /* UART */
+ case 0x03fc: /* UART */
+ case 0x03fd: /* UART */
+ case 0x17c6:
+ retval = 0xffffffff;
+ BX_DEBUG(("unsupported IO read from port %04x\n", address));
+ break;
+ default:
+ retval = 0xffffffff;
+ }
+
+ return_from_read:
+ if (bx_dbg.unsupported_io)
+ switch (io_len) {
+ case 1:
+ retval = (Bit8u)retval;
+ BX_DEBUG(("unmapped: 8-bit read from %04x = %02x\n", address, retval));
+ break;
+ case 2:
+ retval = (Bit16u)retval;
+ BX_DEBUG(("unmapped: 16-bit read from %04x = %04x\n", address, retval));
+ break;
+ case 4:
+ BX_DEBUG(("unmapped: 32-bit read from %04x = %08x\n", address, retval));
+ break;
+ default:
+ BX_DEBUG(("unmapped: ??-bit read from %04x = %x\n", address, retval));
+ }
+ return retval;
+}
+
+
+ // static IO port write callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ void
+bx_unmapped_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_UM_SMF
+ bx_unmapped_c *class_ptr = (bx_unmapped_c *) this_ptr;
+
+ class_ptr->write(address, value, io_len);
+}
+
+ void
+bx_unmapped_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_UM_SMF
+ UNUSED(io_len);
+
+
+ // This function gets called for access to any IO ports which
+ // are not mapped to any device handler. Writes to an unmapped
+ // IO port are ignored.
+
+// ???
+
+
+ if (address >= 0x02e0 && address <= 0x02ef)
+ goto return_from_write;
+
+ switch (address) {
+ case 0x80: // diagnostic test port to display progress of POST
+ //BX_DEBUG(("Diagnostic port 80h: write = %02xh\n", (unsigned) value));
+ BX_UM_THIS s.port80 = value;
+ break;
+
+ case 0x8e: // ???
+ BX_UM_THIS s.port8e = value;
+ break;
+
+#if BX_PORT_E9_HACK
+ // This port doesn't exist on normal ISA architecture. However,
+ // we define a convention here, to display on the console of the
+ // system running Bochs, anything that is written to it. The
+ // idea is to provide debug output very early when writing
+ // BIOS or OS code for example, without having to bother with
+ // properly setting up a serial port or anything.
+ //
+ // Idea by Andreas Beck (andreas.beck@ggi-project.org)
+
+ case 0xe9:
+ putchar(value);
+ fflush(stdout);
+ break;
+#endif
+ case 0xed: // Dummy port used as I/O delay
+ break;
+ case 0xee: // ???
+ break;
+
+ case 0x2f2:
+ case 0x2f3:
+ case 0x2f4:
+ case 0x2f5:
+ case 0x2f6:
+ case 0x2f7:
+ case 0x3e8:
+ case 0x3e9:
+ case 0x3eb:
+ case 0x3ec:
+ case 0x3ed:
+ // BX_DEBUG(("unsupported IO write to port %04x of %02x\n",
+ // address, value));
+ break;
+ case 0x0400:
+ BX_PANIC(("BIOS panic at rombios.c, line %d\n", value));
+ break;
+ case 0xfedc:
+ bx_dbg.debugger = (value > 0);
+ BX_DEBUG(( "DEBUGGER = %u\n", (unsigned) bx_dbg.debugger));
+ break;
+
+ case 0xfff0:
+ BX_UM_THIS s.bios_message[BX_UM_THIS s.bios_message_i] =
+ (Bit8u) value;
+ BX_UM_THIS s.bios_message_i ++;
+ if ( BX_UM_THIS s.bios_message_i >= BX_BIOS_MESSAGE_SIZE ) {
+ BX_UM_THIS s.bios_message[ BX_BIOS_MESSAGE_SIZE - 1] = 0;
+ BX_UM_THIS s.bios_message_i = 0;
+ BX_INFO(("BIOS message: %s", BX_UM_THIS s.bios_message));
+ }
+ else if ((value & 0xff) == '\n') {
+ BX_UM_THIS s.bios_message[ BX_UM_THIS s.bios_message_i ] = 0;
+ BX_UM_THIS s.bios_message_i = 0;
+ BX_INFO(("BIOS message: %s", BX_UM_THIS s.bios_message));
+ }
+ break;
+
+ default:
+ break;
+ }
+ return_from_write:
+ if (bx_dbg.unsupported_io)
+ switch (io_len) {
+ case 1:
+ BX_INFO(("unmapped: 8-bit write to %04x = %02x\n", address, value));
+ break;
+ case 2:
+ BX_INFO(("unmapped: 16-bit write to %04x = %04x\n", address, value));
+ break;
+ case 4:
+ BX_INFO(("unmapped: 32-bit write to %04x = %08x\n", address, value));
+ break;
+ default:
+ BX_INFO(("unmapped: ??-bit write to %04x = %x\n", address, value));
+ break;
+ }
+}
--- /dev/null
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+
+#define BX_BIOS_MESSAGE_SIZE 80
+
+
+#if BX_USE_UM_SMF
+# define BX_UM_SMF static
+# define BX_UM_THIS bx_unmapped.
+#else
+# define BX_UM_SMF
+# define BX_UM_THIS this->
+#endif
+
+
+
+class bx_unmapped_c : public logfunctions {
+public:
+ bx_unmapped_c(void);
+ ~bx_unmapped_c(void);
+#if BX_SUPPORT_SID
+ BX_UM_SMF void init(void);
+#else
+ BX_UM_SMF void init(bx_devices_c *d);
+#endif
+
+private:
+
+ static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+ static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+#if BX_SUPPORT_SID
+ public:
+#endif
+#if !BX_USE_UM_SMF
+ Bit32u read(Bit32u address, unsigned io_len);
+ void write(Bit32u address, Bit32u value, unsigned io_len);
+#endif
+#if BX_SUPPORT_SID
+ private:
+#endif
+
+ struct {
+ Bit8u port80;
+ Bit8u port8e;
+
+ Bit8u bios_message[BX_BIOS_MESSAGE_SIZE];
+ unsigned int bios_message_i;
+ } s; // state information
+
+#if BX_SUPPORT_SID==0
+ bx_devices_c *devices;
+#endif
+ };
+
+#if BX_SUPPORT_SID==0
+extern bx_unmapped_c bx_unmapped;
+#endif
#include "sid-vga-wrapper.h"
+#include <cstdlib>
+#include <cerrno>
+#include <ctime>
+#include <unistd.h>
+#include <fstream>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+using sidutil::make_attribute;
+using sidutil::parse_attribute;
+using sidutil::find_sid_data_file;
+using sidutil::std_error_string;
+
vga::vga ()
: init_pin(this, & vga::init),
- ports_3b4_3b5_bus(this, & vga::read_port_3b4_3b5, &vga::write_port_3b4_3b5),
- ports_3ba_bus(this, & vga::read_port_3ba, &vga::write_port_3ba),
- ports_3c0_3cf_bus(this, & vga::read_port_3c0_3cf, &vga::write_port_3c0_3cf),
- ports_3d4_3d5_bus(this, & vga::read_port_3d4_3d5, &vga::write_port_3d4_3d5),
- ports_3da_bus(this, & vga::read_port_3da, &vga::write_port_3da),
- framebuffer_bus(this, & vga::read_mem, &vga::write_mem)
+ ports_0x3b4_0x3b5_bus(this, & vga::read_port_0x3b4_0x3b5, &vga::write_port_0x3b4_0x3b5),
+ port_0x3ba_bus(this, & vga::read_port_0x3ba, &vga::write_port_0x3ba),
+ ports_0x3c0_0x3cf_bus(this, & vga::read_port_0x3c0_0x3cf, &vga::write_port_0x3c0_0x3cf),
+ ports_0x3d4_0x3d5_bus(this, & vga::read_port_0x3d4_0x3d5, &vga::write_port_0x3d4_0x3d5),
+ port_0x3da_bus(this, & vga::read_port_0x3da, &vga::write_port_0x3da),
+ cmos_registers_bus(0),
+ framebuffer_bus(this, & vga::read_mem, &vga::write_mem),
+ imageload_pin (this, & vga::imageload_handler),
+ imagestore_pin (this, & vga::imagestore_handler),
+ imagemmap_pin (this, & vga::imagemmap_handler),
+ imagemsync_pin (this, & vga::imagemsync_handler)
{
add_pin("init", & this->init_pin);
add_pin("palette-change-index", & this->palette_change_index_pin);
- add_bus("ports-0x3b4-0x3b5", & this->ports_3b4_3b5_bus);
- add_bus("port-0x3ba", & this->ports_3ba_bus);
- add_bus("ports-0x3c0-0x3cf", & this->ports_3c0_3cf_bus);
- add_bus("ports-0x3d4-0x3d5", & this->ports_3d4_3d5_bus);
- add_bus("port-0x3da", & this->ports_3da_bus);
+ add_bus("ports-0x3b4-0x3b5", & this->ports_0x3b4_0x3b5_bus);
+ add_bus("port-0x3ba", & this->port_0x3ba_bus);
+ add_bus("ports-0x3c0-0x3cf", & this->ports_0x3c0_0x3cf_bus);
+ add_bus("ports-0x3d4-0x3d5", & this->ports_0x3d4_0x3d5_bus);
+ add_bus("port-0x3da", & this->port_0x3da_bus);
add_bus("framebuffer", & this->framebuffer_bus);
+
+ add_accessor("cmos-registers", & this->cmos_registers_bus);
+
+ // copied from sid/component/memory/generic.cxx
+
+ add_attribute_virtual ("size", this,
+ & vga::get_size_attr,
+ & vga::set_size_attr, "setting");
+
+ this->max_buffer_length = 32UL * 1024UL * 1024UL;
+ this->buffer = 0;
+ this->buffer_length = 0;
+ this->mmapping_p = false;
+
+ add_attribute ("image-file", & this->image_file_name, "setting");
+ add_pin ("image-load", & this->imageload_pin);
+ add_attribute ("image-load", & this->imageload_pin, "pin");
+ add_pin ("image-store", & this->imagestore_pin);
+ add_attribute ("image-store", & this->imagestore_pin, "pin");
+ add_pin ("image-mmap", & this->imagemmap_pin);
+ add_attribute ("image-mmap", & this->imagemmap_pin, "pin");
+ add_pin ("image-msync", & this->imagemsync_pin);
+ add_attribute ("image-msync", & this->imagemsync_pin, "pin");
}
void
vga::init (host_int_4)
{
bx_vga.init(this, this->buffer);
+ if (cmos_registers_bus)
+ {
+ little_int_1 old_register_value;
+ little_int_1 new_register_value;
+
+ cmos_registers_bus->read(host_int_4(0x14), old_register_value);
+ new_register_value = (old_register_value & 0xcf) | 0x00;
+ cmos_registers_bus->write(host_int_4(0x14), little_int_1(0x00)); /* video card with BIOS ROM */
+ }
}
bus::status
-vga::read_port_3b4_3b5 (host_int_4 addr, little_int_1 mask, little_int_1 & data)
+vga::read_port_0x3b4_0x3b5 (host_int_4 addr, little_int_1 mask, little_int_1 & data)
{
- addr += 0x03b4;
+ addr += 0x3b4;
data = bx_vga.read(addr, 1);
return bus::ok;
}
bus::status
-vga::write_port_3b4_3b5 (host_int_4 addr, little_int_1 mask, little_int_1 data)
+vga::write_port_0x3b4_0x3b5 (host_int_4 addr, little_int_1 mask, little_int_1 data)
{
- addr += 0x03b4;
+ addr += 0x3b4;
bx_vga.write(addr, data, 1, true);
return bus::ok;
}
bus::status
-vga::read_port_3ba (host_int_4 addr, little_int_1 mask, little_int_1 & data)
+vga::read_port_0x3ba (host_int_4 addr, little_int_1 mask, little_int_1 & data)
{
- addr += 0x03ba;
+ addr += 0x3ba;
data = bx_vga.read(addr, 1);
return bus::ok;
}
bus::status
-vga::write_port_3ba (host_int_4 addr, little_int_1 mask, little_int_1 data)
+vga::write_port_0x3ba (host_int_4 addr, little_int_1 mask, little_int_1 data)
{
- addr += 0x03ba;
+ addr += 0x3ba;
bx_vga.write(addr, data, 1, true);
return bus::ok;
}
bus::status
-vga::read_port_3c0_3cf (host_int_4 addr, little_int_1 mask, little_int_1 & data)
+vga::read_port_0x3c0_0x3cf (host_int_4 addr, little_int_1 mask, little_int_1 & data)
{
- addr += 0x03c0;
+ addr += 0x3c0;
data = bx_vga.read(addr, 1);
return bus::ok;
}
bus::status
-vga::write_port_3c0_3cf (host_int_4 addr, little_int_1 mask, little_int_1 data)
+vga::write_port_0x3c0_0x3cf (host_int_4 addr, little_int_1 mask, little_int_1 data)
{
- addr += 0x03c0;
+ addr += 0x3c0;
bx_vga.write(addr, data, 1, true);
return bus::ok;
}
bus::status
-vga::read_port_3d4_3d5 (host_int_4 addr, little_int_1 mask, little_int_1 & data)
+vga::read_port_0x3d4_0x3d5 (host_int_4 addr, little_int_1 mask, little_int_1 & data)
{
- addr += 0x03d4;
+ addr += 0x3d4;
data = bx_vga.read(addr, 1);
return bus::ok;
}
bus::status
-vga::write_port_3d4_3d5 (host_int_4 addr, little_int_1 mask, little_int_1 data)
+vga::write_port_0x3d4_0x3d5 (host_int_4 addr, little_int_1 mask, little_int_1 data)
{
- addr += 0x03d4;
+ addr += 0x3d4;
bx_vga.write(addr, data, 1, true);
return bus::ok;
}
bus::status
-vga::read_port_3da (host_int_4 addr, little_int_1 mask, little_int_1 & data)
+vga::read_port_0x3da (host_int_4 addr, little_int_1 mask, little_int_1 & data)
{
- addr += 0x03da;
+ addr += 0x3da;
data = bx_vga.read(addr, 1);
return bus::ok;
}
bus::status
-vga::write_port_3da (host_int_4 addr, little_int_1 mask, little_int_1 data)
+vga::write_port_0x3da (host_int_4 addr, little_int_1 mask, little_int_1 data)
{
- addr += 0x03da;
+ addr += 0x3da;
bx_vga.write(addr, data, 1, true);
return bus::ok;
}
{
this->palette_change_index_pin.drive(index);
}
+
+bool
+vga::attempt_resize (host_int_4 new_length) throw()
+{
+ if (new_length > max_buffer_length)
+ return false;
+
+ host_int_1* new_buffer = new (nothrow) host_int_1[new_length];
+ if (new_buffer == 0)
+ {
+ cerr << "memory: error allocating memory buffer: " << std_error_string() << endl;
+ this->error_pin.drive (0);
+ return false;
+ }
+
+ if (this->mmapping_p)
+ {
+ munmap (reinterpret_cast<char*>(this->buffer), this->buffer_length);
+ this->mmapping_p = false;
+ }
+ else
+ delete [] this->buffer;
+
+ this->buffer = new_buffer;
+ this->buffer_length = new_length;
+ memset(this->buffer, 0, this->buffer_length);
+
+ return true;
+}
+
+string
+vga::get_size_attr ()
+{
+ return make_attribute (this->buffer_length);
+}
+
+
+component::status
+vga::set_size_attr (const string& s)
+{
+ host_int_4 new_size;
+ component::status st = parse_attribute(s, new_size);
+ if (st == component::ok)
+ {
+ bool ok = this->attempt_resize (new_size);
+ if (! ok)
+ return component::bad_value;
+ }
+ return st;
+}
+
+void
+vga::imageload_handler (host_int_4)
+{
+ assert(this->buffer != 0);
+
+ // Do nothing if file name was empty.
+ if (this->image_file_name == "")
+ {
+ cerr << "memory: no image-file set for image-load" << endl;
+ this->error_pin.drive (0);
+ return;
+ }
+
+ ifstream f (find_sid_data_file(this->image_file_name).c_str(), ios::binary | ios::in);
+ if (! f.good())
+ {
+ cerr << "memory: error opening " << this->image_file_name << ": "
+ << std_error_string() << endl;
+ this->error_pin.drive (0);
+ return;
+ }
+
+ // Load whole darned file
+ memset (& this->buffer[0], 0, this->buffer_length);
+ f.read (reinterpret_cast<char*>(& this->buffer[0]), this->buffer_length);
+}
+
+
+
+void
+vga::imagestore_handler (host_int_4)
+{
+ assert(this->buffer != 0);
+
+ // Do nothing if file name was empty.
+ if (this->image_file_name == "")
+ {
+ cerr << "memory: no image-file set for image-store" << endl;
+ this->error_pin.drive (0);
+ return;
+ }
+
+ ofstream f (find_sid_data_file(this->image_file_name).c_str(),
+ ios::binary | ios::out | ios::trunc);
+ if (! f.good())
+ {
+ cerr << "memory: error opening " << this->image_file_name << ": "
+ << std_error_string() << endl;
+ this->error_pin.drive (0);
+ return;
+ }
+
+ // Save whole darned file
+ f.write (reinterpret_cast<const char*>(& this->buffer[0]), this->buffer_length);
+ // if (! f.good())
+ // cerr << "memory: short write to " << this->image_file_name << endl;
+}
+
+
+
+
+void
+vga::imagemsync_handler (host_int_4)
+{
+ assert (this->buffer);
+ if (this->mmapping_p)
+ {
+ int rc = msync (reinterpret_cast<char*>(this->buffer),
+ this->buffer_length, MS_SYNC|MS_INVALIDATE);
+ if (rc < 0)
+ cerr << "memory: failed in mmap:" << std_error_string() << endl;
+ }
+}
+
+
+
+void
+vga::imagemmap_handler (host_int_4)
+{
+ assert (this->buffer);
+
+ // Do nothing if file name was empty.
+ if (this->image_file_name == "")
+ {
+ cerr << "memory: no image-file set for image-mmap" << endl;
+ this->error_pin.drive (0);
+ return;
+ }
+
+ int fd = open (find_sid_data_file(this->image_file_name).c_str(), O_RDWR);
+ if (fd < 0)
+ {
+ cerr << "memory: cannot open image-file during image-mmap:" << std_error_string() << endl;
+ this->error_pin.drive (0);
+ return;
+ }
+
+ /* Some kernels will SIGBUS the application if mmap'd file is not large enough. */
+ struct stat desc;
+ int rc = fstat (fd, & desc);
+ if (rc < 0 || desc.st_size < this->buffer_length)
+ {
+ cerr << "memory: cannot confirm that mmap file is large enough (>= "
+ << this->buffer_length << " bytes)." << endl;
+ this->error_pin.drive (0);
+ return;
+ }
+
+ char* new_buffer = reinterpret_cast<char*>(mmap (0, this->buffer_length,
+ PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0));
+#ifndef MAP_FAILED
+#define MAP_FAILED ((char*)-1)
+#endif
+ if (new_buffer == 0 || new_buffer == MAP_FAILED)
+ {
+ cerr << "memory: failed in mmap:" << std_error_string() << endl;
+ close (fd);
+ this->error_pin.drive (0);
+ return;
+ }
+
+ if (this->mmapping_p)
+ {
+ // Unmap previous block first
+ munmap (reinterpret_cast<char*>(this->buffer), this->buffer_length);
+ this->mmapping_p = false;
+ }
+
+ this->buffer = reinterpret_cast<host_int_1*>(new_buffer);
+ close (fd);
+ this->mmapping_p = true;
+}
#include <sidmiscutil.h>
#include <sidwatchutil.h>
#include <sidso.h>
-#include "generic.h"
#include "bochs.h"
using sid::component;
using sid::bus;
+using sid::host_int_1;
using sid::host_int_4;
using sid::little_int_1;
+
using sidutil::callback_word_bus;
using sidutil::callback_pin;
using sidutil::output_pin;
-class vga : public generic_memory
+class vga : public sidutil::fixed_pin_map_component,
+ public sidutil::fixed_accessor_map_component,
+ public sidutil::fixed_attribute_map_component,
+ public sidutil::no_relation_component,
+ public sidutil::fixed_bus_map_component
{
public:
vga();
output_pin palette_change_index_pin;
- bus::status read_port_3b4_3b5 (host_int_4 addr, little_int_1 mask, little_int_1 & data);
- bus::status write_port_3b4_3b5 (host_int_4 addr, little_int_1 mask, little_int_1 data);
- bus::status read_port_3ba (host_int_4 addr, little_int_1 mask, little_int_1 & data);
- bus::status write_port_3ba (host_int_4 addr, little_int_1 mask, little_int_1 data);
- bus::status read_port_3c0_3cf (host_int_4 addr, little_int_1 mask, little_int_1 & data);
- bus::status write_port_3c0_3cf (host_int_4 addr, little_int_1 mask, little_int_1 data);
- bus::status read_port_3d4_3d5 (host_int_4 addr, little_int_1 mask, little_int_1 & data);
- bus::status write_port_3d4_3d5 (host_int_4 addr, little_int_1 mask, little_int_1 data);
- bus::status read_port_3da (host_int_4 addr, little_int_1 mask, little_int_1 & data);
- bus::status write_port_3da (host_int_4 addr, little_int_1 mask, little_int_1 data);
+ bus::status read_port_0x3b4_0x3b5 (host_int_4 addr, little_int_1 mask, little_int_1 & data);
+ bus::status write_port_0x3b4_0x3b5 (host_int_4 addr, little_int_1 mask, little_int_1 data);
+ bus::status read_port_0x3ba (host_int_4 addr, little_int_1 mask, little_int_1 & data);
+ bus::status write_port_0x3ba (host_int_4 addr, little_int_1 mask, little_int_1 data);
+ bus::status read_port_0x3c0_0x3cf (host_int_4 addr, little_int_1 mask, little_int_1 & data);
+ bus::status write_port_0x3c0_0x3cf (host_int_4 addr, little_int_1 mask, little_int_1 data);
+ bus::status read_port_0x3d4_0x3d5 (host_int_4 addr, little_int_1 mask, little_int_1 & data);
+ bus::status write_port_0x3d4_0x3d5 (host_int_4 addr, little_int_1 mask, little_int_1 data);
+ bus::status read_port_0x3da (host_int_4 addr, little_int_1 mask, little_int_1 & data);
+ bus::status write_port_0x3da (host_int_4 addr, little_int_1 mask, little_int_1 data);
- callback_word_bus<vga, little_int_1> ports_3b4_3b5_bus;
- callback_word_bus<vga, little_int_1> ports_3ba_bus;
- callback_word_bus<vga, little_int_1> ports_3c0_3cf_bus;
- callback_word_bus<vga, little_int_1> ports_3d4_3d5_bus;
- callback_word_bus<vga, little_int_1> ports_3da_bus;
+ callback_word_bus<vga, little_int_1> ports_0x3b4_0x3b5_bus;
+ callback_word_bus<vga, little_int_1> port_0x3ba_bus;
+ callback_word_bus<vga, little_int_1> ports_0x3c0_0x3cf_bus;
+ callback_word_bus<vga, little_int_1> ports_0x3d4_0x3d5_bus;
+ callback_word_bus<vga, little_int_1> port_0x3da_bus;
bus::status read_mem (host_int_4 addr, little_int_1 mask, little_int_1 & data);
bus::status write_mem (host_int_4 addr, little_int_1 mask, little_int_1 data);
callback_word_bus<vga, little_int_1> framebuffer_bus;
+ bus *cmos_registers_bus;
+
bx_vga_c bx_vga;
+
+ // copied from sid/component/memory/generic.h
+
+ host_int_1* buffer;
+ host_int_4 buffer_length;
+ bool mmapping_p;
+
+ host_int_4 max_buffer_length;
+ bool attempt_resize (host_int_4 new_length) throw();
+
+ string get_size_attr ();
+ component::status set_size_attr (const string& s);
+
+ string image_file_name;
+ callback_pin<vga> imageload_pin;
+ void imageload_handler (host_int_4);
+ callback_pin<vga> imagestore_pin;
+ void imagestore_handler (host_int_4);
+ output_pin error_pin;
+ callback_pin<vga> imagemmap_pin;
+ void imagemmap_handler (host_int_4);
+ callback_pin<vga> imagemsync_pin;
+ void imagemsync_handler (host_int_4);
+
};
#endif // SID_VGA_WRAPPER_DEF_H
}
else {
BX_VGA_THIS s.vga_memory[addr - 0xa0000] = value;
- vga_component->drive_text_memory_updated_pin();
+ // only update on odd address writes,
+ // so that color values go through
+ if (addr % 2)
+ vga_component->drive_text_memory_updated_pin();
BX_VGA_THIS s.vga_mem_updated = 1;
}
}
MSL = BX_VGA_THIS s.CRTC.reg[9] & 0x1f;
rows = (VDE + 1) / (MSL + 1);
if (rows > BX_MAX_TEXT_LINES)
+#if BX_SUPPORT_SID
+ rows = BX_MAX_TEXT_LINES;
+#else
BX_PANIC(("text rows>50\n"));
+#endif
piHeight = rows;
}