]> gitweb.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
imported winuaesrc0826b4.zip
authorToni Wilen <twilen@winuae.net>
Sun, 25 Apr 2004 15:28:03 +0000 (18:28 +0300)
committerToni Wilen <twilen@winuae.net>
Mon, 22 Feb 2010 19:22:36 +0000 (21:22 +0200)
282 files changed:
ChangeLog [new file with mode: 0755]
akiko.c [new file with mode: 0755]
akiko2.c [new file with mode: 0755]
ar.c [new file with mode: 0755]
audio.c [new file with mode: 0755]
autoconf.c [new file with mode: 0755]
blitops.c [new file with mode: 0755]
blitter.c [new file with mode: 0755]
blkdev.c [new file with mode: 0755]
bsdsocket.c [new file with mode: 0755]
build68k.c [new file with mode: 0755]
catweasel.c [new file with mode: 0755]
cdrom.c [new file with mode: 0755]
cfgfile.c [new file with mode: 0755]
cia.c [new file with mode: 0755]
compemu_fpp.c [new file with mode: 0755]
compemu_optimizer.c [new file with mode: 0755]
compemu_optimizer_x86.c [new file with mode: 0755]
compemu_raw_x86.c [new file with mode: 0755]
compemu_support.c [new file with mode: 0755]
compiler.c [new file with mode: 0755]
cpuopti.c [new file with mode: 0755]
custom.c [new file with mode: 0755]
debug.c [new file with mode: 0755]
disk.c [new file with mode: 0755]
dms/cdata.h [new file with mode: 0755]
dms/crc_csum.c [new file with mode: 0755]
dms/crc_csum.h [new file with mode: 0755]
dms/getbits.c [new file with mode: 0755]
dms/getbits.h [new file with mode: 0755]
dms/maketbl.c [new file with mode: 0755]
dms/maketbl.h [new file with mode: 0755]
dms/pfile.c [new file with mode: 0755]
dms/pfile.h [new file with mode: 0755]
dms/tables.c [new file with mode: 0755]
dms/tables.h [new file with mode: 0755]
dms/u_deep.c [new file with mode: 0755]
dms/u_deep.h [new file with mode: 0755]
dms/u_heavy.c [new file with mode: 0755]
dms/u_heavy.h [new file with mode: 0755]
dms/u_init.c [new file with mode: 0755]
dms/u_init.h [new file with mode: 0755]
dms/u_medium.c [new file with mode: 0755]
dms/u_medium.h [new file with mode: 0755]
dms/u_quick.c [new file with mode: 0755]
dms/u_quick.h [new file with mode: 0755]
dms/u_rle.c [new file with mode: 0755]
dms/u_rle.h [new file with mode: 0755]
drawing.c [new file with mode: 0755]
driveclick.c [new file with mode: 0755]
enforcer.c [new file with mode: 0755]
ersatz.c [new file with mode: 0755]
expansion.c [new file with mode: 0755]
fdi2raw.c [new file with mode: 0755]
filesys.asm [new file with mode: 0755]
filesys.c [new file with mode: 0755]
filesys.sh [new file with mode: 0755]
fpp.c [new file with mode: 0755]
fsdb.c [new file with mode: 0755]
fsdb_unix.c [new file with mode: 0755]
fsusage.c [new file with mode: 0755]
genblitter.c [new file with mode: 0755]
gencomp.c [new file with mode: 0755]
gencpu.c [new file with mode: 0755]
gengenblitter.c [new file with mode: 0755]
genp2c.c [new file with mode: 0755]
gfxlib.c [new file with mode: 0755]
gfxutil.c [new file with mode: 0755]
gtkui.c [new file with mode: 0755]
hardfile.c [new file with mode: 0755]
identify.c [new file with mode: 0755]
include/akiko.h [new file with mode: 0755]
include/ar.h [new file with mode: 0755]
include/audio.h [new file with mode: 0755]
include/autoconf.h [new file with mode: 0755]
include/blitter.h [new file with mode: 0755]
include/blkdev.h [new file with mode: 0755]
include/bsdsocket.h [new file with mode: 0755]
include/catweasel.h [new file with mode: 0755]
include/cia.h [new file with mode: 0755]
include/commpipe.h [new file with mode: 0755]
include/compemu.h [new file with mode: 0755]
include/compiler.h [new file with mode: 0755]
include/cpu_prefetch.h [new file with mode: 0755]
include/custom.h [new file with mode: 0755]
include/debug.h [new file with mode: 0755]
include/disk.h [new file with mode: 0755]
include/drawing.h [new file with mode: 0755]
include/driveclick.h [new file with mode: 0755]
include/enforcer.h [new file with mode: 0755]
include/ersatz.h [new file with mode: 0755]
include/events.h [new file with mode: 0755]
include/events_jit.h [new file with mode: 0755]
include/events_normal.h [new file with mode: 0755]
include/execlib.h [new file with mode: 0755]
include/fdi2raw.h [new file with mode: 0755]
include/filesys.h [new file with mode: 0755]
include/filter.h [new file with mode: 0755]
include/fpp-ieee-be.h [new file with mode: 0755]
include/fpp-unknown.h [new file with mode: 0755]
include/fsdb.h [new file with mode: 0755]
include/fsusage.h [new file with mode: 0755]
include/genblitter.h [new file with mode: 0755]
include/gensound.h [new file with mode: 0755]
include/gfxfilter.h [new file with mode: 0755]
include/gui.h [new file with mode: 0755]
include/identify.h [new file with mode: 0755]
include/inputdevice.h [new file with mode: 0755]
include/keyboard.h [new file with mode: 0755]
include/keybuf.h [new file with mode: 0755]
include/mackbd.h [new file with mode: 0755]
include/memory.h [new file with mode: 0755]
include/native2amiga.h [new file with mode: 0755]
include/newcpu.h [new file with mode: 0755]
include/options.h [new file with mode: 0755]
include/osemu.h [new file with mode: 0755]
include/picasso96.h [new file with mode: 0755]
include/readcpu.h [new file with mode: 0755]
include/savestate.h [new file with mode: 0755]
include/scsidev.h [new file with mode: 0755]
include/serial.h [new file with mode: 0755]
include/sysconfig.h.win32 [new file with mode: 0755]
include/sysdeps.h [new file with mode: 0755]
include/tui.h [new file with mode: 0755]
include/uae.h [new file with mode: 0755]
include/uaeexe.h [new file with mode: 0755]
include/unzip.h [new file with mode: 0755]
include/xwin.h [new file with mode: 0755]
include/zfile.h [new file with mode: 0755]
inputdevice.c [new file with mode: 0755]
inputevents.def [new file with mode: 0755]
keybuf.c [new file with mode: 0755]
main.c [new file with mode: 0755]
memory.c [new file with mode: 0755]
missing.c [new file with mode: 0755]
native2amiga.c [new file with mode: 0755]
ncurses.c [new file with mode: 0755]
newcpu.c [new file with mode: 0755]
nogui.c [new file with mode: 0755]
od-generic/exectasks.h [new file with mode: 0755]
od-generic/joystick.c [new file with mode: 0755]
od-generic/memory.h [new file with mode: 0755]
od-generic/sound.c [new file with mode: 0755]
od-generic/sound.h [new file with mode: 0755]
od-win32/ahidsound.c [new file with mode: 0755]
od-win32/ahidsound.h [new file with mode: 0755]
od-win32/asm.bat [new file with mode: 0755]
od-win32/avioutput.c [new file with mode: 0755]
od-win32/avioutput.h [new file with mode: 0755]
od-win32/blkdev_win32_aspi.c [new file with mode: 0755]
od-win32/blkdev_win32_ioctl.c [new file with mode: 0755]
od-win32/blkdev_win32_spti.c [new file with mode: 0755]
od-win32/bsdsock.c [new file with mode: 0755]
od-win32/build68k_msvc/build68k_msvc.rc [new file with mode: 0755]
od-win32/build68k_msvc/build68k_msvc.vcproj [new file with mode: 0755]
od-win32/caps/CapsAPI.h [new file with mode: 0755]
od-win32/caps/CapsLib.h [new file with mode: 0755]
od-win32/caps/Comlib.h [new file with mode: 0755]
od-win32/caps/Comtype.h [new file with mode: 0755]
od-win32/caps/caps_win32.c [new file with mode: 0755]
od-win32/caps/caps_win32.h [new file with mode: 0755]
od-win32/config.h [new file with mode: 0755]
od-win32/dinput.c [new file with mode: 0755]
od-win32/direct3d.c [new file with mode: 0755]
od-win32/direct3d.h [new file with mode: 0755]
od-win32/drivesound.c [new file with mode: 0755]
od-win32/dxwrap.c [new file with mode: 0755]
od-win32/dxwrap.h [new file with mode: 0755]
od-win32/fsdb_win32.c [new file with mode: 0755]
od-win32/genblitter_msvc/genblitter_msvc.vcproj [new file with mode: 0755]
od-win32/gencomp_msvc/gencomp_msvc.vcproj [new file with mode: 0755]
od-win32/gencpu_msvc/gencpu_msvc.vcproj [new file with mode: 0755]
od-win32/hardfile_win32.c [new file with mode: 0755]
od-win32/hq2x32 [new file with mode: 0755]
od-win32/hq2x32.asm [new file with mode: 0755]
od-win32/hq3x16.asm [new file with mode: 0755]
od-win32/hq3x32.asm [new file with mode: 0755]
od-win32/hq4x32.asm [new file with mode: 0755]
od-win32/ioport.c [new file with mode: 0755]
od-win32/ioport.h [new file with mode: 0755]
od-win32/keyboard_win32.c [new file with mode: 0755]
od-win32/machdep/m68k.h [new file with mode: 0755]
od-win32/machdep/maccess.h [new file with mode: 0755]
od-win32/machdep/rpt.h [new file with mode: 0755]
od-win32/machdep/support.c [new file with mode: 0755]
od-win32/makeexe.bat [new file with mode: 0755]
od-win32/md-fpp.h [new file with mode: 0755]
od-win32/midi.c [new file with mode: 0755]
od-win32/midi.h [new file with mode: 0755]
od-win32/midiin.c [new file with mode: 0755]
od-win32/mman.c [new file with mode: 0755]
od-win32/mman2.c [new file with mode: 0755]
od-win32/opengl.c [new file with mode: 0755]
od-win32/opengl.h [new file with mode: 0755]
od-win32/osdep/exectasks.h [new file with mode: 0755]
od-win32/parser.c [new file with mode: 0755]
od-win32/parser.h [new file with mode: 0755]
od-win32/picasso96_win.c [new file with mode: 0755]
od-win32/picasso96_win.h [new file with mode: 0755]
od-win32/posixemu.c [new file with mode: 0755]
od-win32/posixemu.h [new file with mode: 0755]
od-win32/resources/35floppy.ico [new file with mode: 0755]
od-win32/resources/Mycomp.ico [new file with mode: 0755]
od-win32/resources/RCa00564 [new file with mode: 0755]
od-win32/resources/amigainfo.ico [new file with mode: 0755]
od-win32/resources/avioutput.ico [new file with mode: 0755]
od-win32/resources/chip.ico [new file with mode: 0755]
od-win32/resources/cpu.ico [new file with mode: 0755]
od-win32/resources/drive.ico [new file with mode: 0755]
od-win32/resources/drive_click.wav [new file with mode: 0755]
od-win32/resources/drive_snatch.wav [new file with mode: 0755]
od-win32/resources/drive_spin.wav [new file with mode: 0755]
od-win32/resources/drive_spinnd.wav [new file with mode: 0755]
od-win32/resources/drive_startup.wav [new file with mode: 0755]
od-win32/resources/file.ico [new file with mode: 0755]
od-win32/resources/folder.ico [new file with mode: 0755]
od-win32/resources/h_arrow.cur [new file with mode: 0755]
od-win32/resources/joystick.ico [new file with mode: 0755]
od-win32/resources/misc.ico [new file with mode: 0755]
od-win32/resources/move_dow.ico [new file with mode: 0755]
od-win32/resources/move_up.ico [new file with mode: 0755]
od-win32/resources/resource.h [new file with mode: 0755]
od-win32/resources/resource.hm [new file with mode: 0755]
od-win32/resources/root.ico [new file with mode: 0755]
od-win32/resources/screen.ico [new file with mode: 0755]
od-win32/resources/sound.ico [new file with mode: 0755]
od-win32/resources/winuae.exe.manifest [new file with mode: 0755]
od-win32/resources/winuae.ico [new file with mode: 0755]
od-win32/resources/winuae.rc [new file with mode: 0755]
od-win32/resources/winuae_minimal.rc [new file with mode: 0755]
od-win32/scaler.c [new file with mode: 0755]
od-win32/scaler2.c [new file with mode: 0755]
od-win32/screenshot.c [new file with mode: 0755]
od-win32/scsidef.h [new file with mode: 0755]
od-win32/serial_win32.c [new file with mode: 0755]
od-win32/sfhelper.c [new file with mode: 0755]
od-win32/shm.c [new file with mode: 0755]
od-win32/soundcheck.c [new file with mode: 0755]
od-win32/sounddep/sound.c [new file with mode: 0755]
od-win32/sounddep/sound.h [new file with mode: 0755]
od-win32/srcrelease.bat [new file with mode: 0755]
od-win32/support.c [new file with mode: 0755]
od-win32/sys/ipc.h [new file with mode: 0755]
od-win32/sys/mman.h [new file with mode: 0755]
od-win32/sys/shm.h [new file with mode: 0755]
od-win32/sysconfig.h [new file with mode: 0755]
od-win32/target.h [new file with mode: 0755]
od-win32/threaddep/thread.h [new file with mode: 0755]
od-win32/unistd.h [new file with mode: 0755]
od-win32/wcc.sh [new file with mode: 0755]
od-win32/win32.c [new file with mode: 0755]
od-win32/win32.h [new file with mode: 0755]
od-win32/win32_filesys.c [new file with mode: 0755]
od-win32/win32_nogui.c [new file with mode: 0755]
od-win32/win32_scale2x.c [new file with mode: 0755]
od-win32/win32gfx.c [new file with mode: 0755]
od-win32/win32gfx.h [new file with mode: 0755]
od-win32/win32gui.c [new file with mode: 0755]
od-win32/win32gui.h [new file with mode: 0755]
od-win32/winuae.nsi [new file with mode: 0755]
od-win32/winuae_msvc/winuae_msvc.vcproj [new file with mode: 0755]
od-win32/wrc.sh [new file with mode: 0755]
od-win32/writelog.c [new file with mode: 0755]
picasso96.c [new file with mode: 0755]
readcpu.c [new file with mode: 0755]
readdisk.c [new file with mode: 0755]
rpc.c [new file with mode: 0755]
savestate.c [new file with mode: 0755]
scsi-none.c [new file with mode: 0755]
scsidev.c [new file with mode: 0755]
scsiemul.c [new file with mode: 0755]
sdl-joystick.c [new file with mode: 0755]
serial.c [new file with mode: 0755]
svga.c [new file with mode: 0755]
svgancui.c [new file with mode: 0755]
table68k [new file with mode: 0755]
tui.c [new file with mode: 0755]
uaeexe.c [new file with mode: 0755]
uaelib.c [new file with mode: 0755]
unzip.c [new file with mode: 0755]
writelog.c [new file with mode: 0755]
zfile.c [new file with mode: 0755]

diff --git a/ChangeLog b/ChangeLog
new file mode 100755 (executable)
index 0000000..d7c5e21
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,2347 @@
+9C0702 Correct an overflow problem in the CIA code.
+9C0407 Sprite code updates; correct CIA memory access handlers (Toni).
+9C0306 Make w/d representable for fsdb_win32.
+       Don't reorder children of directories; this causes duplicates in
+       exnext.
+       Reorder the code for the 9/10 vsynctime hack a bit.
+       Add code from Toni to remember the last value written to a custom
+       register and to return it when reading from a write-only reg - this
+       seems to match actual hardware behaviour.
+       Add some more blitter tweaks (Toni).
+9C0227 When waking up the copper from a blitter wait, recheck that vpos is
+       larger than vcmp - especially with masking going on, this may not be
+       the case.
+       X11: When changing picasso resolution, reinitialize everything - our
+       bitmap might be too small otherwise.
+       When configuring hardfiles, use specified blocksize, not 512 (Toni).
+       In SPRxCTL_1, don't examine vstart position before computing it (Toni).
+9C0225 Some cfgfile fixes, more blitter timing changes and one big sprite
+       statemachine update from Toni.
+       Some copper timing fixes.
+       Fix flag bit confusion in action_fh_from_lock (taken from earlier
+       WinUAE).
+9C0220 Blitter timing update from Toni.
+       Copper timing "theory" changed (me/Toni).
+       If we have a rdtsc insn, always synchronize with realtime in
+       vsync_handler.
+       Don't reset the lof bit when restoring state.
+       When restoring disk image names, put them in changed_prefs (Toni)
+       Return error in action_seek if trying to seek past end of file (Bernd
+       Roesch).
+       SDL fixes by Maik Qualmann.
+       Fix for gtk warnings when updating floppy LEDs (Maik Qualmann).
+9C0216 Fix the clockspeed detection - we were getting lots of alarm signals
+       even after it had finished.
+       Some tweaks for the GUI - and also fix the problem with waiting on the
+       GUI semaphore even if no GUI is present...
+       More accurate blitter timing (Toni).
+       Support for A1000 bootrom and CDTV/CD32 extended ROMs (Toni).
+       Fix filesystem lockup with "copy dh0: ram: all".
+       Fix for JIT and more than 2MB chipmem from Toni
+       Make fsdb_win32 accept more valid Windows filenames (Toni).
+9C0215 Fix filesystem reset code that used to access freed memory.
+9C0213 gtk UI fixes from Maik Qualmann.
+9C0113 Configury & bsd compilation fixes from Krister Walfridsson.
+       Match up lock/unlock calls in wgfx_do_flushline (found by Axel
+       Doerfler).
+       Fix potential crash taking strlen of NULL in filesys.c (Axel Doerfler).
+       Set diskdmaen to 0 in dsk_dmafinished (Toni).
+9B1230 lockscr/unlockscr fixes in drawing.c.
+       Add sdlgfx from Bernd [4] Lachner.
+       Filesystem asm code improvements from Toni (make it pic, call
+       setup_exter earlier in the boot sequence, etc.)
+       Also add Toni's patch to make rtarea position configurable (keep it
+       at 0xF00000 for now, though).
+       Avoid installing filesystem stuff if user didn't request to mount
+       directories.
+       BEAMCON0 is only available with ECS Agnus.
+       Revert some bogus parts of the write_log patch.
+9B1219 Add some missing clipping to the Picasso code.
+       Limit number of illegal-mem warnings.
+9B1217 Fix the GUI crash when changing floppies.
+       Changes to support programs that change between HAM/no HAM in the
+       middle of a line.
+       Some bug fixes, and a big fprintf->write_log patch from Alex Kazik.
+9B1125 Panning support for Picasso96 (in part from WinUAE).
+       More state save fixes from Toni, and a small disk.c update as well
+       which corrects track/gap lengths.
+       More evolution of the AHI code.
+9B1124 Merged a few more small pieces from WinUAE (larger pieces in case of
+       the Picasso code).
+       CLXCON2 was never called or statesaved.  Fixed by Toni.
+       Sound sample frequency now always based on PAL timings.
+9B1123 Goodness!  Massive memory corruption bug in picasso96.c - passing
+       last color changed to DX_SetPalette instead of count.
+       Fixes for the AHI code.
+       Changed prefetch emulation to be more similar to the one MAME uses.
+       Trace mode fixes (Bernd Roesch & myself).
+9B1122 Redo the ExNext code in the filesystem to make sure we always match
+       opendir with closedir and to fix some renaming problems.
+       Fix hd changing code in gtkui.
+9B1121 Mini-merge of noncontroversial WinUAE filesys.c code.
+       Add harddisk page to gtkui.  Also change gui behaviour to wait for
+       the user to unpause before starting the emulator.
+       Add Toni's drive-led display.
+       Fixed a rather amazing source of crashes (we could fail to notice
+       the end of the frame in some cases).
+       Default to scanline mode.
+       Some tweaks to the SDL driver and the Win32 gui, mostly buffer-size
+       related.
+       Moved C source files back from tools directory (but still build them
+       there) to preserve my CVS history.
+9B1119 Move all the build tools (gencpu, cpuopti etc.) into their own
+       directory which is configured separately.  This was necessary to
+       avoid picking up SDL CFLAGS (which can #define main to _SDL_main, and
+       that breaks if you don't link with SDL), and to make cross-compiling
+       at least a little more likely.
+       Remove sanity check for SDL header file - rely on sdl-config getting
+       things right (not that we have much choice).
+       Move thread support code past sound code in configure, and make sure
+       that SDL sound enables threads.
+       Move sername into options structure.
+       Check for existance of isinf/isnan before using them.
+       Rather large WinUAE merge - this tree compiles again under Windows.
+       Most of the additional features are missing though.
+9B1118 Restore code to mirror banks for 24 bit address space which got lost
+       when all the JIT memory changes were put in.
+       Speed up the CPU time calibration code.
+       Fix the broken file selector handling in the gtk ui.  Add kickstart
+       selector.
+       Don't call XCloseDisplay, it apparently leads to crashes.
+       Try to solve the "missing write_log" problem in a sane way.
+       SDL joystick support.
+       When configure detects win32, use fsdb_win32 rather than fsdb_unix.
+9B1117 Proper masking for DDFSTOP; proper handling of AUDLEN == 0, changed
+       delayoffset code, gencpu BFINS fix, and lots of disk updates (all
+       Toni).
+       Some additional regs for move2c/movec2 (also by Toni IIRC)
+9B1115 COLOR_READ typo fix (Toni).
+9B1024 Filesystem reset leak fixes (Brian)
+       Allocate enough memory for custom state saving.
+       bploff renamed to bpl_off.
+       AGA copper cycle diagram (Toni)
+       Disable disk_data_used optimization.
+9B0926 Delayed palette setting for Picasso modes.  Also fixed problem with
+       palette setting in CLUT emulation - we need to redraw the entire
+       screen if that happens.
+9B0921 Miscellaneous small bugfixes.  Delete some obsolete code.
+9B0907 Beginnings of SDL support.  Exterminated some penguins.
+9B0825 Some xwin.c fixes from Maik Qualmann.
+9B0730 Some sprite state machine tweaks.  Fix sprite vs. DIW comparison.
+       HAM linebuffer was too small by half - oops.
+       Make absolutely, positively sure that when hsync_handler calls
+       sync_copper_with_cpu, we don't take any invalid shortcuts.
+       Memory management changes for JIT (Bernie [2], mostly).
+9B0729 Silly mistake - need to call flush_plane_data unless plfleft is
+       -1, even if no planes were enabled.
+9B0728 Small hack to reduce the time we lose with unnecessary
+       disk_doupdate_read calls.
+       Avoid calling flush_plane_data if we have no bitplanes enabled.
+       Tweak the SPCFLAG_INT handling to make "Delirium" demo work.
+       Limit rate of DDF warning messages.
+       Adjust display parameters so that things are shifted to the left
+       even more.
+       Fix (hopefully) CIA & blitter saving code.
+9B0727 Copper code reorganized; speedup code rewritten.  Can now be
+       enabled with a GUI setting.
+       Fixed the delayoffset stuff.
+9B0725 AGA sprites, and some patches to sprite/playfield collision code,
+       mostly by Toni.
+       Fixed a small sprite restore problem; added missing code to map
+       fastmem banks when restoring them.
+       Some more state saving updates from Toni.
+9B0724 Fix a nasty bug in the copper SKIP instruction introduced by recent
+       changes.
+       Update the FAST_COPPER code.  Not quite enabled yet.
+       More work on the memory configuration stuff.
+       Fix CPU type writeout in cfgfile.c (taken from WinUAE source).
+       Move the WOC demo BPLCON0 fix to compute_toscr_delay (Toni).
+       Added Toni's new disk patches, which include HD disk support by
+       Adil Temel.
+       Rewrote the memory and audio save/restore code.
+       Mask DDFSTOP with 0xFE, not 0xFC.
+9B0723 Yet another new and correct copper state machine (this time for sure)
+       Fix some AGA problems in DDF speedup code.
+       In gencpu.c, branch insns return a hardcoded cycle count; this had
+       not been updated for the CYCLE_UNIT stuff.  Fixed.
+       xwin.c: If mouse is grabbed, we don't need mousehack.
+       Don't clear audio state if produce_sound == 0; this causes problems
+       if we want to turn the sound back on.
+       If an audio channel had a period of PERIOD_MAX, allow AUDxPER to
+       set its evtime back to a reasonable value.
+       Massive cleanup of memory initialization code; it will now use changed
+       prefs on reset.  Added some memory options to gtkui.c.
+       Added Toni's state saving code, then added gtkui options and code to
+       initiate saving/restoring.
+9B0722 filesys.c: Fix writeout of hardfile params (Bernie [2])
+       Add an A1000 Kickstart disk loader (Gerald Schnabel).  Got rid of
+       the automount_uaedev code; we can detect the Kickstart version and
+       do the right thing.
+       Deleted a few unused variables (Toni)
+       Avoid aborting in decode_ham if Amiga code turns on the HAM bit but
+       has too few bitplanes (found by Toni).
+       Make the dummy mem bank return other values than 0; helps some
+       stupid memory detection code.
+       Implemented a little exec task lister for the debugger.
+       Added new debugger commands from Mark Cox.  Improved his copper list
+       debugger by adding recorded timing information to it.
+       MOVE16 fixes from Gwenole Beauchesne.
+       xBCD fixes by Maik Qualmann, with some additional flag fixes by myself
+       (ABCD & SBCD behave exactly like on a 68000 now; dunno about NBCD).
+9B0520 AGA bscan2 fixes and disk.c kickstart speedup fixes from Toni.
+       Remove bogus changes I made to one of Toni's earlier disk.c updates.
+       Call RethinkICRA/B from INTREQ (suggested by Toni).
+       Properly save mixed_stereo setting.
+       NEGX uses X and Z (Bernd Roesch).
+       Danish keyboard support (Jesper Bojesen).
+9B0311 Repair "emulated but no output" sound setting.
+9B0310 Fix massive bug introduced in do_cycles_slow with the rescaling
+       changes.
+       CLXCON logic updated for AGA (Toni).  Change meaning of collision_level
+       and add support for it in cfgfile.c.
+9B0309 Fix problem where a fsdb file could prevent deletion of otherwise
+       empty directory discovered by Torsten Enderling.
+       Rescale return values of CPU emulator functions.
+9B0225 Undo parts of the audio changes that made the "accurate" setting the
+       default.
+9B0221 Make fsdb_unix compile again.
+9B0219 Fix ddf for cases where start isn't aligned to fetchunit.
+       Fix some problems with the sound code going into infinite loops or
+       crashing.
+       Try to re-add Toni's ddf delay fixes properly.
+       Added a fix from Krister Walfridsson for X11 SHM code.
+       Rename OBJECT_NOT_FOUND to OBJECT_NOT_AROUND (not sure why, but the
+       win32 port does this; Fellow picked it up as well...)
+       Give in and allocate ainos with xcalloc.
+       Import fsdb_win32 code from Fellow.
+       Some tidyup and fixes in fsdb code.
+       Lose the lastdiv10 variable, and update CIA timers when reading them
+       (mostly by Bernie [2] Meyer)
+       Move reset_uaedevices and get_new_device to filesys.c.  Add extra
+       parameter to get_new_device.
+9B0213 Fix mouse pointer jumping bug in X11 code (Ralf Hoffmann)
+       Scaled event handling by a factor of 512.  This allows more accurate
+       sound output frequencies, as well as more fine grained CPU speed
+       settings.
+       Implemented totally untested emulator side AHI support.
+9B0211 Partially reverted changes made to the audio event code in 0.8.0.
+       Implemented "mixed" stereo.
+9B0210 Fixed invisible sprite bug - sprite_width got a new meaning, and not
+       everything had been updated.
+9B0121 cycles => get_cycles () (from Bernie [2] Meyer's JIT patchkit)
+9B0120 Final bugfix in speedup code (plfleft got set too early).
+9B0118 Fixed SPEEDUP code for AGA.  Speedup now starts when fetch_state is
+       fetched_plane0.
+9B0115 First batch of AGA playfield changes (Toni & myself).
+9B0110 Small fix for the m68k_run macro (Bernie [2] Meyer)
+9B0109 Use ntscmode from prefs structure (Dwayne C. Litzenberger)
+       Some 040 FPU fixes (Bernie [2] Meyer)
+       Delay DSKREADY a while; fix other small disk bugs (Toni Wilen)
+9A0902 F0FF10 is now a puts () calltrap.
+9A0830 Add some missing initializations in filesys.c, thanks to debugging by
+       Harald Frank.
+9A0827 Fix a crash with framerate != 1.
+       Don't allow programs to see left & right or top & bottom simultaneously
+       with the keyboard joystick replacements.  (Gee, games on the CPC and on
+       the Amiga actually have something in common - some of them crash when
+       the joystick is pushed in too many directions at the same time...)
+9A0825 Put in the new sprite code.  This has existed for many months but
+       I've only now found the final bugs.
+       New version of Bernd Meyer's special_mem code.  Also add his
+       set_special/unset_special code, the noflags changes for gencpu,
+       and a fix for cpuopti's string matching.
+       Tiny clarification in table68k.
+       Add 68040 support from Basilisk.
+       readcpu.h is now included from newcpu.h.
+9A0824 Rather massive overhaul of the DDF code.  Many other timing fixes
+       (copper state machine mostly) (Sam Jordan and myself)
+       Get rid of stupid optimizations in color recording.
+       Synchronize CPU and copper in custom_wget.
+9A0816 Introduce variable "special_mem", set it in each memory handler
+       that doesn't work on real memory (Bernd Meyer).
+9A0815 Fix a really stupid bug in cfgfile_strval.
+       Nonfunctional support for switching between windowed/fullscreen modes
+       in gtkui.
+       Add (semi-broken) support in the debugger to create a trace logfile.
+       Take out most port-specific flags handling; x86 version kept with
+       slight name changes to indicate that this is code is suitable for
+       other ports as well.  Took out HAVE_GAS while I was in configure.
+9A0811 Fix the line doubling slowdown.
+9A0809 Software autofire.
+       Remove one line from Makefile.in in the hope it will fix the build
+       errors people are seeing.
+9A0807 Tighten up some minor aspects of spcflags handling.
+       Fix an AGA bug in customreset.
+       Set default CPU speed to approximate a A500.  Tweak gencpu so that the
+       timings for this are more accurate.
+       Ignore T0 bit if not emulating a 68020.
+       Add an option to set the number of emulated floppy drives.
+       Improve the mfmcode function a bit.  Faster and more accurate.
+       More SCSI patches from Patrick.
+       Add gui_data structure from WinUAE.  Turn on gui leds again.        
+9A0725 Fix incorrect define of m68k_run for non-x86 systems (could have
+       sworn I already fixed that).
+9A0723 Some SCSI patches by Patrick Ohly (which I got two months ago... oops)
+       Filesystem fixes from Brian.
+       AGA updates from Toni.
+9A0627 Apydia loader fixes from Toni.
+9A0611 Fix bug in filesys.c causing in-use ainos to get discarded.  Thanks
+       to Brian for the analysis.
+9A0608 Added some disk.c changes from Toni and a crude hack of my own to
+       speed up disk accesses done by the Kickstart.
+9A0330 Change blitter not to translate memory addresses to native.  Had to
+       disable 32 bit blits.
+       Floppy code changes (Toni Wilen)
+       Delete GGI port.
+       Fix toggle_inhibit_frame (Brian).
+9A0228 Some WARPUP fixes, and changes to accomodate broken Amiga gzip (Sam
+       Jordan).
+9A0221 Tweak POTGO a bit.  Seems to work with BC Kid now.
+9A0220 Fix off-by-one errors in expansion.c (Toni Wilen).
+       Remove AGA checks in DDFSTRT/DDFSTOP (Toni Wilen).
+       Turn off/restrict some warning messages.
+9A0209 Fix some problems where the blitter nasty flag wouldn't ever get reset.
+       cia.c: Set all parallel port related bits to 1 when reading.
+9A0208 gencpu.c: Fix saved PC for division by zero exception (found by Sam
+       Jordan).
+9A0131 update_copper: Mask until_hpos properly.
+       Delay values are masked to 3 bit in hires mode (Sam Jordan).
+9A0102 Only delay horizontal copper wait if vertical position matches exactly.
+       Tweak vblank end position for sprites.
+       Calculate playfield borders more accurately for case where we have
+       sprites.
+9A0101 Reintroduce ev_copper; use it sparingly for longer waits within a
+       single line (but _not_ to time reads).
+       Fix a dumb bug in yesterday's changes that screwed up scrolling.
+991231 drawing.c: Cruftectomy.  genp2c.c: Gone.  X86.S: mostly gone.
+991229 Always use NTSC vblank_lastline for sprite purposes.
+       Make sprite logic recognize vertical stop even if vertical start has
+       not been reached (found by Sam Jordan).
+       Prevent move2c/movec2 instructions from incrementing the PC if they
+       raise an illegal instruction exception (found by Toni Wilen).
+991212 ncurses port compiles again.
+       Disable serial interrupts in custom.c; they break things.
+991208 Add a missing decide_line call in update_copper_1.
+991206 Fix copper emulation to use state machine figured out by Sam Jordan.
+991205 Fix event table corruption in disksync_handler.
+991113 gencpu.c: Fix a problem with BTST.
+991110 fpp.c: Initial set of changes merging code from Lauri Pesonen.
+991024 Add missing type in m68k_run1.
+       Divisions by zero clear overflow bit.
+991023 Fix compilation problem for ! HAVE_STEREO_SUPPORT.
+991022 Rewrite disk read code to transfer some DMA words every raster line.
+       fpp_movem_index1 and fpp_movem_index2 were reversed (Brian King, Sam
+       Jordan).
+       Fix accuracy of fpp fix insns (Sam Jordan).
+       Allow ports to define their own FP 68881/host conversion functions (Sam
+       Jordan).
+       Get rid of all the HAVE_GET_WORD_UNSWAPPED code.
+       Fix prefetch for insn opcodes (Sam Jordan).
+       Fix call insn syntax in X86.S.
+       Tidy up sound interpolation support.
+       Readd old command line arg parsing.
+       Change "long unsigned int" to "unsigned long" in a couple of places.
+       Use Sam's version of the filesys.c fixes (action_parent_fh,
+       action_change_mode).
+       Fix a place in disk.c where a mfm buffer was zeroed instead of 0xaa'ed
+       (Sam Jordan).
+991006 CPU emulator fixes by Christian Bauer
+       tui.c compilation fixes by Christof Petig.
+       Fix operand in one insn in X86.S (Brian).
+       zfile.c fix for filenames with embedded spaces (Ingo Ruhnke).
+       linux-ppc configury patch (Holger Jakob).
+       s,static __inline__,STATIC_INLINE, (Sam Jordan).
+       cfgfile.c: Don't use "t" modifier in fopen (Sam Jordan).
+       serial.c: Don't close file if fd < 0 (Sam Jordan).
+       filesys.c: Open files on readonly devices with O_RDONLY (Sam Jordan).
+       Fix bugs in parent_fh and change_mode actions (Sam Jordan).
+       WARPUP patch (Sam Jordan).
+990621 Initial version of Richard Hoffmann's sound interpolation patches.
+       Fix a crash in action_set_comment.
+       De-inline 68k trace code.
+990508 Fix rdtsc asm statement to show that edx is clobbered.
+       gtkui.c: Add pause button (Patrick Ohly)
+       configure.in: Check for -mpreferred-stack-boundary compiler option
+       and use it if found to set a sane value.
+990429 X11 patches by Patrick Ohly.
+       Filesystem code extended to keep a simple database with information
+       about each file that is not representable on the host FS, such as
+       script/pure bits or filenotes.
+990417 Bits and pieces merged from the Win32 port; mostly options stuff. Got
+       rid of getopt; added chipset options to prefs structure.
+990411 Patches by Patrick Ohly: SCSI support and timehack tool.
+990410 Applied easy parts of Toni's latest AGA patches.
+990315 Attempts to fix Picasso crashes in SVGAlib version.
+990216 picasso96.c: Some optimizations.
+       cfgfile.c: Save target specific options. Allow simple/smart choice
+       for centering options. Delete mount_data junk, substitute immediately.
+       Whitespace handling fixes.  Fix config_description typo.
+       m68k flag handling redone.
+990212 Implement rotate instructions without loops.  Some other m68k
+       optimizations.
+       Some configure.in fixes.
+990122 gtkui.c: Fixes for gtk 1.1.13.
+990113 genp2c.c: Don't include custom.h.
+990109 Some fixes in cfgfile.c.  Make svga.c compile again.
+981229 Miscellaneous fixes in the new config file stuff.
+       In config files, allow 68ec020 as CPU type, and get rid of 24 bit
+       addressing option.
+       Make the get_disp_ea non-inline.
+       SGI sound support (Ari Heikkinen).
+       More updates by Brian:
+       audio.c: Handle frequency, too, when changing sound prefs. Do some
+       work in update_audio even if not generating sound output.
+       filesys.c: Request 50 buffers in our parampacket.
+       Assorted right control key fixes.
+       Some updates in od-win32 (not nearly done...)
+981228 Config file and option handling redone; based on work by Brian.
+       Rename UAEn: devices to DHn: (Brian).
+       filesys.c: Implement ACTION_CHANGE_MODE, ACTION_PARENT_FH; add support
+       for variable hardfile blocksizes (Brian).
+       Some Picasso96 updates (Brian).
+981226 Win32 fsusage.c fixes; zfile bug fix; gui_fps addition (Brian).
+981221 Fix gtkui to work with newer versions of gtk.
+       Fix gencpu so that FPU emulation doesn't crash when unswapped word reads
+       are available.
+981129 gencpu.c: Delete all the queue_amode stuff again.
+       xwin.c: Allow switching between DGA and window mode (Marcus Sundberg).
+       DGA seems broken in X 3.3.3, however :(
+981011 Teach cpuopti.c about epilogues that increment esp by popping.
+980930 Add BSD socket code (Mathias Ortmann).
+980923 filesys.c: Implement FH_FROM_LOCK (Brian King)
+980823 xwin.c: French keyboard patch (Raphaël Poss).
+980810 Fix RDTSC detection (Raphaël Poss).
+       newcpu.c: Patch by Brian King to display what kind of CPU table is
+       built.
+980716 More AGA patches: use new macro GET_PLANES to calculate number of
+       bitplanes from BPLCON0; adapt the copper code; add BPLPT[HL][78] and
+       BPLDAT[78] (Toni Wilen)
+980715 Change sd-uss/sound.c not to keep a file open in setup_sound, to
+       support reconfiguration.
+980713 Fix m68k detection in configure.in. Clear execbase after allocating
+       chipmem (Holger Jakob)
+       od-dos update, tui.c patches (Gustavo Goedert)
+       Get rid of --enable-sound, always enable sound.
+       Make svga.c compilable.
+980712 md-ppc-gcc patches (Holger Jakob)
+980707 gtk ui: Better CPU speed selection.
+       Move initializations from add_filesys_unit to set_filesys_unit.
+980706 AGA patches by Toni Wilen: Call calcdiw when changing fmode; fix
+       references to bplcon variables to go through dp_for_drawing; ifdef out
+       some code that's too hard to fix for now.
+       "Fix" the AGA color code. In pfield_linetoscr_aga, add lframe_end and
+       diw_end parameters and use them. Add some fill_line code for AGA. Make
+       sure no code touches acolors if [AGA_CHIPSET != 0]
+       New function finish_line_aga.
+980705 drawing.c/custom.c: Get rid of line_changed, replace with a single
+       variable thisline_changed. Pass it to hsync_record_line_state and
+       evaluate it there. Get rid of BORDER_PREV and BORDER_NEXT states;
+       add LINE_BLACK/LINE_REMEMBERED_AS_BLACK to implement scanlines option.
+       Remove code in pfield_draw_line that checks line_changed.
+980702 filesys.c: New function move_filesys_unit.
+       Win32 GUI fixes.
+980701 gtk UI beautification and code cleanup (Michael Krause)
+       Beginning to make audio code run-time configurable (mostly by Michael
+       Krause)
+       Fix off-by-one errors in memory check handlers (Jake Hamby)
+       configure: Add AM_CYGWIN32, AM_EXEEXT and AM_MINGW32 and fix some Win32
+       configuration problems.
+       genp2c: Fix symbol name braindamage.
+       md-i386-{gcc,watcom}.c: Don't do machdep_init when [_WIN32].
+       Many Win32 compilation fixes.
+       filesys.c: Attempt to fix the mount code chaos.
+980629 MOVEP bug fixes (Philippe Gerin)
+       Comment out code using readdir_r again.
+980628 gencpu.c: Generate an end label only when it's needed.
+       configure.in: Check for windows.h, ddraw.h, sys/utime.h; check sizeof
+       __int64; check whether a small DirectX program compiles; check for
+       Watcom C; don't do GNOME_FILEUTILS_CHECKS when compiling on Win32
+       without GNU C; use AC_EGREP_CPP in some places instead of compiling a
+       file by hand; check for GAS .p2align feature; check for USE_UNDERSCORE
+       with a small test program; add code to set up od-win32/md-i386-watcom
+       directories when appropriate.
+       genp2c.c: Use GAS .p2align feature; don't generate .type directive.
+       Rename md-*/memory.h to md-*/maccess.h.
+       More fixes in Win32 code.
+       Add wcc.sh and wrc.sh, two scripts to make it possible to use the
+       Watcom C compiler and the resource compiler in a Cygwin32 build
+       environment.
+980626 Change zfile.c not to use fopen_del.
+980614 Delete ihf_sem stuff.
+       picasso_refresh now nonstatic and called by check_picasso after a
+       notice_screen_contents_lost call.
+       More functions to access filesystem mount information.
+       More Win32 code.
+980613 Use an AC_TRY_LINK block to check for libpthread.
+980611 Rename lockscr/unlockscr to gfx_{lock,unlock}_picasso and add new
+       functions lockscr/unlockscr which are now called by drawing.c.
+       xwin.c: Clear picasso_invalid_lines in graphics_subinit and when
+       doing an XPutImage for a refresh.
+       New function reset_all_systems, which is a bit misnamed at the moment
+       because it only resets the filesystem. Called from m68k_go when a
+       reset is needed.
+       In filesys_prepare_reset, examine unit_pipe instead of self to
+       determine whether a unit has a thread that needs to be killed. Move
+       the reset_state and reset_sync_sem variable to UnitInfo so they are
+       available at all times.
+       Don't need to call finish_drawing_frame if we do a reset, it was
+       done a couple of lines earlier.
+       In uae_reset, do nothing if any reset or quit operations are in
+       progress.
+       Make DMACONR static.
+980609 Add memory size fields in struct uae_prefs. New variables
+       allocated_xxxmem for every block of memory that holds the actual
+       amount currently allocated, copied from the preferences at allocation
+       time.
+       Create a new structure "uaedev_mount_info" to hold filesystem mount
+       information. Add a pointer to one of those in struct uae_options,
+       and copy it from currprefs to a filesystem private place when
+       starting the filesystem threads to a work area. 
+       Terminate filesystem threads during a reset, and restart the whole
+       filesystem code afterwards so that prefs changes are noticed.
+980608 If check_prefs_changed_gfx returns nonzero, or if we switch from/to
+       picasso mode, call notice_new_xcolors and notice_screen_contents_lost.
+       Delete the frame_do_semup crap.
+980606 Create config.h link in configure, not in Makefile.
+980604 xwin.c: No longer need picasso_max[wh]. Improve picasso invalid lines
+       code a bit more. Fix some dithering bugs.
+       gtkui.c (add_checkbox_widget, add_radio_widget): New helper functions.
+       Patches by Marcus Sundberg:
+       Make X11 picasso clut emulation mode work in DGA
+       gfxutil.c (setup_dither): Free redvals.
+980602 Split out init_aspect_maps from reset_drawing.
+       Call check_prefs_changed_gfx from vsync_handle_redraw, and initialize
+       row and aspect maps if it returns nonzero.
+       Use an enum instead of integer values to communicate between
+       hsync_handler and hsync_record_line_state.
+       gtkui.c: Use gtk_window_set_title (Marcus Sundberg)
+       xwin.h: Add lockscr/unlockscr prototypes.
+980601 Move check_prefs_changed_xxx into vsync_handle_redraw.
+       Make ersatz.c a little more crash-proof.
+980531 New graphics specs 'a' and 'p'. Support them in the X11 version.
+980530 sysdeps.h, posixemu.c: Change (char *) to (const char *) in the
+       arguments of some of the posixemu functions.
+       sysdeps.h: Delete getopt declaration. Include "getopt.h" in main.c.
+       aclocal.m4: add fsusage.c support from Gnome.
+       fsusage.[ch]: New files from fileutils, slightly modified to fit
+       into UAE and to add Win32 support. Adapt do_info filesys.c to use
+       it, and delete all the old cruft.
+       Some updates for the Win32 port.
+980529 Patches for X11 version by Marcus Sundberg (Picasso invalid lines
+       optimization, XShm availability check, cleanup, etc.)
+980528 Add field emergmem to struct vidbuf_description, and change
+       pfield_draw_line to use it.
+980516 Patches by Samuel Devulder and Holger Jakob: update Amiga port,
+       add support for compiling cpuemu.c in seveal steps again, add
+       cheatsearch in the debugger.
+980515 GGI patches (Christian Schmitt).
+       sd-mme: New directory (Marcus Sundberg).
+       Changes in the X11 version to support mixed DGA/normal binaries,
+       hotkeys, and mouse grabbing (Marcus Sundberg)
+       xwin.c: Copy a bit of code from Win32 port that constrains
+       lastmx/lastmy to real coordinates when ievent_alive.
+980510 gencpu.c: Slightly better flag generation code.
+       picasso96.c (wgfx_flushline): Don't do anything if Picasso screen
+       is invisible.
+980508 Don't disable GGI if we can't find svgalib.
+       newcpu.[ch], gencpu.c, md-i386-gcc/memory.h: Implement unswapped
+       word reads for opcodes.
+980505 drawing.c: add missing #ifdef X86_ASSEMBLY.
+980504 More BSD fixes from Krister.
+       xwin.c: Call XAllocColorCells for dithered modes. Don't set image_mem
+       in get_image, instead arrange for it to store the address in a pointer
+       chosen by the caller.
+       picasso96.h: Add a clut array to picasso_vidinfo.
+       picasso96.c (do_fillrect, do_blit): Use picasso_vidinfo.pixbytes
+       instead of picasso96_state.BytesPerPixel where appropriate.
+       (do_fillrect, do_blit, wgfx_do_flushline): Handle the case when the
+       Amiga-side buffer is a 256 color palette mode and the native buffer
+       is truecolor by looking up colors in the new picasso_vidinfo.clut.
+       xwin.c: Adapt to support emulating a palette display in truecolor.
+       Make tui.c compile.
+980501 picasso96.c: Make sure there's an unlockscr for every lockscr call.
+       In SetColorArray, detect when no colors changed.
+       configure.in, aclocal.m4, Makefile.in: Use AM_PATH_GTK from gtk
+       distribution.
+       New field rgbformat in picasso_vidinfo. Set it in xwin.c and svga.c.
+       custom.c (mousehack_helper): Use Picasso screen offsets correctly.
+980427 Call decide_line in DIWSTOP. Implement DIWHIGH register.
+980426 filesys.c (get_nname): Don't allow Unix "." and ".." directories.
+       gencpu.c: Approximate the number of cycles per instruction. Make
+       generated functions return that number, and use it in newcpu.c in
+       the do_cycles call.
+       custom.c, drawing.c: init_hardware_for_drawing_frame must be
+       called from init_drawing_frame.
+       Move read_processor_time specific stuff to new file md-xxx/rpt.h.
+       md-i386-gcc/support.c: Try to detect whether the CPU has RDTSC.
+       newcpu.c: m68k_speed == 0 means approximate A500 speed;
+       m68k-speed == -1 means use frame rate hack when available. Some
+       changes to support this.
+980425 custom.c: New copper code. Unfortunately not much faster than the
+       old one.
+       Get rid of some unused variables throughout.
+       filesys.c: Use readdir_r when available.
+       picasso96.c: In BlitPattern, correctly handle the pattern offsets.
+       missing.c: Get rid of getopt. Add GNU getopt instead.
+       In SPRxPTH, SPRxPTL, call decide_sprites instead of decide_line.
+980421 custom.c: Add an extra argument, hpos, to plenty of functions, and
+       use it instead of calling current_hpos.
+980420 BeOS update (Christian Bauer).
+       When enabling additional planes in post_decide_line, update
+       thisline_decision.bplcon0.
+       Tweak copper timings.
+980419 Extend post_decide_line to handle cases where some planes are
+       enabled much later in the line than the others.
+       In pfield_doline_unaligned_h, don't increment dataptr.
+       Split custom.c, move drawing code to new file drawing.c. New header
+       file drawing.h for declarations of shared stuff.
+       osemu.h: Delete junk.
+980418 gtkui.c: Don't crash if -G option is given.
+       audio.c, custom.c: Don't use the generic event handling mechanism
+       for audio emulation, the overhead is too high. update_audio: New
+       function, handles audio updates "on demand" or every hsync (Idea by
+       Petter Schau).
+980417 Some cleanups in custom.c to make splitting it up easier.
+980416 custom.c: Don't use bplhires in do_modulos.
+980415 readdisk.c: Support FFS (Jim Cooper).
+       BSD patches by Krister Walfridsson.
+       configure.in, Makefile.in: More fixes for build != source directory.
+       Arrange to build p2c_x86.o when using md-i386-gcc.
+       sysdeps.h: Include limits.h.
+       Remove silly code that restricted possible version numbers.
+980320 configure.in: Check for vprintf.
+       Make write_log a varargs function. Provide a write_log_standard
+       function that is used by most systems.
+       Refuse to compile with non-ANSI compilers.
+       gencpu.c: Rearrange some of the generated code to reduce register
+       pressure.
+
+Release 0.7.0
+980401 gengenblitter.c: Complete rewrite. Much smaller, much faster, much
+       better results.
+       Check for -lXi to support newer versions of gtk+.
+980316 gencpu.c (read_counts): Two silly bugs fixed.
+       main.c (save_options): Don't write out 'a' if cpu_level < 2
+       configure.in: Changes to try to be compatible with Solaris /bin/sh.
+980315 New UAE-Control version from Tauno & Cloanto.
+       Make configure set UNALIGNED_PROFITABLE for x86.
+       Get rid of "-o", add save command to tui.c and gtkui.c.
+       Fix some bugs in save_options.
+980314 Many improvements in the gtk UI. Made CPU type changeable at run-time.
+       Make DGA && ! VIDMODE configuration compile. Kludge around the fact
+       that DGA misses colormap changes. Call XWarpPointer to try to avoid
+       the click-moves-framebuffer bug.
+       Make sure p2c.[ch] don't get deleted.
+980313 Move all CPU_LEVEL handling from build68k.c to gencpu.c. In gencpu.c,
+       ignore all parameters and don't write to standard output, instead
+       hardcode all filenames and generate them all at once. Arrange to
+       generate code for all CPU emulator variants and to select them at
+       run-time.
+       Get rid of copper cheat mode, re-use "-C" option for CPU selection.
+980312 In COPxLCL, mask out LSB (Axel Wefers).
+       newcpu.h: Always compile in both get_disp_ea versions with a different
+       name. Delete USE_POINTER option; always use pointer. Don't fill
+       prefetch in m68k_setpc, do it in callers where necessary. Compile in
+       two versions of get_ixxxx, with different names for prefetch and
+       non-prefetch. Change gencpu.c to use these appropriately.
+       Don't generate 16 small CPU emulation source files. With a decent
+       machine it's no problem to compile all the code in one file. Also turn
+       off -O3 for gcc, -O2 does fine since all the necessary __inline__s are
+       there, and the compiler takes less memory that way.
+       Don't include <linux/joystick.h>, duplicate some definitions from
+       there instead. Makes configure.in simpler, too.
+       Fix Makefile.in/configure.in and a couple of other places to support
+       building in a separate directory (sort of; not complete yet).
+       Remove p2c.[ch] and genp2c when doing make clean.
+       Delete code to support Tcl/Tk and XForms GUIs.
+971215 More Amiga and BeOS patches from Sam and Christian.
+971205 Move some more code from custom.c to audio.c. Optimize sample handlers
+       a bit.
+       Make RDTSC asm statement volatile.
+971203 Latest GGI patch from Christian Schmitt.
+       Fix configure to enable zfile decompression for GGI target.
+       Fix mouse button mapping in ggi.c.
+971128 Fix double definition of gfxvidinfo in custom.c.
+       Fix impossible register constraints in asm statement in newcpu.c
+       Sprinkle casts and rename some variables to make C++ compilers happy.
+       Add BeOS patches by Christian Bauer.
+971125 More Amiga patches from Sam.
+971120 Get rid of DONT_WANT_SOUND.
+971119 Support USS sound not only on Linux (Douglas Carmichael)
+       Update Win32 and DOS ports.
+       Add Polish documentation by Tomasz Sienicki.
+971116 Add a missing return statement in filesys.c (Brian King)
+971112 Fix silly error in xwin.c.
+971108 Add some more decompressors to zfile.c. Set FLOPPY_SPEED to 4.
+971107 Make ggi.c compile again, fix a few bugs and add Picasso support.
+971106 Fill prefetch queue after executing an encrypted ROM illegal insn.
+971105 Initialize the sprites during customreset now that init_hardware_frame
+       no longer does it.
+971104 Implement action_set_file_size as required by the specs.
+       SetPanning/picasso96_state: XOffset and YOffset are signed.
+971103 xwin.c: Offer 640x512 and 320x256 resolutions in windowed Picasso mode.
+       Add a few more memory banks in memory.c (A3000 stuff - nonfunctional)
+       Don't map kickmem at address 0 if using replacement Kickstart.
+       Must fill prefetch buffer when calling calltraps or ersatz functions.
+       Write out hardfile parameters in write_filesys_config().
+       xwin.c: Support 15 bit displays.
+971101 Add latest patches by Samuel Devulder. Improve hardfile support in
+       tui.c.
+971031 Offer "-U" only ifdef PICASSO96.
+       Add support for mounting multiple hardfiles in any order.
+       Don't reset sprite state in init_hardware_frame. Instead, allow SPRxPT
+       functions to set the state to SPR_restart in the vertical blanking
+       area.
+971030 Fix 8MB Chip RAM.
+       filesys_dev_storeinfo: New function and calltrap. Use it to store
+       per-unit data (which now includes geometry information) in the
+       parampacket. Modify filesys.asm to use it instead of trying to find
+       the values by itself.
+971028 "AMIROMTYPE1" has 11 characters, not 0.
+971027 Implement encrypted ROM features. Comment out non-working InvertRect
+       optimization.
+971026 Fix some problems in PlanarToDirect and CopyColorIndexMappingA2U.
+971022 Remove fixed paths in genp2c.c (oops...)
+       Some more XF86VidMode hacks.
+       Include target.h in sysdeps.h. Define PICASSO96_SUPPORTED for X11,
+       SVGAlib and Win32. Don't compile in Picasso support if this macro isn't
+       defined.
+971021 xwin.c: Picasso code wants to use bit_unit, not bitdepth. Also correct
+       byteorder (it's B8G8R8A8 from the Amiga's point of view).
+       Fix Picasso InvertRect function.
+       Half-hearted attempt at 24 bit support in the X11 version, with some
+       awful code in custom.c.
+       Make the X11/VidMode version try to resize the screen for Picasso mode
+       switches.
+971020 Delete option -5, make -4 take an argument. Disable z3fastmem and
+       Picasso emulation when using a 24 bit address space.
+971019 record_color_change: No need to remember a color table if the current
+       line hasn't been decided yet.
+       Add XF86VidMode extension support.
+       Integrate Stefan's Zorro III support, add support for up to 64MB fast.
+       xwin.c: Refresh the whole Picasso screen if there are Expose events.
+       Fix module length calculation for *Tracker modules.
+       Use a 32 bit address space by default if CPU_LEVEL > 1. New option -5.
+971018 Apparently it's not possible to turn on bitplane DMA in the middle of
+       the line, so call post_decide_line only when the number of planes is
+       modified, not in DMACON.
+       genp2c.c: New file, generates planar to chunky conversion routines.
+       Remove those which are now generated from custom.c.
+971017 Make row_map an array, not a pointer to one.
+       Audio periods may not be 0, so initialize them to 65535 in customreset.
+       Implement "S" command in the debugger. Add a bunch of module detection
+       routines.
+971015 od-linux/sound.c: If FRAME_RATE_HACK, reduce vsynctime a bit to give
+       the sound emulation more room to breathe.
+971013 Merge with Brian's latest Picasso code.
+971012 Fix a few more portability problems that showed up when compiling with
+       Watcom C. Also remove superfluous includes from some files.
+       Add md-i386-watcom directory. Update od-win32 with latest code.
+       Remove fast_memcmp routine.
+       Include penguin.h before xwin.h everywhere. Declare a few semaphores
+       for multithreaded setups in xwin.h. Move inhibit_frame stuff to xwin.h.
+971011 gencpu.c: Don't generate labels without following statement. Don't
+       directly generate assembly statements if X86_ASSEMBLY, instead generate
+       code that uses macros defined in machdep/m68k.h.
+971008 xwin.c, svga.c, custom.c, uaelib.c: Add picasso96 code. Add Picasso
+       selection to configure.
+       Move common variables (mouse stuff, gfxvidinfo, xcolors) from graphics
+       files to custom.c.
+       memory.c: custom chip area isn't supposed to be mapped at 0x200000. Use
+       dummy bank for now.
+       od-linux/joystick.c: Open different devices for different joysticks.
+       From Win32 sources: set vsyncmintime in m68k_go.
+971005 genblitter.c: blitzero is initialized to 1, not to 0, so we need to
+       clear, not set it.
+970928 Add another user interface for X11 using libgtk+.
+970925 audio.c: For stereo sound, double all lookup table values.
+       Added (preliminary) win32.c.
+970923 DISK_check_change: Should call gui_filename when ejecting.
+970922 Fix od-linux/joystick.c compilation problem with recent kernels.
+       Merge results of the UAE meeting:
+       New serial code (Stefan Reinauer)
+       Expansion "test card" support (Stefan Reinauer)
+       New GGI code (Christian Schmitt), also configure/Makefile changes
+       to make it compile.
+       Fix 68020/FPU code.
+       Call do_mousehack before every read of the mouse position to get more
+       accurate values.
+       Add sd-file directory; add support for it in configure.
+       Add stereo support in audio.c, od-linux/sound.[ch], and main.c.
+       Fix copper problem: call decide_line in calc_copcomp_true; and if the
+       copper wouldn't wait normally (position reached), but the hardware is
+       fetching data in Hires 4 plane mode, delay until ddf stop.
+       t-ascii.h: Asciiart target understands "-x" parameter.
+970823 gencpu.c [X86_ASSEMBLY]: Turn input constraints for scratch into output
+       constraints.
+970626 Fix 24 bit address space logic (Mathias Ortmann).
+       Raise exception 3 for Bcc.L insns if CPU_LEVEL < 1. Reported by Stefan
+       Ropke.
+       Remove USER_PROGRAMS_BEHAVE for normal emulator. Remove hacks to
+       generate expanded CPU functions for specific opcodes. Replace with code
+       that reads an instruction count file and sorts gencpu output by
+       frequency of the called opcodes.
+970625 Calltraps (at least those with call_m68k calls in them) were broken by
+       the CPU emulator changes. Now use Axxx opcodes as calltraps.
+       Include pOS port by Samuel Devulder.
+970624 Solaris sound patches by Manfred Thole.
+       gencpu.c: The generated code shouldn't just check for odd addresses,
+       it should also call Exception...
+970622 gencpu.c: don't emit return statements; make code jump to a function
+       end label instead. Make genamode() check for odd addresses, also reduce
+       code duplication. Interpret getv parameter so that data is fetched if
+       getv == 1, and the address is checked if getv != 0. Remove exception 3
+       checks from get_long() etc. Get rid of buserr.
+       cpuopti.c: Make a few more checks whether optimization is possible. Add
+       code to undo GCC's epilogue scheduling.
+       newcpu.c: Split all the specialflag handling into new function.
+       Implement -w option as in Win32 port. tui.c: add it to misc menu.
+907621 Fix yesterday's CPU emulator changes. Make cpuopti aware of functions
+       with two RET insns. Make sure that NO_EXCEPTION_3 and
+       NO_PREFETCH_BUFFER are on when emulating a 68020.
+       Add usage information for src/dst operands to table68k.
+       Implement CIA A OVL bit properly.
+970620 New NeXTwin.m from Ian. Fix a number of prefetch bugs in gencpu.c.
+       newcpu.h: m68k_incpc(), get_i{byte,word,long}: New function/macros.
+       Also add oldpc parameter to m68k_do_[bj]sr(). gencpu.c: use all this.
+       CPU functions now don't use nextiword; they keep the PC constant and
+       increment it with the right value at the end.
+       If chipmem_size > 2MB, disable fastmem.
+       In configure.in and od-linux/joystick.c, use ljoystick.h as name for
+       the replacement file for a broken <linux/joystick.h>
+       configure.in: Check for post-gcc-2.7.2 option "-mno-schedule-prologue"
+       and use it for compiling the optimized CPU files if it exists.
+970618 Rename hardfile.device to uaehf.device to avoid name clashes. Suggested
+       by George Nicolaidis.
+       Reimplement CPU prefetch by making gencpu aware of it so it generates
+       code that fetches data from the right places automatically. Also reduce
+       prefetch length to 4 bytes.
+970612 memory.h: Include osdep/memory.h. missing.c: implement xmalloc().
+       Throughout: use xmalloc instead of malloc.
+       Apply changes by Sam Devulder.
+970608 Fix ncurses.c so that it links. Fix configure so that it can be enabled
+       Get rid of spixstate by implementing a new sprite drawing method.
+970607 do_copper_cheat(): New function, Implement inaccurate, line-based
+       copper as an option (-C). calc_copcomp_true(): Fix possible hr 4 plane
+       bug (split the wait into several pieces in this mode).
+       Allow 0 bytes for fast and bogomem (to override .uaerc)
+970606 Fix some bugs in transdisk, and make it compile with SAS C (Joanne Dow)
+       Stupid compilation fixes: Get rid of "==" in shell scripts, check that
+       B300 and friends are defined in serial.c before using them.
+       Implement blitter prefetch. Fix silly typo in main.c that prevented
+       immediate blits.
+       init_ham_decoding(): new function, handles case where the first few
+       pixels of a HAM display are outside the window.
+970605 disk.c: Get rid of need_read. Save cylinder/track number for the data
+       in the MFM buffer for each drive. Force rereads on disk insert and
+       write operations. In drive_fill_bigbuf(), do nothing if saved data
+       matches current. Fix disk change logic: give the program time to read
+       the change bit a couple of times before inserting a new disk.
+       custom.c: Fix really subtle bug: when deciding a line as border,
+       plfstrt/plflinelen were not set up properly, which could confuse
+       post_decide_line(), and eventually there would be lines decided as
+       playfield with plfstrt == 0, plflinelen == -32 ==> Bang. A related
+       bug was that setting DDFSTRT to 0 would result in both plfstrt and
+       plfstop having value 0.
+       gfxutil.c: Fix bug that could cause color values to go out of bounds.
+       xwin.c, svga.c: When dithering, color values were not doubled properly.
+970604 filesys.c: when deleting an a_ino, remove it from hash table (Mathias
+       Ortmann). In do_find(), if creating a file failed and we didn't have
+       an a_ino before, call delete_aino on the one we created.
+       More configure changes: Add $X_PRE_LIBS and $X_EXTRA_LIBS in some
+       places. See if MIT-SHM support for X will compile and link. Always
+       compile it in if it will. Turn DONT_WANT_SHM and LOW_BANDWIDTH into
+       run-time options (-T, -L). Use single line buffer when dithering and
+       in low-bandwidth mode (but in all cases there's a full buffer for the
+       X image).
+       memory.c: Don't map in custom regs at 0x200000 if chipmem_size > 2MB.
+       Split up init_sound(): new function setup_sound(). Make "-B" accept
+       minimum and maximum values as in Gustavo's latest patch. Add code to
+       tui.c to support changing buffer size, number of bits and frequency.
+970603 If using compiler, define NO_EXCEPTION_3 and NO_PREFETCH_BUFFER.
+       (bugreport by Raphael Poss).
+       GGI support from Christian Schmitt/Stefan Reinauer. More serial patches
+       from Stefan. 3 button joystick patch from Mathias.
+       Add linemem field to gfxvidinfo, for systems that don't want to keep
+       a buffer of the full screen. Adjust custom.c to use it instead of
+       bufmem if it's not NULL (mostly by Mathias). svga.c, xwin.c: Use single
+       line buffer in some cases. xwin.c: If USE_DGA_EXTENSION, undef
+       LOW_BANDWIDTH. Move test of DONT_WANT_SHM after inclusion of config.h
+       Make configure.in a bit more structured.
+       Move colormodes array to main.c.
+970602 gfxlib.c: Start implementing layers workalike.
+       md-i386-gcc/support.c: Don't mix sleep and alarm. (Petter Schau)
+970601 Remove may_run_compiled. Print error and abort if m68k_go is called
+       twice.
+       Fix yesterdays bugfix in svga.c.
+       Change FRAME_RATE_HACK so it tries to average the times a bit.
+       Re-implement a call_m68k function in autoconf.c. The new version
+       works by doing some heavy setjmp/longjmp magic and switching stacks.
+       With this, it's even possible to call things that Wait(), so use
+       the new functionality in gfxlib.c to call LockLayer() in WritePixel().
+970531 Turn some inline functions in memory.h into macros. Get rid of
+       get_along and get_aword. Implement CIA A OVL bit.
+       main.c: Add missing close_sound() call.
+       Remove INTEL_FLAG_OPT, use X86_ASSEMBLY for everything.
+       tui.c/svgancui.c: Implement scrollable menus. Add code to select
+       video mode from a given list. Add "graphics_setup" call to graphics
+       specific files. Use it in svga.c to build a video mode menu.
+       Fix bug in svga.c that would crash non-linear modes.
+       disk.c needs to include gensound.h and sounddep/sound.h.
+       Fix bug in fuzzy_memset. In pfield_init_linetoscr, always adjust ddf
+       values if lores hack is being used.
+970530 Apply some patches by Samuel Devulder.
+970529 filesys.c: In "Houston, we have a problem" case, do not only delete
+       the oldest ExKey, but also use it instead of random memory for the
+       new one. Attempt to reduce the number of lost exkeys by allocating
+       them in action_examine_next instead of action_examine_object.
+       Initialize the "uniq" field of unit->rootnode.
+       Attempt to speed up sprite drawing loop.
+       Implement sprite<->sprite collisions.
+       Get rid of -Wtraditional.
+970524 New config option NO_PREFETCH_BUFFER. Emulate 16 byte prefetch if
+       unset.
+       For exception 3, the stack frame seems to be:
+       (saved SR).w, (faulting address).l, (faulting instruction).w, 0.w,
+       (pc at fault time).l. Make everything that could generate this fault
+       handle it properly. That got Cybernoid II working!
+970523 Makefile.in: Make sure $(DEBUGFLAGS) is used for CPU emulation files.
+       memory.c: Don't map chipmem at 0x200000, use custom chip bank for now.
+970507 configure.in: Mutate ac_cv_c_inline=no to ac_cv_c_inline=
+       Check for tcgetattr, <sys/termios.h>, cfmakeraw, <sys/ioctl.h>
+       Check for sem_init in -lposix4 (Marc Zimmermann)
+       serial.c, cia.c, cia.h, serial.c: changes (Stefan Reinauer)
+       Make disk gap 360 (Michael Krause)
+970404 In configure, check for features.h before including it in test program.
+970401 New option -4. Bugreport by Mirko Viviani.
+970324 Petter Schau says the exception frame for Bus Error and Address Error
+       is 14 bytes, not 6, on the 68000. Change Exception() accordingly.
+       It's *** OUCH *** day! Make hardfile beginio return the correct value. 
+       Also load execbase before calling ReplyMsg().
+       It's *** OUCH *** day again! The filesystem asm code was an odd number
+       of bytes, leaving the hardfile code unaligned.
+970318 custom.c: Rename spron to sprst, and use new variable spron to indicate
+       for which sprites the sprite pointer registers have been written. Don't
+       do sprite DMA if spron==0. (The problem was that some programs write
+       SPRxCTL and then SPRxPT, which used to set the sprite state to
+       SPR_restart, but it must be SPR_waiting_start.)
+       Turn a few m68k_reset()s into uae_reset()s.
+       New variable nr_joysticks. Delete joystickpresent. New arg "nr" for
+       getjoystate() and read_joystick().
+       New extra keycode AK_RCTRL. Handle multiple joysticks & different key
+       replacements in keybuf.c/custom.c. Make tui.c handle all the settings.
+970310 od-linux/joystick.c now compiles again without the joystick header.
+       Fix some problems in configure; also check whether [n]curses.h defines
+       attr_t. Keep count of warnings and errors during configuration and
+       print a hopefully helpful message at the end.
+       disk.c sanitized by Mathias Ortmann.
+       Change the replacement getopt around a bit.
+       execlib.c, timerdev.c: Files removed. This will never be compatible
+       enough. Also remove related code (several SPCFLAGs, etc.)
+       Make main.c a bit nicer by introducing additional defines for the t-*
+       files. Also canonicalize the .uaerc file on all systems, eliminating
+       lines starting with '#' in the process.
+       Remove code in autoconf.c to set up 8MB chip; move it to filesys.asm.
+       Try doing the copper end-of-line hack in copper_memory_cycles().
+       Disable the copper speedup hack.
+970309 Add a small, dumb hash table to struct _unit to speed up repeated
+       aino lookups. Delete aino in action_delete_object(). Move children in
+       action_rename_object(). In action_examine_next(), call new function
+       lookup_child_aino_for_exnext() which behaves more or less like
+       lookup_child_aino(), except it uses new function get_aname() to
+       translate filenames.
+       More portability fixes. New links set up in configure: sounddep,
+       target.h. All machine-dependent and joystick code removed
+       from os.c, renamed to audio.c. os.h renamed to audio.h, joystick stuff
+       moved to joystick.h. New directory targets/.
+       missing.c: New file.
+970308 Rewrite filesystem. Now it keeps one unique "a_inode" structure for
+       every object in the filesystem. This contains Amiga name, native
+       name, Amiga permissions, lock counts and several links for building
+       a tree structure. Keys are now made only for files which need a fd
+       and a file position.
+       Treat invalid locking modes als shared.
+       Comment out the code using readdir_r because that function appears
+       to be broken in glibc-2.0.1.
+       Clear RES2 in all packets before handling them.
+       Give mousehack the same task priority as the input.device.
+       Fix (?) some silly bugs in disk.c.
+970307 Include some Acorn port code from Peter Teichmann.
+       Yet Another Serial Diff from Stefan.
+970306 filesys.c: Don't just crash if lookup_key() has no success.
+       action_find_write() is supposed to create the file if it does not
+       exist.
+970305 More DOS patches. Make the Makefile parallel-make safe.
+       svgancui.c: Do cyclic search if character is typed in file selector.
+       my_alphasort(): New function (work around glibc bug)
+       custom.c: Fix error in yesterdays change.
+       filesys.h: New file.
+970304 New serial patch from Stefan and Christian.
+       Remove the assembler code to generate inputevents. Instead, add a new
+       Amiga C program ("mousehack") which does the trick. New function
+       mousehack_helper() in custom.c, activated by calltrap 0xF0FF70.
+       Mouse default is now always normal_mouse, not follow_mouse.
+       Do disk change checks only every 1/2 second. disk.c: Reverse
+       nodskchange to dskchange, and make sure there has been a step with the
+       drive empty before calling drive_insert() from DISK_check_change() (but
+       this _still_ doesn't work. Arrrghh).
+970303 filesys.c: Initialize _all_ of struct _unit in startup_handler().
+       Remove message_lock and friends and use new variables cmds_sent,
+       cmds_acked and cmds_completed to determine when to send dummy messages.
+       Changed examinekey handling so that "dir all" on a large tree doesn't
+       crash anymore (it used to reuse the top-level exkeys which were still
+       in use after a wraparound). Don't allocate examinekeys if we're
+       examining files.
+       Check for readdir_r in configure. Use a wrapper my_readdir() around
+       either readdir or readdir_r.
+       Call filesys_reset() also from filesys_diagentry().
+       Get rid of most of uaelib.c. Now there isn't a library, just a calltrap
+       at 0xF0FF60. Changed uae_pragmas.h accordingly and recompiled uaectrl.
+       Added a bunch of "volatile"s in various places in filesys.c and
+       penguin.h.
+       Make the filesystem reset-safe in the threaded case (paranoia changes).
+       Check disk changes only every 1/10 second in vsync_handler().
+       Add assembler code to generate InputEvents once every vblank to
+       filesys.asm. (Doesn't work yet.)
+970302 filesys.c: Get rid of DosPacket type, pass pointers into Amiga memory
+       instead. Use GET_PCK_* and PUT_PCK_* macros to access fields.
+       Start making filesystem code thread safe & multithreaded. Move static
+       variables from some functions into struct _unit, likewise the key
+       and exkey variables. Add code to filesys.asm to queue commands which
+       did not complete and to reply to them later. Do multithreading if
+       compiled with SUPPORT_THREADS. See source for details.
+       Change hardfile and uaelib code not to call 68k routines. Make emulator
+       traps more efficient (no need to save regs, don't need SPCFLAG_EMULTRAP
+       anymore).
+970301 Fixed ncurses.c so it works with currprefs.
+       filesys_reset(): New function, called from customreset().
+       Changed source layout. Break up machdep into machdep, osdep and
+       threaddep.
+       penguin.h: Now supports arbitrary types in pipes.
+       Changed filesys.c so that no 68k code is called from native C code.
+         filesys.asm, filesys.sh: New files. filesys.asm contains some
+        startup code and the main loop for the filesystem. Several locks
+        are allocated by the assembler code for use by the C code.
+        DOS_AllocMem(), DOS_FreeMem(), make_dev(), build_parmpacket(),
+        filesys_init(): Functions removed.
+970228 ncurses.c: Fix problem in b/w modes.
+       finish_drawing_frame(): Don't need to draw lines in multipenguin mode.
+       Move all options into new struct uae_prefs. New variables currprefs,
+       changed_prefs.
+       svgancui.c, tui_filereq(): If user presses a key, start search at
+       current position, not at the beginning.
+       DISK_check_change(): new function, compares currprefs with
+       changed_prefs and handles diskchanges if they differ. Called from
+       vsync_handler().
+       DISK_validate_filename(): new function, checks whether a file exists.
+       Modify svga.c and tui.c so that F11 now brings up a limited UI.
+970227 Reimplement Mathias Ortmann's frame rate hack: New option HAVE_RDTSC
+       in config.h. New typedef frame_time_t. New variables vsynctime and
+       vsyncmintime. New function machdep_init() in md-*/support.c which
+       sets up vsynctime in the md-i386-gcc and md-i386-linux cases. Use
+       all of those in events.h, do_cycles() to determine whether to spend
+       more time on the CPU emulation.
+       Add missing "int i;" to xwin.c, init_colors().
+       Unroll some loops in sample_*handler().
+       Improve quitting/resetting behaviour: Move quit_program from GUI
+       specific files to main.c. New functions uae_reset() and uae_quit(),
+       quit_program is now handled in vsync_handler() and m68k_go().
+       New variable sample_evtime, used in customreset() and set up in
+       init_sound().
+970226 Solaris sound update from Manfred Thole.
+       keybuf.c: Decided that it doesn't need locking after all.
+       Add a bunch of Gustavo's latest diffs. (I hate CR characters!)
+       Move gfxvidinfo from all the target-specific files to custom.c
+       More Win32 stuff: New function notice_new_xcolors().
+970225 configure.in: In shell string comparisons, always put spaces around =
+       Add warning about standard SVGAlib being incompatible with
+       LinuxThreads.
+       os.c, SOLARIS_SOUND: Remove reference to obsolete variable smplcnt.
+       Two new variables sound8_base and sound16_base.
+       sysdeps.h: Split off some stuff into md-amiga/amiga-kludges.h. Also
+       make the main types now uae_u32 and variants instead of ULONG, etc.
+       Convert some files to use the new types.
+       cia.c: use int/long instead of ULONG/UWORD/etc for most static vars.
+       xdebug.c: Some cleanup.
+       md-i386-linux/penguin.h: Fix bug. Add "chunks" parameter to
+       init_comm_pipe. Use it to decide in write routine whether to signal
+       the other thread if it's waiting. Add no_buffer parameter to
+       write_comm_pipe_int.
+       Start adding Mathias Ortmann's Win32 patches.
+         md-i386-win32: New directory
+        include/sysconfig.h.win32: New file
+        custom.c: is_lastline: new variable, set in hsync_handler().
+        sysdeps.h: Make it possible for system specific code to say that
+          POSIX/ANSI stdio/malloc functions aren't present and are defined
+          by a system-specific file instead. In filesys.c, don't reference
+          errno if DONT_HAVE_POSIX is defined.
+        readcpu.h: Kludge around the fact that Messysoft C apparently doesn't
+          handle enums properly.
+        newcpu.c/sysdeps.h: Preprocessor magic for 64 bit constants to get
+          around a problem with MS C.
+        md-*/penguin.h: Add dummy definitions for semaphores.
+        keybuf.c: Use semaphores to synchronize access.
+        os.c, win32 sound stuff: add memcpy avoidance code.
+970221 X86.S: Don't use .type ifdef USE_UNDERSCORE.
+       Move thread support configuration to configure from config.h. Change
+       pipe implementation to use POSIX semaphore functions.
+970217 From Samuel Devulder: Fix off-by-one error in LINE_TO_SCR, EHB case.
+970215 customreset(): Initialize current_colors.color_regs to invalid values
+       [reported by Samuel Devulder]. config.h: Uncomment ECS_DENISE [reported
+       by Mathias Ortmann]. Add ami-win.c and custom.c patch from Samuel
+       Devulder.
+970213 disk.c: Set FLOPPY_SPEED to 3
+       custom.c: SPRxCTL_1(): if spron was SPR_restart set it to
+       SPR_waiting_start. do_sprites(): don't do that.
+       SPRxPT{H,L}: Call decide_line().
+970210 custom.c, X86.S: Do LORES_HACK for dual playfield screens. Plug memory
+       leak in custom_reset(). Fix pfield_draw_line() not to do so many
+       multiplications. Make line_changed a char array. In remember_ctable(),
+       remember comparison results also if negative.
+       In 8 and 16 bit graphics modes, use the high parts of the color values
+       to duplicate the actual values. This saves a lot of code in the
+       hdoubling routines. Add a special fill_line in the X86_ASSEMBLY case.
+       Check for glibc-2 and libpthread in configure.
+       options.h: In fuzzy_memset(), do rounding slightly more conservative.
+       Add tons of new keycodes to svga.c
+       In record_color_change(), also check if vertically outside DIW.
+       New variable hdiwstate, to represent the horizontal DIW state machine
+       (thanks Petter!) Handled in reset_decisions(), finish_decisions() and
+       decide_diw().
+970209 Change ncurses.c not to do so many multiplications/divisions. Add bold
+       character support. Add color support. Make configure recognize
+       --without-svgalib and enable ncurses.c in that case.
+970208 X86.S, custom.c: Do LORES_HACK for EHB screens also.
+       New function write_log(); convert some fprintf(stderr, ...) calls.
+970207 Argh, Linux/i386/ELF check in configure got broken by latest sh-utils.
+       In disk.c, drive_reset(), clear nodskchange flag.
+970206 Sprite fix from Mathias Ortmann: _really_ get rid of SPR_vtop, and
+       replace all uses by SPR_stop.
+970204 Disk change fix from Mathias Ortmann.
+970203 New file ncurses.c, from Samuel Devulder.
+       Disabled Exec stuff completely. Now it isn't even compiled in anymore.
+970129 Changes from Samuel Devulder for Amiga and Christian Bauer for BeBox.
+970122 Reorder the set_planes_unaligned functions so that better code is
+       generated. Remove the or_planes_unaligned functions, add a parameter
+       do_or to the set_planes functions and rely on the compiler to optimize
+       the additional if away.
+       post_decide_line() can now turn DMA off early.
+       Make struct flag_struct 64 bits large for i386 systems, so we can use
+       long move insns without clobbering the X flag.
+       "make clean" should delete machdep/support.o.
+       Maybe we do need SPR_vtop after all - undo 970120 change. Instead,
+       comment out the code that clears the pos and ctl words at vsync time.
+       In xwin.c, restrict window height to 300 or 600 depending on linedbl
+       mode.
+970121 Get rid of SPCFLAG_BLIT, call do_blitter() directly.
+       In finish_decisions(), don't check for sprite draws in the border.
+       Reimplement the SMART_UPDATE define so that the memcmpy() overhead can
+       be avoided by not setting it (but this usually loses).
+       Detect 7 lores planes in BPLCON0() and change to 6 to avoid memory
+       clobbers.
+       In pfield_draw_line(), do memcpy linedoubling after handling the line
+       to be doubled, not when we see a LINE_AS_PREVIOUS. Get rid of prev_ypos
+       parameter.
+       Add special code for bpldelay1 == bpldelay2 to the UNALIGNED_PROFITABLE
+       code.
+       In pfield_init_linetoscr(), when delays 1 and 2 differ, clear the areas
+       which are covered only by half of the planes at the start and end of
+       the DDF area.
+       Replace FASTER_CPU and LINUX_SOUND_SLOW_MACHINE with M68K_SPEED.
+       Replace fast_unaligned_memset macros with fuzzy_memset; use this also
+       in pfield_init_linetoscr().
+       Use real (PAL) vblank end in do_sprites().
+970120 Mask out high byte in DDF{STRT,STOP}
+       Oops, forgot about long frames while calculating the bounds of all the 
+       maxvpos*2-sized arrays. Increment them all by two.
+       Try to detect empty sprites before recording them for the drawing code,
+       but be careful not to hurt attached sprites.
+       From Paul Kienitz: hack for keyboard code in cia.c to work better with
+       newer Kickstarts; small cleanup in cpuopti.c.
+       Undo yesterday's change in copper_memory_cycles(), instead call
+       decide_line() each iteration and test whether copper_cycle_time == -1
+       to determine whether we're vertically in the DIW.
+       calculate_copper_cycle_time() could get astronomical plane counts due
+       to missing masking operation.
+       No need to put the copper to sleep for one memory cycle after a WAIT,
+       merge that with the two cycles for the next instruction.
+       Get rid of SPR_vtop, no longer needed (it was unnatural anyway)
+970119 Implemented alternate pfield_doline functions that access the apixels
+       array at unaligned addresses; conditional on UNALIGNED_PROFITABLE.
+       Move LORES_HACK from config.h to custom.c.
+       Fix loop exit test for pfield_linetoscr_hdouble_asm8(). Clear the
+       right parts of apixels in pfield_init_linetoscr() when LORES_HACK is
+       enabled.
+       Get rid of bordercol array: the decision-making code should handle
+       lines in the border correctly by setting line_changed.
+       Disable bitplane DMA if more than 4 hires bitplanes are set in BPLCON0.
+       Fix some more copper timing inaccuracies: used to test
+       thisline_decision.which without calling decide_line() before.
+970118 Now remember BPLCON1 changes during data fetch. New functions
+       decide_delay(), pfield_adjust_delay(); new fields in struct drawinfo
+       and new variables next_delay_change, delay_changes.
+       Forgot to set copstate to COP_morewait in one case in do_copper().
+       Add a kludge that checks for copper position 0xDC and changes it to 
+       0xDE.
+       Restore equality test for vertical sprite positions. Disable sprite
+       DMA before the end of the vertical blank area.
+       Mask not only the positions, but also comparison values in 
+       calc_copcomp_true().
+970117 Change custom_bput to put the byte value in each half of the word that
+       is put.
+970116 disk.c: Set the gap between sector 11 and 0 to 380 words. Andromeda's
+       "Seven Seas" demo expects at least 320. Make the KILLEHB bit
+       conditional on AGA_CHIPSET. Decide BPLCON1 (scrolling delays) in
+       decide_diw(). Fix off-by-one errors in the very_broken_program case
+       of decide_plane(). Fix aspect calculation when horizontal resolutions
+       differ. Simplify copper horizontal comparison logic slightly.
+       Fix divide by zero errors when reading from empty floppies.
+970115 pfield_draw_line(): Check for frame_redraw_necessary also for border
+       lines. New global variable pfield_last_drawn_line, used to implement
+       clever Y centering. Make the KILLEHB test conditional on ECS_AGNUS.
+       Move joystick and sound initialization before gui startup. Adapt tui.c
+       so it understands the gfx_requested_* options.
+       We can't always avoid clearing pixdata.apixels if DIW is larger than
+       DDF. There may be sprites in the area outside DDF, but inside the DIW,
+       so we can't just adjust linetoscr_diw_{start,end} blindly in
+       pfield_init_linetoscr() [Sanity Arte demo].
+970114 Bebox diffs from Christian Bauer.
+       Support for Symmetric Multi Penguins under Linux (start second thread
+       with clone and use some pipes for communication - rather simpleminded
+       for now). Rework do_flush_line() and do_flush_screen() so that X
+       libraries are only called from the first thread.
+       Eliminate valid field from struct decision (set which to -2 instead of
+       valid = 0)
+       Fix definition for gui_filename() in xdebug.c to use const char * for
+       the second parameter. Remove CRs from disk.c (now how did they get in
+       there??). Likewise for cpuopti.c.
+970113 When post_decide_line() detects mid-line DDF change, must adjust
+       bitplane pointers in decide_plane() also. Make plfstrt the earlier a
+       position in this case, and adjust bitplane pointers/modulos
+       accordingly.
+       current_hpos() isn't what GCC calls a constant function.
+       Replace line_drawinfo[current_change_set] with new variable
+       curr_drawinfo throughout. Likewise for new variables prev_drawinfo,
+       {curr,prev}_{color_{change,table}s,sprite_positions}; all initialized 
+       in init_drawing_frame (). Turn line_data into a 2dim. array, do some
+       CSE/SR on line_data[lineno] in pfield_doline_{l,h}() and
+       decide_plane(). Make some custom registers unsigned int instead of
+       UWORD.
+       calc_copcomp_true(): Masking with 0xF000 isn't likely to give 0xC0000.
+       Comment out bplcon{3,4} from struct decision.
+970112 filesys.c, action_set_protect(): if __unix is defined, check whether
+       user wants to change directory protection, and if so, force rwx to be
+       the new protection.
+       Force sane window sizes in xwin.c, and set width/height from mode specs
+       in svga.c.
+       Implement LORES_HACK compile-time option.
+       Whee, there _are_ broken programs that enable bitplane DMA in the
+       middle of the data fetch area, draw half a picture on the first line
+       and the full picture on all subsequent lines. New function
+       post_decide_line(), called from BPLCON0() and DMACON() which tries to
+       detect this case and turns the decision from border to playfield if
+       necessary.
+       New arrays, sprvstart and sprvstop, calculated in SPRxPOS and SPRxCTL,
+       and used by do_sprites. Handle sprites with vstart == vstop correctly.
+       Sprite vpos comparisons are now done with <= , not ==.
+       _Now_ the X86-specific linetoscr routines do their masking correctly.
+       configure: If we have GCC, #define GCCCONSTFUNC as __attribute__ 
+       ((const))
+970111 Eliminate can_draw from struct decision.
+       Change vertical DIW code; use enum of two states (waiting for start and
+       for stop) which is updated in decide_line(). Lines during the wait for
+       stop phase are decided as border. No data is fetched outside the
+       vertical DIW.
+       Optimize copper memory cycle calculation a little: the new variable
+       copper_cycle_time is set to a time >= 0 if this time is constant
+       (i.e. 2). Calculated whenever DMA, BPLCON0, or DIW state changes.
+       blitter.c, genblitter.c, custom.c: For BLTBDAT, follow the HRM which
+       says that immediate data is shifted as soon as it is written. This 
+       seems to be wrong for the A channel, though. Also, don't change prevb
+       during blitter loops if DMA B is off (Sanity Arte). Turn FAST_BLITTER
+       stuff into run-time option "-n", and eliminate the ancient blitting
+       code (former FAST_BLITTER == 0).
+       Big OOPS: Copper move checked copcon, but there was no COPCON function
+       so it was always zero -> copper-controlled blitter never worked. As a
+       speed optimization, recognize 00010000 copper commands and put the
+       copper to sleep until the blit is finished.
+       Slow down the blitter in decide_line() if bitplane DMA steals blitter/
+       copper/CPU cycles (but this code is commented out for now).
+970110 New function pfield_init_linetoscr(). Move calculation of diw_end and
+       diw_start values there from x86-specific code. Also use DDF values to
+       determine where data in pixdata.apixels is valid. The x86-specific
+       linetoscr routines now only do the alignment masking (and they now do
+       it correctly, too).
+       Got rid of the display-related contents of struct draw_info, make 
+       static variables and them initialize from pfield_draw_line() only when 
+       necessary in function pfield_expand_dp_bplcon (). Get rid of the four
+       saved_* arrays, remember line_drawinfo instead now that it's smaller.       
+       Color compare avoidance didn't work because color_src_match didn't get
+       set when a compare was successful. Fixed.
+       Reorder parts of the decision-making code so that less redundant checks
+       are performed.
+       Add clever x centering. Change "-O" option parameter format.
+       In md-i386-linux/support.c, memcmpy(), do memcmp() first, then switch
+       to a plain memcpy routine once we find the first difference.
+       Patches from Stefan Reinauer/Christian Schmitt for 
+       xdebug.c/configure.in
+       New uae-ui.tk from Volker Zota.
+       Add --enable-profiling to configure.in.
+       Check for period==0 in AUDxPER() was accidentally commented out -
+       revert.
+970109 Some tweaks in X86.S, plus a new option X86_PPRO_OPT to use movzbl
+       instead of xorl/movb when possible.
+       Fix maxline calculation in finish_drawing_frame().
+       Make next_lineno always a valid array index. Decrease minfirstline to
+       21 (NTSC vblank end). New option -O to specify display parameters,
+       supersedes -d and -C which will be removed eventually. Differentiate
+       between line doubling and aspect correction. Put aspect correction code
+       in custom.c.
+       Remove some more unused stuff from custom.c.
+       Fix Makefile problems when cpuopti isn't used.
+970108 use_lores isn't initialized before custom_init(), setup lores_frame and
+       friends in customreset(). Optimize spixstate clearing. Optimize border
+       drawing with copper color changes (use fill_line instead of linetoscr)
+       Fix the sprite DMA logic, it now works with the Interference demo.
+       Silly bug: Sprite 7 never got displayed (introduced sometime last week)
+       Implement USER_PROGRAMS_BEHAVE for normal (non-compiler) CPU emulation.
+       Add most of Gustavo's last patch (new dir md-i386-dos)
+970107 Finish rewriting most of the drawing code in custom.c/X86.S. See
+       README.PROGRAMMERS and source for details. Improvements include better
+       copper precision, better interlace support, hopefully much less bugs
+       and not too many new ones.
+       Remove calc_adjustment() and gfxvidinfo.x_adjust; replace with code in
+       custom.c that looks at gfxvidinfo.follow_diwstop (new field)
+       Some operations (like EHB playfields) now have a higher penalty than
+       before, the assumption being that these are rare and the normal case
+       runs faster if it doesn't have to care too much about exceptions.
+       Fix sign mismatch bug in BPL1MOD() and BPL2MOD().
+970104 Move x_ShowEA() from xdebug.c in newcpu.c, rename as ShowEA().
+970102 Add check for XK_W to decode_es() in xwin.c.
+       New uae-ui.tk from Volker Zota.
+961218 Add a patch by Bernie Solomon to overcome a problem with K&R compilers. 
+       Change X86.S in a way that may make it either faster or slower.
+       Fix ADF_EXT1.
+961217 #ifdef XK_dead_*, since Solaris doesn't have it.
+961202 Fixed joystick.h problem in configure. X11/DGA support from Kai
+       Kollmorgen.
+961117 Some fixes in svgancui.c.
+961112 Gustavo's latest patch, with GUS support for DOS by Michael Sontheimer.
+       Add menu browsing to tui.c/svgancui.c
+961107 Fix m68k_areg and m68k_dreg macros (put args in parentheses)
+       Initialize gfxvidinfo.maxlinetoscr in xwin.c (found by Sam Devulder)
+961104 svgancui.c tui_refresh() routine tweaked to work with the non-standard
+       ncurses that came with my new SuSE-Linux CD.
+961031 Added Christian Schmitt's xdebug.c (disabled for this release)
+961024 Module search function from Michael Krause.
+961019 Add Samuel Devulder's Amiga patches.
+961018 Don't use -lm on NeXTStep.
+961017 configure checks for -lforms.
+961016 Ian Stephenson's new NeXTwin.m. Make CLXDAT return 0 (no collisions)
+       transdisk and transrom patches from Rodney Hester. Don't warn about
+       256K Kickstarts. Check diskfile sizes and try to determine whether it's
+       a normal or a HD diskfile. No HD drive identification yet (is it
+       different?)
+961013 Corrected lots of bugs in the return address stack. Fix some errors in
+       the compiler memory management. Use the "locked" flag for hash entries
+       differently, and don't enforce it on a cache flush. Compile JMP to a
+       constant address.
+961012 Remove regs from cache before sign extending them for ADDA, MOVEA and
+       similar things. Compile NOPs to nothing. Implement variable shifts/
+       rotates. Most shifts clear the V flag: Handle this in the compiler by
+       some extra magic sequences after shifts or in the CC_AFTER_RO case in
+       flush_cc_cache().
+       Implement a stack containing return addresses and their hash entries,
+       and compile JSR (to constant addresses)/BSR/RTS instructions inline.
+961011 compiler.c: Several bugs introduced in the last two days fixed.
+       New function compile_note_modify() which is used when an ea is
+       modified. This replaces calls to storeea with eaino_s == eaino_d.
+       Bah, the 386 doesn't set flags on a NOT. Use CC_TEST_REG again.
+       Do flag life analysis until no more changes are found.
+       Make sure all "data" parts of EAs are locked exclusively (esp. for 
+       LEA, PEA)
+961010 compiler.c: Finish yesterdays changes. Get rid of reg/offset
+       bookkeeping in m68k_compile_block(), keep the information in struct
+       ea_info instead. Rewrite all instructions to use the new fetch and
+       store routines.
+       Don't force a byteorder conversion in sync_reg() if the reg doesn't need
+       to be written back. Don't do a SAHF or equivalent in compile_condbranch
+       if we are doing a BRA or BF.
+       Don't use CC_TEST_REG for NEG and NOT (this was inefficient for NOT and
+       wrong for NEG).
+961009 compiler.c: Two types of locks for registers; shared and exclusive.
+       Implement better EA fetching and storing routines. For pdi addressing
+       modes, lock the necessary registers shared before calling prepareea.
+       Unlock those registers again in generate_possible_exit().
+961008 MOVEM instructions in the compiler to an absolute address could have
+       caused random memory corruption.
+961007 Spanish keyboard support for X by Ruben Martinez. Some configure fixes
+       (don't assume current dir is in path, don't assume ncurses.h exists if
+       libncurses does).
+       If we're calling 68k code from an emulator function, don't use compiled
+       code.
+       Add a compilation option USER_PROGRAMS_BEHAVE (for compiler). Make
+       compiler hash table larger.
+961004 Fix typo in configure.in.
+       Modify the compiler so it doesn't ever throw away code, unless it's
+       necessary for a cache flush.
+       Didn't quite squash the compiler flag bug yesterday. Try again.
+       In filesys.c, do_find(), add a parameter fallback that indicates that
+       the open should be retried with O_RDONLY if it failed with O_RDWR.
+       Use this in find_input(). This fixes problems with r/o files on r/w
+       volumes.
+961003 Play around with the x86 specific memory access functions. Problem:
+       __attribute__((regparam)) isn't reliable, and it seems that that's a
+       rather hard to fix bug in GCC. Add some alternatives to
+       md-i386-linux/memory.h; these aren't used yet though.
+       Huh, the compiler was completely wrong about the flag needs of
+       conditional instructions. I wonder how it could work at all...
+       Remove a and d arrays from struct regstruct; replace with array regs
+       with 16 elements. This allows better code for get_disp_ea()
+961002 BeBox diffs from Christian Bauer. Move all code from main() to new
+       function real_main().
+961001 Use do_get_mem_*() functions for nextiword(), nextilong() and new
+       function nextibyte().
+960930 genblitter optimizations: Don't generate expressions in genblitter, use
+       a second program called gengenblitter to generate a table of
+       expressions for genblitter to use. gengenblitter knows about a lot of
+       rules to simplify expressions. Some other tweaks to make GCC output
+       better assembly for blitfunc.c.
+960927 Turn off LED() in xwin.c (may fix SunOS joystick emulation problems)
+       Call XFlush() and XSync() when exiting.
+       Add some DOS patches.
+       Add hooks in filesys.c to support filesystem units in a GUI. Use them
+       in tui.c. Bugfixes in svgancui.c. Change the way tui_refresh() works.
+       New option "-A".
+960925 For read-only filesystems (CD...), use O_RDONLY in action_find_input.
+960923 Save options file even if rename fails.
+       Mirror address space every 16MB like we used to (got turned off by
+       accident).
+       Move some checks out of options.h into configure. Set up md-*
+       directories with machine-dependent stuff in them; configure creates
+       a link called machdep to the appropriate one.
+960918 Solaris sound update from Manfred Thole.
+960917 Add a timer.device replacement (buggy).
+960916 Tristan Cavelier's french keyboard patch.
+       Apply ReadTheSpecsBeforeYouWrite(tm) technology to AddPort().
+       Implement RemPort(), GetCC().
+960915 Tighten up some of the return values in Exec.
+960914 EXEC: Implement RemTask(), ObtainSemaphoreList() and
+       ReleaseSemaphoreList(). Set up more fields of the ExecBase properly
+       and Enqueue it in the library list. Make InitResident call AddLibrary
+       when appropriate (otherwise, intuition is never put into the library
+       list). Fix major braino in Obtain/ReleaseSemaphore() (tried to Enqueue
+       tasks into two lists). Make OpenLibrary() honor the version parameter.
+960913 EXEC: Idle task now runs in user mode (abuse 0xFF0D as second STOP
+       instruction). Make EXEC_IntTrap perform the RTE before trying to
+       schedule.
+960912 Solaris sound didn't compile. So much for making blind changes without
+       being able to test them.
+960911 As soon as you compile it under Solaris, it bombs... Now check that the
+       hardfile exists before determining the size in main.c.
+       execlib fixes: Set master DMA enable bit at startup, fix interrupt
+       code to survive an interrupt that occurs before the proper SetIntVector
+       call. Implement RawDoFmt(), CloseDevice(), CloseLibrary(),
+       FindResident().
+960905 Lower 8 bits of POTGOR should be 0.
+960904 Implement MULU, MULS, ADDX and SUBX in compiler.
+960903 ncurses interface works. DOS people: please use the new portable tui.c
+       and turn dos-ui.c into a frontend for conio.h, similar to svgancui.c
+       In xui.c, unlink the temporary files ASAP.
+       Two new command-line options, "-o" and "-G".
+       Get rid of sz_unknown.
+       compiler.h, compiler.c: New files.
+       filesys.c, action_read(): Added a hack to test whether the first four
+       bytes read from a file a file contain 0x000003F3 (HUNK_HEADER), in
+       which case there's probably a LoadSeg() call going on and we ought to
+       flush the cache. Also, use the fact that memory is now linear.
+960902 Struggle a bit with dos-ui.c, rename it to tui.c (text-based ui), add
+       new file svgancui.c (ncurses ui) and try to make these two understand
+       each other.
+960829 New transdisk from Stefan Ropke (can write images)
+       Apply Patrick Hanevolds BeBox patches.
+96082x many changes to Exec. Still not booting (DMACON seems not to be set up
+       properly, and sometimes Signal is called with task==0).
+960821 Solaris sound from Manfred Thole.
+960820 In filesys.c, get_fileinfo(), return volume name for top-level 
+       directory.
+960819 Reimplement WritePixel(). Layer locking is still missing.
+960818 Reverse meaning of -x flag for X11. More Exec code.
+       Several changes to the main CPU loop and the way call traps work.
+960817 Implement some simple Exec functions (Lists, AllocMem & friends)
+960816 filesys.c fixes from David Varley.
+960815 Implement graphics library region functions.
+960814 Modify memory layout: All memory is linear now; get_real_address()
+       returns a (UBYTE *).
+960810 Add Gustavo's latest DOS code.
+       In configure, include <sys/param.h> earlier for the sake of some *BSD.
+       Add three options for sound code (bits, frequency, buffer size).
+       Make -S option take a parameter; remove SPEED_UP_SIDMON_MODULES.
+       New version of transrom (return 0, duh).
+960805 Fixed the blitter line mode emulation (this time, really! I hope.)
+       Thanks to Fabio Ciucci for a detailed description of the correct
+       behaviour.
+960730 Spent the last three days trying to make the filesystem emulation
+       bootable by adding an expansion device for it. A fair bit of trial and
+       error, but now it works! Even the hardfile now works with Kick 1.3, but
+       you have to mount it manually after booting.
+       hardfile.c, filesys.c, expansion.c and autoconf.c now are an
+       entangled mess which badly needs to be cleaned up.
+       We can now mount more than one filesystem even with Kick 1.3: we
+       recognize them by param 2 of the startup packet, which has the same
+       value as the dn_Startup field of the devicenode.
+       Make Kickstart replacement work again (didn't like the CPU emulator
+       changes)
+       Include preliminary serial support from Stefan Reinauer.
+960728 Fixed the scancodes for <> and #' keys in svga.c
+       Apparently, CIA timer latches ought to be 0xFFFF after a reset
+       (prevents Eagleplayer from crashing occasionally). #ifdeffed out a
+       slightly weird call to INTREQ from RethinkICRB()
+960727 Sound code rewritten again. Now uses events (five new ones). All 
+       modules seem to play correctly now. It's a bit slower, though.
+       AF sound should work again, patches from Marcus Sundberg.
+960723 ... and more CPU emulation bugs fixed by Herman.
+       Added uae.library from Tauno Taipaleenmaki, plus support files in the
+       "amiga" directory.
+       Added some files for the XFree86/OS2 port from Krister Bergman.
+       Reorganized all the directories.
+960717 Add latest patch from Herman.
+       More FAST_BLITTER options: 4 and 5. These finish the blit immediately.
+960713 Call XAutoRepeatXXX() only if we know we want to change the state.
+960709 Work around a few AIX bugs (ughhh... what a broken OS). New test for
+       sys/select.h.
+       In xui.c, don't try to communicate with a dead process.
+960704 More bugfixes from Herman.
+       Get rid of dummy_xlate(), use default_xlate() to abort with error.
+       In svga.c, set correct_aspect to 0 if using lores.
+       Change the Bcc exception 3 handling code a bit.
+       Add new program "cpuopti" that takes gcc-generated assembly files and
+       optimizes away unnecessary pushl/popl instructions on the x86.
+960701 68020 exception handling & various bugfixes from Herman ten Brugge.
+       In ersatz.c, use 0xFF0D instead of 0xF00D as trap opcode.
+       Do MMU "emulation" (no-op MMU instructions, probably many cases decoded
+       incorrectly).
+960627 New file LIESMICH, with minimal German instructions. Somebody want to
+       translate the docs to French, Spanish, Italian, all the Scandinavian
+       languages, Hebrew, Polish, Dutch, Russian, Welsh, Gaelic and something
+       Joe_Luser@aol.com understands? (No offense meant - I'm sure there are
+       brillant minds using AOL. There must be.)
+960626 In zfile.c, make sure we delete the temporary file even if file
+       decompression fails.
+       Reimplemented sound support, this time following the HRM closely. Seems
+       to work fine most of the time, but occasionally loses drum beats in
+       TFMX modules. do_sound() is now unconditional, it calls
+       flush_sound_buffer(), which is system-dependent. This breaks everything
+       except Linux sound for now :(
+       Add Herman ten Brugge's 68020/68881 emulation code.
+       FreeBSD chokes if sys/mount.h is included without sys/types.h. Fix the
+       configure script.
+960622 More work on AGA code.
+       Removed 2-bit display routines from custom.c. Ian: please use dithering
+       code.
+       Make slowmem and chipmem sizes run-time configurable.
+       Mask out the high bits in BLT?PTH().
+       Add exception 3 checks to Bcc/BSR instructions. Seems to be not quite
+       correct yet.
+       Completely rewrote the disk emulation. We now create a big track buffer
+       full of MFM data, used in a cyclic fashion by DSKBYTR() and friends. 
+       The current position in the buffer is determined by the cycle counter.
+       DMA reads are now done in one piece. Two new event types: ev_diskblk 
+       and ev_diskindex.
+       ARRGGHH! The RSI demo has _completely_ broken disk loading routines.
+       They start disk DMA on a block while the blitter is still working on 
+       the same memory region.
+       In zfile.c, unlink() the temporary file directly after opening it so
+       it will be freed by the OS as soon as we close it (or crash... :)
+960621 Merge pfield_sprite_h() and pfield_sprite_l() into one function.
+       Split off new files blitter.c and blitter.h from custom.c.
+       Fixed null-pointer dereference in zfile.c when filename has no
+       extension.
+       Add new field maxline to gfxvidinfo that prevents writing past the
+       screen buffer if it has less lines than expected.
+       Modify the 256 color allocation routine to set nb_cols to the same
+       value first for r,g and b; allocate everything as usual and fill the
+       lost colors afterwards with those that have the greatest difference.
+960620 For some extremely weird reason, it is faster to simply call the
+       assembly-optimized pfield_linetoscr_full routines _twice_ to double the
+       line than calling the new (also assembly-optimized)
+       pfield_linetoscr_full_double routines, at least when writing directly 
+       into the framebuffer. If someone has a good theory why, let me know 
+       about it.
+       Drawing into memory is faster with the _double routines, but not
+       noticeably (about 1%).
+       Consequence: Removed the new pfield_linetoscr_full_double assembly
+       routines again.
+       Add a "--disable-gui" option to configure.
+       Add Samuel Devulder's dithering code. Provide support for mono and
+       16 color X servers.
+       Put an assembly version of DitherLine() in X86.S.
+       New color mode (3) available, tells UAE to use 256 colors and dither
+       the image. This is meant for people who have only a 256 color X server
+       available, but it works with the SVGA version, too. It's much slower
+       than normal 256 color mode, though.
+       Use the color allocation algorithm from the dither code in
+       alloc_colors256(), too.
+960619 New files: zfile.c and zfile.h, from Samuel Devulder. These provide
+       transparent decompression of various compressed file formats. Enabled
+       by configure only for Unix systems.
+       Eliminate dont_want_aspect. New option "-C", sets correct_aspect. Make
+       video mode 3 640x480, video mode 4 800x600. Honor correct_aspect in
+       320x400, 640x480 and 800x600 mode with SVGAlib.
+       Add fields maxlinetoscr and x_adjust to gfxvidinfo.
+       Rename pfield_slow_linetoscr() to pfield_do_linetoscr(). Use new fields
+       in gfxvidinfo to enable writing directly to the framebuffer in
+       resolutions with <800 horizontal pixels.
+       New function pfield_do_linetoscr_full(), called when sure that full
+       line update is being done.
+       Move some of the usage() information into some target_specific_usage() 
+       functions, defined in the various system-specific files.
+       Support lower resolutions with LOW_BANDWIDTH, too.
+       memcpy() within screen memory is dog slow. Prevent some common cases:
+       1. Use fill_line() to double a line in the border.
+       2. Add a parameter to pfield_do_linetoscr_full() to indicate whether 
+          the line has to be doubled. New functions
+          pfield_linetoscr_*_double_slow() that simply do a memcpy(), plus 
+         optimized ones in X86.S that are much faster by avoiding the copy.
+       Smart update code could get confused by lores modes when
+       prev_max_diwstop changed from one frame to the next. New variable
+       frame_redraw_necessary, which acts as a counter. It's initialized to
+       2 in interlace mode to handle that case properly, too.
+       Move sprite priority checks into pfield_sprite_?(), move HAM
+       calculations into new function decode_ham6() to simplify the various
+       linetoscr functions.
+       Fixed a bug that would cause sprites to get deformed in some cases
+       when they overlapped (never seen it).
+960618 New file: dos-snd.c, from Gustavo.
+
+960617 Release 0.6.0
+960617 Fix memory clobber in X86.S when diwfirstword==0. Eliminate double test
+       for HAVE_SYS_MOUNT_H in sysdeps.h.
+960616 Handle programs that don't wait for the blitter by finishing a pending
+       blit as soon as a blitter register is written to (regardless of DMACON,
+       to be safe).
+       Call gui_led only if the LED changed.
+960615 Fixed dual playfield sprite priorities. Optimized dual playfield code
+       in X86.S. More work on AGA code. Get joystick status only in
+       vsync_handler to speed things up.
+       Make blitter fill more intelligent with table lookups instead of loop.
+960614 DOS update from Gustavo. Pass real bitplane pointer to
+       bpl_data_differs(), don't calculate it again.
+960610 Fixed silly INTEL_FLAG_OPT bug: The new __asm__ expressions use
+       regflags, which is of course _regflags on a.out...
+       More BeBox fixes from Christian.
+       Make the CIA bank bigger (A0..BF) and relax the CIA A/B selection
+       checks to make broken software (Kingsoft's Emerald Mine, reportedly)
+       happy.
+       Default framerate is now 1.
+960603 New BeBox code from Christian. Fix test for ELF in configure.in.
+960529 genblitter.c: generate blitfunc as a function taking ULONGs and
+       returning an ULONG. This makes custom.o about 4500 bytes smaller on the
+       x86 by removing worthless size prefixes, and should increase
+       performance (better for the cache, and the P6 reportedly doesn't like 
+       16 bit instructions anyway).
+       memory.c: Load Kickstart in one block and swap bytes after that if
+       necessary (eliminates the need for the special bebox load routine)
+       custom.c: Some preliminary work for AGA support.
+960528 Saw a real awful piece of code that detects the right mouse button by
+       reading a value from POT0DAT, counting up to 25, reading from POT0DAT
+       again, and deciding the button is pressed if the value changed. Urgl!
+       Added POT0DAT() in custom.c ...
+       Gustavo's latest patches.
+960525 Do index pulse handling in CIA_hsync_handler(). Make sure bit 12 in 
+       INTREQ gets set on an index pulse. Don't call DISK_Index() for now,
+       since this breaks the Workbench.
+       The CIA code should _probably_ not be resetting the bits in INTREQ.
+       Disable this as an experiment, let's see what breaks.
+960524 Z flag handling for ABCD/SBCD/ADDX/SUBX was wrong (must be clear if not
+       zero, was set if zero). Some other flag bugs in these functions fixed.
+960523 gfxlib.c update from Christian Schmitt. Some new Mac code from Ernesto,
+       still not all of it, though. Italian keyboard from Alessandro Bissacco.
+960522 Fix the CHK instruction. Implement middle mouse button.
+960515 Fix some Nextstep problems in configure.in.
+960513 New Makefile target "streifenfrei" to remove all output from configure.
+       Use autoconf 2.7; 2.9 is buggy.
+960512 Remove BIG_ALIGNMENT hack. Remove superfluous pfield_fetchdata() call
+       in pfield_doline_slow_l() that resulted in garbage on the screen.
+       Move blttbl array from custom.h to genblitter.c
+       Use new lookup tables imm8_table and areg_byteinc in CPU emulation
+       instead of ?: expressions.
+       GCC appears to generate better code if the opcode is passed as ULONG to
+       the CPU emulation functions instead of as UWORD.
+       Modify some of the flag emulation __asm__ statements so that GCC uses
+       less registers for them.
+960510 Cast malloc() results to char *, for C++ compilers.
+960509 Use test for GCC and __i386__ in options.h to decide whether to use
+       intel flag optimization.
+       Use test for wish4.0 to decide whether to use the GUI.
+960507 New bebox.cpp from Christian. AF sound patches from Marcus Sundberg.
+960505 Fix the configuration stuff so it works. Fix some bugs in gfxlib.c
+960504 Use GNU autoconf scripts to generate Makefile and sysconfig.h. Add new
+       files sysdeps.h that includes the right system header files. Remove
+       amiga.h and Makefile.
+960502 More Next code from Ian (new Uae.app directory, 2 bit drawing for
+       custom.c).
+960501 Allow the sound driver to set the frequency to a value that is slightly
+       different from the requested one.
+960430 Added AmigaOS port from Olaf Barthel.
+960427 Fixed single playfield sprite priorities in X86.S.
+960426 Added new NeXTwin.m from Ian.
+       Turn off the blitter delay in line mode.
+       Added a CPU optimization from Olivier Raoul: gencpu now reads a file
+       "insncount" that can be generated by UAE during execution and generates
+       specific functions for the most common opcodes. Not documented yet.
+960414 Reimplemented the fast disk emulation in a more sane way. Also it's
+       only done for reads now. (Plus, it no longer works :-/ Need to work
+       some more on this).
+       In blitter emulation, defer not only the setting of the bltfinish bit,
+       but actually defer the whole blit for the number of cycles it will
+       take. This makes programs the clear the screen while it is still being
+       displayed look much better.
+       Changed supervisor mode handling around a bit (was messy).
+       New DOS code from Gustavo.
+960412 Removed smart update method 2. Added Alessandro Bissacco's blitter
+       optimization patch.
+       Fixed some sprite problems: during hysnc, clear sprpos and sprctl, and
+       don't do_sprites() in line 0.
+960409 Be a little more intelligent about when to call pfield_linetoscr() from
+       pfield_doline_slow(). It's only necessary if a color register changed.
+       If it can be deferred to the end of the line, use the the _full
+       variants.
+       Some CIA TOD fixes.
+       Better transdisk, accepts first/last track parameters.
+960405 New function memcmpy(), inline assembler for the i386. Compares two
+       memory blocks and copies them at the same time. Used in
+       bpl_data_differs.
+960404 French keyboard from Tristan Cavelier. Parallel port emulation from
+       Stefan Reinauer.
+       Turn bpl?pt and r_bpl?pt into arrays, simplify some code using them.
+960401 Some parts of Ernesto's new Mac sources.
+960331 filesys.c: Close filedescriptors in free_key(). get_path() sometimes
+       read uninitialized bytes.
+       Minor cleanups all over the place.
+       unchain_mnn() leaves sibling intact, but clobbers next. customreset()
+       didn't care about that and crashed.
+       Use the __asm__("intel_flag_lookup") magic not only for DOS.
+       Support 320x300 for X (without LOW_BANDWIDTH).
+       Add new function fast_memcmp(), defined as memcmp if __i386__ is
+       undefined, otherwise a slightly optimized inline assembly function.
+960329 Some bug fixes in gencpu.c
+960328 Stupid programs write odd playfield modulos into the hw registers...
+       Eek! Sometimes, linedescr[] was indexed with a negative value... Add a
+       vpos >= minfirstline check to pfield_may_need_update(). I really need
+       to rewrite this in Oberon...
+       Don't turn off SHM when LOW_BANDWIDTH is selected.
+       Keep the nextpos and linepos variables from pfield_doline_slow_?() as
+       globals and initialize them in pfield_may_need_udpate().
+       Modified alloc_colors256() some more.
+       Try to make sprite DMA follow the Amiga DMA slots more closely by
+       adding a currhp parameter to do_sprites() and calling it at the end
+       of a scanline or in pfield_may_need_update().
+960327 Added Gustavo's latest DOS code, as far as possible. Modified X86.S to
+       use a macro SYM() to create symbol names either with underscore or
+       without.
+       Fixed some very silly SVGAlib lores bugs. Move screen 8 pixels up in
+       low resolution.
+       Use diwstop instead of diwstart to caclulate the DIW for 320x200 modes.
+       Reset it not only in calcdiw(), but also in init_frame().
+       Speed up 256 color allocation a little bit.
+960326 New function flush_block() in xwin.c and svga.c. Called from
+       do_flush_line() and (new function) do_flush_screen(). Modify struct
+       vidbuf_description, new member maxblocklines that records the maximum
+       number of scanlines that do_flush_line() should collect before calling
+       flush_block(). If it is zero, then flush_line() is used as before.
+       This makes the special case stuff for SHM unnecessary, so it's removed.
+       Fixed a stupid bug in events code: Put ev_hsync in front of ev_copper,
+       so that do_copper gets called with hpos == 0 instead of hpos == 227 at
+       the beginning of the line.
+       New function init_frame() that sets up some variables, called from 
+       customreset() and vsync_handler().
+       Move smart update code to pfield_doline() from pfield_doline_h() and 
+       ..._l(). Clean up these two with a macro DO_ONE_PLANE, removing
+       duplicate code.
+       Implement big blits and ECS chip ids. New configuration options
+       ECS_AGNUS and ECS_DENISE.
+       Implement MOVEP.
+960325 Before calling pfield_may_need_update(), make sure the value that was
+       written to a register actually differs from the previous one.
+       New expansion code from Stefan Reinauer.
+       Modify struct mem_notify_node to contain a pointer to a valid bit 
+       instead of the valid bit itself, so that the playfield code has to
+       check only one flag to decide whether to draw the line (SU method 2)
+960324 The chip_flags approach has several problems. A flag may cover an area
+       in memory that spans two scanlines, or several scanlines may use the
+       same area in memory.
+       Provide two other, different methods for the smart update:
+       1. Save all the bitplane data for each line and compare the chipmem
+          with the saved data to decide whether an update is necessary.
+       2. Use a chain of memory_notify_node structs instead of a single bit
+          for flags. Each scanline owns a set of these structs and chains them
+         into the right place, and the chipmem_?put routines walk the chains
+         and set the modified bit for each element.
+       Unfortunately, both methods are slower than the old one. Especially the
+       first one has some advantages though: it speeds up programs that clear
+       the screen each update and write the same contents back, and it
+       can speed up double-buffering programs at full framerate, since it does
+       not have to check whether the bitplane pointers have changed.
+       Remember the first and last drawn line for each frame, and pass them to
+       flush_screen. Use this in xwin.c for SHM. Modify SHM logic: if smart
+       update is selected, call XShmPutImage() from flush_line() instead of 
+       from flush_screen(). But gather blocks of consecutive lines to avoid
+       calling XShmPutImage() too often.
+960323 "Smart update" method, based very loosely on Alessandro Bissacco's
+       work, implemented:
+       Add an array chip_flags that records any change made to specific words
+       in chip memory.
+       Move all the hardware registers relevant to playfield display into a
+       new structure bplinfo. Remember the contents of this structure in
+       struct line_description for every line on the screen. Avoid redrawing
+       in pfield_doline if the screen memory has not been modified for the
+       line to be drawn and if the information from the last frame matches
+       that in the current frame.
+960322 Duplicate all functions responsible for drawing (pfield_doline,
+       pfield_doline_slow, pfield_sprite, pfield_*word_*res) and append _h
+       or _l (ah, the golden C++ days, when we had templates... which never
+       worked). Modify the *_l functions to support drawing in low resolution
+       (i.e. 320x200). Change the options -d and -H to support selecting color
+       mode and resolution, thereby getting rid of some SVGALIB_* options.
+       Get rid of the old pfield_*word_*res functions.
+       Collect information about the minimum diwstart value during the
+       previous frame and use that in case 320x200 was selected to fit the
+       image on the screen.
+       Get rid of HAVE_JOYSTICK (breaks the "-J" option)
+960321 Give up in op_illg() if opcode is 0x4e7b and the exception handler for
+       it is NULL. In that case, it's a 68020 Kickstart.
+960319 New Next code from Ian. SunOS target was still screwed (two CFLAGS).
+       Turn -x option into a "hair cursor" option. Support multiple mounts,
+       but warn if more than one is seen (still does not work with Kick 1.3).
+       Integrated Samuel Devulder's new LOW_BANDWIDTH patch.
+960318 Integrated the start of Markus Gietzen's gfx library replacement.
+       Changed the interface between custom.c and the graphics code. There has
+       to be a buffer holding the data of all the lines on the screen. For
+       linear SVGAlib modes, this is the video memory. Eliminated -x option,
+       prepare_line(), DrawPixel() and the X_?BIT_SCREEN options, replace with
+       3 versions of pfield_linetoscr for different datatypes. Implement
+       proper handling of the borders above and below the DIW in custom.c
+       instead of in flush_screen().
+       Move common code (color allocation) from all the graphics files to new 
+       file gfxutil.c.
+       Swedish keyboard from Per Olofsson.
+
+960315 Release 0.5.0
+960315 Newest DOS port from Gustavo. New sgi-gcc target.
+960314 Add -lXext to osf target. Use "rb" for fopen() in main.c
+960310 Play a bit with the __asm__ constraints. Implement CHK.
+960307 Fix some stupid Makefile errors. Call parse_cmdline() if no init file
+       is found.
+       First round of NextStep patches; new file NeXTwin.m
+       Stupid bug in custom.c: The #define is called NO_FAST_DISK, not
+       NO_FAST_FLOPPY.
+       Fix one of the problems the Deform demo had with the blitter: The
+       line texture wasn't rotated to the right position in blitter_init().
+960306 Use some black GCC __asm__ magic to calculate flags more quickly
+       (config INTEL_FLAG_OPT)
+       HAM was broken by pfield_linetoscr changes. Fixed.
+       LOW_BANDWIDTH sometimes got confused when the display window changed.
+960305 BCD instructions work well enough for Locomotive Basic on CPE.
+       New function parse_cmdline_and_init_file() that reads ~/.uaerc or
+       ./.uaerc and adds the options found in those files to those in argv[].
+       Patch from Denis Sablic to make disk image filenames runtime 
+       configurable. Extend it for the ROM filename.
+       Remove some of the run-time configurable stuff from config.h.
+       More X keysym fixes (I finally got a proper .Xmodmap ...)
+       for SVGAlib: Delete key, and PgUp/PgDn as Amiga keys.
+       The sound driver can now handle 22050 Hz and/or 8 bit samples. Both of
+       these are the default with LINUX_SOUND_SLOW_MACHINE.
+       Also use the SNDCTL_DSP_GETBLKSIZE ioctl and write the buffer when 
+       there is enough data.
+       Abuse keybuf.c to provide a fake joystick emulation with the numeric
+       pad (enable with -J)
+960304 bebox.cpp from Christian.
+       Rename pfield_linetoscr_full to pfield_linetoscr_full8.
+       More x86 assembly: pfield_linetoscr_full16.
+960303 SunOS target from Dirk Vangestel. Put some not-so-superfluous includes
+       back in. Added the DOS specific patches to filesys.c.
+       Started x86 assembly optimizations. New file X86.S, includes an
+       optimized version of pfield_linetoscr (for 8 bit screens only).
+       Don't use SA_RESTART if it isn't defined.
+       prepare_line() wasn't called often enough (again...), leading to memory
+       corruption and "hit the reset button" bugs when using SVGAlib.
+960226 Get rid of bool, true and false in amiga.h and everywhere else.
+       Copy yesterdays code to AF_SOUND code, too.
+       Include first round of Christian Bauer's BeBox patches. Add AIX fix
+       from Samuel Mackrill.
+       Add #include <string.h> and #include <stdlib.h> in some more places.
+       Modify gencpu.c and readcpu.c so that immediate types j and J (0..15
+       and 1..8) can be merged. Replace HAVE_ONE_GIG... option with a new
+       CPU_EMU_SIZE option that can be set to a value in the range 0..5,
+       where 0 is minimum size and 5 is equivalent to HAVE_ONE_GIG...
+960225 Remove multiplications in sound code, use a big lookup table.
+960222 Go back to having only one memory bank table of type addrbank instead
+       of several function pointer arrays. Eliminate the HAVE_BROKEN_SOFTWARE 
+       define by extending the memory bank table to 65536 entries.
+       Remove remaining DUALCPU code. Allow BTST src,imm instructions in
+       table68k.
+960220 Back out filesys.c change from Stefan Reinauer: don't call V36 specific
+       functions in expansion.library.
+       Better fix for the filesys.c assign problems by Oliver Moehrke.
+       Make new playfield code conditional on EXPERIMENTAL_SCREEN_UPDATE.
+       Improve the 64bit variant of said code. Try to get alignment for
+       apixels by putting it into a union with a long.
+       Kill the child in gui_exit(). Make graphics_init() return a value and
+       check it in main.c to see whether graphics were initialized. If not,
+       call gui_exit() anyway.
+       Use new 256 color allocation routine from svga.c in xwin.c, too.
+       Make LOW_BANDWIDTH compile _and_ work (wow...).
+960219 Fix bug in memory.c: When loading 256K Kickstart, copy 256K, not 128K.
+960218 Finished the rest of the UI: reset, debug and quit buttons as well as
+       drive LEDs. New target linux-gui; all others use dummy file nogui.c
+       for now.
+960217 The GUI now supports inserting and ejecting diskfiles and displays
+       their names. Two pipes are used now, one for reading and one for
+       writing. Properly wait for the process to start up.
+       Use sigaction() instead of signal() in debug.c.
+       More fixes for the new display routines: Need to do a final call to
+       pfield_*word_*res with the data shifted right from the last fetched
+       word.
+960216 Copper & sprite bugfixes from Marco Nelissen. Better X keyboard support
+       from Bruno Coste.
+       Move my_strdup() from filesys.c to options.h
+       New files xui.c, uae-ui (shell script) and uae-ui.tk (wish script).
+       These create a GUI for the X version of the emulator. So far, the
+       power LED works.
+960215 Don't rely on SVGAlib headers defining any keycodes at all.
+       Include Thorsten Frueauf's NetBSD patch. Apparently, the devname
+       variable in hardfile.c caused a namespace collision, so rename it to
+       uaedevname. Fastmem fixes, debugger help, and ConfigDev allocation in
+       hardfile and filesys from Stefan Reinauer.
+       xwin.c: Give the window a title.
+       Half-implemented the DIVU.L, DIVS.L, MULU.L and MULS.L instructions.
+960213 AF sound system support from Marcus Sundberg. Win95 keyboard support
+       for SVGAlib from Thierry Lescot. Added most of Gustavo Goedert's MS-DOS
+       port.
+       When using the old pfield_*word_*res functions, the gen_pfield_tables()
+       function was undefined.
+       Hmmm, /dev/brain must have been unmounted when I wrote the new pfield_*
+       functions. Now they make sure they access the apixels array only with
+       addresses that are multiples of 16 bytes.
+960212 Fix copy&paste bug in cia.c found by Marco Nelissen: Need to call
+       RethinkICRB() instead of RethinkICRA() for CIA B timers.
+       Added Stefan Reinauers autoconfig area/fastmem support. Added run-time
+       options for use_slow_mem and use_fast_mem.
+       Oops, the pfield_*word_*res() optimizations break completely on HPs and
+       Sparcs. Now use this optimization only if we are using GCC 2.7.
+       HPUX fixes in the Makefile. New target hpux-gcc.
+       The code for clearing the areas above and below the DIW was trying to
+       be a little too clever selecting the color. Just use the current 
+       background color.
+       Added channel attachment to the sound code. Untested.
+960211 Found some flag setting bugs in the rotate/shift instructions and in
+       addx/subx (which I thought I had already fixed) by reimplementing 
+       DUALCPU mode to work with Ed's e68k.
+       Argh! The copper is completely disabled during DDF in Hires 4 bitplane
+       mode - so copper positions 0x30 and 0x34 are about 640 pixels apart.
+       The Kickstart uses FF39FFFE to wait for the end of line 256 instead of
+       FFDFFFFE as in all the other modes. This is implemented now, but
+       probably not 100% correct.
+       Added check whether SVGAlib doesn't support our mode.
+       If using GCC >= 2.7, define __attribute__((aligned(16))) as
+       BIG_ALIGNMENT in config.h. Use it for the apixels array to prevent
+       potential problems on the Alpha.
+       Tried to make the color selection routine produce better results in 256
+       color mode.
+960210 readdisk didn't work at all for large files - fixed.
+       In pfield_doline(), clear the apixels array if playfield DMA is off.
+       In SPRxCTL(), reset sprite mode when sprpos==sprctl==0
+       Rewrite pfield_orword_hires() and friends to use lookup tables. No
+       noticeable improvement on my machine, but might be different on other
+       machines. Two versions of this code: one using 64bit longs on the Alpha.
+       New targets linux-debug and linux-prof.
+       Use 1MB slow mem.
+       -funroll-loops is a little excessive. Remove it.
+       Add support for linear addressing modes for SVGAlib version. Speedup
+       is 20-30% on my old 486 VLB. Now, would someone please fix SVGAlib to
+       support that for the S3-864 as well?
+       Set SVGAlib keyboard mode to DONT_CATCH_CTRLC.
+       Change custom.c, xwin.c and svga.c to keep track of the display window 
+       and background color and to clear the areas above and below the display
+       window if necessary to remove garbage images from previous frames.
+       Set the LOF bit in the Kickstart replacement init routine. Also
+       initialize CIAs to Kick 1.3-like values.
+960209 Some more -DHAVE_xxx_H options in the Makefile and filesys.c. DEC Alpha
+       fixes for filesys.c from Ed and Marcus. HPUX fixes.
+       New field in table68k for CPU type, parsed by readcpu and compared to
+       CPU_LEVEL which is defined in config.h. New instructions MOVE2C, MOVEC2
+       and CAS. Also a new field for priviledge level that is used by gencpu to
+       generate tests for regs.s and Exception(8) calls if necessary.
+       Move parsing of table68k into a new file build68k.c. Generate a file
+       called cpudefs.c containing the information from table68k in 
+       machine-readable form. Change readcpu.c to use the array found in 
+       cpudefs.c.
+       Don't generate the d8(An,Dn) addressing mode in-line. Generate a call to
+       get_disp_ea(), which is an inline function in newcpu.h if UAE is
+       configured for 68000 emulation; for 68020 emulation, it is defined in
+       newcpu.c.
+       Debugger could crash on illegals because there was no mnemonic defined
+       in lookuptab[].
+       Return zero for SERDATR.
+960207 It seems that the copper stops completely if an attempt to write to a
+       specific register fails because of COPDANG. Apparently, the Kickstarts
+       use this to stop the copper with a 0x00000000 longword. This leaves the
+       question why they don't do 0xFFFFFFFE like everybody else.
+       Enable 512K slow memory by default.
+       Integrate Stefan Reinauers battclock patch that makes it work with
+       newer Kickstarts.
+       In cia.c, do the little index pulse hack even if dskdmaen==1, because
+       DMA is only enabled when dskdmaen==2 (Helps the "Mad Decision" demo).
+       Add solaris entry to Makefile (GCC, Openwin, -DHAVE_STATFS_H)
+       Define HAVE_STRINGS_H for SGIs, change filesys.c accordingly.
+960206 Build a smaller table instead of cputbl.c. Use readcpu and the smaller
+       table to build the cpufunctbl array at run-time.
+       Nuked the other half of the old CPU emulator. Reimplemented debugger to
+       use the information generated by readcpu.
+       Define HAVE_STATFS_H for SGIs in the Makefile, and use that as a test
+       in filesys.c instead of #ifndef __linux.
+       Hack filesys.c, get_path() to support the assign command.
+       Add -fstrength-reduce and -funroll-loops in Makefile to make people
+       nervous.
+       Rewrite Sam Devulder's LOW_BANDWIDTH patch and add it to xwin.c.
+960205 Forgot some PC-relative bit instructions in table68k.
+       Nuked half of the old CPU emulator.
+       Split gencpu.c into two parts, new one is called readcpu.c and just
+       parses the table68k file. Link it to the main program.
+
+960205 Release 0.4
+960203 filesys.c, action_read(): Slightly more efficient code (translate Amiga
+       address to real pointer).
+       Moved some common code in the generate_* functions in gencpu.c to a
+       separate function.
+960202 Added an experimental fast disk option. Currently turned off by
+       default (it's not such a big win).
+       Attached sprite fixes (overlapping att. sprites looked bad, Katakis).
+       Add sleep(1) before resetting the console to text mode when using
+       SVGAlib: this might fix some screen corruption problems.
+       Add sprite/playfield priority checking to the most important case
+       (single playfield, no HAM).
+       In filesys.c, do_find(): open() returns -1 on error, not zero.
+       Return ERROR_OBJECT_WRONG_TYPE if do_find() is called for a directory
+       (fixes Champions of Krynn harddisk installation).
+960201 Don't abort if sound driver not present, just set produce_sound to 0.
+       New files keybuf.c and keybuf.h to record keypresses in the right
+       order and without losing any. In cia.c, force 15 scanlines between
+       keypresses, just to be sure.
+       unixfs.device _does_ work with Kick 1.3: just don't trust what Kick 1.3 
+       sends in the startup packet. For now, disable more than one mount per 
+       command line.
+       Started integrating Ernesto's new Mac sources.
+       Remove superfluous includes from some files.
+960131 Added Ed's unixfs.device (great stuff).
+       Adding ULONGs to pointers is a bad idea on the Alpha if the ULONG value
+       really is signed. Add some casts to LONG in (pc_p + src) expressions
+       in genpu.c.
+       If DMACON is written and copper DMA is enabled, do a COPJMP1 at once.
+       Helps the "Interference" demo.
+960129 More SGI fixes from Ed. Bugfixes and transdisk improvements from Marcus 
+       Sundberg.
+       Remove EXTRA_DEFINES from Makefile. Breaks some systems.
+       Move common sprite code from pfield_doline() and pfield_doline_slow()
+       to new function pfield_sprite(). The same sprite may appear more than
+       once on the same line, so don't shift out the bits of sprdata[] and
+       sprdatb[] while displaying it (Turrican I).
+       In xwin.c and svga.c, barf if LINUX_SVGALIB doesn't match the file 
+       being compiled.
+       Make all .o files depend on config.h in the Makefile.
+       No need to exit if sound driver unavailable, but -S given.
+       Small debugger fix: Missing space in output.
+       Fix for the sprite logic: Specifically, use a state variable indicating
+       whether the sprite has been restarted after a VSYNC. Fixes most
+       Turrican problems.
+960124 Added Denis Sablic's patch for sound run-time option.
+       Added Ed Hanway's patch for better Makefile, X mouse cursor blanking 
+       and more SGI compilation fixes.
+960123 Include options.h everywhere.
+       Handle 8 bit GrayScale visuals like PseudoColor.
+       Remove C++ leftovers from joystick code.
+960122 When using the joystick driver, the button test must come after
+       handle_events() in vsync_handler().
+960118 Removed all the remaining C++ comments. Changed all inline keywords to
+       __inline__. Define __inline__ if not using gcc.
+       Make proper prototypes for everything. Compile with maximum warnings +
+       -ansi + -pedantic.
+       Remove CIA_cycle(), obsolete.
+       Reimplemented the STOP optimization in newcpu.c. Removed DualCPU
+       support in CPU emulator.
+       Real nasty bug in pfield_doline() fixed: sprxpos could be evaluated as
+       negative, with not-so-amusing results. (Need to rewrite this in 
+       Oberon to get array bounds checking :-)       
+960117 Heroic effort: Rewrote the thing in C. This might help fix some
+       problems with users being unable to compile it.
+       Fixed a problem in hsync_handler(): Only call flush_line() for lines
+       in the display window, i.e. when we did a prepare_line() before.
+       Better code for relative branches: Don't use setpc(getpc()+x) calls,
+       increment regs.pc_p instead.
+960116 Reimplemented the function to load the Kickstart ROM. Use stdio instead
+       of fstreams since this apparently does not work on the Mac. Detect 256K
+       Kickstarts. Detect corrupt ROM images (calculate checksum).
+       Added Ernesto Corvi's Mac port. Changed it around a bit, so it
+       probably won't compile.
+960115 Reinstate config.h options for X screen depth, so that DrawPixel() can
+       be inlined in custom.cc for speed. xlinebuffer is now incremented in
+       each call to DrawPixel() (for both X and SVGAlib) to get rid of some
+       address calculations.
+960114 Fixed X generic pixel drawing routine for SHM.
+       Still trying to fix the harddisk emulation.
+       uae.device no longer breaks the debugger (can step through uae.device
+       functions now)
+       Bugs affecting performance: SPCFLAG_STOP never got reset, and DSKLEN() 
+       would set SPCFLAG_DISK even if DMA was being turned off.
+       Made slow memory a run-time option.
+       Defer interrupts by one CPU instruction to give programs a chance to
+       read INTREQR ("Seeing is Believing" and "Substance" demos)
+       Added ScrollLock hack for X, too.
+960113 SVGAlib version compiles again. Fixed SVGAlib mouse bug.
+       Fixed SHM bug: Maximum scanline is 313, not 312.
+       Sometimes, disk.cc missed a side change and would read the wrong data.
+       Fixed. Apparently, this was the worst compatibility problem.
+       Implemented trace mode.
+960112 Changed layout of class amigamemory a little so that gcc can generate
+       better addressing modes.
+       Finally wrote functions in gencpu to generate MOVEMs.
+960109 Integrated Ed Hanway's patches for better X support and run-time
+       configuration of some options. 
+       Got rid of the direct VGA memory access. (Need to do this differently).
+       Changed the method of drawing lines: custom.cc now tells the graphics
+       code the line number and whether it needs to be doubleed before drawing
+       it.
+       Added Andre Beck's MIT-SHM patch.
+       Remove warnings for newcpu.cc.
+960108 Fixed exceptions in op_illg(): Need to decrement PC.
+960107 Added an "uae.device" resident module at 0xF00000. This emulates a hard
+       disk (fixed size 8MB for now).
+960106 Moved some common code from pfield_doline() and pfield_doline_slow() to
+       a separate function. This fixes a potential HAM bug (two static vars
+       for the same value).
+       Sound support for Linux. Works only with graphics off and the CPU
+       slowed down.
+       Better SVGAlib keyboard support.
+960105 Added AvailMem(), AllocMem(), AllocAbs() and FreeMem() dummies.
+       The Hardwired demo times the multiplication instructions and prints
+       "This demo don't like Axel" if they are too fast. Apparently, Axel has
+       a 68040. Added a WANT_SLOW_MULTIPLY option to config.h.
+       Fixed the fast blitter emulation (seems to work now).
+960104 Fixed all the ChangeLog entries from 95 that said 96 (oops??!)
+       pfield_may_need_update() should check whether bitplane DMA is on.
+       Added ersatz.cc and ersatz.h. The purpose of these files is to
+       implement one or two Kickstart functions that are commonly called from
+       bootblocks. This should help support some games and demos that only use
+       the Kickstart as an initial track loader. So far, it's only good enough
+       for one program.
+951223 More intelligent event handling in the CPU emulator. Slightly faster.
+951222 Optimize CPU emulation by inlining cctrue(). Also, the real PC no
+       longer needs to be incremented each instruction. The real PC value
+       now has to be fetched by m68k_getpc().
+       Added direct screen access for SVGAlib, but it didn't help much. I'll
+       probably remove it again.
+       The gencpu executable is 2M smaller if it allocates memory
+       dynamically.
+951216 custom_bput() enhanced a little. Now remembers the value that was 
+       written in the other half of the register.
+       Apparently, the USEx bits of BLTCON0 are ignored in line draw mode.
+       (Silents-Demo)
+
+951212 Release 0.3
+951212 Included Alessandro's battclock patch.
+       Fixed mouse autocalibration for wrong-aspect screens.
+951210 Joystick support for Linux.
+       Better color matching for 256 color modes.
+       Rewrote most of the memory management in plain C, mainly to avoid the
+       various template bugs in some compilers, but also because gcc can't
+       handle the regparm attribute for virtual functions yet.
+951209 Added Alessandro's patches for automatic mouse calibration.
+       Tried to optimize the blitter loop a bit. Doesn't work.
+951205 Added Hannu's patches for diskfile write support.
+951201 More portability fixes, especially for weird compilers that workstation
+       vendors ship.
+951125 More keys for X, some keyboard support for SVGAlib (slightly 
+       dangerous); beginnings of US keyboard support.
+951124 256 color mode support for SVGAlib. FAST!
+951123 Tiny tweak to central loops in playfield code results in much better
+       assembly. Apparently, GCC does not feel too good about optimizing 
+       reference variables.
+951113 Bug fix in the events code (nextevent must not be changed while events
+       are being processed).
+951112 The playfield can now be drawn with the right aspect (i.e., every line
+       twice). Slower, but looks nicer and supports interlaced mode
+       (flickerfree!). The first 29 lines (blanking interval) are omitted
+       now to fit everything in 800x600.
+       Oops, disk drive identification did not work. Fixed, all four drives
+       appear now.
+       Oops, CIA_reset() was there all the time but never got called.
+       Optimized the planar->chunky conversion in pfield_doline() a little.
+       This really is time critical.
+951111 If colors change on a line, we might still be able to use the full 
+       line update, if the change occurred outside the DIW. Have to be a 
+       little careful, though.
+       Playfield code now uses real pointers again, but makes sure it can
+       read enough bytes to complete the current line without segfaulting.
+       Oops, my "better estimate" (see below) was a mistake. Restored the
+       original 4 hw cycles per instruction relation. This slows down the
+       emulator while booting (more screen refreshs), but speeds up many
+       demos that otherwise spend most of their time waiting for a specific
+       raster position.
+       Playfield modulos must be added immediately when DDF stops. (WOC demo)
+       Portability fixes in disk.cc (null pointers).
+       Implemented average frame rate calculation ('c' in the debugger).
+       Debugger fixes.
+       Sprite fixes (height was wrong, wrong priorities in fast update)
+       Added an AutoConfig expansion RAM device. The OS seems to recognize
+       it, but breaks sometime later (seems to be the same bug that kills
+       the emulator when there's RAM at 0xC00000).
+       SVGAlib now has mouse support, too.
+       HAM mode implemented.
+951110 Implemented fast complete line playfield update. Switches back if
+       necessary. Fixed attached sprites bug.
+       Copper wait no longer slows down the CPU emulation. (there were
+       lots of new copper bugs because of this, but I hope I fixed all
+       of them).
+       Changed cia?t? from UWORD to ULONG, since there were overflows in
+       the assertion (because of 65535+1 == 0).
+951108 The DIVS remainder could have the wrong sign.
+       New HAVE_BROKEN_SOFTWARE define in config.h that makes the emulator
+       mask out the high byte of all addresses.
+       Wrote genblitter.cc and replaced the awful code in blitter_blit()
+       and blitter_line() with calls to the generated function.
+951107 Implemented ?BCD. These don't really work yet.
+
+951106 Release 0.2
+951105 Fixed a bug in the new CIA timer code.
+       Fixed flag settings for some cases of ADDX/SUBX
+951104 Changed the main loop a bit - call all the *cycle() functions only if
+       it is really necessary. I hope everything still works - at least it is
+       twice as fast now :-D
+       Improved mouse emulation - avoid overflows, permit "wraparound".
+       Added debugger 'g' command.
+       Removed some useless casts from the CPU emulator.
+       Added a configuration option to prevent checks for odd addresses. Only
+       very bad programs need this check.
+951103 The sprite emulation sometimes did not work too well, especially with
+       dual playfield mode. Hopefully fixed.
+951102 The 10 cycle counter is more like a 5 cycle counter in this
+       implementation. (Fine, that makes floppy loading even faster :-)
+       Implemented mouse movement. Totally out of sync with the X pointer,
+       but at least something.
+       Found out about the XAutoRepeatOff() function. Real useful.
+       DualCPU mode works again.
+       Corrected flag settings for CMPA.W.
+       Fixed DIV instructions: Don't change dest in case of overflow.
+951031 The PC is now converted to a real pointer. This is safe (much safer
+       than converting bitplane pointers, since the PC always has to be valid)
+       and should speed things up a little.
+951029 Some primitive event handling: 2 mouse buttons and 1 joystick button
+       are emulated, as well as parts of the keyboard (only german mapping).
+       Fixes: Delay values and sprite widths are always LoRes. Playfield 2
+       uses colors 9..15.
+       Implemented a frame rate configuration option that can speed up the
+       emulation quite a bit.
+951028 A-ha. The 68000 has one strange feature after all. MOVEM.W to Dn sign 
+       extends the value to a longword.
+       Katakis expects that accessing odd addresses causes exception 3, so 
+       we have to emulate this. *Sigh*
+       Do at least something with the index pulse bit. It's more or less a 
+       toggle now.
+       Implemented sprites & dual playfields, both with small glitches.
+951027 When LOF is set, the frame is one line longer.
+951026 Implemented a preliminary diskfile type for special formats. Turrican
+       boots up correctly (crashes if I want to play a game, though).
+       Implemented EHB and added a few missing masking operations in the color
+       handling.
+       Fixed the absw addressing mode - need to sign extend here as well.
+951025 Fixed another extremely stupid bug, this time in the playfield code.
+       Each pixel was calculated four times...
+       Increased the size of the apixels array - this was being overrun.
+951024 Fixed an extremely stupid bug in flag settings for byte and word
+       operations.
+       The "sectors until gap" field must be in the range 1..11 instead of
+       0..10, or very bad things will happen if it is used to calculate a
+       blit size.
+951021 Don't use real pointers to fetch bitplane data - too many segfaults.
+       Delay the copper after executing an instruction, or wait sequences like
+       FFDF FFFE 0200 FFFE won't work.
+       Some programs expect that the CPU is completely turned off if the
+       blitter nasty bit is set. So be it.
+       The RSI Megademo chokes when disk DMA fetches two syncs. Leave one out.
+       The LOF bit wasn't set correctly.
+951020 Blitter fixes: Load fill carry from FCI each line; keep the masked
+       value of bltadat in bltolda
+       Give the CPU twice as many "cycles" - this still is not even remotely
+       correct, but a better estimate.
+951017 Added SVGAlib support. Unfortunately, my graphics card isn't fully
+       supported by the current SVGAlib version.
+951015 More small optimizations to memory.h and custom.cc.
+       Added code for 256 color screens. The type of screen has to be
+       selected at compile time.
+951014 Modified the memory management to be (hopefully) a little more
+       efficient.
+       Changed gencpu.cc to generate functions and a big function pointer
+       array instead of the old case labels. The generated C++ files now
+       compile a lot faster, and the code should be better as well.
+951013 Implemented pseudo POTGOR to keep the RMB from being detected as
+       pressed all the time.
+       GenerateDecTab() generated TRAP incorrectly.
+       Made some more instructions (MOVE.B A0,D0 etc) illegal in gencpu.cc.
+       Fixed X colors. Fixed data fetching for HiRes screens.
+951011 EXT.WL instructions set the flags.
+       Implemented second CPU emulator, plus "DualCPU" option. The new CPU
+       emulator is generated automatically from a file called table68k by
+       a program called gencpu.
+951002 Removed version information from the file headers.
+       Removed some sillinesses in custom.cc. 
+       DSKLEN bug fixed (mask out 0xC000).
+       Playfield code rewritten. Now supports horizontal scrolling. Implemented
+       some primitive color support.
+950927 Fixed predecrement/postincrement addressing with byte size for the
+       stack pointer.
+950926 Fixes to the disk code: Terminate disk DMA, flip disk side, read more
+       than just two sectors during disk DMA, fix checksum calculation.
+       Fixed copper comparison bugs.
+       
+950901 Release 0.1
+950826 bugfix in GenerateDecTab(): LEA.W instructions were generated.
+950312 New file disk.cc, for (guess what) disk support. Doesn't work yet.
+950311 Multiplication instructions were generating 16 bit results.
+       Sign extension was wrong in some places.
+       Removed bugs in the blitter (one word width: ALWM & AFWM and line mode)
+       The Kickstart logo looks perfect now.
+       Playfield routine should check BPLCON0 instead of BLTCON0
+950309 ASR D8,D0 is not a valid instruction.
+       Bitplane pointers were not incremented.
+       Copper comparison didn't work. COP2LC and bitplane pointers were written
+       incorrectly. Fixed.
+       Something that bears a striking resemblance to the familiar Kickstart
+       logo now appears in my X window!
+950306 ROR used to set the X flag. Bug fixes in GenerateDecTab.
+       More bug fixes in several 68000 instructions.
+       Improved blitter. ?????? KS1.3 doesn't seem to set BLTDMOD on a 
+       line draw. What is this??
+       Fixed stupid bugs in playfield code.
+950305 fixed bugs in opcode generation and interrupt handling. Implemented 
+       STOP. Fixed flag settings: Result wasn't masked. Ooops!!
+       ADDQ #imm,An doesn't set flags.
+       One-shot timer mode didn't work.
+       Implemented blitter, doesn't work.
+       Some primitive and slow playfield support, only to make the things that
+       hopefully will soon appear visible.
+950304 CIA timers ought to work OK. Copper is emulated.
+       Emulator loops infinitely when trying to initialize the console.device
+950303 experiments with X, figured out how to open a window and draw pixels.
+       No graphics emulation yet, though.
+950301 Nearly all instructions work.
+       Fixed supervisor mode stack.
+       The memory manager now handles CIA chips.
+950228 Bug fixes in 68000 code, exceptions and more instructions implemented
+       Memory management extended to handle custom chips as well.
+       Debugger improved.
+       Kickstart passes memory & CPU type test, builds up some system
+       structures.
+950227 MC68000 & little debugger for tracing. It can execute the first couple
+       of KS1.3 instructions, but doesn't get past the memory test.
+950225 Work begun
diff --git a/akiko.c b/akiko.c
new file mode 100755 (executable)
index 0000000..31f7f58
--- /dev/null
+++ b/akiko.c
@@ -0,0 +1,1453 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * CD32 Akiko emulation
+  *
+  * - C2P
+  * - NVRAM
+  * - CDROM
+  *
+  * Copyright 2001, 2002 Toni Wilen
+  *
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "memory.h"
+#include "events.h"
+#include "savestate.h"
+#include "blkdev.h"
+#include "zfile.h"
+#include "threaddep/thread.h"
+#include "akiko.h"
+#include "gui.h"
+
+#define AKIKO_DEBUG_NVRAM 0
+#define AKIKO_DEBUG_IO 0
+#define AKIKO_DEBUG_IO_CMD 0
+
+int cd32_enabled;
+
+static int m68k_getpc(void) { return 0; }
+
+/*
+ * CD32 1Kb NVRAM (EEPROM) emulation
+ *
+ * NVRAM chip is 24C08 CMOS EEPROM (1024x8 bits = 1Kb)
+ * Chip interface is I2C (2 wire serial)
+ * Akiko addresses used:
+ * 0xb80030: bit 7 = SCL (clock), 6 = SDA (data)
+ * 0xb80032: 0xb80030 data direction register (0 = input, 1 = output)
+ *
+ * Because I don't have any experience on I2C, following code may be
+ * unnecessarily complex and not 100% correct..
+ */
+
+enum i2c { I2C_WAIT, I2C_START, I2C_DEVICEADDR, I2C_WORDADDR, I2C_DATA };
+
+/* size of EEPROM, don't try to change,
+ * (hardcoded in Kickstart)
+ */
+#define NVRAM_SIZE 1024
+/* max size of one write request */
+#define NVRAM_PAGE_SIZE 16
+
+static uae_u8 cd32_nvram[NVRAM_SIZE], nvram_writetmp[NVRAM_PAGE_SIZE];
+static int nvram_address, nvram_writeaddr;
+static int nvram_rw;
+static int bitcounter = -1, direction = -1;
+static uae_u8 nvram_byte;
+static int scl_out, scl_in, scl_dir, oscl, sda_out, sda_in, sda_dir, osda;
+static int sda_dir_nvram;
+static int state = I2C_WAIT;
+
+static void nvram_write (int offset, int len)
+{
+    struct zfile *f = zfile_fopen (currprefs.flashfile, "rb+");
+    if (!f) {
+        f = zfile_fopen (currprefs.flashfile, "wb");
+        if (!f) return;
+        zfile_fwrite (cd32_nvram, NVRAM_SIZE, 1, f);
+    }
+    zfile_fseek (f, offset, SEEK_SET);
+    zfile_fwrite (cd32_nvram + offset, len, 1, f);
+    zfile_fclose (f);
+}
+
+static void nvram_read (void)
+{
+    struct zfile *f;
+
+    f = zfile_fopen (currprefs.flashfile, "rb");
+    memset (cd32_nvram, 0, NVRAM_SIZE);
+    if (!f) return;
+    zfile_fread (cd32_nvram, NVRAM_SIZE, 1, f);
+    zfile_fclose (f);
+}
+
+static void i2c_do (void)
+{
+#if AKIKO_DEBUG_NVRAM
+    int i;
+#endif
+    sda_in = 1;
+    if (!sda_dir_nvram && scl_out && oscl) {
+       if (!sda_out && osda) { /* START-condition? */
+           state = I2C_DEVICEADDR;
+           bitcounter = 0;
+           direction = -1;
+#if AKIKO_DEBUG_NVRAM
+           write_log ("START\n");
+#endif
+           return;
+       } else if(sda_out && !osda) { /* STOP-condition? */
+           state = I2C_WAIT;
+           bitcounter = -1;
+#if AKIKO_DEBUG_NVRAM
+           write_log ("STOP\n");
+#endif
+           if (direction > 0) {
+               memcpy (cd32_nvram + (nvram_address & ~(NVRAM_PAGE_SIZE - 1)), nvram_writetmp, NVRAM_PAGE_SIZE);
+               nvram_write (nvram_address & ~(NVRAM_PAGE_SIZE - 1), NVRAM_PAGE_SIZE);
+               direction = -1;
+#if AKIKO_DEBUG_NVRAM
+               write_log ("NVRAM write address %04.4X:", nvram_address & ~(NVRAM_PAGE_SIZE - 1));
+               for (i = 0; i < NVRAM_PAGE_SIZE; i++)
+                   write_log ("%02.2X", nvram_writetmp[i]);
+               write_log ("\n");
+
+#endif
+           }
+           return;
+       }
+    } 
+    if (bitcounter >= 0) {
+       if (direction) {
+           /* Amiga -> NVRAM */
+           if (scl_out && !oscl) {
+               if (bitcounter == 8) {
+#if AKIKO_DEBUG_NVRAM
+                   write_log ("RB %02.2X ", nvram_byte, m68k_getpc());
+#endif
+                   sda_in = 0; /* ACK */
+                   if (direction > 0) {
+                       nvram_writetmp[nvram_writeaddr++] = nvram_byte;
+                       nvram_writeaddr &= 15;
+                       bitcounter = 0;
+                   } else {
+                       bitcounter = -1;
+                   }
+               } else {
+                   //write_log("NVRAM received bit %d, offset %d\n", sda_out, bitcounter);
+                   nvram_byte <<= 1;
+                   nvram_byte |= sda_out;
+                   bitcounter++;
+               }
+           }
+       } else {
+           /* NVRAM -> Amiga */
+           if (scl_out && !oscl && bitcounter < 8) {
+               if (bitcounter == 0)
+                   nvram_byte = cd32_nvram[nvram_address];
+               sda_dir_nvram = 1;
+               sda_in = (nvram_byte & 0x80) ? 1 : 0;
+               //write_log("NVRAM sent bit %d, offset %d\n", sda_in, bitcounter);
+               nvram_byte <<= 1;
+               bitcounter++;
+               if (bitcounter == 8) {
+#if AKIKO_DEBUG_NVRAM
+                   write_log ("NVRAM sent byte %02.2X address %04.4X PC=%08.8X\n", cd32_nvram[nvram_address], nvram_address, m68k_getpc());
+#endif
+                   nvram_address++;
+                   nvram_address &= NVRAM_SIZE - 1;
+                   sda_dir_nvram = 0;
+               }
+           }
+           if(!sda_out && sda_dir && !scl_out) /* ACK from Amiga */
+               bitcounter = 0;
+       }
+       if (bitcounter >= 0) return;
+    }
+    switch (state)
+    {
+       case I2C_DEVICEADDR:
+       if ((nvram_byte & 0xf0) != 0xa0) {
+           write_log ("WARNING: I2C_DEVICEADDR: device address != 0xA0\n");
+           state = I2C_WAIT;
+           return;
+       }
+       nvram_rw = (nvram_byte & 1) ? 0 : 1;
+       if (nvram_rw) {
+           /* 2 high address bits, only fetched if WRITE = 1 */
+           nvram_address &= 0xff;
+           nvram_address |= ((nvram_byte >> 1) & 3) << 8;
+           state = I2C_WORDADDR;
+           direction = -1;
+       } else {
+           state = I2C_DATA;
+           direction = 0;
+           sda_dir_nvram = 1;
+       }
+       bitcounter = 0;
+#if AKIKO_DEBUG_NVRAM
+       write_log ("I2C_DEVICEADDR: rw %d, address %02.2Xxx PC=%08.8X\n", nvram_rw, nvram_address >> 8, m68k_getpc());
+#endif
+       break;
+       case I2C_WORDADDR:
+       nvram_address &= 0x300;
+       nvram_address |= nvram_byte;
+#if AKIKO_DEBUG_NVRAM
+       write_log ("I2C_WORDADDR: address %04.4X PC=%08.8X\n", nvram_address, m68k_getpc());
+#endif
+       if (direction < 0) {
+           memcpy (nvram_writetmp, cd32_nvram + (nvram_address & ~(NVRAM_PAGE_SIZE - 1)), NVRAM_PAGE_SIZE);
+           nvram_writeaddr = nvram_address & (NVRAM_PAGE_SIZE - 1);
+       }
+       state = I2C_DATA;
+       bitcounter = 0;
+       direction = 1;
+       break;
+    }
+}
+
+static void akiko_nvram_write (int offset, uae_u32 v)
+{
+    int sda;
+    switch (offset)
+    {
+       case 0:
+       oscl = scl_out;
+       scl_out = (v & 0x80) ? 1 : 0;
+       osda = sda_out;
+       sda_out = (v & 0x40) ? 1 : 0;
+       break;
+       case 2:
+       scl_dir = (v & 0x80) ? 1 : 0;
+       sda_dir = (v & 0x40) ? 1 : 0;
+       break;
+       default:
+       return;
+    }
+    sda = sda_out;
+    if (oscl != scl_out || osda != sda) {
+       i2c_do ();
+       oscl = scl_out;
+       osda = sda;
+    }
+}
+
+static uae_u32 akiko_nvram_read (int offset)
+{
+    uae_u32 v = 0;
+    switch (offset)
+    {
+       case 0:
+       if (!scl_dir)
+           v |= scl_in ? 0x80 : 0x00;
+           else
+           v |= scl_out ? 0x80 : 0x00;
+       if (!sda_dir)
+           v |= sda_in ? 0x40 : 0x00;
+           else
+           v |= sda_out ? 0x40 : 0x00;
+       break;
+       case 2:
+       v |= scl_dir ? 0x80 : 0x00;
+       v |= sda_dir ? 0x40 : 0x00;
+       break;
+    }
+    return v;
+}
+
+/* CD32 Chunky to Planar hardware emulation
+ * Akiko addresses used:
+ * 0xb80038-0xb8003b
+ */
+
+static uae_u32 akiko_buffer[8];
+static int akiko_read_offset, akiko_write_offset;
+static uae_u32 akiko_result[8];
+
+static void akiko_c2p_do (void)
+{
+    int i;
+
+    for (i = 0; i < 8; i++) akiko_result[i] = 0;
+    /* FIXME: better c2p algoritm than this piece of crap.... */
+    for (i = 0; i < 8 * 32; i++) {
+        if (akiko_buffer[7 - (i >> 5)] & (1 << (i & 31)))
+            akiko_result[i & 7] |= 1 << (i >> 3);
+    }
+}
+
+static void akiko_c2p_write (int offset, uae_u32 v)
+{
+    if (offset == 3) akiko_buffer[akiko_write_offset] = 0;
+    akiko_buffer[akiko_write_offset] |= v << ( 8 * (3 - offset));
+    if (offset == 0) {
+       akiko_write_offset++;
+       akiko_write_offset &= 7;
+    }
+    akiko_read_offset = 0;
+}
+
+static uae_u32 akiko_c2p_read (int offset)
+{
+    uae_u32 v;
+
+    if (akiko_read_offset == 0 && offset == 3)
+       akiko_c2p_do ();
+    akiko_write_offset = 0;
+    v = akiko_result[akiko_read_offset];
+    if (offset == 0) {
+       akiko_read_offset++;
+       akiko_read_offset &= 7;
+    }
+    return v >> (8 * (3 - offset));
+}
+
+/* CD32 CDROM hardware emulation
+ * Akiko addresses used:
+ * 0xb80004-0xb80028
+ *
+ * I can't believe cd.device and custom loaders are fooled to think
+ * this piece of crap emulates real CD32 CDROM controller and drive :)
+ */
+
+#define CDSTATUS_FRAME             0x80000000
+#define CDSTATUS_DATA_AVAILABLE            0x10000000
+#define CDSTATUS_DATASECTOR_ERROR   0x08000000 /* ?? */
+#define CDSTATUS_DATASECTOR        0x04000000
+#define CDSTATUS_UNKNOWN            0x02000000
+
+#define CDS_ERROR 0x80
+#define CDS_PLAYING 0x08
+
+static uae_u32 cdrom_status1, cdrom_status2;
+static uae_u8 cdrom_status3;
+static uae_u32 cdrom_address1, cdrom_address2;
+static uae_u32 cdrom_longmask;
+static uae_u32 cdrom_readmask_r, cdrom_readmask_w;
+static uae_u8 cdrom_command_offset_complete; /* 0x19 */
+static uae_u8 cdrom_command_offset_todo; /* 0x1d */
+static uae_u8 cdrom_result_complete; /* 0x1a */
+static uae_u8 cdrom_result_last_pos; /* 0x1f */
+static uae_u8 cdrom_result_buffer[32];
+static uae_u8 cdrom_command_buffer[32];
+static uae_u8 cdrom_command;
+
+#define MAX_TOC_ENTRIES 103 /* tracks 1-99, A0,A1 and A2 */
+static int cdrom_toc_entries;
+static int cdrom_toc_counter;
+static uae_u8 cdrom_toc_buffer[MAX_TOC_ENTRIES*13];
+
+static int cdrom_disk, cdrom_paused, cdrom_playing;
+static int cdrom_command_active;
+static int cdrom_command_length;
+static int cdrom_checksum_error;
+static int cdrom_data_offset, cdrom_speed, cdrom_sector_counter;
+static int cdrom_current_sector;
+static int cdrom_data_end, cdrom_leadout;
+static int cdrom_dosomething;
+
+static uae_u8 *sector_buffer_1, *sector_buffer_2;
+static int sector_buffer_sector_1, sector_buffer_sector_2;
+#define SECTOR_BUFFER_SIZE 64
+static uae_u8 *sector_buffer_info_1, *sector_buffer_info_2;
+
+static int unitnum = -1;
+
+static uae_u8 frombcd (uae_u8 v)
+{
+    return (v >> 4) * 10 + (v & 15);
+}
+
+static uae_u8 tobcd (uae_u8 v)
+{
+    return ((v / 10) << 4) | (v % 10);
+}
+
+static int fromlongbcd (uae_u8 *p)
+{
+    return (frombcd (p[0]) << 16) | (frombcd (p[1]) << 8) | (frombcd (p[2])  << 0);
+}
+
+/* convert minutes, seconds and frames -> logical sector number */
+static int msf2lsn (int msf)
+{
+    int sector = (((msf >> 16) & 0xff) * 60 * 75 + ((msf >> 8) & 0xff) * 75 + ((msf >> 0) & 0xff)) - 150;
+    if (sector < 0)
+       sector = 0;
+    return sector;
+}
+
+/* convert logical sector number -> minutes, seconds and frames */
+static int lsn2msf (int sectors)
+{
+    int msf;
+    sectors += 150;
+    msf = (sectors / (75 * 60)) << 16;
+    msf |= ((sectors / 75) % 60) << 8;
+    msf |= (sectors % 75) << 0;
+    return msf;
+}
+
+static void cdaudiostop (void)
+{
+    cdrom_playing = 0;
+    cdrom_paused = 0;
+    if (unitnum < 0)
+       return;
+    sys_command_pause (DF_IOCTL, unitnum, 0);
+    sys_command_stop (DF_IOCTL, unitnum);
+    sys_command_pause (DF_IOCTL, unitnum, 1);
+}
+
+static uae_u32 last_play_end;
+static int cd_play_audio (uae_u32 startmsf, uae_u32 endmsf, int scan)
+{
+    if (endmsf == 0xffffffff)
+       endmsf = last_play_end;
+    else
+       last_play_end = endmsf;
+    return sys_command_play (DF_IOCTL, unitnum,startmsf, endmsf, scan);
+}
+
+
+/* read qcode */
+static uae_u32 last_play_pos;
+static int cd_qcode (uae_u8 *d)
+{
+    uae_u8 *buf, *s, as;
+
+    if (d)
+        memset (d, 0, 11);
+    last_play_pos = 0;
+    buf = sys_command_qcode (DF_IOCTL, unitnum);
+    if (!buf)
+       return 0;
+    as = buf[1];
+    if (as != 0x11 && as != 0x12 && as != 0x13 && as != 0x15) /* audio status ok? */
+       return 0;
+    s = buf + 4;
+    last_play_pos = (s[9] << 16) | (s[10] << 8) | (s[11] << 0);
+    if (!d)
+       return 0;
+    /* ??? */
+    d[0] = 0;
+    /* CtlAdr */
+    d[1] = (s[1] >> 4) | (s[1] << 4);
+    /* Track */
+    d[2] = tobcd (s[2]);
+    /* Index */
+    d[3] = tobcd (s[3]);
+    /* TrackPos */
+    d[4] = tobcd (s[9]);
+    d[5] = tobcd (s[10]);
+    d[6] = tobcd (s[11]);
+    /* DiskPos */
+    d[7] = 0;
+    d[8] = tobcd (s[5]);
+    d[9] = tobcd (s[6]);
+    d[10] = tobcd (s[7]);
+    if (as == 0x15) {
+       /* Make sure end of disc position is passed.
+        */
+       int lsn = msf2lsn ((s[5] << 16) | (s[6] << 8) | (s[7] << 0));
+        int msf = lsn2msf (cdrom_leadout);
+       if (lsn >= cdrom_leadout || cdrom_leadout - lsn < 10) {
+           d[8] = tobcd ((uae_u8)(msf >> 16));
+           d[9] = tobcd ((uae_u8)(msf >> 8));
+           d[10] = tobcd ((uae_u8)(msf >> 0));
+       }
+    }
+
+    return 0;
+}
+
+/* read toc */
+static int cdrom_toc (void)
+{
+    int i, j;
+    int datatrack = 0, secondtrack = 0;
+    uae_u8 *s, *d, *buf;
+
+    cdrom_toc_counter = -1;
+    cdrom_toc_entries = 0;
+    buf = sys_command_toc (DF_IOCTL, unitnum);
+    if (!buf)
+       return 1;
+    i = (buf[0] << 8) | (buf[1] << 0);
+    i -= 2;
+    i /= 11;
+    if (i > MAX_TOC_ENTRIES)
+       return -1;
+    memset (cdrom_toc_buffer, 0, MAX_TOC_ENTRIES * 13);
+    cdrom_data_end = -1;
+    for (j = 0; j < i; j++) {
+       s = buf + 4 + j * 11;
+       d = &cdrom_toc_buffer[j * 13];
+       d[1] = (s[1] >> 4) | (s[1] << 4);
+       d[3] = s[3] < 100 ? tobcd(s[3]) : s[3];
+       d[8] = tobcd (s[8]);
+       d[9] = tobcd (s[9]);
+       d[10] = tobcd (s[10]);
+       if (s[3] == 1 && (s[1] & 0x0f) == 0x04)
+           datatrack = 1;
+       if (s[3] == 2)
+           secondtrack = msf2lsn ((s[8] << 16) | (s[9] << 8) | (s[10] << 0));
+       if (s[3] == 0xa2)
+           cdrom_leadout = msf2lsn ((s[8] << 16) | (s[9] << 8) | (s[10] << 0));
+    }
+    if (datatrack) {
+       if (secondtrack)
+           cdrom_data_end = secondtrack;
+       else
+           cdrom_data_end = cdrom_leadout;
+    }
+    cdrom_toc_entries = i;
+    return 0;
+}
+
+/* open device */
+static int sys_cddev_open (void)
+{
+    int first = -1;
+    struct device_info di1, *di2;
+    int cd32unit = -1;
+    int audiounit = -1;
+
+    for (unitnum = 0; unitnum < MAX_TOTAL_DEVICES; unitnum++) {
+        if (sys_command_open (DF_IOCTL, unitnum)) {
+           di2 = sys_command_info (DF_IOCTL, unitnum, &di1);
+           if (di2 && di2->type == INQ_ROMD) {
+               write_log ("%s: ", di2->label);
+               if (first < 0)
+                   first = unitnum;
+               if (!cdrom_toc ()) {
+                   if (cdrom_data_end > 0) {
+                       uae_u8 *p = sys_command_read (DF_IOCTL, unitnum, 16);
+                       if (p) {
+                           if (!memcmp (p + 8, "CDTV", 4) || !memcmp (p + 8, "CD32", 4)) {
+                               write_log ("CD32 or CDTV\n");
+                               if (cd32unit < 0)
+                                   cd32unit = unitnum;
+                           } else {
+                               write_log ("non CD32/CDTV data CD\n");
+                           }
+                       } else {
+                           write_log ("read error\n");
+                       }   
+                   } else {
+                       write_log ("Audio CD\n");
+                       if (audiounit < 0)
+                           audiounit = unitnum;
+                   }
+               } else {
+                   write_log ("can't read TOC\n");
+               }
+           }
+           sys_command_close (DF_IOCTL, unitnum);
+       }
+    }
+    unitnum = audiounit;
+    if (cd32unit >= 0)
+        unitnum = cd32unit;
+    if (unitnum < 0)
+       unitnum = first;
+    if (unitnum < 0)
+       return 1;
+    if (!sys_command_open (DF_IOCTL, unitnum))
+       write_log ("re-opening unit %d failed!\n", unitnum);
+    di2 = sys_command_info (DF_IOCTL, unitnum, &di1);
+    if (!di2) {
+       write_log ("unit %d info failed\n", unitnum);
+       sys_command_close (DF_IOCTL, unitnum);
+       return 1;
+    }
+    write_log ("using drive %s (unit %d, media %d)\n", di2->label, unitnum, di2->media_inserted);
+    /* make sure CD audio is not playing */
+    cdaudiostop ();
+    return 0;
+}
+
+/* close device */
+static void sys_cddev_close (void)
+{
+    cdaudiostop ();
+    sys_command_close (DF_IOCTL, unitnum);
+}
+
+static int command_lengths[] = { 1,2,1,1,12,2,1,1,4,1,-1,-1,-1,-1,-1 };
+
+static void cdrom_return_data (int len)
+{
+    uae_u32 cmd_buf = cdrom_address2;
+    int i;
+    uae_u8 checksum;
+
+    if (len <= 0) return;
+#if AKIKO_DEBUG_IO_CMD
+    write_log ("OUT:");
+#endif
+    checksum = 0xff;
+    for (i = 0; i < len; i++) {
+       checksum -= cdrom_result_buffer[i];
+       put_byte (cmd_buf + ((cdrom_result_complete + i) & 0xff), cdrom_result_buffer[i]);
+#if AKIKO_DEBUG_IO_CMD
+       write_log ("%02.2X ", cdrom_result_buffer[i]);
+#endif
+    }
+    put_byte (cmd_buf + ((cdrom_result_complete + len) & 0xff), checksum);
+#if AKIKO_DEBUG_IO_CMD
+    write_log ("%02.2X\n", checksum);
+#endif
+    cdrom_result_complete += len + 1;
+    cdrom_status1 |= CDSTATUS_DATA_AVAILABLE;
+}
+
+static int cdrom_command_something (void)
+{
+    return 0;
+}
+
+static int cdrom_command_media_status (void)
+{
+    struct device_info di;
+
+    cdrom_result_buffer[0] = 10;
+    cdrom_result_buffer[1] = sys_command_info (DF_IOCTL, unitnum, &di)->media_inserted ?  1 : 0;
+    return 2;
+}
+
+/* check if cd drive door is open or closed */
+static int cdrom_command_door_status (void)
+{
+    struct device_info di;
+    if (unitnum >= 0 && !sys_command_info (DF_IOCTL, unitnum, &di)->media_inserted) {
+       cdrom_result_buffer[1] = 0x80;
+       cdrom_disk = 0;
+    } else {
+       cdrom_result_buffer[1] = 1;
+       cdrom_disk = 1;
+    }
+    if (unitnum >= 0)
+       cdrom_toc ();
+    cdrom_result_buffer[0] = cdrom_command;
+    return 20;
+}
+
+/* return one TOC entry */
+static int cdrom_return_toc_entry (void)
+{
+    cdrom_result_buffer[0] = 6;
+    if (cdrom_toc_entries == 0) {
+       cdrom_result_buffer[1] = CDS_ERROR;
+       return 15;
+    }
+    cdrom_result_buffer[1] = 0;
+    memcpy (cdrom_result_buffer + 2, cdrom_toc_buffer + cdrom_toc_counter * 13, 13);
+    cdrom_toc_counter++;
+    if (cdrom_toc_counter >= cdrom_toc_entries)
+       cdrom_toc_counter = 0;
+    return 15;
+}
+
+/* pause CD audio */
+static int cdrom_command_pause (void)
+{
+    cdrom_toc_counter = -1;
+    cdrom_result_buffer[0] = cdrom_command;
+    cdrom_result_buffer[1] = cdrom_playing ? CDS_PLAYING : 0;
+    if (!cdrom_playing)
+       return 2;
+    if (cdrom_paused)
+       return 2;
+    sys_command_pause (DF_IOCTL, unitnum,1);
+    cdrom_paused = 1;
+    return 2;
+}
+
+/* unpause CD audio */
+static int cdrom_command_unpause (void)
+{
+    cdrom_result_buffer[0] = cdrom_command;
+    cdrom_result_buffer[1] = cdrom_playing ? CDS_PLAYING : 0;
+    if (!cdrom_paused)
+       return 2;
+    if (!cdrom_playing)
+       return 2;
+    cdrom_paused = 0;
+    sys_command_pause (DF_IOCTL, unitnum,0);
+    return 2;
+}
+
+/* seek head/play CD audio/read data sectors */
+static int cdrom_command_multi (void)
+{
+    int seekpos = fromlongbcd (cdrom_command_buffer + 1);
+    int endpos = fromlongbcd (cdrom_command_buffer + 4);
+
+    if (cdrom_playing)
+       cdaudiostop ();
+    cdrom_speed = (cdrom_command_buffer[8] & 0x40) ? 2 : 1;
+    cdrom_result_buffer[0] = cdrom_command;
+    cdrom_result_buffer[1] = 0;
+    if (!cdrom_disk) {
+       cdrom_result_buffer[1] |= CDS_ERROR;
+       return 2;
+    }
+
+    if (cdrom_command_buffer[7] == 0x80) {    /* data read */
+       int cdrom_data_offset_end = msf2lsn (endpos);
+       cdrom_data_offset = msf2lsn (seekpos);
+#if AKIKO_DEBUG_IO_CMD
+       write_log ("READ DATA FROM %06.6X (%d) TO %06.6X (%d) SPEED=%dx\n", seekpos, cdrom_data_offset, endpos, cdrom_data_offset_end, cdrom_speed);
+#endif
+       cdrom_result_buffer[1] |= 0x02;
+    } else if (cdrom_command_buffer[10] & 4) { /* play audio */
+       int scan = 0;
+       if (cdrom_command_buffer[7] & 0x04)
+           scan = 1;
+       else if (cdrom_command_buffer[7] & 0x08)
+           scan = -1;
+#if AKIKO_DEBUG_IO_CMD
+       write_log ("PLAY FROM %06.6X to %06.6X SCAN=%d\n", seekpos, endpos, scan);
+#endif
+       if (!cd_play_audio (seekpos, endpos, 0)) {
+           cdrom_result_buffer[1] = CDS_ERROR;
+       } else {
+           cdrom_playing = 1;
+           cdrom_result_buffer[1] |= CDS_PLAYING;
+       }
+    } else {
+#if AKIKO_DEBUG_IO_CMD
+       write_log ("SEEKTO %06.6X\n",seekpos);
+#endif
+       if (seekpos < 150)
+           cdrom_toc_counter = 0;
+       else
+           cdrom_toc_counter = -1;
+    }
+    return 2;
+}
+
+/* return subq entry */
+static int cdrom_command_subq (void)
+{
+    cdrom_result_buffer[0] = cdrom_command;
+    cdrom_result_buffer[1] = 0;
+    if (cd_qcode (cdrom_result_buffer + 2))
+       cdrom_result_buffer[1] = CDS_ERROR;
+    return 15;
+}
+
+static void cdrom_run_command (void)
+{
+    uae_u32 cmd_buf = cdrom_address2 + 0x200;
+    int i, cmd_len;
+    uae_u8 checksum;
+
+    for (;;) {
+       if (cdrom_command_active)
+           return;
+       if (cdrom_command_offset_complete == cdrom_command_offset_todo)
+           return;
+       cdrom_command = get_byte (cmd_buf + cdrom_command_offset_complete);
+       if ((cdrom_command & 0xf0) == 0)
+           return;
+       cdrom_checksum_error = 0;
+       cmd_len = command_lengths[cdrom_command & 0x0f];
+       if (cmd_len < 0) {
+#if AKIKO_DEBUG_IO_CMD
+           write_log ("unknown command\n");
+#endif
+           cmd_len = 1;
+       }
+#if AKIKO_DEBUG_IO_CMD
+       write_log ("IN:");
+#endif
+       checksum = 0;
+       for (i = 0; i < cmd_len + 1; i++) {
+           cdrom_command_buffer[i] = get_byte (cmd_buf + ((cdrom_command_offset_complete + i) & 0xff));
+           checksum += cdrom_command_buffer[i];
+#if AKIKO_DEBUG_IO_CMD
+           write_log ("%02.2X ", cdrom_command_buffer[i]);
+#endif
+       }
+       if (checksum!=0xff) {
+#if AKIKO_DEBUG_IO_CMD
+           write_log (" checksum error");
+#endif
+           cdrom_checksum_error = 1;
+       }
+#if AKIKO_DEBUG_IO_CMD
+       write_log ("\n");
+#endif
+       cdrom_command_active = 1;
+       cdrom_command_length = cmd_len;
+       return;
+    }
+}
+
+static void cdrom_run_command_run (void)
+{
+    int len;
+
+    cdrom_command_offset_complete = (cdrom_command_offset_complete + cdrom_command_length + 1) & 0xff;
+    memset (cdrom_result_buffer, 0, sizeof(cdrom_result_buffer));
+    switch (cdrom_command & 0x0f)
+    {
+        case 2:
+        len = cdrom_command_pause ();
+        break;
+        case 3:
+        len = cdrom_command_unpause ();
+        break;
+        case 4:
+        len = cdrom_command_multi ();
+        break;
+       case 5:
+       cdrom_dosomething = 1;
+       len = cdrom_command_something ();
+       break;
+        case 6:
+        len = cdrom_command_subq ();
+        break;
+        case 7:
+        len = cdrom_command_door_status ();
+        break;
+        default:
+        len = 0;
+        break;
+    }
+    if (len == 0)
+        return;
+    if (cdrom_checksum_error)
+        cdrom_result_buffer[1] |= 0x80;
+    cdrom_return_data (len);
+}
+
+extern void encode_l2 (uae_u8 *p, int address);
+
+/* DMA transfer one CD sector */
+static void cdrom_run_read (void)
+{
+    int i, j, sector;
+    int read = 0;
+    uae_u8 buf[2352];
+    int sec;
+
+    if (!(cdrom_longmask & 0x04000000))
+       return;
+    if (!cdrom_readmask_w)
+       return;
+    if (cdrom_data_offset<0)
+       return;
+    j = cdrom_sector_counter & 15;
+    if (unitnum >= 0 && cdrom_readmask_w & (1 << j)) {
+        sector = cdrom_current_sector = cdrom_data_offset + cdrom_sector_counter;
+        sec = sector - sector_buffer_sector_1;
+        if (sector_buffer_sector_1 >= 0 && sec >= 0 && sec < SECTOR_BUFFER_SIZE) {
+           if (sector_buffer_info_1[sec] != 0xff && sector_buffer_info_1[sec] != 0) {
+               memcpy (buf + 16, sector_buffer_1 + sec * 2048, 2048);
+               encode_l2 (buf, sector + 150);
+               buf[0] = 0;
+               buf[1] = 0;
+               buf[2] = 0;
+               buf[3] = cdrom_sector_counter;
+               for (i = 0; i < 2352; i++)
+                   put_byte (cdrom_address1 + j * 4096 + i, buf[i]);
+               cdrom_readmask_r |= 1 << j;
+           }
+           if (sector_buffer_info_1[sec] != 0xff)
+               sector_buffer_info_1[sec]--;
+       } else
+           return;
+#if AKIKO_DEBUG_IO_CMD
+        write_log("read sector=%d, scnt=%d -> %d\n", cdrom_data_offset, cdrom_sector_counter, sector);
+#endif
+       cdrom_readmask_w &= ~(1 << j);
+    }
+    cdrom_sector_counter++;
+    if (cdrom_readmask_w == 0)
+       cdrom_status1 |= CDSTATUS_DATASECTOR;
+}
+
+static uae_sem_t akiko_sem;
+
+static void akiko_handler (void)
+{
+    static int mediacheckcnt;
+    static int lastmediastate = -1;
+    struct device_info di;
+
+    if (unitnum < 0)
+       return;
+    if (cdrom_result_complete > cdrom_result_last_pos && cdrom_result_complete - cdrom_result_last_pos < 100) {
+        cdrom_status1 |= CDSTATUS_DATA_AVAILABLE;
+       return;
+    }
+    if (cdrom_result_last_pos < cdrom_result_complete)
+       return;
+    if (mediacheckcnt > 0)
+       mediacheckcnt--;
+    if (mediacheckcnt == 0) {
+       int media = sys_command_info (DF_IOCTL, unitnum, &di)->media_inserted;
+       mediacheckcnt = 312 * 50 * 2;
+       if (media != lastmediastate) {
+           write_log ("media changed = %d\n", media);
+           lastmediastate = cdrom_disk = media;
+           cdrom_return_data (cdrom_command_media_status ());
+           cdrom_toc ();
+            /* do not remove! first try may fail */
+           cdrom_toc ();
+           return;
+       }
+    }
+    if (cdrom_toc_counter >= 0 && !cdrom_command_active && cdrom_dosomething) {
+       cdrom_return_data (cdrom_return_toc_entry ());
+       cdrom_dosomething--;
+       return;
+    }
+}
+       
+static void akiko_internal (void)
+{
+    cdrom_run_command ();
+    if (cdrom_command_active > 0) {
+        cdrom_command_active--;
+        if (!cdrom_command_active)
+           cdrom_run_command_run ();
+    }
+}
+
+extern int cd32_enabled;
+
+void AKIKO_hsync_handler (void)
+{
+    static int framecounter;
+
+    if (!cd32_enabled)
+       return;
+    framecounter--;
+    if (framecounter <= 0) {
+       if (cdrom_playing || cdrom_toc_counter > 0)
+           gui_cd_led (1);
+       cdrom_run_read ();
+       framecounter = 1000000 / (74 * 75 * cdrom_speed);
+        cdrom_status1 |= CDSTATUS_FRAME;
+    }
+    akiko_internal ();
+    akiko_handler ();
+}
+
+
+static volatile int akiko_thread_running;
+
+/* cdrom data buffering thread */
+static void *akiko_thread (void *null)
+{
+    int i;
+    uae_u8 *tmp1;
+    uae_u8 *tmp2;
+    int tmp3;
+    uae_u8 *p;
+    int offset;
+    int sector;
+
+    while(akiko_thread_running) {
+        uae_sem_wait (&akiko_sem);
+       sector = cdrom_current_sector;
+       for (i = 0; i < SECTOR_BUFFER_SIZE; i++) {
+           if (sector_buffer_info_1[i] == 0xff) break;
+       }
+       if (cdrom_data_end > 0 && sector >= 0 && (sector_buffer_sector_1 < 0 || sector < sector_buffer_sector_1 || sector >= sector_buffer_sector_1 + SECTOR_BUFFER_SIZE * 2 / 3 || i != SECTOR_BUFFER_SIZE)) {
+           memset (sector_buffer_info_2, 0, SECTOR_BUFFER_SIZE);
+#if AKIKO_DEBUG_IO_CMD
+           write_log("filling buffer sector=%d (max=%d)\n", sector, cdrom_data_end);
+#endif
+           sector_buffer_sector_2 = sector;
+           offset = 0;
+           while (offset < SECTOR_BUFFER_SIZE) {
+               p = 0;
+               if (sector < cdrom_data_end)
+                   p = sys_command_read (DF_IOCTL, unitnum, sector);
+               if (p)
+                   memcpy (sector_buffer_2 + offset * 2048, p, 2048);
+               sector_buffer_info_2[offset] = p ? 3 : 0;
+               offset++;
+               sector++;
+           }
+           tmp1 = sector_buffer_info_1;
+           sector_buffer_info_1 = sector_buffer_info_2;
+           sector_buffer_info_2 = tmp1;
+           tmp2 = sector_buffer_1;
+           sector_buffer_1 = sector_buffer_2;
+           sector_buffer_2 = tmp2;
+           tmp3 = sector_buffer_sector_1;
+           sector_buffer_sector_1 = sector_buffer_sector_2;
+           sector_buffer_sector_2 = tmp3;
+       }
+        uae_sem_post (&akiko_sem);
+       Sleep (10);
+    }
+    akiko_thread_running = -1;
+    return 0;
+}
+
+static uae_u8 akiko_get_long (uae_u32 v, int offset)
+{
+    return v >> ((3 - offset) * 8);
+}
+static void akiko_put_long (uae_u32 *p, int offset, int v)
+{
+    *p &= ~(0xff << ((3 - offset) * 8));
+    *p |= v << ((3 - offset) * 8);
+}
+
+uae_u32 akiko_bget2 (uaecptr addr, int msg)
+{
+    uae_u8 v;
+
+    addr &= 0xffff;
+    uae_sem_wait (&akiko_sem);
+    switch (addr)
+    {
+       /* "CAFE" = Akiko identification.
+        * Kickstart ignores Akiko C2P if this ID isn't correct */
+       case 0x02:
+       v = 0xCA;
+       break;
+       case 0x03:
+       v = 0xFE;
+       break;
+
+       /* CDROM control */
+       case 0x04:
+       case 0x05:
+       case 0x06:
+       case 0x07:
+       v = akiko_get_long (cdrom_status1, addr - 0x04);
+       break;
+       case 0x08:
+       case 0x09:
+       case 0x0a:
+       case 0x0b:
+       v = akiko_get_long (cdrom_status2, addr - 0x08);
+       break;
+       case 0x10:
+       case 0x11:
+       case 0x12:
+       case 0x13:
+       v = akiko_get_long (cdrom_address1, addr - 0x10);
+       break;
+       case 0x14:
+       case 0x15:
+       case 0x16:
+       case 0x17:
+       v = akiko_get_long (cdrom_address2, addr - 0x14);
+       break;
+       case 0x18:
+       v = cdrom_status3;
+       break;
+       case 0x19:
+       v = cdrom_command_offset_complete;
+       break;
+       case 0x1a:
+       v = cdrom_result_complete;
+       break;
+       case 0x1f:
+       v = cdrom_result_last_pos;
+       break;
+       case 0x20:
+       case 0x21:
+       v = akiko_get_long (cdrom_readmask_r, addr - 0x20 + 2);
+       break;
+       case 0x24:
+       case 0x25:
+       case 0x26:
+       case 0x27:
+       v = akiko_get_long (cdrom_longmask, addr - 0x24);
+       break;
+
+       /* NVRAM */
+       case 0x30:
+       case 0x31:
+       case 0x32:
+       case 0x33:
+       v =  akiko_nvram_read (addr - 0x30);
+       break;
+
+       /* C2P */
+       case 0x38:
+       case 0x39:
+        case 0x3a:
+       case 0x3b:
+       v = akiko_c2p_read (addr - 0x38);
+       break;
+
+       default:
+       write_log ("akiko_bget: unknown address %08.8X\n", addr);
+       v = 0;
+       break;
+    }
+    akiko_internal ();
+    uae_sem_post (&akiko_sem);
+    if (msg && addr < 0x30 && AKIKO_DEBUG_IO)
+       write_log ("akiko_bget %08.8X: %08.8X %02.2X\n", m68k_getpc(), addr, v & 0xff);
+    return v;
+}
+
+uae_u32 akiko_bget (uaecptr addr)
+{
+    return akiko_bget2 (addr, 1);
+}
+
+uae_u32 akiko_wget (uaecptr addr)
+{
+    uae_u16 v;
+    addr &= 0xffff;
+    v = akiko_bget2 (addr + 1, 0);
+    v |= akiko_bget2 (addr + 0, 0) << 8;
+    if (addr < 0x30 && AKIKO_DEBUG_IO)
+       write_log ("akiko_wget %08.8X: %08.8X %04.4X\n", m68k_getpc(), addr, v & 0xffff);
+    return v;
+}
+
+uae_u32 akiko_lget (uaecptr addr)
+{
+    uae_u32 v;
+
+    addr &= 0xffff;
+    v = akiko_bget2 (addr + 3, 0);
+    v |= akiko_bget2 (addr + 2, 0) << 8;
+    v |= akiko_bget2 (addr + 1, 0) << 16;
+    v |= akiko_bget2 (addr + 0, 0) << 24;
+    if (addr < 0x30 && (addr != 4 && addr != 8) && AKIKO_DEBUG_IO)
+        write_log ("akiko_lget %08.8X: %08.8X %08.8X\n", m68k_getpc(), addr, v);
+    return v;
+}
+
+void akiko_bput2 (uaecptr addr, uae_u32 v, int msg)
+{
+    uae_u32 tmp;
+
+    addr &= 0xffff;
+    v &= 0xff;
+    if(msg && addr < 0x30 && AKIKO_DEBUG_IO)
+        write_log ("akiko_bput %08.8X: %08.8X=%02.2X\n", m68k_getpc(), addr, v & 0xff);
+    uae_sem_wait (&akiko_sem);
+    switch (addr)
+    {
+       case 0x04:
+       case 0x05:
+       case 0x06:
+       case 0x07:
+       akiko_put_long (&cdrom_status1, addr - 0x04, v);
+       break;
+       case 0x08:
+       case 0x09:
+       case 0x0a:
+       case 0x0b:
+       akiko_put_long (&cdrom_status2, addr - 0x08, v);
+       if (addr == 8)
+           cdrom_status1 &= cdrom_status2;
+       break;
+       case 0x10:
+       case 0x11:
+       case 0x12:
+       case 0x13:
+       akiko_put_long (&cdrom_address1, addr - 0x10, v);
+       break;
+       case 0x14:
+       case 0x15:
+       case 0x16:
+       case 0x17:
+       akiko_put_long (&cdrom_address2, addr - 0x14, v);
+       break;
+       case 0x18:
+       cdrom_status3 = v;
+       break;
+       case 0x19:
+       cdrom_command_offset_complete = v;
+       break;
+       case 0x1a:
+       cdrom_result_complete = v;
+       break;
+       case 0x1d:
+       cdrom_command_offset_todo = v;
+       break;
+       case 0x1f:
+       cdrom_result_last_pos = v;
+       break;
+       case 0x20:
+       cdrom_readmask_w |= (v << 8);
+       cdrom_readmask_r &= 0x00ff;
+       break;
+       case 0x21:
+       cdrom_readmask_w |= (v << 0);
+       cdrom_readmask_r &= 0xff00;
+       break;
+       case 0x24:
+       case 0x25:
+       case 0x26:
+       case 0x27:
+       tmp = cdrom_longmask;
+       akiko_put_long (&cdrom_longmask, addr - 0x24, v);
+       if ((cdrom_longmask & 0x04000000) && !(tmp & 0x04000000))
+           cdrom_sector_counter = 0;
+       break;
+
+       case 0x30:
+       case 0x31:
+       case 0x32:
+       case 0x33:
+       akiko_nvram_write (addr - 0x30, v);
+       break;
+
+       case 0x38:
+       case 0x39:
+       case 0x3a:
+       case 0x3b:
+       akiko_c2p_write (addr - 0x38, v);
+       break;
+
+       default:
+       write_log ("akiko_bput: unknown address %08.8X\n", addr);
+       break;
+    }
+    akiko_internal ();
+    uae_sem_post (&akiko_sem);
+}
+
+void akiko_bput (uaecptr addr, uae_u32 v)
+{
+    akiko_bput2 (addr, v, 1);
+}
+
+void akiko_wput (uaecptr addr, uae_u32 v)
+{
+    addr &= 0xfff;
+    if((addr < 0x30 && AKIKO_DEBUG_IO))
+       write_log("akiko_wput %08.8X: %08.8X=%04.4X\n", m68k_getpc(), addr, v & 0xffff);
+    akiko_bput2 (addr + 1, v & 0xff, 0);
+    akiko_bput2 (addr + 0, v >> 8, 0);
+}
+
+void akiko_lput (uaecptr addr, uae_u32 v)
+{
+    addr &= 0xffff;
+    if(addr < 0x30 && AKIKO_DEBUG_IO)
+        write_log("akiko_lput %08.8X: %08.8X=%08.8X\n", m68k_getpc(), addr, v);
+    akiko_bput2 (addr + 3, (v >> 0) & 0xff, 0);
+    akiko_bput2 (addr + 2, (v >> 8) & 0xff, 0);
+    akiko_bput2 (addr + 1, (v >> 16) & 0xff, 0);
+    akiko_bput2 (addr + 0, (v >> 24) & 0xff, 0);
+}
+
+static uae_thread_id akiko_tid;
+
+void akiko_reset (void)
+{
+    cdaudiostop ();
+    nvram_read ();
+    state = I2C_WAIT;
+    bitcounter = -1;
+    direction = -1;
+
+    cdrom_speed = 1;
+    cdrom_current_sector = -1;
+
+    if (akiko_thread_running > 0) {
+       akiko_thread_running = 0;
+       while(akiko_thread_running == 0)
+           Sleep (10);
+       akiko_thread_running = 0;
+    }
+}
+
+extern uae_u32 extendedkickmemory;
+
+static uae_u8 patchdata[]={0x0c,0x82,0x00,0x00,0x03,0xe8,0x64,0x00,0x00,0x46};
+
+static void patchrom (void)
+{
+    int i;
+    uae_u8 *p = (uae_u8*)extendedkickmemory;
+    for (i = 0; i < 524288 - sizeof (patchdata); i++) {
+       if (!memcmp (p + i, patchdata, sizeof(patchdata))) {
+           p[i + 6] = 0x4e;
+           p[i + 7] = 0x71;
+           p[i + 8] = 0x4e;
+           p[i + 9] = 0x71;
+           write_log ("extended rom delay loop patched at 0x%p\n", i + 6 + 0xe00000);
+           return;
+       }
+    }
+    write_log ("couldn't patch extended rom\n");
+}
+
+static int cdromok = 0;
+
+void akiko_free (void)
+{
+    akiko_reset ();
+    if (unitnum >= 0)
+       sys_cddev_close ();
+    unitnum = -1;
+    free (sector_buffer_1);
+    free (sector_buffer_2);
+    free (sector_buffer_info_1);
+    free (sector_buffer_info_2);
+    sector_buffer_1 = 0;
+    sector_buffer_2 = 0;
+    sector_buffer_info_1 = 0;
+    sector_buffer_info_2 = 0;
+    cdromok = 0;
+}
+
+int akiko_init (void)
+{
+    if (cdromok == 0) {
+       unitnum = -1;
+       if (!device_func_init(DEVICE_TYPE_ANY)) {
+           write_log ("no CDROM support\n");
+           return 0;
+       }
+       if (!sys_cddev_open ()) {
+           cdromok = 1;
+           sector_buffer_1 = malloc (SECTOR_BUFFER_SIZE * 2048);
+           sector_buffer_2 = malloc (SECTOR_BUFFER_SIZE * 2048);
+           sector_buffer_info_1 = malloc (SECTOR_BUFFER_SIZE);
+           sector_buffer_info_2 = malloc (SECTOR_BUFFER_SIZE);
+           sector_buffer_sector_1 = -1;
+           sector_buffer_sector_2 = -1;
+           patchrom ();
+       }
+    }
+    if (!savestate_state) {
+        cdrom_playing = cdrom_paused = 0;
+       cdrom_data_offset = -1;
+       uae_sem_init (&akiko_sem, 0, 1);
+    }
+    if (cdromok && !akiko_thread_running) {
+       akiko_thread_running = 1;
+       uae_start_thread (akiko_thread, 0, &akiko_tid);
+    }
+    return 1;
+}
+
+uae_u8 *save_akiko(int *len)
+{
+    uae_u8 *dstbak, *dst;
+    int i;
+
+    dstbak = dst = malloc (1000);
+    save_u16 (0);
+    save_u16 (0xCAFE);
+    save_u32 (cdrom_status1);
+    save_u32 (cdrom_status2);
+    save_u32 (0);
+    save_u32 (cdrom_address1);
+    save_u32 (cdrom_address2);
+    save_u8 (cdrom_status3);
+    save_u8 (cdrom_command_offset_complete);
+    save_u8 (cdrom_result_complete);
+    save_u8 (0);
+    save_u8 (0);
+    save_u8 (cdrom_command_offset_todo);
+    save_u8 (0);
+    save_u8 (cdrom_result_last_pos);
+    save_u16 ((uae_u16)cdrom_readmask_w);
+    save_u16 (0);
+    save_u32 (cdrom_longmask);
+    save_u32 (0);
+    save_u32 (0);
+    save_u32 ((scl_dir ? 0x8000 : 0) | (sda_dir ? 0x4000 : 0));
+    save_u32 (0);
+    save_u32 (0);
+
+    for (i = 0; i < 8; i++)
+       save_u32 (akiko_buffer[i]);
+    save_u8 ((uae_u8)akiko_read_offset);
+    save_u8 ((uae_u8)akiko_write_offset);
+    
+    save_u32 ((cdrom_playing ? 1 : 0) | (cdrom_paused ? 2 : 0));
+    if (cdrom_playing)
+       cd_qcode (0);
+    save_u32 (last_play_pos);
+    save_u32 (last_play_end);
+    save_u8 ((uae_u8)cdrom_toc_counter);
+
+    *len = dst - dstbak;
+    return dstbak;
+}
+
+uae_u8 *restore_akiko(uae_u8 *src)
+{
+    uae_u32 v;
+    int i;
+
+    restore_u16 ();
+    restore_u16 ();
+    cdrom_status1 = restore_u32 ();
+    cdrom_status2 = restore_u32 ();
+    restore_u32();
+    cdrom_address1 = restore_u32 ();
+    cdrom_address2 = restore_u32 ();
+    cdrom_status3 = restore_u8 ();
+    cdrom_command_offset_complete = restore_u8 ();
+    cdrom_result_complete = restore_u8 ();
+    restore_u8 ();
+    restore_u8 ();
+    cdrom_command_offset_todo = restore_u8 ();
+    restore_u8 ();
+    cdrom_result_last_pos = restore_u8 ();
+    cdrom_readmask_w = restore_u16 ();
+    restore_u16 ();
+    cdrom_longmask = restore_u32 ();
+    restore_u32();
+    restore_u32();
+    v = restore_u32();
+    scl_dir = (v & 0x8000) ? 1 : 0;
+    sda_dir = (v & 0x4000) ? 1 : 0;
+    restore_u32();
+    restore_u32();
+
+    for (i = 0; i < 8; i++)
+       akiko_buffer[i] = restore_u32 ();
+    akiko_read_offset = restore_u8 ();
+    akiko_write_offset = restore_u8 ();
+    akiko_c2p_do ();
+
+    cdrom_playing = cdrom_paused = 0;
+    v = restore_u32 ();
+    if (v & 1)
+       cdrom_playing = 1;
+    if (v & 2)
+       cdrom_paused = 1;
+    last_play_pos = restore_u32 ();
+    last_play_end = restore_u32 ();
+    cdrom_toc_counter = restore_u8 ();
+    if (cdrom_toc_counter == 255)
+       cdrom_toc_counter = -1;
+    if (cdrom_playing)
+       sys_command_play (DF_IOCTL, unitnum, last_play_pos, last_play_end, 0);
+
+    return src;
+}
+void akiko_entergui (void)
+{
+    if (cdrom_playing)
+        sys_command_pause (DF_IOCTL, unitnum, 1);
+}
+void akiko_exitgui (void)
+{
+    if (cdrom_playing)
+       sys_command_pause (DF_IOCTL, unitnum, 0);
+}
+
diff --git a/akiko2.c b/akiko2.c
new file mode 100755 (executable)
index 0000000..8891692
--- /dev/null
+++ b/akiko2.c
@@ -0,0 +1,1393 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * CD32 Akiko emulation
+  *
+  * - C2P
+  * - NVRAM
+  * - CDROM
+  *
+  * Copyright 2001, 2002 Toni Wilen
+  *
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "memory.h"
+#include "events.h"
+#include "savestate.h"
+#include "blkdev.h"
+#include "zfile.h"
+#include "threaddep/thread.h"
+#include "akiko.h"
+
+#define AKIKO_DEBUG_NVRAM 0
+#define AKIKO_DEBUG_IO 1
+#define AKIKO_DEBUG_IO_CMD 1
+
+int cd32_enabled;
+
+static int m68k_getpc(void) { return 0; }
+
+/*
+ * CD32 1Kb NVRAM (EEPROM) emulation
+ *
+ * NVRAM chip is 24C08 CMOS EEPROM (1024x8 bits = 1Kb)
+ * Chip interface is I2C (2 wire serial)
+ * Akiko addresses used:
+ * 0xb80030: bit 7 = SCL (clock), 6 = SDA (data)
+ * 0xb80032: 0xb80030 data direction register (0 = input, 1 = output)
+ *
+ * Because I don't have any experience on I2C, following code may be
+ * unnecessarily complex and not 100% correct..
+ */
+
+enum i2c { I2C_WAIT, I2C_START, I2C_DEVICEADDR, I2C_WORDADDR, I2C_DATA };
+
+/* size of EEPROM, don't try to change,
+ * (hardcoded in Kickstart)
+ */
+#define NVRAM_SIZE 1024
+/* max size of one write request */
+#define NVRAM_PAGE_SIZE 16
+
+static uae_u8 cd32_nvram[NVRAM_SIZE], nvram_writetmp[NVRAM_PAGE_SIZE];
+static int nvram_address, nvram_writeaddr;
+static int nvram_rw;
+static int bitcounter = -1, direction = -1;
+static uae_u8 nvram_byte;
+static int scl_out, scl_in, scl_dir, oscl, sda_out, sda_in, sda_dir, osda;
+static int sda_dir_nvram;
+static int state = I2C_WAIT;
+
+static void nvram_write (int offset, int len)
+{
+    struct zfile *f = zfile_fopen (currprefs.flashfile, "rb+");
+    if (!f) {
+        f = zfile_fopen (currprefs.flashfile, "wb");
+        if (!f) return;
+        zfile_fwrite (cd32_nvram, NVRAM_SIZE, 1, f);
+        zfile_fclose (f);
+    }
+    zfile_fseek (f, offset, SEEK_SET);
+    zfile_fwrite (cd32_nvram + offset, len, 1, f);
+    zfile_fclose (f);
+}
+
+static void nvram_read (void)
+{
+    struct zfile *f;
+
+    f = zfile_fopen (currprefs.flashfile, "rb");
+    memset (cd32_nvram, 0, NVRAM_SIZE);
+    if (!f) return;
+    zfile_fread (cd32_nvram, NVRAM_SIZE, 1, f);
+    zfile_fclose (f);
+}
+
+static void i2c_do (void)
+{
+#if AKIKO_DEBUG_NVRAM
+    int i;
+#endif
+    sda_in = 1;
+    if (!sda_dir_nvram && scl_out && oscl) {
+       if (!sda_out && osda) { /* START-condition? */
+           state = I2C_DEVICEADDR;
+           bitcounter = 0;
+           direction = -1;
+#if AKIKO_DEBUG_NVRAM
+           write_log ("START\n");
+#endif
+           return;
+       } else if(sda_out && !osda) { /* STOP-condition? */
+           state = I2C_WAIT;
+           bitcounter = -1;
+#if AKIKO_DEBUG_NVRAM
+           write_log ("STOP\n");
+#endif
+           if (direction > 0) {
+               memcpy (cd32_nvram + (nvram_address & ~(NVRAM_PAGE_SIZE - 1)), nvram_writetmp, NVRAM_PAGE_SIZE);
+               nvram_write (nvram_address & ~(NVRAM_PAGE_SIZE - 1), NVRAM_PAGE_SIZE);
+               direction = -1;
+#if AKIKO_DEBUG_NVRAM
+               write_log ("NVRAM write address %04.4X:", nvram_address & ~(NVRAM_PAGE_SIZE - 1));
+               for (i = 0; i < NVRAM_PAGE_SIZE; i++)
+                   write_log ("%02.2X", nvram_writetmp[i]);
+               write_log ("\n");
+
+#endif
+           }
+           return;
+       }
+    } 
+    if (bitcounter >= 0) {
+       if (direction) {
+           /* Amiga -> NVRAM */
+           if (scl_out && !oscl) {
+               if (bitcounter == 8) {
+#if AKIKO_DEBUG_NVRAM
+                   write_log ("RB %02.2X ", nvram_byte, m68k_getpc());
+#endif
+                   sda_in = 0; /* ACK */
+                   if (direction > 0) {
+                       nvram_writetmp[nvram_writeaddr++] = nvram_byte;
+                       nvram_writeaddr &= 15;
+                       bitcounter = 0;
+                   } else {
+                       bitcounter = -1;
+                   }
+               } else {
+                   //write_log("NVRAM received bit %d, offset %d\n", sda_out, bitcounter);
+                   nvram_byte <<= 1;
+                   nvram_byte |= sda_out;
+                   bitcounter++;
+               }
+           }
+       } else {
+           /* NVRAM -> Amiga */
+           if (scl_out && !oscl && bitcounter < 8) {
+               if (bitcounter == 0)
+                   nvram_byte = cd32_nvram[nvram_address];
+               sda_dir_nvram = 1;
+               sda_in = (nvram_byte & 0x80) ? 1 : 0;
+               //write_log("NVRAM sent bit %d, offset %d\n", sda_in, bitcounter);
+               nvram_byte <<= 1;
+               bitcounter++;
+               if (bitcounter == 8) {
+#if AKIKO_DEBUG_NVRAM
+                   write_log ("NVRAM sent byte %02.2X address %04.4X PC=%08.8X\n", cd32_nvram[nvram_address], nvram_address, m68k_getpc());
+#endif
+                   nvram_address++;
+                   nvram_address &= NVRAM_SIZE - 1;
+                   sda_dir_nvram = 0;
+               }
+           }
+           if(!sda_out && sda_dir && !scl_out) /* ACK from Amiga */
+               bitcounter = 0;
+       }
+       if (bitcounter >= 0) return;
+    }
+    switch (state)
+    {
+       case I2C_DEVICEADDR:
+       if ((nvram_byte & 0xf0) != 0xa0) {
+           write_log ("WARNING: I2C_DEVICEADDR: device address != 0xA0\n");
+           state = I2C_WAIT;
+           return;
+       }
+       nvram_rw = (nvram_byte & 1) ? 0 : 1;
+       if (nvram_rw) {
+           /* 2 high address bits, only fetched if WRITE = 1 */
+           nvram_address &= 0xff;
+           nvram_address |= ((nvram_byte >> 1) & 3) << 8;
+           state = I2C_WORDADDR;
+           direction = -1;
+       } else {
+           state = I2C_DATA;
+           direction = 0;
+           sda_dir_nvram = 1;
+       }
+       bitcounter = 0;
+#if AKIKO_DEBUG_NVRAM
+       write_log ("I2C_DEVICEADDR: rw %d, address %02.2Xxx PC=%08.8X\n", nvram_rw, nvram_address >> 8, m68k_getpc());
+#endif
+       break;
+       case I2C_WORDADDR:
+       nvram_address &= 0x300;
+       nvram_address |= nvram_byte;
+#if AKIKO_DEBUG_NVRAM
+       write_log ("I2C_WORDADDR: address %04.4X PC=%08.8X\n", nvram_address, m68k_getpc());
+#endif
+       if (direction < 0) {
+           memcpy (nvram_writetmp, cd32_nvram + (nvram_address & ~(NVRAM_PAGE_SIZE - 1)), NVRAM_PAGE_SIZE);
+           nvram_writeaddr = nvram_address & (NVRAM_PAGE_SIZE - 1);
+       }
+       state = I2C_DATA;
+       bitcounter = 0;
+       direction = 1;
+       break;
+    }
+}
+
+static void akiko_nvram_write (int offset, uae_u32 v)
+{
+    int sda;
+    switch (offset)
+    {
+       case 0:
+       oscl = scl_out;
+       scl_out = (v & 0x80) ? 1 : 0;
+       osda = sda_out;
+       sda_out = (v & 0x40) ? 1 : 0;
+       break;
+       case 2:
+       scl_dir = (v & 0x80) ? 1 : 0;
+       sda_dir = (v & 0x40) ? 1 : 0;
+       break;
+       default:
+       return;
+    }
+    sda = sda_out;
+    if (oscl != scl_out || osda != sda) {
+       i2c_do ();
+       oscl = scl_out;
+       osda = sda;
+    }
+}
+
+static uae_u32 akiko_nvram_read (int offset)
+{
+    uae_u32 v = 0;
+    switch (offset)
+    {
+       case 0:
+       if (!scl_dir)
+           v |= scl_in ? 0x80 : 0x00;
+           else
+           v |= scl_out ? 0x80 : 0x00;
+       if (!sda_dir)
+           v |= sda_in ? 0x40 : 0x00;
+           else
+           v |= sda_out ? 0x40 : 0x00;
+       break;
+       case 2:
+       v |= scl_dir ? 0x80 : 0x00;
+       v |= sda_dir ? 0x40 : 0x00;
+       break;
+    }
+    return v;
+}
+
+/* CD32 Chunky to Planar hardware emulation
+ * Akiko addresses used:
+ * 0xb80038-0xb8003b
+ */
+
+static uae_u32 akiko_buffer[8];
+static int akiko_read_offset, akiko_write_offset;
+static uae_u32 akiko_result[8];
+
+static void akiko_c2p_do (void)
+{
+    int i;
+
+    for (i = 0; i < 8; i++) akiko_result[i] = 0;
+    /* FIXME: better c2p algoritm than this piece of crap.... */
+    for (i = 0; i < 8 * 32; i++) {
+        if (akiko_buffer[7 - (i >> 5)] & (1 << (i & 31)))
+            akiko_result[i & 7] |= 1 << (i >> 3);
+    }
+}
+
+static void akiko_c2p_write (int offset, uae_u32 v)
+{
+    if (offset == 3) akiko_buffer[akiko_write_offset] = 0;
+    akiko_buffer[akiko_write_offset] |= v << ( 8 * (3 - offset));
+    if (offset == 0) {
+       akiko_write_offset++;
+       akiko_write_offset &= 7;
+    }
+    akiko_read_offset = 0;
+}
+
+static uae_u32 akiko_c2p_read (int offset)
+{
+    uae_u32 v;
+
+    if (akiko_read_offset == 0 && offset == 3)
+       akiko_c2p_do ();
+    akiko_write_offset = 0;
+    v = akiko_result[akiko_read_offset];
+    if (offset == 0) {
+       akiko_read_offset++;
+       akiko_read_offset &= 7;
+    }
+    return v >> (8 * (3 - offset));
+}
+
+/* CD32 CDROM hardware emulation
+ * Akiko addresses used:
+ * 0xb80004-0xb80028
+ *
+ * I can't believe cd.device and custom loaders are fooled to think
+ * this piece of crap emulates real CD32 CDROM controller and drive :)
+ */
+
+#define CDSTATUS_FRAME             0x80000000
+#define CDSTATUS_DATA_AVAILABLE            0x10000000
+#define CDSTATUS_DATASECTOR_ERROR   0x08000000 /* ?? */
+#define CDSTATUS_DATASECTOR        0x04000000
+
+#define CDS_ERROR 0x80
+#define CDS_PLAYING 0x08
+
+static uae_u32 cdrom_status1, cdrom_status2;
+static uae_u8 cdrom_status3;
+static uae_u32 cdrom_address1, cdrom_address2;
+static uae_u32 cdrom_longmask;
+static uae_u32 cdrom_readmask_r, cdrom_readmask_w;
+static uae_u8 cdrom_command_offset_complete; /* 0x19 */
+static uae_u8 cdrom_command_offset_todo; /* 0x1d */
+static uae_u8 cdrom_result_complete; /* 0x1a */
+static uae_u8 cdrom_result_last_pos; /* 0x1f */
+static uae_u8 cdrom_result_buffer[32];
+static uae_u8 cdrom_command_buffer[32];
+static uae_u8 cdrom_command;
+
+#define MAX_TOC_ENTRIES 103 /* tracks 1-99, A0,A1 and A2 */
+static int cdrom_toc_entries;
+static int cdrom_toc_counter;
+static uae_u8 cdrom_toc_buffer[MAX_TOC_ENTRIES*13];
+
+static int cdrom_disk, cdrom_paused, cdrom_playing;
+static int cdrom_command_active;
+static int cdrom_command_length;
+static int cdrom_checksum_error;
+static int cdrom_data_offset, cdrom_speed, cdrom_sector_counter;
+static int cdrom_current_sector;
+static int cdrom_data_end, cdrom_leadout;
+static int cdrom_dosomething;
+
+static uae_u8 *sector_buffer_1, *sector_buffer_2;
+static int sector_buffer_sector_1, sector_buffer_sector_2;
+#define SECTOR_BUFFER_SIZE 64
+static uae_u8 *sector_buffer_info_1, *sector_buffer_info_2;
+
+static int unitnum = -1;
+
+static uae_u8 frombcd (uae_u8 v)
+{
+    return (v >> 4) * 10 + (v & 15);
+}
+
+static uae_u8 tobcd (uae_u8 v)
+{
+    return ((v / 10) << 4) | (v % 10);
+}
+
+static int fromlongbcd (uae_u8 *p)
+{
+    return (frombcd (p[0]) << 16) | (frombcd (p[1]) << 8) | (frombcd (p[2])  << 0);
+}
+
+/* convert minutes, seconds and frames -> logical sector number */
+static int msf2lsn (int msf)
+{
+    int sector = (((msf >> 16) & 0xff) * 60 * 75 + ((msf >> 8) & 0xff) * 75 + ((msf >> 0) & 0xff)) - 150;
+    if (sector < 0)
+       sector = 0;
+    return sector;
+}
+
+/* convert logical sector number -> minutes, seconds and frames */
+static int lsn2msf (int sectors)
+{
+    int msf;
+    sectors += 150;
+    msf = (sectors / (75 * 60)) << 16;
+    msf |= ((sectors / 75) % 60) << 8;
+    msf |= (sectors % 75) << 0;
+    return msf;
+}
+
+static uae_u32 last_play_end;
+static int cd_play_audio (uae_u32 startmsf, uae_u32 endmsf, int scan)
+{
+    if (endmsf == 0xffffffff)
+       endmsf = last_play_end;
+    else
+       last_play_end = endmsf;
+    return sys_command_play (DF_IOCTL, unitnum,startmsf, endmsf, scan);
+}
+
+
+/* read qcode */
+static uae_u32 last_play_pos;
+static int cd_qcode (uae_u8 *d)
+{
+    uae_u8 *buf, *s, as;
+
+    if (d)
+        memset (d, 0, 11);
+    last_play_pos = 0;
+    buf = sys_command_qcode (DF_IOCTL, unitnum);
+    if (!buf)
+       return 0;
+    as = buf[1];
+    if (as != 0x11 && as != 0x12 && as != 0x13 && as != 0x15) /* audio status ok? */
+       return 0;
+    s = buf + 4;
+    last_play_pos = (s[9] << 16) | (s[10] << 8) | (s[11] << 0);
+    if (!d)
+       return 0;
+    /* ??? */
+    d[0] = 0;
+    /* CtlAdr */
+    d[1] = (s[1] >> 4) | (s[1] << 4);
+    /* Track */
+    d[2] = tobcd (s[2]);
+    /* Index */
+    d[3] = tobcd (s[3]);
+    /* TrackPos */
+    d[4] = tobcd (s[9]);
+    d[5] = tobcd (s[10]);
+    d[6] = tobcd (s[11]);
+    /* DiskPos */
+    d[7] = 0;
+    d[8] = tobcd (s[5]);
+    d[9] = tobcd (s[6]);
+    d[10] = tobcd (s[7]);
+    if (as == 0x15) {
+       /* Make sure end of disc position is passed.
+        */
+       int lsn = msf2lsn ((s[5] << 16) | (s[6] << 8) | (s[7] << 0));
+        int msf = lsn2msf (cdrom_leadout);
+       if (lsn >= cdrom_leadout || cdrom_leadout - lsn < 10) {
+           d[8] = tobcd ((uae_u8)(msf >> 16));
+           d[9] = tobcd ((uae_u8)(msf >> 8));
+           d[10] = tobcd ((uae_u8)(msf >> 0));
+       }
+    }
+
+    return 0;
+}
+
+/* read toc */
+static int cdrom_toc (void)
+{
+    int i, j;
+    int datatrack = 0, secondtrack = 0;
+    uae_u8 *s, *d, *buf;
+
+    cdrom_toc_counter = -1;
+    cdrom_toc_entries = 0;
+    buf = sys_command_toc (DF_IOCTL, unitnum);
+    if (!buf)
+       return 1;
+    i = (buf[0] << 8) | (buf[1] << 0);
+    i -= 2;
+    i /= 11;
+    if (i > MAX_TOC_ENTRIES)
+       return -1;
+    memset (cdrom_toc_buffer, 0, MAX_TOC_ENTRIES * 13);
+    cdrom_data_end = -1;
+    for (j = 0; j < i; j++) {
+       s = buf + 4 + j * 11;
+       d = &cdrom_toc_buffer[j * 13];
+       d[1] = (s[1] >> 4) | (s[1] << 4);
+       d[3] = s[3] < 100 ? tobcd(s[3]) : s[3];
+       d[8] = tobcd (s[8]);
+       d[9] = tobcd (s[9]);
+       d[10] = tobcd (s[10]);
+       if (s[3] == 1 && (s[1] & 0x0f) == 0x04)
+           datatrack = 1;
+       if (s[3] == 2)
+           secondtrack = msf2lsn ((s[8] << 16) | (s[9] << 8) | (s[10] << 0));
+       if (s[3] == 0xa2)
+           cdrom_leadout = msf2lsn ((s[8] << 16) | (s[9] << 8) | (s[10] << 0));
+    }
+    if (datatrack) {
+       if (secondtrack)
+           cdrom_data_end = secondtrack;
+       else
+           cdrom_data_end = cdrom_leadout;
+    }
+    cdrom_toc_entries = i;
+    return 0;
+}
+
+/* open device */
+static int sys_cddev_open (void)
+{
+    int first = -1;
+    int found = 0;
+    struct device_info di1, *di2;
+
+    for (unitnum = 0; unitnum < MAX_TOTAL_DEVICES; unitnum++) {
+       di2 = sys_command_info (DF_IOCTL, unitnum, &di1);
+       if (di2 && di2->type == INQ_ROMD) {
+           if (sys_command_open (DF_IOCTL, unitnum)) {
+               if (first < 0)
+                   first = unitnum;
+               if (!cdrom_toc ()) {
+                   found = 1;
+                   break;
+               }
+               sys_command_close (DF_IOCTL, unitnum);
+           }
+       }
+    }
+    if (!found) {
+       if (first >= 0) {
+           unitnum = first;
+            sys_command_open (DF_IOCTL, unitnum);
+       } else {
+           unitnum = -1;
+           return 1;
+       }
+    }
+    /* make sure CD audio is not playing */
+    sys_command_pause (DF_IOCTL, unitnum, 0);
+    sys_command_stop (DF_IOCTL, unitnum);
+    sys_command_pause (DF_IOCTL, unitnum, 1);
+    return 0;
+}
+
+/* close device */
+static void sys_cddev_close (void)
+{
+    sys_command_pause (DF_IOCTL, unitnum, 0);
+    sys_command_stop (DF_IOCTL, unitnum);
+    sys_command_pause (DF_IOCTL, unitnum, 1);
+    sys_command_close (DF_IOCTL, unitnum);
+}
+
+static int command_lengths[] = { 1,2,1,1,12,2,1,1,4,1,-1,-1,-1,-1,-1 };
+
+static void cdrom_return_data (int len)
+{
+    uae_u32 cmd_buf = cdrom_address2;
+    int i;
+    uae_u8 checksum;
+
+    if (len <= 0) return;
+#if AKIKO_DEBUG_IO_CMD
+    write_log ("OUT:");
+#endif
+    checksum = 0xff;
+    for (i = 0; i < len; i++) {
+       checksum -= cdrom_result_buffer[i];
+       put_byte (cmd_buf + ((cdrom_result_complete + i) & 0xff), cdrom_result_buffer[i]);
+#if AKIKO_DEBUG_IO_CMD
+       write_log ("%02.2X ", cdrom_result_buffer[i]);
+#endif
+    }
+    put_byte (cmd_buf + ((cdrom_result_complete + len) & 0xff), checksum);
+#if AKIKO_DEBUG_IO_CMD
+    write_log ("%02.2X\n", checksum);
+#endif
+    cdrom_result_complete += len + 1;
+    cdrom_status1 |= CDSTATUS_DATA_AVAILABLE;
+}
+
+static int cdrom_command_something (void)
+{
+    return 0;
+}
+
+static int cdrom_command_media_status (void)
+{
+    struct device_info di;
+
+    cdrom_result_buffer[0] = cdrom_command;
+    cdrom_result_buffer[1] = sys_command_info (DF_IOCTL, unitnum, &di)->media_inserted ?  1 : 0;
+    return 2;
+}
+
+/* check if cd drive door is open or closed */
+static int cdrom_command_door_status (void)
+{
+    struct device_info di;
+    if (!sys_command_info (DF_IOCTL, unitnum, &di)->media_inserted) {
+       cdrom_result_buffer[1] = 0x80;
+       cdrom_disk = 0;
+    } else {
+       cdrom_result_buffer[1] = 1;
+       cdrom_disk = 1;
+    }
+    cdrom_toc ();
+    cdrom_result_buffer[0] = cdrom_command;
+    return 20;
+}
+
+/* return one TOC entry */
+static int cdrom_return_toc_entry (void)
+{
+    cdrom_result_buffer[0] = 6;
+    if (cdrom_toc_entries == 0) {
+       cdrom_result_buffer[1] = CDS_ERROR;
+       return 15;
+    }
+    cdrom_result_buffer[1] = 0;
+    memcpy (cdrom_result_buffer + 2, cdrom_toc_buffer + cdrom_toc_counter * 13, 13);
+    cdrom_toc_counter++;
+    if (cdrom_toc_counter >= cdrom_toc_entries)
+       cdrom_toc_counter = 0;
+    return 15;
+}
+
+/* pause CD audio */
+static int cdrom_command_pause (void)
+{
+    cdrom_toc_counter = -1;
+    cdrom_result_buffer[0] = cdrom_command;
+    cdrom_result_buffer[1] = cdrom_playing ? CDS_PLAYING : 0;
+    if (!cdrom_playing)
+       return 2;
+    if (cdrom_paused)
+       return 2;
+    sys_command_pause (DF_IOCTL, unitnum, 1);
+    cdrom_paused = 1;
+    return 2;
+}
+
+/* unpause CD audio */
+static int cdrom_command_unpause (void)
+{
+    cdrom_result_buffer[0] = cdrom_command;
+    cdrom_result_buffer[1] = cdrom_playing ? CDS_PLAYING : 0;
+    if (!cdrom_paused)
+       return 2;
+    if (!cdrom_playing)
+       return 2;
+    cdrom_paused = 0;
+    sys_command_pause (DF_IOCTL, unitnum, 0);
+    return 2;
+}
+
+/* seek head/play CD audio/read data sectors */
+static int cdrom_command_multi (void)
+{
+    int seekpos = fromlongbcd (cdrom_command_buffer + 1);
+    int endpos = fromlongbcd (cdrom_command_buffer + 4);
+
+    cdrom_playing = 0;
+    cdrom_speed = (cdrom_command_buffer[8] & 0x40) ? 2 : 1;
+    cdrom_result_buffer[0] = cdrom_command;
+    cdrom_result_buffer[1] = 0;
+    if (!cdrom_disk) {
+       cdrom_result_buffer[1] |= CDS_ERROR;
+       return 2;
+    }
+
+    if (cdrom_command_buffer[7] == 0x80) {    /* data read */
+       int cdrom_data_offset_end = msf2lsn (endpos);
+       cdrom_data_offset = msf2lsn (seekpos);
+#if AKIKO_DEBUG_IO_CMD
+       write_log ("READ DATA FROM %06.6X (%d) TO %06.6X (%d) SPEED=%dx\n", seekpos, cdrom_data_offset, endpos, cdrom_data_offset_end, cdrom_speed);
+#endif
+       cdrom_result_buffer[1] |= 0x02;
+    } else if (cdrom_command_buffer[10] & 4) { /* play audio */
+       int scan = 0;
+       if (cdrom_command_buffer[7] & 0x04)
+           scan = 1;
+       else if (cdrom_command_buffer[7] & 0x08)
+           scan = -1;
+#if AKIKO_DEBUG_IO_CMD
+       write_log ("PLAY FROM %06.6X to %06.6X SCAN=%d\n", seekpos, endpos, scan);
+#endif
+       if (!cd_play_audio (seekpos, endpos, 0)) {
+           cdrom_result_buffer[1] = CDS_ERROR;
+       } else {
+           cdrom_playing = 1;
+           cdrom_result_buffer[1] |= CDS_PLAYING;
+       }
+    } else {
+#if AKIKO_DEBUG_IO_CMD
+       write_log ("SEEKTO %06.6X\n",seekpos);
+#endif
+       if (seekpos < 150)
+           cdrom_toc_counter = 0;
+       else
+           cdrom_toc_counter = -1;
+    }
+    return 2;
+}
+
+/* return subq entry */
+static int cdrom_command_subq (void)
+{
+    cdrom_result_buffer[0] = cdrom_command;
+    cdrom_result_buffer[1] = 0;
+    if (cd_qcode (cdrom_result_buffer + 2))
+       cdrom_result_buffer[1] = CDS_ERROR;
+    return 15;
+}
+
+static void cdrom_run_command (void)
+{
+    uae_u32 cmd_buf = cdrom_address2 + 0x200;
+    int i, cmd_len;
+    uae_u8 checksum;
+
+    for (;;) {
+       if (cdrom_command_active)
+           return;
+       if (cdrom_command_offset_complete == cdrom_command_offset_todo)
+           return;
+       cdrom_command = get_byte (cmd_buf + cdrom_command_offset_complete);
+       if ((cdrom_command & 0xf0) == 0)
+           return;
+       cdrom_checksum_error = 0;
+       cmd_len = command_lengths[cdrom_command & 0x0f];
+       if (cmd_len < 0) {
+#if AKIKO_DEBUG_IO_CMD
+           write_log ("unknown command\n");
+#endif
+           cmd_len = 1;
+       }
+#if AKIKO_DEBUG_IO_CMD
+       write_log ("IN:");
+#endif
+       checksum = 0;
+       for (i = 0; i < cmd_len + 1; i++) {
+           cdrom_command_buffer[i] = get_byte (cmd_buf + ((cdrom_command_offset_complete + i) & 0xff));
+           checksum += cdrom_command_buffer[i];
+#if AKIKO_DEBUG_IO_CMD
+           write_log ("%02.2X ", cdrom_command_buffer[i]);
+#endif
+       }
+       if (checksum!=0xff) {
+#if AKIKO_DEBUG_IO_CMD
+           write_log (" checksum error");
+#endif
+           cdrom_checksum_error = 1;
+       }
+#if AKIKO_DEBUG_IO_CMD
+       write_log ("\n");
+#endif
+       cdrom_command_active = 1;
+       cdrom_command_length = cmd_len;
+       return;
+    }
+}
+
+static void cdrom_run_command_run (void)
+{
+    int len;
+
+    cdrom_command_offset_complete = (cdrom_command_offset_complete + cdrom_command_length + 1) & 0xff;
+    memset (cdrom_result_buffer, 0, sizeof(cdrom_result_buffer));
+    switch (cdrom_command & 0x0f)
+    {
+        case 2:
+        len = cdrom_command_pause ();
+        break;
+        case 3:
+        len = cdrom_command_unpause ();
+        break;
+        case 4:
+        len = cdrom_command_multi ();
+        break;
+       case 5:
+       cdrom_dosomething = 1;
+       len = cdrom_command_something ();
+       break;
+        case 6:
+        len = cdrom_command_subq ();
+        break;
+        case 7:
+        len = cdrom_command_door_status ();
+        break;
+        default:
+        len = 0;
+        break;
+    }
+    if (len == 0)
+        return;
+    if (cdrom_checksum_error)
+        cdrom_result_buffer[1] |= 0x80;
+    cdrom_return_data (len);
+}
+
+extern void encode_l2 (uae_u8 *p, int address);
+
+/* DMA transfer one CD sector */
+static void cdrom_run_read (void)
+{
+    int i, j, sector;
+    int read = 0;
+    uae_u8 buf[2352];
+    int sec;
+
+    if (!(cdrom_longmask & 0x04000000))
+       return;
+    if (!cdrom_readmask_w)
+       return;
+    if (cdrom_data_offset < 0)
+       return;
+    if (unitnum >= 0) {
+       for (j = 0; j < 16; j++) {
+           if (cdrom_readmask_w & (1 << j)) break;
+       }
+        sector = cdrom_current_sector = cdrom_data_offset + cdrom_sector_counter;
+        sec = sector - sector_buffer_sector_1;
+        if (sector_buffer_sector_1 >= 0 && sec >= 0 && sec < SECTOR_BUFFER_SIZE) {
+           if (sector_buffer_info_1[sec] != 0xff && sector_buffer_info_1[sec] != 0) {
+               memcpy (buf + 16, sector_buffer_1 + sec * 2048, 2048);
+               encode_l2 (buf, sector + 150);
+               buf[0] = 0;
+               buf[1] = 0;
+               buf[2] = 0;
+               buf[3] = cdrom_sector_counter;
+               for (i = 0; i < 2352; i++)
+                   put_byte (cdrom_address1 + j * 4096 + i, buf[i]);
+               cdrom_readmask_r |= 1 << j;
+           }
+           if (sector_buffer_info_1[sec] != 0xff)
+               sector_buffer_info_1[sec]--;
+       } else
+           return;
+#if AKIKO_DEBUG_IO_CMD
+        write_log("read sector=%d, scnt=%d -> %d\n", cdrom_data_offset, cdrom_sector_counter, sector);
+#endif
+       cdrom_readmask_w &= ~(1 << j);
+        cdrom_status1 |= CDSTATUS_DATASECTOR;
+    }
+    cdrom_sector_counter++;
+}
+
+static uae_sem_t akiko_sem;
+
+static void akiko_handler (void)
+{
+    static int mediacheckcnt;
+    struct device_info di;
+
+    if (cdrom_result_complete > cdrom_result_last_pos && cdrom_result_complete - cdrom_result_last_pos < 100) {
+        cdrom_status1 |= CDSTATUS_DATA_AVAILABLE;
+       return;
+    }
+    if (cdrom_result_last_pos < cdrom_result_complete)
+       return;
+    if (mediacheckcnt > 0)
+       mediacheckcnt--;
+    if (mediacheckcnt == 0) {
+       int media = sys_command_info (DF_IOCTL, unitnum, &di)->media_inserted;
+       if (media != cdrom_disk) {
+           write_log ("media changed = %d\n", media);
+           cdrom_disk = media;
+           cdrom_return_data (cdrom_command_media_status ());
+           cdrom_toc ();
+           return;
+       }
+       mediacheckcnt = 312 * 50 * 2;
+    }
+    if (cdrom_toc_counter >= 0 && !cdrom_command_active && cdrom_dosomething) {
+       cdrom_return_data (cdrom_return_toc_entry ());
+       cdrom_dosomething--;
+       return;
+    }
+}
+       
+static void akiko_internal (void)
+{
+    cdrom_run_command ();
+    if (cdrom_command_active > 0) {
+        cdrom_command_active--;
+        if (!cdrom_command_active)
+           cdrom_run_command_run ();
+    }
+}
+
+extern int cd32_enabled;
+
+void AKIKO_hsync_handler (void)
+{
+    static int framecounter;
+
+    if (!cd32_enabled)
+       return;
+    framecounter--;
+    if (framecounter <= 0) {
+       cdrom_run_read ();
+       framecounter = 1000000 / (74 * 75 * cdrom_speed);
+        cdrom_status1 |= CDSTATUS_FRAME;
+    }
+    akiko_internal ();
+    akiko_handler ();
+}
+
+
+static volatile int akiko_thread_running;
+
+/* cdrom data buffering thread */
+static void *akiko_thread (void *null)
+{
+    int i;
+    uae_u8 *tmp1;
+    uae_u8 *tmp2;
+    int tmp3;
+    uae_u8 *p;
+    int offset;
+    int sector;
+
+    while(akiko_thread_running) {
+        uae_sem_wait (&akiko_sem);
+       sector = cdrom_current_sector;
+       for (i = 0; i < SECTOR_BUFFER_SIZE; i++) {
+           if (sector_buffer_info_1[i] == 0xff) break;
+       }
+       if (cdrom_data_end > 0 && sector >= 0 && (sector_buffer_sector_1 < 0 || sector < sector_buffer_sector_1 || sector >= sector_buffer_sector_1 + SECTOR_BUFFER_SIZE * 2 / 3 || i != SECTOR_BUFFER_SIZE)) {
+           memset (sector_buffer_info_2, 0, SECTOR_BUFFER_SIZE);
+#if AKIKO_DEBUG_IO_CMD
+           write_log("filling buffer sector=%d (max=%d)\n", sector, cdrom_data_end);
+#endif
+           sector_buffer_sector_2 = sector;
+           offset = 0;
+           while (offset < SECTOR_BUFFER_SIZE) {
+               p = 0;
+               if (sector < cdrom_data_end)
+                   p = sys_command_read (DF_IOCTL, unitnum, sector);
+               if (p)
+                   memcpy (sector_buffer_2 + offset * 2048, p, 2048);
+               sector_buffer_info_2[offset] = p ? 3 : 0;
+               offset++;
+               sector++;
+           }
+           tmp1 = sector_buffer_info_1;
+           sector_buffer_info_1 = sector_buffer_info_2;
+           sector_buffer_info_2 = tmp1;
+           tmp2 = sector_buffer_1;
+           sector_buffer_1 = sector_buffer_2;
+           sector_buffer_2 = tmp2;
+           tmp3 = sector_buffer_sector_1;
+           sector_buffer_sector_1 = sector_buffer_sector_2;
+           sector_buffer_sector_2 = tmp3;
+       }
+        uae_sem_post (&akiko_sem);
+       Sleep (10);
+    }
+    akiko_thread_running = -1;
+    return 0;
+}
+
+static uae_u8 akiko_get_long (uae_u32 v, int offset)
+{
+    return v >> ((3 - offset) * 8);
+}
+static void akiko_put_long (uae_u32 *p, int offset, int v)
+{
+    *p &= ~(0xff << ((3 - offset) * 8));
+    *p |= v << ((3 - offset) * 8);
+}
+
+uae_u32 akiko_bget2 (uaecptr addr, int msg)
+{
+    uae_u8 v;
+
+    addr &= 0xffff;
+    uae_sem_wait (&akiko_sem);
+    switch (addr)
+    {
+       /* "CAFE" = Akiko identification.
+        * Kickstart ignores Akiko C2P if this ID isn't correct */
+       case 0x02:
+       v = 0xCA;
+       break;
+       case 0x03:
+       v = 0xFE;
+       break;
+
+       /* CDROM control */
+       case 0x04:
+       case 0x05:
+       case 0x06:
+       case 0x07:
+       v = akiko_get_long (cdrom_status1, addr - 0x04);
+       break;
+       case 0x08:
+       case 0x09:
+       case 0x0a:
+       case 0x0b:
+       v = akiko_get_long (cdrom_status2, addr - 0x08);
+       break;
+       case 0x10:
+       case 0x11:
+       case 0x12:
+       case 0x13:
+       v = akiko_get_long (cdrom_address1, addr - 0x10);
+       break;
+       case 0x14:
+       case 0x15:
+       case 0x16:
+       case 0x17:
+       v = akiko_get_long (cdrom_address2, addr - 0x14);
+       break;
+       case 0x18:
+       v = cdrom_status3;
+       break;
+       case 0x19:
+       v = cdrom_command_offset_complete;
+       break;
+       case 0x1a:
+       v = cdrom_result_complete;
+       break;
+       case 0x1f:
+       v = cdrom_result_last_pos;
+       break;
+       case 0x20:
+       case 0x21:
+       v = akiko_get_long (cdrom_readmask_w, addr - 0x20 + 2);
+       break;
+       case 0x24:
+       case 0x25:
+       case 0x26:
+       case 0x27:
+       v = akiko_get_long (cdrom_longmask, addr - 0x24);
+       break;
+
+       /* NVRAM */
+       case 0x30:
+       case 0x31:
+       case 0x32:
+       case 0x33:
+       v =  akiko_nvram_read (addr - 0x30);
+       break;
+
+       /* C2P */
+       case 0x38:
+       case 0x39:
+        case 0x3a:
+       case 0x3b:
+       v = akiko_c2p_read (addr - 0x38);
+       break;
+
+       default:
+       write_log ("akiko_bget: unknown address %08.8X\n", addr);
+       v = 0;
+       break;
+    }
+    akiko_internal ();
+    uae_sem_post (&akiko_sem);
+    if (msg && addr < 0x30 && AKIKO_DEBUG_IO)
+       write_log ("akiko_bget %08.8X: %08.8X %02.2X\n", m68k_getpc(), addr, v & 0xff);
+    return v;
+}
+
+uae_u32 akiko_bget (uaecptr addr)
+{
+    return akiko_bget2 (addr,1);
+}
+
+uae_u32 akiko_wget (uaecptr addr)
+{
+    uae_u16 v;
+    addr &= 0xffff;
+    v = akiko_bget2 (addr + 1, 0);
+    v |= akiko_bget2 (addr + 0, 0) << 8;
+    if (addr < 0x30 && AKIKO_DEBUG_IO)
+       write_log ("akiko_wget %08.8X: %08.8X %04.4X\n", m68k_getpc(), addr, v & 0xffff);
+    return v;
+}
+
+uae_u32 akiko_lget (uaecptr addr)
+{
+    uae_u32 v;
+
+    addr &= 0xffff;
+    v = akiko_bget2 (addr + 3, 0);
+    v |= akiko_bget2 (addr + 2, 0) << 8;
+    v |= akiko_bget2 (addr + 1, 0) << 16;
+    v |= akiko_bget2 (addr + 0, 0) << 24;
+    if (addr < 0x30 && (addr != 4 && addr != 8) && AKIKO_DEBUG_IO)
+        write_log ("akiko_lget %08.8X: %08.8X %08.8X\n", m68k_getpc(), addr, v);
+    return v;
+}
+
+void akiko_bput2 (uaecptr addr, uae_u32 v, int msg)
+{
+    uae_u32 tmp;
+
+    addr &= 0xffff;
+    v &= 0xff;
+    if(msg && addr < 0x30 && AKIKO_DEBUG_IO)
+        write_log ("akiko_bput %08.8X: %08.8X=%02.2X\n", m68k_getpc(), addr, v & 0xff);
+    uae_sem_wait (&akiko_sem);
+    switch (addr)
+    {
+       case 0x04:
+       case 0x05:
+       case 0x06:
+       case 0x07:
+       akiko_put_long (&cdrom_status1, addr - 0x04, v);
+       break;
+       case 0x08:
+       case 0x09:
+       case 0x0a:
+       case 0x0b:
+       akiko_put_long (&cdrom_status2, addr - 0x08, v);
+       if (addr == 8)
+           cdrom_status1 &= cdrom_status2;
+       break;
+       case 0x10:
+       case 0x11:
+       case 0x12:
+       case 0x13:
+       akiko_put_long (&cdrom_address1, addr - 0x10, v);
+       break;
+       case 0x14:
+       case 0x15:
+       case 0x16:
+       case 0x17:
+       akiko_put_long (&cdrom_address2, addr - 0x14, v);
+       break;
+       case 0x18:
+       cdrom_status3 = v;
+       break;
+       case 0x19:
+       cdrom_command_offset_complete = v;
+       break;
+       case 0x1a:
+       cdrom_result_complete = v;
+       break;
+       case 0x1d:
+       cdrom_command_offset_todo = v;
+       break;
+       case 0x1f:
+       cdrom_result_last_pos = v;
+       break;
+       case 0x20:
+       cdrom_readmask_w |= (v << 8);
+       cdrom_readmask_r &= 0x00ff;
+       break;
+       case 0x21:
+       cdrom_readmask_w |= (v << 0);
+       cdrom_readmask_r &= 0xff00;
+       break;
+       case 0x24:
+       case 0x25:
+       case 0x26:
+       case 0x27:
+       tmp = cdrom_longmask;
+       akiko_put_long (&cdrom_longmask, addr - 0x24, v);
+       if ((cdrom_longmask & 0x04000000) && !(tmp & 0x04000000))
+           cdrom_sector_counter = 0;
+       break;
+
+       case 0x30:
+       case 0x31:
+       case 0x32:
+       case 0x33:
+       akiko_nvram_write (addr - 0x30, v);
+       break;
+
+       case 0x38:
+       case 0x39:
+       case 0x3a:
+       case 0x3b:
+       akiko_c2p_write (addr - 0x38, v);
+       break;
+
+       default:
+       write_log ("akiko_bput: unknown address %08.8X\n", addr);
+       break;
+    }
+    akiko_internal ();
+    uae_sem_post (&akiko_sem);
+}
+
+void akiko_bput (uaecptr addr, uae_u32 v)
+{
+    akiko_bput2 (addr, v, 1);
+}
+
+void akiko_wput (uaecptr addr, uae_u32 v)
+{
+    addr &= 0xfff;
+    if((addr < 0x30 && AKIKO_DEBUG_IO))
+       write_log("akiko_wput %08.8X: %08.8X=%04.4X\n", m68k_getpc(), addr, v & 0xffff);
+    akiko_bput2 (addr + 1, v & 0xff, 0);
+    akiko_bput2 (addr + 0, v >> 8, 0);
+}
+
+void akiko_lput (uaecptr addr, uae_u32 v)
+{
+    addr &= 0xffff;
+    if(addr < 0x30 && AKIKO_DEBUG_IO)
+        write_log("akiko_lput %08.8X: %08.8X=%08.8X\n", m68k_getpc(), addr, v);
+    akiko_bput2 (addr + 3, (v >> 0) & 0xff, 0);
+    akiko_bput2 (addr + 2, (v >> 8) & 0xff, 0);
+    akiko_bput2 (addr + 1, (v >> 16) & 0xff, 0);
+    akiko_bput2 (addr + 0, (v >> 24) & 0xff, 0);
+}
+
+static uae_thread_id akiko_tid;
+
+void akiko_reset (void)
+{
+    nvram_read ();
+    state = I2C_WAIT;
+    bitcounter = -1;
+    direction = -1;
+
+    cdrom_speed = 1;
+    cdrom_current_sector = -1;
+
+    if (akiko_thread_running > 0) {
+       akiko_thread_running = 0;
+       while(akiko_thread_running == 0)
+           Sleep (10);
+       akiko_thread_running = 0;
+    }
+}
+
+extern uae_u32 extendedkickmemory;
+
+static uae_u8 patchdata[]={0x0c,0x82,0x00,0x00,0x03,0xe8,0x64,0x00,0x00,0x46};
+
+static void patchrom (void)
+{
+    int i;
+    uae_u8 *p = (uae_u8*)extendedkickmemory;
+    for (i = 0; i < 524288 - sizeof (patchdata); i++) {
+       if (!memcmp (p + i, patchdata, sizeof(patchdata))) {
+           p[i + 6] = 0x4e;
+           p[i + 7] = 0x71;
+           p[i + 8] = 0x4e;
+           p[i + 9] = 0x71;
+           write_log ("extended rom delay loop patched at 0x%p\n", i + 6 + 0xe00000);
+           return;
+       }
+    }
+    write_log ("couldn't patch extended rom\n");
+}
+
+void akiko_free (void)
+{
+    akiko_reset ();
+    if (unitnum >= 0)
+       sys_cddev_close ();
+    unitnum = -1;
+    free (sector_buffer_1);
+    free (sector_buffer_2);
+    free (sector_buffer_info_1);
+    free (sector_buffer_info_2);
+    sector_buffer_1 = 0;
+    sector_buffer_2 = 0;
+    sector_buffer_info_1 = 0;
+    sector_buffer_info_2 = 0;
+}
+
+void akiko_init (void)
+{
+    static int cdromok = 0;
+
+    if (cdromok == 0) {
+       unitnum = -1;
+       device_func_init(DEVICE_TYPE_ANY);
+       if (!sys_cddev_open ()) {
+           cdromok = 1;
+           sector_buffer_1 = malloc (SECTOR_BUFFER_SIZE * 2048);
+           sector_buffer_2 = malloc (SECTOR_BUFFER_SIZE * 2048);
+           sector_buffer_info_1 = malloc (SECTOR_BUFFER_SIZE);
+           sector_buffer_info_2 = malloc (SECTOR_BUFFER_SIZE);
+           sector_buffer_sector_1 = -1;
+           sector_buffer_sector_2 = -1;
+           patchrom ();
+       }
+    }
+    if (!savestate_state) {
+        cdrom_playing = cdrom_paused = 0;
+       cdrom_data_offset = -1;
+       uae_sem_init (&akiko_sem, 0, 1);
+    }
+    if (cdromok && !akiko_thread_running) {
+       akiko_thread_running = 1;
+       uae_start_thread (akiko_thread, 0, &akiko_tid);
+    }
+}
+
+uae_u8 *save_akiko(int *len)
+{
+    uae_u8 *dstbak, *dst;
+    int i;
+
+    dstbak = dst = malloc (1000);
+    save_u16 (0);
+    save_u16 (0xCAFE);
+    save_u32 (cdrom_status1);
+    save_u32 (cdrom_status2);
+    save_u32 (0);
+    save_u32 (cdrom_address1);
+    save_u32 (cdrom_address2);
+    save_u8 (cdrom_status3);
+    save_u8 (cdrom_command_offset_complete);
+    save_u8 (cdrom_result_complete);
+    save_u8 (0);
+    save_u8 (0);
+    save_u8 (cdrom_command_offset_todo);
+    save_u8 (0);
+    save_u8 (cdrom_result_last_pos);
+    save_u16 ((uae_u16)cdrom_readmask_w);
+    save_u16 (0);
+    save_u32 (cdrom_longmask);
+    save_u32 (0);
+    save_u32 (0);
+    save_u32 ((scl_dir ? 0x8000 : 0) | (sda_dir ? 0x4000 : 0));
+    save_u32 (0);
+    save_u32 (0);
+
+    for (i = 0; i < 8; i++)
+       save_u32 (akiko_buffer[i]);
+    save_u8 ((uae_u8)akiko_read_offset);
+    save_u8 ((uae_u8)akiko_write_offset);
+    
+    save_u32 ((cdrom_playing ? 1 : 0) | (cdrom_paused ? 2 : 0));
+    if (cdrom_playing)
+       cd_qcode (0);
+    save_u32 (last_play_pos);
+    save_u32 (last_play_end);
+    save_u8 ((uae_u8)cdrom_toc_counter);
+
+    *len = dst - dstbak;
+    return dstbak;
+}
+
+uae_u8 *restore_akiko(uae_u8 *src)
+{
+    uae_u32 v;
+    int i;
+
+    restore_u16 ();
+    restore_u16 ();
+    cdrom_status1 = restore_u32 ();
+    cdrom_status2 = restore_u32 ();
+    restore_u32();
+    cdrom_address1 = restore_u32 ();
+    cdrom_address2 = restore_u32 ();
+    cdrom_status3 = restore_u8 ();
+    cdrom_command_offset_complete = restore_u8 ();
+    cdrom_result_complete = restore_u8 ();
+    restore_u8 ();
+    restore_u8 ();
+    cdrom_command_offset_todo = restore_u8 ();
+    restore_u8 ();
+    cdrom_result_last_pos = restore_u8 ();
+    cdrom_readmask_w = restore_u16 ();
+    restore_u16 ();
+    cdrom_longmask = restore_u32 ();
+    restore_u32();
+    restore_u32();
+    v = restore_u32();
+    scl_dir = (v & 0x8000) ? 1 : 0;
+    sda_dir = (v & 0x4000) ? 1 : 0;
+    restore_u32();
+    restore_u32();
+
+    for (i = 0; i < 8; i++)
+       akiko_buffer[i] = restore_u32 ();
+    akiko_read_offset = restore_u8 ();
+    akiko_write_offset = restore_u8 ();
+    akiko_c2p_do ();
+
+    cdrom_playing = cdrom_paused = 0;
+    v = restore_u32 ();
+    if (v & 1)
+       cdrom_playing = 1;
+    if (v & 2)
+       cdrom_paused = 1;
+    last_play_pos = restore_u32 ();
+    last_play_end = restore_u32 ();
+    cdrom_toc_counter = restore_u8 ();
+    if (cdrom_toc_counter == 255)
+       cdrom_toc_counter = -1;
+    if (cdrom_playing)
+       sys_command_play (DF_IOCTL, unitnum, last_play_pos, last_play_end, 0);
+
+    return src;
+}
\ No newline at end of file
diff --git a/ar.c b/ar.c
new file mode 100755 (executable)
index 0000000..ddea11c
--- /dev/null
+++ b/ar.c
@@ -0,0 +1,1631 @@
+/* 
+ * UAE Action Replay 1/2/3 and HRTMon support
+ *
+ * (c) 2000-2002 Toni Wilen <twilen@arabuusimiehet.com>
+ * (c) 2003 Mark Cox <markcox@email.com>
+ *
+ * Toni's unofficial UAE patches are located at:
+ * http://www.arabuusimiehet.com/twilen/uae/
+ *
+ * HRTMon:
+ *
+ * HRTMon support is tested with version 2.25 + patch.
+ * More information about HRTMon can be found from
+ * http://dumbo.cryogen.ch/hrtmon/
+ * 
+ * Action Replay 2/3:
+ *
+ * Tested with AR3 ROM version 3.09 (10/13/91) and AR2 2.12 (12/24/90)
+ *
+ * Found to work for the following roms by Mark Cox:
+ * (Yes the date format is inconsistent, i just copied it straight from the rom)
+ * 1.15 
+ * 2.14 22/02/91 dd/mm/yy
+ * 3.09 10/13/91 mm/dd/yy
+ * 3.17 12/17/91 mm/dd/yy
+ *
+ * This patch also makes AR3 compatible with KickStart's other than 1.3
+ * (ROM checksum error is normal with KS != 1.3)  
+ * NOTE: AR has problems with 68020+ processors.
+ * For maximum compatibility select 68000/68010 and A500 speed from UAE
+ * options.
+ *
+ * How to rip Action Replay 1/2/3 ROM:
+ *
+ * Find A500 with AR1/2/3, press 'freeze'-button
+ *
+ * type following:
+ *
+ * AR1:
+ * lord olaf<RETURN>
+ *
+ * AR2 or AR3:
+ * may<RETURN>
+ * the<RETURN>
+ * force<RETURN>
+ * be<RETURN>
+ * with<RETURN>
+ * you<RETURN>
+ * new<RETURN> (AR3 only)
+ * 
+ * AR1: 64K ROM is visible at 0xf00000-0xf0ffff
+ * and 16K RAM at 0x9fc000-0x9fffff
+ * AR2: 128K ROM is visible at 0x400000-0x41ffff
+ * AR3: 256K ROM is visible at 0x400000-0x43ffff
+ * and 64K RAM at 0x440000-0x44ffff
+ *
+ * following command writes ROM to disk:
+ *
+ * AR1: sm ar1.rom,f00000 f10000
+ * AR2: sm ar2.rom,400000 420000
+ * AR3: sm ar3.rom,400000 440000
+ *
+ * NOTE: I (mark) could not get the action replay 1 dump to work as above.
+ * (also, it will only dump to the action replay special disk format)
+ * To dump the rom i had to :
+ * 1. Boot the a500 and start a monitor (e.g. cmon).
+ * 2. Use the monitor to allocate 64k memory.
+ * 3. Enter the action replay.
+ * 4. Enter sysop mode.
+ * 5. Copy the rom into the address the monitor allocated.
+ * 6. Exit the action replay.
+ * 7. Save the ram from the monitor to disk.
+ * 
+ * I DO NOT REPLY MAILS ASKING FOR ACTION REPLAY ROMS!
+ *
+ * AR2/3 hardware notes (not 100% correct..)
+ *
+ * first 8 bytes of ROM are not really ROM, they are
+ * used to read/write cartridge's hardware state
+ *
+ * 0x400000: hides cartridge ROM/RAM when written
+ * 0x400001: read/write HW state
+ *  3 = reset (read-only)
+ *  2 = sets HW to activate when breakpoint condition is detected
+ *  1 = ???
+ *  0 = freeze pressed
+ * 0x400002/0x400003: mirrors 0x400000/0x400001
+ * 0x400006/0x400007: when written to, turns chip-ram overlay off
+ *
+ * breakpoint condition is detected when CPU first accesses
+ * chip memory below 1024 bytes and then reads CIA register
+ * $BFE001.
+ *
+ * cartridge hardware also snoops CPU accesses to custom chip
+ * registers (DFF000-DFF1FE). All CPU custom chip accesses are
+ * saved to RAM at 0x44f000-0x44f1ff. Note that emulated AR3 also 
+ * saves copper's custom chip accesses. This fix stops programs
+ * that try to trick AR by using copper to update write-only
+ * custom registers.
+ *
+ * 30.04.2001 - added AR2 support
+ * 21.07.2001 - patch updated
+ * 29.07.2002 - added AR1 support
+ * 11.03.2003 - added AR1 breakpoint support, checksum support and fixes. (Mark Cox)
+ *
+ */
+
+/* AR2/3 'NORES' info.
+ * On ar2 there is a 'nores' command,
+ * on ar3, it is accessible using the mouse.
+ * This command will not work using the current infrastructure,
+ * so don't use it 8).
+ */
+/* AR1 Breakpoint info.
+ * 1.15 If a breakpoint occurred. Its address is stored at 9fe048.
+ * The 5 breakpoint entries each consisting of 6 bytes are stored at 9fe23e.
+ * Each entry contains the breakpoint long word followed by 2 bytes of the original contents of memory
+ * that is replaced by a trap instruction in mem.
+ * So the table finishes at 9fe25c.
+ */
+
+/* How AR1 is entered on reset:
+ * In the kickstart (1.3) there is the following code:
+ * I have marked the important lines:
+ * 
+ * fc00e6 lea f00000,a1        ; address where AR1 rom is located.
+ * fc00ec cmpa.l a1,a0
+ * fc00ee beq fc00fe.s
+ * fc00f0 lea C(pc), a5
+ * fc00f4 cmpi.w #1111,(a1)            ; The first word of the AR1 rom is set to 1111.
+ * fc00f8 bne fc00fe.s
+ * fc00fa jmp 2(a1)                                            ; This is the entry point of the rom.
+ */
+ /* Flag info:
+       * AR3:'ARON'. This is unset initially. It is set the first time you enter the AR via a freeze. 
+       * It enables you to keep the keyboard buffer and such. 
+       * If this flag is unset, the keyboard buffer is cleared, the breakpoints are deleted and ... */
+ /* AR3:'PRIN'. This flag is unset initially. It is set at some point and when you switch to the 2nd screen
+       * for the first time it displays all the familiar text. Then unsets 'PRIN'.
+       */
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "uae.h"
+#include "memory.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "zfile.h"
+#include "ar.h"
+#include "savestate.h"
+
+#define DEBUG
+#ifdef DEBUG
+#define write_log_debug write_log
+#else
+#define write_log_debug
+#endif
+
+#define ARMODE_FREEZE 0 /* AR2/3 The action replay 'freeze' button has been pressed.  */
+#define ARMODE_BREAKPOINT_AR2 2 /* AR2: The action replay is activated via a breakpoint. */
+#define ARMODE_BREAKPOINT_ACTIVATED 1
+#define ARMODE_BREAKPOINT_AR3_RESET_AR2 3 /* AR2: The action replay is activated after a reset. */
+                                          /* AR3: The action replay is activated by a breakpoint. */
+
+/* HRTMon baseaddress, can be freely changed */
+#define HRTMON_BASE 0x980000
+
+uae_u8 ar_custom[2*256];
+
+int hrtmon_flag = ACTION_REPLAY_INACTIVE;
+
+static uae_u8 *hrtmemory = 0;
+static uae_u8 *armemory_rom = 0, *armemory_ram = 0;
+
+static uae_u32 hrtmem_mask;
+static uae_u8 *hrtmon_custom;
+uae_u32 hrtmem_start, hrtmem_size;
+
+static uae_u32 hrtmem_lget (uaecptr) REGPARAM;
+static uae_u32 hrtmem_wget (uaecptr) REGPARAM;
+static uae_u32 hrtmem_bget (uaecptr) REGPARAM;
+static void  hrtmem_lput (uaecptr, uae_u32) REGPARAM;
+static void  hrtmem_wput (uaecptr, uae_u32) REGPARAM;
+static void  hrtmem_bput (uaecptr, uae_u32) REGPARAM;
+static int  hrtmem_check (uaecptr addr, uae_u32 size) REGPARAM;
+static uae_u8 *hrtmem_xlate (uaecptr addr) REGPARAM;
+static void hrtmon_unmap_banks(void);
+
+void check_prefs_changed_carts(int in_memory_reset);
+int action_replay_unload(int in_memory_reset);
+
+static uae_u32 REGPARAM2 hrtmem_lget (uaecptr addr)
+{
+    uae_u32 *m;
+    addr -= hrtmem_start & hrtmem_mask;
+    addr &= hrtmem_mask;
+    m = (uae_u32 *)(hrtmemory + addr);
+    return do_get_mem_long (m);
+}
+
+static uae_u32 REGPARAM2 hrtmem_wget (uaecptr addr)
+{
+    uae_u16 *m;
+    addr -= hrtmem_start & hrtmem_mask;
+    addr &= hrtmem_mask;
+    m = (uae_u16 *)(hrtmemory + addr);
+    return do_get_mem_word (m);
+}
+
+static uae_u32 REGPARAM2 hrtmem_bget (uaecptr addr)
+{
+    addr -= hrtmem_start & hrtmem_mask;
+    addr &= hrtmem_mask;
+    return hrtmemory[addr];
+}
+
+static void REGPARAM2 hrtmem_lput (uaecptr addr, uae_u32 l)
+{
+    uae_u32 *m;
+    addr -= hrtmem_start & hrtmem_mask;
+    addr &= hrtmem_mask;
+    m = (uae_u32 *)(hrtmemory + addr);
+    do_put_mem_long (m, l);
+}
+
+static void REGPARAM2 hrtmem_wput (uaecptr addr, uae_u32 w)
+{
+    uae_u16 *m;
+    addr -= hrtmem_start & hrtmem_mask;
+    addr &= hrtmem_mask;
+    m = (uae_u16 *)(hrtmemory + addr);
+    do_put_mem_word (m, (uae_u16)w);
+}
+
+static void REGPARAM2 hrtmem_bput (uaecptr addr, uae_u32 b)
+{
+    addr -= hrtmem_start & hrtmem_mask;
+    addr &= hrtmem_mask;
+    hrtmemory[addr] = b;
+}
+
+static int REGPARAM2 hrtmem_check (uaecptr addr, uae_u32 size)
+{
+    addr -= hrtmem_start & hrtmem_mask;
+    addr &= hrtmem_mask;
+    return (addr + size) <= hrtmem_size;
+}
+
+static uae_u8 REGPARAM2 *hrtmem_xlate (uaecptr addr)
+{
+    addr -= hrtmem_start & hrtmem_mask;
+    addr &= hrtmem_mask;
+    return hrtmemory + addr;
+}
+
+addrbank hrtmem_bank = {
+    hrtmem_lget, hrtmem_wget, hrtmem_bget,
+    hrtmem_lput, hrtmem_wput, hrtmem_bput,
+    hrtmem_xlate, hrtmem_check, NULL
+};
+
+static void copyfromamiga(uae_u8 *dst,uae_u8 *src,int len)
+{
+while(len--) {
+    *dst++ = get_byte ((uaecptr)src);
+    src++;
+}
+}
+static void copytoamiga(uae_u8 *dst,uae_u8 *src,int len)
+{
+while(len--) {
+    put_byte ((uaecptr)dst, *src++);
+    dst++;
+}
+}
+
+int action_replay_flag = ACTION_REPLAY_INACTIVE;
+static int ar_rom_file_size;
+
+/* Use this for relocating AR? */
+static int ar_rom_location;
+/*static*/ int armodel;
+static uae_u8 artemp[4]; /* Space to store the 'real' level 7 interrupt */
+static uae_u8 armode;
+
+static uae_u32 arrom_start, arrom_size, arrom_mask;
+static uae_u32 arram_start, arram_size, arram_mask;
+
+static int ar_wait_pop = 0; /* bool used by AR1 when waiting for the program counter to exit it's ram. */
+uaecptr wait_for_pc = 0;       /* The program counter that we wait for. */
+
+/* returns true if the Program counter is currently in the AR rom. */
+int is_ar_pc_in_rom()
+{
+    uaecptr pc = m68k_getpc() & 0xFFFFFF;
+    return pc >= arrom_start && pc < arrom_start+arrom_size;
+}
+
+/* returns true if the Program counter is currently in the AR RAM. */
+int is_ar_pc_in_ram()
+{
+    uaecptr pc = m68k_getpc() & 0xFFFFFF;
+    return pc >= arram_start && pc < arram_start+arram_size;
+}
+
+
+/* flag writing == 1 for writing memory, 0 for reading from memory. */ 
+STATIC_INLINE int ar3a (uaecptr addr, uae_u8 b, int writing)
+{
+    uaecptr pc;
+/*     if ( addr < 8 ) //|| writing ) */
+/*     { */
+/*             if ( writing ) */
+/*   write_log_debug("ARSTATUS armode:%d, Writing %d to address %p, PC=%p\n", armode, b, addr, m68k_getpc()); */
+/*             else */
+/*    write_log_debug("ARSTATUS armode:%d, Reading %d from address %p, PC=%p\n", armode, armemory_rom[addr], addr, m68k_getpc()); */
+/*     }        */
+
+    if (armodel == 1 ) /* With AR1. It is always a read. Actually, it is a strobe on exit of the AR.
+                         * but, it is also read during the checksum routine.   */
+    {
+       if ( addr < 2) 
+       {
+           if ( is_ar_pc_in_rom() )
+           {
+               if ( ar_wait_pop )
+               {
+                   action_replay_flag = ACTION_REPLAY_WAIT_PC;
+/*                 write_log_debug("SP %p\n", m68k_areg(regs,7));  */
+/*                 write_log_debug("SP+2 %p\n", m68k_areg(regs,7)+2 );  */
+/*                 write_log_debug("(SP+2) %p\n", longget(m68k_areg(regs,7)+2));  */
+                   ar_wait_pop = 0; 
+                   /* We get (SP+2) here, as the first word on the stack is the status register. */
+                   /* We want the following long, which is the return program counter. */
+                   wait_for_pc = longget(m68k_areg(regs,7)+2); /* Get (SP+2) */
+                   set_special (SPCFLAG_ACTION_REPLAY);
+                                       
+                   pc = m68k_getpc();
+/*                 write_log_debug("Action Replay marked as ACTION_REPLAY_WAIT_PC, PC=%p\n",pc);*/
+               }
+               else
+               {
+                   uaecptr pc = m68k_getpc();
+/*                 write_log_debug("Action Replay marked as IDLE, PC=%p\n",pc);*/
+                   action_replay_flag = ACTION_REPLAY_IDLE;
+               }
+           }
+       }
+       /* This probably violates the hide_banks thing except ar1 doesn't use that yet .*/
+       return armemory_rom[addr];
+    }
+
+#ifdef ACTION_REPLAY_HIDE_CARTRIDGE
+    if (addr >= 8 )
+       return armemory_rom[addr];
+
+    if (action_replay_flag != ACTION_REPLAY_ACTIVE)
+       return 0;
+#endif
+       
+    if (!writing) /* reading */
+    {
+       if (addr == 1) /* This is necessary because we don't update rom location 0 every time we change armode */
+           return armode;
+       else
+           return armemory_rom[addr];
+    }
+    /* else, we are writing */
+    else if (addr == 1) { 
+        armode = b;
+        if(armode >= 2) 
+       {
+           if ( armode == ARMODE_BREAKPOINT_AR2 )
+           {
+               write_log("AR2: exit with breakpoint(s) active\n"); /* Correct for AR2 */
+           }
+           else if ( armode == ARMODE_BREAKPOINT_AR3_RESET_AR2 )
+           {
+               write_log("AR3: exit waiting for breakpoint.\n"); /* Correct for AR3 (waiting for breakpoint)*/
+           }
+           else 
+           {
+               write_log("AR2/3: mode(%d) > 3 this shouldn't happen.\n", armode);
+           }   
+       } else {
+            write_log("AR: exit with armode(%d)\n", armode);
+        }
+        set_special (SPCFLAG_ACTION_REPLAY);
+        action_replay_flag = ACTION_REPLAY_HIDE;
+    } else if (addr == 6) {
+        copytoamiga ((uae_u8*)regs.vbr + 0x7c, artemp, 4);
+        write_log ("AR: chipmem returned\n");
+    }
+    return 0;
+}
+
+void REGPARAM2 chipmem_lput_actionreplay1 (uaecptr addr, uae_u32 l)
+{
+    uae_u32 *m;
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    if (addr == 0x60 && !is_ar_pc_in_rom())
+       action_replay_chipwrite ();
+    m = (uae_u32 *)(chipmemory + addr);
+    do_put_mem_long (m, l);
+}
+void REGPARAM2 chipmem_wput_actionreplay1 (uaecptr addr, uae_u32 w)
+{
+    uae_u16 *m;
+
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    if (addr == 0x62 && !is_ar_pc_in_rom())
+       action_replay_chipwrite ();
+    m = (uae_u16 *)(chipmemory + addr);
+    do_put_mem_word (m, w);
+}
+void REGPARAM2 chipmem_bput_actionreplay1 (uaecptr addr, uae_u32 b)
+{
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    if (addr >= 0x60 && addr <= 0x63 && !is_ar_pc_in_rom())
+       action_replay_chipwrite();
+    chipmemory[addr] = b;
+}
+void REGPARAM2 chipmem_lput_actionreplay23 (uaecptr addr, uae_u32 l)
+{
+    uae_u32 *m;
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    m = (uae_u32 *)(chipmemory + addr);
+    do_put_mem_long (m, l);
+    if (addr >= 0x40 && addr < 0x200 && action_replay_flag == ACTION_REPLAY_WAITRESET)
+        action_replay_chipwrite();
+}
+void REGPARAM2 chipmem_wput_actionreplay23 (uaecptr addr, uae_u32 w)
+{
+    uae_u16 *m;
+
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    m = (uae_u16 *)(chipmemory + addr);
+    do_put_mem_word (m, w);
+    if (addr >= 0x40 && addr < 0x200 && action_replay_flag == ACTION_REPLAY_WAITRESET)
+        action_replay_chipwrite();
+}
+
+
+static uae_u32 arram_lget (uaecptr) REGPARAM;
+static uae_u32 arram_wget (uaecptr) REGPARAM;
+static uae_u32 arram_bget (uaecptr) REGPARAM;
+static void  arram_lput (uaecptr, uae_u32) REGPARAM;
+static void  arram_wput (uaecptr, uae_u32) REGPARAM;
+static void  arram_bput (uaecptr, uae_u32) REGPARAM;
+static int  arram_check (uaecptr addr, uae_u32 size) REGPARAM;
+static uae_u8 *arram_xlate (uaecptr addr) REGPARAM;
+
+static uae_u32 arrom_lget (uaecptr) REGPARAM;
+static uae_u32 arrom_wget (uaecptr) REGPARAM;
+static uae_u32 arrom_bget (uaecptr) REGPARAM;
+static void  arrom_lput (uaecptr, uae_u32) REGPARAM;
+static void  arrom_wput (uaecptr, uae_u32) REGPARAM;
+static void  arrom_bput (uaecptr, uae_u32) REGPARAM;
+static int  arrom_check (uaecptr addr, uae_u32 size) REGPARAM;
+static uae_u8 *arrom_xlate (uaecptr addr) REGPARAM;
+static void action_replay_unmap_banks(void);
+
+static uae_u32 action_replay_calculate_checksum(void);
+static uae_u8* get_checksum_location(void);
+static void disable_rom_test(void);
+
+static uae_u32 REGPARAM2 arram_lget (uaecptr addr)
+{
+    uae_u32 *m;
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+    addr -= arram_start;
+    addr &= arram_mask;
+    m = (uae_u32 *)(armemory_ram + addr);
+    if (strncmp("T8", (char*)m, 2) == 0)
+       write_log_debug("Reading T8 from addr %08.08x PC=%p\n", addr, m68k_getpc());
+    if (strncmp("LAME", (char*)m, 4) == 0)
+       write_log_debug("Reading LAME from addr %08.08x PC=%p\n", addr, m68k_getpc());
+    if (strncmp("RES1", (char*)m, 4) == 0)
+       write_log_debug("Reading RES1 from addr %08.08x PC=%p\n", addr, m68k_getpc());
+    if (strncmp("ARON", (char*)m, 4) == 0)
+       write_log_debug("Reading ARON from addr %08.08x PC=%p\n", addr, m68k_getpc());
+    if (strncmp("KILL", (char*)m, 4) == 0)
+       write_log_debug("Reading KILL from addr %08.08x PC=%p\n", addr, m68k_getpc());
+    if (strncmp("BRON", (char*)m, 4) == 0)
+       write_log_debug("Reading BRON from addr %08.08x PC=%p\n", addr, m68k_getpc());
+    if (strncmp("PRIN", (char*)m, 4) == 0)
+       write_log_debug("Reading PRIN from addr %08.08x PC=%p\n", addr, m68k_getpc());
+    return do_get_mem_long (m);
+}
+
+static uae_u32 REGPARAM2 arram_wget (uaecptr addr)
+{
+    uae_u16 *m;
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+    addr -= arram_start;
+    addr &= arram_mask;
+    m = (uae_u16 *)(armemory_ram + addr);
+    return do_get_mem_word (m);
+}
+
+static uae_u32 REGPARAM2 arram_bget (uaecptr addr)
+{
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+    addr -= arram_start;
+    addr &= arram_mask;
+    return armemory_ram[addr];
+}
+
+void REGPARAM2 arram_lput (uaecptr addr, uae_u32 l)
+{
+    uae_u32 *m;
+
+    addr -= arram_start;
+    addr &= arram_mask;
+    m = (uae_u32 *)(armemory_ram + addr);
+    if (strncmp("T8", (char*)m, 2) == 0)
+       write_log_debug("Writing T8 to addr %08.08x PC=%p\n", addr, m68k_getpc());
+    if (strncmp("LAME", (char*)m, 4) == 0)
+       write_log_debug("Writing LAME to addr %08.08x PC=%p\n", addr, m68k_getpc());
+    if (strncmp("RES1", (char*)m, 4) == 0)
+       write_log_debug("Writing RES1 to addr %08.08x PC=%p\n", addr, m68k_getpc());
+    if (strncmp("ARON", (char*)m, 4) == 0)
+       write_log_debug("Writing ARON to addr %08.08x PC=%p\n", addr, m68k_getpc());
+    if (strncmp("KILL", (char*)m, 4) == 0)
+       write_log_debug("Writing KILL to addr %08.08x PC=%p\n", addr, m68k_getpc());
+    if (strncmp("BRON", (char*)m, 4) == 0)
+       write_log_debug("Writing BRON to addr %08.08x PC=%p\n", addr, m68k_getpc());
+    if (strncmp("PRIN", (char*)m, 4) == 0)
+       write_log_debug("Writing PRIN to addr %08.08x PC=%p\n", addr, m68k_getpc());
+    do_put_mem_long (m, l);
+}
+
+void REGPARAM2 arram_wput (uaecptr addr, uae_u32 w)
+{
+    uae_u16 *m;
+
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    addr -= arram_start;
+    addr &= arram_mask;
+    m = (uae_u16 *)(armemory_ram + addr);
+    do_put_mem_word (m, w);
+}
+
+void REGPARAM2 arram_bput (uaecptr addr, uae_u32 b)
+{
+    addr -= arram_start;
+    addr &= arram_mask;
+    armemory_ram[addr] = b;
+}
+
+static int REGPARAM2 arram_check (uaecptr addr, uae_u32 size)
+{
+    addr -= arram_start;
+    addr &= arram_mask;
+    return (addr + size) <= arram_size;
+}
+
+static uae_u8 REGPARAM2 *arram_xlate (uaecptr addr)
+{
+    addr -= arram_start;
+    addr &= arram_mask;
+    return armemory_ram + addr;
+}
+
+static uae_u32 REGPARAM2 arrom_lget (uaecptr addr)
+{
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+    addr -= arrom_start;
+    addr &= arrom_mask;
+    return (ar3a (addr, 0, 0) << 24) | (ar3a (addr + 1, 0, 0) << 16) | (ar3a (addr + 2, 0, 0) << 8) | ar3a (addr + 3, 0, 0);
+}
+
+static uae_u32 REGPARAM2 arrom_wget (uaecptr addr)
+{
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+    addr -= arrom_start;
+    addr &= arrom_mask;
+    return (ar3a (addr, 0, 0) << 8) | ar3a (addr + 1, 0, 0);
+}
+
+static uae_u32 REGPARAM2 arrom_bget (uaecptr addr)
+{
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+    addr -= arrom_start;
+    addr &= arrom_mask;
+    return ar3a (addr, 0, 0);
+}
+
+static void REGPARAM2 arrom_lput (uaecptr addr, uae_u32 l)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    addr -= arrom_start;
+    addr &= arrom_mask;
+    ar3a (addr + 0,(uae_u8)(l >> 24), 1);
+    ar3a (addr + 1,(uae_u8)(l >> 16), 1);
+    ar3a (addr + 2,(uae_u8)(l >> 8), 1);
+    ar3a (addr + 3,(uae_u8)(l >> 0), 1);
+}
+
+static void REGPARAM2 arrom_wput (uaecptr addr, uae_u32 w)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    addr -= arrom_start;
+    addr &= arrom_mask;
+    ar3a (addr + 0,(uae_u8)(w >> 8), 1);
+    ar3a (addr + 1,(uae_u8)(w >> 0), 1);
+}
+
+static void REGPARAM2 arrom_bput (uaecptr addr, uae_u32 b)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    addr -= arrom_start;
+    addr &= arrom_mask;
+    ar3a (addr, b, 1);
+}
+
+static int REGPARAM2 arrom_check (uaecptr addr, uae_u32 size)
+{
+    addr -= arrom_start;
+    addr &= arrom_mask;
+    return (addr + size) <= arrom_size;
+}
+
+static uae_u8 REGPARAM2 *arrom_xlate (uaecptr addr)
+{
+    addr -= arrom_start;
+    addr &= arrom_mask;
+    return armemory_rom + addr;
+}
+
+static addrbank arrom_bank = {
+    arrom_lget, arrom_wget, arrom_bget,
+    arrom_lput, arrom_wput, arrom_bput,
+    arrom_xlate, arrom_check, NULL
+};
+static addrbank arram_bank = {
+    arram_lget, arram_wget, arram_bget,
+    arram_lput, arram_wput, arram_bput,
+    arram_xlate, arram_check, NULL
+};
+
+static void action_replay_unmap_banks()
+{
+    if(!armemory_rom)
+        return;
+         
+    map_banks (&dummy_bank, arrom_start >> 16 , arrom_size >> 16, 0);
+    map_banks (&dummy_bank, arram_start >> 16 , arram_size >> 16, 0);
+}
+
+void action_replay_map_banks()
+{
+    if(!armemory_rom)
+        return;
+
+    map_banks (&arrom_bank, arrom_start >> 16, arrom_size >> 16, 0);
+    map_banks (&arram_bank, arram_start >> 16, arram_size >> 16, 0);
+}
+
+static void hide_cart(int hide)
+{
+#ifdef ACTION_REPLAY_HIDE_CARTRIDGE
+    if(hide) {
+        action_replay_unmap_banks(); 
+    } else {
+        action_replay_map_banks();
+    }
+#endif
+}
+
+/*extern void Interrupt (int nr);*/
+
+/* Cartridge activates itself by overlaying its rom
+ * over chip-ram and then issuing IRQ 7
+ *
+ * I just copy IRQ vector 7 from ROM to chip RAM
+ * instead of fully emulating cartridge's behaviour.
+ */
+
+static void action_replay_go (void)
+{
+    hide_cart (0);
+    memcpy (armemory_ram + 0xf000, ar_custom, 2 * 256);
+    action_replay_flag = ACTION_REPLAY_ACTIVE;
+    set_special (SPCFLAG_ACTION_REPLAY);
+    copyfromamiga (artemp, (uae_u8*)regs.vbr + 0x7c, 4);
+    copytoamiga ((uae_u8*)regs.vbr+0x7c, armemory_rom + 0x7c, 4);
+    Interrupt (7);
+}
+
+static void action_replay_go1 (int irq)
+{
+    hide_cart (0);
+    action_replay_flag = ACTION_REPLAY_ACTIVE;
+               
+    memcpy (armemory_ram + 0xf000, ar_custom, 2 * 256);
+    Interrupt (7);
+}
+
+static void hrtmon_go (int mode)
+{
+    memcpy (hrtmon_custom, ar_custom, 2 * 256);
+    hrtmon_flag = ACTION_REPLAY_ACTIVE;
+    set_special (SPCFLAG_ACTION_REPLAY);
+    put_long ((uaecptr)((uae_u8*)regs.vbr+0x7c), hrtmem_start + 8 + (mode ? 4 : 0));
+    Interrupt (7);
+}
+
+void hrtmon_enter (void)
+{
+    if (!hrtmemory) return;
+    write_log("HRTMON: freeze\n");
+    hrtmon_go(1);
+}
+
+void action_replay_enter(void)
+{
+    if (!armemory_rom) return;
+    if (armodel == 1) {
+       write_log("AR1: Enter PC:%p\n", m68k_getpc());
+        action_replay_go1 (7);
+        unset_special (SPCFLAG_ACTION_REPLAY);
+        return;
+    }
+    if (action_replay_flag == ACTION_REPLAY_DORESET) {
+        write_log("AR2/3: reset\n");
+        armode = ARMODE_BREAKPOINT_AR3_RESET_AR2;
+    }
+    else if (armode == ARMODE_FREEZE) {
+        write_log("AR2/3: activated (freeze)\n");
+    } 
+    else if (armode >= 2) 
+    {
+       if ( armode == ARMODE_BREAKPOINT_AR2 )
+       {
+           write_log("AR2: activated (breakpoint)\n");
+       }
+       else if ( armode == ARMODE_BREAKPOINT_AR3_RESET_AR2 )
+       {
+           write_log("AR3: activated (breakpoint)\n");
+       }
+       else 
+       {
+           write_log("AR2/3: mode(%d) > 3 this shouldn't happen.\n", armode);
+       }       
+       armode = ARMODE_BREAKPOINT_ACTIVATED;
+    }
+    action_replay_go();
+}
+
+void check_prefs_changed_carts(int in_memory_reset)
+{
+    if (strcmp (currprefs.cartfile, changed_prefs.cartfile) != 0) 
+    {
+       write_log("Cartridge ROM Prefs changed.\n");
+        if (action_replay_unload(in_memory_reset)) 
+       {
+           memcpy (currprefs.cartfile, changed_prefs.cartfile, sizeof currprefs.cartfile);     
+           #ifdef ACTION_REPLAY
+           action_replay_load();
+           action_replay_init(1); 
+           #endif
+           #ifdef ACTION_REPLAY_HRTMON
+           hrtmon_load(1);
+           #endif
+       }
+    }
+} 
+       
+void action_replay_reset(void)
+{
+    if (action_replay_flag == ACTION_REPLAY_INACTIVE)
+       return;
+    write_log_debug("action_replay_reset()\n");
+
+    if (savestate_state == STATE_RESTORE) {
+        if (regs.pc >= arrom_start && regs.pc <= arrom_start + arrom_size) {
+           action_replay_flag = ACTION_REPLAY_ACTIVE;
+           hide_cart (0);
+       } else {
+           action_replay_flag = ACTION_REPLAY_IDLE;
+            hide_cart (1);
+       }
+       return;
+    }
+
+    if (armodel == 1 )
+    {
+       /* We need to mark it as active here, because the kickstart rom jumps directly into it. */
+       action_replay_flag = ACTION_REPLAY_ACTIVE;
+    }
+    else
+    {
+       write_log_debug("Setting flag to ACTION_REPLAY_WAITRESET\n");
+       write_log_debug("armode == %d\n", armode);
+       action_replay_flag = ACTION_REPLAY_WAITRESET;
+    }
+}
+
+void action_replay_ciaread(void)
+{
+    if (armodel < 2)
+        return;
+    if (action_replay_flag != ACTION_REPLAY_IDLE) return;
+    if (action_replay_flag == ACTION_REPLAY_INACTIVE) return;
+    if (armode < 2) /* If there are no active breakpoints*/ return;
+    if (m68k_getpc() >= 0x200) return;
+    action_replay_flag = ACTION_REPLAY_ACTIVATE;
+    set_special (SPCFLAG_ACTION_REPLAY);
+}
+
+int action_replay_freeze(void)
+{
+    if(action_replay_flag == ACTION_REPLAY_IDLE) 
+    {
+       if (armodel == 1)
+       {
+           action_replay_chipwrite();
+       }
+       else
+       {
+           action_replay_flag = ACTION_REPLAY_ACTIVATE;
+           set_special (SPCFLAG_ACTION_REPLAY);
+           armode = ARMODE_FREEZE;
+       }
+       return 1;
+    } else if(hrtmon_flag == ACTION_REPLAY_IDLE) {
+        hrtmon_flag = ACTION_REPLAY_ACTIVATE;
+        set_special (SPCFLAG_ACTION_REPLAY);
+       return 1;
+    }
+    return 0;
+}
+
+void action_replay_chipwrite(void)
+{
+    if (armodel > 1) 
+    {
+        action_replay_flag = ACTION_REPLAY_DORESET;
+        set_special (SPCFLAG_ACTION_REPLAY);
+    }
+    else
+    {
+       /* copy 0x60 addr info to level 7 */
+       /* This is to emulate the 0x60 interrupt. */
+       copyfromamiga (artemp, (uae_u8*)regs.vbr + 0x60, 4);
+       copytoamiga ((uae_u8*)regs.vbr + 0x7c, artemp, 4);
+       ar_wait_pop = 1; /* Wait for stack to pop. */
+       action_replay_flag = ACTION_REPLAY_ACTIVATE;
+       set_special (SPCFLAG_ACTION_REPLAY);
+    }
+}
+
+void action_replay_hide(void)
+{
+    hide_cart(1);
+    action_replay_flag = ACTION_REPLAY_IDLE;
+}
+
+void hrtmon_hide(void)
+{
+    hrtmon_flag = ACTION_REPLAY_IDLE;
+/*  write_log_debug("HRTMON: exit\n"); */
+}
+
+void hrtmon_breakenter(void)
+{
+    hrtmon_flag = ACTION_REPLAY_HIDE;
+    set_special (SPCFLAG_ACTION_REPLAY);
+/*    write_log_debug("HRTMON: In hrtmon routine.\n"); */
+}
+
+
+/* Disabling copperlist processing:
+ * On: ar317 an rts at 41084c does it.
+ * On: ar214: an rts at 41068e does it.
+ */
+
+
+/* Original AR3 only works with KS 1.3
+ * this patch fixes that problem.
+ */
+
+static uae_u8 ar3patch1[]={0x20,0xc9,0x51,0xc9,0xff,0xfc};
+static uae_u8 ar3patch2[]={0x00,0xfc,0x01,0x44};
+
+static void action_replay_patch(void)
+{
+    int off1,off2;
+    uae_u8 *kickmem = kickmemory;
+
+    if (armodel != 3 || !kickmem)
+        return;
+    if (!memcmp (kickmem, kickmem + 262144, 262144)) off1 = 262144; else off1 = 0;
+    for (;;) {  
+        if (!memcmp (kickmem + off1, ar3patch1, sizeof (ar3patch1)) || off1 == 524288 - sizeof (ar3patch1)) break;
+        off1++;
+    }
+    off2 = 0;
+    for(;;) {
+        if (!memcmp (armemory_rom + off2, ar3patch2, sizeof(ar3patch2)) || off2 == ar_rom_file_size - sizeof (ar3patch2)) break;
+        off2++;
+    }
+    if (off1 == 524288 - sizeof (ar3patch1) || off2 == ar_rom_file_size - sizeof (ar3patch2))
+       return;
+    armemory_rom[off2 + 0] = (uae_u8)((off1 + kickmem_start + 2) >> 24);
+    armemory_rom[off2 + 1] = (uae_u8)((off1 + kickmem_start + 2) >> 16);
+    armemory_rom[off2 + 2] = (uae_u8)((off1 + kickmem_start + 2) >> 8);
+    armemory_rom[off2 + 3] = (uae_u8)((off1 + kickmem_start + 2) >> 0);
+    write_log ("AR ROM patched for KS2.0+\n");
+}
+
+/* Returns 0 if the checksum is OK. 
+ * Else, it returns the calculated checksum.
+ * Note: Will be wrong if the checksum is zero, but i'll take my chances on that not happenning ;) 
+ */
+static uae_u32 action_replay_calculate_checksum()
+{
+       uae_u32* checksum_end;
+       uae_u32* checksum_start;
+       uae_u8   checksum_start_offset[] = {0, 0, 4, 0x7c};
+       uae_u32 checksum = 0;
+       uae_u32 stored_checksum;
+
+       /* All models: The checksum is calculated right upto the long checksum in the rom.
+        * AR1: The checksum starts at offset 0.
+        * AR1: The checksum is the last non-zero long in the rom.
+        * AR2: The checksum starts at offset 4.
+        * AR2: The checksum is the last Long in the rom.
+        * AR3: The checksum starts at offset 0x7c. 
+        * AR3: The checksum is the last Long in the rom.
+        *
+   * Checksums: (This is a good way to compare roms. I have two with different md5sums,
+        * but the same checksum, so the difference must be in the first four bytes.)
+        * 3.17 0xf009bfc9  
+        * 3.09 0xd34d04a7
+        * 2.14 0xad839d36
+        * 2.14 0xad839d36
+        * 1.15 0xee12116
+   */
+       
+       if (!armemory_rom)
+           return 0; /* If there is no rom then i guess the checksum is ok */
+
+       checksum_start = (uae_u32*)&armemory_rom[checksum_start_offset[armodel]];
+       checksum_end = (uae_u32*)&armemory_rom[ar_rom_file_size];
+
+       /* Search for first non-zero Long starting from the end of the rom. */
+       /* Assume long alignment, (will always be true for AR2 and AR3 and the AR1 rom i've got). */
+       /* If anyone finds an AR1 rom with a word-aligned checksum, then this code will have to be modified. */         
+       while (! *(--checksum_end) );
+               
+       if ( armodel == 1)
+       {
+         uae_u16* rom_ptr_word;
+         uae_s16  sign_extended_word;
+               
+               rom_ptr_word = (uae_u16*)checksum_start;
+               while ( rom_ptr_word != (uae_u16*)checksum_end )
+               {
+                               sign_extended_word = (uae_s16)do_get_mem_word (rom_ptr_word);
+                               /* When the word is cast on the following line, it will get sign-extended. */
+                         checksum += (uae_u32)sign_extended_word;
+                               rom_ptr_word++;
+               }
+       }
+       else
+       {       
+         uae_u32* rom_ptr_long;
+
+               rom_ptr_long = checksum_start;
+               while ( rom_ptr_long != checksum_end )
+               {
+                         checksum += do_get_mem_long (rom_ptr_long);
+                               rom_ptr_long++;
+               }
+       }
+       
+       stored_checksum = do_get_mem_long(checksum_end); 
+
+       return checksum == stored_checksum ? 0 : checksum;
+}
+
+/* Returns 0 on error. */
+static uae_u8* get_checksum_location()
+{
+       uae_u32* checksum_end;
+
+       /* See action_replay_calculate_checksum() for checksum info. */
+       
+       if (!armemory_rom)
+               return 0;
+
+       checksum_end = (uae_u32*)&armemory_rom[ar_rom_file_size];
+
+       /* Search for first non-zero Long starting from the end of the rom. */  
+       while (! *(--checksum_end) );
+
+       return (uae_u8*)checksum_end;
+}
+
+
+/* Replaces the existing cart checksum with a correct one. */
+/* Useful if you want to patch the rom. */
+static void action_replay_fixup_checksum(uae_u32 new_checksum)
+{
+       uae_u32* checksum = (uae_u32*)get_checksum_location();
+       if ( checksum )
+       {
+               do_put_mem_long(checksum, new_checksum);
+       }
+       else
+       {
+               write_log("Unable to locate Checksum in ROM.\n");
+       }
+       return;
+}
+
+/* Longword search on word boundary
+ * the search_value is assumed to already be in the local endian format 
+ * return 0 on failure
+ */
+static uae_u8* find_absolute_long(uae_u8* start_addr, uae_u8* end_addr, uae_u32 search_value)
+{
+       uae_u8* addr;
+       
+       for ( addr = start_addr; addr < end_addr; )
+       {
+               if ( do_get_mem_long((uae_u32*)addr) == search_value )
+               {
+/*                     write_log_debug("Found %p at offset %p.\n", search_value, addr - start_addr);*/
+                       return addr;
+               }
+               addr+=2;
+       }
+       return 0;
+}      
+
+/* word search on word boundary
+ * the search_addr is assumed to already be in the local endian format 
+ * return 0 on failure
+ * Currently only tested where the address we are looking for is AFTER the instruction.
+ * Not sure it works with negative offsets. 
+ */
+static uae_u8* find_relative_word(uae_u8* start_addr, uae_u8* end_addr, uae_u16 search_addr)
+{
+       uae_u8* addr;
+       
+       for ( addr = start_addr; addr < end_addr; )
+       {
+               if ( do_get_mem_word((uae_u16*)addr) == (uae_u16)(search_addr - (uae_u16)(addr-start_addr)) )
+               {
+/*                     write_log_debug("Found %p at offset %p.\n", search_addr, addr - start_addr);*/
+                       return addr;
+               }
+               addr+=2;
+       }
+       return 0;
+}
+
+/* Disable rom test */ 
+/* This routine replaces the rom-test routine with a 'rts'. 
+ * It does this in a 'safe' way, by searching for a reference to the checksum 
+ * and only disables it if the surounding bytes are what it expects. 
+ */
+
+static void disable_rom_test()
+{
+    uae_u8* addr;
+       
+    uae_u8* start_addr = armemory_rom;
+    uae_u8* end_addr = get_checksum_location();
+
+/*
+ * To see what the routine below is doing. Here is some code from the Action replay rom where it does the
+ * checksum test.
+ * AR1:
+ * F0D4D0 6100 ???? bsr.w   calc_checksum ; calculate the checksum
+ * F0D4D4 41FA 147A lea     (0xf0e950,PC),a0   ; load the existing checksum. 
+ * ; do a comparison.
+ * AR2:
+ * 40EC92 6100 ???? bsr.w   calc_checksum
+ * 40EC96 41F9 0041 FFFC lea (0x41fffc),a0
+ */
+
+       if ( armodel == 1)
+       {
+         uae_u16 search_value_rel = end_addr - start_addr;
+               addr = find_relative_word(start_addr, end_addr, search_value_rel);
+               
+               if ( addr )
+               {
+                       if ( do_get_mem_word((uae_u16*)(addr-6)) == 0x6100 && /* bsr.w */
+                                        do_get_mem_word((uae_u16*)(addr-2)) == 0x41fa )  /* lea relative */ 
+                       {
+                               write_log("Patching to disable ROM TEST.\n");
+                               do_put_mem_word((uae_u16*)(addr-6), 0x4e75); /* rts */
+                       }
+               }
+       }
+       else
+       {
+         uae_u32 search_value_abs = arrom_start + end_addr - start_addr;
+               addr = find_absolute_long(start_addr, end_addr, search_value_abs);
+
+               if ( addr )
+               {
+                       if ( do_get_mem_word((uae_u16*)(addr-6)) == 0x6100 && /* bsr.w */
+                                        do_get_mem_word((uae_u16*)(addr-2)) == 0x41f9 )  /* lea absolute */ 
+                       {
+                               write_log("Patching to disable ROM TEST.\n");
+                               do_put_mem_word((uae_u16*)(addr-6), 0x4e75); /* rts */
+                       }
+               }
+       }
+}      
+       
+/* After we have calculated the checksum, and verified the rom is ok,
+ * we can do two things.
+ * 1. (optionally)Patch it and then update the checksum.
+ * 2. Remove the checksum check and (optionally) patch it.
+ * I have chosen to use no.2 here, because it should speed up the Action Replay slightly (and it was fun).
+ */
+static void action_replay_checksum_info(void)
+{
+    if (!armemory_rom)
+       return;
+    if ( action_replay_calculate_checksum() == 0 )
+    {
+       write_log("Action Replay Checksum is OK.\n");
+    }
+    else
+    {
+       write_log("Action Replay Checksum is INVALID.\n");
+    }
+    disable_rom_test();
+}
+
+
+
+static void action_replay_setbanks (void)
+{
+    if (!savestate_state && chipmem_bank.lput == chipmem_lput) {
+        switch (armodel)
+        {
+            case 2:
+            case 3:
+            if (currprefs.cpu_cycle_exact)
+                chipmem_bank.wput = chipmem_wput_actionreplay23;
+            chipmem_bank.lput = chipmem_lput_actionreplay23;
+            break;
+            case 1:
+            chipmem_bank.bput = chipmem_bput_actionreplay1;
+            chipmem_bank.wput = chipmem_wput_actionreplay1;
+            chipmem_bank.lput = chipmem_lput_actionreplay1;
+            break;
+        }
+   } 
+}
+
+static void action_replay_unsetbanks (void)
+{
+    chipmem_bank.bput = chipmem_bput;
+    chipmem_bank.wput = chipmem_wput;
+    chipmem_bank.lput = chipmem_lput;
+}
+
+/* param to allow us to unload the cart. Currently we know it is safe if we are doing a reset to unload it.*/
+int action_replay_unload(int in_memory_reset)
+{      
+       char* state[] = 
+       { 
+               "ACTION_REPLAY_WAIT_PC", 
+               "ACTION_REPLAY_INACTIVE",
+               "ACTION_REPLAY_WAITRESET",
+               "0",
+               "ACTION_REPLAY_IDLE",
+               "ACTION_REPLAY_ACTIVATE",
+               "ACTION_REPLAY_ACTIVE",
+               "ACTION_REPLAY_DORESET",
+               "ACTION_REPLAY_HIDE",
+       };
+       
+       write_log_debug("Action Replay State:(%s) Hrtmon State:(%s)\n", state[action_replay_flag+3],state[hrtmon_flag+3] );
+       
+       if ( armemory_rom && armodel == 1 )
+       {
+               if ( is_ar_pc_in_ram() || is_ar_pc_in_rom() || action_replay_flag == ACTION_REPLAY_WAIT_PC )
+               {
+                       write_log("Can't Unload Action Replay 1. It is Active.\n");
+                       return 0;
+               }
+       }
+       else
+       {
+               if ( action_replay_flag != ACTION_REPLAY_IDLE && action_replay_flag != ACTION_REPLAY_INACTIVE )
+               {
+                       write_log("Can't Unload Action Replay. It is Active.\n");
+                       return 0; /* Don't unload it whilst it's active, or it will crash the amiga if not the emulator */
+               }
+               if ( hrtmon_flag != ACTION_REPLAY_IDLE && hrtmon_flag != ACTION_REPLAY_INACTIVE )
+               {
+                       write_log("Can't Unload Hrtmon. It is Active.\n");
+                       return 0; /* Don't unload it whilst it's active, or it will crash the amiga if not the emulator */
+               }
+       }
+
+       unset_special(SPCFLAG_ACTION_REPLAY); /* This shouldn't be necessary here, but just in case. */
+       action_replay_flag = ACTION_REPLAY_INACTIVE;
+       hrtmon_flag = ACTION_REPLAY_INACTIVE;
+       action_replay_unsetbanks();
+       action_replay_unmap_banks();
+       hrtmon_unmap_banks();
+       /* Make sure you unmap everything before you call action_replay_cleanup() */
+       action_replay_cleanup();
+       return 1;
+}
+       
+
+int action_replay_load(void)
+{
+    struct zfile *f;
+
+    armodel = 0;
+    action_replay_flag = ACTION_REPLAY_INACTIVE;
+    write_log_debug("Entered action_replay_load()\n");
+    /* Don't load a rom if one is already loaded. Use action_replay_unload() first. */
+    if (armemory_rom || hrtmemory)
+    {
+       write_log("action_replay_load() ROM already loaded.\n");
+        return 0;
+    }
+
+    if (strlen(currprefs.cartfile) == 0)
+        return 0;
+    f = zfile_fopen(currprefs.cartfile,"rb");
+    if (!f) {
+        write_log("failed to load '%s' Action Replay ROM\n", currprefs.cartfile);
+        return 0;
+    }
+    zfile_fseek(f, 0, SEEK_END);
+    ar_rom_file_size = zfile_ftell(f);
+    zfile_fseek(f, 0, SEEK_SET);
+    if (ar_rom_file_size != 65536 && ar_rom_file_size != 131072 && ar_rom_file_size != 262144) {
+        write_log("rom size must be 64KB (AR1), 128KB (AR2) or 256KB (AR3)\n");
+        zfile_fclose(f);
+        return 0;
+    }
+    action_replay_flag = ACTION_REPLAY_INACTIVE;
+    armemory_rom = xmalloc (ar_rom_file_size);
+    zfile_fread (armemory_rom, ar_rom_file_size, 1, f);
+    zfile_fclose (f);
+    if (ar_rom_file_size == 65536) {
+        armodel = 1;
+        arrom_start = 0xf00000;
+        arrom_size = 0x10000;
+         /* real AR1 RAM location is 0x9fc000-0x9fffff */
+        arram_start = 0x9f0000;
+        arram_size = 0x10000;
+    } else {
+        armodel = ar_rom_file_size / 131072 + 1;
+        arrom_start = 0x400000;
+        arrom_size = armodel == 2 ? 0x20000 : 0x40000;
+        arram_start = 0x440000;
+        arram_size = 0x10000;
+    }
+    arram_mask = arram_size - 1;
+    arrom_mask = arrom_size - 1;
+    armemory_ram = xcalloc (arram_size, 1);
+    write_log("Action Replay %d installed at %08.8X, size %08.8X\n", armodel, arrom_start, arrom_size);
+    action_replay_setbanks ();
+    action_replay_version();
+    return armodel;
+}
+
+void action_replay_init (int activate)
+{
+    if (!armemory_rom)
+        return;
+    hide_cart (0);
+    if (armodel > 1)
+        hide_cart (1);
+    if (activate) {
+        if (armodel > 1)
+            action_replay_flag = ACTION_REPLAY_WAITRESET;
+    }
+}
+
+/* This only deallocates memory, it is not suitable for unloading roms and continuing */
+void action_replay_cleanup()
+{
+    if (armemory_rom)
+       free (armemory_rom);
+    if (armemory_ram)
+       free (armemory_ram);
+    if (hrtmemory)
+       free (hrtmemory);
+
+    armemory_rom = 0;
+    armemory_ram = 0;
+    hrtmemory = 0;
+}
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+typedef struct {
+        char jmps[20];
+        unsigned int mon_size;
+        unsigned short col0, col1;
+        char right;
+        char keyboard;
+        char key;
+        char ide;
+        char a1200;
+        char aga;
+        char insert;
+        char delay;
+        char lview;
+        char cd32;
+        char screenmode;
+        char vbr;
+        char entered;
+        char hexmode;
+        unsigned short error_sr;
+        unsigned int error_pc;
+        unsigned short error_status;
+        char newid[6];
+        unsigned short        mon_version;
+        unsigned short        mon_revision;
+        unsigned int        whd_base;
+        unsigned short        whd_version;
+        unsigned short        whd_revision;
+        unsigned int        max_chip;
+        unsigned int        custom;
+} HRTCFG;
+
+static void hrtmon_configure(HRTCFG *cfg)
+{
+do_put_mem_word(&cfg->col0,0x000);
+do_put_mem_word(&cfg->col1,0xeee);
+cfg->right = 0;
+cfg->key = FALSE;
+cfg->ide = 0;
+cfg->a1200 = 0;
+cfg->aga = (currprefs.chipset_mask & 4) ? 1 : 0;
+cfg->insert = TRUE;
+cfg->delay = 15;
+cfg->lview = FALSE;
+cfg->cd32 = 0;
+cfg->screenmode = 0;
+cfg->vbr = TRUE;
+cfg->hexmode = FALSE;
+cfg->mon_size=0;
+cfg->hexmode = TRUE;
+do_put_mem_long(&cfg->max_chip,currprefs.chipmem_size);
+hrtmon_custom = do_get_mem_long ((uae_u32*)&cfg->custom)+hrtmemory;
+}
+
+static void hrtmon_reloc(uae_u32 *mem,uae_u32 *header)
+{
+    uae_u32 *p;
+    uae_u8 *base;
+    uae_u32 len, i;
+
+    len=do_get_mem_long(header+7); /* Get length of file from exe header.*/
+    p=mem+len+3;
+    len=do_get_mem_long(p-2);
+    for(i=0;i<len;i++) {
+        base=(uae_u8*)do_get_mem_long(p)+(uae_u32)mem;
+        do_put_mem_long((uae_u32*)base, do_get_mem_long((uae_u32*)base)+hrtmem_start);
+        p++;
+    }
+}
+
+static uae_u8 hrt_header[] = { 
+       0x0, 0x0, 0x3, 0xf3,
+       0x0, 0x0, 0x0, 0x0,
+       0x0, 0x0, 0x0, 0x1,
+       0x0, 0x0, 0x0, 0x0,
+       0x0, 0x0, 0x0, 0x0,
+       0x0 
+};
+
+int hrtmon_load(int activate)
+{
+    struct zfile *f;
+    int size;
+    uae_u32 header[8];
+    uae_u32 id_string[2];
+    
+    /* Don't load a rom if one is already loaded. Use action_replay_unload() first. */
+    if (armemory_rom)
+        return 0;
+    if (hrtmemory)
+      return 0;
+    
+    armodel = 0;
+    if (strlen(currprefs.cartfile) == 0)
+        return 0;
+    f=zfile_fopen(currprefs.cartfile,"rb");
+    if(!f) {
+        write_log("failed to load '%s' HRTMon ROM\n", currprefs.cartfile);
+        return 0;
+    }
+    zfile_fseek(f,0,SEEK_END);
+    size = zfile_ftell(f) - 8*4;
+    zfile_fseek(f,0,SEEK_SET);
+    if ( size < sizeof(header)+sizeof(id_string) )
+    {
+       write_log("Not a Hrtmon Rom.\n");
+       zfile_fclose (f);
+       return 0;
+    }
+    zfile_fread(header,sizeof(header),1,f);            
+
+    /* Check the header */
+/*  uae_u8* ptr = (uae_u8*)&header; */
+/*  for ( ; ptr < sizeof(header); ptr++) */
+/*  { */
+/*     if ( *ptr != *header */
+               
+    zfile_fread(id_string,sizeof(id_string),1,f);              
+    if (strncmp((char*)&id_string[1], "HRT!",4) != 0 )
+    {
+       write_log("Not a Hrtmon Rom\n");
+       zfile_fclose (f);
+       return 0;
+    }
+    zfile_fseek(f,sizeof(header),SEEK_SET);
+               
+    hrtmem_size = size;
+    hrtmem_size += 65535;
+    hrtmem_size &= ~65535;
+    hrtmem_mask = hrtmem_size - 1;
+    hrtmem_start = HRTMON_BASE;
+    hrtmemory = xmalloc (hrtmem_size);
+    zfile_fread (hrtmemory,size,1,f);
+    zfile_fclose (f);
+    hrtmon_configure((HRTCFG*)hrtmemory);
+    hrtmon_reloc((uae_u32*)hrtmemory,/*(uae_u32*)*/header);
+    hrtmem_bank.baseaddr = hrtmemory;
+    hrtmon_flag = ACTION_REPLAY_IDLE;
+    if(!activate) hrtmon_flag = ACTION_REPLAY_INACTIVE;
+    write_log("HRTMon installed at %08.8X, size %08.8X\n",hrtmem_start, hrtmem_size);
+    return 1;
+}
+
+void hrtmon_map_banks()
+{
+    if(!hrtmemory)
+        return;
+
+    map_banks (&hrtmem_bank, hrtmem_start >> 16, hrtmem_size >> 16, hrtmem_size);
+}
+
+static void hrtmon_unmap_banks()
+{
+    if(!hrtmemory)
+        return;
+
+    map_banks (&dummy_bank, hrtmem_start >> 16, hrtmem_size >> 16, hrtmem_size);
+}
+
+
+
+#define AR_VER_STR_OFFSET 0x4 /* offset in the rom where the version string begins. */
+#define AR_VER_STR_END 0x7c   /* offset in the rom where the version string ends. */
+#define AR_VER_STR_LEN (AR_VER_STR_END - AR_VER_STR_OFFSET)
+char arVersionString[AR_VER_STR_LEN+1];
+
+/* This function extracts the version info for AR2 and AR3. */
+
+void action_replay_version()
+{
+    char* tmp;
+    int iArVersionMajor = -1 ;
+    int iArVersionMinor = -1;
+    char* pNext;
+    char sArDate[11];
+    *sArDate = '\0';
+
+    if (!armemory_rom)
+        return;
+   
+    if ( armodel == 1 )
+           return; /* no support yet. */
+    
+    /* Extract Version string */
+    memcpy(arVersionString, armemory_rom+AR_VER_STR_OFFSET, AR_VER_STR_LEN);
+    arVersionString[AR_VER_STR_LEN]= '\0';
+    tmp = strchr(arVersionString, 0x0d);
+    if ( tmp )
+    {
+        *tmp = '\0';
+    }
+/*    write_log_debug("Version string is : '%s'\n", arVersionString); */
+    
+    tmp = strchr(arVersionString,')');
+    if ( tmp )
+    {
+        *tmp = '\0';
+        tmp = strchr(arVersionString, '(');
+        if ( tmp )
+        {
+            if ( *(tmp + 1 ) == 'V' )
+            {
+                pNext = tmp + 2;
+                tmp = strchr(pNext, '.');
+                if ( tmp )
+                {
+                    *tmp = '\0';
+                    iArVersionMajor = atoi(pNext);
+                    pNext = tmp+1;
+                    tmp = strchr(pNext, ' ');
+                    if ( tmp )
+                    {
+                        *tmp = '\0';
+                        iArVersionMinor = atoi(pNext);
+                    }
+                    pNext = tmp+1;
+                    strcpy(sArDate, pNext);
+                }
+
+            }
+        }
+    }
+
+    if ( iArVersionMajor > 0 )
+    {
+        write_log("Version of cart is '%d.%.02d', date is '%s'\n", iArVersionMajor, iArVersionMinor, sArDate);
+    }
+}
+/* This function doesn't reset the Cart memory, it is just called during a memory reset */
+void action_replay_memory_reset(void)
+{
+    #ifdef ACTION_REPLAY
+    if ( armemory_rom )
+    {
+       action_replay_hide();
+    }
+    #endif
+    #ifdef ACTION_REPLAY_HRTMON
+    if ( hrtmemory ) 
+    {
+       hrtmon_hide(); /* It is never really idle */
+    }
+    #endif
+    #ifdef ACTION_REPLAY_COMMON
+    check_prefs_changed_carts(1);
+    #endif
+    action_replay_patch();
+    action_replay_checksum_info();
+}
+
+uae_u8 *save_action_replay (int *len, uae_u8 *dstptr)
+{
+    uae_u8 *dstbak,*dst;
+
+    *len = 1;
+    if (!armemory_ram || !armemory_rom || !armodel)
+       return 0;
+    *len = 1 + strlen(currprefs.cartfile) + 1 + arram_size + 256;
+    if (dstptr)
+       dstbak = dst = dstptr;
+    else
+        dstbak = dst = malloc (*len);
+    save_u8 (armodel);
+    strcpy (dst, currprefs.cartfile);
+    dst += strlen(dst) + 1;
+    memcpy (dst, armemory_ram, arram_size);
+    return dstbak;
+}
+
+uae_u8 *restore_action_replay (uae_u8 *src)
+{
+    action_replay_unload (1);
+    armodel = restore_u8 ();
+    if (!armodel)
+       return src;
+    strncpy (changed_prefs.cartfile, src, 255);
+    strcpy (currprefs.cartfile, changed_prefs.cartfile);
+    src += strlen(src) + 1;
+    action_replay_load ();
+    if (armemory_ram) {
+       memcpy (armemory_ram, src, arram_size);
+       memcpy (ar_custom, armemory_ram + 0xf000, 2 * 256);
+        src += arram_size;
+    }
+    src += 256;
+    return src;
+}
diff --git a/audio.c b/audio.c
new file mode 100755 (executable)
index 0000000..b1b92db
--- /dev/null
+++ b/audio.c
@@ -0,0 +1,1084 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * OS specific functions
+  *
+  * Copyright 1995, 1996, 1997 Bernd Schmidt
+  * Copyright 1996 Marcus Sundberg
+  * Copyright 1996 Manfred Thole
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "memory.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "autoconf.h"
+#include "gensound.h"
+#include "sounddep/sound.h"
+#include "events.h"
+#include "audio.h"
+#include "savestate.h"
+#include "driveclick.h"
+#ifdef AVIOUTPUT
+#include "avioutput.h"
+#endif
+
+#define MAX_EV ~0ul
+//#define DEBUG_AUDIO
+#define DEBUG_CHANNEL_MASK 15
+
+int audio_channel_mask = 15;
+
+static int debugchannel (int ch)
+{
+    if ((1 << ch) & DEBUG_CHANNEL_MASK) return 1;
+    return 0;
+}
+
+struct audio_channel_data {
+    unsigned long adk_mask;
+    unsigned long evtime;
+    uae_u8 dmaen, intreq2;
+    uaecptr lc, pt;
+    int current_sample, last_sample;
+    int *voltbl;
+    int state;    
+    int per;
+    int vol;
+    int len, wlen;
+    uae_u16 dat, dat2;
+    int request_word, request_word_skip;
+};
+
+STATIC_INLINE int current_hpos (void)
+{
+    return (get_cycles () - eventtab[ev_hsync].oldcycles) / CYCLE_UNIT;
+}
+
+static struct audio_channel_data audio_channel[4];
+int sound_available = 0;
+static int sound_table[64][256];
+void (*sample_handler) (void);
+
+unsigned long sample_evtime, scaled_sample_evtime;
+
+static unsigned long last_cycles, next_sample_evtime;
+
+void init_sound_table16 (void)
+{
+    int i,j;
+
+    for (i = 0; i < 256; i++)
+       for (j = 0; j < 64; j++)
+           sound_table[j][i] = j * (uae_s8)i * (currprefs.stereo ? 2 : 1);
+}
+
+void init_sound_table8 (void)
+{
+    int i,j;
+
+    for (i = 0; i < 256; i++)
+       for (j = 0; j < 64; j++)
+           sound_table[j][i] = (j * (uae_s8)i * (currprefs.stereo ? 2 : 1)) / 256;
+}
+
+#define MULTIPLICATION_PROFITABLE
+
+#ifdef MULTIPLICATION_PROFITABLE
+typedef uae_s8 sample8_t;
+#define DO_CHANNEL_1(v, c) do { (v) *= audio_channel[c].vol; } while (0)
+#define SBASEVAL16(logn) ((logn) == 1 ? SOUND16_BASE_VAL >> 1 : SOUND16_BASE_VAL)
+#define FINISH_DATA(data,b,logn) do { if (14 - (b) + (logn) > 0) (data) >>= 14 - (b) + (logn); else (data) <<= (b) - 14 - (logn); } while (0);
+#else
+typedef uae_u8 sample8_t;
+#define DO_CHANNEL_1(v, c) do { (v) = audio_channel[c].voltbl[(v)]; } while (0)
+#define SBASEVAL16(logn) SOUND16_BASE_VAL
+#define FINISH_DATA(data,b,logn)
+#endif
+
+/* Always put the right word before the left word.  */
+#define DELAY_BUFFER 32
+static uae_u32 right_word_saved[DELAY_BUFFER];
+static uae_u32 left_word_saved[DELAY_BUFFER];
+static int saved_ptr;
+
+STATIC_INLINE void put_sound_word_right (uae_u32 w)
+{
+    if (currprefs.mixed_stereo) {
+       right_word_saved[saved_ptr] = w;
+       return;
+    }
+    PUT_SOUND_WORD_RIGHT (w);
+}
+
+STATIC_INLINE void put_sound_word_left (uae_u32 w)
+{
+    if (currprefs.mixed_stereo) {
+       uae_u32 rold, lold, rnew, lnew, tmp;
+
+       left_word_saved[saved_ptr] = w;
+       lnew = w - SOUND16_BASE_VAL;
+       rnew = right_word_saved[saved_ptr] - SOUND16_BASE_VAL;
+
+       saved_ptr = (saved_ptr + 1) & (DELAY_BUFFER - 1);
+       lold = left_word_saved[saved_ptr] - SOUND16_BASE_VAL;
+       tmp = (rnew * 5 + lold * 3) >> 3;
+       tmp += SOUND16_BASE_VAL;
+       PUT_SOUND_WORD_RIGHT (tmp);
+
+       rold = right_word_saved[saved_ptr] - SOUND16_BASE_VAL;
+       w = (lnew * 5 + rold * 3) >> 3;
+    }
+    PUT_SOUND_WORD_LEFT (w);
+}
+
+#define DO_CHANNEL(v, c) do { (v) &= audio_channel[c].adk_mask; data += v; } while (0);
+
+void sample16_handler (void)
+{
+    uae_u32 data0 = audio_channel[0].current_sample;
+    uae_u32 data1 = audio_channel[1].current_sample;
+    uae_u32 data2 = audio_channel[2].current_sample;
+    uae_u32 data3 = audio_channel[3].current_sample;
+    DO_CHANNEL_1 (data0, 0);
+    DO_CHANNEL_1 (data1, 1);
+    DO_CHANNEL_1 (data2, 2);
+    DO_CHANNEL_1 (data3, 3);
+    data0 &= audio_channel[0].adk_mask;
+    data1 &= audio_channel[1].adk_mask;
+    data2 &= audio_channel[2].adk_mask;
+    data3 &= audio_channel[3].adk_mask;
+    data0 += data1;
+    data0 += data2;
+    data0 += data3;
+    {
+        uae_u32 data = SBASEVAL16(2) + data0;
+        FINISH_DATA (data, 16, 2);
+        PUT_SOUND_WORD (data);
+    }
+    check_sound_buffers ();
+}
+
+void sample16i_rh_handler (void)
+{
+    unsigned long delta, ratio;
+
+    uae_u32 data0 = audio_channel[0].current_sample;
+    uae_u32 data1 = audio_channel[1].current_sample;
+    uae_u32 data2 = audio_channel[2].current_sample;
+    uae_u32 data3 = audio_channel[3].current_sample;
+    uae_u32 data0p = audio_channel[0].last_sample;
+    uae_u32 data1p = audio_channel[1].last_sample;
+    uae_u32 data2p = audio_channel[2].last_sample;
+    uae_u32 data3p = audio_channel[3].last_sample;
+    DO_CHANNEL_1 (data0, 0);
+    DO_CHANNEL_1 (data1, 1);
+    DO_CHANNEL_1 (data2, 2);
+    DO_CHANNEL_1 (data3, 3);
+    DO_CHANNEL_1 (data0p, 0);
+    DO_CHANNEL_1 (data1p, 1);
+    DO_CHANNEL_1 (data2p, 2);
+    DO_CHANNEL_1 (data3p, 3);
+
+    data0 &= audio_channel[0].adk_mask;
+    data0p &= audio_channel[0].adk_mask;
+    data1 &= audio_channel[1].adk_mask;
+    data1p &= audio_channel[1].adk_mask;
+    data2 &= audio_channel[2].adk_mask;
+    data2p &= audio_channel[2].adk_mask;
+    data3 &= audio_channel[3].adk_mask;
+    data3p &= audio_channel[3].adk_mask;
+
+    /* linear interpolation and summing up... */
+    delta = audio_channel[0].per;
+    ratio = ((audio_channel[0].evtime % delta) << 8) / delta;
+    data0 = (data0 * (256 - ratio) + data0p * ratio) >> 8;
+    delta = audio_channel[1].per;
+    ratio = ((audio_channel[1].evtime % delta) << 8) / delta;
+    data0 += (data1 * (256 - ratio) + data1p * ratio) >> 8;
+    delta = audio_channel[2].per;
+    ratio = ((audio_channel[2].evtime % delta) << 8) / delta;
+    data0 += (data2 * (256 - ratio) + data2p * ratio) >> 8;
+    delta = audio_channel[3].per;
+    ratio = ((audio_channel[3].evtime % delta) << 8) / delta;
+    data0 += (data3 * (256 - ratio) + data3p * ratio) >> 8;
+    {
+        uae_u32 data = SBASEVAL16(2) + data0;
+        FINISH_DATA (data, 16, 2);
+        PUT_SOUND_WORD (data);
+    }
+    check_sound_buffers ();
+}
+
+void sample16i_crux_handler (void)
+{
+    uae_u32 data0 = audio_channel[0].current_sample;
+    uae_u32 data1 = audio_channel[1].current_sample;
+    uae_u32 data2 = audio_channel[2].current_sample;
+    uae_u32 data3 = audio_channel[3].current_sample;
+    uae_u32 data0p = audio_channel[0].last_sample;
+    uae_u32 data1p = audio_channel[1].last_sample;
+    uae_u32 data2p = audio_channel[2].last_sample;
+    uae_u32 data3p = audio_channel[3].last_sample;
+    DO_CHANNEL_1 (data0, 0);
+    DO_CHANNEL_1 (data1, 1);
+    DO_CHANNEL_1 (data2, 2);
+    DO_CHANNEL_1 (data3, 3);
+    DO_CHANNEL_1 (data0p, 0);
+    DO_CHANNEL_1 (data1p, 1);
+    DO_CHANNEL_1 (data2p, 2);
+    DO_CHANNEL_1 (data3p, 3);
+
+    data0 &= audio_channel[0].adk_mask;
+    data0p &= audio_channel[0].adk_mask;
+    data1 &= audio_channel[1].adk_mask;
+    data1p &= audio_channel[1].adk_mask;
+    data2 &= audio_channel[2].adk_mask;
+    data2p &= audio_channel[2].adk_mask;
+    data3 &= audio_channel[3].adk_mask;
+    data3p &= audio_channel[3].adk_mask;
+
+    {    
+        struct audio_channel_data *cdp;
+        unsigned long ratio, ratio1;
+#define INTERVAL (scaled_sample_evtime * 3)
+        cdp = audio_channel + 0;
+        ratio1 = cdp->per - cdp->evtime;
+        ratio = (ratio1 << 12) / INTERVAL;
+        if (cdp->evtime < scaled_sample_evtime || ratio1 >= INTERVAL)
+           ratio = 4096;
+        data0 = (data0 * ratio + data0p * (4096 - ratio)) >> 12;
+
+       cdp = audio_channel + 1;
+        ratio1 = cdp->per - cdp->evtime;
+        ratio = (ratio1 << 12) / INTERVAL;
+        if (cdp->evtime < scaled_sample_evtime || ratio1 >= INTERVAL)
+           ratio = 4096;
+        data1 = (data1 * ratio + data1p * (4096 - ratio)) >> 12;
+
+        cdp = audio_channel + 2;
+        ratio1 = cdp->per - cdp->evtime;
+        ratio = (ratio1 << 12) / INTERVAL;
+        if (cdp->evtime < scaled_sample_evtime || ratio1 >= INTERVAL)
+           ratio = 4096;
+        data2 = (data2 * ratio + data2p * (4096 - ratio)) >> 12;
+
+        cdp = audio_channel + 3;
+        ratio1 = cdp->per - cdp->evtime;
+        ratio = (ratio1 << 12) / INTERVAL;
+        if (cdp->evtime < scaled_sample_evtime || ratio1 >= INTERVAL)
+           ratio = 4096;
+        data3 = (data3 * ratio + data3p * (4096 - ratio)) >> 12;
+    }
+    data1 += data2;
+    data0 += data3;
+    data0 += data1;
+    {
+        uae_u32 data = SBASEVAL16(2) + data0;
+        FINISH_DATA (data, 16, 2);
+        PUT_SOUND_WORD (data);
+    }
+    check_sound_buffers ();
+}
+
+#ifdef HAVE_STEREO_SUPPORT
+void sample16ss_handler (void)
+{
+    uae_u32 data0 = audio_channel[0].current_sample;
+    uae_u32 data1 = audio_channel[1].current_sample;
+    uae_u32 data2 = audio_channel[2].current_sample;
+    uae_u32 data3 = audio_channel[3].current_sample;
+    DO_CHANNEL_1 (data0, 0);
+    DO_CHANNEL_1 (data1, 1);
+    DO_CHANNEL_1 (data2, 2);
+    DO_CHANNEL_1 (data3, 3);
+
+    data0 &= audio_channel[0].adk_mask;
+    data1 &= audio_channel[1].adk_mask;
+    data2 &= audio_channel[2].adk_mask;
+    data3 &= audio_channel[3].adk_mask;
+    
+    PUT_SOUND_WORD_LEFT (data0 << 2);
+    PUT_SOUND_WORD_RIGHT (data1 << 2);
+    PUT_SOUND_WORD_LEFT (data2 << 2);
+    PUT_SOUND_WORD_RIGHT (data3 << 2);
+    
+    check_sound_buffers ();
+}
+
+void sample16s_handler (void)
+{
+    uae_u32 data0 = audio_channel[0].current_sample;
+    uae_u32 data1 = audio_channel[1].current_sample;
+    uae_u32 data2 = audio_channel[2].current_sample;
+    uae_u32 data3 = audio_channel[3].current_sample;
+    DO_CHANNEL_1 (data0, 0);
+    DO_CHANNEL_1 (data1, 1);
+    DO_CHANNEL_1 (data2, 2);
+    DO_CHANNEL_1 (data3, 3);
+
+    data0 &= audio_channel[0].adk_mask;
+    data1 &= audio_channel[1].adk_mask;
+    data2 &= audio_channel[2].adk_mask;
+    data3 &= audio_channel[3].adk_mask;
+    
+    data0 += data3;
+    {
+        uae_u32 data = SBASEVAL16(1) + data0;
+        FINISH_DATA (data, 16, 1);
+        put_sound_word_right (data);
+    }
+
+    data1 += data2;
+    {
+        uae_u32 data = SBASEVAL16(1) + data1;  
+        FINISH_DATA (data, 16, 1);
+        put_sound_word_left (data);
+    }
+
+    check_sound_buffers ();
+}
+
+void sample16si_crux_handler (void)
+{
+    uae_u32 data0 = audio_channel[0].current_sample;
+    uae_u32 data1 = audio_channel[1].current_sample;
+    uae_u32 data2 = audio_channel[2].current_sample;
+    uae_u32 data3 = audio_channel[3].current_sample;
+    uae_u32 data0p = audio_channel[0].last_sample;
+    uae_u32 data1p = audio_channel[1].last_sample;
+    uae_u32 data2p = audio_channel[2].last_sample;
+    uae_u32 data3p = audio_channel[3].last_sample;
+
+    DO_CHANNEL_1 (data0, 0);
+    DO_CHANNEL_1 (data1, 1);
+    DO_CHANNEL_1 (data2, 2);
+    DO_CHANNEL_1 (data3, 3);
+    DO_CHANNEL_1 (data0p, 0);
+    DO_CHANNEL_1 (data1p, 1);
+    DO_CHANNEL_1 (data2p, 2);
+    DO_CHANNEL_1 (data3p, 3);
+
+    data0 &= audio_channel[0].adk_mask;
+    data0p &= audio_channel[0].adk_mask;
+    data1 &= audio_channel[1].adk_mask;
+    data1p &= audio_channel[1].adk_mask;
+    data2 &= audio_channel[2].adk_mask;
+    data2p &= audio_channel[2].adk_mask;
+    data3 &= audio_channel[3].adk_mask;
+    data3p &= audio_channel[3].adk_mask;
+
+    {    
+        struct audio_channel_data *cdp;
+        unsigned long ratio, ratio1;
+#define INTERVAL (scaled_sample_evtime * 3)
+        cdp = audio_channel + 0;
+        ratio1 = cdp->per - cdp->evtime;
+        ratio = (ratio1 << 12) / INTERVAL;
+        if (cdp->evtime < scaled_sample_evtime || ratio1 >= INTERVAL)
+           ratio = 4096;
+        data0 = (data0 * ratio + data0p * (4096 - ratio)) >> 12;
+
+        cdp = audio_channel + 1;
+        ratio1 = cdp->per - cdp->evtime;
+        ratio = (ratio1 << 12) / INTERVAL;
+        if (cdp->evtime < scaled_sample_evtime || ratio1 >= INTERVAL)
+           ratio = 4096;
+        data1 = (data1 * ratio + data1p * (4096 - ratio)) >> 12;
+
+        cdp = audio_channel + 2;
+        ratio1 = cdp->per - cdp->evtime;
+        ratio = (ratio1 << 12) / INTERVAL;
+        if (cdp->evtime < scaled_sample_evtime || ratio1 >= INTERVAL)
+           ratio = 4096;
+        data2 = (data2 * ratio + data2p * (4096 - ratio)) >> 12;
+
+        cdp = audio_channel + 3;
+        ratio1 = cdp->per - cdp->evtime;
+        ratio = (ratio1 << 12) / INTERVAL;
+        if (cdp->evtime < scaled_sample_evtime || ratio1 >= INTERVAL)
+           ratio = 4096;
+        data3 = (data3 * ratio + data3p * (4096 - ratio)) >> 12;
+    }
+    data1 += data2;
+    data0 += data3;
+    {
+        uae_u32 data = SBASEVAL16 (1) + data0;
+        FINISH_DATA (data, 16, 1);
+        put_sound_word_right (data);
+    }
+
+    {
+        uae_u32 data = SBASEVAL16 (1) + data1;
+        FINISH_DATA (data, 16, 1);
+        put_sound_word_left (data);
+    }    
+    check_sound_buffers ();
+}
+
+void sample16si_rh_handler (void)
+{
+    unsigned long delta, ratio;
+
+    uae_u32 data0 = audio_channel[0].current_sample;
+    uae_u32 data1 = audio_channel[1].current_sample;
+    uae_u32 data2 = audio_channel[2].current_sample;
+    uae_u32 data3 = audio_channel[3].current_sample;
+    uae_u32 data0p = audio_channel[0].last_sample;
+    uae_u32 data1p = audio_channel[1].last_sample;
+    uae_u32 data2p = audio_channel[2].last_sample;
+    uae_u32 data3p = audio_channel[3].last_sample;
+
+    DO_CHANNEL_1 (data0, 0);
+    DO_CHANNEL_1 (data1, 1);
+    DO_CHANNEL_1 (data2, 2);
+    DO_CHANNEL_1 (data3, 3);
+    DO_CHANNEL_1 (data0p, 0);
+    DO_CHANNEL_1 (data1p, 1);
+    DO_CHANNEL_1 (data2p, 2);
+    DO_CHANNEL_1 (data3p, 3);
+
+    data0 &= audio_channel[0].adk_mask;
+    data0p &= audio_channel[0].adk_mask;
+    data1 &= audio_channel[1].adk_mask;
+    data1p &= audio_channel[1].adk_mask;
+    data2 &= audio_channel[2].adk_mask;
+    data2p &= audio_channel[2].adk_mask;
+    data3 &= audio_channel[3].adk_mask;
+    data3p &= audio_channel[3].adk_mask;
+
+    /* linear interpolation and summing up... */
+    delta = audio_channel[0].per;
+    ratio = ((audio_channel[0].evtime % delta) << 8) / delta;
+    data0 = (data0 * (256 - ratio) + data0p * ratio) >> 8;
+    delta = audio_channel[1].per;
+    ratio = ((audio_channel[1].evtime % delta) << 8) / delta;
+    data1 = (data1 * (256 - ratio) + data1p * ratio) >> 8;
+    delta = audio_channel[2].per;
+    ratio = ((audio_channel[2].evtime % delta) << 8) / delta;
+    data1 += (data2 * (256 - ratio) + data2p * ratio) >> 8;
+    delta = audio_channel[3].per;
+    ratio = ((audio_channel[3].evtime % delta) << 8) / delta;
+    data0 += (data3 * (256 - ratio) + data3p * ratio) >> 8;
+    {
+        uae_u32 data = SBASEVAL16 (1) + data0;
+        FINISH_DATA (data, 16, 1);
+        put_sound_word_right (data);
+    }
+
+    {
+        uae_u32 data = SBASEVAL16 (1) + data1;
+        FINISH_DATA (data, 16, 1);
+        put_sound_word_left (data);
+    }    
+    check_sound_buffers ();
+}
+
+#else
+void sample16s_handler (void)
+{
+    sample16_handler();
+}
+void sample16si_crux_handler (void)
+{
+    sample16i_crux_handler();
+}
+void sample16si_rh_handler (void)
+{
+    sample16i_rh_handler();
+}
+#endif
+
+void schedule_audio (void)
+{
+    unsigned long best = MAX_EV;
+    int i;
+
+    eventtab[ev_audio].active = 0;
+    eventtab[ev_audio].oldcycles = get_cycles ();
+    for (i = 0; i < 4; i++) {
+       struct audio_channel_data *cdp = audio_channel + i;
+       if (cdp->evtime != MAX_EV) {
+           if (best > cdp->evtime) {
+               best = cdp->evtime;
+               eventtab[ev_audio].active = 1;
+           }
+       }       
+    }
+    eventtab[ev_audio].evtime = get_cycles () + best;
+}
+
+static int isirq (int nr)
+{
+    return INTREQR() & (0x80 << nr);
+}
+
+static void setirq (int nr)
+{
+    INTREQ (0x8000 | (0x80 << nr));
+#ifdef DEBUG_AUDIO
+    if (debugchannel (nr))
+        write_log ("SETIRQ %d %08.8X\n", nr, m68k_getpc());
+#endif
+}
+
+static void newsample (int nr, sample8_t sample)
+{
+    struct audio_channel_data *cdp = audio_channel + nr;
+#ifdef DEBUG_AUDIO
+    if (!debugchannel (nr)) sample = 0;
+#endif
+    if (!(audio_channel_mask & (1 << nr)))
+       sample = 0;
+    cdp->last_sample = cdp->current_sample;
+    cdp->current_sample = sample;
+}
+
+static void state23 (struct audio_channel_data *cdp)
+{
+    if (!cdp->dmaen)
+       return;
+    if (cdp->request_word >= 0)
+       return;
+    cdp->request_word = 0;
+    if (cdp->wlen == 1) {
+       cdp->wlen = cdp->len;
+       cdp->pt = cdp->lc;
+       cdp->intreq2 = 1;
+#ifdef DEBUG_AUDIO
+       if (debugchannel (cdp - audio_channel))
+           write_log ("Channel %d looped, LC=%08.8X LEN=%d\n", cdp - audio_channel, cdp->pt, cdp->wlen);
+#endif
+    } else {
+       cdp->wlen = (cdp->wlen - 1) & 0xFFFF;
+    }
+}
+
+static void audio_handler (int nr, int timed)
+{
+    struct audio_channel_data *cdp = audio_channel + nr;
+
+    int audav = adkcon & (0x01 << nr);
+    int audap = adkcon & (0x10 << nr);
+    int napnav = (!audav && !audap) || audav;
+    int evtime = cdp->evtime;
+
+    cdp->evtime = MAX_EV;
+    switch (cdp->state)
+    {
+       case 0:
+           cdp->request_word = 0;
+           cdp->request_word_skip = 0;
+           cdp->intreq2 = 0;
+           if (cdp->dmaen) {
+               cdp->state = 1;
+               cdp->wlen = cdp->len;
+               /* there are too many stupid sound routines that fail on "too" fast cpus.. */
+               if (currprefs.cpu_level > 1)
+                   cdp->pt = cdp->lc;
+#ifdef DEBUG_AUDIO
+               if (debugchannel (nr))
+                   write_log ("%d:0>1: LEN=%d\n", nr, cdp->wlen);
+#endif
+               audio_handler (nr, timed);
+               return;
+           } else if (!cdp->dmaen && cdp->request_word < 0 && !isirq (nr)) {
+               cdp->evtime = 0;
+               cdp->state = 2;
+               setirq (nr);
+               audio_handler (nr, timed);
+               return;
+           }
+       return;
+
+       case 1:
+           if (!cdp->dmaen) {
+               cdp->state = 0;
+               return;
+           }
+           cdp->state = 5;
+           if (cdp->wlen != 1)
+               cdp->wlen = (cdp->wlen - 1) & 0xFFFF;
+           cdp->request_word = 2;
+           if (current_hpos () > maxhpos - 20)
+               cdp->request_word_skip = 1;
+       return;
+
+       case 5:
+           if (!cdp->request_word) {
+               cdp->request_word = 2;
+               return;
+           }
+           setirq (nr);
+           if (!cdp->dmaen) {
+               cdp->state = 0;
+               cdp->request_word = 0;
+               return;
+           }
+           cdp->state = 2;
+           cdp->request_word = 3;
+           if (napnav)
+               cdp->request_word = 2;
+           cdp->dat = cdp->dat2;
+       return;
+
+       case 2:
+           if (currprefs.produce_sound == 0)
+               cdp->per = PERIOD_MAX;
+
+           if (!cdp->dmaen && isirq (nr) && ((cdp->per <= 30 ) || (evtime == 0 || evtime == MAX_EV || evtime == cdp->per))) {
+               cdp->state = 0;
+               cdp->evtime = MAX_EV;
+               cdp->request_word = 0;
+               return;
+           }
+
+           state23 (cdp);
+           cdp->state = 3;
+           cdp->evtime = cdp->per;
+           newsample (nr, (cdp->dat >> 8) & 0xff);
+           cdp->dat <<= 8;
+           /* Period attachment? */
+           if (audap) {
+               if (cdp->intreq2 && cdp->dmaen)
+                   setirq (nr);
+               cdp->intreq2 = 0;
+               cdp->request_word = 1;
+               cdp->dat = cdp->dat2;
+               if (nr < 3) {
+                   if (cdp->dat == 0)
+                       (cdp+1)->per = PERIOD_MAX;
+                   else if (cdp->dat < maxhpos * CYCLE_UNIT / 2 && currprefs.produce_sound < 3)
+                       (cdp+1)->per = maxhpos * CYCLE_UNIT / 2;
+                   else
+                       (cdp+1)->per = cdp->dat * CYCLE_UNIT;
+               }
+           }
+        return;
+       
+       case 3:
+           if (currprefs.produce_sound == 0)
+               cdp->per = PERIOD_MAX;
+           state23 (cdp);
+           cdp->state = 2;
+           cdp->evtime = cdp->per;
+           newsample (nr, (cdp->dat >> 8) & 0xff);
+           cdp->dat <<= 8;
+           cdp->dat = cdp->dat2;
+           if (cdp->dmaen) {
+               if (napnav)
+                   cdp->request_word = 1;
+               if (cdp->intreq2 && napnav)
+                   setirq (nr);
+           } else {
+               if (napnav)
+                   setirq (nr);
+           }
+           cdp->intreq2 = 0;
+
+           /* Volume attachment? */
+           if (audav) {
+               if (nr < 3) {
+                   (cdp+1)->vol = cdp->dat;
+                   #ifndef MULTIPLICATION_PROFITABLE
+                   (cdp+1)->voltbl = sound_table[cdp->dat];
+                   #endif
+               }
+           }
+        return;
+    }
+}
+
+void audio_reset (void)
+{
+    int i;
+    struct audio_channel_data *cdp;
+
+#ifdef AHI
+    ahi_close_sound ();
+#endif
+    reset_sound ();
+    if (savestate_state != STATE_RESTORE) {
+       for (i = 0; i < 4; i++) {
+           cdp = &audio_channel[i];
+           memset (cdp, 0, sizeof *audio_channel);
+           cdp->per = PERIOD_MAX - 1;
+           cdp->voltbl = sound_table[0];
+           cdp->vol = 0;
+           cdp->evtime = MAX_EV;
+       }
+    } else {
+       for (i = 0; i < 4; i++) {
+           cdp = &audio_channel[i];
+           cdp->dmaen = (dmacon & DMA_MASTER) && (dmacon & (1 << i));
+       }
+    }
+
+#ifndef MULTIPLICATION_PROFITABLE
+    for (i = 0; i < 4; i++)
+       audio_channel[i].voltbl = sound_table[audio_channel[i].vol];
+#endif
+
+    last_cycles = get_cycles ();
+    next_sample_evtime = scaled_sample_evtime;
+    schedule_audio ();
+    events_schedule ();
+}
+
+STATIC_INLINE int sound_prefs_changed (void)
+{
+    return (changed_prefs.produce_sound != currprefs.produce_sound
+           || changed_prefs.win32_soundcard != currprefs.win32_soundcard
+           || changed_prefs.stereo != currprefs.stereo
+           || changed_prefs.mixed_stereo != currprefs.mixed_stereo
+           || changed_prefs.sound_maxbsiz != currprefs.sound_maxbsiz
+           || changed_prefs.sound_freq != currprefs.sound_freq
+           || changed_prefs.sound_adjust != currprefs.sound_adjust
+           || changed_prefs.sound_interpol != currprefs.sound_interpol
+           || changed_prefs.sound_volume != currprefs.sound_volume
+           || changed_prefs.sound_filter != currprefs.sound_filter);
+}
+
+void check_prefs_changed_audio (void)
+{
+#ifdef DRIVESOUND
+    driveclick_check_prefs ();
+#endif
+    if (sound_available && sound_prefs_changed ()) {
+       close_sound ();
+#ifdef AVIOUTPUT
+       AVIOutput_Restart ();
+#endif
+
+       currprefs.produce_sound = changed_prefs.produce_sound;
+       currprefs.win32_soundcard = changed_prefs.win32_soundcard;
+       currprefs.stereo = changed_prefs.stereo;
+       currprefs.mixed_stereo = changed_prefs.mixed_stereo;
+       currprefs.sound_adjust = changed_prefs.sound_adjust;
+       currprefs.sound_interpol = changed_prefs.sound_interpol;
+       currprefs.sound_freq = changed_prefs.sound_freq;
+       currprefs.sound_maxbsiz = changed_prefs.sound_maxbsiz;
+       currprefs.sound_filter = changed_prefs.sound_filter;
+       currprefs.sound_volume = changed_prefs.sound_volume;
+       if (currprefs.produce_sound >= 2) {
+           if (!init_audio ()) {
+               if (! sound_available) {
+                   write_log ("Sound is not supported.\n");
+               } else {
+                   write_log ("Sorry, can't initialize sound.\n");
+                   currprefs.produce_sound = 0;
+                   /* So we don't do this every frame */
+                   changed_prefs.produce_sound = 0;
+               }
+           }
+       }
+       last_cycles = get_cycles () - 1;
+       next_sample_evtime = scaled_sample_evtime;
+       compute_vsynctime ();
+    }
+    /* Select the right interpolation method.  */
+    if (sample_handler == sample16_handler
+       || sample_handler == sample16i_crux_handler
+       || sample_handler == sample16i_rh_handler)
+       sample_handler = (currprefs.sound_interpol == 0 ? sample16_handler
+                         : currprefs.sound_interpol == 1 ? sample16i_rh_handler
+                         : sample16i_crux_handler);
+    else if (sample_handler == sample16s_handler
+            || sample_handler == sample16si_crux_handler
+            || sample_handler == sample16si_rh_handler)
+       sample_handler = (currprefs.sound_interpol == 0 ? sample16s_handler
+                         : currprefs.sound_interpol == 1 ? sample16si_rh_handler
+                         : sample16si_crux_handler);
+
+    if (currprefs.produce_sound == 0) {
+       eventtab[ev_audio].active = 0;
+       events_schedule ();
+    }
+}
+
+void update_audio (void)
+{
+    unsigned long int n_cycles;
+
+    if (currprefs.produce_sound == 0 || savestate_state == STATE_RESTORE)
+       return;
+
+    n_cycles = get_cycles () - last_cycles;
+    for (;;) {
+       unsigned long int best_evtime = n_cycles + 1;
+
+        if (audio_channel[0].evtime != MAX_EV && best_evtime > audio_channel[0].evtime)
+           best_evtime = audio_channel[0].evtime;
+        if (audio_channel[1].evtime != MAX_EV && best_evtime > audio_channel[1].evtime)
+           best_evtime = audio_channel[1].evtime;
+        if (audio_channel[2].evtime != MAX_EV && best_evtime > audio_channel[2].evtime)
+           best_evtime = audio_channel[2].evtime;
+        if (audio_channel[3].evtime != MAX_EV && best_evtime > audio_channel[3].evtime)
+           best_evtime = audio_channel[3].evtime;
+       
+       if (currprefs.produce_sound > 1 && best_evtime > next_sample_evtime)
+           best_evtime = next_sample_evtime;
+
+       if (best_evtime > n_cycles)
+           break;
+
+        if (audio_channel[0].evtime != MAX_EV)
+           audio_channel[0].evtime -= best_evtime;
+        if (audio_channel[1].evtime != MAX_EV)
+           audio_channel[1].evtime -= best_evtime;
+        if (audio_channel[2].evtime != MAX_EV)
+           audio_channel[2].evtime -= best_evtime;
+        if (audio_channel[3].evtime != MAX_EV)
+           audio_channel[3].evtime -= best_evtime;
+
+       n_cycles -= best_evtime;
+       if (currprefs.produce_sound > 1) {
+           next_sample_evtime -= best_evtime;
+           if (next_sample_evtime == 0) {
+               next_sample_evtime = scaled_sample_evtime;
+               (*sample_handler) ();
+           }
+       }
+        if (audio_channel[0].evtime == 0)
+           audio_handler (0, 1);
+        if (audio_channel[1].evtime == 0)
+           audio_handler (1, 1);
+        if (audio_channel[2].evtime == 0)
+           audio_handler (2, 1);
+        if (audio_channel[3].evtime == 0)
+           audio_handler (3, 1);
+    }
+    last_cycles = get_cycles () - n_cycles;
+}
+
+void audio_evhandler (void)
+{
+    update_audio ();
+    schedule_audio ();
+}
+
+#ifdef CPUEMU_6
+extern uae_u8 cycle_line[];
+#endif
+uae_u16 dmacon;
+
+void audio_hsync (int dmaaction)
+{
+    int nr, handle;
+    if (currprefs.produce_sound == 0)
+       return;
+
+    update_audio ();
+    handle = 0;
+    /* Sound data is fetched at the beginning of each line */
+    for (nr = 0; nr < 4; nr++) {
+        struct audio_channel_data *cdp = audio_channel + nr;
+        int chan_ena = (dmacon & DMA_MASTER) && (dmacon & (1 << nr));
+        int handle2 = 0;
+
+        if (dmaaction && cdp->request_word > 0) {
+
+           if (cdp->request_word_skip) {
+               cdp->request_word_skip = 0;
+               continue;
+           }
+
+           if (cdp->state == 5) {
+               cdp->pt = cdp->lc;
+#ifdef DEBUG_AUDIO
+               if (debugchannel (nr))
+                   write_log ("%d:>5: LEN=%d PT=%08.8X\n", nr, cdp->wlen, cdp->pt);
+#endif
+           }
+           cdp->dat2 = chipmem_wget (cdp->pt);
+           if (cdp->request_word >= 2)
+               handle2 = 1;
+           if (chan_ena) {
+#ifdef CPUEMU_6
+               cycle_line[13 + nr * 2] |= CYCLE_AUDIO;
+#endif
+               if (cdp->request_word == 1 || cdp->request_word == 2)
+                   cdp->pt += 2;
+           }
+           cdp->request_word = -1;
+
+       }
+
+       if (cdp->dmaen != chan_ena) {
+#ifdef DEBUG_AUDIO
+           if (debugchannel (nr))
+               write_log ("AUD%dDMA %d->%d (%d) LEN=%d/%d %08.8X\n", nr, cdp->dmaen, chan_ena,
+                   cdp->state, cdp->wlen, cdp->len, m68k_getpc());
+#endif
+           cdp->dmaen = chan_ena;
+           if (cdp->dmaen)
+               handle2 = 1;
+       }
+       if (handle2)
+           audio_handler (nr, 0);
+       handle |= handle2;
+    }
+    if (handle) {
+       schedule_audio ();
+       events_schedule ();
+    }
+}
+
+void AUDxDAT (int nr, uae_u16 v)
+{
+    struct audio_channel_data *cdp = audio_channel + nr;
+
+#ifdef DEBUG_AUDIO
+    if (debugchannel (nr))
+       write_log ("AUD%dDAT: %04.4X STATE=%d IRQ=%d %p\n", nr,
+           v, cdp->state, isirq(nr) ? 1 : 0, m68k_getpc());
+#endif
+    update_audio ();
+    cdp->dat2 = v;
+    cdp->request_word = -1;
+    cdp->request_word_skip = 0;
+    if (cdp->state == 0) {
+       cdp->state = 2;
+       audio_handler (nr, 0);
+        schedule_audio ();
+       events_schedule ();
+    }
+ }
+
+void AUDxLCH (int nr, uae_u16 v)
+{
+    update_audio ();
+    audio_channel[nr].lc = (audio_channel[nr].lc & 0xffff) | ((uae_u32)v << 16);
+#ifdef DEBUG_AUDIO
+    if (debugchannel (nr))
+        write_log ("AUD%dLCH: %04.4X %p\n", nr, v, m68k_getpc());
+#endif
+}
+
+void AUDxLCL (int nr, uae_u16 v)
+{
+    update_audio ();
+    audio_channel[nr].lc = (audio_channel[nr].lc & ~0xffff) | (v & 0xFFFE);
+#ifdef DEBUG_AUDIO
+    if (debugchannel (nr))
+        write_log ("AUD%dLCL: %04.4X %p\n", nr, v, m68k_getpc());
+#endif
+}
+
+void AUDxPER (int nr, uae_u16 v)
+{
+    unsigned long per = v * CYCLE_UNIT;
+    update_audio ();
+
+    if (per == 0)
+       per = PERIOD_MAX - 1;
+
+    if (per < maxhpos * CYCLE_UNIT / 2 && currprefs.produce_sound < 3)
+       per = maxhpos * CYCLE_UNIT / 2;
+
+   if (audio_channel[nr].per == PERIOD_MAX - 1 && per != PERIOD_MAX - 1) {
+       audio_channel[nr].evtime = CYCLE_UNIT;
+       if (currprefs.produce_sound > 0) {
+           schedule_audio ();
+           events_schedule ();
+       }
+    }
+
+    audio_channel[nr].per = per;
+#ifdef DEBUG_AUDIO
+    if (debugchannel (nr))
+        write_log ("AUD%dPER: %d %p\n", nr, v, m68k_getpc());
+#endif
+}
+
+void AUDxLEN (int nr, uae_u16 v)
+{
+    update_audio ();
+    audio_channel[nr].len = v;
+#ifdef DEBUG_AUDIO
+    if (debugchannel (nr))
+        write_log ("AUD%dLEN: %d %p\n", nr, v, m68k_getpc());
+#endif
+}
+
+void AUDxVOL (int nr, uae_u16 v)
+{
+    int v2 = v & 64 ? 63 : v & 63;
+    update_audio ();
+    audio_channel[nr].vol = v2;
+#ifndef MULTIPLICATION_PROFITABLE
+    audio_channel[nr].voltbl = sound_table[v2];
+#endif
+#ifdef DEBUG_AUDIO
+    if (debugchannel (nr))
+        write_log ("AUD%dVOL: %d %p\n", nr, v2, m68k_getpc());
+#endif
+}
+
+void update_adkmasks (void)
+{
+    unsigned long t = adkcon | (adkcon >> 4);
+    audio_channel[0].adk_mask = (((t >> 0) & 1) - 1);
+    audio_channel[1].adk_mask = (((t >> 1) & 1) - 1);
+    audio_channel[2].adk_mask = (((t >> 2) & 1) - 1);
+    audio_channel[3].adk_mask = (((t >> 3) & 1) - 1);
+}
+
+int init_audio (void)
+{
+    return init_sound ();
+}
+
+uae_u8 *restore_audio (int i, uae_u8 *src)
+{
+    struct audio_channel_data *acd;
+    uae_u16 p;
+
+    acd = audio_channel + i;
+    acd->state = restore_u8 ();
+    acd->vol = restore_u8 ();
+    acd->intreq2 = restore_u8 ();
+    acd->request_word = restore_u8 ();
+    acd->len = restore_u16 ();
+    acd->wlen = restore_u16 ();
+    p = restore_u16 ();
+    acd->per = p ? p * CYCLE_UNIT : PERIOD_MAX;
+    p = restore_u16 ();
+    acd->lc = restore_u32 ();
+    acd->pt = restore_u32 ();
+    acd->evtime = restore_u32 ();
+    return src;
+}
+
+
+uae_u8 *save_audio (int i, int *len, uae_u8 *dstptr)
+{
+    struct audio_channel_data *acd;
+    uae_u8 *dst, *dstbak;
+    uae_u16 p;
+
+    if (dstptr)
+       dstbak = dst = dstptr;
+    else
+       dstbak = dst = malloc (100);
+    acd = audio_channel + i;
+    save_u8 ((uae_u8)acd->state);
+    save_u8 (acd->vol);
+    save_u8 (acd->intreq2);
+    save_u8 (acd->request_word);
+    save_u16 (acd->len);
+    save_u16 (acd->wlen);
+    p = acd->per == PERIOD_MAX ? 0 : acd->per / CYCLE_UNIT;
+    save_u16 (p);
+    save_u16 (acd->dat2);
+    save_u32 (acd->lc);
+    save_u32 (acd->pt);
+    save_u32 (acd->evtime);
+    *len = dst - dstbak;
+    return dstbak;
+}
diff --git a/autoconf.c b/autoconf.c
new file mode 100755 (executable)
index 0000000..9ec9e29
--- /dev/null
@@ -0,0 +1,535 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * AutoConfig devices
+  *
+  * Copyright 1995, 1996 Bernd Schmidt
+  * Copyright 1996 Ed Hanway
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "uae.h"
+#include "memory.h"
+#include "custom.h"
+#include "events.h"
+#include "newcpu.h"
+#include "compiler.h"
+#include "autoconf.h"
+#include "osdep/exectasks.h"
+
+/* We'll need a lot of these. */
+#define MAX_TRAPS 4096
+static TrapFunction traps[MAX_TRAPS];
+static int trapmode[MAX_TRAPS];
+static const char *trapstr[MAX_TRAPS];
+static uaecptr trapoldfunc[MAX_TRAPS];
+
+static int max_trap;
+int lasttrap;
+
+/* Stack management */
+
+/* The mechanism for doing m68k calls from native code is as follows:
+ *
+ * m68k code executes, stack is main
+ * calltrap to execute_fn_on_extra_stack. new stack is allocated
+ * do_stack_magic is called for the first time
+ * current context is saved with setjmp [0]
+ *  transfer_control is done
+ *   native code executes on new stack
+ *   native code calls call_m68k
+ *   setjmp saves current context [1]
+ *  longjmp back to execute_fn_on_extra_stack [0]
+ * pointer to new stack is saved on m68k stack. m68k return address set
+ * to RTAREA_BASE + 0xFF00. m68k PC set to called function
+ * m68k function executes, stack is main
+ * m68k function returns to RTAREA_BASE + 0xFF00
+ * calltrap to m68k_mode_return
+ * do_stack_magic is called again
+ * current context is saved again with setjmp [0]
+ *  this time, transfer_control is _not_ done, instead a longjmp[1]
+ *  to the previously saved context
+ *   native code executes again on temp stack
+ *   native function returns to stack_stub
+ *  longjmp[0] back to old context
+ * back again!
+ *
+ * A bearded man enters the room, carrying a bowl of spaghetti.
+ */
+
+/* This _shouldn't_ crash with a stack size of 4096, but it does...
+ * might be a bug */
+#ifndef EXTRA_STACK_SIZE
+#define EXTRA_STACK_SIZE 32768
+#endif
+
+static void *extra_stack_list = NULL;
+
+static void *get_extra_stack (void)
+{
+    void *s = extra_stack_list;
+    //if (s)
+    //extra_stack_list = *(void **)s;
+    if (!s) {
+#ifndef _MSC_VER 
+       s = xmalloc (EXTRA_STACK_SIZE);
+#else
+       {
+           static long opencount=0;
+           extern unsigned long *win32_stackbase;
+           int i;
+           extern unsigned long *win32_freestack[42];
+           for (i=0;i<41;i++) {//0 to MAX_SELECT_THREADS
+               if(!win32_freestack[i])
+                   break; //get a free block
+           }
+           s=win32_stackbase+(i*EXTRA_STACK_SIZE);
+           win32_freestack[i]=s;   
+       }
+#endif
+    }
+    return s;
+}
+
+static void free_extra_stack (void *s)
+{
+    //*(void **)s = extra_stack_list;
+    //extra_stack_list = s;
+    {
+       int i;
+       extern unsigned long *win32_freestack[42];
+       for (i=0;i<41;i++) {//0 to MAX_SELECT_THREADS
+           if(win32_freestack[i]==s)
+               break; //get a free block
+       }
+       win32_freestack[i]=0;
+    }
+}
+
+static void stack_stub (void *s, TrapFunction f, uae_u32 *retval)
+{
+#ifdef CAN_DO_STACK_MAGIC
+    /*printf("in stack_stub: %p %p %p %x\n", s, f, retval, (int)*retval);*/
+    *retval = f ();
+    /*write_log ("returning from stack_stub\n");*/
+    longjmp (((jmp_buf *)s)[0], 1);
+#endif
+}
+
+static void *current_extra_stack = NULL;
+static uaecptr m68k_calladdr;
+
+static void do_stack_magic (TrapFunction f, void *s, int has_retval)
+{
+#ifdef CAN_DO_STACK_MAGIC
+    uaecptr a7;
+    jmp_buf *j = (jmp_buf *)s;
+    switch (setjmp (j[0])) {
+     case 0:
+       /* Returning directly */
+       current_extra_stack = s;
+       if (has_retval == -1) {
+           /*write_log ("finishing m68k mode return\n");*/
+           longjmp (j[1], 1);
+       }
+       /*write_log ("calling native function\n");*/
+       transfer_control (s, EXTRA_STACK_SIZE, stack_stub, f, has_retval);
+       /* not reached */
+       abort ();
+
+     case 1:
+       /*write_log ("native function complete\n");*/
+       /* Returning normally. */
+       if (stack_has_retval (s, EXTRA_STACK_SIZE))
+           m68k_dreg (regs, 0) = get_retval_from_stack (s, EXTRA_STACK_SIZE);
+       free_extra_stack (s);
+       break;
+
+     case 2:
+       /* Returning to do a m68k call. We're now back on the main stack. */
+       a7 = m68k_areg(regs, 7) -= (sizeof (void *) + 7) & ~3;
+       /* Save stack to restore */
+       *((void **)get_real_address (a7 + 4)) = s;
+       /* Save special return address: this address contains a
+        * calltrap that will longjmp to the right stack. */
+       put_long (m68k_areg (regs, 7), RTAREA_BASE + 0xFF00);
+       m68k_setpc (m68k_calladdr);
+       fill_prefetch_slow ();
+       /*write_log ("native function calls m68k\n");*/
+       break;
+    }
+    current_extra_stack = 0;
+#endif
+}
+
+static uae_u32 execute_fn_on_extra_stack (TrapFunction f, int has_retval)
+{
+#ifdef CAN_DO_STACK_MAGIC
+    void *s = get_extra_stack ();
+    do_stack_magic (f, s, has_retval);
+#endif
+    return 0;
+}
+
+static uae_u32 m68k_mode_return (void)
+{
+#ifdef CAN_DO_STACK_MAGIC
+    uaecptr a7 = m68k_areg(regs, 7);
+    void *s = *(void **)get_real_address(a7);
+    m68k_areg(regs, 7) += (sizeof (void *) + 3) & ~3;
+    /*write_log ("doing m68k mode return\n");*/
+    do_stack_magic (NULL, s, -1);
+#endif
+    return 0;
+}
+
+static uae_u32 call_m68k (uaecptr addr, int saveregs)
+{
+    volatile uae_u32 retval = 0;
+    volatile int do_save = saveregs;
+    if (current_extra_stack == NULL)
+       abort();
+#ifdef CAN_DO_STACK_MAGIC
+    {
+       volatile struct regstruct saved_regs;
+       jmp_buf *j = (jmp_buf *)current_extra_stack;
+
+       if (do_save)
+           saved_regs = regs;
+       m68k_calladdr = addr;
+       switch (setjmp(j[1])) {
+        case 0:
+           /*write_log ("doing call\n");*/
+           /* Returning directly: now switch to main stack and do the call */
+           longjmp (j[0], 2);
+        case 1:
+           /*write_log ("returning from call\n");*/
+           retval = m68k_dreg (regs, 0);
+           if (do_save)
+               regs = saved_regs;
+           /* Returning after the call. */
+           break;
+       }
+    }
+#endif
+    return retval;
+}
+
+uae_u32 CallLib (uaecptr base, uae_s16 offset)
+{
+    int i;
+    uaecptr olda6 = m68k_areg(regs, 6);
+    uae_u32 retval;
+#if 0
+    for (i = 0; i < n_libpatches; i++) {
+       if (libpatches[i].libbase == base && libpatches[i].functions[-offset/6] != NULL)
+           return (*libpatches[i].functions[-offset/6])();
+    }
+#endif
+    m68k_areg(regs, 6) = base;
+    retval = call_m68k(base + offset, 1);
+    m68k_areg(regs, 6) = olda6;
+    return retval;
+}
+
+/* Commonly used autoconfig strings */
+
+uaecptr EXPANSION_explibname, EXPANSION_doslibname, EXPANSION_uaeversion;
+uaecptr EXPANSION_uaedevname, EXPANSION_explibbase = 0, EXPANSION_haveV36;
+uaecptr EXPANSION_bootcode, EXPANSION_nullfunc;
+uaecptr EXPANSION_cddevice;
+
+/* ROM tag area memory access */
+
+uae_u8 *rtarea;
+
+static uae_u32 rtarea_lget (uaecptr) REGPARAM;
+static uae_u32 rtarea_wget (uaecptr) REGPARAM;
+static uae_u32 rtarea_bget (uaecptr) REGPARAM;
+static void rtarea_lput (uaecptr, uae_u32) REGPARAM;
+static void rtarea_wput (uaecptr, uae_u32) REGPARAM;
+static void rtarea_bput (uaecptr, uae_u32) REGPARAM;
+static uae_u8 *rtarea_xlate (uaecptr) REGPARAM;
+
+addrbank rtarea_bank = {
+    rtarea_lget, rtarea_wget, rtarea_bget,
+    rtarea_lput, rtarea_wput, rtarea_bput,
+    rtarea_xlate, default_check, NULL
+};
+
+uae_u8 REGPARAM2 *rtarea_xlate (uaecptr addr)
+{
+    addr &= 0xFFFF;
+    return rtarea + addr;
+}
+
+uae_u32 REGPARAM2 rtarea_lget (uaecptr addr)
+{
+    special_mem |= S_READ;
+    addr &= 0xFFFF;
+    return (uae_u32)(rtarea_wget (addr) << 16) + rtarea_wget (addr+2);
+}
+
+uae_u32 REGPARAM2 rtarea_wget (uaecptr addr)
+{
+    special_mem |= S_READ;
+    addr &= 0xFFFF;
+    return (rtarea[addr]<<8) + rtarea[addr+1];
+}
+
+uae_u32 REGPARAM2 rtarea_bget (uaecptr addr)
+{
+    special_mem |= S_READ;
+    addr &= 0xFFFF;
+    return rtarea[addr];
+}
+
+void REGPARAM2 rtarea_lput (uaecptr addr, uae_u32 value)
+{
+    special_mem |= S_WRITE;
+}
+
+void REGPARAM2 rtarea_wput (uaecptr addr, uae_u32 value)
+{
+    special_mem |= S_WRITE;
+}
+
+void REGPARAM2 rtarea_bput (uaecptr addr, uae_u32 value)
+{
+    special_mem |= S_WRITE;
+}
+
+static const int trace_traps = 1;
+
+void REGPARAM2 call_calltrap(int func)
+{
+    uae_u32 retval = 0;
+    int has_retval = (trapmode[func] & TRAPFLAG_NO_RETVAL) == 0;
+    int implicit_rts = (trapmode[func] & TRAPFLAG_DORET) != 0;
+
+    if (trapstr[func] && *trapstr[func] != 0 && trace_traps)
+       write_log ("TRAP: %s\n", trapstr[func]);
+
+    /* For monitoring only? */
+    if (traps[func] == NULL) {
+       m68k_setpc(trapoldfunc[func]);
+       fill_prefetch_slow ();
+       return;
+    }
+
+    if (func < max_trap) {
+       if (trapmode[func] & TRAPFLAG_EXTRA_STACK) {
+           execute_fn_on_extra_stack(traps[func], has_retval);
+           return;
+       }
+       retval = (*traps[func])();
+    } else
+       write_log ("illegal emulator trap\n");
+
+    if (has_retval)
+       m68k_dreg(regs, 0) = retval;
+    if (implicit_rts) {
+       m68k_do_rts ();
+       fill_prefetch_slow ();
+    }
+}
+
+/* @$%&§ compiler bugs */
+static volatile int four = 4;
+
+uaecptr libemu_InstallFunctionFlags (TrapFunction f, uaecptr libbase, int offset,
+                                    int flags, const char *tracename)
+{
+    int i;
+    uaecptr retval;
+    uaecptr execbase = get_long (four);
+    int trnum;
+    uaecptr addr = here();
+    calltrap (trnum = deftrap2 (f, flags, tracename));
+    dw (RTS);
+
+    m68k_areg(regs, 1) = libbase;
+    m68k_areg(regs, 0) = offset;
+    m68k_dreg(regs, 0) = addr;
+    retval = CallLib (execbase, -420);
+
+    trapoldfunc[trnum] = retval;
+#if 0
+    for (i = 0; i < n_libpatches; i++) {
+       if (libpatches[i].libbase == libbase)
+           break;
+    }
+    if (i == n_libpatches) {
+       int j;
+       libpatches[i].libbase = libbase;
+       for (j = 0; j < 300; j++)
+           libpatches[i].functions[j] = NULL;
+       n_libpatches++;
+    }
+    libpatches[i].functions[-offset/6] = f;
+#endif
+    return retval;
+}
+
+/* some quick & dirty code to fill in the rt area and save me a lot of
+ * scratch paper
+ */
+
+static int rt_addr;
+static int rt_straddr;
+
+uae_u32 addr (int ptr)
+{
+    return (uae_u32)ptr + RTAREA_BASE;
+}
+
+void db (uae_u8 data)
+{
+    rtarea[rt_addr++] = data;
+}
+
+void dw (uae_u16 data)
+{
+    rtarea[rt_addr++] = (uae_u8)(data >> 8);
+    rtarea[rt_addr++] = (uae_u8)data;
+}
+
+void dl (uae_u32 data)
+{
+    rtarea[rt_addr++] = data >> 24;
+    rtarea[rt_addr++] = data >> 16;
+    rtarea[rt_addr++] = data >> 8;
+    rtarea[rt_addr++] = data;
+}
+
+/* store strings starting at the end of the rt area and working
+ * backward.  store pointer at current address
+ */
+
+uae_u32 ds (char *str)
+{
+    int len = strlen (str) + 1;
+
+    rt_straddr -= len;
+    strcpy ((char *)rtarea + rt_straddr, str);
+
+    return addr (rt_straddr);
+}
+
+void calltrap (uae_u32 n)
+{
+    dw (0xA000 + n);
+}
+
+void org (uae_u32 a)
+{
+    rt_addr = a - RTAREA_BASE;
+}
+
+uae_u32 here (void)
+{
+    return addr (rt_addr);
+}
+
+int deftrap2 (TrapFunction func, int mode, const char *str)
+{
+    int num = max_trap++;
+    traps[num] = func;
+    trapstr[num] = str;
+    trapmode[num] = mode;
+    return num;
+}
+
+int deftrap (TrapFunction func)
+{
+    return deftrap2 (func, 0, "");
+}
+
+void align (int b)
+{
+    rt_addr = (rt_addr + b - 1) & ~(b - 1);
+}
+
+static uae_u32 nullfunc(void)
+{
+    write_log ("Null function called\n");
+    return 0;
+}
+
+static uae_u32 getchipmemsize (void)
+{
+    return allocated_chipmem;
+}
+
+static uae_u32 uae_puts (void)
+{
+    puts (get_real_address (m68k_areg (regs, 0)));
+    return 0;
+}
+
+static void rtarea_init_mem (void)
+{
+    rtarea = mapped_malloc (0x10000, "rtarea");
+    if (!rtarea) {
+       write_log ("virtual memory exhausted (rtarea)!\n");
+       abort ();
+    }
+    rtarea_bank.baseaddr = rtarea;
+}
+
+void rtarea_init (void)
+{
+    uae_u32 a;
+    char uaever[100];
+
+    rt_straddr = 0xFF00 - 2;
+    rt_addr = 0;
+    max_trap = 0;
+
+    rtarea_init_mem ();
+
+    sprintf (uaever, "uae-%d.%d.%d", UAEMAJOR, UAEMINOR, UAESUBREV);
+
+    EXPANSION_uaeversion = ds (uaever);
+    EXPANSION_explibname = ds ("expansion.library");
+    EXPANSION_doslibname = ds ("dos.library");
+    EXPANSION_uaedevname = ds ("uae.device");
+
+    deftrap (NULL); /* Generic emulator trap */
+    lasttrap = 0;
+
+    EXPANSION_nullfunc = here ();
+    calltrap (deftrap (nullfunc));
+    dw (RTS);
+
+    a = here();
+    /* Standard "return from 68k mode" trap */
+    org (RTAREA_BASE + 0xFF00);
+    calltrap (deftrap2 (m68k_mode_return, TRAPFLAG_NO_RETVAL, ""));
+
+    org (RTAREA_BASE + 0xFF80);
+    calltrap (deftrap2 (getchipmemsize, TRAPFLAG_DORET, ""));
+
+    org (RTAREA_BASE + 0xFF10);
+    calltrap (deftrap2 (uae_puts, TRAPFLAG_NO_RETVAL, ""));
+    dw (RTS);
+
+    org (a);
+
+    filesys_install_code ();
+}
+
+volatile int uae_int_requested = 0;
+
+void set_uae_int_flag (void)
+{
+    rtarea[0xFFFB] = uae_int_requested;
+}
+
+void rtarea_setup(void)
+{
+}
diff --git a/blitops.c b/blitops.c
new file mode 100755 (executable)
index 0000000..eb2142d
--- /dev/null
+++ b/blitops.c
@@ -0,0 +1,262 @@
+ /* This file generated automatically - do not edit */
+
+#include "genblitter.h"
+
+struct blitop blitops[256] = {
+ /* 00 */  { "0", 0 },
+ /* 01 */  { "~(srca | srcb | srcc)", 7 },
+ /* 02 */  { "(srcc & ~(srca | srcb))", 7 },
+ /* 03 */  { "~(srca | srcb)", 3 },
+ /* 04 */  { "(srcb & ~(srca | srcc))", 7 },
+ /* 05 */  { "~(srca | srcc)", 5 },
+ /* 06 */  { "(~srca & (srcb ^ srcc))", 7 },
+ /* 07 */  { "~(srca | (srcb & srcc))", 7 },
+ /* 08 */  { "(~srca & srcb & srcc)", 7 },
+ /* 09 */  { "~(srca | (srcb ^ srcc))", 7 },
+ /* 0a */  { "(~srca & srcc)", 5 },
+ /* 0b */  { "~(srca | (srcb & ~srcc))", 7 },
+ /* 0c */  { "(~srca & srcb)", 3 },
+ /* 0d */  { "~(srca | (~srcb & srcc))", 7 },
+ /* 0e */  { "(~srca & (srcb | srcc))", 7 },
+ /* 0f */  { "~srca", 1 },
+ /* 10 */  { "(srca & ~(srcb | srcc))", 7 },
+ /* 11 */  { "~(srcb | srcc)", 6 },
+ /* 12 */  { "(~srcb & (srca ^ srcc))", 7 },
+ /* 13 */  { "~(srcb | (srca & srcc))", 7 },
+ /* 14 */  { "(~srcc & (srca ^ srcb))", 7 },
+ /* 15 */  { "~(srcc | (srca & srcb))", 7 },
+ /* 16 */  { "(srca ^ ((srca & srcb) | (srcb ^ srcc)))", 7 },
+ /* 17 */  { "~(srca ^ ((srca ^ srcb) & (srca ^ srcc)))", 7 },
+ /* 18 */  { "((srca ^ srcb) & (srca ^ srcc))", 7 },
+ /* 19 */  { "(srcb ^ (~srcc | (srca & srcb)))", 7 },
+ /* 1a */  { "(srca ^ (srcc | (srca & srcb)))", 7 },
+ /* 1b */  { "(srca ^ (srcc | ~(srca ^ srcb)))", 7 },
+ /* 1c */  { "(srca ^ (srcb | (srca & srcc)))", 7 },
+ /* 1d */  { "(srca ^ (srcb | ~(srca ^ srcc)))", 7 },
+ /* 1e */  { "(srca ^ (srcb | srcc))", 7 },
+ /* 1f */  { "~(srca & (srcb | srcc))", 7 },
+ /* 20 */  { "(srca & ~srcb & srcc)", 7 },
+ /* 21 */  { "~(srcb | (srca ^ srcc))", 7 },
+ /* 22 */  { "(~srcb & srcc)", 6 },
+ /* 23 */  { "~(srcb | (srca & ~srcc))", 7 },
+ /* 24 */  { "((srca ^ srcb) & (srcb ^ srcc))", 7 },
+ /* 25 */  { "(srca ^ (~srcc | (srca & srcb)))", 7 },
+ /* 26 */  { "(srcb ^ (srcc | (srca & srcb)))", 7 },
+ /* 27 */  { "~(srca ^ (srcc & (srca ^ srcb)))", 7 },
+ /* 28 */  { "(srcc & (srca ^ srcb))", 7 },
+ /* 29 */  { "~(srca ^ srcb ^ (srcc | (srca & srcb)))", 7 },
+ /* 2a */  { "(srcc & ~(srca & srcb))", 7 },
+ /* 2b */  { "~(srca ^ ((srca ^ srcb) & (srcb ^ srcc)))", 7 },
+ /* 2c */  { "(srcb ^ (srca & (srcb | srcc)))", 7 },
+ /* 2d */  { "(srca ^ (srcb | ~srcc))", 7 },
+ /* 2e */  { "(srca ^ (srcb | (srca ^ srcc)))", 7 },
+ /* 2f */  { "~(srca & (srcb | ~srcc))", 7 },
+ /* 30 */  { "(srca & ~srcb)", 3 },
+ /* 31 */  { "~(srcb | (~srca & srcc))", 7 },
+ /* 32 */  { "(~srcb & (srca | srcc))", 7 },
+ /* 33 */  { "~srcb", 2 },
+ /* 34 */  { "(srcb ^ (srca | (srcb & srcc)))", 7 },
+ /* 35 */  { "(srcb ^ (srca | ~(srcb ^ srcc)))", 7 },
+ /* 36 */  { "(srcb ^ (srca | srcc))", 7 },
+ /* 37 */  { "~(srcb & (srca | srcc))", 7 },
+ /* 38 */  { "(srca ^ (srcb & (srca | srcc)))", 7 },
+ /* 39 */  { "(srcb ^ (srca | ~srcc))", 7 },
+ /* 3a */  { "(srcb ^ (srca | (srcb ^ srcc)))", 7 },
+ /* 3b */  { "~(srcb & (srca | ~srcc))", 7 },
+ /* 3c */  { "(srca ^ srcb)", 3 },
+ /* 3d */  { "(srca ^ (srcb | ~(srca | srcc)))", 7 },
+ /* 3e */  { "(srca ^ (srcb | (srca ^ (srca | srcc))))", 7 },
+ /* 3f */  { "~(srca & srcb)", 3 },
+ /* 40 */  { "(srca & srcb & ~srcc)", 7 },
+ /* 41 */  { "~(srcc | (srca ^ srcb))", 7 },
+ /* 42 */  { "((srca ^ srcc) & (srcb ^ srcc))", 7 },
+ /* 43 */  { "(srca ^ (~srcb | (srca & srcc)))", 7 },
+ /* 44 */  { "(srcb & ~srcc)", 6 },
+ /* 45 */  { "~(srcc | (srca & ~srcb))", 7 },
+ /* 46 */  { "(srcc ^ (srcb | (srca & srcc)))", 7 },
+ /* 47 */  { "~(srca ^ (srcb & (srca ^ srcc)))", 7 },
+ /* 48 */  { "(srcb & (srca ^ srcc))", 7 },
+ /* 49 */  { "~(srca ^ srcc ^ (srcb | (srca & srcc)))", 7 },
+ /* 4a */  { "(srcc ^ (srca & (srcb | srcc)))", 7 },
+ /* 4b */  { "(srca ^ (~srcb | srcc))", 7 },
+ /* 4c */  { "(srcb & ~(srca & srcc))", 7 },
+ /* 4d */  { "(srca ^ ((srca ^ srcb) | ~(srca ^ srcc)))", 7 },
+ /* 4e */  { "(srca ^ (srcc | (srca ^ srcb)))", 7 },
+ /* 4f */  { "~(srca & (~srcb | srcc))", 7 },
+ /* 50 */  { "(srca & ~srcc)", 5 },
+ /* 51 */  { "~(srcc | (~srca & srcb))", 7 },
+ /* 52 */  { "(srcc ^ (srca | (srcb & srcc)))", 7 },
+ /* 53 */  { "~(srcb ^ (srca & (srcb ^ srcc)))", 7 },
+ /* 54 */  { "(~srcc & (srca | srcb))", 7 },
+ /* 55 */  { "~srcc", 4 },
+ /* 56 */  { "(srcc ^ (srca | srcb))", 7 },
+ /* 57 */  { "~(srcc & (srca | srcb))", 7 },
+ /* 58 */  { "(srca ^ (srcc & (srca | srcb)))", 7 },
+ /* 59 */  { "(srcc ^ (srca | ~srcb))", 7 },
+ /* 5a */  { "(srca ^ srcc)", 5 },
+ /* 5b */  { "(srca ^ (srcc | ~(srca | srcb)))", 7 },
+ /* 5c */  { "(srcc ^ (srca | (srcb ^ srcc)))", 7 },
+ /* 5d */  { "~(srcc & (srca | ~srcb))", 7 },
+ /* 5e */  { "(srca ^ (srcc | (srca ^ (srca | srcb))))", 7 },
+ /* 5f */  { "~(srca & srcc)", 5 },
+ /* 60 */  { "(srca & (srcb ^ srcc))", 7 },
+ /* 61 */  { "~(srcb ^ srcc ^ (srca | (srcb & srcc)))", 7 },
+ /* 62 */  { "(srcc ^ (srcb & (srca | srcc)))", 7 },
+ /* 63 */  { "(srcb ^ (~srca | srcc))", 7 },
+ /* 64 */  { "(srcb ^ (srcc & (srca | srcb)))", 7 },
+ /* 65 */  { "(srcc ^ (~srca | srcb))", 7 },
+ /* 66 */  { "(srcb ^ srcc)", 6 },
+ /* 67 */  { "(srcb ^ (srcc | ~(srca | srcb)))", 7 },
+ /* 68 */  { "((srca & srcb) ^ (srcc & (srca | srcb)))", 7 },
+ /* 69 */  { "~(srca ^ srcb ^ srcc)", 7 },
+ /* 6a */  { "(srcc ^ (srca & srcb))", 7 },
+ /* 6b */  { "~(srca ^ srcb ^ (srcc & (srca | srcb)))", 7 },
+ /* 6c */  { "(srcb ^ (srca & srcc))", 7 },
+ /* 6d */  { "~(srca ^ srcc ^ (srcb & (srca | srcc)))", 7 },
+ /* 6e */  { "((~srca & srcb) | (srcb ^ srcc))", 7 },
+ /* 6f */  { "(~srca | (srcb ^ srcc))", 7 },
+ /* 70 */  { "(srca & ~(srcb & srcc))", 7 },
+ /* 71 */  { "~(srca ^ ((srca ^ srcb) | (srca ^ srcc)))", 7 },
+ /* 72 */  { "(srcb ^ (srcc | (srca ^ srcb)))", 7 },
+ /* 73 */  { "~(srcb & (~srca | srcc))", 7 },
+ /* 74 */  { "(srcc ^ (srcb | (srca ^ srcc)))", 7 },
+ /* 75 */  { "~(srcc & (~srca | srcb))", 7 },
+ /* 76 */  { "(srcb ^ (srcc | (srca ^ (srca & srcb))))", 7 },
+ /* 77 */  { "~(srcb & srcc)", 6 },
+ /* 78 */  { "(srca ^ (srcb & srcc))", 7 },
+ /* 79 */  { "~(srcb ^ srcc ^ (srca & (srcb | srcc)))", 7 },
+ /* 7a */  { "((srca & ~srcb) | (srca ^ srcc))", 7 },
+ /* 7b */  { "(~srcb | (srca ^ srcc))", 7 },
+ /* 7c */  { "((srca ^ srcb) | (srca & ~srcc))", 7 },
+ /* 7d */  { "(~srcc | (srca ^ srcb))", 7 },
+ /* 7e */  { "((srca ^ srcb) | (srca ^ srcc))", 7 },
+ /* 7f */  { "~(srca & srcb & srcc)", 7 },
+ /* 80 */  { "(srca & srcb & srcc)", 7 },
+ /* 81 */  { "~((srca ^ srcb) | (srca ^ srcc))", 7 },
+ /* 82 */  { "(srcc & ~(srca ^ srcb))", 7 },
+ /* 83 */  { "(srca ^ (~srcb | (srca & ~srcc)))", 7 },
+ /* 84 */  { "(srcb & ~(srca ^ srcc))", 7 },
+ /* 85 */  { "(srca ^ (~srcc | (srca & ~srcb)))", 7 },
+ /* 86 */  { "(srcb ^ srcc ^ (srca & (srcb | srcc)))", 7 },
+ /* 87 */  { "~(srca ^ (srcb & srcc))", 7 },
+ /* 88 */  { "(srcb & srcc)", 6 },
+ /* 89 */  { "(srcb ^ (~srcc & (~srca | srcb)))", 7 },
+ /* 8a */  { "(srcc & (~srca | srcb))", 7 },
+ /* 8b */  { "(srca ^ (~srcb | (srca ^ srcc)))", 7 },
+ /* 8c */  { "(srcb & (~srca | srcc))", 7 },
+ /* 8d */  { "(srca ^ (~srcc | (srca ^ srcb)))", 7 },
+ /* 8e */  { "(srca ^ ((srca ^ srcb) | (srca ^ srcc)))", 7 },
+ /* 8f */  { "(~srca | (srcb & srcc))", 7 },
+ /* 90 */  { "(srca & ~(srcb ^ srcc))", 7 },
+ /* 91 */  { "(srcb ^ (~srcc | (~srca & srcb)))", 7 },
+ /* 92 */  { "(srca ^ srcc ^ (srcb & (srca | srcc)))", 7 },
+ /* 93 */  { "~(srcb ^ (srca & srcc))", 7 },
+ /* 94 */  { "(srca ^ srcb ^ (srcc & (srca | srcb)))", 7 },
+ /* 95 */  { "~(srcc ^ (srca & srcb))", 7 },
+ /* 96 */  { "(srca ^ srcb ^ srcc)", 7 },
+ /* 97 */  { "(srca ^ srcb ^ (srcc | ~(srca | srcb)))", 7 },
+ /* 98 */  { "(srcb ^ (~srcc & (srca | srcb)))", 7 },
+ /* 99 */  { "~(srcb ^ srcc)", 6 },
+ /* 9a */  { "(srcc ^ (srca & ~srcb))", 7 },
+ /* 9b */  { "~(srcb ^ (srcc & (srca | srcb)))", 7 },
+ /* 9c */  { "(srcb ^ (srca & ~srcc))", 7 },
+ /* 9d */  { "~(srcc ^ (srcb & (srca | srcc)))", 7 },
+ /* 9e */  { "(srcb ^ srcc ^ (srca | (srcb & srcc)))", 7 },
+ /* 9f */  { "~(srca & (srcb ^ srcc))", 7 },
+ /* a0 */  { "(srca & srcc)", 5 },
+ /* a1 */  { "(srca ^ (~srcc & (srca | ~srcb)))", 7 },
+ /* a2 */  { "(srcc & (srca | ~srcb))", 7 },
+ /* a3 */  { "(srcb ^ (~srca | (srcb ^ srcc)))", 7 },
+ /* a4 */  { "(srca ^ (~srcc & (srca | srcb)))", 7 },
+ /* a5 */  { "~(srca ^ srcc)", 5 },
+ /* a6 */  { "(srcc ^ (~srca & srcb))", 7 },
+ /* a7 */  { "~(srca ^ (srcc & (srca | srcb)))", 7 },
+ /* a8 */  { "(srcc & (srca | srcb))", 7 },
+ /* a9 */  { "~(srcc ^ (srca | srcb))", 7 },
+ /* aa */  { "srcc", 4 },
+ /* ab */  { "(srcc | ~(srca | srcb))", 7 },
+ /* ac */  { "(srcb ^ (srca & (srcb ^ srcc)))", 7 },
+ /* ad */  { "~(srcc ^ (srca | (srcb & srcc)))", 7 },
+ /* ae */  { "(srcc | (~srca & srcb))", 7 },
+ /* af */  { "(~srca | srcc)", 5 },
+ /* b0 */  { "(srca & (~srcb | srcc))", 7 },
+ /* b1 */  { "~(srca ^ (srcc | (srca ^ srcb)))", 7 },
+ /* b2 */  { "(srca ^ ((srca ^ srcc) & (srcb ^ srcc)))", 7 },
+ /* b3 */  { "(~srcb | (srca & srcc))", 7 },
+ /* b4 */  { "(srca ^ (srcb & ~srcc))", 7 },
+ /* b5 */  { "~(srcc ^ (srca & (srcb | srcc)))", 7 },
+ /* b6 */  { "(srca ^ srcc ^ (srcb | (srca & srcc)))", 7 },
+ /* b7 */  { "~(srcb & (srca ^ srcc))", 7 },
+ /* b8 */  { "(srca ^ (srcb & (srca ^ srcc)))", 7 },
+ /* b9 */  { "~(srcc ^ (srcb | (srca & srcc)))", 7 },
+ /* ba */  { "(srcc | (srca & ~srcb))", 7 },
+ /* bb */  { "(~srcb | srcc)", 6 },
+ /* bc */  { "((srca ^ srcb) | (srca & srcc))", 7 },
+ /* bd */  { "((srca ^ srcb) | ~(srca ^ srcc))", 7 },
+ /* be */  { "(srcc | (srca ^ srcb))", 7 },
+ /* bf */  { "(srcc | ~(srca & srcb))", 7 },
+ /* c0 */  { "(srca & srcb)", 3 },
+ /* c1 */  { "(srca ^ (~srcb & (srca | ~srcc)))", 7 },
+ /* c2 */  { "(srca ^ (~srcb & (srca | srcc)))", 7 },
+ /* c3 */  { "~(srca ^ srcb)", 3 },
+ /* c4 */  { "(srcb & (srca | ~srcc))", 7 },
+ /* c5 */  { "~(srcb ^ (srca | (srcb ^ srcc)))", 7 },
+ /* c6 */  { "(srcb ^ (~srca & srcc))", 7 },
+ /* c7 */  { "~(srca ^ (srcb & (srca | srcc)))", 7 },
+ /* c8 */  { "(srcb & (srca | srcc))", 7 },
+ /* c9 */  { "~(srcb ^ (srca | srcc))", 7 },
+ /* ca */  { "(srcc ^ (srca & (srcb ^ srcc)))", 7 },
+ /* cb */  { "~(srcb ^ (srca | (srcb & srcc)))", 7 },
+ /* cc */  { "srcb", 2 },
+ /* cd */  { "(srcb | ~(srca | srcc))", 7 },
+ /* ce */  { "(srcb | (~srca & srcc))", 7 },
+ /* cf */  { "(~srca | srcb)", 3 },
+ /* d0 */  { "(srca & (srcb | ~srcc))", 7 },
+ /* d1 */  { "~(srca ^ (srcb | (srca ^ srcc)))", 7 },
+ /* d2 */  { "(srca ^ (~srcb & srcc))", 7 },
+ /* d3 */  { "~(srcb ^ (srca & (srcb | srcc)))", 7 },
+ /* d4 */  { "(srca ^ ((srca ^ srcb) & (srcb ^ srcc)))", 7 },
+ /* d5 */  { "(~srcc | (srca & srcb))", 7 },
+ /* d6 */  { "(srca ^ srcb ^ (srcc | (srca & srcb)))", 7 },
+ /* d7 */  { "~(srcc & (srca ^ srcb))", 7 },
+ /* d8 */  { "(srca ^ (srcc & (srca ^ srcb)))", 7 },
+ /* d9 */  { "~(srcb ^ (srcc | (srca & srcb)))", 7 },
+ /* da */  { "((srca & srcb) | (srca ^ srcc))", 7 },
+ /* db */  { "~((srca ^ srcb) & (srcb ^ srcc))", 7 },
+ /* dc */  { "(srcb | (srca & ~srcc))", 7 },
+ /* dd */  { "(srcb | ~srcc)", 6 },
+ /* de */  { "(srcb | (srca ^ srcc))", 7 },
+ /* df */  { "(srcb | ~(srca & srcc))", 7 },
+ /* e0 */  { "(srca & (srcb | srcc))", 7 },
+ /* e1 */  { "~(srca ^ (srcb | srcc))", 7 },
+ /* e2 */  { "(srcc ^ (srcb & (srca ^ srcc)))", 7 },
+ /* e3 */  { "~(srca ^ (srcb | (srca & srcc)))", 7 },
+ /* e4 */  { "(srcb ^ (srcc & (srca ^ srcb)))", 7 },
+ /* e5 */  { "~(srca ^ (srcc | (srca & srcb)))", 7 },
+ /* e6 */  { "((srca & srcb) | (srcb ^ srcc))", 7 },
+ /* e7 */  { "~((srca ^ srcb) & (srca ^ srcc))", 7 },
+ /* e8 */  { "(srca ^ ((srca ^ srcb) & (srca ^ srcc)))", 7 },
+ /* e9 */  { "(srca ^ srcb ^ (~srcc | (srca & srcb)))", 7 },
+ /* ea */  { "(srcc | (srca & srcb))", 7 },
+ /* eb */  { "(srcc | ~(srca ^ srcb))", 7 },
+ /* ec */  { "(srcb | (srca & srcc))", 7 },
+ /* ed */  { "(srcb | ~(srca ^ srcc))", 7 },
+ /* ee */  { "(srcb | srcc)", 6 },
+ /* ef */  { "(~srca | srcb | srcc)", 7 },
+ /* f0 */  { "srca", 1 },
+ /* f1 */  { "(srca | ~(srcb | srcc))", 7 },
+ /* f2 */  { "(srca | (~srcb & srcc))", 7 },
+ /* f3 */  { "(srca | ~srcb)", 3 },
+ /* f4 */  { "(srca | (srcb & ~srcc))", 7 },
+ /* f5 */  { "(srca | ~srcc)", 5 },
+ /* f6 */  { "(srca | (srcb ^ srcc))", 7 },
+ /* f7 */  { "(srca | ~(srcb & srcc))", 7 },
+ /* f8 */  { "(srca | (srcb & srcc))", 7 },
+ /* f9 */  { "(srca | ~(srcb ^ srcc))", 7 },
+ /* fa */  { "(srca | srcc)", 5 },
+ /* fb */  { "(srca | ~srcb | srcc)", 7 },
+ /* fc */  { "(srca | srcb)", 3 },
+ /* fd */  { "(srca | srcb | ~srcc)", 7 },
+ /* fe */  { "(srca | srcb | srcc)", 7 },
+ /* ff */  { "0xFFFFFFFF", 0 }
+};
diff --git a/blitter.c b/blitter.c
new file mode 100755 (executable)
index 0000000..7bd8b95
--- /dev/null
+++ b/blitter.c
@@ -0,0 +1,1062 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Custom chip emulation
+  *
+  * (c) 1995 Bernd Schmidt, Alessandro Bissacco
+  * (c) 2002 - 2003 Toni Wilen
+  */
+
+//#define BLITTER_DEBUG
+//#define BLITTER_SLOWDOWNDEBUG 4
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "uae.h"
+#include "memory.h"
+#include "custom.h"
+#include "events.h"
+#include "newcpu.h"
+#include "blitter.h"
+#include "blit.h"
+#include "savestate.h"
+
+uae_u16 oldvblts;
+uae_u16 bltcon0,bltcon1;
+uae_u32 bltapt,bltbpt,bltcpt,bltdpt;
+
+int blinea_shift;
+static uae_u16 blinea, blineb;
+static uaecptr bltcnxlpt,bltdnxlpt;
+static int blitline, blitfc, blitfill, blitife, blitsing, blitdesc;
+static int blitonedot,blitsign;
+static int blit_add;
+static int blit_modadda, blit_modaddb, blit_modaddc, blit_modaddd;
+static int blit_ch, blit_starting;
+static unsigned int blit_starts;
+int blit_singlechannel;
+
+#ifdef BLITTER_DEBUG
+static int blitter_dontdo;
+#endif
+#ifdef BLITTER_SLOWDOWNDEBUG
+static int blitter_slowdowndebug;
+#endif
+
+struct bltinfo blt_info;
+
+static uae_u8 blit_filltable[256][4][2];
+uae_u32 blit_masktable[BLITTER_MAX_WORDS];
+static uae_u16 blit_trashtable[BLITTER_MAX_WORDS];
+enum blitter_states bltstate;
+
+static int blit_cyclecounter, blit_maxcyclecounter, blit_slowdown, blit_cycles_total;
+static int blit_linecyclecounter, blit_misscyclecounter;
+
+#ifdef CPUEMU_6
+extern uae_u8 cycle_line[];
+#endif
+
+static long blit_firstline_cycles;
+static long blit_first_cycle;
+static int blit_last_cycle, blit_dmacount, blit_dmacount2;
+static int blit_linecycles, blit_extracycles;
+static uae_u8 *blit_diag;
+
+static uae_u16 ddat1, ddat2;
+static int ddat1use, ddat2use;
+
+static uae_u8 blit_cycle_diagram_finald[] =
+    { 0, 2, 0,4 };
+
+static uae_u8 blit_cycle_diagram[][10] =
+{
+    { 0, 2, 0,0 },             /* 0 */
+    { 0, 2, 4,0 },             /* 1 */
+    { 0, 2, 3,0 },             /* 2 */
+    { 2, 3, 0,3,4, 3,0 },      /* 3 */
+    { 0, 3, 2,0,0 },           /* 4 */
+    { 2, 3, 0,2,4, 2,0 },      /* 5 */
+    { 0, 3, 2,3,0 },           /* 6 */
+    { 3, 4, 0,2,3,4, 2,3,0 },  /* 7 */
+    { 0, 2, 1,0 },             /* 8 */
+    { 2, 2, 1,4, 1,0 },                /* 9 */
+    { 0, 2, 1,3 },             /* A */
+    { 3, 3, 1,3,4, 1,3,0 },    /* B */
+    { 2, 3, 0,1,2, 1,2 },      /* C */
+    { 3, 3, 1,2,4, 1,2,0 },    /* D */
+    { 0, 3, 1,2,3 },           /* E */
+    { 4, 4, 1,2,3,4, 1,2,3,0 } /* F */
+};
+
+/* fill mode always adds C-channel to cycle-diagram */
+/* Reflect - Sound Vision freezes without this */
+static uae_u8 blit_cycle_diagram_fill[][10] =
+{
+    { 0, 2, 0,0 },             /* 0 */
+    { 0, 3, 0,3,4 },           /* 1 */
+    { 0, 2, 3,0 },             /* 2 */
+    { 2, 3, 0,3,4, 3,0 },      /* 3 */
+    { 0, 3, 2,0,0 },           /* 4 */
+    { 3, 4, 0,2,0,4, 2,0,0 },  /* 5 */
+    { 0, 3, 2,3,0 },           /* 6 */
+    { 3, 4, 0,2,3,4, 2,3,0 },  /* 7 */
+    { 0, 2, 1,0 },             /* 8 */
+    { 3, 3, 1,0,4, 1,0,0},     /* 9 */
+    { 0, 2, 1,3 },             /* A */
+    { 3, 3, 1,3,4, 1,3,0 },    /* B */
+    { 2, 3, 0,1,2, 1,2 },      /* C */
+    { 4, 4, 1,2,0,4, 1,2,0,0 },        /* D */
+    { 0, 3, 1,2,3 },           /* E */
+    { 4, 4, 1,2,3,4, 1,2,3,0 } /* F */
+};
+
+static uae_u8 blit_cycle_diagram_line[] =
+{
+    0, 4, 0,0,0,4 /* total guess.. */
+};
+
+void build_blitfilltable(void)
+{
+    unsigned int d, fillmask;
+    int i;
+
+    for (i = 0; i < BLITTER_MAX_WORDS; i++)
+       blit_masktable[i] = 0xFFFF;
+
+    for (d = 0; d < 256; d++) {
+       for (i = 0; i < 4; i++) {
+           int fc = i & 1;
+           uae_u8 data = d;
+           for (fillmask = 1; fillmask != 0x100; fillmask <<= 1) {
+               uae_u16 tmp = data;
+               if (fc) {
+                   if (i & 2)
+                       data |= fillmask;
+                   else
+                       data ^= fillmask;
+               }
+               if (tmp & fillmask) fc = !fc;
+           }
+           blit_filltable[d][i][0] = data;
+           blit_filltable[d][i][1] = fc;
+       }
+    }
+}
+
+static void blitter_dump (void)
+{
+    write_log ("APT=%08.8X BPT=%08.8X CPT=%08.8X DPT=%08.8X\n", bltapt, bltbpt, bltcpt, bltdpt);
+    write_log ("CON0=%04.4X CON1=%04.4X ADAT=%04.4X BDAT=%04.4X CDAT=%04.4X\n",
+       bltcon0, bltcon1, blt_info.bltadat, blt_info.bltbdat, blt_info.bltcdat);
+    write_log ("AFWM=%04.4X ALWM=%04.4X AMOD=%04.4X BMOD=%04.4X CMOD=%04.4X DMOD=%04.4X\n",
+       blt_info.bltafwm, blt_info.bltalwm,
+       blt_info.bltamod & 0xffff, blt_info.bltbmod & 0xffff, blt_info.bltcmod & 0xffff, blt_info.bltdmod & 0xffff);
+}
+
+STATIC_INLINE uae_u8 *blit_xlateptr(uaecptr bltpt, int bytecount)
+{
+    if (!chipmem_bank.check(bltpt,bytecount)) return NULL;
+    return chipmem_bank.xlateaddr(bltpt);
+}
+
+STATIC_INLINE uae_u8 *blit_xlateptr_desc(uaecptr bltpt, int bytecount)
+{
+    if (!chipmem_bank.check(bltpt-bytecount, bytecount)) return NULL;
+    return chipmem_bank.xlateaddr(bltpt);
+}
+
+static void blitter_done (void)
+{
+    ddat1use = ddat2use = 0;
+    bltstate = BLT_done;
+    blitter_done_notify ();
+    INTREQ(0x8040);
+    eventtab[ev_blitter].active = 0;
+    unset_special (SPCFLAG_BLTNASTY);
+#ifdef BLITTER_DEBUG
+    write_log ("cycles %d, missed %d, total %d\n",
+       blit_cyclecounter, blit_misscyclecounter, blit_cyclecounter + blit_misscyclecounter);
+#endif
+}
+
+static void blitter_dofast(void)
+{
+    int i,j;
+    uaecptr bltadatptr = 0, bltbdatptr = 0, bltcdatptr = 0, bltddatptr = 0;
+    uae_u8 mt = bltcon0 & 0xFF;
+
+    blit_masktable[0] = blt_info.bltafwm;
+    blit_masktable[blt_info.hblitsize - 1] &= blt_info.bltalwm;
+
+    if (bltcon0 & 0x800) {
+       bltadatptr = bltapt;
+       bltapt += (blt_info.hblitsize*2 + blt_info.bltamod)*blt_info.vblitsize;
+    }
+    if (bltcon0 & 0x400) {
+       bltbdatptr = bltbpt;
+       bltbpt += (blt_info.hblitsize*2 + blt_info.bltbmod)*blt_info.vblitsize;
+    }
+    if (bltcon0 & 0x200) {
+       bltcdatptr = bltcpt;
+       bltcpt += (blt_info.hblitsize*2 + blt_info.bltcmod)*blt_info.vblitsize;
+    }
+    if (bltcon0 & 0x100) {
+       bltddatptr = bltdpt;
+       bltdpt += (blt_info.hblitsize*2 + blt_info.bltdmod)*blt_info.vblitsize;
+    }
+
+    if (blitfunc_dofast[mt] && !blitfill)
+       (*blitfunc_dofast[mt])(bltadatptr, bltbdatptr, bltcdatptr, bltddatptr, &blt_info);
+    else {
+       uae_u32 blitbhold = blt_info.bltbhold;
+       uae_u32 preva = 0, prevb = 0;
+       uaecptr dstp = 0;
+       int dodst = 0;
+
+       /*if (!blitfill) write_log ("minterm %x not present\n",mt); */
+       for (j = 0; j < blt_info.vblitsize; j++) {
+           blitfc = !!(bltcon1 & 0x4);
+           for (i = 0; i < blt_info.hblitsize; i++) {
+               uae_u32 bltadat, blitahold;
+               uae_u16 bltbdat;
+               if (bltadatptr) {
+                   blt_info.bltadat = bltadat = chipmem_wget (bltadatptr);
+                   bltadatptr += 2;
+               } else
+                   bltadat = blt_info.bltadat;
+               bltadat &= blit_masktable[i];
+               blitahold = (((uae_u32)preva << 16) | bltadat) >> blt_info.blitashift;
+               preva = bltadat;
+
+               if (bltbdatptr) {
+                   blt_info.bltbdat = bltbdat = chipmem_wget (bltbdatptr);
+                   bltbdatptr += 2;
+                   blitbhold = (((uae_u32)prevb << 16) | bltbdat) >> blt_info.blitbshift;
+                   prevb = bltbdat;
+               }
+
+               if (bltcdatptr) {
+                   blt_info.bltcdat = chipmem_wget (bltcdatptr);
+                   bltcdatptr += 2;
+               }
+               if (dodst) chipmem_wput (dstp, blt_info.bltddat);
+               blt_info.bltddat = blit_func (blitahold, blitbhold, blt_info.bltcdat, mt) & 0xFFFF;
+               if (blitfill) {
+                   uae_u16 d = blt_info.bltddat;
+                   int ifemode = blitife ? 2 : 0;
+                   int fc1 = blit_filltable[d & 255][ifemode + blitfc][1];
+                   blt_info.bltddat = (blit_filltable[d & 255][ifemode + blitfc][0]
+                                       + (blit_filltable[d >> 8][ifemode + fc1][0] << 8));
+                   blitfc = blit_filltable[d >> 8][ifemode + fc1][1];
+               }
+               if (blt_info.bltddat)
+                   blt_info.blitzero = 0;
+               if (bltddatptr) {
+                   dodst = 1;
+                   dstp = bltddatptr;
+                   bltddatptr += 2;
+               }
+           }
+           if (bltadatptr) bltadatptr += blt_info.bltamod;
+           if (bltbdatptr) bltbdatptr += blt_info.bltbmod;
+           if (bltcdatptr) bltcdatptr += blt_info.bltcmod;
+           if (bltddatptr) bltddatptr += blt_info.bltdmod;
+       }
+       if (dodst) chipmem_wput (dstp, blt_info.bltddat);
+       blt_info.bltbhold = blitbhold;
+    }
+    blit_masktable[0] = 0xFFFF;
+    blit_masktable[blt_info.hblitsize - 1] = 0xFFFF;
+
+    bltstate = BLT_done;
+}
+
+static void blitter_dofast_desc(void)
+{
+    int i,j;
+    uaecptr bltadatptr = 0, bltbdatptr = 0, bltcdatptr = 0, bltddatptr = 0;
+    uae_u8 mt = bltcon0 & 0xFF;
+
+    blit_masktable[0] = blt_info.bltafwm;
+    blit_masktable[blt_info.hblitsize - 1] &= blt_info.bltalwm;
+
+    if (bltcon0 & 0x800) {
+       bltadatptr = bltapt;
+       bltapt -= (blt_info.hblitsize*2 + blt_info.bltamod)*blt_info.vblitsize;
+    }
+    if (bltcon0 & 0x400) {
+       bltbdatptr = bltbpt;
+       bltbpt -= (blt_info.hblitsize*2 + blt_info.bltbmod)*blt_info.vblitsize;
+    }
+    if (bltcon0 & 0x200) {
+       bltcdatptr = bltcpt;
+       bltcpt -= (blt_info.hblitsize*2 + blt_info.bltcmod)*blt_info.vblitsize;
+    }
+    if (bltcon0 & 0x100) {
+       bltddatptr = bltdpt;
+       bltdpt -= (blt_info.hblitsize*2 + blt_info.bltdmod)*blt_info.vblitsize;
+    }
+    if (blitfunc_dofast_desc[mt] && !blitfill)
+       (*blitfunc_dofast_desc[mt])(bltadatptr, bltbdatptr, bltcdatptr, bltddatptr, &blt_info);
+    else {
+       uae_u32 blitbhold = blt_info.bltbhold;
+       uae_u32 preva = 0, prevb = 0;
+       uaecptr dstp = 0;
+       int dodst = 0;
+
+/*     if (!blitfill) write_log ("minterm %x not present\n",mt);*/
+       for (j = 0; j < blt_info.vblitsize; j++) {
+           blitfc = !!(bltcon1 & 0x4);
+           for (i = 0; i < blt_info.hblitsize; i++) {
+               uae_u32 bltadat, blitahold;
+               uae_u16 bltbdat;
+               if (bltadatptr) {
+                   bltadat = blt_info.bltadat = chipmem_wget (bltadatptr);
+                   bltadatptr -= 2;
+               } else
+                   bltadat = blt_info.bltadat;
+               bltadat &= blit_masktable[i];
+               blitahold = (((uae_u32)bltadat << 16) | preva) >> blt_info.blitdownashift;
+               preva = bltadat;
+
+               if (bltbdatptr) {
+                   blt_info.bltbdat = bltbdat = chipmem_wget (bltbdatptr);
+                   bltbdatptr -= 2;
+                   blitbhold = (((uae_u32)bltbdat << 16) | prevb) >> blt_info.blitdownbshift;
+                   prevb = bltbdat;
+               }
+
+               if (bltcdatptr) {
+                   blt_info.bltcdat = blt_info.bltbdat = chipmem_wget (bltcdatptr);
+                   bltcdatptr -= 2;
+               }
+               if (dodst) chipmem_wput (dstp, blt_info.bltddat);
+               blt_info.bltddat = blit_func (blitahold, blitbhold, blt_info.bltcdat, mt) & 0xFFFF;
+               if (blitfill) {
+                   uae_u16 d = blt_info.bltddat;
+                   int ifemode = blitife ? 2 : 0;
+                   int fc1 = blit_filltable[d & 255][ifemode + blitfc][1];
+                   blt_info.bltddat = (blit_filltable[d & 255][ifemode + blitfc][0]
+                                       + (blit_filltable[d >> 8][ifemode + fc1][0] << 8));
+                   blitfc = blit_filltable[d >> 8][ifemode + fc1][1];
+               }
+               if (blt_info.bltddat)
+                   blt_info.blitzero = 0;
+               if (bltddatptr) {
+                   dstp = bltddatptr;
+                   dodst = 1;
+                   bltddatptr -= 2;
+               }
+           }
+           if (bltadatptr) bltadatptr -= blt_info.bltamod;
+           if (bltbdatptr) bltbdatptr -= blt_info.bltbmod;
+           if (bltcdatptr) bltcdatptr -= blt_info.bltcmod;
+           if (bltddatptr) bltddatptr -= blt_info.bltdmod;
+       }
+       if (dodst) chipmem_wput (dstp, blt_info.bltddat);
+       blt_info.bltbhold = blitbhold;
+    }
+    blit_masktable[0] = 0xFFFF;
+    blit_masktable[blt_info.hblitsize - 1] = 0xFFFF;
+
+    bltstate = BLT_done;
+}
+
+STATIC_INLINE int blitter_read(void)
+{
+    if (bltcon0 & 0x200) {
+       if (!dmaen(DMA_BLITTER))
+           return 1;
+        blt_info.bltcdat = chipmem_bank.wget(bltcpt);
+    }
+    bltstate = BLT_work;
+    return (bltcon0 & 0x200) != 0;
+}
+
+STATIC_INLINE int blitter_write(void)
+{
+    if (blt_info.bltddat)
+       blt_info.blitzero = 0;
+    /* D-channel state has no effect on linedraw, but C must be enabled or nothing is drawn! */
+    if (bltcon0 & 0x200) {
+       if (!dmaen(DMA_BLITTER)) return 1;
+       chipmem_bank.wput(bltdpt, blt_info.bltddat);
+       bltdpt = bltcpt; /* believe it or not but try Cardamon or Cardamom without this.. */
+    }
+    bltstate = BLT_next;
+    return (bltcon0 & 0x200) != 0;
+}
+
+STATIC_INLINE void blitter_line_incx(void)
+{
+    if (++blinea_shift == 16) {
+       blinea_shift = 0;
+       bltcnxlpt += 2;
+    }
+}
+
+STATIC_INLINE void blitter_line_decx(void)
+{
+    if (blinea_shift-- == 0) {
+       blinea_shift = 15;
+       bltcnxlpt -= 2;
+    }
+}
+
+STATIC_INLINE void blitter_line_decy(void)
+{
+    bltcnxlpt -= blt_info.bltcmod;
+    blitonedot = 0;
+}
+
+STATIC_INLINE void blitter_line_incy(void)
+{
+    bltcnxlpt += blt_info.bltcmod;
+    blitonedot = 0;
+}
+
+static void blitter_line(void)
+{
+    uae_u16 blitahold = blinea >> blinea_shift;
+    uae_u16 blitbhold = blineb & 1 ? 0xFFFF : 0;
+    uae_u16 blitchold = blt_info.bltcdat;
+    blt_info.bltddat = 0;
+
+    if (blitsing && blitonedot)
+       blitahold = 0;
+    blitonedot = 1;
+    blt_info.bltddat = blit_func(blitahold, blitbhold, blitchold, bltcon0 & 0xFF);
+    if (!blitsign){
+       if (bltcon0 & 0x800)
+           bltapt += (uae_s16)blt_info.bltamod;
+       if (bltcon1 & 0x10){
+           if (bltcon1 & 0x8)
+               blitter_line_decy();
+           else
+               blitter_line_incy();
+       } else {
+           if (bltcon1 & 0x8)
+               blitter_line_decx();
+           else
+               blitter_line_incx();
+       }
+    } else {
+       if (bltcon0 & 0x800)
+           bltapt += (uae_s16)blt_info.bltbmod;
+    }
+    if (bltcon1 & 0x10){
+       if (bltcon1 & 0x4)
+           blitter_line_decx();
+       else
+           blitter_line_incx();
+    } else {
+       if (bltcon1 & 0x4)
+           blitter_line_decy();
+       else
+           blitter_line_incy();
+    }
+    blitsign = 0 > (uae_s16)bltapt;
+    bltstate = BLT_write;
+}
+
+STATIC_INLINE void blitter_nxline(void)
+{
+    bltdpt = bltcpt = bltcnxlpt;
+    blineb = (blineb << 1) | (blineb >> 15);
+    if (--blt_info.vblitsize == 0) {
+       bltstate = BLT_done;
+    } else {
+       bltstate = BLT_read;
+    }
+}
+
+static void actually_do_blit(void)
+{
+    if (blitline) {
+       do {
+           blitter_read();
+           blitter_line();
+           blitter_write();
+           blitter_nxline();
+       } while (bltstate != BLT_done);
+    } else {
+       if (blitdesc)
+           blitter_dofast_desc();
+       else
+           blitter_dofast();
+        bltstate = BLT_done;
+    }
+}
+
+void blitter_handler(void)
+{
+    if (!dmaen(DMA_BLITTER)) {
+        eventtab[ev_blitter].active = 1;
+        eventtab[ev_blitter].oldcycles = get_cycles ();
+        eventtab[ev_blitter].evtime = 10 * CYCLE_UNIT + get_cycles (); /* wait a little */
+        return; /* gotta come back later. */
+    }
+    if (blit_slowdown > 0) {
+       eventtab[ev_blitter].active = 1;
+        eventtab[ev_blitter].oldcycles = get_cycles ();
+        eventtab[ev_blitter].evtime = blit_slowdown * CYCLE_UNIT + get_cycles ();
+        blit_slowdown = -1;
+        return;
+    }
+#ifdef BLITTER_DEBUG
+    if (!blitter_dontdo) 
+       actually_do_blit();
+    else
+       bltstate = BLT_done;
+#else
+    actually_do_blit ();
+#endif
+    blitter_done ();
+}
+
+STATIC_INLINE int channel_state (int cycles)
+{
+    if (cycles < blit_diag[0])
+        return blit_diag[blit_diag[1] + 2 + cycles];
+    return blit_diag[((cycles - blit_diag[0]) % blit_diag[1]) + 2];
+}
+
+#ifdef CPUEMU_6
+
+static int blit_last_hpos;
+
+static int blitter_dma_cycles_line, blitter_dma_cycles_line_count;
+static int blitter_cyclecounter;
+static int blitter_hcounter1, blitter_hcounter2;
+static int blitter_vcounter1, blitter_vcounter2;
+
+
+static uae_u32 preva, prevb;
+STATIC_INLINE uae_u16 blitter_doblit (void)
+{
+    uae_u32 blitahold;
+    uae_u16 bltadat, ddat;
+    uae_u8 mt = bltcon0 & 0xFF;
+
+    bltadat = blt_info.bltadat;
+    if (blitter_hcounter1 == 0)
+       bltadat &= blt_info.bltafwm;
+    if (blitter_hcounter1 == blt_info.hblitsize - 1)
+       bltadat &= blt_info.bltalwm;
+    if (blitdesc)
+        blitahold = (((uae_u32)bltadat << 16) | preva) >> blt_info.blitdownashift;
+    else
+        blitahold = (((uae_u32)preva << 16) | bltadat) >> blt_info.blitashift;
+    preva = bltadat;
+
+    ddat = blit_func (blitahold, blt_info.bltbhold, blt_info.bltcdat, mt) & 0xFFFF;
+
+    if (bltcon1 & 0x18) {
+        uae_u16 d = ddat;
+        int ifemode = blitife ? 2 : 0;
+        int fc1 = blit_filltable[d & 255][ifemode + blitfc][1];
+        ddat = (blit_filltable[d & 255][ifemode + blitfc][0]
+                       + (blit_filltable[d >> 8][ifemode + fc1][0] << 8));
+        blitfc = blit_filltable[d >> 8][ifemode + fc1][1];
+    }
+       
+    if (ddat)
+        blt_info.blitzero = 0;
+
+    return ddat;
+}
+
+
+int is_bitplane_dma (int hpos);
+
+STATIC_INLINE int blitter_doddma (void)
+{
+    int wd;
+    uae_u16 d;
+
+    wd = 0;
+    if (blit_dmacount2 == 0) {
+       d =  blitter_doblit ();
+       wd = -1;
+    } else if (ddat2use) {
+       d = ddat2;
+       ddat2use = 0;
+       wd = 2;
+    } else if (ddat1use) {
+       d = ddat1;
+       ddat1use = 0;
+       wd = 1;
+    }
+    if (wd) {
+       chipmem_wput (bltdpt, d);
+       bltdpt += blit_add;
+       blitter_hcounter2++;
+       if (blitter_hcounter2 == blt_info.hblitsize) {
+           blitter_hcounter2 = 0;
+           bltdpt += blit_modaddd;
+           blitter_vcounter2++;
+           if (blitter_vcounter2 > blitter_vcounter1)
+               blitter_vcounter1 = blitter_vcounter2;
+       }
+       if (blit_ch == 1)
+           blitter_hcounter1 = blitter_hcounter2;
+    }
+    return wd;
+}
+
+STATIC_INLINE void blitter_dodma (int ch)
+{
+
+    switch (ch)
+    {
+       case 1:
+        blt_info.bltadat = chipmem_wget (bltapt);
+       bltapt += blit_add;
+       break;
+       case 2:
+       blt_info.bltbdat = chipmem_wget (bltbpt);
+       bltbpt += blit_add;
+       if (blitdesc)
+           blt_info.bltbhold = (((uae_u32)blt_info.bltbdat << 16) | prevb) >> blt_info.blitdownbshift;
+       else
+           blt_info.bltbhold = (((uae_u32)prevb << 16) | blt_info.bltbdat) >> blt_info.blitbshift;
+       prevb = blt_info.bltbdat;
+       break;
+       case 3:
+       blt_info.bltcdat = chipmem_wget (bltcpt);
+       bltcpt += blit_add;
+       break;
+    }
+
+    blitter_cyclecounter++;
+    if (blitter_cyclecounter >= blit_dmacount2) {
+       blitter_cyclecounter = 0;
+       ddat2 = ddat1;
+       ddat2use = ddat1use;
+       ddat1use = 0;
+       ddat1 = blitter_doblit ();
+       if (bltcon0 & 0x100)
+           ddat1use = 1;
+       blitter_hcounter1++;
+       if (blitter_hcounter1 == blt_info.hblitsize) {
+           blitter_hcounter1 = 0;
+           if (bltcon0 & 0x800)
+               bltapt += blit_modadda;
+           if (bltcon0 & 0x400)
+               bltbpt += blit_modaddb;
+           if (bltcon0 & 0x200)
+               bltcpt += blit_modaddc;
+           blitter_vcounter1++;
+           blitfc = !!(bltcon1 & 0x4);
+       }
+    }
+}
+
+static void decide_blitter_line (int hpos)
+{
+    hpos++;
+    if (dmaen (DMA_BLITTER)) {
+       while (blit_last_hpos < hpos) {
+           int c = channel_state (blit_cyclecounter);
+           for (;;) {
+               if (c && (cycle_line[blit_last_hpos] || is_bitplane_dma (blit_last_hpos)))
+                   break;
+               if (c)
+                   cycle_line[blit_last_hpos] |= CYCLE_BLITTER;
+               blit_cyclecounter++;
+               blit_linecyclecounter++;
+               if (blit_linecyclecounter >= blit_diag[1]) {
+                   blit_linecyclecounter = 0;
+                   blitter_read();
+                   blitter_line();
+                   blitter_write();
+                   blitter_nxline();
+                   if (bltstate == BLT_done) {
+                       blitter_done ();
+                       return;
+                   }
+               }
+               break;
+           }
+           blit_last_hpos++;
+       }
+    } else {
+       blit_last_hpos = hpos;
+    }
+    if (blit_last_hpos > maxhpos)
+       blit_last_hpos = 0;
+}
+
+void decide_blitter (int hpos)
+{
+    if (bltstate == BLT_done)
+       return;
+    if (!currprefs.blitter_cycle_exact) {
+        blitter_handler ();
+       return;
+    }
+    if (blitline) {
+       decide_blitter_line (hpos);
+       return;
+    }
+    if (blit_starting && get_cycles () - blit_starts < 4 * CYCLE_UNIT) {
+       blit_last_hpos = hpos + 1;
+       return;
+    }
+    hpos++;
+    if (dmaen (DMA_BLITTER)) {
+       while (blit_last_hpos < hpos) {
+           int c = channel_state (blit_cyclecounter);
+#ifdef BLITTER_SLOWDOWNDEBUG
+           blitter_slowdowndebug--;
+           if (blitter_slowdowndebug < 0) {
+               cycle_line[blit_last_hpos] |= CYCLE_BLITTER;
+               blitter_slowdowndebug = BLITTER_SLOWDOWNDEBUG;
+           }
+#endif
+           for (;;) {
+               if (c && (cycle_line[blit_last_hpos] || is_bitplane_dma (blit_last_hpos))) {
+                   blit_misscyclecounter++;
+                   break;
+               }
+               if (c == 4) {
+                   if (blitter_doddma ()) {
+                       cycle_line[blit_last_hpos] |= CYCLE_BLITTER;
+                       blit_cyclecounter++;
+                   }
+               } else if (c) {
+                   if (blitter_vcounter1 < blt_info.vblitsize) {
+                       cycle_line[blit_last_hpos] |= CYCLE_BLITTER;
+                       blitter_dodma (c);
+                   }
+                   blit_cyclecounter++;
+               } else {
+                   blit_cyclecounter++;
+                   /* check if blit with zero channels has ended  */
+                   if (blit_cyclecounter >= blit_maxcyclecounter) {
+                       blitter_done ();
+                       return;
+                   }
+               }
+               if (blitter_vcounter1 >= blt_info.vblitsize && blitter_vcounter2 >= blt_info.vblitsize) {
+                   if (!ddat1use && !ddat2use) {
+                       blitter_done ();
+                       return;
+                   }
+                   if (blit_diag != blit_cycle_diagram_finald) {
+                       blit_cyclecounter = 0;
+                       blit_diag = blit_cycle_diagram_finald;
+                   }
+               }
+               break;
+           }
+           blit_last_hpos++;
+       }
+    } else {
+       blit_last_hpos = hpos;
+    }
+    if (blit_last_hpos > maxhpos)
+       blit_last_hpos = 0;
+}
+#else
+void decide_blitter (int hpos) { }
+#endif
+
+static void blitter_force_finish (void)
+{
+    uae_u16 odmacon;
+    if (bltstate == BLT_done)
+       return;
+    if (bltstate != BLT_done) {
+        /* blitter is currently running
+         * force finish (no blitter state support yet)
+          */
+       odmacon = dmacon;
+       dmacon |= DMA_MASTER | DMA_BLITTER;
+       write_log ("forcing blitter finish\n");
+       if (currprefs.blitter_cycle_exact) {
+           while (bltstate != BLT_done) {
+               memset (cycle_line, 0, maxhpos);
+               decide_blitter (maxhpos);
+           }
+       } else {
+           actually_do_blit ();
+       }
+       blitter_done ();
+       dmacon = odmacon;
+    }
+}
+
+static void blit_bltset (int con)
+{
+    int i;
+
+    blitline = bltcon1 & 1; 
+    blitfill = bltcon1 & 0x18;
+    blitdesc = bltcon1 & 2;
+    blit_ch = (bltcon0 & 0x0f00) >> 8;
+
+    blit_singlechannel = 0;
+    if (blit_ch == 0 || blit_ch == 1 || blit_ch == 2 || blit_ch == 4 || blit_ch == 8)
+       blit_singlechannel = 1;
+    if (blitline) {
+       if (blt_info.hblitsize != 2)
+           write_log ("weird hblitsize in linemode: %d vsize=%d PC%=%x\n", blt_info.hblitsize, blt_info.vblitsize, m68k_getpc());
+        blit_diag = blit_cycle_diagram_line;
+    } else {
+       if (con & 2) {
+           blitfc = !!(bltcon1 & 0x4);
+           blitife = bltcon1 & 0x8;
+           if ((bltcon1 & 0x18) == 0x18) {
+               /* Digital "Trash" demo does this; others too. Apparently, no
+               * negative effects. */
+               static int warn = 1;
+               if (warn)
+                   write_log ("warning: weird fill mode (further messages suppressed)\n");
+               warn = 0;
+               blitife = 0;
+           }
+       }
+       if (blitfill && !blitdesc) {
+           static int warn = 1;
+           if (warn)
+               write_log ("warning: blitter fill without desc (further messages suppressed)\n");
+           warn = 0;
+       }
+       blit_diag = blitfill ? blit_cycle_diagram_fill[blit_ch] : blit_cycle_diagram[blit_ch];
+    }
+    if ((bltcon1 & 0x80) && (currprefs.chipset_mask & CSMASK_ECS_AGNUS))
+       write_log("warning: BLTCON1 DOFF-bit set\n");
+
+    blit_dmacount = blit_dmacount2 = 0;
+    for (i = 0; i < blit_diag[1]; i++) {
+       int v = blit_diag[2 + i];
+       if (v)
+           blit_dmacount++;
+       if (v > 0 && v < 4)
+           blit_dmacount2++;
+    }
+
+    blt_info.blitashift = bltcon0 >> 12;
+    blt_info.blitdownashift = 16 - blt_info.blitashift;
+    blt_info.blitbshift = bltcon1 >> 12;
+    blt_info.blitdownbshift = 16 - blt_info.blitbshift;
+}
+
+void blit_modset (void)
+{
+    int mult;
+
+    blit_add = blitdesc ? -2 : 2;
+    mult = blitdesc ? -1 : 1;
+    blit_modadda = mult * blt_info.bltamod;
+    blit_modaddb = mult * blt_info.bltbmod;
+    blit_modaddc = mult * blt_info.bltcmod;
+    blit_modaddd = mult * blt_info.bltdmod;
+}
+
+void reset_blit (int bltcon)
+{
+    if (bltstate == BLT_done)
+       return;
+    if (bltcon)
+       blit_bltset (bltcon);
+    blit_modset ();
+}
+
+void do_blitter (int hpos)
+{
+    int cycles;
+
+    blt_info.blitzero = 1;
+    bltstate = BLT_init;
+    preva = 0;
+    prevb = 0;
+
+    blit_firstline_cycles = blit_first_cycle = get_cycles ();
+    blit_cyclecounter = blit_misscyclecounter = 0;
+    blit_last_cycle = 0;
+    blit_maxcyclecounter = 0;
+    blit_last_hpos = hpos;
+
+    reset_blit (1|2); 
+
+    if (blitline) {
+       bltcnxlpt = bltcpt;
+       bltdnxlpt = bltdpt;
+       blitsing = bltcon1 & 0x2;
+       blinea = blt_info.bltadat;
+       blineb = (blt_info.bltbdat >> blt_info.blitbshift) | (blt_info.bltbdat << (16 - blt_info.blitbshift));
+       blitsign = bltcon1 & 0x40;
+       blitonedot = 0;
+        cycles = blt_info.vblitsize;
+    } else {
+        blit_firstline_cycles = blit_first_cycle + blit_diag[1] * blt_info.hblitsize * CYCLE_UNIT;
+        cycles = blt_info.vblitsize * blt_info.hblitsize;
+    }
+    blit_cycles_total = cycles;
+
+#ifdef BLITTER_DEBUG
+    blitter_dontdo = 0;
+    if (1) {
+       write_log("blitstart: v=%03.3d h=%03.3d %dx%d %d (%d) d=%d f=%02.2X n=%d pc=%p l=%d dma=%d\n",
+           vpos, hpos, blt_info.hblitsize, blt_info.vblitsize, cycles, blit_ch,
+           blitdesc ? 1 : 0, blitfill,
+           dmaen(DMA_BLITPRI) ? 1 : 0, m68k_getpc(), blitline, dmaen(DMA_BLITTER));
+       blitter_dump ();
+    }
+#endif
+
+    blit_slowdown = 0;
+
+    unset_special (SPCFLAG_BLTNASTY);
+    if (dmaen(DMA_BLITPRI))
+        set_special (SPCFLAG_BLTNASTY);
+
+    if (blt_info.vblitsize == 0 || (blitline && blt_info.hblitsize != 2)) {
+        blitter_done ();
+        return;
+    }
+
+    if (dmaen(DMA_BLITTER))
+       bltstate = BLT_work;
+
+    blit_maxcyclecounter = 0x7fffffff;
+    if (currprefs.blitter_cycle_exact) {
+       blitter_dma_cycles_line_count = 0;
+       blitter_hcounter1 = blitter_hcounter2 = 0;
+       blitter_vcounter1 = blitter_vcounter2 = 0;
+       if (blit_dmacount2 == blit_dmacount)
+           blitter_vcounter2 = blt_info.vblitsize;
+       blit_linecyclecounter = 0;
+       blitter_dma_cycles_line = blt_info.hblitsize * blit_dmacount2;
+       if (blit_ch == 0)
+           blit_maxcyclecounter = blt_info.hblitsize * blt_info.vblitsize;
+       blit_starts = get_cycles ();
+       blit_starting = 1;
+       return;
+    }
+
+    if (currprefs.immediate_blits)
+        cycles = 1;
+
+    eventtab[ev_blitter].active = 1;
+    eventtab[ev_blitter].oldcycles = get_cycles ();
+    eventtab[ev_blitter].evtime = cycles * blit_diag[1] * CYCLE_UNIT + get_cycles ();
+    events_schedule();
+}
+
+
+void maybe_blit (int hpos, int hack)
+{
+    static int warned;
+
+    if (bltstate == BLT_done)
+       return;
+
+    if (!warned && dmaen (DMA_BLITTER)) {
+#ifndef BLITTER_DEBUG
+       warned = 1;
+#endif
+       write_log ("warning: Program does not wait for blitter %p\n", m68k_getpc());
+    }
+
+    if (currprefs.blitter_cycle_exact) {
+       decide_blitter (hpos);
+       return;
+    }
+
+    if (!eventtab[ev_blitter].active)
+       write_log ("FOO!!?\n");
+    if (hack == 1 && get_cycles() < blit_firstline_cycles)
+       return;
+
+    blitter_handler ();
+}
+
+int blitnasty (void)
+{
+    int cycles, ccnt;
+    if (bltstate == BLT_done)
+       return 0;
+    if (!dmaen(DMA_BLITTER))
+       return 0;
+    if (blit_last_cycle >= blit_diag[0] && blit_dmacount == blit_diag[1])
+        return 0;
+    cycles = (get_cycles () - blit_first_cycle) / CYCLE_UNIT;
+    ccnt = 0;
+    while (blit_last_cycle < cycles) {
+       int c = channel_state (blit_last_cycle++);
+       if (!c)
+           ccnt++;
+    }
+    return ccnt;
+}
+
+/* very approximate emulation of blitter slowdown caused by bitplane DMA */
+void blitter_slowdown (int ddfstrt, int ddfstop, int totalcycles, int freecycles)
+{
+    static int oddfstrt, oddfstop, ototal, ofree;
+    static int cycles_used;
+    int slow;
+    
+    if (ddfstrt != oddfstrt || ddfstop != oddfstop || totalcycles != ototal || ofree != freecycles) {
+       int linecycles = ddfstop - ddfstrt;
+        cycles_used = 0;
+        if (linecycles > blit_cycles_total)
+           linecycles = blit_cycles_total;
+       if (linecycles < 0)
+           linecycles = 0;
+       if (totalcycles == 0)
+           return;
+       cycles_used = linecycles * (totalcycles - freecycles) / totalcycles;
+       oddfstrt = ddfstrt;
+       oddfstop = ddfstop;
+       ototal = totalcycles;
+       ofree = freecycles;
+    }
+    if (blit_slowdown < 0 || blitline || totalcycles == 0)
+       return;
+    slow = cycles_used * blit_dmacount / blit_diag[1];
+    slow = slow * 7 / 10;
+    if (slow <= 0)
+       return;
+    blit_slowdown += slow;
+    blit_misscyclecounter += slow;
+    blit_cycles_total -= maxhpos;
+}
+
+uae_u8 *restore_blitter (uae_u8 *src)
+{
+    uae_u32 flags = restore_u32();
+
+    bltstate = (flags & 1) ? BLT_init : BLT_done;
+    if (bltstate == BLT_init) {
+       write_log ("blitter was started but DMA was inactive during save\n");
+       do_blitter (0);
+    }
+    return src;
+}
+
+uae_u8 *save_blitter (int *len, uae_u8 *dstptr)
+{
+    uae_u8 *dstbak,*dst;
+
+    if (bltstate != BLT_done && bltstate != BLT_init) {
+       write_log ("blitter was running, forcing immediate finish\n");
+        /* blitter is active just now but we don't have blitter state support yet */
+       blitter_force_finish ();
+    }
+    if (dstptr)
+       dstbak = dst = dstptr;
+    else
+        dstbak = dst = malloc (16);
+    save_u32((bltstate != BLT_done) ? 0 : 1);
+    *len = dst - dstbak;
+    return dstbak;
+
+}
diff --git a/blkdev.c b/blkdev.c
new file mode 100755 (executable)
index 0000000..0cf3f8b
--- /dev/null
+++ b/blkdev.c
@@ -0,0 +1,319 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * lowlevel device glue
+  *
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+#include "options.h"
+#include "memory.h"
+
+#include "config.h"
+
+#include "blkdev.h"
+
+static struct device_functions *device_func[2];
+static int ioctl;
+
+#ifdef WIN32
+
+#include "od-win32/win32.h"
+
+extern struct device_functions devicefunc_win32_aspi;
+extern struct device_functions devicefunc_win32_spti;
+extern struct device_functions devicefunc_win32_ioctl;
+
+static void install_driver (int flags)
+{
+    device_func[DF_SCSI] = &devicefunc_win32_aspi;
+#ifdef WINDDK
+    if (os_winnt && os_winnt_admin) {
+       device_func[DF_IOCTL] = &devicefunc_win32_ioctl;
+        device_func[DF_SCSI] = &devicefunc_win32_spti;
+    }
+    if (currprefs.win32_aspi) {
+        device_func[DF_SCSI] = &devicefunc_win32_aspi;
+       device_func[DF_IOCTL] = 0;
+    }
+#endif
+}
+#endif
+
+int sys_command_open (int mode, int unitnum)
+{
+    if (mode == DF_SCSI || !ioctl)
+       return device_func[DF_SCSI]->opendev (unitnum);
+    else
+       return device_func[DF_IOCTL]->opendev (unitnum);
+}
+
+void sys_command_close (int mode, int unitnum)
+{
+    if (mode == DF_SCSI || !ioctl)
+       device_func[DF_SCSI]->closedev (unitnum);
+    else
+       device_func[DF_IOCTL]->closedev (unitnum);
+}
+
+int device_func_init (int flags)
+{
+    static int initialized;
+    int support_scsi = 0, support_ioctl = 0;
+    int oflags = (flags & DEVICE_TYPE_SCSI) ? 0 : (1 << INQ_ROMD);
+
+    if (initialized)
+       return initialized;
+    install_driver (flags);
+    if (device_func[DF_IOCTL])
+       ioctl = 1;
+    else
+       ioctl = 0;
+    support_scsi = device_func[DF_SCSI]->openbus (oflags) ? 1 : 0;
+    if (ioctl)
+       support_ioctl = device_func[DF_IOCTL]->openbus (1 << INQ_ROMD) ? 1 : 0;
+    initialized = 1;
+    write_log ("support_scsi = %d support_ioctl = %d\n", support_scsi, support_ioctl);
+    return (support_scsi ? (1 << DF_SCSI) : 0) | (support_ioctl ? (1 << DF_IOCTL) : 0);
+}
+
+static int audiostatus (int unitnum)
+{
+    uae_u8 cmd[10] = {0x42,2,0x40,1,0,0,0,DEVICE_SCSI_BUFSIZE>>8,DEVICE_SCSI_BUFSIZE&0xff,0};
+    uae_u8 *p = device_func[DF_SCSI]->exec_in (unitnum, cmd, sizeof (cmd), 0);
+    if (!p)
+       return 0;
+    return p[1];
+}
+
+/* pause/unpause CD audio */
+void sys_command_pause (int mode, int unitnum, int paused)
+{
+    if (mode == DF_SCSI || !ioctl) {
+       int as = audiostatus (unitnum);
+       if ((paused && as == 0x11) && (!paused && as == 0x12)) {
+           uae_u8 cmd[10] = {0x4b,0,0,0,0,0,0,0,paused?0:1,0};
+           device_func[DF_SCSI]->exec_out (unitnum, cmd, sizeof (cmd));
+       }
+       return;
+    }
+    device_func[DF_IOCTL]->pause (unitnum, paused);
+}
+
+/* stop CD audio */
+void sys_command_stop (int mode, int unitnum)
+{
+    if (mode == DF_SCSI || !ioctl) {
+       int as = audiostatus (unitnum);
+       if (as == 0x11) {
+           uae_u8 cmd[6] = {0x4e,0,0,0,0,0};
+           device_func[DF_SCSI]->exec_out (unitnum, cmd, sizeof (cmd));
+       }
+       return;
+    }
+    device_func[DF_IOCTL]->stop (unitnum);
+}
+
+/* play CD audio */
+int sys_command_play (int mode, int unitnum,uae_u32 startmsf, uae_u32 endmsf, int scan)
+{
+    if (mode == DF_SCSI || !ioctl) {
+        uae_u8 cmd[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
+#if 0
+       if (scan) {
+           cmd[0] = 0xba;
+           cmd[1] = scan < 0 ? 0x10 : 0x0;
+           cmd[3] = (uae_u8)(startmsf >> 16);
+           cmd[4] = (uae_u8)(startmsf >> 8);
+           cmd[5] = (uae_u8)(startmsf >> 0);
+           cmd[9] = 0x40;
+       } else {
+#endif
+           cmd[0] = 0x47;
+           cmd[3] = (uae_u8)(startmsf >> 16);
+           cmd[4] = (uae_u8)(startmsf >> 8);
+           cmd[5] = (uae_u8)(startmsf >> 0);
+           cmd[6] = (uae_u8)(endmsf >> 16);
+           cmd[7] = (uae_u8)(endmsf >> 8);
+           cmd[8] = (uae_u8)(endmsf >> 0);
+#if 0
+       }
+#endif
+        return device_func[DF_SCSI]->exec_out (unitnum, cmd, sizeof (cmd)) == 0 ? 0 : 1;
+    }
+    return device_func[DF_IOCTL]->play (unitnum, startmsf, endmsf, scan);
+}
+
+/* read qcode */
+uae_u8 *sys_command_qcode (int mode, int unitnum)
+{
+    if (mode == DF_SCSI || !ioctl) {
+       uae_u8 cmd[10] = {0x42,2,0x40,1,0,0,0,DEVICE_SCSI_BUFSIZE>>8,DEVICE_SCSI_BUFSIZE&0xff,0};
+       return  device_func[DF_SCSI]->exec_in (unitnum, cmd, sizeof (cmd), 0);
+    }
+    return device_func[DF_IOCTL]->qcode (unitnum);
+};
+
+/* read table of contents */
+uae_u8 *sys_command_toc (int mode, int unitnum)
+{
+    if (mode == DF_SCSI || !ioctl) {
+       uae_u8 cmd [10] = { 0x43,0,2,0,0,0,1,DEVICE_SCSI_BUFSIZE>>8,DEVICE_SCSI_BUFSIZE&0xFF,0};
+        return device_func[DF_SCSI]->exec_in (unitnum, cmd, sizeof(cmd), 0);
+    }
+    return device_func[DF_IOCTL]->toc (unitnum);
+}
+
+/* read one sector */
+uae_u8 *sys_command_read (int mode, int unitnum, int offset)
+{
+    if (mode == DF_SCSI || !ioctl) {
+       uae_u8 cmd[12] = { 0xbe, 0, 0, 0, 0, 0, 0, 0, 1, 0x10, 0, 0 };
+       cmd[3] = (uae_u8)(offset >> 16);
+       cmd[4] = (uae_u8)(offset >> 8);
+       cmd[5] = (uae_u8)(offset >> 0);
+        return device_func[DF_SCSI]->exec_in (unitnum, cmd, sizeof (cmd), 0);
+    }
+    return device_func[DF_IOCTL]->read (unitnum, offset);
+}
+
+struct device_info *sys_command_info (int mode, int unitnum, struct device_info *di)
+{
+    if (mode == DF_SCSI || !ioctl)
+       return device_func[DF_SCSI]->info (unitnum, di);
+    else
+       return device_func[DF_IOCTL]->info (unitnum, di);
+}
+
+#define MODE_SELECT_6 0x15
+#define MODE_SENSE_6 0x1a
+#define MODE_SELECT_10 0x55
+#define MODE_SENSE_10 0x5a
+
+void scsi_atapi_fixup_pre (uae_u8 *scsi_cmd, int *len, uae_u8 **datap, int *datalenp, int *parm)
+{
+    uae_u8 cmd, *p, *data = *datap;
+    int l, datalen = *datalenp;
+
+    *parm = 0;
+    cmd = scsi_cmd[0];
+    if (cmd != MODE_SELECT_6 && cmd != MODE_SENSE_6)
+       return;
+    l = scsi_cmd[4];
+    if (l > 4)
+       l += 4;
+    scsi_cmd[7] = l >> 8;
+    scsi_cmd[8] = l;
+    if (cmd == MODE_SELECT_6) {
+       scsi_cmd[0] = MODE_SELECT_10;
+       scsi_cmd[9] = scsi_cmd[5];
+       scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = scsi_cmd[6] = 0;
+       *len = 10;
+       p = xmalloc (8 + datalen + 4);
+       if (datalen > 4)
+           memcpy (p + 8, data + 4, datalen - 4);
+       p[0] = 0;
+       p[1] = data[0];
+       p[2] = data[1];
+       p[3] = data[2];
+       p[4] = p[5] = p[6] = 0;
+       p[7] = data[3];
+       if (l > 8)
+           datalen += 4;
+       *parm = MODE_SELECT_10;
+       *datap = p;
+    } else {
+       scsi_cmd[0] = MODE_SENSE_10;
+       scsi_cmd[9] = scsi_cmd[5];
+       scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = scsi_cmd[6] = 0;
+       if (l > 8)
+           datalen += 4;
+       *datap = xmalloc (datalen);
+       *len = 10;
+       *parm = MODE_SENSE_10;
+    }
+    *datalenp = datalen;
+}
+
+void scsi_atapi_fixup_post (uae_u8 *scsi_cmd, int len, uae_u8 *olddata, uae_u8 *data, int *datalenp, int parm)
+{
+    int datalen = *datalenp;
+    if (!data || !datalen)
+       return;
+    if (parm == MODE_SENSE_10) {
+       olddata[0] = data[1];
+       olddata[1] = data[2];
+       olddata[2] = data[3];
+       olddata[3] = data[7];
+        datalen -= 4;
+       if (datalen > 4)
+           memcpy (olddata + 4, data + 8, datalen - 4);
+       *datalenp = datalen;
+    }
+}
+
+static void scsi_atapi_fixup_inquiry (uaecptr req)
+{
+    uaecptr scsi_data = get_long (req + 0);
+    uae_u32 scsi_len = get_long (req + 4);
+    uaecptr scsi_cmd = get_long (req + 12);
+    uae_u8 cmd;
+
+    cmd = get_byte (scsi_cmd);
+    /* CDROM INQUIRY: most Amiga programs expect ANSI version == 2
+     * (ATAPI normally responds with zero)
+     */
+    if (cmd == 0x12 && scsi_len > 2 && scsi_data) {
+       uae_u8 per = get_byte (scsi_data + 0);
+       uae_u8 b = get_byte (scsi_data + 2);
+       /* CDROM and ANSI version == 0 ? */
+       if ((per & 31) == 5 && (b & 7) == 0) {
+           b |= 2;
+           put_byte (scsi_data + 2, b);
+       }
+    }
+}
+
+int sys_command_scsi_direct (int unitnum, uaecptr request)
+{
+    int ret = device_func[DF_SCSI]->exec_direct (unitnum, request);
+    if (!ret && device_func[DF_SCSI]->isatapi(unitnum))
+        scsi_atapi_fixup_inquiry (request);
+    return ret;
+}
+
+void scsi_log_before (uae_u8 *cdb, int cdblen, uae_u8 *data, int datalen)
+{
+    int i;
+    for (i = 0; i < cdblen; i++) {
+        write_log("%s%02.2X", i > 0 ? "." : "", cdb[i]);
+    }
+    write_log("\n");
+    if (data) {
+       write_log ("DATAOUT: %d\n", datalen);
+        for (i = 0; i < datalen && i < 100; i++)
+           write_log("%s%02.2X", i > 0 ? "." : "", data[i]);
+        if (datalen > 0)
+           write_log("\n");
+    }
+}
+
+void scsi_log_after (uae_u8 *data, int datalen, uae_u8 *sense, int senselen)
+{
+    int i;
+    if (data) {
+       write_log ("DATAIN: %d\n", datalen);
+       for (i = 0; i < datalen && i < 100; i++)
+           write_log("%s%02.2X", i > 0 ? "." : "", data[i]);
+       if (datalen > 0)
+           write_log("\n");
+    }
+    if (senselen > 0) {
+        write_log("SENSE: ");
+        for (i = 0; i < senselen && i < 32; i++) {
+           write_log("%s%02.2X", i > 0 ? "." : "", sense[i]);
+       }
+       write_log("\n");
+    }
+}
diff --git a/bsdsocket.c b/bsdsocket.c
new file mode 100755 (executable)
index 0000000..63dd7c7
--- /dev/null
@@ -0,0 +1,1408 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * bsdsocket.library emulation machine-independent part
+  *
+  * Copyright 1997, 1998 Mathias Ortmann
+  *
+  * Library initialization code (c) Tauno Taipaleenmaki
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <assert.h>
+#include <stddef.h>
+
+#include "config.h"
+#include "options.h"
+#include "memory.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "autoconf.h"
+#include "bsdsocket.h"
+#include "osdep/exectasks.h"
+
+#ifdef BSDSOCKET
+
+static uae_u32 SockLibBase;
+
+#define SOCKPOOLSIZE 128
+#define UNIQUE_ID      (-1)
+
+/* ObtainSocket()/ReleaseSocket() public socket pool */
+long sockpoolids[SOCKPOOLSIZE];
+int sockpoolsocks[SOCKPOOLSIZE];
+uae_u32 sockpoolflags[SOCKPOOLSIZE];
+
+long curruniqid = 65536;
+
+/* Memory-related helper functions */
+static void memcpyha (uae_u32 dst, char *src, int size)
+{
+    while (size--)
+       put_byte (dst++, *src++);
+}
+
+char *strncpyah (char *dst, uae_u32 src, int size)
+{
+    char *res = dst;
+    while (size-- && (*dst++ = get_byte (src++)));
+    return res;
+}
+
+char *strcpyah (char *dst, uae_u32 src)
+{
+    char *res = dst;
+    while ((*dst++ = get_byte (src++)) != 0);
+    return res;
+}
+
+uae_u32 strcpyha (uae_u32 dst, char *src)
+{
+    uae_u32 res = dst;
+
+    do {
+       put_byte (dst++, *src);
+    } while (*src++);
+
+    return res;
+}
+
+uae_u32 strncpyha (uae_u32 dst, char *src, int size)
+{
+    uae_u32 res = dst;
+    while (size--) {
+       put_byte (dst++, *src);
+       if (!*src++)
+           return res;
+    }
+    return res;
+}
+
+uae_u32 addstr (uae_u32 * dst, char *src)
+{
+    uae_u32 res = *dst;
+    int len;
+
+    len = strlen (src) + 1;
+
+    strcpyha (*dst, src);
+    (*dst) += len;
+
+    return res;
+}
+
+uae_u32 addmem (uae_u32 * dst, char *src, int len)
+{
+    uae_u32 res = *dst;
+
+    if (!src)
+       return 0;
+
+    memcpyha (*dst, src, len);
+    (*dst) += len;
+
+    return res;
+}
+
+/* Get current task */
+static uae_u32 gettask (void)
+{
+    uae_u32 currtask, a1 = m68k_areg (regs, 1);
+
+    m68k_areg (regs, 1) = 0;
+    currtask = CallLib (get_long (4), -0x126); /* FindTask */
+
+    m68k_areg (regs, 1) = a1;
+
+    TRACE (("[%s] ", get_real_address (get_long (currtask + 10))));
+    return currtask;
+}
+
+/* errno/herrno setting */
+void seterrno (SB, int sb_errno)
+{
+    sb->sb_errno = sb_errno;                   
+       
+       if (sb->sb_errno >= 1001 && sb->sb_errno <= 1005) setherrno(sb,sb->sb_errno-1000);
+
+    if (sb->errnoptr) {
+       switch (sb->errnosize) {
+        case 1:
+           put_byte (sb->errnoptr, sb_errno);
+           break;
+        case 2:
+           put_word (sb->errnoptr, sb_errno);
+           break;
+        case 4:
+           put_long (sb->errnoptr, sb_errno);
+       }
+    }
+}
+
+void setherrno (SB, int sb_herrno)
+{
+    sb->sb_herrno = sb_herrno;
+
+    if (sb->herrnoptr) {
+       switch (sb->herrnosize) {
+        case 1:
+           put_byte (sb->herrnoptr, sb_herrno);
+           break;
+        case 2:
+           put_word (sb->herrnoptr, sb_herrno);
+           break;
+        case 4:
+           put_long (sb->herrnoptr, sb_herrno);
+       }
+    }
+}
+
+BOOL checksd(SB, int sd)
+       {
+       int iCounter;
+       SOCKET s;
+
+    s = getsock(sb,sd);
+    if (s != INVALID_SOCKET)
+               {
+               for (iCounter  = 1; iCounter <= sb->dtablesize; iCounter++)
+                       {
+                       if (iCounter != sd)
+                               {
+                               if (getsock(sb,iCounter) == s)
+                                       {
+                                       releasesock(sb,sd);
+                                       return TRUE;
+                                       }
+                               }
+                       }
+               for (iCounter  = 0; iCounter < SOCKPOOLSIZE; iCounter++)
+                       {
+                       if (s == sockpoolsocks[iCounter])
+                               return TRUE;
+                       }
+               }
+       TRACE(("checksd FALSE s 0x%x sd %d\n",s,sd));
+       return FALSE;
+       }
+void setsd(SB, int sd, int s)
+       {
+    sb->dtable[sd - 1] = s;
+       }
+
+/* Socket descriptor/opaque socket handle management */
+int getsd (SB, int s)
+{
+    int i;
+    int *dt = sb->dtable;
+
+    /* return socket descriptor if already exists */
+    for (i = sb->dtablesize; i--;)
+       if (dt[i] == s)
+           return i + 1;
+
+    /* create new table entry */
+    for (i = 0; i < sb->dtablesize; i++)
+       if (dt[i] == -1) {
+           dt[i] = s;
+           sb->ftable[i] = SF_BLOCKING;
+               return i + 1;
+               }
+    /* descriptor table full. */
+    seterrno (sb, 24);         /* EMFILE */
+
+    return -1;
+}
+
+int getsock (SB, int sd)
+{
+    if ((unsigned int) (sd - 1) >= (unsigned int) sb->dtablesize) {
+       TRACE (("Invalid Socket Descriptor (%d)\n", sd));
+       seterrno (sb, 38);      /* ENOTSOCK */
+
+       return -1;
+    }
+    return sb->dtable[sd - 1];
+}
+
+void releasesock (SB, int sd)
+{
+    if ((unsigned int) (sd - 1) < (unsigned int) sb->dtablesize)
+       sb->dtable[sd - 1] = -1;
+}
+
+/* Signal queue */
+/* @@@ TODO: ensure proper interlocking */
+struct socketbase *sbsigqueue;
+
+void addtosigqueue (SB, int events)
+{
+    locksigqueue ();
+
+    if (events)
+       sb->sigstosend |= sb->eventsigs;
+    else
+       sb->sigstosend |= ((uae_u32) 1) << sb->signal;
+
+    if (!sb->dosignal) {
+       sb->nextsig = sbsigqueue;
+       sbsigqueue = sb;
+    }
+    sb->dosignal = 1;
+
+    unlocksigqueue ();
+
+    INTREQ (0xA000);
+}
+
+static uae_u32 bsdsock_int_handler (void)
+{
+    SB;
+
+    if (sbsigqueue != NULL) {
+       locksigqueue ();
+
+       for (sb = sbsigqueue; sb; sb = sb->nextsig) {
+           if (sb->dosignal == 1) {
+               struct regstruct sbved_regs = regs;
+               m68k_areg (regs, 1) = sb->ownertask;
+               m68k_dreg (regs, 0) = sb->sigstosend;
+               CallLib (get_long (4), -0x144);         /* Signal() */
+
+               regs = sbved_regs;
+
+               sb->sigstosend = 0;
+           }
+           sb->dosignal = 0;
+       }
+
+       sbsigqueue = NULL;
+       unlocksigqueue ();
+    }
+    return 0;
+}
+
+void waitsig (SB)
+{
+    long sigs;
+    m68k_dreg (regs, 0) = (((uae_u32) 1) << sb->signal) | sb->eintrsigs;
+    if ((sigs = CallLib (get_long (4), -0x13e)) & sb->eintrsigs) {
+       sockabort (sb); 
+       seterrno (sb, 4);       /* EINTR */
+
+       // Set signal
+       m68k_dreg (regs, 0) = sigs;
+       m68k_dreg (regs, 1) = sb->eintrsigs;
+       sigs = CallLib (get_long (4), -0x132);  /* SetSignal() */
+
+       sb->eintr = 1;
+    } else
+       sb->eintr = 0;
+}
+
+void cancelsig (SB)
+{
+    locksigqueue ();
+    if (sb->dosignal)
+       sb->dosignal = 2;
+    unlocksigqueue ();
+
+    m68k_dreg (regs, 0) = 0;
+    m68k_dreg (regs, 1) = ((uae_u32) 1) << sb->signal;
+    CallLib (get_long (4), -0x132);    /* SetSignal() */
+
+}
+
+/* Allocate and initialize per-task state structure */
+static struct socketbase *alloc_socketbase (void)
+{
+    SB;
+    int i;
+
+    if ((sb = calloc (sizeof (struct socketbase), 1)) != NULL) {
+       sb->ownertask = gettask ();
+
+       m68k_dreg (regs, 0) = -1;
+       sb->signal = CallLib (get_long (4), -0x14A);
+
+       if (sb->signal == -1) {
+           write_log ("bsdsocket: ERROR: Couldn't allocate signal for task 0x%lx.\n", sb->ownertask);
+           free (sb);
+           return NULL;
+       }
+       m68k_dreg (regs, 0) = SCRATCHBUFSIZE;
+       m68k_dreg (regs, 1) = 0;
+
+       sb->dtablesize = DEFAULT_DTABLE_SIZE;
+       /* @@@ check malloc() result */
+       sb->dtable = malloc (sb->dtablesize * sizeof (*sb->dtable));
+       sb->ftable = malloc (sb->dtablesize * sizeof (*sb->ftable));
+
+       for (i = sb->dtablesize; i--;)
+           sb->dtable[i] = -1;
+
+       sb->eintrsigs = 0x1000; /* SIGBREAKF_CTRL_C */
+
+       if (!host_sbinit (sb)) {
+           /* @@@ free everything   */
+       }
+       if (socketbases)
+           sb->next = socketbases;
+       socketbases = sb;
+
+       return sb;
+    }
+    return NULL;
+}
+
+struct socketbase *get_socketbase (void)
+{
+    /* @@@ make portable for sizeof(void *) != sizeof(uae_u32) */
+    return (struct socketbase *) get_long (m68k_areg (regs, 6) + offsetof (struct UAEBSDBase, sb));
+}
+
+static void free_socketbase (void)
+{
+    struct socketbase *sb, *nsb;
+
+    if ((sb = get_socketbase ()) != NULL) {
+       m68k_dreg (regs, 0) = sb->signal;
+       CallLib (get_long (4), -0x150);         /* FreeSignal */
+
+       if (sb->hostent) {
+           m68k_areg (regs, 1) = sb->hostent;
+           m68k_dreg (regs, 0) = sb->hostentsize;
+           CallLib (get_long (4), -0xD2);      /* FreeMem */
+
+       }
+       if (sb->protoent) {
+           m68k_areg (regs, 1) = sb->protoent;
+           m68k_dreg (regs, 0) = sb->protoentsize;
+           CallLib (get_long (4), -0xD2);      /* FreeMem */
+
+       }
+       if (sb->servent) {
+           m68k_areg (regs, 1) = sb->servent;
+           m68k_dreg (regs, 0) = sb->serventsize;
+           CallLib (get_long (4), -0xD2);      /* FreeMem */
+
+       }
+       host_sbcleanup (sb);
+
+       free (sb->dtable);
+       free (sb->ftable);
+
+       locksigqueue ();
+
+       if (sb == socketbases)
+           socketbases = sb->next;
+       else {
+           for (nsb = socketbases; nsb; nsb = nsb->next) {
+               if (sb == nsb->next) {
+                   nsb->next = sb->next;
+                   break;
+               }
+           }
+       }
+
+       if (sb == sbsigqueue)
+           sbsigqueue = sb->next;
+       else {
+           for (nsb = sbsigqueue; nsb; nsb = nsb->next) {
+               if (sb == nsb->next) {
+                   nsb->next = sb->next;
+                   break;
+               }
+           }
+       }
+
+       unlocksigqueue ();
+
+       free (sb);
+    }
+}
+
+static uae_u32 bsdsocklib_Expunge (void)
+{
+    TRACE (("Expunge() -> [ignored]\n"));
+    return 0;
+}
+
+static uae_u32 functable, datatable, inittable;
+
+#define SOCKETBASE get_socketbase()
+
+static uae_u32 bsdsocklib_Open (void)
+{
+    uae_u32 result = 0;
+    int opencount;
+    SB;
+
+    locksigqueue ();
+
+    TRACE (("OpenLibrary() -> "));
+
+    if ((sb = alloc_socketbase ()) != NULL) {
+       put_word (SockLibBase + 32, opencount = get_word (SockLibBase + 32) + 1);
+
+       m68k_areg (regs, 0) = functable;
+       m68k_areg (regs, 1) = datatable;
+       m68k_areg (regs, 2) = 0;
+       m68k_dreg (regs, 0) = sizeof (struct UAEBSDBase);
+       m68k_dreg (regs, 1) = 0;
+       result = CallLib (get_long (4), -0x54);
+
+       /* @@@ make portable for sizeof(void *) != sizeof(uae_u32) */
+       put_long (result + offsetof (struct UAEBSDBase, sb), (uae_u32) sb);
+
+       TRACE (("%0lx [%d]\n", result, opencount));
+    } else
+       TRACE (("failed (out of memory)\n"));
+
+    unlocksigqueue ();
+
+    return result;
+}
+
+static uae_u32 bsdsocklib_Close (void)
+{
+    int opencount;
+
+    uae_u32 base = m68k_areg (regs, 6);
+    uae_u32 negsize = get_word (base + 16);
+
+    free_socketbase ();
+
+    put_word (SockLibBase + 32, opencount = get_word (SockLibBase + 32) - 1);
+
+    m68k_areg (regs, 1) = base - negsize;
+    m68k_dreg (regs, 0) = negsize + get_word (base + 18);
+    CallLib (get_long (4), -0xD2);     /* FreeMem */
+
+    TRACE (("CloseLibrary() -> [%d]\n", opencount));
+
+    return 0;
+}
+
+/* socket(domain, type, protocol)(d0/d1/d2) */
+static uae_u32 bsdsocklib_socket (void)
+{
+    return host_socket (SOCKETBASE, m68k_dreg (regs, 0), m68k_dreg (regs, 1),
+                       m68k_dreg (regs, 2));
+}
+
+/* bind(s, name, namelen)(d0/a0/d1) */
+static uae_u32 bsdsocklib_bind (void)
+{
+    return host_bind (SOCKETBASE, m68k_dreg (regs, 0), m68k_areg (regs, 0),
+                     m68k_dreg (regs, 1));
+       }
+
+/* listen(s, backlog)(d0/d1) */
+static uae_u32 bsdsocklib_listen (void)
+{
+    return host_listen (SOCKETBASE, m68k_dreg (regs, 0), m68k_dreg (regs, 1));
+}
+
+/* accept(s, addr, addrlen)(d0/a0/a1) */
+static uae_u32 bsdsocklib_accept (void)
+{
+    SB = get_socketbase ();
+    host_accept (sb, m68k_dreg (regs, 0), m68k_areg (regs, 0), m68k_areg (regs, 1));
+    return sb->resultval;
+}
+
+/* connect(s, name, namelen)(d0/a0/d1) */
+static uae_u32 bsdsocklib_connect (void)
+{
+    SB = get_socketbase ();
+    host_connect (sb, m68k_dreg (regs, 0), m68k_areg (regs, 0), m68k_dreg (regs, 1));
+    return sb->sb_errno ? -1 : 0;
+}
+
+/* sendto(s, msg, len, flags, to, tolen)(d0/a0/d1/d2/a1/d3) */
+static uae_u32 bsdsocklib_sendto (void)
+{
+    SB = get_socketbase ();
+    host_sendto (sb, m68k_dreg (regs, 0), m68k_areg (regs, 0), m68k_dreg (regs, 1),
+                m68k_dreg (regs, 2), m68k_areg (regs, 1), m68k_dreg (regs, 3));
+    return sb->resultval;
+}
+
+/* send(s, msg, len, flags)(d0/a0/d1/d2) */
+static uae_u32 bsdsocklib_send (void)
+{
+    SB = get_socketbase ();
+    host_sendto (sb, m68k_dreg (regs, 0), m68k_areg (regs, 0), m68k_dreg (regs, 1),
+                m68k_dreg (regs, 2), 0, 0);
+    return sb->resultval;
+}
+
+/* recvfrom(s, buf, len, flags, from, fromlen)(d0/a0/d1/d2/a1/a2) */
+static uae_u32 bsdsocklib_recvfrom (void)
+{
+    SB = get_socketbase ();
+    host_recvfrom (sb, m68k_dreg (regs, 0), m68k_areg (regs, 0), m68k_dreg (regs, 1),
+                  m68k_dreg (regs, 2), m68k_areg (regs, 1), m68k_areg (regs, 2));
+    return sb->resultval;
+}
+
+/* recv(s, buf, len, flags)(d0/a0/d1/d2) */
+static uae_u32 bsdsocklib_recv (void)
+{
+    SB = get_socketbase ();
+    host_recvfrom (sb, m68k_dreg (regs, 0), m68k_areg (regs, 0), m68k_dreg (regs, 1),
+                  m68k_dreg (regs, 2), 0, 0);
+    return sb->resultval;
+}
+
+/* shutdown(s, how)(d0/d1) */
+static uae_u32 bsdsocklib_shutdown (void)
+{
+    return host_shutdown (SOCKETBASE, m68k_dreg (regs, 0), m68k_dreg (regs, 1));
+}
+
+/* setsockopt(s, level, optname, optval, optlen)(d0/d1/d2/a0/d3) */
+static uae_u32 bsdsocklib_setsockopt (void)
+{
+    SB = get_socketbase ();
+    host_setsockopt (sb, m68k_dreg (regs, 0), m68k_dreg (regs, 1), m68k_dreg (regs, 2),
+                    m68k_areg (regs, 0), m68k_dreg (regs, 3));
+    return sb->resultval;
+}
+
+/* getsockopt(s, level, optname, optval, optlen)(d0/d1/d2/a0/a1) */
+static uae_u32 bsdsocklib_getsockopt (void)
+{
+    return host_getsockopt (SOCKETBASE, m68k_dreg (regs, 0), m68k_dreg (regs, 1), m68k_dreg (regs, 2),
+                           m68k_areg (regs, 0), m68k_areg (regs, 1));
+}
+
+/* getsockname(s, hostname, namelen)(d0/a0/a1) */
+static uae_u32 bsdsocklib_getsockname (void)
+{
+    return host_getsockname (SOCKETBASE, m68k_dreg (regs, 0), m68k_areg (regs, 0), m68k_areg (regs, 1));
+}
+
+/* getpeername(s, hostname, namelen)(d0/a0/a1) */
+static uae_u32 bsdsocklib_getpeername (void)
+{
+    return host_getpeername (SOCKETBASE, m68k_dreg (regs, 0), m68k_areg (regs, 0), m68k_areg (regs, 1));
+}
+
+/* *------ generic system calls related to sockets */
+/* IoctlSocket(d, request, argp)(d0/d1/a0) */
+static uae_u32 bsdsocklib_IoctlSocket (void)
+{
+    return host_IoctlSocket (SOCKETBASE, m68k_dreg (regs, 0), m68k_dreg (regs, 1), m68k_areg (regs, 0));
+}
+
+/* *------ AmiTCP/IP specific stuff */
+/* CloseSocket(d)(d0) */
+static uae_u32 bsdsocklib_CloseSocket (void)
+{
+    return host_CloseSocket (SOCKETBASE, m68k_dreg (regs, 0));
+}
+
+/* WaitSelect(nfds, readfds, writefds, execptfds, timeout, maskp)(d0/a0/a1/a2/a3/d1) */
+static uae_u32 bsdsocklib_WaitSelect (void)
+{
+    SB = get_socketbase ();
+    host_WaitSelect (sb, m68k_dreg (regs, 0), m68k_areg (regs, 0), m68k_areg (regs, 1),
+                    m68k_areg (regs, 2), m68k_areg (regs, 3), m68k_dreg (regs, 1));
+    return sb->resultval;
+}
+
+/* SetSocketSignals(SIGINTR, SIGIO, SIGURG)(d0/d1/d2) */
+static uae_u32 bsdsocklib_SetSocketSignals (void)
+{
+    SB = get_socketbase ();
+
+    TRACE (("SetSocketSignals(0x%08lx,0x%08lx,0x%08lx) -> ", m68k_dreg (regs, 0), m68k_dreg (regs, 1), m68k_dreg (regs, 2)));
+    sb->eintrsigs = m68k_dreg (regs, 0);
+    sb->eventsigs = m68k_dreg (regs, 1);
+
+    return 0;
+}
+
+/* SetDTableSize(size)(d0) */
+static uae_u32 bsdsocklib_SetDTableSize (void)
+{
+    write_log ("bsdsocket: UNSUPPORTED: SetDTableSize()\n");
+    return 0;
+}
+
+static int sockpoolindex (long id)
+{
+    int i;
+
+    for (i = 0; i < SOCKPOOLSIZE; i++)
+       if (sockpoolids[i] == id)
+           return i;
+
+    return -1;
+}
+
+/* ObtainSocket(id, domain, type, protocol)(d0/d1/d2/d3) */
+static uae_u32 bsdsocklib_ObtainSocket (void)
+{
+    SB = SOCKETBASE;
+    int sd;
+    long id;
+    int s;
+    int i;
+
+    id = m68k_dreg (regs, 0);
+
+    TRACE (("ObtainSocket(%d,%d,%d,%d) -> ", id, m68k_dreg (regs, 1), m68k_dreg (regs, 2), m68k_dreg (regs, 3)));
+
+    i = sockpoolindex (id);
+
+    if (i == -1) {
+       TRACE (("[invalid key]\n"));
+       return -1;
+    }
+    s = sockpoolsocks[i];
+
+    sd = getsd (sb, s);
+
+    sb->ftable[sd - 1] = sockpoolflags[i];
+
+    TRACE (("%d\n", sd));
+
+    sockpoolids[i] = UNIQUE_ID;
+
+    return sd-1;
+}
+
+/* ReleaseSocket(fd, id)(d0/d1) */
+static uae_u32 bsdsocklib_ReleaseSocket (void)
+{
+    SB = SOCKETBASE;
+    int sd;
+    long id;
+    int s;
+    int i;
+    uae_u32 flags;
+
+    sd = m68k_dreg (regs, 0);
+    id = m68k_dreg (regs, 1);
+       
+       sd++;
+    TRACE (("ReleaseSocket(%d,%d) -> ", sd, id));
+
+    s = getsock (sb, sd);
+
+    if (s != -1) {
+       flags = sb->ftable[sd - 1];
+
+       if (flags & REP_ALL) {
+           write_log ("bsdsocket: ERROR: ReleaseSocket() is not supported for sockets with async event notification enabled!\n");
+           return -1;
+       }
+       releasesock (sb, sd);
+
+       if (id == UNIQUE_ID) {
+           for (;;) {
+               if (sockpoolindex (curruniqid) == -1)
+                   break;
+               curruniqid += 129;
+               if ((unsigned long) (curruniqid + 1) < 65536)
+                   curruniqid += 65537;
+           }
+
+           id = curruniqid;
+       } else if (id < 0 && id > 65535) {
+           if (sockpoolindex (id) != -1) {
+               TRACE (("[unique ID already exists]\n"));
+               return -1;
+           }
+       }
+       i = sockpoolindex (-1);
+
+       if (i == -1) {
+           TRACE (("-1\n"));
+           write_log (("bsdsocket: ERROR: Global socket pool overflow\n"));
+           return -1;
+       }
+       sockpoolids[i] = id;
+       sockpoolsocks[i] = s;
+       sockpoolflags[i] = flags;
+
+       TRACE (("id %d s 0x%x\n", id,s));
+    } else {
+       TRACE (("[invalid socket descriptor]\n"));
+       return -1;
+    }
+
+    return id;
+}
+
+/* ReleaseCopyOfSocket(fd, id)(d0/d1) */
+static uae_u32 bsdsocklib_ReleaseCopyOfSocket (void)
+{
+    write_log ("bsdsocket: UNSUPPORTED: ReleaseCopyOfSocket()\n");
+    return 0;
+}
+
+/* Errno()() */
+static uae_u32 bsdsocklib_Errno (void)
+{
+    SB = get_socketbase ();
+    TRACE (("Errno() -> %d\n", sb->sb_errno));
+    return sb->sb_errno;
+}
+
+/* SetErrnoPtr(errno_p, size)(a0/d0) */
+static uae_u32 bsdsocklib_SetErrnoPtr (void)
+{
+    SB = get_socketbase ();
+    uae_u32 errnoptr = m68k_areg (regs, 0), size = m68k_dreg (regs, 0);
+
+    TRACE (("SetErrnoPtr(0x%lx,%d) -> ", errnoptr, size));
+
+    if (size == 1 || size == 2 || size == 4) {
+       sb->errnoptr = errnoptr;
+       sb->errnosize = size;
+       TRACE (("OK\n"));
+       return 0;
+    }
+    seterrno (sb, 22);         /* EINVAL */
+
+    return -1;
+}
+
+/* *------ inet library calls related to inet address manipulation */
+/* Inet_NtoA(in)(d0) */
+static uae_u32 bsdsocklib_Inet_NtoA (void)
+{
+    return host_Inet_NtoA (SOCKETBASE, m68k_dreg (regs, 0));
+}
+
+/* inet_addr(cp)(a0) */
+static uae_u32 bsdsocklib_inet_addr (void)
+{
+    return host_inet_addr (m68k_areg (regs, 0));
+}
+
+/* Inet_LnaOf(in)(d0) */
+static uae_u32 bsdsocklib_Inet_LnaOf (void)
+{
+    write_log ("bsdsocket: UNSUPPORTED: Inet_LnaOf()\n");
+    return 0;
+}
+
+/* Inet_NetOf(in)(d0) */
+static uae_u32 bsdsocklib_Inet_NetOf (void)
+{
+    write_log ("bsdsocket: UNSUPPORTED: Inet_NetOf()\n");
+    return 0;
+}
+
+/* Inet_MakeAddr(net, host)(d0/d1) */
+static uae_u32 bsdsocklib_Inet_MakeAddr (void)
+{
+    write_log ("bsdsocket: UNSUPPORTED: Inet_MakeAddr()\n");
+    return 0;
+}
+
+/* inet_network(cp)(a0) */
+static uae_u32 bsdsocklib_inet_network (void)
+{
+    return host_inet_addr (m68k_areg (regs, 0));
+}
+
+/* *------ gethostbyname etc */
+/* gethostbyname(name)(a0) */
+static uae_u32 bsdsocklib_gethostbyname (void)
+{
+    SB = get_socketbase ();
+    host_gethostbynameaddr (sb, m68k_areg (regs, 0), 0, -1);
+    return sb->sb_errno ? 0 : sb->hostent;
+}
+
+/* gethostbyaddr(addr, len, type)(a0/d0/d1) */
+static uae_u32 bsdsocklib_gethostbyaddr (void)
+{
+    SB = get_socketbase ();
+    host_gethostbynameaddr (sb, m68k_areg (regs, 0), m68k_dreg (regs, 0), m68k_dreg (regs, 1));
+    return sb->sb_errno ? 0 : sb->hostent;
+}
+
+/* getnetbyname(name)(a0) */
+static uae_u32 bsdsocklib_getnetbyname (void)
+{
+    write_log ("bsdsocket: UNSUPPORTED: getnetbyname()\n");
+    return 0;
+}
+
+/* getnetbyaddr(net, type)(d0/d1) */
+static uae_u32 bsdsocklib_getnetbyaddr (void)
+{
+    write_log ("bsdsocket: UNSUPPORTED: getnetbyaddr()\n");
+    return 0;
+}
+
+/* getservbyname(name, proto)(a0/a1) */
+static uae_u32 bsdsocklib_getservbyname (void)
+{
+    SB = get_socketbase ();
+    host_getservbynameport (sb, m68k_areg (regs, 0), m68k_areg (regs, 1), 0);
+    return sb->sb_errno ? 0 : sb->servent;
+}
+
+/* getservbyport(port, proto)(d0/a0) */
+static uae_u32 bsdsocklib_getservbyport (void)
+{
+    SB = get_socketbase ();
+    host_getservbynameport (sb, m68k_dreg (regs, 0), m68k_areg (regs, 0), 1);
+    return sb->sb_errno ? 0 : sb->servent;
+}
+
+/* getprotobyname(name)(a0) */
+static uae_u32 bsdsocklib_getprotobyname (void)
+{
+    SB = get_socketbase ();
+    host_getprotobyname (sb, m68k_areg (regs, 0));
+    return sb->sb_errno ? 0 : sb->protoent;
+}
+
+/* getprotobynumber(proto)(d0)  */
+static uae_u32 bsdsocklib_getprotobynumber (void)
+{
+    write_log ("bsdsocket: UNSUPPORTED: getprotobynumber()\n");
+    return 0;
+}
+
+/* *------ syslog functions */
+/* Syslog(level, format, ap)(d0/a0/a1) */
+static uae_u32 bsdsocklib_vsyslog (void)
+{
+    write_log ("bsdsocket: UNSUPPORTED: vsyslog()\n");
+    return 0;
+}
+
+/* *------ AmiTCP/IP 1.1 extensions */
+/* Dup2Socket(fd1, fd2)(d0/d1) */
+static uae_u32 bsdsocklib_Dup2Socket (void)
+{
+    return host_dup2socket (SOCKETBASE, m68k_dreg (regs, 0), m68k_dreg (regs, 1));
+}
+
+static uae_u32 bsdsocklib_sendmsg (void)
+{
+    write_log ("bsdsocket: UNSUPPORTED: sendmsg()\n");
+    return 0;
+}
+
+static uae_u32 bsdsocklib_recvmsg (void)
+{
+    write_log ("bsdsocket: UNSUPPORTED: recvmsg()\n");
+    return 0;
+}
+
+static uae_u32 bsdsocklib_gethostname (void)
+{
+    return host_gethostname (m68k_areg (regs, 0), m68k_dreg (regs, 0));
+}
+
+static uae_u32 bsdsocklib_gethostid (void)
+{
+    write_log ("bsdsocket: WARNING: Process '%s' calls deprecated function gethostid() - returning 127.0.0.1\n", get_real_address (get_long (gettask () + 10)));
+    return 0x7f000001;
+}
+
+char *errortexts[] =
+{"No error", "Operation not permitted", "No such file or directory",
+ "No such process", "Interrupted system call", "Input/output error", "Device not configured",
+ "Argument list too long", "Exec format error", "Bad file descriptor", "No child processes",
+ "Resource deadlock avoided", "Cannot allocate memory", "Permission denied", "Bad address",
+ "Block device required", "Device busy", "Object exists", "Cross-device link",
+ "Operation not supported by device", "Not a directory", "Is a directory", "Invalid argument",
+ "Too many open files in system", "Too many open files", "Inappropriate ioctl for device",
+ "Text file busy", "File too large", "No space left on device", "Illegal seek",
+ "Read-only file system", "Too many links", "Broken pipe", "Numerical argument out of domain",
+ "Result too large", "Resource temporarily unavailable", "Operation now in progress",
+ "Operation already in progress", "Socket operation on non-socket", "Destination address required",
+ "Message too long", "Protocol wrong type for socket", "Protocol not available",
+ "Protocol not supported", "Socket type not supported", "Operation not supported",
+ "Protocol family not supported", "Address family not supported by protocol family",
+ "Address already in use", "Can't assign requested address", "Network is down",
+ "Network is unreachable", "Network dropped connection on reset", "Software caused connection abort",
+ "Connection reset by peer", "No buffer space available", "Socket is already connected",
+ "Socket is not connected", "Can't send after socket shutdown", "Too many references: can't splice",
+ "Connection timed out", "Connection refused", "Too many levels of symbolic links",
+ "File name too long", "Host is down", "No route to host", "Directory not empty",
+ "Too many processes", "Too many users", "Disc quota exceeded", "Stale NFS file handle",
+ "Too many levels of remote in path", "RPC struct is bad", "RPC version wrong",
+ "RPC prog. not avail", "Program version wrong", "Bad procedure for program", "No locks available",
+ "Function not implemented", "Inappropriate file type or format", "PError 0"};
+
+uae_u32 errnotextptrs[sizeof (errortexts) / sizeof (*errortexts)];
+uae_u32 number_sys_error = sizeof (errortexts) / sizeof (*errortexts);
+
+
+char *herrortexts[] =
+ {"No error", "Unknown host", "Host name lookup failure", "Unknown server error",
+ "No address associated with name"};
+
+uae_u32 herrnotextptrs[sizeof (herrortexts) / sizeof (*herrortexts)];
+uae_u32 number_host_error = sizeof (herrortexts) / sizeof (*herrortexts);
+
+static const char * const strErr = "Errlist lookup error"; 
+uae_u32 strErrptr;
+
+
+#define TAG_DONE   (0L)                /* terminates array of TagItems. ti_Data unused */
+#define        TAG_IGNORE (1L)         /* ignore this item, not end of array               */
+#define        TAG_MORE   (2L)         /* ti_Data is pointer to another array of TagItems */
+#define        TAG_SKIP   (3L)         /* skip this and the next ti_Data items     */
+#define TAG_USER   ((uae_u32)(1L<<31))
+
+#define SBTF_VAL 0x0000
+#define SBTF_REF 0x8000
+#define SBTB_CODE 1
+#define SBTS_CODE 0x3FFF
+#define SBTM_CODE(tag) ((((UWORD)(tag))>>SBTB_CODE) & SBTS_CODE)
+#define SBTF_GET  0x0
+#define SBTF_SET  0x1
+#define SBTM_GETREF(code) \
+ (TAG_USER | SBTF_REF | (((code) & SBTS_CODE) << SBTB_CODE))
+#define SBTM_GETVAL(code) (TAG_USER | (((code) & SBTS_CODE) << SBTB_CODE))
+#define SBTM_SETREF(code) \
+ (TAG_USER | SBTF_REF | (((code) & SBTS_CODE) << SBTB_CODE) | SBTF_SET)
+#define SBTM_SETVAL(code) \
+ (TAG_USER | (((code) & SBTS_CODE) << SBTB_CODE) | SBTF_SET)
+#define SBTC_BREAKMASK      1
+#define SBTC_SIGIOMASK      2
+#define SBTC_SIGURGMASK     3
+#define SBTC_SIGEVENTMASK   4
+#define SBTC_ERRNO          6
+#define SBTC_HERRNO         7
+#define SBTC_DTABLESIZE     8
+#define SBTC_FDCALLBACK     9
+#define SBTC_LOGSTAT        10
+#define SBTC_LOGTAGPTR      11
+#define SBTC_LOGFACILITY    12
+#define SBTC_LOGMASK        13
+#define SBTC_ERRNOSTRPTR    14 /* <sys/errno.h> */
+#define SBTC_HERRNOSTRPTR   15 /* <netdb.h> */
+#define SBTC_IOERRNOSTRPTR  16 /* <exec/errors.h> */
+#define SBTC_S2ERRNOSTRPTR  17 /* <devices/sana2.h> */
+#define SBTC_S2WERRNOSTRPTR 18 /* <devices/sana2.h> */
+#define SBTC_ERRNOBYTEPTR   21
+#define SBTC_ERRNOWORDPTR   22
+#define SBTC_ERRNOLONGPTR   24
+#define SBTC_HERRNOLONGPTR  25
+#define SBTC_RELEASESTRPTR  29
+
+static void tagcopy (uae_u32 currtag, uae_u32 currval, uae_u32 tagptr, uae_u32 * ptr)
+{
+    switch (currtag & 0x8001) {
+     case 0x0000:              /* SBTM_GETVAL */
+
+       put_long (tagptr + 4, *ptr);
+       break;
+     case 0x8000:              /* SBTM_GETREF */
+
+       put_long (currval, *ptr);
+       break;
+     case 0x0001:              /* SBTM_SETVAL */
+
+       *ptr = currval;
+       break;
+     default:                  /* SBTM_SETREF */
+
+       *ptr = get_long (currval);
+    }
+}
+
+static uae_u32 bsdsocklib_SocketBaseTagList (void)
+{
+    SB = SOCKETBASE;
+    uae_u32 tagptr = m68k_areg (regs, 0);
+    uae_u32 tagsprocessed = 1;
+    uae_u32 currtag;
+    uae_u32 currval;
+
+    TRACE (("SocketBaseTagList("));
+
+    for (;;) {
+       currtag = get_long (tagptr);
+       currval = get_long (tagptr + 4);
+       tagsprocessed++;
+
+       switch (currtag) {
+        case TAG_DONE:
+           TRACE (("TAG_DONE"));
+           tagsprocessed = 0;
+           goto done;
+        case TAG_IGNORE:
+           TRACE (("TAG_IGNORE"));
+           break;
+        case TAG_MORE:
+           TRACE (("TAG_MORE(0x%lx)", currval));
+           tagptr = currval;
+           break;
+        case TAG_SKIP:
+           TRACE (("TAG_SKIP(%d)", currval));
+           tagptr += currval * 8;
+           break;
+
+        default:
+           if (currtag & TAG_USER) {
+               TRACE (("SBTM_"));
+               TRACE ((currtag & 0x0001 ? "SET" : "GET"));
+               TRACE ((currtag & 0x8000 ? "REF(" : "VAL("));
+
+               switch ((currtag >> 1) & SBTS_CODE) {
+                case SBTC_BREAKMASK:
+                   TRACE (("SBTC_BREAKMASK),0x%lx", currval));
+                   tagcopy (currtag, currval, tagptr, &sb->eintrsigs);
+                   break;
+                case SBTC_SIGEVENTMASK:
+                   TRACE (("SBTC_SIGEVENTMASK),0x%lx", currval));
+                   tagcopy (currtag, currval, tagptr, &sb->eventsigs);
+                   break;
+                case SBTC_SIGIOMASK:
+                   TRACE (("SBTC_SIGEVENTMASK),0x%lx", currval));
+                   tagcopy (currtag, currval, tagptr, &sb->eventsigs);
+                   break;
+                case SBTC_ERRNO:
+                   TRACE (("SBTC_ERRNO),%d", currval));
+                   tagcopy (currtag, currval, tagptr, &sb->sb_errno);
+                   break;
+                case SBTC_HERRNO:
+                   TRACE (("SBTC_HERRNO),%d", currval));
+                   tagcopy (currtag, currval, tagptr, &sb->sb_herrno);
+                   break;
+                case SBTC_ERRNOSTRPTR:
+                   if (currtag & 1) {
+                       TRACE (("ERRNOSTRPTR),invalid"));
+                   } else {
+                       unsigned long ulTmp;
+                       if (currtag & 0x8000)
+                               { /* SBTM_GETREF */
+                               ulTmp = get_long(currval);
+                               }
+                       else
+                               { /* SBTM_GETVAL */
+                               ulTmp = currval;
+                               }
+                       TRACE (("ERRNOSTRPTR),%d", ulTmp));
+                       if (ulTmp < number_sys_error)
+                               { 
+                               tagcopy (currtag, currval, tagptr, &errnotextptrs[ulTmp]);
+                               }
+                       else
+                               {
+                               tagcopy (currtag, currval, tagptr, &strErrptr);
+                               }
+                   }
+                   break;
+                case SBTC_HERRNOSTRPTR:
+                   if (currtag & 1) {
+                       TRACE (("HERRNOSTRPTR),invalid"));
+                   } else {
+                       unsigned long ulTmp;
+                       if (currtag & 0x8000)
+                               { /* SBTM_GETREF */
+                               ulTmp = get_long(currval);
+                               }
+                       else
+                               { /* SBTM_GETVAL */
+                               ulTmp = currval;
+                               }
+                       TRACE (("HERRNOSTRPTR),%d", ulTmp));
+                       if (ulTmp < number_host_error)
+                               {
+                               tagcopy (currtag, currval, tagptr, &herrnotextptrs[ulTmp]);
+                               }
+                       else
+                               {
+                               tagcopy (currtag, currval, tagptr, &strErrptr);
+                               }
+                   }
+                   break;
+                case SBTC_ERRNOBYTEPTR:
+                   TRACE (("SBTC_ERRNOBYTEPTR),0x%lx", currval));
+                   tagcopy (currtag, currval, tagptr, &sb->errnoptr);
+                   sb->errnosize = 1;
+                   break;
+                case SBTC_ERRNOWORDPTR:
+                   TRACE (("SBTC_ERRNOWORDPTR),0x%lx", currval));
+                   tagcopy (currtag, currval, tagptr, &sb->errnoptr);
+                   sb->errnosize = 2;
+                   break;
+                case SBTC_ERRNOLONGPTR:
+                   TRACE (("SBTC_ERRNOLONGPTR),0x%lx", currval));
+                   tagcopy (currtag, currval, tagptr, &sb->errnoptr);
+                   sb->errnosize = 4;
+                   break;
+                case SBTC_HERRNOLONGPTR:
+                   TRACE (("SBTC_HERRNOLONGPTR),0x%lx", currval));
+                   tagcopy (currtag, currval, tagptr, &sb->herrnoptr);
+                   sb->herrnosize = 4;
+                   break;
+                default:
+                   write_log ("bsdsocket: WARNING: Unsupported tag type (%x) in SocketBaseTagList()\n", currtag);
+               }
+           } else {
+               TRACE (("TAG_UNKNOWN(0x%x)", currtag));
+           }
+       }
+
+       TRACE ((","));
+       tagptr += 8;
+    }
+
+  done:
+    TRACE ((") -> %d\n", tagsprocessed));
+
+    return tagsprocessed;
+}
+
+static uae_u32 bsdsocklib_GetSocketEvents (void)
+{
+    SB = SOCKETBASE;
+    int i;
+    int flags;
+    uae_u32 ptr = m68k_areg (regs, 0);
+
+    TRACE (("GetSocketEvents(0x%x) -> ", ptr));
+
+    for (i = sb->dtablesize; i--; sb->eventindex++) {
+       if (sb->eventindex >= sb->dtablesize)
+           sb->eventindex = 0;
+
+       if (sb->mtable[sb->eventindex]) {
+           flags = sb->ftable[sb->eventindex] & SET_ALL;
+           if (flags) {
+               sb->ftable[sb->eventindex] &= ~SET_ALL;
+               put_long (m68k_areg (regs, 0), flags >> 8);
+               TRACE (("%d (0x%x)\n", sb->eventindex + 1, flags >> 8));
+               return sb->eventindex; // xxx
+           }
+       }
+    }
+
+    TRACE (("-1\n"));
+    return -1;
+}
+
+static uae_u32 bsdsocklib_getdtablesize (void)
+{
+    return get_socketbase ()->dtablesize;
+}
+
+static uae_u32 bsdsocklib_null (void)
+{
+    return 0;
+}
+
+extern uae_u32 sockfuncvecs[];
+
+static uae_u32 bsdsocklib_init (void)
+{
+    uae_u32 tmp1;
+    int i;
+    write_log ("Creating UAE bsdsocket.library 4.1\n");
+    if (SockLibBase)
+       bsdlib_reset ();
+
+    m68k_areg (regs, 0) = functable;
+    m68k_areg (regs, 1) = datatable;
+    m68k_areg (regs, 2) = 0;
+    m68k_dreg (regs, 0) = LIBRARY_SIZEOF;
+    m68k_dreg (regs, 1) = 0;
+    tmp1 = CallLib (m68k_areg (regs, 6), -0x54);
+
+    if (!tmp1) {
+       write_log ("bsdoscket: FATAL: Cannot create bsdsocket.library!\n");
+       return 0;
+    }
+    m68k_areg (regs, 1) = tmp1;
+    CallLib (m68k_areg (regs, 6), -0x18c);
+    SockLibBase = tmp1;
+#if 0
+    m68k_areg (regs, 1) = ds ("dos.library");
+    m68k_dreg (regs, 0) = 0;
+    dosbase = CallLib (m68k_areg (regs, 6), -552);
+    printf ("%08lx\n", dosbase);
+#endif
+
+    /* Install error strings in Amiga memory */
+       tmp1 = 0;
+    for (i = number_sys_error; i--;)
+               tmp1 += strlen (errortexts[i])+1;
+
+       for (i = number_host_error; i--;)
+               tmp1 += strlen (herrortexts[i])+1;
+
+       tmp1 += strlen(strErr)+1;
+
+    m68k_dreg (regs, 0) = tmp1;
+    m68k_dreg (regs, 1) = 0;
+    tmp1 = CallLib (get_long (4), -0xC6);
+
+    if (!tmp1) {
+       write_log ("bsdsocket: FATAL: Ran out of memory while creating bsdsocket.library!\n");
+       return 0;
+    }
+    for (i = 0; i < (int) (number_sys_error); i++)
+               errnotextptrs[i] = addstr (&tmp1, errortexts[i]);
+
+       for (i = 0; i < (int) (number_host_error); i++)
+               herrnotextptrs[i] = addstr (&tmp1, herrortexts[i]);
+
+       strErrptr = addstr (&tmp1, strErr);
+
+    /* @@@ someone please implement a proper interrupt handler setup here :) */
+    tmp1 = here ();
+    calltrap (deftrap2 (bsdsock_int_handler, TRAPFLAG_EXTRA_STACK | TRAPFLAG_NO_RETVAL, ""));
+    dw (0x4ef9);
+    dl (get_long (regs.vbr + 0x78));
+    put_long (regs.vbr + 0x78, tmp1);
+
+    m68k_dreg (regs, 0) = 1;
+    return 0;
+}
+
+void bsdlib_reset (void)
+{
+    SB, *nsb;
+    int i;
+
+    SockLibBase = 0;
+
+    for (sb = socketbases; sb; sb = nsb) {
+       nsb = sb->next;
+
+       host_sbcleanup (sb);
+
+       free (sb->dtable);
+       free (sb->ftable);
+
+       free (sb);
+    }
+
+    socketbases = NULL;
+    sbsigqueue = NULL;
+
+    for (i = 0; i < SOCKPOOLSIZE; i++) {
+       if (sockpoolids[i] != UNIQUE_ID) {
+           sockpoolids[i] = UNIQUE_ID;
+           host_closesocketquick (sockpoolsocks[i]);
+       }
+    }
+
+    host_sbreset ();
+}
+
+uae_u32 (*sockfuncs[])(void) = {
+    bsdsocklib_init, bsdsocklib_Open, bsdsocklib_Close, bsdsocklib_Expunge,
+    bsdsocklib_socket, bsdsocklib_bind, bsdsocklib_listen, bsdsocklib_accept,
+    bsdsocklib_connect, bsdsocklib_sendto, bsdsocklib_send, bsdsocklib_recvfrom, bsdsocklib_recv,
+    bsdsocklib_shutdown, bsdsocklib_setsockopt, bsdsocklib_getsockopt, bsdsocklib_getsockname,
+    bsdsocklib_getpeername, bsdsocklib_IoctlSocket, bsdsocklib_CloseSocket, bsdsocklib_WaitSelect,
+    bsdsocklib_SetSocketSignals, bsdsocklib_SetDTableSize, bsdsocklib_ObtainSocket, bsdsocklib_ReleaseSocket,
+    bsdsocklib_ReleaseCopyOfSocket, bsdsocklib_Errno, bsdsocklib_SetErrnoPtr, bsdsocklib_Inet_NtoA,
+    bsdsocklib_inet_addr, bsdsocklib_Inet_LnaOf, bsdsocklib_Inet_NetOf, bsdsocklib_Inet_MakeAddr,
+    bsdsocklib_inet_network, bsdsocklib_gethostbyname, bsdsocklib_gethostbyaddr, bsdsocklib_getnetbyname,
+    bsdsocklib_getnetbyaddr, bsdsocklib_getservbyname, bsdsocklib_getservbyport, bsdsocklib_getprotobyname,
+    bsdsocklib_getprotobynumber, bsdsocklib_vsyslog, bsdsocklib_Dup2Socket, bsdsocklib_sendmsg,
+    bsdsocklib_recvmsg, bsdsocklib_gethostname, bsdsocklib_gethostid, bsdsocklib_SocketBaseTagList,
+    bsdsocklib_GetSocketEvents
+};
+
+uae_u32 sockfuncvecs[sizeof (sockfuncs) / sizeof (*sockfuncs)];
+
+void bsdlib_install (void)
+{
+    uae_u32 resname, resid;
+    uae_u32 begin, end;
+    uae_u32 func_place, data_place, init_place;
+    int i;
+
+    if (!init_socket_layer ())
+       return;
+
+    memset (sockpoolids, UNIQUE_ID, sizeof (sockpoolids));
+
+    resname = ds ("bsdsocket.library");
+    resid = ds ("UAE bsdsocket.library 4.1");
+
+    begin = here ();
+    dw (0x4AFC);               /* RT_MATCHWORD */
+    dl (begin);                        /* RT_MATCHTAG */
+    dl (0);                    /* RT_ENDSKIP */
+    dw (0x8004);               /* RTF_AUTOINIT, RT_VERSION */
+    dw (0x0970);               /* NT_LIBRARY, RT_PRI */
+    dl (resname);              /* RT_NAME */
+    dl (resid);                        /* RT_IDSTRING */
+    dl (here () + 4);          /* RT_INIT */
+    dl (512);
+    func_place = here ();
+    dl (0);
+    data_place = here ();
+    dl (0);
+    init_place = here ();
+    dl (0);
+
+    for (i = 0; i < (int) (sizeof (sockfuncs) / sizeof (sockfuncs[0])); i++) {
+       sockfuncvecs[i] = here ();
+       calltrap (deftrap2 (sockfuncs[i], TRAPFLAG_EXTRA_STACK, ""));
+       dw (RTS);
+    }
+
+    /* FuncTable */
+    functable = here ();
+    for (i = 1; i < 4; i++)
+       dl (sockfuncvecs[i]);   /* Open / Close / Expunge */
+    dl (EXPANSION_nullfunc);   /* Null */
+    for (i = 4; i < (int) (sizeof (sockfuncs) / sizeof (sockfuncs[0])); i++)
+       dl (sockfuncvecs[i]);
+    dl (0xFFFFFFFF);           /* end of table */
+
+    /* DataTable */
+    datatable = here ();
+    dw (0xE000);               /* INITBYTE */
+    dw (0x0008);               /* LN_TYPE */
+    dw (0x0900);               /* NT_LIBRARY */
+    dw (0xC000);               /* INITLONG */
+    dw (0x000A);               /* LN_NAME */
+    dl (resname);
+    dw (0xE000);               /* INITBYTE */
+    dw (0x000E);               /* LIB_FLAGS */
+    dw (0x0600);               /* LIBF_SUMUSED | LIBF_CHANGED */
+    dw (0xD000);               /* INITWORD */
+    dw (0x0014);               /* LIB_VERSION */
+    dw (0x0004);
+    dw (0xD000);
+    dw (0x0016);               /* LIB_REVISION */
+    dw (0x0001);
+    dw (0xC000);
+    dw (0x0018);               /* LIB_IDSTRING */
+    dl (resid);
+    dl (0x00000000);           /* end of table */
+
+    end = here ();
+
+    org (begin + 6);           /* Load END value */
+    dl (end);
+
+    org (data_place);
+    dl (datatable);
+
+    org (func_place);
+    dl (functable);
+
+    org (init_place);
+    dl (*sockfuncvecs);
+
+    org (end);
+}
+
+#endif /* ! BSDSOCKET */
diff --git a/build68k.c b/build68k.c
new file mode 100755 (executable)
index 0000000..13848b2
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * Read 68000 CPU specs from file "table68k" and build table68k.c
+ *
+ * Copyright 1995,1996 Bernd Schmidt
+ */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <assert.h>
+#include <ctype.h>
+
+#include "readcpu.h"
+
+static FILE *tablef;
+static int nextch = 0;
+
+static void getnextch(void)
+{
+    do {
+       nextch = fgetc(tablef);
+       if (nextch == '%') {
+           do {
+               nextch = fgetc(tablef);
+           } while (nextch != EOF && nextch != '\n');
+       }
+    } while (nextch != EOF && isspace(nextch));
+}
+
+static int nextchtohex(void)
+{
+    switch (isupper (nextch) ? tolower (nextch) : nextch) {
+     case '0': return 0;
+     case '1': return 1;
+     case '2': return 2;
+     case '3': return 3;
+     case '4': return 4;
+     case '5': return 5;
+     case '6': return 6;
+     case '7': return 7;
+     case '8': return 8;
+     case '9': return 9;
+     case 'a': return 10;
+     case 'b': return 11;
+     case 'c': return 12;
+     case 'd': return 13;
+     case 'e': return 14;
+     case 'f': return 15;
+     default: abort();
+    }
+}
+
+int main(int argc, char **argv)
+{
+    int no_insns = 0;
+
+    printf ("#include \"sysconfig.h\"\n");
+    printf ("#include \"sysdeps.h\"\n");
+    printf ("#include \"readcpu.h\"\n");
+    printf ("struct instr_def defs68k[] = {\n");
+#if 0
+    tablef = fopen("table68k","r");
+    if (tablef == NULL) {
+       fprintf(stderr, "table68k not found\n");
+       exit(1);
+    }
+#else
+    tablef = stdin;
+#endif
+    getnextch();
+    while (nextch != EOF) {
+       int cpulevel, plevel, sduse;
+       int i;
+
+       char patbits[16];
+       char opcstr[256];
+       int bitpos[16];
+       int flagset[5], flaguse[5];
+
+       unsigned int bitmask,bitpattern;
+       int n_variable;
+
+       n_variable = 0;
+       bitmask = bitpattern = 0;
+       memset (bitpos, 0, sizeof(bitpos));
+       for(i=0; i<16; i++) {
+           int currbit;
+           bitmask <<= 1;
+           bitpattern <<= 1;
+
+           switch (nextch) {
+            case '0': currbit = bit0; bitmask |= 1; break;
+            case '1': currbit = bit1; bitmask |= 1; bitpattern |= 1; break;
+            case 'c': currbit = bitc; break;
+            case 'C': currbit = bitC; break;
+            case 'f': currbit = bitf; break;
+            case 'i': currbit = biti; break;
+            case 'I': currbit = bitI; break;
+            case 'j': currbit = bitj; break;
+            case 'J': currbit = bitJ; break;
+            case 'k': currbit = bitk; break;
+            case 'K': currbit = bitK; break;
+            case 's': currbit = bits; break;
+            case 'S': currbit = bitS; break;
+            case 'd': currbit = bitd; break;
+            case 'D': currbit = bitD; break;
+            case 'r': currbit = bitr; break;
+            case 'R': currbit = bitR; break;
+            case 'z': currbit = bitz; break;
+            case 'p': currbit = bitp; break;
+            default: abort();
+           }
+           if (!(bitmask & 1)) {
+               bitpos[n_variable] = currbit;
+               n_variable++;
+           }
+
+           if (nextch == '0' || nextch == '1')
+               bitmask |= 1;
+           if (nextch == '1')
+               bitpattern |= 1;
+           patbits[i] = nextch;
+           getnextch();
+       }
+
+       while (isspace(nextch) || nextch == ':') /* Get CPU and privilege level */
+           getnextch();
+
+       switch (nextch) {
+        case '0': cpulevel = 0; break;
+        case '1': cpulevel = 1; break;
+        case '2': cpulevel = 2; break;
+        case '3': cpulevel = 3; break;
+        case '4': cpulevel = 4; break;
+        case '5': cpulevel = 5; break;
+        case '6': cpulevel = 6; break;
+        case '7': cpulevel = 7; break;
+        default: abort();
+       }
+       getnextch();
+
+       switch (nextch) {
+        case '0': plevel = 0; break;
+        case '1': plevel = 1; break;
+        case '2': plevel = 2; break;
+        case '3': plevel = 3; break;
+        default: abort();
+       }
+       getnextch();
+
+       while (isspace(nextch))                   /* Get flag set information */
+           getnextch();
+
+       if (nextch != ':')
+           abort();
+
+       for(i = 0; i < 5; i++) {
+           getnextch();
+           switch(nextch){
+            case '-': flagset[i] = fa_unset; break;
+            case '/': flagset[i] = fa_isjmp; break;
+            case '+': flagset[i] = fa_isbranch; break;
+            case '0': flagset[i] = fa_zero; break;
+            case '1': flagset[i] = fa_one; break;
+            case 'x': flagset[i] = fa_dontcare; break;
+            case '?': flagset[i] = fa_unknown; break;
+            default: flagset[i] = fa_set; break;
+           }
+       }
+
+       getnextch();
+       while (isspace(nextch))
+           getnextch();
+
+       if (nextch != ':')                        /* Get flag used information */
+           abort();
+
+       for(i = 0; i < 5; i++) {
+           getnextch();
+           switch(nextch){
+            case '-': flaguse[i] = fu_unused; break;
+            case '/': flaguse[i] = fu_isjmp; break;
+            case '+': flaguse[i] = fu_maybecc; break;
+            case '?': flaguse[i] = fu_unknown; break;
+            default: flaguse[i] = fu_used; break;
+           }
+       }
+
+       getnextch();
+       while (isspace(nextch))
+           getnextch();
+
+       if (nextch != ':')                        /* Get source/dest usage information */
+           abort();
+
+       getnextch();
+       sduse = nextchtohex() << 4;
+       getnextch();
+       sduse |= nextchtohex();
+
+       getnextch();
+       while (isspace(nextch))
+           getnextch();
+
+       if (nextch != ':')
+           abort();
+
+       fgets(opcstr, 250, tablef);
+       getnextch();
+       {
+           int j;
+           /* Remove superfluous spaces from the string */
+           char *opstrp = opcstr, *osendp;
+           int slen = 0;
+
+           while (isspace(*opstrp))
+               opstrp++;
+
+           osendp = opstrp;
+           while (*osendp) {
+               if (!isspace (*osendp))
+                   slen = osendp - opstrp + 1;
+               osendp++;
+           }
+           opstrp[slen] = 0;
+
+           if (no_insns > 0)
+               printf(",\n");
+           no_insns++;
+           printf("{ %d, %d, {", bitpattern, n_variable);
+           for (j = 0; j < 16; j++) {
+               printf("%d", bitpos[j]);
+               if (j < 15)
+                   printf(",");
+           }
+           printf ("}, %d, %d, %d, { ", bitmask, cpulevel, plevel);
+           for(i = 0; i < 5; i++) {
+               printf("{ %d, %d }%c ", flaguse[i], flagset[i], i == 4 ? ' ' : ',');
+           }
+           printf("}, %d, \"%s\"}", sduse, opstrp);
+       }
+    }
+    printf("};\nint n_defs68k = %d;\n", no_insns);
+    return 0;
+}
diff --git a/catweasel.c b/catweasel.c
new file mode 100755 (executable)
index 0000000..e35370b
--- /dev/null
@@ -0,0 +1,777 @@
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#ifdef CATWEASEL
+
+#include "config.h"
+#include "options.h"
+#include "memory.h"
+#include "ioport.h"
+#include "catweasel.h"
+#include "uae.h"
+
+struct catweasel_contr cwc;
+
+static int cwhsync;
+static int handshake;
+
+void catweasel_hsync (void)
+{
+    if (cwhsync <= 0)
+       return;
+    cwhsync--;
+    if (cwhsync == 0) {
+        if (handshake)
+           ioport_write (currprefs.catweasel_io + 0xd0, 0);
+       handshake = 0;
+    }
+}
+
+int catweasel_read_joystick (uae_u8 *dir, uae_u8 *buttons)
+{
+    if (cwc.type != CATWEASEL_TYPE_MK3)
+       return 0;
+    *dir = ioport_read (currprefs.catweasel_io + 0xc0);
+    *buttons = ioport_read (currprefs.catweasel_io + 0xc8);
+    return 1;
+}
+
+int catweasel_read_keyboard (uae_u8 *keycode)
+{
+    uae_u8 v;
+    if (cwc.type != CATWEASEL_TYPE_MK3)
+       return 0;
+    v = ioport_read (currprefs.catweasel_io + 0xd4);
+    if (!(v & 0x80))
+       return 0;
+    if (handshake)
+       return 0;
+    *keycode = ioport_read (currprefs.catweasel_io + 0xd0);
+    ioport_write (currprefs.catweasel_io + 0xd0, 0);
+    handshake = 1;
+    cwhsync = 10;
+    return 1;
+}
+
+uae_u32 catweasel_do_bget (uaecptr addr)
+{
+    if (cwc.type == CATWEASEL_TYPE_MK3) {
+       if ((currprefs.catweasel_io & 3) == 0 && addr >= 0xc0 && addr <= 0xfc)
+           return ioport_read (currprefs.catweasel_io + addr);
+    } else {
+       if (addr >= currprefs.catweasel_io && addr <= currprefs.catweasel_io + 8) {
+           return ioport_read (addr & 0x3ff);
+       } else if(addr >= 0x10000 + currprefs.catweasel_io && addr <= 0x10000 + currprefs.catweasel_io) {
+           return ioport_read (addr & 0x3ff);
+       } else if ((addr & 0x3ff) < 0x200 || (addr & 0x3ff) >= 0x400) {
+           write_log("catweasel_bget @%08.8X!\n",addr);
+       }
+    }
+    return 0;
+}
+
+void catweasel_do_bput (uaecptr addr, uae_u32 b)
+{
+    if (cwc.type == CATWEASEL_TYPE_MK3) {
+       if ((currprefs.catweasel_io & 3) == 0 && addr >= 0xc0 && addr <= 0xfc)
+           ioport_write (currprefs.catweasel_io + addr, b);
+    } else {
+       if (addr >= currprefs.catweasel_io && addr <= currprefs.catweasel_io + 8) {
+           ioport_write (addr & 0x3ff, b);
+       } else if(addr >= 0x10000 + currprefs.catweasel_io && addr <= 0x10000 + currprefs.catweasel_io) {
+           ioport_write (addr & 0x3ff, b);
+       } else if ((addr & 0x3ff) < 0x200 || (addr & 0x3ff) >= 0x400) {
+           write_log("catweasel_bput @%08.8X=%02.2X!\n",addr,b);
+       }
+    }
+}
+
+int catweasel_init (void)
+{
+    if (!currprefs.catweasel_io)
+       return 0;
+    if (!ioport_init ())
+       return 0;
+    cwc.type = currprefs.catweasel_io >= 0x400 ? CATWEASEL_TYPE_MK3 : CATWEASEL_TYPE_MK1;
+    cwc.iobase = currprefs.catweasel_io;
+    catweasel_init_controller (&cwc);
+    return 1;
+}
+
+void catweasel_free (void)
+{
+    if (!currprefs.catweasel_io)
+       return;
+    ioport_free ();
+}
+
+#define outb(v,port) ioport_write(port,v)
+#define inb(port) ioport_read(port)
+
+#define LONGEST_TRACK 16000
+
+static uae_u8 mfmbuf[LONGEST_TRACK * 4];
+static uae_u8 tmpmfmbuffer[LONGEST_TRACK * 2];
+
+static int bitshiftcompare(uae_u8 *src,int bit,int len,uae_u8 *comp)
+{
+       uae_u8 b;
+       int ones,zeros,len2;
+
+       ones=zeros=0;
+       len2=len;
+       while(len--) {
+               b = (comp[0] << bit) | (comp[1] >> (8 - bit));
+               if(b != *src) return 1;
+               if(b==0x00) zeros++;
+               if(b==0xff) ones++;
+               src++;
+               comp++;
+       }
+       if(ones==len2||zeros==len2) return 1;
+       return 0;
+}
+
+static uae_u8 *mergepieces(uae_u8 *start,int len,int bits,uae_u8 *sync)
+{
+       uae_u8 *dst=tmpmfmbuffer;
+       uae_u8 b;
+       int size;
+       int shift;
+       
+       size=len-(sync-start);
+       memcpy(dst,sync,size);
+       dst+=size;
+       b=start[len];
+       b&=~(255>>bits);
+       b|=start[0]>>bits;
+       *dst++=b;
+       shift=8-bits;
+       while(start<=sync+2000) {
+               *dst++=(start[0]<<shift)|(start[1]>>(8-shift));
+               start++;
+       }
+       return tmpmfmbuffer;
+}      
+               
+#define SCANOFFSET 1 /* scanning range in bytes, -SCANOFFSET to SCANOFFSET */
+#define SCANOFFSET2 20
+#define SCANLENGHT 200 /* scanning length in bytes */
+
+static uae_u8* scantrack(uae_u8 *sync1,uae_u8 *sync2,int *trackbytes,int *trackbits)
+{
+       int i,bits,bytes,matched;
+       uae_u8 *sync2bak=sync2;
+       
+       sync1+=SCANOFFSET2;
+       sync2+=SCANOFFSET2;
+       while(sync1 < sync2bak - 2*SCANOFFSET - SCANOFFSET2 - SCANLENGHT) {
+               matched=0x7fff;
+               for(i=0;i<2*SCANOFFSET*8;i++) {
+                       bits=i&7;
+                       bytes=-SCANOFFSET+(i>>3);
+                       if(!bitshiftcompare(sync1,bits,SCANLENGHT,sync2+bytes)) {
+                               if(matched==0x7fff) {
+                                       matched=i;
+                               } else {
+                                       break;
+                               }
+                       }
+               }
+               if(matched!=0x7fff && i>=2*SCANOFFSET*8) {
+                       bits=matched&7;
+                       bytes=-SCANOFFSET+(matched>>3);
+                       *trackbytes=sync2+bytes-sync1;
+                       *trackbits=bits;
+                       return mergepieces(sync1,*trackbytes,*trackbits,sync2bak);
+               }
+               sync1++;
+               sync2++;
+       }
+       return 0;
+}      
+
+static unsigned char threshtab[128];
+
+static void codec_makethresh(int trycnt, const unsigned char *origt, unsigned char *t, int numthresh)
+{
+    static unsigned char tab[10] = { 0, 0, 0, 0, -1, -2, 1, 2, -1, 1 };
+
+    if (trycnt >= sizeof (tab))
+       trycnt = sizeof (tab) - 1;
+    while(numthresh--)
+       t[numthresh] = origt[numthresh] + tab[trycnt];
+}
+
+static void codec_init_threshtab(int trycnt, const unsigned char *origt)
+{
+    static unsigned char old_thresholds[2] = { 0, 0 };
+    unsigned char t[2];
+    int a, i;
+
+    codec_makethresh(trycnt, origt, t, 2);
+
+    if(*(unsigned short*)t == *(unsigned short*)old_thresholds)
+       return;
+
+    for(i=0,a=2; i<128; i++) {
+       if(i == t[0] || i == t[1])
+           a++;
+       threshtab[i] = a;
+    }
+
+    *(unsigned short*)&old_thresholds = *(unsigned short*)t;
+}
+
+static __inline__ void CWSetCReg(catweasel_contr *c, unsigned char clear, unsigned char set)
+{
+    c->control_register = (c->control_register & ~clear) | set;
+    outb(c->control_register, c->io_sr);
+}
+
+static void CWTriggerStep(catweasel_contr *c)
+{
+    CWSetCReg(c, c->crm_step, 0);
+    CWSetCReg(c, 0, c->crm_step);
+}
+
+void catweasel_init_controller(catweasel_contr *c)
+{
+    int i, j;
+
+    if(!c->iobase)
+       return;
+
+    switch(c->type) {
+    case CATWEASEL_TYPE_MK1:
+       c->crm_sel0 = 1 << 5;
+       c->crm_sel1 = 1 << 4;
+       c->crm_mot0 = 1 << 3;
+       c->crm_mot1 = 1 << 7;
+       c->crm_dir  = 1 << 1;
+       c->crm_step = 1 << 0;
+       c->srm_trk0 = 1 << 4;
+       c->srm_dchg = 1 << 5;
+       c->srm_writ = 1 << 1;
+       c->io_sr    = c->iobase + 2;
+       c->io_mem   = c->iobase;
+       break;
+    case CATWEASEL_TYPE_MK3:
+       c->crm_sel0 = 1 << 2;
+       c->crm_sel1 = 1 << 3;
+       c->crm_mot0 = 1 << 1;
+       c->crm_mot1 = 1 << 5;
+       c->crm_dir  = 1 << 4;
+       c->crm_step = 1 << 7;
+       c->srm_trk0 = 1 << 2;
+       c->srm_dchg = 1 << 5;
+       c->srm_writ = 1 << 6;
+       c->srm_dskready = 1 << 4;
+       c->io_sr    = c->iobase + 0xe8;
+       c->io_mem   = c->iobase + 0xe0;
+       break;
+    default:
+       return; 
+    }
+
+    c->control_register = 255;
+
+    /* select all drives, step inside */
+    CWSetCReg(c, c->crm_dir | c->crm_sel0 | c->crm_sel1, 0);
+    for(i=0;i<2;i++) {
+       c->drives[i].number = i;
+       c->drives[i].contr = c;
+       c->drives[i].diskindrive = 0;
+       
+       /* select only the respective drive, step to track 0 */
+       if(i == 0) {
+           CWSetCReg(c, c->crm_sel0, c->crm_dir | c->crm_sel1);
+       } else {
+           CWSetCReg(c, c->crm_sel1, c->crm_dir | c->crm_sel0);
+       }
+
+       for(j = 0; j < 86 && (inb(c->io_sr) & c->srm_trk0); j++) {
+           CWTriggerStep(c);
+           sleep_millis(6);
+       }
+       
+       if(j < 86) {
+           c->drives[i].type = 1;
+           c->drives[i].track = 0;
+       } else {
+           c->drives[i].type = 0;
+       }
+    }
+    c->drives[0].sel = c->crm_sel0;
+    c->drives[0].mot = c->crm_mot0;
+    c->drives[1].sel = c->crm_sel1;
+    c->drives[1].mot = c->crm_mot1;
+    CWSetCReg(c, 0, c->crm_sel0 | c->crm_sel1); /* deselect all drives */
+}
+
+void catweasel_free_controller(catweasel_contr *c)
+{
+    if(!c->iobase)
+       return;
+
+    /* all motors off, deselect all drives */
+    CWSetCReg(c, 0, c->crm_mot0 | c->crm_mot1 | c->crm_sel0 | c->crm_sel1);
+}
+
+void catweasel_set_motor(catweasel_drive *d, int on)
+{
+    CWSetCReg(d->contr, d->sel, 0);
+    if (on)
+       CWSetCReg(d->contr, d->mot, 0);
+    else
+       CWSetCReg(d->contr, 0, d->mot);
+    CWSetCReg(d->contr, 0, d->sel);
+}
+
+int catweasel_step(catweasel_drive *d, int dir)
+{
+    catweasel_contr *c = d->contr;
+    CWSetCReg(c, d->sel, 0);
+    if (dir > 0)
+       CWSetCReg(c, c->crm_dir, 0);
+    else
+       CWSetCReg(c, 0, c->crm_dir);
+    CWTriggerStep (c);
+    CWSetCReg(c, 0, d->sel);
+    d->track += dir > 0 ? 1 : -1;
+    return 1;
+}
+
+int catweasel_disk_changed(catweasel_drive *d)
+{
+    int ret;
+    CWSetCReg(d->contr, d->sel, 0);
+    ret = (inb(d->contr->io_sr) & d->contr->srm_dchg) ? 0 : 1;
+    CWSetCReg(d->contr, 0, d->sel);
+    return ret;
+}
+
+int catweasel_diskready(catweasel_drive *d)
+{
+    int ret;
+    CWSetCReg(d->contr, d->sel, 0);
+    ret = (inb(d->contr->io_sr) & d->contr->srm_dskready) ? 0 : 1;
+    CWSetCReg(d->contr, 0, d->sel);
+    return ret;
+}
+
+int catweasel_track0(catweasel_drive *d)
+{
+    int ret;
+    CWSetCReg(d->contr, d->sel, 0);
+    ret = (inb(d->contr->io_sr) & d->contr->srm_trk0) ? 0 : 1;
+    CWSetCReg(d->contr, 0, d->sel);
+    if (ret)
+       d->track = 0;
+    return ret;
+}
+
+int catweasel_write_protected(catweasel_drive *d)
+{
+    int ret;
+    CWSetCReg(d->contr, d->sel, 0);
+    ret = !(inb(d->contr->io_sr) & 8);
+    CWSetCReg(d->contr, 0, d->sel);
+    return ret;
+}
+
+uae_u8 catweasel_read_byte(catweasel_drive *d)
+{
+    return inb(d->contr->io_mem);
+}
+
+static const unsigned char amiga_thresholds[] = { 0x22, 0x30 }; // 27, 38 for 5.25"
+
+#define FLOPPY_WRITE_LEN 6250
+
+#define MFMMASK 0x55555555
+static uae_u32 getmfmlong (uae_u16 * mbuf)
+{
+       return (uae_u32)(((*mbuf << 16) | *(mbuf + 1)) & MFMMASK);
+}
+
+static int drive_write_adf_amigados (uae_u16 *mbuf, uae_u16 *mend, uae_u8 *writebuffer, int track)
+{
+       int i, secwritten = 0;
+       uae_u32 odd, even, chksum, id, dlong;
+       uae_u8 *secdata;
+       uae_u8 secbuf[544];
+       char sectable[22];
+       int num_sectors = 11;
+       int ec = 0;
+
+       memset (sectable, 0, sizeof (sectable));
+       mend -= (4 + 16 + 8 + 512);
+       while (secwritten < num_sectors) {
+               int trackoffs;
+
+               do {
+                       while (*mbuf++ != 0x4489) {
+                           if (mbuf >= mend) {
+                               ec = 1;
+                               goto err;
+                           }
+                       }
+               } while (*mbuf++ != 0x4489);
+
+               odd = getmfmlong (mbuf);
+               even = getmfmlong (mbuf + 2);
+               mbuf += 4;
+               id = (odd << 1) | even;
+
+               trackoffs = (id & 0xff00) >> 8;
+               if (trackoffs > 10) {
+                   ec = 2;
+                   goto err;
+               }
+               chksum = odd ^ even;
+               for (i = 0; i < 4; i++) {
+                       odd = getmfmlong (mbuf);
+                       even = getmfmlong (mbuf + 8);
+                       mbuf += 2;
+
+                       dlong = (odd << 1) | even;
+                       if (dlong) {
+                           ec = 6;
+                           goto err;
+                       }
+                       chksum ^= odd ^ even;
+               } /* could check here if the label is nonstandard */
+               mbuf += 8;
+               odd = getmfmlong (mbuf);
+               even = getmfmlong (mbuf + 2);
+               mbuf += 4;
+               if (((odd << 1) | even) != chksum) {
+                   ec = 3;
+                   goto err;
+               }
+               odd = (id & 0x00ff0000) >> 16;
+               if (odd != track) {
+                   ec = 7;
+                   goto err;
+               }
+               odd = getmfmlong (mbuf);
+               even = getmfmlong (mbuf + 2);
+               mbuf += 4;
+               chksum = (odd << 1) | even;
+               secdata = secbuf + 32;
+               for (i = 0; i < 128; i++) {
+                       odd = getmfmlong (mbuf);
+                       even = getmfmlong (mbuf + 256);
+                       mbuf += 2;
+                       dlong = (odd << 1) | even;
+                       *secdata++ = dlong >> 24;
+                       *secdata++ = dlong >> 16;
+                       *secdata++ = dlong >> 8;
+                       *secdata++ = dlong;
+                       chksum ^= odd ^ even;
+               }
+               mbuf += 256;
+               if (chksum) {
+                   ec = 4;
+                   goto err;
+               }
+               sectable[trackoffs] = 1;
+               secwritten++;
+               memcpy (writebuffer + trackoffs * 512, secbuf + 32, 512);
+       }
+       if (secwritten == 0 || secwritten < 0) {
+           ec = 5;
+           goto err;
+       }
+       return 0;
+err:
+       write_log ("mfm decode error %d. secwritten=%d\n", ec, secwritten);
+       for (i = 0; i < num_sectors; i++)
+           write_log ("%d:%d ", i, sectable[i]);
+       write_log ("\n");
+       return ec;
+}
+
+static void mfmcode (uae_u16 * mfm, int words)
+{
+    uae_u32 lastword = 0;
+
+    while (words--) {
+       uae_u32 v = *mfm;
+       uae_u32 lv = (lastword << 16) | v;
+       uae_u32 nlv = 0x55555555 & ~lv;
+       uae_u32 mfmbits = (nlv << 1) & (nlv >> 1);
+
+       *mfm++ = v | mfmbits;
+       lastword = v;
+    }
+}
+
+#define FLOPPY_GAP_LEN 360
+
+static int amigados_mfmcode (uae_u8 *src, uae_u16 *dst, int num_secs, int track)
+{
+       int sec;
+       memset (dst, 0xaa, FLOPPY_GAP_LEN * 2);
+
+       for (sec = 0; sec < num_secs; sec++) {
+           uae_u8 secbuf[544];
+           int i;
+           uae_u16 *mfmbuf = dst + 544 * sec + FLOPPY_GAP_LEN;
+           uae_u32 deven, dodd;
+           uae_u32 hck = 0, dck = 0;
+
+           secbuf[0] = secbuf[1] = 0x00;
+           secbuf[2] = secbuf[3] = 0xa1;
+           secbuf[4] = 0xff;
+           secbuf[5] = track;
+           secbuf[6] = sec;
+           secbuf[7] = num_secs - sec;
+
+           for (i = 8; i < 24; i++)
+               secbuf[i] = 0;
+
+           mfmbuf[0] = mfmbuf[1] = 0xaaaa;
+           mfmbuf[2] = mfmbuf[3] = 0x4489;
+
+           memcpy (secbuf + 32, src + sec * 512, 512);
+           deven = ((secbuf[4] << 24) | (secbuf[5] << 16)
+                    | (secbuf[6] << 8) | (secbuf[7]));
+           dodd = deven >> 1;
+           deven &= 0x55555555;
+           dodd &= 0x55555555;
+
+           mfmbuf[4] = dodd >> 16;
+           mfmbuf[5] = dodd;
+           mfmbuf[6] = deven >> 16;
+           mfmbuf[7] = deven;
+
+           for (i = 8; i < 48; i++)
+               mfmbuf[i] = 0xaaaa;
+           for (i = 0; i < 512; i += 4) {
+               deven = ((secbuf[i + 32] << 24) | (secbuf[i + 33] << 16)
+                        | (secbuf[i + 34] << 8) | (secbuf[i + 35]));
+               dodd = deven >> 1;
+               deven &= 0x55555555;
+               dodd &= 0x55555555;
+               mfmbuf[(i >> 1) + 32] = dodd >> 16;
+               mfmbuf[(i >> 1) + 33] = dodd;
+               mfmbuf[(i >> 1) + 256 + 32] = deven >> 16;
+               mfmbuf[(i >> 1) + 256 + 33] = deven;
+           }
+
+           for (i = 4; i < 24; i += 2)
+               hck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1];
+
+           deven = dodd = hck;
+           dodd >>= 1;
+           mfmbuf[24] = dodd >> 16;
+           mfmbuf[25] = dodd;
+           mfmbuf[26] = deven >> 16;
+           mfmbuf[27] = deven;
+
+           for (i = 32; i < 544; i += 2)
+               dck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1];
+
+           deven = dodd = dck;
+           dodd >>= 1;
+           mfmbuf[28] = dodd >> 16;
+           mfmbuf[29] = dodd;
+           mfmbuf[30] = deven >> 16;
+           mfmbuf[31] = deven;
+           mfmcode (mfmbuf + 4, 544 - 4);
+
+       }
+    return (num_secs * 544 + FLOPPY_GAP_LEN) * 2 * 8;
+}
+
+static uae_u16 amigamfmbuffer[LONGEST_TRACK];
+static uae_u8 amigabuffer[512*22];
+
+/* search and align to 0x4489 WORDSYNC markers */
+static int isamigatrack(uae_u8 *mfmdata, uae_u8 *mfmdatae, uae_u16 *mfmdst, int track)
+{
+       uae_u16 *dst = amigamfmbuffer;
+       int len;
+       int shift, syncshift, sync,ret;
+       uae_u32 l;
+       uae_u16 w;
+
+       sync = syncshift = shift = 0;
+       len = (mfmdatae - mfmdata) * 8;
+       if (len > LONGEST_TRACK * 8)
+           len = LONGEST_TRACK * 8;
+       while (len--) {
+               l = (mfmdata[0] << 16) | (mfmdata[1] << 8) | (mfmdata[2] << 0);
+               w = l >> (8 - shift);
+               if (w == 0x4489) {
+                       sync = 1;
+                       syncshift = 0;
+               }
+               if (sync) {
+                       if (syncshift == 0) *dst++ = w;
+                       syncshift ++;
+                       if (syncshift == 16) syncshift = 0;
+               }
+               shift++;
+               if (shift == 8) {
+                       mfmdata++;
+                       shift = 0;
+               }
+       }
+       if (sync) {
+               ret=drive_write_adf_amigados (amigamfmbuffer, dst, amigabuffer, track);
+               if(!ret)
+                   return amigados_mfmcode (amigabuffer, mfmdst, 11, track);
+               write_log ("decode error %d\n", ret);
+       } else {
+           write_log ("decode error: no sync found\n");
+       }
+       return 0;
+}
+
+
+
+int catweasel_fillmfm (catweasel_drive *d, uae_u16 *mfm, int side, int clock, int rawmode)
+{
+    int i, j, oldsync, syncs[10], synccnt, endcnt;
+    uae_u32 tt1 = 0, tt2 = 0;
+    uae_u8 *p1;
+    int bytes = 0, bits = 0;
+    static int lasttrack, trycnt;
+
+    if (cwc.type == 0)
+       return 0;
+    if (d->contr->control_register & d->mot)
+       return 0;
+    if (!catweasel_read (d, side, 1, rawmode))
+       return 0;
+    if(d->contr->type == CATWEASEL_TYPE_MK1) {
+       inb(d->contr->iobase + 1);
+       inb(d->contr->io_mem); /* ignore first byte */
+    } else {
+       outb(0, d->contr->iobase + 0xe4);
+    }
+    catweasel_read_byte (d);
+    if (lasttrack == d->track)
+       trycnt++;
+    else
+       trycnt = 0;
+    lasttrack = d->track;
+    codec_init_threshtab(trycnt, amiga_thresholds);
+    i = 0; j = 0;
+    synccnt = 0;
+    oldsync = -1;
+    endcnt = 0;
+    while (j < LONGEST_TRACK * 4) {
+       uae_u8 b = catweasel_read_byte (d);
+       if (b >= 250) {
+           if (b == 255 - endcnt) {
+               endcnt++;
+               if (endcnt == 5)
+                   break;
+           } else
+               endcnt = 0;
+       }
+       if (rawmode) {
+           if (b & 0x80) {
+               if (oldsync < j) {
+                   syncs[synccnt++] = j;
+                   oldsync = j + 300;
+               }
+           }
+           if (synccnt >= 3 && j > oldsync)
+               break;
+       }
+       b = threshtab[b & 0x7f];
+       tt1 = (tt1 << b) + 1;
+       tt2 += b;
+
+       if (tt2 >= 16) {
+           tt2 -= 16;
+           mfmbuf[j++] = tt1 >> (tt2 + 8);
+           mfmbuf[j++] = tt1 >> tt2;
+       }
+       i++;
+    }
+    write_log ("cyl=%d, side=%d, length %d, syncs %d\n", d->track, side, j, synccnt);
+    if (rawmode) {
+       if (synccnt >= 3) {
+           p1 = scantrack (mfmbuf + syncs[1], mfmbuf + syncs[2], &bytes, &bits);
+           if (p1) {
+               j = 0;
+               for (i = 0; i < bytes + 2; i+=2) {
+                   mfm[j++] = (p1[i] << 8) | p1[i + 1];
+               }
+               return bytes * 8 + bits;
+           }
+       }
+    } else {
+       return isamigatrack (mfmbuf, mfmbuf + j, mfm, d->track * 2 + side);
+    }
+    return 0;
+}
+       
+int catweasel_read(catweasel_drive *d, int side, int clock, int rawmode)
+{
+    int iobase = d->contr->iobase;
+
+    CWSetCReg(d->contr, d->sel, 0);
+    if(d->contr->type == CATWEASEL_TYPE_MK1) {
+       CWSetCReg(d->contr, 1<<2, (!side)<<2); /* set disk side */
+
+       inb(iobase+1); /* ra reset */
+       outb(clock*128, iobase+3);
+
+       inb(iobase+1);
+       inb(iobase+0);
+//     inb(iobase+0);
+//     outb(0, iobase+3); /* don't store index pulse */
+
+       inb(iobase+1);
+
+       inb(iobase+7); /* start reading */
+       sleep_millis(rawmode ? 550 : 225);
+       outb(0, iobase+1); /* stop reading, don't reset RAM pointer */
+
+       outb(128, iobase+0); /* add data end mark */
+       outb(128, iobase+0);
+
+       inb(iobase+1); /* Reset RAM pointer */
+    } else {
+       CWSetCReg(d->contr, 1<<6, (!side)<<6); /* set disk side */
+
+       outb(0, iobase + 0xe4); /* Reset memory pointer */
+       switch(clock) {
+       case 0: /* 28MHz */
+           outb(128, iobase + 0xec);
+           break;
+       case 1: /* 14MHz */
+           outb(0, iobase + 0xec);
+           break;
+       }
+       inb(iobase + 0xe0);
+       inb(iobase + 0xe0);
+       outb(0, iobase + 0xec); /* no IRQs, no MFM predecode */
+       inb(iobase + 0xe0);
+       outb(0, iobase + 0xec); /* don't store index pulse */
+
+       outb(0, iobase + 0xe4); /* Reset memory pointer */
+       inb(iobase + 0xf0); /* start reading */
+       sleep_millis(rawmode ? 550 : 225);
+       inb(iobase + 0xe4); /* stop reading, don't reset RAM pointer */
+
+       outb(255, iobase + 0xe0); /* add data end mark */
+       outb(254, iobase + 0xe0); /* add data end mark */
+       outb(253, iobase + 0xe0); /* add data end mark */
+       outb(252, iobase + 0xe0); /* add data end mark */
+       outb(251, iobase + 0xe0); /* add data end mark */
+       outb(0, iobase + 0xe4); /* Reset memory pointer */
+    }
+    CWSetCReg(d->contr, 0, d->sel);
+    return 1;
+}
+
+#endif
\ No newline at end of file
diff --git a/cdrom.c b/cdrom.c
new file mode 100755 (executable)
index 0000000..f171b3c
--- /dev/null
+++ b/cdrom.c
@@ -0,0 +1,236 @@
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+
+/* CDROM MODE 1 EDC/ECC code (from Reed-Solomon library by Heiko Eissfeldt) */
+
+/*****************************************************************/
+/*                                                               */
+/* CRC LOOKUP TABLE                                              */
+/* ================                                              */
+/* The following CRC lookup table was generated automagically    */
+/* by the Rocksoft^tm Model CRC Algorithm Table Generation       */
+/* Program V1.0 using the following model parameters:            */
+/*                                                               */
+/*    Width   : 4 bytes.                                         */
+/*    Poly    : 0x8001801BL                                      */
+/*    Reverse : TRUE.                                            */
+/*                                                               */
+/* For more information on the Rocksoft^tm Model CRC Algorithm,  */
+/* see the document titled "A Painless Guide to CRC Error        */
+/* Detection Algorithms" by Ross Williams                        */
+/* (ross@guest.adelaide.edu.au.). This document is likely to be  */
+/* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft".        */
+/*                                                               */
+/*****************************************************************/
+
+static uae_u32 EDC_crctable[256] =
+{
+ 0x00000000L, 0x90910101L, 0x91210201L, 0x01B00300L,
+ 0x92410401L, 0x02D00500L, 0x03600600L, 0x93F10701L,
+ 0x94810801L, 0x04100900L, 0x05A00A00L, 0x95310B01L,
+ 0x06C00C00L, 0x96510D01L, 0x97E10E01L, 0x07700F00L,
+ 0x99011001L, 0x09901100L, 0x08201200L, 0x98B11301L,
+ 0x0B401400L, 0x9BD11501L, 0x9A611601L, 0x0AF01700L,
+ 0x0D801800L, 0x9D111901L, 0x9CA11A01L, 0x0C301B00L,
+ 0x9FC11C01L, 0x0F501D00L, 0x0EE01E00L, 0x9E711F01L,
+ 0x82012001L, 0x12902100L, 0x13202200L, 0x83B12301L,
+ 0x10402400L, 0x80D12501L, 0x81612601L, 0x11F02700L,
+ 0x16802800L, 0x86112901L, 0x87A12A01L, 0x17302B00L,
+ 0x84C12C01L, 0x14502D00L, 0x15E02E00L, 0x85712F01L,
+ 0x1B003000L, 0x8B913101L, 0x8A213201L, 0x1AB03300L,
+ 0x89413401L, 0x19D03500L, 0x18603600L, 0x88F13701L,
+ 0x8F813801L, 0x1F103900L, 0x1EA03A00L, 0x8E313B01L,
+ 0x1DC03C00L, 0x8D513D01L, 0x8CE13E01L, 0x1C703F00L,
+ 0xB4014001L, 0x24904100L, 0x25204200L, 0xB5B14301L,
+ 0x26404400L, 0xB6D14501L, 0xB7614601L, 0x27F04700L,
+ 0x20804800L, 0xB0114901L, 0xB1A14A01L, 0x21304B00L,
+ 0xB2C14C01L, 0x22504D00L, 0x23E04E00L, 0xB3714F01L,
+ 0x2D005000L, 0xBD915101L, 0xBC215201L, 0x2CB05300L,
+ 0xBF415401L, 0x2FD05500L, 0x2E605600L, 0xBEF15701L,
+ 0xB9815801L, 0x29105900L, 0x28A05A00L, 0xB8315B01L,
+ 0x2BC05C00L, 0xBB515D01L, 0xBAE15E01L, 0x2A705F00L,
+ 0x36006000L, 0xA6916101L, 0xA7216201L, 0x37B06300L,
+ 0xA4416401L, 0x34D06500L, 0x35606600L, 0xA5F16701L,
+ 0xA2816801L, 0x32106900L, 0x33A06A00L, 0xA3316B01L,
+ 0x30C06C00L, 0xA0516D01L, 0xA1E16E01L, 0x31706F00L,
+ 0xAF017001L, 0x3F907100L, 0x3E207200L, 0xAEB17301L,
+ 0x3D407400L, 0xADD17501L, 0xAC617601L, 0x3CF07700L,
+ 0x3B807800L, 0xAB117901L, 0xAAA17A01L, 0x3A307B00L,
+ 0xA9C17C01L, 0x39507D00L, 0x38E07E00L, 0xA8717F01L,
+ 0xD8018001L, 0x48908100L, 0x49208200L, 0xD9B18301L,
+ 0x4A408400L, 0xDAD18501L, 0xDB618601L, 0x4BF08700L,
+ 0x4C808800L, 0xDC118901L, 0xDDA18A01L, 0x4D308B00L,
+ 0xDEC18C01L, 0x4E508D00L, 0x4FE08E00L, 0xDF718F01L,
+ 0x41009000L, 0xD1919101L, 0xD0219201L, 0x40B09300L,
+ 0xD3419401L, 0x43D09500L, 0x42609600L, 0xD2F19701L,
+ 0xD5819801L, 0x45109900L, 0x44A09A00L, 0xD4319B01L,
+ 0x47C09C00L, 0xD7519D01L, 0xD6E19E01L, 0x46709F00L,
+ 0x5A00A000L, 0xCA91A101L, 0xCB21A201L, 0x5BB0A300L,
+ 0xC841A401L, 0x58D0A500L, 0x5960A600L, 0xC9F1A701L,
+ 0xCE81A801L, 0x5E10A900L, 0x5FA0AA00L, 0xCF31AB01L,
+ 0x5CC0AC00L, 0xCC51AD01L, 0xCDE1AE01L, 0x5D70AF00L,
+ 0xC301B001L, 0x5390B100L, 0x5220B200L, 0xC2B1B301L,
+ 0x5140B400L, 0xC1D1B501L, 0xC061B601L, 0x50F0B700L,
+ 0x5780B800L, 0xC711B901L, 0xC6A1BA01L, 0x5630BB00L,
+ 0xC5C1BC01L, 0x5550BD00L, 0x54E0BE00L, 0xC471BF01L,
+ 0x6C00C000L, 0xFC91C101L, 0xFD21C201L, 0x6DB0C300L,
+ 0xFE41C401L, 0x6ED0C500L, 0x6F60C600L, 0xFFF1C701L,
+ 0xF881C801L, 0x6810C900L, 0x69A0CA00L, 0xF931CB01L,
+ 0x6AC0CC00L, 0xFA51CD01L, 0xFBE1CE01L, 0x6B70CF00L,
+ 0xF501D001L, 0x6590D100L, 0x6420D200L, 0xF4B1D301L,
+ 0x6740D400L, 0xF7D1D501L, 0xF661D601L, 0x66F0D700L,
+ 0x6180D800L, 0xF111D901L, 0xF0A1DA01L, 0x6030DB00L,
+ 0xF3C1DC01L, 0x6350DD00L, 0x62E0DE00L, 0xF271DF01L,
+ 0xEE01E001L, 0x7E90E100L, 0x7F20E200L, 0xEFB1E301L,
+ 0x7C40E400L, 0xECD1E501L, 0xED61E601L, 0x7DF0E700L,
+ 0x7A80E800L, 0xEA11E901L, 0xEBA1EA01L, 0x7B30EB00L,
+ 0xE8C1EC01L, 0x7850ED00L, 0x79E0EE00L, 0xE971EF01L,
+ 0x7700F000L, 0xE791F101L, 0xE621F201L, 0x76B0F300L,
+ 0xE541F401L, 0x75D0F500L, 0x7460F600L, 0xE4F1F701L,
+ 0xE381F801L, 0x7310F900L, 0x72A0FA00L, 0xE231FB01L,
+ 0x71C0FC00L, 0xE151FD01L, 0xE0E1FE01L, 0x7070FF00L
+};
+
+/*****************************************************************/
+/*                   End of CRC Lookup Table                     */
+/*****************************************************************/
+
+static uae_u8 rs_l12_alog[255] = {
+ 1, 2, 4, 8,16,32,64,128,29,58,116,232,205,135,19,38,76,152,45,90,180,117,234,201,143, 3, 6,12,24,48,96,192,157,39,78,156,37,74,148,53,106,212,181,119,238,193,159,35,70,140, 5,10,20,40,80,160,93,186,105,210,185,111,222,161,95,190,97,194,153,47,94,188,101,202,137,15,30,60,120,240,253,231,211,187,107,214,177,127,254,225,223,163,91,182,113,226,217,175,67,134,17,34,68,136,13,26,52,104,208,189,103,206,129,31,62,124,248,237,199,147,59,118,236,197,151,51,102,204,133,23,46,92,184,109,218,169,79,158,33,66,132,21,42,84,168,77,154,41,82,164,85,170,73,146,57,114,228,213,183,115,230,209,191,99,198,145,63,126,252,229,215,179,123,246,241,255,227,219,171,75,150,49,98,196,149,55,110,220,165,87,174,65,130,25,50,100,200,141, 7,14,28,56,112,224,221,167,83,166,81,162,89,178,121,242,249,239,195,155,43,86,172,69,138, 9,18,36,72,144,61,122,244,245,247,243,251,235,203,139,11,22,44,88,176,125,250,233,207,131,27,54,108,216,173,71,142,};
+static uae_u8 rs_l12_log[256] = {
+ 0, 0, 1,25, 2,50,26,198, 3,223,51,238,27,104,199,75, 4,100,224,14,52,141,239,129,28,193,105,248,200, 8,76,113, 5,138,101,47,225,36,15,33,53,147,142,218,240,18,130,69,29,181,194,125,106,39,249,185,201,154, 9,120,77,228,114,166, 6,191,139,98,102,221,48,253,226,152,37,179,16,145,34,136,54,208,148,206,143,150,219,189,241,210,19,92,131,56,70,64,30,66,182,163,195,72,126,110,107,58,40,84,250,133,186,61,202,94,155,159,10,21,121,43,78,212,229,172,115,243,167,87, 7,112,192,247,140,128,99,13,103,74,222,237,49,197,254,24,227,165,153,119,38,184,180,124,17,68,146,217,35,32,137,46,55,63,209,91,149,188,207,205,144,135,151,178,220,252,190,97,242,86,211,171,20,42,93,158,132,60,57,83,71,109,65,162,31,45,67,216,183,123,164,118,196,23,73,236,127,12,111,246,108,161,59,82,41,157,85,170,251,96,134,177,187,204,62,90,203,89,95,176,156,169,160,81,11,245,22,235,122,117,44,215,79,174,213,233,230,231,173,232,116,214,244,234,168,80,88,175,};
+static uae_u8 DQ[2][43] = {
+{190,96,250,132,59,81,159,154,200,7,111,245,10,20,41,156,168,79,173,231,229,171,210,240,17,67,215,43,120,8,199,74,102,220,251,95,175,87,166,113,75,198,25,},
+{97,251,133,60,82,160,155,201,8,112,246,11,21,42,157,169,80,174,232,230,172,211,241,18,68,216,44,121,9,200,75,103,221,252,96,176,88,167,114,76,199,26,1,},
+};
+static uae_u8 DP[2][24] = {
+{231,229,171,210,240,17,67,215,43,120,8,199,74,102,220,251,95,175,87,166,113,75,198,25,},
+{230,172,211,241,18,68,216,44,121,9,200,75,103,221,252,96,176,88,167,114,76,199,26,1,},
+};
+
+/* data sector definitions for RSPC */
+/* user data bytes per frame */
+#define L2_RAW (1024*2)
+/* parity bytes for 16 bit units */
+#define L2_Q   (26*2*2)
+#define L2_P   (43*2*2)
+#define RS_L12_BITS 8
+
+static uae_u32 build_edc(uae_u8 *inout, int from, int upto)
+{
+    uae_u8 *p = inout + from;
+    uae_u32 result = 0;
+    for (; from <= upto; from++)
+       result = EDC_crctable[(result ^ *p++) & 0xff] ^ (result >> 8);
+    return result;
+}
+
+static void encode_L2_Q(uae_u8 *inout)
+{
+    uae_u8 *Q;
+    int i,j;
+
+    Q = inout + 4 + L2_RAW + 4 + 8 + L2_P;
+    memset(Q, 0, L2_Q);
+    for (j = 0; j < 26; j++) {
+       for (i = 0; i < 43; i++) {
+           uae_u8 data;
+           /* LSB */
+           data = inout[(j*43*2+i*2*44) % (4 + L2_RAW + 4 + 8 + L2_P)];
+           if (data != 0) {
+               uae_u32 base = rs_l12_log[data];
+               uae_u32 sum = base + DQ[0][i];
+               if (sum >= ((1 << RS_L12_BITS)-1))
+                   sum -= (1 << RS_L12_BITS)-1;
+               Q[0]    ^= rs_l12_alog[sum];
+               sum = base + DQ[1][i];
+               if (sum >= ((1 << RS_L12_BITS)-1))
+                   sum -= (1 << RS_L12_BITS)-1;
+               Q[26*2] ^= rs_l12_alog[sum];
+           }
+           /* MSB */
+           data = inout[(j*43*2+i*2*44+1) % (4 + L2_RAW + 4 + 8 + L2_P)];
+           if (data != 0) {
+               uae_u32 base = rs_l12_log[data];
+               uae_u32 sum = base+DQ[0][i];
+               if (sum >= ((1 << RS_L12_BITS)-1))
+                   sum -= (1 << RS_L12_BITS)-1;
+               Q[1]      ^= rs_l12_alog[sum];
+               sum = base + DQ[1][i];
+               if (sum >= ((1 << RS_L12_BITS)-1))
+                   sum -= (1 << RS_L12_BITS)-1;
+               Q[26*2+1] ^= rs_l12_alog[sum];
+           }
+       }
+       Q += 2;
+    }
+}
+
+static void encode_L2_P(uae_u8 inout[4 + L2_RAW + 4 + 8 + L2_P])
+{
+    uae_u8 *P;
+    int i,j;
+
+    P = inout + 4 + L2_RAW + 4 + 8;
+    memset(P, 0, L2_P);
+    for (j = 0; j < 43; j++) {
+       for (i = 0; i < 24; i++) {
+           uae_u8 data;
+           /* LSB */
+           data = inout[i*2*43];
+           if (data != 0) {
+               uae_u32 base = rs_l12_log[data];
+               uae_u32 sum = base + DP[0][i];
+               if (sum >= ((1 << RS_L12_BITS)-1))
+                   sum -= (1 << RS_L12_BITS)-1;
+               P[0]    ^= rs_l12_alog[sum];
+               sum = base + DP[1][i];
+               if (sum >= ((1 << RS_L12_BITS)-1))
+                   sum -= (1 << RS_L12_BITS)-1;
+               P[43*2] ^= rs_l12_alog[sum];
+           }
+           /* MSB */
+           data = inout[i*2*43+1];
+           if (data != 0) {
+               uae_u32 base = rs_l12_log[data];
+               uae_u32 sum = base + DP[0][i];
+               if (sum >= ((1 << RS_L12_BITS)-1))
+                   sum -= (1 << RS_L12_BITS)-1;
+               P[1]      ^= rs_l12_alog[sum];
+               sum = base + DP[1][i];
+               if (sum >= ((1 << RS_L12_BITS)-1))
+                   sum -= (1 << RS_L12_BITS)-1;
+               P[43*2+1] ^= rs_l12_alog[sum];
+           }
+       }
+       P += 2;
+       inout += 2;
+    }
+}
+
+static uae_u8 tobcd (uae_u8 v)
+{
+    return ((v / 10) << 4) | (v % 10);
+}
+
+void encode_l2 (uae_u8 *p, int address)
+{
+    uae_u32 v;
+
+    p[0] = 0x00;
+    memset (p + 1, 0xff, 11);
+    p[12] = tobcd ((uae_u8)(address / (60 * 75)));
+    p[13] = tobcd ((uae_u8)((address / 75) % 60));
+    p[14] = tobcd ((uae_u8)(address % 75));
+    p[15] = 1; /* MODE1 */
+    v = build_edc (p, 0, 16 + 2048 - 1);
+    p[2064 + 0] = (uae_u8) (v >> 0);
+    p[2064 + 1] = (uae_u8) (v >> 8);
+    p[2064 + 2] = (uae_u8) (v >> 16);
+    p[2064 + 3] = (uae_u8) (v >> 24);
+    memset (p + 2064 + 4, 0, 8);
+    encode_L2_P (p + 12);
+    encode_L2_Q (p + 12);
+}
diff --git a/cfgfile.c b/cfgfile.c
new file mode 100755 (executable)
index 0000000..ff08248
--- /dev/null
+++ b/cfgfile.c
@@ -0,0 +1,1878 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Config file handling
+  * This still needs some thought before it's complete...
+  *
+  * Copyright 1998 Brian King, Bernd Schmidt
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <ctype.h>
+
+#include "config.h"
+#include "options.h"
+#include "threaddep/thread.h"
+#include "uae.h"
+#include "autoconf.h"
+#include "events.h"
+#include "custom.h"
+#include "inputdevice.h"
+#include "gfxfilter.h"
+#include "savestate.h"
+#include "memory.h"
+
+static int config_newfilesystem;
+static struct strlist *temp_lines;
+
+/* @@@ need to get rid of this... just cut part of the manual and print that
+ * as a help text.  */
+struct cfg_lines
+{
+    const char *config_label, *config_help;
+};
+
+static struct cfg_lines opttable[] =
+{
+    {"help", "Prints this help" },
+    {"config_description", "" },
+    {"config_info", "" },
+    {"use_gui", "Enable the GUI?  If no, then goes straight to emulator" },
+    {"use_debugger", "Enable the debugger?" },
+    {"cpu_speed", "can be max, real, or a number between 1 and 20" },
+    {"cpu_type", "Can be 68000, 68010, 68020, 68020/68881" },
+    {"cpu_compatible", "yes enables compatibility-mode" },
+    {"cpu_24bit_addressing", "must be set to 'no' in order for Z3mem or P96mem to work" },
+    {"autoconfig", "yes = add filesystems and extra ram" },
+    {"log_illegal_mem", "print illegal memory access by Amiga software?" },
+    {"fastmem_size", "Size in megabytes of fast-memory" },
+    {"chipmem_size", "Size in megabytes of chip-memory" },
+    {"bogomem_size", "Size in megabytes of bogo-memory at 0xC00000" },
+    {"a3000mem_size", "Size in megabytes of A3000 memory" },
+    {"gfxcard_size", "Size in megabytes of Picasso96 graphics-card memory" },
+    {"z3mem_size", "Size in megabytes of Zorro-III expansion memory" },
+    {"gfx_test_speed", "Test graphics speed?" },
+    {"gfx_framerate", "Print every nth frame" },
+    {"gfx_width", "Screen width" },
+    {"gfx_height", "Screen height" },
+    {"gfx_refreshrate", "Fullscreen refresh rate" },
+    {"gfx_vsync", "Sync screen refresh to refresh rate" },
+    {"gfx_lores", "Treat display as lo-res?" },
+    {"gfx_linemode", "Can be none, double, or scanlines" },
+    {"gfx_fullscreen_amiga", "Amiga screens are fullscreen?" },
+    {"gfx_fullscreen_picasso", "Picasso screens are fullscreen?" },
+    {"gfx_correct_aspect", "Correct aspect ratio?" },
+    {"gfx_center_horizontal", "Center display horizontally?" },
+    {"gfx_center_vertical", "Center display vertically?" },
+    {"gfx_colour_mode", "" },
+    {"32bit_blits", "Enable 32 bit blitter emulation" },
+    {"immediate_blits", "Perform blits immediately" },
+    {"show_leds", "LED display" },
+    {"keyboard_leds", "Keyboard LEDs" },
+    {"gfxlib_replacement", "Use graphics.library replacement?" },
+    {"sound_output", "" },
+    {"sound_frequency", "" },
+    {"sound_bits", "" },
+    {"sound_channels", "" },
+    {"sound_max_buff", "" },
+    {"comp_trustbyte", "How to access bytes in compiler (direct/indirect/indirectKS/afterPic" },
+    {"comp_trustword", "How to access words in compiler (direct/indirect/indirectKS/afterPic" },
+    {"comp_trustlong", "How to access longs in compiler (direct/indirect/indirectKS/afterPic" },
+    {"comp_nf", "Whether to optimize away flag generation where possible" },
+    {"comp_fpu", "Whether to provide JIT FPU emulation" },
+    {"compforcesettings", "Whether to force the JIT compiler settings" },
+    {"cachesize", "How many MB to use to buffer translated instructions"},
+    {"override_dga_address","Address from which to map the frame buffer (upper 16 bits) (DANGEROUS!)"},
+    {"avoid_cmov", "Set to yes on machines that lack the CMOV instruction" },
+    {"avoid_dga", "Set to yes if the use of DGA extension creates problems" },
+    {"avoid_vid", "Set to yes if the use of the Vidmode extension creates problems" },
+    {"parallel_on_demand", "" },
+    {"serial_on_demand", "" },
+    {"scsi", "scsi.device emulation" },
+    {"joyport0", "" },
+    {"joyport1", "" },
+    {"pci_devices", "List of PCI devices to make visible to the emulated Amiga" },
+    {"kickstart_rom_file", "Kickstart ROM image, (C) Copyright Amiga, Inc." },
+    {"kickstart_ext_rom_file", "Extended Kickstart ROM image, (C) Copyright Amiga, Inc." },
+    {"kickstart_key_file", "Key-file for encrypted ROM images (from Cloanto's Amiga Forever)" },
+    {"flash_ram_file", "Flash/battery backed RAM image file." },
+    {"cart_file", "Freezer cartridge ROM image file." },
+    {"floppy0", "Diskfile for drive 0" },
+    {"floppy1", "Diskfile for drive 1" },
+    {"floppy2", "Diskfile for drive 2" },
+    {"floppy3", "Diskfile for drive 3" },
+    {"hardfile", "access,sectors, surfaces, reserved, blocksize, path format" },
+    {"filesystem", "access,'Amiga volume-name':'host directory path' - where 'access' can be 'read-only' or 'read-write'" },
+    {"catweasel_io","Catweasel board io base address" }
+};
+
+static const char *guimode1[] = { "no", "yes", "nowait", 0 };
+static const char *guimode2[] = { "false", "true", "nowait", 0 };
+static const char *guimode3[] = { "0", "1", "nowait", 0 };
+static const char *csmode[] = { "ocs", "ecs_agnus", "ecs_denise", "ecs", "aga", 0 };
+static const char *linemode1[] = { "none", "double", "scanlines", 0 };
+static const char *linemode2[] = { "n", "d", "s", 0 };
+static const char *speedmode[] = { "max", "real", 0 };
+static const char *cpumode[] = {
+    "68000", "68000", "68010", "68010", "68ec020", "68020", "68ec020/68881", "68020/68881",
+    "68040", "68040", "xxxxx", "xxxxx", "68060", "68060", 0
+};
+static const char *portmode[] = { "joy0", "joy1", "mouse", "kbd1", "kbd2", "kbd3", 0 };
+static const char *colormode1[] = { "8bit", "15bit", "16bit", "8bit_dither", "4bit_dither", "32bit", 0 };
+static const char *colormode2[] = { "8", "15", "16", "8d", "4d", "32", 0 };
+static const char *soundmode1[] = { "none", "interrupts", "normal", "exact", 0 };
+static const char *soundmode2[] = { "none", "interrupts", "good", "best", 0 };
+static const char *centermode1[] = { "none", "simple", "smart", 0 };
+static const char *centermode2[] = { "false", "true", "smart", 0 };
+static const char *stereomode1[] = { "mono", "stereo", "mixed", 0 };
+static const char *stereomode2[] = { "m", "s", "x", 0 };
+static const char *stereomode3[] = { "1", "2", "3", 0 };
+static const char *interpolmode[] = { "none", "rh", "crux", 0 };
+static const char *collmode[] = { "none", "sprites", "playfields", "full", 0 };
+static const char *compmode[] = { "direct", "indirect", "indirectKS", "afterPic", 0 };
+static const char *flushmode[]   = { "soft", "hard", 0 };
+static const char *kbleds[] = { "none", "POWER", "DF0", "DF1", "DF2", "DF3", "HD", "CD", 0 };
+static const char *soundfiltermode[] = { "off", "emulated", "on", 0 };
+#ifdef GFXFILTER
+static const char *filtermode1[] = { "no_16", "bilinear_16", "no_32", "bilinear_32", 0 };
+static const char *filtermode2[] = { "0x", "1x", "2x", "3x", "4x", 0 };
+#endif
+
+static const char *obsolete[] = {
+    "accuracy","gfx_opengl","gfx_32bit_blits","32bit_blits",
+    "gfx_immediate_blits","gfx_ntsc","win32",
+    "sound_pri_cutoff", "sound_pri_time", 0 };
+
+#define UNEXPANDED "$(FILE_PATH)"
+
+static int match_string (const char *table[], const char *str)
+{
+    int i;
+    for (i = 0; table[i] != 0; i++)
+       if (strcasecmp (table[i], str) == 0)
+           return i;
+    return -1;
+}
+
+char *cfgfile_subst_path (const char *path, const char *subst, const char *file)
+{
+    /* @@@ use strcasecmp for some targets.  */
+    if (strlen (path) > 0 && strncmp (file, path, strlen (path)) == 0) {
+       int l;
+       char *p = xmalloc (strlen (file) + strlen (subst) + 2);
+       strcpy (p, subst);
+       l = strlen (p);
+       while (l > 0 && p[l - 1] == '/')
+           p[--l] = '\0';
+       l = strlen (path);
+       while (file[l] == '/')
+           l++;
+       strcat (p, "/"); strcat (p, file + l);
+       return p;
+    }
+    return my_strdup (file);
+}
+
+void cfgfile_write (FILE *f, char *format,...)
+{
+    va_list parms;
+    char tmp[1000];
+
+    va_start (parms, format);
+    vsprintf (tmp, format, parms);
+    fprintf (f, tmp);
+    va_end (parms);
+}
+
+void save_options (FILE *f, struct uae_prefs *p, int type)
+{
+    struct strlist *sl;
+    char *str;
+    int i;
+
+    cfgfile_write (f, "config_description=%s\n", p->description);
+    cfgfile_write (f, "config_hardware=%s\n", (type & CONFIG_TYPE_HARDWARE) ? "true" : "false");
+    cfgfile_write (f, "config_host=%s\n", (type & CONFIG_TYPE_HOST) ? "true" : "false");
+    if (p->info[0])
+       cfgfile_write (f, "config_info=%s\n", p->info);
+    cfgfile_write (f, "config_version=%d.%d.%d\n", UAEMAJOR, UAEMINOR, UAESUBREV);
+
+    for (sl = p->all_lines; sl; sl = sl->next) {
+       if (sl->unknown)
+           cfgfile_write (f, "%s=%s\n", sl->option, sl->value);
+    }
+
+    cfgfile_write (f, "%s.rom_path=%s\n", TARGET_NAME, p->path_rom);
+    cfgfile_write (f, "%s.floppy_path=%s\n", TARGET_NAME, p->path_floppy);
+    cfgfile_write (f, "%s.hardfile_path=%s\n", TARGET_NAME, p->path_hardfile);
+
+    target_save_options (f, p);
+
+    cfgfile_write (f, "use_gui=%s\n", guimode1[p->start_gui]);
+    cfgfile_write (f, "use_debugger=%s\n", p->start_debugger ? "true" : "false");
+    str = cfgfile_subst_path (p->path_rom, UNEXPANDED, p->romfile);
+    cfgfile_write (f, "kickstart_rom_file=%s\n", str);
+    free (str);
+    str = cfgfile_subst_path (p->path_rom, UNEXPANDED, p->romextfile);
+    cfgfile_write (f, "kickstart_ext_rom_file=%s\n", str);
+    free (str);
+    str = cfgfile_subst_path (p->path_rom, UNEXPANDED, p->keyfile);
+    cfgfile_write (f, "kickstart_key_file=%s\n", str);
+    free (str);
+    str = cfgfile_subst_path (p->path_rom, UNEXPANDED, p->flashfile);
+    cfgfile_write (f, "flash_file=%s\n", str);
+    free (str);
+    str = cfgfile_subst_path (p->path_rom, UNEXPANDED, p->cartfile);
+    cfgfile_write (f, "cart_file=%s\n", str);
+    free (str);
+    cfgfile_write (f, "kickshifter=%s\n", p->kickshifter ? "true" : "false");
+
+    p->nr_floppies = 4;
+    for (i = 0; i < 4; i++) {
+       str = cfgfile_subst_path (p->path_floppy, UNEXPANDED, p->df[i]);
+       cfgfile_write (f, "floppy%d=%s\n", i, str);
+       free (str);
+       cfgfile_write (f, "floppy%dtype=%d\n", i, p->dfxtype[i]);
+       cfgfile_write (f, "floppy%dsound=%d\n", i, p->dfxclick[i]);
+       if (p->dfxclick[i] < 0 && p->dfxclickexternal[i][0])
+           cfgfile_write (f, "floppy%dsoundext=%s\n", i, p->dfxclickexternal[i]);
+       if (p->dfxtype[i] < 0 && p->nr_floppies > i)
+           p->nr_floppies = i;
+    }
+    for (i = 0; i < MAX_SPARE_DRIVES; i++) {
+       if (p->dfxlist[i][0])
+           cfgfile_write (f, "diskimage%d=%s\n", i, p->dfxlist[i]);
+    }
+
+    cfgfile_write (f, "nr_floppies=%d\n", p->nr_floppies);
+    cfgfile_write (f, "floppy_speed=%d\n", p->floppy_speed);
+    cfgfile_write (f, "floppy_volume=%d\n", p->dfxclickvolume);
+    cfgfile_write (f, "parallel_on_demand=%s\n", p->parallel_demand ? "true" : "false");
+    cfgfile_write (f, "serial_on_demand=%s\n", p->serial_demand ? "true" : "false");
+    cfgfile_write (f, "serial_hardware_ctsrts=%s\n", p->serial_hwctsrts ? "true" : "false");
+    cfgfile_write (f, "serial_direct=%s\n", p->serial_direct ? "true" : "false");
+    cfgfile_write (f, "scsi=%s\n", p->scsi ? "true" : "false");
+
+    cfgfile_write (f, "sound_output=%s\n", soundmode1[p->produce_sound]);
+    cfgfile_write (f, "sound_bits=%d\n", p->sound_bits);
+    cfgfile_write (f, "sound_channels=%s\n", stereomode1[p->stereo + p->mixed_stereo]);
+    cfgfile_write (f, "sound_max_buff=%d\n", p->sound_maxbsiz);
+    cfgfile_write (f, "sound_frequency=%d\n", p->sound_freq);
+    cfgfile_write (f, "sound_interpol=%s\n", interpolmode[p->sound_interpol]);
+    cfgfile_write (f, "sound_adjust=%d\n", p->sound_adjust);
+    cfgfile_write (f, "sound_filter=%s\n", soundfiltermode[p->sound_filter]);
+    cfgfile_write (f, "sound_volume=%d\n", p->sound_volume);
+
+    cfgfile_write (f, "comp_trustbyte=%s\n", compmode[p->comptrustbyte]);
+    cfgfile_write (f, "comp_trustword=%s\n", compmode[p->comptrustword]);
+    cfgfile_write (f, "comp_trustlong=%s\n", compmode[p->comptrustlong]);
+    cfgfile_write (f, "comp_trustnaddr=%s\n", compmode[p->comptrustnaddr]);
+    cfgfile_write (f, "comp_nf=%s\n", p->compnf ? "true" : "false");
+    cfgfile_write (f, "comp_constjump=%s\n", p->comp_constjump ? "true" : "false");
+    cfgfile_write (f, "comp_oldsegv=%s\n", p->comp_oldsegv ? "true" : "false");
+    
+    cfgfile_write (f, "comp_flushmode=%s\n", flushmode[p->comp_hardflush]);
+    cfgfile_write (f, "compforcesettings=%s\n", p->compforcesettings ? "true" : "false");
+    cfgfile_write (f, "compfpu=%s\n", p->compfpu ? "true" : "false");
+    cfgfile_write (f, "comp_midopt=%s\n", p->comp_midopt ? "true" : "false");
+    cfgfile_write (f, "comp_lowopt=%s\n", p->comp_lowopt ? "true" : "false");
+    cfgfile_write (f, "avoid_cmov=%s\n", p->avoid_cmov ? "true" : "false" );
+    cfgfile_write (f, "avoid_dga=%s\n", p->avoid_dga ? "true" : "false" );
+    cfgfile_write (f, "avoid_vid=%s\n", p->avoid_vid ? "true" : "false" );
+    cfgfile_write (f, "cachesize=%d\n", p->cachesize);
+    if (p->override_dga_address)
+       cfgfile_write (f, "override_dga_address=0x%08x\n", p->override_dga_address);
+
+    cfgfile_write (f, "joyport0=%s\n", portmode[p->jport0]);
+    cfgfile_write (f, "joyport1=%s\n", portmode[p->jport1]);
+
+    cfgfile_write (f, "bsdsocket_emu=%s\n", p->socket_emu ? "true" : "false");
+
+    cfgfile_write (f, "synchronize_clock=%s\n", p->tod_hack ? "yes" : "no");
+    cfgfile_write (f, "maprom=0x%x\n", p->maprom);
+
+    cfgfile_write (f, "gfx_display=%d\n", p->gfx_display);
+    cfgfile_write (f, "gfx_framerate=%d\n", p->gfx_framerate);
+    cfgfile_write (f, "gfx_width=%d\n", p->gfx_width_win); /* compatibility with old versions */
+    cfgfile_write (f, "gfx_height=%d\n", p->gfx_height_win); /* compatibility with old versions */
+    cfgfile_write (f, "gfx_width_windowed=%d\n", p->gfx_width_win);
+    cfgfile_write (f, "gfx_height_windowed=%d\n", p->gfx_height_win);
+    cfgfile_write (f, "gfx_width_fullscreen=%d\n", p->gfx_width_fs);
+    cfgfile_write (f, "gfx_height_fullscreen=%d\n", p->gfx_height_fs);
+    cfgfile_write (f, "gfx_refreshrate=%d\n", p->gfx_refreshrate);
+    cfgfile_write (f, "gfx_vsync=%s\n", p->gfx_vsync ? "true" : "false");
+    cfgfile_write (f, "gfx_lores=%s\n", p->gfx_lores ? "true" : "false");
+    cfgfile_write (f, "gfx_linemode=%s\n", linemode1[p->gfx_linedbl]);
+    cfgfile_write (f, "gfx_correct_aspect=%s\n", p->gfx_correct_aspect ? "true" : "false");
+    cfgfile_write (f, "gfx_fullscreen_amiga=%s\n", p->gfx_afullscreen ? "true" : "false");
+    cfgfile_write (f, "gfx_fullscreen_picasso=%s\n", p->gfx_pfullscreen ? "true" : "false");
+    cfgfile_write (f, "gfx_center_horizontal=%s\n", centermode1[p->gfx_xcenter]);
+    cfgfile_write (f, "gfx_center_vertical=%s\n", centermode1[p->gfx_ycenter]);
+    cfgfile_write (f, "gfx_colour_mode=%s\n", colormode1[p->color_mode]);
+
+#ifdef GFXFILTER
+    if (p->gfx_filter > 0) {
+       int i = 0;
+        struct uae_filter *uf;
+       while (uaefilters[i].name) {
+           uf = &uaefilters[i];
+           if (uf->type == p->gfx_filter) {
+               cfgfile_write (f, "gfx_filter=%s\n", uf->cfgname);
+               if (uf->type == p->gfx_filter) {
+                   if (uf->x[0]) {
+                       cfgfile_write (f, "gfx_filter_mode=%s\n", filtermode1[p->gfx_filter_filtermode]);
+                   } else {
+                       int mt[4], i = 0;
+                       if (uf->x[1]) mt[i++] = 1;
+                       if (uf->x[2]) mt[i++] = 2;
+                       if (uf->x[3]) mt[i++] = 3;
+                       if (uf->x[4]) mt[i++] = 4;
+                       cfgfile_write (f, "gfx_filter_mode=%dx\n", mt[p->gfx_filter_filtermode]);
+                   }
+               }
+           }
+           i++;
+       }
+    } else {
+        cfgfile_write (f, "gfx_filter=no\n");
+    }
+
+    cfgfile_write (f, "gfx_filter_vert_zoom=%d\n", p->gfx_filter_vert_zoom);
+    cfgfile_write (f, "gfx_filter_horiz_zoom=%d\n", p->gfx_filter_horiz_zoom);
+    cfgfile_write (f, "gfx_filter_vert_offset=%d\n", p->gfx_filter_vert_offset);
+    cfgfile_write (f, "gfx_filter_horiz_offset=%d\n", p->gfx_filter_horiz_offset);
+    cfgfile_write (f, "gfx_filter_scanlines=%d\n", p->gfx_filter_scanlines);
+    cfgfile_write (f, "gfx_filter_scanlinelevel=%d\n", p->gfx_filter_scanlinelevel);
+    cfgfile_write (f, "gfx_filter_scanlineratio=%d\n", p->gfx_filter_scanlineratio);
+#endif
+
+    cfgfile_write (f, "immediate_blits=%s\n", p->immediate_blits ? "true" : "false");
+    cfgfile_write (f, "fast_copper=%s\n", p->fast_copper ? "true" : "false");
+    cfgfile_write (f, "ntsc=%s\n", p->ntscmode ? "true" : "false");
+    cfgfile_write (f, "show_leds=%s\n", p->leds_on_screen ? "true" : "false");
+    cfgfile_write (f, "keyboard_leds=numlock:%s,capslock:%s,scrolllock:%s\n",
+       kbleds[p->keyboard_leds[0]], kbleds[p->keyboard_leds[1]], kbleds[p->keyboard_leds[2]]);
+    if (p->chipset_mask & CSMASK_AGA)
+       cfgfile_write (f, "chipset=aga\n");
+    else if ((p->chipset_mask & CSMASK_ECS_AGNUS) && (p->chipset_mask & CSMASK_ECS_DENISE))
+       cfgfile_write (f, "chipset=ecs\n");
+    else if (p->chipset_mask & CSMASK_ECS_AGNUS)
+       cfgfile_write (f, "chipset=ecs_agnus\n");
+    else if (p->chipset_mask & CSMASK_ECS_DENISE)
+       cfgfile_write (f, "chipset=ecs_denise\n");
+    else
+       cfgfile_write (f, "chipset=ocs\n");
+    cfgfile_write (f, "collision_level=%s\n", collmode[p->collision_level]);
+
+    cfgfile_write (f, "fastmem_size=%d\n", p->fastmem_size / 0x100000);
+    cfgfile_write (f, "a3000mem_size=%d\n", p->a3000mem_size / 0x100000);
+    cfgfile_write (f, "z3mem_size=%d\n", p->z3fastmem_size / 0x100000);
+    cfgfile_write (f, "bogomem_size=%d\n", p->bogomem_size / 0x40000);
+    cfgfile_write (f, "gfxcard_size=%d\n", p->gfxmem_size / 0x100000);
+    cfgfile_write (f, "chipmem_size=%d\n", (p->chipmem_size == 0x40000) ? 0 : p->chipmem_size / 0x80000);
+
+    if (p->m68k_speed > 0)
+       cfgfile_write (f, "finegrain_cpu_speed=%d\n", p->m68k_speed);
+    else
+       cfgfile_write (f, "cpu_speed=%s\n", p->m68k_speed == -1 ? "max" : "real");
+
+    cfgfile_write (f, "cpu_type=%s\n", cpumode[p->cpu_level * 2 + !p->address_space_24]);
+    cfgfile_write (f, "cpu_compatible=%s\n", p->cpu_compatible ? "true" : "false");
+    cfgfile_write (f, "cpu_cycle_exact=%s\n", p->cpu_cycle_exact ? "true" : "false");
+    cfgfile_write (f, "blitter_cycle_exact=%s\n", p->blitter_cycle_exact ? "true" : "false");
+
+    cfgfile_write (f, "log_illegal_mem=%s\n", p->illegal_mem ? "true" : "false");
+    cfgfile_write (f, "catweasel_io=0x%x\n", p->catweasel_io);
+
+    cfgfile_write (f, "kbd_lang=%s\n", (p->keyboard_lang == KBD_LANG_DE ? "de"
+                                 : p->keyboard_lang == KBD_LANG_DK ? "dk"
+                                 : p->keyboard_lang == KBD_LANG_ES ? "es"
+                                 : p->keyboard_lang == KBD_LANG_US ? "us"
+                                 : p->keyboard_lang == KBD_LANG_SE ? "se"
+                                 : p->keyboard_lang == KBD_LANG_FR ? "fr"
+                                 : p->keyboard_lang == KBD_LANG_IT ? "it"
+                                 : "FOO"));
+
+    cfgfile_write (f, "state_replay=%s\n", p->statecapture ? "yes" : "no");
+    cfgfile_write (f, "state_replay_rate=%d\n", p->statecapturerate);
+    cfgfile_write (f, "state_replay_buffer=%d\n", p->statecapturebuffersize);
+
+#ifdef FILESYS
+    write_filesys_config (currprefs.mountinfo, UNEXPANDED, p->path_hardfile, f);
+    if (p->filesys_no_uaefsdb)
+        cfgfile_write (f, "filesys_no_fsdb=%s\n", p->filesys_no_uaefsdb ? "true" : "false");
+#endif
+    write_inputdevice_config (p, f);
+
+    /* Don't write gfxlib/gfx_test_speed options.  */
+}
+
+int cfgfile_yesno (char *option, char *value, char *name, int *location)
+{
+    if (strcmp (option, name) != 0)
+       return 0;
+    if (strcasecmp (value, "yes") == 0 || strcasecmp (value, "y") == 0
+       || strcasecmp (value, "true") == 0 || strcasecmp (value, "t") == 0)
+       *location = 1;
+    else if (strcasecmp (value, "no") == 0 || strcasecmp (value, "n") == 0
+       || strcasecmp (value, "false") == 0 || strcasecmp (value, "f") == 0)
+       *location = 0;
+    else
+       write_log ("Option `%s' requires a value of either `yes' or `no'.\n", option);
+    return 1;
+}
+
+int cfgfile_intval (char *option, char *value, char *name, int *location, int scale)
+{
+    int base = 10;
+    char *endptr;
+    if (strcmp (option, name) != 0)
+       return 0;
+    /* I guess octal isn't popular enough to worry about here...  */
+    if (value[0] == '0' && value[1] == 'x')
+       value += 2, base = 16;
+    *location = strtol (value, &endptr, base) * scale;
+
+    if (*endptr != '\0' || *value == '\0')
+       write_log ("Option `%s' requires a numeric argument.\n", option);
+    return 1;
+}
+
+int cfgfile_strval (char *option, char *value, char *name, int *location, const char *table[], int more)
+{
+    int val;
+    if (strcmp (option, name) != 0)
+       return 0;
+    val = match_string (table, value);
+    if (val == -1) {
+       if (more)
+           return 0;
+
+       write_log ("Unknown value for option `%s'.\n", option);
+       return 1;
+    }
+    *location = val;
+    return 1;
+}
+
+int cfgfile_string (char *option, char *value, char *name, char *location, int maxsz)
+{
+    if (strcmp (option, name) != 0)
+       return 0;
+    strncpy (location, value, maxsz - 1);
+    location[maxsz - 1] = '\0';
+    return 1;
+}
+
+static int getintval (char **p, int *result, int delim)
+{
+    char *value = *p;
+    int base = 10;
+    char *endptr;
+    char *p2 = strchr (*p, delim);
+
+    if (p2 == 0)
+       return 0;
+
+    *p2++ = '\0';
+
+    if (value[0] == '0' && value[1] == 'x')
+       value += 2, base = 16;
+    *result = strtol (value, &endptr, base);
+    *p = p2;
+
+    if (*endptr != '\0' || *value == '\0')
+       return 0;
+
+    return 1;
+}
+
+static int getintval2 (char **p, int *result, int delim)
+{
+    char *value = *p;
+    int base = 10;
+    char *endptr;
+    char *p2 = strchr (*p, delim);
+
+    if (p2 == 0) {
+       p2 = strchr (*p, 0);
+       if (p2 == 0) {
+           *p = 0;
+           return 0;
+       }
+    }
+    if (*p2 != 0)
+       *p2++ = '\0';
+
+    if (value[0] == '0' && value[1] == 'x')
+       value += 2, base = 16;
+    *result = strtol (value, &endptr, base);
+    *p = p2;
+
+    if (*endptr != '\0' || *value == '\0') {
+       *p = 0;
+       return 0;
+    }
+
+    return 1;
+}
+
+static void set_chipset_mask (struct uae_prefs *p, int val)
+{
+    p->chipset_mask = (val == 0 ? 0
+                      : val == 1 ? CSMASK_ECS_AGNUS
+                      : val == 2 ? CSMASK_ECS_DENISE
+                      : val == 3 ? CSMASK_ECS_DENISE | CSMASK_ECS_AGNUS
+                      : CSMASK_AGA | CSMASK_ECS_DENISE | CSMASK_ECS_AGNUS);
+}
+
+static int cfgfile_parse_host (struct uae_prefs *p, char *option, char *value)
+{
+    int i;
+    char *section = 0;
+    char *tmpp;
+    char tmpbuf[256];
+
+    if (memcmp (option, "input.", 6) == 0) {
+       read_inputdevice_config (p, option, value);
+       return 1;
+    }
+
+    for (tmpp = option; *tmpp != '\0'; tmpp++)
+       if (isupper (*tmpp))
+           *tmpp = tolower (*tmpp);
+    tmpp = strchr (option, '.');
+    if (tmpp) {
+       section = option;
+       option = tmpp + 1;
+       *tmpp = '\0';
+       if (strcmp (section, TARGET_NAME) == 0) {
+           /* We special case the various path options here.  */
+           if (cfgfile_string (option, value, "rom_path", p->path_rom, 256)
+               || cfgfile_string (option, value, "floppy_path", p->path_floppy, 256)
+               || cfgfile_string (option, value, "hardfile_path", p->path_hardfile, 256))
+               return 1;
+           return target_parse_option (p, option, value);
+       }
+       return 0;
+    }
+    for (i = 0; i < MAX_SPARE_DRIVES; i++) {
+       sprintf (tmpbuf, "diskimage%d", i);
+       if (cfgfile_string (option, value, tmpbuf, p->dfxlist[i], 256))
+           return 1;
+    }
+
+    if (cfgfile_intval (option, value, "sound_max_buff", &p->sound_maxbsiz, 1)
+       || cfgfile_intval (option, value, "sound_bits", &p->sound_bits, 1)
+       || cfgfile_intval (option, value, "state_replay_rate", &p->statecapturerate, 1)
+       || cfgfile_intval (option, value, "state_replay_buffer", &p->statecapturebuffersize, 1)
+       || cfgfile_intval (option, value, "sound_frequency", &p->sound_freq, 1)
+       || cfgfile_intval (option, value, "sound_adjust", &p->sound_adjust, 1)
+       || cfgfile_intval (option, value, "sound_volume", &p->sound_volume, 1)
+
+       || cfgfile_intval (option, value, "gfx_display", &p->gfx_display, 1)
+       || cfgfile_intval (option, value, "gfx_framerate", &p->gfx_framerate, 1)
+       || cfgfile_intval (option, value, "gfx_width_windowed", &p->gfx_width_win, 1)
+       || cfgfile_intval (option, value, "gfx_height_windowed", &p->gfx_height_win, 1)
+       || cfgfile_intval (option, value, "gfx_width_fullscreen", &p->gfx_width_fs, 1)
+       || cfgfile_intval (option, value, "gfx_height_fullscreen", &p->gfx_height_fs, 1)
+       || cfgfile_intval (option, value, "gfx_refreshrate", &p->gfx_refreshrate, 1)
+
+#ifdef GFXFILTER
+       || cfgfile_intval (option, value, "gfx_filter_vert_zoom", &p->gfx_filter_vert_zoom, 1)
+       || cfgfile_intval (option, value, "gfx_filter_horiz_zoom", &p->gfx_filter_horiz_zoom, 1)
+       || cfgfile_intval (option, value, "gfx_filter_vert_offset", &p->gfx_filter_vert_offset, 1)
+       || cfgfile_intval (option, value, "gfx_filter_horiz_offset", &p->gfx_filter_horiz_offset, 1)
+       || cfgfile_intval (option, value, "gfx_filter_scanlines", &p->gfx_filter_scanlines, 1)
+       || cfgfile_intval (option, value, "gfx_filter_scanlinelevel", &p->gfx_filter_scanlinelevel, 1)
+       || cfgfile_intval (option, value, "gfx_filter_scanlineratio", &p->gfx_filter_scanlineratio, 1)
+#endif
+       || cfgfile_intval (option, value, "floppy0sound", &p->dfxclick[0], 1)
+       || cfgfile_intval (option, value, "floppy1sound", &p->dfxclick[1], 1)
+       || cfgfile_intval (option, value, "floppy2sound", &p->dfxclick[2], 1)
+       || cfgfile_intval (option, value, "floppy3sound", &p->dfxclick[3], 1)
+       || cfgfile_intval (option, value, "floppy_volume", &p->dfxclickvolume, 1)
+       || cfgfile_intval (option, value, "override_dga_address", &p->override_dga_address, 1))
+           return 1;
+
+       if (cfgfile_string (option, value, "floppy0soundext", p->dfxclickexternal[0], 256)
+       || cfgfile_string (option, value, "floppy1soundext", p->dfxclickexternal[1], 256)
+       || cfgfile_string (option, value, "floppy2soundext", p->dfxclickexternal[2], 256)
+       || cfgfile_string (option, value, "floppy3soundext", p->dfxclickexternal[3], 256)
+       || cfgfile_string (option, value, "config_info", p->info, 256)
+       || cfgfile_string (option, value, "config_description", p->description, 256))
+           return 1;
+
+       if (cfgfile_yesno (option, value, "use_debugger", &p->start_debugger)
+       || cfgfile_yesno (option, value, "state_replay", &p->statecapture)
+       || cfgfile_yesno (option, value, "avoid_cmov", &p->avoid_cmov)
+       || cfgfile_yesno (option, value, "avoid_dga", &p->avoid_dga)
+       || cfgfile_yesno (option, value, "avoid_vid", &p->avoid_vid)
+       || cfgfile_yesno (option, value, "log_illegal_mem", &p->illegal_mem)
+       || cfgfile_yesno (option, value, "filesys_no_fsdb", &p->filesys_no_uaefsdb)
+       || cfgfile_yesno (option, value, "gfx_vsync", &p->gfx_vsync)
+       || cfgfile_yesno (option, value, "gfx_lores", &p->gfx_lores)
+       || cfgfile_yesno (option, value, "gfx_correct_aspect", &p->gfx_correct_aspect)
+       || cfgfile_yesno (option, value, "gfx_fullscreen_amiga", &p->gfx_afullscreen)
+       || cfgfile_yesno (option, value, "gfx_fullscreen_picasso", &p->gfx_pfullscreen)
+       || cfgfile_yesno (option, value, "show_leds", &p->leds_on_screen)
+       || cfgfile_yesno (option, value, "synchronize_clock", &p->tod_hack)
+       || cfgfile_yesno (option, value, "bsdsocket_emu", &p->socket_emu))
+           return 1;
+
+    if (cfgfile_strval (option, value, "sound_output", &p->produce_sound, soundmode1, 1)
+       || cfgfile_strval (option, value, "sound_output", &p->produce_sound, soundmode2, 0)
+       || cfgfile_strval (option, value, "sound_interpol", &p->sound_interpol, interpolmode, 0)
+       || cfgfile_strval (option, value, "sound_filter", &p->sound_filter, soundfiltermode, 0)
+       || cfgfile_strval (option, value, "joyport0", &p->jport0, portmode, 0)
+       || cfgfile_strval (option, value, "joyport1", &p->jport1, portmode, 0)
+       || cfgfile_strval (option, value, "use_gui", &p->start_gui, guimode1, 1)
+       || cfgfile_strval (option, value, "use_gui", &p->start_gui, guimode2, 1)
+       || cfgfile_strval (option, value, "use_gui", &p->start_gui, guimode3, 0)
+       || cfgfile_strval (option, value, "gfx_linemode", &p->gfx_linedbl, linemode1, 1)
+       || cfgfile_strval (option, value, "gfx_linemode", &p->gfx_linedbl, linemode2, 0)
+       || cfgfile_strval (option, value, "gfx_center_horizontal", &p->gfx_xcenter, centermode1, 1)
+       || cfgfile_strval (option, value, "gfx_center_vertical", &p->gfx_ycenter, centermode1, 1)
+       || cfgfile_strval (option, value, "gfx_center_horizontal", &p->gfx_xcenter, centermode2, 0)
+       || cfgfile_strval (option, value, "gfx_center_vertical", &p->gfx_ycenter, centermode2, 0)
+       || cfgfile_strval (option, value, "gfx_colour_mode", &p->color_mode, colormode1, 1)
+       || cfgfile_strval (option, value, "gfx_colour_mode", &p->color_mode, colormode2, 0)
+       || cfgfile_strval (option, value, "gfx_color_mode", &p->color_mode, colormode1, 1)
+       || cfgfile_strval (option, value, "gfx_color_mode", &p->color_mode, colormode2, 0))
+           return 1;
+       
+
+#ifdef GFXFILTER
+    if (strcmp (option,"gfx_filter") == 0) {
+       int i = 0;
+       p->gfx_filter = 0;
+       while(uaefilters[i].name) {
+           if (!strcmp (uaefilters[i].cfgname, value)) {
+               p->gfx_filter = uaefilters[i].type;
+               break;
+           }
+           i++;
+       }
+       return 1;
+    }
+    if (strcmp (option,"gfx_filter_mode") == 0) {
+       p->gfx_filter_filtermode = 0;
+       if (p->gfx_filter > 0) {
+           struct uae_filter *uf;
+           int i = 0;
+           while(uaefilters[i].name) {
+               uf = &uaefilters[i];
+               if (uf->type == p->gfx_filter) {
+                   if (uf->x[0]) {
+                       cfgfile_strval (option, value, "gfx_filter_mode", &p->gfx_filter_filtermode, filtermode1, 0);
+                   } else {
+                       int mt[4], j;
+                       i = 0;
+                       if (uf->x[1]) mt[i++] = 1;
+                       if (uf->x[2]) mt[i++] = 2;
+                       if (uf->x[3]) mt[i++] = 3;
+                       if (uf->x[4]) mt[i++] = 4;
+                       cfgfile_strval (option, value, "gfx_filter_mode", &i, filtermode2, 0);
+                       for (j = 0; j < i; j++) {
+                           if (mt[j] == i)
+                               p->gfx_filter_filtermode = j;
+                       }
+                   }
+                   break;
+               }
+               i++;
+           }
+       }
+       return 1;
+    }
+#endif
+
+    if (strcmp (option, "gfx_width") == 0 || strcmp (option, "gfx_height") == 0) {
+       cfgfile_intval (option, value, "gfx_width", &p->gfx_width_win, 1);
+       cfgfile_intval (option, value, "gfx_height", &p->gfx_height_win, 1);
+       p->gfx_width_fs = p->gfx_width_win;
+       p->gfx_height_fs = p->gfx_height_win;
+       return 1;
+    }
+
+    if (cfgfile_string (option, value, "statefile", tmpbuf, sizeof (tmpbuf))) {
+       savestate_state = STATE_DORESTORE;
+       strcpy (savestate_fname, tmpbuf);
+       return 1;
+    }
+
+    if (cfgfile_strval (option, value, "sound_channels", &p->stereo, stereomode1, 1)
+       || cfgfile_strval (option, value, "sound_channels", &p->stereo, stereomode2, 1)
+       || cfgfile_strval (option, value, "sound_channels", &p->stereo, stereomode3, 0))
+    {
+       p->mixed_stereo = 0;
+       if (p->stereo == 2) {
+           p->stereo = 1;
+           p->mixed_stereo = 1;
+       }
+       return 1;
+    }
+
+    if (strcmp (option, "kbd_lang") == 0) {
+       KbdLang l;
+       if ((l = KBD_LANG_DE, strcasecmp (value, "de") == 0)
+           || (l = KBD_LANG_DK, strcasecmp (value, "dk") == 0)
+           || (l = KBD_LANG_SE, strcasecmp (value, "se") == 0)
+           || (l = KBD_LANG_US, strcasecmp (value, "us") == 0)
+           || (l = KBD_LANG_FR, strcasecmp (value, "fr") == 0)
+           || (l = KBD_LANG_IT, strcasecmp (value, "it") == 0)
+           || (l = KBD_LANG_ES, strcasecmp (value, "es") == 0))
+           p->keyboard_lang = l;
+       else
+           write_log ("Unknown keyboard language\n");
+       return 1;
+    }
+
+    if (cfgfile_string (option, value, "config_version", tmpbuf, sizeof (tmpbuf))) {
+       char *tmpp2;
+       tmpp = strchr (value, '.');
+       if (tmpp) {
+           *tmpp++ = 0;
+           tmpp2 = tmpp;
+           p->config_version = atol (tmpbuf) << 16;
+           tmpp = strchr (tmpp, '.');
+           if (tmpp) {
+               *tmpp++ = 0;
+               p->config_version |= atol (tmpp2) << 8;
+               p->config_version |= atol (tmpp);
+           }
+       }
+       return 1;
+    }
+
+    if (cfgfile_string (option, value, "keyboard_leds", tmpbuf, sizeof (tmpbuf))) {
+        char *tmpp2 = tmpbuf;
+       int i, num;
+       p->keyboard_leds[0] = p->keyboard_leds[1] = p->keyboard_leds[2] = 0;
+       p->keyboard_leds_in_use = 0;
+       strcat (tmpbuf, ",");
+       for (i = 0; i < 3; i++) {
+           tmpp = strchr (tmpp2, ':');
+           if (!tmpp)
+               break;
+           *tmpp++= 0;
+           num = -1;
+           if (!strcasecmp (tmpp2, "numlock")) num = 0;
+           if (!strcasecmp (tmpp2, "capslock")) num = 1;
+           if (!strcasecmp (tmpp2, "scrolllock")) num = 2;
+           tmpp2 = tmpp;
+           tmpp = strchr (tmpp2, ',');
+           if (!tmpp)
+               break;
+           *tmpp++= 0;
+           if (num >= 0) {
+               p->keyboard_leds[num] = match_string (kbleds, tmpp2);
+               if (p->keyboard_leds[num]) p->keyboard_leds_in_use = 1;
+           }
+           tmpp2 = tmpp;
+       }
+       return 1;
+    }
+
+    return 0;
+}
+
+static int cfgfile_parse_hardware (struct uae_prefs *p, char *option, char *value)
+{
+    int tmpval;
+    int dummy;
+    char *section = 0;
+
+    if (cfgfile_yesno (option, value, "immediate_blits", &p->immediate_blits)
+       || cfgfile_yesno (option, value, "fast_copper", &p->fast_copper)
+       || cfgfile_yesno (option, value, "kickshifter", &p->kickshifter)
+       || cfgfile_yesno (option, value, "ntsc", &p->ntscmode)
+       || cfgfile_yesno (option, value, "cpu_compatible", &p->cpu_compatible)
+       || cfgfile_yesno (option, value, "cpu_cycle_exact", &p->cpu_cycle_exact)
+       || cfgfile_yesno (option, value, "blitter_cycle_exact", &p->blitter_cycle_exact)
+       || cfgfile_yesno (option, value, "cpu_24bit_addressing", &p->address_space_24)
+       || cfgfile_yesno (option, value, "parallel_on_demand", &p->parallel_demand)
+       || cfgfile_yesno (option, value, "serial_on_demand", &p->serial_demand)
+       || cfgfile_yesno (option, value, "serial_hardware_ctsrts", &p->serial_hwctsrts)
+       || cfgfile_yesno (option, value, "serial_direct", &p->serial_direct)
+       || cfgfile_yesno (option, value, "comp_nf", &p->compnf)
+       || cfgfile_yesno (option, value, "comp_constjump", &p->comp_constjump)
+       || cfgfile_yesno (option, value, "comp_oldsegv", &p->comp_oldsegv)
+       || cfgfile_yesno (option, value, "compforcesettings", &p->compforcesettings)
+       || cfgfile_yesno (option, value, "compfpu", &p->compfpu)
+       || cfgfile_yesno (option, value, "comp_midopt", &p->comp_midopt)
+       || cfgfile_yesno (option, value, "comp_lowopt", &p->comp_lowopt)
+       || cfgfile_yesno (option, value, "scsi", &p->scsi))
+       return 1;
+    if (cfgfile_intval (option, value, "cachesize", &p->cachesize, 1)
+       || cfgfile_intval (option, value, "fastmem_size", &p->fastmem_size, 0x100000)
+       || cfgfile_intval (option, value, "a3000mem_size", &p->a3000mem_size, 0x100000)
+       || cfgfile_intval (option, value, "z3mem_size", &p->z3fastmem_size, 0x100000)
+       || cfgfile_intval (option, value, "bogomem_size", &p->bogomem_size, 0x40000)
+       || cfgfile_intval (option, value, "gfxcard_size", &p->gfxmem_size, 0x100000)
+       || cfgfile_intval (option, value, "floppy_speed", &p->floppy_speed, 1)
+       || cfgfile_intval (option, value, "nr_floppies", &p->nr_floppies, 1)
+       || cfgfile_intval (option, value, "floppy0type", &p->dfxtype[0], 1)
+       || cfgfile_intval (option, value, "floppy1type", &p->dfxtype[1], 1)
+       || cfgfile_intval (option, value, "floppy2type", &p->dfxtype[2], 1)
+       || cfgfile_intval (option, value, "floppy3type", &p->dfxtype[3], 1)
+       || cfgfile_intval (option, value, "maprom", &p->maprom, 1)
+       || cfgfile_intval (option, value, "catweasel_io", &p->catweasel_io, 1))
+       return 1;
+    if (cfgfile_strval (option, value, "comp_trustbyte", &p->comptrustbyte, compmode, 0)
+       || cfgfile_strval (option, value, "comp_trustword", &p->comptrustword, compmode, 0)
+       || cfgfile_strval (option, value, "comp_trustlong", &p->comptrustlong, compmode, 0)
+       || cfgfile_strval (option, value, "comp_trustnaddr", &p->comptrustnaddr, compmode, 0)
+       || cfgfile_strval (option, value, "collision_level", &p->collision_level, collmode, 0)
+       || cfgfile_strval (option, value, "comp_flushmode", &p->comp_hardflush, flushmode, 0))
+       return 1;
+    if (cfgfile_string (option, value, "floppy0", p->df[0], 256)
+       || cfgfile_string (option, value, "floppy1", p->df[1], 256)
+       || cfgfile_string (option, value, "floppy2", p->df[2], 256)
+       || cfgfile_string (option, value, "floppy3", p->df[3], 256)
+       || cfgfile_string (option, value, "kickstart_rom_file", p->romfile, 256)
+       || cfgfile_string (option, value, "kickstart_ext_rom_file", p->romextfile, 256)
+       || cfgfile_string (option, value, "kickstart_key_file", p->keyfile, 256)
+       || cfgfile_string (option, value, "flash_file", p->flashfile, 256)
+       || cfgfile_string (option, value, "cart_file", p->cartfile, 256)
+       || cfgfile_string (option, value, "pci_devices", p->pci_devices, 256))
+       return 1;
+
+    if (cfgfile_intval (option, value, "chipmem_size", &dummy, 1)) {
+       if (!dummy)
+           p->chipmem_size = 0x40000;
+       else
+           p->chipmem_size = dummy * 0x80000;
+       return 1;
+    }
+
+    if (cfgfile_strval (option, value, "chipset", &tmpval, csmode, 0)) {
+       set_chipset_mask (p, tmpval);
+       return 1;
+    }
+
+    if (cfgfile_strval (option, value, "cpu_type", &p->cpu_level, cpumode, 0)) {
+       p->address_space_24 = p->cpu_level < 8 && !(p->cpu_level & 1);
+       p->cpu_level >>= 1;
+       return 1;
+    }
+    if (p->config_version < (21 << 16)) {
+       if (cfgfile_strval (option, value, "cpu_speed", &p->m68k_speed, speedmode, 1)
+           /* Broken earlier versions used to write this out as a string.  */
+           || cfgfile_strval (option, value, "finegraincpu_speed", &p->m68k_speed, speedmode, 1))
+       {
+           p->m68k_speed--;
+           return 1;
+       }
+    }
+
+    if (cfgfile_intval (option, value, "cpu_speed", &p->m68k_speed, 1)) {
+        p->m68k_speed *= CYCLE_UNIT;
+       return 1;
+    }
+
+    if (cfgfile_intval (option, value, "finegrain_cpu_speed", &p->m68k_speed, 1)) {
+       if (OFFICIAL_CYCLE_UNIT > CYCLE_UNIT) {
+           int factor = OFFICIAL_CYCLE_UNIT / CYCLE_UNIT;
+           p->m68k_speed = (p->m68k_speed + factor - 1) / factor;
+       }
+        if (strcasecmp (value, "max") == 0) p->m68k_speed = -1;
+       return 1;
+    }
+
+    if (strcmp (option, "filesystem") == 0
+       || strcmp (option, "hardfile") == 0)
+    {
+       int secs, heads, reserved, bs, ro;
+       char *aname, *root;
+       char *tmpp = strchr (value, ',');
+       char *str;
+
+       if (config_newfilesystem)
+           return 1;
+
+       if (tmpp == 0)
+           goto invalid_fs;
+
+       *tmpp++ = '\0';
+       if (strcmp (value, "1") == 0 || strcasecmp (value, "ro") == 0
+           || strcasecmp (value, "readonly") == 0
+           || strcasecmp (value, "read-only") == 0)
+           ro = 1;
+       else if (strcmp (value, "0") == 0 || strcasecmp (value, "rw") == 0
+                || strcasecmp (value, "readwrite") == 0
+                || strcasecmp (value, "read-write") == 0)
+           ro = 0;
+       else
+           goto invalid_fs;
+       secs = 0; heads = 0; reserved = 0; bs = 0;
+
+       value = tmpp;
+       if (strcmp (option, "filesystem") == 0) {
+           tmpp = strchr (value, ':');
+           if (tmpp == 0)
+               goto invalid_fs;
+           *tmpp++ = '\0';
+           aname = value;
+           root = tmpp;
+       } else {
+           if (! getintval (&value, &secs, ',')
+               || ! getintval (&value, &heads, ',')
+               || ! getintval (&value, &reserved, ',')
+               || ! getintval (&value, &bs, ','))
+               goto invalid_fs;
+           root = value;
+           aname = 0;
+       }
+       str = cfgfile_subst_path (UNEXPANDED, p->path_hardfile, root);
+       tmpp = 0;
+#ifdef FILESYS
+       tmpp = add_filesys_unit (currprefs.mountinfo, 0, aname, str, ro, secs,
+                                heads, reserved, bs, 0, 0);
+#endif
+       free (str);
+       if (tmpp)
+           write_log ("Error: %s\n", tmpp);
+       return 1;
+
+    }
+
+    if (strcmp (option, "filesystem2") == 0
+       || strcmp (option, "hardfile2") == 0)
+    {
+       int secs, heads, reserved, bs, ro, bp;
+       char *dname, *aname, *root, *fs;
+       char *tmpp = strchr (value, ',');
+       char *str;
+       
+       config_newfilesystem = 1;
+       if (tmpp == 0)
+           goto invalid_fs;
+
+       *tmpp++ = '\0';
+       if (strcasecmp (value, "ro") == 0)
+           ro = 1;
+       else if (strcasecmp (value, "rw") == 0)
+           ro = 0;
+       else
+           goto invalid_fs;
+       secs = 0; heads = 0; reserved = 0; bs = 0; bp = 0;
+       fs = 0;
+
+       value = tmpp;
+       if (strcmp (option, "filesystem2") == 0) {
+           tmpp = strchr (value, ':');
+           if (tmpp == 0)
+               goto invalid_fs;
+           *tmpp++ = 0;
+           dname = value;
+           aname = tmpp;
+           tmpp = strchr (tmpp, ':');
+           if (tmpp == 0)
+               goto invalid_fs;
+           *tmpp++ = 0;
+           root = tmpp;
+           tmpp = strchr (tmpp, ',');
+           if (tmpp == 0)
+               goto invalid_fs;
+           *tmpp++ = 0;
+           if (! getintval (&tmpp, &bp, 0))
+               goto invalid_fs;
+       } else {
+           tmpp = strchr (value, ':');
+           if (tmpp == 0)
+               goto invalid_fs;
+           *tmpp++ = '\0';
+           dname = value;
+           root = tmpp;
+           tmpp = strchr (tmpp, ',');
+           if (tmpp == 0)
+               goto invalid_fs;
+           *tmpp++ = 0;
+           aname = 0;
+           if (! getintval (&tmpp, &secs, ',')
+               || ! getintval (&tmpp, &heads, ',')
+               || ! getintval (&tmpp, &reserved, ',')
+               || ! getintval (&tmpp, &bs, ','))
+               goto invalid_fs;
+           if (getintval2 (&tmpp, &bp, ',')) {
+               fs = tmpp;
+               tmpp = strchr (tmpp, ',');
+               if (tmpp != 0)
+                   *tmpp = 0;
+           }
+       }
+       str = cfgfile_subst_path (UNEXPANDED, p->path_hardfile, root);
+       tmpp = 0;
+#ifdef FILESYS
+       tmpp = add_filesys_unit (currprefs.mountinfo, dname, aname, str, ro, secs,
+                                heads, reserved, bs, bp, fs);
+#endif
+       free (str);
+       if (tmpp)
+           write_log ("Error: %s\n", tmpp);
+       return 1;
+
+      invalid_fs:
+       write_log ("Invalid filesystem/hardfile specification.\n");
+       return 1;
+    }
+
+    return 0;
+}
+
+int cfgfile_parse_option (struct uae_prefs *p, char *option, char *value, int type)
+{
+    if (!strcmp (option, "config_hardware"))
+       return 1;
+    if (!strcmp (option, "config_host"))
+       return 1;
+    if (type == 0 || (type & CONFIG_TYPE_HARDWARE)) {
+       if (cfgfile_parse_hardware (p, option, value))
+           return 1;
+    }
+    if (type == 0 || (type & CONFIG_TYPE_HOST)) {
+       if (cfgfile_parse_host (p, option, value))
+           return 1;
+    }
+    if (type > 0)
+       return 1;
+    return 0;
+}
+
+static int separate_line (char *line, char *line1b, char *line2b)
+{
+    char *line1, *line2;
+    int i;
+
+    line1 = line;
+    line2 = strchr (line, '=');
+    if (! line2) {
+       write_log ("CFGFILE: line was incomplete with only %s\n", line1);
+       return 0;
+    }
+    *line2++ = '\0';
+    strcpy (line1b, line1);
+    strcpy (line2b, line2);
+
+    /* Get rid of whitespace.  */
+    i = strlen (line2);
+    while (i > 0 && (line2[i - 1] == '\t' || line2[i - 1] == ' '
+                    || line2[i - 1] == '\r' || line2[i - 1] == '\n'))
+       line2[--i] = '\0';
+    line2 += strspn (line2, "\t \r\n");
+    strcpy (line2b, line2);
+    i = strlen (line);
+    while (i > 0 && (line[i - 1] == '\t' || line[i - 1] == ' '
+                    || line[i - 1] == '\r' || line[i - 1] == '\n'))
+       line[--i] = '\0';
+    line += strspn (line, "\t \r\n");
+    strcpy (line1b, line);
+    return 1;
+}
+
+static int isobsolete (char *s)
+{
+    int i = 0;
+    while (obsolete[i]) {
+       if (!strcasecmp (s, obsolete[i])) {
+           write_log ("obsolete config entry '%s'\n", s);
+           return 1;
+       }
+       i++;
+    }
+    if (strlen (s) >= 10 && !memcmp (s, "gfx_opengl", 10)) {
+       write_log ("obsolete config entry '%s\n", s);
+       return 1;
+    }
+    if (strlen (s) >= 6 && !memcmp (s, "gfx_3d", 6)) {
+       write_log ("obsolete config entry '%s\n", s);
+       return 1;
+    }
+    return 0;
+}
+
+static void cfgfile_parse_separated_line (struct uae_prefs *p, char *line1b, char *line2b, int type)
+{
+    char line3b[2560], line4b[2560];
+    struct strlist *sl;
+    int ret;
+
+    strcpy (line3b, line1b);
+    strcpy (line4b, line2b);
+    ret = cfgfile_parse_option (p, line1b, line2b, type);
+    if (!isobsolete (line3b)) {
+       for (sl = p->all_lines; sl; sl = sl->next) {
+           if (sl->option && !strcasecmp (line1b, sl->option)) break;
+       }
+       if (!sl) {
+           struct strlist *u = xcalloc (sizeof (struct strlist), 1);
+           u->option = my_strdup(line3b);
+           u->value = my_strdup(line4b);
+           u->next = p->all_lines;
+           p->all_lines = u;
+           if (!ret) {
+               u->unknown = 1;
+               write_log ("unknown config entry: '%s=%s'\n", u->option, u->value);
+           }
+       }
+    }
+}
+
+void cfgfile_parse_line (struct uae_prefs *p, char *line, int type)
+{
+    char line1b[2560], line2b[2560];
+
+    if (!separate_line (line, line1b, line2b))
+       return;
+    cfgfile_parse_separated_line (p, line1b, line2b, type);
+    return;
+}
+
+static void subst (char *p, char *f, int n)
+{
+    char *str = cfgfile_subst_path (UNEXPANDED, p, f);
+    strncpy (f, str, n - 1);
+    f[n - 1] = '\0';
+    free (str);
+}
+
+static char *cfg_fgets (char *line, int max, FILE *fh)
+{
+#ifdef SINGLEFILE
+    extern char singlefile_config[];
+    static char *sfile_ptr;
+    char *p;
+#endif
+
+    if (fh)
+       return fgets (line, max, fh);
+#ifdef SINGLEFILE
+    if (sfile_ptr == 0) {
+       sfile_ptr = singlefile_config;
+       if (*sfile_ptr) {
+           write_log ("singlefile config found\n");
+           while (*sfile_ptr++);
+       }
+    }
+    if (*sfile_ptr == 0) {
+       sfile_ptr = singlefile_config;
+       return 0;
+    }
+    p = sfile_ptr;
+    while (*p != 13 && *p != 10 && *p != 0) p++;
+    memset (line, 0, max);
+    memcpy (line, sfile_ptr, p - sfile_ptr);
+    sfile_ptr = p + 1;
+    if (*sfile_ptr == 13)
+       sfile_ptr++;
+    if (*sfile_ptr == 10)
+       sfile_ptr++;
+    return line;
+#endif
+    return 0;
+}
+
+static int cfgfile_load_2 (struct uae_prefs *p, const char *filename, int real, int *type)
+{
+    int i;
+    FILE *fh;
+    char line[2560], line1b[2560], line2b[2560];
+    struct strlist *sl;
+    int type1 = 0, type2 = 0, askedtype = 0;
+
+    if (type) {
+       askedtype = *type;
+       *type = 0;
+    }
+    if (real) {
+       p->config_version = 0;
+       config_newfilesystem = 0;
+       reset_inputdevice_config (p);
+    }
+
+    fh = fopen (filename, "r");
+#ifndef SINGLEFILE
+    if (! fh)
+       return 0;
+#endif
+
+    while (cfg_fgets (line, sizeof (line), fh) != 0) {
+       int len = strlen (line);
+       /* Delete trailing whitespace.  */
+       while (len > 0 && strcspn (line + len - 1, "\t \r\n") == 0) {
+           line[--len] = '\0';
+       }
+       if (strlen (line) > 0) {
+           if (line[0] == '#')
+               continue;
+           if (!separate_line (line, line1b, line2b))
+               continue;
+           type1 = type2 = 0;
+           if (cfgfile_yesno (line1b, line2b, "config_hardware", &type1) ||
+               cfgfile_yesno (line1b, line2b, "config_host", &type2)) {
+               if (type1 && type)
+                   *type |= CONFIG_TYPE_HARDWARE;
+               if (type2 && type)
+                   *type |= CONFIG_TYPE_HOST;
+               continue;
+           }
+           if (real) {
+               cfgfile_parse_separated_line (p, line1b, line2b, askedtype);
+           } else {
+               cfgfile_string (line1b, line2b, "config_description", p->description, 128);
+           }
+       }
+    }
+
+    if (type && *type == 0)
+       *type = CONFIG_TYPE_HARDWARE | CONFIG_TYPE_HOST;
+    if (fh)
+       fclose (fh);
+
+    if (!real)
+       return 1;
+
+    for (sl = temp_lines; sl; sl = sl->next) {
+       sprintf (line, "%s=%s", sl->option, sl->value);
+       cfgfile_parse_line (p, line, 0);
+    }
+
+    for (i = 0; i < 4; i++)
+       subst (p->path_floppy, p->df[i], sizeof p->df[i]);
+    subst (p->path_rom, p->romfile, sizeof p->romfile);
+    subst (p->path_rom, p->romextfile, sizeof p->romextfile);
+    subst (p->path_rom, p->keyfile, sizeof p->keyfile);
+
+    return 1;
+}
+
+int cfgfile_load (struct uae_prefs *p, const char *filename, int *type)
+{
+    write_log ("load config '%s'\n", filename);
+    return cfgfile_load_2 (p, filename, 1, type);
+}
+
+int cfgfile_save (struct uae_prefs *p, const char *filename, int type)
+{
+    FILE *fh = fopen (filename, "w");
+    write_log ("save config '%s'\n", filename);
+    if (! fh)
+       return 0;
+
+    if (!type)
+       type = CONFIG_TYPE_HARDWARE | CONFIG_TYPE_HOST;
+    save_options (fh, p, type);
+    fclose (fh);
+    return 1;
+}
+
+int cfgfile_get_description (const char *filename, char *description, int *type)
+{
+    int result = 0;
+    struct uae_prefs *p = xmalloc (sizeof (struct uae_prefs));
+    strcpy (p->description, "");
+    if (cfgfile_load_2 (p, filename, 0, type)) {
+       result = 1;
+       strcpy (description, p->description);
+    }
+    free (p);
+    return result;
+}
+
+void cfgfile_show_usage (void)
+{
+    int i;
+    write_log ("UAE Configuration Help:\n" \
+              "=======================\n");
+    for (i = 0; i < sizeof opttable / sizeof *opttable; i++)
+       write_log ("%s: %s\n", opttable[i].config_label, opttable[i].config_help);
+}
+
+/* This implements the old commandline option parsing.  I've re-added this
+   because the new way of doing things is painful for me (it requires me
+   to type a couple hundred characters when invoking UAE).  The following
+   is far less annoying to use.  */
+static void parse_gfx_specs (struct uae_prefs *p, char *spec)
+{
+    char *x0 = my_strdup (spec);
+    char *x1, *x2;
+
+    x1 = strchr (x0, ':');
+    if (x1 == 0)
+       goto argh;
+    x2 = strchr (x1+1, ':');
+    if (x2 == 0)
+       goto argh;
+    *x1++ = 0; *x2++ = 0;
+
+    p->gfx_width_win = p->gfx_width_fs = atoi (x0);
+    p->gfx_height_win = p->gfx_height_fs = atoi (x1);
+    p->gfx_lores = strchr (x2, 'l') != 0;
+    p->gfx_xcenter = strchr (x2, 'x') != 0 ? 1 : strchr (x2, 'X') != 0 ? 2 : 0;
+    p->gfx_ycenter = strchr (x2, 'y') != 0 ? 1 : strchr (x2, 'Y') != 0 ? 2 : 0;
+    p->gfx_linedbl = strchr (x2, 'd') != 0;
+    p->gfx_linedbl += 2 * (strchr (x2, 'D') != 0);
+    p->gfx_afullscreen = strchr (x2, 'a') != 0;
+    p->gfx_pfullscreen = strchr (x2, 'p') != 0;
+    p->gfx_correct_aspect = strchr (x2, 'c') != 0;
+
+    if (p->gfx_linedbl == 3) {
+       write_log ("You can't use both 'd' and 'D' modifiers in the display mode specification.\n");
+    }
+    
+    free (x0);
+    return;
+
+    argh:
+    write_log ("Bad display mode specification.\n");
+    write_log ("The format to use is: \"width:height:modifiers\"\n");
+    write_log ("Type \"uae -h\" for detailed help.\n");
+    free (x0);
+}
+
+static void parse_sound_spec (struct uae_prefs *p, char *spec)
+{
+    char *x0 = my_strdup (spec);
+    char *x1, *x2 = NULL, *x3 = NULL, *x4 = NULL, *x5 = NULL;
+
+    x1 = strchr (x0, ':');
+    if (x1 != NULL) {
+       *x1++ = '\0';
+       x2 = strchr (x1 + 1, ':');
+       if (x2 != NULL) {
+           *x2++ = '\0';
+           x3 = strchr (x2 + 1, ':');
+           if (x3 != NULL) {
+               *x3++ = '\0';
+               x4 = strchr (x3 + 1, ':');
+               if (x4 != NULL) {
+                   *x4++ = '\0';
+                   x5 = strchr (x4 + 1, ':');
+               }
+           }
+       }
+    }
+    p->produce_sound = atoi (x0);
+    if (x1) {
+       p->mixed_stereo = 0;
+       if (*x1 == 'S')
+           p->stereo = p->mixed_stereo = 1;
+       else if (*x1 == 's')
+           p->stereo = 1;
+       else
+           p->stereo = 0;
+    }
+    if (x2)
+       p->sound_bits = atoi (x2);
+    if (x3)
+       p->sound_freq = atoi (x3);
+    if (x4)
+       p->sound_maxbsiz = atoi (x4);
+    free (x0);
+    return;
+}
+
+
+static void parse_joy_spec (struct uae_prefs *p, char *spec)
+{
+    int v0 = 2, v1 = 0;
+    if (strlen(spec) != 2)
+       goto bad;
+
+    switch (spec[0]) {
+     case '0': v0 = 0; break;
+     case '1': v0 = 1; break;
+     case 'M': case 'm': v0 = 2; break;
+     case 'A': case 'a': v0 = 3; break;
+     case 'B': case 'b': v0 = 4; break;
+     case 'C': case 'c': v0 = 5; break;
+     default: goto bad;
+    }
+
+    switch (spec[1]) {
+     case '0': v1 = 0; break;
+     case '1': v1 = 1; break;
+     case 'M': case 'm': v1 = 2; break;
+     case 'A': case 'a': v1 = 3; break;
+     case 'B': case 'b': v1 = 4; break;
+     case 'C': case 'c': v1 = 5; break;
+     default: goto bad;
+    }
+    if (v0 == v1)
+       goto bad;
+    /* Let's scare Pascal programmers */
+    if (0)
+bad:
+    write_log ("Bad joystick mode specification. Use -J xy, where x and y\n"
+            "can be 0 for joystick 0, 1 for joystick 1, M for mouse, and\n"
+            "a, b or c for different keyboard settings.\n");
+
+    p->jport0 = v0;
+    p->jport1 = v1;
+}
+
+static void parse_filesys_spec (int readonly, char *spec)
+{
+    char buf[256];
+    char *s2;
+
+    strncpy (buf, spec, 255); buf[255] = 0;
+    s2 = strchr (buf, ':');
+    if (s2) {
+       *s2++ = '\0';
+#ifdef __DOS__
+       {
+           char *tmp;
+           while ((tmp = strchr (s2, '\\')))
+               *tmp = '/';
+       }
+#endif
+       s2 = 0;
+#ifdef FILESYS
+       s2 = add_filesys_unit (currprefs.mountinfo, 0, buf, s2, readonly, 0, 0, 0, 0, 0, 0);
+#endif
+       if (s2)
+           write_log ("%s\n", s2);
+    } else {
+       write_log ("Usage: [-m | -M] VOLNAME:mount_point\n");
+    }
+}
+static void parse_hardfile_spec (char *spec)
+{
+    char *x0 = my_strdup (spec);
+    char *x1, *x2, *x3, *x4;
+
+    x1 = strchr (x0, ':');
+    if (x1 == NULL)
+       goto argh;
+    *x1++ = '\0';
+    x2 = strchr (x1 + 1, ':');
+    if (x2 == NULL)
+       goto argh;
+    *x2++ = '\0';
+    x3 = strchr (x2 + 1, ':');
+    if (x3 == NULL)
+       goto argh;
+    *x3++ = '\0';
+    x4 = strchr (x3 + 1, ':');
+    if (x4 == NULL)
+       goto argh;
+    *x4++ = '\0';
+    x4 = 0;
+#ifdef FILESYS
+    x4 = add_filesys_unit (currprefs.mountinfo, 0, 0, x4, 0, atoi (x0), atoi (x1), atoi (x2), atoi (x3), 0, 0);
+#endif
+    if (x4)
+       write_log ("%s\n", x4);
+
+    free (x0);
+    return;
+
+ argh:
+    free (x0);
+    write_log ("Bad hardfile parameter specified - type \"uae -h\" for help.\n");
+    return;
+}
+
+static void parse_cpu_specs (struct uae_prefs *p, char *spec)
+{
+    if (*spec < '0' || *spec > '4') {
+       write_log ("CPU parameter string must begin with '0', '1', '2', '3' or '4'.\n");
+       return;
+    }
+       
+    p->cpu_level = *spec++ - '0';
+    p->address_space_24 = p->cpu_level < 2;
+    p->cpu_compatible = 0;
+    while (*spec != '\0') {
+       switch (*spec) {
+        case 'a':
+           if (p->cpu_level < 2)
+               write_log ("In 68000/68010 emulation, the address space is always 24 bit.\n");
+           else if (p->cpu_level >= 4)
+               write_log ("In 68040/060 emulation, the address space is always 32 bit.\n");
+           else
+               p->address_space_24 = 1;
+           break;
+        case 'c':
+           if (p->cpu_level != 0)
+               write_log  ("The more compatible CPU emulation is only available for 68000\n"
+                        "emulation, not for 68010 upwards.\n");
+           else
+               p->cpu_compatible = 1;
+           break;
+        default:
+           write_log  ("Bad CPU parameter specified - type \"uae -h\" for help.\n");
+           break;
+       }
+       spec++;
+    }
+}
+
+/* Returns the number of args used up (0 or 1).  */
+int parse_cmdline_option (struct uae_prefs *p, char c, char *arg)
+{
+    struct strlist *u = xcalloc (sizeof (struct strlist), 1);
+    const char arg_required[] = "0123rKpImWSAJwNCZUFcblOdHRv";
+
+    if (strchr (arg_required, c) && ! arg) {
+       write_log ("Missing argument for option `-%c'!\n", c);
+       return 0;
+    }
+
+    u->option = malloc (2);
+    u->option[0] = c;
+    u->option[1] = 0;
+    u->value = my_strdup(arg);
+    u->next = p->all_lines;
+    p->all_lines = u;
+
+    switch (c) {
+    case 'h': usage (); exit (0);
+
+    case '0': strncpy (p->df[0], arg, 255); p->df[0][255] = 0; break;
+    case '1': strncpy (p->df[1], arg, 255); p->df[1][255] = 0; break;
+    case '2': strncpy (p->df[2], arg, 255); p->df[2][255] = 0; break;
+    case '3': strncpy (p->df[3], arg, 255); p->df[3][255] = 0; break;
+    case 'r': strncpy (p->romfile, arg, 255); p->romfile[255] = 0; break;
+    case 'K': strncpy (p->keyfile, arg, 255); p->keyfile[255] = 0; break;
+    case 'p': strncpy (p->prtname, arg, 255); p->prtname[255] = 0; break;
+       /*     case 'I': strncpy (p->sername, arg, 255); p->sername[255] = 0; currprefs.use_serial = 1; break; */
+    case 'm': case 'M': parse_filesys_spec (c == 'M', arg); break;
+    case 'W': parse_hardfile_spec (arg); break;
+    case 'S': parse_sound_spec (p, arg); break;
+    case 'R': p->gfx_framerate = atoi (arg); break;
+    case 'x': p->no_xhair = 1; break;
+    case 'i': p->illegal_mem = 1; break;
+    case 'J': parse_joy_spec (p, arg); break;
+
+    case 't': p->test_drawing_speed = 1; break;
+#ifdef USE_X11_GFX
+    case 'L': p->x11_use_low_bandwidth = 1; break;
+    case 'T': p->x11_use_mitshm = 1; break;
+#endif
+    case 'w': p->m68k_speed = atoi (arg); break;
+
+       /* case 'g': p->use_gfxlib = 1; break; */
+    case 'G': p->start_gui = 0; break;
+    case 'D': p->start_debugger = 1; break;
+
+    case 'n':
+       if (strchr (arg, 'i') != 0)
+           p->immediate_blits = 1;
+       break;
+
+    case 'v':
+       set_chipset_mask (p, atoi (arg));
+       break;
+
+    case 'C':
+       parse_cpu_specs (p, arg);
+       break;
+
+    case 'Z':
+       p->z3fastmem_size = atoi (arg) * 0x100000;
+       break;
+
+    case 'U':
+       p->gfxmem_size = atoi (arg) * 0x100000;
+       break;
+
+    case 'F':
+       p->fastmem_size = atoi (arg) * 0x100000;
+       break;
+
+    case 'b':
+       p->bogomem_size = atoi (arg) * 0x40000;
+       break;
+
+    case 'c':
+       p->chipmem_size = atoi (arg) * 0x80000;
+       break;
+
+    case 'l':
+       if (0 == strcasecmp(arg, "de"))
+           p->keyboard_lang = KBD_LANG_DE;
+       else if (0 == strcasecmp(arg, "dk"))
+           p->keyboard_lang = KBD_LANG_DK;
+       else if (0 == strcasecmp(arg, "us"))
+           p->keyboard_lang = KBD_LANG_US;
+       else if (0 == strcasecmp(arg, "se"))
+           p->keyboard_lang = KBD_LANG_SE;
+       else if (0 == strcasecmp(arg, "fr"))
+           p->keyboard_lang = KBD_LANG_FR;
+       else if (0 == strcasecmp(arg, "it"))
+           p->keyboard_lang = KBD_LANG_IT;
+       else if (0 == strcasecmp(arg, "es"))
+           p->keyboard_lang = KBD_LANG_ES;
+       break;
+
+    case 'O': parse_gfx_specs (p, arg); break;
+    case 'd':
+       if (strchr (arg, 'S') != NULL || strchr (arg, 's')) {
+           write_log ("  Serial on demand.\n");
+           p->serial_demand = 1;
+       }
+       if (strchr (arg, 'P') != NULL || strchr (arg, 'p')) {
+           write_log ("  Parallel on demand.\n");
+           p->parallel_demand = 1;
+       }
+
+       break;
+
+    case 'H':
+       p->color_mode = atoi (arg);
+       if (p->color_mode < 0) {
+           write_log ("Bad color mode selected. Using default.\n");
+           p->color_mode = 0;
+       }
+       break;
+    default:
+       write_log ("Unknown option `-%c'!\n", c);
+       break;
+    }
+    return !! strchr (arg_required, c);
+}
+
+void cfgfile_addcfgparam (char *line)
+{
+    struct strlist *u;
+    char line1b[2560], line2b[2560];
+
+    if (!line) {
+       struct strlist **ps = &temp_lines;
+       while (*ps) {
+           struct strlist *s = *ps;
+           *ps = s->next;
+           free (s->value);
+           free (s->option);
+           free (s);
+       }
+       temp_lines = 0;
+       return;
+    }
+    if (!separate_line (line, line1b, line2b))
+       return;
+    u = xcalloc (sizeof (struct strlist), 1);
+    u->option = my_strdup(line1b);
+    u->value = my_strdup(line2b);
+    u->next = temp_lines;
+    temp_lines = u;
+}
+
+
+uae_u32 cfgfile_uaelib(int mode, uae_u32 name, uae_u32 dst, uae_u32 maxlen)
+{
+    char tmp[2000];
+    int i;
+    struct strlist *sl;
+
+    if (mode)
+       return 0;
+
+    for (i = 0; i < sizeof(tmp); i++) {
+       tmp[i] = get_byte (name + i);
+       if (tmp[i] == 0)
+           break;
+    }
+    tmp[sizeof(tmp) - 1] = 0;
+    if (tmp[0] == 0)
+       return 0;
+    for (sl = currprefs.all_lines; sl; sl = sl->next) {
+       if (!strcasecmp (sl->option, tmp))
+           break;
+    }
+
+    if (sl) {
+        for (i = 0; i < maxlen; i++) {
+           put_byte (dst + i, sl->value[i]);
+           if (sl->value[i] == 0)
+               break;
+        }
+       return dst;
+    }
+    return 0;
+}
+
+static void default_prefs_mini (struct uae_prefs *p, int type)
+{
+    strcpy (p->description, "UAE default A500 configuration");
+
+    p->nr_floppies = 1;
+    p->dfxtype[0] = 0;
+    p->dfxtype[1] = -1;
+    p->cpu_level = 0;
+    p->address_space_24 = 1;
+    p->chipmem_size = 0x00080000;
+    p->bogomem_size = 0x00080000;
+}
+
+#include "sounddep/sound.h"
+
+void default_prefs (struct uae_prefs *p, int type)
+{
+    memset (p, 0, sizeof (*p));
+    strcpy (p->description, "UAE default configuration");
+
+    p->start_gui = 1;
+    p->start_debugger = 0;
+
+    p->all_lines = 0;
+    /* Note to porters: please don't change any of these options! UAE is supposed
+     * to behave identically on all platforms if possible. */
+    p->illegal_mem = 0;
+    p->no_xhair = 0;
+    p->use_serial = 0;
+    p->serial_demand = 0;
+    p->serial_hwctsrts = 1;
+    p->parallel_demand = 0;
+
+    p->jport0 = 2;
+    p->jport1 = 0;
+    p->keyboard_lang = KBD_LANG_US;
+
+    p->produce_sound = 3;
+    p->stereo = 0;
+    p->sound_bits = DEFAULT_SOUND_BITS;
+    p->sound_freq = DEFAULT_SOUND_FREQ;
+    p->sound_maxbsiz = DEFAULT_SOUND_MAXB;
+    p->sound_interpol = 0;
+    p->sound_filter = 0;
+
+    p->comptrustbyte = 0;
+    p->comptrustword = 0;
+    p->comptrustlong = 0;
+    p->comptrustnaddr= 0;
+    p->compnf = 1;
+    p->comp_hardflush = 0;
+    p->comp_constjump = 1;
+    p->comp_oldsegv = 0;
+    p->compfpu = 1;
+    p->compforcesettings = 0;
+    p->cachesize = 0;
+    p->avoid_cmov = 0;
+    p->avoid_dga = 0;
+    p->avoid_vid = 0;
+    p->comp_midopt = 0;
+    p->comp_lowopt = 0;
+    p->override_dga_address = 0;
+    {
+       int i;
+       for (i = 0;i < 10; i++)
+           p->optcount[i] = -1;
+       p->optcount[0] = 4; /* How often a block has to be executed before it
+                            is translated */
+       p->optcount[1] = 0; /* How often to use the naive translation */
+       p->optcount[2] = 0; 
+       p->optcount[3] = 0;
+       p->optcount[4] = 0;
+       p->optcount[5] = 0;
+    }
+    p->gfx_framerate = 1;
+    p->gfx_width_win = p->gfx_width_fs = 800;
+    p->gfx_height_win = p->gfx_height_fs = 600;
+    p->gfx_lores = 0;
+    p->gfx_linedbl = 2;
+    p->gfx_afullscreen = 0;
+    p->gfx_pfullscreen = 0;
+    p->gfx_correct_aspect = 0;
+    p->gfx_xcenter = 0;
+    p->gfx_ycenter = 0;
+    p->color_mode = 0;
+
+    p->x11_use_low_bandwidth = 0;
+    p->x11_use_mitshm = 0;
+    p->x11_hide_cursor = 1;
+
+    p->svga_no_linear = 0;
+
+    p->curses_reverse_video = 0;
+
+    target_default_options (p);
+
+    p->immediate_blits = 0;
+    p->collision_level = 2;
+    p->leds_on_screen = 0;
+    p->keyboard_leds_in_use = 0;
+    p->keyboard_leds[0] = p->keyboard_leds[1] = p->keyboard_leds[2] = 0;
+    p->fast_copper = 1;
+    p->scsi = 0;
+    p->cpu_idle = 0;
+    p->catweasel_io = 0;
+    p->tod_hack = 0;
+    p->maprom = 0;
+
+    p->gfx_filter = 0;
+    p->gfx_filter_filtermode = 1;
+    p->gfx_filter_scanlineratio = (1 << 4) | 1;
+
+    strcpy (p->df[0], "df0.adf");
+    strcpy (p->df[1], "df1.adf");
+    strcpy (p->df[2], "df2.adf");
+    strcpy (p->df[3], "df3.adf");
+
+    strcpy (p->romfile, "kick.rom");
+    strcpy (p->keyfile, "");
+    strcpy (p->romextfile, "");
+    strcpy (p->flashfile, "");
+    strcpy (p->cartfile, "");
+
+    strcpy (p->path_rom, "./");
+    strcpy (p->path_floppy, "./");
+    strcpy (p->path_hardfile, "./");
+
+    strcpy (p->prtname, DEFPRTNAME);
+    strcpy (p->sername, DEFSERNAME);
+
+#ifdef CPUEMU_68000_ONLY
+    p->cpu_level = 0;
+    p->m68k_speed = 0;
+#else
+    p->m68k_speed = -1;
+    p->cpu_level = 2;
+#endif
+#ifdef CPUEMU_0
+    p->cpu_compatible = 0;
+    p->address_space_24 = 0;
+#else
+    p->cpu_compatible = 1;
+    p->address_space_24 = 1;
+#endif
+    p->cpu_cycle_exact = 0;
+    p->blitter_cycle_exact = 0;
+    p->chipset_mask = CSMASK_ECS_AGNUS;
+
+    p->fastmem_size = 0x00000000;
+    p->a3000mem_size = 0x00000000;
+    p->z3fastmem_size = 0x00000000;
+    p->chipmem_size = 0x00200000;
+    p->bogomem_size = 0x00000000;
+    p->gfxmem_size = 0x00000000;
+
+    p->nr_floppies = 2;
+    p->dfxtype[0] = 0;
+    p->dfxtype[1] = 0;
+    p->dfxtype[2] = -1;
+    p->dfxtype[3] = -1;
+    p->floppy_speed = 100;
+    p->dfxclickvolume = 33;
+
+    p->statecapturebuffersize = 20 * 1024 * 1024;
+    p->statecapturerate = 5 * 50;
+    p->statecapture = 0;
+
+#ifdef FILESYS
+    p->mountinfo = alloc_mountinfo ();
+#endif
+
+#ifdef UAE_MINI
+    default_prefs_mini (p);
+#endif
+
+    inputdevice_default_prefs (p);
+}
diff --git a/cia.c b/cia.c
new file mode 100755 (executable)
index 0000000..2cc108e
--- /dev/null
+++ b/cia.c
@@ -0,0 +1,1409 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * CIA chip support
+  *
+  * Copyright 1995 Bernd Schmidt, Alessandro Bissacco
+  * Copyright 1996, 1997 Stefan Reinauer, Christian Schmitt
+  */
+
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+#include <assert.h>
+
+#include "config.h"
+#include "options.h"
+#include "threaddep/thread.h"
+#include "events.h"
+#include "memory.h"
+#include "custom.h"
+#include "cia.h"
+#include "serial.h"
+#include "disk.h"
+#include "xwin.h"
+#include "keybuf.h"
+#include "gui.h"
+#include "savestate.h"
+#include "inputdevice.h"
+#include "zfile.h"
+#include "ar.h"
+#ifdef CD32
+#include "akiko.h"
+#endif
+#include "debug.h"
+
+//#define CIA_DEBUG
+//#define DONGLE_DEBUG
+
+#define TOD_HACK
+
+#define DIV10 (10 * CYCLE_UNIT / 2) /* Yes, a bad identifier. */
+
+/* battclock stuff */
+#define RTC_D_ADJ      8
+#define RTC_D_IRQ      4
+#define RTC_D_BUSY     2
+#define RTC_D_HOLD     1
+#define RTC_E_t1       8
+#define RTC_E_t0       4
+#define RTC_E_INTR     2
+#define RTC_E_MASK     1
+#define RTC_F_TEST     8
+#define RTC_F_24_12    4
+#define RTC_F_STOP     2
+#define RTC_F_RSET     1
+
+static unsigned int clock_control_d = RTC_D_ADJ + RTC_D_HOLD;
+static unsigned int clock_control_e = 0;
+static unsigned int clock_control_f = RTC_F_24_12;
+
+static unsigned int ciaaicr, ciaaimask, ciabicr, ciabimask;
+static unsigned int ciaacra, ciaacrb, ciabcra, ciabcrb;
+
+/* Values of the CIA timers.  */
+static unsigned long ciaata, ciaatb, ciabta, ciabtb;
+/* Computed by compute_passed_time.  */
+static unsigned long ciaata_passed, ciaatb_passed, ciabta_passed, ciabtb_passed;
+
+static unsigned long ciaatod, ciabtod, ciaatol, ciabtol, ciaaalarm, ciabalarm;
+static int ciaatlatch, ciabtlatch;
+static int oldled, oldovl;
+
+unsigned int ciabpra;
+
+unsigned int gui_ledstate;
+
+static unsigned long ciaala, ciaalb, ciabla, ciablb;
+static int ciaatodon, ciabtodon;
+static unsigned int ciaapra, ciaaprb, ciaadra, ciaadrb, ciaasdr, ciaasdr_cnt;
+static unsigned int ciabprb, ciabdra, ciabdrb, ciabsdr, ciabsdr_cnt;
+static int div10;
+static int kbstate, kback, ciaasdr_unread;
+#ifdef TOD_HACK
+static int tod_hack;
+#endif
+
+static uae_u8 serbits;
+
+static void setclr (unsigned int *p, unsigned int val)
+{
+    if (val & 0x80) {
+       *p |= val & 0x7F;
+    } else {
+       *p &= ~val;
+    }
+}
+
+#include "newcpu.h"
+
+static void RethinkICRA (void)
+{
+    if (ciaaimask & ciaaicr) {
+       ciaaicr |= 0x80;
+       INTREQ_0 (0x8000 | 0x0008);
+    } else {
+       ciaaicr &= 0x7F;
+    }
+}
+
+static void RethinkICRB (void)
+{
+    if (ciabimask & ciabicr) {
+       ciabicr |= 0x80;
+       INTREQ_0 (0x8000 | 0x2000);
+    } else {
+       ciabicr &= 0x7F;
+    }
+}
+
+void rethink_cias (void)
+{
+    RethinkICRA ();
+    RethinkICRB ();
+}
+
+/* Figure out how many CIA timer cycles have passed for each timer since the
+   last call of CIA_calctimers.  */
+
+static void compute_passed_time (void)
+{
+    unsigned long int ccount = (get_cycles () - eventtab[ev_cia].oldcycles + div10);
+    unsigned long int ciaclocks = ccount / DIV10;
+
+    ciaata_passed = ciaatb_passed = ciabta_passed = ciabtb_passed = 0;
+
+    /* CIA A timers */
+    if ((ciaacra & 0x21) == 0x01) {
+       assert ((ciaata+1) >= ciaclocks);
+       ciaata_passed = ciaclocks;
+    }
+    if ((ciaacrb & 0x61) == 0x01) {
+       assert ((ciaatb+1) >= ciaclocks);
+       ciaatb_passed = ciaclocks;
+    }
+
+    /* CIA B timers */
+    if ((ciabcra & 0x21) == 0x01) {
+       assert ((ciabta+1) >= ciaclocks);
+       ciabta_passed = ciaclocks;
+    }
+    if ((ciabcrb & 0x61) == 0x01) {
+       assert ((ciabtb+1) >= ciaclocks);
+       ciabtb_passed = ciaclocks;
+    }
+}
+
+/* Called to advance all CIA timers to the current time.  This expects that
+   one of the timer values will be modified, and CIA_calctimers will be called
+   in the same cycle.  */
+
+static void CIA_update (void)
+{
+    unsigned long int ccount = (get_cycles () - eventtab[ev_cia].oldcycles + div10);
+    unsigned long int ciaclocks = ccount / DIV10;
+
+    int aovfla = 0, aovflb = 0, asp = 0, bovfla = 0, bovflb = 0, bsp = 0;
+
+    div10 = ccount % DIV10;
+
+    /* CIA A timers */
+    if ((ciaacra & 0x21) == 0x01) {
+       assert ((ciaata+1) >= ciaclocks);
+       if ((ciaata+1) == ciaclocks) {
+           if ((ciaacra & 0x48) == 0x40 && ciaasdr_cnt > 0 && --ciaasdr_cnt == 0)
+               asp = 1;
+           aovfla = 1;
+           if ((ciaacrb & 0x61) == 0x41) {
+               if (ciaatb-- == 0)
+                   aovflb = 1;
+           }
+       }
+       ciaata -= ciaclocks;
+    }
+    if ((ciaacrb & 0x61) == 0x01) {
+       assert ((ciaatb+1) >= ciaclocks);
+       if ((ciaatb+1) == ciaclocks) aovflb = 1;
+       ciaatb -= ciaclocks;
+    }
+
+    /* CIA B timers */
+    if ((ciabcra & 0x21) == 0x01) {
+       assert ((ciabta+1) >= ciaclocks);
+       if ((ciabta+1) == ciaclocks) {
+           if ((ciabcra & 0x48) == 0x40 && ciabsdr_cnt > 0 && --ciabsdr_cnt == 0)
+               bsp = 1;
+           bovfla = 1;
+           if ((ciabcrb & 0x61) == 0x41) {
+               if (ciabtb-- == 0)
+                   bovflb = 1;
+           }
+       }
+       ciabta -= ciaclocks;
+    }
+    if ((ciabcrb & 0x61) == 0x01) {
+       assert ((ciabtb+1) >= ciaclocks);
+       if ((ciabtb+1) == ciaclocks) bovflb = 1;
+       ciabtb -= ciaclocks;
+    }
+
+    if (aovfla) {
+       ciaaicr |= 1; RethinkICRA();
+       ciaata = ciaala;
+       if (ciaacra & 0x8) ciaacra &= ~1;
+    }
+    if (aovflb) {
+       ciaaicr |= 2; RethinkICRA();
+       ciaatb = ciaalb;
+       if (ciaacrb & 0x8) ciaacrb &= ~1;
+    }
+    if (asp) {
+       ciaaicr |= 8; RethinkICRA();
+    }
+    if (bovfla) {
+       ciabicr |= 1; RethinkICRB();
+       ciabta = ciabla;
+       if (ciabcra & 0x8) ciabcra &= ~1;
+    }
+    if (bovflb) {
+       ciabicr |= 2; RethinkICRB();
+       ciabtb = ciablb;
+       if (ciabcrb & 0x8) ciabcrb &= ~1;
+    }
+    if (bsp) {
+       ciabicr |= 8; RethinkICRB();
+    }
+}
+
+/* Call this only after CIA_update has been called in the same cycle.  */
+
+static void CIA_calctimers (void)
+{
+    long int ciaatimea = -1, ciaatimeb = -1, ciabtimea = -1, ciabtimeb = -1;
+
+    eventtab[ev_cia].oldcycles = get_cycles ();
+    if ((ciaacra & 0x21) == 0x01) {
+       ciaatimea = (DIV10 - div10) + DIV10 * ciaata;
+    }
+    if ((ciaacrb & 0x61) == 0x41) {
+       /* Timer B will not get any pulses if Timer A is off. */
+       if (ciaatimea >= 0) {
+           /* If Timer A is in one-shot mode, and Timer B needs more than
+            * one pulse, it will not underflow. */
+           if (ciaatb == 0 || (ciaacra & 0x8) == 0) {
+               /* Otherwise, we can determine the time of the underflow. */
+               /* This may overflow, however.  So just ignore this timer and
+                  use the fact that we'll call CIA_handler for the A timer.  */
+#if 0
+               ciaatimeb = ciaatimea + ciaala * DIV10 * ciaatb;
+#endif
+           }
+       }
+    }
+    if ((ciaacrb & 0x61) == 0x01) {
+       ciaatimeb = (DIV10 - div10) + DIV10 * ciaatb;
+    }
+
+    if ((ciabcra & 0x21) == 0x01) {
+       ciabtimea = (DIV10 - div10) + DIV10 * ciabta;
+    }
+    if ((ciabcrb & 0x61) == 0x41) {
+       /* Timer B will not get any pulses if Timer A is off. */
+       if (ciabtimea >= 0) {
+           /* If Timer A is in one-shot mode, and Timer B needs more than
+            * one pulse, it will not underflow. */
+           if (ciabtb == 0 || (ciabcra & 0x8) == 0) {
+               /* Otherwise, we can determine the time of the underflow. */
+#if 0
+               ciabtimeb = ciabtimea + ciabla * DIV10 * ciabtb;
+#endif
+           }
+       }
+    }
+    if ((ciabcrb & 0x61) == 0x01) {
+       ciabtimeb = (DIV10 - div10) + DIV10 * ciabtb;
+    }
+    eventtab[ev_cia].active = (ciaatimea != -1 || ciaatimeb != -1
+                              || ciabtimea != -1 || ciabtimeb != -1);
+    if (eventtab[ev_cia].active) {
+       unsigned long int ciatime = ~0L;
+       if (ciaatimea != -1) ciatime = ciaatimea;
+       if (ciaatimeb != -1 && ciaatimeb < ciatime) ciatime = ciaatimeb;
+       if (ciabtimea != -1 && ciabtimea < ciatime) ciatime = ciabtimea;
+       if (ciabtimeb != -1 && ciabtimeb < ciatime) ciatime = ciabtimeb;
+       eventtab[ev_cia].evtime = ciatime + get_cycles ();
+    }
+    events_schedule();
+}
+
+void CIA_handler (void)
+{
+    CIA_update ();
+    CIA_calctimers ();
+}
+
+void cia_diskindex (void)
+{
+    ciabicr |= 0x10;
+    RethinkICRB();
+}
+
+static void ciab_checkalarm (void)
+{
+    if (ciabtod != ciabalarm)
+       return;
+    ciabicr |= 4; RethinkICRB();
+}
+
+static void ciaa_checkalarm (void)
+{
+    if (ciaatod != ciaaalarm)
+       return;
+    ciaaicr |= 4; RethinkICRA();
+}
+
+void CIA_hsync_handler (void)
+{
+    static unsigned int keytime = 0, sleepyhead = 0;
+
+    if (ciabtodon) {
+       ciabtod++;
+       ciabtod &= 0xFFFFFF;
+       ciab_checkalarm ();
+    }
+
+    if (keys_available() && kback && (ciaacra & 0x40) == 0 && (++keytime & 15) == 0) {
+       /*
+        * This hack lets one possible ciaaicr cycle go by without any key
+        * being read, for every cycle in which a key is pulled out of the
+        * queue.  If no hack is used, a lot of key events just get lost
+        * when you type fast.  With a simple hack that waits for ciaasdr
+        * to be read before feeding it another, it will keep up until the
+        * queue gets about 14 characters ahead and then lose events, and
+        * the mouse pointer will freeze while typing is being taken in.
+        * With this hack, you can type 30 or 40 characters ahead with little
+        * or no lossage, and the mouse doesn't get stuck.  The tradeoff is
+        * that the total slowness of typing appearing on screen is worse.
+        */
+       if (ciaasdr_unread == 2) {
+           ciaasdr_unread = 0;
+       } else if (ciaasdr_unread == 0) {
+           switch (kbstate) {
+            case 0:
+               ciaasdr = (uae_s8)~0xFB; /* aaarghh... stupid compiler */
+               kbstate++;
+               break;
+            case 1:
+               kbstate++;
+               ciaasdr = (uae_s8)~0xFD;
+               break;
+            case 2:
+               ciaasdr = ~get_next_key();
+               ciaasdr_unread = 1;      /* interlock to prevent lost keystrokes */
+               break;
+           }
+           ciaaicr |= 8;
+           RethinkICRA();
+           sleepyhead = 0;
+       } else if (!(++sleepyhead & 15)) {
+           ciaasdr_unread = 0;          /* give up on this key event after unread for a long time */
+       }
+    }
+}
+
+#ifdef TOD_HACK
+static void tod_hack_reset (void)
+{
+    struct timeval tv;
+    uae_u32 rate = currprefs.ntscmode ? 60 : 50;
+    gettimeofday (&tv, NULL);
+    tod_hack = (uae_u32)(((uae_u64)tv.tv_sec) * rate  + tv.tv_usec / (1000000 / rate));
+    tod_hack += ciaatod;
+}
+#endif
+
+void CIA_vsync_handler ()
+{
+#ifdef TOD_HACK
+    if (currprefs.tod_hack && ciaatodon) {
+        struct timeval tv;
+       uae_u32 t, nt, rate = currprefs.ntscmode ? 60 : 50;
+       gettimeofday (&tv, NULL);
+       t = (uae_u32)(((uae_u64)tv.tv_sec) * rate + tv.tv_usec / (1000000 / rate));
+       nt = t - tod_hack;
+       if ((nt < ciaatod && ciaatod - nt < 10) || nt == ciaatod)
+           return; /* try not to count backwards */
+       ciaatod = nt;
+       ciaatod &= 0xffffff;
+       ciaa_checkalarm ();
+       return;
+    }
+#endif
+    if (ciaatodon) {
+       ciaatod++;
+       ciaatod &= 0xFFFFFF;
+       ciaa_checkalarm ();
+    }
+}
+
+static void bfe001_change (void)
+{
+    uae_u8 v = ciaapra;
+
+    v |= ~ciaadra; /* output is high when pin's direction is input */
+    if ((v & 2) != oldled) {
+       int led = (v & 2) ? 0 : 1;
+        oldled = v & 2;
+        gui_led (0, led);
+        gui_ledstate &= ~1;
+        gui_data.powerled = led;
+       gui_ledstate |= led;
+    }
+    if ((v & 1) != oldovl) {
+       oldovl = v & 1;
+        if (!oldovl || ersatzkickfile) {
+           map_overlay (1);
+       } else if (!(currprefs.chipset_mask & CSMASK_AGA)) {
+           /* pin disconnected in AGA chipset, CD audio mute on/off on CD32 */
+           map_overlay (0);
+        }
+    }
+}
+
+#ifdef PARALLEL_PORT
+extern int isprinter (void);
+extern int doprinter (uae_u8);
+#endif
+
+static uae_u8 ReadCIAA (unsigned int addr)
+{
+    unsigned int tmp;
+
+    compute_passed_time ();
+
+#ifdef CIA_DEBUG
+    write_log("R_CIAA: %02.2X %08.8X\n", addr, m68k_getpc());
+#endif
+    
+    switch (addr & 0xf) {
+    case 0:
+#ifdef ACTION_REPLAY
+       action_replay_ciaread();
+#endif
+       tmp = DISK_status() & 0x3c;
+       tmp |= handle_joystick_buttons (ciaadra);
+       tmp |= (ciaapra | (ciaadra ^ 3)) & 0x03;
+       if (ciaadra & 0x40)
+           tmp = (tmp & ~0x40) | (ciaapra & 0x40);
+       if (ciaadra & 0x80)
+           tmp = (tmp & ~0x80) | (ciaapra & 0x80);
+#ifdef DONGLE_DEBUG
+       if (notinrom())
+           write_log ("BFE001 R %02.2X %s\n", tmp, debuginfo(0));
+#endif
+       return tmp;
+    case 1:
+#ifdef PARALLEL_PORT
+       if (isprinter () > 0) {
+           tmp = ciaaprb;
+       } else if (isprinter () < 0) {
+           uae_u8 v;
+           parallel_direct_read_data (&v);
+           tmp = v;
+       } else {
+           tmp = handle_parport_joystick (0, ciaaprb, ciaadrb);
+       }
+#else
+       tmp = handle_parport_joystick (0, ciaaprb, ciaadrb);
+#ifdef DONGLE_DEBUG
+       if (notinrom())
+           write_log ("BFE101 R %02.2X %s\n", tmp, debuginfo(0));
+#endif
+#endif
+       return tmp;
+    case 2:
+#ifdef DONGLE_DEBUG
+       if (notinrom ())
+           write_log ("BFE201 R %02.2X %s\n", ciaadra, debuginfo(0));
+#endif
+       return ciaadra;
+    case 3:
+#ifdef DONGLE_DEBUG
+       if (notinrom ())
+           write_log ("BFE301 R %02.2X %s\n", ciaadrb, debuginfo(0));
+#endif
+       return ciaadrb;
+    case 4:
+       return (uae_u8)((ciaata - ciaata_passed) & 0xff);
+    case 5:
+       return (uae_u8)((ciaata - ciaata_passed) >> 8);
+    case 6:
+       return (uae_u8)((ciaatb - ciaatb_passed) & 0xff);
+    case 7:
+       return (uae_u8)((ciaatb - ciaatb_passed) >> 8);
+    case 8:
+       if (ciaatlatch) {
+           ciaatlatch = 0;
+           return (uae_u8)ciaatol;
+       } else
+           return (uae_u8)ciaatod;
+    case 9:
+       if (ciaatlatch)
+           return (uae_u8)(ciaatol >> 8);
+       else
+           return (uae_u8)(ciaatod >> 8);
+    case 10:
+       ciaatlatch = 1;
+       ciaatol = ciaatod; /* ??? only if not already latched? */
+       return (uae_u8)(ciaatol >> 16);
+    case 12:
+       if (ciaasdr_unread == 1)
+           ciaasdr_unread = 2;
+       return ciaasdr;
+    case 13:
+       tmp = ciaaicr; ciaaicr = 0; RethinkICRA();
+       return tmp;
+    case 14:
+       return ciaacra;
+    case 15:
+       return ciaacrb;
+    }
+    return 0;
+}
+
+static uae_u8 ReadCIAB (unsigned int addr)
+{
+    unsigned int tmp;
+
+#ifdef CIA_DEBUG
+    write_log("R_CIAB: %02.2X %08.8X\n", addr, m68k_getpc());
+#endif
+
+    compute_passed_time ();
+
+    switch (addr & 0xf) {
+    case 0:
+       tmp = 0;
+#ifdef SERIAL_PORT
+       if (currprefs.use_serial)
+           tmp = serial_readstatus(ciabdra);
+#endif
+#ifdef PARALLEL_PORT
+       if (isprinter () > 0) {
+           tmp |= ciabpra & (0x04 | 0x02 | 0x01);
+       } else if (isprinter () < 0) {
+           uae_u8 v;
+           parallel_direct_read_status (&v);
+           tmp |= v & 7;
+       } else {
+           tmp |= handle_parport_joystick (1, ciabpra, ciabdra);
+       }
+#endif
+#ifdef DONGLE_DEBUG
+       if (notinrom ())
+           write_log ("BFD000 R %02.2X %s\n", tmp, debuginfo(0));
+#endif
+       return tmp;
+    case 1:
+#ifdef DONGLE_DEBUG
+       if (notinrom ())
+           write_log ("BFD100 R %02.2X %s\n", ciabprb, debuginfo(0));
+#endif
+       return ciabprb;
+    case 2:
+       return ciabdra;
+    case 3:
+       return ciabdrb;
+    case 4:
+       return (uae_u8)((ciabta - ciabta_passed) & 0xff);
+    case 5:
+       return (uae_u8)((ciabta - ciabta_passed) >> 8);
+    case 6:
+       return (uae_u8)((ciabtb - ciabtb_passed) & 0xff);
+    case 7:
+       return (uae_u8)((ciabtb - ciabtb_passed) >> 8);
+    case 8:
+       if (ciabtlatch) {
+           ciabtlatch = 0;
+           return (uae_u8)ciabtol;
+       } else
+           return (uae_u8)ciabtod;
+    case 9:
+       if (ciabtlatch)
+           return (uae_u8)(ciabtol >> 8);
+       else
+           return (uae_u8)(ciabtod >> 8);
+    case 10:
+       ciabtlatch = 1;
+       ciabtol = ciabtod;
+       return (uae_u8)(ciabtol >> 16);
+    case 12:
+       return ciabsdr;
+    case 13:
+       tmp = ciabicr; ciabicr = 0; RethinkICRB();
+       return tmp;
+    case 14:
+       return ciabcra;
+    case 15:
+       return ciabcrb;
+    }
+    return 0;
+}
+
+static void WriteCIAA (uae_u16 addr,uae_u8 val)
+{
+#ifdef CIA_DEBUG
+    write_log("W_CIAA: %02.2X %02.2X %08.8X\n", addr, val, m68k_getpc());
+#endif
+    switch (addr & 0xf) {
+    case 0:
+#ifdef DONGLE_DEBUG
+       if (notinrom ())
+           write_log ("BFE001 W %02.2X %s\n", val, debuginfo(0));
+#endif
+       ciaapra = (ciaapra & ~0xc3) | (val & 0xc3);
+       bfe001_change ();
+       handle_cd32_joystick_cia (ciaapra, ciaadra);
+       break;
+    case 1:
+#ifdef DONGLE_DEBUG
+       if (notinrom ())
+           write_log ("BFE101 W %02.2X %s\n", val, debuginfo(0));
+#endif
+       ciaaprb = val;
+#ifdef PARALLEL_PORT
+       if (isprinter() > 0) {
+           doprinter (val);
+           ciaaicr |= 0x10;
+       } else if (isprinter() < 0) {
+           parallel_direct_write_data (val, ciaadrb);
+           ciaaicr |= 0x10;
+       }
+#endif
+       break;
+    case 2:
+#ifdef DONGLE_DEBUG
+       if (notinrom ())
+           write_log ("BFE201 W %02.2X %s\n", val, debuginfo(0));
+#endif
+       ciaadra = val; bfe001_change (); break;
+    case 3:
+#ifdef DONGLE_DEBUG
+       if (notinrom ())
+           write_log ("BFE301 W %02.2X %s\n", val, debuginfo(0));
+#endif
+       ciaadrb = val; break;
+    case 4:
+       CIA_update ();
+       ciaala = (ciaala & 0xff00) | val;
+       CIA_calctimers ();
+       break;
+    case 5:
+       CIA_update ();
+       ciaala = (ciaala & 0xff) | (val << 8);
+       if ((ciaacra & 1) == 0)
+           ciaata = ciaala;
+       if (ciaacra & 8) {
+           ciaata = ciaala;
+           ciaacra |= 1;
+       }
+       CIA_calctimers ();
+       break;
+    case 6:
+       CIA_update ();
+       ciaalb = (ciaalb & 0xff00) | val;
+       CIA_calctimers ();
+       break;
+    case 7:
+       CIA_update ();
+       ciaalb = (ciaalb & 0xff) | (val << 8);
+       if ((ciaacrb & 1) == 0)
+           ciaatb = ciaalb;
+       if (ciaacrb & 8) {
+           ciaatb = ciaalb;
+           ciaacrb |= 1;
+       }
+       CIA_calctimers ();
+       break;
+    case 8:
+       if (ciaacrb & 0x80) {
+           ciaaalarm = (ciaaalarm & ~0xff) | val;
+       } else {
+           ciaatod = (ciaatod & ~0xff) | val;
+           ciaatodon = 1;
+           ciaa_checkalarm ();
+#if 0
+#ifdef TOD_HACK
+           if (currprefs.tod_hack)
+               tod_hack_reset ();
+#endif
+#endif
+       }
+       break;
+    case 9:
+       if (ciaacrb & 0x80) {
+           ciaaalarm = (ciaaalarm & ~0xff00) | (val << 8);
+       } else {
+           ciaatod = (ciaatod & ~0xff00) | (val << 8);
+           ciaatodon = 0;
+       }
+       break;
+    case 10:
+       if (ciaacrb & 0x80) {
+           ciaaalarm = (ciaaalarm & ~0xff0000) | (val << 16);
+       } else {
+           ciaatod = (ciaatod & ~0xff0000) | (val << 16);
+           ciaatodon = 0;
+       }
+       break;
+    case 12:
+       CIA_update ();
+        ciaasdr = val;
+        if (ciaacra & 0x40) {
+           kback = 1;
+       } else {
+           ciaasdr_cnt = 0;
+        }
+        if ((ciaacra & 0x41) == 0x41)
+           ciaasdr_cnt = 8 * 2;
+       CIA_calctimers ();
+       break;
+    case 13:
+       setclr(&ciaaimask,val);
+       break;
+    case 14:
+       CIA_update ();
+       val &= 0x7f; /* bit 7 is unused */
+       ciaacra = val;
+       if (ciaacra & 0x10) {
+           ciaacra &= ~0x10;
+           ciaata = ciaala;
+       }
+       if (ciaacra & 0x40)
+           kback = 1;
+       CIA_calctimers ();
+       break;
+    case 15:
+       CIA_update ();
+       ciaacrb = val;
+       if (ciaacrb & 0x10) {
+           ciaacrb &= ~0x10;
+           ciaatb = ciaalb;
+       }
+       CIA_calctimers ();
+       break;
+    }
+}
+
+static void WriteCIAB (uae_u16 addr,uae_u8 val)
+{
+#ifdef CIA_DEBUG
+    write_log("W_CIAB: %02.2X %02.2X %08.8X\n", addr, val, m68k_getpc());
+#endif
+    switch (addr & 0xf) {
+    case 0:
+#ifdef DONGLE_DEBUG
+       if (notinrom ())
+           write_log ("BFD000 W %02.2X %s\n", val, debuginfo(0));
+#endif
+       ciabpra = val;
+#ifdef SERIAL_PORT
+       if (currprefs.use_serial)
+           serial_writestatus(ciabpra, ciabdra);
+#endif
+#ifdef PARALLEL_PORT
+       if (isprinter () < 0)
+           parallel_direct_write_status (val, ciabdra);
+#endif
+       break;
+    case 1:
+#ifdef DONGLE_DEBUG
+       if (notinrom ())
+           write_log ("BFD100 W %02.2X %s\n", val, debuginfo(0));
+#endif
+       ciabprb = val; DISK_select(val); break;
+    case 2:
+#ifdef DONGLE_DEBUG
+       if (notinrom ())
+           write_log ("BFD200 W %02.2X %s\n", val, debuginfo(0));
+#endif
+       ciabdra = val;
+#ifdef SERIAL_PORT
+       if (currprefs.use_serial)
+           serial_writestatus (ciabpra, ciabdra);
+#endif
+       break;
+    case 3:
+#ifdef DONGLE_DEBUG
+       if (notinrom ())
+           write_log ("BFD300 W %02.2X %s\n", val, debuginfo(0));
+#endif
+       ciabdrb = val; break;
+    case 4:
+       CIA_update ();
+       ciabla = (ciabla & 0xff00) | val;
+       CIA_calctimers ();
+       break;
+    case 5:
+       CIA_update ();
+       ciabla = (ciabla & 0xff) | (val << 8);
+       if ((ciabcra & 1) == 0)
+           ciabta = ciabla;
+       if (ciabcra & 8) {
+           ciabta = ciabla;
+           ciabcra |= 1;
+       }
+       CIA_calctimers ();
+       break;
+    case 6:
+       CIA_update ();
+       ciablb = (ciablb & 0xff00) | val;
+       CIA_calctimers ();
+       break;
+    case 7:
+       CIA_update ();
+       ciablb = (ciablb & 0xff) | (val << 8);
+       if ((ciabcrb & 1) == 0)
+           ciabtb = ciablb;
+       if (ciabcrb & 8) {
+           ciabtb = ciablb;
+           ciabcrb |= 1;
+       }
+       CIA_calctimers ();
+       break;
+    case 8:
+       if (ciabcrb & 0x80) {
+           ciabalarm = (ciabalarm & ~0xff) | val;
+       } else {
+           ciabtod = (ciabtod & ~0xff) | val;
+           ciabtodon = 1;
+           ciab_checkalarm ();
+       }
+       break;
+    case 9:
+       if (ciabcrb & 0x80) {
+           ciabalarm = (ciabalarm & ~0xff00) | (val << 8);
+       } else {
+           ciabtod = (ciabtod & ~0xff00) | (val << 8);
+           ciabtodon = 0;
+       }
+       break;
+    case 10:
+       if (ciabcrb & 0x80) {
+           ciabalarm = (ciabalarm & ~0xff0000) | (val << 16);
+       } else {
+           ciabtod = (ciabtod & ~0xff0000) | (val << 16);
+           ciabtodon = 0;
+       }
+       break;
+    case 12:
+       CIA_update ();
+       ciabsdr = val;
+       if ((ciabcra & 0x41) == 0x41)
+           ciabsdr_cnt = 8 * 2;
+       if ((ciabcra & 0x40) == 0)
+           ciabsdr_cnt = 0;
+       CIA_calctimers ();
+       break;
+    case 13:
+       setclr(&ciabimask,val);
+       break;
+    case 14:
+       CIA_update ();
+       val &= 0x7f; /* bit 7 is unused */
+       ciabcra = val;
+       if (ciabcra & 0x10) {
+           ciabcra &= ~0x10;
+           ciabta = ciabla;
+       }
+       CIA_calctimers ();
+       break;
+    case 15:
+       CIA_update ();
+       ciabcrb = val;
+       if (ciabcrb & 0x10) {
+           ciabcrb &= ~0x10;
+           ciabtb = ciablb;
+       }
+       CIA_calctimers ();
+       break;
+    }
+}
+
+void CIA_reset (void)
+{
+#ifdef TOD_HACK
+    tod_hack = 0;
+    if (currprefs.tod_hack)
+       tod_hack_reset ();
+#endif
+    kback = 1;
+    kbstate = 0;
+    ciaasdr_unread = 0;
+    serbits = 0;
+    oldovl = -1;
+    oldled = -1;
+
+    if (!savestate_state) {
+       ciaatlatch = ciabtlatch = 0;
+       ciaapra = 0; ciaadra = 0;
+       ciaatod = ciabtod = 0; ciaatodon = ciabtodon = 0;
+       ciaaicr = ciabicr = ciaaimask = ciabimask = 0;
+       ciaacra = ciaacrb = ciabcra = ciabcrb = 0x4; /* outmode = toggle; */
+       ciaala = ciaalb = ciabla = ciablb = ciaata = ciaatb = ciabta = ciabtb = 0xFFFF;
+       ciaaalarm = ciabalarm = 0;
+       ciabpra = 0x8C; ciabdra = 0;
+       div10 = 0;
+       ciaasdr_cnt = 0; ciaasdr = 0;
+       ciabsdr_cnt = 0; ciabsdr = 0;
+    }
+    CIA_calctimers ();
+    if (! ersatzkickfile)
+       map_overlay (0);
+#ifdef SERIAL_PORT
+    if (currprefs.use_serial && !savestate_state) 
+       serial_dtr_off (); /* Drop DTR at reset */
+#endif
+    if (savestate_state) {
+       bfe001_change ();
+       /* select drives */
+       DISK_select (ciabprb);
+    }
+#ifdef CD32
+    if (cd32_enabled) {
+       akiko_reset ();
+       if (!akiko_init ())
+           cd32_enabled = 0;
+    }
+#endif
+}
+
+void dumpcia (void)
+{
+    write_log("A: CRA %02x CRB %02x ICR %02x IM %02x TOD %06x %c%c TA %04x (%04x) TB %04x (%04x)\n",
+          ciaacra, ciaacrb, ciaaicr, ciaaimask, ciaatod,
+          ciaatlatch ? 'L' : ' ', ciaatodon ? ' ' : 'S', ciaata, ciaala, ciaatb, ciaalb);
+    write_log("B: CRA %02x CRB %02x ICR %02x IM %02x TOD %06x %c%c TA %04x (%04x) TB %04x (%04x)\n",
+          ciabcra, ciabcrb, ciaaicr, ciabimask, ciabtod,
+          ciabtlatch ? 'L' : ' ', ciabtodon ? ' ' : 'S', ciabta, ciabla, ciabtb, ciablb);
+}
+
+/* CIA memory access */
+
+static uae_u32 cia_lget (uaecptr) REGPARAM;
+static uae_u32 cia_wget (uaecptr) REGPARAM;
+static uae_u32 cia_bget (uaecptr) REGPARAM;
+static void cia_lput (uaecptr, uae_u32) REGPARAM;
+static void cia_wput (uaecptr, uae_u32) REGPARAM;
+static void cia_bput (uaecptr, uae_u32) REGPARAM;
+
+addrbank cia_bank = {
+    cia_lget, cia_wget, cia_bget,
+    cia_lput, cia_wput, cia_bput,
+    default_xlate, default_check, NULL
+};
+
+
+#ifdef CD32
+extern uae_u32 akiko_lget (uaecptr addr);
+extern uae_u32 akiko_wget (uaecptr addr);
+extern uae_u32 akiko_bget (uaecptr addr);
+extern void akiko_bput (uaecptr addr, uae_u32 value);
+extern void akiko_wput (uaecptr addr, uae_u32 value);
+extern void akiko_lput (uaecptr addr, uae_u32 value);
+#endif
+
+/* e-clock is 10 CPU cycles, 6 cycles low, 4 high
+ * data transfer happens during 4 high cycles
+ */
+
+#define ECLOCK_DATA_CYCLE 4
+
+static void cia_wait_pre (void)
+{
+#ifndef CUSTOM_SIMPLE
+    int div10 = (get_cycles () - eventtab[ev_cia].oldcycles) % DIV10;
+    int cycles;
+
+    cycles = 2 * CYCLE_UNIT / 2;
+    if (div10 > DIV10 * ECLOCK_DATA_CYCLE / 10) {
+       cycles += DIV10 - div10;
+       cycles += DIV10 * ECLOCK_DATA_CYCLE / 10;
+    } else {
+       cycles += DIV10 * ECLOCK_DATA_CYCLE / 10 - div10;
+    }
+    do_cycles (cycles);
+#endif
+}
+
+static void cia_wait_post (void)
+{
+    do_cycles (2 * CYCLE_UNIT / 2);
+}
+
+uae_u32 REGPARAM2 cia_bget (uaecptr addr)
+{
+    int r = (addr & 0xf00) >> 8;
+    uae_u8 v;
+
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+#ifdef CD32
+    if (cd32_enabled && addr >= AKIKO_BASE && addr < AKIKO_BASE_END)
+       return akiko_bget (addr);
+#endif
+    cia_wait_pre ();
+    v = 0xff;
+    switch ((addr >> 12) & 3)
+    {
+       case 0:
+       v = (addr & 1) ? ReadCIAA (r) : ReadCIAB (r);
+       break;
+       case 1:
+       v = (addr & 1) ? 0xff : ReadCIAB (r);
+       break;
+       case 2:
+       v = (addr & 1) ? ReadCIAA (r) : 0xff;
+       break;
+    }
+    cia_wait_post ();
+    return v;
+}
+
+uae_u32 REGPARAM2 cia_wget (uaecptr addr)
+{
+    int r = (addr & 0xf00) >> 8;
+    uae_u16 v;
+
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+#ifdef CD32
+    if (cd32_enabled && addr >= AKIKO_BASE && addr < AKIKO_BASE_END)
+       return akiko_wget (addr);
+#endif
+    cia_wait_pre ();
+    v = 0xffff;
+    switch ((addr >> 12) & 3)
+    {
+       case 0:
+       v = (ReadCIAB (r) << 8) | ReadCIAA (r);
+       break;
+       case 1:
+       v = (ReadCIAB (r) << 8) | 0xff;
+       break;
+       case 2:
+       v = (0xff << 8) | ReadCIAA (r);
+       break;
+    }
+    cia_wait_post ();
+    return v;
+}
+
+uae_u32 REGPARAM2 cia_lget (uaecptr addr)
+{
+    uae_u32 v;
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+#ifdef CD32
+    if (cd32_enabled && addr >= AKIKO_BASE && addr < AKIKO_BASE_END)
+       return akiko_lget (addr);
+#endif
+    v = cia_wget (addr) << 16;
+    v |= cia_wget (addr + 2);
+    return v;
+}
+
+void REGPARAM2 cia_bput (uaecptr addr, uae_u32 value)
+{
+    int r = (addr & 0xf00) >> 8;
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+#ifdef CD32
+    if (cd32_enabled && addr >= AKIKO_BASE && addr < AKIKO_BASE_END) {
+       akiko_bput (addr, value);
+       return;
+    }
+#endif
+    cia_wait_pre ();
+    if ((addr & 0x2000) == 0)
+       WriteCIAB (r, value);
+    if ((addr & 0x1000) == 0)
+       WriteCIAA (r, value);
+    cia_wait_post ();
+}
+
+void REGPARAM2 cia_wput (uaecptr addr, uae_u32 value)
+{
+    int r = (addr & 0xf00) >> 8;
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+#ifdef CD32
+    if (cd32_enabled && addr >= AKIKO_BASE && addr < AKIKO_BASE_END) {
+       akiko_wput (addr, value);
+       return;
+    }
+#endif
+    cia_wait_pre ();
+    if ((addr & 0x2000) == 0)
+       WriteCIAB (r, value >> 8);
+    if ((addr & 0x1000) == 0)
+       WriteCIAA (r, value & 0xff);
+    cia_wait_post ();
+}
+
+void REGPARAM2 cia_lput (uaecptr addr, uae_u32 value)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+#ifdef CD32
+    if (cd32_enabled && addr >= AKIKO_BASE && addr < AKIKO_BASE_END) {
+       akiko_lput (addr, value);
+       return;
+    }
+#endif
+    cia_wput (addr, value >> 16);
+    cia_wput (addr + 2, value & 0xffff);
+}
+
+#ifdef CDTV
+/* CDTV batterybacked RAM emulation */
+
+static uae_u8 cdtv_battram[4096];
+#define CDTV_NVRAM_MASK 4095
+#define CDTV_NVRAM_SIZE 2048
+int cdtv_enabled;
+
+static void cdtv_battram_reset (void)
+{
+    struct zfile *f = zfile_fopen (currprefs.flashfile,"rb");
+    if (!f)
+        return;
+    zfile_fread (cdtv_battram, CDTV_NVRAM_SIZE,1 ,f);
+    zfile_fclose (f);
+}
+
+static void cdtv_battram_write (int addr, int v)
+{
+    struct zfile *f;
+    int offset = addr & CDTV_NVRAM_MASK;
+    if (offset >= CDTV_NVRAM_SIZE) return;
+    if (cdtv_battram[offset] == v) return;
+    cdtv_battram[offset] = v;
+    f = zfile_fopen (currprefs.flashfile,"rb+");
+    if (!f)
+       return;
+    zfile_fseek (f, offset, SEEK_SET);
+    zfile_fwrite (cdtv_battram + offset, 1, 1, f);
+    zfile_fclose (f);
+}
+
+static uae_u8 cdtv_battram_read (int addr)
+{
+    uae_u8 v;
+    int offset;
+    offset = addr & CDTV_NVRAM_MASK;
+    if (offset >= CDTV_NVRAM_SIZE) return 0;
+    v =  cdtv_battram[offset];
+    return v;
+}
+#endif
+
+/* battclock memory access */
+
+static uae_u32 clock_lget (uaecptr) REGPARAM;
+static uae_u32 clock_wget (uaecptr) REGPARAM;
+static uae_u32 clock_bget (uaecptr) REGPARAM;
+static void clock_lput (uaecptr, uae_u32) REGPARAM;
+static void clock_wput (uaecptr, uae_u32) REGPARAM;
+static void clock_bput (uaecptr, uae_u32) REGPARAM;
+
+addrbank clock_bank = {
+    clock_lget, clock_wget, clock_bget,
+    clock_lput, clock_wput, clock_bput,
+    default_xlate, default_check, NULL
+};
+
+uae_u32 REGPARAM2 clock_lget (uaecptr addr)
+{
+    return (clock_wget (addr) << 16) | clock_wget (addr + 2);
+}
+
+uae_u32 REGPARAM2 clock_wget (uaecptr addr)
+{
+    return (clock_bget (addr) << 8) | clock_bget (addr + 1);
+}
+
+uae_u32 REGPARAM2 clock_bget (uaecptr addr)
+{
+    time_t t = time(0);
+    struct tm *ct;
+
+#ifdef CDTV
+    if (cdtv_enabled && addr >= 0xdc8000)
+       return cdtv_battram_read (addr);
+#endif
+    ct = localtime (&t);
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+    switch (addr & 0x3f) {
+    case 0x03: return ct->tm_sec % 10;
+    case 0x07: return ct->tm_sec / 10;
+    case 0x0b: return ct->tm_min % 10;
+    case 0x0f: return ct->tm_min / 10;
+    case 0x13: return ct->tm_hour % 10;
+    case 0x17: return ct->tm_hour / 10;
+    case 0x1b: return ct->tm_mday % 10;
+    case 0x1f: return ct->tm_mday / 10;
+    case 0x23: return (ct->tm_mon+1) % 10;
+    case 0x27: return (ct->tm_mon+1) / 10;
+    case 0x2b: return ct->tm_year % 10;
+    case 0x2f: return ct->tm_year / 10;
+    case 0x33: return ct->tm_wday;  /*Hack by -=SR=- */
+    case 0x37: return clock_control_d;
+    case 0x3b: return clock_control_e;
+    case 0x3f: return clock_control_f;
+    }
+    return 0;
+}
+
+void REGPARAM2 clock_lput (uaecptr addr, uae_u32 value)
+{
+    clock_wput (addr, value >> 16);
+    clock_wput (addr + 2, value);
+}
+
+void REGPARAM2 clock_wput (uaecptr addr, uae_u32 value)
+{
+    clock_bput (addr, value >> 8);
+    clock_bput (addr + 1, value);
+}
+
+void REGPARAM2 clock_bput (uaecptr addr, uae_u32 value)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+#ifdef CDTV
+    if (cdtv_enabled && addr >= 0xdc8000) {
+       cdtv_battram_write (addr, value);
+       return;
+    }
+#endif
+    switch (addr & 0x3f) {
+    case 0x37: clock_control_d = value; break;
+    case 0x3b: clock_control_e = value; break;
+    case 0x3f: clock_control_f = value; break;
+    }
+}
+
+/* CIA-A and CIA-B save/restore code */
+
+uae_u8 *restore_cia (int num, uae_u8 *src)
+{
+    uae_u8 b;
+    uae_u16 w;
+    uae_u32 l;
+
+    /* CIA registers */
+    b = restore_u8 ();                                 /* 0 PRA */
+    if (num) ciabpra = b; else ciaapra = b;
+    b = restore_u8 ();                                 /* 1 PRB */
+    if (num) ciabprb = b; else ciaaprb = b;
+    b = restore_u8 ();                                 /* 2 DDRA */
+    if (num) ciabdra = b; else ciaadra = b;
+    b = restore_u8 ();                                 /* 3 DDRB */
+    if (num) ciabdrb = b; else ciaadrb = b;
+    w = restore_u16 ();                                        /* 4 TA */
+    if (num) ciabta = w; else ciaata = w;
+    w = restore_u16 ();                                        /* 6 TB */
+    if (num) ciabtb = w; else ciaatb = w;
+    l = restore_u8 ();                                 /* 8/9/A TOD */
+    l |= restore_u8 () << 8;
+    l |= restore_u8 () << 16;
+    if (num) ciabtod = l; else ciaatod = l;
+    restore_u8 ();                                     /* B unused */
+    b = restore_u8 ();                                 /* C SDR */
+    if (num) ciabsdr = b; else ciaasdr = b;
+    b = restore_u8 ();                                 /* D ICR INFORMATION (not mask!) */
+    if (num) ciabicr = b; else ciaaicr = b;
+    b = restore_u8 ();                                 /* E CRA */
+    if (num) ciabcra = b; else ciaacra = b;
+    b = restore_u8 ();                                 /* F CRB */
+    if (num) ciabcrb = b; else ciaacrb = b;
+
+/* CIA internal data */
+
+    b = restore_u8 ();                                 /* ICR MASK */
+    if (num) ciabimask = b; else ciaaimask = b;
+    w = restore_u8 ();                                 /* timer A latch */
+    w |= restore_u8 () << 8;
+    if (num) ciabla = w; else ciaala = w;
+    w = restore_u8 ();                                 /* timer B latch */
+    w |= restore_u8 () << 8;
+    if (num) ciablb = w; else ciaalb = w;
+    w = restore_u8 ();                                 /* TOD latched value */
+    w |= restore_u8 () << 8;
+    w |= restore_u8 () << 16;
+    if (num) ciabtol = w; else ciaatol = w;
+    l = restore_u8 ();                                 /* alarm */
+    l |= restore_u8 () << 8;
+    l |= restore_u8 () << 16;
+    if (num) ciabalarm = l; else ciaaalarm = l;
+    b = restore_u8 ();
+    if (num) ciabtlatch = b & 1; else ciaatlatch = b & 1;      /* is TOD latched? */
+    if (num) ciabtodon = b & 2; else ciaatodon = b & 2;                /* is TOD stopped? */
+    b = restore_u8 ();
+    if (num)
+       div10 = CYCLE_UNIT * b;
+    b = restore_u8 ();
+    if (num) ciabsdr_cnt = b; else ciaasdr_cnt = b;
+    return src;
+}
+
+uae_u8 *save_cia (int num, int *len, uae_u8 *dstptr)
+{
+    uae_u8 *dstbak,*dst, b;
+    uae_u16 t;
+
+    if (dstptr)
+       dstbak = dst = dstptr;
+    else
+       dstbak = dst = malloc (16 + 12 + 1 + 1);
+
+    compute_passed_time ();
+
+    /* CIA registers */
+
+    b = num ? ciabpra : ciaapra;                               /* 0 PRA */
+    save_u8 (b);
+    b = num ? ciabprb : ciaaprb;                               /* 1 PRB */
+    save_u8 (b);
+    b = num ? ciabdra : ciaadra;                               /* 2 DDRA */
+    save_u8 (b); 
+    b = num ? ciabdrb : ciaadrb;                               /* 3 DDRB */
+    save_u8 (b);
+    t = (num ? ciabta - ciabta_passed : ciaata - ciaata_passed);/* 4 TA */
+    save_u16 (t);
+    t = (num ? ciabtb - ciabtb_passed : ciaatb - ciaatb_passed);/* 8 TB */
+    save_u16 (t);
+    b = (num ? ciabtod : ciaatod);                     /* 8 TODL */
+    save_u8 (b);
+    b = (num ? ciabtod >> 8 : ciaatod >> 8);           /* 9 TODM */
+    save_u8 (b);
+    b = (num ? ciabtod >> 16 : ciaatod >> 16);         /* A TODH */
+    save_u8 (b);
+    save_u8 (0);                                               /* B unused */
+    b = num ? ciabsdr : ciaasdr;                               /* C SDR */
+    save_u8 (b);
+    b = num ? ciabicr : ciaaicr;                               /* D ICR INFORMATION (not mask!) */
+    save_u8 (b);
+    b = num ? ciabcra : ciaacra;                               /* E CRA */
+    save_u8 (b);
+    b = num ? ciabcrb : ciaacrb;                               /* F CRB */
+    save_u8 (b);
+
+    /* CIA internal data */
+
+    save_u8 (num ? ciabimask : ciaaimask);                     /* ICR */
+    b = (num ? ciabla : ciaala);                       /* timer A latch LO */
+    save_u8 (b);
+    b = (num ? ciabla >> 8 : ciaala >> 8);             /* timer A latch HI */
+    save_u8 (b);
+    b = (num ? ciablb : ciaalb);                       /* timer B latch LO */
+    save_u8 (b);
+    b = (num ? ciablb >> 8 : ciaalb >> 8);             /* timer B latch HI */
+    save_u8 (b);
+    b = (num ? ciabtol : ciaatol);                     /* latched TOD LO */
+    save_u8 (b);
+    b = (num ? ciabtol >> 8 : ciaatol >> 8);           /* latched TOD MED */
+    save_u8 (b);
+    b = (num ? ciabtol >> 16 : ciaatol >> 16);         /* latched TOD HI */
+    save_u8 (b);
+    b = (num ? ciabalarm : ciaaalarm);                 /* alarm LO */
+    save_u8 (b);
+    b = (num ? ciabalarm >> 8 : ciaaalarm >>8 );       /* alarm MED */
+    save_u8 (b);
+    b = (num ? ciabalarm >> 16 : ciaaalarm >> 16);     /* alarm HI */
+    save_u8 (b);
+    b = 0;
+    if (num)
+       b |= ciabtlatch ? 1 : 0;
+    else
+       b |= ciaatlatch ? 1 : 0; /* is TOD latched? */
+    if (num)
+       b |= ciabtodon ? 2 : 0;
+    else
+       b |= ciaatodon ? 2 : 0;   /* TOD stopped? */
+    save_u8 (b);
+    save_u8 (div10 / CYCLE_UNIT);
+    save_u8 (num ? ciabsdr_cnt : ciaasdr_cnt);
+    *len = dst - dstbak;
+    return dstbak;
+}
diff --git a/compemu_fpp.c b/compemu_fpp.c
new file mode 100755 (executable)
index 0000000..377dcb9
--- /dev/null
@@ -0,0 +1,1561 @@
+/*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * MC68881 emulation
+  *
+  * Copyright 1996 Herman ten Brugge
+  * Adapted for JIT compilation (c) Bernd Meyer, 2000
+  */
+
+#include <math.h>
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "memory.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "ersatz.h"
+#include "md-fpp.h"
+#include "compemu.h"
+
+#define MAKE_FPSR(r) do { fmov_rr(FP_RESULT,r); } while (0)
+
+#define delay   //nop() ;nop()  
+#define delay2  //nop() ;nop()   
+
+uae_s32 temp_fp[3];  /* To convert between FP/integer */
+
+/* return register number, or -1 for failure */
+STATIC_INLINE int get_fp_value (uae_u32 opcode, uae_u16 extra)
+{
+    uaecptr tmppc;
+    uae_u16 tmp;
+    int size;
+    int mode;
+    int reg;
+    double* src;
+    uae_u32 ad = 0;
+    static int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 };
+    static int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 };
+
+    if ((extra & 0x4000) == 0) {
+       return (extra >> 10) & 7;
+    }
+
+    mode = (opcode >> 3) & 7;
+    reg = opcode & 7;
+    size = (extra >> 10) & 7;
+    switch (mode) {
+     case 0:
+       switch (size) {
+        case 6:
+           sign_extend_8_rr(S1,reg);
+           mov_l_mr((uae_u32)temp_fp,S1);
+           delay2;
+           fmovi_rm(FS1,(uae_u32)temp_fp);
+           return FS1;
+        case 4:
+           sign_extend_16_rr(S1,reg);
+           mov_l_mr((uae_u32)temp_fp,S1);
+           delay2;
+           fmovi_rm(FS1,(uae_u32)temp_fp);
+           return FS1;
+        case 0:
+           mov_l_mr((uae_u32)temp_fp,reg);
+           delay2;
+           fmovi_rm(FS1,(uae_u32)temp_fp);
+           return FS1;
+        case 1:
+           mov_l_mr((uae_u32)temp_fp,reg);
+           delay2;
+           fmovs_rm(FS1,(uae_u32)temp_fp);
+           return FS1;
+        default:
+           return -1;
+       }
+       return -1; /* Should be unreachable */
+     case 1:
+       return -1; /* Genuine invalid instruction */
+     default:
+       break;
+    }
+    /* OK, we *will* have to load something from an address. Let's make
+       sure we know how to handle that, or quit early --- i.e. *before*
+       we do any postincrement/predecrement that we may regret */
+
+    switch (size) {
+     case 3:
+       return -1;
+     case 0:
+     case 1:
+     case 2:
+     case 4:
+     case 5:
+     case 6:
+       break; 
+     default:
+       return -1;
+    }
+
+    switch (mode) {
+     case 2:
+       ad=S1;  /* We will change it, anyway ;-) */
+       mov_l_rr(ad,reg+8);
+       break;
+     case 3:
+       ad=S1;
+       mov_l_rr(ad,reg+8);
+       lea_l_brr(reg+8,reg+8,(reg == 7?sz2[size]:sz1[size]));
+       break;
+     case 4:
+       ad=S1;
+       
+       lea_l_brr(reg+8,reg+8,-(reg == 7?sz2[size]:sz1[size]));
+       mov_l_rr(ad,reg+8);
+       break;
+     case 5:
+     {
+        uae_u32 off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
+        ad=S1;
+        mov_l_rr(ad,reg+8);
+        lea_l_brr(ad,ad,off);
+        break;
+     }
+     case 6:
+     {
+       uae_u32 dp=comp_get_iword((m68k_pc_offset+=2)-2);
+       ad=S1;
+       calc_disp_ea_020(reg+8,dp,ad,S2);
+       break;
+     }
+     case 7:
+       switch (reg) {
+        case 0:
+        {
+            uae_u32 off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
+            ad=S1;
+            mov_l_ri(ad,off);
+            break;
+        }
+        case 1:
+        {
+            uae_u32 off=comp_get_ilong((m68k_pc_offset+=4)-4);
+            ad=S1;
+            mov_l_ri(ad,off);
+            break;
+        }
+        case 2:
+        {
+            uae_u32 address=start_pc+((char *)comp_pc_p-(char *)start_pc_p)+
+                m68k_pc_offset;
+            uae_s32 PC16off =(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
+            ad=S1;
+            mov_l_ri(ad,address+PC16off);
+            break;
+        }
+        case 3:
+           return -1;
+           tmppc = m68k_getpc ();
+           tmp = next_iword ();
+           ad = get_disp_ea_020 (tmppc, tmp);
+           break;
+        case 4: 
+        {
+            uae_u32 address=start_pc+((char *)comp_pc_p-(char *)start_pc_p)+
+                m68k_pc_offset;
+            ad=S1;
+            mov_l_ri(ad,address);
+            m68k_pc_offset+=sz2[size];
+            break;
+        }
+        default:
+           return -1;
+       }
+    }
+
+    switch (size) {
+     case 0:
+       readlong(ad,S2,S3);
+       mov_l_mr((uae_u32)temp_fp,S2);
+       delay2;
+       fmovi_rm(FS1,(uae_u32)temp_fp);
+       break;
+     case 1:
+       readlong(ad,S2,S3);
+       mov_l_mr((uae_u32)temp_fp,S2);
+       delay2;
+       fmovs_rm(FS1,(uae_u32)temp_fp);
+       break;
+     case 2:
+       readword(ad,S2,S3);
+       mov_w_mr(((uae_u32)temp_fp)+8,S2);
+       add_l_ri(ad,4);
+       readlong(ad,S2,S3);
+       mov_l_mr((uae_u32)(temp_fp)+4,S2);
+       add_l_ri(ad,4);
+       readlong(ad,S2,S3);
+       mov_l_mr((uae_u32)(temp_fp),S2);
+       delay2;
+       fmov_ext_rm(FS1,(uae_u32)(temp_fp));
+       break;
+     case 3:
+       return -1; /* Some silly "packed" stuff */
+     case 4:
+       readword(ad,S2,S3);
+       sign_extend_16_rr(S2,S2);
+       mov_l_mr((uae_u32)temp_fp,S2);
+       delay2;
+       fmovi_rm(FS1,(uae_u32)temp_fp);
+       break;
+     case 5:
+       readlong(ad,S2,S3);
+       mov_l_mr(((uae_u32)temp_fp)+4,S2);
+       add_l_ri(ad,4);
+       readlong(ad,S2,S3);
+       mov_l_mr((uae_u32)(temp_fp),S2);
+       delay2;
+       fmov_rm(FS1,(uae_u32)(temp_fp));
+       break;
+     case 6:
+       readword(ad,S2,S3); /* fetch word but use only low 8-bits */
+       sign_extend_8_rr(S2,S2);
+       mov_l_mr((uae_u32)temp_fp,S2);
+       delay2;
+       fmovi_rm(FS1,(uae_u32)temp_fp);
+       break;
+     default:
+       return -1;
+    }
+    return FS1;
+}
+
+/* return of -1 means failure, >=0 means OK */
+STATIC_INLINE int put_fp_value (int val, uae_u32 opcode, uae_u16 extra)
+{
+    uae_u16 tmp;
+    uaecptr tmppc;
+    int size;
+    int mode;
+    int reg;
+    uae_u32 ad;
+    static int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 };
+    static int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 };
+
+    if ((extra & 0x4000) == 0) {
+       fmov_rr((extra>>10)&7,val);
+       return 0;
+    }
+
+    mode = (opcode >> 3) & 7;
+    reg = opcode & 7;
+    size = (extra >> 10) & 7;
+    ad = -1;
+    switch (mode) {
+     case 0:
+       switch (size) {
+        case 6:
+           fmovi_mr((uae_u32)temp_fp,val);
+           delay;
+           mov_b_rm(reg,(uae_u32)temp_fp);
+           return 0;
+        case 4:
+           fmovi_mr((uae_u32)temp_fp,val);
+           delay;
+           mov_w_rm(reg,(uae_u32)temp_fp);
+           return 0;
+        case 0:
+           fmovi_mr((uae_u32)temp_fp,val);
+           delay;
+           mov_l_rm(reg,(uae_u32)temp_fp);
+           return 0;
+        case 1:
+           fmovs_mr((uae_u32)temp_fp,val);
+           delay;
+           mov_l_rm(reg,(uae_u32)temp_fp);
+           return 0;
+        default:
+           return -1;
+       }
+     case 1:
+       return -1; /* genuine invalid instruction */
+     default: break;
+    }
+
+    /* Let's make sure we get out *before* doing something silly if
+       we can't handle the size */
+    switch (size) {
+     case 0:
+     case 4:
+     case 5:
+     case 6:
+     case 2:
+     case 1:
+       break;
+     case 3:
+     default:
+       return -1;
+    }
+    
+    switch (mode) {
+     case 2:
+       ad=S1;
+       mov_l_rr(ad,reg+8);
+       break;
+     case 3:
+       ad=S1;
+       mov_l_rr(ad,reg+8);
+       lea_l_brr(reg+8,reg+8,(reg == 7?sz2[size]:sz1[size]));
+       break;
+     case 4:
+       ad=S1;
+       lea_l_brr(reg+8,reg+8,-(reg == 7?sz2[size]:sz1[size]));
+       mov_l_rr(ad,reg+8);
+       break;
+     case 5:
+     {
+        uae_u32 off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
+        ad=S1;
+        mov_l_rr(ad,reg+8);
+        add_l_ri(ad,off);
+        break;
+     }
+     case 6:
+     {
+       uae_u32 dp=comp_get_iword((m68k_pc_offset+=2)-2);
+       ad=S1;
+       calc_disp_ea_020(reg+8,dp,ad,S2);
+       break;
+     }
+     case 7:
+       switch (reg) {
+        case 0:
+        {
+            uae_u32 off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
+            ad=S1;
+            mov_l_ri(ad,off);
+            break;
+        }
+        case 1:
+        {
+            uae_u32 off=comp_get_ilong((m68k_pc_offset+=4)-4);
+            ad=S1;
+            mov_l_ri(ad,off);
+            break;
+        }
+        case 2:
+        {
+            uae_u32 address=start_pc+((char *)comp_pc_p-(char *)start_pc_p)+
+                m68k_pc_offset;
+            uae_s32 PC16off =(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
+            ad=S1;
+            mov_l_ri(ad,address+PC16off);
+            break;
+        }
+        case 3:
+           return -1;
+           tmppc = m68k_getpc ();
+           tmp = next_iword ();
+           ad = get_disp_ea_020 (tmppc, tmp);
+           break;
+        case 4:
+        {
+            uae_u32 address=start_pc+((char *)comp_pc_p-(char *)start_pc_p)+
+                m68k_pc_offset;
+            ad=S1;
+            mov_l_ri(ad,address);
+            m68k_pc_offset+=sz2[size];
+            break;
+        }
+        default:
+           return -1;
+       }
+    }
+    switch (size) {
+     case 0:
+       fmovi_mr((uae_u32)temp_fp,val);
+       delay;
+       mov_l_rm(S2,(uae_u32)temp_fp);
+       writelong_clobber(ad,S2,S3);
+       break;
+     case 1:
+       fmovs_mr((uae_u32)temp_fp,val);
+       delay;
+       mov_l_rm(S2,(uae_u32)temp_fp);
+       writelong_clobber(ad,S2,S3);
+       break;
+     case 2:
+       fmov_ext_mr((uae_u32)temp_fp,val);
+       delay;
+       mov_w_rm(S2,(uae_u32)temp_fp+8);
+       writeword_clobber(ad,S2,S3);
+       add_l_ri(ad,4);
+       mov_l_rm(S2,(uae_u32)temp_fp+4);
+       writelong_clobber(ad,S2,S3);
+       add_l_ri(ad,4);
+       mov_l_rm(S2,(uae_u32)temp_fp);
+       writelong_clobber(ad,S2,S3);
+       break;
+     case 3: return -1; /* Packed */
+
+     case 4:
+       fmovi_mr((uae_u32)temp_fp,val);
+       delay;
+       mov_l_rm(S2,(uae_u32)temp_fp);
+       writeword_clobber(ad,S2,S3);
+       break;
+     case 5:
+       fmov_mr((uae_u32)temp_fp,val);
+       delay;
+       mov_l_rm(S2,(uae_u32)temp_fp+4);
+       writelong_clobber(ad,S2,S3);
+       add_l_ri(ad,4);
+       mov_l_rm(S2,(uae_u32)temp_fp);
+       writelong_clobber(ad,S2,S3);
+       break;
+     case 6:
+       fmovi_mr((uae_u32)temp_fp,val);
+       delay;
+       mov_l_rm(S2,(uae_u32)temp_fp);
+       writebyte(ad,S2,S3);
+       break;
+     default:
+       return -1;
+    }
+    return 0;
+}
+
+/* return -1 for failure, or register number for success */
+STATIC_INLINE int get_fp_ad (uae_u32 opcode, uae_u32 * ad)
+{
+    uae_u16 tmp;
+    uaecptr tmppc;
+    int mode;
+    int reg;
+    uae_s32 off;
+
+    mode = (opcode >> 3) & 7;
+    reg = opcode & 7;
+    switch (mode) {
+     case 0:
+     case 1:
+       return -1;
+     case 2:
+     case 3:
+     case 4:
+       mov_l_rr(S1,8+reg);
+       return S1;
+       *ad = m68k_areg (regs, reg);
+       break;
+     case 5:
+       off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
+
+       mov_l_rr(S1,8+reg);
+       add_l_ri(S1,off);
+       return S1;
+     case 6:
+       return -1;
+       break;
+     case 7:
+       switch (reg) {
+        case 0:
+           off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
+           mov_l_ri(S1,off);
+           return S1;
+        case 1:
+           off=comp_get_ilong((m68k_pc_offset+=4)-4);
+           mov_l_ri(S1,off);
+           return S1;
+        case 2:
+           return -1;
+           *ad = m68k_getpc ();
+           *ad += (uae_s32) (uae_s16) next_iword ();
+           break;
+        case 3:
+           return -1;
+           tmppc = m68k_getpc ();
+           tmp = next_iword ();
+           *ad = get_disp_ea_020 (tmppc, tmp);
+           break;
+        default:
+           return -1;
+       }
+    }
+    abort();
+}
+
+void comp_fdbcc_opp (uae_u32 opcode, uae_u16 extra)
+{
+    FAIL(1);
+    return;
+
+    if (!currprefs.compfpu) {
+       FAIL(1);
+       return;
+    }
+}
+
+void comp_fscc_opp (uae_u32 opcode, uae_u16 extra)
+{
+    uae_u32 ad;
+    int cc;
+    int reg;
+
+    if (!currprefs.compfpu) {
+       FAIL(1);
+       return;
+    }
+
+#if DEBUG_FPP
+    printf ("fscc_opp at %08lx\n", m68k_getpc ());
+    fflush (stdout);
+#endif
+
+
+    if (extra&0x20) {  /* only cc from 00 to 1f are defined */
+       FAIL(1);
+       return;
+    }
+    if ((opcode & 0x38) != 0) { /* We can only do to integer register */
+       FAIL(1); 
+       return;
+    }
+
+    fflags_into_flags(S2);
+    reg=(opcode&7);
+    
+    mov_l_ri(S1,255);
+    mov_l_ri(S4,0);
+    switch(extra&0x0f) {  /* according to fpp.c, the 0x10 bit is ignored
+                           */
+     case 0: break;  /* set never */
+     case 1: mov_l_rr(S2,S4); 
+       cmov_l_rr(S4,S1,4); 
+       cmov_l_rr(S4,S2,10); break;
+     case 2: cmov_l_rr(S4,S1,7); break;
+     case 3: cmov_l_rr(S4,S1,3); break;
+     case 4: mov_l_rr(S2,S4); 
+       cmov_l_rr(S4,S1,2); 
+       cmov_l_rr(S4,S2,10); break;
+     case 5: mov_l_rr(S2,S4); 
+       cmov_l_rr(S4,S1,6); 
+       cmov_l_rr(S4,S2,10); break;
+     case 6: cmov_l_rr(S4,S1,5); break;
+     case 7: cmov_l_rr(S4,S1,11); break;
+     case 8: cmov_l_rr(S4,S1,10); break;
+     case 9: cmov_l_rr(S4,S1,4); break;
+     case 10: cmov_l_rr(S4,S1,10); cmov_l_rr(S4,S1,7); break;
+     case 11: cmov_l_rr(S4,S1,4); cmov_l_rr(S4,S1,3); break;
+     case 12: cmov_l_rr(S4,S1,2); break;
+     case 13: cmov_l_rr(S4,S1,6); break;
+     case 14: cmov_l_rr(S4,S1,5); cmov_l_rr(S4,S1,10); break;
+     case 15: mov_l_rr(S4,S1); break;
+    }
+
+    if ((opcode & 0x38) == 0) {
+       mov_b_rr(reg,S4);
+    } else {
+       abort();
+       if (get_fp_ad (opcode, &ad) == 0) {
+           m68k_setpc (m68k_getpc () - 4);
+           op_illg (opcode);
+       } else
+           put_byte (ad, cc ? 0xff : 0x00);
+    }
+}
+
+void comp_ftrapcc_opp (uae_u32 opcode, uaecptr oldpc)
+{
+    int cc;
+
+    FAIL(1);
+    return;
+}
+
+extern unsigned long foink3, oink;
+
+void comp_fbcc_opp (uae_u32 opcode)
+{
+    uae_u32 start_68k_offset=m68k_pc_offset;
+    uae_u32 off;
+    uae_u32 v1;
+    uae_u32 v2;
+    uae_u32 nh;
+    int cc;
+
+    if (!currprefs.compfpu) {
+       FAIL(1);
+       return;
+    }
+
+    if (opcode&0x20) {  /* only cc from 00 to 1f are defined */
+       FAIL(1);
+       return;
+    }
+    if ((opcode&0x40)==0) {
+       off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
+    }
+    else {
+       off=comp_get_ilong((m68k_pc_offset+=4)-4);
+    }
+    mov_l_ri(S1,(uae_u32)
+            (comp_pc_p+off-(m68k_pc_offset-start_68k_offset)));
+    mov_l_ri(PC_P,(uae_u32)comp_pc_p);
+
+    /* Now they are both constant. Might as well fold in m68k_pc_offset */
+    add_l_ri(S1,m68k_pc_offset);
+    add_l_ri(PC_P,m68k_pc_offset);
+    m68k_pc_offset=0;
+
+    /* according to fpp.c, the 0x10 bit is ignored
+       (it handles exception handling, which we don't
+       do, anyway ;-) */
+    cc=opcode&0x0f;
+    v1=get_const(PC_P);
+    v2=get_const(S1);
+    fflags_into_flags(S2);
+
+    // mov_l_mi((uae_u32)&foink3,cc);
+    switch(cc) {  
+     case 0: break;  /* jump never */
+     case 1: 
+       mov_l_rr(S2,PC_P); 
+       cmov_l_rr(PC_P,S1,4); 
+       cmov_l_rr(PC_P,S2,10); break;
+     case 2: register_branch(v1,v2,7); break;
+     case 3: register_branch(v1,v2,3); break;
+     case 4: 
+       mov_l_rr(S2,PC_P); 
+       cmov_l_rr(PC_P,S1,2); 
+       cmov_l_rr(PC_P,S2,10); break;
+     case 5:
+       mov_l_rr(S2,PC_P); 
+       cmov_l_rr(PC_P,S1,6); 
+       cmov_l_rr(PC_P,S2,10); break;
+     case 6: register_branch(v1,v2,5); break;
+     case 7: register_branch(v1,v2,11); break;
+     case 8: register_branch(v1,v2,10); break;
+     case 9: register_branch(v1,v2,4); break;
+     case 10: 
+       cmov_l_rr(PC_P,S1,10); 
+       cmov_l_rr(PC_P,S1,7); break;
+     case 11: 
+       cmov_l_rr(PC_P,S1,4); 
+       cmov_l_rr(PC_P,S1,3); break;
+     case 12: register_branch(v1,v2,2); break;
+     case 13: register_branch(v1,v2,6); break;
+     case 14: 
+       cmov_l_rr(PC_P,S1,5); 
+       cmov_l_rr(PC_P,S1,10); break;
+     case 15: mov_l_rr(PC_P,S1); break;
+    }
+}
+
+    /* Floating point conditions 
+       The "NotANumber" part could be problematic; Howver, when NaN is
+       encountered, the ftst instruction sets bot N and Z to 1 on the x87,
+       so quite often things just fall into place. This is probably not
+       accurate wrt the 68k FPU, but it is *as* accurate as this was before.
+       However, some more thought should go into fixing this stuff up so
+       it accurately emulates the 68k FPU.
+>=<U 
+0000    0x00: 0                        ---   Never jump
+0101    0x01: Z                        ---   jump if zero (x86: 4)
+1000    0x02: !(NotANumber || Z || N)  --- Neither Z nor N set (x86: 7)
+1101    0x03: Z || !(NotANumber || N); --- Z or !N (x86: 4 and 3)
+0010    0x04: N && !(NotANumber || Z); --- N and !Z (x86: hard!)
+0111    0x05: Z || (N && !NotANumber); --- Z or N (x86: 6)
+1010    0x06: !(NotANumber || Z);      --- not Z (x86: 5)
+1110    0x07: !NotANumber;             --- not NaN (x86: 11, not parity)
+0001    0x08: NotANumber;              --- NaN (x86: 10)
+0101    0x09: NotANumber || Z;         --- Z (x86: 4)
+1001    0x0a: NotANumber || !(N || Z); --- NaN or neither N nor Z (x86: 10 and 7)
+1101    0x0b: NotANumber || Z || !N;   --- Z or !N (x86: 4 and 3)
+0011    0x0c: NotANumber || (N && !Z); --- N (x86: 2)
+0111    0x0d: NotANumber || Z || N;    --- Z or N (x86: 6)
+1010    0x0e: !Z;                      --- not Z (x86: 5)
+1111    0x0f: 1;                       --- always
+
+This is not how the 68k handles things, though --- it sets Z to 0 and N
+to the NaN's sign.... ('o' and 'i' denote differences from the above
+table)
+
+>=<U 
+0000    0x00: 0                        ---   Never jump
+010o    0x01: Z                        ---   jump if zero (x86: 4, not 10)
+1000    0x02: !(NotANumber || Z || N)  --- Neither Z nor N set (x86: 7)
+110o    0x03: Z || !(NotANumber || N); --- Z or !N (x86: 3)
+0010    0x04: N && !(NotANumber || Z); --- N and !Z (x86: 2, not 10)
+011o    0x05: Z || (N && !NotANumber); --- Z or N (x86: 6, not 10)
+1010    0x06: !(NotANumber || Z);      --- not Z (x86: 5)
+1110    0x07: !NotANumber;             --- not NaN (x86: 11, not parity)
+0001    0x08: NotANumber;              --- NaN (x86: 10)
+0101    0x09: NotANumber || Z;         --- Z (x86: 4)
+1001    0x0a: NotANumber || !(N || Z); --- NaN or neither N nor Z (x86: 10 and 7)
+1101    0x0b: NotANumber || Z || !N;   --- Z or !N (x86: 4 and 3)
+0011    0x0c: NotANumber || (N && !Z); --- N (x86: 2)
+0111    0x0d: NotANumber || Z || N;    --- Z or N (x86: 6)
+101i    0x0e: !Z;                      --- not Z (x86: 5 and 10)
+1111    0x0f: 1;                       --- always
+
+Of course, this *still* doesn't mean that the x86 and 68k conditions are
+equivalent --- the handling of infinities is different, for one thing.
+On the 68k, +infinity minus +infinity is NotANumber (as it should be). On
+the x86, it is +infinity, and some exception is raised (which I suspect
+is promptly ignored) STUPID! 
+The more I learn about their CPUs, the more I detest Intel....
+
+You can see this in action if you have "Benoit" (see Aminet) and
+set the exponent to 16. Wait for a long time, and marvel at the extra black
+areas outside the center one. That's where Benoit expects NaN, and the x86
+gives +infinity. [Ooops --- that must have been some kind of bug in my code.
+it no longer happens, and the resulting graphic looks much better, too]
+
+x86 conditions
+0011    : 2
+1100    : 3
+0101    : 4
+1010    : 5
+0111    : 6
+1000    : 7
+0001    : 10
+1110    : 11
+    */
+void comp_fsave_opp (uae_u32 opcode)
+{
+    uae_u32 ad;
+    int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
+    int i;
+
+    FAIL(1);
+    return;
+
+    if (!currprefs.compfpu) {
+       FAIL(1);
+       return;
+    }
+
+#if DEBUG_FPP
+    printf ("fsave_opp at %08lx\n", m68k_getpc ());
+    fflush (stdout);
+#endif
+    if (get_fp_ad (opcode, &ad) == 0) {
+       m68k_setpc (m68k_getpc () - 2);
+       op_illg (opcode);
+       return;
+    }
+
+    if (currprefs.cpu_level >= 4) {
+       /* 4 byte 68040 IDLE frame.  */
+       if (incr < 0) {
+           ad -= 4;
+           put_long (ad, 0x41000000);
+       } else {
+           put_long (ad, 0x41000000);
+           ad += 4;
+       }
+    } else {
+       if (incr < 0) {
+           ad -= 4;
+           put_long (ad, 0x70000000);
+           for (i = 0; i < 5; i++) {
+               ad -= 4;
+               put_long (ad, 0x00000000);
+           }
+           ad -= 4;
+           put_long (ad, 0x1f180000);
+       } else {
+           put_long (ad, 0x1f180000);
+           ad += 4;
+           for (i = 0; i < 5; i++) {
+               put_long (ad, 0x00000000);
+               ad += 4;
+           }
+           put_long (ad, 0x70000000);
+           ad += 4;
+       }
+    }
+    if ((opcode & 0x38) == 0x18)
+       m68k_areg (regs, opcode & 7) = ad;
+    if ((opcode & 0x38) == 0x20)
+       m68k_areg (regs, opcode & 7) = ad;
+}
+
+void comp_frestore_opp (uae_u32 opcode)
+{
+    uae_u32 ad;
+    uae_u32 d;
+    int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
+
+    FAIL(1);
+    return;
+
+    if (!currprefs.compfpu) {
+       FAIL(1);
+       return;
+    }
+
+#if DEBUG_FPP
+    printf ("frestore_opp at %08lx\n", m68k_getpc ());
+    fflush (stdout);
+#endif
+    if (get_fp_ad (opcode, &ad) == 0) {
+       m68k_setpc (m68k_getpc () - 2);
+       op_illg (opcode);
+       return;
+    }
+    if (currprefs.cpu_level >= 4) {
+       /* 68040 */
+       if (incr < 0) {
+           /* @@@ This may be wrong.  */
+           ad -= 4;
+           d = get_long (ad);
+           if ((d & 0xff000000) != 0) { /* Not a NULL frame? */
+               if ((d & 0x00ff0000) == 0) { /* IDLE */
+               } else if ((d & 0x00ff0000) == 0x00300000) { /* UNIMP */
+                   ad -= 44;
+               } else if ((d & 0x00ff0000) == 0x00600000) { /* BUSY */
+                   ad -= 92;
+               }
+           }
+       } else {
+           d = get_long (ad);
+           ad += 4;
+           if ((d & 0xff000000) != 0) { /* Not a NULL frame? */
+               if ((d & 0x00ff0000) == 0) { /* IDLE */
+               } else if ((d & 0x00ff0000) == 0x00300000) { /* UNIMP */
+                   ad += 44;
+               } else if ((d & 0x00ff0000) == 0x00600000) { /* BUSY */
+                   ad += 92;
+               }
+           }
+       }
+    } else {
+       if (incr < 0) {
+           ad -= 4;
+           d = get_long (ad);
+           if ((d & 0xff000000) != 0) {
+               if ((d & 0x00ff0000) == 0x00180000)
+                   ad -= 6 * 4;
+               else if ((d & 0x00ff0000) == 0x00380000)
+                   ad -= 14 * 4;
+               else if ((d & 0x00ff0000) == 0x00b40000)
+                   ad -= 45 * 4;
+           }
+       } else {
+           d = get_long (ad);
+           ad += 4;
+           if ((d & 0xff000000) != 0) {
+               if ((d & 0x00ff0000) == 0x00180000)
+                   ad += 6 * 4;
+               else if ((d & 0x00ff0000) == 0x00380000)
+                   ad += 14 * 4;
+               else if ((d & 0x00ff0000) == 0x00b40000)
+                   ad += 45 * 4;
+           }
+       }
+    }
+    if ((opcode & 0x38) == 0x18)
+       m68k_areg (regs, opcode & 7) = ad;
+    if ((opcode & 0x38) == 0x20)
+       m68k_areg (regs, opcode & 7) = ad;
+}
+
+static fptype const_e=2.718281828;  /* Got some more digits? */
+static fptype const_log10_e=0.4342944819;
+static fptype const_loge_10=2.302585093;
+static fptype power10[]={1e0,1e1,1e2,1e4,1e8,1e16,1e32,1e64,1e128,1e256
+#if USE_LONG_DOUBLE
+,       1e512, 1e1024, 1e2048, 1e4096
+#endif
+};
+
+/* 128 words, indexed through the low byte of the 68k fpu control word */
+static uae_u16 x86_fpucw[]={
+    0x137f, 0x137f, 0x137f, 0x137f, 0x137f, 0x137f, 0x137f, 0x137f, /* p0r0 */
+    0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, /* p0r1 */
+    0x177f, 0x177f, 0x177f, 0x177f, 0x177f, 0x177f, 0x177f, 0x177f, /* p0r2 */
+    0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, /* p0r3 */
+
+    0x107f, 0x107f, 0x107f, 0x107f, 0x107f, 0x107f, 0x107f, 0x107f, /* p1r0 */
+    0x1c7f, 0x1c7f, 0x1c7f, 0x1c7f, 0x1c7f, 0x1c7f, 0x1c7f, 0x1c7f, /* p1r1 */
+    0x147f, 0x147f, 0x147f, 0x147f, 0x147f, 0x147f, 0x147f, 0x147f, /* p1r2 */
+    0x187f, 0x187f, 0x187f, 0x187f, 0x187f, 0x187f, 0x187f, 0x187f, /* p1r3 */
+
+    0x127f, 0x127f, 0x127f, 0x127f, 0x127f, 0x127f, 0x127f, 0x127f, /* p2r0 */
+    0x1e7f, 0x1e7f, 0x1e7f, 0x1e7f, 0x1e7f, 0x1e7f, 0x1e7f, 0x1e7f, /* p2r1 */
+    0x167f, 0x167f, 0x167f, 0x167f, 0x167f, 0x167f, 0x167f, 0x167f, /* p2r2 */
+    0x1a7f, 0x1a7f, 0x1a7f, 0x1a7f, 0x1a7f, 0x1a7f, 0x1a7f, 0x1a7f, /* p2r3 */
+
+    0x137f, 0x137f, 0x137f, 0x137f, 0x137f, 0x137f, 0x137f, 0x137f, /* p3r0 */
+    0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, /* p3r1 */
+    0x177f, 0x177f, 0x177f, 0x177f, 0x177f, 0x177f, 0x177f, 0x177f, /* p3r2 */
+    0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f  /* p3r3 */
+};
+
+void comp_fpp_opp (uae_u32 opcode, uae_u16 extra)
+{
+    int reg;
+    int src;
+    
+    if (!currprefs.compfpu) {
+       FAIL(1);
+       return;
+    }
+    switch ((extra >> 13) & 0x7) {
+     case 3: /* 2nd most common */
+       if (put_fp_value ((extra >> 7)&7 , opcode, extra) < 0) {
+           FAIL(1);
+           return;
+       }
+       return;
+     case 6:
+     case 7: 
+       {
+           uae_u32 ad, list = 0;
+           int incr = 0;
+           if (extra & 0x2000) {
+               int ad;
+
+               /* FMOVEM FPP->memory */
+               switch ((extra >> 11) & 3) { /* Get out early if failure */
+                case 0:
+                case 2:
+                   break;
+                case 1:
+                case 3: 
+                default:
+                   FAIL(1); return;
+               }
+               ad=get_fp_ad (opcode, &ad);
+               if (ad<0) {
+                   FAIL(1);
+#if 0
+                   m68k_setpc (m68k_getpc () - 4);
+                   op_illg (opcode);
+#endif
+                   return;
+               }
+               switch ((extra >> 11) & 3) {
+               case 0: /* static pred */
+                   list = extra & 0xff;
+                   incr = -1;
+                   break;
+               case 2: /* static postinc */
+                   list = extra & 0xff;
+                   incr = 1;
+                   break;
+               case 1: /* dynamic pred */
+               case 3: /* dynamic postinc */
+                  abort();
+               }
+               while (list) {
+                   uae_u32 wrd1, wrd2, wrd3;
+                   if (incr < 0) { /* Predecrement */
+                       fmov_ext_mr((uae_u32)temp_fp,fpp_movem_index2[list]);
+                       delay;
+                       sub_l_ri(ad,4); 
+                       mov_l_rm(S2,(uae_u32)temp_fp);
+                       writelong_clobber(ad,S2,S3);
+                       sub_l_ri(ad,4); 
+                       mov_l_rm(S2,(uae_u32)temp_fp+4);
+                       writelong_clobber(ad,S2,S3);
+                       sub_l_ri(ad,4); 
+                       mov_w_rm(S2,(uae_u32)temp_fp+8);
+                       writeword_clobber(ad,S2,S3);
+                   } else { /* postinc */
+                       fmov_ext_mr((uae_u32)temp_fp,fpp_movem_index2[list]);
+                       delay;
+                       mov_w_rm(S2,(uae_u32)temp_fp+8);
+                       writeword_clobber(ad,S2,S3);
+                       add_l_ri(ad,4);
+                       mov_l_rm(S2,(uae_u32)temp_fp+4);
+                       writelong_clobber(ad,S2,S3);
+                       add_l_ri(ad,4);
+                       mov_l_rm(S2,(uae_u32)temp_fp);
+                       writelong_clobber(ad,S2,S3);
+                       add_l_ri(ad,4);
+                   }
+                   list = fpp_movem_next[list];
+               }
+               if ((opcode & 0x38) == 0x18)
+                   mov_l_rr((opcode & 7)+8,ad);
+               if ((opcode & 0x38) == 0x20)
+                   mov_l_rr((opcode & 7)+8,ad);
+           } else {
+               /* FMOVEM memory->FPP */
+
+               int ad;
+               switch ((extra >> 11) & 3) { /* Get out early if failure */
+                case 0:
+                case 2:
+                   break;
+                case 1:
+                case 3: 
+                default:
+                   FAIL(1); return;
+               }
+               ad=get_fp_ad (opcode, &ad);
+               if (ad<0) {
+                   FAIL(1);
+#if 0
+                   m68k_setpc (m68k_getpc () - 4);
+                   op_illg (opcode);
+#endif
+                   return;
+               }
+               switch ((extra >> 11) & 3) {
+               case 0: /* static pred */
+                   list = extra & 0xff;
+                   incr = -1;
+                   break;
+               case 2: /* static postinc */
+                   list = extra & 0xff;
+                   incr = 1;
+                   break;
+               case 1: /* dynamic pred */
+               case 3: /* dynamic postinc */
+                  abort();
+               }
+
+               while (list) {
+                   uae_u32 wrd1, wrd2, wrd3;
+                   if (incr < 0) {
+                       sub_l_ri(ad,4);
+                       readlong(ad,S2,S3);
+                       mov_l_mr((uae_u32)(temp_fp),S2);
+                       sub_l_ri(ad,4);
+                       readlong(ad,S2,S3);
+                       mov_l_mr((uae_u32)(temp_fp)+4,S2);
+                       sub_l_ri(ad,4);
+                       readword(ad,S2,S3);
+                       mov_w_mr(((uae_u32)temp_fp)+8,S2);
+                       delay2;
+                       fmov_ext_rm(fpp_movem_index2[list],(uae_u32)(temp_fp));
+                   } else {
+                       readword(ad,S2,S3);
+                       mov_w_mr(((uae_u32)temp_fp)+8,S2);
+                       add_l_ri(ad,4);
+                       readlong(ad,S2,S3);
+                       mov_l_mr((uae_u32)(temp_fp)+4,S2);
+                       add_l_ri(ad,4);
+                       readlong(ad,S2,S3);
+                       mov_l_mr((uae_u32)(temp_fp),S2);
+                       add_l_ri(ad,4);
+                       delay2;
+                       fmov_ext_rm(fpp_movem_index1[list],(uae_u32)(temp_fp));
+                   }
+                   list = fpp_movem_next[list];
+               }
+               if ((opcode & 0x38) == 0x18)
+                   mov_l_rr((opcode & 7)+8,ad);
+               if ((opcode & 0x38) == 0x20)
+                   mov_l_rr((opcode & 7)+8,ad);
+           }
+       }
+       return;
+
+     case 4:
+     case 5:  /* rare */
+       if ((opcode & 0x30) == 0) {
+           if (extra & 0x2000) {
+               if (extra & 0x1000) {
+                   mov_l_rm(opcode & 15,(uae_u32)&regs.fpcr); return;
+               }
+               if (extra & 0x0800) {
+                   FAIL(1);
+                   return;
+               }
+               if (extra & 0x0400) {
+                   mov_l_rm(opcode & 15,(uae_u32)&regs.fpiar); return;
+               }
+           } else {
+               if (extra & 0x1000) {
+                   mov_l_mr((uae_u32)&regs.fpcr,opcode & 15); 
+#if USE_X86_FPUCW
+                   mov_l_rr(S1,opcode & 15);
+                   and_l_ri(S1,0x000000f0);
+                   fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
+#endif             
+                   return;
+               }
+               if (extra & 0x0800) {
+                   FAIL(1);
+                   return;
+                   // set_fpsr(m68k_dreg (regs, opcode & 15));
+               }
+               if (extra & 0x0400) {
+                   mov_l_mr((uae_u32)&regs.fpiar,opcode & 15); return;
+               }
+           }
+       } else if ((opcode & 0x3f) == 0x3c) {
+           if ((extra & 0x2000) == 0) {
+               if (extra & 0x1000) {
+                   uae_u32 val=comp_get_ilong((m68k_pc_offset+=4)-4);
+                   mov_l_mi((uae_u32)&regs.fpcr,val);
+#if USE_X86_FPUCW
+                   mov_l_ri(S1,val&0x000000f0);
+                   fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
+#endif             
+                   return;
+               }
+               if (extra & 0x0800) {
+                   FAIL(1);
+                   return;
+               }
+               if (extra & 0x0400) {
+                   uae_u32 val=comp_get_ilong((m68k_pc_offset+=4)-4);
+                   mov_l_mi((uae_u32)&regs.fpiar,val);
+                   return;
+               }
+           }
+           FAIL(1);
+           return;
+       } else if (extra & 0x2000) {
+           FAIL(1);
+           return;
+       } else {
+           FAIL(1);
+           return;
+       }
+       FAIL(1);
+       return;
+
+     case 0:
+     case 2: /* Extremely common */
+       reg = (extra >> 7) & 7;
+       if ((extra & 0xfc00) == 0x5c00) {
+           switch (extra & 0x7f) {
+            case 0x00:
+               fmov_pi(reg);
+               break;
+            case 0x0b:
+               fmov_log10_2(reg);
+               break;
+            case 0x0c:
+               fmov_rm(reg,(uae_u32)&const_e);
+               break;
+            case 0x0d:
+               fmov_log2_e(reg);
+               break;
+            case 0x0e:
+               fmov_rm(reg,(uae_u32)&const_log10_e);
+               break;
+            case 0x0f:
+               fmov_0(reg);
+               break;
+            case 0x30:
+               fmov_loge_2(reg);
+               break;
+            case 0x31:
+               fmov_rm(reg,(uae_u32)&const_loge_10);
+               break;
+            case 0x32:
+               fmov_1(reg);
+               break;
+            case 0x33:
+            case 0x34:
+            case 0x35:
+            case 0x36:
+            case 0x37:
+            case 0x38:
+            case 0x39:
+            case 0x3a:
+            case 0x3b:
+               fmov_rm(reg,(uae_u32)(power10+(extra & 0x7f)-0x32));
+               break;
+            default:
+               /* This is not valid, so we fail */
+               FAIL(1);
+               return;
+           }
+           return;
+       }
+       
+       switch (extra & 0x7f) {
+        case 0x00:             /* FMOVE */
+        case 0x40:  /* Explicit rounding. This is just a quick fix. Same
+                     * for all other cases that have three choices */
+        case 0x44:   
+           dont_care_fflags();
+           src=get_fp_value (opcode, extra);
+           if (src < 0) {
+               FAIL(1);  /* Illegal instruction */
+               return;
+           }
+           fmov_rr(reg,src);
+           MAKE_FPSR (src);
+           break;
+        case 0x01:             /* FINT */
+           FAIL(1);    
+           return;
+           dont_care_fflags();
+        case 0x02:             /* FSINH */
+           FAIL(1);  
+           return;
+
+           dont_care_fflags();
+           regs.fp[reg] = sinh (src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+        case 0x03:             /* FINTRZ */
+#if USE_X86_FPUCW 
+           /* If we have control over the CW, we can do this */
+           dont_care_fflags();
+           src=get_fp_value (opcode, extra);
+           if (src < 0) {
+               FAIL(1);  /* Illegal instruction */
+               return;
+           }
+           mov_l_ri(S1,16);  /* Switch to "round to zero" mode */
+           fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
+           
+           frndint_rr(reg,src);
+
+           /* restore control word */
+           mov_l_rm(S1,(uae_u32)&regs.fpcr); 
+           and_l_ri(S1,0x000000f0);
+           fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
+
+           MAKE_FPSR (reg);
+           break;
+#endif             
+           FAIL(1);  
+           return;
+           regs.fp[reg] = (int) src;
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+        case 0x04:             /* FSQRT */
+        case 0x41:
+        case 0x45:
+           dont_care_fflags();
+           src=get_fp_value (opcode, extra);
+           if (src < 0) {
+               FAIL(1);  /* Illegal instruction */
+               return;
+           }
+           fsqrt_rr(reg,src);
+           MAKE_FPSR (reg);
+           break;
+        case 0x06:             /* FLOGNP1 */
+           FAIL(1);  
+           return;
+           dont_care_fflags();
+           regs.fp[reg] = log (src + 1.0);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+        case 0x08:             /* FETOXM1 */
+           FAIL(1);  
+           return;
+           dont_care_fflags();
+           regs.fp[reg] = exp (src) - 1.0;
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+        case 0x09:             /* FTANH */
+           FAIL(1);  
+           return;
+           dont_care_fflags();
+           regs.fp[reg] = tanh (src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+        case 0x0a:             /* FATAN */
+           FAIL(1);  
+           return;
+           dont_care_fflags();
+           regs.fp[reg] = atan (src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+        case 0x0c:             /* FASIN */
+           FAIL(1);  
+           return;
+           dont_care_fflags();
+           regs.fp[reg] = asin (src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+        case 0x0d:             /* FATANH */
+           FAIL(1);  
+           return;
+           dont_care_fflags();
+#if 1                          /* The BeBox doesn't have atanh, and it isn't in the HPUX libm either */
+           regs.fp[reg] = log ((1 + src) / (1 - src)) / 2;
+#else
+           regs.fp[reg] = atanh (src);
+#endif
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+        case 0x0e:             /* FSIN */
+           dont_care_fflags();
+           src=get_fp_value (opcode, extra);
+           if (src < 0) {
+               FAIL(1);  /* Illegal instruction */
+               return;
+           }
+           fsin_rr(reg,src);
+           MAKE_FPSR (reg);
+           break;
+        case 0x0f:             /* FTAN */
+           FAIL(1);  
+           return;
+           dont_care_fflags();
+           regs.fp[reg] = tan (src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+        case 0x10:             /* FETOX */
+           dont_care_fflags();
+           src=get_fp_value (opcode, extra);
+           if (src < 0) {
+               FAIL(1);  /* Illegal instruction */
+               return;
+           }
+           fetox_rr(reg,src);
+           MAKE_FPSR (reg);
+           break;
+        case 0x11:             /* FTWOTOX */
+           dont_care_fflags();
+           src=get_fp_value (opcode, extra);
+           if (src < 0) {
+               FAIL(1);  /* Illegal instruction */
+               return;
+           }
+           ftwotox_rr(reg,src);
+           MAKE_FPSR (reg);
+           break;
+        case 0x12:             /* FTENTOX */
+           FAIL(1);  
+           return;
+           dont_care_fflags();
+           regs.fp[reg] = pow (10.0, src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+        case 0x14:             /* FLOGN */
+           FAIL(1);  
+           return;
+           dont_care_fflags();
+           regs.fp[reg] = log (src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+        case 0x15:             /* FLOG10 */
+           FAIL(1);  
+           return;
+           dont_care_fflags();
+           regs.fp[reg] = log10 (src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+        case 0x16:             /* FLOG2 */
+           dont_care_fflags();
+           src=get_fp_value (opcode, extra);
+           if (src < 0) {
+               FAIL(1);  /* Illegal instruction */
+               return;
+           }
+           flog2_rr(reg,src);
+           MAKE_FPSR (reg);
+           break;
+        case 0x18:             /* FABS */
+        case 0x58:
+        case 0x5c:
+           dont_care_fflags();
+           src=get_fp_value (opcode, extra);
+           if (src < 0) {
+               FAIL(1);  /* Illegal instruction */
+               return;
+           }
+           fabs_rr(reg,src);
+           MAKE_FPSR (reg);
+           break;
+        case 0x19:             /* FCOSH */
+           FAIL(1);  
+           return;
+           dont_care_fflags();
+           regs.fp[reg] = cosh (src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+        case 0x1a:             /* FNEG */
+        case 0x5a:
+        case 0x5e:
+           dont_care_fflags();
+           src=get_fp_value (opcode, extra);
+           if (src < 0) {
+               FAIL(1);  /* Illegal instruction */
+               return;
+           }
+           fneg_rr(reg,src);
+           MAKE_FPSR (reg);
+           break;
+        case 0x1c:             /* FACOS */
+           FAIL(1);  
+           return;
+           dont_care_fflags();
+           regs.fp[reg] = acos (src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+        case 0x1d:             /* FCOS */
+           dont_care_fflags();
+           src=get_fp_value (opcode, extra);
+           if (src < 0) {
+               FAIL(1);  /* Illegal instruction */
+               return;
+           }
+           fcos_rr(reg,src);
+           MAKE_FPSR (reg);
+           break;
+        case 0x1e:             /* FGETEXP */
+           FAIL(1);  
+           return;
+           dont_care_fflags();
+           {
+               int expon;
+               frexp (src, &expon);
+               regs.fp[reg] = (double) (expon - 1);
+               MAKE_FPSR (regs.fp[reg]);
+           }
+           break;
+        case 0x1f:             /* FGETMAN */
+           FAIL(1);  
+           return;
+           dont_care_fflags();
+           {
+               int expon;
+               regs.fp[reg] = frexp (src, &expon) * 2.0;
+               MAKE_FPSR (regs.fp[reg]);
+           }
+           break;
+        case 0x20:             /* FDIV */
+        case 0x60:
+        case 0x64:
+           dont_care_fflags();
+           src=get_fp_value (opcode, extra);
+           if (src < 0) {
+               FAIL(1);  /* Illegal instruction */
+               return;
+           }
+           fdiv_rr(reg,src);
+           MAKE_FPSR (reg);
+           break;
+        case 0x21:             /* FMOD */
+           dont_care_fflags();
+           src=get_fp_value (opcode, extra);
+           if (src < 0) {
+               FAIL(1);  /* Illegal instruction */
+               return;
+           }
+           frem_rr(reg,src);
+           MAKE_FPSR (reg);
+           break;
+        case 0x22:             /* FADD */
+        case 0x62:
+        case 0x66:
+           dont_care_fflags();
+           src=get_fp_value (opcode, extra);
+           if (src < 0) {
+               FAIL(1);  /* Illegal instruction */
+               return;
+           }
+           fadd_rr(reg,src);
+           MAKE_FPSR (reg);
+           break;
+        case 0x23:             /* FMUL */
+        case 0x63:
+        case 0x67:
+           dont_care_fflags();
+           src=get_fp_value (opcode, extra);
+           if (src < 0) {
+               FAIL(1);  /* Illegal instruction */
+               return;
+           }
+           fmul_rr(reg,src);
+           MAKE_FPSR (reg);
+           break;
+        case 0x24:             /* FSGLDIV */
+           dont_care_fflags();
+           src=get_fp_value (opcode, extra);
+           if (src < 0) {
+               FAIL(1);  /* Illegal instruction */
+               return;
+           }
+           fdiv_rr(reg,src);
+           MAKE_FPSR (reg);
+           break;
+        case 0x25:             /* FREM */
+           dont_care_fflags();
+           src=get_fp_value (opcode, extra);
+           if (src < 0) {
+               FAIL(1);  /* Illegal instruction */
+               return;
+           }
+           frem1_rr(reg,src);
+           MAKE_FPSR (reg);
+           break;
+        case 0x26:             /* FSCALE */
+           dont_care_fflags();
+           FAIL(1);  
+           return;
+           regs.fp[reg] *= exp (log (2.0) * src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+        case 0x27:             /* FSGLMUL */
+           dont_care_fflags();
+           src=get_fp_value (opcode, extra);
+           if (src < 0) {
+               FAIL(1);  /* Illegal instruction */
+               return;
+           }
+           fmul_rr(reg,src);
+           MAKE_FPSR (reg);
+           break;
+        case 0x28:             /* FSUB */
+        case 0x68:
+        case 0x6c:
+           dont_care_fflags();
+           src=get_fp_value (opcode, extra);
+           if (src < 0) {
+               FAIL(1);  /* Illegal instruction */
+               return;
+           }
+           fsub_rr(reg,src);
+           MAKE_FPSR (reg);
+           break;
+        case 0x30:             /* FSINCOS */
+        case 0x31:
+        case 0x32:
+        case 0x33:
+        case 0x34:
+        case 0x35:
+        case 0x36:
+        case 0x37:
+           FAIL(1);  
+           return;
+           dont_care_fflags();
+           regs.fp[reg] = sin (src);
+           regs.fp[extra & 7] = cos (src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+        case 0x38:             /* FCMP */
+           src=get_fp_value (opcode, extra);
+           if (src < 0) {
+               FAIL(1);  /* Illegal instruction */
+               return;
+           }
+           fmov_rr(FP_RESULT,reg);
+           fsub_rr(FP_RESULT,src); /* Right way? */
+           break;
+        case 0x3a:             /* FTST */
+           src=get_fp_value (opcode, extra);
+           if (src < 0) {
+               FAIL(1);  /* Illegal instruction */
+               return;
+           }
+           fmov_rr(FP_RESULT,src);
+           break;
+        default:
+           FAIL(1);  
+           return;
+           break;
+       }
+       return;
+    }
+    m68k_setpc (m68k_getpc () - 4);
+    op_illg (opcode);
+}
diff --git a/compemu_optimizer.c b/compemu_optimizer.c
new file mode 100755 (executable)
index 0000000..e48d57d
--- /dev/null
@@ -0,0 +1,174 @@
+#if USE_OPTIMIZER
+/* Welcome to the magical world of cpp ;-) */
+
+#define USE_REGALLOC optlev>=2
+
+#define opt_op0(dummy) opt_store_op0()
+#define opt_op1(a1) opt_store_op1(OPT_##a1)
+#define opt_op2(a1,a2) opt_store_op2(OPT_##a1,OPT_##a2)
+#define opt_op3(a1,a2,a3) opt_store_op3(OPT_##a1,OPT_##a2,OPT_##a3)
+#define opt_op4(a1,a2,a3,a4) opt_store_op4(OPT_##a1,OPT_##a2,OPT_##a3,OPT_##a4)
+#define opt_op5(a1,a2,a3,a4,a5) opt_store_op5(OPT_##a1,OPT_##a2,OPT_##a3,OPT_##a4,OPT_##a5)
+
+#define direct0(dummy) ()
+#define direct1(a1) (DIR_##a1)
+#define direct2(a1,a2) (DIR_##a1,DIR_##a2)
+#define direct3(a1,a2,a3) (DIR_##a1,DIR_##a2,DIR_##a3)
+#define direct4(a1,a2,a3,a4) (DIR_##a1,DIR_##a2,DIR_##a3,DIR_##a4)
+#define direct5(a1,a2,a3,a4,a5) (DIR_##a1,DIR_##a2,DIR_##a3,DIR_##a4,DIR_##a5)
+
+#define OIMM 0
+#define OMEMR 0
+#define OMEMW 0
+#define OMEMRW 0 /* These are all 32 bit immediates */
+#define OR1  1
+#define OR2  2
+#define OR4  3
+#define OW1  4
+#define OW2  5
+#define OW4  6
+#define ORW1 7
+#define ORW2 8
+#define ORW4 9
+
+#define OFW 10
+#define OFR 11
+#define OFRW 12
+
+#define INST_END 98
+#define FLUSH 99
+
+#define OPT_IMM OIMM,
+#define OPT_MEMR OMEMR,
+#define OPT_MEMW OMEMW,
+#define OPT_MEMRW OMEMRW,
+#define OPT_R1  OR1 ,
+#define OPT_R2  OR2 ,
+#define OPT_R4  OR4 ,
+#define OPT_W1  OW1 ,
+#define OPT_W2  OW2 ,
+#define OPT_W4  OW4 ,
+#define OPT_RW1 ORW1,
+#define OPT_RW2 ORW2,
+#define OPT_RW4 ORW4,
+
+#define OPT_FW  OFW ,
+#define OPT_FR  OFR ,
+#define OPT_FRW OFRW ,
+
+#define DIR_IMM 
+#define DIR_MEMR 
+#define DIR_MEMW 
+#define DIR_MEMRW 
+#define DIR_R1  
+#define DIR_R2  
+#define DIR_R4  
+#define DIR_W1  
+#define DIR_W2  
+#define DIR_W4  
+#define DIR_RW1 
+#define DIR_RW2 
+#define DIR_RW4 
+
+#define DIR_FR
+#define DIR_FW
+#define DIR_FRW
+
+#undef MIDFUNC
+#undef MENDFUNC
+
+#define MIDFUNC(nargs,func,args) \
+  __inline__ void do_##func args
+
+#define MENDFUNC(nargs,func,args) \
+  void func args \
+  { \
+    if (reg_alloc_run) { \
+      opt_op##nargs##args; \
+    } else { \
+      do_##func direct##nargs##args; \
+    } \
+  }
+
+#undef COMPCALL
+#define COMPCALL(func) do_##func
+
+int opt_index=0;
+
+static __inline__ void store_any(uae_u8 type, uae_u32 val)
+{
+    ra[opt_index].type=type;
+    ra[opt_index].reg=val;
+    opt_index++;
+    if (opt_index>=MAXREGOPT) {
+       printf("Oops! opt_index overflow....\n");
+       abort();
+    }
+}
+
+static __inline__ void store_arg(uae_u8 type, uae_u32 val)
+{
+    if (type<OR1 || type>ORW4) 
+       return;
+    store_any(type,val);
+}
+
+static __inline__ void opt_store_op0(void)
+{
+    /* zilch */
+}
+
+static __inline__ void opt_store_op1(uae_u8 t1, uae_u32 a1)
+{
+    store_arg(t1,a1);
+    opt_store_op0();
+}
+static __inline__ void opt_store_op2(uae_u8 t1, uae_u32 a1,
+                                    uae_u8 t2, uae_u32 a2)
+{
+    store_arg(t2,a2);
+    opt_store_op1(t1,a1);
+}
+
+static __inline__ void opt_store_op3(uae_u8 t1, uae_u32 a1,
+                                    uae_u8 t2, uae_u32 a2,
+                                    uae_u8 t3, uae_u32 a3)
+{
+    store_arg(t3,a3);
+    opt_store_op2(t1,a1,t2,a2);
+}
+
+static __inline__ void opt_store_op4(uae_u8 t1, uae_u32 a1,
+                                    uae_u8 t2, uae_u32 a2,
+                                    uae_u8 t3, uae_u32 a3,
+                                    uae_u8 t4, uae_u32 a4)
+{
+    store_arg(t4,a4);
+    opt_store_op3(t1,a1,t2,a2,t3,a3);
+}
+
+static __inline__ void opt_store_op5(uae_u8 t1, uae_u32 a1,
+                                    uae_u8 t2, uae_u32 a2,
+                                    uae_u8 t3, uae_u32 a3,
+                                    uae_u8 t4, uae_u32 a4,
+                                    uae_u8 t5, uae_u32 a5)
+{
+    store_arg(t5,a5);
+    opt_store_op4(t1,a1,t2,a2,t3,a3,t4,a4);
+}
+
+static void opt_assert_empty(int line)
+{
+}
+
+void empty_optimizer(void) 
+{
+}
+
+#else
+static __inline__ void opt_emit_all(void) {}
+static __inline__ void opt_assert_empty(int line) {}
+void empty_optimizer(void) {}
+#define USE_REGALLOC 0
+#endif
diff --git a/compemu_optimizer_x86.c b/compemu_optimizer_x86.c
new file mode 100755 (executable)
index 0000000..52a1b91
--- /dev/null
@@ -0,0 +1,421 @@
+#if USE_LOW_OPTIMIZER
+/* Welcome to the magical world of cpp ;-) */
+
+/* This was broken by the advent of FPU emulation. It also didn't
+   provide any useful speedup while it worked. *Sigh* Someone fix my
+   software, please ;-) */
+
+#define MAXLOPTINST 100
+
+#define LDECISION currprefs.comp_lowopt
+
+#define lopt_op0(dummy) lopt_store_op0(
+#define lopt_op1(a1) lopt_store_op1(LOPT_##a1,
+#define lopt_op2(a1,a2) lopt_store_op2(LOPT_##a1,LOPT_##a2,
+#define lopt_op3(a1,a2,a3) lopt_store_op3(LOPT_##a1,LOPT_##a2,LOPT_##a3,
+#define lopt_op4(a1,a2,a3,a4) lopt_store_op4(LOPT_##a1,LOPT_##a2,LOPT_##a3,LOPT_##a4,
+#define lopt_op5(a1,a2,a3,a4,a5) lopt_store_op5(LOPT_##a1,LOPT_##a2,LOPT_##a3,LOPT_##a4,LOPT_##a5,
+
+#define ldirect0(dummy) ()
+#define ldirect1(a1) (LDIR_##a1)
+#define ldirect2(a1,a2) (LDIR_##a1,LDIR_##a2)
+#define ldirect3(a1,a2,a3) (LDIR_##a1,LDIR_##a2,LDIR_##a3)
+#define ldirect4(a1,a2,a3,a4) (LDIR_##a1,LDIR_##a2,LDIR_##a3,LDIR_##a4)
+#define ldirect5(a1,a2,a3,a4,a5) (LDIR_##a1,LDIR_##a2,LDIR_##a3,LDIR_##a4,LDIR_##a5)
+
+#define NONE 0
+#define READ 1
+#define WRITE 2
+#define RMW (READ|WRITE)
+
+#define SIZE1 4
+#define SIZE2 8
+#define SIZE4 12
+#define FLOAT 16
+#define SIZEMASK 12
+
+#define LIMM NONE
+#define LR1  (READ | SIZE1)
+#define LR2  (READ | SIZE2)
+#define LR4  (READ | SIZE4)
+#define LW1  (WRITE | SIZE1)
+#define LW2  (WRITE | SIZE2)
+#define LW4  (WRITE | SIZE4)
+#define LRW1 (RMW | SIZE1)
+#define LRW2 (RMW | SIZE2)
+#define LRW4 (RMW | SIZE4)
+#define LFW  (READ | FLOAT)
+#define LFR  (WRITE | FLOAT)
+#define LFRW (RMW | FLOAT)
+#define LMEMR NONE
+#define LMEMW NONE
+#define LMEMRW NONE
+
+#define LOPT_IMM LIMM,
+#define LOPT_R1  LR1 ,
+#define LOPT_R2  LR2 ,
+#define LOPT_R4  LR4 ,
+#define LOPT_W1  LW1 ,
+#define LOPT_W2  LW2 ,
+#define LOPT_W4  LW4 ,
+#define LOPT_RW1 LRW1,
+#define LOPT_RW2 LRW2,
+#define LOPT_RW4 LRW4,
+#define LOPT_FR  LFR,
+#define LOPT_FW  LFW,
+#define LOPT_FRW LFRW,
+#define LOPT_MEMR LMEMR,
+#define LOPT_MEMW LMEMW,
+#define LOPT_MEMRW LMEMRW,
+
+#define LDIR_IMM 
+#define LDIR_R1  
+#define LDIR_R2  
+#define LDIR_R4  
+#define LDIR_W1  
+#define LDIR_W2  
+#define LDIR_W4  
+#define LDIR_RW1 
+#define LDIR_RW2 
+#define LDIR_RW4 
+#define LDIR_FW
+#define LDIR_FR
+#define LDIR_FRW
+#define LDIR_MEMR 
+#define LDIR_MEMW 
+#define LDIR_MEMRW 
+
+
+#undef LOWFUNC
+#undef LENDFUNC
+
+#define LOWFUNC(flags,mem,nargs,func,args) \
+  static __inline__ void do_##func args
+
+#define LENDFUNC(flags,mem,nargs,func,args) \
+  static __inline__ void func args \
+  { \
+  if (LDECISION) { \
+    lopt_op##nargs##args do_##func, mem, flags); \
+  } else { \
+    do_##func ldirect##nargs##args; \
+  } \
+  } 
+
+typedef struct lopt_inst_rec {
+    void* func;
+    uae_u32 args[5];
+    uae_u8 argtype[5];
+    uae_s8 nargs;
+    uae_u8 mem;
+    uae_u8 flags;
+} lopt_inst;
+
+
+
+static lopt_inst linst[MAXLOPTINST];
+static int lopt_index=0;
+
+static __inline__ int argsize(int type)
+{
+    return type&SIZEMASK;
+}
+
+static __inline__ int reads_mem(int i) {
+    return linst[i].mem & READ;
+}
+    
+    
+static __inline__ int access_reg(int i, int r, int mode)
+{
+    int k;
+    for (k=0;k<linst[i].nargs;k++)
+       if (linst[i].args[k]==r && 
+           (linst[i].argtype[k]&mode) &&
+           !(linst[i].argtype[k]&FLOAT))
+           return 1;
+    return 0;
+}
+
+static __inline__ int writes_reg(int i, int r)
+{
+    return access_reg(i,r,WRITE);
+}
+
+static __inline__ int reads_reg(int i, int r)
+{
+    return access_reg(i,r,READ);
+}
+
+static __inline__ int uses_reg(int i, int r)
+{
+    return access_reg(i,r,RMW);
+}
+
+
+static __inline__ int writes_mem(int i) {
+    return linst[i].mem & WRITE;
+}
+
+static __inline__ int uses_mem(int i)
+{
+    return linst[i].mem & RMW;
+}
+
+static __inline__ int reads_flags(int i) {
+    return linst[i].flags & READ;
+}
+
+static __inline__ int writes_flags(int i) {
+    return linst[i].flags & WRITE;
+}
+
+static __inline__ int uses_flags(int i)
+{
+    return linst[i].flags & RMW;
+}
+
+static void do_raw_mov_l_rm(W4,MEMR);
+static void do_raw_fflags_save(void);
+
+
+/* Whether i depends on j */
+static __inline__ int depends_on(int i, int j)
+{
+    int n;
+
+    /* First, check memory */
+    if (writes_mem(i) && uses_mem(j))
+       return 1;
+    if (reads_mem(i) && writes_mem(j))
+       return 1;
+
+    /* Next, check flags */
+    if (writes_flags(i) && uses_flags(j))
+       return 1;
+    if (reads_flags(i) && writes_flags(j))
+       return 1;
+    
+    for (n=0;n<linst[i].nargs;n++) {
+       if (linst[i].argtype[n] & FLOAT)
+           return 1;
+    }
+    for (n=0;n<linst[j].nargs;n++) {
+       if (linst[j].argtype[n] & FLOAT)
+           return 1;
+    }
+
+    for (n=0;n<linst[i].nargs;n++) {
+       if ((linst[i].argtype[n] & WRITE) &&
+           !(linst[i].argtype[n] & FLOAT)) {
+           if (uses_reg(j,linst[i].args[n]))
+               return 1;
+       }
+       else if ((linst[i].argtype[n] & READ) &&
+                !(linst[i].argtype[n] & FLOAT))  {
+           if (writes_reg(j,linst[i].args[n]))
+               return 1;
+       }
+    }
+
+    /* The need for this indicates a problem somewhere in the
+       LOWFUNC definitions --- I think. FIXME! */
+
+    if (uses_flags(j) && uses_flags(i))
+       return 1;
+    if (linst[i].func==do_raw_fflags_save)
+       return 1;
+    if (linst[j].func==do_raw_fflags_save)
+       return 1;
+
+    return 0;
+}
+
+static void do_raw_mov_l_rm(W4 d, MEMR s);
+           
+static __inline__ void low_peephole(void)
+{
+    int i;
+    
+    for (i=0;i<lopt_index;i++) {
+       if (uses_mem(i)) {
+           int j=i-1;
+           
+           while (j>=i-4 && j>=0 && !depends_on(i,j)) {
+               j--;
+           }
+           if (j!=i-1) {
+               lopt_inst x=linst[i];
+               int k=i;
+
+               j++;
+               while (k>j) {
+                   linst[k]=linst[k-1];
+                   k--;
+               }
+               linst[j]=x;
+           }
+       }
+    }
+}
+
+
+typedef void lopt_handler0(void);
+typedef void lopt_handler1(uae_u32);
+typedef void lopt_handler2(uae_u32,uae_u32);
+typedef void lopt_handler3(uae_u32,uae_u32,uae_u32);
+typedef void lopt_handler4(uae_u32,uae_u32,uae_u32,uae_u32);
+typedef void lopt_handler5(uae_u32,uae_u32,uae_u32,uae_u32,uae_u32);
+
+static void lopt_emit_all(void)
+{
+    int i;
+    lopt_inst* x;
+    static int inemit=0;
+    
+    if (inemit) {
+       printf("WARNING: lopt_emit is not reentrant!\n");
+    }
+    inemit=1;
+
+    low_peephole();
+
+    for (i=0;i<lopt_index;i++) {
+       x=linst+i;
+       switch(x->nargs) {
+        case 0: ((lopt_handler0*)x->func)(); break;
+        case 1: ((lopt_handler1*)x->func)(x->args[0]); break;
+        case 2: ((lopt_handler2*)x->func)(x->args[0],x->args[1]); break;
+        case 3: ((lopt_handler3*)x->func)(x->args[0],x->args[1],x->args[2]); break;
+        case 4: ((lopt_handler4*)x->func)(x->args[0],x->args[1],x->args[2],
+                                          x->args[3]); break;
+        case 5: ((lopt_handler5*)x->func)(x->args[0],x->args[1],x->args[2],
+                                          x->args[3],x->args[4]); break;
+        default: abort();
+       }
+    }
+    lopt_index=0;
+    inemit=0;
+}
+
+static __inline__ void low_advance(void)
+{
+  lopt_index++;
+  if (lopt_index==MAXLOPTINST)
+    lopt_emit_all();
+}
+
+static __inline__ void lopt_store_op0(void* lfuncptr, uae_u32 lmem, 
+                                     uae_u32 lflags)
+{
+  linst[lopt_index].func=lfuncptr;
+  linst[lopt_index].mem=lmem;
+  linst[lopt_index].flags=lflags;
+  linst[lopt_index].nargs=0;
+  low_advance();
+}
+
+static __inline__ void lopt_store_op1(uae_u8 t1, uae_u32 a1,
+                                     void* lfuncptr, uae_u32 lmem, 
+                                     uae_u32 lflags)
+{
+  linst[lopt_index].func=lfuncptr;
+  linst[lopt_index].mem=lmem;
+  linst[lopt_index].flags=lflags;
+  linst[lopt_index].nargs=1;
+  linst[lopt_index].argtype[0]=t1;
+  linst[lopt_index].args[0]=a1;
+  low_advance();
+}
+
+static __inline__ void lopt_store_op2(uae_u8 t1, uae_u32 a1,
+                                     uae_u8 t2, uae_u32 a2,
+                                     void* lfuncptr, uae_u32 lmem, 
+                                     uae_u32 lflags)
+{
+  linst[lopt_index].func=lfuncptr;
+  linst[lopt_index].mem=lmem;
+  linst[lopt_index].flags=lflags;
+  linst[lopt_index].nargs=2;
+  linst[lopt_index].argtype[0]=t1;
+  linst[lopt_index].args[0]=a1;
+  linst[lopt_index].argtype[1]=t2;
+  linst[lopt_index].args[1]=a2;
+  low_advance();
+}
+
+static __inline__ void lopt_store_op3(uae_u8 t1, uae_u32 a1,
+                                     uae_u8 t2, uae_u32 a2,
+                                     uae_u8 t3, uae_u32 a3,
+                                     void* lfuncptr, uae_u32 lmem, 
+                                     uae_u32 lflags)
+{
+  linst[lopt_index].func=lfuncptr;
+  linst[lopt_index].mem=lmem;
+  linst[lopt_index].flags=lflags;
+  linst[lopt_index].nargs=3;
+  linst[lopt_index].argtype[0]=t1;
+  linst[lopt_index].args[0]=a1;
+  linst[lopt_index].argtype[1]=t2;
+  linst[lopt_index].args[1]=a2;
+  linst[lopt_index].argtype[2]=t3;
+  linst[lopt_index].args[2]=a3;
+  low_advance();
+}
+
+static __inline__ void lopt_store_op4(uae_u8 t1, uae_u32 a1,
+                                     uae_u8 t2, uae_u32 a2,
+                                     uae_u8 t3, uae_u32 a3,
+                                     uae_u8 t4, uae_u32 a4,
+                                     void* lfuncptr, uae_u32 lmem, 
+                                     uae_u32 lflags)
+{
+  linst[lopt_index].func=lfuncptr;
+  linst[lopt_index].mem=lmem;
+  linst[lopt_index].flags=lflags;
+  linst[lopt_index].nargs=4;
+  linst[lopt_index].argtype[0]=t1;
+  linst[lopt_index].args[0]=a1;
+  linst[lopt_index].argtype[1]=t2;
+  linst[lopt_index].args[1]=a2;
+  linst[lopt_index].argtype[2]=t3;
+  linst[lopt_index].args[2]=a3;
+  linst[lopt_index].argtype[3]=t4;
+  linst[lopt_index].args[3]=a4;
+  low_advance();
+}
+
+static __inline__ void lopt_store_op5(uae_u8 t1, uae_u32 a1,
+                                     uae_u8 t2, uae_u32 a2,
+                                     uae_u8 t3, uae_u32 a3,
+                                     uae_u8 t4, uae_u32 a4,
+                                     uae_u8 t5, uae_u32 a5,
+                                     void* lfuncptr, uae_u32 lmem, 
+                                     uae_u32 lflags)
+{
+  linst[lopt_index].func=lfuncptr;
+  linst[lopt_index].mem=lmem;
+  linst[lopt_index].flags=lflags;
+  linst[lopt_index].nargs=5;
+  linst[lopt_index].argtype[0]=t1;
+  linst[lopt_index].args[0]=a1;
+  linst[lopt_index].argtype[1]=t2;
+  linst[lopt_index].args[1]=a2;
+  linst[lopt_index].argtype[2]=t3;
+  linst[lopt_index].args[2]=a3;
+  linst[lopt_index].argtype[3]=t4;
+  linst[lopt_index].args[3]=a4;
+  linst[lopt_index].argtype[4]=t5;
+  linst[lopt_index].args[4]=a5;
+  low_advance();
+}
+
+static __inline__ void empty_low_optimizer(void) 
+{
+  lopt_emit_all();
+}
+
+#else
+static __inline__ void lopt_emit_all(void) {}
+static __inline__ void empty_low_optimizer(void) {}
+#endif
diff --git a/compemu_raw_x86.c b/compemu_raw_x86.c
new file mode 100755 (executable)
index 0000000..3670a3c
--- /dev/null
@@ -0,0 +1,3179 @@
+/* This should eventually end up in machdep/, but for now, x86 is the
+   only target, and it's easier this way... */
+
+/*************************************************************************
+ * Some basic information about the the target CPU                       *
+ *************************************************************************/
+
+#define EAX 0
+#define ECX 1
+#define EDX 2
+#define EBX 3
+
+/* The register in which subroutines return an integer return value */
+#define REG_RESULT 0
+
+/* The registers subroutines take their first and second argument in */
+#define REG_PAR1 0
+#define REG_PAR2 2
+
+/* Three registers that are not used for any of the above */
+#define REG_NOPAR1 6
+#define REG_NOPAR2 5
+#define REG_NOPAR3 3
+
+#define REG_PC_PRE 0 /* The register we use for preloading regs.pc_p */
+#define REG_PC_TMP 1 /* Another register that is not the above */
+
+#define SHIFTCOUNT_NREG 1  /* Register that can be used for shiftcount.
+                             -1 if any reg will do */
+#define MUL_NREG1 0 /* %eax will hold the low 32 bits after a 32x32 mul */
+#define MUL_NREG2 2 /* %edx will hold the high 32 bits */
+
+uae_s8 always_used[]={4,-1};
+uae_s8 can_byte[]={0,1,2,3,-1};
+uae_s8 can_word[]={0,1,2,3,5,6,7,-1};
+
+uae_u8 call_saved[]={0,0,0,0,1,0,0,0};
+
+/* This *should* be the same as call_saved. But:
+   - We might not really know which registers are saved, and which aren't,
+     so we need to preserve some, but don't want to rely on everyone else
+     also saving those registers
+   - Special registers (such like the stack pointer) should not be "preserved"
+     by pushing, even though they are "saved" across function calls
+*/
+uae_u8 need_to_preserve[]={1,1,1,1,0,1,1,1};
+
+/* Whether classes of instructions do or don't clobber the native flags */
+#define CLOBBER_MOV
+#define CLOBBER_LEA
+#define CLOBBER_CMOV
+#define CLOBBER_POP
+#define CLOBBER_PUSH
+#define CLOBBER_SUB  clobber_flags()
+#define CLOBBER_SBB  clobber_flags()
+#define CLOBBER_CMP  clobber_flags()
+#define CLOBBER_ADD  clobber_flags()
+#define CLOBBER_ADC  clobber_flags()
+#define CLOBBER_AND  clobber_flags()
+#define CLOBBER_OR   clobber_flags()
+#define CLOBBER_XOR  clobber_flags()
+
+#define CLOBBER_ROL  clobber_flags()
+#define CLOBBER_ROR  clobber_flags()
+#define CLOBBER_SHLL clobber_flags()
+#define CLOBBER_SHRL clobber_flags()
+#define CLOBBER_SHRA clobber_flags()
+#define CLOBBER_TEST clobber_flags()
+#define CLOBBER_CL16 
+#define CLOBBER_CL8  
+#define CLOBBER_SE16
+#define CLOBBER_SE8
+#define CLOBBER_ZE16
+#define CLOBBER_ZE8
+#define CLOBBER_SW16 clobber_flags()
+#define CLOBBER_SW32
+#define CLOBBER_SETCC
+#define CLOBBER_MUL  clobber_flags()
+#define CLOBBER_BT   clobber_flags()
+#define CLOBBER_BSF  clobber_flags()
+
+/*************************************************************************
+ * Actual encoding of the instructions on the target CPU                 *
+ *************************************************************************/
+
+static int have_cmov=0;  /* We need to generate different code if 
+                           we don't have cmov */
+
+#include "compemu_optimizer_x86.c"
+
+static uae_u16 swap16(uae_u16 x)
+{
+    return ((x&0xff00)>>8)|((x&0x00ff)<<8);
+}
+
+static uae_u32 swap32(uae_u32 x)
+{
+    return ((x&0xff00)<<8)|((x&0x00ff)<<24)|((x&0xff0000)>>8)|((x&0xff000000)>>24);
+}
+
+static __inline__ int isbyte(uae_s32 x)
+{
+  return (x>=-128 && x<=127);
+}
+
+LOWFUNC(NONE,WRITE,1,raw_push_l_r,(R4 r))
+{
+       emit_byte(0x50+r);
+}
+LENDFUNC(NONE,WRITE,1,raw_push_l_r,(R4 r))
+
+LOWFUNC(NONE,READ,1,raw_pop_l_r,(R4 r))
+{
+       emit_byte(0x58+r);
+}
+LENDFUNC(NONE,READ,1,raw_pop_l_r,(R4 r))
+
+LOWFUNC(WRITE,NONE,2,raw_bt_l_ri,(R4 r, IMM i))
+{
+       emit_byte(0x0f);
+       emit_byte(0xba);
+       emit_byte(0xe0+r);
+       emit_byte(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_bt_l_ri,(R4 r, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_bt_l_rr,(R4 r, R4 b))
+{
+       emit_byte(0x0f);
+       emit_byte(0xa3);
+       emit_byte(0xc0+8*b+r);
+}
+LENDFUNC(WRITE,NONE,2,raw_bt_l_rr,(R4 r, R4 b))
+
+LOWFUNC(WRITE,NONE,2,raw_btc_l_ri,(RW4 r, IMM i))
+{
+       emit_byte(0x0f);
+       emit_byte(0xba);
+       emit_byte(0xf8+r);
+       emit_byte(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_btc_l_ri,(RW4 r, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_btc_l_rr,(RW4 r, R4 b))
+{
+       emit_byte(0x0f);
+       emit_byte(0xbb);
+       emit_byte(0xc0+8*b+r);
+}
+LENDFUNC(WRITE,NONE,2,raw_btc_l_rr,(RW4 r, R4 b))
+
+
+LOWFUNC(WRITE,NONE,2,raw_btr_l_ri,(RW4 r, IMM i))
+{
+       emit_byte(0x0f);
+       emit_byte(0xba);
+       emit_byte(0xf0+r);
+       emit_byte(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_btr_l_ri,(RW4 r, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_btr_l_rr,(RW4 r, R4 b))
+{
+       emit_byte(0x0f);
+       emit_byte(0xb3);
+       emit_byte(0xc0+8*b+r);
+}
+LENDFUNC(WRITE,NONE,2,raw_btr_l_rr,(RW4 r, R4 b))
+
+LOWFUNC(WRITE,NONE,2,raw_bts_l_ri,(RW4 r, IMM i))
+{
+       emit_byte(0x0f);
+       emit_byte(0xba);
+       emit_byte(0xe8+r);
+       emit_byte(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_bts_l_ri,(RW4 r, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_bts_l_rr,(RW4 r, R4 b))
+{
+       emit_byte(0x0f);
+       emit_byte(0xab);
+       emit_byte(0xc0+8*b+r);
+}
+LENDFUNC(WRITE,NONE,2,raw_bts_l_rr,(RW4 r, R4 b))
+
+LOWFUNC(WRITE,NONE,2,raw_sub_w_ri,(RW2 d, IMM i))
+{
+    emit_byte(0x66);
+    if (isbyte(i)) {
+       emit_byte(0x83);
+       emit_byte(0xe8+d);
+       emit_byte(i);
+    }
+    else {
+       emit_byte(0x81);
+       emit_byte(0xe8+d);
+       emit_word(i);
+    }
+}
+LENDFUNC(WRITE,NONE,2,raw_sub_w_ri,(RW2 d, IMM i))
+
+
+LOWFUNC(NONE,WRITE,2,raw_mov_l_mi,(MEMW d, IMM s))
+{
+    emit_byte(0xc7);
+    emit_byte(0x05);
+    emit_long(d);
+    emit_long(s);
+}
+LENDFUNC(NONE,WRITE,2,raw_mov_l_mi,(MEMW d, IMM s))
+
+LOWFUNC(NONE,WRITE,2,raw_mov_w_mi,(MEMW d, IMM s))
+{
+    emit_byte(0x66);
+    emit_byte(0xc7);
+    emit_byte(0x05);
+    emit_long(d);
+    emit_word(s);
+}
+LENDFUNC(NONE,WRITE,2,raw_mov_w_mi,(MEMW d, IMM s))
+
+LOWFUNC(NONE,WRITE,2,raw_mov_b_mi,(MEMW d, IMM s))
+{
+    emit_byte(0xc6);
+    emit_byte(0x05);
+    emit_long(d);
+    emit_byte(s);
+}
+LENDFUNC(NONE,WRITE,2,raw_mov_b_mi,(MEMW d, IMM s))
+
+LOWFUNC(WRITE,RMW,2,raw_rol_b_mi,(MEMRW d, IMM i))
+{
+    emit_byte(0xc0);
+    emit_byte(0x05);
+    emit_long(d);
+    emit_byte(i);
+}
+LENDFUNC(WRITE,RMW,2,raw_rol_b_mi,(MEMRW d, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_rol_b_ri,(RW1 r, IMM i))
+{
+    emit_byte(0xc0);
+    emit_byte(0xc0+r);
+    emit_byte(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_rol_b_ri,(RW1 r, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_rol_w_ri,(RW2 r, IMM i))
+{
+    emit_byte(0x66);
+    emit_byte(0xc1);
+    emit_byte(0xc0+r);
+    emit_byte(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_rol_w_ri,(RW2 r, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_rol_l_ri,(RW4 r, IMM i))
+{
+    emit_byte(0xc1);
+    emit_byte(0xc0+r);
+    emit_byte(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_rol_l_ri,(RW4 r, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_rol_l_rr,(RW4 d, R1 r))
+{
+    emit_byte(0xd3);
+    emit_byte(0xc0+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_rol_l_rr,(RW4 d, R1 r))
+
+LOWFUNC(WRITE,NONE,2,raw_rol_w_rr,(RW2 d, R1 r))
+{
+    emit_byte(0x66);
+    emit_byte(0xd3);
+    emit_byte(0xc0+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_rol_w_rr,(RW2 d, R1 r))
+
+LOWFUNC(WRITE,NONE,2,raw_rol_b_rr,(RW1 d, R1 r))
+{
+    emit_byte(0xd2);
+    emit_byte(0xc0+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_rol_b_rr,(RW1 d, R1 r))
+
+LOWFUNC(WRITE,NONE,2,raw_shll_l_rr,(RW4 d, R1 r))
+{
+    emit_byte(0xd3);
+    emit_byte(0xe0+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_shll_l_rr,(RW4 d, R1 r))
+
+LOWFUNC(WRITE,NONE,2,raw_shll_w_rr,(RW2 d, R1 r))
+{
+    emit_byte(0x66);
+    emit_byte(0xd3);
+    emit_byte(0xe0+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_shll_w_rr,(RW2 d, R1 r))
+
+LOWFUNC(WRITE,NONE,2,raw_shll_b_rr,(RW1 d, R1 r))
+{
+    emit_byte(0xd2);
+    emit_byte(0xe0+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_shll_b_rr,(RW1 d, R1 r))
+
+LOWFUNC(WRITE,NONE,2,raw_ror_b_ri,(RW1 r, IMM i))
+{
+    emit_byte(0xc0);
+    emit_byte(0xc8+r);
+    emit_byte(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_ror_b_ri,(RW1 r, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_ror_w_ri,(RW2 r, IMM i))
+{
+    emit_byte(0x66);
+    emit_byte(0xc1);
+    emit_byte(0xc8+r);
+    emit_byte(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_ror_w_ri,(RW2 r, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_ror_l_ri,(RW4 r, IMM i))
+{
+    emit_byte(0xc1);
+    emit_byte(0xc8+r);
+    emit_byte(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_ror_l_ri,(RW4 r, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_ror_l_rr,(RW4 d, R1 r))
+{
+    emit_byte(0xd3);
+    emit_byte(0xc8+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_ror_l_rr,(RW4 d, R1 r))
+
+LOWFUNC(WRITE,NONE,2,raw_ror_w_rr,(RW2 d, R1 r))
+{
+    emit_byte(0x66);
+    emit_byte(0xd3);
+    emit_byte(0xc8+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_ror_w_rr,(RW2 d, R1 r))
+
+LOWFUNC(WRITE,NONE,2,raw_ror_b_rr,(RW1 d, R1 r))
+{
+    emit_byte(0xd2);
+    emit_byte(0xc8+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_ror_b_rr,(RW1 d, R1 r))
+
+LOWFUNC(WRITE,NONE,2,raw_shrl_l_rr,(RW4 d, R1 r))
+{
+    emit_byte(0xd3);
+    emit_byte(0xe8+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_shrl_l_rr,(RW4 d, R1 r))
+
+LOWFUNC(WRITE,NONE,2,raw_shrl_w_rr,(RW2 d, R1 r))
+{
+    emit_byte(0x66);
+    emit_byte(0xd3);
+    emit_byte(0xe8+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_shrl_w_rr,(RW2 d, R1 r))
+
+LOWFUNC(WRITE,NONE,2,raw_shrl_b_rr,(RW1 d, R1 r))
+{
+    emit_byte(0xd2);
+    emit_byte(0xe8+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_shrl_b_rr,(RW1 d, R1 r))
+
+LOWFUNC(WRITE,NONE,2,raw_shra_l_rr,(RW4 d, R1 r))
+{
+    emit_byte(0xd3);
+    emit_byte(0xf8+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_shra_l_rr,(RW4 d, R1 r))
+
+LOWFUNC(WRITE,NONE,2,raw_shra_w_rr,(RW2 d, R1 r))
+{
+    emit_byte(0x66);
+    emit_byte(0xd3);
+    emit_byte(0xf8+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_shra_w_rr,(RW2 d, R1 r))
+
+LOWFUNC(WRITE,NONE,2,raw_shra_b_rr,(RW1 d, R1 r))
+{
+    emit_byte(0xd2);
+    emit_byte(0xf8+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_shra_b_rr,(RW1 d, R1 r))
+
+LOWFUNC(WRITE,NONE,2,raw_shll_l_ri,(RW4 r, IMM i))
+{
+    emit_byte(0xc1);
+    emit_byte(0xe0+r);
+    emit_byte(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_shll_l_ri,(RW4 r, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_shll_w_ri,(RW2 r, IMM i))
+{
+    emit_byte(0x66);
+    emit_byte(0xc1);
+    emit_byte(0xe0+r);
+    emit_byte(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_shll_w_ri,(RW2 r, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_shll_b_ri,(RW1 r, IMM i))
+{
+    emit_byte(0xc0);
+    emit_byte(0xe0+r);
+    emit_byte(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_shll_b_ri,(RW1 r, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_shrl_l_ri,(RW4 r, IMM i))
+{
+    emit_byte(0xc1);
+    emit_byte(0xe8+r);
+    emit_byte(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_shrl_l_ri,(RW4 r, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_shrl_w_ri,(RW2 r, IMM i))
+{
+    emit_byte(0x66);
+    emit_byte(0xc1);
+    emit_byte(0xe8+r);
+    emit_byte(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_shrl_w_ri,(RW2 r, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_shrl_b_ri,(RW1 r, IMM i))
+{
+    emit_byte(0xc0);
+    emit_byte(0xe8+r);
+    emit_byte(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_shrl_b_ri,(RW1 r, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_shra_l_ri,(RW4 r, IMM i))
+{
+    emit_byte(0xc1);
+    emit_byte(0xf8+r);
+    emit_byte(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_shra_l_ri,(RW4 r, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_shra_w_ri,(RW2 r, IMM i))
+{
+    emit_byte(0x66);
+    emit_byte(0xc1);
+    emit_byte(0xf8+r);
+    emit_byte(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_shra_w_ri,(RW2 r, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_shra_b_ri,(RW1 r, IMM i))
+{
+    emit_byte(0xc0);
+    emit_byte(0xf8+r);
+    emit_byte(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_shra_b_ri,(RW1 r, IMM i))
+
+LOWFUNC(WRITE,NONE,1,raw_sahf,(R2 dummy_ah))
+{
+    emit_byte(0x9e);
+}
+LENDFUNC(WRITE,NONE,1,raw_sahf,(R2 dummy_ah))
+
+LOWFUNC(NONE,NONE,1,raw_cpuid,(R4 dummy_eax))
+{
+    emit_byte(0x0f);
+    emit_byte(0xa2);
+}
+LENDFUNC(NONE,NONE,1,raw_cpuid,(R4 dummy_eax))
+
+LOWFUNC(READ,NONE,1,raw_lahf,(W2 dummy_ah))
+{
+    emit_byte(0x9f);
+}
+LENDFUNC(READ,NONE,1,raw_lahf,(W2 dummy_ah))
+
+LOWFUNC(READ,NONE,2,raw_setcc,(W1 d, IMM cc))
+{
+    emit_byte(0x0f);
+    emit_byte(0x90+cc);
+    emit_byte(0xc0+d);
+}
+LENDFUNC(READ,NONE,2,raw_setcc,(W1 d, IMM cc))
+
+LOWFUNC(READ,WRITE,2,raw_setcc_m,(MEMW d, IMM cc))
+{
+    emit_byte(0x0f);
+    emit_byte(0x90+cc);
+    emit_byte(0x05);
+    emit_long(d);
+}
+LENDFUNC(READ,WRITE,2,raw_setcc_m,(MEMW d, IMM cc))
+
+LOWFUNC(READ,NONE,3,raw_cmov_l_rr,(RW4 d, R4 s, IMM cc))
+{
+    if (have_cmov) {
+       emit_byte(0x0f);
+       emit_byte(0x40+cc);
+       emit_byte(0xc0+8*d+s);
+    }
+    else { /* replacement using branch and mov */
+       int uncc=(cc^1);
+       emit_byte(0x70+uncc); 
+       emit_byte(2);  /* skip next 2 bytes if not cc=true */
+       emit_byte(0x89);
+       emit_byte(0xc0+8*s+d);
+    }
+}
+LENDFUNC(READ,NONE,3,raw_cmov_l_rr,(RW4 d, R4 s, IMM cc))
+
+LOWFUNC(WRITE,NONE,2,raw_bsf_l_rr,(W4 d, R4 s))
+{
+    emit_byte(0x0f);
+    emit_byte(0xbc);
+    emit_byte(0xc0+8*d+s);
+}
+LENDFUNC(WRITE,NONE,2,raw_bsf_l_rr,(W4 d, R4 s))
+
+LOWFUNC(NONE,NONE,2,raw_sign_extend_16_rr,(W4 d, R2 s))
+{
+    emit_byte(0x0f);
+    emit_byte(0xbf);
+    emit_byte(0xc0+8*d+s);
+}
+LENDFUNC(NONE,NONE,2,raw_sign_extend_16_rr,(W4 d, R2 s))
+
+LOWFUNC(NONE,NONE,2,raw_sign_extend_8_rr,(W4 d, R1 s))
+{
+    emit_byte(0x0f);
+    emit_byte(0xbe);
+    emit_byte(0xc0+8*d+s);
+}
+LENDFUNC(NONE,NONE,2,raw_sign_extend_8_rr,(W4 d, R1 s))
+
+LOWFUNC(NONE,NONE,2,raw_zero_extend_16_rr,(W4 d, R2 s))
+{
+    emit_byte(0x0f);
+    emit_byte(0xb7);
+    emit_byte(0xc0+8*d+s);
+}
+LENDFUNC(NONE,NONE,2,raw_zero_extend_16_rr,(W4 d, R2 s))
+
+LOWFUNC(NONE,NONE,2,raw_zero_extend_8_rr,(W4 d, R1 s))
+{
+    emit_byte(0x0f);
+    emit_byte(0xb6);
+    emit_byte(0xc0+8*d+s);
+}
+LENDFUNC(NONE,NONE,2,raw_zero_extend_8_rr,(W4 d, R1 s))
+
+LOWFUNC(NONE,NONE,2,raw_imul_32_32,(RW4 d, R4 s))
+{
+    emit_byte(0x0f);
+    emit_byte(0xaf);
+    emit_byte(0xc0+8*d+s);
+}
+LENDFUNC(NONE,NONE,2,raw_imul_32_32,(RW4 d, R4 s))
+
+LOWFUNC(NONE,NONE,2,raw_imul_64_32,(RW4 d, RW4 s))
+{
+    if (d!=MUL_NREG1 || s!=MUL_NREG2)
+       abort();
+    emit_byte(0xf7);
+    emit_byte(0xea);
+}
+LENDFUNC(NONE,NONE,2,raw_imul_64_32,(RW4 d, RW4 s))
+
+LOWFUNC(NONE,NONE,2,raw_mul_64_32,(RW4 d, RW4 s))
+{
+    if (d!=MUL_NREG1 || s!=MUL_NREG2) {
+       printf("Bad register in MUL: d=%d, s=%d\n",d,s);
+       abort();
+    }
+    emit_byte(0xf7);
+    emit_byte(0xe2);
+}
+LENDFUNC(NONE,NONE,2,raw_mul_64_32,(RW4 d, RW4 s))
+
+LOWFUNC(NONE,NONE,2,raw_mul_32_32,(RW4 d, R4 s))
+{
+    abort(); /* %^$&%^$%#^ x86! */
+    emit_byte(0x0f);
+    emit_byte(0xaf);
+    emit_byte(0xc0+8*d+s);
+}
+LENDFUNC(NONE,NONE,2,raw_mul_32_32,(RW4 d, R4 s))
+
+LOWFUNC(NONE,NONE,2,raw_mov_b_rr,(W1 d, R1 s))
+{
+    emit_byte(0x88);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(NONE,NONE,2,raw_mov_b_rr,(W1 d, R1 s))
+
+LOWFUNC(NONE,NONE,2,raw_mov_w_rr,(W2 d, R2 s))
+{
+    emit_byte(0x66);
+    emit_byte(0x89);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(NONE,NONE,2,raw_mov_w_rr,(W2 d, R2 s))
+
+LOWFUNC(NONE,READ,4,raw_mov_l_rrm_indexed,(W4 d,R4 baser, R4 index, IMM factor))
+{
+    int isebp=(baser==5)?0x40:0;
+    int fi;
+    
+    switch(factor) {
+     case 1: fi=0; break;
+     case 2: fi=1; break;
+     case 4: fi=2; break;
+     case 8: fi=3; break;
+     default: abort();
+    }
+
+
+    emit_byte(0x8b);
+    emit_byte(0x04+8*d+isebp);
+    emit_byte(baser+8*index+0x40*fi);
+    if (isebp)
+       emit_byte(0x00);
+}
+LENDFUNC(NONE,READ,4,raw_mov_l_rrm_indexed,(W4 d,R4 baser, R4 index, IMM factor))
+
+LOWFUNC(NONE,READ,4,raw_mov_w_rrm_indexed,(W2 d, R4 baser, R4 index, IMM factor))
+{
+    int fi;
+    int isebp;
+    
+    switch(factor) {
+     case 1: fi=0; break;
+     case 2: fi=1; break;
+     case 4: fi=2; break;
+     case 8: fi=3; break;
+     default: abort();
+    }
+    isebp=(baser==5)?0x40:0;
+    
+    emit_byte(0x66);
+    emit_byte(0x8b);
+    emit_byte(0x04+8*d+isebp);
+    emit_byte(baser+8*index+0x40*fi);
+    if (isebp)
+       emit_byte(0x00);
+}
+LENDFUNC(NONE,READ,4,raw_mov_w_rrm_indexed,(W2 d, R4 baser, R4 index, IMM factor))
+
+LOWFUNC(NONE,READ,4,raw_mov_b_rrm_indexed,(W1 d, R4 baser, R4 index, IMM factor))
+{
+   int fi;
+  int isebp;
+
+  switch(factor) {
+  case 1: fi=0; break;
+  case 2: fi=1; break;
+  case 4: fi=2; break;
+  case 8: fi=3; break;
+  default: abort();
+  }
+  isebp=(baser==5)?0x40:0;
+
+   emit_byte(0x8a);
+    emit_byte(0x04+8*d+isebp);
+    emit_byte(baser+8*index+0x40*fi);
+    if (isebp)
+       emit_byte(0x00);
+}
+LENDFUNC(NONE,READ,4,raw_mov_b_rrm_indexed,(W1 d, R4 baser, R4 index, IMM factor))
+
+LOWFUNC(NONE,WRITE,4,raw_mov_l_mrr_indexed,(R4 baser, R4 index, IMM factor, R4 s))
+{
+  int fi;
+  int isebp;
+
+  switch(factor) {
+  case 1: fi=0; break;
+  case 2: fi=1; break;
+  case 4: fi=2; break;
+  case 8: fi=3; break;
+  default: abort();
+  }
+
+  
+  isebp=(baser==5)?0x40:0;
+
+    emit_byte(0x89);
+    emit_byte(0x04+8*s+isebp);
+    emit_byte(baser+8*index+0x40*fi);
+    if (isebp)
+       emit_byte(0x00);
+}
+LENDFUNC(NONE,WRITE,4,raw_mov_l_mrr_indexed,(R4 baser, R4 index, IMM factor, R4 s))
+
+LOWFUNC(NONE,WRITE,4,raw_mov_w_mrr_indexed,(R4 baser, R4 index, IMM factor, R2 s))
+{
+  int fi;
+  int isebp;
+
+  switch(factor) {
+  case 1: fi=0; break;
+  case 2: fi=1; break;
+  case 4: fi=2; break;
+  case 8: fi=3; break;
+  default: abort();
+  }
+  isebp=(baser==5)?0x40:0;
+
+    emit_byte(0x66);
+    emit_byte(0x89);
+    emit_byte(0x04+8*s+isebp);
+    emit_byte(baser+8*index+0x40*fi);
+    if (isebp)
+       emit_byte(0x00);
+}
+LENDFUNC(NONE,WRITE,4,raw_mov_w_mrr_indexed,(R4 baser, R4 index, IMM factor, R2 s))
+
+LOWFUNC(NONE,WRITE,4,raw_mov_b_mrr_indexed,(R4 baser, R4 index, IMM factor, R1 s))
+{
+  int fi;
+  int isebp;
+
+  switch(factor) {
+  case 1: fi=0; break;
+  case 2: fi=1; break;
+  case 4: fi=2; break;
+  case 8: fi=3; break;
+  default: abort();
+  }
+  isebp=(baser==5)?0x40:0;
+
+    emit_byte(0x88);
+    emit_byte(0x04+8*s+isebp);
+    emit_byte(baser+8*index+0x40*fi);
+    if (isebp)
+       emit_byte(0x00);
+}
+LENDFUNC(NONE,WRITE,4,raw_mov_b_mrr_indexed,(R4 baser, R4 index, IMM factor, R1 s))
+
+LOWFUNC(NONE,WRITE,5,raw_mov_l_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R4 s))
+{
+  int fi;
+
+  switch(factor) {
+  case 1: fi=0; break;
+  case 2: fi=1; break;
+  case 4: fi=2; break;
+  case 8: fi=3; break;
+  default: abort();
+  }
+
+    emit_byte(0x89);
+    emit_byte(0x84+8*s);
+    emit_byte(baser+8*index+0x40*fi);
+    emit_long(base);
+}
+LENDFUNC(NONE,WRITE,5,raw_mov_l_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R4 s))
+
+LOWFUNC(NONE,WRITE,5,raw_mov_w_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R2 s))
+{
+  int fi;
+
+  switch(factor) {
+  case 1: fi=0; break;
+  case 2: fi=1; break;
+  case 4: fi=2; break;
+  case 8: fi=3; break;
+  default: abort();
+  }
+
+    emit_byte(0x66);
+    emit_byte(0x89);
+    emit_byte(0x84+8*s);
+    emit_byte(baser+8*index+0x40*fi);
+    emit_long(base);
+}
+LENDFUNC(NONE,WRITE,5,raw_mov_w_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R2 s))
+
+LOWFUNC(NONE,WRITE,5,raw_mov_b_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R1 s))
+{
+  int fi;
+
+  switch(factor) {
+  case 1: fi=0; break;
+  case 2: fi=1; break;
+  case 4: fi=2; break;
+  case 8: fi=3; break;
+  default: abort();
+  }
+
+    emit_byte(0x88);
+    emit_byte(0x84+8*s);
+    emit_byte(baser+8*index+0x40*fi);
+    emit_long(base);
+}
+LENDFUNC(NONE,WRITE,5,raw_mov_b_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R1 s))
+
+LOWFUNC(NONE,READ,5,raw_mov_l_brrm_indexed,(W4 d, IMM base, R4 baser, R4 index, IMM factor))
+{
+  int fi;
+
+  switch(factor) {
+  case 1: fi=0; break;
+  case 2: fi=1; break;
+  case 4: fi=2; break;
+  case 8: fi=3; break;
+  default: abort();
+  }
+
+    emit_byte(0x8b);
+    emit_byte(0x84+8*d);
+    emit_byte(baser+8*index+0x40*fi);
+    emit_long(base);
+}
+LENDFUNC(NONE,READ,5,raw_mov_l_brrm_indexed,(W4 d, IMM base, R4 baser, R4 index, IMM factor))
+
+LOWFUNC(NONE,READ,5,raw_mov_w_brrm_indexed,(W2 d, IMM base, R4 baser, R4 index, IMM factor))
+{
+  int fi;
+
+  switch(factor) {
+  case 1: fi=0; break;
+  case 2: fi=1; break;
+  case 4: fi=2; break;
+  case 8: fi=3; break;
+  default: abort();
+  }
+
+    emit_byte(0x66);
+    emit_byte(0x8b);
+    emit_byte(0x84+8*d);
+    emit_byte(baser+8*index+0x40*fi);
+    emit_long(base);
+}
+LENDFUNC(NONE,READ,5,raw_mov_w_brrm_indexed,(W2 d, IMM base, R4 baser, R4 index, IMM factor))
+
+LOWFUNC(NONE,READ,5,raw_mov_b_brrm_indexed,(W1 d, IMM base, R4 baser, R4 index, IMM factor))
+{
+  int fi;
+
+  switch(factor) {
+  case 1: fi=0; break;
+  case 2: fi=1; break;
+  case 4: fi=2; break;
+  case 8: fi=3; break;
+  default: abort();
+  }
+
+    emit_byte(0x8a);
+    emit_byte(0x84+8*d);
+    emit_byte(baser+8*index+0x40*fi);
+    emit_long(base);
+}
+LENDFUNC(NONE,READ,5,raw_mov_b_brrm_indexed,(W1 d, IMM base, R4 baser, R4 index, IMM factor))
+
+LOWFUNC(NONE,READ,4,raw_mov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor))
+{
+  int fi;
+  switch(factor) {
+  case 1: fi=0; break;
+  case 2: fi=1; break;
+  case 4: fi=2; break;
+  case 8: fi=3; break;
+  default: 
+    fprintf(stderr,"Bad factor %d in mov_l_rm_indexed!\n",factor);
+    abort();
+  }
+    emit_byte(0x8b);
+    emit_byte(0x04+8*d);
+    emit_byte(0x05+8*index+64*fi);
+    emit_long(base);
+}
+LENDFUNC(NONE,READ,4,raw_mov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor))
+
+LOWFUNC(NONE,READ,5,raw_cmov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor, IMM cond))
+{
+    int fi;
+    switch(factor) {
+     case 1: fi=0; break;
+     case 2: fi=1; break;
+     case 4: fi=2; break;
+     case 8: fi=3; break;
+     default: 
+       fprintf(stderr,"Bad factor %d in mov_l_rm_indexed!\n",factor);
+       abort();
+    }
+    if (have_cmov) {
+       emit_byte(0x0f);
+       emit_byte(0x40+cond);
+       emit_byte(0x04+8*d);
+       emit_byte(0x05+8*index+64*fi);
+       emit_long(base);
+    }
+    else { /* replacement using branch and mov */
+       int uncc=(cond^1);
+       emit_byte(0x70+uncc); 
+       emit_byte(7);  /* skip next 7 bytes if not cc=true */
+       emit_byte(0x8b);
+       emit_byte(0x04+8*d);
+       emit_byte(0x05+8*index+64*fi);
+       emit_long(base);
+    }
+}
+LENDFUNC(NONE,READ,5,raw_cmov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor, IMM cond))
+
+LOWFUNC(NONE,READ,3,raw_cmov_l_rm,(W4 d, IMM mem, IMM cond))
+{
+    if (have_cmov) {
+       emit_byte(0x0f);
+       emit_byte(0x40+cond);
+       emit_byte(0x05+8*d);
+       emit_long(mem);
+    }
+    else { /* replacement using branch and mov */
+       int uncc=(cond^1);
+       emit_byte(0x70+uncc); 
+       emit_byte(6);  /* skip next 6 bytes if not cc=true */
+       emit_byte(0x8b);
+       emit_byte(0x05+8*d);
+       emit_long(mem);
+    }
+}
+LENDFUNC(NONE,READ,3,raw_cmov_l_rm,(W4 d, IMM mem, IMM cond))
+
+LOWFUNC(NONE,READ,3,raw_mov_l_rR,(W4 d, R4 s, IMM offset))
+{
+    emit_byte(0x8b);
+    emit_byte(0x40+8*d+s);
+    emit_byte(offset);
+}
+LENDFUNC(NONE,READ,3,raw_mov_l_rR,(W4 d, R4 s, IMM offset))
+
+LOWFUNC(NONE,READ,3,raw_mov_w_rR,(W2 d, R4 s, IMM offset))
+{
+    emit_byte(0x66);
+    emit_byte(0x8b);
+    emit_byte(0x40+8*d+s);
+    emit_byte(offset);
+}
+LENDFUNC(NONE,READ,3,raw_mov_w_rR,(W2 d, R4 s, IMM offset))
+
+LOWFUNC(NONE,READ,3,raw_mov_b_rR,(W1 d, R4 s, IMM offset))
+{
+    emit_byte(0x8a);
+    emit_byte(0x40+8*d+s);
+    emit_byte(offset);
+}
+LENDFUNC(NONE,READ,3,raw_mov_b_rR,(W1 d, R4 s, IMM offset))
+
+LOWFUNC(NONE,READ,3,raw_mov_l_brR,(W4 d, R4 s, IMM offset))
+{
+    emit_byte(0x8b);
+    emit_byte(0x80+8*d+s);
+    emit_long(offset);
+}
+LENDFUNC(NONE,READ,3,raw_mov_l_brR,(W4 d, R4 s, IMM offset))
+
+LOWFUNC(NONE,READ,3,raw_mov_w_brR,(W2 d, R4 s, IMM offset))
+{
+    emit_byte(0x66);
+    emit_byte(0x8b);
+    emit_byte(0x80+8*d+s);
+    emit_long(offset);
+}
+LENDFUNC(NONE,READ,3,raw_mov_w_brR,(W2 d, R4 s, IMM offset))
+
+LOWFUNC(NONE,READ,3,raw_mov_b_brR,(W1 d, R4 s, IMM offset))
+{
+    emit_byte(0x8a);
+    emit_byte(0x80+8*d+s);
+    emit_long(offset);
+}
+LENDFUNC(NONE,READ,3,raw_mov_b_brR,(W1 d, R4 s, IMM offset))
+
+LOWFUNC(NONE,WRITE,3,raw_mov_l_Ri,(R4 d, IMM i, IMM offset))
+{
+    emit_byte(0xc7);
+    emit_byte(0x40+d);
+    emit_byte(offset);
+    emit_long(i);
+}
+LENDFUNC(NONE,WRITE,3,raw_mov_l_Ri,(R4 d, IMM i, IMM offset))
+
+LOWFUNC(NONE,WRITE,3,raw_mov_w_Ri,(R4 d, IMM i, IMM offset))
+{
+    emit_byte(0x66);
+    emit_byte(0xc7);
+    emit_byte(0x40+d);
+    emit_byte(offset);
+    emit_word(i);
+}
+LENDFUNC(NONE,WRITE,3,raw_mov_w_Ri,(R4 d, IMM i, IMM offset))
+
+LOWFUNC(NONE,WRITE,3,raw_mov_b_Ri,(R4 d, IMM i, IMM offset))
+{
+    emit_byte(0xc6);
+    emit_byte(0x40+d);
+    emit_byte(offset);
+    emit_byte(i);
+}
+LENDFUNC(NONE,WRITE,3,raw_mov_b_Ri,(R4 d, IMM i, IMM offset))
+
+LOWFUNC(NONE,WRITE,3,raw_mov_l_Rr,(R4 d, R4 s, IMM offset))
+{
+    emit_byte(0x89);
+    emit_byte(0x40+8*s+d);
+    emit_byte(offset);
+}
+LENDFUNC(NONE,WRITE,3,raw_mov_l_Rr,(R4 d, R4 s, IMM offset))
+
+LOWFUNC(NONE,WRITE,3,raw_mov_w_Rr,(R4 d, R2 s, IMM offset))
+{
+    emit_byte(0x66);
+    emit_byte(0x89);
+    emit_byte(0x40+8*s+d);
+    emit_byte(offset);
+}
+LENDFUNC(NONE,WRITE,3,raw_mov_w_Rr,(R4 d, R2 s, IMM offset))
+
+LOWFUNC(NONE,WRITE,3,raw_mov_b_Rr,(R4 d, R1 s, IMM offset))
+{
+    emit_byte(0x88);
+    emit_byte(0x40+8*s+d);
+    emit_byte(offset);
+}
+LENDFUNC(NONE,WRITE,3,raw_mov_b_Rr,(R4 d, R1 s, IMM offset))
+
+LOWFUNC(NONE,NONE,3,raw_lea_l_brr,(W4 d, R4 s, IMM offset))
+{
+    emit_byte(0x8d);
+    emit_byte(0x80+8*d+s);
+    emit_long(offset);
+}
+LENDFUNC(NONE,NONE,3,raw_lea_l_brr,(W4 d, R4 s, IMM offset))
+
+LOWFUNC(NONE,NONE,5,raw_lea_l_brr_indexed,(W4 d, R4 s, R4 index, IMM factor, IMM offset))
+{
+  int fi;
+  
+  switch(factor) {
+  case 1: fi=0; break;
+  case 2: fi=1; break;
+  case 4: fi=2; break;
+  case 8: fi=3; break;
+  default: abort();
+  }
+
+    emit_byte(0x8d);
+    emit_byte(0x84+8*d);
+    emit_byte(0x40*fi+8*index+s);
+    emit_long(offset);
+}
+LENDFUNC(NONE,NONE,5,raw_lea_l_brr_indexed,(W4 d, R4 s, R4 index, IMM factor, IMM offset))
+
+LOWFUNC(NONE,NONE,4,raw_lea_l_rr_indexed,(W4 d, R4 s, R4 index, IMM factor))
+{
+  int isebp=(s==5)?0x40:0;
+  int fi;
+  
+  switch(factor) {
+  case 1: fi=0; break;
+  case 2: fi=1; break;
+  case 4: fi=2; break;
+  case 8: fi=3; break;
+  default: abort();
+  }
+
+    emit_byte(0x8d);
+    emit_byte(0x04+8*d+isebp);
+    emit_byte(0x40*fi+8*index+s);
+    if (isebp)
+      emit_byte(0);
+}
+LENDFUNC(NONE,NONE,4,raw_lea_l_rr_indexed,(W4 d, R4 s, R4 index, IMM factor))
+
+LOWFUNC(NONE,WRITE,3,raw_mov_l_bRr,(R4 d, R4 s, IMM offset))
+{
+    emit_byte(0x89);
+    emit_byte(0x80+8*s+d);
+    emit_long(offset);
+}
+LENDFUNC(NONE,WRITE,3,raw_mov_l_bRr,(R4 d, R4 s, IMM offset))
+
+LOWFUNC(NONE,WRITE,3,raw_mov_w_bRr,(R4 d, R2 s, IMM offset))
+{
+    emit_byte(0x66);
+    emit_byte(0x89);
+    emit_byte(0x80+8*s+d);
+    emit_long(offset);
+}
+LENDFUNC(NONE,WRITE,3,raw_mov_w_bRr,(R4 d, R2 s, IMM offset))
+
+LOWFUNC(NONE,WRITE,3,raw_mov_b_bRr,(R4 d, R1 s, IMM offset))
+{
+    emit_byte(0x88);
+    emit_byte(0x80+8*s+d);
+    emit_long(offset);
+}
+LENDFUNC(NONE,WRITE,3,raw_mov_b_bRr,(R4 d, R1 s, IMM offset))
+
+LOWFUNC(NONE,NONE,1,raw_bswap_32,(RW4 r))
+{
+    emit_byte(0x0f);
+    emit_byte(0xc8+r);
+}
+LENDFUNC(NONE,NONE,1,raw_bswap_32,(RW4 r))
+
+LOWFUNC(WRITE,NONE,1,raw_bswap_16,(RW2 r))
+{
+    emit_byte(0x66);
+    emit_byte(0xc1);
+    emit_byte(0xc0+r);
+    emit_byte(0x08);
+}
+LENDFUNC(WRITE,NONE,1,raw_bswap_16,(RW2 r))
+
+LOWFUNC(NONE,NONE,2,raw_mov_l_rr,(W4 d, R4 s))
+{
+    emit_byte(0x89);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(NONE,NONE,2,raw_mov_l_rr,(W4 d, R4 s))
+
+LOWFUNC(NONE,WRITE,2,raw_mov_l_mr,(IMM d, R4 s))
+{
+    emit_byte(0x89);
+    emit_byte(0x05+8*s);
+    emit_long(d);
+}
+LENDFUNC(NONE,WRITE,2,raw_mov_l_mr,(IMM d, R4 s))
+
+LOWFUNC(NONE,READ,2,raw_mov_l_rm,(W4 d, MEMR s))
+{
+    emit_byte(0x8b);
+    emit_byte(0x05+8*d);
+    emit_long(s);
+}
+LENDFUNC(NONE,READ,2,raw_mov_l_rm,(W4 d, MEMR s))
+
+LOWFUNC(NONE,WRITE,2,raw_mov_w_mr,(IMM d, R2 s))
+{
+    emit_byte(0x66);
+    emit_byte(0x89);
+    emit_byte(0x05+8*s);
+    emit_long(d);
+}
+LENDFUNC(NONE,WRITE,2,raw_mov_w_mr,(IMM d, R2 s))
+
+LOWFUNC(NONE,READ,2,raw_mov_w_rm,(W2 d, IMM s))
+{
+    emit_byte(0x66);
+    emit_byte(0x8b);
+    emit_byte(0x05+8*d);
+    emit_long(s);
+}
+LENDFUNC(NONE,READ,2,raw_mov_w_rm,(W2 d, IMM s))
+
+LOWFUNC(NONE,WRITE,2,raw_mov_b_mr,(IMM d, R1 s))
+{
+    emit_byte(0x88);
+    emit_byte(0x05+8*s);
+    emit_long(d);
+}
+LENDFUNC(NONE,WRITE,2,raw_mov_b_mr,(IMM d, R1 s))
+
+LOWFUNC(NONE,READ,2,raw_mov_b_rm,(W1 d, IMM s))
+{
+    emit_byte(0x8a);
+    emit_byte(0x05+8*d);
+    emit_long(s);
+}
+LENDFUNC(NONE,READ,2,raw_mov_b_rm,(W1 d, IMM s))
+
+LOWFUNC(NONE,NONE,2,raw_mov_l_ri,(W4 d, IMM s))
+{
+    emit_byte(0xb8+d);
+    emit_long(s);
+}
+LENDFUNC(NONE,NONE,2,raw_mov_l_ri,(W4 d, IMM s))
+
+LOWFUNC(NONE,NONE,2,raw_mov_w_ri,(W2 d, IMM s))
+{
+    emit_byte(0x66);
+    emit_byte(0xb8+d);
+    emit_word(s);
+}
+LENDFUNC(NONE,NONE,2,raw_mov_w_ri,(W2 d, IMM s))
+
+LOWFUNC(NONE,NONE,2,raw_mov_b_ri,(W1 d, IMM s))
+{
+    emit_byte(0xb0+d);
+    emit_byte(s);
+}
+LENDFUNC(NONE,NONE,2,raw_mov_b_ri,(W1 d, IMM s))
+
+LOWFUNC(RMW,RMW,2,raw_adc_l_mi,(MEMRW d, IMM s))
+{
+    emit_byte(0x81);
+    emit_byte(0x15);
+    emit_long(d);
+    emit_long(s);
+}
+LENDFUNC(RMW,RMW,2,raw_adc_l_mi,(MEMRW d, IMM s))
+
+LOWFUNC(WRITE,RMW,2,raw_add_l_mi,(IMM d, IMM s)) 
+{
+    emit_byte(0x81);
+    emit_byte(0x05);
+    emit_long(d);
+    emit_long(s);
+}
+LENDFUNC(WRITE,RMW,2,raw_add_l_mi,(IMM d, IMM s)) 
+
+LOWFUNC(WRITE,RMW,2,raw_add_w_mi,(IMM d, IMM s)) 
+{
+    emit_byte(0x66);
+    emit_byte(0x81);
+    emit_byte(0x05);
+    emit_long(d);
+    emit_word(s);
+}
+LENDFUNC(WRITE,RMW,2,raw_add_w_mi,(IMM d, IMM s)) 
+
+LOWFUNC(WRITE,RMW,2,raw_add_b_mi,(IMM d, IMM s)) 
+{
+    emit_byte(0x80);
+    emit_byte(0x05);
+    emit_long(d);
+    emit_byte(s);
+}
+LENDFUNC(WRITE,RMW,2,raw_add_b_mi,(IMM d, IMM s)) 
+
+LOWFUNC(WRITE,NONE,2,raw_test_l_ri,(R4 d, IMM i))
+{
+    emit_byte(0xf7);
+    emit_byte(0xc0+d);
+    emit_long(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_test_l_ri,(R4 d, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_test_l_rr,(R4 d, R4 s))
+{
+    emit_byte(0x85);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_test_l_rr,(R4 d, R4 s))
+
+LOWFUNC(WRITE,NONE,2,raw_test_w_rr,(R2 d, R2 s))
+{
+    emit_byte(0x66);
+    emit_byte(0x85);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_test_w_rr,(R2 d, R2 s))
+
+LOWFUNC(WRITE,NONE,2,raw_test_b_rr,(R1 d, R1 s))
+{
+    emit_byte(0x84);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_test_b_rr,(R1 d, R1 s))
+
+LOWFUNC(WRITE,NONE,2,raw_and_l_ri,(RW4 d, IMM i))
+{
+    emit_byte(0x81);
+    emit_byte(0xe0+d);
+    emit_long(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_and_l_ri,(RW4 d, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_and_w_ri,(RW2 d, IMM i))
+{
+    emit_byte(0x66);
+    emit_byte(0x81);
+    emit_byte(0xe0+d);
+    emit_word(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_and_w_ri,(RW2 d, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_and_l,(RW4 d, R4 s))
+{
+    emit_byte(0x21);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_and_l,(RW4 d, R4 s))
+
+LOWFUNC(WRITE,NONE,2,raw_and_w,(RW2 d, R2 s))
+{
+    emit_byte(0x66);
+    emit_byte(0x21);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_and_w,(RW2 d, R2 s))
+
+LOWFUNC(WRITE,NONE,2,raw_and_b,(RW1 d, R1 s))
+{
+    emit_byte(0x20);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_and_b,(RW1 d, R1 s))
+
+LOWFUNC(WRITE,NONE,2,raw_or_l_ri,(RW4 d, IMM i))
+{
+    emit_byte(0x81);
+    emit_byte(0xc8+d);
+    emit_long(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_or_l_ri,(RW4 d, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_or_l,(RW4 d, R4 s))
+{
+    emit_byte(0x09);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_or_l,(RW4 d, R4 s))
+
+LOWFUNC(WRITE,NONE,2,raw_or_w,(RW2 d, R2 s))
+{
+    emit_byte(0x66);
+    emit_byte(0x09);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_or_w,(RW2 d, R2 s))
+
+LOWFUNC(WRITE,NONE,2,raw_or_b,(RW1 d, R1 s))
+{
+    emit_byte(0x08);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_or_b,(RW1 d, R1 s))
+
+LOWFUNC(RMW,NONE,2,raw_adc_l,(RW4 d, R4 s))
+{
+    emit_byte(0x11);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(RMW,NONE,2,raw_adc_l,(RW4 d, R4 s))
+
+LOWFUNC(RMW,NONE,2,raw_adc_w,(RW2 d, R2 s))
+{
+    emit_byte(0x66);
+    emit_byte(0x11);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(RMW,NONE,2,raw_adc_w,(RW2 d, R2 s))
+
+LOWFUNC(RMW,NONE,2,raw_adc_b,(RW1 d, R1 s))
+{
+    emit_byte(0x10);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(RMW,NONE,2,raw_adc_b,(RW1 d, R1 s))
+
+LOWFUNC(WRITE,NONE,2,raw_add_l,(RW4 d, R4 s))
+{
+    emit_byte(0x01);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_add_l,(RW4 d, R4 s))
+
+LOWFUNC(WRITE,NONE,2,raw_add_w,(RW2 d, R2 s))
+{
+    emit_byte(0x66);
+    emit_byte(0x01);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_add_w,(RW2 d, R2 s))
+
+LOWFUNC(WRITE,NONE,2,raw_add_b,(RW1 d, R1 s))
+{
+    emit_byte(0x00);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_add_b,(RW1 d, R1 s))
+
+LOWFUNC(WRITE,NONE,2,raw_sub_l_ri,(RW4 d, IMM i))
+{
+  if (isbyte(i)) {
+    emit_byte(0x83);
+    emit_byte(0xe8+d);
+    emit_byte(i);
+  }
+  else {
+    emit_byte(0x81);
+    emit_byte(0xe8+d);
+    emit_long(i);
+  }
+}
+LENDFUNC(WRITE,NONE,2,raw_sub_l_ri,(RW4 d, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_sub_b_ri,(RW1 d, IMM i))
+{
+    emit_byte(0x80);
+    emit_byte(0xe8+d);
+    emit_byte(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_sub_b_ri,(RW1 d, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_add_l_ri,(RW4 d, IMM i))
+{
+    if (isbyte(i)) {
+       emit_byte(0x83);
+       emit_byte(0xc0+d);
+       emit_byte(i);
+    }
+    else {
+       emit_byte(0x81);
+       emit_byte(0xc0+d);
+       emit_long(i);
+    }
+}
+LENDFUNC(WRITE,NONE,2,raw_add_l_ri,(RW4 d, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_add_w_ri,(RW2 d, IMM i))
+{
+    if (isbyte(i)) {
+       emit_byte(0x66);
+       emit_byte(0x83);
+       emit_byte(0xc0+d);
+       emit_byte(i);
+    }
+    else {
+       emit_byte(0x66);
+       emit_byte(0x81);
+       emit_byte(0xc0+d);
+       emit_word(i);
+    }
+}
+LENDFUNC(WRITE,NONE,2,raw_add_w_ri,(RW2 d, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_add_b_ri,(RW1 d, IMM i))
+{
+    emit_byte(0x80);
+    emit_byte(0xc0+d);
+    emit_byte(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_add_b_ri,(RW1 d, IMM i))
+
+LOWFUNC(RMW,NONE,2,raw_sbb_l,(RW4 d, R4 s))
+{
+    emit_byte(0x19);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(RMW,NONE,2,raw_sbb_l,(RW4 d, R4 s))
+
+LOWFUNC(RMW,NONE,2,raw_sbb_w,(RW2 d, R2 s))
+{
+    emit_byte(0x66);
+    emit_byte(0x19);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(RMW,NONE,2,raw_sbb_w,(RW2 d, R2 s))
+
+LOWFUNC(RMW,NONE,2,raw_sbb_b,(RW1 d, R1 s))
+{
+    emit_byte(0x18);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(RMW,NONE,2,raw_sbb_b,(RW1 d, R1 s))
+
+LOWFUNC(WRITE,NONE,2,raw_sub_l,(RW4 d, R4 s))
+{
+    emit_byte(0x29);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_sub_l,(RW4 d, R4 s))
+
+LOWFUNC(WRITE,NONE,2,raw_sub_w,(RW2 d, R2 s))
+{
+    emit_byte(0x66);
+    emit_byte(0x29);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_sub_w,(RW2 d, R2 s))
+
+LOWFUNC(WRITE,NONE,2,raw_sub_b,(RW1 d, R1 s))
+{
+    emit_byte(0x28);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_sub_b,(RW1 d, R1 s))
+
+LOWFUNC(WRITE,NONE,2,raw_cmp_l,(R4 d, R4 s))
+{
+    emit_byte(0x39);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_cmp_l,(R4 d, R4 s))
+
+LOWFUNC(WRITE,NONE,2,raw_cmp_l_ri,(R4 r, IMM i))
+{
+    emit_byte(0x81);
+    emit_byte(0xf8+r);
+    emit_long(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_cmp_l_ri,(R4 r, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_cmp_w,(R2 d, R2 s))
+{
+    emit_byte(0x66);
+    emit_byte(0x39);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_cmp_w,(R2 d, R2 s))
+
+LOWFUNC(WRITE,NONE,2,raw_cmp_b_ri,(R1 d, IMM i))
+{
+  emit_byte(0x80);
+  emit_byte(0xf8+d);
+  emit_byte(i);
+}
+LENDFUNC(WRITE,NONE,2,raw_cmp_b_ri,(R1 d, IMM i))
+
+LOWFUNC(WRITE,NONE,2,raw_cmp_b,(R1 d, R1 s))
+{
+    emit_byte(0x38);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_cmp_b,(R1 d, R1 s))
+
+LOWFUNC(WRITE,READ,4,raw_cmp_l_rm_indexed,(R4 d, IMM offset, R4 index, IMM factor))
+{
+    int fi;
+    
+    switch(factor) {
+     case 1: fi=0; break;
+     case 2: fi=1; break;
+     case 4: fi=2; break;
+     case 8: fi=3; break;
+     default: abort();
+    }
+    emit_byte(0x39);
+    emit_byte(0x04+8*d);
+    emit_byte(5+8*index+0x40*fi);
+    emit_long(offset);
+}
+LENDFUNC(WRITE,READ,4,raw_cmp_l_rm_indexed,(R4 d, IMM offset, R4 index, IMM factor))
+
+LOWFUNC(WRITE,NONE,2,raw_xor_l,(RW4 d, R4 s))
+{
+    emit_byte(0x31);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_xor_l,(RW4 d, R4 s))
+
+LOWFUNC(WRITE,NONE,2,raw_xor_w,(RW2 d, R2 s))
+{
+    emit_byte(0x66);
+    emit_byte(0x31);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_xor_w,(RW2 d, R2 s))
+
+LOWFUNC(WRITE,NONE,2,raw_xor_b,(RW1 d, R1 s))
+{
+    emit_byte(0x30);
+    emit_byte(0xc0+8*s+d);
+}
+LENDFUNC(WRITE,NONE,2,raw_xor_b,(RW1 d, R1 s))
+
+LOWFUNC(WRITE,RMW,2,raw_sub_l_mi,(MEMRW d, IMM s))
+{
+    emit_byte(0x81);
+    emit_byte(0x2d);
+    emit_long(d);
+    emit_long(s);
+}
+LENDFUNC(WRITE,RMW,2,raw_sub_l_mi,(MEMRW d, IMM s))
+
+LOWFUNC(WRITE,READ,2,raw_cmp_l_mi,(MEMR d, IMM s))
+{
+    emit_byte(0x81);
+    emit_byte(0x3d);
+    emit_long(d);
+    emit_long(s);
+}
+LENDFUNC(WRITE,READ,2,raw_cmp_l_mi,(MEMR d, IMM s))
+
+LOWFUNC(NONE,NONE,2,raw_xchg_l_rr,(RW4 r1, RW4 r2))
+{
+    emit_byte(0x87);
+    emit_byte(0xc0+8*r1+r2);
+}
+LENDFUNC(NONE,NONE,2,raw_xchg_l_rr,(RW4 r1, RW4 r2))
+
+LOWFUNC(READ,WRITE,0,raw_pushfl,(void))
+{
+    emit_byte(0x9c);
+}
+LENDFUNC(READ,WRITE,0,raw_pushfl,(void))
+
+LOWFUNC(WRITE,READ,0,raw_popfl,(void))
+{
+    emit_byte(0x9d);
+}
+LENDFUNC(WRITE,READ,0,raw_popfl,(void))
+
+/*************************************************************************
+ * Unoptimizable stuff --- jump                                          *
+ *************************************************************************/
+
+static __inline__ void raw_call_r(R4 r)
+{
+    lopt_emit_all();
+    emit_byte(0xff);
+    emit_byte(0xd0+r);
+}
+
+static __inline__ void raw_jmp_r(R4 r)
+{
+    lopt_emit_all();
+    emit_byte(0xff);
+    emit_byte(0xe0+r);
+}
+
+static __inline__ void raw_jmp_m_indexed(uae_u32 base, uae_u32 r, uae_u32 m)
+{
+    int mu;
+    switch(m) {
+     case 1: mu=0; break;
+     case 2: mu=1; break;
+     case 4: mu=2; break;
+     case 8: mu=3; break;
+     default: abort();
+    }
+    lopt_emit_all();
+    emit_byte(0xff);
+    emit_byte(0x24);
+    emit_byte(0x05+8*r+0x40*mu);
+    emit_long(base);
+}
+
+static __inline__ void raw_jmp_m(uae_u32 base)
+{
+    lopt_emit_all();
+    emit_byte(0xff);
+    emit_byte(0x25);
+    emit_long(base);
+}
+
+
+static __inline__ void raw_call(uae_u32 t)
+{
+    lopt_emit_all();
+    emit_byte(0xe8);
+    emit_long(t-(uae_u32)target-4);
+}
+
+static __inline__ void raw_jmp(uae_u32 t)
+{
+    lopt_emit_all();
+    emit_byte(0xe9);
+    emit_long(t-(uae_u32)target-4);
+}
+
+static __inline__ void raw_jl(uae_u32 t)
+{
+    lopt_emit_all();
+    emit_byte(0x0f);
+    emit_byte(0x8c);
+    emit_long(t-(uae_u32)target-4);
+}
+
+static __inline__ void raw_jz(uae_u32 t)
+{
+    lopt_emit_all();
+    emit_byte(0x0f);
+    emit_byte(0x84);
+    emit_long(t-(uae_u32)target-4);
+}
+
+static __inline__ void raw_jnz(uae_u32 t)
+{
+    lopt_emit_all();
+    emit_byte(0x0f);
+    emit_byte(0x85);
+    emit_long(t-(uae_u32)target-4);
+}
+
+static __inline__ void raw_jnz_l_oponly(void)
+{
+    lopt_emit_all();
+    emit_byte(0x0f); 
+    emit_byte(0x85); 
+}
+
+static __inline__ void raw_jcc_l_oponly(int cc)
+{
+    lopt_emit_all();
+    emit_byte(0x0f); 
+    emit_byte(0x80+cc); 
+}
+
+static __inline__ void raw_jnz_b_oponly(void)
+{
+    lopt_emit_all();
+    emit_byte(0x75); 
+}
+
+static __inline__ void raw_jz_b_oponly(void)
+{
+    lopt_emit_all();
+    emit_byte(0x74); 
+}
+
+static __inline__ void raw_jmp_l_oponly(void)
+{
+    lopt_emit_all();
+    emit_byte(0xe9); 
+}
+
+static __inline__ void raw_jmp_b_oponly(void)
+{
+    lopt_emit_all();
+    emit_byte(0xeb); 
+}
+
+static __inline__ void raw_ret(void)
+{
+    lopt_emit_all();
+    emit_byte(0xc3);  
+}
+
+static __inline__ void raw_nop(void)
+{
+    lopt_emit_all();
+    emit_byte(0x90);
+}
+
+
+/*************************************************************************
+ * Flag handling, to and fro UAE flag register                           *
+ *************************************************************************/
+
+
+#define FLAG_NREG1 0  /* Set to -1 if any register will do */
+
+static __inline__ void raw_flags_to_reg(int r)
+{
+  raw_lahf(0);  /* Most flags in AH */
+  //raw_setcc(r,0); /* V flag in AL */
+  raw_setcc_m((uae_u32)live.state[FLAGTMP].mem,0); 
+  
+#if 1   /* Let's avoid those nasty partial register stalls */
+  //raw_mov_b_mr((uae_u32)live.state[FLAGTMP].mem,r);
+  raw_mov_b_mr(((uae_u32)live.state[FLAGTMP].mem)+1,r+4);
+  //live.state[FLAGTMP].status=CLEAN;
+  live.state[FLAGTMP].status=INMEM;
+  live.state[FLAGTMP].realreg=-1;
+  /* We just "evicted" FLAGTMP. */
+  if (live.nat[r].nholds!=1) {
+      /* Huh? */
+      abort();
+  }
+  live.nat[r].nholds=0;
+#endif
+}
+
+#define FLAG_NREG2 0  /* Set to -1 if any register will do */
+static __inline__ void raw_reg_to_flags(int r)
+{
+  raw_cmp_b_ri(r,-127); /* set V */
+  raw_sahf(0);
+}
+
+/* Apparently, there are enough instructions between flag store and
+   flag reload to avoid the partial memory stall */
+static __inline__ void raw_load_flagreg(uae_u32 target, uae_u32 r)
+{
+#if 1
+    raw_mov_l_rm(target,(uae_u32)live.state[r].mem);
+#else
+    raw_mov_b_rm(target,(uae_u32)live.state[r].mem);
+    raw_mov_b_rm(target+4,((uae_u32)live.state[r].mem)+1);
+#endif
+}
+
+/* FLAGX is byte sized, and we *do* write it at that size */
+static __inline__ void raw_load_flagx(uae_u32 target, uae_u32 r)
+{
+    if (live.nat[target].canbyte)
+       raw_mov_b_rm(target,(uae_u32)live.state[r].mem);
+    else if (live.nat[target].canword)
+       raw_mov_w_rm(target,(uae_u32)live.state[r].mem);
+    else
+       raw_mov_l_rm(target,(uae_u32)live.state[r].mem);
+}
+
+#define NATIVE_FLAG_Z 0x40
+#define NATIVE_CC_EQ  4
+static __inline__ void raw_flags_set_zero(int f, int r, int t)
+{
+    // FIXME: this is really suboptimal
+    raw_pushfl();
+    raw_pop_l_r(f);
+    raw_and_l_ri(f,~NATIVE_FLAG_Z);
+    raw_test_l_rr(r,r);
+    raw_mov_l_ri(r,0);
+    raw_mov_l_ri(t,NATIVE_FLAG_Z);
+    raw_cmov_l_rr(r,t,NATIVE_CC_EQ);
+    raw_or_l(f,r);
+    raw_push_l_r(f);
+    raw_popfl();
+}
+
+static __inline__ void raw_inc_sp(int off)
+{
+    raw_add_l_ri(4,off);
+}
+
+/*************************************************************************
+ * Handling mistaken direct memory access                                *
+ *************************************************************************/
+
+
+#ifdef NATMEM_OFFSET
+#ifdef _WIN32 // %%% BRIAN KING WAS HERE %%%
+#include <winbase.h>
+#else
+#include <asm/sigcontext.h>
+#endif
+#include <signal.h>
+
+#define SIG_READ 1
+#define SIG_WRITE 2
+
+static int in_handler=0;
+static uae_u8 *veccode;
+
+#ifdef _WIN32
+int EvalException ( LPEXCEPTION_POINTERS blah, int n_except )
+{
+    PEXCEPTION_RECORD pExceptRecord = NULL;
+    PCONTEXT          pContext = NULL;
+
+    uae_u8* i = NULL;
+    uae_u32 addr = 0;
+    int r=-1;
+    int size=4;
+    int dir=-1;
+    int len=0;
+    int j;
+
+    if( n_except != STATUS_ACCESS_VIOLATION || !canbang)
+        return EXCEPTION_CONTINUE_SEARCH;
+
+    pExceptRecord = blah->ExceptionRecord;
+    pContext = blah->ContextRecord;
+
+    if( pContext )
+    {
+       i = (uae_u8 *)(pContext->Eip);
+    }
+    if( pExceptRecord )
+    {
+       addr = (uae_u32)(pExceptRecord->ExceptionInformation[1]);
+    }
+#ifdef JIT_DEBUG
+    write_log("JIT: fault address is 0x%x at 0x%x\n",addr,i);
+#endif
+    if (!canbang || !currprefs.cachesize) 
+    {
+#ifdef JIT_DEBUG
+       write_log("JIT: Not happy! Canbang or cachesize is 0 in SIGSEGV handler!\n");
+#endif
+       return EXCEPTION_CONTINUE_SEARCH;
+    }
+
+    if (in_handler) 
+       write_log("JIT: Argh --- Am already in a handler. Shouldn't happen!\n");
+    
+    if (canbang && i>=compiled_code && i<=current_compile_p) {
+       if (*i==0x66) {
+           i++;
+           size=2;
+           len++;
+       }
+       
+       switch(i[0]) {
+       case 0x8a:
+           if ((i[1]&0xc0)==0x80) {
+               r=(i[1]>>3)&7;
+               dir=SIG_READ;
+               size=1;
+               len+=6;
+               break;
+           }
+           break;
+       case 0x88:
+           if ((i[1]&0xc0)==0x80) {
+               r=(i[1]>>3)&7;
+               dir=SIG_WRITE;
+               size=1;
+               len+=6;
+               break;
+           }
+           break;
+       case 0x8b:
+           switch(i[1]&0xc0) {
+           case 0x80:
+               r=(i[1]>>3)&7;
+               dir=SIG_READ;
+               len+=6;
+               break;
+           case 0x40:
+               r=(i[1]>>3)&7;
+               dir=SIG_READ;
+               len+=3;
+               break;
+           case 0x00:
+               r=(i[1]>>3)&7;
+               dir=SIG_READ;
+               len+=2;
+               break;
+           default: 
+               break;
+           }
+           break;
+           case 0x89:
+               switch(i[1]&0xc0) {
+               case 0x80:
+                   r=(i[1]>>3)&7;
+                   dir=SIG_WRITE;
+                   len+=6;
+                   break;
+               case 0x40:
+                   r=(i[1]>>3)&7;
+                   dir=SIG_WRITE;
+                   len+=3;
+                   break;
+               case 0x00:
+                   r=(i[1]>>3)&7;
+                   dir=SIG_WRITE;
+                   len+=2;
+                   break;
+               }
+               break;
+       }       
+    }
+    
+    if (r!=-1) { 
+       void* pr=NULL;
+#ifdef JIT_DEBUG
+       write_log("register was %d, direction was %d, size was %d\n",r,dir,size);
+#endif
+
+       switch(r) {
+       case 0: pr=&(pContext->Eax); break;
+       case 1: pr=&(pContext->Ecx); break;
+       case 2: pr=&(pContext->Edx); break;
+       case 3: pr=&(pContext->Ebx); break;
+       case 4: pr=(size>1)?NULL:(((uae_u8*)&(pContext->Eax))+1); break;
+       case 5: pr=(size>1)?
+                   (void*)(&(pContext->Ebp)):
+           (void*)(((uae_u8*)&(pContext->Ecx))+1); break;
+       case 6: pr=(size>1)?
+                   (void*)(&(pContext->Esi)):
+           (void*)(((uae_u8*)&(pContext->Edx))+1); break;
+       case 7: pr=(size>1)?
+                   (void*)(&(pContext->Edi)):
+           (void*)(((uae_u8*)&(pContext->Ebx))+1); break;
+       default: abort();
+       }
+       if (pr) {
+           blockinfo* bi;
+           
+           if (currprefs.comp_oldsegv) {
+               addr-=NATMEM_OFFSET;
+               
+               if ((addr>=0x10000000 && addr<0x40000000) ||
+                   (addr>=0x50000000)) {
+#ifdef JIT_DEBUG
+                   write_log("Suspicious address 0x%x in SEGV handler.\n",addr);
+#endif
+               }
+               if (dir==SIG_READ) {
+                   switch(size) {
+                   case 1: *((uae_u8*)pr)=get_byte(addr); break;
+                   case 2: *((uae_u16*)pr)=swap16(get_word(addr)); break;
+                   case 4: *((uae_u32*)pr)=swap32(get_long(addr)); break;
+                   default: abort();
+                   }
+               }
+               else { /* write */
+                   switch(size) {
+                   case 1: put_byte(addr,*((uae_u8*)pr)); break;
+                   case 2: put_word(addr,swap16(*((uae_u16*)pr))); break;
+                   case 4: put_long(addr,swap32(*((uae_u32*)pr))); break;
+                   default: abort();
+                   }
+               }
+#ifdef JIT_DEBUG
+               write_log("Handled one access!\n");
+#endif
+               fflush(stdout);
+               segvcount++;
+               pContext->Eip+=len;
+           }
+           else {
+               void* tmp=target;
+               int i;
+               uae_u8 vecbuf[5];
+               
+               addr-=NATMEM_OFFSET;
+               
+               if ((addr>=0x10000000 && addr<0x40000000) ||
+                   (addr>=0x50000000)) {
+#ifdef JIT_DEBUG
+                   write_log("Suspicious address 0x%x in SEGV handler.\n",addr);
+#endif
+               }
+       
+               target=(uae_u8*)pContext->Eip;
+               for (i=0;i<5;i++)
+                   vecbuf[i]=target[i];
+               emit_byte(0xe9);
+               emit_long((uae_u32)veccode-(uae_u32)target-4);
+#ifdef JIT_DEBUG
+
+               write_log("Create jump to %p\n",veccode);
+               write_log("Handled one access!\n");
+#endif
+               segvcount++;
+               
+               target=veccode;
+               
+               if (dir==SIG_READ) {
+                   switch(size) {
+                   case 1: raw_mov_b_ri(r,get_byte(addr)); break;
+                   case 2: raw_mov_w_ri(r,swap16(get_word(addr))); break;
+                   case 4: raw_mov_l_ri(r,swap32(get_long(addr))); break;
+                   default: abort();
+                   }
+               }
+               else { /* write */
+                   switch(size) {
+                   case 1: put_byte(addr,*((uae_u8*)pr)); break;
+                   case 2: put_word(addr,swap16(*((uae_u16*)pr))); break;
+                   case 4: put_long(addr,swap32(*((uae_u32*)pr))); break;
+                   default: abort();
+                   }
+               }
+               for (i=0;i<5;i++)
+                   raw_mov_b_mi(pContext->Eip+i,vecbuf[i]);
+               raw_mov_l_mi((uae_u32)&in_handler,0);
+               emit_byte(0xe9);
+               emit_long(pContext->Eip+len-(uae_u32)target-4);
+               in_handler=1;
+               target=tmp;
+           }
+           bi=active;
+           while (bi) {
+               if (bi->handler && 
+                   (uae_u8*)bi->direct_handler<=i &&
+                   (uae_u8*)bi->nexthandler>i) {
+#ifdef JIT_DEBUG
+                   write_log("deleted trigger (%p<%p<%p) %p\n",
+                       bi->handler,
+                       i,
+                       bi->nexthandler,
+                       bi->pc_p);
+#endif
+                   invalidate_block(bi);
+                   raise_in_cl_list(bi);
+                   set_special(0);
+                   return EXCEPTION_CONTINUE_EXECUTION;
+               }
+               bi=bi->next;
+           }
+           /* Not found in the active list. Might be a rom routine that
+           is in the dormant list */
+           bi=dormant;
+           while (bi) {
+               if (bi->handler && 
+                   (uae_u8*)bi->direct_handler<=i &&
+                   (uae_u8*)bi->nexthandler>i) {
+#ifdef JIT_DEBUG
+                   write_log("deleted trigger (%p<%p<%p) %p\n",
+                       bi->handler,
+                       i,
+                       bi->nexthandler,
+                       bi->pc_p);
+#endif
+                   invalidate_block(bi);
+                   raise_in_cl_list(bi);
+                   set_special(0);
+                   return EXCEPTION_CONTINUE_EXECUTION;
+               }
+               bi=bi->next;
+           }
+#ifdef JIT_DEBUG
+           write_log("Huh? Could not find trigger!\n");
+#endif
+           return EXCEPTION_CONTINUE_EXECUTION;
+       }
+    }
+    write_log("JIT: Can't handle access!\n");
+    if( i )
+    {
+       for (j=0;j<10;j++) {
+           write_log("JIT: instruction byte %2d is 0x%02x\n",j,i[j]);
+       }
+    }
+#if 0
+    write_log("Please send the above info (starting at \"fault address\") to\n"
+          "bmeyer@csse.monash.edu.au\n"
+          "This shouldn't happen ;-)\n");
+#endif
+    return EXCEPTION_CONTINUE_SEARCH;
+}
+#else
+static void vec(int x, struct sigcontext sc)
+{
+    uae_u8* i=(uae_u8*)sc.eip;
+    uae_u32 addr=sc.cr2;
+    int r=-1;
+    int size=4;
+    int dir=-1;
+    int len=0;
+    int j;
+    
+    write_log("fault address is %08x at %08x\n",sc.cr2,sc.eip);
+    if (!canbang) 
+       write_log("Not happy! Canbang is 0 in SIGSEGV handler!\n");
+    if (in_handler) 
+       write_log("Argh --- Am already in a handler. Shouldn't happen!\n");
+
+    if (canbang && i>=compiled_code && i<=current_compile_p) {
+       if (*i==0x66) {
+           i++;
+           size=2;
+           len++;
+       }
+       
+       switch(i[0]) {
+        case 0x8a:
+           if ((i[1]&0xc0)==0x80) {
+               r=(i[1]>>3)&7;
+               dir=SIG_READ;
+               size=1;
+               len+=6;
+               break;
+           }
+           break;
+        case 0x88:
+           if ((i[1]&0xc0)==0x80) {
+               r=(i[1]>>3)&7;
+               dir=SIG_WRITE;
+               size=1;
+               len+=6;
+               break;
+           }
+           break;
+
+        case 0x8b:
+          switch(i[1]&0xc0) {
+          case 0x80:
+            r=(i[1]>>3)&7;
+            dir=SIG_READ;
+            len+=6;
+            break;
+          case 0x40:
+            r=(i[1]>>3)&7;
+            dir=SIG_READ;
+            len+=3;
+            break;
+          case 0x00:
+            r=(i[1]>>3)&7;
+            dir=SIG_READ;
+            len+=2;
+            break;
+          default: 
+            break;
+          }
+          break;
+           
+        case 0x89:
+          switch(i[1]&0xc0) {
+          case 0x80:
+            r=(i[1]>>3)&7;
+            dir=SIG_WRITE;
+            len+=6;
+            break;
+          case 0x40:
+            r=(i[1]>>3)&7;
+            dir=SIG_WRITE;
+            len+=3;
+            break;
+          case 0x00:
+            r=(i[1]>>3)&7;
+            dir=SIG_WRITE;
+            len+=2;
+            break;
+          }
+          break;
+       }       
+    }
+
+    if (r!=-1) { 
+       void* pr=NULL;
+       write_log("register was %d, direction was %d, size was %d\n",r,dir,size);
+       
+       switch(r) {
+        case 0: pr=&(sc.eax); break;
+        case 1: pr=&(sc.ecx); break;
+        case 2: pr=&(sc.edx); break;
+        case 3: pr=&(sc.ebx); break;
+        case 4: pr=(size>1)?NULL:(((uae_u8*)&(sc.eax))+1); break;
+        case 5: pr=(size>1)?
+                    (void*)(&(sc.ebp)):
+                        (void*)(((uae_u8*)&(sc.ecx))+1); break;
+        case 6: pr=(size>1)?
+                    (void*)(&(sc.esi)):
+                        (void*)(((uae_u8*)&(sc.edx))+1); break;
+        case 7: pr=(size>1)?
+                    (void*)(&(sc.edi)):
+                        (void*)(((uae_u8*)&(sc.ebx))+1); break;
+        default: abort();
+       }
+       if (pr) {
+           blockinfo* bi;
+
+           if (currprefs.comp_oldsegv) {
+           addr-=NATMEM_OFFSET;
+               
+           if ((addr>=0x10000000 && addr<0x40000000) ||
+               (addr>=0x50000000)) {
+               write_log("Suspicious address in %x SEGV handler.\n",addr);
+           }
+           if (dir==SIG_READ) {
+               switch(size) {
+                case 1: *((uae_u8*)pr)=get_byte(addr); break;
+                case 2: *((uae_u16*)pr)=get_word(addr); break;
+                case 4: *((uae_u32*)pr)=get_long(addr); break;
+                default: abort();
+               }
+           }
+           else { /* write */
+               switch(size) {
+                case 1: put_byte(addr,*((uae_u8*)pr)); break;
+                case 2: put_word(addr,*((uae_u16*)pr)); break;
+                case 4: put_long(addr,*((uae_u32*)pr)); break;
+                default: abort();
+               }
+           }
+           write_log("Handled one access!\n");
+           fflush(stdout);
+           segvcount++;
+           sc.eip+=len;
+           }
+           else {
+               void* tmp=target;
+               int i;
+               uae_u8 vecbuf[5];
+               
+               addr-=NATMEM_OFFSET;
+               
+               if ((addr>=0x10000000 && addr<0x40000000) ||
+                   (addr>=0x50000000)) {
+                   write_log("Suspicious address 0x%x in SEGV handler.\n",addr);
+               }
+               
+               target=(uae_u8*)sc.eip;
+               for (i=0;i<5;i++)
+                   vecbuf[i]=target[i];
+               emit_byte(0xe9);
+               emit_long((uae_u32)veccode-(uae_u32)target-4);
+               write_log("Create jump to %p\n",veccode);
+
+               write_log("Handled one access!\n");
+               fflush(stdout);
+               segvcount++;
+               
+               target=veccode;
+
+               if (dir==SIG_READ) {
+                   switch(size) {
+                    case 1: raw_mov_b_ri(r,get_byte(addr)); break;
+                    case 2: raw_mov_w_ri(r,get_word(addr)); break;
+                    case 4: raw_mov_l_ri(r,get_long(addr)); break;
+                    default: abort();
+                   }
+               }
+               else { /* write */
+                   switch(size) {
+                    case 1: put_byte(addr,*((uae_u8*)pr)); break;
+                    case 2: put_word(addr,*((uae_u16*)pr)); break;
+                    case 4: put_long(addr,*((uae_u32*)pr)); break;
+                    default: abort();
+                   }
+               }
+               for (i=0;i<5;i++)
+                   raw_mov_b_mi(sc.eip+i,vecbuf[i]);
+               raw_mov_l_mi((uae_u32)&in_handler,0);
+               emit_byte(0xe9);
+               emit_long(sc.eip+len-(uae_u32)target-4);
+               in_handler=1;
+               target=tmp;
+           }
+           bi=active;
+           while (bi) {
+               if (bi->handler && 
+                   (uae_u8*)bi->direct_handler<=i &&
+                   (uae_u8*)bi->nexthandler>i) {
+                   write_log("deleted trigger (%p<%p<%p) %p\n",
+                             bi->handler,
+                             i,
+                             bi->nexthandler,
+                             bi->pc_p);
+                   invalidate_block(bi);
+                   raise_in_cl_list(bi);
+                   set_special(0);
+                   return;
+               }
+               bi=bi->next;
+           }
+           /* Not found in the active list. Might be a rom routine that
+              is in the dormant list */
+           bi=dormant;
+           while (bi) {
+               if (bi->handler && 
+                   (uae_u8*)bi->direct_handler<=i &&
+                   (uae_u8*)bi->nexthandler>i) {
+                   write_log("deleted trigger (%p<%p<%p) %p\n",
+                             bi->handler,
+                             i,
+                             bi->nexthandler,
+                             bi->pc_p);
+                   invalidate_block(bi);
+                   raise_in_cl_list(bi);
+                   set_special(0);
+                   return;
+               }
+               bi=bi->next;
+           }
+           write_log("Huh? Could not find trigger!\n");
+           return;
+       }
+    }
+    write_log("Can't handle access!\n");
+    for (j=0;j<10;j++) {
+       write_log("instruction byte %2d is %02x\n",j,i[j]);
+    }
+#if 0
+    write_log("Please send the above info (starting at \"fault address\") to\n"
+          "bmeyer@csse.monash.edu.au\n"
+          "This shouldn't happen ;-)\n");
+    fflush(stdout);
+#endif
+    signal(SIGSEGV,SIG_DFL);  /* returning here will cause a "real" SEGV */
+}
+#endif
+#endif
+
+/*************************************************************************
+ * Checking for CPU features                                             *
+ *************************************************************************/
+
+typedef struct {
+    uae_u32 eax;
+    uae_u32 ecx;
+    uae_u32 edx;
+    uae_u32 ebx;
+} x86_regs;
+
+
+/* This could be so much easier if it could make assumptions about the
+   compiler... */
+
+static uae_u32 cpuid_ptr;
+static uae_u32 cpuid_level;
+
+static x86_regs cpuid(uae_u32 level)
+{
+    x86_regs answer;
+    uae_u8 *cpuid_space;
+    void* tmp=get_target();
+
+    cpuid_ptr=(uae_u32)&answer;
+    cpuid_level=level;
+
+    cpuid_space = cache_alloc (256);
+    set_target(cpuid_space);
+    raw_push_l_r(0); /* eax */
+    raw_push_l_r(1); /* ecx */
+    raw_push_l_r(2); /* edx */
+    raw_push_l_r(3); /* ebx */
+    raw_push_l_r(7); /* edi */
+    raw_mov_l_rm(0,(uae_u32)&cpuid_level);
+    raw_cpuid(0);
+    raw_mov_l_rm(7,(uae_u32)&cpuid_ptr);
+    raw_mov_l_Rr(7,0,0);
+    raw_mov_l_Rr(7,1,4);
+    raw_mov_l_Rr(7,2,8);
+    raw_mov_l_Rr(7,3,12);
+    raw_pop_l_r(7);
+    raw_pop_l_r(3);
+    raw_pop_l_r(2);
+    raw_pop_l_r(1);
+    raw_pop_l_r(0);
+    raw_ret();
+    set_target(tmp);
+
+    ((cpuop_func*)cpuid_space)(0);
+    cache_free (cpuid_space);
+    return answer;
+}
+
+static void raw_init_cpu(void)
+{
+    x86_regs x;
+    uae_u32 maxlev;
+    
+    x=cpuid(0);
+    maxlev=x.eax;
+    write_log("Max CPUID level=%d Processor is %c%c%c%c%c%c%c%c%c%c%c%c\n",
+             maxlev,
+             x.ebx,
+             x.ebx>>8,
+             x.ebx>>16,
+             x.ebx>>24,
+             x.edx,
+             x.edx>>8,
+             x.edx>>16,
+             x.edx>>24,
+             x.ecx,
+             x.ecx>>8,
+             x.ecx>>16,
+             x.ecx>>24
+             );
+    have_rat_stall=(x.ecx==0x6c65746e);
+
+    if (maxlev>=1) {
+       x=cpuid(1);
+       if (x.edx&(1<<15)) 
+           have_cmov=1;
+    }
+    have_rat_stall=1;
+#if 0
+    if (!have_cmov)
+       have_rat_stall=0;
+#endif
+#if 0
+    write_log ("have_cmov=%d, avoid_cmov=%d, have_rat_stall=%d\n",
+              have_cmov,currprefs.avoid_cmov,have_rat_stall);
+    if (currprefs.avoid_cmov) {
+       write_log("Disabling cmov use despite processor claiming to support it!\n");
+       have_cmov=0;
+    }
+#else
+    /* Dear Bernie, I don't want to keep around options which are useless, and not
+       represented in the GUI anymore... Is this okay? */
+    write_log ("have_cmov=%d, have_rat_stall=%d\n", have_cmov, have_rat_stall);
+#endif
+#if 0   /* For testing of non-cmov code! */
+    have_cmov=0;
+#endif
+#if 0 /* It appears that partial register writes are a bad idea even on
+        AMD K7 cores, even though they are not supposed to have the
+        dreaded rat stall. Why? Anyway, that's why we lie about it ;-) */
+    if (have_cmov)
+      have_rat_stall=1;
+#endif
+}
+
+/*************************************************************************
+ * FPU stuff                                                             *
+ *************************************************************************/
+
+
+static __inline__ void raw_fp_init(void)
+{
+    int i;
+    
+    for (i=0;i<N_FREGS;i++)
+       live.spos[i]=-2;
+    live.tos=-1;  /* Stack is empty */
+}
+
+static __inline__ void raw_fp_cleanup_drop(void)
+{
+#if 0
+    /* using FINIT instead of popping all the entries.
+       Seems to have side effects --- there is display corruption in
+       Quake when this is used */
+    if (live.tos>1) {
+       emit_byte(0x9b);
+       emit_byte(0xdb);
+       emit_byte(0xe3);
+       live.tos=-1;
+    }
+#endif
+    while (live.tos>=1) {
+       emit_byte(0xde);
+       emit_byte(0xd9);
+       live.tos-=2;
+    }
+    while (live.tos>=0) {
+       emit_byte(0xdd);
+       emit_byte(0xd8);
+       live.tos--;
+    }
+    raw_fp_init();
+}
+
+static __inline__ void make_tos(int r)
+{
+    int p,q;
+
+    if (live.spos[r]<0) { /* Register not yet on stack */
+       emit_byte(0xd9);
+       emit_byte(0xe8);  /* Push '1' on the stack, just to grow it */
+       live.tos++;
+       live.spos[r]=live.tos;
+       live.onstack[live.tos]=r;
+       return;
+    }
+    /* Register is on stack */
+    if (live.tos==live.spos[r])
+       return;
+    p=live.spos[r];
+    q=live.onstack[live.tos];
+
+    emit_byte(0xd9);
+    emit_byte(0xc8+live.tos-live.spos[r]);  /* exchange it with top of stack */
+    live.onstack[live.tos]=r;
+    live.spos[r]=live.tos;
+    live.onstack[p]=q;
+    live.spos[q]=p;
+}
+
+static __inline__ void make_tos2(int r, int r2)
+{
+    int q;
+
+    make_tos(r2); /* Put the reg that's supposed to end up in position2
+                    on top */
+
+    if (live.spos[r]<0) { /* Register not yet on stack */
+       make_tos(r); /* This will extend the stack */
+       return;
+    }
+    /* Register is on stack */
+    emit_byte(0xd9);
+    emit_byte(0xc9); /* Move r2 into position 2 */
+
+    q=live.onstack[live.tos-1];
+    live.onstack[live.tos]=q;
+    live.spos[q]=live.tos;
+    live.onstack[live.tos-1]=r2;
+    live.spos[r2]=live.tos-1;
+
+    make_tos(r); /* And r into 1 */
+}
+
+static __inline__ int stackpos(int r)
+{
+    if (live.spos[r]<0)
+       abort();
+    if (live.tos<live.spos[r]) {
+       printf("Looking for spos for fnreg %d\n",r);
+       abort();
+    }
+    return live.tos-live.spos[r];
+}
+
+static __inline__ void usereg(int r)
+{
+    if (live.spos[r]<0)
+       make_tos(r);
+}
+
+/* This is called with one FP value in a reg *above* tos, which it will
+   pop off the stack if necessary */
+static __inline__ void tos_make(int r)
+{
+    if (live.spos[r]<0) {
+       live.tos++;
+       live.spos[r]=live.tos;
+       live.onstack[live.tos]=r;
+       return;
+    }
+    emit_byte(0xdd);
+    emit_byte(0xd8+(live.tos+1)-live.spos[r]);  /* store top of stack in reg, 
+                                        and pop it*/
+}
+    
+       
+LOWFUNC(NONE,WRITE,2,raw_fmov_mr,(MEMW m, FR r))
+{
+    make_tos(r);
+    emit_byte(0xdd);
+    emit_byte(0x15);
+    emit_long(m);
+}
+LENDFUNC(NONE,WRITE,2,raw_fmov_mr,(MEMW m, FR r))
+
+LOWFUNC(NONE,WRITE,2,raw_fmov_mr_drop,(MEMW m, FR r))
+{
+    make_tos(r);
+    emit_byte(0xdd);
+    emit_byte(0x1d);
+    emit_long(m);
+    live.onstack[live.tos]=-1;
+    live.tos--;
+    live.spos[r]=-2;
+}
+LENDFUNC(NONE,WRITE,2,raw_fmov_mr,(MEMW m, FR r))
+
+LOWFUNC(NONE,READ,2,raw_fmov_rm,(FW r, MEMR m))
+{
+    emit_byte(0xdd);
+    emit_byte(0x05);
+    emit_long(m);
+    tos_make(r);
+}
+LENDFUNC(NONE,READ,2,raw_fmov_rm,(FW r, MEMR m))
+
+LOWFUNC(NONE,READ,2,raw_fmovi_rm,(FW r, MEMR m))
+{
+    emit_byte(0xdb);
+    emit_byte(0x05);
+    emit_long(m);
+    tos_make(r);
+}
+LENDFUNC(NONE,READ,2,raw_fmovi_rm,(FW r, MEMR m))
+
+LOWFUNC(NONE,WRITE,2,raw_fmovi_mr,(MEMW m, FR r))
+{
+    make_tos(r);
+    emit_byte(0xdb);
+    emit_byte(0x15);
+    emit_long(m);
+}
+LENDFUNC(NONE,WRITE,2,raw_fmovi_mr,(MEMW m, FR r))
+
+LOWFUNC(NONE,READ,2,raw_fmovs_rm,(FW r, MEMR m))
+{
+    emit_byte(0xd9);
+    emit_byte(0x05);
+    emit_long(m);
+    tos_make(r);
+}
+LENDFUNC(NONE,READ,2,raw_fmovs_rm,(FW r, MEMR m))
+
+LOWFUNC(NONE,WRITE,2,raw_fmovs_mr,(MEMW m, FR r))
+{
+    make_tos(r);
+    emit_byte(0xd9);
+    emit_byte(0x15);
+    emit_long(m);
+}
+LENDFUNC(NONE,WRITE,2,raw_fmovs_mr,(MEMW m, FR r))
+
+LOWFUNC(NONE,WRITE,2,raw_fmov_ext_mr,(MEMW m, FR r))
+{
+    int rs;
+
+    /* Stupid x87 can't write a long double to mem without popping the 
+       stack! */
+    usereg(r);
+    rs=stackpos(r);
+    emit_byte(0xd9);     /* Get a copy to the top of stack */
+    emit_byte(0xc0+rs);
+
+    emit_byte(0xdb);  /* store and pop it */
+    emit_byte(0x3d);
+    emit_long(m);
+}
+LENDFUNC(NONE,WRITE,2,raw_fmov_ext_mr,(MEMW m, FR r))
+
+LOWFUNC(NONE,WRITE,2,raw_fmov_ext_mr_drop,(MEMW m, FR r))
+{
+    int rs;
+
+    make_tos(r);
+    emit_byte(0xdb);  /* store and pop it */
+    emit_byte(0x3d);
+    emit_long(m);
+    live.onstack[live.tos]=-1;
+    live.tos--;
+    live.spos[r]=-2;
+}
+LENDFUNC(NONE,WRITE,2,raw_fmov_ext_mr,(MEMW m, FR r))
+
+LOWFUNC(NONE,READ,2,raw_fmov_ext_rm,(FW r, MEMR m))
+{
+    emit_byte(0xdb);
+    emit_byte(0x2d);
+    emit_long(m);
+    tos_make(r);
+}
+LENDFUNC(NONE,READ,2,raw_fmov_ext_rm,(FW r, MEMR m))
+
+LOWFUNC(NONE,NONE,1,raw_fmov_pi,(FW r))
+{
+    emit_byte(0xd9);
+    emit_byte(0xeb);
+    tos_make(r);
+}
+LENDFUNC(NONE,NONE,1,raw_fmov_pi,(FW r))
+
+LOWFUNC(NONE,NONE,1,raw_fmov_log10_2,(FW r))
+{
+    emit_byte(0xd9);
+    emit_byte(0xec);
+    tos_make(r);
+}
+LENDFUNC(NONE,NONE,1,raw_fmov_log10_2,(FW r))
+
+LOWFUNC(NONE,NONE,1,raw_fmov_log2_e,(FW r))
+{
+    emit_byte(0xd9);
+    emit_byte(0xea);
+    tos_make(r);
+}
+LENDFUNC(NONE,NONE,1,raw_fmov_log2_e,(FW r))
+
+LOWFUNC(NONE,NONE,1,raw_fmov_loge_2,(FW r))
+{
+    emit_byte(0xd9);
+    emit_byte(0xed);
+    tos_make(r);
+}
+LENDFUNC(NONE,NONE,1,raw_fmov_loge_2,(FW r))
+
+LOWFUNC(NONE,NONE,1,raw_fmov_1,(FW r))
+{
+    emit_byte(0xd9);
+    emit_byte(0xe8);
+    tos_make(r);
+}
+LENDFUNC(NONE,NONE,1,raw_fmov_1,(FW r))
+
+LOWFUNC(NONE,NONE,1,raw_fmov_0,(FW r))
+{
+    emit_byte(0xd9);
+    emit_byte(0xee);
+    tos_make(r);
+}
+LENDFUNC(NONE,NONE,1,raw_fmov_0,(FW r))
+
+LOWFUNC(NONE,NONE,2,raw_fmov_rr,(FW d, FR s))
+{
+    int ds;
+
+    usereg(s);
+    ds=stackpos(s);
+    if (ds==0 && live.spos[d]>=0) {
+       /* source is on top of stack, and we already have the dest */
+       int dd=stackpos(d);
+       emit_byte(0xdd);
+       emit_byte(0xd0+dd);
+    }
+    else {
+       emit_byte(0xd9);
+       emit_byte(0xc0+ds); /* duplicate source on tos */
+       tos_make(d); /* store to destination, pop if necessary */
+    }
+}
+LENDFUNC(NONE,NONE,2,raw_fmov_rr,(FW d, FR s))
+
+LOWFUNC(NONE,READ,4,raw_fldcw_m_indexed,(R4 index, IMM base))
+{
+    emit_byte(0xd9);
+    emit_byte(0xa8+index);
+    emit_long(base);
+}
+LENDFUNC(NONE,READ,4,raw_fldcw_m_indexed,(R4 index, IMM base))
+
+
+LOWFUNC(NONE,NONE,2,raw_fsqrt_rr,(FW d, FR s))
+{
+    int ds;
+
+    if (d!=s) {
+       usereg(s);
+       ds=stackpos(s);
+       emit_byte(0xd9);
+       emit_byte(0xc0+ds); /* duplicate source */
+       emit_byte(0xd9);
+       emit_byte(0xfa); /* take square root */
+       tos_make(d); /* store to destination */
+    }
+    else {
+       make_tos(d);
+       emit_byte(0xd9);
+       emit_byte(0xfa); /* take square root */
+    }  
+}
+LENDFUNC(NONE,NONE,2,raw_fsqrt_rr,(FW d, FR s))
+
+LOWFUNC(NONE,NONE,2,raw_fabs_rr,(FW d, FR s))
+{
+    int ds;
+
+    if (d!=s) {
+       usereg(s);
+       ds=stackpos(s);
+       emit_byte(0xd9);
+       emit_byte(0xc0+ds); /* duplicate source */
+       emit_byte(0xd9);
+       emit_byte(0xe1); /* take fabs */
+       tos_make(d); /* store to destination */
+    }
+    else {
+       make_tos(d);
+       emit_byte(0xd9);
+       emit_byte(0xe1); /* take fabs */
+    }  
+}
+LENDFUNC(NONE,NONE,2,raw_fabs_rr,(FW d, FR s))
+
+LOWFUNC(NONE,NONE,2,raw_frndint_rr,(FW d, FR s))
+{
+    int ds;
+
+    if (d!=s) {
+       usereg(s);
+       ds=stackpos(s);
+       emit_byte(0xd9);
+       emit_byte(0xc0+ds); /* duplicate source */
+       emit_byte(0xd9);
+       emit_byte(0xfc); /* take frndint */
+       tos_make(d); /* store to destination */
+    }
+    else {
+       make_tos(d);
+       emit_byte(0xd9);
+       emit_byte(0xfc); /* take frndint */
+    }  
+}
+LENDFUNC(NONE,NONE,2,raw_frndint_rr,(FW d, FR s))
+
+LOWFUNC(NONE,NONE,2,raw_fcos_rr,(FW d, FR s))
+{
+    int ds;
+
+    if (d!=s) {
+       usereg(s);
+       ds=stackpos(s);
+       emit_byte(0xd9);
+       emit_byte(0xc0+ds); /* duplicate source */
+       emit_byte(0xd9);
+       emit_byte(0xff); /* take cos */
+       tos_make(d); /* store to destination */
+    }
+    else {
+       make_tos(d);
+       emit_byte(0xd9);
+       emit_byte(0xff); /* take cos */
+    }  
+}
+LENDFUNC(NONE,NONE,2,raw_fcos_rr,(FW d, FR s))
+
+LOWFUNC(NONE,NONE,2,raw_fsin_rr,(FW d, FR s))
+{
+    int ds;
+
+    if (d!=s) {
+       usereg(s);
+       ds=stackpos(s);
+       emit_byte(0xd9);
+       emit_byte(0xc0+ds); /* duplicate source */
+       emit_byte(0xd9);
+       emit_byte(0xfe); /* take sin */
+       tos_make(d); /* store to destination */
+    }
+    else {
+       make_tos(d);
+       emit_byte(0xd9);
+       emit_byte(0xfe); /* take sin */
+    }  
+}
+LENDFUNC(NONE,NONE,2,raw_fsin_rr,(FW d, FR s))
+
+double one=1;
+LOWFUNC(NONE,NONE,2,raw_ftwotox_rr,(FW d, FR s))
+{
+    int ds;
+
+    usereg(s);
+    ds=stackpos(s);
+    emit_byte(0xd9);
+    emit_byte(0xc0+ds); /* duplicate source */
+
+    emit_byte(0xd9);
+    emit_byte(0xc0);  /* duplicate top of stack. Now up to 8 high */
+    emit_byte(0xd9);
+    emit_byte(0xfc);  /* rndint */
+    emit_byte(0xd9);
+    emit_byte(0xc9);  /* swap top two elements */
+    emit_byte(0xd8);
+    emit_byte(0xe1);  /* subtract rounded from original */
+    emit_byte(0xd9);
+    emit_byte(0xf0);  /* f2xm1 */
+    emit_byte(0xdc);
+    emit_byte(0x05);
+    emit_long((uae_u32)&one);  /* Add '1' without using extra stack space */
+    emit_byte(0xd9);
+    emit_byte(0xfd);  /* and scale it */
+    emit_byte(0xdd);
+    emit_byte(0xd9);  /* take he rounded value off */
+    tos_make(d); /* store to destination */
+}
+LENDFUNC(NONE,NONE,2,raw_ftwotox_rr,(FW d, FR s))
+
+LOWFUNC(NONE,NONE,2,raw_fetox_rr,(FW d, FR s))
+{
+    int ds;
+
+    usereg(s);
+    ds=stackpos(s);
+    emit_byte(0xd9);
+    emit_byte(0xc0+ds); /* duplicate source */
+    emit_byte(0xd9);
+    emit_byte(0xea);   /* fldl2e */
+    emit_byte(0xde);
+    emit_byte(0xc9);  /* fmulp --- multiply source by log2(e) */
+
+    emit_byte(0xd9);
+    emit_byte(0xc0);  /* duplicate top of stack. Now up to 8 high */
+    emit_byte(0xd9);
+    emit_byte(0xfc);  /* rndint */
+    emit_byte(0xd9);
+    emit_byte(0xc9);  /* swap top two elements */
+    emit_byte(0xd8);
+    emit_byte(0xe1);  /* subtract rounded from original */
+    emit_byte(0xd9);
+    emit_byte(0xf0);  /* f2xm1 */
+    emit_byte(0xdc);
+    emit_byte(0x05);
+    emit_long((uae_u32)&one);  /* Add '1' without using extra stack space */
+    emit_byte(0xd9);
+    emit_byte(0xfd);  /* and scale it */
+    emit_byte(0xdd);
+    emit_byte(0xd9);  /* take he rounded value off */
+    tos_make(d); /* store to destination */
+}
+LENDFUNC(NONE,NONE,2,raw_fetox_rr,(FW d, FR s))
+LOWFUNC(NONE,NONE,2,raw_flog2_rr,(FW d, FR s))
+{
+    int ds;
+
+    usereg(s);
+    ds=stackpos(s);
+    emit_byte(0xd9);
+    emit_byte(0xc0+ds); /* duplicate source */
+    emit_byte(0xd9);
+    emit_byte(0xe8); /* push '1' */
+    emit_byte(0xd9);
+    emit_byte(0xc9); /* swap top two */
+    emit_byte(0xd9);
+    emit_byte(0xf1); /* take 1*log2(x) */
+    tos_make(d); /* store to destination */
+}
+LENDFUNC(NONE,NONE,2,raw_flog2_rr,(FW d, FR s))
+
+
+LOWFUNC(NONE,NONE,2,raw_fneg_rr,(FW d, FR s))
+{
+    int ds;
+
+    if (d!=s) {
+       usereg(s);
+       ds=stackpos(s);
+       emit_byte(0xd9);
+       emit_byte(0xc0+ds); /* duplicate source */
+       emit_byte(0xd9);
+       emit_byte(0xe0); /* take fchs */
+       tos_make(d); /* store to destination */
+    }
+    else {
+       make_tos(d);
+       emit_byte(0xd9);
+       emit_byte(0xe0); /* take fchs */
+    }  
+}
+LENDFUNC(NONE,NONE,2,raw_fneg_rr,(FW d, FR s))
+
+LOWFUNC(NONE,NONE,2,raw_fadd_rr,(FRW d, FR s))
+{
+    int ds;
+
+    usereg(s);
+    usereg(d);
+    
+    if (live.spos[s]==live.tos) {
+       /* Source is on top of stack */
+       ds=stackpos(d);
+       emit_byte(0xdc);
+       emit_byte(0xc0+ds); /* add source to dest*/
+    }
+    else {
+       make_tos(d);
+       ds=stackpos(s);
+       
+       emit_byte(0xd8);
+       emit_byte(0xc0+ds); /* add source to dest*/
+    }
+}
+LENDFUNC(NONE,NONE,2,raw_fadd_rr,(FRW d, FR s))
+
+LOWFUNC(NONE,NONE,2,raw_fsub_rr,(FRW d, FR s))
+{
+    int ds;
+
+    usereg(s);
+    usereg(d);
+    
+    if (live.spos[s]==live.tos) {
+       /* Source is on top of stack */
+       ds=stackpos(d);
+       emit_byte(0xdc);
+       emit_byte(0xe8+ds); /* sub source from dest*/
+    }
+    else {
+       make_tos(d);
+       ds=stackpos(s);
+       
+       emit_byte(0xd8);
+       emit_byte(0xe0+ds); /* sub src from dest */
+    }
+}
+LENDFUNC(NONE,NONE,2,raw_fsub_rr,(FRW d, FR s))
+
+LOWFUNC(NONE,NONE,2,raw_fcmp_rr,(FR d, FR s))
+{
+    int ds;
+
+    usereg(s);
+    usereg(d);
+    
+    make_tos(d);
+    ds=stackpos(s);
+
+    emit_byte(0xdd);
+    emit_byte(0xe0+ds); /* cmp dest with source*/
+}
+LENDFUNC(NONE,NONE,2,raw_fcmp_rr,(FR d, FR s))
+
+LOWFUNC(NONE,NONE,2,raw_fmul_rr,(FRW d, FR s))
+{
+    int ds;
+
+    usereg(s);
+    usereg(d);
+    
+    if (live.spos[s]==live.tos) {
+       /* Source is on top of stack */
+       ds=stackpos(d);
+       emit_byte(0xdc);
+       emit_byte(0xc8+ds); /* mul dest by source*/
+    }
+    else {
+       make_tos(d);
+       ds=stackpos(s);
+       
+       emit_byte(0xd8);
+       emit_byte(0xc8+ds); /* mul dest by source*/
+    }
+}
+LENDFUNC(NONE,NONE,2,raw_fmul_rr,(FRW d, FR s))
+
+LOWFUNC(NONE,NONE,2,raw_fdiv_rr,(FRW d, FR s))
+{
+    int ds;
+
+    usereg(s);
+    usereg(d);
+    
+    if (live.spos[s]==live.tos) {
+       /* Source is on top of stack */
+       ds=stackpos(d);
+       emit_byte(0xdc);
+       emit_byte(0xf8+ds); /* div dest by source */
+    }
+    else {
+       make_tos(d);
+       ds=stackpos(s);
+       
+       emit_byte(0xd8);
+       emit_byte(0xf0+ds); /* div dest by source*/
+    }
+}
+LENDFUNC(NONE,NONE,2,raw_fdiv_rr,(FRW d, FR s))
+
+LOWFUNC(NONE,NONE,2,raw_frem_rr,(FRW d, FR s))
+{
+    int ds;
+
+    usereg(s);
+    usereg(d);
+    
+    make_tos2(d,s);
+    ds=stackpos(s);
+
+    if (ds!=1) {
+       printf("Failed horribly in raw_frem_rr! ds is %d\n",ds);
+       abort();
+    }
+    emit_byte(0xd9);
+    emit_byte(0xf8); /* take rem from dest by source */
+}
+LENDFUNC(NONE,NONE,2,raw_frem_rr,(FRW d, FR s))
+
+LOWFUNC(NONE,NONE,2,raw_frem1_rr,(FRW d, FR s))
+{
+    int ds;
+
+    usereg(s);
+    usereg(d);
+    
+    make_tos2(d,s);
+    ds=stackpos(s);
+
+    if (ds!=1) {
+       printf("Failed horribly in raw_frem1_rr! ds is %d\n",ds);
+       abort();
+    }
+    emit_byte(0xd9);
+    emit_byte(0xf5); /* take rem1 from dest by source */
+}
+LENDFUNC(NONE,NONE,2,raw_frem1_rr,(FRW d, FR s))
+
+
+LOWFUNC(NONE,NONE,1,raw_ftst_r,(FR r))
+{
+    make_tos(r);
+    emit_byte(0xd9);  /* ftst */
+    emit_byte(0xe4);
+}
+LENDFUNC(NONE,NONE,1,raw_ftst_r,(FR r))
+
+static __inline__ void raw_fflags_into_flags(int r)
+{
+    int p;
+
+    usereg(r);
+    p=stackpos(r);
+
+    emit_byte(0xd9);
+    emit_byte(0xee); /* Push 0 */
+    emit_byte(0xd9);
+    emit_byte(0xc9+p); /* swap top two around */
+    if (have_cmov) {
+            // gb-- fucomi is for P6 cores only, not K6-2 then...
+    emit_byte(0xdb);
+    emit_byte(0xe9+p); /* fucomi them */
+    }
+    else {
+            emit_byte(0xdd);
+            emit_byte(0xe1+p); /* fucom them */
+            emit_byte(0x9b);
+            emit_byte(0xdf);
+            emit_byte(0xe0); /* fstsw ax */
+            raw_sahf(0); /* sahf */
+    }
+    emit_byte(0xdd);
+    emit_byte(0xd9+p);  /* store value back, and get rid of 0 */
+}
diff --git a/compemu_support.c b/compemu_support.c
new file mode 100755 (executable)
index 0000000..5143c61
--- /dev/null
@@ -0,0 +1,6185 @@
+#define writemem_special writemem
+#define readmem_special  readmem
+
+#define USE_MATCHSTATE 0
+#define setzflg_uses_bsf 0
+#include "sysconfig.h"
+#include "sysdeps.h"
+#include "config.h"
+#include "options.h"
+#include "events.h"
+#include "include/memory.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "compiler.h"
+#include "comptbl.h"
+#include "compemu.h"
+
+// %%% BRIAN KING WAS HERE %%%
+extern int canbang;
+#include <sys/mman.h>
+#include <limits.h>    /* for PAGESIZE */
+
+cpuop_func *compfunctbl[65536];
+cpuop_func *nfcompfunctbl[65536];
+#ifdef NOFLAGS_SUPPORT
+cpuop_func *nfcpufunctbl[65536];
+#endif
+uae_u8* comp_pc_p;
+
+uae_u8* start_pc_p;
+uae_u32 start_pc;
+uae_u32 current_block_pc_p;
+uae_u32 current_block_start_target;
+uae_u32 needed_flags;
+static uae_u32 next_pc_p;
+static uae_u32 taken_pc_p;
+static int     branch_cc;
+int segvcount=0;
+int soft_flush_count=0;
+int hard_flush_count=0;
+int compile_count=0;
+int checksum_count=0;
+static uae_u8* current_compile_p=NULL;
+static uae_u8* max_compile_start;
+uae_u8* compiled_code=NULL;
+static uae_s32 reg_alloc_run;
+static int have_rat_stall=0;
+
+void* pushall_call_handler=NULL;
+static void* popall_do_nothing=NULL;
+static void* popall_exec_nostats=NULL;
+static void* popall_execute_normal=NULL;
+static void* popall_cache_miss=NULL;
+static void* popall_recompile_block=NULL;
+static void* popall_check_checksum=NULL;
+
+extern uae_u32 oink;
+extern unsigned long foink3;
+extern unsigned long foink;
+
+/* The 68k only ever executes from even addresses. So right now, we
+   waste half the entries in this array
+   UPDATE: We now use those entries to store the start of the linked
+   lists that we maintain for each hash result. */
+cacheline cache_tags[TAGSIZE];
+int letit=0;
+blockinfo* hold_bi[MAX_HOLD_BI];
+blockinfo* active;
+blockinfo* dormant;
+
+op_properties prop[65536];
+
+#ifdef NOFLAGS_SUPPORT
+/* 68040 */
+extern struct cputbl op_smalltbl_0_nf[];
+#endif
+extern struct cputbl op_smalltbl_0_comp_nf[];
+extern struct cputbl op_smalltbl_0_comp_ff[];
+#ifdef NOFLAGS_SUPPORT
+/* 68020 + 68881 */
+extern struct cputbl op_smalltbl_1_nf[];
+/* 68020 */
+extern struct cputbl op_smalltbl_2_nf[];
+/* 68010 */
+extern struct cputbl op_smalltbl_3_nf[];
+/* 68000 */
+extern struct cputbl op_smalltbl_4_nf[];
+/* 68000 slow but compatible.  */
+extern struct cputbl op_smalltbl_5_nf[];
+#endif
+
+static void flush_icache_hard(int n);
+
+
+
+bigstate live;
+smallstate empty_ss;
+smallstate default_ss;
+static int optlev;
+
+static int writereg(int r, int size);
+static void unlock(int r);
+static void setlock(int r);
+static int readreg_specific(int r, int size, int spec);
+static int writereg_specific(int r, int size, int spec);
+static void prepare_for_call_1(void);
+static void prepare_for_call_2(void);
+static void align_target(uae_u32 a);
+
+static uae_s32 nextused[VREGS];
+
+static uae_u8 *popallspace;
+
+uae_u32 m68k_pc_offset;
+
+/* Some arithmetic ooperations can be optimized away if the operands
+   are known to be constant. But that's only a good idea when the
+   side effects they would have on the flags are not important. This
+   variable indicates whether we need the side effects or not 
+*/
+uae_u32 needflags=0;
+
+/* Flag handling is complicated.
+
+   x86 instructions create flags, which quite often are exactly what we
+   want. So at times, the "68k" flags are actually in the x86 flags.
+
+   Then again, sometimes we do x86 instructions that clobber the x86
+   flags, but don't represent a corresponding m68k instruction. In that
+   case, we have to save them. 
+
+   We used to save them to the stack, but now store them back directly
+   into the regflags.cznv of the traditional emulation. Thus some odd
+   names.
+
+   So flags can be in either of two places (used to be three; boy were
+   things complicated back then!); And either place can contain either
+   valid flags or invalid trash (and on the stack, there was also the
+   option of "nothing at all", now gone). A couple of variables keep
+   track of the respective states.
+
+   To make things worse, we might or might not be interested in the flags.
+   by default, we are, but a call to dont_care_flags can change that 
+   until the next call to live_flags. If we are not, pretty much whatever
+   is in the register and/or the native flags is seen as valid.
+*/
+
+
+static __inline__ blockinfo* get_blockinfo(uae_u32 cl)
+{
+    return cache_tags[cl+1].bi;
+}
+
+static __inline__ blockinfo* get_blockinfo_addr(void* addr)
+{
+    blockinfo*  bi=get_blockinfo(cacheline(addr));
+
+    while (bi) {
+       if (bi->pc_p==addr)
+           return bi;
+       bi=bi->next_same_cl;
+    }
+    return NULL;
+}
+
+               
+/*******************************************************************
+ * All sorts of list related functions for all of the lists        *
+ *******************************************************************/
+
+static __inline__ void remove_from_cl_list(blockinfo* bi)
+{
+    uae_u32 cl=cacheline(bi->pc_p);
+
+    if (bi->prev_same_cl_p) 
+       *(bi->prev_same_cl_p)=bi->next_same_cl;
+    if (bi->next_same_cl)
+       bi->next_same_cl->prev_same_cl_p=bi->prev_same_cl_p;
+    if (cache_tags[cl+1].bi) 
+       cache_tags[cl].handler=cache_tags[cl+1].bi->handler_to_use;
+    else 
+       cache_tags[cl].handler=popall_execute_normal;
+}
+
+static __inline__ void remove_from_list(blockinfo* bi)
+{
+    if (bi->prev_p) 
+       *(bi->prev_p)=bi->next;
+    if (bi->next)
+       bi->next->prev_p=bi->prev_p;
+}
+
+static __inline__ void remove_from_lists(blockinfo* bi)
+{
+    remove_from_list(bi);
+    remove_from_cl_list(bi);
+}
+
+static __inline__ void add_to_cl_list(blockinfo* bi)
+{
+    uae_u32 cl=cacheline(bi->pc_p);
+    
+    if (cache_tags[cl+1].bi)
+       cache_tags[cl+1].bi->prev_same_cl_p=&(bi->next_same_cl);
+    bi->next_same_cl=cache_tags[cl+1].bi;
+
+    cache_tags[cl+1].bi=bi;
+    bi->prev_same_cl_p=&(cache_tags[cl+1].bi);
+
+    cache_tags[cl].handler=bi->handler_to_use;
+}
+
+static __inline__ void raise_in_cl_list(blockinfo* bi)
+{
+    remove_from_cl_list(bi);
+    add_to_cl_list(bi);
+}
+
+static __inline__ void add_to_active(blockinfo* bi)
+{
+    if (active) 
+       active->prev_p=&(bi->next);
+    bi->next=active;
+
+    active=bi;
+    bi->prev_p=&active;
+}
+
+static __inline__ void add_to_dormant(blockinfo* bi)
+{
+    if (dormant) 
+       dormant->prev_p=&(bi->next);
+    bi->next=dormant;
+
+    dormant=bi;
+    bi->prev_p=&dormant;
+}
+
+static __inline__ void remove_dep(dependency* d)
+{
+    if (d->prev_p) 
+       *(d->prev_p)=d->next;
+    if (d->next)
+       d->next->prev_p=d->prev_p;
+    d->prev_p=NULL;
+    d->next=NULL;
+}
+
+/* This block's code is about to be thrown away, so it no longer
+   depends on anything else */
+static __inline__ void remove_deps(blockinfo* bi)
+{
+    remove_dep(&(bi->dep[0]));
+    remove_dep(&(bi->dep[1]));
+}
+
+static __inline__ void adjust_jmpdep(dependency* d, void* a)
+{
+    *(d->jmp_off)=(uae_u32)a-((uae_u32)d->jmp_off+4);
+}
+
+/********************************************************************
+ * Soft flush handling support functions                            *
+ ********************************************************************/
+
+static __inline__ void set_dhtu(blockinfo* bi, void* dh)
+{
+    //printf("bi is %p\n",bi);
+    if (dh!=bi->direct_handler_to_use) {
+       dependency* x=bi->deplist;
+       //printf("bi->deplist=%p\n",bi->deplist);
+       while (x) {
+           //printf("x is %p\n",x);
+           //printf("x->next is %p\n",x->next);
+           //printf("x->prev_p is %p\n",x->prev_p);
+           
+           if (x->jmp_off) {
+               adjust_jmpdep(x,dh);
+           }
+           x=x->next;
+       }
+       bi->direct_handler_to_use=dh;
+    }
+}
+
+static __inline__ void invalidate_block(blockinfo* bi)
+{
+    int i;
+
+    bi->optlevel=0;
+    bi->count=currprefs.optcount[0]-1;
+    bi->handler=NULL;
+    bi->handler_to_use=popall_execute_normal;
+    bi->direct_handler=NULL;
+    set_dhtu(bi,bi->direct_pen);
+    bi->needed_flags=0xff;
+
+    for (i=0;i<2;i++) {
+       bi->dep[i].jmp_off=NULL;
+       bi->dep[i].target=NULL;
+    }
+    remove_deps(bi);
+}
+
+static __inline__ void create_jmpdep(blockinfo* bi, int i, uae_u32* jmpaddr, uae_u32 target)
+{
+    blockinfo*  tbi=get_blockinfo_addr((void*)target);
+    
+    Dif(!tbi) {
+       printf("Could not create jmpdep!\n");
+       abort();
+    }
+    bi->dep[i].jmp_off=jmpaddr;
+    bi->dep[i].target=tbi;
+    bi->dep[i].next=tbi->deplist;
+    if (bi->dep[i].next) 
+       bi->dep[i].next->prev_p=&(bi->dep[i].next);
+    bi->dep[i].prev_p=&(tbi->deplist);
+    tbi->deplist=&(bi->dep[i]);
+}
+
+static __inline__ void big_to_small_state(bigstate* b, smallstate* s)
+{
+    int i;
+    int count=0;
+
+    for (i=0;i<N_REGS;i++) {
+       s->nat[i].validsize=0;
+       s->nat[i].dirtysize=0;
+       if (b->nat[i].nholds) {
+           int index=b->nat[i].nholds-1;
+           int r=b->nat[i].holds[index];
+           s->nat[i].holds=r;
+           s->nat[i].validsize=b->state[r].validsize;
+           s->nat[i].dirtysize=b->state[r].dirtysize;
+           count++;
+       }
+    }
+    printf("count=%d\n",count);
+    for (i=0;i<N_REGS;i++) {  // FIXME --- don't do dirty yet 
+       s->nat[i].dirtysize=0;
+    }  
+}
+
+static __inline__ void attached_state(blockinfo* bi)
+{
+    bi->havestate=1;
+    if (bi->direct_handler_to_use==bi->direct_handler)
+       set_dhtu(bi,bi->direct_pen);
+    bi->direct_handler=bi->direct_pen;
+    bi->status=BI_TARGETTED;
+}
+
+static __inline__ blockinfo* get_blockinfo_addr_new(void* addr, int setstate)
+{
+    blockinfo*  bi=get_blockinfo_addr(addr);
+    int i;
+
+#if USE_OPTIMIZER
+    if (reg_alloc_run) 
+       return NULL;
+#endif
+    if (!bi) {
+       for (i=0;i<MAX_HOLD_BI && !bi;i++) {
+           if (hold_bi[i]) {
+               uae_u32 cl=cacheline(addr);
+               
+               bi=hold_bi[i];
+               hold_bi[i]=NULL;
+               bi->pc_p=addr;
+               invalidate_block(bi);
+               add_to_active(bi);
+               add_to_cl_list(bi);
+               
+           }
+       }
+    }
+    if (!bi) {
+       fprintf(stderr,"Looking for blockinfo, can't find free one\n");
+       abort();
+    }
+
+#if USE_MATCHSTATE
+    if (setstate &&
+       !bi->havestate) {
+       big_to_small_state(&live,&(bi->env));
+       attached_state(bi);
+    }
+#endif
+    return bi;
+}
+
+static void prepare_block(blockinfo* bi);
+
+static __inline__ void alloc_blockinfos(void) 
+{
+    int i;
+    blockinfo* bi;
+
+    for (i=0;i<MAX_HOLD_BI;i++) {
+       if (hold_bi[i])
+           return;
+       bi=hold_bi[i]=(blockinfo*)current_compile_p;
+       current_compile_p+=sizeof(blockinfo);
+       
+       prepare_block(bi);
+    }
+}
+
+/********************************************************************
+ * Preferences handling. This is just a convenient place to put it  *
+ ********************************************************************/
+extern int have_done_picasso;
+
+void check_prefs_changed_comp (void)
+{
+    currprefs.comptrustbyte = changed_prefs.comptrustbyte;
+    currprefs.comptrustword = changed_prefs.comptrustword;
+    currprefs.comptrustlong = changed_prefs.comptrustlong;
+    currprefs.comptrustnaddr= changed_prefs.comptrustnaddr;
+    currprefs.compnf = changed_prefs.compnf;
+    currprefs.comp_hardflush= changed_prefs.comp_hardflush;
+    currprefs.comp_constjump= changed_prefs.comp_constjump;
+    currprefs.comp_oldsegv= changed_prefs.comp_oldsegv;
+    currprefs.compfpu= changed_prefs.compfpu;
+
+    if (currprefs.cachesize!=changed_prefs.cachesize) {
+       currprefs.cachesize = changed_prefs.cachesize;
+       alloc_cache();
+    }
+
+    // Turn off illegal-mem logging when using JIT...
+    if( currprefs.cachesize )
+       currprefs.illegal_mem = changed_prefs.illegal_mem;// = 0;
+
+    currprefs.comp_midopt=changed_prefs.comp_midopt;
+    currprefs.comp_lowopt=changed_prefs.comp_lowopt;
+
+    if ( ( !canbang || !currprefs.cachesize ) && 
+       currprefs.comptrustbyte != 1 )
+    {
+       // Set all of these to indirect when canbang == 0
+       // Basically, set the  compforcesettings option...
+       currprefs.comptrustbyte = 1;
+       currprefs.comptrustword = 1;
+       currprefs.comptrustlong = 1;
+       currprefs.comptrustnaddr= 1;
+       currprefs.compforcesettings = 1;
+
+       changed_prefs.comptrustbyte = 1;
+       changed_prefs.comptrustword = 1;
+       changed_prefs.comptrustlong = 1;
+       changed_prefs.comptrustnaddr= 1;
+       changed_prefs.compforcesettings = 1;
+
+       if( currprefs.cachesize )
+       {
+           write_log( "JIT: Reverting to \"indirect\" access, because canbang is zero!\n" );
+       }
+    }
+
+    if (!currprefs.compforcesettings && !have_done_picasso) {
+       int stop=0;
+       if (currprefs.comptrustbyte!=0 && currprefs.comptrustbyte!=3) 
+           stop = 1, write_log("<JIT compiler> : comptrustbyte is not 'direct' or 'afterpic'\n");
+       if (currprefs.comptrustword!=0 && currprefs.comptrustword!=3) 
+           stop = 1, write_log("<JIT compiler> : comptrustword is not 'direct' or 'afterpic'\n");
+       if (currprefs.comptrustlong!=0 && currprefs.comptrustlong!=3) 
+           stop = 1, write_log("<JIT compiler> : comptrustlong is not 'direct' or 'afterpic'\n");
+       if (currprefs.comptrustnaddr!=0 && currprefs.comptrustnaddr!=3) 
+           stop = 1, write_log("<JIT compiler> : comptrustnaddr is not 'direct' or 'afterpic'\n");
+       if (currprefs.compnf!=1) 
+           stop = 1, write_log("<JIT compiler> : compnf is not 'yes'\n");
+       if (currprefs.cachesize<1024) 
+           stop = 1, write_log("<JIT compiler> : cachesize is less than 1024\n");
+       if (currprefs.comp_hardflush) 
+           stop = 1, write_log("<JIT compiler> : comp_flushmode is 'hard'\n");
+       if (!canbang) 
+           stop = 1, write_log("<JIT compiler> : Cannot use most direct memory access,\n"
+                               "                 and unable to recover from failed guess!\n");
+#if 0
+       if (stop) {
+           gui_message("JIT: Configuration problems were detected!\n"
+                     "JIT: These will adversely affect performance, and should\n"
+                     "JIT: not be used. For more info, please see README.JIT-tuning\n"
+                     "JIT: in the UAE documentation directory. You can force\n"
+                     "JIT: your settings to be used by setting\n"
+                     "JIT:      'compforcesettings=yes'\n"
+                     "JIT: in your config file\n");
+           exit(1);
+       }
+#endif
+    }
+}
+
+/********************************************************************
+ * Get the optimizer stuff                                          *
+ ********************************************************************/
+
+#include "compemu_optimizer.c"
+
+/********************************************************************
+ * Functions to emit data into memory, and other general support    *
+ ********************************************************************/
+
+static uae_u8* target;
+
+static  void emit_init(void)
+{
+}
+
+static __inline__ void emit_byte(uae_u8 x)
+{
+    *target++=x;
+}
+
+static __inline__ void emit_word(uae_u16 x)
+{
+    *((uae_u16*)target)=x;
+    target+=2;
+}
+
+static __inline__ void emit_long(uae_u32 x)
+{
+    *((uae_u32*)target)=x;
+    target+=4;
+}
+
+static __inline__ uae_u32 reverse32(uae_u32 oldv)
+{
+    return ((oldv>>24)&0xff) | ((oldv>>8)&0xff00) |
+       ((oldv<<8)&0xff0000) | ((oldv<<24)&0xff000000);
+}
+
+    
+void set_target(uae_u8* t)
+{
+    lopt_emit_all();
+    target=t;
+}
+
+static __inline__ uae_u8* get_target_noopt(void)
+{
+    return target;
+}
+
+__inline__ uae_u8* get_target(void)
+{
+    lopt_emit_all();
+    return get_target_noopt();
+}
+
+
+/********************************************************************
+ * Getting the information about the target CPU                     *
+ ********************************************************************/
+
+#include "compemu_raw_x86.c"
+
+
+/********************************************************************
+ * Flags status handling. EMIT TIME!                                *
+ ********************************************************************/
+
+static void bt_l_ri_noclobber(R4 r, IMM i);
+
+static void make_flags_live_internal(void)
+{
+    if (live.flags_in_flags==VALID)
+       return;
+    Dif (live.flags_on_stack==TRASH) {
+       printf("Want flags, got something on stack, but it is TRASH\n");
+       abort();
+    }
+    if (live.flags_on_stack==VALID) {
+       int tmp;
+       tmp=readreg_specific(FLAGTMP,4,FLAG_NREG2);
+       raw_reg_to_flags(tmp);
+       unlock(tmp);
+
+       live.flags_in_flags=VALID;
+       return;
+    }
+    printf("Huh? live.flags_in_flags=%d, live.flags_on_stack=%d, but need to make live\n",
+          live.flags_in_flags,live.flags_on_stack);
+    abort();
+}
+
+static void flags_to_stack(void)
+{
+    if (live.flags_on_stack==VALID)
+       return;
+    if (!live.flags_are_important) {
+       live.flags_on_stack=VALID;
+       return;
+    }
+    Dif (live.flags_in_flags!=VALID)
+       abort();
+    else  {
+       int tmp;
+       tmp=writereg_specific(FLAGTMP,4,FLAG_NREG1);
+       raw_flags_to_reg(tmp);
+       unlock(tmp);
+    }
+    live.flags_on_stack=VALID;
+}
+
+static __inline__ void clobber_flags(void)
+{
+    if (live.flags_in_flags==VALID && live.flags_on_stack!=VALID)
+       flags_to_stack();
+    live.flags_in_flags=TRASH;
+}
+
+/* Prepare for leaving the compiled stuff */
+static __inline__ void flush_flags(void)
+{
+    flags_to_stack();
+    return;
+}
+
+int touchcnt;
+
+/********************************************************************
+ * register allocation per block logging                            *
+ ********************************************************************/
+
+static uae_s8 vstate[VREGS];
+static uae_s8 nstate[N_REGS];
+
+#define L_UNKNOWN -127
+#define L_UNAVAIL -1
+#define L_NEEDED -2
+#define L_UNNEEDED -3
+
+static __inline__ void log_startblock(void)
+{
+    int i;
+    for (i=0;i<VREGS;i++)
+       vstate[i]=L_UNKNOWN;
+    for (i=0;i<N_REGS;i++)
+       nstate[i]=L_UNKNOWN;
+}
+
+static __inline__ void log_isused(int n)
+{
+    if (nstate[n]==L_UNKNOWN)
+       nstate[n]=L_UNAVAIL;
+}
+
+static __inline__ void log_isreg(int n, int r)
+{
+    if (nstate[n]==L_UNKNOWN)
+       nstate[n]=r;
+    if (vstate[r]==L_UNKNOWN)
+       vstate[r]=L_NEEDED;
+}
+
+static __inline__ void log_clobberreg(int r)
+{
+    if (vstate[r]==L_UNKNOWN)
+       vstate[r]=L_UNNEEDED;
+}
+
+/* This ends all possibility of clever register allocation */
+
+static __inline__ void log_flush(void)
+{
+    int i;
+    for (i=0;i<VREGS;i++)
+       if (vstate[i]==L_UNKNOWN)
+           vstate[i]=L_NEEDED;
+    for (i=0;i<N_REGS;i++)
+       if (nstate[i]==L_UNKNOWN)
+           nstate[i]=L_UNAVAIL;
+}
+
+static __inline__ void log_dump(void)
+{
+    int i;
+    
+    return;
+
+    write_log("----------------------\n");
+    for (i=0;i<N_REGS;i++) {
+       switch(nstate[i]) {
+        case L_UNKNOWN: write_log("Nat %d : UNKNOWN\n",i); break;
+        case L_UNAVAIL: write_log("Nat %d : UNAVAIL\n",i); break;
+        default:        write_log("Nat %d : %d\n",i,nstate[i]); break;
+       }
+    }
+    for (i=0;i<VREGS;i++) {
+       if (vstate[i]==L_UNNEEDED)
+           write_log("Virt %d: UNNEEDED\n",i);
+    }
+}
+
+/********************************************************************
+ * register status handling. EMIT TIME!                             *
+ ********************************************************************/
+
+static __inline__ void set_status(int r, int status)
+{
+    if (status==ISCONST)
+       log_clobberreg(r);
+    live.state[r].status=status;
+}
+
+
+static __inline__ int isinreg(int r)
+{
+    return live.state[r].status==CLEAN || live.state[r].status==DIRTY;
+}
+
+static __inline__ void adjust_nreg(int r, uae_u32 val)
+{
+    if (!val)
+       return;
+    raw_lea_l_brr(r,r,val);
+}
+
+static  void tomem(int r)
+{
+    int rr=live.state[r].realreg;
+
+    if (isinreg(r)) {
+       if (live.state[r].val &&
+           live.nat[rr].nholds==1 &&
+           !live.nat[rr].locked) {
+           // printf("RemovingA offset %x from reg %d (%d) at %p\n",
+           //   live.state[r].val,r,rr,target); 
+           adjust_nreg(rr,live.state[r].val);
+           live.state[r].val=0;
+           live.state[r].dirtysize=4;
+           set_status(r,DIRTY);
+       }
+    }
+
+    if (live.state[r].status==DIRTY) {
+       switch (live.state[r].dirtysize) {
+        case 1: raw_mov_b_mr((uae_u32)live.state[r].mem,rr); break;
+        case 2: raw_mov_w_mr((uae_u32)live.state[r].mem,rr); break;
+        case 4: raw_mov_l_mr((uae_u32)live.state[r].mem,rr); break;
+        default: abort();
+       }
+       set_status(r,CLEAN);
+       live.state[r].dirtysize=0;
+    }
+}
+
+static __inline__ int isconst(int r)
+{
+    return live.state[r].status==ISCONST;
+}
+
+int is_const(int r)
+{
+    return isconst(r);
+}
+
+static __inline__ void writeback_const(int r)
+{
+    if (!isconst(r))
+       return;
+    Dif (live.state[r].needflush==NF_HANDLER) {
+       fprintf(stderr,"Trying to write back constant NF_HANDLER!\n");
+       abort();
+    }
+
+    raw_mov_l_mi((uae_u32)live.state[r].mem,live.state[r].val);
+    live.state[r].val=0;
+    set_status(r,INMEM);
+}
+
+static __inline__ void tomem_c(int r)
+{
+    if (isconst(r)) {
+       writeback_const(r);
+    }
+    else
+       tomem(r);
+}
+
+static  void evict(int r)
+{
+    int rr;
+
+    if (!isinreg(r))
+       return;
+    tomem(r);
+    rr=live.state[r].realreg;
+
+    Dif (live.nat[rr].locked &&
+       live.nat[rr].nholds==1) {
+       fprintf(stderr,"register %d in nreg %d is locked!\n",r,live.state[r].realreg);
+       abort();
+    }
+
+    live.nat[rr].nholds--;
+    if (live.nat[rr].nholds!=live.state[r].realind) { /* Was not last */
+       int topreg=live.nat[rr].holds[live.nat[rr].nholds];
+       int thisind=live.state[r].realind;
+       live.nat[rr].holds[thisind]=topreg;
+       live.state[topreg].realind=thisind;
+    }
+    live.state[r].realreg=-1;
+    set_status(r,INMEM);
+}
+
+static __inline__ void free_nreg(int r)
+{
+    int i=live.nat[r].nholds;
+
+    while (i) {
+       int vr;
+
+       --i;
+       vr=live.nat[r].holds[i];
+       evict(vr);
+    }
+    Dif (live.nat[r].nholds!=0) {
+       printf("Failed to free nreg %d, nholds is %d\n",r,live.nat[r].nholds);
+       abort();
+    }
+}
+
+/* Use with care! */
+static __inline__ void isclean(int r)
+{
+    if (!isinreg(r))
+       return;
+    live.state[r].validsize=4;
+    live.state[r].dirtysize=0;
+    live.state[r].val=0;
+    set_status(r,CLEAN);
+}
+
+static __inline__ void disassociate(int r)
+{
+    isclean(r);
+    evict(r);
+}
+
+static __inline__ void set_const(int r, uae_u32 val)
+{
+    disassociate(r);
+    live.state[r].val=val;
+    set_status(r,ISCONST);
+}
+
+static __inline__ uae_u32 get_offset(int r)
+{
+    return live.state[r].val;
+}
+
+static  int alloc_reg_hinted(int r, int size, int willclobber, int hint)
+{
+    int bestreg;
+    uae_s32 when;
+    int i;
+    uae_s32 badness=0; /* to shut up gcc */
+    bestreg=-1;
+    when=2000000000;
+
+    for (i=N_REGS;i--;) {
+       badness=live.nat[i].touched;
+       if (live.nat[i].nholds==0)
+           badness=0;
+       if (i==hint)  
+           badness-=200000000;
+       if (!live.nat[i].locked && badness<when) {
+           if ((size==1 && live.nat[i].canbyte) ||
+               (size==2 && live.nat[i].canword) ||
+               (size==4)) {
+               bestreg=i;
+               when=badness;
+               if (live.nat[i].nholds==0 && hint<0)
+                   break;
+               if (i==hint)
+                   break;
+           }
+       }
+    }
+    Dif (bestreg==-1)
+       abort();
+
+    if (live.nat[bestreg].nholds>0) {
+       free_nreg(bestreg);
+    }
+    if (isinreg(r)) {
+       int rr=live.state[r].realreg;
+       /* This will happen if we read a partially dirty register at a
+          bigger size */
+       Dif (willclobber || live.state[r].validsize>=size)
+           abort();
+       Dif (live.nat[rr].nholds!=1)
+           abort();
+       if (size==4 && live.state[r].validsize==2) {
+           log_isused(bestreg);
+           raw_mov_l_rm(bestreg,(uae_u32)live.state[r].mem);
+           raw_bswap_32(bestreg);
+           raw_zero_extend_16_rr(rr,rr);
+           raw_zero_extend_16_rr(bestreg,bestreg);
+           raw_bswap_32(bestreg);
+           raw_lea_l_brr_indexed(rr,rr,bestreg,1,0);
+           live.state[r].validsize=4;
+           live.nat[rr].touched=touchcnt++;
+           return rr;
+       }
+       if (live.state[r].validsize==1) {
+           /* Nothing yet */
+       }
+       evict(r);
+    }
+
+    if (!willclobber) {
+       if (live.state[r].status!=UNDEF) {
+           if (isconst(r)) {
+               raw_mov_l_ri(bestreg,live.state[r].val);
+               live.state[r].val=0;
+               live.state[r].dirtysize=4;
+               set_status(r,DIRTY);
+               log_isused(bestreg);
+           }
+           else {
+               if (r==FLAGTMP)
+                   raw_load_flagreg(bestreg,r);
+               else if (r==FLAGX)
+                   raw_load_flagx(bestreg,r);
+               else {
+                   raw_mov_l_rm(bestreg,(uae_u32)live.state[r].mem);
+               }
+               live.state[r].dirtysize=0;
+               set_status(r,CLEAN);
+               log_isreg(bestreg,r);
+           }
+       }
+       else {
+           live.state[r].val=0;
+           live.state[r].dirtysize=0;
+           set_status(r,CLEAN);
+           log_isused(bestreg);
+       }
+       live.state[r].validsize=4;
+    }
+    else { /* this is the easiest way, but not optimal. FIXME! */
+       /* Now it's trickier, but hopefully still OK */
+       if (!isconst(r) || size==4) {
+           live.state[r].validsize=size;
+           live.state[r].dirtysize=size;
+           live.state[r].val=0;
+           set_status(r,DIRTY);
+           if (size==4)
+               log_isused(bestreg);
+           else
+               log_isreg(bestreg,r);
+       }
+       else {
+           if (live.state[r].status!=UNDEF)
+               raw_mov_l_ri(bestreg,live.state[r].val);
+           live.state[r].val=0;
+           live.state[r].validsize=4;
+           live.state[r].dirtysize=4;
+           set_status(r,DIRTY);
+           log_isused(bestreg);
+       }
+    }
+    live.state[r].realreg=bestreg;
+    live.state[r].realind=live.nat[bestreg].nholds;
+    live.nat[bestreg].touched=touchcnt++;
+    live.nat[bestreg].holds[live.nat[bestreg].nholds]=r;
+    live.nat[bestreg].nholds++;
+
+    return bestreg;
+}
+
+static  int alloc_reg(int r, int size, int willclobber)
+{
+    return alloc_reg_hinted(r,size,willclobber,-1);
+}
+
+static  void unlock(int r)
+{
+    Dif (!live.nat[r].locked)
+       abort();
+    live.nat[r].locked--;
+}
+
+static  void setlock(int r)
+{
+    live.nat[r].locked++;
+}
+
+
+static void mov_nregs(int d, int s)
+{
+    int ns=live.nat[s].nholds;
+    int nd=live.nat[d].nholds;
+    int i;
+
+    if (s==d)
+       return;
+
+    if (nd>0) 
+       free_nreg(d);
+
+    raw_mov_l_rr(d,s);
+    log_isused(d);
+
+    for (i=0;i<live.nat[s].nholds;i++) {
+       int vs=live.nat[s].holds[i];
+
+       live.state[vs].realreg=d;
+       live.state[vs].realind=i;
+       live.nat[d].holds[i]=vs;
+    }
+    live.nat[d].nholds=live.nat[s].nholds;
+
+    live.nat[s].nholds=0;
+}
+
+
+static __inline__ void make_exclusive(int r, int size, int spec)
+{
+    int clobber;
+    reg_status oldstate;
+    int rr=live.state[r].realreg;
+    int nr;
+    int nind;
+    int ndirt=0;
+    int i;
+
+    if (!isinreg(r))
+       return;
+    if (live.nat[rr].nholds==1)
+       return;
+    for (i=0;i<live.nat[rr].nholds;i++) {
+       int vr=live.nat[rr].holds[i];
+       if (vr!=r && 
+           (live.state[vr].status==DIRTY || live.state[vr].val))
+           ndirt++;
+    }
+    if (!ndirt && size<live.state[r].validsize && !live.nat[rr].locked) { 
+       /* Everything else is clean, so let's keep this register */
+       for (i=0;i<live.nat[rr].nholds;i++) {
+           int vr=live.nat[rr].holds[i];
+           if (vr!=r) {
+               evict(vr);
+               i--; /* Try that index again! */
+           }
+       }
+       Dif (live.nat[rr].nholds!=1) {
+           printf("natreg %d holds %d vregs, %d not exclusive\n",
+                  rr,live.nat[rr].nholds,r);
+           abort();
+       }
+       return;
+    }
+
+    /* We have to split the register */
+    oldstate=live.state[r];
+
+    setlock(rr); /* Make sure this doesn't go away */
+    /* Forget about r being in the register rr */
+    disassociate(r);
+    /* Get a new register, that we will clobber completely */
+    if (oldstate.status==DIRTY) {
+       /* If dirtysize is <4, we need a register that can handle the
+          eventual smaller memory store! Thanks to Quake68k for exposing
+          this detail ;-) */
+       nr=alloc_reg_hinted(r,oldstate.dirtysize,1,spec);
+    }
+    else {
+       nr=alloc_reg_hinted(r,4,1,spec);
+    }
+    nind=live.state[r].realind;
+    live.state[r]=oldstate;   /* Keep all the old state info */
+    live.state[r].realreg=nr;
+    live.state[r].realind=nind;
+
+    if (size<live.state[r].validsize) {
+       if (live.state[r].val) {
+           /* Might as well compensate for the offset now */
+           raw_lea_l_brr(nr,rr,oldstate.val);
+           live.state[r].val=0;
+           live.state[r].dirtysize=4;
+           set_status(r,DIRTY);
+       }
+       else
+           raw_mov_l_rr(nr,rr);  /* Make another copy */
+    }
+    unlock(rr); 
+}
+
+static __inline__ void add_offset(int r, uae_u32 off)
+{
+    live.state[r].val+=off;
+}
+
+static __inline__ void remove_offset(int r, int spec)
+{
+    reg_status oldstate;
+    int rr;
+
+    if (isconst(r))
+       return;
+    if (live.state[r].val==0)
+       return;
+    if (isinreg(r) && live.state[r].validsize<4) 
+       evict(r);
+
+    if (!isinreg(r)) 
+       alloc_reg_hinted(r,4,0,spec);
+
+    Dif (live.state[r].validsize!=4) {
+       printf("Validsize=%d in remove_offset\n",live.state[r].validsize);
+       abort();
+    }
+    make_exclusive(r,0,-1);
+    /* make_exclusive might have done the job already */
+    if (live.state[r].val==0)
+       return;
+    
+    rr=live.state[r].realreg;
+
+    if (live.nat[rr].nholds==1) {
+       //printf("RemovingB offset %x from reg %d (%d) at %p\n",
+       //       live.state[r].val,r,rr,target); 
+       adjust_nreg(rr,live.state[r].val);
+       live.state[r].dirtysize=4;
+       live.state[r].val=0;
+       set_status(r,DIRTY);
+       return;
+    }
+    printf("Failed in remove_offset\n");
+    abort();
+}
+
+STATIC_INLINE void remove_all_offsets(void)
+{
+    int i;
+
+    for (i=0;i<VREGS;i++)
+       remove_offset(i,-1);
+}
+
+static __inline__ int readreg_general(int r, int size, int spec, int can_offset)
+{
+    int n;
+    int answer=-1;
+    
+    if (live.state[r].status==UNDEF) {
+      printf("WARNING: Unexpected read of undefined register %d\n",r);
+    }
+    if (!can_offset)
+       remove_offset(r,spec);
+    
+    if (isinreg(r) && live.state[r].validsize>=size) {
+       n=live.state[r].realreg;
+       switch(size) {
+        case 1: 
+           if (live.nat[n].canbyte || spec>=0) { 
+               answer=n; 
+           }
+           break;
+        case 2: 
+           if (live.nat[n].canword || spec>=0) { 
+               answer=n; 
+           }
+           break;
+        case 4: 
+           answer=n; 
+           break;
+        default: abort();
+       }
+       if (answer<0)
+           evict(r);
+    }
+    /* either the value was in memory to start with, or it was evicted and 
+       is in memory now */
+    if (answer<0) {
+       answer=alloc_reg_hinted(r,spec>=0?4:size,0,spec);
+    }
+
+    if (spec>=0 && spec!=answer) {
+       /* Too bad */
+       mov_nregs(spec,answer);
+       answer=spec;
+    }
+    live.nat[answer].locked++;
+    live.nat[answer].touched=touchcnt++;
+    return answer;
+}
+
+
+
+static int readreg(int r, int size)
+{
+    return readreg_general(r,size,-1,0);
+}
+
+static int readreg_specific(int r, int size, int spec)
+{
+    return readreg_general(r,size,spec,0);
+}
+
+static int readreg_offset(int r, int size)
+{
+    return readreg_general(r,size,-1,1);
+}
+
+
+static __inline__ int writereg_general(int r, int size, int spec)
+{
+    int n;
+    int answer=-1;
+
+    if (size<4) {
+       remove_offset(r,spec);
+    }
+
+    make_exclusive(r,size,spec);
+    if (isinreg(r)) {
+       int nvsize=size>live.state[r].validsize?size:live.state[r].validsize;
+       int ndsize=size>live.state[r].dirtysize?size:live.state[r].dirtysize;
+       n=live.state[r].realreg;
+
+       Dif (live.nat[n].nholds!=1)
+           abort();
+       switch(size) {
+        case 1: 
+           if (live.nat[n].canbyte || spec>=0) { 
+               live.state[r].dirtysize=ndsize;
+               live.state[r].validsize=nvsize;
+               answer=n;
+           }
+           break;
+        case 2: 
+           if (live.nat[n].canword || spec>=0) { 
+               live.state[r].dirtysize=ndsize;
+               live.state[r].validsize=nvsize;
+               answer=n;
+           }
+           break;
+        case 4: 
+           live.state[r].dirtysize=ndsize;
+           live.state[r].validsize=nvsize;
+           answer=n;
+           break;
+        default: abort();
+       }
+       if (answer<0)
+           evict(r);
+    }
+    /* either the value was in memory to start with, or it was evicted and 
+       is in memory now */
+    if (answer<0) {
+       answer=alloc_reg_hinted(r,size,1,spec);
+    }
+    if (spec>=0 && spec!=answer) {
+       mov_nregs(spec,answer);
+       answer=spec;
+    }
+    if (live.state[r].status==UNDEF)
+       live.state[r].validsize=4;
+    live.state[r].dirtysize=size>live.state[r].dirtysize?size:live.state[r].dirtysize;
+    live.state[r].validsize=size>live.state[r].validsize?size:live.state[r].validsize;
+    
+    live.nat[answer].locked++;
+    live.nat[answer].touched=touchcnt++;
+    if (size==4) {
+       live.state[r].val=0;
+    }
+    else {
+       Dif (live.state[r].val) {
+           printf("Problem with val\n");
+           abort();
+       }
+    }
+    set_status(r,DIRTY);
+    return answer;
+}
+
+static int writereg(int r, int size)
+{
+    return writereg_general(r,size,-1);
+}
+
+static int writereg_specific(int r, int size, int spec)
+{
+    return writereg_general(r,size,spec);
+}
+
+static __inline__ int rmw_general(int r, int wsize, int rsize, int spec)
+{
+    int n;
+    int answer=-1;
+    
+    if (live.state[r].status==UNDEF) {
+      printf("WARNING: Unexpected read of undefined register %d\n",r);
+    }
+    remove_offset(r,spec);
+    make_exclusive(r,0,spec);
+
+    Dif (wsize<rsize) {
+       printf("Cannot handle wsize<rsize in rmw_general()\n");
+       abort();
+    }
+    if (isinreg(r) && live.state[r].validsize>=rsize) {
+       n=live.state[r].realreg;
+       Dif (live.nat[n].nholds!=1)
+           abort();
+
+       switch(rsize) {
+        case 1: 
+           if (live.nat[n].canbyte || spec>=0) { 
+               answer=n; 
+           }
+           break;
+        case 2: 
+           if (live.nat[n].canword || spec>=0) { 
+               answer=n; 
+           }
+           break;
+        case 4: 
+           answer=n; 
+           break;
+        default: abort();
+       }
+       if (answer<0)
+           evict(r);
+    }
+    /* either the value was in memory to start with, or it was evicted and 
+       is in memory now */
+    if (answer<0) {
+       answer=alloc_reg_hinted(r,spec>=0?4:rsize,0,spec);
+    }
+
+    if (spec>=0 && spec!=answer) {
+       /* Too bad */
+       mov_nregs(spec,answer);
+       answer=spec;
+    }
+    if (wsize>live.state[r].dirtysize)
+       live.state[r].dirtysize=wsize;
+    if (wsize>live.state[r].validsize)
+       live.state[r].validsize=wsize;
+    set_status(r,DIRTY);
+
+    live.nat[answer].locked++;
+    live.nat[answer].touched=touchcnt++;
+
+    Dif (live.state[r].val) {
+       printf("Problem with val(rmw)\n");
+       abort();
+    }
+    return answer;
+}
+
+static int rmw(int r, int wsize, int rsize) 
+{
+    return rmw_general(r,wsize,rsize,-1);
+}
+
+static int rmw_specific(int r, int wsize, int rsize, int spec) 
+{
+    return rmw_general(r,wsize,rsize,spec);
+}
+
+
+/* needed for restoring the carry flag on non-P6 cores */
+static void bt_l_ri_noclobber(R4 r, IMM i)
+{
+    int size=4;
+    if (i<16)
+       size=2;
+    r=readreg(r,size);
+    raw_bt_l_ri(r,i);
+    unlock(r);
+}
+
+/********************************************************************
+ * FPU register status handling. EMIT TIME!                         *
+ ********************************************************************/
+
+static  void f_tomem(int r)
+{
+    if (live.fate[r].status==DIRTY) {
+#if USE_LONG_DOUBLE
+       raw_fmov_ext_mr((uae_u32)live.fate[r].mem,live.fate[r].realreg); 
+#else
+       raw_fmov_mr((uae_u32)live.fate[r].mem,live.fate[r].realreg); 
+#endif
+       live.fate[r].status=CLEAN;
+    }
+}
+
+static  void f_tomem_drop(int r)
+{
+    if (live.fate[r].status==DIRTY) {
+#if USE_LONG_DOUBLE
+       raw_fmov_ext_mr_drop((uae_u32)live.fate[r].mem,live.fate[r].realreg); 
+#else
+       raw_fmov_mr_drop((uae_u32)live.fate[r].mem,live.fate[r].realreg); 
+#endif
+       live.fate[r].status=INMEM;
+    }
+}
+
+
+static __inline__ int f_isinreg(int r)
+{
+    return live.fate[r].status==CLEAN || live.fate[r].status==DIRTY;
+}
+
+static void f_evict(int r)
+{
+    int rr;
+
+    if (!f_isinreg(r))
+       return;
+    rr=live.fate[r].realreg;
+    if (live.fat[rr].nholds==1)
+       f_tomem_drop(r);
+    else
+       f_tomem(r);
+
+    Dif (live.fat[rr].locked &&
+       live.fat[rr].nholds==1) {
+       fprintf(stderr,"FPU register %d in nreg %d is locked!\n",r,live.fate[r].realreg);
+       abort();
+    }
+
+    live.fat[rr].nholds--;
+    if (live.fat[rr].nholds!=live.fate[r].realind) { /* Was not last */
+       int topreg=live.fat[rr].holds[live.fat[rr].nholds];
+       int thisind=live.fate[r].realind;
+       live.fat[rr].holds[thisind]=topreg;
+       live.fate[topreg].realind=thisind;
+    }
+    live.fate[r].status=INMEM;
+    live.fate[r].realreg=-1;
+}
+
+static __inline__ void f_free_nreg(int r)
+{
+    int i=live.fat[r].nholds;
+
+    while (i) {
+       int vr;
+
+       --i;
+       vr=live.fat[r].holds[i];
+       f_evict(vr);
+    }
+    Dif (live.fat[r].nholds!=0) {
+       printf("Failed to free nreg %d, nholds is %d\n",r,live.fat[r].nholds);
+       abort();
+    }
+}
+
+
+/* Use with care! */
+static __inline__ void f_isclean(int r)
+{
+    if (!f_isinreg(r))
+       return;
+    live.fate[r].status=CLEAN;
+}
+
+static __inline__ void f_disassociate(int r)
+{
+    f_isclean(r);
+    f_evict(r);
+}
+
+
+
+static  int f_alloc_reg(int r, int willclobber)
+{
+    int bestreg;
+    uae_s32 when;
+    int i;
+    uae_s32 badness;
+    bestreg=-1;
+    when=2000000000;
+    for (i=N_FREGS;i--;) {
+       badness=live.fat[i].touched;
+       if (live.fat[i].nholds==0)
+           badness=0;
+
+       if (!live.fat[i].locked && badness<when) {
+           bestreg=i;
+           when=badness;
+           if (live.fat[i].nholds==0)
+               break;
+       }
+    }
+    Dif (bestreg==-1)
+       abort();
+
+    if (live.fat[bestreg].nholds>0) {
+       f_free_nreg(bestreg);
+    }
+    if (f_isinreg(r)) {
+       f_evict(r);
+    }
+
+    if (!willclobber) {
+       if (live.fate[r].status!=UNDEF) {
+#if USE_LONG_DOUBLE
+           raw_fmov_ext_rm(bestreg,(uae_u32)live.fate[r].mem);
+#else
+           raw_fmov_rm(bestreg,(uae_u32)live.fate[r].mem);
+#endif
+       }
+       live.fate[r].status=CLEAN;
+    }
+    else { 
+       live.fate[r].status=DIRTY;
+    }
+    live.fate[r].realreg=bestreg;
+    live.fate[r].realind=live.fat[bestreg].nholds;
+    live.fat[bestreg].touched=touchcnt++;
+    live.fat[bestreg].holds[live.fat[bestreg].nholds]=r;
+    live.fat[bestreg].nholds++;
+
+    return bestreg;
+}
+
+static  void f_unlock(int r)
+{
+    Dif (!live.fat[r].locked)
+       abort();
+    live.fat[r].locked--;
+}
+
+static  void f_setlock(int r)
+{
+    live.fat[r].locked++;
+}
+
+static __inline__ int f_readreg(int r)
+{
+    int n;
+    int answer=-1;
+
+    if (f_isinreg(r)) {
+       n=live.fate[r].realreg;
+       answer=n; 
+    }
+    /* either the value was in memory to start with, or it was evicted and 
+       is in memory now */
+    if (answer<0) 
+       answer=f_alloc_reg(r,0);
+
+    live.fat[answer].locked++;
+    live.fat[answer].touched=touchcnt++;
+    return answer;
+}
+
+static __inline__ void f_make_exclusive(int r, int clobber)
+{
+    freg_status oldstate;
+    int rr=live.fate[r].realreg;
+    int nr;
+    int nind;
+    int ndirt=0;
+    int i;
+
+    if (!f_isinreg(r))
+       return;
+    if (live.fat[rr].nholds==1)
+       return;
+    for (i=0;i<live.fat[rr].nholds;i++) {
+       int vr=live.fat[rr].holds[i];
+       if (vr!=r && live.fate[vr].status==DIRTY)
+           ndirt++;
+    }
+    if (!ndirt && !live.fat[rr].locked) { 
+       /* Everything else is clean, so let's keep this register */
+       for (i=0;i<live.fat[rr].nholds;i++) {
+           int vr=live.fat[rr].holds[i];
+           if (vr!=r) {
+               f_evict(vr);
+               i--; /* Try that index again! */
+           }
+       }
+       Dif (live.fat[rr].nholds!=1) {
+           printf("realreg %d holds %d (",rr,live.fat[rr].nholds);
+           for (i=0;i<live.fat[rr].nholds;i++) {
+               printf(" %d(%d,%d)",live.fat[rr].holds[i],
+                      live.fate[live.fat[rr].holds[i]].realreg,
+                      live.fate[live.fat[rr].holds[i]].realind);
+           }
+           printf("\n");
+           abort();
+       }
+       return;
+    }
+
+    /* We have to split the register */
+    oldstate=live.fate[r];
+
+    f_setlock(rr); /* Make sure this doesn't go away */
+    /* Forget about r being in the register rr */
+    f_disassociate(r);
+    /* Get a new register, that we will clobber completely */
+    nr=f_alloc_reg(r,1);
+    nind=live.fate[r].realind;
+    if (!clobber)
+       raw_fmov_rr(nr,rr);  /* Make another copy */
+    live.fate[r]=oldstate;   /* Keep all the old state info */
+    live.fate[r].realreg=nr;
+    live.fate[r].realind=nind;
+    f_unlock(rr); 
+}
+
+
+static __inline__ int f_writereg(int r)
+{
+    int n;
+    int answer=-1;
+
+    f_make_exclusive(r,1);
+    if (f_isinreg(r)) {
+       n=live.fate[r].realreg;
+       answer=n;
+    }
+    if (answer<0) {
+       answer=f_alloc_reg(r,1);
+    }
+    live.fate[r].status=DIRTY;
+    live.fat[answer].locked++;
+    live.fat[answer].touched=touchcnt++;
+    return answer;
+}
+
+static int f_rmw(int r)
+{
+    int n;
+
+    f_make_exclusive(r,0);
+    if (f_isinreg(r)) {
+       n=live.fate[r].realreg;
+    }
+    else 
+       n=f_alloc_reg(r,0);
+    live.fate[r].status=DIRTY;
+    live.fat[n].locked++;
+    live.fat[n].touched=touchcnt++;
+    return n;
+}
+
+static void fflags_into_flags_internal(uae_u32 tmp)
+{
+    int r;
+
+    clobber_flags();
+    r=f_readreg(FP_RESULT);
+    raw_fflags_into_flags(r);
+    f_unlock(r);
+}
+
+
+
+
+/********************************************************************
+ * CPU functions exposed to gencomp. Both CREATE and EMIT time      *
+ ********************************************************************/
+
+/* 
+ *  RULES FOR HANDLING REGISTERS:
+ *
+ *  * In the function headers, order the parameters 
+ *     - 1st registers written to
+ *     - 2nd read/modify/write registers
+ *     - 3rd registers read from
+ *  * Before calling raw_*, you must call readreg, writereg or rmw for
+ *    each register
+ *  * The order for this is
+ *     - 1st call remove_offset for all registers written to with size<4
+ *     - 2nd call readreg for all registers read without offset
+ *     - 3rd call rmw for all rmw registers
+ *     - 4th call readreg_offset for all registers that can handle offsets
+ *     - 5th call get_offset for all the registers from the previous step
+ *     - 6th call writereg for all written-to registers
+ *     - 7th call raw_*
+ *     - 8th unlock all registers that were locked
+ */
+
+MIDFUNC(0,live_flags,(void))
+{
+    live.flags_on_stack=TRASH;
+    live.flags_in_flags=VALID;
+    live.flags_are_important=1;
+}
+MENDFUNC(0,live_flags,(void))
+
+MIDFUNC(0,dont_care_flags,(void))
+{
+    live.flags_are_important=0;
+}
+MENDFUNC(0,dont_care_flags,(void))
+
+
+MIDFUNC(0,duplicate_carry,(void))
+{
+    evict(FLAGX);
+    make_flags_live_internal();
+    COMPCALL(setcc_m)((uae_u32)live.state[FLAGX].mem,2);
+}
+MENDFUNC(0,duplicate_carry,(void))
+
+MIDFUNC(0,restore_carry,(void))
+{
+    if (!have_rat_stall) { /* Not a P6 core, i.e. no partial stalls */
+       bt_l_ri_noclobber(FLAGX,0);
+    }
+    else {  /* Avoid the stall the above creates.
+              This is slow on non-P6, though.
+           */
+       COMPCALL(rol_b_ri(FLAGX,8));
+       isclean(FLAGX);
+       /* Why is the above faster than the below? */
+       //raw_rol_b_mi((uae_u32)live.state[FLAGX].mem,8);
+    }
+}
+MENDFUNC(0,restore_carry,(void))
+
+MIDFUNC(0,start_needflags,(void))
+{
+    needflags=1;
+}
+MENDFUNC(0,start_needflags,(void))
+
+MIDFUNC(0,end_needflags,(void))
+{
+    needflags=0;
+}
+MENDFUNC(0,end_needflags,(void))
+
+MIDFUNC(0,make_flags_live,(void))
+{
+    make_flags_live_internal();
+}
+MENDFUNC(0,make_flags_live,(void))
+
+MIDFUNC(1,fflags_into_flags,(W2 tmp))
+{
+    clobber_flags();
+    fflags_into_flags_internal(tmp);
+}
+MENDFUNC(1,fflags_into_flags,(W2 tmp))
+
+
+MIDFUNC(2,bt_l_ri,(R4 r, IMM i)) /* This is defined as only affecting C */
+{    
+    int size=4;
+    if (i<16)
+       size=2;
+    CLOBBER_BT;
+    r=readreg(r,size);
+    raw_bt_l_ri(r,i);
+    unlock(r);
+}
+MENDFUNC(2,bt_l_ri,(R4 r, IMM i)) /* This is defined as only affecting C */
+
+MIDFUNC(2,bt_l_rr,(R4 r, R4 b)) /* This is defined as only affecting C */
+{
+    CLOBBER_BT;
+    r=readreg(r,4);
+    b=readreg(b,4);
+    raw_bt_l_rr(r,b);
+    unlock(r);
+    unlock(b);
+}
+MENDFUNC(2,bt_l_rr,(R4 r, R4 b)) /* This is defined as only affecting C */
+
+MIDFUNC(2,btc_l_ri,(RW4 r, IMM i)) 
+{    
+    int size=4;
+    if (i<16)
+       size=2;
+    CLOBBER_BT;
+    r=rmw(r,size,size);
+    raw_btc_l_ri(r,i);
+    unlock(r);
+}
+MENDFUNC(2,btc_l_ri,(RW4 r, IMM i)) 
+
+MIDFUNC(2,btc_l_rr,(RW4 r, R4 b)) 
+{
+    CLOBBER_BT;
+    b=readreg(b,4);
+    r=rmw(r,4,4);
+    raw_btc_l_rr(r,b);
+    unlock(r);
+    unlock(b);
+}
+MENDFUNC(2,btc_l_rr,(RW4 r, R4 b)) 
+
+
+MIDFUNC(2,btr_l_ri,(RW4 r, IMM i)) 
+{    
+    int size=4;
+    if (i<16)
+       size=2;
+    CLOBBER_BT;
+    r=rmw(r,size,size);
+    raw_btr_l_ri(r,i);
+    unlock(r);
+}
+MENDFUNC(2,btr_l_ri,(RW4 r, IMM i)) 
+
+MIDFUNC(2,btr_l_rr,(RW4 r, R4 b)) 
+{
+    CLOBBER_BT;
+    b=readreg(b,4);
+    r=rmw(r,4,4);
+    raw_btr_l_rr(r,b);
+    unlock(r);
+    unlock(b);
+}
+MENDFUNC(2,btr_l_rr,(RW4 r, R4 b)) 
+
+
+MIDFUNC(2,bts_l_ri,(RW4 r, IMM i)) 
+{    
+    int size=4;
+    if (i<16)
+       size=2;
+    CLOBBER_BT;
+    r=rmw(r,size,size);
+    raw_bts_l_ri(r,i);
+    unlock(r);
+}
+MENDFUNC(2,bts_l_ri,(RW4 r, IMM i)) 
+
+MIDFUNC(2,bts_l_rr,(RW4 r, R4 b)) 
+{
+    CLOBBER_BT;
+    b=readreg(b,4);
+    r=rmw(r,4,4);
+    raw_bts_l_rr(r,b);
+    unlock(r);
+    unlock(b);
+}
+MENDFUNC(2,bts_l_rr,(RW4 r, R4 b)) 
+
+MIDFUNC(2,mov_l_rm,(W4 d, IMM s))
+{
+    CLOBBER_MOV;
+    d=writereg(d,4);
+    raw_mov_l_rm(d,s);
+    unlock(d);
+}
+MENDFUNC(2,mov_l_rm,(W4 d, IMM s))
+
+
+MIDFUNC(1,call_r,(R4 r)) /* Clobbering is implicit */
+{
+    r=readreg(r,4);
+    raw_call_r(r);
+    unlock(r);
+}
+MENDFUNC(1,call_r,(R4 r)) /* Clobbering is implicit */
+
+MIDFUNC(2,sub_l_mi,(IMM d, IMM s)) 
+{
+    CLOBBER_SUB;
+    raw_sub_l_mi(d,s) ;
+}
+MENDFUNC(2,sub_l_mi,(IMM d, IMM s)) 
+
+MIDFUNC(2,mov_l_mi,(IMM d, IMM s)) 
+{
+    CLOBBER_MOV;
+    raw_mov_l_mi(d,s) ;
+}
+MENDFUNC(2,mov_l_mi,(IMM d, IMM s)) 
+
+MIDFUNC(2,mov_w_mi,(IMM d, IMM s)) 
+{
+    CLOBBER_MOV;
+    raw_mov_w_mi(d,s) ;
+}
+MENDFUNC(2,mov_w_mi,(IMM d, IMM s)) 
+
+MIDFUNC(2,mov_b_mi,(IMM d, IMM s)) 
+{
+    CLOBBER_MOV;
+    raw_mov_b_mi(d,s) ;
+}
+MENDFUNC(2,mov_b_mi,(IMM d, IMM s)) 
+
+MIDFUNC(2,rol_b_ri,(RW1 r, IMM i))
+{
+               if (!i && !needflags)
+               return;
+    CLOBBER_ROL;
+    r=rmw(r,1,1);
+    raw_rol_b_ri(r,i);
+    unlock(r);
+}
+MENDFUNC(2,rol_b_ri,(RW1 r, IMM i))
+
+MIDFUNC(2,rol_w_ri,(RW2 r, IMM i))
+{
+               if (!i && !needflags)
+               return;
+    CLOBBER_ROL;
+    r=rmw(r,2,2);
+    raw_rol_w_ri(r,i);
+    unlock(r);
+}
+MENDFUNC(2,rol_w_ri,(RW2 r, IMM i))
+
+MIDFUNC(2,rol_l_ri,(RW4 r, IMM i))
+{
+               if (!i && !needflags)
+               return;
+    CLOBBER_ROL;
+    r=rmw(r,4,4);
+    raw_rol_l_ri(r,i);
+    unlock(r);
+}
+MENDFUNC(2,rol_l_ri,(RW4 r, IMM i))
+
+MIDFUNC(2,rol_l_rr,(RW4 d, R1 r)) 
+{ 
+    if (isconst(r)) {
+       COMPCALL(rol_l_ri)(d,(uae_u8)live.state[r].val);
+       return;
+    }
+    CLOBBER_ROL;
+    r=readreg_specific(r,1,SHIFTCOUNT_NREG);
+    d=rmw(d,4,4);
+    Dif (r!=1) {
+       fprintf(stderr,"Illegal register %d in raw_rol_b\n",r);
+       abort();
+    }
+    raw_rol_l_rr(d,r) ;
+    unlock(r);
+    unlock(d);
+}
+MENDFUNC(2,rol_l_rr,(RW4 d, R1 r)) 
+
+MIDFUNC(2,rol_w_rr,(RW2 d, R1 r)) 
+{ /* Can only do this with r==1, i.e. cl */
+  
+    if (isconst(r)) {
+       COMPCALL(rol_w_ri)(d,(uae_u8)live.state[r].val);
+       return;
+    }
+    CLOBBER_ROL;
+    r=readreg_specific(r,1,SHIFTCOUNT_NREG);
+    d=rmw(d,2,2);
+    Dif (r!=1) {
+       fprintf(stderr,"Illegal register %d in raw_rol_b\n",r);
+       abort();
+    }
+    raw_rol_w_rr(d,r) ;
+    unlock(r);
+    unlock(d);
+}
+MENDFUNC(2,rol_w_rr,(RW2 d, R1 r)) 
+
+MIDFUNC(2,rol_b_rr,(RW1 d, R1 r)) 
+{ /* Can only do this with r==1, i.e. cl */
+  
+    if (isconst(r)) {
+       COMPCALL(rol_b_ri)(d,(uae_u8)live.state[r].val);
+       return;
+    }
+
+    CLOBBER_ROL;
+    r=readreg_specific(r,1,SHIFTCOUNT_NREG);
+    d=rmw(d,1,1);
+    Dif (r!=1) {
+       fprintf(stderr,"Illegal register %d in raw_rol_b\n",r);
+       abort();
+    }
+    raw_rol_b_rr(d,r) ;
+    unlock(r);
+    unlock(d);
+}
+MENDFUNC(2,rol_b_rr,(RW1 d, R1 r)) 
+
+
+MIDFUNC(2,shll_l_rr,(RW4 d, R1 r)) 
+{ 
+    if (isconst(r)) {
+       COMPCALL(shll_l_ri)(d,(uae_u8)live.state[r].val);
+       return;
+    }
+    CLOBBER_SHLL;
+    r=readreg_specific(r,1,SHIFTCOUNT_NREG);
+    d=rmw(d,4,4);
+    Dif (r!=1) {
+       fprintf(stderr,"Illegal register %d in raw_rol_b\n",r);
+       abort();
+    }
+    raw_shll_l_rr(d,r) ;
+    unlock(r);
+    unlock(d);
+}
+MENDFUNC(2,shll_l_rr,(RW4 d, R1 r)) 
+
+MIDFUNC(2,shll_w_rr,(RW2 d, R1 r)) 
+{ /* Can only do this with r==1, i.e. cl */
+  
+    if (isconst(r)) {
+       COMPCALL(shll_w_ri)(d,(uae_u8)live.state[r].val);
+       return;
+    }
+    CLOBBER_SHLL;
+    r=readreg_specific(r,1,SHIFTCOUNT_NREG);
+    d=rmw(d,2,2);
+    Dif (r!=1) {
+       fprintf(stderr,"Illegal register %d in raw_shll_b\n",r);
+       abort();
+    }
+    raw_shll_w_rr(d,r) ;
+    unlock(r);
+    unlock(d);
+}
+MENDFUNC(2,shll_w_rr,(RW2 d, R1 r)) 
+
+MIDFUNC(2,shll_b_rr,(RW1 d, R1 r)) 
+{ /* Can only do this with r==1, i.e. cl */
+  
+    if (isconst(r)) {
+       COMPCALL(shll_b_ri)(d,(uae_u8)live.state[r].val);
+       return;
+    }
+
+    CLOBBER_SHLL;
+    r=readreg_specific(r,1,SHIFTCOUNT_NREG);
+    d=rmw(d,1,1);
+    Dif (r!=1) {
+       fprintf(stderr,"Illegal register %d in raw_shll_b\n",r);
+       abort();
+    }
+    raw_shll_b_rr(d,r) ;
+    unlock(r);
+    unlock(d);
+}
+MENDFUNC(2,shll_b_rr,(RW1 d, R1 r)) 
+
+
+MIDFUNC(2,ror_b_ri,(R1 r, IMM i))
+{
+               if (!i && !needflags)
+               return;
+    CLOBBER_ROR;
+    r=rmw(r,1,1);
+    raw_ror_b_ri(r,i);
+    unlock(r);
+}
+MENDFUNC(2,ror_b_ri,(R1 r, IMM i))
+
+MIDFUNC(2,ror_w_ri,(R2 r, IMM i))
+{
+               if (!i && !needflags)
+               return;
+    CLOBBER_ROR;
+    r=rmw(r,2,2);
+    raw_ror_w_ri(r,i);
+    unlock(r);
+}
+MENDFUNC(2,ror_w_ri,(R2 r, IMM i))
+
+MIDFUNC(2,ror_l_ri,(R4 r, IMM i))
+{
+               if (!i && !needflags)
+               return;
+    CLOBBER_ROR;
+    r=rmw(r,4,4);
+    raw_ror_l_ri(r,i);
+    unlock(r);
+}
+MENDFUNC(2,ror_l_ri,(R4 r, IMM i))
+
+MIDFUNC(2,ror_l_rr,(R4 d, R1 r)) 
+{ 
+    if (isconst(r)) {
+       COMPCALL(ror_l_ri)(d,(uae_u8)live.state[r].val);
+       return;
+    }
+    CLOBBER_ROR;
+    r=readreg_specific(r,1,SHIFTCOUNT_NREG);
+    d=rmw(d,4,4);
+    raw_ror_l_rr(d,r) ;
+    unlock(r);
+    unlock(d);
+}
+MENDFUNC(2,ror_l_rr,(R4 d, R1 r)) 
+
+MIDFUNC(2,ror_w_rr,(R2 d, R1 r)) 
+{ 
+    if (isconst(r)) {
+       COMPCALL(ror_w_ri)(d,(uae_u8)live.state[r].val);
+       return;
+    }
+    CLOBBER_ROR;
+    r=readreg_specific(r,1,SHIFTCOUNT_NREG);
+    d=rmw(d,2,2);
+    raw_ror_w_rr(d,r) ;
+    unlock(r);
+    unlock(d);
+}
+MENDFUNC(2,ror_w_rr,(R2 d, R1 r)) 
+
+MIDFUNC(2,ror_b_rr,(R1 d, R1 r)) 
+{   
+    if (isconst(r)) {
+       COMPCALL(ror_b_ri)(d,(uae_u8)live.state[r].val);
+       return;
+    }
+
+    CLOBBER_ROR;
+    r=readreg_specific(r,1,SHIFTCOUNT_NREG);
+    d=rmw(d,1,1);
+    raw_ror_b_rr(d,r) ;
+    unlock(r);
+    unlock(d);
+}
+MENDFUNC(2,ror_b_rr,(R1 d, R1 r)) 
+
+MIDFUNC(2,shrl_l_rr,(RW4 d, R1 r)) 
+{ 
+    if (isconst(r)) {
+       COMPCALL(shrl_l_ri)(d,(uae_u8)live.state[r].val);
+       return;
+    }
+    CLOBBER_SHRL;
+    r=readreg_specific(r,1,SHIFTCOUNT_NREG);
+    d=rmw(d,4,4);
+    Dif (r!=1) {
+       fprintf(stderr,"Illegal register %d in raw_rol_b\n",r);
+       abort();
+    }
+    raw_shrl_l_rr(d,r) ;
+    unlock(r);
+    unlock(d);
+}
+MENDFUNC(2,shrl_l_rr,(RW4 d, R1 r)) 
+
+MIDFUNC(2,shrl_w_rr,(RW2 d, R1 r)) 
+{ /* Can only do this with r==1, i.e. cl */
+  
+    if (isconst(r)) {
+       COMPCALL(shrl_w_ri)(d,(uae_u8)live.state[r].val);
+       return;
+    }
+    CLOBBER_SHRL;
+    r=readreg_specific(r,1,SHIFTCOUNT_NREG);
+    d=rmw(d,2,2);
+    Dif (r!=1) {
+       fprintf(stderr,"Illegal register %d in raw_shrl_b\n",r);
+       abort();
+    }
+    raw_shrl_w_rr(d,r) ;
+    unlock(r);
+    unlock(d);
+}
+MENDFUNC(2,shrl_w_rr,(RW2 d, R1 r)) 
+
+MIDFUNC(2,shrl_b_rr,(RW1 d, R1 r)) 
+{ /* Can only do this with r==1, i.e. cl */
+  
+    if (isconst(r)) {
+       COMPCALL(shrl_b_ri)(d,(uae_u8)live.state[r].val);
+       return;
+    }
+
+    CLOBBER_SHRL;
+    r=readreg_specific(r,1,SHIFTCOUNT_NREG);
+    d=rmw(d,1,1);
+    Dif (r!=1) {
+       fprintf(stderr,"Illegal register %d in raw_shrl_b\n",r);
+       abort();
+    }
+    raw_shrl_b_rr(d,r) ;
+    unlock(r);
+    unlock(d);
+}
+MENDFUNC(2,shrl_b_rr,(RW1 d, R1 r)) 
+
+
+
+MIDFUNC(2,shll_l_ri,(RW4 r, IMM i))
+{
+    if (!i && !needflags)
+       return;
+    if (isconst(r) && !needflags) {
+       live.state[r].val<<=i;
+       return;
+    }
+    CLOBBER_SHLL;
+    r=rmw(r,4,4);
+    raw_shll_l_ri(r,i);
+    unlock(r);
+}
+MENDFUNC(2,shll_l_ri,(RW4 r, IMM i))
+
+MIDFUNC(2,shll_w_ri,(RW2 r, IMM i))
+{
+    if (!i && !needflags)
+       return;
+    CLOBBER_SHLL;
+    r=rmw(r,2,2);
+    raw_shll_w_ri(r,i);
+    unlock(r);
+}
+MENDFUNC(2,shll_w_ri,(RW2 r, IMM i))
+
+MIDFUNC(2,shll_b_ri,(RW1 r, IMM i))
+{
+    if (!i && !needflags)
+       return;
+    CLOBBER_SHLL;
+    r=rmw(r,1,1);
+    raw_shll_b_ri(r,i);
+    unlock(r);
+}
+MENDFUNC(2,shll_b_ri,(RW1 r, IMM i))
+
+MIDFUNC(2,shrl_l_ri,(RW4 r, IMM i))
+{
+    if (!i && !needflags)
+       return;
+    if (isconst(r) && !needflags) {
+       live.state[r].val>>=i;
+       return;
+    }
+    CLOBBER_SHRL;
+    r=rmw(r,4,4);
+    raw_shrl_l_ri(r,i);
+    unlock(r);
+}
+MENDFUNC(2,shrl_l_ri,(RW4 r, IMM i))
+
+MIDFUNC(2,shrl_w_ri,(RW2 r, IMM i))
+{
+    if (!i && !needflags)
+       return;
+    CLOBBER_SHRL;
+    r=rmw(r,2,2);
+    raw_shrl_w_ri(r,i);
+    unlock(r);
+}
+MENDFUNC(2,shrl_w_ri,(RW2 r, IMM i))
+
+MIDFUNC(2,shrl_b_ri,(RW1 r, IMM i))
+{
+    if (!i && !needflags)
+       return;
+    CLOBBER_SHRL;
+    r=rmw(r,1,1);
+    raw_shrl_b_ri(r,i);
+    unlock(r);
+}
+MENDFUNC(2,shrl_b_ri,(RW1 r, IMM i))
+
+MIDFUNC(2,shra_l_ri,(RW4 r, IMM i))
+{
+    if (!i && !needflags)
+       return;
+    CLOBBER_SHRA;
+    r=rmw(r,4,4);
+    raw_shra_l_ri(r,i);
+    unlock(r);
+}
+MENDFUNC(2,shra_l_ri,(RW4 r, IMM i))
+
+MIDFUNC(2,shra_w_ri,(RW2 r, IMM i))
+{
+    if (!i && !needflags)
+       return;
+    CLOBBER_SHRA;
+    r=rmw(r,2,2);
+    raw_shra_w_ri(r,i);
+    unlock(r);
+}
+MENDFUNC(2,shra_w_ri,(RW2 r, IMM i))
+
+MIDFUNC(2,shra_b_ri,(RW1 r, IMM i))
+{
+    if (!i && !needflags)
+       return;
+    CLOBBER_SHRA;
+    r=rmw(r,1,1);
+    raw_shra_b_ri(r,i);
+    unlock(r);
+}
+MENDFUNC(2,shra_b_ri,(RW1 r, IMM i))
+
+MIDFUNC(2,shra_l_rr,(RW4 d, R1 r)) 
+{ 
+    if (isconst(r)) {
+       COMPCALL(shra_l_ri)(d,(uae_u8)live.state[r].val);
+       return;
+    }
+    CLOBBER_SHRA;
+    r=readreg_specific(r,1,SHIFTCOUNT_NREG);
+    d=rmw(d,4,4);
+    Dif (r!=1) {
+       fprintf(stderr,"Illegal register %d in raw_rol_b\n",r);
+       abort();
+    }
+    raw_shra_l_rr(d,r) ;
+    unlock(r);
+    unlock(d);
+}
+MENDFUNC(2,shra_l_rr,(RW4 d, R1 r)) 
+
+MIDFUNC(2,shra_w_rr,(RW2 d, R1 r)) 
+{ /* Can only do this with r==1, i.e. cl */
+  
+    if (isconst(r)) {
+       COMPCALL(shra_w_ri)(d,(uae_u8)live.state[r].val);
+       return;
+    }
+    CLOBBER_SHRA;
+    r=readreg_specific(r,1,SHIFTCOUNT_NREG);
+    d=rmw(d,2,2);
+    Dif (r!=1) {
+       fprintf(stderr,"Illegal register %d in raw_shra_b\n",r);
+       abort();
+    }
+    raw_shra_w_rr(d,r) ;
+    unlock(r);
+    unlock(d);
+}
+MENDFUNC(2,shra_w_rr,(RW2 d, R1 r)) 
+
+MIDFUNC(2,shra_b_rr,(RW1 d, R1 r)) 
+{ /* Can only do this with r==1, i.e. cl */
+  
+    if (isconst(r)) {
+       COMPCALL(shra_b_ri)(d,(uae_u8)live.state[r].val);
+       return;
+    }
+
+    CLOBBER_SHRA;
+    r=readreg_specific(r,1,SHIFTCOUNT_NREG);
+    d=rmw(d,1,1);
+    Dif (r!=1) {
+       fprintf(stderr,"Illegal register %d in raw_shra_b\n",r);
+       abort();
+    }
+    raw_shra_b_rr(d,r) ;
+    unlock(r);
+    unlock(d);
+}
+MENDFUNC(2,shra_b_rr,(RW1 d, R1 r)) 
+
+
+MIDFUNC(2,setcc,(W1 d, IMM cc))
+{
+    CLOBBER_SETCC;
+    d=writereg(d,1);
+    raw_setcc(d,cc);
+    unlock(d);
+}
+MENDFUNC(2,setcc,(W1 d, IMM cc))
+
+MIDFUNC(2,setcc_m,(IMM d, IMM cc))
+{
+    CLOBBER_SETCC;
+    raw_setcc_m(d,cc);
+}
+MENDFUNC(2,setcc_m,(IMM d, IMM cc))
+
+MIDFUNC(3,cmov_l_rr,(RW4 d, R4 s, IMM cc))
+{
+    if (d==s)
+       return;
+    CLOBBER_CMOV;
+    s=readreg(s,4);
+    d=rmw(d,4,4);
+    raw_cmov_l_rr(d,s,cc);
+    unlock(s);
+    unlock(d);
+}
+MENDFUNC(3,cmov_l_rr,(RW4 d, R4 s, IMM cc))
+
+MIDFUNC(1,setzflg_l,(RW4 r))
+{
+       if (setzflg_uses_bsf) {
+               CLOBBER_BSF;
+               r=rmw(r,4,4);
+               raw_bsf_l_rr(r,r);
+               unlock(r);
+       }
+       else {
+               Dif (live.flags_in_flags!=VALID) {
+                       write_log("setzflg() wanted flags in native flags, they are %d\n",
+                                         live.flags_in_flags);
+                       abort();
+               }
+               r=readreg(r,4);
+               {
+               int f=writereg(S11,4);
+               int t=writereg(S12,4);
+               raw_flags_set_zero(f,r,t);
+               unlock(f);
+               unlock(r);
+               unlock(t);
+               }
+       }
+}
+MENDFUNC(1,setzflg_l,(RW4 r))
+
+MIDFUNC(3,cmov_l_rm,(RW4 d, IMM s, IMM cc))
+{
+    CLOBBER_CMOV;
+    d=rmw(d,4,4);
+    raw_cmov_l_rm(d,s,cc);
+    unlock(d);
+}
+MENDFUNC(3,cmov_l_rm,(RW4 d, IMM s, IMM cc))
+
+MIDFUNC(2,bsf_l_rr,(W4 d, R4 s))
+{
+    CLOBBER_BSF;
+    s=readreg(s,4);
+    d=writereg(d,4);
+    raw_bsf_l_rr(d,s);
+    unlock(s);
+    unlock(d);
+}
+MENDFUNC(2,bsf_l_rr,(W4 d, R4 s))
+
+MIDFUNC(2,imul_32_32,(RW4 d, R4 s))
+{
+    CLOBBER_MUL;
+    s=readreg(s,4);
+    d=rmw(d,4,4);
+    raw_imul_32_32(d,s);
+    unlock(s);
+    unlock(d);
+}
+MENDFUNC(2,imul_32_32,(RW4 d, R4 s))
+
+MIDFUNC(2,imul_64_32,(RW4 d, RW4 s))
+{
+    CLOBBER_MUL;
+    s=rmw_specific(s,4,4,MUL_NREG2);
+    d=rmw_specific(d,4,4,MUL_NREG1);
+    raw_imul_64_32(d,s);
+    unlock(s);
+    unlock(d);
+}
+MENDFUNC(2,imul_64_32,(RW4 d, RW4 s))
+
+MIDFUNC(2,mul_64_32,(RW4 d, RW4 s))
+{
+    CLOBBER_MUL;
+    s=rmw_specific(s,4,4,MUL_NREG2);
+    d=rmw_specific(d,4,4,MUL_NREG1);
+    raw_mul_64_32(d,s);
+    unlock(s);
+    unlock(d);
+}
+MENDFUNC(2,mul_64_32,(RW4 d, RW4 s))
+
+MIDFUNC(2,mul_32_32,(RW4 d, R4 s))
+{
+    CLOBBER_MUL;
+    s=readreg(s,4);
+    d=rmw(d,4,4);
+    raw_mul_32_32(d,s);
+    unlock(s);
+    unlock(d);
+}
+MENDFUNC(2,mul_32_32,(RW4 d, R4 s))
+
+MIDFUNC(2,sign_extend_16_rr,(W4 d, R2 s))
+{
+    int isrmw;
+
+    if (isconst(s)) {
+       set_const(d,(uae_s32)(uae_s16)live.state[s].val);
+       return;
+    }
+
+    CLOBBER_SE16;
+    isrmw=(s==d);
+    if (!isrmw) {
+       s=readreg(s,2);
+       d=writereg(d,4);
+    }
+    else {  /* If we try to lock this twice, with different sizes, we
+              are int trouble! */
+       s=d=rmw(s,4,2);
+    }
+    raw_sign_extend_16_rr(d,s);
+    if (!isrmw) {
+       unlock(d);
+       unlock(s);
+    }
+    else {
+       unlock(s);
+    }
+}
+MENDFUNC(2,sign_extend_16_rr,(W4 d, R2 s))
+
+MIDFUNC(2,sign_extend_8_rr,(W4 d, R1 s))
+{
+    int isrmw;
+
+    if (isconst(s)) {
+       set_const(d,(uae_s32)(uae_s8)live.state[s].val);
+       return;
+    }
+
+    isrmw=(s==d);
+    CLOBBER_SE8;
+    if (!isrmw) {
+       s=readreg(s,1);
+       d=writereg(d,4);
+    }
+    else {  /* If we try to lock this twice, with different sizes, we
+              are int trouble! */
+       s=d=rmw(s,4,1);
+    }
+  
+    raw_sign_extend_8_rr(d,s);
+
+    if (!isrmw) {
+       unlock(d);
+       unlock(s);
+    }
+    else {
+       unlock(s);
+    }
+}
+MENDFUNC(2,sign_extend_8_rr,(W4 d, R1 s))
+
+
+MIDFUNC(2,zero_extend_16_rr,(W4 d, R2 s))
+{
+    int isrmw;
+
+    if (isconst(s)) {
+       set_const(d,(uae_u32)(uae_u16)live.state[s].val);
+       return;
+    }
+
+    isrmw=(s==d);
+    CLOBBER_ZE16;
+    if (!isrmw) {
+       s=readreg(s,2);
+       d=writereg(d,4);
+    }
+    else {  /* If we try to lock this twice, with different sizes, we
+              are int trouble! */
+       s=d=rmw(s,4,2);
+    }
+    raw_zero_extend_16_rr(d,s);
+    if (!isrmw) {
+       unlock(d);
+       unlock(s);
+    }
+    else {
+       unlock(s);
+    }
+}
+MENDFUNC(2,zero_extend_16_rr,(W4 d, R2 s))
+
+MIDFUNC(2,zero_extend_8_rr,(W4 d, R1 s))
+{
+    int isrmw;
+    if (isconst(s)) {
+       set_const(d,(uae_u32)(uae_u8)live.state[s].val);
+       return;
+    }
+
+    isrmw=(s==d);
+    CLOBBER_ZE8;
+    if (!isrmw) {
+       s=readreg(s,1);
+       d=writereg(d,4);
+    }
+    else {  /* If we try to lock this twice, with different sizes, we
+              are int trouble! */
+       s=d=rmw(s,4,1);
+    }
+  
+    raw_zero_extend_8_rr(d,s);
+
+    if (!isrmw) {
+       unlock(d);
+       unlock(s);
+    }
+    else {
+       unlock(s);
+    }
+}
+MENDFUNC(2,zero_extend_8_rr,(W4 d, R1 s))
+
+MIDFUNC(2,mov_b_rr,(W1 d, R1 s))
+{
+    if (d==s)
+       return;
+    if (isconst(s)) {
+       COMPCALL(mov_b_ri)(d,(uae_u8)live.state[s].val);
+       return;
+    }
+
+    CLOBBER_MOV;
+    s=readreg(s,1);
+    d=writereg(d,1);
+    raw_mov_b_rr(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,mov_b_rr,(W1 d, R1 s))
+
+MIDFUNC(2,mov_w_rr,(W2 d, R2 s))
+{
+    if (d==s)
+       return;
+    if (isconst(s)) {
+       COMPCALL(mov_w_ri)(d,(uae_u16)live.state[s].val);
+       return;
+    }
+
+    CLOBBER_MOV;
+    s=readreg(s,2);
+    d=writereg(d,2);
+    raw_mov_w_rr(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,mov_w_rr,(W2 d, R2 s))
+
+
+MIDFUNC(4,mov_l_rrm_indexed,(W4 d,R4 baser, R4 index, IMM factor))
+{
+    CLOBBER_MOV;
+    baser=readreg(baser,4);
+    index=readreg(index,4);
+    d=writereg(d,4);
+
+    raw_mov_l_rrm_indexed(d,baser,index,factor);
+    unlock(d);
+    unlock(baser);
+    unlock(index);
+}
+MENDFUNC(4,mov_l_rrm_indexed,(W4 d,R4 baser, R4 index, IMM factor))
+
+MIDFUNC(4,mov_w_rrm_indexed,(W2 d, R4 baser, R4 index, IMM factor))
+{
+    CLOBBER_MOV;
+    baser=readreg(baser,4);
+    index=readreg(index,4);
+    d=writereg(d,2);
+
+    raw_mov_w_rrm_indexed(d,baser,index,factor);
+    unlock(d);
+    unlock(baser);
+    unlock(index);
+}
+MENDFUNC(4,mov_w_rrm_indexed,(W2 d, R4 baser, R4 index, IMM factor))
+
+MIDFUNC(4,mov_b_rrm_indexed,(W1 d, R4 baser, R4 index, IMM factor))
+{
+    CLOBBER_MOV;
+    baser=readreg(baser,4);
+    index=readreg(index,4);
+    d=writereg(d,1);
+
+    raw_mov_b_rrm_indexed(d,baser,index,factor);
+
+    unlock(d);
+    unlock(baser);
+    unlock(index);
+}
+MENDFUNC(4,mov_b_rrm_indexed,(W1 d, R4 baser, R4 index, IMM factor))
+
+
+MIDFUNC(4,mov_l_mrr_indexed,(R4 baser, R4 index, IMM factor, R4 s))
+{
+    CLOBBER_MOV;
+    baser=readreg(baser,4);
+    index=readreg(index,4);
+    s=readreg(s,4);
+
+    Dif (baser==s || index==s) 
+       abort();
+
+
+    raw_mov_l_mrr_indexed(baser,index,factor,s);
+    unlock(s);
+    unlock(baser);
+    unlock(index);
+}
+MENDFUNC(4,mov_l_mrr_indexed,(R4 baser, R4 index, IMM factor, R4 s))
+
+MIDFUNC(4,mov_w_mrr_indexed,(R4 baser, R4 index, IMM factor, R2 s))
+{
+    CLOBBER_MOV;
+    baser=readreg(baser,4);
+    index=readreg(index,4);
+    s=readreg(s,2);
+
+    raw_mov_w_mrr_indexed(baser,index,factor,s);
+    unlock(s);
+    unlock(baser);
+    unlock(index);
+}
+MENDFUNC(4,mov_w_mrr_indexed,(R4 baser, R4 index, IMM factor, R2 s))
+
+MIDFUNC(4,mov_b_mrr_indexed,(R4 baser, R4 index, IMM factor, R1 s))
+{
+    CLOBBER_MOV;
+    s=readreg(s,1);
+    baser=readreg(baser,4);
+    index=readreg(index,4);
+
+    raw_mov_b_mrr_indexed(baser,index,factor,s);
+    unlock(s);
+    unlock(baser);
+    unlock(index);
+}
+MENDFUNC(4,mov_b_mrr_indexed,(R4 baser, R4 index, IMM factor, R1 s))
+
+
+MIDFUNC(5,mov_l_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R4 s))
+{
+    int basereg=baser;
+    int indexreg=index;
+
+    CLOBBER_MOV;
+    s=readreg(s,4);
+    baser=readreg_offset(baser,4);
+    index=readreg_offset(index,4);
+
+    base+=get_offset(basereg);
+    base+=factor*get_offset(indexreg);
+
+    raw_mov_l_bmrr_indexed(base,baser,index,factor,s);
+    unlock(s);
+    unlock(baser);
+    unlock(index);
+}
+MENDFUNC(5,mov_l_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R4 s))
+
+MIDFUNC(5,mov_w_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R2 s))
+{
+    int basereg=baser;
+    int indexreg=index;
+
+    CLOBBER_MOV;
+    s=readreg(s,2);
+    baser=readreg_offset(baser,4);
+    index=readreg_offset(index,4);
+
+    base+=get_offset(basereg);
+    base+=factor*get_offset(indexreg);
+
+    raw_mov_w_bmrr_indexed(base,baser,index,factor,s);
+    unlock(s);
+    unlock(baser);
+    unlock(index);
+}
+MENDFUNC(5,mov_w_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R2 s))
+
+MIDFUNC(5,mov_b_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R1 s))
+{
+    int basereg=baser;
+    int indexreg=index;
+
+    CLOBBER_MOV;
+    s=readreg(s,1);
+    baser=readreg_offset(baser,4);
+    index=readreg_offset(index,4);
+
+    base+=get_offset(basereg);
+    base+=factor*get_offset(indexreg);
+
+    raw_mov_b_bmrr_indexed(base,baser,index,factor,s);
+    unlock(s);
+    unlock(baser);
+    unlock(index);
+}
+MENDFUNC(5,mov_b_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R1 s))
+
+
+
+/* Read a long from base+baser+factor*index */
+MIDFUNC(5,mov_l_brrm_indexed,(W4 d, IMM base, R4 baser, R4 index, IMM factor))
+{
+    int basereg=baser;
+    int indexreg=index;
+
+    CLOBBER_MOV;
+    baser=readreg_offset(baser,4);
+    index=readreg_offset(index,4);
+    base+=get_offset(basereg);
+    base+=factor*get_offset(indexreg);    
+    d=writereg(d,4);
+    raw_mov_l_brrm_indexed(d,base,baser,index,factor);
+    unlock(d);
+    unlock(baser);
+    unlock(index);
+}
+MENDFUNC(5,mov_l_brrm_indexed,(W4 d, IMM base, R4 baser, R4 index, IMM factor))
+
+
+MIDFUNC(5,mov_w_brrm_indexed,(W2 d, IMM base, R4 baser, R4 index, IMM factor))
+{
+    int basereg=baser;
+    int indexreg=index;
+
+    CLOBBER_MOV;
+    remove_offset(d,-1);
+    baser=readreg_offset(baser,4);
+    index=readreg_offset(index,4);
+    base+=get_offset(basereg);
+    base+=factor*get_offset(indexreg);    
+    d=writereg(d,2);
+    raw_mov_w_brrm_indexed(d,base,baser,index,factor);
+    unlock(d);
+    unlock(baser);
+    unlock(index);
+}
+MENDFUNC(5,mov_w_brrm_indexed,(W2 d, IMM base, R4 baser, R4 index, IMM factor))
+
+
+MIDFUNC(5,mov_b_brrm_indexed,(W1 d, IMM base, R4 baser, R4 index, IMM factor))
+{
+    int basereg=baser;
+    int indexreg=index;
+
+    CLOBBER_MOV;
+    remove_offset(d,-1);
+    baser=readreg_offset(baser,4);
+    index=readreg_offset(index,4);
+    base+=get_offset(basereg);
+    base+=factor*get_offset(indexreg);    
+    d=writereg(d,1);
+    raw_mov_b_brrm_indexed(d,base,baser,index,factor);
+    unlock(d);
+    unlock(baser);
+    unlock(index);
+}
+MENDFUNC(5,mov_b_brrm_indexed,(W1 d, IMM base, R4 baser, R4 index, IMM factor))
+
+/* Read a long from base+factor*index */
+MIDFUNC(4,mov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor))
+{
+    int indexreg=index;
+
+    if (isconst(index)) {
+       COMPCALL(mov_l_rm)(d,base+factor*live.state[index].val);
+       return;
+    }
+
+    CLOBBER_MOV;
+    index=readreg_offset(index,4);
+    base+=get_offset(indexreg)*factor;
+    d=writereg(d,4);
+
+    raw_mov_l_rm_indexed(d,base,index,factor);
+    unlock(index);
+    unlock(d);
+}
+MENDFUNC(4,mov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor))
+
+
+/* read the long at the address contained in s+offset and store in d */
+MIDFUNC(3,mov_l_rR,(W4 d, R4 s, IMM offset))
+{
+    if (isconst(s)) {
+       COMPCALL(mov_l_rm)(d,live.state[s].val+offset);
+       return;
+    }
+    CLOBBER_MOV;
+    s=readreg(s,4);
+    d=writereg(d,4);
+
+    raw_mov_l_rR(d,s,offset);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(3,mov_l_rR,(W4 d, R4 s, IMM offset))
+
+/* read the word at the address contained in s+offset and store in d */
+MIDFUNC(3,mov_w_rR,(W2 d, R4 s, IMM offset))
+{
+    if (isconst(s)) {
+       COMPCALL(mov_w_rm)(d,live.state[s].val+offset);
+       return;
+    }
+    CLOBBER_MOV;
+    s=readreg(s,4);
+    d=writereg(d,2);
+
+    raw_mov_w_rR(d,s,offset);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(3,mov_w_rR,(W2 d, R4 s, IMM offset))
+
+/* read the word at the address contained in s+offset and store in d */
+MIDFUNC(3,mov_b_rR,(W1 d, R4 s, IMM offset))
+{
+    if (isconst(s)) {
+       COMPCALL(mov_b_rm)(d,live.state[s].val+offset);
+       return;
+    }
+    CLOBBER_MOV;
+    s=readreg(s,4);
+    d=writereg(d,1);
+
+    raw_mov_b_rR(d,s,offset);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(3,mov_b_rR,(W1 d, R4 s, IMM offset))
+
+/* read the long at the address contained in s+offset and store in d */
+MIDFUNC(3,mov_l_brR,(W4 d, R4 s, IMM offset))
+{
+    int sreg=s;
+    if (isconst(s)) {
+       COMPCALL(mov_l_rm)(d,live.state[s].val+offset);
+       return;
+    }
+    CLOBBER_MOV;
+    s=readreg_offset(s,4);
+    offset+=get_offset(sreg);
+    d=writereg(d,4);
+    
+    raw_mov_l_brR(d,s,offset);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(3,mov_l_brR,(W4 d, R4 s, IMM offset))
+
+/* read the word at the address contained in s+offset and store in d */
+MIDFUNC(3,mov_w_brR,(W2 d, R4 s, IMM offset))
+{
+    int sreg=s;
+    if (isconst(s)) {
+       COMPCALL(mov_w_rm)(d,live.state[s].val+offset);
+       return;
+    }
+    CLOBBER_MOV;
+    remove_offset(d,-1);
+    s=readreg_offset(s,4);
+    offset+=get_offset(sreg);
+    d=writereg(d,2);
+
+    raw_mov_w_brR(d,s,offset);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(3,mov_w_brR,(W2 d, R4 s, IMM offset))
+
+/* read the word at the address contained in s+offset and store in d */
+MIDFUNC(3,mov_b_brR,(W1 d, R4 s, IMM offset))
+{
+    int sreg=s;
+    if (isconst(s)) {
+       COMPCALL(mov_b_rm)(d,live.state[s].val+offset);
+       return;
+    }
+    CLOBBER_MOV;
+    remove_offset(d,-1);
+    s=readreg_offset(s,4);
+    offset+=get_offset(sreg);
+    d=writereg(d,1);
+
+    raw_mov_b_brR(d,s,offset);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(3,mov_b_brR,(W1 d, R4 s, IMM offset))
+
+MIDFUNC(3,mov_l_Ri,(R4 d, IMM i, IMM offset))
+{
+    int dreg=d;
+    if (isconst(d)) {
+       COMPCALL(mov_l_mi)(live.state[d].val+offset,i);
+       return;
+    }
+
+    CLOBBER_MOV;
+    d=readreg_offset(d,4);
+    offset+=get_offset(dreg);
+    raw_mov_l_Ri(d,i,offset);
+    unlock(d);
+}
+MENDFUNC(3,mov_l_Ri,(R4 d, IMM i, IMM offset))
+
+MIDFUNC(3,mov_w_Ri,(R4 d, IMM i, IMM offset))
+{
+    int dreg=d;
+    if (isconst(d)) {
+       COMPCALL(mov_w_mi)(live.state[d].val+offset,i);
+       return;
+    }
+
+    CLOBBER_MOV;
+    d=readreg_offset(d,4);
+    offset+=get_offset(dreg);
+    raw_mov_w_Ri(d,i,offset);
+    unlock(d);
+}
+MENDFUNC(3,mov_w_Ri,(R4 d, IMM i, IMM offset))
+
+MIDFUNC(3,mov_b_Ri,(R4 d, IMM i, IMM offset))
+{
+    int dreg=d;
+    if (isconst(d)) {
+       COMPCALL(mov_b_mi)(live.state[d].val+offset,i);
+       return;
+    }
+
+    CLOBBER_MOV;
+    d=readreg_offset(d,4);
+    offset+=get_offset(dreg);
+    raw_mov_b_Ri(d,i,offset);
+    unlock(d);
+}
+MENDFUNC(3,mov_b_Ri,(R4 d, IMM i, IMM offset))
+
+     /* Warning! OFFSET is byte sized only! */
+MIDFUNC(3,mov_l_Rr,(R4 d, R4 s, IMM offset))
+{
+    if (isconst(d)) {
+       COMPCALL(mov_l_mr)(live.state[d].val+offset,s);
+       return;
+    }
+    if (isconst(s)) {
+       COMPCALL(mov_l_Ri)(d,live.state[s].val,offset);
+       return;
+    }
+
+    CLOBBER_MOV;
+    s=readreg(s,4);
+    d=readreg(d,4);
+
+    raw_mov_l_Rr(d,s,offset);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(3,mov_l_Rr,(R4 d, R4 s, IMM offset))
+
+MIDFUNC(3,mov_w_Rr,(R4 d, R2 s, IMM offset))
+{
+    if (isconst(d)) {
+       COMPCALL(mov_w_mr)(live.state[d].val+offset,s);
+       return;
+    }
+    if (isconst(s)) {
+       COMPCALL(mov_w_Ri)(d,(uae_u16)live.state[s].val,offset);
+       return;
+    }
+
+    CLOBBER_MOV;
+    s=readreg(s,2);
+    d=readreg(d,4);
+    raw_mov_w_Rr(d,s,offset);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(3,mov_w_Rr,(R4 d, R2 s, IMM offset))
+
+MIDFUNC(3,mov_b_Rr,(R4 d, R1 s, IMM offset))
+{
+    if (isconst(d)) {
+       COMPCALL(mov_b_mr)(live.state[d].val+offset,s);
+       return;
+    }
+    if (isconst(s)) {
+       COMPCALL(mov_b_Ri)(d,(uae_u8)live.state[s].val,offset);
+       return;
+    }
+
+    CLOBBER_MOV;
+    s=readreg(s,1);
+    d=readreg(d,4);
+    raw_mov_b_Rr(d,s,offset);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(3,mov_b_Rr,(R4 d, R1 s, IMM offset))
+
+MIDFUNC(3,lea_l_brr,(W4 d, R4 s, IMM offset))
+{
+    if (isconst(s)) {
+       COMPCALL(mov_l_ri)(d,live.state[s].val+offset);
+       return;
+    }
+#if USE_OFFSET
+    if (d==s) {
+       add_offset(d,offset);
+       return;
+    }
+#endif
+    CLOBBER_LEA;
+    s=readreg(s,4);
+    d=writereg(d,4);
+    raw_lea_l_brr(d,s,offset);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(3,lea_l_brr,(W4 d, R4 s, IMM offset))
+
+MIDFUNC(5,lea_l_brr_indexed,(W4 d, R4 s, R4 index, IMM factor, IMM offset))
+{
+    if (!offset) {
+       COMPCALL(lea_l_rr_indexed)(d,s,index,factor);
+       return;
+    }
+    CLOBBER_LEA;
+    s=readreg(s,4);
+    index=readreg(index,4);
+    d=writereg(d,4);
+
+    raw_lea_l_brr_indexed(d,s,index,factor,offset);
+    unlock(d);
+    unlock(index);
+    unlock(s);
+}
+MENDFUNC(5,lea_l_brr_indexed,(W4 d, R4 s, R4 index, IMM factor, IMM offset))
+
+MIDFUNC(4,lea_l_rr_indexed,(W4 d, R4 s, R4 index, IMM factor))
+{
+    CLOBBER_LEA;
+    s=readreg(s,4);
+    index=readreg(index,4);
+    d=writereg(d,4);
+
+    raw_lea_l_rr_indexed(d,s,index,factor);
+    unlock(d);
+    unlock(index);
+    unlock(s);
+}
+MENDFUNC(4,lea_l_rr_indexed,(W4 d, R4 s, R4 index, IMM factor))
+
+/* write d to the long at the address contained in s+offset */
+MIDFUNC(3,mov_l_bRr,(R4 d, R4 s, IMM offset))
+{
+    int dreg=d;
+    if (isconst(d)) {
+       COMPCALL(mov_l_mr)(live.state[d].val+offset,s);
+       return;
+    }
+
+    CLOBBER_MOV;
+    s=readreg(s,4);
+    d=readreg_offset(d,4);
+    offset+=get_offset(dreg);
+
+    raw_mov_l_bRr(d,s,offset);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(3,mov_l_bRr,(R4 d, R4 s, IMM offset))
+
+/* write the word at the address contained in s+offset and store in d */
+MIDFUNC(3,mov_w_bRr,(R4 d, R2 s, IMM offset))
+{
+    int dreg=d;
+
+    if (isconst(d)) {
+       COMPCALL(mov_w_mr)(live.state[d].val+offset,s);
+       return;
+    }
+
+    CLOBBER_MOV;
+    s=readreg(s,2);
+    d=readreg_offset(d,4);
+    offset+=get_offset(dreg);
+    raw_mov_w_bRr(d,s,offset);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(3,mov_w_bRr,(R4 d, R2 s, IMM offset))
+
+MIDFUNC(3,mov_b_bRr,(R4 d, R1 s, IMM offset))
+{
+    int dreg=d;
+    if (isconst(d)) {
+       COMPCALL(mov_b_mr)(live.state[d].val+offset,s);
+       return;
+    }
+
+    CLOBBER_MOV;
+    s=readreg(s,1);
+    d=readreg_offset(d,4);
+    offset+=get_offset(dreg);
+    raw_mov_b_bRr(d,s,offset);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(3,mov_b_bRr,(R4 d, R1 s, IMM offset))
+
+MIDFUNC(1,bswap_32,(RW4 r))
+{
+    int reg=r;
+
+    if (isconst(r)) {
+       uae_u32 oldv=live.state[r].val;
+       live.state[r].val=reverse32(oldv);
+       return;
+    }
+    
+    CLOBBER_SW32;
+    r=rmw(r,4,4);  
+    raw_bswap_32(r);
+    unlock(r);
+}
+MENDFUNC(1,bswap_32,(RW4 r))
+
+MIDFUNC(1,bswap_16,(RW2 r))
+{
+    if (isconst(r)) {
+       uae_u32 oldv=live.state[r].val;
+       live.state[r].val=((oldv>>8)&0xff) | ((oldv<<8)&0xff00) |
+           (oldv&0xffff0000);
+       return;
+    }
+
+    CLOBBER_SW16;
+    r=rmw(r,2,2);
+  
+    raw_bswap_16(r);
+    unlock(r);
+}
+MENDFUNC(1,bswap_16,(RW2 r))
+
+
+
+MIDFUNC(2,mov_l_rr,(W4 d, R4 s))
+{
+    int olds;
+
+    if (d==s) { /* How pointless! */
+       return;
+    }
+    if (isconst(s)) {
+       COMPCALL(mov_l_ri)(d,live.state[s].val);
+       return;
+    }
+#if USE_ALIAS
+    olds=s;
+    disassociate(d);
+    s=readreg_offset(s,4);
+    live.state[d].realreg=s;
+    live.state[d].realind=live.nat[s].nholds;
+    live.state[d].val=live.state[olds].val;
+    live.state[d].validsize=4;
+    live.state[d].dirtysize=4;
+    set_status(d,DIRTY);
+
+    live.nat[s].holds[live.nat[s].nholds]=d;
+    live.nat[s].nholds++;
+    log_clobberreg(d);
+    
+    /* printf("Added %d to nreg %d(%d), now holds %d regs\n",
+       d,s,live.state[d].realind,live.nat[s].nholds); */
+    unlock(s);
+#else
+    CLOBBER_MOV;
+    s=readreg(s,4);
+    d=writereg(d,4);
+
+    raw_mov_l_rr(d,s);
+    unlock(d);
+    unlock(s);
+#endif
+}
+MENDFUNC(2,mov_l_rr,(W4 d, R4 s))
+
+MIDFUNC(2,mov_l_mr,(IMM d, R4 s))
+{
+    if (isconst(s)) {
+       COMPCALL(mov_l_mi)(d,live.state[s].val);
+       return;
+    }
+    CLOBBER_MOV;
+    s=readreg(s,4);
+
+    raw_mov_l_mr(d,s);
+    unlock(s);
+}
+MENDFUNC(2,mov_l_mr,(IMM d, R4 s))
+
+
+MIDFUNC(2,mov_w_mr,(IMM d, R2 s))
+{
+    if (isconst(s)) {
+       COMPCALL(mov_w_mi)(d,(uae_u16)live.state[s].val);
+       return;
+    }
+    CLOBBER_MOV;
+    s=readreg(s,2);
+
+    raw_mov_w_mr(d,s);
+    unlock(s);
+}
+MENDFUNC(2,mov_w_mr,(IMM d, R2 s))
+
+MIDFUNC(2,mov_w_rm,(W2 d, IMM s))
+{
+    CLOBBER_MOV;
+    d=writereg(d,2);
+
+    raw_mov_w_rm(d,s);
+    unlock(d);
+}
+MENDFUNC(2,mov_w_rm,(W2 d, IMM s))
+
+MIDFUNC(2,mov_b_mr,(IMM d, R1 s))
+{
+    if (isconst(s)) {
+       COMPCALL(mov_b_mi)(d,(uae_u8)live.state[s].val);
+       return;
+    }
+
+    CLOBBER_MOV;
+    s=readreg(s,1);
+
+    raw_mov_b_mr(d,s);
+    unlock(s);
+}
+MENDFUNC(2,mov_b_mr,(IMM d, R1 s))
+
+MIDFUNC(2,mov_b_rm,(W1 d, IMM s))
+{
+    CLOBBER_MOV;
+    d=writereg(d,1);
+
+    raw_mov_b_rm(d,s);
+    unlock(d);
+}
+MENDFUNC(2,mov_b_rm,(W1 d, IMM s))
+
+MIDFUNC(2,mov_l_ri,(W4 d, IMM s))
+{
+    set_const(d,s);
+    return;
+}
+MENDFUNC(2,mov_l_ri,(W4 d, IMM s))
+
+MIDFUNC(2,mov_w_ri,(W2 d, IMM s))
+{
+    CLOBBER_MOV;
+    d=writereg(d,2);
+
+    raw_mov_w_ri(d,s);
+    unlock(d);
+}
+MENDFUNC(2,mov_w_ri,(W2 d, IMM s))
+
+MIDFUNC(2,mov_b_ri,(W1 d, IMM s))
+{
+    CLOBBER_MOV;
+    d=writereg(d,1);
+
+    raw_mov_b_ri(d,s);
+    unlock(d);
+}
+MENDFUNC(2,mov_b_ri,(W1 d, IMM s))
+
+
+MIDFUNC(2,add_l_mi,(IMM d, IMM s)) 
+{
+    CLOBBER_ADD;
+    raw_add_l_mi(d,s) ;
+}
+MENDFUNC(2,add_l_mi,(IMM d, IMM s)) 
+
+MIDFUNC(2,add_w_mi,(IMM d, IMM s)) 
+{
+    CLOBBER_ADD;
+    raw_add_w_mi(d,s) ;
+}
+MENDFUNC(2,add_w_mi,(IMM d, IMM s)) 
+
+MIDFUNC(2,add_b_mi,(IMM d, IMM s)) 
+{
+    CLOBBER_ADD;
+    raw_add_b_mi(d,s) ;
+}
+MENDFUNC(2,add_b_mi,(IMM d, IMM s)) 
+
+
+MIDFUNC(2,test_l_ri,(R4 d, IMM i))
+{
+    CLOBBER_TEST;
+    d=readreg(d,4);
+
+    raw_test_l_ri(d,i);
+    unlock(d);
+}
+MENDFUNC(2,test_l_ri,(R4 d, IMM i))
+
+MIDFUNC(2,test_l_rr,(R4 d, R4 s))
+{
+    CLOBBER_TEST;
+    d=readreg(d,4);
+    s=readreg(s,4);
+
+    raw_test_l_rr(d,s);;
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,test_l_rr,(R4 d, R4 s))
+
+MIDFUNC(2,test_w_rr,(R2 d, R2 s))
+{
+    CLOBBER_TEST;
+    d=readreg(d,2);
+    s=readreg(s,2);
+
+    raw_test_w_rr(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,test_w_rr,(R2 d, R2 s))
+
+MIDFUNC(2,test_b_rr,(R1 d, R1 s))
+{
+    CLOBBER_TEST;
+    d=readreg(d,1);
+    s=readreg(s,1);
+
+    raw_test_b_rr(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,test_b_rr,(R1 d, R1 s))
+
+
+MIDFUNC(2,and_l_ri,(RW4 d, IMM i))
+{
+    if (isconst (d) && ! needflags) {
+       live.state[d].val &= i;
+       return;
+    }
+
+    CLOBBER_AND;
+    d=rmw(d,4,4);
+
+    raw_and_l_ri(d,i);
+    unlock(d);
+}
+MENDFUNC(2,and_l_ri,(RW4 d, IMM i))
+
+MIDFUNC(2,and_l,(RW4 d, R4 s))
+{
+    CLOBBER_AND;
+    s=readreg(s,4);
+    d=rmw(d,4,4);
+
+    raw_and_l(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,and_l,(RW4 d, R4 s))
+
+MIDFUNC(2,and_w,(RW2 d, R2 s))
+{
+    CLOBBER_AND;
+    s=readreg(s,2);
+    d=rmw(d,2,2);
+
+    raw_and_w(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,and_w,(RW2 d, R2 s))
+
+MIDFUNC(2,and_b,(RW1 d, R1 s))
+{
+    CLOBBER_AND;
+    s=readreg(s,1);
+    d=rmw(d,1,1);
+
+    raw_and_b(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,and_b,(RW1 d, R1 s))
+
+MIDFUNC(2,or_l_ri,(RW4 d, IMM i))
+{
+    if (isconst(d) && !needflags) {
+       live.state[d].val|=i;
+       return;
+    }
+    CLOBBER_OR;
+    d=rmw(d,4,4);
+
+    raw_or_l_ri(d,i);
+    unlock(d);
+}
+MENDFUNC(2,or_l_ri,(RW4 d, IMM i))
+
+MIDFUNC(2,or_l,(RW4 d, R4 s))
+{
+    if (isconst(d) && isconst(s) && !needflags) {
+       live.state[d].val|=live.state[s].val;
+       return;
+    }
+    CLOBBER_OR;
+    s=readreg(s,4);
+    d=rmw(d,4,4);
+
+    raw_or_l(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,or_l,(RW4 d, R4 s))
+
+MIDFUNC(2,or_w,(RW2 d, R2 s))
+{
+    CLOBBER_OR;
+    s=readreg(s,2);
+    d=rmw(d,2,2);
+
+    raw_or_w(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,or_w,(RW2 d, R2 s))
+
+MIDFUNC(2,or_b,(RW1 d, R1 s))
+{
+    CLOBBER_OR;
+    s=readreg(s,1);
+    d=rmw(d,1,1);
+
+    raw_or_b(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,or_b,(RW1 d, R1 s))
+
+MIDFUNC(2,adc_l,(RW4 d, R4 s))
+{
+    CLOBBER_ADC;
+    s=readreg(s,4);
+    d=rmw(d,4,4);
+
+    raw_adc_l(d,s);
+
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,adc_l,(RW4 d, R4 s))
+
+MIDFUNC(2,adc_w,(RW2 d, R2 s))
+{
+    CLOBBER_ADC;
+    s=readreg(s,2);
+    d=rmw(d,2,2);
+
+    raw_adc_w(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,adc_w,(RW2 d, R2 s))
+
+MIDFUNC(2,adc_b,(RW1 d, R1 s))
+{
+    CLOBBER_ADC;
+    s=readreg(s,1);
+    d=rmw(d,1,1);
+
+    raw_adc_b(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,adc_b,(RW1 d, R1 s))
+
+MIDFUNC(2,add_l,(RW4 d, R4 s))
+{
+    if (isconst(s)) {
+       COMPCALL(add_l_ri)(d,live.state[s].val);
+       return;
+    }
+
+    CLOBBER_ADD;
+    s=readreg(s,4);
+    d=rmw(d,4,4);
+
+    raw_add_l(d,s);
+
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,add_l,(RW4 d, R4 s))
+
+MIDFUNC(2,add_w,(RW2 d, R2 s))
+{
+    if (isconst(s)) {
+       COMPCALL(add_w_ri)(d,(uae_u16)live.state[s].val);
+       return;
+    }
+
+    CLOBBER_ADD;
+    s=readreg(s,2);
+    d=rmw(d,2,2);
+
+    raw_add_w(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,add_w,(RW2 d, R2 s))
+
+MIDFUNC(2,add_b,(RW1 d, R1 s))
+{
+    if (isconst(s)) {
+       COMPCALL(add_b_ri)(d,(uae_u8)live.state[s].val);
+       return;
+    }
+
+    CLOBBER_ADD;
+    s=readreg(s,1);
+    d=rmw(d,1,1);
+
+    raw_add_b(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,add_b,(RW1 d, R1 s))
+
+MIDFUNC(2,sub_l_ri,(RW4 d, IMM i))
+{
+    if (!i && !needflags)
+       return;
+    if (isconst(d) && !needflags) {
+       live.state[d].val-=i;
+       return;
+    }
+#if USE_OFFSET 
+    if (!needflags) {
+       add_offset(d,-(signed)i);
+       return;
+    }
+#endif
+
+    CLOBBER_SUB;
+    d=rmw(d,4,4);
+
+    raw_sub_l_ri(d,i);
+    unlock(d);
+}
+MENDFUNC(2,sub_l_ri,(RW4 d, IMM i))
+
+MIDFUNC(2,sub_w_ri,(RW2 d, IMM i))
+{
+    if (!i && !needflags)
+       return;
+
+    CLOBBER_SUB;
+    d=rmw(d,2,2);
+
+    raw_sub_w_ri(d,i);
+    unlock(d);
+}
+MENDFUNC(2,sub_w_ri,(RW2 d, IMM i))
+
+MIDFUNC(2,sub_b_ri,(RW1 d, IMM i))
+{
+    if (!i && !needflags)
+       return;
+
+    CLOBBER_SUB;
+    d=rmw(d,1,1);
+
+    raw_sub_b_ri(d,i);
+
+    unlock(d);
+}
+MENDFUNC(2,sub_b_ri,(RW1 d, IMM i))
+
+MIDFUNC(2,add_l_ri,(RW4 d, IMM i))
+{
+    if (!i && !needflags)
+       return;
+    if (isconst(d) && !needflags) {
+       live.state[d].val+=i;
+       return;
+    }
+#if USE_OFFSET 
+    if (!needflags) {
+       add_offset(d,i);
+       return;
+    }
+#endif
+    CLOBBER_ADD;
+    d=rmw(d,4,4);
+    raw_add_l_ri(d,i);
+    unlock(d);
+}
+MENDFUNC(2,add_l_ri,(RW4 d, IMM i))
+
+MIDFUNC(2,add_w_ri,(RW2 d, IMM i))
+{
+    if (!i && !needflags)
+       return;
+
+    CLOBBER_ADD;
+    d=rmw(d,2,2);
+
+    raw_add_w_ri(d,i);
+    unlock(d);
+}
+MENDFUNC(2,add_w_ri,(RW2 d, IMM i))
+
+MIDFUNC(2,add_b_ri,(RW1 d, IMM i))
+{
+    if (!i && !needflags)
+       return;
+
+    CLOBBER_ADD;
+    d=rmw(d,1,1);
+
+    raw_add_b_ri(d,i);
+
+    unlock(d);
+}
+MENDFUNC(2,add_b_ri,(RW1 d, IMM i))
+
+MIDFUNC(2,sbb_l,(RW4 d, R4 s))
+{
+    CLOBBER_SBB;
+    s=readreg(s,4);
+    d=rmw(d,4,4);
+
+    raw_sbb_l(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,sbb_l,(RW4 d, R4 s))
+
+MIDFUNC(2,sbb_w,(RW2 d, R2 s))
+{
+    CLOBBER_SBB;
+    s=readreg(s,2);
+    d=rmw(d,2,2);
+
+    raw_sbb_w(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,sbb_w,(RW2 d, R2 s))
+
+MIDFUNC(2,sbb_b,(RW1 d, R1 s))
+{
+    CLOBBER_SBB;
+    s=readreg(s,1);
+    d=rmw(d,1,1);
+
+    raw_sbb_b(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,sbb_b,(RW1 d, R1 s))
+
+MIDFUNC(2,sub_l,(RW4 d, R4 s))
+{
+    if (isconst(s)) {
+       COMPCALL(sub_l_ri)(d,live.state[s].val);
+       return;
+    }
+
+    CLOBBER_SUB;
+    s=readreg(s,4);
+    d=rmw(d,4,4);
+
+    raw_sub_l(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,sub_l,(RW4 d, R4 s))
+
+MIDFUNC(2,sub_w,(RW2 d, R2 s))
+{
+    if (isconst(s)) {
+       COMPCALL(sub_w_ri)(d,(uae_u16)live.state[s].val);
+       return;
+    }
+
+    CLOBBER_SUB;
+    s=readreg(s,2);
+    d=rmw(d,2,2);
+
+    raw_sub_w(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,sub_w,(RW2 d, R2 s))
+
+MIDFUNC(2,sub_b,(RW1 d, R1 s))
+{
+    if (isconst(s)) {
+       COMPCALL(sub_b_ri)(d,(uae_u8)live.state[s].val);
+       return;
+    }
+
+    CLOBBER_SUB;
+    s=readreg(s,1);
+    d=rmw(d,1,1);
+
+    raw_sub_b(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,sub_b,(RW1 d, R1 s))
+
+MIDFUNC(2,cmp_l,(R4 d, R4 s))
+{
+    CLOBBER_CMP;
+    s=readreg(s,4);
+    d=readreg(d,4);
+
+    raw_cmp_l(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,cmp_l,(R4 d, R4 s))
+
+MIDFUNC(2,cmp_l_ri,(R4 r, IMM i))
+{
+    CLOBBER_CMP;
+    r=readreg(r,4);
+
+    raw_cmp_l_ri(r,i);
+    unlock(r);
+}
+MENDFUNC(2,cmp_l_ri,(R4 r, IMM i))
+
+MIDFUNC(2,cmp_w,(R2 d, R2 s))
+{
+    CLOBBER_CMP;
+    s=readreg(s,2);
+    d=readreg(d,2);
+
+    raw_cmp_w(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,cmp_w,(R2 d, R2 s))
+
+MIDFUNC(2,cmp_b,(R1 d, R1 s))
+{
+    CLOBBER_CMP;
+    s=readreg(s,1);
+    d=readreg(d,1);
+
+    raw_cmp_b(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,cmp_b,(R1 d, R1 s))
+
+
+MIDFUNC(2,xor_l,(RW4 d, R4 s))
+{
+    CLOBBER_XOR;
+    s=readreg(s,4);
+    d=rmw(d,4,4);
+
+    raw_xor_l(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,xor_l,(RW4 d, R4 s))
+
+MIDFUNC(2,xor_w,(RW2 d, R2 s))
+{
+    CLOBBER_XOR;
+    s=readreg(s,2);
+    d=rmw(d,2,2);
+
+    raw_xor_w(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,xor_w,(RW2 d, R2 s))
+
+MIDFUNC(2,xor_b,(RW1 d, R1 s))
+{
+    CLOBBER_XOR;
+    s=readreg(s,1);
+    d=rmw(d,1,1);
+
+    raw_xor_b(d,s);
+    unlock(d);
+    unlock(s);
+}
+MENDFUNC(2,xor_b,(RW1 d, R1 s))
+
+MIDFUNC(5,call_r_11,(W4 out1, R4 r, R4 in1, IMM osize, IMM isize))
+{
+    clobber_flags();
+    remove_all_offsets();
+    if (osize==4) {
+       if (out1!=in1 && out1!=r) {
+           COMPCALL(forget_about)(out1);
+       }
+    }
+    else {
+       tomem_c(out1);
+    }
+
+    in1=readreg_specific(in1,isize,REG_PAR1);
+    r=readreg(r,4);
+    prepare_for_call_1();  /* This should ensure that there won't be
+                             any need for swapping nregs in prepare_for_call_2
+                          */
+#if USE_NORMAL_CALLING_CONVENTION
+    raw_push_l_r(in1);
+#endif
+    unlock(in1);
+    unlock(r);
+
+    prepare_for_call_2();
+    raw_call_r(r);
+
+#if USE_NORMAL_CALLING_CONVENTION
+    raw_inc_sp(4);
+#endif
+
+
+    live.nat[REG_RESULT].holds[0]=out1;
+    live.nat[REG_RESULT].nholds=1;
+    live.nat[REG_RESULT].touched=touchcnt++;
+
+    live.state[out1].realreg=REG_RESULT;
+    live.state[out1].realind=0;
+    live.state[out1].val=0;
+    live.state[out1].validsize=osize;
+    live.state[out1].dirtysize=osize;
+    set_status(out1,DIRTY);
+}
+MENDFUNC(5,call_r_11,(W4 out1, R4 r, R4 in1, IMM osize, IMM isize))
+
+MIDFUNC(5,call_r_02,(R4 r, R4 in1, R4 in2, IMM isize1, IMM isize2))
+{
+    clobber_flags();
+    remove_all_offsets();
+    in1=readreg_specific(in1,isize1,REG_PAR1);
+    in2=readreg_specific(in2,isize2,REG_PAR2);
+    r=readreg(r,4);
+    prepare_for_call_1();  /* This should ensure that there won't be
+                             any need for swapping nregs in prepare_for_call_2
+                          */
+#if USE_NORMAL_CALLING_CONVENTION
+    raw_push_l_r(in2);
+    raw_push_l_r(in1);
+#endif
+    unlock(r);
+    unlock(in1);
+    unlock(in2);
+    prepare_for_call_2();
+    raw_call_r(r);
+#if USE_NORMAL_CALLING_CONVENTION
+    raw_inc_sp(8);
+#endif
+}
+MENDFUNC(5,call_r_02,(R4 r, R4 in1, R4 in2, IMM isize1, IMM isize2))
+
+
+MIDFUNC(1,forget_about,(W4 r))
+{
+    if (isinreg(r))
+       disassociate(r);
+    live.state[r].val=0;
+    set_status(r,UNDEF);
+}
+MENDFUNC(1,forget_about,(W4 r))
+
+MIDFUNC(0,nop,(void))
+{
+    raw_nop();
+}
+MENDFUNC(0,nop,(void))
+
+
+MIDFUNC(1,f_forget_about,(FW r))
+{
+    if (f_isinreg(r))
+       f_disassociate(r);
+    live.fate[r].status=UNDEF;
+}
+MENDFUNC(1,f_forget_about,(FW r))
+
+MIDFUNC(1,fmov_pi,(FW r))
+{
+    r=f_writereg(r);
+    raw_fmov_pi(r);
+    f_unlock(r);
+}
+MENDFUNC(1,fmov_pi,(FW r))
+
+MIDFUNC(1,fmov_log10_2,(FW r))
+{
+    r=f_writereg(r);
+    raw_fmov_log10_2(r);
+    f_unlock(r);
+}
+MENDFUNC(1,fmov_log10_2,(FW r))
+
+MIDFUNC(1,fmov_log2_e,(FW r))
+{
+    r=f_writereg(r);
+    raw_fmov_log2_e(r);
+    f_unlock(r);
+}
+MENDFUNC(1,fmov_log2_e,(FW r))
+
+MIDFUNC(1,fmov_loge_2,(FW r))
+{
+    r=f_writereg(r);
+    raw_fmov_loge_2(r);
+    f_unlock(r);
+}
+MENDFUNC(1,fmov_loge_2,(FW r))
+
+MIDFUNC(1,fmov_1,(FW r))
+{
+    r=f_writereg(r);
+    raw_fmov_1(r);
+    f_unlock(r);
+}
+MENDFUNC(1,fmov_1,(FW r))
+
+MIDFUNC(1,fmov_0,(FW r))
+{
+    r=f_writereg(r);
+    raw_fmov_0(r);
+    f_unlock(r);
+}
+MENDFUNC(1,fmov_0,(FW r))
+
+MIDFUNC(2,fmov_rm,(FW r, MEMR m))
+{
+    r=f_writereg(r);
+    raw_fmov_rm(r,m);
+    f_unlock(r);
+}
+MENDFUNC(2,fmov_rm,(FW r, MEMR m))
+
+MIDFUNC(2,fmovi_rm,(FW r, MEMR m))
+{
+    r=f_writereg(r);
+    raw_fmovi_rm(r,m);
+    f_unlock(r);
+}
+MENDFUNC(2,fmovi_rm,(FW r, MEMR m))
+
+MIDFUNC(2,fmovi_mr,(MEMW m, FR r))
+{
+    r=f_readreg(r);
+    raw_fmovi_mr(m,r);
+    f_unlock(r);
+}
+MENDFUNC(2,fmovi_mr,(MEMW m, FR r))
+
+MIDFUNC(2,fmovs_rm,(FW r, MEMR m))
+{
+    r=f_writereg(r);
+    raw_fmovs_rm(r,m);
+    f_unlock(r);
+}
+MENDFUNC(2,fmovs_rm,(FW r, MEMR m))
+
+MIDFUNC(2,fmovs_mr,(MEMW m, FR r))
+{
+    r=f_readreg(r);
+    raw_fmovs_mr(m,r);
+    f_unlock(r);
+}
+MENDFUNC(2,fmovs_mr,(MEMW m, FR r))
+
+MIDFUNC(2,fmov_ext_mr,(MEMW m, FR r))
+{
+    r=f_readreg(r);
+    raw_fmov_ext_mr(m,r);
+    f_unlock(r);
+}
+MENDFUNC(2,fmov_ext_mr,(MEMW m, FR r))
+
+MIDFUNC(2,fmov_mr,(MEMW m, FR r))
+{
+    r=f_readreg(r);
+    raw_fmov_mr(m,r);
+    f_unlock(r);
+}
+MENDFUNC(2,fmov_mr,(MEMW m, FR r))
+
+MIDFUNC(2,fmov_ext_rm,(FW r, MEMR m))
+{
+    r=f_writereg(r);
+    raw_fmov_ext_rm(r,m);
+    f_unlock(r);
+}
+MENDFUNC(2,fmov_ext_rm,(FW r, MEMR m))
+
+MIDFUNC(2,fmov_rr,(FW d, FR s))
+{
+    if (d==s) { /* How pointless! */
+       return;
+    }
+#if USE_F_ALIAS
+    f_disassociate(d);
+    s=f_readreg(s);
+    live.fate[d].realreg=s;
+    live.fate[d].realind=live.fat[s].nholds;
+    live.fate[d].status=DIRTY;
+    live.fat[s].holds[live.fat[s].nholds]=d;
+    live.fat[s].nholds++;
+    f_unlock(s);
+#else
+    s=f_readreg(s);
+    d=f_writereg(d);
+    raw_fmov_rr(d,s);
+    f_unlock(s);
+    f_unlock(d);
+#endif
+}
+MENDFUNC(2,fmov_rr,(FW d, FR s))
+
+MIDFUNC(2,fldcw_m_indexed,(R4 index, IMM base))
+{
+    index=readreg(index,4);
+
+    raw_fldcw_m_indexed(index,base);
+    unlock(index);
+}
+MENDFUNC(2,fldcw_m_indexed,(R4 index, IMM base))
+
+MIDFUNC(1,ftst_r,(FR r))
+{
+    r=f_readreg(r);
+    raw_ftst_r(r);
+    f_unlock(r);
+}
+MENDFUNC(1,ftst_r,(FR r))
+
+MIDFUNC(0,dont_care_fflags,(void))
+{
+    f_disassociate(FP_RESULT);
+}
+MENDFUNC(0,dont_care_fflags,(void))
+
+MIDFUNC(2,fsqrt_rr,(FW d, FR s))
+{
+    s=f_readreg(s);
+    d=f_writereg(d);
+    raw_fsqrt_rr(d,s);
+    f_unlock(s);
+    f_unlock(d);
+}
+MENDFUNC(2,fsqrt_rr,(FW d, FR s))
+
+MIDFUNC(2,fabs_rr,(FW d, FR s))
+{
+    s=f_readreg(s);
+    d=f_writereg(d);
+    raw_fabs_rr(d,s);
+    f_unlock(s);
+    f_unlock(d);
+}
+MENDFUNC(2,fabs_rr,(FW d, FR s))
+
+MIDFUNC(2,fsin_rr,(FW d, FR s))
+{
+    s=f_readreg(s);
+    d=f_writereg(d);
+    raw_fsin_rr(d,s);
+    f_unlock(s);
+    f_unlock(d);
+}
+MENDFUNC(2,fsin_rr,(FW d, FR s))
+
+MIDFUNC(2,fcos_rr,(FW d, FR s))
+{
+    s=f_readreg(s);
+    d=f_writereg(d);
+    raw_fcos_rr(d,s);
+    f_unlock(s);
+    f_unlock(d);
+}
+MENDFUNC(2,fcos_rr,(FW d, FR s))
+
+MIDFUNC(2,ftwotox_rr,(FW d, FR s))
+{
+    s=f_readreg(s);
+    d=f_writereg(d);
+    raw_ftwotox_rr(d,s);
+    f_unlock(s);
+    f_unlock(d);
+}
+MENDFUNC(2,ftwotox_rr,(FW d, FR s))
+
+MIDFUNC(2,fetox_rr,(FW d, FR s))
+{
+    s=f_readreg(s);
+    d=f_writereg(d);
+    raw_fetox_rr(d,s);
+    f_unlock(s);
+    f_unlock(d);
+}
+MENDFUNC(2,fetox_rr,(FW d, FR s))
+
+MIDFUNC(2,frndint_rr,(FW d, FR s))
+{
+    s=f_readreg(s);
+    d=f_writereg(d);
+    raw_frndint_rr(d,s);
+    f_unlock(s);
+    f_unlock(d);
+}
+MENDFUNC(2,frndint_rr,(FW d, FR s))
+
+MIDFUNC(2,flog2_rr,(FW d, FR s))
+{
+    s=f_readreg(s);
+    d=f_writereg(d);
+    raw_flog2_rr(d,s);
+    f_unlock(s);
+    f_unlock(d);
+}
+MENDFUNC(2,flog2_rr,(FW d, FR s))
+
+MIDFUNC(2,fneg_rr,(FW d, FR s))
+{
+    s=f_readreg(s);
+    d=f_writereg(d);
+    raw_fneg_rr(d,s);
+    f_unlock(s);
+    f_unlock(d);
+}
+MENDFUNC(2,fneg_rr,(FW d, FR s))
+
+MIDFUNC(2,fadd_rr,(FRW d, FR s))
+{
+    s=f_readreg(s);
+    d=f_rmw(d);
+    raw_fadd_rr(d,s);
+    f_unlock(s);
+    f_unlock(d);
+}
+MENDFUNC(2,fadd_rr,(FRW d, FR s))
+
+MIDFUNC(2,fsub_rr,(FRW d, FR s))
+{
+    s=f_readreg(s);
+    d=f_rmw(d);
+    raw_fsub_rr(d,s);
+    f_unlock(s);
+    f_unlock(d);
+}
+MENDFUNC(2,fsub_rr,(FRW d, FR s))
+
+MIDFUNC(2,fcmp_rr,(FR d, FR s))
+{
+    d=f_readreg(d);
+    s=f_readreg(s);
+    raw_fcmp_rr(d,s);
+    f_unlock(s);
+    f_unlock(d);
+}
+MENDFUNC(2,fcmp_rr,(FR d, FR s))
+
+MIDFUNC(2,fdiv_rr,(FRW d, FR s))
+{
+    s=f_readreg(s);
+    d=f_rmw(d);
+    raw_fdiv_rr(d,s);
+    f_unlock(s);
+    f_unlock(d);
+}
+MENDFUNC(2,fdiv_rr,(FRW d, FR s))
+
+MIDFUNC(2,frem_rr,(FRW d, FR s))
+{
+    s=f_readreg(s);
+    d=f_rmw(d);
+    raw_frem_rr(d,s);
+    f_unlock(s);
+    f_unlock(d);
+}
+MENDFUNC(2,frem_rr,(FRW d, FR s))
+
+MIDFUNC(2,frem1_rr,(FRW d, FR s))
+{
+    s=f_readreg(s);
+    d=f_rmw(d);
+    raw_frem1_rr(d,s);
+    f_unlock(s);
+    f_unlock(d);
+}
+MENDFUNC(2,frem1_rr,(FRW d, FR s))
+
+MIDFUNC(2,fmul_rr,(FRW d, FR s))
+{
+    s=f_readreg(s);
+    d=f_rmw(d);
+    raw_fmul_rr(d,s);
+    f_unlock(s);
+    f_unlock(d);
+}
+MENDFUNC(2,fmul_rr,(FRW d, FR s))
+
+
+/********************************************************************
+ * Support functions exposed to gencomp. CREATE time                *
+ ********************************************************************/
+
+int kill_rodent(int r)
+{
+    return KILLTHERAT && 
+        have_rat_stall &&
+       (live.state[r].status==INMEM || 
+        live.state[r].status==CLEAN || 
+        live.state[r].status==ISCONST || 
+        live.state[r].dirtysize==4);
+}
+
+uae_u32 get_const(int r)
+{
+#if USE_OPTIMIZER
+    if (!reg_alloc_run) 
+#endif
+       Dif (!isconst(r)) {
+           printf("Register %d should be constant, but isn't\n",r);
+           abort();
+       }
+    return live.state[r].val;
+}
+
+void sync_m68k_pc(void)
+{
+    if (m68k_pc_offset) {
+       add_l_ri(PC_P,m68k_pc_offset);
+       comp_pc_p+=m68k_pc_offset;
+       m68k_pc_offset=0;
+    }
+}
+    
+/********************************************************************
+ * Support functions exposed to newcpu                              *
+ ********************************************************************/
+
+uae_u32 scratch[VREGS];
+fptype  fscratch[VFREGS];
+
+void init_comp(void)
+{
+    int i;
+    uae_u8* cb=can_byte;
+    uae_u8* cw=can_word;
+    uae_u8* au=always_used;
+
+    for (i=0;i<VREGS;i++) {
+       live.state[i].realreg=-1;
+       live.state[i].needflush=NF_SCRATCH;
+       live.state[i].val=0;
+       set_status(i,UNDEF);
+    }
+
+    for (i=0;i<VFREGS;i++) {
+       live.fate[i].status=UNDEF;
+       live.fate[i].realreg=-1;
+       live.fate[i].needflush=NF_SCRATCH;
+    }
+
+    for (i=0;i<VREGS;i++) {
+       if (i<16) { /* First 16 registers map to 68k registers */
+           live.state[i].mem=((uae_u32*)&regs)+i;
+           live.state[i].needflush=NF_TOMEM;
+           set_status(i,INMEM);
+       }
+       else
+           live.state[i].mem=scratch+i;
+    }
+    live.state[PC_P].mem=(uae_u32*)&(regs.pc_p);
+    live.state[PC_P].needflush=NF_TOMEM;
+    set_const(PC_P,(uae_u32)comp_pc_p);
+
+    live.state[FLAGX].mem=&(regflags.x);
+    live.state[FLAGX].needflush=NF_TOMEM;
+    set_status(FLAGX,INMEM);
+       
+    live.state[FLAGTMP].mem=&(regflags.cznv);
+    live.state[FLAGTMP].needflush=NF_TOMEM;
+    set_status(FLAGTMP,INMEM);
+
+    live.state[NEXT_HANDLER].needflush=NF_HANDLER;
+    set_status(NEXT_HANDLER,UNDEF);
+
+    for (i=0;i<VFREGS;i++) {
+       if (i<8) { /* First 8 registers map to 68k FPU registers */
+           live.fate[i].mem=(uae_u32*)(((fptype*)regs.fp)+i);
+           live.fate[i].needflush=NF_TOMEM;
+           live.fate[i].status=INMEM;
+       }
+       else if (i==FP_RESULT) {
+           live.fate[i].mem=(uae_u32*)(&regs.fp_result);
+           live.fate[i].needflush=NF_TOMEM;
+           live.fate[i].status=INMEM;
+       }
+       else
+           live.fate[i].mem=(uae_u32*)(fscratch+i);
+    }
+
+
+    for (i=0;i<N_REGS;i++) {
+       live.nat[i].touched=0;
+       live.nat[i].nholds=0;
+       live.nat[i].locked=0;
+       if (*cb==i) {
+           live.nat[i].canbyte=1; cb++;
+       } else live.nat[i].canbyte=0;
+       if (*cw==i) {
+           live.nat[i].canword=1; cw++;
+       } else live.nat[i].canword=0;
+       if (*au==i) {
+           live.nat[i].locked=1; au++;
+       }
+    }
+
+    for (i=0;i<N_FREGS;i++) {
+       live.fat[i].touched=0;
+       live.fat[i].nholds=0;
+       live.fat[i].locked=0;
+    }
+    
+    touchcnt=1;
+    m68k_pc_offset=0;
+    live.flags_in_flags=TRASH;
+    live.flags_on_stack=VALID;
+    live.flags_are_important=1;
+
+    raw_fp_init();
+}
+
+
+static void vinton(int i, uae_s8* vton, int depth)
+{
+    int n;
+    int rr;
+
+    Dif (vton[i]==-1) {
+       printf("Asked to load register %d, but nowhere to go\n",i);
+       abort();
+    }
+    n=vton[i];
+    Dif (live.nat[n].nholds>1) 
+       abort();
+    if (live.nat[n].nholds && depth<N_REGS) {
+       vinton(live.nat[n].holds[0],vton,depth+1);
+    }
+    if (!isinreg(i))
+       return;  /* Oops --- got rid of that one in the recursive calls */
+    rr=live.state[i].realreg;
+    if (rr!=n)
+       mov_nregs(n,rr);
+}
+
+#if USE_MATCHSTATE
+/* This is going to be, amongst other things, a more elaborate version of
+   flush() */
+static __inline__ void match_states(smallstate* s)
+{
+    uae_s8 vton[VREGS];
+    uae_s8 ndone[N_REGS];
+    int i;
+    int again=0;
+
+    for (i=0;i<VREGS;i++) 
+       vton[i]=-1;
+
+    for (i=0;i<N_REGS;i++) 
+       if (s->nat[i].validsize) 
+           vton[s->nat[i].holds]=i;
+
+    flush_flags(); /* low level */
+    sync_m68k_pc(); /* mid level */
+    
+    /* We don't do FREGS yet, so this is raw flush() code */
+    for (i=0;i<VFREGS;i++) {
+       if (live.fate[i].needflush==NF_SCRATCH || 
+           live.fate[i].status==CLEAN) {
+           f_disassociate(i);
+       }
+    }
+    for (i=0;i<VFREGS;i++) {
+       if (live.fate[i].needflush==NF_TOMEM && 
+           live.fate[i].status==DIRTY) {
+           f_evict(i);
+       }
+    }
+    raw_fp_cleanup_drop();
+
+    /* Now comes the fun part. First, we need to remove all offsets */
+    for (i=0;i<VREGS;i++)
+       if (!isconst(i) && live.state[i].val)
+           remove_offset(i,-1);
+
+    /* Next, we evict everything that does not end up in registers,
+       write back overly dirty registers, and write back constants */
+    for (i=0;i<VREGS;i++) {
+       switch (live.state[i].status) {
+        case ISCONST:
+           if (i!=PC_P)
+               writeback_const(i);
+           break;
+        case DIRTY:
+           if (vton[i]==-1) {
+               evict(i);
+               break;
+           }
+           if (live.state[i].dirtysize>s->nat[vton[i]].dirtysize)
+               tomem(i);
+           /* Fall-through! */
+        case CLEAN:
+           if (vton[i]==-1 ||
+               live.state[i].validsize<s->nat[vton[i]].validsize)
+               evict(i);
+           else
+               make_exclusive(i,0,-1);
+           break;
+        case INMEM:
+           break;
+        case UNDEF:
+           break;
+        default:
+           printf("Weird status: %d\n",live.state[i].status);
+           abort();
+       }
+    }
+
+    /* Quick consistency check */
+    for (i=0;i<VREGS;i++) {
+       if (isinreg(i)) {
+           int n=live.state[i].realreg;
+           
+           if (live.nat[n].nholds!=1) {
+               printf("Register %d isn't alone in nreg %d\n",
+                      i,n);
+               abort();
+           }
+           if (vton[i]==-1) {
+               printf("Register %d is still in register, shouldn't be\n",
+                      i);
+               abort();
+           }
+       }
+    }
+
+    /* Now we need to shuffle things around so the VREGs are in the
+       right N_REGs. */
+    for (i=0;i<VREGS;i++) {
+       if (isinreg(i) && vton[i]!=live.state[i].realreg)
+           vinton(i,vton,0);
+    }
+    
+    /* And now we may need to load some registers from memory */
+    for (i=0;i<VREGS;i++) {
+       int n=vton[i];
+       if (n==-1) {
+           Dif (isinreg(i)) {
+               printf("Register %d unexpectedly in nreg %d\n",
+                      i,live.state[i].realreg);
+               abort();
+           }
+       }
+       else {
+           switch(live.state[i].status) {
+            case CLEAN:
+            case DIRTY:
+               Dif (n!=live.state[i].realreg)
+                   abort();
+               break;
+            case INMEM:
+               Dif (live.nat[n].nholds) {
+                   printf("natreg %d holds %d vregs, should be empty\n",
+                          n,live.nat[n].nholds);
+               }
+               raw_mov_l_rm(n,(uae_u32)live.state[i].mem);
+               live.state[i].validsize=4;
+               live.state[i].dirtysize=0;
+               live.state[i].realreg=n;
+               live.state[i].realind=0;
+               live.state[i].val=0;
+               live.state[i].is_swapped=0;
+               live.nat[n].nholds=1;
+               live.nat[n].holds[0]=i;
+
+               set_status(i,CLEAN);
+               break;
+            case ISCONST:
+               if (i!=PC_P) {
+                   printf("Got constant in matchstate for reg %d. Bad!\n",i);
+                   abort();
+               }
+               break;
+            case UNDEF:
+               break;
+           }
+       }
+    }
+
+    /* One last consistency check, and adjusting the states in live
+       to those in s */
+    for (i=0;i<VREGS;i++) {
+       int n=vton[i];
+       switch(live.state[i].status) {
+        case INMEM:
+           if (n!=-1)
+               abort();
+           break;
+        case ISCONST:
+           if (i!=PC_P)
+               abort();
+           break;
+        case CLEAN:
+        case DIRTY:
+           if (n==-1)
+               abort();
+           if (live.state[i].dirtysize>s->nat[n].dirtysize)
+               abort;
+           if (live.state[i].validsize<s->nat[n].validsize)
+               abort;
+           live.state[i].dirtysize=s->nat[n].dirtysize;
+           live.state[i].validsize=s->nat[n].validsize;
+           if (live.state[i].dirtysize)
+               set_status(i,DIRTY);
+           break;
+        case UNDEF:
+           break;
+       }
+       if (n!=-1)
+           live.nat[n].touched=touchcnt++;
+    }
+}
+#else
+static __inline__ void match_states(smallstate* s)
+{
+    flush(1);
+}
+#endif
+
+/* Only do this if you really mean it! The next call should be to init!*/
+void flush(int save_regs)
+{
+    int fi,i;
+    
+    log_flush();
+    flush_flags(); /* low level */
+    sync_m68k_pc(); /* mid level */
+
+    if (save_regs) {
+       for (i=0;i<VFREGS;i++) {
+           if (live.fate[i].needflush==NF_SCRATCH || 
+               live.fate[i].status==CLEAN) {
+               f_disassociate(i);
+           }
+       }
+       for (i=0;i<VREGS;i++) {
+           if (live.state[i].needflush==NF_TOMEM) {
+               switch(live.state[i].status) {
+                case INMEM:   
+                   if (live.state[i].val) {
+                       raw_add_l_mi((uae_u32)live.state[i].mem,live.state[i].val);
+                       live.state[i].val=0;
+                   }
+                   break;
+                case CLEAN:   
+                case DIRTY:   
+                   remove_offset(i,-1); tomem(i); break;
+                case ISCONST: 
+                   if (i!=PC_P) 
+                       writeback_const(i); 
+                   break;
+                default: break;
+               }
+               Dif (live.state[i].val && i!=PC_P) {
+                   printf("Register %d still has val %x\n",
+                          i,live.state[i].val);
+               }
+           }
+       }
+       for (i=0;i<VFREGS;i++) {
+           if (live.fate[i].needflush==NF_TOMEM && 
+               live.fate[i].status==DIRTY) {
+               f_evict(i);
+           }
+       }
+       raw_fp_cleanup_drop();
+    }
+    if (needflags) {
+       printf("Warning! flush with needflags=1!\n");
+    }
+
+    lopt_emit_all();
+}
+
+static void flush_keepflags(void)
+{
+    int fi,i;
+    
+    for (i=0;i<VFREGS;i++) {
+       if (live.fate[i].needflush==NF_SCRATCH || 
+           live.fate[i].status==CLEAN) {
+           f_disassociate(i);
+       }
+    }
+    for (i=0;i<VREGS;i++) {
+       if (live.state[i].needflush==NF_TOMEM) {
+           switch(live.state[i].status) {
+            case INMEM:   
+               /* Can't adjust the offset here --- that needs "add" */
+               break;
+            case CLEAN:   
+            case DIRTY:   
+               remove_offset(i,-1); tomem(i); break;
+            case ISCONST: 
+               if (i!=PC_P) 
+                   writeback_const(i); 
+               break;
+            default: break;
+           }
+       }
+    }
+    for (i=0;i<VFREGS;i++) {
+       if (live.fate[i].needflush==NF_TOMEM && 
+           live.fate[i].status==DIRTY) {
+           f_evict(i);
+       }
+    }
+    raw_fp_cleanup_drop();
+    lopt_emit_all();
+}
+
+void freescratch(void)
+{
+    int i;
+    for (i=0;i<N_REGS;i++)
+       if (live.nat[i].locked && i!=4)
+           printf("Warning! %d is locked\n",i);
+
+    for (i=0;i<VREGS;i++)
+       if (live.state[i].needflush==NF_SCRATCH) {
+           forget_about(i);
+       }
+
+    for (i=0;i<VFREGS;i++)
+       if (live.fate[i].needflush==NF_SCRATCH) {
+           f_forget_about(i);
+       }
+}
+
+/********************************************************************
+ * Support functions, internal                                      *
+ ********************************************************************/
+
+
+static void align_target(uae_u32 a)
+{
+    lopt_emit_all();
+    /* Fill with NOPs --- makes debugging with gdb easier */
+    while ((uae_u32)target&(a-1)) 
+       *target++=0x90;
+}
+
+extern uae_u8* kickmemory;
+static __inline__ int isinrom(uae_u32 addr)
+{
+    return (addr>=(uae_u32)kickmemory &&
+           addr<(uae_u32)kickmemory+8*65536);
+}
+
+static void flush_all(void)
+{
+    int i;
+
+    log_flush();
+    for (i=0;i<VREGS;i++)
+       if (live.state[i].status==DIRTY) {
+           if (!call_saved[live.state[i].realreg]) {
+               tomem(i);
+           }
+       }
+    for (i=0;i<VFREGS;i++)
+       if (f_isinreg(i)) 
+           f_evict(i);
+    raw_fp_cleanup_drop();
+}
+
+/* Make sure all registers that will get clobbered by a call are
+   save and sound in memory */
+static void prepare_for_call_1(void)
+{
+    flush_all();  /* If there are registers that don't get clobbered,
+                  * we should be a bit more selective here */
+}
+
+/* We will call a C routine in a moment. That will clobber all registers,
+   so we need to disassociate everything */
+static void prepare_for_call_2(void)
+{
+    int i;
+    for (i=0;i<N_REGS;i++)   
+       if (!call_saved[i] && live.nat[i].nholds>0)
+           free_nreg(i);
+
+    for (i=0;i<N_FREGS;i++)   
+       if (live.fat[i].nholds>0)
+           f_free_nreg(i);
+
+    live.flags_in_flags=TRASH;  /* Note: We assume we already rescued the
+                                  flags at the very start of the call_r
+                                  functions! */
+}
+
+
+/********************************************************************
+ * Memory access and related functions, CREATE time                 *
+ ********************************************************************/
+
+void register_branch(uae_u32 not_taken, uae_u32 taken, uae_u8 cond)
+{
+    next_pc_p=not_taken;
+    taken_pc_p=taken;
+    branch_cc=cond;
+}
+
+
+static uae_u32 get_handler_address(uae_u32 addr)
+{
+    uae_u32 cl=cacheline(addr);
+    blockinfo* bi=get_blockinfo_addr_new((void*)addr,0);
+
+#if USE_OPTIMIZER
+    if (!bi && reg_alloc_run)
+       return 0;
+#endif
+    return (uae_u32)&(bi->direct_handler_to_use);
+}
+
+static uae_u32 get_handler(uae_u32 addr)
+{
+    uae_u32 cl=cacheline(addr);
+    blockinfo* bi=get_blockinfo_addr_new((void*)addr,0);
+
+#if USE_OPTIMIZER
+    if (!bi && reg_alloc_run)
+       return 0;
+#endif
+    return (uae_u32)bi->direct_handler_to_use;
+}
+
+static void load_handler(int reg, uae_u32 addr)
+{
+    mov_l_rm(reg,get_handler_address(addr));
+}
+
+/* This version assumes that it is writing *real* memory, and *will* fail
+ *  if that assumption is wrong! No branches, no second chances, just
+ *  straight go-for-it attitude */
+
+static void writemem_real(int address, int source, int offset, int size, int tmp, int clobber)
+{
+    int f=tmp;
+
+#ifdef NATMEM_OFFSET
+    if (canbang) {  /* Woohoo! go directly at the memory! */
+       if (clobber)
+           f=source;
+       switch(size) {
+        case 1: mov_b_bRr(address,source,NATMEM_OFFSET); break; 
+        case 2: mov_w_rr(f,source); bswap_16(f); mov_w_bRr(address,f,NATMEM_OFFSET); break;
+        case 4: mov_l_rr(f,source); bswap_32(f); mov_l_bRr(address,f,NATMEM_OFFSET); break;
+       }
+       forget_about(tmp);
+       forget_about(f);
+       return;
+    }
+#endif
+
+    mov_l_rr(f,address);
+    shrl_l_ri(f,16);   /* The index into the baseaddr table */
+    mov_l_rm_indexed(f,(uae_u32)(baseaddr),f,4);
+
+    if (address==source && size>1) { /* IBrowse does this! */
+       add_l(f,address); /* f now has the final address */
+       switch(size) {
+        case 2: bswap_16(source); mov_w_Rr(f,source,0); bswap_16(source); break;
+        case 4: bswap_32(source); mov_l_Rr(f,source,0); bswap_32(source); break;
+       }
+    }
+    else {
+       /* f now holds the offset */
+       switch(size) {
+        case 1: mov_b_mrr_indexed(address,f,1,source); break;
+        case 2: bswap_16(source); mov_w_mrr_indexed(address,f,1,source); bswap_16(source); break;
+        case 4: bswap_32(source); mov_l_mrr_indexed(address,f,1,source); bswap_32(source); break;
+       }
+    }
+}
+
+
+
+static __inline__ void writemem(int address, int source, int offset, int size, int tmp)
+{
+    int f=tmp;
+
+    mov_l_rr(f,address);
+    shrl_l_ri(f,16);   /* The index into the mem bank table */
+    mov_l_rm_indexed(f,(uae_u32)mem_banks,f,4);
+    /* Now f holds a pointer to the actual membank */
+    mov_l_rR(f,f,offset);
+    /* Now f holds the address of the b/w/lput function */
+    call_r_02(f,address,source,4,size);
+    forget_about(tmp);
+}
+
+
+void writebyte(int address, int source, int tmp)
+{
+    int  distrust;
+    switch (currprefs.comptrustbyte) {
+     case 0: distrust=0; break;
+     case 1: distrust=1; break;
+     case 2: distrust=((start_pc&0xF80000)==0xF80000); break;
+     case 3: distrust=!have_done_picasso; break;
+     default: abort();
+    }
+
+    if ((special_mem&S_WRITE) || distrust)
+       writemem_special(address,source,20,1,tmp);
+    else
+       writemem_real(address,source,20,1,tmp,0);
+}
+
+static __inline__ void writeword_general(int address, int source, int tmp,
+                                        int clobber)
+{
+    int  distrust;
+    switch (currprefs.comptrustword) {
+     case 0: distrust=0; break;
+     case 1: distrust=1; break;
+     case 2: distrust=((start_pc&0xF80000)==0xF80000); break;
+     case 3: distrust=!have_done_picasso; break;
+     default: abort();
+    }
+
+    if ((special_mem&S_WRITE) || distrust)
+       writemem_special(address,source,16,2,tmp);
+    else
+       writemem_real(address,source,16,2,tmp,clobber);
+}
+
+void writeword_clobber(int address, int source, int tmp)
+{
+    writeword_general(address,source,tmp,1);
+}
+
+void writeword(int address, int source, int tmp)
+{
+    writeword_general(address,source,tmp,0);
+}
+
+static __inline__ void writelong_general(int address, int source, int tmp, 
+                                        int clobber)
+{
+    int  distrust;
+    switch (currprefs.comptrustlong) {
+     case 0: distrust=0; break;
+     case 1: distrust=1; break;
+     case 2: distrust=((start_pc&0xF80000)==0xF80000); break;
+     case 3: distrust=!have_done_picasso; break;
+     default: abort();
+    }
+
+    if ((special_mem&S_WRITE) || distrust)
+       writemem_special(address,source,12,4,tmp);
+    else
+       writemem_real(address,source,12,4,tmp,clobber);
+}
+
+void writelong_clobber(int address, int source, int tmp)
+{
+    writelong_general(address,source,tmp,1);
+}
+
+void writelong(int address, int source, int tmp)
+{
+    writelong_general(address,source,tmp,0);
+}
+
+
+
+/* This version assumes that it is reading *real* memory, and *will* fail
+ *  if that assumption is wrong! No branches, no second chances, just
+ *  straight go-for-it attitude */
+
+static void readmem_real(int address, int dest, int offset, int size, int tmp)
+{
+    int f=tmp; 
+
+    if (size==4 && address!=dest)
+       f=dest;
+
+#ifdef NATMEM_OFFSET
+    if (canbang) {  /* Woohoo! go directly at the memory! */
+       switch(size) {
+        case 1: mov_b_brR(dest,address,NATMEM_OFFSET); break; 
+        case 2: mov_w_brR(dest,address,NATMEM_OFFSET); bswap_16(dest); break;
+        case 4: mov_l_brR(dest,address,NATMEM_OFFSET); bswap_32(dest); break;
+       }
+       forget_about(tmp);
+       return;
+    }
+#endif
+
+    mov_l_rr(f,address);
+    shrl_l_ri(f,16);   /* The index into the baseaddr table */
+    mov_l_rm_indexed(f,(uae_u32)baseaddr,f,4);
+    /* f now holds the offset */
+  
+    switch(size) {
+     case 1: mov_b_rrm_indexed(dest,address,f,1); break;
+     case 2: mov_w_rrm_indexed(dest,address,f,1); bswap_16(dest); break;
+     case 4: mov_l_rrm_indexed(dest,address,f,1); bswap_32(dest); break;
+    }
+    forget_about(tmp);
+}
+
+
+
+static __inline__ void readmem(int address, int dest, int offset, int size, int tmp)
+{
+    int f=tmp;
+
+    mov_l_rr(f,address);
+    shrl_l_ri(f,16);   /* The index into the mem bank table */
+    mov_l_rm_indexed(f,(uae_u32)mem_banks,f,4);
+    /* Now f holds a pointer to the actual membank */
+    mov_l_rR(f,f,offset);
+    /* Now f holds the address of the b/w/lget function */
+    call_r_11(dest,f,address,size,4);
+    forget_about(tmp);
+}
+
+void readbyte(int address, int dest, int tmp)
+{
+    int  distrust;
+    switch (currprefs.comptrustbyte) {
+     case 0: distrust=0; break;
+     case 1: distrust=1; break;
+     case 2: distrust=((start_pc&0xF80000)==0xF80000); break;
+     case 3: distrust=!have_done_picasso; break;
+     default: abort();
+    }
+
+    if ((special_mem&S_READ) || distrust)
+       readmem_special(address,dest,8,1,tmp);
+    else
+       readmem_real(address,dest,8,1,tmp);
+}
+
+void readword(int address, int dest, int tmp)
+{
+    int  distrust;
+    switch (currprefs.comptrustword) {
+     case 0: distrust=0; break;
+     case 1: distrust=1; break;
+     case 2: distrust=((start_pc&0xF80000)==0xF80000); break;
+     case 3: distrust=!have_done_picasso; break;
+     default: abort();
+    }
+
+    if ((special_mem&S_READ) || distrust)
+       readmem_special(address,dest,4,2,tmp);
+    else
+       readmem_real(address,dest,4,2,tmp);
+}
+
+void readlong(int address, int dest, int tmp)
+{
+    int  distrust;
+    switch (currprefs.comptrustlong) {
+     case 0: distrust=0; break;
+     case 1: distrust=1; break;
+     case 2: distrust=((start_pc&0xF80000)==0xF80000); break;
+     case 3: distrust=!have_done_picasso; break;
+     default: abort();
+    }
+
+    if ((special_mem&S_READ) || distrust)
+       readmem_special(address,dest,0,4,tmp);
+    else
+       readmem_real(address,dest,0,4,tmp);
+}
+
+
+
+/* This one might appear a bit odd... */
+static __inline__ void get_n_addr_old(int address, int dest, int tmp)
+{
+    readmem(address,dest,24,4,tmp);
+}
+
+static __inline__ void get_n_addr_real(int address, int dest, int tmp)
+{
+    int f=tmp;
+    if (address!=dest)
+       f=dest;
+
+#ifdef NATMEM_OFFSET
+    if (canbang) {
+       lea_l_brr(dest,address,NATMEM_OFFSET);
+       forget_about(tmp);
+       return;
+    }
+#endif
+    mov_l_rr(f,address);
+    mov_l_rr(dest,address); // gb-- nop if dest==address
+    shrl_l_ri(f,16);
+    mov_l_rm_indexed(f, (uae_u32)baseaddr, f, 4);
+    add_l(dest,f);
+    forget_about(tmp);
+}
+
+void get_n_addr(int address, int dest, int tmp)
+{
+    int  distrust;
+    switch (currprefs.comptrustnaddr) {
+     case 0: distrust=0; break;
+     case 1: distrust=1; break;
+     case 2: distrust=((start_pc&0xF80000)==0xF80000); break;
+     case 3: distrust=!have_done_picasso; break;
+     default: abort();
+    }
+
+    if (special_mem || distrust)
+       get_n_addr_old(address,dest,tmp);
+    else
+       get_n_addr_real(address,dest,tmp);
+}
+
+void get_n_addr_jmp(int address, int dest, int tmp)
+{
+#if 0 /* For this, we need to get the same address as the rest of UAE
+        would --- otherwise we end up translating everything twice */
+    get_n_addr(address,dest,tmp);
+#else
+    int f=tmp;
+    if (address!=dest)
+       f=dest;
+    mov_l_rr(f,address);
+    shrl_l_ri(f,16);   /* The index into the baseaddr bank table */
+    mov_l_rm_indexed(dest,(uae_u32)baseaddr,f,4);
+    add_l(dest,address);
+    and_l_ri (dest, ~1);
+    forget_about(tmp);
+#endif
+}
+
+
+/* base is a register, but dp is an actual value. 
+   target is a register, as is tmp */
+void calc_disp_ea_020(int base, uae_u32 dp, int target, int tmp)
+{
+    int reg = (dp >> 12) & 15;
+    int regd_shift=(dp >> 9) & 3;
+
+    if (dp & 0x100) {
+       int ignorebase=(dp&0x80);
+       int ignorereg=(dp&0x40);
+       int addbase=0;
+       int outer=0;
+    
+       if ((dp & 0x30) == 0x20) addbase = (uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
+       if ((dp & 0x30) == 0x30) addbase = comp_get_ilong((m68k_pc_offset+=4)-4);
+
+       if ((dp & 0x3) == 0x2) outer = (uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
+       if ((dp & 0x3) == 0x3) outer = comp_get_ilong((m68k_pc_offset+=4)-4);
+
+       if ((dp & 0x4) == 0) {  /* add regd *before* the get_long */
+           if (!ignorereg) {
+               if ((dp & 0x800) == 0) 
+                   sign_extend_16_rr(target,reg);
+               else
+                   mov_l_rr(target,reg);
+               shll_l_ri(target,regd_shift);
+           }
+           else
+               mov_l_ri(target,0);
+
+           /* target is now regd */
+           if (!ignorebase)
+               add_l(target,base);
+           add_l_ri(target,addbase);
+           if (dp&0x03) readlong(target,target,tmp);
+       } else { /* do the getlong first, then add regd */
+           if (!ignorebase) {
+               mov_l_rr(target,base);
+               add_l_ri(target,addbase);
+           }
+           else
+               mov_l_ri(target,addbase);
+           if (dp&0x03) readlong(target,target,tmp);
+
+           if (!ignorereg) {
+               if ((dp & 0x800) == 0) 
+                   sign_extend_16_rr(tmp,reg);
+               else
+                   mov_l_rr(tmp,reg);
+               shll_l_ri(tmp,regd_shift);
+               /* tmp is now regd */
+               add_l(target,tmp);
+           }
+       }
+       add_l_ri(target,outer);
+    }
+    else { /* 68000 version */
+       if ((dp & 0x800) == 0) { /* Sign extend */
+           sign_extend_16_rr(target,reg);
+           lea_l_brr_indexed(target,base,target,1<<regd_shift,(uae_s32)((uae_s8)dp));
+       }
+       else {
+           lea_l_brr_indexed(target,base,reg,1<<regd_shift,(uae_s32)((uae_s8)dp));
+       }
+    }
+    forget_about(tmp);
+}
+
+static __inline__ unsigned int cft_map (unsigned int f)
+{
+    return ((f >> 8) & 255) | ((f & 255) << 8);
+}
+
+void set_cache_state(int enabled)
+{
+    if (enabled!=letit)
+       flush_icache_hard(77);
+    letit=enabled;
+}
+
+int get_cache_state(void)
+{
+    return letit;
+}
+
+uae_u32 get_jitted_size(void)
+{
+    if (compiled_code)
+       return current_compile_p-compiled_code;
+    return 0;
+}
+
+void alloc_cache(void)
+{
+    if (compiled_code) {
+       flush_icache_hard(6);
+       cache_free(compiled_code);
+       cache_free(popallspace);
+       cache_free(veccode);
+    }
+    popallspace = NULL;
+    compiled_code=NULL;
+    veccode=NULL;
+    if (currprefs.cachesize==0)
+       return;
+
+    while (!compiled_code && currprefs.cachesize) {
+       compiled_code=cache_alloc(currprefs.cachesize*1024);
+       if (!compiled_code)
+           currprefs.cachesize/=2;
+    }
+    if (compiled_code) {
+       max_compile_start=compiled_code+currprefs.cachesize*1024-BYTES_PER_INST;
+       current_compile_p=compiled_code;
+    }
+    veccode = cache_alloc (256);
+}
+
+extern unsigned long op_illg_1 (uae_u32 opcode) REGPARAM;
+
+static void calc_checksum(blockinfo* bi, uae_u32* c1, uae_u32* c2)
+{
+    uae_u32 k1=0;
+    uae_u32 k2=0;
+    uae_s32 len=bi->len;
+    uae_u32 tmp=bi->min_pcp;
+    uae_u32* pos;
+
+    len+=(tmp&3);
+    tmp&=(~3);
+    pos=(uae_u32*)tmp;
+
+    if (len<0 || len>MAX_CHECKSUM_LEN) { 
+       *c1=0;
+       *c2=0;
+    }
+    else {
+       while (len>0) {
+           k1+=*pos;
+           k2^=*pos;
+           pos++;
+           len-=4;
+       }
+       *c1=k1;
+       *c2=k2;
+    }
+}
+
+static void show_checksum(blockinfo* bi)
+{
+    uae_u32 k1=0;
+    uae_u32 k2=0;
+    uae_s32 len=bi->len;
+    uae_u32 tmp=(uae_u32)bi->pc_p;
+    uae_u32* pos;
+
+    len+=(tmp&3);
+    tmp&=(~3);
+    pos=(uae_u32*)tmp;
+
+    if (len<0 || len>MAX_CHECKSUM_LEN) {
+       return;
+    }
+    else {
+       while (len>0) {
+           printf("%08x ",*pos);
+           pos++;
+           len-=4;
+       }
+       printf(" bla\n");
+    }
+}
+
+
+int check_for_cache_miss(void)
+{
+    blockinfo* bi=get_blockinfo_addr(regs.pc_p);
+    
+    if (bi) {
+       int cl=cacheline(regs.pc_p);
+       if (bi!=cache_tags[cl+1].bi) {
+           raise_in_cl_list(bi);
+           return 1;
+       }
+    }
+    return 0;
+}
+
+    
+static void recompile_block(void)
+{
+    /* An existing block's countdown code has expired. We need to make
+       sure that execute_normal doesn't refuse to recompile due to a
+       perceived cache miss... */
+    blockinfo*  bi=get_blockinfo_addr(regs.pc_p);
+
+    Dif (!bi) 
+       abort();
+    raise_in_cl_list(bi);
+    execute_normal();
+    return;
+}
+
+static void cache_miss(void)
+{
+    blockinfo*  bi=get_blockinfo_addr(regs.pc_p);
+    uae_u32     cl=cacheline(regs.pc_p);
+    blockinfo*  bi2=get_blockinfo(cl);
+
+    if (!bi) {
+       execute_normal(); /* Compile this block now */
+       return;
+    }
+    Dif (!bi2 || bi==bi2) {
+       fprintf(stderr,"Unexplained cache miss %p %p\n",bi,bi2);
+       abort();
+    }
+    raise_in_cl_list(bi);
+    return;
+}
+
+static void check_checksum(void) 
+{
+    blockinfo*  bi=get_blockinfo_addr(regs.pc_p);
+    uae_u32     cl=cacheline(regs.pc_p);
+    blockinfo*  bi2=get_blockinfo(cl);
+
+    uae_u32     c1,c2;
+    
+    checksum_count++;
+    /* These are not the droids you are looking for...  */
+    if (!bi) {
+       /* Whoever is the primary target is in a dormant state, but
+          calling it was accidental, and we should just compile this
+          new block */
+       execute_normal();
+       return;
+    }
+    if (bi!=bi2) {
+       /* The block was hit accidentally, but it does exist. Cache miss */
+       cache_miss();
+       return;
+    }
+
+    if (bi->c1 || bi->c2)
+       calc_checksum(bi,&c1,&c2);
+    else {
+       c1=c2=1;  /* Make sure it doesn't match */
+    }
+    if (c1==bi->c1 && c2==bi->c2) { 
+       /* This block is still OK. So we reactivate. Of course, that
+          means we have to move it into the needs-to-be-flushed list */
+       bi->handler_to_use=bi->handler;
+       set_dhtu(bi,bi->direct_handler);
+
+       /*      printf("reactivate %p/%p (%x %x/%x %x)\n",bi,bi->pc_p,
+               c1,c2,bi->c1,bi->c2);*/
+       remove_from_list(bi);
+       add_to_active(bi);
+       raise_in_cl_list(bi);
+    }
+    else {
+       /* This block actually changed. We need to invalidate it,
+          and set it up to be recompiled */
+       /* printf("discard %p/%p (%x %x/%x %x)\n",bi,bi->pc_p,
+          c1,c2,bi->c1,bi->c2); */
+       invalidate_block(bi);
+       raise_in_cl_list(bi);
+       execute_normal();
+    }
+}
+
+
+static __inline__ void create_popalls(void)
+{
+  int i,r;
+
+  popallspace = cache_alloc (1024);
+  current_compile_p=popallspace;
+  set_target(current_compile_p);
+#if USE_PUSH_POP
+  /* If we can't use gcc inline assembly, we need to pop some
+     registers before jumping back to the various get-out routines.
+     This generates the code for it.
+  */
+  popall_do_nothing=current_compile_p;
+  for (i=0;i<N_REGS;i++) {
+      if (need_to_preserve[i])
+         raw_pop_l_r(i);
+  }
+  raw_jmp((uae_u32)do_nothing);
+  align_target(32);
+  
+  popall_execute_normal=get_target();
+  for (i=0;i<N_REGS;i++) {
+      if (need_to_preserve[i])
+         raw_pop_l_r(i);
+  }
+  raw_jmp((uae_u32)execute_normal);
+  align_target(32);
+
+  popall_cache_miss=get_target();
+  for (i=0;i<N_REGS;i++) {
+      if (need_to_preserve[i])
+         raw_pop_l_r(i);
+  }
+  raw_jmp((uae_u32)cache_miss);
+  align_target(32);
+
+  popall_recompile_block=get_target();
+  for (i=0;i<N_REGS;i++) {
+      if (need_to_preserve[i])
+         raw_pop_l_r(i);
+  }
+  raw_jmp((uae_u32)recompile_block);
+  align_target(32);
+  
+  popall_exec_nostats=get_target();
+  for (i=0;i<N_REGS;i++) {
+      if (need_to_preserve[i])
+         raw_pop_l_r(i);
+  }
+  raw_jmp((uae_u32)exec_nostats);
+  align_target(32);
+  
+  popall_check_checksum=get_target();
+  for (i=0;i<N_REGS;i++) {
+      if (need_to_preserve[i])
+         raw_pop_l_r(i);
+  }
+  raw_jmp((uae_u32)check_checksum);
+  align_target(32);
+  
+  current_compile_p=get_target();
+#else
+  popall_exec_nostats=exec_nostats;
+  popall_execute_normal=execute_normal;
+  popall_cache_miss=cache_miss;
+  popall_recompile_block=recompile_block;
+  popall_do_nothing=do_nothing;
+  popall_check_checksum=check_checksum;
+#endif
+
+  /* And now, the code to do the matching pushes and then jump
+     into a handler routine */
+  pushall_call_handler=get_target();
+#if USE_PUSH_POP
+  for (i=N_REGS;i--;) {
+      if (need_to_preserve[i])
+         raw_push_l_r(i);
+  }
+#endif
+  r=REG_PC_TMP;
+  raw_mov_l_rm(r,(uae_u32)&regs.pc_p);
+  raw_and_l_ri(r,TAGMASK);
+  raw_jmp_m_indexed((uae_u32)cache_tags,r,4);
+}
+
+static __inline__ void reset_lists(void)
+{
+    int i;
+    
+    for (i=0;i<MAX_HOLD_BI;i++)
+       hold_bi[i]=NULL;
+    active=NULL;
+    dormant=NULL;
+}
+
+static void prepare_block(blockinfo* bi)
+{
+    int i;
+
+    set_target(current_compile_p);
+    align_target(32);
+    bi->direct_pen=(void*)get_target();
+    raw_mov_l_rm(0,(uae_u32)&(bi->pc_p));
+    raw_mov_l_mr((uae_u32)&regs.pc_p,0);
+    raw_jmp((uae_u32)popall_execute_normal);
+
+    align_target(32);
+    bi->direct_pcc=(void*)get_target();
+    raw_mov_l_rm(0,(uae_u32)&(bi->pc_p));
+    raw_mov_l_mr((uae_u32)&regs.pc_p,0);
+    raw_jmp((uae_u32)popall_check_checksum);
+
+    align_target(32);
+    current_compile_p=get_target();
+
+    bi->deplist=NULL;
+    for (i=0;i<2;i++) {
+       bi->dep[i].prev_p=NULL;
+       bi->dep[i].next=NULL;
+    }
+    bi->env=default_ss;
+    bi->status=BI_NEW;
+    bi->havestate=0;
+    //bi->env=empty_ss;
+}
+
+void compemu_reset(void)
+{
+    int i;
+
+    set_cache_state(0);
+}
+
+void build_comp(void) 
+{
+    int i;
+    int jumpcount=0;
+    unsigned long opcode;
+    struct cputbl* tbl=op_smalltbl_0_comp_ff;
+    struct cputbl* nftbl=op_smalltbl_0_comp_nf;
+    int count;
+#ifdef NOFLAGS_SUPPORT
+    struct cputbl *nfctbl = (currprefs.cpu_level >= 4 ? op_smalltbl_0_nf
+                            : currprefs.cpu_level == 3 ? op_smalltbl_1_nf
+                            : currprefs.cpu_level == 2 ? op_smalltbl_2_nf
+                            : currprefs.cpu_level == 1 ? op_smalltbl_3_nf
+                            : ! currprefs.cpu_compatible ? op_smalltbl_4_nf
+                            : op_smalltbl_5_nf);
+#endif
+    raw_init_cpu();
+#ifdef NATMEM_OFFSET
+    write_log ("JIT: Setting signal handler\n");
+#ifndef _WIN32
+    signal(SIGSEGV,vec);
+#endif
+#endif
+    write_log ("JIT: Building Compiler function table\n");
+    for (opcode = 0; opcode < 65536; opcode++) {
+#ifdef NOFLAGS_SUPPORT
+       nfcpufunctbl[opcode] = op_illg_1;
+#endif
+       compfunctbl[opcode] = NULL;
+       nfcompfunctbl[opcode] = NULL;
+       prop[opcode].use_flags = 0x1f;
+       prop[opcode].set_flags = 0x1f;
+       prop[opcode].is_jump=1;
+    }
+
+    for (i = 0; tbl[i].opcode < 65536; i++) {
+       int isjmp=(tbl[i].specific&1);
+       int isaddx=(tbl[i].specific&8);
+       int iscjmp=(tbl[i].specific&16);
+
+       prop[tbl[i].opcode].is_jump=isjmp;
+       prop[tbl[i].opcode].is_const_jump=iscjmp;
+       prop[tbl[i].opcode].is_addx=isaddx;
+       compfunctbl[tbl[i].opcode] = tbl[i].handler;
+    }
+    for (i = 0; nftbl[i].opcode < 65536; i++) {
+       nfcompfunctbl[nftbl[i].opcode] = nftbl[i].handler;
+#ifdef NOFLAGS_SUPPORT
+       nfcpufunctbl[nftbl[i].opcode] = nfctbl[i].handler;
+#endif
+    }
+
+#ifdef NOFLAGS_SUPPORT
+    for (i = 0; nfctbl[i].handler; i++) {
+       nfcpufunctbl[nfctbl[i].opcode] = nfctbl[i].handler;
+    }
+#endif
+
+    for (opcode = 0; opcode < 65536; opcode++) {
+       cpuop_func *f;
+       cpuop_func *nff;
+#ifdef NOFLAGS_SUPPORT
+       cpuop_func *nfcf;
+#endif
+       int isjmp,isaddx,iscjmp;
+
+       if (table68k[opcode].mnemo == i_ILLG || table68k[opcode].clev > currprefs.cpu_level)
+           continue;
+
+       if (table68k[opcode].handler != -1) {
+           f = compfunctbl[table68k[opcode].handler];
+           nff = nfcompfunctbl[table68k[opcode].handler];
+#ifdef NOFLAGS_SUPPORT
+           nfcf = nfcpufunctbl[table68k[opcode].handler];
+#endif
+           isjmp=prop[table68k[opcode].handler].is_jump;
+           iscjmp=prop[table68k[opcode].handler].is_const_jump;
+           isaddx=prop[table68k[opcode].handler].is_addx;
+           prop[opcode].is_jump=isjmp;
+           prop[opcode].is_const_jump=iscjmp;
+           prop[opcode].is_addx=isaddx;
+           compfunctbl[opcode] = f;
+           nfcompfunctbl[opcode] = nff;
+#ifdef NOFLAGS_SUPPORT
+           Dif (nfcf == op_illg_1)
+               abort();
+           nfcpufunctbl[opcode] = nfcf;
+#endif
+       }
+       prop[opcode].set_flags =table68k[opcode].flagdead;
+       prop[opcode].use_flags =table68k[opcode].flaglive;
+       /* Unconditional jumps don't evaluate condition codes, so they
+          don't actually use any flags themselves */
+       if (prop[opcode].is_const_jump)
+           prop[opcode].use_flags=0; 
+    }
+#ifdef NOFLAGS_SUPPORT
+    for (i = 0; nfctbl[i].handler != NULL; i++) {
+       if (nfctbl[i].specific)
+           nfcpufunctbl[tbl[i].opcode] = nfctbl[i].handler;
+    }
+#endif
+
+    count=0;
+    for (opcode = 0; opcode < 65536; opcode++) {
+       if (compfunctbl[opcode])
+           count++;
+    }
+    fprintf(stderr,"Supposedly %d compileable opcodes!\n",count);
+
+    /* Initialise state */
+    create_popalls();
+    alloc_cache();
+    reset_lists();
+
+    for (i=0;i<TAGSIZE;i+=2) {
+       cache_tags[i].handler=(void*)popall_execute_normal;
+       cache_tags[i+1].bi=NULL;
+    }
+    compemu_reset();
+    
+    for (i=0;i<N_REGS;i++) {
+       empty_ss.nat[i].holds=-1;
+       empty_ss.nat[i].validsize=0;
+       empty_ss.nat[i].dirtysize=0;
+    }
+    default_ss=empty_ss;
+#if 0    
+    default_ss.nat[6].holds=11;
+    default_ss.nat[6].validsize=4;
+    default_ss.nat[5].holds=12;
+    default_ss.nat[5].validsize=4;
+#endif
+}
+
+    
+static void flush_icache_hard(int n)
+{
+    uae_u32 i;
+    blockinfo* bi;
+
+    hard_flush_count++;
+#if 0
+    printf("Flush Icache_hard(%d/%x/%p), %u instruction bytes\n",
+          n,regs.pc,regs.pc_p,current_compile_p-compiled_code);
+#endif
+    bi=active;
+    while(bi) {
+       cache_tags[cacheline(bi->pc_p)].handler=(void*)popall_execute_normal;
+       cache_tags[cacheline(bi->pc_p)+1].bi=NULL;
+       bi=bi->next;
+    }
+    bi=dormant;
+    while(bi) {
+       cache_tags[cacheline(bi->pc_p)].handler=(void*)popall_execute_normal;
+       cache_tags[cacheline(bi->pc_p)+1].bi=NULL;
+       bi=bi->next;
+    }
+
+    reset_lists();
+    if (!compiled_code)
+       return;
+    current_compile_p=compiled_code;
+    set_special(0); /* To get out of compiled code */
+}
+
+
+/* "Soft flushing" --- instead of actually throwing everything away,
+   we simply mark everything as "needs to be checked". 
+*/
+
+void flush_icache(int n)
+{
+    uae_u32 i;
+    blockinfo* bi;
+    blockinfo* bi2;
+
+    if (currprefs.comp_hardflush) {
+       flush_icache_hard(n);
+       return;
+    }
+    soft_flush_count++;
+    if (!active)
+       return;
+
+    bi=active;
+    while (bi) {
+       uae_u32 cl=cacheline(bi->pc_p);
+       if (!bi->handler) { 
+           /* invalidated block */
+           if (bi==cache_tags[cl+1].bi) 
+               cache_tags[cl].handler=popall_execute_normal;
+           bi->handler_to_use=popall_execute_normal;
+           set_dhtu(bi,bi->direct_pen);
+       }
+       else {
+           if (bi==cache_tags[cl+1].bi) 
+               cache_tags[cl].handler=popall_check_checksum;
+           bi->handler_to_use=popall_check_checksum;
+           set_dhtu(bi,bi->direct_pcc);
+       }
+       bi2=bi;
+       bi=bi->next;
+    }
+    /* bi2 is now the last entry in the active list */
+    bi2->next=dormant;
+    if (dormant)
+       dormant->prev_p=&(bi2->next);
+    
+    dormant=active;
+    active->prev_p=&dormant;
+    active=NULL;
+}
+
+
+static void catastrophe(void)
+{
+    abort();
+}
+
+int failure;
+
+
+void compile_block(cpu_history* pc_hist, int blocklen, int totcycles)
+{
+    if (letit && compiled_code && currprefs.cpu_level>=2) {
+
+       /* OK, here we need to 'compile' a block */
+       int i;
+       int r;
+       int was_comp=0;
+       uae_u8 liveflags[MAXRUN+1];
+       uae_u32 max_pcp=(uae_u32)pc_hist[0].location;
+       uae_u32 min_pcp=max_pcp;
+       uae_u32 cl=cacheline(pc_hist[0].location);
+       void* specflags=(void*)&regs.spcflags;
+       blockinfo* bi=NULL;
+       blockinfo* bi2;
+       int extra_len=0;
+
+       compile_count++;
+       if (current_compile_p>=max_compile_start)
+           flush_icache_hard(7);
+
+       alloc_blockinfos();
+
+       bi=get_blockinfo_addr_new(pc_hist[0].location,0);
+       bi2=get_blockinfo(cl);
+
+       optlev=bi->optlevel;
+       if (bi->handler) {
+           Dif (bi!=bi2) { 
+               /* I don't think it can happen anymore. Shouldn't, in 
+                  any case. So let's make sure... */
+               printf("WOOOWOO count=%d, ol=%d %p %p\n",
+                      bi->count,bi->optlevel,bi->handler_to_use,
+                      cache_tags[cl].handler);
+               abort();
+           }
+
+           Dif (bi->count!=-1 && bi->status!=BI_TARGETTED) {
+               /* What the heck? We are not supposed to be here! */
+               abort();
+           }
+       }       
+       if (bi->count==-1) {
+           optlev++;
+           while (!currprefs.optcount[optlev])
+               optlev++;
+           bi->count=currprefs.optcount[optlev]-1;
+       }
+       current_block_pc_p=(uae_u32)pc_hist[0].location;
+       
+       remove_deps(bi); /* We are about to create new code */
+       bi->optlevel=optlev;
+       bi->pc_p=(uae_u8*)pc_hist[0].location;
+       
+       liveflags[blocklen]=0x1f; /* All flags needed afterwards */
+       i=blocklen;
+       while (i--) {
+           uae_u16* currpcp=pc_hist[i].location;
+           int op=cft_map(*currpcp);
+
+           if ((uae_u32)currpcp<min_pcp)
+               min_pcp=(uae_u32)currpcp;
+           if ((uae_u32)currpcp>max_pcp)
+               max_pcp=(uae_u32)currpcp;
+
+           if (currprefs.compnf) {
+               liveflags[i]=((liveflags[i+1]&
+                              (~prop[op].set_flags))|
+                             prop[op].use_flags);
+               if (prop[op].is_addx && (liveflags[i+1]&FLAG_Z)==0)
+                   liveflags[i]&= ~FLAG_Z;
+           }
+           else {
+               liveflags[i]=0x1f;
+           }
+       }
+
+       bi->needed_flags=liveflags[0];
+
+       /* This is the non-direct handler */
+       align_target(32);
+       set_target(get_target()+1);
+       align_target(16);
+       /* Now aligned at n*32+16 */
+
+       bi->handler=
+           bi->handler_to_use=(void*)get_target();
+       raw_cmp_l_mi((uae_u32)&regs.pc_p,(uae_u32)pc_hist[0].location);
+       raw_jnz((uae_u32)popall_cache_miss);
+       /* This was 16 bytes on the x86, so now aligned on (n+1)*32 */
+
+       was_comp=0;
+
+#if USE_MATCHSTATE
+       comp_pc_p=(uae_u8*)pc_hist[0].location;
+       init_comp();
+       match_states(&(bi->env));
+       was_comp=1;
+#endif
+
+       bi->direct_handler=(void*)get_target();
+       set_dhtu(bi,bi->direct_handler);
+       current_block_start_target=(uae_u32)get_target();
+
+       if (bi->count>=0) { /* Need to generate countdown code */
+           raw_mov_l_mi((uae_u32)&regs.pc_p,(uae_u32)pc_hist[0].location);
+           raw_sub_l_mi((uae_u32)&(bi->count),1);
+           raw_jl((uae_u32)popall_recompile_block);
+       }
+       if (optlev==0) { /* No need to actually translate */
+           /* Execute normally without keeping stats */
+           raw_mov_l_mi((uae_u32)&regs.pc_p,(uae_u32)pc_hist[0].location);
+           raw_jmp((uae_u32)popall_exec_nostats); 
+       }
+       else {
+           reg_alloc_run=0;
+           next_pc_p=0;
+           taken_pc_p=0;
+           branch_cc=0;
+
+           log_startblock();
+           for (i=0;i<blocklen &&
+                    get_target_noopt()<max_compile_start;i++) {
+               cpuop_func **cputbl;
+               cpuop_func **comptbl;
+               uae_u16 opcode;
+               
+               opcode=cft_map((uae_u16)*pc_hist[i].location);
+               special_mem=pc_hist[i].specmem;
+               needed_flags=(liveflags[i+1] & prop[opcode].set_flags);
+               if (!needed_flags && currprefs.compnf) {
+#ifdef NOFLAGS_SUPPORT
+                   cputbl=nfcpufunctbl;
+#else
+                   cputbl=cpufunctbl;
+#endif
+                   comptbl=nfcompfunctbl;
+               }
+               else {
+                   cputbl=cpufunctbl;
+                   comptbl=compfunctbl;
+               }
+               
+               if (comptbl[opcode] && optlev>1) { 
+                   failure=0;
+                   if (!was_comp) {
+                       comp_pc_p=(uae_u8*)pc_hist[i].location;
+                       init_comp();
+                   }
+                   was_comp++;
+
+                   comptbl[opcode](opcode);
+                   freescratch();
+                   if (!(liveflags[i+1] & FLAG_CZNV)) { 
+                       /* We can forget about flags */
+                       dont_care_flags();
+                   }
+#if INDIVIDUAL_INST 
+                   flush(1);
+                   nop();
+                   flush(1);
+                   was_comp=0;
+#endif
+               }
+               else 
+                   failure=1;
+               if (failure) {
+                   if (was_comp) {
+                       flush(1);
+                       was_comp=0;
+                   }
+                   raw_mov_l_ri(REG_PAR1,(uae_u32)opcode);
+#if USE_NORMAL_CALLING_CONVENTION
+                   raw_push_l_r(REG_PAR1);
+#endif
+                   raw_mov_l_mi((uae_u32)&regs.pc_p,
+                                (uae_u32)pc_hist[i].location);
+                   raw_call((uae_u32)cputbl[opcode]);
+                   //raw_add_l_mi((uae_u32)&oink,1); // FIXME
+#if USE_NORMAL_CALLING_CONVENTION
+                   raw_inc_sp(4);
+#endif
+                   if (needed_flags) {
+                       //raw_mov_l_mi((uae_u32)&foink3,(uae_u32)opcode+65536);
+                   }
+                   else {
+                       //raw_mov_l_mi((uae_u32)&foink3,(uae_u32)opcode);
+                   }
+                   
+                   if (i<blocklen-1) {
+                       uae_s8* branchadd;
+                       
+                       raw_mov_l_rm(0,(uae_u32)specflags);
+                       raw_test_l_rr(0,0);
+                       raw_jz_b_oponly();
+                       branchadd=get_target();
+                       emit_byte(0);
+                       raw_sub_l_mi((uae_u32)&countdown,scaled_cycles(totcycles));
+                       raw_jmp((uae_u32)popall_do_nothing);
+                       *branchadd=(uae_u32)get_target()-(uae_u32)branchadd-1;
+                   }
+               }
+           }
+#if 0 /* This isn't completely kosher yet; It really needs to be
+        be integrated into a general inter-block-dependency scheme */
+           if (next_pc_p && taken_pc_p &&
+               was_comp && taken_pc_p==current_block_pc_p) {
+               blockinfo* bi1=get_blockinfo_addr_new((void*)next_pc_p,0);
+               blockinfo* bi2=get_blockinfo_addr_new((void*)taken_pc_p,0);
+               uae_u8 x=bi1->needed_flags;
+               
+               if (x==0xff || 1) {  /* To be on the safe side */
+                   uae_u16* next=(uae_u16*)next_pc_p;
+                   uae_u16 op=cft_map(*next);
+
+                   x=0x1f;
+                   x&=(~prop[op].set_flags);
+                   x|=prop[op].use_flags;
+               }
+               
+               x|=bi2->needed_flags;
+               if (!(x & FLAG_CZNV)) { 
+                   /* We can forget about flags */
+                   dont_care_flags();
+                   extra_len+=2; /* The next instruction now is part of this
+                                    block */
+               }
+                   
+           }
+#endif
+
+           if (next_pc_p) { /* A branch was registered */
+               uae_u32 t1=next_pc_p;
+               uae_u32 t2=taken_pc_p;
+               int     cc=branch_cc;
+               
+               uae_u32* branchadd;
+               uae_u32* tba;
+               bigstate tmp;
+               blockinfo* tbi;
+
+               if (taken_pc_p<next_pc_p) {
+                   /* backward branch. Optimize for the "taken" case ---
+                      which means the raw_jcc should fall through when
+                      the 68k branch is taken. */
+                   t1=taken_pc_p;
+                   t2=next_pc_p;
+                   cc=branch_cc^1;
+               }
+
+#if !USE_MATCHSTATE
+               flush_keepflags();
+#endif
+               tmp=live; /* ouch! This is big... */
+               raw_jcc_l_oponly(cc);
+               branchadd=(uae_u32*)get_target();
+               emit_long(0);
+               /* predicted outcome */
+               tbi=get_blockinfo_addr_new((void*)t1,1);
+               match_states(&(tbi->env));
+               //flush(1); /* Can only get here if was_comp==1 */
+               raw_sub_l_mi((uae_u32)&countdown,scaled_cycles(totcycles));
+               raw_jcc_l_oponly(9);
+               tba=(uae_u32*)get_target();
+               emit_long(get_handler(t1)-((uae_u32)tba+4));
+               raw_mov_l_mi((uae_u32)&regs.pc_p,t1);
+               raw_jmp((uae_u32)popall_do_nothing);
+               create_jmpdep(bi,0,tba,t1);
+
+               align_target(16);
+               /* not-predicted outcome */
+               *branchadd=(uae_u32)get_target()-((uae_u32)branchadd+4);
+               live=tmp; /* Ouch again */
+               tbi=get_blockinfo_addr_new((void*)t2,1);
+               match_states(&(tbi->env));
+
+               //flush(1); /* Can only get here if was_comp==1 */
+               raw_sub_l_mi((uae_u32)&countdown,scaled_cycles(totcycles));
+               raw_jcc_l_oponly(9);
+               tba=(uae_u32*)get_target();
+               emit_long(get_handler(t2)-((uae_u32)tba+4));
+               raw_mov_l_mi((uae_u32)&regs.pc_p,t2);
+               raw_jmp((uae_u32)popall_do_nothing);
+               create_jmpdep(bi,1,tba,t2);
+           }           
+           else 
+           {
+               if (was_comp) {
+                   flush(1);
+               }
+               
+               /* Let's find out where next_handler is... */
+               if (was_comp && isinreg(PC_P)) { 
+                   int r2;
+
+                   r=live.state[PC_P].realreg;
+                   
+                   if (r==0)
+                       r2=1;
+                   else 
+                       r2=0;
+                       
+                   raw_and_l_ri(r,TAGMASK);
+                   raw_mov_l_ri(r2,(uae_u32)popall_do_nothing);
+                   raw_sub_l_mi((uae_u32)&countdown,scaled_cycles(totcycles));
+                   raw_cmov_l_rm_indexed(r2,(uae_u32)cache_tags,r,4,9);
+                   raw_jmp_r(r2);
+               }
+               else if (was_comp && isconst(PC_P)) {
+                   uae_u32 v=live.state[PC_P].val;
+                   uae_u32* tba;
+                   blockinfo* tbi;
+
+                   tbi=get_blockinfo_addr_new((void*)v,1);
+                   match_states(&(tbi->env));
+
+                   raw_sub_l_mi((uae_u32)&countdown,scaled_cycles(totcycles));
+                   raw_jcc_l_oponly(9);
+                   tba=(uae_u32*)get_target();
+                   emit_long(get_handler(v)-((uae_u32)tba+4));
+                   raw_mov_l_mi((uae_u32)&regs.pc_p,v);
+                   raw_jmp((uae_u32)popall_do_nothing);
+                   create_jmpdep(bi,0,tba,v);
+               }               
+               else {
+                   int r2;
+
+                   r=REG_PC_TMP;
+                   raw_mov_l_rm(r,(uae_u32)&regs.pc_p);
+                   if (r==0)
+                       r2=1;
+                   else 
+                       r2=0;
+                       
+                   raw_and_l_ri(r,TAGMASK);
+                   raw_mov_l_ri(r2,(uae_u32)popall_do_nothing);
+                   raw_sub_l_mi((uae_u32)&countdown,scaled_cycles(totcycles));
+                   raw_cmov_l_rm_indexed(r2,(uae_u32)cache_tags,r,4,9);
+                   raw_jmp_r(r2);
+               }
+           }
+       }
+
+       if (next_pc_p+extra_len>=max_pcp && 
+           next_pc_p+extra_len<max_pcp+LONGEST_68K_INST) 
+           max_pcp=next_pc_p+extra_len;  /* extra_len covers flags magic */
+       else
+           max_pcp+=LONGEST_68K_INST;
+       bi->len=max_pcp-min_pcp;
+       bi->min_pcp=min_pcp;
+                   
+       remove_from_list(bi);
+       if (isinrom(min_pcp) && isinrom(max_pcp)) 
+           add_to_dormant(bi); /* No need to checksum it on cache flush.
+                                  Please don't start changing ROMs in
+                                  flight! */
+       else {
+           calc_checksum(bi,&(bi->c1),&(bi->c2));
+           add_to_active(bi);
+       }
+
+       log_dump();
+       align_target(32);
+       current_compile_p=get_target();
+
+        raise_in_cl_list(bi);
+        bi->nexthandler=current_compile_p;
+
+        /* We will flush soon, anyway, so let's do it now */
+        if (current_compile_p>=max_compile_start)
+            flush_icache_hard(7);
+
+        do_extra_cycles(totcycles); /* for the compilation time */
+    }
+}
+
+
diff --git a/compiler.c b/compiler.c
new file mode 100755 (executable)
index 0000000..fd3ee04
--- /dev/null
@@ -0,0 +1,4555 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * m68k emulation
+  *
+  * Copyright 1996 Bernd Schmidt
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "events.h"
+#include "gui.h"
+#include "memory.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "ersatz.h"
+#include "blitter.h"
+#include "debug.h"
+#include "autoconf.h"
+#include "compiler.h"
+
+#ifdef USE_COMPILER
+
+#include <sys/mman.h>
+
+char *address_space, *good_address_map;
+
+code_execfunc exec_me;
+uae_u8 nr_bbs_to_run = 1;
+int nr_bbs_start = 40;
+
+static int compile_failure;
+static int quiet_compile = 1;
+int i_want_to_die = 1;
+static int n_compiled = 0;
+static int n_max_comp = 99999999;
+static uaecptr call_only_me = 0;
+
+int patched_syscalls = 0;
+
+static int count_bits(uae_u16 v)
+{
+    int bits = 0;
+    while (v != 0) {
+       if (v & 1)
+           bits++;
+       v >>= 1;
+    }
+    return bits;
+}
+
+static uae_u16 bitswap(uae_u16 v)
+{
+    uae_u16 newv = 0;
+    uae_u16 m1 = 1, m2 = 0x8000;
+    int i;
+
+    for (i = 0; i < 16; i++) {
+       if (v & m1)
+           newv |= m2;
+       m2 >>= 1;
+       m1 <<= 1;
+    }
+    return newv;
+}
+
+static long long compiled_hits = 0;
+
+/* 16K areas with 512 byte blocks */
+#define SUBUNIT_ORDER 9
+#define PAGE_SUBUNIT (1 << SUBUNIT_ORDER)
+#define PAGE_ALLOC_UNIT (PAGE_SUBUNIT * 32)
+
+static int zerofd;
+static int zeroff;
+static struct code_page *first_code_page;
+
+static struct code_page *new_code_page(void)
+{
+    struct code_page *ncp;
+
+    ncp = (struct code_page *)mmap(NULL, PAGE_ALLOC_UNIT,
+                                  PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE,
+                                  zerofd, zeroff);
+    zeroff += PAGE_ALLOC_UNIT;
+    if (ncp) {
+       ncp->next = first_code_page;
+       first_code_page = ncp;
+       ncp->allocmask = 1; /* what a waste */
+    }
+    return ncp;
+}
+
+#define NUM_HASH 32768 /* larger values cause some paging on my 16MB machine */
+#define HASH_MASK (NUM_HASH-1)
+#define MAX_UNUSED_HASH 512
+
+static int SCAN_MARK = 1; /* Number of calls after which to scan a function */
+static int COMPILE_MARK = 5; /* Number of calls after which to compile a function */
+
+/* The main address -> function lookup hashtable. We use the lower bits of
+ * the address as hash function. */
+static struct hash_entry cpu_hash[NUM_HASH];
+/* These aren't really LRU lists... They used to be, but keeping them in that
+ * order is costly. The hash LRU list is now a two-part list: Functions that have
+ * no code allocated for them are placed at the beginning. Such entries can be
+ * recycled when we need a new hash entry. */
+static struct hash_block lru_first_block;
+static struct hash_entry lru_first_hash;
+static struct hash_entry *freelist_hash;
+static struct hash_block *freelist_block;
+static int num_unused_hash;
+
+static int m68k_scan_func(struct hash_entry *);
+static int m68k_compile_block(struct hash_block *);
+
+static char *alloc_code(struct hash_block *hb, int ninsns)
+{
+    struct code_page *cp;
+    long int allocsize = (ninsns * 32 + PAGE_SUBUNIT-1) & ~(PAGE_SUBUNIT-1);
+    uae_u32 allocmask;
+    int allocbits;
+    int j;
+    int last_bit;
+
+    if (allocsize >= (PAGE_ALLOC_UNIT - (1 << SUBUNIT_ORDER)))
+       return NULL;
+    allocbits = (allocsize >> SUBUNIT_ORDER);
+    allocmask = (1 << allocbits) - 1;
+
+    for (cp = first_code_page; cp != NULL; cp = cp->next) {
+       uae_u32 thispage_alloc = cp->allocmask;
+       for (j = 1; j < (33 - allocbits); j++) {
+           if ((cp->allocmask & (allocmask << j)) == 0) {
+               goto found_page;
+           }
+       }
+    }
+
+    /* Nothing large enough free: make a new page */
+    cp = new_code_page();
+    if (cp == NULL)
+       return NULL;
+    j = 1;
+
+found_page:
+    /* See whether there is in fact more space for us. If so, allocate all of
+     * it. compile_block() will free everything it didn't need. */
+
+    allocmask <<= j;
+    last_bit = allocbits + j;
+    while (last_bit < 32 && (cp->allocmask & (1 << last_bit)) == 0) {
+       allocmask |= 1 << last_bit;
+       allocsize += PAGE_SUBUNIT;
+       last_bit++;
+    }
+
+    hb->page_allocmask = allocmask;
+    hb->cpage = cp;
+    cp->allocmask |= allocmask;
+    hb->compile_start = ((char *)cp + (j << SUBUNIT_ORDER));
+    hb->alloclen = allocsize;
+    return hb->compile_start;
+}
+
+static void remove_hash_from_lists(struct hash_entry *h)
+{
+    h->lru_next->lru_prev = h->lru_prev;
+    h->lru_prev->lru_next = h->lru_next;
+
+    h->next->prev = h->prev;
+    h->prev->next = h->next;
+}
+
+static void lru_touch(struct hash_entry *h)
+{
+    h->lru_next->lru_prev = h->lru_prev;
+    h->lru_prev->lru_next = h->lru_next;
+
+    h->lru_next = &lru_first_hash;
+    h->lru_prev = lru_first_hash.lru_prev;
+    h->lru_prev->lru_next = h;
+    lru_first_hash.lru_prev = h;
+}
+
+static void lru_untouch(struct hash_entry *h)
+{
+    h->lru_next->lru_prev = h->lru_prev;
+    h->lru_prev->lru_next = h->lru_next;
+
+    h->lru_prev = &lru_first_hash;
+    h->lru_next = lru_first_hash.lru_next;
+    h->lru_next->lru_prev = h;
+    lru_first_hash.lru_next = h;
+}
+
+static void forget_block(struct hash_block *hb)
+{
+    struct hash_entry *h = hb->he_first;
+
+    hb->lru_next->lru_prev = hb->lru_prev;
+    hb->lru_prev->lru_next = hb->lru_next;
+
+    hb->lru_next = freelist_block;
+    freelist_block = hb;
+
+    if (hb->cpage != NULL)
+       write_log ("Discarding block with code. Tsk.\n");
+
+    do {
+       struct hash_entry *next = h->next_same_block;
+       h->block = NULL;
+       h->execute = NULL;
+       h->next_same_block = NULL;
+       h = next;
+       num_unused_hash++;
+       lru_untouch(h);
+    } while (h != hb->he_first);
+    compiler_flush_jsr_stack();
+}
+
+static void lru_touch_block(struct hash_block *h)
+{
+    h->lru_next->lru_prev = h->lru_prev;
+    h->lru_prev->lru_next = h->lru_next;
+
+    h->lru_next = &lru_first_block;
+    h->lru_prev = lru_first_block.lru_prev;
+    h->lru_prev->lru_next = h;
+    lru_first_block.lru_prev = h;
+}
+
+STATIC_INLINE int check_block(struct hash_block *hb)
+{
+#ifndef RELY_ON_LOADSEG_DETECTION
+    struct hash_entry *h = hb->he_first;
+
+    do {
+       struct hash_entry *next = h->next_same_block;
+       if (h->matchword != *(uae_u32 *)get_real_address(h->addr))
+           return 0;
+       h = next;
+    } while (h != hb->he_first);
+#endif
+    return 1;
+}
+
+uae_u32 flush_icache(void)
+{
+    struct hash_block *hb = lru_first_block.lru_next;
+
+    while (hb != &lru_first_block) {
+       struct hash_block *next = hb->lru_next;
+       if (hb->cpage != NULL) {
+           /* Address in chipmem? Then forget about block*/
+           if ((hb->he_first->addr & ~0xF80000) != 0xF80000) {
+               hb->cpage->allocmask &= ~hb->page_allocmask;
+               hb->cpage = NULL;
+               forget_block(hb);
+           }
+       }
+       hb = next;
+    }
+    return m68k_dreg(regs, 0);
+}
+
+void possible_loadseg(void)
+{
+    write_log ("Possible LoadSeg() detected\n");
+    flush_icache();
+}
+
+static struct hash_block *new_block(void)
+{
+    struct hash_block *b = freelist_block;
+
+    if (b != NULL) {
+       freelist_block = b->lru_next;
+    } else
+       b = (struct hash_block *)malloc(sizeof *b);
+    b->nrefs = 0;
+    b->cpage = NULL;
+    b->he_first = NULL;
+    b->translated = b->untranslatable = b->allocfailed = 0;
+    return b;
+}
+
+static struct hash_entry *get_free_hash(void)
+{
+    struct hash_entry *h;
+
+    for (;;) {
+       h = freelist_hash;
+       if (h != NULL) {
+           freelist_hash = h->next_same_block;
+           break;
+       }
+       h = lru_first_hash.lru_next;
+       if (num_unused_hash >= MAX_UNUSED_HASH && h->block == NULL
+           && !h->locked)
+       {
+           remove_hash_from_lists(h);
+           num_unused_hash--;
+           break;
+       }
+       h = (struct hash_entry *)malloc(sizeof(struct hash_entry));
+       h->next_same_block = NULL;
+       h->addr = -1;
+       break;
+    }
+    num_unused_hash++;
+    h->block = NULL;
+    h->ncalls = 0;
+    h->locked = h->cacheflush = 0;
+    h->execute = NULL;
+    return h;
+}
+
+static struct hash_entry *new_hash(uaecptr addr)
+{
+    struct hash_entry *h = get_free_hash();
+
+    h->addr = addr;
+
+    /* Chain the new node */
+    h->prev = cpu_hash + ((addr >> 1) & HASH_MASK);
+    h->next = h->prev->next;
+    h->next->prev = h->prev->next = h;
+
+    h->lru_next = &lru_first_hash;
+    h->lru_prev = lru_first_hash.lru_prev;
+    h->lru_prev->lru_next = h;
+    lru_first_hash.lru_prev = h;
+
+    h->next_same_block = NULL;
+
+    return h;
+}
+static struct hash_entry *find_hash(uaecptr addr)
+{
+    struct hash_entry *h;
+    struct hash_entry *h1 = cpu_hash + ((addr >> 1) & HASH_MASK);
+
+    if (h1->next->addr == addr)
+       return h1->next;
+
+    for (h = h1->next; h != h1; h = h->next) {
+       if (h->addr == addr) {
+           /* Put it at the head of the list so that the above shortcut
+            * works the next time we come here */
+           h->next->prev = h->prev; h->prev->next = h->next;
+           h->prev = h1;
+           h->next = h1->next;
+           h->next->prev = h->prev->next = h;
+           return h;
+       }
+    }
+    return NULL;
+}
+
+static struct hash_entry *get_hash_for_func(uaecptr addr, int mark_locked)
+{
+    struct hash_entry *h = find_hash(addr);
+    if (h == NULL)
+       h = new_hash (addr);
+#if 0 /* Too expensive */
+    else
+       lru_touch(h);
+#endif
+    if (mark_locked)
+       h->locked = 1;
+    return h;
+}
+
+static struct hash_entry *get_hash(uaecptr addr)
+{
+    struct hash_entry *h = get_hash_for_func(addr, 0);
+
+    if (h->block == NULL) {
+       if (++h->ncalls == SCAN_MARK) {
+           m68k_scan_func(h);
+       }
+    } else
+       if (!h->block->untranslatable && h->block->nrefs++ == COMPILE_MARK) {
+           lru_touch_block(h->block);
+           if (m68k_compile_block(h->block)) {
+               h->block->untranslatable = 1;
+           } else {
+               h->block->translated = 1;
+           }
+       }
+    return h;
+}
+
+void special_flush_hash(uaecptr addr)
+{
+    struct hash_entry *h = get_hash_for_func(addr, 0);
+
+    h->cacheflush = 1;
+}
+
+STATIC_INLINE void m68k_setpc_hash(uaecptr newpc)
+{
+    struct hash_entry *h = get_hash(newpc);
+
+    if (h->cacheflush)
+       flush_icache();
+
+    if (h->execute != NULL) {
+       if ((h->addr & 0xF80000) == 0xF80000 || check_block(h->block)) {
+           compiled_hits++;
+           if (i_want_to_die && (call_only_me == 0 || call_only_me == newpc)) {
+               exec_me = h->execute;
+               nr_bbs_to_run = nr_bbs_start;
+               regs.spcflags |= SPCFLAG_EXEC;
+           }
+       } else
+           flush_icache();
+    }
+    regs.pc = newpc;
+    regs.pc_p = regs.pc_oldp = get_real_address(newpc);
+}
+
+STATIC_INLINE void m68k_setpc_nohash(uaecptr newpc)
+{
+#if 0
+    /* This is probably not too good for efficiency... FIXME */
+    struct hash_entry *h = find_hash(newpc);
+
+    if (h != NULL && h->cacheflush)
+       flush_icache();
+#endif
+    regs.pc = newpc;
+    regs.pc_p = regs.pc_oldp = get_real_address(newpc);
+}
+
+void m68k_setpc(uaecptr newpc)
+{
+    m68k_setpc_hash(newpc);
+}
+
+void m68k_setpc_fast(uaecptr newpc)
+{
+    m68k_setpc_nohash(newpc);
+}
+
+void m68k_setpc_rte(uaecptr newpc)
+{
+    m68k_setpc_nohash(newpc);
+}
+
+void m68k_setpc_bcc(uaecptr newpc)
+{
+    m68k_setpc_hash(newpc);
+}
+
+static void hash_init(void)
+{
+    int i;
+    struct hash_entry **hepp;
+
+    freelist_block = NULL;
+    freelist_hash = NULL;
+
+    for(i = 0; i < NUM_HASH; i++) {
+       cpu_hash[i].next = cpu_hash[i].prev = cpu_hash + i;
+       cpu_hash[i].lru_next = cpu_hash[i].lru_prev = NULL;
+       cpu_hash[i].block = NULL;
+       cpu_hash[i].locked = 0; cpu_hash[i].cacheflush = 0;
+       cpu_hash[i].addr = -1;
+    }
+
+    lru_first_hash.lru_next = lru_first_hash.lru_prev = &lru_first_hash;
+    lru_first_block.lru_next = lru_first_block.lru_prev = &lru_first_block;
+
+    num_unused_hash = 0;
+}
+
+static void code_init(void)
+{
+    first_code_page = NULL;
+    zerofd = open("/dev/zero", O_RDWR);
+    zeroff = 0;
+}
+
+#define CC68K_C 16
+#define CC68K_V 8
+#define CC68K_Z 4
+#define CC68K_N 2
+#define CC68K_X 1
+
+STATIC_INLINE int cc_flagmask_68k(const int cc)
+{
+    switch(cc){
+     case 0: return 0;                       /* T */
+     case 1: return 0;                       /* F */
+     case 2: return CC68K_C|CC68K_Z;         /* HI */
+     case 3: return CC68K_C|CC68K_Z;         /* LS */
+     case 4: return CC68K_C;                 /* CC */
+     case 5: return CC68K_C;                 /* CS */
+     case 6: return CC68K_Z;                 /* NE */
+     case 7: return CC68K_Z;                 /* EQ */
+     case 8: return CC68K_V;                 /* VC */
+     case 9: return CC68K_V;                 /* VS */
+     case 10:return CC68K_N;                 /* PL */
+     case 11:return CC68K_N;                 /* MI */
+     case 12:return CC68K_N|CC68K_V;         /* GE */
+     case 13:return CC68K_N|CC68K_V;         /* LT */
+     case 14:return CC68K_N|CC68K_V|CC68K_Z; /* GT */
+     case 15:return CC68K_N|CC68K_V|CC68K_Z; /* LE */
+    }
+    abort();
+    return 0;
+}
+
+STATIC_INLINE void translate_step_over_ea(uae_u8 **pcpp, amodes m,
+                                             wordsizes size)
+{
+    switch (m) {
+     case Areg:
+     case Dreg:
+     case Aind:
+     case Aipi:
+     case Apdi:
+     case immi:
+       break;
+
+     case imm:
+       if (size == sz_long)
+           goto is_long;
+       /* fall through */
+     case Ad16:
+     case PC16:
+     case imm0:
+     case imm1:
+     case absw:
+       (*pcpp)+=2;
+       break;
+     case Ad8r:
+     case PC8r:
+       {
+           uae_u16 extra = *(*pcpp)++;
+           extra <<= 8;
+           extra |= *(*pcpp)++;
+           /* @@@ handle 68020 stuff here */
+       }
+       break;
+     case absl:
+     case imm2:
+       is_long:
+       (*pcpp) += 4;
+       break;
+    }
+}
+
+static struct instr *translate_getnextinsn(uae_u8 **pcpp)
+{
+    uae_u16 opcode;
+    struct instr *dp;
+
+    opcode = *(*pcpp)++ << 8;
+    opcode |= *(*pcpp)++;
+
+    if (cpufunctbl[opcode] == op_illg) {
+       opcode = 0x4AFC;
+    }
+    dp = table68k + opcode;
+    if (dp->suse) {
+       translate_step_over_ea(pcpp, dp->smode, dp->size);
+    }
+    if (dp->duse) {
+       translate_step_over_ea(pcpp, dp->dmode, dp->size);
+    }
+    return dp;
+}
+
+#define CB_STACKSIZE 200
+#define BB_STACKSIZE 200
+
+static uae_u32 condbranch_stack[CB_STACKSIZE];
+static int condbranch_src_stack[CB_STACKSIZE];
+
+struct bb_info {
+    struct hash_entry *h;
+    uaecptr stopaddr;
+    int can_compile_last;
+    struct bb_info *bb_next1, *bb_next2;
+    int flags_live_at_end;
+    int flags_live_at_start;
+    int first_iip, last_iip;
+} bb_stack[BB_STACKSIZE];
+
+static int top_bb;
+
+static uaecptr bcc_target_stack[BB_STACKSIZE];
+
+static int new_bcc_target(uaecptr addr)
+{
+    int i;
+
+    for (i = 0; i < top_bb; i++)
+       if (bcc_target_stack[i] == addr)
+           return 1;
+
+    if (top_bb == BB_STACKSIZE)
+       return 0;
+    bcc_target_stack[top_bb++] = addr;
+    return 1;
+}
+
+static int bcc_compfn(const void *a, const void *b)
+{
+    uaecptr *a1 = (uaecptr *)a, *b1 = (uaecptr *)b;
+
+    if (*a1 == *b1)
+       printf("BUG!!\n");
+
+    if (*a1 < *b1)
+       return 1;
+    return -1;
+}
+
+static int bb_compfn(const void *a, const void *b)
+{
+    struct bb_info *a1 = (struct bb_info *)a, *b1 = (struct bb_info *)b;
+
+    if (a1->h->addr == b1->h->addr)
+       printf("BUG!!\n");
+
+    if (a1->h->addr < b1->h->addr)
+       return -1;
+    return 1;
+}
+
+static int find_basic_blocks(struct hash_entry *h)
+{
+    int current_bb = 0;
+
+    top_bb = 0;
+    bcc_target_stack[0] = h->addr;
+    new_bcc_target(h->addr);
+
+    while (top_bb > current_bb) {
+       uaecptr addr = bcc_target_stack[current_bb];
+       int ninsns = 0;
+       uae_u8 *realpc = get_real_address(addr);
+       uae_u8 *rpc_start = realpc;
+
+       for(;;) {
+           uaecptr thisinsn_addr = (realpc - rpc_start) + addr;
+           uae_u8 *rpc_save = realpc;
+           struct instr *dp = translate_getnextinsn(&realpc);
+           uaecptr nextinsn_addr = (realpc - rpc_start) + addr;
+
+           if (dp->mnemo == i_RTS || dp->mnemo == i_RTE
+               || dp->mnemo == i_RTR || dp->mnemo == i_RTD
+               || dp->mnemo == i_JMP || dp->mnemo == i_ILLG)
+           {
+               break;
+           }
+
+           if (dp->mnemo == i_BSR || dp->mnemo == i_JSR) {
+               if (!new_bcc_target(nextinsn_addr))
+                   return 0;
+               break;
+           }
+
+           if (dp->mnemo == i_DBcc) {
+               uaecptr newaddr = thisinsn_addr + 2 + (uae_s16)((*(rpc_save+2) << 8) | *(rpc_save+3));
+               if (!new_bcc_target(nextinsn_addr))
+                   return 0;
+               if (!new_bcc_target(newaddr))
+                   return 0;
+               break;
+           }
+
+           if (dp->mnemo == i_Bcc) {
+               uaecptr newaddr;
+               if (dp->smode == imm1)
+                   newaddr = thisinsn_addr + 2 + (uae_s16)((*(rpc_save+2) << 8) | *(rpc_save+3));
+               else
+                   newaddr = thisinsn_addr + 2 + (uae_s8)dp->sreg;
+
+               if (dp->cc != 0)
+                   if (!new_bcc_target(nextinsn_addr))
+                       return 0;
+               if (!new_bcc_target(newaddr))
+                   return 0;
+               break;
+           }
+       }
+       current_bb++;
+    }
+
+    qsort(bcc_target_stack, top_bb, sizeof (uaecptr), bcc_compfn);
+
+    return 1;
+}
+
+static int m68k_scan_func(struct hash_entry *h)
+{
+    int i;
+    struct hash_block *found_block;
+    struct hash_entry **hepp;
+
+    if (!find_basic_blocks(h))
+       return 0;
+
+    found_block = NULL;
+
+    /* First, lock the hash entries we already have to prevent grief */
+    for (i = 0; i < top_bb; i++) {
+       struct hash_entry *h = find_hash(bcc_target_stack[i]);
+       if (h != NULL)
+           h->locked = 1;
+    }
+
+    /* Allocate new ones */
+    for (i = 0; i < top_bb; i++) {
+       struct hash_entry *h = get_hash_for_func(bcc_target_stack[i], 1);
+       bb_stack[i].h = h;
+#if 0 /* This doesn't work in all cases */
+       if (h->block != NULL && h->block != found_block) {
+           if (found_block == NULL) {
+               if (h->block->cpage != NULL)
+                   write_log ("Found compiled code\n");
+               else
+                   found_block = h->block;
+           } else {
+               write_log ("Multiple blocks found.\n");
+               if (h->block->cpage == NULL)
+                   forget_block(h->block);
+               else if (found_block->cpage == NULL) {
+                   forget_block(found_block);
+                   found_block = h->block;
+               } else
+                   write_log ("Bad case.\n");
+           }
+       }
+#endif
+    }
+    if (found_block == NULL) {
+       found_block = new_block();
+
+       found_block->lru_next = &lru_first_block;
+       found_block->lru_prev = lru_first_block.lru_prev;
+       found_block->lru_prev->lru_next = found_block;
+       lru_first_block.lru_prev = found_block;
+    }
+
+    hepp = &found_block->he_first;
+    found_block->he_first = NULL;
+    for (i = 0; i < top_bb; i++) {
+       struct bb_info *bb = bb_stack + i;
+
+       if (bb->h->block == NULL) {
+           num_unused_hash--;
+           lru_touch(bb->h);
+           bb->h->block = found_block;
+           *hepp = bb->h;
+           hepp = &bb->h->next_same_block;
+       }
+    }
+    *hepp = found_block->he_first;
+    return 1;
+}
+
+struct ea_reg_info {
+    enum { eat_reg, eat_imem, eat_amem, eat_const } ea_type;
+    int regs_set:16;
+    int regs_used:16;
+    int nr_scratch;
+    uae_u32 temp1, temp2;
+};
+
+#define MAX_TRANSLATE 2048
+struct insn_info_struct {
+    uaecptr address;
+    struct instr *dp;
+    int flags_set;
+    int flags_used;
+    int flags_live_at_end;
+    int jump_target;
+    int jumps_to;
+    char *compiled_jumpaddr; /* Address to use for jumps to this insn */
+    char *compiled_fillin;   /* Address where to put offset if this is a Bcc */
+    int regs_set:16;
+    int regs_used:16;
+    int stop_translation:2;
+    int sync_cache:1;
+    int sync_flags:1;
+    int ccuser_follows:1;
+} insn_info [MAX_TRANSLATE];
+
+#define EA_NONE 0
+#define EA_LOAD 1
+#define EA_STORE 2
+#define EA_MODIFY 4
+
+#if 0
+static void analyze_ea_for_insn(amodes mode, int reg, wordsizes size,
+                               struct ea_reg_info *eai,
+                               uae_u8 **pcpp, uaecptr pca,
+                               int ea_purpose)
+{
+    uae_u8 *p = *pcpp;
+
+    switch(mode) {
+     case Dreg:
+       eai->ea_type = eat_reg;
+       if (size != sz_long && (ea_purpose & EA_STORE))
+           ea_purpose |= EA_LOAD;
+       if (ea_purpose & EA_LOAD)
+           eai->regs_used |= 1 << reg;
+       if (ea_purpose & EA_STORE)
+           eai->regs_set |= 1 << reg;
+       break;
+
+     case Areg:
+       eai->ea_type = eat_reg;
+       if (size != sz_long && (ea_purpose & EA_STORE))
+           printf("Areg != long\n");
+       if (ea_purpose & EA_LOAD)
+           eai->regs_used |= 1 << (8+reg);
+       if (ea_purpose & EA_STORE)
+           eai->regs_set |= 1 << (8+reg);
+       break;
+
+     case Ad16:
+     case Aind:
+     case Apdi:
+     case Aipi:
+       eai->ea_type = eat_imem;
+       eai->regs_used |= 1 << (8+reg);
+       break;
+
+     case Ad8r:
+       eai->ea_type = eat_imem;
+       pii->regs_used |= 1 << (8+reg);
+
+       eai->temp = (uae_u16)((*p << 8) | *(p+1));
+       r = (eai->temp & 0x7000) >> 12;
+       (*pcpp) += 2; p += 2;
+
+       if (eai->temp1 & 0x8000)
+           pii->regs_used |= 1 << (8+r);
+       else
+           pii->regs_used |= 1 << r;
+       break;
+
+     case PC8r:
+       eai->ea_type = eat_imem;
+       eai->temp1 = (uae_u16)do_get_mem_word((uae_u16 *)p);
+       eai->temp2 = pca + (uae_s8)eai->temp1;
+       (*pcpp) += 2; p += 2;
+       r = (eai->temp1 & 0x7000) >> 12;
+
+       if (eai->temp1 & 0x8000)
+           pii->regs_used |= 1 << (8+r);
+       else
+           pii->regs_used |= 1 << r;
+       break;
+
+     case PC16:
+       eai->ea_type = eat_amem;
+       eai->temp1 = pca + (uae_s16)do_get_mem_word((uae_u16 *)p);
+       (*pcpp) += 2;
+       break;
+
+     case absw:
+       eai->ea_type = eat_amem;
+       eai->temp1 = (uae_s16)do_get_mem_word((uae_u16 *)p);
+       (*pcpp) += 2;
+       break;
+
+     case absl:
+       eai->ea_type = eat_amem;
+       eai->temp1 = (uae_s32)do_get_mem_long((uae_u32 *)p);
+       (*pcpp) += 4;
+       break;
+
+     case imm:
+       if (size == sz_long)
+           goto imm2_const;
+       if (size == sz_word)
+           goto imm1_const;
+
+       /* fall through */
+     case imm0:
+       eai->ea_type = eat_imm;
+       eai->temp1 = (uae_s8)*(p+1);
+       (*pcpp) += 2;
+       break;
+
+     case imm1:
+       imm1_const:
+       eai->ea_type = eat_imm;
+       eai->temp1 = (uae_s16)do_get_mem_word((uae_u16 *)p);
+       (*pcpp) += 2;
+       break;
+
+     case imm2:
+       imm2_const:
+       eai->ea_type = eat_imm;
+       eai->temp1 = (uae_s32)do_get_mem_long((uae_u32 *)p);
+       (*pcpp) += 4;
+       break;
+
+     case immi:
+       eai->ea_type = eat_imm;
+       eai->temp1 = (uae_s8)reg;
+       break;
+
+     default:
+       break;
+    }
+}
+#endif
+static struct bb_info *find_bb(struct hash_entry *h)
+{
+    int i;
+
+    if (h == NULL)
+       printf("Bug...\n");
+
+    for (i = 0; i < top_bb; i++)
+       if (bb_stack[i].h == h)
+           return bb_stack + i;
+    if (!quiet_compile)
+       write_log ("BB not found!\n");
+    return NULL;
+}
+
+static int m68k_scan_block(struct hash_block *hb, int *movem_count)
+{
+    struct hash_entry *h = hb->he_first;
+    int i, iip, last_iip;
+    int changed, round;
+
+    top_bb = 0;
+
+    do {
+       struct bb_info *bb = bb_stack + top_bb;
+       bb->h = h;
+       bb->bb_next1 = NULL;
+       bb->bb_next2 = NULL;
+       h = h->next_same_block;
+       top_bb++;
+    } while (h != hb->he_first);
+
+    qsort(bb_stack, top_bb, sizeof (struct bb_info), bb_compfn);
+
+    *movem_count = 0;
+
+    iip = 0;
+    for (i = 0; i < top_bb; i++) {
+       struct bb_info *bb = bb_stack + i;
+       uae_u8 *realpc = get_real_address(bb->h->addr);
+       uae_u8 *rpc_start = realpc;
+       uaecptr stop_addr = 0;
+       int live_at_start = 31, may_clear_las = 31;
+       struct insn_info_struct *prev_ii = NULL;
+
+       if (i < top_bb - 1)
+           stop_addr = (bb+1)->h->addr;
+       bb->first_iip = iip;
+
+       for (;;) {
+           struct insn_info_struct *thisii = insn_info + iip;
+           uaecptr thisinsn_addr = (realpc - rpc_start) + bb->h->addr;
+           uae_u8 *rpc_save = realpc;
+           struct instr *dp = translate_getnextinsn(&realpc);
+           uaecptr nextinsn_addr = (realpc - rpc_start) + bb->h->addr;
+
+           int fset = dp->flagdead == -1 ? 31 : dp->flagdead;
+           int fuse = dp->flaglive == -1 ? 31 : dp->flaglive;
+
+           if (thisinsn_addr == stop_addr) {
+               bb->bb_next1 = find_bb (find_hash (thisinsn_addr));
+               break;
+           }
+
+           if (dp->mnemo == i_Scc || dp->mnemo == i_Bcc || dp->mnemo == i_DBcc) {
+               fset = 0, fuse = cc_flagmask_68k(dp->cc);
+               if (prev_ii && dp->mnemo != i_Scc) /* Don't use Scc here: ea can cause an exit */
+                   prev_ii->ccuser_follows = 1;
+           }
+
+           may_clear_las &= ~fuse;
+           live_at_start &= ~(fset & may_clear_las);
+
+           thisii->dp = dp;
+           thisii->address = thisinsn_addr;
+           thisii->stop_translation = 0;
+           thisii->ccuser_follows = 0;
+/*         thisii->have_reginfo = 0;*/
+           thisii->jump_target = 0;
+           thisii->sync_cache = thisii->sync_flags = 0;
+           thisii->flags_set = fset;
+           thisii->flags_used = fuse;
+           thisii->regs_set = 0;
+           thisii->regs_used = 0;
+           iip++;
+           if (iip == MAX_TRANSLATE)
+               return 0;
+
+           if (dp->mnemo == i_RTS || dp->mnemo == i_RTE
+               || dp->mnemo == i_RTR || dp->mnemo == i_RTD
+               || dp->mnemo == i_JMP || dp->mnemo == i_ILLG)
+           {
+               thisii->flags_used = 31;
+               thisii->regs_used = 65535;
+               thisii->stop_translation = dp->mnemo == i_RTS || dp->mnemo == i_JMP ? 2 : 1;
+               break;
+           }
+           if (dp->mnemo == i_BSR || dp->mnemo == i_JSR)
+           {
+               thisii->flags_used = 31;
+               thisii->regs_used = 65535;
+               bb->can_compile_last = 1;
+               bb->bb_next1 = find_bb (get_hash_for_func (nextinsn_addr, 1));
+               if (bb->bb_next1 == NULL)
+                   thisii->stop_translation = 1;
+               break;
+           }
+
+           if (dp->mnemo == i_DBcc) {
+               uaecptr newaddr = thisinsn_addr + 2 + (uae_s16)((*(rpc_save+2) << 8) | *(rpc_save+3));
+               bb->can_compile_last = 1;
+               bb->bb_next1 = find_bb (get_hash_for_func (newaddr, 1));
+               if (bb->bb_next1 == NULL)
+                   thisii->stop_translation = 1;
+               bb->bb_next2 = find_bb (get_hash_for_func (nextinsn_addr, 1));
+               if (bb->bb_next2 == NULL)
+                   thisii->stop_translation = 1;
+               thisii->regs_used = 65535;
+               break;
+           }
+
+           if (dp->mnemo == i_Bcc) {
+               uaecptr newaddr;
+               if (dp->smode == imm1)
+                   newaddr = thisinsn_addr + 2 + (uae_s16)((*(rpc_save+2) << 8) | *(rpc_save+3));
+               else
+                   newaddr = thisinsn_addr + 2 + (uae_s8)dp->sreg;
+               bb->can_compile_last = 1;
+               bb->bb_next1 = find_bb(get_hash_for_func(newaddr, 1));
+               if (bb->bb_next1 == NULL)
+                   thisii->stop_translation = 1;
+               if (dp->cc != 0) {
+                   bb->bb_next2 = find_bb(get_hash_for_func(nextinsn_addr, 1));
+                   if (bb->bb_next2 == NULL)
+                       thisii->stop_translation = 1;
+               }
+               thisii->regs_used = 65535;
+               break;
+           }
+
+           if (dp->mnemo == i_MVMLE || dp->mnemo == i_MVMEL) {
+               uae_u16 regmask = (*(rpc_save + 2) << 8) | (*(rpc_save + 3));
+               *movem_count += count_bits(regmask);
+               if (dp->dmode == Apdi)
+                   regmask = bitswap(regmask);
+               if (dp->mnemo == i_MVMLE)
+                   thisii->regs_used = regmask;
+               else
+                   thisii->regs_set = regmask;
+           }
+
+           prev_ii = thisii;
+       }
+       bb->last_iip = iip - 1;
+       bb->flags_live_at_start = live_at_start;
+    }
+    last_iip = iip;
+    round = 0;
+    do {
+       changed = 0;
+       for (i = 0; i < top_bb; i++) {
+           struct bb_info *bb = bb_stack + i;
+           int mnemo;
+           int current_live;
+           struct instr *dp;
+
+           iip = bb->last_iip;
+           mnemo = insn_info[iip].dp->mnemo;
+
+           /* Fix up branches */
+           if (round == 0 && (mnemo == i_DBcc || mnemo == i_Bcc)) {
+               if (bb->bb_next1 != NULL) {
+                   insn_info[bb->last_iip].jumps_to = bb->bb_next1->first_iip;
+                   insn_info[bb->bb_next1->first_iip].jump_target = 1;
+               }
+           }
+
+           /* And take care of flag life information */
+           dp = insn_info[iip].dp;
+           if (insn_info[iip].stop_translation)
+               current_live = 31;
+           else if (dp->mnemo == i_DBcc || dp->mnemo == i_Bcc) {
+               current_live = 0;
+               if (bb->bb_next1 != NULL)
+                   current_live |= bb->bb_next1->flags_live_at_start;
+               if (bb->bb_next2 != NULL)
+                   current_live |= bb->bb_next2->flags_live_at_start;
+           } else {
+               if (bb->bb_next1 == NULL && bb->bb_next2 == NULL)
+                   write_log ("Can't happen\n");
+               current_live = 0;
+               if (bb->bb_next1 != NULL)
+                   current_live |= bb->bb_next1->flags_live_at_start;
+               if (bb->bb_next2 != NULL)
+                   current_live |= bb->bb_next2->flags_live_at_start;
+           }
+
+           do {
+               insn_info[iip].flags_live_at_end = current_live;
+               current_live &= ~insn_info[iip].flags_set;
+               current_live |= insn_info[iip].flags_used;
+           } while (iip-- != bb->first_iip);
+
+           if (bb->flags_live_at_start != current_live && !quiet_compile)
+               write_log ("Fascinating %d!\n", round), changed = 1;
+           bb->flags_live_at_start = current_live;
+       }
+       round++;
+    } while (changed);
+    return last_iip;
+}
+
+#define MAX_JSRS 4096 /* must be a power of two */
+
+static uaecptr jsr_rets[MAX_JSRS];
+static struct hash_entry *jsr_hash[MAX_JSRS];
+static int jsr_num;
+static struct hash_entry dummy_hash; /* This is for safety purposes only */
+
+
+static void jsr_stack_init(void)
+{
+    jsr_num = 0;
+    dummy_hash.execute = NULL;
+}
+
+void compiler_flush_jsr_stack(void)
+{
+    jsr_num = 0;
+}
+
+void m68k_do_rts(void)
+{
+    m68k_setpc(get_long(m68k_areg(regs, 7)));
+    m68k_areg(regs, 7) += 4;
+    if (jsr_num > 0)
+       jsr_num--;
+}
+
+__inline__ void m68k_do_jsr(uaecptr oldpc, uaecptr dest)
+{
+    struct hash_entry *h = find_hash(oldpc);
+
+    if (jsr_num == MAX_JSRS)
+       compiler_flush_jsr_stack();
+    if (h == NULL) {
+       jsr_hash[jsr_num] = &dummy_hash;
+       jsr_rets[jsr_num++] = 0xC0DEDBAD;
+    } else {
+       jsr_hash[jsr_num] = h;
+       jsr_rets[jsr_num++] = oldpc;
+    }
+    m68k_areg(regs, 7) -= 4;
+    put_long(m68k_areg(regs, 7), oldpc);
+    m68k_setpc(dest);
+}
+
+void m68k_do_bsr(uaecptr oldpc, uae_s32 offset)
+{
+    m68k_do_jsr(oldpc, m68k_getpc() + offset);
+}
+
+/* Here starts the actual compiling part */
+
+static char *compile_current_addr;
+static char *compile_last_addr;
+
+STATIC_INLINE void assemble(uae_u8 a)
+{
+    if (compile_current_addr < compile_last_addr) {
+       *compile_current_addr++ = a;
+    } else {
+       compile_failure = 1;
+    }
+}
+
+STATIC_INLINE void assemble_ulong(uae_u32 a)
+{
+    assemble(a);
+    assemble(a >> 8);
+    assemble(a >> 16);
+    assemble(a >> 24);
+}
+
+STATIC_INLINE void assemble_ulong_68k(uae_u32 a)
+{
+    assemble(a >> 24);
+    assemble(a >> 16);
+    assemble(a >> 8);
+    assemble(a);
+}
+
+STATIC_INLINE void assemble_uword(uae_u16 a)
+{
+    assemble(a);
+    assemble(a >> 8);
+}
+
+STATIC_INLINE void assemble_long(void *a)
+{
+    assemble_ulong((uae_u32)a);
+}
+
+STATIC_INLINE void compile_org(char *addr)
+{
+    compile_current_addr = addr;
+}
+
+STATIC_INLINE char *compile_here(void)
+{
+    return compile_current_addr;
+}
+
+#define r_EAX 0
+#define r_ECX 1
+#define r_EDX 2
+#define r_EBX 3
+#define r_ESP 4
+#define r_EBP 5
+#define r_ESI 6
+#define r_EDI 7
+
+#define r_AH 0x84
+#define r_CH 0x85
+#define r_DH 0x86
+#define r_BH 0x87
+
+#define ALL_X86_REGS 255
+#define ADDRESS_X86_REGS ((1 << r_EBP) | (1 << r_ESI) | (1 << r_EDI))
+#define DATA_X86_REGS ((1 << r_EAX) | (1 << r_EDX) | (1 << r_EBX) | (1 << r_ECX))
+
+#define BO_NORMAL 0
+#define BO_SWAPPED_LONG 1
+#define BO_SWAPPED_WORD 2
+
+struct register_mapping {
+    int dreg_map[8], areg_map[8]; /* 68000 register cache */
+    int x86_const_offset[8];
+    int x86_dirty[8];
+    int x86_cache_reg[8]; /* Regs used for the 68000 register cache */
+    int x86_cr_type[8]; /* Caching data or address register? */
+    int x86_locked[8]; /* Regs used for some purpose */
+    int x86_users[8];
+    int x86_byteorder[8];
+    int x86_verified[8];
+};
+
+/*
+ * First, code to compile some primitive x86 instructions
+ */
+
+static void compile_lea_reg_with_offset(int dstreg, int srcreg, uae_u32 srcoffs)
+{
+    assemble(0x8D);
+    if (srcreg == -2) {
+       assemble(0x05 + 8*dstreg);
+       assemble_ulong(srcoffs);
+    } else if ((uae_s32)srcoffs >= -128 && (uae_s32)srcoffs <= 127) {
+       assemble(0x40 + 8*dstreg + srcreg);
+       assemble(srcoffs);
+    } else {
+       assemble(0x80 + 8*dstreg + srcreg);
+       assemble_ulong(srcoffs);
+    }
+}
+
+static void compile_move_reg_reg(int dstreg, int srcreg, wordsizes size)
+{
+    if (size == sz_byte
+       && (((1 << dstreg) & DATA_X86_REGS) == 0
+           || ((1 << srcreg) & DATA_X86_REGS) == 0))
+    {
+       write_log ("Moving wrong register types!\n");
+    }
+    if (size == sz_word)
+       assemble(0x66);
+    if (size == sz_byte)
+       assemble(0x88);
+    else
+       assemble(0x89);
+    assemble(0xC0 + dstreg + 8*srcreg);
+}
+
+static void compile_move_between_reg_mem_regoffs(int dstreg, int srcreg,
+                                                uae_u32 srcoffs, wordsizes size,
+                                                int code)
+{
+    if (size == sz_byte && (dstreg & 0x80) != 0)
+       dstreg &= ~0x80;
+    else if ((size == sz_byte
+             && ((1 << dstreg) & DATA_X86_REGS) == 0)
+            || (size != sz_byte && (dstreg & 0x80) != 0))
+    {
+       write_log ("Moving wrong register types!\n");
+    }
+    if (size == sz_word)
+       assemble(0x66);
+    if (size == sz_byte)
+       assemble(code);
+    else
+       assemble(code + 1);
+
+    if (srcreg == -2) {
+       assemble(0x05 + 8*dstreg);
+       assemble_ulong(srcoffs);
+    } else if ((uae_s32)srcoffs >= -128 && (uae_s32)srcoffs <= 127) {
+       assemble(0x40 + 8*dstreg + srcreg);
+       assemble(srcoffs);
+    } else {
+       assemble(0x80 + 8*dstreg + srcreg);
+       assemble_ulong(srcoffs);
+    }
+}
+
+static void compile_move_reg_from_mem_regoffs(int dstreg, int srcreg,
+                                             uae_u32 srcoffs, wordsizes size)
+{
+    compile_move_between_reg_mem_regoffs(dstreg, srcreg, srcoffs, size, 0x8A);
+}
+
+static void compile_move_reg_to_mem_regoffs(int dstreg, uae_u32 dstoffs,
+                                           int srcreg, wordsizes size)
+{
+    compile_move_between_reg_mem_regoffs(srcreg, dstreg, dstoffs, size, 0x88);
+}
+
+static void compile_byteswap(int x86r, wordsizes size, int save_flags)
+{
+    switch(size) {
+     case sz_word:
+       if (save_flags)
+           assemble(0x9C);
+       assemble(0x66); /* rolw $8,x86r */
+       assemble(0xC1);
+       assemble(0xC0 + x86r);
+       assemble(8);
+       if (save_flags)
+           assemble(0x9D);
+       break;
+     case sz_long:
+       assemble(0x0F); /* bswapl x86r */
+       assemble(0xC8+x86r);
+       break;
+     default:
+       break;
+    }
+}
+
+static void compile_force_byteorder(struct register_mapping *map, int x86r,
+                                   int desired_bo, int save_flags)
+{
+    if (x86r < 0 || map->x86_byteorder[x86r] == desired_bo)
+       return;
+
+    if (map->x86_byteorder[x86r] == BO_SWAPPED_LONG)
+       compile_byteswap(x86r, sz_long, save_flags);
+    else if (map->x86_byteorder[x86r] == BO_SWAPPED_WORD)
+       compile_byteswap(x86r, sz_word, save_flags);
+
+    if (desired_bo == BO_SWAPPED_LONG)
+       compile_byteswap(x86r, sz_long, save_flags);
+    else if (desired_bo == BO_SWAPPED_WORD)
+       compile_byteswap(x86r, sz_word, save_flags);
+    map->x86_byteorder[x86r] = desired_bo;
+}
+
+/* Add a constant offset to a x86 register. If it's in the cache, make sure
+ * we update the const_offset value. The flags are unaffected by this */
+
+static void compile_offset_reg(struct register_mapping *map, int x86r,
+                              uae_u32 offset)
+{
+    int cached_68k;
+
+    if (offset == 0 || x86r == -1 || x86r == -2)
+       return;
+
+    compile_force_byteorder(map, x86r, BO_NORMAL, 1);
+    cached_68k = map->x86_cache_reg[x86r];
+    if (cached_68k != -1) {
+       map->x86_const_offset[x86r] -= offset;
+       map->x86_dirty[x86r] = 1;
+    }
+    compile_lea_reg_with_offset(x86r, x86r, offset);
+}
+
+static int get_unused_x86_register(struct register_mapping *map)
+{
+    int x86r;
+    for (x86r = 0; x86r < 24; x86r++) {
+       if (map->x86_cache_reg[x86r] != -1)
+           continue;
+       if (map->x86_users[x86r] > 0)
+           continue;
+
+       map->x86_verified[x86r] = 0;
+       map->x86_byteorder[x86r] = BO_NORMAL;
+       return x86r;
+    }
+    return -1;
+}
+
+/*
+ * sync_reg() may not touch the flags
+ * If may_clobber is 1 and the reg had an offset, the reg will be offsetted
+ * by this function
+ */
+static void sync_reg(struct register_mapping *map, int x86r, void *m68kr,
+                    uae_u32 offset, int dirty, int may_clobber)
+{
+    if (dirty || offset != 0)
+       compile_force_byteorder(map, x86r, BO_NORMAL, 1);
+    if (offset != 0) {
+       if (may_clobber) {
+           compile_lea_reg_with_offset(x86r, x86r, offset);
+           dirty = 1;
+       } else {
+           int tmpr = get_unused_x86_register(map);
+           if (tmpr != -1) {
+               compile_lea_reg_with_offset(tmpr, x86r, offset);
+               x86r = tmpr;
+               dirty = 1;
+           } else {
+               compile_lea_reg_with_offset(x86r, x86r, offset);
+               assemble(0x89);          /* movl x86r,m68kr */
+               assemble(0x05 + (x86r << 3));
+               assemble_long(m68kr);
+               compile_lea_reg_with_offset(x86r, x86r, -offset);
+               return;
+           }
+       }
+    }
+    if (dirty) {
+       assemble(0x89);          /* movl x86r,m68kr */
+       assemble(0x05 + (x86r << 3));
+       assemble_long(m68kr);
+    }
+}
+
+static void sync_reg_cache(struct register_mapping *map, int flush)
+{
+    int i;
+
+    for (i = 0; i < 8; i++) {
+       int cr68k = map->x86_cache_reg[i];
+       if (cr68k != -1) {
+           if (map->x86_cr_type[i] == 1) {
+               sync_reg(map, i, regs.regs + cr68k, map->x86_const_offset[i], map->x86_dirty[i], 1);
+               if (flush)
+                   map->dreg_map[cr68k] = -1;
+           } else {
+               sync_reg(map, i, regs.regs + 8 + cr68k, map->x86_const_offset[i], map->x86_dirty[i], 1);
+               if (flush)
+                   map->areg_map[cr68k] = -1;
+           }
+           if (flush)
+               map->x86_cache_reg[i] = -1;
+           map->x86_const_offset[i] = 0;
+       }
+    }
+    memset(map->x86_dirty, 0, sizeof map->x86_dirty);
+}
+
+static void remove_x86r_from_cache(struct register_mapping *map, int x86r,
+                                  int may_clobber)
+{
+    int j;
+    int reg_68k;
+
+    if (x86r == -1)
+       return;
+
+    reg_68k = map->x86_cache_reg[x86r];
+
+    if (reg_68k == -1)
+       return;
+
+    if (map->x86_cr_type[x86r] == 1) {
+       map->dreg_map[reg_68k] = -1;
+       sync_reg(map, x86r, regs.regs + reg_68k, map->x86_const_offset[x86r],
+                map->x86_dirty[x86r], may_clobber);
+    } else {
+       map->areg_map[reg_68k] = -1;
+       sync_reg(map, x86r, regs.regs + 8 + reg_68k,  map->x86_const_offset[x86r],
+                map->x86_dirty[x86r], may_clobber);
+    }
+    map->x86_dirty[x86r] = 0;
+    map->x86_cache_reg[x86r] = -1;
+    map->x86_const_offset[x86r] = 0;
+    map->x86_verified[x86r] = 0;
+    map->x86_byteorder[x86r] = BO_NORMAL;
+}
+
+static int get_free_x86_register(struct register_mapping *map,
+                                int preferred_mask)
+{
+    int cnt;
+    for (cnt = 0; cnt < 24; cnt++) {
+       int x86r = cnt & 7;
+       /* In the first two passes, try to get one of the preferred regs */
+       if (cnt < 16 && ((1 << x86r) & preferred_mask) == 0)
+           continue;
+       /* In the first pass, don't discard any registers from the cache */
+       if (cnt < 8 && map->x86_cache_reg[x86r] != -1)
+           continue;
+       /* Never use locked registers */
+       if (map->x86_users[x86r] > 0)
+           continue;
+
+       remove_x86r_from_cache(map, x86r, 1);
+       map->x86_dirty[x86r] = 0;
+       map->x86_cache_reg[x86r] = -1;
+       map->x86_const_offset[x86r] = 0;
+       map->x86_verified[x86r] = 0;
+       map->x86_byteorder[x86r] = BO_NORMAL;
+       return x86r;
+    }
+    printf("Out of registers!\n");
+    return -1;
+}
+
+static int get_typed_x86_register(struct register_mapping *map,
+                                 int preferred_mask)
+{
+    int cnt;
+    for (cnt = 0; cnt < 16; cnt++) {
+       int x86r = cnt & 7;
+       /* Get one of the preferred regs */
+       if (((1 << x86r) & preferred_mask) == 0)
+           continue;
+       /* In the first pass, don't discard any registers from the cache */
+       if (cnt < 8 && map->x86_cache_reg[x86r] != -1)
+           continue;
+       /* Never use locked registers */
+       if (map->x86_users[x86r] > 0)
+           continue;
+
+       remove_x86r_from_cache(map, x86r, 1);
+       map->x86_dirty[x86r] = 0;
+       map->x86_cache_reg[x86r] = -1;
+       map->x86_const_offset[x86r] = 0;
+       map->x86_verified[x86r] = 0;
+       map->x86_byteorder[x86r] = BO_NORMAL;
+       return x86r;
+    }
+    printf("Out of type registers!\n");
+    return -1;
+}
+
+static void compile_unlock_reg(struct register_mapping *map, int reg)
+{
+    if (reg >= 0) {
+       if (--map->x86_users[reg] == 0)
+           map->x86_locked[reg] = 0;
+
+    }
+}
+
+static void lock_reg(struct register_mapping *map, int x86r, int lock_type)
+{
+#if 1
+    switch (map->x86_locked[x86r]) {
+     case 0:
+       if (map->x86_users[x86r] != 0)
+           printf("Users for an unlocked reg!\n");
+       break;
+     case 1:
+       if (lock_type == 2)
+           printf("Locking shared reg for exclusive use!\n");
+       break;
+     case 2:
+       printf("Locking exclusive reg!\n");
+       break;
+     default:
+       printf("Unknown lock?\n");
+       break;
+    }
+#endif
+    map->x86_locked[x86r] = lock_type;
+    map->x86_users[x86r]++;
+}
+
+static int get_and_lock_68k_reg(struct register_mapping *map, int reg, int is_dreg,
+                               int preferred, int no_offset, int lock_type)
+{
+    int x86r;
+    int *regmap;
+    uae_u32 *reghome;
+    uae_u32 const_off = 0;
+
+    if (reg < 0 || reg > 7) {
+       printf("Mad compiler disease\n");
+       return 0;
+    }
+
+    if (is_dreg)
+       regmap = map->dreg_map, reghome = regs.regs;
+    else
+       regmap = map->areg_map, reghome = regs.regs + 8;
+
+    if (preferred == 0)
+       preferred = ALL_X86_REGS;
+
+    x86r = regmap[reg];
+    if (x86r == -1) {
+       x86r = get_free_x86_register(map, preferred);
+       assemble(0x8B); assemble(0x05 + (x86r << 3)); /* movl regs.d[reg],x86r */
+       assemble_long(reghome + reg);
+       map->x86_cache_reg[x86r] = reg;
+       map->x86_cr_type[x86r] = is_dreg;
+       map->x86_const_offset[x86r] = 0;
+       map->x86_dirty[x86r] = 0;
+       map->x86_verified[x86r] = 0;
+       map->x86_byteorder[x86r] = BO_NORMAL;
+       regmap[reg] = x86r;
+    } else {
+       const_off = map->x86_const_offset[x86r];
+
+       if (map->x86_locked[x86r] == 2
+           || (map->x86_locked[x86r] == 1 && (lock_type == 2 || (const_off != 0 && no_offset))))
+       {
+           int newr;
+           int old_dirty = 0;
+           int old_verified;
+           int old_bo;
+
+           newr = get_free_x86_register(map, preferred);
+           if (const_off == 0) {
+               compile_move_reg_reg(newr, x86r, sz_long);
+           } else {
+               compile_force_byteorder(map, x86r, BO_NORMAL, 1);
+               compile_lea_reg_with_offset(newr, x86r, const_off);
+               old_dirty = 1;
+               const_off = 0;
+           }
+           /* Remove old reg from cache... */
+           map->x86_cache_reg[x86r] = -1;
+           map->x86_cr_type[x86r] = is_dreg;
+           map->x86_const_offset[x86r] = 0;
+           old_dirty |= map->x86_dirty[x86r];
+           old_verified = map->x86_verified[x86r];
+           old_bo = map->x86_byteorder[x86r];
+           map->x86_verified[x86r] = 0;
+           map->x86_dirty[x86r] = 0;
+           x86r = newr;
+           /* ... and make the new one the cache register */
+           map->x86_cache_reg[x86r] = reg;
+           map->x86_cr_type[x86r] = is_dreg;
+           map->x86_const_offset[x86r] = 0;
+           map->x86_dirty[x86r] = old_dirty;
+           map->x86_verified[x86r] = old_verified;
+           map->x86_byteorder[x86r] = old_bo;
+           regmap[reg] = x86r;
+       }
+    }
+    if (no_offset && const_off != 0) {
+       if (map->x86_locked[x86r] != 0)
+           printf("modifying locked reg\n");
+       compile_force_byteorder(map, x86r, BO_NORMAL, 1);
+       compile_lea_reg_with_offset(x86r, x86r, map->x86_const_offset[x86r]);
+       map->x86_const_offset[x86r] = 0;
+       map->x86_dirty[x86r] = 1;
+    }
+    lock_reg(map, x86r, lock_type);
+    return x86r;
+}
+
+/*
+ * Move a constant to a register. Don't do anything if we already have a
+ * register, even if it is offset by a constant
+ */
+
+static int compile_force_const_reg(struct register_mapping *map, int x86r,
+                                  uae_u32 *offs, int desired)
+{
+    int newr = x86r;
+
+    if (newr == -2) {
+       if (desired == 0)
+           newr = get_free_x86_register(map, ALL_X86_REGS);
+       else
+           newr = get_typed_x86_register(map, desired);
+
+       assemble(0xB8 + newr);
+       assemble_ulong(*offs);
+       *offs = 0;
+    }
+    map->x86_users[newr]++;
+    return newr;
+}
+
+static void compile_extend_long(struct register_mapping *map, int x86r,
+                               wordsizes size)
+{
+    if (x86r < 0) {
+       printf("Bad reg in extend_long\n");
+       return;
+    }
+
+    compile_force_byteorder(map, x86r, BO_NORMAL, 1);
+
+    if (size != sz_long) {
+       if (x86r == r_EAX && size == sz_word) {
+           assemble(0x98); /* cwtl */
+       } else {
+           assemble(0x0F);
+           if (size == sz_byte) {
+               assemble(0xBE);
+           } else {
+               assemble(0xBF);
+           }
+           assemble(0xC0 + x86r*9);
+       }
+    }
+}
+
+struct ea_info {
+    int reg;
+    amodes mode;
+    wordsizes size;
+    int address_reg;    /* The x86 reg holding the address, or -1 if ea doesn't refer to memory
+                        * -2 if it refers to memory, but only with a constant address */
+    uae_u32 addr_const_off; /* Constant offset to the address */
+    int data_reg;         /* The x86 reg that holds the data. -1 if data is not present yet.
+                          * -2 if data is constant */
+    uae_u32 data_const_off;
+    int flags;            /* Extra info. Contains the dp field of d8r modes */
+    int purpose;
+};
+
+static void init_eainfo(struct ea_info *eai)
+{
+    eai->address_reg = -1;
+    eai->addr_const_off = 0;
+    eai->data_reg = -1;
+    eai->data_const_off = 0;
+}
+
+struct insn_reg_needs {
+    int checkpoint_no;
+    int dreg_needed[8], areg_needed[8];
+    int dreg_mask[8], areg_mask[8];
+};
+
+/*
+ * This structure holds information about predec/postinc addressing modes.
+ */
+
+struct pid_undo {
+    int used;
+    int x86r[2];
+    int m68kr[2];
+    int dirty[2];
+    int offs[2];
+};
+
+static void add_undo(struct pid_undo *pud, int x86r, int m68kr, int offs,
+                    int dirty)
+{
+    int i;
+    for (i = 0; i < pud->used; i++)
+       if (pud->m68kr[i] == m68kr)
+           return;
+    pud->m68kr[i] = m68kr;
+    pud->x86r[i] = x86r;
+    pud->offs[i] = offs;
+    pud->dirty[i] = dirty;
+    pud->used++;
+}
+
+/*
+ * Lock previous contents of address registers used in predec/postinc modes
+ * for generate_possible_exit().
+ */
+
+static void compile_prepare_undo(struct register_mapping *map, amodes mode,
+                             int reg, struct pid_undo *pud)
+{
+    int x86r;
+
+    switch(mode){
+     default:
+       break;
+
+     case Apdi:
+       x86r = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0, 1);
+       /* This saves recording the byteorder in the pud structure, and we'll
+        * need it in normal byteorder anyway */
+       compile_force_byteorder(map, x86r, BO_NORMAL, 0);
+       /*
+        * Add this reg with its current offset to the undo buffer.
+        * Since we have locked it, we are certain that it will not be
+        * modified.
+        */
+       add_undo(pud, x86r, reg, map->x86_const_offset[x86r], map->x86_dirty[x86r]);
+       break;
+
+     case Aipi:
+       x86r = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0, 1);
+       compile_force_byteorder(map, x86r, BO_NORMAL, 0);
+       add_undo(pud, x86r, reg, map->x86_const_offset[x86r], map->x86_dirty[x86r]);
+       break;
+    }
+}
+
+/*
+ * Load all the registers absolutely needed to calculate and verify thea
+ * address. Load other registers if convenient.
+ * This contains a fair amount of magic to get the register cache working right.
+ */
+
+static void compile_prepareea(struct register_mapping *map, amodes mode,
+                             int reg, wordsizes size, uae_u8 **pcpp, uaecptr pca,
+                             struct ea_info *eainf, int eaino, int ea_purpose,
+                             int pidmult)
+{
+    struct ea_info *eai = eainf + eaino;
+    int pdival = size == sz_byte && reg != 7 ? 1 : size == sz_long ? 4 : 2;
+    uae_u8 *p = *pcpp;
+    uae_u16 dp;
+    int r;
+    int x86r, tmpr;
+
+    pdival *= pidmult;
+
+    init_eainfo(eai);
+    eai->mode = mode;
+    eai->size = size;
+    eai->reg = reg;
+
+    switch(mode){
+     case Dreg:
+     case Areg:
+       break;
+
+     case Ad16:
+       eai->addr_const_off = (uae_s16)do_get_mem_word((uae_u16 *)p);
+       (*pcpp) += 2; p += 2;
+       x86r = eai->address_reg = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0, 1);
+       compile_force_byteorder(map, x86r, BO_NORMAL, 0);
+       eai->addr_const_off += map->x86_const_offset[x86r];
+       break;
+
+     case Aind:
+       x86r = eai->address_reg = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0, 1);
+       compile_force_byteorder(map, x86r, BO_NORMAL, 0);
+       eai->addr_const_off = map->x86_const_offset[x86r];
+       break;
+
+     case Apdi:
+       x86r = eai->address_reg = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0, 1);
+       compile_force_byteorder(map, x86r, BO_NORMAL, 0);
+       map->x86_const_offset[x86r] -= pdival;
+       eai->addr_const_off = map->x86_const_offset[x86r];
+       break;
+
+     case Aipi:
+       x86r = eai->address_reg = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0, 1);
+       compile_force_byteorder(map, x86r, BO_NORMAL, 0);
+       eai->addr_const_off = map->x86_const_offset[x86r];
+       map->x86_const_offset[x86r] += pdival;
+       break;
+
+     case Ad8r:
+       dp = (uae_s16)do_get_mem_word((uae_u16 *)p);
+       r = (dp & 0x7000) >> 12;
+       (*pcpp) += 2; p += 2;
+
+       tmpr = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0, 1);
+       compile_force_byteorder(map, tmpr, BO_NORMAL, 0);
+       eai->addr_const_off = map->x86_const_offset[tmpr] + (uae_s8)dp;
+
+       if (dp & 0x800) {
+           x86r = get_and_lock_68k_reg(map, r, dp & 0x8000 ? 0 : 1, ADDRESS_X86_REGS, 0, 2);
+           remove_x86r_from_cache(map, x86r, 0);
+           compile_force_byteorder(map, x86r, BO_NORMAL, 0);
+           eai->addr_const_off += map->x86_const_offset[x86r];
+       } else {
+           x86r = get_and_lock_68k_reg(map, r, dp & 0x8000 ? 0 : 1, ADDRESS_X86_REGS, 1, 2);
+           remove_x86r_from_cache(map, x86r, 0);
+           compile_force_byteorder(map, x86r, BO_NORMAL, 0);
+       }
+       eai->address_reg = x86r;
+
+       r = (dp & 0x7000) >> 12;
+
+       if (dp & 0x800) {
+           if (eai->addr_const_off == 0) {
+               assemble(0x03); assemble(0xC0 + tmpr + x86r*8); /* addl basereg,addrreg */
+           } else if ((uae_s32)eai->addr_const_off >= -128 && (uae_s32)eai->addr_const_off <= 127) {
+               assemble(0x8D);
+               assemble(0x44 + x86r*8); /* leal disp8(dispreg,basereg),dispreg */
+               assemble(x86r*8 + tmpr);
+               assemble(eai->addr_const_off);
+           } else {
+               assemble(0x8D);
+               assemble(0x84 + x86r*8); /* leal disp32(dispreg,basereg),dispreg */
+               assemble(x86r*8 + tmpr);
+               assemble_ulong(eai->addr_const_off);
+           }
+           eai->addr_const_off = 0;
+       } else {
+           assemble(0x0F); assemble(0xBF);
+           assemble(0xC0 + x86r*9); /* movswl dispreg,addrreg */
+           assemble(0x03); assemble(0xC0 + tmpr + x86r*8); /* addl basereg,addrreg */
+       }
+       compile_unlock_reg(map, tmpr);
+       break;
+
+     case PC8r:
+       dp = (uae_s16)do_get_mem_word((uae_u16 *)p);
+       (*pcpp) += 2; p += 2;
+       r = (dp & 0x7000) >> 12;
+       eai->addr_const_off = pca + (uae_s8)dp;
+       if (dp & 0x800) {
+           x86r = get_and_lock_68k_reg(map, r, dp & 0x8000 ? 0 : 1, ADDRESS_X86_REGS, 0, 1);
+           remove_x86r_from_cache(map, x86r, 0);
+           compile_force_byteorder(map, x86r, BO_NORMAL, 0);
+           eai->addr_const_off += map->x86_const_offset[x86r];
+       } else {
+           x86r = get_and_lock_68k_reg(map, r, dp & 0x8000 ? 0 : 1, ADDRESS_X86_REGS, 1, 2);
+           remove_x86r_from_cache(map, x86r, 0);
+           compile_force_byteorder(map, x86r, BO_NORMAL, 0);
+
+           assemble(0x0F); assemble(0xBF);
+           assemble(0xC0 + x86r*9); /* movswl dispreg,addrreg */
+       }
+       eai->address_reg = x86r;
+       break;
+
+     case PC16:
+       eai->addr_const_off = pca + (uae_s16)do_get_mem_word((uae_u16 *)p);
+       eai->address_reg = -2;
+       (*pcpp) += 2; p += 2;
+       break;
+
+     case absw:
+       eai->addr_const_off = (uae_s16)do_get_mem_word((uae_u16 *)p);
+       eai->address_reg = -2;
+       (*pcpp) += 2; p += 2;
+       break;
+
+     case absl:
+       eai->addr_const_off = (uae_s32)do_get_mem_long((uae_u32 *)p);
+       eai->address_reg = -2;
+       (*pcpp) += 4; p += 4;
+       break;
+
+     case imm:
+       if (size == sz_long)
+           goto imm2_const;
+       if (size == sz_word)
+           goto imm1_const;
+
+       /* fall through */
+     case imm0:
+       eai->data_const_off = (uae_s8)*(p+1);
+       eai->data_reg = -2;
+       (*pcpp) += 2; p += 2;
+       break;
+
+     case imm1:
+       imm1_const:
+       eai->data_const_off = (uae_s16)do_get_mem_word((uae_u16 *)p);
+       eai->data_reg = -2;
+       (*pcpp) += 2; p += 2;
+       break;
+
+     case imm2:
+       imm2_const:
+       eai->data_const_off = (uae_s32)do_get_mem_long((uae_u32 *)p);
+       eai->data_reg = -2;
+       (*pcpp) += 4; p += 4;
+       break;
+
+     case immi:
+       eai->data_const_off = (uae_s8)reg;
+       eai->data_reg = -2;
+       break;
+
+     default:
+       break;
+    }
+    eai->purpose = ea_purpose;
+}
+
+static void compile_get_excl_lock(struct register_mapping *map, struct ea_info *eai)
+{
+    int x86r = eai->data_reg;
+
+    if (x86r >= 0 && map->x86_locked[x86r] == 1) {
+       int newr;
+       if (eai->size == sz_byte)
+           newr = get_typed_x86_register(map, DATA_X86_REGS);
+       else
+           newr = get_free_x86_register(map, ALL_X86_REGS);
+
+       compile_move_reg_reg(newr, x86r, sz_long);
+       eai->data_reg = newr;
+       lock_reg(map, eai->data_reg, 2);
+    }
+}
+
+/*
+ * Some functions to assemble some 386 opcodes which have a similar
+ * structure (ADD, AND, OR, etc.). These take source and destination
+ * addressing modes, check their validity and assemble a complete
+ * 386 instruction.
+ */
+
+STATIC_INLINE int rmop_long(struct ea_info *eai)
+{
+    if (eai->data_reg == -2)
+       printf("rmop for const\n");
+    else if (eai->data_reg == -1) {
+       if (eai->address_reg == -2)
+           return 5;
+       if (eai->address_reg == -1) {
+           /* This must be a 68k register in its home location */
+           return 5;
+       }
+#if 0 /* We need to add address_space... */
+       if (eai->addr_const_off == 0 && eai->address_reg != r_EBP) {
+           return eai->address_reg;
+       }
+       else if ((uae_s32)eai->addr_const_off >= -128 && (uae_s32)eai->addr_const_off <= 127) {
+           return eai->address_reg | 0x40;
+       }
+#endif
+       return eai->address_reg | 0x80;
+    } else {
+       if (eai->size == sz_byte && ((1 << eai->data_reg) & DATA_X86_REGS) == 0)
+           printf("wrong type reg in rmop\n");
+       if (eai->data_const_off != 0)
+           printf("data_const_off in rmop\n");
+       return 0xC0 + eai->data_reg;
+    }
+    return 0;
+}
+
+STATIC_INLINE int rmop_short(struct ea_info *eai)
+{
+    if (eai->data_reg == -2)
+       printf("rmop_short for const\n");
+    else if (eai->data_reg == -1) {
+       printf("rmop_short for mem\n");
+    } else {
+       if (eai->size == sz_byte && ((1 << eai->data_reg) & DATA_X86_REGS) == 0)
+           printf("wrong type reg in rmop_short\n");
+       if (eai->data_const_off != 0)
+           printf("data_const_off in rmop_short\n");
+       return eai->data_reg*8;
+    }
+    return 0;
+}
+
+STATIC_INLINE void rmop_finalize(struct ea_info *eai)
+{
+    if (eai->data_reg == -2)
+       assemble_ulong(eai->data_const_off);
+    else if (eai->data_reg == -1) {
+       if (eai->address_reg == -2)
+           /* Constant address */
+           assemble_long(address_space + (uae_s32)eai->addr_const_off);
+       else if (eai->address_reg == -1) {
+           /* Register in its home location */
+           if (eai->mode == Areg)
+               assemble_long(regs.regs + 8  + eai->reg);
+           else
+               assemble_long(regs.regs + eai->reg);
+       } else {
+#if 0
+           /* Indirect address with offset */
+           if ((uae_s32)eai->addr_const_off >= -128 && (uae_s32)eai->addr_const_off <= 127) {
+           }
+#endif
+           assemble_long(address_space + (uae_s32)eai->addr_const_off);
+       }
+    }
+}
+
+static void compile_eas(struct register_mapping *map, struct ea_info *eainf, int eaino_s, int eaino_d,
+                       int optype)
+{
+    struct ea_info *eais = eainf + eaino_s;
+    struct ea_info *eaid = eainf + eaino_d;
+    int szflag = eais->size == sz_byte ? 0 : 1;
+    int swapflag = 0;
+    int opcode;
+
+    if (eais->data_reg == -1) {
+       compile_force_byteorder(map, eais->address_reg, BO_NORMAL, 0);
+       eais = eainf + eaino_d;
+       eaid = eainf + eaino_s;
+       swapflag = 1;
+    }
+    if (eais->data_reg == -1) {
+       compile_force_byteorder(map, eais->address_reg, BO_NORMAL, 0);
+    }
+
+    if (eais->size == sz_word)
+       assemble(0x66);
+
+    if (eais->data_reg == -2) {
+       assemble(0x80+szflag);
+       assemble(8*optype | rmop_long(eaid));
+       rmop_finalize(eaid);
+       switch(eais->size) {
+        case sz_byte: assemble(eais->data_const_off); break;
+        case sz_word: assemble_uword(eais->data_const_off); break;
+        case sz_long: assemble_ulong(eais->data_const_off); break;
+       }
+    } else {
+       assemble(8*optype | szflag | 2*swapflag);
+       assemble(rmop_long(eaid) | rmop_short(eais));
+       rmop_finalize(eaid);
+    }
+}
+
+static void compile_fetchmem(struct register_mapping *map, struct ea_info *eai)
+{
+    int x86r;
+    if (eai->size == sz_byte)
+       x86r = get_typed_x86_register(map, DATA_X86_REGS);
+    else
+       x86r = get_free_x86_register(map, ALL_X86_REGS);
+
+    lock_reg(map, x86r, 2);
+    compile_force_byteorder(map, eai->address_reg, BO_NORMAL, 0);
+    compile_move_reg_from_mem_regoffs(x86r, eai->address_reg,
+                                     (uae_u32)(eai->addr_const_off + address_space),
+                                     eai->size);
+    map->x86_verified[x86r] = 0;
+    switch (eai->size) {
+     case sz_byte: map->x86_byteorder[x86r] = BO_NORMAL; break;
+     case sz_word: map->x86_byteorder[x86r] = BO_SWAPPED_WORD; break;
+     case sz_long: map->x86_byteorder[x86r] = BO_SWAPPED_LONG; break;
+    }
+    eai->data_reg = x86r;
+    eai->data_const_off = 0;
+}
+
+static void compile_fetchimm(struct register_mapping *map, struct ea_info *eai, int byteorder)
+{
+    int x86r;
+    if (eai->size == sz_byte)
+       x86r = get_typed_x86_register(map, DATA_X86_REGS);
+    else
+       x86r = get_free_x86_register(map, ALL_X86_REGS);
+
+    switch (byteorder) {
+     case BO_SWAPPED_LONG:
+       eai->data_const_off = (((eai->data_const_off & 0xFF000000) >> 24)
+                              | ((eai->data_const_off & 0xFF0000) >> 8)
+                              | ((eai->data_const_off & 0xFF00) << 8)
+                              | ((eai->data_const_off & 0xFF) << 24));
+       break;
+     case BO_SWAPPED_WORD:
+       eai->data_const_off = (((eai->data_const_off & 0xFF00) >> 8)
+                              | ((eai->data_const_off & 0xFF) << 8)
+                              | (eai->data_const_off & 0xFFFF0000));
+       break;
+     case BO_NORMAL:
+       break;
+    }
+    lock_reg(map, x86r, 2);
+    map->x86_byteorder[x86r] = byteorder; map->x86_verified[x86r] = 0;
+
+    switch (eai->size) {
+     case sz_byte: assemble(0xC6); assemble(0xC0 + x86r); assemble(eai->data_const_off); break;
+     case sz_word: assemble(0x66); assemble(0xC7); assemble(0xC0 + x86r); assemble_uword(eai->data_const_off); break;
+     case sz_long: assemble(0xC7); assemble(0xC0 + x86r); assemble_ulong(eai->data_const_off); break;
+    }
+    eai->data_reg = x86r;
+    eai->data_const_off = 0;
+}
+
+/*
+ * 1: reg
+ * 2: mem
+ * 4: imm
+ */
+
+static int binop_alternatives[] = {
+    7, 1,
+    5, 3,
+    0, 0
+};
+
+static int binop_worda_alternatives[] = {
+    1, 3,
+    0, 0
+};
+
+static int regonly_alternatives[] = {
+    1, 1,
+    0, 0
+};
+
+static void compile_loadeas(struct register_mapping *map, struct ea_info *eainf,
+                          int eaino_s, int eaino_d, int *alternatives,
+                          int scramble_poss, int load_dest)
+{
+    struct ea_info *eais = eainf + eaino_s;
+    struct ea_info *eaid = eainf + eaino_d;
+    int scrambled_bo = eaid->size == sz_long ? BO_SWAPPED_LONG : eaid->size == sz_word ? BO_SWAPPED_WORD : BO_NORMAL;
+    int i, scrambled = 0;
+    int best = 0;
+    int bestcost = -1;
+    int *ap;
+    uae_u32 *sregp = NULL, *dregp = NULL;
+    int screg = -1, dcreg = -1;
+    int stype = -1, dtype = -1;
+    int asrc, adst;
+    int regprefs = eais->size == sz_byte ? DATA_X86_REGS : 0;
+
+    if (eais->mode == Dreg) {
+       stype = 0;
+       screg = map->dreg_map[eais->reg];
+       if (screg == -1)
+           sregp = regs.regs + eais->reg;
+    } else if (eais->mode == Areg) {
+       stype = 0;
+       screg = map->areg_map[eais->reg];
+       if (screg == -1)
+           sregp = regs.regs + 8 + eais->reg;
+    } else if (eais->data_reg == -2) {
+       stype = -2;
+    }
+
+    if (eaid->mode == Dreg) {
+       dtype = 0;
+       dcreg = map->dreg_map[eaid->reg];
+       if (dcreg == -1)
+           dregp = regs.regs + eaid->reg;
+    } else if (eaid->mode == Areg) {
+       dtype = 0;
+       dcreg = map->areg_map[eaid->reg];
+       if (dcreg == -1)
+           dregp = regs.regs + 8 + eaid->reg;
+    } else if (eaid->data_reg == -2) {
+       dtype = -2;
+    }
+
+    ap = alternatives;
+
+    for (i = 0;; i++) {
+       int cost = 0;
+
+       asrc = *ap++;
+       if (asrc == 0)
+           break;
+       adst = *ap++;
+
+       if (stype == -2 && (asrc & 4) == 0)
+           cost++;
+       else if (stype == -1 && ((asrc & 2) == 0 || (eais->size != sz_byte && !scramble_poss)))
+           cost++;
+       else if (stype == 0 && screg == -1 && (asrc & 2) == 0)
+           cost++;
+
+       if (dtype == -1 && ((adst & 2) == 0 || (eaid->size != sz_byte && !scramble_poss)))
+           /* The !load_dest case isn't handled by the current code,
+            * and it isn't desirable anyway. Use a different alternative
+            */
+           cost += load_dest ? 1 : 100;
+       else if (dtype == 0 && dcreg == -1 && (adst & 2) == 0)
+           cost++;
+
+       if (bestcost == -1 || cost < bestcost) {
+           bestcost = cost;
+           best = i;
+       }
+    }
+
+    asrc = alternatives[2*best];
+    adst = alternatives[2*best+1];
+
+    if (dtype == -1) {
+       if (load_dest) {
+           if ((adst & 2) == 0 || (eaid->size != sz_byte && !scramble_poss))
+               compile_fetchmem(map, eaid);
+       } else {
+           if ((adst & 2) == 0) {
+               printf("Not loading memory operand. Prepare to die.\n");
+               if (eaid->size == sz_byte)
+                   eaid->data_reg = get_typed_x86_register(map, DATA_X86_REGS);
+               else
+                   eaid->data_reg = get_free_x86_register(map, ALL_X86_REGS);
+           }
+       }
+       /* Scrambled in both mem and reg cases */
+       if (eaid->size != sz_byte && scramble_poss)
+           scrambled = 1;
+    } else {
+       if (dcreg == -1 && !load_dest && (adst & 2) == 0 && eaid->size == sz_long) {
+           /* We need a register, but we don't need to fetch the old data.
+            * See storeea for some more code handling this case. This first
+            * if statement could be eliminated, we would generate some
+            * superfluous moves. This is an optimization. If it were not
+            * done, the mem-mem-move warning could be commented in in
+            * storeea. */
+           if (eaid->size == sz_byte)
+               eaid->data_reg = get_typed_x86_register(map, DATA_X86_REGS);
+           else
+               eaid->data_reg = get_free_x86_register(map, ALL_X86_REGS);
+           eaid->data_const_off = 0;
+       } else if ((dcreg == -1 && (adst & 2) == 0) || dcreg != -1) {
+           int reg_bo;
+           eaid->data_reg = get_and_lock_68k_reg(map, eaid->reg, eaid->mode == Dreg, regprefs, 1, 2);
+           eaid->data_const_off = 0;
+
+           reg_bo = map->x86_byteorder[eaid->data_reg];
+
+           if (reg_bo != BO_NORMAL) {
+               if (reg_bo != scrambled_bo)
+                   compile_force_byteorder(map, eaid->data_reg, BO_NORMAL, 0);
+               else if (scramble_poss)
+                   scrambled = 1;
+           }
+       }
+    }
+
+    if (stype == -2) {
+       /* @@@ may need to scramble imm, this is a workaround */
+       if ((asrc & 4) == 0 || scrambled)
+           compile_fetchimm(map, eais, scrambled ? scrambled_bo : BO_NORMAL);
+    } else if (stype == -1) {
+       if ((asrc & 2) == 0 || (eais->size != sz_byte && !scrambled))
+           compile_fetchmem(map, eais);
+    } else {
+       if ((screg == -1 && (asrc & 2) == 0) || screg != -1) {
+           eais->data_reg = get_and_lock_68k_reg(map, eais->reg, eais->mode == Dreg, regprefs, 1, 2);
+           eais->data_const_off = 0;
+       }
+    }
+
+    /* Optimization */
+    if (scrambled && eais->data_reg >= 0 && !load_dest
+       && map->x86_byteorder[eais->data_reg] == BO_NORMAL
+       && eaid->size == sz_long && dtype == 0)
+       scrambled = 0;
+
+    if (regprefs != 0 && eais->data_reg >= 0 && ((1 << eais->data_reg) & regprefs) == 0) {
+       int tmpr = get_typed_x86_register(map, regprefs);
+       compile_move_reg_reg(tmpr, eais->data_reg, sz_long);
+       eais->data_reg = tmpr;
+    }
+
+    if (regprefs != 0 && eaid->data_reg >= 0 && ((1 << eaid->data_reg) & regprefs) == 0) {
+       int tmpr = get_typed_x86_register(map, regprefs);
+       compile_move_reg_reg(tmpr, eaid->data_reg, sz_long);
+       eaid->data_reg = tmpr;
+    }
+
+    /* Now set the byteorder once and for all (should already be correct for
+     * most cases) */
+    if (scrambled) {
+       if (eaid->data_reg >= 0)
+           compile_force_byteorder(map, eaid->data_reg, scrambled_bo, 0);
+       if (eais->data_reg >= 0)
+           compile_force_byteorder(map, eais->data_reg, scrambled_bo, 0);
+    } else {
+       if (eaid->data_reg >= 0)
+           compile_force_byteorder(map, eaid->data_reg, BO_NORMAL, 0);
+       if (eais->data_reg >= 0)
+           compile_force_byteorder(map, eais->data_reg, BO_NORMAL, 0);
+    }
+}
+
+static void compile_fetchea(struct register_mapping *map, struct ea_info *eainf,
+                           int eaino, int asrc)
+{
+    struct ea_info *eais = eainf + eaino;
+    int scrambled_bo = eais->size == sz_long ? BO_SWAPPED_LONG : eais->size == sz_word ? BO_SWAPPED_WORD : BO_NORMAL;
+    int i, scrambled = 0;
+    int best = 0;
+    int bestcost = -1;
+    int *ap;
+    uae_u32 *sregp = NULL;
+    int screg = -1, stype = -1;
+    int regprefs = eais->size == sz_byte ? DATA_X86_REGS : 0;
+
+    if (eais->mode == Dreg) {
+       stype = 0;
+       screg = map->dreg_map[eais->reg];
+       if (screg == -1)
+           sregp = regs.regs + eais->reg;
+    } else if (eais->mode == Areg) {
+       stype = 0;
+       screg = map->areg_map[eais->reg];
+       if (screg == -1)
+           sregp = regs.regs + 8 + eais->reg;
+    } else if (eais->data_reg == -2) {
+       stype = -2;
+    }
+
+    if (stype == -2) {
+       if ((asrc & 4) == 0)
+           compile_fetchimm(map, eais, scrambled ? scrambled_bo : BO_NORMAL);
+    } else if (stype == -1) {
+       if ((asrc & 2) == 0 || eais->size != sz_byte)
+           compile_fetchmem(map, eais);
+    } else {
+       if ((screg == -1 && (asrc & 2) == 0) || screg != -1) {
+           eais->data_reg = get_and_lock_68k_reg(map, eais->reg, eais->mode == Dreg, regprefs, 1, 2);
+           eais->data_const_off = 0;
+       }
+    }
+
+    if (eais->data_reg >= 0)
+       compile_force_byteorder(map, eais->data_reg, BO_NORMAL, 0);
+}
+
+/*
+ * compile_note_modify() should be called on destination EAs obtained from
+ * compile_loadeas(), if their value was modified (e.g. by the compile_eas()
+ * function)
+ */
+
+static void compile_note_modify(struct register_mapping *map, struct ea_info *eainf,
+                               int eaino)
+{
+    struct ea_info *eai = eainf + eaino;
+    int newr;
+    int szflag = eai->size == sz_byte ? 0 : 1;
+
+    if (eai->mode == Dreg) {
+       /* We only need to do something if we have the value in a register,
+        * otherwise, the home location was modified already */
+       if (eai->data_reg >= 0) {
+           if (eai->data_reg != map->dreg_map[eai->reg]) {
+               remove_x86r_from_cache(map, eai->data_reg, 0);
+               if (map->dreg_map[eai->reg] >= 0)
+                   remove_x86r_from_cache(map, map->dreg_map[eai->reg], 0);
+               map->x86_cache_reg[eai->data_reg] = eai->reg;
+               map->x86_cr_type[eai->data_reg] = 1;
+               map->dreg_map[eai->reg] = eai->data_reg;
+           }
+           map->x86_verified[eai->data_reg] = 0;
+           map->x86_const_offset[eai->data_reg] = eai->data_const_off;
+           map->x86_dirty[eai->data_reg] = 1;
+       }
+       return;
+    } else if (eai->mode == Areg) {
+       if (eai->size != sz_long)
+           printf("Areg put != long\n");
+
+       /* We only need to do something if we have the value in a register,
+        * otherwise, the home location was modified already */
+       if (eai->data_reg >= 0) {
+           if (eai->data_reg != map->areg_map[eai->reg]) {
+               remove_x86r_from_cache(map, eai->data_reg, 0);
+               if (map->areg_map[eai->reg] >= 0)
+                   remove_x86r_from_cache(map, map->areg_map[eai->reg], 0);
+               map->x86_cache_reg[eai->data_reg] = eai->reg;
+               map->x86_cr_type[eai->data_reg] = 0;
+               map->areg_map[eai->reg] = eai->data_reg;
+           }
+           map->x86_verified[eai->data_reg] = 0;
+           map->x86_const_offset[eai->data_reg] = eai->data_const_off;
+           map->x86_dirty[eai->data_reg] = 1;
+       }
+       return;
+    } else {
+       /* Storing to memory from reg? */
+       if (eai->data_reg >= 0) {
+           compile_offset_reg(map, eai->data_reg, eai->data_const_off);
+
+           switch (eai->size) {
+            case sz_byte: compile_force_byteorder(map, eai->data_reg, BO_NORMAL, 1); break;
+            case sz_word: compile_force_byteorder(map, eai->data_reg, BO_SWAPPED_WORD, 1); break;
+            case sz_long: compile_force_byteorder(map, eai->data_reg, BO_SWAPPED_LONG, 1); break;
+           }
+           compile_force_byteorder(map, eai->address_reg, BO_NORMAL, 0);
+           compile_move_reg_to_mem_regoffs(eai->address_reg,
+                                           (uae_u32)(eai->addr_const_off + address_space),
+                                           eai->data_reg, eai->size);
+       }
+    }
+}
+
+static void compile_storeea(struct register_mapping *map, struct ea_info *eainf,
+                           int eaino_s, int eaino_d)
+{
+    struct ea_info *eais = eainf + eaino_s;
+    struct ea_info *eaid = eainf + eaino_d;
+    int newr, cacher;
+    int szflag = eaid->size == sz_byte ? 0 : 1;
+
+    if (eaid->mode == Dreg) {
+       /* Is the reg to move from already the register cache reg for the
+        * destination? */
+       if (eais->data_reg >= 0 && eais->data_reg == map->dreg_map[eaid->reg]) {
+           map->x86_dirty[eais->data_reg] = 1; map->x86_verified[eais->data_reg] = 0;
+           map->x86_const_offset[eais->data_reg] = eais->data_const_off;
+           return;
+       }
+       /* Is the destination register in its home location? */
+       if (map->dreg_map[eaid->reg] < 0) {
+           if (eais->data_reg == -2) {
+               /* Move immediate to regs.regs */
+               if (eaid->size == sz_word) assemble(0x66);
+               assemble(0xC6 + szflag); assemble(0x05); assemble_long(regs.regs + eaid->reg);
+               switch (eaid->size) {
+                case sz_byte: assemble(eais->data_const_off); break;
+                case sz_word: assemble_uword(eais->data_const_off); break;
+                case sz_long: assemble_ulong(eais->data_const_off); break;
+               }
+           } else if (eais->data_reg == -1) {
+#if 0
+               printf("Shouldn't happen (mem-mem-move)\n");
+#endif
+               /* This _can_ happen: move.l $4,d0, if d0 isn't in the
+                * cache, will come here. But a reg will be allocated for
+                * dest. We use this. This _really_ shouldn't happen if
+                * the size isn't long. */
+               if (eaid->size != sz_long)
+                   printf("_Really_ shouldn't happen (Dreg case)\n");
+               map->x86_cache_reg[eaid->data_reg] = eaid->reg;
+               map->x86_cr_type[eaid->data_reg] = 1;
+               map->x86_const_offset[eaid->data_reg] = eaid->data_const_off;
+               map->dreg_map[eaid->reg] = eaid->data_reg;
+               map->x86_verified[eaid->data_reg] = 0;
+               goto have_cache_reg_d;
+           } else {
+               if (eais->size == sz_long) {
+                   /* Make this the new register cache reg */
+                   remove_x86r_from_cache(map, eais->data_reg, 0);
+                   map->x86_cache_reg[eais->data_reg] = eaid->reg;
+                   map->x86_cr_type[eais->data_reg] = 1;
+                   map->x86_const_offset[eais->data_reg] = eais->data_const_off;
+                   map->dreg_map[eaid->reg] = eais->data_reg;
+                   map->x86_verified[eais->data_reg] = 0;
+               } else {
+                   /* Move from reg to regs.regs */
+                   compile_force_byteorder(map, eais->data_reg, BO_NORMAL, 1);
+                   compile_offset_reg (map, eais->data_reg, eais->data_const_off);
+                   if (eaid->size == sz_word) assemble(0x66);
+                   assemble(0x88 + szflag); assemble(0x05 + 8*eais->data_reg);
+                   assemble_long(regs.regs + eaid->reg);
+               }
+           }
+       } else {
+           int destr;
+
+           have_cache_reg_d:
+
+           destr = map->dreg_map[eaid->reg];
+           if (eaid->size != sz_long)
+               compile_force_byteorder(map, destr, BO_NORMAL, 1);
+
+           if (eais->data_reg == -2) {
+               /* Move immediate to reg */
+               if (eaid->size == sz_word) assemble(0x66);
+               assemble(0xC6 + szflag); assemble(0xC0 + destr);
+               switch (eaid->size) {
+                case sz_byte: assemble(eais->data_const_off); break;
+                case sz_word: assemble_uword(eais->data_const_off); break;
+                case sz_long: assemble_ulong(eais->data_const_off); break;
+               }
+               /* normal byteorder comes either from force above or from long
+                * const move */
+               map->x86_byteorder[destr] = BO_NORMAL;
+           } else if (eais->data_reg == -1) {
+               if (eais->mode == Dreg) {
+                   compile_move_reg_from_mem_regoffs(destr, -2, (uae_u32)(regs.regs + eais->reg),
+                                                     eais->size);
+                   map->x86_byteorder[destr] = BO_NORMAL;
+               } else if (eais->mode == Areg) {
+                   compile_move_reg_from_mem_regoffs(destr, -2, (uae_u32)(regs.regs + 8 + eais->reg),
+                                                     eais->size);
+                   map->x86_byteorder[destr] = BO_NORMAL;
+               } else {
+                   /* Move mem to reg */
+                   compile_force_byteorder(map, eais->address_reg, BO_NORMAL, 0);
+                   compile_move_reg_from_mem_regoffs(destr, eais->address_reg,
+                                                     (uae_u32)(eais->addr_const_off + address_space),
+                                                     eais->size);
+
+                   switch (eais->size) {
+                    case sz_byte: map->x86_byteorder[destr] = BO_NORMAL; break;
+                    case sz_word: map->x86_byteorder[destr] = BO_SWAPPED_WORD; break;
+                    case sz_long: map->x86_byteorder[destr] = BO_SWAPPED_LONG; break;
+                   }
+               }
+           } else {
+               if (eais->size == sz_long) {
+                   /* Make this the new register cache reg */
+                   remove_x86r_from_cache(map, eais->data_reg, 0);
+                   remove_x86r_from_cache(map, destr, 0);
+                   map->x86_cache_reg[eais->data_reg] = eaid->reg;
+                   map->x86_cr_type[eais->data_reg] = 1;
+                   map->x86_const_offset[eais->data_reg] = eais->data_const_off;
+                   map->dreg_map[eaid->reg] = eais->data_reg;
+                   map->x86_verified[eais->data_reg] = 0;
+               } else {
+                   /* Move from reg to reg */
+                   compile_force_byteorder(map, eais->data_reg, BO_NORMAL, 1);
+                   compile_offset_reg (map, eais->data_reg, eais->data_const_off);
+                   if (eaid->size == sz_word) assemble(0x66);
+                   assemble(0x88 + szflag); assemble(0xC0 + destr + 8*eais->data_reg);
+               }
+           }
+       }
+
+       if (map->dreg_map[eaid->reg] >= 0)
+           map->x86_dirty[map->dreg_map[eaid->reg]] = 1;
+       return;
+    } else if (eaid->mode == Areg) {
+       if (eaid->size != sz_long)
+           printf("Areg put != long\n");
+
+       /* Is the reg to move from already the register cache reg for the
+        * destination? */
+       if (eais->data_reg >= 0 && eais->data_reg == map->areg_map[eaid->reg]) {
+           map->x86_dirty[eais->data_reg] = 1; map->x86_verified[eais->data_reg] = 0;
+           map->x86_const_offset[eais->data_reg] = eais->data_const_off;
+           return;
+       }
+       /* Is the destination register in its home location? */
+       if (map->areg_map[eaid->reg] < 0) {
+           if (eais->data_reg == -2) {
+               /* Move immediate to regs.regs */
+               assemble(0xC7); assemble(0x05); assemble_long(regs.regs + 8 + eaid->reg);
+               assemble_ulong(eais->data_const_off);
+           } else if (eais->data_reg == -1) {
+#if 0 /* see above... */
+               printf("Shouldn't happen (mem-mem-move)\n");
+#endif
+               map->x86_cache_reg[eaid->data_reg] = eaid->reg;
+               map->x86_cr_type[eaid->data_reg] = 0;
+               map->x86_const_offset[eaid->data_reg] = eaid->data_const_off;
+               map->areg_map[eaid->reg] = eaid->data_reg;
+               map->x86_verified[eaid->data_reg] = 0;
+               goto have_cache_reg_a;
+           } else {
+               /* Make this the new register cache reg */
+               remove_x86r_from_cache(map, eais->data_reg, 0);
+               map->x86_cache_reg[eais->data_reg] = eaid->reg;
+               map->x86_cr_type[eais->data_reg] = 0;
+               map->x86_const_offset[eais->data_reg] = eais->data_const_off;
+               map->areg_map[eaid->reg] = eais->data_reg;
+               map->x86_verified[eais->data_reg] = 0;
+           }
+       } else {
+           int destr;
+
+           have_cache_reg_a:
+
+           destr = map->areg_map[eaid->reg];
+           if (eaid->size != sz_long)
+               compile_force_byteorder(map, destr, BO_NORMAL, 1);
+
+           if (eais->data_reg == -2) {
+               /* Move immediate to reg */
+               assemble(0xC7); assemble(0xC0 + destr);
+               assemble_ulong(eais->data_const_off);
+
+               /* normal byteorder comes either from force above or from long
+                * const move */
+               map->x86_byteorder[destr] = BO_NORMAL;
+           } else if (eais->data_reg == -1) {
+               if (eais->mode == Dreg) {
+                   compile_move_reg_from_mem_regoffs(destr, -2, (uae_u32)(regs.regs + eais->reg),
+                                                     eais->size);
+                   map->x86_byteorder[destr] = BO_NORMAL;
+               } else if (eais->mode == Areg) {
+                   compile_move_reg_from_mem_regoffs(destr, -2, (uae_u32)(regs.regs + 8 + eais->reg),
+                                                     eais->size);
+                   map->x86_byteorder[destr] = BO_NORMAL;
+               } else {
+                   /* Move mem to reg */
+                   compile_force_byteorder(map, eais->address_reg, BO_NORMAL, 0);
+                   compile_move_reg_from_mem_regoffs(destr, eais->address_reg,
+                                                     (uae_u32)(eais->addr_const_off + address_space),
+                                                     eais->size);
+
+                   map->x86_byteorder[destr] = BO_SWAPPED_LONG;
+               }
+           } else {
+               /* Make this the new register cache reg */
+               remove_x86r_from_cache(map, eais->data_reg, 0);
+               remove_x86r_from_cache(map, destr, 0);
+               map->x86_cache_reg[eais->data_reg] = eaid->reg;
+               map->x86_cr_type[eais->data_reg] = 0;
+               map->x86_const_offset[eais->data_reg] = eais->data_const_off;
+               map->areg_map[eaid->reg] = eais->data_reg;
+               map->x86_verified[eais->data_reg] = 0;
+           }
+       }
+
+       if (map->areg_map[eaid->reg] >= 0)
+           map->x86_dirty[map->areg_map[eaid->reg]] = 1;
+       return;
+    }
+
+    if (eais->data_reg == -1)
+       printf("Storing to mem, but not from reg\n");
+    /* Correct the byteorder */
+    if (eais->data_reg != -2) {
+       compile_offset_reg(map, eais->data_reg, eais->data_const_off);
+
+       switch (eaid->size) {
+        case sz_byte: compile_force_byteorder(map, eais->data_reg, BO_NORMAL, 1); break;
+        case sz_word: compile_force_byteorder(map, eais->data_reg, BO_SWAPPED_WORD, 1); break;
+        case sz_long: compile_force_byteorder(map, eais->data_reg, BO_SWAPPED_LONG, 1); break;
+       }
+       compile_force_byteorder(map, eaid->address_reg, BO_NORMAL, 0);
+       compile_move_reg_to_mem_regoffs(eaid->address_reg,
+                                       (uae_u32)(eaid->addr_const_off + address_space),
+                                       eais->data_reg, eaid->size);
+    } else {
+       switch (eaid->size) {
+        case sz_long:
+           eais->data_const_off = (((eais->data_const_off & 0xFF000000) >> 24)
+                                | ((eais->data_const_off & 0xFF0000) >> 8)
+                                | ((eais->data_const_off & 0xFF00) << 8)
+                                | ((eais->data_const_off & 0xFF) << 24));
+           break;
+        case sz_word:
+           eais->data_const_off = (((eais->data_const_off & 0xFF00) >> 8)
+                                | ((eais->data_const_off & 0xFF) << 8));
+           break;
+       }
+       compile_force_byteorder(map, eaid->address_reg, BO_NORMAL, 0);
+       /* generate code to move valueoffset,eaoffset(eareg) */
+       switch(eaid->size) {
+        case sz_byte: assemble(0xC6); break;
+        case sz_word: assemble(0x66); /* fall through */
+        case sz_long: assemble(0xC7); break;
+       }
+       if (eaid->address_reg == -2) { /* absolute or PC-relative */
+           assemble(0x05);
+           assemble_long(eaid->addr_const_off + address_space);
+       } else {
+           assemble(0x80 + eaid->address_reg);
+           assemble_long(eaid->addr_const_off + address_space);
+       }
+       switch(eaid->size) {
+        case sz_byte: assemble(eais->data_const_off); break;
+        case sz_word: assemble_uword(eais->data_const_off); break;
+        case sz_long: assemble_ulong(eais->data_const_off); break;
+       }
+    }
+}
+
+#define CE_STACK_SIZE 1000
+
+static struct {
+    struct register_mapping map;
+    char *jmpoffs;
+    uae_u32 address;
+    int noflush:1;
+} compile_exit_stack[CE_STACK_SIZE];
+
+static int cesp;
+
+static struct register_mapping current_exit_regmap;
+
+static void generate_exit(struct register_mapping *map, int address)
+{
+    int i;
+
+    if (map != NULL)
+       sync_reg_cache (map, 1);
+    assemble(0xB8); /* movl $new_pc,%eax */
+    assemble_ulong(address);
+    assemble(0xC3); /* RET */
+}
+
+static void copy_map_with_undo(struct register_mapping *dst,
+                              struct register_mapping *src,
+                              struct pid_undo *pud)
+{
+    int i;
+    *dst = *src;
+    for (i = 0; i < pud->used; i++) {
+       int m68kr = pud->m68kr[i];
+       int x86r = pud->x86r[i];
+       int old_cr = dst->areg_map[m68kr];
+       if (old_cr != -1) {
+           dst->x86_cache_reg[old_cr] = -1;
+       }
+       dst->x86_cache_reg[x86r] = m68kr;
+       dst->areg_map[m68kr] = x86r;
+       dst->x86_cr_type[x86r] = 0;
+       dst->x86_const_offset[x86r] = pud->offs[i];
+       dst->x86_dirty[x86r] = pud->dirty[i];
+    }
+}
+
+static void unlock_pud(struct register_mapping *map, struct pid_undo *pud)
+{
+    int i;
+    for (i = 0; i < pud->used; i++) {
+       compile_unlock_reg(map, pud->x86r[i]);
+    }
+}
+
+static int exits_necessary;
+
+static void generate_possible_exit(struct register_mapping *map,
+                                  struct ea_info *eai, int iip,
+                                  struct pid_undo *pud)
+{
+    struct register_mapping exit_regmap;
+
+    if (!exits_necessary) {
+       unlock_pud(map, pud);
+       return;
+    }
+
+    compile_force_byteorder(map, eai->address_reg, BO_NORMAL, 0);
+    switch (eai->address_reg) {
+     case -1:
+       /* EA doesn't refer to memory */
+       break;
+     case -2:
+       /* Only a constant offset */
+       eai->addr_const_off &= (1<<24)-1;
+       if (!good_address_map[eai->addr_const_off]) {
+           copy_map_with_undo(&exit_regmap, map, pud);
+           generate_exit(&exit_regmap, insn_info[iip].address);
+       }
+       break;
+     default:
+       if (map->x86_verified[eai->address_reg])
+           break;
+       map->x86_verified[eai->address_reg] = 1;
+       if (cesp == CE_STACK_SIZE) {
+           copy_map_with_undo(&exit_regmap, map, pud);
+           generate_exit(&exit_regmap, insn_info[iip].address);
+           break;
+       }
+       copy_map_with_undo(&compile_exit_stack[cesp].map, map, pud);
+       compile_exit_stack[cesp].address = insn_info[iip].address;
+       assemble(0x80); assemble(0xB8 + eai->address_reg); /* cmpb $0, good_address_map(x86r) */
+       assemble_long(good_address_map + eai->addr_const_off);
+       assemble(0);
+       assemble(0x0F); assemble(0x84); /* JE finish */
+       compile_exit_stack[cesp].jmpoffs = compile_here();
+       compile_exit_stack[cesp].noflush = 0;
+       assemble_ulong(0);
+       cesp++;
+       break;
+    }
+    unlock_pud(map, pud);
+}
+
+static void finish_exits(void)
+{
+    int i;
+    for (i = 0; i < cesp; i++) {
+       char *exitpoint = compile_here();
+       char *nextpoint;
+
+       if (compile_exit_stack[i].noflush)
+           generate_exit(NULL, compile_exit_stack[i].address);
+       else
+           generate_exit(&compile_exit_stack[i].map, compile_exit_stack[i].address);
+       nextpoint = compile_here();
+       compile_org(compile_exit_stack[i].jmpoffs);
+       assemble_ulong(exitpoint - (compile_exit_stack[i].jmpoffs + 4));
+       compile_org(nextpoint);
+    }
+}
+
+static void finish_condjumps(int lastiip)
+{
+    int iip;
+    char *lastptr = compile_here();
+    for (iip = 0; iip < lastiip; iip++) {
+       char *fillin = insn_info[iip].compiled_fillin;
+       if (fillin != NULL) {
+           compile_org(insn_info[iip].compiled_fillin);
+           assemble_ulong(insn_info[insn_info[iip].jumps_to].compiled_jumpaddr - (fillin + 4));
+       }
+    }
+    compile_org(lastptr);
+}
+
+#define CC_X_FROM_86C 1
+#define CC_C_FROM_86C 2
+#define CC_Z_FROM_86Z 4
+#define CC_V_FROM_86V 8
+#define CC_N_FROM_86N 16
+#define CC_TEST_REG   32
+#define CC_Z_FROM_86C 64
+#define CC_SAHF       128
+#define CC_TEST_CONST 256
+#define CC_AFTER_RO   512
+#define CC_AFTER_ROX  1024
+
+static unsigned int cc_status;
+static int cc_reg;
+static uae_u32 cc_offset;
+static wordsizes cc_size;
+
+static void compile_do_cc_test_reg(struct register_mapping *map)
+{
+    compile_force_byteorder(map, cc_reg, BO_NORMAL, 1);
+    if (cc_offset != 0)
+       printf("Pull my finger\n");
+    if (cc_size == sz_word) /* test ccreg */
+       assemble(0x66);
+    if (cc_size == sz_byte)
+       assemble(0x84);
+    else
+       assemble(0x85);
+    assemble(0xC0 + 9*cc_reg);
+}
+
+static int compile_flush_cc_cache(struct register_mapping *map, int status,
+                                 int live_at_end, int user_follows,
+                                 int user_live_at_end, int user_ccval)
+{
+    int status_for_user = 0;
+
+    if (user_follows) {
+       int need_for_user = 0;
+       int user_flagmask = cc_flagmask_68k(user_ccval);
+
+       if (user_flagmask & CC68K_C)
+           need_for_user |= CC_C_FROM_86C;
+       if (user_flagmask & CC68K_Z)
+           need_for_user |= CC_Z_FROM_86Z;
+       if (user_flagmask & CC68K_N)
+           need_for_user |= CC_N_FROM_86N;
+       if (user_flagmask & CC68K_V)
+           need_for_user |= CC_V_FROM_86V;
+
+       /* Check whether we can satisfy the user's needs in a simple way. */
+       if ((need_for_user & status) == need_for_user)
+           status_for_user = status;
+       else if (user_flagmask == CC68K_Z && status == CC_Z_FROM_86C)
+           status_for_user = status;
+       else if (status == CC_TEST_REG && (user_flagmask & (CC68K_C|CC68K_V|CC68K_Z|CC68K_N)) != 0) {
+           if (cc_reg == -2) {
+               status_for_user = CC_TEST_CONST;
+           } else {
+               compile_do_cc_test_reg(map);
+               status_for_user = status = (CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V);
+           }
+       } else if (status == CC_AFTER_RO) {
+           /* We fake some information here... */
+           if (user_flagmask == CC68K_C && (user_live_at_end & ~CC68K_C) == 0)
+               status = status_for_user = CC_C_FROM_86C;
+           else if (((user_flagmask | user_live_at_end) & (CC68K_C|CC68K_V)) == 0) {
+               status = CC_TEST_REG; user_live_at_end = CC68K_Z|CC68K_N|CC68K_V;
+               status_for_user = (CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V);
+           } else
+               status_for_user = CC_SAHF;
+       } else if (status == CC_AFTER_ROX) {
+           if (user_flagmask == CC68K_C && (user_live_at_end & ~(CC68K_C|CC68K_X)) == 0)
+               status = status_for_user = CC_C_FROM_86C;
+           else if (((user_flagmask | user_live_at_end) & (CC68K_C|CC68K_X|CC68K_V)) == 0) {
+               status = CC_TEST_REG; user_live_at_end = CC68K_Z|CC68K_N|CC68K_V;
+               status_for_user = (CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V);
+           } else
+               status_for_user = CC_SAHF;
+       } else if (need_for_user != 0) {
+           /* No way to handle it easily */
+           status_for_user = CC_SAHF;
+       }
+       if (status_for_user != CC_SAHF)
+           live_at_end = user_live_at_end;
+    }
+
+    /*
+     * Now store the flags which are live at the end of this insn and set by
+     * us into their home locations
+     */
+    if (status == CC_TEST_REG) {
+       if ((live_at_end & (CC68K_C|CC68K_V|CC68K_Z|CC68K_N)) == 0)
+           goto all_ok;
+
+       if (cc_reg == -2) {
+           uae_u8 f = 0;
+           if (cc_size == sz_byte) {
+               f |= (cc_offset & 0x80) ? 0x80 : 0;
+               f |= (cc_offset & 0xFF) == 0 ? 0x40 : 0;
+           } else if (cc_size == sz_byte) {
+               f |= (cc_offset & 0x8000) ? 0x80 : 0;
+               f |= (cc_offset & 0xFFFF) == 0 ? 0x40 : 0;
+           } else {
+               f |= (cc_offset & 0x80000000) ? 0x80 : 0;
+               f |= (cc_offset & 0xFFFFFFFF) == 0 ? 0x40 : 0;
+           }
+           assemble(0xC7); assemble(0x05);
+           assemble_long((char*)&regflags);
+           assemble_uword(f);
+       } else {
+           int tmpr = get_free_x86_register(map, ALL_X86_REGS);
+           compile_do_cc_test_reg(map);
+
+           /* pushfl; popl tmpr; movl tempr, regflags */
+           assemble(0x9C); assemble(0x58+tmpr);
+           compile_move_reg_to_mem_regoffs(-2, (uae_u32)&regflags, tmpr, sz_long);
+       }
+    } else if (status == CC_Z_FROM_86C) {
+       if ((live_at_end & CC68K_Z) != 0) {
+           int tmpr = get_typed_x86_register(map, DATA_X86_REGS);
+           assemble(0x9C);
+           /* setnc tmpr; shl $6, tmpr; andb $~0x40, regflags; orb tmpr, regflags */
+           assemble(0x0F); assemble(0x93); assemble(0xC0 + tmpr);
+           assemble(0xC0); assemble(4*8 + 0xC0 + tmpr); assemble(6);
+           assemble(0x80); assemble(0x05+0x20); assemble_long(&regflags); assemble((uae_u8)~0x40);
+           assemble(0x08); assemble(0x05+ tmpr*8); assemble_long(&regflags);
+           assemble(0x9D);
+       }
+    } else if (status == CC_AFTER_RO || status == CC_AFTER_ROX) {
+       int tmpr = get_typed_x86_register(map, DATA_X86_REGS);
+       assemble(0x9C);
+       compile_do_cc_test_reg(map);
+       /* pushfl; popl tmpr; andl $0xff,tmpr (mask out V flag which is cleared after rotates) */
+       assemble(0x9C); assemble(0x58 + tmpr);
+       assemble(0x81); assemble(0xC0 + tmpr + 8*4); assemble_ulong(0xFF);
+       assemble(0x9D);
+       /* adc $0, tmpr */
+       assemble(0x80); assemble(0xC0 + tmpr + 8*2); assemble(0);
+       compile_move_reg_to_mem_regoffs(-2, (uae_u32)&regflags, tmpr, sz_long);
+       if (status == CC_AFTER_ROX)
+           compile_move_reg_to_mem_regoffs(-2, 4 + (uae_u32)&regflags, tmpr, sz_long);
+    } else if (status != 0) {
+       assert((status & CC_TEST_REG) == 0);
+       assert (status == (CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_X_FROM_86C | CC_V_FROM_86V)
+               || status == (CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V)
+               || status == CC_C_FROM_86C);
+
+       if ((status & CC_X_FROM_86C) == 0)
+           live_at_end &= ~CC68K_X;
+
+       if (status == CC_C_FROM_86C && (live_at_end & CC68K_C) != 0)
+           write_log ("Shouldn't be needing C here!\n");
+       else if (live_at_end) {
+           if ((live_at_end & CC68K_X) == 0)
+               status &= ~CC_X_FROM_86C;
+
+           if (live_at_end) {
+               if ((status & CC_X_FROM_86C) != 0 && live_at_end == CC68K_X) {
+                   /* SETC regflags + 4 */
+                   assemble(0x0F); assemble(0x92);
+                   assemble(0x05); assemble_long(4 + (uae_u32)&regflags);
+               } else {
+                   int tmpr = get_free_x86_register(map, ALL_X86_REGS);
+                   /* pushfl; popl tmpr; movl tempr, regflags */
+                   assemble(0x9C); assemble(0x58+tmpr);
+                   compile_move_reg_to_mem_regoffs(-2, (uae_u32)&regflags, tmpr, sz_long);
+
+                   if (status & CC_X_FROM_86C) {
+                       compile_move_reg_to_mem_regoffs(-2, 4 + (uae_u32)&regflags, tmpr, sz_word);
+                   }
+               }
+           }
+       }
+    }
+
+    all_ok:
+    return status_for_user;
+}
+
+static char *compile_condbranch(struct register_mapping *map, int iip,
+                               int new_cc_status)
+{
+    int cc = insn_info[iip].dp->cc;
+    int flagsused = cc_flagmask_68k(cc);
+    int flagsneeded = 0;
+    char *undo_pointer = compile_here();
+
+    if (flagsused & CC68K_C)
+       flagsneeded |= CC_C_FROM_86C;
+    if (flagsused & CC68K_Z)
+       flagsneeded |= CC_Z_FROM_86Z;
+    if (flagsused & CC68K_N)
+       flagsneeded |= CC_N_FROM_86N;
+    if (flagsused & CC68K_V)
+       flagsneeded |= CC_V_FROM_86V;
+
+    if (flagsneeded == 0)
+       /* Fine */;
+    else if (new_cc_status == CC_SAHF) {
+       int tmpr = get_free_x86_register(map, ALL_X86_REGS);
+       compile_move_reg_from_mem_regoffs(tmpr, -2, (uae_u32)&regflags, sz_long);
+       assemble(0x66); assemble(0x50+tmpr); assemble(0x66); assemble(0x9D);
+       new_cc_status = CC_C_FROM_86C|CC_Z_FROM_86Z|CC_N_FROM_86N|CC_V_FROM_86V;
+    } else if (new_cc_status == CC_TEST_CONST) {
+       int n,z;
+       switch(cc_size) {
+        case sz_byte: n = ((uae_s8)cc_offset) < 0; z = ((uae_s8)cc_offset) == 0; break;
+        case sz_word: n = ((uae_s16)cc_offset) < 0; z = ((uae_s16)cc_offset) == 0; break;
+        case sz_long: n = ((uae_s32)cc_offset) < 0; z = ((uae_s32)cc_offset) == 0; break;
+       }
+#define Bcc_TRUE 0
+#define Bcc_FALSE 1
+       flagsneeded = 0;
+       new_cc_status = 0;
+       switch (cc) {
+        case 2: cc = !z ? Bcc_TRUE : Bcc_FALSE; break; /* !CFLG && !ZFLG */
+        case 3: cc = z ? Bcc_TRUE : Bcc_FALSE; break; /* CFLG || ZFLG */
+        case 4: cc = Bcc_TRUE; break; /* !CFLG */
+        case 5: cc = Bcc_FALSE; break; /* CFLG */
+        case 6: cc = !z ? Bcc_TRUE : Bcc_FALSE; break; /* !ZFLG */
+        case 7: cc = z ? Bcc_TRUE : Bcc_FALSE; break; /* ZFLG */
+        case 8: cc = Bcc_TRUE; break; /* !VFLG */
+        case 9: cc = Bcc_FALSE; break; /* VFLG */
+        case 10:cc = !n ? Bcc_TRUE : Bcc_FALSE; break; /* !NFLG */
+        case 11:cc = n ? Bcc_TRUE : Bcc_FALSE; break; /* NFLG */
+        case 12:cc = !n ? Bcc_TRUE : Bcc_FALSE; break; /* NFLG == VFLG */
+        case 13:cc = n ? Bcc_TRUE : Bcc_FALSE; break; /* NFLG != VFLG */
+        case 14:cc = !n && !z ? Bcc_TRUE : Bcc_FALSE; break; /* !ZFLG && (NFLG == VFLG) */
+        case 15:cc = n || z ? Bcc_TRUE : Bcc_FALSE; break; /* ZFLG || (NFLG != VFLG) */
+       }
+    } else if (new_cc_status == CC_Z_FROM_86C) {
+       if (cc == 6 || cc == 7) {
+           cc = (cc - 2) ^ 1;
+           /* Fake... */
+           flagsneeded = new_cc_status = CC_C_FROM_86C;
+       } else if (cc != 0 && cc != 1)
+           printf("Groan!\n");
+    }
+
+    if (cc == 1)
+       return NULL;
+
+    if ((flagsneeded & new_cc_status) == flagsneeded) {
+       char *result;
+       /* We can generate a simple branch */
+       if (cc == 0)
+           assemble(0xE9);
+       else
+           assemble(0x0F);
+       switch(cc) {
+        case 2: assemble(0x87); break;          /* HI */
+        case 3: assemble(0x86); break;          /* LS */
+        case 4: assemble(0x83); break;          /* CC */
+        case 5: assemble(0x82); break;          /* CS */
+        case 6: assemble(0x85); break;          /* NE */
+        case 7: assemble(0x84); break;          /* EQ */
+        case 8: assemble(0x81); break;          /* VC */
+        case 9: assemble(0x80); break;          /* VS */
+        case 10:assemble(0x89); break;          /* PL */
+        case 11:assemble(0x88); break;          /* MI */
+        case 12:assemble(0x8D); break;          /* GE */
+        case 13:assemble(0x8C); break;          /* LT */
+        case 14:assemble(0x8F); break;          /* GT */
+        case 15:assemble(0x8E); break;          /* LE */
+       }
+       result = compile_here();
+       assemble_ulong(0);
+       return result;
+    }
+    printf("Uhhuh.\n");
+    return NULL;
+}
+
+static void compile_handle_bcc(struct register_mapping *map, int iip,
+                              int new_cc_status)
+{
+    insn_info[iip].compiled_fillin = compile_condbranch(map, iip, new_cc_status);
+}
+
+static void compile_handle_dbcc(struct register_mapping *map, int iip,
+                               int new_cc_status, int dreg)
+{
+    char *fillin1 = compile_condbranch(map, iip, new_cc_status);
+
+    /* subw $1,dreg; jnc ... */
+    assemble(0x66); assemble(0x83); assemble(0x05 + 5*8);
+    assemble_long(regs.regs + dreg);
+    assemble(1);
+    assemble(0x0F); assemble(0x83);
+    insn_info[iip].compiled_fillin = compile_here();
+    assemble_ulong(0);
+    if (fillin1 != NULL) {
+       char *oldp = compile_here();
+       compile_org(fillin1);
+       assemble_ulong(oldp - (fillin1+4));
+       compile_org(oldp);
+    }
+}
+
+static void handle_bit_insns(struct register_mapping *map, struct ea_info *eainf,
+                            int eaino_s, int eaino_d, instrmnem optype)
+{
+    struct ea_info *srcea = eainf + eaino_s, *dstea = eainf + eaino_d;
+    int code = (optype == i_BTST ? 0
+               : optype == i_BSET ? 1
+               : optype == i_BCLR ? 2
+               : /* optype == i_BCHG */ 3);
+
+    compile_fetchea(map, eainf, eaino_s, 5);
+    compile_fetchea(map, eainf, eaino_d, 3);
+
+    if (srcea->data_reg != -2) {
+       compile_force_byteorder(map, srcea->data_reg, BO_NORMAL, 0);
+       remove_x86r_from_cache(map, srcea->data_reg, 0);
+       /* andl $something,srcreg */
+       assemble(0x83); assemble(0xC0 + 4*8 + srcea->data_reg);
+       if (dstea->size == sz_byte)
+           assemble(7);
+       else
+           assemble(31);
+    } else
+       if (dstea->size == sz_byte)
+           srcea->data_const_off &= 7;
+       else
+           srcea->data_const_off &= 31;
+
+    /* Areg isn't possible here */
+    if (dstea->mode == Dreg && dstea->data_reg == -1) {
+       if (srcea->data_reg == -2) {
+           assemble(0x0F); assemble(0xBA); assemble(5 + 8*(4 + code));
+           assemble_long(regs.regs + dstea->reg);
+           assemble(srcea->data_const_off);
+       } else {
+           assemble(0x0F); assemble(0xA3 + 8*code);
+           assemble(5 + srcea->data_reg*8);
+           assemble_long(regs.regs + dstea->reg);
+       }
+    } else if (dstea->data_reg >= 0) {
+       compile_force_byteorder(map, dstea->data_reg, BO_NORMAL, 0);
+       if (srcea->data_reg == -2) {
+           assemble(0x0F); assemble(0xBA); assemble(0xC0 + dstea->data_reg + 8*(4 + code));
+           assemble(srcea->data_const_off);
+       } else {
+           assemble(0x0F); assemble(0xA3 + 8*code);
+           assemble(0xC0 + dstea->data_reg + srcea->data_reg*8);
+       }
+       if (optype != i_BTST)
+           map->x86_dirty[dstea->data_reg] = 1;
+    } else {
+       int addr_code = dstea->address_reg == -2 ? 5 : dstea->address_reg + 0x80;
+       compile_force_byteorder(map, dstea->address_reg, BO_NORMAL, 0);
+       /* We have an address in memory */
+       if (dstea->data_reg != -1)
+           printf("Things don't look good in handle_bit_insns\n");
+       if (srcea->data_reg == -2) {
+           assemble(0x0F); assemble(0xBA);
+           assemble(addr_code + 8*(4 + code));
+           assemble_long(address_space + dstea->addr_const_off);
+           assemble(srcea->data_const_off);
+       } else {
+           assemble(0x0F); assemble(0xA3 + 8*code);
+           assemble(addr_code + srcea->data_reg*8);
+           assemble_long(address_space + dstea->addr_const_off);
+       }
+
+    }
+    cc_status = CC_Z_FROM_86C;
+}
+
+static int do_rotshi = 1;
+
+static void handle_rotshi(struct register_mapping *map, int iip,
+                         uae_u8 *realpc, uaecptr current_addr, struct pid_undo *pud)
+{
+    struct ea_info eai;
+    int amode_reg = insn_info[iip].dp->sreg;
+    int amode_mode = insn_info[iip].dp->smode;
+    wordsizes size = insn_info[iip].dp->size;
+    int shiftcount;
+    int mnemo = insn_info[iip].dp->mnemo;
+    int shiftcode;
+    int locked_eax_for_sahf = 0;
+
+    switch(mnemo) {
+     case i_ASLW: shiftcount = 1; mnemo = i_ASL; break;
+     case i_ASRW: shiftcount = 1; mnemo = i_ASR; break;
+     case i_LSLW: shiftcount = 1; mnemo = i_LSL; break;
+     case i_LSRW: shiftcount = 1; mnemo = i_LSR; break;
+     case i_ROLW: shiftcount = 1; mnemo = i_ROL; break;
+     case i_RORW: shiftcount = 1; mnemo = i_ROR; break;
+     case i_ROXLW:shiftcount = 1; mnemo = i_ROXL;break;
+     case i_ROXRW:shiftcount = 1; mnemo = i_ROXR;break;
+     default:
+       amode_reg = insn_info[iip].dp->dreg;
+       amode_mode = insn_info[iip].dp->dmode;
+       shiftcount = insn_info[iip].dp->sreg;
+       break;
+    }
+    if ((insn_info[iip].flags_live_at_end & CC68K_V) != 0) {
+       if (mnemo == i_ASL) {
+           generate_exit(map, insn_info[iip].address);
+           printf("Can't handle this shift\n");
+           return;
+       } else if (mnemo == i_ASR || mnemo == i_LSR || mnemo == i_LSL) {
+           remove_x86r_from_cache(map, r_EAX, 1);
+           locked_eax_for_sahf = 1;
+           lock_reg(map, r_EAX, 2);
+       }
+
+    }
+    if (mnemo == i_ROXR || mnemo == i_ROXL) {
+       remove_x86r_from_cache(map, r_EAX, 1);
+       lock_reg(map, r_EAX, 2);
+       compile_move_reg_from_mem_regoffs(r_AH, -2, 4 + (uae_u32)&regflags, sz_byte);
+    }
+    compile_prepare_undo(map, amode_mode, amode_reg, pud);
+    compile_prepareea(map, amode_mode, amode_reg, size,
+                     &realpc, current_addr,
+                     &eai, 0, EA_LOAD|EA_STORE|EA_MODIFY, 1);
+
+    generate_possible_exit(map, &eai, iip, pud);
+
+    compile_fetchea(map, &eai, 0, 1);
+    compile_force_byteorder(map, eai.data_reg, BO_NORMAL, 0);
+
+    switch (mnemo) {
+     case i_ASL:
+       shiftcode = 4; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C;
+       break;
+     case i_LSL:
+       shiftcode = 4; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C;
+       break;
+     case i_LSR:
+       shiftcode = 5; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C;
+       break;
+     case i_ASR:
+       shiftcode = 7; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C;
+       break;
+     case i_ROR:
+       shiftcode = 1; cc_status = CC_AFTER_RO;
+       break;
+     case i_ROL:
+       shiftcode = 0; cc_status = CC_AFTER_RO;
+       break;
+     case i_ROXL:
+       shiftcode = 2; assemble(0x9E); /* SAHF */ cc_status = CC_AFTER_ROX; compile_unlock_reg(map, r_EAX);
+       break;
+     case i_ROXR:
+       shiftcode = 3; assemble(0x9E); /* SAHF */ cc_status = CC_AFTER_ROX; compile_unlock_reg(map, r_EAX);
+       break;
+    }
+
+    if (size == sz_word)
+       assemble(0x66);
+    assemble((shiftcount == 1 ? 0xD0 : 0xC0) + (size == sz_byte ? 0 : 1));
+    assemble(shiftcode*8+0xC0 + eai.data_reg);
+    if (shiftcount != 1) assemble(shiftcount);
+    cc_offset = 0; cc_size = size; cc_reg = eai.data_reg;
+
+    if (locked_eax_for_sahf) {
+       /* The trick here is that the overflow flag isn't put into AH in SAHF */
+       assemble(0x9E);
+       assemble(0x0B); assemble(9*1 + 0xC0);
+       assemble(0x9F);
+       compile_unlock_reg(map, r_EAX);
+    }
+    compile_note_modify(map, &eai, 0);
+}
+
+static void handle_rotshi_variable(struct register_mapping *map, int iip,
+                                  uae_u8 *realpc, uaecptr current_addr,
+                                  struct pid_undo *pud)
+{
+    struct ea_info eais, eaid;
+    int mnemo = insn_info[iip].dp->mnemo;
+    int shiftcode;
+    char *tmp1, *tmp2;
+    int locked_eax_for_sahf = 0;
+
+    remove_x86r_from_cache(map, r_ECX, 1);
+    lock_reg(map, r_ECX, 2);
+
+    if ((insn_info[iip].flags_live_at_end & CC68K_V) != 0) {
+       if (mnemo == i_ASL) {
+           generate_exit(map, insn_info[iip].address);
+           printf("Can't handle this shift (var)\n");
+           return;
+       } else if (mnemo == i_ASR || mnemo == i_LSR || mnemo == i_LSL) {
+           remove_x86r_from_cache(map, r_EAX, 1);
+           locked_eax_for_sahf = 1;
+           lock_reg(map, r_EAX, 2);
+       }
+
+    }
+    if (mnemo == i_ROXR || mnemo == i_ROXL) {
+       remove_x86r_from_cache(map, r_EAX, 1);
+       lock_reg(map, r_EAX, 2);
+       compile_move_reg_from_mem_regoffs(r_AH, -2, 4 + (uae_u32)&regflags,
+                                         sz_byte);
+    }
+    /* Both src and dest are Dreg modes */
+    compile_prepareea(map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg,
+                     sz_long, &realpc, current_addr,
+                     &eais, 0, EA_LOAD, 1);
+    compile_prepareea(map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg,
+                     insn_info[iip].dp->size, &realpc, current_addr,
+                     &eaid, 0, EA_LOAD|EA_STORE|EA_MODIFY, 1);
+
+    compile_fetchea(map, &eais, 0, 1);
+    compile_fetchea(map, &eaid, 1, 1);
+    compile_force_byteorder(map, eais.data_reg, BO_NORMAL, 0);
+    compile_force_byteorder(map, eaid.data_reg, BO_NORMAL, 0);
+    compile_move_reg_reg(r_ECX, eais.data_reg, sz_long);
+    /* Test against zero, and test bit 6. If 1 <= count <= 31, we can do the
+     * operation, otherwise, we have to exit */
+    assemble(0xF6); assemble(0xC0 + r_ECX); assemble(0x1F);
+    assemble(0x74); assemble(9);
+    assemble(0xF6); assemble(0xC0 + r_ECX); assemble(0x20);
+
+    assemble(0x0F); assemble(0x85); tmp1 = compile_here(); assemble_ulong(0);
+    generate_exit(map, insn_info[iip].address);
+    tmp2 = compile_here(); compile_org (tmp1); assemble_ulong((tmp2-tmp1) + 4); compile_org(tmp2);
+
+    switch (mnemo) {
+     case i_ASL:
+       shiftcode = 4; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C;
+       break;
+     case i_LSL:
+       shiftcode = 4; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C;
+       break;
+     case i_LSR:
+       shiftcode = 5; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C;
+       break;
+     case i_ASR:
+       shiftcode = 7; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C;
+       break;
+     case i_ROR:
+       shiftcode = 1; cc_status = CC_AFTER_RO;
+       break;
+     case i_ROL:
+       shiftcode = 0; cc_status = CC_AFTER_RO;
+       break;
+     case i_ROXL:
+       shiftcode = 2; assemble(0x9E); /* SAHF */ cc_status = CC_AFTER_ROX; compile_unlock_reg(map, r_EAX);
+       break;
+     case i_ROXR:
+       shiftcode = 3; assemble(0x9E); /* SAHF */ cc_status = CC_AFTER_ROX; compile_unlock_reg(map, r_EAX);
+       break;
+    }
+
+    if (insn_info[iip].dp->size == sz_word)
+       assemble(0x66);
+    assemble(0xD2 + (insn_info[iip].dp->size == sz_byte ? 0 : 1));
+    assemble(shiftcode*8+0xC0 + eaid.data_reg);
+    cc_offset = 0; cc_size = insn_info[iip].dp->size; cc_reg = eaid.data_reg;
+
+    if (locked_eax_for_sahf) {
+       /* The trick here is that the overflow flag isn't put into AH in SAHF */
+       assemble(0x9E);
+       assemble(0x0B); assemble(9*1 + 0xC0);
+       assemble(0x9F);
+       compile_unlock_reg(map, r_EAX);
+    }
+    compile_note_modify(map, &eaid, 0);
+    compile_unlock_reg(map, r_ECX);
+}
+
+static uae_u32 testmask = 0xF80000, testval = 0xF80000;
+
+static int m68k_compile_block(struct hash_block *hb)
+{
+    int movem_extra = 0;
+    int last_iip = m68k_scan_block(hb, &movem_extra);
+    struct register_mapping map;
+    int i, iip, szflag;
+    uae_u8 *realpc_start = NULL;
+    struct bb_info *current_bb;
+    int cc_status_for_bcc = CC_SAHF;
+    struct insn_reg_needs reg_needs_init;
+
+    cesp = 0;
+
+    if (n_compiled > n_max_comp)
+       return 1;
+    else if (n_compiled++ == n_max_comp)
+       printf("X\n");
+
+    cc_status = 0; compile_failure = 0;
+
+    /* Kickstart ROM address? */
+    if ((hb->he_first->addr & 0xF80000) != 0xF80000
+       && 0 && !patched_syscalls)
+       return 1;
+
+    exits_necessary = ((hb->he_first->addr & 0xF80000) == 0xF80000 || !USER_PROGRAMS_BEHAVE);
+
+    if (alloc_code (hb, last_iip + movem_extra) == NULL) {
+       hb->allocfailed = 1;
+       return 0;
+    }
+    compile_org(hb->compile_start);
+    compile_last_addr = (char *)hb->compile_start + hb->alloclen;
+
+    /* m68k_scan_block() will leave this all set up */
+    current_bb = bb_stack;
+
+    for (i = 0; i < 8; i++) {
+       map.dreg_map[i] = map.areg_map[i] = -1;
+       map.x86_dirty[i] = 0;
+       map.x86_cache_reg[i] = -1;
+       map.x86_cr_type[i] = 0;
+       map.x86_const_offset[i] = 0;
+       map.x86_verified[i] = 0;
+       map.x86_byteorder[i] = BO_NORMAL;
+    }
+
+    reg_needs_init.checkpoint_no = 0;
+    for (i = 0; i < 8; i++) {
+       reg_needs_init.dreg_needed[i] = reg_needs_init.areg_needed[i] = -1;
+       reg_needs_init.dreg_mask[i] = reg_needs_init.areg_mask[i] = ALL_X86_REGS;
+    }
+
+    for (iip = 0; iip < last_iip && !compile_failure; iip++) {
+       uae_u8 *realpc;
+       struct ea_info eainfo[8];
+       uaecptr current_addr;
+       struct pid_undo pub;
+       struct insn_reg_needs this_reg_needs = reg_needs_init;
+
+       /* Set up locks for a new insn. We don't bother to clear this
+        * properly after compiling one insn. */
+       for (i = 0; i < 8; i++) {
+           map.x86_users[i] = i == r_ESP ? 1 : 0;
+           map.x86_locked[i] = i == r_ESP ? 2 : 0;
+       }
+
+       pub.used = 0;
+       current_addr = insn_info[iip].address + 2;
+
+       if (iip == current_bb->first_iip) {
+           sync_reg_cache(&map, 1);
+           if (!quiet_compile)
+               printf("Compiling %08lx\n", current_bb->h->addr);
+
+           realpc_start = get_real_address(current_bb->h->addr);
+           current_bb->h->execute = (code_execfunc)compile_here();
+           current_bb->h->matchword = *(uae_u32 *)realpc_start;
+           cc_status_for_bcc = CC_SAHF;
+       }
+
+       realpc = realpc_start + (current_addr - current_bb->h->addr);
+
+       insn_info[iip].compiled_jumpaddr = compile_here();
+       insn_info[iip].compiled_fillin = NULL;
+
+       if (insn_info[iip].jump_target) {
+           if (cesp == CE_STACK_SIZE) {
+               generate_exit(NULL, insn_info[iip].address);
+               compile_failure = 1;
+           } else {
+               assemble(0xFE); assemble(0x05 + 8*1); assemble_long(&nr_bbs_to_run);
+               assemble(0x0F); assemble(0x84); /* JE finish */
+               compile_exit_stack[cesp].noflush = 1;
+               compile_exit_stack[cesp].address = current_bb->h;
+               compile_exit_stack[cesp].jmpoffs = compile_here();
+               assemble_ulong(0);
+               cesp++;
+           }
+       }
+       /*
+        * This will sort out all insns we can't compile, including
+        * jumps out of this block */
+       if (insn_info[iip].stop_translation == 1) {
+           generate_exit(&map, insn_info[iip].address);
+           cc_status = 0;
+       } else switch (insn_info[iip].dp->mnemo) {
+        case i_NOP:
+           cc_status = 0;
+           if (!quiet_compile)
+               printf("Compiling a NOP\n");
+           break;
+
+        case i_RTS:
+           sync_reg_cache(&map, 1);
+           lock_reg(&map, r_ECX, 2);
+           lock_reg(&map, r_EBX, 2);
+           {
+               char *tmp1, *tmp2, *tmp3;
+
+               /* fetch (A7) */
+               assemble(0x8B); assemble(0x5 + r_EBX*8); assemble_long(regs.regs + 15);
+               assemble(0x8B); assemble(0x80 + 9*r_EBX); assemble_long(address_space);
+               assemble(0x0F); /* bswapl x86r */
+               assemble(0xC8 + r_EBX);
+               /* fetch jsr_num */
+               assemble(0x8B); assemble(0x5 + r_ECX*8); assemble_long(&jsr_num);
+               assemble(0x09); assemble(0xC0 + 9*r_ECX);
+               assemble(0x0F); assemble(0x84); tmp1 = compile_here(); assemble_ulong(0);
+               assemble(0xFF); assemble(1*8 + 0xC0 + r_ECX);
+               /* cmpl %ebx,disp32(,%ecx,4) */
+               assemble(0x39); assemble(0x04 + 8*r_EBX); assemble(0x8d);
+               assemble_long(jsr_rets);
+               assemble(0x0F); assemble(0x85); tmp2 = compile_here(); assemble_ulong(0);
+               /* movl disp32(,%ecx,4),%ebx */
+               assemble(0x8B); assemble(0x04 + 8*r_EBX); assemble(0x8d);
+               assemble_long(jsr_hash);
+               /* movl execute(%ebx), %ebx */
+               assemble(0x8B); assemble(0x040 + 9*r_EBX); assemble((int)&((struct hash_entry *)0)->execute);
+               assemble(0x09); assemble(0xC0 + 9*r_EBX);
+               assemble(0x0F); assemble(0x85); tmp3 = compile_here(); assemble_ulong(0);
+               compile_org(tmp1); assemble_ulong(tmp3 - tmp1);
+               compile_org(tmp2); assemble_ulong(tmp3 - tmp2);
+               compile_org(tmp3 + 4);
+               generate_exit(&map, insn_info[iip].address);
+               tmp1 = compile_here();
+               compile_org(tmp3); assemble_ulong((tmp1-tmp3)-4);
+               compile_org(tmp1);
+               assemble(0x89); assemble(0x5 + r_ECX*8); assemble_long(&jsr_num);
+               assemble(0x83); assemble(0x05 + 5*8); assemble_long(regs.regs + 15); assemble(-4);
+               /* Off we go */
+               assemble(0xFF); assemble(4*8 + 0xC0 + r_EBX);
+           }
+           break;
+
+        case i_JMP:
+           sync_reg_cache(&map, 1);
+           compile_prepareea(&map, insn_info[iip].dp->smode,
+                             insn_info[iip].dp->sreg,
+                             insn_info[iip].dp->size, &realpc, current_addr,
+                             eainfo, 0, EA_LOAD, 1);
+           {
+               char *tmp1, *tmp2, *tmp3;
+
+               struct hash_entry *tmph;
+               if (eainfo[0].address_reg != -2 || (tmph = get_hash_for_func(eainfo[0].addr_const_off, 1)) == 0) {
+                   if (eainfo[0].address_reg != -2 && !quiet_compile)
+                       printf("Can't compile indirect JMP\n");
+                   generate_exit(&map, insn_info[iip].address);
+                   break;
+               }
+               /* check whether the destination has compiled code */
+               assemble(0x8B); assemble(r_EBX*8 + 0x05); assemble_long(&(tmph->execute));
+               assemble(0x09); assemble(0xC0 + 9*r_EBX);
+               assemble(0x0F); assemble(0x85); tmp1 = compile_here(); assemble_ulong(0);
+               generate_exit(&map, insn_info[iip].address);
+               tmp2 = compile_here(); compile_org(tmp1);
+               assemble_ulong((tmp2 - tmp1) - 4);
+               compile_org(tmp2);
+               /* Off we go */
+               assemble(0xFF); assemble(4*8 + 0xC0 + r_EBX);
+           }
+           cc_status = 0;
+           break;
+
+        case i_JSR:
+           sync_reg_cache(&map, 1);
+           lock_reg(&map, r_ECX, 2);
+           lock_reg(&map, r_EBX, 2);
+           compile_prepareea(&map, insn_info[iip].dp->smode,
+                             insn_info[iip].dp->sreg,
+                             insn_info[iip].dp->size, &realpc, current_addr,
+                             eainfo, 0, EA_LOAD, 1);
+           {
+               char *tmp1, *tmp2, *tmp3;
+
+               struct hash_entry *tmph;
+               if (eainfo[0].address_reg != -2 || (tmph = get_hash_for_func(eainfo[0].addr_const_off, 1)) == 0) {
+                   if (eainfo[0].address_reg != -2 && !quiet_compile)
+                       printf("Can't compile indirect JSR\n");
+                   generate_exit(&map, insn_info[iip].address);
+                   break;
+               }
+               assert(iip + 1 < last_iip);
+               assert(iip == current_bb->last_iip);
+               /* check whether the destination has compiled code */
+               assemble(0x8B); assemble(r_EBX*8 + 0x05); assemble_long(&(tmph->execute));
+               assemble(0x09); assemble(0xC0 + 9*r_EBX);
+               assemble(0x0F); assemble(0x84); tmp3 = compile_here(); assemble_ulong(0);
+               /* check for stack overflow */
+               assemble(0x8B); assemble(r_ECX*8 + 0x05); assemble_long(&jsr_num);
+               assemble(0xF7); assemble(0xC0+r_ECX); assemble_ulong(MAX_JSRS);
+               assemble(0x0F); assemble(0x84); tmp1 = compile_here(); assemble_ulong(0);
+               generate_exit(&map, insn_info[iip].address);
+               tmp2 = compile_here(); compile_org(tmp1); assemble_ulong((tmp2 - tmp1) - 4);
+               compile_org(tmp3); assemble_ulong(tmp1-tmp3);
+               compile_org(tmp2);
+               /* movl $something,disp32(,%ecx,4) */
+               assemble(0xC7); assemble(0x04); assemble(0x8d);
+               assemble_long(jsr_rets); assemble_ulong(insn_info[iip+1].address);
+               assemble(0xC7); assemble(0x04); assemble(0x8d);
+               assemble_long(jsr_hash); assemble_long((current_bb + 1)->h);
+               /* incl jsr_num */
+               assemble(0xFF); assemble(0x05); assemble_long(&jsr_num);
+               /* Put things on the 68k stack */
+               assemble(0x83); assemble(0x05 + 5*8); assemble_long(regs.regs + 15); assemble(4);
+               assemble(0x8B); assemble(r_ECX*8+ 0x05); assemble_long(regs.regs + 15);
+               assemble(0xC7); assemble(0x80 + r_ECX); assemble_long(address_space);
+               assemble_ulong_68k(insn_info[iip+1].address);
+               /* Off we go */
+               assemble(0xFF); assemble(4*8 + 0xC0 + r_EBX);
+           }
+           break;
+
+        case i_BSR:
+           sync_reg_cache(&map, 1);
+           lock_reg(&map, r_ECX, 2);
+           lock_reg(&map, r_EBX, 2);
+           compile_prepareea(&map, insn_info[iip].dp->smode,
+                             insn_info[iip].dp->sreg,
+                             insn_info[iip].dp->size, &realpc, current_addr,
+                             eainfo, 0, EA_LOAD, 1);
+           {
+               char *tmp1, *tmp2, *tmp3;
+               uaecptr dest = insn_info[iip].address + 2 + (uae_s32)eainfo[0].data_const_off;
+               struct hash_entry *tmph;
+               if ((tmph = get_hash_for_func(dest, 1)) == 0) {
+                   generate_exit(&map, insn_info[iip].address);
+                   break;
+               }
+               assert(iip + 1 < last_iip);
+               assert(iip == current_bb->last_iip);
+
+               /* check whether the destination has compiled code */
+               assemble(0x8B); assemble(r_EBX*8 + 0x05); assemble_long(&(tmph->execute));
+               assemble(0x09); assemble(0xC0 + 9*r_EBX);
+               assemble(0x0F); assemble(0x84); tmp3 = compile_here(); assemble_ulong(0);
+               /* check for stack overflow */
+               assemble(0x8B); assemble(r_ECX*8 + 0x05); assemble_long(&jsr_num);
+               assemble(0xF7); assemble(0xC0+r_ECX); assemble_ulong(MAX_JSRS);
+               assemble(0x0F); assemble(0x84); tmp1 = compile_here(); assemble_ulong(0);
+               generate_exit(&map, insn_info[iip].address);
+               tmp2 = compile_here(); compile_org(tmp1); assemble_ulong((tmp2 - tmp1) - 4);
+               compile_org(tmp3); assemble_ulong(tmp1-tmp3);
+               compile_org(tmp2);
+               /* movl $something,disp32(,%ecx,4) */
+               assemble(0xC7); assemble(0x04); assemble(0x8d);
+               assemble_long(jsr_rets); assemble_ulong(insn_info[iip+1].address);
+               assemble(0xC7); assemble(0x04); assemble(0x8d);
+               assemble_long(jsr_hash); assemble_long((current_bb + 1)->h);
+               /* incl jsr_num */
+               assemble(0xFF); assemble(0x05); assemble_long(&jsr_num);
+               /* Put things on the 68k stack */
+               assemble(0x83); assemble(0x05 + 5*8); assemble_long(regs.regs + 15); assemble(4);
+               assemble(0x8B); assemble(r_ECX*8+ 0x05); assemble_long(regs.regs + 15);
+               assemble(0xC7); assemble(0x80 + r_ECX); assemble_long(address_space);
+               assemble_ulong_68k(insn_info[iip+1].address);
+               /* Off we go */
+               assemble(0xFF); assemble(4*8 + 0xC0 + r_EBX);
+           }
+           break;
+
+        case i_Bcc:
+           sync_reg_cache(&map, 0);
+           compile_handle_bcc(&map, iip, cc_status_for_bcc);
+           cc_status = 0;
+           break;
+
+        case i_DBcc:
+           sync_reg_cache(&map, 0);
+           remove_x86r_from_cache(&map, map.dreg_map[insn_info[iip].dp->sreg], 1);
+           compile_handle_dbcc(&map, iip, cc_status_for_bcc,
+                               insn_info[iip].dp->sreg);
+           cc_status = 0;
+           break;
+#if 0
+        case i_Scc:
+           compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub);
+           compile_prepareea(&map, insn_info[iip].dp->smode,
+                             insn_info[iip].dp->sreg,
+                             insn_info[iip].dp->size, &realpc, current_addr,
+                             eainfo, 0, EA_STORE, 1);
+
+           generate_possible_exit(&map, eainfo, iip, &pub);
+           srcreg2 = get_;
+           compile_note_modify(&map, eainfo, 0);
+
+           cc_status = 0;
+           break;
+#endif
+        case i_ADD:
+        case i_SUB:
+        case i_CMP:
+        case i_CMPM:
+           compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub);
+           compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub);
+           compile_prepareea(&map, insn_info[iip].dp->smode,
+                             insn_info[iip].dp->sreg,
+                             insn_info[iip].dp->size, &realpc, current_addr,
+                             eainfo, 0, EA_LOAD, 1);
+           compile_prepareea(&map, insn_info[iip].dp->dmode,
+                             insn_info[iip].dp->dreg,
+                             insn_info[iip].dp->size, &realpc, current_addr,
+                             eainfo, 1,
+                             (insn_info[iip].dp->mnemo == i_ADD || insn_info[iip].dp->mnemo == i_SUB
+                              ? EA_MODIFY | EA_LOAD | EA_STORE
+                              : EA_LOAD | EA_STORE), 1);
+
+           generate_possible_exit(&map, eainfo, iip, &pub);
+           generate_possible_exit(&map, eainfo+1, iip, &pub);
+
+           compile_loadeas(&map, eainfo, 0, 1, binop_alternatives, 0, 1);
+
+           switch (insn_info[iip].dp->mnemo) {
+            case i_ADD: compile_eas(&map, eainfo, 0, 1, 0); break;
+            case i_SUB: compile_eas(&map, eainfo, 0, 1, 5); break;
+            case i_CMP: case i_CMPM: compile_eas(&map, eainfo, 0, 1, 7); break;
+           }
+
+           if (insn_info[iip].dp->mnemo != i_CMP && insn_info[iip].dp->mnemo != i_CMPM)
+               compile_note_modify(&map, eainfo, 1);
+           switch (insn_info[iip].dp->mnemo) {
+            case i_ADD:
+            case i_SUB:
+               cc_status = CC_X_FROM_86C | CC_Z_FROM_86Z | CC_C_FROM_86C | CC_V_FROM_86V | CC_N_FROM_86N;
+               break;
+            case i_CMP:
+            case i_CMPM:
+               cc_status = CC_Z_FROM_86Z | CC_C_FROM_86C | CC_V_FROM_86V | CC_N_FROM_86N;
+               break;
+           }
+           break;
+
+        case i_ADDX:
+        case i_SUBX:
+           compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub);
+           compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub);
+           compile_prepareea(&map, insn_info[iip].dp->smode,
+                             insn_info[iip].dp->sreg,
+                             insn_info[iip].dp->size, &realpc, current_addr,
+                             eainfo, 0, EA_LOAD, 1);
+           compile_prepareea(&map, insn_info[iip].dp->dmode,
+                             insn_info[iip].dp->dreg,
+                             insn_info[iip].dp->size, &realpc, current_addr,
+                             eainfo, 1, EA_MODIFY | EA_LOAD | EA_STORE, 1);
+
+           generate_possible_exit(&map, eainfo, iip, &pub);
+           generate_possible_exit(&map, eainfo+1, iip, &pub);
+
+           compile_loadeas(&map, eainfo, 0, 1, binop_alternatives, 0, 1);
+
+           /* bt $0, regflags+4 ; get carry */
+           assemble(0x0F); assemble(0xBA); assemble(0x5+4*8);
+           assemble_ulong(4 + (uae_u32)&regflags); assemble(0);
+
+           switch (insn_info[iip].dp->mnemo) {
+            case i_ADDX: compile_eas(&map, eainfo, 0, 1, 2); break;
+            case i_SUBX: compile_eas(&map, eainfo, 0, 1, 3); break;
+           }
+           compile_note_modify(&map, eainfo, 1);
+
+           if (insn_info[iip].flags_live_at_end & CC68K_Z) {
+               /* Darn. */
+               int tmpr = get_free_x86_register(&map, ALL_X86_REGS);
+               /* pushfl; popl tmpr */
+               assemble(0x9C); assemble(0x58+tmpr);
+               /* Magic! */
+               /* andl tmpr, regflags; andl $~0x40,tmpr; orl tmpr, regflags */
+               assemble(0x21); assemble(0x05 + 8*tmpr); assemble_long(&regflags);
+               assemble(0x81); assemble(0xC0 + 8*4 + tmpr); assemble_ulong(~0x40);
+               assemble(0x09); assemble(0x05 + 8*tmpr); assemble_long(&regflags);
+               compile_move_reg_to_mem_regoffs(-2, 4 + (uae_u32)&regflags, tmpr, sz_long);
+               cc_status = 0;
+           } else {
+               /* Lies! */
+               cc_status = CC_X_FROM_86C | CC_Z_FROM_86Z |CC_C_FROM_86C |CC_V_FROM_86V |CC_N_FROM_86N;
+           }
+           break;
+
+        case i_MULU:
+        case i_MULS:
+           compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub);
+           compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub);
+           compile_prepareea(&map, insn_info[iip].dp->smode,
+                             insn_info[iip].dp->sreg,
+                             insn_info[iip].dp->size, &realpc, current_addr,
+                             eainfo, 0, EA_LOAD, 1);
+           compile_prepareea(&map, insn_info[iip].dp->dmode,
+                             insn_info[iip].dp->dreg,
+                             insn_info[iip].dp->size, &realpc, current_addr,
+                             eainfo, 1, EA_MODIFY | EA_LOAD | EA_STORE, 1);
+
+           generate_possible_exit(&map, eainfo, iip, &pub);
+           generate_possible_exit(&map, eainfo+1, iip, &pub);
+
+           compile_loadeas(&map, eainfo, 0, 1, regonly_alternatives, 0, 1);
+
+           /* Extend the regs properly */
+           remove_x86r_from_cache(&map, eainfo[0].data_reg, 0);
+           switch (insn_info[iip].dp->mnemo) {
+            case i_MULU:
+               assemble(0x81); assemble(0xC0+4*8 + eainfo[0].data_reg); assemble_ulong(0xFFFF);
+               assemble(0x81); assemble(0xC0+4*8 + eainfo[1].data_reg); assemble_ulong(0xFFFF);
+               break;
+            case i_MULS:
+               assemble(0x0F); assemble(0xBF); assemble(0xC0 + 9*eainfo[0].data_reg);
+               assemble(0x0F); assemble(0xBF); assemble(0xC0 + 9*eainfo[1].data_reg);
+               break;
+           }
+           /* and multiply */
+           assemble(0x0F); assemble(0xAF); assemble(0xC0 + 8*eainfo[1].data_reg + eainfo[0].data_reg);
+           compile_note_modify(&map, eainfo, 1);
+           cc_status = CC_TEST_REG;
+           cc_reg = eainfo[1].data_reg;
+           cc_offset = 0;
+           cc_size = sz_long;
+           break;
+
+        case i_ADDA:
+        case i_SUBA:
+        case i_CMPA:
+           compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub);
+           compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub);
+           compile_prepareea(&map, insn_info[iip].dp->smode,
+                             insn_info[iip].dp->sreg,
+                             insn_info[iip].dp->size, &realpc, current_addr,
+                             eainfo, 0, EA_LOAD, 1);
+           compile_prepareea(&map, insn_info[iip].dp->dmode,
+                             insn_info[iip].dp->dreg,
+                             sz_long, &realpc, current_addr,
+                             eainfo, 1,
+                             (insn_info[iip].dp->mnemo == i_ADDA || insn_info[iip].dp->mnemo == i_SUBA
+                              ? EA_MODIFY | EA_LOAD | EA_STORE
+                              : EA_LOAD | EA_STORE),
+                             1);
+
+           generate_possible_exit(&map, eainfo, iip, &pub);
+
+           compile_loadeas(&map, eainfo, 0, 1,
+                           insn_info[iip].dp->size == sz_word ? binop_worda_alternatives : binop_alternatives,
+                           0, 1);
+
+           if (insn_info[iip].dp->size == sz_word) {
+               remove_x86r_from_cache(&map, eainfo[0].data_reg, 0);
+               compile_extend_long(&map, eainfo[0].data_reg, sz_word);
+           }
+           eainfo[0].size = sz_long;
+
+           switch (insn_info[iip].dp->mnemo) {
+            case i_ADDA: compile_eas(&map, eainfo, 0, 1, 0); break;
+            case i_SUBA: compile_eas(&map, eainfo, 0, 1, 5); break;
+            case i_CMPA: compile_eas(&map, eainfo, 0, 1, 7); break;
+           }
+
+           if (insn_info[iip].dp->mnemo == i_CMPA) {
+               cc_status = CC_Z_FROM_86Z |CC_C_FROM_86C |CC_V_FROM_86V |CC_N_FROM_86N;
+           } else {
+               compile_note_modify(&map, eainfo, 1);
+               cc_status = 0;
+           }
+           break;
+
+        case i_MOVE:
+           compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub);
+           compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub);
+           compile_prepareea(&map, insn_info[iip].dp->smode,
+                             insn_info[iip].dp->sreg,
+                             insn_info[iip].dp->size, &realpc, current_addr,
+                             eainfo, 0, EA_LOAD, 1);
+           compile_prepareea(&map, insn_info[iip].dp->dmode,
+                             insn_info[iip].dp->dreg,
+                             insn_info[iip].dp->size, &realpc, current_addr,
+                             eainfo, 1, EA_STORE, 1);
+
+           generate_possible_exit(&map, eainfo, iip, &pub);
+           generate_possible_exit(&map, eainfo + 1, iip, &pub);
+
+           compile_loadeas(&map, eainfo, 0, 1, binop_alternatives, 1, 0);
+           compile_storeea(&map, eainfo, 0, 1);
+
+           if (eainfo[0].data_reg == -2) {
+               cc_status = CC_TEST_REG;
+               cc_reg = -2;
+               cc_offset = eainfo[0].data_const_off;
+           } else if (eainfo[0].data_reg == -1) {
+               if (eainfo[1].data_reg == -1)
+                   printf("Don't know where to get flags from\n");
+               cc_status = CC_TEST_REG;
+               cc_offset = 0;
+               cc_reg = eainfo[1].data_reg;
+           } else {
+               cc_status = CC_TEST_REG;
+               cc_reg = eainfo[0].data_reg;
+               cc_offset = 0;
+           }
+           cc_size = eainfo[0].size;
+
+           break;
+
+        case i_MOVEA:
+           compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub);
+           compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub);
+           compile_prepareea(&map, insn_info[iip].dp->smode,
+                             insn_info[iip].dp->sreg,
+                             insn_info[iip].dp->size, &realpc, current_addr,
+                             eainfo, 0, EA_LOAD, 1);
+           compile_prepareea(&map, insn_info[iip].dp->dmode,
+                             insn_info[iip].dp->dreg,
+                             sz_long, &realpc, current_addr,
+                             eainfo, 1, EA_STORE, 1);
+
+           generate_possible_exit(&map, eainfo, iip, &pub);
+
+           compile_loadeas(&map, eainfo, 0, 1,
+                           insn_info[iip].dp->size == sz_word ? binop_worda_alternatives : binop_alternatives,
+                           0, 0);
+
+           if (insn_info[iip].dp->size == sz_word) {
+               remove_x86r_from_cache(&map, eainfo[0].data_reg, 0);
+               compile_extend_long(&map, eainfo[0].data_reg, sz_word);
+           }
+           eainfo[0].size = sz_long;
+
+           compile_storeea(&map, eainfo, 0, 1);
+
+           cc_status = 0;
+           break;
+
+        case i_EXG:
+           if (insn_info[iip].dp->smode != insn_info[iip].dp->dmode
+               || insn_info[iip].dp->sreg != insn_info[iip].dp->dreg)
+           {
+               compile_prepareea(&map, insn_info[iip].dp->smode,
+                                 insn_info[iip].dp->sreg,
+                                 sz_long, &realpc, current_addr,
+                                 eainfo, 0, EA_LOAD|EA_STORE, 1);
+               compile_prepareea(&map, insn_info[iip].dp->dmode,
+                                 insn_info[iip].dp->dreg,
+                                 sz_long, &realpc, current_addr,
+                                 eainfo, 1, EA_LOAD|EA_STORE, 1);
+
+               compile_loadeas(&map, eainfo, 0, 1, regonly_alternatives, 0, 1);
+               compile_storeea(&map, eainfo, 1, 0);
+               compile_storeea(&map, eainfo, 0, 1);
+           }
+
+           cc_status = 0;
+           break;
+
+        case i_LINK:
+           compile_prepare_undo(&map, Apdi, 7, &pub);
+           compile_prepareea(&map, insn_info[iip].dp->smode,
+                             insn_info[iip].dp->sreg,
+                             sz_long, &realpc, current_addr,
+                             eainfo, 0, EA_LOAD|EA_STORE, 1);
+           compile_prepareea(&map, insn_info[iip].dp->dmode,
+                             insn_info[iip].dp->dreg,
+                             sz_long, &realpc, current_addr,
+                             eainfo, 1, EA_LOAD, 1);
+           compile_prepareea(&map, Apdi, 7, sz_long, &realpc, current_addr,
+                             eainfo, 2, EA_STORE, 1);
+
+           generate_possible_exit(&map, eainfo+2, iip, &pub);
+
+           compile_fetchea(&map, eainfo, 0, 1);
+           /* we know this is a constant - no need to fetch it*/
+           /* compile_fetchea(&map, eainfo, 1); */
+           compile_storeea(&map, eainfo, 0, 2); /* An -> -(A7) */
+
+           compile_prepareea(&map, Areg, 7, sz_long, &realpc, current_addr,
+                             eainfo, 3, EA_STORE, 1);
+           compile_fetchea(&map, eainfo, 3, 1);
+           compile_storeea(&map, eainfo, 3, 0); /* A7 -> An */
+
+           /* @@@ 020 */
+           compile_prepareea(&map, Areg, 7, sz_long, &realpc, current_addr,
+                             eainfo, 4, EA_LOAD, 1);
+           compile_prepareea(&map, Areg, 7, sz_long, &realpc, current_addr,
+                             eainfo, 5, EA_STORE, 1);
+           compile_fetchea(&map, eainfo, 4, 1);
+           eainfo[4].data_const_off += (uae_s16)eainfo[1].data_const_off;
+           compile_storeea(&map, eainfo, 4, 5); /* A7+off -> A7 */
+           cc_status = 0;
+           break;
+
+        case i_UNLK:
+           compile_prepareea(&map, Areg,
+                             insn_info[iip].dp->sreg,
+                             sz_long, &realpc, current_addr,
+                             eainfo, 0, EA_LOAD, 1);
+           compile_prepareea(&map, Areg, 7, sz_long, &realpc, current_addr,
+                             eainfo, 1, EA_STORE, 1);
+
+           generate_possible_exit(&map, eainfo + 0, iip, &pub);
+
+           compile_fetchea(&map, eainfo, 0, 1);
+           compile_storeea(&map, eainfo, 0, 1);
+
+           /* The Apdi could of course point to a non-memory area, but undos
+            * are difficult here, and anyway: which program does evil hacks
+            * with UNLK? */
+           compile_prepareea(&map, Aipi, 7, sz_long, &realpc, current_addr,
+                             eainfo, 2, EA_LOAD, 1);
+           compile_prepareea(&map, insn_info[iip].dp->smode,
+                             insn_info[iip].dp->sreg,
+                             sz_long, &realpc, current_addr,
+                             eainfo, 3, EA_STORE, 1);
+           compile_fetchea(&map, eainfo, 2, 1);
+           compile_storeea(&map, eainfo, 2, 3);
+
+           cc_status = 0;
+           break;
+
+        case i_OR:
+        case i_AND:
+        case i_EOR:
+           compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub);
+           compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub);
+           compile_prepareea(&map, insn_info[iip].dp->smode,
+                             insn_info[iip].dp->sreg,
+                             insn_info[iip].dp->size, &realpc, current_addr,
+                             eainfo, 0, EA_LOAD, 1);
+           compile_prepareea(&map, insn_info[iip].dp->dmode,
+                             insn_info[iip].dp->dreg,
+                             insn_info[iip].dp->size, &realpc, current_addr,
+                             eainfo, 1, EA_MODIFY | EA_LOAD | EA_STORE, 1);
+
+           generate_possible_exit(&map, eainfo, iip, &pub);
+           generate_possible_exit(&map, eainfo + 1, iip, &pub);
+
+           compile_loadeas(&map, eainfo, 0, 1, binop_alternatives, 0, 1);
+
+           switch (insn_info[iip].dp->mnemo) {
+            case i_AND: compile_eas(&map, eainfo, 0, 1, 4); break;
+            case i_EOR: compile_eas(&map, eainfo, 0, 1, 6); break;
+            case i_OR:  compile_eas(&map, eainfo, 0, 1, 1); break;
+           }
+
+           compile_note_modify(&map, eainfo, 1);
+           cc_status = CC_Z_FROM_86Z | CC_C_FROM_86C | CC_V_FROM_86V | CC_N_FROM_86N;
+           break;
+
+        case i_TST:
+           compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub);
+           compile_prepareea(&map, insn_info[iip].dp->smode,
+                             insn_info[iip].dp->sreg,
+                             insn_info[iip].dp->size, &realpc, current_addr,
+                             eainfo, 0, EA_LOAD, 1);
+
+           generate_possible_exit(&map, eainfo, iip, &pub);
+
+           compile_fetchea(&map, eainfo, 0, 1);
+           cc_status = CC_TEST_REG;
+           cc_reg = eainfo[0].data_reg;
+           cc_offset = 0;
+           cc_size = eainfo[0].size;
+           break;
+
+        case i_CLR:
+           compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub);
+           compile_prepareea(&map, insn_info[iip].dp->smode,
+                             insn_info[iip].dp->sreg,
+                             insn_info[iip].dp->size, &realpc, current_addr,
+                             eainfo, 0, EA_STORE, 1);
+           compile_prepareea(&map, immi, 0, sz_long, &realpc, current_addr,
+                             eainfo, 1, EA_LOAD, 1);
+           generate_possible_exit(&map, eainfo + 0, iip, &pub);
+           compile_loadeas(&map, eainfo, 1, 0, binop_alternatives, 1, 0);
+           compile_storeea(&map, eainfo, 1, 0);
+
+           cc_status = CC_TEST_REG;
+           cc_reg = -2;
+           cc_offset = 0;
+           cc_size = eainfo[0].size;
+           break;
+
+        case i_EXT:
+           /* No exits, no undo - this is always a Dreg; fetchea will get it in a reg
+            * without offset */
+           compile_prepareea(&map, insn_info[iip].dp->smode,
+                             insn_info[iip].dp->sreg,
+                             insn_info[iip].dp->size == sz_long ? sz_word : sz_byte,
+                             &realpc, current_addr,
+                             eainfo, 0, EA_LOAD|EA_STORE, 1);
+           compile_fetchea(&map, eainfo, 0, 1);
+           compile_force_byteorder(&map, eainfo[0].data_reg, BO_NORMAL, 0);
+
+           if (insn_info[iip].dp->size == sz_word)
+               assemble(0x66);
+           assemble(0x0F);
+           if (insn_info[iip].dp->size == sz_long)
+               assemble(0xBF);
+           else
+               assemble(0xBE);
+
+           assemble(0xC0 + 9*eainfo[0].data_reg);
+           map.x86_dirty[eainfo[0].data_reg] = 1;
+
+           cc_status = CC_TEST_REG;
+           cc_reg = eainfo[0].data_reg;
+           cc_offset = 0;
+           cc_size = eainfo[0].size;
+           break;
+
+        case i_NOT:
+        case i_NEG:
+           szflag = insn_info[iip].dp->size == sz_byte ? 0 : 1;
+
+           compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub);
+           compile_prepareea(&map, insn_info[iip].dp->smode,
+                             insn_info[iip].dp->sreg,
+                             insn_info[iip].dp->size,
+                             &realpc, current_addr,
+                             eainfo, 0, EA_LOAD|EA_STORE, 1);
+
+           generate_possible_exit(&map, eainfo, iip, &pub);
+
+           compile_fetchea(&map, eainfo, 0, 1);
+           compile_force_byteorder(&map, eainfo[0].data_reg, BO_NORMAL, 0);
+
+           if (insn_info[iip].dp->size == sz_word)
+               assemble(0x66);
+           assemble(0xF6 + szflag);
+
+           assemble(0xC0 + eainfo[0].data_reg + 8*(insn_info[iip].dp->mnemo == i_NOT ? 2 : 3));
+           compile_note_modify(&map, eainfo, 0);
+
+           if (insn_info[iip].dp->mnemo == i_NEG)
+               cc_status = CC_Z_FROM_86Z | CC_C_FROM_86C | CC_V_FROM_86V | CC_N_FROM_86N | CC_X_FROM_86C;
+           else {
+               cc_status = CC_TEST_REG;
+               cc_reg = eainfo[0].data_reg;
+               cc_offset = 0;
+               cc_size = eainfo[0].size;
+           }
+           break;
+
+        case i_SWAP:
+           /* No exits, no undo - this is always a Dreg; fetchea will get it in a reg
+            * without offset */
+           compile_prepareea(&map, insn_info[iip].dp->smode,
+                             insn_info[iip].dp->sreg, sz_long,
+                             &realpc, current_addr,
+                             eainfo, 0, EA_LOAD|EA_STORE, 1);
+
+           compile_fetchea(&map, eainfo, 0, 1);
+           compile_force_byteorder(&map, eainfo[0].data_reg, BO_NORMAL, 0);
+
+           /* roll $16, srcreg */
+           assemble(0xC1); assemble(0xC0 + eainfo[0].data_reg); assemble(16);
+
+           /* @@@ un-shortcut */
+           map.x86_dirty[eainfo[0].data_reg] = 1;
+
+           cc_status = CC_TEST_REG;
+           cc_reg = eainfo[0].data_reg;
+           cc_offset = 0;
+           cc_size = eainfo[0].size;
+           break;
+
+        case i_LEA:
+           /* No exits necessary here: never touches memory */
+           compile_prepareea(&map, insn_info[iip].dp->smode,
+                             insn_info[iip].dp->sreg,
+                             insn_info[iip].dp->size, &realpc, current_addr,
+                             eainfo, 0, 0, 1);
+           eainfo[0].data_reg = eainfo[0].address_reg;
+           eainfo[0].data_const_off = eainfo[0].addr_const_off;
+           eainfo[0].address_reg = -1;
+           compile_get_excl_lock(&map, eainfo + 0);
+           compile_prepareea(&map, insn_info[iip].dp->dmode,
+                             insn_info[iip].dp->dreg,
+                             sz_long, &realpc, current_addr,
+                             eainfo, 1, EA_STORE, 1);
+           compile_storeea(&map, eainfo, 0, 1);
+           cc_status = 0;
+           break;
+
+        case i_PEA:
+           compile_prepare_undo(&map, Apdi, 7, &pub);
+           compile_prepareea(&map, insn_info[iip].dp->smode,
+                             insn_info[iip].dp->sreg,
+                             insn_info[iip].dp->size, &realpc, current_addr,
+                             eainfo, 0, 0, 1);
+           eainfo[0].data_reg = eainfo[0].address_reg;
+           eainfo[0].data_const_off = eainfo[0].addr_const_off;
+           eainfo[0].address_reg = -1;
+           compile_get_excl_lock(&map, eainfo + 0);
+           compile_prepareea(&map, Apdi, 7, sz_long, &realpc, current_addr,
+                             eainfo, 1, EA_STORE, 1);
+
+           generate_possible_exit(&map, eainfo+1, iip, &pub);
+           compile_storeea(&map, eainfo, 0, 1);
+
+           cc_status = 0;
+           break;
+
+        case i_MVMEL:
+           compile_prepareea(&map, insn_info[iip].dp->smode,
+                             insn_info[iip].dp->sreg,
+                             sz_word, &realpc, current_addr,
+                             eainfo, 0, EA_LOAD, 1);
+           sync_reg_cache(&map, 0);
+           {
+               /* Scratch 0 holds the registers while they are being moved
+                * from/to memory. Scratch 1 points at regs.d. Scratch 2
+                * points at the base addr in memory where to fetch data
+                * from.
+                */
+               int scratch0, scratch1, scratch2;
+               uae_u16 mask = eainfo[0].data_const_off;
+               int bits = count_bits(mask);
+               int size = insn_info[iip].dp->size == sz_long ? 4 : 2;
+               int i;
+               uae_u8 x86amode;
+               uae_u32 current_offs = 0;
+
+               compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub);
+               /* !!! Note current_addr + 2 here! */
+               compile_prepareea(&map, insn_info[iip].dp->dmode,
+                                 insn_info[iip].dp->dreg,
+                                 insn_info[iip].dp->size, &realpc, current_addr + 2,
+                                 eainfo, 1, EA_LOAD, bits);
+
+               generate_possible_exit(&map, eainfo + 1, iip, &pub);
+
+               scratch0 = get_free_x86_register(&map, ADDRESS_X86_REGS);
+               lock_reg(&map, scratch0, 2);
+               scratch1 = get_free_x86_register(&map, ADDRESS_X86_REGS);
+               lock_reg(&map, scratch1, 2);
+               scratch2 = get_free_x86_register(&map, ADDRESS_X86_REGS);
+               lock_reg(&map, scratch2, 2);
+               compile_force_byteorder(&map, eainfo[1].address_reg, BO_NORMAL, 0);
+
+               compile_lea_reg_with_offset(scratch1, -2, (uae_u32)regs.regs);
+               compile_lea_reg_with_offset(scratch2, eainfo[1].address_reg,
+                                           (uae_u32)(address_space + eainfo[1].addr_const_off));
+
+               for (i = 0; i < 16; i++) {
+                   int r68k = i;
+                   int *cache68k = i < 8 ? map.dreg_map : map.areg_map;
+                   if (mask & 1
+                       && (i < 8
+                           || insn_info[iip].dp->dmode != Aipi
+                           || (r68k & 7) != insn_info[iip].dp->dreg)) {
+                       int tmpr = cache68k[r68k & 7];
+
+                       if (tmpr != -1) {
+                           cache68k[r68k & 7] = -1;
+                           map.x86_cache_reg[tmpr] = -1;
+                       }
+                       compile_move_reg_from_mem_regoffs(scratch0, scratch2,
+                                                         current_offs, insn_info[iip].dp->size);
+                       if (size == 2) {
+                           assemble(0x66); /* rolw $8,scratch0 */
+                           assemble(0xC1);
+                           assemble(0xC0 + scratch0);
+                           assemble(8);
+                           assemble(0x0F); assemble(0xBF); /* extend */
+                           assemble(0xC0 + 9*scratch0);
+                       } else {
+                           assemble(0x0F); /* bswapl scratch0 */
+                           assemble(0xC8 + scratch0);
+                       }
+                       compile_move_reg_to_mem_regoffs(scratch1, (char *)(regs.regs + r68k) - (char *)regs.regs,
+                                                       scratch0, sz_long);
+                   }
+                   if (mask & 1)
+                       current_offs += size;
+                   mask >>= 1;
+               }
+           }
+           cc_status = 0;
+           break;
+
+        case i_MVMLE:
+           compile_prepareea(&map, insn_info[iip].dp->smode,
+                             insn_info[iip].dp->sreg,
+                             sz_word, &realpc, current_addr,
+                             eainfo, 0, EA_LOAD, 1);
+           sync_reg_cache(&map, 0);
+           {
+               int scratch0,scratch1,scratch2;
+               uae_u16 mask = eainfo[0].data_const_off;
+               int bits = count_bits(mask);
+               int size = insn_info[iip].dp->size == sz_long ? 4 : 2;
+               int i;
+               uae_u8 x86amode;
+               uae_u32 current_offs = 0;
+               int addrareg = -1;
+               if (insn_info[iip].dp->dmode == Aind
+                   || insn_info[iip].dp->dmode == Apdi
+                   || insn_info[iip].dp->dmode == Aipi
+                   || insn_info[iip].dp->dmode == Ad16
+                   || insn_info[iip].dp->dmode == Ad8r)
+               {
+                   addrareg = get_and_lock_68k_reg(&map, insn_info[iip].dp->dreg, 0, ADDRESS_X86_REGS, 1, 2);
+                   compile_force_byteorder(&map, addrareg, BO_NORMAL, 0);
+               }
+               if (insn_info[iip].dp->dmode == Apdi)
+                   mask = bitswap(mask);
+               /* !!! Note current_addr + 2 here! */
+               compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub);
+               compile_prepareea(&map, insn_info[iip].dp->dmode,
+                                 insn_info[iip].dp->dreg,
+                                 insn_info[iip].dp->size, &realpc, current_addr + 2,
+                                 eainfo, 1, EA_STORE, bits);
+
+               generate_possible_exit(&map, eainfo + 1, iip, &pub);
+
+               scratch0 = get_free_x86_register(&map, ADDRESS_X86_REGS);
+               lock_reg(&map, scratch0, 2);
+               scratch1 = get_free_x86_register(&map, ADDRESS_X86_REGS);
+               lock_reg(&map, scratch1, 2);
+               scratch2 = get_free_x86_register(&map, ADDRESS_X86_REGS);
+               lock_reg(&map, scratch2, 2);
+
+               compile_force_byteorder(&map, eainfo[1].address_reg, BO_NORMAL, 0);
+
+               compile_lea_reg_with_offset(scratch1, -2, (uae_u32)regs.regs);
+               compile_lea_reg_with_offset(scratch2, eainfo[1].address_reg,
+                                           (uae_u32)(address_space + eainfo[1].addr_const_off));
+
+               for (i = 0; i < 16; i++) {
+                   int r68k = i;
+                   if (mask & 1) {
+                       /* move from 68k reg */
+                       if (i < 8 || (i & 7) != insn_info[iip].dp->dreg || addrareg == -1) {
+                           compile_move_reg_from_mem_regoffs(scratch0, scratch1, (char *)(regs.regs + r68k) - (char *)regs.regs,
+                                                             sz_long);
+                       } else {
+                           assemble(0x8B); assemble(0xC0 + 8*scratch0 + addrareg);
+                       }
+
+                       if (size == 2) {
+                           assemble(0x66); /* rolw $8,scratch0 */
+                           assemble(0xC1);
+                           assemble(0xC0 + scratch0); assemble(8);
+                       } else {
+                           assemble(0x0F); /* bswapl scratch0 */
+                           assemble(0xC8 + scratch0);
+                       }
+                       compile_move_reg_to_mem_regoffs(scratch2, current_offs,
+                                                       scratch0, insn_info[iip].dp->size);
+                   }
+                   if (mask & 1)
+                       current_offs += size;
+                   mask >>= 1;
+               }
+           }
+           cc_status = 0;
+           break;
+#if 1
+        case i_BTST:
+        case i_BSET:
+        case i_BCLR:
+        case i_BCHG:
+           compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub);
+           compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub);
+           compile_prepareea(&map, insn_info[iip].dp->smode,
+                             insn_info[iip].dp->sreg,
+                             insn_info[iip].dp->size, &realpc, current_addr,
+                             eainfo, 0, EA_LOAD, 1);
+           compile_prepareea(&map, insn_info[iip].dp->dmode,
+                             insn_info[iip].dp->dreg,
+                             insn_info[iip].dp->size, &realpc, current_addr,
+                             eainfo, 1, 0, 1);
+
+           generate_possible_exit(&map, eainfo, iip, &pub);
+           generate_possible_exit(&map, eainfo + 1, iip, &pub);
+
+           handle_bit_insns(&map, eainfo, 0, 1, insn_info[iip].dp->mnemo);
+           break;
+
+        case i_ASL: case i_ASR: case i_LSL: case i_LSR:
+        case i_ROL: case i_ROR: case i_ROXL:case i_ROXR:
+           if (insn_info[iip].dp->smode == Dreg && do_rotshi) {
+               handle_rotshi_variable(&map, iip, realpc, current_addr, &pub);
+               break;
+           }
+           /* fall through */
+        case i_ASLW: case i_ASRW: case i_LSLW: case i_LSRW:
+        case i_ROLW: case i_RORW: case i_ROXLW:case i_ROXRW:
+           if (do_rotshi) {
+               handle_rotshi(&map, iip, realpc, current_addr, &pub);
+               break;
+           }
+#endif
+        default:
+           generate_exit(&map, insn_info[iip].address); cc_status = 0;
+           break;
+       }
+       if (insn_info[iip].ccuser_follows)
+           cc_status_for_bcc = compile_flush_cc_cache(&map, cc_status,
+                                  insn_info[iip].flags_live_at_end,
+                                  1, insn_info[iip+1].flags_live_at_end,
+                                  insn_info[iip+1].dp->cc);
+       else
+           cc_status_for_bcc = compile_flush_cc_cache(&map, cc_status,
+                                  insn_info[iip].flags_live_at_end,
+                                  0, 0, 0);
+
+       if (iip == current_bb->last_iip) {
+           current_bb++;
+       }
+    }
+    if (compile_failure)
+       goto oops;
+
+    /* Compile all exits that we prepared earlier */
+    finish_exits();
+    if (compile_failure)
+       goto oops;
+    finish_condjumps(last_iip);
+    {
+       int needed_len = compile_here() - hb->compile_start;
+       int allocsize = (needed_len + PAGE_SUBUNIT - 1) & ~(PAGE_SUBUNIT-1);
+       uae_u32 allocmask;
+       int allocbits;
+
+       allocbits = (allocsize >> SUBUNIT_ORDER);
+       allocmask = (1 << allocbits) - 1;
+       while ((allocmask & hb->page_allocmask) != allocmask)
+           allocmask <<= 1;
+       if ((hb->page_allocmask & ~allocmask) != 0 && !quiet_compile)
+           write_log ("Gaining some bits: %08lx\n", hb->page_allocmask & ~allocmask);
+       hb->cpage->allocmask &= ~hb->page_allocmask;
+       hb->page_allocmask = allocmask;
+       hb->cpage->allocmask |= allocmask;
+    }
+    return 0;
+
+    oops:
+    if (1 || !quiet_compile)
+       write_log ("Compile failed!\n");
+    hb->cpage->allocmask &= ~hb->page_allocmask;
+    hb->cpage = NULL;
+    hb->untranslatable = 1;
+    {
+       struct hash_entry *h = hb->he_first;
+
+       do {
+           h->execute = NULL;
+           h = h->next_same_block;
+       } while (h != hb->he_first);
+    }
+    return 1;
+}
+
+void compiler_init(void)
+{
+    code_init();
+    hash_init();
+    jsr_stack_init();
+}
+
+/*
+ * Why do compilers always have to be so complicated? And I thought GCC was
+ * a mess...
+ */
+
+#endif /* USE_COMPILER */
diff --git a/cpuopti.c b/cpuopti.c
new file mode 100755 (executable)
index 0000000..1582bf5
--- /dev/null
+++ b/cpuopti.c
@@ -0,0 +1,321 @@
+/*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * cpuopti.c - Small optimizer for cpu*.s files
+ *             Based on work by Tauno Taipaleenmaki
+ *
+ * Copyright 1996 Bernd Schmidt
+ */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+#include <ctype.h>
+
+struct line {
+    struct line *next, *prev;
+    int delet;
+    char *data;
+};
+
+struct func {
+    struct line *first_line, *last_line;
+    int initial_offset;
+};
+
+static void oops(void)
+{
+    fprintf(stderr, "Corrupted assembly file!\n");
+    abort();
+}
+
+/* Not strictly true to definition, as it only checks for match/no match,
+   not for ordering */
+static int mystrncmp(const char* a, const char* b, int len)
+{
+    int biswhite=0;
+    while (len) {
+       if (isspace(*a)) {
+           if (!biswhite) {
+               biswhite=isspace(*b++);
+               while (isspace(*b))
+                   b++;
+           }
+           if (!biswhite)
+               return -1;
+       }
+       else {
+           biswhite=0;
+           if (*a!=*b++)
+               return -1;
+       }
+       a++;
+       len--;
+    }
+    return 0;
+}
+
+
+static char * match(struct line *l, const char *m)
+{
+    char *str = l->data;
+    int len = strlen(m);
+    while (isspace(*str))
+       str++;
+
+    if (mystrncmp(str, m, len) != 0)
+       return NULL;
+    return str + len;
+}
+
+static int insn_references_reg (struct line *l, char *reg)
+{
+    if (reg[0] != 'e') {
+       fprintf(stderr, "Unknown register?!?\n");
+       abort();
+    }
+    if (strstr (l->data, reg) != 0)
+       return 1;
+    if (strstr (l->data, reg+1) != 0)
+       return 1;
+    if (strcmp (reg, "eax") == 0
+       && (strstr (l->data, "%al") != 0 || strstr (l->data, "%ah") != 0))
+       return 1;
+    if (strcmp (reg, "ebx") == 0
+       && (strstr (l->data, "%bl") != 0 || strstr (l->data, "%bh") != 0))
+       return 1;
+    if (strcmp (reg, "ecx") == 0
+       && (strstr (l->data, "%cl") != 0 || strstr (l->data, "%ch") != 0))
+       return 1;
+    if (strcmp (reg, "edx") == 0
+       && (strstr (l->data, "%dl") != 0 || strstr (l->data, "%dh") != 0))
+       return 1;
+    return 0;
+}
+
+static void do_function(struct func *f)
+{
+    int v;
+    int pops_at_end = 0;
+    struct line *l, *l1, *fl, *l2;
+    char *s, *s2;
+    int in_pop_area = 1;
+
+    f->initial_offset = 0;
+
+    l = f->last_line;
+    fl = f->first_line;
+
+    if (!match(l,"ret"))
+       oops();
+
+    while (!match(fl, "op_"))
+       fl = fl->next;
+    fl = fl->next;
+
+    /* Try reordering the insns at the end of the function so that the
+     * pops are all at the end. */
+    l2 = l->prev;
+    /* Tolerate one stack adjustment */
+    if (match (l2, "addl $") && strstr(l2->data, "esp") != 0)
+       l2 = l2->prev;
+    for (;;) {
+       char *forbidden_reg;
+       struct line *l3, *l4;
+
+       while (match (l2, "popl %"))
+           l2 = l2->prev;
+
+       l3 = l2;
+       for (;;) {
+           forbidden_reg = match (l3, "popl %");
+           if (forbidden_reg)
+               break;
+           if (l3 == fl)
+               goto reordered;
+           /* Jumps and labels put an end to our attempts... */
+           if (strstr (l3->data, ".L") != 0)
+               goto reordered;
+           /* Likewise accesses to the stack pointer... */
+           if (strstr (l3->data, "esp") != 0)
+               goto reordered;
+           /* Function calls... */
+           if (strstr (l3->data, "call") != 0)
+               goto reordered;
+           l3 = l3->prev;
+       }
+       if (l3 == l2)
+           abort();
+       for (l4 = l2; l4 != l3; l4 = l4->prev) {
+           /* The register may not be referenced by any of the insns that we
+            * move the popl past */
+           if (insn_references_reg (l4, forbidden_reg))
+               goto reordered;
+       }
+       l3->prev->next = l3->next;
+       l3->next->prev = l3->prev;
+       l2->next->prev = l3;
+       l3->next = l2->next;
+       l2->next = l3;
+       l3->prev = l2;
+    }
+reordered:
+
+    l = l->prev;
+
+    s = match (l, "addl $");
+    s2 = match (fl, "subl $");
+
+    l1 = l;
+    if (s == 0) {
+       char *t = match (l, "popl %");
+       if (t != 0 && (strcmp (t, "ecx") == 0 || strcmp (t, "edx") == 0)) {
+           s = "4,%esp";
+           l = l->prev;
+           t = match (l, "popl %");
+           if (t != 0 && (strcmp (t, "ecx") == 0 || strcmp (t, "edx") == 0)) {
+               s = "8,%esp";
+               l = l->prev;
+           }
+       }
+    } else {
+       l = l->prev;
+    }
+
+    if (s && s2) {
+       int v = 0;
+       if (strcmp (s, s2) != 0) {
+           fprintf (stderr, "Stack adjustment not matching.\n");
+           return;
+       }
+
+       while (isdigit(*s)) {
+           v = v * 10 + (*s) - '0';
+           s++;
+       }
+
+       if (strcmp (s, ",%esp") != 0) {
+           fprintf (stderr, "Not adjusting the stack pointer.\n");
+           return;
+       }
+       f->initial_offset = v;
+       fl->delet = 3;
+       fl = fl->next;
+       l1->delet = 2;
+       l1 = l1->prev;
+       while (l1 != l) {
+           l1->delet = 1;
+           l1 = l1->prev;
+       }
+    }
+
+    while (in_pop_area) {
+       char *popm, *pushm;
+       popm = match (l, "popl %");
+       pushm = match (fl, "pushl %");
+       if (popm && pushm && strcmp(pushm, popm) == 0) {
+           pops_at_end++;
+           fl->delet = l->delet = 1;
+       } else
+           in_pop_area = 0;
+       l = l->prev;
+       fl = fl->next;
+    }
+    if (f->initial_offset)
+       f->initial_offset += 4 * pops_at_end;
+}
+
+static void output_function(struct func *f)
+{
+    struct line *l = f->first_line;
+
+    while (l) {
+       switch (l->delet) {
+        case 1:
+           break;
+        case 0:
+           printf("%s\n", l->data);
+           break;
+        case 2:
+           if (f->initial_offset)
+               printf("\taddl $%d,%%esp\n", f->initial_offset);
+           break;
+        case 3:
+           if (f->initial_offset)
+               printf("\tsubl $%d,%%esp\n", f->initial_offset);
+           break;
+       }
+       l = l->next;
+    }
+}
+
+int main(int argc, char **argv)
+{
+    FILE *infile = stdin;
+    char tmp[4096];
+
+#ifdef __mc68000__
+    if(system("perl machdep/cpuopti")==-1) {
+       perror("perl machdep/cpuopti");
+       return 10;
+   } else return 0;
+#endif
+
+    /* For debugging... */
+    if (argc == 2)
+       infile = fopen (argv[1], "r");
+
+    for(;;) {
+       char *s;
+
+       if ((fgets(tmp, 4095, infile)) == NULL)
+           break;
+
+       s = strchr (tmp, '\n');
+       if (s != NULL)
+           *s = 0;
+
+       if (mystrncmp(tmp, ".globl op_", 10) == 0) {
+           struct line *first_line = NULL, *prev = NULL;
+           struct line **nextp = &first_line;
+           struct func f;
+           int nr_rets = 0;
+           int can_opt = 1;
+
+           do {
+               struct line *current;
+
+               if (strcmp (tmp, "#APP") != 0 && strcmp (tmp, "#NO_APP") != 0) {
+                   current = *nextp = (struct line *)malloc(sizeof (struct line));
+                   nextp = &current->next;
+                   current->prev = prev; prev = current;
+                   current->next = NULL;
+                   current->delet = 0;
+                   current->data = my_strdup (tmp);
+                   if (match (current, "movl %esp,%ebp") || match (current, "enter")) {
+                       fprintf (stderr, "GCC failed to eliminate fp: %s\n", first_line->data);
+                       can_opt = 0;
+                   }
+
+                   if (match (current, "ret"))
+                       nr_rets++;
+               }
+               if ((fgets(tmp, 4095, infile)) == NULL)
+                   oops();
+               s = strchr (tmp, '\n');
+               if (s != NULL)
+                   *s = 0;
+           } while (strncmp (tmp,".Lfe", 4) != 0);
+
+           f.first_line = first_line;
+           f.last_line = prev;
+
+           if (nr_rets == 1 && can_opt)
+               do_function(&f);
+           /*else
+               fprintf(stderr, "Too many RET instructions: %s\n", first_line->data);*/
+           output_function(&f);
+       }
+       printf("%s\n", tmp);
+    }
+    return 0;
+}
diff --git a/custom.c b/custom.c
new file mode 100755 (executable)
index 0000000..90d2bfd
--- /dev/null
+++ b/custom.c
@@ -0,0 +1,5525 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Custom chip emulation
+  *
+  * Copyright 1995-2002 Bernd Schmidt
+  * Copyright 1995 Alessandro Bissacco
+  * Copyright 2000-2004 Toni Wilen
+  */
+
+//#define CUSTOM_DEBUG
+#define DEBUG_COPPER 0
+#define SPRITE_DEBUG 0
+#define SPRITE_DEBUG_MINY 0
+#define SPRITE_DEBUG_MAXY 400
+//#define DISABLE_SPRITES
+#define SPR0_HPOS 0x15
+#define MAX_SPRITES 8
+#define SPRITE_COLLISIONS
+#define SPEEDUP
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <ctype.h>
+#include <assert.h>
+
+#include "config.h"
+#include "options.h"
+#include "threaddep/thread.h"
+#include "uae.h"
+#include "gensound.h"
+#include "sounddep/sound.h"
+#include "events.h"
+#include "memory.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "cia.h"
+#include "disk.h"
+#include "blitter.h"
+#include "xwin.h"
+#include "inputdevice.h"
+#include "audio.h"
+#include "keybuf.h"
+#include "serial.h"
+#include "osemu.h"
+#include "autoconf.h"
+#include "gui.h"
+#include "picasso96.h"
+#include "drawing.h"
+#include "savestate.h"
+#include "ar.h"
+#include "avioutput.h"
+#include "debug.h"
+#include "akiko.h"
+#include "enforcer.h"
+
+void uae_abort (const char *format,...)
+{
+    va_list parms;
+    char buffer[1000];
+
+    va_start (parms, format);
+    _vsnprintf( buffer, sizeof (buffer) -1, format, parms );
+    va_end (parms);
+    gui_message (buffer);
+    activate_debugger ();
+}
+
+#if 0
+void customhack_put (struct customhack *ch, uae_u16 v, int hpos)
+{
+    ch->v = v;
+    ch->vpos = vpos;
+    ch->hpos = hpos;
+}
+
+uae_u16 customhack_get (struct customhack *ch, int hpos)
+{
+    if (ch->vpos == vpos && ch->hpos == hpos) {
+       ch->vpos = -1;
+       return 0xffff;
+    }
+    return ch->v;
+}
+#endif
+
+static uae_u16 last_custom_value;
+
+static unsigned int n_consecutive_skipped = 0;
+static unsigned int total_skipped = 0;
+
+STATIC_INLINE void sync_copper (int hpos);
+
+/* Events */
+unsigned long int event_cycles, nextevent, is_lastline, currcycle;
+long cycles_to_next_event;
+long max_cycles_to_next_event;
+long cycles_to_hsync_event;
+
+static int rpt_did_reset;
+struct ev eventtab[ev_max];
+
+volatile frame_time_t vsynctime, vsyncmintime;
+
+int ievent_alive = 0;
+#ifdef JIT
+extern uae_u8* compiled_code;
+#endif
+
+int vpos;
+int hack_vpos;
+static uae_u16 lof;
+static int next_lineno;
+static enum nln_how nextline_how;
+static int lof_changed = 0;
+
+static uae_u32 sprtaba[256],sprtabb[256];
+static uae_u32 sprite_ab_merge[256];
+/* Tables for collision detection.  */
+static uae_u32 sprclx[16], clxmask[16];
+
+/*
+ * Hardware registers of all sorts.
+ */
+
+static int custom_wput_1 (int, uaecptr, uae_u32, int) REGPARAM;
+
+static uae_u16 cregs[256];
+
+uae_u16 intena,intreq;
+uae_u16 dmacon;
+uae_u16 adkcon; /* used by audio code */
+
+static uae_u32 cop1lc,cop2lc,copcon;
+int maxhpos = MAXHPOS_PAL;
+int maxvpos = MAXVPOS_PAL;
+int minfirstline = VBLANK_ENDLINE_PAL;
+int vblank_hz = VBLANK_HZ_PAL, fake_vblank_hz, vblank_skip;
+unsigned long syncbase;
+static int fmode;
+unsigned int beamcon0, new_beamcon0;
+uae_u16 vtotal = MAXVPOS_PAL, htotal = MAXHPOS_PAL;
+static uae_u16 hsstop, hbstrt, hbstop, vsstop, vbstrt, vbstop, hsstrt, vsstrt, hcenter;
+
+#define HSYNCTIME (maxhpos * CYCLE_UNIT);
+
+/* This is but an educated guess. It seems to be correct, but this stuff
+ * isn't documented well. */
+struct sprite {
+    uaecptr pt;
+    int xpos;
+    int vstart;
+    int vstop;
+    int armed;
+    int dmastate;
+    int dmacycle;
+};
+
+static struct sprite spr[MAX_SPRITES];
+
+static int sprite_vblank_endline = VBLANK_SPRITE_PAL;
+
+static unsigned int sprctl[MAX_SPRITES], sprpos[MAX_SPRITES];
+#ifdef AGA
+static uae_u16 sprdata[MAX_SPRITES][4], sprdatb[MAX_SPRITES][4];
+#else
+static uae_u16 sprdata[MAX_SPRITES][1], sprdatb[MAX_SPRITES][1];
+#endif
+static int sprite_last_drawn_at[MAX_SPRITES];
+static int last_sprite_point, nr_armed;
+static int sprite_width, sprres, sprite_buffer_res;
+
+#ifdef CPUEMU_6
+uae_u8 cycle_line[256];
+#endif
+
+static uae_u32 bpl1dat, bpl2dat, bpl3dat, bpl4dat, bpl5dat, bpl6dat, bpl7dat, bpl8dat;
+static uae_s16 bpl1mod, bpl2mod;
+
+static uaecptr bplpt[8];
+uae_u8 *real_bplpt[8];
+/* Used as a debugging aid, to offset any bitplane temporarily.  */
+int bpl_off[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+/*static int blitcount[256];  blitter debug */
+
+static struct color_entry current_colors;
+static unsigned int bplcon0, bplcon1, bplcon2, bplcon3, bplcon4;
+static unsigned int diwstrt, diwstop, diwhigh;
+static int diwhigh_written;
+static unsigned int ddfstrt, ddfstop, ddfstrt_old, ddfstrt_old_hpos, ddfstrt_old_vpos;
+static int ddf_change;
+static unsigned int bplcon0_at_start;
+
+/* The display and data fetch windows */
+
+enum diw_states
+{
+    DIW_waiting_start, DIW_waiting_stop
+};
+
+int plffirstline, plflastline;
+int plfstrt, plfstop;
+static int last_diw_pix_hpos, last_ddf_pix_hpos, last_decide_line_hpos;
+static int last_fetch_hpos, last_sprite_hpos;
+int diwfirstword, diwlastword;
+static enum diw_states diwstate, hdiwstate, ddfstate;
+
+/* Sprite collisions */
+static unsigned int clxdat, clxcon, clxcon2, clxcon_bpl_enable, clxcon_bpl_match;
+
+enum copper_states {
+    COP_stop,
+    COP_read1_in2,
+    COP_read1_wr_in4,
+    COP_read1_wr_in2,
+    COP_read1,
+    COP_read2_wr_in2,
+    COP_read2,
+    COP_bltwait,
+    COP_wait_in4,
+    COP_wait_in2,
+    COP_skip_in4,
+    COP_skip_in2,
+    COP_wait1,
+    COP_wait,
+    COP_skip1,
+    COP_strobe_delay
+};
+
+struct copper {
+    /* The current instruction words.  */
+    unsigned int i1, i2;
+    unsigned int saved_i1, saved_i2;
+    enum copper_states state;
+    /* Instruction pointer.  */
+    uaecptr ip, saved_ip;
+    int hpos, vpos;
+    unsigned int ignore_next;
+    int vcmp, hcmp;
+
+    /* When we schedule a copper event, knowing a few things about the future
+       of the copper list can reduce the number of sync_with_cpu calls
+       dramatically.  */
+    unsigned int first_sync;
+    unsigned int regtypes_modified;
+    int strobe; /* COPJMP1 / COPJMP2 accessed */
+};
+
+#define REGTYPE_NONE 0
+#define REGTYPE_COLOR 1
+#define REGTYPE_SPRITE 2
+#define REGTYPE_PLANE 4
+#define REGTYPE_BLITTER 8
+#define REGTYPE_JOYPORT 16
+#define REGTYPE_DISK 32
+#define REGTYPE_POS 64
+#define REGTYPE_AUDIO 128
+
+#define REGTYPE_ALL 255
+/* Always set in regtypes_modified, to enable a forced update when things like
+   DMACON, BPLCON0, COPJMPx get written.  */
+#define REGTYPE_FORCE 256
+
+
+static unsigned int regtypes[512];
+
+static struct copper cop_state;
+static int copper_enabled_thisline;
+static int cop_min_waittime;
+
+/*
+ * Statistics
+ */
+
+/* Used also by bebox.cpp */
+unsigned long int frametime = 0, lastframetime = 0, timeframes = 0, hsync_counter = 0;
+unsigned long int idletime;
+int bogusframe;
+
+#if DEBUG_COPPER
+/* 10000 isn't enough!  */
+#define NR_COPPER_RECORDS 40000
+#else
+#define NR_COPPER_RECORDS 1
+#endif
+
+/* Record copper activity for the debugger.  */
+struct cop_record
+{
+  int hpos, vpos;
+  uaecptr addr;
+};
+static struct cop_record cop_record[2][NR_COPPER_RECORDS];
+static int nr_cop_records[2];
+static int curr_cop_set;
+
+/* Recording of custom chip register changes.  */
+static int current_change_set;
+
+#ifdef OS_WITHOUT_MEMORY_MANAGEMENT
+/* sam: Those arrays uses around 7Mb of BSS... That seems  */
+/* too much for AmigaDOS (uae crashes as soon as one loads */
+/* it. So I use a different strategy here (realloc the     */
+/* arrays when needed. That strategy might be usefull for  */
+/* computer with low memory.                               */
+struct sprite_entry  *sprite_entries[2];
+struct color_change *color_changes[2];
+static int max_sprite_entry = 400;
+static int delta_sprite_entry = 0;
+static int max_color_change = 400;
+static int delta_color_change = 0;
+#else
+struct sprite_entry sprite_entries[2][MAX_SPR_PIXELS / 16];
+struct color_change color_changes[2][MAX_REG_CHANGE];
+#endif
+
+struct decision line_decisions[2 * (MAXVPOS + 1) + 1];
+struct draw_info line_drawinfo[2][2 * (MAXVPOS + 1) + 1];
+struct color_entry color_tables[2][(MAXVPOS + 1) * 2];
+
+static int next_sprite_entry = 0;
+static int prev_next_sprite_entry;
+static int next_sprite_forced = 1;
+
+struct sprite_entry *curr_sprite_entries, *prev_sprite_entries;
+struct color_change *curr_color_changes, *prev_color_changes;
+struct draw_info *curr_drawinfo, *prev_drawinfo;
+struct color_entry *curr_color_tables, *prev_color_tables;
+
+static int next_color_change;
+static int next_color_entry, remembered_color_entry;
+static int color_src_match, color_dest_match, color_compare_result;
+
+static uae_u32 thisline_changed;
+
+#ifdef SMART_UPDATE
+#define MARK_LINE_CHANGED do { thisline_changed = 1; } while (0)
+#else
+#define MARK_LINE_CHANGED do { ; } while (0)
+#endif
+
+static struct decision thisline_decision;
+static int passed_plfstop, fetch_cycle;
+
+enum fetchstate {
+    fetch_not_started,
+    fetch_started,
+    fetch_was_plane0
+} fetch_state;
+
+/*
+ * helper functions
+ */
+
+uae_u32 get_copper_address (int copno)
+{
+    switch (copno) {
+    case 1: return cop1lc;
+    case 2: return cop2lc;
+    default: return 0;
+    }
+}
+
+STATIC_INLINE void record_copper (uaecptr addr, int hpos, int vpos)
+{
+#if DEBUG_COPPER
+    int t = nr_cop_records[curr_cop_set];
+    if (t < NR_COPPER_RECORDS) {
+       cop_record[curr_cop_set][t].addr = addr;
+       cop_record[curr_cop_set][t].hpos = hpos;
+       cop_record[curr_cop_set][t].vpos = vpos;
+       nr_cop_records[curr_cop_set] = t + 1;
+    }
+#endif
+}
+
+int find_copper_record (uaecptr addr, int *phpos, int *pvpos)
+{
+    int s = curr_cop_set ^ 1;
+    int t = nr_cop_records[s];
+    int i;
+    for (i = 0; i < t; i++) {
+       if (cop_record[s][i].addr == addr) {
+           *phpos = cop_record[s][i].hpos;
+           *pvpos = cop_record[s][i].vpos;
+           return 1;
+       }
+    }
+    return 0;
+}
+
+int rpt_available = 0;
+
+void reset_frame_rate_hack (void)
+{
+    if (currprefs.m68k_speed != -1)
+       return;
+
+    if (! rpt_available) {
+       currprefs.m68k_speed = 0;
+       return;
+    }
+
+    rpt_did_reset = 1;
+    is_lastline = 0;
+    vsyncmintime = read_processor_time() + vsynctime;
+    write_log ("Resetting frame rate hack\n");
+}
+
+STATIC_INLINE void setclr (uae_u16 *p, uae_u16 val)
+{
+    if (val & 0x8000)
+       *p |= val & 0x7FFF;
+    else
+       *p &= ~val;
+}
+
+STATIC_INLINE int current_hpos (void)
+{
+    return (get_cycles () - eventtab[ev_hsync].oldcycles) / CYCLE_UNIT;
+}
+
+STATIC_INLINE uae_u8 *pfield_xlateptr (uaecptr plpt, int bytecount)
+{
+    if (!chipmem_bank.check (plpt, bytecount)) {
+       static int count = 0;
+       if (!count)
+           count++, write_log ("Warning: Bad playfield pointer\n");
+       return NULL;
+    }
+    return chipmem_bank.xlateaddr (plpt);
+}
+
+STATIC_INLINE void docols (struct color_entry *colentry)
+{
+    int i;
+
+#ifdef AGA
+    if (currprefs.chipset_mask & CSMASK_AGA) {
+       for (i = 0; i < 256; i++) {
+           int v = color_reg_get (colentry, i);
+           if (v < 0 || v > 16777215)
+               continue;
+           colentry->acolors[i] = CONVERT_RGB (v);
+       }
+    } else {
+#endif
+        for (i = 0; i < 32; i++) {
+           int v = color_reg_get (colentry, i);
+           if (v < 0 || v > 4095)
+               continue;
+           colentry->acolors[i] = xcolors[v];
+       }
+#ifdef AGA
+    }
+#endif
+}
+
+void notice_new_xcolors (void)
+{
+    int i;
+
+    docols(&current_colors);
+/*    docols(&colors_for_drawing);*/
+    for (i = 0; i < (MAXVPOS + 1)*2; i++) {
+       docols(color_tables[0]+i);
+       docols(color_tables[1]+i);
+    }
+}
+
+static void do_sprites (int currhp);
+
+static void remember_ctable (void)
+{
+    if (remembered_color_entry == -1) {
+       /* The colors changed since we last recorded a color map. Record a
+        * new one. */
+       color_reg_cpy (curr_color_tables + next_color_entry, &current_colors);
+       remembered_color_entry = next_color_entry++;
+    }
+    thisline_decision.ctable = remembered_color_entry;
+    if (color_src_match == -1 || color_dest_match != remembered_color_entry
+       || line_decisions[next_lineno].ctable != color_src_match)
+    {
+       /* The remembered comparison didn't help us - need to compare again. */
+       int oldctable = line_decisions[next_lineno].ctable;
+       int changed = 0;
+
+       if (oldctable == -1) {
+           changed = 1;
+           color_src_match = color_dest_match = -1;
+       } else {
+           color_compare_result = color_reg_cmp (&prev_color_tables[oldctable], &current_colors) != 0;
+           if (color_compare_result)
+               changed = 1;
+           color_src_match = oldctable;
+           color_dest_match = remembered_color_entry;
+       }
+       thisline_changed |= changed;
+    } else {
+       /* We know the result of the comparison */
+       if (color_compare_result)
+           thisline_changed = 1;
+    }
+}
+
+static void remember_ctable_for_border (void)
+{
+    remember_ctable ();
+}
+
+/* Called to determine the state of the horizontal display window state
+ * machine at the current position. It might have changed since we last
+ * checked.  */
+static void decide_diw (int hpos)
+{
+    int pix_hpos = coord_diw_to_window_x (hpos == 227 ? 455 : hpos * 2); /* (227.5*2 = 455) */
+    if (hdiwstate == DIW_waiting_start && thisline_decision.diwfirstword == -1
+       && pix_hpos >= diwfirstword && last_diw_pix_hpos < diwfirstword)
+    {
+       thisline_decision.diwfirstword = diwfirstword < 0 ? 0 : diwfirstword;
+       hdiwstate = DIW_waiting_stop;
+    }
+    if (hdiwstate == DIW_waiting_stop && thisline_decision.diwlastword == -1
+       && pix_hpos >= diwlastword && last_diw_pix_hpos < diwlastword)
+    {
+       thisline_decision.diwlastword = diwlastword < 0 ? 0 : diwlastword;
+       hdiwstate = DIW_waiting_start;
+    }
+    last_diw_pix_hpos = pix_hpos;
+}
+
+/* The HRM says 0xD8, but that can't work... */
+#define HARD_DDF_STOP 0xd4
+#define HARD_DDF_START 0x18
+
+static void add_modulos (void)
+{
+    int m1, m2;
+
+    if (fmode & 0x4000) {
+       if (((diwstrt >> 8) ^ vpos) & 1)
+           m1 = m2 = bpl2mod;
+       else
+           m1 = m2 = bpl1mod;
+    } else {
+       m1 = bpl1mod;
+       m2 = bpl2mod;
+    }
+
+    switch (GET_PLANES (bplcon0)) {
+#ifdef AGA
+       case 8: bplpt[7] += m2;
+       case 7: bplpt[6] += m1;
+#endif
+       case 6: bplpt[5] += m2;
+       case 5: bplpt[4] += m1;
+       case 4: bplpt[3] += m2;
+       case 3: bplpt[2] += m1;
+       case 2: bplpt[1] += m2;
+       case 1: bplpt[0] += m1;
+    }
+}
+
+static void finish_playfield_line (void)
+{
+    /* The latter condition might be able to happen in interlaced frames. */
+    if (vpos >= minfirstline && (thisframe_first_drawn_line == -1 || vpos < thisframe_first_drawn_line))
+       thisframe_first_drawn_line = vpos;
+    thisframe_last_drawn_line = vpos;
+
+    /* These are for comparison. */
+    thisline_decision.bplcon0 = bplcon0;
+    thisline_decision.bplcon2 = bplcon2;
+#ifdef AGA
+    thisline_decision.bplcon3 = bplcon3;
+    thisline_decision.bplcon4 = bplcon4;
+#endif
+
+#ifdef SMART_UPDATE
+    if (line_decisions[next_lineno].plflinelen != thisline_decision.plflinelen
+       || line_decisions[next_lineno].plfleft != thisline_decision.plfleft
+       || line_decisions[next_lineno].bplcon0 != thisline_decision.bplcon0
+       || line_decisions[next_lineno].bplcon2 != thisline_decision.bplcon2
+#ifdef AGA
+       || line_decisions[next_lineno].bplcon3 != thisline_decision.bplcon3
+       || line_decisions[next_lineno].bplcon4 != thisline_decision.bplcon4
+#endif
+       )
+#endif /* SMART_UPDATE */
+       thisline_changed = 1;
+}
+
+static int fetchmode;
+
+/* The fetch unit mainly controls ddf stop.  It's the number of cycles that
+   are contained in an indivisible block during which ddf is active.  E.g.
+   if DDF starts at 0x30, and fetchunit is 8, then possible DDF stops are
+   0x30 + n * 8.  */
+static int fetchunit, fetchunit_mask;
+/* The delay before fetching the same bitplane again.  Can be larger than
+   the number of bitplanes; in that case there are additional empty cycles
+   with no data fetch (this happens for high fetchmodes and low
+   resolutions).  */
+static int fetchstart, fetchstart_shift, fetchstart_mask;
+/* fm_maxplane holds the maximum number of planes possible with the current
+   fetch mode.  This selects the cycle diagram:
+   8 planes: 73516240
+   4 planes: 3120
+   2 planes: 10.  */
+static int fm_maxplane, fm_maxplane_shift;
+
+/* The corresponding values, by fetchmode and display resolution.  */
+static int fetchunits[] = { 8,8,8,0, 16,8,8,0, 32,16,8,0 };
+static int fetchstarts[] = { 3,2,1,0, 4,3,2,0, 5,4,3,0 };
+static int fm_maxplanes[] = { 3,2,1,0, 3,3,2,0, 3,3,3,0 }; 
+
+static uae_u8 cycle_diagram_table[3][3][9][32];
+static uae_u8 cycle_diagram_free_cycles[3][3][9];
+static uae_u8 cycle_diagram_total_cycles[3][3][9];
+static uae_u8 *curr_diagram;
+static uae_u8 cycle_sequences[3*8] = { 2,1,2,1,2,1,2,1, 4,2,3,1,4,2,3,1, 8,4,6,2,7,3,5,1 };
+
+static void debug_cycle_diagram(void)
+{
+    int fm, res, planes, cycle, v;
+    char aa;
+
+    for (fm = 0; fm < 3; fm++) {
+       write_log ("FMODE %d\n=======\n", fm);
+       for (res = 0; res <= 2; res++) {
+           for (planes = 0; planes <= 8; planes++) {
+               write_log("%d: ",planes);
+               for (cycle = 0; cycle < 32; cycle++) {
+                   v=cycle_diagram_table[fm][res][planes][cycle];
+                   if (v==0) aa='-'; else if(v>0) aa='1'; else aa='X';
+                   write_log("%c",aa);
+               }
+               write_log(" %d:%d\n", 
+                   cycle_diagram_free_cycles[fm][res][planes], cycle_diagram_total_cycles[fm][res][planes]);
+           }
+           write_log("\n");
+       }
+    }
+    fm=0;
+}
+
+static void create_cycle_diagram_table(void)
+{
+    int fm, res, cycle, planes, v;
+    int fetch_start, max_planes, freecycles;
+    uae_u8 *cycle_sequence;
+
+    for (fm = 0; fm <= 2; fm++) {
+       for (res = 0; res <= 2; res++) {
+           max_planes = fm_maxplanes[fm * 4 + res];
+           fetch_start = 1 << fetchstarts[fm * 4 + res];
+           cycle_sequence = &cycle_sequences[(max_planes - 1) * 8];
+           max_planes = 1 << max_planes;
+           for (planes = 0; planes <= 8; planes++) {
+               freecycles = 0;
+               for (cycle = 0; cycle < 32; cycle++)
+                   cycle_diagram_table[fm][res][planes][cycle] = -1;
+               if (planes <= max_planes) {
+                   for (cycle = 0; cycle < fetch_start; cycle++) {
+                       if (cycle < max_planes && planes >= cycle_sequence[cycle & 7]) {
+                           v = 1;
+                       } else {
+                           v = 0;
+                           freecycles++;
+                       }
+                       cycle_diagram_table[fm][res][planes][cycle] = v;
+                   }
+               }
+               cycle_diagram_free_cycles[fm][res][planes] = freecycles;
+               cycle_diagram_total_cycles[fm][res][planes] = fetch_start;
+           }
+       }
+    }
+#if 0
+    debug_cycle_diagram ();
+#endif
+}
+
+
+/* Used by the copper.  */
+static int estimated_last_fetch_cycle;
+static int cycle_diagram_shift;
+
+static void estimate_last_fetch_cycle (int hpos)
+{
+    int fetchunit = fetchunits[fetchmode * 4 + GET_RES (bplcon0)];
+
+    if (! passed_plfstop) {
+       int stop = plfstop < hpos || plfstop > HARD_DDF_STOP ? HARD_DDF_STOP : plfstop;
+       /* We know that fetching is up-to-date up until hpos, so we can use fetch_cycle.  */
+       int fetch_cycle_at_stop = fetch_cycle + (stop - hpos);
+       int starting_last_block_at = (fetch_cycle_at_stop + fetchunit - 1) & ~(fetchunit - 1);
+
+       estimated_last_fetch_cycle = hpos + (starting_last_block_at - fetch_cycle) + fetchunit;
+    } else {
+       int starting_last_block_at = (fetch_cycle + fetchunit - 1) & ~(fetchunit - 1);
+       if (passed_plfstop == 2)
+           starting_last_block_at -= fetchunit;
+
+       estimated_last_fetch_cycle = hpos + (starting_last_block_at - fetch_cycle) + fetchunit;
+    }
+}
+
+static uae_u32 outword[MAX_PLANES];
+static int out_nbits, out_offs;
+static uae_u32 todisplay[MAX_PLANES][4];
+static uae_u32 fetched[MAX_PLANES];
+#ifdef AGA
+static uae_u32 fetched_aga0[MAX_PLANES];
+static uae_u32 fetched_aga1[MAX_PLANES];
+#endif
+
+/* Expansions from bplcon0/bplcon1.  */
+static int toscr_res, toscr_res_first, toscr_nr_planes, fetchwidth;
+static int toscr_delay1x, toscr_delay2x, toscr_delay1, toscr_delay2;
+
+/* The number of bits left from the last fetched words.  
+   This is an optimization - conceptually, we have to make sure the result is
+   the same as if toscr is called in each clock cycle.  However, to speed this
+   up, we accumulate display data; this variable keeps track of how much. 
+   Thus, once we do call toscr_nbits (which happens at least every 16 bits),
+   we can do more work at once.  */
+static int toscr_nbits;
+
+static int delayoffset;
+
+STATIC_INLINE void compute_delay_offset (void)
+{
+    delayoffset = ((plfstrt - HARD_DDF_START) & fetchstart_mask) << 1;
+    if (delayoffset & 8)
+       delayoffset = 8;
+    else if (delayoffset & 16)
+       delayoffset = 16;
+    else if (delayoffset & 32)
+       delayoffset = 32;
+    else
+       delayoffset = 0;
+}
+
+static void expand_fmodes (void)
+{
+    int res = GET_RES(bplcon0);
+    int fm = fetchmode;
+    fetchunit = fetchunits[fm * 4 + res];
+    fetchunit_mask = fetchunit - 1;
+    fetchstart_shift = fetchstarts[fm * 4 + res];
+    fetchstart = 1 << fetchstart_shift;
+    fetchstart_mask = fetchstart - 1;
+    fm_maxplane_shift = fm_maxplanes[fm * 4 + res];
+    fm_maxplane = 1 << fm_maxplane_shift;
+    curr_diagram = cycle_diagram_table[fm][res][GET_PLANES (bplcon0)];
+}
+
+static int maxplanes_ocs[]={ 6,4,0,0 };
+static int maxplanes_ecs[]={ 6,4,2,0 };
+static int maxplanes_aga[]={ 8,4,2,0, 8,8,4,0, 8,8,8,0 };
+
+/* Expand bplcon0/bplcon1 into the toscr_xxx variables.  */
+static void compute_toscr_delay_1 (void)
+{
+    int delay1 = (bplcon1 & 0x0f) | ((bplcon1 & 0x0c00) >> 6);
+    int delay2 = ((bplcon1 >> 4) & 0x0f) | (((bplcon1 >> 4) & 0x0c00) >> 6);
+    int delaymask;
+    int fetchwidth = 16 << fetchmode;
+
+    delay1 += delayoffset;
+    delay2 += delayoffset;
+    delaymask = (fetchwidth - 1) >> toscr_res;
+    toscr_delay1x = (delay1 & delaymask) << toscr_res;
+    toscr_delay2x = (delay2 & delaymask) << toscr_res;
+}
+
+static int get_maxplanes (int res)
+{
+    int *planes;
+    if (currprefs.chipset_mask & CSMASK_AGA)
+       planes = maxplanes_aga;
+    else if (! (currprefs.chipset_mask & CSMASK_ECS_DENISE))
+       planes = maxplanes_ocs;
+    else
+       planes = maxplanes_ecs;
+    return planes[fetchmode * 4 + res];
+}
+
+static void compute_toscr_delay (int hpos)
+{
+    int v = bplcon0;
+    /* Disable bitplane DMA if planes > maxplanes.  This is needed e.g. by the
+       Sanity WOC demo (at the "Party Effect").  */
+    if (GET_PLANES(v) > get_maxplanes (GET_RES(v)))
+       v &= ~0x7010;
+    toscr_res = GET_RES (v);
+    toscr_nr_planes = GET_PLANES (v);
+    compute_toscr_delay_1 ();
+}
+
+STATIC_INLINE void maybe_first_bpl1dat (int hpos)
+{
+    if (thisline_decision.plfleft == -1) {
+       thisline_decision.plfleft = hpos;
+       compute_delay_offset ();
+       compute_toscr_delay_1 ();
+    }
+}
+
+STATIC_INLINE void fetch (int nr, int fm)
+{
+    uaecptr p;
+    if (nr >= toscr_nr_planes)
+       return;
+    p = bplpt[nr] + bpl_off[nr];
+    switch (fm) {
+    case 0:
+       fetched[nr] = last_custom_value = chipmem_wget (p);
+       bplpt[nr] += 2;
+       break;
+#ifdef AGA
+    case 1:
+       fetched_aga0[nr] = chipmem_lget (p);
+       last_custom_value = (uae_u16)fetched_aga0[nr];
+       bplpt[nr] += 4;
+       break;
+    case 2:
+       fetched_aga1[nr] = chipmem_lget (p);
+       fetched_aga0[nr] = chipmem_lget (p + 4);
+       last_custom_value = (uae_u16)fetched_aga0[nr];
+       bplpt[nr] += 8;
+       break;
+#endif
+    }
+    if (passed_plfstop == 2 && fetch_cycle >= (fetch_cycle & ~fetchunit_mask) + fetchunit - fetchstart) {
+       int mod;
+       if (fmode & 0x4000) {
+           if (((diwstrt >> 8) ^ vpos) & 1)
+               mod = bpl2mod;
+           else
+               mod = bpl1mod;
+       } else if (nr & 1)
+           mod = bpl2mod;
+       else
+           mod = bpl1mod;
+       bplpt[nr] += mod;
+    }
+    if (nr == 0)
+       fetch_state = fetch_was_plane0;
+}
+
+static void clear_fetchbuffer (uae_u32 *ptr, int nwords)
+{
+    int i;
+
+    if (! thisline_changed)
+       for (i = 0; i < nwords; i++)
+           if (ptr[i]) {
+               thisline_changed = 1;
+               break;
+           }
+
+    memset (ptr, 0, nwords * 4);
+}
+
+static void update_toscr_planes (void)
+{
+    if (toscr_nr_planes > thisline_decision.nr_planes) {
+       int j;
+       for (j = thisline_decision.nr_planes; j < toscr_nr_planes; j++)
+           clear_fetchbuffer ((uae_u32 *)(line_data[next_lineno] + 2 * MAX_WORDS_PER_LINE * j), out_offs);
+#if 0
+       if (thisline_decision.nr_planes > 0)
+           printf ("Planes from %d to %d\n", thisline_decision.nr_planes, toscr_nr_planes);
+#endif
+       thisline_decision.nr_planes = toscr_nr_planes;
+    }
+}
+
+STATIC_INLINE void toscr_3_ecs (int nbits)
+{
+    int delay1 = toscr_delay1;
+    int delay2 = toscr_delay2;
+    int i;
+    uae_u32 mask = 0xFFFF >> (16 - nbits);
+
+    for (i = 0; i < toscr_nr_planes; i += 2) {
+       outword[i] <<= nbits;
+       outword[i] |= (todisplay[i][0] >> (16 - nbits + delay1)) & mask;
+       todisplay[i][0] <<= nbits;
+    }
+    for (i = 1; i < toscr_nr_planes; i += 2) {
+       outword[i] <<= nbits;
+       outword[i] |= (todisplay[i][0] >> (16 - nbits + delay2)) & mask;
+       todisplay[i][0] <<= nbits;
+    }
+}
+
+STATIC_INLINE void shift32plus (uae_u32 *p, int n)
+{
+    uae_u32 t = p[1];
+    t <<= n;
+    t |= p[0] >> (32 - n);
+    p[1] = t;
+}
+
+#ifdef AGA
+STATIC_INLINE void aga_shift (uae_u32 *p, int n, int fm)
+{
+    if (fm == 2) {
+       shift32plus (p + 2, n);
+       shift32plus (p + 1, n);
+    }
+    shift32plus (p + 0, n);
+    p[0] <<= n;
+}
+
+STATIC_INLINE void toscr_3_aga (int nbits, int fm)
+{
+    int delay1 = toscr_delay1;
+    int delay2 = toscr_delay2;
+    int i;
+    uae_u32 mask = 0xFFFF >> (16 - nbits);
+
+    {
+       int offs = (16 << fm) - nbits + delay1;
+       int off1 = offs >> 5;
+       if (off1 == 3)
+           off1 = 2;
+       offs -= off1 * 32;
+       for (i = 0; i < toscr_nr_planes; i += 2) {
+           uae_u32 t0 = todisplay[i][off1];
+           uae_u32 t1 = todisplay[i][off1 + 1];
+           uae_u64 t = (((uae_u64)t1) << 32) | t0;
+           outword[i] <<= nbits;
+           outword[i] |= (t >> offs) & mask;
+           aga_shift (todisplay[i], nbits, fm);
+       }
+    }
+    {
+       int offs = (16 << fm) - nbits + delay2;
+       int off1 = offs >> 5;
+       if (off1 == 3)
+           off1 = 2;
+       offs -= off1 * 32;
+       for (i = 1; i < toscr_nr_planes; i += 2) {
+           uae_u32 t0 = todisplay[i][off1];
+           uae_u32 t1 = todisplay[i][off1 + 1];
+           uae_u64 t = (((uae_u64)t1) << 32) | t0;
+           outword[i] <<= nbits;
+           outword[i] |= (t >> offs) & mask;
+           aga_shift (todisplay[i], nbits, fm);
+       }
+    }
+}
+
+#endif
+
+static void toscr_2_0 (int nbits) { toscr_3_ecs (nbits); }
+#ifdef AGA
+static void toscr_2_1 (int nbits) { toscr_3_aga (nbits, 1); }
+static void toscr_2_2 (int nbits) { toscr_3_aga (nbits, 2); }
+#endif
+
+STATIC_INLINE void toscr_1 (int nbits, int fm)
+{
+    switch (fm) {
+    case 0:
+       toscr_2_0 (nbits);
+       break;
+#ifdef AGA
+    case 1:
+       toscr_2_1 (nbits);
+       break;
+    case 2:
+       toscr_2_2 (nbits);
+       break;
+#endif
+    }
+    out_nbits += nbits;
+    if (out_nbits == 32) {
+       int i;
+       uae_u8 *dataptr = line_data[next_lineno] + out_offs * 4;
+       for (i = 0; i < thisline_decision.nr_planes; i++) {
+           uae_u32 *dataptr32 = (uae_u32 *)dataptr;
+           if (i >= toscr_nr_planes)
+               outword[i] = 0;
+           if (*dataptr32 != outword[i])
+               thisline_changed = 1;
+           *dataptr32 = outword[i];
+           dataptr += MAX_WORDS_PER_LINE * 2;
+       }
+       out_offs++;
+       out_nbits = 0;
+    }
+}
+
+static void toscr_fm0 (int);
+static void toscr_fm1 (int);
+static void toscr_fm2 (int);
+
+STATIC_INLINE void toscr (int nbits, int fm)
+{
+    switch (fm) {
+    case 0: toscr_fm0 (nbits); break;
+#ifdef AGA
+    case 1: toscr_fm1 (nbits); break;
+    case 2: toscr_fm2 (nbits); break;
+#endif
+    }
+}
+
+STATIC_INLINE void toscr_0 (int nbits, int fm)
+{
+    int t;
+
+    if (nbits > 16) {
+       toscr (16, fm);
+       nbits -= 16;
+    }
+
+    t = 32 - out_nbits;
+    if (t < nbits) {
+       toscr_1 (t, fm);
+       nbits -= t;
+    }
+    toscr_1 (nbits, fm);
+}
+
+static void toscr_fm0 (int nbits) { toscr_0 (nbits, 0); }
+static void toscr_fm1 (int nbits) { toscr_0 (nbits, 1); }
+static void toscr_fm2 (int nbits) { toscr_0 (nbits, 2); }
+
+static int flush_plane_data (int fm)
+{
+    int i = 0;
+    int fetchwidth = 16 << fm;
+
+    if (out_nbits <= 16) {
+       i += 16;
+       toscr_1 (16, fm);
+    }
+    if (out_nbits != 0) {
+       i += 32 - out_nbits;
+       toscr_1 (32 - out_nbits, fm);
+    }
+    i += 32;
+
+    toscr_1 (16, fm);
+    toscr_1 (16, fm);
+    return i >> (1 + toscr_res);
+}
+
+STATIC_INLINE void flush_display (int fm)
+{
+    if (toscr_nbits > 0 && thisline_decision.plfleft != -1)
+       toscr (toscr_nbits, fm);
+    toscr_nbits = 0;
+}
+
+/* Called when all planes have been fetched, i.e. when a new block
+   of data is available to be displayed.  The data in fetched[] is
+   moved into todisplay[].  */
+STATIC_INLINE void beginning_of_plane_block (int pos, int fm)
+{
+    int i;
+
+    flush_display (fm);
+    if (fm == 0)
+       for (i = 0; i < MAX_PLANES; i++)
+           todisplay[i][0] |= fetched[i];
+#ifdef AGA
+    else
+       for (i = 0; i < MAX_PLANES; i++) {
+           if (fm == 2)
+               todisplay[i][1] = fetched_aga1[i];
+           todisplay[i][0] = fetched_aga0[i];
+       }
+#endif
+    maybe_first_bpl1dat (pos);
+    toscr_delay1 = toscr_delay1x;
+    toscr_delay2 = toscr_delay2x;
+}
+
+#ifdef SPEEDUP
+
+/* The usual inlining tricks - don't touch unless you know what you are doing.  */
+STATIC_INLINE void long_fetch_ecs (int plane, int nwords, int weird_number_of_bits, int dma)
+{
+    uae_u16 *real_pt = (uae_u16 *)pfield_xlateptr (bplpt[plane] + bpl_off[plane], nwords * 2);
+    int delay = (plane & 1) ? toscr_delay2 : toscr_delay1;
+    int tmp_nbits = out_nbits;
+    uae_u32 shiftbuffer = todisplay[plane][0];
+    uae_u32 outval = outword[plane];
+    uae_u32 fetchval = fetched[plane];
+    uae_u32 *dataptr = (uae_u32 *)(line_data[next_lineno] + 2 * plane * MAX_WORDS_PER_LINE + 4 * out_offs);
+
+    if (dma)
+       bplpt[plane] += nwords * 2;
+
+    if (real_pt == 0)
+       /* @@@ Don't do this, fall back on chipmem_wget instead.  */
+       return;
+
+    while (nwords > 0) {
+       int bits_left = 32 - tmp_nbits;
+       uae_u32 t;
+
+       shiftbuffer |= fetchval;
+
+       t = (shiftbuffer >> delay) & 0xFFFF;
+
+       if (weird_number_of_bits && bits_left < 16) {
+           outval <<= bits_left;
+           outval |= t >> (16 - bits_left);
+           thisline_changed |= *dataptr ^ outval;
+           *dataptr++ = outval;
+
+           outval = t;
+           tmp_nbits = 16 - bits_left;
+           shiftbuffer <<= 16;
+       } else {
+           outval = (outval << 16) | t;
+           shiftbuffer <<= 16;
+           tmp_nbits += 16;
+           if (tmp_nbits == 32) {
+               thisline_changed |= *dataptr ^ outval;
+               *dataptr++ = outval;
+               tmp_nbits = 0;
+           }
+       }
+       nwords--;
+       if (dma) {
+           fetchval = do_get_mem_word (real_pt);
+           real_pt++;
+       }
+    }
+    fetched[plane] = fetchval;
+    todisplay[plane][0] = shiftbuffer;
+    outword[plane] = outval;
+}
+
+#ifdef AGA
+STATIC_INLINE void long_fetch_aga (int plane, int nwords, int weird_number_of_bits, int fm, int dma)
+{
+    uae_u32 *real_pt = (uae_u32 *)pfield_xlateptr (bplpt[plane] + bpl_off[plane], nwords * 2);
+    int delay = (plane & 1) ? toscr_delay2 : toscr_delay1;
+    int tmp_nbits = out_nbits;
+    uae_u32 *shiftbuffer = todisplay[plane];
+    uae_u32 outval = outword[plane];
+    uae_u32 fetchval0 = fetched_aga0[plane];
+    uae_u32 fetchval1 = fetched_aga1[plane];
+    uae_u32 *dataptr = (uae_u32 *)(line_data[next_lineno] + 2 * plane * MAX_WORDS_PER_LINE + 4 * out_offs);
+    int offs = (16 << fm) - 16 + delay;
+    int off1 = offs >> 5;
+    if (off1 == 3)
+       off1 = 2;
+    offs -= off1 * 32;
+
+    if (dma)
+       bplpt[plane] += nwords * 2;
+
+    if (real_pt == 0)
+       /* @@@ Don't do this, fall back on chipmem_wget instead.  */
+       return;
+
+    while (nwords > 0) {
+       int i;
+
+       shiftbuffer[0] = fetchval0;
+       if (fm == 2)
+           shiftbuffer[1] = fetchval1;
+
+       for (i = 0; i < (1 << fm); i++) {
+           int bits_left = 32 - tmp_nbits;
+
+           uae_u32 t0 = shiftbuffer[off1];
+           uae_u32 t1 = shiftbuffer[off1 + 1];
+           uae_u64 t = (((uae_u64)t1) << 32) | t0;
+
+           t0 = (uae_u32)((t >> offs) & 0xFFFF);
+
+           if (weird_number_of_bits && bits_left < 16) {
+               outval <<= bits_left;
+               outval |= t0 >> (16 - bits_left);
+
+               thisline_changed |= *dataptr ^ outval;
+               *dataptr++ = outval;
+
+               outval = t0;
+               tmp_nbits = 16 - bits_left;
+               aga_shift (shiftbuffer, 16, fm);
+           } else {
+               outval = (outval << 16) | t0;
+               aga_shift (shiftbuffer, 16, fm);
+               tmp_nbits += 16;
+               if (tmp_nbits == 32) {
+                   thisline_changed |= *dataptr ^ outval;
+                   *dataptr++ = outval;
+                   tmp_nbits = 0;
+               }
+           }
+       }
+
+       nwords -= 1 << fm;
+
+       if (dma) {
+           if (fm == 1)
+               fetchval0 = do_get_mem_long (real_pt);
+           else {
+               fetchval1 = do_get_mem_long (real_pt);
+               fetchval0 = do_get_mem_long (real_pt + 1);
+           }
+           real_pt += fm;
+       }
+    }
+    fetched_aga0[plane] = fetchval0;
+    fetched_aga1[plane] = fetchval1;
+    outword[plane] = outval;
+}
+#endif
+
+static void long_fetch_ecs_0 (int hpos, int nwords, int dma) { long_fetch_ecs (hpos, nwords, 0, dma); }
+static void long_fetch_ecs_1 (int hpos, int nwords, int dma) { long_fetch_ecs (hpos, nwords, 1, dma); }
+#ifdef AGA
+static void long_fetch_aga_1_0 (int hpos, int nwords, int dma) { long_fetch_aga (hpos, nwords,  0, 1, dma); }
+static void long_fetch_aga_1_1 (int hpos, int nwords, int dma) { long_fetch_aga (hpos, nwords,  1, 1, dma); }
+static void long_fetch_aga_2_0 (int hpos, int nwords, int dma) { long_fetch_aga (hpos, nwords,  0, 2, dma); }
+static void long_fetch_aga_2_1 (int hpos, int nwords, int dma) { long_fetch_aga (hpos, nwords,  1, 2, dma); }
+#endif
+
+static void do_long_fetch (int hpos, int nwords, int dma, int fm)
+{
+    int i;
+
+    flush_display (fm);
+    switch (fm) {
+    case 0:
+       if (out_nbits & 15) {
+           for (i = 0; i < toscr_nr_planes; i++)
+               long_fetch_ecs_1 (i, nwords, dma);
+       } else {
+           for (i = 0; i < toscr_nr_planes; i++)
+               long_fetch_ecs_0 (i, nwords, dma);
+       }
+       break;
+#ifdef AGA
+    case 1:
+       if (out_nbits & 15) {
+           for (i = 0; i < toscr_nr_planes; i++)
+               long_fetch_aga_1_1 (i, nwords, dma);
+       } else {
+           for (i = 0; i < toscr_nr_planes; i++)
+               long_fetch_aga_1_0 (i, nwords, dma);
+       }
+       break;
+    case 2:
+       if (out_nbits & 15) {
+           for (i = 0; i < toscr_nr_planes; i++)
+               long_fetch_aga_2_1 (i, nwords, dma);
+       } else {
+           for (i = 0; i < toscr_nr_planes; i++)
+               long_fetch_aga_2_0 (i, nwords, dma);
+       }
+       break;
+#endif
+    }
+
+    out_nbits += nwords * 16;
+    out_offs += out_nbits >> 5;
+    out_nbits &= 31;
+
+    if (dma && toscr_nr_planes > 0)
+       fetch_state = fetch_was_plane0;
+}
+
+#endif
+
+/* make sure fetch that goes beyond maxhpos is finished */
+static void finish_final_fetch (int i, int fm)
+{
+    if (thisline_decision.plfleft == -1)
+       return;
+    if (passed_plfstop == 3)
+       return;
+    passed_plfstop = 3;
+    ddfstate = DIW_waiting_start;
+    i += flush_plane_data (fm);
+    thisline_decision.plfright = i;
+    thisline_decision.plflinelen = out_offs;
+    thisline_decision.bplres = toscr_res_first;
+    finish_playfield_line ();
+}
+
+STATIC_INLINE int one_fetch_cycle_0 (int i, int ddfstop_to_test, int dma, int fm)
+{
+    if (! passed_plfstop && i == ddfstop_to_test)
+       passed_plfstop = 1;
+
+    if ((fetch_cycle & fetchunit_mask) == 0) {
+       if (passed_plfstop == 2) {
+           finish_final_fetch (i, fm);
+           return 1;
+       }
+       if (passed_plfstop)
+           passed_plfstop++;
+    }
+
+    if (dma) {
+       /* fetchstart_mask can be larger than fm_maxplane if FMODE > 0.  This means
+          that the remaining cycles are idle; we'll fall through the whole switch
+          without doing anything.  */
+       int cycle_start = fetch_cycle & fetchstart_mask;
+       switch (fm_maxplane) {
+       case 8:
+           switch (cycle_start) {
+           case 0: fetch (7, fm); break;
+           case 1: fetch (3, fm); break;
+           case 2: fetch (5, fm); break;
+           case 3: fetch (1, fm); break;
+           case 4: fetch (6, fm); break;
+           case 5: fetch (2, fm); break;
+           case 6: fetch (4, fm); break;
+           case 7: fetch (0, fm); break;
+           }
+           break;
+       case 4:
+           switch (cycle_start) {
+           case 0: fetch (3, fm); break;
+           case 1: fetch (1, fm); break;
+           case 2: fetch (2, fm); break;
+           case 3: fetch (0, fm); break;
+           }
+           break;
+       case 2:
+           switch (cycle_start) {
+           case 0: fetch (1, fm); break;
+           case 1: fetch (0, fm); break;
+           }
+           break;
+       }
+    }
+    fetch_cycle++;
+    toscr_nbits += 2 << toscr_res;
+
+    if (toscr_nbits == 16)
+       flush_display (fm);
+    if (toscr_nbits > 16)
+       uae_abort ("toscr_nbits > 16 (%d)", toscr_nbits);
+
+    return 0;
+}
+
+static int one_fetch_cycle_fm0 (int i, int ddfstop_to_test, int dma) { return one_fetch_cycle_0 (i, ddfstop_to_test, dma, 0); }
+static int one_fetch_cycle_fm1 (int i, int ddfstop_to_test, int dma) { return one_fetch_cycle_0 (i, ddfstop_to_test, dma, 1); }
+static int one_fetch_cycle_fm2 (int i, int ddfstop_to_test, int dma) { return one_fetch_cycle_0 (i, ddfstop_to_test, dma, 2); }
+
+STATIC_INLINE int one_fetch_cycle (int i, int ddfstop_to_test, int dma, int fm)
+{
+    switch (fm) {
+    case 0: return one_fetch_cycle_fm0 (i, ddfstop_to_test, dma);
+#ifdef AGA
+    case 1: return one_fetch_cycle_fm1 (i, ddfstop_to_test, dma);
+    case 2: return one_fetch_cycle_fm2 (i, ddfstop_to_test, dma);
+#endif
+    default: uae_abort ("fm corrupt"); return 0;
+    }
+}
+
+STATIC_INLINE void update_fetch (int until, int fm)
+{
+    int pos;
+    int dma = dmaen (DMA_BITPLANE);
+
+    int ddfstop_to_test;
+
+    if (framecnt != 0 || passed_plfstop == 3)
+       return;
+
+    /* We need an explicit test against HARD_DDF_STOP here to guard against
+       programs that move the DDFSTOP before our current position before we
+       reach it.  */
+    ddfstop_to_test = HARD_DDF_STOP;
+    if (ddfstop >= last_fetch_hpos && plfstop < ddfstop_to_test)
+       ddfstop_to_test = plfstop;
+
+    compute_toscr_delay (last_fetch_hpos);
+    update_toscr_planes ();
+
+    pos = last_fetch_hpos;
+    cycle_diagram_shift = last_fetch_hpos - fetch_cycle;
+
+    /* First, a loop that prepares us for the speedup code.  We want to enter
+       the SPEEDUP case with fetch_state == fetch_was_plane0, and then unroll
+       whole blocks, so that we end on the same fetch_state again.  */
+    for (; ; pos++) {
+       if (pos == until) {
+           if (until >= maxhpos) {
+               finish_final_fetch (pos, fm);
+               return;
+           }
+           flush_display (fm);
+           return;
+       }
+
+       if (fetch_state == fetch_was_plane0)
+           break;
+
+       fetch_state = fetch_started;
+       if (one_fetch_cycle (pos, ddfstop_to_test, dma, fm))
+           return;
+    }
+
+#ifdef SPEEDUP
+    /* Unrolled version of the for loop below.  */
+    if (! passed_plfstop && ddf_change != vpos && ddf_change + 1 != vpos
+       && dma
+       && (fetch_cycle & fetchstart_mask) == (fm_maxplane & fetchstart_mask)
+       && toscr_delay1 == toscr_delay1x && toscr_delay2 == toscr_delay2x
+ # if 0
+       /* @@@ We handle this case, but the code would be simpler if we
+        * disallowed it - it may even be possible to guarantee that
+        * this condition never is false.  Later.  */
+       && (out_nbits & 15) == 0
+# endif
+       && toscr_nr_planes == thisline_decision.nr_planes)
+    {
+       int offs = (pos - fetch_cycle) & fetchunit_mask;
+       int ddf2 = ((ddfstop_to_test - offs + fetchunit - 1) & ~fetchunit_mask) + offs;
+       int ddf3 = ddf2 + fetchunit;
+       int stop = until < ddf2 ? until : until < ddf3 ? ddf2 : ddf3;
+       int count;
+
+       count = stop - pos;
+
+       if (count >= fetchstart) {
+           count &= ~fetchstart_mask;
+
+           if (thisline_decision.plfleft == -1) {
+               compute_delay_offset ();
+               compute_toscr_delay_1 ();
+           }
+           do_long_fetch (pos, count >> (3 - toscr_res), dma, fm);
+
+           /* This must come _after_ do_long_fetch so as not to confuse flush_display
+              into thinking the first fetch has produced any output worth emitting to
+              the screen.  But the calculation of delay_offset must happen _before_.  */
+           maybe_first_bpl1dat (pos);
+
+           if (pos <= ddfstop_to_test && pos + count > ddfstop_to_test)
+               passed_plfstop = 1;
+           if (pos <= ddfstop_to_test && pos + count > ddf2)
+               passed_plfstop = 2;
+           if (pos <= ddf2 && pos + count >= ddf2 + fm_maxplane)
+               add_modulos ();
+           pos += count;
+           fetch_cycle += count;
+       }
+    }
+#endif
+    for (; pos < until; pos++) {
+       if (fetch_state == fetch_was_plane0)
+           beginning_of_plane_block (pos, fm);
+       fetch_state = fetch_started;
+
+       if (one_fetch_cycle (pos, ddfstop_to_test, dma, fm))
+           return;
+    }
+    if (until >= maxhpos) {
+       finish_final_fetch (pos, fm);
+       return;
+    }
+    flush_display (fm);
+}
+
+static void update_fetch_0 (int hpos) { update_fetch (hpos, 0); }
+static void update_fetch_1 (int hpos) { update_fetch (hpos, 1); }
+static void update_fetch_2 (int hpos) { update_fetch (hpos, 2); }
+
+STATIC_INLINE void decide_fetch (int hpos)
+{
+    if (fetch_state != fetch_not_started && hpos > last_fetch_hpos) {
+       switch (fetchmode) {
+       case 0: update_fetch_0 (hpos); break;
+#ifdef AGA
+       case 1: update_fetch_1 (hpos); break;
+       case 2: update_fetch_2 (hpos); break;
+#endif
+       default: uae_abort ("fetchmode corrupt");
+       }
+    }
+    last_fetch_hpos = hpos;
+}
+
+static void start_bpl_dma (int hpos, int hstart)
+{
+    fetch_state = fetch_started;
+    fetch_cycle = 0;
+    last_fetch_hpos = hstart;
+    out_nbits = 0;
+    out_offs = 0;
+    toscr_nbits = 0;
+    toscr_res_first = GET_RES (bplcon0);
+
+    ddfstate = DIW_waiting_stop;
+    compute_toscr_delay (last_fetch_hpos);
+
+    /* If someone already wrote BPL1DAT, clear the area between that point and
+       the real fetch start.  */
+    if (framecnt == 0) {
+       if (thisline_decision.plfleft != -1) {
+           out_nbits = (plfstrt - thisline_decision.plfleft) << (1 + toscr_res);
+           out_offs = out_nbits >> 5;
+           out_nbits &= 31;
+       }
+       update_toscr_planes ();
+    }
+}
+
+/* this may turn on datafetch if program turns dma on during the ddf */
+static void maybe_start_bpl_dma (int hpos)
+{
+    /* OCS: BPL DMA never restarts if DMA is turned on during DDF
+     * ECS/AGA: BPL DMA restarts but only if DMA was turned off
+       outside of DDF or during current line, otherwise display
+       processing jumps immediately to "DDFSTOP passed"-condition */
+    if (!(currprefs.chipset_mask & CSMASK_ECS_AGNUS))
+       return;
+    if (fetch_state != fetch_not_started)
+       return;
+    if (diwstate != DIW_waiting_stop)
+       return;
+    if (hpos <= plfstrt)
+       return;
+    if (hpos > plfstop)
+       return;
+    if (ddfstate != DIW_waiting_start)
+        passed_plfstop = 1;
+    start_bpl_dma (hpos, hpos);
+}
+
+/* This function is responsible for turning on datafetch if necessary.  */
+STATIC_INLINE void decide_line (int hpos)
+{
+    /* Take care of the vertical DIW.  */
+    if (vpos == plffirstline)
+       diwstate = DIW_waiting_stop;
+    if (vpos == plflastline)
+       diwstate = DIW_waiting_start;
+
+    if (hpos <= last_decide_line_hpos)
+       return;
+    if (fetch_state != fetch_not_started)
+       return;
+
+    if (dmaen (DMA_BITPLANE) && diwstate == DIW_waiting_stop) {
+       int ok = 0;
+        /* Test if we passed the start of the DDF window.  */
+       if (last_decide_line_hpos < plfstrt && hpos >= plfstrt) {
+           ok = 1;
+           /* hack warning.. Writing to DDFSTRT when DMA should start must be ignored
+            * (correct fix would be emulate this delay for every custom register, but why bother..) */
+           if (ddfstrt_old != ddfstrt && hpos - 2 == ddfstrt_old_hpos && ddfstrt_old_vpos == vpos)
+               ok = 0;
+           if (ok) {
+               start_bpl_dma (hpos, plfstrt);
+               estimate_last_fetch_cycle (plfstrt);
+               last_decide_line_hpos = hpos;
+#ifndef CUSTOM_SIMPLE
+               do_sprites (plfstrt);
+#endif
+               return;
+           }
+       }
+    }
+
+#ifndef CUSTOM_SIMPLE
+    if (last_decide_line_hpos < SPR0_HPOS + 4 * MAX_SPRITES)
+       do_sprites (hpos);
+#endif
+    last_decide_line_hpos = hpos;
+}
+
+/* Called when a color is about to be changed (write to a color register),
+ * but the new color has not been entered into the table yet. */
+static void record_color_change (int hpos, int regno, unsigned long value)
+{
+    if (regno == -1 && value) {
+       thisline_decision.ham_seen = 1;
+       if (hpos < HARD_DDF_START)
+           thisline_decision.ham_at_start = 1;
+    }
+
+    /* Early positions don't appear on-screen. */
+    if (framecnt != 0 || vpos < minfirstline || hpos < HARD_DDF_START
+       /*|| currprefs.emul_accuracy == 0*/)
+       return;
+
+    decide_diw (hpos);
+    decide_line (hpos);
+
+    if (thisline_decision.ctable == -1)
+       remember_ctable ();
+
+#ifdef OS_WITHOUT_MEMORY_MANAGEMENT
+    if (next_color_change >= max_color_change) {
+       ++delta_color_change;
+       return;
+    }
+#endif
+    curr_color_changes[next_color_change].linepos = hpos;
+    curr_color_changes[next_color_change].regno = regno;
+    curr_color_changes[next_color_change++].value = value;
+}
+
+typedef int sprbuf_res_t, cclockres_t, hwres_t, bplres_t;
+
+static void do_playfield_collisions (void)
+{
+    uae_u8 *ld = line_data[next_lineno];
+    int i;
+
+    if (clxcon_bpl_enable == 0) {
+       clxdat |= 1;
+       return;
+    }
+       
+    for (i = thisline_decision.plfleft; i < thisline_decision.plfright; i += 2) {
+       int j;
+       uae_u32 total = 0xFFFFFFFF;
+       for (j = 0; j < 8; j++) {
+           uae_u32 t = 0;
+           if ((clxcon_bpl_enable & (1 << j)) == 0)
+               t = 0xFFFFFFFF;
+           else if (j < thisline_decision.nr_planes) {
+               t = *(uae_u32 *)(line_data[next_lineno] + 2 * i + 2 * j * MAX_WORDS_PER_LINE);
+               t ^= ~(((clxcon_bpl_match >> j) & 1) - 1);
+           }
+           total &= t;
+       }
+       if (total)
+           clxdat |= 1;        
+    }
+}
+
+/* Sprite-to-sprite collisions are taken care of in record_sprite.  This one does
+   playfield/sprite collisions.
+   That's the theory.  In practice this doesn't work yet.  I also suspect this code
+   is way too slow.  */
+static void do_sprite_collisions (void)
+{
+    int nr_sprites = curr_drawinfo[next_lineno].nr_sprites;
+    int first = curr_drawinfo[next_lineno].first_sprite_entry;
+    int i;
+    unsigned int collision_mask = clxmask[clxcon >> 12];
+    int bplres = GET_RES (bplcon0);
+    hwres_t ddf_left = thisline_decision.plfleft * 2 << bplres;
+    hwres_t hw_diwlast = coord_window_to_diw_x (thisline_decision.diwlastword);
+    hwres_t hw_diwfirst = coord_window_to_diw_x (thisline_decision.diwfirstword);
+
+    if (clxcon_bpl_enable == 0) {
+       clxdat |= 0x1FE;
+       return;
+    }
+
+    for (i = 0; i < nr_sprites; i++) {
+       struct sprite_entry *e = curr_sprite_entries + first + i;
+       sprbuf_res_t j;
+       sprbuf_res_t minpos = e->pos;
+       sprbuf_res_t maxpos = e->max;
+       hwres_t minp1 = minpos >> sprite_buffer_res;
+       hwres_t maxp1 = maxpos >> sprite_buffer_res;
+
+       if (maxp1 > hw_diwlast)
+           maxpos = hw_diwlast << sprite_buffer_res;
+       if (maxp1 > thisline_decision.plfright * 2)
+           maxpos = thisline_decision.plfright * 2 << sprite_buffer_res;
+       if (minp1 < hw_diwfirst)
+           minpos = hw_diwfirst << sprite_buffer_res;
+       if (minp1 < thisline_decision.plfleft * 2)
+           minpos = thisline_decision.plfleft * 2 << sprite_buffer_res;
+
+       for (j = minpos; j < maxpos; j++) {
+           int sprpix = spixels[e->first_pixel + j - e->pos] & collision_mask;
+           int k, offs, match = 1;
+
+           if (sprpix == 0)
+               continue;
+
+           offs = ((j << bplres) >> sprite_buffer_res) - ddf_left;
+           sprpix = sprite_ab_merge[sprpix & 255] | (sprite_ab_merge[sprpix >> 8] << 2);
+           sprpix <<= 1;
+
+           /* Loop over number of playfields.  */
+           for (k = 1; k >= 0; k--) {
+               int l;
+#ifdef AGA
+               int planes = (currprefs.chipset_mask & CSMASK_AGA) ? 8 : 6;
+#else
+               int planes = 6;
+#endif
+               if (bplcon0 & 0x400)
+                   match = 1;
+               for (l = k; match && l < planes; l += 2) {
+                   int t = 0;
+                   if (l < thisline_decision.nr_planes) {
+                       uae_u32 *ldata = (uae_u32 *)(line_data[next_lineno] + 2 * l * MAX_WORDS_PER_LINE);
+                       uae_u32 word = ldata[offs >> 5];
+                       t = (word >> (31 - (offs & 31))) & 1;
+#if 0 /* debug: draw collision mask */
+                       if (1) {
+                           int m;
+                           for (m = 0; m < 5; m++) {
+                               ldata = (uae_u32 *)(line_data[next_lineno] + 2 * m * MAX_WORDS_PER_LINE);
+                               ldata[(offs >> 5) + 1] |= 15 << (31 - (offs & 31));
+                           }
+                       }
+#endif
+                   }
+                   if (clxcon_bpl_enable & (1 << l)) {
+                       if (t != ((clxcon_bpl_match >> l) & 1))
+                           match = 0;
+                   }
+               }
+               if (match) {
+#if 0 /* debug: mark lines where collisions are detected */
+                   if (0) {
+                       int l;
+                       for (l = 0; l < 5; l++) {
+                           uae_u32 *ldata = (uae_u32 *)(line_data[next_lineno] + 2 * l * MAX_WORDS_PER_LINE);
+                           ldata[(offs >> 5) + 1] |= 15 << (31 - (offs & 31));
+                       }
+                   }
+#endif
+                   clxdat |= sprpix << (k * 4);
+               }
+           }
+       }
+    }
+#if 0
+    {
+       static int olx;
+       if (clxdat != olx)
+           write_log ("%d: %04.4X\n", vpos, clxdat);
+       olx = clxdat;
+    }
+#endif
+}
+
+static void expand_sprres (void)
+{
+    switch ((bplcon3 >> 6) & 3) {
+    case 0: /* ECS defaults (LORES,HIRES=140ns,SHRES=70ns) */
+       if ((currprefs.chipset_mask & CSMASK_ECS_DENISE) && GET_RES (bplcon0) == RES_SUPERHIRES)
+           sprres = RES_HIRES;
+       else
+           sprres = RES_LORES;
+       break;
+    case 1:
+       sprres = RES_LORES;
+       break;
+    case 2:
+       sprres = RES_HIRES;
+       break;
+    case 3:
+       sprres = RES_SUPERHIRES;
+       break;
+    }
+}
+
+STATIC_INLINE void record_sprite_1 (uae_u16 *buf, uae_u32 datab, int num, int dbl,
+                                   unsigned int mask, int do_collisions, uae_u32 collision_mask)
+{
+    int j = 0;
+    while (datab) {
+       unsigned int tmp = *buf;
+       unsigned int col = (datab & 3) << (2 * num);
+       tmp |= col;
+       if ((j & mask) == 0)
+           *buf++ = tmp;
+       if (dbl)
+           *buf++ = tmp;
+       j++;
+       datab >>= 2;
+       if (do_collisions) {
+           tmp &= collision_mask;
+           if (tmp) {
+               unsigned int shrunk_tmp = sprite_ab_merge[tmp & 255] | (sprite_ab_merge[tmp >> 8] << 2);
+               clxdat |= sprclx[shrunk_tmp];
+           }
+       }
+    }
+}
+
+/* DATAB contains the sprite data; 16 pixels in two-bit packets.  Bits 0/1
+   determine the color of the leftmost pixel, bits 2/3 the color of the next
+   etc.
+   This function assumes that for all sprites in a given line, SPRXP either
+   stays equal or increases between successive calls.
+
+   The data is recorded either in lores pixels (if ECS), or in hires pixels
+   (if AGA).  No support for SHRES sprites.  */
+
+static void record_sprite (int line, int num, int sprxp, uae_u16 *data, uae_u16 *datb, unsigned int ctl)
+{
+    struct sprite_entry *e = curr_sprite_entries + next_sprite_entry;
+    int i;
+    int word_offs;
+    uae_u16 *buf;
+    uae_u32 collision_mask;
+    int width = sprite_width;
+    int dbl = 0, half = 0;
+    unsigned int mask = 0;
+
+    if (sprres != RES_LORES)
+       thisline_decision.any_hires_sprites = 1;
+
+#ifdef AGA
+    if (currprefs.chipset_mask & CSMASK_AGA) {
+       width = (width << 1) >> sprres;
+       dbl = sprite_buffer_res - sprres;
+       if (dbl < 0) {
+           half = -dbl;
+           dbl = 0;
+       }
+       mask = sprres == RES_SUPERHIRES ? 1 : 0;
+    }
+#endif
+
+    /* Try to coalesce entries if they aren't too far apart.  */
+    if (! next_sprite_forced && e[-1].max + 16 >= sprxp) {
+       e--;
+    } else {
+       next_sprite_entry++;
+       e->pos = sprxp;
+       e->has_attached = 0;
+    }
+
+    if (sprxp < e->pos)
+       uae_abort ("sprxp < e->pos");
+
+    e->max = sprxp + width;
+    e[1].first_pixel = e->first_pixel + ((e->max - e->pos + 3) & ~3);
+    next_sprite_forced = 0;
+
+    collision_mask = clxmask[clxcon >> 12];
+    word_offs = e->first_pixel + sprxp - e->pos;
+
+    for (i = 0; i < sprite_width; i += 16) {
+       unsigned int da = *data;
+       unsigned int db = *datb;
+       uae_u32 datab = ((sprtaba[da & 0xFF] << 16) | sprtaba[da >> 8]
+                        | (sprtabb[db & 0xFF] << 16) | sprtabb[db >> 8]);
+
+       buf = spixels + word_offs + ((i << dbl) >> half);
+       if (currprefs.collision_level > 0 && collision_mask)
+           record_sprite_1 (buf, datab, num, dbl, mask, 1, collision_mask);
+       else
+           record_sprite_1 (buf, datab, num, dbl, mask, 0, collision_mask);
+       data++;
+       datb++;
+    }
+
+    /* We have 8 bits per pixel in spixstate, two for every sprite pair.  The
+       low order bit records whether the attach bit was set for this pair.  */
+
+    if (ctl & 0x80) {
+       uae_u32 state = 0x01010101 << (num & ~1);
+       uae_u32 *stbuf = spixstate.words + (word_offs >> 2);
+       uae_u8 *stb1 = spixstate.bytes + word_offs;     
+       for (i = 0; i < width; i += 8) {
+           stb1[0] |= state;
+           stb1[1] |= state;
+           stb1[2] |= state;
+           stb1[3] |= state;
+           stb1[4] |= state;
+           stb1[5] |= state;
+           stb1[6] |= state;
+           stb1[7] |= state;
+           stb1 += 8;
+       }
+       e->has_attached = 1;
+    }
+}
+
+static void decide_sprites (int hpos)
+{
+    int nrs[MAX_SPRITES], posns[MAX_SPRITES];
+    int count, i;
+    int point = hpos * 2;
+    int width = sprite_width;
+    int window_width = (width << lores_shift) >> sprres;
+
+    if (framecnt != 0 || hpos < 0x14 || nr_armed == 0 || point == last_sprite_point)
+       return;
+#ifdef DISABLE_SPRITES
+    return;
+#endif
+
+    decide_diw (hpos);
+    decide_line (hpos);
+
+#if 0
+    /* This tries to detect whether the line is border, but that doesn't work, it's too early.  */
+    if (thisline_decision.plfleft == -1)
+       return;
+#endif
+    count = 0;
+    for (i = 0; i < MAX_SPRITES; i++) {
+       int sprxp = spr[i].xpos;
+       int hw_xp = (sprxp >> sprite_buffer_res);
+       int window_xp = coord_hw_to_window_x (hw_xp) + (DIW_DDF_OFFSET << lores_shift);
+       int j, bestp;
+
+       if (! spr[i].armed || sprxp < 0 || hw_xp <= last_sprite_point || hw_xp > point)
+           continue;
+       if ( !(bplcon3 & 2) && /* sprites outside playfields enabled? */
+           ((thisline_decision.diwfirstword >= 0 && window_xp + window_width < thisline_decision.diwfirstword)
+           || (thisline_decision.diwlastword >= 0 && window_xp > thisline_decision.diwlastword)))
+           continue;
+
+       /* Sort the sprites in order of ascending X position before recording them.  */
+       for (bestp = 0; bestp < count; bestp++) {
+           if (posns[bestp] > sprxp)
+               break;
+           if (posns[bestp] == sprxp && nrs[bestp] < i)
+               break;
+       }
+       for (j = count; j > bestp; j--) {
+           posns[j] = posns[j-1];
+           nrs[j] = nrs[j-1];
+       }
+       posns[j] = sprxp;
+       nrs[j] = i;
+       count++;
+    }
+    for (i = 0; i < count; i++) {
+       int nr = nrs[i];    
+       record_sprite (next_lineno, nr, spr[nr].xpos, sprdata[nr], sprdatb[nr], sprctl[nr]);
+    }
+    last_sprite_point = point;
+}
+
+STATIC_INLINE int sprites_differ (struct draw_info *dip, struct draw_info *dip_old)
+{
+    struct sprite_entry *this_first = curr_sprite_entries + dip->first_sprite_entry;
+    struct sprite_entry *this_last = curr_sprite_entries + dip->last_sprite_entry;
+    struct sprite_entry *prev_first = prev_sprite_entries + dip_old->first_sprite_entry;
+    int npixels;
+    int i;
+
+    if (dip->nr_sprites != dip_old->nr_sprites)
+       return 1;
+    
+    if (dip->nr_sprites == 0)
+       return 0;
+
+    for (i = 0; i < dip->nr_sprites; i++)
+       if (this_first[i].pos != prev_first[i].pos
+           || this_first[i].max != prev_first[i].max
+           || this_first[i].has_attached != prev_first[i].has_attached)
+           return 1;
+
+    npixels = this_last->first_pixel + (this_last->max - this_last->pos) - this_first->first_pixel;
+    if (memcmp (spixels + this_first->first_pixel, spixels + prev_first->first_pixel,
+               npixels * sizeof (uae_u16)) != 0)
+       return 1;
+    if (memcmp (spixstate.bytes + this_first->first_pixel, spixstate.bytes + prev_first->first_pixel, npixels) != 0)
+       return 1;
+    return 0;
+}
+
+STATIC_INLINE int color_changes_differ (struct draw_info *dip, struct draw_info *dip_old)
+{
+    if (dip->nr_color_changes != dip_old->nr_color_changes)
+       return 1;
+    
+    if (dip->nr_color_changes == 0)
+       return 0;
+    if (memcmp (curr_color_changes + dip->first_color_change,
+               prev_color_changes + dip_old->first_color_change,
+               dip->nr_color_changes * sizeof *curr_color_changes) != 0)
+       return 1;
+    return 0;
+}
+
+/* End of a horizontal scan line. Finish off all decisions that were not
+ * made yet. */
+static void finish_decisions (void)
+{
+    struct draw_info *dip;
+    struct draw_info *dip_old;
+    struct decision *dp;
+    int changed;
+    int hpos = current_hpos ();
+
+    if (framecnt != 0)
+       return;
+
+    decide_diw (hpos);
+    decide_line (hpos);
+    decide_fetch (hpos);
+
+    if (thisline_decision.plfleft != -1 && thisline_decision.plflinelen == -1) {
+       if (fetch_state != fetch_not_started) {
+           write_log("fetch_state=%d plfleft=%d\n",fetch_state,thisline_decision.plfleft);
+           uae_abort ("fetch_state != fetch_not_started");
+       }
+       thisline_decision.plfright = thisline_decision.plfleft;
+       thisline_decision.plflinelen = 0;
+       thisline_decision.bplres = RES_LORES;
+    }
+
+    /* Large DIWSTOP values can cause the stop position never to be
+     * reached, so the state machine always stays in the same state and
+     * there's a more-or-less full-screen DIW. */
+    if (hdiwstate == DIW_waiting_stop || thisline_decision.diwlastword > max_diwlastword)
+       thisline_decision.diwlastword = max_diwlastword;
+
+    if (thisline_decision.diwfirstword != line_decisions[next_lineno].diwfirstword)
+       MARK_LINE_CHANGED;
+    if (thisline_decision.diwlastword != line_decisions[next_lineno].diwlastword)
+       MARK_LINE_CHANGED;
+
+    dip = curr_drawinfo + next_lineno;
+    dip_old = prev_drawinfo + next_lineno;
+    dp = line_decisions + next_lineno;
+    changed = thisline_changed;
+
+    if (thisline_decision.plfleft != -1) {
+       record_diw_line (thisline_decision.diwfirstword, thisline_decision.diwlastword);
+
+       decide_sprites (hpos);
+    }
+
+    dip->last_sprite_entry = next_sprite_entry;
+    dip->last_color_change = next_color_change;
+
+    if (thisline_decision.ctable == -1) {
+       if (thisline_decision.plfleft == -1)
+           remember_ctable_for_border ();
+       else
+           remember_ctable ();
+    }
+
+    dip->nr_color_changes = next_color_change - dip->first_color_change;
+    dip->nr_sprites = next_sprite_entry - dip->first_sprite_entry;
+
+    if (thisline_decision.plfleft != line_decisions[next_lineno].plfleft)
+       changed = 1;
+    if (! changed && color_changes_differ (dip, dip_old))
+       changed = 1;
+    if (!changed && thisline_decision.plfleft != -1 && sprites_differ (dip, dip_old))
+       changed = 1;
+
+    if (changed) {
+       thisline_changed = 1;
+       *dp = thisline_decision;
+    } else
+       /* The only one that may differ: */
+       dp->ctable = thisline_decision.ctable;
+}
+
+/* Set the state of all decisions to "undecided" for a new scanline. */
+static void reset_decisions (void)
+{
+    if (framecnt != 0)
+       return;
+    toscr_res_first = 0;
+
+    thisline_decision.any_hires_sprites = 0;
+    thisline_decision.nr_planes = 0;
+
+    thisline_decision.plfleft = -1;
+    thisline_decision.plflinelen = -1;
+    thisline_decision.ham_seen = !! (bplcon0 & 0x800);
+    thisline_decision.ham_at_start = !! (bplcon0 & 0x800);
+
+    /* decided_res shouldn't be touched before it's initialized by decide_line(). */
+    thisline_decision.diwfirstword = -1;
+    thisline_decision.diwlastword = -1;
+    if (hdiwstate == DIW_waiting_stop) {
+       thisline_decision.diwfirstword = 0;
+       if (thisline_decision.diwfirstword != line_decisions[next_lineno].diwfirstword)
+           MARK_LINE_CHANGED;
+    }
+    thisline_decision.ctable = -1;
+
+    thisline_changed = 0;
+    curr_drawinfo[next_lineno].first_color_change = next_color_change;
+    curr_drawinfo[next_lineno].first_sprite_entry = next_sprite_entry;
+    next_sprite_forced = 1;
+
+    /* memset(sprite_last_drawn_at, 0, sizeof sprite_last_drawn_at); */
+    last_sprite_point = 0;
+    fetch_state = fetch_not_started;
+    passed_plfstop = 0;
+
+    memset (todisplay, 0, sizeof todisplay);
+    memset (fetched, 0, sizeof fetched);
+#ifdef AGA
+    memset (fetched_aga0, 0, sizeof fetched_aga0);
+    memset (fetched_aga1, 0, sizeof fetched_aga1);
+#endif
+    memset (outword, 0, sizeof outword);
+
+    last_decide_line_hpos = -1;
+    last_diw_pix_hpos = -1;
+    last_ddf_pix_hpos = -1;
+    last_sprite_hpos = -1;
+    last_fetch_hpos = -1;
+
+}
+
+int vsynctime_orig;
+int turbo_emulation;
+
+void compute_vsynctime (void)
+{
+    fake_vblank_hz = 0;
+    if (currprefs.gfx_vsync && currprefs.gfx_afullscreen && currprefs.gfx_refreshrate) {
+       vblank_hz = currprefs.gfx_refreshrate;
+       vblank_skip = 1;
+#if 0
+       if (vblank_hz == 75) {
+           fake_vblank_hz = 50;
+           vblank_skip = 2;
+       }
+       if (vblank_hz == 90) {
+           fake_vblank_hz = 60;
+           vblank_skip = 2;
+       }
+#endif
+       if (!fake_vblank_hz && vblank_hz > 85) {
+           vblank_hz /= 2;
+           vblank_skip = -1;
+       }
+    }
+    if (!fake_vblank_hz)
+        fake_vblank_hz = vblank_hz;
+    if (turbo_emulation)
+       vsynctime = vsynctime_orig = 1;
+    else
+       vsynctime = vsynctime_orig = syncbase / fake_vblank_hz;
+#ifdef OPENGL
+    OGL_refresh ();
+#endif
+#ifdef D3D
+    D3D_refresh ();
+#endif
+    if (currprefs.produce_sound > 1)
+       update_sound (fake_vblank_hz);
+}
+
+
+/* set PAL or NTSC timing variables */
+void init_hz (void)
+{
+    int isntsc;
+
+    beamcon0 = new_beamcon0;
+    isntsc = beamcon0 & 0x20 ? 0 : 1;
+    if (hack_vpos > 0) {
+       if (maxvpos == hack_vpos) return;
+       maxvpos = hack_vpos;
+       vblank_hz = 15600 / hack_vpos;
+       hack_vpos = -1;
+    } else if (hack_vpos < 0) {
+       hack_vpos = 0;
+    }
+    if (hack_vpos == 0) {
+       if (!isntsc) {
+           maxvpos = MAXVPOS_PAL;
+           maxhpos = MAXHPOS_PAL;
+           minfirstline = VBLANK_ENDLINE_PAL;
+           vblank_hz = VBLANK_HZ_PAL;
+           sprite_vblank_endline = VBLANK_SPRITE_PAL;
+       } else {
+           maxvpos = MAXVPOS_NTSC;
+           maxhpos = MAXHPOS_NTSC;
+           minfirstline = VBLANK_ENDLINE_NTSC;
+           vblank_hz = VBLANK_HZ_NTSC;
+           sprite_vblank_endline = VBLANK_SPRITE_NTSC;
+       }
+    }
+    if (beamcon0 & 0x80) {
+       if (vtotal >= MAXVPOS)
+           vtotal = MAXVPOS - 1;
+       maxvpos = vtotal + 1;
+       if (htotal >= MAXHPOS)
+           htotal = MAXHPOS - 1;
+       maxhpos = htotal + 1;
+       vblank_hz = 227 * 312 * 50 / (maxvpos * maxhpos);
+    }
+    /* limit to sane values */
+    if (vblank_hz < 10)
+       vblank_hz = 10;
+    if (vblank_hz > 300)
+       vblank_hz = 300;
+    eventtab[ev_hsync].oldcycles = get_cycles ();
+    eventtab[ev_hsync].evtime = get_cycles() + HSYNCTIME;
+    events_schedule ();
+    compute_vsynctime ();
+#ifdef OPENGL
+    OGL_refresh ();
+#endif
+#ifdef PICASSO96
+    init_hz_p96 ();
+#endif
+    write_log ("%s mode, %dHz\n", isntsc ? "NTSC" : "PAL", vblank_hz);
+}
+
+static void calcdiw (void)
+{
+    int hstrt = diwstrt & 0xFF;
+    int hstop = diwstop & 0xFF;
+    int vstrt = diwstrt >> 8;
+    int vstop = diwstop >> 8;
+
+    if (diwhigh_written) {
+       hstrt |= ((diwhigh >> 5) & 1) << 8;
+       hstop |= ((diwhigh >> 13) & 1) << 8;
+       vstrt |= (diwhigh & 7) << 8;
+       vstop |= ((diwhigh >> 8) & 7) << 8;
+    } else {
+       hstop += 0x100;
+       if ((vstop & 0x80) == 0)
+           vstop |= 0x100;
+    }
+
+    diwfirstword = coord_diw_to_window_x (hstrt);
+    diwlastword = coord_diw_to_window_x (hstop);
+    if (diwfirstword < 0)
+       diwfirstword = 0;
+
+    plffirstline = vstrt;
+    plflastline = vstop;
+
+#if 0
+    /* This happens far too often. */
+    if (plffirstline < minfirstline_bpl) {
+       write_log ("Warning: Playfield begins before line %d (%d)!\n", minfirstline_bpl, plffirstline);
+    }
+#endif
+
+#if 0 /* this comparison is not needed but previous is.. */
+    if (plflastline > 313) {
+       /* Turrican does this */
+       write_log ("Warning: Playfield out of range!\n");
+       plflastline = 313;
+    }
+#endif
+
+    plfstrt = ddfstrt;
+    plfstop = ddfstop;
+    /* probably not the correct place.. */
+    if ((currprefs.chipset_mask & CSMASK_ECS_AGNUS) && ddfstop > maxhpos)
+       plfstrt = 0;
+    if (plfstrt < HARD_DDF_START)
+       plfstrt = HARD_DDF_START;
+}
+
+static int timehack_alive = 0;
+
+static uae_u32 timehack_helper (void)
+{
+#ifdef HAVE_GETTIMEOFDAY
+    struct timeval tv;
+    if (m68k_dreg (regs, 0) == 0)
+       return timehack_alive;
+
+    timehack_alive = 10;
+
+    gettimeofday (&tv, NULL);
+    put_long (m68k_areg (regs, 0), tv.tv_sec - (((365 * 8 + 2) * 24) * 60 * 60));
+    put_long (m68k_areg (regs, 0) + 4, tv.tv_usec);
+    return 0;
+#else
+    return 2;
+#endif
+}
+
+ /*
+  * register functions
+  */
+STATIC_INLINE uae_u16 DENISEID (void)
+{
+#ifdef AGA
+    if (currprefs.chipset_mask & CSMASK_AGA)
+       return 0xF8;
+#endif
+    if (currprefs.chipset_mask & CSMASK_ECS_DENISE)
+       return 0xFC;
+    return 0xffff;
+}
+STATIC_INLINE uae_u16 DMACONR (void)
+{
+    uae_u16 v;
+    decide_blitter (current_hpos ());
+    v = dmacon | (bltstate == BLT_done ? 0 : 0x4000)
+           | (blt_info.blitzero ? 0x2000 : 0);
+    return v;
+}
+STATIC_INLINE uae_u16 INTENAR (void)
+{
+    return intena;
+}
+uae_u16 INTREQR (void)
+{
+    return intreq;
+}
+STATIC_INLINE uae_u16 ADKCONR (void)
+{
+    return adkcon;
+}
+STATIC_INLINE uae_u16 VPOSR (void)
+{
+    unsigned int csbit = currprefs.ntscmode ? 0x1000 : 0;
+    int vp = (vpos >> 8) & 7;
+#ifdef AGA
+    csbit |= (currprefs.chipset_mask & CSMASK_AGA) ? 0x2300 : 0;
+#else
+    csbit |= (currprefs.chipset_mask & CSMASK_ECS_AGNUS) ? 0x2000 : 0;
+#endif
+    if (!(currprefs.chipset_mask & CSMASK_ECS_AGNUS))
+       vp &= 1;
+    vp = vp | lof | csbit;
+    return vp;
+}
+static void VPOSW (uae_u16 v)
+{
+#if 0
+    write_log ("vposw %x at %x\n", v, m68k_getpc());
+#endif
+    if (lof != (v & 0x8000))
+       lof_changed = 1;
+    lof = v & 0x8000;
+    if ( (v & 1) && vpos > 0)
+       hack_vpos = vpos;
+}
+
+STATIC_INLINE uae_u16 VHPOSR (void)
+{
+    uae_u16 v = (vpos << 8) | current_hpos ();
+    return v;
+}
+
+STATIC_INLINE void COP1LCH (uae_u16 v) { cop1lc = (cop1lc & 0xffff) | ((uae_u32)v << 16); }
+STATIC_INLINE void COP1LCL (uae_u16 v) { cop1lc = (cop1lc & ~0xffff) | (v & 0xfffe); }
+STATIC_INLINE void COP2LCH (uae_u16 v) { cop2lc = (cop2lc & 0xffff) | ((uae_u32)v << 16); }
+STATIC_INLINE void COP2LCL (uae_u16 v) { cop2lc = (cop2lc & ~0xffff) | (v & 0xfffe); }
+
+static void COPJMP (int num)
+{
+    int was_active = eventtab[ev_copper].active;
+    eventtab[ev_copper].active = 0;
+    if (was_active)
+       events_schedule ();
+
+    cop_state.ignore_next = 0;
+    cop_state.state = COP_read1;
+    cop_state.vpos = vpos;
+    cop_state.hpos = current_hpos () & ~1;
+    cop_state.strobe = num;
+    copper_enabled_thisline = 0;
+
+    if (dmaen (DMA_COPPER)) {
+       copper_enabled_thisline = 1;
+       set_special (SPCFLAG_COPPER);
+    }
+}
+
+STATIC_INLINE void COPCON (uae_u16 a)
+{
+    copcon = a;
+}
+
+static void compute_spcflag_copper (void);
+static void DMACON (int hpos, uae_u16 v)
+{
+    int oldcop, newcop;
+    uae_u16 changed;
+
+    uae_u16 oldcon = dmacon;
+
+    decide_line (hpos);
+    decide_fetch (hpos);
+    decide_blitter (hpos);
+
+    setclr (&dmacon, v);
+    dmacon &= 0x1FFF;
+
+    changed = dmacon ^ oldcon;
+
+    oldcop = (oldcon & DMA_COPPER) && (oldcon & DMA_MASTER);
+    newcop = (dmacon & DMA_COPPER) && (dmacon & DMA_MASTER);
+
+    if (oldcop != newcop) {
+       eventtab[ev_copper].active = 0;
+       if (newcop && !oldcop) {
+           compute_spcflag_copper ();
+       } else if (!newcop) {
+           copper_enabled_thisline = 0;
+           unset_special (SPCFLAG_COPPER);
+       }
+    }
+    if ((dmacon & DMA_BLITPRI) > (oldcon & DMA_BLITPRI) && bltstate != BLT_done) {
+       static int count = 0;
+       if (!count) {
+           count = 1;
+           write_log ("warning: program is doing blitpri hacks.\n");
+       }
+       set_special (SPCFLAG_BLTNASTY);
+       decide_blitter (hpos);
+    }
+    if (dmaen (DMA_BLITTER) && bltstate == BLT_init)
+       bltstate = BLT_work;
+    if ((dmacon & (DMA_BLITPRI | DMA_BLITTER | DMA_MASTER)) != (DMA_BLITPRI | DMA_BLITTER | DMA_MASTER)) {
+       unset_special (SPCFLAG_BLTNASTY);
+       decide_blitter (hpos);
+    }
+    if (changed & (DMA_MASTER | 0x0f))
+       audio_hsync (0);
+    if (changed & (DMA_MASTER | DMA_BITPLANE)) {
+        ddf_change = vpos;
+       if (dmaen (DMA_BITPLANE))
+           maybe_start_bpl_dma (hpos);
+    }
+           
+    events_schedule();
+}
+
+
+static int intlev_2 (void)
+{
+    uae_u16 imask = intreq & intena;
+    unsigned long cycles = get_cycles ();
+    int c = currprefs.cpu_level >= 2 ? 20 : 4;
+    int i;
+
+    if (!(imask && (intena & 0x4000))) {
+        unset_special (SPCFLAG_INT);
+       return -1;
+    }
+    for (i = 14; i >= 0; i--) {
+       if (imask & (1 << i)) {
+           if (!(irqdelay[i] && (cycles - irqcycles[i]) < c * CYCLE_UNIT)) {
+               irqdelay[i] = 0;
+               if (i == 13 || i == 14)
+                   return 6;
+               else if (i == 11 || i == 12)
+                   return 5;
+               else if (i >= 7 && i <= 10)
+                   return 4;
+               else if (i >= 4 && i <= 6)
+                   return 3;
+               else if (i == 3)
+                   return 2;
+               else
+                   return 1;
+           }
+       }
+    }
+    return -1;
+}
+
+int intlev (void)
+{
+    int il = intlev_2 ();
+    if (il >= 0 && il <= regs.intmask)
+       unset_special (SPCFLAG_INT);
+    return il;
+}
+
+static void doint (void)
+{
+    int i;
+    uae_u16 imask = intreq & intena;
+
+    set_special (SPCFLAG_INT);
+    if (imask && (intena & 0x4000)) {
+       for (i = 0; i < 14; i++) {
+           if ((imask & (1 << i)) && irqdelay[i] == 0) {
+               irqdelay[i] = 1;
+               irqcycles[i] = get_cycles ();
+           }
+       }
+    }
+}
+
+STATIC_INLINE void INTENA (uae_u16 v)
+{
+    setclr (&intena,v);
+#if 0
+    if (v & 0x100)
+       write_log("INTENA %04.4X (%04.4X) %p\n", intena, v, m68k_getpc());
+#endif
+    if (v & 0x8000)
+       doint ();
+}
+
+void INTREQ_0 (uae_u16 v)
+{
+    setclr (&intreq,v);
+    doint ();
+}
+
+void INTREQ (uae_u16 v)
+{
+    INTREQ_0 (v);
+    serial_check_irq ();
+    rethink_cias ();
+#if 0
+    if (v & 0x100)
+       write_log("INTREQ %04.4X (%04.4X) %p\n", intreq, v, m68k_getpc());
+#endif
+}
+
+static void ADKCON (int hpos, uae_u16 v)
+{
+    if (currprefs.produce_sound > 0)
+       update_audio ();
+
+    setclr (&adkcon,v);
+    update_adkmasks ();
+    DISK_update (hpos);
+    if ((v >> 11) & 1)
+       serial_uartbreak ((adkcon >> 11) & 1);
+}
+
+static void dumpsync (void)
+{
+#if 0
+    write_log ("BEAMCON0 = %04.4X VTOTAL=%04.4X HTOTAL=%04.4X\n", new_beamcon0, vtotal, htotal);
+    write_log ("HSSTOP=%04.4X HBSTRT=%04.4X HBSTOP=%04.4X\n", hsstop, hbstrt, hbstop);
+    write_log ("VSSTOP=%04.4X VBSTRT=%04.4X VBSTOP=%04.4X\n", vsstop, vbstrt, vbstop);
+    write_log ("HSSTRT=%04.4X VSSTRT=%04.4X HCENTER=%04.4X\n", hsstrt, vsstrt, hcenter);
+#endif
+}
+
+static void BEAMCON0 (uae_u16 v)
+{
+    if (currprefs.chipset_mask & CSMASK_ECS_AGNUS) {
+       if (!(currprefs.chipset_mask & CSMASK_ECS_DENISE))
+           v &= 0x20;
+       if (v != new_beamcon0) {
+            new_beamcon0 = v;
+           if (v & ~0x20)
+               write_log ("warning: %04.4X written to BEAMCON0\n", v);
+       }
+    }
+}
+
+static void varsync (void)
+{
+#ifdef PICASSO96
+    if (p96refresh_active)
+    {
+       extern int p96hack_vpos2;
+       static int p96hack_vpos_old;
+       if (p96hack_vpos_old == p96hack_vpos2) return;
+       vtotal = p96hack_vpos2;
+       p96hack_vpos_old = p96hack_vpos2;
+       hack_vpos = -1;
+       return;
+    }
+#endif
+    if (!(currprefs.chipset_mask & CSMASK_ECS_DENISE))
+       return;
+    if (!(beamcon0 & 0x80))
+       return;
+    hack_vpos = -1;
+    dumpsync ();
+}
+
+
+static void BPLxPTH (int hpos, uae_u16 v, int num)
+{
+    decide_line (hpos);
+    decide_fetch (hpos);
+    bplpt[num] = (bplpt[num] & 0xffff) | ((uae_u32)v << 16);
+    //write_log("%d:%d:BPL%dPTH %08.8X\n", hpos, vpos, num, v);
+}
+static void BPLxPTL (int hpos, uae_u16 v, int num)
+{
+    decide_line (hpos);
+    decide_fetch (hpos);
+    bplpt[num] = (bplpt[num] & ~0xffff) | (v & 0xfffe);
+    //write_log("%d:%d:BPL%dPTL %08.8X\n", hpos, vpos, num, v);
+}
+
+static void BPLCON0 (int hpos, uae_u16 v)
+{
+    if (! (currprefs.chipset_mask & CSMASK_ECS_DENISE))
+       v &= ~0x00F1;
+    else if (! (currprefs.chipset_mask & CSMASK_AGA))
+       v &= ~0x00B1;
+
+    if (bplcon0 == v)
+       return;
+
+    ddf_change = vpos;
+    decide_line (hpos);
+    decide_fetch (hpos);
+    decide_blitter (hpos);
+
+    /* HAM change?  */
+    if ((bplcon0 ^ v) & 0x800) {
+       record_color_change (hpos, -1, !! (v & 0x800));
+    }
+    bplcon0 = v;
+
+#ifdef AGA
+    if (currprefs.chipset_mask & CSMASK_AGA) {
+       decide_sprites (hpos);
+       expand_sprres ();
+    }
+#endif
+
+    expand_fmodes ();
+    calcdiw ();
+    estimate_last_fetch_cycle (hpos);
+}
+
+STATIC_INLINE void BPLCON1 (int hpos, uae_u16 v)
+{
+    if (!(currprefs.chipset_mask & CSMASK_AGA))
+       v &= 0xff;
+    if (bplcon1 == v)
+       return;
+    decide_line (hpos);
+    decide_fetch (hpos);
+    bplcon1 = v;
+}
+
+STATIC_INLINE void BPLCON2 (int hpos, uae_u16 v)
+{
+    if (!(currprefs.chipset_mask & CSMASK_AGA))
+       v &= 0x7f;
+    if (bplcon2 == v)
+       return;
+    decide_line (hpos);
+    bplcon2 = v;
+}
+
+#ifdef AGA
+STATIC_INLINE void BPLCON3 (int hpos, uae_u16 v)
+{
+    if (! (currprefs.chipset_mask & CSMASK_AGA))
+       return;
+    if (bplcon3 == v)
+       return;
+    decide_line (hpos);
+    decide_sprites (hpos);
+    bplcon3 = v;
+    expand_sprres ();
+}
+
+STATIC_INLINE void BPLCON4 (int hpos, uae_u16 v)
+{
+    if (! (currprefs.chipset_mask & CSMASK_AGA))
+       return;
+    if (bplcon4 == v)
+       return;
+    decide_line (hpos);
+    bplcon4 = v;
+}
+#endif
+
+static void BPL1MOD (int hpos, uae_u16 v)
+{
+    v &= ~1;
+    if ((uae_s16)bpl1mod == (uae_s16)v)
+       return;
+    decide_line (hpos);
+    decide_fetch (hpos);
+    bpl1mod = v;
+}
+
+static void BPL2MOD (int hpos, uae_u16 v)
+{
+    v &= ~1;
+    if ((uae_s16)bpl2mod == (uae_s16)v)
+       return;
+    decide_line (hpos);
+    decide_fetch (hpos);
+    bpl2mod = v;
+}
+
+STATIC_INLINE void BPL1DAT (int hpos, uae_u16 v)
+{
+    decide_line (hpos);
+    bpl1dat = v;
+
+    maybe_first_bpl1dat (hpos);
+}
+/* We could do as well without those... */
+STATIC_INLINE void BPL2DAT (uae_u16 v) { bpl2dat = v; }
+STATIC_INLINE void BPL3DAT (uae_u16 v) { bpl3dat = v; }
+STATIC_INLINE void BPL4DAT (uae_u16 v) { bpl4dat = v; }
+STATIC_INLINE void BPL5DAT (uae_u16 v) { bpl5dat = v; }
+STATIC_INLINE void BPL6DAT (uae_u16 v) { bpl6dat = v; }
+STATIC_INLINE void BPL7DAT (uae_u16 v) { bpl7dat = v; }
+STATIC_INLINE void BPL8DAT (uae_u16 v) { bpl8dat = v; }
+
+static void DIWSTRT (int hpos, uae_u16 v)
+{
+    if (diwstrt == v && ! diwhigh_written)
+       return;
+    decide_line (hpos);
+    diwhigh_written = 0;
+    diwstrt = v;
+    calcdiw ();
+}
+
+static void DIWSTOP (int hpos, uae_u16 v)
+{
+    if (diwstop == v && ! diwhigh_written)
+       return;
+    decide_line (hpos);
+    diwhigh_written = 0;
+    diwstop = v;
+    calcdiw ();
+}
+
+static void DIWHIGH (int hpos, uae_u16 v)
+{
+    if (! (currprefs.chipset_mask & CSMASK_ECS_AGNUS))
+       return;
+    if (diwhigh_written && diwhigh == v)
+       return;
+    decide_line (hpos);
+    diwhigh_written = 1;
+    diwhigh = v;
+    calcdiw ();
+}
+
+static void DDFSTRT (int hpos, uae_u16 v)
+{
+    v &= 0xfe;
+    if (!(currprefs.chipset_mask & CSMASK_ECS_AGNUS))
+       v &= 0xfc;
+    if (ddfstrt == v)
+       return;
+    ddf_change = vpos;
+    decide_line (hpos);
+    ddfstrt_old = ddfstrt;
+    ddfstrt_old_hpos = hpos;
+    ddfstrt_old_vpos = vpos;
+    ddfstrt = v;
+    calcdiw ();
+    if (ddfstop > 0xD4 && (ddfstrt & 4) == 4) {
+       static int last_warned;
+       last_warned = (last_warned + 1) & 4095;
+       if (last_warned == 0)
+           write_log ("WARNING! Very strange DDF values.\n");
+    }
+}
+
+int test_cnt = 0x80;
+
+static void DDFSTOP (int hpos, uae_u16 v)
+{
+    v &= 0xfe;
+    if (!(currprefs.chipset_mask & CSMASK_ECS_AGNUS))
+       v &= 0xfc;
+    if (ddfstop == v)
+       return;
+    decide_line (hpos);
+    decide_fetch (hpos);
+    decide_blitter (hpos);
+    ddfstop = v;
+    calcdiw ();
+    if (fetch_state != fetch_not_started)
+       estimate_last_fetch_cycle (hpos);
+    if (ddfstop > 0xD4 && (ddfstrt & 4) == 4) {
+       static int last_warned;
+       if (last_warned == 0)
+           write_log ("WARNING! Very strange DDF values (%x).\n", ddfstop);
+       last_warned = (last_warned + 1) & 4095;
+    }
+}
+
+static void FMODE (uae_u16 v)
+{
+    if (! (currprefs.chipset_mask & CSMASK_AGA))
+       v = 0;
+    ddf_change = vpos;
+    fmode = v;
+    sprite_width = GET_SPRITEWIDTH (fmode);
+    switch (fmode & 3) {
+    case 0:
+       fetchmode = 0;
+       break;
+    case 1:
+    case 2:
+       fetchmode = 1;
+       break;
+    case 3:
+       fetchmode = 2;
+       break;
+    }
+    expand_fmodes ();
+    calcdiw ();
+}
+
+static void BLTADAT (uae_u16 v)
+{
+    maybe_blit (current_hpos(), 0);
+
+    blt_info.bltadat = v;
+}
+/*
+ * "Loading data shifts it immediately" says the HRM. Well, that may
+ * be true for BLTBDAT, but not for BLTADAT - it appears the A data must be
+ * loaded for every word so that AFWM and ALWM can be applied.
+ */
+static void BLTBDAT (uae_u16 v)
+{
+    maybe_blit (current_hpos(), 0);
+
+    if (bltcon1 & 2)
+       blt_info.bltbhold = v << (bltcon1 >> 12);
+    else
+       blt_info.bltbhold = v >> (bltcon1 >> 12);
+    blt_info.bltbdat = v;
+}
+static void BLTCDAT (uae_u16 v) { maybe_blit (current_hpos(), 0); blt_info.bltcdat = v; reset_blit (0); }
+
+static void BLTAMOD (uae_u16 v) { maybe_blit (current_hpos(), 1); blt_info.bltamod = (uae_s16)(v & 0xFFFE); reset_blit (0); }
+static void BLTBMOD (uae_u16 v) { maybe_blit (current_hpos(), 1); blt_info.bltbmod = (uae_s16)(v & 0xFFFE); reset_blit (0); }
+static void BLTCMOD (uae_u16 v) { maybe_blit (current_hpos(), 1); blt_info.bltcmod = (uae_s16)(v & 0xFFFE); reset_blit (0); }
+static void BLTDMOD (uae_u16 v) { maybe_blit (current_hpos(), 1); blt_info.bltdmod = (uae_s16)(v & 0xFFFE); reset_blit (0); }
+
+static void BLTCON0 (uae_u16 v) { maybe_blit (current_hpos(), 2); bltcon0 = v; blinea_shift = v >> 12; reset_blit (1); }
+/* The next category is "Most useless hardware register".
+ * And the winner is... */
+static void BLTCON0L (uae_u16 v)
+{
+    if (! (currprefs.chipset_mask & CSMASK_ECS_AGNUS))
+       return;
+    maybe_blit (current_hpos(), 2); bltcon0 = (bltcon0 & 0xFF00) | (v & 0xFF);
+    reset_blit (1);
+}
+static void BLTCON1 (uae_u16 v) { maybe_blit (current_hpos(), 2); bltcon1 = v; reset_blit (2); }
+
+static void BLTAFWM (uae_u16 v) { maybe_blit (current_hpos(), 2); blt_info.bltafwm = v; reset_blit (0); }
+static void BLTALWM (uae_u16 v) { maybe_blit (current_hpos(), 2); blt_info.bltalwm = v; reset_blit (0); }
+
+static void BLTAPTH (uae_u16 v) { maybe_blit (current_hpos(), 0); bltapt = (bltapt & 0xffff) | ((uae_u32)v << 16); }
+static void BLTAPTL (uae_u16 v) { maybe_blit (current_hpos(), 0); bltapt = (bltapt & ~0xffff) | (v & 0xFFFE); }
+static void BLTBPTH (uae_u16 v) { maybe_blit (current_hpos(), 0); bltbpt = (bltbpt & 0xffff) | ((uae_u32)v << 16); }
+static void BLTBPTL (uae_u16 v) { maybe_blit (current_hpos(), 0); bltbpt = (bltbpt & ~0xffff) | (v & 0xFFFE); }
+static void BLTCPTH (uae_u16 v) { maybe_blit (current_hpos(), 0); bltcpt = (bltcpt & 0xffff) | ((uae_u32)v << 16); }
+static void BLTCPTL (uae_u16 v) { maybe_blit (current_hpos(), 0); bltcpt = (bltcpt & ~0xffff) | (v & 0xFFFE); }
+static void BLTDPTH (uae_u16 v) { maybe_blit (current_hpos(), 0); bltdpt = (bltdpt & 0xffff) | ((uae_u32)v << 16); }
+static void BLTDPTL (uae_u16 v) { maybe_blit (current_hpos(), 0); bltdpt = (bltdpt & ~0xffff) | (v & 0xFFFE); }
+
+static void BLTSIZE (uae_u16 v)
+{
+    maybe_blit (current_hpos(), 0);
+
+    blt_info.vblitsize = v >> 6;
+    blt_info.hblitsize = v & 0x3F;
+    if (!blt_info.vblitsize) blt_info.vblitsize = 1024;
+    if (!blt_info.hblitsize) blt_info.hblitsize = 64;
+    do_blitter (current_hpos());
+}
+
+static void BLTSIZV (uae_u16 v)
+{
+    if (! (currprefs.chipset_mask & CSMASK_ECS_AGNUS))
+       return;
+    maybe_blit (current_hpos(), 0);
+    blt_info.vblitsize = v & 0x7FFF;
+}
+
+static void BLTSIZH (uae_u16 v)
+{
+    if (! (currprefs.chipset_mask & CSMASK_ECS_AGNUS))
+       return;
+    maybe_blit (current_hpos(), 0);
+    blt_info.hblitsize = v & 0x7FF;
+    if (!blt_info.vblitsize) blt_info.vblitsize = 32768;
+    if (!blt_info.hblitsize) blt_info.hblitsize = 0x800;
+    do_blitter (current_hpos());
+}
+
+STATIC_INLINE void SPRxCTLPOS (int num)
+{
+    int sprxp;
+    struct sprite *s = &spr[num];
+
+    sprxp = (sprpos[num] & 0xFF) * 2 + (sprctl[num] & 1);
+    /* Quite a bit salad in this register... */
+#ifdef AGA
+    if (currprefs.chipset_mask & CSMASK_AGA) {
+       /* We ignore the SHRES 35ns increment for now; SHRES support doesn't
+          work anyway, so we may as well restrict AGA sprites to a 70ns
+          resolution.  */
+       sprxp <<= 1;
+       sprxp |= (sprctl[num] >> 4) & 1;
+    }
+#endif
+    s->xpos = sprxp;
+    s->vstart = (sprpos[num] >> 8) | ((sprctl[num] << 6) & 0x100);
+    s->vstop = (sprctl[num] >> 8) | ((sprctl[num] << 7) & 0x100);
+    if (currprefs.chipset_mask & CSMASK_ECS_AGNUS) {
+       s->vstart |= (sprctl[num] << 3) & 0x200;
+       s->vstop |= (sprctl[num] << 4) & 0x200;
+    }
+    if (vpos == s->vstart)
+        s->dmastate = 1;
+    if (vpos == s->vstop)
+        s->dmastate = 0;
+}
+    
+STATIC_INLINE void SPRxCTL_1 (uae_u16 v, int num, int hpos)
+{
+    struct sprite *s = &spr[num];
+    sprctl[num] = v;
+    nr_armed -= s->armed;
+    s->armed = 0;
+    SPRxCTLPOS (num);
+#if SPRITE_DEBUG > 0
+    if (vpos >= SPRITE_DEBUG_MINY && vpos <= SPRITE_DEBUG_MAXY) {
+       write_log ("%d:%d:SPR%dCTL %04.4X VSTRT=%d VSTOP=%d HSTRT=%d DMA=%d ARM=%d COP=%x PC=%x\n",
+           vpos, hpos, num, v, s->vstart, s->vstop, s->xpos, spr[num].dmastate, spr[num].armed, cop_state.ip, m68k_getpc());
+    }
+#endif
+
+}
+STATIC_INLINE void SPRxPOS_1 (uae_u16 v, int num, int hpos)
+{
+    struct sprite *s = &spr[num];
+    sprpos[num] = v;
+    SPRxCTLPOS (num);
+#if SPRITE_DEBUG > 0
+    if (vpos >= SPRITE_DEBUG_MINY && vpos <= SPRITE_DEBUG_MAXY) {
+        write_log ("%d:%d:SPR%dPOS %04.4X VSTRT=%d VSTOP=%d HSTRT=%d DMA=%d ARM=%d COP=%x PC=%x\n",
+           vpos, hpos, num, v, s->vstart, s->vstop, s->xpos, spr[num].dmastate, spr[num].armed, cop_state.ip, m68k_getpc());
+    }
+#endif
+}
+STATIC_INLINE void SPRxDATA_1 (uae_u16 v, int num, int hpos)
+{
+    sprdata[num][0] = v;
+#ifdef AGA
+    sprdata[num][1] = v;
+    sprdata[num][2] = v;
+    sprdata[num][3] = v;
+#endif
+    nr_armed += 1 - spr[num].armed;
+    spr[num].armed = 1;
+#if SPRITE_DEBUG > 1
+    if (vpos >= SPRITE_DEBUG_MINY && vpos <= SPRITE_DEBUG_MAXY) {
+        write_log ("%d:%d:SPR%dDATA %04.4X DMA=%d ARM=%d PC=%x\n",
+           vpos, hpos, num, v, spr[num].dmastate, spr[num].armed, m68k_getpc());
+    }
+#endif
+}
+STATIC_INLINE void SPRxDATB_1 (uae_u16 v, int num, int hpos)
+{
+    sprdatb[num][0] = v;
+#ifdef AGA
+    sprdatb[num][1] = v;
+    sprdatb[num][2] = v;
+    sprdatb[num][3] = v;
+#endif
+#if SPRITE_DEBUG > 1
+    if (vpos >= SPRITE_DEBUG_MINY && vpos <= SPRITE_DEBUG_MAXY) {
+        write_log ("%d:%d:SPR%dDATB %04.4X DMA=%d ARM=%d PC=%x\n",
+           vpos, hpos, num, v, spr[num].dmastate, spr[num].armed, m68k_getpc());
+    }
+#endif
+}
+static void SPRxDATA (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxDATA_1 (v, num, hpos); }
+static void SPRxDATB (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxDATB_1 (v, num, hpos); }
+static void SPRxCTL (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxCTL_1 (v, num, hpos); }
+static void SPRxPOS (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxPOS_1 (v, num, hpos); }
+static void SPRxPTH (int hpos, uae_u16 v, int num)
+{
+    decide_sprites (hpos);
+    spr[num].pt &= 0xffff;
+    spr[num].pt |= (uae_u32)v << 16;
+#if SPRITE_DEBUG > 0
+    if (vpos >= SPRITE_DEBUG_MINY && vpos <= SPRITE_DEBUG_MAXY) {
+        write_log ("%d:%d:SPR%dPTH %08.8X\n", vpos, hpos, num, spr[num].pt);
+    }
+#endif
+}
+static void SPRxPTL (int hpos, uae_u16 v, int num)
+{
+    decide_sprites (hpos);
+    spr[num].pt &= ~0xffff;
+    spr[num].pt |= v;
+#if SPRITE_DEBUG > 0
+     if (vpos >= SPRITE_DEBUG_MINY && vpos <= SPRITE_DEBUG_MAXY) {
+       write_log ("%d:%d:SPR%dPTL %08.8X\n", vpos, hpos, num, spr[num].pt);
+     }
+#endif
+}
+
+static void CLXCON (uae_u16 v)
+{
+    clxcon = v;
+    clxcon_bpl_enable = (v >> 6) & 63;
+    clxcon_bpl_match = v & 63;
+    //write_log("CLXCON: %04.4X PC=%x\n", v, m68k_getpc());
+}
+
+static void CLXCON2 (uae_u16 v)
+{
+    if (!(currprefs.chipset_mask & CSMASK_AGA))
+       return;
+    clxcon2 = v;
+    clxcon_bpl_enable |= v & (0x40|0x80);
+    clxcon_bpl_match |= (v & (0x01|0x02)) << 6;
+    //write_log("CLXCON2: %04.4X\n", v);
+}
+
+static uae_u16 CLXDAT (void)
+{
+    uae_u16 v = clxdat | 0x8000;
+    //write_log("%d:CLXDAT %04.4X PC=%x\n", vpos, v, m68k_getpc());
+    clxdat = 0;
+    return v;
+}
+
+#ifdef AGA
+static uae_u16 COLOR_READ (int num)
+{
+    int cr, cg, cb, colreg;
+    uae_u16 cval;
+
+    if (!(currprefs.chipset_mask & CSMASK_AGA) || !(bplcon2 & 0x0100))
+       return 0xffff;
+
+    colreg = ((bplcon3 >> 13) & 7) * 32 + num;
+    cr = current_colors.color_regs_aga[colreg] >> 16;
+    cg = (current_colors.color_regs_aga[colreg] >> 8) & 0xFF;
+    cb = current_colors.color_regs_aga[colreg] & 0xFF;
+    if (bplcon3 & 0x200)
+       cval = ((cr & 15) << 8) | ((cg & 15) << 4) | ((cb & 15) << 0);
+    else
+       cval = ((cr >> 4) << 8) | ((cg >> 4) << 4) | ((cb >> 4) << 0);
+    return cval;
+}
+#endif
+
+static void COLOR_WRITE (int hpos, uae_u16 v, int num)
+{
+    v &= 0xFFF;
+#ifdef AGA
+    if (currprefs.chipset_mask & CSMASK_AGA) {
+       int r,g,b;
+       int cr,cg,cb;
+       int colreg;
+       uae_u32 cval;
+
+       /* writing is disabled when RDRAM=1 */
+       if (bplcon2 & 0x0100)
+           return;
+
+       colreg = ((bplcon3 >> 13) & 7) * 32 + num;
+       r = (v & 0xF00) >> 8;
+       g = (v & 0xF0) >> 4;
+       b = (v & 0xF) >> 0;
+       cr = current_colors.color_regs_aga[colreg] >> 16;
+       cg = (current_colors.color_regs_aga[colreg] >> 8) & 0xFF;
+       cb = current_colors.color_regs_aga[colreg] & 0xFF;
+
+       if (bplcon3 & 0x200) {
+           cr &= 0xF0; cr |= r;
+           cg &= 0xF0; cg |= g;
+           cb &= 0xF0; cb |= b;
+       } else {
+           cr = r + (r << 4);
+           cg = g + (g << 4);
+           cb = b + (b << 4);
+       }
+       cval = (cr << 16) | (cg << 8) | cb;
+       if (cval == current_colors.color_regs_aga[colreg])
+           return;
+
+       /* Call this with the old table still intact. */
+       record_color_change (hpos, colreg, cval);
+       remembered_color_entry = -1;
+       current_colors.color_regs_aga[colreg] = cval;
+       current_colors.acolors[colreg] = CONVERT_RGB (cval);
+   } else {
+#endif
+       if (current_colors.color_regs_ecs[num] == v)
+           return;
+       /* Call this with the old table still intact. */
+       record_color_change (hpos, num, v);
+       remembered_color_entry = -1;
+       current_colors.color_regs_ecs[num] = v;
+       current_colors.acolors[num] = xcolors[v];
+#ifdef AGA
+    }
+#endif
+}
+
+/* The copper code.  The biggest nightmare in the whole emulator.
+
+   Alright.  The current theory:
+   1. Copper moves happen 2 cycles after state READ2 is reached.
+      It can't happen immediately when we reach READ2, because the
+      data needs time to get back from the bus.  An additional 2
+      cycles are needed for non-Agnus registers, to take into account
+      the delay for moving data from chip to chip.
+   2. As stated in the HRM, a WAIT really does need an extra cycle
+      to wake up.  This is implemented by _not_ falling through from
+      a successful wait to READ1, but by starting the next cycle.
+      (Note: the extra cycle for the WAIT apparently really needs a
+      free cycle; i.e. contention with the bitplane fetch can slow
+      it down).
+   3. Apparently, to compensate for the extra wake up cycle, a WAIT
+      will use the _incremented_ horizontal position, so the WAIT
+      cycle normally finishes two clocks earlier than the position
+      it was waiting for.  The extra cycle then takes us to the
+      position that was waited for.
+      If the earlier cycle is busy with a bitplane, things change a bit.
+      E.g., waiting for position 0x50 in a 6 plane display: In cycle
+      0x4e, we fetch BPL5, so the wait wakes up in 0x50, the extra cycle
+      takes us to 0x54 (since 0x52 is busy), then we have READ1/READ2,
+      and the next register write is at 0x5c.
+   4. The last cycle in a line is not usable for the copper.
+   5. A 4 cycle delay also applies to the WAIT instruction.  This means
+      that the second of two back-to-back WAITs (or a WAIT whose
+      condition is immediately true) takes 8 cycles.
+   6. This also applies to a SKIP instruction.  The copper does not
+      fetch the next instruction while waiting for the second word of
+      a WAIT or a SKIP to arrive.
+   7. A SKIP also seems to need an unexplained additional two cycles
+      after its second word arrives; this is _not_ a memory cycle (I
+      think, the documentation is pretty clear on this).
+   8. Two additional cycles are inserted when writing to COPJMP1/2.  */
+
+/* Determine which cycles are available for the copper in a display
+ * with a agiven number of planes.  */
+
+int is_bitplane_dma (int hpos)
+{
+    if (fetch_state == fetch_not_started || hpos < thisline_decision.plfleft)
+       return 0;
+    if ((passed_plfstop == 3 && hpos >= thisline_decision.plfright)
+       || hpos >= estimated_last_fetch_cycle)
+       return 0;
+    return curr_diagram[(hpos - cycle_diagram_shift) & fetchstart_mask];
+}
+
+STATIC_INLINE int is_bitplane_dma_inline (int hpos)
+{
+    if (fetch_state == fetch_not_started || hpos < thisline_decision.plfleft)
+       return 0;
+    if ((passed_plfstop == 3 && hpos >= thisline_decision.plfright)
+       || hpos >= estimated_last_fetch_cycle)
+       return 0;
+    return curr_diagram[(hpos - cycle_diagram_shift) & fetchstart_mask];
+}
+
+STATIC_INLINE int copper_cant_read (int hpos)
+{
+    if (hpos + 1 >= maxhpos)
+       return 1;
+    return is_bitplane_dma_inline (hpos);
+}
+
+STATIC_INLINE int dangerous_reg (int reg)
+{
+    /* Safe:
+     * Bitplane pointers, control registers, modulos and data.
+     * Sprite pointers, control registers, and data.
+     * Color registers.  */
+    if (reg >= 0xE0 && reg < 0x1C0)
+       return 0;
+    return 1;
+}
+
+#define FAST_COPPER 1
+
+/* The future, Conan?
+   We try to look ahead in the copper list to avoid doing continuous calls
+   to updat_copper (which is what happens when SPCFLAG_COPPER is set).  If
+   we find that the same effect can be achieved by setting a delayed event
+   and then doing multiple copper insns in one batch, we can get a massive
+   speedup.
+
+   We don't try to be precise here.  All copper reads take exactly 2 cycles,
+   the effect of bitplane contention is ignored.  Trying to get it exactly
+   right would be much more complex and as such carry a huge risk of getting
+   it subtly wrong; and it would also be more expensive - we want this code
+   to be fast.  */
+static void predict_copper (void)
+{
+    uaecptr ip = cop_state.ip;
+    unsigned int c_hpos = cop_state.hpos;
+    enum copper_states state = cop_state.state;
+    unsigned int w1, w2, cycle_count;
+
+    switch (state) {
+    case COP_read1_wr_in2:
+    case COP_read2_wr_in2:
+    case COP_read1_wr_in4:
+       if (dangerous_reg (cop_state.saved_i1))
+           return;
+       state = state == COP_read2_wr_in2 ? COP_read2 : COP_read1;
+       break;
+
+    case COP_read1_in2:
+       c_hpos += 2;
+       state = COP_read1;
+       break;
+
+    case COP_stop:
+    case COP_bltwait:
+    case COP_wait1:
+    case COP_skip_in4:
+    case COP_skip_in2:
+    case COP_skip1:
+    case COP_strobe_delay:
+       return;
+
+    case COP_wait_in4:
+       c_hpos += 2;
+       /* fallthrough */
+    case COP_wait_in2:
+       c_hpos += 2;
+       /* fallthrough */
+    case COP_wait:
+       state = COP_wait;
+       break;
+
+    default:
+       break;
+    }
+
+    /* Only needed for COP_wait, but let's shut up the compiler.  */
+    w1 = cop_state.saved_i1;
+    w2 = cop_state.saved_i2;
+    cop_state.first_sync = c_hpos;
+    cop_state.regtypes_modified = REGTYPE_FORCE;
+
+    /* Get this case out of the way, so that the loop below only has to deal
+       with read1 and wait.  */
+    if (state == COP_read2) {
+       w1 = cop_state.i1;
+       if (w1 & 1) {
+           w2 = chipmem_wget (ip);
+           if (w2 & 1)
+               goto done;
+           state = COP_wait;
+           c_hpos += 4;
+       } else if (dangerous_reg (w1)) {
+           c_hpos += 4;
+           goto done;
+       } else {
+           cop_state.regtypes_modified |= regtypes[w1 & 0x1FE];
+           state = COP_read1;
+           c_hpos += 2;
+       }
+       ip += 2;        
+    }
+
+    while (c_hpos + 1 < maxhpos) {
+       if (state == COP_read1) {
+           w1 = chipmem_wget (ip);
+           if (w1 & 1) {
+               w2 = chipmem_wget (ip + 2);
+               if (w2 & 1)
+                   break;
+               state = COP_wait;
+               c_hpos += 6;
+           } else if (dangerous_reg (w1)) {
+               c_hpos += 6;
+               break;
+           } else {
+               cop_state.regtypes_modified |= regtypes[w1 & 0x1FE];
+               c_hpos += 4;
+           }
+           ip += 4;
+       } else if (state == COP_wait) {
+           if ((w2 & 0xFE) != 0xFE)
+               break;
+           else {
+               unsigned int vcmp = (w1 & (w2 | 0x8000)) >> 8;
+               unsigned int hcmp = (w1 & 0xFE);
+
+               unsigned int vp = vpos & (((w2 >> 8) & 0x7F) | 0x80);
+               if (vp < vcmp) {
+                   /* Whee.  We can wait until the end of the line!  */
+                   c_hpos = maxhpos;
+               } else if (vp > vcmp || hcmp <= c_hpos) {
+                   state = COP_read1;
+                   /* minimum wakeup time */
+                   c_hpos += 2;
+               } else {
+                   state = COP_read1;
+                   c_hpos = hcmp;
+               }
+               /* If this is the current instruction, remember that we don't
+                  need to sync CPU and copper anytime soon.  */
+               if (cop_state.ip == ip) {
+                   cop_state.first_sync = c_hpos;
+               }
+           }
+       } else
+           uae_abort ("predict copper %d", state);
+    }
+
+  done:
+    cycle_count = c_hpos - cop_state.hpos;
+    if (cycle_count >= 8) {
+       unset_special (SPCFLAG_COPPER);
+       eventtab[ev_copper].active = 1;
+       eventtab[ev_copper].oldcycles = get_cycles ();
+       eventtab[ev_copper].evtime = get_cycles () + cycle_count * CYCLE_UNIT;
+       events_schedule ();
+    }
+}
+
+static int test_copper_dangerous (unsigned int address)
+{
+    if ((address & 0x1fe) < (copcon & 2 ? ((currprefs.chipset_mask & CSMASK_AGA) ? 0 : 0x40u) : 0x80u)) {
+       cop_state.state = COP_stop;     
+       copper_enabled_thisline = 0;
+       unset_special (SPCFLAG_COPPER);
+       return 1;
+    }
+    return 0;
+}
+
+static void perform_copper_write (int old_hpos)
+{
+    unsigned int address = cop_state.saved_i1 & 0x1FE;
+
+    record_copper (cop_state.saved_ip - 4, old_hpos, vpos);
+
+    if (test_copper_dangerous (address))
+       return;
+    if (address == 0x88) {
+       cop_state.ip = cop1lc;
+       cop_state.state = COP_strobe_delay;
+    } else if (address == 0x8A) {
+       cop_state.ip = cop2lc;
+       cop_state.state = COP_strobe_delay;
+    } else
+       custom_wput_1 (old_hpos, cop_state.saved_i1, cop_state.saved_i2, 0);
+}
+
+static int isagnus[]= {
+    1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* 32 0x00 - 0x3e */
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 27 0x40 - 0x74 */
+    0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, /* 21 */
+    1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0, /* 32 0xa0 - 0xde
+    /* BPLxPTH/BPLxPTL */
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 16 */
+    0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0, /* 16 */
+    /* SPRxPTH/SPRxPTL */
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 16 */
+    /* SPRxPOS/SPRxCTL/SPRxDATA/SPRxDATB */
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    /* COLORxx */
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    /* RESERVED */
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+};
+
+static void dump_copper (char *error, int until_hpos)
+{
+    write_log("%s: vpos=%d until_hpos=%d\n",
+       error, vpos, until_hpos);
+    write_log("cvcmp=%d chcmp=%d chpos=%d cvpos=%d ci1=%04.4X ci2=%04.4X\n",
+       cop_state.vcmp,cop_state.hcmp,cop_state.hpos,cop_state.vpos,cop_state.saved_i1,cop_state.saved_i2);
+    write_log("cstate=%d ip=%08.8X ev_copper=%d\n",
+       cop_state.state,cop_state.ip,eventtab[ev_copper].active);
+}
+
+static void update_copper (int until_hpos)
+{
+    int vp = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);    
+    int c_hpos = cop_state.hpos;
+
+    if (eventtab[ev_copper].active) {
+       static int warned;
+       if (!warned) {
+           dump_copper ("error1",until_hpos);
+           warned = 1;
+       }
+       eventtab[ev_copper].active = 0;
+       return;
+       uae_abort ("update_copper1");
+    }
+
+    if (cop_state.state == COP_wait && vp < cop_state.vcmp) {
+       static int warned;
+       if (!warned) {
+           dump_copper ("error2",until_hpos);
+           warned = 1;
+       }
+       copper_enabled_thisline = 0;
+       return;
+       uae_abort ("update_copper2");
+    }
+    
+    until_hpos &= ~1;
+
+    if (until_hpos > (maxhpos & ~1))
+       until_hpos = maxhpos & ~1;
+
+    until_hpos += 2;
+    for (;;) {
+       int old_hpos = c_hpos;
+       int hp;
+
+       if (c_hpos >= until_hpos)
+           break;
+
+       /* So we know about the fetch state.  */
+       decide_line (c_hpos);
+       
+       switch (cop_state.state) {
+       case COP_read1_in2:
+           cop_state.state = COP_read1;
+           break;
+       case COP_read1_wr_in2:
+           cop_state.state = COP_read1;
+           perform_copper_write (old_hpos);
+           /* That could have turned off the copper.  */
+           if (! copper_enabled_thisline)
+               goto out;
+
+           break;
+       case COP_read1_wr_in4:
+           cop_state.state = COP_read1_wr_in2;
+           break;
+       case COP_read2_wr_in2:
+           cop_state.state = COP_read2;
+           perform_copper_write (old_hpos);
+           /* That could have turned off the copper.  */
+           if (! copper_enabled_thisline)
+               goto out;
+
+           break;
+       case COP_wait_in2:
+           cop_state.state = COP_wait1;
+           break;
+       case COP_wait_in4:
+           cop_state.state = COP_wait_in2;
+           break;
+       case COP_skip_in2:
+           cop_state.state = COP_skip1;
+           break;
+       case COP_skip_in4:
+           cop_state.state = COP_skip_in2;
+           break;
+        case COP_strobe_delay:
+           cop_state.state = COP_read1;
+           break;
+
+       default:
+           break;
+       }
+
+       c_hpos += 2;
+#if 0
+        if (copper_cant_read (old_hpos))
+           continue;
+#endif
+        if (cop_state.strobe) {
+           cop_state.ip = cop_state.strobe == 1 ? cop1lc : cop2lc;
+           cop_state.strobe = 0;
+       }
+
+       switch (cop_state.state) {
+
+       case COP_read1_wr_in4:
+           uae_abort ("COP_read1_wr_in4");
+
+       case COP_read1_wr_in2:
+       case COP_read1:
+           if (copper_cant_read (old_hpos))
+               continue;
+           cop_state.i1 = chipmem_wget (cop_state.ip);
+#ifdef CPUEMU_6
+           cycle_line[old_hpos] |= CYCLE_COPPER;
+#endif
+           cop_state.ip += 2;
+           cop_state.state = cop_state.state == COP_read1 ? COP_read2 : COP_read2_wr_in2;
+           break;
+
+       case COP_read2_wr_in2:
+           uae_abort ("read2_wr_in2");
+
+       case COP_read2:
+           if (copper_cant_read (old_hpos))
+               continue;
+           cop_state.i2 = chipmem_wget (cop_state.ip);
+#ifdef CPUEMU_6
+           cycle_line[old_hpos] |= CYCLE_COPPER;
+#endif
+           cop_state.ip += 2;
+           if (cop_state.ignore_next) {
+               cop_state.ignore_next = 0;
+               cop_state.state = COP_read1;
+               break;
+           }
+
+           cop_state.saved_i1 = cop_state.i1;
+           cop_state.saved_i2 = cop_state.i2;
+           cop_state.saved_ip = cop_state.ip;
+
+           if (cop_state.i1 & 1) {
+               if (cop_state.i2 & 1)
+                   cop_state.state = COP_skip_in4;
+               else
+                   cop_state.state = COP_wait_in4;
+           } else {
+               unsigned int reg = cop_state.i1 & 0x1FE;
+               cop_state.state = isagnus[reg >> 1] ? COP_read1_wr_in2 : COP_read1_wr_in4;
+           }
+           break;
+
+       case COP_wait1:
+           /* There's a nasty case here.  As stated in the "Theory" comment above, we
+              test against the incremented copper position.  I believe this means that
+              we have to increment the _vertical_ position at the last cycle in the line,
+              and set the horizontal position to 0.
+              Normally, this isn't going to make a difference, since we consider these
+              last cycles unavailable for the copper, so waking up in the last cycle has
+              the same effect as waking up at the start of the line.  However, there is
+              one possible problem:  If we're at 0xFFE0, any wait for an earlier position
+              must _not_ complete (since, in effect, the current position will be back
+              at 0/0).  This can be seen in the Superfrog copper list.
+              Things get monstrously complicated if we try to handle this "properly" by
+              incrementing vpos and setting c_hpos to 0.  Especially the various speedup
+              hacks really assume that vpos remains constant during one line.  Hence,
+              this hack: defer the entire decision until the next line if necessary.  */
+           if (c_hpos >= (maxhpos & ~1))
+               break;
+
+           cop_state.state = COP_wait;
+
+           cop_state.vcmp = (cop_state.saved_i1 & (cop_state.saved_i2 | 0x8000)) >> 8;
+           cop_state.hcmp = (cop_state.saved_i1 & cop_state.saved_i2 & 0xFE);
+
+           vp = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
+           if (cop_state.saved_i1 == 0xFFFF && cop_state.saved_i2 == 0xFFFE) {
+               cop_state.state = COP_stop;
+               copper_enabled_thisline = 0;
+               unset_special (SPCFLAG_COPPER);
+               goto out;
+           }
+           if (vp < cop_state.vcmp) {
+               copper_enabled_thisline = 0;
+               unset_special (SPCFLAG_COPPER);
+               goto out;
+           }
+
+           /* fall through */
+       case COP_wait:
+           if (vp < cop_state.vcmp)
+               uae_abort ("vp < cop_state.vcmp");
+           if (copper_cant_read (old_hpos))
+               continue;
+
+           hp = c_hpos & (cop_state.saved_i2 & 0xFE);
+           if (vp == cop_state.vcmp && hp < cop_state.hcmp) {
+               /* Position not reached yet.  */
+               if (currprefs.fast_copper && FAST_COPPER && (cop_state.saved_i2 & 0xFE) == 0xFE) {
+                   int wait_finish = cop_state.hcmp - 2;
+                   /* This will leave c_hpos untouched if it's equal to wait_finish.  */
+                   if (wait_finish < c_hpos)
+                       uae_abort ("wait_finish < c_hpos");
+                   else if (wait_finish <= until_hpos) {
+                       c_hpos = wait_finish;
+                   } else
+                       c_hpos = until_hpos;
+               }             
+               break;
+           }
+
+           /* Now we know that the comparisons were successful.  We might still
+              have to wait for the blitter though.  */
+           if ((cop_state.saved_i2 & 0x8000) == 0 && (DMACONR() & 0x4000)) {
+               /* We need to wait for the blitter.  */
+               cop_state.state = COP_bltwait;
+               copper_enabled_thisline = 0;
+               unset_special (SPCFLAG_COPPER);
+               goto out;
+           }
+
+           record_copper (cop_state.ip - 4, old_hpos, vpos);
+
+           cop_state.state = COP_read1;
+           break;
+
+       case COP_skip1:
+       {
+           static int skipped_before;
+           unsigned int vcmp, hcmp, vp1, hp1;
+
+           if (! skipped_before) {
+               skipped_before = 1;
+               write_log ("Program uses Copper SKIP instruction.\n");
+           }
+
+           if (c_hpos >= (maxhpos & ~1))
+               break;
+
+           vcmp = (cop_state.saved_i1 & (cop_state.saved_i2 | 0x8000)) >> 8;
+           hcmp = (cop_state.saved_i1 & cop_state.saved_i2 & 0xFE);
+           vp1 = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
+           hp1 = c_hpos & (cop_state.saved_i2 & 0xFE);
+
+           if ((vp1 > vcmp || (vp1 == vcmp && hp1 >= hcmp))
+               && ((cop_state.saved_i2 & 0x8000) != 0 || ! (DMACONR() & 0x4000)))
+               cop_state.ignore_next = 1;
+           if (chipmem_wget (cop_state.ip) & 1) { /* FIXME: HACK!!! */
+               /* copper never skips if following instruction is WAIT or another SKIP... */
+               cop_state.ignore_next = 0;
+           }
+
+           cop_state.state = COP_read1;
+
+           if (cop_state.ignore_next && (chipmem_wget (cop_state.ip) & 1) == 0) {
+               /* another undocumented copper feature:
+                  copper stops if skipped instruction is MOVE to dangerous register...
+               */
+               test_copper_dangerous (chipmem_wget(cop_state.ip));
+           }
+
+           record_copper (cop_state.ip - 4, old_hpos, vpos);
+
+           break;
+       }
+       default:
+           break;
+       }
+    }
+
+  out:
+    cop_state.hpos = c_hpos;
+
+    /* The test against maxhpos also prevents us from calling predict_copper
+       when we are being called from hsync_handler, which would not only be
+       stupid, but actively harmful.  */
+    if (currprefs.fast_copper && FAST_COPPER && (regs.spcflags & SPCFLAG_COPPER) && c_hpos + 8 < maxhpos)
+       predict_copper ();
+}
+
+static void compute_spcflag_copper (void)
+{
+    copper_enabled_thisline = 0;
+    unset_special (SPCFLAG_COPPER);
+    if (! dmaen (DMA_COPPER) || cop_state.state == COP_stop || cop_state.state == COP_bltwait)
+       return;
+
+    if (cop_state.state == COP_wait) {
+       int vp = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
+
+       if (vp < cop_state.vcmp)
+           return;
+    }
+    copper_enabled_thisline = 1;
+
+    if (currprefs.fast_copper && FAST_COPPER)
+       predict_copper ();
+
+    if (! eventtab[ev_copper].active)
+       set_special (SPCFLAG_COPPER);
+}
+
+static void copper_handler (void)
+{
+    /* This will take effect immediately, within the same cycle.  */
+    set_special (SPCFLAG_COPPER);
+
+    if (! copper_enabled_thisline)
+       uae_abort ("copper_handler");
+
+    eventtab[ev_copper].active = 0;
+}
+
+void blitter_done_notify (void)
+{
+    if (cop_state.state != COP_bltwait)
+       return;
+
+    cop_state.hpos = current_hpos () & ~1;
+    cop_state.vpos = vpos;
+    cop_state.state = COP_wait;
+    compute_spcflag_copper ();
+}
+
+void do_copper (void)
+{
+    int hpos = current_hpos ();
+    update_copper (hpos);
+}
+
+/* ADDR is the address that is going to be read/written; this access is
+   the reason why we want to update the copper.  This function is also
+   used from hsync_handler to finish up the line; for this case, we check
+   hpos against maxhpos.  */
+STATIC_INLINE void sync_copper_with_cpu (int hpos, int do_schedule, unsigned int addr)
+{
+    /* Need to let the copper advance to the current position.  */
+    if (eventtab[ev_copper].active) {
+       if (hpos != maxhpos) {
+           /* There might be reasons why we don't actually need to bother
+              updating the copper.  */
+           if (hpos < cop_state.first_sync)
+               return;
+
+           if ((cop_state.regtypes_modified & regtypes[addr & 0x1FE]) == 0)
+               return;
+       }
+
+       eventtab[ev_copper].active = 0;
+       if (do_schedule)
+           events_schedule ();
+       set_special (SPCFLAG_COPPER);
+    }
+    if (copper_enabled_thisline)
+       update_copper (hpos);
+}
+
+STATIC_INLINE uae_u16 sprite_fetch (struct sprite *s, int dma, int hpos)
+{
+    uae_u16 data = last_custom_value;
+    if (dma) {
+        data = last_custom_value = chipmem_wget (s->pt);
+#ifdef CPUEMU_6
+       cycle_line[hpos] |= CYCLE_SPRITE;
+#endif
+    }
+    s->pt += 2;
+    return data;
+}
+
+STATIC_INLINE void do_sprites_1 (int num, int cycle, int hpos)
+{
+    struct sprite *s = &spr[num];
+    int dma, posctl = 0;
+    uae_u16 data;
+
+    if (vpos == s->vstart) {
+        s->dmastate = 1;
+#if SPRITE_DEBUG > 0
+       write_log ("%d:SPR%d START\n", vpos, num);
+#endif
+    }
+    if (vpos == s->vstop || vpos == sprite_vblank_endline) {
+        s->dmastate = 0;
+#if SPRITE_DEBUG > 0
+       write_log ("%d:SPR%d STOP\n", vpos, num);
+#endif
+    }
+    if (!dmaen (DMA_SPRITE))
+       return;
+    dma = hpos < plfstrt || diwstate != DIW_waiting_stop || !dmaen (DMA_BITPLANE);
+    if (vpos == s->vstop || vpos == sprite_vblank_endline) {
+       s->dmastate = 0;
+       posctl = 1;
+        if (dma) {
+           data = sprite_fetch (s, dma, hpos);
+           s->pt += (sprite_width >> 3) - 2;
+       } else {
+            data = cycle == 0 ? sprpos[num] : sprctl[num];
+       }
+#if SPRITE_DEBUG > 1
+        if (vpos >= SPRITE_DEBUG_MINY && vpos <= SPRITE_DEBUG_MAXY) {
+           write_log ("dma:");
+       }
+#endif
+        if (cycle == 0)
+           SPRxPOS_1 (data, num, hpos);
+       else
+           SPRxCTL_1 (data, num, hpos);
+    }
+    if (s->dmastate && !posctl) {
+       uae_u16 data = sprite_fetch (s, dma, hpos);
+        /* Hack for X mouse auto-calibration */
+        if (num == 0 && cycle == 0)
+            mousehack_handle (sprctl[0], sprpos[0]);
+#if SPRITE_DEBUG > 1
+        if (vpos >= SPRITE_DEBUG_MINY && vpos <= SPRITE_DEBUG_MAXY) {
+           write_log ("dma:");
+       }
+#endif
+        if (cycle == 0)
+            SPRxDATA_1 (dma ? data : sprdata[num][0], num, hpos);
+        else
+            SPRxDATB_1 (dma ? data : sprdatb[num][0], num, hpos);
+#ifdef AGA
+        switch (sprite_width)
+            {
+            case 64:
+           {
+               uae_u16 data32 = sprite_fetch (s, dma, hpos);
+               uae_u16 data641 = sprite_fetch (s, dma, hpos);
+               uae_u16 data642 = sprite_fetch (s, dma, hpos);
+               if (dma) {
+                   if (cycle == 0) {
+                       sprdata[num][3] = data642;
+                       sprdata[num][2] = data641;
+                       sprdata[num][1] = data32;
+                   } else {
+                       sprdatb[num][3] = data642;
+                       sprdatb[num][2] = data641;
+                       sprdatb[num][1] = data32;
+                   }
+               }
+           }
+            break;
+            case 32:
+           {   
+               uae_u16 data32 = sprite_fetch (s, dma, hpos);
+               if (dma) {
+                   if (cycle == 0)
+                       sprdata[num][1] = data32;
+                   else
+                       sprdatb[num][1] = data32;
+               }
+           }
+           break;
+       }
+#endif
+    }
+}
+
+static void do_sprites (int hpos)
+{
+    int maxspr, minspr;
+    int i;
+
+    /* I don't know whether this is right. Some programs write the sprite pointers
+     * directly at the start of the copper list. With the test against currvp, the
+     * first two words of data are read on the second line in the frame. The problem
+     * occurs when the program jumps to another copperlist a few lines further down
+     * which _also_ writes the sprite pointer registers. This means that a) writing
+     * to the sprite pointers sets the state to SPR_restart; or b) that sprite DMA
+     * is disabled until the end of the vertical blanking interval. The HRM
+     * isn't clear - it says that the vertical sprite position can be set to any
+     * value, but this wouldn't be the first mistake... */
+    /* Update: I modified one of the programs to write the sprite pointers the
+     * second time only _after_ the VBlank interval, and it showed the same behaviour
+     * as it did unmodified under UAE with the above check. This indicates that the
+     * solution below is correct. */
+    /* Another update: seems like we have to use the NTSC value here (see Sanity Turmoil
+     * demo).  */
+    /* Maximum for Sanity Turmoil: 27.
+       Minimum for Sanity Arte: 22.  */
+    if (vpos < sprite_vblank_endline)
+       return;
+
+#ifndef CUSTOM_SIMPLE
+    maxspr = hpos;
+    minspr = last_sprite_hpos;
+
+    if (minspr >= SPR0_HPOS + MAX_SPRITES * 4 || maxspr < SPR0_HPOS)
+       return;
+
+    if (maxspr > SPR0_HPOS + MAX_SPRITES * 4)
+       maxspr = SPR0_HPOS + MAX_SPRITES * 4;
+    if (minspr < SPR0_HPOS)
+        minspr = SPR0_HPOS;
+
+    for (i = minspr; i < maxspr; i++) {
+       int cycle = -1;
+        switch ((i - SPR0_HPOS) & 3)
+           {
+           case 0:
+           cycle = 0;
+           break;
+           case 2:
+           cycle = 1;
+           break;
+       }
+       if (cycle >= 0)
+           do_sprites_1 ((i - SPR0_HPOS) / 4, cycle, i);
+    }
+    last_sprite_hpos = hpos;
+#else
+    for (i = 0; i < MAX_SPRITES * 2; i++)
+       do_sprites_1 (i / 2, i & 1, 0);
+#endif
+}
+
+static void init_sprites (void)
+{
+    memset (sprpos, 0, sizeof sprpos);
+    memset (sprctl, 0, sizeof sprctl);
+}
+
+static void adjust_array_sizes (void)
+{
+#ifdef OS_WITHOUT_MEMORY_MANAGEMENT
+    if (delta_sprite_entry) {
+       void *p1,*p2;
+       int mcc = max_sprite_entry + 50 + delta_sprite_entry;
+       delta_sprite_entry = 0;
+       p1 = realloc (sprite_entries[0], mcc * sizeof (struct sprite_entry));
+       p2 = realloc (sprite_entries[1], mcc * sizeof (struct sprite_entry));
+       if (p1) sprite_entries[0] = p1;
+       if (p2) sprite_entries[1] = p2;
+       if (p1 && p2) {
+           write_log ("new max_sprite_entry=%d\n",mcc);
+           max_sprite_entry = mcc;
+       }
+    }
+    if (delta_color_change) {
+       void *p1,*p2;
+       int mcc = max_color_change + 200 + delta_color_change;
+       delta_color_change = 0;
+       p1 = realloc (color_changes[0], mcc * sizeof (struct color_change));
+       p2 = realloc (color_changes[1], mcc * sizeof (struct color_change));
+       if (p1) color_changes[0] = p1;
+       if (p2) color_changes[1] = p2;
+       if (p1 && p2) {
+           write_log ("new max_color_change=%d\n",mcc);
+           max_color_change = mcc;
+       }
+    }
+#endif
+}
+
+static void init_hardware_frame (void)
+{
+    next_lineno = 0;
+    nextline_how = nln_normal;
+    diwstate = DIW_waiting_start;
+    hdiwstate = DIW_waiting_start;
+    ddfstate = DIW_waiting_start;
+}
+
+void init_hardware_for_drawing_frame (void)
+{
+    adjust_array_sizes ();
+
+    /* Avoid this code in the first frame after a customreset.  */
+    if (prev_sprite_entries) {
+       int first_pixel = prev_sprite_entries[0].first_pixel;
+       int npixels = prev_sprite_entries[prev_next_sprite_entry].first_pixel - first_pixel;
+       memset (spixels + first_pixel, 0, npixels * sizeof *spixels);
+       memset (spixstate.bytes + first_pixel, 0, npixels * sizeof *spixstate.bytes);
+    }
+    prev_next_sprite_entry = next_sprite_entry;
+
+    next_color_change = 0;
+    next_sprite_entry = 0;
+    next_color_entry = 0;
+    remembered_color_entry = -1;
+
+    prev_sprite_entries = sprite_entries[current_change_set];
+    curr_sprite_entries = sprite_entries[current_change_set ^ 1];
+    prev_color_changes = color_changes[current_change_set];
+    curr_color_changes = color_changes[current_change_set ^ 1];
+    prev_color_tables = color_tables[current_change_set];
+    curr_color_tables = color_tables[current_change_set ^ 1];
+
+    prev_drawinfo = line_drawinfo[current_change_set];
+    curr_drawinfo = line_drawinfo[current_change_set ^ 1];
+    current_change_set ^= 1;
+
+    color_src_match = color_dest_match = -1;
+
+    /* Use both halves of the array in alternating fashion.  */
+    curr_sprite_entries[0].first_pixel = current_change_set * MAX_SPR_PIXELS;
+    next_sprite_forced = 1;
+}
+
+static void do_savestate(void);
+
+static int rpt_vsync (void)
+{
+    int v = read_processor_time () - vsyncmintime;
+    if (v > (int)syncbase || v < -((int)syncbase)) {
+       vsyncmintime = read_processor_time();
+       v = 0;
+    }
+    return v;
+}
+       
+static void framewait (void)
+{
+    frame_time_t curr_time;
+    int start;
+
+    for (;;) {
+        double v = rpt_vsync () / (syncbase / 1000.0);
+       if (v >= -4)
+           break;
+        sleep_millis_busy (1);
+    }
+    start = read_processor_time();
+    do {
+        curr_time = read_processor_time ();
+    } while (rpt_vsync () < 0);
+    vsyncmintime = curr_time + vsynctime;
+    idletime += read_processor_time() - start;
+}
+
+static int frametime2;
+
+void fpscounter_reset (void)
+{
+    timeframes = 0;
+    frametime2 = 0;
+    bogusframe = 2;
+    lastframetime = read_processor_time ();
+    idletime = 0;
+}
+
+static void fpscounter (void)
+{
+    int now, last;
+    
+    now = read_processor_time ();
+    last = now - lastframetime;
+    lastframetime = now;
+
+    if (bogusframe)
+       return;
+
+    frametime += last;
+    frametime2 += last;
+    timeframes++;
+    if ((timeframes & 31) == 0) {
+       double idle = 1000 - (idletime == 0 ? 0.0 : (double)idletime * 1000.0 / (vsynctime * 32.0));
+       int fps = frametime2 == 0 ? 0 : syncbase * 32 / (frametime2 / 10);
+       if (fps > 9999)
+               fps = 9999;
+       if (idle < 0)
+           idle = 0;
+       if (idle > 100 * 10)
+           idle = 100 * 10;
+       if (fake_vblank_hz * 10 > fps) {
+           double mult = (double)fake_vblank_hz * 10.0 / fps;
+           idle *= mult;
+       }
+       if (turbo_emulation && idle < 100 * 10)
+           idle = 100 * 10;
+       gui_fps (fps, (int)idle);
+       frametime2 = 0;
+       idletime = 0;
+    }
+}
+
+static void vsync_handler (void)
+{
+    fpscounter ();
+
+    if ((!currprefs.gfx_vsync || !currprefs.gfx_afullscreen)
+#ifdef AVIOUTPUT
+       && ((avioutput_framelimiter && avioutput_enabled) || !avioutput_enabled)
+#endif
+       ) {
+#ifdef JIT
+       if (!compiled_code) {
+#endif
+           if (currprefs.m68k_speed == -1) {
+               frame_time_t curr_time = read_processor_time ();
+               vsyncmintime += vsynctime;
+               /* @@@ Mathias? How do you think we should do this? */
+               /* If we are too far behind, or we just did a reset, adjust the
+                * needed time. */
+               if ((long int)(curr_time - vsyncmintime) > 0 || rpt_did_reset)
+                   vsyncmintime = curr_time + vsynctime;
+               rpt_did_reset = 0;
+           } else if (rpt_available) {
+               framewait ();
+           }
+#ifdef JIT
+       } else {
+           if (rpt_available && currprefs.m68k_speed == 0) {
+               framewait ();
+           }
+       }
+#endif
+    }
+
+    if (bogusframe > 0)
+       bogusframe--;
+
+    handle_events ();
+
+    INTREQ (0x8020);
+    if (bplcon0 & 4)
+       lof ^= 0x8000;
+
+#ifdef PICASSO96
+    /* And now let's update the Picasso palette, if required */
+    DX_SetPalette_vsync();
+    if (picasso_on)
+       picasso_handle_vsync ();
+#endif
+   vsync_handle_redraw (lof, lof_changed);
+
+    if (quit_program > 0) {
+       /* prevent possible infinite loop at wait_cycles().. */
+       framecnt = 0;
+        reset_decisions ();
+       return;
+    }
+
+    {
+       static int cnt = 0;
+       if (cnt == 0) {
+           /* resolution_check_change (); */
+           DISK_check_change ();
+           cnt = 5;
+       }
+       cnt--;
+    }
+
+    /* Start a new set of copper records.  */
+    curr_cop_set ^= 1;
+    nr_cop_records[curr_cop_set] = 0;
+
+    /* For now, let's only allow this to change at vsync time.  It gets too
+     * hairy otherwise.  */
+    if ((beamcon0 & (0x20|0x80)) != (new_beamcon0 & (0x20|0x80)) || hack_vpos)
+       init_hz ();
+
+    lof_changed = 0;
+
+    eventtab[ev_copper].active = 0;
+    COPJMP (1);
+
+    init_hardware_frame ();
+
+    if (ievent_alive > 0)
+       ievent_alive--;
+    if (timehack_alive > 0)
+       timehack_alive--;
+    inputdevice_vsync ();
+
+}
+
+#ifdef JIT
+
+#define N_LINES 8
+
+static __inline__ int trigger_frh(int v)
+{
+    return (v & (N_LINES - 1)) == 0;
+}
+
+extern int gonebad;
+
+static long int diff32(frame_time_t x, frame_time_t y)
+{
+    return (long int)(x-y);
+}
+static void frh_handler(void)
+{
+    if (currprefs.m68k_speed == -1) {
+       frame_time_t curr_time = read_processor_time ();
+       vsyncmintime += vsynctime * N_LINES / maxvpos;
+       /* @@@ Mathias? How do you think we should do this? */
+       /* If we are too far behind, or we just did a reset, adjust the
+        * needed time. */
+       if (rpt_did_reset) {
+           vsyncmintime = curr_time + vsynctime;
+           rpt_did_reset = 0;
+       }
+       /* Allow this to be one frame's worth of cycles out */
+       while (diff32 (curr_time, vsyncmintime + vsynctime) > 0) {
+           vsyncmintime += vsynctime * N_LINES / maxvpos;
+           gonebad++;
+       }
+    }
+}
+#endif
+
+static void copper_check (int n)
+{
+    if (cop_state.state == COP_wait) {
+       int vp = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
+       if (vp < cop_state.vcmp) {
+           if (eventtab[ev_copper].active || copper_enabled_thisline)
+               write_log ("COPPER BUG %d: vp=%d vpos=%d vcmp=%d act=%d thisline=%d\n", n, vp, vpos, cop_state.vcmp, eventtab[ev_copper].active, copper_enabled_thisline);
+       }
+    }
+}
+
+static void hsync_handler (void)
+{
+    static int ciahsync;
+    int hpos = current_hpos ();
+
+    /* Using 0x8A makes sure that we don't accidentally trip over the
+       modified_regtypes check.  */
+    sync_copper_with_cpu (maxhpos, 0, 0x8A);
+
+    //copper_check (1);
+
+    finish_decisions ();
+    if (thisline_decision.plfleft != -1) {
+       if (currprefs.collision_level > 1)
+           do_sprite_collisions ();
+       if (currprefs.collision_level > 2)
+           do_playfield_collisions ();
+    }
+    hsync_record_line_state (next_lineno, nextline_how, thisline_changed);
+
+    eventtab[ev_hsync].evtime += get_cycles () - eventtab[ev_hsync].oldcycles;
+    eventtab[ev_hsync].oldcycles = get_cycles ();
+    CIA_hsync_handler ();
+#ifdef CD32
+    AKIKO_hsync_handler ();
+#endif
+
+#ifdef PICASSO96
+    picasso_handle_hsync ();
+#endif
+    ciahsync++;
+    if (ciahsync >= (currprefs.ntscmode ? MAXVPOS_NTSC : MAXVPOS_PAL) * MAXHPOS_PAL / maxhpos) { /* not so perfect.. */
+        CIA_vsync_handler ();
+       ciahsync = 0;
+    }
+
+#ifdef CPUEMU_6
+    if (currprefs.cpu_cycle_exact || currprefs.blitter_cycle_exact) {
+        decide_blitter (hpos);
+       memset (cycle_line, 0, MAXHPOS);
+       cycle_line[maxhpos - 1] = CYCLE_REFRESH;
+       cycle_line[0] = CYCLE_REFRESH;
+       cycle_line[2] = CYCLE_REFRESH;
+       cycle_line[4] = CYCLE_REFRESH;
+    }
+#endif
+    if ((currprefs.chipset_mask & CSMASK_AGA) || (!currprefs.chipset_mask & CSMASK_ECS_AGNUS))
+       last_custom_value = rand ();
+    else
+       last_custom_value = 0xffff;
+
+    if (!currprefs.blitter_cycle_exact && bltstate != BLT_done && dmaen (DMA_BITPLANE) && diwstate == DIW_waiting_stop)
+       blitter_slowdown (ddfstrt, ddfstop, cycle_diagram_total_cycles[fmode][GET_RES (bplcon0)][GET_PLANES (bplcon0)],
+           cycle_diagram_free_cycles[fmode][GET_RES (bplcon0)][GET_PLANES (bplcon0)]);
+
+    if (currprefs.produce_sound)
+       audio_hsync (1);
+
+    hardware_line_completed (next_lineno);
+
+    /* In theory only an equality test is needed here - but if a program
+       goes haywire with the VPOSW register, it can cause us to miss this,
+       with vpos going into the thousands (and all the nasty consequences
+       this has).  */
+
+    if (++vpos >= (maxvpos + (lof == 0 ? 0 : 1))) {
+       vpos = 0;
+       vsync_handler ();
+    }
+
+    DISK_update (maxhpos);
+
+#ifdef JIT
+    if (compiled_code) {
+       if (currprefs.m68k_speed == -1) {
+           static int count=0;
+
+           count++;
+           if (trigger_frh(count)) {
+               frh_handler();
+           }
+           is_lastline = trigger_frh(count+1) && ! rpt_did_reset;
+       }
+       else
+           is_lastline=0;
+    } else {
+#endif
+       is_lastline = vpos + 1 == maxvpos + (lof == 0 ? 0 : 1) && currprefs.m68k_speed == -1 && ! rpt_did_reset;
+#ifdef JIT
+    }
+#endif
+
+    if ((bplcon0 & 4) && currprefs.gfx_linedbl)
+       notice_interlace_seen ();
+
+    if (framecnt == 0) {
+       int lineno = vpos;
+       nextline_how = nln_normal;
+       if (currprefs.gfx_linedbl) {
+           lineno *= 2;
+           nextline_how = currprefs.gfx_linedbl == 1 ? nln_doubled : nln_nblack;
+           if (bplcon0 & 4) {
+               if (!lof) {
+                   lineno++;
+                   nextline_how = nln_lower;
+               } else {
+                   nextline_how = nln_upper;
+               }
+           }
+       }
+       next_lineno = lineno;
+       reset_decisions ();
+    }
+#ifdef FILESYS    
+    if (uae_int_requested) {
+       set_uae_int_flag ();
+       INTREQ (0x8000 | 0x0008);
+    }
+#endif
+    /* See if there's a chance of a copper wait ending this line.  */
+    cop_state.hpos = 0;
+    compute_spcflag_copper ();
+    inputdevice_hsync ();
+    serial_hsynchandler ();
+#ifdef CUSTOM_SIMPLE
+    do_sprites (0);
+#endif
+    //copper_check (2);
+}
+
+static void init_regtypes (void)
+{
+    int i;
+    for (i = 0; i < 512; i += 2) {
+       regtypes[i] = REGTYPE_ALL;
+       if ((i >= 0x20 && i < 0x28) || i == 0x08 || i == 0x7E)
+           regtypes[i] = REGTYPE_DISK;
+       else if (i >= 0x68 && i < 0x70)
+           regtypes[i] = REGTYPE_NONE;
+       else if (i >= 0x40 && i < 0x78)
+           regtypes[i] = REGTYPE_BLITTER;
+       else if (i >= 0xA0 && i < 0xE0 && (i & 0xF) < 0xE)
+           regtypes[i] = REGTYPE_AUDIO;
+       else if (i >= 0xA0 && i < 0xE0)
+           regtypes[i] = REGTYPE_NONE;
+       else if (i >= 0xE0 && i < 0x100)
+           regtypes[i] = REGTYPE_PLANE;
+       else if (i >= 0x120 && i < 0x180)
+           regtypes[i] = REGTYPE_SPRITE;
+       else if (i >= 0x180 && i < 0x1C0)
+           regtypes[i] = REGTYPE_COLOR;
+       else switch (i) {
+       case 0x02:
+           /* DMACONR - setting this to REGTYPE_BLITTER will cause it to
+              conflict with DMACON (since that is REGTYPE_ALL), and the
+              blitter registers (for the BBUSY bit), but nothing else,
+              which is (I think) what we want.  */
+           regtypes[i] = REGTYPE_BLITTER;
+           break;
+       case 0x04: case 0x06: case 0x2A: case 0x2C:
+           regtypes[i] = REGTYPE_POS;
+           break;
+       case 0x0A: case 0x0C:
+       case 0x12: case 0x14: case 0x16:
+       case 0x36:
+           regtypes[i] = REGTYPE_JOYPORT;
+           break;
+       case 0x104:
+       case 0x102:
+           regtypes[i] = REGTYPE_PLANE;
+           break;
+       case 0x88: case 0x8A:
+       case 0x8E: case 0x90: case 0x92: case 0x94:
+       case 0x96:
+       case 0x100:
+           regtypes[i] |= REGTYPE_FORCE;
+           break;
+       }
+    }
+}
+
+void init_eventtab (void)
+{
+    int i;
+
+    nextevent = 0;
+    set_cycles (0);
+    for (i = 0; i < ev_max; i++) {
+       eventtab[i].active = 0;
+       eventtab[i].oldcycles = 0;
+    }
+
+    eventtab[ev_cia].handler = CIA_handler;
+    eventtab[ev_hsync].handler = hsync_handler;
+    eventtab[ev_hsync].evtime = get_cycles () + HSYNCTIME;
+    eventtab[ev_hsync].active = 1;
+
+    eventtab[ev_copper].handler = copper_handler;
+    eventtab[ev_copper].active = 0;
+    eventtab[ev_blitter].handler = blitter_handler;
+    eventtab[ev_blitter].active = 0;
+    eventtab[ev_disk].handler = DISK_handler;
+    eventtab[ev_disk].active = 0;
+    eventtab[ev_audio].handler = audio_evhandler;
+    eventtab[ev_audio].active = 0;
+    events_schedule ();
+}
+
+void customreset (void)
+{
+    int i;
+    int zero = 0;
+
+    write_log ("reset at %x\n", m68k_getpc());
+    if (! savestate_state) {
+       currprefs.chipset_mask = changed_prefs.chipset_mask;
+       if ((currprefs.chipset_mask & CSMASK_AGA) == 0) {
+           for (i = 0; i < 32; i++) {
+               current_colors.color_regs_ecs[i] = 0;
+               current_colors.acolors[i] = xcolors[0];
+           }
+#ifdef AGA
+       } else {
+            for (i = 0; i < 256; i++) {
+               current_colors.color_regs_aga[i] = 0;
+               current_colors.acolors[i] = CONVERT_RGB (zero);
+           }
+#endif
+       }
+
+       clxdat = 0;
+
+       /* Clear the armed flags of all sprites.  */
+       memset (spr, 0, sizeof spr);
+       nr_armed = 0;
+
+       dmacon = intena = 0;
+
+       copcon = 0;
+       DSKLEN (0, 0);
+
+       bplcon0 = 0;
+       bplcon4 = 0x11; /* Get AGA chipset into ECS compatibility mode */
+       bplcon3 = 0xC00;
+
+       FMODE (0);
+       CLXCON (0);
+    }
+
+#ifdef AUTOCONFIG
+    expamem_reset ();
+#endif
+    a1000_reset ();
+    DISK_reset ();
+    CIA_reset ();
+#ifdef JIT
+    compemu_reset ();
+#endif
+    unset_special (~(SPCFLAG_BRK | SPCFLAG_MODE_CHANGE));
+
+    vpos = 0;
+
+    if (needmousehack ()) {
+#if 0
+       mousehack_set (mousehack_follow);
+#else
+       mousehack_set (mousehack_dontcare);
+#endif
+    } else {
+       mousehack_set (mousehack_normal);
+    }
+    ievent_alive = 0;
+    timehack_alive = 0;
+
+    curr_sprite_entries = 0;
+    prev_sprite_entries = 0;
+    sprite_entries[0][0].first_pixel = 0;
+    sprite_entries[1][0].first_pixel = MAX_SPR_PIXELS;
+    sprite_entries[0][1].first_pixel = 0;
+    sprite_entries[1][1].first_pixel = MAX_SPR_PIXELS;
+    memset (spixels, 0, sizeof spixels);
+    memset (&spixstate, 0, sizeof spixstate);
+
+    bltstate = BLT_done;
+    cop_state.state = COP_stop;
+    diwstate = DIW_waiting_start;
+    hdiwstate = DIW_waiting_start;
+    set_cycles (0);
+
+    new_beamcon0 = currprefs.ntscmode ? 0x00 : 0x20;
+    hack_vpos = 0;
+    init_hz ();
+
+    audio_reset ();
+    if (savestate_state != STATE_RESTORE) {
+       /* must be called after audio_reset */
+       adkcon = 0;
+       serial_uartbreak (0);
+       update_adkmasks ();
+    }
+
+    init_sprites ();
+
+    init_hardware_frame ();
+    drawing_init ();
+
+    reset_decisions ();
+
+    bogusframe = 1;
+
+    init_regtypes ();
+
+    sprite_buffer_res = currprefs.chipset_mask & CSMASK_AGA ? RES_HIRES : RES_LORES;
+    if (savestate_state == STATE_RESTORE) {
+       uae_u16 v;
+       uae_u32 vv;
+
+       update_adkmasks ();
+       INTENA (0);
+       INTREQ (0);
+#if 0
+       DMACON (0, 0);
+#endif
+       COPJMP (1);
+       v = bplcon0;
+       BPLCON0 (0, 0);
+       BPLCON0 (0, v);
+       FMODE (fmode);
+       if (!(currprefs.chipset_mask & CSMASK_AGA)) {
+           for(i = 0 ; i < 32 ; i++)  {
+               vv = current_colors.color_regs_ecs[i];
+               current_colors.color_regs_ecs[i] = -1;
+               record_color_change (0, i, vv);
+               remembered_color_entry = -1;
+               current_colors.color_regs_ecs[i] = vv;
+               current_colors.acolors[i] = xcolors[vv];
+           }
+#ifdef AGA
+       } else {
+           for(i = 0 ; i < 256 ; i++)  {
+               vv = current_colors.color_regs_aga[i];
+               current_colors.color_regs_aga[i] = -1;
+               record_color_change (0, i, vv);
+               remembered_color_entry = -1;
+               current_colors.color_regs_aga[i] = vv;
+               current_colors.acolors[i] = CONVERT_RGB(vv);
+           }
+#endif
+       }
+       CLXCON (clxcon);
+       CLXCON2 (clxcon2);
+       calcdiw ();
+       write_log ("State restored\n");
+       dumpcustom ();
+       for (i = 0; i < 8; i++)
+           nr_armed += spr[i].armed != 0;
+    }
+    expand_sprres ();
+
+    #ifdef ACTION_REPLAY
+    /* Doing this here ensures we can use the 'reset' command from within AR */
+    action_replay_reset ();
+    #endif
+    #ifdef WIN32
+    #ifndef UAE_MINI
+    enforcer_disable();
+    #endif
+    #endif
+}
+
+void dumpcustom (void)
+{
+    write_log ("DMACON: %x INTENA: %x INTREQ: %x VPOS: %x HPOS: %x\n", DMACONR(),
+              (unsigned int)intena, (unsigned int)intreq, (unsigned int)vpos, (unsigned int)current_hpos());
+    write_log ("COP1LC: %08lx, COP2LC: %08lx COPPTR: %08lx\n", (unsigned long)cop1lc, (unsigned long)cop2lc, cop_state.ip);
+    write_log ("DIWSTRT: %04x DIWSTOP: %04x DDFSTRT: %04x DDFSTOP: %04x\n",
+              (unsigned int)diwstrt, (unsigned int)diwstop, (unsigned int)ddfstrt, (unsigned int)ddfstop);
+    write_log ("BPLCON 0: %04x 1: %04x 2: %04x 3: %04x 4: %04x\n", bplcon0, bplcon1, bplcon2, bplcon3, bplcon4);
+    if (timeframes) {
+       write_log ("Average frame time: %f ms [frames: %d time: %d]\n",
+                  (double)frametime / timeframes, timeframes, frametime);
+       if (total_skipped)
+           write_log ("Skipped frames: %d\n", total_skipped);
+    }
+    /*for (i=0; i<256; i++) if (blitcount[i]) write_log ("minterm %x = %d\n",i,blitcount[i]);  blitter debug */
+}
+
+static void gen_custom_tables (void)
+{
+    int i;
+    for (i = 0; i < 256; i++) {
+       sprtaba[i] = ((((i >> 7) & 1) << 0)
+                     | (((i >> 6) & 1) << 2)
+                     | (((i >> 5) & 1) << 4)
+                     | (((i >> 4) & 1) << 6)
+                     | (((i >> 3) & 1) << 8)
+                     | (((i >> 2) & 1) << 10)
+                     | (((i >> 1) & 1) << 12)
+                     | (((i >> 0) & 1) << 14));
+       sprtabb[i] = sprtaba[i] * 2;
+       sprite_ab_merge[i] = (((i & 15) ? 1 : 0)
+                             | ((i & 240) ? 2 : 0));
+    }
+    for (i = 0; i < 16; i++) {
+       clxmask[i] = (((i & 1) ? 0xF : 0x3)
+                     | ((i & 2) ? 0xF0 : 0x30)
+                     | ((i & 4) ? 0xF00 : 0x300)
+                     | ((i & 8) ? 0xF000 : 0x3000));
+       sprclx[i] = (((i & 0x3) == 0x3 ? 1 : 0)
+                    | ((i & 0x5) == 0x5 ? 2 : 0)
+                    | ((i & 0x9) == 0x9 ? 4 : 0)
+                    | ((i & 0x6) == 0x6 ? 8 : 0)
+                    | ((i & 0xA) == 0xA ? 16 : 0)
+                    | ((i & 0xC) == 0xC ? 32 : 0)) << 9;
+    }
+}
+
+void custom_init (void)
+{
+
+#ifdef OS_WITHOUT_MEMORY_MANAGEMENT
+    int num;
+
+    for (num = 0; num < 2; num++) {
+       sprite_entries[num] = xmalloc (max_sprite_entry * sizeof (struct sprite_entry));
+       color_changes[num] = xmalloc (max_color_change * sizeof (struct color_change));
+    }
+#endif
+
+#ifdef AUTOCONFIG
+    {
+       uaecptr pos;
+       pos = here ();
+
+       org (RTAREA_BASE+0xFF70);
+       calltrap (deftrap (mousehack_helper));
+       dw (RTS);
+
+       org (RTAREA_BASE+0xFFA0);
+       calltrap (deftrap (timehack_helper));
+       dw (RTS);
+
+       org (pos);
+    }
+#endif
+
+    gen_custom_tables ();
+    build_blitfilltable ();
+
+    drawing_init ();
+
+    mousehack_set (mousehack_unknown);
+    if (needmousehack ())
+       mousehack_set (mousehack_follow);
+
+    create_cycle_diagram_table ();
+}
+
+/* Custom chip memory bank */
+
+static uae_u32 custom_lget (uaecptr) REGPARAM;
+static uae_u32 custom_wget (uaecptr) REGPARAM;
+static uae_u32 custom_bget (uaecptr) REGPARAM;
+static void custom_lput (uaecptr, uae_u32) REGPARAM;
+static void custom_wput (uaecptr, uae_u32) REGPARAM;
+static void custom_bput (uaecptr, uae_u32) REGPARAM;
+
+addrbank custom_bank = {
+    custom_lget, custom_wget, custom_bget,
+    custom_lput, custom_wput, custom_bput,
+    default_xlate, default_check, NULL
+};
+
+STATIC_INLINE uae_u32 REGPARAM2 custom_wget_1 (uaecptr addr, int noput)
+{
+    uae_u16 v;
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+    addr &= 0xfff;
+#ifdef CUSTOM_DEBUG
+    write_log ("%d:%d:wget: %04.4X=%04.4X pc=%p\n", current_hpos(), vpos, addr, addr & 0x1fe, m68k_getpc());
+#endif
+    switch (addr & 0x1fe) {
+     case 0x002: v = DMACONR (); break;
+     case 0x004: v = VPOSR (); break;
+     case 0x006: v = VHPOSR (); break;
+
+     case 0x00A: v = JOY0DAT (); break;
+     case 0x00C: v = JOY1DAT (); break;
+     case 0x00E: v = CLXDAT (); break;
+     case 0x010: v = ADKCONR (); break;
+
+     case 0x012: v = POT0DAT (); break;
+     case 0x014: v = POT1DAT (); break;
+     case 0x016: v = POTGOR (); break;
+     case 0x018: v = SERDATR (); break;
+     case 0x01A: v = DSKBYTR (current_hpos ()); break;
+     case 0x01C: v = INTENAR (); break;
+     case 0x01E: v = INTREQR (); break;
+     case 0x07C: v = DENISEID (); break;
+
+     case 0x02E: v = 0xffff; break; /* temporary hack */
+
+#ifdef AGA
+     case 0x180: case 0x182: case 0x184: case 0x186: case 0x188: case 0x18A:
+     case 0x18C: case 0x18E: case 0x190: case 0x192: case 0x194: case 0x196:
+     case 0x198: case 0x19A: case 0x19C: case 0x19E: case 0x1A0: case 0x1A2:
+     case 0x1A4: case 0x1A6: case 0x1A8: case 0x1AA: case 0x1AC: case 0x1AE:
+     case 0x1B0: case 0x1B2: case 0x1B4: case 0x1B6: case 0x1B8: case 0x1BA:
+     case 0x1BC: case 0x1BE:
+       v = COLOR_READ ((addr & 0x3E) / 2);
+       break;
+#endif
+
+     default:
+       /* reading write-only register causes write with last value in bus */
+        v = last_custom_value;
+       if (!noput) {
+           int r;
+           int hpos = current_hpos ();
+            decide_line (hpos);
+           decide_fetch (hpos);
+           decide_blitter (hpos);
+            v = last_custom_value;
+           r = custom_wput_1 (hpos, addr, v, 1);
+       }
+       return v;
+    }
+    return v;
+}
+
+ STATIC_INLINE custom_wget2 (uaecptr addr)
+ {
+    uae_u32 v;
+    sync_copper_with_cpu (current_hpos (), 1, addr);
+    if (currprefs.cpu_level >= 2) {
+       if(addr > 0xde0000 && addr <= 0xdeffff)
+           return 0x7f7f;
+       if(addr > 0xdd0000 && addr <= 0xddffff)
+            return 0xffff;
+    }
+    v = custom_wget_1 (addr, 0);
+#ifdef ACTION_REPLAY
+#ifdef ACTION_REPLAY_COMMON
+    addr &= 0x1ff;
+    ar_custom[addr + 0] = (uae_u8)(v >> 8);
+    ar_custom[addr + 1] = (uae_u8)(v);
+#endif
+#endif
+    return v;
+}
+
+uae_u32 REGPARAM2 custom_wget (uaecptr addr)
+{
+    uae_u32 v;
+
+    if (addr & 1) {
+       /* think about move.w $dff005,d0.. (68020+ only) */
+       addr &= ~1;
+       v = custom_wget2 (addr) << 8;
+       v |= custom_wget2 (addr + 2) >> 8;
+       return v;
+    }
+    return custom_wget2 (addr);
+ }
+uae_u32 REGPARAM2 custom_bget (uaecptr addr)
+{
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+    return custom_wget2 (addr & ~1) >> (addr & 1 ? 0 : 8);
+}
+
+uae_u32 REGPARAM2 custom_lget (uaecptr addr)
+{
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+    return ((uae_u32)custom_wget (addr) << 16) | custom_wget (addr + 2);
+}
+
+int REGPARAM2 custom_wput_1 (int hpos, uaecptr addr, uae_u32 value, int noget)
+{
+    addr &= 0x1FE;
+    value &= 0xffff;
+#ifdef ACTION_REPLAY
+#ifdef ACTION_REPLAY_COMMON
+    ar_custom[addr+0]=(uae_u8)(value>>8);
+    ar_custom[addr+1]=(uae_u8)(value);
+#endif
+#endif
+    last_custom_value = value;
+    switch (addr) {
+     case 0x00E: CLXDAT (); break;
+
+     case 0x020: DSKPTH (value); break;
+     case 0x022: DSKPTL (value); break;
+     case 0x024: DSKLEN (value, hpos); break;
+     case 0x026: DSKDAT (value); break;
+
+     case 0x02A: VPOSW (value); break;
+     case 0x02E: COPCON (value); break;
+     case 0x030: SERDAT (value); break;
+     case 0x032: SERPER (value); break;
+     case 0x034: POTGO (value); break;
+     case 0x040: BLTCON0 (value); break;
+     case 0x042: BLTCON1 (value); break;
+
+     case 0x044: BLTAFWM (value); break;
+     case 0x046: BLTALWM (value); break;
+
+     case 0x050: BLTAPTH (value); break;
+     case 0x052: BLTAPTL (value); break;
+     case 0x04C: BLTBPTH (value); break;
+     case 0x04E: BLTBPTL (value); break;
+     case 0x048: BLTCPTH (value); break;
+     case 0x04A: BLTCPTL (value); break;
+     case 0x054: BLTDPTH (value); break;
+     case 0x056: BLTDPTL (value); break;
+
+     case 0x058: BLTSIZE (value); break;
+
+     case 0x064: BLTAMOD (value); break;
+     case 0x062: BLTBMOD (value); break;
+     case 0x060: BLTCMOD (value); break;
+     case 0x066: BLTDMOD (value); break;
+
+     case 0x070: BLTCDAT (value); break;
+     case 0x072: BLTBDAT (value); break;
+     case 0x074: BLTADAT (value); break;
+
+     case 0x07E: DSKSYNC (hpos, value); break;
+
+     case 0x080: COP1LCH (value); break;
+     case 0x082: COP1LCL (value); break;
+     case 0x084: COP2LCH (value); break;
+     case 0x086: COP2LCL (value); break;
+
+     case 0x088: COPJMP (1); break;
+     case 0x08A: COPJMP (2); break;
+
+     case 0x08E: DIWSTRT (hpos, value); break;
+     case 0x090: DIWSTOP (hpos, value); break;
+     case 0x092: DDFSTRT (hpos, value); break;
+     case 0x094: DDFSTOP (hpos, value); break;
+
+     case 0x096: DMACON (hpos, value); break;
+     case 0x098: CLXCON (value); break;
+     case 0x09A: INTENA (value); break;
+     case 0x09C: INTREQ (value); break;
+     case 0x09E: ADKCON (hpos, value); break;
+
+     case 0x0A0: AUDxLCH (0, value); break;
+     case 0x0A2: AUDxLCL (0, value); break;
+     case 0x0A4: AUDxLEN (0, value); break;
+     case 0x0A6: AUDxPER (0, value); break;
+     case 0x0A8: AUDxVOL (0, value); break;
+     case 0x0AA: AUDxDAT (0, value); break;
+
+     case 0x0B0: AUDxLCH (1, value); break;
+     case 0x0B2: AUDxLCL (1, value); break;
+     case 0x0B4: AUDxLEN (1, value); break;
+     case 0x0B6: AUDxPER (1, value); break;
+     case 0x0B8: AUDxVOL (1, value); break;
+     case 0x0BA: AUDxDAT (1, value); break;
+
+     case 0x0C0: AUDxLCH (2, value); break;
+     case 0x0C2: AUDxLCL (2, value); break;
+     case 0x0C4: AUDxLEN (2, value); break;
+     case 0x0C6: AUDxPER (2, value); break;
+     case 0x0C8: AUDxVOL (2, value); break;
+     case 0x0CA: AUDxDAT (2, value); break;
+
+     case 0x0D0: AUDxLCH (3, value); break;
+     case 0x0D2: AUDxLCL (3, value); break;
+     case 0x0D4: AUDxLEN (3, value); break;
+     case 0x0D6: AUDxPER (3, value); break;
+     case 0x0D8: AUDxVOL (3, value); break;
+     case 0x0DA: AUDxDAT (3, value); break;
+
+     case 0x0E0: BPLxPTH (hpos, value, 0); break;
+     case 0x0E2: BPLxPTL (hpos, value, 0); break;
+     case 0x0E4: BPLxPTH (hpos, value, 1); break;
+     case 0x0E6: BPLxPTL (hpos, value, 1); break;
+     case 0x0E8: BPLxPTH (hpos, value, 2); break;
+     case 0x0EA: BPLxPTL (hpos, value, 2); break;
+     case 0x0EC: BPLxPTH (hpos, value, 3); break;
+     case 0x0EE: BPLxPTL (hpos, value, 3); break;
+     case 0x0F0: BPLxPTH (hpos, value, 4); break;
+     case 0x0F2: BPLxPTL (hpos, value, 4); break;
+     case 0x0F4: BPLxPTH (hpos, value, 5); break;
+     case 0x0F6: BPLxPTL (hpos, value, 5); break;
+     case 0x0F8: BPLxPTH (hpos, value, 6); break;
+     case 0x0FA: BPLxPTL (hpos, value, 6); break;
+     case 0x0FC: BPLxPTH (hpos, value, 7); break;
+     case 0x0FE: BPLxPTL (hpos, value, 7); break;
+
+     case 0x100: BPLCON0 (hpos, value); break;
+     case 0x102: BPLCON1 (hpos, value); break;
+     case 0x104: BPLCON2 (hpos, value); break;
+#ifdef AGA
+     case 0x106: BPLCON3 (hpos, value); break;
+#endif
+
+     case 0x108: BPL1MOD (hpos, value); break;
+     case 0x10A: BPL2MOD (hpos, value); break;
+#ifdef AGA
+     case 0x10E: CLXCON2 (value); break;
+#endif
+
+     case 0x110: BPL1DAT (hpos, value); break;
+     case 0x112: BPL2DAT (value); break;
+     case 0x114: BPL3DAT (value); break;
+     case 0x116: BPL4DAT (value); break;
+     case 0x118: BPL5DAT (value); break;
+     case 0x11A: BPL6DAT (value); break;
+     case 0x11C: BPL7DAT (value); break;
+     case 0x11E: BPL8DAT (value); break;
+
+     case 0x180: case 0x182: case 0x184: case 0x186: case 0x188: case 0x18A:
+     case 0x18C: case 0x18E: case 0x190: case 0x192: case 0x194: case 0x196:
+     case 0x198: case 0x19A: case 0x19C: case 0x19E: case 0x1A0: case 0x1A2:
+     case 0x1A4: case 0x1A6: case 0x1A8: case 0x1AA: case 0x1AC: case 0x1AE:
+     case 0x1B0: case 0x1B2: case 0x1B4: case 0x1B6: case 0x1B8: case 0x1BA:
+     case 0x1BC: case 0x1BE:
+       COLOR_WRITE (hpos, value & 0xFFF, (addr & 0x3E) / 2);
+       break;
+     case 0x120: case 0x124: case 0x128: case 0x12C:
+     case 0x130: case 0x134: case 0x138: case 0x13C:
+       SPRxPTH (hpos, value, (addr - 0x120) / 4);
+       break;
+     case 0x122: case 0x126: case 0x12A: case 0x12E:
+     case 0x132: case 0x136: case 0x13A: case 0x13E:
+       SPRxPTL (hpos, value, (addr - 0x122) / 4);
+       break;
+     case 0x140: case 0x148: case 0x150: case 0x158:
+     case 0x160: case 0x168: case 0x170: case 0x178:
+       SPRxPOS (hpos, value, (addr - 0x140) / 8);
+       break;
+     case 0x142: case 0x14A: case 0x152: case 0x15A:
+     case 0x162: case 0x16A: case 0x172: case 0x17A:
+       SPRxCTL (hpos, value, (addr - 0x142) / 8);
+       break;
+     case 0x144: case 0x14C: case 0x154: case 0x15C:
+     case 0x164: case 0x16C: case 0x174: case 0x17C:
+       SPRxDATA (hpos, value, (addr - 0x144) / 8);
+       break;
+     case 0x146: case 0x14E: case 0x156: case 0x15E:
+     case 0x166: case 0x16E: case 0x176: case 0x17E:
+       SPRxDATB (hpos, value, (addr - 0x146) / 8);
+       break;
+
+     case 0x36: JOYTEST (value); break;
+     case 0x5A: BLTCON0L (value); break;
+     case 0x5C: BLTSIZV (value); break;
+     case 0x5E: BLTSIZH (value); break;
+     case 0x1E4: DIWHIGH (hpos, value); break;
+#ifdef AGA
+     case 0x10C: BPLCON4 (hpos, value); break;
+#endif
+
+     case 0x1DC: BEAMCON0 (value); break;
+     case 0x1C0: if (htotal != value) { htotal = value; varsync (); } break;
+     case 0x1C2: if (hsstop != value) { hsstop = value; varsync (); } break;
+     case 0x1C4: if (hbstrt != value) { hbstrt = value; varsync (); } break;
+     case 0x1C6: if (hbstop != value) { hbstop = value; varsync (); } break;
+     case 0x1C8: if (vtotal != value) { vtotal = value; varsync (); } break;
+     case 0x1CA: if (vsstop != value) { vsstop = value; varsync (); } break;
+     case 0x1CC: if (vbstrt != value) { vbstrt = value; varsync (); } break;
+     case 0x1CE: if (vbstop != value) { vbstop = value; varsync (); } break;
+     case 0x1DE: if (hsstrt != value) { hsstrt = value; varsync (); } break;
+     case 0x1E0: if (vsstrt != value) { vsstrt = value; varsync (); } break;
+     case 0x1E2: if (hcenter != value) { hcenter = value; varsync (); } break;
+
+#ifdef AGA
+     case 0x1FC: FMODE (value); break;
+#endif
+
+     /* writing to read-only register causes read access */
+     default:
+       if (!noget)
+           custom_wget_1 (addr, 1);
+        if (!(currprefs.chipset_mask & CSMASK_AGA) && (currprefs.chipset_mask & CSMASK_ECS_AGNUS))
+           last_custom_value = 0xffff;
+       return 1;
+    }
+    return 0;
+}
+
+void REGPARAM2 custom_wput (uaecptr addr, uae_u32 value)
+{
+    int hpos = current_hpos ();
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+#ifdef CUSTOM_DEBUG
+    write_log ("%d:%d:wput: %04.4X %04.4X pc=%p\n", hpos, vpos, addr & 0x01fe, value & 0xffff, m68k_getpc());
+#endif
+    sync_copper_with_cpu (hpos, 1, addr);
+    custom_wput_1 (hpos, addr, value, 0);
+}
+
+void REGPARAM2 custom_bput (uaecptr addr, uae_u32 value)
+{
+    static int warned;
+    /* Is this correct now? (There are people who bput things to the upper byte of AUDxVOL). */
+    uae_u16 rval = (value << 8) | (value & 0xFF);
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    custom_wput (addr & ~1, rval);
+    if (warned < 10) {
+       write_log ("Byte put to custom register %04.4X PC=%08.8X\n", addr, m68k_getpc());
+       warned++;
+    }
+}
+
+void REGPARAM2 custom_lput(uaecptr addr, uae_u32 value)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    custom_wput (addr & 0xfffe, value >> 16);
+    custom_wput ((addr + 2) & 0xfffe, (uae_u16)value);
+}
+
+void custom_prepare_savestate (void)
+{
+}
+
+#define RB restore_u8 ()
+#define RW restore_u16 ()
+#define RL restore_u32 ()
+
+uae_u8 *restore_custom (uae_u8 *src)
+{
+    uae_u16 dsklen, dskbytr;
+    int dskpt;
+    int i;
+
+    audio_reset ();
+
+    changed_prefs.chipset_mask = currprefs.chipset_mask = RL;
+    RW;                                /* 000 ? */
+    RW;                                /* 002 DMACONR */
+    RW;                                /* 004 VPOSR */
+    RW;                                /* 006 VHPOSR */
+    RW;                                /* 008 DSKDATR (dummy register) */
+    RW;                                /* 00A JOY0DAT */
+    RW;                                /* 00C JOY1DAT */
+    clxdat = RW;               /* 00E CLXDAT */
+    RW;                                /* 010 ADKCONR */
+    RW;                                /* 012 POT0DAT* */
+    RW;                                /* 014 POT1DAT* */
+    RW;                                /* 016 POTINP* */
+    RW;                                /* 018 SERDATR* */
+    dskbytr = RW;              /* 01A DSKBYTR */
+    RW;                                /* 01C INTENAR */
+    RW;                                /* 01E INTREQR */
+    dskpt = RL;                        /* 020-022 DSKPT */
+    dsklen = RW;               /* 024 DSKLEN */
+    RW;                                /* 026 DSKDAT */
+    RW;                                /* 028 REFPTR */
+    lof = RW;                  /* 02A VPOSW */
+    RW;                                /* 02C VHPOSW */
+    COPCON(RW);                        /* 02E COPCON */
+    RW;                                /* 030 SERDAT* */
+    RW;                                /* 032 SERPER* */
+    POTGO(RW);                 /* 034 POTGO */
+    RW;                                /* 036 JOYTEST* */
+    RW;                                /* 038 STREQU */
+    RW;                                /* 03A STRVHBL */
+    RW;                                /* 03C STRHOR */
+    RW;                                /* 03E STRLONG */
+    BLTCON0(RW);               /* 040 BLTCON0 */
+    BLTCON1(RW);               /* 042 BLTCON1 */
+    BLTAFWM(RW);               /* 044 BLTAFWM */
+    BLTALWM(RW);               /* 046 BLTALWM */
+    BLTCPTH(RL);               /* 048-04B BLTCPT */
+    BLTBPTH(RL);               /* 04C-04F BLTBPT */
+    BLTAPTH(RL);               /* 050-053 BLTAPT */
+    BLTDPTH(RL);               /* 054-057 BLTDPT */
+    RW;                                /* 058 BLTSIZE */
+    RW;                                /* 05A BLTCON0L */
+    blt_info.vblitsize = RW;   /* 05C BLTSIZV */
+    blt_info.hblitsize = RW;   /* 05E BLTSIZH */
+    BLTCMOD(RW);               /* 060 BLTCMOD */
+    BLTBMOD(RW);               /* 062 BLTBMOD */
+    BLTAMOD(RW);               /* 064 BLTAMOD */
+    BLTDMOD(RW);               /* 066 BLTDMOD */
+    RW;                                /* 068 ? */
+    RW;                                /* 06A ? */
+    RW;                                /* 06C ? */
+    RW;                                /* 06E ? */
+    BLTCDAT(RW);               /* 070 BLTCDAT */
+    BLTBDAT(RW);               /* 072 BLTBDAT */
+    BLTADAT(RW);               /* 074 BLTADAT */
+    RW;                                /* 076 ? */
+    RW;                                /* 078 ? */
+    RW;                                /* 07A ? */
+    RW;                                /* 07C LISAID */
+    DSKSYNC(-1, RW);           /* 07E DSKSYNC */
+    cop1lc = RL;               /* 080/082 COP1LC */
+    cop2lc = RL;               /* 084/086 COP2LC */
+    RW;                                /* 088 ? */
+    RW;                                /* 08A ? */
+    RW;                                /* 08C ? */
+    diwstrt = RW;              /* 08E DIWSTRT */
+    diwstop = RW;              /* 090 DIWSTOP */
+    ddfstrt = RW;              /* 092 DDFSTRT */
+    ddfstop = RW;              /* 094 DDFSTOP */
+    dmacon = RW & ~(0x2000|0x4000); /* 096 DMACON */
+    CLXCON(RW);                        /* 098 CLXCON */
+    intena = RW;               /* 09A INTENA */
+    intreq = RW;               /* 09C INTREQ */
+    adkcon = RW;               /* 09E ADKCON */
+    for (i = 0; i < 8; i++)
+       bplpt[i] = RL;
+    bplcon0 = RW;              /* 100 BPLCON0 */
+    bplcon1 = RW;              /* 102 BPLCON1 */
+    bplcon2 = RW;              /* 104 BPLCON2 */
+    bplcon3 = RW;              /* 106 BPLCON3 */
+    bpl1mod = RW;              /* 108 BPL1MOD */
+    bpl2mod = RW;              /* 10A BPL2MOD */
+    bplcon4 = RW;              /* 10C BPLCON4 */
+    clxcon2 = RW;              /* 10E CLXCON2* */
+    for(i = 0; i < 8; i++)
+       RW;                     /*     BPLXDAT */
+    for(i = 0; i < 32; i++)
+       current_colors.color_regs_ecs[i] = RW; /* 180 COLORxx */
+    htotal = RW;               /* 1C0 HTOTAL */
+    RW;                                /* 1C2 ? */
+    RW;                                /* 1C4 ? */
+    RW;                                /* 1C6 ? */
+    vtotal = RW;               /* 1C8 VTOTAL */
+    RW;                                /* 1CA ? */
+    RW;                                /* 1CC ? */
+    RW;                                /* 1CE ? */
+    RW;                                /* 1D0 ? */
+    RW;                                /* 1D2 ? */
+    RW;                                /* 1D4 ? */
+    RW;                                /* 1D6 ? */
+    RW;                                /* 1D8 ? */
+    RW;                                /* 1DA ? */
+    new_beamcon0 = RW;         /* 1DC BEAMCON0 */
+    RW;                                /* 1DE ? */
+    RW;                                /* 1E0 ? */
+    RW;                                /* 1E2 ? */
+    diwhigh = RW;              /* 1E4 ? */
+    if (diwhigh & 0x8000)
+       diwhigh_written = 1;
+    diwhigh &= 0x7fff;
+    RW;                                /* 1E6 ? */
+    RW;                                /* 1E8 ? */
+    RW;                                /* 1EA ? */
+    RW;                                /* 1EC ? */
+    RW;                                /* 1EE ? */
+    RW;                                /* 1F0 ? */
+    RW;                                /* 1F2 ? */
+    RW;                                /* 1F4 ? */
+    RW;                                /* 1F6 ? */
+    RW;                                /* 1F8 ? */
+    RW;                                /* 1FA ? */
+    fmode = RW;                        /* 1FC FMODE */
+    last_custom_value = RW;    /* 1FE ? */
+
+    DISK_restore_custom (dskpt, dsklen, dskbytr);
+
+    return src;
+}
+
+
+#define SB save_u8
+#define SW save_u16
+#define SL save_u32
+
+extern uae_u16 serper;
+
+uae_u8 *save_custom (int *len, uae_u8 *dstptr, int full)
+{
+    uae_u8 *dstbak, *dst;
+    int i;
+    uae_u32 dskpt;
+    uae_u16 dsklen, dsksync, dskbytr;
+
+    DISK_save_custom (&dskpt, &dsklen, &dsksync, &dskbytr);
+
+    if (dstptr)
+       dstbak = dst = dstptr;
+    else
+        dstbak = dst = malloc (8+256*2);
+
+    SL (currprefs.chipset_mask);
+    SW (0);                    /* 000 ? */
+    SW (dmacon);               /* 002 DMACONR */
+    SW (VPOSR());              /* 004 VPOSR */
+    SW (VHPOSR());             /* 006 VHPOSR */
+    SW (0);                    /* 008 DSKDATR */
+    SW (JOY0DAT());            /* 00A JOY0DAT */
+    SW (JOY1DAT());            /* 00C JOY1DAT */
+    SW (clxdat);               /* 00E CLXDAT */
+    SW (ADKCONR());            /* 010 ADKCONR */
+    SW (POT0DAT());            /* 012 POT0DAT */
+    SW (POT0DAT());            /* 014 POT1DAT */
+    SW (0)     ;               /* 016 POTINP * */
+    SW (0);                    /* 018 SERDATR * */
+    SW (dskbytr);              /* 01A DSKBYTR */
+    SW (INTENAR());            /* 01C INTENAR */
+    SW (INTREQR());            /* 01E INTREQR */
+    SL (dskpt);                        /* 020-023 DSKPT */
+    SW (dsklen);               /* 024 DSKLEN */
+    SW (0);                    /* 026 DSKDAT */
+    SW (0);                    /* 028 REFPTR */
+    SW (lof);                  /* 02A VPOSW */
+    SW (0);                    /* 02C VHPOSW */
+    SW (copcon);               /* 02E COPCON */
+    SW (serper);               /* 030 SERDAT * */
+    SW (serdat);               /* 032 SERPER * */
+    SW (potgo_value);          /* 034 POTGO */
+    SW (0);                    /* 036 JOYTEST * */
+    SW (0);                    /* 038 STREQU */
+    SW (0);                    /* 03A STRVBL */
+    SW (0);                    /* 03C STRHOR */
+    SW (0);                    /* 03E STRLONG */
+    SW (bltcon0);              /* 040 BLTCON0 */
+    SW (bltcon1);              /* 042 BLTCON1 */
+    SW (blt_info.bltafwm);     /* 044 BLTAFWM */
+    SW (blt_info.bltalwm);     /* 046 BLTALWM */
+    SL (bltcpt);               /* 048-04B BLTCPT */
+    SL (bltbpt);               /* 04C-04F BLTCPT */
+    SL (bltapt);               /* 050-053 BLTCPT */
+    SL (bltdpt);               /* 054-057 BLTCPT */
+    SW (0);                    /* 058 BLTSIZE */
+    SW (0);                    /* 05A BLTCON0L (use BLTCON0 instead) */
+    SW (blt_info.vblitsize);   /* 05C BLTSIZV */
+    SW (blt_info.hblitsize);   /* 05E BLTSIZH */
+    SW (blt_info.bltcmod);     /* 060 BLTCMOD */
+    SW (blt_info.bltbmod);     /* 062 BLTBMOD */
+    SW (blt_info.bltamod);     /* 064 BLTAMOD */
+    SW (blt_info.bltdmod);     /* 066 BLTDMOD */
+    SW (0);                    /* 068 ? */
+    SW (0);                    /* 06A ? */
+    SW (0);                    /* 06C ? */
+    SW (0);                    /* 06E ? */
+    SW (blt_info.bltcdat);     /* 070 BLTCDAT */
+    SW (blt_info.bltbdat);     /* 072 BLTBDAT */
+    SW (blt_info.bltadat);     /* 074 BLTADAT */
+    SW (0);                    /* 076 ? */
+    SW (0);                    /* 078 ? */
+    SW (0);                    /* 07A ? */
+    SW (DENISEID());           /* 07C DENISEID/LISAID */
+    SW (dsksync);              /* 07E DSKSYNC */
+    SL (cop1lc);               /* 080-083 COP1LC */
+    SL (cop2lc);               /* 084-087 COP2LC */
+    SW (0);                    /* 088 ? */
+    SW (0);                    /* 08A ? */
+    SW (0);                    /* 08C ? */
+    SW (diwstrt);              /* 08E DIWSTRT */
+    SW (diwstop);              /* 090 DIWSTOP */
+    SW (ddfstrt);              /* 092 DDFSTRT */
+    SW (ddfstop);              /* 094 DDFSTOP */
+    SW (dmacon);               /* 096 DMACON */
+    SW (clxcon);               /* 098 CLXCON */
+    SW (intena);               /* 09A INTENA */
+    SW (intreq);               /* 09C INTREQ */
+    SW (adkcon);               /* 09E ADKCON */
+    for (i = 0; full && i < 32; i++)
+       SW (0);
+    for (i = 0; i < 8; i++)
+       SL (bplpt[i]);          /* 0E0-0FE BPLxPT */
+    SW (bplcon0);              /* 100 BPLCON0 */
+    SW (bplcon1);              /* 102 BPLCON1 */
+    SW (bplcon2);              /* 104 BPLCON2 */
+    SW (bplcon3);              /* 106 BPLCON3 */
+    SW (bpl1mod);              /* 108 BPL1MOD */
+    SW (bpl2mod);              /* 10A BPL2MOD */
+    SW (bplcon4);              /* 10C BPLCON4 */
+    SW (clxcon2);              /* 10E CLXCON2 */
+    for (i = 0;i < 8; i++)
+       SW (0);                 /* 110 BPLxDAT */
+    if (full) {
+       for (i = 0; i < 8; i++) {
+           SL (spr[i].pt);         /* 120-13E SPRxPT */
+           SW (sprpos[i]);         /* 1x0 SPRxPOS */
+           SW (sprctl[i]);         /* 1x2 SPRxPOS */
+           SW (sprdata[i][0]);     /* 1x4 SPRxDATA */
+           SW (sprdatb[i][0]);     /* 1x6 SPRxDATB */
+       }
+    }
+    for ( i = 0; i < 32; i++)
+       SW (current_colors.color_regs_ecs[i]); /* 180-1BE COLORxx */
+    SW (htotal);               /* 1C0 HTOTAL */
+    SW (0);                    /* 1C2 */
+    SW (0);                    /* 1C4 */
+    SW (0);                    /* 1C6 */
+    SW (vtotal);               /* 1C8 VTOTAL */
+    SW (0);                    /* 1CA */
+    SW (0);                    /* 1CC */
+    SW (0);                    /* 1CE */
+    SW (0);                    /* 1D0 */
+    SW (0);                    /* 1D2 */
+    SW (0);                    /* 1D4 */
+    SW (0);                    /* 1D6 */
+    SW (0);                    /* 1D8 */
+    SW (0);                    /* 1DA */
+    SW (beamcon0);             /* 1DC BEAMCON0 */
+    SW (0);                    /* 1DE */
+    SW (0);                    /* 1E0 */
+    SW (0);                    /* 1E2 */
+    SW (diwhigh | (diwhigh_written ? 0x8000 : 0)); /* 1E4 */
+    SW (0);                    /* 1E6 */
+    SW (0);                    /* 1E8 */
+    SW (0);                    /* 1EA */
+    SW (0);                    /* 1EC */
+    SW (0);                    /* 1EE */
+    SW (0);                    /* 1F0 */
+    SW (0);                    /* 1F2 */
+    SW (0);                    /* 1F4 */
+    SW (0);                    /* 1F6 */
+    SW (0);                    /* 1F8 */
+    SW (0);                    /* 1FA */
+    SW (fmode);                        /* 1FC FMODE */
+    SW (last_custom_value);    /* 1FE */
+
+    *len = dst - dstbak;
+    return dstbak;
+}
+
+uae_u8 *restore_custom_agacolors (uae_u8 *src)
+{
+    int i;
+
+    for (i = 0; i < 256; i++)
+#ifdef AGA
+       current_colors.color_regs_aga[i] = RL;
+#else
+       RL;
+#endif
+    return src;
+}
+
+uae_u8 *save_custom_agacolors (int *len, uae_u8 *dstptr)
+{
+    uae_u8 *dstbak, *dst;
+    int i;
+
+    if (dstptr)
+       dstbak = dst = dstptr;
+    else
+        dstbak = dst = malloc (256*4);
+    for (i = 0; i < 256; i++)
+#ifdef AGA     
+    SL (current_colors.color_regs_aga[i]);
+#else
+    SL (0);
+#endif
+    *len = dst - dstbak;
+    return dstbak;
+}
+
+uae_u8 *restore_custom_sprite (int num, uae_u8 *src)
+{
+    spr[num].pt = RL;          /* 120-13E SPRxPT */
+    sprpos[num] = RW;          /* 1x0 SPRxPOS */
+    sprctl[num] = RW;          /* 1x2 SPRxPOS */
+    sprdata[num][0] = RW;      /* 1x4 SPRxDATA */
+    sprdatb[num][0] = RW;      /* 1x6 SPRxDATB */
+    sprdata[num][1] = RW;
+    sprdatb[num][1] = RW;
+    sprdata[num][2] = RW;
+    sprdatb[num][2] = RW;
+    sprdata[num][3] = RW;
+    sprdatb[num][3] = RW;
+    spr[num].armed = RB;
+    return src;
+}
+
+uae_u8 *save_custom_sprite(int num, int *len, uae_u8 *dstptr)
+{
+    uae_u8 *dstbak, *dst;
+
+    if (dstptr)
+       dstbak = dst = dstptr;
+    else
+        dstbak = dst = malloc (25);
+    SL (spr[num].pt);          /* 120-13E SPRxPT */
+    SW (sprpos[num]);          /* 1x0 SPRxPOS */
+    SW (sprctl[num]);          /* 1x2 SPRxPOS */
+    SW (sprdata[num][0]);      /* 1x4 SPRxDATA */
+    SW (sprdatb[num][0]);      /* 1x6 SPRxDATB */
+    SW (sprdata[num][1]);
+    SW (sprdatb[num][1]);
+    SW (sprdata[num][2]);
+    SW (sprdatb[num][2]);
+    SW (sprdata[num][3]);
+    SW (sprdatb[num][3]);
+    SB (spr[num].armed ? 1 : 0);
+    *len = dst - dstbak;
+    return dstbak;
+}
+
+void check_prefs_changed_custom (void)
+{
+    currprefs.gfx_framerate = changed_prefs.gfx_framerate;
+    if (inputdevice_config_change_test ()) {
+       inputdevice_copyconfig (&changed_prefs, &currprefs);
+       inputdevice_updateconfig (&currprefs);
+    }
+    currprefs.immediate_blits = changed_prefs.immediate_blits;
+    currprefs.collision_level = changed_prefs.collision_level;
+    currprefs.fast_copper = changed_prefs.fast_copper;
+
+    if (currprefs.chipset_mask != changed_prefs.chipset_mask ||
+       currprefs.gfx_vsync != changed_prefs.gfx_vsync ||
+       currprefs.ntscmode != changed_prefs.ntscmode) {
+       currprefs.gfx_vsync = changed_prefs.gfx_vsync;
+       currprefs.chipset_mask = changed_prefs.chipset_mask;
+       if (currprefs.ntscmode != changed_prefs.ntscmode) {
+           currprefs.ntscmode = changed_prefs.ntscmode;
+           new_beamcon0 = currprefs.ntscmode ? 0x00 : 0x20;
+       }
+       init_hz ();
+       calcdiw ();
+    }
+    currprefs.gfx_filter_horiz_zoom = changed_prefs.gfx_filter_horiz_zoom;
+    currprefs.gfx_filter_vert_zoom = changed_prefs.gfx_filter_vert_zoom;
+    currprefs.gfx_filter_horiz_offset = changed_prefs.gfx_filter_horiz_offset;
+    currprefs.gfx_filter_vert_offset = changed_prefs.gfx_filter_vert_offset;
+    currprefs.gfx_filter_scanlines = changed_prefs.gfx_filter_scanlines;
+    currprefs.gfx_filter_filtermode = changed_prefs.gfx_filter_filtermode;
+}
+
+#ifdef CPUEMU_6
+
+STATIC_INLINE void sync_copper (int hpos)
+{
+    if (eventtab[ev_copper].active) {
+       eventtab[ev_copper].active = 0;
+       update_copper (hpos);
+       return;
+    }
+    if (copper_enabled_thisline)
+       update_copper (hpos);
+}
+
+STATIC_INLINE int dma_cycle(void)
+{
+    int hpos, cycles = 0, bnasty = 0;
+
+    for (;;) {
+       int bpldma;
+       int blitpri = dmaen (DMA_BLITPRI);
+        do_cycles (1 * CYCLE_UNIT);
+       cycles += CYCLE_UNIT;
+        hpos = current_hpos ();
+       sync_copper (hpos);
+       decide_line (hpos);
+       bpldma = is_bitplane_dma (hpos);
+       if (cycle_line[hpos] == 0 && !bpldma) {
+           if (bltstate == BLT_done || bnasty >= 3)
+               break;
+           decide_blitter (hpos);
+           if (cycle_line[hpos] == 0)
+               break;
+           if (!blitpri || blit_singlechannel)
+               bnasty++;
+       } else if (bpldma && (blit_singlechannel || !blitpri)) {
+           bnasty++;
+       }
+       /* bus was allocated to dma channel, wait for next cycle.. */
+    }
+    cycle_line[hpos] |= CYCLE_CPU;
+    return cycles;
+}
+
+uae_u32 wait_cpu_cycle_read (uaecptr addr, int mode)
+{
+    uae_u32 v = 0;
+    dma_cycle ();
+    if (mode > 0)
+       v = get_word (addr);
+    else if (mode == 0)
+       v = get_byte (addr);
+    do_cycles (1 * CYCLE_UNIT);
+    return v;
+}
+
+uae_u32 wait_cpu_cycle_read_cycles (uaecptr addr, int mode, int *cycles)
+{
+    uae_u32 v = 0;
+    *cycles = dma_cycle () + CYCLE_UNIT;
+    if (mode > 0)
+       v = get_word (addr);
+    else if (mode == 0)
+       v = get_byte (addr);
+    do_cycles (1 * CYCLE_UNIT);
+    return v;
+}
+
+void wait_cpu_cycle_write (uaecptr addr, int mode, uae_u32 v)
+{
+    dma_cycle ();
+    if (mode > 0)
+       put_word (addr, v);
+    else if (mode == 0)
+       put_byte (addr, v);
+    do_cycles (1 * CYCLE_UNIT);
+}
+
+void do_cycles_ce (long cycles)
+{
+    int hpos, bpldma;
+    while (cycles > 0) {
+        do_cycles (1 * CYCLE_UNIT);
+       cycles -= CYCLE_UNIT;
+        hpos = current_hpos ();
+       sync_copper (hpos);
+       decide_line (hpos);
+       bpldma = is_bitplane_dma (hpos);
+       if (cycle_line[hpos] == 0 && !bpldma)
+           decide_blitter (hpos);
+    }
+}
+
+#endif
diff --git a/debug.c b/debug.c
new file mode 100755 (executable)
index 0000000..c2b442e
--- /dev/null
+++ b/debug.c
@@ -0,0 +1,1401 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Debugger
+  *
+  * (c) 1995 Bernd Schmidt
+  *
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <ctype.h>
+#include <signal.h>
+
+#include "config.h"
+#include "options.h"
+#include "threaddep/thread.h"
+#include "uae.h"
+#include "memory.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "cpu_prefetch.h"
+#include "debug.h"
+#include "cia.h"
+#include "xwin.h"
+#include "gui.h"
+#include "identify.h"
+#include "sound.h"
+#include "disk.h"
+#include "savestate.h"
+#include "autoconf.h"
+
+static int debugger_active;
+static uaecptr skipaddr_start, skipaddr_end, skipaddr_doskip;
+static uae_u32 skipins;
+static int do_skip;
+static int debug_rewind;
+static int memwatch_enabled, memwatch_triggered;
+int debugging;
+int exception_debugging;
+
+extern int audio_channel_mask;
+
+static FILE *logfile;
+
+void activate_debugger (void)
+{
+    if (logfile)
+       fclose (logfile);
+    logfile = 0;
+    do_skip = 0;
+    if (debugger_active)
+       return;
+    debugger_active = 1;
+    set_special (SPCFLAG_BRK);
+    debugging = 1;
+}
+
+int firsthist = 0;
+int lasthist = 0;
+#ifdef NEED_TO_DEBUG_BADLY
+struct regstruct history[MAX_HIST];
+union flagu historyf[MAX_HIST];
+#else
+uaecptr history[MAX_HIST];
+#endif
+
+static char help[] = {
+    "          HELP for UAE Debugger\n"
+    "         -----------------------\n\n"
+    "  g [<address>]         Start execution at the current address or <address>\n"
+    "  c                     Dump state of the CIA, disk drives and custom registers\n"
+    "  r                     Dump state of the CPU\n"
+    "  m <address> [<lines>] Memory dump starting at <address>\n"
+    "  d <address> [<lines>] Disassembly starting at <address>\n"
+    "  t [instructions]      Step one or more instructions\n"
+    "  z                     Step through one instruction - useful for JSR, DBRA etc\n"
+    "  f                     Step forward until PC in RAM\n"
+    "  f <address>           Add/remove breakpoint\n"
+    "  fi                    Step forward until PC points to RTS/RTD or RTE\n"
+    "  fi <opcode>           Step forward until PC points to <opcode>\n"
+    "  fl                    List breakpoints\n"
+    "  fd                    Remove all breakpoints\n"
+    "  f <addr1> <addr2>     Step forward until <addr1> <= PC <= <addr2>\n"
+    "  e                     Dump contents of all custom registers\n"
+    "  i                     Dump contents of interrupt and trap vectors\n"
+    "  o <1|2|addr> [<lines>]View memory as Copper instructions\n"
+    "  O                     Display bitplane offsets\n"
+    "  O <plane> <offset>    Offset a bitplane\n"
+    "  H <count>             Show PC history <count> instructions\n"
+    "  M                     Search for *Tracker sound modules\n"
+    "  C <value>             Search for values like energy or lifes in games\n"
+    "  W <address> <value>   Write into Amiga memory\n"
+    "  w <num> <address> <length> <R/W/RW> [<value>]\n"
+    "                        Add/remove memory watchpoints\n"
+    "  S <file> <addr> <n>   Save a block of Amiga memory\n"
+    "  s <string>/<values> [<addr>] [<length>]\n"
+    "                        search for string/bytes\n"
+    "  T                     Show exec tasks and their PCs\n"
+    "  h,?                   Show this help page\n"
+    "  b                     Step to previous state capture position\n"
+    "  am <channel mask>     Enable or disable audio channels\n"                  
+    "  q                     Quit the emulator. You don't want to use this command.\n\n"
+};
+
+static void debug_help (void)
+{
+    console_out (help);
+}
+
+
+
+static void ignore_ws (char **c)
+{
+    while (**c && isspace(**c)) (*c)++;
+}
+
+static uae_u32 readint (char **c);
+static uae_u32 readhex (char **c)
+{
+    uae_u32 val = 0;
+    char nc;
+
+    ignore_ws (c);
+    if (**c == '!' || **c == '_') {
+       (*c)++;
+       return readint (c);
+    }
+    while (isxdigit(nc = **c)) {
+       (*c)++;
+       val *= 16;
+       nc = toupper(nc);
+       if (isdigit(nc)) {
+           val += nc - '0';
+       } else {
+           val += nc - 'A' + 10;
+       }
+    }
+    return val;
+}
+
+static uae_u32 readint (char **c)
+{
+    uae_u32 val = 0;
+    char nc;
+    int negative = 0;
+
+    ignore_ws (c);
+    if (**c == '$') {
+       (*c)++;
+       return readhex (c);
+    }
+    if (**c == '0' && toupper((*c)[1]) == 'X') {
+       (*c)+= 2;       
+       return readhex (c);
+    }
+    if (**c == '-')
+       negative = 1, (*c)++;
+    while (isdigit(nc = **c)) {
+       (*c)++;
+       val *= 10;
+       val += nc - '0';
+    }
+    return val * (negative ? -1 : 1);
+}
+
+static char next_char( char **c)
+{
+    ignore_ws (c);
+    return *(*c)++;
+}
+
+static int more_params (char **c)
+{
+    ignore_ws (c);
+    return (**c) != 0;
+}
+
+static uae_u32 nextaddr (uae_u32 addr)
+{
+    if (addr == 0xffffffff) {
+       if (currprefs.bogomem_size)
+           return 0xc00000 + currprefs.bogomem_size;
+       if (currprefs.fastmem_size)
+           return 0x200000 + currprefs.fastmem_size;
+       return currprefs.chipmem_size;
+    }
+    if (addr == currprefs.chipmem_size) {
+       if (currprefs.fastmem_size)
+           return 0x200000;
+       else if (currprefs.bogomem_size)
+           return 0xc00000;
+       return 0xffffffff;
+    }
+    if (addr == 0x200000 + currprefs.fastmem_size) {
+       if (currprefs.bogomem_size)
+           return 0xc00000;
+       return 0xffffffff;
+    }
+    if (addr == 0xc00000 + currprefs.bogomem_size)
+       return 0xffffffff;
+    return addr + 1;
+}
+
+static void dumpmem (uaecptr addr, uaecptr *nxmem, int lines)
+{
+    char line[80];
+    int cols = 8;
+    broken_in = 0;
+    for (;lines-- && !broken_in;) {
+       int i;
+       sprintf (line, "%08lx ", addr);
+       for (i = 0; i < cols; i++) {
+           uae_u8 b1 = get_byte (addr + 0);
+           uae_u8 b2 = get_byte (addr + 1);
+           addr += 2;
+           sprintf (line + 9 + i * 5, "%02x%02x ", b1, b2);
+           line[9 + cols * 5 + 1 + i * 2 + 0] = b1 >= 32 && b1 < 127 ? b1 : '.';
+           line[9 + cols * 5 + 1 + i * 2 + 1] = b2 >= 32 && b2 < 127 ? b2 : '.';
+       }
+       line[9 + cols * 5] = ' ';
+       line[9 + cols * 5 + 1 + 2 * cols] = 0;
+       console_out (line);
+       console_out ("\n");
+    }
+    *nxmem = addr;
+}
+
+static void foundmod (uae_u32 ptr, char *type)
+{
+    char name[21];
+    uae_u8 *ptr2 = chipmemory + ptr;
+    int i,length;
+
+    console_out ("Found possible %s module at 0x%lx.\n", type, ptr);
+    memcpy (name, ptr2, 20);
+    name[20] = '\0';
+
+    /* Browse playlist */
+    length = 0;
+    for (i = 0x3b8; i < 0x438; i++)
+       if (ptr2[i] > length)
+           length = ptr2[i];
+
+    length = (length+1)*1024 + 0x43c;
+
+    /* Add sample lengths */
+    ptr2 += 0x2A;
+    for (i = 0; i < 31; i++, ptr2 += 30)
+       length += 2*((ptr2[0]<<8)+ptr2[1]);
+    
+    console_out ("Name \"%s\", Length 0x%lx bytes.\n", name, length);
+}
+
+static void modulesearch (void)
+{
+    uae_u8 *p = get_real_address (0);
+    uae_u32 ptr;
+
+    for (ptr = 0; ptr < allocated_chipmem - 40; ptr += 2, p += 2) {
+       /* Check for Mahoney & Kaktus */
+       /* Anyone got the format of old 15 Sample (SoundTracker)modules? */
+       if (ptr >= 0x438 && p[0] == 'M' && p[1] == '.' && p[2] == 'K' && p[3] == '.')
+           foundmod (ptr - 0x438, "ProTracker (31 samples)");
+
+       if (ptr >= 0x438 && p[0] == 'F' && p[1] == 'L' && p[2] == 'T' && p[3] == '4')
+           foundmod (ptr - 0x438, "Startrekker");
+
+       if (strncmp ((char *)p, "SMOD", 4) == 0) {
+           console_out ("Found possible FutureComposer 1.3 module at 0x%lx, length unknown.\n", ptr);
+       }
+       if (strncmp ((char *)p, "FC14", 4) == 0) {
+           console_out ("Found possible FutureComposer 1.4 module at 0x%lx, length unknown.\n", ptr);
+       }
+       if (p[0] == 0x48 && p[1] == 0xe7 && p[4] == 0x61 && p[5] == 0
+           && p[8] == 0x4c && p[9] == 0xdf && p[12] == 0x4e && p[13] == 0x75
+           && p[14] == 0x48 && p[15] == 0xe7 && p[18] == 0x61 && p[19] == 0
+           && p[22] == 0x4c && p[23] == 0xdf && p[26] == 0x4e && p[27] == 0x75) {
+           console_out ("Found possible Whittaker module at 0x%lx, length unknown.\n", ptr);
+       }
+       if (p[4] == 0x41 && p[5] == 0xFA) {
+           int i;
+
+           for (i = 0; i < 0x240; i += 2)
+               if (p[i] == 0xE7 && p[i + 1] == 0x42 && p[i + 2] == 0x41 && p[i + 3] == 0xFA)
+                   break;
+           if (i < 0x240) {
+               uae_u8 *p2 = p + i + 4;
+               for (i = 0; i < 0x30; i += 2)
+                   if (p2[i] == 0xD1 && p2[i + 1] == 0xFA) {
+                       console_out ("Found possible MarkII module at %lx, length unknown.\n", ptr);
+                   }
+           }
+       }
+    }
+}
+
+static void dump_custom_regs (void)
+{
+    int len, i, j, end;
+    uae_u8 *p1, *p2, *p3, *p4;
+
+    p1 = p2 = save_custom (&len, 0, 1);
+    p1 += 4; // skip chipset type
+    for (i = 0; i < 4; i++) {
+       p4 = p1 + 0xa0 + i * 16;
+       p3 = save_audio (i, &len, 0);
+       p4[0] = p3[12];
+       p4[1] = p3[13];
+       p4[2] = p3[14];
+       p4[3] = p3[15];
+       p4[4] = p3[4];
+       p4[5] = p3[5];
+       p4[6] = p3[8];
+       p4[7] = p3[9];
+       p4[8] = 0;
+       p4[9] = p3[1];
+       p4[10] = p3[10];
+       p4[11] = p3[11];
+       free (p3);
+    }
+    end = 0;
+    while (custd[end].name)
+       end++;
+    end++;
+    end /= 2;
+    for (i = 0; i < end; i++) {
+       uae_u16 v1, v2;
+       int addr1, addr2;
+       j = end + i;
+       addr1 = custd[i].adr & 0x1ff;
+       addr2 = custd[j].adr & 0x1ff;
+       v1 = (p1[addr1 + 0] << 8) | p1[addr1 + 1];
+       v2 = (p1[addr2 + 0] << 8) | p1[addr2 + 1];
+       console_out ("%03.3X %s\t%04.4X\t%03.3X %s\t%04.4X\n",
+           addr1, custd[i].name, v1,
+           addr2, custd[j].name, v2);
+    }
+    free (p2);
+}
+
+static void dump_vectors (void)
+{
+    int i = 0, j = 0;
+
+    while (int_labels[i].name || trap_labels[j].name) {
+       if (int_labels[i].name) {
+           console_out ("$%08X: %s  \t $%08X\t", int_labels[i].adr + regs.vbr,
+               int_labels[i].name, get_long (int_labels[i].adr + (int_labels[i].adr == 4 ? 0 : regs.vbr)));
+           i++;
+       } else {
+           console_out ("\t\t\t\t");
+       }
+       if (trap_labels[j].name) {
+           console_out("$%08X: %s  \t $%08X", trap_labels[j].adr + regs.vbr,
+              trap_labels[j].name, get_long (trap_labels[j].adr + regs.vbr));
+           j++;
+       }
+       console_out ("\n");
+    }
+}
+
+static void disassemble_wait (FILE *file, unsigned long insn)
+{
+    int vp, hp, ve, he, bfd, v_mask, h_mask;
+
+    vp = (insn & 0xff000000) >> 24;
+    hp = (insn & 0x00fe0000) >> 16;
+    ve = (insn & 0x00007f00) >> 8;
+    he = (insn & 0x000000fe);
+    bfd = (insn & 0x00008000) >> 15;
+
+    /* bit15 can never be masked out*/
+    v_mask = vp & (ve | 0x80);
+    h_mask = hp & he;
+    if (v_mask > 0) {
+       console_out ("vpos ");
+       if (ve != 0x7f) {
+           console_out ("& 0x%02x ", ve);
+       }
+       console_out (">= 0x%02x", v_mask);
+    }
+    if (he > 0) {
+       if (v_mask > 0) {
+           console_out (" and");
+       }
+       console_out (" hpos ");
+       if (he != 0xfe) {
+           console_out ("& 0x%02x ", he);
+       }
+       console_out (">= 0x%02x", h_mask);
+    } else {
+       console_out (", ignore horizontal");
+    }
+
+    console_out (".\n                        \t; VP %02x, VE %02x; HP %02x, HE %02x; BFD %d\n",
+            vp, ve, hp, he, bfd);
+}
+
+/* simple decode copper by Mark Cox */
+static void decode_copper_insn (FILE* file, unsigned long insn, unsigned long addr)
+{
+    uae_u32 insn_type = insn & 0x00010001;
+    int hpos, vpos;
+    char record[] = "          ";
+    if (find_copper_record (addr, &hpos, &vpos)) {
+       sprintf (record, " [%03x %03x]", vpos, hpos);
+    }
+
+    console_out ("%08lx: %04lx %04lx%s\t; ", addr, insn >> 16, insn & 0xFFFF, record);
+
+    switch (insn_type) {
+    case 0x00010000: /* WAIT insn */
+       console_out ("Wait for ");
+       disassemble_wait (file, insn);
+
+       if (insn == 0xfffffffe)
+           console_out ("                           \t; End of Copperlist\n");
+
+       break;
+
+    case 0x00010001: /* SKIP insn */
+       console_out ("Skip if ");
+       disassemble_wait (file, insn);
+       break;
+
+    case 0x00000000:
+    case 0x00000001: /* MOVE insn */
+       {
+           int addr = (insn >> 16) & 0x1fe;
+           int i = 0;
+           while (custd[i].name) {
+               if (custd[i].adr == addr + 0xdff000)
+                   break;
+               i++;
+           }
+           if (custd[i].name)
+               console_out ("%s := 0x%04lx\n", custd[i].name, insn & 0xffff);
+           else
+               console_out ("%04x := 0x%04lx\n", addr, insn & 0xffff);
+       }
+       break;
+
+    default:
+       abort ();
+    }
+
+}
+
+
+static uaecptr decode_copperlist (FILE* file, uaecptr address, int nolines)
+{
+    uae_u32 insn;
+    while (nolines-- > 0) {
+       insn = get_long (address);
+       decode_copper_insn (file, insn, address);
+       address += 4;
+    }
+    return address;
+    /* You may wonder why I don't stop this at the end of the copperlist?
+     * Well, often nice things are hidden at the end and it is debatable the actual 
+     * values that mean the end of the copperlist */
+}
+
+
+/* cheat-search by Holger Jakob */
+static void cheatsearch (char **c)
+{
+    uae_u8 *p = get_real_address (0);
+    static uae_u32 *vlist = NULL;
+    uae_u32 ptr;
+    uae_u32 val = 0;
+    uae_u32 type = 0; /* not yet */
+    uae_u32 count = 0;
+    uae_u32 fcount = 0;
+    uae_u32 full = 0;
+
+    ignore_ws (c);
+    val = readhex (c);
+    if (vlist == NULL) {
+       vlist = malloc (256*4);
+       if (vlist != 0) {
+           for (count = 0; count<255; count++)
+               vlist[count] = 0;
+           count = 0;
+           for (ptr = 0; ptr < allocated_chipmem - 40; ptr += 2, p += 2) {
+               if (ptr >= 0x438 && p[3] == (val & 0xff)
+                   && p[2] == (val >> 8 & 0xff)
+                   && p[1] == (val >> 16 & 0xff)
+                   && p[0] == (val >> 24 & 0xff))
+               {
+                   if (count < 255) {
+                       vlist[count++]=ptr;
+                       console_out ("%08x: %x%x%x%x\n",ptr,p[0],p[1],p[2],p[3]);
+                   } else
+                       full = 1;
+               }
+           }
+           console_out ("Found %d possible addresses with %d\n",count,val);
+           console_out ("Now continue with 'g' and use 'C' with a different value\n");
+       }
+    } else {
+       for (count = 0; count<255; count++) {
+           if (p[vlist[count]+3] == (val & 0xff)
+               && p[vlist[count]+2] == (val>>8 & 0xff) 
+               && p[vlist[count]+1] == (val>>16 & 0xff)
+               && p[vlist[count]] == (val>>24 & 0xff))
+           {
+               fcount++;
+               console_out ("%08x: %x%x%x%x\n", vlist[count], p[vlist[count]],
+                       p[vlist[count]+1], p[vlist[count]+2], p[vlist[count]+3]);
+           }
+       }
+       console_out ("%d hits of %d found\n",fcount,val);
+       free (vlist);
+       vlist = NULL;
+    }
+}
+
+#define BREAKPOINT_TOTAL 8
+struct breakpoint_node {
+    uaecptr addr;
+    int enabled;
+};
+static struct breakpoint_node bpnodes[BREAKPOINT_TOTAL];
+
+static addrbank **debug_mem_banks;
+#define MEMWATCH_TOTAL 4
+struct memwatch_node {
+    uaecptr addr;
+    int size;
+    int rw;
+    uae_u32 val;
+    int val_enabled;
+    uae_u32 modval;
+    int modval_written;
+};
+static struct memwatch_node mwnodes[MEMWATCH_TOTAL];
+static struct memwatch_node mwhit;
+
+static int debug_mem_off (uaecptr addr)
+{
+    return (munge24 (addr) >> 16) & 0xff;
+}
+
+static void memwatch_func (uaecptr addr, int rw, int size, uae_u32 val)
+{
+    int i, brk;
+
+    addr = munge24 (addr);
+    for (i = 0; i < MEMWATCH_TOTAL; i++) {
+       uaecptr addr2 = mwnodes[i].addr;
+       uaecptr addr3 = addr2 + mwnodes[i].size;
+       int rw2 = mwnodes[i].rw;
+
+       brk = 0;
+       if (mwnodes[i].size == 0)
+           continue;
+       if (mwnodes[i].val_enabled && mwnodes[i].val != val)
+           continue;
+       if (rw != rw2 && rw2 < 2)
+           continue;
+       if (addr >= addr2 && addr < addr3)
+           brk = 1;
+       if (!brk && size == 2 && (addr + 1 >= addr2 && addr + 1 < addr3))
+           brk = 1;
+       if (!brk && size == 4 && ((addr + 2 >= addr2 && addr + 2 < addr3) || (addr + 3 >= addr2 && addr + 3 < addr3)))
+           brk = 1;
+       if (brk && mwnodes[i].modval_written) {
+           if (!rw) {
+               brk = 0;
+           } else if (mwnodes[i].modval_written == 1) {
+               mwnodes[i].modval_written = 2;
+               mwnodes[i].modval = val;
+               brk = 0;
+           } else if (mwnodes[i].modval == val) {
+               brk = 0;
+           }
+       }
+       if (brk) {
+           mwhit.addr = addr;
+           mwhit.rw = rw;
+           mwhit.size = size;
+           mwhit.val = 0;
+           if (mwhit.rw)
+               mwhit.val = val;
+           memwatch_triggered = i + 1;
+           debugging = 1;
+           set_special (SPCFLAG_BRK);
+           break;
+       }
+    }
+}
+
+static uae_u32 debug_lget (uaecptr addr)
+{
+    int off = debug_mem_off (addr);
+    uae_u32 v;
+    v = debug_mem_banks[off]->lget(addr);
+    memwatch_func (addr, 0, 4, v);
+    return v;
+}
+static uae_u32 debug_wget (uaecptr addr)
+{
+    int off = debug_mem_off (addr);
+    uae_u32 v;
+    v = debug_mem_banks[off]->wget(addr);
+    memwatch_func (addr, 0, 2, v);
+    return v;
+}
+static uae_u32 debug_bget (uaecptr addr)
+{
+    int off = debug_mem_off (addr);
+    uae_u32 v;
+    v = debug_mem_banks[off]->bget(addr);
+    memwatch_func (addr, 0, 1, v);
+    return v;
+}
+static void debug_lput (uaecptr addr, uae_u32 v)
+{
+    int off = debug_mem_off (addr);
+    memwatch_func (addr, 1, 4, v);
+    debug_mem_banks[off]->lput(addr, v);
+}   
+static void debug_wput (uaecptr addr, uae_u32 v)
+{
+    int off = debug_mem_off (addr);
+    memwatch_func (addr, 1, 2, v);
+    debug_mem_banks[off]->wput(addr, v);
+}   
+static void debug_bput (uaecptr addr, uae_u32 v)
+{
+    int off = debug_mem_off (addr);
+    memwatch_func (addr, 1, 1, v);
+    debug_mem_banks[off]->bput(addr, v);
+}   
+static int debug_check (uaecptr addr, uae_u32 size)
+{
+    return debug_mem_banks[munge24 (addr) >> 16]->check (addr, size);
+}
+static uae_u8 *debug_xlate (uaecptr addr)
+{
+    return debug_mem_banks[munge24 (addr) >> 16]->xlateaddr (addr);
+}
+
+static void deinitialize_memwatch (void)
+{
+    int i;
+    addrbank *a1, *a2;
+
+    if (!memwatch_enabled)
+       return;
+    for (i = 0; i < 256; i++) {
+       a1 = debug_mem_banks[i];
+       a2 = mem_banks[i];
+       memcpy (a2, a1, sizeof (addrbank));
+       free (a1);
+    }
+    free (debug_mem_banks);
+    debug_mem_banks = 0;
+    memwatch_enabled = 0;
+}
+
+static int initialize_memwatch (void)
+{
+    int i;
+    addrbank *a1, *a2;
+
+    if (!currprefs.address_space_24)
+       return 0;
+    debug_mem_banks = xmalloc (sizeof (addrbank*) * 256);
+    for (i = 0; i < 256; i++) {
+       a1 = debug_mem_banks[i] = xmalloc (sizeof (addrbank));
+       a2 = mem_banks[i];
+       memcpy (a1, a2, sizeof (addrbank));
+    }
+    for (i = 0; i < 256; i++) {
+       a2 = mem_banks[i];
+       a2->bget = debug_bget;
+       a2->wget = debug_wget;
+       a2->lget = debug_lget;
+       a2->bput = debug_bput;
+       a2->wput = debug_wput;
+       a2->lput = debug_lput;
+       a2->check = debug_check;
+       a2->xlateaddr = debug_xlate;
+    }
+    memwatch_enabled = 1;
+    return 1;
+}
+
+static void memwatch_dump (int num)
+{
+    int i;
+    struct memwatch_node *mwn;
+    for (i = 0; i < MEMWATCH_TOTAL; i++) {
+       if ((num >= 0 && num == i) || (num < 0)) {
+           mwn = &mwnodes[i];
+           if (mwn->size == 0)
+               continue;
+           console_out ("%d: %08.8X - %08.8X (%d) %s",
+               i, mwn->addr, mwn->addr + (mwn->size - 1), mwn->size,
+               mwn->rw == 0 ? "R" : (mwn->rw == 1 ? "W" : "RW"));
+           if (mwn->val_enabled)
+               console_out (" =%X", mwn->val);
+           if (mwn->modval_written)
+               console_out (" =M");
+           console_out("\n");
+       }
+    }
+}
+
+static void memwatch (char **c)
+{
+    int num;
+    struct memwatch_node *mwn;
+    char nc;
+
+    if (!memwatch_enabled) {
+       if (!initialize_memwatch ()) {
+           console_out ("Memwatch breakpoints require 24-bit address space\n");
+           return;
+       }
+       console_out ("Memwatch breakpoints enabled\n");
+    }
+
+    ignore_ws (c);
+    if (!more_params (c)) {
+       memwatch_dump (-1);
+       return;
+    }
+    nc = next_char (c);
+    if (nc == '-') {
+       deinitialize_memwatch ();
+       console_out ("Memwatch breakpoints disabled\n");
+       return;
+    }
+    num = nc - '0';
+    if (num < 0 || num >= MEMWATCH_TOTAL)
+       return;
+    mwn = &mwnodes[num];
+    mwn->size = 0;
+    ignore_ws (c);
+    if (!more_params (c)) {
+       console_out ("Memwatch %d removed\n", num);
+       return;
+    }
+    mwn->addr = readhex (c);
+    mwn->size = 1;
+    mwn->rw = 2;
+    mwn->val_enabled = 0;
+    mwn->modval_written = 0;
+    ignore_ws (c);
+    if (more_params (c)) {
+       mwn->size = readhex (c);
+       ignore_ws (c);
+       if (more_params (c)) {
+           char nc = toupper (next_char (c));
+           if (nc == 'W')
+               mwn->rw = 1;
+           else if (nc == 'R' && toupper(**c) != 'W')
+               mwn->rw = 0;
+           ignore_ws (c);
+           if (more_params (c)) {
+               if (toupper(**c) == 'M') {
+                   mwn->modval_written = 1;
+               } else {
+                   mwn->val = readhex (c);
+                   mwn->val_enabled = 1;
+               }
+           }
+       }
+    }
+    memwatch_dump (num);
+}
+
+static void writeintomem (char **c)
+{
+    uae_u32 addr = 0;
+    uae_u32 val = 0;
+    char cc;
+
+    ignore_ws(c);
+    addr = readhex (c);
+    ignore_ws(c);
+    val = readhex (c);
+    if (val > 0xffff) {
+       put_long (addr, val);
+       cc = 'L';
+    } else if (val > 0xff) {
+       put_word (addr, val);
+       cc = 'W';
+    } else {
+       put_byte (addr, val);
+       cc = 'B';
+    }
+    console_out ("Wrote %x (%u) at %08x.%c\n", val, val, addr, cc);
+}
+
+static void show_exec_tasks (void)
+{
+    uaecptr execbase = get_long (4);
+    uaecptr taskready = get_long (execbase + 406);
+    uaecptr taskwait = get_long (execbase + 420);
+    uaecptr node, end;
+    console_out ("execbase at 0x%08lx\n", (unsigned long) execbase);
+    console_out ("Current:\n");
+    node = get_long (execbase + 276);
+    console_out ("%08lx: %08lx %s\n", node, 0, get_real_address (get_long (node + 10)));
+    console_out ("Ready:\n");
+    node = get_long (taskready);
+    end = get_long (taskready + 4);
+    while (node) {
+       console_out ("%08lx: %08lx %s\n", node, 0, get_real_address (get_long (node + 10)));
+       node = get_long (node);
+    }
+    console_out ("Waiting:\n");
+    node = get_long (taskwait);
+    end = get_long (taskwait + 4);
+    while (node) {
+       console_out ("%08lx: %08lx %s\n", node, 0, get_real_address (get_long (node + 10)));
+       node = get_long (node);
+    }
+}
+
+static int trace_same_insn_count;
+static uae_u8 trace_insn_copy[10];
+static struct regstruct trace_prev_regs;
+static uaecptr nextpc;
+
+static int instruction_breakpoint (char **c)
+{
+    struct breakpoint_node *bpn;
+    int i;
+
+    if (more_params (c)) {
+       char nc = toupper((*c)[0]);
+       if (nc == 'I') {
+           next_char (c);
+           if (more_params (c))
+               skipins = readhex (c);
+           else
+               skipins = 0x10000;
+           do_skip = 1;
+           skipaddr_doskip = 1;
+           return 1;
+       } else if (nc == 'D') {
+           for (i = 0; i < BREAKPOINT_TOTAL; i++)
+               bpnodes[i].enabled = 0;
+           console_out ("All breakpoints removed\n");
+           return 0;
+       } else if (nc == 'L') {
+           int got = 0;
+           for (i = 0; i < BREAKPOINT_TOTAL; i++) {
+               bpn = &bpnodes[i];
+               if (!bpn->enabled)
+                   continue;
+               console_out ("%8X ", bpn->addr);
+               got = 1;
+           }
+           if (!got)
+               console_out ("No breakpoints\n");
+           else
+               console_out ("\n");
+           return 0;
+       }
+       skipaddr_doskip = 1;
+       skipaddr_start = readhex (c);
+       if (more_params (c)) {
+           skipaddr_end = readhex (c);
+       } else {
+           for (i = 0; i < BREAKPOINT_TOTAL; i++) {
+               bpn = &bpnodes[i];
+               if (bpn->enabled && bpn->addr == skipaddr_start) {
+                   bpn->enabled = 0;
+                   console_out ("Breakpoint removed\n");
+                   skipaddr_start = 0xffffffff;
+                   skipaddr_doskip = 0;
+                   return 0;
+               }
+           }
+           for (i = 0; i < BREAKPOINT_TOTAL; i++) {
+               bpn = &bpnodes[i];
+               if (bpn->enabled)
+                   continue;
+               bpn->addr = skipaddr_start;
+               bpn->enabled = 1;
+               console_out ("Breakpoint added\n");
+               skipaddr_start = 0xffffffff;
+               skipaddr_doskip = 0;
+               break;
+           }
+           return 0;
+       }
+    }
+    if (skipaddr_start == 0xC0DEDBAD) {
+        trace_same_insn_count = 0;
+       logfile = fopen ("uae.trace", "w");
+       memcpy (trace_insn_copy, regs.pc_p, 10);
+       memcpy (&trace_prev_regs, &regs, sizeof regs);
+    }
+    do_skip = 1;
+    skipaddr_doskip = 1;
+    return 1;
+}
+
+static void savemem (char **cc)
+{
+    uae_u8 b;
+    uae_u32 src, src2, len, len2;
+    char *name;
+    FILE *fp;
+
+    if (!more_params (cc))
+       goto S_argh;
+
+    name = *cc;
+    while (**cc != '\0' && !isspace (**cc))
+       (*cc)++;
+    if (!isspace (**cc))
+       goto S_argh;
+
+    **cc = '\0';
+    (*cc)++;
+    if (!more_params (cc))
+       goto S_argh;
+    src2 = src = readhex (cc);
+    if (!more_params (cc))
+       goto S_argh;
+    len2 = len = readhex (cc);
+    fp = fopen (name, "wb");
+    if (fp == NULL) {
+       console_out ("Couldn't open file '%s'\n", name);
+       return;
+    }
+    while (len > 0) {
+       b = get_byte (src);
+       src++;
+       len--;
+       if (fwrite (&b, 1, 1, fp) != 1) {
+           console_out ("Error writing file\n");
+           break;
+       }
+    }
+    fclose (fp);
+    if (len == 0)
+       console_out ("Wrote %08X - %08X (%d bytes) to '%s'\n",
+           src2, src2 + len2, len2, name);
+    return;
+S_argh:
+    console_out ("S-command needs more arguments!\n");
+}
+
+static void searchmem (char **cc)
+{
+    int i, sslen, got, val, stringmode;
+    uae_u8 ss[256];
+    uae_u32 addr, endaddr;
+    char nc;
+
+    got = 0;
+    sslen = 0;
+    stringmode = 0;
+    ignore_ws (cc);
+    if (**cc == '"') {
+       stringmode = 1;
+       (*cc)++;
+       while (**cc != '"' && **cc != 0) {
+           ss[sslen++] = tolower (**cc);
+           (*cc)++;
+       }
+       if (**cc != 0)
+           (*cc)++;
+    } else {
+       for (;;) {
+           if (**cc == 32 || **cc == 0)
+               break;
+           nc = toupper (next_char (cc));
+           if (isspace (nc))
+               break;
+           if (isdigit(nc))
+               val = nc - '0';
+           else
+               val = nc - 'A' + 10;
+           if (val < 0 || val > 15)
+               return;
+           val *= 16;
+           if (**cc == 32 || **cc == 0)
+               break;
+           nc = toupper (next_char (cc));
+           if (isspace (nc))
+               break;
+           if (isdigit(nc))
+               val += nc - '0';
+           else
+               val += nc - 'A' + 10;
+           if (val < 0 || val > 255)
+               return;
+           ss[sslen++] = (uae_u8)val;
+       }
+    }
+    if (sslen == 0)
+       return;
+    ignore_ws (cc);
+    addr = 0;
+    endaddr = nextaddr (0xffffffff);
+    if (more_params (cc)) {
+       addr = readhex (cc);
+       if (more_params (cc))
+           endaddr = readhex (cc);
+    }
+    console_out ("Searching from %08x to %08x..\n", addr, endaddr);
+    while (addr < endaddr && addr != 0xffffffff) {
+       for (i = 0; i < sslen; i++) {
+           uae_u8 b = get_byte (addr + i);
+           if (stringmode) {
+               if (tolower (b) != ss[i])
+                   break;
+           } else {
+               if (b != ss[i])
+                   break;
+           }
+       }
+       if (i == sslen) {
+           got++;
+           console_out (" %08x", addr);
+           if (got > 100) {
+               console_out ("\nMore than 100 results, aborting..");
+               break;
+           }
+       }
+       addr = nextaddr (addr);
+    }
+    if (!got)
+       console_out ("nothing found");
+    console_out ("\n");
+}      
+
+static int staterecorder (char **cc)
+{
+    char nc;
+
+    if (!more_params (cc)) {
+        if (savestate_dorewind (1)) {
+           debug_rewind = 1;
+           return 1;
+       }
+       return 0;
+    }
+    nc = next_char (cc);
+    if (nc == 'l') {
+       savestate_listrewind ();
+       return 0;
+    }
+    return 0;
+}
+
+static void m68k_modify (char **inptr)
+{
+    char c1, c2;
+    uae_u32 v;
+    
+    c1 = toupper (next_char (inptr));
+    if (!more_params (inptr))
+       return;
+    c2 = toupper (next_char (inptr));
+    if (c2 < '0' || c2 > '7')
+       return;
+    c2 -= '0';
+    v = readhex (inptr);
+    if (c1 == 'A')
+       regs.regs[8 + c2] = v;
+    else if (c1 == 'D')
+       regs.regs[c2] = v;
+    else if (c1 == 'P' && c2 == 0)
+       regs.irc = v;
+    else if (c1 == 'P' && c2 == 1)
+       regs.ir = v;
+}
+
+static void debug_1 (void)
+{
+    char input[80];
+    uaecptr nxdis,nxmem,nxcopper;
+
+    m68k_dumpstate (stdout, &nextpc);
+    nxdis = nextpc; nxmem = nxcopper = 0;
+
+    for (;;) {
+       char cmd, *inptr;
+
+       console_out (">");
+       console_flush ();
+        if (!console_get (input, 80))
+           continue;
+       inptr = input;
+       cmd = next_char (&inptr);
+       switch (cmd) {
+       case 'c': dumpcia (); dumpdisk (); dumpcustom (); break;
+       case 'i': dump_vectors (); break;
+       case 'e': dump_custom_regs (); break;
+       case 'r': if (more_params(&inptr))
+                     m68k_modify (&inptr);
+                 else
+                     m68k_dumpstate (stdout, &nextpc);
+       break;
+       case 'M': modulesearch (); break;
+       case 'C': cheatsearch (&inptr); break; 
+       case 'W': writeintomem (&inptr); break;
+       case 'w': memwatch (&inptr); break;
+       case 'S': savemem (&inptr); break;
+       case 's': searchmem (&inptr); break;
+       case 'd':
+       {
+           uae_u32 daddr;
+           int count;
+
+           if (more_params(&inptr))
+               daddr = readhex(&inptr);
+           else
+               daddr = nxdis;
+           if (more_params(&inptr))
+               count = readhex(&inptr);
+           else
+               count = 10;
+           m68k_disasm (stdout, daddr, &nxdis, count);
+       }
+       break;
+       case 'T': show_exec_tasks (); break;
+       case 't':
+           if (more_params (&inptr))
+               skipaddr_doskip = readint (&inptr);
+           if (skipaddr_doskip <= 0 || skipaddr_doskip > 10000)
+               skipaddr_doskip = 1;
+           set_special (SPCFLAG_BRK);
+           exception_debugging = 1;
+           return;
+       case 'z':
+           skipaddr_start = nextpc;
+           skipaddr_doskip = 1;
+           do_skip = 1;
+           exception_debugging = 1;
+           return;
+
+       case 'f':
+           if (instruction_breakpoint (&inptr))
+               return;
+           break;
+
+       case 'q': uae_quit();
+           debugger_active = 0;
+           debugging = 0;
+           return;
+
+       case 'g':
+           if (more_params (&inptr)) {
+               m68k_setpc (readhex (&inptr));
+               fill_prefetch_slow ();
+           }
+           debugger_active = 0;
+           debugging = 0;
+           return;
+
+       case 'H':
+       {
+           int count;
+           int temp;
+#ifdef NEED_TO_DEBUG_BADLY
+           struct regstruct save_regs = regs;
+           union flagu save_flags = regflags;
+#endif
+
+           if (more_params(&inptr))
+               count = readhex(&inptr);
+           else
+               count = 10;
+           if (count < 0)
+               break;
+           temp = lasthist;
+           while (count-- > 0 && temp != firsthist) {
+               if (temp == 0) temp = MAX_HIST-1; else temp--;
+           }
+           while (temp != lasthist) {
+#ifdef NEED_TO_DEBUG_BADLY
+               regs = history[temp];
+               regflags = historyf[temp];
+               m68k_dumpstate (NULL);
+#else
+               m68k_disasm (stdout, history[temp], NULL, 1);
+#endif
+               if (++temp == MAX_HIST) temp = 0;
+           }
+#ifdef NEED_TO_DEBUG_BADLY
+           regs = save_regs;
+           regflags = save_flags;
+#endif
+       }
+       break;
+       case 'm':
+       {
+           uae_u32 maddr; int lines;
+           if (more_params(&inptr))
+               maddr = readhex(&inptr);
+           else
+               maddr = nxmem;
+           if (more_params(&inptr))
+               lines = readhex(&inptr);
+           else
+               lines = 20;
+           dumpmem(maddr, &nxmem, lines);
+       }
+       break;
+       case 'o':
+       {
+           uae_u32 maddr;
+           int lines;
+           if (more_params(&inptr)) {
+               maddr = readhex(&inptr);
+               if (maddr == 1 || maddr == 2)
+                   maddr = get_copper_address (maddr);         
+           }
+           else
+               maddr = nxcopper;
+
+           if (more_params (&inptr))
+               lines = readhex (&inptr);
+           else
+               lines = 20;
+
+           nxcopper = decode_copperlist (stdout, maddr, lines);
+           break;
+       }
+       case 'O':
+           if (more_params (&inptr)) {
+               int plane = readint (&inptr);
+               int offs = readint (&inptr);
+               if (plane >= 0 && plane < 8)
+                   bpl_off[plane] = offs;
+           } else {
+               int i;
+               for (i = 0; i < 8; i++)
+                   console_out ("Plane %d offset %d\n", i, bpl_off[i]);
+           }
+           break;
+       case 'b':
+           if (staterecorder (&inptr))
+               return;
+           break;
+       case 'a':
+           if (more_params (&inptr)) {
+               char nc = toupper((inptr)[0]);
+               if (nc == 'm')
+                   audio_channel_mask = readint (&inptr);
+           }
+           break;
+       case 'h':
+       case '?':
+           debug_help ();
+       break;
+       }
+    }
+}
+
+void debug (void)
+{
+    int i;
+
+    if (savestate_state)
+       return;
+
+    bogusframe = 1;
+
+    if (do_skip && skipaddr_start == 0xC0DEDBAD) {
+#if 0
+       if (trace_same_insn_count > 0) {
+           if (memcmp (trace_insn_copy, regs.pc_p, 10) == 0
+               && memcmp (trace_prev_regs.regs, regs.regs, sizeof regs.regs) == 0)
+           {
+               trace_same_insn_count++;
+               return;
+           }
+       }
+       if (trace_same_insn_count > 1)
+           fprintf (logfile, "[ repeated %d times ]\n", trace_same_insn_count);
+#endif
+       m68k_dumpstate (logfile, &nextpc);
+       trace_same_insn_count = 1;
+       memcpy (trace_insn_copy, regs.pc_p, 10);
+       memcpy (&trace_prev_regs, &regs, sizeof regs);
+    }
+
+    if (!memwatch_triggered) {
+       if (do_skip) {
+           uae_u32 pc = munge24 (m68k_getpc());
+           uae_u16 opcode = (currprefs.cpu_compatible || currprefs.cpu_cycle_exact) ? regs.ir : get_word (pc);
+           int bp = 0;
+
+           for (i = 0; i < BREAKPOINT_TOTAL; i++) {
+               if (!bpnodes[i].enabled)
+                   continue;
+               if (bpnodes[i].addr == pc) {
+                   bp = 1;
+                   console_out ("Breakpoint at %08.8X\n", pc);
+                   break;
+               }
+           }
+           if (skipaddr_doskip) {
+               if (skipaddr_start == pc)
+                   bp = 1;
+               if (skipins != 0xffffffff) {
+                   if (skipins == 0x10000) {
+                       if (opcode == 0x4e75 || opcode == 0x4e73 || opcode == 0x4e77)
+                           bp = 1;
+                   } else if (opcode == skipins)
+                       bp = 1;
+               } else if (skipaddr_start == 0xffffffff && skipaddr_doskip) {
+                   if ((pc < 0xe00000 || pc >= 0x1000000) && opcode != 0x4ef9)
+                       bp = 1;
+               } else if (skipaddr_end != 0xffffffff) {
+                   if (pc >= skipaddr_start && pc < skipaddr_end)
+                       bp = 1;
+               }
+           }
+           if (!bp) {
+               set_special (SPCFLAG_BRK);
+               return;
+           }
+       }
+    } else {
+        write_log ("Memwatch %d: break at %08.8X.%c %c %08.8X\n", memwatch_triggered - 1, mwhit.addr,
+           mwhit.size == 1 ? 'B' : (mwhit.size == 2 ? 'W' : 'L'), mwhit.rw ? 'W' : 'R', mwhit.val);
+       memwatch_triggered = 0;
+    }
+    if (skipaddr_doskip > 0) {
+       skipaddr_doskip--;
+       if (skipaddr_doskip > 0) {
+           set_special (SPCFLAG_BRK);
+           return;
+       }
+    }
+
+#ifdef NEED_TO_DEBUG_BADLY
+    history[lasthist] = regs;
+    historyf[lasthist] = regflags;
+#else
+    history[lasthist] = m68k_getpc();
+#endif
+    if (++lasthist == MAX_HIST) lasthist = 0;
+    if (lasthist == firsthist) {
+       if (++firsthist == MAX_HIST) firsthist = 0;
+    }
+    pause_sound ();
+    do_skip = 0;
+    skipaddr_start = 0xffffffff;
+    skipaddr_end = 0xffffffff;
+    skipins = 0xffffffff;
+    skipaddr_doskip = 0;
+    exception_debugging = 0;
+    debug_rewind = 0;
+#if 0
+    if (!currprefs.statecapture) {
+       changed_prefs.statecapture = currprefs.statecapture = 1;
+       savestate_init ();
+    }
+#endif
+    debug_1 ();
+    if (!debug_rewind && !currprefs.cachesize
+#ifdef FILESYS
+       && nr_units (currprefs.mountinfo) == 0
+#endif
+       ) {
+       savestate_capture (1);
+    }
+    for (i = 0; i < BREAKPOINT_TOTAL; i++) {
+       if (bpnodes[i].enabled)
+           do_skip = 1;
+    }
+    if (do_skip) {
+        set_special (SPCFLAG_BRK);
+       debugging = 1;
+    }
+    resume_sound ();
+}
+
+int notinrom (void)
+{
+    if (munge24 (m68k_getpc()) < 0xe0000)
+       return 1;
+    return 0;
+}
+
+const char *debuginfo (int mode)
+{
+    static char txt[100];
+    uae_u32 pc = m68k_getpc();
+    sprintf (txt, "PC=%08.8X INS=%04.4X %04.4X %04.4X",
+       pc, get_word(pc), get_word(pc+2), get_word(pc+4));
+    return txt;
+}
diff --git a/disk.c b/disk.c
new file mode 100755 (executable)
index 0000000..c2a29fa
--- /dev/null
+++ b/disk.c
@@ -0,0 +1,2601 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Floppy disk emulation
+  *
+  * Copyright 1995 Hannu Rummukainen
+  * Copyright 1995-2001 Bernd Schmidt
+  * Copyright 2000-2003 Toni Wilen
+  *
+  * High Density Drive Handling by Dr. Adil Temel (C) 2001 [atemel1@hotmail.com]
+  *
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "uae.h"
+#include "config.h"
+#include "options.h"
+#include "threaddep/thread.h"
+#include "memory.h"
+#include "events.h"
+#include "custom.h"
+#include "ersatz.h"
+#include "disk.h"
+#include "gui.h"
+#include "zfile.h"
+#include "autoconf.h"
+#include "newcpu.h"
+#include "xwin.h"
+#include "osemu.h"
+#include "execlib.h"
+#include "savestate.h"
+#include "fdi2raw.h"
+#include "catweasel.h"
+#include "driveclick.h"
+#ifdef CAPS
+#include "caps/caps_win32.h"
+#endif
+
+/* writable track length with normal 2us bitcell/300RPM motor (PAL) */
+#define FLOPPY_WRITE_LEN (currprefs.ntscmode ? (12798 / 2) : (12668 / 2)) /* 12667 PAL, 12797 NTSC */
+/* This works out to 350 */
+#define FLOPPY_GAP_LEN (FLOPPY_WRITE_LEN - 11 * 544)
+/* (cycles/bitcell) << 8, normal = ((2us/280ns)<<8) = ~1830 */
+#define NORMAL_FLOPPY_SPEED (currprefs.ntscmode ? 1810 : 1829)
+
+#define DISK_DEBUG
+#define DISK_DEBUG2
+#undef DISK_DEBUG
+#undef DISK_DEBUG2
+#undef DEBUG_DRIVE_ID
+
+/* UAE-1ADF (ADF_EXT2)
+ * W   reserved
+ * W   number of tracks (default 2*80=160)
+ *
+ * W   reserved
+ * W   type, 0=normal AmigaDOS track, 1 = raw MFM
+ * L   available space for track in bytes (must be even)
+ * L   track length in bits
+ */
+
+static int side, direction, writing;
+static uae_u8 selected = 15, disabled;
+
+static uae_u8 *writebuffer[544 * 22];
+
+#define DISK_INDEXSYNC 1
+#define DISK_WORDSYNC 2
+
+/* A value of 5 works out to a guaranteed delay of 1/2 of a second
+ Higher values are dangerous, e.g. a value of 8 breaks the RSI
+ demo.  */
+#define DSKREADY_TIME 5
+#define DSKREADY_DOWN_TIME 10
+
+#if 0
+#define MAX_DISK_WORDS_PER_LINE 50 /* depends on floppy_speed */
+static uae_u32 dma_tab[MAX_DISK_WORDS_PER_LINE + 1];
+#endif
+static int dskdmaen, dsklength, dsklen;
+static uae_u16 dskbytr_val;
+static uae_u32 dskpt;
+static int dma_enable, bitoffset, syncoffset;
+static uae_u16 word, dsksync;
+/* Always carried through to the next line.  */
+static int disk_hpos;
+
+typedef enum { TRACK_AMIGADOS, TRACK_RAW, TRACK_RAW1 } image_tracktype;
+typedef struct {
+    uae_u16 len;
+    uae_u32 offs;
+    int bitlen, track;
+    unsigned int sync;
+    image_tracktype type;
+} trackid;
+
+#define MAX_TRACKS 328
+
+/* We have three kinds of Amiga floppy drives
+ * - internal A500/A2000 drive:
+ *   ID is always DRIVE_ID_NONE (S.T.A.G expects this)
+ * - HD drive (A3000/A4000):
+ *   ID is DRIVE_ID_35DD if DD floppy is inserted or drive is empty
+ *   ID is DRIVE_ID_35HD if HD floppy is inserted
+ * - regular external drive:
+ *   ID is always DRIVE_ID_35DD
+ */
+
+#define DRIVE_ID_NONE  0x00000000
+#define DRIVE_ID_35DD  0xFFFFFFFF
+#define DRIVE_ID_35HD  0xAAAAAAAA
+#define DRIVE_ID_525SD 0x55555555 /* 40 track 5.25 drive , kickstart does not recognize this */
+
+#define MAX_REVOLUTIONS 5
+
+typedef enum { ADF_NORMAL, ADF_EXT1, ADF_EXT2, ADF_FDI, ADF_IPF, ADF_CATWEASEL } drive_filetype;
+typedef struct {
+    struct zfile *diskfile;
+    struct zfile *writediskfile;
+    drive_filetype filetype;
+    trackid trackdata[MAX_TRACKS];
+    trackid writetrackdata[MAX_TRACKS];
+    int buffered_cyl, buffered_side;
+    int cyl;
+    int motoroff;
+    int state;
+    int wrprot;
+    uae_u16 bigmfmbuf[MAX_REVOLUTIONS * 0x8000];
+    int revolutions;
+    int current_revolution;
+    uae_u16 *trackpointers[MAX_REVOLUTIONS];
+    uae_u16 *tracktiming;
+    int tracklengths[MAX_REVOLUTIONS];
+    int mfmpos;
+    int indexoffset;
+    int tracklen;
+    int prevtracklen;
+    int trackspeed;
+    int dmalen;
+    int num_tracks, write_num_tracks, num_secs;
+    int hard_num_cyls;
+    int dskchange;
+    int dskchange_time;
+    int dskready;
+    int dskready_time;
+    int dskready_down_time;
+    int steplimit;
+    int ddhd; /* 1=DD 2=HD */
+    int drive_id_scnt; /* drive id shift counter */
+    int idbit;
+    unsigned long drive_id; /* drive id to be reported */
+    char newname[256]; /* storage space for new filename during eject delay */
+    FDI *fdi;
+    int useturbo;
+    int floppybitcounter; /* number of bits left */
+#ifdef CATWEASEL
+    catweasel_drive *catweasel;
+#else
+    int catweasel;
+#endif
+} drive;
+
+static uae_u16 bigmfmbufw[0x8000];
+static drive floppy[4];
+#define MAX_PREVIOUS_FLOPPIES 99
+static char dfxhistory[MAX_PREVIOUS_FLOPPIES][256];
+
+static uae_u8 exeheader[]={0x00,0x00,0x03,0xf3,0x00,0x00,0x00,0x00};
+static uae_u8 bootblock[]={
+    0x44,0x4f,0x53,0x00,0xc0,0x20,0x0f,0x19,0x00,0x00,0x03,0x70,0x43,0xfa,0x00,0x18,
+    0x4e,0xae,0xff,0xa0,0x4a,0x80,0x67,0x0a,0x20,0x40,0x20,0x68,0x00,0x16,0x70,0x00,
+    0x4e,0x75,0x70,0xff,0x60,0xfa,0x64,0x6f,0x73,0x2e,0x6c,0x69,0x62,0x72,0x61,0x72,
+    0x79
+};
+
+#define FS_OFS_DATABLOCKSIZE 488
+#define FS_FLOPPY_BLOCKSIZE 512
+#define FS_EXTENSION_BLOCKS 72
+#define FS_FLOPPY_TOTALBLOCKS 1760
+#define FS_FLOPPY_RESERVED 2
+
+static void writeimageblock (struct zfile *dst, uae_u8 *sector, int offset)
+{
+    zfile_fseek (dst, offset, SEEK_SET);
+    zfile_fwrite (sector, FS_FLOPPY_BLOCKSIZE, 1, dst);
+}
+
+static void disk_checksum(uae_u8 *p, uae_u8 *c)
+{
+    uae_u32 cs = 0;
+    int i;
+    for (i = 0; i < FS_FLOPPY_BLOCKSIZE; i+= 4) cs += (p[i] << 24) | (p[i+1] << 16) | (p[i+2] << 8) | (p[i+3] << 0);
+    cs = -cs;
+    c[0] = cs >> 24; c[1] = cs >> 16; c[2] = cs >> 8; c[3] = cs >> 0;
+}
+
+static int dirhash (unsigned char *name)
+{
+    unsigned long hash;
+    int i;
+
+    hash = strlen (name);
+    for(i = 0; i < strlen (name); i++) {
+       hash = hash * 13;
+       hash = hash + toupper (name[i]);
+       hash = hash & 0x7ff;
+    }
+    hash = hash % ((FS_FLOPPY_BLOCKSIZE / 4) - 56);
+    return hash;
+}
+
+static void disk_date (uae_u8 *p)
+{
+    time_t t;
+    struct tm *today;
+    int year, days, minutes, ticks;
+    char tmp[10];
+    time (&t);
+    today = localtime( &t );
+    strftime (tmp, sizeof(tmp), "%Y", today);
+    year = atol (tmp);
+    strftime (tmp, sizeof(tmp), "%j", today);
+    days = atol (tmp) - 1;
+    strftime (tmp, sizeof(tmp), "%H", today);
+    minutes = atol (tmp) * 60;
+    strftime (tmp, sizeof(tmp), "%M", today);
+    minutes += atol (tmp);
+    strftime (tmp, sizeof(tmp), "%S", today);
+    ticks = atol (tmp) * 50;
+    while (year > 1978) {
+       if ( !(year % 100) ? !(year % 400) : !(year % 4) ) days++;
+       days += 365;
+       year--;
+    }
+    p[0] = days >> 24; p[1] = days >> 16; p[2] = days >> 8; p[3] = days >> 0;
+    p[4] = minutes >> 24; p[5] = minutes >> 16; p[6] = minutes >> 8; p[7] = minutes >> 0;
+    p[8] = ticks >> 24; p[9] = ticks >> 16; p[10] = ticks >> 8; p[11] = ticks >> 0; 
+}
+
+static void createbootblock (uae_u8 *sector, int bootable)
+{
+    memset (sector, 0, FS_FLOPPY_BLOCKSIZE);
+    memcpy (sector, "DOS", 3);
+    if (bootable)
+       memcpy (sector, bootblock, sizeof(bootblock));
+}
+
+static void createrootblock (uae_u8 *sector, uae_u8 *disk_name)
+{
+    memset (sector, 0, FS_FLOPPY_BLOCKSIZE);
+    sector[0+3] = 2;
+    sector[12+3] = 0x48;
+    sector[312] = sector[313] = sector[314] = sector[315] = (uae_u8)0xff;
+    sector[316+2] = 881 >> 8; sector[316+3] = 881 & 255;
+    sector[432] = strlen (disk_name);
+    strcpy (sector + 433, disk_name);
+    sector[508 + 3] = 1;
+    disk_date (sector + 420);
+    memcpy (sector + 472, sector + 420, 3 * 4);
+    memcpy (sector + 484, sector + 420, 3 * 4);
+}
+
+static int getblock (uae_u8 *bitmap)
+{
+    int i = 0;
+    while (bitmap[i] != 0xff) {
+       if (bitmap[i] == 0) {
+           bitmap[i] = 1;
+           return i;
+       }
+       i++;
+    }
+    return -1;
+}
+
+static void pl (uae_u8 *sector, int offset, uae_u32 v)
+{
+    sector[offset + 0] = v >> 24;
+    sector[offset + 1] = v >> 16;
+    sector[offset + 2] = v >> 8;
+    sector[offset + 3] = v >> 0;
+}
+
+static int createdirheaderblock (uae_u8 *sector, int parent, char *filename, uae_u8 *bitmap)
+{
+    int block = getblock (bitmap);
+
+    memset (sector, 0, FS_FLOPPY_BLOCKSIZE);
+    pl (sector, 0, 2);
+    pl (sector, 4, block);
+    disk_date (sector + 512 - 92);
+    sector[512 - 80] = strlen (filename);
+    strcpy (sector + 512 - 79, filename);
+    pl (sector, 512 - 12, parent);
+    pl (sector, 512 - 4, 2);
+    return block;
+}
+
+static int createfileheaderblock (struct zfile *z,uae_u8 *sector, int parent, char *filename, struct zfile *src, uae_u8 *bitmap)
+{
+    uae_u8 sector2[FS_FLOPPY_BLOCKSIZE];
+    uae_u8 sector3[FS_FLOPPY_BLOCKSIZE];
+    int block = getblock (bitmap);
+    int datablock = getblock (bitmap);
+    int datasec = 1;
+    int extensions;
+    int extensionblock, extensioncounter, headerextension = 1;
+    int size;
+
+    zfile_fseek (src, 0, SEEK_END);
+    size = zfile_ftell (src);
+    zfile_fseek (src, 0, SEEK_SET);
+    extensions = (size + FS_OFS_DATABLOCKSIZE - 1) / FS_OFS_DATABLOCKSIZE;
+
+    memset (sector, 0, FS_FLOPPY_BLOCKSIZE);
+    pl (sector, 0, 2);
+    pl (sector, 4, block);
+    pl (sector, 8, extensions > FS_EXTENSION_BLOCKS ? FS_EXTENSION_BLOCKS : extensions);
+    pl (sector, 16, datablock);
+    pl (sector, FS_FLOPPY_BLOCKSIZE - 188, size);
+    disk_date (sector + FS_FLOPPY_BLOCKSIZE - 92);
+    sector[FS_FLOPPY_BLOCKSIZE - 80] = strlen (filename);
+    strcpy (sector + FS_FLOPPY_BLOCKSIZE - 79, filename);
+    pl (sector, FS_FLOPPY_BLOCKSIZE - 12, parent);
+    pl (sector, FS_FLOPPY_BLOCKSIZE - 4, -3);
+    extensioncounter = 0;
+    extensionblock = 0;
+
+    while (size > 0) {
+       int datablock2 = datablock;
+       int extensionblock2 = extensionblock;
+       if (extensioncounter == FS_EXTENSION_BLOCKS) {
+           extensioncounter = 0;
+           extensionblock = getblock (bitmap);
+           if (datasec > FS_EXTENSION_BLOCKS + 1) {
+               pl (sector3, 8, FS_EXTENSION_BLOCKS);
+               pl (sector3, FS_FLOPPY_BLOCKSIZE - 8, extensionblock);
+               pl (sector3, 4, extensionblock2);
+               disk_checksum(sector3, sector3 + 20);
+               writeimageblock (z, sector3, extensionblock2 * FS_FLOPPY_BLOCKSIZE);
+           } else {
+               pl (sector, 512 - 8, extensionblock);
+           }
+           memset (sector3, 0, FS_FLOPPY_BLOCKSIZE);
+           pl (sector3, 0, 16);
+           pl (sector3, FS_FLOPPY_BLOCKSIZE - 12, block);
+           pl (sector3, FS_FLOPPY_BLOCKSIZE - 4, -3);
+       }
+       memset (sector2, 0, FS_FLOPPY_BLOCKSIZE);
+       pl (sector2, 0, 8);
+       pl (sector2, 4, block);
+       pl (sector2, 8, datasec++);
+       pl (sector2, 12, size > FS_OFS_DATABLOCKSIZE ? FS_OFS_DATABLOCKSIZE : size);
+       zfile_fread (sector2 + 24, size > FS_OFS_DATABLOCKSIZE ? FS_OFS_DATABLOCKSIZE : size, 1, src);
+       size -= FS_OFS_DATABLOCKSIZE;
+       datablock = 0;
+       if (size > 0) datablock = getblock (bitmap);
+       pl (sector2, 16, datablock);
+        disk_checksum(sector2, sector2 + 20);
+        writeimageblock (z, sector2, datablock2 * FS_FLOPPY_BLOCKSIZE);
+       if (datasec <= FS_EXTENSION_BLOCKS + 1)
+           pl (sector, 512 - 204 - extensioncounter * 4, datablock2);
+       else
+           pl (sector3, 512 - 204 - extensioncounter * 4, datablock2);
+       extensioncounter++;
+    }
+    if (datasec > FS_EXTENSION_BLOCKS) {
+       pl (sector3, 8, extensioncounter);
+        disk_checksum(sector3, sector3 + 20);
+        writeimageblock (z, sector3, extensionblock * FS_FLOPPY_BLOCKSIZE);
+    }
+    disk_checksum(sector, sector + 20);
+    writeimageblock (z, sector, block * FS_FLOPPY_BLOCKSIZE);
+    return block;
+}
+
+static void createbitmapblock (uae_u8 *sector, uae_u8 *bitmap)
+{
+    uae_u8 mask;
+    int i, j;
+    memset (sector, 0, FS_FLOPPY_BLOCKSIZE);
+    for (i = FS_FLOPPY_RESERVED; i < FS_FLOPPY_TOTALBLOCKS; i += 8) {
+       mask = 0;
+       for (j = 0; j < 8; j++) {
+           if (bitmap[i + j]) mask |= 1 << j;
+       }
+       sector[4 + i / 8] = mask;
+    }
+    disk_checksum(sector, sector + 0);
+}
+
+static int createimagefromexe (struct zfile *src, struct zfile *dst)
+{
+    uae_u8 sector1[FS_FLOPPY_BLOCKSIZE], sector2[FS_FLOPPY_BLOCKSIZE];
+    uae_u8 bitmap[FS_FLOPPY_TOTALBLOCKS + 8];
+    int exesize;
+    int blocksize = FS_OFS_DATABLOCKSIZE;
+    int blocks, extensionblocks;
+    int totalblocks;
+    int fblock1, dblock1;
+    char *fname1 = "runme.exe";
+    char *fname2 = "startup-sequence";
+    char *dirname1 = "s";
+    struct zfile *ss;
+
+    memset (bitmap, 0, sizeof (bitmap));
+    zfile_fseek (src, 0, SEEK_END);
+    exesize = zfile_ftell (src);
+    blocks = (exesize + blocksize - 1) / blocksize;
+    extensionblocks = (blocks + FS_EXTENSION_BLOCKS - 1) / FS_EXTENSION_BLOCKS;
+    /* bootblock=2, root=1, bitmap=1, startup-sequence=1+1, exefileheader=1 */
+    totalblocks = 2 + 1 + 1 + 2 + 1 + blocks + extensionblocks;
+    if (totalblocks > FS_FLOPPY_TOTALBLOCKS)
+       return 0;
+
+    bitmap[880] = 1;
+    bitmap[881] = 1;
+    bitmap[0] = 1;
+    bitmap[1] = 1;
+
+    dblock1 = createdirheaderblock (sector2, 880, dirname1, bitmap);
+    ss = zfile_fopen_empty (fname1, strlen(fname1));
+    zfile_fwrite (fname1, strlen(fname1), 1, ss);
+    fblock1 = createfileheaderblock (dst, sector1,  dblock1, fname2, ss, bitmap);
+    zfile_fclose (ss);
+    pl (sector2, 24 + dirhash (fname2) * 4, fblock1);
+    disk_checksum(sector2, sector2 + 20);
+    writeimageblock (dst, sector2, dblock1 * FS_FLOPPY_BLOCKSIZE);
+
+    fblock1 = createfileheaderblock (dst, sector1, 880, fname1, src, bitmap);
+
+    createrootblock (sector1, "empty");
+    pl (sector1, 24 + dirhash (fname1) * 4, fblock1);
+    pl (sector1, 24 + dirhash (dirname1) * 4, dblock1);
+    disk_checksum(sector1, sector1 + 20);
+    writeimageblock (dst, sector1, 880 * FS_FLOPPY_BLOCKSIZE);
+    
+    createbitmapblock (sector1, bitmap);
+    writeimageblock (dst, sector1, 881 * FS_FLOPPY_BLOCKSIZE);
+
+    createbootblock (sector1, 1);
+    writeimageblock (dst, sector1, 0 * FS_FLOPPY_BLOCKSIZE);
+
+    return 1;
+}
+
+static int get_floppy_speed (void)
+{
+    int m = currprefs.floppy_speed;
+    if (m <= 10) m = 100;
+    m = NORMAL_FLOPPY_SPEED * 100 / m;
+    return m;
+}
+
+static char *drive_id_name(drive *drv)
+{
+    switch(drv->drive_id)
+    {
+    case DRIVE_ID_35HD : return "3.5HD";
+    case DRIVE_ID_525SD: return "5.25SD";
+    case DRIVE_ID_35DD : return "3.5DD";
+    }
+    return "UNKNOWN"; 
+}
+
+/* Simulate exact behaviour of an A3000T 3.5 HD disk drive. 
+ * The drive reports to be a 3.5 DD drive whenever there is no
+ * disk or a 3.5 DD disk is inserted. Only 3.5 HD drive id is reported
+ * when a real 3.5 HD disk is inserted. -Adil
+ */
+static void drive_settype_id(drive *drv)
+{
+    int t = currprefs.dfxtype[drv - &floppy[0]];
+
+    switch (t)
+    {
+       case DRV_35_HD:
+       if (!drv->diskfile || drv->ddhd <= 1)
+           drv->drive_id = DRIVE_ID_35DD;
+       else
+           drv->drive_id = DRIVE_ID_35HD;
+       break;
+       case DRV_35_DD:
+       default:
+        drv->drive_id = DRIVE_ID_35DD;
+       break;
+       case DRV_525_SD:
+       drv->drive_id = DRIVE_ID_525SD;
+       break;
+    }
+#ifdef DEBUG_DRIVE_ID
+    write_log("drive_settype_id: DF%d: set to %s\n", drv-floppy, drive_id_name(drv));
+#endif
+}
+
+static void drive_image_free (drive *drv)
+{
+    switch (drv->filetype)
+    {
+        case ADF_IPF:
+#ifdef CAPS
+        caps_unloadimage (drv - floppy);
+#endif
+        break;
+        case ADF_FDI:
+        fdi2raw_header_free (drv->fdi);
+        drv->fdi = 0;
+        break;
+    }
+    drv->filetype = -1;
+    zfile_fclose (drv->diskfile);
+    drv->diskfile = 0;
+    zfile_fclose (drv->writediskfile);
+    drv->writediskfile = 0;
+}
+
+static int drive_insert (drive * drv, int dnum, const char *fname);
+
+static void reset_drive(int i)
+{
+    drive *drv = &floppy[i];
+    drive_image_free (drv);
+    drv->motoroff = 1;
+    disabled &= ~(1 << i);
+    gui_data.drive_disabled[i] = 0;
+    if (currprefs.dfxtype[i] < 0) {
+        disabled |= 1 << i;
+        gui_data.drive_disabled[i] = 1;
+    }
+    drv->dskchange_time = 0;
+    drv->buffered_cyl = -1;
+    drv->buffered_side = -1;
+    gui_led (i + 1, 0);
+    drive_settype_id (drv);
+    if (strlen (drv->newname) > 0)
+        strcpy (currprefs.df[i], drv->newname);
+    if (!drive_insert (drv, i, currprefs.df[i]))
+        disk_eject (i);
+}
+
+/* code for track display */
+static void update_drive_gui (int num)
+{
+    drive *drv = floppy + num;
+
+    if (drv->state == gui_data.drive_motor[num]
+       && drv->cyl == gui_data.drive_track[num]
+       && side == gui_data.drive_side
+       && ((writing && gui_data.drive_writing[num])
+           || (!writing && !gui_data.drive_writing[num]))) {
+       return;
+    }
+    gui_data.drive_motor[num] = drv->state;
+    gui_data.drive_track[num] = drv->cyl;
+    gui_data.drive_side = side;
+    if (!gui_data.drive_writing[num])
+       gui_data.drive_writing[num] = writing;
+    gui_ledstate &= ~(2 << num);
+    if (drv->state)
+       gui_ledstate |= 2 << num;
+    gui_led (num + 1, gui_data.drive_motor[num]);
+}
+
+static void drive_fill_bigbuf (drive * drv,int);
+
+struct zfile *DISK_validate_filename (const char *fname, int leave_open, int *wrprot)
+{
+    struct zfile *f = zfile_fopen (fname, "r+b");
+    if (f) {
+       if (wrprot)
+           *wrprot = 0;
+    } else {
+       if (wrprot)
+           *wrprot = 1;
+       f = zfile_fopen (fname, "rb");
+    }
+    if (!leave_open)
+       zfile_fclose (f);
+    return f;
+}
+
+static void updatemfmpos (drive *drv)
+{
+    if (drv->prevtracklen)
+       drv->mfmpos = drv->mfmpos * (drv->tracklen * 1000 / drv->prevtracklen) / 1000;
+    drv->mfmpos %= drv->tracklen;
+    drv->prevtracklen = drv->tracklen;
+}
+
+static void track_reset (drive *drv)
+{
+    drv->tracklen = FLOPPY_WRITE_LEN * drv->ddhd * 2 * 8;
+    drv->trackspeed = get_floppy_speed ();
+    drv->revolutions = 0;
+    drv->tracklengths[0] = drv->tracklen;
+    drv->current_revolution = 0;
+    drv->trackpointers[0] = drv->bigmfmbuf;
+    drv->buffered_side = -1;
+    free (drv->tracktiming);
+    drv->tracktiming = 0;
+    memset (drv->bigmfmbuf, 0xaa, FLOPPY_WRITE_LEN * 2 * drv->ddhd);
+    updatemfmpos (drv);
+}
+
+static int read_header_ext2 (struct zfile *diskfile, trackid *trackdata, int *num_tracks, int *ddhd)
+{
+    uae_u8 buffer[2 + 2 + 4 + 4];
+    trackid *tid;
+    int offs;
+    int i;
+
+    zfile_fseek (diskfile, 0, SEEK_SET);
+    zfile_fread (buffer, 1, 8, diskfile);
+    if (strncmp (buffer, "UAE-1ADF", 8))
+       return 0;
+    zfile_fread (buffer, 1, 4, diskfile);
+    *num_tracks = buffer[2] * 256 + buffer[3];
+    offs = 8 + 2 + 2 + (*num_tracks) * (2 + 2 + 4 + 4);
+
+    for (i = 0; i < (*num_tracks); i++) {
+        tid = trackdata + i;
+        zfile_fread (buffer, 2 + 2 + 4 + 4, 1, diskfile);
+        tid->type = buffer[2] * 256 + buffer[3];
+        tid->len = buffer[5] * 65536 + buffer[6] * 256 + buffer[7];
+        tid->bitlen = buffer[9] * 65536 + buffer[10] * 256 + buffer[11];
+        tid->offs = offs;
+        if (tid->len > 20000 && ddhd)
+           *ddhd = 2;
+       tid->track = i;
+       offs += tid->len;
+    }
+    return 1;
+}
+
+static char *getwritefilename (const char *name)
+{
+    static char name1[1024];
+    char name2[1024];
+    int i;
+    
+    strcpy (name2, name);
+    i = strlen (name2) - 1;
+    while (i > 0) {
+       if (name2[i] == '.') {
+           name2[i] = 0;
+           break;
+       }
+       i--;
+    }
+    while (i > 0) {
+       if (name2[i] == '/' || name2[i] == '\\') {
+           i++;
+           break;
+       }
+       i--;
+    }
+    sprintf (name1, "%sSaveImages%c%s_save.adf", start_path, FSDB_DIR_SEPARATOR, name2 + i);
+    return name1;
+}
+
+static struct zfile *getwritefile (const char *name, int *wrprot)
+{
+    return DISK_validate_filename (getwritefilename (name), 1, wrprot);
+}
+
+static int iswritefileempty (const char *name)
+{
+    struct zfile *zf;
+    int wrprot;
+    uae_u8 buffer[8];
+    trackid td[MAX_TRACKS];
+    int tracks, ddhd, i, ret;
+
+    zf = getwritefile (name, &wrprot);
+    if (!zf) return 1;
+    zfile_fread (buffer, sizeof (char), 8, zf);
+    if (strncmp ((char *) buffer, "UAE-1ADF", 8))
+       return 0;
+    ret = read_header_ext2 (zf, td, &tracks, &ddhd);
+    zfile_fclose (zf);
+    if (!ret)
+       return 1;
+    for (i = 0; i < tracks; i++) {
+       if (td[i].bitlen) return 0;
+    }
+    return 1;
+}
+
+static int openwritefile (drive *drv, int create)
+{
+    int wrprot = 0;
+
+    drv->writediskfile = getwritefile (currprefs.df[drv - &floppy[0]], &wrprot);
+    if (drv->writediskfile) {
+        drv->wrprot = wrprot;
+       if (!read_header_ext2 (drv->writediskfile, drv->writetrackdata, &drv->write_num_tracks, 0)) {
+           zfile_fclose (drv->writediskfile);
+           drv->writediskfile = 0;
+           drv->wrprot = 1;
+       } else {
+           if (drv->write_num_tracks > drv->num_tracks)
+               drv->num_tracks = drv->write_num_tracks;
+       }
+    } else if (zfile_iscompressed (drv->diskfile)) {
+       drv->wrprot = 1;
+    }
+    return drv->writediskfile ? 1 : 0;
+}
+
+static int diskfile_iswriteprotect (const char *fname, int *needwritefile, drive_type *drvtype)
+{
+    struct zfile *zf1, *zf2;
+    int wrprot1 = 0, wrprot2 = 1;
+    unsigned char buffer[25];
+    
+    *needwritefile = 0;
+    *drvtype = DRV_35_DD;
+    zf1 = DISK_validate_filename (fname, 1, &wrprot1);
+    if (!zf1) return 1;
+    if (zfile_iscompressed (zf1)) {
+       wrprot1 = 1;
+       *needwritefile = 1;
+    }
+    zf2 = getwritefile (fname, &wrprot2);
+    zfile_fclose (zf2);
+    zfile_fread (buffer, sizeof (char), 25, zf1);
+    zfile_fclose (zf1);
+    if (strncmp ((char *) buffer, "CAPS", 4) == 0) {
+       *needwritefile = 1;
+       return wrprot2;
+    }
+    if (strncmp ((char *) buffer, "Formatted Disk Image file", 25) == 0) {
+       *needwritefile = 1;
+       return wrprot2;
+    }
+    if (strncmp ((char *) buffer, "UAE-1ADF", 8) == 0) {
+       if (wrprot1)
+           return wrprot2;
+       return wrprot1;
+    }
+    if (strncmp ((char *) buffer, "UAE--ADF", 8) == 0) {
+       *needwritefile = 1;
+       return wrprot2;
+    }
+    if (memcmp (exeheader, buffer, sizeof(exeheader)) == 0)
+       return 0;
+    if (wrprot1)
+       return wrprot2;
+    return wrprot1;
+}
+
+static int drive_insert (drive * drv, int dnum, const char *fname)
+{
+    unsigned char buffer[2 + 2 + 4 + 4];
+    trackid *tid;
+    int num_tracks;
+
+    drive_image_free (drv);
+    drv->diskfile = DISK_validate_filename (fname, 1, &drv->wrprot);
+    drv->ddhd = 1;
+    drv->num_secs = 0;
+    drv->hard_num_cyls = currprefs.dfxtype[dnum] == DRV_525_SD ? 40 : 80;
+    free (drv->tracktiming);
+    drv->tracktiming = 0;
+    drv->useturbo = 0;
+    drv->indexoffset = 0;
+    
+    if (!drv->motoroff) {
+       drv->dskready_time = DSKREADY_TIME;
+       drv->dskready_down_time = 0;
+    }
+
+    if (drv->diskfile == 0 && !drv->catweasel) {
+       track_reset (drv);
+       return 0;
+    }
+    strncpy (currprefs.df[dnum], fname, 255);
+    currprefs.df[dnum][255] = 0;
+    strncpy (changed_prefs.df[dnum], fname, 255);
+    changed_prefs.df[dnum][255] = 0;
+    gui_filename (dnum, fname);
+
+    memset (buffer, 0, sizeof (buffer));
+    if (drv->diskfile)
+       zfile_fread (buffer, sizeof (char), 8, drv->diskfile);
+
+    if (drv->catweasel) {
+
+        drv->wrprot = 1;
+       drv->filetype = ADF_CATWEASEL;
+       drv->num_tracks = 80;
+       drv->ddhd = 1;
+
+#ifdef CAPS
+    } else if (strncmp ((char *) buffer, "CAPS", 4) == 0) {
+
+        drv->wrprot = 1;
+       if (!caps_loadimage (drv->diskfile, drv - floppy, &num_tracks)) {
+           zfile_fclose (drv->diskfile);
+           drv->diskfile = 0;
+           return 0;
+       }
+        drv->num_tracks = num_tracks;
+        drv->filetype = ADF_IPF;
+#endif
+    } else if (drv->fdi = fdi2raw_header (drv->diskfile)) {
+
+        drv->wrprot = 1;
+       drv->num_tracks = fdi2raw_get_last_track (drv->fdi);
+       drv->num_secs = fdi2raw_get_num_sector (drv->fdi);
+       drv->filetype = ADF_FDI;
+
+    } else if (strncmp ((char *) buffer, "UAE-1ADF", 8) == 0) {
+
+       read_header_ext2 (drv->diskfile, drv->trackdata, &drv->num_tracks, &drv->ddhd);
+       drv->filetype = ADF_EXT2;
+       drv->num_secs = 11;
+       if (drv->ddhd > 1)
+           drv->num_secs = 22;
+
+    } else if (strncmp ((char *) buffer, "UAE--ADF", 8) == 0) {
+       int offs = 160 * 4 + 8;
+       int i;
+
+        drv->wrprot = 1;
+       drv->filetype = ADF_EXT1;
+       drv->num_tracks = 160;
+       drv->num_secs = 11;
+
+       for (i = 0; i < 160; i++) {
+           tid = &drv->trackdata[i];
+           zfile_fread (buffer, 4, 1, drv->diskfile);
+           tid->sync = buffer[0] * 256 + buffer[1];
+           tid->len = buffer[2] * 256 + buffer[3];
+           tid->offs = offs;
+           if (tid->sync == 0) {
+               tid->type = TRACK_AMIGADOS;
+               tid->bitlen = 0;
+           } else {
+               tid->type = TRACK_RAW1;
+               tid->bitlen = tid->len * 8;
+           }
+           offs += tid->len;
+       }
+
+    } else if (memcmp (exeheader, buffer, sizeof(exeheader)) == 0) {
+
+       int i;
+       struct zfile *z = zfile_fopen_empty ("", 512 * 1760);
+       createimagefromexe (drv->diskfile, z);
+       drv->filetype = ADF_NORMAL;
+       zfile_fclose (drv->diskfile);
+       drv->diskfile = z;
+       drv->num_tracks = 160;
+       drv->num_secs = 11;
+       for (i = 0; i < drv->num_tracks; i++) {
+           tid = &drv->trackdata[i];
+           tid->type = TRACK_AMIGADOS;
+           tid->len = 512 * drv->num_secs;
+           tid->bitlen = 0;
+           tid->offs = i * 512 * drv->num_secs;
+       }
+       drv->useturbo = 1;
+    
+    } else {
+       int i;
+
+       drv->filetype = ADF_NORMAL;
+
+       zfile_fseek (drv->diskfile, 0, SEEK_END);
+       i = zfile_ftell (drv->diskfile);
+       zfile_fseek (drv->diskfile, 0, SEEK_SET);
+
+       /* High-density disk? */
+       if (i >= 160 * 22 * 512) {
+           drv->num_tracks = i / (512 * (drv->num_secs = 22));
+           drv->ddhd = 2;
+       } else
+           drv->num_tracks = i / (512 * (drv->num_secs = 11));
+
+       if (drv->num_tracks > MAX_TRACKS)
+           write_log ("Your diskfile is too big!\n");
+       for (i = 0; i < drv->num_tracks; i++) {
+           tid = &drv->trackdata[i];
+           tid->type = TRACK_AMIGADOS;
+           tid->len = 512 * drv->num_secs;
+           tid->bitlen = 0;
+           tid->offs = i * 512 * drv->num_secs;
+       }
+    }
+    openwritefile (drv, 0);
+    drive_settype_id(drv);     /* Set DD or HD drive */
+    drive_fill_bigbuf (drv, 1);
+    drv->mfmpos = (rand () | (rand () << 16)) % drv->tracklen;
+    drv->prevtracklen = 0;
+#ifdef DRIVESOUND    
+    driveclick_insert (drv - floppy, 0);
+#endif
+    return 1;
+}
+
+static void rand_shifter (drive *drv)
+{
+    int r = ((rand () >> 4) & 7) + 1;
+    while (r-- > 0) {
+       word <<= 1;
+       word |= (rand () & 0x1000) ? 1 : 0;
+       bitoffset++;
+       bitoffset &= 15;
+    }
+}
+
+static int drive_empty (drive * drv)
+{
+#ifdef CATWEASEL
+    if (drv->catweasel)
+       return catweasel_disk_changed (drv->catweasel) == 0;
+#endif
+    return drv->diskfile == 0;
+}
+
+static void drive_step (drive * drv)
+{
+#if 0
+    if (drv->dskready) {
+       drv->dskready = 0;
+       drv->dskready_time = DSKREADY_TIME;
+    }
+#endif
+#ifdef CATWEASEL
+    if (drv->catweasel) {
+       int dir = direction ? -1 : 1;
+       catweasel_step (drv->catweasel, dir);
+       drv->cyl += dir;
+       if (drv->cyl < 0)
+           drv->cyl = 0;
+       write_log ("%d -> %d\n", dir, drv->cyl);
+       return;
+    }
+#endif
+    if (drv->steplimit) {
+#ifdef DISK_DEBUG2
+        write_dlog (" step ignored");
+#endif
+       return;
+    }
+    /* A1200's floppy drive needs at least 30 raster lines between steps
+     * but we'll use very small value for better compatibility with faster CPU emulation
+     * (stupid trackloaders with CPU delay loops)
+     */
+    drv->steplimit = 2;
+    if (!drive_empty (drv))
+       drv->dskchange = 0;
+    if (direction) {
+       if (drv->cyl) {
+           drv->cyl--;
+#ifdef DRIVESOUND    
+           driveclick_click (drv - floppy, drv->cyl);
+#endif
+       }
+/*     else
+           write_log("program tried to step beyond track zero\n");
+           "no-click" programs does that
+*/
+  } else {
+       int maxtrack = drv->hard_num_cyls;
+       if (drv->cyl < maxtrack + 3) {
+           drv->cyl++;
+#ifdef CATWEASEL
+           if (drv->catweasel)
+               catweasel_step (drv->catweasel, 1);
+#endif
+       }
+       if (drv->cyl >= maxtrack)
+           write_dlog ("program tried to step over track %d\n", maxtrack);
+#ifdef DRIVESOUND    
+       driveclick_click (drv - floppy, drv->cyl);
+#endif
+    }
+    rand_shifter (drv);
+#ifdef DISK_DEBUG2
+    write_dlog (" ->step %d", drv->cyl);
+#endif
+}
+
+static int drive_track0 (drive * drv)
+{
+#ifdef CATWEASEL
+    if (drv->catweasel)
+       return catweasel_track0 (drv->catweasel);
+#endif
+    return drv->cyl == 0;
+}
+
+static int drive_writeprotected (drive * drv)
+{
+#ifdef CATWEASEL
+    if (drv->catweasel)
+       return 1;
+#endif
+    return drv->wrprot || drv->diskfile == NULL;
+}
+
+static int drive_running (drive * drv)
+{
+    return !drv->motoroff;
+}
+
+static void drive_motor (drive * drv, int off)
+{
+    if (drv->motoroff && !off) {
+       drv->dskready_time = DSKREADY_TIME;
+        rand_shifter (drv);
+#ifdef DRIVESOUND    
+       driveclick_motor (drv - floppy, drv->dskready_down_time == 0 ? 2 : 1);
+#endif
+#ifdef DISK_DEBUG2
+       write_dlog (" ->motor on");
+#endif
+    }
+    if (!drv->motoroff && off) {
+       drv->drive_id_scnt = 0; /* Reset id shift reg counter */
+       drv->dskready_down_time = DSKREADY_DOWN_TIME;
+#ifdef DRIVESOUND    
+       driveclick_motor (drv - floppy, 0);
+#endif
+#ifdef DEBUG_DRIVE_ID
+       write_dlog("drive_motor: Selected DF%d: reset id shift reg.\n",drv-floppy);
+#endif
+#ifdef DISK_DEBUG2
+       write_dlog (" ->motor off");
+#endif
+    }
+    drv->motoroff = off;
+    if (drv->motoroff) {
+       drv->dskready = 0;
+       drv->dskready_time = 0;
+    }
+#ifdef CATWEASEL
+    if (drv->catweasel)
+       catweasel_set_motor (drv->catweasel, !drv->motoroff);
+#endif
+}
+
+static void read_floppy_data (struct zfile *diskfile, trackid *tid, int offset, unsigned char *dst, int len)
+{
+    if (len == 0)
+       return;
+    zfile_fseek (diskfile, tid->offs + offset, SEEK_SET);
+    zfile_fread (dst, 1, len, diskfile);
+}
+
+/* Megalomania does not like zero MFM words... */
+static void mfmcode (uae_u16 * mfm, int words)
+{
+    uae_u32 lastword = 0;
+
+    while (words--) {
+       uae_u32 v = *mfm;
+       uae_u32 lv = (lastword << 16) | v;
+       uae_u32 nlv = 0x55555555 & ~lv;
+       uae_u32 mfmbits = (nlv << 1) & (nlv >> 1);
+
+       *mfm++ = v | mfmbits;
+       lastword = v;
+    }
+}
+
+static void drive_fill_bigbuf (drive * drv, int force)
+{
+    int tr = drv->cyl * 2 + side;
+    trackid *ti = drv->trackdata + tr;
+
+    if ((!drv->diskfile && !drv->catweasel) || tr >= drv->num_tracks) {
+       track_reset (drv);
+       return;
+    }
+
+    if (!force && drv->catweasel) {
+       drv->buffered_cyl = -1;
+       return;
+    }
+
+    if (!force && drv->buffered_cyl == drv->cyl && drv->buffered_side == side)
+       return;
+    drv->revolutions = 0;
+    drv->indexoffset = 0;
+    free (drv->tracktiming);
+    drv->tracktiming = 0;
+
+    if (drv->writediskfile && drv->writetrackdata[tr].bitlen > 0) {
+       int i;
+       trackid *wti = &drv->writetrackdata[tr];
+       drv->tracklen = wti->bitlen;
+       read_floppy_data (drv->writediskfile, wti, 0, (char *) drv->bigmfmbuf, (wti->bitlen + 7) / 8);
+       for (i = 0; i < (drv->tracklen + 15) / 16; i++) {
+           uae_u16 *mfm = drv->bigmfmbuf + i;
+           uae_u8 *data = (uae_u8 *) mfm;
+           *mfm = 256 * *data + *(data + 1);
+       }
+#ifdef DISK_DEBUG
+       write_log ("track %d, length %d read from \"saveimage\"\n", tr, drv->tracklen);
+#endif
+    } else if (drv->filetype == ADF_CATWEASEL) {
+#ifdef CATWEASEL
+       drv->tracklen = 0;
+       if (!catweasel_disk_changed (drv->catweasel)) {
+           drv->tracklen = catweasel_fillmfm (drv->catweasel, drv->bigmfmbuf, side, drv->ddhd, 0);
+       }
+       drv->buffered_cyl = -1;
+       if (!drv->tracklen) {
+           track_reset (drv);
+           return;
+       }
+#endif 
+    } else if (drv->filetype == ADF_IPF) {
+
+#ifdef CAPS
+       caps_loadtrack (drv->bigmfmbuf, drv->trackpointers, &drv->tracktiming, drv - floppy, tr, drv->tracklengths, &drv->revolutions);
+       drv->tracklen = drv->tracklengths[0];
+#endif
+
+    } else if (drv->filetype == ADF_FDI) {
+
+       fdi2raw_loadtrack (drv->fdi, drv->bigmfmbuf, drv->trackpointers, &drv->tracktiming, tr, drv->tracklengths, &drv->revolutions, &drv->indexoffset);
+       drv->tracklen = drv->tracklengths[0];
+
+    } else if (ti->type == TRACK_AMIGADOS) {
+
+       /* Normal AmigaDOS format track */
+       int sec;
+       int dstmfmoffset = 0;
+        uae_u16 *dstmfmbuf = drv->bigmfmbuf;
+        int len = drv->num_secs * 544 + FLOPPY_GAP_LEN;
+
+       memset (dstmfmbuf, 0xaa, len * 2);
+       dstmfmoffset += FLOPPY_GAP_LEN;
+       drv->tracklen = len * 2 * 8;
+
+       for (sec = 0; sec < drv->num_secs; sec++) {
+           uae_u8 secbuf[544];
+           uae_u16 mfmbuf[544];
+           int i;
+           uae_u32 deven, dodd;
+           uae_u32 hck = 0, dck = 0;
+
+           secbuf[0] = secbuf[1] = 0x00;
+           secbuf[2] = secbuf[3] = 0xa1;
+           secbuf[4] = 0xff;
+           secbuf[5] = tr;
+           secbuf[6] = sec;
+           secbuf[7] = drv->num_secs - sec;
+
+           for (i = 8; i < 24; i++)
+               secbuf[i] = 0;
+
+           read_floppy_data (drv->diskfile, ti, sec * 512, &secbuf[32], 512);
+
+           mfmbuf[0] = mfmbuf[1] = 0xaaaa;
+           mfmbuf[2] = mfmbuf[3] = 0x4489;
+
+           deven = ((secbuf[4] << 24) | (secbuf[5] << 16)
+                    | (secbuf[6] << 8) | (secbuf[7]));
+           dodd = deven >> 1;
+           deven &= 0x55555555;
+           dodd &= 0x55555555;
+
+           mfmbuf[4] = dodd >> 16;
+           mfmbuf[5] = dodd;
+           mfmbuf[6] = deven >> 16;
+           mfmbuf[7] = deven;
+
+           for (i = 8; i < 48; i++)
+               mfmbuf[i] = 0xaaaa;
+           for (i = 0; i < 512; i += 4) {
+               deven = ((secbuf[i + 32] << 24) | (secbuf[i + 33] << 16)
+                        | (secbuf[i + 34] << 8) | (secbuf[i + 35]));
+               dodd = deven >> 1;
+               deven &= 0x55555555;
+               dodd &= 0x55555555;
+               mfmbuf[(i >> 1) + 32] = dodd >> 16;
+               mfmbuf[(i >> 1) + 33] = dodd;
+               mfmbuf[(i >> 1) + 256 + 32] = deven >> 16;
+               mfmbuf[(i >> 1) + 256 + 33] = deven;
+           }
+
+           for (i = 4; i < 24; i += 2)
+               hck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1];
+
+           deven = dodd = hck;
+           dodd >>= 1;
+           mfmbuf[24] = dodd >> 16;
+           mfmbuf[25] = dodd;
+           mfmbuf[26] = deven >> 16;
+           mfmbuf[27] = deven;
+
+           for (i = 32; i < 544; i += 2)
+               dck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1];
+
+           deven = dodd = dck;
+           dodd >>= 1;
+           mfmbuf[28] = dodd >> 16;
+           mfmbuf[29] = dodd;
+           mfmbuf[30] = deven >> 16;
+           mfmbuf[31] = deven;
+           mfmcode (mfmbuf + 4, 544 - 4);
+
+           for (i = 0; i < 544; i++) {
+               dstmfmbuf[dstmfmoffset % len] = mfmbuf[i];
+               dstmfmoffset++;
+           }
+        
+        }
+
+#ifdef DISK_DEBUG
+       write_log ("amigados read track %d\n", tr);
+#endif
+    } else {
+       int i;
+       int base_offset = ti->type == TRACK_RAW ? 0 : 1;
+       drv->tracklen = ti->bitlen + 16 * base_offset;
+       drv->bigmfmbuf[0] = ti->sync;
+       read_floppy_data (drv->diskfile, ti, 0, (char *) (drv->bigmfmbuf + base_offset), (ti->bitlen + 7) / 8);
+       for (i = base_offset; i < (drv->tracklen + 15) / 16; i++) {
+           uae_u16 *mfm = drv->bigmfmbuf + i;
+           uae_u8 *data = (uae_u8 *) mfm;
+           *mfm = 256 * *data + *(data + 1);
+       }
+#if 0 && defined DISK_DEBUG
+       write_log ("rawtrack %d\n", tr);
+#endif
+    }
+    drv->current_revolution = 0;
+    drv->tracklengths[0] = drv->tracklen;
+    drv->trackpointers[0] = drv->bigmfmbuf;
+    drv->buffered_side = side;
+    drv->buffered_cyl = drv->cyl;
+    if (drv->tracklen == 0) {
+       drv->tracklengths[0] = drv->tracklen = FLOPPY_WRITE_LEN * drv->ddhd * 2 * 8;
+       memset (drv->bigmfmbuf, 0, FLOPPY_WRITE_LEN * 2 * drv->ddhd);
+    }
+    drv->trackspeed = get_floppy_speed () * drv->tracklen / (2 * 8 * FLOPPY_WRITE_LEN * drv->ddhd);
+    updatemfmpos (drv);
+}
+
+/* Update ADF_EXT2 track header */
+static void diskfile_update (struct zfile *diskfile, trackid *ti, int len, uae_u8 type)
+{
+    uae_u8 buf[2 + 2 + 4 + 4], *zerobuf;
+
+    ti->bitlen = len;
+    zfile_fseek (diskfile, 8 + 4 + (2 + 2 + 4 + 4) * ti->track, SEEK_SET);
+    memset (buf, 0, sizeof buf);
+    ti->type = type;
+    buf[3] = ti->type;
+    do_put_mem_long ((uae_u32 *) (buf + 4), ti->len);
+    do_put_mem_long ((uae_u32 *) (buf + 8), ti->bitlen);
+    zfile_fwrite (buf, sizeof (buf), 1, diskfile);
+    if (ti->len > (len + 7) / 8) {
+       zerobuf = malloc (ti->len);
+       memset (zerobuf, 0, ti->len);
+       zfile_fseek (diskfile, ti->offs, SEEK_SET);
+       zfile_fwrite (zerobuf, 1, ti->len, diskfile);
+       free (zerobuf);
+    }
+#ifdef DISK_DEBUG
+    write_log ("track %d, raw track length %d written (total size %d)\n", ti->track, (ti->bitlen + 7) / 8, ti->len);
+#endif
+}
+
+#define MFMMASK 0x55555555
+static uae_u32 getmfmlong (uae_u16 * mbuf)
+{
+    return ((*mbuf << 16) | *(mbuf + 1)) & MFMMASK;
+}
+
+static int drive_write_adf_amigados (drive * drv)
+{
+    int i, secwritten = 0;
+    int fwlen = FLOPPY_WRITE_LEN * drv->ddhd;
+    int length = 2 * fwlen;
+    int drvsec = drv->num_secs;
+    uae_u32 odd, even, chksum, id, dlong;
+    uae_u8 *secdata;
+    uae_u8 secbuf[544];
+    uae_u16 *mbuf = drv->bigmfmbuf;
+    uae_u16 *mend = mbuf + length;
+    char sectable[22];
+
+    if (!drvsec)
+       return 2;
+    memset (sectable, 0, sizeof (sectable));
+    memcpy (mbuf + fwlen, mbuf, fwlen * sizeof (uae_u16));
+    mend -= (4 + 16 + 8 + 512);
+    while (secwritten < drvsec) {
+       int trackoffs;
+
+       do {
+           while (*mbuf++ != 0x4489) {
+               if (mbuf >= mend)
+                   return 1;
+           }
+       } while (*mbuf++ != 0x4489);
+
+       odd = getmfmlong (mbuf);
+       even = getmfmlong (mbuf + 2);
+       mbuf += 4;
+       id = (odd << 1) | even;
+
+       trackoffs = (id & 0xff00) >> 8;
+       if (trackoffs + 1 > drvsec) {
+           write_log ("Disk write: weird sector number %d\n", trackoffs);
+           if (drv->filetype == ADF_EXT2)
+               return 2;
+           continue;
+       }
+       chksum = odd ^ even;
+       for (i = 0; i < 4; i++) {
+           odd = getmfmlong (mbuf);
+           even = getmfmlong (mbuf + 8);
+           mbuf += 2;
+
+           dlong = (odd << 1) | even;
+           if (dlong) {
+               if (drv->filetype == ADF_EXT2)
+                   return 6;
+               secwritten = -200;
+           }
+           chksum ^= odd ^ even;
+       }                       /* could check here if the label is nonstandard */
+       mbuf += 8;
+       odd = getmfmlong (mbuf);
+       even = getmfmlong (mbuf + 2);
+       mbuf += 4;
+       if (((odd << 1) | even) != chksum || ((id & 0x00ff0000) >> 16) != drv->cyl * 2 + side) {
+           write_log ("Disk write: checksum error on sector %d header\n", trackoffs);
+           if (drv->filetype == ADF_EXT2)
+               return 3;
+           continue;
+       }
+       odd = getmfmlong (mbuf);
+       even = getmfmlong (mbuf + 2);
+       mbuf += 4;
+       chksum = (odd << 1) | even;
+       secdata = secbuf + 32;
+       for (i = 0; i < 128; i++) {
+           odd = getmfmlong (mbuf);
+           even = getmfmlong (mbuf + 256);
+           mbuf += 2;
+           dlong = (odd << 1) | even;
+           *secdata++ = dlong >> 24;
+           *secdata++ = dlong >> 16;
+           *secdata++ = dlong >> 8;
+           *secdata++ = dlong;
+           chksum ^= odd ^ even;
+       }
+       mbuf += 256;
+       if (chksum) {
+           write_log ("Disk write: sector %d, data checksum error\n", trackoffs);
+           if (drv->filetype == ADF_EXT2)
+               return 4;
+           continue;
+       }
+       sectable[trackoffs] = 1;
+       secwritten++;
+       memcpy (writebuffer + trackoffs * 512, secbuf + 32, 512);
+    }
+    if (drv->filetype == ADF_EXT2 && (secwritten == 0 || secwritten < 0))
+       return 5;
+    if (secwritten == 0)
+       write_log ("Disk write in unsupported format\n");
+    if (secwritten < 0)
+       write_log ("Disk write: sector labels ignored\n");
+
+    if (drv->filetype == ADF_EXT2)
+       diskfile_update (drv->diskfile, &drv->trackdata[drv->cyl * 2 + side], drvsec * 512 * 8, TRACK_AMIGADOS);
+    for (i = 0; i < drvsec; i++) {
+       zfile_fseek (drv->diskfile, drv->trackdata[drv->cyl * 2 + side].offs + i * 512, SEEK_SET);
+       zfile_fwrite (writebuffer + i * 512, sizeof (uae_u8), 512, drv->diskfile);
+    }
+
+    return 0;
+}
+
+/* write raw track to disk file */
+static int drive_write_ext2 (uae_u16 *bigmfmbuf, struct zfile *diskfile, trackid *ti, int tracklen)
+{
+    int len, i;
+
+    len = (tracklen + 7) / 8;
+    if (len > ti->len) {
+       write_log ("disk raw write: image file's track %d is too small (%d < %d)!\n", ti->track, ti->len, len);
+       return 0;
+    }
+    diskfile_update (diskfile, ti, tracklen, TRACK_RAW);
+    for (i = 0; i < ti->len / 2; i++) {
+       uae_u16 *mfm = bigmfmbuf + i;
+       uae_u16 *mfmw = bigmfmbufw + i;
+       uae_u8 *data = (uae_u8 *) mfm;
+       *mfmw = 256 * *data + *(data + 1);
+    }
+    zfile_fseek (diskfile, ti->offs, SEEK_SET);
+    zfile_fwrite (bigmfmbufw, 1, len, diskfile);
+    return 1;
+}
+
+static void drive_write_data (drive * drv)
+{
+    int ret;
+    if (drive_writeprotected (drv)) {
+       /* read original track back because we didn't really write anything */
+       drv->buffered_side = 2;
+       return;
+    }
+    if (drv->writediskfile)
+       drive_write_ext2 (drv->bigmfmbuf, drv->writediskfile, &drv->writetrackdata[drv->cyl * 2 + side], drv->tracklen);
+
+    switch (drv->filetype) {
+    case ADF_NORMAL:
+       drive_write_adf_amigados (drv);
+       return;
+    case ADF_EXT1:
+       break;
+    case ADF_EXT2:
+       ret = drive_write_adf_amigados (drv);
+       if (ret) {
+           write_log("not an amigados track (error %d), writing as raw track\n",ret);
+           drive_write_ext2 (drv->bigmfmbuf, drv->diskfile, &drv->trackdata[drv->cyl * 2 + side], drv->tracklen);
+       }
+       return;
+    case ADF_IPF:
+       break;
+    }
+    free (drv->tracktiming);
+    drv->tracktiming = 0;
+}
+
+static void drive_eject (drive * drv)
+{
+#ifdef DRIVESOUND    
+    driveclick_insert (drv - floppy, 1);
+#endif
+    drive_image_free (drv);
+    drv->dskchange = 1;
+    drv->ddhd = 1;
+    drv->dskchange_time = 0;
+    drv->dskready = 0;
+    drv->dskready_time = 0;
+    drv->dskready_down_time = 0;
+    drive_settype_id(drv); /* Back to 35 DD */
+#ifdef DISK_DEBUG
+    write_dlog ("eject drive %d\n", drv - &floppy[0]);
+#endif
+}
+
+/* We use this function if we have no Kickstart ROM.
+ * No error checking - we trust our luck. */
+void DISK_ersatz_read (int tr, int sec, uaecptr dest)
+{
+    uae_u8 *dptr = get_real_address (dest);
+    zfile_fseek (floppy[0].diskfile, floppy[0].trackdata[tr].offs + sec * 512, SEEK_SET);
+    zfile_fread (dptr, 1, 512, floppy[0].diskfile);
+}
+
+/* type: 0=regular, 1=ext2adf */
+/* adftype: 0=DD,1=HD,2=525SD */
+void disk_creatediskfile (char *name, int type, drive_type adftype)
+{
+    struct zfile *f;
+    int i, l, file_size, tracks, track_len;
+    char *chunk = NULL;
+    uae_u8 tmp[3*4];
+    char *disk_name = "empty";
+
+    if (type == 1) tracks = 2 * 83; else tracks = 2 * 80;
+    file_size = 880 * 1024;
+    track_len = FLOPPY_WRITE_LEN * 2;
+    if (adftype == 1) {
+       file_size *= 2;
+       track_len *= 2;
+    } else if (adftype == 2) {
+       file_size /= 2;
+       tracks /= 2;
+    }
+
+    f = zfile_fopen (name, "wb");
+    chunk = xmalloc (16384);
+    if (f && chunk) {
+       memset(chunk,0,16384);
+       switch(type)
+           {
+           case 0:
+           for (i = 0; i < file_size; i += 11264) {
+               memset(chunk, 0, 11264);
+               if (i == 0) {
+                   /* boot block */
+                   strcpy (chunk, "DOS");
+               } else if (i == file_size / 2) {
+                   int block = file_size / 1024;
+                   /* root block */
+                   chunk[0+3] = 2;
+                   chunk[12+3] = 0x48;
+                   chunk[312] = chunk[313] = chunk[314] = chunk[315] = (uae_u8)0xff;
+                   chunk[316+2] = (block + 1) >> 8; chunk[316+3] = (block + 1) & 255;
+                   chunk[432] = strlen (disk_name);
+                   strcpy (chunk + 433, disk_name);
+                   chunk[508 + 3] = 1;
+                   disk_date (chunk + 420);
+                   memcpy (chunk + 472, chunk + 420, 3 * 4);
+                   memcpy (chunk + 484, chunk + 420, 3 * 4);
+                   disk_checksum(chunk, chunk + 20);
+                   /* bitmap block */
+                   memset (chunk + 512 + 4, 0xff, 220);
+                   chunk[512 + 112 + 2] = 0x3f;
+                   disk_checksum(chunk + 512, chunk + 512);
+
+               }
+               zfile_fwrite (chunk, 11264, 1, f);
+           }
+           break;
+           case 1:
+           l = track_len;
+           zfile_fwrite ("UAE-1ADF", 8, 1, f);
+           tmp[0] = 0; tmp[1] = 0; /* flags (reserved) */
+           tmp[2] = 0; tmp[3] = tracks; /* number of tracks */
+           zfile_fwrite (tmp, 4, 1, f);
+           tmp[0] = 0; tmp[1] = 0; /* flags (reserved) */
+           tmp[2] = 0; tmp[3] = 1; /* track type */
+           tmp[4] = 0; tmp[5] = 0; tmp[6]=(uae_u8)(l >> 8); tmp[7] = (uae_u8)l;
+           tmp[8] = 0; tmp[9] = 0; tmp[10] = 0; tmp[11] = 0;
+           for (i = 0; i < tracks; i++) zfile_fwrite (tmp, sizeof (tmp), 1, f);
+           for (i = 0; i < tracks; i++) zfile_fwrite (chunk, l, 1, f);
+           break;
+       }
+    }
+    free (chunk);
+    zfile_fclose (f);
+}
+
+int disk_getwriteprotect (const char *name)
+{
+    int needwritefile;
+    drive_type drvtype;
+    return diskfile_iswriteprotect (name, &needwritefile, &drvtype);
+}
+
+static void diskfile_readonly (const char *name, int readonly)
+{
+    struct stat st;
+    int mode, oldmode;
+    
+    if (stat (name, &st))
+       return;
+    oldmode = mode = st.st_mode;
+    mode &= ~FILEFLAG_WRITE;
+    if (!readonly) mode |= FILEFLAG_WRITE;
+    if (mode != oldmode)
+       chmod (name, mode);
+}
+
+static void setdskchangetime(drive *drv, int dsktime)
+{
+    int i;
+    /* prevent multiple disk insertions at the same time */
+    if (drv->dskchange_time > 0)
+       return;
+    for (i = 0; i < 4; i++) {
+       if (&floppy[i] != drv && floppy[i].dskchange_time > 0 && floppy[i].dskchange_time + 5 >= dsktime) {
+           dsktime = floppy[i].dskchange_time + 5;
+       }
+    }
+    drv->dskchange_time = dsktime;
+}
+
+int disk_setwriteprotect (int num, const char *name, int protect)
+{
+    int needwritefile, oldprotect;
+    struct zfile *zf1, *zf2;
+    int wrprot1, wrprot2, i;
+    char *name2;
+    drive_type drvtype;
+    oldprotect = diskfile_iswriteprotect (name, &needwritefile, &drvtype);
+    zf1 = DISK_validate_filename (name, 1, &wrprot1);
+    if (!zf1) return 0;
+    if (zfile_iscompressed (zf1)) wrprot1 = 1;
+    zf2 = getwritefile (name, &wrprot2);
+    name2 = getwritefilename (name);
+
+    if (needwritefile && zf2 == 0)
+       disk_creatediskfile (name2, 1, drvtype);
+    zfile_fclose (zf2);
+    if (protect && iswritefileempty (name)) {
+       for (i = 0; i < 4; i++) {
+           if (!strcmp (name, floppy[i].newname))
+               drive_eject (&floppy[i]);
+       }
+       unlink (name2);
+    }
+
+    if (!needwritefile)
+        diskfile_readonly (name, protect);
+    diskfile_readonly (name2, protect);
+    drive_eject (&floppy[num]);
+    setdskchangetime (&floppy[num], 20);
+    return 1;
+}
+
+void disk_eject (int num)
+{
+    gui_filename (num, "");
+    drive_eject (floppy + num);
+    *currprefs.df[num] = *changed_prefs.df[num] = 0;
+    floppy[num].newname[0] = 0;
+}
+
+void DISK_history_add (const char *name, int idx)
+{
+    int i;
+
+    if (idx >= 0) {
+       if (idx >= MAX_PREVIOUS_FLOPPIES)
+           return;
+       strcpy (dfxhistory[idx], name);
+       return;
+    }
+    if (name[0] == 0)
+       return;
+    for (i = 0; i < MAX_PREVIOUS_FLOPPIES; i++) {
+       if (!strcmp (dfxhistory[i], name)) {
+           while (i < MAX_PREVIOUS_FLOPPIES - 1) {
+               strcpy (dfxhistory[i], dfxhistory[i + 1]);
+               i++;
+           }
+           dfxhistory[MAX_PREVIOUS_FLOPPIES - 1][0] = 0;
+           break;
+       }
+    }
+    for (i = MAX_PREVIOUS_FLOPPIES - 2; i >= 0; i--)
+       strcpy (dfxhistory[i + 1], dfxhistory[i]);
+    strcpy (dfxhistory[0], name);
+}
+
+char *DISK_history_get (int idx)
+{
+    if (idx >= MAX_PREVIOUS_FLOPPIES)
+       return 0;
+    if (dfxhistory[idx][0] == 0)
+       return 0;
+    return dfxhistory[idx];
+}
+
+void disk_insert (int num, const char *name)
+{
+    drive *drv = floppy + num;
+    strcpy (drv->newname, name);
+    strcpy (currprefs.df[num], name);
+    DISK_history_add (name, -1);
+    if (name[0] == 0) {
+       disk_eject (num);
+    } else if (!drive_empty(drv) || drv->dskchange_time > 0) {
+       drive_eject (drv);
+       /* set dskchange_time, disk_insert() will be
+        * called from DISK_check_change() after 2 second delay
+        * this makes sure that all programs detect disk change correctly
+        */
+       setdskchangetime (drv, 20);
+    } else {
+       setdskchangetime (drv, 1);
+    }
+}
+
+void DISK_check_change (void)
+{
+    int i;
+
+    if (currprefs.floppy_speed != changed_prefs.floppy_speed)
+       currprefs.floppy_speed = changed_prefs.floppy_speed;
+    for (i = 0; i < 4; i++) {
+       drive *drv = floppy + i;
+       gui_lock ();
+       if (currprefs.dfxtype[i] != changed_prefs.dfxtype[i]) {
+           currprefs.dfxtype[i] = changed_prefs.dfxtype[i];
+           reset_drive (i);
+       }
+       if (strcmp (currprefs.df[i], changed_prefs.df[i])) {
+           strcpy (currprefs.df[i], changed_prefs.df[i]);
+           disk_insert (i, currprefs.df[i]);
+       }
+       gui_unlock ();
+       if (drv->dskready_down_time > 0)
+           drv->dskready_down_time--;
+#if 1
+       /* emulate drive motor turn on time */
+       if (drv->dskready_time) {
+           drv->dskready_time--;
+           if (drv->dskready_time == 0)
+               drv->dskready = 1;
+       }
+#endif
+       /* delay until new disk image is inserted */
+       if (drv->dskchange_time) {
+           drv->dskchange_time--;
+           if (drv->dskchange_time == 0) {
+               drive_insert (drv, i, drv->newname);
+#ifdef DISK_DEBUG
+               write_dlog ("delayed insert, drive %d, image '%s'\n", i, drv->newname);
+#endif
+           }
+       }
+    }
+}
+
+int disk_empty (int num)
+{
+    return drive_empty (floppy + num);
+}
+
+#ifdef DISK_DEBUG2
+static char *tobin(uae_u8 v)
+{
+    int i;
+    static char buf[10];
+    for( i = 7; i >= 0; i--)
+       buf[7 - i] = v & (1 << i) ? '1' : '0';
+    buf[i] = 0;
+    return buf;
+}
+#endif
+
+void DISK_select (uae_u8 data)
+{
+    int step_pulse, lastselected, dr;
+    static uae_u8 prevdata;
+    static int step;
+
+#ifdef DISK_DEBUG2
+    write_dlog ("%08.8X %02.2X %s", m68k_getpc(), data, tobin(data));
+#endif
+    lastselected = selected;
+    selected = (data >> 3) & 15;
+    side = 1 - ((data >> 2) & 1);
+    direction = (data >> 1) & 1;
+    step_pulse = data & 1;
+
+#ifdef DISK_DEBUG2
+    write_dlog (" %d%d%d%d% ", (selected & 1) ? 0 : 1, (selected & 2) ? 0 : 1, (selected & 4) ? 0 : 1, (selected & 8) ? 0 : 1);
+    if ((prevdata & 0x80) != (data & 0x80))
+       write_dlog (" dskmotor %d ", (data & 0x80) ? 1 : 0);
+    if ((prevdata & 0x02) != (data & 0x02))
+       write_dlog (" direct %d ", (data & 0x02) ? 1 : 0);
+    if ((prevdata & 0x04) != (data & 0x04))
+       write_dlog (" side %d ", (data & 0x04) ? 1 : 0);
+#endif
+
+    selected |= disabled;
+
+    if (step != step_pulse) {
+#ifdef DISK_DEBUG2
+       write_dlog (" dskstep %d ", step_pulse);
+#endif
+       step = step_pulse;
+       if (step && !savestate_state) {
+           for (dr = 0; dr < 4; dr++) {
+               if (!(selected & (1 << dr))) {
+                   drive_step (floppy + dr);
+               }
+           }
+       }
+    }
+    if (!savestate_state) {
+       for (dr = 0; dr < 4; dr++) {
+           drive *drv = floppy + dr;
+           /* motor on/off workings tested with small assembler code on real Amiga 1200. */
+           /* motor/id flipflop is set only when drive select goes from high to low */ 
+           if (!(selected & (1 << dr)) && (lastselected & (1 << dr)) ) {
+               drv->drive_id_scnt++;
+               drv->drive_id_scnt &= 31;
+               drv->idbit = (drv->drive_id & (1L << (31 - drv->drive_id_scnt))) ? 1 : 0;
+               if ((prevdata & 0x80) == 0 || (data & 0x80) == 0) {
+                   /* motor off: if motor bit = 0 in prevdata or data -> turn motor on */
+                   drive_motor (drv, 0);
+               } else if (prevdata & 0x80) {
+                   /* motor on: if motor bit = 1 in prevdata only (motor flag state in data has no effect)
+                       -> turn motor off */
+                   drive_motor (drv, 1);
+               }
+               if (currprefs.dfxtype[dr] == DRV_35_DD) {
+                   if (dr == 0) /* A500/A2000 internal drive always returns 0 */
+                       drv->idbit = 0;
+                   else /* regular external DD drive always returns 1 */
+                       drv->idbit = 1;
+               }
+#ifdef DEBUG_DRIVE_ID
+               write_dlog("DISK_status: sel %d id %s (%08.8X) [0x%08lx, bit #%02d: %d]\n",
+                   dr, drive_id_name(drv), drv->drive_id, drv->drive_id << drv->drive_id_scnt, 31 - drv->drive_id_scnt, drv->idbit);
+#endif
+           }
+       }
+    }
+    for (dr = 0; dr < 4; dr++) {
+       floppy[dr].state = (!(selected & (1 << dr))) | !floppy[dr].motoroff;
+       update_drive_gui (dr);
+    }
+    prevdata = data;
+#ifdef DISK_DEBUG2
+    write_log ("\n");
+#endif
+}
+
+uae_u8 DISK_status (void)
+{
+    uae_u8 st = 0x3c;
+    int dr;
+
+    for (dr = 0; dr < 4; dr++) {
+       drive *drv = floppy + dr;
+       if (!(selected & (1 << dr))) {
+           if (drive_running (drv)) {
+               if (drv->catweasel) {
+#ifdef CATWEASEL
+                   if (catweasel_diskready (drv->catweasel))
+                       st &= ~0x20;
+#endif
+               } else {
+                   if (drv->dskready)
+                       st &= ~0x20;
+               }
+           } else {
+               /* report drive ID */
+               if (drv->idbit)
+                   st &= ~0x20;
+#if 0
+               if (dr == 0 && currprefs.dfxtype[dr] == DRV_35_DD &&
+                   drv->motoroff && drv->motorcycle + CYCLE_UNIT * 1 > get_cycles())
+                   st &= ~0x20, write_log("x %d\n", get_cycles());
+#endif
+           }
+           if (drive_track0 (drv))
+               st &= ~0x10;
+           if (drive_writeprotected (drv))
+               st &= ~8;
+           if (drv->catweasel) {
+#ifdef CATWEASEL
+               if (catweasel_disk_changed (drv->catweasel))
+                   st &= ~4;
+#endif
+           } else if (drv->dskchange && currprefs.dfxtype[dr] != DRV_525_SD) {
+               st &= ~4;
+           }
+       } 
+    }
+    return st;
+}
+
+static int unformatted (drive *drv)
+{
+    int tr = drv->cyl * 2 + side;
+    if (tr >= drv->num_tracks)
+       return 1;
+    if (drv->filetype == ADF_EXT2 && drv->trackdata[tr].bitlen == 0)
+       return 1;
+    return 0;
+}
+
+/* get one bit from MFM bit stream */
+STATIC_INLINE uae_u32 getonebit (uae_u16 * mfmbuf, int mfmpos)
+{
+    uae_u16 *buf;
+
+    buf = &mfmbuf[mfmpos >> 4];
+    return (buf[0] & (1 << (15 - (mfmpos & 15)))) ? 1 : 0;
+}
+
+void dumpdisk (void)
+{
+    int i, j, k;
+    uae_u16 w;
+
+    for (i = 0; i < 4; i++) {
+       drive *drv = &floppy[i];
+       if (!(disabled & (1 << i))) {
+           write_log ("Drive %d: motor %s cylinder %2d sel %s %s mfmpos %d/%d\n",
+               i, drv->motoroff ? "off" : " on", drv->cyl, (selected & (1 << i)) ? "no" : "yes",
+               drive_writeprotected(drv) ? "ro" : "rw", drv->mfmpos, drv->tracklen);
+           w = word;
+           for (j = 0; j < 15; j++) {
+               write_log ("%04.4X ", w);
+               for (k = 0; k < 16; k++) {
+                   w <<= 1;
+                   w |= getonebit (drv->bigmfmbuf, drv->mfmpos + j * 16 + k);
+               }
+           }
+           write_log ("\n");
+       }
+    }
+    write_log ("side %d, dma %d, bitoffset %d, word %04.4X, dskbytr %04.4X adkcon %04.4X dsksync %04.4X\n", side, dskdmaen, bitoffset, word, dskbytr_val, adkcon, dsksync);
+}
+
+static void disk_dmafinished (void)
+{
+    INTREQ (0x8002);
+    dskdmaen = 0;
+#ifdef DISK_DEBUG
+    write_dlog("disk dma finished %08.8X\n", dskpt);
+#endif
+}    
+
+extern void cia_diskindex (void);
+
+static int diskevent_flag;
+static int disk_sync_cycle;
+
+void DISK_handler (void)
+{
+    int i, flag = diskevent_flag;
+    eventtab[ev_disk].active = 0;
+    DISK_update (disk_sync_cycle);
+    if (flag & DISK_WORDSYNC) {
+       INTREQ (0x8000 | 0x1000);
+    }
+    if (flag & DISK_INDEXSYNC) {
+       cia_diskindex ();
+#if 0
+       for (i = 0; i < 4; i++) {
+           drive *drv = &floppy[i];
+           if (drv->dskready_time) {
+               drv->dskready_time--;
+               if (drv->dskready_time == 0) {
+                   drv->dskready = 1;
+#ifdef DISK_DEBUG
+                   write_log ("%d: %d\n", i, drv->mfmpos);
+#endif
+               }
+           }
+       }
+#endif
+    }
+}
+
+static void disk_doupdate_write (drive * drv, int floppybits)
+{
+    int dr;
+    int drives[4];
+    
+    for (dr = 0; dr < 4 ; dr++) {
+        drive *drv2 = &floppy[dr];
+        drives[dr] = 0;
+        if (drv2->motoroff)
+           continue;
+        if (selected & (1 << dr))
+           continue;
+       drives[dr] = 1;
+    }
+
+    while (floppybits >= drv->trackspeed) {
+       for (dr = 0; dr < 4; dr++) {
+           if (drives[dr]) {
+               floppy[dr].mfmpos++;
+               floppy[dr].mfmpos %= drv->tracklen;
+           }
+       }
+       if ((dmacon & 0x210) == 0x210 && dskdmaen == 3 && dsklength > 0) {
+           bitoffset++;
+           bitoffset &= 15;
+           if (!bitoffset) {
+               for (dr = 0; dr < 4 ; dr++) {
+                   drive *drv2 = &floppy[dr];
+                   if (drives[dr])
+                       drv2->bigmfmbuf[drv2->mfmpos >> 4] = get_word (dskpt);
+               }
+               dskpt += 2;
+               dsklength--;
+               if (dsklength == 0) {
+                   disk_dmafinished ();
+                   drive_write_data (drv);
+               }
+           }
+       }
+       floppybits -= drv->trackspeed;
+    }
+}
+
+static void updatetrackspeed (drive *drv, int mfmpos)
+{
+    if (dskdmaen < 3) {
+       uae_u16 *p = drv->trackpointers[drv->current_revolution] - drv->trackpointers[0] + drv->tracktiming;
+       p += mfmpos / 8;
+       drv->trackspeed = get_floppy_speed () * drv->tracklen / (2 * 8 * FLOPPY_WRITE_LEN * drv->ddhd);
+       drv->trackspeed = drv->trackspeed * p[0] / 1000;
+       if (drv->trackspeed < 700 || drv->trackspeed > 3000) {
+           write_log ("corrupted trackspeed value %d\n", drv->trackspeed);
+           assert (0);
+       }
+    }
+}
+
+static void disk_doupdate_predict (drive * drv, int startcycle)
+{
+    int is_sync = 0;
+    int firstcycle = startcycle;
+    uae_u32 tword = word;
+    int mfmpos = drv->mfmpos;
+
+    diskevent_flag = 0;
+    while (startcycle < (maxhpos << 8) && !diskevent_flag) {
+       int cycle = startcycle >> 8;
+       if (drv->tracktiming)
+           updatetrackspeed (drv, mfmpos);
+       if (dskdmaen != 3) {
+           tword <<= 1;
+           if (unformatted (drv))
+               tword |= (rand() & 0x1000) ? 1 : 0;
+           else
+               tword |= getonebit (drv->trackpointers[drv->current_revolution], mfmpos);
+           if ((tword & 0xffff) == dsksync)
+               diskevent_flag |= DISK_WORDSYNC;
+       }
+       mfmpos++;
+       mfmpos %= drv->tracklen;
+       if (mfmpos == drv->indexoffset)
+           diskevent_flag |= DISK_INDEXSYNC;
+       startcycle += drv->trackspeed;
+    }
+    if (drv->tracktiming)
+        updatetrackspeed (drv, drv->mfmpos);
+    if (diskevent_flag) {
+       disk_sync_cycle = startcycle >> 8;
+        eventtab[ev_disk].oldcycles = get_cycles ();
+        eventtab[ev_disk].evtime = get_cycles () + startcycle - firstcycle;
+       eventtab[ev_disk].active = 1;
+       events_schedule ();
+    }
+}
+
+#ifdef CPUEMU_6
+extern uae_u8 cycle_line[256];
+#endif
+
+static void disk_doupdate_read (drive * drv, int floppybits)
+{
+    int j = 0, k = 1, l = 0;
+
+/*
+    uae_u16 *mfmbuf = drv->bigmfmbuf;
+    dsksync = 0x4444;
+    adkcon |= 0x400;
+    drv->mfmpos = 0;
+    memset (mfmbuf, 0, 1000);
+    cycles = 0x1000000;
+    // 4444 4444 4444 aaaa aaaaa 4444 4444 4444
+    // 4444 aaaa aaaa 4444
+    mfmbuf[0] = 0x4444;
+    mfmbuf[1] = 0x4444;
+    mfmbuf[2] = 0x4444;
+    mfmbuf[3] = 0xaaaa;
+    mfmbuf[4] = 0xaaaa;
+    mfmbuf[5] = 0x4444;
+    mfmbuf[6] = 0x4444;
+    mfmbuf[7] = 0x4444;
+*/
+    while (floppybits >= drv->trackspeed) {
+        if (drv->tracktiming)
+           updatetrackspeed (drv, drv->mfmpos);
+       word <<= 1;
+        if (unformatted (drv))
+           word |= (rand() & 0x1000) ? 1 : 0;
+       else
+           word |= getonebit (drv->trackpointers[drv->current_revolution], drv->mfmpos);
+       //write_log ("%08.8X bo=%d so=%d mfmpos=%d dma=%d\n", (word & 0xffffff), bitoffset, syncoffset, drv->mfmpos,dma_enable);
+       drv->mfmpos++;
+       drv->mfmpos %= drv->tracklen;
+       if (drv->mfmpos == drv->indexoffset) {
+           drv->current_revolution++;
+           if (drv->current_revolution >= drv->revolutions)
+               drv->current_revolution = 0;
+           drv->tracklen = drv->tracklengths[drv->current_revolution];
+           drv->trackspeed = get_floppy_speed () * drv->tracklen / (2 * 8 * FLOPPY_WRITE_LEN * drv->ddhd);
+       }
+
+       if (bitoffset == 15 && dma_enable && dskdmaen == 2 && dsklength >= 0) {
+           if (dsklength > 0) {
+               put_word (dskpt, word);
+               dskpt += 2;
+#ifdef CPUEMU_6
+               cycle_line[7] |= CYCLE_DISK;
+               cycle_line[9] |= CYCLE_DISK;
+#endif
+           }
+#if 0
+           dma_tab[j++] = word;
+           if (j == MAX_DISK_WORDS_PER_LINE - 1) {
+               write_log ("Bug: Disk DMA buffer overflow!\n");
+               j--;
+           }
+#endif
+           dsklength--;
+           if (dsklength <= 0)
+               disk_dmafinished ();
+       }
+       if ((bitoffset & 7) == 7) {
+           dskbytr_val = word & 0xff;
+           dskbytr_val |= 0x8000;
+       }
+       if (word == dsksync) {
+           if (adkcon & 0x400)
+               bitoffset = 15;
+#ifdef DISK_DEBUG
+           if (dma_enable == 0)
+               write_dlog ("Sync match, DMA started at %d\n", drv->mfmpos);
+#endif
+           dma_enable = 1;
+       }
+       
+       bitoffset++;
+       bitoffset &= 15;
+       floppybits -= drv->trackspeed;
+    }
+#if 0
+    dma_tab[j] = 0xffffffff;
+#endif
+}
+
+#if 0
+/* disk DMA fetch happens on real Amiga at the beginning of next horizontal line
+   (cycles 9, 11 and 13 according to hardware manual) We transfer all DMA'd
+   data at cycle 0. I don't think any program cares about this small difference.
+*/
+static void dodmafetch (void)
+{
+    int i;
+
+    i = 0;
+    while (dma_tab[i] != 0xffffffff && dskdmaen != 3 && (dmacon & 0x210) == 0x210) {
+        put_word (dskpt, dma_tab[i++]);
+        dskpt += 2;
+    }
+    dma_tab[0] = 0xffffffff;
+}
+#endif
+
+/* this is very unoptimized. DSKBYTR is used very rarely, so it should not matter. */
+
+uae_u16 DSKBYTR (int hpos)
+{
+    uae_u16 v;
+
+    DISK_update (hpos);
+    v = dskbytr_val;
+    dskbytr_val &= ~0x8000;
+    if (word == dsksync)
+       v |= 0x1000;
+    if (dskdmaen && (dmacon & 0x210) == 0x210)
+       v |= 0x4000;
+    if (dsklen & 0x4000)
+       v |= 0x2000;
+#ifdef DISK_DEBUG2
+    write_dlog ("DSKBYTR=%04.4X hpos=%d\n", v, hpos);
+#endif
+    return v;
+}
+
+static void DISK_start (void)
+{
+    int dr;
+
+    for (dr = 0; dr < 4; dr++) {
+       drive *drv = &floppy[dr];
+       if (!(selected & (1 << dr))) {
+           int tr = drv->cyl * 2 + side;
+           trackid *ti = drv->trackdata + tr;
+
+           if (dskdmaen == 3) {
+               drv->tracklen = FLOPPY_WRITE_LEN * drv->ddhd * 8 * 2;
+               drv->trackspeed = get_floppy_speed ();
+               updatemfmpos (drv);
+           }
+           /* Ugh.  A nasty hack.  Assume ADF_EXT1 tracks are always read
+              from the start.  */
+           if (ti->type == TRACK_RAW1)
+               drv->mfmpos = 0;
+           if (drv->catweasel)
+               drive_fill_bigbuf (drv, 1);
+       }
+        drv->floppybitcounter = 0;
+    }
+    dma_enable = (adkcon & 0x400) ? 0 : 1;
+}
+
+static int linecounter;
+
+void DISK_update (int tohpos)
+{
+    int dr;
+    int cycles = (tohpos << 8) - disk_hpos;
+    int startcycle = disk_hpos;
+
+    if (cycles <= 0)
+       return;
+    disk_hpos += cycles;
+    if (disk_hpos >= (maxhpos << 8))
+       disk_hpos -= maxhpos << 8;
+
+    for (dr = 0; dr < 4; dr++) {
+       drive *drv = &floppy[dr];
+       if (drv->steplimit)
+           drv->steplimit--;
+    }
+    if (linecounter) {
+       linecounter--;
+       if (! linecounter)
+           disk_dmafinished ();
+       return;
+    }
+
+#if 0
+    dodmafetch ();
+#endif
+
+    for (dr = 0; dr < 4; dr++) {
+       drive *drv = &floppy[dr];
+       
+       if (drv->motoroff)
+           continue;
+        drv->floppybitcounter += cycles;
+       if (selected & (1 << dr)) {
+           drv->mfmpos += drv->floppybitcounter / drv->trackspeed;
+           drv->mfmpos %= drv->tracklen;
+            drv->floppybitcounter %= drv->trackspeed;
+           continue;
+       }
+       drive_fill_bigbuf (drv, 0);
+       drv->mfmpos %= drv->tracklen;
+    }
+    for (dr = 0; dr < 4; dr++) {
+       drive *drv = &floppy[dr];
+       if (drv->motoroff)
+           continue;
+       if (selected & (1 << dr))
+           continue;
+       if (dskdmaen == 3)
+           disk_doupdate_write (drv, drv->floppybitcounter);
+       else
+           disk_doupdate_read (drv, drv->floppybitcounter);
+       disk_doupdate_predict (drv, disk_hpos);
+        drv->floppybitcounter %= drv->trackspeed;
+       break;
+    }
+}
+
+void DSKLEN (uae_u16 v, int hpos)
+{
+    int dr, prev = dsklen;
+
+    DISK_update (hpos);
+    if ((v & 0x8000) && (dsklen & 0x8000)) {
+       dskdmaen = 2;
+        DISK_start ();
+    }
+    if (!(v & 0x8000)) {
+       if (dskdmaen) {
+       /* Megalomania and Knightmare does this */
+#ifdef DISK_DEBUG
+           if (dskdmaen == 2)
+               write_dlog ("warning: Disk read DMA aborted, %d words left PC=%x\n", dsklength, m68k_getpc());
+#endif
+           if (dskdmaen == 3)
+               write_dlog ("warning: Disk write DMA aborted, %d words left PC=%x\n", dsklength, m68k_getpc());
+           dskdmaen = 0;
+       }
+    }
+    dsklen = v;
+    dsklength = dsklen & 0x3fff;
+    if (dsklength == 1)
+       dsklength = 0;
+
+    if (dskdmaen == 0)
+       return;
+
+    if ((v & 0x4000) && (prev & 0x4000)) {
+       if (dsklength == 0)
+           return;
+       dskdmaen = 3;
+       DISK_start ();
+    }
+
+#ifdef DISK_DEBUG
+    for (dr = 0; dr < 4; dr++) {
+        drive *drv = &floppy[dr];
+        if (drv->motoroff)
+           continue;
+       if ((selected & (1 << dr)) == 0)
+           break;
+    }
+    if (dr == 4)
+        write_log ("disk %s DMA started but no drive selected!\n",
+              dskdmaen == 3 ? "write" : "read");
+    else
+        write_log ("disk %s DMA started, drv=%x track %d mfmpos %d\n",
+           dskdmaen == 3 ? "write" : "read", selected ^ 15,
+           floppy[dr].cyl * 2 + side, floppy[dr].mfmpos);
+    write_dlog ("LEN=%04.4X (%d) SYNC=%04.4X PT=%08.8X ADKCON=%04.4X PC=%08.8X\n", 
+       dsklength, dsklength, (adkcon & 0x400) ? dsksync : 0xffff, dskpt, adkcon, m68k_getpc());
+#endif
+
+    /* Try to make floppy access from Kickstart faster.  */
+    if (dskdmaen != 2 && dskdmaen != 3)
+       return;
+    for (dr = 0; dr < 4; dr++) {
+        drive *drv = &floppy[dr];
+        if (selected & (1 << dr))
+           continue;
+       if (drv->filetype != ADF_NORMAL)
+           break;
+    }
+    if (dr < 4) /* no turbo mode if any selected drive has non-standard ADF */
+       return;
+    {
+       int done = 0;
+       for (dr = 0; dr < 4; dr++) {
+           drive *drv = &floppy[dr];
+           int pos, i;
+
+           if (drv->motoroff)
+               continue;
+           if (!drv->useturbo && currprefs.floppy_speed > 0)
+               continue;
+           if (selected & (1 << dr))
+               continue;
+
+           pos = drv->mfmpos & ~15;
+           drive_fill_bigbuf (drv, 0);
+
+           if (dskdmaen == 2) { /* TURBO read */
+
+               if (adkcon & 0x400) {
+                   for (i = 0; i < drv->tracklen; i += 16) {
+                       pos += 16;
+                       pos %= drv->tracklen;
+                       if (drv->bigmfmbuf[pos >> 4] == dsksync) {
+                           /* must skip first disk sync marker */
+                           pos += 16;
+                           pos %= drv->tracklen;
+                           break;
+                       }
+                   }
+                   if (i >= drv->tracklen)
+                       return;
+               }
+               while (dsklength-- > 0) {
+                   put_word (dskpt, drv->bigmfmbuf[pos >> 4]);
+                   dskpt += 2;
+                   pos += 16;
+                   pos %= drv->tracklen;
+               }
+               INTREQ (0x9000);
+               done = 1;
+
+           } else if (dskdmaen == 3) { /* TURBO write */
+
+               for (i = 0; i < dsklength; i++) {
+                   drv->bigmfmbuf[pos >> 4] = get_word (dskpt + i * 2);
+                   pos += 16;
+                   pos %= drv->tracklen;
+               }
+               drive_write_data (drv);
+               done = 1;
+           }
+       }
+       if (done) {
+           linecounter = 2;
+           dskdmaen = 0;
+           return;
+       }       
+    }
+}
+
+void DSKSYNC (int hpos, uae_u16 v)
+{
+    if (v == dsksync)
+       return;
+    DISK_update (hpos);
+    dsksync = v;
+}
+
+void DSKDAT (uae_u16 v)
+{
+    static int count = 0;
+    if (count < 5) {
+       count++;
+       write_dlog ("%04.4X written to DSKDAT. Not good. PC=%08.8X", v, m68k_getpc());
+       if (count == 5)
+           write_log ("(further messages suppressed)");
+
+       write_log ("\n");
+    }
+}
+void DSKPTH (uae_u16 v)
+{
+    dskpt = (dskpt & 0xffff) | ((uae_u32) v << 16);
+}
+
+void DSKPTL (uae_u16 v)
+{
+    dskpt = (dskpt & ~0xffff) | (v);
+}
+
+void DISK_free (void)
+{
+    int dr;
+    for (dr = 0; dr < 4; dr++) {
+       drive *drv = &floppy[dr];
+       drive_image_free (drv);
+    }
+}
+
+void DISK_init (void)
+{
+    int dr;
+
+#if 0
+    dma_tab[0] = 0xffffffff;
+#endif
+    for (dr = 0; dr < 4; dr++) {
+       drive *drv = &floppy[dr];
+       /* reset all drive types to 3.5 DD */
+       drive_settype_id (drv);
+       if (!drive_insert (drv, dr, currprefs.df[dr]))
+           disk_eject (dr);
+    }
+    if (disk_empty (0))
+       write_log ("No disk in drive 0.\n");
+}
+
+void DISK_reset (void)
+{
+    int i;
+
+    if (savestate_state)
+       return;
+
+    //floppy[0].catweasel = &cwc.drives[0];
+    disk_hpos = 0;
+    dskdmaen = 0;
+    disabled = 0;
+    for (i = 0; i < 4; i++)
+       reset_drive (i);
+}
+
+/* Disk save/restore code */
+
+void DISK_save_custom (uae_u32 *pdskpt, uae_u16 *pdsklength, uae_u16 *pdsksync, uae_u16 *pdskbytr)
+{
+    if(pdskpt) *pdskpt = dskpt;
+    if(pdsklength) *pdsklength = dsklength;
+    if(pdsksync) *pdsksync = dsksync;
+    if(pdskbytr) *pdskbytr = dskbytr_val;
+}
+
+void DISK_restore_custom (uae_u32 pdskpt, uae_u16 pdsklength, uae_u16 pdskbytr)
+{
+    dskpt = pdskpt;
+    dsklength = pdsklength;
+    dskbytr_val = pdskbytr;
+}
+
+uae_u8 *restore_disk(int num,uae_u8 *src)
+{
+    drive *drv;
+    int state, dfxtype;
+
+    drv = &floppy[num];
+    disabled &= ~(1 << num);
+    drv->drive_id = restore_u32 ();
+    drv->motoroff = 1;
+    drv->idbit = 0;
+    state = restore_u8 ();
+    if (state & 2) {
+       disabled |= 1 << num;
+       if (changed_prefs.nr_floppies > num)
+           changed_prefs.nr_floppies = num;
+       changed_prefs.dfxtype[num] = -1;
+    } else {
+       drv->motoroff = (state & 1) ? 0 : 1;
+       drv->idbit = (state & 4) ? 1 : 0;
+       if (changed_prefs.nr_floppies < num)
+           changed_prefs.nr_floppies = num;
+       switch (drv->drive_id)
+       {
+           case DRIVE_ID_35HD:
+           dfxtype = DRV_35_HD;
+           break;
+           case DRIVE_ID_525SD:
+           dfxtype = DRV_525_SD;
+           break;
+           default:
+           dfxtype = DRV_35_DD;
+           break;
+       }
+       changed_prefs.dfxtype[num] = dfxtype;
+    }
+    drv->cyl = restore_u8 ();
+    drv->dskready = restore_u8 ();
+    drv->drive_id_scnt = restore_u8 ();
+    drv->mfmpos = restore_u32 ();
+    drv->dskchange = 0;
+    drv->dskchange_time = 0;
+    restore_u32 ();
+    strncpy(changed_prefs.df[num],src,255);
+    src+=strlen(src)+1;
+    drive_insert (floppy + num, num, changed_prefs.df[num]);
+    if (drive_empty (floppy + num)) drv->dskchange = 1;
+
+    return src;
+}
+
+static uae_u32 getadfcrc (drive *drv)
+{
+    uae_u8 *b;
+    uae_u32 crc32;
+    int size;
+
+    if (!drv->diskfile)
+       return 0;
+    zfile_fseek (drv->diskfile, 0, SEEK_END);
+    size = zfile_ftell (drv->diskfile);
+    b = malloc (size);
+    if (!b)
+       return 0;
+    zfile_fseek (drv->diskfile, 0, SEEK_SET);
+    zfile_fread (b, 1, size, drv->diskfile);
+    crc32 = CRC32 (0, b, size);
+    free (b);
+    return crc32;
+}
+
+uae_u8 *save_disk(int num, int *len, uae_u8 *dstptr)
+{
+    uae_u8 *dstbak,*dst;
+    drive *drv;
+
+    drv = &floppy[num];
+    if (dstptr)
+       dstbak = dst = dstptr;
+    else
+        dstbak = dst = malloc (2+1+1+1+1+4+4+256);
+    save_u32 (drv->drive_id);      /* drive type ID */
+    save_u8 ((drv->motoroff ? 0:1) | ((disabled & (1 << num)) ? 2 : 0) | (drv->idbit ? 4 : 0));
+    save_u8 (drv->cyl);                    /* cylinder */
+    save_u8 (drv->dskready);       /* dskready */
+    save_u8 (drv->drive_id_scnt);   /* id mode position */
+    save_u32 (drv->mfmpos);        /* disk position */
+    save_u32 (getadfcrc (drv));            /* CRC of disk image */
+    strcpy (dst, currprefs.df[num]);/* image name */
+    dst += strlen(dst) + 1;
+
+    *len = dst - dstbak;
+    return dstbak;
+}
+
+/* internal floppy controller variables */
+
+uae_u8 *restore_floppy(uae_u8 *src)
+{
+    word = restore_u16();
+    bitoffset = restore_u8();
+    dma_enable = restore_u8();
+    disk_hpos = restore_u8() << 8;
+    dskdmaen = restore_u8();
+    restore_u16 ();
+    //word |= restore_u16() << 16;
+
+    return src;
+}
+
+uae_u8 *save_floppy(int *len, uae_u8 *dstptr)
+{
+    uae_u8 *dstbak, *dst;
+
+    /* flush dma buffer before saving */
+#if 0
+    dodmafetch();
+#endif
+    if (dstptr)
+       dstbak = dst = dstptr;
+    else
+        dstbak = dst = malloc(2+1+1+1+1+2);
+    save_u16 (word);           /* current fifo (low word) */
+    save_u8 (bitoffset);       /* dma bit offset */
+    save_u8 (dma_enable);      /* disk sync found */
+    save_u8 (disk_hpos >> 8);  /* next bit read position */
+    save_u8 (dskdmaen);                /* dma status */
+    save_u16 (0);              /* was current fifo (high word), but it was wrong???? */
+
+    *len = dst - dstbak;
+    return dstbak;
+}
+
+
diff --git a/dms/cdata.h b/dms/cdata.h
new file mode 100755 (executable)
index 0000000..b5e77e0
--- /dev/null
@@ -0,0 +1,80 @@
+
+/*
+ *     xDMS  v1.3  -  Portable DMS archive unpacker  -  Public Domain
+ *     Written by     Andre Rodrigues de la Rocha  <adlroc@usa.net>
+ *
+ *     Main types of variables used in xDMS, some implementation
+ *     dependant features and other global stuff
+ */
+
+
+#ifndef UCHAR
+#define UCHAR unsigned char
+#endif
+
+#ifndef USHORT
+#define USHORT unsigned short
+#endif
+
+#ifndef SHORT
+#define SHORT short
+#endif
+
+#ifndef ULONG
+#define ULONG unsigned long
+#endif
+
+
+
+#ifndef INLINE
+       #ifdef __cplusplus
+               #define INLINE inline
+       #else
+               #ifdef __GNUC__
+                       #define INLINE inline
+               #else
+                       #ifdef __SASC
+                               #define INLINE __inline
+                       #else
+                               #define INLINE static
+                       #endif
+               #endif
+       #endif
+#endif
+
+
+#ifndef UNDER_DOS
+       #ifdef __MSDOS__
+               #define UNDER_DOS
+       #else
+               #ifdef __MSDOS
+                       #define UNDER_DOS
+               #else
+                       #ifdef _OS2
+                               #define UNDER_DOS
+                       #else
+                               #ifdef _QC
+                                       #define UNDER_DOS
+                               #endif
+                       #endif
+               #endif
+       #endif
+#endif
+
+
+#ifndef DIR_CHAR
+       #ifdef UNDER_DOS
+               /* running under MSDOS or DOS-like OS */
+               #define DIR_CHAR '\\'
+       #else
+               #define DIR_CHAR '/'
+       #endif
+#endif
+
+
+#define DIR_SEPARATORS ":\\/"
+
+
+extern UCHAR *text;
+
+
diff --git a/dms/crc_csum.c b/dms/crc_csum.c
new file mode 100755 (executable)
index 0000000..70337c6
--- /dev/null
@@ -0,0 +1,69 @@
+
+/*
+ *     xDMS  v1.3  -  Portable DMS archive unpacker  -  Public Domain
+ *     Written by     Andre Rodrigues de la Rocha  <adlroc@usa.net>
+ *
+ *     CRC16 & CheckSum16 calculation functions
+ *     CreateCRC was written (aparently) by Bjorn Stenberg
+ *
+ */
+
+
+#include "cdata.h"
+#include "crc_csum.h"
+
+
+
+USHORT Calc_CheckSum(UCHAR *mem, ULONG size){
+       USHORT u=0;
+
+       while(size--) u += *mem++;
+       return (USHORT)(u & 0xffff);
+}
+
+
+
+USHORT CreateCRC(UCHAR* mem, ULONG size ){
+       static USHORT CRCTab[256]={
+               0x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241,
+               0xC601,0x06C0,0x0780,0xC741,0x0500,0xC5C1,0xC481,0x0440,
+               0xCC01,0x0CC0,0x0D80,0xCD41,0x0F00,0xCFC1,0xCE81,0x0E40,
+               0x0A00,0xCAC1,0xCB81,0x0B40,0xC901,0x09C0,0x0880,0xC841,
+               0xD801,0x18C0,0x1980,0xD941,0x1B00,0xDBC1,0xDA81,0x1A40,
+               0x1E00,0xDEC1,0xDF81,0x1F40,0xDD01,0x1DC0,0x1C80,0xDC41,
+               0x1400,0xD4C1,0xD581,0x1540,0xD701,0x17C0,0x1680,0xD641,
+               0xD201,0x12C0,0x1380,0xD341,0x1100,0xD1C1,0xD081,0x1040,
+               0xF001,0x30C0,0x3180,0xF141,0x3300,0xF3C1,0xF281,0x3240,
+               0x3600,0xF6C1,0xF781,0x3740,0xF501,0x35C0,0x3480,0xF441,
+               0x3C00,0xFCC1,0xFD81,0x3D40,0xFF01,0x3FC0,0x3E80,0xFE41,
+               0xFA01,0x3AC0,0x3B80,0xFB41,0x3900,0xF9C1,0xF881,0x3840,
+               0x2800,0xE8C1,0xE981,0x2940,0xEB01,0x2BC0,0x2A80,0xEA41,
+               0xEE01,0x2EC0,0x2F80,0xEF41,0x2D00,0xEDC1,0xEC81,0x2C40,
+               0xE401,0x24C0,0x2580,0xE541,0x2700,0xE7C1,0xE681,0x2640,
+               0x2200,0xE2C1,0xE381,0x2340,0xE101,0x21C0,0x2080,0xE041,
+               0xA001,0x60C0,0x6180,0xA141,0x6300,0xA3C1,0xA281,0x6240,
+               0x6600,0xA6C1,0xA781,0x6740,0xA501,0x65C0,0x6480,0xA441,
+               0x6C00,0xACC1,0xAD81,0x6D40,0xAF01,0x6FC0,0x6E80,0xAE41,
+               0xAA01,0x6AC0,0x6B80,0xAB41,0x6900,0xA9C1,0xA881,0x6840,
+               0x7800,0xB8C1,0xB981,0x7940,0xBB01,0x7BC0,0x7A80,0xBA41,
+               0xBE01,0x7EC0,0x7F80,0xBF41,0x7D00,0xBDC1,0xBC81,0x7C40,
+               0xB401,0x74C0,0x7580,0xB541,0x7700,0xB7C1,0xB681,0x7640,
+               0x7200,0xB2C1,0xB381,0x7340,0xB101,0x71C0,0x7080,0xB041,
+               0x5000,0x90C1,0x9181,0x5140,0x9301,0x53C0,0x5280,0x9241,
+               0x9601,0x56C0,0x5780,0x9741,0x5500,0x95C1,0x9481,0x5440,
+               0x9C01,0x5CC0,0x5D80,0x9D41,0x5F00,0x9FC1,0x9E81,0x5E40,
+               0x5A00,0x9AC1,0x9B81,0x5B40,0x9901,0x59C0,0x5880,0x9841,
+               0x8801,0x48C0,0x4980,0x8941,0x4B00,0x8BC1,0x8A81,0x4A40,
+               0x4E00,0x8EC1,0x8F81,0x4F40,0x8D01,0x4DC0,0x4C80,0x8C41,
+               0x4400,0x84C1,0x8581,0x4540,0x8701,0x47C0,0x4680,0x8641,
+               0x8201,0x42C0,0x4380,0x8341,0x4100,0x81C1,0x8081,0x4040
+       };
+       register USHORT CRC = 0;
+
+       while(size--)
+               CRC = (USHORT) (CRCTab[((CRC ^ *mem++) & 255)] ^ ((CRC >> 8) & 255));
+
+       return CRC;
+}
+
+
diff --git a/dms/crc_csum.h b/dms/crc_csum.h
new file mode 100755 (executable)
index 0000000..0fa92f5
--- /dev/null
@@ -0,0 +1,4 @@
+
+USHORT Calc_CheckSum(UCHAR *, ULONG);
+USHORT CreateCRC(UCHAR *, ULONG);
+
diff --git a/dms/getbits.c b/dms/getbits.c
new file mode 100755 (executable)
index 0000000..d474977
--- /dev/null
@@ -0,0 +1,34 @@
+
+/*
+ *     xDMS  v1.3  -  Portable DMS archive unpacker  -  Public Domain
+ *     Written by     Andre Rodrigues de la Rocha  <adlroc@usa.net>
+ *     Functions/macros to get a variable number of bits
+ * 
+ */
+
+#include "cdata.h"
+#include "getbits.h"
+
+
+ULONG mask_bits[]={
+       0x000000L,0x000001L,0x000003L,0x000007L,0x00000fL,0x00001fL,
+       0x00003fL,0x00007fL,0x0000ffL,0x0001ffL,0x0003ffL,0x0007ffL,
+       0x000fffL,0x001fffL,0x003fffL,0x007fffL,0x00ffffL,0x01ffffL,
+       0x03ffffL,0x07ffffL,0x0fffffL,0x1fffffL,0x3fffffL,0x7fffffL,
+       0xffffffL
+};
+
+
+UCHAR *indata, bitcount;
+ULONG bitbuf;
+
+
+
+void initbitbuf(UCHAR *in){
+       bitbuf = 0;
+       bitcount = 0;
+       indata = in;
+       DROPBITS(0);
+}      
+
+
diff --git a/dms/getbits.h b/dms/getbits.h
new file mode 100755 (executable)
index 0000000..f0c5add
--- /dev/null
@@ -0,0 +1,10 @@
+
+extern ULONG mask_bits[], bitbuf;
+extern UCHAR *indata, bitcount;
+
+#define GETBITS(n) ((USHORT)(bitbuf >> (bitcount-(n))))
+#define DROPBITS(n) {bitbuf &= mask_bits[bitcount-=(n)]; while (bitcount<16) {bitbuf = (bitbuf << 8) | *indata++;  bitcount += 8;}}
+
+
+void initbitbuf(UCHAR *);
+
diff --git a/dms/maketbl.c b/dms/maketbl.c
new file mode 100755 (executable)
index 0000000..c735988
--- /dev/null
@@ -0,0 +1,92 @@
+
+/*
+ *     xDMS  v1.3  -  Portable DMS archive unpacker  -  Public Domain
+ *     Written by     Andre Rodrigues de la Rocha  <adlroc@usa.net>
+ *
+ *     Makes decoding table for Heavy LZH decompression
+ *     From  UNIX LHA made by Masaru Oki
+ *
+ */
+
+
+#include "cdata.h"
+#include "maketbl.h"
+
+
+static SHORT c;
+static USHORT n, tblsiz, len, depth, maxdepth, avail;
+static USHORT codeword, bit, *tbl, TabErr;
+static UCHAR *blen;
+
+
+static USHORT mktbl(void);
+
+
+
+USHORT make_table(USHORT nchar, UCHAR bitlen[],USHORT tablebits, USHORT table[]){
+       n = avail = nchar;
+       blen = bitlen;
+       tbl = table;
+       tblsiz = (USHORT) (1U << tablebits);
+       bit = (USHORT) (tblsiz / 2);
+       maxdepth = (USHORT)(tablebits + 1);
+       depth = len = 1;
+       c = -1;
+       codeword = 0;
+       TabErr = 0;
+       mktbl();        /* left subtree */
+       if (TabErr) return TabErr;
+       mktbl();        /* right subtree */
+       if (TabErr) return TabErr;
+       if (codeword != tblsiz) return 5;
+       return 0;
+}
+
+
+
+static USHORT mktbl(void){
+       USHORT i=0;
+
+       if (TabErr) return 0;
+
+       if (len == depth) {
+               while (++c < n)
+                       if (blen[c] == len) {
+                               i = codeword;
+                               codeword += bit;
+                               if (codeword > tblsiz) {
+                                       TabErr=1;
+                                       return 0;
+                               }
+                               while (i < codeword) tbl[i++] = (USHORT)c;
+                               return (USHORT)c;
+                       }
+               c = -1;
+               len++;
+               bit >>= 1;
+       }
+       depth++;
+       if (depth < maxdepth) {
+               mktbl();
+               mktbl();
+       } else if (depth > 32) {
+               TabErr = 2;
+               return 0;
+       } else {
+               if ((i = avail++) >= 2 * n - 1) {
+                       TabErr = 3;
+                       return 0;
+               }
+               left[i] = mktbl();
+               right[i] = mktbl();
+               if (codeword >= tblsiz) {
+                       TabErr = 4;
+                       return 0;
+               }
+               if (depth == maxdepth) tbl[codeword++] = i;
+       }
+       depth--;
+       return i;
+}
+
+
diff --git a/dms/maketbl.h b/dms/maketbl.h
new file mode 100755 (executable)
index 0000000..42abc3e
--- /dev/null
@@ -0,0 +1,5 @@
+
+extern USHORT left[], right[];
+
+USHORT make_table(USHORT nchar, UCHAR bitlen[], USHORT tablebits, USHORT table[]);
+
diff --git a/dms/pfile.c b/dms/pfile.c
new file mode 100755 (executable)
index 0000000..f7c2204
--- /dev/null
@@ -0,0 +1,416 @@
+
+/*
+ *     xDMS  v1.3  -  Portable DMS archive unpacker  -  Public Domain
+ *     Written by     Andre Rodrigues de la Rocha  <adlroc@usa.net>
+ *
+ *     Handles the processing of a single DMS archive
+ *
+ */
+
+
+#define HEADLEN 56
+#define THLEN 20
+#define TRACK_BUFFER_LEN 32000
+#define TEMP_BUFFER_LEN 32000
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+#include "zfile.h"
+
+#include "cdata.h"
+#include "u_init.h"
+#include "u_rle.h"
+#include "u_quick.h"
+#include "u_medium.h"
+#include "u_deep.h"
+#include "u_heavy.h"
+#include "crc_csum.h"
+#include "pfile.h"
+
+
+
+static USHORT Process_Track(struct zfile *, struct zfile *, UCHAR *, UCHAR *, USHORT, USHORT, USHORT);
+static USHORT Unpack_Track(UCHAR *, UCHAR *, USHORT, USHORT, UCHAR, UCHAR);
+static void printbandiz(UCHAR *, USHORT);
+static void dms_decrypt(UCHAR *, USHORT);
+
+
+static char modes[7][7]={"NOCOMP","SIMPLE","QUICK ","MEDIUM","DEEP  ","HEAVY1","HEAVY2"};
+static USHORT PWDCRC;
+
+UCHAR *text;
+
+
+
+USHORT DMS_Process_File(struct zfile *fi, struct zfile *fo, USHORT cmd, USHORT opt, USHORT PCRC, USHORT pwd){
+       USHORT from, to, geninfo, c_version, cmode, hcrc, disktype, pv, ret;
+       ULONG pkfsize, unpkfsize;
+       UCHAR *b1, *b2;
+       time_t date;
+
+
+       b1 = (UCHAR *)calloc((size_t)TRACK_BUFFER_LEN,1);
+       if (!b1) return ERR_NOMEMORY;
+       b2 = (UCHAR *)calloc((size_t)TRACK_BUFFER_LEN,1);
+       if (!b2) {
+               free(b1);
+               return ERR_NOMEMORY;
+       }
+       text = (UCHAR *)calloc((size_t)TEMP_BUFFER_LEN,1);
+       if (!text) {
+               free(b1);
+               free(b2);
+               return ERR_NOMEMORY;
+       }
+
+       /* if iname is NULL, input is stdin;   if oname is NULL, output is stdout */
+
+       if (zfile_fread(b1,1,HEADLEN,fi) != HEADLEN) {
+               free(b1);
+               free(b2);
+               free(text);
+               return ERR_SREAD;
+       }
+
+       if ( (b1[0] != 'D') || (b1[1] != 'M') || (b1[2] != 'S') || (b1[3] != '!') ) {
+               /*  Check the first 4 bytes of file to see if it is "DMS!"  */
+               free(b1);
+               free(b2);
+               free(text);
+               return ERR_NOTDMS;
+       }
+
+       hcrc = (USHORT)((b1[HEADLEN-2]<<8) | b1[HEADLEN-1]);
+       /* Header CRC */
+
+       if (hcrc != CreateCRC(b1+4,(ULONG)(HEADLEN-6))) {
+               free(b1);
+               free(b2);
+               free(text);
+               return ERR_HCRC;
+       }
+       
+       geninfo = (USHORT) ((b1[10]<<8) | b1[11]);      /* General info about archive */
+       date = (time_t) ((((ULONG)b1[12])<<24) | (((ULONG)b1[13])<<16) | (((ULONG)b1[14])<<8) | (ULONG)b1[15]); /* date in standard UNIX/ANSI format */
+       from = (USHORT) ((b1[16]<<8) | b1[17]);         /*  Lowest track in archive. May be incorrect if archive is "appended" */
+       to = (USHORT) ((b1[18]<<8) | b1[19]);           /*  Highest track in archive. May be incorrect if archive is "appended" */
+
+       pkfsize = (ULONG) ((((ULONG)b1[21])<<16) | (((ULONG)b1[22])<<8) | (ULONG)b1[23]);       /*  Length of total packed data as in archive   */
+       unpkfsize = (ULONG) ((((ULONG)b1[25])<<16) | (((ULONG)b1[26])<<8) | (ULONG)b1[27]);     /*  Length of unpacked data. Usually 901120 bytes  */
+
+       c_version = (USHORT) ((b1[46]<<8) | b1[47]);    /*  version of DMS used to generate it  */
+       disktype = (USHORT) ((b1[50]<<8) | b1[51]);             /*  Type of compressed disk  */
+       cmode = (USHORT) ((b1[52]<<8) | b1[53]);        /*  Compression mode mostly used in this archive  */
+
+       PWDCRC = PCRC;
+
+       if ( (cmd == CMD_VIEW) || (cmd == CMD_VIEWFULL) ) {
+
+               pv = (USHORT)(c_version/100);
+               write_log(" Created with DMS version %d.%02d ",pv,c_version-pv*100);
+               if (geninfo & 0x80)
+                       write_log("Registered\n");
+               else
+                       write_log("Evaluation\n");
+
+               write_log(" Creation date : %s",ctime(&date));
+               write_log(" Lowest track in archive : %d\n",from);
+               write_log(" Highest track in archive : %d\n",to);
+               write_log(" Packed data size : %lu\n",pkfsize);
+               write_log(" Unpacked data size : %lu\n",unpkfsize);
+               write_log(" Disk type of archive : ");
+
+               /*  The original DMS from SDS software (DMS up to 1.11) used other values    */
+               /*  in disk type to indicate formats as MS-DOS, AMax and Mac, but it was     */
+               /*  not suported for compression. It was for future expansion and was never  */
+               /*  used. The newer versions of DMS made by ParCon Software changed it to    */
+               /*  add support for new Amiga disk types.                                    */
+               switch (disktype) {
+                       case 0:
+                       case 1:
+                               /* Can also be a non-dos disk */
+                               write_log("AmigaOS 1.0 OFS\n");
+                               break;
+                       case 2:
+                               write_log("AmigaOS 2.0 FFS\n");
+                               break;
+                       case 3:
+                               write_log("AmigaOS 3.0 OFS / International\n");
+                               break;
+                       case 4:
+                               write_log("AmigaOS 3.0 FFS / International\n");
+                               break;
+                       case 5:
+                               write_log("AmigaOS 3.0 OFS / Dir Cache\n");
+                               break;
+                       case 6:
+                               write_log("AmigaOS 3.0 FFS / Dir Cache\n");
+                               break;
+                       case 7:
+                               write_log("FMS Amiga System File\n");
+                               break;
+                       default:
+                               write_log("Unknown\n");
+               }
+
+               write_log(" Compression mode used : ");
+               if (cmode>6)
+                       write_log("Unknown !\n");
+               else
+                       write_log("%s\n",modes[cmode]);
+
+               write_log(" General info : ");
+               if ((geninfo==0)||(geninfo==0x80)) write_log("None");
+               if (geninfo & 1) write_log("NoZero ");
+               if (geninfo & 2) write_log("Encrypted ");
+               if (geninfo & 4) write_log("Appends ");
+               if (geninfo & 8) write_log("Banner ");
+               if (geninfo & 16) write_log("HD ");
+               if (geninfo & 32) write_log("MS-DOS ");
+               if (geninfo & 64) write_log("DMS_DEV_Fixed ");
+               if (geninfo & 256) write_log("FILEID.DIZ");
+               write_log("\n");
+
+               write_log(" Info Header CRC : %04X\n\n",hcrc);
+
+       }
+
+       if (disktype == 7) {
+               /*  It's not a DMS compressed disk image, but a FMS archive  */
+               free(b1);
+               free(b2);
+               free(text);
+               return ERR_FMS;
+       }
+
+
+       if (cmd == CMD_VIEWFULL)        {
+               write_log(" Track   Plength  Ulength  Cmode   USUM  HCRC  DCRC Cflag\n");
+               write_log(" ------  -------  -------  ------  ----  ----  ---- -----\n");
+       }
+
+       if (((cmd==CMD_UNPACK) || (cmd==CMD_SHOWBANNER)) && (geninfo & 2) && (!pwd))
+               return ERR_NOPASSWD;
+
+       ret=NO_PROBLEM;
+
+       Init_Decrunchers();
+
+       if (cmd != CMD_VIEW) {
+               if (cmd == CMD_SHOWBANNER) /*  Banner is in the first track  */
+                       ret = Process_Track(fi,NULL,b1,b2,cmd,opt,(geninfo & 2)?pwd:0);
+               else {
+                       while ( (ret=Process_Track(fi,fo,b1,b2,cmd,opt,(geninfo & 2)?pwd:0)) == NO_PROBLEM ) ;
+               }
+       }
+
+       if ((cmd == CMD_VIEWFULL) || (cmd == CMD_SHOWDIZ) || (cmd == CMD_SHOWBANNER)) write_log("\n");
+
+       if (ret == DMS_FILE_END) ret = NO_PROBLEM;
+
+
+       /*  Used to give an error message, but I have seen some DMS  */
+       /*  files with texts or zeros at the end of the valid data   */
+       /*  So, when we find something that is not a track header,   */
+       /*  we suppose that the valid data is over. And say it's ok. */
+       if (ret == ERR_NOTTRACK) ret = NO_PROBLEM;
+
+
+       free(b1);
+       free(b2);
+       free(text);
+
+       return ret;
+}
+
+
+
+static USHORT Process_Track(struct zfile *fi, struct zfile *fo, UCHAR *b1, UCHAR *b2, USHORT cmd, USHORT opt, USHORT pwd){
+       USHORT hcrc, dcrc, usum, number, pklen1, pklen2, unpklen, l, r;
+       UCHAR cmode, flags;
+
+
+       l = (USHORT)zfile_fread(b1,1,THLEN,fi);
+
+       if (l != THLEN) {
+               if (l==0)
+                       return DMS_FILE_END;
+               else
+                       return ERR_SREAD;
+       }
+
+       /*  "TR" identifies a Track Header  */
+       if ((b1[0] != 'T')||(b1[1] != 'R')) return ERR_NOTTRACK;
+
+       /*  Track Header CRC  */
+       hcrc = (USHORT)((b1[THLEN-2] << 8) | b1[THLEN-1]);
+
+       if (CreateCRC(b1,(ULONG)(THLEN-2)) != hcrc) return ERR_THCRC;
+
+       number = (USHORT)((b1[2] << 8) | b1[3]);        /*  Number of track  */
+       pklen1 = (USHORT)((b1[6] << 8) | b1[7]);        /*  Length of packed track data as in archive  */
+       pklen2 = (USHORT)((b1[8] << 8) | b1[9]);        /*  Length of data after first unpacking  */
+       unpklen = (USHORT)((b1[10] << 8) | b1[11]);     /*  Length of data after subsequent rle unpacking */
+       flags = b1[12];         /*  control flags  */
+       cmode = b1[13];         /*  compression mode used  */
+       usum = (USHORT)((b1[14] << 8) | b1[15]);        /*  Track Data CheckSum AFTER unpacking  */
+       dcrc = (USHORT)((b1[16] << 8) | b1[17]);        /*  Track Data CRC BEFORE unpacking  */
+
+       if (cmd == CMD_VIEWFULL) {
+               if (number==80)
+                       write_log(" FileID   ");
+               else if (number==0xffff)
+                       write_log(" Banner   ");
+               else if ((number==0) && (unpklen==1024))
+                       write_log(" FakeBB   ");
+               else
+                       write_log("   %2d     ",(short)number);
+
+           write_log("%5d    %5d   %s  %04X  %04X  %04X    %0d\n", pklen1, unpklen, modes[cmode], usum, hcrc, dcrc, flags);
+       }
+
+       if ((pklen1 > TRACK_BUFFER_LEN) || (pklen2 >TRACK_BUFFER_LEN) || (unpklen > TRACK_BUFFER_LEN)) return ERR_BIGTRACK;
+
+       if (zfile_fread(b1,1,(size_t)pklen1,fi) != pklen1) return ERR_SREAD;
+
+       if (CreateCRC(b1,(ULONG)pklen1) != dcrc) return ERR_TDCRC;
+
+       /*  track 80 is FILEID.DIZ, track 0xffff (-1) is Banner  */
+       /*  and track 0 with 1024 bytes only is a fake boot block with more advertising */
+       /*  FILE_ID.DIZ is never encrypted  */
+
+       if (pwd && (number!=80)) dms_decrypt(b1,pklen1);
+
+       if ((cmd == CMD_UNPACK) && (number<80) && (unpklen>2048)) {
+               r = Unpack_Track(b1, b2, pklen2, unpklen, cmode, flags);
+               if (r != NO_PROBLEM) 
+                       if (pwd)
+                               return ERR_BADPASSWD;
+                       else
+                               return r;
+               if (usum != Calc_CheckSum(b2,(ULONG)unpklen))
+                       if (pwd)
+                               return ERR_BADPASSWD;
+                       else
+                               return ERR_CSUM;
+               if (zfile_fwrite(b2,1,(size_t)unpklen,fo) != unpklen) return ERR_CANTWRITE;
+       }
+
+       if ((cmd == CMD_SHOWBANNER) && (number == 0xffff)){
+               r = Unpack_Track(b1, b2, pklen2, unpklen, cmode, flags);
+               if (r != NO_PROBLEM) 
+                       if (pwd)
+                               return ERR_BADPASSWD;
+                       else
+                               return r;
+               if (usum != Calc_CheckSum(b2,(ULONG)unpklen))
+                       if (pwd)
+                               return ERR_BADPASSWD;
+                       else
+                               return ERR_CSUM;
+               printbandiz(b2,unpklen);
+       }
+
+       if ((cmd == CMD_SHOWDIZ) && (number == 80)) {
+               r = Unpack_Track(b1, b2, pklen2, unpklen, cmode, flags);
+               if (r != NO_PROBLEM) return r;
+               if (usum != Calc_CheckSum(b2,(ULONG)unpklen)) return ERR_CSUM;
+               printbandiz(b2,unpklen);
+       }
+
+       return NO_PROBLEM;
+
+}
+
+
+
+static USHORT Unpack_Track(UCHAR *b1, UCHAR *b2, USHORT pklen2, USHORT unpklen, UCHAR cmode, UCHAR flags){
+       switch (cmode){
+               case 0:
+                       /*   No Compression   */
+                       memcpy(b2,b1,(size_t)unpklen);
+                       break;
+               case 1:
+                       /*   Simple Compression   */
+                       if (Unpack_RLE(b1,b2,unpklen)) return ERR_BADDECR;
+                       break;
+               case 2:
+                       /*   Quick Compression   */
+                       if (Unpack_QUICK(b1,b2,pklen2)) return ERR_BADDECR;
+                       if (Unpack_RLE(b2,b1,unpklen)) return ERR_BADDECR;
+                       memcpy(b2,b1,(size_t)unpklen);
+                       break;
+               case 3:
+                       /*   Medium Compression   */
+                       if (Unpack_MEDIUM(b1,b2,pklen2)) return ERR_BADDECR;
+                       if (Unpack_RLE(b2,b1,unpklen)) return ERR_BADDECR;
+                       memcpy(b2,b1,(size_t)unpklen);
+                       break;
+               case 4:
+                       /*   Deep Compression   */
+                       if (Unpack_DEEP(b1,b2,pklen2)) return ERR_BADDECR;
+                       if (Unpack_RLE(b2,b1,unpklen)) return ERR_BADDECR;
+                       memcpy(b2,b1,(size_t)unpklen);
+                       break;
+               case 5:
+               case 6:
+                       /*   Heavy Compression   */
+                       if (cmode==5) {
+                               /*   Heavy 1   */
+                               if (Unpack_HEAVY(b1,b2,flags & 7,pklen2)) return ERR_BADDECR;
+                       } else {
+                               /*   Heavy 2   */
+                               if (Unpack_HEAVY(b1,b2,flags | 8,pklen2)) return ERR_BADDECR;
+                       }
+                       if (flags & 4) {
+                               /*  Unpack with RLE only if this flag is set  */
+                               if (Unpack_RLE(b2,b1,unpklen)) return ERR_BADDECR;
+                               memcpy(b2,b1,(size_t)unpklen);
+                       }
+                       break;
+               default:
+                       return ERR_UNKNMODE;
+       }
+
+       if (!(flags & 1)) Init_Decrunchers();
+
+       return NO_PROBLEM;
+
+}
+
+
+/*  DMS uses a lame encryption  */
+static void dms_decrypt(UCHAR *p, USHORT len){
+       USHORT t;
+
+       while (len--){
+               t = (USHORT) *p;
+               *p++ ^= (UCHAR)PWDCRC;
+               PWDCRC = (USHORT)((PWDCRC >> 1) + t);
+       }
+}
+
+
+
+static void printbandiz(UCHAR *m, USHORT len){
+       UCHAR *i,*j;
+
+       i=j=m;
+       while (i<m+len) {
+               if (*i == 10) {
+                       *i=0;
+                       write_log("%s\n",j);
+                       j=i+1;
+               }
+               i++;
+       }
+
+}
+
+
diff --git a/dms/pfile.h b/dms/pfile.h
new file mode 100755 (executable)
index 0000000..473c34b
--- /dev/null
@@ -0,0 +1,43 @@
+
+
+/* Functions return codes */
+#define NO_PROBLEM 0
+#define DMS_FILE_END 1
+#define ERR_NOMEMORY 2
+#define ERR_CANTOPENIN 3
+#define ERR_CANTOPENOUT 4
+#define ERR_NOTDMS 5
+#define ERR_SREAD 6
+#define ERR_HCRC 7
+#define ERR_NOTTRACK 8
+#define ERR_BIGTRACK 9
+#define ERR_THCRC 10
+#define ERR_TDCRC 11
+#define ERR_CSUM 12
+#define ERR_CANTWRITE 13
+#define ERR_BADDECR 14
+#define ERR_UNKNMODE 15
+#define ERR_NOPASSWD 16
+#define ERR_BADPASSWD 17
+#define ERR_FMS 18
+#define ERR_GZIP 19
+#define ERR_READDISK 20
+
+
+/* Command to execute */
+#define CMD_VIEW 1
+#define CMD_VIEWFULL 2
+#define CMD_SHOWDIZ 3
+#define CMD_SHOWBANNER 4
+#define CMD_TEST 5
+#define CMD_UNPACK 6
+#define CMD_UNPKGZ 7
+#define CMD_EXTRACT 8
+
+
+#define OPT_VERBOSE 1
+#define OPT_QUIET 2
+
+
+USHORT DMS_Process_File(struct zfile *, struct zfile *, USHORT, USHORT, USHORT, USHORT);
+
diff --git a/dms/tables.c b/dms/tables.c
new file mode 100755 (executable)
index 0000000..ef80243
--- /dev/null
@@ -0,0 +1,87 @@
+
+/*
+ *     xDMS  v1.3  -  Portable DMS archive unpacker  -  Public Domain
+ *     Written by     Andre Rodrigues de la Rocha  <adlroc@usa.net>
+ *
+ *     Tables used in Medium and Deep compression modes
+ *
+ */
+
+
+#include "cdata.h"
+#include "tables.h"
+
+
+UCHAR d_code[256] = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+    0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+    0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+    0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+    0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+    0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+    0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
+    0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
+    0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
+    0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
+    0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
+    0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
+    0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
+    0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B,
+    0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F,
+    0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23,
+    0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
+    0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B,
+    0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F,
+    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+    0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+};
+
+
+
+UCHAR d_len[256] = {
+    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+    0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+    0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+    0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+    0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+    0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+    0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+    0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+    0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+    0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+    0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+    0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+    0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+    0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+    0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+};
+
+
diff --git a/dms/tables.h b/dms/tables.h
new file mode 100755 (executable)
index 0000000..9d557c3
--- /dev/null
@@ -0,0 +1,3 @@
+
+extern UCHAR d_code[], d_len[];
+
diff --git a/dms/u_deep.c b/dms/u_deep.c
new file mode 100755 (executable)
index 0000000..e1e5dca
--- /dev/null
@@ -0,0 +1,207 @@
+
+/*
+ *     xDMS  v1.3  -  Portable DMS archive unpacker  -  Public Domain
+ *     Written by     Andre Rodrigues de la Rocha  <adlroc@usa.net>
+ *
+ *     Lempel-Ziv-DynamicHuffman decompression functions used in Deep
+ *     mode.
+ *     Most routines ripped from LZHUF written by  Haruyasu Yoshizaki
+ *
+ */
+
+#include <string.h>
+
+#include "cdata.h"
+#include "tables.h"
+#include "u_deep.h"
+#include "getbits.h"
+
+
+INLINE USHORT DecodeChar(void);
+INLINE USHORT DecodePosition(void);
+INLINE void update(USHORT c);
+static void reconst(void);
+
+
+USHORT deep_text_loc;
+int init_deep_tabs=1;
+
+
+
+#define DBITMASK 0x3fff   /*  uses 16Kb dictionary  */
+
+#define F       60  /* lookahead buffer size */
+#define THRESHOLD   2
+#define N_CHAR      (256 - THRESHOLD + F)   /* kinds of characters (character code = 0..N_CHAR-1) */
+#define T       (N_CHAR * 2 - 1)    /* size of table */
+#define R       (T - 1)         /* position of root */
+#define MAX_FREQ    0x8000      /* updates tree when the */
+
+
+USHORT freq[T + 1]; /* frequency table */
+
+USHORT prnt[T + N_CHAR]; /* pointers to parent nodes, except for the */
+                               /* elements [T..T + N_CHAR - 1] which are used to get */
+                               /* the positions of leaves corresponding to the codes. */
+
+USHORT son[T];   /* pointers to child nodes (son[], son[] + 1) */
+
+
+
+void Init_DEEP_Tabs(void){
+       USHORT i, j;
+
+       for (i = 0; i < N_CHAR; i++) {
+               freq[i] = 1;
+               son[i] = (USHORT)(i + T);
+               prnt[i + T] = i;
+       }
+       i = 0; j = N_CHAR;
+       while (j <= R) {
+               freq[j] = (USHORT) (freq[i] + freq[i + 1]);
+               son[j] = i;
+               prnt[i] = prnt[i + 1] = j;
+               i += 2; j++;
+       }
+       freq[T] = 0xffff;
+       prnt[R] = 0;
+
+       init_deep_tabs = 0;
+}
+
+
+
+USHORT Unpack_DEEP(UCHAR *in, UCHAR *out, USHORT origsize){
+       USHORT i, j, c;
+       UCHAR *outend;
+
+       initbitbuf(in);
+
+       if (init_deep_tabs) Init_DEEP_Tabs();
+
+       outend = out+origsize;
+       while (out < outend) {
+               c = DecodeChar();
+               if (c < 256) {
+                       *out++ = text[deep_text_loc++ & DBITMASK] = (UCHAR)c;
+               } else {
+                       j = (USHORT) (c - 255 + THRESHOLD);
+                       i = (USHORT) (deep_text_loc - DecodePosition() - 1);
+                       while (j--) *out++ = text[deep_text_loc++ & DBITMASK] = text[i++ & DBITMASK];
+               }
+       }
+
+       deep_text_loc = (USHORT)((deep_text_loc+60) & DBITMASK);
+
+       return 0;
+}
+
+
+
+INLINE USHORT DecodeChar(void){
+       USHORT c;
+
+       c = son[R];
+
+       /* travel from root to leaf, */
+       /* choosing the smaller child node (son[]) if the read bit is 0, */
+       /* the bigger (son[]+1} if 1 */
+       while (c < T) {
+               c = son[c + GETBITS(1)];
+               DROPBITS(1);
+       }
+       c -= T;
+       update(c);
+       return c;
+}
+
+
+
+INLINE USHORT DecodePosition(void){
+       USHORT i, j, c;
+
+       i = GETBITS(8);  DROPBITS(8);
+       c = (USHORT) (d_code[i] << 8);
+       j = d_len[i];
+       i = (USHORT) (((i << j) | GETBITS(j)) & 0xff);  DROPBITS(j);
+
+       return (USHORT) (c | i) ;
+}
+
+
+
+/* reconstruction of tree */
+
+static void reconst(void){
+       USHORT i, j, k, f, l;
+
+       /* collect leaf nodes in the first half of the table */
+       /* and replace the freq by (freq + 1) / 2. */
+       j = 0;
+       for (i = 0; i < T; i++) {
+               if (son[i] >= T) {
+                       freq[j] = (USHORT) ((freq[i] + 1) / 2);
+                       son[j] = son[i];
+                       j++;
+               }
+       }
+       /* begin constructing tree by connecting sons */
+       for (i = 0, j = N_CHAR; j < T; i += 2, j++) {
+               k = (USHORT) (i + 1);
+               f = freq[j] = (USHORT) (freq[i] + freq[k]);
+               for (k = (USHORT)(j - 1); f < freq[k]; k--);
+               k++;
+               l = (USHORT)((j - k) * 2);
+               memmove(&freq[k + 1], &freq[k], (size_t)l);
+               freq[k] = f;
+               memmove(&son[k + 1], &son[k], (size_t)l);
+               son[k] = i;
+       }
+       /* connect prnt */
+       for (i = 0; i < T; i++) {
+               if ((k = son[i]) >= T) {
+                       prnt[k] = i;
+               } else {
+                       prnt[k] = prnt[k + 1] = i;
+               }
+       }
+}
+
+
+
+/* increment frequency of given code by one, and update tree */
+
+INLINE void update(USHORT c){
+       USHORT i, j, k, l;
+
+       if (freq[R] == MAX_FREQ) {
+               reconst();
+       }
+       c = prnt[c + T];
+       do {
+               k = ++freq[c];
+
+               /* if the order is disturbed, exchange nodes */
+               if (k > freq[l = (USHORT)(c + 1)]) {
+                       while (k > freq[++l]);
+                       l--;
+                       freq[c] = freq[l];
+                       freq[l] = k;
+
+                       i = son[c];
+                       prnt[i] = l;
+                       if (i < T) prnt[i + 1] = l;
+
+                       j = son[l];
+                       son[l] = i;
+
+                       prnt[j] = c;
+                       if (j < T) prnt[j + 1] = c;
+                       son[c] = j;
+
+                       c = l;
+               }
+       } while ((c = prnt[c]) != 0); /* repeat up to root */
+}
+
+
diff --git a/dms/u_deep.h b/dms/u_deep.h
new file mode 100755 (executable)
index 0000000..d87be1d
--- /dev/null
@@ -0,0 +1,7 @@
+
+
+USHORT Unpack_DEEP(UCHAR *, UCHAR *, USHORT);
+
+extern int init_deep_tabs;
+extern USHORT deep_text_loc;
+
diff --git a/dms/u_heavy.c b/dms/u_heavy.c
new file mode 100755 (executable)
index 0000000..fff93d3
--- /dev/null
@@ -0,0 +1,175 @@
+
+/*
+ *     xDMS  v1.3  -  Portable DMS archive unpacker  -  Public Domain
+ *     Written by     Andre Rodrigues de la Rocha  <adlroc@usa.net>
+ *
+ *     Lempel-Ziv-Huffman decompression functions used in Heavy 1 & 2 
+ *     compression modes. Based on LZH decompression functions from
+ *     UNIX LHA made by Masaru Oki
+ *
+ */
+
+
+#include "cdata.h"
+#include "u_heavy.h"
+#include "getbits.h"
+#include "maketbl.h"
+
+
+#define NC 510
+#define NPT 20
+#define N1 510
+#define OFFSET 253
+
+USHORT left[2 * NC - 1], right[2 * NC - 1 + 9];
+static UCHAR c_len[NC], pt_len[NPT];
+static USHORT c_table[4096], pt_table[256];
+static USHORT lastlen, np;
+USHORT heavy_text_loc;
+
+
+static USHORT read_tree_c(void);
+static USHORT read_tree_p(void);
+INLINE USHORT decode_c(void);
+INLINE USHORT decode_p(void);
+
+
+
+USHORT Unpack_HEAVY(UCHAR *in, UCHAR *out, UCHAR flags, USHORT origsize){
+       USHORT j, i, c, bitmask;
+       UCHAR *outend;
+
+       /*  Heavy 1 uses a 4Kb dictionary,  Heavy 2 uses 8Kb  */
+
+       if (flags & 8) {
+               np = 15;
+               bitmask = 0x1fff;
+       } else {
+               np = 14;
+               bitmask = 0x0fff;
+       }
+
+       initbitbuf(in);
+
+       if (flags & 2) {
+               if (read_tree_c()) return 1;
+               if (read_tree_p()) return 2;
+       }
+
+       outend = out+origsize;
+
+       while (out<outend) {
+               c = decode_c();
+               if (c < 256) {
+                       *out++ = text[heavy_text_loc++ & bitmask] = (UCHAR)c;
+               } else {
+                       j = (USHORT) (c - OFFSET);
+                       i = (USHORT) (heavy_text_loc - decode_p() - 1);
+                       while(j--) *out++ = text[heavy_text_loc++ & bitmask] = text[i++ & bitmask];
+               }
+       }
+
+       return 0;
+}
+
+
+
+INLINE USHORT decode_c(void){
+       USHORT i, j, m;
+
+       j = c_table[GETBITS(12)];
+       if (j < N1) {
+               DROPBITS(c_len[j]);
+       } else {
+               DROPBITS(12);
+               i = GETBITS(16);
+               m = 0x8000;
+               do {
+                       if (i & m) j = right[j];
+                       else              j = left [j];
+                       m >>= 1;
+               } while (j >= N1);
+               DROPBITS(c_len[j] - 12);
+       }
+       return j;
+}
+
+
+
+INLINE USHORT decode_p(void){
+       USHORT i, j, m;
+
+       j = pt_table[GETBITS(8)];
+       if (j < np) {
+               DROPBITS(pt_len[j]);
+       } else {
+               DROPBITS(8);
+               i = GETBITS(16);
+               m = 0x8000;
+               do {
+                       if (i & m) j = right[j];
+                       else             j = left [j];
+                       m >>= 1;
+               } while (j >= np);
+               DROPBITS(pt_len[j] - 8);
+       }
+
+       if (j != np-1) {
+               if (j > 0) {
+                       j = (USHORT)(GETBITS(i=(USHORT)(j-1)) | (1U << (j-1)));
+                       DROPBITS(i);
+               }
+               lastlen=j;
+       }
+
+       return lastlen;
+
+}
+
+
+
+static USHORT read_tree_c(void){
+       USHORT i,n;
+
+       n = GETBITS(9);
+       DROPBITS(9);
+       if (n>0){
+               for (i=0; i<n; i++) {
+                       c_len[i] = (UCHAR)GETBITS(5);
+                       DROPBITS(5);
+               }
+               for (i=n; i<510; i++) c_len[i] = 0;
+               if (make_table(510,c_len,12,c_table)) return 1;
+       } else {
+               n = GETBITS(9);
+               DROPBITS(9);
+               for (i=0; i<510; i++) c_len[i] = 0;
+               for (i=0; i<4096; i++) c_table[i] = n;
+       }
+       return 0;
+}
+
+
+
+static USHORT read_tree_p(void){
+       USHORT i,n;
+
+       n = GETBITS(5);
+       DROPBITS(5);
+       if (n>0){
+               for (i=0; i<n; i++) {
+                       pt_len[i] = (UCHAR)GETBITS(4);
+                       DROPBITS(4);
+               }
+               for (i=n; i<np; i++) pt_len[i] = 0;
+               if (make_table(np,pt_len,8,pt_table)) return 1;
+       } else {
+               n = GETBITS(5);
+               DROPBITS(5);
+               for (i=0; i<np; i++) pt_len[i] = 0;
+               for (i=0; i<256; i++) pt_table[i] = n;
+       }
+       return 0;
+}
+
+
diff --git a/dms/u_heavy.h b/dms/u_heavy.h
new file mode 100755 (executable)
index 0000000..35c77f3
--- /dev/null
@@ -0,0 +1,6 @@
+
+
+USHORT Unpack_HEAVY(UCHAR *, UCHAR *, UCHAR, USHORT);
+
+extern USHORT heavy_text_loc;
+
diff --git a/dms/u_init.c b/dms/u_init.c
new file mode 100755 (executable)
index 0000000..8b00288
--- /dev/null
@@ -0,0 +1,28 @@
+
+/*
+ *     xDMS  v1.3  -  Portable DMS archive unpacker  -  Public Domain
+ *     Written by     Andre Rodrigues de la Rocha  <adlroc@usa.net>
+ *
+ *     Decruncher reinitialization
+ *
+ */
+
+#include <string.h>
+
+#include "cdata.h"
+#include "u_init.h"
+#include "u_quick.h"
+#include "u_medium.h"
+#include "u_deep.h"
+#include "u_heavy.h"
+
+
+void Init_Decrunchers(void){
+       quick_text_loc = 251;
+       medium_text_loc = 0x3fbe;
+       heavy_text_loc = 0;
+       deep_text_loc = 0x3fc4;
+       init_deep_tabs = 1;
+       memset(text,0,0x3fc8);
+}
+
diff --git a/dms/u_init.h b/dms/u_init.h
new file mode 100755 (executable)
index 0000000..9a74d58
--- /dev/null
@@ -0,0 +1,3 @@
+
+void Init_Decrunchers(void);
+
diff --git a/dms/u_medium.c b/dms/u_medium.c
new file mode 100755 (executable)
index 0000000..6dd0b65
--- /dev/null
@@ -0,0 +1,58 @@
+
+/*
+ *     xDMS  v1.3  -  Portable DMS archive unpacker  -  Public Domain
+ *     Written by     Andre Rodrigues de la Rocha  <adlroc@usa.net>
+ *
+ *     Main decompression functions used in MEDIUM mode
+ *
+ */
+
+
+#include <string.h>
+
+#include "cdata.h"
+#include "u_medium.h"
+#include "getbits.h"
+#include "tables.h"
+
+
+#define MBITMASK 0x3fff
+
+
+USHORT medium_text_loc;
+
+
+
+USHORT Unpack_MEDIUM(UCHAR *in, UCHAR *out, USHORT origsize){
+       USHORT i, j, c;
+       UCHAR u, *outend;
+
+
+       initbitbuf(in);
+
+       outend = out+origsize;
+       while (out < outend) {
+               if (GETBITS(1)!=0) {
+                       DROPBITS(1);
+                       *out++ = text[medium_text_loc++ & MBITMASK] = (UCHAR)GETBITS(8);
+                       DROPBITS(8);
+               } else {
+                       DROPBITS(1);
+                       c = GETBITS(8);  DROPBITS(8);
+                       j = (USHORT) (d_code[c]+3);
+                       u = d_len[c];
+                       c = (USHORT) (((c << u) | GETBITS(u)) & 0xff);  DROPBITS(u);
+                       u = d_len[c];
+                       c = (USHORT) ((d_code[c] << 8) | (((c << u) | GETBITS(u)) & 0xff));  DROPBITS(u);
+                       i = (USHORT) (medium_text_loc - c - 1);
+
+                       while(j--) *out++ = text[medium_text_loc++ & MBITMASK] = text[i++ & MBITMASK];
+                       
+               }
+       }
+       medium_text_loc = (USHORT)((medium_text_loc+66) & MBITMASK);
+
+       return 0;
+}
+
+
diff --git a/dms/u_medium.h b/dms/u_medium.h
new file mode 100755 (executable)
index 0000000..3c1b4fc
--- /dev/null
@@ -0,0 +1,5 @@
+
+USHORT Unpack_MEDIUM(UCHAR *, UCHAR *, USHORT);
+
+extern USHORT medium_text_loc;
+
diff --git a/dms/u_quick.c b/dms/u_quick.c
new file mode 100755 (executable)
index 0000000..74131c2
--- /dev/null
@@ -0,0 +1,47 @@
+
+/*
+ *     xDMS  v1.3  -  Portable DMS archive unpacker  -  Public Domain
+ *     Written by     Andre Rodrigues de la Rocha  <adlroc@usa.net>
+ *
+ *
+ */
+
+
+#include <string.h>
+
+#include "cdata.h"
+#include "u_quick.h"
+#include "getbits.h"
+
+
+#define QBITMASK 0xff
+
+
+USHORT quick_text_loc;
+
+
+USHORT Unpack_QUICK(UCHAR *in, UCHAR *out, USHORT origsize){
+       USHORT i, j;
+       UCHAR *outend;
+
+       initbitbuf(in);
+
+       outend = out+origsize;
+       while (out < outend) {
+               if (GETBITS(1)!=0) {
+                       DROPBITS(1);
+                       *out++ = text[quick_text_loc++ & QBITMASK] = (UCHAR)GETBITS(8);  DROPBITS(8);
+               } else {
+                       DROPBITS(1);
+                       j = (USHORT) (GETBITS(2)+2);  DROPBITS(2);
+                       i = (USHORT) (quick_text_loc - GETBITS(8) - 1);  DROPBITS(8);
+                       while(j--) {
+                               *out++ = text[quick_text_loc++ & QBITMASK] = text[i++ & QBITMASK];
+                       }
+               }
+       }
+       quick_text_loc = (USHORT)((quick_text_loc+5) & QBITMASK);
+
+       return 0;
+}
+
diff --git a/dms/u_quick.h b/dms/u_quick.h
new file mode 100755 (executable)
index 0000000..9518815
--- /dev/null
@@ -0,0 +1,5 @@
+
+USHORT Unpack_QUICK(UCHAR *, UCHAR *, USHORT);
+
+extern USHORT quick_text_loc;
+
diff --git a/dms/u_rle.c b/dms/u_rle.c
new file mode 100755 (executable)
index 0000000..ff46c56
--- /dev/null
@@ -0,0 +1,42 @@
+
+/*
+ *     xDMS  v1.3  -  Portable DMS archive unpacker  -  Public Domain
+ *     Written by     Andre Rodrigues de la Rocha  <adlroc@usa.net>
+ *
+ *     Run Length Encoding decompression function used in most
+ *     modes after decompression by other algorithm
+ *
+ */
+
+#include <string.h>
+#include "cdata.h"
+#include "u_rle.h"
+
+
+
+USHORT Unpack_RLE(UCHAR *in, UCHAR *out, USHORT origsize){
+       USHORT n;
+       UCHAR a,b, *outend;
+
+       outend = out+origsize;
+       while (out<outend){
+               if ((a = *in++) != 0x90)
+                       *out++ = a;
+               else if (!(b = *in++))
+                       *out++ = a;
+               else {
+                       a = *in++;
+                       if (b == 0xff) {
+                               n = *in++;
+                               n = (USHORT)((n<<8) + *in++);
+                       } else
+                               n = b;
+                       if (out+n > outend) return 1;
+                       memset(out,a,(size_t) n);
+                       out += n;
+               }
+       }
+       return 0;
+}
+
+
diff --git a/dms/u_rle.h b/dms/u_rle.h
new file mode 100755 (executable)
index 0000000..0cf2493
--- /dev/null
@@ -0,0 +1,3 @@
+
+USHORT Unpack_RLE(UCHAR *, UCHAR *, USHORT);
+
diff --git a/drawing.c b/drawing.c
new file mode 100755 (executable)
index 0000000..e758bb8
--- /dev/null
+++ b/drawing.c
@@ -0,0 +1,2077 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Screen drawing functions
+  *
+  * Copyright 1995-2000 Bernd Schmidt
+  * Copyright 1995 Alessandro Bissacco
+  * Copyright 2000,2001 Toni Wilen
+  */
+
+/* There are a couple of concepts of "coordinates" in this file.
+   - DIW coordinates
+   - DDF coordinates (essentially cycles, resolution lower than lores by a factor of 2)
+   - Pixel coordinates
+     * in the Amiga's resolution as determined by BPLCON0 ("Amiga coordinates")
+     * in the window resolution as determined by the preferences ("window coordinates").
+     * in the window resolution, and with the origin being the topmost left corner of
+       the window ("native coordinates")
+   One note about window coordinates.  The visible area depends on the width of the
+   window, and the centering code.  The first visible horizontal window coordinate is
+   often _not_ 0, but the value of VISIBLE_LEFT_BORDER instead.
+
+   One important thing to remember: DIW coordinates are in the lowest possible
+   resolution.
+
+   To prevent extremely bad things (think pixels cut in half by window borders) from
+   happening, all ports should restrict window widths to be multiples of 16 pixels.  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <ctype.h>
+#include <assert.h>
+
+#include "config.h"
+#include "options.h"
+#include "threaddep/thread.h"
+#include "uae.h"
+#include "memory.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "xwin.h"
+#include "autoconf.h"
+#include "gui.h"
+#include "picasso96.h"
+#include "drawing.h"
+#include "compemu.h"
+#include "savestate.h"
+
+int lores_factor, lores_shift;
+
+/* The shift factor to apply when converting between Amiga coordinates and window
+   coordinates.  Zero if the resolution is the same, positive if window coordinates
+   have a higher resolution (i.e. we're stretching the image), negative if window
+   coordinates have a lower resolution (i.e. we're shrinking the image).  */
+static int res_shift;
+
+static int interlace_seen = 0;
+#define AUTO_LORES_FRAMES 10
+static int can_use_lores = 0;
+
+/* Lookup tables for dual playfields.  The dblpf_*1 versions are for the case
+   that playfield 1 has the priority, dbplpf_*2 are used if playfield 2 has
+   priority.  If we need an array for non-dual playfield mode, it has no number.  */
+/* The dbplpf_ms? arrays contain a shift value.  plf_spritemask is initialized
+   to contain two 16 bit words, with the appropriate mask if pf1 is in the
+   foreground being at bit offset 0, the one used if pf2 is in front being at
+   offset 16.  */
+
+static int dblpf_ms1[256], dblpf_ms2[256], dblpf_ms[256];
+static int dblpf_ind1[256], dblpf_ind2[256];
+
+static int dblpf_2nd1[256], dblpf_2nd2[256];
+
+static int dblpfofs[] = { 0, 2, 4, 8, 16, 32, 64, 128 };
+
+static int sprite_offs[256];
+
+static uae_u32 clxtab[256];
+
+/* Video buffer description structure. Filled in by the graphics system
+ * dependent code. */
+
+struct vidbuf_description gfxvidinfo;
+
+/* OCS/ECS color lookup table. */
+xcolnr xcolors[4096];
+
+#ifdef AGA
+static uae_u8 spriteagadpfpixels[MAX_PIXELS_PER_LINE * 2]; /* AGA dualplayfield sprite */
+/* AGA mode color lookup tables */
+unsigned int xredcolors[256], xgreencolors[256], xbluecolors[256];
+static int dblpf_ind1_aga[256], dblpf_ind2_aga[256];
+#else
+static uae_u8 spriteagadpfpixels[1];
+static int dblpf_ind1_aga[1], dblpf_ind2_aga[1];
+#endif
+
+struct color_entry colors_for_drawing;
+
+/* The size of these arrays is pretty arbitrary; it was chosen to be "more
+   than enough".  The coordinates used for indexing into these arrays are
+   almost, but not quite, Amiga coordinates (there's a constant offset).  */
+union {
+    /* Let's try to align this thing. */
+    double uupzuq;
+    long int cruxmedo;
+    uae_u8 apixels[MAX_PIXELS_PER_LINE * 2];
+    uae_u16 apixels_w[MAX_PIXELS_PER_LINE * 2 / 2];
+    uae_u32 apixels_l[MAX_PIXELS_PER_LINE * 2 / 4];
+} pixdata;
+
+uae_u16 spixels[2 * MAX_SPR_PIXELS];
+/* Eight bits for every pixel.  */
+union sps_union spixstate;
+
+static uae_u32 ham_linebuf[MAX_PIXELS_PER_LINE * 2];
+
+char *xlinebuffer;
+
+static int *amiga2aspect_line_map, *native2amiga_line_map;
+static char *row_map[MAX_VIDHEIGHT];
+static int max_drawn_amiga_line;
+
+/* line_draw_funcs: pfield_do_linetoscr, pfield_do_fill_line, decode_ham */
+typedef void (*line_draw_func)(int, int);
+
+#define LINE_UNDECIDED 1
+#define LINE_DECIDED 2
+#define LINE_DECIDED_DOUBLE 3
+#define LINE_AS_PREVIOUS 4
+#define LINE_BLACK 5
+#define LINE_REMEMBERED_AS_BLACK 6
+#define LINE_DONE 7
+#define LINE_DONE_AS_PREVIOUS 8
+#define LINE_REMEMBERED_AS_PREVIOUS 9
+
+static char *line_drawn;
+static char linestate[(MAXVPOS + 1)*2 + 1];
+
+uae_u8 line_data[(MAXVPOS + 1) * 2][MAX_PLANES * MAX_WORDS_PER_LINE * 2];
+
+/* Centering variables.  */
+static int min_diwstart, max_diwstop, prev_x_adjust;
+/* The visible window: VISIBLE_LEFT_BORDER contains the left border of the visible
+   area, VISIBLE_RIGHT_BORDER the right border.  These are in window coordinates.  */
+static int visible_left_border, visible_right_border;
+static int linetoscr_x_adjust_bytes;
+static int thisframe_y_adjust, prev_y_adjust;
+static int thisframe_y_adjust_real, max_ypos_thisframe, min_ypos_for_screen;
+static int extra_y_adjust;
+int thisframe_first_drawn_line, thisframe_last_drawn_line;
+
+/* A frame counter that forces a redraw after at least one skipped frame in
+   interlace mode.  */
+static int last_redraw_point;
+
+static int first_drawn_line, last_drawn_line;
+static int first_block_line, last_block_line;
+
+/* These are generated by the drawing code from the line_decisions array for
+   each line that needs to be drawn.  These are basically extracted out of
+   bit fields in the hardware registers.  */
+static int bplehb, bplham, bpldualpf, bpldualpfpri, bpldualpf2of, bplplanecnt, bplres;
+static int plf1pri, plf2pri;
+static uae_u32 plf_sprite_mask;
+static int sbasecol[2] = { 16, 16 };
+static int brdsprt, brdblank;
+
+int picasso_requested_on;
+int picasso_on;
+
+uae_sem_t gui_sem;
+int inhibit_frame;
+
+int framecnt = 0;
+static int frame_redraw_necessary;
+static int picasso_redraw_necessary;
+
+STATIC_INLINE void count_frame (void)
+{
+    framecnt++;
+    if (framecnt >= currprefs.gfx_framerate)
+       framecnt = 0;
+}
+
+int coord_native_to_amiga_x (int x)
+{
+    x += visible_left_border;
+    x <<= (1 - lores_shift);
+    return x + 2*DISPLAY_LEFT_SHIFT - 2*DIW_DDF_OFFSET;
+}
+
+int coord_native_to_amiga_y (int y)
+{
+    return native2amiga_line_map[y] + thisframe_y_adjust - minfirstline;
+}
+
+STATIC_INLINE int res_shift_from_window (int x)
+{
+    if (res_shift >= 0)
+       return x >> res_shift;
+    return x << -res_shift;
+}
+
+STATIC_INLINE int res_shift_from_amiga (int x)
+{
+    if (res_shift >= 0)
+       return x >> res_shift;
+    return x << -res_shift;
+}
+
+void notice_screen_contents_lost (void)
+{
+    picasso_redraw_necessary = 1;
+    frame_redraw_necessary = 2;
+}
+
+static struct decision *dp_for_drawing;
+static struct draw_info *dip_for_drawing;
+
+/* Record DIW of the current line for use by centering code.  */
+void record_diw_line (int first, int last)
+{
+    if (last > max_diwstop)
+       max_diwstop = last;
+    if (first < min_diwstart)
+       min_diwstart = first;
+}
+
+/*
+ * Screen update macros/functions
+ */
+
+/* The important positions in the line: where do we start drawing the left border,
+   where do we start drawing the playfield, where do we start drawing the right border.
+   All of these are forced into the visible window (VISIBLE_LEFT_BORDER .. VISIBLE_RIGHT_BORDER).
+   PLAYFIELD_START and PLAYFIELD_END are in window coordinates.  */
+static int playfield_start, playfield_end;
+static int real_playfield_start, real_playfield_end;
+
+static int pixels_offset;
+static int src_pixel;
+/* How many pixels in window coordinates which are to the left of the left border.  */
+static int unpainted;
+
+/* Initialize the variables necessary for drawing a line.
+ * This involves setting up start/stop positions and display window
+ * borders.  */
+static void pfield_init_linetoscr (void)
+{
+    /* First, get data fetch start/stop in DIW coordinates.  */
+    int ddf_left = dp_for_drawing->plfleft * 2 + DIW_DDF_OFFSET;
+    int ddf_right = dp_for_drawing->plfright * 2 + DIW_DDF_OFFSET;
+    /* Compute datafetch start/stop in pixels; native display coordinates.  */
+    int native_ddf_left = coord_hw_to_window_x (ddf_left);
+    int native_ddf_right = coord_hw_to_window_x (ddf_right);
+
+    int linetoscr_diw_start = dp_for_drawing->diwfirstword;
+    int linetoscr_diw_end = dp_for_drawing->diwlastword;
+
+    if (dip_for_drawing->nr_sprites == 0) {
+       if (linetoscr_diw_start < native_ddf_left)
+           linetoscr_diw_start = native_ddf_left;
+       if (linetoscr_diw_end > native_ddf_right)
+           linetoscr_diw_end = native_ddf_right;
+    }
+
+    /* Perverse cases happen. */
+    if (linetoscr_diw_end < linetoscr_diw_start)
+       linetoscr_diw_end = linetoscr_diw_start;
+
+    playfield_start = linetoscr_diw_start;
+    playfield_end = linetoscr_diw_end;
+    
+    if (playfield_start < visible_left_border)
+       playfield_start = visible_left_border;
+    if (playfield_start > visible_right_border)
+       playfield_start = visible_right_border;
+    if (playfield_end < visible_left_border)
+       playfield_end = visible_left_border;
+    if (playfield_end > visible_right_border)
+       playfield_end = visible_right_border;
+
+    real_playfield_end = playfield_end;
+    real_playfield_start = playfield_start;
+#ifdef AGA
+    if (brdsprt && dip_for_drawing->nr_sprites) {
+        int min = visible_right_border, max = visible_left_border, i;
+        for (i = 0; i < dip_for_drawing->nr_sprites; i++) {
+           int x;
+           x = curr_sprite_entries[dip_for_drawing->first_sprite_entry + i].pos;
+           if (x < min) min = x;
+           x = curr_sprite_entries[dip_for_drawing->first_sprite_entry + i].max;
+           if (x > max) max = x;
+       }
+       min += (DIW_DDF_OFFSET - DISPLAY_LEFT_SHIFT) << (2 - lores_shift);
+       max += (DIW_DDF_OFFSET - DISPLAY_LEFT_SHIFT) << (2 - lores_shift);
+       if (min < playfield_start)
+           playfield_start = min;
+        if (playfield_start < visible_left_border)
+           playfield_start = visible_left_border;
+       if (max > playfield_end)
+           playfield_end = max;
+        if (playfield_end > visible_right_border)
+           playfield_end = visible_right_border;
+    }    
+#endif
+    /* Now, compute some offsets.  */
+
+    res_shift = lores_shift - bplres;
+    ddf_left -= DISPLAY_LEFT_SHIFT;
+    ddf_left <<= bplres;
+    pixels_offset = MAX_PIXELS_PER_LINE - ddf_left;
+
+    unpainted = visible_left_border < playfield_start ? 0 : visible_left_border - playfield_start;
+    src_pixel = MAX_PIXELS_PER_LINE + res_shift_from_window (playfield_start - native_ddf_left + unpainted);
+
+    if (dip_for_drawing->nr_sprites == 0)
+       return;
+    /* Must clear parts of apixels.  */
+    if (linetoscr_diw_start < native_ddf_left) {
+       int size = res_shift_from_window (native_ddf_left - linetoscr_diw_start);
+       linetoscr_diw_start = native_ddf_left;
+       memset (pixdata.apixels + MAX_PIXELS_PER_LINE - size, 0, size);
+    }
+    if (linetoscr_diw_end > native_ddf_right) {
+       int pos = res_shift_from_window (native_ddf_right - native_ddf_left);
+       int size = res_shift_from_window (linetoscr_diw_end - native_ddf_right);
+       linetoscr_diw_start = native_ddf_left;
+       memset (pixdata.apixels + MAX_PIXELS_PER_LINE + pos, 0, size);
+    }
+}
+
+/* If C++ compilers didn't suck, we'd use templates.  */
+
+#define TYPE uae_u8
+#define LNAME linetoscr_8
+#define SRC_INC 1
+#define HDOUBLE 0
+#define AGAC 0
+#include "linetoscr.c"
+#define LNAME linetoscr_8_stretch1
+#define SRC_INC 1
+#define HDOUBLE 1
+#define AGAC 0
+#include "linetoscr.c"
+#define LNAME linetoscr_8_shrink1
+#define SRC_INC 2
+#define HDOUBLE 0
+#define AGAC 0
+#include "linetoscr.c"
+
+#ifdef AGA
+#define LNAME linetoscr_8_aga
+#define SRC_INC 1
+#define HDOUBLE 0
+#define AGAC 1
+#include "linetoscr.c"
+#define LNAME linetoscr_8_stretch1_aga
+#define SRC_INC 1
+#define HDOUBLE 1
+#define AGAC 1
+#include "linetoscr.c"
+#define LNAME linetoscr_8_shrink1_aga
+#define SRC_INC 2
+#define HDOUBLE 0
+#define AGAC 1
+#include "linetoscr.c"
+#endif
+
+#undef TYPE
+
+#define TYPE uae_u16
+#define LNAME linetoscr_16
+#define SRC_INC 1
+#define HDOUBLE 0
+#define AGAC 0
+#include "linetoscr.c"
+#define LNAME linetoscr_16_stretch1
+#define SRC_INC 1
+#define HDOUBLE 1
+#define AGAC 0
+#include "linetoscr.c"
+#define LNAME linetoscr_16_shrink1
+#define SRC_INC 2
+#define HDOUBLE 0
+#define AGAC 0
+#include "linetoscr.c"
+
+#ifdef AGA
+#define LNAME linetoscr_16_aga
+#define SRC_INC 1
+#define HDOUBLE 0
+#define AGAC 1
+#include "linetoscr.c"
+#define LNAME linetoscr_16_stretch1_aga
+#define SRC_INC 1
+#define HDOUBLE 1
+#define AGAC 1
+#include "linetoscr.c"
+#define LNAME linetoscr_16_shrink1_aga
+#define SRC_INC 2
+#define HDOUBLE 0
+#define AGAC 1
+#include "linetoscr.c"
+#endif
+
+#undef TYPE
+
+#define TYPE uae_u32
+#define LNAME linetoscr_32
+#define SRC_INC 1
+#define HDOUBLE 0
+#define AGAC 0
+#include "linetoscr.c"
+#define LNAME linetoscr_32_stretch1
+#define SRC_INC 1
+#define HDOUBLE 1
+#define AGAC 0
+#include "linetoscr.c"
+#define LNAME linetoscr_32_shrink1
+#define SRC_INC 2
+#define HDOUBLE 0
+#define AGAC 0
+#include "linetoscr.c"
+
+#ifdef AGA
+#define LNAME linetoscr_32_aga
+#define SRC_INC 1
+#define HDOUBLE 0
+#define AGAC 1
+#include "linetoscr.c"
+#define LNAME linetoscr_32_stretch1_aga
+#define SRC_INC 1
+#define HDOUBLE 1
+#define AGAC 1
+#include "linetoscr.c"
+#define LNAME linetoscr_32_shrink1_aga
+#define SRC_INC 2
+#define HDOUBLE 0
+#define AGAC 1
+#include "linetoscr.c"
+#endif
+
+#undef TYPE
+
+static void fill_line_8 (char *buf, int start, int stop)
+{
+    uae_u8 *b = (uae_u8 *)buf;
+    int i;
+    xcolnr col = brdblank ? 0 : colors_for_drawing.acolors[0];
+    for (i = start; i < stop; i++)
+       b[i] = (uae_u8)col;
+}
+static void fill_line_16 (char *buf, int start, int stop)
+{
+    uae_u16 *b = (uae_u16 *)buf;
+    int i;
+    xcolnr col = brdblank ? 0 : colors_for_drawing.acolors[0];
+    for (i = start; i < stop; i++)
+       b[i] = (uae_u16)col;
+}
+static void fill_line_32 (char *buf, int start, int stop)
+{
+    uae_u32 *b = (uae_u32 *)buf;
+    int i;
+    xcolnr col = brdblank ? 0 : colors_for_drawing.acolors[0];
+    for (i = start; i < stop; i++)
+       b[i] = col;
+}
+
+STATIC_INLINE void fill_line (void)
+{
+    int shift;
+    int nints, nrem;
+    int *start;
+    xcolnr val;
+
+    shift = 0;
+    if (gfxvidinfo.pixbytes == 2)
+       shift = 1;
+    if (gfxvidinfo.pixbytes == 4)
+       shift = 2;
+
+    nints = gfxvidinfo.width >> (2-shift);
+    nrem = nints & 7;
+    nints &= ~7;
+    start = (int *)(((char *)xlinebuffer) + (visible_left_border << shift));
+#ifdef AGA
+    val = brdblank ? 0 : colors_for_drawing.acolors[0];
+#else
+    val = colors_for_drawing.acolors[0];
+#endif
+    if (gfxvidinfo.pixbytes == 2)
+        val |= val << 16;
+    for (; nints > 0; nints -= 8, start += 8) {
+       *start = val;
+       *(start+1) = val;
+       *(start+2) = val;
+       *(start+3) = val;
+       *(start+4) = val;
+       *(start+5) = val;
+       *(start+6) = val;
+       *(start+7) = val;
+    }
+
+    switch (nrem) {
+     case 7:
+       *start++ = val;
+     case 6:
+       *start++ = val;
+     case 5:
+       *start++ = val;
+     case 4:
+       *start++ = val;
+     case 3:
+       *start++ = val;
+     case 2:
+       *start++ = val;
+     case 1:
+       *start = val;
+    }
+}
+
+static int linetoscr_double_offset;
+
+static void pfield_do_linetoscr (int start, int stop)
+{
+#ifdef AGA
+    if (currprefs.chipset_mask & CSMASK_AGA) {
+        if (res_shift == 0)
+           switch (gfxvidinfo.pixbytes) {
+           case 1: src_pixel = linetoscr_8_aga (src_pixel, start, stop); break;
+           case 2: src_pixel = linetoscr_16_aga (src_pixel, start, stop); break;
+           case 4: src_pixel = linetoscr_32_aga (src_pixel, start, stop); break;
+           }
+       else if (res_shift > 0)
+           switch (gfxvidinfo.pixbytes) {
+           case 1: src_pixel = linetoscr_8_stretch1_aga (src_pixel, start, stop); break;
+           case 2: src_pixel = linetoscr_16_stretch1_aga (src_pixel, start, stop); break;
+           case 4: src_pixel = linetoscr_32_stretch1_aga (src_pixel, start, stop); break;
+           }
+       else if (res_shift < 0)
+           switch (gfxvidinfo.pixbytes) {
+           case 1: src_pixel = linetoscr_8_shrink1_aga (src_pixel, start, stop); break;
+           case 2: src_pixel = linetoscr_16_shrink1_aga (src_pixel, start, stop); break;
+           case 4: src_pixel = linetoscr_32_shrink1_aga (src_pixel, start, stop); break;
+           }
+    } else {
+#endif
+        if (res_shift == 0)
+           switch (gfxvidinfo.pixbytes) {
+           case 1: src_pixel = linetoscr_8 (src_pixel, start, stop); break;
+           case 2: src_pixel = linetoscr_16 (src_pixel, start, stop); break;
+           case 4: src_pixel = linetoscr_32 (src_pixel, start, stop); break;
+           }
+       else if (res_shift > 0)
+           switch (gfxvidinfo.pixbytes) {
+           case 1: src_pixel = linetoscr_8_stretch1 (src_pixel, start, stop); break;
+           case 2: src_pixel = linetoscr_16_stretch1 (src_pixel, start, stop); break;
+           case 4: src_pixel = linetoscr_32_stretch1 (src_pixel, start, stop); break;
+           }
+       else if (res_shift < 0)
+           switch (gfxvidinfo.pixbytes) {
+           case 1: src_pixel = linetoscr_8_shrink1 (src_pixel, start, stop); break;
+           case 2: src_pixel = linetoscr_16_shrink1 (src_pixel, start, stop); break;
+           case 4: src_pixel = linetoscr_32_shrink1 (src_pixel, start, stop); break;
+           }
+#ifdef AGA
+    }
+#endif
+}
+
+static void pfield_do_fill_line (int start, int stop)
+{
+    switch (gfxvidinfo.pixbytes) {
+    case 1: fill_line_8 (xlinebuffer, start, stop); break;
+    case 2: fill_line_16 (xlinebuffer, start, stop); break;
+    case 4: fill_line_32 (xlinebuffer, start, stop); break;
+    }
+}
+
+static void pfield_do_linetoscr_full (int double_line)
+{
+    char *oldxlb = (char *)xlinebuffer;
+    int old_src_pixel = src_pixel;
+
+    pfield_do_linetoscr (playfield_start, playfield_end);
+    xlinebuffer = oldxlb + linetoscr_double_offset;
+    src_pixel = old_src_pixel;
+    pfield_do_linetoscr (playfield_start, playfield_end);
+}
+
+static void dummy_worker (int start, int stop)
+{
+}
+
+static unsigned int ham_lastcolor;
+
+static int ham_decode_pixel;
+
+/* Decode HAM in the invisible portion of the display (left of VISIBLE_LEFT_BORDER),
+   but don't draw anything in.  This is done to prepare HAM_LASTCOLOR for later,
+   when decode_ham runs.  */
+static void init_ham_decoding (void)
+{
+    int unpainted_amiga = res_shift_from_window (unpainted);
+    ham_decode_pixel = src_pixel;
+    ham_lastcolor = color_reg_get (&colors_for_drawing, 0);
+
+    if (! bplham || (bplplanecnt != 6 && ((currprefs.chipset_mask & CSMASK_AGA) == 0 || bplplanecnt != 8))) {
+       if (unpainted_amiga > 0) {
+           int pv = pixdata.apixels[ham_decode_pixel + unpainted_amiga - 1];
+#ifdef AGA
+           if (currprefs.chipset_mask & CSMASK_AGA)
+               ham_lastcolor = colors_for_drawing.color_regs_aga[pv];
+           else
+#endif
+               ham_lastcolor = colors_for_drawing.color_regs_ecs[pv];
+       }
+#ifdef AGA
+    } else if (currprefs.chipset_mask & CSMASK_AGA) {
+       if (bplplanecnt == 8) { /* AGA mode HAM8 */
+           while (unpainted_amiga-- > 0) {
+               int pv = pixdata.apixels[ham_decode_pixel++];
+               switch (pv & 0x3) {
+               case 0x0: ham_lastcolor = colors_for_drawing.color_regs_aga[pv >> 2]; break;
+               case 0x1: ham_lastcolor &= 0xFFFF03; ham_lastcolor |= (pv & 0xFC); break;
+               case 0x2: ham_lastcolor &= 0x03FFFF; ham_lastcolor |= (pv & 0xFC) << 16; break;
+               case 0x3: ham_lastcolor &= 0xFF03FF; ham_lastcolor |= (pv & 0xFC) << 8; break;
+               }
+           }
+       } else if (bplplanecnt == 6) { /* AGA mode HAM6 */
+           while (unpainted_amiga-- > 0) {
+               int pv = pixdata.apixels[ham_decode_pixel++];
+               switch (pv & 0x30) {
+               case 0x00: ham_lastcolor = colors_for_drawing.color_regs_aga[pv]; break;
+               case 0x10: ham_lastcolor &= 0xFFFF00; ham_lastcolor |= (pv & 0xF) << 4; break;
+               case 0x20: ham_lastcolor &= 0x00FFFF; ham_lastcolor |= (pv & 0xF) << 20; break;
+               case 0x30: ham_lastcolor &= 0xFF00FF; ham_lastcolor |= (pv & 0xF) << 12; break;
+               }
+           }
+       }
+#endif
+    } else {
+        if (bplplanecnt == 6) { /* OCS/ECS mode HAM6 */
+           while (unpainted_amiga-- > 0) {
+               int pv = pixdata.apixels[ham_decode_pixel++];
+               switch (pv & 0x30) {
+               case 0x00: ham_lastcolor = colors_for_drawing.color_regs_ecs[pv]; break;
+               case 0x10: ham_lastcolor &= 0xFF0; ham_lastcolor |= (pv & 0xF); break;
+               case 0x20: ham_lastcolor &= 0x0FF; ham_lastcolor |= (pv & 0xF) << 8; break;
+               case 0x30: ham_lastcolor &= 0xF0F; ham_lastcolor |= (pv & 0xF) << 4; break;
+               }
+           }
+       }
+    }
+}
+
+static void decode_ham (int pix, int stoppos)
+{
+    int todraw_amiga = res_shift_from_window (stoppos - pix);
+
+    if (! bplham || (bplplanecnt != 6 && ((currprefs.chipset_mask & CSMASK_AGA) == 0 || bplplanecnt != 8))) {
+       while (todraw_amiga-- > 0) {
+           int pv = pixdata.apixels[ham_decode_pixel];
+#ifdef AGA
+           if (currprefs.chipset_mask & CSMASK_AGA)
+               ham_lastcolor = colors_for_drawing.color_regs_aga[pv];
+           else
+#endif
+               ham_lastcolor = colors_for_drawing.color_regs_ecs[pv];
+
+           ham_linebuf[ham_decode_pixel++] = ham_lastcolor;
+       }
+#ifdef AGA
+    } else if (currprefs.chipset_mask & CSMASK_AGA) {
+       if (bplplanecnt == 8) { /* AGA mode HAM8 */
+           while (todraw_amiga-- > 0) {
+               int pv = pixdata.apixels[ham_decode_pixel];
+               switch (pv & 0x3) {
+               case 0x0: ham_lastcolor = colors_for_drawing.color_regs_aga[pv >> 2]; break;
+               case 0x1: ham_lastcolor &= 0xFFFF03; ham_lastcolor |= (pv & 0xFC); break;
+               case 0x2: ham_lastcolor &= 0x03FFFF; ham_lastcolor |= (pv & 0xFC) << 16; break;
+               case 0x3: ham_lastcolor &= 0xFF03FF; ham_lastcolor |= (pv & 0xFC) << 8; break;
+               }
+               ham_linebuf[ham_decode_pixel++] = ham_lastcolor;
+           }
+       } else if (bplplanecnt == 6) { /* AGA mode HAM6 */
+           while (todraw_amiga-- > 0) {
+               int pv = pixdata.apixels[ham_decode_pixel];
+               switch (pv & 0x30) {
+               case 0x00: ham_lastcolor = colors_for_drawing.color_regs_aga[pv]; break;
+               case 0x10: ham_lastcolor &= 0xFFFF00; ham_lastcolor |= (pv & 0xF) << 4; break;
+               case 0x20: ham_lastcolor &= 0x00FFFF; ham_lastcolor |= (pv & 0xF) << 20; break;
+               case 0x30: ham_lastcolor &= 0xFF00FF; ham_lastcolor |= (pv & 0xF) << 12; break;
+               }
+               ham_linebuf[ham_decode_pixel++] = ham_lastcolor;
+           }
+       }
+#endif
+    } else {
+        if (bplplanecnt == 6) { /* OCS/ECS mode HAM6 */
+           while (todraw_amiga-- > 0) {
+               int pv = pixdata.apixels[ham_decode_pixel];
+               switch (pv & 0x30) {
+               case 0x00: ham_lastcolor = colors_for_drawing.color_regs_ecs[pv]; break;
+               case 0x10: ham_lastcolor &= 0xFF0; ham_lastcolor |= (pv & 0xF); break;
+               case 0x20: ham_lastcolor &= 0x0FF; ham_lastcolor |= (pv & 0xF) << 8; break;
+               case 0x30: ham_lastcolor &= 0xF0F; ham_lastcolor |= (pv & 0xF) << 4; break;
+               }
+               ham_linebuf[ham_decode_pixel++] = ham_lastcolor;
+           }
+       }
+    }
+}
+
+static void gen_pfield_tables (void)
+{
+    int i;
+
+    /* For now, the AGA stuff is broken in the dual playfield case. We encode
+     * sprites in dpf mode by ORing the pixel value with 0x80. To make dual
+     * playfield rendering easy, the lookup tables contain are made linear for
+     * values >= 128. That only works for OCS/ECS, though. */
+
+    for (i = 0; i < 256; i++) {
+       int plane1 = (i & 1) | ((i >> 1) & 2) | ((i >> 2) & 4) | ((i >> 3) & 8);
+       int plane2 = ((i >> 1) & 1) | ((i >> 2) & 2) | ((i >> 3) & 4) | ((i >> 4) & 8);
+
+       dblpf_2nd1[i] = plane1 == 0 ? (plane2 == 0 ? 0 : 2) : 1;
+       dblpf_2nd2[i] = plane2 == 0 ? (plane1 == 0 ? 0 : 1) : 2;
+
+#ifdef AGA
+       dblpf_ind1_aga[i] = plane1 == 0 ? plane2 : plane1;
+       dblpf_ind2_aga[i] = plane2 == 0 ? plane1 : plane2;
+#endif
+
+       dblpf_ms1[i] = plane1 == 0 ? (plane2 == 0 ? 16 : 8) : 0;
+       dblpf_ms2[i] = plane2 == 0 ? (plane1 == 0 ? 16 : 0) : 8;
+       dblpf_ms[i] = i == 0 ? 16 : 8;
+       if (plane2 > 0)
+           plane2 += 8;
+       dblpf_ind1[i] = i >= 128 ? i & 0x7F : (plane1 == 0 ? plane2 : plane1);
+       dblpf_ind2[i] = i >= 128 ? i & 0x7F : (plane2 == 0 ? plane1 : plane2);
+
+       sprite_offs[i] = (i & 15) ? 0 : 2;
+
+       clxtab[i] = ((((i & 3) && (i & 12)) << 9)
+                    | (((i & 3) && (i & 48)) << 10)
+                    | (((i & 3) && (i & 192)) << 11)
+                    | (((i & 12) && (i & 48)) << 12)
+                    | (((i & 12) && (i & 192)) << 13)
+                    | (((i & 48) && (i & 192)) << 14));
+
+    }
+}
+
+#define SPRITE_DEBUG 0
+
+/* When looking at this function and the ones that inline it, bear in mind
+   what an optimizing compiler will do with this code.  All callers of this
+   function only pass in constant arguments (except for E).  This means
+   that many of the if statements will go away completely after inlining.  */
+STATIC_INLINE void draw_sprites_1 (struct sprite_entry *e, int ham, int dualpf,
+                                  int doubling, int skip, int has_attach, int aga)
+{
+    int *shift_lookup = dualpf ? (bpldualpfpri ? dblpf_ms2 : dblpf_ms1) : dblpf_ms;
+    uae_u16 *buf = spixels + e->first_pixel;
+    uae_u8 *stbuf = spixstate.bytes + e->first_pixel;
+    int pos, window_pos;
+#ifdef AGA
+    uae_u8 xor_val = (uae_u8)(dp_for_drawing->bplcon4 >> 8);
+#endif
+
+    buf -= e->pos;
+    stbuf -= e->pos;
+
+    window_pos = e->pos + ((DIW_DDF_OFFSET - DISPLAY_LEFT_SHIFT) << (aga ? 1 : 0));
+    if (skip)
+       window_pos >>= 1;
+    else if (doubling)
+       window_pos <<= 1;
+    window_pos += pixels_offset;
+    for (pos = e->pos; pos < e->max; pos += 1 << skip) {
+       int maskshift, plfmask;
+       unsigned int v = buf[pos];
+
+       /* The value in the shift lookup table is _half_ the shift count we
+          need.  This is because we can't shift 32 bits at once (undefined
+          behaviour in C).  */
+       maskshift = shift_lookup[pixdata.apixels[window_pos]];
+       plfmask = (plf_sprite_mask >> maskshift) >> maskshift;
+       v &= ~plfmask;
+       if (v != 0 || SPRITE_DEBUG) {
+           unsigned int vlo, vhi, col;
+           unsigned int v1 = v & 255;
+           /* OFFS determines the sprite pair with the highest priority that has
+              any bits set.  E.g. if we have 0xFF00 in the buffer, we have sprite
+              pairs 01 and 23 cleared, and pairs 45 and 67 set, so OFFS will
+              have a value of 4.
+              2 * OFFS is the bit number in V of the sprite pair, and it also
+              happens to be the color offset for that pair.  */
+           int offs;
+           if (v1 == 0)
+               offs = 4 + sprite_offs[v >> 8];
+           else
+               offs = sprite_offs[v1];
+
+           /* Shift highest priority sprite pair down to bit zero.  */
+           v >>= offs * 2;
+           v &= 15;
+#if SPRITE_DEBUG > 0
+           v |= 1 | 4;
+#endif
+           if (has_attach && (stbuf[pos] & (3 << offs))) {
+               col = v;
+               if (aga)
+                   col += sbasecol[1];
+               else
+                   col += 16;
+           } else {
+               /* This sequence computes the correct color value.  We have to select
+                  either the lower-numbered or the higher-numbered sprite in the pair.
+                  We have to select the high one if the low one has all bits zero.
+                  If the lower-numbered sprite has any bits nonzero, (VLO - 1) is in
+                  the range of 0..2, and with the mask and shift, VHI will be zero.
+                  If the lower-numbered sprite is zero, (VLO - 1) is a mask of
+                  0xFFFFFFFF, and we select the bits of the higher numbered sprite
+                  in VHI.
+                  This is _probably_ more efficient than doing it with branches.  */
+               vlo = v & 3;
+               vhi = (v & (vlo - 1)) >> 2;
+               col = (vlo | vhi);
+               if (aga) {
+                   if (vhi > 0)
+                       col += sbasecol[1];
+                   else
+                       col += sbasecol[0];
+               } else {
+                   col += 16;
+               }
+               col += (offs * 2);
+           }
+           if (dualpf) {
+#ifdef AGA
+               if (aga) {
+                   spriteagadpfpixels[window_pos] = col;
+                   if (doubling)
+                       spriteagadpfpixels[window_pos + 1] = col;
+               } else {
+#endif
+                   col += 128;
+                   if (doubling)
+                       pixdata.apixels_w[window_pos >> 1] = col | (col << 8);
+                   else
+                       pixdata.apixels[window_pos] = col;
+#ifdef AGA
+               }
+#endif
+           } else if (ham) {
+               col = color_reg_get (&colors_for_drawing, col);
+#ifdef AGA
+               if (aga)
+                   col ^= xor_val;
+#endif
+               ham_linebuf[window_pos] = col;
+               if (doubling)
+                   ham_linebuf[window_pos + 1] = col;
+           } else {
+#ifdef AGA
+               if (aga)
+                   col ^= xor_val;
+#endif
+               if (doubling)
+                   pixdata.apixels_w[window_pos >> 1] = col | (col << 8);
+               else
+                   pixdata.apixels[window_pos] = col;
+           }
+       }
+       window_pos += 1 << doubling;
+    }
+}
+  
+/* See comments above.  Do not touch if you don't know what's going on.
+ * (We do _not_ want the following to be inlined themselves).  */
+/* lores bitplane, lores sprites */
+static void draw_sprites_normal_sp_lo_nat (struct sprite_entry *e) { draw_sprites_1    (e, 0, 0, 0, 0, 0, 0); }
+static void draw_sprites_normal_dp_lo_nat (struct sprite_entry *e) { draw_sprites_1    (e, 0, 1, 0, 0, 0, 0); }
+static void draw_sprites_ham_sp_lo_nat (struct sprite_entry *e) { draw_sprites_1       (e, 1, 0, 0, 0, 0, 0); }
+static void draw_sprites_normal_sp_lo_at (struct sprite_entry *e) { draw_sprites_1     (e, 0, 0, 0, 0, 1, 0); }
+static void draw_sprites_normal_dp_lo_at (struct sprite_entry *e) { draw_sprites_1     (e, 0, 1, 0, 0, 1, 0); }
+static void draw_sprites_ham_sp_lo_at (struct sprite_entry *e) { draw_sprites_1                (e, 1, 0, 0, 0, 1, 0); }
+/* hires bitplane, lores sprites */
+static void draw_sprites_normal_sp_hi_nat (struct sprite_entry *e) { draw_sprites_1    (e, 0, 0, 1, 0, 0, 0); }
+static void draw_sprites_normal_dp_hi_nat (struct sprite_entry *e) { draw_sprites_1    (e, 0, 1, 1, 0, 0, 0); }
+static void draw_sprites_ham_sp_hi_nat (struct sprite_entry *e) { draw_sprites_1       (e, 1, 0, 1, 0, 0, 0); }
+static void draw_sprites_normal_sp_hi_at (struct sprite_entry *e) { draw_sprites_1     (e, 0, 0, 1, 0, 1, 0); }
+static void draw_sprites_normal_dp_hi_at (struct sprite_entry *e) { draw_sprites_1     (e, 0, 1, 1, 0, 1, 0); }
+static void draw_sprites_ham_sp_hi_at (struct sprite_entry *e) { draw_sprites_1                (e, 1, 0, 1, 0, 1, 0); }
+
+#ifdef AGA
+/* not very optimized */
+STATIC_INLINE void draw_sprites_aga (struct sprite_entry *e)
+{
+    int diff = RES_HIRES - bplres;
+    if (diff > 0)
+       draw_sprites_1 (e, dp_for_drawing->ham_seen, bpldualpf, 0, diff, e->has_attached, 1);
+    else
+       draw_sprites_1 (e, dp_for_drawing->ham_seen, bpldualpf, -diff, 0, e->has_attached, 1);
+}
+#endif
+
+STATIC_INLINE void draw_sprites_ecs (struct sprite_entry *e)
+{
+    if (e->has_attached)
+       if (bplres == 1)
+           if (dp_for_drawing->ham_seen)
+               draw_sprites_ham_sp_hi_at (e);
+           else
+               if (bpldualpf)
+                   draw_sprites_normal_dp_hi_at (e);
+               else
+                   draw_sprites_normal_sp_hi_at (e);
+       else
+           if (dp_for_drawing->ham_seen)
+               draw_sprites_ham_sp_lo_at (e);
+           else
+               if (bpldualpf)
+                   draw_sprites_normal_dp_lo_at (e);
+               else
+                   draw_sprites_normal_sp_lo_at (e);
+    else
+       if (bplres == 1)
+           if (dp_for_drawing->ham_seen)
+               draw_sprites_ham_sp_hi_nat (e);
+           else
+               if (bpldualpf)
+                   draw_sprites_normal_dp_hi_nat (e);
+               else
+                   draw_sprites_normal_sp_hi_nat (e);
+       else
+           if (dp_for_drawing->ham_seen)
+               draw_sprites_ham_sp_lo_nat (e);
+           else
+               if (bpldualpf)
+                   draw_sprites_normal_dp_lo_nat (e);
+               else
+                   draw_sprites_normal_sp_lo_nat (e);
+}
+
+#ifdef AGA
+/* clear possible bitplane data outside DIW area */
+static void clear_bitplane_border_aga (void)
+{
+    int len, shift = lores_shift - bplres;
+    uae_u8 v = 0;
+    if (shift < 0) {
+       shift = -shift;
+       len = (real_playfield_start - playfield_start) << shift;
+       memset (pixdata.apixels + pixels_offset + (playfield_start << shift), v, len);
+       len = (playfield_end - real_playfield_end) << shift;
+       memset (pixdata.apixels + pixels_offset + (real_playfield_end << shift), v, len);
+    } else {
+       len = (real_playfield_start - playfield_start) >> shift;
+       memset (pixdata.apixels + pixels_offset + (playfield_start >> shift), v, len);
+       len = (playfield_end - real_playfield_end) >> shift;
+       memset (pixdata.apixels + pixels_offset + (real_playfield_end >> shift), v, len);
+    }
+}
+#endif
+
+/* emulate OCS/ECS only undocumented "SWIV" hardware feature */
+static void weird_bitplane_fix (void)
+{
+    int i, shift = lores_shift - bplres;
+    
+    if (shift < 0) {
+       shift = -shift;
+       for (i = playfield_start << lores_shift; i < playfield_end << lores_shift; i++) {
+           if (pixdata.apixels[pixels_offset + i] > 16)
+               pixdata.apixels[pixels_offset + i] = 16;
+       }
+    } else {
+       for (i = playfield_start >> lores_shift; i < playfield_end >> lores_shift; i++) {
+           if (pixdata.apixels[pixels_offset + i] > 16)
+               pixdata.apixels[pixels_offset + i] = 16;
+       }
+    }
+}
+
+#define MERGE(a,b,mask,shift) do {\
+    uae_u32 tmp = mask & (a ^ (b >> shift)); \
+    a ^= tmp; \
+    b ^= (tmp << shift); \
+} while (0)
+
+#define GETLONG(P) (*(uae_u32 *)P)
+
+/* We use the compiler's inlining ability to ensure that PLANES is in effect a compile time
+   constant.  That will cause some unnecessary code to be optimized away.
+   Don't touch this if you don't know what you are doing.  */
+STATIC_INLINE void pfield_doline_1 (uae_u32 *pixels, int wordcount, int planes)
+{
+    while (wordcount-- > 0) {
+       uae_u32 b0, b1, b2, b3, b4, b5, b6, b7;
+
+       b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0, b6 = 0, b7 = 0;
+       switch (planes) {
+       case 8: b0 = GETLONG ((uae_u32 *)real_bplpt[7]); real_bplpt[7] += 4;
+       case 7: b1 = GETLONG ((uae_u32 *)real_bplpt[6]); real_bplpt[6] += 4;
+       case 6: b2 = GETLONG ((uae_u32 *)real_bplpt[5]); real_bplpt[5] += 4;
+       case 5: b3 = GETLONG ((uae_u32 *)real_bplpt[4]); real_bplpt[4] += 4;
+       case 4: b4 = GETLONG ((uae_u32 *)real_bplpt[3]); real_bplpt[3] += 4;
+       case 3: b5 = GETLONG ((uae_u32 *)real_bplpt[2]); real_bplpt[2] += 4;
+       case 2: b6 = GETLONG ((uae_u32 *)real_bplpt[1]); real_bplpt[1] += 4;
+       case 1: b7 = GETLONG ((uae_u32 *)real_bplpt[0]); real_bplpt[0] += 4;
+       }
+
+       MERGE (b0, b1, 0x55555555, 1);
+       MERGE (b2, b3, 0x55555555, 1);
+       MERGE (b4, b5, 0x55555555, 1);
+       MERGE (b6, b7, 0x55555555, 1);
+
+       MERGE (b0, b2, 0x33333333, 2);
+       MERGE (b1, b3, 0x33333333, 2);
+       MERGE (b4, b6, 0x33333333, 2);
+       MERGE (b5, b7, 0x33333333, 2);
+
+       MERGE (b0, b4, 0x0f0f0f0f, 4);
+       MERGE (b1, b5, 0x0f0f0f0f, 4);
+       MERGE (b2, b6, 0x0f0f0f0f, 4);
+       MERGE (b3, b7, 0x0f0f0f0f, 4);
+
+       MERGE (b0, b1, 0x00ff00ff, 8);
+       MERGE (b2, b3, 0x00ff00ff, 8);
+       MERGE (b4, b5, 0x00ff00ff, 8);
+       MERGE (b6, b7, 0x00ff00ff, 8);
+
+       MERGE (b0, b2, 0x0000ffff, 16);
+       do_put_mem_long (pixels, b0);
+       do_put_mem_long (pixels + 4, b2);
+       MERGE (b1, b3, 0x0000ffff, 16);
+       do_put_mem_long (pixels + 2, b1);
+       do_put_mem_long (pixels + 6, b3);
+       MERGE (b4, b6, 0x0000ffff, 16);
+       do_put_mem_long (pixels + 1, b4);
+       do_put_mem_long (pixels + 5, b6);
+       MERGE (b5, b7, 0x0000ffff, 16);
+       do_put_mem_long (pixels + 3, b5);
+       do_put_mem_long (pixels + 7, b7);
+       pixels += 8;
+    }
+}
+
+/* See above for comments on inlining.  These functions should _not_
+   be inlined themselves.  */
+static void pfield_doline_n1 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 1); }
+static void pfield_doline_n2 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 2); }
+static void pfield_doline_n3 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 3); }
+static void pfield_doline_n4 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 4); }
+static void pfield_doline_n5 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 5); }
+static void pfield_doline_n6 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 6); }
+#ifdef AGA
+static void pfield_doline_n7 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 7); }
+static void pfield_doline_n8 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 8); }
+#endif
+
+static void pfield_doline (int lineno)
+{
+    int wordcount = dp_for_drawing->plflinelen;
+    uae_u32 *data = pixdata.apixels_l + MAX_PIXELS_PER_LINE/4;
+
+#ifdef SMART_UPDATE
+#define DATA_POINTER(n) (line_data[lineno] + (n)*MAX_WORDS_PER_LINE*2)
+    real_bplpt[0] = DATA_POINTER (0);
+    real_bplpt[1] = DATA_POINTER (1);
+    real_bplpt[2] = DATA_POINTER (2);
+    real_bplpt[3] = DATA_POINTER (3);
+    real_bplpt[4] = DATA_POINTER (4);
+    real_bplpt[5] = DATA_POINTER (5);
+#ifdef AGA
+    real_bplpt[6] = DATA_POINTER (6);
+    real_bplpt[7] = DATA_POINTER (7);
+#endif
+#endif
+
+    switch (bplplanecnt) {
+    default: break;
+    case 0: memset (data, 0, wordcount * 32); break;
+    case 1: pfield_doline_n1 (data, wordcount); break;
+    case 2: pfield_doline_n2 (data, wordcount); break;
+    case 3: pfield_doline_n3 (data, wordcount); break;
+    case 4: pfield_doline_n4 (data, wordcount); break;
+    case 5: pfield_doline_n5 (data, wordcount); break;
+    case 6: pfield_doline_n6 (data, wordcount); break;
+#ifdef AGA
+    case 7: pfield_doline_n7 (data, wordcount); break;
+    case 8: pfield_doline_n8 (data, wordcount); break;
+#endif
+    }
+}
+
+void init_row_map (void)
+{
+    int i;
+    if (gfxvidinfo.height > MAX_VIDHEIGHT) {
+       write_log ("Resolution too high, aborting\n");
+       abort ();
+    }
+    for (i = 0; i < gfxvidinfo.height + 1; i++)
+       row_map[i] = gfxvidinfo.bufmem + gfxvidinfo.rowbytes * i;
+}
+
+static void init_aspect_maps (void)
+{
+    int i, maxl;
+    double native_lines_per_amiga_line;
+
+    if (native2amiga_line_map)
+       free (native2amiga_line_map);
+    if (amiga2aspect_line_map)
+       free (amiga2aspect_line_map);
+
+    /* At least for this array the +1 is necessary. */
+    amiga2aspect_line_map = (int *)malloc (sizeof (int) * (MAXVPOS + 1) * 2 + 1);
+    native2amiga_line_map = (int *)malloc (sizeof (int) * gfxvidinfo.height);
+
+    if (currprefs.gfx_correct_aspect)
+       native_lines_per_amiga_line = ((double)gfxvidinfo.height
+                                      * (currprefs.gfx_lores ? 320 : 640)
+                                      / (currprefs.gfx_linedbl ? 512 : 256)
+                                      / gfxvidinfo.width);
+    else
+       native_lines_per_amiga_line = 1;
+
+    maxl = (MAXVPOS + 1) * (currprefs.gfx_linedbl ? 2 : 1);
+    min_ypos_for_screen = minfirstline << (currprefs.gfx_linedbl ? 1 : 0);
+    max_drawn_amiga_line = -1;
+    for (i = 0; i < maxl; i++) {
+       int v = (int) ((i - min_ypos_for_screen) * native_lines_per_amiga_line);
+       if (v >= gfxvidinfo.height && max_drawn_amiga_line == -1)
+           max_drawn_amiga_line = i - min_ypos_for_screen;
+       if (i < min_ypos_for_screen || v >= gfxvidinfo.height)
+           v = -1;
+       amiga2aspect_line_map[i] = v;
+    }
+    if (currprefs.gfx_linedbl)
+       max_drawn_amiga_line >>= 1;
+
+    if (currprefs.gfx_ycenter && !(currprefs.gfx_correct_aspect)) {
+       /* @@@ verify maxvpos vs. MAXVPOS */
+       extra_y_adjust = (gfxvidinfo.height - (maxvpos << (currprefs.gfx_linedbl ? 1 : 0))) >> 1;
+       if (extra_y_adjust < 0)
+           extra_y_adjust = 0;
+    }
+
+    for (i = 0; i < gfxvidinfo.height; i++)
+       native2amiga_line_map[i] = -1;
+
+    if (native_lines_per_amiga_line < 1) {
+       /* Must omit drawing some lines. */
+       for (i = maxl - 1; i > min_ypos_for_screen; i--) {
+           if (amiga2aspect_line_map[i] == amiga2aspect_line_map[i-1]) {
+               if (currprefs.gfx_linedbl && (i & 1) == 0 && amiga2aspect_line_map[i+1] != -1) {
+                   /* If only the first line of a line pair would be omitted,
+                    * omit the second one instead to avoid problems with line
+                    * doubling. */
+                   amiga2aspect_line_map[i] = amiga2aspect_line_map[i+1];
+                   amiga2aspect_line_map[i+1] = -1;
+               } else
+                   amiga2aspect_line_map[i] = -1;
+           }
+       }
+    }
+
+    for (i = maxl-1; i >= min_ypos_for_screen; i--) {
+       int j;
+       if (amiga2aspect_line_map[i] == -1)
+           continue;
+       for (j = amiga2aspect_line_map[i]; j < gfxvidinfo.height && native2amiga_line_map[j] == -1; j++)
+           native2amiga_line_map[j] = i >> (currprefs.gfx_linedbl ? 1 : 0);
+    }
+}
+
+/*
+ * A raster line has been built in the graphics buffer. Tell the graphics code
+ * to do anything necessary to display it.
+ */
+static void do_flush_line_1 (int lineno)
+{
+    if (lineno < first_drawn_line)
+       first_drawn_line = lineno;
+    if (lineno > last_drawn_line)
+       last_drawn_line = lineno;
+
+    if (gfxvidinfo.maxblocklines == 0)
+       flush_line (lineno);
+    else {
+       if ((last_block_line+1) != lineno) {
+           if (first_block_line != -2)
+               flush_block (first_block_line, last_block_line);
+           first_block_line = lineno;
+       }
+       last_block_line = lineno;
+       if (last_block_line - first_block_line >= gfxvidinfo.maxblocklines) {
+           flush_block (first_block_line, last_block_line);
+           first_block_line = last_block_line = -2;
+       }
+    }
+}
+
+STATIC_INLINE void do_flush_line (int lineno)
+{
+    do_flush_line_1 (lineno);
+}
+
+/*
+ * One drawing frame has been finished. Tell the graphics code about it.
+ * Note that the actual flush_screen() call is a no-op for all reasonable
+ * systems.
+ */
+
+STATIC_INLINE void do_flush_screen (int start, int stop)
+{
+    /* TODO: this flush operation is executed outside locked state!
+       Should be corrected.
+       (sjo 26.9.99) */
+
+    if (gfxvidinfo.maxblocklines != 0 && first_block_line != -2) {
+       flush_block (first_block_line, last_block_line);
+    }
+    unlockscr ();
+    if (start <= stop)
+       flush_screen (start, stop);
+    else if (currprefs.gfx_afullscreen && currprefs.gfx_vsync)
+       flush_screen (0, 0); /* vsync mode */
+}
+
+static int drawing_color_matches;
+static enum { color_match_acolors, color_match_full } color_match_type;
+
+/* Set up colors_for_drawing to the state at the beginning of the currently drawn
+   line.  Try to avoid copying color tables around whenever possible.  */
+static void adjust_drawing_colors (int ctable, int need_full)
+{
+    if (drawing_color_matches != ctable) {
+       if (need_full) {
+           color_reg_cpy (&colors_for_drawing, curr_color_tables + ctable);
+           color_match_type = color_match_full;
+       } else {
+           memcpy (colors_for_drawing.acolors, curr_color_tables[ctable].acolors,
+               sizeof colors_for_drawing.acolors);
+           color_match_type = color_match_acolors;
+       }
+       drawing_color_matches = ctable;
+    } else if (need_full && color_match_type != color_match_full) {
+       color_reg_cpy (&colors_for_drawing, &curr_color_tables[ctable]);
+       color_match_type = color_match_full;
+    }
+}
+
+STATIC_INLINE void do_color_changes (line_draw_func worker_border, line_draw_func worker_pfield)
+{
+    int i;
+    int lastpos = visible_left_border;
+
+    for (i = dip_for_drawing->first_color_change; i <= dip_for_drawing->last_color_change; i++) {
+       int regno = curr_color_changes[i].regno;
+       unsigned int value = curr_color_changes[i].value;
+       int nextpos, nextpos_in_range;
+       if (i == dip_for_drawing->last_color_change)
+           nextpos = max_diwlastword;
+       else
+           nextpos = coord_hw_to_window_x (curr_color_changes[i].linepos * 2);
+
+       nextpos_in_range = nextpos;
+       if (nextpos > visible_right_border)
+           nextpos_in_range = visible_right_border;
+
+       if (nextpos_in_range > lastpos) {
+           if (lastpos < playfield_start) {
+               int t = nextpos_in_range <= playfield_start ? nextpos_in_range : playfield_start;
+               (*worker_border) (lastpos, t);
+               lastpos = t;
+           }
+       }
+       if (nextpos_in_range > lastpos) {
+           if (lastpos >= playfield_start && lastpos < playfield_end) {
+               int t = nextpos_in_range <= playfield_end ? nextpos_in_range : playfield_end;
+               (*worker_pfield) (lastpos, t);
+               lastpos = t;
+           }
+       }
+       if (nextpos_in_range > lastpos) {
+           if (lastpos >= playfield_end)
+               (*worker_border) (lastpos, nextpos_in_range);
+           lastpos = nextpos_in_range;
+       }
+       if (i != dip_for_drawing->last_color_change) {
+           if (regno == -1)
+               bplham = value;
+           else {
+               color_reg_set (&colors_for_drawing, regno, value);
+               colors_for_drawing.acolors[regno] = getxcolor (value);
+           }
+       }
+       if (lastpos >= visible_right_border)
+           break;
+    }
+}
+
+/* We only save hardware registers during the hardware frame. Now, when
+ * drawing the frame, we expand the data into a slightly more useful
+ * form. */
+static void pfield_expand_dp_bplcon (void)
+{
+    bplres = dp_for_drawing->bplres;
+    bplplanecnt = dp_for_drawing->nr_planes;
+    bplham = dp_for_drawing->ham_at_start;
+
+    if (bplres > 0)
+       can_use_lores = 0;
+    if (currprefs.chipset_mask & CSMASK_AGA) {
+       /* The KILLEHB bit exists in ECS, but is apparently meant for Genlock
+        * stuff, and it's set by some demos (e.g. Andromeda Seven Seas) */
+       bplehb = ((dp_for_drawing->bplcon0 & 0x7010) == 0x6000 && !(dp_for_drawing->bplcon2 & 0x200));
+    } else {
+       bplehb = (dp_for_drawing->bplcon0 & 0xFC00) == 0x6000;
+    }
+    plf1pri = dp_for_drawing->bplcon2 & 7;
+    plf2pri = (dp_for_drawing->bplcon2 >> 3) & 7;
+    plf_sprite_mask = 0xFFFF0000 << (4 * plf2pri);
+    plf_sprite_mask |= (0xFFFF << (4 * plf1pri)) & 0xFFFF;
+    bpldualpf = (dp_for_drawing->bplcon0 & 0x400) == 0x400;
+    bpldualpfpri = (dp_for_drawing->bplcon2 & 0x40) == 0x40;
+#ifdef AGA
+    bpldualpf2of = (dp_for_drawing->bplcon3 >> 10) & 7;
+    sbasecol[0] = ((dp_for_drawing->bplcon4 >> 4) & 15) << 4;
+    sbasecol[1] = ((dp_for_drawing->bplcon4 >> 0) & 15) << 4;
+
+    brdsprt = (currprefs.chipset_mask & CSMASK_AGA) && (dp_for_drawing->bplcon0 & 1) && (dp_for_drawing->bplcon3 & 0x02);
+    /* FIXME: we must update top and bottom borders when BRDBLANK changes */
+    brdblank = (currprefs.chipset_mask & CSMASK_AGA) && (dp_for_drawing->bplcon0 & 1) && (dp_for_drawing->bplcon3 & 0x20);
+    if (brdblank)
+       brdsprt = 0;
+#endif
+}
+
+enum double_how {
+    dh_buf,
+    dh_line,
+    dh_emerg
+};
+
+STATIC_INLINE void pfield_draw_line (int lineno, int gfx_ypos, int follow_ypos)
+{
+    static int warned = 0;
+    int border = 0;
+    int do_double = 0;
+    enum double_how dh;
+
+    dp_for_drawing = line_decisions + lineno;
+    dip_for_drawing = curr_drawinfo + lineno;
+    switch (linestate[lineno]) {
+    case LINE_REMEMBERED_AS_PREVIOUS:
+       if (!warned)
+           write_log ("Shouldn't get here... this is a bug.\n"), warned++;
+       return;
+
+    case LINE_BLACK:
+       linestate[lineno] = LINE_REMEMBERED_AS_BLACK;
+       border = 2;
+       break;
+
+    case LINE_REMEMBERED_AS_BLACK:
+       return;
+
+    case LINE_AS_PREVIOUS:
+       dp_for_drawing--;
+       dip_for_drawing--;
+       if (dp_for_drawing->plfleft == -1)
+           border = 1;
+       linestate[lineno] = LINE_DONE_AS_PREVIOUS;
+       break;
+
+    case LINE_DONE_AS_PREVIOUS:
+       /* fall through */
+    case LINE_DONE:
+       return;
+
+    case LINE_DECIDED_DOUBLE:
+       if (follow_ypos != -1) {
+           do_double = 1;
+           linetoscr_double_offset = gfxvidinfo.rowbytes * (follow_ypos - gfx_ypos);
+           linestate[lineno + 1] = LINE_DONE_AS_PREVIOUS;
+       }
+
+       /* fall through */
+    default:
+       if (dp_for_drawing->plfleft == -1)
+           border = 1;
+       linestate[lineno] = LINE_DONE;
+       break;
+    }
+
+    dh = dh_line;
+    xlinebuffer = gfxvidinfo.linemem;
+    if (xlinebuffer == 0 && do_double
+       && (border == 0 || (border != 1 && dip_for_drawing->nr_color_changes > 0)))
+       xlinebuffer = gfxvidinfo.emergmem, dh = dh_emerg;
+    if (xlinebuffer == 0)
+       xlinebuffer = row_map[gfx_ypos], dh = dh_buf;
+    xlinebuffer -= linetoscr_x_adjust_bytes;
+
+    if (border == 0) {
+       pfield_expand_dp_bplcon ();
+
+       if (bplres == RES_LORES && ! currprefs.gfx_lores)
+           currprefs.gfx_lores = 2;
+
+       pfield_init_linetoscr ();
+       pfield_doline (lineno);
+
+       adjust_drawing_colors (dp_for_drawing->ctable, dp_for_drawing->ham_seen || bplehb);
+
+       /* The problem is that we must call decode_ham() BEFORE we do the
+          sprites. */
+       if (! border && dp_for_drawing->ham_seen) {
+           init_ham_decoding ();
+           if (dip_for_drawing->nr_color_changes == 0) {
+               /* The easy case: need to do HAM decoding only once for the
+                * full line. */
+               decode_ham (visible_left_border, visible_right_border);
+           } else /* Argh. */ {
+               do_color_changes (dummy_worker, decode_ham);
+               adjust_drawing_colors (dp_for_drawing->ctable, dp_for_drawing->ham_seen || bplehb);
+           }
+           bplham = dp_for_drawing->ham_at_start;
+       }
+
+       {
+           if (dip_for_drawing->nr_sprites) {
+               int i;
+#ifdef AGA
+               if (brdsprt)
+                   clear_bitplane_border_aga ();
+#endif
+               for (i = 0; i < dip_for_drawing->nr_sprites; i++) {
+#ifdef AGA
+                   if (currprefs.chipset_mask & CSMASK_AGA)
+                       draw_sprites_aga (curr_sprite_entries + dip_for_drawing->first_sprite_entry + i);
+                   else
+#endif
+                       draw_sprites_ecs (curr_sprite_entries + dip_for_drawing->first_sprite_entry + i);
+               }
+           }
+           if (plf2pri > 5 && bplplanecnt > 4 && !(currprefs.chipset_mask & CSMASK_AGA))
+               weird_bitplane_fix ();
+       }
+
+       do_color_changes (pfield_do_fill_line, pfield_do_linetoscr);
+       if (dh == dh_emerg)
+           memcpy (row_map[gfx_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.pixbytes * gfxvidinfo.width);
+
+       do_flush_line (gfx_ypos);
+       if (do_double) {
+           if (dh == dh_emerg)
+               memcpy (row_map[follow_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.pixbytes * gfxvidinfo.width);
+           else if (dh == dh_buf)
+               memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.pixbytes * gfxvidinfo.width);
+           do_flush_line (follow_ypos);
+       }
+       if (currprefs.gfx_lores == 2)
+           currprefs.gfx_lores = 0;
+    } else if (border == 1) {
+       adjust_drawing_colors (dp_for_drawing->ctable, 0);
+
+       if (dip_for_drawing->nr_color_changes == 0) {
+           fill_line ();
+           do_flush_line (gfx_ypos);
+#if 0
+           if (dh == dh_emerg)
+               abort ();
+#endif
+           if (do_double) {
+               if (dh == dh_buf) {
+                   xlinebuffer = row_map[follow_ypos] - linetoscr_x_adjust_bytes;
+                   fill_line ();
+               }
+               /* If dh == dh_line, do_flush_line will re-use the rendered line
+                * from linemem.  */
+               do_flush_line (follow_ypos);
+           }
+           return;
+       }
+
+       playfield_start = visible_right_border;
+       playfield_end = visible_right_border;
+
+       do_color_changes (pfield_do_fill_line, pfield_do_fill_line);
+
+       if (dh == dh_emerg)
+           memcpy (row_map[gfx_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.pixbytes * gfxvidinfo.width);
+
+       do_flush_line (gfx_ypos);
+       if (do_double) {
+           if (dh == dh_emerg)
+               memcpy (row_map[follow_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.pixbytes * gfxvidinfo.width);
+           else if (dh == dh_buf)
+               memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.pixbytes * gfxvidinfo.width);
+           /* If dh == dh_line, do_flush_line will re-use the rendered line
+            * from linemem.  */
+           do_flush_line (follow_ypos);
+       }
+    } else {
+       xcolnr tmp = colors_for_drawing.acolors[0];
+       colors_for_drawing.acolors[0] = getxcolor (0);
+       fill_line ();
+       do_flush_line (gfx_ypos);
+       colors_for_drawing.acolors[0] = tmp;
+    }
+}
+
+static void center_image (void)
+{
+    prev_x_adjust = visible_left_border;
+    prev_y_adjust = thisframe_y_adjust;
+
+    if (currprefs.gfx_xcenter) {
+#if 0
+       if (min_diwstart && (max_diwstop - min_diwstart < gfxvidinfo.width) && (currprefs.gfx_xcenter == 2))
+           visible_left_border = ((max_diwstop - min_diwstart - gfxvidinfo.width) / 2 + min_diwstart) & ~1;
+#endif
+       if (max_diwstop - min_diwstart < gfxvidinfo.width && currprefs.gfx_xcenter == 2)
+           /* Try to center. */
+           visible_left_border = ((max_diwstop - min_diwstart - gfxvidinfo.width) / 2 + min_diwstart) & ~1;
+       else
+           visible_left_border = max_diwstop - gfxvidinfo.width;
+
+       /* Would the old value be good enough? If so, leave it as it is if we want to
+        * be clever. */
+       if (currprefs.gfx_xcenter == 2) {
+           if (visible_left_border < prev_x_adjust && prev_x_adjust < min_diwstart)
+               visible_left_border = prev_x_adjust;
+       }
+    } else
+       visible_left_border = max_diwlastword - gfxvidinfo.width;
+    if (visible_left_border > max_diwlastword - 32)
+       visible_left_border = max_diwlastword - 32;
+    if (visible_left_border < 0)
+       visible_left_border = 0;
+
+    linetoscr_x_adjust_bytes = visible_left_border * gfxvidinfo.pixbytes;
+
+    visible_right_border = visible_left_border + gfxvidinfo.width;
+    if (visible_right_border > max_diwlastword)
+       visible_right_border = max_diwlastword;
+
+    thisframe_y_adjust = minfirstline;
+    if (currprefs.gfx_ycenter && thisframe_first_drawn_line != -1) {
+#if 0
+       if (thisframe_first_drawn_line && (thisframe_last_drawn_line - thisframe_first_drawn_line < max_drawn_amiga_line) && currprefs.gfx_ycenter == 2)
+           thisframe_y_adjust = (thisframe_last_drawn_line - thisframe_first_drawn_line - max_drawn_amiga_line) / 2 + thisframe_first_drawn_line;
+#endif
+
+       if (thisframe_last_drawn_line - thisframe_first_drawn_line < max_drawn_amiga_line && currprefs.gfx_ycenter == 2)
+           thisframe_y_adjust = (thisframe_last_drawn_line - thisframe_first_drawn_line - max_drawn_amiga_line) / 2 + thisframe_first_drawn_line;
+       else
+           thisframe_y_adjust = thisframe_first_drawn_line;
+
+       /* Would the old value be good enough? If so, leave it as it is if we want to
+        * be clever. */
+       if (currprefs.gfx_ycenter == 2) {
+           if (thisframe_y_adjust != prev_y_adjust
+               && prev_y_adjust <= thisframe_first_drawn_line
+               && prev_y_adjust + max_drawn_amiga_line > thisframe_last_drawn_line)
+               thisframe_y_adjust = prev_y_adjust;
+       }
+       /* Make sure the value makes sense */
+       if (thisframe_y_adjust + max_drawn_amiga_line > maxvpos)
+           thisframe_y_adjust = maxvpos - max_drawn_amiga_line;
+       if (thisframe_y_adjust < minfirstline)
+           thisframe_y_adjust = minfirstline;
+    }
+    thisframe_y_adjust_real = thisframe_y_adjust << (currprefs.gfx_linedbl ? 1 : 0);
+    max_ypos_thisframe = (maxvpos - thisframe_y_adjust) << (currprefs.gfx_linedbl ? 1 : 0);
+
+    /* @@@ interlace_seen used to be (bplcon0 & 4), but this is probably
+     * better.  */
+    if (prev_x_adjust != visible_left_border || prev_y_adjust != thisframe_y_adjust)
+       frame_redraw_necessary |= interlace_seen && currprefs.gfx_linedbl ? 2 : 1;
+
+    max_diwstop = 0;
+    min_diwstart = 10000;
+}
+
+static void lores_reset (void)
+{
+    lores_factor = currprefs.gfx_lores ? 1 : 2;
+    lores_shift = currprefs.gfx_lores ? 0 : 1;
+}
+
+static void init_drawing_frame (void)
+{
+    int i, maxline;
+
+    if (can_use_lores > AUTO_LORES_FRAMES && 0) {
+        lores_factor = 1;
+       lores_shift = 0;
+    } else {
+       can_use_lores++;
+       lores_reset ();
+    }
+
+    init_hardware_for_drawing_frame ();
+
+    if (thisframe_first_drawn_line == -1)
+       thisframe_first_drawn_line = minfirstline;
+    if (thisframe_first_drawn_line > thisframe_last_drawn_line)
+       thisframe_last_drawn_line = thisframe_first_drawn_line;
+
+    maxline = currprefs.gfx_linedbl ? (maxvpos + 1) * 2 + 1 : (maxvpos + 1) + 1;
+#ifdef SMART_UPDATE
+    for (i = 0; i < maxline; i++) {
+       switch (linestate[i]) {
+        case LINE_DONE_AS_PREVIOUS:
+           linestate[i] = LINE_REMEMBERED_AS_PREVIOUS;
+           break;
+        case LINE_REMEMBERED_AS_BLACK:
+           break;
+        default:
+           linestate[i] = LINE_UNDECIDED;
+           break;
+       }
+    }
+#else
+    memset (linestate, LINE_UNDECIDED, maxline);
+#endif
+    last_drawn_line = 0;
+    first_drawn_line = 32767;
+
+    first_block_line = last_block_line = -2;
+    if (currprefs.test_drawing_speed)
+       frame_redraw_necessary = 1;
+    else if (frame_redraw_necessary)
+       frame_redraw_necessary--;
+
+    center_image ();
+
+    thisframe_first_drawn_line = -1;
+    thisframe_last_drawn_line = -1;
+
+    drawing_color_matches = -1;
+}
+
+/*
+ * Some code to put status information on the screen.
+ */
+
+#define TD_PADX 10
+#define TD_PADY 2
+#define TD_WIDTH 32
+#define TD_LED_WIDTH 24
+#define TD_LED_HEIGHT 4
+
+#define TD_RIGHT 1
+#define TD_BOTTOM 2
+
+static int td_pos = (TD_RIGHT|TD_BOTTOM);
+
+#define TD_NUM_WIDTH 7
+#define TD_NUM_HEIGHT 7
+
+#define TD_TOTAL_HEIGHT (TD_PADY * 2 + TD_NUM_HEIGHT)
+
+#define NUMBERS_NUM 14
+
+static char *numbers = { /* ugly */
+"+++++++--++++-+++++++++++++++++-++++++++++++++++++++++++++++++++++++++++++++-++++++-++++----++---+"
+"+xxxxx+--+xx+-+xxxxx++xxxxx++x+-+x++xxxxx++xxxxx++xxxxx++xxxxx++xxxxx++xxxx+-+x++x+-+xxx++-+xx+-+x"
+"+x+++x+--++x+-+++++x++++++x++x+++x++x++++++x++++++++++x++x+++x++x+++x++x++++-+x++x+-+x++x+--+x++x+"
+"+x+-+x+---+x+-+xxxxx++xxxxx++xxxxx++xxxxx++xxxxx+--++x+-+xxxxx++xxxxx++x+----+xxxx+-+x++x+----+x+-"
+"+x+++x+---+x+-+x++++++++++x++++++x++++++x++x+++x+--+x+--+x+++x++++++x++x++++-+x++x+-+x++x+---+x+x+"
+"+xxxxx+---+x+-+xxxxx++xxxxx+----+x++xxxxx++xxxxx+--+x+--+xxxxx++xxxxx++xxxx+-+x++x+-+xxx+---+x++xx"
+"+++++++---+++-++++++++++++++----+++++++++++++++++--+++--++++++++++++++++++++-++++++-++++----------"
+};
+
+STATIC_INLINE void putpixel (int x, xcolnr c8)
+{
+    switch(gfxvidinfo.pixbytes)
+    {
+    case 1:
+       xlinebuffer[x] = (uae_u8)c8;
+       break;
+    case 2:
+    {
+       uae_u16 *p = (uae_u16 *)xlinebuffer + x;
+       *p = (uae_u16)c8;
+       break;
+    }
+    case 3:
+       /* no 24 bit yet */
+       break;
+    case 4:
+    {
+       uae_u32 *p = (uae_u32 *)xlinebuffer + x;
+       *p = c8;
+       break;
+    }
+    }
+}
+
+static void write_tdnumber (int x, int y, int num)
+{
+    int j;
+    uae_u8 *numptr;
+    
+    numptr = numbers + num * TD_NUM_WIDTH + NUMBERS_NUM * TD_NUM_WIDTH * y;
+    for (j = 0; j < TD_NUM_WIDTH; j++) {
+       if (*numptr == 'x')
+           putpixel (x + j, xcolors[0xfff]);
+       else if (*numptr == '+')
+           putpixel (x + j, xcolors[0x000]);
+       numptr++;
+    }
+}
+
+static void draw_status_line (int line)
+{
+    int x_start, y, j, led;
+    
+    if (td_pos & TD_RIGHT)
+        x_start = gfxvidinfo.width - TD_PADX - NUM_LEDS * TD_WIDTH;
+    else
+        x_start = TD_PADX;
+
+    y = line - (gfxvidinfo.height - TD_TOTAL_HEIGHT);
+    xlinebuffer = gfxvidinfo.linemem;
+    if (xlinebuffer == 0)
+       xlinebuffer = row_map[line];
+
+    memset (xlinebuffer, 0, gfxvidinfo.width * gfxvidinfo.pixbytes);
+
+    for (led = 0; led < NUM_LEDS; led++) {
+       int side, pos, num1 = -1, num2 = -1, num3 = -1, num4 = -1, x, off_rgb, on_rgb, c, on = 0;
+       if (led >= 1 && led <= 4) {
+           int track = gui_data.drive_track[led-1];
+           pos = 5 + (led - 1);
+           if (!gui_data.drive_disabled[led - 1]) {
+               num1 = -1;
+               num2 = track / 10;
+               num3 = track % 10;
+               on = gui_data.drive_motor[led-1];
+           }
+           side = gui_data.drive_side;
+           on_rgb = 0x0c0;
+           off_rgb = 0x030;
+       } else if (led == 0) {
+           pos = 2;
+           on = gui_data.powerled;
+           on_rgb = 0xc00;
+           off_rgb = 0x300;
+       } else if (led == 5) {
+           pos = 4;
+           on = gui_data.cd;
+           on_rgb = 0x00c;
+           off_rgb = 0x003;
+           num1 = -1;
+           num2 = 10;
+           num3 = 12;
+       } else if (led == 6) {
+           pos = 3;
+           on = gui_data.hd;
+           on_rgb = 0x00c;
+           off_rgb = 0x003;
+           num1 = -1;
+           num2 = 11;
+           num3 = 12;
+       } else if (led == 7) {
+           int fps = (gui_data.fps + 5) / 10;
+           pos = 1;
+           on_rgb = 0x000;
+           off_rgb = 0x000;
+           num1 = fps / 100;
+           num2 = (fps - num1 * 100) / 10;
+           num3 = fps % 10;
+       } else if (led == 8) {
+           int idle = (gui_data.idle + 5) / 10;
+           pos = 0;
+           on_rgb = 0x000;
+           off_rgb = 0x000;
+           num1 = idle / 100;
+           num2 = (idle - num1 * 100) / 10;
+           num3 = idle % 10;
+           num4 = 13;
+       }
+
+       c = xcolors[on ? on_rgb : off_rgb];
+
+       x = x_start + pos * TD_WIDTH;
+       for (j = 0; j < TD_LED_WIDTH; j++) 
+           putpixel (x + j, c);
+
+       if (y >= TD_PADY && y - TD_PADY < TD_NUM_HEIGHT) {
+           if (num3 >= 0) {
+               int tn = num1 > 0 ? 3 : 2;
+               int offs = (TD_LED_WIDTH - tn * TD_NUM_WIDTH) / 2;
+               if (num1 > 0) {
+                   write_tdnumber (x + offs, y - TD_PADY, num1);
+                   offs += TD_NUM_WIDTH;
+               }
+               write_tdnumber (x + offs, y - TD_PADY, num2);
+               write_tdnumber (x + offs + TD_NUM_WIDTH, y - TD_PADY, num3);
+               if (num4 > 0)
+                   write_tdnumber (x + offs + 2 * TD_NUM_WIDTH, y - TD_PADY, num4);
+           }
+       }
+    }
+}
+
+void finish_drawing_frame (void)
+{
+    int i;
+
+    if (! lockscr ()) {
+       notice_screen_contents_lost ();
+       return;
+    }
+
+#ifndef SMART_UPDATE
+    /* @@@ This isn't exactly right yet. FIXME */
+    if (!interlace_seen)
+       do_flush_screen (first_drawn_line, last_drawn_line);
+    else
+       unlockscr ();
+    return;
+#endif
+    for (i = 0; i < max_ypos_thisframe; i++) {
+       int where;
+       int i1 = i + min_ypos_for_screen;
+       int line = i + thisframe_y_adjust_real;
+
+       if (linestate[line] == LINE_UNDECIDED)
+           break;
+
+       where = amiga2aspect_line_map[i1];
+       if (where >= gfxvidinfo.height - (currprefs.leds_on_screen ? TD_TOTAL_HEIGHT : 0))
+           break;
+       if (where == -1)
+           continue;
+
+       pfield_draw_line (line, where, amiga2aspect_line_map[i1 + 1]);
+    }
+    if (currprefs.leds_on_screen) {
+       for (i = 0; i < TD_TOTAL_HEIGHT; i++) {
+           int line = gfxvidinfo.height - TD_TOTAL_HEIGHT + i;
+           draw_status_line (line);
+           do_flush_line (line);
+       }
+    }
+
+    do_flush_screen (first_drawn_line, last_drawn_line);
+}
+
+void hardware_line_completed (int lineno)
+{
+#ifndef SMART_UPDATE
+    {
+       int i, where;
+       /* l is the line that has been finished for drawing. */
+       i = lineno - thisframe_y_adjust_real;
+       if (i >= 0 && i < max_ypos_thisframe) {
+           where = amiga2aspect_line_map[i+min_ypos_for_screen];
+           if (where < gfxvidinfo.height && where != -1)
+               pfield_draw_line (lineno, where, amiga2aspect_line_map[i+min_ypos_for_screen+1]);
+       }
+    }
+#endif
+}
+
+STATIC_INLINE void check_picasso (void)
+{
+#ifdef PICASSO96
+    if (picasso_on && picasso_redraw_necessary)
+       picasso_refresh (1);
+    picasso_redraw_necessary = 0;
+
+    if (picasso_requested_on == picasso_on)
+       return;
+
+    picasso_on = picasso_requested_on;
+
+    if (!picasso_on)
+       clear_inhibit_frame (IHF_PICASSO);
+    else
+       set_inhibit_frame (IHF_PICASSO);
+
+    gfx_set_picasso_state (picasso_on);
+    picasso_enablescreen (picasso_requested_on);
+
+    notice_screen_contents_lost ();
+    notice_new_xcolors ();
+#endif
+}
+
+void redraw_frame (void)
+{
+    last_drawn_line = 0;
+    first_drawn_line = 32767;
+    finish_drawing_frame ();
+    flush_screen (0, 0);
+}
+
+void vsync_handle_redraw (int long_frame, int lof_changed)
+{
+    last_redraw_point++;
+    if (lof_changed || ! interlace_seen || last_redraw_point >= 2 || long_frame) {
+       last_redraw_point = 0;
+       interlace_seen = 0;
+
+       if (framecnt == 0) {
+           finish_drawing_frame ();
+#ifdef AVIOUTPUT
+           frame_drawn ();
+       } else if (picasso_on) {
+           frame_drawn ();
+#endif
+       }
+
+       /* At this point, we have finished both the hardware and the
+        * drawing frame. Essentially, we are outside of all loops and
+        * can do some things which would cause confusion if they were
+        * done at other times.
+        */
+
+       if (savestate_state == STATE_DORESTORE) {
+           savestate_state = STATE_RESTORE;
+           reset_drawing ();
+           uae_reset (0);
+       } else if (savestate_state == STATE_DOREWIND) {
+           savestate_state = STATE_REWIND;
+           reset_drawing ();
+           uae_reset (0);
+       }
+
+       if (quit_program < 0) {
+           quit_program = -quit_program;
+           set_inhibit_frame (IHF_QUIT_PROGRAM);
+           set_special (SPCFLAG_BRK);
+#ifdef FILESYS
+           filesys_prepare_reset ();
+#endif
+           return;
+       }
+
+       savestate_capture (0);
+       count_frame ();
+       check_picasso ();
+
+       if (check_prefs_changed_gfx ()) {
+           reset_drawing ();
+           init_row_map ();
+           init_aspect_maps ();
+           notice_screen_contents_lost ();
+           notice_new_xcolors ();
+       }
+
+       check_prefs_changed_audio ();
+       check_prefs_changed_comp ();
+       check_prefs_changed_custom ();
+       check_prefs_changed_cpu ();
+
+       if (inhibit_frame != 0)
+           framecnt = 1;
+
+       if (framecnt == 0)
+           init_drawing_frame ();
+    } else {
+       if (currprefs.gfx_afullscreen && currprefs.gfx_vsync)
+           flush_screen (0, 0); /* vsync mode */
+    }
+    gui_hd_led (0);
+    gui_cd_led (0);
+}
+
+void hsync_record_line_state (int lineno, enum nln_how how, int changed)
+{
+    char *state;
+    if (framecnt != 0)
+       return;
+
+    state = linestate + lineno;
+    changed += frame_redraw_necessary;
+
+    switch (how) {
+     case nln_normal:
+       *state = changed ? LINE_DECIDED : LINE_DONE;
+       break;
+     case nln_doubled:
+       *state = changed ? LINE_DECIDED_DOUBLE : LINE_DONE;
+       changed += state[1] != LINE_REMEMBERED_AS_PREVIOUS;
+       state[1] = changed ? LINE_AS_PREVIOUS : LINE_DONE_AS_PREVIOUS;
+       break;
+     case nln_nblack:
+       *state = changed ? LINE_DECIDED : LINE_DONE;
+       if (state[1] != LINE_REMEMBERED_AS_BLACK)
+           state[1] = LINE_BLACK;
+       break;
+     case nln_lower:
+       if (state[-1] == LINE_UNDECIDED)
+           state[-1] = LINE_BLACK;
+       *state = changed ? LINE_DECIDED : LINE_DONE;
+       break;
+     case nln_upper:
+       *state = changed ? LINE_DECIDED : LINE_DONE;
+       if (state[1] == LINE_UNDECIDED
+           || state[1] == LINE_REMEMBERED_AS_PREVIOUS
+           || state[1] == LINE_AS_PREVIOUS)
+           state[1] = LINE_BLACK;
+       break;
+    }
+}
+
+void notice_interlace_seen (void)
+{
+    interlace_seen = 1;
+}
+
+void reset_drawing (void)
+{
+    int i;
+
+    max_diwstop = 0;
+
+    lores_reset ();
+
+    for (i = 0; i < sizeof linestate / sizeof *linestate; i++)
+       linestate[i] = LINE_UNDECIDED;
+
+    init_aspect_maps ();
+
+    if (line_drawn == 0)
+       line_drawn = (char *)malloc (gfxvidinfo.height);
+
+    init_row_map();
+
+    last_redraw_point = 0;
+
+    memset (spixels, 0, sizeof spixels);
+    memset (&spixstate, 0, sizeof spixstate);
+
+    init_drawing_frame ();
+
+    flush_clear_screen ();
+    notice_screen_contents_lost ();
+}
+
+void drawing_init (void)
+{
+    gen_pfield_tables();
+
+    uae_sem_init (&gui_sem, 0, 1);
+#ifdef PICASSO96
+    InitPicasso96 ();
+    picasso_on = 0;
+    picasso_requested_on = 0;
+    gfx_set_picasso_state (0);
+#endif
+    xlinebuffer = gfxvidinfo.bufmem;
+    inhibit_frame = 0;
+
+    reset_drawing ();
+}
+
diff --git a/driveclick.c b/driveclick.c
new file mode 100755 (executable)
index 0000000..9aecd6f
--- /dev/null
@@ -0,0 +1,323 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Drive Click Emulation Support Functions
+  *
+  * Copyright 2004 James Bagg, Toni Wilen
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#ifdef DRIVESOUND
+
+#include "uae.h"
+#include "config.h"
+#include "options.h"
+#include "sounddep/sound.h"
+#include "zfile.h"
+#include "events.h"
+
+#include "driveclick.h"
+
+static struct drvsample drvs[4][DS_END];
+static int freq = 44100;
+
+static int drv_starting[4], drv_spinning[4], drv_has_spun[4], drv_has_disk[4];
+
+static int click_initialized;
+#define DS_SHIFT 10
+static int sample_step;
+
+static uae_s16 *clickbuffer;
+
+uae_s16 *decodewav (uae_u8 *s, int *lenp)
+{
+    uae_s16 *dst;
+    uae_u8 *src = s;
+    int len;
+
+    if (memcmp (s, "RIFF", 4))
+       return 0;
+    if (memcmp (s + 8, "WAVE", 4))
+       return 0;
+    s += 12;
+    len = *lenp;
+    while (s < src + len) {
+       if (!memcmp (s, "fmt ", 4))
+           freq = s[8 + 4] | (s[8 + 5] << 8);
+       if (!memcmp (s, "data", 4)) {
+           s += 4;
+           len = s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24);
+           dst = xmalloc (len);
+           memcpy (dst, s + 4, len);
+           *lenp = len / 2;
+           return dst;
+       }
+       s += 8 + (s[4] | (s[5] << 8) | (s[6] << 16) | (s[7] << 24));
+    }
+    return 0;
+}
+
+static int loadsample (char *path, struct drvsample *ds)
+{
+    struct zfile *f;
+    uae_u8 *buf;
+    int size;
+
+    f = zfile_fopen (path, "rb");
+    if (!f) {
+       write_log ("driveclick: can't open '%s'\n", path);
+       return 0;
+    }
+    zfile_fseek (f, 0, SEEK_END);
+    size = zfile_ftell (f);
+    buf = malloc (size);
+    zfile_fseek (f, 0, SEEK_SET);
+    zfile_fread (buf, size, 1, f);
+    zfile_fclose (f);
+    ds->len = size;
+    ds->p = decodewav (buf, &ds->len);
+    free (buf);
+    return 1;
+}
+
+static void freesample (struct drvsample *s)
+{
+    free (s->p);
+    s->p = 0;
+}
+
+void driveclick_init(void)
+{
+    int v, vv, i, j;
+    char tmp[1000];
+
+    driveclick_free ();
+    vv = 0;
+    for (i = 0; i < 4; i++) {
+       if (currprefs.dfxclick[i]) {
+           if (currprefs.dfxclick[i] > 0) {
+               v = 0;
+               if (driveclick_loadresource (drvs[i], currprefs.dfxclick[i]))
+                   v = 3;
+           } else if (currprefs.dfxclick[i] == -1) {
+               sprintf (tmp, "%suae_data%cdrive_click_%s", start_path, FSDB_DIR_SEPARATOR, currprefs.dfxclickexternal[i]);
+               v = loadsample (tmp, &drvs[i][DS_CLICK]);
+               sprintf (tmp, "%suae_data%cdrive_spin_%s", start_path, FSDB_DIR_SEPARATOR, currprefs.dfxclickexternal[i]);
+               v += loadsample (tmp, &drvs[i][DS_SPIN]);
+               sprintf (tmp, "%suae_data%cdrive_spinnd_%s", start_path, FSDB_DIR_SEPARATOR, currprefs.dfxclickexternal[i]);
+               v += loadsample (tmp, &drvs[i][DS_SPINND]);
+               sprintf (tmp, "%suae_data%cdrive_startup_%s", start_path, FSDB_DIR_SEPARATOR, currprefs.dfxclickexternal[i]);
+               v += loadsample (tmp, &drvs[i][DS_START]);
+               sprintf (tmp, "%suae_data%cdrive_snatch_%s", start_path, FSDB_DIR_SEPARATOR, currprefs.dfxclickexternal[i]);
+               v += loadsample (tmp, &drvs[i][DS_SNATCH]);
+           }
+           if (v == 0) {
+               int j;
+               for (j = 0; j < DS_END; j++)
+                   freesample (&drvs[i][j]);
+               currprefs.dfxclick[i] = changed_prefs.dfxclick[i] = 0;
+           }
+           for (j = 0; j < DS_END; j++)
+               drvs[i][j].len <<= DS_SHIFT;
+           drvs[i][DS_CLICK].pos = drvs[i][DS_CLICK].len;
+           drvs[i][DS_SNATCH].pos = drvs[i][DS_SNATCH].len;
+           vv += currprefs.dfxclick[i];
+       }
+    }
+    if (vv > 0) {
+       driveclick_reset ();
+       click_initialized = 1;
+    }
+}
+
+void driveclick_reset (void)
+{
+    free (clickbuffer);
+    clickbuffer = xmalloc (sndbufsize);
+    sample_step = (freq << DS_SHIFT) / currprefs.sound_freq;
+}
+
+void driveclick_free (void)
+{
+    int i, j;
+
+    for (i = 0; i < 4; i++) {
+       for (j = 0; j < DS_END; j++)
+           freesample (&drvs[i][j]);
+    }
+    memset (drvs, 0, sizeof (drvs));
+    free (clickbuffer);
+    clickbuffer = 0;
+    click_initialized = 0;
+}
+
+STATIC_INLINE uae_s16 getsample(void)
+{
+    uae_s32 smp = 0;
+    int div = 0, i;
+
+    for (i = 0; i < 4; i++) {
+       if (currprefs.dfxclick[i]) {
+           struct drvsample *ds_start = &drvs[i][DS_START];
+           struct drvsample *ds_spin = drv_has_disk[i] ? &drvs[i][DS_SPIN] : &drvs[i][DS_SPINND];
+           struct drvsample *ds_click = &drvs[i][DS_CLICK];
+           struct drvsample *ds_snatch = &drvs[i][DS_SNATCH];
+           div += 2;
+           if (drv_spinning[i] || drv_starting[i]) {
+               if (drv_starting[i] && drv_has_spun[i]) {
+                   if (ds_start->p && ds_start->pos < ds_start->len) {
+                       smp = ds_start->p[ds_start->pos >> DS_SHIFT];
+                       ds_start->pos += sample_step;
+                   } else {
+                       drv_starting[i] = 0;
+                   }
+               } else if (drv_starting[i] && drv_has_spun[i] == 0) {
+                   if (ds_snatch->p && ds_snatch->pos < ds_snatch->len) {
+                       smp = ds_snatch->p[ds_snatch->pos >> DS_SHIFT];
+                       ds_snatch->pos += sample_step;
+                   } else {
+                       drv_starting[i] = 0;
+                       ds_start->pos = ds_start->len;
+                       drv_has_spun[i] = 1;
+                   }
+               }
+               if (ds_spin->p && drv_starting[i] == 0) {
+                   if (ds_spin->pos >= ds_spin->len)
+                       ds_spin->pos -= ds_spin->len;
+                   smp = ds_spin->p[ds_spin->pos >> DS_SHIFT];
+                   ds_spin->pos += sample_step;
+               }
+           }
+           if (ds_click->p && ds_click->pos < ds_click->len) {
+               smp += ds_click->p[ds_click->pos >> DS_SHIFT];
+               ds_click->pos += sample_step;
+           }
+       }
+    }
+    if (!div)
+       return 0;
+    return smp / div;
+}
+
+static int clickcnt;
+
+static void mix (void)
+{
+    int total = ((uae_u8*)sndbufpt - (uae_u8*)sndbuffer) / (currprefs.stereo ? 4 : 2);
+    if (currprefs.dfxclickvolume > 0) {
+       while (clickcnt < total) {
+           clickbuffer[clickcnt++] = getsample() * (100 - currprefs.dfxclickvolume) / 100;
+       }
+    } else {
+       while (clickcnt < total) {
+           clickbuffer[clickcnt++] = getsample();
+       }
+    }
+    if (clickcnt > 0)
+       clickbuffer[clickcnt] = clickbuffer[clickcnt - 1];
+}
+
+STATIC_INLINE uae_s16 limit (uae_s32 v)
+{
+    if (v < -32768)
+       v = -32768;
+    if (v > 32767)
+       v = 32767;
+    return v;
+}
+
+void driveclick_mix (uae_s16 *sndbuffer, int size)
+{
+    int i;
+
+    if (!click_initialized)
+       return;
+    mix();
+    clickcnt = 0;
+    if (currprefs.stereo) {
+        for (i = 0; i < size / 2; i++) {
+           uae_s16 s = clickbuffer[i];
+           sndbuffer[0] = limit(((sndbuffer[0] + s) * 2) / 3);
+           sndbuffer[1] = limit(((sndbuffer[1] + s) * 2) / 3);
+           sndbuffer += 2;
+        }
+    } else {
+        for (i = 0; i < size; i++) {
+           sndbuffer[0] = limit(((sndbuffer[0] + clickbuffer[i]) * 2) / 3);
+           sndbuffer++;
+       }
+    }
+}
+
+void driveclick_click (int drive, int startOffset)
+{
+    if (!click_initialized)
+       return;
+    if (!currprefs.dfxclick[drive])
+       return;
+    mix();
+    drvs[drive][DS_CLICK].pos = (startOffset * 4) << DS_SHIFT;
+    if (drvs[drive][DS_CLICK].pos > drvs[drive][DS_CLICK].len / 2)
+       drvs[drive][DS_CLICK].pos = drvs[drive][DS_CLICK].len / 2;
+}
+
+void driveclick_motor (int drive, int running)
+{
+    if (!click_initialized)
+       return;
+    if (!currprefs.dfxclick[drive])
+       return;
+    mix();
+    if (running == 0) {
+       drv_starting[drive] = 0;
+       drv_spinning[drive] = 0;
+    } else {
+        if (drv_spinning[drive] == 0) {
+           drv_starting[drive] = 1;
+           drv_spinning[drive] = 1;
+           if (drv_has_disk[drive] && drv_has_spun[drive] == 0 && drvs[drive][DS_SNATCH].pos >= drvs[drive][DS_SNATCH].len)
+               drvs[drive][DS_SNATCH].pos = 0;
+           if (running == 2)
+               drvs[drive][DS_START].pos = 0;
+           drvs[drive][DS_SPIN].pos = 0;
+       }
+    }
+}
+
+void driveclick_insert (int drive, int eject)
+{
+    if (!click_initialized)
+       return;
+    if (!currprefs.dfxclick[drive])
+       return;
+    if (eject)
+       drv_has_spun[drive] = 0;
+    drv_has_disk[drive] = !eject;
+}
+
+void driveclick_check_prefs (void)
+{
+    int i;
+
+    if (currprefs.dfxclickvolume != changed_prefs.dfxclickvolume ||
+       currprefs.dfxclick[0] != changed_prefs.dfxclick[0] ||
+       currprefs.dfxclick[1] != changed_prefs.dfxclick[1] ||
+       currprefs.dfxclick[2] != changed_prefs.dfxclick[2] ||
+       currprefs.dfxclick[3] != changed_prefs.dfxclick[3] ||
+       strcmp (currprefs.dfxclickexternal[0], changed_prefs.dfxclickexternal[0]) ||
+       strcmp (currprefs.dfxclickexternal[1], changed_prefs.dfxclickexternal[1]) ||
+       strcmp (currprefs.dfxclickexternal[2], changed_prefs.dfxclickexternal[2]) ||
+       strcmp (currprefs.dfxclickexternal[3], changed_prefs.dfxclickexternal[3]))
+    {
+       currprefs.dfxclickvolume = changed_prefs.dfxclickvolume;
+       for (i = 0; i < 4; i++) {
+           currprefs.dfxclick[i] = changed_prefs.dfxclick[i];
+           strcpy (currprefs.dfxclickexternal[i], changed_prefs.dfxclickexternal[i]);
+       }
+       driveclick_init ();
+    }
+}
+
+#endif
\ No newline at end of file
diff --git a/enforcer.c b/enforcer.c
new file mode 100755 (executable)
index 0000000..74a5070
--- /dev/null
@@ -0,0 +1,588 @@
+/*
+ * UAE - The Un*x Amiga Emulator
+ * 
+ * Enforcer Like Support
+ *
+ * Copyright 2000-2003 Bernd Roesch and Sebastian Bauer
+ */
+
+#include <stdlib.h>
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "memory.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "enforcer.h"
+
+/* Configurable options */
+#define ENFORCESIZE 1024
+#define STACKLINES 5
+#define INSTRUCTIONLINES 17
+
+#define ISILLEGAL(addr) (addr < 4 || (addr > 4 && addr < ENFORCESIZE))
+
+extern uae_u32 natmem_offset;
+
+int flashscreen = 0;
+static int enforcer_installed = 0;
+static int enforcer_hit = 0; /* set to 1 if displaying the hit */
+
+#define ENFORCER_BUF_SIZE 4096
+static char enforcer_buf[ENFORCER_BUF_SIZE];
+
+uae_u32 REGPARAM2      (*saved_chipmem_lget) (uaecptr addr);
+uae_u32 REGPARAM2      (*saved_chipmem_wget) (uaecptr addr);
+uae_u32 REGPARAM2      (*saved_chipmem_bget) (uaecptr addr);
+void REGPARAM2         (*saved_chipmem_lput) (uaecptr addr, uae_u32 l);
+void REGPARAM2         (*saved_chipmem_wput) (uaecptr addr, uae_u32 w);
+void REGPARAM2         (*saved_chipmem_bput) (uaecptr addr, uae_u32 b);
+int REGPARAM2          (*saved_chipmem_check) (uaecptr addr, uae_u32 size);
+uae_u8 * REGPARAM2     (*saved_chipmem_xlate) (uaecptr addr);
+uae_u32 REGPARAM2      (*saved_dummy_lget) (uaecptr addr);
+uae_u32 REGPARAM2      (*saved_dummy_wget) (uaecptr addr);
+uae_u32 REGPARAM2      (*saved_dummy_bget) (uaecptr addr);
+void REGPARAM2         (*saved_dummy_lput) (uaecptr addr, uae_u32 l);
+void REGPARAM2         (*saved_dummy_wput) (uaecptr addr, uae_u32 w);
+void REGPARAM2         (*saved_dummy_bput) (uaecptr addr, uae_u32 b);
+int REGPARAM2          (*saved_dummy_check) (uaecptr addr, uae_u32 size);
+
+/*************************************************************
+ Returns the first node entry of an exec list or 0 if
+ empty
+*************************************************************/
+static uae_u32 amiga_list_first(uae_u32 list)
+{
+       uae_u32 node = get_long(list);      /* lh_Head */
+       if (!node) return 0;
+       if (!get_long(node)) return 0;   /* ln_Succ */
+       return node;
+}
+
+/*************************************************************
+ Returns the next node of an exec node or 0 if it was the
+ last element
+*************************************************************/
+static uae_u32 amiga_node_next(uae_u32 node)
+{
+       uae_u32 next = get_long(node);    /* ln_Succ */
+       if (!next) return 0;
+       if (!get_long(next)) return 0; /* ln_Succ */
+       return next;
+}
+
+/*************************************************************
+ Converts an amiga address to a native one or NULL if this
+ is not possible, Size specified the number of bytes you
+ want to access
+*************************************************************/
+static uae_u8 *amiga2native(uae_u32 aptr, int size)
+{
+       addrbank bank = get_mem_bank(aptr);
+
+       /* Check if the address can be translated to native */
+       if (bank.check(aptr,size))
+       {
+               return bank.xlateaddr(aptr);
+       }
+       return NULL;
+}
+
+/*************************************************************
+ Writes the Hunk and Offset of the given Address into buf
+*************************************************************/
+static int enforcer_decode_hunk_and_offset(char *buf, uae_u32 pc)
+{
+       uae_u32 sysbase = get_long(4);
+       uae_u32 semaphore_list = sysbase + 532;
+
+       /* First step is searching for the SegTracker semaphore */
+       uae_u32 node = amiga_list_first(semaphore_list);
+       while (node)
+       {
+               uae_u32 string = get_long(node+10); /* ln_Name */
+               uae_u8 *native_string = amiga2native(string,100);
+
+               if (native_string)
+               {
+                       if (!strcmp(native_string,"SegTracker"))
+                               break;
+               }
+               node = amiga_node_next(node);
+       }
+
+       if (node)
+       {
+               /* We have found the segtracker semaphore. Soon after the
+                * public documented semaphore structure Segtracker holds
+                * an own list of all segements. We will use this list to
+                * find out the hunk and offset (simliar to segtracker).
+                *
+                * Source of segtracker can be found at:
+                *    http://www.sinz.org/Michael.Sinz/Enforcer/SegTracker.c.html
+                */
+               
+               uae_u32 seg_list = node + 46 + 4; /* sizeof(struct SignalSemaphore) + seg find */
+
+               node = amiga_list_first(seg_list);
+               while (node)
+               {
+                       uae_u32 seg_entry = node + 12;
+                       uae_u32 address, size;
+                       int hunk = 0;
+
+                       /* Go through all entries until an address is 0
+                        * or the segment has been found */
+                       while ((address = get_long(seg_entry)))
+                       {
+                               size = get_long(seg_entry+4);
+
+                               if (pc >= address && pc < address + size)
+                               {
+                                       uae_u32 name,offset;
+                                       uae_u8 *native_name;
+
+                                       offset = pc - address - 4;
+                                       name = get_long(node + 8); /* ln_Name */
+                                       if (name)
+                                       {
+                                               native_name = amiga2native(name,100);
+                                               if (!native_name) native_name = "Unknown";
+                                       } else native_name = "Unknown";
+
+                                       sprintf(buf,"----> %08lx - \"%s\" Hunk %04lx Offset %08lx\n",pc,native_name,hunk,offset);
+                                       return 1;
+                               }
+
+                               seg_entry += 8;
+                               hunk++;
+                       }
+                       node = amiga_node_next(node);
+               }
+       }
+       return 0;
+}
+
+/*************************************************************
+ Display the enforcer hit
+*************************************************************/
+static void enforcer_display_hit(const char *addressmode, uae_u32 pc, uaecptr addr)
+{
+       uae_u32 a7;
+       uae_u32 sysbase;
+       uae_u32 this_task;
+       uae_u32 task_name;
+       uae_u8 *native_task_name;
+       int i,j;
+       static char buf[256],instrcode[256];
+       static char lines[INSTRUCTIONLINES/2][256];
+       static uaecptr bestpc_array[INSTRUCTIONLINES/2][5];
+       static int bestpc_idxs[INSTRUCTIONLINES/2];
+       char *enforcer_buf_ptr = enforcer_buf;
+       uaecptr bestpc,pospc,nextpc,temppc;
+
+       if (enforcer_hit) return; /* our function itself generated a hit ;), avoid endless loop */
+       enforcer_hit = 1;
+
+       if (!(sysbase = get_long(4))) return;
+       if (!(this_task = get_long(sysbase + 276))) return;
+
+       task_name = get_long(this_task + 10); /* ln_Name */
+       native_task_name = amiga2native(task_name,100);
+
+       strcpy(enforcer_buf_ptr,"Enforcer Hit! Bad program\n");
+       enforcer_buf_ptr += strlen(enforcer_buf_ptr);
+
+       sprintf(buf,"Illegal %s: %08lx",addressmode, addr);
+       sprintf(enforcer_buf_ptr,"%-48sPC: %0lx\n",buf, pc);
+       enforcer_buf_ptr += strlen(enforcer_buf_ptr);
+
+       /* Data registers */
+       sprintf(enforcer_buf_ptr,"Data: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+               m68k_dreg (regs, 0), m68k_dreg (regs, 1), m68k_dreg (regs, 2), m68k_dreg (regs, 3),
+               m68k_dreg (regs, 4), m68k_dreg (regs, 5), m68k_dreg (regs, 6), m68k_dreg (regs, 7));
+       enforcer_buf_ptr += strlen(enforcer_buf_ptr);
+
+       /* Address registers */
+       sprintf(enforcer_buf_ptr,"Addr: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+               m68k_areg (regs, 0), m68k_areg (regs, 1), m68k_areg (regs, 2), m68k_areg (regs, 3),
+               m68k_areg (regs, 4), m68k_areg (regs, 5), m68k_areg (regs, 6), m68k_areg (regs, 7));
+       enforcer_buf_ptr += strlen(enforcer_buf_ptr);
+
+       /* Stack */
+       a7 = m68k_areg(regs,7);
+       for (i = 0; i < 8 * STACKLINES; i++)
+       {
+               a7 -= 4;
+               if (!(i % 8))
+               {
+                       strcpy(enforcer_buf_ptr,"Stck:");
+                       enforcer_buf_ptr += strlen(enforcer_buf_ptr);
+               }
+               sprintf(enforcer_buf_ptr," %08lx",get_long(a7));
+               enforcer_buf_ptr += strlen(enforcer_buf_ptr);
+
+               if (i%8 == 7)
+                       *enforcer_buf_ptr++ = '\n';
+       }
+
+       /* Segtracker output */
+       a7 = m68k_areg(regs,7);
+       if (get_long(a7-4) != pc)
+       {
+               if (enforcer_decode_hunk_and_offset(buf,pc))
+               {
+                       strcpy(enforcer_buf_ptr, buf);
+                       enforcer_buf_ptr += strlen(enforcer_buf_ptr);
+               }
+       }
+
+       for (i = 0; i < 8 * STACKLINES; i++)
+       {
+               a7 -= 4;
+               if (enforcer_decode_hunk_and_offset(buf,get_long(a7)))
+               {
+                       int l= strlen(buf);
+
+                       if (ENFORCER_BUF_SIZE - (enforcer_buf_ptr - enforcer_buf) > l + 256)
+                       {
+                               strcpy(enforcer_buf_ptr, buf);
+                               enforcer_buf_ptr += l;
+                       }
+               }
+       }
+
+       /* Decode the instructions around the pc where the enforcer hit was caused.
+        *
+        * At first, the area before the pc, this not always done correctly because
+        * it's done backwards */
+       temppc = pc;
+       
+       memset(bestpc_array,0,sizeof(bestpc_array));
+       for (i=0;i<INSTRUCTIONLINES/2;i++)
+               bestpc_idxs[i] = -1;
+
+       for (i=0;i<INSTRUCTIONLINES/2;i++)
+       {
+               pospc = temppc;
+               bestpc = 0;
+
+               if (bestpc_idxs[i] == -1)
+               {
+                       for (j=0;j<5;j++)
+                       {
+                               pospc -= 2;
+                               sm68k_disasm(buf, NULL, pospc, &nextpc);
+                               if (nextpc == temppc)
+                               {
+                                       bestpc_idxs[i] = j;
+                                       bestpc_array[i][j] = bestpc = pospc;
+                               }
+                       }
+               } else
+               {
+                       bestpc = bestpc_array[i][bestpc_idxs[i]];
+               }
+
+               if (!bestpc)
+               {
+                       /* there was no best pc found, so it is high probable that
+                        * a former used best pc was wrong.
+                        *
+                        * We trace back and use the former best pc instead
+                        */
+
+                       int former_idx;
+                       int leave = 0;
+
+                       do
+                       {
+                               if (!i)
+                               {
+                                       leave = 1;
+                                       break;
+                               }
+                               i--;
+                               former_idx = bestpc_idxs[i];
+                               bestpc_idxs[i] = -1;
+                               bestpc_array[i][former_idx]=0;
+
+                               for (j=former_idx-1;j>=0;j--)
+                               {
+                                       if (bestpc_array[i][j])
+                                       {
+                                               bestpc_idxs[i] = j;
+                                               break;
+                                       }
+                               }
+                       } while (bestpc_idxs[i] == -1);
+                       if (leave) break;
+                       if (i) temppc = bestpc_array[i-1][bestpc_idxs[i-1]];
+                       else temppc = pc;
+                       i--; /* will be increased in after continue */
+                       continue;
+               }
+
+               sm68k_disasm(buf, instrcode, bestpc, NULL);
+               sprintf(lines[i],"%08lx :   %-20s %s\n",bestpc,instrcode,buf);
+               temppc = bestpc;
+       }
+
+       i--;
+       for (;i>=0;i--)
+       {
+               strcpy(enforcer_buf_ptr,lines[i]);
+               enforcer_buf_ptr += strlen(enforcer_buf_ptr);
+       }
+
+       /* Now the instruction after the pc including the pc */
+       temppc = pc;
+       for (i=0;i<(INSTRUCTIONLINES+1)/2;i++)
+       {
+               sm68k_disasm(buf, instrcode, temppc, &nextpc);
+               sprintf(enforcer_buf_ptr,"%08lx : %s %-20s %s\n",temppc,(i==0?"*":" "),instrcode,buf);
+               enforcer_buf_ptr += strlen(enforcer_buf_ptr);
+               temppc = nextpc;
+       }
+
+       if (!native_task_name) native_task_name = "Unknown";
+       sprintf(enforcer_buf_ptr,"Name: \"%s\"\n\n",native_task_name);
+       enforcer_buf_ptr += strlen(enforcer_buf_ptr);
+
+       console_out(enforcer_buf);
+       write_log(enforcer_buf);
+
+       enforcer_hit = 0;
+       flashscreen = 30;
+}
+
+uae_u32 REGPARAM2 chipmem_lget2 (uaecptr addr)
+{
+    uae_u32 *m;
+
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    m = (uae_u32 *)(chipmemory + addr);
+       
+       if (ISILLEGAL(addr))
+               enforcer_display_hit("LONG READ from",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr);
+
+    return do_get_mem_long (m);
+}
+
+uae_u32 REGPARAM2 chipmem_wget2(uaecptr addr)
+{
+    uae_u16 *m;
+
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    m = (uae_u16 *)(chipmemory + addr);
+
+       if (ISILLEGAL(addr))
+               enforcer_display_hit("WORD READ from",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr);
+
+    return do_get_mem_word (m);
+}
+
+uae_u32 REGPARAM2 chipmem_bget2 (uaecptr addr)
+{
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+
+       if (ISILLEGAL(addr))
+               enforcer_display_hit("BYTE READ from",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr);
+
+    return chipmemory[addr];
+}
+
+void REGPARAM2 chipmem_lput2 (uaecptr addr, uae_u32 l)
+{
+    uae_u32 *m;
+    
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    m = (uae_u32 *)(chipmemory + addr);
+
+       if (ISILLEGAL(addr))
+               enforcer_display_hit("LONG WRITE to",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr);
+
+    do_put_mem_long (m, l);
+}
+
+void REGPARAM2 chipmem_wput2 (uaecptr addr, uae_u32 w)
+{
+    uae_u16 *m;
+
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    m = (uae_u16 *)(chipmemory + addr);
+
+       if (ISILLEGAL(addr))
+               enforcer_display_hit("WORD WRITE to",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr);
+   
+    do_put_mem_word (m, w);
+}
+
+
+void REGPARAM2 chipmem_bput2 (uaecptr addr, uae_u32 b)
+{
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+
+       if (ISILLEGAL(addr))
+               enforcer_display_hit("BYTE WRITE to",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr);
+    chipmemory[addr] = b;
+}
+
+int REGPARAM2 chipmem_check2 (uaecptr addr, uae_u32 size)
+{
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    return (addr + size) <= allocated_chipmem;
+}
+
+uae_u8 * REGPARAM2 chipmem_xlate2 (uaecptr addr)
+{
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    return chipmemory + addr;
+}
+
+uae_u32 REGPARAM2 dummy_lget2 (uaecptr addr)
+{
+    special_mem |= S_READ;
+       enforcer_display_hit("LONG READ from",(uae_u32)(regs.pc_p - NATMEM_OFFSET), addr);
+       return 0xbadedeef;
+}
+
+#ifdef JIT
+static int warned_JIT_0xF10000 = 0;
+#endif
+
+uae_u32 REGPARAM2 dummy_wget2 (uaecptr addr)
+{
+
+    special_mem |= S_READ;
+
+#ifdef JIT
+       if( addr >= 0x00F10000 && addr <= 0x00F7FFFF )
+       {
+           if( !warned_JIT_0xF10000 )
+           {
+                       warned_JIT_0xF10000 = 1;
+                       enforcer_display_hit("LONG READ from",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr);
+           }
+           return 0;
+       }
+#endif
+       enforcer_display_hit("WORD READ from",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr);
+       return 0xbadf;
+}
+
+uae_u32 REGPARAM2 dummy_bget2 (uaecptr addr)
+{
+    special_mem |= S_READ;
+       enforcer_display_hit("BYTE READ from",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr);
+       return 0xbadedeef;
+}
+
+void REGPARAM2 dummy_lput2 (uaecptr addr, uae_u32 l)
+{
+    special_mem |= S_WRITE;
+       enforcer_display_hit("LONG WRITE to",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr);
+}
+
+void REGPARAM2 dummy_wput2 (uaecptr addr, uae_u32 w)
+{
+    special_mem |= S_WRITE;
+       enforcer_display_hit("WORD WRITE to",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr);
+}
+
+void REGPARAM2 dummy_bput2 (uaecptr addr, uae_u32 b)
+{
+    special_mem |= S_WRITE;
+       enforcer_display_hit("BYTE WRITE to",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr);
+}
+
+int REGPARAM2 dummy_check2 (uaecptr addr, uae_u32 size)
+{
+    special_mem |= S_READ;
+       enforcer_display_hit("CHECK from ",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr);
+    return 0;
+}
+
+
+/*************************************************************
+ enable the enforcer like support, maybe later this make MMU
+ exceptions so enforcer can use it. Returns 1 if enforcer
+ is enabled
+*************************************************************/
+int enforcer_enable(void)
+{
+       extern addrbank chipmem_bank,dummy_bank;
+
+       if (!enforcer_installed)
+       {
+               saved_dummy_lget = dummy_bank.lget;
+               saved_dummy_wget = dummy_bank.wget;
+               saved_dummy_bget = dummy_bank.bget;
+               saved_dummy_lput = dummy_bank.lput;
+               saved_dummy_wput = dummy_bank.wput;
+               saved_dummy_bput = dummy_bank.bput;
+               saved_chipmem_lget = chipmem_bank.lget;
+               saved_chipmem_wget = chipmem_bank.wget;
+               saved_chipmem_bget = chipmem_bank.bget;
+               saved_chipmem_lput = chipmem_bank.lput;
+               saved_chipmem_wput = chipmem_bank.wput;
+               saved_chipmem_bput = chipmem_bank.bput;
+               saved_chipmem_xlate = chipmem_bank.xlateaddr;
+               saved_chipmem_check = chipmem_bank.check;
+
+               dummy_bank.lget = dummy_lget2;
+           dummy_bank.wget = dummy_wget2;
+               dummy_bank.bget = dummy_bget2;
+               dummy_bank.lput = dummy_lput2;
+           dummy_bank.wput = dummy_wput2;
+               dummy_bank.bput = dummy_bput2;
+           chipmem_bank.lget = chipmem_lget2;
+           chipmem_bank.wget = chipmem_wget2;
+           chipmem_bank.bget = chipmem_bget2;
+           chipmem_bank.lput = chipmem_lput2;
+           chipmem_bank.wput = chipmem_wput2;
+           chipmem_bank.bput = chipmem_bput2;
+               chipmem_bank.xlateaddr = chipmem_xlate2;
+               chipmem_bank.check = chipmem_check2;
+
+               enforcer_installed = 1;
+       }
+       return 1;
+}
+
+/*************************************************************
+ Disable Enforcer like support
+*************************************************************/
+int enforcer_disable(void)
+{
+       if (enforcer_installed)
+       {
+               dummy_bank.lget = saved_dummy_lget;
+           dummy_bank.wget = saved_dummy_wget;
+               dummy_bank.bget = saved_dummy_bget;
+               dummy_bank.lput = saved_dummy_lput;
+           dummy_bank.wput = saved_dummy_wput;
+               dummy_bank.bput = saved_dummy_bput;
+           chipmem_bank.lget = saved_chipmem_lget;
+           chipmem_bank.wget = saved_chipmem_wget;
+           chipmem_bank.bget = saved_chipmem_bget;
+           chipmem_bank.lput = saved_chipmem_lput;
+           chipmem_bank.wput = saved_chipmem_wput;
+           chipmem_bank.bput = saved_chipmem_bput;
+               chipmem_bank.xlateaddr = saved_chipmem_xlate;
+               chipmem_bank.check = saved_chipmem_check;
+
+               enforcer_installed = 0;
+       }
+       return 1;
+}
+
diff --git a/ersatz.c b/ersatz.c
new file mode 100755 (executable)
index 0000000..4b364fc
--- /dev/null
+++ b/ersatz.c
@@ -0,0 +1,240 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * A "replacement" for a missing Kickstart
+  * Warning! Q&D
+  *
+  * (c) 1995 Bernd Schmidt
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "uae.h"
+#include "memory.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "cpu_prefetch.h"
+#include "cia.h"
+#include "disk.h"
+#include "ersatz.h"
+
+#define EOP_INIT     0
+#define EOP_NIMP     1
+#define EOP_SERVEINT 2
+#define EOP_DOIO     3
+#define EOP_OPENLIB  4
+#define EOP_AVAILMEM 5
+#define EOP_ALLOCMEM 6
+#define EOP_ALLOCABS 7
+#define EOP_LOOP 8
+
+void init_ersatz_rom (uae_u8 *data)
+{
+    *data++ = 0x00; *data++ = 0x08; /* initial SP */
+    *data++ = 0x00; *data++ = 0x00;
+    *data++ = 0x00; *data++ = 0xF8; /* initial PC */
+    *data++ = 0x00; *data++ = 0x08;
+
+    *data++ = 0xFF; *data++ = 0x0D;
+    *data++ = 0x00; *data++ = EOP_INIT;
+    *data++ = 0xFF; *data++ = 0x0D;
+    *data++ = 0x00; *data++ = EOP_NIMP;
+
+    *data++ = 0xFF; *data++ = 0x0D;
+    *data++ = 0x00; *data++ = EOP_LOOP;
+    *data++ = 0xFF; *data++ = 0x0D;
+    *data++ = 0x00; *data++ = EOP_DOIO;
+
+    *data++ = 0x4E; *data++ = 0x75;
+    *data++ = 0xFF; *data++ = 0x0D;
+    *data++ = 0x00; *data++ = EOP_SERVEINT;
+    *data++ = 0x4E; *data++ = 0x73;
+
+    *data++ = 0xFF; *data++ = 0x0D;
+    *data++ = 0x00; *data++ = EOP_AVAILMEM;
+    *data++ = 0x4E; *data++ = 0x75;
+    *data++ = 0xFF; *data++ = 0x0D;
+
+    *data++ = 0x00; *data++ = EOP_ALLOCMEM;
+    *data++ = 0x4E; *data++ = 0x75;
+    *data++ = 0xFF; *data++ = 0x0D;
+    *data++ = 0x00; *data++ = EOP_ALLOCABS;
+
+    *data++ = 0x4E; *data++ = 0x75;
+}
+
+static void ersatz_doio (void)
+{
+    uaecptr request = m68k_areg(regs, 1);
+    switch (get_word (request + 0x1C)) {
+     case 9: /* TD_MOTOR is harmless */
+     case 2: case 0x8002: /* READ commands */
+       break;
+
+     default:
+       write_log ("Only CMD_READ supported in DoIO()\n");
+       abort();
+    }
+    {
+       uaecptr dest = get_long (request + 0x28);
+       int start = get_long (request + 0x2C) / 512;
+       int nsecs = get_long (request + 0x24) / 512;
+       int tr = start / 11;
+       int sec = start % 11;
+       while (nsecs--) {
+           DISK_ersatz_read (tr, sec, dest);
+           dest += 512;
+           if (++sec == 11)
+               sec = 0, tr++;
+       }
+    }
+}
+
+static void ersatz_init (void)
+{
+    int f;
+    uaecptr request;
+    uaecptr a;
+
+    if (disk_empty (0)) {
+       gui_message ("You need to have a diskfile in DF0 to use the Kickstart replacement!\n");
+       uae_quit ();
+       m68k_setpc (0xF80010);
+       return;
+    }
+
+    regs.s = 0;
+    /* Set some interrupt vectors */
+    for (a = 8; a < 0xC0; a += 4) {
+       put_long (a, 0xF8001A);
+    }
+    regs.isp = regs.msp = regs.usp = 0x800;
+    m68k_areg(regs, 7) = 0x80000;
+    regs.intmask = 0;
+
+    /* Build a dummy execbase */
+    put_long (4, m68k_areg(regs, 6) = 0x676);
+    put_byte (0x676 + 0x129, 0);
+    for (f = 1; f < 105; f++) {
+       put_word (0x676 - 6*f, 0x4EF9);
+       put_long (0x676 - 6*f + 2, 0xF8000C);
+    }
+    /* Some "supported" functions */
+    put_long (0x676 - 456 + 2, 0xF80014);
+    put_long (0x676 - 216 + 2, 0xF80020);
+    put_long (0x676 - 198 + 2, 0xF80026);
+    put_long (0x676 - 204 + 2, 0xF8002c);
+    put_long (0x676 - 210 + 2, 0xF8002a);
+
+    /* Build an IORequest */
+    request = 0x800;
+    put_word (request + 0x1C, 2);
+    put_long (request + 0x28, 0x4000);
+    put_long (request + 0x2C, 0);
+    put_long (request + 0x24, 0x200 * 4);
+    m68k_areg(regs, 1) = request;
+    ersatz_doio ();
+    /* kickstart disk loader */
+    if (get_long(0x4000) == 0x4b49434b) {
+       /* a kickstart disk was found in drive 0! */
+       write_log ("Loading Kickstart rom image from Kickstart disk\n");
+       /* print some notes... */
+       write_log ("NOTE: if UAE crashes set CPU to 68000 and/or chipmem size to 512KB!\n");
+
+       /* read rom image from kickstart disk */
+       put_word (request + 0x1C, 2);
+       put_long (request + 0x28, 0xF80000);
+       put_long (request + 0x2C, 0x200);
+       put_long (request + 0x24, 0x200 * 512);
+       m68k_areg(regs, 1) = request;
+       ersatz_doio ();
+
+       /* read rom image once again to mirror address space.
+          not elegant, but it works... */
+       put_word (request + 0x1C, 2);
+       put_long (request + 0x28, 0xFC0000);
+       put_long (request + 0x2C, 0x200);
+       put_long (request + 0x24, 0x200 * 512);
+       m68k_areg(regs, 1) = request;
+       ersatz_doio ();
+
+       disk_eject (0);
+
+       m68k_setpc (0xFC0002);
+       fill_prefetch_slow ();
+       uae_reset (0);
+       ersatzkickfile = 0;
+       return;
+    }
+
+    m68k_setpc (0x400C);
+    fill_prefetch_slow ();
+
+    /* Init the hardware */
+    put_long (0x3000, 0xFFFFFFFEul);
+    put_long (0xDFF080, 0x3000);
+    put_word (0xDFF088, 0);
+    put_word (0xDFF096, 0xE390);
+    put_word (0xDFF09A, 0xE02C);
+    put_word (0xDFF09E, 0x0000);
+    put_word (0xDFF092, 0x0038);
+    put_word (0xDFF094, 0x00D0);
+    put_word (0xDFF08E, 0x2C81);
+    put_word (0xDFF090, 0xF4C1);
+    put_word (0xDFF02A, 0x8000);
+
+    put_byte (0xBFD100, 0xF7);
+    put_byte (0xBFEE01, 0);
+    put_byte (0xBFEF01, 0x08);
+    put_byte (0xBFDE00, 0x04);
+    put_byte (0xBFDF00, 0x84);
+    put_byte (0xBFDD00, 0x9F);
+    put_byte (0xBFED01, 0x9F);
+}
+
+void ersatz_perform (uae_u16 what)
+{
+    switch (what) {
+     case EOP_INIT:
+       ersatz_init ();
+       break;
+
+     case EOP_SERVEINT:
+       /* Just reset all the interrupt request bits */
+       put_word (0xDFF09C, get_word (0xDFF01E) & 0x3FFF);
+       break;
+
+     case EOP_DOIO:
+       ersatz_doio ();
+       break;
+
+     case EOP_AVAILMEM:
+       m68k_dreg(regs, 0) = m68k_dreg(regs, 1) & 4 ? 0 : 0x70000;
+       break;
+
+     case EOP_ALLOCMEM:
+       m68k_dreg(regs, 0) = m68k_dreg(regs, 1) & 4 ? 0 : 0x0F000;
+       break;
+
+     case EOP_ALLOCABS:
+       m68k_dreg(regs, 0) = m68k_areg(regs, 1);
+       break;
+
+     case EOP_NIMP:
+       write_log ("Unimplemented Kickstart function called\n");
+       uae_quit ();
+       
+       /* fall through */
+     case EOP_LOOP:
+       m68k_setpc (0xF80010);
+       break;
+
+     case EOP_OPENLIB:
+     default:
+       write_log ("Internal error. Giving up.\n");
+       abort ();
+    }
+}
diff --git a/expansion.c b/expansion.c
new file mode 100755 (executable)
index 0000000..3cbd1f2
--- /dev/null
@@ -0,0 +1,1310 @@
+ /* 
+  * UAE - The Un*x Amiga Emulator
+  *
+  * AutoConfig (tm) Expansions (ZorroII/III)
+  *
+  * Copyright 1996,1997 Stefan Reinauer <stepan@linux.de>
+  * Copyright 1997 Brian King <Brian_King@Mitel.com>
+  *   - added gfxcard code
+  *
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "uae.h"
+#include "memory.h"
+#include "autoconf.h"
+#include "picasso96.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "savestate.h"
+#include "zfile.h"
+#include "catweasel.h"
+
+#define MAX_EXPANSION_BOARDS   8
+
+/* ********************************************************** */
+/* 00 / 02 */
+/* er_Type */
+
+#define Z2_MEM_8MB     0x00 /* Size of Memory Block */
+#define Z2_MEM_4MB     0x07
+#define Z2_MEM_2MB     0x06
+#define Z2_MEM_1MB     0x05
+#define Z2_MEM_512KB   0x04
+#define Z2_MEM_256KB   0x03
+#define Z2_MEM_128KB   0x02
+#define Z2_MEM_64KB    0x01
+/* extended definitions */
+#define Z2_MEM_16MB    0x00
+#define Z2_MEM_32MB    0x01
+#define Z2_MEM_64MB    0x02
+#define Z2_MEM_128MB   0x03
+#define Z2_MEM_256MB   0x04
+#define Z2_MEM_512MB   0x05
+#define Z2_MEM_1GB     0x06
+
+#define chainedconfig  0x08 /* Next config is part of the same card */
+#define rom_card       0x10 /* ROM vector is valid */
+#define add_memory     0x20 /* Link RAM into free memory list */
+
+#define zorroII                0xc0 /* Type of Expansion Card */
+#define zorroIII       0x80
+
+/* ********************************************************** */
+/* 04 - 06 & 10-16 */
+
+/* Manufacturer */
+#define commodore_g     513 /* Commodore Braunschweig (Germany) */
+#define commodore       514 /* Commodore West Chester */
+#define gvp            2017 /* GVP */
+#define ass            2102 /* Advanced Systems & Software */
+#define hackers_id     2011 /* Special ID for test cards */
+
+/* Card Type */
+#define commodore_a2091             3 /* A2091 / A590 Card from C= */
+#define commodore_a2091_ram 10 /* A2091 / A590 Ram on HD-Card */
+#define commodore_a2232            70 /* A2232 Multiport Expansion */
+#define ass_nexus_scsi      1 /* Nexus SCSI Controller */
+
+#define gvp_series_2_scsi   11
+#define gvp_iv_24_gfx      32
+
+/* ********************************************************** */
+/* 08 - 0A  */
+/* er_Flags */
+#define Z3_MEM_64KB    0x02
+#define Z3_MEM_128KB   0x03
+#define Z3_MEM_256KB   0x04
+#define Z3_MEM_512KB   0x05
+#define Z3_MEM_1MB     0x06 /* Zorro III card subsize */
+#define Z3_MEM_2MB     0x07
+#define Z3_MEM_4MB     0x08
+#define Z3_MEM_6MB     0x09
+#define Z3_MEM_8MB     0x0a
+#define Z3_MEM_10MB    0x0b
+#define Z3_MEM_12MB    0x0c
+#define Z3_MEM_14MB    0x0d
+#define Z3_MEM_16MB    0x00
+#define Z3_MEM_AUTO    0x01
+#define Z3_MEM_defunct1        0x0e
+#define Z3_MEM_defunct2        0x0f
+
+#define force_z3       0x10 /* *MUST* be set if card is Z3 */
+#define ext_size       0x20 /* Use extended size table for bits 0-2 of er_Type */
+#define no_shutup      0x40 /* Card cannot receive Shut_up_forever */
+#define care_addr      0x80 /* Adress HAS to be $200000-$9fffff */
+
+/* ********************************************************** */
+/* 40-42 */
+/* ec_interrupt (unused) */
+
+#define enable_irq     0x01 /* enable Interrupt */
+#define reset_card     0x04 /* Reset of Expansion Card - must be 0 */
+#define card_int2      0x10 /* READ ONLY: IRQ 2 active */
+#define card_irq6      0x20 /* READ ONLY: IRQ 6 active */
+#define card_irq7      0x40 /* READ ONLY: IRQ 7 active */
+#define does_irq       0x80 /* READ ONLY: Card currently throws IRQ */
+
+/* ********************************************************** */
+
+/* ROM defines (DiagVec) */
+
+#define rom_4bit       (0x00<<14) /* ROM width */
+#define rom_8bit       (0x01<<14)
+#define rom_16bit      (0x02<<14)
+
+#define rom_never      (0x00<<12) /* Never run Boot Code */
+#define rom_install    (0x01<<12) /* run code at install time */
+#define rom_binddrv    (0x02<<12) /* run code with binddrivers */
+
+uaecptr ROM_filesys_resname, ROM_filesys_resid;
+uaecptr ROM_filesys_diagentry;
+uaecptr ROM_hardfile_resname, ROM_hardfile_resid;
+uaecptr ROM_hardfile_init;
+
+/* ********************************************************** */
+
+static void (*card_init[MAX_EXPANSION_BOARDS]) (void);
+static void (*card_map[MAX_EXPANSION_BOARDS]) (void);
+
+static int ecard;
+
+/* ********************************************************** */
+
+/* Please note: ZorroIII implementation seems to work different
+ * than described in the HRM. This claims that ZorroIII config
+ * address is 0xff000000 while the ZorroII config space starts
+ * at 0x00e80000. In reality, both, Z2 and Z3 cards are 
+ * configured in the ZorroII config space. Kickstart 3.1 doesn't
+ * even do a single read or write access to the ZorroIII space.
+ * The original Amiga include files tell the same as the HRM.
+ * ZorroIII: If you set ext_size in er_Flags and give a Z2-size
+ * in er_Type you can very likely add some ZorroII address space
+ * to a ZorroIII card on a real Amiga. This is not implemented
+ * yet.
+ *  -- Stefan
+ * 
+ * Surprising that 0xFF000000 isn't used. Maybe it depends on the
+ * ROM. Anyway, the HRM says that Z3 cards may appear in Z2 config
+ * space, so what we are doing here is correct.
+ *  -- Bernd
+ */
+
+/* Autoconfig address space at 0xE80000 */
+static uae_u8 expamem[65536];
+
+static uae_u8 expamem_lo;
+static uae_u16 expamem_hi;
+
+/*
+ *  Dummy entries to show that there's no card in a slot
+ */
+
+static void expamem_map_clear (void)
+{
+    write_log ("expamem_map_clear() got called. Shouldn't happen.\n");
+}
+
+static void expamem_init_clear (void)
+{
+    memset (expamem, 0xff, sizeof expamem);
+}
+static void expamem_init_clear2 (void)
+{
+    expamem_init_clear();
+    ecard = MAX_EXPANSION_BOARDS - 1;
+}
+
+static uae_u32 expamem_lget (uaecptr) REGPARAM;
+static uae_u32 expamem_wget (uaecptr) REGPARAM;
+static uae_u32 expamem_bget (uaecptr) REGPARAM;
+static void expamem_lput (uaecptr, uae_u32) REGPARAM;
+static void expamem_wput (uaecptr, uae_u32) REGPARAM;
+static void expamem_bput (uaecptr, uae_u32) REGPARAM;
+
+addrbank expamem_bank = {
+    expamem_lget, expamem_wget, expamem_bget,
+    expamem_lput, expamem_wput, expamem_bput,
+    default_xlate, default_check, NULL
+};
+
+static uae_u32 REGPARAM2 expamem_lget (uaecptr addr)
+{
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+    write_log ("warning: READ.L from address $%lx \n", addr);
+    return 0xfffffffful;
+}
+
+static uae_u32 REGPARAM2 expamem_wget (uaecptr addr)
+{
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+    write_log ("warning: READ.W from address $%lx \n", addr);
+    return 0xffff;
+}
+
+static uae_u32 REGPARAM2 expamem_bget (uaecptr addr)
+{
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+    addr &= 0xFFFF;
+    return expamem[addr];
+}
+
+static void REGPARAM2 expamem_write (uaecptr addr, uae_u32 value)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    addr &= 0xffff;
+    if (addr == 00 || addr == 02 || addr == 0x40 || addr == 0x42) {
+       expamem[addr] = (value & 0xf0);
+       expamem[addr + 2] = (value & 0x0f) << 4;
+    } else {
+       expamem[addr] = ~(value & 0xf0);
+       expamem[addr + 2] = ~((value & 0x0f) << 4);
+    }
+}
+
+static int REGPARAM2 expamem_type (void)
+{
+    return ((expamem[0] | expamem[2] >> 4) & 0xc0);
+}
+
+static void REGPARAM2 expamem_lput (uaecptr addr, uae_u32 value)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    write_log ("warning: WRITE.L to address $%lx : value $%lx\n", addr, value);
+}
+
+static void REGPARAM2 expamem_wput (uaecptr addr, uae_u32 value)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    if (expamem_type() != zorroIII)
+       write_log ("warning: WRITE.W to address $%lx : value $%x\n", addr, value);
+    else {
+       switch (addr & 0xff) {
+        case 0x44:
+           if (expamem_type() == zorroIII) {
+               // +Bernd Roesch
+               value = value - 0x3000;  // maps to 0x10000000     
+               chipmem_wput (regs.regs[11] + 0x20, value);
+               chipmem_wput (regs.regs[11] + 0x28, value);
+               // -Bernd Roesch
+               expamem_hi = value;
+               (*card_map[ecard]) ();
+               write_log ("   Card %d (Zorro%s) done.\n", ecard + 1, expamem_type() == 0xc0 ? "II" : "III");
+               ++ecard;
+               if (ecard < MAX_EXPANSION_BOARDS)
+                   (*card_init[ecard]) ();
+               else
+                   expamem_init_clear2 ();
+           }
+           break;
+       }
+    }
+}
+
+static void REGPARAM2 expamem_bput (uaecptr addr, uae_u32 value)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    switch (addr & 0xff) {
+     case 0x30:
+     case 0x32:
+       expamem_hi = 0;
+       expamem_lo = 0;
+       expamem_write (0x48, 0x00);
+       break;
+
+     case 0x48:
+       if (expamem_type () == zorroII) {
+           expamem_hi = value & 0xFF;
+           (*card_map[ecard]) ();
+           write_log ("   Card %d (Zorro%s) done.\n", ecard + 1, expamem_type() == 0xc0 ? "II" : "III");
+           ++ecard;
+           if (ecard < MAX_EXPANSION_BOARDS)
+               (*card_init[ecard]) ();
+           else
+               expamem_init_clear2 ();
+       } else if (expamem_type() == zorroIII)
+           expamem_lo = value;
+       break;
+
+     case 0x4a:
+       if (expamem_type () == zorroII)
+           expamem_lo = value;
+       break;
+
+     case 0x4c:
+       write_log ("   Card %d (Zorro %s) had no success.\n", ecard + 1, expamem_type() == 0xc0 ? "II" : "III");
+       ++ecard;
+       if (ecard < MAX_EXPANSION_BOARDS)
+           (*card_init[ecard]) ();
+       else
+           expamem_init_clear2 ();
+       break;
+    }
+}
+
+/* ********************************************************** */
+
+/*
+ *  Fast Memory
+ */
+
+static uae_u32 fastmem_mask;
+
+static uae_u32 fastmem_lget (uaecptr) REGPARAM;
+static uae_u32 fastmem_wget (uaecptr) REGPARAM;
+static uae_u32 fastmem_bget (uaecptr) REGPARAM;
+static void fastmem_lput (uaecptr, uae_u32) REGPARAM;
+static void fastmem_wput (uaecptr, uae_u32) REGPARAM;
+static void fastmem_bput (uaecptr, uae_u32) REGPARAM;
+static int fastmem_check (uaecptr addr, uae_u32 size) REGPARAM;
+static uae_u8 *fastmem_xlate (uaecptr addr) REGPARAM;
+
+static uae_u32 fastmem_start; /* Determined by the OS */
+static uae_u8 *fastmemory;
+
+uae_u32 REGPARAM2 fastmem_lget (uaecptr addr)
+{
+    uae_u8 *m;
+    addr -= fastmem_start & fastmem_mask;
+    addr &= fastmem_mask;
+    m = fastmemory + addr;
+    return do_get_mem_long ((uae_u32 *)m);
+}
+
+uae_u32 REGPARAM2 fastmem_wget (uaecptr addr)
+{
+    uae_u8 *m;
+    addr -= fastmem_start & fastmem_mask;
+    addr &= fastmem_mask;
+    m = fastmemory + addr;
+    return do_get_mem_word ((uae_u16 *)m);
+}
+
+uae_u32 REGPARAM2 fastmem_bget (uaecptr addr)
+{
+    addr -= fastmem_start & fastmem_mask;
+    addr &= fastmem_mask;
+    return fastmemory[addr];
+}
+
+void REGPARAM2 fastmem_lput (uaecptr addr, uae_u32 l)
+{
+    uae_u8 *m;
+    addr -= fastmem_start & fastmem_mask;
+    addr &= fastmem_mask;
+    m = fastmemory + addr;
+    do_put_mem_long ((uae_u32 *)m, l);
+}
+
+void REGPARAM2 fastmem_wput (uaecptr addr, uae_u32 w)
+{
+    uae_u8 *m;
+    addr -= fastmem_start & fastmem_mask;
+    addr &= fastmem_mask;
+    m = fastmemory + addr;
+    do_put_mem_word ((uae_u16 *)m, w);
+}
+
+void REGPARAM2 fastmem_bput (uaecptr addr, uae_u32 b)
+{
+    addr -= fastmem_start & fastmem_mask;
+    addr &= fastmem_mask;
+    fastmemory[addr] = b;
+}
+
+static int REGPARAM2 fastmem_check (uaecptr addr, uae_u32 size)
+{
+    addr -= fastmem_start & fastmem_mask;
+    addr &= fastmem_mask;
+    return (addr + size) <= allocated_fastmem;
+}
+
+static uae_u8 REGPARAM2 *fastmem_xlate (uaecptr addr)
+{
+    addr -= fastmem_start & fastmem_mask;
+    addr &= fastmem_mask;
+    return fastmemory + addr;
+}
+
+addrbank fastmem_bank = {
+    fastmem_lget, fastmem_wget, fastmem_bget,
+    fastmem_lput, fastmem_wput, fastmem_bput,
+    fastmem_xlate, fastmem_check, NULL
+};
+
+
+#ifdef CATWEASEL
+
+/*
+ * Catweasel ZorroII
+ */
+
+static uae_u32 catweasel_lget (uaecptr) REGPARAM;
+static uae_u32 catweasel_wget (uaecptr) REGPARAM;
+static uae_u32 catweasel_bget (uaecptr) REGPARAM;
+static void catweasel_lput (uaecptr, uae_u32) REGPARAM;
+static void catweasel_wput (uaecptr, uae_u32) REGPARAM;
+static void catweasel_bput (uaecptr, uae_u32) REGPARAM;
+static int catweasel_check (uaecptr addr, uae_u32 size) REGPARAM;
+static uae_u8 *catweasel_xlate (uaecptr addr) REGPARAM;
+
+static uae_u32 catweasel_mask;
+static uae_u32 catweasel_start;
+
+static uae_u32 REGPARAM2 catweasel_lget (uaecptr addr)
+{
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+    write_log("catweasel_lget @%08.8X!\n",addr);
+    return 0;
+}
+
+static uae_u32 REGPARAM2 catweasel_wget (uaecptr addr)
+{
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+    write_log("catweasel_wget @%08.8X!\n",addr);
+    return 0;
+}
+
+static uae_u32 REGPARAM2 catweasel_bget (uaecptr addr)
+{
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+    addr -= catweasel_start & catweasel_mask;
+    addr &= catweasel_mask;
+    return catweasel_do_bget (addr);
+}
+
+static void REGPARAM2 catweasel_lput (uaecptr addr, uae_u32 l)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    write_log("catweasel_lput @%08.8X=%08.8X!\n",addr,l);
+}
+
+static void REGPARAM2 catweasel_wput (uaecptr addr, uae_u32 w)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    write_log("catweasel_wput @%08.8X=%04.4X!\n",addr,w);
+}
+
+static void REGPARAM2 catweasel_bput (uaecptr addr, uae_u32 b)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    addr -= catweasel_start & catweasel_mask;
+    addr &= catweasel_mask;
+    catweasel_do_bput (addr, b);
+}
+
+static int REGPARAM2 catweasel_check (uaecptr addr, uae_u32 size)
+{
+    write_log ("catweasel_check @%08.8X size %08.8X\n", addr, size);
+    return 0;
+}
+
+static uae_u8 REGPARAM2 *catweasel_xlate (uaecptr addr)
+{
+    write_log ("catweasel_xlate @%08.8X size %08.8X\n", addr);
+    return 0;
+}
+
+static addrbank catweasel_bank = {
+    catweasel_lget, catweasel_wget, catweasel_bget,
+    catweasel_lput, catweasel_wput, catweasel_bput,
+    catweasel_xlate, catweasel_check, NULL
+};
+
+static void expamem_map_catweasel (void)
+{
+    catweasel_start = ((expamem_hi | (expamem_lo >> 4)) << 16);
+    map_banks (&catweasel_bank, catweasel_start >> 16, 1, 0);  
+    write_log ("Catweasel MK%d: mapped @$%lx\n", cwc.type, catweasel_start);
+}
+
+static void expamem_init_catweasel (void)
+{
+    uae_u8 productid = cwc.type == CATWEASEL_TYPE_MK3 ? 66 : 200;
+    uae_u16 vendorid = cwc.type == CATWEASEL_TYPE_MK3 ? 4626 : 5001;
+
+    catweasel_mask = (cwc.type == CATWEASEL_TYPE_MK3) ? 0xffff : 0x1ffff;
+
+    expamem_init_clear();
+
+    expamem_write (0x00, (cwc.type == CATWEASEL_TYPE_MK3 ? Z2_MEM_64KB : Z2_MEM_128KB) | zorroII);
+
+    expamem_write (0x04, productid);
+
+    expamem_write (0x08, no_shutup);
+
+    expamem_write (0x10, vendorid >> 8);
+    expamem_write (0x14, vendorid & 0xff);
+
+    expamem_write (0x18, 0x00); /* ser.no. Byte 0 */
+    expamem_write (0x1c, 0x00); /* ser.no. Byte 1 */
+    expamem_write (0x20, 0x00); /* ser.no. Byte 2 */
+    expamem_write (0x24, 0x00); /* ser.no. Byte 3 */
+
+    expamem_write (0x28, 0x00); /* Rom-Offset hi */
+    expamem_write (0x2c, 0x00); /* ROM-Offset lo */
+
+    expamem_write (0x40, 0x00); /* Ctrl/Statusreg.*/
+}
+
+#endif
+
+/*
+ * CDTV DMAC
+ */
+
+//#define CDTV_DEBUG
+
+static uae_u32 dmac_lget (uaecptr) REGPARAM;
+static uae_u32 dmac_wget (uaecptr) REGPARAM;
+static uae_u32 dmac_bget (uaecptr) REGPARAM;
+static void dmac_lput (uaecptr, uae_u32) REGPARAM;
+static void dmac_wput (uaecptr, uae_u32) REGPARAM;
+static void dmac_bput (uaecptr, uae_u32) REGPARAM;
+
+static uae_u32 dmac_start = 0xe90000;
+static uae_u8 dmacmemory[0x100];
+
+static int cdtv_command_len;
+static uae_u8 cdtv_command_buf[6];
+
+static void cdtv_interrupt (int v)
+{
+    write_log ("cdtv int %d\n", v);
+    dmacmemory[0x41] = (1 << 4) | (1 << 6);
+    Interrupt (6);
+}
+
+uae_u32 REGPARAM2 dmac_lget (uaecptr addr)
+{
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+#ifdef CDTV_DEBUG
+    write_log ("dmac_lget %08.8X\n", addr);
+#endif
+    return (dmac_wget (addr) << 16) | dmac_wget (addr + 2);
+}
+
+uae_u32 REGPARAM2 dmac_wget (uaecptr addr)
+{
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+#ifdef CDTV_DEBUG
+    write_log ("dmac_wget %08.8X PC=%X\n", addr, m68k_getpc());
+#endif
+    return (dmac_bget (addr) << 8) | dmac_bget (addr + 1);
+}
+
+uae_u32 REGPARAM2 dmac_bget (uaecptr addr)
+{
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+#ifdef CDTV_DEBUG
+    write_log ("dmac_bget %08.8X PC=%X\n", addr, m68k_getpc());
+#endif
+    addr -= dmac_start;
+    addr &= 65535;
+    switch (addr)
+    {
+       case 0xa3:
+       return 1;
+    }
+    return dmacmemory[addr];
+}
+
+static void REGPARAM2 dmac_lput (uaecptr addr, uae_u32 l)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+#ifdef CDTV_DEBUG
+    write_log ("dmac_lput %08.8X = %08.8X\n", addr, l);
+#endif
+    dmac_wput (addr, l >> 16);
+    dmac_wput (addr + 2, l);
+}
+
+static void REGPARAM2 dmac_wput (uaecptr addr, uae_u32 w)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+#ifdef CDTV_DEBUG
+    write_log ("dmac_wput %04.4X = %04.4X\n", addr, w & 65535);
+#endif
+    dmac_bput (addr, w >> 8);
+    dmac_bput (addr, w);
+}
+
+static void REGPARAM2 dmac_bput (uaecptr addr, uae_u32 b)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+#ifdef CDTV_DEBUG
+    write_log ("dmac_bput %08.8X = %02.2X PC=%X\n", addr, b & 255, m68k_getpc());
+#endif
+    addr -= dmac_start;
+    addr &= 65535;
+#ifdef CDTV_DEBUG
+    dmacmemory[addr] = b;
+    switch (addr)
+    {
+       case 0xa1:
+       if (cdtv_command_len >= sizeof (cdtv_command_buf))
+           cdtv_command_len = sizeof (cdtv_command_buf) - 1;
+       cdtv_command_buf[cdtv_command_len++] = b;
+       if (cdtv_command_len == 6) {
+           cdtv_interrupt (1);
+       }
+       break;
+       case 0xa5:
+       cdtv_command_len = 0;
+       break;
+       case 0xe4:
+       dmacmemory[0x41] = 0;
+       write_log ("cdtv interrupt cleared\n");
+       activate_debugger();
+       break;
+    }
+#endif
+}
+
+addrbank dmac_bank = {
+    dmac_lget, dmac_wget, dmac_bget,
+    dmac_lput, dmac_wput, dmac_bput,
+    default_xlate, default_check, NULL
+};
+
+/*
+ * Filesystem device ROM
+ * This is very simple, the Amiga shouldn't be doing things with it.
+ */
+
+static uae_u32 filesys_lget (uaecptr) REGPARAM;
+static uae_u32 filesys_wget (uaecptr) REGPARAM;
+static uae_u32 filesys_bget (uaecptr) REGPARAM;
+static void filesys_lput (uaecptr, uae_u32) REGPARAM;
+static void filesys_wput (uaecptr, uae_u32) REGPARAM;
+static void filesys_bput (uaecptr, uae_u32) REGPARAM;
+
+static uae_u32 filesys_start; /* Determined by the OS */
+uae_u8 *filesysory;
+
+uae_u32 REGPARAM2 filesys_lget (uaecptr addr)
+{
+    uae_u8 *m;
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+    addr -= filesys_start & 65535;
+    addr &= 65535;
+    m = filesysory + addr;
+    return do_get_mem_long ((uae_u32 *)m);
+}
+
+uae_u32 REGPARAM2 filesys_wget (uaecptr addr)
+{
+    uae_u8 *m;
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+    addr -= filesys_start & 65535;
+    addr &= 65535;
+    m = filesysory + addr;
+    return do_get_mem_word ((uae_u16 *)m);
+}
+
+uae_u32 REGPARAM2 filesys_bget (uaecptr addr)
+{
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+    addr -= filesys_start & 65535;
+    addr &= 65535;
+    return filesysory[addr];
+}
+
+static void REGPARAM2 filesys_lput (uaecptr addr, uae_u32 l)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    write_log ("filesys_lput called PC=%p\n", m68k_getpc());
+}
+
+static void REGPARAM2 filesys_wput (uaecptr addr, uae_u32 w)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    write_log ("filesys_wput called PC=%p\n", m68k_getpc());
+}
+
+static void REGPARAM2 filesys_bput (uaecptr addr, uae_u32 b)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    write_log ("filesys_bput called. This usually means that you are using\n");
+    write_log ("Kickstart 1.2. Please give UAE the \"-a\" option next time\n");
+    write_log ("you start it. If you are _not_ using Kickstart 1.2, then\n");
+    write_log ("there's a bug somewhere.\n");
+    write_log ("Exiting...\n");
+    uae_quit ();
+}
+
+static addrbank filesys_bank = {
+    filesys_lget, filesys_wget, filesys_bget,
+    filesys_lput, filesys_wput, filesys_bput,
+    default_xlate, default_check, NULL
+};
+
+/*
+ *  Z3fastmem Memory
+ */
+
+static uae_u32 z3fastmem_mask;
+
+static uae_u32 z3fastmem_lget (uaecptr) REGPARAM;
+static uae_u32 z3fastmem_wget (uaecptr) REGPARAM;
+static uae_u32 z3fastmem_bget (uaecptr) REGPARAM;
+static void z3fastmem_lput (uaecptr, uae_u32) REGPARAM;
+static void z3fastmem_wput (uaecptr, uae_u32) REGPARAM;
+static void z3fastmem_bput (uaecptr, uae_u32) REGPARAM;
+static int z3fastmem_check (uaecptr addr, uae_u32 size) REGPARAM;
+static uae_u8 *z3fastmem_xlate (uaecptr addr) REGPARAM;
+
+static uae_u32 z3fastmem_start; /* Determined by the OS */
+static uae_u8 *z3fastmem;
+
+uae_u32 REGPARAM2 z3fastmem_lget (uaecptr addr)
+{
+    uae_u8 *m;
+    addr -= z3fastmem_start & z3fastmem_mask;
+    addr &= z3fastmem_mask;
+    m = z3fastmem + addr;
+    return do_get_mem_long ((uae_u32 *)m);
+}
+
+uae_u32 REGPARAM2 z3fastmem_wget (uaecptr addr)
+{
+    uae_u8 *m;
+    addr -= z3fastmem_start & z3fastmem_mask;
+    addr &= z3fastmem_mask;
+    m = z3fastmem + addr;
+    return do_get_mem_word ((uae_u16 *)m);
+}
+
+uae_u32 REGPARAM2 z3fastmem_bget (uaecptr addr)
+{
+    addr -= z3fastmem_start & z3fastmem_mask;
+    addr &= z3fastmem_mask;
+    return z3fastmem[addr];
+}
+
+void REGPARAM2 z3fastmem_lput (uaecptr addr, uae_u32 l)
+{
+    uae_u8 *m;
+    addr -= z3fastmem_start & z3fastmem_mask;
+    addr &= z3fastmem_mask;
+    m = z3fastmem + addr;
+    do_put_mem_long ((uae_u32 *)m, l);
+}
+
+void REGPARAM2 z3fastmem_wput (uaecptr addr, uae_u32 w)
+{
+    uae_u8 *m;
+    addr -= z3fastmem_start & z3fastmem_mask;
+    addr &= z3fastmem_mask;
+    m = z3fastmem + addr;
+    do_put_mem_word ((uae_u16 *)m, w);
+}
+
+void REGPARAM2 z3fastmem_bput (uaecptr addr, uae_u32 b)
+{
+    addr -= z3fastmem_start & z3fastmem_mask;
+    addr &= z3fastmem_mask;
+    z3fastmem[addr] = b;
+}
+
+static int REGPARAM2 z3fastmem_check (uaecptr addr, uae_u32 size)
+{
+    addr -= z3fastmem_start & z3fastmem_mask;
+    addr &= z3fastmem_mask;
+    return (addr + size) <= allocated_z3fastmem;
+}
+
+static uae_u8 REGPARAM2 *z3fastmem_xlate (uaecptr addr)
+{
+    addr -= z3fastmem_start & z3fastmem_mask;
+    addr &= z3fastmem_mask;
+    return z3fastmem + addr;
+}
+
+addrbank z3fastmem_bank = {
+    z3fastmem_lget, z3fastmem_wget, z3fastmem_bget,
+    z3fastmem_lput, z3fastmem_wput, z3fastmem_bput,
+    z3fastmem_xlate, z3fastmem_check, NULL
+};
+
+/* Z3-based UAEGFX-card */
+uae_u32 gfxmem_mask; /* for memory.c */
+uae_u8 *gfxmemory;
+uae_u32 gfxmem_start;
+
+/* ********************************************************** */
+
+/*
+ *     Expansion Card (ZORRO II) for 1/2/4/8 MB of Fast Memory
+ */
+
+static void expamem_map_fastcard (void)
+{
+    fastmem_start = ((expamem_hi | (expamem_lo >> 4)) << 16);
+    map_banks (&fastmem_bank, fastmem_start >> 16, allocated_fastmem >> 16, allocated_fastmem);
+    write_log ("Fastcard: mapped @$%lx: %dMB fast memory\n", fastmem_start, allocated_fastmem >> 20);
+}
+
+static void expamem_init_fastcard (void)
+{
+    expamem_init_clear();
+    if (allocated_fastmem == 0x100000)
+       expamem_write (0x00, Z2_MEM_1MB + add_memory + zorroII);
+    else if (allocated_fastmem == 0x200000)
+       expamem_write (0x00, Z2_MEM_2MB + add_memory + zorroII);
+    else if (allocated_fastmem == 0x400000)
+       expamem_write (0x00, Z2_MEM_4MB + add_memory + zorroII);
+    else if (allocated_fastmem == 0x800000)
+       expamem_write (0x00, Z2_MEM_8MB + add_memory + zorroII);
+
+    expamem_write (0x08, care_addr);
+
+    expamem_write (0x04, 1);
+
+    expamem_write (0x10, hackers_id >> 8);
+    expamem_write (0x14, hackers_id & 0xff);
+
+    expamem_write (0x18, 0x00); /* ser.no. Byte 0 */
+    expamem_write (0x1c, 0x00); /* ser.no. Byte 1 */
+    expamem_write (0x20, 0x00); /* ser.no. Byte 2 */
+    expamem_write (0x24, 0x01); /* ser.no. Byte 3 */
+
+    expamem_write (0x28, 0x00); /* Rom-Offset hi */
+    expamem_write (0x2c, 0x00); /* ROM-Offset lo */
+
+    expamem_write (0x40, 0x00); /* Ctrl/Statusreg.*/
+}
+
+/* ********************************************************** */
+
+/* 
+ * Filesystem device
+ */
+
+static void expamem_map_filesys (void)
+{
+    uaecptr a;
+
+    filesys_start = ((expamem_hi | (expamem_lo >> 4)) << 16);
+    map_banks (&filesys_bank, filesys_start >> 16, 1, 0);
+    write_log ("Filesystem: mapped memory @$%lx.\n", filesys_start);
+    /* 68k code needs to know this. */
+    a = here ();
+    org (RTAREA_BASE+0xFFFC);
+    dl (filesys_start + 0x2000);
+    org (a);
+}
+
+static void expamem_init_filesys (void)
+{
+    /* struct DiagArea - the size has to be large enough to store several device ROMTags */
+    uae_u8 diagarea[] = { 0x90, 0x00, /* da_Config, da_Flags */
+                          0x02, 0x00, /* da_Size */
+                          0x01, 0x00, /* da_DiagPoint */
+                          0x01, 0x06  /* da_BootPoint */
+    };
+
+    expamem_init_clear();
+    expamem_write (0x00, Z2_MEM_64KB | rom_card | zorroII);
+
+    expamem_write (0x08, no_shutup);
+
+    expamem_write (0x04, 2);
+    expamem_write (0x10, hackers_id >> 8);
+    expamem_write (0x14, hackers_id & 0xff);
+
+    expamem_write (0x18, 0x00); /* ser.no. Byte 0 */
+    expamem_write (0x1c, 0x00); /* ser.no. Byte 1 */
+    expamem_write (0x20, 0x00); /* ser.no. Byte 2 */
+    expamem_write (0x24, 0x01); /* ser.no. Byte 3 */
+
+    /* er_InitDiagVec */
+    expamem_write (0x28, 0x10); /* Rom-Offset hi */
+    expamem_write (0x2c, 0x00); /* ROM-Offset lo */
+
+    expamem_write (0x40, 0x00); /* Ctrl/Statusreg.*/
+
+    /* Build a DiagArea */
+    memcpy (expamem + 0x1000, diagarea, sizeof diagarea);
+
+    /* Call DiagEntry */
+    do_put_mem_word ((uae_u16 *)(expamem + 0x1100), 0x4EF9); /* JMP */
+    do_put_mem_long ((uae_u32 *)(expamem + 0x1102), ROM_filesys_diagentry);
+
+    /* What comes next is a plain bootblock */
+    do_put_mem_word ((uae_u16 *)(expamem + 0x1106), 0x4EF9); /* JMP */
+    do_put_mem_long ((uae_u32 *)(expamem + 0x1108), EXPANSION_bootcode);
+
+    memcpy (filesysory, expamem, 0x3000);
+}
+
+/*
+ * Zorro III expansion memory
+ */
+
+static void expamem_map_z3fastmem (void)
+{
+       int z3fs = ((expamem_hi | (expamem_lo >> 4)) << 16);
+
+       if (z3fastmem_start != z3fs) {
+               write_log("WARNING: Z3FAST mapping changed from $%lx to $%lx\n", z3fastmem_start, z3fs);
+               map_banks(&dummy_bank, z3fastmem_start >> 16, currprefs.z3fastmem_size >> 16,
+                       allocated_z3fastmem);
+               z3fastmem_start = z3fs;
+           map_banks (&z3fastmem_bank, z3fastmem_start >> 16, currprefs.z3fastmem_size >> 16,
+              allocated_z3fastmem);
+       }
+    write_log ("Fastmem (32bit): mapped @$%lx: %d MB Zorro III fast memory \n",
+              z3fastmem_start, allocated_z3fastmem / 0x100000);
+}
+
+static void expamem_init_z3fastmem (void)
+{
+    int code = (allocated_z3fastmem == 0x100000 ? Z2_MEM_1MB
+               : allocated_z3fastmem == 0x200000 ? Z2_MEM_2MB
+               : allocated_z3fastmem == 0x400000 ? Z2_MEM_4MB
+               : allocated_z3fastmem == 0x800000 ? Z2_MEM_8MB
+               : allocated_z3fastmem == 0x1000000 ? Z2_MEM_16MB
+               : allocated_z3fastmem == 0x2000000 ? Z2_MEM_32MB
+               : allocated_z3fastmem == 0x4000000 ? Z2_MEM_64MB
+               : allocated_z3fastmem == 0x8000000 ? Z2_MEM_128MB
+               : allocated_z3fastmem == 0x10000000 ? Z2_MEM_256MB
+               : allocated_z3fastmem == 0x20000000 ? Z2_MEM_512MB
+               : Z2_MEM_1GB);
+    expamem_init_clear();
+    expamem_write (0x00, add_memory | zorroIII | code);
+
+    expamem_write (0x08, no_shutup | force_z3 | (allocated_z3fastmem > 0x800000 ? ext_size : Z3_MEM_AUTO));
+
+    expamem_write (0x04, 3);
+
+    expamem_write (0x10, hackers_id >> 8);
+    expamem_write (0x14, hackers_id & 0xff);
+
+    expamem_write (0x18, 0x00); /* ser.no. Byte 0 */
+    expamem_write (0x1c, 0x00); /* ser.no. Byte 1 */
+    expamem_write (0x20, 0x00); /* ser.no. Byte 2 */
+    expamem_write (0x24, 0x01); /* ser.no. Byte 3 */
+
+    expamem_write (0x28, 0x00); /* Rom-Offset hi */
+    expamem_write (0x2c, 0x00); /* ROM-Offset lo */
+
+    expamem_write (0x40, 0x00); /* Ctrl/Statusreg.*/
+
+    z3fastmem_start = 0x10000000;
+
+    map_banks (&z3fastmem_bank, z3fastmem_start >> 16, currprefs.z3fastmem_size >> 16,
+              allocated_z3fastmem);
+
+}
+
+#ifdef PICASSO96
+/*
+ *  Fake Graphics Card (ZORRO III) - BDK
+ */
+
+static void expamem_map_gfxcard (void)
+{
+    gfxmem_start = ((expamem_hi | (expamem_lo >> 4)) << 16);
+    map_banks (&gfxmem_bank, gfxmem_start >> 16, allocated_gfxmem >> 16, allocated_gfxmem);
+    write_log ("UAEGFX-card: mapped @$%lx \n", gfxmem_start);
+}
+
+static void expamem_init_gfxcard (void)
+{
+    expamem_init_clear();
+    expamem_write (0x00, zorroIII);
+
+    switch (allocated_gfxmem) {
+     case 0x00100000:
+       expamem_write (0x08, no_shutup | force_z3 | Z3_MEM_1MB);
+       break;
+     case 0x00200000:
+       expamem_write (0x08, no_shutup | force_z3 | Z3_MEM_2MB);
+       break;
+     case 0x00400000:
+       expamem_write (0x08, no_shutup | force_z3 | Z3_MEM_4MB);
+       break;
+     case 0x00800000:
+       expamem_write (0x08, no_shutup | force_z3 | Z3_MEM_8MB);
+       break;
+    }
+
+    expamem_write (0x04, 96);
+
+    expamem_write (0x10, hackers_id >> 8);
+    expamem_write (0x14, hackers_id & 0xff);
+
+    expamem_write (0x18, 0x00); /* ser.no. Byte 0 */
+    expamem_write (0x1c, 0x00); /* ser.no. Byte 1 */
+    expamem_write (0x20, 0x00); /* ser.no. Byte 2 */
+    expamem_write (0x24, 0x01); /* ser.no. Byte 3 */
+
+    expamem_write (0x28, 0x00); /* Rom-Offset hi */
+    expamem_write (0x2c, 0x00); /* ROM-Offset lo */
+
+    expamem_write (0x40, 0x00); /* Ctrl/Statusreg.*/
+}
+#endif
+
+static long fast_filepos, z3_filepos, p96_filepos;
+
+static void allocate_expamem (void)
+{
+    currprefs.fastmem_size = changed_prefs.fastmem_size;
+    currprefs.z3fastmem_size = changed_prefs.z3fastmem_size;
+    currprefs.gfxmem_size = changed_prefs.gfxmem_size;
+
+    if (allocated_fastmem != currprefs.fastmem_size) {
+       if (fastmemory)
+           mapped_free (fastmemory);
+       fastmemory = 0;
+       allocated_fastmem = currprefs.fastmem_size;
+       fastmem_mask = allocated_fastmem - 1;
+
+       if (allocated_fastmem) {
+           fastmemory = mapped_malloc (allocated_fastmem, "fast");
+           if (fastmemory == 0) {
+               write_log ("Out of memory for fastmem card.\n");
+               allocated_fastmem = 0;
+           }
+       }
+       clearexec ();
+    }
+    if (allocated_z3fastmem != currprefs.z3fastmem_size) {
+       if (z3fastmem)
+           mapped_free (z3fastmem);
+       z3fastmem = 0;
+
+       allocated_z3fastmem = currprefs.z3fastmem_size;
+       z3fastmem_mask = allocated_z3fastmem - 1;
+
+       if (allocated_z3fastmem) {
+           z3fastmem = mapped_malloc (allocated_z3fastmem, "z3");
+           if (z3fastmem == 0) {
+               write_log ("Out of memory for 32 bit fast memory.\n");
+               allocated_z3fastmem = 0;
+           }
+       }
+       clearexec ();
+    }
+    if (allocated_gfxmem != currprefs.gfxmem_size) {
+       if (gfxmemory)
+           mapped_free (gfxmemory);
+       gfxmemory = 0;
+
+       allocated_gfxmem = currprefs.gfxmem_size;
+       gfxmem_mask = allocated_gfxmem - 1;
+
+       if (allocated_gfxmem) {
+           gfxmemory = mapped_malloc (allocated_gfxmem, "gfx");
+           if (gfxmemory == 0) {
+               write_log ("Out of memory for graphics card memory\n");
+               allocated_gfxmem = 0;
+           }
+       }
+       clearexec ();
+    }
+
+    z3fastmem_bank.baseaddr = z3fastmem;
+    fastmem_bank.baseaddr = fastmemory;
+
+    if (savestate_state == STATE_RESTORE) {
+       if (allocated_fastmem > 0) {
+           restore_ram (fast_filepos, fastmemory);
+           map_banks (&fastmem_bank, fastmem_start >> 16, currprefs.fastmem_size >> 16,
+                      allocated_fastmem);
+       }
+       if (allocated_z3fastmem > 0) {
+           restore_ram (z3_filepos, z3fastmem);
+           map_banks (&z3fastmem_bank, z3fastmem_start >> 16, currprefs.z3fastmem_size >> 16,
+                      allocated_z3fastmem);
+       }
+       if (allocated_gfxmem > 0 && gfxmem_start > 0) {
+           restore_ram (p96_filepos, gfxmemory);
+           map_banks (&gfxmem_bank, gfxmem_start >> 16, currprefs.gfxmem_size >> 16,
+                      allocated_gfxmem);
+       }
+    }
+}
+
+extern int cdtv_enabled;
+
+void expamem_reset (void)
+{
+    int do_mount = 1;
+    int cardno = 0;
+    ecard = 0;
+
+    allocate_expamem ();
+
+    if (cdtv_enabled)
+        map_banks (&dmac_bank, dmac_start >> 16, 0x10000 >> 16, 0x10000);
+
+    /* check if Kickstart version is below 1.3 */
+    if (! ersatzkickfile && kickstart_version
+       && (/* Kickstart 1.0 & 1.1! */
+           kickstart_version == 0xFFFF
+           /* Kickstart < 1.3 */
+           || kickstart_version < 34))
+    {
+       /* warn user */
+       write_log ("Kickstart version is below 1.3!  Disabling autoconfig devices.\n");
+       do_mount = 0;
+    }
+    /* No need for filesystem stuff if there aren't any mounted.  */
+    if (nr_units (currprefs.mountinfo) == 0)
+       do_mount = 0;
+
+    if (fastmemory != NULL) {
+       card_init[cardno] = expamem_init_fastcard;
+       card_map[cardno++] = expamem_map_fastcard;
+    }
+    if (z3fastmem != NULL) {
+       card_init[cardno] = expamem_init_z3fastmem;
+       card_map[cardno++] = expamem_map_z3fastmem;
+    }
+#ifdef PICASSO96
+    if (gfxmemory != NULL) {
+       card_init[cardno] = expamem_init_gfxcard;
+       card_map[cardno++] = expamem_map_gfxcard;
+    }
+#endif
+    if (do_mount && ! ersatzkickfile) {
+       card_init[cardno] = expamem_init_filesys;
+       card_map[cardno++] = expamem_map_filesys;
+    }
+#ifdef CATWEASEL
+    if (catweasel_init ()) {
+        card_init[cardno] = expamem_init_catweasel;
+        card_map[cardno++] = expamem_map_catweasel;
+    }
+#endif
+    while (cardno < MAX_EXPANSION_BOARDS) {
+       card_init[cardno] = expamem_init_clear;
+       card_map[cardno++] = expamem_map_clear;
+    }
+
+    (*card_init[0]) ();
+}
+
+void expansion_init (void)
+{
+    z3fastmem = 0;
+    gfxmemory = 0;
+    fastmemory = 0;
+    allocated_z3fastmem = 0;
+    allocated_gfxmem = 0;
+    allocated_fastmem = 0;
+    fastmem_mask = fastmem_start = 0;
+    fastmemory = 0;
+    gfxmem_mask = gfxmem_start = 0;
+    gfxmemory = 0;
+    catweasel_mask = catweasel_start = 0;
+    filesys_start = 0;
+    filesysory = 0;
+    z3fastmem_mask = z3fastmem_start = 0;
+    z3fastmem = 0;
+
+    allocate_expamem ();
+
+    filesysory = (uae_u8 *) mapped_malloc (0x10000, "filesys");
+    if (!filesysory) {
+       write_log ("virtual memory exhausted (filesysory)!\n");
+       exit (0);
+    }
+    filesys_bank.baseaddr = (uae_u8*)filesysory;
+
+}
+
+void expansion_cleanup (void)
+{
+    if (fastmemory)
+       mapped_free (fastmemory);
+    if (z3fastmem)
+       mapped_free (z3fastmem);
+    if (gfxmemory)
+       mapped_free (gfxmemory);
+    if (filesysory)
+       mapped_free (filesysory);
+    fastmemory = 0;
+    z3fastmem = 0;
+    gfxmemory = 0;
+    filesysory = 0;
+#ifdef CATWEASEL
+    catweasel_free ();
+#endif
+}
+
+/* State save/restore code.  */
+
+uae_u8 *save_fram (int *len)
+{
+    *len = allocated_fastmem;
+    return fastmemory;
+}
+
+uae_u8 *save_zram (int *len)
+{
+    *len = allocated_z3fastmem;
+    return z3fastmem;
+}
+
+uae_u8 *save_pram (int *len)
+{
+    *len = allocated_gfxmem;
+    return gfxmemory;
+}
+
+void restore_fram (int len, long filepos)
+{
+    fast_filepos = filepos;
+    changed_prefs.fastmem_size = len;
+}
+
+void restore_zram (int len, long filepos)
+{
+    z3_filepos = filepos;
+    changed_prefs.z3fastmem_size = len;
+}
+
+void restore_pram (int len, long filepos)
+{
+    p96_filepos = filepos;
+    changed_prefs.gfxmem_size = len;
+}
+
+uae_u8 *save_expansion (int *len, uae_u8 *dstptr)
+{
+    static uae_u8 t[20];
+    uae_u8 *dst = t, *dstbak = t;
+    if (dstptr)
+       dst = dstbak = dstptr;
+    save_u32 (fastmem_start);
+    save_u32 (z3fastmem_start);
+    save_u32 (gfxmem_start);
+    *len = 4 + 4 + 4;
+    return dstbak;
+}
+
+uae_u8 *restore_expansion (uae_u8 *src)
+{
+    fastmem_start = restore_u32 ();
+    z3fastmem_start = restore_u32 ();
+    gfxmem_start = restore_u32 ();
+    return src;
+}
diff --git a/fdi2raw.c b/fdi2raw.c
new file mode 100755 (executable)
index 0000000..adc770b
--- /dev/null
+++ b/fdi2raw.c
@@ -0,0 +1,1841 @@
+/*
+
+  FDI to raw bit stream converter
+  Copyright (c) 2001 by Toni Wilen <twilen@arabuusimiehet.com>
+  FDI 2.0 support
+  Copyright (c) 2003-2004 by Toni Wilen <twilen@arabuusimiehet.com>
+                    and Vincent Joguin
+
+  FDI format created by Vincent "ApH" Joguin
+
+  Tiny changes - function type fixes, multiple drives, addition of
+  get_last_head and C++ callability - by Thomas Harte, 2001,
+  T.Harte@excite.co.uk
+
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by the Free
+  Software Foundation; either version 2 of the License, or (at your option)
+  any later version.
+
+  This program is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along
+  with this program; if not, write to the Free Software Foundation, Inc.,
+  59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* IF UAE */
+#include "sysconfig.h"
+#include "sysdeps.h"
+#include "zfile.h"
+/* ELSE */
+//#include "types.h"
+
+#include "fdi2raw.h"
+
+#undef DEBUG
+#define VERBOSE
+
+#include <assert.h>
+
+#ifdef DEBUG
+static char *datalog(uae_u8 *src, int len)
+{
+       static char buf[1000];
+       static int offset;
+       int i = 0, offset2;
+
+       offset2 = offset;
+       buf[offset++]='\'';
+       while(len--) {
+               sprintf (buf + offset, "%02.2X", src[i]);
+               offset += 2;
+               i++;
+               if (i > 10) break;
+       }
+       buf[offset++]='\'';
+       buf[offset++] = 0;
+       if (offset >= 900) offset = 0;
+       return buf + offset2;
+}
+#else
+static char *datalog(uae_u8 *src, int len) { return ""; }
+#endif
+
+#ifdef DEBUG
+#define debuglog write_log
+#else
+#define debuglog
+#endif
+#ifdef VERBOSE
+#define outlog write_log
+#else
+#define outlog
+#endif
+
+static int fdi_allocated;
+#ifdef DEBUG
+static void fdi_free (void *p)
+{
+       int size;
+       if (!p)
+               return;
+       size = ((int*)p)[-1];
+       fdi_allocated -= size;
+       write_log ("%d freed (%d)\n", size, fdi_allocated);
+       free ((int*)p - 1);
+}
+static void *fdi_malloc (int size)
+{
+       void *p = xmalloc (size + sizeof (int));
+       ((int*)p)[0] = size;
+       fdi_allocated += size;
+       write_log ("%d allocated (%d)\n", size, fdi_allocated);
+       return (int*)p + 1;
+}
+#else
+#define fdi_free free
+#define fdi_malloc xmalloc
+#endif
+
+#define MAX_SRC_BUFFER 4194304
+#define MAX_DST_BUFFER 40000
+#define MAX_MFM_SYNC_BUFFER 60000
+#define MAX_TIMING_BUFFER 400000
+#define MAX_TRACKS 166
+#define MAX_REVOLUTIONS 4
+
+struct fdi_cache {
+       uae_u8 *cache_buffer[MAX_REVOLUTIONS];
+       uae_u8 *cache_buffer_timing;
+       int length[MAX_REVOLUTIONS];
+       int indexoffset;
+};
+
+struct fdi {
+       uae_u8 *track_src_buffer;
+       uae_u8 *track_src;
+       int track_src_len;
+       uae_u8 *track_dst_buffer;
+       uae_u8 *track_dst;
+       uae_u16 *track_dst_buffer_timing;
+       uae_u8 track_len;
+       uae_u8 track_type;
+       int current_track;
+       int last_track;
+       int last_head;
+       int rotation_speed;
+       int bit_rate;
+       int disk_type;
+       int write_protect;
+       int err;
+       uae_u8 header[2048];
+       int track_offsets[MAX_TRACKS];
+       struct zfile *file;
+       int out;
+       int mfmsync_offset;
+       int *mfmsync_buffer;
+       /* sector described only */
+       int index_offset;
+       int encoding_type;
+       /* bit handling */
+       int nextdrop;
+       struct fdi_cache cache[MAX_TRACKS];
+};
+
+#define get_u32(x) ((((x)[0])<<24)|(((x)[1])<<16)|(((x)[2])<<8)|((x)[3]))
+#define get_u24(x) ((((x)[0])<<16)|(((x)[1])<<8)|((x)[2]))
+STATIC_INLINE put_u32 (uae_u8 *d, uae_u32 v)
+{
+       d[0] = v >> 24;
+       d[1] = v >> 16;
+       d[2] = v >> 8;
+       d[3] = v;
+}
+
+struct node {
+       uae_u16 v;
+       struct node *left;
+       struct node *right;
+};
+typedef struct node NODE;
+
+static uae_u8 temp, temp2;
+
+static uae_u8 *expand_tree (uae_u8 *stream, NODE *node)
+{
+       if (temp & temp2) {
+               fdi_free (node->left);
+               node->left = 0;
+               fdi_free (node->right);
+               node->right = 0;
+               temp2 >>= 1;
+               if (!temp2) {
+                       temp = *stream++;
+                       temp2 = 0x80;
+               }
+               return stream;
+       } else {
+               uae_u8 *stream_temp;
+               temp2 >>= 1;
+               if (!temp2) {
+                       temp = *stream++;
+                       temp2 = 0x80;
+               }
+               node->left = fdi_malloc (sizeof (NODE));
+               memset (node->left, 0, sizeof (NODE));
+               stream_temp = expand_tree (stream, node->left);
+               node->right = fdi_malloc (sizeof (NODE));
+               memset (node->right, 0, sizeof (NODE));
+               return expand_tree (stream_temp, node->right);
+       }
+}
+
+static uae_u8 *values_tree8 (uae_u8 *stream, NODE *node)
+{
+       if (node->left == 0) {
+               node->v = *stream++;
+               return stream;
+       } else {
+               uae_u8 *stream_temp = values_tree8 (stream, node->left);
+               return values_tree8 (stream_temp, node->right);
+       }
+}
+
+static uae_u8 *values_tree16 (uae_u8 *stream, NODE *node)
+{
+       if (node->left == 0) {
+               uae_u16 high_8_bits = (*stream++) << 8;
+               node->v = high_8_bits | (*stream++);
+               return stream;
+       } else {
+               uae_u8 *stream_temp = values_tree16 (stream, node->left);
+               return values_tree16 (stream_temp, node->right);
+       }
+}
+
+static void free_nodes (NODE *node)
+{
+       if (node) {
+               free_nodes (node->left);
+               free_nodes (node->right);
+               fdi_free (node);
+       }
+}
+
+static uae_u32 sign_extend16 (uae_u32 v)
+{
+       if (v & 0x8000)
+               v |= 0xffff0000;
+       return v;
+}
+
+static uae_u32 sign_extend8 (uae_u32 v)
+{
+       if (v & 0x80)
+               v |= 0xffffff00;
+       return v;
+}
+
+static void fdi_decode (uae_u8 *stream, int size, uae_u8 *out)
+{
+       int i;
+       uae_u8 sign_extend, sixteen_bit, sub_stream_shift;
+       NODE root;
+       NODE *current_node;
+
+       memset (out, 0, size * 4);
+       sub_stream_shift = 1;
+       while (sub_stream_shift) {
+
+               //sub-stream header decode
+               sign_extend = *stream++;
+               sub_stream_shift = sign_extend & 0x7f;
+               sign_extend &= 0x80;
+               sixteen_bit = (*stream++) & 0x80;
+
+               //huffman tree architecture decode
+               temp = *stream++;
+               temp2 = 0x80;
+               stream = expand_tree (stream, &root);
+               if (temp2 == 0x80)
+                       stream--;
+
+               //huffman output values decode
+               if (sixteen_bit)
+                       stream = values_tree16 (stream, &root);
+               else
+                       stream = values_tree8 (stream, &root);
+
+               //sub-stream data decode
+               temp2 = 0;
+               for (i = 0; i < size; i++) {
+                       uae_u32 v;
+                       uae_u8 decode = 1;
+                       current_node = &root;
+                       while (decode) {
+                               if (current_node->left == 0) {
+                                       decode = 0;
+                               } else {
+                                       temp2 >>= 1;
+                                       if (!temp2) {
+                                               temp2 = 0x80;
+                                               temp = *stream++;
+                                       }
+                                       if (temp & temp2)
+                                               current_node = current_node->right;
+                                       else
+                                               current_node = current_node->left;
+                               }
+                       }
+                       v = ((uae_u32*)out)[i];
+                       if (sign_extend) {
+                               if (sixteen_bit)
+                                       v |= sign_extend16 (current_node->v) << sub_stream_shift;
+                               else
+                                       v |= sign_extend8 (current_node->v) << sub_stream_shift;
+                       } else {
+                               v |= current_node->v << sub_stream_shift;
+                       }
+                       ((uae_u32*)out)[i] = v;
+               }
+               free_nodes (root.left);
+               free_nodes (root.right);
+       }
+}
+
+
+static int decode_raw_track (FDI *fdi)
+{
+       int size = get_u32(fdi->track_src);
+       memcpy (fdi->track_dst, fdi->track_src, (size + 7) >> 3);
+       fdi->track_src += (size + 7) >> 3;
+       return size;
+}
+
+/* unknown track */
+static void zxx (FDI *fdi)
+{
+       outlog ("track %d: unknown track type 0x%02.2X\n", fdi->current_track, fdi->track_type);
+//     return -1;
+}
+/* unsupported track */
+static void zyy (FDI *fdi)
+{
+       outlog ("track %d: unsupported track type 0x%02.2X\n", fdi->current_track, fdi->track_type);
+//     return -1;
+}
+/* empty track */
+static void track_empty (FDI *fdi)
+{
+//     return 0;
+}
+
+/* unknown sector described type */
+static void dxx (FDI *fdi)
+{
+       outlog ("\ntrack %d: unknown sector described type 0x%02.2X\n", fdi->current_track, fdi->track_type);
+       fdi->err = 1;
+}
+/* unsupported sector described type */
+static void dyy (FDI *fdi)
+{
+       outlog ("\ntrack %d: unsupported sector described 0x%02.2X\n", fdi->current_track, fdi->track_type);
+       fdi->err = 1;
+}
+/* add position of mfm sync bit */
+static void add_mfm_sync_bit (FDI *fdi)
+{
+       if (fdi->nextdrop) {
+               fdi->nextdrop = 0;
+               return;
+       }
+       fdi->mfmsync_buffer[fdi->mfmsync_offset++] = fdi->out;
+       if (fdi->out == 0) {
+               outlog ("illegal position for mfm sync bit, offset=%d\n",fdi->out);
+               fdi->err = 1;
+       }
+       if (fdi->mfmsync_offset >= MAX_MFM_SYNC_BUFFER) {
+               fdi->mfmsync_offset = 0;
+               outlog ("mfmsync buffer overflow\n");
+               fdi->err = 1;
+       }
+       fdi->out++;
+}
+
+#define BIT_BYTEOFFSET ((fdi->out) >> 3)
+#define BIT_BITOFFSET (7-((fdi->out)&7))
+
+/* add one bit */
+static void bit_add (FDI *fdi, int bit)
+{
+       if (fdi->nextdrop) {
+               fdi->nextdrop = 0;
+               return;
+       }
+       fdi->track_dst[BIT_BYTEOFFSET] &= ~(1 << BIT_BITOFFSET);
+       if (bit) 
+               fdi->track_dst[BIT_BYTEOFFSET] |= (1 << BIT_BITOFFSET);
+       fdi->out++;
+       if (fdi->out >= MAX_DST_BUFFER * 8) {
+               outlog ("destination buffer overflow\n");
+               fdi->err = 1;
+               fdi->out = 1;
+       }
+}
+/* add bit and mfm sync bit */
+static void bit_mfm_add (FDI *fdi, int bit)
+{
+       add_mfm_sync_bit (fdi);
+       bit_add (fdi, bit);
+}
+/* remove following bit */
+static void bit_drop_next (FDI *fdi)
+{
+       if (fdi->nextdrop > 0) {
+               outlog("multiple bit_drop_next() called");
+       } else if (fdi->nextdrop < 0) {
+               fdi->nextdrop = 0;
+               debuglog(":DNN:");
+               return;
+       }
+       debuglog(":DN:");
+       fdi->nextdrop = 1;
+}
+
+/* ignore next bit_drop_next() */
+static void bit_dedrop (FDI *fdi)
+{
+       if (fdi->nextdrop) {
+               outlog("bit_drop_next called before bit_dedrop");
+       }
+       fdi->nextdrop = -1;
+       debuglog(":BDD:");
+}
+
+/* add one byte */
+static void byte_add (FDI *fdi, uae_u8 v)
+{
+       int i;
+       for (i = 7; i >= 0; i--)
+               bit_add (fdi, v & (1 << i));
+}
+/* add one word */
+static void word_add (FDI *fdi, uae_u16 v)
+{
+       byte_add (fdi, (uae_u8)(v >> 8));
+       byte_add (fdi, (uae_u8)v);
+}
+/* add one byte and mfm encode it */
+static void byte_mfm_add (FDI *fdi, uae_u8 v)
+{
+       int i;
+       for (i = 7; i >= 0; i--)
+               bit_mfm_add (fdi, v & (1 << i));
+}
+/* add multiple bytes and mfm encode them */
+static void bytes_mfm_add (FDI *fdi, uae_u8 v, int len)
+{
+       int i;
+       for (i = 0; i < len; i++) byte_mfm_add (fdi, v);
+}
+/* add one mfm encoded word and re-mfm encode it */
+static void word_post_mfm_add (FDI *fdi, uae_u16 v)
+{
+       int i;
+       for (i = 14; i >= 0; i -= 2)
+               bit_mfm_add (fdi, v & (1 << i));
+}
+
+/* bit 0 */
+static void s00(FDI *fdi) { bit_add (fdi, 0); }
+/* bit 1*/
+static void s01(FDI *fdi) { bit_add (fdi, 1); }
+/* 4489 */
+static void s02(FDI *fdi) { word_add (fdi, 0x4489); }
+/* 5224 */
+static void s03(FDI *fdi) { word_add (fdi, 0x5224); }
+/* mfm sync bit */
+static void s04(FDI *fdi) { add_mfm_sync_bit (fdi); }
+/* RLE MFM-encoded data */
+static void s08(FDI *fdi)
+{
+       int bytes = *fdi->track_src++;
+       uae_u8 byte = *fdi->track_src++;
+       if (bytes == 0) bytes = 256;
+       debuglog ("s08:len=%d,data=%02.2X",bytes,byte);
+       while(bytes--) byte_add (fdi, byte);
+}
+/* RLE MFM-decoded data */
+static void s09(FDI *fdi)
+{
+       int bytes = *fdi->track_src++;
+       uae_u8 byte = *fdi->track_src++;
+       if (bytes == 0) bytes = 256;
+       bit_drop_next (fdi);
+       debuglog ("s09:len=%d,data=%02.2X",bytes,byte);
+       while(bytes--) byte_mfm_add (fdi, byte);
+}
+/* MFM-encoded data */
+static void s0a(FDI *fdi)
+{
+       int i, bits = (fdi->track_src[0] << 8) | fdi->track_src[1];
+       uae_u8 b;
+       fdi->track_src += 2;
+       debuglog ("s0a:bits=%d,data=%s", bits, datalog(fdi->track_src, (bits + 7) / 8));
+       while (bits >= 8) {
+               byte_add (fdi, *fdi->track_src++);
+               bits -= 8;
+       }
+       if (bits > 0) {
+               i = 7;
+               b = *fdi->track_src++;
+               while (bits--) {
+                       bit_add (fdi, b & (1 << i));
+                       i--;
+               }
+       }
+}
+/* MFM-encoded data */
+static void s0b(FDI *fdi)
+{
+       int i, bits = ((fdi->track_src[0] << 8) | fdi->track_src[1]) + 65536;
+       uae_u8 b;
+       fdi->track_src += 2;
+       debuglog ("s0b:bits=%d,data=%s", bits, datalog(fdi->track_src, (bits + 7) / 8));
+       while (bits >= 8) {
+               byte_add (fdi, *fdi->track_src++);
+               bits -= 8;
+       }
+       if (bits > 0) {
+               i = 7;
+               b = *fdi->track_src++;
+               while (bits--) {
+                       bit_add (fdi, b & (1 << i));
+                       i--;
+               }
+       }
+}
+/* MFM-decoded data */
+static void s0c(FDI *fdi)
+{
+       int i, bits = (fdi->track_src[0] << 8) | fdi->track_src[1];
+       uae_u8 b;
+       fdi->track_src += 2;
+       bit_drop_next (fdi);
+       debuglog ("s0c:bits=%d,data=%s", bits, datalog(fdi->track_src, (bits + 7) / 8));
+       while (bits >= 8) {
+               byte_mfm_add (fdi, *fdi->track_src++);
+               bits -= 8;
+       }
+       if (bits > 0) {
+               i = 7;
+               b = *fdi->track_src++;
+               while(bits--) {
+                       bit_mfm_add (fdi, b & (1 << i));
+                       i--;
+               }
+       }
+}
+/* MFM-decoded data */
+static void s0d(FDI *fdi)
+{
+       int i, bits = ((fdi->track_src[0] << 8) | fdi->track_src[1]) + 65536;
+       uae_u8 b;
+       fdi->track_src += 2;
+       bit_drop_next (fdi);
+       debuglog ("s0d:bits=%d,data=%s", bits, datalog(fdi->track_src, (bits + 7) / 8));
+       while (bits >= 8) {
+               byte_mfm_add (fdi, *fdi->track_src++);
+               bits -= 8;
+       }
+       if (bits > 0) {
+               i = 7;
+               b = *fdi->track_src++;
+               while(bits--) {
+                       bit_mfm_add (fdi, b & (1 << i));
+                       i--;
+               }
+       }
+}
+
+/* ***** */
+/* AMIGA */
+/* ***** */
+
+/* just for testing integrity of Amiga sectors */
+
+static void rotateonebit (uae_u8 *start, uae_u8 *end, int shift)
+{
+       if (shift == 0)
+               return;
+       while (start <= end) {
+               start[0] <<= shift;
+               start[0] |= start[1] >> (8 - shift);
+               start++;
+       }
+}
+
+static int check_offset;
+static uae_u16 getmfmword (uae_u8 *mbuf)
+{
+       uae_u32 v;
+
+       v = (mbuf[0] << 8) | (mbuf[1] << 0);
+       if (check_offset == 0)
+               return v;
+       v <<= 8;
+       v |= mbuf[2];
+       v >>= check_offset;
+       return v;
+}
+
+#define MFMMASK 0x55555555
+static uae_u32 getmfmlong (uae_u8 * mbuf)
+{
+       return ((getmfmword (mbuf) << 16) | getmfmword (mbuf + 2)) & MFMMASK;
+}
+
+static int amiga_check_track (FDI *fdi)
+{
+       int i, j, secwritten = 0;
+       int fwlen = fdi->out / 8;
+       int length = 2 * fwlen;
+       int drvsec = 11;
+       uae_u32 odd, even, chksum, id, dlong;
+       uae_u8 *secdata;
+       uae_u8 secbuf[544];
+       uae_u8 bigmfmbuf[60000];
+       uae_u8 *mbuf, *mbuf2, *mend;
+       char sectable[22];
+       uae_u8 *raw = fdi->track_dst_buffer;
+       int slabel, off;
+       int ok = 1;
+
+       memset (bigmfmbuf, 0, sizeof (bigmfmbuf));
+       mbuf = bigmfmbuf;
+       check_offset = 0;
+       for (i = 0; i < (fdi->out + 7) / 8; i++)
+               *mbuf++ = raw[i];
+       off = fdi->out & 7;
+#if 1
+       if (off > 0) {
+               mbuf--;
+               *mbuf &= ~((1 << (8 - off)) - 1);
+       }
+       j = 0;
+       while (i < (fdi->out + 7) / 8 + 600) {
+               *mbuf++ |= (raw[j] >> off) | ((raw[j + 1]) << (8 - off));
+               j++;
+               i++;
+       }
+#endif
+       mbuf = bigmfmbuf;
+
+       memset (sectable, 0, sizeof (sectable));
+       //memcpy (mbuf + fwlen, mbuf, fwlen * sizeof (uae_u16));
+       mend = bigmfmbuf + length;
+       mend -= (4 + 16 + 8 + 512);
+
+       while (secwritten < drvsec) {
+               int trackoffs;
+
+               for (;;) {
+                       rotateonebit (bigmfmbuf, mend, 1);
+                       if (getmfmword (mbuf) == 0)
+                               break;
+                       if (secwritten == 10) {
+                               mbuf[0] = 0x44;
+                               mbuf[1] = 0x89;
+                       }
+//                     check_offset++;
+                       if (check_offset > 7) {
+                               check_offset = 0;
+                               mbuf++;
+                               if (mbuf >= mend || *mbuf == 0)
+                                       break;
+                       }
+                       if (getmfmword (mbuf) == 0x4489)
+                               break;
+               }
+               if (mbuf >= mend || *mbuf == 0)
+                       break;
+
+               rotateonebit (bigmfmbuf, mend, check_offset);
+               check_offset = 0;
+               mbuf2 = mbuf;
+
+               while (getmfmword (mbuf) == 0x4489)
+                       mbuf+= 1 * 2;
+
+               odd = getmfmlong (mbuf);
+               even = getmfmlong (mbuf + 2 * 2);
+               mbuf += 4 * 2;
+               id = (odd << 1) | even;
+
+               trackoffs = (id & 0xff00) >> 8;
+               if (trackoffs + 1 > drvsec) {
+                       debuglog("illegal sector offset %d\n",trackoffs);
+                       ok = 0;
+                       mbuf = mbuf2;
+                       continue;
+               }
+               if ((id >> 24) != 0xff) {
+                       debuglog ("sector %d format type %02.2X?\n", trackoffs, id >> 24);
+                       ok = 0;
+               }
+               chksum = odd ^ even;
+               slabel = 0;
+               for (i = 0; i < 4; i++) {
+                       odd = getmfmlong (mbuf);
+                       even = getmfmlong (mbuf + 8 * 2);
+                       mbuf += 2* 2;
+
+                       dlong = (odd << 1) | even;
+                       if (dlong) slabel = 1;
+                       chksum ^= odd ^ even;
+               }
+               mbuf += 8 * 2;
+               odd = getmfmlong (mbuf);
+               even = getmfmlong (mbuf + 2 * 2);
+               mbuf += 4 * 2;
+               if (((odd << 1) | even) != chksum) {
+                       debuglog("sector %d header crc error\n", trackoffs);
+                       ok = 0;
+                       mbuf = mbuf2;
+                       continue;
+               }
+               debuglog("sector %d header crc ok\n", trackoffs);
+               if (((id & 0x00ff0000) >> 16) != (uae_u32)fdi->current_track) {
+                       debuglog("illegal track number %d <> %d\n",fdi->current_track,(id & 0x00ff0000) >> 16);
+                       ok++;
+                       mbuf = mbuf2;
+                       continue;
+               }
+               odd = getmfmlong (mbuf);
+               even = getmfmlong (mbuf + 2 * 2);
+               mbuf += 4 * 2;
+               chksum = (odd << 1) | even;
+               secdata = secbuf + 32;
+               for (i = 0; i < 128; i++) {
+                       odd = getmfmlong (mbuf);
+                       even = getmfmlong (mbuf + 256 * 2);
+                       mbuf += 2 * 2;
+                       dlong = (odd << 1) | even;
+                       *secdata++ = (uae_u8) (dlong >> 24);
+                       *secdata++ = (uae_u8) (dlong >> 16);
+                       *secdata++ = (uae_u8) (dlong >> 8);
+                       *secdata++ = (uae_u8) dlong;
+                       chksum ^= odd ^ even;
+               }
+               mbuf += 256 * 2;
+               if (chksum) {
+                       debuglog("sector %d data checksum error\n",trackoffs);
+                       ok = 0;
+               } else if (sectable[trackoffs]) {
+                       debuglog("sector %d already found?\n", trackoffs);
+                       mbuf = mbuf2;
+               } else {
+                       debuglog("sector %d ok\n",trackoffs);
+                       if (slabel) debuglog("(non-empty sector header)\n");
+                       sectable[trackoffs] = 1;
+                       secwritten++;
+                       if (trackoffs == 9)
+                               mbuf += 0x228;
+               }
+       }
+       for (i = 0; i < drvsec; i++) {
+               if (!sectable[i]) {
+                       debuglog ("sector %d missing\n", i);
+                       ok = 0;
+               }
+       }
+       return ok;
+}
+
+static void amiga_data_raw (FDI *fdi, uae_u8 *secbuf, uae_u8 *crc, int len)
+{
+       int i;
+       uae_u8 crcbuf[4];
+
+       if (!crc) {
+               memset (crcbuf, 0, 4);
+       } else {
+               memcpy (crcbuf, crc ,4);
+       }
+       for (i = 0; i < 4; i++)
+               byte_mfm_add (fdi, crcbuf[i]);
+       for (i = 0; i < len; i++)
+               byte_mfm_add (fdi, secbuf[i]);
+}
+
+static void amiga_data (FDI *fdi, uae_u8 *secbuf)
+{
+       uae_u16 mfmbuf[4 + 512];
+       uae_u32 dodd, deven, dck;
+       int i;
+
+       for (i = 0; i < 512; i += 4) {
+               deven = ((secbuf[i + 0] << 24) | (secbuf[i + 1] << 16)
+                | (secbuf[i + 2] << 8) | (secbuf[i + 3]));
+               dodd = deven >> 1;
+               deven &= 0x55555555;
+               dodd &= 0x55555555;
+               mfmbuf[(i >> 1) + 4] = (uae_u16) (dodd >> 16);
+               mfmbuf[(i >> 1) + 5] = (uae_u16) dodd;
+               mfmbuf[(i >> 1) + 256 + 4] = (uae_u16) (deven >> 16);
+               mfmbuf[(i >> 1) + 256 + 5] = (uae_u16) deven;
+       }
+       dck = 0;
+       for (i = 4; i < 4 + 512; i += 2)
+               dck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1];
+       deven = dodd = dck;
+       dodd >>= 1;
+       deven &= 0x55555555;
+       dodd &= 0x55555555;
+       mfmbuf[0] = (uae_u16) (dodd >> 16);
+       mfmbuf[1] = (uae_u16) dodd;
+       mfmbuf[2] = (uae_u16) (deven >> 16);
+       mfmbuf[3] = (uae_u16) deven;
+
+       for (i = 0; i < 4 + 512; i ++)
+               word_post_mfm_add (fdi, mfmbuf[i]);
+}
+
+static void amiga_sector_header (FDI *fdi, uae_u8 *header, uae_u8 *data, int sector, int untilgap)
+{
+       uae_u8 headerbuf[4], databuf[16];
+       uae_u32 deven, dodd, hck;
+       uae_u16 mfmbuf[24];
+       int i;
+
+       byte_mfm_add (fdi, 0);
+       byte_mfm_add (fdi, 0);
+       word_add (fdi, 0x4489);
+       word_add (fdi, 0x4489);
+       if (header) {
+               memcpy (headerbuf, header, 4);
+       } else {
+               headerbuf[0] = 0xff;
+               headerbuf[1] = (uae_u8)fdi->current_track;
+               headerbuf[2] = (uae_u8)sector;
+               headerbuf[3] = (uae_u8)untilgap;
+       }
+       if (data)
+               memcpy (databuf, data, 16);
+       else
+               memset (databuf, 0, 16);
+
+       deven = ((headerbuf[0] << 24) | (headerbuf[1] << 16)
+               | (headerbuf[2] << 8) | (headerbuf[3]));
+       dodd = deven >> 1;
+       deven &= 0x55555555;
+       dodd &= 0x55555555;
+       mfmbuf[0] = (uae_u16) (dodd >> 16);
+       mfmbuf[1] = (uae_u16) dodd;
+       mfmbuf[2] = (uae_u16) (deven >> 16);
+       mfmbuf[3] = (uae_u16) deven;
+       for (i = 0; i < 16; i += 4) {
+               deven = ((databuf[i] << 24) | (databuf[i + 1] << 16)
+                       | (databuf[i + 2] << 8) | (databuf[i + 3]));
+               dodd = deven >> 1;
+               deven &= 0x55555555;
+               dodd &= 0x55555555;
+               mfmbuf[(i >> 1) + 0 + 4] = (uae_u16) (dodd >> 16);
+               mfmbuf[(i >> 1) + 0 + 5] = (uae_u16) dodd;
+               mfmbuf[(i >> 1) + 8 + 4] = (uae_u16) (deven >> 16);
+               mfmbuf[(i >> 1) + 8 + 5] = (uae_u16) deven;
+       }
+       hck = 0;
+       for (i = 0; i < 4 + 16; i += 2)
+               hck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1];
+       deven = dodd = hck;
+       dodd >>= 1;
+       deven &= 0x55555555;
+       dodd &= 0x55555555;
+       mfmbuf[20] = (uae_u16) (dodd >> 16);
+       mfmbuf[21] = (uae_u16) dodd;
+       mfmbuf[22] = (uae_u16) (deven >> 16);
+       mfmbuf[23] = (uae_u16) deven;
+
+       for (i = 0; i < 4 + 16 + 4; i ++)
+               word_post_mfm_add (fdi, mfmbuf[i]);
+}
+
+/* standard super-extended Amiga sector header */
+static void s20(FDI *fdi)
+{
+       bit_drop_next (fdi);
+       debuglog ("s20:header=%s,data=%s", datalog(fdi->track_src, 4), datalog(fdi->track_src + 4, 16)); 
+       amiga_sector_header (fdi, fdi->track_src, fdi->track_src + 4, 0, 0);
+       fdi->track_src += 4 + 16;
+}
+/* standard extended Amiga sector header */
+static void s21(FDI *fdi)
+{
+       bit_drop_next (fdi);
+       debuglog ("s21:header=%s", datalog(fdi->track_src, 4)); 
+       amiga_sector_header (fdi, fdi->track_src, 0, 0, 0);
+       fdi->track_src += 4;
+}
+/* standard Amiga sector header */
+static void s22(FDI *fdi)
+{
+       bit_drop_next (fdi);
+       debuglog("s22:sector=%d,untilgap=%d", fdi->track_src[0], fdi->track_src[1]);
+       amiga_sector_header (fdi, 0, 0, fdi->track_src[0], fdi->track_src[1]);
+       fdi->track_src += 2;
+}
+/* standard 512-byte, CRC-correct Amiga data */
+static void s23(FDI *fdi)
+{
+       debuglog("s23:data=%s", datalog (fdi->track_src, 512));
+       amiga_data (fdi, fdi->track_src);
+       fdi->track_src += 512;
+}
+/* not-decoded, 128*2^x-byte, CRC-correct Amiga data */
+static void s24(FDI *fdi)
+{
+       int shift = *fdi->track_src++;
+       debuglog("s24:shift=%d,data=%s", shift, datalog (fdi->track_src, 128 << shift));
+       amiga_data_raw (fdi, fdi->track_src, 0, 128 << shift);
+       fdi->track_src += 128 << shift;
+}
+/* not-decoded, 128*2^x-byte, CRC-incorrect Amiga data */
+static void s25(FDI *fdi)
+{
+       int shift = *fdi->track_src++;
+       debuglog("s25:shift=%d,crc=%s,data=%s", shift, datalog (fdi->track_src, 4), datalog (fdi->track_src + 4, 128 << shift));
+       amiga_data_raw (fdi, fdi->track_src + 4, fdi->track_src, 128 << shift);
+       fdi->track_src += 4 + (128 << shift);
+}
+/* standard extended Amiga sector */
+static void s26(FDI *fdi)
+{
+       s21 (fdi);
+       debuglog("s26:data=%s", datalog (fdi->track_src, 512));
+       amiga_data (fdi, fdi->track_src);
+       fdi->track_src += 512;
+}
+/* standard short Amiga sector */
+static void s27(FDI *fdi)
+{
+       s22 (fdi);
+       debuglog("s27:data=%s", datalog (fdi->track_src, 512));
+       amiga_data (fdi, fdi->track_src);
+       fdi->track_src += 512;
+}
+
+/* *** */
+/* IBM */
+/* *** */
+
+static uae_u16 ibm_crc (uae_u8 byte, int reset)
+{
+       static uae_u16 crc;
+       int i;
+
+       if (reset) crc = 0xcdb4;
+       for (i = 0; i < 8; i++) {
+               if (crc & 0x8000) {
+                       crc <<= 1;
+                       if (!(byte & 0x80)) crc ^= 0x1021;
+               } else {
+                       crc <<= 1;
+                       if (byte & 0x80) crc ^= 0x1021;
+               }
+               byte <<= 1;
+       }
+       return crc;
+}
+
+static void ibm_data (FDI *fdi, uae_u8 *data, uae_u8 *crc, int len)
+{
+       int i;
+       uae_u8 crcbuf[2];
+       uae_u16 crcv;
+
+       word_add (fdi, 0x4489);
+       word_add (fdi, 0x4489);
+       word_add (fdi, 0x4489);
+       byte_mfm_add (fdi, 0xfb);
+       ibm_crc (0xfb, 1);
+       for (i = 0; i < len; i++) {
+               byte_mfm_add (fdi, data[i]);
+               crcv = ibm_crc (data[i], 0);
+       }
+       if (!crc) {
+               crc = crcbuf;
+               crc[0] = (uae_u8)(crcv >> 8);
+               crc[1] = (uae_u8)crcv;
+       }
+       byte_mfm_add (fdi, crc[0]);
+       byte_mfm_add (fdi, crc[1]);
+}
+
+static void ibm_sector_header (FDI *fdi, uae_u8 *data, uae_u8 *crc, int secnum, int pre)
+{
+       uae_u8 secbuf[5];
+       uae_u8 crcbuf[2];
+       uae_u16 crcv;
+       int i;
+
+       if (pre)
+               bytes_mfm_add (fdi, 0, 12);
+       word_add (fdi, 0x4489);
+       word_add (fdi, 0x4489);
+       word_add (fdi, 0x4489);
+       secbuf[0] = 0xfe;
+       if (secnum >= 0) {
+               secbuf[1] = (uae_u8)(fdi->current_track/2);
+               secbuf[2] = (uae_u8)(fdi->current_track%2);
+               secbuf[3] = (uae_u8)secnum;
+               secbuf[4] = 2;
+       } else {
+               memcpy (secbuf + 1, data, 4);
+       }
+       ibm_crc (secbuf[0], 1);
+       ibm_crc (secbuf[1], 0);
+       ibm_crc (secbuf[2], 0);
+       ibm_crc (secbuf[3], 0);
+       crcv = ibm_crc (secbuf[4], 0);
+       if (crc) {
+               memcpy (crcbuf, crc, 2);
+       } else {
+               crcbuf[0] = (uae_u8)(crcv >> 8);
+               crcbuf[1] = (uae_u8)crcv;
+       }
+       /* data */
+       for (i = 0;i < 5; i++)
+               byte_mfm_add (fdi, secbuf[i]);
+       /* crc */
+       byte_mfm_add (fdi, crcbuf[0]);
+       byte_mfm_add (fdi, crcbuf[1]);
+}
+
+/* standard IBM index address mark */
+static void s10(FDI *fdi)
+{
+       bit_drop_next (fdi);
+       bytes_mfm_add (fdi, 0, 12);
+       word_add (fdi, 0x5224);
+       word_add (fdi, 0x5224);
+       word_add (fdi, 0x5224);
+       byte_mfm_add (fdi, 0xfc);
+}
+/* standard IBM pre-gap */
+static void s11(FDI *fdi)
+{
+       bit_drop_next (fdi);
+       bytes_mfm_add (fdi, 0x4e, 78);
+       bit_dedrop (fdi);
+       s10 (fdi);
+       bytes_mfm_add (fdi, 0x4e, 50);
+}
+/* standard ST pre-gap */
+static void s12(FDI *fdi)
+{
+       bit_drop_next (fdi);
+       bytes_mfm_add (fdi, 0x4e, 78);
+}
+/* standard extended IBM sector header */
+static void s13(FDI *fdi)
+{
+       bit_drop_next (fdi);
+       debuglog ("s13:header=%s", datalog (fdi->track_src, 4));
+       ibm_sector_header (fdi, fdi->track_src, 0, -1, 1);
+       fdi->track_src += 4;
+}
+/* standard mini-extended IBM sector header */
+static void s14(FDI *fdi)
+{
+       debuglog ("s14:header=%s", datalog (fdi->track_src, 4));
+       ibm_sector_header (fdi, fdi->track_src, 0, -1, 0);
+       fdi->track_src += 4;
+}
+/* standard short IBM sector header */
+static void s15(FDI *fdi)
+{
+       bit_drop_next (fdi);
+       debuglog ("s15:sector=%d", *fdi->track_src);
+       ibm_sector_header (fdi, 0, 0, *fdi->track_src++, 1);
+}
+/* standard mini-short IBM sector header */
+static void s16(FDI *fdi)
+{
+       debuglog ("s16:track=%d", *fdi->track_src);
+       ibm_sector_header (fdi, 0, 0, *fdi->track_src++, 0);
+}
+/* standard CRC-incorrect mini-extended IBM sector header */
+static void s17(FDI *fdi)
+{
+       debuglog ("s17:header=%s,crc=%s", datalog (fdi->track_src, 4), datalog (fdi->track_src + 4, 2));
+       ibm_sector_header (fdi, fdi->track_src, fdi->track_src + 4, -1, 0);
+       fdi->track_src += 4 + 2;
+}
+/* standard CRC-incorrect mini-short IBM sector header */
+static void s18(FDI *fdi)
+{
+       debuglog ("s18:sector=%d,header=%s", *fdi->track_src, datalog (fdi->track_src + 1, 4));
+       ibm_sector_header (fdi, 0, fdi->track_src + 1, *fdi->track_src, 0);
+       fdi->track_src += 1 + 4;
+}
+/* standard 512-byte CRC-correct IBM data */
+static void s19(FDI *fdi)
+{
+       debuglog ("s19:data=%s", datalog (fdi->track_src , 512));
+       ibm_data (fdi, fdi->track_src, 0, 512);
+       fdi->track_src += 512;
+}
+/* standard 128*2^x-byte-byte CRC-correct IBM data */
+static void s1a(FDI *fdi)
+{
+       int shift = *fdi->track_src++;
+       debuglog ("s1a:shift=%d,data=%s", shift, datalog (fdi->track_src , 128 << shift));
+       ibm_data (fdi, fdi->track_src, 0, 128 << shift);
+       fdi->track_src += 128 << shift;
+}
+/* standard 128*2^x-byte-byte CRC-incorrect IBM data */
+static void s1b(FDI *fdi)
+{
+       int shift = *fdi->track_src++;
+       debuglog ("s1b:shift=%d,crc=%s,data=%s", shift, datalog (fdi->track_src + (128 << shift), 2), datalog (fdi->track_src , 128 << shift));
+       ibm_data (fdi, fdi->track_src, fdi->track_src + (128 << shift), 128 << shift);
+       fdi->track_src += (128 << shift) + 2;
+}
+/* standard extended IBM sector */
+static void s1c(FDI *fdi)
+{
+       int shift = fdi->track_src[3];
+       s13 (fdi);
+       bytes_mfm_add (fdi, 0x4e, 22);
+       bytes_mfm_add (fdi, 0x00, 12);
+       ibm_data (fdi, fdi->track_src, 0, 128 << shift);
+       fdi->track_src += 128 << shift;
+}
+/* standard short IBM sector */
+static void s1d(FDI *fdi)
+{
+       s15 (fdi);
+       bytes_mfm_add (fdi, 0x4e, 22);
+       bytes_mfm_add (fdi, 0x00, 12);
+       s19 (fdi);
+}
+
+/* end marker */
+static void sff(FDI *fdi)
+{
+}
+
+typedef void (*decode_described_track_func)(FDI*);
+
+static decode_described_track_func decode_sectors_described_track[] =
+{
+       s00,s01,s02,s03,s04,dxx,dxx,dxx,s08,s09,s0a,s0b,s0c,s0d,dxx,dxx, /* 00-0F */
+       s10,s11,s12,s13,s14,s15,s16,s17,s18,s19,s1a,s1b,s1c,s1d,dxx,dxx, /* 10-1F */
+       s20,s21,s22,s23,s24,s25,s26,s27,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 20-2F */
+       dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 30-3F */
+       dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 40-4F */
+       dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 50-5F */
+       dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 60-6F */
+       dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 70-7F */
+       dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 80-8F */
+       dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 90-9F */
+       dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* A0-AF */
+       dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* B0-BF */
+       dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* C0-CF */
+       dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* D0-DF */
+       dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* E0-EF */
+       dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,sff  /* F0-FF */
+};
+
+static void track_amiga (struct fdi *fdi, int first_sector, int max_sector)
+{
+       int i;
+
+       bit_add (fdi, 0);
+       bit_drop_next (fdi);
+       for (i = 0; i < max_sector; i++) {
+               amiga_sector_header (fdi, 0, 0, first_sector, max_sector - i);
+               amiga_data (fdi, fdi->track_src + first_sector * 512);
+               first_sector++;
+               if (first_sector >= max_sector) first_sector = 0;
+       }
+       bytes_mfm_add (fdi, 0, 260); /* gap */
+}
+static void track_atari_st (struct fdi *fdi, int max_sector)
+{
+       int i, gap3;
+       uae_u8 *p = fdi->track_src;
+
+       switch (max_sector)
+               {
+               case 9:
+               gap3 = 40;
+               break;
+               case 10:
+               gap3 = 24;
+               break;
+       }
+       s15 (fdi);
+       for (i = 0; i < max_sector; i++) {
+               byte_mfm_add (fdi, 0x4e);
+               byte_mfm_add (fdi, 0x4e);
+               ibm_sector_header (fdi, 0, 0, fdi->current_track, 1);
+               ibm_data (fdi, p + i * 512, 0, 512);
+               bytes_mfm_add (fdi, 0x4e, gap3);
+       }
+       bytes_mfm_add (fdi, 0x4e, 660 - gap3);
+       fdi->track_src += fdi->track_len * 256;
+}
+static void track_pc (struct fdi *fdi, int max_sector)
+{
+       int i, gap3;
+       uae_u8 *p = fdi->track_src;
+
+       switch (max_sector)
+               {
+               case 8:
+               gap3 = 116;
+               break;
+               case 9:
+               gap3 = 54;
+               break;
+               default:
+               gap3 = 100; /* fixme */
+               break;
+       }
+       s11 (fdi);
+       for (i = 0; i < max_sector; i++) {
+               byte_mfm_add (fdi, 0x4e);
+               byte_mfm_add (fdi, 0x4e);
+               ibm_sector_header (fdi, 0, 0, fdi->current_track, 1);
+               ibm_data (fdi, p + i * 512, 0, 512);
+               bytes_mfm_add (fdi, 0x4e, gap3);
+       }
+       bytes_mfm_add (fdi, 0x4e, 600 - gap3);
+       fdi->track_src += fdi->track_len * 256;
+}
+
+/* amiga dd */
+static void track_amiga_dd (struct fdi *fdi)
+{
+       uae_u8 *p = fdi->track_src;
+       track_amiga (fdi, fdi->track_len >> 4, 11);
+       fdi->track_src = p + (fdi->track_len & 15) * 512;
+}
+/* amiga hd */
+static void track_amiga_hd (struct fdi *fdi)
+{
+       uae_u8 *p = fdi->track_src;
+       track_amiga (fdi, 0, 22);
+       fdi->track_src = p + fdi->track_len * 256;
+}
+/* atari st 9 sector */
+static void track_atari_st_9 (struct fdi *fdi)
+{
+       track_atari_st (fdi, 9);
+}
+/* atari st 10 sector */
+static void track_atari_st_10 (struct fdi *fdi)
+{
+       track_atari_st (fdi, 10);
+}
+/* pc 8 sector */
+static void track_pc_8 (struct fdi *fdi)
+{
+       track_pc (fdi, 8);
+}
+/* pc 9 sector */
+static void track_pc_9 (struct fdi *fdi)
+{
+       track_pc (fdi, 9);
+}
+/* pc 15 sector */
+static void track_pc_15 (struct fdi *fdi)
+{
+       track_pc (fdi, 15);
+}
+/* pc 18 sector */
+static void track_pc_18 (struct fdi *fdi)
+{
+       track_pc (fdi, 18);
+}
+/* pc 36 sector */
+static void track_pc_36 (struct fdi *fdi)
+{
+       track_pc (fdi, 36);
+}
+
+typedef void (*decode_normal_track_func)(FDI*);
+
+static decode_normal_track_func decode_normal_track[] =
+{ 
+       track_empty, /* 0 */
+       track_amiga_dd, track_amiga_hd, /* 1-2 */
+       track_atari_st_9, track_atari_st_10, /* 3-4 */
+       track_pc_8, track_pc_9, track_pc_15, track_pc_18, track_pc_36, /* 5-9 */
+       zxx,zxx,zxx,zxx,zxx /* A-F */
+};
+
+static void fix_mfm_sync (FDI *fdi)
+{
+       int i, pos, off1, off2, off3, mask1, mask2, mask3;
+
+       for (i = 0; i < fdi->mfmsync_offset; i++) {
+               pos = fdi->mfmsync_buffer[i];
+               off1 = (pos - 1) >> 3;
+               off2 = (pos + 1) >> 3;
+               off3 = pos >> 3;
+               mask1 = 1 << (7 - ((pos - 1) & 7));
+               mask2 = 1 << (7 - ((pos + 1) & 7));
+               mask3 = 1 << (7 - (pos & 7));
+               if (!(fdi->track_dst[off1] & mask1) && !(fdi->track_dst[off2] & mask2))
+                       fdi->track_dst[off3] |= mask3;
+               else
+                       fdi->track_dst[off3] &= ~mask3;
+       }
+}
+
+static int handle_sectors_described_track (FDI *fdi)
+{
+       int oldout;
+       uae_u8 *start_src = fdi->track_src ;
+       fdi->encoding_type = *fdi->track_src++;
+       fdi->index_offset = get_u32(fdi->track_src);
+       fdi->index_offset >>= 8;
+       fdi->track_src += 3;
+       outlog ("sectors_described, index offset: %d\n",fdi->index_offset);
+
+       do {
+               fdi->track_type = *fdi->track_src++;
+               outlog ("%06.6X %06.6X %02.2X:",fdi->track_src - start_src + 0x200, fdi->out/8, fdi->track_type);
+               oldout = fdi->out;
+               decode_sectors_described_track[fdi->track_type](fdi);
+               outlog(" %d\n", fdi->out - oldout);
+               oldout = fdi->out;
+               if (fdi->out < 0 || fdi->err) {
+                       outlog ("\nin %d bytes, out %d bits\n", fdi->track_src - fdi->track_src_buffer, fdi->out);
+                       return -1;
+               }
+               if (fdi->track_src - fdi->track_src_buffer >= fdi->track_src_len) {
+                       outlog ("source buffer overrun, previous type: %02.2X\n", fdi->track_type);
+                       return -1;
+               }
+       } while (fdi->track_type != 0xff);
+       outlog("\n");
+       fix_mfm_sync (fdi);
+       return fdi->out;
+}
+
+static uae_u8 *fdi_decompress (int pulses, uae_u8 *sizep, uae_u8 *src, int *dofree)
+{
+       uae_u32 size = get_u24 (sizep);
+       uae_u32 *dst2;
+       int len = size & 0x3fffff;
+       uae_u8 *dst;
+       int mode = size >> 22, i;
+
+       *dofree = 0;
+       if (mode == 0 && pulses * 2 > len)
+               mode = 1;
+       if (mode == 0) {
+               dst2 = (uae_u32*)src;
+               for (i = 0; i < pulses; i++) {
+                       *dst2++ = get_u32 (src);                        
+                       src += 4;
+               }
+               dst = src;
+       } else if (mode == 1) {
+               dst = fdi_malloc (pulses *4);
+               *dofree = 1;
+               fdi_decode (src, pulses, dst);
+       } else {
+               dst = 0;
+       }
+       return dst;
+}
+
+static void dumpstream(int track, uae_u8 *stream, int len)
+{
+    char name[100];
+    FILE *f;
+
+    sprintf (name, "track_%d.raw", track);
+    f = fopen(name, "wb");
+    fwrite (stream, 1, len * 4, f);
+    fclose (f);
+}    
+
+static int bitoffset;
+
+STATIC_INLINE void addbit (uae_u8 *p, int bit)
+{
+       int off1 = bitoffset / 8;
+       int off2 = bitoffset % 8;
+       p[off1] |= bit << (7 - off2);
+       bitoffset++;
+}
+
+
+struct pulse_sample {
+       unsigned long size;
+       int number_of_bits;
+};
+
+#define FDI_MAX_ARRAY 6 /* change this value as you want */
+static int pulse_limitval = 20;
+static struct pulse_sample psarray[FDI_MAX_ARRAY];
+static int array_index;
+static unsigned long total;
+static int totaldiv;
+
+static void init_array(unsigned long standard_MFM_2_bit_cell_size)
+{
+       int i;
+       
+       for (i = 0; i < FDI_MAX_ARRAY; i++) {
+               psarray[i].size = standard_MFM_2_bit_cell_size; // That is (total track length / 50000) for Amiga double density
+               total += psarray[i].size;
+               psarray[i].number_of_bits = 2;
+               totaldiv += psarray[i].number_of_bits;
+       }
+       array_index = 0;
+}
+
+static void fdi2_mfm_decode(FDI *fdi, unsigned long totalavg, uae_u32 *avgp, uae_u8 *idx, int idx_off1, int idx_off2, int idx_off3, int maxidx, int pulses)
+{
+       unsigned long adjust;
+       unsigned long adjusted_pulse;
+       unsigned long standard_MFM_2_bit_cell_size = totalavg / 50000;
+       int real_size, i, j;
+       uae_u8 *d = fdi->track_dst_buffer;
+       uae_u16 *pt = fdi->track_dst_buffer_timing;
+
+       adjust = 0;
+       total = 0;
+       totaldiv = 0;
+       init_array(standard_MFM_2_bit_cell_size);
+       bitoffset = 0;
+       for (i = 0; i < pulses; i++)
+       {
+               if (idx[idx_off1] + idx[idx_off2] >= maxidx) {
+                       uae_u32 pulse = avgp[i];
+                       uae_u32 avg_size = total / totaldiv; /* this is the new average size for one MFM bit */
+                       /* you can try tighter ranges than 25%, or wider ranges. I would probably go for tighter... */
+                       if ((avg_size < ((standard_MFM_2_bit_cell_size / 2) - (pulse_limitval * standard_MFM_2_bit_cell_size / 200))) ||
+                               (avg_size > ((standard_MFM_2_bit_cell_size / 2) + (pulse_limitval * standard_MFM_2_bit_cell_size /200))))
+                                       init_array(standard_MFM_2_bit_cell_size); 
+                               /* this is to prevent the average value from going too far
+                               * from the theoretical value, otherwise it could progressively go to (2 *
+                               * real value), or (real value / 2), etc. */
+                       if ((pulse > adjust) && (adjust < avg_size))
+                               adjusted_pulse = pulse - adjust;
+                       else
+                               adjusted_pulse = pulse;
+                       adjusted_pulse = pulse;
+                       real_size = 1;
+                       do {
+                               addbit (d, 0);
+                               real_size++;
+                       } while (adjusted_pulse > avg_size * real_size + avg_size / 2);
+                       addbit (d, 1);
+#if 1
+                       for (j = 0; j < real_size; j++)
+                               *pt++ = (uae_u16)(adjusted_pulse / real_size);
+#endif
+                       /* Note that you should also consider values above 4! Too lazy to do it here ;-) */
+                       adjust = (real_size * avg_size) - pulse;
+                       /* function to transform the value in real_size to '01', '001' or '0001', and append this to the decoded MFM stream */
+                       total -= psarray[array_index].size;
+                       totaldiv -= psarray[array_index].number_of_bits;
+                       psarray[array_index].size = pulse;
+                       psarray[array_index].number_of_bits = real_size;
+                       total += pulse;
+                       totaldiv += real_size;
+                       array_index++;
+                       if (array_index >= FDI_MAX_ARRAY)
+                               array_index = 0;
+               }
+               idx += idx_off3;
+       }
+       fdi->out = bitoffset;
+       write_log ("result bits: %d\n", bitoffset);
+}
+
+static void fdi2_celltiming (FDI *fdi, unsigned long totalavg, int bitoffset)
+{
+       uae_u16 *pt2, *pt;
+       double avg_bit_len;
+       int timed = 0;
+       int i;
+
+       avg_bit_len = (double)totalavg / (double)bitoffset;
+       pt2 = pt = fdi->track_dst_buffer_timing;
+       for (i = 0; i < bitoffset / 8; i++) {
+               double v = (pt2[0] + pt2[1] + pt2[2] + pt2[3] + pt2[4] + pt2[5] + pt2[6] + pt2[7]) / 8.0;
+               uae_u16 vv;
+               v = 1000.0 * v / avg_bit_len;
+               vv = (uae_u16)v;
+               *pt++ = vv;
+               if (vv > 1030 || vv < 970)
+                       timed = 1;
+               pt2 += 8;
+       }
+       *pt++ = fdi->track_dst_buffer_timing[0];
+       *pt = fdi->track_dst_buffer_timing[0];
+       if (!timed)
+               fdi->track_dst_buffer_timing[0] = 0;
+}
+
+static int decode_lowlevel_track (FDI *fdi, int *indexoffsetp, int track)
+{
+       uae_u8 *p1, *d;
+       uae_u32 *p2;
+       uae_u32 *avgp, *minp = 0, *maxp = 0;
+       uae_u8 *idxp = 0;
+       uae_u32 maxidx, minidx, totalavg, weakbits;
+       int i, len, pulses, indexoffset;
+       int avg_free, min_free = 0, max_free = 0, idx_free;
+       int idx_off1, idx_off2, idx_off3;
+
+       d = fdi->track_dst;
+       p1 = fdi->track_src;
+       pulses = get_u32 (p1);
+       if (!pulses)
+               return -1;
+       p1 += 4;
+       len = 12;
+       avgp = (uae_u32*)fdi_decompress (pulses, p1 + 0, p1 + len, &avg_free);
+       //dumpstream(track, (uae_u8*)avgp, pulses);
+       len += get_u24 (p1 + 0) & 0x3fffff;
+       if (!avgp)
+               return -1;
+       if (get_u24 (p1 + 3) && get_u24 (p1 + 6)) {
+#if 0
+               minp = (uae_u32*)fdi_decompress (pulses, p1 + 3, p1 + len, &min_free);
+#endif
+               len += get_u24 (p1 + 3) & 0x3fffff;
+#if 0
+               maxp = (uae_u32*)fdi_decompress (pulses, p1 + 6, p1 + len, &max_free);
+#endif
+               len += get_u24 (p1 + 6) & 0x3fffff;
+       }
+       if (get_u24 (p1 + 9)) {
+               idx_off1 = 0;
+               idx_off2 = 1;
+               idx_off3 = 2;
+               idxp = fdi_decompress (pulses, p1 + 9, p1 + len, &idx_free);
+               if (idx_free) {
+                       if (idxp[0] == 0 && idxp[1] == 0) {
+                               idx_off1 = 2;
+                               idx_off2 = 3;
+                       } else {
+                               idx_off1 = 1;
+                               idx_off2 = 0;
+                       }
+                       idx_off3 = 4;
+               }
+       } else {
+               idxp = fdi_malloc (pulses * 2);
+               idx_free = 1;
+               for (i = 0; i < pulses; i++) {
+                       idxp[i * 2 + 0] = 2;
+                       idxp[i * 2 + 1] = 0;
+               }
+               idxp[0] = 1;
+               idxp[1] = 1;
+       }
+
+       maxidx = 0;
+       minidx = 255;
+       indexoffset = 0;
+       p1 = idxp;
+       for (i = 0; i < pulses; i++) {
+               if (p1[idx_off1] + p1[idx_off2] > maxidx)
+                       maxidx = p1[idx_off1] + p1[idx_off2];
+               if (abs (p1[idx_off1] - p1[idx_off2]) < minidx) {
+                       minidx = abs (p1[idx_off1] - p1[idx_off2]);
+                       indexoffset = i;
+               }
+               p1 += idx_off3;
+       }
+       p1 = idxp;
+       p2 = avgp;
+       totalavg = 0;
+       weakbits = 0;
+       for (i = 0; i < pulses; i++) {
+               if (p1[idx_off1] + p1[idx_off2] >= maxidx) {
+                       totalavg += *p2;
+               } else {
+                       weakbits++;
+               }
+               p2++;
+               p1 += idx_off3;
+       }
+       len = totalavg / 100000;
+       outlog("totalavg=%d index=%d maxidx=%d weakbits=%d len=%d\n",
+               totalavg, indexoffset, maxidx, weakbits, len);
+       fdi2_mfm_decode (fdi, totalavg, avgp, idxp, idx_off1, idx_off2, idx_off3, maxidx, pulses);
+       outlog("number of bits=%d avg len=%.2f\n", bitoffset, (double)totalavg / bitoffset);
+       fdi2_celltiming (fdi, totalavg, bitoffset);
+
+       *indexoffsetp = indexoffset;
+       if (avg_free)
+               fdi_free (avgp);
+       if (min_free)
+               fdi_free (minp);
+       if (max_free)
+               fdi_free (maxp);
+       if (idx_free)
+               fdi_free (idxp);
+       return bitoffset;
+}
+
+static unsigned char fdiid[]={"Formatted Disk Image file"};
+static int bit_rate_table[16] = { 125,150,250,300,500,1000 };
+
+void fdi2raw_header_free (FDI *fdi)
+{
+       int i, j;
+
+       fdi_free (fdi->mfmsync_buffer);
+       fdi_free (fdi->track_src_buffer);
+       fdi_free (fdi->track_dst_buffer);
+       fdi_free (fdi->track_dst_buffer_timing);
+       for (i = 0; i < MAX_TRACKS; i++) {
+               struct fdi_cache *c = &fdi->cache[i];
+               for (j = 0; j < MAX_REVOLUTIONS; j++)
+                       fdi_free (c->cache_buffer[j]);
+               fdi_free (c->cache_buffer_timing);
+       }
+       fdi_free (fdi);
+#ifdef DEBUG
+       write_log ("FREE: memory allocated %d\n", fdi_allocated);
+#endif
+}
+
+int fdi2raw_get_last_track (FDI *fdi)
+{
+       return fdi->last_track;
+}
+
+int fdi2raw_get_num_sector (FDI *fdi)
+{
+       if (fdi->header[152] == 0x02)
+               return 22;
+       return 11;
+}
+
+int fdi2raw_get_last_head (FDI *fdi)
+{
+       return fdi->last_head;
+}
+
+int fdi2raw_get_rotation (FDI *fdi)
+{
+       return fdi->rotation_speed;
+}
+
+int fdi2raw_get_bit_rate (FDI *fdi)
+{
+       return fdi->bit_rate;
+}
+
+int fdi2raw_get_type (FDI *fdi)
+{
+       return fdi->disk_type;
+}
+
+int fdi2raw_get_write_protect (FDI *fdi)
+{
+       return fdi->write_protect;
+}
+
+FDI *fdi2raw_header(struct zfile *f)
+{
+       int i, offset, oldseek;
+       uae_u8 type, size;
+       FDI *fdi;
+
+#ifdef DEBUG
+       write_log ("ALLOC: memory allocated %d\n", fdi_allocated);
+#endif
+       fdi = fdi_malloc(sizeof(FDI));
+       memset (fdi, 0, sizeof (FDI));
+       fdi->file = f;
+       oldseek = zfile_ftell (fdi->file);
+       zfile_fseek (fdi->file, 0, SEEK_SET);
+       zfile_fread (fdi->header, 2048, 1, fdi->file);
+       zfile_fseek (fdi->file, oldseek, SEEK_SET);
+       if (memcmp (fdiid, fdi->header, strlen (fdiid)) ) {
+               fdi_free(fdi);
+               return NULL;
+       }
+       if ((fdi->header[140] != 1 && fdi->header[140] != 2) || fdi->header[141] != 0) {
+               fdi_free(fdi);
+               return NULL;
+       }
+
+       fdi->mfmsync_buffer = fdi_malloc (MAX_MFM_SYNC_BUFFER * sizeof(int));
+       fdi->track_src_buffer = fdi_malloc (MAX_SRC_BUFFER);
+       fdi->track_dst_buffer = fdi_malloc (MAX_DST_BUFFER);
+       fdi->track_dst_buffer_timing = fdi_malloc (MAX_TIMING_BUFFER);
+       
+       fdi->last_track = ((fdi->header[142] << 8) + fdi->header[143]) + 1;
+       fdi->last_track *= fdi->header[144] + 1;
+       if (fdi->last_track > MAX_TRACKS)
+               fdi->last_track = MAX_TRACKS;
+       fdi->last_head = fdi->header[144];
+       fdi->disk_type = fdi->header[145];
+       fdi->rotation_speed = fdi->header[146] + 128;
+       fdi->write_protect = fdi->header[147] & 1;
+       outlog ("FDI version %d.%d\n", fdi->header[140], fdi->header[141]);
+       outlog ("last_track=%d rotation_speed=%d\n",fdi->last_track,fdi->rotation_speed);
+
+       offset = 512;
+       i = fdi->last_track;
+       if (i > 180) {
+               offset += 512;
+               i -= 180;
+               while (i > 256) {
+                       offset += 512;
+                       i -= 256;
+               }
+       }
+       for (i = 0; i < fdi->last_track; i++) {
+               fdi->track_offsets[i] = offset;
+               type = fdi->header[152 + i * 2];
+               size = fdi->header[152 + i * 2 + 1];
+               if (type == 1)
+                       offset += (size & 15) * 512;
+               else if ((type & 0xc0) == 0x80)
+                       offset += (((type & 0x3f) << 8) | size) * 256;
+               else
+                       offset += size * 256;
+       }
+       fdi->track_offsets[i] = offset;
+
+       return fdi;
+}
+
+
+int fdi2raw_loadtrack (FDI *fdi, uae_u16 *mfmbuf, uae_u16 **trackpointers, uae_u16 **tracktiming, int track, int *tracklengths, int *revolutions, int *indexoffsetp)
+{
+       uae_u8 *p;
+       int outlen, i, j, indexoffset = 0;
+       struct fdi_cache *cache;
+
+       *revolutions = 1;
+       *tracktiming = 0;
+       trackpointers[0] = mfmbuf;
+
+       cache = &fdi->cache[track];
+       if (cache->cache_buffer[0]) {
+               uae_u16 *tt;
+               *revolutions = 0;
+               for (j = 0; j < MAX_REVOLUTIONS && cache->cache_buffer[j]; j++) {
+                       (*revolutions)++;
+                       tracklengths[j] = cache->length[j];
+                       trackpointers[j] = mfmbuf;
+                       for (i = 0; i < (tracklengths[j] + 15) / (2 * 8); i++) {
+                               uae_u8 *data = cache->cache_buffer[j] + i * 2;
+                               *mfmbuf++ = 256 * *data + *(data + 1);
+                       }
+               }               
+               if (cache->cache_buffer_timing) {
+                       tt = xmalloc ((tracklengths[0] + 7) / 8 * sizeof (uae_u16));
+                       memcpy (tt, cache->cache_buffer_timing, (tracklengths[0] + 7) / 8 * sizeof (uae_u16));
+                       *tracktiming = tt;
+               }
+               *indexoffsetp = cache->indexoffset;
+               return 1;
+       }
+               
+       fdi->err = 0;
+       fdi->track_src_len = fdi->track_offsets[track + 1] - fdi->track_offsets[track];
+       zfile_fseek (fdi->file, fdi->track_offsets[track], SEEK_SET);
+       zfile_fread (fdi->track_src_buffer, fdi->track_src_len, 1, fdi->file);
+       memset (fdi->track_dst_buffer, 0, MAX_DST_BUFFER);
+       fdi->track_dst_buffer_timing[0] = 0;
+
+       fdi->current_track = track;
+       fdi->track_src = fdi->track_src_buffer;
+       fdi->track_dst = fdi->track_dst_buffer;
+       p = fdi->header + 152 + fdi->current_track * 2;
+       fdi->track_type = *p++;
+       fdi->track_len = *p++;
+       fdi->bit_rate = 0;
+       fdi->out = 0;
+       fdi->mfmsync_offset = 0;
+
+       if ((fdi->track_type & 0xf0) == 0xf0 || (fdi->track_type & 0xf0) == 0xe0)
+               fdi->bit_rate = bit_rate_table[fdi->track_type & 0x0f];
+       else
+               fdi->bit_rate = 250;
+
+       outlog ("track %d: srclen: %d track_type: %02.2X, bitrate: %d\n",
+               fdi->current_track, fdi->track_src_len, fdi->track_type, fdi->bit_rate);
+
+       if ((fdi->track_type & 0xc0) == 0x80) {
+
+               outlen = decode_lowlevel_track (fdi, &indexoffset, track);
+
+       } else if ((fdi->track_type & 0xf0) == 0xf0) {
+
+               outlen = decode_raw_track (fdi);
+
+       } else if ((fdi->track_type & 0xf0) == 0xe0) {
+
+               outlen = handle_sectors_described_track (fdi);
+
+       } else if ((fdi->track_type & 0xf0)) {
+
+               zxx (fdi);
+               outlen = -1;
+               
+       } else if (fdi->track_type < 0x10) {
+
+               decode_normal_track[fdi->track_type](fdi);
+               fix_mfm_sync (fdi);
+               outlen = fdi->out;
+
+       } else {
+
+               zxx (fdi);
+               outlen = -1;
+
+       }
+
+       if (fdi->err)
+               return 0;
+
+       if (outlen > 0) {
+               for (j = 0; j < MAX_REVOLUTIONS; j++) {
+                       fdi_free (cache->cache_buffer[j]);
+                       cache->cache_buffer[j] = 0;
+               }
+               fdi_free (cache->cache_buffer_timing);
+               cache->cache_buffer_timing = 0;
+               cache->indexoffset = indexoffset;
+               cache->length[0] = outlen;
+               cache->cache_buffer[0] = fdi_malloc ((outlen + 7) / 8);
+               memcpy (cache->cache_buffer[0], fdi->track_dst_buffer, (outlen + 7) / 8);
+               if (fdi->track_dst_buffer_timing[0] > 0) {
+                       cache->cache_buffer_timing = fdi_malloc ((outlen + 7) / 8 * sizeof (uae_u16));
+                       memcpy (cache->cache_buffer_timing, fdi->track_dst_buffer_timing, (outlen + 7) / 8 * sizeof (uae_u16));
+               }
+               return fdi2raw_loadtrack (fdi, mfmbuf, trackpointers, tracktiming, track, tracklengths, revolutions, indexoffsetp);
+       }
+       return 0;
+}
+
diff --git a/filesys.asm b/filesys.asm
new file mode 100755 (executable)
index 0000000..ade0472
--- /dev/null
@@ -0,0 +1,767 @@
+       SECTION code,code
+; This file can be translated with A68k or PhxAss and then linked with BLink
+; to produce an Amiga executable. Make sure it does not contain any
+; relocations, then run it through the filesys.sh script
+;
+; Patrick: It also works with SAS/C asm+slink, but I had to remove
+; the .l from jsr.l and jmp.l.
+; Toni Wilen: modified SECTION, compiles now with AsmOne and clones(?)
+; Removed absolute RT_AREA references
+; 2002.08.06 RDB automount/autoboot support (Toni Wilen)
+; 2002.09.11 KS1.3 RDB support (TW)
+
+AllocMem = -198
+FreeMem = -210
+
+; don't forget filesys.c! */
+PP_MAXSIZE = 4 * 96
+PP_FSSIZE = 400
+PP_FSPTR = 404
+PP_FSRES = 408
+PP_EXPLIB = 412
+PP_FSHDSTART = 416
+PP_TOTAL = (PP_FSHDSTART+140)
+
+NOTIFY_CLASS = $40000000
+NOTIFY_CODE = $1234
+NRF_SEND_MESSAGE = 1
+NRF_SEND_SIGNAL = 2
+NRF_WAIT_REPLY = 8
+NRF_NOTIFY_INITIAL = 16
+NRF_MAGIC = $80000000
+
+       dc.l 16
+our_seglist:
+       dc.l 0 ;/* NextSeg */
+start:
+       bra filesys_mainloop
+       dc.l make_dev-start
+       dc.l filesys_init-start
+       dc.l exter_server-start
+       dc.l bootcode-start
+       dc.l setup_exter-start
+
+       dc.l p96vsyncfix1-start
+
+bootcode:
+       lea.l doslibname(pc),a1
+       jsr -96(a6) ; FindResident
+       move.l d0,a0
+       move.l 22(a0),d0
+       move.l d0,a0
+       jsr (a0)
+       rts
+
+filesys_init:
+       movem.l d0-d7/a0-a6,-(sp)
+       move.l 4.w,a6
+       move.w #$FFFC,d0 ; filesys base
+       bsr getrtbase
+       move.l (a0),a5
+       lea.l explibname(pc),a1 ; expansion lib name
+       moveq #36,d0
+       moveq #0,d5
+       jsr  -552(a6) ; OpenLibrary
+       tst.l d0
+       bne.b FSIN_explibok
+       lea.l explibname(pc),a1 ; expansion lib name
+       moveq #0,d0
+       moveq #1,d5
+       jsr  -552(a6) ; OpenLibrary
+FSIN_explibok:
+       move.l d0,a4
+       move.l #PP_TOTAL,d0
+       moveq #1,d1 ; MEMF_PUBLIC
+       jsr AllocMem(a6)
+       move.l d0,a3  ; param packet
+       move.l a4,PP_EXPLIB(a3)
+
+       moveq #0,d6
+FSIN_init_units:
+       cmp.l  $10c(a5),d6
+       bcc.b FSIN_units_ok
+       move.l d6,-(sp)
+FSIN_nextsub:
+       moveq   #1,d7
+       move.l a3,-(sp)
+       move.l a3,a0
+       bsr.w make_dev
+       move.l (sp)+,a3
+       cmp.l #-2,d0
+       beq.s FSIN_nomoresub
+       swap d6
+       addq.w #1,d6
+       swap d6
+       bra.s FSIN_nextsub
+FSIN_nomoresub:        
+       move.l (sp)+,d6
+       addq.w #1,d6
+       bra.b  FSIN_init_units
+
+FSIN_units_ok:
+       move.l 4.w,a6
+       move.l a4,a1
+       jsr -414(a6) ; CloseLibrary
+
+       ; add >2MB chip RAM to memory list
+       move.w #$FF80,d0
+       bsr.w getrtbase
+       jsr (a0)
+       moveq.l #3,d1
+       moveq.l #-10,d2
+       move.l #$200000,a0
+       sub.l a0,d0
+       bcs.b FSIN_chip_done
+       beq.b FSIN_chip_done
+       moveq.l #0,d4
+       move.l d4,a1
+       jsr -618(a6)
+FSIN_chip_done
+
+       movem.l (sp)+,d0-d7/a0-a6
+general_ret:
+       rts
+
+exter_data:
+exter_server:
+       movem.l a2,-(sp)
+       move.w #$FF50,d0
+       bsr.w getrtbase
+       moveq.l #0,d0
+       jsr (a0)
+       tst.l d0
+       beq.w exter_server_exit
+       ; This is the hard part - we have to send some messages.
+       move.l 4.w,a6
+EXTS_loop:
+       move.w #$FF50,d0 ;exter_int_helper
+       bsr.w getrtbase
+       moveq.l #2,d0
+       jsr (a0)
+       cmp.w #1,d0
+       blt.b EXTS_done
+       bgt.b EXTS_signal_reply
+       jsr -366(a6) ; PutMsg
+       bra.b EXTS_loop
+EXTS_signal_reply:
+        cmp.w #2,d0
+        bgt.b EXTS_reply
+       move.l d1,d0
+       jsr -$144(a6)   ; Signal
+       bra.b EXTS_loop
+EXTS_reply:
+       cmp.w #3,d0
+       bgt.b EXTS_cause
+       jsr -$17a(a6)   ; ReplyMsg
+       bra.b EXTS_loop
+EXTS_cause:
+       cmp.w #4,d0
+       bgt.b EXTS_notificationhack
+       jsr -$b4(a6)    ; Cause
+       bra.b EXTS_loop
+EXTS_notificationhack:
+       cmp.w #5,d0
+       bgt.b EXTS_done
+       movem.l a0-a1,-(sp)
+       moveq #38,d0
+       move.l #65536+1,d1
+       jsr AllocMem(a6)
+       movem.l (sp)+,a0-a1
+       move.l d0,a2
+       move.b #8,8(a2)
+       move.l a0,14(a2)
+       move.w #38,18(a2)
+       move.l #NOTIFY_CLASS,20(a2)
+       move.w #NOTIFY_CODE,24(a2)
+       move.l a1,26(a2)
+       move.l 16(a1),a0
+       move.l a2,a1
+       jsr -366(a6) ; PutMsg
+       bra.w EXTS_loop
+EXTS_done:
+       move.w #$FF50,d0 ;exter_int_helper
+       bsr.w getrtbase
+       moveq.l #4,d0
+       jsr (a0)        
+       moveq.l #1,d0 ; clear Z - it was for us.
+exter_server_exit:
+       movem.l (sp)+,a2
+       rts
+
+setup_exter:
+       movem.l d0-d1/a0-a1,-(sp)
+       moveq.l #26,d0
+       move.l #$10001,d1
+       jsr AllocMem(a6)
+       move.l d0,a1
+       lea.l exter_name(pc),a0
+       move.l a0,10(a1)
+       lea.l exter_data(pc),a0
+       move.l a0,14(a1)
+       lea.l exter_server(pc),a0
+       move.l a0,18(a1)
+       move.w #$0214,8(a1)
+       moveq.l #3,d0
+       jsr -168(a6) ; AddIntServer
+       movem.l (sp)+,d0-d1/a0-a1
+       rts
+
+addfs: ; a0 = first hunk, a1 = parmpacket
+       movem.l d0-d1/a0-a3/a6,-(sp)
+       move.l 4.w,a6
+       move.l a0,a2
+       move.l a1,a3
+       move.l #62+128,d0 ; sizeof(FileSysEntry) + patchflags;
+       move.l #$10001,d1
+       jsr -198(a6)
+       move.l d0,a0
+       moveq #0,d0
+       lea PP_FSHDSTART(a3),a1
+af1    move.b 0(a1,d0.w),14(a0,d0.w)
+       addq.w #1,d0
+       cmp.w #140,d0
+       bne.s af1
+       move.l a2,d0
+       lsr.l #2,d0
+       move.l d0,54(a0) ;seglist
+       move.l a0,a1
+       lea exter_name(pc),a0
+       move.l a0,10(a1) ; name
+       move.l PP_FSRES(a3),a0 ; FileSystem.resource
+       lea 18(a0),a0 ; fsr_FileSysEntries
+       jsr -$f0(a6) ;AddHead
+       movem.l (sp)+,d0-d1/a0-a3/a6
+       rts
+
+relocate: ;a0=pointer to executable, returns first segment in A0
+       movem.l d1-d7/a1-a6,-(sp)
+       move.l 4.w,a6
+       move.l a0,a2
+       cmp.l #$3f3,(a2)+
+       bne.w ree
+       addq.l #8,a2 ; skip name end and skip total hunks + 1
+       move.l 4(a2),d7 ; last hunk
+       sub.l (a2),d7 ; first hunk
+       addq.l #8,a2 ; skip hunk to load first and hunk to load last
+       addq.l #1,d7
+       move.l a2,a3
+       move.l d7,d0
+       add.l d0,d0
+       add.l d0,d0
+       add.l d0,a3
+       move.l a2,a4
+
+       ; allocate hunks
+       sub.l a5,a5 ;prev segment
+       moveq #0,d6
+r15    move.l (a2),d2 ; hunk size (header)
+       lsl.l #2,d2
+       moveq #1,d1
+       btst #30,d3 ; chip mem?
+       beq.s r2
+       bset #1,d1
+r2     bset #16,d1
+       bclr #31,d3
+       bclr #30,d3
+       move.l d2,d0
+       bne.s r17
+       clr.l (a2)+ ; empty hunk
+       bra.s r18
+r17    addq.l #8,d0 ; size + pointer to next hunk + hunk size
+       jsr AllocMem(a6)
+       tst.l d0
+       beq.w ree
+       move.l d0,a0
+       move.l d2,(a0)+ ; store size
+       move.l a0,(a2)+ ; store new pointer
+       move.l a5,d1
+       beq.s r10
+       move.l a0,d0
+       lsr.l #2,d0
+       move.l d0,(a5)
+r10    move.l a0,a5
+r18    addq.l #1,d6
+       cmp.l d6,d7
+       bne.s r15
+
+       moveq #0,d6
+r3     
+       move.l 0(a4,d6.l*4),a0
+       addq.l #4,a0
+       move.l (a3)+,d3 ; hunk type
+       move.l (a3)+,d4 ; hunk size
+       lsl.l #2,d4
+       cmp.l #$3e9,d3 ;code
+       beq.s r4
+       cmp.l #$3ea,d3 ;data
+       bne.s r5
+r4
+       ; code and data
+       move.l d4,d0
+r6     tst.l d0
+       beq.s r7
+       move.b (a3)+,(a0)+
+       subq.l #1,d0
+       bra.s r6
+r5
+       cmp.l #$3eb,d3 ;bss
+       bne.s ree
+
+r7 ; scan for reloc32 or hunk_end
+       move.l (a3)+,d3
+       cmp.l #$3ec,d3 ;reloc32
+       bne.s r13
+
+       ; relocate
+       move.l 0(a4,d6.l*4),a0 ; current hunk
+       addq.l #4,a0
+r11    move.l (a3)+,d0 ;number of relocs
+       beq.s r7
+       move.l (a3)+,d1 ;hunk
+       move.l 0(a4,d1.l*4),d3 ;hunk start address
+       addq.l #4,d3
+r9     move.l (a3)+,d2 ;offset
+       add.l d3,0(a0,d2.l)
+       subq.l #1,d0
+       bne.s r9
+       bra.s r11
+r13
+       cmp.l #$3f2,d3 ;end
+       bne.s ree
+       
+       addq.l #1,d6
+       cmp.l d6,d7
+       bne.w r3
+       
+       moveq #1,d7
+       move.l (a4),a0
+r0     move.l d7,d0
+       movem.l (sp)+,d1-d7/a1-a6
+       rts
+ree    move.w #30000,d0
+re1    move.w #$f00,$dff180
+       move.w #$00f,$dff180
+       move.w #$0f0,$dff180
+       dbf d0,re1
+       moveq #0,d7
+       bra.s r0
+
+fsres
+       movem.l d1/a0-a2/a6,-(sp)
+       move.l 4.w,a6
+       lea $150(a6),a0
+fsres3
+       tst.l (a0)
+       beq.s fsres1
+       move.l 10(a0),a1
+       lea fsresname(pc),a2
+fsres5
+       move.b (a1)+,d0
+       move.b (a2)+,d1
+       cmp.b d1,d0
+       bne.s fsres2
+       tst.b d0
+       beq.s fsres4
+       bra.s fsres5
+fsres2
+       move.l (a0),a0
+       bra.s fsres3
+       ; FileSystem.resource does not exist -> create it
+fsres1
+       moveq #32,d0 ; sizeof(FileSysResource)
+       move.l #$10001,d1
+       jsr AllocMem(a6)
+       move.l d0,a2
+       move.b #8,8(a2) ; NT_RESOURCE
+       lea fsresname(pc),a0
+       move.l a0,10(a2) ; node name
+       lea exter_name(pc),a0
+       move.l a0,14(a2) ; fsr_Creator
+       lea 18(a2),a0
+       move.l a0,(a0) ; NewList() fsr_FileSysEntries
+       addq.l #4,(a0)
+       move.l a0,8(a0)
+       lea $150(a6),a0 ; ResourceList
+       move.l a2,a1
+       jsr -$f6(a6) ; AddTail
+       move.l a2,a0
+fsres4
+       move.l a0,d0
+       movem.l (sp)+,d1/a0-a2/a6
+       rts
+       
+make_dev: ; IN: A0 param_packet, D6: unit_no, D7: boot, A4: expansionbase
+
+       bsr.w fsres
+       move.l d0,PP_FSRES(a0) ; pointer to FileSystem.resource
+       move.l a0,-(sp)
+       move.w #$FFFC,d0 ; filesys base
+       bsr.w getrtbase
+       move.l (a0),a5
+       move.w #$FF28,d0 ; fill in unit-dependent info (filesys_dev_storeinfo)
+       bsr.w getrtbase
+       move.l a0,a1
+       move.l (sp)+,a0
+       clr.l PP_FSSIZE(a0) ; filesystem size
+       clr.l PP_FSPTR(a0) ; filesystem memory
+       jsr (a1)
+       ; ret:0=virtual,1=hardfile,2=rdbhardfile,-1=hardfile-donotmount,-2=no more subunits
+       move.l d0,d3
+       cmp.l #-2,d3
+       beq.w general_ret
+       cmp.l #2,d3
+       beq.s mountalways
+       
+       ; KS < V36: init regular hardfiles only if filesystem is loaded
+       and.l d5,d0
+       beq.s mountalways ; >= 36
+       tst.l PP_FSSIZE(a0)
+       beq.w general_ret ; no filesystem -> don't mount
+
+mountalways
+       ; allocate memory for loaded filesystem
+       move.l PP_FSSIZE(a0),d0
+       beq.s nordbfs1
+       move.l a0,-(sp)
+       moveq #1,d1
+       move.l 4.w,a6
+       jsr  AllocMem(a6)
+       move.l (sp)+,a0
+       move.l d0,PP_FSPTR(a0)
+nordbfs1:
+
+       tst.l d3
+       bpl.s do_mount
+
+       ; do not mount but we might need to load possible custom filesystem(s)
+       move.l a0,a1
+       move.w #$FF20,d0 ; record in ui.startup (filesys_dev_remember)
+       bsr.w getrtbase
+       jsr (a0)
+       bra.w dont_mount
+
+do_mount:
+       move.l a4,a6
+       move.l a0,-(sp)
+       jsr -144(a6) ; MakeDosNode()
+       move.l (sp)+,a0 ; parmpacket
+       move.l a0,a1
+       move.l d0,a3 ; devicenode
+       move.w #$FF20,d0 ; record in ui.startup (filesys_dev_remember)
+       bsr.w getrtbase
+       jsr (a0)
+       moveq #0,d0
+       move.l d0,8(a3)          ; dn_Task
+       move.l d0,16(a3)         ; dn_Handler
+       move.l d0,32(a3)         ; dn_SegList
+
+dont_mount
+       tst.l PP_FSPTR(a1)      ; filesystem?
+       beq.s nordbfs2
+       move.l PP_FSPTR(a1),a0
+       bsr.w relocate
+       movem.l d0/a0-a1,-(sp)
+       move.l PP_FSSIZE(a1),d0
+       move.l PP_FSPTR(a1),a1
+       move.l 4.w,a6
+       jsr FreeMem(a6)
+       movem.l (sp)+,d0/a0-a1
+       tst.l d0
+       beq.s nordbfs2
+       bsr.w addfs
+nordbfs2:
+
+       tst.l d3
+       bmi.w general_ret
+
+       move.w #$FF18,d0 ; update dn_SegList if needed (filesys_dev_bootfilesys)
+       bsr.w getrtbase
+       jsr (a0)
+
+       move.l d3,d0
+       move.b 79(a1),d3 ; bootpri
+       tst.l d0
+       bne.b MKDV_doboot
+
+MKDV_is_filesys:
+       move.l #4000,20(a3)     ; dn_StackSize
+       lea.l our_seglist(pc),a1
+       move.l a1,d0
+       lsr.l  #2,d0
+       move.l d0,32(a3)        ; dn_SegList
+       moveq #-1,d0
+       move.l d0,36(a3)       ; dn_GlobalVec
+
+MKDV_doboot:
+       tst.l d7
+       beq.b MKDV_noboot
+
+       move.l 4.w,a6
+       moveq.l #20,d0
+       moveq.l #0,d1
+       jsr  AllocMem(a6)
+       move.l d0,a1 ; bootnode
+       moveq #0,d0
+       move.l d0,(a1)
+       move.l d0,4(a1)
+       move.w d0,14(a1)
+       move.w #$1000,d0
+       or.b d3,d0
+       move.w d0,8(a1)
+       move.l $104(a5),10(a1) ; filesys_configdev
+       move.l a3,16(a1)        ; devicenode
+       lea.l  74(a4),a0 ; MountList
+       jmp  -270(a6) ; Enqueue()
+
+MKDV_noboot:
+       move.l a3,a0
+       moveq #0,d1
+       move.l d1,a1
+       moveq #-1,d0
+       move.l a4,a6 ; expansion base
+       jmp  -150(a6) ; AddDosNode
+
+filesys_mainloop:
+       move.l 4.w,a6
+       moveq.l #0,d0
+       move.l d0,a1
+       jsr -294(a6) ; FindTask
+       move.l d0,a0
+       lea.l $5c(a0),a5 ; pr_MsgPort
+
+       ; Open DOS library
+       lea.l doslibname(pc),a1
+       moveq.l #0,d0
+       jsr -552(a6) ; OpenLibrary
+       move.l d0,a2
+
+       ; Allocate some memory. Usage:
+       ; 0: lock chain
+       ; 4: command chain
+       ; 8: second thread's lock chain
+       ; 12: dummy message
+       ; 32: the volume (80+44+1 bytes)
+       move.l #80+44+1+20+12,d0
+       move.l #$10001,d1 ; MEMF_PUBLIC | MEMF_CLEAR
+       jsr AllocMem(a6)
+       move.l d0,a3
+       moveq.l #0,d6
+       move.l d6,(a3)
+       move.l d6,4(a3)
+       move.l d6,8(a3)
+
+       moveq.l #0,d5 ; No commands queued.
+
+       ; Fetch our startup packet
+       move.l a5,a0
+       jsr -384(a6) ; WaitPort
+       move.l a5,a0
+       jsr -372(a6) ; GetMsg
+       move.l d0,a4
+       move.l 10(a4),d3 ; ln_Name
+       move.w #$FF40,d0 ; startup_handler
+       bsr.w getrtbase
+       moveq.l #0,d0
+       jsr (a0)
+       bra.w FSML_Reply
+
+       ; We abuse some of the fields of the message we get. Offset 0 is
+       ; used for chaining unprocessed commands, and offset 1 is used for
+       ; indicating the status of a command. 0 means the command was handed
+       ; off to some UAE thread and did not complete yet, 1 means we didn't
+       ; even hand it over yet because we were afraid that might blow some
+       ; pipe limit, and -1 means the command was handed over and has completed
+       ; processing by now, so it's safe to reply to it.
+
+FSML_loop:
+       move.l a5,a0
+       jsr -384(a6) ; WaitPort
+       move.l a5,a0
+       jsr -372(a6) ; GetMsg
+       move.l d0,a4
+
+       ; notify reply?
+       cmp.w #38, 18(a4)
+       bne.s nonotif
+       cmp.l #NOTIFY_CLASS, 20(a4)
+       bne.s nonotif
+       cmp.w #NOTIFY_CODE, 24(a4)
+       bne.s nonotif
+       move.l 26(a4),a0 ; NotifyRequest
+       move.l 12(a0),d0 ; flags
+       and.l #NRF_WAIT_REPLY|NRF_MAGIC,d0
+       cmp.l #NRF_WAIT_REPLY|NRF_MAGIC,d0
+       bne.s nonoti
+       and.l #~NRF_MAGIC,12(a0)
+       move.l 16(a0),a0
+       move.l a4,a1
+       move.b #8,(a1)
+       jsr -366(a6) ; PutMsg
+       bra.s FSML_loop
+nonoti
+       move.l a4,a1
+       moveq #38,d0
+       jsr FreeMem(a6)
+       bra.s FSML_loop
+
+nonotif
+       move.l 10(a4),d3 ; ln_Name
+       bne.b FSML_FromDOS
+
+       ; It's a dummy packet indicating that some queued command finished.
+       move.w #$FF50,d0 ; exter_int_helper
+       bsr.w getrtbase
+       moveq.l #1,d0
+       jsr (a0)
+       ; Go through the queue and reply all those that finished.
+       lea.l 4(a3),a2
+       move.l (a2),a0
+FSML_check_old:
+       move.l a0,d0
+       beq.b FSML_loop
+       move.l (a0),a1
+       move.l d0,a0
+       ; This field may be accessed concurrently by several UAE threads.
+       ; This _should_ be harmless on all reasonable machines.
+       move.l 4(a0),d0
+       bpl.b FSML_check_next
+       movem.l a0/a1,-(a7)
+       move.l 10(a0),a4
+       bsr.b ReplyOne
+       subq.l #1,d5  ; One command less in the queue
+       movem.l (a7)+,a0/a1
+       move.l a1,(a2)
+       move.l a1,a0
+       bra.b FSML_check_old
+FSML_check_next:
+       move.l a0,a2
+       move.l a1,a0
+       bra.b FSML_check_old
+
+FSML_FromDOS:
+       ; Limit the number of outstanding started commands. We can handle an
+       ; unlimited number of unstarted commands.
+       cmp.l #20,d5
+       bcs  FSML_DoCommand
+       ; Too many commands queued.
+       moveq.l #1,d0
+       move.l d0,4(a4)
+       bra.b FSML_Enqueue
+
+FSML_DoCommand:
+       bsr.b LockCheck  ; Make sure there are enough locks for the C code to grab.
+       move.w #$FF30,d0
+       bsr.w getrtbase
+       jsr (a0)
+       tst.l d0
+       beq.b FSML_Reply
+       ; The command did not complete yet. Enqueue it and increase number of
+       ; queued commands
+       ; The C code already set 4(a4) to 0
+       addq.l #1,d5
+FSML_Enqueue:
+       move.l 4(a3),(a4)
+       move.l a4,4(a3)
+       bra.w FSML_loop
+
+FSML_Reply:
+       move.l d3,a4
+       bsr.b ReplyOne
+       bra.w FSML_loop
+
+ReplyOne:
+       move.l (a4),a1  ; dp_Link
+       move.l 4(a4),a0 ; dp_Port
+       move.l a5,4(a4)
+       jmp -366(a6) ; PutMsg
+
+; ugly code to avoid calling AllocMem / FreeMem from native C code.
+; We keep a linked list of 3 locks. In theory, only one should ever
+; be used. Before handling every packet, we check that the list has the
+; right length.
+
+LockCheck:
+       move.l d5,-(a7)
+       moveq.l #-4,d5  ; Keep three locks
+       move.l (a3),a2
+       move.l a2,d7
+LKCK_Loop:
+       move.l a2,d1
+       beq LKCK_ListEnd
+       addq.l #1,d5
+       beq.b LKCK_TooMany
+       move.l a2,a1
+       move.l (a2),a2
+       bra.b LKCK_Loop
+LKCK_ListEnd:
+       addq.l #1,d5
+       beq.b LKCK_ret
+       move.l d7,a2
+       moveq.l #24,d0 ; sizeof Lock is 20, 4 for chain
+       moveq.l #1,d1 ; MEMF_PUBLIC
+       jsr AllocMem(a6)
+       addq.w #1,d6
+       move.l d0,a2
+       move.l d7,(a2)
+       move.l a2,d7
+       bra.b LKCK_ListEnd
+LKCK_TooMany:
+       move.l (a2),d0 ; We have too many, but we tolerate that to some extent.
+       beq.b LKCK_ret
+       move.l d0,a0
+       move.l (a0),d0
+       beq.b LKCK_ret
+       move.l d0,a0
+       move.l (a0),d0
+       beq.b LKCK_ret
+
+       moveq.l #0,d0 ; Now we are sure that we really have too many. Delete some.
+       move.l d0,(a1)
+LKCK_TooManyLoop:
+       move.l a2,a1
+       move.l (a1),a2
+       moveq.l #24,d0
+       jsr FreeMem(a6)
+       add.l #$10000,d6
+       move.l a2,d0
+       bne.b LKCK_TooManyLoop
+LKCK_ret:
+       move.l d7,(a3)
+       move.l (a7)+,d5
+       rts
+
+getrtbase:
+       lea start-8-4(pc),a0
+       and.l #$FFFF,d0
+       add.l d0,a0
+       rts
+
+p96flag        dc.w 0
+p96vsyncfix1
+       cmp.l #34,8(sp) ; picasso_WaitVerticalSync?
+       bne.s p961
+       movem.l d0-d1/a0-a2/a6,-(sp)
+       move.l 4.w,a6
+       sub.l a1,a1
+       jsr -$126(a6) ; FindTask
+       move.l d0,a2
+       move.l a2,a1
+       moveq #-20,d0
+       jsr -$12c(a6) ; SetTaskPri
+       lea p96flag(pc),a0
+       move.w (a0),d1
+p962   cmp.w (a0),d1
+       beq.s p962
+       move.l a2,a1
+       jsr -$12c(a6) ; SetTaskPri
+       moveq #1,d1
+       movem.l (sp)+,d0-d1/a0-a2/a6
+       addq.l #4,sp ; return directly to caller
+p961   rts
+
+
+exter_name: dc.b 'UAE filesystem',0
+doslibname: dc.b 'dos.library',0
+explibname: dc.b 'expansion.library',0
+fsresname: dc.b 'FileSystem.resource',0
+       END
diff --git a/filesys.c b/filesys.c
new file mode 100755 (executable)
index 0000000..02e2901
--- /dev/null
+++ b/filesys.c
@@ -0,0 +1,4351 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Unix file system handler for AmigaDOS
+  *
+  * Copyright 1996 Ed Hanway
+  * Copyright 1996, 1997 Bernd Schmidt
+  *
+  * Version 0.4: 970308
+  *
+  * Based on example code (c) 1988 The Software Distillery
+  * and published in Transactor for the Amiga, Volume 2, Issues 2-5.
+  * (May - August 1989)
+  *
+  * Known limitations:
+  * Does not support ACTION_INHIBIT (big deal).
+  * Does not support several 2.0+ packet types.
+  * Does not support removable volumes.
+  * May not return the correct error code in some cases.
+  * Does not check for sane values passed by AmigaDOS.  May crash the emulation
+  * if passed garbage values.
+  * Could do tighter checks on malloc return values.
+  * Will probably fail spectacularly in some cases if the filesystem is
+  * modified at the same time by another process while UAE is running.
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "threaddep/thread.h"
+#include "options.h"
+#include "uae.h"
+#include "memory.h"
+#include "custom.h"
+#include "events.h"
+#include "newcpu.h"
+#include "filesys.h"
+#include "autoconf.h"
+#include "compiler.h"
+#include "fsusage.h"
+#include "native2amiga.h"
+#include "scsidev.h"
+#include "fsdb.h"
+#include "zfile.h"
+#include "gui.h"
+
+#define TRACING_ENABLED 0
+#if TRACING_ENABLED
+#define TRACE(x)       do { write_log x; } while(0)
+#define DUMPLOCK(u,x)  dumplock(u,x)
+#else
+#define TRACE(x)
+#define DUMPLOCK(u,x)
+#endif
+
+void xfree (void *p)
+{
+    free (p);
+}
+
+static void aino_test (a_inode *aino)
+{
+#ifdef AINO_DEBUG
+    a_inode *aino2 = aino, *aino3;
+    for (;;) {
+        if (!aino || !aino->next)
+           return;
+       if ((aino->checksum1 ^ aino->checksum2) != 0xaaaa5555) {
+           write_log ("PANIC: corrupted or freed but used aino detected!", aino);
+       }
+       aino3 = aino;
+       aino = aino->next;
+       if (aino->prev != aino3) {
+           write_log ("PANIC: corrupted aino linking!\n");
+           break;
+       }
+       if (aino == aino2) break;
+    }
+#endif
+}
+
+static void aino_test_init (a_inode *aino)
+{
+#ifdef AINO_DEBUG
+    aino->checksum1 = (uae_u32)aino;
+    aino->checksum2 = aino->checksum1 ^ 0xaaaa5555;
+#endif
+}
+
+static long dos_errno(void)
+{
+    int e = errno;
+
+    switch (e) {
+     case ENOMEM:      return ERROR_NO_FREE_STORE;
+     case EEXIST:      return ERROR_OBJECT_EXISTS;
+     case EACCES:      return ERROR_WRITE_PROTECTED;
+     case ENOENT:      return ERROR_OBJECT_NOT_AROUND;
+     case ENOTDIR:     return ERROR_OBJECT_WRONG_TYPE;
+     case ENOSPC:      return ERROR_DISK_IS_FULL;
+     case EBUSY:               return ERROR_OBJECT_IN_USE;
+     case EISDIR:      return ERROR_OBJECT_WRONG_TYPE;
+#if defined(ETXTBSY)
+     case ETXTBSY:     return ERROR_OBJECT_IN_USE;
+#endif
+#if defined(EROFS)
+     case EROFS:               return ERROR_DISK_WRITE_PROTECTED;
+#endif
+#if defined(ENOTEMPTY)
+#if ENOTEMPTY != EEXIST
+     case ENOTEMPTY:   return ERROR_DIRECTORY_NOT_EMPTY;
+#endif
+#endif
+
+     default:
+       TRACE(("Unimplemented error %s\n", strerror(e)));
+       return ERROR_NOT_IMPLEMENTED;
+    }
+}
+
+/*
+ * This _should_ be no issue for us, but let's rather use a guaranteed
+ * thread safe function if we have one.
+ * This used to be broken in glibc versions <= 2.0.1 (I think). I hope
+ * no one is using this these days.
+ * Michael Krause says it's also broken in libc5. ARRRGHHHHHH!!!!
+ */
+#if 0 && defined HAVE_READDIR_R
+
+static struct dirent *my_readdir (DIR *dirstream, struct dirent *space)
+{
+    struct dirent *loc;
+    if (readdir_r (dirstream, space, &loc) == 0) {
+       /* Success */
+       return loc;
+    }
+    return 0;
+}
+
+#else
+#define my_readdir(dirstream, space) readdir(dirstream)
+#endif
+
+uaecptr filesys_initcode;
+static uae_u32 fsdevname, filesys_configdev;
+
+#define FS_STARTUP 0
+#define FS_GO_DOWN 1
+
+#define DEVNAMES_PER_HDF 32
+
+typedef struct {
+    char *devname; /* device name, e.g. UAE0: */
+    uaecptr devname_amiga;
+    uaecptr startup;
+    char *volname; /* volume name, e.g. CDROM, WORK, etc. */
+    char *rootdir; /* root unix directory */
+    int readonly; /* disallow write access? */
+    int bootpri; /* boot priority */
+    int devno;
+    
+    struct hardfiledata hf;
+
+    /* Threading stuff */
+    smp_comm_pipe *volatile unit_pipe, *volatile back_pipe;
+    uae_thread_id tid;
+    struct _unit *self;
+    /* Reset handling */
+    volatile uae_sem_t reset_sync_sem;
+    volatile int reset_state;
+
+    /* RDB stuff */
+    uaecptr rdb_devname_amiga[DEVNAMES_PER_HDF];
+    int rdb_lowcyl;
+    int rdb_highcyl;
+    int rdb_cylblocks;
+    uae_u8 *rdb_filesysstore;
+    int rdb_filesyssize;
+    char *filesysdir;
+
+
+} UnitInfo;
+
+struct uaedev_mount_info {
+    int num_units;
+    UnitInfo ui[MAX_FILESYSTEM_UNITS];
+};
+
+static struct uaedev_mount_info *current_mountinfo;
+
+int nr_units (struct uaedev_mount_info *mountinfo)
+{
+    return mountinfo->num_units;
+}
+
+int is_hardfile (struct uaedev_mount_info *mountinfo, int unit_no)
+{
+    if (mountinfo->ui[unit_no].volname)
+       return FILESYS_VIRTUAL;
+    if (mountinfo->ui[unit_no].hf.secspertrack == 0) {
+       if (mountinfo->ui[unit_no].hf.flags & 1)
+           return FILESYS_HARDDRIVE;
+       return FILESYS_HARDFILE_RDB;
+    }
+    return FILESYS_HARDFILE;
+}
+
+static void close_filesys_unit (UnitInfo *uip)
+{
+    if (uip->hf.handle != 0)
+       hdf_close (&uip->hf);
+    if (uip->volname != 0)
+       xfree (uip->volname);
+    if (uip->devname != 0)
+       xfree (uip->devname);
+    if (uip->rootdir != 0)
+       xfree (uip->rootdir);
+    if (uip->unit_pipe)
+       xfree (uip->unit_pipe);
+    if (uip->back_pipe)
+       xfree (uip->back_pipe);
+
+    uip->unit_pipe = 0;
+    uip->back_pipe = 0;
+
+    uip->hf.handle = 0;
+    uip->volname = 0;
+    uip->devname = 0;
+    uip->rootdir = 0;
+}
+
+char *get_filesys_unit (struct uaedev_mount_info *mountinfo, int nr,
+                       char **devname, char **volname, char **rootdir, int *readonly,
+                       int *secspertrack, int *surfaces, int *reserved,
+                       int *cylinders, uae_u64 *size, int *blocksize, int *bootpri, char **filesysdir)
+{
+    UnitInfo *uip = mountinfo->ui + nr;
+
+    if (nr >= mountinfo->num_units)
+       return "No slot allocated for this unit";
+    
+    *volname = uip->volname ? my_strdup (uip->volname) : 0;
+    if (uip->devname == 0 || strlen(uip->devname) == 0) {
+       *devname = xmalloc (10);
+       sprintf (*devname, "DH%d", nr);
+    } else {
+       *devname = my_strdup (uip->devname);
+    }
+    *rootdir = uip->rootdir ? my_strdup (uip->rootdir) : 0;
+    *readonly = uip->readonly;
+    *secspertrack = uip->hf.secspertrack;
+    *surfaces = uip->hf.surfaces;
+    *reserved = uip->hf.reservedblocks;
+    *cylinders = uip->hf.nrcyls;
+    *blocksize = uip->hf.blocksize;
+    *size = uip->hf.size;
+    *bootpri = uip->bootpri;
+    if (filesysdir)
+       *filesysdir = uip->filesysdir ? my_strdup (uip->filesysdir) : 0;
+    return 0;
+}
+
+static char *set_filesys_unit_1 (struct uaedev_mount_info *mountinfo, int nr,
+                                char *devname, char *volname, char *rootdir, int readonly,
+                                int secspertrack, int surfaces, int reserved,
+                                int blocksize, int bootpri, char *filesysdir)
+{
+    UnitInfo *ui = mountinfo->ui + nr;
+    int v;
+    static char errmsg[1024];
+
+    if (nr >= mountinfo->num_units)
+       return "No slot allocated for this unit";
+
+    ui->devname = 0;
+    ui->volname = 0;
+    ui->rootdir = 0;
+    ui->unit_pipe = 0;
+    ui->back_pipe = 0;
+    ui->hf.handle = 0;
+    ui->bootpri = 0;
+    ui->filesysdir = 0;
+
+    if (volname != 0) {
+        struct stat statbuf;
+       memset (&statbuf, 0, sizeof (statbuf));
+       ui->volname = my_strdup (volname);
+       v = isspecialdrive (rootdir);
+       if (v < 0) {
+           sprintf (errmsg, "invalid drive '%s'", rootdir);
+           return errmsg;
+       }
+       if (v == 0) {
+            if (stat (rootdir, &statbuf) < 0) {
+               sprintf (errmsg, "directory '%s' not found", rootdir);
+               return errmsg;
+           }
+           if (!(statbuf.st_mode & FILEFLAG_WRITE)) {
+               write_log ("'%s' set to read-only\n", rootdir);
+               readonly = 1;
+           }
+       }
+    } else {
+       ui->hf.secspertrack = secspertrack;
+       ui->hf.surfaces = surfaces;
+       ui->hf.reservedblocks = reserved;
+       ui->hf.blocksize = blocksize;
+       ui->volname = 0;
+       ui->hf.readonly = readonly;
+       if (!hdf_open (&ui->hf, rootdir) && !readonly) {
+           ui->hf.readonly = readonly = 1;
+           hdf_open (&ui->hf, rootdir);
+       }
+        ui->hf.readonly = readonly;
+       if (ui->hf.handle == 0)
+           return "Hardfile not found";
+
+       if ((blocksize & (blocksize - 1)) != 0)
+           return "Bad blocksize";
+       if ((secspertrack || surfaces || reserved) &&
+           (secspertrack < 1 || surfaces < 1 || surfaces > 1023 || reserved < 0 || reserved > 1023) != 0)
+       {
+           return "Bad hardfile geometry";
+       }
+       ui->hf.nrcyls = (int)(secspertrack * surfaces ? (ui->hf.size / blocksize) / (secspertrack * surfaces) : 0);
+    }
+    ui->self = 0;
+    ui->reset_state = FS_STARTUP;
+    ui->rootdir = my_strdup (rootdir);
+    ui->devname = my_strdup (devname);
+    if (filesysdir)
+       ui->filesysdir = my_strdup (filesysdir);
+    ui->readonly = readonly;
+    if (bootpri < -128) bootpri = -128;
+    if (bootpri > 127) bootpri = 127;
+    ui->bootpri = bootpri;
+
+    return 0;
+}
+
+char *set_filesys_unit (struct uaedev_mount_info *mountinfo, int nr,
+                       char *devname, char *volname, char *rootdir, int readonly,
+                       int secspertrack, int surfaces, int reserved,
+                       int blocksize, int bootpri, char *filesysdir)
+{
+    char *result;
+    UnitInfo ui = mountinfo->ui[nr];
+
+    hdf_close (&ui.hf);
+    result = set_filesys_unit_1 (mountinfo, nr, devname, volname, rootdir, readonly,
+                                      secspertrack, surfaces, reserved, blocksize, bootpri, filesysdir);
+    if (result)
+       mountinfo->ui[nr] = ui;
+    else
+       close_filesys_unit (&ui);
+
+    return result;
+}
+
+char *add_filesys_unit (struct uaedev_mount_info *mountinfo,
+                       char *devname, char *volname, char *rootdir, int readonly,
+                       int secspertrack, int surfaces, int reserved,
+                       int blocksize, int bootpri, char *filesysdir)
+{
+    char *retval;
+    int nr = mountinfo->num_units;
+    UnitInfo *uip = mountinfo->ui + nr;
+
+    if (nr >= MAX_FILESYSTEM_UNITS)
+       return "Maximum number of file systems mounted";
+
+    mountinfo->num_units++;
+    retval = set_filesys_unit_1 (mountinfo, nr, devname, volname, rootdir, readonly,
+                                secspertrack, surfaces, reserved, blocksize, bootpri, filesysdir);
+    if (retval)
+       mountinfo->num_units--;
+    return retval;
+}
+
+int kill_filesys_unit (struct uaedev_mount_info *mountinfo, int nr)
+{
+    UnitInfo *uip = mountinfo->ui;
+    if (nr >= mountinfo->num_units || nr < 0)
+       return -1;
+
+    close_filesys_unit (mountinfo->ui + nr);
+
+    mountinfo->num_units--;
+    for (; nr < mountinfo->num_units; nr++) {
+       uip[nr] = uip[nr+1];
+    }
+    return 0;
+}
+
+int move_filesys_unit (struct uaedev_mount_info *mountinfo, int nr, int to)
+{
+    UnitInfo tmpui;
+    UnitInfo *uip = mountinfo->ui;
+
+    if (nr >= mountinfo->num_units || nr < 0
+       || to >= mountinfo->num_units || to < 0
+       || to == nr)
+       return -1;
+    tmpui = uip[nr];
+    if (to > nr) {
+       int i;
+       for (i = nr; i < to; i++)
+           uip[i] = uip[i + 1];
+    } else {
+       int i;
+       for (i = nr; i > to; i--)
+           uip[i] = uip[i - 1];
+    }
+    uip[to] = tmpui;
+    return 0;
+}
+
+int sprintf_filesys_unit (struct uaedev_mount_info *mountinfo, char *buffer, int num)
+{
+    UnitInfo *uip = mountinfo->ui;
+    if (num >= mountinfo->num_units)
+       return -1;
+
+    if (uip[num].volname != 0)
+       sprintf (buffer, "(DH%d:) Filesystem, %s: %s %s", num, uip[num].volname,
+                uip[num].rootdir, uip[num].readonly ? "ro" : "");
+    else
+       sprintf (buffer, "(DH%d:) Hardfile, \"%s\", size %d Mbytes", num,
+       uip[num].rootdir, uip[num].hf.size / (1024 * 1024));
+    return 0;
+}
+
+void write_filesys_config (struct uaedev_mount_info *mountinfo,
+                          const char *unexpanded, const char *default_path, FILE *f)
+{
+    UnitInfo *uip = mountinfo->ui;
+    int i;
+
+    for (i = 0; i < mountinfo->num_units; i++) {
+       char *str;
+       str = cfgfile_subst_path (default_path, unexpanded, uip[i].rootdir);
+       if (uip[i].volname != 0) {
+           fprintf (f, "filesystem2=%s,%s:%s:%s,%d\n", uip[i].readonly ? "ro" : "rw",
+               uip[i].devname ? uip[i].devname : "", uip[i].volname, str, uip[i].bootpri);
+           fprintf (f, "filesystem=%s,%s:%s\n", uip[i].readonly ? "ro" : "rw",
+               uip[i].volname, str);
+       } else {
+           fprintf (f, "hardfile2=%s,%s:%s,%d,%d,%d,%d,%d,%s\n",
+                    uip[i].readonly ? "ro" : "rw",
+                    uip[i].devname ? uip[i].devname : "", str,
+                    uip[i].hf.secspertrack, uip[i].hf.surfaces, uip[i].hf.reservedblocks, uip[i].hf.blocksize,
+                    uip[i].bootpri,uip[i].filesysdir ? uip[i].filesysdir : "");
+           fprintf (f, "hardfile=%s,%d,%d,%d,%d,%s\n",
+                    uip[i].readonly ? "ro" : "rw", uip[i].hf.secspertrack,
+                    uip[i].hf.surfaces, uip[i].hf.reservedblocks, uip[i].hf.blocksize, str);
+       }
+       xfree (str);
+    }
+}
+
+struct uaedev_mount_info *alloc_mountinfo (void)
+{
+    struct uaedev_mount_info *info;
+    info = malloc (sizeof *info);
+    memset (info, 0, sizeof *info);
+    info->num_units = 0;
+    return info;
+}
+
+struct uaedev_mount_info *dup_mountinfo (struct uaedev_mount_info *mip)
+{
+    int i;
+    struct uaedev_mount_info *i2 = alloc_mountinfo ();
+
+    memcpy (i2, mip, sizeof *i2);
+
+    for (i = 0; i < i2->num_units; i++) {
+       UnitInfo *uip = i2->ui + i;
+       if (uip->volname)
+           uip->volname = my_strdup (uip->volname);
+       if (uip->devname)
+           uip->devname = my_strdup (uip->devname);
+       if (uip->rootdir)
+           uip->rootdir = my_strdup (uip->rootdir);
+       if (uip->hf.handle)
+           hdf_dup (&uip->hf, uip->hf.handle);
+    }
+    return i2;
+}
+
+void free_mountinfo (struct uaedev_mount_info *mip)
+{
+    int i;
+    if (!mip)
+       return;
+    for (i = 0; i < mip->num_units; i++)
+       close_filesys_unit (mip->ui + i);
+    xfree (mip);
+}
+
+struct hardfiledata *get_hardfile_data (int nr)
+{
+    UnitInfo *uip = current_mountinfo->ui;
+    if (nr < 0 || nr >= current_mountinfo->num_units || uip[nr].volname != 0)
+       return 0;
+    return &uip[nr].hf;
+}
+
+/* minimal AmigaDOS definitions */
+
+/* field offsets in DosPacket */
+#define dp_Type 8
+#define dp_Res1        12
+#define dp_Res2 16
+#define dp_Arg1 20
+#define dp_Arg2 24
+#define dp_Arg3 28
+#define dp_Arg4 32
+
+/* result codes */
+#define DOS_TRUE ((unsigned long)-1L)
+#define DOS_FALSE (0L)
+
+/* Passed as type to Lock() */
+#define SHARED_LOCK         -2     /* File is readable by others */
+#define ACCESS_READ         -2     /* Synonym */
+#define EXCLUSIVE_LOCK      -1     /* No other access allowed    */
+#define ACCESS_WRITE        -1     /* Synonym */
+
+/* packet types */
+#define ACTION_CURRENT_VOLUME  7
+#define ACTION_LOCATE_OBJECT   8
+#define ACTION_RENAME_DISK     9
+#define ACTION_FREE_LOCK       15
+#define ACTION_DELETE_OBJECT   16
+#define ACTION_RENAME_OBJECT   17
+#define ACTION_COPY_DIR                19
+#define ACTION_SET_PROTECT     21
+#define ACTION_CREATE_DIR      22
+#define ACTION_EXAMINE_OBJECT  23
+#define ACTION_EXAMINE_NEXT    24
+#define ACTION_DISK_INFO       25
+#define ACTION_INFO            26
+#define ACTION_FLUSH           27
+#define ACTION_SET_COMMENT     28
+#define ACTION_PARENT          29
+#define ACTION_SET_DATE                34
+#define ACTION_FIND_WRITE      1004
+#define ACTION_FIND_INPUT      1005
+#define ACTION_FIND_OUTPUT     1006
+#define ACTION_END             1007
+#define ACTION_SEEK            1008
+#define ACTION_IS_FILESYSTEM   1027
+#define ACTION_READ            'R'
+#define ACTION_WRITE           'W'
+
+/* 2.0+ packet types */
+#define ACTION_INHIBIT       31
+#define ACTION_SET_FILE_SIZE 1022
+#define ACTION_LOCK_RECORD   2008
+#define ACTION_FREE_RECORD   2009
+#define ACTION_SAME_LOCK     40
+#define ACTION_CHANGE_MODE   1028
+#define ACTION_FH_FROM_LOCK  1026
+#define ACTION_COPY_DIR_FH   1030
+#define ACTION_PARENT_FH     1031
+#define ACTION_EXAMINE_FH    1034
+#define ACTION_EXAMINE_ALL   1033
+#define ACTION_MAKE_LINK     1021
+#define ACTION_READ_LINK     1024
+#define ACTION_FORMAT        1020
+#define ACTION_IS_FILESYSTEM 1027
+#define ACTION_ADD_NOTIFY    4097
+#define ACTION_REMOVE_NOTIFY 4098
+
+#define DISK_TYPE              0x444f5301 /* DOS\1 */
+
+typedef struct {
+    uae_u32 uniq;
+    /* The directory we're going through.  */
+    a_inode *aino;
+    /* The file we're going to look up next.  */
+    a_inode *curr_file;
+} ExamineKey;
+
+typedef struct key {
+    struct key *next;
+    a_inode *aino;
+    uae_u32 uniq;
+    int fd;
+    off_t file_pos;
+    int dosmode;
+    int createmode;
+    int notifyactive;
+} Key;
+
+typedef struct notify {
+    struct notify *next;
+    uaecptr notifyrequest;
+    char *fullname;
+    char *partname;
+} Notify;
+
+/* Since ACTION_EXAMINE_NEXT is so braindamaged, we have to keep
+ * some of these around
+ */
+
+#define EXKEYS 100
+#define MAX_AINO_HASH 128
+#define NOTIFY_HASH_SIZE 127
+
+/* handler state info */
+
+typedef struct _unit {
+    struct _unit *next;
+
+    /* Amiga stuff */
+    uaecptr dosbase;
+    uaecptr volume;
+    uaecptr port;      /* Our port */
+    uaecptr locklist;
+
+    /* Native stuff */
+    uae_s32 unit;      /* unit number */
+    UnitInfo ui;       /* unit startup info */
+    char tmpbuf3[256];
+
+    /* Dummy message processing */
+    uaecptr dummy_message;
+    volatile unsigned int cmds_sent;
+    volatile unsigned int cmds_complete;
+    volatile unsigned int cmds_acked;
+
+    /* ExKeys */
+    ExamineKey examine_keys[EXKEYS];
+    int next_exkey;
+    unsigned long total_locked_ainos;
+
+    /* Keys */
+    struct key *keys;
+    uae_u32 key_uniq;
+    uae_u32 a_uniq;
+
+    a_inode rootnode;
+    unsigned long aino_cache_size;
+    a_inode *aino_hash[MAX_AINO_HASH];
+    unsigned long nr_cache_hits;
+    unsigned long nr_cache_lookups;
+
+    struct notify *notifyhash[NOTIFY_HASH_SIZE];
+
+} Unit;
+
+typedef uae_u8 *dpacket;
+#define PUT_PCK_RES1(p,v) do { do_put_mem_long ((uae_u32 *)((p) + dp_Res1), (v)); } while (0)
+#define PUT_PCK_RES2(p,v) do { do_put_mem_long ((uae_u32 *)((p) + dp_Res2), (v)); } while (0)
+#define GET_PCK_TYPE(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Type))))
+#define GET_PCK_RES1(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Res1))))
+#define GET_PCK_RES2(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Res2))))
+#define GET_PCK_ARG1(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg1))))
+#define GET_PCK_ARG2(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg2))))
+#define GET_PCK_ARG3(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg3))))
+#define GET_PCK_ARG4(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg4))))
+
+static char *char1 (uaecptr addr)
+{
+    static char buf[1024];
+    int i = 0;
+    do {
+       buf[i] = get_byte(addr);
+       addr++;
+    } while (buf[i++] && i < sizeof(buf));
+    return buf;
+}
+
+static char *bstr1 (uaecptr addr)
+{
+    static char buf[256];
+    int i;
+    int n = get_byte(addr);
+    addr++;
+
+    for (i = 0; i < n; i++, addr++)
+       buf[i] = get_byte(addr);
+    buf[i] = 0;
+    return buf;
+}
+
+static char *bstr (Unit *unit, uaecptr addr)
+{
+    int i;
+    int n = get_byte(addr);
+
+    addr++;
+    for (i = 0; i < n; i++, addr++)
+       unit->tmpbuf3[i] = get_byte(addr);
+    unit->tmpbuf3[i] = 0;
+    return unit->tmpbuf3;
+}
+
+static char *bstr_cut (Unit *unit, uaecptr addr)
+{
+    char *p = unit->tmpbuf3;
+    int i, colon_seen = 0;
+    int n = get_byte (addr);
+
+    addr++;
+    for (i = 0; i < n; i++, addr++) {
+       uae_u8 c = get_byte(addr);
+       unit->tmpbuf3[i] = c;
+       if (c == '/' || (c == ':' && colon_seen++ == 0))
+           p = unit->tmpbuf3 + i + 1;
+    }
+    unit->tmpbuf3[i] = 0;
+    return p;
+}
+
+static Unit *units = 0;
+static int unit_num = 0;
+
+static Unit*
+find_unit (uaecptr port)
+{
+    Unit* u;
+    for (u = units; u; u = u->next)
+       if (u->port == port)
+           break;
+
+    return u;
+}
+    
+static void prepare_for_open (char *name)
+{
+#if 0
+    struct stat statbuf;
+    int mode;
+
+    if (-1 == stat (name, &statbuf))
+       return;
+
+    mode = statbuf.st_mode;
+    mode |= S_IRUSR;
+    mode |= S_IWUSR;
+    mode |= S_IXUSR;
+    chmod (name, mode);
+#endif
+}
+
+static void de_recycle_aino (Unit *unit, a_inode *aino)
+{
+    aino_test (aino);
+    if (aino->next == 0 || aino == &unit->rootnode)
+       return;
+    aino->next->prev = aino->prev;
+    aino->prev->next = aino->next;
+    aino->next = aino->prev = 0;
+    unit->aino_cache_size--;
+}
+
+static void dispose_aino (Unit *unit, a_inode **aip, a_inode *aino)
+{
+    int hash = aino->uniq % MAX_AINO_HASH;
+    if (unit->aino_hash[hash] == aino)
+       unit->aino_hash[hash] = 0;
+
+    if (aino->dirty && aino->parent)
+       fsdb_dir_writeback (aino->parent);
+
+    *aip = aino->sibling;
+    xfree (aino->aname);
+    if (aino->comment)
+       xfree (aino->comment);
+    xfree (aino->nname);
+    xfree (aino);
+}
+
+static void recycle_aino (Unit *unit, a_inode *new_aino)
+{
+    aino_test (new_aino);
+    if (new_aino->dir || new_aino->shlock > 0
+       || new_aino->elock || new_aino == &unit->rootnode)
+       /* Still in use */
+       return;
+
+    TRACE (("Recycling; cache size %d, total_locked %d\n",
+           unit->aino_cache_size, unit->total_locked_ainos));
+    if (unit->aino_cache_size > 5000 + unit->total_locked_ainos) {
+       /* Reap a few. */
+       int i = 0;
+       while (i < 50) {
+           a_inode *parent = unit->rootnode.prev->parent;
+           a_inode **aip;
+           aip = &parent->child;
+
+           aino_test (parent);
+           if (! parent->locked_children) {
+               for (;;) {
+                   a_inode *aino = *aip;
+                   aino_test (aino);
+                   if (aino == 0)
+                       break;
+                   /* Not recyclable if next == 0 (i.e., not chained into
+                      recyclable list), or if parent directory is being
+                      ExNext()ed.  */
+                   if (aino->next == 0) {
+                       aip = &aino->sibling;
+                   } else {
+                       if (aino->shlock > 0 || aino->elock)
+                           write_log ("panic: freeing locked a_inode!\n");
+
+                       de_recycle_aino (unit, aino);
+                       dispose_aino (unit, aip, aino);
+                       i++;
+                   }
+               }
+           }
+           /* In the previous loop, we went through all children of one
+              parent.  Re-arrange the recycled list so that we'll find a
+              different parent the next time around.  */
+           do {
+               unit->rootnode.next->prev = unit->rootnode.prev;
+               unit->rootnode.prev->next = unit->rootnode.next;
+               unit->rootnode.next = unit->rootnode.prev;
+               unit->rootnode.prev = unit->rootnode.prev->prev;
+               unit->rootnode.prev->next = unit->rootnode.next->prev = &unit->rootnode;
+           } while (unit->rootnode.prev->parent == parent);
+       }
+#if 0
+       {
+           char buffer[40];
+           sprintf (buffer, "%d ainos reaped.\n", i);
+           TRACE ((buffer));
+       }
+#endif
+    }
+
+    aino_test (new_aino);
+    /* Chain it into circular list. */
+    new_aino->next = unit->rootnode.next;
+    new_aino->prev = &unit->rootnode;
+    new_aino->prev->next = new_aino;
+    new_aino->next->prev = new_aino;
+    aino_test (new_aino->next);
+    aino_test (new_aino->prev);
+
+    unit->aino_cache_size++;
+}
+
+static void update_child_names (Unit *unit, a_inode *a, a_inode *parent)
+{
+    int l0 = strlen (parent->nname) + 2;
+
+    while (a != 0) {
+       char *name_start;
+       char *new_name;
+       char dirsep[2] = { FSDB_DIR_SEPARATOR, '\0' };
+         
+       a->parent = parent;
+       name_start = strrchr (a->nname, FSDB_DIR_SEPARATOR);
+       if (name_start == 0) {
+           write_log ("malformed file name");
+       }
+       name_start++;
+       new_name = (char *)xmalloc (strlen (name_start) + l0);
+       strcpy (new_name, parent->nname);
+       strcat (new_name, dirsep);
+       strcat (new_name, name_start);
+       xfree (a->nname);
+       a->nname = new_name;
+       if (a->child)
+           update_child_names (unit, a->child, a);
+       a = a->sibling;
+    }
+}
+
+static void move_aino_children (Unit *unit, a_inode *from, a_inode *to)
+{
+    aino_test (from);
+    aino_test (to);
+    to->child = from->child;
+    from->child = 0;
+    update_child_names (unit, to->child, to);
+}
+
+static void delete_aino (Unit *unit, a_inode *aino)
+{
+    a_inode **aip;
+
+    TRACE(("deleting aino %x\n", aino->uniq));
+
+    aino_test (aino);
+    aino->dirty = 1;
+    aino->deleted = 1;
+    de_recycle_aino (unit, aino);
+
+    /* If any ExKeys are currently pointing at us, advance them.  */
+    if (aino->parent->exnext_count > 0) {
+       int i;
+       TRACE(("entering exkey validation\n"));
+       for (i = 0; i < EXKEYS; i++) {
+           ExamineKey *k = unit->examine_keys + i;
+           if (k->uniq == 0)
+               continue;
+           if (k->aino == aino->parent) {
+               TRACE(("Same parent found for %d\n", i));
+               if (k->curr_file == aino) {
+                   k->curr_file = aino->sibling;
+                   TRACE(("Advancing curr_file\n"));
+               }
+           }
+       }
+    }
+
+    aip = &aino->parent->child;
+    while (*aip != aino && *aip != 0)
+       aip = &(*aip)->sibling;
+    if (*aip != aino) {
+       write_log ("Couldn't delete aino.\n");
+       return;
+    }
+    dispose_aino (unit, aip, aino);
+}
+
+static a_inode *lookup_sub (a_inode *dir, uae_u32 uniq)
+{
+    a_inode **cp = &dir->child;
+    a_inode *c, *retval;
+
+    for (;;) {
+       c = *cp;
+       if (c == 0)
+           return 0;
+
+       if (c->uniq == uniq) {
+           retval = c;
+           break;
+       }
+       if (c->dir) {
+           a_inode *a = lookup_sub (c, uniq);
+           if (a != 0) {
+               retval = a;
+               break;
+           }
+       }
+       cp = &c->sibling;
+    }
+    if (! dir->locked_children) {
+       /* Move to the front to speed up repeated lookups.  Don't do this if
+          an ExNext is going on in this directory, or we'll terminally
+          confuse it.  */
+       *cp = c->sibling;
+       c->sibling = dir->child;
+       dir->child = c;
+    }
+    return retval;
+}
+
+static a_inode *lookup_aino (Unit *unit, uae_u32 uniq)
+{
+    a_inode *a;
+    int hash = uniq % MAX_AINO_HASH;
+
+    if (uniq == 0)
+       return &unit->rootnode;
+    a = unit->aino_hash[hash];
+    if (a == 0 || a->uniq != uniq)
+       a = lookup_sub (&unit->rootnode, uniq);
+    else
+       unit->nr_cache_hits++;
+    unit->nr_cache_lookups++;
+    unit->aino_hash[hash] = a;
+    aino_test (a);
+    return a;
+}
+
+char *build_nname (const char *d, const char *n)
+{
+    char dsep[2] = { FSDB_DIR_SEPARATOR, '\0' };
+    char *p = (char *) xmalloc (strlen (d) + strlen (n) + 2);
+    strcpy (p, d);
+    strcat (p, dsep);
+    strcat (p, n);
+    return p;
+}
+
+char *build_aname (const char *d, const char *n)
+{
+    char *p = (char *) xmalloc (strlen (d) + strlen (n) + 2);
+    strcpy (p, d);
+    strcat (p, "/");
+    strcat (p, n);
+    return p;
+}
+
+/* This gets called to translate an Amiga name that some program used to
+ * a name that we can use on the native filesystem.  */
+static char *get_nname (Unit *unit, a_inode *base, char *rel,
+                       char **modified_rel)
+{
+    char *found;
+    char *p = 0;
+
+    aino_test (base);
+
+    *modified_rel = 0;
+    
+    /* If we have a mapping of some other aname to "rel", we must pretend
+     * it does not exist.
+     * This can happen for example if an Amiga program creates a
+     * file called ".".  We can't represent this in our filesystem,
+     * so we create a special file "uae_xxx" and record the mapping
+     * aname "." -> nname "uae_xxx" in the database.  Then, the Amiga
+     * program looks up "uae_xxx" (yes, it's contrived).  The filesystem
+     * should not make the uae_xxx file visible to the Amiga side.  */
+    if (fsdb_used_as_nname (base, rel))
+       return 0;
+    /* A file called "." (or whatever else is invalid on this filesystem)
+       * does not exist, as far as the Amiga side is concerned.  */
+    if (fsdb_name_invalid (rel))
+       return 0;
+
+    /* See if we have a file that has the same name as the aname we are
+     * looking for.  */
+    found = fsdb_search_dir (base->nname, rel);
+    if (found == 0)
+       return found;
+    if (found == rel)
+       return build_nname (base->nname, rel);
+
+    *modified_rel = found;
+    return build_nname (base->nname, found);
+}
+
+static char *create_nname (Unit *unit, a_inode *base, char *rel)
+{
+    char *p;
+
+    aino_test (base);
+    /* We are trying to create a file called REL.  */
+    
+    /* If the name is used otherwise in the directory (or globally), we
+     * need a new unique nname.  */
+    if (fsdb_name_invalid (rel) || fsdb_used_as_nname (base, rel)) {
+#if 0
+       oh_dear:
+#endif
+       if (currprefs.filesys_no_uaefsdb) {
+           write_log ("illegal filename '%s' and uaefsdb disabled\n", rel);
+           return 0;
+       }
+       p = fsdb_create_unique_nname (base, rel);
+       return p;
+    }
+    p = build_nname (base->nname, rel);
+#if 0
+    /* Delete this code once we know everything works.  */
+    if (access (p, R_OK) >= 0 || errno != ENOENT) {
+       write_log ("Filesystem in trouble... please report.\n");
+       xfree (p);
+       goto oh_dear;
+    }
+#endif
+    return p;
+}
+
+/*
+ * This gets called if an ACTION_EXAMINE_NEXT happens and we hit an object
+ * for which we know the name on the native filesystem, but no corresponding
+ * Amiga filesystem name.
+ * @@@ For DOS filesystems, it might make sense to declare the new name
+ * "weak", so that it can get overriden by a subsequent call to get_nname().
+ * That way, if someone does "dir :" and there is a file "foobar.inf", and
+ * someone else tries to open "foobar.info", get_nname() could maybe made to
+ * figure out that this is supposed to be the file "foobar.inf".
+ * DOS sucks...
+ */
+static char *get_aname (Unit *unit, a_inode *base, char *rel)
+{
+    return my_strdup (rel);
+}
+
+static void init_child_aino (Unit *unit, a_inode *base, a_inode *aino)
+{
+    aino->uniq = ++unit->a_uniq;
+    if (unit->a_uniq == 0xFFFFFFFF) {
+       write_log ("Running out of a_inodes (prepare for big trouble)!\n");
+    }
+    aino->shlock = 0;
+    aino->elock = 0;
+
+    aino->dirty = 0;
+    aino->deleted = 0;
+
+    /* For directories - this one isn't being ExNext()ed yet.  */
+    aino->locked_children = 0;
+    aino->exnext_count = 0;
+    /* But the parent might be.  */
+    if (base->exnext_count) {
+       unit->total_locked_ainos++;
+       base->locked_children++;
+    }
+    /* Update tree structure */
+    aino->parent = base;
+    aino->child = 0;
+    aino->sibling = base->child;
+    base->child = aino;
+    aino->next = aino->prev = 0;
+
+    aino_test_init (aino);
+    aino_test (aino);
+}
+
+static a_inode *new_child_aino (Unit *unit, a_inode *base, char *rel)
+{
+    char *modified_rel;
+    char *nn;
+    a_inode *aino;
+
+    TRACE(("new_child_aino %s, %s\n", base->aname, rel));
+
+    aino = fsdb_lookup_aino_aname (base, rel);
+    if (aino == 0) {
+       nn = get_nname (unit, base, rel, &modified_rel);
+       if (nn == 0)
+           return 0;
+
+       aino = (a_inode *) xcalloc (sizeof (a_inode), 1);
+       if (aino == 0)
+           return 0;
+       aino->aname = modified_rel ? modified_rel : my_strdup (rel);
+       aino->nname = nn;
+
+       aino->comment = 0;
+       aino->has_dbentry = 0;
+
+       fsdb_fill_file_attrs (aino);
+       if (aino->dir)
+           fsdb_clean_dir (aino);
+    }
+    init_child_aino (unit, base, aino);
+
+    recycle_aino (unit, aino);
+    TRACE(("created aino %x, lookup, amigaos_mode %d\n", aino->uniq, aino->amigaos_mode));
+    return aino;
+}
+
+static a_inode *create_child_aino (Unit *unit, a_inode *base, char *rel, int isdir)
+{
+    a_inode *aino = (a_inode *) xcalloc (sizeof (a_inode), 1);
+    if (aino == 0)
+       return 0;
+
+    aino->nname = create_nname (unit, base, rel);
+    if (!aino->nname) {
+       free (aino);
+       return 0;
+    }
+    aino->aname = my_strdup (rel);
+
+    init_child_aino (unit, base, aino);
+    aino->amigaos_mode = 0;
+    aino->dir = isdir;
+
+    aino->comment = 0;
+    aino->has_dbentry = 0;
+    aino->dirty = 1;
+
+    recycle_aino (unit, aino);
+    TRACE(("created aino %x, create\n", aino->uniq));
+    return aino;
+}
+
+static a_inode *lookup_child_aino (Unit *unit, a_inode *base, char *rel, uae_u32 *err)
+{
+    a_inode *c = base->child;
+    int l0 = strlen (rel);
+
+    aino_test (base);
+    aino_test (c);
+
+    if (base->dir == 0) {
+       *err = ERROR_OBJECT_WRONG_TYPE;
+       return 0;
+    }
+
+    while (c != 0) {
+       int l1 = strlen (c->aname);
+       if (l0 <= l1 && same_aname (rel, c->aname + l1 - l0)
+           && (l0 == l1 || c->aname[l1-l0-1] == '/'))
+           break;
+       c = c->sibling;
+    }
+    if (c != 0)
+       return c;
+    c = new_child_aino (unit, base, rel);
+    if (c == 0)
+       *err = ERROR_OBJECT_NOT_AROUND;
+    return c;
+}
+
+/* Different version because for this one, REL is an nname.  */
+static a_inode *lookup_child_aino_for_exnext (Unit *unit, a_inode *base, char *rel, uae_u32 *err)
+{
+    a_inode *c = base->child;
+    int l0 = strlen (rel);
+
+    aino_test (base);
+    aino_test (c);
+
+    *err = 0;
+    while (c != 0) {
+       int l1 = strlen (c->nname);
+       /* Note: using strcmp here.  */
+       if (l0 <= l1 && strcmp (rel, c->nname + l1 - l0) == 0
+           && (l0 == l1 || c->nname[l1-l0-1] == FSDB_DIR_SEPARATOR))
+           break;
+       c = c->sibling;
+    }
+    if (c != 0)
+       return c;
+    c = fsdb_lookup_aino_nname (base, rel);
+    if (c == 0) {
+       c = xcalloc (sizeof (a_inode), 1);
+       if (c == 0) {
+           *err = ERROR_NO_FREE_STORE;
+           return 0;
+       }
+
+       c->nname = build_nname (base->nname, rel);
+       c->aname = get_aname (unit, base, rel);
+       c->comment = 0;
+       c->has_dbentry = 0;
+       fsdb_fill_file_attrs (c);
+       if (c->dir)
+           fsdb_clean_dir (c);
+    }
+    init_child_aino (unit, base, c);
+
+    recycle_aino (unit, c);
+    TRACE(("created aino %x, exnext\n", c->uniq));
+
+    return c;
+}
+
+static a_inode *get_aino (Unit *unit, a_inode *base, const char *rel, uae_u32 *err)
+{
+    char *tmp;
+    char *p;
+    a_inode *curr;
+    int i;
+
+    aino_test (base);
+
+    *err = 0;
+    TRACE(("get_path(%s,%s)\n", base->aname, rel));
+
+    /* root-relative path? */
+    for (i = 0; rel[i] && rel[i] != '/' && rel[i] != ':'; i++)
+       ;
+    if (':' == rel[i])
+       rel += i+1;
+
+    tmp = my_strdup (rel);
+    p = tmp;
+    curr = base;
+
+    while (*p) {
+       /* start with a slash? go up a level. */
+       if (*p == '/') {
+           if (curr->parent != 0)
+               curr = curr->parent;
+           p++;
+       } else {
+           a_inode *next;
+
+           char *component_end;
+           component_end = strchr (p, '/');
+           if (component_end != 0)
+               *component_end = '\0';
+           next = lookup_child_aino (unit, curr, p, err);
+           if (next == 0) {
+               /* if only last component not found, return parent dir. */
+               if (*err != ERROR_OBJECT_NOT_AROUND || component_end != 0)
+                   curr = 0;
+               /* ? what error is appropriate? */
+               break;
+           }
+           curr = next;
+           if (component_end)
+               p = component_end+1;
+           else
+               break;
+
+       }
+    }
+    xfree (tmp);
+    return curr;
+}
+
+static uae_u32 startup_handler (void)
+{
+    /* Just got the startup packet. It's in A4. DosBase is in A2,
+     * our allocated volume structure is in D6, A5 is a pointer to
+     * our port. */
+    uaecptr rootnode = get_long (m68k_areg (regs, 2) + 34);
+    uaecptr dos_info = get_long (rootnode + 24) << 2;
+    uaecptr pkt = m68k_dreg (regs, 3);
+    uaecptr arg2 = get_long (pkt + dp_Arg2);
+    int i, namelen;
+    char* devname = bstr1 (get_long (pkt + dp_Arg1) << 2);
+    char* s;
+    Unit *unit;
+    UnitInfo *uinfo;
+
+    /* find UnitInfo with correct device name */
+    s = strchr (devname, ':');
+    if (s)
+       *s = '\0';
+
+    for (i = 0; i < current_mountinfo->num_units; i++) {
+       /* Hardfile volume name? */
+       if (current_mountinfo->ui[i].volname == 0)
+           continue;
+
+       if (current_mountinfo->ui[i].startup == arg2)
+           break;
+    }
+
+    if (i == current_mountinfo->num_units
+       || access (current_mountinfo->ui[i].rootdir, R_OK) != 0)
+    {
+       write_log ("Failed attempt to mount device\n", devname);
+       put_long (pkt + dp_Res1, DOS_FALSE);
+       put_long (pkt + dp_Res2, ERROR_DEVICE_NOT_MOUNTED);
+       return 1;
+    }
+    uinfo = current_mountinfo->ui + i;
+
+    unit = (Unit *) xcalloc (sizeof (Unit), 1);
+    unit->next = units;
+    units = unit;
+    uinfo->self = unit;
+
+    unit->volume = 0;
+    unit->port = m68k_areg (regs, 5);
+    unit->unit = unit_num++;
+
+    unit->ui.devname = uinfo->devname;
+    unit->ui.volname = my_strdup (uinfo->volname); /* might free later for rename */
+    unit->ui.rootdir = uinfo->rootdir;
+    unit->ui.readonly = uinfo->readonly;
+    unit->ui.unit_pipe = uinfo->unit_pipe;
+    unit->ui.back_pipe = uinfo->back_pipe;
+    unit->cmds_complete = 0;
+    unit->cmds_sent = 0;
+    unit->cmds_acked = 0;
+    for (i = 0; i < EXKEYS; i++) {
+       unit->examine_keys[i].aino = 0;
+       unit->examine_keys[i].curr_file = 0;
+       unit->examine_keys[i].uniq = 0;
+    }
+    unit->total_locked_ainos = 0;
+    unit->next_exkey = 1;
+    unit->keys = 0;
+    unit->a_uniq = unit->key_uniq = 0;
+
+    unit->rootnode.aname = uinfo->volname;
+    unit->rootnode.nname = uinfo->rootdir;
+    unit->rootnode.sibling = 0;
+    unit->rootnode.next = unit->rootnode.prev = &unit->rootnode;
+    unit->rootnode.uniq = 0;
+    unit->rootnode.parent = 0;
+    unit->rootnode.child = 0;
+    unit->rootnode.dir = 1;
+    unit->rootnode.amigaos_mode = 0;
+    unit->rootnode.shlock = 0;
+    unit->rootnode.elock = 0;
+    unit->rootnode.comment = 0;
+    unit->rootnode.has_dbentry = 0;
+    aino_test_init (&unit->rootnode);
+    unit->aino_cache_size = 0;
+    for (i = 0; i < MAX_AINO_HASH; i++)
+       unit->aino_hash[i] = 0;
+
+/*    write_comm_pipe_int (unit->ui.unit_pipe, -1, 1);*/
+
+    TRACE(("**** STARTUP volume %s\n", unit->ui.volname));
+
+    /* fill in our process in the device node */
+    put_long ((get_long (pkt + dp_Arg3) << 2) + 8, unit->port);
+    unit->dosbase = m68k_areg (regs, 2);
+
+    /* make new volume */
+    unit->volume = m68k_areg (regs, 3) + 32;
+#ifdef UAE_FILESYS_THREADS
+    unit->locklist = m68k_areg (regs, 3) + 8;
+#else
+    unit->locklist = m68k_areg (regs, 3);
+#endif
+    unit->dummy_message = m68k_areg (regs, 3) + 12;
+
+    put_long (unit->dummy_message + 10, 0);
+
+    put_long (unit->volume + 4, 2); /* Type = dt_volume */
+    put_long (unit->volume + 12, 0); /* Lock */
+    put_long (unit->volume + 16, 3800); /* Creation Date */
+    put_long (unit->volume + 20, 0);
+    put_long (unit->volume + 24, 0);
+    put_long (unit->volume + 28, 0); /* lock list */
+    put_long (unit->volume + 40, (unit->volume + 44) >> 2); /* Name */
+    namelen = strlen (unit->ui.volname);
+    put_byte (unit->volume + 44, namelen);
+    for (i = 0; i < namelen; i++)
+       put_byte (unit->volume + 45 + i, unit->ui.volname[i]);
+
+    /* link into DOS list */
+    put_long (unit->volume, get_long (dos_info + 4));
+    put_long (dos_info + 4, unit->volume >> 2);
+
+    put_long (unit->volume + 8, unit->port);
+    put_long (unit->volume + 32, DISK_TYPE);
+
+    put_long (pkt + dp_Res1, DOS_TRUE);
+
+    fsdb_clean_dir (&unit->rootnode);
+
+    return 0;
+}
+
+static void
+do_info (Unit *unit, dpacket packet, uaecptr info)
+{
+    struct fs_usage fsu;
+    
+    if (get_fs_usage (unit->ui.rootdir, 0, &fsu) != 0) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, dos_errno ());
+       return;
+    }
+
+    fsu.fsu_blocks >>= 1;
+    fsu.fsu_bavail >>= 1;
+    put_long (info, 0); /* errors */
+    put_long (info + 4, unit->unit); /* unit number */
+    put_long (info + 8, unit->ui.readonly ? 80 : 82); /* state  */
+    put_long (info + 12, fsu.fsu_blocks ); /* numblocks */
+    put_long (info + 16, fsu.fsu_blocks - fsu.fsu_bavail); /* inuse */
+    put_long (info + 20, 1024); /* bytesperblock */
+    put_long (info + 24, DISK_TYPE); /* disk type */
+    put_long (info + 28, unit->volume >> 2); /* volume node */
+    put_long (info + 32, 0); /* inuse */
+    PUT_PCK_RES1 (packet, DOS_TRUE);
+}
+
+static void
+action_disk_info (Unit *unit, dpacket packet)
+{
+    TRACE(("ACTION_DISK_INFO\n"));
+    do_info(unit, packet, GET_PCK_ARG1 (packet) << 2);
+}
+
+static void
+action_info (Unit *unit, dpacket packet)
+{
+    TRACE(("ACTION_INFO\n"));
+    do_info(unit, packet, GET_PCK_ARG2 (packet) << 2);
+}
+
+static void free_key (Unit *unit, Key *k)
+{
+    Key *k1;
+    Key *prev = 0;
+    for (k1 = unit->keys; k1; k1 = k1->next) {
+       if (k == k1) {
+           if (prev)
+               prev->next = k->next;
+           else
+               unit->keys = k->next;
+           break;
+       }
+       prev = k1;
+    }
+
+    if (k->fd >= 0)
+       close (k->fd);
+
+    xfree(k);
+}
+
+static Key *lookup_key (Unit *unit, uae_u32 uniq)
+{
+    Key *k;
+    /* It's hardly worthwhile to optimize this - most of the time there are
+     * only one or zero keys. */
+    for (k = unit->keys; k; k = k->next) {
+       if (uniq == k->uniq)
+           return k;
+    }
+    write_log ("Error: couldn't find key!\n");
+#if 0
+    exit(1);
+    /* NOTREACHED */
+#endif
+    /* There isn't much hope we will recover. Unix would kill the process,
+     * AmigaOS gets killed by it. */
+    write_log ("Better reset that Amiga - the system is messed up.\n");
+    return 0;
+}
+
+static Key *new_key (Unit *unit)
+{
+    Key *k = (Key *) xmalloc(sizeof(Key));
+    k->uniq = ++unit->key_uniq;
+    k->fd = -1;
+    k->file_pos = 0;
+    k->next = unit->keys;
+    unit->keys = k;
+
+    return k;
+}
+
+static void
+dumplock (Unit *unit, uaecptr lock)
+{
+    a_inode *a;
+    TRACE(("LOCK: 0x%lx", lock));
+    if (!lock) {
+       TRACE(("\n"));
+       return;
+    }
+    TRACE(("{ next=0x%lx, mode=%ld, handler=0x%lx, volume=0x%lx, aino %lx ",
+          get_long (lock) << 2, get_long (lock+8),
+          get_long (lock+12), get_long (lock+16),
+          get_long (lock + 4)));
+    a = lookup_aino (unit, get_long (lock + 4));
+    if (a == 0) {
+       TRACE(("not found!"));
+    } else {
+       TRACE(("%s", a->nname));
+    }
+    TRACE((" }\n"));
+}
+
+static a_inode *find_aino (Unit *unit, uaecptr lock, const char *name, uae_u32 *err)
+{
+    a_inode *a;
+
+    if (lock) {
+       a_inode *olda = lookup_aino (unit, get_long (lock + 4));
+       if (olda == 0) {
+           /* That's the best we can hope to do. */
+           a = get_aino (unit, &unit->rootnode, name, err);
+       } else {
+           TRACE(("aino: 0x%08lx", (unsigned long int)olda->uniq));
+           TRACE((" \"%s\"\n", olda->nname));
+           a = get_aino (unit, olda, name, err);
+       }
+    } else {
+       a = get_aino (unit, &unit->rootnode, name, err);
+    }
+    if (a) {
+       TRACE(("aino=\"%s\"\n", a->nname));
+    }
+    aino_test (a);
+    return a;
+}
+
+static uaecptr make_lock (Unit *unit, uae_u32 uniq, long mode)
+{
+    /* allocate lock from the list kept by the assembly code */
+    uaecptr lock;
+
+    lock = get_long (unit->locklist);
+    put_long (unit->locklist, get_long (lock));
+    lock += 4;
+
+    put_long (lock + 4, uniq);
+    put_long (lock + 8, mode);
+    put_long (lock + 12, unit->port);
+    put_long (lock + 16, unit->volume >> 2);
+
+    /* prepend to lock chain */
+    put_long (lock, get_long (unit->volume + 28));
+    put_long (unit->volume + 28, lock >> 2);
+
+    DUMPLOCK(unit, lock);
+    return lock;
+}
+
+static uae_u32 notifyhash (char *s)
+{
+    uae_u32 hash = 0;
+    while (*s) hash = (hash << 5) + *s++;
+    return hash % NOTIFY_HASH_SIZE;
+}
+
+static Notify *new_notify (Unit *unit, char *name)
+{
+    Notify *n = xmalloc(sizeof(Notify));
+    int hash = notifyhash (name);
+    n->next = unit->notifyhash[hash];
+    unit->notifyhash[hash] = n;
+    n->partname = name;
+    return n;
+}
+
+static void free_notify (Unit *unit, int hash, Notify *n)
+{
+    Notify *n1, *prev = 0;
+    for (n1 = unit->notifyhash[hash]; n1; n1 = n1->next) {
+       if (n == n1) {
+           if (prev)
+               prev->next = n->next;
+           else
+               unit->notifyhash[hash] = n->next;
+           break;
+       }
+       prev = n1;
+    }
+    xfree(n);
+}
+
+#define NOTIFY_CLASS   0x40000000
+#define NOTIFY_CODE    0x1234
+
+#define NRF_SEND_MESSAGE 1
+#define NRF_SEND_SIGNAL 2
+#define NRF_WAIT_REPLY 8
+#define NRF_NOTIFY_INITIAL 16
+#define NRF_MAGIC (1 << 31)
+
+static void notify_send (Unit *unit, Notify *n)
+{
+    uaecptr nr = n->notifyrequest;
+    int flags = get_long (nr + 12);
+
+    if (flags & NRF_SEND_MESSAGE) {
+       if (!(flags & NRF_WAIT_REPLY) || ((flags & NRF_WAIT_REPLY) && !(flags & NRF_MAGIC))) {
+           uae_NotificationHack (unit->port, nr);
+       } else if (flags & NRF_WAIT_REPLY) {
+           put_long (nr + 12, get_long (nr + 12) | NRF_MAGIC);
+       }
+    } else if (flags & NRF_SEND_SIGNAL) {
+       uae_Signal (get_long (nr + 16), 1 << get_byte (nr + 20));
+    }
+}
+
+static void notify_check (Unit *unit, a_inode *a)
+{
+    Notify *n;
+    int hash = notifyhash (a->aname);
+    for (n = unit->notifyhash[hash]; n; n = n->next) {
+       uaecptr nr = n->notifyrequest;
+       if (same_aname(n->partname, a->aname)) {
+           uae_u32 err;
+           a_inode *a2 = find_aino (unit, 0, n->fullname, &err);
+           if (err == 0 && a == a2)
+               notify_send (unit, n);
+       }
+    }
+    if (a->parent) {
+       hash = notifyhash (a->parent->aname);
+       for (n = unit->notifyhash[hash]; n; n = n->next) {
+           uaecptr nr = n->notifyrequest;
+           if (same_aname(n->partname, a->parent->aname)) {
+               uae_u32 err;
+               a_inode *a2 = find_aino (unit, 0, n->fullname, &err);
+               if (err == 0 && a->parent == a2)
+                   notify_send (unit, n);
+           }
+       }
+    }
+}
+
+static void
+action_add_notify (Unit *unit, dpacket packet)
+{
+    uaecptr nr = GET_PCK_ARG1 (packet);
+    int flags;
+    Notify *n;
+    char *name, *p, *partname;
+
+    TRACE(("ACTION_ADD_NOTIFY\n"));
+
+    name = my_strdup (char1 (get_long (nr + 4)));
+    flags = get_long (nr + 12);
+
+#if 0
+    write_log ("Notify:\n");
+    write_log ("nr_Name '%s'\n", char1 (get_long (nr + 0)));
+    write_log ("nr_FullName '%s'\n", name);
+    write_log ("nr_UserData %08.8X\n", get_long (nr + 8));
+    write_log ("nr_Flags %08.8X\n", flags);
+    if (flags & NRF_SEND_MESSAGE) {
+       write_log ("Message NotifyRequest, port = %08.8X\n", get_long (nr + 16));
+    } else if (flags & NRF_SEND_SIGNAL) {
+       write_log ("Signal NotifyRequest, Task = %08.8X signal = %d\n", get_long (nr + 16), get_long (nr + 20));
+    } else {
+       write_log ("corrupt NotifyRequest\n");
+    }
+#endif
+
+    p = name + strlen (name) - 1;
+    if (p[0] == ':') p--;
+    while (p > name && p[0] != ':' && p[0] != '/') p--;
+    if (p[0] == ':' || p[0] == '/') p++;
+    partname = my_strdup (p);
+    n = new_notify (unit, partname);
+    n->notifyrequest = nr;
+    n->fullname = name;
+    if (flags & NRF_NOTIFY_INITIAL) {
+       uae_u32 err;
+       a_inode *a = find_aino (unit, 0, n->fullname, &err);
+       if (err == 0)
+           notify_send (unit, n);
+    }
+    PUT_PCK_RES1 (packet, DOS_TRUE);
+}
+static void
+action_remove_notify (Unit *unit, dpacket packet)
+{
+    uaecptr nr = GET_PCK_ARG1 (packet);
+    Notify *n;
+    int hash;
+
+    TRACE(("ACTION_REMOVE_NOTIFY\n"));
+    for (hash = 0; hash < NOTIFY_HASH_SIZE; hash++) {
+        for (n = unit->notifyhash[hash]; n; n = n->next) {
+           if (n->notifyrequest == nr) {
+               //write_log ("NotifyRequest %08.8X freed\n", n->notifyrequest);
+               xfree (n->fullname);
+               xfree (n->partname);
+               free_notify (unit, hash, n);
+               PUT_PCK_RES1 (packet, DOS_TRUE);
+               return;
+           }
+       }
+    }
+    //write_log ("Tried to free non-existing NotifyRequest %08.8X\n", nr);
+    PUT_PCK_RES1 (packet, DOS_TRUE);
+}
+
+static void free_lock (Unit *unit, uaecptr lock)
+{
+    if (! lock)
+       return;
+
+    if (lock == get_long (unit->volume + 28) << 2) {
+       put_long (unit->volume + 28, get_long (lock));
+    } else {
+       uaecptr current = get_long (unit->volume + 28);
+       uaecptr next = 0;
+       while (current) {
+           next = get_long (current << 2);
+           if (lock == next << 2)
+               break;
+           current = next;
+       }
+       put_long (current << 2, get_long (lock));
+    }
+    lock -= 4;
+    put_long (lock, get_long (unit->locklist));
+    put_long (unit->locklist, lock);
+}
+
+static void
+action_lock (Unit *unit, dpacket packet)
+{
+    uaecptr lock = GET_PCK_ARG1 (packet) << 2;
+    uaecptr name = GET_PCK_ARG2 (packet) << 2;
+    long mode = GET_PCK_ARG3 (packet);
+    a_inode *a;
+    uae_u32 err;
+
+    if (mode != SHARED_LOCK && mode != EXCLUSIVE_LOCK) {
+       TRACE(("Bad mode.\n"));
+       mode = SHARED_LOCK;
+    }
+
+    TRACE(("ACTION_LOCK(0x%lx, \"%s\", %d)\n", lock, bstr (unit, name), mode));
+    DUMPLOCK(unit, lock);
+
+    a = find_aino (unit, lock, bstr (unit, name), &err);
+    if (err == 0 && (a->elock || (mode != SHARED_LOCK && a->shlock > 0))) {
+       err = ERROR_OBJECT_IN_USE;
+    }
+    /* Lock() doesn't do access checks. */
+    if (err != 0) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, err);
+       return;
+    }
+    if (mode == SHARED_LOCK)
+       a->shlock++;
+    else
+       a->elock = 1;
+    de_recycle_aino (unit, a);
+    PUT_PCK_RES1 (packet, make_lock (unit, a->uniq, mode) >> 2);
+}
+
+static void action_free_lock (Unit *unit, dpacket packet)
+{
+    uaecptr lock = GET_PCK_ARG1 (packet) << 2;
+    a_inode *a;
+    TRACE(("ACTION_FREE_LOCK(0x%lx)\n", lock));
+    DUMPLOCK(unit, lock);
+
+    a = lookup_aino (unit, get_long (lock + 4));
+    if (a == 0) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
+       return;
+    }
+    if (a->elock)
+       a->elock = 0;
+    else
+       a->shlock--;
+    recycle_aino (unit, a);
+    free_lock(unit, lock);
+
+    PUT_PCK_RES1 (packet, DOS_TRUE);
+}
+
+static void
+action_dup_lock (Unit *unit, dpacket packet)
+{
+    uaecptr lock = GET_PCK_ARG1 (packet) << 2;
+    a_inode *a;
+    TRACE(("ACTION_DUP_LOCK(0x%lx)\n", lock));
+    DUMPLOCK(unit, lock);
+
+    if (!lock) {
+       PUT_PCK_RES1 (packet, 0);
+       return;
+    }
+    a = lookup_aino (unit, get_long (lock + 4));
+    if (a == 0) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
+       return;
+    }
+    /* DupLock()ing exclusive locks isn't possible, says the Autodoc, but
+     * at least the RAM-Handler seems to allow it. Let's see what happens
+     * if we don't. */
+    if (a->elock) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
+       return;
+    }
+    a->shlock++;
+    de_recycle_aino (unit, a);
+    PUT_PCK_RES1 (packet, make_lock (unit, a->uniq, -2) >> 2);
+}
+
+/* convert time_t to/from AmigaDOS time */
+const int secs_per_day = 24 * 60 * 60;
+const int diff = (8 * 365 + 2) * (24 * 60 * 60);
+
+static void
+get_time (time_t t, long* days, long* mins, long* ticks)
+{
+    /* time_t is secs since 1-1-1970 */
+    /* days since 1-1-1978 */
+    /* mins since midnight */
+    /* ticks past minute @ 50Hz */
+
+    t -= diff;
+    *days = t / secs_per_day;
+    t -= *days * secs_per_day;
+    *mins = t / 60;
+    t -= *mins * 60;
+    *ticks = t * 50;
+}
+
+static time_t
+put_time (long days, long mins, long ticks)
+{
+    time_t t;
+    t = ticks / 50;
+    t += mins * 60;
+    t += days * secs_per_day;
+    t += diff;
+
+    return t;
+}
+
+static void free_exkey (Unit *unit, ExamineKey *ek)
+{
+    if (--ek->aino->exnext_count == 0) {
+       TRACE (("Freeing ExKey and reducing total_locked from %d by %d\n",
+               unit->total_locked_ainos, ek->aino->locked_children));
+       unit->total_locked_ainos -= ek->aino->locked_children;
+       ek->aino->locked_children = 0;
+    }
+    ek->aino = 0;
+    ek->uniq = 0;
+}
+
+static ExamineKey *lookup_exkey (Unit *unit, uae_u32 uniq)
+{
+    ExamineKey *ek;
+    int i;
+
+    ek = unit->examine_keys;
+    for (i = 0; i < EXKEYS; i++, ek++) {
+       /* Did we find a free one? */
+       if (ek->uniq == uniq)
+           return ek;
+    }
+    write_log ("Houston, we have a BIG problem.\n");
+    return 0;
+}
+
+/* This is so sick... who invented ACTION_EXAMINE_NEXT? What did he THINK??? */
+static ExamineKey *new_exkey (Unit *unit, a_inode *aino)
+{
+    uae_u32 uniq;
+    uae_u32 oldest = 0xFFFFFFFE;
+    ExamineKey *ek, *oldest_ek = 0;
+    int i;
+
+    ek = unit->examine_keys;
+    for (i = 0; i < EXKEYS; i++, ek++) {
+       /* Did we find a free one? */
+       if (ek->aino == 0)
+           continue;
+       if (ek->uniq < oldest)
+           oldest = (oldest_ek = ek)->uniq;
+    }
+    ek = unit->examine_keys;
+    for (i = 0; i < EXKEYS; i++, ek++) {
+       /* Did we find a free one? */
+       if (ek->aino == 0)
+           goto found;
+    }
+    /* This message should usually be harmless. */
+    write_log ("Houston, we have a problem (%s).\n", aino->nname);
+    free_exkey (unit, oldest_ek);
+    ek = oldest_ek;
+    found:
+
+    uniq = unit->next_exkey;
+    if (uniq >= 0xFFFFFFFE) {
+       /* Things will probably go wrong, but most likely the Amiga will crash
+        * before this happens because of something else. */
+       uniq = 1;
+    }
+    unit->next_exkey = uniq+1;
+    ek->aino = aino;
+    ek->curr_file = 0;
+    ek->uniq = uniq;
+    return ek;
+}
+
+static void move_exkeys (Unit *unit, a_inode *from, a_inode *to)
+{
+    int i;
+    unsigned long tmp = 0;
+    for (i = 0; i < EXKEYS; i++) {
+       ExamineKey *k = unit->examine_keys + i;
+       if (k->uniq == 0)
+           continue;
+       if (k->aino == from) {
+           k->aino = to;
+           tmp++;
+       }
+    }
+    if (tmp != from->exnext_count)
+       write_log ("filesys.c: Bug in ExNext bookkeeping.  BAD.\n");
+    to->exnext_count = from->exnext_count;
+    to->locked_children = from->locked_children;
+    from->exnext_count = 0;
+    from->locked_children = 0;
+}
+
+static void
+get_fileinfo (Unit *unit, dpacket packet, uaecptr info, a_inode *aino)
+{
+    struct stat statbuf;
+    long days, mins, ticks;
+    int i, n;
+    char *x;
+
+    /* No error checks - this had better work. */
+    stat (aino->nname, &statbuf);
+
+    if (aino->parent == 0) {
+       x = unit->ui.volname;
+       put_long (info + 4, 1);
+       put_long (info + 120, 1);
+    } else {
+       /* AmigaOS docs say these have to contain the same value. */
+       put_long (info + 4, aino->dir ? 2 : -3);
+       put_long (info + 120, aino->dir ? 2 : -3);
+       x = aino->aname;
+    }
+    TRACE(("name=\"%s\"\n", x));
+    n = strlen (x);
+    if (n > 106)
+       n = 106;
+    i = 8;
+    put_byte (info + i, n); i++;
+    while (n--)
+       put_byte (info + i, *x), i++, x++;
+    while (i < 108)
+       put_byte (info + i, 0), i++;
+
+    put_long (info + 116, aino->amigaos_mode);
+    put_long (info + 124, statbuf.st_size);
+#ifdef HAVE_ST_BLOCKS
+    put_long (info + 128, statbuf.st_blocks);
+#else
+    put_long (info + 128, statbuf.st_size / 512 + 1);
+#endif
+    get_time (statbuf.st_mtime, &days, &mins, &ticks);
+    put_long (info + 132, days);
+    put_long (info + 136, mins);
+    put_long (info + 140, ticks);
+    if (aino->comment == 0)
+       put_long (info + 144, 0);
+    else {
+       TRACE(("comment=\"%s\"\n", aino->comment));
+       i = 144;
+       x = aino->comment;
+       if (! x)
+           x = "";
+       n = strlen (x);
+       if (n > 78)
+           n = 78;
+       put_byte (info + i, n); i++;
+       while (n--)
+           put_byte (info + i, *x), i++, x++;
+       while (i < 224)
+           put_byte (info + i, 0), i++;
+    }
+    PUT_PCK_RES1 (packet, DOS_TRUE);
+}
+
+static void action_examine_object (Unit *unit, dpacket packet)
+{
+    uaecptr lock = GET_PCK_ARG1 (packet) << 2;
+    uaecptr info = GET_PCK_ARG2 (packet) << 2;
+    a_inode *aino = 0;
+
+    TRACE(("ACTION_EXAMINE_OBJECT(0x%lx,0x%lx)\n", lock, info));
+    DUMPLOCK(unit, lock);
+
+    if (lock != 0)
+       aino = lookup_aino (unit, get_long (lock + 4));
+    if (aino == 0)
+       aino = &unit->rootnode;
+
+    get_fileinfo (unit, packet, info, aino);
+    if (aino->dir) {
+       put_long (info, 0xFFFFFFFF);
+    } else
+       put_long (info, 0);
+}
+
+/* Read a directory's contents, create a_inodes for each file, and
+   mark them as locked in memory so that recycle_aino will not reap
+   them.
+   We do this to avoid problems with the host OS: we don't want to
+   leave the directory open on the host side until all ExNext()s have
+   finished - they may never finish!  */
+
+static void populate_directory (Unit *unit, a_inode *base)
+{
+    DIR *d = opendir (base->nname);
+    a_inode *aino;
+
+    if (!d)
+       return;
+    for (aino = base->child; aino; aino = aino->sibling) {
+       base->locked_children++;
+       unit->total_locked_ainos++;
+    }
+    TRACE(("Populating directory, child %p, locked_children %d\n",
+          base->child, base->locked_children));
+    for (;;) {
+       struct dirent *de;
+       uae_u32 err;
+
+       /* Find next file that belongs to the Amiga fs (skipping things
+          like "..", "." etc.  */
+       do {
+           de = my_readdir (d, &de_space);
+       } while (de && fsdb_name_invalid (de->d_name));
+       if (! de)
+           break;
+       /* This calls init_child_aino, which will notice that the parent is
+          being ExNext()ed, and it will increment the locked counts.  */
+       aino = lookup_child_aino_for_exnext (unit, base, de->d_name, &err);
+    }
+    closedir (d);
+}
+
+static void do_examine (Unit *unit, dpacket packet, ExamineKey *ek, uaecptr info)
+{
+    if (ek->curr_file == 0)
+       goto no_more_entries;
+
+    get_fileinfo (unit, packet, info, ek->curr_file);
+    ek->curr_file = ek->curr_file->sibling;
+    TRACE (("curr_file set to %p %s\n", ek->curr_file,
+       ek->curr_file ? ek->curr_file->aname : "NULL"));
+    return;
+
+  no_more_entries:
+    TRACE(("no more entries\n"));
+    free_exkey (unit, ek);
+    PUT_PCK_RES1 (packet, DOS_FALSE);
+    PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
+}
+
+static void action_examine_next (Unit *unit, dpacket packet)
+{
+    uaecptr lock = GET_PCK_ARG1 (packet) << 2;
+    uaecptr info = GET_PCK_ARG2 (packet) << 2;
+    a_inode *aino = 0;
+    ExamineKey *ek;
+    uae_u32 uniq;
+
+    TRACE(("ACTION_EXAMINE_NEXT(0x%lx,0x%lx)\n", lock, info));
+    DUMPLOCK(unit, lock);
+
+    if (lock != 0)
+       aino = lookup_aino (unit, get_long (lock + 4));
+    if (aino == 0)
+       aino = &unit->rootnode;
+
+    uniq = get_long (info);
+    if (uniq == 0) {
+       write_log ("ExNext called for a file! (Houston?)\n");
+       goto no_more_entries;
+    } else if (uniq == 0xFFFFFFFE)
+       goto no_more_entries;
+    else if (uniq == 0xFFFFFFFF) {
+       TRACE(("Creating new ExKey\n"));
+       ek = new_exkey (unit, aino);
+       if (ek) {
+           if (aino->exnext_count++ == 0)
+               populate_directory (unit, aino);
+       }
+       ek->curr_file = aino->child;
+       TRACE(("Initial curr_file: %p %s\n", ek->curr_file,
+              ek->curr_file ? ek->curr_file->aname : "NULL"));
+    } else {
+       TRACE(("Looking up ExKey\n"));
+       ek = lookup_exkey (unit, get_long (info));
+    }
+    if (ek == 0) {
+       write_log ("Couldn't find a matching ExKey. Prepare for trouble.\n");
+       goto no_more_entries;
+    }
+    put_long (info, ek->uniq);
+    do_examine (unit, packet, ek, info);
+    return;
+
+  no_more_entries:
+    PUT_PCK_RES1 (packet, DOS_FALSE);
+    PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
+}
+
+static void do_find (Unit *unit, dpacket packet, int mode, int create, int fallback)
+{
+    uaecptr fh = GET_PCK_ARG1 (packet) << 2;
+    uaecptr lock = GET_PCK_ARG2 (packet) << 2;
+    uaecptr name = GET_PCK_ARG3 (packet) << 2;
+    a_inode *aino;
+    Key *k;
+    int fd;
+    uae_u32 err;
+    mode_t openmode;
+    int aino_created = 0;
+
+    TRACE(("ACTION_FIND_*(0x%lx,0x%lx,\"%s\",%d,%d)\n", fh, lock, bstr (unit, name), mode, create));
+    DUMPLOCK(unit, lock);
+
+    aino = find_aino (unit, lock, bstr (unit, name), &err);
+
+    if (aino == 0 || (err != 0 && err != ERROR_OBJECT_NOT_AROUND)) {
+       /* Whatever it is, we can't handle it. */
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, err);
+       return;
+    }
+    if (err == 0) {
+       /* Object exists. */
+       if (aino->dir) {
+           PUT_PCK_RES1 (packet, DOS_FALSE);
+           PUT_PCK_RES2 (packet, ERROR_OBJECT_WRONG_TYPE);
+           return;
+       }
+       if (aino->elock || (create == 2 && aino->shlock > 0)) {
+           PUT_PCK_RES1 (packet, DOS_FALSE);
+           PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
+           return;
+       }
+       if (create == 2 && (aino->amigaos_mode & A_FIBF_DELETE) != 0) {
+           PUT_PCK_RES1 (packet, DOS_FALSE);
+           PUT_PCK_RES2 (packet, ERROR_DELETE_PROTECTED);
+           return;
+       }
+       if (create != 2) {
+           if ((((mode & aino->amigaos_mode) & A_FIBF_WRITE) != 0 || unit->ui.readonly)
+               && fallback)
+           {
+               mode &= ~A_FIBF_WRITE;
+           }
+           /* Kick 1.3 doesn't check read and write access bits - maybe it would be
+            * simpler just not to do that either. */
+           if ((mode & A_FIBF_WRITE) != 0 && unit->ui.readonly) {
+               PUT_PCK_RES1 (packet, DOS_FALSE);
+               PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
+               return;
+           }
+           if (((mode & aino->amigaos_mode) & A_FIBF_WRITE) != 0
+               || mode == 0)
+           {
+               PUT_PCK_RES1 (packet, DOS_FALSE);
+               PUT_PCK_RES2 (packet, ERROR_WRITE_PROTECTED);
+               return;
+           }
+           if (((mode & aino->amigaos_mode) & A_FIBF_READ) != 0) {
+               PUT_PCK_RES1 (packet, DOS_FALSE);
+               PUT_PCK_RES2 (packet, ERROR_READ_PROTECTED);
+               return;
+           }
+       }
+    } else if (create == 0) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, err);
+       return;
+    } else {
+       /* Object does not exist. aino points to containing directory. */
+       aino = create_child_aino (unit, aino, my_strdup (bstr_cut (unit, name)), 0);
+       if (aino == 0) {
+           PUT_PCK_RES1 (packet, DOS_FALSE);
+           PUT_PCK_RES2 (packet, ERROR_DISK_IS_FULL); /* best we can do */
+           return;
+       }
+       aino_created = 1;
+    }
+
+    prepare_for_open (aino->nname);
+
+    openmode = (((mode & A_FIBF_READ) == 0 ? O_WRONLY
+                : (mode & A_FIBF_WRITE) == 0 ? O_RDONLY
+                : O_RDWR)
+               | (create ? O_CREAT : 0)
+               | (create == 2 ? O_TRUNC : 0));
+
+    fd = open (aino->nname, openmode | O_BINARY, 0777);
+
+    if (fd < 0) {
+       if (aino_created)
+           delete_aino (unit, aino);
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, dos_errno ());
+       return;
+    }
+    k = new_key (unit);
+    k->fd = fd;
+    k->aino = aino;
+    k->dosmode = mode;
+    k->createmode = create;
+    k->notifyactive = create ? 1 : 0;
+
+    put_long (fh+36, k->uniq);
+    if (create == 2)
+       aino->elock = 1;
+    else
+       aino->shlock++;
+    de_recycle_aino (unit, aino);
+    PUT_PCK_RES1 (packet, DOS_TRUE);
+}
+
+static void
+action_fh_from_lock (Unit *unit, dpacket packet)
+{
+    uaecptr fh = GET_PCK_ARG1 (packet) << 2;
+    uaecptr lock = GET_PCK_ARG2 (packet) << 2;
+    a_inode *aino;
+    Key *k;
+    int fd;
+    mode_t openmode;
+    int mode;
+
+    TRACE(("ACTION_FH_FROM_LOCK(0x%lx,0x%lx)\n",fh,lock));
+    DUMPLOCK(unit,lock);
+
+    if (!lock) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, 0);
+       return;
+    }
+
+    aino = lookup_aino (unit, get_long (lock + 4));
+    if (aino == 0)
+       aino = &unit->rootnode;
+    mode = aino->amigaos_mode; /* Use same mode for opened filehandle as existing Lock() */
+
+    prepare_for_open (aino->nname);
+
+    TRACE (("  mode is %d\n", mode));
+    openmode = (((mode & A_FIBF_READ) ? O_WRONLY
+                : (mode & A_FIBF_WRITE) ? O_RDONLY
+                : O_RDWR));
+
+   /* the files on CD really can have the write-bit set.  */
+    if (unit->ui.readonly)
+       openmode = O_RDONLY;
+
+    fd = open (aino->nname, openmode | O_BINARY, 0777);
+
+    if (fd < 0) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, dos_errno());
+       return;
+    }
+    k = new_key (unit);
+    k->fd = fd;
+    k->aino = aino;
+
+    put_long (fh+36, k->uniq);
+    /* I don't think I need to play with shlock count here, because I'm
+       opening from an existing lock ??? */
+
+    /* Is this right?  I don't completely understand how this works.  Do I
+       also need to free_lock() my lock, since nobody else is going to? */
+    de_recycle_aino (unit, aino);
+    PUT_PCK_RES1 (packet, DOS_TRUE);
+    /* PUT_PCK_RES2 (packet, k->uniq); - this shouldn't be necessary, try without it */
+}
+
+static void
+action_find_input (Unit *unit, dpacket packet)
+{
+    do_find(unit, packet, A_FIBF_READ|A_FIBF_WRITE, 0, 1);
+}
+
+static void
+action_find_output (Unit *unit, dpacket packet)
+{
+    if (unit->ui.readonly) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
+       return;
+    }
+    do_find(unit, packet, A_FIBF_READ|A_FIBF_WRITE, 2, 0);
+}
+
+static void
+action_find_write (Unit *unit, dpacket packet)
+{
+    if (unit->ui.readonly) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
+       return;
+    }
+    do_find(unit, packet, A_FIBF_READ|A_FIBF_WRITE, 1, 0);
+}
+
+/* change file/dir's parent dir modification time */
+static void updatedirtime (a_inode *a1, int now)
+{
+    struct stat statbuf;
+    struct utimbuf ut;
+    long days, mins, ticks;
+
+    if (!a1->parent)
+       return;
+    if (!now) {
+       if (stat (a1->nname, &statbuf) == -1)
+           return;
+       get_time (statbuf.st_mtime, &days, &mins, &ticks);
+       ut.actime = ut.modtime = put_time(days, mins, ticks);
+       utime (a1->parent->nname, &ut);
+    } else {
+       utime (a1->parent->nname, NULL);
+    }
+}
+
+static void
+action_end (Unit *unit, dpacket packet)
+{
+    Key *k;
+    TRACE(("ACTION_END(0x%lx)\n", GET_PCK_ARG1 (packet)));
+
+    k = lookup_key (unit, GET_PCK_ARG1 (packet));
+    if (k != 0) {
+       if (k->notifyactive) {
+           notify_check (unit, k->aino);
+           updatedirtime (k->aino, 1);
+       }
+       if (k->aino->elock)
+           k->aino->elock = 0;
+       else
+           k->aino->shlock--;
+       recycle_aino (unit, k->aino);
+       free_key (unit, k);
+    }
+    PUT_PCK_RES1 (packet, DOS_TRUE);
+    PUT_PCK_RES2 (packet, 0);
+}
+
+static void
+action_read (Unit *unit, dpacket packet)
+{
+    Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
+    uaecptr addr = GET_PCK_ARG2 (packet);
+    long size = (uae_s32)GET_PCK_ARG3 (packet);
+    int actual;
+
+    if (k == 0) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       /* PUT_PCK_RES2 (packet, EINVAL); */
+       return;
+    }
+    TRACE(("ACTION_READ(%s,0x%lx,%ld)\n",k->aino->nname,addr,size));
+    gui_hd_led (1);
+#ifdef RELY_ON_LOADSEG_DETECTION
+    /* HACK HACK HACK HACK
+     * Try to detect a LoadSeg() */
+    if (k->file_pos == 0 && size >= 4) {
+       unsigned char buf[4];
+       off_t currpos = lseek(k->fd, 0, SEEK_CUR);
+       read(k->fd, buf, 4);
+       lseek(k->fd, currpos, SEEK_SET);
+       if (buf[0] == 0 && buf[1] == 0 && buf[2] == 3 && buf[3] == 0xF3)
+           possible_loadseg();
+    }
+#endif
+    if (valid_address (addr, size)) {
+       uae_u8 *realpt;
+       realpt = get_real_address (addr);
+       actual = read(k->fd, realpt, size);
+
+       if (actual == 0) {
+           PUT_PCK_RES1 (packet, 0);
+           PUT_PCK_RES2 (packet, 0);
+       } else if (actual < 0) {
+           PUT_PCK_RES1 (packet, 0);
+           PUT_PCK_RES2 (packet, dos_errno());
+       } else {
+           PUT_PCK_RES1 (packet, actual);
+           k->file_pos += actual;
+       }
+    } else {
+       char *buf;
+       unsigned long old, filesize;
+
+       write_log ("unixfs warning: Bad pointer passed for read: %08x, size %d\n", addr, size);
+       /* ugh this is inefficient but easy */
+
+       old = lseek (k->fd, 0, SEEK_CUR);
+       filesize = lseek (k->fd, 0, SEEK_END);
+       lseek (k->fd, old, SEEK_SET);
+       if (size > filesize)
+           size = filesize;
+
+       buf = (char *)malloc(size);
+       if (!buf) {
+           PUT_PCK_RES1 (packet, -1);
+           PUT_PCK_RES2 (packet, ERROR_NO_FREE_STORE);
+           return;
+       }
+       actual = read(k->fd, buf, size);
+
+       if (actual < 0) {
+           PUT_PCK_RES1 (packet, 0);
+           PUT_PCK_RES2 (packet, dos_errno());
+       } else {
+           int i;
+           PUT_PCK_RES1 (packet, actual);
+           for (i = 0; i < actual; i++)
+               put_byte(addr + i, buf[i]);
+           k->file_pos += actual;
+       }
+       xfree (buf);
+    }
+}
+
+static void
+action_write (Unit *unit, dpacket packet)
+{
+    Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
+    uaecptr addr = GET_PCK_ARG2 (packet);
+    long size = GET_PCK_ARG3 (packet);
+    char *buf;
+    int i;
+
+    if (k == 0) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       /* PUT_PCK_RES2 (packet, EINVAL); */
+       return;
+    }
+
+    gui_hd_led (1);
+    TRACE(("ACTION_WRITE(%s,0x%lx,%ld)\n",k->aino->nname,addr,size));
+
+    if (unit->ui.readonly) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
+       return;
+    }
+
+    /* ugh this is inefficient but easy */
+    buf = (char *)malloc(size);
+    if (!buf) {
+       PUT_PCK_RES1 (packet, -1);
+       PUT_PCK_RES2 (packet, ERROR_NO_FREE_STORE);
+       return;
+    }
+
+    for (i = 0; i < size; i++)
+       buf[i] = get_byte(addr + i);
+
+    PUT_PCK_RES1 (packet, write(k->fd, buf, size));
+    if (GET_PCK_RES1 (packet) != size)
+       PUT_PCK_RES2 (packet, dos_errno ());
+    if (GET_PCK_RES1 (packet) >= 0)
+       k->file_pos += GET_PCK_RES1 (packet);
+
+    k->notifyactive = 1;
+    xfree (buf);
+}
+
+static void
+action_seek (Unit *unit, dpacket packet)
+{
+    Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
+    long pos = (uae_s32)GET_PCK_ARG2 (packet);
+    long mode = (uae_s32)GET_PCK_ARG3 (packet);
+    off_t res;
+    long old;
+    int whence = SEEK_CUR;
+
+    if (k == 0) {
+       PUT_PCK_RES1 (packet, -1);
+       PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK);
+       return;
+    }
+
+    if (mode > 0) whence = SEEK_END;
+    if (mode < 0) whence = SEEK_SET;
+
+    TRACE(("ACTION_SEEK(%s,%d,%d)\n", k->aino->nname, pos, mode));
+
+    old = lseek (k->fd, 0, SEEK_CUR);
+    {
+       uae_s32 temppos;
+       long filesize = lseek (k->fd, 0, SEEK_END);
+       lseek (k->fd, old, SEEK_SET);
+
+       if (whence == SEEK_CUR) temppos = old + pos;
+       if (whence == SEEK_SET) temppos = pos;
+       if (whence == SEEK_END) temppos = filesize + pos;
+       if (filesize < temppos) {
+           res = -1;
+           PUT_PCK_RES1 (packet,res);
+           PUT_PCK_RES2 (packet, ERROR_SEEK_ERROR);
+           return;
+       }
+    }
+    res = lseek (k->fd, pos, whence);
+
+    if (-1 == res) {
+       PUT_PCK_RES1 (packet, res);
+       PUT_PCK_RES2 (packet, ERROR_SEEK_ERROR);
+    } else
+       PUT_PCK_RES1 (packet, old);
+    k->file_pos = res;
+}
+
+static void
+action_set_protect (Unit *unit, dpacket packet)
+{
+    uaecptr lock = GET_PCK_ARG2 (packet) << 2;
+    uaecptr name = GET_PCK_ARG3 (packet) << 2;
+    uae_u32 mask = GET_PCK_ARG4 (packet);
+    a_inode *a;
+    uae_u32 err;
+
+    TRACE(("ACTION_SET_PROTECT(0x%lx,\"%s\",0x%lx)\n", lock, bstr (unit, name), mask));
+
+    if (unit->ui.readonly) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
+       return;
+    }
+
+    a = find_aino (unit, lock, bstr (unit, name), &err);
+    if (err != 0) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, err);
+       return;
+    }
+
+    err = fsdb_set_file_attrs (a, mask);
+    if (err != 0) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, err);
+    } else {
+       PUT_PCK_RES1 (packet, DOS_TRUE);
+    }
+    notify_check (unit, a);
+}
+
+static void action_set_comment (Unit * unit, dpacket packet)
+{
+    uaecptr lock = GET_PCK_ARG2 (packet) << 2;
+    uaecptr name = GET_PCK_ARG3 (packet) << 2;
+    uaecptr comment = GET_PCK_ARG4 (packet) << 2;
+    char *commented;
+    a_inode *a;
+    uae_u32 err;
+
+    if (unit->ui.readonly) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
+       return;
+    }
+
+    commented = bstr (unit, comment);
+    commented = strlen (commented) > 0 ? my_strdup (commented) : 0;
+    TRACE (("ACTION_SET_COMMENT(0x%lx,\"%s\")\n", lock, commented));
+
+    a = find_aino (unit, lock, bstr (unit, name), &err);
+    if (err != 0) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, err);
+
+       maybe_free_and_out:
+       if (commented)
+           xfree (commented);
+       return;
+    }
+    PUT_PCK_RES1 (packet, DOS_TRUE);
+    PUT_PCK_RES2 (packet, 0);
+    if (a->comment == 0 && commented == 0)
+       goto maybe_free_and_out;
+    if (a->comment != 0 && commented != 0 && strcmp (a->comment, commented) == 0)
+       goto maybe_free_and_out;
+    if (a->comment)
+       xfree (a->comment);
+    a->comment = commented;
+    a->dirty = 1;
+    notify_check (unit, a);
+}
+
+static void
+action_same_lock (Unit *unit, dpacket packet)
+{
+    uaecptr lock1 = GET_PCK_ARG1 (packet) << 2;
+    uaecptr lock2 = GET_PCK_ARG2 (packet) << 2;
+
+    TRACE(("ACTION_SAME_LOCK(0x%lx,0x%lx)\n",lock1,lock2));
+    DUMPLOCK(unit, lock1); DUMPLOCK(unit, lock2);
+
+    if (!lock1 || !lock2) {
+       PUT_PCK_RES1 (packet, lock1 == lock2 ? DOS_TRUE : DOS_FALSE);
+    } else {
+       PUT_PCK_RES1 (packet, get_long (lock1 + 4) == get_long (lock2 + 4) ? DOS_TRUE : DOS_FALSE);
+    }
+}
+
+static void
+action_change_mode (Unit *unit, dpacket packet)
+{
+#define CHANGE_LOCK 0
+#define CHANGE_FH 1
+    /* will be CHANGE_FH or CHANGE_LOCK value */
+    long type = GET_PCK_ARG1 (packet);
+    /* either a file-handle or lock */
+    uaecptr object = GET_PCK_ARG2 (packet) << 2; 
+    /* will be EXCLUSIVE_LOCK/SHARED_LOCK if CHANGE_LOCK,
+     * or MODE_OLDFILE/MODE_NEWFILE/MODE_READWRITE if CHANGE_FH */
+    long mode = GET_PCK_ARG3 (packet);
+    unsigned long uniq;
+    a_inode *a = NULL, *olda = NULL;
+    uae_u32 err = 0;
+    TRACE(("ACTION_CHANGE_MODE(0x%lx,%d,%d)\n",object,type,mode));
+
+    if (! object
+       || (type != CHANGE_FH && type != CHANGE_LOCK))
+    {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK);
+       return;
+    }
+
+    /* @@@ Brian: shouldn't this be good enough to support
+       CHANGE_FH?  */
+    if (type == CHANGE_FH)
+       mode = (mode == 1006 ? -1 : -2);
+
+    if (type == CHANGE_LOCK)
+       uniq = get_long (object + 4);
+    else {
+       Key *k = lookup_key (unit, object);
+       if (!k) {
+           PUT_PCK_RES1 (packet, DOS_FALSE);
+           PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
+           return;
+       }
+       uniq = k->aino->uniq;
+    }
+    a = lookup_aino (unit, uniq);
+
+    if (! a)
+       err = ERROR_INVALID_LOCK;
+    else {
+       if (mode == -1) {
+           if (a->shlock > 1)
+               err = ERROR_OBJECT_IN_USE;
+           else {
+               a->shlock = 0;
+               a->elock = 1;
+           }
+       } else { /* Must be SHARED_LOCK == -2 */
+           a->elock = 0;
+           a->shlock++;
+       }
+    }
+
+    if (err) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, err);
+       return;
+    } else {
+       de_recycle_aino (unit, a);
+       PUT_PCK_RES1 (packet, DOS_TRUE);
+    }
+}
+
+static void
+action_parent_common (Unit *unit, dpacket packet, unsigned long uniq)
+{
+    a_inode *olda = lookup_aino (unit, uniq);
+    if (olda == 0) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK);
+       return;
+    }
+
+    if (olda->parent == 0) {
+       PUT_PCK_RES1 (packet, 0);
+       PUT_PCK_RES2 (packet, 0);
+       return;
+    }
+    if (olda->parent->elock) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
+       return;
+    }
+    olda->parent->shlock++;
+    de_recycle_aino (unit, olda->parent);
+    PUT_PCK_RES1 (packet, make_lock (unit, olda->parent->uniq, -2) >> 2);
+}
+
+static void
+action_parent_fh (Unit *unit, dpacket packet)
+{
+    Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
+    if (!k) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
+       return;
+    }
+    action_parent_common (unit, packet, k->aino->uniq);
+}
+
+static void
+action_parent (Unit *unit, dpacket packet)
+{
+    uaecptr lock = GET_PCK_ARG1 (packet) << 2;
+
+    TRACE(("ACTION_PARENT(0x%lx)\n",lock));
+
+    if (!lock) {
+       PUT_PCK_RES1 (packet, 0);
+       PUT_PCK_RES2 (packet, 0);
+       return;
+    }
+    action_parent_common (unit, packet, get_long (lock + 4));
+}
+
+static void
+action_create_dir (Unit *unit, dpacket packet)
+{
+    uaecptr lock = GET_PCK_ARG1 (packet) << 2;
+    uaecptr name = GET_PCK_ARG2 (packet) << 2;
+    a_inode *aino;
+    uae_u32 err;
+
+    TRACE(("ACTION_CREATE_DIR(0x%lx,\"%s\")\n", lock, bstr (unit, name)));
+
+    if (unit->ui.readonly) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
+       return;
+    }
+
+    aino = find_aino (unit, lock, bstr (unit, name), &err);
+    if (aino == 0 || (err != 0 && err != ERROR_OBJECT_NOT_AROUND)) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, err);
+       return;
+    }
+    if (err == 0) {
+       /* Object exists. */
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, ERROR_OBJECT_EXISTS);
+       return;
+    }
+    /* Object does not exist. aino points to containing directory. */
+    aino = create_child_aino (unit, aino, my_strdup (bstr_cut (unit, name)), 1);
+    if (aino == 0) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, ERROR_DISK_IS_FULL); /* best we can do */
+       return;
+    }
+
+    if (mkdir (aino->nname, 0777) == -1) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, dos_errno());
+       return;
+    }
+    aino->shlock = 1;
+    de_recycle_aino (unit, aino);
+    notify_check (unit, aino);
+    updatedirtime (aino, 0);
+    PUT_PCK_RES1 (packet, make_lock (unit, aino->uniq, -2) >> 2);
+}
+
+static void
+action_examine_fh (Unit *unit, dpacket packet)
+{
+    Key *k;
+    a_inode *aino = 0;
+    uaecptr info = GET_PCK_ARG2 (packet) << 2;
+
+    TRACE(("ACTION_EXAMINE_FH(0x%lx,0x%lx)\n",
+          GET_PCK_ARG1 (packet), GET_PCK_ARG2 (packet) ));
+
+    k = lookup_key (unit, GET_PCK_ARG1 (packet));
+    if (k != 0)
+       aino = k->aino;
+    if (aino == 0)
+       aino = &unit->rootnode;
+
+    get_fileinfo (unit, packet, info, aino);
+    if (aino->dir)
+       put_long (info, 0xFFFFFFFF);
+    else
+       put_long (info, 0);
+}
+
+/* For a nice example of just how contradictory documentation can be, see the
+ * Autodoc for DOS:SetFileSize and the Packets.txt description of this packet...
+ * This implementation tries to mimic the behaviour of the Kick 3.1 ramdisk
+ * (which seems to match the Autodoc description). */
+static void
+action_set_file_size (Unit *unit, dpacket packet)
+{
+    Key *k, *k1;
+    off_t offset = GET_PCK_ARG2 (packet);
+    long mode = (uae_s32)GET_PCK_ARG3 (packet);
+    int whence = SEEK_CUR;
+
+    if (mode > 0) whence = SEEK_END;
+    if (mode < 0) whence = SEEK_SET;
+
+    TRACE(("ACTION_SET_FILE_SIZE(0x%lx, %d, 0x%x)\n", GET_PCK_ARG1 (packet), offset, mode));
+
+    k = lookup_key (unit, GET_PCK_ARG1 (packet));
+    if (k == 0) {
+       PUT_PCK_RES1 (packet, DOS_TRUE);
+       PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
+       return;
+    }
+
+    k->notifyactive = 1;
+    /* If any open files have file pointers beyond this size, truncate only
+     * so far that these pointers do not become invalid.  */
+    for (k1 = unit->keys; k1; k1 = k1->next) {
+       if (k != k1 && k->aino == k1->aino) {
+           if (k1->file_pos > offset)
+               offset = k1->file_pos;
+       }
+    }
+
+    /* Write one then truncate: that should give the right size in all cases.  */
+    offset = lseek (k->fd, offset, whence);
+    write (k->fd, /* whatever */(char *)&k1, 1);
+    if (k->file_pos > offset)
+       k->file_pos = offset;
+    lseek (k->fd, k->file_pos, SEEK_SET);
+
+    /* Brian: no bug here; the file _must_ be one byte too large after writing
+       The write is supposed to guarantee that the file can't be smaller than
+       the requested size, the truncate guarantees that it can't be larger.
+       If we were to write one byte earlier we'd clobber file data.  */
+    if (truncate (k->aino->nname, offset) == -1) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, dos_errno ());
+       return;
+    }
+
+    PUT_PCK_RES1 (packet, offset);
+    PUT_PCK_RES2 (packet, 0);
+}
+
+static void
+action_delete_object (Unit *unit, dpacket packet)
+{
+    uaecptr lock = GET_PCK_ARG1 (packet) << 2;
+    uaecptr name = GET_PCK_ARG2 (packet) << 2;
+    a_inode *a;
+    uae_u32 err;
+
+    TRACE(("ACTION_DELETE_OBJECT(0x%lx,\"%s\")\n", lock, bstr (unit, name)));
+
+    if (unit->ui.readonly) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
+       return;
+    }
+
+    a = find_aino (unit, lock, bstr (unit, name), &err);
+
+    if (err != 0) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, err);
+       return;
+    }
+    if (a->amigaos_mode & A_FIBF_DELETE) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, ERROR_DELETE_PROTECTED);
+       return;
+    }
+    if (a->shlock > 0 || a->elock) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
+       return;
+    }
+    if (a->dir) {
+       /* This should take care of removing the fsdb if no files remain.  */
+       fsdb_dir_writeback (a);
+       if (rmdir (a->nname) == -1) {
+           PUT_PCK_RES1 (packet, DOS_FALSE);
+           PUT_PCK_RES2 (packet, dos_errno());
+           return;
+       }
+    } else {
+       if (unlink (a->nname) == -1) {
+            PUT_PCK_RES1 (packet, DOS_FALSE);
+           PUT_PCK_RES2 (packet, dos_errno());
+           return;
+       }
+    }
+    notify_check (unit, a);
+    updatedirtime (a, 1);
+    if (a->child != 0) {
+       write_log ("Serious error in action_delete_object.\n");
+    } else {
+       delete_aino (unit, a);
+    }
+    PUT_PCK_RES1 (packet, DOS_TRUE);
+}
+
+static void
+action_set_date (Unit *unit, dpacket packet)
+{
+    uaecptr lock = GET_PCK_ARG2 (packet) << 2;
+    uaecptr name = GET_PCK_ARG3 (packet) << 2;
+    uaecptr date = GET_PCK_ARG4 (packet);
+    a_inode *a;
+    struct utimbuf ut;
+    uae_u32 err;
+
+    TRACE(("ACTION_SET_DATE(0x%lx,\"%s\")\n", lock, bstr (unit, name)));
+
+    if (unit->ui.readonly) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
+       return;
+    }
+
+    ut.actime = ut.modtime = put_time(get_long (date), get_long (date + 4),
+                                     get_long (date + 8));
+    a = find_aino (unit, lock, bstr (unit, name), &err);
+    if (err == 0 && utime (a->nname, &ut) == -1)
+       err = dos_errno ();
+    if (err != 0) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, err);
+    } else
+       PUT_PCK_RES1 (packet, DOS_TRUE);
+    notify_check (unit, a);
+}
+
+static void
+action_rename_object (Unit *unit, dpacket packet)
+{
+    uaecptr lock1 = GET_PCK_ARG1 (packet) << 2;
+    uaecptr name1 = GET_PCK_ARG2 (packet) << 2;
+    uaecptr lock2 = GET_PCK_ARG3 (packet) << 2;
+    uaecptr name2 = GET_PCK_ARG4 (packet) << 2;
+    a_inode *a1, *a2;
+    uae_u32 err1, err2;
+    Key *k1, *knext;
+    int wehavekeys = 0;
+
+    TRACE(("ACTION_RENAME_OBJECT(0x%lx,\"%s\",", lock1, bstr (unit, name1)));
+    TRACE(("0x%lx,\"%s\")\n", lock2, bstr (unit, name2)));
+
+    if (unit->ui.readonly) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
+       return;
+    }
+
+    a1 = find_aino (unit, lock1, bstr (unit, name1), &err1);
+    if (err1 != 0) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, err1);
+       return;
+    }
+
+    /* rename always fails if file is open for writing */
+    for (k1 = unit->keys; k1; k1 = knext) {
+        knext = k1->next;
+       if (k1->aino == a1 && k1->fd >= 0 && k1->createmode == 2) {
+           PUT_PCK_RES1 (packet, DOS_FALSE);
+           PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
+           return;
+       }
+    }
+
+    /* See whether the other name already exists in the filesystem.  */
+    a2 = find_aino (unit, lock2, bstr (unit, name2), &err2);
+
+    if (a2 == a1) {
+       /* Renaming to the same name, but possibly different case.  */
+       if (strcmp (a1->aname, bstr_cut (unit, name2)) == 0) {
+           /* Exact match -> do nothing.  */
+           notify_check (unit, a1);
+           updatedirtime (a1, 1);
+           PUT_PCK_RES1 (packet, DOS_TRUE);
+           return;
+       }
+       a2 = a2->parent;
+    } else if (a2 == 0 || err2 != ERROR_OBJECT_NOT_AROUND) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, err2 == 0 ? ERROR_OBJECT_EXISTS : err2);
+       return;
+    }
+
+    a2 = create_child_aino (unit, a2, bstr_cut (unit, name2), a1->dir);
+    if (a2 == 0) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, ERROR_DISK_IS_FULL); /* best we can do */
+       return;
+    }
+
+    if (-1 == rename (a1->nname, a2->nname)) {
+       int ret = -1;
+       /* maybe we have open file handles that caused failure? */
+       write_log ("rename '%s' -> '%s' failed, trying relocking..\n", a1->nname, a2->nname);
+       for (k1 = unit->keys; k1; k1 = knext) {
+           knext = k1->next;
+           if (k1->aino == a1 && k1->fd >= 0) {
+               wehavekeys++;
+               close (k1->fd);
+               write_log ("handle %d freed\n", k1->fd);
+           }
+        }
+       /* try again... */
+       ret = rename (a1->nname, a2->nname);
+       for (k1 = unit->keys; k1; k1 = knext) {
+           knext = k1->next;
+           if (k1->aino == a1 && k1->fd >= 0) {
+               int mode = (k1->dosmode & A_FIBF_READ) == 0 ? O_WRONLY : (k1->dosmode & A_FIBF_WRITE) == 0 ? O_RDONLY : O_RDWR;
+               mode |= O_BINARY;
+               if (ret == -1) {
+                   /* rename still failed, restore fd */
+                   k1->fd = open (a1->nname, mode, 0777);
+                   write_log ("restoring old handle '%s' %d\n", a1->nname, k1->dosmode);
+               } else {
+                   /* transfer fd to new name */
+                   k1->aino = a2;
+                   k1->fd = open (a2->nname, mode, 0777);
+                   write_log ("restoring new handle '%s' %d\n", a2->nname, k1->dosmode);
+               }
+               if (k1->fd < 0) {
+                   write_log ("relocking failed '%s' -> '%s'\n", a1->nname, a2->nname);
+                   free_key (unit, k1);
+               } else {
+                   lseek (k1->fd, k1->file_pos, SEEK_SET);
+               }
+           }
+        }
+       if (ret == -1) {
+           delete_aino (unit, a2);
+           PUT_PCK_RES1 (packet, DOS_FALSE);
+           PUT_PCK_RES2 (packet, dos_errno ());
+           return;
+       }
+    }
+
+    notify_check (unit, a1);
+    notify_check (unit, a2);
+    a2->comment = a1->comment;
+    a1->comment = 0;
+    a2->amigaos_mode = a1->amigaos_mode;
+    a2->uniq = a1->uniq;
+    a2->elock = a1->elock;
+    a2->shlock = a1->shlock;
+    a2->has_dbentry = a1->has_dbentry;
+    a2->db_offset = a1->db_offset;
+    a2->dirty = 0;
+    move_exkeys (unit, a1, a2);
+    move_aino_children (unit, a1, a2);
+    delete_aino (unit, a1);
+    a2->dirty = 1;
+    if (a2->parent)
+       fsdb_dir_writeback (a2->parent);
+    updatedirtime (a2, 1);
+    if (a2->elock > 0 || a2->shlock > 0 || wehavekeys > 0)
+       de_recycle_aino (unit, a2);
+    PUT_PCK_RES1 (packet, DOS_TRUE);
+}
+
+static void
+action_current_volume (Unit *unit, dpacket packet)
+{
+    PUT_PCK_RES1 (packet, unit->volume >> 2);
+}
+
+static void
+action_rename_disk (Unit *unit, dpacket packet)
+{
+    uaecptr name = GET_PCK_ARG1 (packet) << 2;
+    int i;
+    int namelen;
+
+    TRACE(("ACTION_RENAME_DISK(\"%s\")\n", bstr (unit, name)));
+
+    if (unit->ui.readonly) {
+       PUT_PCK_RES1 (packet, DOS_FALSE);
+       PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
+       return;
+    }
+
+    /* get volume name */
+    namelen = get_byte (name); name++;
+    xfree (unit->ui.volname);
+    unit->ui.volname = (char *) xmalloc (namelen + 1);
+    for (i = 0; i < namelen; i++, name++)
+       unit->ui.volname[i] = get_byte (name);
+    unit->ui.volname[i] = 0;
+
+    put_byte (unit->volume + 44, namelen);
+    for (i = 0; i < namelen; i++)
+       put_byte (unit->volume + 45 + i, unit->ui.volname[i]);
+
+    PUT_PCK_RES1 (packet, DOS_TRUE);
+}
+
+static void
+action_is_filesystem (Unit *unit, dpacket packet)
+{
+    PUT_PCK_RES1 (packet, DOS_TRUE);
+}
+
+static void
+action_flush (Unit *unit, dpacket packet)
+{
+    /* sync(); */ /* pretty drastic, eh */
+    PUT_PCK_RES1 (packet, DOS_TRUE);
+}
+
+/* We don't want multiple interrupts to be active at the same time. I don't
+ * know whether AmigaOS takes care of that, but this does. */
+static uae_sem_t singlethread_int_sem;
+
+static uae_u32 exter_int_helper (void)
+{
+    UnitInfo *uip = current_mountinfo->ui;
+    uaecptr port;
+    static int unit_no;
+
+    switch (m68k_dreg (regs, 0)) {
+     case 0:
+       /* Determine whether a given EXTER interrupt is for us. */
+       if (uae_int_requested) {
+           if (uae_sem_trywait (&singlethread_int_sem) != 0)
+               /* Pretend it isn't for us. We might get it again later. */
+               return 0;
+           /* Clear the interrupt flag _before_ we do any processing.
+            * That way, we can get too many interrupts, but never not
+            * enough. */
+           uae_int_requested = 0;
+           unit_no = 0;
+           return 1;
+       }
+       return 0;
+     case 1:
+       /* Release a message_lock. This is called as soon as the message is
+        * received by the assembly code. We use the opportunity to check
+        * whether we have some locks that we can give back to the assembler
+        * code.
+        * Note that this is called from the main loop, unlike the other cases
+        * in this switch statement which are called from the interrupt handler.
+        */
+#ifdef UAE_FILESYS_THREADS
+       {
+           Unit *unit = find_unit (m68k_areg (regs, 5));
+           uaecptr msg = m68k_areg (regs, 4);
+           unit->cmds_complete = unit->cmds_acked;
+           while (comm_pipe_has_data (unit->ui.back_pipe)) {
+               uaecptr locks, lockend;
+               locks = read_comm_pipe_int_blocking (unit->ui.back_pipe);
+               lockend = locks;
+               while (get_long (lockend) != 0)
+                   lockend = get_long (lockend);
+               put_long (lockend, get_long (m68k_areg (regs, 3)));
+               put_long (m68k_areg (regs, 3), locks);
+           }
+       }
+#else
+       write_log ("exter_int_helper should not be called with arg 1!\n");
+#endif
+       break;
+     case 2:
+       /* Find work that needs to be done:
+        * return d0 = 0: none
+        *        d0 = 1: PutMsg(), port in a0, message in a1
+        *        d0 = 2: Signal(), task in a1, signal set in d1
+        *        d0 = 3: ReplyMsg(), message in a1
+        *        d0 = 4: Cause(), interrupt in a1
+        *        d0 = 5: AllocMem(), size in d0, flags in d1, pointer to address at a0
+        *        d0 = 6: FreeMem(), memory in a1, size in d0
+        */
+
+#ifdef SUPPORT_THREADS
+       /* First, check signals/messages */
+       while (comm_pipe_has_data (&native2amiga_pending)) {
+           int cmd = read_comm_pipe_int_blocking (&native2amiga_pending);
+           switch (cmd) {
+            case 0: /* Signal() */
+               m68k_areg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending);
+               m68k_dreg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending);
+               return 2;
+
+            case 1: /* PutMsg() */
+               m68k_areg (regs, 0) = read_comm_pipe_u32_blocking (&native2amiga_pending);
+               m68k_areg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending);
+               return 1;
+
+            case 2: /* ReplyMsg() */
+               m68k_areg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending);
+               return 3;
+
+            case 3: /* Cause() */
+               m68k_areg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending);
+               return 4;
+
+            case 4: /* NotifyHack() */
+               m68k_areg (regs, 0) = read_comm_pipe_u32_blocking (&native2amiga_pending);
+               m68k_areg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending);
+               return 5;
+
+            default:
+               write_log ("exter_int_helper: unknown native action %X\n", cmd);
+               break;
+           }
+       }
+#endif
+
+       /* Find some unit that needs a message sent, and return its port,
+        * or zero if all are done.
+        * Take care not to dereference self for units that didn't have their
+        * startup packet sent. */
+       for (;;) {
+           if (unit_no >= current_mountinfo->num_units)
+               return 0;
+
+           if (uip[unit_no].self != 0
+               && uip[unit_no].self->cmds_acked == uip[unit_no].self->cmds_complete
+               && uip[unit_no].self->cmds_acked != uip[unit_no].self->cmds_sent)
+               break;
+           unit_no++;
+       }
+       uip[unit_no].self->cmds_acked = uip[unit_no].self->cmds_sent;
+       port = uip[unit_no].self->port;
+       if (port) {
+           m68k_areg (regs, 0) = port;
+           m68k_areg (regs, 1) = find_unit (port)->dummy_message;
+           unit_no++;
+           return 1;
+       }
+       break;
+     case 4:
+       /* Exit the interrupt, and release the single-threading lock. */
+       uae_sem_post (&singlethread_int_sem);
+       break;
+
+     default:
+       write_log ("Shouldn't happen in exter_int_helper.\n");
+       break;
+    }
+    return 0;
+}
+
+static int handle_packet (Unit *unit, dpacket pck)
+{
+    uae_s32 type = GET_PCK_TYPE (pck);
+    PUT_PCK_RES2 (pck, 0);
+    switch (type) {
+     case ACTION_LOCATE_OBJECT: action_lock (unit, pck); break;
+     case ACTION_FREE_LOCK: action_free_lock (unit, pck); break;
+     case ACTION_COPY_DIR: action_dup_lock (unit, pck); break;
+     case ACTION_DISK_INFO: action_disk_info (unit, pck); break;
+     case ACTION_INFO: action_info (unit, pck); break;
+     case ACTION_EXAMINE_OBJECT: action_examine_object (unit, pck); break;
+     case ACTION_EXAMINE_NEXT: action_examine_next (unit, pck); break;
+     case ACTION_FIND_INPUT: action_find_input (unit, pck); break;
+     case ACTION_FIND_WRITE: action_find_write (unit, pck); break;
+     case ACTION_FIND_OUTPUT: action_find_output (unit, pck); break;
+     case ACTION_END: action_end (unit, pck); break;
+     case ACTION_READ: action_read (unit, pck); break;
+     case ACTION_WRITE: action_write (unit, pck); break;
+     case ACTION_SEEK: action_seek (unit, pck); break;
+     case ACTION_SET_PROTECT: action_set_protect (unit, pck); break;
+     case ACTION_SET_COMMENT: action_set_comment (unit, pck); break;
+     case ACTION_SAME_LOCK: action_same_lock (unit, pck); break;
+     case ACTION_PARENT: action_parent (unit, pck); break;
+     case ACTION_CREATE_DIR: action_create_dir (unit, pck); break;
+     case ACTION_DELETE_OBJECT: action_delete_object (unit, pck); break;
+     case ACTION_RENAME_OBJECT: action_rename_object (unit, pck); break;
+     case ACTION_SET_DATE: action_set_date (unit, pck); break;
+     case ACTION_CURRENT_VOLUME: action_current_volume (unit, pck); break;
+     case ACTION_RENAME_DISK: action_rename_disk (unit, pck); break;
+     case ACTION_IS_FILESYSTEM: action_is_filesystem (unit, pck); break;
+     case ACTION_FLUSH: action_flush (unit, pck); break;
+
+     /* 2.0+ packet types */
+     case ACTION_SET_FILE_SIZE: action_set_file_size (unit, pck); break;
+     case ACTION_EXAMINE_FH: action_examine_fh (unit, pck); break;
+     case ACTION_FH_FROM_LOCK: action_fh_from_lock (unit, pck); break;
+     case ACTION_CHANGE_MODE: action_change_mode (unit, pck); break;
+     case ACTION_PARENT_FH: action_parent_fh (unit, pck); break;
+     case ACTION_ADD_NOTIFY: action_add_notify (unit, pck); break;
+     case ACTION_REMOVE_NOTIFY: action_remove_notify (unit, pck); break;
+
+     /* unsupported packets */
+     case ACTION_LOCK_RECORD:
+     case ACTION_FREE_RECORD:
+     case ACTION_COPY_DIR_FH:
+     case ACTION_EXAMINE_ALL:
+     case ACTION_MAKE_LINK:
+     case ACTION_READ_LINK:
+     case ACTION_FORMAT:
+     default:
+       TRACE(("*** UNSUPPORTED PACKET %ld\n", type));
+       return 0;
+    }
+    return 1;
+}
+
+#ifdef UAE_FILESYS_THREADS
+static void *filesys_thread (void *unit_v)
+{
+    UnitInfo *ui = (UnitInfo *)unit_v;
+
+    set_thread_priority (2);
+    for (;;) {
+       uae_u8 *pck;
+       uae_u8 *msg;
+       uae_u32 morelocks;
+
+       pck = (uae_u8 *)read_comm_pipe_pvoid_blocking (ui->unit_pipe);
+       msg = (uae_u8 *)read_comm_pipe_pvoid_blocking (ui->unit_pipe);
+       morelocks = (uae_u32)read_comm_pipe_int_blocking (ui->unit_pipe);
+
+       if (ui->reset_state == FS_GO_DOWN) {
+           if (pck != 0)
+               continue;
+           /* Death message received. */
+           uae_sem_post (&ui->reset_sync_sem);
+           /* Die.  */
+           return 0;
+       }
+
+       put_long (get_long (morelocks), get_long (ui->self->locklist));
+       put_long (ui->self->locklist, morelocks);
+       if (! handle_packet (ui->self, pck)) {
+           PUT_PCK_RES1 (pck, DOS_FALSE);
+           PUT_PCK_RES2 (pck, ERROR_ACTION_NOT_KNOWN);
+       }
+       /* Mark the packet as processed for the list scan in the assembly code. */
+       do_put_mem_long ((uae_u32 *)(msg + 4), -1);
+       /* Acquire the message lock, so that we know we can safely send the
+        * message. */
+       ui->self->cmds_sent++;
+       /* The message is sent by our interrupt handler, so make sure an interrupt
+        * happens. */
+       uae_int_requested = 1;
+       /* Send back the locks. */
+       if (get_long (ui->self->locklist) != 0)
+           write_comm_pipe_int (ui->back_pipe, (int)(get_long (ui->self->locklist)), 0);
+       put_long (ui->self->locklist, 0);
+    }
+    return 0;
+}
+#endif
+
+/* Talk about spaghetti code... */
+static uae_u32 filesys_handler (void)
+{
+    Unit *unit = find_unit (m68k_areg (regs, 5));
+    uaecptr packet_addr = m68k_dreg (regs, 3);
+    uaecptr message_addr = m68k_areg (regs, 4);
+    uae_u8 *pck;
+    uae_u8 *msg;
+    if (! valid_address (packet_addr, 36) || ! valid_address (message_addr, 14)) {
+       write_log ("Bad address passed for packet.\n");
+       goto error2;
+    }
+    pck = get_real_address (packet_addr);
+    msg = get_real_address (message_addr);
+
+#if 0
+    if (unit->reset_state == FS_GO_DOWN)
+       /* You might as well queue it, if you live long enough */
+       return 1;
+#endif
+
+    do_put_mem_long ((uae_u32 *)(msg + 4), -1);
+    if (!unit || !unit->volume) {
+       write_log ("Filesystem was not initialized.\n");
+       goto error;
+    }
+#ifdef UAE_FILESYS_THREADS
+    {
+       uae_u32 morelocks;
+       if (!unit->ui.unit_pipe)
+           goto error;
+       /* Get two more locks and hand them over to the other thread. */
+       morelocks = get_long (m68k_areg (regs, 3));
+       put_long (m68k_areg (regs, 3), get_long (get_long (morelocks)));
+       put_long (get_long (morelocks), 0);
+
+       /* The packet wasn't processed yet. */
+       do_put_mem_long ((uae_u32 *)(msg + 4), 0);
+       write_comm_pipe_pvoid (unit->ui.unit_pipe, (void *)pck, 0);
+       write_comm_pipe_pvoid (unit->ui.unit_pipe, (void *)msg, 0);
+       write_comm_pipe_int (unit->ui.unit_pipe, (int)morelocks, 1);
+       /* Don't reply yet. */
+       return 1;
+    }
+#endif
+
+    if (! handle_packet (unit, pck)) {
+       error:
+       PUT_PCK_RES1 (pck, DOS_FALSE);
+       PUT_PCK_RES2 (pck, ERROR_ACTION_NOT_KNOWN);
+    }
+    TRACE(("reply: %8lx, %ld\n", GET_PCK_RES1 (pck), GET_PCK_RES2 (pck)));
+
+    error2:
+
+    return 0;
+}
+
+void filesys_start_threads (void)
+{
+    UnitInfo *uip;
+    int i;
+
+    current_mountinfo = currprefs.mountinfo;
+    uip = current_mountinfo->ui;
+    for (i = 0; i < current_mountinfo->num_units; i++) {
+       UnitInfo *ui = &uip[i];
+       ui->unit_pipe = 0;
+       ui->back_pipe = 0;
+       ui->startup = 0;
+       ui->reset_state = 0;
+       ui->self = 0;
+#ifdef UAE_FILESYS_THREADS
+       if (is_hardfile (current_mountinfo, i) == FILESYS_VIRTUAL) {
+           ui->unit_pipe = (smp_comm_pipe *)xmalloc (sizeof (smp_comm_pipe));
+           ui->back_pipe = (smp_comm_pipe *)xmalloc (sizeof (smp_comm_pipe));
+           init_comm_pipe (uip[i].unit_pipe, 100, 3);
+           init_comm_pipe (uip[i].back_pipe, 100, 1);
+           uae_start_thread (filesys_thread, (void *)(uip + i), &uip[i].tid);
+       }
+#endif
+    }
+}
+
+void filesys_reset (void)
+{
+    Unit *u, *u1;
+
+    /* We get called once from customreset at the beginning of the program
+     * before filesys_start_threads has been called. Survive that.  */
+    if (current_mountinfo == 0)
+       return;
+
+    for (u = units; u; u = u1) {
+       u1 = u->next;
+       xfree (u);
+    }
+    unit_num = 0;
+    units = 0;
+    current_mountinfo = 0;
+}
+
+static void free_all_ainos (Unit *u, a_inode *parent)
+{
+    a_inode *a;
+    while (a = parent->child) {
+       free_all_ainos (u, a);
+       dispose_aino (u, &parent->child, a);
+    }
+}
+
+void filesys_flush_cache (void)
+{
+}
+
+void filesys_prepare_reset (void)
+{
+    UnitInfo *uip = current_mountinfo->ui;
+    Unit *u;
+    int i;
+
+#ifdef UAE_FILESYS_THREADS
+    for (i = 0; i < current_mountinfo->num_units; i++) {
+       if (uip[i].unit_pipe != 0) {
+           uae_sem_init (&uip[i].reset_sync_sem, 0, 0);
+           uip[i].reset_state = FS_GO_DOWN;
+           /* send death message */
+           write_comm_pipe_int (uip[i].unit_pipe, 0, 0);
+           write_comm_pipe_int (uip[i].unit_pipe, 0, 0);
+           write_comm_pipe_int (uip[i].unit_pipe, 0, 1);
+           uae_sem_wait (&uip[i].reset_sync_sem);
+       }
+    }
+#endif
+    u = units;
+    while (u != 0) {
+       free_all_ainos (u, &u->rootnode);
+       u->rootnode.next = u->rootnode.prev = &u->rootnode;
+       u->aino_cache_size = 0;
+       u = u->next;
+    }
+}
+
+static uae_u32 filesys_diagentry (void)
+{
+    uaecptr resaddr = m68k_areg (regs, 2) + 0x10;
+    uaecptr start = resaddr;
+    uaecptr residents, tmp;
+
+    TRACE (("filesystem: diagentry called\n"));
+
+    filesys_configdev = m68k_areg (regs, 3);
+
+    do_put_mem_long ((uae_u32 *)(filesysory + 0x2100), EXPANSION_explibname);
+    do_put_mem_long ((uae_u32 *)(filesysory + 0x2104), filesys_configdev);
+    do_put_mem_long ((uae_u32 *)(filesysory + 0x2108), EXPANSION_doslibname);
+    do_put_mem_long ((uae_u32 *)(filesysory + 0x210c), current_mountinfo->num_units);
+
+    uae_sem_init (&singlethread_int_sem, 0, 1);
+    if (ROM_hardfile_resid != 0) {
+       /* Build a struct Resident. This will set up and initialize
+        * the uae.device */
+       put_word (resaddr + 0x0, 0x4AFC);
+       put_long (resaddr + 0x2, resaddr);
+       put_long (resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */
+       put_word (resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */
+       put_word (resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */
+       put_long (resaddr + 0xE, ROM_hardfile_resname);
+       put_long (resaddr + 0x12, ROM_hardfile_resid);
+       put_long (resaddr + 0x16, ROM_hardfile_init); /* calls filesys_init */
+    }
+    resaddr += 0x1A;
+    tmp = resaddr;
+    
+    /* The good thing about this function is that it always gets called
+     * when we boot. So we could put all sorts of stuff that wants to be done
+     * here.
+     * We can simply add more Resident structures here. Although the Amiga OS
+     * only knows about the one at address DiagArea + 0x10, we scan for other
+     * Resident structures and call InitResident() for them at the end of the
+     * diag entry. */
+
+    resaddr = scsidev_startup(resaddr);
+    native2amiga_startup();
+
+    /* scan for Residents and return pointer to array of them */
+    residents = resaddr;
+    while (tmp < residents && tmp > start) {
+       if (get_word (tmp) == 0x4AFC &&
+           get_long (tmp + 0x2) == tmp) {
+           put_word (resaddr, 0x227C);         /* movea.l #tmp,a1 */
+           put_long (resaddr + 2, tmp);
+           put_word (resaddr + 6, 0x7200);     /* moveq.l #0,d1 */
+           put_long (resaddr + 8, 0x4EAEFF9A); /* jsr -$66(a6) ; InitResident */
+           resaddr += 12;
+           tmp = get_long (tmp + 0x6);
+       } else {
+           tmp++;
+       }
+    }
+    /* call setup_exter */
+    put_word (resaddr +  0, 0x2079);
+    put_long (resaddr +  2, RTAREA_BASE + 28 + 4); /* move.l RTAREA_BASE+32,a0 */
+    put_word (resaddr +  6, 0xd1fc);
+    put_long (resaddr +  8, RTAREA_BASE + 8 + 4); /* add.l #RTAREA_BASE+12,a0 */
+    put_word (resaddr + 12, 0x4e90); /* jsr (a0) */
+    put_word (resaddr + 14, 0x7001); /* moveq.l #1,d0 */
+    put_word (resaddr + 16, RTS);
+
+    m68k_areg (regs, 0) = residents;
+    return 1;
+}
+
+/* don't forget filesys.asm! */
+#define PP_MAXSIZE 4 * 96
+#define PP_FSSIZE 400
+#define PP_FSPTR 404
+#define PP_FSRES 408
+#define PP_EXPLIB 412
+#define PP_FSHDSTART 416
+
+static uae_u32 filesys_dev_bootfilesys (void)
+{
+    uaecptr devicenode = m68k_areg (regs, 3);
+    uaecptr parmpacket = m68k_areg (regs, 1);
+    uaecptr fsres = get_long (parmpacket + PP_FSRES);
+    uaecptr fsnode;
+    uae_u32 dostype, dostype2;
+    UnitInfo *uip = current_mountinfo->ui;
+    int no = m68k_dreg (regs, 6);
+    int unit_no = no & 65535;
+    int type = is_hardfile (current_mountinfo, unit_no);
+
+    if (type == FILESYS_VIRTUAL)
+       return 0;
+    dostype = get_long (parmpacket + 80);
+    fsnode = get_long (fsres + 18);
+    while (get_long (fsnode)) {
+        dostype2 = get_long (fsnode + 14);
+        if (dostype2 == dostype) {
+           if (get_long (fsnode + 22) & (1 << 7)) {
+               put_long (devicenode + 32, get_long (fsnode + 54)); /* dn_SegList */
+               put_long (devicenode + 36, -1); /* dn_GlobalVec */
+           }
+           return 1;
+        }
+        fsnode = get_long (fsnode);
+    }
+    return 0;
+}
+
+/* Remember a pointer AmigaOS gave us so we can later use it to identify
+ * which unit a given startup message belongs to.  */
+static uae_u32 filesys_dev_remember (void)
+{
+    int no = m68k_dreg (regs, 6);
+    int unit_no = no & 65535;
+    int sub_no = no >> 16;
+    UnitInfo *uip = &current_mountinfo->ui[unit_no];
+    int i;
+    uaecptr devicenode = m68k_areg (regs, 3);
+    uaecptr parmpacket = m68k_areg (regs, 1);
+
+    /* copy filesystem loaded from RDB */
+    if (get_long (parmpacket + PP_FSPTR)) {
+       for (i = 0; i < uip->rdb_filesyssize; i++)
+           put_byte (get_long (parmpacket + PP_FSPTR) + i, uip->rdb_filesysstore[i]);
+       xfree (uip->rdb_filesysstore);
+       uip->rdb_filesysstore = 0;
+       uip->rdb_filesyssize = 0;
+    }
+    if (m68k_dreg (regs, 3) >= 0)
+        uip->startup = get_long (devicenode + 28);
+    return devicenode;
+}
+
+static int legalrdbblock (UnitInfo *uip, int block)
+{
+    if (block <= 0)
+       return 0;
+    if (block >= uip->hf.size / uip->hf.blocksize)
+       return 0;
+    return 1;
+}
+
+static int rl (uae_u8 *p)
+{
+    return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
+}
+
+static int rdb_checksum (char *id, uae_u8 *p, int block)
+{
+    uae_u32 sum = 0;
+    int i, blocksize;
+
+    if (memcmp (id, p, 4))
+       return 0;
+    blocksize = rl (p + 4);
+    if (blocksize < 1 || blocksize * 4 > FILESYS_MAX_BLOCKSIZE)
+       return 0;
+    for (i = 0; i < blocksize; i++)
+       sum += rl (p + i * 4);
+    sum = -sum;
+    if (sum) {
+       write_log ("RDB: block %d ('%s') checksum error\n", block, id);
+       return 1;
+    }
+    return 1;
+}
+
+static char *device_dupfix (uaecptr expbase, char *devname)
+{
+    uaecptr bnode, dnode, name;
+    int len, i, modified;
+    char dname[256], newname[256];
+
+    strcpy (newname, devname);
+    modified = 1;
+    while (modified) {
+       modified = 0;
+       bnode = get_long (expbase + 74); /* expansion.library bootnode list */
+       while (get_long (bnode)) {
+           dnode = get_long (bnode + 16); /* device node */
+           name = get_long (dnode + 40) << 2; /* device name BSTR */
+           len = get_byte(name);
+           for (i = 0; i < len; i++)
+               dname[i] = get_byte (name + 1 + i);
+           dname[len] = 0;
+           for (;;) {
+               if (!strcmpi (newname, dname)) {
+                   if (strlen (newname) > 2 && newname[strlen (newname) - 2] == '_') {
+                       newname[strlen (newname) - 1]++;
+                   } else {
+                       strcat (newname, "_0");
+                   }
+                   modified = 1;
+               } else {
+                   break;
+               }
+           }
+           bnode = get_long (bnode);
+       }
+    }
+    return strdup (newname);
+}
+
+static int rdb_mount (UnitInfo *uip, int unit_no, int partnum, uaecptr parmpacket)
+{
+    int lastblock = 63, blocksize, readblocksize, badblock, driveinitblock;
+    uae_u8 bufrdb[FILESYS_MAX_BLOCKSIZE], *buf = 0;
+    uae_u8 *fsmem = 0;
+    int rdblock, partblock, fileblock, lsegblock, i;
+    uae_u32 flags;
+    struct hardfiledata *hfd = &uip->hf;
+    uae_u32 dostype;
+    uaecptr fsres, fsnode;
+    int err = 0;
+    int oldversion, oldrevision;
+    int newversion, newrevision;
+
+    if (lastblock * hfd->blocksize > hfd->size)
+       return -2;
+    for (rdblock = 0; rdblock < lastblock; rdblock++) {
+       hdf_read (hfd, bufrdb, rdblock * hfd->blocksize, hfd->blocksize);
+       if (rdb_checksum ("RDSK", bufrdb, rdblock))
+           break;
+       hdf_read (hfd, bufrdb, rdblock * hfd->blocksize, hfd->blocksize);
+       if (!memcmp ("RDSK", bufrdb, 4)) {
+           bufrdb[0xdc] = 0;
+           bufrdb[0xdd] = 0;
+           bufrdb[0xde] = 0;
+           bufrdb[0xdf] = 0;
+           if (rdb_checksum ("RDSK", bufrdb, rdblock)) {
+               write_log ("Windows trashed RDB detected, fixing..\n");
+               hdf_write (hfd, bufrdb, rdblock * hfd->blocksize, hfd->blocksize);
+               break;
+           }
+       }
+    }
+    if (rdblock == lastblock)
+       return -2;
+    blocksize = rl (bufrdb + 16);
+    readblocksize = blocksize > hfd->blocksize ? blocksize : hfd->blocksize;
+    badblock = rl (bufrdb + 24);
+    if (badblock != -1) {
+       write_log ("RDB: badblock list is not yet supported. Contact the author.\n");
+       return -2;
+    }
+    driveinitblock = rl (bufrdb + 36);
+    if (driveinitblock != -1) {
+       write_log ("RDB: driveinit is not yet supported. Contact the author.\n");
+       return -2;
+    }
+    fileblock = rl (bufrdb + 32);
+    partblock = rl (bufrdb + 28);
+    buf = xmalloc (readblocksize);
+    for (i = 0; i <= partnum; i++) {
+       if (!legalrdbblock (uip, partblock)) {
+           err = -2;
+           goto error;
+       }
+       hdf_read (hfd, buf, partblock * hfd->blocksize, readblocksize);
+       if (!rdb_checksum ("PART", buf, partblock)) {
+           err = -2;
+           goto error;
+       }
+       partblock = rl (buf + 4 * 4);
+    }
+
+    flags = rl (buf + 20);
+    if (flags & 2) { /* do not mount */
+       err = -1;
+       goto error;
+    }
+
+    if (!(flags & 1)) /* not bootable */
+       m68k_dreg (regs, 7) = 0;
+
+    buf[37 + buf[36]] = 0; /* zero terminate BSTR */
+    uip->rdb_devname_amiga[partnum] = ds (device_dupfix (get_long (parmpacket + PP_EXPLIB), buf + 37));
+    put_long (parmpacket, uip->rdb_devname_amiga[partnum]); /* name */
+    put_long (parmpacket + 4, ROM_hardfile_resname);
+    put_long (parmpacket + 8, uip->devno);
+    put_long (parmpacket + 12, 0); /* Device flags */
+    for (i = 0; i < PP_MAXSIZE; i++)
+       put_byte (parmpacket + 16 + i, buf[128 + i]);
+    dostype = get_long (parmpacket + 80);
+    write_log ("RDB: '%s' uaehf.device:%d, dostype=%08.8X\n", buf + 37, uip->devno, dostype);
+
+    if (dostype == 0) {
+       err = -1;
+       goto error;
+    }
+    
+    err = 2;
+
+    /* load custom filesystems if needed */
+    if (!legalrdbblock (uip, fileblock))
+       goto error;
+    fsres = get_long (parmpacket + PP_FSRES);
+    if (!fsres) {
+       write_log ("FileSystem.resource not found, this shouldn't happen!\n");
+       goto error;
+    }
+
+    for (;;) {
+       if (!legalrdbblock (uip, fileblock)) {
+           err = -1;
+           goto error;
+       }
+       hdf_read (hfd, buf, fileblock * hfd->blocksize, readblocksize);
+       if (!rdb_checksum ("FSHD", buf, fileblock)) {
+           err = -1;
+           goto error;
+       }
+       fileblock = rl (buf + 16);
+       if ((dostype >> 8) == (rl (buf + 32) >> 8))
+           break;
+    }
+
+    fsnode = get_long (fsres + 18);
+    while (get_long (fsnode)) {
+       if (get_long (fsnode + 14) == dostype)
+           break;
+       fsnode = get_long (fsnode);
+    }
+
+    oldversion = oldrevision = -1;
+    newversion = (buf[36] << 8) | buf[37];
+    newrevision = (buf[38] << 8) | buf[39];
+    write_log ("RDB: RDB filesystem %08.8X version %d.%d\n", dostype, newversion, newrevision);
+    if (get_long (fsnode)) {
+       oldversion = get_word (fsnode + 18);
+       oldrevision = get_word (fsnode + 20);
+       write_log ("RDB: ROM filesystem version %d.%d\n", oldversion, oldrevision);
+    }
+    if (newversion * 65536 + newrevision <= oldversion * 65536 + oldrevision && oldversion >= 0) {
+       write_log ("RDB: ROM filesystem is newer or same, ignoring RDB filesystem\n");
+       goto error;
+    }
+
+    for (i = 0; i < 140; i++)
+       put_byte (parmpacket + PP_FSHDSTART + i, buf[32 + i]);
+    put_long (parmpacket + PP_FSHDSTART, dostype);
+    /* we found required FSHD block */
+    fsmem = xmalloc (262144);
+    lsegblock = rl (buf + 72);
+    i = 0;
+    for (;;) {
+       if (!legalrdbblock (uip, lsegblock))
+           goto error;
+       hdf_read (hfd, buf, lsegblock * hfd->blocksize, readblocksize);
+       if (!rdb_checksum ("LSEG", buf, lsegblock))
+           goto error;
+       lsegblock = rl (buf + 16);
+       memcpy (fsmem + i * (blocksize - 20), buf + 20, blocksize - 20);
+       i++;
+       if (lsegblock == -1)
+           break;
+    }
+    write_log ("RDB: Filesystem loaded, %d bytes\n", i * (blocksize - 20));
+    put_long (parmpacket + PP_FSSIZE, i * (blocksize - 20)); /* RDB filesystem size hack */
+    uip->rdb_filesysstore = fsmem;
+    uip->rdb_filesyssize = i * (blocksize - 20);
+    xfree (buf);
+    return 2;
+error:
+    xfree (buf);
+    xfree (fsmem);
+    return err;
+}
+
+static void addfakefilesys (uaecptr parmpacket, uae_u32 dostype)
+{
+    int i;
+
+    for (i = 0; i < 140; i++)
+       put_byte (parmpacket + PP_FSHDSTART + i, 0);
+    put_long (parmpacket + 80, dostype);
+    put_long (parmpacket + PP_FSHDSTART, dostype);
+    put_long (parmpacket + PP_FSHDSTART + 8, 0x100 | (dostype == 0x444f5300 ? 0x0 : 0x80));
+    put_long (parmpacket + PP_FSHDSTART + 44, 0xffffffff);
+}
+
+static void dofakefilesys (UnitInfo *uip, uaecptr parmpacket)
+{
+    int i, size;
+    char tmp[1024];
+    struct zfile *zf;
+    uae_u32 dostype, fsres, fsnode;
+
+    hdf_read (&uip->hf, tmp, 0, 4);
+    dostype = (tmp[0] << 24) | (tmp[1] << 16) |(tmp[2] << 8) | tmp[3];
+    if (dostype == 0)
+       return;
+    fsres = get_long (parmpacket + PP_FSRES);
+    fsnode = get_long (fsres + 18);
+    while (get_long (fsnode)) {
+       if (get_long (fsnode + 14) == dostype) {
+           if ((dostype & 0xffffff00) != 0x444f5300)
+               addfakefilesys (parmpacket, dostype);
+           return;
+       }
+        fsnode = get_long (fsnode);
+    }
+
+    tmp[0] = 0;
+    if (uip->filesysdir && strlen(uip->filesysdir) > 0) {
+       strcpy (tmp, uip->filesysdir);
+    } else if ((dostype & 0xffffff00) == 0x444f5300) {
+       strcpy (tmp, currprefs.romfile);
+       i = strlen (tmp);
+       while (i > 0 && tmp[i - 1] != '/' && tmp[i - 1] != '\\')
+           i--;
+        strcpy (tmp + i, "FastFileSystem");
+    }
+    if (tmp[0] == 0) {
+       write_log ("RDB: no filesystem for dostype 0x%08.8X\n", dostype);
+       return;
+    }
+    write_log ("RDB: fakefilesys, trying to load '%s', dostype 0x%08.8X\n", tmp, dostype);
+    zf = zfile_fopen (tmp,"rb");
+    if (!zf) {
+       write_log ("RDB: filesys not found\n");
+        return;
+    }
+
+    zfile_fseek (zf, 0, SEEK_END);
+    size = zfile_ftell (zf);
+    zfile_fseek (zf, 0, SEEK_SET);
+    uip->rdb_filesysstore = xmalloc (size);
+    zfile_fread (uip->rdb_filesysstore, size, 1, zf);
+    zfile_fclose (zf);
+    uip->rdb_filesyssize = size;
+    put_long (parmpacket + PP_FSSIZE, uip->rdb_filesyssize);
+    addfakefilesys (parmpacket, dostype);
+    write_log ("HDF: faked RDB filesystem %08.8X loaded\n", dostype);
+}
+
+static void get_new_device (int type, uaecptr parmpacket, char **devname, uaecptr *devname_amiga, int unit_no)
+{
+    char buffer[80];
+
+    if (*devname == 0 || strlen(*devname) == 0) {
+        sprintf (buffer, "DH%d", unit_no);
+    } else {
+       strcpy (buffer, *devname);
+    }
+    *devname_amiga = ds (device_dupfix (get_long (parmpacket + PP_EXPLIB), buffer));
+    if (type == FILESYS_VIRTUAL)
+       write_log ("FS: mounted virtual unit %s\n", buffer);
+    else
+       write_log ("FS: mounted HDF unit %s\n", buffer);
+}
+
+/* Fill in per-unit fields of a parampacket */
+static uae_u32 filesys_dev_storeinfo (void)
+{
+    UnitInfo *uip = current_mountinfo->ui;
+    int no = m68k_dreg (regs, 6);
+    int unit_no = no & 65535;
+    int sub_no = no >> 16;
+    int type = is_hardfile (current_mountinfo, unit_no);
+    uaecptr parmpacket = m68k_areg (regs, 0);
+
+    if (type == FILESYS_HARDFILE_RDB || type == FILESYS_HARDDRIVE) {
+       /* RDB hardfile */
+        uip[unit_no].devno = unit_no;
+       return rdb_mount (&uip[unit_no], unit_no, sub_no, parmpacket);
+    }
+    if (sub_no)
+        return -2;
+    get_new_device (type, parmpacket, &uip[unit_no].devname, &uip[unit_no].devname_amiga, unit_no);
+    uip[unit_no].devno = unit_no;
+    put_long (parmpacket, uip[unit_no].devname_amiga);
+    put_long (parmpacket + 4, type != FILESYS_VIRTUAL ? ROM_hardfile_resname : fsdevname);
+    put_long (parmpacket + 8, uip[unit_no].devno);
+    put_long (parmpacket + 12, 0); /* Device flags */
+    put_long (parmpacket + 16, 16); /* Env. size */
+    put_long (parmpacket + 20, uip[unit_no].hf.blocksize >> 2); /* longwords per block */
+    put_long (parmpacket + 24, 0); /* unused */
+    put_long (parmpacket + 28, uip[unit_no].hf.surfaces); /* heads */
+    put_long (parmpacket + 32, 1); /* sectors per block */
+    put_long (parmpacket + 36, uip[unit_no].hf.secspertrack); /* sectors per track */
+    put_long (parmpacket + 40, uip[unit_no].hf.reservedblocks); /* reserved blocks */
+    put_long (parmpacket + 44, 0); /* unused */
+    put_long (parmpacket + 48, 0); /* interleave */
+    put_long (parmpacket + 52, 0); /* lowCyl */
+    put_long (parmpacket + 56, uip[unit_no].hf.nrcyls - 1); /* hiCyl */
+    put_long (parmpacket + 60, 50); /* Number of buffers */
+    put_long (parmpacket + 64, 0); /* Buffer mem type */
+    put_long (parmpacket + 68, 0x7FFFFFFF); /* largest transfer */
+    put_long (parmpacket + 72, ~1); /* addMask (?) */
+    put_long (parmpacket + 76, uip[unit_no].bootpri); /* bootPri */
+    put_long (parmpacket + 80, 0x444f5300); /* DOS\0 */
+    if (type == FILESYS_HARDFILE)
+       dofakefilesys (&uip[unit_no], parmpacket);
+    return type;
+}
+
+void filesys_install (void)
+{
+    uaecptr loop;
+
+    TRACE (("Installing filesystem\n"));
+
+    ROM_filesys_resname = ds("UAEunixfs.resource");
+    ROM_filesys_resid = ds("UAE unixfs 0.4");
+
+    fsdevname = ds ("uae.device"); /* does not really exist */
+
+    ROM_filesys_diagentry = here();
+    calltrap (deftrap(filesys_diagentry));
+    dw(0x4ED0); /* JMP (a0) - jump to code that inits Residents */
+
+    loop = here ();
+
+    org (RTAREA_BASE + 0xFF18);
+    calltrap (deftrap (filesys_dev_bootfilesys));
+    dw (RTS);
+
+    /* Special trap for the assembly make_dev routine */
+    org (RTAREA_BASE + 0xFF20);
+    calltrap (deftrap (filesys_dev_remember));
+    dw (RTS);
+
+    org (RTAREA_BASE + 0xFF28);
+    calltrap (deftrap (filesys_dev_storeinfo));
+    dw (RTS);
+
+    org (RTAREA_BASE + 0xFF30);
+    calltrap (deftrap (filesys_handler));
+    dw (RTS);
+
+    org (RTAREA_BASE + 0xFF40);
+    calltrap (deftrap (startup_handler));
+    dw (RTS);
+
+    org (RTAREA_BASE + 0xFF50);
+    calltrap (deftrap (exter_int_helper));
+    dw (RTS);
+
+    org (loop);
+}
+
+void filesys_install_code (void)
+{
+    align(4);
+
+    /* The last offset comes from the code itself, look for it near the top. */
+    EXPANSION_bootcode = here () + 8 + 0x18 + 4;
+    /* Ouch. Make sure this is _always_ a multiple of two bytes. */
+    filesys_initcode = here() + 8 + 0x2c + 4;
+
+ /* see filesys.asm for source */
+
+ db(0x00); db(0x00); db(0x00); db(0x10); db(0x00); db(0x00); db(0x00); db(0x00);
+ db(0x60); db(0x00); db(0x04); db(0xe0); db(0x00); db(0x00); db(0x03); db(0x9c);
+ db(0x00); db(0x00); db(0x00); db(0x30); db(0x00); db(0x00); db(0x00); db(0xd0);
+ db(0x00); db(0x00); db(0x00); db(0x1c); db(0x00); db(0x00); db(0x01); db(0x8a);
+ db(0x00); db(0x00); db(0x06); db(0x98); db(0x43); db(0xfa); db(0x06); db(0xc5);
+ db(0x4e); db(0xae); db(0xff); db(0xa0); db(0x20); db(0x40); db(0x20); db(0x28);
+ db(0x00); db(0x16); db(0x20); db(0x40); db(0x4e); db(0x90); db(0x4e); db(0x75);
+ db(0x48); db(0xe7); db(0xff); db(0xfe); db(0x2c); db(0x78); db(0x00); db(0x04);
+ db(0x30); db(0x3c); db(0xff); db(0xfc); db(0x61); db(0x00); db(0x06); db(0x4a);
+ db(0x2a); db(0x50); db(0x43); db(0xfa); db(0x06); db(0xab); db(0x70); db(0x24);
+ db(0x7a); db(0x00); db(0x4e); db(0xae); db(0xfd); db(0xd8); db(0x4a); db(0x80);
+ db(0x66); db(0x0c); db(0x43); db(0xfa); db(0x06); db(0x9b); db(0x70); db(0x00);
+ db(0x7a); db(0x01); db(0x4e); db(0xae); db(0xfd); db(0xd8); db(0x28); db(0x40);
+ db(0x20); db(0x3c); db(0x00); db(0x00); db(0x02); db(0x2c); db(0x72); db(0x01);
+ db(0x4e); db(0xae); db(0xff); db(0x3a); db(0x26); db(0x40); db(0x27); db(0x4c);
+ db(0x01); db(0x9c); db(0x7c); db(0x00); db(0xbc); db(0xad); db(0x01); db(0x0c);
+ db(0x64); db(0x24); db(0x2f); db(0x06); db(0x7e); db(0x01); db(0x2f); db(0x0b);
+ db(0x20); db(0x4b); db(0x61); db(0x00); db(0x03); db(0x18); db(0x26); db(0x5f);
+ db(0x0c); db(0x80); db(0xff); db(0xff); db(0xff); db(0xfe); db(0x67); db(0x08);
+ db(0x48); db(0x46); db(0x52); db(0x46); db(0x48); db(0x46); db(0x60); db(0xe4);
+ db(0x2c); db(0x1f); db(0x52); db(0x46); db(0x60); db(0xd6); db(0x2c); db(0x78);
+ db(0x00); db(0x04); db(0x22); db(0x4c); db(0x4e); db(0xae); db(0xfe); db(0x62);
+ db(0x30); db(0x3c); db(0xff); db(0x80); db(0x61); db(0x00); db(0x05); db(0xda);
+ db(0x4e); db(0x90); db(0x72); db(0x03); db(0x74); db(0xf6); db(0x20); db(0x7c);
+ db(0x00); db(0x20); db(0x00); db(0x00); db(0x90); db(0x88); db(0x65); db(0x0a);
+ db(0x67); db(0x08); db(0x78); db(0x00); db(0x22); db(0x44); db(0x4e); db(0xae);
+ db(0xfd); db(0x96); db(0x4c); db(0xdf); db(0x7f); db(0xff); db(0x4e); db(0x75);
+ db(0x48); db(0xe7); db(0x00); db(0x20); db(0x30); db(0x3c); db(0xff); db(0x50);
+ db(0x61); db(0x00); db(0x05); db(0xae); db(0x70); db(0x00); db(0x4e); db(0x90);
+ db(0x4a); db(0x80); db(0x67); db(0x00); db(0x00); db(0xa0); db(0x2c); db(0x78);
+ db(0x00); db(0x04); db(0x30); db(0x3c); db(0xff); db(0x50); db(0x61); db(0x00);
+ db(0x05); db(0x98); db(0x70); db(0x02); db(0x4e); db(0x90); db(0x0c); db(0x40);
+ db(0x00); db(0x01); db(0x6d); db(0x7a); db(0x6e); db(0x06); db(0x4e); db(0xae);
+ db(0xfe); db(0x92); db(0x60); db(0xe6); db(0x0c); db(0x40); db(0x00); db(0x02);
+ db(0x6e); db(0x08); db(0x20); db(0x01); db(0x4e); db(0xae); db(0xfe); db(0xbc);
+ db(0x60); db(0xd8); db(0x0c); db(0x40); db(0x00); db(0x03); db(0x6e); db(0x06);
+ db(0x4e); db(0xae); db(0xfe); db(0x86); db(0x60); db(0xcc); db(0x0c); db(0x40);
+ db(0x00); db(0x04); db(0x6e); db(0x06); db(0x4e); db(0xae); db(0xff); db(0x4c);
+ db(0x60); db(0xc0); db(0x0c); db(0x40); db(0x00); db(0x05); db(0x6e); db(0x46);
+ db(0x48); db(0xe7); db(0x00); db(0xc0); db(0x70); db(0x26); db(0x22); db(0x3c);
+ db(0x00); db(0x01); db(0x00); db(0x01); db(0x4e); db(0xae); db(0xff); db(0x3a);
+ db(0x4c); db(0xdf); db(0x03); db(0x00); db(0x24); db(0x40); db(0x15); db(0x7c);
+ db(0x00); db(0x08); db(0x00); db(0x08); db(0x25); db(0x48); db(0x00); db(0x0e);
+ db(0x35); db(0x7c); db(0x00); db(0x26); db(0x00); db(0x12); db(0x25); db(0x7c);
+ db(0x40); db(0x00); db(0x00); db(0x00); db(0x00); db(0x14); db(0x35); db(0x7c);
+ db(0x12); db(0x34); db(0x00); db(0x18); db(0x25); db(0x49); db(0x00); db(0x1a);
+ db(0x20); db(0x69); db(0x00); db(0x10); db(0x22); db(0x4a); db(0x4e); db(0xae);
+ db(0xfe); db(0x92); db(0x60); db(0x00); db(0xff); db(0x76); db(0x30); db(0x3c);
+ db(0xff); db(0x50); db(0x61); db(0x00); db(0x05); db(0x0c); db(0x70); db(0x04);
+ db(0x4e); db(0x90); db(0x70); db(0x01); db(0x4c); db(0xdf); db(0x04); db(0x00);
+ db(0x4e); db(0x75); db(0x48); db(0xe7); db(0xc0); db(0xc0); db(0x70); db(0x1a);
+ db(0x22); db(0x3c); db(0x00); db(0x01); db(0x00); db(0x01); db(0x4e); db(0xae);
+ db(0xff); db(0x3a); db(0x22); db(0x40); db(0x41); db(0xfa); db(0x05); db(0x36);
+ db(0x23); db(0x48); db(0x00); db(0x0a); db(0x41); db(0xfa); db(0xff); db(0x2a);
+ db(0x23); db(0x48); db(0x00); db(0x0e); db(0x41); db(0xfa); db(0xff); db(0x22);
+ db(0x23); db(0x48); db(0x00); db(0x12); db(0x33); db(0x7c); db(0x02); db(0x14);
+ db(0x00); db(0x08); db(0x70); db(0x03); db(0x4e); db(0xae); db(0xff); db(0x58);
+ db(0x4c); db(0xdf); db(0x03); db(0x03); db(0x4e); db(0x75); db(0x48); db(0xe7);
+ db(0xc0); db(0xf2); db(0x2c); db(0x78); db(0x00); db(0x04); db(0x24); db(0x48);
+ db(0x26); db(0x49); db(0x20); db(0x3c); db(0x00); db(0x00); db(0x00); db(0xbe);
+ db(0x22); db(0x3c); db(0x00); db(0x01); db(0x00); db(0x01); db(0x4e); db(0xae);
+ db(0xff); db(0x3a); db(0x20); db(0x40); db(0x70); db(0x00); db(0x43); db(0xeb);
+ db(0x01); db(0xa0); db(0x11); db(0xb1); db(0x00); db(0x00); db(0x00); db(0x0e);
+ db(0x52); db(0x40); db(0x0c); db(0x40); db(0x00); db(0x8c); db(0x66); db(0xf2);
+ db(0x20); db(0x0a); db(0xe4); db(0x88); db(0x21); db(0x40); db(0x00); db(0x36);
+ db(0x22); db(0x48); db(0x41); db(0xfa); db(0x04); db(0xd0); db(0x23); db(0x48);
+ db(0x00); db(0x0a); db(0x20); db(0x6b); db(0x01); db(0x98); db(0x41); db(0xe8);
+ db(0x00); db(0x12); db(0x4e); db(0xae); db(0xff); db(0x10); db(0x4c); db(0xdf);
+ db(0x4f); db(0x03); db(0x4e); db(0x75); db(0x48); db(0xe7); db(0x7f); db(0x7e);
+ db(0x2c); db(0x78); db(0x00); db(0x04); db(0x24); db(0x48); db(0x0c); db(0x9a);
+ db(0x00); db(0x00); db(0x03); db(0xf3); db(0x66); db(0x00); db(0x00); db(0xdc);
+ db(0x50); db(0x8a); db(0x2e); db(0x2a); db(0x00); db(0x04); db(0x9e); db(0x92);
+ db(0x50); db(0x8a); db(0x52); db(0x87); db(0x26); db(0x4a); db(0x20); db(0x07);
+ db(0xd0); db(0x80); db(0xd0); db(0x80); db(0xd7); db(0xc0); db(0x28); db(0x4a);
+ db(0x9b); db(0xcd); db(0x7c); db(0x00); db(0x24); db(0x12); db(0xe5); db(0x8a);
+ db(0x72); db(0x01); db(0x08); db(0x03); db(0x00); db(0x1e); db(0x67); db(0x04);
+ db(0x08); db(0xc1); db(0x00); db(0x01); db(0x08); db(0xc1); db(0x00); db(0x10);
+ db(0x08); db(0x83); db(0x00); db(0x1f); db(0x08); db(0x83); db(0x00); db(0x1e);
+ db(0x20); db(0x02); db(0x66); db(0x04); db(0x42); db(0x9a); db(0x60); db(0x1e);
+ db(0x50); db(0x80); db(0x4e); db(0xae); db(0xff); db(0x3a); db(0x4a); db(0x80);
+ db(0x67); db(0x00); db(0x00); db(0x90); db(0x20); db(0x40); db(0x20); db(0xc2);
+ db(0x24); db(0xc8); db(0x22); db(0x0d); db(0x67); db(0x06); db(0x20); db(0x08);
+ db(0xe4); db(0x88); db(0x2a); db(0x80); db(0x2a); db(0x48); db(0x52); db(0x86);
+ db(0xbe); db(0x86); db(0x66); db(0xb8); db(0x7c); db(0x00); db(0x20); db(0x74);
+ db(0x6c); db(0x00); db(0x58); db(0x88); db(0x26); db(0x1b); db(0x28); db(0x1b);
+ db(0xe5); db(0x8c); db(0x0c); db(0x83); db(0x00); db(0x00); db(0x03); db(0xe9);
+ db(0x67); db(0x08); db(0x0c); db(0x83); db(0x00); db(0x00); db(0x03); db(0xea);
+ db(0x66); db(0x0c); db(0x20); db(0x04); db(0x4a); db(0x80); db(0x67); db(0x0e);
+ db(0x10); db(0xdb); db(0x53); db(0x80); db(0x60); db(0xf6); db(0x0c); db(0x83);
+ db(0x00); db(0x00); db(0x03); db(0xeb); db(0x66); db(0x44); db(0x26); db(0x1b);
+ db(0x0c); db(0x83); db(0x00); db(0x00); db(0x03); db(0xec); db(0x66); db(0x1e);
+ db(0x20); db(0x74); db(0x6c); db(0x00); db(0x58); db(0x88); db(0x20); db(0x1b);
+ db(0x67); db(0xec); db(0x22); db(0x1b); db(0x26); db(0x34); db(0x1c); db(0x00);
+ db(0x58); db(0x83); db(0x24); db(0x1b); db(0xd7); db(0xb0); db(0x28); db(0x00);
+ db(0x53); db(0x80); db(0x66); db(0xf6); db(0x60); db(0xe8); db(0x0c); db(0x83);
+ db(0x00); db(0x00); db(0x03); db(0xf2); db(0x66); db(0x14); db(0x52); db(0x86);
+ db(0xbe); db(0x86); db(0x66); db(0x00); db(0xff); db(0x9a); db(0x7e); db(0x01);
+ db(0x20); db(0x54); db(0x20); db(0x07); db(0x4c); db(0xdf); db(0x7e); db(0xfe);
+ db(0x4e); db(0x75); db(0x30); db(0x3c); db(0x75); db(0x30); db(0x33); db(0xfc);
+ db(0x0f); db(0x00); db(0x00); db(0xdf); db(0xf1); db(0x80); db(0x33); db(0xfc);
+ db(0x00); db(0x0f); db(0x00); db(0xdf); db(0xf1); db(0x80); db(0x33); db(0xfc);
+ db(0x00); db(0xf0); db(0x00); db(0xdf); db(0xf1); db(0x80); db(0x51); db(0xc8);
+ db(0xff); db(0xe6); db(0x7e); db(0x00); db(0x60); db(0xd4); db(0x48); db(0xe7);
+ db(0x40); db(0xe2); db(0x2c); db(0x78); db(0x00); db(0x04); db(0x41); db(0xee);
+ db(0x01); db(0x50); db(0x4a); db(0x90); db(0x67); db(0x1a); db(0x22); db(0x68);
+ db(0x00); db(0x0a); db(0x45); db(0xfa); db(0x03); db(0xbd); db(0x10); db(0x19);
+ db(0x12); db(0x1a); db(0xb0); db(0x01); db(0x66); db(0x06); db(0x4a); db(0x00);
+ db(0x67); db(0x42); db(0x60); db(0xf2); db(0x20); db(0x50); db(0x60); db(0xe2);
+ db(0x70); db(0x20); db(0x22); db(0x3c); db(0x00); db(0x01); db(0x00); db(0x01);
+ db(0x4e); db(0xae); db(0xff); db(0x3a); db(0x24); db(0x40); db(0x15); db(0x7c);
+ db(0x00); db(0x08); db(0x00); db(0x08); db(0x41); db(0xfa); db(0x03); db(0x93);
+ db(0x25); db(0x48); db(0x00); db(0x0a); db(0x41); db(0xfa); db(0x03); db(0x5e);
+ db(0x25); db(0x48); db(0x00); db(0x0e); db(0x41); db(0xea); db(0x00); db(0x12);
+ db(0x20); db(0x88); db(0x58); db(0x90); db(0x21); db(0x48); db(0x00); db(0x08);
+ db(0x41); db(0xee); db(0x01); db(0x50); db(0x22); db(0x4a); db(0x4e); db(0xae);
+ db(0xff); db(0x0a); db(0x20); db(0x4a); db(0x20); db(0x08); db(0x4c); db(0xdf);
+ db(0x47); db(0x02); db(0x4e); db(0x75); db(0x61); db(0x00); db(0xff); db(0x90);
+ db(0x21); db(0x40); db(0x01); db(0x98); db(0x2f); db(0x08); db(0x30); db(0x3c);
+ db(0xff); db(0xfc); db(0x61); db(0x00); db(0x02); db(0xdc); db(0x2a); db(0x50);
+ db(0x30); db(0x3c); db(0xff); db(0x28); db(0x61); db(0x00); db(0x02); db(0xd2);
+ db(0x22); db(0x48); db(0x20); db(0x5f); db(0x42); db(0xa8); db(0x01); db(0x90);
+ db(0x42); db(0xa8); db(0x01); db(0x94); db(0x4e); db(0x91); db(0x26); db(0x00);
+ db(0x0c); db(0x83); db(0xff); db(0xff); db(0xff); db(0xfe); db(0x67); db(0x00);
+ db(0xfc); db(0xfe); db(0x0c); db(0x83); db(0x00); db(0x00); db(0x00); db(0x02);
+ db(0x67); db(0x0c); db(0xc0); db(0x85); db(0x67); db(0x08); db(0x4a); db(0xa8);
+ db(0x01); db(0x90); db(0x67); db(0x00); db(0xfc); db(0xea); db(0x20); db(0x28);
+ db(0x01); db(0x90); db(0x67); db(0x12); db(0x2f); db(0x08); db(0x72); db(0x01);
+ db(0x2c); db(0x78); db(0x00); db(0x04); db(0x4e); db(0xae); db(0xff); db(0x3a);
+ db(0x20); db(0x5f); db(0x21); db(0x40); db(0x01); db(0x94); db(0x4a); db(0x83);
+ db(0x6a); db(0x10); db(0x22); db(0x48); db(0x30); db(0x3c); db(0xff); db(0x20);
+ db(0x61); db(0x00); db(0x02); db(0x7e); db(0x4e); db(0x90); db(0x60); db(0x00);
+ db(0x00); db(0x28); db(0x2c); db(0x4c); db(0x2f); db(0x08); db(0x4e); db(0xae);
+ db(0xff); db(0x70); db(0x20); db(0x5f); db(0x22); db(0x48); db(0x26); db(0x40);
+ db(0x30); db(0x3c); db(0xff); db(0x20); db(0x61); db(0x00); db(0x02); db(0x62);
+ db(0x4e); db(0x90); db(0x70); db(0x00); db(0x27); db(0x40); db(0x00); db(0x08);
+ db(0x27); db(0x40); db(0x00); db(0x10); db(0x27); db(0x40); db(0x00); db(0x20);
+ db(0x4a); db(0xa9); db(0x01); db(0x94); db(0x67); db(0x28); db(0x20); db(0x69);
+ db(0x01); db(0x94); db(0x61); db(0x00); db(0xfd); db(0xd8); db(0x48); db(0xe7);
+ db(0x80); db(0xc0); db(0x20); db(0x29); db(0x01); db(0x90); db(0x22); db(0x69);
+ db(0x01); db(0x94); db(0x2c); db(0x78); db(0x00); db(0x04); db(0x4e); db(0xae);
+ db(0xff); db(0x2e); db(0x4c); db(0xdf); db(0x03); db(0x01); db(0x4a); db(0x80);
+ db(0x67); db(0x04); db(0x61); db(0x00); db(0xfd); db(0x62); db(0x4a); db(0x83);
+ db(0x6b); db(0x00); db(0xfc); db(0x64); db(0x30); db(0x3c); db(0xff); db(0x18);
+ db(0x61); db(0x00); db(0x02); db(0x16); db(0x4e); db(0x90); db(0x20); db(0x03);
+ db(0x16); db(0x29); db(0x00); db(0x4f); db(0x4a); db(0x80); db(0x66); db(0x1a);
+ db(0x27); db(0x7c); db(0x00); db(0x00); db(0x0f); db(0xa0); db(0x00); db(0x14);
+ db(0x43); db(0xfa); db(0xfb); db(0x72); db(0x20); db(0x09); db(0xe4); db(0x88);
+ db(0x27); db(0x40); db(0x00); db(0x20); db(0x70); db(0xff); db(0x27); db(0x40);
+ db(0x00); db(0x24); db(0x4a); db(0x87); db(0x67); db(0x36); db(0x2c); db(0x78);
+ db(0x00); db(0x04); db(0x70); db(0x14); db(0x72); db(0x00); db(0x4e); db(0xae);
+ db(0xff); db(0x3a); db(0x22); db(0x40); db(0x70); db(0x00); db(0x22); db(0x80);
+ db(0x23); db(0x40); db(0x00); db(0x04); db(0x33); db(0x40); db(0x00); db(0x0e);
+ db(0x30); db(0x3c); db(0x10); db(0x00); db(0x80); db(0x03); db(0x33); db(0x40);
+ db(0x00); db(0x08); db(0x23); db(0x6d); db(0x01); db(0x04); db(0x00); db(0x0a);
+ db(0x23); db(0x4b); db(0x00); db(0x10); db(0x41); db(0xec); db(0x00); db(0x4a);
+ db(0x4e); db(0xee); db(0xfe); db(0xf2); db(0x20); db(0x4b); db(0x72); db(0x00);
+ db(0x22); db(0x41); db(0x70); db(0xff); db(0x2c); db(0x4c); db(0x4e); db(0xee);
+ db(0xff); db(0x6a); db(0x2c); db(0x78); db(0x00); db(0x04); db(0x70); db(0x00);
+ db(0x22); db(0x40); db(0x4e); db(0xae); db(0xfe); db(0xda); db(0x20); db(0x40);
+ db(0x4b); db(0xe8); db(0x00); db(0x5c); db(0x43); db(0xfa); db(0x01); db(0xed);
+ db(0x70); db(0x00); db(0x4e); db(0xae); db(0xfd); db(0xd8); db(0x24); db(0x40);
+ db(0x20); db(0x3c); db(0x00); db(0x00); db(0x00); db(0x9d); db(0x22); db(0x3c);
+ db(0x00); db(0x01); db(0x00); db(0x01); db(0x4e); db(0xae); db(0xff); db(0x3a);
+ db(0x26); db(0x40); db(0x7c); db(0x00); db(0x26); db(0x86); db(0x27); db(0x46);
+ db(0x00); db(0x04); db(0x27); db(0x46); db(0x00); db(0x08); db(0x7a); db(0x00);
+ db(0x20); db(0x4d); db(0x4e); db(0xae); db(0xfe); db(0x80); db(0x20); db(0x4d);
+ db(0x4e); db(0xae); db(0xfe); db(0x8c); db(0x28); db(0x40); db(0x26); db(0x2c);
+ db(0x00); db(0x0a); db(0x30); db(0x3c); db(0xff); db(0x40); db(0x61); db(0x00);
+ db(0x01); db(0x50); db(0x70); db(0x00); db(0x4e); db(0x90); db(0x60); db(0x00);
+ db(0x00); db(0xd4); db(0x20); db(0x4d); db(0x4e); db(0xae); db(0xfe); db(0x80);
+ db(0x20); db(0x4d); db(0x4e); db(0xae); db(0xfe); db(0x8c); db(0x28); db(0x40);
+ db(0x0c); db(0x6c); db(0x00); db(0x26); db(0x00); db(0x12); db(0x66); db(0x4a);
+ db(0x0c); db(0xac); db(0x40); db(0x00); db(0x00); db(0x00); db(0x00); db(0x14);
+ db(0x66); db(0x40); db(0x0c); db(0x6c); db(0x12); db(0x34); db(0x00); db(0x18);
+ db(0x66); db(0x38); db(0x20); db(0x6c); db(0x00); db(0x1a); db(0x20); db(0x28);
+ db(0x00); db(0x0c); db(0x02); db(0x80); db(0x80); db(0x00); db(0x00); db(0x08);
+ db(0x0c); db(0x80); db(0x80); db(0x00); db(0x00); db(0x08); db(0x66); db(0x18);
+ db(0x02); db(0xa8); db(0x7f); db(0xff); db(0xff); db(0xff); db(0x00); db(0x0c);
+ db(0x20); db(0x68); db(0x00); db(0x10); db(0x22); db(0x4c); db(0x12); db(0xbc);
+ db(0x00); db(0x08); db(0x4e); db(0xae); db(0xfe); db(0x92); db(0x60); db(0xaa);
+ db(0x22); db(0x4c); db(0x70); db(0x26); db(0x4e); db(0xae); db(0xff); db(0x2e);
+ db(0x60); db(0xa0); db(0x26); db(0x2c); db(0x00); db(0x0a); db(0x66); db(0x3c);
+ db(0x30); db(0x3c); db(0xff); db(0x50); db(0x61); db(0x00); db(0x00); db(0xda);
+ db(0x70); db(0x01); db(0x4e); db(0x90); db(0x45); db(0xeb); db(0x00); db(0x04);
+ db(0x20); db(0x52); db(0x20); db(0x08); db(0x67); db(0x84); db(0x22); db(0x50);
+ db(0x20); db(0x40); db(0x20); db(0x28); db(0x00); db(0x04); db(0x6a); db(0x16);
+ db(0x48); db(0xe7); db(0x00); db(0xc0); db(0x28); db(0x68); db(0x00); db(0x0a);
+ db(0x61); db(0x4a); db(0x53); db(0x85); db(0x4c); db(0xdf); db(0x03); db(0x00);
+ db(0x24); db(0x89); db(0x20); db(0x49); db(0x60); db(0xdc); db(0x24); db(0x48);
+ db(0x20); db(0x49); db(0x60); db(0xd6); db(0x0c); db(0x85); db(0x00); db(0x00);
+ db(0x00); db(0x14); db(0x65); db(0x00); db(0x00); db(0x0a); db(0x70); db(0x01);
+ db(0x29); db(0x40); db(0x00); db(0x04); db(0x60); db(0x12); db(0x61); db(0x32);
+ db(0x30); db(0x3c); db(0xff); db(0x30); db(0x61); db(0x00); db(0x00); db(0x8a);
+ db(0x4e); db(0x90); db(0x4a); db(0x80); db(0x67); db(0x0e); db(0x52); db(0x85);
+ db(0x28); db(0xab); db(0x00); db(0x04); db(0x27); db(0x4c); db(0x00); db(0x04);
+ db(0x60); db(0x00); db(0xff); db(0x30); db(0x28); db(0x43); db(0x61); db(0x04);
+ db(0x60); db(0x00); db(0xff); db(0x28); db(0x22); db(0x54); db(0x20); db(0x6c);
+ db(0x00); db(0x04); db(0x29); db(0x4d); db(0x00); db(0x04); db(0x4e); db(0xee);
+ db(0xfe); db(0x92); db(0x2f); db(0x05); db(0x7a); db(0xfc); db(0x24); db(0x53);
+ db(0x2e); db(0x0a); db(0x22); db(0x0a); db(0x67); db(0x00); db(0x00); db(0x0c);
+ db(0x52); db(0x85); db(0x67); db(0x1e); db(0x22); db(0x4a); db(0x24); db(0x52);
+ db(0x60); db(0xf0); db(0x52); db(0x85); db(0x67); db(0x3c); db(0x24); db(0x47);
+ db(0x70); db(0x18); db(0x72); db(0x01); db(0x4e); db(0xae); db(0xff); db(0x3a);
+ db(0x52); db(0x46); db(0x24); db(0x40); db(0x24); db(0x87); db(0x2e); db(0x0a);
+ db(0x60); db(0xe8); db(0x20); db(0x12); db(0x67); db(0x24); db(0x20); db(0x40);
+ db(0x20); db(0x10); db(0x67); db(0x1e); db(0x20); db(0x40); db(0x20); db(0x10);
+ db(0x67); db(0x18); db(0x70); db(0x00); db(0x22); db(0x80); db(0x22); db(0x4a);
+ db(0x24); db(0x51); db(0x70); db(0x18); db(0x4e); db(0xae); db(0xff); db(0x2e);
+ db(0x06); db(0x86); db(0x00); db(0x01); db(0x00); db(0x00); db(0x20); db(0x0a);
+ db(0x66); db(0xec); db(0x26); db(0x87); db(0x2a); db(0x1f); db(0x4e); db(0x75);
+ db(0x41); db(0xfa); db(0xf9); db(0x6a); db(0x02); db(0x80); db(0x00); db(0x00);
+ db(0xff); db(0xff); db(0xd1); db(0xc0); db(0x4e); db(0x75); db(0x00); db(0x00);
+ db(0x0c); db(0xaf); db(0x00); db(0x00); db(0x00); db(0x22); db(0x00); db(0x08);
+ db(0x66); db(0x30); db(0x48); db(0xe7); db(0xc0); db(0xe2); db(0x2c); db(0x78);
+ db(0x00); db(0x04); db(0x93); db(0xc9); db(0x4e); db(0xae); db(0xfe); db(0xda);
+ db(0x24); db(0x40); db(0x22); db(0x4a); db(0x70); db(0xec); db(0x4e); db(0xae);
+ db(0xfe); db(0xd4); db(0x41); db(0xfa); db(0xff); db(0xda); db(0x32); db(0x10);
+ db(0xb2); db(0x50); db(0x67); db(0xfc); db(0x22); db(0x4a); db(0x4e); db(0xae);
+ db(0xfe); db(0xd4); db(0x72); db(0x01); db(0x4c); db(0xdf); db(0x47); db(0x03);
+ db(0x58); db(0x8f); db(0x4e); db(0x75); db(0x55); db(0x41); db(0x45); db(0x20);
+ db(0x66); db(0x69); db(0x6c); db(0x65); db(0x73); db(0x79); db(0x73); db(0x74);
+ db(0x65); db(0x6d); db(0x00); db(0x64); db(0x6f); db(0x73); db(0x2e); db(0x6c);
+ db(0x69); db(0x62); db(0x72); db(0x61); db(0x72); db(0x79); db(0x00); db(0x65);
+ db(0x78); db(0x70); db(0x61); db(0x6e); db(0x73); db(0x69); db(0x6f); db(0x6e);
+ db(0x2e); db(0x6c); db(0x69); db(0x62); db(0x72); db(0x61); db(0x72); db(0x79);
+ db(0x00); db(0x46); db(0x69); db(0x6c); db(0x65); db(0x53); db(0x79); db(0x73);
+ db(0x74); db(0x65); db(0x6d); db(0x2e); db(0x72); db(0x65); db(0x73); db(0x6f);
+ db(0x75); db(0x72); db(0x63); db(0x65); db(0x00); db(0x00); db(0x00); db(0x00);
+ db(0x00); db(0x00); db(0x03); db(0xf2);
+
+}
+
+#include "od-win32/win32_filesys.c"
diff --git a/filesys.sh b/filesys.sh
new file mode 100755 (executable)
index 0000000..72a1418
--- /dev/null
@@ -0,0 +1,7 @@
+#! /bin/sh
+# Script to convert an Amiga executable named filesys into a series of
+# dw(...) statements.
+# This assumes that the first four lines only contain hunk information.
+# That is what you get if you assemble/link with a68k/blink
+od -v -t xC -w8 filesys |tail -n +5 | sed -e "s,^.......,,"  \
+  -e "s,[0123456789abcdefABCDEF][0123456789abcdefABCDEF],db(0x&);,g"
diff --git a/fpp.c b/fpp.c
new file mode 100755 (executable)
index 0000000..56190b9
--- /dev/null
+++ b/fpp.c
@@ -0,0 +1,1453 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * MC68881 emulation
+  *
+  * Copyright 1996 Herman ten Brugge
+  */
+
+#define __USE_ISOC9X  /* We might be able to pick up a NaN */
+#include <math.h>
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "memory.h"
+#include "custom.h"
+#include "events.h"
+#include "newcpu.h"
+#include "ersatz.h"
+#include "md-fpp.h"
+#include "savestate.h"
+
+#if 1
+
+#define        DEBUG_FPP       0
+
+#define FFLAG_Z   0x4000
+#define FFLAG_N   0x0100
+#define FFLAG_NAN 0x0400 
+
+#define MAKE_FPSR(r)  regs.fp_result=(r)
+
+static __inline__ void native_set_fpucw (uae_u32 m68k_cw)
+{
+#if USE_X86_FPUCW
+  int mprec=(m68k_cw>>6)&3;
+  int mround=(m68k_cw>>4)&3;
+  uae_u16 x;
+
+  int iprec=0;
+  int iround=0;
+
+  switch(mprec) {
+  case 0: /* extend */ iprec=3; break;
+  case 1: /* single */ iprec=0; break;
+  case 2: /* double */ iprec=2; break;
+  case 3: /* undef  */ iprec=3; break;
+  }
+
+  switch(mround) {
+  case 0: /* nearest */ iround=0; break;
+  case 1: /* zero    */ iround=3; break;
+  case 2: /* down    */ iround=1; break;
+  case 3: /* up      */ iround=2; break;
+  }
+   
+  x=0x107f + (iprec<<8) + (iround<<10);
+#ifdef _MSC_VER
+  __asm {
+  fldcw x
+  }
+#else
+  __asm__ ("fldcw %0" : : "m" (*&x));
+#endif
+#endif
+}
+
+#if defined(uae_s64) /* Close enough for government work? */
+typedef uae_s64 tointtype;
+#else
+typedef uae_s32 tointtype;
+#endif
+
+static __inline__ tointtype toint(fptype src)
+{
+    switch ((regs.fpcr >> 4) & 0x3) {
+    case 0:
+#if USE_X86_FPUCW
+       return (tointtype) (src);
+#else
+       return (tointtype) (src + 0.5);
+#endif
+    case 1:
+       return (tointtype) src;
+    case 2:
+       return (tointtype)floor (src);
+    case 3:
+       return (tointtype)ceil (src);
+    }
+    return (tointtype)src; /* Should never be reached */
+}
+
+uae_u32 get_fpsr (void) 
+{
+    uae_u32 answer = regs.fpsr & 0x00ffffff;
+#ifdef HAVE_ISNAN
+    if (isnan (regs.fp_result))
+       answer |= 0x01000000;
+    else
+#endif
+    {
+       if (regs.fp_result == 0)
+           answer |= 0x04000000;
+       else if (regs.fp_result < 0)
+           answer |= 0x08000000;
+#ifdef HAVE_ISINF
+       if (isinf (regs.fp_result))
+           answer |= 0x02000000;
+#endif
+    }
+    return answer;
+}
+
+STATIC_INLINE void set_fpsr (uae_u32 x) 
+{
+    regs.fpsr = x;
+
+    if (x & 0x01000000) {
+#ifdef NAN
+       regs.fp_result = NAN;
+#else
+       regs.fp_result = pow (1e100, 10) - pow(1e100, 10);  /* Any better way? */
+#endif
+    }
+    else if (x & 0x04000000)
+       regs.fp_result = 0;
+    else if (x & 0x08000000)
+       regs.fp_result = -1;
+    else
+       regs.fp_result = 1;
+}
+
+
+/* single   : S  8*E 23*F */
+/* double   : S 11*E 52*F */
+/* extended : S 15*E 64*F */
+/* E = 0 & F = 0 -> 0 */
+/* E = MAX & F = 0 -> Infin */
+/* E = MAX & F # 0 -> NotANumber */
+/* E = biased by 127 (single) ,1023 (double) ,16383 (extended) */
+
+STATIC_INLINE fptype to_pack (uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
+{
+    fptype d;
+    char *cp;
+    char str[100];
+
+    cp = str;
+    if (wrd1 & 0x80000000)
+       *cp++ = '-';
+    *cp++ = (wrd1 & 0xf) + '0';
+    *cp++ = '.';
+    *cp++ = ((wrd2 >> 28) & 0xf) + '0';
+    *cp++ = ((wrd2 >> 24) & 0xf) + '0';
+    *cp++ = ((wrd2 >> 20) & 0xf) + '0';
+    *cp++ = ((wrd2 >> 16) & 0xf) + '0';
+    *cp++ = ((wrd2 >> 12) & 0xf) + '0';
+    *cp++ = ((wrd2 >> 8) & 0xf) + '0';
+    *cp++ = ((wrd2 >> 4) & 0xf) + '0';
+    *cp++ = ((wrd2 >> 0) & 0xf) + '0';
+    *cp++ = ((wrd3 >> 28) & 0xf) + '0';
+    *cp++ = ((wrd3 >> 24) & 0xf) + '0';
+    *cp++ = ((wrd3 >> 20) & 0xf) + '0';
+    *cp++ = ((wrd3 >> 16) & 0xf) + '0';
+    *cp++ = ((wrd3 >> 12) & 0xf) + '0';
+    *cp++ = ((wrd3 >> 8) & 0xf) + '0';
+    *cp++ = ((wrd3 >> 4) & 0xf) + '0';
+    *cp++ = ((wrd3 >> 0) & 0xf) + '0';
+    *cp++ = 'E';
+    if (wrd1 & 0x40000000)
+       *cp++ = '-';
+    *cp++ = ((wrd1 >> 24) & 0xf) + '0';
+    *cp++ = ((wrd1 >> 20) & 0xf) + '0';
+    *cp++ = ((wrd1 >> 16) & 0xf) + '0';
+    *cp = 0;
+    sscanf (str, "%le", &d);
+    return d;
+}
+
+STATIC_INLINE void from_pack (fptype src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3)
+{
+    int i;
+    int t;
+    char *cp;
+    char str[100];
+
+    sprintf (str, "%.16e", src);
+    cp = str;
+    *wrd1 = *wrd2 = *wrd3 = 0;
+    if (*cp == '-') {
+       cp++;
+       *wrd1 = 0x80000000;
+    }
+    if (*cp == '+')
+       cp++;
+    *wrd1 |= (*cp++ - '0');
+    if (*cp == '.')
+       cp++;
+    for (i = 0; i < 8; i++) {
+       *wrd2 <<= 4;
+       if (*cp >= '0' && *cp <= '9')
+           *wrd2 |= *cp++ - '0';
+    }
+    for (i = 0; i < 8; i++) {
+       *wrd3 <<= 4;
+       if (*cp >= '0' && *cp <= '9')
+           *wrd3 |= *cp++ - '0';
+    }
+    if (*cp == 'e' || *cp == 'E') {
+       cp++;
+       if (*cp == '-') {
+           cp++;
+           *wrd1 |= 0x40000000;
+       }
+       if (*cp == '+')
+           cp++;
+       t = 0;
+       for (i = 0; i < 3; i++) {
+           if (*cp >= '0' && *cp <= '9')
+               t = (t << 4) | (*cp++ - '0');
+       }
+       *wrd1 |= t << 16;
+    }
+}
+
+STATIC_INLINE int get_fp_value (uae_u32 opcode, uae_u16 extra, fptype *src)
+{
+    uaecptr tmppc;
+    uae_u16 tmp;
+    int size;
+    int mode;
+    int reg;
+    uae_u32 ad = 0;
+    static int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 };
+    static int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 };
+
+    if ((extra & 0x4000) == 0) {
+       *src = regs.fp[(extra >> 10) & 7];
+       return 1;
+    }
+    mode = (opcode >> 3) & 7;
+    reg = opcode & 7;
+    size = (extra >> 10) & 7;
+    switch (mode) {
+    case 0:
+       switch (size) {
+       case 6:
+           *src = (fptype) (uae_s8) m68k_dreg (regs, reg);
+           break;
+       case 4:
+           *src = (fptype) (uae_s16) m68k_dreg (regs, reg);
+           break;
+       case 0:
+           *src = (fptype) (uae_s32) m68k_dreg (regs, reg);
+           break;
+       case 1:
+           *src = to_single (m68k_dreg (regs, reg));
+           break;
+       default:
+           return 0;
+       }
+       return 1;
+    case 1:
+       return 0;
+    case 2:
+       ad = m68k_areg (regs, reg);
+       break;
+    case 3:
+       ad = m68k_areg (regs, reg);
+       m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
+       break;
+    case 4:
+       m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
+       ad = m68k_areg (regs, reg);
+       break;
+    case 5:
+       ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword ();
+       break;
+    case 6:
+       ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword ());
+       break;
+    case 7:
+       switch (reg) {
+       case 0:
+           ad = (uae_s32) (uae_s16) next_iword ();
+           break;
+       case 1:
+           ad = next_ilong ();
+           break;
+       case 2:
+           ad = m68k_getpc ();
+           ad += (uae_s32) (uae_s16) next_iword ();
+           break;
+       case 3:
+           tmppc = m68k_getpc ();
+           tmp = next_iword ();
+           ad = get_disp_ea_020 (tmppc, tmp);
+           break;
+       case 4:
+           ad = m68k_getpc ();
+           m68k_setpc (ad + sz2[size]);
+           break;
+       default:
+           return 0;
+       }
+    }
+    switch (size) {
+    case 0:
+       *src = (fptype) (uae_s32) get_long (ad);
+       break;
+    case 1:
+       *src = to_single (get_long (ad));
+       break;
+    case 2:{
+           uae_u32 wrd1, wrd2, wrd3;
+           wrd1 = get_long (ad);
+           ad += 4;
+           wrd2 = get_long (ad);
+           ad += 4;
+           wrd3 = get_long (ad);
+           *src = to_exten (wrd1, wrd2, wrd3);
+       }
+       break;
+    case 3:{
+           uae_u32 wrd1, wrd2, wrd3;
+           wrd1 = get_long (ad);
+           ad += 4;
+           wrd2 = get_long (ad);
+           ad += 4;
+           wrd3 = get_long (ad);
+           *src = to_pack (wrd1, wrd2, wrd3);
+       }
+       break;
+    case 4:
+       *src = (fptype) (uae_s16) get_word (ad);
+       break;
+    case 5:{
+           uae_u32 wrd1, wrd2;
+           wrd1 = get_long (ad);
+           ad += 4;
+           wrd2 = get_long (ad);
+           *src = to_double (wrd1, wrd2);
+       }
+       break;
+    case 6:
+       *src = (fptype) (uae_s8) get_byte (ad + 1);
+       break;
+    default:
+       return 0;
+    }
+    return 1;
+}
+
+STATIC_INLINE int put_fp_value (fptype value, uae_u32 opcode, uae_u16 extra)
+{
+    uae_u16 tmp;
+    uaecptr tmppc;
+    int size;
+    int mode;
+    int reg;
+    uae_u32 ad;
+    static int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 };
+    static int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 };
+
+    if ((extra & 0x4000) == 0) {
+       regs.fp[(extra >> 10) & 7] = value;
+       return 1;
+    }
+    mode = (opcode >> 3) & 7;
+    reg = opcode & 7;
+    size = (extra >> 10) & 7;
+    ad = -1;
+    
+    switch (mode) {
+    case 0:
+       switch (size) {
+       case 6:
+           m68k_dreg (regs, reg) = (uae_u32)(((toint(value) & 0xff)
+                                    | (m68k_dreg (regs, reg) & ~0xff)));
+           break;
+       case 4:
+           m68k_dreg (regs, reg) = (uae_u32)(((toint(value) & 0xffff)
+                                    | (m68k_dreg (regs, reg) & ~0xffff)));
+           break;
+       case 0:
+           m68k_dreg (regs, reg) = (uae_u32)toint(value);
+           break;
+       case 1:
+           m68k_dreg (regs, reg) = from_single (value);
+           break;
+       default:
+           return 0;
+       }
+       return 1;
+    case 1:
+       return 0;
+    case 2:
+       ad = m68k_areg (regs, reg);
+       break;
+    case 3:
+       ad = m68k_areg (regs, reg);
+       m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
+       break;
+    case 4:
+       m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
+       ad = m68k_areg (regs, reg);
+       break;
+    case 5:
+       ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword ();
+       break;
+    case 6:
+       ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword ());
+       break;
+    case 7:
+       switch (reg) {
+       case 0:
+           ad = (uae_s32) (uae_s16) next_iword ();
+           break;
+       case 1:
+           ad = next_ilong ();
+           break;
+       case 2:
+           ad = m68k_getpc ();
+           ad += (uae_s32) (uae_s16) next_iword ();
+           break;
+       case 3:
+           tmppc = m68k_getpc ();
+           tmp = next_iword ();
+           ad = get_disp_ea_020 (tmppc, tmp);
+           break;
+       case 4:
+           ad = m68k_getpc ();
+           m68k_setpc (ad + sz2[size]);
+           break;
+       default:
+           return 0;
+       }
+    }
+    switch (size) {
+    case 0:
+       put_long (ad, (uae_u32)toint(value));
+       break;
+    case 1:
+       put_long (ad, from_single (value));
+       break;
+    case 2:
+       {
+           uae_u32 wrd1, wrd2, wrd3;
+           from_exten (value, &wrd1, &wrd2, &wrd3);
+           put_long (ad, wrd1);
+           ad += 4;
+           put_long (ad, wrd2);
+           ad += 4;
+           put_long (ad, wrd3);
+       }
+       break;
+    case 3:
+       {
+           uae_u32 wrd1, wrd2, wrd3;
+           from_pack (value, &wrd1, &wrd2, &wrd3);
+           put_long (ad, wrd1);
+           ad += 4;
+           put_long (ad, wrd2);
+           ad += 4;
+           put_long (ad, wrd3);
+       }
+       break;
+    case 4:
+       put_word (ad, (uae_s16) toint(value));
+       break;
+    case 5:{
+           uae_u32 wrd1, wrd2;
+           from_double (value, &wrd1, &wrd2);
+           put_long (ad, wrd1);
+           ad += 4;
+           put_long (ad, wrd2);
+       }
+       break;
+    case 6:
+       put_byte (ad, (uae_s8)toint(value));
+       break;
+    default:
+       return 0;
+    }
+    return 1;
+}
+
+STATIC_INLINE int get_fp_ad (uae_u32 opcode, uae_u32 * ad)
+{
+    uae_u16 tmp;
+    uaecptr tmppc;
+    int mode;
+    int reg;
+
+    mode = (opcode >> 3) & 7;
+    reg = opcode & 7;
+    switch (mode) {
+    case 0:
+    case 1:
+       return 0;
+    case 2:
+       *ad = m68k_areg (regs, reg);
+       break;
+    case 3:
+       *ad = m68k_areg (regs, reg);
+       break;
+    case 4:
+       *ad = m68k_areg (regs, reg);
+       break;
+    case 5:
+       *ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword ();
+       break;
+    case 6:
+       *ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword ());
+       break;
+    case 7:
+       switch (reg) {
+       case 0:
+           *ad = (uae_s32) (uae_s16) next_iword ();
+           break;
+       case 1:
+           *ad = next_ilong ();
+           break;
+       case 2:
+           *ad = m68k_getpc ();
+           *ad += (uae_s32) (uae_s16) next_iword ();
+           break;
+       case 3:
+           tmppc = m68k_getpc ();
+           tmp = next_iword ();
+           *ad = get_disp_ea_020 (tmppc, tmp);
+           break;
+       default:
+           return 0;
+       }
+    }
+    return 1;
+}
+
+STATIC_INLINE int fpp_cond (uae_u32 opcode, int contition)
+{
+    int N = (regs.fp_result<0);
+    int Z = (regs.fp_result==0);
+    /* int I = (regs.fpsr & 0x2000000) != 0; */
+    int NotANumber = 0;
+
+#ifdef HAVE_ISNAN
+    NotANumber = isnan (regs.fp_result);
+#endif
+
+    if (NotANumber)
+       N=Z=0;
+
+    switch (contition) {
+    case 0x00:
+       return 0;
+    case 0x01:
+       return Z;
+    case 0x02:
+       return !(NotANumber || Z || N);
+    case 0x03:
+       return Z || !(NotANumber || N);
+    case 0x04:
+       return N && !(NotANumber || Z);
+    case 0x05:
+       return Z || (N && !NotANumber);
+    case 0x06:
+       return !(NotANumber || Z);
+    case 0x07:
+       return !NotANumber;
+    case 0x08:
+       return NotANumber;
+    case 0x09:
+       return NotANumber || Z;
+    case 0x0a:
+       return NotANumber || !(N || Z);
+    case 0x0b:
+       return NotANumber || Z || !N;
+    case 0x0c:
+       return NotANumber || (N && !Z);
+    case 0x0d:
+       return NotANumber || Z || N;
+    case 0x0e:
+       return !Z;
+    case 0x0f:
+       return 1;
+    case 0x10:
+       return 0;
+    case 0x11:
+       return Z;
+    case 0x12:
+       return !(NotANumber || Z || N);
+    case 0x13:
+       return Z || !(NotANumber || N);
+    case 0x14:
+       return N && !(NotANumber || Z);
+    case 0x15:
+       return Z || (N && !NotANumber);
+    case 0x16:
+       return !(NotANumber || Z);
+    case 0x17:
+       return !NotANumber;
+    case 0x18:
+       return NotANumber;
+    case 0x19:
+       return NotANumber || Z;
+    case 0x1a:
+       return NotANumber || !(N || Z);
+    case 0x1b:
+       return NotANumber || Z || !N;
+    case 0x1c:
+#if 0
+        return NotANumber || (Z && N); /* This is wrong, compare 0x0c */
+#else
+        return NotANumber || (N && !Z);  
+#endif
+    case 0x1d:
+       return NotANumber || Z || N;
+    case 0x1e:
+       return !Z;
+    case 0x1f:
+       return 1;
+    }
+    return -1;
+}
+
+void fdbcc_opp (uae_u32 opcode, uae_u16 extra)
+{
+    uaecptr pc = (uae_u32) m68k_getpc ();
+    uae_s32 disp = (uae_s32) (uae_s16) next_iword ();
+    int cc;
+
+#if DEBUG_FPP
+    printf ("fdbcc_opp at %08lx\n", m68k_getpc ());
+    fflush (stdout);
+#endif
+    cc = fpp_cond (opcode, extra & 0x3f);
+    if (cc == -1) {
+       m68k_setpc (pc - 4);
+       op_illg (opcode);
+    } else if (!cc) {
+       int reg = opcode & 0x7;
+
+       m68k_dreg (regs, reg) = ((m68k_dreg (regs, reg) & ~0xffff)
+                                | ((m68k_dreg (regs, reg) - 1) & 0xffff));
+       if ((m68k_dreg (regs, reg) & 0xffff) == 0xffff)
+           m68k_setpc (pc + disp);
+    }
+}
+
+void fscc_opp (uae_u32 opcode, uae_u16 extra)
+{
+    uae_u32 ad;
+    int cc;
+
+#if DEBUG_FPP
+    printf ("fscc_opp at %08lx\n", m68k_getpc ());
+    fflush (stdout);
+#endif
+    cc = fpp_cond (opcode, extra & 0x3f);
+    if (cc == -1) {
+       m68k_setpc (m68k_getpc () - 4);
+       op_illg (opcode);
+    } else if ((opcode & 0x38) == 0) {
+       m68k_dreg (regs, opcode & 7) = (m68k_dreg (regs, opcode & 7) & ~0xff) | (cc ? 0xff : 0x00);
+    } else {
+       if (get_fp_ad (opcode, &ad) == 0) {
+           m68k_setpc (m68k_getpc () - 4);
+           op_illg (opcode);
+       } else
+           put_byte (ad, cc ? 0xff : 0x00);
+    }
+}
+
+void ftrapcc_opp (uae_u32 opcode, uaecptr oldpc)
+{
+    int cc;
+
+#if DEBUG_FPP
+    printf ("ftrapcc_opp at %08lx\n", m68k_getpc ());
+    fflush (stdout);
+#endif
+    cc = fpp_cond (opcode, opcode & 0x3f);
+    if (cc == -1) {
+       m68k_setpc (oldpc);
+       op_illg (opcode);
+    }
+    if (cc)
+       Exception (7, oldpc - 2);
+}
+
+void fbcc_opp (uae_u32 opcode, uaecptr pc, uae_u32 extra)
+{
+    int cc;
+
+#if DEBUG_FPP
+    printf ("fbcc_opp at %08lx\n", m68k_getpc ());
+    fflush (stdout);
+#endif
+    cc = fpp_cond (opcode, opcode & 0x3f);
+    if (cc == -1) {
+       m68k_setpc (pc);
+       op_illg (opcode);
+    } else if (cc) {
+       if ((opcode & 0x40) == 0)
+           extra = (uae_s32) (uae_s16) extra;
+       m68k_setpc (pc + extra);
+    }
+}
+
+void fsave_opp (uae_u32 opcode)
+{
+    uae_u32 ad;
+    int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
+    int fpu_version = 0x18; /* 68881 */
+//    int fpu_version = 0x38; /* 68882 */
+    int i;
+
+
+#if DEBUG_FPP
+    printf ("fsave_opp at %08lx\n", m68k_getpc ());
+    fflush (stdout);
+#endif
+    if (get_fp_ad (opcode, &ad) == 0) {
+       m68k_setpc (m68k_getpc () - 2);
+       op_illg (opcode);
+       return;
+    }
+
+    if (currprefs.cpu_level >= 4) {
+       /* 4 byte 68040 IDLE frame.  */
+       if (incr < 0) {
+           ad -= 4;
+           put_long (ad, 0x41000000);
+       } else {
+           put_long (ad, 0x41000000);
+           ad += 4;
+       }
+    } else {
+       if (incr < 0) {
+           ad -= 4;
+           put_long (ad, 0x70000000);
+           for (i = 0; i < 5; i++) {
+               ad -= 4;
+               put_long (ad, 0x00000000);
+           }
+           ad -= 4;
+           put_long (ad, 0x1f000000 | (fpu_version << 16));
+       } else {
+           put_long (ad, 0x1f000000 | (fpu_version << 16));
+           ad += 4;
+           for (i = 0; i < 5; i++) {
+               put_long (ad, 0x00000000);
+               ad += 4;
+           }
+           put_long (ad, 0x70000000);
+           ad += 4;
+       }
+    }
+    if ((opcode & 0x38) == 0x18)
+       m68k_areg (regs, opcode & 7) = ad;
+    if ((opcode & 0x38) == 0x20)
+       m68k_areg (regs, opcode & 7) = ad;
+}
+
+void frestore_opp (uae_u32 opcode)
+{
+    uae_u32 ad;
+    uae_u32 d;
+    int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
+
+#if DEBUG_FPP
+    printf ("frestore_opp at %08lx\n", m68k_getpc ());
+    fflush (stdout);
+#endif
+    if (get_fp_ad (opcode, &ad) == 0) {
+       m68k_setpc (m68k_getpc () - 2);
+       op_illg (opcode);
+       return;
+    }
+    if (currprefs.cpu_level >= 4) {
+       /* 68040 */
+       if (incr < 0) {
+           /* @@@ This may be wrong.  */
+           ad -= 4;
+           d = get_long (ad);
+           if ((d & 0xff000000) != 0) { /* Not a NULL frame? */
+               if ((d & 0x00ff0000) == 0) { /* IDLE */
+               } else if ((d & 0x00ff0000) == 0x00300000) { /* UNIMP */
+                   ad -= 44;
+               } else if ((d & 0x00ff0000) == 0x00600000) { /* BUSY */
+                   ad -= 92;
+               }
+           }
+       } else {
+           d = get_long (ad);
+           ad += 4;
+           if ((d & 0xff000000) != 0) { /* Not a NULL frame? */
+               if ((d & 0x00ff0000) == 0) { /* IDLE */
+               } else if ((d & 0x00ff0000) == 0x00300000) { /* UNIMP */
+                   ad += 44;
+               } else if ((d & 0x00ff0000) == 0x00600000) { /* BUSY */
+                   ad += 92;
+               }
+           }
+       }
+    } else {
+       if (incr < 0) {
+           ad -= 4;
+           d = get_long (ad);
+           if ((d & 0xff000000) != 0) {
+               if ((d & 0x00ff0000) == 0x00180000)
+                   ad -= 6 * 4;
+               else if ((d & 0x00ff0000) == 0x00380000)
+                   ad -= 14 * 4;
+               else if ((d & 0x00ff0000) == 0x00b40000)
+                   ad -= 45 * 4;
+           }
+       } else {
+           d = get_long (ad);
+           ad += 4;
+           if ((d & 0xff000000) != 0) {
+               if ((d & 0x00ff0000) == 0x00180000)
+                   ad += 6 * 4;
+               else if ((d & 0x00ff0000) == 0x00380000)
+                   ad += 14 * 4;
+               else if ((d & 0x00ff0000) == 0x00b40000)
+                   ad += 45 * 4;
+           }
+       }
+    }
+    if ((opcode & 0x38) == 0x18)
+       m68k_areg (regs, opcode & 7) = ad;
+    if ((opcode & 0x38) == 0x20)
+       m68k_areg (regs, opcode & 7) = ad;
+}
+
+static void fround (int reg)
+{
+    regs.fp[reg] = (float)regs.fp[reg];
+}
+
+void fpp_opp (uae_u32 opcode, uae_u16 extra)
+{
+    int reg;
+    fptype src;
+
+#if DEBUG_FPP
+    printf ("FPP %04lx %04x at %08lx\n", opcode & 0xffff, extra & 0xffff, m68k_getpc () - 4);
+    fflush (stdout);
+#endif
+    switch ((extra >> 13) & 0x7) {
+    case 3:
+       if (put_fp_value (regs.fp[(extra >> 7) & 7], opcode, extra) == 0) {
+           m68k_setpc (m68k_getpc () - 4);
+           op_illg (opcode);
+       }
+       return;
+    case 4:
+    case 5:
+       if ((opcode & 0x38) == 0) {
+           if (extra & 0x2000) {
+               if (extra & 0x1000)
+                   m68k_dreg (regs, opcode & 7) = regs.fpcr;
+               if (extra & 0x0800)
+                   m68k_dreg (regs, opcode & 7) = get_fpsr ();
+               if (extra & 0x0400)
+                   m68k_dreg (regs, opcode & 7) = regs.fpiar;
+           } else {
+               if (extra & 0x1000) {
+                   regs.fpcr = m68k_dreg (regs, opcode & 7);
+                   native_set_fpucw (regs.fpcr);
+               }
+               if (extra & 0x0800)
+                   set_fpsr (m68k_dreg (regs, opcode & 7));
+               if (extra & 0x0400)
+                   regs.fpiar = m68k_dreg (regs, opcode & 7);
+           }
+       } else if ((opcode & 0x38) == 0x08) {
+           if (extra & 0x2000) {
+               if (extra & 0x1000)
+                   m68k_areg (regs, opcode & 7) = regs.fpcr;
+               if (extra & 0x0800)
+                   m68k_areg (regs, opcode & 7) = get_fpsr ();
+               if (extra & 0x0400)
+                   m68k_areg (regs, opcode & 7) = regs.fpiar;
+           } else {
+               if (extra & 0x1000) {
+                   regs.fpcr = m68k_areg (regs, opcode & 7);
+                   native_set_fpucw (regs.fpcr);
+               }
+               if (extra & 0x0800)
+                   set_fpsr (m68k_areg (regs, opcode & 7));
+               if (extra & 0x0400)
+                   regs.fpiar = m68k_areg (regs, opcode & 7);
+           }
+       } else if ((opcode & 0x3f) == 0x3c) {
+           if ((extra & 0x2000) == 0) {
+               if (extra & 0x1000) {
+                   regs.fpcr = next_ilong ();
+                   native_set_fpucw (regs.fpcr);
+               }
+               if (extra & 0x0800)
+                   set_fpsr (next_ilong ());
+               if (extra & 0x0400)
+                   regs.fpiar = next_ilong ();
+           }
+       } else if (extra & 0x2000) {
+           /* FMOVEM FPP->memory */
+           uae_u32 ad;
+           int incr = 0;
+
+           if (get_fp_ad (opcode, &ad) == 0) {
+               m68k_setpc (m68k_getpc () - 4);
+               op_illg (opcode);
+               return;
+           }
+           if ((opcode & 0x38) == 0x20) {
+               if (extra & 0x1000)
+                   incr += 4;
+               if (extra & 0x0800)
+                   incr += 4;
+               if (extra & 0x0400)
+                   incr += 4;
+           }
+           ad -= incr;
+           if (extra & 0x1000) {
+               put_long (ad, regs.fpcr);
+               ad += 4;
+           }
+           if (extra & 0x0800) {
+               put_long (ad, get_fpsr());
+               ad += 4;
+           }
+           if (extra & 0x0400) {
+               put_long (ad, regs.fpiar);
+               ad += 4;
+           }
+           ad -= incr;
+           if ((opcode & 0x38) == 0x18)
+               m68k_areg (regs, opcode & 7) = ad;
+           if ((opcode & 0x38) == 0x20)
+               m68k_areg (regs, opcode & 7) = ad;
+       } else {
+           /* FMOVEM memory->FPP */
+           uae_u32 ad;
+
+           if (get_fp_ad (opcode, &ad) == 0) {
+               m68k_setpc (m68k_getpc () - 4);
+               op_illg (opcode);
+               return;
+           }
+           ad = (opcode & 0x38) == 0x20 ? ad - 12 : ad;
+           if (extra & 0x1000) {
+               regs.fpcr = get_long (ad);
+               native_set_fpucw(regs.fpcr);
+               ad += 4;
+           }
+           if (extra & 0x0800) {
+               set_fpsr(get_long (ad));
+               ad += 4;
+           }
+           if (extra & 0x0400) {
+               regs.fpiar = get_long (ad);
+               ad += 4;
+           }
+           if ((opcode & 0x38) == 0x18)
+               m68k_areg (regs, opcode & 7) = ad;
+           if ((opcode & 0x38) == 0x20)
+               m68k_areg (regs, opcode & 7) = ad - 12;
+       }
+       return;
+    case 6:
+    case 7:
+    {
+       uae_u32 ad, list = 0;
+       int incr = 0;
+       if (extra & 0x2000) {
+           /* FMOVEM FPP->memory */
+           if (get_fp_ad (opcode, &ad) == 0) {
+               m68k_setpc (m68k_getpc () - 4);
+               op_illg (opcode);
+               return;
+           }
+           switch ((extra >> 11) & 3) {
+           case 0:     /* static pred */
+               list = extra & 0xff;
+               incr = -1;
+               break;
+           case 1:     /* dynamic pred */
+               list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
+               incr = -1;
+               break;
+           case 2:     /* static postinc */
+               list = extra & 0xff;
+               incr = 1;
+               break;
+           case 3:     /* dynamic postinc */
+               list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
+               incr = 1;
+               break;
+           }
+           while (list) {
+               uae_u32 wrd1, wrd2, wrd3;
+               if (incr < 0) {
+                   from_exten (regs.fp[fpp_movem_index2[list]], &wrd1, &wrd2, &wrd3);
+                   ad -= 4;
+                   put_long (ad, wrd3);
+                   ad -= 4;
+                   put_long (ad, wrd2);
+                   ad -= 4;
+                   put_long (ad, wrd1);
+               } else {
+                   from_exten (regs.fp[fpp_movem_index1[list]], &wrd1, &wrd2, &wrd3);
+                   put_long (ad, wrd1);
+                   ad += 4;
+                   put_long (ad, wrd2);
+                   ad += 4;
+                   put_long (ad, wrd3);
+                   ad += 4;
+               }
+               list = fpp_movem_next[list];
+           }
+           if ((opcode & 0x38) == 0x18)
+               m68k_areg (regs, opcode & 7) = ad;
+           if ((opcode & 0x38) == 0x20)
+               m68k_areg (regs, opcode & 7) = ad;
+       } else {
+           /* FMOVEM memory->FPP */
+           if (get_fp_ad (opcode, &ad) == 0) {
+               m68k_setpc (m68k_getpc () - 4);
+               op_illg (opcode);
+               return;
+           }
+           switch ((extra >> 11) & 3) {
+           case 0:     /* static pred */
+               list = extra & 0xff;
+               incr = -1;
+               break;
+           case 1:     /* dynamic pred */
+               list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
+               incr = -1;
+               break;
+           case 2:     /* static postinc */
+               list = extra & 0xff;
+               incr = 1;
+               break;
+           case 3:     /* dynamic postinc */
+               list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
+               incr = 1;
+               break;
+           }
+           while (list) {
+               uae_u32 wrd1, wrd2, wrd3;
+               if (incr < 0) {
+                   ad -= 4;
+                   wrd3 = get_long (ad);
+                   ad -= 4;
+                   wrd2 = get_long (ad);
+                   ad -= 4;
+                   wrd1 = get_long (ad);
+                   regs.fp[fpp_movem_index2[list]] = to_exten (wrd1, wrd2, wrd3);
+               } else {
+                   wrd1 = get_long (ad);
+                   ad += 4;
+                   wrd2 = get_long (ad);
+                   ad += 4;
+                   wrd3 = get_long (ad);
+                   ad += 4;
+                   regs.fp[fpp_movem_index1[list]] = to_exten (wrd1, wrd2, wrd3);
+               }
+               list = fpp_movem_next[list];
+           }
+           if ((opcode & 0x38) == 0x18)
+               m68k_areg (regs, opcode & 7) = ad;
+           if ((opcode & 0x38) == 0x20)
+               m68k_areg (regs, opcode & 7) = ad;
+       }
+    }
+    return;
+    case 0:
+    case 2: /* Extremely common */
+       reg = (extra >> 7) & 7;
+       if ((extra & 0xfc00) == 0x5c00) {
+           switch (extra & 0x7f) {
+           case 0x00:
+               regs.fp[reg] = 4.0 * atan (1.0);
+               break;
+           case 0x0b:
+               regs.fp[reg] = log10 (2.0);
+               break;
+           case 0x0c:
+               regs.fp[reg] = exp (1.0);
+               break;
+           case 0x0d:
+               regs.fp[reg] = log (exp (1.0)) / log (2.0);
+               break;
+           case 0x0e:
+               regs.fp[reg] = log (exp (1.0)) / log (10.0);
+               break;
+           case 0x0f:
+               regs.fp[reg] = 0.0;
+               break;
+           case 0x30:
+               regs.fp[reg] = log (2.0);
+               break;
+           case 0x31:
+               regs.fp[reg] = log (10.0);
+               break;
+           case 0x32:
+               regs.fp[reg] = 1.0e0;
+               break;
+           case 0x33:
+               regs.fp[reg] = 1.0e1;
+               break;
+           case 0x34:
+               regs.fp[reg] = 1.0e2;
+               break;
+           case 0x35:
+               regs.fp[reg] = 1.0e4;
+               break;
+           case 0x36:
+               regs.fp[reg] = 1.0e8;
+               break;
+           case 0x37:
+               regs.fp[reg] = 1.0e16;
+               break;
+           case 0x38:
+               regs.fp[reg] = 1.0e32;
+               break;
+           case 0x39:
+               regs.fp[reg] = 1.0e64;
+               break;
+           case 0x3a:
+               regs.fp[reg] = 1.0e128;
+               break;
+           case 0x3b:
+               regs.fp[reg] = 1.0e256;
+               break;
+#if 0
+           case 0x3c:
+               regs.fp[reg] = 1.0e512;
+               break;
+           case 0x3d:
+               regs.fp[reg] = 1.0e1024;
+               break;
+           case 0x3e:
+               regs.fp[reg] = 1.0e2048;
+               break;
+           case 0x3f:
+               regs.fp[reg] = 1.0e4096;
+               break;
+#endif
+           default:
+               m68k_setpc (m68k_getpc () - 4);
+               op_illg (opcode);
+               break;
+           }
+           return;
+       }
+       if (get_fp_value (opcode, extra, &src) == 0) {
+           m68k_setpc (m68k_getpc () - 4);
+           op_illg (opcode);
+           return;
+       }
+       switch (extra & 0x7f) {
+       case 0x00:              /* FMOVE */
+       case 0x40:  /* Explicit rounding. This is just a quick fix. Same
+                    * for all other cases that have three choices */
+       case 0x44:   
+           regs.fp[reg] = src;
+           /* Brian King was here.  <ea> to register needs FPSR updated.
+            * See page 3-73 in Motorola 68K programmers reference manual.
+            * %%%FPU */
+           if ((extra & 0x44) == 0x40)
+               fround (reg);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x01:              /* FINT */
+           /* need to take the current rounding mode into account */
+           regs.fp[reg] = (fptype)toint(src);
+           break;
+       case 0x02:              /* FSINH */
+           regs.fp[reg] = sinh (src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x03:              /* FINTRZ */
+           regs.fp[reg] = (int) src;
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x04:              /* FSQRT */
+       case 0x41:
+       case 0x45:
+           regs.fp[reg] = sqrt (src);
+           if ((extra & 0x44) == 0x40)
+               fround (reg);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x06:              /* FLOGNP1 */
+           regs.fp[reg] = log (src + 1.0);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x08:              /* FETOXM1 */
+           regs.fp[reg] = exp (src) - 1.0;
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x09:              /* FTANH */
+           regs.fp[reg] = tanh (src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x0a:              /* FATAN */
+           regs.fp[reg] = atan (src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x0c:              /* FASIN */
+           regs.fp[reg] = asin (src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x0d:              /* FATANH */
+#if 1                          /* The BeBox doesn't have atanh, and it isn't in the HPUX libm either */
+           regs.fp[reg] = log ((1 + src) / (1 - src)) / 2;
+#else
+           regs.fp[reg] = atanh (src);
+#endif
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x0e:              /* FSIN */
+           regs.fp[reg] = sin (src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x0f:              /* FTAN */
+           regs.fp[reg] = tan (src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x10:              /* FETOX */
+           regs.fp[reg] = exp (src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x11:              /* FTWOTOX */
+           regs.fp[reg] = pow (2.0, src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x12:              /* FTENTOX */
+           regs.fp[reg] = pow (10.0, src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x14:              /* FLOGN */
+           regs.fp[reg] = log (src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x15:              /* FLOG10 */
+           regs.fp[reg] = log10 (src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x16:              /* FLOG2 */
+           regs.fp[reg] = log (src) / log (2.0);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x18:              /* FABS */
+       case 0x58:
+       case 0x5c:
+           regs.fp[reg] = src < 0 ? -src : src;
+           if ((extra & 0x44) == 0x40)
+               fround (reg);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x19:              /* FCOSH */
+           regs.fp[reg] = cosh (src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x1a:              /* FNEG */
+       case 0x5a:
+       case 0x5e:
+           regs.fp[reg] = -src;
+           if ((extra & 0x44) == 0x40)
+               fround (reg);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x1c:              /* FACOS */
+           regs.fp[reg] = acos (src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x1d:              /* FCOS */
+           regs.fp[reg] = cos (src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x1e:              /* FGETEXP */
+       {
+           int expon;
+           frexp (src, &expon);
+           regs.fp[reg] = (double) (expon - 1);
+           MAKE_FPSR (regs.fp[reg]);
+       }
+       break;
+       case 0x1f:              /* FGETMAN */
+       {
+           int expon;
+           regs.fp[reg] = frexp (src, &expon) * 2.0;
+           MAKE_FPSR (regs.fp[reg]);
+       }
+       break;
+       case 0x20:              /* FDIV */
+       case 0x60:
+       case 0x64:
+           regs.fp[reg] /= src;
+           if ((extra & 0x44) == 0x40)
+               fround (reg);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x21:              /* FMOD */
+           regs.fp[reg] = regs.fp[reg] - (double) ((int) (regs.fp[reg] / src)) * src;
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x22:              /* FADD */
+       case 0x62:
+       case 0x66:
+           regs.fp[reg] += src;
+           if ((extra & 0x44) == 0x40)
+               fround (reg);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x23:              /* FMUL */
+       case 0x63:
+       case 0x67:
+           regs.fp[reg] *= src;
+           if ((extra & 0x44) == 0x40)
+               fround (reg);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x24:              /* FSGLDIV */
+           regs.fp[reg] /= src;
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x25:              /* FREM */
+           regs.fp[reg] = regs.fp[reg] - (double) ((int) (regs.fp[reg] / src + 0.5)) * src;
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x26:              /* FSCALE */
+           regs.fp[reg] *= exp (log (2.0) * src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x27:              /* FSGLMUL */
+           regs.fp[reg] *= src;
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x28:              /* FSUB */
+       case 0x68:
+       case 0x6c:
+           regs.fp[reg] -= src;
+           if ((extra & 0x44) == 0x40)
+               fround (reg);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x30:              /* FSINCOS */
+       case 0x31:
+       case 0x32:
+       case 0x33:
+       case 0x34:
+       case 0x35:
+       case 0x36:
+       case 0x37:
+           regs.fp[reg] = sin (src);
+           regs.fp[extra & 7] = cos (src);
+           MAKE_FPSR (regs.fp[reg]);
+           break;
+       case 0x38:              /* FCMP */
+       {
+           fptype tmp = regs.fp[reg] - src;
+           regs.fpsr = 0;
+           MAKE_FPSR (tmp);
+       }
+       break;
+       case 0x3a:              /* FTST */
+           regs.fpsr = 0;
+           MAKE_FPSR (src);
+           break;
+       default:
+           m68k_setpc (m68k_getpc () - 4);
+           op_illg (opcode);
+           break;
+       }
+       return;
+    }
+    m68k_setpc (m68k_getpc () - 4);
+    op_illg (opcode);
+}
+
+#endif
+
+uae_u8 *restore_fpu (uae_u8 *src)
+{
+    int model, i;
+
+    model = restore_u32();
+    restore_u32 ();
+    if (currprefs.cpu_level == 2) {
+       currprefs.cpu_level++;
+        init_m68k_full ();
+    }
+    changed_prefs.cpu_level = currprefs.cpu_level;
+    for (i = 0; i < 8; i++) {
+       uae_u32 w1 = restore_u32 ();
+       uae_u32 w2 = restore_u32 ();
+       uae_u32 w3 = restore_u16 ();
+       regs.fp[i] = to_exten (w1, w2, w3);
+    }
+    regs.fpcr = restore_u32 ();
+    regs.fpsr = restore_u32 ();
+    regs.fpiar = restore_u32 ();
+    return src;
+}
+
+uae_u8 *save_fpu (int *len, uae_u8 *dstptr)
+{
+    uae_u8 *dstbak,*dst;
+    int model,i;
+
+    *len = 0;
+    switch (currprefs.cpu_level)
+    {
+       case 3:
+       model = 68881;
+       break;
+       case 4:
+       model = 68040;
+       break;
+       case 6:
+       model = 68060;
+       break;
+       default:
+       return 0;
+    }
+    if (dstptr)
+       dstbak = dst = dstptr;
+    else
+        dstbak = dst = malloc(4+4+8*10+4+4+4);
+    save_u32 (model);
+    save_u32 (0);
+    for (i = 0; i < 8; i++) {
+       uae_u32 w1, w2, w3;
+       from_exten (regs.fp[i], &w1, &w2, &w3);
+       save_u32 (w1);
+       save_u32 (w2);
+       save_u16 (w3);
+    }
+    save_u32 (regs.fpcr);
+    save_u32 (regs.fpsr);
+    save_u32 (regs.fpiar);
+    *len = dst - dstbak;
+    return dstbak;
+}
diff --git a/fsdb.c b/fsdb.c
new file mode 100755 (executable)
index 0000000..369b705
--- /dev/null
+++ b/fsdb.c
@@ -0,0 +1,334 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Library of functions to make emulated filesystem as independent as
+  * possible of the host filesystem's capabilities.
+  *
+  * Copyright 1999 Bernd Schmidt
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "threaddep/thread.h"
+#include "options.h"
+#include "uae.h"
+#include "memory.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "filesys.h"
+#include "autoconf.h"
+#include "compiler.h"
+#include "fsusage.h"
+#include "native2amiga.h"
+#include "scsidev.h"
+#include "fsdb.h"
+
+/* The on-disk format is as follows:
+ * Offset 0, 1 byte, valid
+ * Offset 1, 4 bytes, mode
+ * Offset 5, 257 bytes, aname
+ * Offset 263, 257 bytes, nname
+ * Offset 518, 81 bytes, comment
+ */
+
+char *nname_begin (char *nname)
+{
+    char *p = strrchr (nname, FSDB_DIR_SEPARATOR);
+    if (p)
+       return p + 1;
+    return nname;
+}
+
+/* Find the name REL in directory DIRNAME.  If we find a file that
+ * has exactly the same name, return REL.  If we find a file that
+ * has the same name when compared case-insensitively, return a
+ * malloced string that contains the name we found.  If no file
+ * exists that compares equal to REL, return 0.  */
+char *fsdb_search_dir (const char *dirname, char *rel)
+{
+    char *p = 0;
+    struct dirent *de;
+    DIR *dir = opendir (dirname);
+
+    /* This really shouldn't happen...  */
+    if (! dir)
+       return 0;
+    
+    while (p == 0 && (de = readdir (dir)) != 0) {
+       if (strcmp (de->d_name, rel) == 0)
+           p = rel;
+       else if (strcasecmp (de->d_name, rel) == 0)
+           p = my_strdup (de->d_name);
+    }
+    closedir (dir);
+    return p;
+}
+
+static FILE *get_fsdb (a_inode *dir, const char *mode)
+{
+    char *n;
+    FILE *f;
+    
+    n = build_nname (dir->nname, FSDB_FILE);
+    f = fopen (n, mode);
+    free (n);
+    return f;
+}
+
+static void kill_fsdb (a_inode *dir)
+{
+    char *n = build_nname (dir->nname, FSDB_FILE);
+    unlink (n);
+    free (n);
+}
+
+static void fsdb_fixup (FILE *f, char *buf, int size, a_inode *base)
+{
+    char *nname;
+    int ret;
+
+    if (buf[0] == 0)
+       return;
+    nname = build_nname (base->nname, buf + 5 + 257);
+    ret = fsdb_exists (nname);
+    if (ret) {
+        free (nname);
+       return;
+    }
+    write_log ("uaefsdb '%s' deleted\n", nname);
+    /* someone deleted this file/dir outside of emulation.. */
+    buf[0] = 0;
+    free (nname);
+}
+
+/* Prune the db file the first time this directory is opened in a session.  */
+void fsdb_clean_dir (a_inode *dir)
+{
+    char buf[1 + 4 + 257 + 257 + 81];
+    char *n = build_nname (dir->nname, FSDB_FILE);
+    FILE *f = fopen (n, "r+b");
+    off_t pos1 = 0, pos2;
+
+    if (f == 0) {
+       free (n);
+       return;
+    }
+    for (;;) {
+       pos2 = ftell (f);
+       if (fread (buf, 1, sizeof buf, f) < sizeof buf)
+           break;
+       fsdb_fixup (f, buf, sizeof buf, dir);
+       if (buf[0] == 0)
+           continue;
+       if (pos1 != pos2) {
+           fseek (f, pos1, SEEK_SET);
+           fwrite (buf, 1, sizeof buf, f);
+           fseek (f, pos2 + sizeof buf, SEEK_SET);
+       }
+       pos1 += sizeof buf;
+    }
+    fclose (f);
+    truncate (n, pos1);
+    free (n);
+}
+
+static a_inode *aino_from_buf (a_inode *base, char *buf, long off)
+{
+    uae_u32 mode;
+    a_inode *aino = (a_inode *) xcalloc (sizeof (a_inode), 1);
+
+    mode = do_get_mem_long ((uae_u32 *)(buf + 1));
+    buf += 5;
+    aino->aname = my_strdup (buf);
+    buf += 257;
+    aino->nname = build_nname (base->nname, buf);
+    buf += 257;
+    aino->comment = *buf != '\0' ? my_strdup (buf) : 0;
+    fsdb_fill_file_attrs (aino);
+    aino->amigaos_mode = mode;
+    aino->has_dbentry = 1;
+    aino->dirty = 0;
+    aino->db_offset = off;
+    write_log("aino=%d a='%s' n='%s' c='%s' mode=%d dir=%d\n",off,aino->aname,aino->nname,aino->comment,aino->amigaos_mode,aino->dir);
+    return aino;
+}
+
+a_inode *fsdb_lookup_aino_aname (a_inode *base, const char *aname)
+{
+    FILE *f = get_fsdb (base, "r+b");
+
+    if (f == 0)
+       return 0;
+
+    for (;;) {
+       char buf[1 + 4 + 257 + 257 + 81];
+       if (fread (buf, 1, sizeof buf, f) < sizeof buf)
+           break;
+       if (buf[0] != 0 && same_aname (buf + 5, aname)) {
+           long pos = ftell (f) - sizeof buf;
+           fclose (f);
+           return aino_from_buf (base, buf, pos);
+       }
+    }
+    fclose (f);
+    return 0;
+}
+
+a_inode *fsdb_lookup_aino_nname (a_inode *base, const char *nname)
+{
+    FILE *f = get_fsdb (base, "r+b");
+
+    if (f == 0)
+       return 0;
+
+    for (;;) {
+       char buf[1 + 4 + 257 + 257 + 81];
+       if (fread (buf, 1, sizeof buf, f) < sizeof buf)
+           break;
+       if (buf[0] != 0 && strcmp (buf + 5 + 257, nname) == 0) {
+           long pos = ftell (f) - sizeof buf;
+           fclose (f);
+           return aino_from_buf (base, buf, pos);
+       }
+    }
+    fclose (f);
+    return 0;
+}
+
+int fsdb_used_as_nname (a_inode *base, const char *nname)
+{
+    FILE *f = get_fsdb (base, "r+b");
+    char buf[1 + 4 + 257 + 257 + 81];
+    
+    if (f == 0)
+       return 0;
+    for (;;) {
+       if (fread (buf, 1, sizeof buf, f) < sizeof buf)
+           break;
+       if (buf[0] == 0)
+           continue;
+       if (strcmp (buf + 5 + 257, nname) == 0) {
+           fclose (f);
+           return 1;
+       }
+    }
+    fclose (f);
+    return 0;
+}
+
+static int needs_dbentry (a_inode *aino)
+{
+    const char *nn_begin;
+
+    if (aino->deleted)
+       return 0;
+    
+    if (! fsdb_mode_representable_p (aino) || aino->comment != 0)
+       return 1;
+
+    nn_begin = nname_begin (aino->nname);
+    return strcmp (nn_begin, aino->aname) != 0;
+}
+
+static void write_aino (FILE *f, a_inode *aino)
+{
+    char buf[1 + 4 + 257 + 257 + 81];
+    buf[0] = aino->needs_dbentry;
+    do_put_mem_long ((uae_u32 *)(buf + 1), aino->amigaos_mode);
+    strncpy (buf + 5, aino->aname, 256);
+    buf[5 + 256] = '\0';
+    strncpy (buf + 5 + 257, nname_begin (aino->nname), 256);
+    buf[5 + 257 + 256] = '\0';
+    strncpy (buf + 5 + 2*257, aino->comment ? aino->comment : "", 80);
+    buf[5 + 2 * 257 + 80] = '\0';
+    aino->db_offset = ftell (f);
+    fwrite (buf, 1, sizeof buf, f);
+    aino->has_dbentry = aino->needs_dbentry;
+    write_log ("%d '%s' '%s' written\n", aino->db_offset, aino->aname, aino->nname);
+}
+
+/* Write back the db file for a directory.  */
+
+void fsdb_dir_writeback (a_inode *dir)
+{
+    FILE *f;
+    int changes_needed = 0;
+    int entries_needed = 0;
+    a_inode *aino;
+    uae_u8 *tmpbuf;
+    int size, i;
+
+    /* First pass: clear dirty bits where unnecessary, and see if any work
+     * needs to be done.  */
+    for (aino = dir->child; aino; aino = aino->sibling) {
+/*
+       int old_needs_dbentry = aino->needs_dbentry || aino->has_dbentry;
+       aino->needs_dbentry = needs_dbentry (aino);
+       entries_needed |= aino->has_dbentry | aino->needs_dbentry;
+*/
+       int old_needs_dbentry = aino->has_dbentry;
+       int need = needs_dbentry (aino);
+       aino->needs_dbentry = need;
+       entries_needed |= need;
+       if (! aino->dirty)
+           continue;
+       if (! aino->needs_dbentry && ! old_needs_dbentry)
+           aino->dirty = 0;
+       else
+           changes_needed = 1;
+    }
+    if (! entries_needed) {
+       kill_fsdb (dir);
+       return;
+    }
+
+    if (! changes_needed)
+       return;
+
+    f = get_fsdb (dir, "r+b");
+    if (f == 0) {
+       if (currprefs.filesys_no_uaefsdb)
+           return;
+       f = get_fsdb (dir, "w+b");
+       if (f == 0)
+           /* This shouldn't happen... */
+           return;
+    }
+    fseek (f, 0, SEEK_END);
+    size = ftell (f);
+    fseek (f, 0, SEEK_SET);
+    tmpbuf = 0;
+    if (size > 0) {
+       tmpbuf = malloc (size);
+       fread (tmpbuf, 1, size, f);
+    }
+    write_log ("**** updating '%s'\n", dir->aname);
+
+    for (aino = dir->child; aino; aino = aino->sibling) {
+       if (! aino->dirty)
+           continue;
+       aino->dirty = 0;
+
+       i = 0;
+       while (!aino->has_dbentry && i < size) {
+           if (!strcmp (tmpbuf + i + 5, aino->aname)) {
+               aino->has_dbentry = 1;
+               aino->db_offset = i;
+           }
+           i += 1 + 4 + 257 + 257 + 81;
+       }
+
+       if (! aino->has_dbentry) {
+           fseek (f, 0, SEEK_END);
+           aino->has_dbentry = 1;
+       } else {
+           fseek (f, aino->db_offset, SEEK_SET);
+       }
+       write_aino (f, aino);
+    }
+    write_log ("end\n");
+    fclose (f);
+    free (tmpbuf);
+}
diff --git a/fsdb_unix.c b/fsdb_unix.c
new file mode 100755 (executable)
index 0000000..e2b2232
--- /dev/null
@@ -0,0 +1,105 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Library of functions to make emulated filesystem as independent as
+  * possible of the host filesystem's capabilities.
+  * This is the Unix version.
+  *
+  * Copyright 1999 Bernd Schmidt
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "fsdb.h"
+
+/* Return nonzero for any name we can't create on the native filesystem.  */
+int fsdb_name_invalid (const char *n)
+{
+    if (strcmp (n, FSDB_FILE) == 0)
+       return 1;
+    if (n[0] != '.')
+       return 0;
+    if (n[1] == '\0')
+       return 1;
+    return n[1] == '.' && n[2] == '\0';
+}
+
+/* For an a_inode we have newly created based on a filename we found on the
+ * native fs, fill in information about this file/directory.  */
+int fsdb_fill_file_attrs (a_inode *aino)
+{
+    struct stat statbuf;
+    /* This really shouldn't happen...  */
+    if (stat (aino->nname, &statbuf) == -1)
+       return 0;
+    aino->dir = S_ISDIR (statbuf.st_mode) ? 1 : 0;
+    aino->amigaos_mode = ((S_IXUSR & statbuf.st_mode ? 0 : A_FIBF_EXECUTE)
+                         | (S_IWUSR & statbuf.st_mode ? 0 : A_FIBF_WRITE)
+                         | (S_IRUSR & statbuf.st_mode ? 0 : A_FIBF_READ));
+    return 1;
+}
+
+int fsdb_set_file_attrs (a_inode *aino, int mask)
+{
+    struct stat statbuf;
+    int mode;
+
+    if (stat (aino->nname, &statbuf) == -1)
+       return ERROR_OBJECT_NOT_AROUND;
+
+    mode = statbuf.st_mode;
+    /* Unix dirs behave differently than AmigaOS ones.  */
+    if (! aino->dir) {
+       if (mask & A_FIBF_READ)
+           mode &= ~S_IRUSR;
+       else
+           mode |= S_IRUSR;
+
+       if (mask & A_FIBF_WRITE)
+           mode &= ~S_IWUSR;
+       else
+           mode |= S_IWUSR;
+
+       if (mask & A_FIBF_EXECUTE)
+           mode &= ~S_IXUSR;
+       else
+           mode |= S_IXUSR;
+
+       chmod (aino->nname, mode);
+    }
+
+    aino->amigaos_mode = mask;
+    aino->dirty = 1;
+    return 0;
+}
+
+/* Return nonzero if we can represent the amigaos_mode of AINO within the
+ * native FS.  Return zero if that is not possible.  */
+int fsdb_mode_representable_p (const a_inode *aino)
+{
+    if (aino->dir)
+       return aino->amigaos_mode == 0;
+    return (aino->amigaos_mode & (A_FIBF_DELETE | A_FIBF_SCRIPT | A_FIBF_PURE)) == 0;
+}
+
+char *fsdb_create_unique_nname (a_inode *base, const char *suggestion)
+{
+    char tmp[256] = "__uae___";
+    strncat (tmp, suggestion, 240);
+    for (;;) {
+       int i;
+       char *p = build_nname (base->nname, tmp);
+       if (access (p, R_OK) < 0 && errno == ENOENT) {
+           printf ("unique name: %s\n", p);
+           return p;
+       }
+       free (p);
+
+       /* tmpnam isn't reentrant and I don't really want to hack configure
+        * right now to see whether tmpnam_r is available...  */
+       for (i = 0; i < 8; i++) {
+           tmp[i] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"[random () % 63];
+       }
+    }
+}
diff --git a/fsusage.c b/fsusage.c
new file mode 100755 (executable)
index 0000000..206e706
--- /dev/null
+++ b/fsusage.c
@@ -0,0 +1,355 @@
+/* fsusage.c -- return space usage of mounted filesystems
+   Copyright (C) 1991, 1992, 1996 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "sysconfig.h"
+
+#include <stdlib.h>
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#include "fsusage.h"
+
+/* Return the number of TOSIZE-byte blocks used by
+   BLOCKS FROMSIZE-byte blocks, rounding away from zero.
+   TOSIZE must be positive.  Return -1 if FROMSIZE is not positive.  */
+
+static long
+adjust_blocks (blocks, fromsize, tosize)
+     long blocks;
+     int fromsize, tosize;
+{
+  if (tosize <= 0)
+    abort ();
+  if (fromsize <= 0)
+    return -1;
+
+  if (fromsize == tosize)      /* e.g., from 512 to 512 */
+    return blocks;
+  else if (fromsize > tosize)  /* e.g., from 2048 to 512 */
+    return blocks * (fromsize / tosize);
+  else                         /* e.g., from 256 to 512 */
+    return (blocks + (blocks < 0 ? -1 : 1)) / (tosize / fromsize);
+}
+
+#ifdef _WIN32
+#include "sysdeps.h"
+#include "od-win32/posixemu.h"
+#include <windows.h>
+int
+get_fs_usage (path, disk, fsp)
+     const char *path;
+     const char *disk;
+     struct fs_usage *fsp;
+{
+    char buf1[1024];
+    char buf2[1024];
+    DWORD SectorsPerCluster;
+    DWORD BytesPerSector;
+    DWORD NumberOfFreeClusters;
+    DWORD TotalNumberOfClusters;
+
+    fname_atow (path, buf1, sizeof buf1);
+
+    GetFullPathName (buf1, sizeof buf2, buf2, NULL);
+
+    buf2[3] = 0;
+
+    if (!GetDiskFreeSpace (buf2, &SectorsPerCluster, &BytesPerSector,
+                          &NumberOfFreeClusters, &TotalNumberOfClusters))
+    {
+       /* lasterror = GetLastError ();*/
+       return -1;
+    }
+
+    /* HACK ALERT! WinNT returns 0 in TotalNumberOfClusters for an audio-CD, which calls the GURU! */
+    if( ( TotalNumberOfClusters == 0 ) && 
+        ( GetDriveType( buf2 ) == DRIVE_CDROM ) )
+    {
+        TotalNumberOfClusters = 327680;
+    }
+
+    BytesPerSector *= SectorsPerCluster;
+    fsp->fsu_blocks = adjust_blocks (TotalNumberOfClusters, BytesPerSector, 512);
+    fsp->fsu_bavail = adjust_blocks (NumberOfFreeClusters, BytesPerSector, 512);
+
+    return 0;
+}
+
+#else /* ! _WIN32 */
+
+int statfs ();
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+
+#if HAVE_SYS_MOUNT_H
+# include <sys/mount.h>
+#endif
+
+#if HAVE_SYS_VFS_H
+# include <sys/vfs.h>
+#endif
+
+#if HAVE_SYS_FS_S5PARAM_H      /* Fujitsu UXP/V */
+# include <sys/fs/s5param.h>
+#endif
+
+#if defined (HAVE_SYS_FILSYS_H) && !defined (_CRAY)
+# include <sys/filsys.h>       /* SVR2 */
+#endif
+
+#if HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#if HAVE_SYS_STATFS_H
+# include <sys/statfs.h>
+#endif
+
+#if HAVE_DUSTAT_H              /* AIX PS/2 */
+# include <sys/dustat.h>
+#endif
+
+#if HAVE_SYS_STATVFS_H         /* SVR4 */
+# include <sys/statvfs.h>
+int statvfs ();
+#endif
+
+/* Read LEN bytes at PTR from descriptor DESC, retrying if interrupted.
+   Return the actual number of bytes read, zero for EOF, or negative
+   for an error.  */
+
+int
+safe_read (desc, ptr, len)
+     int desc;
+     char *ptr;
+     int len;
+{
+  int n_chars;
+
+  if (len <= 0)
+    return len;
+
+#ifdef EINTR
+  do
+    {
+      n_chars = read (desc, ptr, len);
+    }
+  while (n_chars < 0 && errno == EINTR);
+#else
+  n_chars = read (desc, ptr, len);
+#endif
+
+  return n_chars;
+}
+
+/* Fill in the fields of FSP with information about space usage for
+   the filesystem on which PATH resides.
+   DISK is the device on which PATH is mounted, for space-getting
+   methods that need to know it.
+   Return 0 if successful, -1 if not.  When returning -1, ensure that
+   ERRNO is either a system error value, or zero if DISK is NULL
+   on a system that requires a non-NULL value.  */
+int
+get_fs_usage (path, disk, fsp)
+     const char *path;
+     const char *disk;
+     struct fs_usage *fsp;
+{
+#ifdef STAT_STATFS3_OSF1
+# define CONVERT_BLOCKS(B) adjust_blocks ((B), fsd.f_fsize, 512)
+
+  struct statfs fsd;
+
+  if (statfs (path, &fsd, sizeof (struct statfs)) != 0)
+    return -1;
+
+#endif /* STAT_STATFS3_OSF1 */
+
+#ifdef STAT_STATFS2_FS_DATA    /* Ultrix */
+# define CONVERT_BLOCKS(B) adjust_blocks ((B), 1024, 512)
+
+  struct fs_data fsd;
+
+  if (statfs (path, &fsd) != 1)
+    return -1;
+  fsp->fsu_blocks = CONVERT_BLOCKS (fsd.fd_req.btot);
+  fsp->fsu_bfree = CONVERT_BLOCKS (fsd.fd_req.bfree);
+  fsp->fsu_bavail = CONVERT_BLOCKS (fsd.fd_req.bfreen);
+  fsp->fsu_files = fsd.fd_req.gtot;
+  fsp->fsu_ffree = fsd.fd_req.gfree;
+
+#endif /* STAT_STATFS2_FS_DATA */
+
+#ifdef STAT_READ_FILSYS                /* SVR2 */
+# ifndef SUPERBOFF
+#  define SUPERBOFF (SUPERB * 512)
+# endif
+# define CONVERT_BLOCKS(B) \
+    adjust_blocks ((B), (fsd.s_type == Fs2b ? 1024 : 512), 512)
+
+  struct filsys fsd;
+  int fd;
+
+  if (! disk)
+    {
+      errno = 0;
+      return -1;
+    }
+
+  fd = open (disk, O_RDONLY);
+  if (fd < 0)
+    return -1;
+  lseek (fd, (long) SUPERBOFF, 0);
+  if (safe_read (fd, (char *) &fsd, sizeof fsd) != sizeof fsd)
+    {
+      close (fd);
+      return -1;
+    }
+  close (fd);
+  fsp->fsu_blocks = CONVERT_BLOCKS (fsd.s_fsize);
+  fsp->fsu_bfree = CONVERT_BLOCKS (fsd.s_tfree);
+  fsp->fsu_bavail = CONVERT_BLOCKS (fsd.s_tfree);
+  fsp->fsu_files = (fsd.s_isize - 2) * INOPB * (fsd.s_type == Fs2b ? 2 : 1);
+  fsp->fsu_ffree = fsd.s_tinode;
+
+#endif /* STAT_READ_FILSYS */
+
+#ifdef STAT_STATFS2_BSIZE      /* 4.3BSD, SunOS 4, HP-UX, AIX */
+# define CONVERT_BLOCKS(B) adjust_blocks ((B), fsd.f_bsize, 512)
+
+  struct statfs fsd;
+
+  if (statfs (path, &fsd) < 0)
+    return -1;
+
+# ifdef STATFS_TRUNCATES_BLOCK_COUNTS
+
+  /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
+     struct statfs are truncated to 2GB.  These conditions detect that
+     truncation, presumably without botching the 4.1.1 case, in which
+     the values are not truncated.  The correct counts are stored in
+     undocumented spare fields.  */
+  if (fsd.f_blocks == 0x1fffff && fsd.f_spare[0] > 0)
+    {
+      fsd.f_blocks = fsd.f_spare[0];
+      fsd.f_bfree = fsd.f_spare[1];
+      fsd.f_bavail = fsd.f_spare[2];
+    }
+# endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
+
+#endif /* STAT_STATFS2_BSIZE */
+
+#ifdef STAT_STATFS2_FSIZE      /* 4.4BSD */
+# define CONVERT_BLOCKS(B) adjust_blocks ((B), fsd.f_fsize, 512)
+
+  struct statfs fsd;
+
+  if (statfs (path, &fsd) < 0)
+    return -1;
+
+#endif /* STAT_STATFS2_FSIZE */
+
+#ifdef STAT_STATFS4            /* SVR3, Dynix, Irix, AIX */
+# if _AIX || defined(_CRAY)
+#  define CONVERT_BLOCKS(B) adjust_blocks ((B), fsd.f_bsize, 512)
+#  ifdef _CRAY
+#   define f_bavail f_bfree
+#  endif
+# else
+#  define CONVERT_BLOCKS(B) (B)
+#  ifndef _SEQUENT_            /* _SEQUENT_ is DYNIX/ptx */
+#   ifndef DOLPHIN             /* DOLPHIN 3.8.alfa/7.18 has f_bavail */
+#    define f_bavail f_bfree
+#   endif
+#  endif
+# endif
+
+  struct statfs fsd;
+
+  if (statfs (path, &fsd, sizeof fsd, 0) < 0)
+    return -1;
+  /* Empirically, the block counts on most SVR3 and SVR3-derived
+     systems seem to always be in terms of 512-byte blocks,
+     no matter what value f_bsize has.  */
+
+#endif /* STAT_STATFS4 */
+
+#ifdef STAT_STATVFS            /* SVR4 */
+# define CONVERT_BLOCKS(B) \
+    adjust_blocks ((B), fsd.f_frsize ? fsd.f_frsize : fsd.f_bsize, 512)
+
+  struct statvfs fsd;
+
+  if (statvfs (path, &fsd) < 0)
+    return -1;
+  /* f_frsize isn't guaranteed to be supported.  */
+
+#endif /* STAT_STATVFS */
+
+#if !defined(STAT_STATFS2_FS_DATA) && !defined(STAT_READ_FILSYS)
+                               /* !Ultrix && !SVR2 */
+
+  fsp->fsu_blocks = CONVERT_BLOCKS (fsd.f_blocks);
+  fsp->fsu_bfree = CONVERT_BLOCKS (fsd.f_bfree);
+  fsp->fsu_bavail = CONVERT_BLOCKS (fsd.f_bavail);
+  fsp->fsu_files = fsd.f_files;
+  fsp->fsu_ffree = fsd.f_ffree;
+
+#endif /* not STAT_STATFS2_FS_DATA && not STAT_READ_FILSYS */
+
+  return 0;
+}
+
+#if defined(_AIX) && defined(_I386)
+/* AIX PS/2 does not supply statfs.  */
+
+int
+statfs (path, fsb)
+     char *path;
+     struct statfs *fsb;
+{
+  struct stat stats;
+  struct dustat fsd;
+
+  if (stat (path, &stats))
+    return -1;
+  if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd)))
+    return -1;
+  fsb->f_type   = 0;
+  fsb->f_bsize  = fsd.du_bsize;
+  fsb->f_blocks = fsd.du_fsize - fsd.du_isize;
+  fsb->f_bfree  = fsd.du_tfree;
+  fsb->f_bavail = fsd.du_tfree;
+  fsb->f_files  = (fsd.du_isize - 2) * fsd.du_inopb;
+  fsb->f_ffree  = fsd.du_tinode;
+  fsb->f_fsid.val[0] = fsd.du_site;
+  fsb->f_fsid.val[1] = fsd.du_pckno;
+  return 0;
+}
+
+#endif /* _AIX && _I386 */
+
+#endif /* ! _WIN32 */
diff --git a/genblitter.c b/genblitter.c
new file mode 100755 (executable)
index 0000000..0cb3204
--- /dev/null
@@ -0,0 +1,271 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Optimized blitter minterm function generator
+  *
+  * Copyright 1995,1996 Bernd Schmidt
+  * Copyright 1996 Alessandro Bissacco
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "genblitter.h"
+
+/* Here is the minterm table used in blitter function generation */
+
+static unsigned char blttbl[]= {
+    0x00, 0x0a, 0x2a, 0x30, 0x3a, 0x3c, 0x4a, 0x6a, 0x8a, 0x8c, 0x9a, 0xa8,
+    0xaa, 0xb1, 0xca, 0xcc, 0xd8, 0xe2, 0xea, 0xf0, 0xfa, 0xfc
+};
+
+static void generate_include(void)
+{
+    int minterm;
+    printf("STATIC_INLINE uae_u32 blit_func(uae_u32 srca, uae_u32 srcb, uae_u32 srcc, uae_u8 mt)\n{\nswitch(mt){\n");
+    for (minterm = 0; minterm < 256; minterm++) {
+       printf("case 0x%x:\n", minterm);
+       printf("\treturn %s;\n", blitops[minterm].s);
+    }
+    printf("}\n");
+    printf("return 0;\n"); /* No, sir, it doesn't! */
+    printf("}\n");
+}
+
+static void generate_func(void)
+{
+    unsigned int i;
+    printf("#include \"sysconfig.h\"\n");
+    printf("#include \"sysdeps.h\"\n");
+    printf("#include \"config.h\"\n");
+    printf("#include \"options.h\"\n");
+    printf("#include \"custom.h\"\n");
+    printf("#include \"memory.h\"\n");
+    printf("#include \"blitter.h\"\n");
+    printf("#include \"blitfunc.h\"\n\n");
+
+    for (i = 0; i < sizeof(blttbl); i++) {
+       int active = blitops[blttbl[i]].used;
+       int a_is_on = active & 1, b_is_on = active & 2, c_is_on = active & 4;
+       printf("void blitdofast_%x (uaecptr pta, uaecptr ptb, uaecptr ptc, uaecptr ptd, struct bltinfo *b)\n",blttbl[i]);
+       printf("{\n");
+       printf("int i,j;\n");
+       printf("uae_u32 totald = 0;\n");
+#if 0
+       printf("if (currprefs.blits_32bit_enabled && b->hblitsize > 1");
+       if (a_is_on) printf(" && !b->blitashift && b->bltafwm==0xffff && b->bltalwm==0xffff");
+       if (b_is_on) printf(" && !b->blitbshift");
+       printf(") {\n");
+       if (a_is_on) printf("uae_u32 srca=((uae_u32)b->bltadat << 16) | b->bltadat;\n");
+       if (b_is_on) printf("uae_u32 srcb=((uae_u32)b->bltbdat << 16) | b->bltbdat;\n");
+       if (c_is_on) printf("uae_u32 srcc=((uae_u32)b->bltcdat << 16) | b->bltcdat;\n");
+       printf("uae_u32 dest;\n");
+       printf("int count=b->hblitsize/2, oddword=b->hblitsize&1;\n");
+       printf("for (j=0;j<b->vblitsize;j++) {\n");
+       printf("\tfor(i=0;i<count;i++) {\n");
+       if (a_is_on) printf("\t\tif (pta) {srca=*((uae_u32 *)pta); pta += 4;}\n");
+       if (b_is_on) printf("\t\tif (ptb) {srcb=*((uae_u32 *)ptb); ptb += 4;}\n");
+       if (c_is_on) printf("\t\tif (ptc) {srcc=*((uae_u32 *)ptc); ptc += 4;}\n");
+       printf("\t\tdest = %s;\n", blitops[blttbl[i]].s);
+       printf("\t\ttotald |= dest;\n");
+       printf("\t\tif (ptd) {*(uae_u32 *)ptd=dest; ptd += 4;}\n");
+       printf("\t}\n");
+       printf("\tif (oddword) {\n");
+       if (a_is_on) printf("\t\tif (pta) { srca=(uae_u32)*(uae_u16 *)pta; pta += 2; }\n");
+       if (b_is_on) printf("\t\tif (ptb) { srcb=(uae_u32)*(uae_u16 *)ptb; ptb += 2; }\n");
+       if (c_is_on) printf("\t\tif (ptc) { srcc=(uae_u32)*(uae_u16 *)ptc; ptc += 2; }\n");
+       printf("\t\tdest = %s;\n", blitops[blttbl[i]].s);
+       printf("\t\ttotald |= dest;\n");
+       printf("\t\tif (ptd) { *(uae_u16 *)ptd= dest; ptd += 2; }\n");
+       printf("\t}\n");
+       if (a_is_on) printf("\tif (pta) pta += b->bltamod;\n");
+       if (b_is_on) printf("\tif (ptb) ptb += b->bltbmod;\n");
+       if (c_is_on) printf("\tif (ptc) ptc += b->bltcmod;\n");
+       printf("\tif (ptd) ptd += b->bltdmod;\n");
+       printf("}\n");
+       if (a_is_on) printf("if (pta) b->bltadat = (*(pta-b->bltamod-2) << 8) | *(pta - b->bltamod - 1);\n"); /* Maybe not necessary, but I don't want problems */
+       if (b_is_on) printf("if (ptb) b->bltbdat = (*(ptb-b->bltbmod-2) << 8) | *(ptb - b->bltbmod - 1);\n");
+       if (c_is_on) printf("if (ptc) b->bltcdat = (*(ptc-b->bltcmod-2) << 8) | *(ptc - b->bltcmod - 1);\n");
+       printf("if (ptd) b->bltddat = (*(ptd-b->bltdmod-2) << 8) | *(ptd - b->bltdmod - 1);\n");
+
+       printf("} else {\n");
+#endif
+       if (a_is_on) printf("uae_u32 preva = 0;\n");
+       if (b_is_on) printf("uae_u32 prevb = 0, srcb = b->bltbhold;\n");
+       printf("uae_u32 srcc = b->bltcdat;\n");
+       printf("uae_u32 dstd=0;\n");
+       printf("uaecptr dstp = 0;\n");
+       printf("for (j = 0; j < b->vblitsize; j++) {\n");
+       printf("\tfor (i = 0; i < b->hblitsize; i++) {\n\t\tuae_u32 bltadat, srca;\n\n");
+       if (c_is_on) printf("\t\tif (ptc) { srcc = chipmem_wget (ptc); ptc += 2; }\n");
+       if (b_is_on) printf("\t\tif (ptb) {\n\t\t\tuae_u32 bltbdat = blt_info.bltbdat = chipmem_wget (ptb); ptb += 2;\n");
+       if (b_is_on) printf("\t\t\tsrcb = (((uae_u32)prevb << 16) | bltbdat) >> b->blitbshift;\n");
+       if (b_is_on) printf("\t\t\tprevb = bltbdat;\n\t\t}\n");
+       if (a_is_on) printf("\t\tif (pta) { bltadat = blt_info.bltadat = chipmem_wget (pta); pta += 2; } else { bltadat = blt_info.bltadat; }\n");
+       if (a_is_on) printf("\t\tbltadat &= blit_masktable[i];\n");
+       if (a_is_on) printf("\t\tsrca = (((uae_u32)preva << 16) | bltadat) >> b->blitashift;\n");
+       if (a_is_on) printf("\t\tpreva = bltadat;\n");
+       printf("\t\tif (dstp) chipmem_wput (dstp, dstd);\n");
+       printf("\t\tdstd = (%s) & 0xFFFF;\n", blitops[blttbl[i]].s);
+       printf("\t\ttotald |= dstd;\n");
+       printf("\t\tif (ptd) { dstp = ptd; ptd += 2; }\n");
+       printf("\t}\n");
+       if (a_is_on) printf("\tif (pta) pta += b->bltamod;\n");
+       if (b_is_on) printf("\tif (ptb) ptb += b->bltbmod;\n");
+       if (c_is_on) printf("\tif (ptc) ptc += b->bltcmod;\n");
+       printf("\tif (ptd) ptd += b->bltdmod;\n");
+       printf("}\n");
+       if (b_is_on) printf("b->bltbhold = srcb;\n");
+       printf("b->bltcdat = srcc;\n");
+       printf("\t\tif (dstp) chipmem_wput (dstp, dstd);\n");
+#if 0
+       printf("}\n");
+#endif
+       printf("if (totald != 0) b->blitzero = 0;\n");
+       printf("}\n");
+
+       printf("void blitdofast_desc_%x (uaecptr pta, uaecptr ptb, uaecptr ptc, uaecptr ptd, struct bltinfo *b)\n",blttbl[i]);
+       printf("{\n");
+       printf("uae_u32 totald = 0;\n");
+       printf("int i,j;\n");
+#if 0
+       printf("if (currprefs.blits_32bit_enabled && b->hblitsize > 1");
+       if (a_is_on) printf(" && !b->blitashift && b->bltafwm==0xffff && b->bltalwm==0xffff");
+       if (b_is_on) printf(" && !b->blitbshift");
+       printf(") {\n");
+       if (a_is_on) printf("uae_u32 srca = ((uae_u32)b->bltadat << 16) | b->bltadat;\n");
+       if (b_is_on) printf("uae_u32 srcb = ((uae_u32)b->bltbdat << 16) | b->bltbdat;\n");
+       if (c_is_on) printf("uae_u32 srcc = ((uae_u32)b->bltcdat << 16) | b->bltcdat;\n");
+       printf("uae_u32 dest;\n");
+       printf("int count=b->hblitsize/2, oddword=b->hblitsize&1;\n");
+       printf("for (j=0;j<b->vblitsize;j++) {\n");
+       printf("\tfor(i=0;i<count;i++) {\n");
+       if (a_is_on) printf("\t\tif (pta) { srca=*((uae_u32 *)(pta-2)); pta -= 4;}\n");
+       if (b_is_on) printf("\t\tif (ptb) { srcb=*((uae_u32 *)(ptb-2)); ptb -= 4;}\n");
+       if (c_is_on) printf("\t\tif (ptc) { srcc=*((uae_u32 *)(ptc-2)); ptc -= 4;}\n");
+       printf("\t\tdest = %s;\n", blitops[blttbl[i]].s);
+       printf("\t\ttotald |= dest;\n");
+       printf("\t\tif (ptd) {*(uae_u32 *)(ptd-2)=dest; ptd -= 4;}\n");
+       printf("\t}\n");
+       printf("\tif (oddword) {\n");
+       if (a_is_on) printf("\t\tif (pta) { srca=(uae_u32)*(uae_u16 *)pta; pta -= 2; }\n");
+       if (b_is_on) printf("\t\tif (ptb) { srcb=(uae_u32)*(uae_u16 *)ptb; ptb -= 2; }\n");
+       if (c_is_on) printf("\t\tif (ptc) { srcc=(uae_u32)*(uae_u16 *)ptc; ptc -= 2; }\n");
+       printf("\t\tdest = %s;\n", blitops[blttbl[i]].s);
+       printf("\t\ttotald |= dest;\n");
+       printf("\t\tif (ptd) { *(uae_u16 *)ptd= dest; ptd -= 2; }\n");
+       printf("\t}\n");
+       if (a_is_on) printf("\tif (pta) pta -= b->bltamod;\n");
+       if (b_is_on) printf("\tif (ptb) ptb -= b->bltbmod;\n");
+       if (c_is_on) printf("\tif (ptc) ptc -= b->bltcmod;\n");
+       printf("\tif (ptd) ptd-=b->bltdmod;\n");
+       printf("}\n");
+       if (a_is_on) printf("if (pta) b->bltadat = (*(pta + b->bltamod + 2) << 8) | *(pta + b->bltamod + 1);\n"); /* Maybe not necessary, but I don't want problems */
+       if (b_is_on) printf("if (ptb) b->bltbdat = (*(ptb + b->bltbmod + 2) << 8) | *(ptb + b->bltbmod + 1);\n");
+       if (c_is_on) printf("if (ptc) b->bltcdat = (*(ptc + b->bltcmod + 2) << 8) | *(ptc + b->bltcmod + 1);\n");
+       printf("if (ptd) b->bltddat = (*(ptd + b->bltdmod + 2) << 8) | *(ptd + b->bltdmod + 1);\n");
+
+       printf("} else {\n");
+#endif
+       if (a_is_on) printf("uae_u32 preva = 0;\n");
+       if (b_is_on) printf("uae_u32 prevb = 0, srcb = b->bltbhold;\n");
+       printf("uae_u32 srcc = b->bltcdat;\n");
+       printf("uae_u32 dstd=0;\n");
+       printf("uaecptr dstp = 0;\n");
+       printf("for (j = 0; j < b->vblitsize; j++) {\n");
+       printf("\tfor (i = 0; i < b->hblitsize; i++) {\n\t\tuae_u32 bltadat, srca;\n");
+       if (c_is_on) printf("\t\tif (ptc) { srcc = chipmem_wget (ptc); ptc -= 2; }\n");
+       if (b_is_on) printf("\t\tif (ptb) {\n\t\t\tuae_u32 bltbdat = blt_info.bltbdat = chipmem_wget (ptb); ptb -= 2;\n");
+       if (b_is_on) printf("\t\t\tsrcb = ((bltbdat << 16) | prevb) >> b->blitdownbshift;\n");
+       if (b_is_on) printf("\t\t\tprevb = bltbdat;\n\t\t}\n");
+       if (a_is_on) printf("\t\tif (pta) { bltadat = blt_info.bltadat = chipmem_wget (pta); pta -= 2; } else { bltadat = blt_info.bltadat; }\n");
+       if (a_is_on) printf("\t\tbltadat &= blit_masktable[i];\n");
+       if (a_is_on) printf("\t\tsrca = (((uae_u32)bltadat << 16) | preva) >> b->blitdownashift;\n");
+       if (a_is_on) printf("\t\tpreva = bltadat;\n");
+       printf("\t\tif (dstp) chipmem_wput (dstp, dstd);\n");
+       printf("\t\tdstd = (%s) & 0xFFFF;\n", blitops[blttbl[i]].s);
+       printf("\t\ttotald |= dstd;\n");
+       printf("\t\tif (ptd) { dstp = ptd; ptd -= 2; }\n");
+       printf("\t}\n");
+       if (a_is_on) printf("\tif (pta) pta -= b->bltamod;\n");
+       if (b_is_on) printf("\tif (ptb) ptb -= b->bltbmod;\n");
+       if (c_is_on) printf("\tif (ptc) ptc -= b->bltcmod;\n");
+       printf("\tif (ptd) ptd -= b->bltdmod;\n");
+       printf("}\n");
+       if (b_is_on) printf("b->bltbhold = srcb;\n");
+       printf("b->bltcdat = srcc;\n");
+       printf("\t\tif (dstp) chipmem_wput (dstp, dstd);\n");
+#if 0
+       printf("}\n");
+#endif
+       printf("if (totald != 0) b->blitzero = 0;\n");
+       printf("}\n");
+    }
+}
+
+static void generate_table(void)
+{
+    unsigned int index = 0;
+    unsigned int i;
+    printf("#include \"sysconfig.h\"\n");
+    printf("#include \"sysdeps.h\"\n");
+    printf("#include \"config.h\"\n");
+    printf("#include \"options.h\"\n");
+    printf("#include \"custom.h\"\n");
+    printf("#include \"memory.h\"\n");
+    printf("#include \"blitter.h\"\n");
+    printf("#include \"blitfunc.h\"\n\n");
+    printf("blitter_func *blitfunc_dofast[256] = {\n");
+    for (i = 0; i < 256; i++) {
+       if (index < sizeof(blttbl) && i == blttbl[index]) {
+           printf("blitdofast_%x",i);
+           index++;
+       }
+       else printf("0");
+       if (i < 255) printf(", ");
+       if ((i & 7) == 7) printf("\n");
+    }
+    printf("};\n\n");
+
+    index = 0;
+    printf("blitter_func *blitfunc_dofast_desc[256] = {\n");
+    for (i = 0; i < 256; i++) {
+       if (index < sizeof(blttbl) && i == blttbl[index]) {
+           printf("blitdofast_desc_%x",i);
+           index++;
+       }
+       else printf("0");
+       if (i < 255) printf(", ");
+       if ((i & 7) == 7) printf("\n");
+    }
+    printf("};\n");
+}
+
+static void generate_header(void)
+{
+    unsigned int i;
+    for (i = 0; i < sizeof(blttbl); i++) {
+       printf("extern blitter_func blitdofast_%x;\n",blttbl[i]);
+       printf("extern blitter_func blitdofast_desc_%x;\n",blttbl[i]);
+    }
+}
+
+int main(int argc, char **argv)
+{
+    char mode = 'i';
+
+    if (argc == 2) mode = *argv[1];
+    switch (mode) {
+     case 'i': generate_include();
+              break;
+     case 'f': generate_func();
+              break;
+     case 't': generate_table();
+              break;
+     case 'h': generate_header();
+              break;
+     default: abort();
+    }
+    return 0;
+}
+
diff --git a/gencomp.c b/gencomp.c
new file mode 100755 (executable)
index 0000000..9d38133
--- /dev/null
+++ b/gencomp.c
@@ -0,0 +1,3118 @@
+/*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * MC68000 compilation generator
+ *
+ * Based on work Copyright 1995, 1996 Bernd Schmidt. Changes Copyright 2000
+ * Bernd Meyer
+ */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+#include <ctype.h>
+
+#include "readcpu.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#define BOOL_TYPE "int"
+#define failure global_failure=1
+#define FAILURE global_failure=1
+#define isjump  global_isjump=1
+#define is_const_jump global_iscjump=1;
+#define isaddx  global_isaddx=1
+#define uses_cmov global_cmov=1
+#define mayfail global_mayfail=1
+
+int hack_opcode;
+
+static int global_failure;
+static int global_isjump;
+static int global_iscjump;
+static int global_isaddx;
+static int global_cmov;
+static int long_opcode;
+static int global_mayfail;
+
+static char endstr[1000];
+static char lines[100000];
+static int comp_index=0;
+
+static int cond_codes_x86[]={-1,-1,7,6,3,2,5,4,-1,-1,9,8,13,12,15,14};
+
+static void comprintf(const char* format, ...)
+{
+    va_list args;
+
+    va_start(args,format);
+    comp_index+=vsprintf(lines+comp_index,format,args);
+}
+
+static void com_discard(void)
+{
+    comp_index=0;
+}
+
+static void com_flush(void)
+{
+    int i;
+    for (i=0;i<comp_index;i++)
+       putchar(lines[i]);
+    com_discard();
+}
+
+
+static FILE *headerfile;
+static FILE *stblfile;
+
+static int using_prefetch;
+static int using_exception_3;
+static int cpu_level;
+static int noflags;
+
+/* For the current opcode, the next lower level that will have different code.
+ * Initialized to -1 for each opcode. If it remains unchanged, indicates we
+ * are done with that opcode.  */
+static int next_cpu_level;
+
+static int *opcode_map;
+static int *opcode_next_clev;
+static int *opcode_last_postfix;
+static unsigned long *counts;
+
+static void 
+read_counts (void)
+{
+    FILE *file;
+    unsigned long opcode, count = 0, total;
+    char name[20];
+    int nr = 0;
+    memset (counts, 0, 65536 * sizeof *counts);
+
+    file = fopen ("frequent.68k", "r");
+    if (file)
+    {
+       fscanf (file, "Total: %lu\n", &total);
+       while (fscanf (file, "%lx: %lu %s\n", &opcode, &count, name) == 3)
+       {
+           opcode_next_clev[nr] = 4;
+           opcode_last_postfix[nr] = -1;
+           opcode_map[nr++] = opcode;
+           counts[opcode] = count;
+       }
+       fclose (file);
+    }
+    if (nr == nr_cpuop_funcs)
+       return;
+    for (opcode = 0; opcode < 0x10000; opcode++)
+    {
+       if (table68k[opcode].handler == -1 && table68k[opcode].mnemo != i_ILLG
+           && counts[opcode] == 0)
+       {
+           opcode_next_clev[nr] = 4;
+           opcode_last_postfix[nr] = -1;
+           opcode_map[nr++] = opcode;
+           counts[opcode] = count;
+       }
+    }
+    if (nr != nr_cpuop_funcs)
+       abort ();
+}
+
+static int n_braces = 0;
+static int insn_n_cycles;
+
+static void 
+start_brace (void)
+{
+    n_braces++;
+    comprintf ("{");
+}
+
+static void 
+close_brace (void)
+{
+    assert (n_braces > 0);
+    n_braces--;
+    comprintf ("}");
+}
+
+static void 
+finish_braces (void)
+{
+    while (n_braces > 0)
+       close_brace ();
+}
+
+static void 
+pop_braces (int to)
+{
+    while (n_braces > to)
+       close_brace ();
+}
+
+static int 
+bit_size (int size)
+{
+    switch (size)
+    {
+     case sz_byte:
+       return 8;
+     case sz_word:
+       return 16;
+     case sz_long:
+       return 32;
+     default:
+       abort ();
+    }
+    return 0;
+}
+
+static const char *
+bit_mask (int size)
+{
+    switch (size)
+    {
+     case sz_byte:
+       return "0xff";
+     case sz_word:
+       return "0xffff";
+     case sz_long:
+       return "0xffffffff";
+     default:
+       abort ();
+    }
+    return 0;
+}
+
+static __inline__ void gen_update_next_handler(void)
+{
+    return; /* Can anything clever be done here? */
+}
+
+static void gen_writebyte(char* address, char* source)
+{
+    comprintf("\twritebyte(%s,%s,scratchie);\n",address,source);
+}
+
+static void gen_writeword(char* address, char* source)
+{
+    comprintf("\twriteword(%s,%s,scratchie);\n",address,source);
+}
+
+static void gen_writelong(char* address, char* source)
+{
+    comprintf("\twritelong(%s,%s,scratchie);\n",address,source);
+}
+
+static void gen_readbyte(char* address, char* dest)
+{
+    comprintf("\treadbyte(%s,%s,scratchie);\n",address,dest);
+}
+
+static void gen_readword(char* address, char* dest)
+{
+    comprintf("\treadword(%s,%s,scratchie);\n",address,dest);
+}
+
+static void gen_readlong(char* address, char* dest)
+{
+    comprintf("\treadlong(%s,%s,scratchie);\n",address,dest);
+}
+
+
+
+static const char *
+gen_nextilong (void)
+{
+    static char buffer[80];
+
+    sprintf (buffer, "comp_get_ilong((m68k_pc_offset+=4)-4)");
+    insn_n_cycles += 4;
+  
+    long_opcode=1;
+    return buffer;
+}
+
+static const char *
+gen_nextiword (void)
+{
+    static char buffer[80];
+
+    sprintf (buffer, "comp_get_iword((m68k_pc_offset+=2)-2)");
+    insn_n_cycles+=2;
+
+    long_opcode=1;
+    return buffer;
+}
+
+static const char *
+gen_nextibyte (void)
+{
+    static char buffer[80];
+
+    sprintf (buffer, "comp_get_ibyte((m68k_pc_offset+=2)-2)");
+    insn_n_cycles += 2;
+
+    long_opcode=1;
+    return buffer;
+}
+
+static void 
+sync_m68k_pc (void)
+{
+    comprintf("\t if (m68k_pc_offset>100) sync_m68k_pc();\n"); 
+}
+
+
+/* getv == 1: fetch data; getv != 0: check for odd address. If movem != 0,
+ * the calling routine handles Apdi and Aipi modes. */
+static void 
+genamode (amodes mode, char *reg, wordsizes size, char *name, int getv, int movem)
+{
+    start_brace ();
+    switch (mode)
+    {
+     case Dreg: /* Do we need to check dodgy here? */
+       if (movem)
+           abort ();
+       if (getv == 1 || getv==2) { 
+           /* We generate the variable even for getv==2, so we can use
+              it as a destination for MOVE */
+           comprintf ("\tint %s=%s;\n",name,reg);
+       }
+       return;
+
+     case Areg:
+       if (movem)
+           abort ();
+       if (getv == 1 || getv==2) {
+           /* see above */
+           comprintf ("\tint %s=dodgy?scratchie++:%s+8;\n",name,reg);
+           if (getv==1) {
+               comprintf ("\tif (dodgy) \n");
+               comprintf ("\t\tmov_l_rr(%s,%s+8);\n",name, reg);
+           }
+       }
+       return;
+
+     case Aind:
+       comprintf ("\tint %sa=dodgy?scratchie++:%s+8;\n",name,reg);
+       comprintf ("\tif (dodgy) \n");
+       comprintf ("\t\tmov_l_rr(%sa,%s+8);\n",name, reg);
+       break;
+     case Aipi:
+       comprintf ("\tint %sa=scratchie++;\n",name,reg);
+       comprintf ("\tmov_l_rr(%sa,%s+8);\n",name, reg);
+       break;
+     case Apdi: 
+       switch (size)   
+       {
+        case sz_byte:
+           if (movem) {
+               comprintf ("\tint %sa=dodgy?scratchie++:%s+8;\n",name,reg);
+               comprintf ("\tif (dodgy) \n");
+               comprintf("\tmov_l_rr(%sa,8+%s);\n",name,reg);
+           }
+           else {
+               start_brace();
+               comprintf ("\tint %sa=dodgy?scratchie++:%s+8;\n",name,reg);
+               comprintf("\tlea_l_brr(%s+8,%s+8,(uae_s32)-areg_byteinc[%s]);\n",reg,reg,reg);
+               comprintf ("\tif (dodgy) \n");
+               comprintf("\tmov_l_rr(%sa,8+%s);\n",name,reg);
+           }
+           break;
+        case sz_word:
+           if (movem) {
+               comprintf ("\tint %sa=dodgy?scratchie++:%s+8;\n",name,reg);
+               comprintf ("\tif (dodgy) \n");
+               comprintf("\tmov_l_rr(%sa,8+%s);\n",name,reg);
+           }
+           else {
+               start_brace();
+               comprintf ("\tint %sa=dodgy?scratchie++:%s+8;\n",name,reg);
+               comprintf("\tlea_l_brr(%s+8,%s+8,-2);\n",reg,reg);
+               comprintf ("\tif (dodgy) \n");
+               comprintf("\tmov_l_rr(%sa,8+%s);\n",name,reg);
+           }
+           break;
+        case sz_long:
+           if (movem) {
+               comprintf ("\tint %sa=dodgy?scratchie++:%s+8;\n",name,reg);
+               comprintf ("\tif (dodgy) \n");
+               comprintf("\tmov_l_rr(%sa,8+%s);\n",name,reg);
+           }
+           else {
+               start_brace();
+               comprintf ("\tint %sa=dodgy?scratchie++:%s+8;\n",name,reg);
+               comprintf("\tlea_l_brr(%s+8,%s+8,-4);\n",reg,reg);
+               comprintf ("\tif (dodgy) \n");
+               comprintf("\tmov_l_rr(%sa,8+%s);\n",name,reg);
+           }
+           break;
+        default:
+           abort ();
+       }
+       break;
+     case Ad16:
+       comprintf("\tint %sa=scratchie++;\n",name);
+       comprintf("\tmov_l_rr(%sa,8+%s);\n",name,reg);
+       comprintf("\tlea_l_brr(%sa,%sa,(uae_s32)(uae_s16)%s);\n",name,name,gen_nextiword());
+       break;
+     case Ad8r:
+       comprintf("\tint %sa=scratchie++;\n",name);
+       comprintf("\tcalc_disp_ea_020(%s+8,%s,%sa,scratchie);\n",
+                 reg,gen_nextiword(),name);
+       break;
+
+     case PC16:
+       comprintf("\tint %sa=scratchie++;\n",name);
+       comprintf("\tuae_u32 address=start_pc+((char *)comp_pc_p-(char *)start_pc_p)+m68k_pc_offset;\n");
+       comprintf ("\tuae_s32 PC16off = (uae_s32)(uae_s16)%s;\n", gen_nextiword ());
+       comprintf("\tmov_l_ri(%sa,address+PC16off);\n",name);
+       break;
+
+     case PC8r:
+       comprintf("\tint pctmp=scratchie++;\n");
+       comprintf("\tint %sa=scratchie++;\n",name);
+       comprintf("\tuae_u32 address=start_pc+((char *)comp_pc_p-(char *)start_pc_p)+m68k_pc_offset;\n");
+       start_brace();
+       comprintf("\tmov_l_ri(pctmp,address);\n");
+
+       comprintf("\tcalc_disp_ea_020(pctmp,%s,%sa,scratchie);\n",
+                 gen_nextiword(),name);
+       break;
+     case absw:
+       comprintf ("\tint %sa = scratchie++;\n",name);
+       comprintf ("\tmov_l_ri(%sa,(uae_s32)(uae_s16)%s);\n", name, gen_nextiword ());
+       break;
+     case absl:
+       comprintf ("\tint %sa = scratchie++;\n",name);
+       comprintf ("\tmov_l_ri(%sa,%s); /* absl */\n", name, gen_nextilong ());
+       break;
+     case imm:
+       if (getv != 1)
+           abort ();
+       switch (size)
+       {
+        case sz_byte:
+           comprintf ("\tint %s = scratchie++;\n",name);
+           comprintf ("\tmov_l_ri(%s,(uae_s32)(uae_s8)%s);\n", name, gen_nextibyte ());
+           break;
+        case sz_word:
+           comprintf ("\tint %s = scratchie++;\n",name);
+           comprintf ("\tmov_l_ri(%s,(uae_s32)(uae_s16)%s);\n", name, gen_nextiword ());
+           break;
+        case sz_long:
+           comprintf ("\tint %s = scratchie++;\n",name);
+           comprintf ("\tmov_l_ri(%s,%s);\n", name, gen_nextilong ());
+           break;
+        default:
+           abort ();
+       }
+       return;
+     case imm0:
+       if (getv != 1)
+           abort ();
+       comprintf ("\tint %s = scratchie++;\n",name);
+       comprintf ("\tmov_l_ri(%s,(uae_s32)(uae_s8)%s);\n", name, gen_nextibyte ());
+       return;
+     case imm1:
+       if (getv != 1)
+           abort ();
+       comprintf ("\tint %s = scratchie++;\n",name);
+       comprintf ("\tmov_l_ri(%s,(uae_s32)(uae_s16)%s);\n", name, gen_nextiword ());
+       return;
+     case imm2:
+       if (getv != 1)
+           abort ();
+       comprintf ("\tint %s = scratchie++;\n",name);
+       comprintf ("\tmov_l_ri(%s,%s);\n", name, gen_nextilong ());
+       return;
+     case immi:
+       if (getv != 1)
+           abort ();
+       comprintf ("\tint %s = scratchie++;\n",name);
+       comprintf ("\tmov_l_ri(%s,%s);\n", name, reg);
+       return;
+     default:
+       abort ();
+    }
+
+    /* We get here for all non-reg non-immediate addressing modes to
+     * actually fetch the value. */
+    if (getv == 1)
+    {
+       char astring[80];
+       sprintf(astring,"%sa",name);
+       switch (size)
+       {
+        case sz_byte:
+           insn_n_cycles += 2;
+           break;
+        case sz_word:
+           insn_n_cycles += 2;
+           break;
+        case sz_long:
+           insn_n_cycles += 4;
+           break;
+        default:
+           abort ();
+       }
+       start_brace ();
+       comprintf("\tint %s=scratchie++;\n",name);
+       switch (size)
+       {
+        case sz_byte:
+           gen_readbyte(astring,name);
+           break;
+        case sz_word:
+           gen_readword(astring,name);
+           break;
+        case sz_long:
+           gen_readlong(astring,name);
+           break;
+        default:
+           abort ();
+       }
+    }
+
+    /* We now might have to fix up the register for pre-dec or post-inc
+     * addressing modes. */
+    if (!movem) {
+       switch (mode)
+       {
+        case Aipi:
+           switch (size)
+           {
+            case sz_byte:
+               comprintf("\tlea_l_brr(%s+8,%s+8,areg_byteinc[%s]);\n",reg,reg,reg);
+               break;
+            case sz_word:
+               comprintf("\tlea_l_brr(%s+8,%s+8,2);\n",reg,reg,reg);
+               break;
+            case sz_long:
+               comprintf("\tlea_l_brr(%s+8,%s+8,4);\n",reg,reg);
+               break;
+            default:
+               abort ();
+           }
+           break;
+        case Apdi:
+           break;
+        default:
+           break;
+       }
+    }
+}
+
+static void 
+genastore (char *from, amodes mode, char *reg, wordsizes size, char *to)
+{
+    switch (mode)
+    {
+     case Dreg:
+       switch (size)
+       {
+        case sz_byte:
+           comprintf("\tif(%s!=%s)\n",reg,from);
+           comprintf ("\t\tmov_b_rr(%s,%s);\n", reg, from);
+           break;
+        case sz_word:
+           comprintf("\tif(%s!=%s)\n",reg,from);
+           comprintf ("\t\tmov_w_rr(%s,%s);\n", reg, from);
+           break;
+        case sz_long:
+           comprintf("\tif(%s!=%s)\n",reg,from);
+           comprintf ("\t\tmov_l_rr(%s,%s);\n", reg, from);
+           break;
+        default:
+           abort ();
+       }
+       break;
+     case Areg:
+       switch (size)
+       {
+        case sz_word:
+           comprintf("\tif(%s+8!=%s)\n",reg,from);
+           comprintf ("\t\tmov_w_rr(%s+8,%s);\n", reg, from);
+           break;
+        case sz_long:
+           comprintf("\tif(%s+8!=%s)\n",reg,from);
+           comprintf ("\t\tmov_l_rr(%s+8,%s);\n", reg, from);
+           break;
+        default:
+           abort ();
+       }
+       break;
+
+     case Apdi:
+     case absw:
+     case PC16:
+     case PC8r:
+     case Ad16:
+     case Ad8r:
+     case Aipi:
+     case Aind:
+     case absl:
+     {
+        char astring[80];
+        sprintf(astring,"%sa",to);
+       
+        switch (size)
+        {
+         case sz_byte:
+            insn_n_cycles += 2;
+            gen_writebyte(astring,from);
+            break;
+         case sz_word:
+            insn_n_cycles += 2;
+            gen_writeword(astring,from);
+            break;
+         case sz_long:
+            insn_n_cycles += 4;
+            gen_writelong(astring,from);
+            break;
+         default:
+            abort ();
+        }
+     }
+     break;
+     case imm:
+     case imm0:
+     case imm1:
+     case imm2:
+     case immi:
+       abort ();
+       break;
+     default:
+       abort ();
+    }
+}
+static void genmov16(uae_u32 opcode, struct instr *curi)
+{
+    comprintf("\tint src=scratchie++;\n");
+    comprintf("\tint dst=scratchie++;\n");
+
+    if ((opcode & 0xfff8) == 0xf620) {
+       /* MOVE16 (Ax)+,(Ay)+ */
+       comprintf("\tuae_u16 dstreg=((%s)>>12)&0x07;\n", gen_nextiword());
+       comprintf("\tmov_l_rr(src,8+srcreg);\n");
+       comprintf("\tmov_l_rr(dst,8+dstreg);\n");
+    } else {
+       /* Other variants */
+       genamode (curi->smode, "srcreg", curi->size, "src", 0, 2);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 0, 2);
+       comprintf("\tmov_l_rr(src,srca);\n");
+       comprintf("\tmov_l_rr(dst,dsta);\n");
+    }
+       
+    /* Align on 16-byte boundaries */
+    comprintf("\tand_l_ri(src,~15);\n");
+    comprintf("\tand_l_ri(dst,~15);\n");
+       
+       
+    if ((opcode & 0xfff8) == 0xf620) {
+       comprintf("\tif (srcreg != dstreg)\n");
+       comprintf("\tadd_l_ri(srcreg+8,16);\n");
+       comprintf("\tadd_l_ri(dstreg+8,16);\n");
+    } else if ((opcode & 0xfff8) == 0xf600)
+       comprintf("\tadd_l_ri(srcreg+8,16);\n");
+    else if ((opcode & 0xfff8) == 0xf608)
+       comprintf("\tadd_l_ri(dstreg+8,16);\n");
+
+    comprintf("\tif (special_mem) {\n");
+    comprintf("\t\tint tmp=scratchie;\n");
+    comprintf("\tscratchie+=4;\n"
+             "\treadlong(src,tmp,scratchie);\n"
+             "\twritelong_clobber(dst,tmp,scratchie);\n"
+             "\tadd_l_ri(src,4);\n"
+             "\tadd_l_ri(dst,4);\n"
+             "\treadlong(src,tmp,scratchie);\n"
+             "\twritelong_clobber(dst,tmp,scratchie);\n"
+             "\tadd_l_ri(src,4);\n"
+             "\tadd_l_ri(dst,4);\n"
+             "\treadlong(src,tmp,scratchie);\n"
+             "\twritelong_clobber(dst,tmp,scratchie);\n"
+             "\tadd_l_ri(src,4);\n"
+             "\tadd_l_ri(dst,4);\n"
+             "\treadlong(src,tmp,scratchie);\n"
+             "\twritelong_clobber(dst,tmp,scratchie);\n");
+    comprintf("\t} else {\n");
+    comprintf("\t\tint tmp=scratchie;\n");
+    comprintf("\tscratchie+=4;\n");
+    comprintf("\tget_n_addr(src,src,scratchie);\n"
+             "\tget_n_addr(dst,dst,scratchie);\n"
+             "\tmov_l_rR(tmp+0,src,0);\n"
+             "\tmov_l_rR(tmp+1,src,4);\n"
+             "\tmov_l_rR(tmp+2,src,8);\n"
+             "\tmov_l_rR(tmp+3,src,12);\n"
+             "\tmov_l_Rr(dst,tmp+0,0);\n"
+             "\tforget_about(tmp+0);\n"
+             "\tmov_l_Rr(dst,tmp+1,4);\n"
+             "\tforget_about(tmp+1);\n"
+             "\tmov_l_Rr(dst,tmp+2,8);\n"
+             "\tforget_about(tmp+2);\n"
+             "\tmov_l_Rr(dst,tmp+3,12);\t}\n");
+
+}
+
+#if 0
+static void genmov16(void)
+{
+    comprintf("\tint src=scratchie++;\n"
+             "\tuae_u16 dstreg=((%s)>>12)&0x07;\n",gen_nextiword());
+    comprintf("\tint dst=scratchie++;\n"
+             "\tint tmp=scratchie;\n"
+             "\tscratchie+=4;\n"
+             "\tmov_l_rr(src,8+srcreg);\n"
+             "\tand_l_ri(src,~15);\n"
+             "\tmov_l_rr(dst,8+dstreg);\n"
+             "\tand_l_ri(dst,~15);\n"
+             "\tadd_l_ri(srcreg+8,16);\n"
+             "\tadd_l_ri(dstreg+8,16);\n");
+
+    comprintf("\tif (special_mem) {\n"
+             "\treadlong(src,tmp,scratchie);\n"
+             "\twritelong_clobber(dst,tmp,scratchie);\n"
+             "\tadd_l_ri(src,4);\n"
+             "\tadd_l_ri(dst,4);\n"
+             "\treadlong(src,tmp,scratchie);\n"
+             "\twritelong_clobber(dst,tmp,scratchie);\n"
+             "\tadd_l_ri(src,4);\n"
+             "\tadd_l_ri(dst,4);\n"
+             "\treadlong(src,tmp,scratchie);\n"
+             "\twritelong_clobber(dst,tmp,scratchie);\n"
+             "\tadd_l_ri(src,4);\n"
+             "\tadd_l_ri(dst,4);\n"
+             "\treadlong(src,tmp,scratchie);\n"
+             "\twritelong_clobber(dst,tmp,scratchie);\n");
+    comprintf("\t} else {\n");
+    comprintf("\tget_n_addr(src,src,scratchie);\n"
+             "\tget_n_addr(dst,dst,scratchie);\n"
+             "\tmov_l_rR(tmp+0,src,0);\n"
+             "\tmov_l_rR(tmp+1,src,4);\n"
+             "\tmov_l_rR(tmp+2,src,8);\n"
+             "\tmov_l_rR(tmp+3,src,12);\n"
+             "\tmov_l_Rr(dst,tmp+0,0);\n"
+             "\tforget_about(tmp+0);\n"
+             "\tmov_l_Rr(dst,tmp+1,4);\n"
+             "\tforget_about(tmp+1);\n"
+             "\tmov_l_Rr(dst,tmp+2,8);\n"
+             "\tforget_about(tmp+2);\n"
+             "\tmov_l_Rr(dst,tmp+3,12);\n"
+             "\t}\n");
+}
+#endif
+
+static void 
+genmovemel (uae_u16 opcode)
+{
+    comprintf ("\tuae_u16 mask = %s;\n", gen_nextiword ());
+    comprintf ("\tint native=scratchie++;\n");
+    comprintf ("\tint i;\n");
+    comprintf ("\tint offset=0;\n");
+    genamode (table68k[opcode].dmode, "dstreg", table68k[opcode].size, "src", 2, 1);
+    comprintf("\tif (1 && !special_mem) {\n");
+
+    /* Fast but unsafe...  */
+    comprintf("\tget_n_addr(srca,native,scratchie);\n");
+
+
+    comprintf("\tfor (i=0;i<16;i++) {\n"
+             "\t\tif ((mask>>i)&1) {\n");
+    switch(table68k[opcode].size) {
+     case sz_long: 
+       comprintf("\t\t\tmov_l_rR(i,native,offset);\n"
+                 "\t\t\tbswap_32(i);\n"
+                 "\t\t\toffset+=4;\n");
+       break;
+     case sz_word: 
+       comprintf("\t\t\tmov_w_rR(i,native,offset);\n"
+                 "\t\t\tbswap_16(i);\n"
+                 "\t\t\tsign_extend_16_rr(i,i);\n"
+                 "\t\t\toffset+=2;\n");
+       break;
+     default: abort();
+    }
+    comprintf("\t\t}\n"
+             "\t}");
+    if (table68k[opcode].dmode == Aipi) {
+       comprintf("\t\t\tlea_l_brr(8+dstreg,srca,offset);\n"); 
+    }
+    /* End fast but unsafe.   */
+
+    comprintf("\t} else {\n");
+
+    comprintf ("\tint tmp=scratchie++;\n");
+
+    comprintf("\tmov_l_rr(tmp,srca);\n");
+    comprintf("\tfor (i=0;i<16;i++) {\n"
+             "\t\tif ((mask>>i)&1) {\n");
+    switch(table68k[opcode].size) {
+    case sz_long: 
+       comprintf("\t\t\treadlong(tmp,i,scratchie);\n"
+                 "\t\t\tadd_l_ri(tmp,4);\n");
+       break;
+    case sz_word:
+       comprintf("\t\t\treadword(tmp,i,scratchie);\n"
+                 "\t\t\tadd_l_ri(tmp,2);\n");
+       break;
+    default: abort();
+    }
+
+    comprintf("\t\t}\n"
+             "\t}");
+    if (table68k[opcode].dmode == Aipi) {
+       comprintf("\t\t\tmov_l_rr(8+dstreg,tmp);\n");
+    }
+    comprintf("\t}\n");
+
+}
+
+
+static void 
+genmovemle (uae_u16 opcode)
+{
+    comprintf ("\tuae_u16 mask = %s;\n", gen_nextiword ());
+    comprintf ("\tint native=scratchie++;\n");
+    comprintf ("\tint i;\n");
+    comprintf ("\tint tmp=scratchie++;\n");
+    comprintf ("\tsigned char offset=0;\n");
+    genamode (table68k[opcode].dmode, "dstreg", table68k[opcode].size, "src", 2, 1);
+
+    /* *Sigh* Some clever geek realized that the fastest way to copy a
+       buffer from main memory to the gfx card is by using movmle. Good
+       on her, but unfortunately, gfx mem isn't "real" mem, and thus that
+       act of cleverness means that movmle must pay attention to special_mem,
+       or Genetic Species is a rather boring-looking game ;-) */
+    comprintf("\tif (1 && !special_mem) {\n");
+    comprintf("\tget_n_addr(srca,native,scratchie);\n");
+
+    if (table68k[opcode].dmode!=Apdi) {
+       comprintf("\tfor (i=0;i<16;i++) {\n"
+                 "\t\tif ((mask>>i)&1) {\n");
+       switch(table68k[opcode].size) {
+        case sz_long: 
+           comprintf("\t\t\tmov_l_rr(tmp,i);\n"
+                     "\t\t\tbswap_32(tmp);\n"
+                     "\t\t\tmov_l_Rr(native,tmp,offset);\n"
+                     "\t\t\toffset+=4;\n");
+           break;
+        case sz_word: 
+           comprintf("\t\t\tmov_l_rr(tmp,i);\n"
+                     "\t\t\tbswap_16(tmp);\n"
+                     "\t\t\tmov_w_Rr(native,tmp,offset);\n"
+                     "\t\t\toffset+=2;\n");
+           break;
+        default: abort();
+       }
+    } else {  /* Pre-decrement */
+       comprintf("\tfor (i=0;i<16;i++) {\n"
+                 "\t\tif ((mask>>i)&1) {\n");
+       switch(table68k[opcode].size) {
+        case sz_long: 
+           comprintf("\t\t\toffset-=4;\n"
+                     "\t\t\tmov_l_rr(tmp,15-i);\n"
+                     "\t\t\tbswap_32(tmp);\n"
+                     "\t\t\tmov_l_Rr(native,tmp,offset);\n"
+                     );
+           break;
+        case sz_word: 
+           comprintf("\t\t\toffset-=2;\n"
+                     "\t\t\tmov_l_rr(tmp,15-i);\n"
+                     "\t\t\tbswap_16(tmp);\n"
+                     "\t\t\tmov_w_Rr(native,tmp,offset);\n"
+                     );
+           break;
+        default: abort();
+       }
+    }
+
+    comprintf("\t\t}\n"
+             "\t}");
+    if (table68k[opcode].dmode == Apdi) {
+       comprintf("\t\t\tlea_l_brr(8+dstreg,srca,(uae_s32)offset);\n");
+    }
+    comprintf("\t} else {\n");
+
+    if (table68k[opcode].dmode!=Apdi) {
+       comprintf("\tmov_l_rr(tmp,srca);\n");
+       comprintf("\tfor (i=0;i<16;i++) {\n"
+                 "\t\tif ((mask>>i)&1) {\n");
+       switch(table68k[opcode].size) {
+        case sz_long: 
+           comprintf("\t\t\twritelong(tmp,i,scratchie);\n"
+                     "\t\t\tadd_l_ri(tmp,4);\n");
+           break;
+        case sz_word: 
+           comprintf("\t\t\twriteword(tmp,i,scratchie);\n"
+                     "\t\t\tadd_l_ri(tmp,2);\n");
+           break;
+        default: abort();
+       }
+    }
+    else {  /* Pre-decrement */
+       comprintf("\tfor (i=0;i<16;i++) {\n"
+                 "\t\tif ((mask>>i)&1) {\n");
+       switch(table68k[opcode].size) {
+        case sz_long: 
+           comprintf("\t\t\tsub_l_ri(srca,4);\n"
+                     "\t\t\twritelong(srca,15-i,scratchie);\n");
+           break;
+        case sz_word: 
+           comprintf("\t\t\tsub_l_ri(srca,2);\n"
+                     "\t\t\twriteword(srca,15-i,scratchie);\n");
+           break;
+        default: abort();
+       }
+    }
+  
+
+    comprintf("\t\t}\n"
+             "\t}");
+    if (table68k[opcode].dmode == Apdi) {
+       comprintf("\t\t\tmov_l_rr(8+dstreg,srca);\n");
+    }
+    comprintf("\t}\n");
+}
+
+
+static void 
+duplicate_carry (void)
+{
+    comprintf ("\tif (needed_flags&FLAG_X) duplicate_carry();\n");
+}
+
+typedef enum
+{
+    flag_logical_noclobber, flag_logical, flag_add, flag_sub, flag_cmp, 
+    flag_addx, flag_subx, flag_zn, flag_av, flag_sv, flag_and, flag_or,
+    flag_eor, flag_mov
+}
+flagtypes;
+
+
+static void 
+genflags (flagtypes type, wordsizes size, char *value, char *src, char *dst)
+{
+    if (noflags) {
+       switch(type) {
+        case flag_cmp:
+           comprintf("\tdont_care_flags();\n");
+           comprintf("/* Weird --- CMP with noflags ;-) */\n");
+           return;
+        case flag_add:
+        case flag_sub:
+           comprintf("\tdont_care_flags();\n");
+           {
+               char* op;
+               switch(type) {
+                case flag_add: op="add"; break;
+                case flag_sub: op="sub"; break;
+                default: abort();
+               }
+               switch (size)
+               {
+                case sz_byte:
+                   comprintf("\t%s_b(%s,%s);\n",op,dst,src);
+                   break;
+                case sz_word:
+                   comprintf("\t%s_w(%s,%s);\n",op,dst,src);
+                   break;
+                case sz_long:
+                   comprintf("\t%s_l(%s,%s);\n",op,dst,src);
+                   break;
+               }
+               return;
+           }
+           break;
+
+        case flag_and:
+           comprintf("\tdont_care_flags();\n");
+           switch (size)
+           {
+            case sz_byte:
+               comprintf("if (kill_rodent(dst)) {\n");
+               comprintf("\tzero_extend_8_rr(scratchie,%s);\n",src);
+               comprintf("\tor_l_ri(scratchie,0xffffff00);\n");
+               comprintf("\tand_l(%s,scratchie);\n",dst);
+               comprintf("\tforget_about(scratchie);\n");
+               comprintf("\t} else \n"
+                         "\tand_b(%s,%s);\n",dst,src);
+               break;
+            case sz_word:
+               comprintf("if (kill_rodent(dst)) {\n");
+               comprintf("\tzero_extend_16_rr(scratchie,%s);\n",src);
+               comprintf("\tor_l_ri(scratchie,0xffff0000);\n");
+               comprintf("\tand_l(%s,scratchie);\n",dst);
+               comprintf("\tforget_about(scratchie);\n");
+               comprintf("\t} else \n"
+                         "\tand_w(%s,%s);\n",dst,src);
+               break;
+            case sz_long:
+               comprintf("\tand_l(%s,%s);\n",dst,src);
+               break;
+           }
+           return;
+
+        case flag_mov:
+           comprintf("\tdont_care_flags();\n");
+           switch (size)
+           {
+            case sz_byte:
+               comprintf("if (kill_rodent(dst)) {\n");
+               comprintf("\tzero_extend_8_rr(scratchie,%s);\n",src);
+               comprintf("\tand_l_ri(%s,0xffffff00);\n",dst);
+               comprintf("\tor_l(%s,scratchie);\n",dst);
+               comprintf("\tforget_about(scratchie);\n");
+               comprintf("\t} else \n"
+                         "\tmov_b_rr(%s,%s);\n",dst,src);
+               break;
+            case sz_word:
+               comprintf("if (kill_rodent(dst)) {\n");
+               comprintf("\tzero_extend_16_rr(scratchie,%s);\n",src);
+               comprintf("\tand_l_ri(%s,0xffff0000);\n",dst);
+               comprintf("\tor_l(%s,scratchie);\n",dst);
+               comprintf("\tforget_about(scratchie);\n");
+               comprintf("\t} else \n"
+                         "\tmov_w_rr(%s,%s);\n",dst,src);
+               break;
+            case sz_long:
+               comprintf("\tmov_l_rr(%s,%s);\n",dst,src);
+               break;
+           }
+           return;
+
+        case flag_or:
+        case flag_eor:
+           comprintf("\tdont_care_flags();\n");
+           start_brace();
+           {
+               char* op;
+               switch(type) {
+                case flag_or:  op="or"; break;
+                case flag_eor: op="xor"; break;
+                default: abort();
+               }
+               switch (size)
+               {
+                case sz_byte:
+                   comprintf("if (kill_rodent(dst)) {\n");
+                   comprintf("\tzero_extend_8_rr(scratchie,%s);\n",src);
+                   comprintf("\t%s_l(%s,scratchie);\n",op,dst);
+                   comprintf("\tforget_about(scratchie);\n");
+                   comprintf("\t} else \n"
+                             "\t%s_b(%s,%s);\n",op,dst,src);
+                   break;
+                case sz_word:
+                   comprintf("if (kill_rodent(dst)) {\n");
+                   comprintf("\tzero_extend_16_rr(scratchie,%s);\n",src);
+                   comprintf("\t%s_l(%s,scratchie);\n",op,dst);
+                   comprintf("\tforget_about(scratchie);\n");
+                   comprintf("\t} else \n"
+                             "\t%s_w(%s,%s);\n",op,dst,src);
+                   break;
+                case sz_long:
+                   comprintf("\t%s_l(%s,%s);\n",op,dst,src);
+                   break;
+               }
+               close_brace();
+               return;
+           }
+      
+
+        case flag_addx:
+        case flag_subx:
+               
+           comprintf("\tdont_care_flags();\n");
+           {
+               char* op;
+               switch(type) {
+                case flag_addx: op="adc"; break;
+                case flag_subx: op="sbb"; break;
+                default: abort();
+               }
+               comprintf("\trestore_carry();\n"); /* Reload the X flag into C */
+               switch (size)
+               {
+                case sz_byte:
+                   comprintf("\t%s_b(%s,%s);\n",op,dst,src);
+                   break;
+                case sz_word:
+                   comprintf("\t%s_w(%s,%s);\n",op,dst,src);
+                   break;
+                case sz_long:
+                   comprintf("\t%s_l(%s,%s);\n",op,dst,src);
+                   break;
+               }
+               return;
+           }
+           break;
+        default: return;
+       }
+    }
+  
+    /* Need the flags, but possibly not all of them */
+    switch (type)
+    {
+     case flag_logical_noclobber:
+       failure;
+
+     case flag_and:
+     case flag_or:
+     case flag_eor:
+       comprintf("\tdont_care_flags();\n");
+       start_brace();
+       {
+           char* op;
+           switch(type) {
+            case flag_and: op="and"; break;
+            case flag_or:  op="or"; break;
+            case flag_eor: op="xor"; break;
+            default: abort();
+           }
+           switch (size)
+           {
+            case sz_byte:
+               comprintf("\tstart_needflags();\n"
+                         "\t%s_b(%s,%s);\n",op,dst,src);
+               break;
+            case sz_word:
+               comprintf("\tstart_needflags();\n"
+                         "\t%s_w(%s,%s);\n",op,dst,src);
+               break;
+            case sz_long:
+               comprintf("\tstart_needflags();\n"
+                         "\t%s_l(%s,%s);\n",op,dst,src);
+               break;
+           }
+           comprintf("\tlive_flags();\n");
+           comprintf("\tend_needflags();\n");
+           close_brace();
+           return;
+       }
+
+     case flag_mov:
+       comprintf("\tdont_care_flags();\n");
+       start_brace();
+       {
+           switch (size)
+           {
+            case sz_byte:
+               comprintf("\tif (%s!=%s) {\n",src,dst);
+               comprintf("\tmov_b_ri(%s,0);\n"
+                         "\tstart_needflags();\n",dst);
+               comprintf("\tor_b(%s,%s);\n",dst,src);
+               comprintf("\t} else {\n");
+               comprintf("\tmov_b_rr(%s,%s);\n",dst,src);
+               comprintf("\ttest_b_rr(%s,%s);\n",dst,dst);
+               comprintf("\t}\n");
+               break;
+            case sz_word:
+               comprintf("\tif (%s!=%s) {\n",src,dst);
+               comprintf("\tmov_w_ri(%s,0);\n"
+                         "\tstart_needflags();\n",dst);
+               comprintf("\tor_w(%s,%s);\n",dst,src);
+               comprintf("\t} else {\n");
+               comprintf("\tmov_w_rr(%s,%s);\n",dst,src);
+               comprintf("\ttest_w_rr(%s,%s);\n",dst,dst);
+               comprintf("\t}\n");
+               break;
+            case sz_long:
+               comprintf("\tif (%s!=%s) {\n",src,dst);
+               comprintf("\tmov_l_ri(%s,0);\n"
+                         "\tstart_needflags();\n",dst);
+               comprintf("\tor_l(%s,%s);\n",dst,src);
+               comprintf("\t} else {\n");
+               comprintf("\tmov_l_rr(%s,%s);\n",dst,src);
+               comprintf("\ttest_l_rr(%s,%s);\n",dst,dst);
+               comprintf("\t}\n");
+               break;
+           }
+           comprintf("\tlive_flags();\n");
+           comprintf("\tend_needflags();\n");
+           close_brace();
+           return;
+       }
+
+     case flag_logical:
+       comprintf("\tdont_care_flags();\n");
+       start_brace();
+       switch (size)
+       {
+        case sz_byte:
+           comprintf("\tstart_needflags();\n"
+                     "\ttest_b_rr(%s,%s);\n",value,value);
+           break;
+        case sz_word:
+           comprintf("\tstart_needflags();\n"
+                     "\ttest_w_rr(%s,%s);\n",value,value);
+           break;
+        case sz_long:
+           comprintf("\tstart_needflags();\n"
+                     "\ttest_l_rr(%s,%s);\n",value,value);
+           break;
+       }
+       comprintf("\tlive_flags();\n");
+       comprintf("\tend_needflags();\n");
+       close_brace();
+       return;
+
+
+     case flag_add:
+     case flag_sub:
+     case flag_cmp:
+       comprintf("\tdont_care_flags();\n");
+       {
+           char* op;
+           switch(type) {
+            case flag_add: op="add"; break;
+            case flag_sub: op="sub"; break;
+            case flag_cmp: op="cmp"; break;
+            default: abort();
+           }
+           switch (size)
+           {
+            case sz_byte:
+               comprintf("\tstart_needflags();\n"
+                         "\t%s_b(%s,%s);\n",op,dst,src);
+               break;
+            case sz_word:
+               comprintf("\tstart_needflags();\n"
+                         "\t%s_w(%s,%s);\n",op,dst,src);
+               break;
+            case sz_long:
+               comprintf("\tstart_needflags();\n"
+                         "\t%s_l(%s,%s);\n",op,dst,src);
+               break;
+           }
+           comprintf("\tlive_flags();\n");
+           comprintf("\tend_needflags();\n");
+           if (type!=flag_cmp) {
+               duplicate_carry();
+           }
+           comprintf("if (!(needed_flags & FLAG_CZNV)) dont_care_flags();\n");
+           
+           return;
+       }
+      
+     case flag_addx:
+     case flag_subx:
+                uses_cmov;
+       comprintf("\tdont_care_flags();\n");
+       {
+           char* op;
+           switch(type) {
+            case flag_addx: op="adc"; break;
+            case flag_subx: op="sbb"; break;
+            default: abort();
+           }
+           start_brace();
+           comprintf("\tint zero=scratchie++;\n"
+                     "\tint one=scratchie++;\n"
+                     "\tif (needed_flags&FLAG_Z) {\n"
+                     "\tmov_l_ri(zero,0);\n"
+                     "\tmov_l_ri(one,1);\n"
+                     "\tmake_flags_live();\n"
+                     "\tcmov_l_rr(zero,one,5);\n"
+                     "\t}\n");
+           comprintf("\trestore_carry();\n"); /* Reload the X flag into C */
+           switch (size)
+           {
+            case sz_byte:
+               comprintf("\tstart_needflags();\n"
+                         "\t%s_b(%s,%s);\n",op,dst,src);
+               break;
+            case sz_word:
+               comprintf("\tstart_needflags();\n"
+                         "\t%s_w(%s,%s);\n",op,dst,src);
+               break;
+            case sz_long:
+               comprintf("\tstart_needflags();\n"
+                         "\t%s_l(%s,%s);\n",op,dst,src);
+               break;
+           }
+           comprintf("\tlive_flags();\n");
+           comprintf("\tif (needed_flags&FLAG_Z) {\n"
+                     "\tcmov_l_rr(zero,one,5);\n"
+                     "\tsetzflg_l(zero);\n"
+                     "\tlive_flags();\n"
+                     "\t}\n");
+           comprintf("\tend_needflags();\n");
+           duplicate_carry();
+           comprintf("if (!(needed_flags & FLAG_CZNV)) dont_care_flags();\n");
+           return;
+       }
+     default:
+       failure;
+       break;
+    }
+}
+
+static void 
+force_range_for_rox (const char *var, wordsizes size)
+{
+    /* Could do a modulo operation here... which one is faster? */
+    switch (size)
+    {
+     case sz_long:
+       comprintf ("\tif (%s >= 33) %s -= 33;\n", var, var);
+       break;
+     case sz_word:
+       comprintf ("\tif (%s >= 34) %s -= 34;\n", var, var);
+       comprintf ("\tif (%s >= 17) %s -= 17;\n", var, var);
+       break;
+     case sz_byte:
+       comprintf ("\tif (%s >= 36) %s -= 36;\n", var, var);
+       comprintf ("\tif (%s >= 18) %s -= 18;\n", var, var);
+       comprintf ("\tif (%s >= 9) %s -= 9;\n", var, var);
+       break;
+    }
+}
+
+static const char *
+cmask (wordsizes size)
+{
+    switch (size)
+    {
+     case sz_byte:
+       return "0x80";
+     case sz_word:
+       return "0x8000";
+     case sz_long:
+       return "0x80000000";
+     default:
+       abort ();
+    }
+}
+
+static int 
+source_is_imm1_8 (struct instr *i)
+{
+    return i->stype == 3;
+}
+
+static int  /* returns zero for success, non-zero for failure */
+gen_opcode (unsigned long int opcode)
+{
+    struct instr *curi = table68k + opcode;
+    char* ssize=NULL;
+
+    insn_n_cycles = 2;
+    global_failure=0;
+    long_opcode=0;
+    global_isjump=0;
+    global_iscjump=0;
+    global_isaddx=0;
+    global_cmov=0;
+    global_mayfail=0;
+    hack_opcode=opcode;
+    endstr[0]=0;
+
+    start_brace ();
+    comprintf("\tuae_u8 scratchie=S1;\n");
+    switch (curi->plev)
+    {
+     case 0:                   /* not privileged */
+       break;
+     case 1:                   /* unprivileged only on 68000 */
+       if (cpu_level == 0)
+           break;
+       if (next_cpu_level < 0)
+           next_cpu_level = 0;
+
+       /* fall through */
+     case 2:                   /* priviledged */
+       failure;   /* Easy ones first */
+       break;
+     case 3:                   /* privileged if size == word */
+       if (curi->size == sz_byte)
+           break;
+       failure;
+       break;
+    }
+    switch (curi->size) {
+     case sz_byte: ssize="b"; break;
+     case sz_word: ssize="w"; break;
+     case sz_long: ssize="l"; break;
+     default: abort();
+    }
+
+    switch (curi->mnemo)
+    {
+     case i_OR:
+     case i_AND:
+     case i_EOR:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0);
+       switch(curi->mnemo) {
+        case i_OR: genflags (flag_or, curi->size, "", "src", "dst"); break;
+        case i_AND: genflags (flag_and, curi->size, "", "src", "dst"); break;
+        case i_EOR: genflags (flag_eor, curi->size, "", "src", "dst"); break;
+       }
+       genastore ("dst", curi->dmode, "dstreg", curi->size, "dst");
+       break;
+
+     case i_ORSR:
+     case i_EORSR:
+       failure;
+       isjump; 
+       break;
+     case i_ANDSR:
+       failure;
+       isjump; 
+       break;
+     case i_SUB:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0);
+       genflags (flag_sub, curi->size, "", "src", "dst");
+       genastore ("dst", curi->dmode, "dstreg", curi->size, "dst");
+       break;
+     case i_SUBA:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0);
+       genamode (curi->dmode, "dstreg", sz_long, "dst", 1, 0);
+       start_brace();
+       comprintf("\tint tmp=scratchie++;\n");
+       switch(curi->size) {
+        case sz_byte: comprintf("\tsign_extend_8_rr(tmp,src);\n"); break;
+        case sz_word: comprintf("\tsign_extend_16_rr(tmp,src);\n"); break;
+        case sz_long: comprintf("\ttmp=src;\n"); break;
+        default: abort();
+       }
+       comprintf("\tsub_l(dst,tmp);\n");
+       genastore ("dst", curi->dmode, "dstreg", sz_long, "dst");
+       break;
+     case i_SUBX:
+       isaddx;
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0);
+       genflags (flag_subx, curi->size, "", "src", "dst");
+       genastore ("dst", curi->dmode, "dstreg", curi->size, "dst");
+       break;
+     case i_SBCD:
+       failure;
+       /* I don't think so! */
+       break;
+     case i_ADD:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0);
+       genflags (flag_add, curi->size, "", "src", "dst");
+       genastore ("dst", curi->dmode, "dstreg", curi->size, "dst");
+       break;
+     case i_ADDA:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0);
+       genamode (curi->dmode, "dstreg", sz_long, "dst", 1, 0);
+       start_brace();
+       comprintf("\tint tmp=scratchie++;\n");
+       switch(curi->size) {
+        case sz_byte: comprintf("\tsign_extend_8_rr(tmp,src);\n"); break;
+        case sz_word: comprintf("\tsign_extend_16_rr(tmp,src);\n"); break;
+        case sz_long: comprintf("\ttmp=src;\n"); break;
+        default: abort();
+       }
+       comprintf("\tadd_l(dst,tmp);\n");
+       genastore ("dst", curi->dmode, "dstreg", sz_long, "dst");
+       break;
+     case i_ADDX:
+       isaddx;
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0);
+       start_brace();
+       genflags (flag_addx, curi->size, "", "src", "dst");
+       genastore ("dst", curi->dmode, "dstreg", curi->size, "dst");
+       break;
+     case i_ABCD:
+       failure;
+       /* No BCD maths for me.... */
+       break;
+     case i_NEG:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0);
+       start_brace ();
+       comprintf("\tint dst=scratchie++;\n");
+       comprintf("\tmov_l_ri(dst,0);\n");
+       genflags (flag_sub, curi->size, "", "src", "dst");
+       genastore ("dst", curi->smode, "srcreg", curi->size, "src");
+       break;
+     case i_NEGX:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0);
+       start_brace ();
+       comprintf("\tint dst=scratchie++;\n");
+       comprintf("\tmov_l_ri(dst,0);\n");
+       genflags (flag_subx, curi->size, "", "src", "dst");
+       genastore ("dst", curi->smode, "srcreg", curi->size, "src");
+       break;
+
+     case i_NBCD:
+       failure;
+       /* Nope! */
+       break;
+     case i_CLR:
+       genamode (curi->smode, "srcreg", curi->size, "src", 2, 0);
+       start_brace();
+       comprintf("\tint dst=scratchie++;\n");
+       comprintf("\tmov_l_ri(dst,0);\n");
+       genflags (flag_logical, curi->size, "dst", "", "");
+       genastore ("dst", curi->smode, "srcreg", curi->size, "src");
+       break;
+     case i_NOT:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0);
+       start_brace ();
+       comprintf("\tint dst=scratchie++;\n");
+       comprintf("\tmov_l_ri(dst,0xffffffff);\n");
+       genflags (flag_eor, curi->size, "", "src", "dst");
+       genastore ("dst", curi->smode, "srcreg", curi->size, "src");
+       break;
+     case i_TST:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0);
+       genflags (flag_logical, curi->size, "src", "", "");
+       break;
+     case i_BCHG:
+     case i_BCLR:
+     case i_BSET:
+     case i_BTST:
+                       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0);
+       start_brace();
+       comprintf("\tint s=scratchie++;\n"
+                 "\tmov_l_rr(s,src);\n");
+       if (curi->size == sz_byte)
+           comprintf("\tand_l_ri(s,7);\n");
+       else
+           comprintf("\tand_l_ri(s,31);\n");
+
+       { 
+           char* op;
+           int need_write=1;
+
+           switch(curi->mnemo) {
+            case i_BCHG: op="btc"; break;
+            case i_BCLR: op="btr"; break;
+            case i_BSET: op="bts"; break;
+            case i_BTST: op="bt"; need_write=0; break;
+           }
+           comprintf("\t%s_l_rr(dst,s);\n"  /* Answer now in C */
+                                 "\tsbb_l(s,s);\n" /* s is 0 if bit was 0, -1 otherwise */
+                                 "\tmake_flags_live();\n" /* Get the flags back */
+                                 "\tdont_care_flags();\n",op);
+               if (!noflags) {
+                 comprintf("\tstart_needflags();\n"
+                                       "\tsetzflg_l(s);\n"
+                                       "\tlive_flags();\n"
+                                       "\tend_needflags();\n");
+               }
+           if (need_write) 
+               genastore ("dst", curi->dmode, "dstreg", curi->size, "dst");
+       }
+       break;
+       /*if (!noflags) {
+           failure;
+           break;
+       }
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0);
+       start_brace();
+       comprintf("\tint s=scratchie++;\n"
+                 "\tmov_l_rr(s,src);\n");
+       if (curi->size == sz_byte)
+           comprintf("\tand_l_ri(s,7);\n");
+       else
+           comprintf("\tand_l_ri(s,31);\n");
+
+       {
+           char* op;
+           int need_write=1;
+
+           switch(curi->mnemo) {
+            case i_BCHG: op="btc"; break;
+            case i_BCLR: op="btr"; break;
+            case i_BSET: op="bts"; break;
+            case i_BTST: op="bt"; need_write=0; break;
+           }
+           comprintf("\t%s_l_rr(dst,s);\n"  // Answer now in C 
+                     "\tsbb_l(s,s);\n" // s is 0 if bit was 0,  -1 otherwise 
+                     "\tmake_flags_live();\n" // Get the flags back 
+                     "\tdont_care_flags();\n" 
+                     "\tstart_needflags();\n"
+                     "\tbsf_l_rr(s,s);\n"
+                     "\tlive_flags();\n"
+                     "\tend_needflags();\n",op);
+           if (need_write) 
+               genastore ("dst", curi->dmode, "dstreg", curi->size, "dst");
+       }
+       break;
+*/
+     case i_CMPM:
+     case i_CMP:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0);
+       start_brace ();
+       genflags (flag_cmp, curi->size, "", "src", "dst");
+       break;
+     case i_CMPA:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0);
+       genamode (curi->dmode, "dstreg", sz_long, "dst", 1, 0);
+       start_brace();
+       comprintf("\tint tmps=scratchie++;\n");
+       switch(curi->size) {
+        case sz_byte: comprintf("\tsign_extend_8_rr(tmps,src);\n"); break;
+        case sz_word: comprintf("\tsign_extend_16_rr(tmps,src);\n"); break;
+        case sz_long: comprintf("tmps=src;\n"); break;
+        default: abort();
+       }
+       genflags (flag_cmp, sz_long, "", "tmps", "dst");
+       break;
+       /* The next two are coded a little unconventional, but they are doing
+        * weird things... */
+     case i_MVPRM:
+       isjump; 
+       failure;
+       break;
+     case i_MVPMR:
+       isjump; 
+       failure;
+       break;
+     case i_MOVE:
+       switch(curi->dmode) {
+        case Dreg:
+        case Areg:
+           genamode (curi->smode, "srcreg", curi->size, "src", 1, 0);
+           genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0);
+           genflags (flag_mov, curi->size, "", "src", "dst");
+           genastore ("dst", curi->dmode, "dstreg", curi->size, "dst");
+           break;
+        default: /* It goes to memory, not a register */
+           genamode (curi->smode, "srcreg", curi->size, "src", 1, 0);
+           genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0);
+           genflags (flag_logical, curi->size, "src", "", "");
+           genastore ("src", curi->dmode, "dstreg", curi->size, "dst");
+           break;
+       }
+       break;
+     case i_MOVEA:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0);
+
+       start_brace();
+       comprintf("\tint tmps=scratchie++;\n");
+       switch(curi->size) {
+        case sz_word: comprintf("\tsign_extend_16_rr(dst,src);\n"); break;
+        case sz_long: comprintf("\tmov_l_rr(dst,src);\n"); break;
+        default: abort();
+       }
+       genastore ("dst", curi->dmode, "dstreg", sz_long, "dst");
+       break;
+
+     case i_MVSR2:
+       isjump; 
+       failure;
+       break;
+     case i_MV2SR:
+       isjump; 
+       failure;
+       break;
+     case i_SWAP:
+       genamode (curi->smode, "srcreg", sz_long, "src", 1, 0);
+       comprintf("\tdont_care_flags();\n");
+       comprintf("\trol_l_ri(src,16);\n");
+       genflags (flag_logical, sz_long, "src", "", "");
+       genastore ("src", curi->smode, "srcreg", sz_long, "src");
+       break;
+     case i_EXG:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0);
+       start_brace();
+       comprintf("\tint tmp=scratchie++;\n"
+                 "\tmov_l_rr(tmp,src);\n");
+       genastore ("dst", curi->smode, "srcreg", curi->size, "src");
+       genastore ("tmp", curi->dmode, "dstreg", curi->size, "dst");
+       break;
+     case i_EXT:
+       genamode (curi->smode, "srcreg", sz_long, "src", 1, 0);
+       comprintf("\tdont_care_flags();\n");
+       start_brace ();
+       switch (curi->size)
+       {
+        case sz_byte:
+           comprintf ("\tint dst = src;\n"
+                      "\tsign_extend_8_rr(src,src);\n");
+           break;
+        case sz_word:
+           comprintf ("\tint dst = scratchie++;\n"
+                      "\tsign_extend_8_rr(dst,src);\n");
+           break;
+        case sz_long:
+           comprintf ("\tint dst = src;\n"
+                      "\tsign_extend_16_rr(src,src);\n");
+           break;
+        default:
+           abort ();
+       }
+       genflags (flag_logical,
+                 curi->size == sz_word ? sz_word : sz_long, "dst", "", "");
+       genastore ("dst", curi->smode, "srcreg",
+                  curi->size == sz_word ? sz_word : sz_long, "src");
+       break;
+     case i_MVMEL:
+       genmovemel (opcode);
+       break;
+     case i_MVMLE:
+       genmovemle (opcode);
+       break;
+     case i_TRAP:
+       isjump; 
+       failure;
+       break;
+     case i_MVR2USP:
+       isjump; 
+       failure;
+       break;
+     case i_MVUSP2R:
+       isjump; 
+       failure;
+       break;
+     case i_RESET:
+       isjump; 
+       failure;
+       break;
+     case i_NOP:
+       break;
+     case i_STOP:
+       isjump; 
+       failure;
+       break;
+     case i_RTE:
+       isjump; 
+       failure;
+       break;
+     case i_RTD:
+       genamode (curi->smode, "srcreg", curi->size, "offs", 1, 0);
+       /* offs is constant */
+       comprintf("\tadd_l_ri(offs,4);\n");
+       start_brace();
+       comprintf("\tint newad=scratchie++;\n"
+                 "\treadlong(15,newad,scratchie);\n"
+                 "\tand_l_ri(newad,~1);\n"
+                 "\tmov_l_mr((uae_u32)&regs.pc,newad);\n"
+                 "\tget_n_addr_jmp(newad,PC_P,scratchie);\n"
+                 "\tmov_l_mr((uae_u32)&regs.pc_oldp,PC_P);\n"
+                 "\tm68k_pc_offset=0;\n"
+                 "\tadd_l(15,offs);\n");
+       gen_update_next_handler();
+       isjump; 
+       break;
+     case i_LINK:
+       genamode (curi->smode, "srcreg", sz_long, "src", 1, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "offs", 1, 0);
+       comprintf("\tsub_l_ri(15,4);\n"
+                 "\twritelong_clobber(15,src,scratchie);\n"
+                 "\tmov_l_rr(src,15);\n");
+       if (curi->size==sz_word)
+           comprintf("\tsign_extend_16_rr(offs,offs);\n");
+       comprintf("\tadd_l(15,offs);\n");
+       genastore ("src", curi->smode, "srcreg", sz_long, "src");
+       break;
+     case i_UNLK:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0);
+       comprintf("\tmov_l_rr(15,src);\n"
+                 "\treadlong(15,src,scratchie);\n"
+                 "\tadd_l_ri(15,4);\n");
+       genastore ("src", curi->smode, "srcreg", curi->size, "src");
+       break;
+     case i_RTS:
+       comprintf("\tint newad=scratchie++;\n"
+                 "\treadlong(15,newad,scratchie);\n"
+                 "\tand_l_ri(newad,~1);\n"
+                 "\tmov_l_mr((uae_u32)&regs.pc,newad);\n"
+                 "\tget_n_addr_jmp(newad,PC_P,scratchie);\n"
+                 "\tmov_l_mr((uae_u32)&regs.pc_oldp,PC_P);\n"
+                 "\tm68k_pc_offset=0;\n"
+                 "\tlea_l_brr(15,15,4);\n");
+       gen_update_next_handler();
+       isjump; 
+       break;
+     case i_TRAPV:
+       isjump; 
+       failure;
+       break;
+     case i_RTR:
+       isjump; 
+       failure;
+       break;
+     case i_JSR:
+       isjump; 
+       genamode (curi->smode, "srcreg", curi->size, "src", 0, 0);
+       start_brace();
+       comprintf("\tuae_u32 retadd=start_pc+((char *)comp_pc_p-(char *)start_pc_p)+m68k_pc_offset;\n");
+       comprintf("\tint ret=scratchie++;\n"
+                 "\tmov_l_ri(ret,retadd);\n"
+                 "\tsub_l_ri(15,4);\n"
+                 "\twritelong_clobber(15,ret,scratchie);\n");
+       comprintf("\tand_l_ri(srca,~1);\n"
+                 "\tmov_l_mr((uae_u32)&regs.pc,srca);\n"
+                 "\tget_n_addr_jmp(srca,PC_P,scratchie);\n"
+                 "\tmov_l_mr((uae_u32)&regs.pc_oldp,PC_P);\n"
+                 "\tm68k_pc_offset=0;\n");
+       gen_update_next_handler();
+       break;
+     case i_JMP:
+       isjump;
+       genamode (curi->smode, "srcreg", curi->size, "src", 0, 0);
+       comprintf("\tand_l_ri(srca,~1);\n"
+                 "\tmov_l_mr((uae_u32)&regs.pc,srca);\n"
+                 "\tget_n_addr_jmp(srca,PC_P,scratchie);\n"
+                 "\tmov_l_mr((uae_u32)&regs.pc_oldp,PC_P);\n"
+                 "\tm68k_pc_offset=0;\n");
+       gen_update_next_handler();
+       break;
+     case i_BSR:
+       if (curi->size==sz_long)
+           failure;
+       is_const_jump;
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0);
+       comprintf("\tand_l_ri(src,~1);\n");
+       start_brace();
+       comprintf("\tuae_u32 retadd=start_pc+((char *)comp_pc_p-(char *)start_pc_p)+m68k_pc_offset;\n");
+       comprintf("\tint ret=scratchie++;\n"
+                 "\tmov_l_ri(ret,retadd);\n"
+                 "\tsub_l_ri(15,4);\n"
+                 "\twritelong_clobber(15,ret,scratchie);\n");
+       comprintf("\tadd_l_ri(src,m68k_pc_offset_thisinst+2);\n");
+       comprintf("\tm68k_pc_offset=0;\n");
+       comprintf("\tadd_l(PC_P,src);\n");
+
+       comprintf("\tcomp_pc_p=(void*)get_const(PC_P);\n");
+       break;
+     case i_Bcc:
+       comprintf("\tuae_u32 v,v1,v2;\n");
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0);
+       /* That source is an immediate, so we can clobber it with abandon */
+       switch(curi->size) {
+        case sz_byte: comprintf("\tsign_extend_8_rr(src,src);\n"); break;
+        case sz_word: comprintf("\tsign_extend_16_rr(src,src);\n"); break;
+        case sz_long: break;
+       }
+       comprintf("\tand_l_ri(src,~1);\n");
+       comprintf("\tsub_l_ri(src,m68k_pc_offset-m68k_pc_offset_thisinst-2);\n");
+       /* Leave the following as "add" --- it will allow it to be optimized
+          away due to src being a constant ;-) */
+       comprintf("\tadd_l_ri(src,(uae_u32)comp_pc_p);\n");  
+       comprintf("\tmov_l_ri(PC_P,(uae_u32)comp_pc_p);\n");
+       /* Now they are both constant. Might as well fold in m68k_pc_offset */
+       comprintf("\tadd_l_ri(src,m68k_pc_offset);\n");
+       comprintf("\tadd_l_ri(PC_P,m68k_pc_offset);\n");
+       comprintf("\tm68k_pc_offset=0;\n");
+
+       if (curi->cc>=2) {
+           comprintf("\tv1=get_const(PC_P);\n"
+                     "\tv2=get_const(src);\n"
+                     "\tregister_branch(v1,v2,%d);\n",
+                     cond_codes_x86[curi->cc]);
+           comprintf("\tmake_flags_live();\n"); /* Load the flags */
+           isjump; 
+       }
+       else {
+           is_const_jump; 
+       }
+
+       switch(curi->cc) {
+        case 0:  /* Unconditional jump */
+           comprintf("\tmov_l_rr(PC_P,src);\n"); 
+           comprintf("\tcomp_pc_p=(void*)get_const(PC_P);\n");
+           break;
+        case 1: break; /* This is silly! */
+        case 8: failure; break;  /* Work out details! FIXME */
+        case 9: failure; break;  /* Not critical, though! */
+
+        case 2:
+        case 3:
+        case 4:
+        case 5:
+        case 6:
+        case 7:
+        case 10:
+        case 11:
+        case 12:
+        case 13:
+        case 14:
+        case 15: 
+           break;
+        default: abort();
+       }
+       break;
+     case i_LEA:
+       genamode (curi->smode, "srcreg", curi->size, "src", 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0);
+       genastore ("srca", curi->dmode, "dstreg", curi->size, "dst");
+       break;
+     case i_PEA:
+       if (table68k[opcode].smode==Areg || 
+           table68k[opcode].smode==Aind || 
+           table68k[opcode].smode==Aipi || 
+           table68k[opcode].smode==Apdi || 
+           table68k[opcode].smode==Ad16 || 
+           table68k[opcode].smode==Ad8r) 
+           comprintf("if (srcreg==7) dodgy=1;\n");
+
+       genamode (curi->smode, "srcreg", curi->size, "src", 0, 0);
+       genamode (Apdi, "7", sz_long, "dst", 2, 0);
+       genastore ("srca", Apdi, "7", sz_long, "dst");
+       break;
+     case i_DBcc:
+       isjump; 
+       uses_cmov;
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "offs", 1, 0);
+
+       /* That offs is an immediate, so we can clobber it with abandon */
+       switch(curi->size) {
+        case sz_word: comprintf("\tsign_extend_16_rr(offs,offs);\n"); break;
+        default: abort();  /* Seems this only comes in word flavour */
+       }
+       comprintf("\tsub_l_ri(offs,m68k_pc_offset-m68k_pc_offset_thisinst-2);\n"); 
+       comprintf("\tadd_l_ri(offs,(uae_u32)comp_pc_p);\n"); /* New PC, 
+                                                               once the 
+                                                               offset_68k is
+                                                               * also added */
+       /* Let's fold in the m68k_pc_offset at this point */
+       comprintf("\tadd_l_ri(offs,m68k_pc_offset);\n");
+       comprintf("\tadd_l_ri(PC_P,m68k_pc_offset);\n");
+       comprintf("\tm68k_pc_offset=0;\n");
+
+       start_brace();
+       comprintf("\tint nsrc=scratchie++;\n");
+
+       if (curi->cc>=2) {
+           comprintf("\tmake_flags_live();\n"); /* Load the flags */
+       }
+
+       if (curi->size!=sz_word) 
+           abort();
+
+
+       switch(curi->cc) {
+        case 0: /* This is an elaborate nop? */
+           break;
+        case 1: 
+           comprintf("\tstart_needflags();\n");
+           comprintf("\tsub_w_ri(src,1);\n");
+           comprintf("\t end_needflags();\n");
+           start_brace();
+           comprintf("\tuae_u32 v2,v;\n"
+                     "\tuae_u32 v1=get_const(PC_P);\n");
+           comprintf("\tv2=get_const(offs);\n"
+                     "\tregister_branch(v1,v2,3);\n");
+           break;
+
+        case 8: failure; break;  /* Work out details! FIXME */
+        case 9: failure; break;  /* Not critical, though! */
+
+        case 2:
+        case 3:
+        case 4:
+        case 5:
+        case 6:
+        case 7:
+        case 10:
+        case 11:
+        case 12:
+        case 13:
+        case 14:
+        case 15:
+           comprintf("\tmov_l_rr(nsrc,src);\n");
+           comprintf("\tlea_l_brr(scratchie,src,(uae_s32)-1);\n"
+                     "\tmov_w_rr(src,scratchie);\n");
+           comprintf("\tcmov_l_rr(offs,PC_P,%d);\n",
+                     cond_codes_x86[curi->cc]);
+           comprintf("\tcmov_l_rr(src,nsrc,%d);\n",
+                     cond_codes_x86[curi->cc]);
+           /* OK, now for cc=true, we have src==nsrc and offs==PC_P, 
+              so whether we move them around doesn't matter. However,
+              if cc=false, we have offs==jump_pc, and src==nsrc-1 */
+
+           comprintf("\t start_needflags();\n");
+           comprintf("\ttest_w_rr(nsrc,nsrc);\n"); 
+           comprintf("\t end_needflags();\n");
+           comprintf("\tcmov_l_rr(PC_P,offs,5);\n"); 
+           break;
+        default: abort();
+       }
+       genastore ("src", curi->smode, "srcreg", curi->size, "src");
+       gen_update_next_handler();
+       break;
+
+     case i_Scc:
+       genamode (curi->smode, "srcreg", curi->size, "src", 2, 0);
+       start_brace ();
+       comprintf ("\tint val = scratchie++;\n");
+
+       /* We set val to 0 if we really should use 255, and to 1 for real 0 */
+       switch(curi->cc) {
+        case 0:  /* Unconditional set */
+           comprintf("\tmov_l_ri(val,0);\n"); 
+           break;
+        case 1: 
+           /* Unconditional not-set */
+           comprintf("\tmov_l_ri(val,1);\n"); 
+           break;
+        case 8: failure; break;  /* Work out details! FIXME */
+        case 9: failure; break;  /* Not critical, though! */
+
+        case 2:
+        case 3:
+        case 4:
+        case 5:
+        case 6:
+        case 7:
+        case 10:
+        case 11:
+        case 12:
+        case 13:
+        case 14:
+        case 15:
+           comprintf("\tmake_flags_live();\n"); /* Load the flags */
+           /* All condition codes can be inverted by changing the LSB */
+           comprintf("\tsetcc(val,%d);\n",
+                     cond_codes_x86[curi->cc]^1); break;
+        default: abort();
+       }
+       comprintf("\tsub_b_ri(val,1);\n");
+       genastore ("val", curi->smode, "srcreg", curi->size, "src");
+       break;
+     case i_DIVU:
+       isjump; 
+       failure;
+       break;
+     case i_DIVS:
+       isjump; 
+       failure;
+       break;
+     case i_MULU:
+       comprintf("\tdont_care_flags();\n");
+       genamode (curi->smode, "srcreg", sz_word, "src", 1, 0);
+       genamode (curi->dmode, "dstreg", sz_word, "dst", 1, 0);
+       /* To do 16x16 unsigned multiplication, we actually use 
+          32x32 signed, and zero-extend the registers first.
+          That solves the problem of MUL needing dedicated registers
+          on the x86 */
+       comprintf("\tzero_extend_16_rr(scratchie,src);\n"
+                 "\tzero_extend_16_rr(dst,dst);\n"
+                 "\timul_32_32(dst,scratchie);\n");
+       genflags (flag_logical, sz_long, "dst", "", "");
+       genastore ("dst", curi->dmode, "dstreg", sz_long, "dst");
+       break;
+     case i_MULS:
+       comprintf("\tdont_care_flags();\n");
+       genamode (curi->smode, "srcreg", sz_word, "src", 1, 0);
+       genamode (curi->dmode, "dstreg", sz_word, "dst", 1, 0);
+       comprintf("\tsign_extend_16_rr(scratchie,src);\n"
+                 "\tsign_extend_16_rr(dst,dst);\n"
+                 "\timul_32_32(dst,scratchie);\n");
+       genflags (flag_logical, sz_long, "dst", "", "");
+       genastore ("dst", curi->dmode, "dstreg", sz_long, "dst");
+       break;
+     case i_CHK:
+       isjump; 
+       failure;
+       break;
+
+     case i_CHK2:
+       isjump; 
+       failure;
+       break;
+
+     case i_ASR:
+       mayfail;
+       if (curi->smode==Dreg) {
+           comprintf("if ((uae_u32)srcreg==(uae_u32)dstreg) {\n"
+               "  FAIL(1);\n"
+               "  return 0;\n"
+               "} \n");
+           start_brace();
+       }
+       comprintf("\tdont_care_flags();\n");
+
+       genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0);
+       if (curi->smode!=immi) {
+           if (!noflags) {
+               uses_cmov;
+               start_brace();
+               comprintf("\tint highmask;\n"
+                         "\tint width;\n"
+                         "\tint cdata=scratchie++;\n"
+                         "\tint tmpcnt=scratchie++;\n"
+                         "\tint highshift=scratchie++;\n");
+               comprintf("\tmov_l_rr(tmpcnt,cnt);\n"
+                         "\tand_l_ri(tmpcnt,63);\n"
+                         "\tmov_l_ri(cdata,0);\n"
+                         "\tcmov_l_rr(cdata,data,5);\n");
+               /* cdata is now either data (for shift count!=0) or
+                  0 (for shift count==0) */
+               switch(curi->size) {
+                case sz_byte: comprintf("\tshra_b_rr(data,cnt);\n"
+                                        "\thighmask=0x38;\n"
+                                        "\twidth=8;\n"); 
+                break;
+                case sz_word: comprintf("\tshra_w_rr(data,cnt);\n"
+                                        "\thighmask=0x30;\n"
+                                        "\twidth=16;\n"); 
+                break;
+                case sz_long: comprintf("\tshra_l_rr(data,cnt);\n"
+                                        "\thighmask=0x20;\n"
+                                        "\twidth=32;\n"); 
+                break;
+                default: abort();
+               }
+               comprintf("test_l_ri(cnt,highmask);\n"
+                         "mov_l_ri(highshift,0);\n"
+                         "mov_l_ri(scratchie,width/2);\n"
+                         "cmov_l_rr(highshift,scratchie,5);\n");
+               /* The x86 masks out bits, so we now make sure that things
+                  really get shifted as much as planned */
+               switch(curi->size) {
+                case sz_byte: comprintf("\tshra_b_rr(data,highshift);\n");break;
+                case sz_word: comprintf("\tshra_w_rr(data,highshift);\n");break;
+                case sz_long: comprintf("\tshra_l_rr(data,highshift);\n");break;
+                default: abort();
+               }
+               /* And again */
+               switch(curi->size) {
+                case sz_byte: comprintf("\tshra_b_rr(data,highshift);\n");break;
+                case sz_word: comprintf("\tshra_w_rr(data,highshift);\n");break;
+                case sz_long: comprintf("\tshra_l_rr(data,highshift);\n");break;
+                default: abort();
+               }
+               
+               /* Result of shift is now in data. Now we need to determine
+                  the carry by shifting cdata one less */
+               comprintf("\tsub_l_ri(tmpcnt,1);\n");
+               switch(curi->size) {
+                case sz_byte: comprintf("\tshra_b_rr(cdata,tmpcnt);\n");break;
+                case sz_word: comprintf("\tshra_w_rr(cdata,tmpcnt);\n");break;
+                case sz_long: comprintf("\tshra_l_rr(cdata,tmpcnt);\n");break;
+                default: abort();
+               }
+               /* If the shift count was higher than the width, we need
+                  to pick up the sign from data */
+               comprintf("test_l_ri(tmpcnt,highmask);\n"
+                         "cmov_l_rr(cdata,data,5);\n");
+               /* And create the flags */
+               comprintf("\tstart_needflags();\n");
+               comprintf("\tif (needed_flags & FLAG_ZNV)\n");
+               switch(curi->size) {
+                case sz_byte: comprintf("\t  test_b_rr(data,data);\n"); break;
+                case sz_word: comprintf("\t  test_w_rr(data,data);\n"); break;
+                case sz_long: comprintf("\t  test_l_rr(data,data);\n"); break;
+               }
+               comprintf("\t bt_l_ri(cdata,0);\n"); /* Set C */
+               comprintf("\t live_flags();\n");
+               comprintf("\t end_needflags();\n");
+               comprintf("\t duplicate_carry();\n");
+               comprintf("if (!(needed_flags & FLAG_CZNV)) dont_care_flags();\n");
+               genastore ("data", curi->dmode, "dstreg", curi->size, "data");
+           }
+           else {
+               uses_cmov;
+               start_brace();
+               comprintf("\tint highmask;\n"
+                         "\tint width;\n"
+                         "\tint highshift=scratchie++;\n");
+               switch(curi->size) {
+                case sz_byte: comprintf("\tshra_b_rr(data,cnt);\n"
+                                        "\thighmask=0x38;\n"
+                                        "\twidth=8;\n"); 
+                break;
+                case sz_word: comprintf("\tshra_w_rr(data,cnt);\n"
+                                        "\thighmask=0x30;\n"
+                                        "\twidth=16;\n"); 
+                break;
+                case sz_long: comprintf("\tshra_l_rr(data,cnt);\n"
+                                        "\thighmask=0x20;\n"
+                                        "\twidth=32;\n"); 
+                break;
+                default: abort();
+               }
+               comprintf("test_l_ri(cnt,highmask);\n"
+                         "mov_l_ri(highshift,0);\n"
+                         "mov_l_ri(scratchie,width/2);\n"
+                         "cmov_l_rr(highshift,scratchie,5);\n");
+               /* The x86 masks out bits, so we now make sure that things
+                  really get shifted as much as planned */
+               switch(curi->size) {
+                case sz_byte: comprintf("\tshra_b_rr(data,highshift);\n");break;
+                case sz_word: comprintf("\tshra_w_rr(data,highshift);\n");break;
+                case sz_long: comprintf("\tshra_l_rr(data,highshift);\n");break;
+                default: abort();
+               }
+               /* And again */
+               switch(curi->size) {
+                case sz_byte: comprintf("\tshra_b_rr(data,highshift);\n");break;
+                case sz_word: comprintf("\tshra_w_rr(data,highshift);\n");break;
+                case sz_long: comprintf("\tshra_l_rr(data,highshift);\n");break;
+                default: abort();
+               }
+               genastore ("data", curi->dmode, "dstreg", curi->size, "data");
+           }
+       }
+       else {
+           start_brace();
+           comprintf("\tint tmp=scratchie++;\n"
+                     "\tint bp;\n"
+                     "\tmov_l_rr(tmp,data);\n");
+           switch(curi->size) {
+            case sz_byte: comprintf("\tshra_b_ri(data,srcreg);\n"
+                                    "\tbp=srcreg-1;\n"); break;
+            case sz_word: comprintf("\tshra_w_ri(data,srcreg);\n"
+                                    "\tbp=srcreg-1;\n"); break;
+            case sz_long: comprintf("\tshra_l_ri(data,srcreg);\n"
+                                    "\tbp=srcreg-1;\n"); break;
+            default: abort();
+           }
+
+           if (!noflags) {
+               comprintf("\tstart_needflags();\n");
+               comprintf("\tif (needed_flags & FLAG_ZNV)\n");
+               switch(curi->size) {
+                case sz_byte: comprintf("\t  test_b_rr(data,data);\n"); break;
+                case sz_word: comprintf("\t  test_w_rr(data,data);\n"); break;
+                case sz_long: comprintf("\t  test_l_rr(data,data);\n"); break;
+               }
+               comprintf("\t bt_l_ri(tmp,bp);\n"); /* Set C */
+               comprintf("\t live_flags();\n");
+               comprintf("\t end_needflags();\n");
+               comprintf("\t duplicate_carry();\n");
+               comprintf("if (!(needed_flags & FLAG_CZNV)) dont_care_flags();\n");
+           }
+           genastore ("data", curi->dmode, "dstreg", curi->size, "data");
+       }
+       break;
+
+     case i_ASL:
+       mayfail;
+       if (curi->smode==Dreg) {
+           comprintf("if ((uae_u32)srcreg==(uae_u32)dstreg) {\n"
+               "  FAIL(1);\n"
+               "  return 0;\n"
+               "} \n");
+           start_brace();
+       }
+       comprintf("\tdont_care_flags();\n");
+       /* Except for the handling of the V flag, this is identical to
+          LSL. The handling of V is, uhm, unpleasant, so if it's needed,
+          let the normal emulation handle it. Shoulders of giants kinda
+          thing ;-) */
+       comprintf("if (needed_flags & FLAG_V) {\n"
+                 "  FAIL(1);\n"
+                 "  return 0;\n"
+                 "} \n");
+       
+       genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0);
+       if (curi->smode!=immi) {
+           if (!noflags) {
+               uses_cmov;
+               start_brace();
+               comprintf("\tint highmask;\n"
+                         "\tint cdata=scratchie++;\n"
+                         "\tint tmpcnt=scratchie++;\n");
+               comprintf("\tmov_l_rr(tmpcnt,cnt);\n"
+                         "\tand_l_ri(tmpcnt,63);\n"
+                         "\tmov_l_ri(cdata,0);\n"
+                         "\tcmov_l_rr(cdata,data,5);\n");
+               /* cdata is now either data (for shift count!=0) or
+                  0 (for shift count==0) */
+               switch(curi->size) {
+                case sz_byte: comprintf("\tshll_b_rr(data,cnt);\n"
+                                        "\thighmask=0x38;\n"); 
+                break;
+                case sz_word: comprintf("\tshll_w_rr(data,cnt);\n"
+                                        "\thighmask=0x30;\n"); 
+                break;
+                case sz_long: comprintf("\tshll_l_rr(data,cnt);\n"
+                                        "\thighmask=0x20;\n"); 
+                break;
+                default: abort();
+               }
+               comprintf("test_l_ri(cnt,highmask);\n"
+                         "mov_l_ri(scratchie,0);\n"
+                         "cmov_l_rr(scratchie,data,4);\n");
+               switch(curi->size) {
+                case sz_byte: comprintf("\tmov_b_rr(data,scratchie);\n");break;
+                case sz_word: comprintf("\tmov_w_rr(data,scratchie);\n");break;
+                case sz_long: comprintf("\tmov_l_rr(data,scratchie);\n");break;
+                default: abort();
+               }
+               /* Result of shift is now in data. Now we need to determine
+                  the carry by shifting cdata one less */
+               comprintf("\tsub_l_ri(tmpcnt,1);\n");
+               switch(curi->size) {
+                case sz_byte: comprintf("\tshll_b_rr(cdata,tmpcnt);\n");break;
+                case sz_word: comprintf("\tshll_w_rr(cdata,tmpcnt);\n");break;
+                case sz_long: comprintf("\tshll_l_rr(cdata,tmpcnt);\n");break;
+                default: abort();
+               }
+               comprintf("test_l_ri(tmpcnt,highmask);\n"
+                         "mov_l_ri(scratchie,0);\n"
+                         "cmov_l_rr(cdata,scratchie,5);\n");
+               /* And create the flags */
+               comprintf("\tstart_needflags();\n");
+
+               comprintf("\tif (needed_flags & FLAG_ZNV)\n");
+               switch(curi->size) {
+                case sz_byte: comprintf("\t  test_b_rr(data,data);\n"); 
+                   comprintf("\t bt_l_ri(cdata,7);\n"); break;
+                case sz_word: comprintf("\t  test_w_rr(data,data);\n"); 
+                   comprintf("\t bt_l_ri(cdata,15);\n"); break;
+                case sz_long: comprintf("\t  test_l_rr(data,data);\n"); 
+                   comprintf("\t bt_l_ri(cdata,31);\n"); break;
+               }
+               comprintf("\t live_flags();\n");
+               comprintf("\t end_needflags();\n");
+               comprintf("\t duplicate_carry();\n");
+               comprintf("if (!(needed_flags & FLAG_CZNV)) dont_care_flags();\n");
+               genastore ("data", curi->dmode, "dstreg", curi->size, "data");
+           }
+           else {
+               uses_cmov;
+               start_brace();
+               comprintf("\tint highmask;\n");
+               switch(curi->size) {
+                case sz_byte: comprintf("\tshll_b_rr(data,cnt);\n"
+                                        "\thighmask=0x38;\n"); 
+                   break;
+                case sz_word: comprintf("\tshll_w_rr(data,cnt);\n"
+                                        "\thighmask=0x30;\n"); 
+                   break;
+                case sz_long: comprintf("\tshll_l_rr(data,cnt);\n"
+                                        "\thighmask=0x20;\n"); 
+                   break;
+                default: abort();
+               }
+               comprintf("test_l_ri(cnt,highmask);\n"
+                         "mov_l_ri(scratchie,0);\n"
+                         "cmov_l_rr(scratchie,data,4);\n");
+               switch(curi->size) {
+                case sz_byte: comprintf("\tmov_b_rr(data,scratchie);\n");break;
+                case sz_word: comprintf("\tmov_w_rr(data,scratchie);\n");break;
+                case sz_long: comprintf("\tmov_l_rr(data,scratchie);\n");break;
+                default: abort();
+               }
+               genastore ("data", curi->dmode, "dstreg", curi->size, "data");
+           }
+       }
+       else {
+           start_brace();
+           comprintf("\tint tmp=scratchie++;\n"
+                     "\tint bp;\n"
+                     "\tmov_l_rr(tmp,data);\n");
+           switch(curi->size) {
+            case sz_byte: comprintf("\tshll_b_ri(data,srcreg);\n"
+                                    "\tbp=8-srcreg;\n"); break;
+            case sz_word: comprintf("\tshll_w_ri(data,srcreg);\n"
+                                    "\tbp=16-srcreg;\n"); break;
+            case sz_long: comprintf("\tshll_l_ri(data,srcreg);\n"
+                                    "\tbp=32-srcreg;\n"); break;
+            default: abort();
+           }
+
+           if (!noflags) {
+               comprintf("\tstart_needflags();\n");
+               comprintf("\tif (needed_flags & FLAG_ZNV)\n");
+               switch(curi->size) {
+                case sz_byte: comprintf("\t  test_b_rr(data,data);\n"); break;
+                case sz_word: comprintf("\t  test_w_rr(data,data);\n"); break;
+                case sz_long: comprintf("\t  test_l_rr(data,data);\n"); break;
+               }
+               comprintf("\t bt_l_ri(tmp,bp);\n"); /* Set C */
+               comprintf("\t live_flags();\n");
+               comprintf("\t end_needflags();\n");
+               comprintf("\t duplicate_carry();\n");
+               comprintf("if (!(needed_flags & FLAG_CZNV)) dont_care_flags();\n");
+           }
+           genastore ("data", curi->dmode, "dstreg", curi->size, "data");
+       }
+       break;
+    
+     case i_LSR:
+       mayfail;
+       if (curi->smode==Dreg) {
+           comprintf("if ((uae_u32)srcreg==(uae_u32)dstreg) {\n"
+               "  FAIL(1);\n"
+               "  return 0;\n"
+               "} \n");
+           start_brace();
+       }
+       comprintf("\tdont_care_flags();\n");
+
+       genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0);
+       if (curi->smode!=immi) {
+           if (!noflags) {
+               uses_cmov;
+               start_brace();
+               comprintf("\tint highmask;\n"
+                         "\tint cdata=scratchie++;\n"
+                         "\tint tmpcnt=scratchie++;\n");
+               comprintf("\tmov_l_rr(tmpcnt,cnt);\n"
+                         "\tand_l_ri(tmpcnt,63);\n"
+                         "\tmov_l_ri(cdata,0);\n"
+                         "\tcmov_l_rr(cdata,data,5);\n");
+               /* cdata is now either data (for shift count!=0) or
+                  0 (for shift count==0) */
+               switch(curi->size) {
+                case sz_byte: comprintf("\tshrl_b_rr(data,cnt);\n"
+                                        "\thighmask=0x38;\n"); 
+                break;
+                case sz_word: comprintf("\tshrl_w_rr(data,cnt);\n"
+                                        "\thighmask=0x30;\n"); 
+                break;
+                case sz_long: comprintf("\tshrl_l_rr(data,cnt);\n"
+                                        "\thighmask=0x20;\n"); 
+                break;
+                default: abort();
+               }
+               comprintf("test_l_ri(cnt,highmask);\n"
+                         "mov_l_ri(scratchie,0);\n"
+                         "cmov_l_rr(scratchie,data,4);\n");
+               switch(curi->size) {
+                case sz_byte: comprintf("\tmov_b_rr(data,scratchie);\n");break;
+                case sz_word: comprintf("\tmov_w_rr(data,scratchie);\n");break;
+                case sz_long: comprintf("\tmov_l_rr(data,scratchie);\n");break;
+                default: abort();
+               }
+               /* Result of shift is now in data. Now we need to determine
+                  the carry by shifting cdata one less */
+               comprintf("\tsub_l_ri(tmpcnt,1);\n");
+               switch(curi->size) {
+                case sz_byte: comprintf("\tshrl_b_rr(cdata,tmpcnt);\n");break;
+                case sz_word: comprintf("\tshrl_w_rr(cdata,tmpcnt);\n");break;
+                case sz_long: comprintf("\tshrl_l_rr(cdata,tmpcnt);\n");break;
+                default: abort();
+               }
+               comprintf("test_l_ri(tmpcnt,highmask);\n"
+                         "mov_l_ri(scratchie,0);\n"
+                         "cmov_l_rr(cdata,scratchie,5);\n");
+               /* And create the flags */
+               comprintf("\tstart_needflags();\n");
+               comprintf("\tif (needed_flags & FLAG_ZNV)\n");
+               switch(curi->size) {
+                case sz_byte: comprintf("\t  test_b_rr(data,data);\n"); break;
+                case sz_word: comprintf("\t  test_w_rr(data,data);\n"); break;
+                case sz_long: comprintf("\t  test_l_rr(data,data);\n"); break;
+               }
+               comprintf("\t bt_l_ri(cdata,0);\n"); /* Set C */
+               comprintf("\t live_flags();\n");
+               comprintf("\t end_needflags();\n");
+               comprintf("\t duplicate_carry();\n");
+               comprintf("if (!(needed_flags & FLAG_CZNV)) dont_care_flags();\n");
+               genastore ("data", curi->dmode, "dstreg", curi->size, "data");
+           }
+           else {
+               uses_cmov;
+               start_brace();
+               comprintf("\tint highmask;\n");
+               switch(curi->size) {
+                case sz_byte: comprintf("\tshrl_b_rr(data,cnt);\n"
+                                        "\thighmask=0x38;\n"); 
+                   break;
+                case sz_word: comprintf("\tshrl_w_rr(data,cnt);\n"
+                                        "\thighmask=0x30;\n"); 
+                   break;
+                case sz_long: comprintf("\tshrl_l_rr(data,cnt);\n"
+                                        "\thighmask=0x20;\n"); 
+                   break;
+                default: abort();
+               }
+               comprintf("test_l_ri(cnt,highmask);\n"
+                         "mov_l_ri(scratchie,0);\n"
+                         "cmov_l_rr(scratchie,data,4);\n");
+               switch(curi->size) {
+                case sz_byte: comprintf("\tmov_b_rr(data,scratchie);\n");break;
+                case sz_word: comprintf("\tmov_w_rr(data,scratchie);\n");break;
+                case sz_long: comprintf("\tmov_l_rr(data,scratchie);\n");break;
+                default: abort();
+               }
+               genastore ("data", curi->dmode, "dstreg", curi->size, "data");
+           }
+       }
+       else {
+           start_brace();
+           comprintf("\tint tmp=scratchie++;\n"
+                     "\tint bp;\n"
+                     "\tmov_l_rr(tmp,data);\n");
+           switch(curi->size) {
+            case sz_byte: comprintf("\tshrl_b_ri(data,srcreg);\n"
+                                    "\tbp=srcreg-1;\n"); break;
+            case sz_word: comprintf("\tshrl_w_ri(data,srcreg);\n"
+                                    "\tbp=srcreg-1;\n"); break;
+            case sz_long: comprintf("\tshrl_l_ri(data,srcreg);\n"
+                                    "\tbp=srcreg-1;\n"); break;
+            default: abort();
+           }
+
+           if (!noflags) {
+               comprintf("\tstart_needflags();\n");
+               comprintf("\tif (needed_flags & FLAG_ZNV)\n");
+               switch(curi->size) {
+                case sz_byte: comprintf("\t  test_b_rr(data,data);\n"); break;
+                case sz_word: comprintf("\t  test_w_rr(data,data);\n"); break;
+                case sz_long: comprintf("\t  test_l_rr(data,data);\n"); break;
+               }
+               comprintf("\t bt_l_ri(tmp,bp);\n"); /* Set C */
+               comprintf("\t live_flags();\n");
+               comprintf("\t end_needflags();\n");
+               comprintf("\t duplicate_carry();\n");
+               comprintf("if (!(needed_flags & FLAG_CZNV)) dont_care_flags();\n");
+           }
+           genastore ("data", curi->dmode, "dstreg", curi->size, "data");
+       }
+       break;
+
+     case i_LSL:
+       comprintf("\tdont_care_flags();\n");
+
+       genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0);
+       if (curi->smode!=immi) {
+           if (!noflags) {
+               uses_cmov;
+               start_brace();
+               comprintf("\tint highmask;\n"
+                         "\tint cdata=scratchie++;\n"
+                         "\tint tmpcnt=scratchie++;\n");
+               comprintf("\tmov_l_rr(tmpcnt,cnt);\n"
+                         "\tand_l_ri(tmpcnt,63);\n"
+                         "\tmov_l_ri(cdata,0);\n"
+                         "\tcmov_l_rr(cdata,data,5);\n");
+               /* cdata is now either data (for shift count!=0) or
+                  0 (for shift count==0) */
+               switch(curi->size) {
+                case sz_byte: comprintf("\tshll_b_rr(data,cnt);\n"
+                                        "\thighmask=0x38;\n"); 
+                break;
+                case sz_word: comprintf("\tshll_w_rr(data,cnt);\n"
+                                        "\thighmask=0x30;\n"); 
+                break;
+                case sz_long: comprintf("\tshll_l_rr(data,cnt);\n"
+                                        "\thighmask=0x20;\n"); 
+                break;
+                default: abort();
+               }
+               comprintf("test_l_ri(cnt,highmask);\n"
+                         "mov_l_ri(scratchie,0);\n"
+                         "cmov_l_rr(scratchie,data,4);\n");
+               switch(curi->size) {
+                case sz_byte: comprintf("\tmov_b_rr(data,scratchie);\n");break;
+                case sz_word: comprintf("\tmov_w_rr(data,scratchie);\n");break;
+                case sz_long: comprintf("\tmov_l_rr(data,scratchie);\n");break;
+                default: abort();
+               }
+               /* Result of shift is now in data. Now we need to determine
+                  the carry by shifting cdata one less */
+               comprintf("\tsub_l_ri(tmpcnt,1);\n");
+               switch(curi->size) {
+                case sz_byte: comprintf("\tshll_b_rr(cdata,tmpcnt);\n");break;
+                case sz_word: comprintf("\tshll_w_rr(cdata,tmpcnt);\n");break;
+                case sz_long: comprintf("\tshll_l_rr(cdata,tmpcnt);\n");break;
+                default: abort();
+               }
+               comprintf("test_l_ri(tmpcnt,highmask);\n"
+                         "mov_l_ri(scratchie,0);\n"
+                         "cmov_l_rr(cdata,scratchie,5);\n");
+               /* And create the flags */
+               comprintf("\tstart_needflags();\n");
+               comprintf("\tif (needed_flags & FLAG_ZNV)\n");
+               switch(curi->size) {
+                case sz_byte: comprintf("\t  test_b_rr(data,data);\n"); 
+                   comprintf("\t bt_l_ri(cdata,7);\n"); break;
+                case sz_word: comprintf("\t  test_w_rr(data,data);\n"); 
+                   comprintf("\t bt_l_ri(cdata,15);\n"); break;
+                case sz_long: comprintf("\t  test_l_rr(data,data);\n"); 
+                   comprintf("\t bt_l_ri(cdata,31);\n"); break;
+               }
+               comprintf("\t live_flags();\n");
+               comprintf("\t end_needflags();\n");
+               comprintf("\t duplicate_carry();\n");
+               comprintf("if (!(needed_flags & FLAG_CZNV)) dont_care_flags();\n");
+               genastore ("data", curi->dmode, "dstreg", curi->size, "data");
+           }
+           else {
+               uses_cmov;
+               start_brace();
+               comprintf("\tint highmask;\n");
+               switch(curi->size) {
+                case sz_byte: comprintf("\tshll_b_rr(data,cnt);\n"
+                                        "\thighmask=0x38;\n"); 
+                   break;
+                case sz_word: comprintf("\tshll_w_rr(data,cnt);\n"
+                                        "\thighmask=0x30;\n"); 
+                   break;
+                case sz_long: comprintf("\tshll_l_rr(data,cnt);\n"
+                                        "\thighmask=0x20;\n"); 
+                   break;
+                default: abort();
+               }
+               comprintf("test_l_ri(cnt,highmask);\n"
+                         "mov_l_ri(scratchie,0);\n"
+                         "cmov_l_rr(scratchie,data,4);\n");
+               switch(curi->size) {
+                case sz_byte: comprintf("\tmov_b_rr(data,scratchie);\n");break;
+                case sz_word: comprintf("\tmov_w_rr(data,scratchie);\n");break;
+                case sz_long: comprintf("\tmov_l_rr(data,scratchie);\n");break;
+                default: abort();
+               }
+               genastore ("data", curi->dmode, "dstreg", curi->size, "data");
+           }
+       }
+       else {
+           start_brace();
+           comprintf("\tint tmp=scratchie++;\n"
+                     "\tint bp;\n"
+                     "\tmov_l_rr(tmp,data);\n");
+           switch(curi->size) {
+            case sz_byte: comprintf("\tshll_b_ri(data,srcreg);\n"
+                                    "\tbp=8-srcreg;\n"); break;
+            case sz_word: comprintf("\tshll_w_ri(data,srcreg);\n"
+                                    "\tbp=16-srcreg;\n"); break;
+            case sz_long: comprintf("\tshll_l_ri(data,srcreg);\n"
+                                    "\tbp=32-srcreg;\n"); break;
+            default: abort();
+           }
+
+           if (!noflags) {
+               comprintf("\tstart_needflags();\n");
+               comprintf("\tif (needed_flags & FLAG_ZNV)\n");
+               switch(curi->size) {
+                case sz_byte: comprintf("\t  test_b_rr(data,data);\n"); break;
+                case sz_word: comprintf("\t  test_w_rr(data,data);\n"); break;
+                case sz_long: comprintf("\t  test_l_rr(data,data);\n"); break;
+               }
+               comprintf("\t bt_l_ri(tmp,bp);\n"); /* Set C */
+               comprintf("\t live_flags();\n");
+               comprintf("\t end_needflags();\n");
+               comprintf("\t duplicate_carry();\n");
+               comprintf("if (!(needed_flags & FLAG_CZNV)) dont_care_flags();\n");
+           }
+           genastore ("data", curi->dmode, "dstreg", curi->size, "data");
+       }
+       break;
+
+     case i_ROL:
+       mayfail;
+       if (curi->smode==Dreg) {
+           comprintf("if ((uae_u32)srcreg==(uae_u32)dstreg) {\n"
+               "  FAIL(1);\n"
+               "  return 0;\n"
+               "} \n");
+           start_brace();
+       }
+       comprintf("\tdont_care_flags();\n");
+       genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0);
+       start_brace ();
+
+       switch(curi->size) {
+        case sz_long: comprintf("\t rol_l_rr(data,cnt);\n"); break;
+        case sz_word: comprintf("\t rol_w_rr(data,cnt);\n"); break;
+        case sz_byte: comprintf("\t rol_b_rr(data,cnt);\n"); break;
+       }
+      
+       if (!noflags) {
+           comprintf("\tstart_needflags();\n");
+           comprintf("\tif (needed_flags & FLAG_ZNV)\n");
+           switch(curi->size) {
+            case sz_byte: comprintf("\t  test_b_rr(data,data);\n"); break;
+            case sz_word: comprintf("\t  test_w_rr(data,data);\n"); break;
+            case sz_long: comprintf("\t  test_l_rr(data,data);\n"); break;
+           }
+           comprintf("\t bt_l_ri(data,0x00);\n"); /* Set C */
+           comprintf("\t live_flags();\n");
+           comprintf("\t end_needflags();\n");
+       }
+       genastore ("data", curi->dmode, "dstreg", curi->size, "data");
+       break;
+
+     case i_ROR:
+       mayfail;
+       if (curi->smode==Dreg) {
+           comprintf("if ((uae_u32)srcreg==(uae_u32)dstreg) {\n"
+               "  FAIL(1);\n"
+               "  return 0;\n"
+               "} \n");
+           start_brace();
+       }
+       comprintf("\tdont_care_flags();\n");
+       genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0);
+       start_brace ();
+
+       switch(curi->size) {
+        case sz_long: comprintf("\t ror_l_rr(data,cnt);\n"); break;
+        case sz_word: comprintf("\t ror_w_rr(data,cnt);\n"); break;
+        case sz_byte: comprintf("\t ror_b_rr(data,cnt);\n"); break;
+       }
+      
+       if (!noflags) {
+           comprintf("\tstart_needflags();\n");
+           comprintf("\tif (needed_flags & FLAG_ZNV)\n");
+           switch(curi->size) {
+            case sz_byte: comprintf("\t  test_b_rr(data,data);\n"); break;
+            case sz_word: comprintf("\t  test_w_rr(data,data);\n"); break;
+            case sz_long: comprintf("\t  test_l_rr(data,data);\n"); break;
+           }
+           switch(curi->size) {
+            case sz_byte: comprintf("\t bt_l_ri(data,0x07);\n"); break;
+            case sz_word: comprintf("\t bt_l_ri(data,0x0f);\n"); break;
+            case sz_long: comprintf("\t bt_l_ri(data,0x1f);\n"); break;
+           }
+           comprintf("\t live_flags();\n");
+           comprintf("\t end_needflags();\n");
+       }
+       genastore ("data", curi->dmode, "dstreg", curi->size, "data");
+       break;
+
+     case i_ROXL:
+       failure;
+       break;
+     case i_ROXR:
+       failure;
+       break;
+     case i_ASRW:
+       failure;
+       break;
+     case i_ASLW:
+       failure;
+       break;
+     case i_LSRW:
+       failure;
+       break;
+     case i_LSLW:
+       failure;
+       break;
+     case i_ROLW:
+       failure;
+       break;
+     case i_RORW:
+       failure;
+       break;
+     case i_ROXLW:
+       failure;
+       break;
+     case i_ROXRW:
+       failure;
+       break;
+     case i_MOVEC2:
+       isjump; 
+       failure;
+       break;
+     case i_MOVE2C:
+       isjump; 
+       failure;
+       break;
+     case i_CAS:
+       failure;
+       break;
+     case i_CAS2:
+       failure;
+       break;
+     case i_MOVES:             /* ignore DFC and SFC because we have no MMU */
+       isjump; 
+       failure;
+       break;
+     case i_BKPT:              /* only needed for hardware emulators */
+       isjump; 
+       failure;
+       break;
+     case i_CALLM:             /* not present in 68030 */
+       isjump; 
+       failure;
+       break;
+     case i_RTM:               /* not present in 68030 */
+       isjump; 
+       failure;
+       break;
+     case i_TRAPcc:
+       isjump; 
+       failure;
+       break;
+     case i_DIVL:
+       isjump; 
+       failure;
+       break;
+     case i_MULL:
+       if (!noflags) {
+           failure;
+           break;
+       }
+       comprintf("\tuae_u16 extra=%s;\n",gen_nextiword());
+       comprintf("\tint r2=(extra>>12)&7;\n"
+                 "\tint tmp=scratchie++;\n");
+       
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0);
+       /* The two operands are in dst and r2 */
+       comprintf("\tif (extra&0x0400) {\n" /* Need full 64 bit result */
+                 "\tint r3=(extra&7);\n"
+                 "\tmov_l_rr(r3,dst);\n"); /* operands now in r3 and r2 */
+       comprintf("\tif (extra&0x0800) { \n" /* signed */
+                 "\t\timul_64_32(r2,r3);\n"
+                 "\t} else { \n"
+                 "\t\tmul_64_32(r2,r3);\n"
+                 "\t} \n");
+       /* The result is in r2/tmp, with r2 holding the lower 32 bits */
+       comprintf("\t} else {\n");  /* Only want 32 bit result */
+       /* operands in dst and r2, result foes into r2 */
+       /* shouldn't matter whether it's signed or unsigned?!? */
+       comprintf("\timul_32_32(r2,dst);\n"
+                 "\t}\n");
+       break;
+
+     case i_BFTST:
+     case i_BFEXTU:
+     case i_BFCHG:
+     case i_BFEXTS:
+     case i_BFCLR:
+     case i_BFFFO:
+     case i_BFSET:
+     case i_BFINS:
+       failure;
+       break;
+     case i_PACK:
+       failure;
+       break;
+     case i_UNPK:
+       failure;
+       break;
+     case i_TAS:
+       failure;
+       break;
+     case i_FPP:
+       mayfail;
+       comprintf("\tuae_u16 extra=%s;\n",gen_nextiword());
+       comprintf("\tcomp_fpp_opp(opcode,extra);\n");
+       break;
+     case i_FBcc:
+       isjump;
+       uses_cmov;
+       mayfail;
+       comprintf("\tcomp_fbcc_opp(opcode);\n");
+       break;
+     case i_FDBcc:
+       isjump; 
+       failure;
+       break;
+     case i_FScc:
+       mayfail;
+       uses_cmov;
+       comprintf("\tuae_u16 extra=%s;\n",gen_nextiword());
+       comprintf("\tcomp_fscc_opp(opcode,extra);\n");
+       break;
+     case i_FTRAPcc:
+       isjump; 
+       failure;
+       break;
+     case i_FSAVE:
+       failure;
+       break;
+     case i_FRESTORE:
+       failure;
+       break;
+
+     case i_CINVL:
+     case i_CINVP:
+     case i_CINVA:
+       isjump;  /* Not really, but it's probably a good idea to stop 
+                   translating at this point */
+       failure;
+       comprintf ("\tflush_icache();\n");  /* Differentiate a bit more? */
+       break;
+     case i_CPUSHL:
+     case i_CPUSHP:
+     case i_CPUSHA:
+       isjump;  /* Not really, but it's probably a good idea to stop 
+                   translating at this point */
+       failure;
+       break;
+     case i_MOVE16:
+       //if ((opcode & 0xfff8) == 0xf620) {
+           genmov16(opcode,curi);
+       //} else {
+       //    isjump;
+       //    failure;
+       //}
+       break;
+
+     case i_MMUOP:
+       isjump; 
+       failure;
+       break;
+     default:
+       abort ();
+       break;
+    }
+    comprintf("%s",endstr);
+    finish_braces ();
+    sync_m68k_pc ();
+    if (global_mayfail)
+       comprintf("\tif (failure)  m68k_pc_offset=m68k_pc_offset_thisinst;\n");
+    return global_failure;
+}
+
+static void 
+generate_includes (FILE * f)
+{
+    fprintf (f, "#include \"sysconfig.h\"\n");
+    fprintf (f, "#include \"sysdeps.h\"\n");
+    fprintf (f, "#include \"config.h\"\n");
+    fprintf (f, "#include \"options.h\"\n");
+    fprintf (f, "#include \"memory.h\"\n");
+    fprintf (f, "#include \"custom.h\"\n");
+    fprintf (f, "#include \"events.h\"\n");
+    fprintf (f, "#include \"newcpu.h\"\n");
+    fprintf (f, "#include \"compiler.h\"\n");
+    fprintf (f, "#include \"comptbl.h\"\n");
+}
+
+static int postfix;
+
+static void 
+generate_one_opcode (int rp, int noflags)
+{
+    int i;
+    uae_u16 smsk, dmsk;
+    long int opcode = opcode_map[rp];
+    int aborted=0;
+    int have_srcreg=0;
+    int have_dstreg=0;
+
+    if (table68k[opcode].mnemo == i_ILLG
+       || table68k[opcode].clev > cpu_level)
+       return;
+
+    for (i = 0; lookuptab[i].name[0]; i++)
+    {
+       if (table68k[opcode].mnemo == lookuptab[i].mnemo)
+           break;
+    }
+
+    if (table68k[opcode].handler != -1)
+       return;
+
+    switch (table68k[opcode].stype)
+    {
+    case 0: smsk = 7; break;
+    case 1: smsk = 255; break;
+    case 2: smsk = 15; break;
+    case 3: smsk = 7; break;
+    case 4: smsk = 7; break;
+    case 5: smsk = 63; break;
+    case 7: smsk = 3; break;
+    default: abort ();
+    }
+    dmsk = 7;
+
+    next_cpu_level = -1;
+    if (table68k[opcode].suse
+       && table68k[opcode].smode != imm && table68k[opcode].smode != imm0
+       && table68k[opcode].smode != imm1 && table68k[opcode].smode != imm2
+       && table68k[opcode].smode != absw && table68k[opcode].smode != absl
+       && table68k[opcode].smode != PC8r && table68k[opcode].smode != PC16)
+    {
+       have_srcreg=1;
+       if (table68k[opcode].spos == -1)
+       {
+           if (((int) table68k[opcode].sreg) >= 128)
+               comprintf ("\tuae_s32 srcreg = (uae_s32)(uae_s8)%d;\n", (int) table68k[opcode].sreg);
+           else
+               comprintf ("\tuae_s32 srcreg = %d;\n", (int) table68k[opcode].sreg);
+       }
+       else
+       {
+           char source[100];
+           int pos = table68k[opcode].spos;
+         
+           if (pos)
+               sprintf (source, "((opcode >> %d) & %d)", pos, smsk);
+           else
+               sprintf (source, "(opcode & %d)", smsk);
+
+           if (table68k[opcode].stype == 3)
+               comprintf ("\tuae_s32 srcreg = imm8_table[%s];\n", source);
+           else if (table68k[opcode].stype == 1)
+               comprintf ("\tuae_s32 srcreg = (uae_s32)(uae_s8)%s;\n", source);
+           else
+               comprintf ("\tuae_s32 srcreg = %s;\n", source);
+       }
+    }
+    if (table68k[opcode].duse
+       /* Yes, the dmode can be imm, in case of LINK or DBcc */
+       && table68k[opcode].dmode != imm && table68k[opcode].dmode != imm0
+       && table68k[opcode].dmode != imm1 && table68k[opcode].dmode != imm2
+       && table68k[opcode].dmode != absw && table68k[opcode].dmode != absl)
+    {
+       have_dstreg=1;
+       if (table68k[opcode].dpos == -1)
+       {
+           if (((int) table68k[opcode].dreg) >= 128)
+               comprintf ("\tuae_s32 dstreg = (uae_s32)(uae_s8)%d;\n", (int) table68k[opcode].dreg);
+           else
+               comprintf ("\tuae_s32 dstreg = %d;\n", (int) table68k[opcode].dreg);
+       }
+       else
+       {
+           int pos = table68k[opcode].dpos;
+         
+           if (pos)
+               comprintf ("\tuae_u32 dstreg = (opcode >> %d) & %d;\n",
+                          pos, dmsk);
+           else
+               comprintf ("\tuae_u32 dstreg = opcode & %d;\n", dmsk);
+       }
+    }
+
+    if (have_srcreg && have_dstreg &&
+       (table68k[opcode].dmode==Areg || 
+        table68k[opcode].dmode==Aind || 
+        table68k[opcode].dmode==Aipi || 
+        table68k[opcode].dmode==Apdi || 
+        table68k[opcode].dmode==Ad16 || 
+        table68k[opcode].dmode==Ad8r) &&
+       (table68k[opcode].smode==Areg || 
+        table68k[opcode].smode==Aind || 
+        table68k[opcode].smode==Aipi || 
+        table68k[opcode].smode==Apdi || 
+        table68k[opcode].smode==Ad16 || 
+        table68k[opcode].smode==Ad8r) 
+       ) {
+       comprintf("\tuae_u32 dodgy=(srcreg==(uae_s32)dstreg);\n");
+    }
+    else {
+       comprintf("\tuae_u32 dodgy=0;\n");
+    }
+    comprintf("\tuae_u32 m68k_pc_offset_thisinst=m68k_pc_offset;\n");
+    comprintf("\tm68k_pc_offset+=2;\n");
+
+    aborted=gen_opcode (opcode);
+    {
+       int flags=0;
+       if (global_isjump) flags|=1;
+       if (long_opcode)   flags|=2;
+       if (global_cmov)   flags|=4;
+       if (global_isaddx) flags|=8;
+       if (global_iscjump) flags|=16;
+       comprintf ("return 0;\n");
+       comprintf ("}\n");
+    
+       if (aborted) {
+           fprintf (stblfile, "{ NULL, 0x%08x, %ld }, /* %s */\n", flags, opcode, lookuptab[i].name);
+           com_discard();
+       }
+       else {
+           if (noflags) {
+               fprintf (stblfile, "{ op_%lx_%d_comp_nf, 0x%08x, %ld }, /* %s */\n", opcode, postfix, flags, opcode, lookuptab[i].name);
+               fprintf (headerfile, "extern cpuop_func op_%lx_%d_comp_nf;\n", opcode, postfix);
+               printf ("unsigned long REGPARAM2 op_%lx_%d_comp_nf(uae_u32 opcode) /* %s */\n{\n", opcode, postfix, lookuptab[i].name);
+           }
+           else {
+               fprintf (stblfile, "{ op_%lx_%d_comp_ff, 0x%08x, %ld }, /* %s */\n", opcode, postfix, flags, opcode, lookuptab[i].name);
+               fprintf (headerfile, "extern cpuop_func op_%lx_%d_comp_ff;\n", opcode, postfix);
+               printf ("unsigned long REGPARAM2 op_%lx_%d_comp_ff(uae_u32 opcode) /* %s */\n{\n", opcode, postfix, lookuptab[i].name);
+           }
+           com_flush();
+       }
+    }
+    opcode_next_clev[rp] = next_cpu_level;
+    opcode_last_postfix[rp] = postfix;
+}
+
+static void 
+generate_func (int noflags)
+{
+    int i, j, rp;
+
+    using_prefetch = 0;
+    using_exception_3 = 0;
+    for (i = 0; i < 1; i++) /* We only do one level! */
+    {
+       cpu_level = 4 - i;
+       postfix = i;
+
+       if (noflags)
+           fprintf (stblfile, "struct cputbl op_smalltbl_%d_comp_nf[] = {\n", postfix);
+       else
+           fprintf (stblfile, "struct cputbl op_smalltbl_%d_comp_ff[] = {\n", postfix);
+
+
+       /* sam: this is for people with low memory (eg. me :)) */
+       !printf ("\n"
+                "#if !defined(PART_1) && !defined(PART_2) && "
+                "!defined(PART_3) && !defined(PART_4) && "
+                "!defined(PART_5) && !defined(PART_6) && "
+                "!defined(PART_7) && !defined(PART_8)"
+                "\n"
+                "#define PART_1 1\n"
+                "#define PART_2 1\n"
+                "#define PART_3 1\n"
+                "#define PART_4 1\n"
+                "#define PART_5 1\n"
+                "#define PART_6 1\n"
+                "#define PART_7 1\n"
+                "#define PART_8 1\n"
+                "#endif\n\n");
+
+       rp = 0;
+       for (j = 1; j <= 8; ++j)
+       {
+           int k = (j * nr_cpuop_funcs) / 8;
+           printf ("#ifdef PART_%d\n", j);
+           for (; rp < k; rp++)
+               generate_one_opcode (rp,noflags);
+           printf ("#endif\n\n");
+       }
+
+       fprintf (stblfile, "{ 0, 0,65536 }};\n");
+    }
+
+}
+
+int 
+main (int argc, char **argv)
+{
+    read_table68k ();
+    do_merges ();
+
+    opcode_map = (int *) xmalloc (sizeof (int) * nr_cpuop_funcs);
+    opcode_last_postfix = (int *) xmalloc (sizeof (int) * nr_cpuop_funcs);
+    opcode_next_clev = (int *) xmalloc (sizeof (int) * nr_cpuop_funcs);
+    counts = (unsigned long *) xmalloc (65536 * sizeof (unsigned long));
+    read_counts ();
+
+    /* It would be a lot nicer to put all in one file (we'd also get rid of
+     * cputbl.h that way), but cpuopti can't cope.  That could be fixed, but
+     * I don't dare to touch the 68k version.  */
+
+    headerfile = fopen ("comptbl.h", "wb");
+    stblfile = fopen ("compstbl.c", "wb");
+    freopen ("compemu.c", "wb", stdout);
+
+    generate_includes (stdout);
+    generate_includes (stblfile);
+
+    printf("#include \"compemu.h\"\n");
+
+    noflags=0;
+    generate_func (noflags);
+
+
+    opcode_map = (int *) xmalloc (sizeof (int) * nr_cpuop_funcs);
+    opcode_last_postfix = (int *) xmalloc (sizeof (int) * nr_cpuop_funcs);
+    opcode_next_clev = (int *) xmalloc (sizeof (int) * nr_cpuop_funcs);
+    counts = (unsigned long *) xmalloc (65536 * sizeof (unsigned long));
+    read_counts ();
+    noflags=1;
+    generate_func (noflags);
+
+    free (table68k);
+    return 0;
+}
diff --git a/gencpu.c b/gencpu.c
new file mode 100755 (executable)
index 0000000..81f597d
--- /dev/null
+++ b/gencpu.c
@@ -0,0 +1,3147 @@
+/*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * MC68000 emulation generator
+ *
+ * This is a fairly stupid program that generates a lot of case labels that
+ * can be #included in a switch statement.
+ * As an alternative, it can generate functions that handle specific
+ * MC68000 instructions, plus a prototype header file and a function pointer
+ * array to look up the function for an opcode.
+ * Error checking is bad, an illegal table68k file will cause the program to
+ * call abort().
+ * The generated code is sometimes sub-optimal, an optimizing compiler should
+ * take care of this.
+ *
+ * The source for the insn timings is Markt & Technik's Amiga Magazin 8/1992.
+ *
+ * Copyright 1995, 1996, 1997, 1998, 1999, 2000 Bernd Schmidt
+ */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+#include <ctype.h>
+
+#include "readcpu.h"
+
+#define BOOL_TYPE "int"
+
+static FILE *headerfile;
+static FILE *stblfile;
+
+static int using_prefetch;
+static int using_exception_3;
+static int using_ce;
+static int cpu_level;
+
+#define GF_APDI 1
+#define GF_AD8R 2
+#define GF_PC8R 4
+#define GF_AA 7
+#define GF_NOREFILL 8
+#define GF_PREFETCH 16
+
+
+/* For the current opcode, the next lower level that will have different code.
+ * Initialized to -1 for each opcode. If it remains unchanged, indicates we
+ * are done with that opcode.  */
+static int next_cpu_level;
+
+static int *opcode_map;
+static int *opcode_next_clev;
+static int *opcode_last_postfix;
+static unsigned long *counts;
+
+static void read_counts (void)
+{
+    FILE *file;
+    unsigned long opcode, count, total;
+    char name[20];
+    int nr = 0;
+    memset (counts, 0, 65536 * sizeof *counts);
+
+       count = 0;
+    file = fopen ("frequent.68k", "r");
+    if (file) {
+       fscanf (file, "Total: %lu\n", &total);
+       while (fscanf (file, "%lx: %lu %s\n", &opcode, &count, name) == 3) {
+           opcode_next_clev[nr] = 4;
+           opcode_last_postfix[nr] = -1;
+           opcode_map[nr++] = opcode;
+           counts[opcode] = count;
+       }
+       fclose (file);
+    }
+    if (nr == nr_cpuop_funcs)
+       return;
+    for (opcode = 0; opcode < 0x10000; opcode++) {
+       if (table68k[opcode].handler == -1 && table68k[opcode].mnemo != i_ILLG
+           && counts[opcode] == 0)
+       {
+           opcode_next_clev[nr] = 4;
+           opcode_last_postfix[nr] = -1;
+           opcode_map[nr++] = opcode;
+           counts[opcode] = count;
+       }
+    }
+    if (nr != nr_cpuop_funcs)
+       abort ();
+}
+
+static char endlabelstr[80];
+static int endlabelno = 0;
+static int need_endlabel;
+
+static int n_braces = 0, limit_braces;
+static int m68k_pc_offset = 0;
+static int insn_n_cycles;
+
+static void fpulimit (void)
+{
+    if (limit_braces)
+       return;
+    printf ("\n#ifdef FPUEMU\n");
+    limit_braces = n_braces;
+    n_braces = 0;
+}
+static void cpulimit (void)
+{
+    if (limit_braces)
+       return;
+    printf ("\n#ifndef CPUEMU_68000_ONLY\n");
+    limit_braces = n_braces;
+    n_braces = 0;
+}
+
+static void returncycles (char *s, int cycles)
+{
+    if (using_ce) return;
+    printf ("%sreturn %d * %d;\n", s, cycles, CYCLE_UNIT / 2);
+}
+static void addcycles (int cycles)
+{
+    if (!using_ce) return;
+    printf ("\tdo_cycles_ce (%d * %d);\n", cycles, CYCLE_UNIT / 2);
+}
+static void addcycles2 (char *s, int cycles)
+{
+    if (!using_ce) return;
+    printf ("%sdo_cycles_ce (%d * %d);\n", s, cycles, CYCLE_UNIT / 2);
+}
+static void addcycles3 (char *s)
+{
+    if (!using_ce) return;
+    printf ("%sif (cycles > 0) do_cycles_ce (cycles);\n", s);
+}
+
+static int isreg(amodes mode)
+{
+    if (mode == Dreg || mode == Areg)
+       return 1;
+    return 0;
+}
+
+static void start_brace (void)
+{
+    n_braces++;
+    printf ("{");
+}
+
+static void close_brace (void)
+{
+    assert (n_braces > 0);
+    n_braces--;
+    printf ("}");
+}
+
+static void finish_braces (void)
+{
+    while (n_braces > 0)
+       close_brace ();
+}
+
+static void pop_braces (int to)
+{
+    while (n_braces > to)
+       close_brace ();
+}
+
+static int bit_size (int size)
+{
+    switch (size) {
+     case sz_byte: return 8;
+     case sz_word: return 16;
+     case sz_long: return 32;
+     default: abort ();
+    }
+    return 0;
+}
+
+static const char *bit_mask (int size)
+{
+    switch (size) {
+     case sz_byte: return "0xff";
+     case sz_word: return "0xffff";
+     case sz_long: return "0xffffffff";
+     default: abort ();
+    }
+    return 0;
+}
+
+static void gen_nextilong (char *type, char *name, int norefill)
+{
+    int r = m68k_pc_offset;
+    m68k_pc_offset += 4;
+
+    if (using_ce) {
+        printf ("\t%s %s;\n", type, name);
+       /* we must do this because execution order of (something | something2) is not defined */
+       if (norefill) {
+           printf ("\t%s = get_word_ce_prefetch (%d) << 16;\n", name, r + 2);
+           printf ("\t%s |= regs.irc;\n", name);
+       } else {
+           printf ("\t%s = get_word_ce_prefetch (%d) << 16;\n", name, r + 2);
+           printf ("\t%s |= get_word_ce_prefetch (%d);\n", name, r + 4);
+       }
+    } else {
+        if (using_prefetch) {
+           if (norefill) {
+               printf ("\t%s %s;\n", type, name);
+               printf ("\t%s = get_word_prefetch (%d) << 16;\n", name, r + 2);
+               printf ("\t%s |= regs.irc;\n", name);
+               insn_n_cycles += 4;
+           } else
+               printf ("\t%s %s = get_long_prefetch (%d);\n", type, name, r + 2);
+               insn_n_cycles += 8;
+       } else {
+           insn_n_cycles += 8;
+           printf ("\t%s %s = get_ilong (%d);\n", type, name, r);
+       }
+    }
+}
+
+static const char *gen_nextiword (int norefill)
+{
+    static char buffer[80];
+    int r = m68k_pc_offset;
+    m68k_pc_offset += 2;
+
+    if (using_ce) {
+       if (norefill)
+           strcpy (buffer, "regs.irc");
+       else
+           sprintf (buffer, "get_word_ce_prefetch (%d)", r + 2);
+    } else {
+       if (using_prefetch) {
+           if (norefill) {
+               sprintf (buffer, "regs.irc", r);
+           } else {
+               sprintf (buffer, "get_word_prefetch (%d)", r + 2);
+               insn_n_cycles += 4;
+           }
+       } else {
+           sprintf (buffer, "get_iword (%d)", r);
+            insn_n_cycles += 4;
+       }
+    }
+    return buffer;
+}
+
+static const char *gen_nextibyte (int norefill)
+{
+    static char buffer[80];
+    int r = m68k_pc_offset;
+    m68k_pc_offset += 2;
+
+    if (using_ce) {
+       if (norefill)
+           strcpy (buffer, "(uae_u8)regs.irc");
+       else
+           sprintf (buffer, "(uae_u8)get_word_ce_prefetch (%d)", r + 2);
+    } else {
+        insn_n_cycles += 4;
+       if (using_prefetch) {
+           if (norefill) {
+               sprintf (buffer, "(uae_u8)regs.irc", r);
+           } else {
+               sprintf (buffer, "(uae_u8)get_word_prefetch (%d)", r + 2);
+               insn_n_cycles += 4;
+           }
+       } else {
+           sprintf (buffer, "get_ibyte (%d)", r);
+            insn_n_cycles += 4;
+       }
+    }
+    return buffer;
+}
+
+static void irc2ir (void)
+{
+    if (!using_prefetch)
+       return;
+    printf ("\tregs.ir = regs.irc;\n");
+}
+
+static int did_prefetch;
+
+static void fill_prefetch_2 (void)
+{
+    if (!using_prefetch)
+       return;
+    if (using_ce)
+       printf ("\tget_word_ce_prefetch (%d);\n", m68k_pc_offset + 2);
+    else
+       printf ("\tget_word_prefetch (%d);\n", m68k_pc_offset + 2);
+    did_prefetch = 1;
+    insn_n_cycles += 4;
+}
+
+static void fill_prefetch_1 (int o, int needcycles)
+{
+    if (!using_prefetch)
+       return;
+    if (using_ce) {
+       if (needcycles) {
+           printf ("\tlostcycles = get_word_ce_prefetch_cycles (%d);\n", o);
+       } else {
+           printf ("\tget_word_ce_prefetch (%d);\n", o);
+       }
+    } else {
+       printf ("\tget_word_prefetch (%d);\n", o);
+    }
+    did_prefetch = 1;
+    insn_n_cycles += 4;
+}
+
+static void fill_prefetch_full (void)
+{
+    fill_prefetch_1 (0, 0);
+    irc2ir ();
+    fill_prefetch_1 (2, 0);
+}
+
+static void fill_prefetch_0 (void)
+{
+    if (!using_prefetch)
+       return;
+    if (using_ce)
+       printf ("\tget_word_ce_prefetch (0);\n");
+    else
+       printf ("\tget_word_prefetch (0);\n");
+    did_prefetch = 1;
+    insn_n_cycles += 4;
+} 
+
+static void fill_prefetch_next_1 (needcycles)
+{
+    if (needcycles && using_ce) {
+       printf ("\tint lostcycles;\n");
+    }
+    irc2ir ();
+    fill_prefetch_1 (m68k_pc_offset + 2, needcycles);
+} 
+
+static void fill_prefetch_next (void)
+{
+    fill_prefetch_next_1 (0);
+}
+static void fill_prefetch_next_cycles (void)
+{
+    fill_prefetch_next_1 (1);
+}
+
+static void fill_prefetch_next_delay (int extracycles)
+{
+    if (!using_prefetch)
+       return;
+    if (using_ce) {
+       if (extracycles > 0) {
+           printf("\t{\n");
+           fill_prefetch_next_cycles ();
+           printf("\tif (%d * %d > lostcycles) do_cycles_ce (%d * %d - lostcycles);\n",
+               extracycles, CYCLE_UNIT / 2, extracycles, CYCLE_UNIT / 2);
+           printf("\t}\n");
+       } else {
+           fill_prefetch_next ();
+       }
+    } else {
+       fill_prefetch_next ();
+    }
+}
+
+static void fill_prefetch_finish (void)
+{
+    if (did_prefetch || !using_prefetch)
+       return;
+    fill_prefetch_1 (m68k_pc_offset, 0);
+}
+
+static void sync_m68k_pc (void)
+{
+    if (m68k_pc_offset == 0)
+       return;
+    printf ("\tm68k_incpc (%d);\n", m68k_pc_offset);
+    m68k_pc_offset = 0;
+}
+
+/* getv == 1: fetch data; getv != 0: check for odd address. If movem != 0,
+ * the calling routine handles Apdi and Aipi modes.
+ * gb-- movem == 2 means the same thing but for a MOVE16 instruction */
+static void genamode (amodes mode, char *reg, wordsizes size, char *name, int getv, int movem, int flags)
+{
+    char namea[100];
+    int m68k_pc_offset_last = m68k_pc_offset;
+    
+    sprintf (namea, "%sa", name);
+
+    start_brace ();
+    switch (mode) {
+    case Dreg:
+       if (movem)
+           abort ();
+       if (getv == 1)
+           switch (size) {
+           case sz_byte:
+#if defined(AMIGA) && !defined(WARPUP)
+               /* sam: I don't know why gcc.2.7.2.1 produces a code worse */
+               /* if it is not done like that: */
+               printf ("\tuae_s8 %s = ((uae_u8*)&m68k_dreg(regs, %s))[3];\n", name, reg);
+#else
+               printf ("\tuae_s8 %s = m68k_dreg(regs, %s);\n", name, reg);
+#endif
+               break;
+           case sz_word:
+#if defined(AMIGA) && !defined(WARPUP)
+               printf ("\tuae_s16 %s = ((uae_s16*)&m68k_dreg(regs, %s))[1];\n", name, reg);
+#else
+               printf ("\tuae_s16 %s = m68k_dreg(regs, %s);\n", name, reg);
+#endif
+               break;
+           case sz_long:
+               printf ("\tuae_s32 %s = m68k_dreg(regs, %s);\n", name, reg);
+               break;
+           default:
+               abort ();
+           }
+       return;
+    case Areg:
+       if (movem)
+           abort ();
+       if (getv == 1)
+           switch (size) {
+           case sz_word:
+               printf ("\tuae_s16 %s = m68k_areg(regs, %s);\n", name, reg);
+               break;
+           case sz_long:
+               printf ("\tuae_s32 %s = m68k_areg(regs, %s);\n", name, reg);
+               break;
+           default:
+               abort ();
+           }
+       return;
+    case Aind:
+       printf ("\tuaecptr %sa = m68k_areg(regs, %s);\n", name, reg);
+       break;
+    case Aipi:
+       printf ("\tuaecptr %sa = m68k_areg(regs, %s);\n", name, reg);
+       break;
+    case Apdi:
+       printf ("\tuaecptr %sa;\n", name);
+       switch (size) {
+       case sz_byte:
+           if (movem)
+               printf ("\t%sa = m68k_areg(regs, %s);\n", name, reg);
+           else
+               printf ("\t%sa = m68k_areg(regs, %s) - areg_byteinc[%s];\n", name, reg, reg);
+           break;
+       case sz_word:
+           printf ("\t%sa = m68k_areg(regs, %s) - %d;\n", name, reg, movem ? 0 : 2);
+           break;
+       case sz_long:
+           printf ("\t%sa = m68k_areg(regs, %s) - %d;\n", name, reg, movem ? 0 : 4);
+           break;
+       default:
+           abort ();
+       }
+       if (!(flags & GF_APDI)) {
+           addcycles (2);
+           insn_n_cycles += 2;
+       }
+       break;
+    case Ad16:
+       printf ("\tuaecptr %sa = m68k_areg(regs, %s) + (uae_s32)(uae_s16)%s;\n", name, reg, gen_nextiword (flags & GF_NOREFILL));
+       break;
+    case Ad8r:
+       printf ("\tuaecptr %sa;\n", name);
+       if (cpu_level > 1) {
+           if (next_cpu_level < 1)
+               next_cpu_level = 1;
+           sync_m68k_pc ();
+           start_brace ();
+           /* This would ordinarily be done in gen_nextiword, which we bypass.  */
+           insn_n_cycles += 4;
+           printf ("\t%sa = get_disp_ea_020(m68k_areg(regs, %s), next_iword());\n", name, reg);
+       } else
+           printf ("\t%sa = get_disp_ea_000(m68k_areg(regs, %s), %s);\n", name, reg, gen_nextiword (flags & GF_NOREFILL));
+       if (!(flags & GF_AD8R)) {
+           addcycles (2);
+           insn_n_cycles += 2;
+       }
+       break;
+    case PC16:
+       printf ("\tuaecptr %sa = m68k_getpc () + %d;\n", name, m68k_pc_offset);
+       printf ("\t%sa += (uae_s32)(uae_s16)%s;\n", name, gen_nextiword (flags & GF_NOREFILL));
+       break;
+    case PC8r:
+       printf ("\tuaecptr tmppc;\n");
+       printf ("\tuaecptr %sa;\n", name);
+       if (cpu_level > 1) {
+           if (next_cpu_level < 1)
+               next_cpu_level = 1;
+           sync_m68k_pc ();
+           start_brace ();
+           /* This would ordinarily be done in gen_nextiword, which we bypass.  */
+           insn_n_cycles += 4;
+           printf ("\ttmppc = m68k_getpc();\n");
+           printf ("\t%sa = get_disp_ea_020(tmppc, next_iword());\n", name);
+       } else {
+           printf ("\ttmppc = m68k_getpc() + %d;\n", m68k_pc_offset);
+           printf ("\t%sa = get_disp_ea_000(tmppc, %s);\n", name, gen_nextiword (flags & GF_NOREFILL));
+       }
+       if (!(flags & GF_PC8R)) {
+           addcycles (2);
+           insn_n_cycles += 2;
+       }
+
+       break;
+    case absw:
+       printf ("\tuaecptr %sa = (uae_s32)(uae_s16)%s;\n", name, gen_nextiword (flags & GF_NOREFILL));
+       break;
+    case absl:
+       gen_nextilong ("uaecptr", namea, flags & GF_NOREFILL);
+       break;
+    case imm:
+       if (getv != 1)
+           abort ();
+       switch (size) {
+       case sz_byte:
+           printf ("\tuae_s8 %s = %s;\n", name, gen_nextibyte (flags & GF_NOREFILL));
+           break;
+       case sz_word:
+           printf ("\tuae_s16 %s = %s;\n", name, gen_nextiword (flags & GF_NOREFILL));
+           break;
+       case sz_long:
+           gen_nextilong ("uae_s32", name, flags & GF_NOREFILL);
+           break;
+       default:
+           abort ();
+       }
+       return;
+    case imm0:
+       if (getv != 1)
+           abort ();
+       printf ("\tuae_s8 %s = %s;\n", name, gen_nextibyte (flags & GF_NOREFILL));
+       return;
+    case imm1:
+       if (getv != 1)
+           abort ();
+       printf ("\tuae_s16 %s = %s;\n", name, gen_nextiword (flags & GF_NOREFILL));
+       return;
+    case imm2:
+       if (getv != 1)
+           abort ();
+       gen_nextilong ("uae_s32", name, flags & GF_NOREFILL);
+       return;
+    case immi:
+       if (getv != 1)
+           abort ();
+       printf ("\tuae_u32 %s = %s;\n", name, reg);
+       return;
+    default:
+       abort ();
+    }
+
+    /* We get here for all non-reg non-immediate addressing modes to
+     * actually fetch the value. */
+
+    if ((using_prefetch || using_ce) && using_exception_3 && getv != 0 && size != sz_byte) {       
+       printf ("\tif (%sa & 1) {\n", name);
+       printf ("\t\texception3 (opcode, m68k_getpc() + %d, %sa);\n", m68k_pc_offset_last, name); 
+       printf ("\t\tgoto %s;\n", endlabelstr);
+       printf ("\t}\n");
+       need_endlabel = 1;
+       start_brace ();
+    }
+
+    if (flags & GF_PREFETCH)
+       fill_prefetch_next ();
+
+    if (getv == 1) {
+       start_brace ();
+       if (using_ce) {
+           switch (size) {
+           case sz_byte: printf ("\tuae_s8 %s = get_byte_ce (%sa);\n", name, name); break;
+           case sz_word: printf ("\tuae_s16 %s = get_word_ce (%sa);\n", name, name); break;
+           case sz_long: printf ("\tuae_s32 %s = get_word_ce (%sa) << 16; %s |= get_word_ce (%sa + 2);\n", name, name, name, name); break;
+           default: abort ();
+           }
+       } else {
+           switch (size) {
+           case sz_byte: insn_n_cycles += 4; printf ("\tuae_s8 %s = get_byte (%sa);\n", name, name); break;
+           case sz_word: insn_n_cycles += 4; printf ("\tuae_s16 %s = get_word (%sa);\n", name, name); break;
+           case sz_long: insn_n_cycles += 8; printf ("\tuae_s32 %s = get_long (%sa);\n", name, name); break;
+           default: abort ();
+           }
+       }
+    }
+
+    /* We now might have to fix up the register for pre-dec or post-inc
+     * addressing modes. */
+    if (!movem)
+       switch (mode) {
+       case Aipi:
+           switch (size) {
+           case sz_byte:
+               printf ("\tm68k_areg(regs, %s) += areg_byteinc[%s];\n", reg, reg);
+               break;
+           case sz_word:
+               printf ("\tm68k_areg(regs, %s) += 2;\n", reg);
+               break;
+           case sz_long:
+               printf ("\tm68k_areg(regs, %s) += 4;\n", reg);
+               break;
+           default:
+               abort ();
+           }
+           break;
+       case Apdi:
+           printf ("\tm68k_areg (regs, %s) = %sa;\n", reg, name);
+           break;
+       default:
+           break;
+       }
+}
+
+static void genastore (char *from, amodes mode, char *reg, wordsizes size, char *to)
+{
+    switch (mode) {
+     case Dreg:
+       switch (size) {
+        case sz_byte:
+           printf ("\tm68k_dreg(regs, %s) = (m68k_dreg(regs, %s) & ~0xff) | ((%s) & 0xff);\n", reg, reg, from);
+           break;
+        case sz_word:
+           printf ("\tm68k_dreg(regs, %s) = (m68k_dreg(regs, %s) & ~0xffff) | ((%s) & 0xffff);\n", reg, reg, from);
+           break;
+        case sz_long:
+           printf ("\tm68k_dreg(regs, %s) = (%s);\n", reg, from);
+           break;
+        default:
+           abort ();
+       }
+       break;
+     case Areg:
+       switch (size) {
+        case sz_word:
+           write_log ("Foo\n");
+           printf ("\tm68k_areg(regs, %s) = (uae_s32)(uae_s16)(%s);\n", reg, from);
+           break;
+        case sz_long:
+           printf ("\tm68k_areg(regs, %s) = (%s);\n", reg, from);
+           break;
+        default:
+           abort ();
+       }
+       break;
+     case Aind:
+     case Aipi:
+     case Apdi:
+     case Ad16:
+     case Ad8r:
+     case absw:
+     case absl:
+     case PC16:
+     case PC8r:
+       if (using_ce) {
+           switch (size) {
+            case sz_byte:
+               printf ("\tput_byte_ce (%sa,%s);\n", to, from);
+               break;
+            case sz_word:
+               if (cpu_level < 2 && (mode == PC16 || mode == PC8r))
+                   abort ();
+               printf ("\tput_word_ce (%sa,%s);\n", to, from);
+               break;
+            case sz_long:
+               if (cpu_level < 2 && (mode == PC16 || mode == PC8r))
+                   abort ();
+               printf ("\tput_word_ce (%sa, %s >> 16); put_word_ce (%sa + 2, %s);\n", to, from, to, from);
+               //printf ("\tput_word_ce (%sa + 2, %s); put_word_ce (%sa, %s >> 16);\n", to, from, to, from);
+               break;
+            default:
+               abort ();
+           }
+       } else {
+           switch (size) {
+            case sz_byte:
+               insn_n_cycles += 4;
+               printf ("\tput_byte (%sa,%s);\n", to, from);
+               break;
+            case sz_word:
+               insn_n_cycles += 4;
+               if (cpu_level < 2 && (mode == PC16 || mode == PC8r))
+                   abort ();
+               printf ("\tput_word (%sa,%s);\n", to, from);
+               break;
+            case sz_long:
+               insn_n_cycles += 8;
+               if (cpu_level < 2 && (mode == PC16 || mode == PC8r))
+                   abort ();
+               printf ("\tput_long (%sa,%s);\n", to, from);
+               break;
+            default:
+               abort ();
+           }
+       }
+       break;
+     case imm:
+     case imm0:
+     case imm1:
+     case imm2:
+     case immi:
+       abort ();
+       break;
+     default:
+       abort ();
+    }
+}
+
+static void genmovemel (uae_u16 opcode)
+{
+    char getcode[100];
+    int size = table68k[opcode].size == sz_long ? 4 : 2;
+
+    if (table68k[opcode].size == sz_long) {
+       strcpy (getcode, "get_long(srca)");
+    } else {
+       strcpy (getcode, "(uae_s32)(uae_s16)get_word(srca)");
+    }
+
+    printf ("\tuae_u16 mask = %s;\n", gen_nextiword (0));
+    printf ("\tunsigned int dmask = mask & 0xff, amask = (mask >> 8) & 0xff;\n");
+    genamode (table68k[opcode].dmode, "dstreg", table68k[opcode].size, "src", 2, 1, 0);
+    start_brace ();
+    printf ("\twhile (dmask) { m68k_dreg(regs, movem_index1[dmask]) = %s; srca += %d; dmask = movem_next[dmask]; }\n",
+           getcode, size);
+    printf ("\twhile (amask) { m68k_areg(regs, movem_index1[amask]) = %s; srca += %d; amask = movem_next[amask]; }\n",
+           getcode, size);
+
+    if (table68k[opcode].dmode == Aipi)
+       printf ("\tm68k_areg(regs, dstreg) = srca;\n");
+}
+
+static void genmovemel_ce (uae_u16 opcode)
+{
+    int size = table68k[opcode].size == sz_long ? 4 : 2;
+    printf ("\tuae_u16 mask = %s;\n", gen_nextiword (0));
+    printf ("\tunsigned int dmask = mask & 0xff, amask = (mask >> 8) & 0xff;\n");
+    printf ("\tuae_u32 v;\n");
+    genamode (table68k[opcode].dmode, "dstreg", table68k[opcode].size, "src", 2, 1, GF_AA);
+    if (table68k[opcode].dmode == Ad8r || table68k[opcode].dmode == PC8r)
+        addcycles (2);
+    start_brace ();
+    if (table68k[opcode].size == sz_long) {
+       printf ("\twhile (dmask) { v = get_word_ce(srca) << 16; v |= get_word_ce(srca + 2); m68k_dreg(regs, movem_index1[dmask]) = v; srca += %d; dmask = movem_next[dmask]; }\n",
+               size);
+       printf ("\twhile (amask) { v = get_word_ce(srca) << 16; v |= get_word_ce(srca + 2); m68k_areg(regs, movem_index1[amask]) = v; srca += %d; amask = movem_next[amask]; }\n",
+               size);
+    } else {
+       printf ("\twhile (dmask) { m68k_dreg(regs, movem_index1[dmask]) = (uae_s32)(uae_s16)get_word_ce(srca); srca += %d; dmask = movem_next[dmask]; }\n",
+               size);
+       printf ("\twhile (amask) { m68k_areg(regs, movem_index1[amask]) = (uae_s32)(uae_s16)get_word_ce(srca); srca += %d; amask = movem_next[amask]; }\n",
+               size);
+    }
+    printf ("\tget_word_ce (srca);\n");
+    if (table68k[opcode].dmode == Aipi)
+       printf ("\tm68k_areg(regs, dstreg) = srca;\n");
+}
+
+static void genmovemle (uae_u16 opcode)
+{
+    char putcode[100];
+    int size = table68k[opcode].size == sz_long ? 4 : 2;
+    if (table68k[opcode].size == sz_long) {
+       strcpy (putcode, "put_long(srca,");
+    } else {
+       strcpy (putcode, "put_word(srca,");
+    }
+
+    printf ("\tuae_u16 mask = %s;\n", gen_nextiword (0));
+    genamode (table68k[opcode].dmode, "dstreg", table68k[opcode].size, "src", 2, 1, 0);
+    if (using_prefetch)
+       sync_m68k_pc ();
+
+    start_brace ();
+    if (table68k[opcode].dmode == Apdi) {
+       printf ("\tuae_u16 amask = mask & 0xff, dmask = (mask >> 8) & 0xff;\n");
+       printf ("\twhile (amask) { srca -= %d; %s m68k_areg(regs, movem_index2[amask])); amask = movem_next[amask]; }\n",
+               size, putcode);
+       printf ("\twhile (dmask) { srca -= %d; %s m68k_dreg(regs, movem_index2[dmask])); dmask = movem_next[dmask]; }\n",
+               size, putcode);
+       printf ("\tm68k_areg(regs, dstreg) = srca;\n");
+    } else {
+       printf ("\tuae_u16 dmask = mask & 0xff, amask = (mask >> 8) & 0xff;\n");
+       printf ("\twhile (dmask) { %s m68k_dreg(regs, movem_index1[dmask])); srca += %d; dmask = movem_next[dmask]; }\n",
+               putcode, size);
+       printf ("\twhile (amask) { %s m68k_areg(regs, movem_index1[amask])); srca += %d; amask = movem_next[amask]; }\n",
+               putcode, size);
+    }
+}
+
+static void genmovemle_ce (uae_u16 opcode)
+{
+    int size = table68k[opcode].size == sz_long ? 4 : 2;
+    printf ("\tuae_u16 mask = %s;\n", gen_nextiword (0));
+    genamode (table68k[opcode].dmode, "dstreg", table68k[opcode].size, "src", 2, 1, GF_AA);
+
+    if (table68k[opcode].dmode == Ad8r || table68k[opcode].dmode == PC8r)
+        addcycles (2);
+    start_brace ();
+    if (table68k[opcode].size == sz_long) {
+       if (table68k[opcode].dmode == Apdi) {
+           printf ("\tuae_u16 amask = mask & 0xff, dmask = (mask >> 8) & 0xff;\n");
+           printf ("\twhile (amask) { srca -= %d; put_word_ce (srca, m68k_areg(regs, movem_index2[amask]) >> 16); put_word_ce (srca + 2, m68k_areg(regs, movem_index2[amask])); amask = movem_next[amask]; }\n",
+                   size);
+           printf ("\twhile (dmask) { srca -= %d; put_word_ce (srca, m68k_dreg(regs, movem_index2[dmask]) >> 16); put_word_ce (srca + 2, m68k_dreg(regs, movem_index2[dmask])); dmask = movem_next[dmask]; }\n",
+                   size);
+           printf ("\tm68k_areg(regs, dstreg) = srca;\n");
+       } else {
+           printf ("\tuae_u16 dmask = mask & 0xff, amask = (mask >> 8) & 0xff;\n");
+           printf ("\twhile (dmask) { put_word_ce (srca, m68k_dreg(regs, movem_index1[dmask]) >> 16); put_word_ce (srca + 2, m68k_dreg(regs, movem_index1[dmask])); srca += %d; dmask = movem_next[dmask]; }\n",
+                   size);
+           printf ("\twhile (amask) { put_word_ce (srca, m68k_areg(regs, movem_index1[amask]) >> 16); put_word_ce (srca + 2, m68k_areg(regs, movem_index1[amask])); srca += %d; amask = movem_next[amask]; }\n",
+                   size);
+       }
+    } else {
+       if (table68k[opcode].dmode == Apdi) {
+           printf ("\tuae_u16 amask = mask & 0xff, dmask = (mask >> 8) & 0xff;\n");
+           printf ("\twhile (amask) { srca -= %d; put_word_ce (srca, m68k_areg(regs, movem_index2[amask])); amask = movem_next[amask]; }\n",
+                   size);
+           printf ("\twhile (dmask) { srca -= %d; put_word_ce (srca, m68k_dreg(regs, movem_index2[dmask])); dmask = movem_next[dmask]; }\n",
+                   size);
+           printf ("\tm68k_areg(regs, dstreg) = srca;\n");
+       } else {
+           printf ("\tuae_u16 dmask = mask & 0xff, amask = (mask >> 8) & 0xff;\n");
+           printf ("\twhile (dmask) { put_word_ce (srca, m68k_dreg(regs, movem_index1[dmask])); srca += %d; dmask = movem_next[dmask]; }\n",
+                   size);
+           printf ("\twhile (amask) { put_word_ce (srca, m68k_areg(regs, movem_index1[amask])); srca += %d; amask = movem_next[amask]; }\n",
+                   size);
+       }
+    }
+}
+
+static void duplicate_carry (int n)
+{
+    int i;
+    for (i = 0; i <= n; i++)
+       printf ("\t");
+    printf ("COPY_CARRY;\n");
+}
+
+typedef enum
+{
+  flag_logical_noclobber, flag_logical, flag_add, flag_sub, flag_cmp, flag_addx, flag_subx, flag_zn,
+  flag_av, flag_sv
+}
+flagtypes;
+
+static void genflags_normal (flagtypes type, wordsizes size, char *value, char *src, char *dst)
+{
+    char vstr[100], sstr[100], dstr[100];
+    char usstr[100], udstr[100];
+    char unsstr[100], undstr[100];
+
+    switch (size) {
+     case sz_byte:
+       strcpy (vstr, "((uae_s8)(");
+       strcpy (usstr, "((uae_u8)(");
+       break;
+     case sz_word:
+       strcpy (vstr, "((uae_s16)(");
+       strcpy (usstr, "((uae_u16)(");
+       break;
+     case sz_long:
+       strcpy (vstr, "((uae_s32)(");
+       strcpy (usstr, "((uae_u32)(");
+       break;
+     default:
+       abort ();
+    }
+    strcpy (unsstr, usstr);
+
+    strcpy (sstr, vstr);
+    strcpy (dstr, vstr);
+    strcat (vstr, value);
+    strcat (vstr, "))");
+    strcat (dstr, dst);
+    strcat (dstr, "))");
+    strcat (sstr, src);
+    strcat (sstr, "))");
+
+    strcpy (udstr, usstr);
+    strcat (udstr, dst);
+    strcat (udstr, "))");
+    strcat (usstr, src);
+    strcat (usstr, "))");
+
+    strcpy (undstr, unsstr);
+    strcat (unsstr, "-");
+    strcat (undstr, "~");
+    strcat (undstr, dst);
+    strcat (undstr, "))");
+    strcat (unsstr, src);
+    strcat (unsstr, "))");
+
+    switch (type) {
+     case flag_logical_noclobber:
+     case flag_logical:
+     case flag_zn:
+     case flag_av:
+     case flag_sv:
+     case flag_addx:
+     case flag_subx:
+       break;
+
+     case flag_add:
+       start_brace ();
+       printf ("uae_u32 %s = %s + %s;\n", value, dstr, sstr);
+       break;
+     case flag_sub:
+     case flag_cmp:
+       start_brace ();
+       printf ("uae_u32 %s = %s - %s;\n", value, dstr, sstr);
+       break;
+    }
+
+    switch (type) {
+     case flag_logical_noclobber:
+     case flag_logical:
+     case flag_zn:
+       break;
+
+     case flag_add:
+     case flag_sub:
+     case flag_addx:
+     case flag_subx:
+     case flag_cmp:
+     case flag_av:
+     case flag_sv:
+       start_brace ();
+       printf ("\t" BOOL_TYPE " flgs = %s < 0;\n", sstr);
+       printf ("\t" BOOL_TYPE " flgo = %s < 0;\n", dstr);
+       printf ("\t" BOOL_TYPE " flgn = %s < 0;\n", vstr);
+       break;
+    }
+
+    switch (type) {
+     case flag_logical:
+       printf ("\tCLEAR_CZNV;\n");
+       printf ("\tSET_ZFLG (%s == 0);\n", vstr);
+       printf ("\tSET_NFLG (%s < 0);\n", vstr);
+       break;
+     case flag_logical_noclobber:
+       printf ("\tSET_ZFLG (%s == 0);\n", vstr);
+       printf ("\tSET_NFLG (%s < 0);\n", vstr);
+       break;
+     case flag_av:
+       printf ("\tSET_VFLG ((flgs ^ flgn) & (flgo ^ flgn));\n");
+       break;
+     case flag_sv:
+       printf ("\tSET_VFLG ((flgs ^ flgo) & (flgn ^ flgo));\n");
+       break;
+     case flag_zn:
+       printf ("\tSET_ZFLG (GET_ZFLG & (%s == 0));\n", vstr);
+       printf ("\tSET_NFLG (%s < 0);\n", vstr);
+       break;
+     case flag_add:
+       printf ("\tSET_ZFLG (%s == 0);\n", vstr);
+       printf ("\tSET_VFLG ((flgs ^ flgn) & (flgo ^ flgn));\n");
+       printf ("\tSET_CFLG (%s < %s);\n", undstr, usstr);
+       duplicate_carry (0);
+       printf ("\tSET_NFLG (flgn != 0);\n");
+       break;
+     case flag_sub:
+       printf ("\tSET_ZFLG (%s == 0);\n", vstr);
+       printf ("\tSET_VFLG ((flgs ^ flgo) & (flgn ^ flgo));\n");
+       printf ("\tSET_CFLG (%s > %s);\n", usstr, udstr);
+       duplicate_carry (0);
+       printf ("\tSET_NFLG (flgn != 0);\n");
+       break;
+     case flag_addx:
+       printf ("\tSET_VFLG ((flgs ^ flgn) & (flgo ^ flgn));\n"); /* minterm SON: 0x42 */
+       printf ("\tSET_CFLG (flgs ^ ((flgs ^ flgo) & (flgo ^ flgn)));\n"); /* minterm SON: 0xD4 */
+       duplicate_carry (0);
+       break;
+     case flag_subx:
+       printf ("\tSET_VFLG ((flgs ^ flgo) & (flgo ^ flgn));\n"); /* minterm SON: 0x24 */
+       printf ("\tSET_CFLG (flgs ^ ((flgs ^ flgn) & (flgo ^ flgn)));\n"); /* minterm SON: 0xB2 */
+       duplicate_carry (0);
+       break;
+     case flag_cmp:
+       printf ("\tSET_ZFLG (%s == 0);\n", vstr);
+       printf ("\tSET_VFLG ((flgs != flgo) && (flgn != flgo));\n");
+       printf ("\tSET_CFLG (%s > %s);\n", usstr, udstr);
+       printf ("\tSET_NFLG (flgn != 0);\n");
+       break;
+    }
+}
+
+static void genflags (flagtypes type, wordsizes size, char *value, char *src, char *dst)
+{
+    /* Temporarily deleted 68k/ARM flag optimizations.  I'd prefer to have
+       them in the appropriate m68k.h files and use just one copy of this
+       code here.  The API can be changed if necessary.  */
+#ifdef OPTIMIZED_FLAGS
+    switch (type) {
+     case flag_add:
+     case flag_sub:
+       start_brace ();
+       printf ("\tuae_u32 %s;\n", value);
+       break;
+
+     default:
+       break;
+    }
+
+    /* At least some of those casts are fairly important! */
+    switch (type) {
+     case flag_logical_noclobber:
+       printf ("\t{uae_u32 oldcznv = GET_CZNV & ~(FLAGVAL_Z | FLAGVAL_N);\n");
+       if (strcmp (value, "0") == 0) {
+           printf ("\tSET_CZNV (olcznv | FLAGVAL_Z);\n");
+       } else {
+           switch (size) {
+            case sz_byte: printf ("\toptflag_testb ((uae_s8)(%s));\n", value); break;
+            case sz_word: printf ("\toptflag_testw ((uae_s16)(%s));\n", value); break;
+            case sz_long: printf ("\toptflag_testl ((uae_s32)(%s));\n", value); break;
+           }
+           printf ("\tIOR_CZNV (oldcznv);\n");
+       }
+       printf ("\t}\n");
+       return;
+     case flag_logical:
+       if (strcmp (value, "0") == 0) {
+           printf ("\tSET_CZNV (FLAGVAL_Z);\n");
+       } else {
+           switch (size) {
+            case sz_byte: printf ("\toptflag_testb ((uae_s8)(%s));\n", value); break;
+            case sz_word: printf ("\toptflag_testw ((uae_s16)(%s));\n", value); break;
+            case sz_long: printf ("\toptflag_testl ((uae_s32)(%s));\n", value); break;
+           }
+       }
+       return;
+
+     case flag_add:
+       switch (size) {
+        case sz_byte: printf ("\toptflag_addb (%s, (uae_s8)(%s), (uae_s8)(%s));\n", value, src, dst); break;
+        case sz_word: printf ("\toptflag_addw (%s, (uae_s16)(%s), (uae_s16)(%s));\n", value, src, dst); break;
+        case sz_long: printf ("\toptflag_addl (%s, (uae_s32)(%s), (uae_s32)(%s));\n", value, src, dst); break;
+       }
+       return;
+
+     case flag_sub:
+       switch (size) {
+        case sz_byte: printf ("\toptflag_subb (%s, (uae_s8)(%s), (uae_s8)(%s));\n", value, src, dst); break;
+        case sz_word: printf ("\toptflag_subw (%s, (uae_s16)(%s), (uae_s16)(%s));\n", value, src, dst); break;
+        case sz_long: printf ("\toptflag_subl (%s, (uae_s32)(%s), (uae_s32)(%s));\n", value, src, dst); break;
+       }
+       return;
+
+     case flag_cmp:
+       switch (size) {
+        case sz_byte: printf ("\toptflag_cmpb ((uae_s8)(%s), (uae_s8)(%s));\n", src, dst); break;
+        case sz_word: printf ("\toptflag_cmpw ((uae_s16)(%s), (uae_s16)(%s));\n", src, dst); break;
+        case sz_long: printf ("\toptflag_cmpl ((uae_s32)(%s), (uae_s32)(%s));\n", src, dst); break;
+       }
+       return;
+       
+     default:
+       break;
+    }
+#endif
+
+    genflags_normal (type, size, value, src, dst);
+}
+
+static void force_range_for_rox (const char *var, wordsizes size)
+{
+    /* Could do a modulo operation here... which one is faster? */
+    switch (size) {
+     case sz_long:
+       printf ("\tif (%s >= 33) %s -= 33;\n", var, var);
+       break;
+     case sz_word:
+       printf ("\tif (%s >= 34) %s -= 34;\n", var, var);
+       printf ("\tif (%s >= 17) %s -= 17;\n", var, var);
+       break;
+     case sz_byte:
+       printf ("\tif (%s >= 36) %s -= 36;\n", var, var);
+       printf ("\tif (%s >= 18) %s -= 18;\n", var, var);
+       printf ("\tif (%s >= 9) %s -= 9;\n", var, var);
+       break;
+    }
+}
+
+static const char *cmask (wordsizes size)
+{
+    switch (size) {
+     case sz_byte: return "0x80";
+     case sz_word: return "0x8000";
+     case sz_long: return "0x80000000";
+     default: abort ();
+    }
+}
+
+static int source_is_imm1_8 (struct instr *i)
+{
+    return i->stype == 3;
+}
+
+static void shift_ce (amodes dmode, int size)
+{
+    if (using_ce && isreg (dmode)) {
+        printf ("\t{\n");
+        printf ("\t\tint cycles = %d * %d - lostcycles;\n", size == sz_long ? 8 : 6, CYCLE_UNIT / 2);
+       printf ("\t\tcycles += 2 * %d * ccnt;\n", CYCLE_UNIT / 2);
+        addcycles3 ("\t\t");
+        printf ("\t}\n");
+    }
+}
+
+static void gen_opcode (unsigned long int opcode)
+{
+    struct instr *curi = table68k + opcode;
+    int tmpc = 0;
+    insn_n_cycles = using_prefetch ? 0 : 4;
+
+    start_brace ();
+#if 0
+    printf ("uae_u8 *m68k_pc = regs.pc_p;\n");
+#endif
+    m68k_pc_offset = 2;
+    switch (curi->plev) {
+    case 0: /* not privileged */
+       break;
+    case 1: /* unprivileged only on 68000 */
+       if (cpu_level == 0)
+           break;
+       if (next_cpu_level < 0)
+           next_cpu_level = 0;
+
+       /* fall through */
+    case 2: /* priviledged */
+       printf ("if (!regs.s) { Exception(8,0); goto %s; }\n", endlabelstr);
+       need_endlabel = 1;
+       start_brace ();
+       break;
+    case 3: /* privileged if size == word */
+       if (curi->size == sz_byte)
+           break;
+       printf ("if (!regs.s) { Exception(8,0); goto %s; }\n", endlabelstr);
+       need_endlabel = 1;
+       start_brace ();
+       break;
+    }
+    switch (curi->mnemo) {
+    case i_OR:
+    case i_AND:
+    case i_EOR:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0, 0);
+       printf ("\tsrc %c= dst;\n", curi->mnemo == i_OR ? '|' : curi->mnemo == i_AND ? '&' : '^');
+       genflags (flag_logical, curi->size, "src", "", "");
+       if (curi->size == sz_long && isreg (curi->dmode))
+           tmpc += curi->mnemo == i_AND ? 2 : 4;
+       fill_prefetch_next_delay (tmpc);
+       genastore ("src", curi->dmode, "dstreg", curi->size, "dst");
+       break;
+    case i_ORSR:
+    case i_EORSR:
+       printf ("\tMakeSR();\n");
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       if (curi->size == sz_byte) {
+           printf ("\tsrc &= 0xFF;\n");
+       }
+        fill_prefetch_next_delay (8);
+       printf ("\tregs.sr %c= src;\n", curi->mnemo == i_EORSR ? '^' : '|');
+       printf ("\tMakeFromSR();\n");
+       break;
+    case i_ANDSR:
+       printf ("\tMakeSR();\n");
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       if (curi->size == sz_byte) {
+           printf ("\tsrc |= 0xFF00;\n");
+       }
+        fill_prefetch_next_delay (8);
+       printf ("\tregs.sr &= src;\n");
+       printf ("\tMakeFromSR();\n");
+       break;
+    case i_SUB:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0, 0);
+       if (isreg (curi->dmode)) {
+           if (curi->dmode == Dreg && curi->size == sz_long)
+               tmpc += (curi->smode == imm || curi->smode == immi) ? 4 : 2;
+       }
+        fill_prefetch_next_delay (tmpc);
+       start_brace ();
+       genflags (flag_sub, curi->size, "newv", "src", "dst");
+       genastore ("newv", curi->dmode, "dstreg", curi->size, "dst");
+       break;
+    case i_SUBA:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", sz_long, "dst", 1, 0, 0);
+       if (isreg (curi->dmode) && curi->dmode == Areg) {
+           tmpc += curi->size == sz_long ? 2 : 4;
+           if (curi->size == sz_long)
+               tmpc += (isreg (curi->smode) || curi->smode == imm) ? 2 : 0;
+       }
+       fill_prefetch_next_delay (tmpc);
+       start_brace ();
+       printf ("\tuae_u32 newv = dst - src;\n");
+       genastore ("newv", curi->dmode, "dstreg", sz_long, "dst");
+       break;
+    case i_SUBX:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, GF_AA);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0, GF_AA);
+       if ((isreg (curi->smode) && curi->size == sz_long) || !isreg (curi->smode))
+           tmpc += 2;
+        fill_prefetch_next_delay (tmpc);
+       start_brace ();
+       printf ("\tuae_u32 newv = dst - src - (GET_XFLG ? 1 : 0);\n");
+       genflags (flag_subx, curi->size, "newv", "src", "dst");
+       genflags (flag_zn, curi->size, "newv", "", "");
+       genastore ("newv", curi->dmode, "dstreg", curi->size, "dst");
+       break;
+    case i_SBCD:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, GF_AA);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0, GF_AA);
+        fill_prefetch_next ();
+       start_brace ();
+       printf ("\tuae_u16 newv_lo = (dst & 0xF) - (src & 0xF) - (GET_XFLG ? 1 : 0);\n");
+       printf ("\tuae_u16 newv_hi = (dst & 0xF0) - (src & 0xF0);\n");
+       printf ("\tuae_u16 newv, tmp_newv;\n");
+       printf ("\tint bcd = 0;\n");
+       printf ("\tnewv = tmp_newv = newv_hi + newv_lo;\n");
+       printf ("\tif (newv_lo & 0xF0) { newv -= 6; bcd = 6; };\n");
+       printf ("\tif ((((dst & 0xFF) - (src & 0xFF) - (GET_XFLG ? 1 : 0)) & 0x100) > 0xFF) { newv -= 0x60; }\n");
+       printf ("\tSET_CFLG ((((dst & 0xFF) - (src & 0xFF) - bcd - (GET_XFLG ? 1 : 0)) & 0x300) > 0xFF);\n");
+       duplicate_carry (0);
+       genflags (flag_zn, curi->size, "newv", "", "");
+       printf ("\tSET_VFLG ((tmp_newv & 0x80) != 0 && (newv & 0x80) == 0);\n");
+       addcycles (2);
+       genastore ("newv", curi->dmode, "dstreg", curi->size, "dst");
+       break;
+    case i_ADD:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0, 0);
+       if (isreg (curi->dmode)) {
+           if (curi->dmode == Dreg && curi->size == sz_long)
+               tmpc += (curi->smode == imm || curi->smode == immi) ? 4 : 2;
+       }
+        fill_prefetch_next_delay (tmpc);
+       start_brace ();
+       genflags (flag_add, curi->size, "newv", "src", "dst");
+       genastore ("newv", curi->dmode, "dstreg", curi->size, "dst");
+       break;
+    case i_ADDA:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", sz_long, "dst", 1, 0, 0);
+       if (isreg (curi->dmode) && curi->dmode == Areg) {
+           tmpc += curi->size == sz_long ? 2 : 4;
+           if (curi->size == sz_long)
+               tmpc += (isreg (curi->smode) || curi->smode == imm) ? 2 : 0;
+       }
+        fill_prefetch_next_delay (tmpc);
+       start_brace ();
+       printf ("\tuae_u32 newv = dst + src;\n");
+       genastore ("newv", curi->dmode, "dstreg", sz_long, "dst");
+       break;
+    case i_ADDX:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, GF_AA);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0, GF_AA);
+       if ((isreg (curi->smode) && curi->size == sz_long) || !isreg (curi->smode))
+           tmpc += 2;
+        fill_prefetch_next_delay (tmpc);
+       start_brace ();
+       printf ("\tuae_u32 newv = dst + src + (GET_XFLG ? 1 : 0);\n");
+       genflags (flag_addx, curi->size, "newv", "src", "dst");
+       genflags (flag_zn, curi->size, "newv", "", "");
+       genastore ("newv", curi->dmode, "dstreg", curi->size, "dst");
+       break;
+    case i_ABCD:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, GF_AA);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0, GF_AA);
+        fill_prefetch_next ();
+       start_brace ();
+       printf ("\tuae_u16 newv_lo = (src & 0xF) + (dst & 0xF) + (GET_XFLG ? 1 : 0);\n");
+       printf ("\tuae_u16 newv_hi = (src & 0xF0) + (dst & 0xF0);\n");
+       printf ("\tuae_u16 newv, tmp_newv;\n");
+       printf ("\tint cflg;\n");
+       printf ("\tnewv = tmp_newv = newv_hi + newv_lo;");
+       printf ("\tif (newv_lo > 9) { newv += 6; }\n");
+       printf ("\tcflg = (newv & 0x3F0) > 0x90;\n");
+       printf ("\tif (cflg) newv += 0x60;\n");
+       printf ("\tSET_CFLG (cflg);\n");
+       duplicate_carry (0);
+       genflags (flag_zn, curi->size, "newv", "", "");
+       printf ("\tSET_VFLG ((tmp_newv & 0x80) == 0 && (newv & 0x80) != 0);\n");
+       addcycles (2);
+       genastore ("newv", curi->dmode, "dstreg", curi->size, "dst");
+       break;
+    case i_NEG:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       if (isreg (curi->smode) && curi->size == sz_long) tmpc += 2;
+        fill_prefetch_next_delay (tmpc);
+       start_brace ();
+       genflags (flag_sub, curi->size, "dst", "src", "0");
+       genastore ("dst", curi->smode, "srcreg", curi->size, "src");
+       break;
+    case i_NEGX:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       if (isreg (curi->smode) && curi->size == sz_long) tmpc += 2;
+        fill_prefetch_next_delay (tmpc);
+       start_brace ();
+       printf ("\tuae_u32 newv = 0 - src - (GET_XFLG ? 1 : 0);\n");
+       genflags (flag_subx, curi->size, "newv", "src", "0");
+       genflags (flag_zn, curi->size, "newv", "", "");
+       genastore ("newv", curi->smode, "srcreg", curi->size, "src");
+       break;
+    case i_NBCD:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       if (isreg (curi->smode)) tmpc += 2;
+        fill_prefetch_next_delay (tmpc);
+       start_brace ();
+       printf ("\tuae_u16 newv_lo = - (src & 0xF) - (GET_XFLG ? 1 : 0);\n");
+       printf ("\tuae_u16 newv_hi = - (src & 0xF0);\n");
+       printf ("\tuae_u16 newv;\n");
+       printf ("\tint cflg;\n");
+       printf ("\tif (newv_lo > 9) { newv_lo -= 6; }\n");
+       printf ("\tnewv = newv_hi + newv_lo;");
+       printf ("\tcflg = (newv & 0x1F0) > 0x90;\n");
+       printf ("\tif (cflg) newv -= 0x60;\n");
+       printf ("\tSET_CFLG (cflg);\n");
+       duplicate_carry(0);
+       genflags (flag_zn, curi->size, "newv", "", "");
+       genastore ("newv", curi->smode, "srcreg", curi->size, "src");
+       break;
+    case i_CLR:
+       genamode (curi->smode, "srcreg", curi->size, "src", cpu_level == 0 ? 1 : 2, 0, 0);
+       if (isreg (curi->smode) && curi->size == sz_long) tmpc += 2;
+        fill_prefetch_next_delay (tmpc);
+       genflags (flag_logical, curi->size, "0", "", "");
+       genastore ("0", curi->smode, "srcreg", curi->size, "src");
+       break;
+    case i_NOT:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       if (isreg (curi->smode) && curi->size == sz_long) tmpc += 2;
+        fill_prefetch_next_delay (tmpc);
+       start_brace ();
+       printf ("\tuae_u32 dst = ~src;\n");
+       genflags (flag_logical, curi->size, "dst", "", "");
+       genastore ("dst", curi->smode, "srcreg", curi->size, "src");
+       break;
+    case i_TST:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+        fill_prefetch_next ();
+       genflags (flag_logical, curi->size, "src", "", "");
+       break;
+    case i_BTST:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0, 0);
+       if (isreg (curi->dmode)) tmpc += 2;
+        fill_prefetch_next_delay (tmpc);
+       if (curi->size == sz_byte)
+           printf ("\tsrc &= 7;\n");
+       else
+           printf ("\tsrc &= 31;\n");
+       printf ("\tSET_ZFLG (1 ^ ((dst >> src) & 1));\n");
+       break;
+    case i_BCHG:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0, 0);
+       if (isreg (curi->dmode)) tmpc += 4;
+        fill_prefetch_next_delay (tmpc);
+       if (curi->size == sz_byte)
+           printf ("\tsrc &= 7;\n");
+       else
+           printf ("\tsrc &= 31;\n");
+       printf ("\tdst ^= (1 << src);\n");
+       printf ("\tSET_ZFLG (((uae_u32)dst & (1 << src)) >> src);\n");
+       genastore ("dst", curi->dmode, "dstreg", curi->size, "dst");
+       break;
+    case i_BCLR:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0, 0);
+       if (isreg (curi->dmode)) tmpc += 4;
+        fill_prefetch_next_delay (tmpc);
+       if (curi->size == sz_byte)
+           printf ("\tsrc &= 7;\n");
+       else
+           printf ("\tsrc &= 31;\n");
+       printf ("\tSET_ZFLG (1 ^ ((dst >> src) & 1));\n");
+       printf ("\tdst &= ~(1 << src);\n");
+       genastore ("dst", curi->dmode, "dstreg", curi->size, "dst");
+       break;
+    case i_BSET:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0, 0);
+       if (isreg (curi->dmode)) tmpc += 4;
+        fill_prefetch_next_delay (tmpc);
+       if (curi->size == sz_byte)
+           printf ("\tsrc &= 7;\n");
+       else
+           printf ("\tsrc &= 31;\n");
+       printf ("\tSET_ZFLG (1 ^ ((dst >> src) & 1));\n");
+       printf ("\tdst |= (1 << src);\n");
+       genastore ("dst", curi->dmode, "dstreg", curi->size, "dst");
+       break;
+    case i_CMPM:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, GF_AA);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0, GF_AA);
+        fill_prefetch_next ();
+       start_brace ();
+       genflags (flag_cmp, curi->size, "newv", "src", "dst");
+       break;
+    case i_CMP:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0, 0);
+       if (isreg (curi->dmode)) {
+           if (curi->dmode == Areg || (curi->dmode == Dreg && curi->size == sz_long))
+               tmpc += 2;
+       }
+        fill_prefetch_next_delay (tmpc);
+       start_brace ();
+       genflags (flag_cmp, curi->size, "newv", "src", "dst");
+       break;
+    case i_CMPA:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", sz_long, "dst", 1, 0, 0);
+       if (isreg (curi->dmode)) {
+           if (curi->dmode == Areg || (curi->dmode == Dreg && curi->size == sz_long))
+               tmpc += 2;
+       }
+        fill_prefetch_next_delay (tmpc);
+       start_brace ();
+       genflags (flag_cmp, sz_long, "newv", "src", "dst");
+       break;
+       /* The next two are coded a little unconventional, but they are doing
+        * weird things... */
+    case i_MVPRM:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       printf ("\tuaecptr memp = m68k_areg(regs, dstreg) + (uae_s32)(uae_s16)%s;\n", gen_nextiword (0));
+        fill_prefetch_next ();
+       if (using_ce) {
+           if (curi->size == sz_word) {
+               printf ("\tput_byte_ce (memp, src >> 8); put_byte_ce (memp + 2, src);\n");
+           } else {
+               printf ("\tput_byte_ce (memp, src >> 24); put_byte_ce (memp + 2, src >> 16);\n");
+               printf ("\tput_byte_ce (memp + 4, src >> 8); put_byte_ce (memp + 6, src);\n");
+           }
+       } else {
+           if (curi->size == sz_word) {
+               printf ("\tput_byte (memp, src >> 8); put_byte (memp + 2, src);\n");
+           } else {
+               printf ("\tput_byte (memp, src >> 24); put_byte (memp + 2, src >> 16);\n");
+               printf ("\tput_byte (memp + 4, src >> 8); put_byte (memp + 6, src);\n");
+           }
+       }
+       break;
+    case i_MVPMR:
+       printf ("\tuaecptr memp = m68k_areg(regs, srcreg) + (uae_s32)(uae_s16)%s;\n", gen_nextiword (0));
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0, 0);
+       if (using_ce) {
+           if (curi->size == sz_word) {
+               printf ("\tuae_u16 val = (get_byte_ce (memp) << 8) + get_byte_ce (memp + 2);\n");
+           } else {
+               printf ("\tuae_u32 val = (get_byte_ce (memp) << 24) + (get_byte_ce (memp + 2) << 16)\n");
+               printf ("              + (get_byte_ce (memp + 4) << 8) + get_byte_ce (memp + 6);\n");
+           }
+       } else {
+           if (curi->size == sz_word) {
+               printf ("\tuae_u16 val = (get_byte (memp) << 8) + get_byte (memp + 2);\n");
+           } else {
+               printf ("\tuae_u32 val = (get_byte (memp) << 24) + (get_byte (memp + 2) << 16)\n");
+               printf ("              + (get_byte (memp + 4) << 8) + get_byte (memp + 6);\n");
+           }
+       }
+        fill_prefetch_next ();
+       genastore ("val", curi->dmode, "dstreg", curi->size, "dst");
+       break;
+    case i_MOVE:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0, 1);
+       genastore ("src", curi->dmode, "dstreg", curi->size, "dst");
+       genflags (flag_logical, curi->size, "src", "", "");
+       sync_m68k_pc ();
+       fill_prefetch_next ();
+       break;
+    case i_MOVEA:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0, 1);
+       if (curi->size == sz_word) {
+           printf ("\tuae_u32 val = (uae_s32)(uae_s16)src;\n");
+       } else {
+           printf ("\tuae_u32 val = src;\n");
+       }
+        fill_prefetch_next ();
+       genastore ("val", curi->dmode, "dstreg", sz_long, "dst");
+       break;
+    case i_MVSR2:
+       genamode (curi->smode, "srcreg", sz_word, "src", 2, 0, 0);
+       if (isreg (curi->smode)) tmpc += 2;
+        fill_prefetch_next_delay (tmpc);
+       printf ("\tMakeSR();\n");
+       if (curi->size == sz_byte)
+           genastore ("regs.sr & 0xff", curi->smode, "srcreg", sz_word, "src");
+       else
+           genastore ("regs.sr", curi->smode, "srcreg", sz_word, "src");
+       break;
+    case i_MV2SR:
+       genamode (curi->smode, "srcreg", sz_word, "src", 1, 0, 0);
+       if (curi->size == sz_byte) {
+           tmpc += 8;
+           printf ("\tMakeSR();\n\tregs.sr &= 0xFF00;\n\tregs.sr |= src & 0xFF;\n");
+       } else {
+           tmpc += 4;
+           printf ("\tregs.sr = src;\n");
+       }
+        fill_prefetch_next_delay (tmpc);
+       printf ("\tMakeFromSR();\n");
+       break;
+    case i_SWAP:
+       genamode (curi->smode, "srcreg", sz_long, "src", 1, 0, 0);
+        fill_prefetch_next ();
+       start_brace ();
+       printf ("\tuae_u32 dst = ((src >> 16)&0xFFFF) | ((src&0xFFFF)<<16);\n");
+       genflags (flag_logical, sz_long, "dst", "", "");
+       genastore ("dst", curi->smode, "srcreg", sz_long, "src");
+       break;
+    case i_EXG:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0, 0);
+        fill_prefetch_next_delay (2);
+       genastore ("dst", curi->smode, "srcreg", curi->size, "src");
+       genastore ("src", curi->dmode, "dstreg", curi->size, "dst");
+       break;
+    case i_EXT:
+       genamode (curi->smode, "srcreg", sz_long, "src", 1, 0, 0);
+        fill_prefetch_next ();
+       start_brace ();
+       switch (curi->size) {
+       case sz_byte: printf ("\tuae_u32 dst = (uae_s32)(uae_s8)src;\n"); break;
+       case sz_word: printf ("\tuae_u16 dst = (uae_s16)(uae_s8)src;\n"); break;
+       case sz_long: printf ("\tuae_u32 dst = (uae_s32)(uae_s16)src;\n"); break;
+       default: abort ();
+       }
+       genflags (flag_logical,
+                 curi->size == sz_word ? sz_word : sz_long, "dst", "", "");
+       genastore ("dst", curi->smode, "srcreg",
+                  curi->size == sz_word ? sz_word : sz_long, "src");
+       break;
+    case i_MVMEL:
+       if (using_ce)
+           genmovemel_ce (opcode);
+       else
+           genmovemel (opcode);
+        fill_prefetch_next ();
+       break;
+    case i_MVMLE:
+       if (using_ce)
+           genmovemle_ce (opcode);
+       else
+           genmovemle (opcode);
+        fill_prefetch_next ();
+       break;
+    case i_TRAP:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       sync_m68k_pc ();
+       printf ("\tException (src + 32,0);\n");
+       did_prefetch = 1;
+       m68k_pc_offset = 0;
+       break;
+    case i_MVR2USP:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       fill_prefetch_next ();
+       printf ("\tregs.usp = src;\n");
+       break;
+    case i_MVUSP2R:
+       genamode (curi->smode, "srcreg", curi->size, "src", 2, 0, 0);
+       fill_prefetch_next ();
+       genastore ("regs.usp", curi->smode, "srcreg", curi->size, "src");
+       break;
+    case i_RESET:
+       fill_prefetch_next ();
+       printf ("\tcpureset();\n");
+       break;
+    case i_NOP:
+        fill_prefetch_next ();
+       break;
+    case i_STOP:
+       /* real stop do not prefetch anything, later... */
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       printf ("\tregs.sr = src;\n");
+       printf ("\tMakeFromSR();\n");
+       printf ("\tm68k_setstopped(1);\n");
+       sync_m68k_pc ();
+       fill_prefetch_full ();
+       break;
+    case i_RTE:
+       if (cpu_level == 0) {
+           genamode (Aipi, "7", sz_word, "sr", 1, 0, GF_NOREFILL);
+           genamode (Aipi, "7", sz_long, "pc", 1, 0, GF_NOREFILL);
+           printf ("\tregs.sr = sr; m68k_setpc_rte(pc);\n");
+           printf ("\tMakeFromSR();\n");
+       } else {
+           int old_brace_level = n_braces;
+           if (next_cpu_level < 0)
+               next_cpu_level = 0;
+           printf ("\tuae_u16 newsr; uae_u32 newpc; for (;;) {\n");
+           genamode (Aipi, "7", sz_word, "sr", 1, 0, 0);
+           genamode (Aipi, "7", sz_long, "pc", 1, 0, 0);
+           genamode (Aipi, "7", sz_word, "format", 1, 0, 0);
+           printf ("\tnewsr = sr; newpc = pc;\n");
+           printf ("\tif ((format & 0xF000) == 0x0000) { break; }\n");
+           printf ("\telse if ((format & 0xF000) == 0x1000) { ; }\n");
+           printf ("\telse if ((format & 0xF000) == 0x2000) { m68k_areg(regs, 7) += 4; break; }\n");
+           printf ("\telse if ((format & 0xF000) == 0x8000) { m68k_areg(regs, 7) += 50; break; }\n");
+           printf ("\telse if ((format & 0xF000) == 0x9000) { m68k_areg(regs, 7) += 12; break; }\n");
+           printf ("\telse if ((format & 0xF000) == 0xa000) { m68k_areg(regs, 7) += 24; break; }\n");
+           printf ("\telse if ((format & 0xF000) == 0xb000) { m68k_areg(regs, 7) += 84; break; }\n");
+           printf ("\telse { Exception(14,0); goto %s; }\n", endlabelstr);
+           printf ("\tregs.sr = newsr; MakeFromSR();\n}\n");
+           pop_braces (old_brace_level);
+           printf ("\tregs.sr = newsr; MakeFromSR();\n");
+           printf ("\tif (newpc & 1)\n");
+           printf ("\t\texception3 (0x%04.4X, m68k_getpc(), newpc);\n", opcode);
+           printf ("\telse\n");
+           printf ("\t\tm68k_setpc_rte(newpc);\n");
+           need_endlabel = 1;
+       }
+       /* PC is set and prefetch filled. */
+       m68k_pc_offset = 0;
+       fill_prefetch_full ();
+       break;
+    case i_RTD:
+       printf ("\tcompiler_flush_jsr_stack();\n");
+       genamode (Aipi, "7", sz_long, "pc", 1, 0, 0);
+       genamode (curi->smode, "srcreg", curi->size, "offs", 1, 0, 0);
+       printf ("\tm68k_areg(regs, 7) += offs;\n");
+        printf ("\tif (pc & 1)\n");
+        printf ("\t\texception3 (0x%04.4X, m68k_getpc(), pc);\n", opcode);
+        printf ("\telse\n");
+       printf ("\t\tm68k_setpc_rte(pc);\n");
+       /* PC is set and prefetch filled. */
+       m68k_pc_offset = 0;
+       fill_prefetch_full ();
+       break;
+    case i_LINK:
+       genamode (Apdi, "7", sz_long, "old", 2, 0, GF_AA);
+       genamode (curi->smode, "srcreg", sz_long, "src", 1, 0, GF_AA);
+       genastore ("src", Apdi, "7", sz_long, "old");
+       genastore ("m68k_areg(regs, 7)", curi->smode, "srcreg", sz_long, "src");
+       genamode (curi->dmode, "dstreg", curi->size, "offs", 1, 0, 0);
+       printf ("\tm68k_areg(regs, 7) += offs;\n");
+        fill_prefetch_next ();
+       break;
+    case i_UNLK:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       printf ("\tm68k_areg(regs, 7) = src;\n");
+       genamode (Aipi, "7", sz_long, "old", 1, 0, 0);
+        fill_prefetch_next ();
+       genastore ("old", curi->smode, "srcreg", curi->size, "src");
+       break;
+    case i_RTS:
+       if (using_ce)
+           printf ("\tm68k_do_rts_ce();\n");
+       else
+           printf ("\tm68k_do_rts();\n");
+       m68k_pc_offset = 0;
+        fill_prefetch_full ();
+       break;
+    case i_TRAPV:
+       sync_m68k_pc ();
+       printf ("\tif (GET_VFLG) {\n");
+       printf ("\t\tException (7, m68k_getpc ());\n");
+       printf ("\t\tgoto %s;\n", endlabelstr);
+       printf ("\t}\n");
+        fill_prefetch_next ();
+       need_endlabel = 1;
+       break;
+    case i_RTR:
+       printf ("\tcompiler_flush_jsr_stack();\n");
+       printf ("\tMakeSR();\n");
+       genamode (Aipi, "7", sz_word, "sr", 1, 0, 0);
+       genamode (Aipi, "7", sz_long, "pc", 1, 0, 0);
+       printf ("\tregs.sr &= 0xFF00; sr &= 0xFF;\n");
+       printf ("\tregs.sr |= sr; m68k_setpc(pc);\n");
+       printf ("\tMakeFromSR();\n");
+       m68k_pc_offset = 0;
+        fill_prefetch_full ();
+       break;
+    case i_JSR:
+       genamode (curi->smode, "srcreg", curi->size, "src", 0, 0, GF_AA|GF_NOREFILL);
+       start_brace ();
+       printf ("\tuaecptr oldpc = m68k_getpc() + %d;\n", m68k_pc_offset);
+       if (using_exception_3) {
+           printf ("\tif (srca & 1) {\n");
+           printf ("\t\texception3i (opcode, oldpc, srca);\n");
+           printf ("\t\tgoto %s;\n", endlabelstr);
+           printf ("\t}\n");
+           need_endlabel = 1;
+       }
+        printf ("\tm68k_setpc (srca);\n");
+       m68k_pc_offset = 0;
+       fill_prefetch_1 (0, 0);
+        printf("\tm68k_areg (regs, 7) -= 4;\n");
+       if (using_ce) {
+           printf("\tput_word_ce (m68k_areg (regs, 7), oldpc >> 16);\n");
+           printf("\tput_word_ce (m68k_areg (regs, 7) + 2, oldpc);\n");
+       } else {
+           printf("\tput_long (m68k_areg (regs, 7), oldpc);\n");
+       }
+        fill_prefetch_next ();
+       break;
+    case i_JMP:
+       genamode (curi->smode, "srcreg", curi->size, "src", 0, 0, GF_AA|GF_NOREFILL);
+       if (using_exception_3) {
+           printf ("\tif (srca & 1) {\n");
+           printf ("\t\texception3i (opcode, m68k_getpc() + 6, srca);\n");
+           printf ("\t\tgoto %s;\n", endlabelstr);
+           printf ("\t}\n");
+           need_endlabel = 1;
+       }
+       if (curi->smode == Ad16 || curi->smode == Ad8r || curi->smode == absw || curi->smode == PC16 || curi->smode == PC8r)
+           addcycles (2);
+       printf ("\tm68k_setpc(srca);\n");
+       m68k_pc_offset = 0;
+        fill_prefetch_full ();
+    break;
+    case i_BSR:
+       printf ("\tuae_s32 s;\n");
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, GF_AA|GF_NOREFILL);
+       printf ("\ts = (uae_s32)src + 2;\n");
+       if (using_exception_3) {
+           printf ("\tif (src & 1) {\n");
+           printf ("\t\texception3i (opcode, m68k_getpc() + 2, m68k_getpc() + s);\n");
+           printf ("\t\tgoto %s;\n", endlabelstr);
+           printf ("\t}\n");
+           need_endlabel = 1;
+       }
+       addcycles (2);
+       if (using_ce)
+           printf ("\tm68k_do_bsr_ce (m68k_getpc() + %d, s);\n", m68k_pc_offset);
+       else
+           printf ("\tm68k_do_bsr (m68k_getpc() + %d, s);\n", m68k_pc_offset);
+       m68k_pc_offset = 0;
+        fill_prefetch_full ();
+       break;
+    case i_Bcc:
+       if (curi->size == sz_long) {
+           if (cpu_level < 2) {
+               addcycles (2);
+               printf ("\tif (cctrue(%d)) {\n", curi->cc, endlabelstr);
+               printf ("\t\texception3i (opcode, m68k_getpc() + 2, m68k_getpc() + 1);\n");
+               printf ("\t\tgoto %s;\n", endlabelstr);
+               printf ("\t}\n");
+               sync_m68k_pc ();
+               irc2ir ();
+               fill_prefetch_2 ();
+               printf ("\tgoto %s;\n", endlabelstr);
+               need_endlabel = 1;
+           } else {
+               if (next_cpu_level < 1)
+                   next_cpu_level = 1;
+           }
+       }
+        genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, GF_AA | GF_NOREFILL);
+       addcycles (2);
+       printf ("\tif (!cctrue(%d)) goto didnt_jump;\n", curi->cc);
+       if (using_exception_3) {
+           printf ("\tif (src & 1) {\n");
+           printf ("\t\texception3i (opcode, m68k_getpc() + 2, m68k_getpc() + 2 + (uae_s32)src);\n");
+           printf ("\t\tgoto %s;\n", endlabelstr);
+           printf ("\t}\n");
+           need_endlabel = 1;
+       }
+       if (using_prefetch) {
+           if (curi->size == sz_byte) {
+               printf ("\tm68k_incpc ((uae_s32)src + 2);\n");
+           } else {
+               printf ("\tm68k_incpc ((uae_s32)src + 2);\n");
+           }
+           fill_prefetch_full ();
+           if (using_ce)
+               printf ("\treturn 0;\n");
+           else
+               printf ("\treturn 10 * %d;\n", CYCLE_UNIT / 2);
+       } else {
+#ifdef USE_COMPILER
+           printf ("\tm68k_setpc_bcc(m68k_getpc() + 2+ (uae_s32)src);\n");
+#else
+           printf ("\tm68k_incpc ((uae_s32)src + 2);\n");
+#endif
+           returncycles ("\t", 10);
+       }
+       printf ("didnt_jump:;\n");
+       need_endlabel = 1;
+       sync_m68k_pc ();
+       if (curi->size == sz_byte) {
+           addcycles (2);
+           irc2ir ();
+           fill_prefetch_2 ();
+       } else
+           fill_prefetch_full ();
+        insn_n_cycles = curi->size == sz_byte ? 8 : 12;
+       break;
+    case i_LEA:
+       genamode (curi->smode, "srcreg", curi->size, "src", 0, 0, GF_AA);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0, GF_AA);
+       if (curi->smode == Ad8r || curi->smode == PC8r)
+           tmpc += 4;
+        fill_prefetch_next_delay (tmpc);
+       genastore ("srca", curi->dmode, "dstreg", curi->size, "dst");
+       break;
+    case i_PEA:
+       genamode (curi->smode, "srcreg", curi->size, "src", 0, 0, GF_AA);
+       genamode (Apdi, "7", sz_long, "dst", 2, 0, GF_AA);
+       if (curi->smode == Ad8r || curi->smode == PC8r)
+           tmpc += 4;
+        fill_prefetch_next_delay (tmpc);
+       genastore ("srca", Apdi, "7", sz_long, "dst");
+       break;
+    case i_DBcc:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, GF_AA | GF_NOREFILL);
+       genamode (curi->dmode, "dstreg", curi->size, "offs", 1, 0, GF_AA | GF_NOREFILL);
+
+       printf ("\tuaecptr oldpc = m68k_getpc();\n");
+       addcycles (2);
+       printf ("\tif (!cctrue(%d)) {\n", curi->cc);
+#ifdef USE_COMPILER
+       printf ("\t\tm68k_setpc_bcc(m68k_getpc() + (uae_s32)offs + 2);\n");
+#else
+       printf ("\t\tm68k_incpc((uae_s32)offs + 2);\n");
+#endif
+       printf ("\t"); fill_prefetch_1 (0, 0);
+       printf ("\t"); genastore ("(src-1)", curi->smode, "srcreg", curi->size, "src");
+
+       printf ("\t\tif (src) {\n");
+       if (using_exception_3) {
+           printf ("\t\t\tif (offs & 1) {\n");
+           printf ("\t\t\t\texception3i (opcode, m68k_getpc() + 2, m68k_getpc() + 2 + (uae_s32)offs + 2);\n");
+           printf ("\t\t\t\tgoto %s;\n", endlabelstr);
+           printf ("\t\t\t}\n");
+           need_endlabel = 1;
+       }
+       irc2ir ();
+       fill_prefetch_1 (2, 0);
+       returncycles ("\t\t\t", 12);
+       if (using_ce)
+           printf ("\t\t\treturn 0;\n");
+       printf ("\t\t}\n");
+       printf ("\t} else {\n");
+       addcycles2 ("\t\t", 2);
+       printf ("\t}\n");
+       printf ("\tm68k_setpc (oldpc + %d);\n", m68k_pc_offset);
+       m68k_pc_offset = 0;
+       fill_prefetch_full ();
+        insn_n_cycles = 12;
+       need_endlabel = 1;
+       break;
+    case i_Scc:
+       genamode (curi->smode, "srcreg", curi->size, "src", cpu_level == 0 ? 1 : 2, 0, 0);
+       start_brace ();
+        fill_prefetch_next_cycles ();
+       start_brace ();
+       printf ("\tint val = cctrue(%d) ? 0xff : 0;\n", curi->cc);
+       if (using_ce) {
+           printf ("\tint cycles = -lostcycles;\n");
+           if (isreg (curi->smode))
+               printf ("\tif (val) cycles += 2 * %d;\n", CYCLE_UNIT / 2);
+           addcycles3 ("\t");
+       }
+       genastore ("val", curi->smode, "srcreg", curi->size, "src");
+       break;
+    case i_DIVU:
+       printf ("\tuaecptr oldpc = m68k_getpc();\n");
+       genamode (curi->smode, "srcreg", sz_word, "src", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", sz_long, "dst", 1, 0, 0);
+        fill_prefetch_next_cycles ();
+       sync_m68k_pc ();
+       /* Clear V flag when dividing by zero - Alcatraz Odyssey demo depends
+        * on this (actually, it's doing a DIVS).  */
+       printf ("\tif (src == 0) {\n");
+       printf ("\t\tSET_VFLG (0);\n");
+       printf ("\t\tException (5, oldpc);\n");
+       printf ("\t\tgoto %s;\n", endlabelstr);
+       printf ("\t} else {\n");
+       printf ("\t\tuae_u32 newv = (uae_u32)dst / (uae_u32)(uae_u16)src;\n");
+       printf ("\t\tuae_u32 rem = (uae_u32)dst %% (uae_u32)(uae_u16)src;\n");
+       if (using_ce) {
+           printf ("\t\tint cycles = 138 * %d - lostcycles;\n", CYCLE_UNIT / 2);
+           addcycles3 ("\t\t");
+       }
+       /* The N flag appears to be set each time there is an overflow.
+        * Weird. */
+       printf ("\t\tif (newv > 0xffff) {\n");
+       printf ("\t\t\tSET_VFLG (1); SET_NFLG (1); SET_CFLG (0);\n");
+       printf ("\t\t} else {\n");
+       printf ("\t\t"); genflags (flag_logical, sz_word, "newv", "", "");
+       printf ("\t\t\tnewv = (newv & 0xffff) | ((uae_u32)rem << 16);\n");
+       printf ("\t\t"); genastore ("newv", curi->dmode, "dstreg", sz_long, "dst");
+       printf ("\t\t}\n");
+       printf ("\t}\n");
+       insn_n_cycles += 136;
+       need_endlabel = 1;
+       break;
+    case i_DIVS:
+       printf ("\tuaecptr oldpc = m68k_getpc();\n");
+       genamode (curi->smode, "srcreg", sz_word, "src", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", sz_long, "dst", 1, 0, 0);
+        fill_prefetch_next_cycles ();
+       sync_m68k_pc ();
+       printf ("\tif (src == 0) {\n");
+       printf ("\t\tSET_VFLG (0);\n");
+       printf ("\t\tException (5, oldpc);\n");
+       printf ("\t\tgoto %s;\n", endlabelstr);
+       printf ("\t} else {\n");
+       printf ("\t\tuae_s32 newv = (uae_s32)dst / (uae_s32)(uae_s16)src;\n");
+       printf ("\t\tuae_u16 rem = (uae_s32)dst %% (uae_s32)(uae_s16)src;\n");
+       if (using_ce) {
+           printf ("\t\tint cycles = 156 * %d - lostcycles;\n", CYCLE_UNIT / 2);
+           addcycles3 ("\t\t");
+       }
+       printf ("\t\tif ((newv & 0xffff8000) != 0 && (newv & 0xffff8000) != 0xffff8000) {\n");
+       printf ("\t\t\tSET_VFLG (1); SET_NFLG (1); SET_CFLG (0);\n");
+       printf ("\t\t} else {\n");
+       printf ("\t\t\tif (((uae_s16)rem < 0) != ((uae_s32)dst < 0)) rem = -rem;\n");
+       genflags (flag_logical, sz_word, "newv", "", "");
+       printf ("\t\t\tnewv = (newv & 0xffff) | ((uae_u32)rem << 16);\n");
+       printf ("\t\t"); genastore ("newv", curi->dmode, "dstreg", sz_long, "dst");
+       printf ("\t\t}\n");
+       printf ("\t}\n");
+       insn_n_cycles += 154;
+       need_endlabel = 1;
+       break;
+    case i_MULU:
+       genamode (curi->smode, "srcreg", sz_word, "src", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", sz_word, "dst", 1, 0, 0);
+        fill_prefetch_next_cycles ();
+       start_brace ();
+       printf ("\tuae_u32 newv = (uae_u32)(uae_u16)dst * (uae_u32)(uae_u16)src;\n");
+       if (using_ce)
+           printf ("\tint cycles = 38 * %d - lostcycles, bits;\n", CYCLE_UNIT / 2);
+       genflags (flag_logical, sz_long, "newv", "", "");
+       if (using_ce) {
+           printf ("\tfor(bits = 0; bits < 16 && src; bits++, src >>= 1)\n");
+           printf ("\t\tif (src & 1) cycles += 2 * %d;\n", CYCLE_UNIT / 2);
+           addcycles3 ("\t");
+       }
+       genastore ("newv", curi->dmode, "dstreg", sz_long, "dst");
+       sync_m68k_pc ();
+        insn_n_cycles += (70 - 38) / 2 + 38; /* average */
+       break;
+    case i_MULS:
+       genamode (curi->smode, "srcreg", sz_word, "src", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", sz_word, "dst", 1, 0, 0);
+        fill_prefetch_next_cycles ();
+       start_brace ();
+       printf ("\tuae_u32 newv = (uae_s32)(uae_s16)dst * (uae_s32)(uae_s16)src;\n");
+       if (using_ce)
+           printf ("\tint cycles = 38 * %d - lostcycles, bits;\n", CYCLE_UNIT / 2);
+       genflags (flag_logical, sz_long, "newv", "", "");
+       if (using_ce) {
+           printf ("\tsrc <<= 1;\n");
+           printf ("\tfor(bits = 0; bits < 16 && src; bits++, src >>= 1)\n");
+           printf ("\t\tif ((src & 3) == 1 || (src & 3) == 2) cycles += 2 * %d;\n", CYCLE_UNIT / 2);
+           addcycles3 ("\t");
+       }
+       genastore ("newv", curi->dmode, "dstreg", sz_long, "dst");
+       insn_n_cycles += (70 - 38) / 2 + 38; /* average */
+       break;
+    case i_CHK:
+       printf ("\tuaecptr oldpc = m68k_getpc();\n");
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0, 0);
+       sync_m68k_pc ();
+        fill_prefetch_next_delay (6);
+       printf ("\tif ((uae_s32)dst < 0) {\n");
+       printf ("\t\tSET_NFLG (1);\n");
+       printf ("\t\tException (6, oldpc);\n");
+       printf ("\t\tgoto %s;\n", endlabelstr);
+       printf ("\t} else if (dst > src) {\n");
+       printf ("\t\tSET_NFLG (0);\n");
+       printf ("\t\tException (6, oldpc);\n");
+       printf ("\t\tgoto %s;\n", endlabelstr);
+       printf ("\t}\n");
+       need_endlabel = 1;
+       break;
+    case i_CHK2:
+       cpulimit ();
+       printf ("\tuaecptr oldpc = m68k_getpc();\n");
+       genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0, 0);
+        fill_prefetch_0 ();
+       printf ("\t{uae_s32 upper,lower,reg = regs.regs[(extra >> 12) & 15];\n");
+       switch (curi->size) {
+       case sz_byte:
+           printf ("\tlower=(uae_s32)(uae_s8)get_byte(dsta); upper = (uae_s32)(uae_s8)get_byte(dsta+1);\n");
+           printf ("\tif ((extra & 0x8000) == 0) reg = (uae_s32)(uae_s8)reg;\n");
+           break;
+       case sz_word:
+           printf ("\tlower=(uae_s32)(uae_s16)get_word(dsta); upper = (uae_s32)(uae_s16)get_word(dsta+2);\n");
+           printf ("\tif ((extra & 0x8000) == 0) reg = (uae_s32)(uae_s16)reg;\n");
+           break;
+       case sz_long:
+           printf ("\tlower=get_long(dsta); upper = get_long(dsta+4);\n");
+           break;
+       default:
+           abort ();
+       }
+       printf ("\tSET_ZFLG (upper == reg || lower == reg);\n");
+       printf ("\tSET_CFLG_ALWAYS (lower <= upper ? reg < lower || reg > upper : reg > upper || reg < lower);\n");
+       printf ("\tif ((extra & 0x800) && GET_CFLG) { Exception(6,oldpc); goto %s; }\n}\n", endlabelstr);
+       need_endlabel = 1;
+       break;
+
+    case i_ASR:
+       genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0, 0);
+       fill_prefetch_next_cycles ();
+       start_brace ();
+       switch (curi->size) {
+       case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break;
+       case sz_word: printf ("\tuae_u32 val = (uae_u16)data;\n"); break;
+       case sz_long: printf ("\tuae_u32 val = data;\n"); break;
+       default: abort ();
+       }
+       printf ("\tuae_u32 sign = (%s & val) >> %d;\n", cmask (curi->size), bit_size (curi->size) - 1);
+        printf ("\tint ccnt = cnt & 63;\n");
+       printf ("\tcnt &= 63;\n");
+       printf ("\tCLEAR_CZNV;\n");
+       printf ("\tif (cnt >= %d) {\n", bit_size (curi->size));
+       printf ("\t\tval = %s & (uae_u32)-sign;\n", bit_mask (curi->size));
+       printf ("\t\tSET_CFLG (sign);\n");
+       duplicate_carry (1);
+       if (source_is_imm1_8 (curi))
+           printf ("\t} else {\n");
+       else
+           printf ("\t} else if (cnt > 0) {\n");
+       printf ("\t\tval >>= cnt - 1;\n");
+       printf ("\t\tSET_CFLG (val & 1);\n");
+       duplicate_carry (1);
+       printf ("\t\tval >>= 1;\n");
+       printf ("\t\tval |= (%s << (%d - cnt)) & (uae_u32)-sign;\n",
+               bit_mask (curi->size),
+               bit_size (curi->size));
+       printf ("\t\tval &= %s;\n", bit_mask (curi->size));
+       printf ("\t}\n");
+       genflags (flag_logical_noclobber, curi->size, "val", "", "");
+       shift_ce (curi->dmode, curi->size);
+       genastore ("val", curi->dmode, "dstreg", curi->size, "data");
+       break;
+    case i_ASL:
+       genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0, 0);
+       fill_prefetch_next_cycles ();
+       start_brace ();
+       switch (curi->size) {
+       case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break;
+       case sz_word: printf ("\tuae_u32 val = (uae_u16)data;\n"); break;
+       case sz_long: printf ("\tuae_u32 val = data;\n"); break;
+       default: abort ();
+       }
+        printf ("\tint ccnt = cnt & 63;\n");
+       printf ("\tcnt &= 63;\n");
+       printf ("\tCLEAR_CZNV;\n");
+       printf ("\tif (cnt >= %d) {\n", bit_size (curi->size));
+       printf ("\t\tSET_VFLG (val != 0);\n");
+       printf ("\t\tSET_CFLG (cnt == %d ? val & 1 : 0);\n",
+               bit_size (curi->size));
+       duplicate_carry (1);
+       printf ("\t\tval = 0;\n");
+       if (source_is_imm1_8 (curi))
+           printf ("\t} else {\n");
+       else
+           printf ("\t} else if (cnt > 0) {\n");
+       printf ("\t\tuae_u32 mask = (%s << (%d - cnt)) & %s;\n",
+               bit_mask (curi->size),
+               bit_size (curi->size) - 1,
+               bit_mask (curi->size));
+       printf ("\t\tSET_VFLG ((val & mask) != mask && (val & mask) != 0);\n");
+       printf ("\t\tval <<= cnt - 1;\n");
+       printf ("\t\tSET_CFLG ((val & %s) >> %d);\n", cmask (curi->size), bit_size (curi->size) - 1);
+       duplicate_carry (1);
+       printf ("\t\tval <<= 1;\n");
+       printf ("\t\tval &= %s;\n", bit_mask (curi->size));
+       printf ("\t}\n");
+       genflags (flag_logical_noclobber, curi->size, "val", "", "");
+       shift_ce (curi->dmode, curi->size);
+       genastore ("val", curi->dmode, "dstreg", curi->size, "data");
+       break;
+    case i_LSR:
+       genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0, 0);
+       fill_prefetch_next_cycles ();
+       start_brace ();
+       switch (curi->size) {
+       case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break;
+       case sz_word: printf ("\tuae_u32 val = (uae_u16)data;\n"); break;
+       case sz_long: printf ("\tuae_u32 val = data;\n"); break;
+       default: abort ();
+       }
+        printf ("\tint ccnt = cnt & 63;\n");
+       printf ("\tcnt &= 63;\n");
+       printf ("\tCLEAR_CZNV;\n");
+       printf ("\tif (cnt >= %d) {\n", bit_size (curi->size));
+       printf ("\t\tSET_CFLG ((cnt == %d) & (val >> %d));\n",
+               bit_size (curi->size), bit_size (curi->size) - 1);
+       duplicate_carry (1);
+       printf ("\t\tval = 0;\n");
+       if (source_is_imm1_8 (curi))
+           printf ("\t} else {\n");
+       else
+           printf ("\t} else if (cnt > 0) {\n");
+       printf ("\t\tval >>= cnt - 1;\n");
+       printf ("\t\tSET_CFLG (val & 1);\n");
+       duplicate_carry (1);
+       printf ("\t\tval >>= 1;\n");
+       printf ("\t}\n");
+       genflags (flag_logical_noclobber, curi->size, "val", "", "");
+       shift_ce (curi->dmode, curi->size);
+       genastore ("val", curi->dmode, "dstreg", curi->size, "data");
+       break;
+    case i_LSL:
+       genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0, 0);
+       fill_prefetch_next_cycles ();
+       start_brace ();
+       switch (curi->size) {
+       case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break;
+       case sz_word: printf ("\tuae_u32 val = (uae_u16)data;\n"); break;
+       case sz_long: printf ("\tuae_u32 val = data;\n"); break;
+       default: abort ();
+       }
+        printf ("\tint ccnt = cnt & 63;\n");
+       printf ("\tcnt &= 63;\n");
+       printf ("\tCLEAR_CZNV;\n");
+       printf ("\tif (cnt >= %d) {\n", bit_size (curi->size));
+       printf ("\t\tSET_CFLG (cnt == %d ? val & 1 : 0);\n",
+               bit_size (curi->size));
+       duplicate_carry (1);
+       printf ("\t\tval = 0;\n");
+       if (source_is_imm1_8 (curi))
+           printf ("\t} else {\n");
+       else
+           printf ("\t} else if (cnt > 0) {\n");
+       printf ("\t\tval <<= (cnt - 1);\n");
+       printf ("\t\tSET_CFLG ((val & %s) >> %d);\n", cmask (curi->size), bit_size (curi->size) - 1);
+       duplicate_carry (1);
+       printf ("\t\tval <<= 1;\n");
+       printf ("\tval &= %s;\n", bit_mask (curi->size));
+       printf ("\t}\n");
+       genflags (flag_logical_noclobber, curi->size, "val", "", "");
+       shift_ce (curi->dmode, curi->size);
+       genastore ("val", curi->dmode, "dstreg", curi->size, "data");
+       break;
+    case i_ROL:
+       genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0, 0);
+       fill_prefetch_next_cycles ();
+       start_brace ();
+       switch (curi->size) {
+       case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break;
+       case sz_word: printf ("\tuae_u32 val = (uae_u16)data;\n"); break;
+       case sz_long: printf ("\tuae_u32 val = data;\n"); break;
+       default: abort ();
+       }
+        printf ("\tint ccnt = cnt & 63;\n");
+       printf ("\tcnt &= 63;\n");
+       printf ("\tCLEAR_CZNV;\n");
+       if (source_is_imm1_8 (curi))
+           printf ("{");
+       else
+           printf ("\tif (cnt > 0) {\n");
+       printf ("\tuae_u32 loval;\n");
+       printf ("\tcnt &= %d;\n", bit_size (curi->size) - 1);
+       printf ("\tloval = val >> (%d - cnt);\n", bit_size (curi->size));
+       printf ("\tval <<= cnt;\n");
+       printf ("\tval |= loval;\n");
+       printf ("\tval &= %s;\n", bit_mask (curi->size));
+       printf ("\tSET_CFLG (val & 1);\n");
+       printf ("}\n");
+       genflags (flag_logical_noclobber, curi->size, "val", "", "");
+       shift_ce (curi->dmode, curi->size);
+       genastore ("val", curi->dmode, "dstreg", curi->size, "data");
+       break;
+    case i_ROR:
+       genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0, 0);
+       fill_prefetch_next_cycles ();
+       start_brace ();
+       switch (curi->size) {
+       case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break;
+       case sz_word: printf ("\tuae_u32 val = (uae_u16)data;\n"); break;
+       case sz_long: printf ("\tuae_u32 val = data;\n"); break;
+       default: abort ();
+       }
+        printf ("\tint ccnt = cnt & 63;\n");
+       printf ("\tcnt &= 63;\n");
+       printf ("\tCLEAR_CZNV;\n");
+       if (source_is_imm1_8 (curi))
+           printf ("{");
+       else
+           printf ("\tif (cnt > 0) {");
+       printf ("\tuae_u32 hival;\n");
+       printf ("\tcnt &= %d;\n", bit_size (curi->size) - 1);
+       printf ("\thival = val << (%d - cnt);\n", bit_size (curi->size));
+       printf ("\tval >>= cnt;\n");
+       printf ("\tval |= hival;\n");
+       printf ("\tval &= %s;\n", bit_mask (curi->size));
+       printf ("\tSET_CFLG ((val & %s) >> %d);\n", cmask (curi->size), bit_size (curi->size) - 1);
+       printf ("\t}\n");
+       genflags (flag_logical_noclobber, curi->size, "val", "", "");
+       shift_ce (curi->dmode, curi->size);
+       genastore ("val", curi->dmode, "dstreg", curi->size, "data");
+       break;
+    case i_ROXL:
+       genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0, 0);
+       fill_prefetch_next_cycles ();
+       start_brace ();
+       switch (curi->size) {
+       case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break;
+       case sz_word: printf ("\tuae_u32 val = (uae_u16)data;\n"); break;
+       case sz_long: printf ("\tuae_u32 val = data;\n"); break;
+       default: abort ();
+       }
+        printf ("\tint ccnt = cnt & 63;\n");
+       printf ("\tcnt &= 63;\n");
+       printf ("\tCLEAR_CZNV;\n");
+       if (source_is_imm1_8 (curi))
+           printf ("{");
+       else {
+           force_range_for_rox ("cnt", curi->size);
+           printf ("\tif (cnt > 0) {\n");
+       }
+       printf ("\tcnt--;\n");
+       printf ("\t{\n\tuae_u32 carry;\n");
+       printf ("\tuae_u32 loval = val >> (%d - cnt);\n", bit_size (curi->size) - 1);
+       printf ("\tcarry = loval & 1;\n");
+       printf ("\tval = (((val << 1) | GET_XFLG) << cnt) | (loval >> 1);\n");
+       printf ("\tSET_XFLG (carry);\n");
+       printf ("\tval &= %s;\n", bit_mask (curi->size));
+       printf ("\t} }\n");
+       printf ("\tSET_CFLG (GET_XFLG);\n");
+       genflags (flag_logical_noclobber, curi->size, "val", "", "");
+       shift_ce (curi->dmode, curi->size);
+       genastore ("val", curi->dmode, "dstreg", curi->size, "data");
+       break;
+    case i_ROXR:
+       genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0, 0);
+       fill_prefetch_next_cycles ();
+       start_brace ();
+       switch (curi->size) {
+       case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break;
+       case sz_word: printf ("\tuae_u32 val = (uae_u16)data;\n"); break;
+       case sz_long: printf ("\tuae_u32 val = data;\n"); break;
+       default: abort ();
+       }
+       printf ("\tint ccnt = cnt & 63;\n");
+       printf ("\tcnt &= 63;\n");
+       printf ("\tCLEAR_CZNV;\n");
+       if (source_is_imm1_8 (curi))
+           printf ("{");
+       else {
+           force_range_for_rox ("cnt", curi->size);
+           printf ("\tif (cnt > 0) {\n");
+       }
+       printf ("\tcnt--;\n");
+       printf ("\t{\n\tuae_u32 carry;\n");
+       printf ("\tuae_u32 hival = (val << 1) | GET_XFLG;\n");
+       printf ("\thival <<= (%d - cnt);\n", bit_size (curi->size) - 1);
+       printf ("\tval >>= cnt;\n");
+       printf ("\tcarry = val & 1;\n");
+       printf ("\tval >>= 1;\n");
+       printf ("\tval |= hival;\n");
+       printf ("\tSET_XFLG (carry);\n");
+       printf ("\tval &= %s;\n", bit_mask (curi->size));
+       printf ("\t} }\n");
+       printf ("\tSET_CFLG (GET_XFLG);\n");
+       genflags (flag_logical_noclobber, curi->size, "val", "", "");
+       shift_ce (curi->dmode, curi->size);
+       genastore ("val", curi->dmode, "dstreg", curi->size, "data");
+       break;
+    case i_ASRW:
+       genamode (curi->smode, "srcreg", curi->size, "data", 1, 0, 0);
+        fill_prefetch_next ();
+       start_brace ();
+       switch (curi->size) {
+       case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break;
+       case sz_word: printf ("\tuae_u32 val = (uae_u16)data;\n"); break;
+       case sz_long: printf ("\tuae_u32 val = data;\n"); break;
+       default: abort ();
+       }
+       printf ("\tuae_u32 sign = %s & val;\n", cmask (curi->size));
+       printf ("\tuae_u32 cflg = val & 1;\n");
+       printf ("\tval = (val >> 1) | sign;\n");
+       genflags (flag_logical, curi->size, "val", "", "");
+       printf ("\tSET_CFLG (cflg);\n");
+       duplicate_carry (0);
+       genastore ("val", curi->smode, "srcreg", curi->size, "data");
+       break;
+    case i_ASLW:
+       genamode (curi->smode, "srcreg", curi->size, "data", 1, 0, 0);
+        fill_prefetch_next ();
+       start_brace ();
+       switch (curi->size) {
+       case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break;
+       case sz_word: printf ("\tuae_u32 val = (uae_u16)data;\n"); break;
+       case sz_long: printf ("\tuae_u32 val = data;\n"); break;
+       default: abort ();
+       }
+       printf ("\tuae_u32 sign = %s & val;\n", cmask (curi->size));
+       printf ("\tuae_u32 sign2;\n");
+       printf ("\tval <<= 1;\n");
+       genflags (flag_logical, curi->size, "val", "", "");
+       printf ("\tsign2 = %s & val;\n", cmask (curi->size));
+       printf ("\tSET_CFLG (sign != 0);\n");
+       duplicate_carry (0);
+
+       printf ("\tSET_VFLG (GET_VFLG | (sign2 != sign));\n");
+       genastore ("val", curi->smode, "srcreg", curi->size, "data");
+       break;
+    case i_LSRW:
+       genamode (curi->smode, "srcreg", curi->size, "data", 1, 0, 0);
+        fill_prefetch_next ();
+       start_brace ();
+       switch (curi->size) {
+       case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break;
+       case sz_word: printf ("\tuae_u32 val = (uae_u16)data;\n"); break;
+       case sz_long: printf ("\tuae_u32 val = data;\n"); break;
+       default: abort ();
+       }
+       printf ("\tuae_u32 carry = val & 1;\n");
+       printf ("\tval >>= 1;\n");
+       genflags (flag_logical, curi->size, "val", "", "");
+       printf ("SET_CFLG (carry);\n");
+       duplicate_carry (0);
+       genastore ("val", curi->smode, "srcreg", curi->size, "data");
+       break;
+    case i_LSLW:
+       genamode (curi->smode, "srcreg", curi->size, "data", 1, 0, 0);
+        fill_prefetch_next ();
+       start_brace ();
+       switch (curi->size) {
+       case sz_byte: printf ("\tuae_u8 val = data;\n"); break;
+       case sz_word: printf ("\tuae_u16 val = data;\n"); break;
+       case sz_long: printf ("\tuae_u32 val = data;\n"); break;
+       default: abort ();
+       }
+       printf ("\tuae_u32 carry = val & %s;\n", cmask (curi->size));
+       printf ("\tval <<= 1;\n");
+       genflags (flag_logical, curi->size, "val", "", "");
+       printf ("SET_CFLG (carry >> %d);\n", bit_size (curi->size) - 1);
+       duplicate_carry (0);
+       genastore ("val", curi->smode, "srcreg", curi->size, "data");
+       break;
+    case i_ROLW:
+       genamode (curi->smode, "srcreg", curi->size, "data", 1, 0, 0);
+        fill_prefetch_next ();
+       start_brace ();
+       switch (curi->size) {
+       case sz_byte: printf ("\tuae_u8 val = data;\n"); break;
+       case sz_word: printf ("\tuae_u16 val = data;\n"); break;
+       case sz_long: printf ("\tuae_u32 val = data;\n"); break;
+       default: abort ();
+       }
+       printf ("\tuae_u32 carry = val & %s;\n", cmask (curi->size));
+       printf ("\tval <<= 1;\n");
+       printf ("\tif (carry)  val |= 1;\n");
+       genflags (flag_logical, curi->size, "val", "", "");
+       printf ("SET_CFLG (carry >> %d);\n", bit_size (curi->size) - 1);
+       genastore ("val", curi->smode, "srcreg", curi->size, "data");
+       break;
+    case i_RORW:
+       genamode (curi->smode, "srcreg", curi->size, "data", 1, 0, 0);
+        fill_prefetch_next ();
+       start_brace ();
+       switch (curi->size) {
+       case sz_byte: printf ("\tuae_u8 val = data;\n"); break;
+       case sz_word: printf ("\tuae_u16 val = data;\n"); break;
+       case sz_long: printf ("\tuae_u32 val = data;\n"); break;
+       default: abort ();
+       }
+       printf ("\tuae_u32 carry = val & 1;\n");
+       printf ("\tval >>= 1;\n");
+       printf ("\tif (carry) val |= %s;\n", cmask (curi->size));
+       genflags (flag_logical, curi->size, "val", "", "");
+       printf ("SET_CFLG (carry);\n");
+       genastore ("val", curi->smode, "srcreg", curi->size, "data");
+       break;
+    case i_ROXLW:
+       genamode (curi->smode, "srcreg", curi->size, "data", 1, 0, 0);
+        fill_prefetch_next ();
+       start_brace ();
+       switch (curi->size) {
+       case sz_byte: printf ("\tuae_u8 val = data;\n"); break;
+       case sz_word: printf ("\tuae_u16 val = data;\n"); break;
+       case sz_long: printf ("\tuae_u32 val = data;\n"); break;
+       default: abort ();
+       }
+       printf ("\tuae_u32 carry = val & %s;\n", cmask (curi->size));
+       printf ("\tval <<= 1;\n");
+       printf ("\tif (GET_XFLG) val |= 1;\n");
+       genflags (flag_logical, curi->size, "val", "", "");
+       printf ("SET_CFLG (carry >> %d);\n", bit_size (curi->size) - 1);
+       duplicate_carry (0);
+       genastore ("val", curi->smode, "srcreg", curi->size, "data");
+       break;
+    case i_ROXRW:
+       genamode (curi->smode, "srcreg", curi->size, "data", 1, 0, 0);
+        fill_prefetch_next ();
+       start_brace ();
+       switch (curi->size) {
+       case sz_byte: printf ("\tuae_u8 val = data;\n"); break;
+       case sz_word: printf ("\tuae_u16 val = data;\n"); break;
+       case sz_long: printf ("\tuae_u32 val = data;\n"); break;
+       default: abort ();
+       }
+       printf ("\tuae_u32 carry = val & 1;\n");
+       printf ("\tval >>= 1;\n");
+       printf ("\tif (GET_XFLG) val |= %s;\n", cmask (curi->size));
+       genflags (flag_logical, curi->size, "val", "", "");
+       printf ("SET_CFLG (carry);\n");
+       duplicate_carry (0);
+       genastore ("val", curi->smode, "srcreg", curi->size, "data");
+       break;
+    case i_MOVEC2:
+       cpulimit ();
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+        fill_prefetch_next ();
+       start_brace ();
+       printf ("\tint regno = (src >> 12) & 15;\n");
+       printf ("\tuae_u32 *regp = regs.regs + regno;\n");
+       printf ("\tif (! m68k_movec2(src & 0xFFF, regp)) goto %s;\n", endlabelstr);
+       break;
+    case i_MOVE2C:
+       cpulimit ();
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+        fill_prefetch_next ();
+       start_brace ();
+       printf ("\tint regno = (src >> 12) & 15;\n");
+       printf ("\tuae_u32 *regp = regs.regs + regno;\n");
+       printf ("\tif (! m68k_move2c(src & 0xFFF, regp)) goto %s;\n", endlabelstr);
+       break;
+    case i_CAS:
+    {
+       int old_brace_level;
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0, 0);
+        fill_prefetch_0 ();
+       start_brace ();
+       printf ("\tint ru = (src >> 6) & 7;\n");
+       printf ("\tint rc = src & 7;\n");
+       genflags (flag_cmp, curi->size, "newv", "m68k_dreg(regs, rc)", "dst");
+       printf ("\tif (GET_ZFLG)");
+       old_brace_level = n_braces;
+       start_brace ();
+       genastore ("(m68k_dreg(regs, ru))", curi->dmode, "dstreg", curi->size, "dst");
+       pop_braces (old_brace_level);
+       printf ("else");
+       start_brace ();
+       printf ("m68k_dreg(regs, rc) = dst;\n");
+       pop_braces (old_brace_level);
+    }
+    break;
+    case i_CAS2:
+       cpulimit ();
+       genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0, 0);
+       printf ("\tuae_u32 rn1 = regs.regs[(extra >> 28) & 15];\n");
+       printf ("\tuae_u32 rn2 = regs.regs[(extra >> 12) & 15];\n");
+       if (curi->size == sz_word) {
+           int old_brace_level = n_braces;
+           printf ("\tuae_u16 dst1 = get_word(rn1), dst2 = get_word(rn2);\n");
+           genflags (flag_cmp, curi->size, "newv", "m68k_dreg(regs, (extra >> 16) & 7)", "dst1");
+           printf ("\tif (GET_ZFLG) {\n");
+           genflags (flag_cmp, curi->size, "newv", "m68k_dreg(regs, extra & 7)", "dst2");
+           printf ("\tif (GET_ZFLG) {\n");
+           printf ("\tput_word(rn1, m68k_dreg(regs, (extra >> 22) & 7));\n");
+           printf ("\tput_word(rn1, m68k_dreg(regs, (extra >> 6) & 7));\n");
+           printf ("\t}}\n");
+           pop_braces (old_brace_level);
+           printf ("\tif (! GET_ZFLG) {\n");
+           printf ("\tm68k_dreg(regs, (extra >> 22) & 7) = (m68k_dreg(regs, (extra >> 22) & 7) & ~0xffff) | (dst1 & 0xffff);\n");
+           printf ("\tm68k_dreg(regs, (extra >> 6) & 7) = (m68k_dreg(regs, (extra >> 6) & 7) & ~0xffff) | (dst2 & 0xffff);\n");
+           printf ("\t}\n");
+       } else {
+           int old_brace_level = n_braces;
+           printf ("\tuae_u32 dst1 = get_long(rn1), dst2 = get_long(rn2);\n");
+           genflags (flag_cmp, curi->size, "newv", "m68k_dreg(regs, (extra >> 16) & 7)", "dst1");
+           printf ("\tif (GET_ZFLG) {\n");
+           genflags (flag_cmp, curi->size, "newv", "m68k_dreg(regs, extra & 7)", "dst2");
+           printf ("\tif (GET_ZFLG) {\n");
+           printf ("\tput_long(rn1, m68k_dreg(regs, (extra >> 22) & 7));\n");
+           printf ("\tput_long(rn1, m68k_dreg(regs, (extra >> 6) & 7));\n");
+           printf ("\t}}\n");
+           pop_braces (old_brace_level);
+           printf ("\tif (! GET_ZFLG) {\n");
+           printf ("\tm68k_dreg(regs, (extra >> 22) & 7) = dst1;\n");
+           printf ("\tm68k_dreg(regs, (extra >> 6) & 7) = dst2;\n");
+           printf ("\t}\n");
+       }
+       break;
+    case i_MOVES:              /* ignore DFC and SFC because we have no MMU */
+    {
+       int old_brace_level;
+       cpulimit ();
+       genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0, 0);
+       printf ("\tif (extra & 0x800)\n");
+       old_brace_level = n_braces;
+       start_brace ();
+       printf ("\tuae_u32 src = regs.regs[(extra >> 12) & 15];\n");
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0, 0);
+       genastore ("src", curi->dmode, "dstreg", curi->size, "dst");
+       pop_braces (old_brace_level);
+       printf ("else");
+       start_brace ();
+       genamode (curi->dmode, "dstreg", curi->size, "src", 1, 0, 0);
+       printf ("\tif (extra & 0x8000) {\n");
+       switch (curi->size) {
+       case sz_byte: printf ("\tm68k_areg(regs, (extra >> 12) & 7) = (uae_s32)(uae_s8)src;\n"); break;
+       case sz_word: printf ("\tm68k_areg(regs, (extra >> 12) & 7) = (uae_s32)(uae_s16)src;\n"); break;
+       case sz_long: printf ("\tm68k_areg(regs, (extra >> 12) & 7) = src;\n"); break;
+       default: abort ();
+       }
+       printf ("\t} else {\n");
+       genastore ("src", Dreg, "(extra >> 12) & 7", curi->size, "");
+       printf ("\t}\n");
+       pop_braces (old_brace_level);
+    }
+    break;
+    case i_BKPT:               /* only needed for hardware emulators */
+       cpulimit ();
+       sync_m68k_pc ();
+       printf ("\top_illg(opcode);\n");
+       break;
+    case i_CALLM:              /* not present in 68030 */
+       cpulimit ();
+       sync_m68k_pc ();
+       printf ("\top_illg(opcode);\n");
+       break;
+    case i_RTM:                /* not present in 68030 */
+       cpulimit ();
+       sync_m68k_pc ();
+       printf ("\top_illg(opcode);\n");
+       break;
+    case i_TRAPcc:
+       cpulimit ();
+       if (curi->smode != am_unknown && curi->smode != am_illg)
+           genamode (curi->smode, "srcreg", curi->size, "dummy", 1, 0, 0);
+        fill_prefetch_0 ();
+       printf ("\tif (cctrue(%d)) { Exception(7,m68k_getpc()); goto %s; }\n", curi->cc, endlabelstr);
+       need_endlabel = 1;
+       break;
+    case i_DIVL:
+       cpulimit ();
+       sync_m68k_pc ();
+       start_brace ();
+       printf ("\tuaecptr oldpc = m68k_getpc();\n");
+       genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0, 0);
+       sync_m68k_pc ();
+       printf ("\tm68k_divl(opcode, dst, extra, oldpc);\n");
+       break;
+    case i_MULL:
+       cpulimit ();
+       genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0, 0);
+       sync_m68k_pc ();
+       printf ("\tm68k_mull(opcode, dst, extra);\n");
+       break;
+    case i_BFTST:
+    case i_BFEXTU:
+    case i_BFCHG:
+    case i_BFEXTS:
+    case i_BFCLR:
+    case i_BFFFO:
+    case i_BFSET:
+    case i_BFINS:
+       cpulimit ();
+       genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0, 0);
+       genamode (curi->dmode, "dstreg", sz_long, "dst", 2, 0, 0);
+       start_brace ();
+       printf ("\tuae_s32 offset = extra & 0x800 ? m68k_dreg(regs, (extra >> 6) & 7) : (extra >> 6) & 0x1f;\n");
+       printf ("\tint width = (((extra & 0x20 ? m68k_dreg(regs, extra & 7) : extra) -1) & 0x1f) +1;\n");
+       if (curi->dmode == Dreg) {
+           printf ("\tuae_u32 tmp = m68k_dreg(regs, dstreg) << (offset & 0x1f);\n");
+       } else {
+           printf ("\tuae_u32 tmp,bf0,bf1;\n");
+           printf ("\tdsta += (offset >> 3) | (offset & 0x80000000 ? ~0x1fffffff : 0);\n");
+           printf ("\tbf0 = get_long(dsta);bf1 = get_byte(dsta+4) & 0xff;\n");
+           printf ("\ttmp = (bf0 << (offset & 7)) | (bf1 >> (8 - (offset & 7)));\n");
+       }
+       printf ("\ttmp >>= (32 - width);\n");
+       printf ("\tSET_NFLG_ALWAYS (tmp & (1 << (width-1)) ? 1 : 0);\n");
+       printf ("\tSET_ZFLG (tmp == 0); SET_VFLG (0); SET_CFLG (0);\n");
+       switch (curi->mnemo) {
+       case i_BFTST:
+           break;
+       case i_BFEXTU:
+           printf ("\tm68k_dreg(regs, (extra >> 12) & 7) = tmp;\n");
+           break;
+       case i_BFCHG:
+           printf ("\ttmp = ~tmp;\n");
+           break;
+       case i_BFEXTS:
+           printf ("\tif (GET_NFLG) tmp |= width == 32 ? 0 : (-1 << width);\n");
+           printf ("\tm68k_dreg(regs, (extra >> 12) & 7) = tmp;\n");
+           break;
+       case i_BFCLR:
+           printf ("\ttmp = 0;\n");
+           break;
+       case i_BFFFO:
+           printf ("\t{ uae_u32 mask = 1 << (width-1);\n");
+           printf ("\twhile (mask) { if (tmp & mask) break; mask >>= 1; offset++; }}\n");
+           printf ("\tm68k_dreg(regs, (extra >> 12) & 7) = offset;\n");
+           break;
+       case i_BFSET:
+           printf ("\ttmp = 0xffffffff;\n");
+           break;
+       case i_BFINS:
+           printf ("\ttmp = m68k_dreg(regs, (extra >> 12) & 7);\n");
+           printf ("\tSET_NFLG (tmp & (1 << (width - 1)) ? 1 : 0);\n");
+           printf ("\tSET_ZFLG (tmp == 0);\n");
+           break;
+       default:
+           break;
+       }
+       if (curi->mnemo == i_BFCHG
+           || curi->mnemo == i_BFCLR
+           || curi->mnemo == i_BFSET
+           || curi->mnemo == i_BFINS)
+           {
+               printf ("\ttmp <<= (32 - width);\n");
+               if (curi->dmode == Dreg) {
+                   printf ("\tm68k_dreg(regs, dstreg) = (m68k_dreg(regs, dstreg) & ((offset & 0x1f) == 0 ? 0 :\n");
+                   printf ("\t\t(0xffffffff << (32 - (offset & 0x1f))))) |\n");
+                   printf ("\t\t(tmp >> (offset & 0x1f)) |\n");
+                   printf ("\t\t(((offset & 0x1f) + width) >= 32 ? 0 :\n");
+                   printf (" (m68k_dreg(regs, dstreg) & ((uae_u32)0xffffffff >> ((offset & 0x1f) + width))));\n");
+               } else {
+                   printf ("\tbf0 = (bf0 & (0xff000000 << (8 - (offset & 7)))) |\n");
+                   printf ("\t\t(tmp >> (offset & 7)) |\n");
+                   printf ("\t\t(((offset & 7) + width) >= 32 ? 0 :\n");
+                   printf ("\t\t (bf0 & ((uae_u32)0xffffffff >> ((offset & 7) + width))));\n");
+                   printf ("\tput_long(dsta,bf0 );\n");
+                   printf ("\tif (((offset & 7) + width) > 32) {\n");
+                   printf ("\t\tbf1 = (bf1 & (0xff >> (width - 32 + (offset & 7)))) |\n");
+                   printf ("\t\t\t(tmp << (8 - (offset & 7)));\n");
+                   printf ("\t\tput_byte(dsta+4,bf1);\n");
+                   printf ("\t}\n");
+               }
+           }
+       break;
+    case i_PACK:
+       if (curi->smode == Dreg) {
+           printf ("\tuae_u16 val = m68k_dreg(regs, srcreg) + %s;\n", gen_nextiword (0));
+           printf ("\tm68k_dreg(regs, dstreg) = (m68k_dreg(regs, dstreg) & 0xffffff00) | ((val >> 4) & 0xf0) | (val & 0xf);\n");
+       } else {
+           printf ("\tuae_u16 val;\n");
+           printf ("\tm68k_areg(regs, srcreg) -= areg_byteinc[srcreg];\n");
+           printf ("\tval = (uae_u16)get_byte(m68k_areg(regs, srcreg));\n");
+           printf ("\tm68k_areg(regs, srcreg) -= areg_byteinc[srcreg];\n");
+           printf ("\tval = (val | ((uae_u16)get_byte(m68k_areg(regs, srcreg)) << 8)) + %s;\n", gen_nextiword (0));
+           printf ("\tm68k_areg(regs, dstreg) -= areg_byteinc[dstreg];\n");
+           printf ("\tput_byte(m68k_areg(regs, dstreg),((val >> 4) & 0xf0) | (val & 0xf));\n");
+       }
+       break;
+    case i_UNPK:
+       if (curi->smode == Dreg) {
+           printf ("\tuae_u16 val = m68k_dreg(regs, srcreg);\n");
+           printf ("\tval = (((val << 4) & 0xf00) | (val & 0xf)) + %s;\n", gen_nextiword (0));
+           printf ("\tm68k_dreg(regs, dstreg) = (m68k_dreg(regs, dstreg) & 0xffff0000) | (val & 0xffff);\n");
+       } else {
+           printf ("\tuae_u16 val;\n");
+           printf ("\tm68k_areg(regs, srcreg) -= areg_byteinc[srcreg];\n");
+           printf ("\tval = (uae_u16)get_byte(m68k_areg(regs, srcreg));\n");
+           printf ("\tval = (((val << 4) & 0xf00) | (val & 0xf)) + %s;\n", gen_nextiword (0));
+           printf ("\tm68k_areg(regs, dstreg) -= areg_byteinc[dstreg];\n");
+           printf ("\tput_byte(m68k_areg(regs, dstreg),val);\n");
+           printf ("\tm68k_areg(regs, dstreg) -= areg_byteinc[dstreg];\n");
+           printf ("\tput_byte(m68k_areg(regs, dstreg),val >> 8);\n");
+       }
+       break;
+    case i_TAS:
+       genamode (curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+       genflags (flag_logical, curi->size, "src", "", "");
+       if (!isreg (curi->smode))
+           tmpc += 2;
+        fill_prefetch_next_delay (tmpc);
+       printf ("\tsrc |= 0x80;\n");
+       genastore ("src", curi->smode, "srcreg", curi->size, "src");
+       break;
+    case i_FPP:
+       fpulimit();
+       genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0, 0);
+       sync_m68k_pc ();
+       printf ("\tfpp_opp(opcode,extra);\n");
+       break;
+    case i_FDBcc:
+       fpulimit();
+       genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0, 0);
+       sync_m68k_pc ();
+       printf ("\tfdbcc_opp(opcode,extra);\n");
+       break;
+    case i_FScc:
+       fpulimit();
+       genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0, 0);
+       sync_m68k_pc ();
+       printf ("\tfscc_opp(opcode,extra);\n");
+       break;
+    case i_FTRAPcc:
+       fpulimit();
+       sync_m68k_pc ();
+       start_brace ();
+       printf ("\tuaecptr oldpc = m68k_getpc();\n");
+       if (curi->smode != am_unknown && curi->smode != am_illg)
+           genamode (curi->smode, "srcreg", curi->size, "dummy", 1, 0, 0);
+       sync_m68k_pc ();
+       printf ("\tftrapcc_opp(opcode,oldpc);\n");
+       break;
+    case i_FBcc:
+       fpulimit();
+       sync_m68k_pc ();
+       start_brace ();
+       printf ("\tuaecptr pc = m68k_getpc();\n");
+       genamode (curi->dmode, "srcreg", curi->size, "extra", 1, 0, 0);
+       sync_m68k_pc ();
+       printf ("\tfbcc_opp(opcode,pc,extra);\n");
+       break;
+    case i_FSAVE:
+       fpulimit();
+       sync_m68k_pc ();
+       printf ("\tfsave_opp(opcode);\n");
+       break;
+    case i_FRESTORE:
+       fpulimit();
+       sync_m68k_pc ();
+       printf ("\tfrestore_opp(opcode);\n");
+       break;
+
+     case i_CINVL:
+       cpulimit ();
+       printf ("\tif (opcode&0x80)\n"
+               "\t\tflush_icache(31);\n"); 
+       break;
+     case i_CINVP:
+       cpulimit ();
+       printf ("\tif (opcode&0x80)\n"
+               "\t\tflush_icache(32);\n"); 
+       break;
+     case i_CINVA:
+       cpulimit ();
+       printf ("\tif (opcode&0x80)\n"
+               "\t\tflush_icache(33);\n"); 
+       break;
+     case i_CPUSHL:
+       cpulimit ();
+       printf ("\tif (opcode&0x80)\n"
+               "\t\tflush_icache(41);\n"); 
+       break;
+     case i_CPUSHP:
+       cpulimit ();
+       printf ("\tif (opcode&0x80)\n"
+               "\t\tflush_icache(42);\n"); 
+       break;
+     case i_CPUSHA:
+       cpulimit ();
+       printf ("\tif (opcode&0x80)\n"
+               "\t\tflush_icache(43);\n"); 
+       break;
+     case i_MOVE16:
+       cpulimit ();
+       if ((opcode & 0xfff8) == 0xf620) {
+            /* MOVE16 (Ax)+,(Ay)+ */
+            printf ("\tuaecptr mems = m68k_areg(regs, srcreg) & ~15, memd;\n");
+            printf ("\tdstreg = (%s >> 12) & 7;\n", gen_nextiword(0));
+            printf ("\tmemd = m68k_areg(regs, dstreg) & ~15;\n");
+            printf ("\tput_long(memd, get_long(mems));\n");
+            printf ("\tput_long(memd+4, get_long(mems+4));\n");
+            printf ("\tput_long(memd+8, get_long(mems+8));\n");
+            printf ("\tput_long(memd+12, get_long(mems+12));\n");
+            printf ("\tif (srcreg != dstreg)\n");
+            printf ("\tm68k_areg(regs, srcreg) += 16;\n");
+            printf ("\tm68k_areg(regs, dstreg) += 16;\n");
+       } else {
+            /* Other variants */
+            genamode (curi->smode, "srcreg", curi->size, "mems", 0, 2, 0);
+            genamode (curi->dmode, "dstreg", curi->size, "memd", 0, 2, 0);
+            printf ("\tmemsa &= ~15;\n");
+            printf ("\tmemda &= ~15;\n");
+            printf ("\tput_long(memda, get_long(memsa));\n");
+            printf ("\tput_long(memda+4, get_long(memsa+4));\n");
+            printf ("\tput_long(memda+8, get_long(memsa+8));\n");
+            printf ("\tput_long(memda+12, get_long(memsa+12));\n");
+            if ((opcode & 0xfff8) == 0xf600)
+                 printf ("\tm68k_areg(regs, srcreg) += 16;\n");
+            else if ((opcode & 0xfff8) == 0xf608)
+                printf ("\tm68k_areg(regs, dstreg) += 16;\n");
+       }
+       break;
+
+    case i_MMUOP:
+       cpulimit ();
+       genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0, 0);
+       sync_m68k_pc ();
+       printf ("\tmmu_op(opcode,extra);\n");
+       break;
+    default:
+       abort ();
+       break;
+    }
+    finish_braces ();
+    if (limit_braces) {
+       printf ("\n#endif\n");
+       n_braces = limit_braces;
+       limit_braces = 0;
+       finish_braces ();
+    }
+    fill_prefetch_finish ();
+    sync_m68k_pc ();
+    did_prefetch = 0;
+}
+
+static void generate_includes (FILE * f)
+{
+    fprintf (f, "#include \"sysconfig.h\"\n");
+    fprintf (f, "#include \"sysdeps.h\"\n");
+    fprintf (f, "#include \"config.h\"\n");
+    fprintf (f, "#include \"options.h\"\n");
+    fprintf (f, "#include \"memory.h\"\n");
+    fprintf (f, "#include \"custom.h\"\n");
+    fprintf (f, "#include \"events.h\"\n");
+    fprintf (f, "#include \"newcpu.h\"\n");
+    fprintf (f, "#include \"cpu_prefetch.h\"\n");
+    fprintf (f, "#include \"compiler.h\"\n");
+    fprintf (f, "#include \"cputbl.h\"\n");
+    
+    fprintf (f, "#define CPUFUNC(x) x##_ff\n"
+            "#define SET_CFLG_ALWAYS(x) SET_CFLG(x)\n"
+            "#define SET_NFLG_ALWAYS(x) SET_NFLG(x)\n"
+            "#ifdef NOFLAGS\n"
+            "#include \"noflags.h\"\n"
+            "#endif\n");
+}
+
+static int postfix;
+
+
+static char *decodeEA (amodes mode, wordsizes size)
+{
+    static char buffer[80];
+
+    buffer[0] = 0;
+    switch (mode){
+     case Dreg:
+       strcpy (buffer,"Dn");
+       break;
+     case Areg:
+       strcpy (buffer,"An");
+       break;
+     case Aind:
+       strcpy (buffer,"(An)");
+       break;
+     case Aipi:
+       strcpy (buffer,"(An)+");
+       break;
+     case Apdi:
+       strcpy (buffer,"-(An)");
+       break;
+     case Ad16:
+       strcpy (buffer,"(d16,An)");
+       break;
+     case Ad8r:
+       strcpy (buffer,"(d8,An,Xn)");
+       break;
+     case PC16:
+       strcpy (buffer,"(d16,PC)");
+       break;
+     case PC8r:
+        strcpy (buffer,"(d8,PC,Xn)");
+       break;
+     case absw:
+       strcpy (buffer,"(xxx).W");
+       break;
+     case absl:
+       strcpy (buffer,"(xxx).L");
+       break;
+     case imm:
+       switch (size){
+        case sz_byte:
+           strcpy (buffer,"#<data>.B");
+           break;
+        case sz_word:
+           strcpy (buffer,"#<data>.W");
+           break;
+        case sz_long:
+           strcpy (buffer,"#<data>.L");
+           break;
+        default:
+           break;
+       }
+       break;
+     case imm0:
+        strcpy (buffer,"#<data>.B");
+        break;
+     case imm1:
+        strcpy (buffer,"#<data>.W");
+        break;
+     case imm2:
+        strcpy (buffer,"#<data>.L");
+        break;
+     case immi:
+        strcpy (buffer,"#<data>");
+        break;
+
+     default:
+       break;
+    }
+    return buffer;
+}
+
+static char *outopcode (int opcode)
+{
+    static char out[100];
+    struct instr *ins;
+    int i;
+
+    ins = &table68k[opcode];
+    for (i = 0; lookuptab[i].name[0]; i++) {
+       if (ins->mnemo == lookuptab[i].mnemo)
+           break;
+    }
+    strcpy (out, lookuptab[i].name);
+    if (ins->size == sz_byte)
+       strcat (out,".B");
+    if (ins->size == sz_word)
+       strcat (out,".W");
+    if (ins->size == sz_long)
+       strcat (out,".L");
+    strcat (out," ");
+    if (ins->suse)
+       strcat (out, decodeEA (ins->smode, ins->size));
+    if (ins->duse) {
+       if (ins->suse) strcat (out,",");
+       strcat (out, decodeEA (ins->dmode, ins->size));
+    }
+    return out;
+}
+
+static void generate_one_opcode (int rp)
+{
+    int i;
+    uae_u16 smsk, dmsk;
+    long int opcode = opcode_map[rp];
+
+    if (table68k[opcode].mnemo == i_ILLG
+       || table68k[opcode].clev > cpu_level)
+       return;
+
+    for (i = 0; lookuptab[i].name[0]; i++) {
+       if (table68k[opcode].mnemo == lookuptab[i].mnemo)
+           break;
+    }
+
+    if (table68k[opcode].handler != -1)
+       return;
+
+    if (opcode_next_clev[rp] != cpu_level) {
+       fprintf (stblfile, "{ CPUFUNC(op_%04lx_%d), 0, %ld }, /* %s */\n", opcode, opcode_last_postfix[rp],
+                opcode, lookuptab[i].name);
+       return;
+    }
+    fprintf (stblfile, "{ CPUFUNC(op_%04lx_%d), 0, %ld }, /* %s */\n", opcode, postfix, opcode, lookuptab[i].name);
+    fprintf (headerfile, "extern cpuop_func op_%04lx_%d_nf;\n", opcode, postfix);
+    fprintf (headerfile, "extern cpuop_func op_%04lx_%d_ff;\n", opcode, postfix);
+    printf ("/* %s */\n", outopcode (opcode));
+    printf ("unsigned long REGPARAM2 CPUFUNC(op_%04lx_%d)(uae_u32 opcode)\n{\n", opcode, postfix);
+
+    switch (table68k[opcode].stype) {
+    case 0: smsk = 7; break;
+    case 1: smsk = 255; break;
+    case 2: smsk = 15; break;
+    case 3: smsk = 7; break;
+    case 4: smsk = 7; break;
+    case 5: smsk = 63; break;
+    case 7: smsk = 3; break;
+    default: abort ();
+    }
+    dmsk = 7;
+
+    next_cpu_level = -1;
+    if (table68k[opcode].suse
+       && table68k[opcode].smode != imm && table68k[opcode].smode != imm0
+       && table68k[opcode].smode != imm1 && table68k[opcode].smode != imm2
+       && table68k[opcode].smode != absw && table68k[opcode].smode != absl
+       && table68k[opcode].smode != PC8r && table68k[opcode].smode != PC16)
+    {
+       if (table68k[opcode].spos == -1) {
+           if (((int) table68k[opcode].sreg) >= 128)
+               printf ("\tuae_u32 srcreg = (uae_s32)(uae_s8)%d;\n", (int) table68k[opcode].sreg);
+           else
+               printf ("\tuae_u32 srcreg = %d;\n", (int) table68k[opcode].sreg);
+       } else {
+           char source[100];
+           int pos = table68k[opcode].spos;
+
+           if (pos)
+               sprintf (source, "((opcode >> %d) & %d)", pos, smsk);
+           else
+               sprintf (source, "(opcode & %d)", smsk);
+
+           if (table68k[opcode].stype == 3)
+               printf ("\tuae_u32 srcreg = imm8_table[%s];\n", source);
+           else if (table68k[opcode].stype == 1)
+               printf ("\tuae_u32 srcreg = (uae_s32)(uae_s8)%s;\n", source);
+           else
+               printf ("\tuae_u32 srcreg = %s;\n", source);
+       }
+    }
+    if (table68k[opcode].duse
+       /* Yes, the dmode can be imm, in case of LINK or DBcc */
+       && table68k[opcode].dmode != imm && table68k[opcode].dmode != imm0
+       && table68k[opcode].dmode != imm1 && table68k[opcode].dmode != imm2
+       && table68k[opcode].dmode != absw && table68k[opcode].dmode != absl)
+    {
+       if (table68k[opcode].dpos == -1) {
+           if (((int) table68k[opcode].dreg) >= 128)
+               printf ("\tuae_u32 dstreg = (uae_s32)(uae_s8)%d;\n", (int) table68k[opcode].dreg);
+           else
+               printf ("\tuae_u32 dstreg = %d;\n", (int) table68k[opcode].dreg);
+       } else {
+           int pos = table68k[opcode].dpos;
+#if 0
+           /* Check that we can do the little endian optimization safely.  */
+           if (pos < 8 && (dmsk >> (8 - pos)) != 0)
+               abort ();
+#endif     
+           if (pos)
+               printf ("\tuae_u32 dstreg = (opcode >> %d) & %d;\n",
+                       pos, dmsk);
+           else
+               printf ("\tuae_u32 dstreg = opcode & %d;\n", dmsk);
+       }
+    }
+    need_endlabel = 0;
+    endlabelno++;
+    sprintf (endlabelstr, "endlabel%d", endlabelno);
+    gen_opcode (opcode);
+    if (need_endlabel)
+       printf ("%s: ;\n", endlabelstr);
+    returncycles ("", insn_n_cycles);
+    if (using_ce)
+       printf ("return 0;\n");
+    printf ("}\n");
+    opcode_next_clev[rp] = next_cpu_level;
+    opcode_last_postfix[rp] = postfix;
+}
+
+static void generate_func (void)
+{
+    int j, rp;
+
+       /* sam: this is for people with low memory (eg. me :)) */
+       printf ("\n"
+                "#if !defined(PART_1) && !defined(PART_2) && "
+                   "!defined(PART_3) && !defined(PART_4) && "
+                   "!defined(PART_5) && !defined(PART_6) && "
+                   "!defined(PART_7) && !defined(PART_8)"
+               "\n"
+               "#define PART_1 1\n"
+               "#define PART_2 1\n"
+               "#define PART_3 1\n"
+               "#define PART_4 1\n"
+               "#define PART_5 1\n"
+               "#define PART_6 1\n"
+               "#define PART_7 1\n"
+               "#define PART_8 1\n"
+               "#endif\n\n");
+       
+       rp = 0;
+       for(j=1;j<=8;++j) {
+               int k = (j*nr_cpuop_funcs)/8;
+               printf ("#ifdef PART_%d\n",j);
+               for (; rp < k; rp++)
+                  generate_one_opcode (rp);
+               printf ("#endif\n\n");
+       }
+
+       fprintf (stblfile, "{ 0, 0, 0 }};\n");
+}
+
+int main (int argc, char **argv)
+{
+    int i, rp;
+    char fname[100];
+
+    read_table68k ();
+    do_merges ();
+
+    opcode_map = (int *) xmalloc (sizeof (int) * nr_cpuop_funcs);
+    opcode_last_postfix = (int *) xmalloc (sizeof (int) * nr_cpuop_funcs);
+    opcode_next_clev = (int *) xmalloc (sizeof (int) * nr_cpuop_funcs);
+    counts = (unsigned long *) xmalloc (65536 * sizeof (unsigned long));
+    read_counts ();
+
+    /* It would be a lot nicer to put all in one file (we'd also get rid of
+     * cputbl.h that way), but cpuopti can't cope.  That could be fixed, but
+     * I don't dare to touch the 68k version.  */
+
+    headerfile = fopen ("cputbl.h", "wb");
+
+    stblfile = fopen ("cpustbl.c", "wb");
+    generate_includes (stblfile);
+
+    using_prefetch = 0;
+    using_exception_3 = 1;
+    using_ce = 0;
+
+    for (i = 0; i < 7; i++) {
+       postfix = i;
+       if (i == 0 || i == 5 || i == 6) {
+           if (i > 0)
+               fprintf (stblfile,"#endif\n");
+           fprintf (stblfile, "#ifdef CPUEMU_%d\n", postfix);
+           sprintf (fname, "cpuemu_%d.c", postfix);
+            freopen (fname, "wb", stdout);
+           generate_includes (stdout);
+       }
+       cpu_level = 4 - i;
+       if (i == 5 || i == 6) {
+           cpu_level = 0;
+           using_prefetch = 1;
+           using_exception_3 = 1;
+           if (i == 6) using_ce = 1;
+           for (rp = 0; rp < nr_cpuop_funcs; rp++)
+               opcode_next_clev[rp] = 0;
+       }
+        fprintf (stblfile, "struct cputbl CPUFUNC(op_smalltbl_%d)[] = {\n", postfix);
+       generate_func ();
+    }
+    fprintf (stblfile,"#endif\n");
+
+    free (table68k);
+    return 0;
+}
diff --git a/gengenblitter.c b/gengenblitter.c
new file mode 100755 (executable)
index 0000000..a5659bf
--- /dev/null
@@ -0,0 +1,452 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Optimized blitter minterm function generator
+  *
+  * Copyright 1995,1996 Bernd Schmidt
+  * Copyright 1996 Alessandro Bissacco
+  *
+  * Overkill, n: cf. genblitter
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+
+static void nop(int);
+
+#define xmalloc malloc
+#define xfree free
+#define xrealloc realloc
+
+typedef struct tree_n {
+    enum tree_op { op_and, op_or, op_xor, op_not, op_a, op_b, op_c, op_d, op_e, op_f } op;
+    struct tree_n *left, *right;
+} *tree;
+
+static struct tree_n TRA = { op_a, NULL, NULL };
+static struct tree_n TRB = { op_b, NULL, NULL };
+static struct tree_n TRC = { op_c, NULL, NULL };
+static struct tree_n TRD = { op_d, NULL, NULL };
+static struct tree_n TRE = { op_e, NULL, NULL };
+static struct tree_n TRF = { op_f, NULL, NULL };
+static tree tree_a = &TRA;
+static tree tree_b = &TRB;
+static tree tree_c = &TRC;
+static tree tree_d = &TRD;
+static tree tree_e = &TRE;
+static tree tree_f = &TRF;
+
+typedef struct {
+    tree *trees;
+    int space;
+    int ntrees;
+} tree_vec;
+
+STATIC_INLINE int issrc (tree t)
+{
+    return t == tree_a || t == tree_b || t == tree_c || t == tree_d || t == tree_e || t == tree_f;
+}
+
+static tree new_op_tree(enum tree_op op, tree l, tree r)
+{
+    tree t;
+    if (op == op_not && l->op == op_not) {
+       t = l->left;
+       xfree(l);
+       return t;
+    }
+    t = (tree)xmalloc(sizeof(struct tree_n));
+    t->left = l;
+    t->right = r;
+    t->op = op;
+    return t;
+}
+
+static int opidx (tree t)
+{
+    switch (t->op) {
+     case op_a:
+       return 0;
+     case op_b:
+       return 1;
+     case op_c:
+       return 2;
+     case op_d:
+       return 3;
+     case op_e:
+       return 4;
+     case op_f:
+       return 5;
+     default:
+       return -1;
+    }
+}
+
+static int tree_cst (tree t, unsigned int *src, unsigned int *notsrc)
+{
+    int idx = opidx (t);
+    if (idx >= 0) {
+       src[idx] = 1;
+       return 0;
+    }
+    switch (t->op) {
+     case op_not:
+       idx = opidx (t->left);
+       if (idx >= 0) {
+           notsrc[idx] = 1;
+           return 3;
+       }
+       return 3 + tree_cst (t->left, src, notsrc);
+
+     case op_and:
+     case op_xor:
+     case op_or:
+       return 4 + tree_cst (t->left, src, notsrc) + tree_cst (t->right, src, notsrc);
+       
+     default:
+       abort ();
+    }
+}
+
+static int tree_cost (tree t)
+{
+    int i, cost;
+    unsigned int src[6], notsrc[6];
+    memset (src, 0, sizeof src);
+    memset (notsrc, 0, sizeof notsrc);
+
+    cost = tree_cst (t, src, notsrc);
+    for (i = 0; i < 6; i++)
+       if (src[i] && notsrc[i])
+           cost++;
+    return cost;
+}
+
+static int add_vec(tree_vec *tv, tree t)
+{
+    int i;
+#if 0
+    if (! tree_isnormal(t))
+       nop(2);
+#endif
+    if (tv->ntrees == tv->space) {
+       tv->trees = (tree *)xrealloc(tv->trees, sizeof(tree)*(tv->space += 40));
+    }
+    tv->trees[tv->ntrees++] = t;
+
+    return 1;
+}
+
+static void init_vec(tree_vec *tv)
+{
+    tv->ntrees = tv->space = 0;
+    tv->trees = NULL;
+}
+
+static void do_sprint_tree (char *s, tree t)
+{
+    enum tree_op op = t->op;
+    switch (op) {
+     case op_a:
+       strcat (s, "srca");
+       break;
+     case op_b:
+       strcat (s, "srcb");
+       break;
+     case op_c:
+       strcat (s, "srcc");
+       break;
+     case op_d:
+       strcat (s, "srcd");
+       break;
+     case op_e:
+       strcat (s, "srce");
+       break;
+     case op_f:
+       strcat (s, "srcf");
+       break;
+
+     case op_and:
+     case op_or:
+     case op_xor:
+       {
+           
+           char *c = op == op_and ? " & " : op == op_or ? " | " : " ^ ";
+           strcat (s, "(");
+           do_sprint_tree (s, t->left);
+           strcat (s, c);
+           while (t->right->op == op) {
+               t = t->right;
+               do_sprint_tree (s, t->left);
+               strcat (s, c);
+           }
+           do_sprint_tree(s, t->right);
+           strcat (s, ")");
+       }
+       break;
+
+     case op_not:
+       strcat (s, "~");
+       do_sprint_tree (s, t->left);
+       break;
+    }
+}
+
+static tree_vec size_trees[20];
+
+static struct tree_n bad_tree = { op_and, &bad_tree, &bad_tree };
+
+static unsigned int used_mask[256];
+static tree best_trees[256];
+static unsigned int best_cost[256];
+static int n_unknown;
+
+static unsigned long which_fn (tree t)
+{
+    switch (t->op) {
+     case op_a:
+       return 0xf0;
+     case op_b:
+       return 0xcc;
+     case op_c:
+       return 0xaa;
+     case op_and:
+       return which_fn (t->left) & which_fn (t->right);
+     case op_or:
+       return which_fn (t->left) | which_fn (t->right);
+     case op_xor:
+       return which_fn (t->left) ^ which_fn (t->right);
+     case op_not:
+       return 0xFF & ~which_fn (t->left);
+     default:
+       abort ();
+    }
+}
+
+static unsigned long tree_used_mask (tree t)
+{
+    switch (t->op) {
+     case op_a:
+       return 1;
+     case op_b:
+       return 2;
+     case op_c:
+       return 4;
+     case op_and:
+     case op_or:
+     case op_xor:
+       return tree_used_mask (t->left) | tree_used_mask (t->right);
+     case op_not:
+       return tree_used_mask (t->left);
+     default:
+       abort ();
+    }
+}
+
+static void candidate (tree_vec *v, tree t)
+{
+    unsigned long fn = which_fn (t);
+    unsigned int cost = tree_cost (t);
+    if (best_trees[fn] == 0)
+       n_unknown--;
+    if (cost < best_cost[fn])
+       best_trees[fn] = t, best_cost[fn] = cost;
+    add_vec (v, t);
+}
+
+static void cand_and_not (tree_vec *v, tree t)
+{
+    candidate (v, t);
+    t = new_op_tree (op_not, t, 0);
+    candidate (v, t);
+}
+
+static void try_tree (tree_vec *v, tree t)
+{
+    int fnl = which_fn (t->left);
+    int fnr = which_fn (t->right);
+    int fn = which_fn (t);
+    if (fn == fnl
+       || fn == fnr
+       || fn == 0
+       || fn == 0xFF
+       || (tree_used_mask (t) & ~used_mask[fn]) != 0
+       || best_cost[fn] + 6 < tree_cost (t))
+    {
+       xfree (t);
+       return;
+    }
+    cand_and_not (v, t);
+}
+
+static void find_best_trees (void)
+{
+    int i, size, do_stop;
+    for (i = 0; i < 256; i++) {
+       best_trees[i] = i == 0 || i == 255 ? &bad_tree : 0;
+       best_cost[i] = 65535;
+    }
+    n_unknown = 254;
+
+    init_vec (size_trees);
+    cand_and_not (size_trees, tree_a);
+    cand_and_not (size_trees, tree_b);
+    cand_and_not (size_trees, tree_c);
+
+    do_stop = 0;
+    for (size = 2; ! do_stop && size < 20; size++) {
+       int split, last_split;
+       tree_vec *sv = size_trees + size - 1;
+       
+       if (n_unknown == 0)
+           do_stop = 1;
+       last_split = (size >> 1) + 1;
+       for (split = 1; split < last_split; split++) {
+           int szl = split;
+           int szr = size - split;
+           tree_vec *lv = size_trees + szl - 1;
+           tree_vec *rv = size_trees + szr - 1;
+           int i;
+
+           for (i = 0; i < lv->ntrees; i++) {
+               tree l = lv->trees[i];
+               int j;
+               for (j = szl == szr ? i + 1 : 0; j < rv->ntrees; j++) {
+                   tree r = rv->trees[j];
+
+                   if (l->op != op_and || r->op != op_and) {
+                       tree tmp = (l->op == op_and
+                                   ? new_op_tree (op_and, r, l)
+                                   : new_op_tree (op_and, l, r));
+                       try_tree (sv, tmp);
+                   }
+                   if (l->op != op_or || r->op != op_or) {
+                       tree tmp = (l->op == op_or
+                                   ? new_op_tree (op_or, r, l)
+                                   : new_op_tree (op_or, l, r));
+                       try_tree (sv, tmp);
+                   }
+                   if (l->op != op_xor || r->op != op_xor) {
+                       tree tmp = (l->op == op_xor
+                                   ? new_op_tree (op_xor, r, l)
+                                   : new_op_tree (op_xor, l, r));
+                       try_tree (sv, tmp);
+                   }
+               }
+           }
+       }
+       /* An additional pass doesn't seem to create better solutions
+        * (not that much of a surprise).  */
+       if (n_unknown == 0)
+           do_stop = 1;
+    }
+}
+
+static int bitset (int mt, int bit)
+{
+    return mt & (1 << bit);
+}
+
+static unsigned int generate_expr (int minterm)
+{
+    int bits = 0;
+    int i;
+    int expr_dc[8], nexp = 0;
+    int expr_used[8];
+
+    if (minterm == 0 || minterm == 0xFF)
+       return 0;
+
+    for (i = 0; i < 8; i++) {
+       if (bitset (minterm, i) && !bitset (bits, i)) {
+           int j;
+           int dontcare = 0;
+           int firstand = 1;
+           int bitbucket[8], bitcount;
+
+           bits |= 1<<i;
+           bitcount = 1; bitbucket[0] = i;
+           for(j=1; j<8; j *= 2) {
+               int success = 1;
+               int k;
+               for(k=0; k < bitcount; k++) {
+                   if (!bitset (minterm, bitbucket[k] ^ j)) {
+                       success = 0;
+                   }
+               }
+               if (success) {
+                   int l;
+                   dontcare |= j;
+                   for(l=bitcount; l < bitcount*2; l++) {
+                       bitbucket[l] = bitbucket[l-bitcount] ^ j;
+                       bits |= 1 << bitbucket[l];
+                   }
+                   bitcount *= 2;
+               }
+           }
+           expr_used[nexp] = 1;
+           expr_dc[nexp] = dontcare;
+           nexp++;
+       }
+    }
+
+    {
+       unsigned int result = 0;
+       for (i = 0; i < nexp; i++) {
+           int j;
+
+           for (j = 1; j < 8; j *= 2) {
+               if (!(expr_dc[i] & j))
+                   result |= (j == 1 ? 4 : j == 2 ? 2 : 1);
+           }
+       }
+       return result;
+    }
+}
+
+static void print_tree(tree t)
+{
+    char buf[300] = "";
+    do_sprint_tree (buf, t);
+    printf ("%s", buf);
+}
+
+static void generate_optable(void)
+{
+    int minterm;
+    printf(" /* This file generated automatically - do not edit */\n\n");
+    printf("#include \"genblitter.h\"\n\n");
+    printf("struct blitop blitops[256] = {\n");
+    for (minterm = 0; minterm < 256; minterm++) {
+       printf(" /* %02x */  { \"", minterm);
+       if (minterm == 0)
+           printf ("0");
+       else if (minterm == 255)
+           printf ("0xFFFFFFFF");
+       else
+           print_tree (best_trees[minterm]);
+
+       printf("\", %d }%s\n", used_mask[minterm], minterm == 255 ? "" : ",");
+       fflush(stdout);
+    }
+    printf("};\n");
+}
+
+int main (int argc, char **argv)
+{
+    int minterm;
+    for (minterm = 0; minterm < 256; minterm++)
+       used_mask[minterm] = generate_expr (minterm);
+    find_best_trees ();
+    generate_optable ();
+
+    return 0;
+}
+
+void nop(int a)
+{
+}
+
diff --git a/genp2c.c b/genp2c.c
new file mode 100755 (executable)
index 0000000..b6d09df
--- /dev/null
+++ b/genp2c.c
@@ -0,0 +1,688 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Generator for planar to chunky conversions
+  *
+  * Copyright 1997 Bernd Schmidt
+  */
+
+
+#include <stdio.h>
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+/* We can't include custom.h here.  */
+#define MAX_WORDS_PER_LINE 50
+
+
+static char *gen_ind (char *a, int b)
+{
+    char buf[200];
+    sprintf (buf, "%d(%s)", b, a);
+    return strdup (buf);
+}
+
+static char *gen_indx (char *a, int b, char *c, int d)
+{
+    char buf[200];
+    sprintf (buf, "%d(%s,%s,%d)", b, a, c, d);
+    return strdup (buf);
+}
+
+static char *gen_indsx (char *a, char *sym, int b, char *c, int d)
+{
+    char buf[200];
+    sprintf (buf, "%s+%d(%s,%s,%d)", sym, b, a, c, d);
+    return strdup (buf);
+}
+
+#define reg(a) "%" a
+#define ind(a,b) #b"("a")"
+#define imm(a) "$"#a
+#ifdef USE_UNDERSCORE
+#define sym(a) "_"#a
+#else
+#define sym(a) #a
+#endif
+#define indx(a,b,c,d) #b"("a","c","#d")"
+#define indsx(a,s,b,c,d) s"+"#b"("a","c","#d")"
+
+static int labelno = 0;
+
+static int get_label (void)
+{
+    return labelno++;
+}
+static void declare_label (int nr)
+{
+    printf (".L%d:\n", nr);
+}
+static int new_label (void)
+{
+    int nr = get_label ();
+    declare_label (nr);
+    return nr;
+}
+static void gen_label (int nr) { printf (".L%d", nr); }
+static void jnz (int nr) { printf ("\tjnz "); gen_label (nr); printf ("\n"); }
+static void jnc (int nr) { printf ("\tjnc "); gen_label (nr); printf ("\n"); }
+static void jc (int nr) { printf ("\tjc "); gen_label (nr); printf ("\n"); }
+static void jmp (int nr) { printf ("\tjmp "); gen_label (nr); printf ("\n"); }
+static void movl (char *src, char *dst) { printf ("\tmovl %s,%s\n", src, dst); }
+static void movw (char *src, char *dst) { printf ("\tmovl %s,%s\n", src, dst); }
+static void movb (char *src, char *dst) { printf ("\tmovl %s,%s\n", src, dst); }
+static void movzbl (char *src, char *dst) { printf ("\tmovzbl %s,%s\n", src, dst); }
+static void leal (char *src, char *dst) { printf ("\tleal %s,%s\n", src, dst); }
+static void addl (char *src, char *dst) { printf ("\taddl %s,%s\n", src, dst); }
+static void subl (char *src, char *dst) { printf ("\tsubl %s,%s\n", src, dst); }
+static void cmpl (char *src, char *dst) { printf ("\tcmpl %s,%s\n", src, dst); }
+static void andl (unsigned long mask, char *dst) { printf ("\tandl $0x%0lx,%s\n", mask, dst); }
+static void orl (char *src, char *dst) { printf ("\torl %s,%s\n", src, dst); }
+static void imull (unsigned long val, char *dst) { printf ("\timull $0x%08lx,%s\n", val, dst); }
+static void decl (char *dst) { printf ("\tdecl %s\n", dst); }
+static void incl (char *dst) { printf ("\tincl %s\n", dst); }
+static void bswapl (char *dst) { printf ("\tbswap %s\n", dst); }
+static void shrl (int count, char *dst) { printf ("\tshrl $%d,%s\n", count, dst); }
+static void shll (int count, char *dst) { printf ("\tshll $%d,%s\n", count, dst); }
+static void pushl (char *src) { printf ("\tpushl %s\n", src); }
+static void popl (char *dst) { printf ("\tpopl %s\n", dst); }
+static void ret (void) { printf ("\tret\n"); }
+static void align (int a) { printf ("\t.p2align %d,0x90\n", a); }
+
+static void shiftleftl (int count, char *dst)
+{
+    if (count == 0)
+       return;
+    if (count < 0)
+       shrl (-count, dst);
+    else {
+       char *indb0;
+       switch (count) {
+        case 1:
+           addl (dst, dst);
+           break;
+        case 2: case 3:
+           indb0 = gen_indx ("", 0, dst, 1 << count);
+           leal (indb0, dst);
+           free (indb0);
+           break;
+        default:
+           shll (count, dst);
+       }
+    }
+}
+
+static void declare_fn (char *name)
+{
+    printf ("\t.globl %s\n", name);
+/*    printf ("\t.type %s,@function\n", name); */
+    align (5);
+    printf ("%s:\n", name);
+}
+
+#define esi reg("esi")
+#define edi reg("edi")
+#define ebp reg("ebp")
+#define esp reg("esp")
+#define eax reg("eax")
+#define ebx reg("ebx")
+#define ecx reg("ecx")
+#define edx reg("edx")
+
+/* Modes:
+ * 0: normal
+ * 1: only generate every second plane, set memory
+ * 2: only generate every second plane, starting at second plane, or to memory
+ */
+
+/* Normal code: one pixel per bit */
+static void gen_x86_set_hires_h_toobad_k6_too_slow_someone_try_this_with_a_ppro (int pl, int mode)
+{
+    int plmul = mode == 0 ? 1 : 2;
+    int ploff = mode == 2 ? 1 : 0;
+    int i;
+    int loop;
+    char buf[40];
+    char *indb0;
+
+    sprintf (buf, sym (set_hires_h_%d_%d), pl, mode);
+    declare_fn (buf);
+
+    pushl (ebp);
+    pushl (esi);
+    pushl (edi);
+    pushl (ebx);
+
+    if (pl == 0) {
+       movl (ind (esp, 20), ebp);
+       movl (ind (esp, 24), esi);
+    }
+    movl (imm (0), edi);
+
+    loop = get_label ();
+    jmp (loop);
+    align (5);
+    declare_label (loop);
+
+    if (pl > 0)
+      movl (ind (esp, 24), esi);
+    if (mode == 2) {
+       if (pl > 0)
+         movl (ind (esp, 20), ebp);
+       movl (indx (ebp, 0, edi, 8), ecx);
+       movl (indx (ebp, 4, edi, 8), ebx);
+    }
+    for (i = 0; i <= pl; i+=2) {
+       int realpl = i * plmul + ploff;
+       char *data1 = (i == 0 && mode != 2 ? ecx : edx);
+       char *data2 = (i == 0 && mode != 2 ? ebx : eax);
+
+       if (i < pl) {
+           indb0 = gen_indx (esi, (realpl + plmul)*MAX_WORDS_PER_LINE*2, edi, 1);
+           movzbl (indb0, ebp);
+           free (indb0);
+           imull (0x08040201, ebp);
+       }
+
+       indb0 = gen_indx (esi, realpl*MAX_WORDS_PER_LINE*2, edi, 1);
+       movzbl (indb0, data2);
+       free (indb0);
+
+       if (i == pl || i == pl - 1)
+           incl (edi);
+       imull (0x08040201, data2);
+       if (i < pl) {
+           movl (ebp, esi);
+           andl (0x08080808, ebp);
+           shiftleftl (realpl + plmul - 7, esi);
+       }
+       movl (data2, data1);
+       andl (0x08080808, data2);
+       shiftleftl (realpl - 7, data1);
+       if (i < pl) {
+           andl (0x01010101 << (realpl + plmul), esi);
+       }
+       andl (0x01010101 << realpl, data1);
+       shiftleftl (realpl - 3, data2);
+       if (i < pl) {
+           shiftleftl (realpl + plmul - 3, ebp);
+       }
+       if (i < pl) {
+           orl (esi, ecx);
+           movl (ind (esp, 24), esi);
+           orl (ebp, ebx);
+       }
+       if (i > 0 || mode == 2) {
+           orl (edx, ecx);
+           orl (eax, ebx);
+       }
+    }
+    if (pl > 0)
+      movl (ind (esp, 20), ebp);
+    cmpl (ind (esp, 28), edi);
+    movl (ecx, indx (ebp, -8, edi, 8));
+    movl (ebx, indx (ebp, -4, edi, 8));
+    jc (loop);
+
+    popl (reg ("ebx"));
+    popl (reg ("edi"));
+    popl (reg ("esi"));
+    popl (reg ("ebp"));
+    ret ();
+    printf ("\n\n");
+}
+
+static void gen_x86_set_hires_h (int pl, int mode)
+{
+    int plmul = mode == 0 ? 1 : 2;
+    int ploff = mode == 2 ? 1 : 0;
+    int i;
+    int loop;
+    char buf[40];
+    char *indb0;
+
+    sprintf (buf, sym (set_hires_h_%d_%d), pl, mode);
+    declare_fn (buf);
+
+    pushl (ebp);
+    pushl (esi);
+    pushl (edi);
+    pushl (ebx);
+
+    if (pl == 0) {
+       movl (ind (esp, 20), ebp);
+       movl (ind (esp, 24), esi);
+    }
+    movl (imm (0), edi);
+
+    loop = get_label ();
+    jmp (loop);
+    align (5);
+    declare_label (loop);
+
+    if (pl > 0)
+      movl (ind (esp, 24), esi);
+    if (mode == 2) {
+       if (pl > 0)
+         movl (ind (esp, 20), ebp);
+       movl (indx (ebp, 0, edi, 8), ecx);
+       movl (indx (ebp, 4, edi, 8), ebx);
+    }
+    for (i = 0; i <= pl; i+=2) {
+       int realpl = i * plmul + ploff;
+       char *data1 = (i == 0 && mode != 2 ? ecx : edx);
+       char *data2 = (i == 0 && mode != 2 ? ebx : eax);
+
+       if (i < pl) {
+           indb0 = gen_indx (esi, (realpl + plmul)*MAX_WORDS_PER_LINE*2, edi, 1);
+           movzbl (indb0, ebp);
+           free (indb0);
+       }
+       indb0 = gen_indx (esi, realpl*MAX_WORDS_PER_LINE*2, edi, 1);
+       movzbl (indb0, data2);
+       free (indb0);
+       if (i < pl) {
+           indb0 = gen_indsx ("", sym (hirestab_h), 0, ebp, 8);
+           movl (indb0, esi);
+           free (indb0);
+           indb0 = gen_indsx ("", sym (hirestab_h), 4, ebp, 8);
+           movl (indb0, ebp);
+           free (indb0);
+       }
+       if (i == pl || i == pl - 1)
+         incl (edi);
+       indb0 = gen_indsx ("", sym (hirestab_h), 0, data2, 8);
+       movl (indb0, data1);
+       free (indb0);
+       indb0 = gen_indsx ("", sym (hirestab_h), 4, data2, 8);
+       movl (indb0, data2);
+       free (indb0);
+       switch (realpl) {
+        case 0:
+           if (i < pl) {
+               addl (esi, esi);
+               addl (ebp, ebp);
+               if (plmul == 2) {
+                   addl (esi, esi);
+                   addl (ebp, ebp);
+               }
+           }
+           break;
+        case 1:
+           if (i < pl) {
+               indb0 = gen_indx ("", 0, esi, 4*plmul);
+               leal (indb0, esi);
+               free (indb0);
+               indb0 = gen_indx ("", 0, ebp, 4*plmul);
+               leal (indb0, ebp);
+               free (indb0);
+           }
+           addl (data1, data1);
+           addl (data2, data2);
+           break;
+        case 2:
+           if (i < pl) {
+               if (plmul == 1)
+                   leal (indx ("", 0, esi, 8), esi);
+               else
+                   shll (4, esi);
+           }
+           addl (data1, data1);
+           addl (data2, data2);
+           if (i < pl) {
+               if (plmul == 1)
+                   leal (indx ("", 0, ebp, 8), ebp);
+               else
+                   shll (4, ebp);
+           }
+           addl (data1, data1);
+           addl (data2, data2);
+           break;
+        case 3:
+           if (i < pl)
+             shll (3 + plmul, esi);
+           indb0 = gen_indx ("", 0, data1, 8);
+           leal (indb0, data1);
+           free (indb0);
+           if (i < pl)
+             shll (3 + plmul, ebp);
+           indb0 = gen_indx ("", 0, data2, 8);
+           leal (indb0, data2);
+           free (indb0);
+           break;
+        case 4: case 5: case 6: case 7:
+           shll (realpl, data1);
+           shll (realpl, data2);
+           if (i < pl) {
+               shll (realpl+plmul, esi);
+               shll (realpl+plmul, ebp);
+           }
+           break;
+       }
+       
+       if (i < pl) {
+           orl (esi, ecx);
+           orl (ebp, ebx);
+           if (i + 2 <= pl)
+             movl (ind (esp, 24), esi);
+       }
+       if (i + 2 > pl && pl > 0)
+         movl (ind (esp, 20), ebp);
+       if (i > 0 || mode == 2) {
+           orl (data1, ecx);
+           orl (data2, ebx);
+       }
+    }
+
+    cmpl (ind (esp, 28), edi);
+    movl (ecx, indx (ebp, -8, edi, 8));
+    movl (ebx, indx (ebp, -4, edi, 8));
+    jc (loop);
+
+    popl (reg ("ebx"));
+    popl (reg ("edi"));
+    popl (reg ("esi"));
+    popl (reg ("ebp"));
+    ret ();
+    printf ("\n\n");
+}
+
+/* Squeeze: every second bit does not generate a pixel 
+   Not optimized, this mode isn't useful. */
+static void gen_x86_set_hires_l (int pl, int mode)
+{
+    int plmul = mode == 0 ? 1 : 2;
+    int ploff = mode == 2 ? 1 : 0;
+    int i;
+    int loop;
+    char buf[40];
+
+    sprintf (buf, sym (set_hires_l_%d_%d), pl, mode);
+    declare_fn (buf);
+
+    pushl (ebp);
+    pushl (esi);
+    pushl (edi);
+    pushl (ebx);
+    
+    movl (ind (esp, 20), ebp);
+    movl (ind (esp, 24), esi);
+    movl (imm (0), edi);
+
+    align (5);
+    loop = new_label ();
+
+    if (mode == 2) {
+       movl (indx (ebp, 0, edi, 1), ecx);
+    }
+
+    for (i = 0; i <= pl; i++) {
+       int realpl = i * plmul + ploff;
+       char *data1 = (i == 0 && mode != 2 ? ecx : edx);
+       char *indb0;
+
+       indb0 = gen_indx (esi, realpl*MAX_WORDS_PER_LINE*2, edi, 1);
+       movzbl (indb0, data1);
+       free (indb0);
+
+       indb0 = gen_indsx ("", sym (hirestab_l), 0, data1, 4);
+       movl (indb0, data1);
+       free (indb0);
+       if (i == pl)
+           incl (edi);
+       shiftleftl (realpl, data1);
+       if (i > 0 || mode == 2) {
+           orl (data1, ecx);
+       }
+    }
+    cmpl (ind (esp, 28), edi);
+    movl (ecx, indx (ebp, -4, edi, 4));
+    jc (loop);
+
+    popl (reg ("ebx"));
+    popl (reg ("edi"));
+    popl (reg ("esi"));
+    popl (reg ("ebp"));
+    ret ();
+    printf ("\n\n");
+}
+
+/* Stretch: two pixels per bit */
+static void gen_x86_set_lores_h (int pl, int mode)
+{
+    int plmul = mode == 0 ? 1 : 2;
+    int ploff = mode == 2 ? 1 : 0;
+    int i, j;
+    int loop;
+    char buf[40];
+
+    sprintf (buf, sym (set_lores_h_%d_%d), pl, mode);
+    declare_fn (buf);
+
+    pushl (ebp);
+    pushl (esi);
+    pushl (edi);
+    pushl (ebx);
+    
+    movl (ind (esp, 20), ebp);
+    movl (ind (esp, 24), esi);
+    movl (imm (0), edi);
+
+    align (5);
+    loop = new_label ();
+
+    for (j = 0; j < 2; j++) {
+       if (mode == 2) {
+           movl (j ? ind (ebp, 8) : ind (ebp, 0), ecx);
+           movl (j ? ind (ebp, 12) : ind (ebp, 4), ebx);
+       }
+
+       for (i = 0; i <= pl; i++) {
+           int realpl = i * plmul + ploff;
+           char *data1 = (i == 0 && mode != 2 ? ecx : edx);
+           char *data2 = (i == 0 && mode != 2 ? ebx : eax);
+           char *indb0;
+           
+           indb0 = gen_indx (esi, realpl*MAX_WORDS_PER_LINE*2, edi, 1);
+           movzbl (indb0, data2);
+           free (indb0);
+           addl (data2, data2);
+           indb0 = gen_indsx ("", sym (lorestab_h), 0 + j*8, data2, 8);
+           movl (indb0, data1);
+           free (indb0);
+           indb0 = gen_indsx ("", sym (lorestab_h), 4 + j*8, data2, 8);
+           movl (indb0, data2);
+           free (indb0);
+           shiftleftl (realpl, data1);
+           shiftleftl (realpl, data2);
+           if (i > 0 || mode == 2) {
+               orl (data1, ecx);
+               orl (data2, ebx);
+           }
+       }
+       movl (ecx, j ? ind (ebp, 8) : ind (ebp, 0));
+       movl (ebx, j ? ind (ebp, 12) : ind (ebp, 4));
+    }
+    incl (edi);
+    cmpl (ind (esp, 28), edi);
+    leal (ind (ebp, 16), ebp);
+    jc (loop);
+
+    popl (reg ("ebx"));
+    popl (reg ("edi"));
+    popl (reg ("esi"));
+    popl (reg ("ebp"));
+    ret ();
+    printf ("\n\n");
+}
+
+
+/* Normal code: one pixel per bit */
+static void gen_c_set_hires_h (int pl, int mode, int header)
+{
+    int plmul = mode == 0 ? 1 : 2;
+    int ploff = mode == 2 ? 1 : 0;
+    int i;
+
+    if (header)
+       printf("extern ");
+    printf ("void set_hires_h_%d_%d (uae_u32 *app, uae_u8 *ptr, int len)", pl, mode);
+    if (header) {
+       printf (";\n");
+       return;
+    }
+
+    printf ("\n\{\n\tint i;\n\tfor (i = 0; i < len; i++) {\n\t\tuae_u32 v1, v2;\n");
+
+    if (mode == 2) {
+       printf ("\t\tv1 = app[i*2 + 0]; v2 = app[i*2 + 1];\n");
+    }
+
+    for (i = 0; i <= pl; i++) {
+       int realpl = i * plmul + ploff;
+       char *asgn = (i == 0 && mode != 2 ? "=" : "|=");
+       
+       printf ("\t\t{\n");
+       printf ("\t\t\tunsigned int data = *(ptr + i  + %d);\n", MAX_WORDS_PER_LINE*2*realpl);
+       
+       printf ("\t\t\tv1 %s hirestab_h[data][0] << %d;\n", asgn, realpl);
+       printf ("\t\t\tv2 %s hirestab_h[data][1] << %d;\n", asgn, realpl);
+       printf ("\t\t}\n");
+    }
+    printf ("\t\tapp[i*2 + 0] = v1;\n");
+    printf ("\t\tapp[i*2 + 1] = v2;\n");
+    printf ("\t}\n");
+    printf ("}\n\n");
+}
+
+/* Squeeze: every second bit does not generate a pixel 
+   Not optimized, this mode isn't useful. */
+static void gen_c_set_hires_l (int pl, int mode, int header)
+{
+    int plmul = mode == 0 ? 1 : 2;
+    int ploff = mode == 2 ? 1 : 0;
+    int i;
+
+    if (header)
+       printf("extern ");
+    printf ("void set_hires_l_%d_%d (uae_u32 *app, uae_u8 *ptr, int len)", pl, mode);
+    if (header) {
+       printf (";\n");
+       return;
+    }
+
+    printf ("\n\{\n\tint i;\n\tfor (i = 0; i < len; i++) {\n\t\tuae_u32 v1;\n");
+
+    if (mode == 2) {
+       printf ("\t\tv1 = app[i];\n");
+    }
+
+    for (i = 0; i <= pl; i++) {
+       int realpl = i * plmul + ploff;
+       char *asgn = (i == 0 && mode != 2 ? "=" : "|=");
+       
+       printf ("\t\t{\n");
+       printf ("\t\t\tunsigned int data = *(ptr + i  + %d);\n", MAX_WORDS_PER_LINE*2*realpl);
+
+       printf ("\t\t\tv1 %s hirestab_l[data][0] << %d;\n", asgn, realpl);
+       printf ("\t\t}\n");
+    }
+    printf ("\t\tapp[i] = v1;\n");
+    printf ("\t}\n");
+    printf ("}\n\n");
+}
+
+/* Stretch: two pixels per bit */
+static void gen_c_set_lores_h (int pl, int mode, int header)
+{
+    int plmul = mode == 0 ? 1 : 2;
+    int ploff = mode == 2 ? 1 : 0;
+    int i;
+
+    if (header)
+       printf("extern ");
+    printf ("void set_lores_h_%d_%d (uae_u32 *app, uae_u8 *ptr, int len)", pl, mode);
+    if (header) {
+       printf (";\n");
+       return;
+    }
+
+    printf ("\n\{\n\tint i;\n\tfor (i = 0; i < len; i++) {\n\t\tuae_u32 v1, v2, v3, v4;\n");
+
+    if (mode == 2) {
+       printf ("\t\tv1 = app[i*4 + 0]; v2 = app[i*4 + 1]; v3 = app[i*4 + 2]; v4 = app[i*4 + 3];\n");
+    }
+
+    for (i = 0; i <= pl; i++) {
+       int realpl = i * plmul + ploff;
+       char *asgn = (i == 0 && mode != 2 ? "=" : "|=");
+
+       printf ("\t\t{\n");
+       printf ("\t\t\tunsigned int data = *(ptr + i  + %d);\n", MAX_WORDS_PER_LINE*2*realpl);
+
+       printf ("\t\t\tv1 %s lorestab_h[data][0] << %d;\n", asgn, realpl);
+       printf ("\t\t\tv2 %s lorestab_h[data][1] << %d;\n", asgn, realpl);
+       printf ("\t\t\tv3 %s lorestab_h[data][2] << %d;\n", asgn, realpl);
+       printf ("\t\t\tv4 %s lorestab_h[data][3] << %d;\n", asgn, realpl);
+       printf ("\t\t}\n");
+    }
+    printf ("\t\tapp[i*4 + 0] = v1;\n");
+    printf ("\t\tapp[i*4 + 1] = v2;\n");
+    printf ("\t\tapp[i*4 + 2] = v3;\n");
+    printf ("\t\tapp[i*4 + 3] = v4;\n");
+    printf ("\t}\n");
+    printf ("}\n\n");
+}
+
+int main(int argc, char **argv)
+{
+    int pl;
+    int outmode;
+
+    if (argc != 2)
+       return 1;
+    if (strcmp (argv[1], "C") == 0)
+       outmode = 0;
+    else if (strcmp (argv[1], "H") == 0)
+       outmode = 1;
+    else if (strcmp (argv[1], "x86") == 0)
+       outmode = 2;
+    else
+       return 1;
+
+    switch (outmode) {
+     case 0:
+       printf ("#include \"sysconfig.h\"\n");
+       printf ("#include \"sysdeps.h\"\n");
+       printf ("#include \"custom.h\"\n");
+       printf ("#include \"p2c.h\"\n");
+       break;
+     case 1:
+       printf ("#define MAX_WORDS_PER_LINE %d\n", MAX_WORDS_PER_LINE);
+       break;
+     case 2:
+       printf ("#define MAX_WORDS_PER_LINE %d\n", MAX_WORDS_PER_LINE);
+       printf (".text\n");
+       break;
+    }
+    for (pl = 0; pl < 8; pl++) {
+       int j;
+       for (j = 0; j < (pl < 4 ? 3 : 1); j++) {
+           switch (outmode) {
+            case 0: case 1:
+               gen_c_set_hires_h (pl, j, outmode);
+               gen_c_set_hires_l (pl, j, outmode);
+               gen_c_set_lores_h (pl, j, outmode);
+               break;
+            case 2:
+               gen_x86_set_hires_h (pl, j);
+               gen_x86_set_hires_l (pl, j);
+               gen_x86_set_lores_h (pl, j);
+               break;
+           }
+       }
+    }
+
+    return 0;
+}
diff --git a/gfxlib.c b/gfxlib.c
new file mode 100755 (executable)
index 0000000..8c821ad
--- /dev/null
+++ b/gfxlib.c
@@ -0,0 +1,1682 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * graphics.library emulation
+  *
+  * Copyright 1996, 1997 Bernd Schmidt
+  *
+  * Ideas for this:
+  * Rewrite layers completely. When there are lots of windows on the screen
+  * it can take 3 minutes to update everything after resizing or moving one
+  * (at least with Kick 1.3). Hide the internal structure of the layers as far
+  * as possible, keep most of the data in emulator space so we save copying/
+  * conversion time. Programs really shouldn't do anything directly with the
+  * Layer or ClipRect structures.
+  * This means that a lot of graphics.library functions will have to be
+  * rewritten as well.
+  * Once that's done, add support for non-planar bitmaps. Conveniently, the
+  * struct Bitmap has an unused pad field which we could abuse as some sort of
+  * type field. Need to add chunky<->planar conversion routines to get it
+  * going, plus variants of all the drawing functions for speed reasons.
+  *
+  * When it becomes necessary to convert a structure from Amiga memory, make
+  * a function with a name ending in ..FA, which takes a pointer to the
+  * native structure and a uaecptr and returns the native pointer.
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <assert.h>
+
+#include "config.h"
+#include "options.h"
+#include "threaddep/thread.h"
+#include "memory.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "xwin.h"
+#include "autoconf.h"
+#include "osemu.h"
+#include "osdep/exectasks.h"
+
+#ifdef USE_EXECLIB
+
+/* Uniq list management. Should be in a separate file. */
+struct uniq_head {
+    struct uniq_head *next;
+    uae_u32 uniq;
+};
+
+typedef struct {
+    struct uniq_head *head;
+    uae_u32 uniq;
+} uniq_list;
+
+#define UNIQ_INIT { NULL, 1 }
+
+static void init_uniq(uniq_list *list)
+{
+    list->head = NULL;
+    list->uniq = 1;
+}
+
+static struct uniq_head *find_uniq (uniq_list *a, uae_u32 uniq)
+{
+    struct uniq_head *b = a->head;
+    while (b && b->uniq != uniq)
+       b = b->next;
+    if (!b)
+       write_log("Couldn't find structure. Bad\n");
+    return b;
+}
+
+static struct uniq_head *find_and_rem_uniq (uniq_list *a, uae_u32 uniq)
+{
+    struct uniq_head **b = &a->head, *c;
+    while (*b && (*b)->uniq != uniq)
+       b = &(*b)->next;
+    c = *b;
+    if (!c)
+       write_log("Couldn't find structure. Bad\n");
+    else
+       *b = c->next;
+    return c;
+}
+
+static void add_uniq (uniq_list *a, struct uniq_head *item, uaecptr amem)
+{
+    item->uniq = a->uniq++;
+    put_long(amem, item->uniq);
+    if (a->uniq == 0)
+       a->uniq++;
+    item->next = a->head;
+    a->head = item;
+}
+
+/* Graphics stuff begins here */
+#define CLIPRECT_SIZE 40
+#define LAYER_SIZE 160
+#define LINFO_SIZE 102
+
+static uaecptr gfxbase, layersbase;
+
+static void do_LockLayer(uaecptr layer)
+{
+#if 0 /* Later.. */
+    uaecptr sigsem = layer + 72;
+    m68k_areg(regs, 0) = sigsem;
+    CallLib(get_long(4), -564);
+#else
+    m68k_areg(regs, 1) = layer;
+    CallLib(layersbase, -96);
+#endif
+}
+
+static void do_UnlockLayer(uaecptr layer)
+{
+    m68k_areg(regs, 0) = layer;
+    CallLib(layersbase, -102);
+}
+
+static uae_u32 gfxlibname, layerslibname;
+
+struct Rectangle {
+    int MinX, MinY, MaxX, MaxY;
+};
+
+static int GFX_PointInRectangle(uaecptr rect, int x, int y)
+{
+    uae_s16 minx = get_word(rect);
+    uae_s16 miny = get_word(rect+2);
+    uae_s16 maxx = get_word(rect+4);
+    uae_s16 maxy = get_word(rect+6);
+
+    if (x < minx || x > maxx || y < miny || y > maxy)
+       return 0;
+    return 1;
+}
+
+static int GFX_RectContainsRect(struct Rectangle *r1, struct Rectangle *r2)
+{
+    return (r2->MinX >= r1->MinX && r2->MaxX <= r1->MaxX
+           && r2->MinY >= r1->MinY && r2->MaxY <= r1->MaxY);
+}
+
+static struct Rectangle *GFX_RectFA(struct Rectangle *rp, uaecptr rect)
+{
+    rp->MinX = (uae_s16)get_word(rect);
+    rp->MinY = (uae_s16)get_word(rect+2);
+    rp->MaxX = (uae_s16)get_word(rect+4);
+    rp->MaxY = (uae_s16)get_word(rect+6);
+    return rp;
+}
+
+static int GFX_Bitmap_WritePixel(uaecptr bitmap, int x, int y, uaecptr rp)
+{
+    int i, offs;
+    unsigned int bpr = get_word (bitmap);
+    unsigned int rows = get_word (bitmap + 2);
+    uae_u16 mask;
+
+    uae_u8 planemask = get_byte(rp + 24);
+    uae_u8 fgpen = get_byte(rp + 25);
+    uae_u8 bgpen = get_byte(rp + 26);
+    uae_u8 drmd = get_byte(rp + 28);
+    uae_u8 pen = drmd & 4 ? bgpen : fgpen;
+
+    if (x < 0 || y < 0 || x >= 8*bpr || y >= rows)
+       return -1;
+
+    offs = y*bpr + (x & ~15)/8;
+
+    for (i = 0; i < get_byte (bitmap + 5); i++) {
+       uaecptr planeptr;
+       uae_u16 data;
+
+       if ((planemask & (1 << i)) == 0)
+           continue;
+
+       planeptr = get_long(bitmap + 8 + i*4);
+       data = get_word(planeptr + offs);
+
+       mask = 0x8000 >> (x & 15);
+
+       if (drmd & 2) {
+           if ((pen & (1 << i)) != 0)
+               data ^=mask;
+       } else {
+           data &= ~mask;
+           if ((pen & (1 << i)) != 0)
+               data |= mask;
+       }
+       put_word(planeptr + offs, data);
+    }
+    return 0;
+}
+
+int GFX_WritePixel(uaecptr rp, int x, int y)
+{
+    int v;
+    uaecptr layer = get_long(rp);
+    uaecptr bitmap = get_long(rp + 4);
+    uaecptr cliprect;
+    int x2, y2;
+
+    if (bitmap == 0) {
+       write_log ("bogus RastPort in WritePixel\n");
+       return -1;
+    }
+
+    /* Easy case first */
+    if (layer == 0) {
+       return GFX_Bitmap_WritePixel(bitmap, x, y, rp);
+    }
+    do_LockLayer(layer);
+    /*
+     * Now, in theory we ought to obtain the semaphore.
+     * Since we don't, the programs will happily write into the raster
+     * even though we are currently moving the window around.
+     * Not good.
+     */
+
+    x2 = x + (uae_s16)get_word(layer + 16);
+    y2 = y + (uae_s16)get_word(layer + 18);
+
+    if (!GFX_PointInRectangle (layer + 16, x2, y2)) {
+       do_UnlockLayer(layer);
+       return -1;
+    }
+    /* Find the right ClipRect */
+    cliprect = get_long(layer + 8);
+    while (cliprect != 0 && !GFX_PointInRectangle (cliprect + 16, x2, y2))
+       cliprect = get_long(cliprect);
+    if (cliprect == 0) {
+       /* Don't complain: The "Dots" demo does this all the time. I
+        * suppose if we can't find a ClipRect, we aren't supposed to draw
+        * the dot.
+        */
+       /*write_log ("Weirdness in WritePixel\n");*/
+       v = -1;
+    } else if (get_long(cliprect + 8) == 0) {
+       v = GFX_Bitmap_WritePixel(bitmap, x2, y2, rp);
+    } else if (get_long(cliprect + 12) == 0) {
+       /* I don't really know what to do here... */
+       v = 0;
+    } else {
+       /* This appears to be normal for smart refresh layers which are obscured */
+       v = GFX_Bitmap_WritePixel (get_long(cliprect + 12), x2 - (uae_s16)get_word(cliprect + 16),
+                                  y2 - (uae_s16)get_word(cliprect + 18), rp);
+    }
+    do_UnlockLayer(layer);
+    return v;
+}
+
+
+static uae_u32 gfxl_WritePixel(void) { return GFX_WritePixel(m68k_areg(regs, 1), (uae_s16)m68k_dreg(regs, 0), (uae_s16)m68k_dreg(regs, 1)); }
+
+static uae_u32 gfxl_BltClear(void)
+{
+    uaecptr mem=m68k_areg(regs, 1);
+    uae_u8 *mptr = chipmem_bank.xlateaddr(m68k_areg(regs, 1));
+    uae_u32 count=m68k_dreg(regs, 0);
+    uae_u32 flags=m68k_dreg(regs, 1);
+    unsigned int i;
+    uae_u32 pattern;
+
+    if ((flags & 2) == 2){
+       /* count is given in Rows / Bytes per row */
+       count=(count & 0xFFFF) * (count >> 16);
+    }
+
+    if ((mem & 1) != 0 || (count & 1) != 0)
+       write_log ("gfx: BltClear called with odd parameters\n");
+
+    /* Bit 2 set means use pattern (V36+ only, but we might as well emulate
+     * it always) */
+    if ((flags & 4) == 0)
+       pattern = 0;
+    else
+       pattern= ((flags >> 16) & 0xFFFF) | (flags & 0xFFFF0000ul);
+
+    if ((pattern & 0xFF) == ((pattern >> 8) & 0xFF)) {
+       memset(mptr, pattern, count);
+       return 0;
+    }
+
+    for(i = 0; i < count; i += 4)
+       chipmem_bank.lput(mem+i, pattern);
+
+    if ((count & 3) != 0)
+       chipmem_bank.wput(mem + i - 4, pattern);
+
+    return 0;
+}
+
+static uae_u32 gfxl_BltBitmap(void)
+{
+    uaecptr srcbitmap = m68k_areg(regs, 0), dstbitmap = m68k_areg(regs, 1);
+    int srcx = (uae_s16)m68k_dreg(regs, 0), srcy = (uae_s16)m68k_dreg(regs, 1);
+    int dstx = (uae_s16)m68k_dreg(regs, 2), dsty = (uae_s16)m68k_dreg(regs, 3);
+    int sizex = (uae_s16)m68k_dreg(regs, 4), sizey = (uae_s16)m68k_dreg(regs, 5);
+    uae_u8 minterm = (uae_u8)m68k_dreg(regs, 6), mask = m68k_dreg(regs, 7);
+    return 0; /* sam: a return was missing here ! */
+}
+
+static uaecptr amiga_malloc(int len)
+{
+    m68k_dreg(regs, 0) = len;
+    m68k_dreg(regs, 1) = 1; /* MEMF_PUBLIC */
+    return CallLib(get_long(4), -198); /* AllocMem */
+}
+
+static void amiga_free(uaecptr addr, int len)
+{
+    m68k_areg(regs, 1) = addr;
+    m68k_dreg(regs, 0) = len;
+    CallLib(get_long(4), -210); /* FreeMem */
+}
+
+/*
+ * Region handling code
+ *
+ * General ideas stolen from xc/verylongpath/miregion.c
+ *
+ * The Clear code is untested. And and Or seem to work, Xor is only used
+ * by the 1.3 Prefs program and seems to work, too.
+ */
+
+struct RegionRectangle {
+    struct RegionRectangle *Next,*Prev;
+    struct Rectangle bounds;
+};
+
+struct Region {
+    struct Rectangle bounds;
+    struct RegionRectangle *RegionRectangle;
+};
+
+struct RectList {
+    int count;
+    int space;
+    struct Rectangle bounds;
+    struct Rectangle *rects;
+};
+
+struct BandList {
+    int count;
+    int space;
+    int *miny, *maxy;
+};
+
+static void init_bandlist(struct BandList *bl)
+{
+    bl->count = 0;
+    bl->space = 20;
+    bl->miny = (int *)malloc(20*sizeof(int));
+    bl->maxy = (int *)malloc(20*sizeof(int));
+}
+
+static void dup_bandlist(struct BandList *to, struct BandList *from)
+{
+    to->count = from->count;
+    to->space = to->count+4;
+    to->miny = (int *)malloc (to->space*sizeof(int));
+    to->maxy = (int *)malloc (to->space*sizeof(int));
+    memcpy(to->miny, from->miny, to->count*sizeof(int));
+    memcpy(to->maxy, from->maxy, to->count*sizeof(int));
+}
+
+STATIC_INLINE void add_band(struct BandList *bl, int miny, int maxy, int pos)
+{
+    if (bl->count == bl->space) {
+       bl->space += 20;
+       bl->miny = (int *)realloc(bl->miny, bl->space*sizeof(int));
+       bl->maxy = (int *)realloc(bl->maxy, bl->space*sizeof(int));
+    }
+    memmove(bl->miny + pos + 1, bl->miny + pos, (bl->count - pos) * sizeof(int));
+    memmove(bl->maxy + pos + 1, bl->maxy + pos, (bl->count - pos) * sizeof(int));
+    bl->count++;
+    bl->miny[pos] = miny;
+    bl->maxy[pos] = maxy;
+}
+
+static void init_rectlist(struct RectList *rl)
+{
+    rl->count = 0;
+    rl->space = 100;
+    rl->bounds.MinX = rl->bounds.MinY = rl->bounds.MaxX = rl->bounds.MaxY = 0;
+    rl->rects = (struct Rectangle *)malloc(100*sizeof(struct Rectangle));
+}
+
+static void dup_rectlist(struct RectList *to, struct RectList *from)
+{
+    to->count = from->count;
+    to->space = to->count+4;
+    to->bounds = from->bounds;
+    to->rects = (struct Rectangle *)malloc (to->space*sizeof(struct Rectangle));
+    memcpy(to->rects, from->rects, to->count*sizeof(struct Rectangle));
+}
+
+STATIC_INLINE void add_rect(struct RectList *rl, struct Rectangle r)
+{
+    if (rl->count == 0)
+       rl->bounds = r;
+    else {
+       if (r.MinX < rl->bounds.MinX)
+           rl->bounds.MinX = r.MinX;
+       if (r.MinY < rl->bounds.MinY)
+           rl->bounds.MinY = r.MinY;
+       if (r.MaxX > rl->bounds.MaxX)
+           rl->bounds.MaxX = r.MaxX;
+       if (r.MaxY > rl->bounds.MaxY)
+           rl->bounds.MaxY = r.MaxY;
+    }
+    if (rl->count == rl->space) {
+       rl->space += 100;
+       rl->rects = (struct Rectangle *)realloc(rl->rects, rl->space*sizeof(struct Rectangle));
+    }
+    rl->rects[rl->count++] = r;
+}
+
+STATIC_INLINE void rem_rect(struct RectList *rl, int num)
+{
+    rl->count--;
+    if (num == rl->count)
+       return;
+    rl->rects[num] = rl->rects[rl->count];
+}
+
+static void free_rectlist(struct RectList *rl)
+{
+    free(rl->rects);
+}
+
+static void free_bandlist(struct BandList *bl)
+{
+    free(bl->miny);
+    free(bl->maxy);
+}
+
+static int regionrect_cmpfn(const void *a, const void *b)
+{
+    struct Rectangle *ra = (struct Rectangle *)a;
+    struct Rectangle *rb = (struct Rectangle *)b;
+
+    if (ra->MinY < rb->MinY)
+       return -1;
+    if (ra->MinY > rb->MinY)
+       return 1;
+    if (ra->MinX < rb->MinX)
+       return -1;
+    if (ra->MinX > rb->MinX)
+       return 1;
+    if (ra->MaxX < rb->MaxX)
+       return -1;
+    return 1;
+}
+
+STATIC_INLINE int min(int x, int y)
+{
+    return x < y ? x : y;
+}
+
+STATIC_INLINE int max(int x, int y)
+{
+    return x > y ? x : y;
+}
+
+static void add_rect_to_bands(struct BandList *bl, struct Rectangle *rect)
+{
+    int j;
+    struct Rectangle tmpr = *rect;
+
+    for (j = 0; j < bl->count; j++) {
+       /* Is the current band before the rectangle? */
+       if (bl->maxy[j] < tmpr.MinY)
+           continue;
+       /* Band already present? */
+       if (bl->miny[j] == tmpr.MinY && bl->maxy[j] == tmpr.MaxY)
+           break;
+       /* Completely new band? Add it */
+       if (bl->miny[j] > tmpr.MaxY) {
+           add_band(bl, tmpr.MinY, tmpr.MaxY, j);
+           break;
+       }
+       /* Now we know that the bands are overlapping.
+        * See whether they match in one point */
+       if (bl->miny[j] == tmpr.MinY) {
+           int t;
+           if (bl->maxy[j] < tmpr.MaxY) {
+               /* Rectangle exceeds band */
+               tmpr.MinY = bl->maxy[j]+1;
+               continue;
+           }
+           /* Rectangle splits band */
+           t = bl->maxy[j];
+           bl->maxy[j] = tmpr.MaxY;
+           tmpr.MinY = bl->maxy[j] + 1;
+           tmpr.MaxY = t;
+           continue;
+       } else if (bl->maxy[j] == tmpr.MaxY) {
+           int t;
+           if (bl->miny[j] > tmpr.MinY) {
+               /* Rectangle exceeds band */
+               t = bl->miny[j];
+               bl->miny[j] = tmpr.MinY;
+               bl->maxy[j] = t-1;
+               tmpr.MinY = t;
+               continue;
+           }
+           /* Rectangle splits band */
+           bl->maxy[j] = tmpr.MinY - 1;
+           continue;
+       }
+       /* Bands overlap and match in no points. Get a new band and align */
+       if (bl->miny[j] > tmpr.MinY) {
+           /* Rectangle begins before band, so make a new band before
+            * and adjust rectangle */
+           add_band(bl, tmpr.MinY, bl->miny[j] - 1, j);
+           tmpr.MinY = bl->miny[j+1];
+       } else {
+           /* Rectangle begins in band */
+           add_band(bl, bl->miny[j], tmpr.MinY - 1, j);
+           bl->miny[j+1] = tmpr.MinY;
+       }
+       continue;
+    }
+    if (j == bl->count)
+       add_band(bl, tmpr.MinY, tmpr.MaxY, j);
+}
+
+static void region_addbands(struct RectList *rl, struct BandList *bl)
+{
+    int i,j;
+
+    for (i = 0; i < rl->count; i++) {
+       add_rect_to_bands(bl, rl->rects + i);
+    }
+}
+
+static void merge_bands(struct BandList *dest, struct BandList *src)
+{
+    int i;
+    for (i = 0; i < src->count; i++) {
+       struct Rectangle tmp;
+       tmp.MinY = src->miny[i];
+       tmp.MaxY = src->maxy[i];
+       add_rect_to_bands(dest, &tmp);
+    }
+}
+
+static void region_splitrects_band(struct RectList *rl, struct BandList *bl)
+{
+    int i,j;
+    for (i = 0; i < rl->count; i++) {
+       for (j = 0; j < bl->count; j++) {
+           if (bl->miny[j] == rl->rects[i].MinY && bl->maxy[j] == rl->rects[i].MaxY)
+               break;
+           if (rl->rects[i].MinY > bl->maxy[j])
+               continue;
+           if (bl->miny[j] == rl->rects[i].MinY) {
+               struct Rectangle tmpr;
+               tmpr.MinX = rl->rects[i].MinX;
+               tmpr.MaxX = rl->rects[i].MaxX;
+               tmpr.MinY = bl->maxy[j] + 1;
+               tmpr.MaxY = rl->rects[i].MaxY;
+               add_rect(rl, tmpr); /* will be processed later */
+               rl->rects[i].MaxY = bl->maxy[j];
+               break;
+           }
+           write_log ("Foo..\n");
+       }
+    }
+    qsort(rl->rects, rl->count, sizeof (struct Rectangle), regionrect_cmpfn);
+}
+
+static void region_coalesce_rects(struct RectList *rl, int do_2nd_pass)
+{
+    int i,j;
+
+    /* First pass: Coalesce horizontally */
+    for (i = j = 0; i < rl->count;) {
+       int offs = 1;
+       while (i + offs < rl->count) {
+           if (rl->rects[i].MinY != rl->rects[i+offs].MinY
+               || rl->rects[i].MaxY != rl->rects[i+offs].MaxY
+               || rl->rects[i].MaxX+1 < rl->rects[i+offs].MinX)
+               break;
+           rl->rects[i].MaxX = rl->rects[i+offs].MaxX;
+           offs++;
+       }
+       rl->rects[j++] = rl->rects[i];
+       i += offs;
+    }
+    rl->count = j;
+
+    if (!do_2nd_pass)
+       return;
+
+    /* Second pass: Coalesce bands */
+    for (i = 0; i < rl->count;) {
+       int match = 0;
+       for (j = i + 1; j < rl->count; j++)
+           if (rl->rects[i].MinY != rl->rects[j].MinY)
+               break;
+       if (j < rl->count && rl->rects[i].MaxY + 1 == rl->rects[j].MinY) {
+           int k;
+           match = 1;
+           for (k = 0; i+k < j; k++) {
+               if (j+k >= rl->count
+                   || rl->rects[j+k].MinY != rl->rects[j].MinY)
+               {
+                   match = 0; break;
+               }
+               if (rl->rects[i+k].MinX != rl->rects[j+k].MinX
+                   || rl->rects[i+k].MaxX != rl->rects[j+k].MaxX)
+               {
+                   match = 0;
+                   break;
+               }
+           }
+           if (j+k < rl->count && rl->rects[j+k].MinY == rl->rects[j].MinY)
+               match = 0;
+           if (match) {
+               for (k = 0; i+k < j; k++)
+                   rl->rects[i+k].MaxY = rl->rects[j].MaxY;
+               memmove(rl->rects + j, rl->rects + j + k, (rl->count - j - k)*sizeof(struct Rectangle));
+               rl->count -= k;
+           }
+       }
+       if (!match)
+           i = j;
+    }
+}
+
+static int copy_rects (uaecptr region, struct RectList *rl)
+{
+    uaecptr regionrect;
+    int numrects = 0;
+    struct Rectangle b;
+    regionrect = get_long(region+8);
+    b.MinX = get_word(region);
+    b.MinY = get_word(region+2);
+    b.MaxX = get_word(region+4);
+    b.MaxY = get_word(region+6);
+
+    while (regionrect != 0) {
+       struct Rectangle tmpr;
+
+       tmpr.MinX = (uae_s16)get_word(regionrect+8)  + b.MinX;
+       tmpr.MinY = (uae_s16)get_word(regionrect+10) + b.MinY;
+       tmpr.MaxX = (uae_s16)get_word(regionrect+12) + b.MinX;
+       tmpr.MaxY = (uae_s16)get_word(regionrect+14) + b.MinY;
+       add_rect(rl, tmpr);
+       regionrect = get_long(regionrect);
+       numrects++;
+    }
+    return numrects;
+}
+
+static int rect_in_region(struct RectList *rl, struct Rectangle *r)
+{
+    int i;
+    int miny = r->MinY;
+
+    for (i = 0; i < rl->count; i++) {
+       int j;
+       if (rl->rects[i].MaxY < miny)
+           continue;
+       if (rl->rects[i].MinY > miny)
+           break;
+       if (rl->rects[i].MaxX < r->MinX)
+           continue;
+       if (rl->rects[i].MinX > r->MaxX)
+           break;
+       /* Overlap! */
+       j = i;
+       for (;;) {
+           if (rl->rects[j].MaxX > r->MaxX) {
+               miny = rl->rects[i].MaxY + 1;
+               break;
+           }
+           j++;
+           if (j == rl->count)
+               break;
+           if (rl->rects[j].MinX != rl->rects[j-1].MaxX+1)
+               break;
+           if (rl->rects[i].MinY != rl->rects[j].MinY)
+               break;
+       }
+       if (miny <= rl->rects[i].MaxY)
+           break;
+    }
+    return 0;
+}
+
+typedef void (*regionop)(struct RectList *,struct RectList *,struct RectList *);
+
+static void region_do_ClearRegionRegion(struct RectList *rl1,struct RectList *rl2,
+                                       struct RectList *rl3)
+{
+    int i,j;
+
+    for (i = j = 0; i < rl2->count && j < rl1->count;) {
+       struct Rectangle tmpr;
+
+       while ((rl1->rects[j].MinY < rl2->rects[i].MinY
+               || (rl1->rects[j].MinY == rl2->rects[i].MinY
+                   && rl1->rects[j].MaxX < rl2->rects[i].MinX))
+              && j < rl1->count)
+           j++;
+       if (j >= rl1->count)
+           break;
+       while ((rl1->rects[j].MinY > rl2->rects[i].MinY
+               || (rl1->rects[j].MinY == rl2->rects[i].MinY
+                   && rl1->rects[j].MinX > rl2->rects[i].MaxX))
+              && i < rl2->count)
+       {
+           add_rect(rl3, rl2->rects[i]);
+           i++;
+       }
+       if (i >= rl2->count)
+           break;
+
+       tmpr = rl2->rects[i];
+
+       while (i < rl2->count && j < rl1->count
+              && rl1->rects[j].MinY == tmpr.MinY
+              && rl2->rects[i].MinY == tmpr.MinY
+              && rl1->rects[j].MinX <= rl2->rects[i].MaxX
+              && rl1->rects[j].MaxX >= rl2->rects[i].MinX)
+       {
+           int oldmin = tmpr.MinX;
+           int oldmax = tmpr.MaxX;
+           if (tmpr.MinX < rl1->rects[j].MinX) {
+               tmpr.MaxX = rl1->rects[j].MinX - 1;
+               add_rect(rl3, tmpr);
+           }
+           if (oldmax <= rl1->rects[j].MaxX) {
+               i++;
+               if (i < rl2->count && rl2->rects[i].MinY == tmpr.MinY)
+                   tmpr = rl2->rects[i];
+           } else {
+               tmpr.MinX = rl1->rects[j].MaxX + 1;
+               tmpr.MaxX = oldmax;
+               j++;
+           }
+       }
+    }
+    for(; i < rl2->count; i++)
+       add_rect(rl3, rl2->rects[i]);
+}
+
+static void region_do_AndRegionRegion(struct RectList *rl1,struct RectList *rl2,
+                                     struct RectList *rl3)
+{
+    int i,j;
+
+    for (i = j = 0; i < rl2->count && j < rl1->count;) {
+       while ((rl1->rects[j].MinY < rl2->rects[i].MinY
+               || (rl1->rects[j].MinY == rl2->rects[i].MinY
+                   && rl1->rects[j].MaxX < rl2->rects[i].MinX))
+              && j < rl1->count)
+           j++;
+       if (j >= rl1->count)
+           break;
+       while ((rl1->rects[j].MinY > rl2->rects[i].MinY
+               || (rl1->rects[j].MinY == rl2->rects[i].MinY
+                   && rl1->rects[j].MinX > rl2->rects[i].MaxX))
+              && i < rl2->count)
+           i++;
+       if (i >= rl2->count)
+           break;
+       if (rl1->rects[j].MinY == rl2->rects[i].MinY
+           && rl1->rects[j].MinX <= rl2->rects[i].MaxX
+           && rl1->rects[j].MaxX >= rl2->rects[i].MinX)
+       {
+           /* We have an intersection! */
+           struct Rectangle tmpr;
+           tmpr = rl2->rects[i];
+           if (tmpr.MinX < rl1->rects[j].MinX)
+               tmpr.MinX = rl1->rects[j].MinX;
+           if (tmpr.MaxX > rl1->rects[j].MaxX)
+               tmpr.MaxX = rl1->rects[j].MaxX;
+           add_rect(rl3, tmpr);
+           if (rl1->rects[j].MaxX == rl2->rects[i].MaxX)
+               i++, j++;
+           else if (rl1->rects[j].MaxX > rl2->rects[i].MaxX)
+               i++;
+           else
+               j++;
+       }
+    }
+}
+
+static void region_do_OrRegionRegion(struct RectList *rl1,struct RectList *rl2,
+                                    struct RectList *rl3)
+{
+    int i,j;
+
+    for (i = j = 0; i < rl2->count && j < rl1->count;) {
+       while ((rl1->rects[j].MinY < rl2->rects[i].MinY
+               || (rl1->rects[j].MinY == rl2->rects[i].MinY
+                   && rl1->rects[j].MaxX < rl2->rects[i].MinX))
+              && j < rl1->count)
+       {
+           add_rect(rl3, rl1->rects[j]);
+           j++;
+       }
+       if (j >= rl1->count)
+           break;
+       while ((rl1->rects[j].MinY > rl2->rects[i].MinY
+               || (rl1->rects[j].MinY == rl2->rects[i].MinY
+                   && rl1->rects[j].MinX > rl2->rects[i].MaxX))
+              && i < rl2->count)
+       {
+           add_rect(rl3, rl2->rects[i]);
+           i++;
+       }
+       if (i >= rl2->count)
+           break;
+       if (rl1->rects[j].MinY == rl2->rects[i].MinY
+           && rl1->rects[j].MinX <= rl2->rects[i].MaxX
+           && rl1->rects[j].MaxX >= rl2->rects[i].MinX)
+       {
+           /* We have an intersection! */
+           struct Rectangle tmpr;
+           tmpr = rl2->rects[i];
+           if (tmpr.MinX > rl1->rects[j].MinX)
+               tmpr.MinX = rl1->rects[j].MinX;
+           if (tmpr.MaxX < rl1->rects[j].MaxX)
+               tmpr.MaxX = rl1->rects[j].MaxX;
+           i++; j++;
+           for (;;) {
+               int cont = 0;
+               if (j < rl1->count && rl1->rects[j].MinY == tmpr.MinY
+                   && tmpr.MaxX+1 >= rl1->rects[j].MinX) {
+                   if (tmpr.MaxX < rl1->rects[j].MaxX)
+                       tmpr.MaxX = rl1->rects[j].MaxX;
+                   j++; cont = 1;
+               }
+               if (i < rl2->count && rl2->rects[i].MinY == tmpr.MinY
+                   && tmpr.MaxX+1 >= rl2->rects[i].MinX) {
+                   if (tmpr.MaxX < rl2->rects[i].MaxX)
+                       tmpr.MaxX = rl2->rects[i].MaxX;
+                   i++; cont = 1;
+               }
+               if (!cont)
+                   break;
+           }
+           add_rect(rl3, tmpr);
+       }
+    }
+    for(; i < rl2->count; i++)
+       add_rect(rl3, rl2->rects[i]);
+    for(; j < rl1->count; j++)
+       add_rect(rl3, rl1->rects[j]);
+}
+
+static void region_do_XorRegionRegion(struct RectList *rl1,struct RectList *rl2,
+                                     struct RectList *rl3)
+{
+    int i,j;
+
+    for (i = j = 0; i < rl2->count && j < rl1->count;) {
+       struct Rectangle tmpr1, tmpr2;
+
+       while ((rl1->rects[j].MinY < rl2->rects[i].MinY
+               || (rl1->rects[j].MinY == rl2->rects[i].MinY
+                   && rl1->rects[j].MaxX < rl2->rects[i].MinX))
+              && j < rl1->count)
+       {
+           add_rect(rl3, rl1->rects[j]);
+           j++;
+       }
+       if (j >= rl1->count)
+           break;
+       while ((rl1->rects[j].MinY > rl2->rects[i].MinY
+               || (rl1->rects[j].MinY == rl2->rects[i].MinY
+                   && rl1->rects[j].MinX > rl2->rects[i].MaxX))
+              && i < rl2->count)
+       {
+           add_rect(rl3, rl2->rects[i]);
+           i++;
+       }
+       if (i >= rl2->count)
+           break;
+
+       tmpr2 = rl2->rects[i];
+       tmpr1 = rl1->rects[j];
+
+       while (i < rl2->count && j < rl1->count
+              && rl1->rects[j].MinY == tmpr1.MinY
+              && rl2->rects[i].MinY == tmpr1.MinY
+              && rl1->rects[j].MinX <= rl2->rects[i].MaxX
+              && rl1->rects[j].MaxX >= rl2->rects[i].MinX)
+       {
+           int oldmin2 = tmpr2.MinX;
+           int oldmax2 = tmpr2.MaxX;
+           int oldmin1 = tmpr1.MinX;
+           int oldmax1 = tmpr1.MaxX;
+           int need_1 = 0, need_2 = 0;
+
+           if (tmpr2.MinX > tmpr1.MinX && tmpr2.MaxX < tmpr1.MaxX)
+           {
+               /*
+                *    ###########
+                *       ****
+                */
+               tmpr1.MaxX = tmpr2.MinX - 1;
+               add_rect(rl3, tmpr1);
+               tmpr1.MaxX = oldmax1;
+               tmpr1.MinX = tmpr2.MaxX + 1;
+               add_rect(rl3, tmpr1);
+               need_2 = 1;
+           } else if (tmpr2.MinX > tmpr1.MinX && tmpr2.MaxX > tmpr1.MaxX) {
+               /*
+                *    ##########
+                *       *********
+                */
+               tmpr1.MaxX = tmpr2.MinX - 1;
+               add_rect(rl3, tmpr1);
+               tmpr2.MinX = oldmax1 + 1;
+               add_rect(rl3, tmpr2);
+               need_1 = 1;
+           } else if (tmpr2.MinX < tmpr1.MinX && tmpr2.MaxX < tmpr1.MaxX) {
+               /*
+                *       ##########
+                *    *********
+                */
+               tmpr2.MaxX = tmpr1.MinX - 1;
+               add_rect(rl3, tmpr2);
+               tmpr1.MinX = oldmax2 + 1;
+               add_rect(rl3, tmpr1);
+               need_2 = 1;
+           } else if (tmpr2.MinX < tmpr1.MinX && tmpr2.MaxX > tmpr1.MaxX) {
+               /*
+                *       ###
+                *    *********
+                */
+               tmpr2.MaxX = tmpr1.MinX - 1;
+               add_rect(rl3, tmpr2);
+               tmpr2.MaxX = oldmax2;
+               tmpr2.MinX = tmpr1.MaxX + 1;
+               add_rect(rl3, tmpr2);
+               need_1 = 1;
+           } else if (tmpr1.MinX == tmpr2.MinX && tmpr2.MaxX < tmpr1.MaxX) {
+               /*
+                *    #############
+                *    *********
+                */
+               tmpr1.MinX = tmpr2.MaxX + 1;
+               need_2 = 1;
+           } else if (tmpr1.MinX == tmpr2.MinX && tmpr2.MaxX > tmpr1.MaxX) {
+               /*
+                *    #########
+                *    *************
+                */
+               tmpr2.MinX = tmpr1.MaxX + 1;
+               need_1 = 1;
+           } else if (tmpr1.MinX < tmpr2.MinX && tmpr2.MaxX == tmpr1.MaxX) {
+               /*
+                *    #############
+                *        *********
+                */
+               tmpr1.MaxX = tmpr2.MinX - 1;
+               add_rect(rl3, tmpr1);
+               need_2 = need_1 = 1;
+           } else if (tmpr1.MinX > tmpr2.MinX && tmpr2.MaxX == tmpr1.MaxX) {
+               /*
+                *        #########
+                *    *************
+                */
+               tmpr2.MaxX = tmpr1.MinX - 1;
+               add_rect(rl3, tmpr2);
+               need_2 = need_1 = 1;
+           } else {
+               assert(tmpr1.MinX == tmpr2.MinX && tmpr2.MaxX == tmpr1.MaxX);
+               need_1 = need_2 = 1;
+           }
+           if (need_1) {
+               j++;
+               if (j < rl1->count && rl1->rects[j].MinY == tmpr1.MinY)
+                   tmpr1 = rl1->rects[j];
+           }
+           if (need_2) {
+               i++;
+               if (i < rl2->count && rl2->rects[i].MinY == tmpr2.MinY)
+                   tmpr2 = rl2->rects[i];
+           }
+       }
+    }
+    for(; i < rl2->count; i++)
+       add_rect(rl3, rl2->rects[i]);
+    for(; j < rl1->count; j++)
+       add_rect(rl3, rl1->rects[j]);
+}
+
+static uae_u32 gfxl_perform_regionop(regionop op, int with_rect)
+{
+    int i,j,k;
+    uaecptr reg1;
+    uaecptr reg2;
+    uaecptr tmp, rpp;
+    struct RectList rl1, rl2, rl3;
+    struct BandList bl;
+
+    int retval = 0;
+    int numrects2;
+
+    init_rectlist(&rl1); init_rectlist(&rl2); init_rectlist(&rl3);
+
+    if (with_rect) {
+       struct Rectangle tmpr;
+       reg2 = m68k_areg(regs, 0);
+       numrects2 = copy_rects(reg2, &rl2);
+       tmpr.MinX = get_word(m68k_areg(regs, 1));
+       tmpr.MinY = get_word(m68k_areg(regs, 1) + 2);
+       tmpr.MaxX = get_word(m68k_areg(regs, 1) + 4);
+       tmpr.MaxY = get_word(m68k_areg(regs, 1) + 6);
+       add_rect(&rl1, tmpr);
+    } else {
+       reg1 = m68k_areg(regs, 0);
+       reg2 = m68k_areg(regs, 1);
+
+       copy_rects(reg1, &rl1);
+       numrects2 = copy_rects(reg2, &rl2);
+    }
+
+    init_bandlist(&bl);
+    region_addbands(&rl1, &bl);
+    region_addbands(&rl2, &bl);
+    region_splitrects_band(&rl1, &bl);
+    region_splitrects_band(&rl2, &bl);
+    region_coalesce_rects(&rl1, 0);
+    region_coalesce_rects(&rl2, 0);
+
+    (*op)(&rl1, &rl2, &rl3);
+    region_coalesce_rects(&rl3, 1);
+
+    rpp = reg2 + 8;
+    if (rl3.count < numrects2) {
+       while (numrects2-- != rl3.count) {
+           tmp = get_long(rpp);
+           put_long(rpp, get_long(tmp));
+           amiga_free(tmp, 16);
+       }
+       if (rl3.count > 0)
+           put_long(get_long(rpp) + 4, rpp);
+    } else if (rl3.count > numrects2) {
+       while(numrects2++ != rl3.count) {
+           uaecptr prev = get_long(rpp);
+           tmp = amiga_malloc(16);
+           if (tmp == 0)
+               goto done;
+           put_long(tmp, prev);
+           put_long(tmp + 4, rpp);
+           if (prev != 0)
+               put_long(prev + 4, tmp);
+           put_long(rpp, tmp);
+       }
+    }
+
+    if (rl3.count > 0) {
+       rpp = reg2 + 8;
+       for (i = 0; i < rl3.count; i++) {
+           uaecptr rr = get_long(rpp);
+           put_word(rr+8, rl3.rects[i].MinX - rl3.bounds.MinX);
+           put_word(rr+10, rl3.rects[i].MinY - rl3.bounds.MinY);
+           put_word(rr+12, rl3.rects[i].MaxX - rl3.bounds.MinX);
+           put_word(rr+14, rl3.rects[i].MaxY - rl3.bounds.MinY);
+           rpp = rr;
+       }
+       if (get_long(rpp) != 0)
+           write_log ("BUG\n");
+    }
+    put_word(reg2+0, rl3.bounds.MinX);
+    put_word(reg2+2, rl3.bounds.MinY);
+    put_word(reg2+4, rl3.bounds.MaxX);
+    put_word(reg2+6, rl3.bounds.MaxY);
+    retval = 1;
+
+    done:
+    free_rectlist(&rl1); free_rectlist(&rl2); free_rectlist(&rl3);
+    free_bandlist(&bl);
+
+    return retval;
+}
+
+static uae_u32 gfxl_AndRegionRegion(void)
+{
+    return gfxl_perform_regionop(region_do_AndRegionRegion, 0);
+}
+static uae_u32 gfxl_XorRegionRegion(void)
+{
+    return gfxl_perform_regionop(region_do_XorRegionRegion, 0);
+}
+static uae_u32 gfxl_OrRegionRegion(void)
+{
+    return gfxl_perform_regionop(region_do_OrRegionRegion, 0);
+}
+
+static uae_u32 gfxl_ClearRectRegion(void)
+{
+    return gfxl_perform_regionop(region_do_ClearRegionRegion, 1);
+}
+static uae_u32 gfxl_OrRectRegion(void)
+{
+    return gfxl_perform_regionop(region_do_OrRegionRegion, 1);
+}
+
+static uae_u32 gfxl_AndRectRegion(void)
+{
+    return gfxl_perform_regionop(region_do_AndRegionRegion, 1);
+}
+
+static uae_u32 gfxl_XorRectRegion(void)
+{
+    return gfxl_perform_regionop(region_do_XorRegionRegion, 1);
+}
+
+
+/* Layers code */
+
+static uae_u32 LY_TryLockLayer(uaecptr layer)
+{
+    uaecptr sigsem = layer + 72;
+
+    m68k_areg(regs, 0) = sigsem;
+    return CallLib(get_long(4), -576);
+}
+
+static void LY_LockLayer(uaecptr layer)
+{
+    uaecptr sigsem = layer + 72;
+
+    m68k_areg(regs, 0) = sigsem;
+    CallLib(get_long(4), -564);
+}
+
+static void LY_UnlockLayer(uaecptr layer)
+{
+    uaecptr sigsem = layer + 72;
+
+    m68k_areg(regs, 0) = sigsem;
+    CallLib(get_long(4), -570);
+}
+
+static void LY_LockLayerInfo(uaecptr li)
+{
+    uaecptr sigsem = li + 24;
+
+    m68k_areg(regs, 0) = sigsem;
+    CallLib(get_long(4), -564);
+    put_byte(li+91, get_byte(li+91)+1);
+}
+
+static void LY_UnlockLayerInfo(uaecptr li)
+{
+    uaecptr sigsem = li + 24;
+
+    put_byte(li+91, get_byte(li+91)-1);
+    m68k_areg(regs, 0) = sigsem;
+    CallLib(get_long(4), -570);
+}
+
+static void LY_LockLayers(uaecptr li)
+{
+    uaecptr l = get_long (li);
+    LY_LockLayerInfo(li);
+    while (l != 0) {
+       LY_LockLayer(l);
+       l = get_long(l);
+    }
+    LY_UnlockLayerInfo(li);
+}
+
+static void LY_UnlockLayers(uaecptr li)
+{
+    uaecptr l = get_long (li);
+    LY_LockLayerInfo(li);
+    while (l != 0) {
+       LY_UnlockLayer(l);
+       l = get_long(l);
+    }
+    LY_UnlockLayerInfo(li);
+}
+
+#define LAYER_CLUELESS   0x8000 /* Indicates we know nothing about the layer's regions. */
+#define LAYER_CR_CHANGED 0x4000 /* Indicates that the cliprects in Amiga memory need to be re-done */
+#define LAYER_REDO       0x2000 /* Indicates that we have regions, but they are bogus. */
+
+static uae_u32 layer_uniq = 1;
+
+struct MyLayerInfo {
+    struct uniq_head head;
+    uaecptr amigaos_linfo;
+    uniq_list layer_list;
+};
+
+struct MyLayer {
+    struct uniq_head head;
+    uaecptr amigaos_layer, rastport;
+    struct Rectangle bounds;
+    struct RectList clipregion;
+    struct RectList obscured;
+    struct RectList visible;
+    struct BandList big_bands; /* created by obscuring layers */
+    struct BandList small_bands; /* big_bands + those from clipregion */
+    struct RectList damage;
+    struct BandList damage_bands;
+    struct MyLayerInfo *mli;
+};
+
+static uniq_list MyLayerInfo_list = UNIQ_INIT;
+
+static void LY_InitLayers(uaecptr li)
+{
+    memset (get_real_address(li), 0, 92);
+    put_long(li + 0, 0); /* top layer */
+    put_long(li+84, 0); /* uniq: */
+    m68k_areg(regs, 0) = li + 24; CallLib(get_long(4), -558); /* InitSemaphore() */
+    put_word(li+88, 0); /* flags (???) */
+    put_byte(li+89, 0); /* fatten_count */
+    /* @@@ How big can I assume the structure? What's all this 1.0/1.1 cruft? */
+}
+
+static void LY_FattenLayerInfo(uaecptr li)
+{
+    struct MyLayerInfo *mli;
+    int fatten_count = get_byte (li + 89);
+    if (fatten_count == 0) {
+       mli = (struct MyLayerInfo *)malloc(sizeof(struct MyLayerInfo));
+       add_uniq(&MyLayerInfo_list, &mli->head, li + 84);
+       init_uniq(&mli->layer_list);
+       mli->amigaos_linfo = li;
+    }
+    put_byte (li + 89, fatten_count + 1);
+}
+
+static void LY_ThinLayerInfo(uaecptr li)
+{
+    int fatten_count = get_byte (li + 89)-1;
+    put_byte (li + 89, fatten_count);
+    if (fatten_count == 0) {
+       struct MyLayerInfo *mli = (struct MyLayerInfo *)find_and_rem_uniq(&MyLayerInfo_list, get_long(li+84));
+       if (mli)
+           free(mli);
+    }
+}
+
+static void build_cliprect (struct MyLayer *l, struct Rectangle *bounds,
+                           int obscured, uaecptr *crp, uaecptr *prev)
+{
+    uaecptr cr = get_long (*crp);
+    if (cr == 0) {
+       put_long (*crp, cr = amiga_malloc(CLIPRECT_SIZE));
+       put_long (cr, 0);
+    }
+    *prev = cr;
+    *crp = cr;
+    put_word (cr + 16, bounds->MinX);
+    put_word (cr + 18, bounds->MinY);
+    put_word (cr + 20, bounds->MaxX);
+    put_word (cr + 22, bounds->MaxY);
+    put_long (cr + 8, obscured ? l->amigaos_layer : 0); /* cheat */
+    put_long (cr + 12, 0); /* no smart refresh yet */
+}
+
+static void build_cliprects (struct MyLayer *l)
+{
+    uaecptr layer = l->amigaos_layer;
+    uaecptr cr = layer + 8;
+    uaecptr prev = 0;
+    uae_u16 flags = get_word(layer + 30);
+    int i;
+
+    if ((flags & LAYER_CR_CHANGED) == 0)
+       return;
+    put_word (layer + 30, flags & ~LAYER_CR_CHANGED);
+    for (i = 0; i < l->obscured.count; i++) {
+       build_cliprect (l, l->obscured.rects + i, 1, &cr, &prev);
+    }
+    for (i = 0; i < l->visible.count; i++) {
+       build_cliprect (l, l->visible.rects + i, 1, &cr, &prev);
+    }
+    while ((prev = get_long (cr))) {
+       put_long (cr, get_long (prev));
+       amiga_free (prev, CLIPRECT_SIZE);
+    }
+}
+
+static void propagate_clueless_redo (struct MyLayerInfo *mli)
+{
+    /* For all CLUELESS layers, set the REDO bit for all layers below it that overlap it
+     * and delete the data associated with them. */
+    uaecptr current_l = get_long(mli->amigaos_linfo);
+    while (current_l) {
+       struct MyLayer *l = (struct MyLayer *)find_uniq(&mli->layer_list, get_long(current_l + 24));
+       if ((get_word(l->amigaos_layer + 32) & LAYER_CLUELESS) != 0) {
+           uaecptr next_l = get_long(current_l);
+           put_word(l->amigaos_layer + 32, get_word(l->amigaos_layer + 32) | LAYER_REDO);
+           while (next_l) {
+               struct MyLayer *l2 = (struct MyLayer *)find_uniq(&mli->layer_list, get_long(next_l + 24));
+               uae_u16 flags = get_word(l2->amigaos_layer + 32);
+               if (l2->bounds.MinX <= l->bounds.MaxX && l->bounds.MinX <= l2->bounds.MaxX
+                   && l2->bounds.MinY <= l->bounds.MaxY && l->bounds.MinY <= l2->bounds.MaxY)
+                   put_word(l2->amigaos_layer + 32, flags | LAYER_REDO);
+               if ((flags & (LAYER_REDO|LAYER_CLUELESS)) == 0) {
+                   free_rectlist(&l->obscured);
+                   free_rectlist(&l->visible);
+                   free_bandlist(&l->big_bands);
+                   free_bandlist(&l->small_bands);
+               }
+               next_l = get_long(next_l);
+           }
+       }
+       current_l = get_long(current_l);
+    }
+}
+
+static void redo_layers(struct MyLayerInfo *mli, uaecptr bm)
+{
+    uaecptr current_l;
+    struct RectList tmp_rl;
+
+    propagate_clueless_redo(mli);
+    current_l = get_long(mli->amigaos_linfo);
+
+    while (current_l) {
+       struct MyLayer *l = (struct MyLayer *)find_uniq(&mli->layer_list, get_long(current_l + 24));
+       uae_u16 flags = get_word(l->amigaos_layer + 32);
+       if ((flags & LAYER_REDO) != 0) {
+           uaecptr next_l = get_long(current_l+4);
+           int have_rects = 0;
+
+           init_rectlist(&l->obscured);
+           init_bandlist(&l->big_bands);
+           add_rect_to_bands(&l->big_bands, &l->bounds);
+
+           while (next_l) {
+               struct MyLayer *l2 = (struct MyLayer *)find_uniq(&mli->layer_list, get_long(next_l + 24));
+               if (l2->visible.bounds.MinX <= l->bounds.MaxX && l->bounds.MinX <= l2->visible.bounds.MaxX
+                   && l2->visible.bounds.MinY <= l->bounds.MaxY && l->bounds.MinY <= l2->visible.bounds.MaxY
+                   && !rect_in_region (&l->obscured, &l2->visible.bounds))
+               {
+                   add_rect_to_bands(&l->big_bands, &l2->visible.bounds);
+                   add_rect(&l->obscured, l2->visible.bounds);
+                   have_rects++;
+               }
+               next_l = get_long(next_l+4);
+           }
+           init_rectlist(&l->visible);
+           init_rectlist(&tmp_rl);
+           add_rect (&tmp_rl, l->bounds);
+
+           region_splitrects_band(&l->obscured, &l->big_bands);
+           region_splitrects_band(&tmp_rl, &l->big_bands);
+           region_do_ClearRegionRegion(&l->obscured, &tmp_rl, &l->visible);
+           flags |= LAYER_CR_CHANGED;
+       }
+       put_word (l->amigaos_layer + 32, flags & ~(LAYER_CLUELESS|LAYER_REDO));
+       current_l = get_long(current_l);
+    }
+}
+
+static struct MyLayer *LY_NewLayer(struct MyLayerInfo *mli, int x0, int x1, int y0, int y1,
+                                  uae_u16 flags, uaecptr bm, uaecptr sbm)
+{
+    struct MyLayer *l = (struct MyLayer *)malloc(sizeof (struct MyLayer));
+    uaecptr layer = amiga_malloc(LAYER_SIZE);
+    memset (get_real_address(layer), 0, LAYER_SIZE);
+    l->amigaos_layer = layer;
+
+    put_word(layer + 16, x0); /* bounds */
+    put_word(layer + 18, y0);
+    put_word(layer + 20, x1);
+    put_word(layer + 22, y1);
+    put_word(layer + 30, flags | LAYER_CLUELESS);
+    put_long(layer + 32, flags & 4 ? sbm : 0); /* ClipRect */
+    put_long(layer + 68, mli->amigaos_linfo);
+    m68k_areg(regs, 0) = layer + 72; CallLib(get_long(4), -558); /* InitSemaphore() */
+    add_uniq(&mli->layer_list, &l->head, layer + 24);
+    l->mli = mli;
+
+    l->bounds.MinX = x0;
+    l->bounds.MaxX = x1;
+    l->bounds.MinY = y0;
+    l->bounds.MaxY = y1;
+    return l;
+}
+
+static void LY_DeleteLayer(uaecptr layer)
+{
+    uaecptr cr;
+    struct MyLayer *l = (struct MyLayer *)find_and_rem_uniq(&l->mli->layer_list, get_long (layer + 24));
+    /* Free ClipRects */
+    while ((cr = get_long (l->amigaos_layer + 8))) {
+       put_long (l->amigaos_layer + 8, get_long(cr));
+       amiga_free(cr, CLIPRECT_SIZE);
+    }
+    amiga_free (l->amigaos_layer, LAYER_SIZE);
+    free(l);
+}
+
+static uaecptr find_behindlayer_position(uaecptr li, uae_u16 flags)
+{
+    uaecptr where = li;
+    for (;;) {
+       uaecptr other = get_long (where);
+       /* End of list? */
+       if (other == 0)
+           break;
+       /* Backdrop? */
+       if ((get_word(other + 30) & 0x40) > (flags & 0x40))
+           break;
+       where = other;
+    }
+    return where;
+}
+
+static uaecptr LY_CreateLayer(uaecptr li, int x0, int x1, int y0, int y1,
+                             uae_u16 flags, uaecptr bm, uaecptr sbm, uaecptr where)
+{
+    struct MyLayerInfo *mli = (struct MyLayerInfo *)find_uniq(&MyLayerInfo_list, get_long (li + 84));
+    struct MyLayer *l;
+
+    LY_LockLayerInfo(li);
+
+    l = LY_NewLayer(mli, x0, x1, y0, y1, flags, bm, sbm);
+    /* Chain into list */
+    put_long(l->amigaos_layer, get_long (where));
+    put_long(l->amigaos_layer + 4, where == li ? 0 : where);
+    if (get_long (where) != 0)
+       put_long(get_long (where) + 4, l->amigaos_layer);
+    put_long(where, l->amigaos_layer);
+    redo_layers(mli, bm);
+    build_cliprects(l);
+    LY_UnlockLayerInfo(li);
+    return l->amigaos_layer;
+}
+
+static void LY_DisposeLayerInfo(uaecptr li)
+{
+    LY_ThinLayerInfo(li);
+    amiga_free(li, LINFO_SIZE);
+}
+
+static uae_u32 layers_NewLayerInfo(void)
+{
+    uaecptr li = amiga_malloc(LINFO_SIZE);
+    LY_InitLayers(li);
+    LY_FattenLayerInfo(li);
+    return li;
+}
+static uae_u32 layers_InitLayers(void) { LY_InitLayers (m68k_areg (regs, 0)); return 0; }
+static uae_u32 layers_DisposeLayerInfo(void) { LY_DisposeLayerInfo (m68k_areg (regs, 0)); return 0; }
+
+static uae_u32 layers_FattenLayerInfo(void) { LY_FattenLayerInfo(m68k_areg(regs, 0)); return 0; }
+static uae_u32 layers_ThinLayerInfo(void) { LY_ThinLayerInfo(m68k_areg(regs, 0)); return 0; }
+
+static uae_u32 layers_CreateUpfrontLayer(void)
+{
+    return LY_CreateLayer(m68k_areg(regs, 0), (uae_s32)m68k_dreg(regs, 0),
+                         (uae_s32)m68k_dreg(regs, 1), (uae_s32)m68k_dreg(regs, 2),
+                         (uae_s32)m68k_dreg(regs, 3),
+                         m68k_dreg(regs, 4),
+                         m68k_areg(regs, 1), m68k_areg(regs, 2), m68k_areg(regs, 0));
+}
+static uae_u32 layers_CreateBehindLayer(void)
+{
+    return LY_CreateLayer(m68k_areg(regs, 0), (uae_s32)m68k_dreg(regs, 0),
+                         (uae_s32)m68k_dreg(regs, 1), (uae_s32)m68k_dreg(regs, 2),
+                         (uae_s32)m68k_dreg(regs, 3),
+                         m68k_dreg(regs, 4),
+                         m68k_areg(regs, 1), m68k_areg(regs, 2),
+                         find_behindlayer_position (m68k_areg(regs, 0), m68k_dreg(regs, 4)));
+}
+static uae_u32 layers_DeleteLayer(void) { LY_DeleteLayer (m68k_areg (regs, 1)); return 0; }
+
+static void LY_LockLayer1(uaecptr layer)
+{
+    uaecptr li = get_long (layer + 68);
+    struct MyLayerInfo *mli = (struct MyLayerInfo *)find_uniq (&MyLayerInfo_list, get_long (li + 84));
+    struct MyLayer *l = (struct MyLayer *)find_uniq (&mli->layer_list, get_long (layer + 24));
+
+    LY_LockLayer(layer);
+    build_cliprects (l);
+}
+static uae_u32 LY_TryLockLayer1(uaecptr layer)
+{
+    uaecptr li = get_long (layer + 68);
+    struct MyLayerInfo *mli = (struct MyLayerInfo *)find_uniq (&MyLayerInfo_list, get_long (li + 84));
+    struct MyLayer *l = (struct MyLayer *)find_uniq (&mli->layer_list, get_long (layer + 24));
+
+    if (!LY_TryLockLayer(layer))
+       return 0;
+    build_cliprects (l);
+    return 1;
+}
+static uae_u32 gfx_TryLockLayer(void) { return LY_TryLockLayer1 (m68k_areg(regs, 5));  }
+static uae_u32 gfx_LockLayer(void) { LY_LockLayer1 (m68k_areg(regs, 5)); return 0; }
+static uae_u32 gfx_UnlockLayer(void) { LY_UnlockLayer(m68k_areg(regs, 5)); return 0; }
+static uae_u32 layers_LockLayer(void) { LY_LockLayer1 (m68k_areg(regs, 1)); return 0; }
+static uae_u32 layers_LockLayers(void) { LY_LockLayers(m68k_areg(regs, 0)); return 0; }
+static uae_u32 layers_LockLayerInfo(void) { LY_LockLayerInfo(m68k_areg(regs, 0)); return 0; }
+static uae_u32 layers_UnlockLayer(void) { LY_UnlockLayer(m68k_areg(regs, 0)); return 0; }
+static uae_u32 layers_UnlockLayers(void) { LY_UnlockLayers(m68k_areg(regs, 0)); return 0; }
+static uae_u32 layers_UnlockLayerInfo(void) { LY_UnlockLayerInfo(m68k_areg(regs, 0)); return 0; }
+
+static uae_u32 layers_ScrollLayer(void)
+{
+    abort();
+}
+
+static uae_u32 layers_SizeLayer(void)
+{
+    abort();
+}
+
+static uae_u32 layers_MoveLayer(void)
+{
+    abort();
+}
+
+static uae_u32 layers_UpfrontLayer(void)
+{
+    abort();
+}
+
+static uae_u32 layers_BehindLayer(void)
+{
+    abort();
+}
+
+static uae_u32 layers_MoveLayerInFrontOf(void)
+{
+    abort();
+}
+
+static uae_u32 layers_BeginUpdate(void)
+{
+    return 1;
+}
+
+static uae_u32 layers_EndUpdate(void)
+{
+    return 0;
+}
+
+static uae_u32 layers_WhichLayer(void)
+{
+    abort();
+}
+
+static uae_u32 layers_InstallClipRegion(void)
+{
+    return 0;
+}
+
+static uae_u32 layers_SwapBitsRastPortClipRect(void)
+{
+    abort();
+}
+
+/*
+ *  Initialization
+ */
+static uae_u32 gfxlib_init(void)
+{
+    uae_u32 old_arr;
+    uaecptr sysbase=m68k_areg(regs, 6);
+    int i=0;
+
+    /* Install new routines */
+    m68k_dreg(regs, 0)=0;
+    m68k_areg(regs, 1)=gfxlibname;
+    gfxbase=CallLib(sysbase, -408);  /* OpenLibrary */
+    m68k_dreg(regs, 0)=0;
+    m68k_areg(regs, 1)=layerslibname;
+    layersbase=CallLib(sysbase, -408);  /* OpenLibrary */
+
+    libemu_InstallFunctionFlags(gfxl_WritePixel, gfxbase, -324, TRAPFLAG_EXTRA_STACK, "");
+    libemu_InstallFunctionFlags(gfxl_BltClear, gfxbase, -300, 0, "");
+    libemu_InstallFunctionFlags(gfxl_AndRegionRegion, gfxbase, -624, TRAPFLAG_EXTRA_STACK, "");
+    libemu_InstallFunctionFlags(gfxl_OrRegionRegion, gfxbase, -612, TRAPFLAG_EXTRA_STACK, "");
+    libemu_InstallFunctionFlags(gfxl_XorRegionRegion, gfxbase, -618, TRAPFLAG_EXTRA_STACK, "");
+    libemu_InstallFunctionFlags(gfxl_AndRectRegion, gfxbase, -504, TRAPFLAG_EXTRA_STACK, "");
+    libemu_InstallFunctionFlags(gfxl_OrRectRegion, gfxbase, -510, TRAPFLAG_EXTRA_STACK, "");
+    libemu_InstallFunctionFlags(gfxl_XorRectRegion, gfxbase, -558, TRAPFLAG_EXTRA_STACK, "");
+    libemu_InstallFunctionFlags(gfxl_ClearRectRegion, gfxbase, -522, TRAPFLAG_EXTRA_STACK, "");
+
+#if 0
+#define MAYBE_FUNCTION(a) NULL
+#else
+#define MAYBE_FUNCTION(a) (a)
+#endif
+#if 0
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(gfx_TryLockLayer), gfxbase, -654, TRAPFLAG_EXTRA_STACK|TRAPFLAG_NO_RETVAL, "AttemptLockLayerRom");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(gfx_LockLayer), gfxbase, -432, TRAPFLAG_EXTRA_STACK|TRAPFLAG_NO_RETVAL, "LockLayerRom");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(gfx_UnlockLayer), gfxbase, -438, TRAPFLAG_EXTRA_STACK|TRAPFLAG_NO_RETVAL, "UnlockLayerRom");
+
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_InitLayers), layersbase, -30, TRAPFLAG_EXTRA_STACK, "InitLayers");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_CreateUpfrontLayer), layersbase, -36, TRAPFLAG_EXTRA_STACK, "CreateUpfrontLayer");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_CreateBehindLayer), layersbase, -42, TRAPFLAG_EXTRA_STACK, "CreateBehindLayer");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_UpfrontLayer), layersbase, -48, TRAPFLAG_EXTRA_STACK, "UpfrontLayer");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_BehindLayer), layersbase, -54, TRAPFLAG_EXTRA_STACK, "BehindLayer");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_MoveLayer), layersbase, -60, TRAPFLAG_EXTRA_STACK, "MoveLayer");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_SizeLayer), layersbase, -66, TRAPFLAG_EXTRA_STACK, "SizeLayer");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_ScrollLayer), layersbase, -72, TRAPFLAG_EXTRA_STACK, "ScrollLayer");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_BeginUpdate), layersbase, -78, TRAPFLAG_EXTRA_STACK, "BeginUpdate");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_EndUpdate), layersbase, -84, TRAPFLAG_EXTRA_STACK, "EndUpdate");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_DeleteLayer), layersbase, -90, TRAPFLAG_EXTRA_STACK, "DeleteLayer");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_LockLayer), layersbase, -96, TRAPFLAG_EXTRA_STACK, "LockLayer");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_UnlockLayer), layersbase, -102, TRAPFLAG_EXTRA_STACK, "UnlockLayer");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_LockLayers), layersbase, -108, TRAPFLAG_EXTRA_STACK, "LockLayers");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_UnlockLayers), layersbase, -114, TRAPFLAG_EXTRA_STACK, "UnlockLayers");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_LockLayerInfo), layersbase, -120, TRAPFLAG_EXTRA_STACK, "LockLayerInfo");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_SwapBitsRastPortClipRect), layersbase, -126, TRAPFLAG_EXTRA_STACK, "SwapBitsRastPortClipRect");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_WhichLayer), layersbase, -132, TRAPFLAG_EXTRA_STACK, "WhichLayer");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_UnlockLayerInfo), layersbase, -138, TRAPFLAG_EXTRA_STACK, "UnlockLayerInfo");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_NewLayerInfo), layersbase, -144, TRAPFLAG_EXTRA_STACK, "NewLayerInfo");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_DisposeLayerInfo), layersbase, -150, TRAPFLAG_EXTRA_STACK, "DisposeLayerInfo");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_FattenLayerInfo), layersbase, -156, TRAPFLAG_EXTRA_STACK, "FattenLayerInfo");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_ThinLayerInfo), layersbase, -162, TRAPFLAG_EXTRA_STACK, "ThinLayerInfo");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_MoveLayerInFrontOf), layersbase, -168, TRAPFLAG_EXTRA_STACK, "MoveLayerInFrontOf");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_InstallClipRegion), layersbase, -174, TRAPFLAG_EXTRA_STACK, "InstallClipRegion");
+#if 0
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_), layersbase, -180, TRAPFLAG_EXTRA_STACK, "MoveSizeLayer");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_), layersbase, -186, TRAPFLAG_EXTRA_STACK, "CreateUpfrontHookLayer");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_), layersbase, -192, TRAPFLAG_EXTRA_STACK, "CreateBehindHookLayer");
+    libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_), layersbase, -198, TRAPFLAG_EXTRA_STACK, "InstallLayerHook");
+#endif
+#endif
+    return 0;
+}
+
+/*
+ *  Install the gfx-library-replacement
+ */
+void gfxlib_install(void)
+{
+    uae_u32 begin, end, resname, resid;
+    int i;
+
+    if (! currprefs.use_gfxlib)
+       return;
+
+    write_log ("Warning: you enabled the graphics.library replacement with -g\n"
+            "This may be buggy right now, and will not speed things up much.\n");
+
+    resname = ds ("UAEgfxlib.resource");
+    resid = ds ("UAE gfxlib 0.1");
+
+    gfxlibname = ds ("graphics.library");
+    layerslibname = ds ("layers.library");
+
+    begin = here();
+    dw(0x4AFC);             /* RTC_MATCHuae_s16 */
+    dl(begin);              /* our start address */
+    dl(0);                  /* Continue scan here */
+    dw(0x0101);             /* RTF_COLDSTART; Version 1 */
+    dw(0x0805);             /* NT_RESOURCE; pri 5 */
+    dl(resname);            /* name */
+    dl(resid);              /* ID */
+    dl(here() + 4);         /* Init area: directly after this */
+
+    calltrap(deftrap2(gfxlib_init, TRAPFLAG_EXTRA_STACK, "")); dw(RTS);
+
+    end = here();
+    org(begin + 6);
+    dl(end);
+
+    org(end);
+}
+#else
+
+void gfxlib_install (void)
+{
+}
+
+#endif
diff --git a/gfxutil.c b/gfxutil.c
new file mode 100755 (executable)
index 0000000..695d08d
--- /dev/null
+++ b/gfxutil.c
@@ -0,0 +1,528 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Common code needed by all the various graphics systems.
+  *
+  * (c) 1996 Bernd Schmidt, Ed Hanway, Samuel Devulder
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+#include "custom.h"
+#include "xwin.h"
+
+#define        RED     0
+#define        GRN     1
+#define        BLU     2
+
+/*
+ * dither matrix
+ */
+static uae_u8 dither[4][4] =
+{
+  { 0, 8, 2, 10 },
+  { 12, 4, 14, 6 },
+  { 3, 11, 1, 9 },
+  { 14 /* 15 */, 7, 13, 5 }
+};
+
+
+unsigned long doMask (int p, int bits, int shift)
+{
+    /* scale to 0..255, shift to align msb with mask, and apply mask */
+    unsigned long val = p << 24;
+    if (!bits)
+       return 0;
+    val >>= (32 - bits);
+    val <<= shift;
+
+    return val;
+}
+
+int bits_in_mask (unsigned long mask)
+{
+    int n = 0;
+    while (mask) {
+       n += mask & 1;
+       mask >>= 1;
+    }
+    return n;
+}
+
+int mask_shift (unsigned long mask)
+{
+    int n = 0;
+    while (!(mask & 1)) {
+       n++;
+       mask >>= 1;
+    }
+    return n;
+}
+
+unsigned long doMask256 (int p, int bits, int shift)
+{
+    /* p is a value from 0 to 255 (Amiga color value)
+     * shift to align msb with mask, and apply mask */
+
+    unsigned long val = p * 0x01010101UL;
+    val >>= (32 - bits);
+    val <<= shift;
+
+    return val;
+}
+
+static unsigned int doColor (int i, int bits, int shift)
+{
+    int shift2;
+    if(bits >= 8) shift2 = 0; else shift2 = 8 - bits;
+    return (i >> shift2) << shift;
+}
+
+static unsigned int doAlpha (int alpha, int bits, int shift)
+{
+    return (alpha & ((1 << bits) - 1)) << shift;
+}
+
+#if 0
+static void colormodify (int *r, int *g, int *b)
+{
+    double h, l, s;
+
+    RGBToHLS (*r, *g, *b, &h, &l, &s);
+
+    h = h + currprefs.gfx_hue / 10.0;
+    if (h > 359) h = 359;
+    if (h < 0) h = 0;
+    s = s + currprefs.gfx_saturation / 30.0;
+    if (s > 99) s = 99;
+    if (s < 0) s = 0;
+    l = l + currprefs.gfx_luminance / 30.0;
+    l = (l - currprefs.gfx_contrast / 30.0) / (100 - 2 * currprefs.gfx_contrast / 30.0) * 100;
+    l = pow (l / 100.0, (currprefs.gfx_gamma + 1000) / 1000.0) * 100.0;
+    if (l > 99) l = 99;
+    if (l < 0) l = 0;
+    HLSToRGB (h, l, s, r, g, b);
+}
+#endif
+
+void alloc_colors64k (int rw, int gw, int bw, int rs, int gs, int bs, int aw, int as, int alpha)
+{
+    int i;
+
+    for (i = 0; i < 4096; i++) {
+       int r = (i >> 8) << 4;
+       int g = ((i >> 4) & 0xF) << 4;
+       int b = (i & 0xF) << 4;
+       //colormodify (&r, &g, &b);
+       xcolors[i] = doMask(r, rw, rs) | doMask(g, gw, gs) | doMask(b, bw, bs) | doAlpha (alpha, aw, as);
+    }
+#ifdef AGA
+    /* create AGA color tables */
+    for(i = 0; i < 256; i++) {
+       xredcolors[i] = doColor (i, rw, rs) | doAlpha (alpha, aw, as);
+       xgreencolors[i] = doColor (i, gw, gs) | doAlpha (alpha, aw, as);
+       xbluecolors[i] = doColor (i, bw, bs) | doAlpha (alpha, aw, as);;
+    }
+#endif
+}
+
+static int allocated[4096];
+static int color_diff[4096];
+static int newmaxcol = 0;
+
+void setup_maxcol (int max)
+{
+    newmaxcol = max;
+}
+
+void alloc_colors256 (allocfunc_type allocfunc)
+{
+    int nb_cols[3]; /* r,g,b */
+    int maxcol = newmaxcol == 0 ? 256 : newmaxcol;
+    int i,j,k,l;
+
+    xcolnr *map;
+
+    map = (xcolnr *)malloc (sizeof(xcolnr) * maxcol);
+    if (!map) {
+       write_log ("Not enough mem for colormap!\n");
+       abort ();
+    }
+
+    /*
+     * compute #cols per components
+     */
+    for (i = 1; i*i*i <= maxcol; ++i)
+       ;
+    --i;
+
+    nb_cols[RED] = i;
+    nb_cols[GRN] = i;
+    nb_cols[BLU] = i;
+
+    /*
+     * set the colormap
+     */
+    l = 0;
+    for (i = 0; i < nb_cols[RED]; ++i) {
+       int r = (i * 15) / (nb_cols[RED] - 1);
+       for (j = 0; j < nb_cols[GRN]; ++j) {
+           int g = (j * 15) / (nb_cols[GRN] - 1);
+           for (k = 0; k < nb_cols[BLU]; ++k) {
+               int b = (k * 15) / (nb_cols[BLU] - 1);
+               int result;
+               result = allocfunc (r, g, b, map + l);
+               l++;
+           }
+       }
+    }
+/*    printf("%d color(s) lost\n",maxcol - l);*/
+
+    /*
+     * for each component compute the mapping
+     */
+    {
+       int diffr, diffg, diffb, maxdiff = 0, won = 0, lost;
+       int r, d = 8;
+       for (r = 0; r < 16; ++r) {
+           int cr, g, q;
+
+           k = nb_cols[RED]-1;
+           cr = (r * k) / 15;
+           q = (r * k) % 15;
+           if (q > d && cr < k) ++cr;
+           diffr = abs (cr*k - r);
+           for (g = 0; g < 16; ++g) {
+               int cg, b;
+
+               k = nb_cols[GRN]-1;
+               cg = (g * k) / 15;
+               q  = (g * k) % 15;
+               if (q > d && cg < k) ++cg;
+               diffg = abs (cg*k - g);
+               for (b = 0; b < 16; ++b) {
+                   int cb, rgb = (r << 8) | (g << 4) | b;
+
+                   k = nb_cols[BLU]-1;
+                   cb = (b * k) / 15;
+                   q = (b * k) % 15;
+                   if (q > d && cb < k) ++cb;
+                   diffb = abs (cb*k - b);
+                   xcolors[rgb] = map[(cr * nb_cols[GRN] + cg) * nb_cols[BLU] + cb];
+                   color_diff[rgb] = diffr + diffg + diffb;
+                   if (color_diff[rgb] > maxdiff)
+                       maxdiff = color_diff[rgb];
+               }
+           }
+       }
+       while (maxdiff > 0 && l < maxcol) {
+           int newmaxdiff = 0;
+           lost = 0; won++;
+           for (r = 15; r >= 0; r--) {
+               int g;
+
+               for (g = 15; g >= 0; g--) {
+                   int b;
+
+                   for (b = 15; b >= 0; b--) {
+                       int rgb = (r << 8) | (g << 4) | b;
+
+                       if (color_diff[rgb] == maxdiff) {
+                           int result;
+
+                           if (l >= maxcol)
+                               lost++;
+                           else {
+                               result = allocfunc (r, g, b, xcolors + rgb);
+                               l++;
+                           }
+                           color_diff[rgb] = 0;
+                       } else if (color_diff[rgb] > newmaxdiff)
+                               newmaxdiff = color_diff[rgb];
+
+                   }
+               }
+           }
+           maxdiff = newmaxdiff;
+       }
+/*     printf("%d color(s) lost, %d stages won\n",lost, won);*/
+    }
+    free (map);
+}
+
+/*
+ * This dithering process works by letting UAE run internaly in 12bit
+ * mode and doing the dithering on the fly when rendering to the display.
+ * The dithering algorithm is quite fast but uses lot of memory (4*8*2^12 =
+ * 128Kb). I don't think that is a trouble right now, but when UAE will
+ * emulate AGA and work internaly in 24bit mode, that dithering algorithm
+ * will need 4*8*2^24 = 512Mb. Obviously that fast algorithm will not be
+ * tractable. However, we could then use an other algorithm, slower, but
+ * far more reasonable (I am thinking about the one that is used in DJPEG).
+ */
+
+uae_u8 cidx[4][8*4096]; /* fast, but memory hungry =:-( */
+
+/*
+ * Compute dithering structures
+ */
+void setup_greydither_maxcol (int maxcol, allocfunc_type allocfunc)
+{
+    int i,j,k;
+    xcolnr *map;
+
+    for (i = 0; i < 4096; i++)
+       xcolors[i] = i;
+
+    map = (xcolnr *)malloc (sizeof(xcolnr) * maxcol);
+    if (!map) {
+       write_log ("Not enough mem for colormap!\n");
+       abort();
+    }
+
+    /*
+     * set the colormap
+     */
+    for (i = 0; i < maxcol; ++i) {
+       int c, result;
+       c = (15 * i + (maxcol-1)/2) / (maxcol - 1);
+       result = allocfunc(c, c, c, map + i);
+       /* @@@ check for errors */
+    }
+
+    /*
+     * for each componant compute the mapping
+     */
+    for (i = 0; i < 4; ++i) {
+       for (j = 0; j < 4; ++j) {
+           int r, d = dither[i][j]*17;
+           for (r = 0; r<16; ++r) {
+               int g;
+               for (g = 0; g < 16; ++g) {
+                   int  b;
+                   for (b = 0; b < 16; ++b) {
+                       int rgb = (r << 8) | (g << 4) | b;
+                       int c,p,q;
+
+                       c = (77  * r +
+                            151 * g +
+                            28  * b) / 15; /* c in 0..256 */
+
+                       k = maxcol-1;
+                       p = (c * k) / 256;
+                       q = (c * k) % 256;
+                       if (q /*/ k*/> d /*/ k*/ && p < k) ++p;
+/* sam:                      ^^^^^^^ */
+/*  It seems that produces better output */
+                       cidx[i][rgb + (j+4)*4096] =
+                           cidx[i][rgb + j*4096] = (uae_u8)map[p];
+                   }
+               }
+           }
+       }
+    }
+    free (map);
+}
+
+void setup_greydither (int bits, allocfunc_type allocfunc)
+{
+    setup_greydither_maxcol(1 << bits, allocfunc);
+}
+
+void setup_dither (int bits, allocfunc_type allocfunc)
+{
+    int nb_cols[3]; /* r,g,b */
+    int maxcol = 1 << bits;
+    int i,j,k,l;
+
+    xcolnr *map;
+    int *redvals, *grnvals, *bluvals;
+
+    map = (xcolnr *)malloc (sizeof(xcolnr) * maxcol);
+    if (!map) {
+       write_log ("Not enough mem for colormap!\n");
+       abort();
+    }
+
+    for (i = 0; i < 4096; i++)
+       xcolors[i] = i;
+
+    /*
+     * compute #cols per components
+     */
+    for (i = 1; i*i*i <= maxcol; ++i)
+       ;
+    --i;
+
+    nb_cols[RED] = i;
+    nb_cols[GRN] = i;
+    nb_cols[BLU] = i;
+
+    if (nb_cols[RED]*(++i)*nb_cols[BLU] <= maxcol) {
+       nb_cols[GRN] = i;
+       if ((i)*nb_cols[GRN]*nb_cols[BLU] <= maxcol)
+           nb_cols[RED] = i;
+    }
+
+    redvals = (int *)malloc (sizeof(int) * maxcol);
+    grnvals = redvals + nb_cols[RED];
+    bluvals = grnvals + nb_cols[GRN];
+    /*
+     * set the colormap
+     */
+    l = 0;
+    for (i = 0; i < nb_cols[RED]; ++i) {
+       int r = (i * 15) / (nb_cols[RED] - 1);
+       redvals[i] = r;
+       for (j = 0; j < nb_cols[GRN]; ++j) {
+           int g = (j * 15) / (nb_cols[GRN] - 1);
+           grnvals[j] = g;
+           for (k = 0; k < nb_cols[BLU]; ++k) {
+               int b = (k * 15) / (nb_cols[BLU] - 1);
+               int result;
+               bluvals[k] = b;
+               result = allocfunc(r, g, b, map + l);
+               l++;
+           }
+       }
+    }
+/*    write_log ("%d color(s) lost\n",maxcol - l);*/
+
+    /*
+     * for each component compute the mapping
+     */
+    {
+       int r;
+       for (r = 0; r < 16; ++r) {
+           int g;
+           for (g = 0; g < 16; ++g) {
+               int b;
+               for (b = 0; b < 16; ++b) {
+                   int rgb = (r << 8) | (g << 4) | b;
+
+                   for (i = 0; i < 4; ++i) for (j = 0; j < 4; ++j) {
+                       int d = dither[i][j];
+                       int cr, cg, cb, k, q;
+#if 0 /* Slightly different algorithm. Needs some tuning. */
+                       int rederr = 0, grnerr = 0, bluerr = 0;
+
+                       k  = nb_cols[RED]-1;
+                       cr = r * k / 15;
+                       q  = r * k - 15*cr;
+                       if (cr < 0)
+                           cr = 0;
+                       else if (q / k > d / k && rederr <= 0)
+                           ++cr;
+                       if (cr > k) cr = k;
+                       rederr += redvals[cr]-r;
+
+                       k  = nb_cols[GRN]-1;
+                       cg = g * k / 15;
+                       q  = g * k - 15*cg;
+                       if (cg < 0)
+                           cg = 0;
+                       else if (q / k > d / k && grnerr <= 0)
+                           ++cg;
+                       if (cg > k) cg = k;
+                       grnerr += grnvals[cg]-g;
+
+                       k  = nb_cols[BLU]-1;
+                       cb = b * k / 15;
+                       q  = b * k - 15*cb;
+                       if (cb < 0)
+                           cb = 0;
+                       else if (q / k > d / k && bluerr <= 0)
+                           ++cb;
+                       if (cb > k) cb = k;
+                       bluerr += bluvals[cb]-b;
+#else
+                       k  = nb_cols[RED]-1;
+                       cr = r * k / 15;
+                       q  = r * k - 15*cr;
+                       if (cr < 0)
+                           cr = 0;
+                       else if (q /*/ k*/ > d /*/ k*/)
+                           ++cr;
+                       if (cr > k) cr = k;
+
+                       k  = nb_cols[GRN]-1;
+                       cg = g * k / 15;
+                       q  = g * k - 15*cg;
+                       if (cg < 0)
+                           cg = 0;
+                       else if (q /*/ k*/ > d /*/ k*/)
+                           ++cg;
+                       if (cg > k) cg = k;
+
+                       k  = nb_cols[BLU]-1;
+                       cb = b * k / 15;
+                       q  = b * k - 15*cb;
+                       if (cb < 0)
+                           cb = 0;
+                       else if (q /*/ k*/ > d /*/ k*/)
+                           ++cb;
+                       if (cb > k) cb = k;
+#endif
+                       cidx[i][rgb + (j+4)*4096] = cidx[i][rgb + j*4096] = (uae_u8)map[(cr*nb_cols[GRN]+cg)*nb_cols[BLU]+cb];
+                   }
+               }
+           }
+       }
+    }
+    free (redvals);
+    free (map);
+}
+
+#if !defined X86_ASSEMBLY
+/*
+ * Dither the line.
+ * Make sure you call this only with (len & 3) == 0, or you'll just make
+ * yourself unhappy.
+ */
+
+void DitherLine (uae_u8 *l, uae_u16 *r4g4b4, int x, int y, uae_s16 len, int bits)
+{
+    uae_u8 *dith = cidx[y&3]+(x&3)*4096;
+    uae_u8 d = 0;
+    int bitsleft = 8;
+
+    if (bits == 8) {
+       while (len > 0) {
+           *l++ = dith[0*4096 + *r4g4b4++];
+           *l++ = dith[1*4096 + *r4g4b4++];
+           *l++ = dith[2*4096 + *r4g4b4++];
+           *l++ = dith[3*4096 + *r4g4b4++];
+           len -= 4;
+       }
+       return;
+    }
+
+    while (len) {
+       int v;
+       v = dith[0*4096 + *r4g4b4++];
+       bitsleft -= bits;
+       d |= (v << bitsleft);
+       if (!bitsleft)
+           *l++ = d, bitsleft = 8, d = 0;
+
+       v = dith[1*4096 + *r4g4b4++];
+       bitsleft -= bits;
+       d |= (v << bitsleft);
+       if (!bitsleft)
+           *l++ = d, bitsleft = 8, d = 0;
+
+       v = dith[2*4096 + *r4g4b4++];
+       bitsleft -= bits;
+       d |= (v << bitsleft);
+       if (!bitsleft)
+           *l++ = d, bitsleft = 8, d = 0;
+
+       v = dith[3*4096 + *r4g4b4++];
+       bitsleft -= bits;
+       d |= (v << bitsleft);
+       if (!bitsleft)
+           *l++ = d, bitsleft = 8, d = 0;
+       len -= 4;
+    }
+}
+#endif
diff --git a/gtkui.c b/gtkui.c
new file mode 100755 (executable)
index 0000000..a536030
--- /dev/null
+++ b/gtkui.c
@@ -0,0 +1,1912 @@
+/*
+ * UAE - the Un*x Amiga Emulator
+ *
+ * Yet Another User Interface for the X11 version
+ *
+ * Copyright 1997, 1998 Bernd Schmidt
+ * Copyright 1998 Michael Krause
+ * 
+ * The Tk GUI doesn't work.
+ * The X Forms Library isn't available as source, and there aren't any
+ * binaries compiled against glibc
+ *
+ * So let's try this...
+ */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "uae.h"
+#include "memory.h"
+#include "custom.h"
+#include "gui.h"
+#include "newcpu.h"
+#include "autoconf.h"
+#include "threaddep/thread.h"
+#include "sounddep/sound.h"
+#include "savestate.h"
+#include "compemu.h"
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+
+/* One of the 1.1.6 "features" is a gratuitous name change */
+#ifndef HAVE_GTK_FEATURES_1_1_6
+#define gtk_container_set_border_width gtk_container_border_width
+#endif
+/* Likewise for 1.1.8.  */
+#ifndef HAVE_GTK_FEATURES_1_1_8
+#define gtk_label_set_text gtk_label_set
+#endif
+/* This is beginning to suck... */
+#ifndef HAVE_GTK_FEATURES_1_1_13
+#define gtk_toggle_button_set_active gtk_toggle_button_set_state
+#endif
+
+static int gui_active;
+
+static GtkWidget *gui_window;
+
+static GtkWidget *pause_uae_widget, *snap_save_widget, *snap_load_widget;
+
+static GtkWidget *chipsize_widget[5];
+static GtkWidget *bogosize_widget[4];
+static GtkWidget *fastsize_widget[5];
+static GtkWidget *z3size_widget[10];
+static GtkWidget *p96size_widget[7];
+static GtkWidget *rom_text_widget, *key_text_widget;
+static GtkWidget *rom_change_widget, *key_change_widget;
+
+static GtkWidget *disk_insert_widget[4], *disk_eject_widget[4], *disk_text_widget[4];
+static char *new_disk_string[4];
+
+static GtkAdjustment *cpuspeed_adj;
+static GtkWidget *cpuspeed_widgets[4], *cpuspeed_scale;
+static GtkWidget *cpu_widget[5], *a24m_widget, *ccpu_widget;
+static GtkWidget *sound_widget[4], *sound_bits_widget[2], *sound_freq_widget[3], *sound_ch_widget[3];
+
+static GtkWidget *coll_widget[4], *cslevel_widget[4];
+static GtkWidget *fcop_widget;
+
+static GtkAdjustment *framerate_adj;
+static GtkWidget *bimm_widget, *b32_widget, *afscr_widget, *pfscr_widget;
+
+static GtkWidget *compbyte_widget[4], *compword_widget[4], *complong_widget[4];
+static GtkWidget *compaddr_widget[4], *compnf_widget[2], *comp_midopt_widget[2];
+static GtkWidget *comp_lowopt_widget[2], *compfpu_widget[2], *comp_hardflush_widget[2];
+static GtkWidget *comp_constjump_widget[2];
+static GtkAdjustment *cachesize_adj;
+
+static GtkWidget *joy_widget[2][6];
+
+static GtkWidget *led_widgets[5];
+static GdkColor led_on[5], led_off[5];
+static unsigned int prevledstate;
+
+static GtkWidget *hdlist_widget;
+static int selected_hd_row;
+static GtkWidget *hdchange_button, *hddel_button;
+static GtkWidget *volname_entry, *path_entry;
+static GtkWidget *dirdlg;
+static char dirdlg_volname[256], dirdlg_path[256];
+
+static smp_comm_pipe to_gui_pipe, from_gui_pipe;
+static uae_sem_t gui_sem, gui_init_sem, gui_quit_sem; /* gui_sem protects the DFx fields */
+
+static volatile int quit_gui = 0, quitted_gui = 0;
+
+static void save_config (void)
+{
+    FILE *f;
+    char tmp[257];
+
+    /* Backup the options file.  */
+    strcpy (tmp, optionsfile);
+    strcat (tmp, "~");
+    rename (optionsfile, tmp);
+
+    f = fopen (optionsfile, "w");
+    if (f == NULL) {
+       write_log ("Error saving options file!\n");
+       return;
+    }
+    save_options (f, &currprefs);
+    fclose (f);
+}
+
+static int nr_for_led (GtkWidget *led)
+{
+    int i;
+    i = 0;
+    while (led_widgets[i] != led)
+       i++;
+    return i;
+}
+
+static void enable_disk_buttons (int enable)
+{
+    int i;
+    for (i = 0; i < 4; i++) {
+       gtk_widget_set_sensitive (disk_insert_widget[i], enable);
+       gtk_widget_set_sensitive (disk_eject_widget[i], enable);
+    }
+}
+
+static void enable_snap_buttons (int enable)
+{
+    gtk_widget_set_sensitive (snap_save_widget, enable);
+    gtk_widget_set_sensitive (snap_load_widget, enable);
+}
+
+static void set_cpu_state (void)
+{
+    int i;
+
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (a24m_widget), changed_prefs.address_space_24 != 0);
+    gtk_widget_set_sensitive (a24m_widget, changed_prefs.cpu_level > 1 && changed_prefs.cpu_level < 4);
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ccpu_widget), changed_prefs.cpu_compatible != 0);
+    gtk_widget_set_sensitive (ccpu_widget, changed_prefs.cpu_level == 0);
+    gtk_widget_set_sensitive (cpuspeed_scale, changed_prefs.m68k_speed > 0);
+    for (i = 0; i < 10; i++)
+       gtk_widget_set_sensitive (z3size_widget[i],
+                                 changed_prefs.cpu_level >= 2 && ! changed_prefs.address_space_24);
+}
+
+static void set_cpu_widget (void)
+{
+    int nr = changed_prefs.cpu_level;
+
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cpu_widget[nr]), TRUE);
+    nr = currprefs.m68k_speed + 1 < 3 ? currprefs.m68k_speed + 1 : 2;
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cpuspeed_widgets[nr]), TRUE);
+
+}
+
+static void set_gfx_state (void)
+{
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bimm_widget), currprefs.immediate_blits != 0);
+#if 0
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b32_widget), currprefs.blits_32bit_enabled != 0);
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (afscr_widget), currprefs.gfx_afullscreen != 0);
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pfscr_widget), currprefs.gfx_pfullscreen != 0);
+#endif
+}
+
+static void set_chipset_state (void)
+{
+    int t0 = 0;
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (coll_widget[currprefs.collision_level]), TRUE);
+    if (currprefs.chipset_mask & CSMASK_AGA)
+       t0 = 3;
+    else if (currprefs.chipset_mask & CSMASK_ECS_DENISE)
+       t0 = 2;
+    else if (currprefs.chipset_mask & CSMASK_ECS_AGNUS)
+       t0 = 1;
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cslevel_widget[t0]), TRUE);
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fcop_widget), currprefs.fast_copper != 0);
+}
+
+static void set_sound_state (void)
+{
+    int stereo = currprefs.stereo + currprefs.mixed_stereo;
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sound_widget[currprefs.produce_sound]), 1);
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sound_ch_widget[stereo]), 1);
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sound_bits_widget[currprefs.sound_bits == 16]), 1);
+}
+
+static void set_mem_state (void)
+{
+    int t, t2;
+
+    t = 0;
+    t2 = currprefs.chipmem_size;
+    while (t < 4 && t2 > 0x80000)
+       t++, t2 >>= 1;
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (chipsize_widget[t]), 1);
+
+    t = 0;
+    t2 = currprefs.bogomem_size;
+    while (t < 3 && t2 >= 0x80000)
+       t++, t2 >>= 1;
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bogosize_widget[t]), 1);
+
+    t = 0;
+    t2 = currprefs.fastmem_size;
+    while (t < 4 && t2 >= 0x100000)
+       t++, t2 >>= 1;
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fastsize_widget[t]), 1);
+
+    t = 0;
+    t2 = currprefs.z3fastmem_size;
+    while (t < 9 && t2 >= 0x100000)
+       t++, t2 >>= 1;
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (z3size_widget[t]), 1);
+
+    t = 0;
+    t2 = currprefs.gfxmem_size;
+    while (t < 6 && t2 >= 0x100000)
+       t++, t2 >>= 1;
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (p96size_widget[t]), 1);
+
+    gtk_label_set_text (GTK_LABEL (rom_text_widget), currprefs.romfile);
+    gtk_label_set_text (GTK_LABEL (key_text_widget), currprefs.keyfile);
+}
+
+static void set_comp_state (void)
+{
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (compbyte_widget[currprefs.comptrustbyte]), 1);
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (compword_widget[currprefs.comptrustword]), 1);
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (complong_widget[currprefs.comptrustlong]), 1);
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (compaddr_widget[currprefs.comptrustnaddr]), 1);
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (compnf_widget[currprefs.compnf]), 1);
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (comp_hardflush_widget[currprefs.comp_hardflush]), 1);
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (comp_constjump_widget[currprefs.comp_constjump]), 1);
+
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (compfpu_widget[currprefs.compfpu]), 1);
+#if USE_OPTIMIZER
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (comp_midopt_widget[currprefs.comp_midopt]), 1);
+#endif
+#if USE_LOW_OPTIMIZER
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (comp_lowopt_widget[currprefs.comp_lowopt]), 1);
+#endif
+}
+
+static void set_joy_state (void)
+{
+    int j0t = changed_prefs.jport0;
+    int j1t = changed_prefs.jport1;
+    int i;
+
+    if (j0t == j1t) {
+       /* Can't happen */
+       j0t++;
+       j0t %= 6;
+    }
+    for (i = 0; i < 6; i++) {
+       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (joy_widget[0][i]), j0t == i);
+       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (joy_widget[1][i]), j1t == i);
+       gtk_widget_set_sensitive (joy_widget[0][i], j1t != i);
+       gtk_widget_set_sensitive (joy_widget[1][i], j0t != i);
+    }
+}
+
+static void set_hd_state (void)
+{
+    char texts[9][256];
+    char *tptrs[] = { texts[0], texts[1], texts[2], texts[3], texts[4], texts[5], texts[6], texts[7], texts[8] };
+    int nr = nr_units (currprefs.mountinfo);
+    int i;
+
+    gtk_clist_freeze (GTK_CLIST (hdlist_widget));
+    gtk_clist_clear (GTK_CLIST (hdlist_widget));
+    for (i = 0; i < nr; i++) {
+       int secspertrack, surfaces, reserved, blocksize, size;
+       int cylinders, readonly;
+       char *volname, *rootdir;
+       char *failure;
+
+       /* We always use currprefs.mountinfo for the GUI.  The filesystem
+          code makes a private copy which is updated every reset.  */
+       failure = get_filesys_unit (currprefs.mountinfo, i,
+                                   &volname, &rootdir, &readonly,
+                                   &secspertrack, &surfaces, &reserved,
+                                   &cylinders, &size, &blocksize);
+           
+       if (is_hardfile (currprefs.mountinfo, i)) {
+           sprintf (texts[0], "DH%d", i );
+           sprintf (texts[3], "%d", surfaces);
+           sprintf (texts[4], "%d", cylinders);
+           sprintf (texts[5], "%d", secspertrack);
+           sprintf (texts[6], "%d", reserved);
+           sprintf (texts[7], "%d", size);
+           sprintf (texts[8], "%d", blocksize);
+       } else {
+           strcpy (texts[0], volname);
+           strcpy (texts[3], "n/a");
+           strcpy (texts[4], "n/a");
+           strcpy (texts[5], "n/a");
+           strcpy (texts[6], "n/a");
+           strcpy (texts[7], "n/a");
+           strcpy (texts[8], "n/a");
+       }
+       strcpy (texts[1], rootdir);
+       strcpy (texts[2], readonly ? "y" : "n");
+       gtk_clist_append (GTK_CLIST (hdlist_widget), tptrs);
+    }
+    gtk_clist_thaw (GTK_CLIST (hdlist_widget));
+    gtk_widget_set_sensitive (hdchange_button, FALSE);
+    gtk_widget_set_sensitive (hddel_button, FALSE);
+}
+
+static void draw_led (int nr)
+{
+    GtkWidget *thing = led_widgets[nr];
+    GdkWindow *window = thing->window;
+    GdkGC *gc = gdk_gc_new (window);
+    GdkColor *col;
+
+    if (gui_ledstate & (1 << nr))
+       col = led_on + nr;
+    else
+       col = led_off + nr;
+    gdk_gc_set_foreground (gc, col);
+    gdk_draw_rectangle (window, gc, 1, 0, 0, -1, -1);
+    gdk_gc_destroy (gc);
+}
+
+static int my_idle (void)
+{
+    unsigned int leds = gui_ledstate;
+    int i;
+
+    if (quit_gui) {
+       gtk_main_quit ();
+       goto out;
+    }
+    while (comm_pipe_has_data (&to_gui_pipe)) {
+       int cmd = read_comm_pipe_int_blocking (&to_gui_pipe);
+       int n;
+       switch (cmd) {
+        case 0:
+           n = read_comm_pipe_int_blocking (&to_gui_pipe);
+           gtk_label_set_text (GTK_LABEL (disk_text_widget[n]), currprefs.df[n]);
+           break;
+        case 1:
+           /* Initialization.  */
+           set_cpu_widget ();
+           set_cpu_state ();
+           set_gfx_state ();
+           set_joy_state ();
+           set_sound_state ();
+           set_comp_state ();
+           set_mem_state ();
+           set_hd_state ();
+           set_chipset_state ();
+
+           gtk_widget_show (gui_window);
+           uae_sem_post (&gui_init_sem);
+           gui_active = 1;
+           break;
+       }
+    }
+
+    for (i = 0; i < 5; i++) {
+       unsigned int mask = 1 << i;
+       unsigned int on = leds & mask;
+
+       if (on == (prevledstate & mask))
+           continue;
+
+/*     printf(": %d %d\n", i, on);*/
+       draw_led (i);
+    }
+    prevledstate = leds;
+out:
+    return 1;
+}
+
+static int find_current_toggle (GtkWidget **widgets, int count)
+{
+    int i;
+    for (i = 0; i < count; i++)
+       if (GTK_TOGGLE_BUTTON (*widgets++)->active)
+           return i;
+    write_log ("GTKUI: Can't happen!\n");
+    return -1;
+}
+
+static void joy_changed (void)
+{
+    if (! gui_active)
+       return;
+
+    changed_prefs.jport0 = find_current_toggle (joy_widget[0], 6);
+    changed_prefs.jport1 = find_current_toggle (joy_widget[1], 6);
+    set_joy_state ();
+}
+
+static void coll_changed (void)
+{
+    changed_prefs.collision_level = find_current_toggle (coll_widget, 4);
+}
+
+static void cslevel_changed (void)
+{
+    int t = find_current_toggle (cslevel_widget, 4);
+    int t1 = 0;
+    if (t > 0)
+       t1 |= CSMASK_ECS_AGNUS;
+    if (t > 1)
+       t1 |= CSMASK_ECS_DENISE;
+    if (t > 2)
+       t1 |= CSMASK_AGA;
+    changed_prefs.chipset_mask = t1;
+}
+
+static void custom_changed (void)
+{
+    changed_prefs.gfx_framerate = framerate_adj->value;
+    changed_prefs.immediate_blits = GTK_TOGGLE_BUTTON (bimm_widget)->active;
+    changed_prefs.fast_copper = GTK_TOGGLE_BUTTON (fcop_widget)->active;
+#if 0
+    changed_prefs.blits_32bit_enabled = GTK_TOGGLE_BUTTON (b32_widget)->active;
+    changed_prefs.gfx_afullscreen = GTK_TOGGLE_BUTTON (afscr_widget)->active;
+    changed_prefs.gfx_pfullscreen = GTK_TOGGLE_BUTTON (pfscr_widget)->active;
+#endif
+}
+
+static void cpuspeed_changed (void)
+{
+    int which = find_current_toggle (cpuspeed_widgets, 3);
+    changed_prefs.m68k_speed = (which == 0 ? -1
+                               : which == 1 ? 0
+                               : cpuspeed_adj->value);
+    set_cpu_state ();
+}
+
+static void cputype_changed (void)
+{
+    int i, oldcl;
+    if (! gui_active)
+       return;
+
+    oldcl = changed_prefs.cpu_level;
+
+    changed_prefs.cpu_level = find_current_toggle (cpu_widget, 5);
+    changed_prefs.cpu_compatible = GTK_TOGGLE_BUTTON (ccpu_widget)->active;
+    changed_prefs.address_space_24 = GTK_TOGGLE_BUTTON (a24m_widget)->active;
+
+    if (changed_prefs.cpu_level != 0)
+       changed_prefs.cpu_compatible = 0;
+    /* 68000/68010 always have a 24 bit address space.  */
+    if (changed_prefs.cpu_level < 2)
+       changed_prefs.address_space_24 = 1;
+    /* Changing from 68000/68010 to 68020 should set a sane default.  */
+    else if (oldcl < 2)
+       changed_prefs.address_space_24 = 0;
+
+    set_cpu_state ();
+}
+
+static void chipsize_changed (void)
+{
+    int t = find_current_toggle (chipsize_widget, 5);
+    changed_prefs.chipmem_size = 0x80000 << t;
+    for (t = 0; t < 5; t++)
+       gtk_widget_set_sensitive (fastsize_widget[t], changed_prefs.chipmem_size <= 0x200000);
+    if (changed_prefs.chipmem_size > 0x200000) {
+       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fastsize_widget[0]), 1);
+       changed_prefs.fastmem_size = 0;
+    }
+}
+
+static void bogosize_changed (void)
+{
+    int t = find_current_toggle (bogosize_widget, 4);
+    changed_prefs.bogomem_size = (0x40000 << t) & ~0x40000;
+}
+
+static void fastsize_changed (void)
+{
+    int t = find_current_toggle (fastsize_widget, 5);
+    changed_prefs.fastmem_size = (0x80000 << t) & ~0x80000;
+}
+
+static void z3size_changed (void)
+{
+    int t = find_current_toggle (z3size_widget, 10);
+    changed_prefs.z3fastmem_size = (0x80000 << t) & ~0x80000;
+}
+
+static void p96size_changed (void)
+{
+    int t = find_current_toggle (p96size_widget, 7);
+    changed_prefs.gfxmem_size = (0x80000 << t) & ~0x80000;
+}
+
+static void sound_changed (void)
+{
+    changed_prefs.produce_sound = find_current_toggle (sound_widget, 4);
+    changed_prefs.stereo = find_current_toggle (sound_ch_widget, 3);
+    changed_prefs.mixed_stereo = 0;
+    if (changed_prefs.stereo == 2)
+       changed_prefs.mixed_stereo = changed_prefs.stereo = 1;
+    changed_prefs.sound_bits = (find_current_toggle (sound_bits_widget, 2) + 1) * 8;
+}
+
+static void comp_changed (void)
+{
+  changed_prefs.cachesize=cachesize_adj->value;
+  changed_prefs.comptrustbyte = find_current_toggle (compbyte_widget, 4);
+  changed_prefs.comptrustword = find_current_toggle (compword_widget, 4);
+  changed_prefs.comptrustlong = find_current_toggle (complong_widget, 4);
+  changed_prefs.comptrustnaddr = find_current_toggle (compaddr_widget, 4);
+  changed_prefs.compnf = find_current_toggle (compnf_widget, 2);
+  changed_prefs.comp_hardflush = find_current_toggle (comp_hardflush_widget, 2);
+  changed_prefs.comp_constjump = find_current_toggle (comp_constjump_widget, 2);
+  changed_prefs.compfpu= find_current_toggle (compfpu_widget, 2);
+#if USE_OPTIMIZER
+  changed_prefs.comp_midopt = find_current_toggle (comp_midopt_widget, 2);
+#endif
+#if USE_LOW_OPTIMIZER
+  changed_prefs.comp_lowopt = find_current_toggle (comp_lowopt_widget, 2);
+#endif
+}
+
+static void did_reset (void)
+{
+    if (quit_gui)
+       return;
+    
+    write_comm_pipe_int (&from_gui_pipe, 2, 1);
+}
+
+static void did_debug (void)
+{
+    if (quit_gui)
+       return;
+    
+    write_comm_pipe_int (&from_gui_pipe, 3, 1);
+}
+
+static void did_quit (void)
+{
+    if (quit_gui)
+       return;
+    
+    write_comm_pipe_int (&from_gui_pipe, 4, 1);
+}
+
+static void did_eject (GtkWidget *w, gpointer data)
+{
+    if (quit_gui)
+       return;
+    
+    write_comm_pipe_int (&from_gui_pipe, 0, 0);
+    write_comm_pipe_int (&from_gui_pipe, (int)data, 1);
+}
+
+static void pause_uae (GtkWidget *widget, gpointer data)
+{
+    if (quit_gui)
+       return;
+
+    write_comm_pipe_int (&from_gui_pipe, GTK_TOGGLE_BUTTON (widget)->active ? 5 : 6, 1);  
+}
+
+static void end_pause_uae (void)
+{
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pause_uae_widget), FALSE);
+}
+    
+static int filesel_active = -1;
+static GtkWidget *disk_selector;
+
+static int snapsel_active = -1;
+static char *gui_snapname, *gui_romname, *gui_keyname;
+
+static void did_close_insert (gpointer data)
+{
+    filesel_active = -1;
+    enable_disk_buttons (1);
+}
+
+static void did_insert_select (GtkObject *o)
+{
+    char *s = gtk_file_selection_get_filename (GTK_FILE_SELECTION (disk_selector));
+    printf ("%d %s\n", filesel_active, s);
+    if (quit_gui)
+       return;
+
+    uae_sem_wait (&gui_sem);
+    if (new_disk_string[filesel_active] != 0)
+       free (new_disk_string[filesel_active]);
+    new_disk_string[filesel_active] = strdup (s);
+    uae_sem_post (&gui_sem);
+    write_comm_pipe_int (&from_gui_pipe, 1, 0);
+    write_comm_pipe_int (&from_gui_pipe, filesel_active, 1);
+    filesel_active = -1;
+    enable_disk_buttons (1);
+    gtk_widget_destroy (disk_selector);
+}
+
+static char fsbuffer[100];
+
+static GtkWidget *make_file_selector (const char *title,
+                                     void (*insertfunc)(GtkObject *),
+                                     void (*closefunc)(gpointer))
+{
+    GtkWidget *p = gtk_file_selection_new (title);
+    gtk_signal_connect (GTK_OBJECT (p), "destroy", (GtkSignalFunc) closefunc, p);
+
+    gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (p)->ok_button),
+                              "clicked", (GtkSignalFunc) insertfunc,
+                              GTK_OBJECT (p));
+    gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (p)->cancel_button),
+                              "clicked", (GtkSignalFunc) gtk_widget_destroy,
+                              GTK_OBJECT (p));
+
+#if 0
+    gtk_window_set_title (GTK_WINDOW (p), title);
+#endif
+
+    gtk_widget_show (p);
+    return p;
+}
+
+static void filesel_set_path (GtkWidget *p, const char *path)
+{
+    size_t len = strlen (path);
+    if (len > 0 && ! access (path, R_OK)) {
+       char *tmp = xmalloc (len + 2);
+       strcpy (tmp, path);
+       strcat (tmp, "/");
+       gtk_file_selection_set_filename (GTK_FILE_SELECTION (p),
+                                        tmp);
+    }
+}
+
+static void did_insert (GtkWidget *w, gpointer data)
+{
+    int n = (int)data;
+    if (filesel_active != -1)
+       return;
+    filesel_active = n;
+    enable_disk_buttons (0);
+
+    sprintf (fsbuffer, "Select a disk image file for DF%d", n);
+    disk_selector = make_file_selector (fsbuffer, did_insert_select, did_close_insert);
+    filesel_set_path (disk_selector, currprefs.path_floppy);
+}
+
+static gint driveled_event (GtkWidget *thing, GdkEvent *event)
+{
+    int lednr = nr_for_led (thing);
+
+    switch (event->type) {
+     case GDK_MAP:
+       draw_led (lednr);
+       break;
+     case GDK_EXPOSE:
+       draw_led (lednr);
+       break;
+     default:
+       break;
+    }
+
+  return 0;
+}
+
+static GtkWidget *snap_selector;
+
+static void did_close_snap (gpointer gdata)
+{
+    snapsel_active = -1;
+    enable_snap_buttons (1);
+}
+
+static void did_snap_select (GtkObject *o)
+{
+    char *s = gtk_file_selection_get_filename (GTK_FILE_SELECTION (snap_selector));
+
+    if (quit_gui)
+       return;
+
+    uae_sem_wait (&gui_sem);
+    gui_snapname = strdup (s);
+    uae_sem_post (&gui_sem);
+    write_comm_pipe_int (&from_gui_pipe, 7, 0);
+    write_comm_pipe_int (&from_gui_pipe, snapsel_active, 1);
+    snapsel_active = -1;
+    enable_snap_buttons (1);
+    gtk_widget_destroy (snap_selector);
+}
+
+static void did_loadstate (void)
+{
+    if (snapsel_active != -1)
+       return;
+    snapsel_active = STATE_DORESTORE;
+    enable_snap_buttons (0);
+
+    snap_selector = make_file_selector ("Select a state file to restore",
+                                       did_snap_select, did_close_snap);
+}
+
+static void did_savestate (void)
+{
+    if (snapsel_active != -1)
+       return;
+    snapsel_active = STATE_DOSAVE;
+    enable_snap_buttons (0);
+
+    snap_selector = make_file_selector ("Select a filename for the state file",
+                                       did_snap_select, did_close_snap);
+}
+
+static GtkWidget *rom_selector;
+
+static void did_close_rom (gpointer gdata)
+{
+    gtk_widget_set_sensitive (rom_change_widget, 1);
+}
+
+static void did_rom_select (GtkObject *o)
+{
+    char *s = gtk_file_selection_get_filename (GTK_FILE_SELECTION (rom_selector));
+
+    if (quit_gui)
+       return;
+
+    gtk_widget_set_sensitive (rom_change_widget, 1);
+
+    uae_sem_wait (&gui_sem);
+    gui_romname = strdup (s);
+    uae_sem_post (&gui_sem);
+    write_comm_pipe_int (&from_gui_pipe, 8, 0);
+    gtk_label_set_text (GTK_LABEL (rom_text_widget), gui_romname);
+    gtk_widget_destroy (rom_selector);
+}
+
+static void did_romchange (GtkWidget *w, gpointer data)
+{
+    gtk_widget_set_sensitive (rom_change_widget, 0);
+
+    rom_selector = make_file_selector ("Select a ROM file",
+                                      did_rom_select, did_close_rom);
+    filesel_set_path (rom_selector, currprefs.path_rom);
+}
+
+static GtkWidget *key_selector;
+
+static void did_close_key (gpointer gdata)
+{
+    gtk_widget_set_sensitive (key_change_widget, 1);
+}
+
+static void did_key_select (GtkObject *o)
+{
+    char *s = gtk_file_selection_get_filename (GTK_FILE_SELECTION (key_selector));
+
+    if (quit_gui)
+       return;
+
+    gtk_widget_set_sensitive (key_change_widget, 1);
+
+    uae_sem_wait (&gui_sem);
+    gui_keyname = strdup (s);
+    uae_sem_post (&gui_sem);
+    write_comm_pipe_int (&from_gui_pipe, 9, 0);
+    gtk_label_set_text (GTK_LABEL (key_text_widget), gui_keyname);
+    gtk_widget_destroy (key_selector);
+}
+
+static void did_keychange (GtkWidget *w, gpointer data)
+{
+    gtk_widget_set_sensitive (key_change_widget, 0);
+
+    key_selector = make_file_selector ("Select a Kickstart key file",
+                                      did_key_select, did_close_key);
+    filesel_set_path (key_selector, currprefs.path_rom);
+}
+
+static void add_empty_vbox (GtkWidget *tobox)
+{
+    GtkWidget *thing = gtk_vbox_new (FALSE, 0);
+    gtk_widget_show (thing);
+    gtk_box_pack_start (GTK_BOX (tobox), thing, TRUE, TRUE, 0);
+}
+
+static void add_empty_hbox (GtkWidget *tobox)
+{
+    GtkWidget *thing = gtk_hbox_new (FALSE, 0);
+    gtk_widget_show (thing);
+    gtk_box_pack_start (GTK_BOX (tobox), thing, TRUE, TRUE, 0);
+}
+
+static void add_centered_to_vbox (GtkWidget *vbox, GtkWidget *w)
+{
+    GtkWidget *hbox = gtk_hbox_new (TRUE, 0);
+    gtk_widget_show (hbox);
+    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, FALSE, 0);
+    gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
+}
+
+static GtkWidget *make_labelled_widget (const char *str, GtkWidget *thing)
+{
+    GtkWidget *label = gtk_label_new (str);
+    GtkWidget *hbox2 = gtk_hbox_new (FALSE, 4);
+
+    gtk_widget_show (label);
+    gtk_widget_show (thing);
+
+    gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 0);
+    gtk_box_pack_start (GTK_BOX (hbox2), thing, FALSE, TRUE, 0);
+
+    return hbox2;
+}
+
+static GtkWidget *add_labelled_widget_centered (const char *str, GtkWidget *thing, GtkWidget *vbox)
+{
+    GtkWidget *w = make_labelled_widget (str, thing);
+    gtk_widget_show (w);
+    add_centered_to_vbox (vbox, w);
+    return w;
+}
+
+static int make_radio_group (const char **labels, GtkWidget *tobox,
+                             GtkWidget **saveptr, gint t1, gint t2,
+                             void (*sigfunc) (void), int count, GSList *group)
+{
+    int t = 0;
+
+    while (*labels && (count == -1 || count-- > 0)) {
+       GtkWidget *thing = gtk_radio_button_new_with_label (group, *labels++);
+       group = gtk_radio_button_group (GTK_RADIO_BUTTON (thing));
+
+       *saveptr++ = thing;
+       gtk_widget_show (thing);
+       gtk_box_pack_start (GTK_BOX (tobox), thing, t1, t2, 0);
+       gtk_signal_connect (GTK_OBJECT (thing), "clicked", (GtkSignalFunc) sigfunc, NULL);
+       t++;
+    }
+    return t;
+}
+
+static GtkWidget *make_radio_group_box (const char *title, const char **labels,
+                                       GtkWidget **saveptr, int horiz,
+                                       void (*sigfunc) (void))
+{
+    GtkWidget *frame, *newbox;
+
+    frame = gtk_frame_new (title);
+    newbox = (horiz ? gtk_hbox_new : gtk_vbox_new) (FALSE, 4);
+    gtk_widget_show (newbox);
+    gtk_container_set_border_width (GTK_CONTAINER (newbox), 4);
+    gtk_container_add (GTK_CONTAINER (frame), newbox);
+    make_radio_group (labels, newbox, saveptr, horiz, !horiz, sigfunc, -1, NULL);
+    return frame;
+}
+
+static GtkWidget *make_radio_group_box_1 (const char *title, const char **labels,
+                                         GtkWidget **saveptr, int horiz,
+                                         void (*sigfunc) (void), int elts_per_column)
+{
+    GtkWidget *frame, *newbox;
+    GtkWidget *column;
+    GSList *group = 0;
+
+    frame = gtk_frame_new (title);
+    column = (horiz ? gtk_vbox_new : gtk_hbox_new) (FALSE, 4);
+    gtk_container_add (GTK_CONTAINER (frame), column);
+    gtk_widget_show (column);
+
+    while (*labels) {
+       int count;
+       newbox = (horiz ? gtk_hbox_new : gtk_vbox_new) (FALSE, 4);
+       gtk_widget_show (newbox);
+       gtk_container_set_border_width (GTK_CONTAINER (newbox), 4);
+       gtk_container_add (GTK_CONTAINER (column), newbox);
+       count = make_radio_group (labels, newbox, saveptr, horiz, !horiz, sigfunc, elts_per_column, group);
+       labels += count;
+       saveptr += count;
+       group = gtk_radio_button_group (GTK_RADIO_BUTTON (saveptr[-1]));
+    }
+    return frame;
+}
+
+static GtkWidget *make_led (int nr)
+{
+    GtkWidget *subframe, *the_led, *thing;
+    GdkColormap *colormap;
+
+    the_led = gtk_vbox_new (FALSE, 0);
+    gtk_widget_show (the_led);
+
+    thing = gtk_preview_new (GTK_PREVIEW_COLOR);
+    gtk_box_pack_start (GTK_BOX (the_led), thing, TRUE, TRUE, 0);
+    gtk_widget_show (thing);
+
+    subframe = gtk_frame_new (NULL);
+    gtk_box_pack_start (GTK_BOX (the_led), subframe, TRUE, TRUE, 0);
+    gtk_widget_show (subframe);
+
+    thing = gtk_drawing_area_new ();
+    gtk_drawing_area_size (GTK_DRAWING_AREA (thing), 20, 5);
+    gtk_widget_set_events (thing, GDK_EXPOSURE_MASK);
+    gtk_container_add (GTK_CONTAINER (subframe), thing);
+    colormap = gtk_widget_get_colormap (thing);
+    led_on[nr].red = nr == 0 ? 0xEEEE : 0xCCCC;
+    led_on[nr].green = nr == 0 ? 0: 0xFFFF;
+    led_on[nr].blue = 0;
+    led_on[nr].pixel = 0;
+    led_off[nr].red = 0;
+    led_off[nr].green = 0;
+    led_off[nr].blue = 0;
+    led_off[nr].pixel = 0;
+    gdk_color_alloc (colormap, led_on + nr);
+    gdk_color_alloc (colormap, led_off + nr);
+    led_widgets[nr] = thing;
+    gtk_signal_connect (GTK_OBJECT (thing), "event",
+                       (GtkSignalFunc) driveled_event, (gpointer) thing);
+    gtk_widget_show (thing);
+
+    thing = gtk_preview_new (GTK_PREVIEW_COLOR);
+    gtk_box_pack_start (GTK_BOX (the_led), thing, TRUE, TRUE, 0);
+    gtk_widget_show (thing);
+    
+    return the_led;
+}
+
+static GtkWidget *make_file_container (const char *title, GtkWidget *vbox)
+{
+    GtkWidget *thing = gtk_frame_new (title);
+    GtkWidget *buttonbox = gtk_hbox_new (FALSE, 4);
+
+    gtk_container_set_border_width (GTK_CONTAINER (buttonbox), 4);
+    gtk_container_add (GTK_CONTAINER (thing), buttonbox);
+    gtk_box_pack_start (GTK_BOX (vbox), thing, FALSE, TRUE, 0);
+    gtk_widget_show (buttonbox);
+    gtk_widget_show (thing);
+
+    return buttonbox;
+}
+
+static GtkWidget *make_file_widget (GtkWidget *buttonbox)
+{
+    GtkWidget *thing, *subthing;
+    GtkWidget *subframe = gtk_frame_new (NULL);
+
+    gtk_frame_set_shadow_type (GTK_FRAME (subframe), GTK_SHADOW_ETCHED_OUT);
+    gtk_box_pack_start (GTK_BOX (buttonbox), subframe, TRUE, TRUE, 0);
+    gtk_widget_show (subframe);
+    subthing = gtk_vbox_new (FALSE, 0);
+    gtk_widget_show (subthing);
+    gtk_container_add (GTK_CONTAINER (subframe), subthing);
+    thing = gtk_label_new ("");
+    gtk_widget_show (thing);
+    gtk_box_pack_start (GTK_BOX (subthing), thing, TRUE, TRUE, 0);
+
+    return thing;
+}
+
+static void make_floppy_disks (GtkWidget *vbox)
+{
+    GtkWidget *thing, *subthing, *subframe, *buttonbox;
+    char buf[5];
+    int i;
+
+    add_empty_vbox (vbox);
+
+    for (i = 0; i < 4; i++) {
+       /* Frame with an hbox and the "DFx:" title */
+       sprintf (buf, "DF%d:", i);
+       buttonbox = make_file_container (buf, vbox);
+       
+       /* LED */
+       subthing = make_led (i + 1);
+       gtk_box_pack_start (GTK_BOX (buttonbox), subthing, FALSE, TRUE, 0);
+
+       /* Current file display */
+       disk_text_widget[i] = make_file_widget (buttonbox);
+
+       /* Now, the buttons.  */
+       thing = gtk_button_new_with_label ("Eject");
+       gtk_box_pack_start (GTK_BOX (buttonbox), thing, FALSE, TRUE, 0);
+       gtk_widget_show (thing);
+       disk_eject_widget[i] = thing;
+       gtk_signal_connect (GTK_OBJECT (thing), "clicked", (GtkSignalFunc) did_eject, (gpointer) i);
+
+       thing = gtk_button_new_with_label ("Insert");
+       gtk_box_pack_start (GTK_BOX (buttonbox), thing, FALSE, TRUE, 0);
+       gtk_widget_show (thing);
+       disk_insert_widget[i] = thing;
+       gtk_signal_connect (GTK_OBJECT (thing), "clicked", (GtkSignalFunc) did_insert, (gpointer) i);
+    }
+
+    add_empty_vbox (vbox);
+}
+
+static GtkWidget *make_cpu_speed_sel (void)
+{
+    int t;
+    static const char *labels[] = {
+       "Optimize for host CPU speed","Approximate 68000/7MHz speed", "Adjustable",
+       NULL
+    };
+    GtkWidget *frame, *newbox;
+
+    frame = gtk_frame_new ("CPU speed");
+    newbox = gtk_vbox_new (FALSE, 4);
+    gtk_widget_show (newbox);
+    gtk_container_set_border_width (GTK_CONTAINER (newbox), 4);
+    gtk_container_add (GTK_CONTAINER (frame), newbox);
+    make_radio_group (labels, newbox, cpuspeed_widgets, 0, 1, cpuspeed_changed, -1, NULL);
+
+    t = currprefs.m68k_speed > 0 ? currprefs.m68k_speed : 4 * CYCLE_UNIT;
+    cpuspeed_adj = GTK_ADJUSTMENT (gtk_adjustment_new (t, 1.0, 5120.0, 1.0, 1.0, 1.0));
+    gtk_signal_connect (GTK_OBJECT (cpuspeed_adj), "value_changed",
+                       GTK_SIGNAL_FUNC (cpuspeed_changed), NULL);
+
+    cpuspeed_scale = gtk_hscale_new (cpuspeed_adj);
+    gtk_range_set_update_policy (GTK_RANGE (cpuspeed_scale), GTK_UPDATE_DELAYED);
+    gtk_scale_set_digits (GTK_SCALE (cpuspeed_scale), 0);
+    gtk_scale_set_value_pos (GTK_SCALE (cpuspeed_scale), GTK_POS_RIGHT);
+    cpuspeed_scale = add_labelled_widget_centered ("Cycles per instruction:", cpuspeed_scale, newbox);
+
+    return frame;
+}
+
+static void make_cpu_widgets (GtkWidget *vbox)
+{
+    int i;
+    GtkWidget *newbox, *hbox, *frame;
+    GtkWidget *thing;
+    static const char *radiolabels[] = {
+       "68000", "68010", "68020", "68020+68881", "68040",
+       NULL
+    };
+
+    add_empty_vbox (vbox);
+
+    hbox = gtk_hbox_new (FALSE, 0);
+    add_empty_vbox (hbox);
+
+    newbox = make_radio_group_box ("CPU type", radiolabels, cpu_widget, 0, cputype_changed);
+    gtk_widget_show (newbox);
+    gtk_box_pack_start (GTK_BOX (hbox), newbox, FALSE, FALSE, 0);
+
+    newbox = make_cpu_speed_sel ();
+    gtk_widget_show (newbox);
+    gtk_box_pack_start (GTK_BOX (hbox), newbox, FALSE, FALSE, 0);
+
+    add_empty_vbox (hbox);
+    gtk_widget_show (hbox); 
+    gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+
+    frame = gtk_frame_new ("CPU flags");
+    add_centered_to_vbox (vbox, frame);
+    gtk_widget_show (frame);
+    newbox = gtk_vbox_new (FALSE, 4);
+    gtk_widget_show (newbox);
+    gtk_container_set_border_width (GTK_CONTAINER (newbox), 4);
+    gtk_container_add (GTK_CONTAINER (frame), newbox);
+
+    a24m_widget = gtk_check_button_new_with_label ("24 bit address space");
+    add_centered_to_vbox (newbox, a24m_widget);
+    gtk_widget_show (a24m_widget);
+    ccpu_widget = gtk_check_button_new_with_label ("Slow but compatible");
+    add_centered_to_vbox (newbox, ccpu_widget);
+    gtk_widget_show (ccpu_widget);
+
+    add_empty_vbox (vbox);
+
+    gtk_signal_connect (GTK_OBJECT (ccpu_widget), "clicked",
+                       (GtkSignalFunc) cputype_changed, NULL);
+    gtk_signal_connect (GTK_OBJECT (a24m_widget), "clicked",
+                       (GtkSignalFunc) cputype_changed, NULL);    
+}
+
+static void make_gfx_widgets (GtkWidget *vbox)
+{
+    GtkWidget *thing, *frame, *newbox, *hbox;
+    static const char *p96labels[] = {
+       "None", "1 MB", "2 MB", "4 MB", "8 MB", "16 MB", "32 MB", NULL
+    };
+
+    add_empty_vbox (vbox);
+
+    hbox = gtk_hbox_new (FALSE, 10);
+    gtk_widget_show (hbox);
+    add_centered_to_vbox (vbox, hbox);
+
+    frame = make_radio_group_box_1 ("P96 RAM", p96labels, p96size_widget, 0, p96size_changed, 4);
+    gtk_widget_show (frame);
+    gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, TRUE, 0);
+
+    frame = gtk_frame_new ("Miscellaneous");
+    gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
+
+    gtk_widget_show (frame);
+    newbox = gtk_vbox_new (FALSE, 4);
+    gtk_widget_show (newbox);
+    gtk_container_set_border_width (GTK_CONTAINER (newbox), 4);
+    gtk_container_add (GTK_CONTAINER (frame), newbox);
+
+    framerate_adj = GTK_ADJUSTMENT (gtk_adjustment_new (currprefs.gfx_framerate, 1.0, 21.0, 1.0, 1.0, 1.0));
+    gtk_signal_connect (GTK_OBJECT (framerate_adj), "value_changed",
+                       GTK_SIGNAL_FUNC (custom_changed), NULL);
+
+    thing = gtk_hscale_new (framerate_adj);
+    gtk_range_set_update_policy (GTK_RANGE (thing), GTK_UPDATE_DELAYED);
+    gtk_scale_set_digits (GTK_SCALE (thing), 0);
+    gtk_scale_set_value_pos (GTK_SCALE (thing), GTK_POS_RIGHT);
+    add_labelled_widget_centered ("Framerate:", thing, newbox);
+
+    b32_widget = gtk_check_button_new_with_label ("32 bit blitter");
+    add_centered_to_vbox (newbox, b32_widget);
+#if 0
+    gtk_widget_show (b32_widget);
+#endif
+    bimm_widget = gtk_check_button_new_with_label ("Immediate blits");
+    add_centered_to_vbox (newbox, bimm_widget);
+    gtk_widget_show (bimm_widget);
+
+    afscr_widget = gtk_check_button_new_with_label ("Amiga modes fullscreen");
+    add_centered_to_vbox (newbox, afscr_widget);
+#if 0
+    gtk_widget_show (afscr_widget);
+#endif
+    pfscr_widget = gtk_check_button_new_with_label ("Picasso modes fullscreen");
+    add_centered_to_vbox (newbox, pfscr_widget);
+#if 0
+    gtk_widget_show (pfscr_widget);
+#endif
+    add_empty_vbox (vbox);
+
+    gtk_signal_connect (GTK_OBJECT (bimm_widget), "clicked",
+                       (GtkSignalFunc) custom_changed, NULL);
+#if 0
+    gtk_signal_connect (GTK_OBJECT (b32_widget), "clicked",
+                       (GtkSignalFunc) custom_changed, NULL);
+    gtk_signal_connect (GTK_OBJECT (afscr_widget), "clicked",
+                       (GtkSignalFunc) custom_changed, NULL);
+    gtk_signal_connect (GTK_OBJECT (pfscr_widget), "clicked",
+                       (GtkSignalFunc) custom_changed, NULL);
+#endif
+}
+
+static void make_chipset_widgets (GtkWidget *vbox)
+{
+    GtkWidget *frame, *newbox, *hbox;
+    static const char *colllabels[] = {
+       "None (fastest)", "Sprites only", "Sprites & playfields", "Full (very slow)",
+       NULL
+    };
+    static const char *cslevellabels[] = {
+       "OCS", "ECS Agnus", "Full ECS", "AGA", NULL
+    };
+
+    add_empty_vbox (vbox);
+
+    hbox = gtk_hbox_new (FALSE, 10);
+    gtk_widget_show (hbox);
+    add_centered_to_vbox (vbox, hbox);
+
+    newbox = make_radio_group_box ("Sprite collisions", colllabels, coll_widget, 0, coll_changed);
+    gtk_widget_show (newbox);
+    gtk_box_pack_start (GTK_BOX (hbox), newbox, FALSE, TRUE, 0);
+
+    newbox = make_radio_group_box ("Chipset", cslevellabels, cslevel_widget, 0, cslevel_changed);
+    gtk_widget_show (newbox);
+    gtk_box_pack_start (GTK_BOX (hbox), newbox, FALSE, TRUE, 0);
+
+    fcop_widget = gtk_check_button_new_with_label ("Enable copper speedup code");
+    add_centered_to_vbox (vbox, fcop_widget);
+    gtk_widget_show (fcop_widget);
+
+    gtk_signal_connect (GTK_OBJECT (fcop_widget), "clicked",
+                       (GtkSignalFunc) custom_changed, NULL);
+
+    add_empty_vbox (vbox);
+}
+
+static void make_sound_widgets (GtkWidget *vbox)
+{
+    GtkWidget *frame, *newbox;
+    int i;
+    GtkWidget *hbox;
+    static const char *soundlabels1[] = {
+       "None", "No output", "Normal", "Accurate",
+       NULL
+    }, *soundlabels2[] = {
+       "8 bit", "16 bit",
+       NULL
+    }, *soundlabels3[] = {
+       "Mono", "Stereo", "Mixed",
+       NULL
+    };
+
+    add_empty_vbox (vbox);
+
+    newbox = make_radio_group_box ("Mode", soundlabels1, sound_widget, 1, sound_changed);
+    gtk_widget_show (newbox);
+    add_centered_to_vbox (vbox, newbox);
+
+    hbox = gtk_hbox_new (FALSE, 10);
+    gtk_widget_show (hbox);
+    add_centered_to_vbox (vbox, hbox);
+    newbox = make_radio_group_box ("Channels", soundlabels3, sound_ch_widget, 1, sound_changed);
+    gtk_widget_show (newbox);
+    gtk_box_pack_start (GTK_BOX (hbox), newbox, FALSE, TRUE, 0);
+    newbox = make_radio_group_box ("Resolution", soundlabels2, sound_bits_widget, 1, sound_changed);
+    gtk_widget_show (newbox);
+    gtk_box_pack_start (GTK_BOX (hbox), newbox, FALSE, TRUE, 0);
+
+    add_empty_vbox (vbox);
+}
+
+static void make_mem_widgets (GtkWidget *vbox)
+{
+    GtkWidget *hbox = gtk_hbox_new (FALSE, 10);
+    GtkWidget *label, *frame;
+
+    static const char *chiplabels[] = {
+       "512 KB", "1 MB", "2 MB", "4 MB", "8 MB", NULL
+    };
+    static const char *bogolabels[] = {
+       "None", "512 KB", "1 MB", "1.8 MB", NULL
+    };
+    static const char *fastlabels[] = {
+       "None", "1 MB", "2 MB", "4 MB", "8 MB", NULL
+    };
+    static const char *z3labels[] = {
+       "None", "1 MB", "2 MB", "4 MB", "8 MB",
+       "16 MB", "32 MB", "64 MB", "128 MB", "256 MB",
+       NULL
+    };
+
+    add_empty_vbox (vbox);
+
+    {
+       GtkWidget *buttonbox = make_file_container ("Kickstart ROM file:", vbox);
+       GtkWidget *thing = gtk_button_new_with_label ("Change");
+
+       /* Current file display */
+       rom_text_widget = make_file_widget (buttonbox);
+
+       gtk_box_pack_start (GTK_BOX (buttonbox), thing, FALSE, TRUE, 0);
+       gtk_widget_show (thing);
+       rom_change_widget = thing;
+       gtk_signal_connect (GTK_OBJECT (thing), "clicked", (GtkSignalFunc) did_romchange, 0);
+    }
+
+    {
+       GtkWidget *buttonbox = make_file_container ("ROM key file for Cloanto Amiga Forever:", vbox);
+       GtkWidget *thing = gtk_button_new_with_label ("Change");
+
+       /* Current file display */
+       key_text_widget = make_file_widget (buttonbox);
+
+       gtk_box_pack_start (GTK_BOX (buttonbox), thing, FALSE, TRUE, 0);
+       gtk_widget_show (thing);
+       key_change_widget = thing;
+       gtk_signal_connect (GTK_OBJECT (thing), "clicked", (GtkSignalFunc) did_keychange, 0);
+    }
+
+    gtk_widget_show (hbox);
+    add_centered_to_vbox (vbox, hbox);
+
+    add_empty_vbox (vbox);
+
+    label = gtk_label_new ("These settings take effect after the next reset.");
+    gtk_widget_show (label);
+    add_centered_to_vbox (vbox, label);
+
+    frame = make_radio_group_box ("Chip Mem", chiplabels, chipsize_widget, 0, chipsize_changed);
+    gtk_widget_show (frame);
+    gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, TRUE, 0);
+
+    frame = make_radio_group_box ("Slow Mem", bogolabels, bogosize_widget, 0, bogosize_changed);
+    gtk_widget_show (frame);
+    gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, TRUE, 0);
+
+    frame = make_radio_group_box ("Fast Mem", fastlabels, fastsize_widget, 0, fastsize_changed);
+    gtk_widget_show (frame);
+    gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, TRUE, 0);
+
+    frame = make_radio_group_box_1 ("Z3 Mem", z3labels, z3size_widget, 0, z3size_changed, 5);
+    gtk_widget_show (frame);
+    gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, TRUE, 0);
+}
+
+static void make_comp_widgets (GtkWidget *vbox)
+{
+    GtkWidget *frame, *newbox;
+    int i;
+    GtkWidget *hbox;
+    static const char *complabels1[] = {
+       "Direct", "Indirect", "Indirect for KS", "Direct after Picasso",
+       NULL
+    },*complabels2[] = {
+       "Direct", "Indirect", "Indirect for KS", "Direct after Picasso", 
+       NULL
+    },*complabels3[] = {
+       "Direct", "Indirect", "Indirect for KS", "Direct after Picasso", 
+       NULL
+    },*complabels3a[] = {
+       "Direct", "Indirect", "Indirect for KS", "Direct after Picasso", 
+       NULL
+    }, *complabels4[] = {
+      "Always generate", "Only generate when needed",
+       NULL
+    }, *complabels5[] = {
+      "Disable", "Enable",
+       NULL
+    }, *complabels6[] = {
+      "Disable", "Enable",
+       NULL
+    }, *complabels7[] = {
+      "Disable", "Enable",
+       NULL
+    }, *complabels8[] = {
+      "Soft", "Hard",
+       NULL
+    }, *complabels9[] = {
+      "Disable", "Enable", 
+       NULL
+    };
+    GtkWidget *thing;
+
+    add_empty_vbox (vbox);
+
+    newbox = make_radio_group_box ("Byte access", complabels1, compbyte_widget, 1, comp_changed);
+    gtk_widget_show (newbox);
+    add_centered_to_vbox (vbox, newbox);
+    newbox = make_radio_group_box ("Word access", complabels2, compword_widget, 1, comp_changed);
+    gtk_widget_show (newbox);
+    add_centered_to_vbox (vbox, newbox);
+    newbox = make_radio_group_box ("Long access", complabels3, complong_widget, 1, comp_changed);
+    gtk_widget_show (newbox);
+    add_centered_to_vbox (vbox, newbox);
+    newbox = make_radio_group_box ("Address lookup", complabels3a, compaddr_widget, 1, comp_changed);
+    gtk_widget_show (newbox);
+    add_centered_to_vbox (vbox, newbox);
+
+    newbox = make_radio_group_box ("Flags", complabels4, compnf_widget, 1, comp_changed);
+    gtk_widget_show (newbox);
+    add_centered_to_vbox (vbox, newbox);
+
+    newbox = make_radio_group_box ("Icache flushes", complabels8, comp_hardflush_widget, 1, comp_changed);
+    gtk_widget_show (newbox);
+    add_centered_to_vbox (vbox, newbox);
+
+    newbox = make_radio_group_box ("Compile through uncond branch", complabels9, comp_constjump_widget, 1, comp_changed);
+    gtk_widget_show (newbox);
+    add_centered_to_vbox (vbox, newbox);
+
+    newbox = make_radio_group_box ("JIT FPU compiler", complabels7, compfpu_widget, 1, comp_changed);
+    gtk_widget_show (newbox);
+    add_centered_to_vbox (vbox, newbox);
+
+#if USE_OPTIMIZER
+    newbox = make_radio_group_box ("Mid Level Optimizer", complabels5, comp_midopt_widget, 1, comp_changed);
+    gtk_widget_show (newbox);
+    add_centered_to_vbox (vbox, newbox);
+#endif
+
+#if USE_LOW_OPTIMIZER
+    newbox = make_radio_group_box ("Low Level Optimizer", complabels6, comp_lowopt_widget, 1, comp_changed);
+    gtk_widget_show (newbox);
+    add_centered_to_vbox (vbox, newbox);
+#endif
+
+    cachesize_adj = GTK_ADJUSTMENT (gtk_adjustment_new (currprefs.cachesize, 0.0, 16384.0, 1.0, 1.0, 1.0));
+    gtk_signal_connect (GTK_OBJECT (cachesize_adj), "value_changed",
+                       GTK_SIGNAL_FUNC (comp_changed), NULL);
+
+    thing = gtk_hscale_new (cachesize_adj);
+    gtk_range_set_update_policy (GTK_RANGE (thing), GTK_UPDATE_DELAYED);
+    gtk_scale_set_digits (GTK_SCALE (thing), 0);
+    gtk_scale_set_value_pos (GTK_SCALE (thing), GTK_POS_RIGHT);
+    add_labelled_widget_centered ("Translation buffer(kB):", thing, vbox);
+
+    add_empty_vbox (vbox);
+}
+
+
+static void make_joy_widgets (GtkWidget *dvbox)
+{
+    int i;
+    GtkWidget *hbox = gtk_hbox_new (FALSE, 10);
+    static const char *joylabels[] = {
+       "Joystick 0", "Joystick 1", "Mouse", "Numeric pad",
+       "Cursor keys/Right Ctrl", "T/F/H/B/Left Alt",
+       NULL
+    };
+
+    add_empty_vbox (dvbox);
+    gtk_widget_show (hbox);
+    add_centered_to_vbox (dvbox, hbox);
+
+    for (i = 0; i < 2; i++) {
+       GtkWidget *vbox, *frame;
+       GtkWidget *thing;
+       char buffer[20];
+       int j;
+
+       sprintf (buffer, "Port %d", i);
+       frame = make_radio_group_box (buffer, joylabels, joy_widget[i], 0, joy_changed);
+       gtk_widget_show (frame);
+       gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, TRUE, 0);
+    }
+
+    add_empty_vbox (dvbox);
+}
+
+static int hd_change_mode;
+
+static void newdir_ok (void)
+{
+    int n;
+    strcpy (dirdlg_volname, gtk_entry_get_text (GTK_ENTRY (volname_entry)));
+    strcpy (dirdlg_path, gtk_entry_get_text (GTK_ENTRY (path_entry)));
+
+    n = strlen (dirdlg_volname);
+    /* Strip colons from the end.  */
+    if (n > 0) {
+       if (dirdlg_volname[n - 1] == ':')
+           dirdlg_volname[n - 1] = '\0';
+    }
+    if (strlen (dirdlg_volname) == 0 || strlen (dirdlg_path) == 0) {
+       /* Uh, no messageboxes in gtk?  */
+    } else if (hd_change_mode) {
+       set_filesys_unit (currprefs.mountinfo, selected_hd_row, dirdlg_volname, dirdlg_path,
+                         0, 0, 0, 0, 0);
+       set_hd_state ();
+    } else {
+       add_filesys_unit (currprefs.mountinfo, dirdlg_volname, dirdlg_path,
+                         0, 0, 0, 0, 0);
+       set_hd_state ();
+    }
+    gtk_widget_destroy (dirdlg);
+}
+
+static GtkWidget *create_dirdlg (const char *title)
+{
+    GtkWidget *vbox, *hbox, *thing, *label1, *button;
+
+    dirdlg = gtk_dialog_new ();
+
+    gtk_window_set_title (GTK_WINDOW (dirdlg), title);
+    gtk_window_set_position (GTK_WINDOW (dirdlg), GTK_WIN_POS_MOUSE);
+    gtk_window_set_modal (GTK_WINDOW (dirdlg), TRUE);
+    gtk_widget_show (dirdlg);
+
+    vbox = GTK_DIALOG (dirdlg)->vbox;
+    hbox = gtk_hbox_new (FALSE, 10);
+    gtk_widget_show (hbox);
+    gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 10);
+    label1 = gtk_label_new ("Path:");
+    gtk_box_pack_start (GTK_BOX (hbox), label1, FALSE, TRUE, 10);
+    gtk_widget_show (label1);
+    thing = gtk_entry_new_with_max_length (255);
+    gtk_box_pack_start (GTK_BOX (hbox), thing, TRUE, TRUE, 10);   
+    gtk_widget_show (thing);
+    path_entry = thing;
+
+    hbox = gtk_hbox_new (FALSE, 10);
+    gtk_widget_show (hbox);
+    gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 10);
+    thing = gtk_label_new ("Volume name:");
+    gtk_box_pack_start (GTK_BOX (hbox), thing, FALSE, TRUE, 10);
+    gtk_widget_show (thing);
+    thing = gtk_entry_new_with_max_length (255);
+    gtk_box_pack_start (GTK_BOX (hbox), thing, TRUE, TRUE, 10);   
+    gtk_widget_show (thing);
+    gtk_widget_set_usize (thing, 200, -1);
+    volname_entry = thing;
+
+    hbox = GTK_DIALOG (dirdlg)->action_area;
+    button = gtk_button_new_with_label ("OK");
+    gtk_signal_connect (GTK_OBJECT (button), "clicked",
+                       GTK_SIGNAL_FUNC(newdir_ok), NULL);
+    GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+    gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
+    gtk_widget_grab_default (button);
+    gtk_widget_show (button);
+
+    button = gtk_button_new_with_label ("Cancel");
+    gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+                              GTK_SIGNAL_FUNC (gtk_widget_destroy),
+                              GTK_OBJECT (dirdlg));
+    gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
+    gtk_widget_show (button);
+}
+
+static void did_newdir (void)
+{
+    hd_change_mode = 0;
+    create_dirdlg ("Add a new mounted directory");
+}
+static void did_newhdf (void)
+{
+    hd_change_mode = 0;
+}
+
+static void did_hdchange (void)
+{
+    int secspertrack, surfaces, reserved, blocksize, size;
+    int cylinders, readonly;
+    char *volname, *rootdir;
+    char *failure;
+
+    failure = get_filesys_unit (currprefs.mountinfo, selected_hd_row,
+                               &volname, &rootdir, &readonly,
+                               &secspertrack, &surfaces, &reserved,
+                               &cylinders, &size, &blocksize);
+
+    hd_change_mode = 1;
+    if (is_hardfile (currprefs.mountinfo, selected_hd_row)) {
+    } else {
+       create_dirdlg ("Change a mounted directory"); 
+       gtk_entry_set_text (GTK_ENTRY (volname_entry), volname);
+       gtk_entry_set_text (GTK_ENTRY (path_entry), rootdir);
+   }
+}
+static void did_hddel (void)
+{
+    kill_filesys_unit (currprefs.mountinfo, selected_hd_row);
+    set_hd_state ();
+}
+
+static void hdselect (GtkWidget *widget, gint row, gint column, GdkEventButton *bevent,
+                     gpointer user_data)
+{
+    selected_hd_row = row;
+    gtk_widget_set_sensitive (hdchange_button, TRUE);
+    gtk_widget_set_sensitive (hddel_button, TRUE);
+}
+
+static void hdunselect (GtkWidget *widget, gint row, gint column, GdkEventButton *bevent,
+                       gpointer user_data)
+{
+    gtk_widget_set_sensitive (hdchange_button, FALSE);
+    gtk_widget_set_sensitive (hddel_button, FALSE);
+}
+
+
+static GtkWidget *make_buttons (const char *label, GtkWidget *box, void (*sigfunc) (void), GtkWidget *(*create)(const char *label))
+{
+    GtkWidget *thing = create (label);
+    gtk_widget_show (thing);
+    gtk_signal_connect (GTK_OBJECT (thing), "clicked", (GtkSignalFunc) sigfunc, NULL);
+    gtk_box_pack_start (GTK_BOX (box), thing, TRUE, TRUE, 0);
+
+    return thing;
+}
+#define make_button(label, box, sigfunc) make_buttons(label, box, sigfunc, gtk_button_new_with_label)
+
+static void make_hd_widgets (GtkWidget *dvbox)
+{
+    GtkWidget *thing, *buttonbox, *hbox;
+    char *titles [] = {
+       "Volume", "File/Directory", "R/O", "Heads", "Cyl.", "Sec.", "Rsrvd", "Size", "Blksize"
+    };
+
+    thing = gtk_clist_new_with_titles (9, titles);
+    gtk_clist_set_selection_mode (GTK_CLIST (thing), GTK_SELECTION_SINGLE);
+    gtk_signal_connect (GTK_OBJECT (thing), "select_row", (GtkSignalFunc) hdselect, NULL);
+    gtk_signal_connect (GTK_OBJECT (thing), "unselect_row", (GtkSignalFunc) hdunselect, NULL);
+    hdlist_widget = thing;
+    gtk_widget_set_usize (thing, -1, 200);
+
+    gtk_widget_show (thing);
+    add_centered_to_vbox (dvbox, thing);
+
+    hbox = gtk_hbox_new (FALSE, 10);
+    gtk_widget_show (hbox);
+    gtk_box_pack_start (GTK_BOX (dvbox), hbox, FALSE, TRUE, 0);
+
+    /* The buttons */
+    buttonbox = gtk_hbox_new (TRUE, 4);
+    gtk_widget_show (buttonbox);
+    gtk_box_pack_start (GTK_BOX (hbox), buttonbox, TRUE, TRUE, 0);
+    make_button ("New filesystem...", buttonbox, did_newdir);
+#if 0 /* later... */
+    make_button ("New hardfile...", buttonbox, did_newhdf);
+#endif
+    hdchange_button = make_button ("Change...", buttonbox, did_hdchange);
+    hddel_button = make_button ("Delete", buttonbox, did_hddel);
+
+    thing = gtk_label_new ("These settings take effect after the next reset.");
+    gtk_widget_show (thing);
+    add_centered_to_vbox (dvbox, thing);
+}
+
+static void make_about_widgets (GtkWidget *dvbox)
+{
+    GtkWidget *thing;
+    GtkStyle *style;
+    GdkFont *font;
+    char t[20];
+
+    add_empty_vbox (dvbox);
+
+    sprintf (t, "UAE %d.%d.%d", UAEMAJOR, UAEMINOR, UAESUBREV);
+    thing = gtk_label_new (t);
+    gtk_widget_show (thing);
+    add_centered_to_vbox (dvbox, thing);
+
+    font = gdk_font_load ("-*-helvetica-medium-r-normal--*-240-*-*-*-*-*-*");
+    if (font) {
+       style = gtk_style_copy (GTK_WIDGET (thing)->style);
+       gdk_font_unref (style->font);
+       style->font = font;
+       gdk_font_ref (style->font);
+       gtk_widget_push_style (style);
+       gtk_widget_set_style (thing, style);
+    }
+    thing = gtk_label_new ("Choose your settings, then deselect the Pause button to start!");
+    gtk_widget_show (thing);
+    add_centered_to_vbox (dvbox, thing);
+
+    add_empty_vbox (dvbox);
+}
+
+
+static void create_guidlg (void)
+{
+    GtkWidget *window, *notebook;
+    GtkWidget *buttonbox, *vbox, *hbox;
+    GtkWidget *thing;
+    int i;
+    int argc = 1;
+    char *a[] = {"UAE"};
+    char **argv = a;
+    static const struct _pages {
+       const char *title;
+       void (*createfunc)(GtkWidget *);
+    } pages[] = {
+       /* ??? If this isn't the first page, there are errors in draw_led.  */
+       { "Floppy disks", make_floppy_disks },
+       { "Memory", make_mem_widgets },
+       { "CPU emulation", make_cpu_widgets },
+       { "Graphics", make_gfx_widgets },
+       { "Chipset", make_chipset_widgets },
+       { "Sound", make_sound_widgets },
+       { "JIT", make_comp_widgets },
+       { "Game ports", make_joy_widgets },
+       { "Harddisks", make_hd_widgets },
+       { "About", make_about_widgets }
+    };
+
+    gtk_init (&argc, &argv);
+    gtk_rc_parse ("uaegtkrc");
+
+    gui_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+    gtk_window_set_title (GTK_WINDOW (gui_window), "UAE control");
+
+    vbox = gtk_vbox_new (FALSE, 4);
+    gtk_container_add (GTK_CONTAINER (gui_window), vbox);
+    gtk_container_set_border_width (GTK_CONTAINER (gui_window), 10);
+
+    /* First line - buttons and power LED */
+    hbox = gtk_hbox_new (FALSE, 10);
+    gtk_widget_show (hbox);
+    gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
+
+    /* The buttons */
+    buttonbox = gtk_hbox_new (TRUE, 4);
+    gtk_widget_show (buttonbox);
+    gtk_box_pack_start (GTK_BOX (hbox), buttonbox, TRUE, TRUE, 0);
+    make_button ("Reset", buttonbox, did_reset);
+    make_button ("Debug", buttonbox, did_debug);
+    make_button ("Quit", buttonbox, did_quit);
+    make_button ("Save config", buttonbox, save_config);
+    pause_uae_widget = make_buttons ("Pause", buttonbox, pause_uae, gtk_toggle_button_new_with_label);
+
+    /* The LED */
+    thing = make_led (0);
+    thing = make_labelled_widget ("Power:", thing);
+    gtk_widget_show (thing);
+    gtk_box_pack_start (GTK_BOX (hbox), thing, FALSE, TRUE, 0);
+
+    /* More buttons */
+    buttonbox = gtk_hbox_new (TRUE, 4);
+    gtk_widget_show (buttonbox);
+    gtk_box_pack_start (GTK_BOX (vbox), buttonbox, TRUE, TRUE, 0);
+    snap_save_widget = make_button ("Save state", buttonbox, did_savestate);
+    snap_load_widget = make_button ("Load state", buttonbox, did_loadstate);
+
+    /* Place a separator below those buttons.  */
+    thing = gtk_hseparator_new ();
+    gtk_box_pack_start (GTK_BOX (vbox), thing, FALSE, TRUE, 0);
+    gtk_widget_show (thing);
+
+    /* Now the notebook */
+    notebook = gtk_notebook_new ();
+    gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0);
+    gtk_widget_show (notebook);
+
+    for (i = 0; i < sizeof pages / sizeof (struct _pages); i++) {
+       thing = gtk_vbox_new (FALSE, 4);
+       gtk_widget_show (thing);
+       gtk_container_set_border_width (GTK_CONTAINER (thing), 10);
+       pages[i].createfunc (thing);
+       gtk_notebook_append_page (GTK_NOTEBOOK (notebook), thing, gtk_label_new (pages[i].title));
+    }
+
+    /* Put "about" screen first.  */
+    gtk_notebook_set_page (GTK_NOTEBOOK (notebook), i - 1);
+    enable_disk_buttons (1);
+    enable_snap_buttons (1);
+
+    gtk_widget_show (vbox);
+
+    filesel_active = -1;
+    snapsel_active = -1;
+
+    gtk_timeout_add (1000, (GtkFunction)my_idle, 0);
+}
+
+static void *gtk_gui_thread (void *dummy)
+{
+    gtk_main ();
+
+    quitted_gui = 1;
+    uae_sem_post (&gui_quit_sem);
+    return 0;
+}
+
+void gui_changesettings(void)
+{
+    
+}
+
+void gui_fps (int x)
+{
+}
+
+void gui_led (int num, int on)
+{
+    if (no_gui)
+       return;
+
+/*    if (num == 0)
+       return;
+    printf("LED %d %d\n", num, on);
+    write_comm_pipe_int (&to_gui_pipe, 1, 0);
+    write_comm_pipe_int (&to_gui_pipe, num == 0 ? 4 : num - 1, 0);
+    write_comm_pipe_int (&to_gui_pipe, on, 1);
+    printf("#LED %d %d\n", num, on);*/
+}
+
+void gui_filename (int num, const char *name)
+{
+    if (no_gui)
+       return;
+
+    write_comm_pipe_int (&to_gui_pipe, 0, 0);
+    write_comm_pipe_int (&to_gui_pipe, num, 1);
+
+/*    gui_update ();*/
+}
+
+void gui_handle_events (void)
+{
+    int pause_uae = FALSE;
+    
+    if (no_gui)
+       return;
+
+    do {
+        while (pause_uae || comm_pipe_has_data (&from_gui_pipe)) {
+            int cmd = read_comm_pipe_int_blocking (&from_gui_pipe);
+            int n;
+            switch (cmd) {
+           case 0:
+               n = read_comm_pipe_int_blocking (&from_gui_pipe);
+               changed_prefs.df[n][0] = '\0';
+               break;
+           case 1:
+               n = read_comm_pipe_int_blocking (&from_gui_pipe);
+               uae_sem_wait (&gui_sem);
+               strncpy (changed_prefs.df[n], new_disk_string[n], 255);
+               free (new_disk_string[n]);
+               new_disk_string[n] = 0;
+               changed_prefs.df[n][255] = '\0';
+               uae_sem_post (&gui_sem);
+               break;
+           case 2:
+               uae_reset ();
+               end_pause_uae ();
+               break;
+           case 3:
+               activate_debugger ();
+               end_pause_uae ();
+               break;
+           case 4:
+               uae_quit ();
+               end_pause_uae ();
+               break;
+           case 5:
+               pause_uae = TRUE;
+               break;
+           case 6:
+               pause_uae = FALSE;
+               break;
+           case 7:
+               printf ("STATESAVE\n");
+               savestate_state = read_comm_pipe_int_blocking (&from_gui_pipe);
+               uae_sem_wait (&gui_sem);
+               savestate_filename = gui_snapname;
+               uae_sem_post (&gui_sem);
+               break;
+           case 8:
+               uae_sem_wait (&gui_sem);
+               strncpy (changed_prefs.romfile, gui_romname, 255);
+               changed_prefs.romfile[255] = '\0';
+               free (gui_romname);
+               uae_sem_post (&gui_sem);
+               break;
+           case 9:
+               uae_sem_wait (&gui_sem);
+               strncpy (changed_prefs.keyfile, gui_keyname, 255);
+               changed_prefs.keyfile[255] = '\0';
+               free (gui_keyname);
+               uae_sem_post (&gui_sem);
+               break;
+            }
+        }
+    } while (pause_uae);
+}
+
+void gui_update_gfx (void)
+{
+#if 0 /* This doesn't work... */
+    set_gfx_state ();
+#endif
+}
+
+int gui_init (void)
+{
+    uae_thread_id tid;
+
+    gui_active = 0;
+    
+    init_comm_pipe (&to_gui_pipe, 20, 1);
+    init_comm_pipe (&from_gui_pipe, 20, 1);
+    uae_sem_init (&gui_sem, 0, 1);
+    uae_sem_init (&gui_init_sem, 0, 0);
+    uae_sem_init (&gui_quit_sem, 0, 0);
+
+    create_guidlg ();
+    uae_start_thread (gtk_gui_thread, NULL, &tid);
+    gui_update ();
+
+    if (currprefs.start_gui == 1) {
+       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pause_uae_widget), TRUE);
+       write_comm_pipe_int (&from_gui_pipe, 5, 1);
+       /* Handle events until Pause is unchecked.  */
+       gui_handle_events ();
+       /* Quit requested?  */
+       if (quit_program == -1) {
+           gui_exit ();
+           return -2;
+       }
+    }
+
+    return 1;
+}
+
+int gui_update (void)
+{
+    if (no_gui)
+       return 0;
+
+    write_comm_pipe_int (&to_gui_pipe, 1, 1);
+    uae_sem_wait (&gui_init_sem);
+    return 0;
+}
+
+void gui_exit (void)
+{
+    if (no_gui)
+       return;
+
+    quit_gui = 1;
+    uae_sem_wait (&gui_quit_sem);
+}
+
+void gui_lock (void)
+{
+    uae_sem_wait (&gui_sem);
+}
+
+void gui_unlock (void)
+{
+    uae_sem_post (&gui_sem);
+}
diff --git a/hardfile.c b/hardfile.c
new file mode 100755 (executable)
index 0000000..c5ec6ad
--- /dev/null
@@ -0,0 +1,825 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Hardfile emulation
+  *
+  * Copyright 1995 Bernd Schmidt
+  *           2002 Toni Wilen (scsi emulation, 64-bit support)
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "threaddep/thread.h"
+#include "options.h"
+#include "memory.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "disk.h"
+#include "autoconf.h"
+#include "filesys.h"
+#include "execlib.h"
+#include "native2amiga.h"
+#include "gui.h"
+#include "uae.h"
+
+#define CMD_INVALID    0
+#define CMD_RESET      1
+#define CMD_READ       2
+#define CMD_WRITE      3
+#define CMD_UPDATE     4
+#define CMD_CLEAR      5
+#define CMD_STOP       6
+#define CMD_START      7
+#define CMD_FLUSH      8
+#define CMD_MOTOR      9
+#define CMD_SEEK       10
+#define CMD_FORMAT     11
+#define CMD_REMOVE     12
+#define CMD_CHANGENUM  13
+#define CMD_CHANGESTATE        14
+#define CMD_PROTSTATUS 15
+#define CMD_GETDRIVETYPE 18
+#define CMD_GETNUMTRACKS 19
+#define CMD_ADDCHANGEINT 20
+#define CMD_REMCHANGEINT 21
+#define CMD_GETGEOMETRY        22
+#define HD_SCSICMD 28
+
+/* Trackdisk64 support */
+#define TD_READ64 24
+#define TD_WRITE64 25
+#define TD_SEEK64 26
+#define TD_FORMAT64 27
+
+/* New Style Devices (NSD) support */
+#define DRIVE_NEWSTYLE 0x4E535459L   /* 'NSTY' */
+#define NSCMD_DEVICEQUERY 0x4000
+#define NSCMD_TD_READ64 0xc000
+#define NSCMD_TD_WRITE64 0xc001
+#define NSCMD_TD_SEEK64 0xc002
+#define NSCMD_TD_FORMAT64 0xc003
+
+#undef DEBUGME
+//#define DEBUGME
+#ifdef DEBUGME
+#define hf_log write_log
+#define hf_log2 write_log
+#define scsi_log write_log
+#else
+#define hf_log
+#define hf_log2
+#define scsi_log
+#endif
+
+#define MAX_ASYNC_REQUESTS 50
+#define ASYNC_REQUEST_NONE 0
+#define ASYNC_REQUEST_TEMP 1
+#define ASYNC_REQUEST_CHANGEINT 10
+
+static struct hardfileprivdata {
+    volatile uaecptr d_request[MAX_ASYNC_REQUESTS];
+    volatile int d_request_type[MAX_ASYNC_REQUESTS];
+    volatile uae_u32 d_request_data[MAX_ASYNC_REQUESTS];
+    smp_comm_pipe requests;
+    uae_thread_id tid;
+    int thread_running;
+    uae_sem_t sync_sem;
+    int opencount;
+};
+
+static uae_sem_t change_sem;
+
+static struct hardfileprivdata hardfpd[MAX_FILESYSTEM_UNITS];
+
+static uae_u32 nscmd_cmd;
+
+static void wl (uae_u8 *p, int v)
+{
+    p[0] = v >> 24;
+    p[1] = v >> 16;
+    p[2] = v >> 8;
+    p[3] = v;
+}
+static int rl (uae_u8 *p)
+{
+    return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
+}
+
+static uae_u64 cmd_read (struct hardfiledata *hfd, uaecptr dataptr, uae_u64 offset, uae_u64 len)
+{
+    uae_u64 got = 0;
+    uae_u8 buffer[FILESYS_MAX_BLOCKSIZE];
+
+    gui_hd_led (1);
+    hf_log2 ("cmd_read: %p %04.4x-%08.8x %08.8x\n", dataptr, (uae_u32)(offset >> 32), (uae_u32)offset, (uae_u32)len);
+    while (len > 0) {
+        int i, got2;
+       got2 = hdf_read (hfd, buffer, offset, hfd->blocksize);
+        if (got2 != hfd->blocksize)
+           break;
+       for (i = 0; i < got2; i++)
+           put_byte(dataptr + i, buffer[i]);
+        len -= got2;
+        got += got2;
+        dataptr += got2;
+       offset += got2;
+    }
+    return got;
+}
+
+static uae_u64 cmd_write (struct hardfiledata *hfd, uaecptr dataptr, uae_u64 offset, uae_u64 len)
+{
+    uae_u64 got = 0;
+    uae_u8 buffer[FILESYS_MAX_BLOCKSIZE];
+
+    gui_hd_led (1);
+    hf_log2 ("cmd_write: %p %04.4x-%08.8x %08.8x\n", dataptr, (uae_u32)(offset >> 32), (uae_u32)offset, (uae_u32)len);
+    while (len > 0) {
+        int i, got2;
+        for (i = 0; i < hfd->blocksize; i++)
+           buffer[i] = get_byte (dataptr + i);
+       got2 = hdf_write (hfd, buffer, offset, hfd->blocksize);
+       if (got2 != hfd->blocksize)
+           break;
+       len -= got2;
+       got += got2;
+       dataptr += got2;
+       offset += got2;
+    }
+    return got;
+}
+
+static int handle_scsi (uaecptr request, struct hardfiledata *hfd)
+{
+    uae_u32 acmd = get_long (request + 40);
+    uaecptr scsi_data = get_long (acmd + 0);
+    uae_u32 scsi_len = get_long (acmd + 4);
+    uaecptr scsi_cmd = get_long (acmd + 12);
+    uae_u16 scsi_cmd_len = get_word (acmd + 16);
+    uae_u8 scsi_flags = get_byte (acmd + 20);
+    uaecptr scsi_sense = get_long (acmd + 22);
+    uae_u16 scsi_sense_len = get_word (acmd + 26);
+    uae_u8 cmd = get_byte (scsi_cmd);
+    uae_u8 cmdbuf[256];
+    int status, ret = 0, lr, ls;
+    uae_u32 i;
+    uae_u8 r[256], s[256];
+    uae_u64 len, offset;
+
+    scsi_sense_len  = (scsi_flags & 4) ? 4 : /* SCSIF_OLDAUTOSENSE */
+        (scsi_flags & 2) ? scsi_sense_len : /* SCSIF_AUTOSENSE */
+        32;
+    status = 0;
+    memset (r, 0, sizeof (r));
+    lr = 0; ls = 0;
+    scsi_log ("hdf scsiemu: cmd=%02.2X,%d flags=%02.2X sense=%p,%d data=%p,%d\n",
+       cmd, scsi_cmd_len, scsi_flags, scsi_sense, scsi_sense_len, scsi_data, scsi_len);
+    for (i = 0; i < scsi_cmd_len; i++) {
+       cmdbuf[i] = get_byte (scsi_cmd + i);
+       scsi_log ("%02.2X%c", get_byte (scsi_cmd + i), i < scsi_cmd_len - 1 ? '.' : ' ');
+    }
+    scsi_log ("\n");
+
+    switch (cmd)
+    {
+       case 0x00: /* TEST UNIT READY */
+       break;
+       case 0x08: /* READ (6) */
+       offset = ((cmdbuf[1] & 31) << 16) | (cmdbuf[2] << 8) | cmdbuf[3];
+       offset *= hfd->blocksize;
+       len = cmdbuf[4];
+       if (!len) len = 256;
+       len *= hfd->blocksize;
+       scsi_len = (uae_u32)cmd_read (hfd, scsi_data, offset, len);
+        break;
+       case 0x0a: /* WRITE (6) */
+       offset = ((cmdbuf[1] & 31) << 16) | (cmdbuf[2] << 8) | cmdbuf[3];
+       offset *= hfd->blocksize;
+       len = cmdbuf[4];
+       if (!len) len = 256;
+       len *= hfd->blocksize;
+       scsi_len = (uae_u32)cmd_write (hfd, scsi_data, offset, len);
+        break;
+       case 0x12: /* INQUIRY */
+       len = cmdbuf[4];
+       r[2] = 2; /* supports SCSI-2 */
+       r[3] = 2; /* response data format */
+       r[4] = 32; /* additional length */
+       r[7] = 0x20; /* 16 bit bus */
+       i = 0; /* vendor id */
+       while (i < 8 && hfd->vendor_id[i]) {
+           r[8 + i] = hfd->vendor_id[i];
+           i++;
+       }
+       while (i < 8) {
+           r[8 + i] = 32;
+           i++;
+       }
+       i = 0; /* product id */
+       while (i < 16 && hfd->product_id[i]) {
+           r[16 + i] = hfd->product_id[i];
+           i++;
+       }
+       while (i < 16) {
+           r[16 + i] = 32;
+           i++;
+       }
+       i = 0; /* product revision */
+       while (i < 4 && hfd->product_rev[i]) {
+           r[32 + i] = hfd->product_rev[i];
+           i++;
+       }
+       while (i < 4) {
+           r[32 + i] = 32;
+           i++;
+       }
+       scsi_len = lr = len < 36 ? (uae_u32)len : 36;
+       break;
+       case 0x25: /* READ_CAPACITY */
+       wl (r, (uae_u32)(hfd->size / hfd->blocksize - 1));
+       wl (r + 4, hfd->blocksize);
+       scsi_len = lr = 8;
+       break;
+       case 0x28: /* READ (10) */
+       offset = rl (cmdbuf + 2);
+       offset *= hfd->blocksize;
+        len = rl (cmdbuf + 7 - 2) & 0xffff;
+       len *= hfd->blocksize;
+       scsi_len = (uae_u32)cmd_read (hfd, scsi_data, offset, len);
+       break;
+       case 0x2a: /* WRITE (10) */
+       offset = rl (cmdbuf + 2);
+       offset *= hfd->blocksize;
+        len = rl (cmdbuf + 7 - 2) & 0xffff;
+       len *= hfd->blocksize;
+       scsi_len = (uae_u32)cmd_write (hfd, scsi_data, offset, len);
+        break;
+       case 0xa8: /* READ (12) */
+       offset = rl (cmdbuf + 2);
+       offset *= hfd->blocksize;
+        len = rl (cmdbuf + 6);
+       len *= hfd->blocksize;
+       scsi_len = (uae_u32)cmd_read (hfd, scsi_data, offset, len);
+       break;
+       case 0xaa: /* WRITE (12) */
+       offset = rl (cmdbuf + 2);
+       offset *= hfd->blocksize;
+        len = rl (cmdbuf + 6);
+       len *= hfd->blocksize;
+       scsi_len = (uae_u32)cmd_write (hfd, scsi_data, offset, len);
+        break;
+       default:
+       lr = -1;
+       write_log ("unsupported scsi command 0x%02.2X\n", cmd);
+       status = 2; /* CHECK CONDITION */
+       s[0] = 0x70;
+       s[2] = 5; /* ILLEGAL REQUEST */
+       s[12] = 0x24; /* ILLEGAL FIELD IN CDB */
+       ls = 12;
+       break;
+    }
+    put_word (acmd + 18, status != 0 ? 0 : scsi_cmd_len); /* fake scsi_CmdActual */
+    put_byte (acmd + 21, status); /* scsi_Status */
+    if (lr > 0) {
+       scsi_log ("RD:");
+       i = 0;
+       while (i < lr && i < scsi_len) {
+           if (i < 24)
+               scsi_log ("%02.2X%c", r[i], i < scsi_len - 1 ? '.' : ' ');
+           put_byte (scsi_data + i, r[i]);
+           i++;
+       }
+       scsi_log ("\n");
+    }
+    i = 0;
+    if (ls > 0 && scsi_sense) {
+       while (i < ls && i < scsi_sense_len) {
+           put_byte (scsi_sense + i, s[i]);
+           i++;
+       }
+    }
+    while (i < scsi_sense_len && scsi_sense) {
+       put_byte (scsi_sense + i, 0);
+       i++;
+    }
+    if (lr < 0) {
+       put_long (acmd + 8, 0); /* scsi_Actual */
+       ret = 20;
+    } else {
+       put_long (acmd + 8, scsi_len); /* scsi_Actual */
+    }
+    return ret;
+}
+
+static int add_async_request (struct hardfileprivdata *hfpd, uaecptr request, int type, uae_u32 data)
+{
+    int i;
+
+    i = 0;
+    while (i < MAX_ASYNC_REQUESTS) {
+       if (hfpd->d_request[i] == request) {
+           hfpd->d_request_type[i] = type;
+           hfpd->d_request_data[i] = data;
+           hf_log ("old async request %p (%d) added\n", request, type);
+           return 0;
+       }
+       i++;
+    }
+    i = 0;
+    while (i < MAX_ASYNC_REQUESTS) {
+       if (hfpd->d_request[i] == 0) {
+           hfpd->d_request[i] = request;
+           hfpd->d_request_type[i] = type;
+           hfpd->d_request_data[i] = data;
+           hf_log ("async request %p (%d) added (total=%d)\n", request, type, i);
+           return 0;
+       }
+       i++;
+    }
+    hf_log ("async request overflow %p!\n", request);
+    return -1;
+}
+
+static int release_async_request (struct hardfileprivdata *hfpd, uaecptr request)
+{
+    int i = 0;
+
+    while (i < MAX_ASYNC_REQUESTS) {
+       if (hfpd->d_request[i] == request) {
+           int type = hfpd->d_request_type[i];
+           hfpd->d_request[i] = 0;
+           hfpd->d_request_data[i] = 0;
+           hfpd->d_request_type[i] = 0;
+           hf_log ("async request %p removed\n", request);
+           return type;
+       }
+       i++;
+    }
+    hf_log ("tried to remove non-existing request %p\n", request);
+    return -1;
+}
+
+static void abort_async (struct hardfileprivdata *hfpd, uaecptr request, int errcode, int type)
+{
+    int i;
+    hf_log ("aborting async request %p\n", request);
+    i = 0;
+    while (i < MAX_ASYNC_REQUESTS) {
+       if (hfpd->d_request[i] == request && hfpd->d_request_type[i] == ASYNC_REQUEST_TEMP) {
+           /* ASYNC_REQUEST_TEMP = request is processing */
+           sleep_millis (1);
+           i = 0;
+           continue;
+       }
+       i++;
+    }
+    i = release_async_request (hfpd, request);
+    if (i >= 0)
+       hf_log ("asyncronous request=%08.8X aborted, error=%d\n", request, errcode);
+}
+
+static void *hardfile_thread (void *devs);
+static int start_thread (int unit)
+{
+    struct hardfileprivdata *hfpd = &hardfpd[unit];
+
+    if (hfpd->thread_running)
+        return 1;
+    memset (hfpd, 0, sizeof (struct hardfileprivdata));
+    init_comm_pipe (&hfpd->requests, 100, 1);
+    uae_sem_init (&hfpd->sync_sem, 0, 0);
+    uae_start_thread (hardfile_thread, hfpd, &hfpd->tid);
+    uae_sem_wait (&hfpd->sync_sem);
+    return hfpd->thread_running;
+}
+
+static int mangleunit (int unit)
+{
+    if (unit <= 99)
+       return unit;
+    if (unit == 100)
+       return 8;
+    if (unit == 110)
+       return 9;
+    return -1;
+}
+
+static uae_u32 hardfile_open (void)
+{
+    uaecptr tmp1 = m68k_areg(regs, 1); /* IOReq */
+    int unit = mangleunit (m68k_dreg (regs, 0));
+    struct hardfileprivdata *hfpd = &hardfpd[unit];
+
+    hf_log ("hardfile_open, unit %d (%d)\n", unit, m68k_dreg (regs, 0));
+    /* Check unit number */
+    if (unit >= 0 && get_hardfile_data (unit) && start_thread (unit)) {
+       hfpd->opencount++;
+       put_word (m68k_areg(regs, 6) + 32, get_word (m68k_areg(regs, 6) + 32) + 1);
+       put_long (tmp1 + 24, unit); /* io_Unit */
+       put_byte (tmp1 + 31, 0); /* io_Error */
+       put_byte (tmp1 + 8, 7); /* ln_type = NT_REPLYMSG */
+       return 0;
+    }
+
+    put_long (tmp1 + 20, (uae_u32)-1);
+    put_byte (tmp1 + 31, (uae_u8)-1);
+    return (uae_u32)-1;
+}
+
+static uae_u32 hardfile_close (void)
+{
+    uaecptr request = m68k_areg(regs, 1); /* IOReq */
+    int unit = mangleunit (get_long (request + 24));
+    struct hardfileprivdata *hfpd = &hardfpd[unit];
+
+    if (!hfpd->opencount) return 0;
+    hfpd->opencount--;
+    if (hfpd->opencount == 0)
+       write_comm_pipe_u32 (&hfpd->requests, 0, 1);
+    put_word (m68k_areg(regs, 6) + 32, get_word (m68k_areg(regs, 6) + 32) - 1);
+    return 0;
+}
+
+static uae_u32 hardfile_expunge (void)
+{
+    return 0; /* Simply ignore this one... */
+}
+
+static uae_u32 hardfile_do_io (struct hardfiledata *hfd, struct hardfileprivdata *hfpd, uaecptr request)
+{
+    uae_u32 dataptr, offset, actual = 0, cmd;
+    uae_u64 offset64;
+    int unit = get_long (request + 24);
+    uae_u32 error = 0, len;
+    int async = 0;
+    int bmask = hfd->blocksize - 1;
+
+    cmd = get_word (request + 28); /* io_Command */
+    dataptr = get_long (request + 40);
+    switch (cmd)
+    {
+       case CMD_READ:
+       if (dataptr & 1)
+           goto bad_command;
+       offset = get_long (request + 44);
+       if (offset & bmask)
+           goto bad_command;
+       len = get_long (request + 36); /* io_Length */
+       if (len & bmask)
+           goto bad_command;
+       if (len + offset > hfd->size)
+           goto bad_command;
+       actual = (uae_u32)cmd_read (hfd, dataptr, offset, len);
+       break;
+
+       case TD_READ64:
+       case NSCMD_TD_READ64:
+       if (dataptr & 1)
+           goto bad_command;
+       offset64 = get_long (request + 44) | ((uae_u64)get_long (request + 32) << 32);
+       if (offset64 & bmask)
+           goto bad_command;
+       len = get_long (request + 36); /* io_Length */
+       if (len & bmask)
+           goto bad_command;
+       if (len + offset64 > hfd->size)
+           goto bad_command;
+       actual = (uae_u32)cmd_read (hfd, dataptr, offset64, len);
+       break;
+
+       case CMD_WRITE:
+       case CMD_FORMAT: /* Format */
+       if (hfd->readonly) {
+           error = 28; /* write protect */
+       } else {
+           if (dataptr & 1)
+               goto bad_command;
+           offset = get_long (request + 44);
+           if (offset & bmask)
+               goto bad_command;
+           len = get_long (request + 36); /* io_Length */
+           if (len & bmask)
+               goto bad_command;
+           if (len + offset > hfd->size)
+               goto bad_command;
+           actual = (uae_u32)cmd_write (hfd, dataptr, offset, len);
+       }
+       break;
+
+       case TD_WRITE64:
+       case TD_FORMAT64:
+       case NSCMD_TD_WRITE64:
+       case NSCMD_TD_FORMAT64:
+       if (hfd->readonly) {
+           error = 28; /* write protect */
+       } else {
+           if (dataptr & 1)
+               goto bad_command;
+           offset64 = get_long (request + 44) | ((uae_u64)get_long (request + 32) << 32);
+           if (offset64 & bmask)
+               goto bad_command;
+           len = get_long (request + 36); /* io_Length */
+           if (len & bmask)
+               goto bad_command;
+           if (len + offset64 > hfd->size)
+               goto bad_command;
+           put_long (request + 32, (uae_u32)cmd_write (hfd, dataptr, offset64, len));
+       }
+       break;
+
+       bad_command:
+       break;
+
+       case NSCMD_DEVICEQUERY:
+           put_long (dataptr + 4, 16); /* size */
+           put_word (dataptr + 8, 5); /* NSDEVTYPE_TRACKDISK */
+           put_word (dataptr + 10, 0);
+           put_long (dataptr + 12, nscmd_cmd);
+           actual = 16;
+       break;
+
+       case CMD_GETDRIVETYPE:
+           actual = DRIVE_NEWSTYLE;
+           break;
+
+       case CMD_GETNUMTRACKS:
+           hf_log ("CMD_GETNUMTRACKS - shouldn't happen\n");
+           actual = 0;
+           break;
+
+       case CMD_PROTSTATUS:
+           if (hfd->readonly)
+               actual = -1;
+           else
+               actual = 0;
+       break;
+
+       case CMD_CHANGESTATE:
+       actual = 0;
+       break;
+
+       /* Some commands that just do nothing and return zero */
+       case CMD_UPDATE:
+       case CMD_CLEAR:
+       case CMD_MOTOR:
+       case CMD_SEEK:
+       case CMD_CHANGENUM:
+       case TD_SEEK64:
+       case NSCMD_TD_SEEK64:
+       break;
+
+       case CMD_REMOVE:
+       break;
+
+       case CMD_ADDCHANGEINT:
+       error = add_async_request (hfpd, request, ASYNC_REQUEST_CHANGEINT, get_long (request + 40));
+       if (!error)
+           async = 1;
+       break;
+       case CMD_REMCHANGEINT:
+       release_async_request (hfpd, request);
+       break;
+       case HD_SCSICMD: /* SCSI */
+           if (hfd->nrcyls == 0)
+               error = handle_scsi (request, hfd);
+           else /* we don't want users trashing their "partition" hardfiles with hdtoolbox */
+               error = -3; /* io_Error */
+       break;
+
+       default:
+           /* Command not understood. */
+           error = -3; /* io_Error */
+       break;
+    }
+    put_long (request + 32, actual);
+    put_byte (request + 31, error);
+
+    hf_log2 ("hf: unit=%d, request=%p, cmd=%d offset=%u len=%d, actual=%d error%=%d\n", unit, request,
+       get_word(request + 28), get_long (request + 44), get_long (request + 36), actual, error);
+    return async;
+}
+
+static uae_u32 hardfile_abortio (void)
+{
+    uae_u32 request = m68k_areg(regs, 1);
+    int unit = mangleunit (get_long (request + 24));
+    struct hardfiledata *hfd = get_hardfile_data (unit);
+    struct hardfileprivdata *hfpd = &hardfpd[unit];
+
+    hf_log2 ("uaehf.device abortio ");
+    if (!hfd) {
+       put_byte (request + 31, 32);
+       hf_log2 ("error\n");
+       return get_byte (request + 31);
+    }
+    put_byte (request + 31, -2);
+    hf_log2 ("unit=%d, request=%08.8X\n",  unit, request);
+    abort_async (hfpd, request, -2, 0);
+    return 0;
+}
+
+static int hardfile_can_quick (uae_u32 command)
+{
+    switch (command)
+    {
+       case CMD_RESET:
+       case CMD_STOP:
+       case CMD_START:
+       case CMD_CHANGESTATE:
+       case CMD_PROTSTATUS:
+       case CMD_MOTOR:
+       case CMD_GETDRIVETYPE:
+       case CMD_GETNUMTRACKS:
+       case NSCMD_DEVICEQUERY:
+       return 1;
+    }
+    return 0;
+}
+
+static int hardfile_canquick (struct hardfiledata *hfd, uaecptr request)
+{
+    uae_u32 command = get_word (request + 28);
+    return hardfile_can_quick (command);
+}
+
+static uae_u32 hardfile_beginio (void)
+{
+    uae_u32 request = m68k_areg(regs, 1);
+    uae_u8 flags = get_byte (request + 30);
+    int cmd = get_word (request + 28);
+    int unit = mangleunit (get_long (request + 24));
+    struct hardfiledata *hfd = get_hardfile_data (unit);
+    struct hardfileprivdata *hfpd = &hardfpd[unit];
+
+    put_byte (request + 8, NT_MESSAGE);
+    if (!hfd) {
+       put_byte (request + 31, 32);
+       return get_byte (request + 31);
+    }
+    put_byte (request + 31, 0);
+    if ((flags & 1) && hardfile_canquick (hfd, request)) {
+        hf_log ("hf quickio unit=%d request=%p cmd=%d\n", unit, request, cmd);
+       if (hardfile_do_io (hfd, hfpd, request))
+           hf_log2 ("uaehf.device cmd %d bug with IO_QUICK\n", cmd);
+       return get_byte (request + 31);
+    } else {
+        hf_log2 ("hf asyncio unit=%d request=%p cmd=%d\n", unit, request, cmd);
+        add_async_request (hfpd, request, ASYNC_REQUEST_TEMP, 0);
+        put_byte (request + 30, get_byte (request + 30) & ~1);
+       write_comm_pipe_u32 (&hfpd->requests, request, 1);
+       return 0;
+    }
+}
+
+static void *hardfile_thread (void *devs)
+{
+    struct hardfileprivdata *hfpd = devs;
+
+    set_thread_priority (2);
+    hfpd->thread_running = 1;
+    uae_sem_post (&hfpd->sync_sem);
+    for (;;) {
+       uaecptr request = (uaecptr)read_comm_pipe_u32_blocking (&hfpd->requests);
+       uae_sem_wait (&change_sem);
+        if (!request) {
+           hfpd->thread_running = 0;
+           uae_sem_post (&hfpd->sync_sem);
+           uae_sem_post (&change_sem);
+           return 0;
+       } else if (hardfile_do_io (get_hardfile_data (hfpd - &hardfpd[0]), hfpd, request) == 0) {
+            put_byte (request + 30, get_byte (request + 30) & ~1);
+           release_async_request (hfpd, request);
+            uae_ReplyMsg (request);
+       } else {
+           hf_log2 ("async request %08.8X\n", request);
+       }
+       uae_sem_post (&change_sem);
+    }
+}
+
+void hardfile_reset (void)
+{
+    int i, j;
+    struct hardfileprivdata *hfpd;
+
+    for (i = 0; i < MAX_FILESYSTEM_UNITS; i++) {
+        hfpd = &hardfpd[i];
+       if (hfpd->opencount > 0) {
+           for (j = 0; j < MAX_ASYNC_REQUESTS; j++) {
+               uaecptr request;
+               if (request = hfpd->d_request[i]) 
+                   abort_async (hfpd, request, 0, 0);
+           }
+       }
+       memset (hfpd, 0, sizeof (struct hardfileprivdata));
+    }
+}
+
+void hardfile_install (void)
+{
+    uae_u32 functable, datatable;
+    uae_u32 initcode, openfunc, closefunc, expungefunc;
+    uae_u32 beginiofunc, abortiofunc;
+
+    uae_sem_init (&change_sem, 0, 1);
+
+    ROM_hardfile_resname = ds ("uaehf.device");
+    ROM_hardfile_resid = ds ("UAE hardfile.device 0.2");
+
+    nscmd_cmd = here ();
+    dw (NSCMD_DEVICEQUERY);
+    dw (CMD_RESET);
+    dw (CMD_READ);
+    dw (CMD_WRITE);
+    dw (CMD_UPDATE);
+    dw (CMD_CLEAR);
+    dw (CMD_START);
+    dw (CMD_STOP);
+    dw (CMD_FLUSH);
+    dw (CMD_MOTOR);
+    dw (CMD_SEEK);
+    dw (CMD_FORMAT);
+    dw (CMD_REMOVE);
+    dw (CMD_CHANGENUM);
+    dw (CMD_CHANGESTATE);
+    dw (CMD_PROTSTATUS);
+    dw (CMD_GETDRIVETYPE);
+    dw (CMD_ADDCHANGEINT);
+    dw (CMD_REMCHANGEINT);
+    dw (HD_SCSICMD);
+    dw (NSCMD_TD_READ64);
+    dw (NSCMD_TD_WRITE64);
+    dw (NSCMD_TD_SEEK64);
+    dw (NSCMD_TD_FORMAT64);
+    dw (0);
+
+    /* initcode */
+#if 0
+    initcode = here ();
+    calltrap (deftrap (hardfile_init)); dw (RTS);
+#else
+    initcode = filesys_initcode;
+#endif
+    /* Open */
+    openfunc = here ();
+    calltrap (deftrap (hardfile_open)); dw (RTS);
+
+    /* Close */
+    closefunc = here ();
+    calltrap (deftrap (hardfile_close)); dw (RTS);
+
+    /* Expunge */
+    expungefunc = here ();
+    calltrap (deftrap (hardfile_expunge)); dw (RTS);
+
+    /* BeginIO */
+    beginiofunc = here ();
+    calltrap (deftrap (hardfile_beginio));
+    dw (RTS);
+
+    /* AbortIO */
+    abortiofunc = here ();
+    calltrap (deftrap (hardfile_abortio)); dw (RTS);
+
+    /* FuncTable */
+    functable = here ();
+    dl (openfunc); /* Open */
+    dl (closefunc); /* Close */
+    dl (expungefunc); /* Expunge */
+    dl (EXPANSION_nullfunc); /* Null */
+    dl (beginiofunc); /* BeginIO */
+    dl (abortiofunc); /* AbortIO */
+    dl (0xFFFFFFFFul); /* end of table */
+
+    /* DataTable */
+    datatable = here ();
+    dw (0xE000); /* INITBYTE */
+    dw (0x0008); /* LN_TYPE */
+    dw (0x0300); /* NT_DEVICE */
+    dw (0xC000); /* INITLONG */
+    dw (0x000A); /* LN_NAME */
+    dl (ROM_hardfile_resname);
+    dw (0xE000); /* INITBYTE */
+    dw (0x000E); /* LIB_FLAGS */
+    dw (0x0600); /* LIBF_SUMUSED | LIBF_CHANGED */
+    dw (0xD000); /* INITWORD */
+    dw (0x0014); /* LIB_VERSION */
+    dw (0x0004); /* 0.4 */
+    dw (0xD000);
+    dw (0x0016); /* LIB_REVISION */
+    dw (0x0000);
+    dw (0xC000);
+    dw (0x0018); /* LIB_IDSTRING */
+    dl (ROM_hardfile_resid);
+    dw (0x0000); /* end of table */
+
+    ROM_hardfile_init = here ();
+    dl (0x00000100); /* ??? */
+    dl (functable);
+    dl (datatable);
+    dl (initcode);
+}
diff --git a/identify.c b/identify.c
new file mode 100755 (executable)
index 0000000..8d1bae6
--- /dev/null
@@ -0,0 +1,400 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Routines for labelling amiga internals. 
+  *
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+#include "memory.h"
+#include "identify.h"
+
+struct mem_labels int_labels[] =
+{
+    { "Reset:SSP",  0x0000 },
+    { "EXECBASE",   0x0004 },
+    { "BUS ERROR",  0x0008 },
+    { "ADR ERROR",  0x000C },
+    { "ILLEG OPC",  0x0010 },
+    { "DIV BY 0",   0x0014 },
+    { "CHK",        0x0018 },
+    { "TRAPV",      0x001C },
+    { "PRIVIL VIO", 0x0020 },
+    { "TRACE",      0x0024 },
+    { "LINEA EMU",  0x0028 },
+    { "LINEF EMU",  0x002C },
+    { "INT Uninit", 0x003C },
+    { "INT Unjust", 0x0060 },
+    { "Lvl 1 Int",  0x0064 },
+    { "Lvl 2 Int",  0x0068 },
+    { "Lvl 3 Int",  0x006C },
+    { "Lvl 4 Int",  0x0070 },
+    { "Lvl 5 Int",  0x0074 },
+    { "Lvl 6 Int",  0x0078 },
+    { "NMI",        0x007C },
+    { 0, 0 }
+};
+
+struct mem_labels trap_labels[] =
+{
+    { "TRAP 00",    0x0080 },
+    { "TRAP 01",    0x0084 },
+    { "TRAP 02",    0x0088 },
+    { "TRAP 03",    0x008C },
+    { "TRAP 04",    0x0090 },
+    { "TRAP 05",    0x0094 },
+    { "TRAP 06",    0x0098 },
+    { "TRAP 07",    0x009C },
+    { "TRAP 08",    0x00A0 },
+    { "TRAP 09",    0x00A4 },
+    { "TRAP 10",    0x00A8 },
+    { "TRAP 11",    0x00AC },
+    { "TRAP 12",    0x00B0 },
+    { "TRAP 13",    0x00B4 },
+    { "TRAP 14",    0x00B8 },
+    { "TRAP 15",    0x00BC },
+    { 0, 0 }
+};
+
+struct mem_labels mem_labels[] =
+{
+    { "CIAB PRA",   0xBFD000 },
+    { "CIAB PRB",   0xBFD100 },
+    { "CIAB DDRA",  0xBFD200 },
+    { "CIAB DDRB",  0xBFD300 },
+    { "CIAB TALO",  0xBFD400 },
+    { "CIAB TAHI",  0xBFD500 },
+    { "CIAB TBLO",  0xBFD600 },
+    { "CIAB TBHI",  0xBFD700 },
+    { "CIAB TDLO",  0xBFD800 },
+    { "CIAB TDMD",  0xBFD900 },
+    { "CIAB TDHI",  0xBFDA00 },
+    { "CIAB SDR",   0xBFDC00 },
+    { "CIAB ICR",   0xBFDD00 },
+    { "CIAB CRA",   0xBFDE00 },
+    { "CIAB CRB",   0xBFDF00 },
+    { "CIAA PRA",   0xBFE001 },
+    { "CIAA PRB",   0xBFE101 },
+    { "CIAA DDRA",  0xBFE201 },
+    { "CIAA DDRB",  0xBFE301 },
+    { "CIAA TALO",  0xBFE401 },
+    { "CIAA TAHI",  0xBFE501 },
+    { "CIAA TBLO",  0xBFE601 },
+    { "CIAA TBHI",  0xBFE701 },
+    { "CIAA TDLO",  0xBFE801 },
+    { "CIAA TDMD",  0xBFE901 },
+    { "CIAA TDHI",  0xBFEA01 },
+    { "CIAA SDR",   0xBFEC01 },
+    { "CIAA ICR",   0xBFED01 },
+    { "CIAA CRA",   0xBFEE01 },
+    { "CIAA CRB",   0xBFEF01 },
+    { "CLK S1",     0xDC0000 },
+    { "CLK S10",    0xDC0004 },
+    { "CLK MI1",    0xDC0008 },
+    { "CLK MI10",   0xDC000C },
+    { "CLK H1",     0xDC0010 },
+    { "CLK H10",    0xDC0014 },
+    { "CLK D1",     0xDC0018 },
+    { "CLK D10",    0xDC001C },
+    { "CLK MO1",    0xDC0020 },
+    { "CLK MO10",   0xDC0024 },
+    { "CLK Y1",     0xDC0028 },
+    { "CLK Y10",    0xDC002E },
+    { "CLK WEEK",   0xDC0030 },
+    { "CLK CD",     0xDC0034 },
+    { "CLK CE",     0xDC0038 },
+    { "CLK CF",     0xDC003C },
+    { NULL, 0 }
+};
+
+/* This table was generated from the list of AGA chip names in 
+ * AGA.guide available on aminet. It could well have errors in it. */
+
+struct customData custd[] =
+{
+#if 0
+    { "BLTDDAT",  0xdff000 }, /* Blitter dest. early read (dummy address) */
+#endif
+    { "DMACONR",  0xdff002 }, /* Dma control (and blitter status) read */
+    { "VPOSR",    0xdff004 }, /* Read vert most sig. bits (and frame flop */
+    { "VHPOSR",   0xdff006 }, /* Read vert and horiz position of beam */
+#if 0
+    { "DSKDATR",  0xdff008 }, /* Disk data early read (dummy address) */
+#endif
+    { "JOY0DAT",  0xdff00A }, /* Joystick-mouse 0 data (vert,horiz) */
+    { "JOT1DAT",  0xdff00C }, /* Joystick-mouse 1 data (vert,horiz) */
+    { "CLXDAT",   0xdff00E }, /* Collision data reg. (read and clear) */
+    { "ADKCONR",  0xdff010 }, /* Audio,disk control register read */
+    { "POT0DAT",  0xdff012 }, /* Pot counter pair 0 data (vert,horiz) */
+    { "POT1DAT",  0xdff014 }, /* Pot counter pair 1 data (vert,horiz) */
+    { "POTGOR",   0xdff016 }, /* Pot pin data read */
+    { "SERDATR",  0xdff018 }, /* Serial port data and status read */
+    { "DSKBYTR",  0xdff01A }, /* Disk data byte and status read */
+    { "INTENAR",  0xdff01C }, /* Interrupt enable bits read */
+    { "INTREQR",  0xdff01E }, /* Interrupt request bits read */
+    { "DSKPTH",   0xdff020 }, /* Disk pointer (high 5 bits) */
+    { "DSKPTL",   0xdff022 }, /* Disk pointer (low 15 bits) */
+    { "DSKLEN",   0xdff024 }, /* Disk lentgh */
+    { "DSKDAT",   0xdff026 }, /* Disk DMA data write */
+#if 0
+    { "REFPTR",   0xdff028 }, /* Refresh pointer */
+#endif
+    { "VPOSW",    0xdff02A }, /* Write vert most sig. bits(and frame flop) */
+    { "VHPOSW",   0xdff02C }, /* Write vert and horiz pos of beam */
+    { "COPCON",   0xdff02e }, /* Coprocessor control reg (CDANG) */
+    { "SERDAT",   0xdff030 }, /* Serial port data and stop bits write */
+    { "SERPER",   0xdff032 }, /* Serial port period and control */
+    { "POTGO",    0xdff034 }, /* Pot count start,pot pin drive enable data */
+    { "JOYTEST",  0xdff036 }, /* Write to all 4 joystick-mouse counters at once */
+    { "STREQU",   0xdff038 }, /* Strobe for horiz sync with VB and EQU */
+    { "STRVBL",   0xdff03A }, /* Strobe for horiz sync with VB (vert blank) */
+    { "STRHOR",   0xdff03C }, /* Strobe for horiz sync */
+    { "STRLONG",  0xdff03E }, /* Strobe for identification of long horiz line */
+    { "BLTCON0",  0xdff040 }, /* Blitter control reg 0 */
+    { "BLTCON1",  0xdff042 }, /* Blitter control reg 1 */
+    { "BLTAFWM",  0xdff044 }, /* Blitter first word mask for source A */
+    { "BLTALWM",  0xdff046 }, /* Blitter last word mask for source A */
+    { "BLTCPTH",  0xdff048 }, /* Blitter pointer to source C (high 5 bits) */
+    { "BLTCPTL",  0xdff04A }, /* Blitter pointer to source C (low 15 bits) */
+    { "BLTBPTH",  0xdff04C }, /* Blitter pointer to source B (high 5 bits) */
+    { "BLTBPTL",  0xdff04E }, /* Blitter pointer to source B (low 15 bits) */
+    { "BLTAPTH",  0xdff050 }, /* Blitter pointer to source A (high 5 bits) */
+    { "BLTAPTL",  0xdff052 }, /* Blitter pointer to source A (low 15 bits) */
+    { "BPTDPTH",  0xdff054 }, /* Blitter pointer to destn  D (high 5 bits) */
+    { "BLTDPTL",  0xdff056 }, /* Blitter pointer to destn  D (low 15 bits) */
+    { "BLTSIZE",  0xdff058 }, /* Blitter start and size (win/width,height) */
+    { "BLTCON0L", 0xdff05A }, /* Blitter control 0 lower 8 bits (minterms) */
+    { "BLTSIZV",  0xdff05C }, /* Blitter V size (for 15 bit vert size) */
+    { "BLTSIZH",  0xdff05E }, /* Blitter H size & start (for 11 bit H size) */
+    { "BLTCMOD",  0xdff060 }, /* Blitter modulo for source C */
+    { "BLTBMOD",  0xdff062 }, /* Blitter modulo for source B */
+    { "BLTAMOD",  0xdff064 }, /* Blitter modulo for source A */
+    { "BLTDMOD",  0xdff066 }, /* Blitter modulo for destn  D */
+#if 0
+    { "Unknown",  0xdff068 }, /* Unknown or Unused */
+    { "Unknown",  0xdff06a }, /* Unknown or Unused */
+    { "Unknown",  0xdff06c }, /* Unknown or Unused */
+    { "Unknown",  0xdff06e }, /* Unknown or Unused */
+#endif
+    { "BLTCDAT",  0xdff070 }, /* Blitter source C data reg */
+    { "BLTBDAT",  0xdff072 }, /* Blitter source B data reg */
+    { "BLTADAT",  0xdff074 }, /* Blitter source A data reg */
+    { "BLTDDAT",  0xdff076 }, /* Blitter destination reg */
+#if 0
+    { "SPRHDAT",  0xdff078 }, /* Ext logic UHRES sprite pointer and data identifier */
+    { "BPLHDAT",  0xdff07A }, /* Ext logic UHRES bit plane identifier */
+#endif
+    { "LISAID",   0xdff07C }, /* Chip revision level for Denise/Lisa */
+    { "DSKSYNC",  0xdff07E }, /* Disk sync pattern reg for disk read */
+    { "COP1LCH",  0xdff080 }, /* Coprocessor first location reg (high 5 bits) */
+    { "COP1LCL",  0xdff082 }, /* Coprocessor first location reg (low 15 bits) */
+    { "COP2LCH",  0xdff084 }, /* Coprocessor second reg (high 5 bits) */
+    { "COP2LCL",  0xdff086 }, /* Coprocessor second reg (low 15 bits) */
+    { "COPJMP1",  0xdff088 }, /* Coprocessor restart at first location */
+    { "COPJMP2",  0xdff08A }, /* Coprocessor restart at second location */
+#if 0
+    { "COPINS",   0xdff08C }, /* Coprocessor inst fetch identify */
+#endif
+    { "DIWSTRT",  0xdff08E }, /* Display window start (upper left vert-hor pos) */
+    { "DIWSTOP",  0xdff090 }, /* Display window stop (lower right vert-hor pos) */
+    { "DDFSTRT",  0xdff092 }, /* Display bit plane data fetch start.hor pos */
+    { "DDFSTOP",  0xdff094 }, /* Display bit plane data fetch stop.hor pos */
+    { "DMACON",   0xdff096 }, /* DMA control write (clear or set) */
+    { "CLXCON",   0xdff098 }, /* Collision control */
+    { "INTENA",   0xdff09A }, /* Interrupt enable bits (clear or set bits) */
+    { "INTREQ",   0xdff09C }, /* Interrupt request bits (clear or set bits) */
+    { "ADKCON",   0xdff09E }, /* Audio,disk,UART,control */
+    { "AUD0LCH",  0xdff0A0 }, /* Audio channel 0 location (high 5 bits) */
+    { "AUD0LCL",  0xdff0A2 }, /* Audio channel 0 location (low 15 bits) */
+    { "AUD0LEN",  0xdff0A4 }, /* Audio channel 0 lentgh */
+    { "AUD0PER",  0xdff0A6 }, /* Audio channel 0 period */
+    { "AUD0VOL",  0xdff0A8 }, /* Audio channel 0 volume */
+    { "AUD0DAT",  0xdff0AA }, /* Audio channel 0 data */
+#if 0
+    { "Unknown",  0xdff0AC }, /* Unknown or Unused */
+    { "Unknown",  0xdff0AE }, /* Unknown or Unused */
+#endif
+    { "AUD1LCH",  0xdff0B0 }, /* Audio channel 1 location (high 5 bits) */
+    { "AUD1LCL",  0xdff0B2 }, /* Audio channel 1 location (low 15 bits) */
+    { "AUD1LEN",  0xdff0B4 }, /* Audio channel 1 lentgh */
+    { "AUD1PER",  0xdff0B6 }, /* Audio channel 1 period */
+    { "AUD1VOL",  0xdff0B8 }, /* Audio channel 1 volume */
+    { "AUD1DAT",  0xdff0BA }, /* Audio channel 1 data */
+#if 0
+    { "Unknown",  0xdff0BC }, /* Unknown or Unused */
+    { "Unknown",  0xdff0BE }, /* Unknown or Unused */
+#endif
+    { "AUD2LCH",  0xdff0C0 }, /* Audio channel 2 location (high 5 bits) */
+    { "AUD2LCL",  0xdff0C2 }, /* Audio channel 2 location (low 15 bits) */
+    { "AUD2LEN",  0xdff0C4 }, /* Audio channel 2 lentgh */
+    { "AUD2PER",  0xdff0C6 }, /* Audio channel 2 period */
+    { "AUD2VOL",  0xdff0C8 }, /* Audio channel 2 volume */
+    { "AUD2DAT",  0xdff0CA }, /* Audio channel 2 data */
+#if 0
+    { "Unknown",  0xdff0CC }, /* Unknown or Unused */
+    { "Unknown",  0xdff0CE }, /* Unknown or Unused */
+#endif
+    { "AUD3LCH",  0xdff0D0 }, /* Audio channel 3 location (high 5 bits) */
+    { "AUD3LCL",  0xdff0D2 }, /* Audio channel 3 location (low 15 bits) */
+    { "AUD3LEN",  0xdff0D4 }, /* Audio channel 3 lentgh */
+    { "AUD3PER",  0xdff0D6 }, /* Audio channel 3 period */
+    { "AUD3VOL",  0xdff0D8 }, /* Audio channel 3 volume */
+    { "AUD3DAT",  0xdff0DA }, /* Audio channel 3 data */
+#if 0
+    { "Unknown",  0xdff0DC }, /* Unknown or Unused */
+    { "Unknown",  0xdff0DE }, /* Unknown or Unused */
+#endif
+    { "BPL1PTH",  0xdff0E0 }, /* Bit plane pointer 1 (high 5 bits) */
+    { "BPL1PTL",  0xdff0E2 }, /* Bit plane pointer 1 (low 15 bits) */
+    { "BPL2PTH",  0xdff0E4 }, /* Bit plane pointer 2 (high 5 bits) */
+    { "BPL2PTL",  0xdff0E6 }, /* Bit plane pointer 2 (low 15 bits) */
+    { "BPL3PTH",  0xdff0E8 }, /* Bit plane pointer 3 (high 5 bits) */
+    { "BPL3PTL",  0xdff0EA }, /* Bit plane pointer 3 (low 15 bits) */
+    { "BPL4PTH",  0xdff0EC }, /* Bit plane pointer 4 (high 5 bits) */
+    { "BPL4PTL",  0xdff0EE }, /* Bit plane pointer 4 (low 15 bits) */
+    { "BPL5PTH",  0xdff0F0 }, /* Bit plane pointer 5 (high 5 bits) */
+    { "BPL5PTL",  0xdff0F2 }, /* Bit plane pointer 5 (low 15 bits) */
+    { "BPL6PTH",  0xdff0F4 }, /* Bit plane pointer 6 (high 5 bits) */
+    { "BPL6PTL",  0xdff0F6 }, /* Bit plane pointer 6 (low 15 bits) */
+    { "BPL7PTH",  0xdff0F8 }, /* Bit plane pointer 7 (high 5 bits) */
+    { "BPL7PTL",  0xdff0FA }, /* Bit plane pointer 7 (low 15 bits) */
+    { "BPL8PTH",  0xdff0FC }, /* Bit plane pointer 8 (high 5 bits) */
+    { "BPL8PTL",  0xdff0FE }, /* Bit plane pointer 8 (low 15 bits) */
+    { "BPLCON0",  0xdff100 }, /* Bit plane control reg (misc control bits) */
+    { "BPLCON1",  0xdff102 }, /* Bit plane control reg (scroll val PF1,PF2) */
+    { "BPLCON2",  0xdff104 }, /* Bit plane control reg (priority control) */
+    { "BPLCON3",  0xdff106 }, /* Bit plane control reg (enhanced features) */
+    { "BPL1MOD",  0xdff108 }, /* Bit plane modulo (odd planes,or active- fetch lines if bitplane scan-doubling is enabled */
+    { "BPL2MOD",  0xdff10A }, /* Bit plane modulo (even planes or inactive- fetch lines if bitplane scan-doubling is enabled */
+    { "BPLCON4",  0xdff10C }, /* Bit plane control reg (bitplane and sprite masks) */
+    { "CLXCON2",  0xdff10e }, /* Extended collision control reg */
+    { "BPL1DAT",  0xdff110 }, /* Bit plane 1 data (parallel to serial con- vert) */
+    { "BPL2DAT",  0xdff112 }, /* Bit plane 2 data (parallel to serial con- vert) */
+    { "BPL3DAT",  0xdff114 }, /* Bit plane 3 data (parallel to serial con- vert) */
+    { "BPL4DAT",  0xdff116 }, /* Bit plane 4 data (parallel to serial con- vert) */
+    { "BPL5DAT",  0xdff118 }, /* Bit plane 5 data (parallel to serial con- vert) */
+    { "BPL6DAT",  0xdff11a }, /* Bit plane 6 data (parallel to serial con- vert) */
+    { "BPL7DAT",  0xdff11c }, /* Bit plane 7 data (parallel to serial con- vert) */
+    { "BPL8DAT",  0xdff11e }, /* Bit plane 8 data (parallel to serial con- vert) */
+    { "SPR0PTH",  0xdff120 }, /* Sprite 0 pointer (high 5 bits) */
+    { "SPR0PTL",  0xdff122 }, /* Sprite 0 pointer (low 15 bits) */
+    { "SPR1PTH",  0xdff124 }, /* Sprite 1 pointer (high 5 bits) */
+    { "SPR1PTL",  0xdff126 }, /* Sprite 1 pointer (low 15 bits) */
+    { "SPR2PTH",  0xdff128 }, /* Sprite 2 pointer (high 5 bits) */
+    { "SPR2PTL",  0xdff12A }, /* Sprite 2 pointer (low 15 bits) */
+    { "SPR3PTH",  0xdff12C }, /* Sprite 3 pointer (high 5 bits) */
+    { "SPR3PTL",  0xdff12E }, /* Sprite 3 pointer (low 15 bits) */
+    { "SPR4PTH",  0xdff130 }, /* Sprite 4 pointer (high 5 bits) */
+    { "SPR4PTL",  0xdff132 }, /* Sprite 4 pointer (low 15 bits) */
+    { "SPR5PTH",  0xdff134 }, /* Sprite 5 pointer (high 5 bits) */
+    { "SPR5PTL",  0xdff136 }, /* Sprite 5 pointer (low 15 bits) */
+    { "SPR6PTH",  0xdff138 }, /* Sprite 6 pointer (high 5 bits) */
+    { "SPR6PTL",  0xdff13A }, /* Sprite 6 pointer (low 15 bits) */
+    { "SPR7PTH",  0xdff13C }, /* Sprite 7 pointer (high 5 bits) */
+    { "SPR7PTL",  0xdff13E }, /* Sprite 7 pointer (low 15 bits) */
+    { "SPR0POS",  0xdff140 }, /* Sprite 0 vert-horiz start pos data */
+    { "SPR0CTL",  0xdff142 }, /* Sprite 0 position and control data */
+    { "SPR0DATA", 0xdff144 }, /* Sprite 0 image data register A */
+    { "SPR0DATB", 0xdff146 }, /* Sprite 0 image data register B */
+    { "SPR1POS",  0xdff148 }, /* Sprite 1 vert-horiz start pos data */
+    { "SPR1CTL",  0xdff14A }, /* Sprite 1 position and control data */
+    { "SPR1DATA", 0xdff14C }, /* Sprite 1 image data register A */
+    { "SPR1DATB", 0xdff14E }, /* Sprite 1 image data register B */
+    { "SPR2POS",  0xdff150 }, /* Sprite 2 vert-horiz start pos data */
+    { "SPR2CTL",  0xdff152 }, /* Sprite 2 position and control data */
+    { "SPR2DATA", 0xdff154 }, /* Sprite 2 image data register A */
+    { "SPR2DATB", 0xdff156 }, /* Sprite 2 image data register B */
+    { "SPR3POS",  0xdff158 }, /* Sprite 3 vert-horiz start pos data */
+    { "SPR3CTL",  0xdff15A }, /* Sprite 3 position and control data */
+    { "SPR3DATA", 0xdff15C }, /* Sprite 3 image data register A */
+    { "SPR3DATB", 0xdff15E }, /* Sprite 3 image data register B */
+    { "SPR4POS",  0xdff160 }, /* Sprite 4 vert-horiz start pos data */
+    { "SPR4CTL",  0xdff162 }, /* Sprite 4 position and control data */
+    { "SPR4DATA", 0xdff164 }, /* Sprite 4 image data register A */
+    { "SPR4DATB", 0xdff166 }, /* Sprite 4 image data register B */
+    { "SPR5POS",  0xdff168 }, /* Sprite 5 vert-horiz start pos data */
+    { "SPR5CTL",  0xdff16A }, /* Sprite 5 position and control data */
+    { "SPR5DATA", 0xdff16C }, /* Sprite 5 image data register A */
+    { "SPR5DATB", 0xdff16E }, /* Sprite 5 image data register B */
+    { "SPR6POS",  0xdff170 }, /* Sprite 6 vert-horiz start pos data */
+    { "SPR6CTL",  0xdff172 }, /* Sprite 6 position and control data */
+    { "SPR6DATA", 0xdff174 }, /* Sprite 6 image data register A */
+    { "SPR6DATB", 0xdff176 }, /* Sprite 6 image data register B */
+    { "SPR7POS",  0xdff178 }, /* Sprite 7 vert-horiz start pos data */
+    { "SPR7CTL",  0xdff17A }, /* Sprite 7 position and control data */
+    { "SPR7DATA", 0xdff17C }, /* Sprite 7 image data register A */
+    { "SPR7DATB", 0xdff17E }, /* Sprite 7 image data register B */
+    { "COLOR00",  0xdff180 }, /* Color table 00 */
+    { "COLOR01",  0xdff182 }, /* Color table 01 */
+    { "COLOR02",  0xdff184 }, /* Color table 02 */
+    { "COLOR03",  0xdff186 }, /* Color table 03 */
+    { "COLOR04",  0xdff188 }, /* Color table 04 */
+    { "COLOR05",  0xdff18A }, /* Color table 05 */
+    { "COLOR06",  0xdff18C }, /* Color table 06 */
+    { "COLOR07",  0xdff18E }, /* Color table 07 */
+    { "COLOR08",  0xdff190 }, /* Color table 08 */
+    { "COLOR09",  0xdff192 }, /* Color table 09 */
+    { "COLOR10",  0xdff194 }, /* Color table 10 */
+    { "COLOR11",  0xdff196 }, /* Color table 11 */
+    { "COLOR12",  0xdff198 }, /* Color table 12 */
+    { "COLOR13",  0xdff19A }, /* Color table 13 */
+    { "COLOR14",  0xdff19C }, /* Color table 14 */
+    { "COLOR15",  0xdff19E }, /* Color table 15 */
+    { "COLOR16",  0xdff1A0 }, /* Color table 16 */
+    { "COLOR17",  0xdff1A2 }, /* Color table 17 */
+    { "COLOR18",  0xdff1A4 }, /* Color table 18 */
+    { "COLOR19",  0xdff1A6 }, /* Color table 19 */
+    { "COLOR20",  0xdff1A8 }, /* Color table 20 */
+    { "COLOR21",  0xdff1AA }, /* Color table 21 */
+    { "COLOR22",  0xdff1AC }, /* Color table 22 */
+    { "COLOR23",  0xdff1AE }, /* Color table 23 */
+    { "COLOR24",  0xdff1B0 }, /* Color table 24 */
+    { "COLOR25",  0xdff1B2 }, /* Color table 25 */
+    { "COLOR26",  0xdff1B4 }, /* Color table 26 */
+    { "COLOR27",  0xdff1B6 }, /* Color table 27 */
+    { "COLOR28",  0xdff1B8 }, /* Color table 28 */
+    { "COLOR29",  0xdff1BA }, /* Color table 29 */
+    { "COLOR30",  0xdff1BC }, /* Color table 30 */
+    { "COLOR31",  0xdff1BE }, /* Color table 31 */
+    { "HTOTAL",   0xdff1C0 }, /* Highest number count in horiz line (VARBEAMEN = 1) */
+    { "HSSTOP",   0xdff1C2 }, /* Horiz line pos for HSYNC stop */
+    { "HBSTRT",   0xdff1C4 }, /* Horiz line pos for HBLANK start */
+    { "HBSTOP",   0xdff1C6 }, /* Horiz line pos for HBLANK stop */
+    { "VTOTAL",   0xdff1C8 }, /* Highest numbered vertical line (VARBEAMEN = 1) */
+    { "VSSTOP",   0xdff1CA }, /* Vert line for VBLANK start */
+    { "VBSTRT",   0xdff1CC }, /* Vert line for VBLANK start */
+    { "VBSTOP",   0xdff1CE }, /* Vert line for VBLANK stop */
+#if 0
+    { "SPRHSTRT", 0xdff1D0 }, /* UHRES sprite vertical start */
+    { "SPRHSTOP", 0xdff1D2 }, /* UHRES sprite vertical stop */
+    { "BPLHSTRT", 0xdff1D4 }, /* UHRES bit plane vertical stop */
+    { "BPLHSTOP", 0xdff1D6 }, /* UHRES bit plane vertical stop */
+    { "HHPOSW",   0xdff1D8 }, /* DUAL mode hires H beam counter write */
+    { "HHPOSR",   0xdff1DA }, /* DUAL mode hires H beam counter read */
+#endif
+    { "BEAMCON0", 0xdff1DC }, /* Beam counter control register (SHRES,UHRES,PAL) */
+    { "HSSTRT",   0xdff1DE }, /* Horizontal sync start (VARHSY) */
+    { "VSSTRT",   0xdff1E0 }, /* Vertical sync start (VARVSY) */
+    { "HCENTER",  0xdff1E2 }, /* Horizontal pos for vsync on interlace */
+    { "DIWHIGH",  0xdff1E4 }, /* Display window upper bits for start/stop */
+#if 0
+    { "BPLHMOD",  0xdff1E6 }, /* UHRES bit plane modulo */
+    { "SPRHPTH",  0xdff1E8 }, /* UHRES sprite pointer (high 5 bits) */
+    { "SPRHPTL",  0xdff1EA }, /* UHRES sprite pointer (low 15 bits) */
+    { "BPLHPTH",  0xdff1EC }, /* VRam (UHRES) bitplane pointer (hi 5 bits) */
+    { "BPLHPTL",  0xdff1EE }, /* VRam (UHRES) bitplane pointer (lo 15 bits) */
+    { "RESERVED", 0xdff1F0 }, /* Reserved (forever i guess!) */
+    { "RESERVED", 0xdff1F2 }, /* Reserved (forever i guess!) */
+    { "RESERVED", 0xdff1F4 }, /* Reserved (forever i guess!) */
+    { "RESERVED", 0xdff1F6 }, /* Reserved (forever i guess!) */
+    { "RESERVED", 0xdff1F8 }, /* Reserved (forever i guess!) */
+    { "RESERVED", 0xdff1Fa }, /* Reserved (forever i guess!) */
+#endif
+    { "FMODE",    0xdff1FC }, /* Fetch mode register */
+#if 0
+    { "NO-OP(NULL)", 0xdff1FE },        /*   Can also indicate last 2 or 3 refresh
+                                           cycles or the restart of the COPPER after lockup.*/
+#endif
+};
+
diff --git a/include/akiko.h b/include/akiko.h
new file mode 100755 (executable)
index 0000000..8be2065
--- /dev/null
@@ -0,0 +1,13 @@
+
+
+#define AKIKO_BASE 0xb80000
+#define AKIKO_BASE_END 0xb80100 /* ?? */
+
+extern void akiko_reset (void);
+extern int akiko_init (void);
+extern void akiko_free (void);
+extern int cd32_enabled;
+
+extern void akiko_entergui (void);
+extern void akiko_exitgui (void);
+extern void AKIKO_hsync_handler (void);
diff --git a/include/ar.h b/include/ar.h
new file mode 100755 (executable)
index 0000000..03f3692
--- /dev/null
@@ -0,0 +1,69 @@
+
+/* disable HRTMon support by commenting this out */
+#define ACTION_REPLAY_HRTMON
+
+#ifdef ACTION_REPLAY
+#define ACTION_REPLAY_COMMON
+#endif
+
+#ifdef ACTION_REPLAY_HRTMON
+#define ACTION_REPLAY_COMMON
+#endif
+
+#ifdef ACTION_REPLAY
+/* disable Action Replay ROM/RAM hide by commenting this out */
+/* Better not disable this unless you do plenty of testing first. -Mark */
+#define ACTION_REPLAY_HIDE_CARTRIDGE
+#endif
+
+#define ACTION_REPLAY_WAIT_PC -3       /* Wait for a specified Program counter */
+#define ACTION_REPLAY_INACTIVE -2
+#define ACTION_REPLAY_WAITRESET -1
+#define ACTION_REPLAY_IDLE 1
+#define ACTION_REPLAY_ACTIVATE 2
+#define ACTION_REPLAY_ACTIVE 3
+#define ACTION_REPLAY_DORESET 4
+#define ACTION_REPLAY_HIDE 5
+
+extern int action_replay_freeze (void);
+
+extern uaecptr wait_for_pc;
+extern int action_replay_flag;
+extern int armodel;
+
+extern int is_ar_pc_in_rom(void);
+extern int is_ar_pc_in_ram(void);
+extern void action_replay_enter (void);
+extern void action_replay_ciaread (void);
+extern void action_replay_hide (void);
+extern void action_replay_reset (void);
+extern int action_replay_load (void);
+
+extern void action_replay_memory_reset(void);
+extern void action_replay_init (int);
+extern void action_replay_cleanup (void);
+extern void action_replay_chipwrite(void);
+extern void action_replay_map_banks(void);
+extern void REGPARAM2 chipmem_lput_actionreplay23 (uaecptr addr, uae_u32 l) REGPARAM;
+extern void REGPARAM2 chipmem_wput_actionreplay23 (uaecptr addr, uae_u32 w) REGPARAM;
+extern void REGPARAM2 chipmem_bput_actionreplay1 (uaecptr addr, uae_u32 b) REGPARAM;
+extern void REGPARAM2 chipmem_wput_actionreplay1 (uaecptr addr, uae_u32 w) REGPARAM;
+extern void REGPARAM2 chipmem_lput_actionreplay1 (uaecptr addr, uae_u32 l) REGPARAM;
+
+extern void action_replay_version(void);
+
+
+extern int hrtmon_flag;
+
+extern void hrtmon_enter (void);
+extern void hrtmon_breakenter (void);
+extern void hrtmon_ciaread (void);
+extern void hrtmon_hide (void);
+extern void hrtmon_reset (void);
+extern int hrtmon_load (int);
+extern void hrtmon_map_banks(void);
+
+/*extern uae_u8 *hrtmemory;*/
+extern uae_u32 hrtmem_start, hrtmem_size;
+
+extern uae_u8 ar_custom[2*256];
diff --git a/include/audio.h b/include/audio.h
new file mode 100755 (executable)
index 0000000..5ae517d
--- /dev/null
@@ -0,0 +1,32 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Sound emulation stuff
+  *
+  * Copyright 1995, 1996, 1997 Bernd Schmidt
+  */
+
+#define PERIOD_MAX ULONG_MAX
+
+extern void aud0_handler (void);
+extern void aud1_handler (void);
+extern void aud2_handler (void);
+extern void aud3_handler (void);
+
+extern void AUDxDAT (int nr, uae_u16 value);
+extern void AUDxVOL (int nr, uae_u16 value);
+extern void AUDxPER (int nr, uae_u16 value);
+extern void AUDxLCH (int nr, uae_u16 value);
+extern void AUDxLCL (int nr, uae_u16 value);
+extern void AUDxLEN (int nr, uae_u16 value);
+
+extern int init_audio (void);
+extern void ahi_install (void);
+extern void audio_reset (void);
+extern void update_audio (void);
+extern void schedule_audio (void);
+extern void audio_evhandler (void);
+extern void audio_hsync (int);
+extern void update_adkmasks (void);
+extern void update_sound (int freq);
+
diff --git a/include/autoconf.h b/include/autoconf.h
new file mode 100755 (executable)
index 0000000..4c3040c
--- /dev/null
@@ -0,0 +1,93 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Autoconfig device support
+  *
+  * (c) 1996 Ed Hanway
+  */
+
+typedef uae_u32 (*TrapFunction) (void);
+
+extern int lasttrap;
+extern uae_u8 *rtarea;
+extern void do_emultrap (int nr);
+
+extern uae_u32 addr (int);
+extern void db (uae_u8);
+extern void dw (uae_u16);
+extern void dl (uae_u32);
+extern uae_u32 ds (char *);
+extern void calltrap (uae_u32);
+extern void org (uae_u32);
+extern uae_u32 here (void);
+extern int deftrap2 (TrapFunction func, int mode, const char *str);
+extern int deftrap (TrapFunction);
+extern void align (int);
+extern uae_u32 CallLib (uaecptr base, uae_s16 offset);
+extern void call_calltrap (int nr) REGPARAM;
+
+extern volatile int uae_int_requested;
+extern void set_uae_int_flag (void);
+
+#define RTS 0x4e75
+#define RTE 0x4e73
+
+extern uaecptr EXPANSION_explibname, EXPANSION_doslibname, EXPANSION_uaeversion;
+extern uaecptr EXPANSION_explibbase, EXPANSION_uaedevname, EXPANSION_haveV36;
+extern uaecptr EXPANSION_bootcode, EXPANSION_nullfunc;
+
+extern uaecptr ROM_filesys_resname, ROM_filesys_resid;
+extern uaecptr ROM_filesys_diagentry;
+extern uaecptr ROM_hardfile_resname, ROM_hardfile_resid;
+extern uaecptr ROM_hardfile_init;
+extern uaecptr filesys_initcode;
+
+extern int nr_units (struct uaedev_mount_info *mountinfo);
+extern int is_hardfile (struct uaedev_mount_info *mountinfo, int unit_no);
+extern char *set_filesys_unit (struct uaedev_mount_info *mountinfo, int,
+                              char *devname, char *volname, char *rootdir, int readonly,
+                              int secs, int surfaces, int reserved,
+                              int blocksize, int bootpri, char *filesysdir);
+extern char *add_filesys_unit (struct uaedev_mount_info *mountinfo,
+                              char *devname, char *volname, char *rootdir, int readonly,
+                              int secs, int surfaces, int reserved,
+                              int blocksize, int bootpri, char *filesysdir);
+extern char *get_filesys_unit (struct uaedev_mount_info *mountinfo, int nr,
+                              char **devname, char **volame, char **rootdir, int *readonly,
+                              int *secspertrack, int *surfaces, int *reserved,
+                              int *cylinders, uae_u64 *size, int *blocksize, int *bootpri, char **filesysdir);
+extern int kill_filesys_unit (struct uaedev_mount_info *mountinfo, int);
+extern int move_filesys_unit (struct uaedev_mount_info *mountinfo, int nr, int to);
+extern int sprintf_filesys_unit (struct uaedev_mount_info *mountinfo, char *buffer, int num);
+extern void write_filesys_config (struct uaedev_mount_info *mountinfo, const char *unexpanded,
+                                 const char *defaultpath, FILE *f);
+
+extern struct uaedev_mount_info *alloc_mountinfo (void);
+extern struct uaedev_mount_info *dup_mountinfo (struct uaedev_mount_info *);
+extern void free_mountinfo (struct uaedev_mount_info *);
+
+extern void filesys_reset (void);
+extern void filesys_prepare_reset (void);
+extern void filesys_start_threads (void);
+extern void filesys_flush_cache (void);
+
+extern void filesys_install (void);
+extern void filesys_install_code (void);
+extern void filesys_store_devinfo (uae_u8 *);
+extern void hardfile_install (void);
+extern void hardfile_reset (void);
+extern void emulib_install (void);
+extern void expansion_init (void);
+extern void expansion_cleanup (void);
+
+extern uae_u8* rtarea;
+
+#define TRAPFLAG_NO_REGSAVE 1
+#define TRAPFLAG_NO_RETVAL 2
+#define TRAPFLAG_EXTRA_STACK 4
+#define TRAPFLAG_DORET 8
+
+extern uaecptr libemu_InstallFunction (TrapFunction, uaecptr, int, const char *);
+extern uaecptr libemu_InstallFunctionFlags (TrapFunction, uaecptr, int, int, const char *);
+
+#define RTAREA_BASE 0xF00000
diff --git a/include/blitter.h b/include/blitter.h
new file mode 100755 (executable)
index 0000000..bc7d501
--- /dev/null
@@ -0,0 +1,60 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Blitter emulation
+  *
+  * (c) 1995 Bernd Schmidt
+  */
+
+#if 0
+struct bltinfo {
+    int blitzero;
+    int blitashift,blitbshift,blitdownashift,blitdownbshift;
+    uae_u32 bltadat, bltbdat, bltcdat,bltddat,bltahold,bltbhold,bltafwm,bltalwm;
+    int vblitsize,hblitsize;
+    int bltamod,bltbmod,bltcmod,bltdmod;
+};
+#else
+struct bltinfo {
+    int blitzero;
+    int blitashift,blitbshift,blitdownashift,blitdownbshift;
+    uae_u16 bltadat, bltbdat, bltcdat,bltddat,bltahold,bltbhold,bltafwm,bltalwm;
+    int vblitsize,hblitsize;
+    int bltamod,bltbmod,bltcmod,bltdmod;
+};
+#endif
+extern enum blitter_states {
+    BLT_done, BLT_init, BLT_read, BLT_work, BLT_write, BLT_next
+} bltstate;
+
+extern struct bltinfo blt_info;
+
+extern uae_u16 bltsize;
+extern uae_u16 bltcon0,bltcon1;
+extern int blinea_shift;
+extern uae_u32 bltapt,bltbpt,bltcpt,bltdpt;
+extern int blit_singlechannel;
+
+extern void maybe_blit (int, int);
+extern void reset_blit (int);
+extern int blitnasty (void);
+extern int blitnnasty (int);
+extern void blitter_handler (void);
+extern void build_blitfilltable (void);
+extern void do_blitter (int);
+extern void decide_blitter (int hpos);
+extern void blitter_done_notify (void);
+extern void blitter_slowdown (int, int, int, int);
+
+typedef void blitter_func(uaecptr, uaecptr, uaecptr, uaecptr, struct bltinfo *);
+
+#define BLITTER_MAX_WORDS 2048
+
+extern blitter_func *blitfunc_dofast[256];
+extern blitter_func *blitfunc_dofast_desc[256];
+extern uae_u32 blit_masktable[BLITTER_MAX_WORDS];
+
+#define BLIT_MODE_IMMEDIATE -1
+#define BLIT_MODE_APPROXIMATE 0
+#define BLIT_MODE_COMPATIBLE 1
+#define BLIT_MODE_EXACT 2
diff --git a/include/blkdev.h b/include/blkdev.h
new file mode 100755 (executable)
index 0000000..51d613d
--- /dev/null
@@ -0,0 +1,105 @@
+
+#define MAX_TOTAL_DEVICES 8
+#define DEVICE_SCSI_BUFSIZE 4096
+
+//#define device_debug write_log
+#define device_debug
+
+#define        INQ_DASD        0x00            /* Direct-access device (disk) */
+#define        INQ_SEQD        0x01            /* Sequential-access device (tape) */
+#define        INQ_PRTD        0x02            /* Printer device */
+#define        INQ_PROCD       0x03            /* Processor device */
+#define        INQ_OPTD        0x04            /* Write once device (optical disk) */
+#define        INQ_WORM        0x04            /* Write once device (optical disk) */
+#define        INQ_ROMD        0x05            /* CD-ROM device */
+#define        INQ_SCAN        0x06            /* Scanner device */
+#define        INQ_OMEM        0x07            /* Optical Memory device */
+#define        INQ_JUKE        0x08            /* Medium Changer device (jukebox) */
+#define        INQ_COMM        0x09            /* Communications device */
+#define        INQ_IT8_1       0x0A            /* IT8 */
+#define        INQ_IT8_2       0x0B            /* IT8 */
+#define        INQ_STARR       0x0C            /* Storage array device */
+#define        INQ_ENCL        0x0D            /* Enclosure services device */
+#define        INQ_NODEV       0x1F            /* Unknown or no device */
+#define        INQ_NOTPR       0x1F            /* Logical unit not present (SCSI-1) */
+
+#define DEVICE_TYPE_ANY 1
+#define DEVICE_TYPE_SCSI 2
+
+#define DF_SCSI 0
+#define DF_IOCTL 1
+
+struct device_info {
+    int type;
+    int media_inserted;
+    int write_protected;
+    int cylinders;
+    int trackspercylinder;
+    int sectorspertrack;
+    int bytespersector;
+    int bus, target, lun;
+    int id;
+    char label[60];
+};
+
+typedef int (*open_bus_func)(int flags);
+typedef void (*close_bus_func)(void);
+typedef int (*open_device_func)(int);
+typedef void (*close_device_func)(int);
+typedef struct device_info* (*info_device_func)(int, struct device_info*);
+typedef uae_u8* (*execscsicmd_out_func)(int, uae_u8*, int);
+typedef uae_u8* (*execscsicmd_in_func)(int, uae_u8*, int, int*);
+typedef int (*execscsicmd_direct_func)(int, uaecptr);
+
+typedef int (*pause_func)(int, int);
+typedef int (*stop_func)(int);
+typedef int (*play_func)(int, uae_u32, uae_u32, int);
+typedef uae_u8* (*qcode_func)(int);
+typedef uae_u8* (*toc_func)(int);
+typedef uae_u8* (*read_func)(int, int);
+typedef int (*write_func)(int, int, uae_u8*);
+typedef int (*isatapi_func)(int);
+
+struct device_functions {
+    open_bus_func openbus;
+    close_bus_func closebus;
+    open_device_func opendev;
+    close_device_func closedev;
+    info_device_func info;
+    execscsicmd_out_func exec_out;
+    execscsicmd_in_func exec_in;
+    execscsicmd_direct_func exec_direct;
+
+    pause_func pause;
+    stop_func stop;
+    play_func play;
+    qcode_func qcode;
+    toc_func toc;
+    read_func read;
+    write_func write;
+
+    isatapi_func isatapi;
+
+    
+};
+
+extern struct device_functions *device_func[2];
+
+extern int device_func_init(int flags);
+extern int sys_command_open (int mode, int unitnum);
+extern void sys_command_close (int mode, int unitnum);
+extern struct device_info *sys_command_info (int mode, int unitnum, struct device_info *di);
+extern void sys_command_pause (int mode, int unitnum, int paused);
+extern void sys_command_stop (int mode, int unitnum);
+extern int sys_command_play (int mode, int unitnum, uae_u32 startmsf, uae_u32 endmsf, int);
+extern uae_u8 *sys_command_qcode (int mode, int unitnum);
+extern uae_u8 *sys_command_toc (int mode, int unitnum);
+extern uae_u8 *sys_command_read (int mode, int unitnum, int offset);
+extern int sys_command_write (int mode, int unitnum, int offset, uae_u8 *data);
+extern int sys_command_scsi_direct (int unitnum, uaecptr request);
+
+void scsi_atapi_fixup_pre (uae_u8 *scsi_cmd, int *len, uae_u8 **data, int *datalen, int *parm);
+void scsi_atapi_fixup_post (uae_u8 *scsi_cmd, int len, uae_u8 *olddata, uae_u8 *data, int *datalen, int parm);
+
+void scsi_log_before (uae_u8 *cdb, int cdblen, uae_u8 *data, int datalen);
+void scsi_log_after (uae_u8 *data, int datalen, uae_u8 *sense, int senselen);
diff --git a/include/bsdsocket.h b/include/bsdsocket.h
new file mode 100755 (executable)
index 0000000..cacdcb0
--- /dev/null
@@ -0,0 +1,178 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * bsdsocket.library emulation
+  *
+  * Copyright 1997,98 Mathias Ortmann
+  *
+  */
+
+//#define TRACING_ENABLED
+
+#ifdef TRACING_ENABLED
+#define TRACE(x) do { write_log x; } while(0)
+#else
+#define TRACE(x)
+#endif
+
+extern int init_socket_layer (void);
+extern void deinit_socket_layer (void);
+
+/* inital size of per-process descriptor table (currently fixed) */
+#define DEFAULT_DTABLE_SIZE 64
+
+#define SCRATCHBUFSIZE 128
+
+#define MAXPENDINGASYNC 512
+
+#define MAXADDRLEN 256
+
+/* allocated and maintained on a per-task basis */
+struct socketbase {
+    struct socketbase *next;
+    struct socketbase *nextsig;        /* queue for tasks to signal */
+
+    int dosignal;              /* signal flag */
+    uae_u32 ownertask;         /* task that opened the library */
+    int signal;                        /* signal allocated for that task */
+    int sb_errno, sb_herrno;   /* errno and herrno variables */
+    uae_u32 errnoptr, herrnoptr;       /* pointers */
+    uae_u32 errnosize, herrnosize;     /* pinter sizes */
+    int dtablesize;            /* current descriptor/flag etc. table size */
+    int *dtable;               /* socket descriptor table */
+    int *ftable;               /* socket flags */
+    int resultval;
+    uae_u32 hostent;           /* pointer to the current hostent structure (Amiga mem) */
+    uae_u32 hostentsize;
+    uae_u32 protoent;          /* pointer to the current protoent structure (Amiga mem) */
+    uae_u32 protoentsize;
+    uae_u32 servent;           /* pointer to the current servent structure (Amiga mem) */
+    uae_u32 serventsize;
+    uae_u32 sigstosend;
+    uae_u32 eventsigs;         /* EVENT sigmask */
+    uae_u32 eintrsigs;         /* EINTR sigmask */
+    int eintr;                 /* interrupted by eintrsigs? */
+    int eventindex;            /* current socket looked at by GetSocketEvents() to prevent starvation */
+
+    /* host-specific fields below */
+#ifdef _WIN32
+    unsigned int sockAbort;    /* for aborting WinSock2 select() (damn Microsoft) */
+    unsigned int sockAsync;    /* for aborting WSBAsyncSelect() in window message handler */
+    int needAbort;             /* abort flag */
+    void *hAsyncTask;          /* async task handle */
+    void *hEvent;              /* thread event handle */
+    unsigned int *mtable;      /* window messages allocated for asynchronous event notification */
+#endif
+} *socketbases;
+
+
+#define LIBRARY_SIZEOF 36
+
+struct UAEBSDBase {
+    char dummy[LIBRARY_SIZEOF];
+    struct socketbase *sb;
+    char scratchbuf[SCRATCHBUFSIZE];
+};
+
+/* socket flags */
+/* socket events to report */
+#define REP_ACCEPT      0x01   /* there is a connection to accept() */
+#define REP_CONNECT     0x02   /* connect() completed */
+#define REP_OOB                 0x04   /* socket has out-of-band data */
+#define REP_READ        0x08   /* socket is readable */
+#define REP_WRITE       0x10   /* socket is writeable */
+#define REP_ERROR       0x20   /* asynchronous error on socket */
+#define REP_CLOSE       0x40   /* connection closed (graceful or not) */
+#define REP_ALL      0x7f
+/* socket events that occurred */
+#define SET_ACCEPT      0x0100 /* there is a connection to accept() */
+#define SET_CONNECT     0x0200 /* connect() completed */
+#define SET_OOB                 0x0400 /* socket has out-of-band data */
+#define SET_READ        0x0800 /* socket is readable */
+#define SET_WRITE       0x1000 /* socket is writeable */
+#define SET_ERROR       0x2000 /* asynchronous error on socket */
+#define SET_CLOSE       0x4000 /* connection closed (graceful or not) */
+#define SET_ALL      0x7f00
+/* socket properties */
+#define SF_BLOCKING 0x80000000
+#define SF_BLOCKINGINPROGRESS 0x40000000
+
+struct socketbase *get_socketbase (void);
+
+extern uae_u32 addstr (uae_u32 *, char *);
+extern uae_u32 addmem (uae_u32 *, char *, int len);
+
+extern char *strncpyah (char *, uae_u32, int);
+extern char *strcpyah (char *, uae_u32);
+extern uae_u32 strcpyha (uae_u32, char *);
+extern uae_u32 strncpyha (uae_u32, char *, int);
+
+#define SB struct socketbase *sb
+
+extern void seterrno (SB, int);
+extern void setherrno (SB, int);
+
+extern void sockmsg (unsigned int, unsigned long, unsigned long);
+extern void sockabort (SB);
+
+extern void addtosigqueue (SB, int);
+extern void removefromsigqueue (SB);
+extern void sigsockettasks (void);
+extern void locksigqueue (void);
+extern void unlocksigqueue (void);
+
+extern BOOL checksd(SB, int sd);
+extern void setsd(SB, int ,int );
+extern int getsd (SB, int);
+extern int getsock (SB, int);
+extern void releasesock (SB, int);
+
+extern void waitsig (SB);
+extern void cancelsig (SB);
+
+extern int host_sbinit (SB);
+extern void host_sbcleanup (SB);
+extern void host_sbreset (void);
+extern void host_closesocketquick (int);
+
+extern int host_dup2socket (SB, int, int);
+extern int host_socket (SB, int, int, int);
+extern uae_u32 host_bind (SB, uae_u32, uae_u32, uae_u32);
+extern uae_u32 host_listen (SB, uae_u32, uae_u32);
+extern void host_accept (SB, uae_u32, uae_u32, uae_u32);
+extern void host_sendto (SB, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32);
+extern void host_recvfrom (SB, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32);
+extern uae_u32 host_shutdown (SB, uae_u32, uae_u32);
+extern void host_setsockopt (SB, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32);
+extern uae_u32 host_getsockopt (SB, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32);
+extern uae_u32 host_getsockname (SB, uae_u32, uae_u32, uae_u32);
+extern uae_u32 host_getpeername (SB, uae_u32, uae_u32, uae_u32);
+extern uae_u32 host_IoctlSocket (SB, uae_u32, uae_u32, uae_u32);
+extern uae_u32 host_shutdown (SB, uae_u32, uae_u32);
+extern int host_CloseSocket (SB, int);
+extern void host_connect (SB, uae_u32, uae_u32, uae_u32);
+extern void host_WaitSelect (SB, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32);
+extern uae_u32 host_SetSocketSignals (void);
+extern uae_u32 host_getdtablesize (void);
+extern uae_u32 host_ObtainSocket (void);
+extern uae_u32 host_ReleaseSocket (void);
+extern uae_u32 host_ReleaseCopyOfSocket (void);
+extern uae_u32 host_Inet_NtoA (SB, uae_u32);
+extern uae_u32 host_inet_addr (uae_u32);
+extern uae_u32 host_Inet_LnaOf (void);
+extern uae_u32 host_Inet_NetOf (void);
+extern uae_u32 host_Inet_MakeAddr (void);
+extern uae_u32 host_inet_network (void);
+extern void host_gethostbynameaddr (SB, uae_u32, uae_u32, long);
+extern uae_u32 host_getnetbyname (void);
+extern uae_u32 host_getnetbyaddr (void);
+extern void host_getservbynameport (SB, uae_u32, uae_u32, uae_u32);
+extern void host_getprotobyname (SB, uae_u32);
+extern uae_u32 host_getprotobynumber (void);
+extern uae_u32 host_vsyslog (void);
+extern uae_u32 host_Dup2Socket (void);
+extern uae_u32 host_gethostname (uae_u32, uae_u32);
+
+
+extern void bsdlib_install (void);
+extern void bsdlib_reset (void);
diff --git a/include/catweasel.h b/include/catweasel.h
new file mode 100755 (executable)
index 0000000..848221e
--- /dev/null
@@ -0,0 +1,85 @@
+
+#ifdef CATWEASEL
+
+extern struct catweasel_contr cwc;
+extern int catweasel_read_keyboard (uae_u8 *keycode);
+extern int catweasel_init (void);
+extern void catweasel_free (void);
+extern uae_u32 catweasel_do_bget (uaecptr addr);
+extern void catweasel_do_bput (uaecptr addr, uae_u32 b);
+extern int catweasel_read_joystick (uae_u8 *dir, uae_u8 *buttons);
+extern void catweasel_hsync (void);
+
+typedef struct catweasel_drive {
+    struct catweasel_contr *contr; /* The controller this drive belongs to */
+    int number;                    /* Drive number: 0 or 1 */
+    int type;                      /* 0 = not present, 1 = 3.5" */
+    int track;                     /* current r/w head position (0..79) */
+    int diskindrive;               /* 0 = no disk, 1 = disk in drive */
+    int wprot;                     /* 0 = not, 1 = write protected */
+    unsigned char sel;
+    unsigned char mot;
+} catweasel_drive;
+
+typedef struct catweasel_contr {
+    int type;                      /* see CATWEASEL_TYPE_* defines below */
+    int iobase;                    /* 0 = not present (factory default is 0x320) */
+    void (*msdelay)(int ms);       /* microseconds delay routine, provided by host program */
+    catweasel_drive drives[2];     /* at most two drives on each controller */
+    int control_register;          /* contents of control register */
+    unsigned char crm_sel0;        /* bit masks for the control / status register */
+    unsigned char crm_sel1;
+    unsigned char crm_mot0;
+    unsigned char crm_mot1;
+    unsigned char crm_dir;
+    unsigned char crm_step;
+    unsigned char srm_trk0;
+    unsigned char srm_dchg;
+    unsigned char srm_writ;
+    unsigned char srm_dskready;
+    int io_sr;                     /* IO port of control / status register */
+    int io_mem;                    /* IO port of memory register */
+} catweasel_contr;
+
+#define CATWEASEL_TYPE_NONE  -1
+#define CATWEASEL_TYPE_MK1    1
+#define CATWEASEL_TYPE_MK3    3
+
+/* Initialize a Catweasel controller; c->iobase and c->msdelay must have
+   been initialized -- msdelay might be used */
+void catweasel_init_controller(catweasel_contr *c);
+
+/* Reset the controller */
+void catweasel_free_controller(catweasel_contr *c);
+
+/* Set current drive select mask */
+void catweasel_select(catweasel_contr *c, int dr0, int dr1);
+
+/* Start/stop the drive's motor */
+void catweasel_set_motor(catweasel_drive *d, int on);
+
+/* Move the r/w head */
+int catweasel_step(catweasel_drive *d, int dir);
+
+/* Check for a disk change and update d->diskindrive
+   -- msdelay might be used. Returns 1 == disk has been changed */
+int catweasel_disk_changed(catweasel_drive *d);
+
+/* Check if disk in selected drive is write protected. */
+int catweasel_write_protected(catweasel_drive *d);
+
+/* Read data -- msdelay will be used */
+int catweasel_read(catweasel_drive *d, int side, int clock, int time);
+
+/* Write data -- msdelay will be used. If time == -1, the write will
+   be started at the index pulse and stopped at the next index pulse,
+   or earlier if the Catweasel RAM contains a 128 end byte.  The
+   function returns after the write has finished. */
+int catweasel_write(catweasel_drive *d, int side, int clock, int time);
+
+int catweasel_fillmfm (catweasel_drive *d, uae_u16 *mfm, int side, int clock, int rawmode);
+
+int catweasel_diskready(catweasel_drive *d);
+int catweasel_track0(catweasel_drive *d);
+
+#endif
\ No newline at end of file
diff --git a/include/cia.h b/include/cia.h
new file mode 100755 (executable)
index 0000000..dbf9237
--- /dev/null
@@ -0,0 +1,29 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * CIA chip support
+  *
+  * (c) 1995 Bernd Schmidt
+  */
+
+extern void CIA_reset (void);
+extern void CIA_vsync_handler (void);
+extern void CIA_hsync_handler (void);
+extern void CIA_handler (void);
+
+extern void diskindex_handler (void);
+
+extern void dumpcia (void);
+extern void rethink_cias (void);
+extern unsigned int ciaaicr,ciaaimask,ciabicr,ciabimask;
+extern unsigned int ciaacra,ciaacrb,ciabcra,ciabcrb;
+extern unsigned int ciabpra;
+extern unsigned long ciaata,ciaatb,ciabta,ciabtb;
+extern unsigned long ciaatod,ciabtod,ciaatol,ciabtol,ciaaalarm,ciabalarm;
+extern int ciaatlatch,ciabtlatch;
+
+extern int parallel_direct_write_data (uae_u8, uae_u8);
+extern int parallel_direct_read_data (uae_u8*);
+extern int parallel_direct_write_status (uae_u8, uae_u8);
+extern int parallel_direct_read_status (uae_u8*);
+
diff --git a/include/commpipe.h b/include/commpipe.h
new file mode 100755 (executable)
index 0000000..7c27d31
--- /dev/null
@@ -0,0 +1,157 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Communication between threads
+  *
+  * Copyright 1997, 2001 Bernd Schmidt
+  */
+
+typedef union {
+    int i;
+    uae_u32 u32;
+    void *pv;
+} uae_pt;
+
+/* These currently require the maximum size to be known at initialization
+ * time, but it wouldn't be hard to use a "normal" pipe as an extension once the
+ * user-level one gets full.
+ * We queue up to chunks pieces of data before signalling the other thread to
+ * avoid overhead. */
+
+typedef struct {
+    uae_sem_t lock;
+    uae_sem_t reader_wait;
+    uae_sem_t writer_wait;
+    uae_pt *data;
+    int size, chunks;
+    volatile int rdp, wrp;
+    volatile int writer_waiting;
+    volatile int reader_waiting;
+} smp_comm_pipe;
+
+static __inline__ void init_comm_pipe (smp_comm_pipe *p, int size, int chunks)
+{
+    memset (p, 0, sizeof (*p));
+    p->data = (uae_pt *)malloc (size*sizeof (uae_pt));
+    p->size = size;
+    p->chunks = chunks;
+    p->rdp = p->wrp = 0;
+    p->reader_waiting = 0;
+    p->writer_waiting = 0;
+    uae_sem_init (&p->lock, 0, 1);
+    uae_sem_init (&p->reader_wait, 0, 0);
+    uae_sem_init (&p->writer_wait, 0, 0);
+}
+
+static __inline__ void destroy_comm_pipe (smp_comm_pipe *p)
+{
+    uae_sem_destroy (&p->lock);
+    uae_sem_destroy (&p->reader_wait);
+    uae_sem_destroy (&p->writer_wait);
+}
+
+static __inline__ void maybe_wake_reader (smp_comm_pipe *p, int no_buffer)
+{
+    if (p->reader_waiting
+       && (no_buffer || ((p->wrp - p->rdp + p->size) % p->size) >= p->chunks))
+    {
+       p->reader_waiting = 0;
+       uae_sem_post (&p->reader_wait);
+    }
+}
+
+static __inline__ void write_comm_pipe_pt (smp_comm_pipe *p, uae_pt data, int no_buffer)
+{
+    int nxwrp = (p->wrp + 1) % p->size;
+
+    if (p->reader_waiting) {
+       /* No need to do all the locking */
+       p->data[p->wrp] = data;
+       p->wrp = nxwrp;
+       maybe_wake_reader (p, no_buffer);
+       return;
+    }
+    
+    uae_sem_wait (&p->lock);
+    if (nxwrp == p->rdp) {
+       /* Pipe full! */
+       p->writer_waiting = 1;
+       uae_sem_post (&p->lock);
+       /* Note that the reader could get in between here and do a
+        * sem_post on writer_wait before we wait on it. That's harmless.
+        * There's a similar case in read_comm_pipe_int_blocking. */
+       uae_sem_wait (&p->writer_wait);
+       uae_sem_wait (&p->lock);
+    }
+    p->data[p->wrp] = data;
+    p->wrp = nxwrp;
+    maybe_wake_reader (p, no_buffer);
+    uae_sem_post (&p->lock);
+}
+
+static __inline__ uae_pt read_comm_pipe_pt_blocking (smp_comm_pipe *p)
+{
+    uae_pt data;
+
+    uae_sem_wait (&p->lock);
+    if (p->rdp == p->wrp) {
+       p->reader_waiting = 1;
+       uae_sem_post (&p->lock);
+       uae_sem_wait (&p->reader_wait);
+       uae_sem_wait (&p->lock);
+    }
+    data = p->data[p->rdp];
+    p->rdp = (p->rdp + 1) % p->size;
+
+    /* We ignore chunks here. If this is a problem, make the size bigger in the init call. */
+    if (p->writer_waiting) {
+       write_log ("read_comm_pipe_pt_blocking!\n");
+       p->writer_waiting = 0;
+       uae_sem_post (&p->writer_wait);
+    }
+    uae_sem_post (&p->lock);
+    return data;
+}
+
+static __inline__ int comm_pipe_has_data (smp_comm_pipe *p)
+{
+    return p->rdp != p->wrp;
+}
+
+static __inline__ int read_comm_pipe_int_blocking (smp_comm_pipe *p)
+{
+    uae_pt foo = read_comm_pipe_pt_blocking (p);
+    return foo.i;
+}
+static __inline__ uae_u32 read_comm_pipe_u32_blocking (smp_comm_pipe *p)
+{
+    uae_pt foo = read_comm_pipe_pt_blocking (p);
+    return foo.u32;
+}
+
+static __inline__ void *read_comm_pipe_pvoid_blocking (smp_comm_pipe *p)
+{
+    uae_pt foo = read_comm_pipe_pt_blocking (p);
+    return foo.pv;
+}
+
+static __inline__ void write_comm_pipe_int (smp_comm_pipe *p, int data, int no_buffer)
+{
+    uae_pt foo;
+    foo.i = data;
+    write_comm_pipe_pt (p, foo, no_buffer);
+}
+
+static __inline__ void write_comm_pipe_u32 (smp_comm_pipe *p, int data, int no_buffer)
+{
+    uae_pt foo;
+    foo.u32 = data;
+    write_comm_pipe_pt (p, foo, no_buffer);
+}
+
+static __inline__ void write_comm_pipe_pvoid (smp_comm_pipe *p, void *data, int no_buffer)
+{
+    uae_pt foo;
+    foo.pv = data;
+    write_comm_pipe_pt (p, foo, no_buffer);
+}
diff --git a/include/compemu.h b/include/compemu.h
new file mode 100755 (executable)
index 0000000..a8b2a75
--- /dev/null
@@ -0,0 +1,527 @@
+#define USE_OPTIMIZER 0
+#define USE_LOW_OPTIMIZER 0
+#define USE_ALIAS 1
+#define USE_F_ALIAS 1
+#define USE_SOFT_FLUSH 1
+#define USE_OFFSET 1
+#define COMP_DEBUG 1
+
+#if COMP_DEBUG
+#define Dif(x) if (x)
+#else
+#define Dif(x) if (0)
+#endif
+
+#define SCALE 2
+#define MAXCYCLES (1000 * CYCLE_UNIT)
+#define MAXREGOPT 65536
+
+#define BYTES_PER_INST 10240  /* paranoid ;-) */
+#define LONGEST_68K_INST 16 /* The number of bytes the longest possible
+                              68k instruction takes */
+#define MAX_CHECKSUM_LEN 2048 /* The maximum size we calculate checksums
+                                for. Anything larger will be flushed
+                                unconditionally even with SOFT_FLUSH */
+#define MAX_HOLD_BI 3  /* One for the current block, and up to two
+                         for jump targets */
+
+#define INDIVIDUAL_INST 0
+#define FLAG_C    0x0010
+#define FLAG_V    0x0008
+#define FLAG_Z    0x0004
+#define FLAG_N    0x0002
+#define FLAG_X    0x0001
+#define FLAG_CZNV (FLAG_C | FLAG_Z | FLAG_N | FLAG_V)
+#define FLAG_ZNV  (FLAG_Z | FLAG_N | FLAG_V)
+
+#define KILLTHERAT 1  /* Set to 1 to avoid some partial_rat_stalls */
+
+/* Whether to preserve registers across calls to JIT compiled routines */
+#if defined X86_ASSEMBLY
+#define USE_PUSH_POP 0
+#else
+#define USE_PUSH_POP 1
+#endif
+
+#define N_REGS 8  /* really only 7, but they are numbered 0,1,2,3,5,6,7 */
+#define N_FREGS 6 /* That leaves us two positions on the stack to play with */
+
+/* Functions exposed to newcpu, or to what was moved from newcpu.c to
+ * compemu_support.c */
+extern void init_comp(void);
+extern void flush(int save_regs);
+extern void small_flush(int save_regs);
+extern void set_target(uae_u8* t);
+extern uae_u8* get_target(void);
+extern void freescratch(void);
+extern void build_comp(void);
+extern void set_cache_state(int enabled);
+extern int get_cache_state(void);
+extern uae_u32 get_jitted_size(void);
+#ifdef JIT
+extern void flush_icache(int n);
+#endif
+extern void alloc_cache(void);
+extern void compile_block(cpu_history* pc_hist, int blocklen, int totcyles);
+extern void lopt_emit_all(void);
+extern int check_for_cache_miss(void);
+
+
+#define scaled_cycles(x) (currprefs.m68k_speed==-1?(((x)/SCALE)?(((x)/SCALE<MAXCYCLES?((x)/SCALE):MAXCYCLES)):1):(x))
+
+
+extern uae_u32 needed_flags;
+extern cacheline cache_tags[];
+extern uae_u8* comp_pc_p;
+extern void* pushall_call_handler;
+
+#define VREGS 32
+#define VFREGS 16
+
+#define INMEM 1
+#define CLEAN 2
+#define DIRTY 3
+#define UNDEF 4
+#define ISCONST 5
+
+typedef struct {
+  uae_u32* mem;
+  uae_u32 val;
+  uae_u8 is_swapped;
+  uae_u8 status;
+  uae_u8 realreg;
+  uae_u8 realind; /* The index in the holds[] array */
+  uae_u8 needflush;
+  uae_u8 validsize;
+  uae_u8 dirtysize;
+  uae_u8 dummy;
+} reg_status;
+
+typedef struct {
+  uae_u32* mem;
+  double val;
+  uae_u8 status;
+  uae_u8 realreg;
+  uae_u8 realind;  
+  uae_u8 needflush;
+} freg_status;
+
+typedef struct {
+    uae_u8 use_flags;
+    uae_u8 set_flags;
+    uae_u8 is_jump;
+    uae_u8 is_addx;
+    uae_u8 is_const_jump;
+} op_properties;
+extern op_properties prop[65536];
+
+static __inline__ int end_block(uae_u16 opcode)
+{
+    return prop[opcode].is_jump ||
+       (prop[opcode].is_const_jump && !currprefs.comp_constjump);
+}
+
+#define PC_P 16
+#define FLAGX 17
+#define FLAGTMP 18
+#define NEXT_HANDLER 19
+#define S1 20
+#define S2 21
+#define S3 22
+#define S4 23
+#define S5 24
+#define S6 25
+#define S7 26
+#define S8 27
+#define S9 28
+#define S10 29
+#define S11 30
+#define S12 31
+
+#define FP_RESULT 8
+#define FS1 9
+#define FS2 10
+#define FS3 11
+
+typedef struct {
+  uae_u32 touched;
+  uae_s8 holds[VREGS];
+  uae_u8 nholds;
+  uae_u8 canbyte;
+  uae_u8 canword;
+  uae_u8 locked;
+} n_status;
+
+typedef struct {
+    uae_s8 holds;
+    uae_u8 validsize;
+    uae_u8 dirtysize;
+} n_smallstatus;
+
+typedef struct {
+  uae_u32 touched;
+  uae_s8 holds[VFREGS];
+  uae_u8 nholds;
+  uae_u8 locked;
+} fn_status;
+
+/* For flag handling */
+#define NADA 1
+#define TRASH 2
+#define VALID 3
+
+/* needflush values */
+#define NF_SCRATCH   0
+#define NF_TOMEM     1
+#define NF_HANDLER   2
+
+typedef struct {
+    /* Integer part */
+    reg_status state[VREGS];
+    n_status   nat[N_REGS];
+    uae_u32 flags_on_stack;
+    uae_u32 flags_in_flags;
+    uae_u32 flags_are_important;
+    /* FPU part */
+    freg_status fate[VFREGS];
+    fn_status   fat[N_FREGS];
+
+    /* x86 FPU part */
+    uae_s8 spos[N_FREGS];
+    uae_s8 onstack[6];
+    uae_s8 tos;
+} bigstate;
+
+typedef struct {
+    /* Integer part */
+    n_smallstatus  nat[N_REGS];
+} smallstate;
+
+extern bigstate live;
+extern int touchcnt;
+
+
+#define IMM uae_u32
+#define R1  uae_u32
+#define R2  uae_u32
+#define R4  uae_u32
+#define W1  uae_u32
+#define W2  uae_u32
+#define W4  uae_u32
+#define RW1 uae_u32
+#define RW2 uae_u32
+#define RW4 uae_u32
+#define MEMR uae_u32
+#define MEMW uae_u32
+#define MEMRW uae_u32
+
+#define FW   uae_u32
+#define FR   uae_u32
+#define FRW  uae_u32
+
+#define MIDFUNC(nargs,func,args) void func args
+#define MENDFUNC(nargs,func,args) 
+#define COMPCALL(func) func
+
+#define LOWFUNC(flags,mem,nargs,func,args) static __inline__ void func args
+#define LENDFUNC(flags,mem,nargs,func,args) 
+
+#if USE_OPTIMIZER
+#define REGALLOC_O 2
+#define PEEPHOLE_O 3 /* Has to be >= REGALLOC */
+#define DECLARE(func) extern void func; extern void do_##func
+#else
+#define REGALLOC_O 2000000
+#define PEEPHOLE_O 2000000
+#define DECLARE(func) extern void func
+#endif
+
+
+/* What we expose to the outside */
+DECLARE(bt_l_ri(R4 r, IMM i));
+DECLARE(bt_l_rr(R4 r, R4 b));
+DECLARE(btc_l_ri(RW4 r, IMM i));
+DECLARE(btc_l_rr(RW4 r, R4 b));
+DECLARE(bts_l_ri(RW4 r, IMM i));
+DECLARE(bts_l_rr(RW4 r, R4 b));
+DECLARE(btr_l_ri(RW4 r, IMM i));
+DECLARE(btr_l_rr(RW4 r, R4 b));
+DECLARE(mov_l_rm(W4 d, IMM s));
+DECLARE(call_r(R4 r));
+DECLARE(sub_l_mi(IMM d, IMM s));
+DECLARE(mov_l_mi(IMM d, IMM s));
+DECLARE(mov_w_mi(IMM d, IMM s));
+DECLARE(mov_b_mi(IMM d, IMM s));
+DECLARE(rol_b_ri(RW1 r, IMM i));
+DECLARE(rol_w_ri(RW2 r, IMM i));
+DECLARE(rol_l_ri(RW4 r, IMM i));
+DECLARE(rol_l_rr(RW4 d, R1 r));
+DECLARE(rol_w_rr(RW2 d, R1 r));
+DECLARE(rol_b_rr(RW1 d, R1 r));
+DECLARE(shll_l_rr(RW4 d, R1 r));
+DECLARE(shll_w_rr(RW2 d, R1 r));
+DECLARE(shll_b_rr(RW1 d, R1 r));
+DECLARE(ror_b_ri(R1 r, IMM i));
+DECLARE(ror_w_ri(R2 r, IMM i));
+DECLARE(ror_l_ri(R4 r, IMM i));
+DECLARE(ror_l_rr(R4 d, R1 r));
+DECLARE(ror_w_rr(R2 d, R1 r));
+DECLARE(ror_b_rr(R1 d, R1 r));
+DECLARE(shrl_l_rr(RW4 d, R1 r));
+DECLARE(shrl_w_rr(RW2 d, R1 r));
+DECLARE(shrl_b_rr(RW1 d, R1 r));
+DECLARE(shra_l_rr(RW4 d, R1 r));
+DECLARE(shra_w_rr(RW2 d, R1 r));
+DECLARE(shra_b_rr(RW1 d, R1 r));
+DECLARE(shll_l_ri(RW4 r, IMM i));
+DECLARE(shll_w_ri(RW2 r, IMM i));
+DECLARE(shll_b_ri(RW1 r, IMM i));
+DECLARE(shrl_l_ri(RW4 r, IMM i));
+DECLARE(shrl_w_ri(RW2 r, IMM i));
+DECLARE(shrl_b_ri(RW1 r, IMM i));
+DECLARE(shra_l_ri(RW4 r, IMM i));
+DECLARE(shra_w_ri(RW2 r, IMM i));
+DECLARE(shra_b_ri(RW1 r, IMM i));
+DECLARE(setcc(W1 d, IMM cc));
+DECLARE(setcc_m(IMM d, IMM cc));
+DECLARE(cmov_l_rr(RW4 d, R4 s, IMM cc));
+DECLARE(cmov_l_rm(RW4 d, IMM s, IMM cc));
+DECLARE(bsf_l_rr(W4 d, R4 s));
+DECLARE(pop_m(IMM d));
+DECLARE(push_m(IMM d));
+DECLARE(pop_l(W4 d));
+DECLARE(push_l_i(IMM i));
+DECLARE(push_l(R4 s));
+DECLARE(clear_16(RW4 r));
+DECLARE(clear_8(RW4 r));
+DECLARE(sign_extend_16_rr(W4 d, R2 s));
+DECLARE(sign_extend_8_rr(W4 d, R1 s));
+DECLARE(zero_extend_16_rr(W4 d, R2 s));
+DECLARE(zero_extend_8_rr(W4 d, R1 s));
+DECLARE(imul_64_32(RW4 d, RW4 s));
+DECLARE(mul_64_32(RW4 d, RW4 s));
+DECLARE(imul_32_32(RW4 d, R4 s));
+DECLARE(mul_32_32(RW4 d, R4 s));
+DECLARE(mov_b_rr(W1 d, R1 s));
+DECLARE(mov_w_rr(W2 d, R2 s));
+DECLARE(mov_l_rrm_indexed(W4 d,R4 baser, R4 index, IMM factor));
+DECLARE(mov_w_rrm_indexed(W2 d, R4 baser, R4 index, IMM factor));
+DECLARE(mov_b_rrm_indexed(W1 d, R4 baser, R4 index, IMM factor));
+DECLARE(mov_l_mrr_indexed(R4 baser, R4 index, IMM factor, R4 s));
+DECLARE(mov_w_mrr_indexed(R4 baser, R4 index, IMM factor, R2 s));
+DECLARE(mov_b_mrr_indexed(R4 baser, R4 index, IMM factor, R1 s));
+DECLARE(mov_l_bmrr_indexed(IMM base, R4 baser, R4 index, IMM factor, R4 s));
+DECLARE(mov_w_bmrr_indexed(IMM base, R4 baser, R4 index, IMM factor, R2 s));
+DECLARE(mov_b_bmrr_indexed(IMM base, R4 baser, R4 index, IMM factor, R1 s));
+DECLARE(mov_l_brrm_indexed(W4 d, IMM base, R4 baser, R4 index, IMM factor));
+DECLARE(mov_w_brrm_indexed(W2 d, IMM base, R4 baser, R4 index, IMM factor));
+DECLARE(mov_b_brrm_indexed(W1 d, IMM base, R4 baser, R4 index, IMM factor));
+DECLARE(mov_l_rm_indexed(W4 d, IMM base, R4 index, IMM factor));
+DECLARE(mov_l_rR(W4 d, R4 s, IMM offset));
+DECLARE(mov_w_rR(W2 d, R4 s, IMM offset));
+DECLARE(mov_b_rR(W1 d, R4 s, IMM offset));
+DECLARE(mov_l_brR(W4 d, R4 s, IMM offset));
+DECLARE(mov_w_brR(W2 d, R4 s, IMM offset));
+DECLARE(mov_b_brR(W1 d, R4 s, IMM offset));
+DECLARE(mov_l_Ri(R4 d, IMM i, IMM offset));
+DECLARE(mov_w_Ri(R4 d, IMM i, IMM offset));
+DECLARE(mov_b_Ri(R4 d, IMM i, IMM offset));
+DECLARE(mov_l_Rr(R4 d, R4 s, IMM offset));
+DECLARE(mov_w_Rr(R4 d, R2 s, IMM offset));
+DECLARE(mov_b_Rr(R4 d, R1 s, IMM offset));
+DECLARE(lea_l_brr(W4 d, R4 s, IMM offset));
+DECLARE(lea_l_brr_indexed(W4 d, R4 s, R4 index, IMM factor, IMM offset));
+DECLARE(lea_l_rr_indexed(W4 d, R4 s, R4 index, IMM factor));
+DECLARE(mov_l_bRr(R4 d, R4 s, IMM offset));
+DECLARE(mov_w_bRr(R4 d, R2 s, IMM offset));
+DECLARE(mov_b_bRr(R4 d, R1 s, IMM offset));
+DECLARE(bswap_32(RW4 r));
+DECLARE(bswap_16(RW2 r));
+DECLARE(mov_l_rr(W4 d, R4 s));
+DECLARE(mov_l_mr(IMM d, R4 s));
+DECLARE(mov_w_mr(IMM d, R2 s));
+DECLARE(mov_w_rm(W2 d, IMM s));
+DECLARE(mov_b_mr(IMM d, R1 s));
+DECLARE(mov_b_rm(W1 d, IMM s));
+DECLARE(mov_l_ri(W4 d, IMM s));
+DECLARE(mov_w_ri(W2 d, IMM s));
+DECLARE(mov_b_ri(W1 d, IMM s));
+DECLARE(add_l_mi(IMM d, IMM s) );
+DECLARE(add_w_mi(IMM d, IMM s) );
+DECLARE(add_b_mi(IMM d, IMM s) );
+DECLARE(test_l_ri(R4 d, IMM i));
+DECLARE(test_l_rr(R4 d, R4 s));
+DECLARE(test_w_rr(R2 d, R2 s));
+DECLARE(test_b_rr(R1 d, R1 s));
+DECLARE(and_l_ri(RW4 d, IMM i));
+DECLARE(and_l(RW4 d, R4 s));
+DECLARE(and_w(RW2 d, R2 s));
+DECLARE(and_b(RW1 d, R1 s));
+DECLARE(or_l_ri(RW4 d, IMM i));
+DECLARE(or_l(RW4 d, R4 s));
+DECLARE(or_w(RW2 d, R2 s));
+DECLARE(or_b(RW1 d, R1 s));
+DECLARE(adc_l(RW4 d, R4 s));
+DECLARE(adc_w(RW2 d, R2 s));
+DECLARE(adc_b(RW1 d, R1 s));
+DECLARE(add_l(RW4 d, R4 s));
+DECLARE(add_w(RW2 d, R2 s));
+DECLARE(add_b(RW1 d, R1 s));
+DECLARE(sub_l_ri(RW4 d, IMM i));
+DECLARE(sub_w_ri(RW2 d, IMM i));
+DECLARE(sub_b_ri(RW1 d, IMM i));
+DECLARE(add_l_ri(RW4 d, IMM i));
+DECLARE(add_w_ri(RW2 d, IMM i));
+DECLARE(add_b_ri(RW1 d, IMM i));
+DECLARE(sbb_l(RW4 d, R4 s));
+DECLARE(sbb_w(RW2 d, R2 s));
+DECLARE(sbb_b(RW1 d, R1 s));
+DECLARE(sub_l(RW4 d, R4 s));
+DECLARE(sub_w(RW2 d, R2 s));
+DECLARE(sub_b(RW1 d, R1 s));
+DECLARE(cmp_l(R4 d, R4 s));
+DECLARE(cmp_l_ri(R4 r, IMM i));
+DECLARE(cmp_w(R2 d, R2 s));
+DECLARE(cmp_b(R1 d, R1 s));
+DECLARE(xor_l(RW4 d, R4 s));
+DECLARE(xor_w(RW2 d, R2 s));
+DECLARE(xor_b(RW1 d, R1 s));
+DECLARE(live_flags(void));
+DECLARE(dont_care_flags(void));
+DECLARE(duplicate_carry(void));
+DECLARE(restore_carry(void));
+DECLARE(start_needflags(void));
+DECLARE(end_needflags(void));
+DECLARE(make_flags_live(void));
+DECLARE(call_r_11(R4 r, W4 out1, R4 in1, IMM osize, IMM isize));
+DECLARE(call_r_02(R4 r, R4 in1, R4 in2, IMM isize1, IMM isize2));
+DECLARE(readmem_new(R4 address, W4 dest, IMM offset, IMM size, W4 tmp));
+DECLARE(writemem_new(R4 address, R4 source, IMM offset, IMM size, W4 tmp));
+DECLARE(forget_about(W4 r));
+DECLARE(nop(void));
+
+DECLARE(f_forget_about(FW r));
+DECLARE(fmov_pi(FW r));
+DECLARE(fmov_log10_2(FW r));
+DECLARE(fmov_log2_e(FW r));
+DECLARE(fmov_loge_2(FW r));
+DECLARE(fmov_1(FW r));
+DECLARE(fmov_0(FW r));
+DECLARE(fmov_rm(FW r, MEMR m));
+DECLARE(fmovi_rm(FW r, MEMR m));
+DECLARE(fmovi_mr(MEMW m, FR r));
+DECLARE(fmovs_rm(FW r, MEMR m));
+DECLARE(fmovs_mr(MEMW m, FR r));
+DECLARE(fmov_mr(MEMW m, FR r));
+DECLARE(fmov_ext_mr(MEMW m, FR r));
+DECLARE(fmov_ext_rm(FW r, MEMR m));
+DECLARE(fmov_rr(FW d, FR s));
+DECLARE(fldcw_m_indexed(R4 index, IMM base));
+DECLARE(ftst_r(FR r));
+DECLARE(dont_care_fflags(void));
+DECLARE(fsqrt_rr(FW d, FR s));
+DECLARE(fabs_rr(FW d, FR s));
+DECLARE(frndint_rr(FW d, FR s));
+DECLARE(fsin_rr(FW d, FR s));
+DECLARE(fcos_rr(FW d, FR s));
+DECLARE(ftwotox_rr(FW d, FR s));
+DECLARE(fetox_rr(FW d, FR s));
+DECLARE(flog2_rr(FW d, FR s));
+DECLARE(fneg_rr(FW d, FR s));
+DECLARE(fadd_rr(FRW d, FR s));
+DECLARE(fsub_rr(FRW d, FR s));
+DECLARE(fmul_rr(FRW d, FR s));
+DECLARE(frem_rr(FRW d, FR s));
+DECLARE(frem1_rr(FRW d, FR s));
+DECLARE(fdiv_rr(FRW d, FR s));
+DECLARE(fcmp_rr(FR d, FR s));
+DECLARE(fflags_into_flags(W2 tmp));
+
+extern int failure;
+#define FAIL(x) do { failure|=x; } while (0)
+
+/* Convenience functions exposed to gencomp */
+extern uae_u32 m68k_pc_offset;
+extern void readbyte(int address, int dest, int tmp);
+extern void readword(int address, int dest, int tmp);
+extern void readlong(int address, int dest, int tmp);
+extern void writebyte(int address, int source, int tmp);
+extern void writeword(int address, int source, int tmp);
+extern void writelong(int address, int source, int tmp);
+extern void writeword_clobber(int address, int source, int tmp);
+extern void writelong_clobber(int address, int source, int tmp);
+extern void get_n_addr(int address, int dest, int tmp);
+extern void get_n_addr_jmp(int address, int dest, int tmp);
+extern void calc_disp_ea_020(int base, uae_u32 dp, int target, int tmp);
+extern int kill_rodent(int r);
+extern void sync_m68k_pc(void);
+extern uae_u32 get_const(int r);
+extern int  is_const(int r);
+extern void register_branch(uae_u32 not_taken, uae_u32 taken, uae_u8 cond);
+extern void empty_optimizer(void);
+
+#define comp_get_ibyte(o) do_get_mem_byte((uae_u8 *)(comp_pc_p + (o) + 1))
+#define comp_get_iword(o) do_get_mem_word((uae_u16 *)(comp_pc_p + (o)))
+#define comp_get_ilong(o) do_get_mem_long((uae_u32 *)(comp_pc_p + (o)))
+
+/* Preferences handling */
+void check_prefs_changed_comp (void);
+
+struct blockinfo_t;
+
+typedef struct dep_t {
+  uae_u32*            jmp_off;
+  struct blockinfo_t* target;
+  struct dep_t**      prev_p;
+  struct dep_t*       next;
+} dependency;
+
+typedef struct blockinfo_t {
+    uae_s32 count;
+    cpuop_func* direct_handler_to_use;
+    cpuop_func* handler_to_use;
+    /* The direct handler does not check for the correct address */
+
+    cpuop_func* handler; 
+    cpuop_func* direct_handler;
+
+    cpuop_func* direct_pen;
+    cpuop_func* direct_pcc;
+
+    uae_u8* nexthandler;
+    uae_u8* pc_p;
+    
+    uae_u32 c1;     
+    uae_u32 c2;
+    uae_u32 len;
+
+    struct blockinfo_t* next_same_cl;
+    struct blockinfo_t** prev_same_cl_p;  
+    struct blockinfo_t* next;
+    struct blockinfo_t** prev_p; 
+
+    uae_u32 min_pcp; 
+    uae_u8 optlevel;  
+    uae_u8 needed_flags;  
+    uae_u8 status;  
+    uae_u8 havestate;
+    
+    dependency  dep[2];  /* Holds things we depend on */
+    dependency* deplist; /* List of things that depend on this */
+    smallstate  env;
+} blockinfo;
+
+#define BI_NEW 0
+#define BI_COUNTING 1
+#define BI_TARGETTED 2
+
+typedef struct {
+    uae_u8 type;
+    uae_u8 reg;
+    uae_u32 next;
+} regacc;
+
+void execute_normal(void);
+void exec_nostats(void);
+void do_nothing(void);
+
diff --git a/include/compiler.h b/include/compiler.h
new file mode 100755 (executable)
index 0000000..544a00e
--- /dev/null
@@ -0,0 +1,115 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * m68k -> i386 compiler
+  *
+  * (c) 1995 Bernd Schmidt
+  */
+
+typedef uaecptr (*code_execfunc)(void);
+
+struct code_page {
+    struct code_page *next;
+    uae_u32 allocmask;
+};
+
+struct hash_block {
+    struct hash_block *lru_next, *lru_prev;
+    struct hash_entry *he_first;
+
+    struct code_page *cpage;
+    int alloclen;
+    uae_u32 page_allocmask;
+    char *compile_start;
+
+    int nrefs;
+
+    int translated:1;
+    int untranslatable:1;
+    int allocfailed:1;
+};
+
+struct hash_entry {
+    code_execfunc execute; /* For the sake of the stubs in X86.S */
+    struct hash_entry *next,*prev;
+    struct hash_entry *next_same_block, *lru_next, *lru_prev;
+    struct hash_block *block;
+
+    uaecptr addr;
+    uae_u32 matchword;
+    int ncalls:8;
+    int locked:1;
+    int cacheflush:1;
+};
+
+extern int nr_bbs_start;
+extern uae_u8 nr_bbs_to_run;
+extern code_execfunc exec_me;
+
+#ifdef USE_COMPILER
+STATIC_INLINE void run_compiled_code(void)
+{
+
+    /*if (regs.spcflags == SPCFLAG_EXEC && may_run_compiled) {*/
+       while (regs.spcflags == SPCFLAG_EXEC) {
+           uaecptr newpc;
+           regs.spcflags = 0;
+           /*          newpc = (*exec_me)();*/
+           __asm__ __volatile__ ("pushl %%ebp; call *%1; popl %%ebp" : "=a" (newpc) : "r" (exec_me) :
+                                 "%eax", "%edx", "%ecx", "%ebx",
+                                 "%edi", "%esi", "memory", "cc");
+           if (nr_bbs_to_run == 0) {
+               struct hash_entry *h = (struct hash_entry *)newpc;
+               regs.spcflags = SPCFLAG_EXEC;
+               exec_me = h->execute;
+               regs.pc = h->addr;
+               regs.pc_p = regs.pc_oldp = get_real_address(h->addr);
+               nr_bbs_to_run = nr_bbs_start;
+           } else
+               m68k_setpc_fast(newpc);
+           do_cycles();
+       }
+/*} else */
+       regs.spcflags &= ~SPCFLAG_EXEC;
+}
+
+extern void compiler_init(void);
+extern void possible_loadseg(void);
+
+extern void m68k_do_rts(void);
+extern void m68k_do_bsr(uaecptr, uae_s32);
+extern void m68k_do_jsr(uaecptr, uaecptr);
+extern void compiler_flush_jsr_stack(void);
+
+#else
+
+#define run_compiled_code() do { ; } while (0)
+#define compiler_init() do { ; } while (0)
+#define possible_loadseg() do { ; } while (0)
+#define compiler_flush_jsr_stack() do { ; } while (0)
+
+STATIC_INLINE void m68k_do_rts(void)
+{
+    uaecptr pc = get_long (m68k_areg(regs, 7));
+    m68k_areg(regs, 7) += 4;
+    if (pc & 1)
+       exception3 (0x4e75, m68k_getpc(), pc);
+    else
+       m68k_setpc(pc);
+}
+
+STATIC_INLINE void m68k_do_bsr(uaecptr oldpc, uae_s32 offset)
+{
+    m68k_areg(regs, 7) -= 4;
+    put_long(m68k_areg(regs, 7), oldpc);
+    m68k_incpc(offset);
+}
+
+STATIC_INLINE void m68k_do_jsr(uaecptr oldpc, uaecptr dest)
+{
+    m68k_areg(regs, 7) -= 4;
+    put_long(m68k_areg(regs, 7), oldpc);
+    m68k_setpc(dest);
+}
+
+#endif
diff --git a/include/cpu_prefetch.h b/include/cpu_prefetch.h
new file mode 100755 (executable)
index 0000000..f30f05f
--- /dev/null
@@ -0,0 +1,126 @@
+
+STATIC_INLINE uae_u32 get_word_prefetch (int o)
+{
+    uae_u32 v = regs.irc;
+    regs.irc = get_word (m68k_getpc() + o);
+    return v;
+}
+STATIC_INLINE uae_u32 get_long_prefetch (int o)
+{
+    uae_u32 v = get_word_prefetch (o) << 16;
+    v |= get_word_prefetch (o + 2);
+    return v;
+}
+
+#ifdef CPUEMU_6
+STATIC_INLINE uae_u32 mem_access_delay_word_read_cycles (uaecptr addr, int *cycles)
+{
+    if (addr < 0x200000 || (addr >= 0xc00000 && addr < 0xe00000)) {
+       return wait_cpu_cycle_read_cycles (addr, 1, cycles);
+    } else if (!(addr >= 0xa00000 && addr < 0xc00000)) {
+       do_cycles_ce (4 * CYCLE_UNIT / 2);
+       *cycles = 4;
+    }
+    return get_word (addr);
+}
+STATIC_INLINE uae_u32 mem_access_delay_word_read (uaecptr addr)
+{
+    if (addr < 0x200000 || (addr >= 0xc00000 && addr < 0xe00000)) {
+       return wait_cpu_cycle_read (addr, 1);
+    } else if (!(addr >= 0xa00000 && addr < 0xc00000)) {
+       do_cycles_ce (4 * CYCLE_UNIT / 2);
+    }
+    return get_word (addr);
+}
+STATIC_INLINE uae_u32 mem_access_delay_byte_read (uaecptr addr)
+{
+    if (addr < 0x200000 || (addr >= 0xc00000 && addr < 0xe00000)) {
+       return wait_cpu_cycle_read (addr, 0);
+    } else if (!(addr >= 0xa00000 && addr < 0xc00000)) {
+       do_cycles_ce (4 * CYCLE_UNIT / 2);
+    }
+    return get_byte (addr);
+}
+STATIC_INLINE void mem_access_delay_byte_write (uaecptr addr, uae_u32 v)
+{
+    if (addr < 0x200000 || (addr >= 0xc00000 && addr < 0xe00000)) {
+       wait_cpu_cycle_write (addr, 0, v);
+       return;
+    } else if (!(addr >= 0xa00000 && addr < 0xc00000)) {
+       do_cycles_ce (4 * CYCLE_UNIT / 2);
+    }
+    put_byte (addr, v);
+}
+STATIC_INLINE void mem_access_delay_word_write (uaecptr addr, uae_u32 v)
+{
+    if (addr < 0x200000 || (addr >= 0xc00000 && addr < 0xe00000)) {
+       wait_cpu_cycle_write (addr, 1, v);
+       return;
+    } else if (!(addr >= 0xa00000 && addr < 0xc00000)) {
+       do_cycles_ce (4 * CYCLE_UNIT / 2);
+    }
+    put_word (addr, v);
+}
+
+STATIC_INLINE uae_u32 get_word_ce (uaecptr addr)
+{
+    return mem_access_delay_word_read (addr);
+}
+
+STATIC_INLINE uae_u32 get_byte_ce (uaecptr addr)
+{
+    return mem_access_delay_byte_read (addr);
+}
+
+STATIC_INLINE uae_u32 get_word_ce_prefetch (int o)
+{
+    uae_u32 v = regs.irc;
+    regs.irc = get_word_ce (m68k_getpc() + o);
+    return v;
+}
+
+STATIC_INLINE int get_word_ce_prefetch_cycles (int o)
+{
+    int cycles = 0;
+    regs.irc = mem_access_delay_word_read_cycles (m68k_getpc() + o, &cycles);
+    return cycles;
+}
+
+STATIC_INLINE void put_word_ce (uaecptr addr, uae_u16 v)
+{
+    mem_access_delay_word_write (addr, v);
+}
+
+STATIC_INLINE void put_byte_ce (uaecptr addr, uae_u8 v)
+{
+    mem_access_delay_byte_write (addr, v);
+}
+
+STATIC_INLINE void m68k_do_rts_ce (void)
+{
+    uaecptr pc;
+    pc = get_word_ce (m68k_areg (regs, 7)) << 16;
+    pc |= get_word_ce (m68k_areg (regs, 7) + 2);
+    m68k_areg (regs, 7) += 4;
+    if (pc & 1)
+       exception3 (0x4e75, m68k_getpc(), pc);
+    else
+       m68k_setpc (pc);
+}
+
+STATIC_INLINE void m68k_do_bsr_ce (uaecptr oldpc, uae_s32 offset)
+{
+    m68k_areg (regs, 7) -= 4;
+    put_word_ce (m68k_areg (regs, 7), oldpc >> 16);
+    put_word_ce (m68k_areg (regs, 7) + 2, oldpc);
+    m68k_incpc (offset);
+}
+
+STATIC_INLINE void m68k_do_jsr_ce (uaecptr oldpc, uaecptr dest)
+{
+    m68k_areg (regs, 7) -= 4;
+    put_word_ce (m68k_areg (regs, 7), oldpc >> 16);
+    put_word_ce (m68k_areg (regs, 7) + 2, oldpc);
+    m68k_setpc (dest);
+}
+#endif
\ No newline at end of file
diff --git a/include/custom.h b/include/custom.h
new file mode 100755 (executable)
index 0000000..09a5dab
--- /dev/null
@@ -0,0 +1,174 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * custom chip support
+  *
+  * (c) 1995 Bernd Schmidt
+  */
+
+/* These are the masks that are ORed together in the chipset_mask option.
+ * If CSMASK_AGA is set, the ECS bits are guaranteed to be set as well.  */
+#define CSMASK_ECS_AGNUS 1
+#define CSMASK_ECS_DENISE 2
+#define CSMASK_AGA 4
+
+uae_u32 get_copper_address(int copno);
+
+extern void custom_init (void);
+extern void customreset (void);
+extern int intlev (void);
+extern void dumpcustom (void);
+
+extern void do_disk (void);
+extern void do_copper (void);
+
+extern void notice_new_xcolors (void);
+extern void notice_screen_contents_lost (void);
+extern void init_row_map (void);
+extern void init_hz (void);
+
+extern int picasso_requested_on;
+extern int picasso_on;
+extern int turbo_emulation;
+
+/* Set to 1 to leave out the current frame in average frame time calculation.
+ * Useful if the debugger was active.  */
+extern int bogusframe;
+
+extern uae_u16 dmacon;
+extern uae_u16 intena,intreq;
+
+extern int current_hpos (void);
+extern int vpos;
+
+extern int find_copper_record (uaecptr, int *, int *);
+
+extern int n_frames;
+
+STATIC_INLINE int dmaen (unsigned int dmamask)
+{
+    return (dmamask & dmacon) && (dmacon & 0x200);
+}
+
+#define SPCFLAG_STOP 2
+#define SPCFLAG_COPPER 4
+#define SPCFLAG_INT 8
+#define SPCFLAG_BRK 16
+#define SPCFLAG_EXTRA_CYCLES 32
+#define SPCFLAG_TRACE 64
+#define SPCFLAG_DOTRACE 128
+/* #define SPCFLAG_DOINT 256 obsolete hack */
+#define SPCFLAG_BLTNASTY 512
+#define SPCFLAG_EXEC 1024
+#define SPCFLAG_ACTION_REPLAY 2048
+#define SPCFLAG_MODE_CHANGE 8192
+#define SPCFLAG_END_COMPILE 16384
+
+extern uae_u16 adkcon;
+
+extern unsigned int joy0dir, joy1dir;
+extern int joy0button, joy1button;
+
+extern void INTREQ (uae_u16);
+extern void INTREQ_0 (uae_u16);
+extern uae_u16 INTREQR (void);
+
+/* maximums for statically allocated tables */
+
+#define MAXHPOS 256
+#define MAXVPOS 576
+
+/* PAL/NTSC values */
+
+#define MAXHPOS_PAL 227
+#define MAXHPOS_NTSC 227
+#define MAXVPOS_PAL 312
+#define MAXVPOS_NTSC 262
+#define VBLANK_ENDLINE_PAL 27
+#define VBLANK_ENDLINE_NTSC 28
+#define VBLANK_SPRITE_PAL 25
+#define VBLANK_SPRITE_NTSC 20
+#define VBLANK_HZ_PAL 50
+#define VBLANK_HZ_NTSC 60
+
+extern int maxhpos, maxvpos, minfirstline, vblank_endline, numscrlines;
+extern int vblank_hz, fake_vblank_hz, vblank_skip;
+extern unsigned long syncbase;
+#define NUMSCRLINES (maxvpos+1-minfirstline+1)
+
+#define DMA_AUD0      0x0001
+#define DMA_AUD1      0x0002
+#define DMA_AUD2      0x0004
+#define DMA_AUD3      0x0008
+#define DMA_DISK      0x0010
+#define DMA_SPRITE    0x0020
+#define DMA_BLITTER   0x0040
+#define DMA_COPPER    0x0080
+#define DMA_BITPLANE  0x0100
+#define DMA_MASTER    0x0200
+#define DMA_BLITPRI   0x0400
+
+#define CYCLE_REFRESH  0x001
+#define CYCLE_DISK     0x002
+#define CYCLE_AUDIO    0x004
+#define CYCLE_SPRITE   0x008
+#define CYCLE_BITPLANE 0x010
+#define CYCLE_COPPER   0x020
+#define CYCLE_BLITTER  0x040
+#define CYCLE_BLITTER_F        0x080
+#define CYCLE_CPU      0x100
+
+extern unsigned long frametime, timeframes;
+extern int plfstrt, plfstop, plffirstline, plflastline;
+extern uae_u16 htotal, vtotal;
+
+/* 100 words give you 1600 horizontal pixels. Should be more than enough for
+ * superhires. Don't forget to update the definition in genp2c.c as well.
+ * needs to be larger for superhires support */
+#ifdef CUSTOM_SIMPLE
+#define MAX_WORDS_PER_LINE 50
+#else
+#define MAX_WORDS_PER_LINE 100
+#endif
+
+extern uae_u32 hirestab_h[256][2];
+extern uae_u32 lorestab_h[256][4];
+
+extern uae_u32 hirestab_l[256][1];
+extern uae_u32 lorestab_l[256][2];
+
+#ifdef AGA
+/* AGA mode color lookup tables */
+extern unsigned int xredcolors[256], xgreencolors[256], xbluecolors[256];
+#endif
+
+extern int bpl_off[8];
+
+#define RES_LORES 0
+#define RES_HIRES 1
+#define RES_SUPERHIRES 2
+
+/* calculate shift depending on resolution (replaced "decided_hires ? 4 : 8") */
+#define RES_SHIFT(res) ((res) == RES_LORES ? 8 : (res) == RES_HIRES ? 4 : 2)
+
+/* get resolution from bplcon0 */
+STATIC_INLINE int GET_RES (uae_u16 con0)
+{
+    int res = ((con0) & 0x8000) ? RES_HIRES : ((con0) & 0x40) ? RES_SUPERHIRES : RES_LORES;
+    return res;
+}
+/* get sprite width from FMODE */
+#define GET_SPRITEWIDTH(FMODE) ((((FMODE) >> 2) & 3) == 3 ? 64 : (((FMODE) >> 2) & 3) == 0 ? 16 : 32)
+/* Compute the number of bitplanes from a value written to BPLCON0  */
+#define GET_PLANES(x) ((((x) >> 12) & 7) | (((x) & 0x10) >> 1))
+
+extern void fpscounter_reset (void);
+extern unsigned long idletime;
+
+struct customhack {
+    uae_u16 v;
+    int vpos, hpos;
+};
+void customhack_put (struct customhack *ch, uae_u16 v, int hpos);
+uae_u16 customhack_get (struct customhack *ch, int hpos);
+
diff --git a/include/debug.h b/include/debug.h
new file mode 100755 (executable)
index 0000000..6875898
--- /dev/null
@@ -0,0 +1,26 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Debugger
+  *
+  * (c) 1995 Bernd Schmidt
+  *
+  */
+
+#define        MAX_HIST        10000
+
+extern int firsthist;
+extern int lasthist;
+extern int debugging;
+#ifdef NEED_TO_DEBUG_BADLY
+extern struct regstruct history[MAX_HIST];
+extern union flagu historyf[MAX_HIST];
+#else
+extern uaecptr history[MAX_HIST];
+#endif
+extern int exception_debugging;
+
+extern void debug(void);
+extern void activate_debugger(void);
+extern int notinrom (void);
+extern const char *debuginfo(int);
diff --git a/include/disk.h b/include/disk.h
new file mode 100755 (executable)
index 0000000..b1972ef
--- /dev/null
@@ -0,0 +1,35 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * disk support
+  *
+  * (c) 1995 Bernd Schmidt
+  */
+
+typedef enum { DRV_35_DD, DRV_35_HD, DRV_525_SD } drive_type;
+
+extern void DISK_init (void);
+extern void DISK_free (void);
+extern void DISK_select (uae_u8 data);
+extern uae_u8 DISK_status (void);
+extern void disk_eject (int num);
+extern int disk_empty (int num);
+extern void disk_insert (int num, const char *name);
+extern void DISK_check_change (void);
+extern struct zfile *DISK_validate_filename (const char *, int, int *);
+extern void DISK_handler (void);
+extern void DISK_update (int hpos);
+extern void DISK_reset (void);
+extern int disk_getwriteprotect (const char *name);
+extern int disk_setwriteprotect (int num, const char *name, int protect);
+extern void disk_creatediskfile (char *name, int type, drive_type adftype);
+extern void dumpdisk (void);
+extern void DISK_history_add (const char *name, int idx);
+extern char *DISK_history_get (int idx);
+
+extern void DSKLEN (uae_u16 v, int hpos);
+extern uae_u16 DSKBYTR (int hpos);
+extern void DSKDAT (uae_u16);
+extern void DSKSYNC (int, uae_u16);
+extern void DSKPTL (uae_u16);
+extern void DSKPTH (uae_u16);
diff --git a/include/drawing.h b/include/drawing.h
new file mode 100755 (executable)
index 0000000..b5e8a9f
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * Data used for communication between custom.c and drawing.c.
+ * 
+ * Copyright 1996-1998 Bernd Schmidt
+ */
+
+#define SMART_UPDATE 1
+
+#ifdef SUPPORT_PENGUINS
+#undef SMART_UPDATE
+#define SMART_UPDATE 1
+#endif
+
+#ifdef AGA
+#define MAX_PLANES 8
+#else
+#define MAX_PLANES 6
+#endif
+
+/* According to the HRM, pixel data spends a couple of cycles somewhere in the chips
+   before it appears on-screen.  */
+#define DIW_DDF_OFFSET 9
+
+/* We ignore that many lores pixels at the start of the display. These are
+ * invisible anyway due to hardware DDF limits. */
+#define DISPLAY_LEFT_SHIFT 0x40
+#define PIXEL_XPOS(HPOS) (((HPOS)*2 - DISPLAY_LEFT_SHIFT + DIW_DDF_OFFSET - 1) << lores_shift)
+
+#define max_diwlastword (PIXEL_XPOS(0x1d4 >> 1))
+
+extern int lores_factor, lores_shift, sprite_width;
+
+STATIC_INLINE int coord_hw_to_window_x (int x)
+{
+    x -= DISPLAY_LEFT_SHIFT;
+    return x << lores_shift;
+}
+
+STATIC_INLINE int coord_window_to_hw_x (int x)
+{
+    x >>= lores_shift;
+    return x + DISPLAY_LEFT_SHIFT;
+}
+
+STATIC_INLINE int coord_diw_to_window_x (int x)
+{
+    return (x - DISPLAY_LEFT_SHIFT + DIW_DDF_OFFSET - 1) << lores_shift;
+}
+
+STATIC_INLINE int coord_window_to_diw_x (int x)
+{
+    x = coord_window_to_hw_x (x);
+    return x - DIW_DDF_OFFSET;
+}
+
+extern int framecnt;
+
+
+/* color values in two formats: 12 (OCS/ECS) or 24 (AGA) bit Amiga RGB (color_regs),
+ * and the native color value; both for each Amiga hardware color register. 
+ *
+ * !!! See color_reg_xxx functions below before touching !!!
+ */
+struct color_entry {
+    uae_u16 color_regs_ecs[32];
+#ifndef AGA
+    xcolnr acolors[32];
+#else
+    xcolnr acolors[256];
+    uae_u32 color_regs_aga[256];
+#endif
+};
+
+#ifdef AGA
+/* convert 24 bit AGA Amiga RGB to native color */
+/* warning: ugly and works with little-endian cpu's only */
+#define CONVERT_RGB(c) \
+    ( xbluecolors[((uae_u8*)(&c))[0]] | xgreencolors[((uae_u8*)(&c))[1]] | xredcolors[((uae_u8*)(&c))[2]] )
+#else
+#define CONVERT_RGB(c) 0
+#endif
+
+STATIC_INLINE xcolnr getxcolor (int c)
+{
+#ifdef AGA
+    if (currprefs.chipset_mask & CSMASK_AGA)
+       return CONVERT_RGB(c);
+    else
+#endif
+       return xcolors[c];
+}
+
+/* functions for reading, writing, copying and comparing struct color_entry */
+STATIC_INLINE int color_reg_get (struct color_entry *ce, int c)
+{
+#ifdef AGA
+    if (currprefs.chipset_mask & CSMASK_AGA)
+       return ce->color_regs_aga[c];
+    else
+#endif
+       return ce->color_regs_ecs[c];
+}
+STATIC_INLINE void color_reg_set (struct color_entry *ce, int c, int v)
+{
+#ifdef AGA
+    if (currprefs.chipset_mask & CSMASK_AGA)
+       ce->color_regs_aga[c] = v;
+    else
+#endif
+       ce->color_regs_ecs[c] = v;
+}
+STATIC_INLINE int color_reg_cmp (struct color_entry *ce1, struct color_entry *ce2)
+{
+#ifdef AGA
+    if (currprefs.chipset_mask & CSMASK_AGA)
+       return memcmp (ce1->color_regs_aga, ce2->color_regs_aga, sizeof (uae_u32) * 256);
+    else
+#endif
+       return memcmp (ce1->color_regs_ecs, ce2->color_regs_ecs, sizeof (uae_u16) * 32);    
+}
+/* ugly copy hack, is there better solution? */
+STATIC_INLINE void color_reg_cpy (struct color_entry *dst, struct color_entry *src)
+{
+#ifdef AGA
+    if (currprefs.chipset_mask & CSMASK_AGA)
+       /* copy acolors and color_regs_aga */
+       memcpy (dst->acolors, src->acolors, sizeof(struct color_entry) - sizeof(uae_u16) * 32);
+    else
+#endif
+       /* copy first 32 acolors and color_regs_ecs */
+       memcpy (dst->color_regs_ecs, src->color_regs_ecs,
+               sizeof(struct color_entry));
+}
+
+/*
+ * The idea behind this code is that at some point during each horizontal
+ * line, we decide how to draw this line. There are many more-or-less
+ * independent decisions, each of which can be taken at a different horizontal
+ * position.
+ * Sprites and color changes are handled specially: There isn't a single decision,
+ * but a list of structures containing information on how to draw the line.
+ */
+
+struct color_change {
+    int linepos;
+    int regno;
+    unsigned long value;
+};
+
+/* 440 rather than 880, since sprites are always lores.  */
+#ifdef CUSTOM_SIMPLE
+#define MAX_PIXELS_PER_LINE 880
+#define MAX_VIDHEIGHT 800
+#else
+#define MAX_PIXELS_PER_LINE 1760
+#define MAX_VIDHEIGHT 2048
+#endif
+
+/* No divisors for MAX_PIXELS_PER_LINE; we support AGA and may one day
+   want to use SHRES sprites.  */
+#define MAX_SPR_PIXELS (((MAXVPOS + 1)*2 + 1) * MAX_PIXELS_PER_LINE)
+
+struct sprite_entry
+{
+    unsigned short pos;
+    unsigned short max;
+    unsigned int first_pixel;
+    unsigned int has_attached;
+};
+
+union sps_union {
+    uae_u8 bytes[2 * MAX_SPR_PIXELS];
+    uae_u32 words[2 * MAX_SPR_PIXELS / 4];
+};
+extern union sps_union spixstate;
+extern uae_u16 spixels[MAX_SPR_PIXELS * 2];
+
+/* Way too much... */
+#define MAX_REG_CHANGE ((MAXVPOS + 1) * 2 * MAXHPOS)
+
+#ifdef OS_WITHOUT_MEMORY_MANAGEMENT
+extern struct color_change *color_changes[2];
+#else
+extern struct color_change color_changes[2][MAX_REG_CHANGE];
+#endif
+
+extern struct color_entry color_tables[2][(MAXVPOS+1) * 2];
+extern struct color_entry *curr_color_tables, *prev_color_tables;
+
+extern struct sprite_entry *curr_sprite_entries, *prev_sprite_entries;
+extern struct color_change *curr_color_changes, *prev_color_changes;
+extern struct draw_info *curr_drawinfo, *prev_drawinfo;
+
+/* struct decision contains things we save across drawing frames for
+ * comparison (smart update stuff). */
+struct decision {
+    /* Records the leftmost access of BPL1DAT.  */
+    int plfleft, plfright, plflinelen;
+    /* Display window: native coordinates, depend on lores state.  */
+    int diwfirstword, diwlastword;
+    int ctable;
+
+    uae_u16 bplcon0, bplcon2;
+#ifdef AGA
+    uae_u16 bplcon3, bplcon4;
+#endif
+    uae_u8 nr_planes;
+    uae_u8 bplres;
+    unsigned int any_hires_sprites:1;
+    unsigned int ham_seen:1;
+    unsigned int ham_at_start:1;
+};
+
+/* Anything related to changes in hw registers during the DDF for one
+ * line. */
+struct draw_info {
+    int first_sprite_entry, last_sprite_entry;
+    int first_color_change, last_color_change;
+    int nr_color_changes, nr_sprites;
+};
+
+extern int next_sprite_entry;
+
+extern struct decision line_decisions[2 * (MAXVPOS+1) + 1];
+extern struct draw_info line_drawinfo[2][2 * (MAXVPOS+1) + 1];
+
+extern uae_u8 line_data[(MAXVPOS+1) * 2][MAX_PLANES * MAX_WORDS_PER_LINE * 2];
+
+extern uae_u8 *real_bplpt[8];
+
+/* Functions in drawing.c.  */
+extern int coord_native_to_amiga_y (int);
+extern int coord_native_to_amiga_x (int);
+
+extern void record_diw_line (int first, int last);
+extern void hardware_line_completed (int lineno);
+
+/* Determine how to draw a scan line.  */
+enum nln_how {
+    /* All lines on a non-doubled display. */
+    nln_normal,
+    /* Non-interlace, doubled display.  */
+    nln_doubled,
+    /* Interlace, doubled display, upper line.  */
+    nln_upper,
+    /* Interlace, doubled display, lower line.  */
+    nln_lower,
+    /* This line normal, next one black.  */
+    nln_nblack
+};
+
+extern void hsync_record_line_state (int lineno, enum nln_how, int changed);
+extern void vsync_handle_redraw (int long_frame, int lof_changed);
+extern void init_hardware_for_drawing_frame (void);
+extern void finish_drawing_frame (void);
+extern void reset_drawing (void);
+extern void drawing_init (void);
+extern void notice_interlace_seen (void);
+extern void frame_drawn (void);
+extern void redraw_frame (void);
+
+/* Finally, stuff that shouldn't really be shared.  */
+
+extern int thisframe_first_drawn_line, thisframe_last_drawn_line;
+extern int diwfirstword,diwlastword;
+
+#define IHF_SCROLLLOCK 0
+#define IHF_QUIT_PROGRAM 1
+#define IHF_PICASSO 2
+#define IHF_SOUNDADJUST 3
+
+extern int inhibit_frame;
+
+STATIC_INLINE void set_inhibit_frame (int bit)
+{
+    inhibit_frame |= 1 << bit;
+}
+STATIC_INLINE void clear_inhibit_frame (int bit)
+{
+    inhibit_frame &= ~(1 << bit);
+}
+STATIC_INLINE void toggle_inhibit_frame (int bit)
+{
+    inhibit_frame ^= 1 << bit;
+}
diff --git a/include/driveclick.h b/include/driveclick.h
new file mode 100755 (executable)
index 0000000..2cd70ae
--- /dev/null
@@ -0,0 +1,40 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Drive Click emulation stuff
+  *
+  * Copyright 2004 James Bagg, Toni Wilen
+  */
+
+
+struct drvsample {
+    int len;
+    int pos;
+    uae_s16 *p;
+};
+
+#define DS_CLICK 0
+#define DS_SPIN 1
+#define DS_SPINND 2
+#define DS_START 3
+#define DS_SNATCH 4
+#define DS_END 5
+
+extern void driveclick_click(int drive, int startOffset);
+extern void driveclick_motor(int drive, int running);
+extern void driveclick_insert(int drive, int eject);
+extern void driveclick_init(void);
+extern void driveclick_free(void);
+extern void driveclick_reset(void);
+extern void driveclick_mix(uae_s16*, int);
+extern int driveclick_loadresource(struct drvsample*, int);
+extern void driveclick_check_prefs (void);
+extern uae_s16 *decodewav (uae_u8 *s, int *len);
+
+#define DS_BUILD_IN_SOUNDS 1
+#define DS_NAME_CLICK "drive_click_"
+#define DS_NAME_SPIN "drive_spin_"
+#define DS_NAME_SPIN_ND "drive_spinnd_"
+#define DS_NAME_START "drive_start_"
+#define DS_NAME_SNATCH "drive_snatch_"
+
diff --git a/include/enforcer.h b/include/enforcer.h
new file mode 100755 (executable)
index 0000000..c54efc0
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef UAE__ENFORCER_H
+#define UAE__ENFORCER_H
+
+int enforcer_enable(void);
+int enforcer_disable(void);
+
+#endif
\ No newline at end of file
diff --git a/include/ersatz.h b/include/ersatz.h
new file mode 100755 (executable)
index 0000000..4929db5
--- /dev/null
@@ -0,0 +1,11 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * A "replacement" for a missing Kickstart
+  *
+  * (c) 1995 Bernd Schmidt
+  */
+
+extern void init_ersatz_rom (uae_u8 *data);
+extern void ersatz_perform (uae_u16);
+extern void DISK_ersatz_read (int,int, uaecptr);
diff --git a/include/events.h b/include/events.h
new file mode 100755 (executable)
index 0000000..e65eba6
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef EVENTS_H
+#define EVENTS_H
+
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Events
+  * These are best for low-frequency events. Having too many of them,
+  * or using them for events that occur too frequently, can cause massive
+  * slowdown.
+  *
+  * Copyright 1995-1998 Bernd Schmidt
+  */
+
+#undef EVENT_DEBUG
+
+#include "machdep/rpt.h"
+
+extern volatile frame_time_t vsynctime, vsyncmintime;
+extern void reset_frame_rate_hack (void);
+extern int rpt_available;
+extern unsigned long syncbase;
+
+extern void compute_vsynctime (void);
+extern void init_eventtab (void);
+extern void do_cycles_ce (long cycles);
+
+extern unsigned long currcycle, nextevent, is_lastline;
+extern unsigned long sample_evtime;
+typedef void (*evfunc)(void);
+
+struct ev
+{
+    int active;
+    unsigned long int evtime, oldcycles;
+    evfunc handler;
+};
+
+enum {
+    ev_hsync, ev_copper, ev_audio, ev_cia, ev_blitter, ev_disk,
+    ev_max
+};
+
+extern struct ev eventtab[ev_max];
+
+
+#ifdef JIT
+#include "events_jit.h"
+#else
+#include "events_normal.h"
+#endif
+
+#endif
diff --git a/include/events_jit.h b/include/events_jit.h
new file mode 100755 (executable)
index 0000000..8b1995d
--- /dev/null
@@ -0,0 +1,197 @@
+#if 1
+
+/* Let's see whether hiding this away somewhere where the compiler can't
+   see it will cure it of its silly urge to mis-optimize the comparison */
+extern long int diff32(frame_time_t x, frame_time_t y);
+
+STATIC_INLINE void events_schedule (void)
+{
+    int i;
+
+    unsigned long int mintime = ~0L;
+    for (i = 0; i < ev_max; i++) {
+       if (eventtab[i].active) {
+           unsigned long int eventtime = eventtab[i].evtime - currcycle;
+#ifdef EVENT_DEBUG
+           if (eventtime == 0) {
+               write_log("event %d bug\n",i);
+           }
+#endif
+           if (eventtime < mintime)
+               mintime = eventtime;
+       }
+    }
+    nextevent = currcycle + mintime;
+}
+
+extern signed long pissoff;
+
+STATIC_INLINE void cycles_do_special (void)
+{
+    if (pissoff >= 0)
+       pissoff = -1;
+}
+
+STATIC_INLINE void do_extra_cycles (unsigned long cycles_to_add)
+{
+    pissoff -= cycles_to_add;
+}
+
+STATIC_INLINE unsigned long int get_cycles (void)
+{
+    return currcycle;
+}
+
+STATIC_INLINE void set_cycles (unsigned long int x)
+{
+    currcycle = x;
+}
+
+STATIC_INLINE void do_cycles_slow (unsigned long cycles_to_add)
+{
+    if ((pissoff -= cycles_to_add) >= 0)
+       return;
+
+    cycles_to_add = -pissoff;
+    pissoff = 0;
+
+    if (is_lastline && eventtab[ev_hsync].evtime - currcycle <= cycles_to_add) {
+       int rpt = read_processor_time ();
+       int v = rpt - vsyncmintime;
+       if (v > (int)syncbase || v < -((int)syncbase))
+           vsyncmintime = rpt;
+       if (v < 0) {
+           pissoff = 3000 * CYCLE_UNIT;
+           return;
+       }
+    }
+    while ((nextevent - currcycle) <= cycles_to_add) {
+        int i;
+        cycles_to_add -= (nextevent - currcycle);
+        currcycle = nextevent;
+
+        for (i = 0; i < ev_max; i++) {
+           if (eventtab[i].active && eventtab[i].evtime == currcycle) {
+               (*eventtab[i].handler)();
+           }
+       }
+        events_schedule();
+    }
+    currcycle += cycles_to_add;
+}
+
+#define do_cycles do_cycles_slow
+#define countdown pissoff
+
+#else
+
+/* Let's see whether hiding this away somewhere where the compiler can't
+   see it will cure it of its silly urge to mis-optimize the comparison */ extern long int diff32(frame_time_t x, frame_time_t y);
+
+extern long cycles_to_next_event;
+extern long max_cycles_to_next_event;
+extern long cycles_to_hsync_event;
+extern long pissoff;
+
+STATIC_INLINE void cycles_do_special(void)
+{
+    if (cycles_to_next_event >= 0) {
+       pissoff += cycles_to_next_event;
+       cycles_to_next_event = 0;
+    }
+}
+
+
+STATIC_INLINE void do_extra_cycles (unsigned long cycles_to_add) {
+    pissoff -= cycles_to_add;
+}
+
+STATIC_INLINE unsigned long int get_cycles (void)
+{
+    if (cycles_to_next_event <= max_cycles_to_next_event) {
+       max_cycles_to_next_event = cycles_to_next_event;
+       return nextevent - cycles_to_next_event;
+    } else {
+       return nextevent - max_cycles_to_next_event;
+    }
+}
+
+STATIC_INLINE void events_schedule (void)
+{
+    int i;
+
+    unsigned long int curcycles = get_cycles();
+    unsigned long int mintime = ~0L;
+
+    cycles_to_hsync_event=eventtab[ev_hsync].evtime - curcycles;
+    for (i = 0; i < ev_max; i++) {
+       if (eventtab[i].active) {
+           unsigned long int eventtime = eventtab[i].evtime - curcycles;
+           if (eventtime < mintime) 
+               mintime = eventtime;
+       }
+    }
+    nextevent = curcycles + mintime;
+    max_cycles_to_next_event = mintime;
+    cycles_to_next_event = mintime;
+    cycles_to_hsync_event = mintime - cycles_to_hsync_event;
+}
+
+STATIC_INLINE void set_cycles (unsigned long int x)
+{
+    cycles_to_next_event = nextevent - x;
+    events_schedule ();
+}
+
+STATIC_INLINE void do_cycles_slow (long cycles_to_add)
+{
+    cycles_to_next_event -= cycles_to_add;
+    if (cycles_to_next_event > 0)
+       return;
+
+    cycles_to_next_event += pissoff;
+    pissoff=0;
+
+    if (is_lastline
+       && /*cycles_to_next_event <= cycles_to_hsync_event*/
+       eventtab[ev_hsync].evtime == nextevent) 
+    {
+       frame_time_t now=read_processor_time();
+       if (diff32(now, vsyncmintime)<0)
+       {
+           cycles_to_next_event += 3000 * CYCLE_UNIT;
+           return;
+       }
+    }
+    cycles_to_add=0;
+    while (cycles_to_next_event <= cycles_to_add) {
+       int i;
+
+       cycles_to_add-=cycles_to_next_event;
+       cycles_to_next_event=0;
+       for (i = 0; i < ev_max; i++) {
+           if (eventtab[i].active && eventtab[i].evtime == nextevent) {
+               (*eventtab[i].handler) ();
+           }
+       }
+       events_schedule();
+    }
+    cycles_to_next_event -= cycles_to_add;
+}
+
+#define do_cycles do_cycles_slow
+#define countdown cycles_to_next_event
+
+#endif
+
+/* This is a special-case function.  Normally, all events should lie in the
+   future; they should only ever be active at the current cycle during
+   do_cycles.  However, a snapshot is saved during do_cycles, and so when
+   restoring it, we may have other events pending.  */ STATIC_INLINE void handle_active_events (void) {
+    int i;
+    for (i = 0; i < ev_max; i++) {
+       if (eventtab[i].active && eventtab[i].evtime == currcycle) {
+           (*eventtab[i].handler)();
+       }
+    }
+}
diff --git a/include/events_normal.h b/include/events_normal.h
new file mode 100755 (executable)
index 0000000..88f78b3
--- /dev/null
@@ -0,0 +1,90 @@
+
+STATIC_INLINE void cycles_do_special (void)
+{
+}
+STATIC_INLINE void set_cycles (int c)
+{
+}
+
+STATIC_INLINE void events_schedule (void)
+{
+    int i;
+
+    unsigned long int mintime = ~0L;
+    for (i = 0; i < ev_max; i++) {
+       if (eventtab[i].active) {
+           unsigned long int eventtime = eventtab[i].evtime - currcycle;
+           if (eventtime < mintime)
+               mintime = eventtime;
+       }
+    }
+    nextevent = currcycle + mintime;
+}
+
+STATIC_INLINE void do_cycles_slow (unsigned long cycles_to_add)
+{
+    if (is_lastline && eventtab[ev_hsync].evtime - currcycle <= cycles_to_add
+       && (long int)(read_processor_time () - vsyncmintime) < 0)
+       return;
+
+    while ((nextevent - currcycle) <= cycles_to_add) {
+        int i;
+        cycles_to_add -= (nextevent - currcycle);
+        currcycle = nextevent;
+
+        for (i = 0; i < ev_max; i++) {
+           if (eventtab[i].active && eventtab[i].evtime == currcycle) {
+               (*eventtab[i].handler)();
+           }
+       }
+        events_schedule();
+    }
+    currcycle += cycles_to_add;
+}
+
+STATIC_INLINE void do_cycles_fast (void)
+{
+    if (is_lastline && eventtab[ev_hsync].evtime - currcycle <= 1
+       && (long int)(read_processor_time () - vsyncmintime) < 0)
+       return;
+
+    currcycle++;
+    if (nextevent == currcycle) {
+       int i;
+
+       for (i = 0; i < ev_max; i++) {
+           if (eventtab[i].active && eventtab[i].evtime == currcycle) {
+               (*eventtab[i].handler) ();
+           }
+       }
+       events_schedule();
+    }
+
+}
+
+/* This is a special-case function.  Normally, all events should lie in the
+   future; they should only ever be active at the current cycle during
+   do_cycles.  However, a snapshot is saved during do_cycles, and so when
+   restoring it, we may have other events pending.  */
+STATIC_INLINE void handle_active_events (void)
+{
+    int i;
+    for (i = 0; i < ev_max; i++) {
+       if (eventtab[i].active && eventtab[i].evtime == currcycle) {
+           (*eventtab[i].handler)();
+       }
+    }
+}
+
+STATIC_INLINE unsigned long get_cycles (void)
+{
+    return currcycle;
+}
+
+extern void init_eventtab (void);
+
+#if /* M68K_SPEED == 1 */  0
+#define do_cycles do_cycles_fast
+#else
+#define do_cycles do_cycles_slow
+#endif
diff --git a/include/execlib.h b/include/execlib.h
new file mode 100755 (executable)
index 0000000..362bc6c
--- /dev/null
@@ -0,0 +1,45 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Miscellaneous bits for exec emulation
+  *
+  * Copyright 1996 Bernd Schmidt
+  */
+
+#define CMD_INVALID 0
+#define CMD_RESET   1
+#define CMD_READ    2
+#define CMD_WRITE   3
+#define CMD_UPDATE  4
+#define CMD_CLEAR   5
+#define CMD_STOP    6
+#define CMD_START   7
+#define CMD_FLUSH   8
+#define CMD_NONSTD  9
+
+#define TD_READ64   24
+#define TD_WRITE64  25
+#define TD_SEEK64   26
+#define TD_FORMAT64 27
+
+#define NT_TASK     1
+#define NT_DEVICE   3
+#define NT_MSGPORT  4
+#define NT_MESSAGE  5
+#define NT_FREEMSG  6
+#define NT_REPLYMSG 7
+#define NT_RESOURCE 8
+#define NT_LIBRARY  9
+#define NT_SIGNALSEM 15
+
+#ifndef MEMF_PUBLIC /* protection for AmigaDOS */
+#define MEMF_PUBLIC 1
+#define MEMF_CHIP 2
+#define MEMF_FAST 4
+#define MEMF_LOCAL 256
+#define MEMF_24BITDMA 512
+#define MEMF_CLEAR (1<<16)
+#define MEMF_LARGEST (1<<17)
+#define MEMF_REVERSE (1<<18)
+#define MEMF_TOTAL (1<<19)
+#endif
diff --git a/include/fdi2raw.h b/include/fdi2raw.h
new file mode 100755 (executable)
index 0000000..e5ffa0c
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef __FDI2RAW_H
+#define __FDI2RAW_H
+
+//#include "types.h"
+#include <stdio.h>
+typedef struct fdi FDI;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int fdi2raw_loadtrack (FDI*, uae_u16 *mfmbuf, uae_u16 **trackpointers, uae_u16 **tracktiming, int track, int *tracklengths, int *revolutions, int *indexoffset);
+extern FDI *fdi2raw_header(struct zfile *f);
+extern void fdi2raw_header_free (FDI *);
+extern int fdi2raw_get_last_track(FDI *);
+extern int fdi2raw_get_num_sector (FDI *);
+extern int fdi2raw_get_last_head(FDI *);
+extern int fdi2raw_get_type (FDI *);
+extern int fdi2raw_get_bit_rate (FDI *);
+extern int fdi2raw_get_rotation (FDI *);
+extern int fdi2raw_get_write_protect (FDI *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/filesys.h b/include/filesys.h
new file mode 100755 (executable)
index 0000000..cee3455
--- /dev/null
@@ -0,0 +1,50 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Unix file system handler for AmigaDOS
+  *
+  * Copyright 1997 Bernd Schmidt
+  */
+
+struct hardfiledata {
+    uae_u64 size;
+    uae_u64 offset;
+    int nrcyls;
+    int secspertrack;
+    int surfaces;
+    int reservedblocks;
+    int blocksize;
+    void *handle;
+    int readonly;
+    int flags;
+    uae_u8 *cache;
+    int cache_valid;
+    uae_u64 cache_offset;
+    char vendor_id[8 + 1];
+    char product_id[16 + 1];
+    char product_rev[4 + 1];
+    char device_name[256];
+    uae_u64 size2;
+    uae_u64 offset2;
+};
+
+#define FILESYS_VIRTUAL 0
+#define FILESYS_HARDFILE 1
+#define FILESYS_HARDFILE_RDB 2
+#define FILESYS_HARDDRIVE 3
+
+#define MAX_FILESYSTEM_UNITS 20
+
+struct uaedev_mount_info;
+
+extern struct hardfiledata *get_hardfile_data (int nr);
+#define FILESYS_MAX_BLOCKSIZE 2048
+extern int hdf_open (struct hardfiledata *hfd, char *name);
+extern int hdf_dup (struct hardfiledata *hfd, void *src);
+extern void hdf_close (struct hardfiledata *hfd);
+extern int hdf_read (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len);
+extern int hdf_write (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len);
+extern int hdf_getnumharddrives (void);
+extern char *hdf_getnameharddrive (int index, int flags);
+extern int hdf_init (void);
+extern int isspecialdrive(const char *name);
diff --git a/include/filter.h b/include/filter.h
new file mode 100755 (executable)
index 0000000..c31b34f
--- /dev/null
@@ -0,0 +1,56 @@
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long u32;
+
+extern void S2X_refresh (void);
+extern void S2X_render (void);
+extern void S2X_init (int dw, int dh, int aw, int ah, int mult, int ad, int dd);
+
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned long uint32;
+typedef int bool;
+
+extern void S2X_configure (int rb, int gb, int bb, int rs, int gs, int bs);
+extern int Init_2xSaI(int rb, int gb, int bb, int rs, int gs, int bs);
+extern void Super2xSaI(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height);
+extern void SuperEagle(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height);
+extern void _2xSaI(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height);
+extern void AdMame2x(u8 *srcPtr, u32 srcPitch, /* u8 deltaPtr, */
+              u8 *dstPtr, u32 dstPitch, int width, int height);
+extern void AdMame2x32(u8 *srcPtr, u32 srcPitch, /* u8 deltaPtr, */
+              u8 *dstPtr, u32 dstPitch, int width, int height);
+
+extern void hq_init(int rb, int gb, int bb, int rs, int gs, int bs);
+extern void hq2x_32(unsigned char*, unsigned char*, int, int, int, int, int);
+extern void hq3x_32(unsigned char*, unsigned char*, int, int, int, int, int);
+extern void hq3x_16(unsigned char*, unsigned char*, int, int, int, int, int);
+extern void hq4x_32(unsigned char*, unsigned char*, int, int, int, int, int);
+
+#define UAE_FILTER_NULL 1
+#define UAE_FILTER_DIRECT3D 2
+#define UAE_FILTER_OPENGL 3
+#define UAE_FILTER_SCALE2X 4
+#define UAE_FILTER_SUPEREAGLE 5
+#define UAE_FILTER_SUPER2XSAI 6
+#define UAE_FILTER_2XSAI 7
+#define UAE_FILTER_HQ 8
+
+#define UAE_FILTER_MODE_16 16
+#define UAE_FILTER_MODE_16_16 16
+#define UAE_FILTER_MODE_16_32 (16 | 8)
+#define UAE_FILTER_MODE_32 32
+#define UAE_FILTER_MODE_32_32 32
+#define UAE_FILTER_MODE_32_16 (32 | 8)
+
+
+struct uae_filter
+{
+    int type;
+    char *name, *cfgname;
+    int x[5];
+};
+
+extern struct uae_filter uaefilters[];
+extern struct uae_filter *usedfilter;
diff --git a/include/fpp-ieee-be.h b/include/fpp-ieee-be.h
new file mode 100755 (executable)
index 0000000..81e67b7
--- /dev/null
@@ -0,0 +1,64 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * MC68881 emulation
+  * Support functions for IEEE compatible host CPUs.
+  * These functions use a GCC extension (type punning through unions) and
+  * should only be compiled with compilers that support this.
+  *
+  * Copyright 1999 Sam Jordan
+  */
+
+STATIC_INLINE double to_single (uae_u32 value)
+{
+    union {
+        float f;
+        uae_u32 u;
+    } val;
+
+    val.u = value;
+    return val.f;
+}
+
+STATIC_INLINE uae_u32 from_single (double src)
+{
+    union {
+        float f;
+        uae_u32 u;
+    } val;
+
+    val.f = src;
+    return val.u;
+}
+
+STATIC_INLINE double to_double(uae_u32 wrd1, uae_u32 wrd2)
+{
+    union {
+        double d;
+        uae_u32 u[2];
+    } val;
+
+    val.u[0] = wrd1;
+    val.u[1] = wrd2;
+    return val.d;
+}
+
+STATIC_INLINE void from_double(double src, uae_u32 * wrd1, uae_u32 * wrd2)
+{
+    union {
+        double d;
+        uae_u32 u[2];
+    } val;
+
+    val.d = src;
+    *wrd1 = val.u[0];
+    *wrd2 = val.u[1];
+}
+
+#define HAVE_from_double
+#define HAVE_to_double
+#define HAVE_from_single
+#define HAVE_to_single
+
+/* Get the rest of the conversion functions defined.  */
+#include "fpp-unknown.h"
diff --git a/include/fpp-unknown.h b/include/fpp-unknown.h
new file mode 100755 (executable)
index 0000000..26d5e1f
--- /dev/null
@@ -0,0 +1,139 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * MC68881 emulation
+  *
+  * Conversion routines for hosts with unknown floating point format.
+  *
+  * Copyright 1996 Herman ten Brugge
+  */
+
+#ifndef HAVE_to_single
+STATIC_INLINE double to_single (uae_u32 value)
+{
+    double frac;
+
+    if ((value & 0x7fffffff) == 0)
+        return (0.0);
+    frac = (double) ((value & 0x7fffff) | 0x800000) / 8388608.0;
+    if (value & 0x80000000)
+        frac = -frac;
+    return (ldexp (frac, ((value >> 23) & 0xff) - 127));
+}
+#endif
+
+#ifndef HAVE_from_single
+STATIC_INLINE uae_u32 from_single (double src)
+{
+    int expon;
+    uae_u32 tmp;
+    double frac;
+
+    if (src == 0.0)
+        return 0;
+    if (src < 0) {
+        tmp = 0x80000000;
+        src = -src;
+    } else {
+        tmp = 0;
+    }
+    frac = frexp (src, &expon);
+    frac += 0.5 / 16777216.0;
+    if (frac >= 1.0) {
+        frac /= 2.0;
+        expon++;
+    }
+    return (tmp | (((expon + 127 - 1) & 0xff) << 23) |
+            (((int) (frac * 16777216.0)) & 0x7fffff));
+}
+#endif
+
+#ifndef HAVE_to_exten
+STATIC_INLINE double to_exten(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
+{
+    double frac;
+
+    if ((wrd1 & 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0)
+        return 0.0;
+    frac = (double) wrd2 / 2147483648.0 +
+        (double) wrd3 / 9223372036854775808.0;
+    if (wrd1 & 0x80000000)
+        frac = -frac;
+    return ldexp (frac, ((wrd1 >> 16) & 0x7fff) - 16383);
+}
+#endif
+
+#ifndef HAVE_from_exten
+STATIC_INLINE void from_exten(double src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3)
+{
+    int expon;
+    double frac;
+
+    if (src == 0.0) {
+        *wrd1 = 0;
+        *wrd2 = 0;
+        *wrd3 = 0;
+        return;
+    }
+    if (src < 0) {
+        *wrd1 = 0x80000000;
+        src = -src;
+    } else {
+        *wrd1 = 0;
+    }
+    frac = frexp (src, &expon);
+    frac += 0.5 / 18446744073709551616.0;
+    if (frac >= 1.0) {
+        frac /= 2.0;
+        expon++;
+    }
+    *wrd1 |= (((expon + 16383 - 1) & 0x7fff) << 16);
+    *wrd2 = (uae_u32) (frac * 4294967296.0);
+    *wrd3 = (uae_u32) (frac * 18446744073709551616.0 - *wrd2 * 4294967296.0);
+}
+#endif
+
+#ifndef HAVE_to_double
+STATIC_INLINE double to_double(uae_u32 wrd1, uae_u32 wrd2)
+{
+    double frac;
+
+    if ((wrd1 & 0x7fffffff) == 0 && wrd2 == 0)
+        return 0.0;
+    frac = (double) ((wrd1 & 0xfffff) | 0x100000) / 1048576.0 +
+        (double) wrd2 / 4503599627370496.0;
+    if (wrd1 & 0x80000000)
+        frac = -frac;
+    return ldexp (frac, ((wrd1 >> 20) & 0x7ff) - 1023);
+}
+#endif
+
+#ifndef HAVE_from_double
+STATIC_INLINE void from_double(double src, uae_u32 * wrd1, uae_u32 * wrd2)
+{
+    int expon;
+    int tmp;
+    double frac;
+
+    if (src == 0.0) {
+        *wrd1 = 0;
+        *wrd2 = 0;
+        return;
+    }
+    if (src < 0) {
+        *wrd1 = 0x80000000;
+        src = -src;
+    } else {
+        *wrd1 = 0;
+    }
+    frac = frexp (src, &expon);
+    frac += 0.5 / 9007199254740992.0;
+    if (frac >= 1.0) {
+        frac /= 2.0;
+        expon++;
+    }
+    tmp = (uae_u32) (frac * 2097152.0);
+    *wrd1 |= (((expon + 1023 - 1) & 0x7ff) << 20) | (tmp & 0xfffff);
+    *wrd2 = (uae_u32) (frac * 9007199254740992.0 - tmp * 4294967296.0);
+}
+#endif
diff --git a/include/fsdb.h b/include/fsdb.h
new file mode 100755 (executable)
index 0000000..1c247d4
--- /dev/null
@@ -0,0 +1,114 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Library of functions to make emulated filesystem as independent as
+  * possible of the host filesystem's capabilities.
+  *
+  * Copyright 1999 Bernd Schmidt
+  */
+
+#ifndef FSDB_FILE
+#define FSDB_FILE "_UAEFSDB.___"
+#endif
+
+#ifndef FSDB_DIR_SEPARATOR
+#define FSDB_DIR_SEPARATOR '/'
+#endif
+
+/* AmigaOS errors */
+#define ERROR_NO_FREE_STORE            103
+#define ERROR_OBJECT_IN_USE            202
+#define ERROR_OBJECT_EXISTS            203
+#define ERROR_DIR_NOT_FOUND            204
+#define ERROR_OBJECT_NOT_AROUND                205
+#define ERROR_ACTION_NOT_KNOWN         209
+#define ERROR_INVALID_LOCK             211
+#define ERROR_OBJECT_WRONG_TYPE                212
+#define ERROR_DISK_WRITE_PROTECTED     214
+#define ERROR_DIRECTORY_NOT_EMPTY      216
+#define ERROR_DEVICE_NOT_MOUNTED       218
+#define ERROR_SEEK_ERROR               219
+#define ERROR_DISK_IS_FULL             221
+#define ERROR_DELETE_PROTECTED         222
+#define ERROR_WRITE_PROTECTED          223
+#define ERROR_READ_PROTECTED           224
+#define ERROR_NO_MORE_ENTRIES          232
+#define ERROR_NOT_IMPLEMENTED          236
+
+#define A_FIBF_SCRIPT  (1<<6)
+#define A_FIBF_PURE    (1<<5)
+#define A_FIBF_ARCHIVE (1<<4)
+#define A_FIBF_READ    (1<<3)
+#define A_FIBF_WRITE   (1<<2)
+#define A_FIBF_EXECUTE (1<<1)
+#define A_FIBF_DELETE  (1<<0)
+
+/* AmigaOS "keys" */
+typedef struct a_inode_struct {
+#ifdef AINO_DEBUG
+    uae_u32 checksum1;
+#endif
+    /* Circular list of recycleable a_inodes.  */
+    struct a_inode_struct *next, *prev;
+    /* This a_inode's relatives in the directory structure.  */
+    struct a_inode_struct *parent;
+    struct a_inode_struct *child, *sibling;
+    /* AmigaOS name, and host OS name.  The host OS name is a full path, the
+     * AmigaOS name is relative to the parent.  */
+    char *aname;
+    char *nname;
+    /* AmigaOS file comment, or NULL if file has none.  */
+    char *comment;
+    /* AmigaOS protection bits.  */
+    int amigaos_mode;
+    /* Unique number for identification.  */
+    uae_u32 uniq;
+    /* For a directory that is being ExNext()ed, the number of child ainos
+       which must be kept locked in core.  */
+    unsigned long locked_children;
+    /* How many ExNext()s are going on in this directory?  */
+    unsigned long exnext_count;
+    /* AmigaOS locking bits.  */
+    int shlock;
+    long db_offset;
+    unsigned int dir:1;
+    unsigned int elock:1;
+    /* Nonzero if this came from an entry in our database.  */
+    unsigned int has_dbentry:1;
+    /* Nonzero if this will need an entry in our database.  */
+    unsigned int needs_dbentry:1;
+    /* This a_inode possibly needs writing back to the database.  */
+    unsigned int dirty:1;
+    /* If nonzero, this represents a deleted file; the corresponding
+     * entry in the database must be cleared.  */
+    unsigned int deleted:1;
+#ifdef AINO_DEBUG
+    uae_u32 checksum2;
+#endif
+} a_inode;
+
+extern char *nname_begin (char *);
+
+extern char *build_nname (const char *d, const char *n);
+extern char *build_aname (const char *d, const char *n);
+
+/* Filesystem-independent functions.  */
+extern void fsdb_clean_dir (a_inode *);
+extern char *fsdb_search_dir (const char *dirname, char *rel);
+extern void fsdb_dir_writeback (a_inode *);
+extern int fsdb_used_as_nname (a_inode *base, const char *);
+extern a_inode *fsdb_lookup_aino_aname (a_inode *base, const char *);
+extern a_inode *fsdb_lookup_aino_nname (a_inode *base, const char *);
+extern int fsdb_exists (char *nname);
+
+STATIC_INLINE int same_aname (const char *an1, const char *an2)
+{
+    return strcasecmp (an1, an2) == 0;
+}
+
+/* Filesystem-dependent functions.  */
+extern int fsdb_name_invalid (const char *n);
+extern int fsdb_fill_file_attrs (a_inode *);
+extern int fsdb_set_file_attrs (a_inode *, int);
+extern int fsdb_mode_representable_p (const a_inode *);
+extern char *fsdb_create_unique_nname (a_inode *base, const char *);
diff --git a/include/fsusage.h b/include/fsusage.h
new file mode 100755 (executable)
index 0000000..227c5b4
--- /dev/null
@@ -0,0 +1,37 @@
+/* fsusage.h -- declarations for filesystem space usage info
+   Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* Space usage statistics for a filesystem.  Blocks are 512-byte. */
+struct fs_usage
+{
+  long fsu_blocks;             /* Total blocks. */
+  long fsu_bfree;              /* Free blocks available to superuser. */
+  long fsu_bavail;             /* Free blocks available to non-superuser. */
+  long fsu_files;              /* Total file nodes. */
+  long fsu_ffree;              /* Free file nodes. */
+};
+
+#ifndef __P
+#if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
+#define __P(args) args
+#else
+#define __P(args) ()
+#endif  /* GCC.  */
+#endif  /* Not __P.  */
+
+int get_fs_usage __P ((const char *path, const char *disk,
+                      struct fs_usage *fsp));
diff --git a/include/genblitter.h b/include/genblitter.h
new file mode 100755 (executable)
index 0000000..3b333fe
--- /dev/null
@@ -0,0 +1,15 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Optimized blitter minterm function generator
+  *
+  * Copyright 1995,1996 Bernd Schmidt
+  * Copyright 1996 Alessandro Bissacco
+  */
+
+struct blitop {
+    const char *s;
+    int used;
+};
+
+extern struct blitop blitops[256];
diff --git a/include/gensound.h b/include/gensound.h
new file mode 100755 (executable)
index 0000000..82a0565
--- /dev/null
@@ -0,0 +1,38 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Prototypes for general sound related functions
+  * This use to be called sound.h, but that causes confusion
+  *
+  * Copyright 1997 Bernd Schmidt
+  */
+
+extern int sound_available;
+
+extern void (*sample_handler) (void);
+/* sample_evtime is in normal Amiga cycles; scaled_sample_evtime is in our
+   event cycles.  scaled_sample_evtime_ok is set to 1 by init_sound if the
+   port understands scaled_sample_evtime and set it to something sensible.  */
+extern unsigned long sample_evtime, scaled_sample_evtime;
+extern int scaled_sample_evtime_ok;
+
+/* Determine if we can produce any sound at all.  This can be only a guess;
+ * if unsure, say yes.  Any call to init_sound may change the value.  */
+extern int setup_sound (void);
+
+extern int init_sound (void);
+extern void close_sound (void);
+
+extern void sample16_handler (void);
+extern void sample16i_rh_handler (void);
+extern void sample16i_crux_handler (void);
+extern void sample8_handler (void);
+extern void sample16s_handler (void);
+extern void sample16ss_handler (void);
+extern void sample16si_rh_handler (void);
+extern void sample16si_crux_handler (void);
+extern void sample8s_handler (void);
+extern void sample_ulaw_handler (void);
+extern void init_sound_table16 (void);
+extern void init_sound_table8 (void);
+
diff --git a/include/gfxfilter.h b/include/gfxfilter.h
new file mode 100755 (executable)
index 0000000..1770820
--- /dev/null
@@ -0,0 +1,60 @@
+
+#ifdef GFXFILTER
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long u32;
+
+extern void S2X_refresh (void);
+extern void S2X_render (void);
+extern void S2X_init (int dw, int dh, int aw, int ah, int mult, int ad, int dd);
+
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned long uint32;
+typedef int bool;
+
+extern void S2X_configure (int rb, int gb, int bb, int rs, int gs, int bs);
+extern int Init_2xSaI(int rb, int gb, int bb, int rs, int gs, int bs);
+extern void Super2xSaI(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height);
+extern void SuperEagle(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height);
+extern void _2xSaI(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height);
+extern void AdMame2x(u8 *srcPtr, u32 srcPitch, /* u8 deltaPtr, */
+              u8 *dstPtr, u32 dstPitch, int width, int height);
+extern void AdMame2x32(u8 *srcPtr, u32 srcPitch, /* u8 deltaPtr, */
+              u8 *dstPtr, u32 dstPitch, int width, int height);
+
+extern void hq_init(int rb, int gb, int bb, int rs, int gs, int bs);
+extern void hq2x_32(unsigned char*, unsigned char*, int, int, int, int, int);
+extern void hq3x_32(unsigned char*, unsigned char*, int, int, int, int, int);
+extern void hq3x_16(unsigned char*, unsigned char*, int, int, int, int, int);
+extern void hq4x_32(unsigned char*, unsigned char*, int, int, int, int, int);
+
+#define UAE_FILTER_NULL 1
+#define UAE_FILTER_DIRECT3D 2
+#define UAE_FILTER_OPENGL 3
+#define UAE_FILTER_SCALE2X 4
+#define UAE_FILTER_SUPEREAGLE 5
+#define UAE_FILTER_SUPER2XSAI 6
+#define UAE_FILTER_2XSAI 7
+#define UAE_FILTER_HQ 8
+
+#define UAE_FILTER_MODE_16 16
+#define UAE_FILTER_MODE_16_16 16
+#define UAE_FILTER_MODE_16_32 (16 | 8)
+#define UAE_FILTER_MODE_32 32
+#define UAE_FILTER_MODE_32_32 32
+#define UAE_FILTER_MODE_32_16 (32 | 8)
+
+
+struct uae_filter
+{
+    int type;
+    char *name, *cfgname;
+    int x[5];
+};
+
+extern struct uae_filter uaefilters[];
+extern struct uae_filter *usedfilter;
+
+#endif
diff --git a/include/gui.h b/include/gui.h
new file mode 100755 (executable)
index 0000000..6f78f0c
--- /dev/null
@@ -0,0 +1,43 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Interface to the Tcl/Tk GUI
+  *
+  * Copyright 1996 Bernd Schmidt
+  */
+
+extern int gui_init (void);
+extern int gui_update (void);
+extern void gui_exit (void);
+extern void gui_led (int, int);
+extern void gui_handle_events (void);
+extern void gui_filename (int, const char *);
+extern void gui_fps (int fps, int idle);
+extern void gui_changesettings (void);
+extern void gui_lock (void);
+extern void gui_unlock (void);
+extern void gui_hd_led (int);
+extern void gui_cd_led (int);
+extern unsigned int gui_ledstate;
+extern void gui_display(int shortcut);
+
+extern int no_gui;
+
+struct gui_info
+{
+    uae_u8 drive_motor[4];          /* motor on off */
+    uae_u8 drive_track[4];          /* rw-head track */
+    uae_u8 drive_writing[4];        /* drive is writing */
+    uae_u8 drive_disabled[4];      /* drive is disabled */
+    uae_u8 powerled;                /* state of power led */
+    uae_u8 drive_side;             /* floppy side */
+    uae_u8 hd;                     /* harddrive */
+    uae_u8 cd;                     /* CD */
+    int fps, idle;
+};
+#define NUM_LEDS (1 + 1 + 1 + 1 + 1 + 4)
+
+extern struct gui_info gui_data;
+
+/* Functions to be called when prefs are changed by non-gui code.  */
+extern void gui_update_gfx (void);
diff --git a/include/identify.h b/include/identify.h
new file mode 100755 (executable)
index 0000000..4da9bb8
--- /dev/null
@@ -0,0 +1,25 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Tables for labelling amiga internals. 
+  *
+  */
+               
+struct mem_labels
+{
+    const char *name;
+    uae_u32 adr;
+};
+
+struct customData
+{
+    const char *name;
+    uae_u32 adr;
+};
+
+
+extern struct mem_labels mem_labels[];
+extern struct mem_labels int_labels[];
+extern struct mem_labels trap_labels[];
+extern struct customData custd[];
+
diff --git a/include/inputdevice.h b/include/inputdevice.h
new file mode 100755 (executable)
index 0000000..3ddbfde
--- /dev/null
@@ -0,0 +1,129 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Joystick, mouse and keyboard emulation prototypes and definitions
+  *
+  * Copyright 1995 Bernd Schmidt
+  * Copyright 2001-2002 Toni Wilen
+  */
+
+
+#define IDTYPE_JOYSTICK 0
+#define IDTYPE_MOUSE 1
+#define IDTYPE_KEYBOARD 2
+
+struct inputdevice_functions {
+    int (*init)(void);
+    void (*close)(void);
+    int (*acquire)(int,int);
+    void (*unacquire)(int);
+    void (*read)(void);
+    int (*get_num)(void);
+    char* (*get_name)(int);
+    int (*get_widget_num)(int);
+    int (*get_widget_type)(int,int,char*,uae_u32*);
+    int (*get_widget_first)(int,int);
+};
+extern struct inputdevice_functions idev[3];
+extern struct inputdevice_functions inputdevicefunc_joystick;
+extern struct inputdevice_functions inputdevicefunc_mouse;
+extern struct inputdevice_functions inputdevicefunc_keyboard;
+extern int pause_emulation;
+
+struct uae_input_device_kbr_default {
+    int scancode;
+    int event;
+};
+
+#define IDEV_WIDGET_NONE 0
+#define IDEV_WIDGET_BUTTON 1
+#define IDEV_WIDGET_AXIS 2
+#define IDEV_WIDGET_KEY 3
+
+#define IDEV_MAPPED_AUTOFIRE_POSSIBLE 1
+#define IDEV_MAPPED_AUTOFIRE_SET 2
+
+#define ID_BUTTON_OFFSET 0
+#define ID_BUTTON_TOTAL 32
+#define ID_AXIS_OFFSET 32
+#define ID_AXIS_TOTAL 32
+
+extern int inputdevice_iterate (int devnum, int num, char *name, int *af);
+extern int inputdevice_set_mapping (int devnum, int num, char *name, int af, int sub);
+extern int inputdevice_get_mapped_name (int devnum, int num, int *pflags, char *name, int sub);
+extern void inputdevice_copyconfig (struct uae_prefs *src, struct uae_prefs *dst);
+extern void inputdevice_copy_single_config (struct uae_prefs *p, int src, int dst, int devnum);
+extern void inputdevice_swap_ports (struct uae_prefs *p, int devnum);
+extern void inputdevice_config_change (void);
+extern int inputdevice_config_change_test (void);
+extern int inputdevice_get_device_index (int devnum);
+extern char *inputdevice_get_device_name (int type, int devnum);
+extern int inputdevice_get_device_status (int devnum);
+extern void inputdevice_set_device_status (int devnum, int enabled);
+extern int inputdevice_get_device_total (int type);
+extern int inputdevice_get_widget_num (int devnum);
+extern int inputdevice_get_widget_type (int devnum, int num, char *name);
+
+extern void input_get_default_mouse (struct uae_input_device *uid);
+extern void input_get_default_joystick (struct uae_input_device *uid);
+
+#define DEFEVENT(A, B, C, D, E, F) INPUTEVENT_ ## A,
+enum inputevents {
+INPUTEVENT_ZERO,
+#include "inputevents.def"
+INPUTEVENT_END
+};
+#undef DEFEVENT
+
+enum mousestate { mousehack_unknown, mousehack_normal, mousehack_dontcare, mousehack_follow };
+
+extern void handle_cd32_joystick_cia (uae_u8, uae_u8);
+extern uae_u8 handle_parport_joystick (int port, uae_u8 pra, uae_u8 dra);
+extern uae_u8 handle_joystick_buttons (uae_u8);
+extern int getbuttonstate (int joy, int button);
+extern int getjoystate (int joy);
+
+extern void mousehack_set (enum mousestate);
+extern uae_u32 mousehack_helper (void);
+extern void mousehack_handle (int sprctl, int sprpos);
+
+extern void setmousebuttonstateall (int mouse, uae_u32 buttonbits, uae_u32 buttonmask);
+extern void setjoybuttonstateall (int joy, uae_u32 buttonbits, uae_u32 buttonmask);
+extern void setjoybuttonstate (int joy, int button, int state);
+extern void setmousebuttonstate (int mouse, int button, int state);
+extern void setjoystickstate (int joy, int axle, int state, int max);
+void setmousestate (int mouse, int axis, int data, int isabs);
+extern void inputdevice_updateconfig (struct uae_prefs *prefs);
+
+extern int inputdevice_translatekeycode (int keyboard, int scancode, int state);
+extern void inputdevice_setkeytranslation (struct uae_input_device_kbr_default *trans);
+extern void handle_input_event (int nr, int state, int max, int autofire);
+extern void inputdevice_do_keyboard (int code, int state);
+
+extern uae_u16 potgo_value;
+extern uae_u16 POTGOR (void);
+extern void POTGO (uae_u16 v);
+extern uae_u16 POT0DAT (void);
+extern uae_u16 POT1DAT (void);
+extern void JOYTEST (uae_u16 v);
+extern uae_u16 JOY0DAT (void);
+extern uae_u16 JOY1DAT (void);
+
+extern void inputdevice_vsync (void);
+extern void inputdevice_hsync (void);
+
+extern void write_inputdevice_config (struct uae_prefs *p, FILE *f);
+extern void read_inputdevice_config (struct uae_prefs *p, char *option, char *value);
+extern void reset_inputdevice_config (struct uae_prefs *pr);
+
+extern void inputdevice_init (void);
+extern void inputdevice_close (void);
+extern void inputdevice_default_prefs (struct uae_prefs *p);
+
+extern void inputdevice_acquire (int);
+extern void inputdevice_unacquire (void);
+
+extern void indicator_leds (int num, int state);
+
+extern void warpmode (int mode);
+extern void pausemode (int mode);
diff --git a/include/keyboard.h b/include/keyboard.h
new file mode 100755 (executable)
index 0000000..dd1b4b0
--- /dev/null
@@ -0,0 +1,139 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Amiga keycodes
+  *
+  * (c) 1995 Bernd Schmidt
+  */
+
+/* First, two dummies */
+#define AK_mousestuff 0x100
+#define AK_inhibit 0x101
+/* This mutates into AK_CTRL in keybuf.c. */
+#define AK_RCTRL 0x7f
+
+#define AK_A 0x20
+#define AK_B 0x35
+#define AK_C 0x33
+#define AK_D 0x22
+#define AK_E 0x12
+#define AK_F 0x23
+#define AK_G 0x24
+#define AK_H 0x25
+#define AK_I 0x17
+#define AK_J 0x26
+#define AK_K 0x27
+#define AK_L 0x28
+#define AK_M 0x37
+#define AK_N 0x36
+#define AK_O 0x18
+#define AK_P 0x19
+#define AK_Q 0x10
+#define AK_R 0x13
+#define AK_S 0x21
+#define AK_T 0x14
+#define AK_U 0x16
+#define AK_V 0x34
+#define AK_W 0x11
+#define AK_X 0x32
+#define AK_Y 0x15
+#define AK_Z 0x31
+
+#define AK_0 0x0A
+#define AK_1 0x01
+#define AK_2 0x02
+#define AK_3 0x03
+#define AK_4 0x04
+#define AK_5 0x05
+#define AK_6 0x06
+#define AK_7 0x07
+#define AK_8 0x08
+#define AK_9 0x09
+
+#define AK_NP0 0x0F
+#define AK_NP1 0x1D
+#define AK_NP2 0x1E
+#define AK_NP3 0x1F
+#define AK_NP4 0x2D
+#define AK_NP5 0x2E
+#define AK_NP6 0x2F
+#define AK_NP7 0x3D
+#define AK_NP8 0x3E
+#define AK_NP9 0x3F
+
+#define AK_NPDIV 0x5C
+#define AK_NPMUL 0x5D
+#define AK_NPSUB 0x4A
+#define AK_NPADD 0x5E
+#define AK_NPDEL 0x3C
+#define AK_NPLPAREN 0x5A
+#define AK_NPRPAREN 0x5B
+
+#define AK_F1 0x50
+#define AK_F2 0x51
+#define AK_F3 0x52
+#define AK_F4 0x53
+#define AK_F5 0x54
+#define AK_F6 0x55
+#define AK_F7 0x56
+#define AK_F8 0x57
+#define AK_F9 0x58
+#define AK_F10 0x59
+
+#define AK_UP 0x4C
+#define AK_DN 0x4D
+#define AK_LF 0x4F
+#define AK_RT 0x4E
+
+#define AK_SPC 0x40
+#define AK_BS 0x41
+#define AK_TAB 0x42
+#define AK_ENT 0x43
+#define AK_RET 0x44
+#define AK_ESC 0x45
+#define AK_DEL 0x46
+
+#define AK_LSH 0x60
+#define AK_RSH 0x61
+#define AK_CAPSLOCK 0x62
+#define AK_CTRL 0x63
+#define AK_LALT 0x64
+#define AK_RALT 0x65
+#define AK_LAMI 0x66
+#define AK_RAMI 0x67
+#define AK_HELP 0x5F
+
+/* The following have different mappings on national keyboards */
+
+#define AK_LBRACKET 0x1A
+#define AK_RBRACKET 0x1B
+#define AK_SEMICOLON 0x29
+#define AK_COMMA 0x38
+#define AK_PERIOD 0x39
+#define AK_SLASH 0x3A
+#define AK_BACKSLASH 0x0D
+#define AK_QUOTE 0x2A
+#define AK_NUMBERSIGN 0x2B
+#define AK_LTGT 0x30
+#define AK_BACKQUOTE 0x00
+#define AK_MINUS 0x0B
+#define AK_EQUAL 0x0C
+
+#define AK_RESETWARNING 0x78
+#define AK_INIT_POWERUP 0xfd
+#define AK_TERM_POWERUP 0xfe
+
+// KB LED stuff
+
+#define KBLED_NUMLOCK 1
+#define KBLED_CAPSLOCK 2
+#define KBLED_SCROLLLOCK 4
+
+enum aks { AKS_ENTERGUI = 0x200, AKS_SCREENSHOT, AKS_FREEZEBUTTON,
+    AKS_FLOPPY0, AKS_FLOPPY1, AKS_FLOPPY2, AKS_FLOPPY3,
+    AKS_EFLOPPY0, AKS_EFLOPPY1, AKS_EFLOPPY2, AKS_EFLOPPY3,
+    AKS_TOGGLEFULLSCREEN, AKS_ENTERDEBUGGER, AKS_IRQ7,
+    AKS_PAUSE, AKS_WARP, AKS_INHIBITSCREEN, AKS_STATEREWIND,
+    AKS_VOLDOWN, AKS_VOLUP, AKS_VOLMUTE, AKS_QUIT,
+    AKS_STATESAVE, AKS_STATERESTORE
+}; 
diff --git a/include/keybuf.h b/include/keybuf.h
new file mode 100755 (executable)
index 0000000..65e3cb2
--- /dev/null
@@ -0,0 +1,16 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Keyboard buffer. Not really needed for X, but for SVGAlib and possibly
+  * Mac and DOS ports.
+  *
+  * (c) 1996 Bernd Schmidt
+  */
+
+extern int get_next_key (void);
+extern int keys_available (void);
+extern void record_key (int);
+extern void keybuf_init (void);
+extern void joystick_setting_changed (void);
+extern int getcapslockstate (void);
+extern void setcapslockstate (int);
\ No newline at end of file
diff --git a/include/mackbd.h b/include/mackbd.h
new file mode 100755 (executable)
index 0000000..bbd5764
--- /dev/null
@@ -0,0 +1,109 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Mac keycodes
+  *
+  * (c) 1996 Ernesto Corvi
+  */
+
+#define kUpArrowKeyMap                         0x7E    /* key map offset for up arrow */
+#define kDownArrowKeyMap                       0x7D    /* key map offset for down arrow */
+#define kRightArrowKeyMap                      0x7C    /* key map offset for right arrow */
+#define kLeftArrowKeyMap                       0x7B    /* key map offset for left arrow */
+
+#define kBackSpaceKeyMap                       0x33
+#define kReturnKeyMap                          0x24
+#define kEscapeKeyMap                          0x35
+#define kLBracketKeyMap                                0x21
+#define kRBracketKeyMap                                0x1E
+#define kCommaKeyMap                           0x2B
+#define kSlashKeyMap                           0x2C
+#define kSemiColonKeyMap                       0x29
+#define kMinusKeyMap                           0x1B
+#define kEqualKeyMap                           0x18
+#define kQuoteKeyMap                           0x27
+
+#define k0KeyMap                               0x1D
+#define k1KeyMap                               0x12
+#define k2KeyMap                               0x13
+#define k3KeyMap                                       0x14
+#define k4KeyMap                               0x15
+#define k5KeyMap                               0x17
+#define k6KeyMap                               0x16
+#define k7KeyMap                                       0x1A
+#define k8KeyMap                               0x1C
+#define k9KeyMap                               0x19
+
+#define kAKeyMap                               0x00
+#define        kBKeyMap                                0x0B
+#define        kCKeyMap                                0x08
+#define        kDKeyMap                                0x02
+#define        kEKeyMap                                0x0E
+#define        kFKeyMap                                0x03
+#define        kGKeyMap                                0x05
+#define        kHKeyMap                                0x04
+#define        kIKeyMap                                0x22
+#define        kJKeyMap                                0x26
+#define        kKKeyMap                                0x28
+#define        kLKeyMap                                0x25
+#define        kMKeyMap                                0x2E
+#define        kNKeyMap                                0x2D
+#define        kOKeyMap                                0x1F
+#define        kPKeyMap                                0x23
+#define        kQKeyMap                                0x0C
+#define        kRKeyMap                                0x0F
+#define kSKeyMap                               0x01
+#define kTKeyMap                                       0x11
+#define kUKeyMap                               0x20
+#define kVKeyMap                               0x09
+#define kWKeyMap                               0x0D
+#define kXKeyMap                                       0x07
+#define kYKeyMap                               0x10
+#define kZKeyMap                               0x06
+#define kPeriodKeyMap                          0x2F
+#define        kCommandKeyMap                          0x37
+#define kSpaceBarMap                           0x31
+#define        kTabKeyMap                              0x30
+#define        kControlKeyMap                          0x3B
+#define        kOptionKeyMap                           0x3A
+#define        kCapsLockKeyMap                         0x39
+#define        kShiftKeyMap                            0x38
+#define        kPgUpKeyMap                             0x74
+#define        kPgDnKeyMap                             0x79
+#define kBackSlash                                     0x2A
+
+
+#define kF1KeyMap                                      0x7A
+#define kF2KeyMap                                      0x78
+#define kF3KeyMap                                      0x63
+#define kF4KeyMap                                      0x76
+#define kF5KeyMap                                      0x60
+#define kF6KeyMap                                      0x61
+#define kF7KeyMap                                      0x62
+#define kF8KeyMap                                      0x64
+#define kF9KeyMap                                      0x65
+#define kF10KeyMap                                     0x6D
+#define kF11KeyMap                                     0x67
+#define kF12KeyMap                                     0x6F
+
+#define        kShiftRawKey                            0x3F
+#define        kControlRawKey                          0x3C
+#define kOptionRawKey                          0x3D
+#define kCapsRawKey                                    0x3E
+#define kCommandRawKey                         0x30
+#define kUpRawKey                                      0x79
+#define kDownRawKey                                    0x7A
+#define kLeftRawKey                                    0x7C
+#define kRightRawKey                           0x7B
+#define kSpaceRawKey                           0x36
+
+#define kKP0KeyMap                                     0x52
+#define kKP1KeyMap                                     0x53
+#define kKP2KeyMap                                     0x54
+#define kKP3KeyMap                                     0x55
+#define kKP4KeyMap                                     0x56
+#define kKP5KeyMap                                     0x57
+#define kKP6KeyMap                                     0x58
+#define kKP7KeyMap                                     0x59
+#define kKP8KeyMap                                     0x5B
+#define kKP9KeyMap                                     0x5C
diff --git a/include/memory.h b/include/memory.h
new file mode 100755 (executable)
index 0000000..ffe4db1
--- /dev/null
@@ -0,0 +1,240 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * memory management
+  *
+  * Copyright 1995 Bernd Schmidt
+  */
+
+extern void memory_reset (void);
+extern void a1000_reset (void);
+
+#ifdef JIT
+extern int special_mem;
+#define S_READ 1
+#define S_WRITE 2
+extern void *cache_alloc (int);
+extern void cache_free (void*);
+#endif
+
+typedef uae_u32 (*mem_get_func)(uaecptr) REGPARAM;
+typedef void (*mem_put_func)(uaecptr, uae_u32) REGPARAM;
+typedef uae_u8 *(*xlate_func)(uaecptr) REGPARAM;
+typedef int (*check_func)(uaecptr, uae_u32) REGPARAM;
+
+extern char *address_space, *good_address_map;
+extern uae_u8 *chipmemory;
+
+extern uae_u32 allocated_chipmem;
+extern uae_u32 allocated_fastmem;
+extern uae_u32 allocated_bogomem;
+extern uae_u32 allocated_gfxmem;
+extern uae_u32 allocated_z3fastmem;
+extern uae_u32 allocated_a3000mem;
+
+extern uae_u32 wait_cpu_cycle_read (uaecptr addr, int mode);
+extern uae_u32 wait_cpu_cycle_read_cycles (uaecptr addr, int mode, int *cycles);
+extern void wait_cpu_cycle_write (uaecptr addr, int mode, uae_u32 v);
+
+#undef DIRECT_MEMFUNCS_SUCCESSFUL
+#include "machdep/maccess.h"
+
+#ifndef CAN_MAP_MEMORY
+#undef USE_COMPILER
+#endif
+
+#ifdef JIT
+#if defined(USE_COMPILER) && !defined(USE_MAPPED_MEMORY)
+#define USE_MAPPED_MEMORY
+#endif
+#endif
+
+#define kickmem_size 0x080000
+
+#define chipmem_start 0x00000000
+#define bogomem_start 0x00C00000
+#define a3000mem_start 0x07000000
+#define kickmem_start 0x00F80000
+
+extern int ersatzkickfile;
+extern int cloanto_rom;
+extern uae_u16 kickstart_version;
+
+extern uae_u8* baseaddr[];
+
+typedef struct {
+    /* These ones should be self-explanatory... */
+    mem_get_func lget, wget, bget;
+    mem_put_func lput, wput, bput;
+    /* Use xlateaddr to translate an Amiga address to a uae_u8 * that can
+     * be used to address memory without calling the wget/wput functions.
+     * This doesn't work for all memory banks, so this function may call
+     * abort(). */
+    xlate_func xlateaddr;
+    /* To prevent calls to abort(), use check before calling xlateaddr.
+     * It checks not only that the memory bank can do xlateaddr, but also
+     * that the pointer points to an area of at least the specified size.
+     * This is used for example to translate bitplane pointers in custom.c */
+    check_func check;
+    /* For those banks that refer to real memory, we can save the whole trouble
+       of going through function calls, and instead simply grab the memory
+       ourselves. This holds the memory address where the start of memory is
+       for this particular bank. */
+    uae_u8 *baseaddr;
+} addrbank;
+
+extern uae_u8 *filesysory;
+extern uae_u8 *rtarea;
+
+extern addrbank chipmem_bank;
+extern addrbank chipmem_bank_ce2;
+extern addrbank kickmem_bank;
+extern addrbank custom_bank;
+extern addrbank clock_bank;
+extern addrbank cia_bank;
+extern addrbank rtarea_bank;
+extern addrbank expamem_bank;
+extern addrbank fastmem_bank;
+extern addrbank gfxmem_bank;
+
+extern void rtarea_init (void);
+extern void rtarea_setup (void);
+extern void expamem_init (void);
+extern void expamem_reset (void);
+
+extern uae_u32 gfxmem_start;
+extern uae_u8 *gfxmemory;
+extern uae_u32 gfxmem_mask;
+extern int address_space_24;
+
+/* Default memory access functions */
+
+extern int default_check(uaecptr addr, uae_u32 size) REGPARAM;
+extern uae_u8 *default_xlate(uaecptr addr) REGPARAM;
+
+#define bankindex(addr) (((uaecptr)(addr)) >> 16)
+
+extern addrbank *mem_banks[65536];
+extern uae_u8 *baseaddr[65536];
+#define get_mem_bank(addr) (*mem_banks[bankindex(addr)])
+#define put_mem_bank(addr, b, realstart) do { \
+    (mem_banks[bankindex(addr)] = (b)); \
+    if ((b)->baseaddr) \
+        baseaddr[bankindex(addr)] = (b)->baseaddr - (realstart); \
+    else \
+        baseaddr[bankindex(addr)] = (uae_u8*)(((long)b)+1); \
+} while (0)
+
+extern void memory_init (void);
+extern void memory_cleanup (void);
+extern void map_banks (addrbank *bank, int first, int count, int realsize);
+extern void map_overlay (int chip);
+
+#ifndef NO_INLINE_MEMORY_ACCESS
+
+#define longget(addr) (call_mem_get_func(get_mem_bank(addr).lget, addr))
+#define wordget(addr) (call_mem_get_func(get_mem_bank(addr).wget, addr))
+#define byteget(addr) (call_mem_get_func(get_mem_bank(addr).bget, addr))
+#define longput(addr,l) (call_mem_put_func(get_mem_bank(addr).lput, addr, l))
+#define wordput(addr,w) (call_mem_put_func(get_mem_bank(addr).wput, addr, w))
+#define byteput(addr,b) (call_mem_put_func(get_mem_bank(addr).bput, addr, b))
+
+#else
+
+extern uae_u32 alongget(uaecptr addr);
+extern uae_u32 awordget(uaecptr addr);
+extern uae_u32 longget(uaecptr addr);
+extern uae_u32 wordget(uaecptr addr);
+extern uae_u32 byteget(uaecptr addr);
+extern void longput(uaecptr addr, uae_u32 l);
+extern void wordput(uaecptr addr, uae_u32 w);
+extern void byteput(uaecptr addr, uae_u32 b);
+
+#endif
+
+#ifndef MD_HAVE_MEM_1_FUNCS
+
+#define longget_1 longget
+#define wordget_1 wordget
+#define byteget_1 byteget
+#define longput_1 longput
+#define wordput_1 wordput
+#define byteput_1 byteput
+
+#endif
+
+STATIC_INLINE uae_u32 get_long(uaecptr addr)
+{
+    return longget_1(addr);
+}
+STATIC_INLINE uae_u32 get_word(uaecptr addr)
+{
+    return wordget_1(addr);
+}
+STATIC_INLINE uae_u32 get_byte(uaecptr addr)
+{
+    return byteget_1(addr);
+}
+STATIC_INLINE void put_long(uaecptr addr, uae_u32 l)
+{
+    longput_1(addr, l);
+}
+STATIC_INLINE void put_word(uaecptr addr, uae_u32 w)
+{
+    wordput_1(addr, w);
+}
+STATIC_INLINE void put_byte(uaecptr addr, uae_u32 b)
+{
+    byteput_1(addr, b);
+}
+
+STATIC_INLINE uae_u8 *get_real_address(uaecptr addr)
+{
+    return get_mem_bank(addr).xlateaddr(addr);
+}
+
+STATIC_INLINE int valid_address(uaecptr addr, uae_u32 size)
+{
+    return get_mem_bank(addr).check(addr, size);
+}
+
+/* For faster access in custom chip emulation.  */
+extern uae_u32 chipmem_lget (uaecptr) REGPARAM;
+extern uae_u32 chipmem_wget (uaecptr) REGPARAM;
+extern uae_u32 chipmem_bget (uaecptr) REGPARAM;
+extern void chipmem_lput (uaecptr, uae_u32) REGPARAM;
+extern void chipmem_wput (uaecptr, uae_u32) REGPARAM;
+extern void chipmem_bput (uaecptr, uae_u32) REGPARAM;
+
+extern uae_u32 chipmem_mask, kickmem_mask;
+extern uae_u8 *kickmemory;
+extern addrbank dummy_bank;
+
+/* 68020+ Chip RAM DMA contention emulation */
+extern uae_u32 chipmem_lget_ce2 (uaecptr) REGPARAM;
+extern uae_u32 chipmem_wget_ce2 (uaecptr) REGPARAM;
+extern uae_u32 chipmem_bget_ce2 (uaecptr) REGPARAM;
+extern void chipmem_lput_ce2 (uaecptr, uae_u32) REGPARAM;
+extern void chipmem_wput_ce2 (uaecptr, uae_u32) REGPARAM;
+extern void chipmem_bput_c2 (uaecptr, uae_u32) REGPARAM;
+
+#ifdef NATMEM_OFFSET
+
+typedef struct shmpiece_reg {
+    uae_u8 *native_address;
+    int id;
+    uae_u32 size;
+    struct shmpiece_reg *next;
+    struct shmpiece_reg *prev;
+} shmpiece;
+
+extern shmpiece *shm_start;
+
+#endif
+
+extern int canbang;
+
+extern uae_u8 *mapped_malloc (size_t, char *);
+extern void mapped_free (uae_u8 *);
+extern void clearexec (void);
+extern void mapkick (void);
\ No newline at end of file
diff --git a/include/native2amiga.h b/include/native2amiga.h
new file mode 100755 (executable)
index 0000000..ca986dd
--- /dev/null
@@ -0,0 +1,56 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Call (some) Amiga Exec functions outside the main UAE thread
+  * and without stack magic.
+  *
+  * Copyright 1999 Patrick Ohly
+  * 
+  * Uses the EXTER interrupt that is setup in filesys.c
+  * and some of it needs thread support.
+  */
+
+/*
+ * The following functions do exactly the same thing as their
+ * Amiga counterpart, but can be called in situation where calling
+ * the exec.library functions is impossible.
+ */
+#ifdef SUPPORT_THREADS
+void uae_Cause(uaecptr interrupt);
+void uae_ReplyMsg(uaecptr msg);
+void uae_PutMsg(uaecptr port, uaecptr msg);
+void uae_Signal(uaecptr task, uae_u32 mask);
+void uae_NotificationHack(uaecptr, uaecptr);
+#endif
+void uae_NewList(uaecptr list);
+
+/*
+ * The following functions are shortcuts for calling
+ * the exec.library function with CallLib(), so they
+ * are only available in a trap function. This trap
+ * function has to be setup with deftrap2() and
+ * TRAPFLAG_EXTRA_STACK and stack magic is required.
+ */
+uaecptr uae_AllocMem (uae_u32 size, uae_u32 flags);
+void uae_FreeMem (uaecptr memory, uae_u32 size);
+
+
+/*
+ * to be called when setting up the hardware
+ */
+void native2amiga_install (void);
+
+/*
+ * to be called when the Amiga boots, i.e. by filesys_diagentry()
+ */
+void native2amiga_startup (void);
+
+/**** internal stuff ****/
+#ifdef SUPPORT_THREADS
+/* This pipe is filled by Signal() with pairs of
+ * (uae_u32)0/(uaecptr)task/(uae_u32)signal_set,
+ * by PutMsg() with (uae_u32)1/(uaecptr)port/(uaecptr)msg and by
+ * ReplyMsg() with (uae_u32)2/(uaecptr)msg.
+ * It's emptied via exter_int_helper by the EXTER interrupt. */
+extern smp_comm_pipe native2amiga_pending;
+#endif
diff --git a/include/newcpu.h b/include/newcpu.h
new file mode 100755 (executable)
index 0000000..379b00f
--- /dev/null
@@ -0,0 +1,300 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * MC68000 emulation
+  *
+  * Copyright 1995 Bernd Schmidt
+  */
+
+#include "readcpu.h"
+#include "machdep/m68k.h"
+#include "events.h"
+
+#ifndef SET_CFLG
+
+#define SET_CFLG(x) (CFLG = (x))
+#define SET_NFLG(x) (NFLG = (x))
+#define SET_VFLG(x) (VFLG = (x))
+#define SET_ZFLG(x) (ZFLG = (x))
+#define SET_XFLG(x) (XFLG = (x))
+
+#define GET_CFLG CFLG
+#define GET_NFLG NFLG
+#define GET_VFLG VFLG
+#define GET_ZFLG ZFLG
+#define GET_XFLG XFLG
+
+#define CLEAR_CZNV do { \
+ SET_CFLG (0); \
+ SET_ZFLG (0); \
+ SET_NFLG (0); \
+ SET_VFLG (0); \
+} while (0)
+
+#define COPY_CARRY (SET_XFLG (GET_CFLG))
+#endif
+
+extern int areg_byteinc[];
+extern int imm8_table[];
+
+extern int movem_index1[256];
+extern int movem_index2[256];
+extern int movem_next[256];
+
+#ifdef FPUEMU
+extern int fpp_movem_index1[256];
+extern int fpp_movem_index2[256];
+extern int fpp_movem_next[256];
+#endif
+
+extern int broken_in;
+
+typedef unsigned long cpuop_func (uae_u32) REGPARAM;
+
+struct cputbl {
+    cpuop_func *handler;
+    int specific;
+    uae_u32 opcode;
+};
+
+extern unsigned long op_illg (uae_u32) REGPARAM;
+
+typedef char flagtype;
+
+#ifdef FPUEMU
+/* You can set this to long double to be more accurate. However, the
+   resulting alignment issues will cost a lot of performance in some
+   apps */
+#define USE_LONG_DOUBLE 0
+
+#if USE_LONG_DOUBLE
+typedef long double fptype;
+#else
+typedef double fptype;
+#endif
+#endif
+
+extern struct regstruct
+{
+    uae_u32 regs[16];
+    uaecptr  usp,isp,msp;
+    uae_u16 sr;
+    flagtype t1;
+    flagtype t0;
+    flagtype s;
+    flagtype m;
+    flagtype x;
+    flagtype stopped;
+    int intmask;
+
+    uae_u32 pc;
+    uae_u8 *pc_p;
+    uae_u8 *pc_oldp;
+
+    uae_u32 vbr,sfc,dfc;
+
+#ifdef FPUEMU
+    fptype fp[8];
+    fptype fp_result;
+
+    uae_u32 fpcr,fpsr,fpiar;
+    uae_u32 fpsr_highbyte;
+#endif
+
+    uae_u32 spcflags;
+    uae_u32 kick_mask;
+    uae_u32 address_space_mask;
+
+    uae_u16 irc;
+    uae_u16 ir;
+
+    uae_u8 panic;
+    uae_u32 panic_pc, panic_addr;
+
+} regs, lastint_regs;
+
+typedef struct {
+  uae_u16* location;
+  uae_u8  cycles;
+  uae_u8  specmem;
+  uae_u8  dummy2;
+  uae_u8  dummy3;
+} cpu_history;
+
+struct blockinfo_t;
+
+typedef union {
+    cpuop_func* handler;
+    struct blockinfo_t* bi;
+} cacheline;
+
+extern signed long pissoff;
+
+STATIC_INLINE uae_u32 munge24(uae_u32 x)
+{
+    return x & regs.address_space_mask;
+}
+
+extern unsigned long irqcycles[15];
+extern int irqdelay[15];
+
+STATIC_INLINE void set_special (uae_u32 x)
+{
+    regs.spcflags |= x;
+    cycles_do_special();
+}
+
+STATIC_INLINE void unset_special (uae_u32 x)
+{
+    regs.spcflags &= ~x;
+}
+
+#define m68k_dreg(r,num) ((r).regs[(num)])
+#define m68k_areg(r,num) (((r).regs + 8)[(num)])
+
+#if !defined USE_COMPILER
+STATIC_INLINE void m68k_setpc (uaecptr newpc)
+{
+    regs.pc_p = regs.pc_oldp = get_real_address (newpc);
+    regs.pc = newpc;
+}
+#else
+extern void m68k_setpc (uaecptr newpc);
+#endif
+
+STATIC_INLINE uaecptr m68k_getpc (void)
+{
+    return regs.pc + ((char *)regs.pc_p - (char *)regs.pc_oldp);
+}
+
+STATIC_INLINE uaecptr m68k_getpc_p (uae_u8 *p)
+{
+    return regs.pc + ((char *)p - (char *)regs.pc_oldp);
+}
+
+#define get_ibyte(o) do_get_mem_byte((uae_u8 *)(regs.pc_p + (o) + 1))
+#define get_iword(o) do_get_mem_word((uae_u16 *)(regs.pc_p + (o)))
+#define get_ilong(o) do_get_mem_long((uae_u32 *)(regs.pc_p + (o)))
+
+#define m68k_incpc(o) (regs.pc_p += (o))
+
+/* These are only used by the 68020/68881 code, and therefore don't
+ * need to handle prefetch.  */
+STATIC_INLINE uae_u32 next_ibyte (void)
+{
+    uae_u32 r = get_ibyte (0);
+    m68k_incpc (2);
+    return r;
+}
+
+STATIC_INLINE uae_u32 next_iword (void)
+{
+    uae_u32 r = get_iword (0);
+    m68k_incpc (2);
+    return r;
+}
+
+STATIC_INLINE uae_u32 next_ilong (void)
+{
+    uae_u32 r = get_ilong (0);
+    m68k_incpc (4);
+    return r;
+}
+
+#ifdef USE_COMPILER
+extern void m68k_setpc_fast (uaecptr newpc);
+extern void m68k_setpc_bcc (uaecptr newpc);
+extern void m68k_setpc_rte (uaecptr newpc);
+#else
+#define m68k_setpc_fast m68k_setpc
+#define m68k_setpc_bcc  m68k_setpc
+#define m68k_setpc_rte  m68k_setpc
+#endif
+
+STATIC_INLINE void m68k_setstopped (int stop)
+{
+    regs.stopped = stop;
+    /* A traced STOP instruction drops through immediately without
+       actually stopping.  */
+    if (stop && (regs.spcflags & SPCFLAG_DOTRACE) == 0)
+       set_special (SPCFLAG_STOP);
+}
+
+extern uae_u32 get_disp_ea_020 (uae_u32 base, uae_u32 dp);
+extern uae_u32 get_disp_ea_000 (uae_u32 base, uae_u32 dp);
+
+extern uae_s32 ShowEA (void *, uae_u16 opcode, int reg, amodes mode, wordsizes size, char *buf);
+
+extern void MakeSR (void);
+extern void MakeFromSR (void);
+extern void Exception (int, uaecptr);
+extern void Interrupt (int nr);
+extern void dump_counts (void);
+extern int m68k_move2c (int, uae_u32 *);
+extern int m68k_movec2 (int, uae_u32 *);
+extern void m68k_divl (uae_u32, uae_u32, uae_u16, uaecptr);
+extern void m68k_mull (uae_u32, uae_u32, uae_u16);
+extern void init_m68k (void);
+extern void init_m68k_full (void);
+extern void m68k_go (int);
+extern void m68k_dumpstate (void *, uaecptr *);
+extern void m68k_disasm (void *, uaecptr, uaecptr *, int);
+extern void sm68k_disasm(char *, char *, uaecptr addr, uaecptr *nextpc);
+extern void m68k_reset (void);
+
+extern void mmu_op (uae_u32, uae_u16);
+
+extern void fpp_opp (uae_u32, uae_u16);
+extern void fdbcc_opp (uae_u32, uae_u16);
+extern void fscc_opp (uae_u32, uae_u16);
+extern void ftrapcc_opp (uae_u32,uaecptr);
+extern void fbcc_opp (uae_u32, uaecptr, uae_u32);
+extern void fsave_opp (uae_u32);
+extern void frestore_opp (uae_u32);
+
+extern void exception3 (uae_u32 opcode, uaecptr addr, uaecptr fault);
+extern void exception3i (uae_u32 opcode, uaecptr addr, uaecptr fault);
+extern void exception2 (uaecptr addr, uaecptr fault);
+extern void cpureset (void);
+
+extern void fill_prefetch_slow (void);
+
+#define CPU_OP_NAME(a) op ## a
+
+/* 68040 */
+extern struct cputbl op_smalltbl_0_ff[];
+/* 68020 + 68881 */
+extern struct cputbl op_smalltbl_1_ff[];
+/* 68020 */
+extern struct cputbl op_smalltbl_2_ff[];
+/* 68010 */
+extern struct cputbl op_smalltbl_3_ff[];
+/* 68000 */
+extern struct cputbl op_smalltbl_4_ff[];
+/* 68000 slow but compatible.  */
+extern struct cputbl op_smalltbl_5_ff[];
+/* 68000 slow but compatible and cycle-exact.  */
+extern struct cputbl op_smalltbl_6_ff[];
+
+extern cpuop_func *cpufunctbl[65536] ASM_SYM_FOR_FUNC ("cpufunctbl");
+
+  
+/* Flags for Bernie during development/debugging. Should go away eventually */
+#define DISTRUST_CONSISTENT_MEM 0
+#define TAGMASK 0x000fffff
+#define TAGSIZE (TAGMASK+1)
+#define MAXRUN 1024
+
+extern uae_u8* start_pc_p;
+extern uae_u32 start_pc;
+
+#define cacheline(x) (((uae_u32)x)&TAGMASK)
+
+void newcpu_showstate(void);
+
+#ifdef JIT
+extern void flush_icache(int n);
+extern void compemu_reset(void);
+#else
+#define flush_icache(X) do {} while (0)
+#endif
diff --git a/include/options.h b/include/options.h
new file mode 100755 (executable)
index 0000000..b41ec08
--- /dev/null
@@ -0,0 +1,368 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Stuff
+  *
+  * Copyright 1995, 1996 Ed Hanway
+  * Copyright 1995-2001 Bernd Schmidt
+  */
+
+#define UAEMAJOR 0
+#define UAEMINOR 8
+#define UAESUBREV 26
+
+typedef enum { KBD_LANG_US, KBD_LANG_DK, KBD_LANG_DE, KBD_LANG_SE, KBD_LANG_FR, KBD_LANG_IT, KBD_LANG_ES } KbdLang;
+
+extern long int version;
+
+struct uaedev_mount_info;
+
+struct strlist {
+    struct strlist *next;
+    char *option, *value;
+    int unknown;
+};
+
+/* maximum number native input devices supported (single type) */
+#define MAX_INPUT_DEVICES 6
+/* maximum number of native input device's buttons and axles supported */
+#define MAX_INPUT_DEVICE_EVENTS 256
+/* 4 different customization settings */
+#define MAX_INPUT_SETTINGS 4
+#define MAX_INPUT_SUB_EVENT 4
+#define MAX_INPUT_SIMULTANEOUS_KEYS 4
+
+struct uae_input_device {
+    char *name;
+    uae_s16 eventid[MAX_INPUT_DEVICE_EVENTS][MAX_INPUT_SUB_EVENT];
+    uae_u16 flags[MAX_INPUT_DEVICE_EVENTS][MAX_INPUT_SUB_EVENT];
+    uae_s16 extra[MAX_INPUT_DEVICE_EVENTS][MAX_INPUT_SIMULTANEOUS_KEYS];
+    uae_u8 enabled;
+};
+
+#define MAX_SPARE_DRIVES 20
+
+#define CONFIG_TYPE_HARDWARE 1
+#define CONFIG_TYPE_HOST 2
+
+struct uae_prefs {
+
+    struct strlist *all_lines;
+
+    char description[256];
+    char info[256];
+    int config_version;
+
+    int illegal_mem;
+    int no_xhair;
+    int use_serial;
+    int serial_demand;
+    int serial_hwctsrts;
+    int serial_direct;
+    int parallel_demand;
+    int use_gfxlib;
+    int socket_emu;
+
+    int start_debugger;
+    int start_gui;
+
+    KbdLang keyboard_lang;
+    int test_drawing_speed;
+
+    int produce_sound;
+    int stereo;
+    int mixed_stereo;
+    int sound_bits;
+    int sound_freq;
+    int sound_maxbsiz;
+    int sound_interpol;
+    int sound_adjust;
+    int sound_filter;
+    int sound_volume;
+
+    int comptrustbyte;
+    int comptrustword;
+    int comptrustlong;
+    int comptrustnaddr;
+    int compnf;
+    int compforcesettings;
+    int compfpu;
+    int comp_midopt;
+    int comp_lowopt;
+
+    int comp_hardflush;
+    int comp_constjump;
+    int comp_oldsegv;
+
+    int cachesize;
+    int optcount[10];
+
+    int avoid_cmov;
+    int avoid_dga;
+    int avoid_vid;
+    uae_u32 override_dga_address;
+
+    int gfx_display;
+    int gfx_framerate;
+    int gfx_width_win, gfx_height_win;
+    int gfx_width_fs, gfx_height_fs;
+    int gfx_width, gfx_height;
+    int gfx_refreshrate;
+    int gfx_vsync;
+    int gfx_lores;
+    int gfx_linedbl;
+    int gfx_correct_aspect;
+    int gfx_afullscreen;
+    int gfx_pfullscreen;
+    int gfx_xcenter;
+    int gfx_ycenter;
+    int gfx_hue, gfx_saturation, gfx_luminance, gfx_contrast, gfx_gamma;
+
+    int gfx_filter;
+    int gfx_filter_scanlines;
+    int gfx_filter_scanlineratio;
+    int gfx_filter_scanlinelevel;
+    int gfx_filter_horiz_zoom, gfx_filter_vert_zoom;
+    int gfx_filter_horiz_offset, gfx_filter_vert_offset;
+    int gfx_filter_filtermode;
+    int color_mode;
+
+    int immediate_blits;
+    unsigned int chipset_mask;
+    int ntscmode;
+    int collision_level;
+    int leds_on_screen;
+    int keyboard_leds[3];
+    int keyboard_leds_in_use;
+    int fast_copper;
+    int scsi;
+    int catweasel_io;
+    int cpu_idle;
+    int cpu_cycle_exact;
+    int blitter_cycle_exact;
+    int floppy_speed;
+    int tod_hack;
+    uae_u32 maprom;
+
+    char df[4][256];
+    char dfxlist[MAX_SPARE_DRIVES][256];
+    char romfile[256];
+    char romextfile[256];
+    char keyfile[256];
+    char flashfile[256];
+    char cartfile[256];
+    char pci_devices[256];
+    char prtname[256];
+    char sername[256];
+
+    char path_floppy[256];
+    char path_hardfile[256];
+    char path_rom[256];
+
+    int m68k_speed;
+    int cpu_level;
+    int cpu_compatible;
+    int address_space_24;
+
+    uae_u32 z3fastmem_size;
+    uae_u32 fastmem_size;
+    uae_u32 chipmem_size;
+    uae_u32 bogomem_size;
+    uae_u32 a3000mem_size;
+    uae_u32 gfxmem_size;
+
+    int kickshifter;
+    int filesys_no_uaefsdb;
+
+    struct uaedev_mount_info *mountinfo;
+
+    int nr_floppies;
+    int dfxtype[4];
+    int dfxclick[4];
+    char dfxclickexternal[4][256];
+    int dfxclickvolume;
+
+    /* Target specific options */
+    int x11_use_low_bandwidth;
+    int x11_use_mitshm;
+    int x11_use_dgamode;
+    int x11_hide_cursor;
+    int svga_no_linear;
+    int win32_middle_mouse;
+    int win32_logfile;
+
+    int win32_active_priority;
+    int win32_inactive_priority;
+    int win32_inactive_pause;
+    int win32_inactive_nosound;
+    int win32_iconified_priority;
+    int win32_iconified_pause;
+    int win32_iconified_nosound;
+
+    int win32_no_overlay; /* If this is set, we won't try and use any RGB overlays */
+    int win32_ctrl_F11_is_quit;
+    int win32_automount_drives;
+    int win32_midioutdev;
+    int win32_midiindev;
+    int win32_aspi;
+    int win32_soundcard;
+
+    int curses_reverse_video;
+
+    int statecapture;
+    int statecapturerate, statecapturebuffersize;
+
+    /* input */
+
+    int jport0;
+    int jport1;
+    int input_selected_setting;
+    int input_joymouse_multiplier;
+    int input_joymouse_deadzone;
+    int input_joystick_deadzone;
+    int input_joymouse_speed;
+    int input_autofire_framecnt;
+    int input_mouse_speed;
+    struct uae_input_device joystick_settings[MAX_INPUT_SETTINGS + 1][MAX_INPUT_DEVICES];
+    struct uae_input_device mouse_settings[MAX_INPUT_SETTINGS + 1][MAX_INPUT_DEVICES];
+    struct uae_input_device keyboard_settings[MAX_INPUT_SETTINGS + 1][MAX_INPUT_DEVICES];
+};
+
+/* Contains the filename of .uaerc */
+extern char optionsfile[];
+extern void save_options (FILE *, struct uae_prefs *, int);
+extern void cfgfile_write (FILE *f, char *format,...);
+
+extern void default_prefs (struct uae_prefs *, int);
+extern void discard_prefs (struct uae_prefs *, int);
+
+int parse_cmdline_option (struct uae_prefs *, char, char *);
+
+extern int cfgfile_yesno (char *option, char *value, char *name, int *location);
+extern int cfgfile_intval (char *option, char *value, char *name, int *location, int scale);
+extern int cfgfile_strval (char *option, char *value, char *name, int *location, const char *table[], int more);
+extern int cfgfile_string (char *option, char *value, char *name, char *location, int maxsz);
+extern char *cfgfile_subst_path (const char *path, const char *subst, const char *file);
+
+extern int target_parse_option (struct uae_prefs *, char *option, char *value);
+extern void target_save_options (FILE *, struct uae_prefs *);
+extern void target_default_options (struct uae_prefs *);
+
+extern int cfgfile_load (struct uae_prefs *, const char *filename, int *);
+extern int cfgfile_save (struct uae_prefs *, const char *filename, int);
+extern void cfgfile_parse_line (struct uae_prefs *p, char *, int);
+extern int cfgfile_parse_option (struct uae_prefs *p, char *option, char *value, int);
+extern int cfgfile_get_description (const char *filename, char *description, int*);
+extern void cfgfile_show_usage (void);
+extern uae_u32 cfgfile_uaelib(int mode, uae_u32 name, uae_u32 dst, uae_u32 maxlen);
+extern void cfgfile_addcfgparam (char *);
+
+extern void fixup_prefs_dimensions (struct uae_prefs *prefs);
+
+extern void check_prefs_changed_custom (void);
+extern void check_prefs_changed_cpu (void);
+extern void check_prefs_changed_audio (void);
+extern int check_prefs_changed_gfx (void);
+
+#define JSEM_DECODEVAL(n,v) ((n) == 0 ? (v)->jport0 : (v)->jport1)
+/* Determine how port n is configured */
+#define JSEM_ISJOY0(n,v) (JSEM_DECODEVAL(n,v) == 0)
+#define JSEM_ISJOY1(n,v) (JSEM_DECODEVAL(n,v) == 1)
+#define JSEM_ISMOUSE(n,v) (JSEM_DECODEVAL(n,v) == 2)
+#define JSEM_ISNUMPAD(n,v) (JSEM_DECODEVAL(n,v) == 3)
+#define JSEM_ISCURSOR(n,v) (JSEM_DECODEVAL(n,v) == 4)
+#define JSEM_ISSOMEWHEREELSE(n,v) (JSEM_DECODEVAL(n,v) == 5)
+extern const char *gameport_state (int n);
+
+extern struct uae_prefs currprefs, changed_prefs;
+
+extern void machdep_init (void);
+
+/* AIX doesn't think it is Unix. Neither do I. */
+#if defined(_ALL_SOURCE) || defined(_AIX)
+#undef __unix
+#define __unix
+#endif
+
+#define MAX_COLOR_MODES 5
+
+/* #define NEED_TO_DEBUG_BADLY */
+
+#if !defined(USER_PROGRAMS_BEHAVE)
+#define USER_PROGRAMS_BEHAVE 0
+#endif
+
+/* Some memsets which know that they can safely overwrite some more memory
+ * at both ends and use that knowledge to align the pointers. */
+
+#define QUADRUPLIFY(c) (((c) | ((c) << 8)) | (((c) | ((c) << 8)) << 16))
+
+/* When you call this routine, bear in mind that it rounds the bounds and
+ * may need some padding for the array. */
+
+#define fuzzy_memset(p, c, o, l) fuzzy_memset_1 ((p), QUADRUPLIFY (c), (o) & ~3, ((l) + 4) >> 2)
+STATIC_INLINE void fuzzy_memset_1 (void *p, uae_u32 c, int offset, int len)
+{
+    uae_u32 *p2 = (uae_u32 *)((char *)p + offset);
+    int a = len & 7;
+    len >>= 3;
+    switch (a) {
+     case 7: p2--; goto l1;
+     case 6: p2-=2; goto l2;
+     case 5: p2-=3; goto l3;
+     case 4: p2-=4; goto l4;
+     case 3: p2-=5; goto l5;
+     case 2: p2-=6; goto l6;
+     case 1: p2-=7; goto l7;
+     case 0: if (!--len) return; break;
+    }
+
+    for (;;) {
+       p2[0] = c;
+       l1:
+       p2[1] = c;
+       l2:
+       p2[2] = c;
+       l3:
+       p2[3] = c;
+       l4:
+       p2[4] = c;
+       l5:
+       p2[5] = c;
+       l6:
+       p2[6] = c;
+       l7:
+       p2[7] = c;
+
+       if (!len)
+           break;
+       len--;
+       p2 += 8;
+    }
+}
+
+/* This one knows it will never be asked to clear more than 32 bytes.  Make sure you call this with a
+   constant for the length.  */
+#define fuzzy_memset_le32(p, c, o, l) fuzzy_memset_le32_1 ((p), QUADRUPLIFY (c), (o) & ~3, ((l) + 7) >> 2)
+STATIC_INLINE void fuzzy_memset_le32_1 (void *p, uae_u32 c, int offset, int len)
+{
+    uae_u32 *p2 = (uae_u32 *)((char *)p + offset);
+
+    switch (len) {
+     case 9: p2[0] = c; p2[1] = c; p2[2] = c; p2[3] = c; p2[4] = c; p2[5] = c; p2[6] = c; p2[7] = c; p2[8] = c; break;
+     case 8: p2[0] = c; p2[1] = c; p2[2] = c; p2[3] = c; p2[4] = c; p2[5] = c; p2[6] = c; p2[7] = c; break;
+     case 7: p2[0] = c; p2[1] = c; p2[2] = c; p2[3] = c; p2[4] = c; p2[5] = c; p2[6] = c; break;
+     case 6: p2[0] = c; p2[1] = c; p2[2] = c; p2[3] = c; p2[4] = c; p2[5] = c; break;
+     case 5: p2[0] = c; p2[1] = c; p2[2] = c; p2[3] = c; p2[4] = c; break;
+     case 4: p2[0] = c; p2[1] = c; p2[2] = c; p2[3] = c; break;
+     case 3: p2[0] = c; p2[1] = c; p2[2] = c; break;
+     case 2: p2[0] = c; p2[1] = c; break;
+     case 1: p2[0] = c; break;
+     case 0: break;
+     default: printf("Hit the programmer.\n"); break;
+    }
+}
+
+#if defined(AMIGA) && defined(__GNUC__)
+#include "od-amiga/amiga-kludges.h"
+#endif
diff --git a/include/osemu.h b/include/osemu.h
new file mode 100755 (executable)
index 0000000..acd536b
--- /dev/null
@@ -0,0 +1,19 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * OS emulation prototypes
+  *
+  * Copyright 1996 Bernd Schmidt
+  */
+
+STATIC_INLINE char *raddr(uaecptr p)
+{
+    return p == 0 ? NULL : (char *)get_real_address(p);
+}
+
+extern void gfxlib_install(void);
+
+/* graphics.library */
+
+extern int GFX_WritePixel(uaecptr rp, int x, int y);
+
diff --git a/include/picasso96.h b/include/picasso96.h
new file mode 100755 (executable)
index 0000000..bf13dd4
--- /dev/null
@@ -0,0 +1,587 @@
+
+#ifdef WIN32
+
+#include "picasso96_win.h"
+
+#else
+/*
+ * UAE - The U*nix Amiga Emulator
+ *
+ * Picasso96 Support Module Header
+ *
+ * Copyright 1997 Brian King <Brian_King@Mitel.com, Brian_King@Cloanto.com>
+ */
+
+#if defined PICASSO96_SUPPORTED
+
+#define PICASSO96
+
+
+/* Seems the same routines copy back and forth ;-) */
+#define PIC_READ (S_READ|S_WRITE)
+#define PIC_WRITE (S_READ|S_WRITE)
+
+#define JAM1 0
+#define JAM2 1
+#define COMP 2
+#define INVERS 4
+
+typedef enum {
+    BLIT_FALSE,
+    BLIT_NOR,
+    BLIT_ONLYDST,
+    BLIT_NOTSRC,
+    BLIT_ONLYSRC,
+    BLIT_NOTDST,
+    BLIT_EOR,
+    BLIT_NAND,
+    BLIT_AND,
+    BLIT_NEOR,
+    BLIT_DST,
+    BLIT_NOTONLYSRC,
+    BLIT_SRC,
+    BLIT_NOTONLYDST,
+    BLIT_OR,
+    BLIT_TRUE,
+    BLIT_LAST
+} BLIT_OPCODE;
+
+/************************************************************************/
+/* Types for BoardType Identification
+ */
+typedef enum {
+       BT_NoBoard,
+       BT_oMniBus,
+       BT_Graffity,
+       BT_CyberVision,
+       BT_Domino,
+       BT_Merlin,
+       BT_PicassoII,
+       BT_Piccolo,
+       BT_RetinaBLT,
+       BT_Spectrum,
+       BT_PicassoIV,
+       BT_PiccoloSD64,
+       BT_A2410,
+       BT_Pixel64,
+       BT_uaegfx,
+       BT_CVision3D,
+       BT_Altais,
+       BT_Prototype1,
+       BT_Prototype2,
+       BT_Prototype3,
+       BT_Prototype4,
+       BT_Prototype5,
+       BT_MaxBoardTypes
+} BTYPE;
+
+struct ScreenResolution
+{
+    uae_u32 width;  /* in pixels */
+    uae_u32 height; /* in pixels */
+};
+
+#define MAX_PICASSO_MODES 64
+
+struct PicassoResolution
+{
+    struct Resolutions *next;
+    struct ScreenResolution res;
+    int depth;
+    int refresh;
+    char name[25];
+};
+extern struct PicassoResolution DisplayModes[MAX_PICASSO_MODES];
+
+
+/* Types for RGBFormat used */
+typedef enum {
+    RGBFB_NONE,                /* no valid RGB format (should not happen) */
+    RGBFB_CLUT,                /* palette mode, set colors when opening screen using
+                          tags or use SetRGB32/LoadRGB32(...) */
+    RGBFB_R8G8B8,      /* TrueColor RGB (8 bit each) */
+    RGBFB_B8G8R8,      /* TrueColor BGR (8 bit each) */
+    RGBFB_R5G6B5PC,    /* HiColor16 (5 bit R, 6 bit G, 5 bit B),
+                          format: gggbbbbbrrrrrggg */
+    RGBFB_R5G5B5PC,    /* HiColor15 (5 bit each), format: gggbbbbb0rrrrrgg */
+    RGBFB_A8R8G8B8,    /* 4 Byte TrueColor ARGB (A unused alpha channel) */
+    RGBFB_A8B8G8R8,    /* 4 Byte TrueColor ABGR (A unused alpha channel) */
+    RGBFB_R8G8B8A8,    /* 4 Byte TrueColor RGBA (A unused alpha channel) */
+    RGBFB_B8G8R8A8,    /* 4 Byte TrueColor BGRA (A unused alpha channel) */
+    RGBFB_R5G6B5,      /* HiColor16 (5 bit R, 6 bit G, 5 bit B),
+                          format: rrrrrggggggbbbbb */
+    RGBFB_R5G5B5,      /* HiColor15 (5 bit each), format: 0rrrrrgggggbbbbb */
+    RGBFB_B5G6R5PC,    /* HiColor16 (5 bit R, 6 bit G, 5 bit B),
+                          format: gggrrrrrbbbbbggg */
+    RGBFB_B5G5R5PC,    /* HiColor15 (5 bit each), format: gggrrrrr0bbbbbbgg */
+
+    /* By now, the following formats are for use with a hardware window only
+       (bitmap operations may be implemented incompletely) */
+
+    RGBFB_Y4U2V2,      /* 2 Byte TrueColor YUV (CCIR recommendation CCIR601).
+                          Each two-pixel unit is stored as one longword
+                          containing luminance (Y) for each of the two pixels,
+                          and chrominance (U,V) for alternate pixels.
+                          The missing chrominance values are generated by
+                          interpolation. (Y1-U0-Y0-V0) */
+    RGBFB_Y4U1V1,      /* 1 Byte TrueColor ACCUPAK. Four adjacent pixels form
+                          a packet of 5 bits Y (luminance) each pixel and 6 bits
+                          U and V (chrominance) shared by the four pixels */
+
+    RGBFB_MaxFormats
+} RGBFTYPE;
+
+#define RGBFF_NONE     (1<<RGBFB_NONE)
+#define RGBFF_CLUT     (1<<RGBFB_CLUT)
+#define RGBFF_R8G8B8   (1<<RGBFB_R8G8B8)
+#define RGBFF_B8G8R8   (1<<RGBFB_B8G8R8)
+#define RGBFF_R5G6B5PC (1<<RGBFB_R5G6B5PC)
+#define RGBFF_R5G5B5PC (1<<RGBFB_R5G5B5PC)
+#define RGBFF_A8R8G8B8 (1<<RGBFB_A8R8G8B8)
+#define RGBFF_A8B8G8R8 (1<<RGBFB_A8B8G8R8)
+#define RGBFF_R8G8B8A8 (1<<RGBFB_R8G8B8A8)
+#define RGBFF_B8G8R8A8 (1<<RGBFB_B8G8R8A8)
+#define RGBFF_R5G6B5   (1<<RGBFB_R5G6B5)
+#define RGBFF_R5G5B5   (1<<RGBFB_R5G5B5)
+#define RGBFF_B5G6R5PC (1<<RGBFB_B5G6R5PC)
+#define RGBFF_B5G5R5PC (1<<RGBFB_B5G5R5PC)
+#define RGBFF_Y4U2V2   (1<<RGBFB_Y4U2V2)
+#define RGBFF_Y4U1V1   (1<<RGBFB_Y4U1V1)
+
+#define RGBMASK_8BIT RGBFF_CLUT
+#define RGBMASK_16BIT (RGBFF_R5G6B5PC | RGBFF_B5G6R5PC | RGBFF_R5G6B5)
+#define RGBMASK_15BIT (RGBFF_R5G5B5PC | RGBFF_B5G5R5PC | RGBFF_R5G5B5)
+#define RGBMASK_24BIT (RGBFF_R8G8B8 | RGBFF_B8G8R8)
+#define RGBMASK_32BIT (RGBFF_A8R8G8B8 | RGBFF_A8B8G8R8 | RGBFF_R8G8B8A8 | RGBFF_B8G8R8A8)
+
+/************************************************************************/
+
+#define RGBFF_PLANAR   RGBFF_NONE
+#define RGBFF_CHUNKY   RGBFF_CLUT
+
+#define RGBFB_PLANAR   RGBFB_NONE
+#define RGBFB_CHUNKY   RGBFB_CLUT
+
+/************************************************************************/
+
+enum {
+    PLANAR,
+    CHUNKY,
+    HICOLOR,
+    TRUECOLOR,
+    TRUEALPHA,
+    MAXMODES
+};
+
+/************************************************************************/
+struct MyCLUTEntry {
+    uae_u8 Red;
+    uae_u8 Green;
+    uae_u8 Blue;
+    uae_u8 Pad;
+};
+
+struct ColorIndexMapping {
+    uae_u32 ColorMask;
+    uae_u32 Colors[256];
+};
+
+struct CLUTEntry {
+    uae_u8 Red;
+    uae_u8 Green;
+    uae_u8 Blue;
+};
+
+#define PSSO_BitMap_BytesPerRow 0
+#define PSSO_BitMap_Rows 2
+#define PSSO_BitMap_Flags 4
+#define PSSO_BitMap_Depth 5
+#define PSSO_BitMap_pad 6
+#define PSSO_BitMap_Planes 8
+#define PSSO_BitMap_sizeof 40
+
+struct BitMap
+{
+    uae_u16 BytesPerRow;
+    uae_u16 Rows;
+    uae_u8 Flags;
+    uae_u8 Depth;
+    uae_u16 pad;
+    uae_u8 *Planes[8];
+};
+
+/************************************************************************/
+
+#define SETTINGSNAMEMAXCHARS           30
+#define BOARDNAMEMAXCHARS              30
+
+struct Settings {
+    uae_u32                                    BoardType;
+    /* a value discribing assignment to nth board local to boardtype
+     * to be used for reassignment when boards are added or removed.  */
+    uae_u16                                    LocalOrdering;
+    uae_s16                                    LastSelected;
+    char                                       NameField[SETTINGSNAMEMAXCHARS];
+    /* neu! */
+    char                                       *BoardName;
+};
+
+#define MAXRESOLUTIONNAMELENGTH 22
+
+/********************************
+ * only used within rtg.library *
+ ********************************/
+
+#define PSSO_LibResolution_P96ID 14
+#define PSSO_LibResolution_Name 20
+#define PSSO_LibResolution_DisplayID 42 /* Name + MAXRESOLUTIONNAMELENGTH */
+#define PSSO_LibResolution_Width 46
+#define PSSO_LibResolution_Height 48
+#define PSSO_LibResolution_Flags 50
+#define PSSO_LibResolution_Modes 52
+#define PSSO_LibResolution_BoardInfo (52 + MAXMODES*4)
+#define PSSO_LibResolution_sizeof (60 + MAXMODES*4)
+
+struct LibResolution {
+    char P96ID[6];
+    char Name[MAXRESOLUTIONNAMELENGTH];
+    uae_u32 DisplayID;
+    uae_u16 Width;
+    uae_u16 Height;
+    uae_u16 Flags;
+    uaecptr Modes[MAXMODES];
+    uaecptr BoardInfo;
+};
+
+#define P96B_FAMILY    0                       /* obsolete (Resolution is an entire family) */
+#define P96B_PUBLIC    1                       /* Resolution should be added to the public */
+#define P96B_MONITOOL  2
+
+#define P96F_FAMILY    (1<<P96B_FAMILY)        /* obsolete */
+#define P96F_PUBLIC    (1<<P96B_PUBLIC)
+#define P96F_MONITOOL  (1<<P96B_MONITOOL)
+
+#define PSSO_ModeInfo_OpenCount 14
+#define PSSO_ModeInfo_Active 16
+#define PSSO_ModeInfo_Width 18
+#define PSSO_ModeInfo_Height 20
+#define PSSO_ModeInfo_Depth 22
+#define PSSO_ModeInfo_Flags 23
+#define PSSO_ModeInfo_HorTotal 24
+#define PSSO_ModeInfo_HorBlankSize 26
+#define PSSO_ModeInfo_HorSyncStart 28
+#define PSSO_ModeInfo_HorSyncSize 30
+#define PSSO_ModeInfo_HorSyncSkew 32
+#define PSSO_ModeInfo_HorEnableSkew 33
+#define PSSO_ModeInfo_VerTotal 34
+#define PSSO_ModeInfo_VerBlankSize 36
+#define PSSO_ModeInfo_VerSyncStart 38
+#define PSSO_ModeInfo_VerSyncSize 40
+#define PSSO_ModeInfo_first_union 42
+#define PSSO_ModeInfo_second_union 43
+#define PSSO_ModeInfo_PixelClock 44
+#define PSSO_ModeInfo_sizeof 48
+
+#define PSSO_RenderInfo_Memory 0
+#define PSSO_RenderInfo_BytesPerRow 4
+#define PSSO_RenderInfo_pad 6
+#define PSSO_RenderInfo_RGBFormat 8
+#define PSSO_RenderInfo_sizeof 12
+
+struct RenderInfo {
+    uae_u8 *Memory;
+    uae_s16 BytesPerRow;
+    uae_s16 pad;
+    RGBFTYPE RGBFormat;
+    uaecptr AMemory;
+};
+
+#define PSSO_Pattern_Memory 0
+#define PSSO_Pattern_XOffset 4
+#define PSSO_Pattern_YOffset 6
+#define PSSO_Pattern_FgPen 8
+#define PSSO_Pattern_BgPen 12
+#define PSSO_Pattern_Size 16
+#define PSSO_Pattern_DrawMode 17
+#define PSSO_Pattern_sizeof 18
+struct Pattern {
+    char *Memory;
+    uae_u16 XOffset, YOffset;
+    uae_u32 FgPen, BgPen;
+    uae_u8 Size;                                       /* Width: 16, Height: (1<<pat_Size) */
+    uae_u8 DrawMode;
+};
+
+#define PSSO_Template_Memory 0
+#define PSSO_Template_BytesPerRow 4
+#define PSSO_Template_XOffset 6
+#define PSSO_Template_DrawMode 7
+#define PSSO_Template_FgPen 8
+#define PSSO_Template_BgPen 12
+#define PSSO_Template_sizeof 16
+
+struct Template {
+    char *Memory;
+    uae_s16 BytesPerRow;
+    uae_u8 XOffset;
+    uae_u8 DrawMode;
+    uae_u32 FgPen;
+    uae_u32 BgPen;
+};
+
+#define PSSO_BitMapExtra_BoardNode       0
+#define PSSO_BitMapExtra_HashChain       8 /* BoardNode is 8-bytes */
+#define PSSO_BitMapExtra_Match          12
+#define PSSO_BitMapExtra_BitMap                 16
+#define PSSO_BitMapExtra_BoardInfo      20
+#define PSSO_BitMapExtra_MemChunk       24
+#define PSSO_BitMapExtra_RenderInfo     28
+#define PSSO_BitMapExtra_Width          40 /* RenderInfo is 12-bytes */
+#define PSSO_BitMapExtra_Height                 42
+#define PSSO_BitMapExtra_Flags          44
+#define PSSO_BitMapExtra_BaseLevel      46
+#define PSSO_BitMapExtra_CurrentLevel   48
+#define PSSO_BitMapExtra_CompanionMaster 50
+#define PSSO_BitMapExtra_Last           54
+
+#define PSSO_BoardInfo_RegisterBase               0
+#define PSSO_BoardInfo_MemoryBase                 PSSO_BoardInfo_RegisterBase + 4
+#define PSSO_BoardInfo_MemoryIOBase               PSSO_BoardInfo_MemoryBase + 4
+#define PSSO_BoardInfo_MemorySize                 PSSO_BoardInfo_MemoryIOBase + 4
+#define PSSO_BoardInfo_BoardName                  PSSO_BoardInfo_MemorySize + 4
+#define PSSO_BoardInfo_VBIName                    PSSO_BoardInfo_BoardName + 4
+#define PSSO_BoardInfo_CardBase                           PSSO_BoardInfo_VBIName + 32
+#define PSSO_BoardInfo_ChipBase                           PSSO_BoardInfo_CardBase + 4
+#define PSSO_BoardInfo_ExecBase                           PSSO_BoardInfo_ChipBase + 4
+#define PSSO_BoardInfo_UtilBase                           PSSO_BoardInfo_ExecBase + 4
+#define PSSO_BoardInfo_HardInterrupt              PSSO_BoardInfo_UtilBase + 4
+#define PSSO_BoardInfo_SoftInterrupt              PSSO_BoardInfo_HardInterrupt + 22 /* The HardInterrupt is 22-bytes */
+#define PSSO_BoardInfo_BoardLock                  PSSO_BoardInfo_SoftInterrupt + 22 /* The SoftInterrupt is 22-bytes */
+#define PSSO_BoardInfo_ResolutionsList            PSSO_BoardInfo_BoardLock + 46 /* On the BoardLock, we were having some fun... */
+#define PSSO_BoardInfo_BoardType                  PSSO_BoardInfo_ResolutionsList + 12 /* The ResolutionsList is 12-bytes */
+#define PSSO_BoardInfo_PaletteChipType            PSSO_BoardInfo_BoardType + 4
+#define PSSO_BoardInfo_GraphicsControllerType     PSSO_BoardInfo_PaletteChipType + 4
+#define PSSO_BoardInfo_MoniSwitch                 PSSO_BoardInfo_GraphicsControllerType + 4
+#define PSSO_BoardInfo_BitsPerCannon              PSSO_BoardInfo_MoniSwitch + 2
+#define PSSO_BoardInfo_Flags                      PSSO_BoardInfo_BitsPerCannon + 2
+#define PSSO_BoardInfo_SoftSpriteFlags            PSSO_BoardInfo_Flags + 4
+#define PSSO_BoardInfo_ChipFlags                  PSSO_BoardInfo_SoftSpriteFlags + 2
+#define PSSO_BoardInfo_CardFlags                  PSSO_BoardInfo_ChipFlags + 2
+#define PSSO_BoardInfo_BoardNum                           PSSO_BoardInfo_CardFlags + 4
+#define PSSO_BoardInfo_RGBFormats                 PSSO_BoardInfo_BoardNum + 2
+#define PSSO_BoardInfo_MaxHorValue                PSSO_BoardInfo_RGBFormats + 2
+#define PSSO_BoardInfo_MaxVerValue                PSSO_BoardInfo_MaxHorValue + MAXMODES*2
+#define PSSO_BoardInfo_MaxHorResolution                   PSSO_BoardInfo_MaxVerValue + MAXMODES*2
+#define PSSO_BoardInfo_MaxVerResolution                   PSSO_BoardInfo_MaxHorResolution + MAXMODES*2
+#define PSSO_BoardInfo_MaxMemorySize              PSSO_BoardInfo_MaxVerResolution + MAXMODES*2
+#define PSSO_BoardInfo_MaxChunkSize               PSSO_BoardInfo_MaxMemorySize + 4
+#define PSSO_BoardInfo_MemoryClock                PSSO_BoardInfo_MaxChunkSize + 4
+#define PSSO_BoardInfo_PixelClockCount            PSSO_BoardInfo_MemoryClock + 4
+#define PSSO_BoardInfo_AllocCardMem               PSSO_BoardInfo_PixelClockCount + MAXMODES*4
+#define PSSO_BoardInfo_SpecialFeatures            PSSO_BoardInfo_AllocCardMem + 68*4 /* 68 function pointers */
+#define PSSO_BoardInfo_ModeInfo                           PSSO_BoardInfo_SpecialFeatures + 12 /* SpecialFeatures is 12-bytes */
+#define PSSO_BoardInfo_RGBFormat                  PSSO_BoardInfo_ModeInfo + 4
+#define PSSO_BoardInfo_XOffset                    PSSO_BoardInfo_RGBFormat + 4
+#define PSSO_BoardInfo_YOffset                    PSSO_BoardInfo_XOffset + 2
+#define PSSO_BoardInfo_Depth                      PSSO_BoardInfo_YOffset + 2
+#define PSSO_BoardInfo_ClearMask                  PSSO_BoardInfo_Depth + 1
+#define PSSO_BoardInfo_Border                     PSSO_BoardInfo_ClearMask + 1
+#define PSSO_BoardInfo_Mask                       PSSO_BoardInfo_Border + 2 /* BOOL type is only 2-bytes! */
+#define PSSO_BoardInfo_CLUT                       PSSO_BoardInfo_Mask + 4
+#define PSSO_BoardInfo_ViewPort                           PSSO_BoardInfo_CLUT + 3*256
+#define PSSO_BoardInfo_VisibleBitMap              PSSO_BoardInfo_ViewPort + 4
+#define PSSO_BoardInfo_BitMapExtra                PSSO_BoardInfo_VisibleBitMap + 4
+#define PSSO_BoardInfo_BitMapList                 PSSO_BoardInfo_BitMapExtra + 4
+#define PSSO_BoardInfo_MemList                    PSSO_BoardInfo_BitMapList + 12 /* BitMapList is 12-bytes */
+#define PSSO_BoardInfo_MouseX                     PSSO_BoardInfo_MemList + 12 /* MemList is 12-bytes */
+#define PSSO_BoardInfo_MouseY                     PSSO_BoardInfo_MouseX + 2
+#define PSSO_BoardInfo_MouseWidth                 PSSO_BoardInfo_MouseY + 2
+#define PSSO_BoardInfo_MouseHeight                PSSO_BoardInfo_MouseWidth + 1
+#define PSSO_BoardInfo_MouseXOffset               PSSO_BoardInfo_MouseHeight + 1
+#define PSSO_BoardInfo_MouseYOffset               PSSO_BoardInfo_MouseXOffset + 1
+#define PSSO_BoardInfo_MouseImage                 PSSO_BoardInfo_MouseYOffset + 1
+#define PSSO_BoardInfo_MousePens                  PSSO_BoardInfo_MouseImage + 4
+#define PSSO_BoardInfo_MouseRect                  PSSO_BoardInfo_MousePens + 4
+#define PSSO_BoardInfo_MouseChunky                PSSO_BoardInfo_MouseRect + 8 /* MouseRect is 8-bytes */
+#define PSSO_BoardInfo_MouseRendered              PSSO_BoardInfo_MouseChunky + 4
+#define PSSO_BoardInfo_MouseSaveBuffer            PSSO_BoardInfo_MouseRendered + 4
+
+struct BoardInfo {
+    uae_u8 *RegisterBase, *MemoryBase, *MemoryIOBase;
+    uae_u32 MemorySize;
+    char *BoardName, VBIName[32];
+
+    uae_u16 MoniSwitch;
+    uae_u16 BitsPerCannon;
+    uae_u32 Flags;
+    uae_u16 SoftSpriteFlags;
+    uae_u16 ChipFlags; /* private, chip specific, not touched by RTG */
+    uae_u32 CardFlags; /* private, card specific, not touched by RTG */
+
+    uae_u16 BoardNum;
+    uae_s16 RGBFormats;
+
+    uae_u16 MaxHorValue[MAXMODES];
+    uae_u16 MaxVerValue[MAXMODES];
+    uae_u16 MaxHorResolution[MAXMODES];
+    uae_u16 MaxVerResolution[MAXMODES];
+    uae_u32 MaxMemorySize, MaxChunkSize;
+};
+
+/* BoardInfo flags */
+/*  0-15: hardware flags */
+/* 16-31: user flags */
+#define BIB_HARDWARESPRITE     0       /* board has hardware sprite */
+#define BIB_NOMEMORYMODEMIX    1       /* board does not support modifying planar bitmaps while displaying chunky and vice versa */
+#define BIB_NEEDSALIGNMENT     2       /* bitmaps have to be aligned (not yet supported!) */
+#define BIB_DBLSCANDBLSPRITEY  8       /* hardware sprite y position is doubled on doublescan display modes */
+#define BIB_ILACEHALFSPRITEY   9       /* hardware sprite y position is halved on interlace display modes */
+#define BIB_ILACEDBLROWOFFSET  10      /* doubled row offset in interlaced display modes needs additional horizontal bit */
+
+#define BIB_FLICKERFIXER       12      /* board can flicker fix Amiga RGB signal */
+#define BIB_VIDEOCAPTURE       13      /* board can capture video data to a memory area */
+#define BIB_VIDEOWINDOW                14      /* board can display a second mem area as a pip */
+#define BIB_BLITTER            15      /* board has blitter */
+
+#define BIB_HIRESSPRITE                16      /* mouse sprite has double resolution */
+#define BIB_BIGSPRITE          17      /* user wants big mouse sprite */
+#define BIB_BORDEROVERRIDE     18      /* user wants to override system overscan border prefs */
+#define BIB_BORDERBLANK                19      /* user wants border blanking */
+#define BIB_INDISPLAYCHAIN     20      /* board switches Amiga signal */
+#define BIB_QUIET              21      /* not yet implemented */
+#define BIB_NOMASKBLITS                22      /* perform blits without taking care of mask */
+#define BIB_NOC2PBLITS         23      /* use CPU for planar to chunky conversions */
+#define BIB_NOBLITTER          24      /* disable all blitter functions */
+
+#define BIB_IGNOREMASK BIB_NOMASKBLITS
+
+#define BIF_HARDWARESPRITE     (1<<BIB_HARDWARESPRITE)
+#define BIF_NOMEMORYMODEMIX    (1<<BIB_NOMEMORYMODEMIX)
+#define BIF_NEEDSALIGNMENT     (1<<BIB_NEEDSALIGNMENT)
+#define BIF_DBLSCANDBLSPRITEY  (1<<BIB_DBLSCANDBLSPRITEY)
+#define BIF_ILACEHALFSPRITEY   (1<<BIB_ILACEHALFSPRITEY)
+#define BIF_ILACEDBLROWOFFSET  (1<<BIB_ILACEDBLROWOFFSET)
+#define BIF_FLICKERFIXER       (1<<BIB_FLICKERFIXER)
+#define BIF_VIDEOCAPTURE       (1<<BIB_VIDEOCAPTURE)
+#define BIF_VIDEOWINDOW                (1<<BIB_VIDEOWINDOW)
+#define BIF_BLITTER            (1<<BIB_BLITTER)
+#define BIF_HIRESSPRITE                (1<<BIB_HIRESSPRITE)
+#define BIF_BIGSPRITE          (1<<BIB_BIGSPRITE)
+#define BIF_BORDEROVERRIDE     (1<<BIB_BORDEROVERRIDE)
+#define BIF_BORDERBLANK                (1<<BIB_BORDERBLANK)
+#define BIF_INDISPLAYCHAIN     (1<<BIB_INDISPLAYCHAIN)
+#define BIF_QUIET              (1<<BIB_QUIET)
+#define BIF_NOMASKBLITS                (1<<BIB_NOMASKBLITS)
+#define BIF_NOC2PBLITS         (1<<BIB_NOC2PBLITS)
+#define BIF_NOBLITTER          (1<<BIB_NOBLITTER)
+
+#define BIF_IGNOREMASK BIF_NOMASKBLITS
+
+/************************************************************************/
+struct picasso96_state_struct
+{
+    uae_u32            RGBFormat;   /* true-colour, CLUT, hi-colour, etc. */
+    struct MyCLUTEntry CLUT[256];   /* Duh! */
+    uaecptr            Address;     /* Active screen address (Amiga-side) */
+    uaecptr            Extent;      /* End address of screen (Amiga-side) */
+    uae_u16            Width;       /* Active display width  (From SetGC) */
+    uae_u16            VirtualWidth;/* Total screen width (From SetPanning) */
+    uae_u16            BytesPerRow; /* Total screen width in bytes (From SetGC) */
+    uae_u16            Height;      /* Active display height (From SetGC) */
+    uae_u16            VirtualHeight; /* Total screen height */
+    uae_u8             GC_Depth;    /* From SetGC() */
+    uae_u8             GC_Flags;    /* From SetGC() */
+    long               XOffset;     /* From SetPanning() */
+    long               YOffset;     /* From SetPanning() */
+    uae_u8             SwitchState; /* From SetSwitch() - 0 is Amiga, 1 is Picasso */
+    uae_u8             BytesPerPixel;
+    uae_u8             CardFound;
+};
+
+extern void InitPicasso96 (void);
+
+extern uae_u32 picasso_SetDisplay (void);
+extern uae_u32 picasso_WaitVerticalSync (void);
+extern uae_u32 picasso_CalculateBytesPerRow (void);
+extern uae_u32 picasso_FillRect (void);
+extern uae_u32 picasso_BlitRect (void);
+extern uae_u32 picasso_InvertRect (void);
+extern uae_u32 picasso_SetPanning (void);
+extern uae_u32 picasso_SetGC (void);
+extern uae_u32 picasso_SetDAC (void);
+extern uae_u32 picasso_SetColorArray (void);
+extern uae_u32 picasso_SetSwitch (void);
+extern uae_u32 picasso_SetSwitch (void);
+extern uae_u32 picasso_FindCard (void);
+extern uae_u32 picasso_InitCard (void);
+extern uae_u32 picasso_BlitPlanar2Chunky (void);
+extern uae_u32 picasso_BlitPlanar2Direct (void);
+extern uae_u32 picasso_BlitTemplate (void);
+extern uae_u32 picasso_BlitPattern (void);
+extern uae_u32 picasso_BlitRectNoMaskComplete (void);
+
+extern uae_u32 gfxmem_mask;
+extern uae_u8 *gfxmemory;
+
+extern int uaegfx_card_found;
+
+extern struct picasso96_state_struct picasso96_state;
+
+#ifdef _WIN32
+extern unsigned int timer_id;
+#endif
+
+extern int DX_Fill (int dstx, int dsty, int width, int height, uae_u32 color, RGBFTYPE rgbtype);
+extern int DX_Blit (int srcx, int srcy, int dstx, int dsty, int width, int height, BLIT_OPCODE opcode);
+extern void DX_BlitRectFromBuffer (struct RenderInfo *ri, uae_u8* buffer, uae_u16 dstx, uae_u16 dsty, uae_u16 w, uae_u16 h);
+extern void DX_InvertRect (struct RenderInfo *ri, uae_u16 X, uae_u16 Y, uae_u16 Width, uae_u16 Height);
+extern void DX_SetPalette (int start, int count);
+extern void DX_SetPalette_vsync (void);
+extern int DX_FillResolutions (uae_u16 *);
+extern int DX_BitsPerCannon (void);
+extern void DX_Invalidate (int first, int last);
+extern void picasso_enablescreen (int on);
+extern void picasso_refresh (int call_setpalette);
+extern void picasso_handle_vsync (void);
+
+extern uae_u8 *gfxmemory;
+
+/* This structure describes the UAE-side framebuffer for the Picasso
+ * screen.  */
+struct picasso_vidbuf_description {
+    int width, height, depth;
+    int rowbytes, pixbytes;
+    int extra_mem; /* nonzero if there's a second buffer that must be updated */
+    uae_u32 rgbformat;
+    uae_u32 selected_rgbformat;
+    uae_u32 clut[256];
+};
+
+extern struct picasso_vidbuf_description picasso_vidinfo;
+
+extern void gfx_set_picasso_modeinfo (int w, int h, int d, int rgbfmt);
+extern void gfx_set_picasso_baseaddr (uaecptr);
+extern void gfx_set_picasso_state (int on);
+extern uae_u8 *gfx_lock_picasso (void);
+extern void gfx_unlock_picasso (void);
+extern int picasso_display_mode_index (uae_u32 x, uae_u32 y, uae_u32 d);
+extern int picasso_nr_resolutions (void);
+extern void picasso_clip_mouse (int *, int *);
+
+extern int NDX_InvertRect(struct RenderInfo* ri, unsigned long X, unsigned long Y, unsigned long Width, unsigned long Height, uae_u32 mask, int Bpp);
+extern int NDX_BlitPattern(struct RenderInfo* ri,struct Pattern* pat,unsigned long X, unsigned long Y, unsigned long W, unsigned long H, uae_u8 Mask, uae_u32 RGBFmt);
+extern int NDX_BlitTemplate(struct RenderInfo* ri, struct Template* tmp, unsigned long X, unsigned long Y, unsigned long W, unsigned long H, uae_u16 Mask);
+extern int NDX_BlitPlanar2Chunky(struct RenderInfo* ri, struct BitMap* bm, unsigned long srcx, unsigned long srcy, unsigned long dstx, unsigned long dsty, unsigned long width, unsigned long height, uae_u8 minterm, uae_u8 mask);
+extern int NDX_BlitPlanar2Direct(struct RenderInfo* ri, struct BitMap* bm, unsigned long srcx, unsigned long srcy, unsigned long dstx, unsigned long dsty, unsigned long width, unsigned long height, uae_u8 minterm, uae_u8 Mask);
+extern int NDX_FillRect(struct RenderInfo* ri, unsigned long X, unsigned long Y, unsigned long Width, unsigned long Height, uae_u32 Pen, uae_u8 Mask, uae_u32 RGBFormat);
+extern int NDX_BlitRect(struct RenderInfo* ri, unsigned long srcx, unsigned long srcy, unsigned long dstx, unsigned long dsty, unsigned long width, unsigned long height, uae_u8 Mask);
+extern int NDX_BlitRectNoMaskComplete(struct RenderInfo* sri,struct RenderInfo* dri, unsigned long srcx, unsigned long srcy, unsigned long dstx, unsigned long dsty, unsigned long width, unsigned long height, uae_u8 OpCode, uae_u32 RGBFmt);
+
+extern int picasso_is_special;
+extern int picasso_is_special_read;
+
+extern int p96hack_vpos2;
+extern int p96refresh_active;
+#endif
+
+#endif
diff --git a/include/readcpu.h b/include/readcpu.h
new file mode 100755 (executable)
index 0000000..92c4869
--- /dev/null
@@ -0,0 +1,102 @@
+ENUMDECL {
+  Dreg, Areg, Aind, Aipi, Apdi, Ad16, Ad8r,
+  absw, absl, PC16, PC8r, imm, imm0, imm1, imm2, immi, am_unknown, am_illg
+} ENUMNAME (amodes);
+
+ENUMDECL {
+    i_ILLG,
+
+    i_OR, i_AND, i_EOR, i_ORSR, i_ANDSR, i_EORSR,
+    i_SUB, i_SUBA, i_SUBX, i_SBCD,
+    i_ADD, i_ADDA, i_ADDX, i_ABCD,
+    i_NEG, i_NEGX, i_NBCD, i_CLR, i_NOT, i_TST,
+    i_BTST, i_BCHG, i_BCLR, i_BSET,
+    i_CMP, i_CMPM, i_CMPA,
+    i_MVPRM, i_MVPMR, i_MOVE, i_MOVEA, i_MVSR2, i_MV2SR,
+    i_SWAP, i_EXG, i_EXT, i_MVMEL, i_MVMLE,
+    i_TRAP, i_MVR2USP, i_MVUSP2R, i_RESET, i_NOP, i_STOP, i_RTE, i_RTD,
+    i_LINK, i_UNLK,
+    i_RTS, i_TRAPV, i_RTR,
+    i_JSR, i_JMP, i_BSR, i_Bcc,
+    i_LEA, i_PEA, i_DBcc, i_Scc,
+    i_DIVU, i_DIVS, i_MULU, i_MULS,
+    i_ASR, i_ASL, i_LSR, i_LSL, i_ROL, i_ROR, i_ROXL, i_ROXR,
+    i_ASRW, i_ASLW, i_LSRW, i_LSLW, i_ROLW, i_RORW, i_ROXLW, i_ROXRW,
+    i_CHK,i_CHK2,
+    i_MOVEC2, i_MOVE2C, i_CAS, i_CAS2, i_DIVL, i_MULL,
+    i_BFTST,i_BFEXTU,i_BFCHG,i_BFEXTS,i_BFCLR,i_BFFFO,i_BFSET,i_BFINS,
+    i_PACK, i_UNPK, i_TAS, i_BKPT, i_CALLM, i_RTM, i_TRAPcc, i_MOVES,
+    i_FPP, i_FDBcc, i_FScc, i_FTRAPcc, i_FBcc, i_FSAVE, i_FRESTORE,
+    i_CINVL, i_CINVP, i_CINVA, i_CPUSHL, i_CPUSHP, i_CPUSHA, i_MOVE16,
+    i_MMUOP
+} ENUMNAME (instrmnem);
+
+extern struct mnemolookup {
+    instrmnem mnemo;
+    const char *name;
+} lookuptab[];
+
+ENUMDECL {
+    sz_byte, sz_word, sz_long
+} ENUMNAME (wordsizes);
+
+ENUMDECL {
+    fa_set, fa_unset, fa_zero, fa_one, fa_dontcare, fa_unknown, fa_isjmp,
+    fa_isbranch
+} ENUMNAME (flagaffect);
+
+ENUMDECL {
+    fu_used, fu_unused, fu_maybecc, fu_unknown, fu_isjmp
+} ENUMNAME (flaguse);
+
+ENUMDECL {
+    bit0, bit1, bitc, bitC, bitf, biti, bitI, bitj, bitJ, bitk, bitK,
+    bits, bitS, bitd, bitD, bitr, bitR, bitz, bitp, lastbit
+} ENUMNAME (bitvals);
+
+struct instr_def {
+    unsigned int bits;
+    int n_variable;
+    char bitpos[16];
+    unsigned int mask;
+    int cpulevel;
+    int plevel;
+    struct {
+       unsigned int flaguse:3;
+       unsigned int flagset:3;
+    } flaginfo[5];
+    unsigned char sduse;
+    const char *opcstr;
+};
+
+extern struct instr_def defs68k[];
+extern int n_defs68k;
+
+extern struct instr {
+    long int handler;
+    unsigned char dreg;
+    unsigned char sreg;
+    signed char dpos;
+    signed char spos;
+    unsigned char sduse;
+    int flagdead:8, flaglive:8;
+    unsigned int mnemo:8;
+    unsigned int cc:4;
+    unsigned int plev:2;
+    unsigned int size:2;
+    unsigned int smode:5;
+    unsigned int stype:3;
+    unsigned int dmode:5;
+    unsigned int suse:1;
+    unsigned int duse:1;
+    unsigned int unused1:1;
+    unsigned int clev:3;
+    unsigned int isjmp:1;
+    unsigned int unused2:4;
+} *table68k;
+
+extern void read_table68k (void);
+extern void do_merges (void);
+extern int get_no_mismatches (void);
+extern int nr_cpuop_funcs;
+
diff --git a/include/savestate.h b/include/savestate.h
new file mode 100755 (executable)
index 0000000..c656047
--- /dev/null
@@ -0,0 +1,125 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Save/restore emulator state
+  *
+  * (c) 1999-2001 Toni Wilen
+  */
+
+
+/* functions to save byte,word or long word
+ * independent of CPU's endianess */
+
+extern void save_u16_func (uae_u8 **, uae_u16);
+extern void save_u32_func (uae_u8 **, uae_u32);
+extern void save_u8_func (uae_u8 **, uae_u8);
+
+extern uae_u16 restore_u16_func (uae_u8 **);
+extern uae_u32 restore_u32_func (uae_u8 **);
+extern uae_u8 restore_u8_func (uae_u8 **);
+
+extern void save_string_func (uae_u8 **, char*);
+extern char *restore_string_func (uae_u8 **);
+
+#define save_u16(x) save_u16_func (&dst, (x))
+#define save_u32(x) save_u32_func (&dst, (x))
+#define save_u8(x) save_u8_func (&dst, (x))
+
+#define restore_u16() restore_u16_func (&src)
+#define restore_u32() restore_u32_func (&src)
+#define restore_u8() restore_u8_func (&src)
+
+#define save_string(x) save_string_func (&dst, (x))
+#define restore_string() restore_string_func (&src)
+
+/* save, restore and initialize routines for Amiga's subsystems */
+
+extern uae_u8 *restore_cpu (uae_u8 *);
+extern uae_u8 *save_cpu (int *, uae_u8 *);
+
+extern uae_u8 *restore_fpu (uae_u8 *);
+extern uae_u8 *save_fpu (int *, uae_u8 *);
+
+extern uae_u8 *restore_disk (int, uae_u8 *);
+extern uae_u8 *save_disk (int, int *, uae_u8 *);
+extern uae_u8 *restore_floppy (uae_u8 *src);
+extern uae_u8 *save_floppy (int *len, uae_u8 *);
+extern void DISK_save_custom  (uae_u32 *pdskpt, uae_u16 *pdsklen, uae_u16 *pdsksync, uae_u16 *pdskbytr);
+extern void DISK_restore_custom  (uae_u32 pdskpt, uae_u16 pdsklength, uae_u16 pdskbytr);
+
+extern uae_u8 *restore_custom (uae_u8 *);
+extern uae_u8 *save_custom (int *, uae_u8 *, int);
+
+extern uae_u8 *restore_custom_sprite (int num, uae_u8 *src);
+extern uae_u8 *save_custom_sprite (int num, int *len, uae_u8 *);
+
+extern uae_u8 *restore_custom_agacolors (uae_u8 *src);
+extern uae_u8 *save_custom_agacolors (int *len, uae_u8 *);
+
+extern uae_u8 *restore_blitter (uae_u8 *src);
+extern uae_u8 *save_blitter (int *len, uae_u8 *);
+
+extern uae_u8 *restore_audio (int, uae_u8 *);
+extern uae_u8 *save_audio (int, int *, uae_u8 *);
+
+extern uae_u8 *restore_cia (int, uae_u8 *);
+extern uae_u8 *save_cia (int, int *, uae_u8 *);
+
+extern uae_u8 *restore_expansion (uae_u8 *);
+extern uae_u8 *save_expansion (int *, uae_u8 *);
+
+extern uae_u8 *restore_p96 (uae_u8 *);
+extern uae_u8 *save_p96 (int *, uae_u8 *);
+
+extern uae_u8 *restore_keyboard (uae_u8 *);
+extern uae_u8 *save_keyboard (int *);
+
+extern void restore_cram (int, long);
+extern void restore_bram (int, long);
+extern void restore_fram (int, long);
+extern void restore_zram (int, long);
+extern void restore_pram (int, long);
+extern void restore_ram (long, uae_u8*);
+
+extern uae_u8 *save_cram (int *);
+extern uae_u8 *save_bram (int *);
+extern uae_u8 *save_fram (int *);
+extern uae_u8 *save_zram (int *);
+extern uae_u8 *save_pram (int *);
+
+extern uae_u8 *restore_rom (uae_u8 *);
+extern uae_u8 *save_rom (int, int *, uae_u8 *);
+
+extern uae_u8 *restore_action_replay (uae_u8 *);
+extern uae_u8 *save_action_replay (int *, uae_u8 *);
+
+extern void savestate_initsave (char *filename, int docompress);
+extern void save_state (char *filename, char *description);
+extern void restore_state (char *filename);
+extern void savestate_restore_finish (void);
+
+extern void custom_save_state (void);
+extern void custom_prepare_savestate (void);
+
+#define STATE_SAVE 1
+#define STATE_RESTORE 2
+#define STATE_DOSAVE 4
+#define STATE_DORESTORE 8
+#define STATE_REWIND 16
+#define STATE_DOREWIND 32
+
+extern int savestate_state;
+extern char savestate_fname[MAX_PATH];
+extern struct zfile *savestate_file;
+
+extern uae_u32 CRC32(uae_u32 crc, const uae_u8 *buf, int len);
+
+extern void savestate_quick (int slot, int save);
+
+extern void savestate_capture (int);
+extern void savestate_free (void);
+extern void savestate_init (void);
+extern void savestate_rewind (void);
+extern int savestate_dorewind (int);
+extern void savestate_listrewind (void);
+
diff --git a/include/scsidev.h b/include/scsidev.h
new file mode 100755 (executable)
index 0000000..ddfb6cc
--- /dev/null
@@ -0,0 +1,17 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * a SCSI device
+  *
+  * (c) 1995 Bernd Schmidt (hardfile.c)
+  * (c) 1999 Patrick Ohly
+  * (c) 2001-2002 Toni Wilen
+  */
+
+uaecptr scsidev_startup (uaecptr resaddr);
+void scsidev_install (void);
+void scsidev_reset (void);
+void scsidev_start_threads (void);
+void scsi_do_disk_change (int device_id, int insert);
+
+extern int log_scsi;
diff --git a/include/serial.h b/include/serial.h
new file mode 100755 (executable)
index 0000000..f208327
--- /dev/null
@@ -0,0 +1,29 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Serial Line Emulation
+  *
+  * Copyright 1996, 1997 Stefan Reinauer <stepan@linux.de>
+  * Copyright 1997 Christian Schmitt <schmitt@freiburg.linux.de>
+  */
+
+extern void serial_init(void);
+extern void serial_exit(void);
+extern void serial_dtr_off(void);
+
+extern uae_u16 SERDATR(void);
+extern int   SERDATS(void);
+extern void  SERPER(uae_u16 w);
+extern void  SERDAT(uae_u16 w);
+
+extern uae_u8 serial_writestatus(uae_u8, uae_u8);
+extern uae_u8 serial_readstatus (uae_u8);
+extern void serial_uartbreak (int);
+extern uae_u16 serdat;
+
+extern int doreadser, serstat;
+
+extern void serial_flush_buffer(void);
+
+extern void serial_hsynchandler (void);
+extern void serial_check_irq (void);
\ No newline at end of file
diff --git a/include/sysconfig.h.win32 b/include/sysconfig.h.win32
new file mode 100755 (executable)
index 0000000..85eb0b6
--- /dev/null
@@ -0,0 +1,42 @@
+/* The number of bytes in a char.  */
+#define SIZEOF_CHAR 1
+
+/* The number of bytes in a int.  */
+#define SIZEOF_INT 4
+
+/* The number of bytes in a long.  */
+#define SIZEOF_LONG 4
+
+#ifdef __GNUC__
+/* The number of bytes in a long long.  */
+#define SIZEOF_LONG_LONG 8
+#define SIZEOF___INT64 0
+#else
+#define SIZEOF_LONG_LONG 0
+#define SIZEOF___INT64 8
+#endif
+
+/* The number of bytes in a short.  */
+#define SIZEOF_SHORT 2
+
+/* Define if you have the <fcntl.h> header file.  */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <string.h> header file.  */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <sys/stat.h> header file.  */
+#define HAVE_SYS_STAT_H 1
+
+/* Define if you have the <sys/types.h> header file.  */
+#define HAVE_SYS_TYPES_H 1
+
+// Windows-specific #defines
+#ifndef __GNUC__
+#define REGPARAM
+#define REGPARAM2
+#define __inline__ __inline
+#define __asm__(a) ;
+#define O_NDELAY 0
+#endif
+#define lseek _lseek
diff --git a/include/sysdeps.h b/include/sysdeps.h
new file mode 100755 (executable)
index 0000000..b60b92e
--- /dev/null
@@ -0,0 +1,491 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Try to include the right system headers and get other system-specific
+  * stuff right & other collected kludges.
+  *
+  * If you think about modifying this, think twice. Some systems rely on
+  * the exact order of the #include statements. That's also the reason
+  * why everything gets included unconditionally regardless of whether
+  * it's actually needed by the .c file.
+  *
+  * Copyright 1996, 1997 Bernd Schmidt
+  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <limits.h>
+
+#ifndef __STDC__
+#ifndef _MSC_VER
+#error "Your compiler is not ANSI. Get a real one."
+#endif
+#endif
+
+#include <stdarg.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_VALUES_H
+#include <values.h>
+#endif
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_UTIME_H
+#include <utime.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+#else
+# define dirent direct
+# if HAVE_SYS_NDIR_H
+#  include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+#  include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+#  include <ndir.h>
+# endif
+#endif
+
+#ifdef HAVE_SYS_UTIME_H
+# include <sys/utime.h>
+#endif
+
+#include <errno.h>
+#include <assert.h>
+
+#if EEXIST == ENOTEMPTY
+#define BROKEN_OS_PROBABLY_AIX
+#endif
+
+#ifdef __NeXT__
+#define S_IRUSR S_IREAD
+#define S_IWUSR S_IWRITE
+#define S_IXUSR S_IEXEC
+#define S_ISDIR(val) (S_IFDIR & val)
+struct utimbuf
+{
+    time_t actime;
+    time_t modtime;
+};
+#endif
+
+#if defined(__GNUC__) && defined(AMIGA)
+/* gcc on the amiga need that __attribute((regparm)) must */
+/* be defined in function prototypes as well as in        */
+/* function definitions !                                 */
+#define REGPARAM2 REGPARAM
+#else /* not(GCC & AMIGA) */
+#define REGPARAM2
+#endif
+
+/* sam: some definitions so that SAS/C can compile UAE */
+#if defined(__SASC) && defined(AMIGA)
+#define REGPARAM2 
+#define REGPARAM
+#define S_IRUSR S_IREAD
+#define S_IWUSR S_IWRITE
+#define S_IXUSR S_IEXECUTE
+#define S_ISDIR(val) (S_IFDIR & val)
+#define mkdir(x,y) mkdir(x)
+#define truncate(x,y) 0
+#define creat(x,y) open("T:creat",O_CREAT|O_TEMP|O_RDWR) /* sam: for zfile.c */
+#define strcasecmp stricmp
+#define utime(file,time) 0
+struct utimbuf
+{
+    time_t actime;
+    time_t modtime;
+};
+#endif
+
+#if defined(WARPUP)
+#include "devices/timer.h"
+#include "osdep/posixemu.h"
+#define REGPARAM
+#define REGPARAM2
+#define RETSIGTYPE
+#define USE_ZFILE
+#define strcasecmp stricmp
+#define memcpy q_memcpy
+#define memset q_memset
+#define strdup my_strdup
+#define random rand
+#define creat(x,y) open("T:creat",O_CREAT|O_RDWR|O_TRUNC,777)
+extern void* q_memset(void*,int,size_t);
+extern void* q_memcpy(void*,const void*,size_t);
+#endif
+
+#ifdef __DOS__
+#include <pc.h>
+#include <io.h>
+#endif
+
+/* Acorn specific stuff */
+#ifdef ACORN
+
+#define S_IRUSR S_IREAD
+#define S_IWUSR S_IWRITE
+#define S_IXUSR S_IEXEC
+
+#define strcasecmp stricmp
+
+#endif
+
+#ifndef L_tmpnam
+#define L_tmpnam 128 /* ought to be safe */
+#endif
+
+/* If char has more then 8 bits, good night. */
+typedef unsigned char uae_u8;
+typedef signed char uae_s8;
+
+typedef struct { uae_u8 RGB[3]; } RGB;
+
+#if SIZEOF_SHORT == 2
+typedef unsigned short uae_u16;
+typedef short uae_s16;
+#elif SIZEOF_INT == 2
+typedef unsigned int uae_u16;
+typedef int uae_s16;
+#else
+#error No 2 byte type, you lose.
+#endif
+
+#if SIZEOF_INT == 4
+typedef unsigned int uae_u32;
+typedef int uae_s32;
+#elif SIZEOF_LONG == 4
+typedef unsigned long uae_u32;
+typedef long uae_s32;
+#else
+#error No 4 byte type, you lose.
+#endif
+
+typedef uae_u32 uaecptr;
+
+#undef uae_s64
+#undef uae_u64
+
+#if SIZEOF_LONG_LONG == 8
+#define uae_s64 long long
+#define uae_u64 unsigned long long
+#define VAL64(a) (a ## LL)
+#define UVAL64(a) (a ## uLL)
+#elif SIZEOF___INT64 == 8
+#define uae_s64 __int64
+#define uae_u64 unsigned __int64
+#define VAL64(a) (a)
+#define UVAL64(a) (a)
+#elif SIZEOF_LONG == 8
+#define uae_s64 long;
+#define uae_u64 unsigned long;
+#define VAL64(a) (a ## l)
+#define UVAL64(a) (a ## ul)
+#endif
+
+#ifdef HAVE_STRDUP
+#define my_strdup strdup
+#else
+extern char *my_strdup (const char*s);
+#endif
+
+extern void *xmalloc(size_t);
+extern void *xcalloc(size_t, size_t);
+
+/* We can only rely on GNU C getting enums right. Mickeysoft VSC++ is known
+ * to have problems, and it's likely that other compilers choke too. */
+#ifdef __GNUC__
+#define ENUMDECL typedef enum
+#define ENUMNAME(name) name
+
+/* While we're here, make abort more useful.  */
+#define abort() \
+  do { \
+    write_log ("Internal error; file %s, line %d\n", __FILE__, __LINE__); \
+    (abort) (); \
+} while (0)
+#else
+#define ENUMDECL enum
+#define ENUMNAME(name) ; typedef int name
+#endif
+
+/*
+ * Porters to weird systems, look! This is the preferred way to get
+ * filesys.c (and other stuff) running on your system. Define the
+ * appropriate macros and implement wrappers in a machine-specific file.
+ *
+ * I guess the Mac port could use this (Ernesto?)
+ */
+
+#undef DONT_HAVE_POSIX
+#undef DONT_HAVE_REAL_POSIX /* define if open+delete doesn't do what it should */
+#undef DONT_HAVE_STDIO
+#undef DONT_HAVE_MALLOC
+
+#if defined(WARPUP)
+#define DONT_HAVE_POSIX
+#endif
+
+#if defined _WIN32
+
+#if defined __WATCOMC__
+
+#define O_NDELAY 0
+#include <direct.h>
+#define dirent direct
+#define mkdir(a,b) mkdir(a)
+#define strcasecmp stricmp
+
+#elif defined __MINGW32__
+
+#define O_NDELAY 0
+#define mkdir(a,b) mkdir(a)
+
+#elif defined _MSC_VER
+
+#ifdef HAVE_GETTIMEOFDAY
+#include <winsock.h> // for 'struct timeval' definition
+extern void gettimeofday( struct timeval *tv, void *blah );
+#endif
+
+#define O_NDELAY 0
+
+#define FILEFLAG_DIR     0x1
+#define FILEFLAG_ARCHIVE 0x2
+#define FILEFLAG_WRITE   0x4
+#define FILEFLAG_READ    0x8
+#define FILEFLAG_EXECUTE 0x10
+#define FILEFLAG_SCRIPT  0x20
+#define FILEFLAG_PURE    0x40
+
+#define REGPARAM 
+
+#include <io.h>
+#define O_BINARY _O_BINARY
+#define O_WRONLY _O_WRONLY
+#define O_RDONLY _O_RDONLY
+#define O_RDWR   _O_RDWR
+#define O_CREAT  _O_CREAT
+#define O_TRUNC  _O_TRUNC
+#define strcasecmp _stricmp
+#define strncasecmp _strnicmp
+#define W_OK 0x2
+#define R_OK 0x4
+#define STAT struct stat
+#define DIR struct DIR
+struct direct
+{
+    char d_name[1];
+};
+#include <sys/utime.h>
+#define utimbuf _utimbuf
+#define USE_ZFILE
+
+#undef S_ISDIR
+#undef S_IWUSR
+#undef S_IRUSR
+#undef S_IXUSR
+#define S_ISDIR(a) (a&FILEFLAG_DIR)
+#define S_ISARC(a) (a&FILEFLAG_ARCHIVE)
+#define S_IWUSR FILEFLAG_WRITE
+#define S_IRUSR FILEFLAG_READ
+#define S_IXUSR FILEFLAG_EXECUTE
+
+/* These are prototypes for functions from the Win32 posixemu file */
+extern void get_time(time_t t, long* days, long* mins, long* ticks);
+extern time_t put_time (long days, long mins, long ticks);
+extern DWORD getattr(const char *name, LPFILETIME lpft, size_t *size);
+
+/* #define DONT_HAVE_POSIX - don't need all of Mathias' posixemu_functions, just a subset (below) */
+#define chmod(a,b) posixemu_chmod ((a), (b))
+extern int posixemu_chmod (const char *, int);
+#define stat(a,b) posixemu_stat ((a), (b))
+extern int posixemu_stat (const char *, struct stat *);
+#define mkdir(x,y) mkdir(x)
+#define truncate posixemu_truncate
+extern int posixemu_truncate (const char *, long int);
+#define utime posixemu_utime
+extern int posixemu_utime (const char *, struct utimbuf *);
+#define opendir posixemu_opendir
+extern DIR * posixemu_opendir (const char *);
+#define readdir posixemu_readdir
+extern struct dirent* posixemu_readdir (DIR *);
+#define closedir posixemu_closedir
+extern void posixemu_closedir (DIR *);
+
+#endif
+
+#endif /* _WIN32 */ 
+
+#ifdef DONT_HAVE_POSIX
+
+#define access posixemu_access
+extern int posixemu_access (const char *, int);
+#define open posixemu_open
+extern int posixemu_open (const char *, int, int);
+#define close posixemu_close
+extern void posixemu_close (int);
+#define read posixemu_read
+extern int posixemu_read (int, char *, int);
+#define write posixemu_write
+extern int posixemu_write (int, const char *, int);
+#undef lseek
+#define lseek posixemu_seek
+extern int posixemu_seek (int, int, int);
+#define stat(a,b) posixemu_stat ((a), (b))
+extern int posixemu_stat (const char *, STAT *);
+#define mkdir posixemu_mkdir
+extern int mkdir (const char *, int);
+#define rmdir posixemu_rmdir
+extern int posixemu_rmdir (const char *);
+#define unlink posixemu_unlink
+extern int posixemu_unlink (const char *);
+#define truncate posixemu_truncate
+extern int posixemu_truncate (const char *, long int);
+#define rename posixemu_rename
+extern int posixemu_rename (const char *, const char *);
+#define chmod posixemu_chmod
+extern int posixemu_chmod (const char *, int);
+#define tmpnam posixemu_tmpnam
+extern void posixemu_tmpnam (char *);
+#define utime posixemu_utime
+extern int posixemu_utime (const char *, struct utimbuf *);
+#define opendir posixemu_opendir
+extern DIR * posixemu_opendir (const char *);
+#define readdir posixemu_readdir
+extern struct dirent* readdir (DIR *);
+#define closedir posixemu_closedir
+extern void closedir (DIR *);
+
+/* This isn't the best place for this, but it fits reasonably well. The logic
+ * is that you probably don't have POSIX errnos if you don't have the above
+ * functions. */
+extern long dos_errno (void);
+
+#endif
+
+#ifdef DONT_HAVE_STDIO
+
+extern FILE *stdioemu_fopen (const char *, const char *);
+#define fopen(a,b) stdioemu_fopen(a, b)
+extern int stdioemu_fseek (FILE *, int, int);
+#define fseek(a,b,c) stdioemu_fseek(a, b, c)
+extern int stdioemu_fread (char *, int, int, FILE *);
+#define fread(a,b,c,d) stdioemu_fread(a, b, c, d)
+extern int stdioemu_fwrite (const char *, int, int, FILE *);
+#define fwrite(a,b,c,d) stdioemu_fwrite(a, b, c, d)
+extern int stdioemu_ftell (FILE *);
+#define ftell(a) stdioemu_ftell(a)
+extern int stdioemu_fclose (FILE *);
+#define fclose(a) stdioemu_fclose(a)
+
+#endif
+
+#ifdef DONT_HAVE_MALLOC
+
+#define malloc(a) mallocemu_malloc(a)
+extern void *mallocemu_malloc (int size);
+#define free(a) mallocemu_free(a)
+extern void mallocemu_free (void *ptr);
+
+#endif
+
+#ifdef X86_ASSEMBLY
+#define ASM_SYM_FOR_FUNC(a) __asm__(a)
+#else
+#define ASM_SYM_FOR_FUNC(a)
+#endif
+
+#if defined USE_COMPILER
+#undef NO_PREFETCH_BUFFER
+#undef NO_EXCEPTION_3
+#define NO_EXCEPTION_3
+#define NO_PREFETCH_BUFFER
+#endif
+
+#include "target.h"
+
+#ifdef UAE_CONSOLE
+#undef write_log
+#define write_log write_log_standard
+#endif
+
+#if __GNUC__ - 1 > 1 || __GNUC_MINOR__ - 1 > 6
+extern void write_log (const char *, ...) __attribute__ ((format (printf, 1, 2)));
+#else
+extern void write_log (const char *, ...);
+#endif
+extern void write_dlog (const char *, ...);
+
+extern void console_out (const char *, ...);
+extern void console_flush (void);
+extern int console_get (char *, int);
+extern void f_out (void *, const char *, ...);
+extern void gui_message (const char *,...);
+#define write_log_err write_log
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#ifndef STATIC_INLINE
+#define STATIC_INLINE static __inline__
+#endif
+
+/* Every Amiga hardware clock cycle takes this many "virtual" cycles.  This
+   used to be hardcoded as 1, but using higher values allows us to time some
+   stuff more precisely.
+   512 is the official value from now on - it can't change, unless we want
+   _another_ config option "finegrain2_m68k_speed".
+
+   We define this value here rather than in events.h so that gencpu.c sees
+   it.  */
+#define CYCLE_UNIT 512
+
+/* This one is used by cfgfile.c.  We could reduce the CYCLE_UNIT back to 1,
+   I'm not 100% sure this code is bug free yet.  */
+#define OFFICIAL_CYCLE_UNIT 512
+
+/*
+ * You can specify numbers from 0 to 5 here. It is possible that higher
+ * numbers will make the CPU emulation slightly faster, but if the setting
+ * is too high, you will run out of memory while compiling.
+ * Best to leave this as it is.
+ */
+#define CPU_EMU_SIZE 0
diff --git a/include/tui.h b/include/tui.h
new file mode 100755 (executable)
index 0000000..d5c5f3b
--- /dev/null
@@ -0,0 +1,39 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Text-based user interface
+  * Sie haben es sich verdient!
+  *
+  * Copyright 1996 Tim Gunn, Bernd Schmidt
+  */
+
+extern void tui_setup(void);
+extern void tui_shutdown(void);
+extern void tui_refresh(void);
+
+extern void tui_curson(void);
+extern void tui_cursoff(void);
+
+extern void tui_cr(void);
+extern void tui_gotoxy(int, int);
+extern void tui_puts(const char *);
+extern void tui_putc(char);
+extern char tui_getc(void);
+extern int tui_gets(char *, int, int, int);
+extern int tui_wgets(char *, const char *, int);
+extern void tui_clrwin(int);
+extern void tui_selwin(int);
+
+extern int tui_dlog(int, int, int, int);
+extern int tui_menubrowse(struct bstring *, int, int, int, int);
+
+extern void tui_dlogdie(int);
+extern char *tui_filereq(char *, char *, const char *);
+extern void tui_drawbox(int);
+extern void tui_hline(int, int, int);
+extern void tui_errorbox(const char *);
+
+extern int tui_cols(void);
+extern int tui_lines(void);
+
+extern int tui_backup_optionsfile(void);
diff --git a/include/uae.h b/include/uae.h
new file mode 100755 (executable)
index 0000000..10338b6
--- /dev/null
@@ -0,0 +1,43 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Prototypes for main.c
+  *
+  * Copyright 1996 Bernd Schmidt
+  */
+
+extern void do_start_program (void);
+extern void do_leave_program (void);
+extern void start_program (void);
+extern void leave_program (void);
+extern void real_main (int, char **);
+extern void usage (void);
+extern void parse_cmdline (int argc, char **argv);
+extern void sleep_millis (int ms);
+
+
+extern void uae_reset (int);
+extern void uae_quit (void);
+extern void uae_restart (int, char*);
+extern void reset_all_systems (void);
+
+extern int quit_program;
+
+extern char warning_buffer[256];
+extern char *start_path;
+
+/* This structure is used to define menus. The val field can hold key
+ * shortcuts, or one of these special codes:
+ *   -4: deleted entry, not displayed, not selectable, but does count in
+ *       select value
+ *   -3: end of table
+ *   -2: line that is displayed, but not selectable
+ *   -1: line that is selectable, but has no keyboard shortcut
+ *    0: Menu title
+ */
+struct bstring {
+    const char *data;
+    int val;
+};
+
+extern char *colormodes[];
diff --git a/include/uaeexe.h b/include/uaeexe.h
new file mode 100755 (executable)
index 0000000..e43e8cf
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ *  uaeexe.h - launch executable in UAE
+ *
+ *  (c) 1997 by Samuel Devulder
+ */
+
+struct uae_xcmd {
+    struct uae_xcmd *prev,*next;
+    char *cmd;
+};
+
+#define UAEEXE_ORG         0xF0FF90 /* sam: I hope this slot is free */
+
+#define UAEEXE_OK          0
+#define UAEEXE_NOTRUNNING  1
+#define UAEEXE_NOMEM       2
+
+extern void uaeexe_install(void);
+extern int  uaeexe(char *cmd);
+
+
diff --git a/include/unzip.h b/include/unzip.h
new file mode 100755 (executable)
index 0000000..091b8df
--- /dev/null
@@ -0,0 +1,275 @@
+/* unzip.h -- IO for uncompress .zip files using zlib 
+   Version 0.15 beta, Mar 19th, 1998,
+
+   Copyright (C) 1998 Gilles Vollant
+
+   This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g
+     WinZip, InfoZip tools and compatible.
+   Encryption and multi volume ZipFile (span) are not supported.
+   Old compressions used by old PKZip 1.x are not supported
+
+   THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE
+   CAN CHANGE IN FUTURE VERSION !!
+   I WAIT FEEDBACK at mail info@winimage.com
+   Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution
+
+   Condition of use and distribution are the same than zlib :
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+
+*/
+/* for more info about .ZIP format, see 
+      ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip
+   PkWare has also a specification at :
+      ftp://ftp.pkware.com/probdesc.zip */
+
+#ifndef _unz_H
+#define _unz_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ZLIB_H
+#include "zlib.h"
+#endif
+
+#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
+/* like the STRICT of WIN32, we define a pointer that cannot be converted
+    from (void*) without cast */
+typedef struct TagunzFile__ { int unused; } unzFile__; 
+typedef unzFile__ *unzFile;
+#else
+typedef voidp unzFile;
+#endif
+
+
+#define UNZ_OK                                  (0)
+#define UNZ_END_OF_LIST_OF_FILE (-100)
+#define UNZ_ERRNO               (Z_ERRNO)
+#define UNZ_EOF                 (0)
+#define UNZ_PARAMERROR                  (-102)
+#define UNZ_BADZIPFILE                  (-103)
+#define UNZ_INTERNALERROR               (-104)
+#define UNZ_CRCERROR                    (-105)
+
+/* tm_unz contain date/time info */
+typedef struct tm_unz_s 
+{
+       uInt tm_sec;            /* seconds after the minute - [0,59] */
+       uInt tm_min;            /* minutes after the hour - [0,59] */
+       uInt tm_hour;           /* hours since midnight - [0,23] */
+       uInt tm_mday;           /* day of the month - [1,31] */
+       uInt tm_mon;            /* months since January - [0,11] */
+       uInt tm_year;           /* years - [1980..2044] */
+} tm_unz;
+
+/* unz_global_info structure contain global data about the ZIPfile
+   These data comes from the end of central dir */
+typedef struct unz_global_info_s
+{
+       uLong number_entry;         /* total number of entries in
+                                      the central dir on this disk */
+       uLong size_comment;         /* size of the global comment of the zipfile */
+} unz_global_info;
+
+
+/* unz_file_info contain information about a file in the zipfile */
+typedef struct unz_file_info_s
+{
+    uLong version;              /* version made by                 2 bytes */
+    uLong version_needed;       /* version needed to extract       2 bytes */
+    uLong flag;                 /* general purpose bit flag        2 bytes */
+    uLong compression_method;   /* compression method              2 bytes */
+    uLong dosDate;              /* last mod file date in Dos fmt   4 bytes */
+    uLong crc;                  /* crc-32                          4 bytes */
+    uLong compressed_size;      /* compressed size                 4 bytes */ 
+    uLong uncompressed_size;    /* uncompressed size               4 bytes */ 
+    uLong size_filename;        /* filename length                 2 bytes */
+    uLong size_file_extra;      /* extra field length              2 bytes */
+    uLong size_file_comment;    /* file comment length             2 bytes */
+
+    uLong disk_num_start;       /* disk number start               2 bytes */
+    uLong internal_fa;          /* internal file attributes        2 bytes */
+    uLong external_fa;          /* external file attributes        4 bytes */
+
+    tm_unz tmu_date;
+} unz_file_info;
+
+extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1,
+                                                                                                const char* fileName2,
+                                                                                                int iCaseSensitivity));
+/*
+   Compare two filename (fileName1,fileName2).
+   If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
+   If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
+                                                               or strcasecmp)
+   If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
+       (like 1 on Unix, 2 on Windows)
+*/
+
+
+extern unzFile ZEXPORT unzOpen OF((struct zfile *path));
+/*
+  Open a Zip file. path contain the full pathname (by example,
+     on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer
+        "zlib/zlib111.zip".
+        If the zipfile cannot be opened (file don't exist or in not valid), the
+          return value is NULL.
+     Else, the return value is a unzFile Handle, usable with other function
+          of this unzip package.
+*/
+
+extern int ZEXPORT unzClose OF((unzFile file));
+/*
+  Close a ZipFile opened with unzipOpen.
+  If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
+    these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
+  return UNZ_OK if there is no problem. */
+
+extern int ZEXPORT unzGetGlobalInfo OF((unzFile file,
+                                       unz_global_info *pglobal_info));
+/*
+  Write info about the ZipFile in the *pglobal_info structure.
+  No preparation of the structure is needed
+  return UNZ_OK if there is no problem. */
+
+
+extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
+                                                                                  char *szComment,
+                                          uLong uSizeBuf));
+/*
+  Get the global comment string of the ZipFile, in the szComment buffer.
+  uSizeBuf is the size of the szComment buffer.
+  return the number of byte copied or an error code <0
+*/
+
+
+/***************************************************************************/
+/* Unzip package allow you browse the directory of the zipfile */
+
+extern int ZEXPORT unzGoToFirstFile OF((unzFile file));
+/*
+  Set the current file of the zipfile to the first file.
+  return UNZ_OK if there is no problem
+*/
+
+extern int ZEXPORT unzGoToNextFile OF((unzFile file));
+/*
+  Set the current file of the zipfile to the next file.
+  return UNZ_OK if there is no problem
+  return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
+*/
+
+extern int ZEXPORT unzLocateFile OF((unzFile file, 
+                                    const char *szFileName,
+                                    int iCaseSensitivity));
+/*
+  Try locate the file szFileName in the zipfile.
+  For the iCaseSensitivity signification, see unzStringFileNameCompare
+
+  return value :
+  UNZ_OK if the file is found. It becomes the current file.
+  UNZ_END_OF_LIST_OF_FILE if the file is not found
+*/
+
+
+extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,
+                                            unz_file_info *pfile_info,
+                                            char *szFileName,
+                                            uLong fileNameBufferSize,
+                                            void *extraField,
+                                            uLong extraFieldBufferSize,
+                                            char *szComment,
+                                            uLong commentBufferSize));
+/*
+  Get Info about the current file
+  if pfile_info!=NULL, the *pfile_info structure will contain somes info about
+           the current file
+  if szFileName!=NULL, the filemane string will be copied in szFileName
+                       (fileNameBufferSize is the size of the buffer)
+  if extraField!=NULL, the extra field information will be copied in extraField
+                       (extraFieldBufferSize is the size of the buffer).
+                       This is the Central-header version of the extra field
+  if szComment!=NULL, the comment string of the file will be copied in szComment
+                       (commentBufferSize is the size of the buffer)
+*/
+
+/***************************************************************************/
+/* for reading the content of the current zipfile, you can open it, read data
+   from it, and close it (you can close it before reading all the file)
+   */
+
+extern int ZEXPORT unzOpenCurrentFile OF((unzFile file));
+/*
+  Open for reading data the current file in the zipfile.
+  If there is no error, the return value is UNZ_OK.
+*/
+
+extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
+/*
+  Close the file in zip opened with unzOpenCurrentFile
+  Return UNZ_CRCERROR if all the file was read but the CRC is not good
+*/
+
+                                                                                               
+extern int ZEXPORT unzReadCurrentFile OF((unzFile file, 
+                                         voidp buf,
+                                         unsigned len));
+/*
+  Read bytes from the current file (opened by unzOpenCurrentFile)
+  buf contain buffer where data must be copied
+  len the size of buf.
+
+  return the number of byte copied if somes bytes are copied
+  return 0 if the end of file was reached
+  return <0 with error code if there is an error
+    (UNZ_ERRNO for IO error, or zLib error for uncompress error)
+*/
+
+extern z_off_t ZEXPORT unztell OF((unzFile file));
+/*
+  Give the current position in uncompressed data
+*/
+
+extern int ZEXPORT unzeof OF((unzFile file));
+/*
+  return 1 if the end of file was reached, 0 elsewhere 
+*/
+
+extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file,
+                                                                                        voidp buf,
+                                                                                        unsigned len));
+/*
+  Read extra field from the current file (opened by unzOpenCurrentFile)
+  This is the local-header version of the extra field (sometimes, there is
+    more info in the local-header version than in the central-header)
+
+  if buf==NULL, it return the size of the local extra field
+
+  if buf!=NULL, len is the size of the buffer, the extra header is copied in
+       buf.
+  the return value is the number of bytes copied in buf, or (if <0) 
+       the error code
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _unz_H */
diff --git a/include/xwin.h b/include/xwin.h
new file mode 100755 (executable)
index 0000000..81f7184
--- /dev/null
@@ -0,0 +1,88 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Interface to the graphics system (X, SVGAlib)
+  *
+  * Copyright 1995-1997 Bernd Schmidt
+  */
+
+typedef long int xcolnr;
+
+typedef int (*allocfunc_type)(int, int, int, xcolnr *);
+
+extern xcolnr xcolors[4096];
+
+extern int buttonstate[3];
+extern int newmousecounters;
+extern int lastmx, lastmy;
+extern int ievent_alive;
+
+extern int graphics_setup (void);
+extern int graphics_init (void);
+extern void graphics_leave (void);
+extern void handle_events (void);
+extern void setup_brkhandler (void);
+extern int isfullscreen (void);
+
+extern void flush_line (int);
+extern void flush_block (int, int);
+extern void flush_screen (int, int);
+extern void flush_clear_screen (void);
+
+extern int lockscr (void);
+extern void unlockscr (void);
+
+extern int debuggable (void);
+extern int needmousehack (void);
+extern void togglemouse (void);
+extern void LED (int);
+extern void screenshot (int);
+
+extern int bits_in_mask (unsigned long mask);
+extern int mask_shift (unsigned long mask);
+extern unsigned long doMask (int p, int bits, int shift);
+extern unsigned long doMask256 (int p, int bits, int shift);
+extern void setup_maxcol (int);
+extern void alloc_colors256 (int (*)(int, int, int, xcolnr *));
+extern void alloc_colors64k (int, int, int, int, int, int, int, int, int);
+extern void setup_greydither (int bits, allocfunc_type allocfunc);
+extern void setup_greydither_maxcol (int maxcol, allocfunc_type allocfunc);
+extern void setup_dither (int bits, allocfunc_type allocfunc);
+extern void DitherLine (uae_u8 *l, uae_u16 *r4g4b4, int x, int y, uae_s16 len, int bits) ASM_SYM_FOR_FUNC("DitherLine");
+
+struct vidbuf_description
+{
+    /* The graphics code has a choice whether it wants to use a large buffer
+     * for the whole display, or only a small buffer for a single line.
+     * If you use a large buffer:
+     *   - set bufmem to point at it
+     *   - set linemem to 0
+     *   - if memcpy within bufmem would be very slow, i.e. because bufmem is
+     *     in graphics card memory, also set emergmem to point to a buffer 
+     *     that is large enough to hold a single line.
+     *   - implement flush_line to be a no-op.
+     * If you use a single line buffer:
+     *   - set bufmem and emergmem to 0
+     *   - set linemem to point at your buffer
+     *   - implement flush_line to copy a single line to the screen
+     */
+    uae_u8 *bufmem;
+    uae_u8 *realbufmem;
+    uae_u8 *linemem;
+    uae_u8 *emergmem;
+    int rowbytes; /* Bytes per row in the memory pointed at by bufmem. */
+    int pixbytes; /* Bytes per pixel. */
+    int width;
+    int height;
+    int maxblocklines; /* Set to 0 if you want calls to flush_line after each drawn line, or the number of
+                       * lines that flush_block wants to/can handle (it isn't really useful to use another
+                       * value than maxline here). */
+    int can_double; /* Set if the high part of each entry in xcolors contains the same value
+                    * as the low part, so that two pixels can be drawn at once. */
+};
+
+extern struct vidbuf_description gfxvidinfo;
+
+/* For ports using tui.c, this should be built by graphics_setup(). */
+extern struct bstring *video_mode_menu;
+extern void vidmode_menu_selected(int);
diff --git a/include/zfile.h b/include/zfile.h
new file mode 100755 (executable)
index 0000000..8d6bd09
--- /dev/null
@@ -0,0 +1,34 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * routines to handle compressed file automatically
+  *
+  * (c) 1996 Samuel Devulder
+  */
+
+struct zfile;
+extern int is_zlib;
+
+extern struct zfile *zfile_fopen (const char *, const char *);
+extern struct zfile *zfile_fopen_empty (const char *name, int size);
+extern int zfile_exists (const char *name);
+extern void zfile_fclose (struct zfile *);
+extern int zfile_fseek (struct zfile *z, long offset, int mode);
+extern long zfile_ftell (struct zfile *z);
+extern size_t zfile_fread  (void *b, size_t l1, size_t l2, struct zfile *z);
+extern size_t zfile_fwrite  (void *b, size_t l1, size_t l2, struct zfile *z);
+extern void zfile_exit (void);
+extern int execute_command (char *);
+extern int zfile_iscompressed (struct zfile *z);
+extern int zfile_zcompress (struct zfile *dst, void *src, int size);
+extern int zfile_zuncompress (void *dst, int dstsize, struct zfile *src, int srcsize);
+extern int zfile_gettype (struct zfile *z);
+
+#define ZFILE_UNKNOWN 0
+#define ZFILE_CONFIGURATION 1
+#define ZFILE_DISKIMAGE 2
+#define ZFILE_ROM 3
+#define ZFILE_KEY 4
+#define ZFILE_HDF 5
+#define ZFILE_STATEFILE 6
+#define ZFILE_NVR 7
\ No newline at end of file
diff --git a/inputdevice.c b/inputdevice.c
new file mode 100755 (executable)
index 0000000..aa27ae7
--- /dev/null
@@ -0,0 +1,2253 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * joystick/mouse emulation
+  *
+  * Copyright 2001, 2002 Toni Wilen
+  *
+  * new fetures:
+  * - very configurable (and very complex to configure :)
+  * - supports multiple native input devices (joysticks and mice)
+  * - supports mapping joystick/mouse buttons to keys and vice versa
+  * - joystick mouse emulation (supports both ports)
+  * - supports parallel port joystick adapter
+  * - full cd32 pad support (supports both ports)
+  * - fully backward compatible with old joystick/mouse configuration
+  *
+  */
+
+//#define DONGLE_DEBUG
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "keyboard.h"
+#include "inputdevice.h"
+#include "keybuf.h"
+#include "custom.h"
+#include "xwin.h"
+#include "drawing.h"
+#include "memory.h"
+#include "events.h"
+#include "newcpu.h"
+#include "uae.h"
+#include "picasso96.h"
+#include "catweasel.h"
+#include "debug.h"
+#include "ar.h"
+#include "gui.h"
+#include "disk.h"
+#include "sound.h"
+#include "savestate.h"
+
+#define DIR_LEFT 1
+#define DIR_RIGHT 2
+#define DIR_UP 4
+#define DIR_DOWN 8
+
+struct inputevent {
+    char *confname;
+    char *name;
+    int allow_mask;
+    int type;
+    int unit;
+    int data;
+};
+
+#define JOYBUTTON_1 0 /* fire/left mousebutton */
+#define JOYBUTTON_2 1 /* 2nd/right mousebutton */
+#define JOYBUTTON_3 2 /* 3rd/middle mousebutton */
+#define JOYBUTTON_CD32_PLAY 3
+#define JOYBUTTON_CD32_RWD 4
+#define JOYBUTTON_CD32_FFW 5
+#define JOYBUTTON_CD32_GREEN 6
+#define JOYBUTTON_CD32_YELLOW 7
+#define JOYBUTTON_CD32_RED 8
+#define JOYBUTTON_CD32_BLUE 9
+
+#define INPUTEVENT_JOY1_CD32_FIRST INPUTEVENT_JOY1_CD32_PLAY
+#define INPUTEVENT_JOY2_CD32_FIRST INPUTEVENT_JOY2_CD32_PLAY
+#define INPUTEVENT_JOY1_CD32_LAST INPUTEVENT_JOY1_CD32_BLUE
+#define INPUTEVENT_JOY2_CD32_LAST INPUTEVENT_JOY2_CD32_BLUE
+
+/* event masks */
+#define AM_KEY 1 /* keyboard allowed */
+#define AM_JOY_BUT 2 /* joystick buttons allowed */
+#define AM_JOY_AXIS 4 /* joystick axis allowed */
+#define AM_MOUSE_BUT 8 /* mouse buttons allowed */
+#define AM_MOUSE_AXIS 16 /* mouse direction allowed */
+#define AM_AF 32 /* supports autofire */
+#define AM_INFO 64 /* information data for gui */
+#define AM_DUMMY 128 /* placeholder */
+#define AM_K (AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF) /* keyboard */
+
+/* event flags */
+#define ID_FLAG_AUTOFIRE 1
+
+#define DEFEVENT(A, B, C, D, E, F) {#A, B, C, D, E, F },
+struct inputevent events[] = {
+{0, 0, 0, 0, 0, 0},
+#include "inputevents.def"
+{0, 0, 0, 0, 0, 0}
+};
+#undef DEFEVENT
+
+static int sublevdir[2][MAX_INPUT_SUB_EVENT];
+
+struct uae_input_device2 {
+    uae_u32 buttonmask;
+    int states[MAX_INPUT_DEVICE_EVENTS / 2];
+};
+
+static struct uae_input_device2 joysticks2[MAX_INPUT_DEVICES];
+static struct uae_input_device2 mice2[MAX_INPUT_DEVICES];
+
+static uae_u8 mouse_settings_reset[MAX_INPUT_SETTINGS][MAX_INPUT_DEVICES];
+static uae_u8 joystick_settings_reset[MAX_INPUT_SETTINGS][MAX_INPUT_DEVICES];
+
+static int isdevice (struct uae_input_device *id)
+{
+    int i, j;
+    for (i = 0; i < MAX_INPUT_DEVICE_EVENTS; i++) {
+       for (j = 0; j < MAX_INPUT_SUB_EVENT; j++) {
+           if (id->eventid[i][j] > 0)
+               return 1;
+       }
+    }
+    return 0;
+}
+
+static struct uae_input_device *joysticks;
+static struct uae_input_device *mice;
+static struct uae_input_device *keyboards;
+static struct uae_input_device_kbr_default *keyboard_default;
+
+static double mouse_axis[MAX_INPUT_DEVICES][MAX_INPUT_DEVICE_EVENTS];
+static double oldm_axis[MAX_INPUT_DEVICES][MAX_INPUT_DEVICE_EVENTS];
+
+static int mouse_x[MAX_INPUT_DEVICES], mouse_y[MAX_INPUT_DEVICE_EVENTS];
+static int mouse_delta[MAX_INPUT_DEVICES][MAX_INPUT_DEVICE_EVENTS];
+static int mouse_deltanoreset[MAX_INPUT_DEVICES][MAX_INPUT_DEVICE_EVENTS];
+static int joybutton[MAX_INPUT_DEVICES];
+static unsigned int joydir[MAX_INPUT_DEVICE_EVENTS];
+static int joydirpot[MAX_INPUT_DEVICE_EVENTS][2];
+static int mouse_frame_x[2], mouse_frame_y[2];
+
+static int lastmx, lastmy;
+
+static int mouse_port[2];
+static int cd32_shifter[2];
+static int cd32_pad_enabled[2];
+static int parport_joystick_enabled;
+static int oldmx[4], oldmy[4];
+static int oleft[4], oright[4], otop[4], obot[4];
+static int potgo_hsync;
+
+static int use_joysticks[MAX_INPUT_DEVICES];
+static int use_mice[MAX_INPUT_DEVICES];
+static int use_keyboards[MAX_INPUT_DEVICES];
+
+#define INPUT_QUEUE_SIZE 16
+struct input_queue_struct {
+    int event, storedstate, state, max, framecnt, nextframecnt;
+};
+static struct input_queue_struct input_queue[INPUT_QUEUE_SIZE];
+
+static void out_config (FILE *f, int id, int num, char *s1, char *s2)
+{
+    cfgfile_write (f, "input.%d.%s%d=%s\n", id, s1, num, s2);
+    //write_log ("-input.%d.%s%d=%s\n", id, s1, num, s2);
+}
+
+static void write_config2 (FILE *f, int idnum, int i, int offset, char *tmp1, struct uae_input_device *id)
+{
+    char tmp2[200], *p;
+    int event, got, j, k;
+
+    p = tmp2;
+    got = 0;
+    for (j = 0; j < MAX_INPUT_SUB_EVENT; j++) {
+        event = id->eventid[i + offset][j];
+       if (event <= 0) {
+           for (k = j + 1; k < MAX_INPUT_SUB_EVENT; k++) {
+               if (id->eventid[i + offset][k] > 0) break;
+           }
+           if (k == MAX_INPUT_SUB_EVENT)
+               break;
+       }
+       if (p > tmp2) {
+           *p++ = ',';
+           *p = 0;
+       }
+       if (event <= 0)
+           sprintf (p, "NULL");
+       else
+           sprintf (p, "%s.%d", events[event].confname, id->flags[i + offset][j]);
+       p += strlen (p);
+    }
+    if (p > tmp2)
+       out_config (f, idnum, i, tmp1, tmp2);
+}
+
+static void write_config (FILE *f, int idnum, int devnum, char *name, struct uae_input_device *id, struct uae_input_device2 *id2)
+{
+    char tmp1[100];
+    int i;
+
+    if (!isdevice (id))
+       return;
+    cfgfile_write (f, "input.%d.%s.%d.disabled=%d\n", idnum, name, devnum, id->enabled ? 0 : 1);
+    sprintf (tmp1, "%s.%d.axis.", name, devnum);
+    for (i = 0; i < ID_AXIS_TOTAL; i++)
+       write_config2 (f, idnum, i, ID_AXIS_OFFSET, tmp1, id);
+    sprintf (tmp1, "%s.%d.button." ,name, devnum);
+    for (i = 0; i < ID_BUTTON_TOTAL; i++)
+       write_config2 (f, idnum, i, ID_BUTTON_OFFSET, tmp1, id);
+}
+
+static void kbrlabel (char *s)
+{
+    while (*s) {
+       *s = toupper(*s);
+       if (*s == ' ') *s = '_';
+       s++;
+    }
+}
+
+static void write_kbr_config (FILE *f, int idnum, int devnum, struct uae_input_device *kbr)
+{
+    char tmp1[200], tmp2[200], tmp3[200], *p;
+    int i, j, k, event, skip;
+
+    if (!keyboard_default)
+       return;
+    i = 0;
+    while (i < MAX_INPUT_DEVICE_EVENTS && kbr->extra[i][0] >= 0) {
+       skip = 0;
+       k = 0;
+       while (keyboard_default[k].scancode >= 0) {
+           if (keyboard_default[k].scancode == kbr->extra[i][0]) {
+               skip = 1;
+               for (j = 1; j < MAX_INPUT_SUB_EVENT; j++) {
+                   if (kbr->flags[i][j] || kbr->eventid[i][j] > 0)
+                       skip = 0;
+               }
+               if (keyboard_default[k].event != kbr->eventid[i][0] || kbr->flags[i][0] != 0)
+                   skip = 0;
+               break;
+           }
+           k++;
+       }
+       if (kbr->eventid[i][0] == 0 && kbr->flags[i][0] == 0 && keyboard_default[k].scancode < 0)
+           skip = 1;
+       if (skip) {
+           i++;
+           continue;
+       }
+       p = tmp2;
+       p[0] = 0;
+       for (j = 0; j < MAX_INPUT_SUB_EVENT; j++) {
+           event = kbr->eventid[i][j];
+           if (event <= 0) {
+               for (k = j + 1; k < MAX_INPUT_SUB_EVENT; k++) {
+                   if (kbr->eventid[i][k] > 0) break;
+               }
+               if (k == MAX_INPUT_SUB_EVENT)
+                   break;
+           }
+           if (p > tmp2) {
+               *p++ = ',';
+               *p = 0;
+           }
+           if (event > 0)
+               sprintf (p, "%s.%d", events[event].confname, kbr->flags[i][j]);
+           else
+               strcat (p, "NULL");
+           p += strlen(p);
+       }
+       sprintf (tmp3, "%d", kbr->extra[i][0]);
+       kbrlabel (tmp3);
+       sprintf (tmp1, "keyboard.%d.button.%s", devnum, tmp3);
+        cfgfile_write (f, "input.%d.%s=%s\n", idnum, tmp1, tmp2);
+       i++;
+    }
+}
+
+void write_inputdevice_config (struct uae_prefs *p, FILE *f)
+{
+    int i, id;
+
+    cfgfile_write (f, "input.config=%d\n", p->input_selected_setting);
+    cfgfile_write (f, "input.joymouse_speed_analog=%d\n", p->input_joymouse_multiplier);
+    cfgfile_write (f, "input.joymouse_speed_digital=%d\n", p->input_joymouse_speed);
+    cfgfile_write (f, "input.joymouse_deadzone=%d\n", p->input_joymouse_deadzone);
+    cfgfile_write (f, "input.joystick_deadzone=%d\n", p->input_joystick_deadzone);
+    cfgfile_write (f, "input.mouse_speed=%d\n", p->input_mouse_speed);
+    cfgfile_write (f, "input.autofire=%d\n", p->input_autofire_framecnt);
+    for (id = 1; id <= MAX_INPUT_SETTINGS; id++) {
+       for (i = 0; i < MAX_INPUT_DEVICES; i++)
+           write_config (f, id, i, "joystick", &p->joystick_settings[id][i], &joysticks2[i]);
+       for (i = 0; i < MAX_INPUT_DEVICES; i++)
+           write_config (f, id, i, "mouse", &p->mouse_settings[id][i], &mice2[i]);
+       for (i = 0; i < MAX_INPUT_DEVICES; i++)
+           write_kbr_config (f, id, i, &p->keyboard_settings[id][i]);
+    }
+}
+
+static int getnum (char **pp)
+{
+    char *p = *pp;
+    int v = atol (p);
+
+    while (*p != 0 && *p !='.' && *p != ',') p++;
+    if (*p == '.' || *p == ',') p++;
+    *pp = p;
+    return v;
+}
+static char *getstring (char **pp)
+{
+    int i;
+    static char str[100];
+    char *p = *pp;
+
+    if (*p == 0)
+       return 0;
+    i = 0;
+    while (*p != 0 && *p !='.' && *p != ',') str[i++] = *p++;
+    if (*p == '.' || *p == ',') p++;
+    str[i] = 0;
+    *pp = p;
+    return str;
+}
+
+void reset_inputdevice_config (struct uae_prefs *pr)
+{
+    memset (joystick_settings_reset, 0, sizeof (joystick_settings_reset));
+    memset (mouse_settings_reset, 0, sizeof (mouse_settings_reset));
+}
+
+void read_inputdevice_config (struct uae_prefs *pr, char *option, char *value)
+{
+    struct uae_input_device *id = 0;
+    struct inputevent *ie;
+    int devnum, num, button, joystick, flags, i, subnum, idnum, keynum;
+    int mask;
+    char *p, *p2;
+
+    option += 6; /* "input." */
+    p = getstring (&option);
+    if (!strcasecmp (p, "config")) 
+       pr->input_selected_setting = atol (value);
+    if (!strcasecmp (p, "joymouse_speed_analog")) 
+       pr->input_joymouse_multiplier = atol (value);
+    if (!strcasecmp (p, "joymouse_speed_digital")) 
+       pr->input_joymouse_speed = atol (value);
+    if (!strcasecmp (p, "joystick_deadzone")) 
+       pr->input_joystick_deadzone = atol (value);
+    if (!strcasecmp (p, "joymouse_deadzone")) 
+       pr->input_joymouse_deadzone = atol (value);
+    if (!strcasecmp (p, "mouse_speed")) 
+       pr->input_mouse_speed = atol (value);
+    if (!strcasecmp (p, "autofire")) 
+       pr->input_autofire_framecnt = atol (value);
+    idnum = atol (p);
+    if (idnum <= 0 || idnum > MAX_INPUT_SETTINGS)
+       return;
+    if (memcmp (option, "mouse.", 6) == 0) {
+       p = option + 6;
+        devnum = getnum (&p);
+       if (devnum < 0 || devnum >= MAX_INPUT_DEVICES)
+           return;
+       id = &pr->mouse_settings[idnum][devnum];
+       if (!mouse_settings_reset[idnum][devnum]) {
+           memset (id, 0, sizeof (struct uae_input_device));
+           id->enabled = 1;
+       }
+       mouse_settings_reset[idnum][devnum] = 1;
+       joystick = 0;
+    } else if (memcmp (option, "joystick.", 9) == 0) {
+       p = option + 9;
+        devnum = getnum (&p);
+       if (devnum < 0 || devnum >= MAX_INPUT_DEVICES)
+           return;
+       id = &pr->joystick_settings[idnum][devnum];
+       if (!joystick_settings_reset[idnum][devnum]) {
+           memset (id, 0, sizeof (struct uae_input_device));
+           id->enabled = 1;
+       }
+       joystick_settings_reset[idnum][devnum] = 1;
+       joystick = 1;
+    } else if (memcmp (option, "keyboard.", 9) == 0) {
+       joystick = -1;
+       p = option + 9;
+        devnum = getnum (&p);
+       if (devnum < 0 || devnum >= MAX_INPUT_DEVICES)
+           return;
+       id = &pr->keyboard_settings[idnum][devnum];
+    }
+    if (!id)
+       return;
+    p2 = getstring (&p);
+    if (!p2)
+       return;
+    if (!strcmp (p2, "disabled")) {
+       int disabled;
+       p = value;
+       disabled = getnum (&p);
+       id->enabled = disabled == 0 ? 1 : 0;
+       return;
+    }
+
+    if (joystick < 0) {
+       num = getnum (&p);
+       keynum = 0;
+       while (id->extra[keynum][0] >= 0) {
+           if (id->extra[keynum][0] == num)
+               break;
+           keynum++;
+       }
+       if (id->extra[keynum][0] < 0)
+           return;
+    } else {
+       button = -1;
+       if (!strcmp (p2, "axis"))
+           button = 0;
+       else if(!strcmp (p2, "button"))
+           button = 1;
+       if (button < 0)
+           return;
+       num = getnum (&p);
+    }
+    p = value;
+    
+    subnum = 0;
+    while (subnum < MAX_INPUT_SUB_EVENT) {
+       p2 = getstring (&p);
+       if (!p2) break;
+       i = 1;
+       while (events[i].name) {
+           if (!strcmp (events[i].confname, p2))
+               break;
+           i++;
+       }
+       ie = &events[i];
+       if (!ie->name) {
+           subnum++;
+           continue;
+       }
+       flags = getnum (&p);
+       if (joystick < 0) {
+           if (!(ie->allow_mask & AM_K))
+               return;
+           id->eventid[keynum][subnum] = ie - events;
+           id->flags[keynum][subnum] = flags;
+       } else  if (button) {
+           if (joystick)
+               mask = AM_JOY_BUT;
+           else
+               mask = AM_MOUSE_BUT;
+           if (!(ie->allow_mask & mask))
+               return;
+           id->eventid[num + ID_BUTTON_OFFSET][subnum] = ie - events;
+           id->flags[num + ID_BUTTON_OFFSET][subnum] = flags;
+       } else {
+           if (joystick)
+               mask = AM_JOY_AXIS;
+           else
+               mask = AM_MOUSE_AXIS;
+           if (!(ie->allow_mask & mask))
+               return;
+           id->eventid[num + ID_AXIS_OFFSET][subnum] = ie - events;
+           id->flags[num + ID_AXIS_OFFSET][subnum] = flags;
+       }
+       subnum++;
+    }
+}
+
+/* Mousehack stuff */
+
+#define defstepx (1<<16)
+#define defstepy (1<<16)
+#define defxoffs 0
+#define defyoffs 0
+
+static const int docal = 60, xcaloff = 40, ycaloff = 20;
+static const int calweight = 3;
+static int lastsampledmx, lastsampledmy;
+static int lastspr0x,lastspr0y,lastdiffx,lastdiffy,spr0pos,spr0ctl;
+static int mstepx,mstepy,xoffs=defxoffs,yoffs=defyoffs;
+static int sprvbfl;
+
+static enum mousestate mousestate;
+
+void mousehack_handle (int sprctl, int sprpos)
+{                  
+    if (!sprvbfl && ((sprpos & 0xff) << 2) > 2 * DISPLAY_LEFT_SHIFT) {
+       spr0ctl = sprctl;
+       spr0pos = sprpos;
+       sprvbfl = 2;
+    }
+}
+
+static void mousehack_setunknown (void)
+{
+    mousestate = mousehack_unknown;
+}
+
+static void mousehack_setdontcare (void)
+{
+    if (mousestate == mousehack_dontcare)
+       return;
+
+    write_log ("Don't care mouse mode set\n");
+    mousestate = mousehack_dontcare;
+    lastspr0x = lastmx; lastspr0y = lastmy;
+    mstepx = defstepx; mstepy = defstepy;
+}
+
+static void mousehack_setfollow (void)
+{
+    if (mousestate == mousehack_follow)
+       return;
+    write_log ("Follow sprite mode set\n");
+    mousestate = mousehack_follow;
+    lastdiffx = lastdiffy = 0;
+    sprvbfl = 0;
+    spr0ctl = spr0pos = 0;
+    mstepx = defstepx; mstepy = defstepy;
+}
+
+void mousehack_set (int state)
+{
+    switch (state)
+    {
+       case mousehack_dontcare:
+       mousehack_setdontcare();
+       break;
+       case mousehack_follow:
+       mousehack_setfollow();
+       break;
+       default:
+       mousestate = state;
+       break;
+    }
+}
+
+uae_u32 mousehack_helper (void)
+{
+    int mousexpos, mouseypos;
+
+#ifdef PICASSO96
+    if (picasso_on) {
+       mousexpos = lastmx - picasso96_state.XOffset;
+       mouseypos = lastmy - picasso96_state.YOffset;
+    } else
+#endif
+    {
+       if (mouse_y[0] >= gfxvidinfo.height)
+           mouse_y[0] = gfxvidinfo.height - 1;
+       mouseypos = coord_native_to_amiga_y (lastmy) << 1;
+       mousexpos = coord_native_to_amiga_x (lastmx);
+    }
+
+    switch (m68k_dreg (regs, 0)) {
+    case 0:
+       return ievent_alive ? -1 : needmousehack ();
+    case 1:
+       ievent_alive = 10;
+       return mousexpos;
+    case 2:
+       return mouseypos;
+    }
+    return 0;
+}
+
+void togglemouse (void)
+{
+    switch (mousestate) {
+     case mousehack_dontcare: mousehack_setfollow (); break;
+     case mousehack_follow: mousehack_setdontcare (); break;
+     default: break; /* Nnnnnghh! */
+    }
+}
+
+STATIC_INLINE int adjust (int val)
+{
+    if (val > 127)
+       return 127;
+    else if (val < -127)
+       return -127;
+    return val;
+}
+
+static void do_mouse_hack (void)
+{
+    int spr0x = ((spr0pos & 0xff) << 2) | ((spr0ctl & 1) << 1);
+    int spr0y = ((spr0pos >> 8) | ((spr0ctl & 4) << 6)) << 1;
+    int diffx, diffy;
+
+#if 0
+    if (ievent_alive > 0) {
+       mouse_x[0] = mouse_y[0] = 0;
+       return;
+    }
+#endif
+    switch (mousestate) {
+    case mousehack_normal:
+#if 0
+       diffx = lastmx - lastsampledmx;
+       diffy = lastmy - lastsampledmy;
+       if (!newmousecounters) {
+           if (diffx > 127) diffx = 127;
+           if (diffx < -127) diffx = -127;
+           mouse_x[0] += diffx;
+           if (diffy > 127) diffy = 127;
+           if (diffy < -127) diffy = -127;
+           mouse_y[0] += diffy;
+       }
+       lastsampledmx += diffx; lastsampledmy += diffy;
+#endif
+       break;
+
+    case mousehack_dontcare:
+#if 0
+       diffx = adjust (((lastmx - lastspr0x) * mstepx) >> 16);
+       diffy = adjust (((lastmy - lastspr0y) * mstepy) >> 16);
+       lastspr0x = lastmx; lastspr0y = lastmy;
+       mouse_x[0] += diffx; mouse_y[0] += diffy;
+#endif
+       break;
+
+    case mousehack_follow:
+       if (sprvbfl && sprvbfl-- > 1) {
+           int mousexpos, mouseypos;
+
+           if ((lastdiffx > docal || lastdiffx < -docal)
+               && lastspr0x != spr0x
+               && spr0x > plfstrt*4 + 34 + xcaloff
+               && spr0x < plfstop*4 - xcaloff)
+           {
+               int val = (lastdiffx << 16) / (spr0x - lastspr0x);
+               if (val >= 0x8000)
+                   mstepx = (mstepx * (calweight - 1) + val) / calweight;
+           }
+           if ((lastdiffy > docal || lastdiffy < -docal)
+               && lastspr0y != spr0y
+               && spr0y > plffirstline + ycaloff
+               && spr0y < plflastline - ycaloff)
+           {
+               int val = (lastdiffy << 16) / (spr0y - lastspr0y);
+               if (val >= 0x8000)
+                   mstepy = (mstepy * (calweight - 1) + val) / calweight;
+           }
+           if (mouse_y[0] >= gfxvidinfo.height)
+               mouse_y[0] = gfxvidinfo.height-1;
+           mouseypos = coord_native_to_amiga_y (lastmy) << 1;
+           mousexpos = coord_native_to_amiga_x (lastmx);
+           diffx = adjust ((((mousexpos + xoffs - spr0x) & ~1) * mstepx) >> 16);
+           diffy = adjust ((((mouseypos + yoffs - spr0y) & ~1) * mstepy) >> 16);
+           lastspr0x = spr0x; lastspr0y = spr0y;
+           lastdiffx = diffx; lastdiffy = diffy;
+           mouse_x[0] += diffx; mouse_y[0] += diffy;
+       }
+       break;
+       
+    default:
+       abort ();
+    }
+}
+
+int getbuttonstate (int joy, int button)
+{
+    return joybutton[joy] & (1 << button);
+}
+
+static void mouseupdate (int pct)
+{
+    int v, i;
+
+    for (i = 0; i < 2; i++) {
+
+       v = mouse_delta[i][0] * pct / 100;
+        mouse_x[i] += v;
+        if (!mouse_deltanoreset[i][0])
+           mouse_delta[i][0] -= v;
+
+       v = mouse_delta[i][1] * pct / 100;
+       mouse_y[i] += v;
+        if (!mouse_deltanoreset[i][1])
+           mouse_delta[i][1] -= v;
+
+       v = mouse_delta[i][2] * pct / 100;
+       if (v > 0)
+           record_key (0x7a << 1);
+       else if (v < 0)
+           record_key (0x7b << 1);
+        if (!mouse_deltanoreset[i][2])
+           mouse_delta[i][2] = 0;
+
+       if (mouse_frame_x[i] - mouse_x[i] > 127)
+           mouse_x[i] = mouse_frame_x[i] - 127;
+       if (mouse_frame_x[i] - mouse_x[i] < -127)
+           mouse_x[i] = mouse_frame_x[i] + 127;
+
+       if (mouse_frame_y[i] - mouse_y[i] > 127)
+           mouse_y[i] = mouse_frame_y[i] - 127;
+       if (mouse_frame_y[i] - mouse_y[i] < -127)
+           mouse_y[i] = mouse_frame_y[i] + 127;
+
+       if (pct == 100) {
+           if (!mouse_deltanoreset[i][0])
+               mouse_delta[i][0] = 0;
+           if (!mouse_deltanoreset[i][1])
+               mouse_delta[i][1] = 0;
+           if (!mouse_deltanoreset[i][2])
+               mouse_delta[i][2] = 0;
+           mouse_frame_x[i] = mouse_x[i];
+           mouse_frame_y[i] = mouse_y[i];
+        }
+    
+    }
+}
+
+static int input_read, input_vpos;
+extern int vpos;
+static void readinput (void)
+{
+    if (!input_read && (vpos & ~31) != (input_vpos & ~31)) {
+       idev[IDTYPE_JOYSTICK].read ();
+       idev[IDTYPE_MOUSE].read ();
+       mouseupdate ((vpos - input_vpos) * 100 / maxvpos);
+       input_vpos = vpos;
+    }
+    if (input_read) {
+       input_vpos = vpos;
+        input_read = 0;
+    }
+}
+
+int getjoystate (int joy)
+{
+    int left = 0, right = 0, top = 0, bot = 0;
+    uae_u16 v = 0;
+
+    readinput ();
+    if (joydir[joy] & DIR_LEFT)
+       left = 1;
+    if (joydir[joy] & DIR_RIGHT)
+       right = 1;
+    if (joydir[joy] & DIR_UP)
+       top = 1;
+    if (joydir[joy] & DIR_DOWN)
+       bot = 1;
+    if (mouse_port[joy]) {
+        if (joy == 0)
+           do_mouse_hack ();
+    }
+    v = (uae_u8)mouse_x[joy] | (mouse_y[joy] << 8);
+    if (left || right || top || bot || !mouse_port[joy]) {
+       if (left)
+           top = !top;
+       if (right)
+           bot = !bot;
+       v &= ~0x0303;
+       v |= bot | (right << 1) | (top << 8) | (left << 9);
+    }
+//    write_log ("%d:%d:%04.4X %p\n",vpos,joy,v,m68k_getpc());
+#ifdef DONGLE_DEBUG
+    if (notinrom ())
+       write_log ("JOY%dDAT %04.4X %s\n", joy, v, debuginfo (0));
+#endif
+    return v;
+}
+
+uae_u16 JOY0DAT (void)
+{
+    return getjoystate (0);
+}
+uae_u16 JOY1DAT (void)
+{
+    return getjoystate (1);
+}
+
+void JOYTEST (uae_u16 v)
+{
+    mouse_x[0] &= 3;
+    mouse_y[0] &= 3;
+    mouse_x[1] &= 3;
+    mouse_y[1] &= 3;
+    mouse_x[0] |= v & 0xFC;
+    mouse_x[1] |= v & 0xFC;
+    mouse_y[0] |= (v >> 8) & 0xFC;
+    mouse_y[1] |= (v >> 8) & 0xFC;
+    mouse_frame_x[0] = mouse_x[0];
+    mouse_frame_y[0] = mouse_y[0];
+    mouse_frame_x[1] = mouse_x[1];
+    mouse_frame_y[1] = mouse_y[1];
+//    write_log ("%d:%04.4X %p\n",vpos,v,m68k_getpc());
+}
+
+static uae_u8 parconvert (uae_u8 v, int jd, int shift)
+{
+    if (jd & DIR_UP)
+       v &= ~(1 << shift);
+    if (jd & DIR_DOWN)
+       v &= ~(2 << shift);
+    if (jd & DIR_LEFT)
+       v &= ~(4 << shift);
+    if (jd & DIR_RIGHT)
+       v &= ~(8 << shift);
+    return v;
+}
+
+/* io-pins floating: dir=1 -> return data, dir=0 -> always return 1 */
+uae_u8 handle_parport_joystick (int port, uae_u8 pra, uae_u8 dra)
+{
+    uae_u8 v;
+    switch (port)
+    {
+       case 0:
+       v = (pra & dra) | (dra ^ 0xff);
+       if (parport_joystick_enabled) {
+           v = parconvert (v, joydir[2], 0);
+           v = parconvert (v, joydir[3], 4);
+       }
+       return v;
+       case 1:
+       v = ((pra & dra) | (dra ^ 0xff)) & 0x7;
+       if (parport_joystick_enabled) {
+           if (getbuttonstate (2, 0)) v &= ~1;
+           if (getbuttonstate (3, 0)) v &= ~4;
+       }
+       return v;
+       default:
+       abort ();
+    }
+}
+
+uae_u8 handle_joystick_buttons (uae_u8 dra)
+{
+    uae_u8 but = 0;
+    if (!getbuttonstate (0, JOYBUTTON_1) && !getbuttonstate (0, JOYBUTTON_CD32_RED))
+        but |= 0x40;
+    if (!getbuttonstate (1, JOYBUTTON_1) && !getbuttonstate (1, JOYBUTTON_CD32_RED))
+        but |= 0x80;
+    //write_log("%02.2X %02.2X %08.8X\n", but, dra, m68k_getpc());
+    return but;
+}
+
+/* joystick 1 button 1 is used as a output for incrementing shift register */
+void handle_cd32_joystick_cia (uae_u8 pra, uae_u8 dra)
+{
+    static int oldstate[2];
+    if ((dra & 0x80) && (pra & 0x80) != oldstate[1]) {
+       if (!(pra & 0x80))
+           cd32_shifter[1]--;
+       if (cd32_shifter[1] < 0)
+           cd32_shifter[1] = 8;
+       oldstate[1] = pra & 0x80;
+    }
+    if ((dra & 0x40) && (pra & 0x40) != oldstate[0]) {
+       if (!(pra & 0x40))
+           cd32_shifter[0]--;
+       if (cd32_shifter[0] < 0)
+           cd32_shifter[0] = 8;
+       oldstate[0] = pra & 0x40;
+    }
+}
+
+/* joystick port 1 button 3 is used as a output for clearing shift register */
+static void handle_cd32_joystick_potgo (uae_u16 potgo)
+{
+
+    if (potgo & 0x2000) {
+        if (!(potgo & 0x1000))
+           cd32_shifter[1] = 8;
+    }
+    if (potgo & 0x0200) {
+        if (!(potgo & 0x0100))
+           cd32_shifter[0] = 8;
+    }
+#if 0
+    int v;
+    static int oldstate[2];
+    if (potgo & 0x2000) {
+       v = potgo & 0x1000;
+       if (v != oldstate[1]) {
+           if (v == 0x0000)
+               cd32_shifter[1] = 8;
+           oldstate[1] = v;
+       }
+    }
+    if (potgo & 0x0200) {
+       v = potgo & 0x0100;
+       if (v != oldstate[0]) {
+           if (v == 0x0000)
+               cd32_shifter[0] = 8;
+           oldstate[0] = v;
+       }
+    }
+#endif
+}
+
+/* joystick port 1 button 2 is input for button state */
+static uae_u16 handle_joystick_potgor (uae_u16 potgor)
+{
+    int i;
+
+    for (i = 0; i < 2; i++) {
+       uae_u16 mask8 = 0x0800 << (i * 4);
+       uae_u16 mask4 = 0x0400 << (i * 4);
+       uae_u16 mask2 = 0x0200 << (i * 4);
+       uae_u16 mask1 = 0x0100 << (i * 4);
+
+       if (mouse_port[i]) {
+           /* mouse has pull-up resistors in button lines */
+           if (!(potgor & mask2))
+               potgor |= mask1;
+           if (!(potgor & mask8))
+               potgor |= mask4;
+       }
+        if (potgo_hsync < 0) {
+           /* first 10 or so lines after potgo has started
+            * forces input-lines to zero
+            */
+           if (!(potgor & mask2))
+               potgor &= ~mask1;
+           if (!(potgor & mask8))
+               potgor &= ~mask4;
+       }
+
+       if (cd32_pad_enabled[i]) {
+           if (!(potgor & mask8))
+               potgor |= mask4;
+           if (!(potgor & mask1) || !(potgor & mask8)) {
+               if (cd32_shifter[i] <= 0)
+                   potgor &= ~mask4;
+               if (cd32_shifter[i] >= 2 && (joybutton[i] & ((1 << JOYBUTTON_CD32_PLAY) << (cd32_shifter[i] - 2))))
+                   potgor &= ~mask4;
+           }
+       } else {
+           if (getbuttonstate (i, JOYBUTTON_3))
+               potgor &= ~mask1;
+       }
+       if (getbuttonstate (i, JOYBUTTON_2) || getbuttonstate (i, JOYBUTTON_CD32_BLUE))
+           potgor &= ~mask4;
+    }
+    return potgor;
+}
+
+uae_u16 potgo_value;
+static uae_u16 potdats[2];
+static int inputdelay;
+
+void inputdevice_hsync (void)
+{
+    int joy;
+
+    for (joy = 0; joy < 2; joy++) {
+       if (potgo_hsync >= 0) {
+           int active;
+
+           active = 0;
+           if ((potgo_value >> 9) & 1) /* output? */
+               active = ((potgo_value >> 8) & 1) ? 0 : 1;
+           if (potgo_hsync < joydirpot[joy][0])
+               active = 1;
+           if (getbuttonstate (joy, JOYBUTTON_3))
+               active = 1;
+           if (active)
+               potdats[joy] = ((potdats[joy] + 1) & 0xFF) | (potdats[joy] & 0xFF00);
+
+           active = 0;
+           if ((potgo_value >> 11) & 1) /* output? */
+               active = ((potgo_value >> 10) & 1) ? 0 : 1;
+           if (potgo_hsync < joydirpot[joy][1])
+               active = 1;
+           if (getbuttonstate (joy, JOYBUTTON_2))
+               active = 1;
+           if (active)
+               potdats[joy] += 0x100;
+       }
+    }
+    potgo_hsync++;
+    if (potgo_hsync > 255)
+       potgo_hsync = 255;
+
+
+#ifdef CATWEASEL
+    catweasel_hsync ();
+#endif
+    if (inputdelay > 0) {
+       inputdelay--;
+       if (inputdelay == 0) {
+           idev[IDTYPE_JOYSTICK].read ();
+           idev[IDTYPE_KEYBOARD].read ();
+       }
+    }
+}
+
+uae_u16 POT0DAT (void)
+{
+    return potdats[0];
+}
+uae_u16 POT1DAT (void)
+{
+    return potdats[1];
+}
+
+/* direction=input, data pin floating, last connected logic level or previous status
+                    written when direction was ouput
+ *                  otherwise it is currently connected logic level.
+ * direction=output, data pin is current value, forced to zero if joystick button is pressed
+ * it takes some tens of microseconds before data pin changes state
+ */
+
+void POTGO (uae_u16 v)
+{
+    int i;
+
+    //write_log ("W:%d: %04.4X %p\n", vpos, v, m68k_getpc());
+#ifdef DONGLE_DEBUG
+    if (notinrom ())
+       write_log ("POTGO %04.4X %s\n", v, debuginfo(0));
+#endif
+    potgo_value = potgo_value & 0x5500; /* keep state of data bits */
+    potgo_value |= v & 0xaa00; /* get new direction bits */
+    for (i = 0; i < 8; i += 2) {
+       uae_u16 dir = 0x0200 << i;
+       if (v & dir) {
+           uae_u16 data = 0x0100 << i;
+           potgo_value &= ~data;
+           potgo_value |= v & data;
+       }
+    }
+    if (v & 1) {
+       potdats[0] = potdats[1] = 0;
+       potgo_hsync = -15;
+    }
+    handle_cd32_joystick_potgo (v);
+}
+
+uae_u16 POTGOR (void)
+{
+    uae_u16 v = handle_joystick_potgor (potgo_value) & 0x5500;
+#ifdef DONGLE_DEBUG
+    if (notinrom ())
+       write_log ("POTGOR %04.4X %s\n", v, debuginfo(0));
+#endif
+    //write_log("R:%d:%04.4X %d %p\n", vpos, v, cd32_shifter[1], m68k_getpc());
+    return v;
+}
+
+static int check_input_queue (int event)
+{
+    struct input_queue_struct *iq;
+    int i;
+    for (i = 0; i < INPUT_QUEUE_SIZE; i++) {
+        iq = &input_queue[i];
+        if (iq->event == event) return i;
+    }
+    return -1;
+}
+
+static void queue_input_event (int event, int state, int max, int framecnt, int autofire)
+{
+    struct input_queue_struct *iq;
+    int i = check_input_queue (event);
+
+    if (state < 0 && i >= 0) {
+        iq = &input_queue[i];
+       iq->nextframecnt = -1;
+       iq->framecnt = -1;
+       iq->event = 0;
+       if (iq->state == 0)
+           handle_input_event (event, 0, 1, 0);
+    } else if (i < 0) {
+       for (i = 0; i < INPUT_QUEUE_SIZE; i++) {
+           iq = &input_queue[i];
+           if (iq->framecnt < 0) break;
+       }
+       if (i == INPUT_QUEUE_SIZE) {
+           write_log ("input queue overflow\n");
+           return;
+       }
+       iq->event = event;
+       iq->state = iq->storedstate = state;
+       iq->max = max;
+       iq->framecnt = framecnt;
+       iq->nextframecnt = autofire > 0 ? framecnt : -1;
+    }
+}
+
+static uae_u8 keybuf[256];
+
+void inputdevice_do_keyboard (int code, int state)
+{
+    if (code < 0x80) {
+       uae_u8 key = code | (state ? 0x00 : 0x80);
+        keybuf[key & 0x7f] = (key & 0x80) ? 0 : 1;
+       if (((keybuf[AK_CTRL] || keybuf[AK_RCTRL]) && keybuf[AK_LAMI] && keybuf[AK_RAMI]) || key == AK_RESETWARNING) {
+           int r = keybuf[AK_LALT] | keybuf[AK_RALT];
+           memset (keybuf, 0, sizeof (keybuf));
+           uae_reset (r);
+       }
+       record_key ((uae_u8)((key << 1) | (key >> 7)));
+       //write_log("Amiga key %02.2X %d\n", key & 0x7f, key >> 7);
+       return;
+    }
+    if (state == 0)
+       return;
+    switch (code)
+    {
+       case AKS_ENTERGUI:
+       gui_display (-1);
+       break;
+       case AKS_SCREENSHOT:
+       screenshot (1);
+       break;
+#ifdef ACTION_REPLAY
+       case AKS_FREEZEBUTTON:
+       action_replay_freeze ();
+       break;
+#endif
+       case AKS_FLOPPY0:
+       gui_display (0);
+       break;
+       case AKS_FLOPPY1:
+       gui_display (1);
+       break;
+       case AKS_FLOPPY2:
+       gui_display (2);
+       break;
+       case AKS_FLOPPY3:
+       gui_display (3);
+       break;
+       case AKS_EFLOPPY0:
+       disk_eject (0);
+       break;
+       case AKS_EFLOPPY1:
+       disk_eject (1);
+       break;
+       case AKS_EFLOPPY2:
+       disk_eject (2);
+       break;
+       case AKS_EFLOPPY3:
+       disk_eject (3);
+       break;
+       case AKS_IRQ7:
+       Interrupt (7);
+       break;
+       case AKS_PAUSE:
+       pausemode (-1);
+       break;
+       case AKS_WARP:
+       warpmode (-1);
+       break;
+       case AKS_INHIBITSCREEN:
+       toggle_inhibit_frame (IHF_SCROLLLOCK);
+       break;
+       case AKS_STATEREWIND:
+       savestate_dorewind(1);
+       break;
+       case AKS_VOLDOWN:
+       sound_volume (-1);
+       break;
+       case AKS_VOLUP:
+       sound_volume (1);
+       break;
+       case AKS_VOLMUTE:
+       sound_volume (0);
+       break;
+       case AKS_QUIT:
+       uae_quit ();
+       break;
+       case AKS_STATESAVE:
+       savestate_quick (0, 1);
+       break;
+       case AKS_STATERESTORE:
+       savestate_quick (0, 0);
+       break;
+    }
+}
+
+void handle_input_event (int nr, int state, int max, int autofire)
+{
+    struct inputevent *ie;
+    int joy;
+    
+    if (nr <= 0) return;
+    ie = &events[nr];
+    //write_log("'%s' %d %d\n", ie->name, state, max);
+    if (autofire) {
+       if (state)
+           queue_input_event (nr, state, max, currprefs.input_autofire_framecnt, 1);
+           else
+           queue_input_event (nr, -1, 0, 0, 1);
+    }
+    switch (ie->unit)
+    {
+       case 1: /* ->JOY1 */
+       case 2: /* ->JOY2 */
+       case 3: /* ->Parallel port joystick adapter port #1 */
+       case 4: /* ->Parallel port joystick adapter port #2 */
+           joy = ie->unit - 1;
+           if (ie->type & 4) {
+               if (state)
+                   joybutton[joy] |= 1 << ie->data;
+               else
+                   joybutton[joy] &= ~(1 << ie->data);
+           } else if (ie->type & 8) {
+               /* real mouse / analog stick mouse emulation */
+               int delta;
+               int deadzone = currprefs.input_joymouse_deadzone * max / 100;
+               if (max) {
+                   if (state < deadzone && state > -deadzone) {
+                       state = 0;
+                   } else if (state < 0) {
+                       state += deadzone;
+                   } else {
+                       state -= deadzone;
+                   }
+                   max -= deadzone;
+                   delta = state * currprefs.input_joymouse_multiplier / max;
+               } else {
+                   delta = state;
+               }
+               mouse_delta[joy][ie->data] += delta;
+           } else if (ie->type & 32) {
+               int speed = currprefs.input_joymouse_speed;
+
+               /* button mouse emulation */
+               if (state && (ie->data & DIR_LEFT)) {
+                   mouse_delta[joy][0] = -speed;
+                   mouse_deltanoreset[joy][0] = 1;
+               } else if (state && (ie->data & DIR_RIGHT)) {
+                   mouse_delta[joy][0] = speed;
+                   mouse_deltanoreset[joy][0] = 1;
+               } else
+                   mouse_deltanoreset[joy][0] = 0;
+
+               if (state && (ie->data & DIR_UP)) {
+                   mouse_delta[joy][1] = -speed;
+                   mouse_deltanoreset[joy][1] = 1;
+               } else if (state && (ie->data & DIR_DOWN)) {
+                   mouse_delta[joy][1] = speed;
+                   mouse_deltanoreset[joy][1] = 1;
+               } else
+                   mouse_deltanoreset[joy][1] = 0;
+
+           } else if (ie->type & 64) { /* analog (paddle) */
+               int deadzone = currprefs.input_joymouse_deadzone * max / 100;
+               if (max) {
+                   if (state < deadzone && state > -deadzone) {
+                       state = 0;
+                   } else if (state < 0) {
+                       state += deadzone;
+                   } else {
+                       state -= deadzone;
+                   }
+                   state = state * max / (max - deadzone);
+               }
+               state = state / 256 + 128;
+               joydirpot[joy][ie->data] = state;
+           } else {
+               int left = oleft[joy], right = oright[joy], top = otop[joy], bot = obot[joy];
+               if (ie->type & 16) {
+                   /* button to axis mapping */
+                   if (ie->data & DIR_LEFT) left = oleft[joy] = state ? 1 : 0;
+                   if (ie->data & DIR_RIGHT) right = oright[joy] = state ? 1 : 0;
+                   if (ie->data & DIR_UP) top = otop[joy] = state ? 1 : 0;
+                   if (ie->data & DIR_DOWN) bot = obot[joy] = state ? 1 : 0;
+               } else {
+                   /* "normal" joystick axis */
+                   int deadzone = currprefs.input_joystick_deadzone * max / 100;
+                   int neg, pos;
+                   if (state < deadzone && state > -deadzone)
+                       state = 0;
+                   neg = state < 0 ? 1 : 0;
+                   pos = state > 0 ? 1 : 0;
+                   if (ie->data & DIR_LEFT) left = oleft[joy] = neg;
+                   if (ie->data & DIR_RIGHT) right = oright[joy] = pos;
+                   if (ie->data & DIR_UP) top = otop[joy] = neg;
+                   if (ie->data & DIR_DOWN) bot = obot[joy] = pos;
+               }
+               joydir[joy] = 0;
+               if (left) joydir[joy] |= DIR_LEFT;
+               if (right) joydir[joy] |= DIR_RIGHT;
+               if (top) joydir[joy] |= DIR_UP;
+               if (bot) joydir[joy] |= DIR_DOWN;
+           }
+       break;
+       case 0: /* ->KEY */
+           inputdevice_do_keyboard (ie->data, state);
+       break;
+    }
+}
+
+void inputdevice_vsync (void)
+{
+    struct input_queue_struct *iq;
+    int i;
+
+    for (i = 0; i < INPUT_QUEUE_SIZE; i++) {
+       iq = &input_queue[i];
+       if (iq->framecnt > 0) {
+           iq->framecnt--;
+           if (iq->framecnt == 0) {
+               if (iq->state) iq->state = 0; else iq->state = iq->storedstate;
+               handle_input_event (iq->event, iq->state, iq->max, 0);
+               iq->framecnt = iq->nextframecnt;
+           }
+       }
+    }
+    mouseupdate (100);
+    inputdelay = rand () % (maxvpos - 1);
+    idev[IDTYPE_MOUSE].read ();
+    input_read = 1;
+    input_vpos = 0;
+}
+
+static void setbuttonstateall (struct uae_input_device *id, struct uae_input_device2 *id2, int button, int state)
+{
+    int event, autofire, i;
+    uae_u32 mask = 1 << button;
+    uae_u32 omask = id2->buttonmask & mask;
+    uae_u32 nmask = (state ? 1 : 0) << button;
+    
+    if (button >= ID_BUTTON_TOTAL)
+       return;
+    for (i = 0; i < MAX_INPUT_SUB_EVENT; i++) {
+       event = id->eventid[ID_BUTTON_OFFSET + button][sublevdir[state <= 0 ? 0 : 1][i]];
+       if (event <= 0)
+           continue;
+       autofire = (id->flags[ID_BUTTON_OFFSET + button][sublevdir[state <= 0 ? 0 : 1][i]] & ID_FLAG_AUTOFIRE) ? 1 : 0;
+       if (state < 0) {
+           handle_input_event (event, 1, 1, 0);
+           queue_input_event (event, 0, 1, 1, 0); /* send release event next frame */
+       } else {
+           if ((omask ^ nmask) & mask)
+               handle_input_event (event, state, 1, autofire);
+       }
+    }
+    if ((omask ^ nmask) & mask) {
+       if (state)
+           id2->buttonmask |= mask;
+       else
+           id2->buttonmask &= ~mask;
+    }    
+}
+
+
+/* - detect required number of joysticks and mice from configuration data
+ * - detect if CD32 pad emulation is needed
+ * - detect device type in ports (mouse or joystick)
+ */
+
+static int iscd32 (int ei)
+{
+    if (ei >= INPUTEVENT_JOY1_CD32_FIRST && ei <= INPUTEVENT_JOY1_CD32_LAST) {
+       cd32_pad_enabled[0] = 1;
+       return 1;
+    }
+    if (ei >= INPUTEVENT_JOY2_CD32_FIRST && ei <= INPUTEVENT_JOY2_CD32_LAST) {
+        cd32_pad_enabled[1] = 1;
+        return 2;
+    }
+    return 0;
+}
+
+static int isparport (int ei)
+{
+    if (ei > INPUTEVENT_PAR_JOY1_START && ei < INPUTEVENT_PAR_JOY_END) {
+        parport_joystick_enabled = 1;
+       return 1;
+    }
+    return 0;
+}
+
+static int ismouse (int ei)
+{
+    if (ei >= INPUTEVENT_MOUSE1_FIRST && ei <= INPUTEVENT_MOUSE1_LAST) {
+       mouse_port[0] = 1;
+       return 1;
+    }
+    if (ei >= INPUTEVENT_MOUSE2_FIRST && ei <= INPUTEVENT_MOUSE2_LAST) {
+       mouse_port[1] = 1;
+       return 2;
+    }
+    return 0;
+}
+
+#ifdef CD32
+extern int cd32_enabled;
+#endif
+
+static void scanevents(struct uae_prefs *p)
+{
+    int i, j, k, ei;
+    struct inputevent *e;
+    int n_joy = idev[IDTYPE_JOYSTICK].get_num();
+    int n_mouse = idev[IDTYPE_MOUSE].get_num();
+
+    cd32_pad_enabled[0] = cd32_pad_enabled[1] = 0;
+    parport_joystick_enabled = 0;
+    mouse_port[0] = mouse_port[1] = 0;
+    for (i = 0; i < MAX_INPUT_DEVICE_EVENTS; i++)
+       joydir[i] = 0;
+
+    for (i = 0; i < MAX_INPUT_DEVICES; i++) {
+       use_joysticks[i] = 0;
+       use_mice[i] = 0;
+        for (k = 0; k < MAX_INPUT_SUB_EVENT; k++) {
+           for (j = 0; j < ID_BUTTON_TOTAL; j++) {
+
+               if (joysticks[i].enabled && i < n_joy) {
+                   ei = joysticks[i].eventid[ID_BUTTON_OFFSET + j][k];
+                   e = &events[ei];
+                   iscd32 (ei);
+                   isparport (ei);
+                   ismouse (ei);
+                   if (joysticks[i].eventid[ID_BUTTON_OFFSET + j][k] > 0)
+                       use_joysticks[i] = 1;
+               }
+               if (mice[i].enabled && i < n_mouse) {
+                   ei = mice[i].eventid[ID_BUTTON_OFFSET + j][k];
+                   e = &events[ei];
+                   iscd32 (ei);
+                   isparport (ei);
+                   ismouse (ei);
+                   if (mice[i].eventid[ID_BUTTON_OFFSET + j][k] > 0)
+                       use_mice[i] = 1;
+               }
+
+           }
+
+           for (j = 0; j < ID_AXIS_TOTAL; j++) {
+
+               if (joysticks[i].enabled && i < n_joy) {
+                   ei = joysticks[i].eventid[ID_AXIS_OFFSET + j][k];
+                   iscd32 (ei);
+                   isparport (ei);
+                   ismouse (ei);
+                   if (ei > 0)
+                       use_joysticks[i] = 1;
+               }
+               if (mice[i].enabled && i < n_mouse) {
+                   ei = mice[i].eventid[ID_AXIS_OFFSET + j][k];
+                   iscd32 (ei);
+                   isparport (ei);
+                   ismouse (ei);
+                   if (ei > 0)
+                       use_mice[i] = 1;
+               }
+           }
+       }
+    }
+    for (i = 0; i < MAX_INPUT_DEVICES; i++) {
+       use_keyboards[i] = 0;
+       if (keyboards[i].enabled && i < idev[IDTYPE_KEYBOARD].get_num()) {
+           j = 0;
+           while (keyboards[i].extra[j][0] >= 0) {
+               use_keyboards[i] = 1;
+               for (k = 0; k < MAX_INPUT_SUB_EVENT; k++) {
+                   ei = keyboards[i].eventid[j][k];
+                   iscd32 (ei);
+                   isparport (ei);
+                   ismouse (ei);
+               }
+               j++;
+           }
+       }
+    }
+}
+
+static void compatibility_mode (struct uae_prefs *prefs)
+{
+    int joy, i;
+
+    for (i = 0; i < MAX_INPUT_DEVICES; i++) {
+       memset (&mice[i], 0, sizeof (*mice));
+       memset (&joysticks[i], 0, sizeof (*joysticks));
+    }
+
+    /* mouse compatibility code */
+    if (JSEM_ISMOUSE (0, prefs)) {
+       mice[0].eventid[ID_AXIS_OFFSET + 0][0] = INPUTEVENT_MOUSE1_HORIZ;
+       mice[0].eventid[ID_AXIS_OFFSET + 1][0] = INPUTEVENT_MOUSE1_VERT;
+       mice[0].eventid[ID_AXIS_OFFSET + 2][0] = INPUTEVENT_MOUSE1_WHEEL;
+        mice[0].eventid[ID_BUTTON_OFFSET + 0][0] = INPUTEVENT_JOY1_FIRE_BUTTON;
+       mice[0].eventid[ID_BUTTON_OFFSET + 1][0] = INPUTEVENT_JOY1_2ND_BUTTON;
+       mice[0].eventid[ID_BUTTON_OFFSET + 2][0] = INPUTEVENT_JOY1_3RD_BUTTON;
+       mice[0].enabled = 1;
+    } else if (JSEM_ISMOUSE (1, prefs)) {
+       mice[0].eventid[ID_AXIS_OFFSET + 0][0] = INPUTEVENT_MOUSE2_HORIZ;
+       mice[0].eventid[ID_AXIS_OFFSET + 1][0] = INPUTEVENT_MOUSE2_VERT;
+        mice[0].eventid[ID_BUTTON_OFFSET + 0][0] = INPUTEVENT_JOY2_FIRE_BUTTON;
+       mice[0].eventid[ID_BUTTON_OFFSET + 1][0] = INPUTEVENT_JOY2_2ND_BUTTON;
+       mice[0].eventid[ID_BUTTON_OFFSET + 2][0] = INPUTEVENT_JOY2_3RD_BUTTON;
+       mice[0].enabled = 1;
+    }
+
+    /* joystick 2 compatibility code */
+    joy = -1;
+    if (JSEM_ISJOY0 (1, prefs))
+       joy = 0;
+    else if (JSEM_ISJOY1 (1, prefs))
+       joy = 1;
+    if (joy >= 0) {
+       joysticks[joy].eventid[ID_AXIS_OFFSET + 0][0] = INPUTEVENT_JOY2_HORIZ;
+        joysticks[joy].eventid[ID_AXIS_OFFSET + 1][0] = INPUTEVENT_JOY2_VERT;
+#ifdef CD32
+       if (cd32_enabled) {
+           joysticks[joy].eventid[ID_BUTTON_OFFSET + 0][0] = INPUTEVENT_JOY2_FIRE_BUTTON;
+           joysticks[joy].eventid[ID_BUTTON_OFFSET + 1][0] = INPUTEVENT_JOY2_CD32_RED;
+           joysticks[joy].eventid[ID_BUTTON_OFFSET + 2][0] = INPUTEVENT_JOY2_CD32_BLUE;
+           joysticks[joy].eventid[ID_BUTTON_OFFSET + 3][0] = INPUTEVENT_JOY2_CD32_YELLOW;
+           joysticks[joy].eventid[ID_BUTTON_OFFSET + 4][0] = INPUTEVENT_JOY2_CD32_GREEN;
+           joysticks[joy].eventid[ID_BUTTON_OFFSET + 5][0] = INPUTEVENT_JOY2_CD32_FFW;
+           joysticks[joy].eventid[ID_BUTTON_OFFSET + 6][0] = INPUTEVENT_JOY2_CD32_RWD;
+           joysticks[joy].eventid[ID_BUTTON_OFFSET + 7][0] = INPUTEVENT_JOY2_CD32_PLAY;
+       } else {
+#endif
+           joysticks[joy].eventid[ID_BUTTON_OFFSET + 0][0] = INPUTEVENT_JOY2_FIRE_BUTTON;
+           joysticks[joy].eventid[ID_BUTTON_OFFSET + 1][0] = INPUTEVENT_JOY2_2ND_BUTTON;
+           joysticks[joy].eventid[ID_BUTTON_OFFSET + 2][0] = INPUTEVENT_JOY2_3RD_BUTTON;
+#ifdef CD32
+       }
+#endif
+       joysticks[joy].enabled = 1;
+    }
+    if (JSEM_ISNUMPAD (1, prefs) || JSEM_ISCURSOR (1, prefs) || JSEM_ISSOMEWHEREELSE (1, prefs)) {
+        joysticks[3].eventid[ID_AXIS_OFFSET +  0][0] = INPUTEVENT_JOY2_HORIZ;
+       joysticks[3].eventid[ID_AXIS_OFFSET +  1][0] = INPUTEVENT_JOY2_VERT;
+       joysticks[3].eventid[ID_BUTTON_OFFSET + 0][0] = INPUTEVENT_JOY2_FIRE_BUTTON;
+       joysticks[3].eventid[ID_BUTTON_OFFSET + 1][0] = INPUTEVENT_JOY2_2ND_BUTTON;
+       joysticks[3].eventid[ID_BUTTON_OFFSET + 2][0] = INPUTEVENT_JOY2_3RD_BUTTON;
+       joysticks[3].enabled = 1;
+    }
+    
+
+    /* joystick 1 compatibility code */
+    joy = -1;
+    if (JSEM_ISJOY0 (0, prefs))
+       joy = 0;
+    else if (JSEM_ISJOY1 (0, prefs))
+       joy = 1;
+    if (joy >= 0) {
+        joysticks[joy].eventid[ID_AXIS_OFFSET + 0][0] = INPUTEVENT_JOY1_HORIZ;
+       joysticks[joy].eventid[ID_AXIS_OFFSET + 1][0] = INPUTEVENT_JOY1_VERT;
+       joysticks[joy].eventid[ID_BUTTON_OFFSET + 0][0] = INPUTEVENT_JOY1_FIRE_BUTTON;
+       joysticks[joy].eventid[ID_BUTTON_OFFSET + 1][0] = INPUTEVENT_JOY1_2ND_BUTTON;
+       joysticks[joy].eventid[ID_BUTTON_OFFSET + 2][0] = INPUTEVENT_JOY1_3RD_BUTTON;
+       joysticks[joy].enabled = 1;
+    }
+    if (JSEM_ISNUMPAD (0, prefs) || JSEM_ISCURSOR (0, prefs) || JSEM_ISSOMEWHEREELSE (0, prefs)) {
+        joysticks[2].eventid[ID_AXIS_OFFSET +  0][0] = INPUTEVENT_JOY1_HORIZ;
+       joysticks[2].eventid[ID_AXIS_OFFSET +  1][0] = INPUTEVENT_JOY1_VERT;
+       joysticks[2].eventid[ID_BUTTON_OFFSET + 0][0] = INPUTEVENT_JOY1_FIRE_BUTTON;
+       joysticks[2].eventid[ID_BUTTON_OFFSET + 1][0] = INPUTEVENT_JOY1_2ND_BUTTON;
+       joysticks[2].eventid[ID_BUTTON_OFFSET + 2][0] = INPUTEVENT_JOY1_3RD_BUTTON;
+       joysticks[2].enabled = 1;
+    }
+}
+
+void inputdevice_updateconfig (struct uae_prefs *prefs)
+{
+    int i;
+
+    if (currprefs.jport0 != changed_prefs.jport0
+       || currprefs.jport1 != changed_prefs.jport1) {
+       currprefs.jport0 = changed_prefs.jport0;
+       currprefs.jport1 = changed_prefs.jport1;
+    }
+    joybutton[0] = joybutton[1] = 0;
+    joydir[0] = joydir[1] = 0;
+    oldmx[0] = oldmx[1] = -1;
+    oldmy[0] = oldmy[1] = -1;
+    cd32_shifter[0] = cd32_shifter[1] = 8;
+    oleft[0] = oleft[1] = 0;
+    oright[0] = oright[1] = 0;
+    otop[0] = otop[1] = 0;
+    obot[0] = obot[1] = 0;
+    for (i = 0; i < 2; i++) {
+       mouse_deltanoreset[i][0] = 0;
+       mouse_delta[i][0] = 0;
+       mouse_deltanoreset[i][1] = 0;
+       mouse_delta[i][1] = 0;
+       mouse_deltanoreset[i][2] = 0;
+       mouse_delta[i][2] = 0;
+    }
+    memset (keybuf, 0, sizeof (keybuf));
+    for (i = 0; i < INPUT_QUEUE_SIZE; i++)
+       input_queue[i].framecnt = input_queue[i].nextframecnt = -1;
+
+    for (i = 0; i < MAX_INPUT_SUB_EVENT; i++) {
+       sublevdir[0][i] = i;
+       sublevdir[1][i] = MAX_INPUT_SUB_EVENT - i - 1;
+    }
+
+    joysticks = prefs->joystick_settings[prefs->input_selected_setting];
+    mice = prefs->mouse_settings[prefs->input_selected_setting];
+    keyboards = prefs->keyboard_settings[prefs->input_selected_setting];
+
+    memset (joysticks2, 0, sizeof (joysticks2));
+    memset (mice2, 0, sizeof (mice2));
+    if (prefs->input_selected_setting == 0)
+       compatibility_mode (prefs);
+
+    joystick_setting_changed ();
+
+    scanevents (prefs);
+
+#ifdef CD32
+    if (currprefs.input_selected_setting == 0 && cd32_enabled)
+       cd32_pad_enabled[1] = 1;
+#endif
+}
+
+static void set_kbr_default (struct uae_prefs *p, int index, int num)
+{
+    int i, j, k, l;
+    struct uae_input_device_kbr_default *trans = keyboard_default;
+    struct uae_input_device *kbr;
+    struct inputdevice_functions *id = &idev[IDTYPE_KEYBOARD];
+    uae_u32 scancode;
+
+    if (!trans)
+       return;
+    for (j = 0; j < MAX_INPUT_DEVICES; j++) {
+        kbr = &p->keyboard_settings[index][j];
+       for (i = 0; i < MAX_INPUT_DEVICE_EVENTS; i++) {
+           memset (kbr, 0, sizeof (struct uae_input_device));
+           kbr->extra[i][0] = -1;
+       }
+       if (j < id->get_num ()) {
+           if (j == 0)
+               kbr->enabled = 1;
+           for (i = 0; i < id->get_widget_num (num); i++) {
+               id->get_widget_type (num, i, 0, &scancode);
+               kbr->extra[i][0] = scancode;
+               l = 0;
+               while (trans[l].scancode >= 0) {
+                   if (kbr->extra[i][0] == trans[l].scancode) {
+                       for (k = 0; k < MAX_INPUT_SUB_EVENT; k++) {
+                           if (kbr->eventid[i][k] == 0) break;
+                       }
+                       if (k == MAX_INPUT_SUB_EVENT) {
+                           write_log ("corrupt default keyboard mappings\n");
+                           return;
+                       }
+                       kbr->eventid[i][k] = trans[l].event;
+                       break;
+                   }
+                   l++;
+               }
+           }
+       }
+    }
+}
+
+void inputdevice_default_prefs (struct uae_prefs *p)
+{
+    int i;
+
+    inputdevice_init ();
+    p->input_joymouse_multiplier = 20;
+    p->input_joymouse_deadzone = 33;
+    p->input_joystick_deadzone = 33;
+    p->input_joymouse_speed = 10;
+    p->input_mouse_speed = 100;
+    p->input_autofire_framecnt = 10;
+    for (i = 0; i <= MAX_INPUT_SETTINGS; i++) {
+        set_kbr_default (p, i, 0);
+       input_get_default_mouse (p->mouse_settings[i]);
+       input_get_default_joystick (p->joystick_settings[i]);
+    }
+}
+
+void inputdevice_setkeytranslation (struct uae_input_device_kbr_default *trans)
+{
+    keyboard_default = trans;
+}
+
+int inputdevice_translatekeycode (int keyboard, int scancode, int state)
+{
+    struct uae_input_device *na = &keyboards[keyboard];
+    int j, k;
+
+    if (!keyboards || scancode < 0)
+       return 0;
+    j = 0;
+    while (na->extra[j][0] >= 0) {
+        if (na->extra[j][0] == scancode) {
+           for (k = 0; k < MAX_INPUT_SUB_EVENT; k++) {/* send key release events in reverse order */
+               int autofire = (na->flags[j][sublevdir[state  == 0 ? 1 : 0][k]] & ID_FLAG_AUTOFIRE) ? 1 : 0;
+               int event = na->eventid[j][sublevdir[state == 0 ? 1 : 0][k]];
+               handle_input_event (event, state, 1, autofire);
+               //write_log ("'%s' %d ('%s') %d\n", na->name, event, events[event].name,  state);
+           }
+           return 1;
+       }
+       j++;
+    }
+    return 0;
+}
+
+static struct inputdevice_functions idev[3];
+
+void inputdevice_init (void)
+{
+    idev[IDTYPE_JOYSTICK] = inputdevicefunc_joystick;
+    idev[IDTYPE_JOYSTICK].init ();
+    idev[IDTYPE_MOUSE] = inputdevicefunc_mouse;
+    idev[IDTYPE_MOUSE].init ();
+    idev[IDTYPE_KEYBOARD] = inputdevicefunc_keyboard;
+    idev[IDTYPE_KEYBOARD].init ();
+}
+
+void inputdevice_close (void)
+{
+    idev[IDTYPE_JOYSTICK].close ();
+    idev[IDTYPE_MOUSE].close ();
+    idev[IDTYPE_KEYBOARD].close ();
+}
+
+static struct uae_input_device *get_uid (struct inputdevice_functions *id, int devnum)
+{
+    struct uae_input_device *uid = 0;
+    if (id == &idev[IDTYPE_JOYSTICK]) {
+       uid = &joysticks[devnum];
+    } else if (id == &idev[IDTYPE_MOUSE]) {
+       uid = &mice[devnum];
+    } else if (id == &idev[IDTYPE_KEYBOARD]) {
+       uid = &keyboards[devnum];
+    }
+    return uid;
+}
+
+static int get_event_data (struct inputdevice_functions *id, int devnum, int num, int *eventid, int *flags, int sub)
+{
+    struct uae_input_device *uid = get_uid (id, devnum);
+    int type = id->get_widget_type (devnum, num, 0, 0);
+    int i;
+    if (type == IDEV_WIDGET_BUTTON) {
+       i = num - id->get_widget_first (devnum, type);
+       *eventid = uid->eventid[ID_BUTTON_OFFSET + i][sub];
+       *flags = uid->flags[ID_BUTTON_OFFSET + i][sub];
+       return i;
+    } else if (type == IDEV_WIDGET_AXIS) {
+       i = num - id->get_widget_first (devnum, type);
+       *eventid = uid->eventid[ID_AXIS_OFFSET + i][sub];
+       *flags = uid->flags[ID_AXIS_OFFSET + i][sub];
+       return i;
+    } else if (type == IDEV_WIDGET_KEY) {
+       i = num - id->get_widget_first (devnum, type);
+       *eventid = uid->eventid[i][sub];
+       *flags = uid->flags[i][sub];
+       return i;
+    }
+    return -1;
+}
+
+static int put_event_data (struct inputdevice_functions *id, int devnum, int num, int eventid, int flags, int sub)
+{
+    struct uae_input_device *uid = get_uid (id, devnum);
+    int type = id->get_widget_type (devnum, num, 0, 0);
+    int i;
+    if (type == IDEV_WIDGET_BUTTON) {
+       i = num - id->get_widget_first (devnum, type);
+       uid->eventid[ID_BUTTON_OFFSET + i][sub] = eventid;
+       uid->flags[ID_BUTTON_OFFSET + i][sub] = flags;
+       return i;
+    } else if (type == IDEV_WIDGET_AXIS) {
+       i = num - id->get_widget_first (devnum, type);
+       uid->eventid[ID_AXIS_OFFSET + i][sub] = eventid;
+       uid->flags[ID_AXIS_OFFSET + i][sub] = flags;
+       return i;
+    } else if (type == IDEV_WIDGET_KEY) {
+       i = num - id->get_widget_first (devnum, type);
+       uid->eventid[i][sub] = eventid;
+       uid->flags[i][sub] = flags;
+       return i;
+    }
+    return -1;
+}
+
+static int is_event_used (struct inputdevice_functions *id, int devnum, int isnum, int isevent)
+{
+    struct uae_input_device *uid = get_uid (id, devnum);
+    int num, event, flag, sub;
+
+    for (num = 0; num < id->get_widget_num (devnum); num++) {
+       for (sub = 0; sub < MAX_INPUT_SUB_EVENT; sub++) {
+           if (get_event_data (id, devnum, num, &event, &flag, sub) >= 0) {
+               if (event == isevent && isnum != num)
+                   return 1;
+           }
+       }
+    }
+    return 0;
+}
+
+int inputdevice_get_device_index (int devnum)
+{
+    if (devnum < idev[IDTYPE_JOYSTICK].get_num())
+       return devnum;
+    else if (devnum < idev[IDTYPE_JOYSTICK].get_num() + idev[IDTYPE_MOUSE].get_num())
+       return devnum - idev[IDTYPE_JOYSTICK].get_num();
+    else
+       return devnum - idev[IDTYPE_JOYSTICK].get_num() - idev[IDTYPE_MOUSE].get_num();
+}
+
+static int gettype (int devnum)
+{
+    if (devnum < idev[IDTYPE_JOYSTICK].get_num())
+       return IDTYPE_JOYSTICK;
+    else if (devnum < idev[IDTYPE_JOYSTICK].get_num() + idev[IDTYPE_MOUSE].get_num())
+       return IDTYPE_MOUSE;
+    else if (devnum < idev[IDTYPE_JOYSTICK].get_num() + idev[IDTYPE_MOUSE].get_num() + idev[IDTYPE_KEYBOARD].get_num())
+       return IDTYPE_KEYBOARD;
+    else
+       return -1;
+}
+
+static struct inputdevice_functions *getidf (int devnum)
+{
+    return &idev[gettype (devnum)];
+}
+
+
+/* returns number of devices of type "type" */
+int inputdevice_get_device_total (int type)
+{
+    return idev[type].get_num ();
+}
+/* returns the name of device */
+char *inputdevice_get_device_name (int type, int devnum)
+{
+    return idev[type].get_name (devnum);
+}
+/* returns state (enabled/disabled) */
+int inputdevice_get_device_status (int devnum)
+{
+    struct inputdevice_functions *idf = getidf (devnum);
+    struct uae_input_device *uid = get_uid (idf, inputdevice_get_device_index (devnum));
+    return uid->enabled;
+}
+
+/* set state (enabled/disabled) */
+void inputdevice_set_device_status (int devnum, int enabled)
+{
+    struct inputdevice_functions *idf = getidf (devnum);
+    struct uae_input_device *uid = get_uid (idf, inputdevice_get_device_index (devnum));
+    uid->enabled = enabled;
+}
+
+/* returns number of axis/buttons and keys from selected device */
+int inputdevice_get_widget_num (int devnum)
+{
+    struct inputdevice_functions *idf = getidf (devnum);
+    return idf->get_widget_num (inputdevice_get_device_index (devnum));
+}
+
+static void get_ename (struct inputevent *ie, char *out)
+{
+    if (!out)
+       return;
+    if (ie->allow_mask == AM_K)
+        sprintf (out, "%s (0x%02.2X)", ie->name, ie->data);
+    else
+       strcpy (out, ie->name);
+}
+
+int inputdevice_iterate (int devnum, int num, char *name, int *af)
+{
+    struct inputdevice_functions *idf = getidf (devnum);
+    static int id_iterator;
+    struct inputevent *ie;
+    int mask, data, flags, type;
+    int devindex = inputdevice_get_device_index (devnum);
+
+    *af = 0;
+    *name = 0;
+    for (;;) {
+       ie = &events[++id_iterator];
+       if (!ie->confname) {
+           id_iterator = 0;
+           return 0;
+       }
+       mask = 0;
+       type = idf->get_widget_type (devindex, num, 0, 0);
+       if (type == IDEV_WIDGET_BUTTON) {
+           if (idf == &idev[IDTYPE_JOYSTICK]) {
+               mask |= AM_JOY_BUT;
+           } else {
+               mask |= AM_MOUSE_BUT;
+           }
+       } else if (type == IDEV_WIDGET_AXIS) {
+           if (idf == &idev[IDTYPE_JOYSTICK]) {
+               mask |= AM_JOY_AXIS;
+           } else {
+               mask |= AM_MOUSE_AXIS;
+           }
+       } else if (type == IDEV_WIDGET_KEY) {
+           mask |= AM_K;
+       }
+       if (ie->allow_mask & AM_INFO) {
+           struct inputevent *ie2 = ie + 1;
+           while (!(ie2->allow_mask & AM_INFO)) {
+               if (is_event_used (idf, devindex, ie2 - ie, -1)) {
+                   ie2++;
+                   continue;
+               }
+               if (ie2->allow_mask & mask) break;
+               ie2++;
+           }
+           if (!(ie2->allow_mask & AM_INFO))
+               mask |= AM_INFO;
+       }
+       if (!(ie->allow_mask & mask))
+           continue;
+       get_event_data (idf, devindex, num, &data, &flags, 0);
+        get_ename (ie, name);
+       *af = (flags & ID_FLAG_AUTOFIRE) ? 1 : 0;
+       return 1;
+    }
+}
+
+int inputdevice_get_mapped_name (int devnum, int num, int *pflags, char *name, int sub)
+{
+    struct inputdevice_functions *idf = getidf (devnum);
+    struct uae_input_device *uid = get_uid (idf, inputdevice_get_device_index (devnum));
+    int flags = 0, flag, data;
+    int devindex = inputdevice_get_device_index (devnum);
+
+    if (name)
+       strcpy (name, "<none>");
+    if (pflags)
+       *pflags = 0;
+    if (uid == 0 || num < 0)
+       return 0;
+    if (get_event_data (idf, devindex, num, &data, &flag, sub) < 0)
+       return 0;
+    if (flag & ID_FLAG_AUTOFIRE)
+       flags |= IDEV_MAPPED_AUTOFIRE_SET;
+    if (!data) return 0;
+    if (events[data].allow_mask & AM_AF)
+       flags |= IDEV_MAPPED_AUTOFIRE_POSSIBLE;
+    if (pflags)
+       *pflags = flags;
+    get_ename (&events[data], name);
+    return data;
+}
+
+int inputdevice_set_mapping (int devnum, int num, char *name, int af, int sub)
+{
+    struct inputdevice_functions *idf = getidf (devnum);
+    struct uae_input_device *uid = get_uid (idf, inputdevice_get_device_index (devnum));
+    int eid, data, flag, amask;
+    char ename[256];
+    int devindex = inputdevice_get_device_index (devnum);
+
+    if (uid == 0 || num < 0)
+       return 0;
+    if (name) {
+        eid = 1;
+       while (events[eid].name) {
+           get_ename (&events[eid], ename);
+           if (!strcmp(ename, name)) break;
+           eid++;
+       }
+       if (!events[eid].name)
+           return 0;
+       if (events[eid].allow_mask & AM_INFO)
+           return 0;
+    } else {
+       eid = 0;
+    }
+    if (get_event_data (idf, devindex, num, &data, &flag, sub) < 0)
+       return 0;
+    if (data >= 0) {
+       amask = events[eid].allow_mask;
+       flag &= ~ID_FLAG_AUTOFIRE;
+       if (amask & AM_AF)
+           flag |= af ? ID_FLAG_AUTOFIRE : 0;
+       put_event_data (idf, devindex, num, eid, flag, sub);
+       return 1;
+    }
+    return 0;
+}
+
+int inputdevice_get_widget_type (int devnum, int num, char *name)
+{
+    struct inputdevice_functions *idf = getidf (devnum);
+    return idf->get_widget_type (inputdevice_get_device_index (devnum), num, name, 0);
+}
+
+static int config_change;
+
+void inputdevice_config_change (void)
+{
+    config_change = 1;
+}
+
+int inputdevice_config_change_test (void)
+{
+    int v = config_change;
+    config_change = 0;
+    return v;
+}
+
+void inputdevice_copyconfig (struct uae_prefs *src, struct uae_prefs *dst)
+{
+    int i, j;
+
+    dst->input_selected_setting = src->input_selected_setting;
+    dst->input_joymouse_multiplier = src->input_joymouse_multiplier;
+    dst->input_joymouse_deadzone = src->input_joymouse_deadzone;
+    dst->input_joystick_deadzone = src->input_joystick_deadzone;
+    dst->input_joymouse_speed = src->input_joymouse_speed;
+    dst->input_mouse_speed = src->input_mouse_speed;
+    dst->input_autofire_framecnt = src->input_autofire_framecnt;
+    dst->jport0 = src->jport0;
+    dst->jport1 = src->jport1;
+
+    for (i = 0; i < MAX_INPUT_SETTINGS + 1; i++) {
+       for (j = 0; j < MAX_INPUT_DEVICES; j++) {
+           memcpy (&dst->joystick_settings[i][j], &src->joystick_settings[i][j], sizeof (struct uae_input_device));
+           memcpy (&dst->mouse_settings[i][j], &src->mouse_settings[i][j], sizeof (struct uae_input_device));
+           memcpy (&dst->keyboard_settings[i][j], &src->keyboard_settings[i][j], sizeof (struct uae_input_device));
+       }
+    }
+    
+    inputdevice_updateconfig (dst);
+}
+
+void inputdevice_swap_ports (struct uae_prefs *p, int devnum)
+{
+    struct inputdevice_functions *idf = getidf (devnum);
+    struct uae_input_device *uid = get_uid (idf, inputdevice_get_device_index (devnum));
+    int i, j, k, event, unit;
+    struct inputevent *ie, *ie2;
+
+    for (i = 0; i < MAX_INPUT_DEVICE_EVENTS; i++) {
+       for (j = 0; j < MAX_INPUT_SUB_EVENT; j++) {
+           event = uid->eventid[i][j];
+           if (event <= 0)
+               continue;
+           ie = &events[event];
+           if (ie->unit <= 0)
+               continue;
+           unit = ie->unit;
+           k = 1;
+           while (events[k].confname) {
+               ie2 = &events[k];
+               if (ie2->type == ie->type && ie2->data == ie->data && ie2->unit - 1 == ((ie->unit - 1) ^ 1) && ie2->allow_mask == ie->allow_mask) {
+                   uid->eventid[i][j] = k;
+                   break;
+               }
+               k++;
+           }
+       }
+    }    
+}
+
+void inputdevice_copy_single_config (struct uae_prefs *p, int src, int dst, int devnum)
+{
+    if (src == dst)
+       return;
+    if (devnum < 0 || gettype (devnum) == IDTYPE_JOYSTICK)
+       memcpy (p->joystick_settings[dst], p->joystick_settings[src], sizeof (struct uae_input_device) * MAX_INPUT_DEVICES);
+    if (devnum < 0 || gettype (devnum) == IDTYPE_MOUSE)
+       memcpy (p->mouse_settings[dst], p->mouse_settings[src], sizeof (struct uae_input_device) * MAX_INPUT_DEVICES);
+    if (devnum < 0 || gettype (devnum) == IDTYPE_KEYBOARD)
+       memcpy (p->keyboard_settings[dst], p->keyboard_settings[src], sizeof (struct uae_input_device) * MAX_INPUT_DEVICES);
+}
+
+void inputdevice_acquire (int exclusive)
+{
+    int i;
+
+    inputdevice_unacquire ();
+    for (i = 0; i < MAX_INPUT_DEVICES; i++) {
+       if (use_joysticks[i])
+           idev[IDTYPE_JOYSTICK].acquire (i, 0);
+    }
+    for (i = 0; i < MAX_INPUT_DEVICES; i++) {
+       if (use_mice[i])
+           idev[IDTYPE_MOUSE].acquire (i, 0);
+    }
+    for (i = 0; i < MAX_INPUT_DEVICES; i++) {
+       if (use_keyboards[i])
+           idev[IDTYPE_KEYBOARD].acquire (i, 0);
+    }
+}
+
+void inputdevice_unacquire (void)
+{
+    int i;
+
+    for (i = 0; i < MAX_INPUT_DEVICES; i++)
+       idev[IDTYPE_JOYSTICK].unacquire (i);
+    for (i = 0; i < MAX_INPUT_DEVICES; i++)
+       idev[IDTYPE_MOUSE].unacquire (i);
+    for (i = 0; i < MAX_INPUT_DEVICES; i++)
+        idev[IDTYPE_KEYBOARD].unacquire (i);
+}
+
+/* Call this function when host machine's joystick/joypad/etc button state changes
+ * This function translates button events to Amiga joybutton/joyaxis/keyboard events
+ */
+
+/* button states:
+ * state = -1 -> mouse wheel turned or similar (button without release)
+ * state = 1 -> button pressed
+ * state = 0 -> button released
+ */
+
+void setjoybuttonstate (int joy, int button, int state)
+{
+    if (!joysticks[joy].enabled)
+       return;
+    setbuttonstateall (&joysticks[joy], &joysticks2[joy], button, state ? 1 : 0);
+}
+
+/* buttonmask = 1 = normal toggle button, 0 = mouse wheel turn or similar
+ */
+void setjoybuttonstateall (int joy, uae_u32 buttonbits, uae_u32 buttonmask)
+{
+    int i;
+
+    if (!joysticks[joy].enabled)
+       return;
+    for (i = 0; i < ID_BUTTON_TOTAL; i++) {
+       if (buttonmask & (1 << i))
+           setbuttonstateall (&joysticks[joy], &joysticks2[joy], i, (buttonbits & (1 << i)) ? 1 : 0);
+       else if (buttonbits & (1 << i))
+           setbuttonstateall (&joysticks[joy], &joysticks2[joy], i, -1);
+    }
+}
+/* mouse buttons (just like joystick buttons)
+ */
+void setmousebuttonstateall (int mouse, uae_u32 buttonbits, uae_u32 buttonmask)
+{
+    int i;
+
+    if (!mice[mouse].enabled)
+       return;
+    for (i = 0; i < ID_BUTTON_TOTAL; i++) {
+       if (buttonmask & (1 << i))
+           setbuttonstateall (&mice[mouse], &mice2[mouse], i, (buttonbits & (1 << i)) ? 1 : 0);
+       else if (buttonbits & (1 << i))
+           setbuttonstateall (&mice[mouse], &mice2[mouse], i, -1);
+    }
+}
+
+void setmousebuttonstate (int mouse, int button, int state)
+{
+    if (!mice[mouse].enabled)
+       return;
+    setbuttonstateall (&mice[mouse], &mice2[mouse], button, state);
+}
+
+/* same for joystick axis (analog or digital)
+ * (0 = center, -max = full left/top, max = full right/bottom)
+ */
+void setjoystickstate (int joy, int axis, int state, int max)
+{
+    struct uae_input_device *id = &joysticks[joy];
+    struct uae_input_device2 *id2 = &joysticks2[joy];
+    int deadzone = currprefs.input_joymouse_deadzone * max / 100;
+    int i, v1, v2;
+
+    if (!joysticks[joy].enabled)
+       return;
+    v1 = state;
+    v2 = id2->states[axis];
+    if (v1 < deadzone && v1 > -deadzone)
+       v1 = 0;
+    if (v2 < deadzone && v2 > -deadzone)
+       v2 = 0;
+    if (v1 == v2)
+       return;
+    for (i = 0; i < MAX_INPUT_SUB_EVENT; i++)
+       handle_input_event (id->eventid[ID_AXIS_OFFSET + axis][i], state, max, id->flags[ID_AXIS_OFFSET + axis][i]);
+    id2->states[axis] = state;
+}
+
+void setmousestate (int mouse, int axis, int data, int isabs)
+{
+    int i, v;
+    double *mouse_p, *oldm_p, d, diff;
+    struct uae_input_device *id = &mice[mouse];
+    static double fract1[MAX_INPUT_DEVICES][MAX_INPUT_DEVICE_EVENTS];
+    static double fract2[MAX_INPUT_DEVICES][MAX_INPUT_DEVICE_EVENTS];
+
+    if (!mice[mouse].enabled)
+       return;
+    d = 0;
+    mouse_p = &mouse_axis[mouse][axis];
+    oldm_p = &oldm_axis[mouse][axis];
+    if (!isabs) {
+       *oldm_p = *mouse_p;
+       *mouse_p += data;
+        d = (*mouse_p - *oldm_p) * currprefs.input_mouse_speed / 100.0;
+    } else {
+       d = data - (int)(*oldm_p);
+       *oldm_p = data;
+       *mouse_p += d;
+       if (mouse == 0) {
+           if (axis == 0)
+               lastmx = data;
+           else
+               lastmy = data;
+       }
+    }
+    v = (int)(d > 0 ? d + 0.5 : d - 0.5);
+    fract1[mouse][axis] += d;
+    fract2[mouse][axis] += v;
+    diff = fract2[mouse][axis] - fract1[mouse][axis];
+    if (diff > 1 || diff < -1) {
+       v -= (int)diff; 
+       fract2[mouse][axis] -= diff;
+    }
+    for (i = 0; i < MAX_INPUT_SUB_EVENT; i++)
+       handle_input_event (id->eventid[ID_AXIS_OFFSET + axis][i], v, 0, 0);
+}
+
+void warpmode (int mode)
+{
+    if (mode < 0) {
+       if (turbo_emulation) {
+           changed_prefs.gfx_framerate = currprefs.gfx_framerate = turbo_emulation;
+           turbo_emulation = 0;
+       }  else {
+           turbo_emulation = currprefs.gfx_framerate;
+       }
+    } else if (mode == 0 && turbo_emulation > 0) {
+        changed_prefs.gfx_framerate = currprefs.gfx_framerate = turbo_emulation;
+       turbo_emulation = 0;
+    } else if (mode > 0 && !turbo_emulation) {
+        turbo_emulation = currprefs.gfx_framerate;
+    }
+    if (turbo_emulation) {
+       if (!currprefs.cpu_cycle_exact && !currprefs.blitter_cycle_exact)
+           changed_prefs.gfx_framerate = currprefs.gfx_framerate = 10;
+        pause_sound ();
+    } else {
+        resume_sound ();
+    }
+    compute_vsynctime ();
+}
+
+void pausemode (int mode)
+{
+    if (mode < 0)
+       pause_emulation = pause_emulation ? 0 : 1;
+    else
+       pause_emulation = mode;
+}
diff --git a/inputevents.def b/inputevents.def
new file mode 100755 (executable)
index 0000000..aa0e99d
--- /dev/null
@@ -0,0 +1,273 @@
+/* joystick/mouse port 1 */
+
+DEFEVENT(JOYPORT1_START,"Joystick port 1", AM_INFO, 0,1,0)
+
+DEFEVENT(MOUSE1_FIRST, "", AM_DUMMY, 0,0,0)
+
+DEFEVENT(MOUSE1_HORIZ,"Mouse1 Horizontal",AM_MOUSE_AXIS|AM_JOY_AXIS,8,1,0)
+DEFEVENT(MOUSE1_VERT,"Mouse1 Vertical",AM_MOUSE_AXIS|AM_JOY_AXIS,8,1,1)
+
+DEFEVENT(MOUSE1_LAST, "", AM_DUMMY, 0,0,0)
+
+DEFEVENT(MOUSE1_UP,"Mouse1 Up",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT,32,1,DIR_UP)
+DEFEVENT(MOUSE1_DOWN,"Mouse1 Down",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT,32,1,DIR_DOWN)
+DEFEVENT(MOUSE1_LEFT,"Mouse1 Left",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT,32,1,DIR_LEFT)
+DEFEVENT(MOUSE1_RIGHT,"Mouse1 Right",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT,32,1,DIR_RIGHT)
+
+DEFEVENT(MOUSE1_WHEEL,"Mouse1 Wheel",AM_MOUSE_AXIS|AM_JOY_AXIS,8,1,2)
+
+DEFEVENT(JOY1_HORIZ,"Joy1 Horizontal",AM_JOY_AXIS,0,1,DIR_LEFT|DIR_RIGHT)
+DEFEVENT(JOY1_VERT,"Joy1 Vertical",AM_JOY_AXIS,0,1,DIR_UP|DIR_DOWN)
+DEFEVENT(JOY1_HORIZ_POT,"Joy1 Horizontal (Analog)",AM_JOY_AXIS,64,1,0)
+DEFEVENT(JOY1_VERT_POT,"Joy1 Vertical (Analog)",AM_JOY_AXIS,64,1,1)
+
+DEFEVENT(JOY1_LEFT,"Joy1 Left",AM_KEY|AM_JOY_BUT|AM_AF,16,1,DIR_LEFT)
+DEFEVENT(JOY1_RIGHT,"Joy1 Right",AM_KEY|AM_JOY_BUT|AM_AF,16,1,DIR_RIGHT)
+DEFEVENT(JOY1_UP,"Joy1 Up",AM_KEY|AM_JOY_BUT|AM_AF,16,1,DIR_UP)
+DEFEVENT(JOY1_DOWN,"Joy1 Down",AM_KEY|AM_JOY_BUT|AM_AF,16,1,DIR_DOWN)
+DEFEVENT(JOY1_LEFT_UP,"Joy1 Left+Up",AM_KEY|AM_JOY_BUT|AM_AF,16,1,DIR_LEFT|DIR_UP)
+DEFEVENT(JOY1_LEFT_DOWN,"Joy1 Left+Down",AM_KEY|AM_JOY_BUT|AM_AF,16,1,DIR_LEFT|DIR_DOWN)
+DEFEVENT(JOY1_RIGHT_UP,"Joy1 Right+Up",AM_KEY|AM_JOY_BUT|AM_AF,16,1,DIR_RIGHT|DIR_UP)
+DEFEVENT(JOY1_RIGHT_DOWN,"Joy1 Right+Down",AM_KEY|AM_JOY_BUT|AM_AF,16,1,DIR_RIGHT|DIR_DOWN)
+
+DEFEVENT(JOY1_FIRE_BUTTON,"Joy1 Fire/Mouse1 Left Button",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,1,JOYBUTTON_1)
+DEFEVENT(JOY1_2ND_BUTTON,"Joy1 2nd Button/Mouse1 Right Button",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,1,JOYBUTTON_2)
+DEFEVENT(JOY1_3RD_BUTTON,"Joy1 3rd Button/Mouse1 Middle Button",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,1,JOYBUTTON_3)
+DEFEVENT(JOY1_CD32_PLAY,"Joy1 CD32 Play",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,1,JOYBUTTON_CD32_PLAY)
+DEFEVENT(JOY1_CD32_RWD,"Joy1 CD32 RWD",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,1,JOYBUTTON_CD32_RWD)
+DEFEVENT(JOY1_CD32_FFW,"Joy1 CD32 FFW",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,1,JOYBUTTON_CD32_FFW)
+DEFEVENT(JOY1_CD32_GREEN,"Joy1 CD32 Green",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,1,JOYBUTTON_CD32_GREEN)
+DEFEVENT(JOY1_CD32_YELLOW,"Joy1 CD32 Yellow",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,1,JOYBUTTON_CD32_YELLOW)
+DEFEVENT(JOY1_CD32_RED,"Joy1 CD32 Red",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,1,JOYBUTTON_CD32_RED)
+DEFEVENT(JOY1_CD32_BLUE,"Joy1 CD32 Blue",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,1,JOYBUTTON_CD32_BLUE)
+
+/* joystick/mouse port 2 */
+
+DEFEVENT(JOYPORT2_START,"Joystick port 2", AM_INFO, 0,2,0)
+
+DEFEVENT(MOUSE2_FIRST, "", AM_DUMMY, 0,0,0)
+
+DEFEVENT(MOUSE2_HORIZ,"Mouse2 Horizontal",AM_MOUSE_AXIS|AM_JOY_AXIS,8,2,0)
+DEFEVENT(MOUSE2_VERT,"Mouse2 Vertical",AM_MOUSE_AXIS|AM_JOY_AXIS,8,2,1)
+
+DEFEVENT(MOUSE2_LAST, "", AM_DUMMY, 0,0,0)
+
+DEFEVENT(MOUSE2_UP,"Mouse2 Up",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT,32,2,DIR_UP)
+DEFEVENT(MOUSE2_DOWN,"Mouse2 Down",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT,32,2,DIR_DOWN)
+DEFEVENT(MOUSE2_LEFT,"Mouse2 Left",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT,32,2,DIR_LEFT)
+DEFEVENT(MOUSE2_RIGHT,"Mouse2 Right",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT,32,2,DIR_RIGHT)
+
+DEFEVENT(JOY2_HORIZ,"Joy2 Horizontal",AM_JOY_AXIS,0,2,DIR_LEFT|DIR_RIGHT)
+DEFEVENT(JOY2_VERT,"Joy2 Vertical",AM_JOY_AXIS,0,2,DIR_UP|DIR_DOWN)
+DEFEVENT(JOY2_HORIZ_POT,"Joy2 Horizontal (Analog)",AM_JOY_AXIS,64,2,0)
+DEFEVENT(JOY2_VERT_POT,"Joy2 Vertical (Analog)",AM_JOY_AXIS,64,2,1)
+
+DEFEVENT(JOY2_LEFT,"Joy2 Left",AM_KEY|AM_JOY_BUT|AM_AF,16,2,DIR_LEFT)
+DEFEVENT(JOY2_RIGHT,"Joy2 Right",AM_KEY|AM_JOY_BUT|AM_AF,16,2,DIR_RIGHT)
+DEFEVENT(JOY2_UP,"Joy2 Up",AM_KEY|AM_JOY_BUT|AM_AF,16,2,DIR_UP)
+DEFEVENT(JOY2_DOWN,"Joy2 Down",AM_KEY|AM_JOY_BUT|AM_AF,16,2,DIR_DOWN)
+DEFEVENT(JOY2_LEFT_UP,"Joy2 Left+Up",AM_KEY|AM_JOY_BUT|AM_AF,16,2,DIR_LEFT|DIR_UP)
+DEFEVENT(JOY2_LEFT_DOWN,"Joy2 Left+Down",AM_KEY|AM_JOY_BUT|AM_AF,16,2,DIR_LEFT|DIR_DOWN)
+DEFEVENT(JOY2_RIGHT_UP,"Joy2 Right+Up",AM_KEY|AM_JOY_BUT|AM_AF,16,2,DIR_RIGHT|DIR_UP)
+DEFEVENT(JOY2_RIGHT_DOWN,"Joy2 Right+Down",AM_KEY|AM_JOY_BUT|AM_AF,16,2,DIR_RIGHT|DIR_DOWN)
+
+DEFEVENT(JOY2_FIRE_BUTTON,"Joy2 Fire/Mouse1 Left Button",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,2,JOYBUTTON_1)
+DEFEVENT(JOY2_2ND_BUTTON,"Joy2 2nd Button/Mouse1 Right Button",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,2,JOYBUTTON_2)
+DEFEVENT(JOY2_3RD_BUTTON,"Joy2 3rd Button/Mouse1 Middle Button",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,2,JOYBUTTON_3)
+DEFEVENT(JOY2_CD32_PLAY,"Joy2 CD32 Play",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,2,JOYBUTTON_CD32_PLAY)
+DEFEVENT(JOY2_CD32_RWD,"Joy2 CD32 RWD",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,2,JOYBUTTON_CD32_RWD)
+DEFEVENT(JOY2_CD32_FFW,"Joy2 CD32 FFW",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,2,JOYBUTTON_CD32_FFW)
+DEFEVENT(JOY2_CD32_GREEN,"Joy2 CD32 Green",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,2,JOYBUTTON_CD32_GREEN)
+DEFEVENT(JOY2_CD32_YELLOW,"Joy2 CD32 Yellow",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,2,JOYBUTTON_CD32_YELLOW)
+DEFEVENT(JOY2_CD32_RED,"Joy2 CD32 Red",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,2,JOYBUTTON_CD32_RED)
+DEFEVENT(JOY2_CD32_BLUE,"Joy2 CD32 Blue",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,2,JOYBUTTON_CD32_BLUE)
+
+/* parallel port joystick adapter */
+
+DEFEVENT(PAR_JOY1_START, "Parallel port joystick adapter", AM_INFO, 0,3,0)
+
+DEFEVENT(PAR_JOY1_HORIZ,"Parallel Joy1 Horizontal",AM_JOY_AXIS,0,3,DIR_LEFT|DIR_RIGHT)
+DEFEVENT(PAR_JOY1_VERT,"Parallel Joy1 Vertical",AM_JOY_AXIS,0,3,DIR_UP|DIR_DOWN)
+DEFEVENT(PAR_JOY1_LEFT,"Parallel Joy1 Left",AM_KEY|AM_JOY_BUT|AM_AF,16,3,DIR_LEFT)
+DEFEVENT(PAR_JOY1_RIGHT,"Parallel Joy1 Right",AM_KEY|AM_JOY_BUT|AM_AF,16,3,DIR_RIGHT)
+DEFEVENT(PAR_JOY1_UP,"Parallel Joy1 Up",AM_KEY|AM_JOY_BUT|AM_AF,16,3,DIR_UP)
+DEFEVENT(PAR_JOY1_DOWN,"Parallel Joy1 Down",AM_KEY|AM_JOY_BUT|AM_AF,16,3,DIR_DOWN)
+DEFEVENT(PAR_JOY1_LEFT_UP,"Parallel Joy1 Left+Up",AM_KEY|AM_JOY_BUT|AM_AF,16,3,DIR_LEFT|DIR_UP)
+DEFEVENT(PAR_JOY1_LEFT_DOWN,"Parallel Joy1 Left+Down",AM_KEY|AM_JOY_BUT|AM_AF,16,3,DIR_LEFT|DIR_DOWN)
+DEFEVENT(PAR_JOY1_RIGHT_UP,"Parallel Joy1 Right+Up",AM_KEY|AM_JOY_BUT|AM_AF,16,3,DIR_RIGHT|DIR_UP)
+DEFEVENT(PAR_JOY1_RIGHT_DOWN,"Parallel Joy1 Right+Down",AM_KEY|AM_JOY_BUT|AM_AF,16,3,DIR_RIGHT|DIR_DOWN)
+DEFEVENT(PAR_JOY1_FIRE_BUTTON,"Parallel Joy1 Fire Button",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,3,JOYBUTTON_1)
+
+DEFEVENT(PAR_JOY2_START, "", AM_DUMMY, 0,4,0)
+
+DEFEVENT(PAR_JOY2_HORIZ,"Parallel Joy2 Horizontal",AM_JOY_AXIS,0,4,DIR_LEFT|DIR_RIGHT)
+DEFEVENT(PAR_JOY2_VERT,"Parallel Joy2 Vertical",AM_JOY_AXIS,0,4,DIR_UP|DIR_DOWN)
+DEFEVENT(PAR_JOY2_LEFT,"Parallel Joy2 Left",AM_KEY|AM_JOY_BUT|AM_AF,16,4,DIR_LEFT)
+DEFEVENT(PAR_JOY2_RIGHT,"Parallel Joy2 Right",AM_KEY|AM_JOY_BUT|AM_AF,16,4,DIR_RIGHT)
+DEFEVENT(PAR_JOY2_UP,"Parallel Joy2 Up",AM_KEY|AM_JOY_BUT|AM_AF,16,4,DIR_UP)
+DEFEVENT(PAR_JOY2_DOWN,"Parallel Joy2 Down",AM_KEY|AM_JOY_BUT|AM_AF,16,4,DIR_DOWN)
+DEFEVENT(PAR_JOY2_LEFT_UP,"Parallel Joy2 Left+Up",AM_KEY|AM_JOY_BUT|AM_AF,16,4,DIR_LEFT|DIR_UP)
+DEFEVENT(PAR_JOY2_LEFT_DOWN,"Parallel Joy2 Left+Down",AM_KEY|AM_JOY_BUT|AM_AF,16,4,DIR_LEFT|DIR_DOWN)
+DEFEVENT(PAR_JOY2_RIGHT_UP,"Parallel Joy2 Right+Up",AM_KEY|AM_JOY_BUT|AM_AF,16,4,DIR_RIGHT|DIR_UP)
+DEFEVENT(PAR_JOY2_RIGHT_DOWN,"Parallel Joy2 Right+Down",AM_KEY|AM_JOY_BUT|AM_AF,16,4,DIR_RIGHT|DIR_DOWN)
+DEFEVENT(PAR_JOY2_FIRE_BUTTON,"Parallel Joy2 Fire Button",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,4,JOYBUTTON_1)
+
+DEFEVENT(PAR_JOY_END, "", AM_DUMMY, 0,0,0)
+
+/* keys */
+
+DEFEVENT(KEY_START,"Keyboard",AM_INFO, 0,0,0)
+
+DEFEVENT(KEY_F1,"F1",AM_K,0,0,AK_F1)
+DEFEVENT(KEY_F2,"F2",AM_K,0,0,AK_F2)
+DEFEVENT(KEY_F3,"F3",AM_K,0,0,AK_F3)
+DEFEVENT(KEY_F4,"F4",AM_K,0,0,AK_F4)
+DEFEVENT(KEY_F5,"F5",AM_K,0,0,AK_F5)
+DEFEVENT(KEY_F6,"F6",AM_K,0,0,AK_F6)
+DEFEVENT(KEY_F7,"F7",AM_K,0,0,AK_F7)
+DEFEVENT(KEY_F8,"F8",AM_K,0,0,AK_F8)
+DEFEVENT(KEY_F9,"F9",AM_K,0,0,AK_F9)
+DEFEVENT(KEY_F10,"F10",AM_K,0,0,AK_F10)
+
+/* "special" keys */
+
+DEFEVENT(KEY_ESC,"ESC",AM_K,0,0,AK_ESC)
+DEFEVENT(KEY_TAB,"Tab",AM_K,0,0,AK_TAB)
+DEFEVENT(KEY_CTRL,"CTRL",AM_K,0,0,AK_CTRL)
+DEFEVENT(KEY_CTRL_RIGHT,"Right CTRL",AM_K,0,0,AK_RCTRL)
+DEFEVENT(KEY_CAPS_LOCK,"Caps Lock",AM_K,0,0,AK_CAPSLOCK)
+DEFEVENT(KEY_SHIFT_LEFT,"Left Shift",AM_K,0,0,AK_LSH)
+DEFEVENT(KEY_ALT_LEFT,"Left Alt",AM_K,0,0,AK_LALT)
+DEFEVENT(KEY_AMIGA_LEFT,"Left Amiga",AM_K,0,0,AK_LAMI)
+DEFEVENT(KEY_AMIGA_RIGHT,"Right Amiga",AM_K,0,0,AK_RAMI)
+DEFEVENT(KEY_ALT_RIGHT,"Right Alt",AM_K,0,0,AK_RALT)
+DEFEVENT(KEY_SHIFT_RIGHT,"Right Shift",AM_K,0,0,AK_RSH)
+DEFEVENT(KEY_SPACE,"Space",AM_K,0,0,AK_SPC)
+DEFEVENT(KEY_CURSOR_UP,"Cursor Up",AM_K,0,0,AK_UP)
+DEFEVENT(KEY_CURSOR_DOWN,"Cursor Down",AM_K,0,0,AK_DN)
+DEFEVENT(KEY_CURSOR_LEFT,"Cursor Left",AM_K,0,0,AK_LF)
+DEFEVENT(KEY_CURSOR_RIGHT,"Cursor Right",AM_K,0,0,AK_RT)
+DEFEVENT(KEY_HELP,"Help",AM_K,0,0,AK_HELP)
+DEFEVENT(KEY_DEL,"Del",AM_K,0,0,AK_DEL)
+DEFEVENT(KEY_BACKSPACE,"Backspace",AM_K,0,0,AK_BS)
+DEFEVENT(KEY_RETURN,"Return",AM_K,0,0,AK_RET)
+
+/* numpad */
+
+DEFEVENT(KEY_A,"A",AM_K,0,0,AK_A)
+DEFEVENT(KEY_B,"B",AM_K,0,0,AK_B)
+DEFEVENT(KEY_C,"C",AM_K,0,0,AK_C)
+DEFEVENT(KEY_D,"D",AM_K,0,0,AK_D)
+DEFEVENT(KEY_E,"E",AM_K,0,0,AK_E)
+DEFEVENT(KEY_F,"F",AM_K,0,0,AK_F)
+DEFEVENT(KEY_G,"G",AM_K,0,0,AK_G)
+DEFEVENT(KEY_H,"H",AM_K,0,0,AK_H)
+DEFEVENT(KEY_I,"I",AM_K,0,0,AK_I)
+DEFEVENT(KEY_J,"J",AM_K,0,0,AK_J)
+DEFEVENT(KEY_K,"K",AM_K,0,0,AK_K)
+DEFEVENT(KEY_L,"L",AM_K,0,0,AK_L)
+DEFEVENT(KEY_M,"M",AM_K,0,0,AK_M)
+DEFEVENT(KEY_N,"N",AM_K,0,0,AK_N)
+DEFEVENT(KEY_O,"O",AM_K,0,0,AK_O)
+DEFEVENT(KEY_P,"P",AM_K,0,0,AK_P)
+DEFEVENT(KEY_Q,"Q",AM_K,0,0,AK_Q)
+DEFEVENT(KEY_R,"R",AM_K,0,0,AK_R)
+DEFEVENT(KEY_S,"S",AM_K,0,0,AK_S)
+DEFEVENT(KEY_T,"T",AM_K,0,0,AK_T)
+DEFEVENT(KEY_U,"U",AM_K,0,0,AK_U)
+DEFEVENT(KEY_V,"V",AM_K,0,0,AK_V)
+DEFEVENT(KEY_W,"W",AM_K,0,0,AK_W)
+DEFEVENT(KEY_X,"X",AM_K,0,0,AK_X)
+DEFEVENT(KEY_Y,"Y",AM_K,0,0,AK_Y)
+DEFEVENT(KEY_Z,"Z",AM_K,0,0,AK_Z)
+
+DEFEVENT(KEY_ENTER,"Numpad Enter",AM_K,0,0,AK_ENT)
+DEFEVENT(KEY_NP_0,"Numpad 0",AM_K,0,0,AK_NP0)
+DEFEVENT(KEY_NP_1,"Numpad 1",AM_K,0,0,AK_NP1)
+DEFEVENT(KEY_NP_2,"Numpad 2",AM_K,0,0,AK_NP2)
+DEFEVENT(KEY_NP_3,"Numpad 3",AM_K,0,0,AK_NP3)
+DEFEVENT(KEY_NP_4,"Numpad 4",AM_K,0,0,AK_NP4)
+DEFEVENT(KEY_NP_5,"Numpad 5",AM_K,0,0,AK_NP5)
+DEFEVENT(KEY_NP_6,"Numpad 6",AM_K,0,0,AK_NP6)
+DEFEVENT(KEY_NP_7,"Numpad 7",AM_K,0,0,AK_NP7)
+DEFEVENT(KEY_NP_8,"Numpad 8",AM_K,0,0,AK_NP8)
+DEFEVENT(KEY_NP_9,"Numpad 9",AM_K,0,0,AK_NP9)
+DEFEVENT(KEY_NP_PERIOD,"Numpad Period",AM_K,0,0,AK_NPDEL)
+DEFEVENT(KEY_NP_ADD,"Numpad Plus",AM_K,0,0,AK_NPADD)
+DEFEVENT(KEY_NP_SUB,"Numpad Minus",AM_K,0,0,AK_NPSUB)
+DEFEVENT(KEY_NP_MUL,"Numpad Multiply",AM_K,0,0,AK_NPMUL)
+DEFEVENT(KEY_NP_DIV,"Numpad Divide",AM_K,0,0,AK_NPDIV)
+DEFEVENT(KEY_NP_LPAREN,"Numpad Left Parenthesis",AM_K,0,0,AK_NPLPAREN)
+DEFEVENT(KEY_NP_RPAREN,"Numpad Right Parenthesis",AM_K,0,0,AK_NPRPAREN)
+DEFEVENT(KEY_2B,"Keycode 0x2b",AM_K,0,0,0x2b)
+DEFEVENT(KEY_30,"Keycode 0x30",AM_K,0,0,0x30)
+
+DEFEVENT(KEY_BACKQUOTE,"Back Quote",AM_K,0,0,AK_BACKQUOTE)
+DEFEVENT(KEY_1,"1",AM_K,0,0,AK_1)
+DEFEVENT(KEY_2,"2",AM_K,0,0,AK_2)
+DEFEVENT(KEY_3,"3",AM_K,0,0,AK_3)
+DEFEVENT(KEY_4,"4",AM_K,0,0,AK_4)
+DEFEVENT(KEY_5,"5",AM_K,0,0,AK_5)
+DEFEVENT(KEY_6,"6",AM_K,0,0,AK_6)
+DEFEVENT(KEY_7,"7",AM_K,0,0,AK_7)
+DEFEVENT(KEY_8,"8",AM_K,0,0,AK_8)
+DEFEVENT(KEY_9,"9",AM_K,0,0,AK_9)
+DEFEVENT(KEY_0,"0",AM_K,0,0,AK_0)
+DEFEVENT(KEY_SUB,"Minus",AM_K,0,0,AK_MINUS)
+DEFEVENT(KEY_EQUALS,"Equals",AM_K,0,0,AK_EQUAL)
+DEFEVENT(KEY_BACKSLASH,"Backslash",AM_K,0,0,AK_BACKSLASH)
+
+DEFEVENT(KEY_LEFTBRACKET,"Left Bracket",AM_K,0,0,AK_LBRACKET)
+DEFEVENT(KEY_RIGHTBRACKET,"Right Bracket",AM_K,0,0,AK_RBRACKET)
+DEFEVENT(KEY_SEMICOLON,"Semicolon",AM_K,0,0,AK_SEMICOLON)
+DEFEVENT(KEY_SINGLEQUOTE,"Single Quote",AM_K,0,0,AK_QUOTE)
+DEFEVENT(KEY_COMMA,"Comma",AM_K,0,0,AK_COMMA)
+DEFEVENT(KEY_PERIOD,"Period",AM_K,0,0,AK_PERIOD)
+DEFEVENT(KEY_DIV,"Slash",AM_K,0,0,AK_SLASH)
+
+// DEFEVENT(KEY_,"",AM_K,0,0,0x)
+
+/* mouse wheel "keys" */
+
+DEFEVENT(MOUSEWHEEL_DOWN,"Mouse Wheel Down",AM_K,0,0,0x7a)
+DEFEVENT(MOUSEWHEEL_UP,"Mouse Wheel Up",AM_K,0,0,0x7b)
+
+/* misc */
+
+DEFEVENT(KEY_CDTV_STOP,"CDTV Stop",AM_K,0,0,0x72)
+DEFEVENT(KEY_CDTV_PLAYPAUSE,"CDTV Play/Pause",AM_K,0,0,0x73)
+DEFEVENT(KEY_CDTV_FF,"CDTV Fast Forward",AM_K,0,0,0x74)
+DEFEVENT(KEY_CDTV_REW,"CDTV Rewind",AM_K,0,0,0x75)
+
+DEFEVENT(KEY_70,"Keycode 0x70",AM_K,0,0,0x70)
+DEFEVENT(KEY_71,"Keycode 0x71",AM_K,0,0,0x71)
+DEFEVENT(KEY_76,"Keycode 0x76",AM_K,0,0,0x76)
+DEFEVENT(KEY_77,"Keycode 0x77",AM_K,0,0,0x77)
+DEFEVENT(KEY_78,"Keycode 0x78 (Reset Warning)",AM_K,0,0,0x78)
+DEFEVENT(KEY_79,"Keycode 0x79",AM_K,0,0,0x79)
+
+/* special */
+
+DEFEVENT(SPC_ENTERGUI,"Enter GUI",AM_K,0,0,AKS_ENTERGUI)
+DEFEVENT(SPC_SCREENSHOT,"Screenshot",AM_K,0,0,AKS_SCREENSHOT)
+DEFEVENT(SPC_FREEZEBUTTON,"Activate Cartridge",AM_K,0,0,AKS_FREEZEBUTTON)
+DEFEVENT(SPC_FLOPPY0,"Change disk in DF0:",AM_K,0,0,AKS_FLOPPY0)
+DEFEVENT(SPC_FLOPPY1,"Change disk in DF1:",AM_K,0,0,AKS_FLOPPY1)
+DEFEVENT(SPC_FLOPPY2,"Change disk in DF2:",AM_K,0,0,AKS_FLOPPY2)
+DEFEVENT(SPC_FLOPPY3,"Change disk in DF3:",AM_K,0,0,AKS_FLOPPY3)
+DEFEVENT(SPC_EFLOPPY0,"Eject disk in DF0:",AM_K,0,0,AKS_EFLOPPY0)
+DEFEVENT(SPC_EFLOPPY1,"Eject disk in DF0:",AM_K,0,0,AKS_EFLOPPY1)
+DEFEVENT(SPC_EFLOPPY2,"Eject disk in DF0:",AM_K,0,0,AKS_EFLOPPY2)
+DEFEVENT(SPC_EFLOPPY3,"Eject disk in DF0:",AM_K,0,0,AKS_EFLOPPY3)
+DEFEVENT(SPC_PAUSE,"Pause emulation",AM_K,0,0,AKS_PAUSE)
+DEFEVENT(SPC_WARP,"Warp mode",AM_K,0,0,AKS_WARP)
+DEFEVENT(SPC_INHIBITSCREEN,"Toggle screen updates",AM_K,0,0,AKS_INHIBITSCREEN)
+DEFEVENT(SPC_IRQ7,"Level 7 interrupt",AM_K,0,0,AKS_IRQ7)
+DEFEVENT(SPC_STATEREWIND,"Load previous state capture",AM_K,0,0,AKS_STATEREWIND)
+DEFEVENT(SPC_VOLUME_DOWN,"Decrease volume level",AM_K,0,0,AKS_VOLDOWN)
+DEFEVENT(SPC_VOLUME_UP,"Increase volume level",AM_K,0,0,AKS_VOLUP)
+DEFEVENT(SPC_VOLUME_MUTE,"Mute/unmute volume",AM_K,0,0,AKS_VOLMUTE)
+DEFEVENT(SPC_QUIT,"Quit emulator",AM_K,0,0,AKS_QUIT)
+DEFEVENT(SPC_STATESAVE,"Save state",AM_K,0,0,AKS_STATESAVE)
+DEFEVENT(SPC_STATERESTORE,"Restore state",AM_K,0,0,AKS_STATERESTORE)
+
diff --git a/keybuf.c b/keybuf.c
new file mode 100755 (executable)
index 0000000..f4ff6a5
--- /dev/null
+++ b/keybuf.c
@@ -0,0 +1,169 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Keyboard buffer. Not really needed for X, but for SVGAlib and possibly
+  * Mac and DOS ports.
+  *
+  * Note: it's possible to have two threads in UAE, one reading keystrokes
+  * and the other one writing them. Despite this, no synchronization effort
+  * is needed. This code should be perfectly thread safe. At least if you
+  * assume that integer store instructions are atomic.
+  *
+  * Copyright 1995, 1997 Bernd Schmidt
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+#include <assert.h>
+
+#include "config.h"
+#include "options.h"
+#include "keybuf.h"
+#include "keyboard.h"
+#include "inputdevice.h"
+#include "custom.h"
+#include "savestate.h"
+
+static int fakestate[3][6] = { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0 } };
+
+static int *fs_np;
+static int *fs_ck;
+static int *fs_se;
+
+/* Not static so the DOS code can mess with them */
+int kpb_first, kpb_last;
+
+static int keybuf[256];
+
+int keys_available (void)
+{
+    int val;
+    val = kpb_first != kpb_last;
+    return val;
+}
+
+int get_next_key (void)
+{
+    int key;
+    assert (kpb_first != kpb_last);
+
+    key = keybuf[kpb_last];
+    if (++kpb_last == 256)
+       kpb_last = 0;
+    return key;
+}
+
+static void do_fake (int nr)
+{
+    int *fake = fakestate[nr];
+
+    nr += 2;
+    setjoystickstate (nr, 0, fake[1] ? -100 : (fake[2] ? 100 : 0), 100);
+    setjoystickstate (nr, 1, fake[0] ? -100 : (fake[3] ? 100 : 0), 100);
+    setjoybuttonstate (nr, 0, fake[4]);
+    setjoybuttonstate (nr, 1, fake[5]);
+}
+
+void record_key (int kc)
+{
+    int fs = 0;
+    int kpb_next = kpb_first + 1;
+
+    //write_log ("got kc %02.2X\n", ((kc << 7) | (kc >> 1)) & 0xff);
+    if (kpb_next == 256)
+       kpb_next = 0;
+    if (kpb_next == kpb_last) {
+       write_log ("Keyboard buffer overrun. Congratulations.\n");
+       return;
+    }
+    if (fs_np != 0) {
+       switch (kc >> 1) {
+       case AK_NP8: fs = 1; fs_np[0] = !(kc & 1); break;
+       case AK_NP4: fs = 1; fs_np[1] = !(kc & 1); break;
+       case AK_NP6: fs = 1; fs_np[2] = !(kc & 1); break;
+       case AK_NP2: fs = 1; fs_np[3] = !(kc & 1); break;
+       case AK_NP0: case AK_NP5: fs = 1; fs_np[4] = !(kc & 1); break;
+       case AK_NPDEL: case AK_NPDIV: case AK_ENT: fs = 1; fs_np[5] = !(kc & 1); break;
+       }
+    }
+    if (fs_ck != 0) {
+       switch (kc >> 1) {
+       case AK_UP: fs = 1; fs_ck[0] = !(kc & 1); break;
+       case AK_LF: fs = 1; fs_ck[1] = !(kc & 1); break;
+       case AK_RT: fs = 1; fs_ck[2] = !(kc & 1); break;
+       case AK_DN: fs = 1; fs_ck[3] = !(kc & 1); break;
+       case AK_RCTRL: fs = 1; fs_ck[4] = !(kc & 1); break;
+       case AK_RSH: fs = 1; fs_ck[5] = !(kc & 1); break;
+       }
+    }
+    if (fs_se != 0) {
+       switch (kc >> 1) {
+       case AK_T: fs = 1; fs_se[0] = !(kc & 1); break;
+       case AK_F: fs = 1; fs_se[1] = !(kc & 1); break;
+       case AK_H: fs = 1; fs_se[2] = !(kc & 1); break;
+       case AK_B: fs = 1; fs_se[3] = !(kc & 1); break;
+       case AK_LALT: fs = 1; fs_se[4] = !(kc & 1); break;
+       case AK_LSH: fs = 1; fs_se[5] = !(kc & 1); break;
+       }
+    }
+
+    if (fs && currprefs.input_selected_setting == 0) {
+       if (JSEM_ISNUMPAD (0, &currprefs) || JSEM_ISCURSOR (0, &currprefs) || JSEM_ISSOMEWHEREELSE (0, &currprefs))
+           do_fake (0);
+       if (JSEM_ISNUMPAD (1, &currprefs) || JSEM_ISCURSOR (1, &currprefs) || JSEM_ISSOMEWHEREELSE (1, &currprefs))
+           do_fake (1);
+       return;
+    } else {
+        if ((kc >> 1) == AK_RCTRL) {
+           kc ^= AK_RCTRL << 1;
+           kc ^= AK_CTRL << 1;
+       }
+    }
+
+    keybuf[kpb_first] = kc;
+    kpb_first = kpb_next;
+}
+
+void joystick_setting_changed (void)
+{
+    fs_np = fs_ck = fs_se = 0;
+
+    if (JSEM_ISNUMPAD (0, &currprefs))
+       fs_np = fakestate[0];
+    else if (JSEM_ISNUMPAD (1, &currprefs))
+       fs_np = fakestate[1];
+
+    if (JSEM_ISCURSOR (0, &currprefs))
+       fs_ck = fakestate[0];
+    else if (JSEM_ISCURSOR (1, &currprefs))
+       fs_ck = fakestate[1];
+
+    if (JSEM_ISSOMEWHEREELSE (0, &currprefs))
+       fs_se = fakestate[0];
+    else if (JSEM_ISSOMEWHEREELSE (1, &currprefs))
+       fs_se = fakestate[1];
+}
+
+void keybuf_init (void)
+{
+    kpb_first = kpb_last = 0;
+    inputdevice_updateconfig (&currprefs);
+}
+
+
+uae_u8 *save_keyboard (int *len)
+{
+    uae_u8 *dst, *t;
+    dst = t = malloc (8);
+    save_u32 (getcapslockstate() ? 1 : 0);
+    save_u32 (0);
+    *len = 8;
+    return t;
+}
+
+uae_u8 *restore_keyboard (uae_u8 *src)
+{
+    setcapslockstate (restore_u32 ());
+    restore_u32 ();
+    return src;
+}
diff --git a/main.c b/main.c
new file mode 100755 (executable)
index 0000000..58dbb18
--- /dev/null
+++ b/main.c
@@ -0,0 +1,701 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Main program
+  *
+  * Copyright 1995 Ed Hanway
+  * Copyright 1995, 1996, 1997 Bernd Schmidt
+  */
+#include "sysconfig.h"
+#include "sysdeps.h"
+#include <assert.h>
+
+#include "config.h"
+#include "options.h"
+#include "threaddep/thread.h"
+#include "uae.h"
+#include "gensound.h"
+#include "audio.h"
+#include "sounddep/sound.h"
+#include "events.h"
+#include "memory.h"
+#include "custom.h"
+#include "serial.h"
+#include "newcpu.h"
+#include "disk.h"
+#include "debug.h"
+#include "xwin.h"
+#include "inputdevice.h"
+#include "keybuf.h"
+#include "gui.h"
+#include "zfile.h"
+#include "autoconf.h"
+#include "osemu.h"
+#include "osdep/exectasks.h"
+#include "compiler.h"
+#include "picasso96.h"
+#include "bsdsocket.h"
+#include "uaeexe.h"
+#include "native2amiga.h"
+#include "scsidev.h"
+#include "akiko.h"
+#include "savestate.h"
+
+#ifdef USE_SDL
+#include "SDL.h"
+#endif
+
+long int version = 256*65536L*UAEMAJOR + 65536L*UAEMINOR + UAESUBREV;
+
+struct uae_prefs currprefs, changed_prefs;
+
+int no_gui = 0;
+int joystickpresent = 0;
+int cloanto_rom = 0;
+
+struct gui_info gui_data;
+
+char warning_buffer[256];
+
+char optionsfile[256];
+
+/* If you want to pipe printer output to a file, put something like
+ * "cat >>printerfile.tmp" above.
+ * The printer support was only tested with the driver "PostScript" on
+ * Amiga side, using apsfilter for linux to print ps-data.
+ *
+ * Under DOS it ought to be -p LPT1: or -p PRN: but you'll need a
+ * PostScript printer or ghostscript -=SR=-
+ */
+
+/* Slightly stupid place for this... */
+/* ncurses.c might use quite a few of those. */
+char *colormodes[] = { "256 colors", "32768 colors", "65536 colors",
+    "256 colors dithered", "16 colors dithered", "16 million colors",
+    "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
+    "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
+    "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
+    "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
+    "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""
+};
+
+void discard_prefs (struct uae_prefs *p, int type)
+{
+    struct strlist **ps = &p->all_lines;
+    while (*ps) {
+       struct strlist *s = *ps;
+       *ps = s->next;
+       free (s->value);
+       free (s->option);
+       free (s);
+    }
+#ifdef FILESYS
+    free_mountinfo (p->mountinfo);
+    p->mountinfo = alloc_mountinfo ();
+#endif
+}
+
+void fixup_prefs_dimensions (struct uae_prefs *prefs)
+{
+    if (prefs->gfx_width_fs < 320)
+       prefs->gfx_width_fs = 320;
+    if (prefs->gfx_height_fs < 200)
+       prefs->gfx_height_fs = 200;
+    if (prefs->gfx_height_fs > 1280)
+       prefs->gfx_height_fs = 1280;
+    prefs->gfx_width_fs += 7; /* X86.S wants multiples of 4 bytes, might be 8 in the future. */
+    prefs->gfx_width_fs &= ~7;
+    if (prefs->gfx_width_win < 320)
+       prefs->gfx_width_win = 320;
+    if (prefs->gfx_height_win < 200)
+       prefs->gfx_height_win = 200;
+    if (prefs->gfx_height_win > 1280)
+       prefs->gfx_height_win = 1280;
+    prefs->gfx_width_win += 7; /* X86.S wants multiples of 4 bytes, might be 8 in the future. */
+    prefs->gfx_width_win &= ~7;
+}
+
+static void fix_options (void)
+{
+    int err = 0;
+
+    if ((currprefs.chipmem_size & (currprefs.chipmem_size - 1)) != 0
+       || currprefs.chipmem_size < 0x40000
+       || currprefs.chipmem_size > 0x800000)
+    {
+       currprefs.chipmem_size = 0x200000;
+       write_log ("Unsupported chipmem size!\n");
+       err = 1;
+    }
+    if (currprefs.chipmem_size > 0x80000)
+       currprefs.chipset_mask |= CSMASK_ECS_AGNUS;
+
+    if ((currprefs.fastmem_size & (currprefs.fastmem_size - 1)) != 0
+       || (currprefs.fastmem_size != 0 && (currprefs.fastmem_size < 0x100000 || currprefs.fastmem_size > 0x800000)))
+    {
+       currprefs.fastmem_size = 0;
+       write_log ("Unsupported fastmem size!\n");
+       err = 1;
+    }
+    if ((currprefs.gfxmem_size & (currprefs.gfxmem_size - 1)) != 0
+       || (currprefs.gfxmem_size != 0 && (currprefs.gfxmem_size < 0x100000 || currprefs.gfxmem_size > 0x2000000)))
+    {
+       write_log ("Unsupported graphics card memory size %lx!\n", currprefs.gfxmem_size);
+       currprefs.gfxmem_size = 0;
+       err = 1;
+    }
+    if ((currprefs.z3fastmem_size & (currprefs.z3fastmem_size - 1)) != 0
+       || (currprefs.z3fastmem_size != 0 && (currprefs.z3fastmem_size < 0x100000 || currprefs.z3fastmem_size > 0x20000000)))
+    {
+       currprefs.z3fastmem_size = 0;
+       write_log ("Unsupported Zorro III fastmem size!\n");
+       err = 1;
+    }
+    if (currprefs.address_space_24 && (currprefs.gfxmem_size != 0 || currprefs.z3fastmem_size != 0)) {
+       currprefs.z3fastmem_size = currprefs.gfxmem_size = 0;
+       write_log ("Can't use a graphics card or Zorro III fastmem when using a 24 bit\n"
+                "address space - sorry.\n");
+    }
+    if (currprefs.bogomem_size != 0 && currprefs.bogomem_size != 0x80000 && currprefs.bogomem_size != 0x100000 && currprefs.bogomem_size != 0x180000)
+    {
+       currprefs.bogomem_size = 0;
+       write_log ("Unsupported bogomem size!\n");
+       err = 1;
+    }
+
+    if (currprefs.chipmem_size > 0x200000 && currprefs.fastmem_size != 0) {
+       write_log ("You can't use fastmem and more than 2MB chip at the same time!\n");
+       currprefs.fastmem_size = 0;
+       err = 1;
+    }
+#if 0
+    if (currprefs.m68k_speed < -1 || currprefs.m68k_speed > 20) {
+       write_log ("Bad value for -w parameter: must be -1, 0, or within 1..20.\n");
+       currprefs.m68k_speed = 4;
+       err = 1;
+    }
+#endif
+  
+    if (currprefs.produce_sound < 0 || currprefs.produce_sound > 3) {
+       write_log ("Bad value for -S parameter: enable value must be within 0..3\n");
+       currprefs.produce_sound = 0;
+       err = 1;
+    }
+    if (currprefs.comptrustbyte < 0 || currprefs.comptrustbyte > 3) {
+       fprintf (stderr, "Bad value for comptrustbyte parameter: value must be within 0..2\n");
+       currprefs.comptrustbyte = 1;
+       err = 1;
+    }
+    if (currprefs.comptrustword < 0 || currprefs.comptrustword > 3) {
+       fprintf (stderr, "Bad value for comptrustword parameter: value must be within 0..2\n");
+       currprefs.comptrustword = 1;
+       err = 1;
+    }
+    if (currprefs.comptrustlong < 0 || currprefs.comptrustlong > 3) {
+       fprintf (stderr, "Bad value for comptrustlong parameter: value must be within 0..2\n");
+       currprefs.comptrustlong = 1;
+       err = 1;
+    }
+    if (currprefs.comptrustnaddr < 0 || currprefs.comptrustnaddr > 3) {
+       fprintf (stderr, "Bad value for comptrustnaddr parameter: value must be within 0..2\n");
+       currprefs.comptrustnaddr = 1;
+       err = 1;
+    }
+    if (currprefs.compnf < 0 || currprefs.compnf > 1) {
+       fprintf (stderr, "Bad value for compnf parameter: value must be within 0..1\n");
+       currprefs.compnf = 1;
+       err = 1;
+    }
+    if (currprefs.comp_hardflush < 0 || currprefs.comp_hardflush > 1) {
+       fprintf (stderr, "Bad value for comp_hardflush parameter: value must be within 0..1\n");
+       currprefs.comp_hardflush = 1;
+       err = 1;
+    }
+    if (currprefs.comp_constjump < 0 || currprefs.comp_constjump > 1) {
+       fprintf (stderr, "Bad value for comp_constjump parameter: value must be within 0..1\n");
+       currprefs.comp_constjump = 1;
+       err = 1;
+    }
+    if (currprefs.comp_oldsegv < 0 || currprefs.comp_oldsegv > 1) {
+       fprintf (stderr, "Bad value for comp_oldsegv parameter: value must be within 0..1\n");
+       currprefs.comp_oldsegv = 1;
+       err = 1;
+    }
+    if (currprefs.cachesize < 0 || currprefs.cachesize > 16384) {
+       fprintf (stderr, "Bad value for cachesize parameter: value must be within 0..16384\n");
+       currprefs.cachesize = 0;
+       err = 1;
+    }
+
+    if (currprefs.cpu_level < 2 && currprefs.z3fastmem_size > 0) {
+       write_log ("Z3 fast memory can't be used with a 68000/68010 emulation. It\n"
+                "requires a 68020 emulation. Turning off Z3 fast memory.\n");
+       currprefs.z3fastmem_size = 0;
+       err = 1;
+    }
+    if (currprefs.gfxmem_size > 0 && (currprefs.cpu_level < 2 || currprefs.address_space_24)) {
+       write_log ("Picasso96 can't be used with a 68000/68010 or 68EC020 emulation. It\n"
+                "requires a 68020 emulation. Turning off Picasso96.\n");
+       currprefs.gfxmem_size = 0;
+       err = 1;
+    }
+#ifndef BSDSOCKET
+    if (currprefs.socket_emu) {
+       write_log ("Compile-time option of BSDSOCKET_SUPPORTED was not enabled.  You can't use bsd-socket emulation.\n");
+       currprefs.socket_emu = 0;
+       err = 1;
+    }
+#endif
+
+    if (currprefs.nr_floppies < 0 || currprefs.nr_floppies > 4) {
+       write_log ("Invalid number of floppies.  Using 4.\n");
+       currprefs.nr_floppies = 4;
+       currprefs.dfxtype[0] = 0;
+       currprefs.dfxtype[1] = 0;
+       currprefs.dfxtype[2] = 0;
+       currprefs.dfxtype[3] = 0;
+       err = 1;
+    }
+
+    if (currprefs.floppy_speed > 0 && currprefs.floppy_speed < 10) {
+       currprefs.floppy_speed = 100;
+    }
+    if (currprefs.input_mouse_speed < 1 || currprefs.input_mouse_speed > 1000) {
+       currprefs.input_mouse_speed = 100;
+    }
+    if (currprefs.cpu_cycle_exact || currprefs.blitter_cycle_exact)
+       currprefs.fast_copper = 0;
+
+    if (currprefs.collision_level < 0 || currprefs.collision_level > 3) {
+       write_log ("Invalid collision support level.  Using 1.\n");
+       currprefs.collision_level = 1;
+       err = 1;
+    }
+    fixup_prefs_dimensions (&currprefs);
+
+#ifdef CPU_68000_ONLY
+    currprefs.cpu_level = 0;
+#endif
+#ifndef CPUEMU_0
+    currprefs.cpu_compatible = 1;
+    currprefs.address_space_24 = 1;
+#endif
+#if !defined(CPUEMU_5) && !defined (CPUEMU_6)
+    currprefs.cpu_compatible = 0;
+    currprefs.address_space_24 = 0;
+#endif
+#if !defined (CPUEMU_6)
+    currprefs.cpu_cycle_exact = currprefs.blitter_cycle_exact = 0;
+#endif
+#ifndef AGA
+    currprefs.chipset_mask &= ~CSMASK_AGA;
+#endif
+#ifndef AUTOCONFIG
+    currprefs.z3fastmem_size = 0;
+    currprefs.fastmem_size = 0;
+    currprefs.gfxmem_size = 0;
+#endif
+#if !defined (BSDSOCKET)
+    currprefs.socket_emu = 0;
+#endif
+#if !defined (SCSIEMU)
+    currprefs.scsi = 0;
+    currprefs.win32_aspi = 0;
+#endif
+
+    if (err)
+       write_log ("Please use \"uae -h\" to get usage information.\n");
+}
+
+int quit_program = 0;
+static int restart_program;
+static char restart_config[256];
+
+void uae_reset (int hardreset)
+{
+    if (quit_program == 0) {
+       quit_program = -2;
+       if (hardreset)
+           quit_program = -3;
+    }
+    
+}
+
+void uae_quit (void)
+{
+    if (quit_program != -1)
+       quit_program = -1;
+}
+
+void uae_restart (int opengui, char *cfgfile)
+{
+    uae_quit ();
+    restart_program = opengui ? 1 : 2;
+    restart_config[0] = 0;
+    if (cfgfile)
+       strcpy (restart_config, cfgfile);
+}
+
+const char *gameport_state (int nr)
+{
+    if (JSEM_ISJOY0 (nr, &currprefs) && inputdevice_get_device_total (IDTYPE_JOYSTICK) > 0)
+       return "using joystick #0";
+    else if (JSEM_ISJOY1 (nr, &currprefs) && inputdevice_get_device_total (IDTYPE_JOYSTICK) > 1)
+       return "using joystick #1";
+    else if (JSEM_ISMOUSE (nr, &currprefs))
+       return "using mouse";
+    else if (JSEM_ISNUMPAD (nr, &currprefs))
+       return "using numeric pad as joystick";
+    else if (JSEM_ISCURSOR (nr, &currprefs))
+       return "using cursor keys as joystick";
+    else if (JSEM_ISSOMEWHEREELSE (nr, &currprefs))
+       return "using T/F/H/B/Alt as joystick";
+
+    return "not connected";
+}
+
+#ifndef DONT_PARSE_CMDLINE
+
+void usage (void)
+{
+}
+static void parse_cmdline_2 (int argc, char **argv)
+{
+    int i;
+
+    cfgfile_addcfgparam (0);
+    for (i = 1; i < argc; i++) {
+       if (strcmp (argv[i], "-cfgparam") == 0) {
+           if (i + 1 == argc)
+               write_log ("Missing argument for '-cfgparam' option.\n");
+           else
+               cfgfile_addcfgparam (argv[++i]);
+       }
+    }
+}
+
+static void parse_cmdline (int argc, char **argv)
+{
+    int i;
+
+    for (i = 1; i < argc; i++) {
+       if (strcmp (argv[i], "-cfgparam") == 0) {
+           if (i + 1 < argc)
+               i++;
+       } else if (strncmp (argv[i], "-config=", 8) == 0) {
+#ifdef FILESYS
+            free_mountinfo (currprefs.mountinfo);
+            currprefs.mountinfo = alloc_mountinfo ();
+#endif
+           cfgfile_load (&currprefs, argv[i] + 8, 0);
+       }
+       /* Check for new-style "-f xxx" argument, where xxx is config-file */
+       else if (strcmp (argv[i], "-f") == 0) {
+           if (i + 1 == argc) {
+               write_log ("Missing argument for '-f' option.\n");
+           } else {
+#ifdef FILESYS
+                free_mountinfo (currprefs.mountinfo);
+               currprefs.mountinfo = alloc_mountinfo ();
+#endif
+               cfgfile_load (&currprefs, argv[++i], 0);
+           }
+       } else if (strcmp (argv[i], "-s") == 0) {
+           if (i + 1 == argc)
+               write_log ("Missing argument for '-s' option.\n");
+           else
+               cfgfile_parse_line (&currprefs, argv[++i], 0);
+       } else if (strcmp (argv[i], "-h") == 0 || strcmp (argv[i], "-help") == 0) {
+           usage ();
+           exit (0);
+       } else {
+           if (argv[i][0] == '-' && argv[i][1] != '\0') {
+               const char *arg = argv[i] + 2;
+               int extra_arg = *arg == '\0';
+               if (extra_arg)
+                   arg = i + 1 < argc ? argv[i + 1] : 0;
+               if (parse_cmdline_option (&currprefs, argv[i][1], (char*)arg) && extra_arg)
+                   i++;
+           }
+       }
+    }
+}
+#endif
+
+static void parse_cmdline_and_init_file (int argc, char **argv)
+{
+
+    strcpy (optionsfile, "");
+
+#ifdef OPTIONS_IN_HOME
+    {
+       char *home = getenv ("HOME");
+       if (home != NULL && strlen (home) < 240)
+       {
+           strcpy (optionsfile, home);
+           strcat (optionsfile, "/");
+       }
+    }
+#endif
+
+    parse_cmdline_2 (argc, argv);
+
+    strcat (optionsfile, restart_config);
+
+    if (! cfgfile_load (&currprefs, optionsfile, 0)) {
+       write_log ("failed to load config '%s'\n", optionsfile);
+#ifdef OPTIONS_IN_HOME
+       /* sam: if not found in $HOME then look in current directory */
+       strcpy (optionsfile, restart_config);
+       cfgfile_load (&currprefs, optionsfile);
+#endif
+    } else {
+       write_log ("loaded config '%s'\n", optionsfile);
+    }
+    fix_options ();
+
+    parse_cmdline (argc, argv);
+}
+
+void reset_all_systems (void)
+{
+    init_eventtab ();
+
+    memory_reset ();
+#ifdef BSDSOCKET
+    bsdlib_reset ();
+#endif
+#ifdef FILESYS
+    filesys_reset ();
+    filesys_start_threads ();
+    hardfile_reset ();
+#endif
+#ifdef SCSIEMU
+    scsidev_reset ();
+    scsidev_start_threads ();
+#endif
+}
+
+/* Okay, this stuff looks strange, but it is here to encourage people who
+ * port UAE to re-use as much of this code as possible. Functions that you
+ * should be using are do_start_program() and do_leave_program(), as well
+ * as real_main(). Some OSes don't call main() (which is braindamaged IMHO,
+ * but unfortunately very common), so you need to call real_main() from
+ * whatever entry point you have. You may want to write your own versions
+ * of start_program() and leave_program() if you need to do anything special.
+ * Add #ifdefs around these as appropriate.
+ */
+
+void do_start_program (void)
+{
+    /* Do a reset on startup. Whether this is elegant is debatable. */
+    inputdevice_updateconfig (&currprefs);
+    quit_program = 2;
+    m68k_go (1);
+}
+
+void do_leave_program (void)
+{
+    graphics_leave ();
+    inputdevice_close ();
+    DISK_free ();
+    close_sound ();
+    dump_counts ();
+#ifdef SERIAL_PORT
+    serial_exit ();
+#endif
+#ifdef CD32
+    akiko_free ();
+#endif
+    if (! no_gui)
+       gui_exit ();
+#ifdef USE_SDL
+    SDL_Quit ();
+#endif
+#ifdef AUTOCONFIG
+    expansion_cleanup ();
+#endif
+    savestate_free ();
+    memory_cleanup ();
+    cfgfile_addcfgparam (0);
+}
+
+void start_program (void)
+{
+    do_start_program ();
+}
+
+void leave_program (void)
+{
+    do_leave_program ();
+}
+
+static void real_main2 (int argc, char **argv)
+{
+#if defined (NATMEM_OFFSET) && defined( _WIN32 ) && !defined( NO_WIN32_EXCEPTION_HANDLER )
+    extern int EvalException ( LPEXCEPTION_POINTERS blah, int n_except );
+    __try
+#endif
+    {
+
+#ifdef USE_SDL
+    SDL_Init (SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_NOPARACHUTE);
+#endif
+
+    if (restart_config[0]) {
+#ifdef FILESYS
+       free_mountinfo (currprefs.mountinfo);
+        currprefs.mountinfo = alloc_mountinfo ();
+#endif
+       default_prefs (&currprefs, 0);
+       fix_options ();
+    }
+
+    if (! graphics_setup ()) {
+       exit (1);
+    }
+
+#ifdef JIT
+    init_shm();
+#endif
+
+#ifdef FILESYS
+    rtarea_init ();
+    hardfile_install ();
+#endif
+
+    if (restart_config[0])
+        parse_cmdline_and_init_file (argc, argv);
+    else
+       currprefs = changed_prefs;
+
+    machdep_init ();
+
+    if (! setup_sound ()) {
+       write_log ("Sound driver unavailable: Sound output disabled\n");
+       currprefs.produce_sound = 0;
+    }
+    inputdevice_init ();
+
+    changed_prefs = currprefs;
+    no_gui = ! currprefs.start_gui;
+    if (restart_program == 2)
+       no_gui = 1;
+    restart_program = 0;
+    if (! no_gui) {
+       int err = gui_init ();
+       struct uaedev_mount_info *mi = currprefs.mountinfo;
+       currprefs = changed_prefs;
+       currprefs.mountinfo = mi;
+       if (err == -1) {
+           write_log ("Failed to initialize the GUI\n");
+       } else if (err == -2) {
+           return;
+       }
+    }
+
+#ifdef JIT
+    if (!(( currprefs.cpu_level >= 2 ) && ( currprefs.address_space_24 == 0 ) && ( currprefs.cachesize )))
+       canbang = 0;
+#endif
+
+    logging_init(); /* Yes, we call this twice - the first case handles when the user has loaded
+                      a config using the cmd-line.  This case handles loads through the GUI. */
+    fix_options ();
+    changed_prefs = currprefs;
+
+    savestate_init ();
+#ifdef SCSIEMU
+    scsidev_install ();
+#endif
+#ifdef AUTOCONFIG
+    /* Install resident module to get 8MB chipmem, if requested */
+    rtarea_setup ();
+#endif
+
+    keybuf_init (); /* Must come after init_joystick */
+
+#ifdef AUTOCONFIG
+    expansion_init ();
+#endif
+    memory_init ();
+    memory_reset ();
+
+#ifdef FILESYS
+    filesys_install ();
+#endif
+#ifdef AUTOCONFIG
+    gfxlib_install ();
+    bsdlib_install ();
+    emulib_install ();
+    uaeexe_install ();
+    native2amiga_install ();
+#endif
+
+    custom_init (); /* Must come after memory_init */
+#ifdef SERIAL_PORT
+    serial_init ();
+#endif
+    DISK_init ();
+
+    reset_frame_rate_hack ();
+    init_m68k(); /* must come after reset_frame_rate_hack (); */
+
+    compiler_init ();
+    gui_update ();
+
+    if (graphics_init ()) {
+       setup_brkhandler ();
+       if (currprefs.start_debugger && debuggable ())
+           activate_debugger ();
+
+#ifdef WIN32
+#ifdef FILESYS
+       filesys_init (); /* New function, to do 'add_filesys_unit()' calls at start-up */
+#endif
+#endif
+       if (sound_available && currprefs.produce_sound > 1 && ! init_audio ()) {
+           write_log ("Sound driver unavailable: Sound output disabled\n");
+           currprefs.produce_sound = 0;
+       }
+
+       start_program ();
+    }
+
+    }
+#if defined (NATMEM_OFFSET) && defined( _WIN32 ) && !defined( NO_WIN32_EXCEPTION_HANDLER )
+    __except( EvalException( GetExceptionInformation(), GetExceptionCode() ) )
+    {
+       // EvalException does the good stuff...
+    }
+#endif
+}
+
+void real_main (int argc, char **argv)
+{
+    restart_program = 1;
+#ifdef _WIN32
+    sprintf (restart_config, "%sConfigurations\\", start_path);
+#endif
+    strcat (restart_config, OPTIONSFILENAME);
+    while (restart_program) {
+       changed_prefs = currprefs;
+       real_main2 (argc, argv);
+        leave_program ();
+       quit_program = 0;
+    }
+    zfile_exit ();
+}
+
+#ifndef NO_MAIN_IN_MAIN_C
+int main (int argc, char **argv)
+{
+    real_main (argc, argv);
+    return 0;
+}
+#endif
+
+#ifdef SINGLEFILE
+uae_u8 singlefile_config[50000] = { "_CONFIG_STARTS_HERE" };
+uae_u8 singlefile_data[1500000] = { "_DATA_STARTS_HERE" };
+#endif
diff --git a/memory.c b/memory.c
new file mode 100755 (executable)
index 0000000..1218c73
--- /dev/null
+++ b/memory.c
@@ -0,0 +1,1765 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Memory management
+  *
+  * (c) 1995 Bernd Schmidt
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "uae.h"
+#include "memory.h"
+#include "ersatz.h"
+#include "zfile.h"
+#include "custom.h"
+#include "events.h"
+#include "newcpu.h"
+#include "autoconf.h"
+#include "savestate.h"
+#include "ar.h"
+
+#ifdef USE_MAPPED_MEMORY
+#include <sys/mman.h>
+#endif
+
+#ifdef JIT
+int canbang;
+
+/* Set by each memory handler that does not simply access real memory.  */
+int special_mem;
+#endif
+
+int ersatzkickfile;
+
+#ifdef CD32
+extern int cd32_enabled;
+#endif
+#ifdef CDTV
+extern int cdtv_enabled;
+#endif
+
+uae_u32 allocated_chipmem;
+uae_u32 allocated_fastmem;
+uae_u32 allocated_bogomem;
+uae_u32 allocated_gfxmem;
+uae_u32 allocated_z3fastmem;
+uae_u32 allocated_a3000mem;
+
+static long chip_filepos;
+static long bogo_filepos;
+static long rom_filepos;
+
+addrbank *mem_banks[65536];
+
+/* This has two functions. It either holds a host address that, when added
+   to the 68k address, gives the host address corresponding to that 68k
+   address (in which case the value in this array is even), OR it holds the
+   same value as mem_banks, for those banks that have baseaddr==0. In that
+   case, bit 0 is set (the memory access routines will take care of it).  */
+
+uae_u8 *baseaddr[65536];
+
+#ifdef NO_INLINE_MEMORY_ACCESS
+__inline__ uae_u32 longget (uaecptr addr)
+{
+    return call_mem_get_func (get_mem_bank (addr).lget, addr);
+}
+__inline__ uae_u32 wordget (uaecptr addr)
+{
+    return call_mem_get_func (get_mem_bank (addr).wget, addr);
+}
+__inline__ uae_u32 byteget (uaecptr addr)
+{
+    return call_mem_get_func (get_mem_bank (addr).bget, addr);
+}
+__inline__ void longput (uaecptr addr, uae_u32 l)
+{
+    call_mem_put_func (get_mem_bank (addr).lput, addr, l);
+}
+__inline__ void wordput (uaecptr addr, uae_u32 w)
+{
+    call_mem_put_func (get_mem_bank (addr).wput, addr, w);
+}
+__inline__ void byteput (uaecptr addr, uae_u32 b)
+{
+    call_mem_put_func (get_mem_bank (addr).bput, addr, b);
+}
+#endif
+
+uae_u32 chipmem_mask, kickmem_mask, extendedkickmem_mask, bogomem_mask, a3000mem_mask;
+
+static int illegal_count;
+/* A dummy bank that only contains zeros */
+
+static uae_u32 dummy_lget (uaecptr) REGPARAM;
+static uae_u32 dummy_wget (uaecptr) REGPARAM;
+static uae_u32 dummy_bget (uaecptr) REGPARAM;
+static void dummy_lput (uaecptr, uae_u32) REGPARAM;
+static void dummy_wput (uaecptr, uae_u32) REGPARAM;
+static void dummy_bput (uaecptr, uae_u32) REGPARAM;
+static int dummy_check (uaecptr addr, uae_u32 size) REGPARAM;
+
+#define MAX_ILG 20
+
+uae_u32 REGPARAM2 dummy_lget (uaecptr addr)
+{
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+    if (currprefs.illegal_mem) {
+       if (illegal_count < MAX_ILG) {
+           illegal_count++;
+           write_log ("Illegal lget at %08lx\n", addr);
+       }
+    }
+    if (currprefs.cpu_level >= 2)
+       return 0;
+    return (regs.irc << 16) | regs.irc;
+}
+
+uae_u32 REGPARAM2 dummy_wget (uaecptr addr)
+{
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+    if (currprefs.illegal_mem) {
+       if (illegal_count < MAX_ILG) {
+           illegal_count++;
+           write_log ("Illegal wget at %08lx\n", addr);
+       }
+    }
+    if (currprefs.cpu_level >= 2)
+       return 0;
+    return regs.irc;
+}
+
+uae_u32 REGPARAM2 dummy_bget (uaecptr addr)
+{
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+    if (currprefs.illegal_mem) {
+       if (illegal_count < MAX_ILG) {
+           illegal_count++;
+           write_log ("Illegal bget at %08lx\n", addr);
+       }
+    }
+    if (currprefs.cpu_level >= 2)
+       return 0;
+    return (addr & 1) ? regs.irc : regs.irc >> 8;
+}
+
+void REGPARAM2 dummy_lput (uaecptr addr, uae_u32 l)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif 
+   if (currprefs.illegal_mem) {
+       if (illegal_count < MAX_ILG) {
+           illegal_count++;
+           write_log ("Illegal lput at %08lx\n", addr);
+       }
+    }
+}
+void REGPARAM2 dummy_wput (uaecptr addr, uae_u32 w)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    if (currprefs.illegal_mem) {
+       if (illegal_count < MAX_ILG) {
+           illegal_count++;
+           write_log ("Illegal wput at %08lx\n", addr);
+       }
+    }
+}
+void REGPARAM2 dummy_bput (uaecptr addr, uae_u32 b)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    if (currprefs.illegal_mem) {
+       if (illegal_count < MAX_ILG) {
+           illegal_count++;
+           write_log ("Illegal bput at %08lx\n", addr);
+       }
+    }
+}
+
+int REGPARAM2 dummy_check (uaecptr addr, uae_u32 size)
+{
+#ifdef JIT
+    special_mem |= S_READ;
+#endif
+    if (currprefs.illegal_mem) {
+       if (illegal_count < MAX_ILG) {
+           illegal_count++;
+           write_log ("Illegal check at %08lx\n", addr);
+       }
+    }
+
+    return 0;
+}
+
+#ifdef AUTOCONFIG
+
+/* A3000 "motherboard resources" bank.  */
+static uae_u32 mbres_lget (uaecptr) REGPARAM;
+static uae_u32 mbres_wget (uaecptr) REGPARAM;
+static uae_u32 mbres_bget (uaecptr) REGPARAM;
+static void mbres_lput (uaecptr, uae_u32) REGPARAM;
+static void mbres_wput (uaecptr, uae_u32) REGPARAM;
+static void mbres_bput (uaecptr, uae_u32) REGPARAM;
+static int mbres_check (uaecptr addr, uae_u32 size) REGPARAM;
+
+static int mbres_val = 0;
+
+uae_u32 REGPARAM2 mbres_lget (uaecptr addr)
+{
+    special_mem |= S_READ;
+    if (currprefs.illegal_mem)
+       write_log ("Illegal lget at %08lx\n", addr);
+
+    return 0;
+}
+
+uae_u32 REGPARAM2 mbres_wget (uaecptr addr)
+{
+    special_mem |= S_READ;
+    if (currprefs.illegal_mem)
+       write_log ("Illegal wget at %08lx\n", addr);
+
+    return 0;
+}
+
+uae_u32 REGPARAM2 mbres_bget (uaecptr addr)
+{
+    special_mem |= S_READ;
+    if (currprefs.illegal_mem)
+       write_log ("Illegal bget at %08lx\n", addr);
+
+    return (addr & 0xFFFF) == 3 ? mbres_val : 0;
+}
+
+void REGPARAM2 mbres_lput (uaecptr addr, uae_u32 l)
+{
+    special_mem |= S_WRITE;
+    if (currprefs.illegal_mem)
+       write_log ("Illegal lput at %08lx\n", addr);
+}
+void REGPARAM2 mbres_wput (uaecptr addr, uae_u32 w)
+{
+    special_mem |= S_WRITE;
+    if (currprefs.illegal_mem)
+       write_log ("Illegal wput at %08lx\n", addr);
+}
+void REGPARAM2 mbres_bput (uaecptr addr, uae_u32 b)
+{
+    special_mem |= S_WRITE;
+    if (currprefs.illegal_mem)
+       write_log ("Illegal bput at %08lx\n", addr);
+
+    if ((addr & 0xFFFF) == 3)
+       mbres_val = b;
+}
+
+int REGPARAM2 mbres_check (uaecptr addr, uae_u32 size)
+{
+    if (currprefs.illegal_mem)
+       write_log ("Illegal check at %08lx\n", addr);
+
+    return 0;
+}
+
+#endif
+
+/* Chip memory */
+
+uae_u8 *chipmemory;
+
+static int chipmem_check (uaecptr addr, uae_u32 size) REGPARAM;
+static uae_u8 *chipmem_xlate (uaecptr addr) REGPARAM;
+
+#ifdef AGA
+
+/* AGA ce-chipram access */
+
+static void ce2_timeout (void)
+{
+    wait_cpu_cycle_read (0, -1);
+}
+
+uae_u32 REGPARAM2 chipmem_lget_ce2 (uaecptr addr)
+{
+    uae_u32 *m;
+
+    special_mem |= S_READ;
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    m = (uae_u32 *)(chipmemory + addr);
+    ce2_timeout ();
+    return do_get_mem_long (m);
+}
+
+uae_u32 REGPARAM2 chipmem_wget_ce2 (uaecptr addr)
+{
+    uae_u16 *m;
+
+    special_mem |= S_READ;
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    m = (uae_u16 *)(chipmemory + addr);
+    ce2_timeout ();
+    return do_get_mem_word (m);
+}
+
+uae_u32 REGPARAM2 chipmem_bget_ce2 (uaecptr addr)
+{
+    special_mem |= S_READ;
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    ce2_timeout ();
+    return chipmemory[addr];
+}
+
+void REGPARAM2 chipmem_lput_ce2 (uaecptr addr, uae_u32 l)
+{
+    uae_u32 *m;
+
+    special_mem |= S_WRITE;
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    m = (uae_u32 *)(chipmemory + addr);
+    ce2_timeout ();
+    do_put_mem_long (m, l);
+}
+
+void REGPARAM2 chipmem_wput_ce2 (uaecptr addr, uae_u32 w)
+{
+    uae_u16 *m;
+
+    special_mem |= S_WRITE;
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    m = (uae_u16 *)(chipmemory + addr);
+    ce2_timeout ();
+    do_put_mem_word (m, w);
+}
+
+void REGPARAM2 chipmem_bput_ce2 (uaecptr addr, uae_u32 b)
+{
+    special_mem |= S_WRITE;
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    ce2_timeout ();
+    chipmemory[addr] = b;
+}
+
+#endif
+
+uae_u32 REGPARAM2 chipmem_lget (uaecptr addr)
+{
+    uae_u32 *m;
+
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    m = (uae_u32 *)(chipmemory + addr);
+    return do_get_mem_long (m);
+}
+
+uae_u32 REGPARAM2 chipmem_wget (uaecptr addr)
+{
+    uae_u16 *m;
+
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    m = (uae_u16 *)(chipmemory + addr);
+    return do_get_mem_word (m);
+}
+
+uae_u32 REGPARAM2 chipmem_bget (uaecptr addr)
+{
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    return chipmemory[addr];
+}
+
+void REGPARAM2 chipmem_lput (uaecptr addr, uae_u32 l)
+{
+    uae_u32 *m;
+
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    m = (uae_u32 *)(chipmemory + addr);
+    do_put_mem_long (m, l);
+}
+
+
+void REGPARAM2 chipmem_wput (uaecptr addr, uae_u32 w)
+{
+    uae_u16 *m;
+
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    m = (uae_u16 *)(chipmemory + addr);
+    do_put_mem_word (m, w);
+}
+
+void REGPARAM2 chipmem_bput (uaecptr addr, uae_u32 b)
+{
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    chipmemory[addr] = b;
+}
+
+int REGPARAM2 chipmem_check (uaecptr addr, uae_u32 size)
+{
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    return (addr + size) <= allocated_chipmem;
+}
+
+uae_u8 REGPARAM2 *chipmem_xlate (uaecptr addr)
+{
+    addr -= chipmem_start & chipmem_mask;
+    addr &= chipmem_mask;
+    return chipmemory + addr;
+}
+
+/* Slow memory */
+
+static uae_u8 *bogomemory;
+
+static uae_u32 bogomem_lget (uaecptr) REGPARAM;
+static uae_u32 bogomem_wget (uaecptr) REGPARAM;
+static uae_u32 bogomem_bget (uaecptr) REGPARAM;
+static void bogomem_lput (uaecptr, uae_u32) REGPARAM;
+static void bogomem_wput (uaecptr, uae_u32) REGPARAM;
+static void bogomem_bput (uaecptr, uae_u32) REGPARAM;
+static int bogomem_check (uaecptr addr, uae_u32 size) REGPARAM;
+static uae_u8 *bogomem_xlate (uaecptr addr) REGPARAM;
+
+uae_u32 REGPARAM2 bogomem_lget (uaecptr addr)
+{
+    uae_u32 *m;
+    addr -= bogomem_start & bogomem_mask;
+    addr &= bogomem_mask;
+    m = (uae_u32 *)(bogomemory + addr);
+    return do_get_mem_long (m);
+}
+
+uae_u32 REGPARAM2 bogomem_wget (uaecptr addr)
+{
+    uae_u16 *m;
+    addr -= bogomem_start & bogomem_mask;
+    addr &= bogomem_mask;
+    m = (uae_u16 *)(bogomemory + addr);
+    return do_get_mem_word (m);
+}
+
+uae_u32 REGPARAM2 bogomem_bget (uaecptr addr)
+{
+    addr -= bogomem_start & bogomem_mask;
+    addr &= bogomem_mask;
+    return bogomemory[addr];
+}
+
+void REGPARAM2 bogomem_lput (uaecptr addr, uae_u32 l)
+{
+    uae_u32 *m;
+    addr -= bogomem_start & bogomem_mask;
+    addr &= bogomem_mask;
+    m = (uae_u32 *)(bogomemory + addr);
+    do_put_mem_long (m, l);
+}
+
+void REGPARAM2 bogomem_wput (uaecptr addr, uae_u32 w)
+{
+    uae_u16 *m;
+    addr -= bogomem_start & bogomem_mask;
+    addr &= bogomem_mask;
+    m = (uae_u16 *)(bogomemory + addr);
+    do_put_mem_word (m, w);
+}
+
+void REGPARAM2 bogomem_bput (uaecptr addr, uae_u32 b)
+{
+    addr -= bogomem_start & bogomem_mask;
+    addr &= bogomem_mask;
+    bogomemory[addr] = b;
+}
+
+int REGPARAM2 bogomem_check (uaecptr addr, uae_u32 size)
+{
+    addr -= bogomem_start & bogomem_mask;
+    addr &= bogomem_mask;
+    return (addr + size) <= allocated_bogomem;
+}
+
+uae_u8 REGPARAM2 *bogomem_xlate (uaecptr addr)
+{
+    addr -= bogomem_start & bogomem_mask;
+    addr &= bogomem_mask;
+    return bogomemory + addr;
+}
+
+#ifdef AUTOCONFIG
+
+/* A3000 motherboard fast memory */
+
+static uae_u8 *a3000memory;
+
+static uae_u32 a3000mem_lget (uaecptr) REGPARAM;
+static uae_u32 a3000mem_wget (uaecptr) REGPARAM;
+static uae_u32 a3000mem_bget (uaecptr) REGPARAM;
+static void a3000mem_lput (uaecptr, uae_u32) REGPARAM;
+static void a3000mem_wput (uaecptr, uae_u32) REGPARAM;
+static void a3000mem_bput (uaecptr, uae_u32) REGPARAM;
+static int a3000mem_check (uaecptr addr, uae_u32 size) REGPARAM;
+static uae_u8 *a3000mem_xlate (uaecptr addr) REGPARAM;
+
+uae_u32 REGPARAM2 a3000mem_lget (uaecptr addr)
+{
+    uae_u32 *m;
+    addr -= a3000mem_start & a3000mem_mask;
+    addr &= a3000mem_mask;
+    m = (uae_u32 *)(a3000memory + addr);
+    return do_get_mem_long (m);
+}
+
+uae_u32 REGPARAM2 a3000mem_wget (uaecptr addr)
+{
+    uae_u16 *m;
+    addr -= a3000mem_start & a3000mem_mask;
+    addr &= a3000mem_mask;
+    m = (uae_u16 *)(a3000memory + addr);
+    return do_get_mem_word (m);
+}
+
+uae_u32 REGPARAM2 a3000mem_bget (uaecptr addr)
+{
+    addr -= a3000mem_start & a3000mem_mask;
+    addr &= a3000mem_mask;
+    return a3000memory[addr];
+}
+
+void REGPARAM2 a3000mem_lput (uaecptr addr, uae_u32 l)
+{
+    uae_u32 *m;
+    addr -= a3000mem_start & a3000mem_mask;
+    addr &= a3000mem_mask;
+    m = (uae_u32 *)(a3000memory + addr);
+    do_put_mem_long (m, l);
+}
+
+void REGPARAM2 a3000mem_wput (uaecptr addr, uae_u32 w)
+{
+    uae_u16 *m;
+    addr -= a3000mem_start & a3000mem_mask;
+    addr &= a3000mem_mask;
+    m = (uae_u16 *)(a3000memory + addr);
+    do_put_mem_word (m, w);
+}
+
+void REGPARAM2 a3000mem_bput (uaecptr addr, uae_u32 b)
+{
+    addr -= a3000mem_start & a3000mem_mask;
+    addr &= a3000mem_mask;
+    a3000memory[addr] = b;
+}
+
+int REGPARAM2 a3000mem_check (uaecptr addr, uae_u32 size)
+{
+    addr -= a3000mem_start & a3000mem_mask;
+    addr &= a3000mem_mask;
+    return (addr + size) <= allocated_a3000mem;
+}
+
+uae_u8 REGPARAM2 *a3000mem_xlate (uaecptr addr)
+{
+    addr -= a3000mem_start & a3000mem_mask;
+    addr &= a3000mem_mask;
+    return a3000memory + addr;
+}
+
+#endif
+
+/* Kick memory */
+
+uae_u8 *kickmemory;
+uae_u16 kickstart_version;
+
+/*
+ * A1000 kickstart RAM handling
+ *
+ * RESET instruction unhides boot ROM and disables write protection
+ * write access to boot ROM hides boot ROM and enables write protection
+ *
+ */
+static int a1000_kickstart_mode;
+static uae_u8 *a1000_bootrom;
+static void a1000_handle_kickstart (int mode)
+{
+    if (mode == 0) {
+       a1000_kickstart_mode = 0;
+       memcpy (kickmemory, kickmemory + 262144, 262144);
+    } else {
+       a1000_kickstart_mode = 1;
+       memset (kickmemory, 0, 262144);
+       memcpy (kickmemory, a1000_bootrom, 65536);
+       memcpy (kickmemory + 131072, a1000_bootrom, 65536);
+        kickstart_version = 0;
+    }
+    kickstart_version = (kickmemory[262144 + 12] << 8) | kickmemory[262144 + 13];
+}
+
+void a1000_reset (void)
+{
+    if (a1000_bootrom)
+       a1000_handle_kickstart (1);
+}
+
+static uae_u32 kickmem_lget (uaecptr) REGPARAM;
+static uae_u32 kickmem_wget (uaecptr) REGPARAM;
+static uae_u32 kickmem_bget (uaecptr) REGPARAM;
+static void kickmem_lput (uaecptr, uae_u32) REGPARAM;
+static void kickmem_wput (uaecptr, uae_u32) REGPARAM;
+static void kickmem_bput (uaecptr, uae_u32) REGPARAM;
+static int kickmem_check (uaecptr addr, uae_u32 size) REGPARAM;
+static uae_u8 *kickmem_xlate (uaecptr addr) REGPARAM;
+
+uae_u32 REGPARAM2 kickmem_lget (uaecptr addr)
+{
+    uae_u32 *m;
+    addr -= kickmem_start & kickmem_mask;
+    addr &= kickmem_mask;
+    m = (uae_u32 *)(kickmemory + addr);
+    return do_get_mem_long (m);
+}
+
+uae_u32 REGPARAM2 kickmem_wget (uaecptr addr)
+{
+    uae_u16 *m;
+    addr -= kickmem_start & kickmem_mask;
+    addr &= kickmem_mask;
+    m = (uae_u16 *)(kickmemory + addr);
+    return do_get_mem_word (m);
+}
+
+uae_u32 REGPARAM2 kickmem_bget (uaecptr addr)
+{
+    addr -= kickmem_start & kickmem_mask;
+    addr &= kickmem_mask;
+    return kickmemory[addr];
+}
+
+void REGPARAM2 kickmem_lput (uaecptr addr, uae_u32 b)
+{
+    uae_u32 *m;
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    if (a1000_kickstart_mode) {
+       if (addr >= 0xfc0000) {
+           addr -= kickmem_start & kickmem_mask;
+           addr &= kickmem_mask;
+           m = (uae_u32 *)(kickmemory + addr);
+           do_put_mem_long (m, b);
+           return;
+       } else
+           a1000_handle_kickstart (0);
+    } else if (currprefs.illegal_mem)
+       write_log ("Illegal kickmem lput at %08lx\n", addr);
+}
+
+void REGPARAM2 kickmem_wput (uaecptr addr, uae_u32 b)
+{
+    uae_u16 *m;
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    if (a1000_kickstart_mode) {
+       if (addr >= 0xfc0000) {
+           addr -= kickmem_start & kickmem_mask;
+           addr &= kickmem_mask;
+           m = (uae_u16 *)(kickmemory + addr);
+           do_put_mem_word (m, b);
+           return;
+       } else
+           a1000_handle_kickstart (0);
+    } else if (currprefs.illegal_mem)
+       write_log ("Illegal kickmem wput at %08lx\n", addr);
+}
+
+void REGPARAM2 kickmem_bput (uaecptr addr, uae_u32 b)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    if (a1000_kickstart_mode) {
+       if (addr >= 0xfc0000) {
+           addr -= kickmem_start & kickmem_mask;
+           addr &= kickmem_mask;
+           kickmemory[addr] = b;
+           return;
+       } else
+           a1000_handle_kickstart (0);
+    } else if (currprefs.illegal_mem)
+       write_log ("Illegal kickmem lput at %08lx\n", addr);
+}
+
+void REGPARAM2 kickmem2_lput (uaecptr addr, uae_u32 l)
+{
+    uae_u32 *m;
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    addr -= kickmem_start & kickmem_mask;
+    addr &= kickmem_mask;
+    m = (uae_u32 *)(kickmemory + addr);
+    do_put_mem_long (m, l);
+}
+
+void REGPARAM2 kickmem2_wput (uaecptr addr, uae_u32 w)
+{
+    uae_u16 *m;
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    addr -= kickmem_start & kickmem_mask;
+    addr &= kickmem_mask;
+    m = (uae_u16 *)(kickmemory + addr);
+    do_put_mem_word (m, w);
+}
+
+void REGPARAM2 kickmem2_bput (uaecptr addr, uae_u32 b)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    addr -= kickmem_start & kickmem_mask;
+    addr &= kickmem_mask;
+    kickmemory[addr] = b;
+}
+
+int REGPARAM2 kickmem_check (uaecptr addr, uae_u32 size)
+{
+    addr -= kickmem_start & kickmem_mask;
+    addr &= kickmem_mask;
+    return (addr + size) <= kickmem_size;
+}
+
+uae_u8 REGPARAM2 *kickmem_xlate (uaecptr addr)
+{
+    addr -= kickmem_start & kickmem_mask;
+    addr &= kickmem_mask;
+    return kickmemory + addr;
+}
+
+/* CD32/CDTV extended kick memory */
+
+uae_u8 *extendedkickmemory;
+static int extendedkickmem_size;
+static uae_u32 extendedkickmem_start;
+
+#define EXTENDED_ROM_CD32 1
+#define EXTENDED_ROM_CDTV 2
+
+static int extromtype (void)
+{
+    switch (extendedkickmem_size) {
+    case 524288:
+       return EXTENDED_ROM_CD32;
+    case 262144:
+       return EXTENDED_ROM_CDTV;
+    }
+    return 0;
+}
+
+static uae_u32 extendedkickmem_lget (uaecptr) REGPARAM;
+static uae_u32 extendedkickmem_wget (uaecptr) REGPARAM;
+static uae_u32 extendedkickmem_bget (uaecptr) REGPARAM;
+static void extendedkickmem_lput (uaecptr, uae_u32) REGPARAM;
+static void extendedkickmem_wput (uaecptr, uae_u32) REGPARAM;
+static void extendedkickmem_bput (uaecptr, uae_u32) REGPARAM;
+static int extendedkickmem_check (uaecptr addr, uae_u32 size) REGPARAM;
+static uae_u8 *extendedkickmem_xlate (uaecptr addr) REGPARAM;
+
+uae_u32 REGPARAM2 extendedkickmem_lget (uaecptr addr)
+{
+    uae_u32 *m;
+    addr -= extendedkickmem_start & extendedkickmem_mask;
+    addr &= extendedkickmem_mask;
+    m = (uae_u32 *)(extendedkickmemory + addr);
+    return do_get_mem_long (m);
+}
+
+uae_u32 REGPARAM2 extendedkickmem_wget (uaecptr addr)
+{
+    uae_u16 *m;
+    addr -= extendedkickmem_start & extendedkickmem_mask;
+    addr &= extendedkickmem_mask;
+    m = (uae_u16 *)(extendedkickmemory + addr);
+    return do_get_mem_word (m);
+}
+
+uae_u32 REGPARAM2 extendedkickmem_bget (uaecptr addr)
+{
+    addr -= extendedkickmem_start & extendedkickmem_mask;
+    addr &= extendedkickmem_mask;
+    return extendedkickmemory[addr];
+}
+
+void REGPARAM2 extendedkickmem_lput (uaecptr addr, uae_u32 b)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    if (currprefs.illegal_mem)
+       write_log ("Illegal extendedkickmem lput at %08lx\n", addr);
+}
+
+void REGPARAM2 extendedkickmem_wput (uaecptr addr, uae_u32 b)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    if (currprefs.illegal_mem)
+       write_log ("Illegal extendedkickmem wput at %08lx\n", addr);
+}
+
+void REGPARAM2 extendedkickmem_bput (uaecptr addr, uae_u32 b)
+{
+#ifdef JIT
+    special_mem |= S_WRITE;
+#endif
+    if (currprefs.illegal_mem)
+       write_log ("Illegal extendedkickmem lput at %08lx\n", addr);
+}
+
+int REGPARAM2 extendedkickmem_check (uaecptr addr, uae_u32 size)
+{
+    addr -= extendedkickmem_start & extendedkickmem_mask;
+    addr &= extendedkickmem_mask;
+    return (addr + size) <= extendedkickmem_size;
+}
+
+uae_u8 REGPARAM2 *extendedkickmem_xlate (uaecptr addr)
+{
+    addr -= extendedkickmem_start & extendedkickmem_mask;
+    addr &= extendedkickmem_mask;
+    return extendedkickmemory + addr;
+}
+
+/* Default memory access functions */
+
+int REGPARAM2 default_check (uaecptr a, uae_u32 b)
+{
+    return 0;
+}
+
+static int be_cnt;
+
+uae_u8 REGPARAM2 *default_xlate (uaecptr a)
+{
+    if (quit_program == 0) {
+       /* do this only in 68010+ mode, there are some tricky A500 programs.. */
+       if (currprefs.cpu_level > 0 || !currprefs.cpu_compatible) {
+           if (be_cnt < 3) {
+               int i, j;
+               uaecptr a2 = a - 32;
+               uaecptr a3 = m68k_getpc() - 32;
+               write_log ("Your Amiga program just did something terribly stupid %p PC=%p\n", a, m68k_getpc());
+               m68k_dumpstate (0, 0);
+               for (i = 0; i < 10; i++) {
+                   write_log ("%08.8X ", i >= 5 ? a3 : a2);
+                   for (j = 0; j < 16; j += 2) {
+                       write_log (" %04.4X", get_word (i >= 5 ? a3 : a2));
+                       if (i >= 5) a3 +=2; else a2 += 2;
+                   }
+                   write_log ("\n");
+               }
+           }
+           be_cnt++;
+           if (be_cnt > 1000) {
+               uae_reset (0);
+               be_cnt = 0;
+           } else {
+               regs.panic = 1;
+               regs.panic_pc = m68k_getpc ();
+               regs.panic_addr = a;
+               set_special (SPCFLAG_BRK);
+           }
+       }
+    }
+    return kickmem_xlate (0);  /* So we don't crash. */
+}
+
+/* Address banks */
+
+addrbank dummy_bank = {
+    dummy_lget, dummy_wget, dummy_bget,
+    dummy_lput, dummy_wput, dummy_bput,
+    default_xlate, dummy_check, NULL
+};
+
+#ifdef AUTOCONFIG
+addrbank mbres_bank = {
+    mbres_lget, mbres_wget, mbres_bget,
+    mbres_lput, mbres_wput, mbres_bput,
+    default_xlate, mbres_check, NULL
+};
+#endif
+
+addrbank chipmem_bank = {
+    chipmem_lget, chipmem_wget, chipmem_bget,
+    chipmem_lput, chipmem_wput, chipmem_bput,
+    chipmem_xlate, chipmem_check, NULL
+};
+
+#ifdef AGA
+addrbank chipmem_bank_ce2 = {
+    chipmem_lget_ce2, chipmem_wget_ce2, chipmem_bget_ce2,
+    chipmem_lput_ce2, chipmem_wput_ce2, chipmem_bput_ce2,
+    chipmem_xlate, chipmem_check, NULL
+};
+#endif
+
+addrbank bogomem_bank = {
+    bogomem_lget, bogomem_wget, bogomem_bget,
+    bogomem_lput, bogomem_wput, bogomem_bput,
+    bogomem_xlate, bogomem_check, NULL
+};
+
+#ifdef AUTOCONFIG
+addrbank a3000mem_bank = {
+    a3000mem_lget, a3000mem_wget, a3000mem_bget,
+    a3000mem_lput, a3000mem_wput, a3000mem_bput,
+    a3000mem_xlate, a3000mem_check, NULL
+};
+#endif
+
+addrbank kickmem_bank = {
+    kickmem_lget, kickmem_wget, kickmem_bget,
+    kickmem_lput, kickmem_wput, kickmem_bput,
+    kickmem_xlate, kickmem_check, NULL
+};
+
+addrbank kickram_bank = {
+    kickmem_lget, kickmem_wget, kickmem_bget,
+    kickmem2_lput, kickmem2_wput, kickmem2_bput,
+    kickmem_xlate, kickmem_check, NULL
+};
+
+addrbank extendedkickmem_bank = {
+    extendedkickmem_lget, extendedkickmem_wget, extendedkickmem_bget,
+    extendedkickmem_lput, extendedkickmem_wput, extendedkickmem_bput,
+    extendedkickmem_xlate, extendedkickmem_check, NULL
+};
+
+static int decode_cloanto_rom (uae_u8 *mem, int size, int real_size)
+{
+    struct zfile *keyf;
+    uae_u8 *p;
+    long cnt, t;
+    int keysize;
+
+    if (strlen (currprefs.keyfile) == 0) {
+#ifndef SINGLEFILE
+       gui_message ("No filename given for ROM key file and ROM image is an encrypted \"Amiga Forever\" ROM file.\n");
+#endif
+       return 0;
+    } else {
+       keyf = zfile_fopen (currprefs.keyfile, "rb");
+        if (keyf == 0)  {
+            keyf = zfile_fopen( "..\\shared\\rom\\rom.key", "rb" );
+            if( keyf == 0 )
+            {
+#ifndef SINGLEFILE
+                gui_message ("Could not find specified ROM key-file.\n");
+#endif
+               return 0;
+            }
+       }
+       p = (uae_u8 *)xmalloc (524288);
+       keysize = zfile_fread (p, 1, 524288, keyf);
+       for (t = cnt = 0; cnt < size; cnt++, t = (t + 1) % keysize)  {
+           mem[cnt] ^= p[t];
+           if (real_size == cnt + 1)
+               t = keysize - 1;
+       }
+       zfile_fclose (keyf);
+       free (p);
+    }
+    return 1;
+}
+
+static int kickstart_checksum (uae_u8 *mem, int size)
+{
+    uae_u32 cksum = 0, prevck = 0;
+    int i;
+    for (i = 0; i < size; i+=4) {
+       uae_u32 data = mem[i]*65536*256 + mem[i+1]*65536 + mem[i+2]*256 + mem[i+3];
+       cksum += data;
+       if (cksum < prevck)
+           cksum++;
+       prevck = cksum;
+    }
+#ifndef SINGLEFILE
+    if (cksum != 0xFFFFFFFFul)
+       gui_message("Kickstart checksum incorrect. You probably have a corrupted ROM image.\n");
+#endif
+    return 0;
+}
+
+static int read_kickstart (struct zfile *f, uae_u8 *mem, int size, int dochecksum, int *cloanto_rom)
+{
+    unsigned char buffer[20];
+    int i, cr = 0;
+
+    if (cloanto_rom)
+       *cloanto_rom = 0;
+    i = zfile_fread (buffer, 1, 11, f);
+    if (strncmp ((char *)buffer, "AMIROMTYPE1", 11) != 0) {
+       zfile_fseek (f, 0, SEEK_SET);
+    } else {
+       cr = 1;
+    }
+
+    i = zfile_fread (mem, 1, size, f);
+    if (i == size/2) {
+       memcpy (mem + size/2, mem, i);
+    } else if ((i != 8192 && i != 65536) && i != size) {
+       gui_message ("Error while reading Kickstart.\n");
+        zfile_fclose (f);
+       return 0;
+    }
+    zfile_fclose (f);
+
+    if (cr)
+       decode_cloanto_rom (mem, size, i);
+    if (i == 8192 || i == 65536) {
+        a1000_bootrom = malloc (65536);
+        memcpy (a1000_bootrom, kickmemory, 65536);
+        a1000_handle_kickstart (1);
+    }
+    if (dochecksum && i >= 262144)
+       kickstart_checksum (mem, size);
+    if (cloanto_rom)
+       *cloanto_rom = cr;
+    return 1;
+}
+
+static int load_extendedkickstart (void)
+{
+    struct zfile *f;
+    int size;
+
+    if (strlen(currprefs.romextfile) == 0)
+       return 0;
+    f = zfile_fopen (currprefs.romextfile, "rb");
+    if (!f) {
+       gui_message("No extended Kickstart ROM found");
+       return 0;
+    }
+    zfile_fseek (f, 0, SEEK_END);
+    size = zfile_ftell (f);
+    if (size > 300000)
+       extendedkickmem_size = 524288;
+    else
+       extendedkickmem_size = 262144;
+    zfile_fseek (f, 0, SEEK_SET);
+    switch (extromtype ()) {
+
+    case EXTENDED_ROM_CDTV:
+       extendedkickmemory = (uae_u8 *) mapped_malloc (extendedkickmem_size, "rom_f0");
+       extendedkickmem_bank.baseaddr = (uae_u8 *) extendedkickmemory;
+       break;
+    case EXTENDED_ROM_CD32:
+       extendedkickmemory = (uae_u8 *) mapped_malloc (extendedkickmem_size, "rom_e0");
+       extendedkickmem_bank.baseaddr = (uae_u8 *) extendedkickmemory;
+       break;
+    }
+    read_kickstart (f, extendedkickmemory, extendedkickmem_size,  0, 0);
+    extendedkickmem_mask = extendedkickmem_size - 1;
+    return 1;
+}
+
+static void kickstart_fix_checksum (uae_u8 *mem, int size)
+{
+    uae_u32 cksum = 0, prevck = 0;
+    int i, ch = size == 524288 ? 0x7ffe8 : 0x3e;
+    
+    mem[ch] = 0;
+    mem[ch + 1] = 0;
+    mem[ch + 2] = 0;
+    mem[ch + 3] = 0;
+    for (i = 0; i < size; i+=4) {
+       uae_u32 data = (mem[i] << 24) | (mem[i + 1] << 16) | (mem[i + 2] << 8) | mem[i + 3];
+       cksum += data;
+       if (cksum < prevck)
+           cksum++;
+       prevck = cksum;
+    }
+    cksum ^= 0xffffffff;
+    mem[ch++] = cksum >> 24;
+    mem[ch++] = cksum >> 16;
+    mem[ch++] = cksum >> 8;
+    mem[ch++] = cksum >> 0;
+}
+
+static int load_kickstart (void)
+{
+    struct zfile *f = zfile_fopen (currprefs.romfile, "rb");
+    char tmprom[512], tmpkey[512];
+
+    strcpy (tmprom, currprefs.romfile);
+    strcpy (tmpkey, currprefs.keyfile);
+    if (f == NULL) {
+       strcpy (currprefs.romfile, "roms/kick.rom");
+       f = zfile_fopen (currprefs.romfile, "rb");
+       if (f == NULL) {
+           strcpy( currprefs.romfile, "kick.rom" );
+           f = zfile_fopen( currprefs.romfile, "rb" );
+           if (f == NULL) {
+               strcpy( currprefs.romfile, "..\\shared\\rom\\kick.rom" );
+               f = zfile_fopen( currprefs.romfile, "rb" );
+           }
+        }
+    }
+    if( f == NULL ) { /* still no luck */
+#if defined(AMIGA)||defined(__POS__)
+#define USE_UAE_ERSATZ "USE_UAE_ERSATZ"
+       if( !getenv(USE_UAE_ERSATZ)) 
+        {
+           write_log ("Using current ROM. (create ENV:%s to "
+               "use uae's ROM replacement)\n",USE_UAE_ERSATZ);
+           memcpy(kickmemory,(char*)0x1000000-kickmem_size,kickmem_size);
+           kickstart_checksum (kickmemory, kickmem_size);
+           goto chk_sum;
+       }
+#else
+       goto err;
+#endif
+    }
+
+    if (f != NULL) {
+       if (!read_kickstart (f, kickmemory, kickmem_size, 1, &cloanto_rom))
+           goto err;
+    }
+
+#if defined(AMIGA)
+    chk_sum:
+#endif
+
+    if (currprefs.kickshifter && kickmem_size >= 524288) {
+       /* Patch Kickstart ROM for ShapeShifter - from Christian Bauer.
+        * Changes 'lea $400,a0' and 'lea $1000,a0' to 'lea $3000,a0' for
+        * ShapeShifter compatability.
+       */
+       int i;
+       uae_u8 kickshift1[] = { 0x41, 0xf8, 0x04, 0x00 };
+       uae_u8 kickshift2[] = { 0x41, 0xf8, 0x10, 0x00 };
+       uae_u8 kickshift3[] = { 0x43, 0xf8, 0x04, 0x00 };
+       
+       for (i = 0x200; i < 0x300; i++) {
+           if (!memcmp (kickmemory + i, kickshift1, sizeof (kickshift1)) ||
+           !memcmp (kickmemory + i, kickshift2, sizeof (kickshift2)) ||
+           !memcmp (kickmemory + i, kickshift3, sizeof (kickshift3))) {
+               kickmemory[i + 2] = 0x30;
+               write_log ("Kickstart KickShifted @%04.4X\n", i);
+           }
+       }
+       kickstart_fix_checksum (kickmemory, kickmem_size);
+    }
+    kickstart_version = (kickmemory[12] << 8) | kickmemory[13];
+    return 1;
+err:
+    strcpy (currprefs.romfile, tmprom);
+    strcpy (currprefs.keyfile, tmpkey);
+    return 0;
+}
+
+#ifndef NATMEM_OFFSET
+
+uae_u8 *mapped_malloc (size_t s, char *file)
+{
+    return malloc (s);
+}
+
+void mapped_free (uae_u8 *p)
+{
+    free (p);
+}
+
+#else
+
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+shmpiece *shm_start;
+
+static void dumplist(void)
+{
+    shmpiece *x = shm_start;
+    write_log ("Start Dump:\n");
+    while (x) {
+       write_log ("this=%p,Native %p,id %d,prev=%p,next=%p,size=0x%08x\n",
+               x, x->native_address, x->id, x->prev, x->next, x->size);
+       x = x->next;
+    }
+    write_log ("End Dump:\n");
+}
+
+static shmpiece *find_shmpiece (uae_u8 *base)
+{
+    shmpiece *x = shm_start;
+
+    while (x && x->native_address != base)
+       x = x->next;
+    if (!x) {
+       write_log ("NATMEM: Failure to find mapping at %p\n",base);
+       dumplist ();
+       canbang = 0;
+       return 0;
+    }
+    return x;
+}
+
+static void delete_shmmaps (uae_u32 start, uae_u32 size)
+{
+    if (!canbang)
+       return;
+
+    while (size) {
+       uae_u8 *base = mem_banks[bankindex (start)]->baseaddr;
+       if (base) {
+           shmpiece *x;
+           //base = ((uae_u8*)NATMEM_OFFSET)+start;
+
+           x = find_shmpiece (base);
+           if (!x)
+               return;
+
+           if (x->size > size) {
+               write_log ("NATMEM: Failure to delete mapping at %08x(size %08x, delsize %08x)\n",start,x->size,size);
+               dumplist ();
+               canbang = 0;
+               return;
+           }
+           shmdt (x->native_address);
+           size -= x->size;
+           start += x->size;
+           if (x->next)
+               x->next->prev = x->prev;        /* remove this one from the list */
+           if (x->prev)
+               x->prev->next = x->next;
+           else
+               shm_start = x->next;
+           free (x);
+       } else {
+           size -= 0x10000;
+           start += 0x10000;
+       }
+    }
+}
+static void add_shmmaps (uae_u32 start, addrbank *what)
+{
+    shmpiece *x = shm_start;
+    shmpiece *y;
+    uae_u8 *base = what->baseaddr;
+
+    if (!canbang)
+       return;
+    if (!base)
+       return;
+
+    x = find_shmpiece (base);
+    if (!x)
+       return;
+    y = malloc (sizeof (shmpiece));
+    *y = *x;
+    base = ((uae_u8 *) NATMEM_OFFSET) + start;
+    y->native_address = shmat (y->id, base, 0);
+    if (y->native_address == (void *) -1) {
+       write_log ("NATMEM: Failure to map existing at %08x(%p)\n",start,base);
+       dumplist ();
+       canbang = 0;
+       return;
+    }
+    y->next = shm_start;
+    y->prev = NULL;
+    if (y->next)
+       y->next->prev = y;
+    shm_start = y;
+}
+
+uae_u8 *mapped_malloc (size_t s, char *file)
+{
+    int id;
+    void *answer;
+    shmpiece *x;
+
+    if (!canbang)
+       return malloc (s);
+
+    id = shmget (IPC_PRIVATE, s, 0x1ff, file);
+    if (id == -1) {
+       canbang = 0;
+       return mapped_malloc (s, file);
+    }
+    answer = shmat (id, 0, 0);
+    shmctl (id, IPC_RMID, NULL);
+    if (answer != (void *) -1) {
+       x = malloc (sizeof (shmpiece));
+       x->native_address = answer;
+       x->id = id;
+       x->size = s;
+       x->next = shm_start;
+       x->prev = NULL;
+       if (x->next)
+           x->next->prev = x;
+       shm_start = x;
+
+       return answer;
+    }
+    canbang = 0;
+    return mapped_malloc (s, file);
+}
+
+#endif
+
+static void init_mem_banks (void)
+{
+    int i;
+    for (i = 0; i < 65536; i++)
+       put_mem_bank (i << 16, &dummy_bank, 0);
+#ifdef NATMEM_OFFSET
+    delete_shmmaps (0, 0xFFFF0000);
+#endif
+}
+
+void clearexec (void)
+{
+    if (chipmemory)
+       memset (chipmemory + 4, 0,  4);
+}
+
+static void allocate_memory (void)
+{
+    if (allocated_chipmem != currprefs.chipmem_size) {
+       if (chipmemory)
+           mapped_free (chipmemory);
+       chipmemory = 0;
+
+       allocated_chipmem = currprefs.chipmem_size;
+       chipmem_mask = allocated_chipmem - 1;
+
+       chipmemory = mapped_malloc (allocated_chipmem, "chip");
+       if (chipmemory == 0) {
+           write_log ("Fatal error: out of memory for chipmem.\n");
+           allocated_chipmem = 0;
+       } else
+       clearexec ();
+    }
+
+    if (allocated_bogomem != currprefs.bogomem_size) {
+       if (bogomemory)
+           mapped_free (bogomemory);
+       bogomemory = 0;
+
+       allocated_bogomem = currprefs.bogomem_size;
+       bogomem_mask = allocated_bogomem - 1;
+
+       if (allocated_bogomem) {
+           bogomemory = mapped_malloc (allocated_bogomem, "bogo");
+           if (bogomemory == 0) {
+               write_log ("Out of memory for bogomem.\n");
+               allocated_bogomem = 0;
+           }
+       }
+       clearexec ();
+    }
+#ifdef AUTOCONFIG
+    if (allocated_a3000mem != currprefs.a3000mem_size) {
+       if (a3000memory)
+           mapped_free (a3000memory);
+       a3000memory = 0;
+
+       allocated_a3000mem = currprefs.a3000mem_size;
+       a3000mem_mask = allocated_a3000mem - 1;
+
+       if (allocated_a3000mem) {
+           a3000memory = mapped_malloc (allocated_a3000mem, "a3000");
+           if (a3000memory == 0) {
+               write_log ("Out of memory for a3000mem.\n");
+               allocated_a3000mem = 0;
+           }
+       }
+       clearexec ();
+    }
+#endif
+    if (savestate_state == STATE_RESTORE) {
+       restore_ram (chip_filepos, chipmemory);
+       if (allocated_bogomem > 0)
+           restore_ram (bogo_filepos, bogomemory);
+    }
+    chipmem_bank.baseaddr = chipmemory;
+#ifdef AGA
+    chipmem_bank_ce2.baseaddr = chipmemory;
+#endif
+    bogomem_bank.baseaddr = bogomemory;
+}
+
+void map_overlay (int chip)
+{
+    int i = allocated_chipmem > 0x200000 ? (allocated_chipmem >> 16) : 32;
+    addrbank *cb;
+
+    cb = &chipmem_bank;
+#ifdef AGA
+    if (currprefs.cpu_cycle_exact && currprefs.cpu_level >= 2)
+       cb = &chipmem_bank_ce2;
+#endif
+    if (chip)
+       map_banks (cb, 0, i, allocated_chipmem);
+    else
+       map_banks (&kickmem_bank, 0, i, 0x80000);
+    if (savestate_state != STATE_RESTORE && savestate_state != STATE_REWIND)
+        m68k_setpc(m68k_getpc());
+}
+
+void memory_reset (void)
+{
+    int custom_start;
+
+    be_cnt = 0;
+    currprefs.chipmem_size = changed_prefs.chipmem_size;
+    currprefs.bogomem_size = changed_prefs.bogomem_size;
+    currprefs.a3000mem_size = changed_prefs.a3000mem_size;
+
+    init_mem_banks ();
+    allocate_memory ();
+
+    if (strcmp (currprefs.romfile, changed_prefs.romfile) != 0
+       || strcmp (currprefs.keyfile, changed_prefs.keyfile) != 0)
+    {
+       ersatzkickfile = 0;
+       memcpy (currprefs.romfile, changed_prefs.romfile, sizeof currprefs.romfile);
+       memcpy (currprefs.keyfile, changed_prefs.keyfile, sizeof currprefs.keyfile);
+        if (savestate_state != STATE_RESTORE)
+           clearexec ();
+        load_extendedkickstart ();
+       if (!load_kickstart ()) {
+#ifdef AUTOCONFIG
+            init_ersatz_rom (kickmemory);
+           ersatzkickfile = 1;
+#endif
+       }
+    }
+
+    custom_start = 0xC0;
+
+    map_banks (&custom_bank, custom_start, 0xE0 - custom_start, 0);
+    map_banks (&cia_bank, 0xA0, 32, 0);
+    map_banks (&clock_bank, 0xDC, 1, 0);
+
+    /* @@@ Does anyone have a clue what should be in the 0x200000 - 0xA00000
+     * range on an Amiga without expansion memory?  */
+    custom_start = allocated_chipmem >> 16;
+    if (custom_start < 0x20 + (currprefs.fastmem_size >> 16))
+       custom_start = 0x20 + (currprefs.fastmem_size >> 16);
+    map_banks (&dummy_bank, custom_start, 0xA0 - custom_start, 0);
+    /*map_banks (&mbres_bank, 0xDE, 1); */
+
+    if (bogomemory != 0) {
+       int t = allocated_bogomem >> 16;
+       if (t > 0x1C)
+           t = 0x1C;
+       map_banks (&bogomem_bank, 0xC0, t, allocated_bogomem);
+    }
+#ifdef AUTOCONFIG
+    if (a3000memory != 0)
+       map_banks (&a3000mem_bank, a3000mem_start >> 16, allocated_a3000mem >> 16,
+                  allocated_a3000mem);
+
+    map_banks (&rtarea_bank, RTAREA_BASE >> 16, 1, 0);
+#endif
+
+    map_banks (&kickmem_bank, 0xF8, 8, 0);
+    if (currprefs.maprom)
+       map_banks (&kickram_bank, currprefs.maprom >> 16, 8, 0);
+
+    if (a1000_bootrom)
+        a1000_handle_kickstart (1);
+#ifdef AUTOCONFIG
+    map_banks (&expamem_bank, 0xE8, 1, 0);
+#endif
+
+    /* Map the chipmem into all of the lower 8MB */
+    map_overlay (1);
+
+#ifdef CDTV
+    cdtv_enabled = 0;
+#endif
+#ifdef CD32
+    cd32_enabled = 0;
+#endif
+
+    switch (extromtype ()) {
+
+#ifdef CDTV
+    case EXTENDED_ROM_CDTV:
+       map_banks (&extendedkickmem_bank, 0xF0, 4, 0);
+       cdtv_enabled = 1;
+       break;
+#endif
+#ifdef CD32
+    case EXTENDED_ROM_CD32:
+       map_banks (&extendedkickmem_bank, 0xE0, 8, 0);
+       cd32_enabled = 1;
+       break;
+#endif
+    default:
+       if (cloanto_rom && !currprefs.maprom)
+           map_banks (&kickmem_bank, 0xE0, 8, 0);
+    }
+
+#ifdef ACTION_REPLAY
+    action_replay_memory_reset(); 
+    #ifdef ACTION_REPLAY_HRTMON
+    hrtmon_map_banks();
+    #endif
+
+    #ifndef ACTION_REPLAY_HIDE_CARTRIDGES
+    #ifdef ACTION_REPLAY
+    action_replay_map_banks(); 
+    #endif
+    #endif
+#endif
+}
+
+void memory_init (void)
+{
+    allocated_chipmem = 0;
+    allocated_bogomem = 0;
+    kickmemory = 0;
+    extendedkickmemory = 0;
+    extendedkickmem_size = 0;
+    chipmemory = 0;
+#ifdef AUTOCONFIG
+    allocated_a3000mem = 0;
+    a3000memory = 0;
+#endif
+    bogomemory = 0;
+
+    kickmemory = mapped_malloc (kickmem_size, "kick");
+    memset (kickmemory, 0, kickmem_size);
+    kickmem_bank.baseaddr = kickmemory;
+    kickmem_mask = kickmem_size - 1;
+    currprefs.romfile[0] = 0;
+    currprefs.keyfile[0] = 0;
+#ifdef AUTOCONFIG
+    init_ersatz_rom (kickmemory);
+    ersatzkickfile = 1;
+#endif
+
+#ifdef ACTION_REPLAY   
+    action_replay_load();
+    action_replay_init(1);
+    
+    #ifdef ACTION_REPLAY_HRTM
+    hrtmon_load(1);
+    #endif
+#endif
+
+    init_mem_banks ();
+}
+
+void memory_cleanup (void)
+{
+#ifdef AUTOCONFIG
+    if (a3000memory)
+       mapped_free (a3000memory);
+    a3000memory = 0;
+#endif
+    if (bogomemory)
+       mapped_free (bogomemory);
+    if (kickmemory)
+       mapped_free (kickmemory);
+    if (a1000_bootrom)
+       free (a1000_bootrom);
+    if (chipmemory)
+       mapped_free (chipmemory);
+  
+    bogomemory = 0;
+    kickmemory = 0;
+    a1000_bootrom = 0;
+    chipmemory = 0;
+
+    #ifdef ACTION_REPLAY
+    action_replay_cleanup();
+    #endif
+}
+
+void map_banks (addrbank *bank, int start, int size, int realsize)
+{
+    int bnr;
+    unsigned long int hioffs = 0, endhioffs = 0x100;
+    addrbank *orgbank = bank;
+    uae_u32 realstart = start;
+
+    flush_icache (1);          /* Sure don't want to keep any old mappings around! */
+#ifdef NATMEM_OFFSET
+    delete_shmmaps (start << 16, size << 16);
+#endif
+
+    if (!realsize)
+       realsize = size << 16;
+
+    if ((size << 16) < realsize) {
+       //write_log ("Please report to bmeyer@cs.monash.edu.au, and mention:\n");
+       write_log ("Broken mapping, size=%x, realsize=%x\n", size, realsize);
+       write_log ("Start is %x\n", start);
+       write_log ("Reducing memory sizes, especially chipmem, may fix this problem\n");
+       abort ();
+    }
+
+    if (start >= 0x100) {
+       int real_left = 0;
+       for (bnr = start; bnr < start + size; bnr++) {
+           if (!real_left) {
+               realstart = bnr;
+               real_left = realsize >> 16;
+#ifdef NATMEM_OFFSET
+               add_shmmaps (realstart << 16, bank);
+#endif
+           }
+           put_mem_bank (bnr << 16, bank, realstart << 16);
+           real_left--;
+       }
+       return;
+    }
+    if (currprefs.address_space_24)
+       endhioffs = 0x10000;
+    for (hioffs = 0; hioffs < endhioffs; hioffs += 0x100) {
+       int real_left = 0;
+       for (bnr = start; bnr < start + size; bnr++) {
+           if (!real_left) {
+               realstart = bnr + hioffs;
+               real_left = realsize >> 16;
+#ifdef NATMEM_OFFSET
+               add_shmmaps (realstart << 16, bank);
+#endif
+           }
+           put_mem_bank ((bnr + hioffs) << 16, bank, realstart << 16);
+           real_left--;
+       }
+    }
+}
+
+
+/* memory save/restore code */
+
+uae_u8 *save_cram (int *len)
+{
+    *len = allocated_chipmem;
+    return chipmemory;
+}
+
+uae_u8 *save_bram (int *len)
+{
+    *len = allocated_bogomem;
+    return bogomemory;
+}
+
+void restore_cram (int len, long filepos)
+{
+    chip_filepos = filepos;
+    changed_prefs.chipmem_size = len;
+}
+
+void restore_bram (int len, long filepos)
+{
+    bogo_filepos = filepos;
+    changed_prefs.bogomem_size = len;
+}
+
+uae_u8 *restore_rom (uae_u8 *src)
+{
+    restore_u32 ();
+    restore_u32 ();
+    restore_u32 ();
+    restore_u32 ();
+    restore_u32 ();
+    src += strlen (src) + 1;
+    if (src[0]) {
+       if (zfile_exists (src))
+           strncpy (changed_prefs.romfile , src, 255);
+        src+=strlen(src)+1;
+    }
+    return src;
+}
+
+uae_u8 *save_rom (int first, int *len, uae_u8 *dstptr)
+{
+    static int count;
+    uae_u8 *dst, *dstbak;
+    uae_u8 *mem_real_start;
+    int mem_start, mem_size, mem_type, i, saverom;
+
+    saverom = 0;
+    if (first)
+       count = 0;
+    for (;;) {
+       mem_type = count;
+       switch (count) {
+       case 0:         /* Kickstart ROM */
+           mem_start = 0xf80000;
+           mem_real_start = kickmemory;
+           mem_size = kickmem_size;
+           /* 256KB or 512KB ROM? */
+           for (i = 0; i < mem_size / 2 - 4; i++) {
+               if (longget (i + mem_start) != longget (i + mem_start + mem_size / 2))
+                   break;
+           }
+           if (i == mem_size / 2 - 4) {
+               mem_size /= 2;
+               mem_start += 262144;
+           }
+           mem_type = 0;
+           break;
+       default:
+           return 0;
+       }
+       count++;
+       if (mem_size)
+           break;
+    }
+    if (dstptr)
+       dstbak = dst = dstptr;
+    else
+        dstbak = dst = malloc (4 + 4 + 4 + 4 + 4 + mem_size);
+    save_u32 (mem_start);
+    save_u32 (mem_size);
+    save_u32 (mem_type);
+    save_u32 (longget (mem_start + 12));       /* version+revision */
+    save_u32 (CRC32 (0, kickmemory, mem_size));
+    sprintf (dst, "Kickstart %d.%d", wordget (mem_start + 12), wordget (mem_start + 14));
+    dst += strlen (dst) + 1;
+    strcpy (dst, currprefs.romfile);/* rom image name */
+    dst += strlen(dst) + 1;
+    if (saverom) {
+       for (i = 0; i < mem_size; i++)
+           *dst++ = byteget (mem_start + i);
+    }
+    *len = dst - dstbak;
+    return dstbak;
+}
diff --git a/missing.c b/missing.c
new file mode 100755 (executable)
index 0000000..d0c7ddc
--- /dev/null
+++ b/missing.c
@@ -0,0 +1,44 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Various stuff missing in some OSes.
+  *
+  * Copyright 1997 Bernd Schmidt
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "uae.h"
+
+#ifndef HAVE_STRDUP
+
+char *my_strdup (const char *s)
+{
+    /* The casts to char * are there to shut up the compiler on HPUX */
+    char *x = (char*)xmalloc(strlen((char *)s) + 1);
+    strcpy(x, (char *)s);
+    return x;
+}
+
+#endif
+
+void *xmalloc (size_t n)
+{
+    void *a = malloc (n);
+    if (a == NULL) {
+       write_log ("virtual memory exhausted\n");
+       abort ();
+    }
+    return a;
+}
+
+void *xcalloc (size_t n, size_t size)
+{
+    void *a = calloc (n, size);
+    if (a == NULL) {
+       write_log ("virtual memory exhausted\n");
+       abort ();
+    }
+    return a;
+}
diff --git a/native2amiga.c b/native2amiga.c
new file mode 100755 (executable)
index 0000000..f73286a
--- /dev/null
@@ -0,0 +1,114 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Call Amiga Exec functions outside the main UAE thread.
+  *
+  * Copyright 1999 Patrick Ohly
+  * 
+  * Uses the EXTER interrupt that is setup in filesys.c
+  * and needs thread support.
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "threaddep/thread.h"
+#include "options.h"
+#include "memory.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "disk.h"
+#include "autoconf.h"
+#include "filesys.h"
+#include "execlib.h"
+#include "native2amiga.h"
+
+smp_comm_pipe native2amiga_pending;
+
+/*
+ * to be called when setting up the hardware
+ */
+
+void native2amiga_install (void)
+{
+    init_comm_pipe (&native2amiga_pending, 10, 2);
+}
+
+/*
+ * to be called when the Amiga boots, i.e. by filesys_diagentry()
+ */
+void native2amiga_startup (void)
+{
+}
+
+#ifdef SUPPORT_THREADS
+
+void uae_Cause(uaecptr interrupt)
+{
+    write_comm_pipe_int (&native2amiga_pending, 3, 0);
+    write_comm_pipe_u32 (&native2amiga_pending, interrupt, 1);
+
+    uae_int_requested = 1;
+}
+
+void uae_ReplyMsg(uaecptr msg)
+{
+    write_comm_pipe_int (&native2amiga_pending, 2, 0);
+    write_comm_pipe_u32 (&native2amiga_pending, msg, 1);
+
+    uae_int_requested = 1;
+}
+
+void uae_PutMsg(uaecptr port, uaecptr msg)
+{
+    uae_pt data;
+    data.i = 1;
+    write_comm_pipe_int (&native2amiga_pending, 1, 0);
+    write_comm_pipe_u32 (&native2amiga_pending, port, 0);
+    write_comm_pipe_u32 (&native2amiga_pending, msg, 1);
+
+    uae_int_requested = 1;
+}
+
+void uae_Signal(uaecptr task, uae_u32 mask)
+{
+    write_comm_pipe_int (&native2amiga_pending, 0, 0);
+    write_comm_pipe_u32 (&native2amiga_pending, task, 0);
+    write_comm_pipe_int (&native2amiga_pending, mask, 1);
+    
+    uae_int_requested = 1;
+}
+
+void uae_NotificationHack(uaecptr port, uaecptr nr)
+{
+    write_comm_pipe_int (&native2amiga_pending, 4, 0);
+    write_comm_pipe_int (&native2amiga_pending, port, 0);
+    write_comm_pipe_int (&native2amiga_pending, nr, 1);
+    
+    uae_int_requested = 1;
+}
+
+#endif
+
+void uae_NewList(uaecptr list)
+{
+    put_long (list, list + 4);
+    put_long (list + 4, 0);
+    put_long (list + 8, list);
+}
+
+uaecptr uae_AllocMem (uae_u32 size, uae_u32 flags)
+{
+    m68k_dreg (regs, 0) = size;
+    m68k_dreg (regs, 1) = flags;
+    write_log ("allocmem(%d,%08.8X)\n", size, flags);
+    return CallLib (get_long (4), -198); /* AllocMem */
+}
+
+void uae_FreeMem (uaecptr memory, uae_u32 size)
+{
+    m68k_dreg (regs, 0) = size;
+    m68k_areg (regs, 1) = memory;
+    CallLib (get_long (4), -0xD2); /* FreeMem */
+}
diff --git a/ncurses.c b/ncurses.c
new file mode 100755 (executable)
index 0000000..0375627
--- /dev/null
+++ b/ncurses.c
@@ -0,0 +1,680 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * [n]curses output.
+  *
+  * There are 17 color modes:
+  *  -H0/-H1 are black/white output
+  *  -H2 through -H16 give you different color allocation strategies. On my
+  *    system, -H14 seems to give nice results.
+  *
+  * Copyright 1997 Samuel Devulder, Bernd Schmidt
+  */
+
+/****************************************************************************/
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <ctype.h>
+#include <signal.h>
+
+/****************************************************************************/
+
+#include "config.h"
+#include "options.h"
+#include "threaddep/thread.h"
+#include "uae.h"
+#include "memory.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "xwin.h"
+#include "keyboard.h"
+#include "keybuf.h"
+#include "disk.h"
+#include "debug.h"
+#include "gui.h"
+
+#ifdef HAVE_NCURSES_H
+#include <ncurses.h>
+#else
+#include <curses.h>
+#endif
+
+/****************************************************************************/
+
+#define MAXGRAYCHAR 128
+
+enum {
+    MYCOLOR_BLACK, MYCOLOR_RED, MYCOLOR_GREEN, MYCOLOR_BLUE,
+    MYCOLOR_YELLOW, MYCOLOR_CYAN, MYCOLOR_MAGENTA, MYCOLOR_WHITE
+};
+
+static int mycolor2curses_map [] = {
+    COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_BLUE,
+    COLOR_YELLOW, COLOR_CYAN, COLOR_MAGENTA, COLOR_WHITE
+};
+
+static int mycolor2pair_map[] = { 1,2,3,4,5,6,7,8 };
+
+static chtype graychar[MAXGRAYCHAR];
+static int maxc,max_graychar;
+static int curses_on;
+
+static int *x2graymap;
+
+/* Keyboard and mouse */
+
+static int keystate[256];
+static int keydelay = 20;
+
+static void curses_exit(void);
+
+/****************************************************************************/
+
+static RETSIGTYPE sigbrkhandler(int foo)
+{
+    curses_exit();
+    activate_debugger();
+}
+
+void setup_brkhandler(void)
+{
+    struct sigaction sa;
+    sa.sa_handler = sigbrkhandler;
+    sa.sa_flags = 0;
+    sa.sa_flags = SA_RESTART;
+    sigemptyset(&sa.sa_mask);
+    sigaction(SIGINT, &sa, NULL);
+}
+
+/***************************************************************************/
+
+static void curses_insert_disk(void)
+{
+    curses_exit();
+    gui_changesettings();
+    flush_screen(0,0);
+}
+
+/****************************************************************************/
+
+/*
+ * old:        fmt = " .,:=(Io^vM^vb*X^#M^vX*boI(=:. ^b^vobX^#M" doesn't work: "^vXb*oI(=:. ";
+ * good:       fmt = " .':;=(IoJpgFPEB#^vgpJoI(=;:'. ^v^b=(IoJpgFPEB";
+ *
+ *     fmt = " .,:=(Io*b^vM^vX^#M^vXb*oI(=:. ";
+ */
+
+static void init_graychar(void)
+{
+    chtype *p = graychar;
+    chtype attrs;
+    int i,j;
+    char *fmt;
+
+    attrs = termattrs();
+    if ((currprefs.color_mode & 1) == 0 && (attrs & (A_REVERSE | A_BOLD)))
+       fmt = " .':;=(IoJpgFPEB#^vgpJoI(=;:'. ^v^boJpgFPEB";
+    else if ((currprefs.color_mode & 1) == 0 && (attrs & A_REVERSE))
+       fmt = " .':;=(IoJpgFPEB#^vgpJoI(=;:'. ";
+    else
+       /* One could find a better pattern.. */
+       fmt = " .`'^^\",:;i!1Il+=tfjxznuvyZYXHUOQ0MWB";
+    attrs = A_NORMAL | COLOR_PAIR (0);
+    while(*fmt) {
+       if(*fmt == '^') {
+           ++fmt;
+           switch(*fmt) {
+               case 's': case 'S': attrs ^= A_STANDOUT; break;
+               case 'v': case 'V': attrs ^= A_REVERSE; break;
+               case 'b': case 'B': attrs ^= A_BOLD; break;
+               case 'd': case 'D': attrs ^= A_DIM; break;
+               case 'u': case 'U': attrs ^= A_UNDERLINE; break;
+               case 'p': case 'P': attrs  = A_NORMAL; break;
+               case '#': if(ACS_CKBOARD == ':')
+                              *p++ = (attrs | '#');
+                         else *p++ = (attrs | ACS_CKBOARD); break;
+               default:  *p++ = (attrs | *fmt); break;
+           }
+           ++fmt;
+       } else *p++ = (attrs | *fmt++);
+       if(p >= graychar + MAXGRAYCHAR) break;
+    }
+    max_graychar = (p - graychar) - 1;
+
+    for (i = 0; i <= maxc; i++)
+       x2graymap[i] = i * max_graychar / maxc;
+#if 0
+    for(j=0;j<LINES;++j) {
+       move(j,0);
+       for(i=0;i<COLS;++i) addch(graychar[i % (max_graychar+1)]);
+    }
+    refresh();
+    sleep(3);
+#endif
+}
+
+static int x_map[900], y_map[700], y_rev_map [700];
+
+
+/****************************************************************************/
+
+static void init_colors(void)
+{
+    int i;
+
+    maxc = 0;
+
+    for(i = 0; i < 4096; ++i) {
+       int r,g,b,r1,g1,b1;
+       int m, comp;
+       int ctype;
+
+       r =  i >> 8;
+       g = (i >> 4) & 15;
+       b =  i & 15;
+
+       xcolors[i] = (77 * r + 151 * g + 28 * b)/16;
+       if(xcolors[i] > maxc)
+           maxc = xcolors[i];
+       m = r;
+       if (g > m)
+           m = g;
+       if (b > m)
+           m = b;
+       if (m == 0) {
+           xcolors[i] |= MYCOLOR_WHITE << 8; /* to get gray instead of black in dark areas */
+           continue;
+       }
+
+       if ((currprefs.color_mode & ~1) != 0) {
+           r1 = r*15 / m;
+           g1 = g*15 / m;
+           b1 = b*15 / m;
+
+           comp = 8;
+           for (;;) {
+               if (b1 < comp) {
+                   if (r1 < comp)
+                       ctype = MYCOLOR_GREEN;
+                   else if (g1 < comp)
+                       ctype = MYCOLOR_RED;
+                   else
+                       ctype = MYCOLOR_YELLOW;
+               } else {
+                   if (r1 < comp) {
+                       if (g1 < comp)
+                           ctype = MYCOLOR_BLUE;
+                       else
+                           ctype = MYCOLOR_CYAN;
+                   } else if (g1 < comp)
+                           ctype = MYCOLOR_MAGENTA;
+                   else {
+                       comp += 4;
+                       if (comp == 12 && (currprefs.color_mode & 2) != 0)
+                           continue;
+                       ctype = MYCOLOR_WHITE;
+                   }
+               }
+               break;
+           }
+           if (currprefs.color_mode & 8) {
+               if (ctype == MYCOLOR_BLUE && xcolors[i] > /*27*/50)
+                   ctype = r1 > (g1+2) ? MYCOLOR_MAGENTA : MYCOLOR_CYAN;
+               if (ctype == MYCOLOR_RED && xcolors[i] > /*75*/ 90)
+                   ctype = b1 > (g1+6) ? MYCOLOR_MAGENTA : MYCOLOR_YELLOW;
+           }
+           xcolors[i] |= ctype << 8;
+       }
+    }
+    if (currprefs.color_mode & 4) {
+       int j;
+       for (j = MYCOLOR_RED; j < MYCOLOR_WHITE; j++) {
+           int best = 0, maxv = 0;
+           int multi, divi;
+
+           for (i = 0; i < 4096; i++)
+               if ((xcolors[i] & 255) > maxv && (xcolors[i] >> 8) == j) {
+                   best = i;
+                   maxv = (xcolors[best] & 255);
+               }
+           /* Now maxv is the highest intensity a color of type J is supposed to have.
+            * In  reality, it will most likely only have intensity maxv*multi/divi.
+            * We try to correct this. */
+           maxv = maxv * 256 / maxc;
+
+           divi = 256;
+           switch (j) {
+            case MYCOLOR_RED:     multi = 77; break;
+            case MYCOLOR_GREEN:   multi = 151; break;
+            case MYCOLOR_BLUE:    multi = 28; break;
+            case MYCOLOR_YELLOW:  multi = 228; break;
+            case MYCOLOR_CYAN:    multi = 179; break;
+            case MYCOLOR_MAGENTA: multi = 105; break;
+            default: abort();
+           }
+#if 1 /* This makes the correction less extreme */
+           if (! (currprefs.color_mode & 8))
+               multi = (multi + maxv) / 2;
+#endif
+           for (i = 0; i < 4096; i++) {
+               int v = xcolors[i];
+               if ((v >> 8) != j)
+                   continue;
+               v &= 255;
+               /* I don't think either of these is completely correct, but
+                * the first one produces rather good results. */
+#if 1
+               v = v * divi / multi;
+               if (v > maxc)
+                   v = maxc;
+#else
+               v = v * 256 / maxv);
+               if (v > maxc)
+                   /*maxc = v*/abort();
+#endif
+               xcolors[i] = v | (j << 8);
+           }
+       }
+    }
+    x2graymap = (int *)malloc(sizeof(int) * (maxc+1));
+}
+
+static void curses_init(void)
+{
+    initscr ();
+
+    start_color ();
+    if (! has_colors () || COLOR_PAIRS < 20 /* whatever */)
+       currprefs.color_mode &= 1;
+    else {
+       init_pair (1, COLOR_BLACK, COLOR_BLACK);
+       init_pair (2, COLOR_RED, COLOR_BLACK);
+       init_pair (3, COLOR_GREEN, COLOR_BLACK);
+       init_pair (4, COLOR_BLUE, COLOR_BLACK);
+       init_pair (5, COLOR_YELLOW, COLOR_BLACK);
+       init_pair (6, COLOR_CYAN, COLOR_BLACK);
+       init_pair (7, COLOR_MAGENTA, COLOR_BLACK);
+       init_pair (8, COLOR_WHITE, COLOR_BLACK);
+    }
+    printf ("curses_init: %d pairs available\n", COLOR_PAIRS);
+
+    cbreak(); noecho();
+    nonl (); intrflush(stdscr, FALSE); keypad(stdscr, TRUE);
+    nodelay(stdscr, TRUE);
+    leaveok(stdscr, TRUE);
+
+    attron (A_NORMAL | COLOR_PAIR (0));
+    bkgd(' '|COLOR_PAIR(0));
+
+#ifdef NCURSES_MOUSE_VERSION
+    mousemask(BUTTON1_PRESSED | BUTTON1_RELEASED |
+             BUTTON2_PRESSED | BUTTON2_RELEASED |
+             BUTTON3_PRESSED | BUTTON3_RELEASED |
+             REPORT_MOUSE_POSITION, NULL);
+#endif
+
+    init_graychar();
+    curses_on = 1;
+}
+
+static void curses_exit(void)
+{
+#ifdef NCURSES_MOUSE_VERSION
+    mousemask(0, NULL);
+#endif
+
+    nocbreak(); echo(); nl(); intrflush(stdscr, TRUE);
+    keypad(stdscr, FALSE); nodelay(stdscr, FALSE); leaveok(stdscr, FALSE);
+    endwin();
+    curses_on = 0;
+}
+
+/****************************************************************************/
+
+static int getgraycol(int x, int y)
+{
+    uae_u8 *bufpt;
+    int xs, xl, ys, yl, c, cm;
+
+    xl = x_map[x+1] - (xs = x_map[x]);
+    yl = y_map[y+1] - (ys = y_map[y]);
+
+    bufpt = ((uae_u8 *)gfxvidinfo.bufmem) + ys*currprefs.gfx_width + xs;
+
+    cm = c = 0;
+    for(y = 0; y < yl; y++, bufpt += currprefs.gfx_width)
+       for(x = 0; x < xl; x++) {
+           c += bufpt[x];
+           ++cm;
+       }
+    if (cm)
+       c /= cm;
+    if (! currprefs.curses_reverse_video)
+       c = maxc - c;
+    return graychar[x2graymap[c]];
+}
+
+static int getcol(int x, int y)
+{
+    uae_u16 *bufpt;
+    int xs, xl, ys, yl, c, cm;
+    int bestcol = MYCOLOR_BLACK, bestccnt = 0;
+    unsigned char colcnt [8];
+
+    memset (colcnt, 0 , sizeof colcnt);
+
+    xl = x_map[x+1] - (xs = x_map[x]);
+    yl = y_map[y+1] - (ys = y_map[y]);
+
+    bufpt = ((uae_u16 *)gfxvidinfo.bufmem) + ys*currprefs.gfx_width + xs;
+
+    cm = c = 0;
+    for(y = 0; y < yl; y++, bufpt += currprefs.gfx_width)
+       for(x = 0; x < xl; x++) {
+           int v = bufpt[x];
+           int cnt;
+
+           c += v & 0xFF;
+           cnt = ++colcnt[v >> 8];
+           if (cnt > bestccnt) {
+               bestccnt = cnt;
+               bestcol = v >> 8;
+           }
+           ++cm;
+       }
+    if (cm)
+       c /= cm;
+    if (! currprefs.curses_reverse_video)
+       c = maxc - c;
+    return (graychar[x2graymap[c]] & ~A_COLOR) | COLOR_PAIR (mycolor2pair_map[bestcol]);
+}
+
+static void flush_line_txt(int y)
+{
+    int x;
+    move (y,0);
+    if (currprefs.color_mode < 2)
+       for (x = 0; x < COLS; ++x) {
+           int c;
+
+           c = getgraycol(x,y);
+           addch(c);
+       }
+    else
+       for (x = 0; x < COLS; ++x) {
+           int c;
+
+           c = getcol(x,y);
+           addch(c);
+       }
+}
+
+__inline__ void flush_line(int y)
+{
+    if(y < 0 || y >= currprefs.gfx_height) {
+/*       printf("flush_line out of window: %d\n", y); */
+       return;
+    }
+    if(!curses_on)
+       return;
+    flush_line_txt(y_rev_map[y]);
+}
+
+void flush_block (int ystart, int ystop)
+{
+    int y;
+    if(!curses_on)
+       return;
+    ystart = y_rev_map[ystart];
+    ystop  = y_rev_map[ystop];
+    for(y = ystart; y <= ystop; ++y)
+       flush_line_txt(y);
+}
+
+void flush_screen (int ystart, int ystop)
+{
+    if(!debugging && !curses_on) {
+       curses_init();
+       flush_block(0, currprefs.gfx_height - 1);
+    }
+    refresh();
+}
+
+/****************************************************************************/
+
+struct bstring *video_mode_menu = NULL;
+
+void vidmode_menu_selected(int a)
+{
+}
+
+int graphics_setup(void)
+{
+    return 1;
+}
+
+int graphics_init(void)
+{
+    int i;
+
+    if (currprefs.color_mode > 16)
+       write_log ("Bad color mode selected. Using default.\n"), currprefs.color_mode = 0;
+
+    init_colors();
+
+    curses_init();
+    write_log("Using %s.\n",longname());
+
+    if (debugging)
+       curses_exit ();
+
+    /* we have a 320x256x8 pseudo screen */
+
+    currprefs.gfx_width = 320;
+    currprefs.gfx_height = 256;
+    currprefs.gfx_lores = 1;
+
+    gfxvidinfo.width = currprefs.gfx_width;
+    gfxvidinfo.height = currprefs.gfx_height;
+    gfxvidinfo.maxblocklines = 1000;
+    gfxvidinfo.pixbytes = currprefs.color_mode < 2 ? 1 : 2;
+    gfxvidinfo.rowbytes = gfxvidinfo.pixbytes * currprefs.gfx_width;
+    gfxvidinfo.bufmem = (char *)calloc(gfxvidinfo.rowbytes, currprefs.gfx_height+1);
+    gfxvidinfo.linemem = 0;
+    gfxvidinfo.emergmem = 0;
+    gfxvidinfo.can_double = 0;
+    switch (gfxvidinfo.pixbytes) {
+     case 1:
+       for (i = 0; i < 4096; i++)
+           xcolors[i] = xcolors[i] * 0x01010101;
+       gfxvidinfo.can_double = 1;
+       break;
+     case 2:
+       for (i = 0; i < 4096; i++)
+           xcolors[i] = xcolors[i] * 0x00010001;
+       gfxvidinfo.can_double = 1;
+       break;
+    }
+    if(!gfxvidinfo.bufmem) {
+       write_log("Not enough memory.\n");
+       return 0;
+    }
+
+    for (i = 0; i < sizeof x_map / sizeof *x_map; i++)
+       x_map[i] = (i * currprefs.gfx_width) / COLS;
+    for (i = 0; i < sizeof y_map / sizeof *y_map; i++)
+       y_map[i] = (i * currprefs.gfx_height) / LINES;
+    for (i = 0; i < sizeof y_map / sizeof *y_map - 1; i++) {
+       int l1 = y_map[i];
+       int l2 = y_map[i+1];
+       int j;
+       if (l2 >= sizeof y_rev_map / sizeof *y_rev_map)
+           break;
+       for (j = l1; j < l2; j++)
+           y_rev_map[j] = i;
+    }
+
+    buttonstate[0] = buttonstate[1] = buttonstate[2] = 0;
+    for(i=0; i<256; i++)
+       keystate[i] = 0;
+
+    lastmx = lastmy = 0;
+    newmousecounters = 0;
+
+    return 1;
+}
+
+/****************************************************************************/
+
+void graphics_leave(void)
+{
+    curses_exit();
+}
+
+/****************************************************************************/
+
+static int keycode2amiga(int ch)
+{
+    switch(ch) {
+       case KEY_A1:    return AK_NP7;
+       case KEY_UP:    return AK_NP8;
+       case KEY_A3:    return AK_NP9;
+       case KEY_LEFT:  return AK_NP4;
+       case KEY_B2:    return AK_NP5;
+       case KEY_RIGHT: return AK_NP6;
+       case KEY_C1:    return AK_NP1;
+       case KEY_DOWN:  return AK_NP2;
+       case KEY_C3:    return AK_NP3;
+       case KEY_ENTER: return AK_ENT;
+       case 13:        return AK_RET;
+       case ' ':       return AK_SPC;
+       case 27:        return AK_ESC;
+       default: return -1;
+    }
+}
+
+/***************************************************************************/
+
+void handle_events(void)
+{
+    int ch;
+    int kc;
+
+    /* Hack to simulate key release */
+    for(kc = 0; kc < 256; ++kc) {
+       if(keystate[kc]) if(!--keystate[kc]) record_key((kc << 1) | 1);
+    }
+    if(buttonstate[0]) --buttonstate[0];
+    if(buttonstate[1]) --buttonstate[1];
+    if(buttonstate[2]) --buttonstate[2];
+
+    newmousecounters = 0;
+    if(!curses_on) return;
+
+    while((ch = getch())!=ERR) {
+       if(ch == 12) {clearok(stdscr,TRUE);refresh();}
+#ifdef NCURSES_MOUSE_VERSION
+       if(ch == KEY_MOUSE) {
+           MEVENT ev;
+           if(getmouse(&ev) == OK) {
+               lastmx = (ev.x*currprefs.gfx_width)/COLS;
+               lastmy = (ev.y*currprefs.gfx_height)/LINES;
+               if(ev.bstate & BUTTON1_PRESSED)  buttonstate[0] = keydelay;
+               if(ev.bstate & BUTTON1_RELEASED) buttonstate[0] = 0;
+               if(ev.bstate & BUTTON2_PRESSED)  buttonstate[1] = keydelay;
+               if(ev.bstate & BUTTON2_RELEASED) buttonstate[1] = 0;
+               if(ev.bstate & BUTTON3_PRESSED)  buttonstate[2] = keydelay;
+               if(ev.bstate & BUTTON3_RELEASED) buttonstate[2] = 0;
+           }
+       }
+#endif
+       if (ch == 6)  ++lastmx; /* ^F */
+       if (ch == 2)  --lastmx; /* ^B */
+       if (ch == 14) ++lastmy; /* ^N */
+       if (ch == 16) --lastmy; /* ^P */
+       if (ch == 11) {buttonstate[0] = keydelay;ch = 0;} /* ^K */
+       if (ch == 25) {buttonstate[2] = keydelay;ch = 0;} /* ^Y */
+       if (ch == 15) uae_reset (); /* ^O */
+       if (ch == 17) uae_quit (); /* ^Q */
+       if (ch == KEY_F(1)) {
+         curses_insert_disk();
+         ch = 0;
+       }
+
+       if(isupper(ch)) {
+           keystate[AK_LSH] =
+           keystate[AK_RSH] = keydelay;
+           record_key(AK_LSH << 1);
+           record_key(AK_RSH << 1);
+           kc = keycode2amiga(tolower(ch));
+           keystate[kc] = keydelay;
+           record_key(kc << 1);
+       } else if((kc = keycode2amiga(ch)) >= 0) {
+           keystate[kc] = keydelay;
+           record_key(kc << 1);
+       }
+    }
+    gui_handle_events();
+}
+
+/***************************************************************************/
+
+void target_specific_usage(void)
+{
+    printf("----------------------------------------------------------------------------\n");
+    printf("[n]curses specific usage:\n");
+    printf("  -x : Display reverse video.\n");
+    printf("By default uae will assume a black on white display. If yours\n");
+    printf("is light on dark, use -x. In case of graphics garbage, ^L will\n");
+    printf("redisplay the screen. ^K simulate left mouse button, ^Y RMB.\n");
+    printf("If you are using a xterm UAE can use the mouse. Else use ^F ^B\n");
+    printf("^P ^N to emulate mouse mouvements.\n");
+    printf("----------------------------------------------------------------------------\n");
+}
+
+/***************************************************************************/
+
+int check_prefs_changed_gfx (void)
+{
+    return 0;
+}
+
+int debuggable(void)
+{
+    return 1;
+}
+
+int needmousehack(void)
+{
+    return 1;
+}
+
+void LED(int on)
+{
+}
+
+void write_log (const char *buf, ...)
+{
+
+}
+
+int lockscr (void)
+{
+    return 1;
+}
+
+void unlockscr (void)
+{
+}
+
+void target_save_options (FILE *f, struct uae_prefs *p)
+{
+    fprintf (f, "curses.reverse_video=%s\n", p->curses_reverse_video ? "true" : "false");
+}
+
+int target_parse_option (struct uae_prefs *p, char *option, char *value)
+{
+    return (cfgfile_yesno (option, value, "reverse_video", &p->curses_reverse_video));
+}
diff --git a/newcpu.c b/newcpu.c
new file mode 100755 (executable)
index 0000000..b91e666
--- /dev/null
+++ b/newcpu.c
@@ -0,0 +1,2567 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * MC68000 emulation
+  *
+  * (c) 1995 Bernd Schmidt
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "events.h"
+#include "uae.h"
+#include "memory.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "cpu_prefetch.h"
+#include "autoconf.h"
+#include "ersatz.h"
+#include "debug.h"
+#include "compiler.h"
+#include "gui.h"
+#include "savestate.h"
+#include "blitter.h"
+#include "ar.h"
+
+#ifdef JIT
+#include "compemu.h"
+#include <signal.h>
+extern void vec(int x, struct siginfo* si, struct sigcontext* sc);
+int oink=0;
+/* For faster cycles handling */
+signed long pissoff=0;
+/* Counter for missed vsyncmintime deadlines */
+int gonebad=0;
+#else
+/* Need to have these somewhere */
+static void build_comp(void) {}
+void check_prefs_changed_comp (void) {}
+#endif
+
+/* Opcode of faulting instruction */
+static uae_u16 last_op_for_exception_3;
+/* PC at fault time */
+static uaecptr last_addr_for_exception_3;
+/* Address that generated the exception */
+static uaecptr last_fault_for_exception_3;
+/* read (0) or write (1) access */
+static int last_writeaccess_for_exception_3;
+/* instruction (1) or data (0) access */
+static int last_instructionaccess_for_exception_3;
+unsigned long irqcycles[15];
+int irqdelay[15];
+
+int areg_byteinc[] = { 1,1,1,1,1,1,1,2 };
+int imm8_table[] = { 8,1,2,3,4,5,6,7 };
+
+int movem_index1[256];
+int movem_index2[256];
+int movem_next[256];
+
+int fpp_movem_index1[256];
+int fpp_movem_index2[256];
+int fpp_movem_next[256];
+
+cpuop_func *cpufunctbl[65536];
+
+extern uae_u32 get_fpsr(void);
+
+#define COUNT_INSTRS 0
+
+#if COUNT_INSTRS
+static unsigned long int instrcount[65536];
+static uae_u16 opcodenums[65536];
+
+static int compfn (const void *el1, const void *el2)
+{
+    return instrcount[*(const uae_u16 *)el1] < instrcount[*(const uae_u16 *)el2];
+}
+
+static char *icountfilename (void)
+{
+    char *name = getenv ("INSNCOUNT");
+    if (name)
+       return name;
+    return COUNT_INSTRS == 2 ? "frequent.68k" : "insncount";
+}
+
+void dump_counts (void)
+{
+    FILE *f = fopen (icountfilename (), "w");
+    unsigned long int total;
+    int i;
+
+    write_log ("Writing instruction count file...\n");
+    for (i = 0; i < 65536; i++) {
+       opcodenums[i] = i;
+       total += instrcount[i];
+    }
+    qsort (opcodenums, 65536, sizeof(uae_u16), compfn);
+
+    fprintf (f, "Total: %lu\n", total);
+    for (i=0; i < 65536; i++) {
+       unsigned long int cnt = instrcount[opcodenums[i]];
+       struct instr *dp;
+       struct mnemolookup *lookup;
+       if (!cnt)
+           break;
+       dp = table68k + opcodenums[i];
+       for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++)
+           ;
+       fprintf (f, "%04x: %lu %s\n", opcodenums[i], cnt, lookup->name);
+    }
+    fclose (f);
+}
+#else
+void dump_counts (void)
+{
+}
+#endif
+
+
+int broken_in;
+
+static unsigned long op_illg_1 (uae_u32 opcode) REGPARAM;
+
+static unsigned long REGPARAM2 op_illg_1 (uae_u32 opcode)
+{
+    op_illg (opcode);
+    return 4;
+}
+
+static void build_cpufunctbl (void)
+{
+    int i;
+    unsigned long opcode;
+    struct cputbl *tbl = 0;
+
+   switch (currprefs.cpu_level)
+    {
+#ifdef CPUEMU_0
+       case 4:
+       case 6:
+       tbl = op_smalltbl_0_ff;
+       break;
+       case 3:
+       tbl = op_smalltbl_1_ff;
+       break;
+       case 2:
+       tbl = op_smalltbl_2_ff;
+       break;
+       case 1:
+       tbl = op_smalltbl_3_ff;
+       break;
+#endif
+       case 0:
+       tbl = op_smalltbl_4_ff;
+#ifdef CPUEMU_5
+       if (currprefs.cpu_compatible)
+           tbl = op_smalltbl_5_ff; /* prefetch */
+#endif
+#ifdef CPUEMU_6
+        if (currprefs.cpu_cycle_exact)
+           tbl = op_smalltbl_6_ff; /* prefetch and cycle-exact */
+#endif
+       break;
+    }
+
+    if (tbl == 0) {
+       write_log ("no CPU emulation cores available!");
+       abort ();
+    }
+    write_log ("Building CPU function table (%d %d %d).\n",
+       currprefs.cpu_level,
+       currprefs.cpu_cycle_exact ? -1 : currprefs.cpu_compatible ? 1 : 0,
+       currprefs.address_space_24);
+
+    for (opcode = 0; opcode < 65536; opcode++)
+       cpufunctbl[opcode] = op_illg_1;
+    for (i = 0; tbl[i].handler != NULL; i++) {
+       if (! tbl[i].specific)
+           cpufunctbl[tbl[i].opcode] = tbl[i].handler;
+    }
+    for (opcode = 0; opcode < 65536; opcode++) {
+       cpuop_func *f;
+
+       if (table68k[opcode].mnemo == i_ILLG || table68k[opcode].clev > currprefs.cpu_level)
+           continue;
+
+       if (table68k[opcode].handler != -1) {
+           f = cpufunctbl[table68k[opcode].handler];
+           if (f == op_illg_1)
+               abort();
+           cpufunctbl[opcode] = f;
+       }
+    }
+    for (i = 0; tbl[i].handler != NULL; i++) {
+       if (tbl[i].specific)
+           cpufunctbl[tbl[i].opcode] = tbl[i].handler;
+    }
+#ifdef JIT
+    build_comp();
+#endif
+}
+
+void fill_prefetch_slow (void)
+{
+#ifdef CPUEMU_6
+    if (currprefs.cpu_cycle_exact) {
+       regs.ir = get_word_ce (m68k_getpc ());
+       regs.irc = get_word_ce (m68k_getpc () + 2);
+    } else {
+#endif
+       regs.ir = get_word (m68k_getpc ());
+       regs.irc = get_word (m68k_getpc () + 2);
+#ifdef CPUEMU_6
+    }
+#endif
+}
+
+unsigned long cycles_mask, cycles_val;
+
+static void update_68k_cycles (void)
+{
+    cycles_mask = 0;
+    cycles_val = currprefs.m68k_speed;
+    if (currprefs.m68k_speed < 1) {
+       cycles_mask = 0xFFFFFFFF;
+       cycles_val = 0;
+    }
+}
+
+void check_prefs_changed_cpu (void)
+{
+    if (currprefs.cpu_level != changed_prefs.cpu_level
+       || currprefs.cpu_compatible != changed_prefs.cpu_compatible
+       || currprefs.cpu_cycle_exact != changed_prefs.cpu_cycle_exact) {
+
+       if (!currprefs.cpu_compatible && changed_prefs.cpu_compatible)
+           regs.ir = get_word (m68k_getpc()); /* non-prefetch to prefetch fix */
+
+       currprefs.cpu_level = changed_prefs.cpu_level;
+       currprefs.cpu_compatible = changed_prefs.cpu_compatible;
+       currprefs.cpu_cycle_exact = changed_prefs.cpu_cycle_exact;
+       currprefs.blitter_cycle_exact = changed_prefs.cpu_cycle_exact;
+       build_cpufunctbl ();
+    }
+    if (currprefs.m68k_speed != changed_prefs.m68k_speed) {
+       currprefs.m68k_speed = changed_prefs.m68k_speed;
+       reset_frame_rate_hack ();
+       update_68k_cycles ();
+    }
+    if (currprefs.cpu_idle != changed_prefs.cpu_idle) {
+       currprefs.cpu_idle = changed_prefs.cpu_idle;
+    }
+}
+
+void init_m68k (void)
+{
+    int i;
+
+    update_68k_cycles ();
+
+    for (i = 0 ; i < 256 ; i++) {
+       int j;
+       for (j = 0 ; j < 8 ; j++) {
+               if (i & (1 << j)) break;
+       }
+       movem_index1[i] = j;
+       movem_index2[i] = 7-j;
+       movem_next[i] = i & (~(1 << j));
+    }
+    for (i = 0 ; i < 256 ; i++) {
+       int j;
+       for (j = 7 ; j >= 0 ; j--) {
+               if (i & (1 << j)) break;
+       }
+       fpp_movem_index1[i] = 7-j;
+       fpp_movem_index2[i] = j;
+       fpp_movem_next[i] = i & (~(1 << j));
+    }
+#if COUNT_INSTRS
+    {
+       FILE *f = fopen (icountfilename (), "r");
+       memset (instrcount, 0, sizeof instrcount);
+       if (f) {
+           uae_u32 opcode, count, total;
+           char name[20];
+           write_log ("Reading instruction count file...\n");
+           fscanf (f, "Total: %lu\n", &total);
+           while (fscanf (f, "%lx: %lu %s\n", &opcode, &count, name) == 3) {
+               instrcount[opcode] = count;
+           }
+           fclose(f);
+       }
+    }
+#endif
+    write_log ("Building CPU table for configuration: 68");
+    regs.address_space_mask = 0xffffffff;
+    if (currprefs.cpu_compatible > 0) {
+       if (currprefs.address_space_24 && currprefs.cpu_level > 3)
+           currprefs.address_space_24 = 0;
+       if (currprefs.address_space_24 && currprefs.cpu_level > 1)
+           write_log ("EC");
+    }
+    switch (currprefs.cpu_level) {
+    case 1:
+        write_log ("010");
+        break;
+    case 2:
+        write_log ("020");
+        break;
+    case 3:
+        write_log ("020/881");
+        break;
+    case 4:
+        /* Who is going to miss the MMU anyway...? :-)  */
+        write_log ("040");
+        break;
+    case 6:
+        /* Who is going to miss the MMU anyway...? :-)  */
+        write_log ("060");
+        break;
+    default:
+        write_log ("000");
+        break;
+    }
+    if (currprefs.cpu_cycle_exact) {
+       if (currprefs.cpu_level == 0)
+           write_log (" prefetch and cycle-exact");
+       else
+           write_log (" ~cycle-exact");
+    } else if (currprefs.cpu_compatible)
+       write_log (" prefetch");
+    if (currprefs.address_space_24) {
+       regs.address_space_mask = 0x00ffffff;
+       write_log (" 24-bit addressing");
+    }
+    write_log ("\n");
+    
+    read_table68k ();
+    do_merges ();
+
+    write_log ("%d CPU functions\n", nr_cpuop_funcs);
+
+    build_cpufunctbl ();
+}
+
+void init_m68k_full (void)
+{
+    init_m68k ();
+    build_cpufunctbl ();
+    update_68k_cycles ();
+}
+
+struct regstruct regs, lastint_regs;
+static struct regstruct regs_backup[16];
+static int backup_pointer = 0;
+static long int m68kpc_offset;
+int lastint_no;
+
+#define get_ibyte_1(o) get_byte(regs.pc + (regs.pc_p - regs.pc_oldp) + (o) + 1)
+#define get_iword_1(o) get_word(regs.pc + (regs.pc_p - regs.pc_oldp) + (o))
+#define get_ilong_1(o) get_long(regs.pc + (regs.pc_p - regs.pc_oldp) + (o))
+       
+uae_s32 ShowEA (void *f, uae_u16 opcode, int reg, amodes mode, wordsizes size, char *buf)
+{
+    uae_u16 dp;
+    uae_s8 disp8;
+    uae_s16 disp16;
+    int r;
+    uae_u32 dispreg;
+    uaecptr addr;
+    uae_s32 offset = 0;
+    char buffer[80];
+
+    switch (mode){
+     case Dreg:
+       sprintf (buffer,"D%d", reg);
+       break;
+     case Areg:
+       sprintf (buffer,"A%d", reg);
+       break;
+     case Aind:
+       sprintf (buffer,"(A%d)", reg);
+       break;
+     case Aipi:
+       sprintf (buffer,"(A%d)+", reg);
+       break;
+     case Apdi:
+       sprintf (buffer,"-(A%d)", reg);
+       break;
+     case Ad16:
+       disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
+       addr = m68k_areg(regs,reg) + (uae_s16)disp16;
+       sprintf (buffer,"(A%d,$%04x) == $%08lx", reg, disp16 & 0xffff,
+                                       (unsigned long)addr);
+       break;
+     case Ad8r:
+       dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
+       disp8 = dp & 0xFF;
+       r = (dp & 0x7000) >> 12;
+       dispreg = dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r);
+       if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg);
+       dispreg <<= (dp >> 9) & 3;
+
+       if (dp & 0x100) {
+           uae_s32 outer = 0, disp = 0;
+           uae_s32 base = m68k_areg(regs,reg);
+           char name[10];
+           sprintf (name,"A%d, ",reg);
+           if (dp & 0x80) { base = 0; name[0] = 0; }
+           if (dp & 0x40) dispreg = 0;
+           if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; }
+           if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; }
+           base += disp;
+
+           if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; }
+           if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; }
+
+           if (!(dp & 4)) base += dispreg;
+           if (dp & 3) base = get_long (base);
+           if (dp & 4) base += dispreg;
+
+           addr = base + outer;
+           sprintf (buffer,"(%s%c%d.%c*%d+%ld)+%ld == $%08lx", name,
+                   dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W',
+                   1 << ((dp >> 9) & 3),
+                   disp,outer,
+                   (unsigned long)addr);
+       } else {
+         addr = m68k_areg(regs,reg) + (uae_s32)((uae_s8)disp8) + dispreg;
+         sprintf (buffer,"(A%d, %c%d.%c*%d, $%02x) == $%08lx", reg,
+              dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W',
+              1 << ((dp >> 9) & 3), disp8,
+              (unsigned long)addr);
+       }
+       break;
+     case PC16:
+       addr = m68k_getpc () + m68kpc_offset;
+       disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
+       addr += (uae_s16)disp16;
+       sprintf (buffer,"(PC,$%04x) == $%08lx", disp16 & 0xffff,(unsigned long)addr);
+       break;
+     case PC8r:
+       addr = m68k_getpc () + m68kpc_offset;
+       dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
+       disp8 = dp & 0xFF;
+       r = (dp & 0x7000) >> 12;
+       dispreg = dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r);
+       if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg);
+       dispreg <<= (dp >> 9) & 3;
+
+       if (dp & 0x100) {
+           uae_s32 outer = 0,disp = 0;
+           uae_s32 base = addr;
+           char name[10];
+           sprintf (name,"PC, ");
+           if (dp & 0x80) { base = 0; name[0] = 0; }
+           if (dp & 0x40) dispreg = 0;
+           if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; }
+           if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; }
+           base += disp;
+
+           if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; }
+           if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; }
+
+           if (!(dp & 4)) base += dispreg;
+           if (dp & 3) base = get_long (base);
+           if (dp & 4) base += dispreg;
+
+           addr = base + outer;
+           sprintf (buffer,"(%s%c%d.%c*%d+%ld)+%ld == $%08lx", name,
+                   dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W',
+                   1 << ((dp >> 9) & 3),
+                   disp,outer,
+                   (unsigned long)addr);
+       } else {
+         addr += (uae_s32)((uae_s8)disp8) + dispreg;
+         sprintf (buffer,"(PC, %c%d.%c*%d, $%02x) == $%08lx", dp & 0x8000 ? 'A' : 'D',
+               (int)r, dp & 0x800 ? 'L' : 'W',  1 << ((dp >> 9) & 3),
+               disp8, (unsigned long)addr);
+       }
+       break;
+     case absw:
+       sprintf (buffer,"$%08lx", (unsigned long)(uae_s32)(uae_s16)get_iword_1 (m68kpc_offset));
+       m68kpc_offset += 2;
+       break;
+     case absl:
+       sprintf (buffer,"$%08lx", (unsigned long)get_ilong_1 (m68kpc_offset));
+       m68kpc_offset += 4;
+       break;
+     case imm:
+       switch (size){
+        case sz_byte:
+           sprintf (buffer,"#$%02x", (unsigned int)(get_iword_1 (m68kpc_offset) & 0xff));
+           m68kpc_offset += 2;
+           break;
+        case sz_word:
+           sprintf (buffer,"#$%04x", (unsigned int)(get_iword_1 (m68kpc_offset) & 0xffff));
+           m68kpc_offset += 2;
+           break;
+        case sz_long:
+           sprintf (buffer,"#$%08lx", (unsigned long)(get_ilong_1 (m68kpc_offset)));
+           m68kpc_offset += 4;
+           break;
+        default:
+           break;
+       }
+       break;
+     case imm0:
+       offset = (uae_s32)(uae_s8)get_iword_1 (m68kpc_offset);
+       m68kpc_offset += 2;
+       sprintf (buffer,"#$%02x", (unsigned int)(offset & 0xff));
+       break;
+     case imm1:
+       offset = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset);
+       m68kpc_offset += 2;
+       buffer[0] = 0;
+        sprintf (buffer,"#$%04x", (unsigned int)(offset & 0xffff));
+       break;
+     case imm2:
+       offset = (uae_s32)get_ilong_1 (m68kpc_offset);
+       m68kpc_offset += 4;
+       sprintf (buffer,"#$%08lx", (unsigned long)offset);
+       break;
+     case immi:
+       offset = (uae_s32)(uae_s8)(reg & 0xff);
+       sprintf (buffer,"#$%08lx", (unsigned long)offset);
+       break;
+     default:
+       break;
+    }
+    if (buf == 0)
+       f_out (f, "%s", buffer);
+    else
+       strcat (buf, buffer);
+    return offset;
+}
+
+/* The plan is that this will take over the job of exception 3 handling -
+ * the CPU emulation functions will just do a longjmp to m68k_go whenever
+ * they hit an odd address. */
+static int verify_ea (int reg, amodes mode, wordsizes size, uae_u32 *val)
+{
+    uae_u16 dp;
+    uae_s8 disp8;
+    uae_s16 disp16;
+    int r;
+    uae_u32 dispreg;
+    uaecptr addr;
+    uae_s32 offset = 0;
+
+    switch (mode){
+     case Dreg:
+       *val = m68k_dreg (regs, reg);
+       return 1;
+     case Areg:
+       *val = m68k_areg (regs, reg);
+       return 1;
+
+     case Aind:
+     case Aipi:
+       addr = m68k_areg (regs, reg);
+       break;
+     case Apdi:
+       addr = m68k_areg (regs, reg);
+       break;
+     case Ad16:
+       disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
+       addr = m68k_areg(regs,reg) + (uae_s16)disp16;
+       break;
+     case Ad8r:
+       addr = m68k_areg (regs, reg);
+     d8r_common:
+       dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
+       disp8 = dp & 0xFF;
+       r = (dp & 0x7000) >> 12;
+       dispreg = dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r);
+       if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg);
+       dispreg <<= (dp >> 9) & 3;
+
+       if (dp & 0x100) {
+           uae_s32 outer = 0, disp = 0;
+           uae_s32 base = addr;
+           if (dp & 0x80) base = 0;
+           if (dp & 0x40) dispreg = 0;
+           if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; }
+           if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; }
+           base += disp;
+
+           if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; }
+           if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; }
+
+           if (!(dp & 4)) base += dispreg;
+           if (dp & 3) base = get_long (base);
+           if (dp & 4) base += dispreg;
+
+           addr = base + outer;
+       } else {
+         addr += (uae_s32)((uae_s8)disp8) + dispreg;
+       }
+       break;
+     case PC16:
+       addr = m68k_getpc () + m68kpc_offset;
+       disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
+       addr += (uae_s16)disp16;
+       break;
+     case PC8r:
+       addr = m68k_getpc () + m68kpc_offset;
+       goto d8r_common;
+     case absw:
+       addr = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset);
+       m68kpc_offset += 2;
+       break;
+     case absl:
+       addr = get_ilong_1 (m68kpc_offset);
+       m68kpc_offset += 4;
+       break;
+     case imm:
+       switch (size){
+        case sz_byte:
+           *val = get_iword_1 (m68kpc_offset) & 0xff;
+           m68kpc_offset += 2;
+           break;
+        case sz_word:
+           *val = get_iword_1 (m68kpc_offset) & 0xffff;
+           m68kpc_offset += 2;
+           break;
+        case sz_long:
+           *val = get_ilong_1 (m68kpc_offset);
+           m68kpc_offset += 4;
+           break;
+        default:
+           break;
+       }
+       return 1;
+     case imm0:
+       *val = (uae_s32)(uae_s8)get_iword_1 (m68kpc_offset);
+       m68kpc_offset += 2;
+       return 1;
+     case imm1:
+       *val = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset);
+       m68kpc_offset += 2;
+       return 1;
+     case imm2:
+       *val = get_ilong_1 (m68kpc_offset);
+       m68kpc_offset += 4;
+       return 1;
+     case immi:
+       *val = (uae_s32)(uae_s8)(reg & 0xff);
+       return 1;
+     default:
+       addr = 0;
+       break;
+    }
+    if ((addr & 1) == 0)
+       return 1;
+
+    last_addr_for_exception_3 = m68k_getpc () + m68kpc_offset;
+    last_fault_for_exception_3 = addr;
+    last_writeaccess_for_exception_3 = 0;
+    last_instructionaccess_for_exception_3 = 0;
+    return 0;
+}
+
+uae_u32 get_disp_ea_020 (uae_u32 base, uae_u32 dp)
+{
+    int reg = (dp >> 12) & 15;
+    uae_s32 regd = regs.regs[reg];
+    if ((dp & 0x800) == 0)
+       regd = (uae_s32)(uae_s16)regd;
+    regd <<= (dp >> 9) & 3;
+    if (dp & 0x100) {
+       uae_s32 outer = 0;
+       if (dp & 0x80) base = 0;
+       if (dp & 0x40) regd = 0;
+
+       if ((dp & 0x30) == 0x20) base += (uae_s32)(uae_s16)next_iword();
+       if ((dp & 0x30) == 0x30) base += next_ilong();
+
+       if ((dp & 0x3) == 0x2) outer = (uae_s32)(uae_s16)next_iword();
+       if ((dp & 0x3) == 0x3) outer = next_ilong();
+
+       if ((dp & 0x4) == 0) base += regd;
+       if (dp & 0x3) base = get_long (base);
+       if (dp & 0x4) base += regd;
+
+       return base + outer;
+    } else {
+       return base + (uae_s32)((uae_s8)dp) + regd;
+    }
+}
+
+uae_u32 get_disp_ea_000 (uae_u32 base, uae_u32 dp)
+{
+    int reg = (dp >> 12) & 15;
+    uae_s32 regd = regs.regs[reg];
+#if 1
+    if ((dp & 0x800) == 0)
+       regd = (uae_s32)(uae_s16)regd;
+    return base + (uae_s8)dp + regd;
+#else
+    /* Branch-free code... benchmark this again now that
+     * things are no longer inline.  */
+    uae_s32 regd16;
+    uae_u32 mask;
+    mask = ((dp & 0x800) >> 11) - 1;
+    regd16 = (uae_s32)(uae_s16)regd;
+    regd16 &= mask;
+    mask = ~mask;
+    base += (uae_s8)dp;
+    regd &= mask;
+    regd |= regd16;
+    return base + regd;
+#endif
+}
+
+void MakeSR (void)
+{
+#if 0
+    assert((regs.t1 & 1) == regs.t1);
+    assert((regs.t0 & 1) == regs.t0);
+    assert((regs.s & 1) == regs.s);
+    assert((regs.m & 1) == regs.m);
+    assert((XFLG & 1) == XFLG);
+    assert((NFLG & 1) == NFLG);
+    assert((ZFLG & 1) == ZFLG);
+    assert((VFLG & 1) == VFLG);
+    assert((CFLG & 1) == CFLG);
+#endif
+    regs.sr = ((regs.t1 << 15) | (regs.t0 << 14)
+              | (regs.s << 13) | (regs.m << 12) | (regs.intmask << 8)
+              | (GET_XFLG << 4) | (GET_NFLG << 3) | (GET_ZFLG << 2) | (GET_VFLG << 1)
+              | GET_CFLG);
+}
+
+void MakeFromSR (void)
+{
+    int oldm = regs.m;
+    int olds = regs.s;
+
+    SET_XFLG ((regs.sr >> 4) & 1);
+    SET_NFLG ((regs.sr >> 3) & 1);
+    SET_ZFLG ((regs.sr >> 2) & 1);
+    SET_VFLG ((regs.sr >> 1) & 1);
+    SET_CFLG (regs.sr & 1);
+    if (regs.t1 == ((regs.sr >> 15) & 1) &&
+        regs.t0 == ((regs.sr >> 14) & 1) &&
+        regs.s == ((regs.sr >> 13) & 1) &&
+       regs.m == ((regs.sr >> 12) & 1) &&
+        regs.intmask == ((regs.sr >> 8) & 7))
+           return;
+    regs.t1 = (regs.sr >> 15) & 1;
+    regs.t0 = (regs.sr >> 14) & 1;
+    regs.s = (regs.sr >> 13) & 1;
+    regs.m = (regs.sr >> 12) & 1;
+    regs.intmask = (regs.sr >> 8) & 7;
+    if (currprefs.cpu_level >= 2) {
+       if (olds != regs.s) {
+           if (olds) {
+               if (oldm)
+                   regs.msp = m68k_areg(regs, 7);
+               else
+                   regs.isp = m68k_areg(regs, 7);
+               m68k_areg(regs, 7) = regs.usp;
+           } else {
+               regs.usp = m68k_areg(regs, 7);
+               m68k_areg(regs, 7) = regs.m ? regs.msp : regs.isp;
+           }
+       } else if (olds && oldm != regs.m) {
+           if (oldm) {
+               regs.msp = m68k_areg(regs, 7);
+               m68k_areg(regs, 7) = regs.isp;
+           } else {
+               regs.isp = m68k_areg(regs, 7);
+               m68k_areg(regs, 7) = regs.msp;
+           }
+       }
+    } else {
+       regs.t0 = regs.m = 0;
+       if (olds != regs.s) {
+           if (olds) {
+               regs.isp = m68k_areg(regs, 7);
+               m68k_areg(regs, 7) = regs.usp;
+           } else {
+               regs.usp = m68k_areg(regs, 7);
+               m68k_areg(regs, 7) = regs.isp;
+           }
+       }
+    }
+
+    set_special (SPCFLAG_INT);
+    if (regs.t1 || regs.t0)
+       set_special (SPCFLAG_TRACE);
+    else
+       /* Keep SPCFLAG_DOTRACE, we still want a trace exception for
+          SR-modifying instructions (including STOP).  */
+       unset_special (SPCFLAG_TRACE);
+}
+
+static void exception_trace (int nr)
+{
+    unset_special (SPCFLAG_TRACE | SPCFLAG_DOTRACE);
+    if (regs.t1 && !regs.t0) {
+       /* trace stays pending if exception is div by zero, chk,
+        * trapv or trap #x
+        */
+       if (nr == 5 || nr == 6 || nr ==  7 || (nr >= 32 && nr <= 47))
+           set_special (SPCFLAG_DOTRACE);
+    }
+    regs.t1 = regs.t0 = regs.m = 0;
+}
+
+static void exception_debug (int nr)
+{
+    if (!exception_debugging)
+       return;
+    console_out ("Exception %d, PC=%08.8X\n", nr, m68k_getpc()); 
+}
+
+#ifdef CPUEMU_6
+
+/* cycle-exact exception handler, 68000 only */
+
+static void Exception_ce (int nr, uaecptr oldpc)
+{
+    uae_u32 currpc = m68k_getpc (), newpc;
+    int c;
+    int sv = regs.s;
+
+    exception_debug (nr);
+    compiler_flush_jsr_stack();
+    MakeSR();
+
+    c = 0;
+    switch (nr)
+    {
+       case 2: /* bus */
+       case 3: /* address */
+       c = 6;
+       break;
+       case 4: /* illegal instruction */
+       c = 6;
+       break;
+       case 5: /* divide by zero */
+       c = 10;
+       break;
+       case 6: /* chk */
+       c = 12;
+       break;
+       case 7: /* trapv */
+       c = 6;
+       break;
+       case 8: /* privilege */
+       c = 6;
+       break;
+       case 9: /* trace */
+       c = 6;
+       break;
+       case 25: /* interrupts */
+       case 26:
+       case 27:
+       case 28:
+       case 29:
+       case 30:
+       case 31:
+       c = 12;
+       break;
+       case 32: /* traps */
+       case 33:
+       case 34:
+       case 35:
+       case 36:
+       case 37:
+       case 38:
+       case 39:
+       case 40:
+       case 41:
+       case 42:
+       case 43:
+       case 44:
+       case 45:
+       case 46:
+       case 47:
+       c = 6;
+       break;
+    }
+    /* some delays are interleaved with stack pushes, not bothered yet..
+     */
+    if (c)
+       do_cycles (c * CYCLE_UNIT / 2);
+    if (!regs.s) {
+       regs.usp = m68k_areg(regs, 7);
+        m68k_areg(regs, 7) = regs.isp;
+       regs.s = 1;
+    }
+    if (nr == 2 || nr == 3) { /* 2=bus error,3=address error */
+        uae_u16 mode = (sv ? 4 : 0) | (last_instructionaccess_for_exception_3 ? 2 : 1);
+       mode |= last_writeaccess_for_exception_3 ? 0 : 16;
+        m68k_areg(regs, 7) -= 14;
+        /* fixme: bit3=I/N */
+        put_word_ce (m68k_areg(regs, 7) + 12, last_addr_for_exception_3);
+        put_word_ce (m68k_areg(regs, 7) + 8, regs.sr);
+        put_word_ce (m68k_areg(regs, 7) + 10, last_addr_for_exception_3 >> 16);
+        put_word_ce (m68k_areg(regs, 7) + 6, last_op_for_exception_3);
+        put_word_ce (m68k_areg(regs, 7) + 4, last_fault_for_exception_3);
+        put_word_ce (m68k_areg(regs, 7) + 0, mode);
+        put_word_ce (m68k_areg(regs, 7) + 2, last_fault_for_exception_3 >> 16);
+        write_log ("Exception %d at %x -> %x!\n", nr, currpc, get_long (4 * nr));
+        goto kludge_me_do;
+    }
+    m68k_areg (regs, 7) -= 6;
+    put_word_ce (m68k_areg(regs, 7) + 4, currpc);
+    put_word_ce (m68k_areg(regs, 7) + 0, regs.sr);
+    put_word_ce (m68k_areg(regs, 7) + 2, currpc >> 16);
+kludge_me_do:
+    newpc = get_word_ce (4 * nr) << 16;
+    newpc |= get_word_ce (4 * nr + 2);
+    if (newpc & 1) {
+       exception3 (regs.ir, m68k_getpc(), newpc);
+       return;
+    }
+    m68k_setpc (newpc);
+    fill_prefetch_slow ();
+    set_special(SPCFLAG_END_COMPILE);
+    exception_trace (nr);
+}
+#endif
+
+static void Exception_normal (int nr, uaecptr oldpc)
+{
+    uae_u32 currpc = m68k_getpc (), newpc;
+    int sv = regs.s;
+
+    exception_debug (nr);
+    compiler_flush_jsr_stack();
+    MakeSR();
+
+    if (!regs.s) {
+       regs.usp = m68k_areg(regs, 7);
+       if (currprefs.cpu_level >= 2)
+           m68k_areg(regs, 7) = regs.m ? regs.msp : regs.isp;
+       else
+           m68k_areg(regs, 7) = regs.isp;
+       regs.s = 1;
+    }
+    if (currprefs.cpu_level > 0) {
+       if (nr == 2 || nr == 3) {
+           int i;
+           if (currprefs.cpu_level >= 4) { /* 68040 */
+               if (nr == 2) {
+                   for (i = 0 ; i < 18 ; i++) {
+                       m68k_areg(regs, 7) -= 2;
+                       put_word (m68k_areg(regs, 7), 0);
+                   }
+                   m68k_areg(regs, 7) -= 4;
+                   put_long (m68k_areg(regs, 7), last_fault_for_exception_3);
+                   m68k_areg(regs, 7) -= 2;
+                   put_word (m68k_areg(regs, 7), 0);
+                   m68k_areg(regs, 7) -= 2;
+                   put_word (m68k_areg(regs, 7), 0);
+                   m68k_areg(regs, 7) -= 2;
+                   put_word (m68k_areg(regs, 7), 0);
+                   m68k_areg(regs, 7) -= 2;
+                   put_word (m68k_areg(regs, 7), 0x0140 | (sv ? 6 : 2)); /* SSW */
+                   m68k_areg(regs, 7) -= 4;
+                   put_long (m68k_areg(regs, 7), last_addr_for_exception_3);
+                   m68k_areg(regs, 7) -= 2;
+                   put_word (m68k_areg(regs, 7), 0x7000 + nr * 4);
+               } else {
+                   m68k_areg(regs, 7) -= 4;
+                   put_long (m68k_areg(regs, 7), last_fault_for_exception_3);
+                   m68k_areg(regs, 7) -= 2;
+                   put_word (m68k_areg(regs, 7), 0x2000 + nr * 4);
+               }
+           } else {
+               uae_u16 ssw = (sv ? 4 : 0) | (last_instructionaccess_for_exception_3 ? 2 : 1);
+               ssw |= last_writeaccess_for_exception_3 ? 0 : 0x40;
+               ssw |= 0x20;
+               for (i = 0 ; i < 36; i++) {
+                   m68k_areg(regs, 7) -= 2;
+                   put_word (m68k_areg(regs, 7), 0);
+               }
+               m68k_areg(regs, 7) -= 4;
+               put_long (m68k_areg(regs, 7), last_fault_for_exception_3);
+               m68k_areg(regs, 7) -= 2;
+               put_word (m68k_areg(regs, 7), 0);
+               m68k_areg(regs, 7) -= 2;
+               put_word (m68k_areg(regs, 7), 0);
+               m68k_areg(regs, 7) -= 2;
+               put_word (m68k_areg(regs, 7), 0);
+               m68k_areg(regs, 7) -= 2;
+               put_word (m68k_areg(regs, 7), ssw);
+               m68k_areg(regs, 7) -= 2;
+               put_word (m68k_areg(regs, 7), 0xb000 + nr * 4);
+           }
+           write_log ("Exception %d at %p!\n", nr, currpc);
+       } else if (nr ==5 || nr == 6 || nr == 7 || nr == 9) {
+           m68k_areg(regs, 7) -= 4;
+           put_long (m68k_areg(regs, 7), oldpc);
+           m68k_areg(regs, 7) -= 2;
+           put_word (m68k_areg(regs, 7), 0x2000 + nr * 4);
+       } else if (regs.m && nr >= 24 && nr < 32) { /* M + Interrupt */
+           m68k_areg(regs, 7) -= 2;
+           put_word (m68k_areg(regs, 7), nr * 4);
+           m68k_areg(regs, 7) -= 4;
+           put_long (m68k_areg(regs, 7), currpc);
+           m68k_areg(regs, 7) -= 2;
+           put_word (m68k_areg(regs, 7), regs.sr);
+           regs.sr |= (1 << 13);
+           regs.msp = m68k_areg(regs, 7);
+           m68k_areg(regs, 7) = regs.isp;
+           m68k_areg(regs, 7) -= 2;
+           put_word (m68k_areg(regs, 7), 0x1000 + nr * 4);
+       } else {
+           m68k_areg(regs, 7) -= 2;
+           put_word (m68k_areg(regs, 7), nr * 4);
+       }
+    } else if (nr == 2 || nr == 3) {
+       uae_u16 mode = (sv ? 4 : 0) | (last_instructionaccess_for_exception_3 ? 2 : 1);
+        mode |= last_writeaccess_for_exception_3 ? 0 : 16;
+       m68k_areg(regs, 7) -= 14;
+       /* fixme: bit3=I/N */
+       put_word (m68k_areg(regs, 7) + 0, mode);
+       put_long (m68k_areg(regs, 7) + 2, last_fault_for_exception_3);
+       put_word (m68k_areg(regs, 7) + 6, last_op_for_exception_3);
+       put_word (m68k_areg(regs, 7) + 8, regs.sr);
+       put_long (m68k_areg(regs, 7) + 10, last_addr_for_exception_3);
+       write_log ("Exception %d at %x -> %x!\n", nr, currpc, get_long (regs.vbr + 4*nr));
+       goto kludge_me_do;
+    }
+    m68k_areg(regs, 7) -= 4;
+    put_long (m68k_areg(regs, 7), currpc);
+    m68k_areg(regs, 7) -= 2;
+    put_word (m68k_areg(regs, 7), regs.sr);
+kludge_me_do:
+    newpc = get_long (regs.vbr + 4*nr);
+    if (newpc & 1) {
+       if ((nr == 2 || nr == 3) && currprefs.cpu_level >= 2)
+           uae_reset (1); /* there is nothing else we can do.. */
+       exception3 (regs.ir, m68k_getpc(), newpc);
+       return;
+    }
+    m68k_setpc (newpc);
+    set_special(SPCFLAG_END_COMPILE);
+    fill_prefetch_slow ();
+    exception_trace (nr);
+}
+
+void Exception (int nr, uaecptr oldpc)
+{
+#ifdef CPUEMU_6
+    if (currprefs.cpu_cycle_exact && currprefs.cpu_level == 0)
+       Exception_ce (nr, oldpc);
+    else
+#endif
+       Exception_normal (nr, oldpc);
+}
+
+void Interrupt (int nr)
+{
+#if 0
+    if (nr == 4)
+       write_log("irq %d at %x (%04.4X)\n", nr, m68k_getpc(), intena & intreq);
+#endif
+    regs.stopped = 0;
+    unset_special (SPCFLAG_STOP);
+    assert(nr < 8 && nr >= 0);
+    lastint_regs = regs;
+    lastint_no = nr;
+    Exception (nr + 24, 0);
+
+    regs.intmask = nr;
+    set_special (SPCFLAG_INT);
+}
+
+static uae_u32 caar, cacr, itt0, itt1, dtt0, dtt1, tc, mmusr, urp, srp, buscr, pcr;
+
+#ifdef CPUEMU_0
+
+static int movec_illg (int regno)
+{
+    int regno2 = regno & 0x7ff;
+    if (currprefs.cpu_level == 1) { /* 68010 */
+       if (regno2 < 2)
+           return 0;
+       return 1;
+    }
+    if (currprefs.cpu_level == 2 || currprefs.cpu_level == 3) { /* 68020 */
+       if (regno == 3) return 1; /* 68040 only */
+       if (regno2 < 4)
+           return 0;
+       return 1;
+    }
+    if (currprefs.cpu_level >= 4) { /* 68040 */
+       if (regno == 0x802) return 1; /* 68020 only */
+       if (regno2 < 8) return 0;
+       if (currprefs.cpu_level == 6 && regno2 == 8) /* 68060 only */
+           return 0;
+       return 1;
+    }
+    return 1;
+}
+
+int m68k_move2c (int regno, uae_u32 *regp)
+{
+    //write_log("move2c %04.4X <- %08.8X\n", regno, *regp);
+    if (movec_illg (regno)) {
+       op_illg (0x4E7B);
+       return 0;
+    } else {
+       switch (regno) {
+       case 0: regs.sfc = *regp & 7; break;
+       case 1: regs.dfc = *regp & 7; break;
+        case 2: 
+           cacr = *regp & (currprefs.cpu_level < 4 ? 0x3 : (currprefs.cpu_level == 4 ? 0x80008000 : 0xf8800e00));
+#ifdef JIT
+           if (currprefs.cpu_level < 4) {
+               set_cache_state(cacr & 1);
+               if (*regp & 0x08) {
+                   flush_icache(1);
+               }
+           } else {
+               set_cache_state((cacr & 0x8000) || 0);
+               if (*regp & 0x08) {   /* Just to be on the safe side */
+                   flush_icache(2);
+               }
+           }
+#endif
+           break;
+       case 3: tc = *regp & 0xc000; break;
+           /* Mask out fields that should be zero.  */
+       case 4: itt0 = *regp & 0xffffe364; break;
+       case 5: itt1 = *regp & 0xffffe364; break;
+       case 6: dtt0 = *regp & 0xffffe364; break;
+       case 7: dtt1 = *regp & 0xffffe364; break;
+       case 8: buscr = *regp & 0xf0000000; break;
+
+       case 0x800: regs.usp = *regp; break;
+       case 0x801: regs.vbr = *regp; break;
+       case 0x802: caar = *regp & 0xfc; break;
+       case 0x803: regs.msp = *regp; if (regs.m == 1) m68k_areg(regs, 7) = regs.msp; break;
+       case 0x804: regs.isp = *regp; if (regs.m == 0) m68k_areg(regs, 7) = regs.isp; break;
+       case 0x805: mmusr = *regp; break;
+       case 0x806: urp = *regp; break;
+       case 0x807: srp = *regp; break;
+       case 0x808: pcr = *regp & (0x40 | 2 | 1); break;
+       default:
+           op_illg (0x4E7B);
+           return 0;
+       }
+    }
+    return 1;
+}
+
+int m68k_movec2 (int regno, uae_u32 *regp)
+{
+    //write_log("movec2 %04.4X\n", regno);
+    if (movec_illg (regno)) {
+       op_illg (0x4E7A);
+       return 0;
+    } else {
+       switch (regno) {
+       case 0: *regp = regs.sfc; break;
+       case 1: *regp = regs.dfc; break;
+       case 2: *regp = cacr; break;
+       case 3: *regp = tc; break;
+       case 4: *regp = itt0; break;
+       case 5: *regp = itt1; break;
+       case 6: *regp = dtt0; break;
+       case 7: *regp = dtt1; break;
+       case 8: *regp = buscr; break;
+
+       case 0x800: *regp = regs.usp; break;
+       case 0x801: *regp = regs.vbr; break;
+       case 0x802: *regp = caar; break;
+       case 0x803: *regp = regs.m == 1 ? m68k_areg(regs, 7) : regs.msp; break;
+       case 0x804: *regp = regs.m == 0 ? m68k_areg(regs, 7) : regs.isp; break;
+       case 0x805: *regp = mmusr; break;
+       case 0x806: *regp = urp; break;
+       case 0x807: *regp = srp; break;
+       case 0x808: *regp = 0x04300100 | pcr; break;
+
+       default:
+           op_illg (0x4E7A);
+           return 0;
+       }
+    }
+    //write_log("-> %08.8X\n", *regp);
+    return 1;
+}
+
+STATIC_INLINE int
+div_unsigned(uae_u32 src_hi, uae_u32 src_lo, uae_u32 div, uae_u32 *quot, uae_u32 *rem)
+{
+       uae_u32 q = 0, cbit = 0;
+       int i;
+
+       if (div <= src_hi) {
+           return 1;
+       }
+       for (i = 0 ; i < 32 ; i++) {
+               cbit = src_hi & 0x80000000ul;
+               src_hi <<= 1;
+               if (src_lo & 0x80000000ul) src_hi++;
+               src_lo <<= 1;
+               q = q << 1;
+               if (cbit || div <= src_hi) {
+                       q |= 1;
+                       src_hi -= div;
+               }
+       }
+       *quot = q;
+       *rem = src_hi;
+       return 0;
+}
+
+void m68k_divl (uae_u32 opcode, uae_u32 src, uae_u16 extra, uaecptr oldpc)
+{
+#if defined(uae_s64)
+    if (src == 0) {
+       Exception (5, oldpc);
+       return;
+    }
+    if (extra & 0x800) {
+       /* signed variant */
+       uae_s64 a = (uae_s64)(uae_s32)m68k_dreg(regs, (extra >> 12) & 7);
+       uae_s64 quot, rem;
+
+       if (extra & 0x400) {
+           a &= 0xffffffffu;
+           a |= (uae_s64)m68k_dreg(regs, extra & 7) << 32;
+       }
+       rem = a % (uae_s64)(uae_s32)src;
+       quot = a / (uae_s64)(uae_s32)src;
+       if ((quot & UVAL64(0xffffffff80000000)) != 0
+           && (quot & UVAL64(0xffffffff80000000)) != UVAL64(0xffffffff80000000))
+       {
+           SET_VFLG (1);
+           SET_NFLG (1);
+           SET_CFLG (0);
+       } else {
+           if (((uae_s32)rem < 0) != ((uae_s64)a < 0)) rem = -rem;
+           SET_VFLG (0);
+           SET_CFLG (0);
+           SET_ZFLG (((uae_s32)quot) == 0);
+           SET_NFLG (((uae_s32)quot) < 0);
+           m68k_dreg(regs, extra & 7) = (uae_u32)rem;
+           m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)quot;
+       }
+    } else {
+       /* unsigned */
+       uae_u64 a = (uae_u64)(uae_u32)m68k_dreg(regs, (extra >> 12) & 7);
+       uae_u64 quot, rem;
+
+       if (extra & 0x400) {
+           a &= 0xffffffffu;
+           a |= (uae_u64)m68k_dreg(regs, extra & 7) << 32;
+       }
+       rem = a % (uae_u64)src;
+       quot = a / (uae_u64)src;
+       if (quot > 0xffffffffu) {
+           SET_VFLG (1);
+           SET_NFLG (1);
+           SET_CFLG (0);
+       } else {
+           SET_VFLG (0);
+           SET_CFLG (0);
+           SET_ZFLG (((uae_s32)quot) == 0);
+           SET_NFLG (((uae_s32)quot) < 0);
+           m68k_dreg(regs, extra & 7) = (uae_u32)rem;
+           m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)quot;
+       }
+    }
+#else
+    if (src == 0) {
+       Exception (5, oldpc);
+       return;
+    }
+    if (extra & 0x800) {
+       /* signed variant */
+       uae_s32 lo = (uae_s32)m68k_dreg(regs, (extra >> 12) & 7);
+       uae_s32 hi = lo < 0 ? -1 : 0;
+       uae_s32 save_high;
+       uae_u32 quot, rem;
+       uae_u32 sign;
+
+       if (extra & 0x400) {
+           hi = (uae_s32)m68k_dreg(regs, extra & 7);
+       }
+       save_high = hi;
+       sign = (hi ^ src);
+       if (hi < 0) {
+           hi = ~hi;
+           lo = -lo;
+           if (lo == 0) hi++;
+       }
+       if ((uae_s32)src < 0) src = -src;
+       if (div_unsigned(hi, lo, src, &quot, &rem) ||
+           (sign & 0x80000000) ? quot > 0x80000000 : quot > 0x7fffffff) {
+           SET_VFLG (1);
+           SET_NFLG (1);
+           SET_CFLG (0);
+       } else {
+           if (sign & 0x80000000) quot = -quot;
+           if (((uae_s32)rem < 0) != (save_high < 0)) rem = -rem;
+           SET_VFLG (0);
+           SET_CFLG (0);
+           SET_ZFLG (((uae_s32)quot) == 0);
+           SET_NFLG (((uae_s32)quot) < 0);
+           m68k_dreg(regs, extra & 7) = rem;
+           m68k_dreg(regs, (extra >> 12) & 7) = quot;
+       }
+    } else {
+       /* unsigned */
+       uae_u32 lo = (uae_u32)m68k_dreg(regs, (extra >> 12) & 7);
+       uae_u32 hi = 0;
+       uae_u32 quot, rem;
+
+       if (extra & 0x400) {
+           hi = (uae_u32)m68k_dreg(regs, extra & 7);
+       }
+       if (div_unsigned(hi, lo, src, &quot, &rem)) {
+           SET_VFLG (1);
+           SET_NFLG (1);
+           SET_CFLG (0);
+       } else {
+           SET_VFLG (0);
+           SET_CFLG (0);
+           SET_ZFLG (((uae_s32)quot) == 0);
+           SET_NFLG (((uae_s32)quot) < 0);
+           m68k_dreg(regs, extra & 7) = rem;
+           m68k_dreg(regs, (extra >> 12) & 7) = quot;
+       }
+    }
+#endif
+}
+
+STATIC_INLINE void
+mul_unsigned(uae_u32 src1, uae_u32 src2, uae_u32 *dst_hi, uae_u32 *dst_lo)
+{
+       uae_u32 r0 = (src1 & 0xffff) * (src2 & 0xffff);
+       uae_u32 r1 = ((src1 >> 16) & 0xffff) * (src2 & 0xffff);
+       uae_u32 r2 = (src1 & 0xffff) * ((src2 >> 16) & 0xffff);
+       uae_u32 r3 = ((src1 >> 16) & 0xffff) * ((src2 >> 16) & 0xffff);
+       uae_u32 lo;
+
+       lo = r0 + ((r1 << 16) & 0xffff0000ul);
+       if (lo < r0) r3++;
+       r0 = lo;
+       lo = r0 + ((r2 << 16) & 0xffff0000ul);
+       if (lo < r0) r3++;
+       r3 += ((r1 >> 16) & 0xffff) + ((r2 >> 16) & 0xffff);
+       *dst_lo = lo;
+       *dst_hi = r3;
+}
+
+void m68k_mull (uae_u32 opcode, uae_u32 src, uae_u16 extra)
+{
+#if defined(uae_s64)
+    if (extra & 0x800) {
+       /* signed variant */
+       uae_s64 a = (uae_s64)(uae_s32)m68k_dreg(regs, (extra >> 12) & 7);
+
+       a *= (uae_s64)(uae_s32)src;
+       SET_VFLG (0);
+       SET_CFLG (0);
+       SET_ZFLG (a == 0);
+       SET_NFLG (a < 0);
+       if (extra & 0x400)
+           m68k_dreg(regs, extra & 7) = (uae_u32)(a >> 32);
+       else if ((a & UVAL64(0xffffffff80000000)) != 0
+                && (a & UVAL64(0xffffffff80000000)) != UVAL64(0xffffffff80000000))
+       {
+           SET_VFLG (1);
+       }
+       m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)a;
+    } else {
+       /* unsigned */
+       uae_u64 a = (uae_u64)(uae_u32)m68k_dreg(regs, (extra >> 12) & 7);
+
+       a *= (uae_u64)src;
+       SET_VFLG (0);
+       SET_CFLG (0);
+       SET_ZFLG (a == 0);
+       SET_NFLG (((uae_s64)a) < 0);
+       if (extra & 0x400)
+           m68k_dreg(regs, extra & 7) = (uae_u32)(a >> 32);
+       else if ((a & UVAL64(0xffffffff00000000)) != 0) {
+           SET_VFLG (1);
+       }
+       m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)a;
+    }
+#else
+    if (extra & 0x800) {
+       /* signed variant */
+       uae_s32 src1,src2;
+       uae_u32 dst_lo,dst_hi;
+       uae_u32 sign;
+
+       src1 = (uae_s32)src;
+       src2 = (uae_s32)m68k_dreg(regs, (extra >> 12) & 7);
+       sign = (src1 ^ src2);
+       if (src1 < 0) src1 = -src1;
+       if (src2 < 0) src2 = -src2;
+       mul_unsigned((uae_u32)src1,(uae_u32)src2,&dst_hi,&dst_lo);
+       if (sign & 0x80000000) {
+               dst_hi = ~dst_hi;
+               dst_lo = -dst_lo;
+               if (dst_lo == 0) dst_hi++;
+       }
+       SET_VFLG (0);
+       SET_CFLG (0);
+       SET_ZFLG (dst_hi == 0 && dst_lo == 0);
+       SET_NFLG (((uae_s32)dst_hi) < 0);
+       if (extra & 0x400)
+           m68k_dreg(regs, extra & 7) = dst_hi;
+       else if ((dst_hi != 0 || (dst_lo & 0x80000000) != 0)
+                && ((dst_hi & 0xffffffff) != 0xffffffff
+                    || (dst_lo & 0x80000000) != 0x80000000))
+       {
+           SET_VFLG (1);
+       }
+       m68k_dreg(regs, (extra >> 12) & 7) = dst_lo;
+    } else {
+       /* unsigned */
+       uae_u32 dst_lo,dst_hi;
+
+       mul_unsigned(src,(uae_u32)m68k_dreg(regs, (extra >> 12) & 7),&dst_hi,&dst_lo);
+
+       SET_VFLG (0);
+       SET_CFLG (0);
+       SET_ZFLG (dst_hi == 0 && dst_lo == 0);
+       SET_NFLG (((uae_s32)dst_hi) < 0);
+       if (extra & 0x400)
+           m68k_dreg(regs, extra & 7) = dst_hi;
+       else if (dst_hi != 0) {
+           SET_VFLG (1);
+       }
+       m68k_dreg(regs, (extra >> 12) & 7) = dst_lo;
+    }
+#endif
+}
+
+#endif
+
+static char* ccnames[] =
+{ "T ","F ","HI","LS","CC","CS","NE","EQ",
+  "VC","VS","PL","MI","GE","LT","GT","LE" };
+
+void m68k_reset (void)
+{
+    regs.kick_mask = 0x00F80000;
+    regs.spcflags = 0;
+    if (savestate_state == STATE_RESTORE || savestate_state == STATE_REWIND) {
+        m68k_setpc (regs.pc);
+       /* MakeFromSR() must not swap stack pointer */
+       regs.s = (regs.sr >> 13) & 1;
+       MakeFromSR();
+       /* set stack pointer */
+       if (regs.s)
+           m68k_areg(regs, 7) = regs.isp;
+       else
+           m68k_areg(regs, 7) = regs.usp;
+       return;
+    }
+
+    m68k_areg (regs, 7) = get_long (0x00f80000);
+    m68k_setpc (get_long (0x00f80004));
+    regs.s = 1;
+    regs.m = 0;
+    regs.stopped = 0;
+    regs.t1 = 0;
+    regs.t0 = 0;
+    SET_ZFLG (0);
+    SET_XFLG (0);
+    SET_CFLG (0);
+    SET_VFLG (0);
+    SET_NFLG (0);
+    regs.intmask = 7;
+    regs.vbr = regs.sfc = regs.dfc = 0;
+#ifdef FPUEMU
+    regs.fpcr = regs.fpsr = regs.fpiar = 0;
+    regs.fp_result=1;
+    regs.irc = 0xffff;
+#endif
+    fill_prefetch_slow ();
+}
+
+STATIC_INLINE int in_rom (uaecptr pc)
+{
+    return (munge24 (pc) & 0xFFF80000) == 0xF80000;
+}
+
+STATIC_INLINE int in_rtarea (uaecptr pc)
+{
+    return (munge24 (pc) & 0xFFFF0000) == RTAREA_BASE;
+}
+
+unsigned long REGPARAM2 op_illg (uae_u32 opcode)
+{
+    uaecptr pc = m68k_getpc ();
+    static int warned;
+
+    if (cloanto_rom && (opcode & 0xF100) == 0x7100) {
+       m68k_dreg (regs, (opcode >> 9) & 7) = (uae_s8)(opcode & 0xFF);
+       m68k_incpc (2);
+       fill_prefetch_slow ();
+       return 4;
+    }
+
+    compiler_flush_jsr_stack ();
+    if (opcode == 0x4E7B && get_long (0x10) == 0 && in_rom (pc)) {
+       gui_message ("Your Kickstart requires a 68020 CPU. Giving up.\n");
+       broken_in = 1;
+       set_special (SPCFLAG_BRK);
+       quit_program = 1;
+    }
+
+#ifdef AUTOCONFIG
+    if (opcode == 0xFF0D) {
+       if (in_rom (pc)) {
+           /* This is from the dummy Kickstart replacement */
+           uae_u16 arg = get_iword (2);
+           m68k_incpc (4);
+           ersatz_perform (arg);
+           fill_prefetch_slow ();
+           return 4;
+       } else if (in_rtarea (pc)) {
+           /* User-mode STOP replacement */
+           m68k_setstopped (1);
+           return 4;
+       }
+    }
+
+    if ((opcode & 0xF000) == 0xA000 && in_rtarea (pc)) {
+       /* Calltrap. */
+       m68k_incpc(2);
+       call_calltrap (opcode & 0xFFF);
+       fill_prefetch_slow ();
+       return 4;
+    }
+#endif
+
+    if ((opcode & 0xF000) == 0xF000) {
+       if (warned < 20) {
+           write_log ("B-Trap %x at %x (%p)\n", opcode, m68k_getpc () + m68kpc_offset, regs.pc_p);
+           warned++;
+       }
+       Exception(0xB,0);
+       return 4;
+    }
+    if ((opcode & 0xF000) == 0xA000) {
+#ifdef AUTOCONFIG
+       if (in_rtarea (pc)) {
+           /* Calltrap. */
+           call_calltrap (opcode & 0xFFF);
+       }
+#endif
+       Exception(0xA,0);
+       return 4;
+    }
+    if (warned < 20) {
+        write_log ("Illegal instruction: %04x at %08.8X -> %08.8X\n", opcode, pc, get_long (regs.vbr + 0x10));
+        warned++;
+    }
+
+    Exception (4,0);
+    return 4;
+}
+
+#ifdef CPUEMU_0
+
+void mmu_op(uae_u32 opcode, uae_u16 extra)
+{
+    if ((opcode & 0xFE0) == 0x0500) {
+       /* PFLUSH */
+       mmusr = 0;
+       write_log ("PFLUSH @$%lx\n", m68k_getpc());
+    } else if ((opcode & 0x0FD8) == 0x548) {
+       /* PTEST */
+       write_log ("PTEST @$%lx\n", m68k_getpc());
+    } else
+       op_illg (opcode);
+}
+
+#endif
+
+static int n_insns = 0, n_spcinsns = 0;
+
+static uaecptr last_trace_ad = 0;
+
+static void do_trace (void)
+{
+    if (regs.t0 && currprefs.cpu_level >= 2) {
+       uae_u16 opcode;
+       /* should also include TRAP, CHK, SR modification FPcc */
+       /* probably never used so why bother */
+       /* We can afford this to be inefficient... */
+       m68k_setpc (m68k_getpc ());
+       fill_prefetch_slow ();
+       opcode = get_word (regs.pc);
+       if (opcode == 0x4e72            /* RTE */
+           || opcode == 0x4e74                 /* RTD */
+           || opcode == 0x4e75                 /* RTS */
+           || opcode == 0x4e77                 /* RTR */
+           || opcode == 0x4e76                 /* TRAPV */
+           || (opcode & 0xffc0) == 0x4e80      /* JSR */
+           || (opcode & 0xffc0) == 0x4ec0      /* JMP */
+           || (opcode & 0xff00) == 0x6100  /* BSR */
+           || ((opcode & 0xf000) == 0x6000     /* Bcc */
+               && cctrue((opcode >> 8) & 0xf))
+           || ((opcode & 0xf0f0) == 0x5050 /* DBcc */
+               && !cctrue((opcode >> 8) & 0xf)
+               && (uae_s16)m68k_dreg(regs, opcode & 7) != 0))
+       {
+           last_trace_ad = m68k_getpc ();
+           unset_special (SPCFLAG_TRACE);
+           set_special (SPCFLAG_DOTRACE);
+       }
+    } else if (regs.t1) {
+       last_trace_ad = m68k_getpc ();
+       unset_special (SPCFLAG_TRACE);
+       set_special (SPCFLAG_DOTRACE);
+    }
+}
+
+#define CPU_IDLE_LINES 60
+
+static int do_specialties (int cycles)
+{
+    #ifdef ACTION_REPLAY
+    #ifdef ACTION_REPLAY_HRTMON
+    if ((regs.spcflags & SPCFLAG_ACTION_REPLAY) && hrtmon_flag != ACTION_REPLAY_INACTIVE) {
+       int isinhrt = (m68k_getpc() >= hrtmem_start && m68k_getpc() < hrtmem_start + hrtmem_size);
+       /* exit from HRTMon? */
+       if(hrtmon_flag == ACTION_REPLAY_HIDE && !isinhrt) hrtmon_hide();
+       /* HRTMon breakpoint? (not via IRQ7) */
+       if(hrtmon_flag == ACTION_REPLAY_IDLE && isinhrt) hrtmon_breakenter();
+       if(hrtmon_flag == ACTION_REPLAY_ACTIVE && isinhrt) hrtmon_flag = ACTION_REPLAY_HIDE;
+       if(hrtmon_flag == ACTION_REPLAY_ACTIVATE) hrtmon_enter();
+       if(!(regs.spcflags & ~SPCFLAG_ACTION_REPLAY)) return 0;
+    }
+    #endif
+    if ((regs.spcflags & SPCFLAG_ACTION_REPLAY) && action_replay_flag != ACTION_REPLAY_INACTIVE ) 
+    {
+       /*if(action_replay_flag == ACTION_REPLAY_ACTIVE && !is_ar_pc_in_rom())*/
+       /*      write_log("PC:%p\n",m68k_getpc());*/
+               
+       if(action_replay_flag == ACTION_REPLAY_ACTIVATE || action_replay_flag == ACTION_REPLAY_DORESET) 
+           action_replay_enter();
+       if(action_replay_flag == ACTION_REPLAY_HIDE && !is_ar_pc_in_rom()) 
+       {
+           action_replay_hide();
+           unset_special(SPCFLAG_ACTION_REPLAY);
+       }
+       if (action_replay_flag == ACTION_REPLAY_WAIT_PC )
+       {
+           /*write_log("Waiting for PC: %p, current PC= %p\n",wait_for_pc, m68k_getpc());*/
+           if (m68k_getpc() == wait_for_pc)
+           {
+               action_replay_flag = ACTION_REPLAY_ACTIVATE; /* Activate after next instruction. */
+           }
+       }
+    }
+    #endif
+
+    if (regs.spcflags & SPCFLAG_COPPER)
+       do_copper ();
+
+    /*n_spcinsns++;*/
+#ifdef JIT
+    unset_special(SPCFLAG_END_COMPILE);   /* has done its job */
+#endif
+
+    while ((regs.spcflags & SPCFLAG_BLTNASTY) && dmaen (DMA_BLITTER) && cycles > 0 && !currprefs.blitter_cycle_exact) {
+        int c = blitnasty();
+        if (c > 0) {
+            cycles -= c * CYCLE_UNIT * 2;
+            if (cycles < CYCLE_UNIT)
+               cycles = 0;
+       } else
+           c = 4;
+       do_cycles (c * CYCLE_UNIT);
+       if (regs.spcflags & SPCFLAG_COPPER)
+           do_copper ();
+    }
+
+#ifdef JIT
+    run_compiled_code();
+#endif
+    if (regs.spcflags & SPCFLAG_DOTRACE) {
+       Exception (9,last_trace_ad);
+    }
+    while (regs.spcflags & SPCFLAG_STOP) {
+       do_cycles (4 * CYCLE_UNIT);
+       if (regs.spcflags & SPCFLAG_COPPER)
+           do_copper ();
+       if (regs.spcflags & SPCFLAG_INT) {
+           int intr = intlev ();
+           if (intr != -1 && intr > regs.intmask)
+               Interrupt (intr);
+       }
+       if ((regs.spcflags & (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE))) {
+           unset_special (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE);
+           return 1;
+       }
+#ifdef JIT
+       if (currprefs.cpu_idle && currprefs.m68k_speed != 0 && ((regs.spcflags & SPCFLAG_STOP)) == SPCFLAG_STOP) {
+           /* sleep 1ms if STOP-instruction is executed */
+           if (1) {
+               extern uae_u8* compiled_code;
+               static int sleepcnt, lvpos, zerocnt;
+               if (vpos != lvpos) {
+                   sleepcnt--;
+                   if (pissoff == 0 && compiled_code && --zerocnt < 0) {
+                       sleepcnt = -1;
+                       zerocnt = currprefs.cpu_idle / 2;
+                   }
+                   lvpos = vpos;
+                   if (sleepcnt < 0) {
+                       sleepcnt = currprefs.cpu_idle;
+                       sleep_millis (1);
+                   }
+               }
+           }
+       }
+#endif
+    }
+    if (regs.spcflags & SPCFLAG_TRACE)
+       do_trace ();
+
+    /* interrupt takes at least 2 cycles (maybe 4) to reach the CPU and
+     * there are programs that require this delay (which is not too surprising..)
+     */
+    if (regs.spcflags & SPCFLAG_INT) {
+        int intr = intlev ();
+       if (intr != -1 && intr > regs.intmask)
+           Interrupt (intr);
+    }
+
+    if ((regs.spcflags & (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE))) {
+       unset_special (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE);
+       return 1;
+    }
+    return 0;
+}
+
+static uae_u32 pcs[1000];
+
+
+#ifndef CPUEMU_5
+
+static void m68k_run_1 (void)
+{
+}
+
+#else
+
+/* It's really sad to have two almost identical functions for this, but we
+   do it all for performance... :(
+   This version emulates 68000's prefetch "cache" */
+static void m68k_run_1 (void)
+{
+    for (;;) {
+       int cycles;
+       uae_u32 opcode = regs.ir;
+#if 0
+       int pc = m68k_getpc();
+       if (pc != pcs[0] && (pc < 0xd00000 || pc > 0x1000000)) {
+           memmove (pcs + 1, pcs, 998 * 4);
+           pcs[0] = pc;
+           //write_log("%08.8X-%04.4X ",pc, opcode);
+       }
+#endif
+       /* assert (!regs.stopped && !(regs.spcflags & SPCFLAG_STOP)); */
+/*     regs_backup[backup_pointer = (backup_pointer + 1) % 16] = regs;*/
+#if COUNT_INSTRS == 2
+       if (table68k[opcode].handler != -1)
+           instrcount[table68k[opcode].handler]++;
+#elif COUNT_INSTRS == 1
+       instrcount[opcode]++;
+#endif
+#if defined X86_ASSEMBLY
+       __asm__ __volatile__("\tcall *%%ebx"
+                            : "=&a" (cycles) : "b" (cpufunctbl[opcode]), "0" (opcode)
+                            : "%edx", "%ecx",
+                            "%esi", "%edi", "%ebp", "memory", "cc");
+#else
+       cycles = (*cpufunctbl[opcode])(opcode);
+#endif
+       /*n_insns++;*/
+       cycles &= cycles_mask;
+       cycles |= cycles_val;
+       do_cycles (cycles);
+       if (regs.spcflags) {
+           if (do_specialties (cycles))
+               return;
+       }
+       if (!currprefs.cpu_compatible || (currprefs.cpu_cycle_exact && currprefs.cpu_level == 0))
+           return;
+    }
+}
+
+#endif
+
+#ifndef CPUEMU_6
+
+static void m68k_run_1_ce (void)
+{
+}
+
+#else
+
+/* cycle-exact m68k_run() */
+
+static void m68k_run_1_ce (void)
+{
+    for (;;) {
+       uae_u32 opcode = regs.ir;
+#if 0
+       int pc = m68k_getpc();
+       if (pc != pcs[0]) {
+           memmove (pcs + 1, pcs, 998 * 4);
+           pcs[0] = pc;
+       }
+#endif
+       (*cpufunctbl[opcode])(opcode);
+       if (regs.spcflags) {
+           if (do_specialties (0))
+               return;
+       }
+       if (!currprefs.cpu_cycle_exact || currprefs.cpu_level > 0)
+           return;
+    }
+}
+#endif
+
+#ifdef JIT  /* Completely different run_2 replacement */
+
+void do_nothing(void)
+{
+    /* What did you expect this to do? */
+    do_cycles(0);
+    /* I bet you didn't expect *that* ;-) */
+}
+
+#ifdef JIT
+
+void exec_nostats(void)
+{
+    int new_cycles;
+
+    for (;;) 
+    { 
+       uae_u16 opcode = get_iword(0);
+#if defined X86_ASSEMBLY
+       __asm__ __volatile__("\tpush %%ebp\n\tcall *%%ebx\n\tpop %%ebp" /* FIXME */
+                            : "=&a" (new_cycles) 
+                            : "b" (cpufunctbl[opcode]), "0" (opcode)
+                            : "%edx", "%ecx", "%esi", "%edi", 
+                            "%ebp", "memory", "cc");
+#else
+       new_cycles = (*cpufunctbl[opcode])(opcode);
+#endif
+
+       new_cycles &= cycles_mask;
+       new_cycles |= cycles_val;
+       do_cycles (new_cycles);
+       
+       if (end_block(opcode) ||
+           regs.spcflags) {
+           return; /* We will deal with the spcflags in the caller */
+       }
+    }
+}
+
+static int triggered;
+
+void execute_normal(void)
+{
+    int blocklen;
+    cpu_history pc_hist[MAXRUN];
+    int new_cycles;
+    int total_cycles;
+
+    if (check_for_cache_miss())
+       return;
+    total_cycles = 0;
+    blocklen = 0;
+    start_pc_p = regs.pc_oldp;  
+    start_pc = regs.pc; 
+    for (;;) 
+    {    /* Take note: This is the do-it-normal loop */
+       uae_u16 opcode = get_iword (0);
+
+       special_mem = DISTRUST_CONSISTENT_MEM;
+       pc_hist[blocklen].location = (uae_u16*)regs.pc_p;
+#if defined X86_ASSEMBLY
+       __asm__ __volatile__("\tpush %%ebp\n\tcall *%%ebx\n\tpop %%ebp" /* FIXME */
+                            : "=&a" (new_cycles) 
+                            : "b" (cpufunctbl[opcode]), "0" (opcode)
+                            : "%edx", "%ecx", "%esi", "%edi", 
+                            "%ebp", "memory", "cc");
+#else
+       new_cycles = (*cpufunctbl[opcode])(opcode);
+#endif
+       new_cycles &= cycles_mask;
+       new_cycles |= cycles_val;
+       do_cycles (new_cycles);
+       total_cycles += new_cycles;
+       pc_hist[blocklen].specmem = special_mem;
+       blocklen++;
+       if (end_block(opcode) || blocklen >= MAXRUN || regs.spcflags) {
+           compile_block(pc_hist,blocklen,total_cycles);
+           return; /* We will deal with the spcflags in the caller */
+       }
+       /* No need to check regs.spcflags, because if they were set,
+          we'd have ended up inside that "if" */
+    }
+}
+#endif
+
+typedef void compiled_handler(void);
+
+static void m68k_run_2a (void)
+{
+    for (;;) {  
+#if defined X86_ASSEMBLY 
+       __asm__ __volatile__(
+           "\tpush %%ebp\n\tcall *%0\n\tpop %%ebp"  /* FIXME */
+           :: "m" (cache_tags[cacheline(regs.pc_p)].handler) 
+           : "%edx", "%ecx", "%eax",
+           "%esi", "%ebx", "%edi", "%ebp", "memory", "cc");
+#else
+       ((compiled_handler*)(pushall_call_handler))();
+#endif
+       /* Whenever we return from that, we should check spcflags */
+       if (regs.spcflags) {
+           if (do_specialties (0)) {
+               return;
+           }
+       }
+    }
+}
+#endif
+
+#ifndef CPUEMU_0
+
+static void m68k_run_2 (void)
+{
+}
+
+#else
+
+//#define DEBUG_CD32IO
+#ifdef DEBUG_CD32IO
+
+static uae_u32 cd32nextpc, cd32request;
+
+static void out_cd32io2(void)
+{
+    uae_u32 request = cd32request;
+    write_log ("ACTUAL=%d ERROR=%d\n", get_long (request + 32), get_byte (request + 31));
+    cd32nextpc = 0;
+    cd32request = 0;
+}
+
+static void out_cd32io (uae_u32 pc)
+{
+    char out[100];
+    int ioreq = 0;
+    uae_u32 request = m68k_areg (regs, 1);
+
+    out[0] = 0;
+    switch (pc)
+       {
+       case 0xe57cc0:
+       sprintf (out, "opendevice");
+       break;
+       case 0xe57ce6:
+       sprintf (out, "closedevice");
+       break;
+       case 0xe57e44:
+       sprintf (out, "beginio");
+       ioreq = 1;
+       break;
+       case 0xe57ef2:
+       sprintf (out, "abortio");
+       ioreq = 1;
+       break;
+    }
+    if (out[0] == 0)
+       return;
+    if (cd32request)
+       write_log ("old request still not returned!\n");
+    cd32request = request;
+    cd32nextpc = get_long(m68k_areg (regs, 7));
+    write_log("%s A1=%08.8X\n", out, request);
+    if (ioreq) {
+       write_log ("CMD=%d DATA=%08.8X LEN=%d %OFF=%d\n",
+       get_word(request + 28),get_long(request + 40),get_long(request + 36),get_long(request + 44));
+    }
+}
+#endif
+
+/* emulate simple prefetch  */
+static void m68k_run_2p (void)
+{
+    uae_u32 prefetch, prefetch_pc;
+
+    prefetch_pc = m68k_getpc ();
+    prefetch = get_long (prefetch_pc);
+    for (;;) {
+       int cycles;
+       uae_u32 opcode;
+       uae_u32 pc = m68k_getpc ();
+       if (pc == prefetch_pc)
+           opcode = prefetch >> 16;
+       else if (pc == prefetch_pc + 2)
+           opcode = prefetch & 0xffff;
+       else
+           opcode = get_word (pc);
+#if COUNT_INSTRS == 2
+       if (table68k[opcode].handler != -1)
+           instrcount[table68k[opcode].handler]++;
+#elif COUNT_INSTRS == 1
+       instrcount[opcode]++;
+#endif
+       prefetch_pc = m68k_getpc () + 2;
+       prefetch = get_long (prefetch_pc);
+       cycles = (*cpufunctbl[opcode])(opcode);
+       cycles &= cycles_mask;
+       cycles |= cycles_val;
+        do_cycles (cycles);
+       if (regs.spcflags) {
+           if (do_specialties (cycles))
+               return;
+       }
+    }
+}
+
+/* Same thing, but don't use prefetch to get opcode.  */
+static void m68k_run_2 (void)
+{
+    for (;;) {
+       int cycles;
+       uae_u32 opcode = get_iword (0);
+
+#ifdef DEBUG_CD32IO
+       {
+           int pc = m68k_getpc();
+           if (pc >= 0xe57cc0 && pc <= 0xe57ef2)
+               out_cd32io (pc);
+           if (pc == cd32nextpc)
+               out_cd32io2 ();
+       }
+#endif
+#if 0
+       int pc = m68k_getpc();
+       if (pc == 0xd0000) {
+           write_log ("%x %x %x %x\n", pcs[0], pcs[1], pcs[2], pcs[3]);
+           activate_debugger();
+       }
+       if (pc != pcs[0] && pc <0xd00000) {
+           memmove (pcs + 1, pcs, 998 * 4);
+           pcs[0] = pc;
+       }
+#endif
+       /* assert (!regs.stopped && !(regs.spcflags & SPCFLAG_STOP)); */
+/*     regs_backup[backup_pointer = (backup_pointer + 1) % 16] = regs;*/
+#if COUNT_INSTRS == 2
+       if (table68k[opcode].handler != -1)
+           instrcount[table68k[opcode].handler]++;
+#elif COUNT_INSTRS == 1
+       instrcount[opcode]++;
+#endif
+#if defined X86_ASSEMBLY
+       __asm__ __volatile__("\tcall *%%ebx"
+                            : "=&a" (cycles) : "b" (cpufunctbl[opcode]), "0" (opcode)
+                            : "%edx", "%ecx",
+                            "%esi", "%edi", "%ebp", "memory", "cc");
+#else
+       cycles = (*cpufunctbl[opcode])(opcode);
+#endif
+
+       /*n_insns++;*/
+       cycles &= cycles_mask;
+       cycles |= cycles_val;
+        do_cycles (cycles);
+       if (regs.spcflags) {
+           if (do_specialties (cycles))
+               return;
+       }
+    }
+}
+
+#endif
+
+#ifdef X86_ASSEMBLY
+STATIC_INLINE void m68k_run1 (void (*func)(void))
+{
+    /* Work around compiler bug: GCC doesn't push %ebp in m68k_run_1. */
+    __asm__ __volatile__ ("pushl %%ebp\n\tcall *%0\n\tpopl %%ebp"
+                         : : "r" (func) : "%eax", "%edx", "%ecx", "memory", "cc");
+}
+#else
+#define m68k_run1(F) (F) ()
+#endif
+
+int in_m68k_go = 0;
+
+void m68k_go (int may_quit)
+{
+    if (in_m68k_go || !may_quit) {
+       write_log ("Bug! m68k_go is not reentrant.\n");
+       abort ();
+    }
+
+    reset_frame_rate_hack ();
+    update_68k_cycles ();
+
+    in_m68k_go++;
+    for (;;) {
+       if (quit_program > 0) {
+           int hardreset = quit_program == 3 ? 1 : 0;
+           if (quit_program == 1)
+               break;
+           quit_program = 0;
+           if (savestate_state == STATE_RESTORE)
+               restore_state (savestate_fname);
+           else if (savestate_state == STATE_REWIND)
+               savestate_rewind ();
+           /* following three lines must not be reordered or
+            * fastram state restore breaks
+            */
+           reset_all_systems ();
+           customreset ();
+           m68k_reset ();
+           if (hardreset) {
+               memset (chipmemory, 0, allocated_chipmem);
+               write_log ("chipmem cleared\n");
+           }
+           /* We may have been restoring state, but we're done now.  */
+           if (savestate_state == STATE_RESTORE || savestate_state == STATE_REWIND) {
+               map_overlay (1);
+               fill_prefetch_slow (); /* compatibility with old state saves */
+           }
+           savestate_restore_finish ();
+           fill_prefetch_slow ();
+           if (currprefs.produce_sound == 0)
+               eventtab[ev_audio].active = 0;
+           handle_active_events ();
+           if (regs.spcflags)
+               do_specialties (0);
+            m68k_setpc (regs.pc);
+       }
+
+       if (debugging)
+           debug ();
+       if (regs.panic) {
+           regs.panic = 0;
+           /* program jumped to non-existing memory and cpu was >= 68020 */
+           get_real_address (regs.isp); /* stack in no one's land? -> reboot */
+           if (regs.isp & 1)
+               regs.panic = 1;
+           if (!regs.panic)
+               exception2 (regs.panic_pc, regs.panic_addr);
+           if (regs.panic) {
+               /* system is very badly confused */
+               write_log ("double bus error or corrupted stack, forcing reboot..\n");
+               regs.panic = 0;
+               uae_reset (1);
+           }
+       }
+
+#ifndef JIT
+       m68k_run1 (currprefs.cpu_level == 0 && currprefs.cpu_cycle_exact ? m68k_run_1_ce :
+                   currprefs.cpu_level == 0 && currprefs.cpu_compatible ? m68k_run_1 :
+                   currprefs.cpu_compatible ? m68k_run_2p : m68k_run_2);
+#else
+       m68k_run1 (currprefs.cpu_cycle_exact && currprefs.cpu_level == 0 ? m68k_run_1_ce : 
+                  currprefs.cpu_compatible > 0 && currprefs.cpu_level == 0 ? m68k_run_1 : 
+                  currprefs.cpu_level >= 2 && currprefs.cachesize ? m68k_run_2a :
+                  currprefs.cpu_compatible ? m68k_run_2p : m68k_run_2);
+#endif
+    }
+    in_m68k_go--;
+}
+
+static void m68k_verify (uaecptr addr, uaecptr *nextpc)
+{
+    uae_u32 opcode, val;
+    struct instr *dp;
+
+    opcode = get_iword_1(0);
+    last_op_for_exception_3 = opcode;
+    m68kpc_offset = 2;
+
+    if (cpufunctbl[opcode] == op_illg_1) {
+       opcode = 0x4AFC;
+    }
+    dp = table68k + opcode;
+
+    if (dp->suse) {
+       if (!verify_ea (dp->sreg, dp->smode, dp->size, &val)) {
+           Exception (3, 0);
+           return;
+       }
+    }
+    if (dp->duse) {
+       if (!verify_ea (dp->dreg, dp->dmode, dp->size, &val)) {
+           Exception (3, 0);
+           return;
+       }
+    }
+}
+
+void m68k_disasm (void *f, uaecptr addr, uaecptr *nextpc, int cnt)
+{
+    uaecptr newpc = 0;
+    m68kpc_offset = addr - m68k_getpc ();
+    while (cnt-- > 0) {
+       char instrname[100],*ccpt;
+       int i;
+       uae_u32 opcode;
+       struct mnemolookup *lookup;
+       struct instr *dp;
+       int oldpc;
+
+       oldpc = m68kpc_offset;
+       opcode = get_iword_1 (m68kpc_offset);
+       if (cpufunctbl[opcode] == op_illg_1) {
+           opcode = 0x4AFC;
+       }
+       dp = table68k + opcode;
+       for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++)
+           ;
+
+       f_out (f, "%08lx ", m68k_getpc () + m68kpc_offset);
+       m68kpc_offset += 2;
+
+       strcpy (instrname, lookup->name);
+       ccpt = strstr (instrname, "cc");
+       if (ccpt != 0) {
+           strncpy (ccpt, ccnames[dp->cc], 2);
+       }
+       switch (dp->size){
+        case sz_byte: strcat (instrname, ".B "); break;
+        case sz_word: strcat (instrname, ".W "); break;
+        case sz_long: strcat (instrname, ".L "); break;
+        default: strcat (instrname, "   "); break;
+       }
+
+       if (dp->suse) {
+           newpc = m68k_getpc () + m68kpc_offset;
+           newpc += ShowEA (0, opcode, dp->sreg, dp->smode, dp->size, instrname);
+       }
+       if (dp->suse && dp->duse)
+           strcat (instrname, ",");
+       if (dp->duse) {
+           newpc = m68k_getpc () + m68kpc_offset;
+           newpc += ShowEA (0, opcode, dp->dreg, dp->dmode, dp->size, instrname);
+       }
+
+    
+       for (i = 0; i < (m68kpc_offset - oldpc) / 2; i++) {
+           f_out (f, "%04x ", get_iword_1 (oldpc + i * 2));
+       }
+       while (i++ < 5) f_out (f, "     ");
+       f_out (f, instrname);
+
+       if (ccpt != 0) {
+           if (cctrue(dp->cc))
+               f_out (f, " == %08lx (TRUE)", newpc);
+           else
+               f_out (f, " == %08lx (FALSE)", newpc);
+       } else if ((opcode & 0xff00) == 0x6100) /* BSR */
+           f_out (f, " == %08lx", newpc);
+       f_out (f, "\n");
+    }
+    if (nextpc)
+       *nextpc = m68k_getpc () + m68kpc_offset;
+}
+
+/*************************************************************
+ Disasm the m68kcode at the given address into instrname
+ and instrcode
+*************************************************************/
+void sm68k_disasm(char *instrname, char *instrcode, uaecptr addr, uaecptr *nextpc)
+{
+    char *ccpt;
+    uae_u32 opcode;
+    struct mnemolookup *lookup;
+    struct instr *dp;
+    int oldpc;
+
+    uaecptr newpc = 0;
+
+    m68kpc_offset = addr - m68k_getpc ();
+
+    oldpc = m68kpc_offset;
+    opcode = get_iword_1 (m68kpc_offset);
+    if (cpufunctbl[opcode] == op_illg_1) {
+        opcode = 0x4AFC;
+    }
+    dp = table68k + opcode;
+    for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++);
+
+    m68kpc_offset += 2;
+
+    strcpy (instrname, lookup->name);
+    ccpt = strstr (instrname, "cc");
+    if (ccpt != 0) {
+        strncpy (ccpt, ccnames[dp->cc], 2);
+    }
+    switch (dp->size){
+       case sz_byte: strcat (instrname, ".B "); break;
+       case sz_word: strcat (instrname, ".W "); break;
+       case sz_long: strcat (instrname, ".L "); break;
+       default: strcat (instrname, "   "); break;
+    }
+
+    if (dp->suse) {
+        newpc = m68k_getpc () + m68kpc_offset;
+        newpc += ShowEA (0, opcode, dp->sreg, dp->smode, dp->size, instrname);
+    }
+    if (dp->suse && dp->duse)
+        strcat (instrname, ",");
+    if (dp->duse) {
+        newpc = m68k_getpc () + m68kpc_offset;
+        newpc += ShowEA (0, opcode, dp->dreg, dp->dmode, dp->size, instrname);
+    }
+    
+    if (instrcode)
+    {
+       int i;
+       for (i = 0; i < (m68kpc_offset - oldpc) / 2; i++)
+       {
+           sprintf(instrcode,"%04x ",get_iword_1 (oldpc + i * 2));
+           instrcode += strlen(instrcode);
+       }
+    }
+
+    if (nextpc)
+       *nextpc = m68k_getpc () + m68kpc_offset;
+}
+
+void m68k_dumpstate (void *f, uaecptr *nextpc)
+{
+    int i;
+
+    for (i = 0; i < 8; i++){
+       f_out (f, "D%d: %08lx ", i, m68k_dreg(regs, i));
+       if ((i & 3) == 3) f_out (f, "\n");
+    }
+    for (i = 0; i < 8; i++){
+       f_out (f, "A%d: %08lx ", i, m68k_areg(regs, i));
+       if ((i & 3) == 3) f_out (f, "\n");
+    }
+    if (regs.s == 0) regs.usp = m68k_areg(regs, 7);
+    if (regs.s && regs.m) regs.msp = m68k_areg(regs, 7);
+    if (regs.s && regs.m == 0) regs.isp = m68k_areg(regs, 7);
+    f_out (f, "USP=%08lx ISP=%08lx MSP=%08lx VBR=%08lx\n",
+            regs.usp,regs.isp,regs.msp,regs.vbr);
+    f_out (f, "T=%d%d S=%d M=%d X=%d N=%d Z=%d V=%d C=%d IMASK=%d\n",
+            regs.t1, regs.t0, regs.s, regs.m,
+            GET_XFLG, GET_NFLG, GET_ZFLG, GET_VFLG, GET_CFLG, regs.intmask);
+#ifdef FPUEMU
+    if (currprefs.cpu_level >= 2) {
+        uae_u32 fpsr;
+       for (i = 0; i < 8; i++){
+           f_out (f, "FP%d: %g ", i, regs.fp[i]);
+           if ((i & 3) == 3) f_out (f, "\n");
+       }
+       fpsr = get_fpsr();
+       f_out (f, "N=%d Z=%d I=%d NAN=%d\n",
+               (fpsr & 0x8000000) != 0,
+               (fpsr & 0x4000000) != 0,
+               (fpsr & 0x2000000) != 0,
+               (fpsr & 0x1000000) != 0);
+    }
+#endif
+    if (currprefs.cpu_compatible) {
+       struct instr *dp;
+       struct mnemolookup *lookup1, *lookup2;
+       dp = table68k + regs.irc;
+       for (lookup1 = lookuptab; lookup1->mnemo != dp->mnemo; lookup1++);
+       dp = table68k + regs.ir;
+       for (lookup2 = lookuptab; lookup2->mnemo != dp->mnemo; lookup2++);
+       f_out (f, "prefetch %04x (%s) %04x (%s)\n", regs.irc, lookup1->name, regs.ir, lookup2->name);
+    }
+
+    m68k_disasm (f, m68k_getpc (), nextpc, 1);
+    if (nextpc)
+       f_out (f, "next PC: %08lx\n", *nextpc);
+}
+
+
+/* CPU save/restore code */
+
+#define CPUTYPE_EC 1
+#define CPUMODE_HALT 1
+
+uae_u8 *restore_cpu (uae_u8 *src)
+{
+    int i,model,flags;
+    uae_u32 l;
+
+    model = restore_u32();
+    switch (model) {
+    case 68000:
+       changed_prefs.cpu_level = 0;
+       break;
+    case 68010:
+       changed_prefs.cpu_level = 1;
+       break;
+    case 68020:
+       changed_prefs.cpu_level = 2;
+       break;
+    case 68040:
+       changed_prefs.cpu_level = 4;
+       break;
+    case 68060:
+       changed_prefs.cpu_level = 6;
+       break;
+    default:
+       write_log ("Unknown cpu type %d\n", model);
+       break;
+    }
+
+    flags = restore_u32();
+    changed_prefs.address_space_24 = 0;
+    if (flags & CPUTYPE_EC)
+       changed_prefs.address_space_24 = 1;
+    if (model > 68000)
+       changed_prefs.cpu_compatible = 0;
+    currprefs.cpu_level = changed_prefs.cpu_level;
+    currprefs.address_space_24 = changed_prefs.address_space_24;
+    currprefs.cpu_compatible = changed_prefs.cpu_compatible;
+    currprefs.cpu_cycle_exact = changed_prefs.cpu_cycle_exact;
+    currprefs.blitter_cycle_exact = changed_prefs.blitter_cycle_exact;
+    for (i = 0; i < 15; i++)
+       regs.regs[i] = restore_u32 ();
+    regs.pc = restore_u32 ();
+    regs.irc = restore_u16 ();
+    regs.ir = restore_u16 ();
+    regs.usp = restore_u32 ();
+    regs.isp = restore_u32 ();
+    regs.sr = restore_u16 ();
+    l = restore_u32();
+    if (l & CPUMODE_HALT) {
+       regs.stopped = 1;
+       set_special (SPCFLAG_STOP);
+    } else
+       regs.stopped = 0;
+    if (model >= 68010) {
+       regs.dfc = restore_u32 ();
+       regs.sfc = restore_u32 ();
+       regs.vbr = restore_u32 ();
+    }
+    if (model >= 68020) {
+       caar = restore_u32 ();
+       cacr = restore_u32 ();
+       regs.msp = restore_u32 ();
+       /* A500 speed in 68020 mode isn't too logical.. */
+       if (changed_prefs.m68k_speed == 0)
+           currprefs.m68k_speed = changed_prefs.m68k_speed = -1;
+    }
+    write_log ("CPU %d%s%03d, PC=%08.8X\n",
+              model / 1000, flags & 1 ? "EC" : "", model % 1000, regs.pc);
+
+    init_m68k_full ();
+    return src;
+}
+
+static int cpumodel[] = { 68000, 68010, 68020, 68020, 68040, 68060 };
+
+uae_u8 *save_cpu (int *len, uae_u8 *dstptr)
+{
+    uae_u8 *dstbak,*dst;
+    int model,i;
+
+    if (dstptr)
+       dstbak = dst = dstptr;
+    else
+        dstbak = dst = malloc(4+4+15*4+4+4+4+4+2+4+4+4+4+4+4+4);
+    model = cpumodel[currprefs.cpu_level];
+    save_u32 (model);                                  /* MODEL */
+    save_u32 (currprefs.address_space_24 ? 1 : 0);     /* FLAGS */
+    for(i = 0;i < 15; i++) save_u32 (regs.regs[i]);    /* D0-D7 A0-A6 */
+    save_u32 (m68k_getpc ());                          /* PC */
+    save_u16 (regs.irc);                               /* prefetch */
+    save_u16 (regs.ir);                                        /* instruction prefetch */
+    MakeSR ();
+    save_u32 (!regs.s ? regs.regs[15] : regs.usp);     /* USP */
+    save_u32 (regs.s ? regs.regs[15] : regs.isp);      /* ISP */
+    save_u16 (regs.sr);                                /* SR/CCR */
+    save_u32 (regs.stopped ? CPUMODE_HALT : 0);        /* flags */
+    if(model >= 68010) {
+       save_u32 (regs.dfc);                            /* DFC */
+       save_u32 (regs.sfc);                            /* SFC */
+       save_u32 (regs.vbr);                            /* VBR */
+    }
+    if(model >= 68020) {
+       save_u32 (caar);                                /* CAAR */
+       save_u32 (cacr);                                /* CACR */
+       save_u32 (regs.msp);                            /* MSP */
+    }
+    *len = dst - dstbak;
+    return dstbak;
+}
+
+static void exception3f (uae_u32 opcode, uaecptr addr, uaecptr fault, int writeaccess, int instructionaccess)
+{
+    last_addr_for_exception_3 = addr;
+    last_fault_for_exception_3 = fault;
+    last_op_for_exception_3 = opcode;
+    last_writeaccess_for_exception_3 = writeaccess;
+    last_instructionaccess_for_exception_3 = instructionaccess;
+    Exception (3,0);
+}
+
+void exception3 (uae_u32 opcode, uaecptr addr, uaecptr fault)
+{
+    exception3f (opcode, addr, fault, 0, 0);
+}
+void exception3i (uae_u32 opcode, uaecptr addr, uaecptr fault)
+{
+    exception3f (opcode, addr, fault, 0, 1);
+}
+
+void exception2 (uaecptr addr, uaecptr fault)
+{
+    last_addr_for_exception_3 = addr;
+    last_fault_for_exception_3 = fault;
+    last_writeaccess_for_exception_3 = 0;
+    last_instructionaccess_for_exception_3 = 0;
+    Exception (2, 0);
+}
+
+void cpureset (void)
+{
+    customreset ();
+#if 0
+    uae_u16 ins;
+    if (currprefs.cpu_level == 0 && (currprefs.cpu_compatible || currprefs.cpu_cycle_exact)) {
+       customreset ();
+       return;
+    }
+    ins = get_word (m68k_getpc() + 2);
+    if ((ins & ~7) == 0x4ed0) {
+       int reg = ins & 7;
+       uae_u32 addr = m68k_areg (regs, reg);
+       write_log ("reset/jmp (ax) combination emulated\n");
+       customreset ();
+       if (addr < 0x80000)
+           addr += 0xf80000;
+       m68k_setpc (addr);
+    }
+#endif
+}
+
+
diff --git a/nogui.c b/nogui.c
new file mode 100755 (executable)
index 0000000..5e8830d
--- /dev/null
+++ b/nogui.c
@@ -0,0 +1,88 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Interface to the Tcl/Tk GUI
+  *
+  * Copyright 1996 Bernd Schmidt
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "gui.h"
+
+static void sigchldhandler(int foo)
+{
+}
+
+int gui_init (void)
+{
+    return 0;
+}
+
+int gui_update (void)
+{
+    return 0;
+}
+
+void gui_exit (void)
+{
+}
+
+void gui_fps (int x)
+{
+}
+
+void gui_led (int led, int on)
+{
+}
+
+void gui_hd_led (int led)
+{
+}
+
+void gui_cd_led (int led)
+{
+}
+
+void gui_filename (int num, const char *name)
+{
+}
+
+static void getline (char *p)
+{
+}
+
+void gui_handle_events (void)
+{
+}
+
+void gui_changesettings (void)
+{
+}
+
+void gui_update_gfx (void)
+{
+}
+
+void gui_lock (void)
+{
+}
+
+void gui_unlock (void)
+{
+}
+
+void gui_message (const char *format,...)
+{   
+       char msg[2048];
+       va_list parms;
+
+       va_start (parms,format);
+       vsprintf ( msg, format, parms);
+       va_end (parms);
+
+       write_log (msg);
+}
diff --git a/od-generic/exectasks.h b/od-generic/exectasks.h
new file mode 100755 (executable)
index 0000000..f6a93ca
--- /dev/null
@@ -0,0 +1,17 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * exec.library multitasking emulation
+  *
+  * Copyright 1996 Bernd Schmidt
+  */
+
+struct switch_struct {
+    int dummy;
+};
+/* Looks weird. I think I had a report once that some compiler chokes if
+ * the statement is empty. */
+#define EXEC_SWITCH_TASKS(run, ready) do { int i = 0; i++; } while(0)
+
+#define EXEC_SETUP_SWS(t) do { int i = 0; i++; } while(0)
+
diff --git a/od-generic/joystick.c b/od-generic/joystick.c
new file mode 100755 (executable)
index 0000000..5ec3561
--- /dev/null
@@ -0,0 +1,71 @@
+ /* 
+  * UAE - The Un*x Amiga Emulator
+  * 
+  * Joystick emulation stubs
+  * 
+  * Copyright 1997 Bernd Schmidt
+  * Copyright 2003 Richard Drummond
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "memory.h"
+#include "custom.h"
+#include "inputdevice.h"
+
+static int init_joysticks (void)
+{
+   return 1;
+}
+
+static void close_joysticks (void)
+{
+}
+
+static int acquire_joystick (int num, int flags)
+{
+    return 0;
+}
+
+static void unacquire_joystick (int num)
+{
+}
+
+static void read_joysticks (void)
+{
+}
+
+static int get_joystick_num (void)
+{
+    return 0;
+}
+
+static char *get_joystick_name (int joy)
+{
+    return 0;
+}
+
+static int get_joystick_widget_num (int joy)
+{
+    return 0;
+}
+
+static int get_joystick_widget_type (int joy, int num, char *name, uae_u32 *code)
+{
+    return IDEV_WIDGET_NONE;
+}
+
+static int get_joystick_widget_first (int joy, int type)
+{
+    return -1;
+}
+
+struct inputdevice_functions inputdevicefunc_joystick = {
+    init_joysticks, close_joysticks, acquire_joystick, unacquire_joystick,
+    read_joysticks, get_joystick_num, get_joystick_name,
+    get_joystick_widget_num, get_joystick_widget_type,
+    get_joystick_widget_first
+};
diff --git a/od-generic/memory.h b/od-generic/memory.h
new file mode 100755 (executable)
index 0000000..5d21b6c
--- /dev/null
@@ -0,0 +1,11 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * See if this OS has mmap or equivalent
+  *
+  * Copyright 1996 Bernd Schmidt
+  */
+
+#undef USE_MAPPED_MEMORY
+#undef CAN_MAP_MEMORY
+
diff --git a/od-generic/sound.c b/od-generic/sound.c
new file mode 100755 (executable)
index 0000000..4c63521
--- /dev/null
@@ -0,0 +1,43 @@
+ /* 
+  * UAE - The Un*x Amiga Emulator
+  * 
+  * Support for the Mute sound system
+  * 
+  * Copyright 1997 Bernd Schmidt
+  * Copyright 2003 Richard Drummond
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "memory.h"
+#include "custom.h"
+#include "audio.h"
+#include "gensound.h"
+#include "sounddep/sound.h"
+
+int init_sound (void)
+{
+    currprefs.produce_sound = 0;
+    return 1;
+}
+
+int setup_sound (void)
+{
+    currprefs.produce_sound = 0;
+    return 1;
+}
+
+void close_sound (void)
+{
+}
+
+void update_sound (int freq)
+{
+}
+
+void reset_sound (void)
+{
+}
diff --git a/od-generic/sound.h b/od-generic/sound.h
new file mode 100755 (executable)
index 0000000..1817268
--- /dev/null
@@ -0,0 +1,27 @@
+ /* 
+  * UAE - The Un*x Amiga Emulator
+  * 
+  * Support for the Mute sound system.
+  * 
+  * Copyright 1997 Bernd Schmidt
+  */
+
+static __inline__ void check_sound_buffers (void)
+{
+}
+
+#define PUT_SOUND_BYTE(b) do { ; } while (0)
+#define PUT_SOUND_WORD(b) do { ; } while (0)
+#define SOUND16_BASE_VAL 0
+#define SOUND8_BASE_VAL 0
+
+#define DEFAULT_SOUND_MINB 8192
+#define DEFAULT_SOUND_MAXB 8192
+#define DEFAULT_SOUND_BITS 16
+#define DEFAULT_SOUND_FREQ 44100
+
+#define UNSUPPORTED_OPTION_B
+#define UNSUPPORTED_OPTION_R
+#define UNSUPPORTED_OPTION_b
+#define UNSUPPORTED_OPTION_S
+
diff --git a/od-win32/ahidsound.c b/od-win32/ahidsound.c
new file mode 100755 (executable)
index 0000000..814ee6c
--- /dev/null
@@ -0,0 +1,901 @@
+/*
+ * UAE - The Un*x Amiga Emulator
+ * 
+ * Win32 interface
+ *
+ * Copyright 1997 Mathias Ortmann
+ * Copyright 1997-2001 Brian King
+ * Copyright 2000-2002 Bernd Roesch
+ */
+    
+
+#define NATIVBUFFNUM 4
+#define RECORDBUFFER 50 //survive 9 sec of blocking at 44100
+
+#include "sysconfig.h"
+
+#ifdef __GNUC__
+#define INITGUID
+#endif 
+#include <windows.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <mmsystem.h>
+#include <dsound.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <io.h>
+#include "winspool.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "memory.h"
+#include "events.h"
+#include "custom.h"
+#include "gensound.h"
+#include "newcpu.h"
+#include "threaddep/thread.h"
+#include <ctype.h>
+#include <assert.h>
+#include "od-win32/win32.h"
+#include "gui.h"
+#include "picasso96_win.h"
+#include "sounddep/sound.h"
+#include "od-win32/ahidsound.h"
+#include "vfw.h"
+#include "win32.h"
+#include "win32gfx.h"
+#include "dxwrap.h"
+#include "inputdevice.h"
+#include "avioutput.h"
+#include "parser.h"
+#include "enforcer.h"
+
+static long samples,playchannel,intcount,norec;
+int ahi_on;
+static char *sndptrmax, soundneutral,sndptr,*tempmem;
+static HWND dsound_tmpw;
+
+static WAVEFORMATEX wavfmt;
+
+static LPSTR lpData,sndptrout;
+extern uae_u32 chipmem_mask;
+unsigned int samplecount,*sndbufrecpt;
+static char *ahisndbuffer,*sndrecbuffer; 
+static int ahisndbufsize,oldpos,*ahisndbufpt,ahitweak;;
+static unsigned int dwBytes,dwBytes1,dwBytes2,espstore;
+static LPVOID dwData1,dwData2;
+
+int sound_freq_ahi;
+       
+static int vin,devicenum;
+static int amigablksize;
+
+DWORD sound_flushes2  = 0;
+
+extern HWND hAmigaWnd;
+#ifdef __GNUC__
+DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16);
+#endif
+
+static LPDIRECTSOUND lpDS2 = NULL;
+static LPDIRECTSOUNDBUFFER lpDSBprimary2 = NULL;
+static LPDIRECTSOUNDBUFFER lpDSB2 = NULL;
+static LPDIRECTSOUNDNOTIFY lpDSBN2 = NULL;
+
+// for record
+static LPDIRECTSOUNDCAPTURE lpDS2r = NULL;
+static LPDIRECTSOUNDCAPTUREBUFFER lpDSBprimary2r = NULL;
+static LPDIRECTSOUNDCAPTUREBUFFER lpDSB2r = NULL;
+
+struct winuae        //this struct is put in a6 if you call 
+                        //execute native function
+{
+       HWND                    amigawnd;    //adress of amiga Window Windows Handle
+    unsigned int    changenum;   //number to detect screen close/open 
+    unsigned int    z3offset;    //the offset to add to acsess Z3 mem from Dll side
+};
+
+struct winuae uaevar;
+struct winuae *a6;
+
+#define CREATE_NATIVE_FUNC_PTR2 uae_u32 (* native_func)( uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, \
+                                                uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32,uae_u32,uae_u32)
+#define SET_NATIVE_FUNC2(x) native_func = (uae_u32 (*)(uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32,uae_u32,uae_u32))(x)
+#define CALL_NATIVE_FUNC2( d1,d2,d3,d4,d5,d6,d7,a1,a2,a3,a4,a5,a6,a7) if(native_func) return native_func( d1,d2,d3,d4,d5,d6,d7,a1,a2,a3,a4,a5,a6,a7,regs_ )
+       
+static uae_u32 emulib_ExecuteNativeCode2 (void)
+{ 
+    uae_u8* object_UAM = (uae_u8*) m68k_areg( regs, 0 );
+    uae_u32 d1 = m68k_dreg( regs, 1 );
+    uae_u32 d2 = m68k_dreg( regs, 2 );
+    uae_u32 d3 = m68k_dreg( regs, 3 );
+    uae_u32 d4 = m68k_dreg( regs, 4 );
+    uae_u32 d5 = m68k_dreg( regs, 5 );
+    uae_u32 d6 = m68k_dreg( regs, 6 );
+    uae_u32 d7 = m68k_dreg( regs, 7 );
+    uae_u32 a1 = m68k_areg( regs, 1 );
+    uae_u32 a2 = m68k_areg( regs, 2 );
+    uae_u32 a3 = m68k_areg( regs, 3 );
+    uae_u32 a4 = m68k_areg( regs, 4 );
+    uae_u32 a5 = m68k_areg( regs, 5 );
+    uae_u32 a7 = m68k_areg( regs, 7 );
+    uae_u32 regs_ = (uae_u32)&regs;
+    CREATE_NATIVE_FUNC_PTR2;
+    uaevar.z3offset = (uae_u32)(get_real_address (0x10000000) - 0x10000000);
+    uaevar.amigawnd = hAmigaWnd;
+    a6 = &uaevar;    
+    if( object_UAM ) 
+    {
+       SET_NATIVE_FUNC2(object_UAM );
+    __asm
+       {   mov espstore,esp
+           push regs_
+               push a7
+               push a6
+               push a5
+               push a4
+               push a3
+               push a2
+               push a1
+        push d7
+               push d6
+        push d5
+               push d4
+               push d3
+               push d2
+               push d1
+               call native_func
+               mov esp,espstore
+       }
+       //CALL_NATIVE_FUNC2( d1, d2,d3, d4, d5, d6, d7, a1, a2, a3, a4 , a5 , a6 , a7);
+    }
+       else
+    return 0;
+}
+
+char *DSError2( HRESULT error )
+{
+    switch( error )
+    {
+    case DSERR_ALLOCATED:
+        return "Allocated";
+
+    case DSERR_CONTROLUNAVAIL:
+        return "Control Unavailable";
+
+    case DSERR_INVALIDPARAM:
+        return "Invalid Parameter";
+
+    case DSERR_INVALIDCALL:
+        return "Invalid Call";
+
+    case DSERR_GENERIC:
+        return "Generic";
+
+    case DSERR_PRIOLEVELNEEDED:
+        return "Priority Level Needed";
+
+    case DSERR_OUTOFMEMORY:
+        return "Out of Memory";
+
+    case DSERR_BADFORMAT:
+        return "Bad Format";
+
+    case DSERR_UNSUPPORTED:
+        return "Unsupported";
+
+    case DSERR_NODRIVER:
+        return "No Driver";
+
+    case DSERR_ALREADYINITIALIZED:
+        return "Already Initialized";
+
+    case DSERR_NOAGGREGATION:
+        return "No Aggregation";
+
+    case DSERR_BUFFERLOST:
+        return "Buffer Lost";
+
+    case DSERR_OTHERAPPHASPRIO:
+        return "Other Application Has Priority";
+
+    case DSERR_UNINITIALIZED:
+        return "Uninitialized";
+
+    case DSERR_NOINTERFACE:
+        return "No Interface";
+
+    default:
+        return "Unknown";
+    }
+}
+
+
+void ahi_close_sound (void)
+{
+        HRESULT hr = DS_OK;
+
+   
+        if (!ahi_on)
+            return;
+               ahi_on=0;
+        ahisndbufpt =(int*) ahisndbuffer;
+        samplecount = 0;
+               if( lpDSB2 )
+               {
+        hr = IDirectSoundBuffer_Stop( lpDSB2 );
+               }
+        
+        if( hr != DS_OK )
+        {
+            write_log( "SoundStop() failure: %s\n", DSError2( hr ) );
+        }
+     else
+       {
+            write_log( "Sound Stopped...\n" );
+       }
+    if( lpDSB2 )
+    {
+        IDirectSoundBuffer_Release( lpDSB2 );
+        lpDSB2 = NULL;
+    }
+    if( lpDSBprimary2 )
+    {
+        IDirectSoundBuffer_Release( lpDSBprimary2 );
+        lpDSBprimary2 = NULL;
+    }
+    if( lpDS2 )
+    {
+        IDirectSound_Release( lpDS2 );
+        lpDS2 = NULL;
+    }
+  
+        if( lpDSB2r )
+    {
+        IDirectSoundCaptureBuffer_Release( lpDSB2r );
+        lpDSB2r = NULL;
+    }
+       if (dsound_tmpw)
+       {
+               DestroyWindow(dsound_tmpw);dsound_tmpw=0;
+       }
+       if (ahisndbuffer) free(ahisndbuffer);
+    
+
+    }
+
+void ahi_updatesound( int force )
+{
+  HRESULT hr;
+       int i;
+
+
+  
+               if( sound_flushes2 == 1 )
+       {
+               oldpos=0;
+           INTREQ(0xa000);
+               intcount=1;
+               /* Lock the entire buffer */
+               hr = IDirectSoundBuffer_Lock( lpDSB2, 0, ahisndbufsize, &lpData, &dwBytes,&dwData2,&dwBytes2,0 );
+               if( hr == DSERR_BUFFERLOST )
+               {
+                   IDirectSoundBuffer_Restore( lpDSB2 );
+                   hr = IDirectSoundBuffer_Lock( lpDSB2, 0, 0, &lpData, &dwBytes,&dwData2,&dwBytes2, DSBLOCK_ENTIREBUFFER );
+                       
+               }
+         
+           /* Get the big looping IDirectSoundBuffer_Play() rolling here, but only once at startup */
+           hr = IDirectSoundBuffer_Play( lpDSB2, 0, 0, DSBPLAY_LOOPING );
+               hr=IDirectSoundBuffer_Unlock(lpDSB2,lpData,dwBytes,dwData2,dwBytes2); 
+        if (!norec)hr = IDirectSoundCaptureBuffer_Start( lpDSB2r,DSBPLAY_LOOPING );
+
+        //memset( lpData, 0x80,4 );
+        
+       }
+/*
+               {
+long dwEvt=1;
+
+  dwEvt = MsgWaitForMultipleObjects(
+            2,      // How many possible events
+            rghEvent,       // Location of handles
+            FALSE,          // Wait for all?
+            INFINITE,       // How long to wait
+            QS_ALLINPUT);   // Any message is an event
+
+                       
+calcsound=1;
+if (dwEvt==0)freeblock=0;
+if (dwEvt==1)freeblock=1;
+
+
+if (dwEvt>1 ){calcsound=0;return;}
+               }
+*/
+
+   hr = IDirectSoundBuffer_GetCurrentPosition(lpDSB2, &i, 0);
+  if( hr != DSERR_BUFFERLOST )
+       {
+       i -= ahitweak;
+       if (i < 0)i = i + ahisndbufsize;                  
+       if (i >= ahisndbufsize)i = i - ahisndbufsize;
+       i = ( i / (amigablksize * 4 )) * ( amigablksize * 4 );
+               if (force == 1)
+               {
+                       if (( oldpos != i) )
+                       {
+                       INTREQ( 0xa000 );
+                       intcount = 1;
+                       return; //to generate amiga ints every amigablksize
+                              
+                       }
+                       else
+                       {
+                       return;
+                       }
+               }
+  
+   }
+
+hr = IDirectSoundBuffer_Lock( lpDSB2, oldpos, amigablksize * 4, &dwData1, &dwBytes1, &dwData2, &dwBytes2 ,0);
+
+
+               if( hr == DSERR_BUFFERLOST )
+                       {
+                       write_log("lostbuf%d  %x\n",i,amigablksize);
+                   IDirectSoundBuffer_Restore( lpDSB2 );
+                   hr = IDirectSoundBuffer_Lock( lpDSB2, 0, 0, &lpData, &dwBytes, NULL, NULL, DSBLOCK_ENTIREBUFFER );
+                       dwData1=lpData;dwBytes1=dwBytes;dwBytes2=0;dwData2=0;
+               }
+               
+       
+                               //write_log("%d  %x\n",freeblock,blksize);
+                       
+                
+       memcpy(dwData1,ahisndbuffer,dwBytes1);                                                                        
+    sndptrmax = ahisndbuffer+ahisndbufsize;
+       ahisndbufpt = (int*)ahisndbuffer;
+IDirectSoundBuffer_Unlock(lpDSB2, dwData1,dwBytes1,dwData2, dwBytes2); 
+  oldpos = i;
+  //oldpos=oldpos+(amigablksize*4);
+  //if (oldpos >= ahisndbufsize)oldpos=0; 
+}
+
+
+/* Use this to pause or stop Win32 sound output */
+
+
+void ahi_finish_sound_buffer( void )
+{
+    sound_flushes2++;
+
+    ahi_updatesound(2);
+       
+}
+
+extern GUID sound_device_guid[];
+
+static int ahi_init_sound_win32 (void)
+{
+    HRESULT hr;
+    DSBUFFERDESC sound_buffer;
+    DSCAPS DSCaps;
+    DSCBUFFERDESC sound_buffer_rec;
+    
+    if (lpDS2 )
+        return 0;
+
+    enumerate_sound_devices (0);
+    wavfmt.wFormatTag = WAVE_FORMAT_PCM;
+    wavfmt.nChannels = 2;
+    wavfmt.nSamplesPerSec = sound_freq_ahi;
+    wavfmt.wBitsPerSample = 16;
+    wavfmt.nBlockAlign = 16 / 8 * 2;
+    wavfmt.nAvgBytesPerSec = wavfmt.nBlockAlign * sound_freq_ahi;
+
+    soundneutral = 0;
+    ahisndbufsize = (amigablksize*4)*NATIVBUFFNUM;  // use 4 native buffer
+    ahisndbuffer=malloc(ahisndbufsize+32);
+    if (!ahisndbuffer)return 0;
+    hr = DirectSoundCreate( &sound_device_guid[currprefs.win32_soundcard], &lpDS2, NULL );
+    if (hr != DS_OK) 
+    {
+        write_log( "DirectSoundCreate() failure: %s\n", DSError2 (hr));
+        return 0;
+    }
+       memset (&sound_buffer, 0, sizeof( DSBUFFERDESC ));
+    sound_buffer.dwSize = sizeof( DSBUFFERDESC );
+    sound_buffer.dwFlags = DSBCAPS_PRIMARYBUFFER;
+    sound_buffer.dwBufferBytes = 0;
+    sound_buffer.lpwfxFormat = NULL;
+    
+    dsound_tmpw = CreateWindowEx( WS_EX_ACCEPTFILES,
+                                  "PCsuxRox",
+                                  "Argh",
+                                  WS_CAPTION,
+                                  CW_USEDEFAULT, CW_USEDEFAULT,
+                                  10, 10,
+                                  NULL,
+                                  NULL,
+                                  0,
+                                  NULL);
+
+    
+
+    DSCaps.dwSize = sizeof( DSCAPS );
+    hr = IDirectSound_GetCaps( lpDS2, &DSCaps );
+    if( hr == DS_OK )
+    {
+       if( DSCaps.dwFlags & DSCAPS_EMULDRIVER )
+           write_log( "Your DirectSound Driver is emulated via WaveOut - yuck!\n" );
+    }
+       if FAILED(IDirectSound_SetCooperativeLevel(
+            lpDS2,dsound_tmpw, DSSCL_PRIORITY))
+        return 0;
+    hr = IDirectSound_CreateSoundBuffer (lpDS2, &sound_buffer, &lpDSBprimary2, NULL);
+    if( hr != DS_OK ) 
+    {
+        write_log( "CreateSoundBuffer() failure: %s\n", DSError2( hr ) );
+        return 0;
+    }
+    hr = IDirectSoundBuffer_SetFormat (lpDSBprimary2, &wavfmt);
+    if( hr != DS_OK ) 
+    {
+        write_log( "SetFormat() failure: %s\n", DSError2 (hr));
+        return 0;
+    }
+    sound_buffer.dwBufferBytes = ahisndbufsize;
+    sound_buffer.lpwfxFormat = &wavfmt;
+    sound_buffer.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLVOLUME /*| DSBCAPS_CTRLPOSITIONNOTIFY */| DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_GLOBALFOCUS |DSBCAPS_STATIC ;
+    hr = IDirectSound_CreateSoundBuffer( lpDS2, &sound_buffer, &lpDSB2, NULL );
+    if (hr != DS_OK) 
+    {
+        write_log ("CreateSoundBuffer() failure: %s\n", DSError2 (hr));
+        return 0;
+    }
+/*  //used for PositionNotify 
+    for ( i = 0; i < 2; i++)
+    {
+        rghEvent[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
+        if (NULL == rghEvent[i]) return FALSE;
+    }
+    rgdsbpn[0].dwOffset = 0;
+    rgdsbpn[0].hEventNotify = rghEvent[0];
+    rgdsbpn[1].dwOffset = (soundbufsize/2)*1;
+    rgdsbpn[1].hEventNotify = rghEvent[1];
+
+   
+    if FAILED(IDirectSoundBuffer_QueryInterface(lpDSB, 
+            &IID_IDirectSoundNotify, (VOID **)&lpdsNotify))
+        return FALSE; 
+    if FAILED(IDirectSoundNotify_SetNotificationPositions(
+             lpdsNotify, 2,rgdsbpn))
+    {
+        IDirectSoundNotify_Release(lpdsNotify);
+        return FALSE;
+    }
+
+*/
+
+    hr = IDirectSoundBuffer_SetVolume (lpDSB2, 0);
+    if (hr != DS_OK) 
+    {
+        write_log( "SetVolume() 2 failure: %s\n", DSError2 (hr));
+        return 0;
+    }
+
+     hr = IDirectSoundBuffer_GetFormat (lpDSBprimary2,&wavfmt,500,0);
+    if( hr != DS_OK ) 
+    {
+        write_log( "GetFormat() failure: %s\n", DSError2 (hr));
+        return 0;
+    }
+    // Record begin
+       hr = DirectSoundCaptureCreate( NULL, &lpDS2r, NULL );
+    if (hr != DS_OK) 
+    {
+        write_log( "DirectSoundCaptureCreate() failure: %s\n", DSError2 (hr));
+        norec = 1;
+    }
+    memset (&sound_buffer_rec, 0, sizeof( DSCBUFFERDESC ));
+    sound_buffer_rec.dwSize = sizeof( DSCBUFFERDESC );
+       sound_buffer_rec.dwBufferBytes = amigablksize*4*RECORDBUFFER;
+    sound_buffer_rec.lpwfxFormat = &wavfmt;
+    sound_buffer_rec.dwFlags = 0 ;
+  
+       if (!norec)
+       {       
+               hr = IDirectSoundCapture_CreateCaptureBuffer( lpDS2r, &sound_buffer_rec, &lpDSB2r, NULL );
+               }
+               if (hr != DS_OK) 
+               {
+                       write_log ("CreateCaptureSoundBuffer() failure: %s\n", DSError2 (hr));
+                       norec = 1;
+               }
+               else
+               
+
+    
+    
+    if(ahisndbuffer==0)return 0;
+    ahisndbufpt =(int*) ahisndbuffer;
+    sndptrmax = ahisndbuffer + ahisndbufsize;
+    samplecount = 0;
+    memset( ahisndbuffer, soundneutral,amigablksize*8 );
+    write_log("Init AHI Sound Rate %d Buffsize %d\n",sound_freq_ahi,amigablksize); 
+       if (!norec)write_log("Init AHI Audio Recording \n");
+    ahi_on = 1;
+    return sound_freq_ahi;
+}
+
+static int rate;
+
+int ahi_open_sound (void)
+{  
+    uaevar.changenum++;
+    if (!sound_freq_ahi)
+       return 0;
+    if (ahi_on) {
+       ahi_close_sound();
+    }
+    sound_flushes2 = 1;
+    if ((rate = ahi_init_sound_win32 ()) )
+       return rate;
+    return 0;
+} 
+
+
+static char *addr;
+static void *bswap_buffer = NULL;
+static uae_u32 bswap_buffer_size = 0;
+
+uae_u32 ahi_demux (void)
+{
+//use the extern int (6 #13)  
+// d0 0=opensound      d1=unit d2=samplerate d3=blksize ret: sound frequency
+// d0 1=closesound     d1=unit
+// d0 2=writesamples   d1=unit a0=addr      write blksize samples to card     
+// d0 3=readsamples    d1=unit a0=addr      read samples from card ret: d0=samples read
+      // make sure you have from amigaside blksize*4 mem alloced 
+      // d0=-1 no data available d0=-2 no recording open
+         // d0 > 0 there are more blksize Data in the que
+         // do the loop until d0 get 0
+         // if d0 is greater than 200 bring a message
+         // that show the user that data is lost
+         // maximum blocksbuffered are 250 (8,5 sec)
+// d0 4=writeinterrupt d1=unit  d0=0 no interrupt happen for this unit
+         // d0=-2 no playing open
+
+       //note units for now not support use only unit 0
+       
+// d0=10 get clipboard size      d0=size in bytes  
+// d0=11 get clipboard data      a0=clipboarddata
+                                  //Note: a get clipboard size must do before
+// d0=12 write clipboard data    a0=clipboarddata
+// d0=13 setp96mouserate         d1=hz value
+// d0=100 open dll               d1=dll name in windows name conventions
+// d0=101 get dll function addr  d1=dllhandle a0 function/var name 
+// d0=102 exec dllcode           a0=addr of function (see 101)
+// d0=103 close dll
+// d0=104 screenlost
+// d0=105 mem offset
+// d0=106 16Bit byteswap    
+// d0=107 32Bit byteswap
+// d0=108 free swap array
+// d0=200 ahitweak               d1=offset for dsound position pointer
+
+int opcode = m68k_dreg (regs, 0);
+switch (opcode) {
+       int i,slen,t,todo,byte1,byte2;  
+       LPTSTR p,p2,pos1,pos2;
+       uae_u32 src, num_vars;
+       static int cap_pos,clipsize;
+       static  LPTSTR clipdat;
+       int cur_pos;
+       
+    case 0:
+               cap_pos=0;
+               sound_freq_ahi=m68k_dreg (regs, 2);
+               amigablksize=m68k_dreg (regs, 3);
+               sound_freq_ahi=ahi_open_sound();
+               uaevar.changenum--;
+               return sound_freq_ahi;
+    case 1:
+               ahi_close_sound();
+               sound_freq_ahi = 0;
+               return 0;
+       case 2:
+               addr=(char *)m68k_areg (regs, 0);
+               for (i=0;i<(amigablksize*4);i+=4)
+               { 
+               
+                       ahisndbufpt[0]=get_long((unsigned int)addr+i);
+                       ahisndbufpt+=1;
+                       /*ahisndbufpt[0]=chipmem_bget((unsigned int)addr+i+2);
+                       ahisndbufpt+=1;
+                       ahisndbufpt[0]=chipmem_bget((unsigned int)addr+i+1);
+                       ahisndbufpt+=1;
+                       ahisndbufpt[0]=chipmem_bget((unsigned int)addr+i);
+                       ahisndbufpt+=1;*/
+               }
+                       ahi_finish_sound_buffer();
+               return amigablksize;
+       case 3:
+               if (norec)return -1;
+               if (!ahi_on)return -2;
+        i = IDirectSoundCaptureBuffer_GetCurrentPosition(lpDSB2r,&t,&cur_pos);
+        t =  amigablksize*4;
+               
+               if (cap_pos<=cur_pos)todo=cur_pos-cap_pos;
+               else
+                       todo=cur_pos+(RECORDBUFFER*t)-cap_pos;
+               if (todo<t)    
+               {                //if no complete buffer ready exit
+                       return -1;
+               }
+               i = IDirectSoundCaptureBuffer_Lock(lpDSB2r,cap_pos,t,&pos1,&byte1,&pos2,&byte2,0);
+
+               if ((cap_pos+t)< (t*RECORDBUFFER))
+               {
+                       cap_pos=cap_pos+t;
+               }
+               else
+               {
+                       cap_pos = 0;
+
+               }  
+               addr=(char *)m68k_areg (regs, 0);
+               sndbufrecpt=(unsigned int*)pos1;
+               t=t/4;
+               for (i=0;i<t;i++)
+               {
+                       put_long((uae_u32)addr,sndbufrecpt[0]);
+                       addr+=4;
+                       sndbufrecpt+=1;
+               }
+               t=t*4;
+               i=IDirectSoundCaptureBuffer_Unlock(lpDSB2r,pos1,byte1,pos2,byte2);
+        return (todo-t)/t;
+       case 4:
+               if (!ahi_on)return -2;
+               i=intcount;
+               intcount=0;
+        return i;
+       case 5:
+        if ( !ahi_on ) return 0;
+            ahi_updatesound ( 1 );
+        return 1;      
+
+       case 10:        
+       i=OpenClipboard(0);
+          clipdat=GetClipboardData(CF_TEXT);
+          if (clipdat)
+          {
+              clipsize=strlen(clipdat);
+              clipsize++;
+              return clipsize;
+          }
+          else 
+          {
+                  return 0;
+          }
+       case 11:
+               addr=(char *)m68k_areg (regs, 0);
+               for (i=0;i<clipsize;i++)
+               {
+                       put_byte((uae_u32)addr,clipdat[0]);
+                       addr++;
+                       clipdat++;
+               }
+               CloseClipboard();
+               return 0;
+       case 12:           
+          addr = (char *)m68k_areg (regs, 0);
+          addr = (char *)get_real_address ((uae_u32)addr);
+          i = OpenClipboard (0);
+          EmptyClipboard();
+          slen = strlen(addr);
+          p = GlobalAlloc (GMEM_DDESHARE,slen+2);
+          p2 = GlobalLock (p);
+       memcpy (p2,addr,slen);
+          p2[slen]=0;
+          GlobalUnlock (p);
+          i = (int)SetClipboardData (CF_TEXT,p2);
+          CloseClipboard ();
+          GlobalFree (p);
+          return 0;
+       case 13:
+      /* HACK */
+        { //for higher P96 mouse draw rate
+       extern int p96hack_vpos2,hack_vpos,p96refresh_active;
+       extern uae_u16 vtotal;
+       extern unsigned int new_beamcon0;
+       p96hack_vpos2=15625/m68k_dreg (regs, 1);
+       p96refresh_active=1;
+       if (!picasso_on)return 0;
+       vtotal=p96hack_vpos2;           // only do below if P96 screen is visible
+       new_beamcon0 |= 0x80;              
+       hack_vpos=vtotal;                  
+        } //end for higher P96 mouse draw rate
+      return 0;
+
+       case 20:
+               return enforcer_enable();
+
+       case 21:
+               return enforcer_disable();
+
+       case 25:
+        flushprinter ();
+       return 0;
+       
+       case 100: // open dll
+               {  
+               char *dllname;
+               uae_u32 result;
+        dllname = ( char *) m68k_areg (regs, 0);
+        dllname = (char *)get_real_address ((uae_u32)dllname);
+        result=(uae_u32) LoadLibrary(dllname);
+               write_log("%s windows dll/alib loaded at %d (0 mean failure)\n",dllname,result); 
+               return result;
+               }
+       case 101:      //get dll label
+               {
+               HMODULE m;
+        char *funcname;
+               m = (HMODULE) m68k_dreg (regs, 1);
+               funcname = (char *)m68k_areg (regs, 0);
+        funcname = (char *)get_real_address ((uae_u32)funcname);
+               return (uae_u32) GetProcAddress(m,funcname);
+               }
+       case 102:      //execute native code
+               return emulib_ExecuteNativeCode2 ();
+               
+       case 103:      //close dll
+               {
+               HMODULE libaddr;
+               libaddr= (HMODULE) m68k_dreg (regs, 1);
+               FreeLibrary(libaddr);
+               return 0;
+               }
+       case 104:        //screenlost
+       {
+               static int oldnum=0;
+               if (uaevar.changenum == oldnum)return 0;
+               oldnum=uaevar.changenum;return 1;
+       }
+       case 105:               //returns memory offset
+           return (uae_u32) get_real_address(0);
+       case 106:               //byteswap 16bit vars
+                                       //a0 = start address
+                                       //d1 = number of 16bit vars
+                                       //returns address of new array
+               src = m68k_areg(regs, 0);
+               num_vars = m68k_dreg(regs, 1);
+               
+               if (bswap_buffer_size < num_vars * 2) {
+                       bswap_buffer_size = (num_vars + 1024) * 2;
+                       free(bswap_buffer);
+                       bswap_buffer = (void*)malloc(bswap_buffer_size);
+               }
+                       __asm {
+                               mov esi, dword ptr [src]
+                               mov edi, dword ptr [bswap_buffer]
+                               mov ecx, num_vars
+                               
+                               mov ebx, ecx
+                               and ecx, 3
+                               je BSWAP_WORD_4X
+                               
+                       BSWAP_WORD_LOOP:
+                               mov ax, [esi]
+                               mov dl, al
+                               mov al, ah
+                               mov ah, dl
+                               mov [edi], ax
+                               add esi, 2
+                               add edi, 2
+                               loopne BSWAP_WORD_LOOP
+                               
+                       BSWAP_WORD_4X:
+                               mov ecx, ebx
+                               shr ecx, 2
+                               je BSWAP_WORD_END
+                       BSWAP_WORD_4X_LOOP:
+                               mov ax, [esi]
+                               mov dl, al
+                               mov al, ah
+                               mov ah, dl
+                               mov [edi], ax
+                               mov ax, [esi+2]
+                               mov dl, al
+                               mov al, ah
+                               mov ah, dl
+                               mov [edi+2], ax
+                               mov ax, [esi+4]
+                               mov dl, al
+                               mov al, ah
+                               mov ah, dl
+                               mov [edi+4], ax
+                               mov ax, [esi+6]
+                               mov dl, al
+                               mov al, ah
+                               mov ah, dl
+                               mov [edi+6], ax
+                               add esi, 8
+                               add edi, 8
+                               loopne BSWAP_WORD_4X_LOOP
+                               
+                       BSWAP_WORD_END:
+                       }
+               return (uae_u32) bswap_buffer;
+       case 107:       //byteswap 32bit vars - see case 106
+                               //a0 = start address
+                               //d1 = number of 32bit vars
+                               //returns address of new array
+               src = m68k_areg(regs, 0);
+               num_vars = m68k_dreg(regs, 1);
+               if (bswap_buffer_size < num_vars * 4) {
+                       bswap_buffer_size = (num_vars + 16384) * 4;
+                       free(bswap_buffer);
+                       bswap_buffer = (void*)malloc(bswap_buffer_size);
+               }
+                       __asm {
+                               mov esi, dword ptr [src]
+                               mov edi, dword ptr [bswap_buffer]
+                               mov ecx, num_vars
+                               
+                               mov ebx, ecx
+                               and ecx, 3
+                               je BSWAP_DWORD_4X
+                               
+                       BSWAP_DWORD_LOOP:
+                               mov eax, [esi]
+                               bswap eax
+                               mov [edi], eax
+                               add esi, 4
+                               add edi, 4
+                               loopne BSWAP_DWORD_LOOP
+                               
+                       BSWAP_DWORD_4X:
+                               mov ecx, ebx
+                               shr ecx, 2
+                               je BSWAP_DWORD_END
+                       BSWAP_DWORD_4X_LOOP:
+                               mov eax, [esi]
+                               bswap eax
+                               mov [edi], eax
+                               mov eax, [esi+4]
+                               bswap eax
+                               mov [edi+4], eax
+                               mov eax, [esi+8]
+                               bswap eax
+                               mov [edi+8], eax
+                               mov eax, [esi+12]
+                               bswap eax
+                               mov [edi+12], eax
+                               add esi, 16
+                               add edi, 16
+                               loopne BSWAP_DWORD_4X_LOOP
+                               
+                       BSWAP_DWORD_END:
+                       }
+               return (uae_u32) bswap_buffer;
+       case 108:               //frees swap array
+               bswap_buffer_size = 0;
+               free(bswap_buffer);
+               bswap_buffer = NULL;
+               return 0;       
+       case 200:
+     ahitweak = m68k_dreg (regs, 1);
+        return 1;
+       default:
+       return 0x12345678;     // Code for not supportet function
+       }
+} 
diff --git a/od-win32/ahidsound.h b/od-win32/ahidsound.h
new file mode 100755 (executable)
index 0000000..108bdbd
--- /dev/null
@@ -0,0 +1,9 @@
+extern void ahi_updatesound( int force );
+extern uae_u32 ahi_demux(void);
+extern int ahi_open_sound (void);
+extern void ahi_close_sound (void);
+extern void ahi_finish_sound_buffer( void );
+
+extern int ahi_on;
+
+
diff --git a/od-win32/asm.bat b/od-win32/asm.bat
new file mode 100755 (executable)
index 0000000..ec0326b
--- /dev/null
@@ -0,0 +1,3 @@
+nasm -O1 -f win32 hq2x32.asm
+nasm -O1 -f win32 hq3x32.asm
+nasm -O1 -f win32 hq4x32.asm
diff --git a/od-win32/avioutput.c b/od-win32/avioutput.c
new file mode 100755 (executable)
index 0000000..dc27cf2
--- /dev/null
@@ -0,0 +1,930 @@
+/*
+  UAE - The Ultimate Amiga Emulator
+  
+  avioutput.c
+  
+  Copyright(c) 2001 - 2002; Â§ane
+
+*/
+
+#include <windows.h>
+
+#include <ddraw.h>
+
+#include <mmsystem.h>
+#include <vfw.h>
+#include <msacm.h>
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+#include "options.h"
+#include "custom.h"
+#include "picasso96.h"
+#include "dxwrap.h"
+#include "win32.h"
+#include "win32gfx.h"
+#include "direct3d.h"
+#include "opengl.h"
+#include "sound.h"
+#include "gfxfilter.h"
+#include "xwin.h"
+#include "resource.h"
+#include "avioutput.h"
+
+static int newmode = 1;
+
+#define MAX_AVI_SIZE (0x80000000 - 0x1000000)
+
+static int avioutput_init = 0;
+static int actual_width = 320, actual_height = 256;
+static int avioutput_needs_restart;
+
+static int frame_start; // start frame
+static int frame_count; // current frame
+static int frame_end; // end frame (0 = no end, infinite)
+static int frame_skip;
+static unsigned int total_avi_size;
+static int partcnt;
+
+static unsigned int StreamSizeAudio; // audio write position
+static double StreamSizeAudioExpected;
+
+int avioutput_audio, avioutput_video, avioutput_enabled, avioutput_requested;
+
+int avioutput_width = 320, avioutput_height = 256, avioutput_bits = 24;
+int avioutput_fps = VBLANK_HZ_PAL;
+int avioutput_framelimiter = 0;
+
+char avioutput_filename[MAX_PATH] = "output.avi";
+static char avioutput_filename_tmp[MAX_PATH];
+
+extern struct uae_prefs workprefs;
+extern char config_filename[256];
+
+static CRITICAL_SECTION AVIOutput_CriticalSection;
+
+
+static PAVIFILE pfile = NULL; // handle of our AVI file
+static PAVISTREAM AVIStreamInterface = NULL; // Address of stream interface
+
+
+/* audio */
+
+static PAVISTREAM AVIAudioStream = NULL; // compressed stream pointer
+
+static HACMSTREAM has = NULL; // stream handle that can be used to perform conversions
+static ACMSTREAMHEADER ash;
+
+static ACMFORMATCHOOSE acmopt;
+
+static WAVEFORMATEX wfxSrc; // source audio format
+static LPWAVEFORMATEX pwfxDst = NULL; // pointer to destination audio format
+
+static uae_u8 *lpAudio; // pointer to audio data
+
+static FILE *wavfile;
+
+/* video */
+
+static PAVISTREAM AVIVideoStream = NULL; // compressed stream pointer
+
+static AVICOMPRESSOPTIONS videoOptions;
+static AVICOMPRESSOPTIONS FAR * aOptions[] = { &videoOptions }; // array of pointers to AVICOMPRESSOPTIONS structures
+
+static PCOMPVARS pcompvars;
+
+static LPBITMAPINFOHEADER lpbi = NULL; // can also be used as LPBITMAPINFO because we allocate memory for bitmap info header + bitmap infomation
+static uae_u8 *lpVideo = NULL; // pointer to video data (bitmap bits)
+
+
+
+static UINT CALLBACK acmFilterChooseHookProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+       if(uMsg == MM_ACM_FORMATCHOOSE)
+       {
+               switch(wParam)
+               {
+               case FORMATCHOOSE_FORMATTAG_VERIFY:
+                       switch(lParam) // remove known error prone codecs
+                       {
+                       case WAVE_FORMAT_ADPCM: // 0x0002 Microsoft Corporation
+                       case WAVE_FORMAT_IMA_ADPCM: // 0x0011 Intel Corporation
+                       case WAVE_FORMAT_GSM610: // 0x0031 Microsoft Corporation
+                       case WAVE_FORMAT_SONY_SCX: // 0x0270 Sony Corp.
+                               return TRUE;
+                       }
+                       break;
+               }
+       }
+       
+       return FALSE;
+}
+
+void AVIOutput_ReleaseAudio(void)
+{
+       if(lpAudio)
+       {
+               free(lpAudio);
+               lpAudio = NULL;
+       }
+       
+       if(pwfxDst)
+       {
+               free(pwfxDst);
+               pwfxDst = NULL;
+       }
+}
+
+void AVIOutput_ReleaseVideo(void)
+{
+       if(pcompvars)
+       {
+               ICClose(pcompvars->hic); // <sane> did we inadvertently open it?
+               ICCompressorFree(pcompvars);
+               free(pcompvars);
+               pcompvars = NULL;
+       }
+       
+       if(lpbi)
+       {
+               free(lpbi);
+               lpbi = NULL;
+       }
+       
+       if(lpVideo)
+       {
+               free(lpVideo);
+               lpVideo = NULL;
+       }
+}
+
+LPSTR AVIOutput_ChooseAudioCodec(HWND hwnd)
+{
+       DWORD wfxMaxFmtSize;
+       MMRESULT err;
+       
+       AVIOutput_ReleaseAudio();
+       
+       if((err = acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &wfxMaxFmtSize)))
+       {
+               gui_message("acmMetrics() FAILED (%X)\n", err);
+               return NULL;
+       }
+       
+       // set the source format
+       wfxSrc.wFormatTag = WAVE_FORMAT_PCM;
+       wfxSrc.nChannels = workprefs.stereo ? 2 : 1;
+       wfxSrc.nSamplesPerSec = workprefs.sound_freq;
+       wfxSrc.nBlockAlign = wfxSrc.nChannels * (workprefs.sound_bits / 8);
+       wfxSrc.nAvgBytesPerSec = wfxSrc.nBlockAlign * wfxSrc.nSamplesPerSec;
+       wfxSrc.wBitsPerSample = workprefs.sound_bits;
+       wfxSrc.cbSize = 0;
+       
+       if(!(pwfxDst = (LPWAVEFORMATEX) malloc(wfxMaxFmtSize)))
+               return NULL;
+       
+       // set the initial destination format to match source
+       memset(pwfxDst, 0, wfxMaxFmtSize);
+       memcpy(pwfxDst, &wfxSrc, sizeof(WAVEFORMATEX));
+       pwfxDst->cbSize = (WORD) (wfxMaxFmtSize - sizeof(WAVEFORMATEX)); // shrugs
+       
+       memset(&acmopt, 0, sizeof(ACMFORMATCHOOSE));
+       
+       acmopt.cbStruct = sizeof(ACMFORMATCHOOSE);
+       acmopt.fdwStyle = ACMFORMATCHOOSE_STYLEF_ENABLEHOOK | ACMFORMATCHOOSE_STYLEF_INITTOWFXSTRUCT;
+       acmopt.hwndOwner = hwnd;
+       
+       acmopt.pwfx = pwfxDst;
+       acmopt.cbwfx = wfxMaxFmtSize;
+       
+       acmopt.pszTitle  = "Choose Audio Codec";
+       
+       //acmopt.szFormatTag =; // not valid until the format is chosen
+       //acmopt.szFormat =; // not valid until the format is chosen
+       
+       //acmopt.pszName =; // can use later in config saving loading
+       //acmopt.cchName =; // size of pszName, as pszName can be non-null-terminated
+       
+       acmopt.fdwEnum = ACM_FORMATENUMF_INPUT | ACM_FORMATENUMF_NCHANNELS | ACM_FORMATENUMF_NSAMPLESPERSEC;
+       //ACM_FORMATENUMF_CONVERT // renders WinUAE unstable for some unknown reason
+       //ACM_FORMATENUMF_WBITSPERSAMPLE // MP3 doesn't apply so it will be removed from codec selection
+       //ACM_FORMATENUMF_SUGGEST // with this flag set, only MP3 320kbps is displayed, which is closest to the source format
+       
+       acmopt.pwfxEnum = &wfxSrc;
+       
+       acmopt.pfnHook = acmFilterChooseHookProc;
+       
+       switch(acmFormatChoose(&acmopt))
+       {
+       case MMSYSERR_NOERROR:
+               {
+                       
+                       return acmopt.szFormatTag;
+               }
+               
+       case ACMERR_CANCELED:
+               //MessageBox(hwnd, "The user chose the Cancel button or the Close command on the System menu to close the dialog box.", VersionStr, MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
+               break;
+               
+       case ACMERR_NOTPOSSIBLE:
+               MessageBox(hwnd, "The buffer identified by the pwfx member of the ACMFORMATCHOOSE structure is too small to contain the selected format.", VersionStr, MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
+               break;
+               
+       case MMSYSERR_INVALFLAG:
+               MessageBox(hwnd, "At least one flag is invalid.", VersionStr, MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
+               break;
+               
+       case MMSYSERR_INVALHANDLE:
+               MessageBox(hwnd, "The specified handle is invalid.", VersionStr, MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
+               break;
+               
+       case MMSYSERR_INVALPARAM:
+               MessageBox(hwnd, "At least one parameter is invalid.", VersionStr, MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
+               break;
+               
+       case MMSYSERR_NODRIVER:
+               MessageBox(hwnd, "A suitable driver is not available to provide valid format selections.", VersionStr, MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
+               break;
+               
+       default:
+               MessageBox(hwnd, "acmFormatChoose() FAILED", VersionStr, MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
+               break;
+       }
+       
+       return NULL;
+}
+
+LPSTR AVIOutput_ChooseVideoCodec(HWND hwnd)
+{
+       ICINFO icinfo = { 0 };
+       
+       AVIOutput_ReleaseVideo();
+
+       if (newmode) {
+           avioutput_width = workprefs.gfx_width;
+           avioutput_height = workprefs.gfx_height;
+           avioutput_bits = workprefs.color_mode == 2 ? 16 : workprefs.color_mode > 2 ? 32 : 8;
+       }
+       
+       if(!(lpbi = (LPBITMAPINFOHEADER) malloc(sizeof(BITMAPINFOHEADER) + (((avioutput_bits <= 8) ? 1 << avioutput_bits : 0) * sizeof(RGBQUAD)))))
+               return NULL;
+       
+       lpbi->biSize = sizeof(BITMAPINFOHEADER);
+       lpbi->biWidth = avioutput_width;
+       lpbi->biHeight = avioutput_height;
+       lpbi->biPlanes = 1;
+       lpbi->biBitCount = avioutput_bits;
+       lpbi->biCompression = BI_RGB; // uncompressed format
+       lpbi->biSizeImage = (lpbi->biWidth * lpbi->biHeight) * (lpbi->biBitCount / 8);
+       lpbi->biXPelsPerMeter = 0; // ??
+       lpbi->biYPelsPerMeter = 0; // ??
+       lpbi->biClrUsed = (lpbi->biBitCount <= 8) ? 1 << lpbi->biBitCount : 0;
+       lpbi->biClrImportant = 0;
+
+       if(!(pcompvars = (PCOMPVARS) malloc(sizeof(COMPVARS))))
+               return NULL;
+       
+       memset(pcompvars, 0, sizeof(COMPVARS));
+       pcompvars->cbSize = sizeof(COMPVARS);
+       
+       // we really should check first to see if the user has a particular compressor installed before we set one
+       // we could set one but we will leave it up to the operating system and the set priority levels for the compressors
+       
+       // default
+       //pcompvars->fccHandler = mmioFOURCC('C','V','I','D'); // "Cinepak Codec by Radius"
+       //pcompvars->fccHandler = mmioFOURCC('M','R','L','E'); // "Microsoft RLE"
+       //pcompvars->fccHandler = mmioFOURCC('D','I','B',' '); // "Full Frames (Uncompressed)"
+       
+       pcompvars->lQ = 10000; // 10000 is maximum quality setting or ICQUALITY_DEFAULT for default
+       pcompvars->lKey = avioutput_fps; // default to one key frame per second, every (FPS) frames
+       
+       pcompvars->dwFlags = ICMF_COMPVARS_VALID;
+       
+       if(ICCompressorChoose(hwnd, ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME, lpbi, NULL, pcompvars, "Choose Video Codec") == TRUE)
+       {
+               if(pcompvars->fccHandler == mmioFOURCC('D','I','B',' '))
+                       return "Full Frames (Uncompressed)";
+               
+               if(ICGetInfo(pcompvars->hic, &icinfo, sizeof(ICINFO)) != 0)
+               {
+                       static char string[128];
+                       
+                       if(WideCharToMultiByte(CP_ACP, 0, icinfo.szDescription, -1, string, 128, NULL, NULL) != 0)
+                               return string;
+               }
+       }
+       
+       return NULL;
+}
+
+static void checkAVIsize (int force)
+{
+    int tmp_partcnt = partcnt + 1;
+    int tmp_avioutput_video = avioutput_video;
+    int tmp_avioutput_audio = avioutput_audio;
+    char fn[MAX_PATH];
+
+    if (!force && total_avi_size < MAX_AVI_SIZE)
+       return;
+    strcpy (fn, avioutput_filename_tmp);
+    sprintf (avioutput_filename, "%s_%d.avi", fn, tmp_partcnt);
+    write_log("AVI split %d at %d bytes, %d frames\n",
+       tmp_partcnt, total_avi_size, frame_count);
+    AVIOutput_End ();
+    total_avi_size = 0;
+    avioutput_video = tmp_avioutput_video;
+    avioutput_audio = tmp_avioutput_audio;
+    AVIOutput_Begin ();
+    strcpy (avioutput_filename_tmp, fn);
+    partcnt = tmp_partcnt;
+}
+
+static void dorestart (void)
+{
+    write_log ("AVIOutput: parameters changed, restarting..\n");
+    avioutput_needs_restart = 0;
+    checkAVIsize (1);
+}
+
+static void AVIOuput_AVIWriteAudio (uae_u8 *sndbuffer, int sndbufsize)
+{
+       DWORD dwOutputBytes = 0, written = 0, swritten = 0;
+       unsigned int err;
+       
+        if (avioutput_needs_restart)
+           dorestart ();
+
+       EnterCriticalSection(&AVIOutput_CriticalSection);
+       
+       if(avioutput_audio)
+       {
+               if(!avioutput_init)
+                       goto error;
+               
+               if((err = acmStreamSize(has, sndbufsize, &dwOutputBytes, ACM_STREAMSIZEF_SOURCE) != 0))
+               {
+                       gui_message("acmStreamSize() FAILED (%X)\n", err);
+                       goto error;
+               }
+               
+               if(!(lpAudio = malloc(dwOutputBytes)))
+               {
+                       goto error;
+               }
+
+               ash.cbStruct = sizeof(ACMSTREAMHEADER);
+               ash.fdwStatus = 0;
+               ash.dwUser = 0;
+               
+               // source
+               ash.pbSrc = sndbuffer;
+               
+               ash.cbSrcLength = sndbufsize;
+               ash.cbSrcLengthUsed = 0; // This member is not valid until the conversion is complete.
+               
+               ash.dwSrcUser = 0;
+               
+               // destination
+               ash.pbDst = lpAudio;
+               
+               ash.cbDstLength = dwOutputBytes;
+               ash.cbDstLengthUsed = 0; // This member is not valid until the conversion is complete.
+               
+               ash.dwDstUser = 0;
+               
+               if((err = acmStreamPrepareHeader(has, &ash, 0)))
+               {
+                       gui_message("acmStreamPrepareHeader() FAILED (%X)\n", err);
+                       goto error;
+               }
+               
+               if((err = acmStreamConvert(has, &ash, ACM_STREAMCONVERTF_BLOCKALIGN)))
+               {
+                       gui_message("acmStreamConvert() FAILED (%X)\n", err);
+                       goto error;
+               }
+               
+               if((err = AVIStreamWrite(AVIAudioStream, StreamSizeAudio, ash.cbDstLengthUsed / pwfxDst->nBlockAlign, lpAudio, ash.cbDstLengthUsed, 0, &swritten, &written)) != 0)
+               {
+                       gui_message("AVIStreamWrite() FAILED (%X)\n", err);
+                       goto error;
+               }
+               
+               StreamSizeAudio += swritten;
+               total_avi_size += written;
+               
+               acmStreamUnprepareHeader(has, &ash, 0);
+               
+               if(lpAudio)
+               {
+                       free(lpAudio);
+                       lpAudio = NULL;
+               }
+               checkAVIsize (0);
+       }
+       
+       LeaveCriticalSection(&AVIOutput_CriticalSection);
+       return;
+       
+error:
+       
+       LeaveCriticalSection(&AVIOutput_CriticalSection);
+       AVIOutput_End();
+}
+
+static void AVIOuput_WAVWriteAudio (uae_u8 *sndbuffer, int sndbufsize)
+{
+    fwrite (sndbuffer, 1, sndbufsize, wavfile);
+}
+
+void AVIOutput_WriteAudio(uae_u8 *sndbuffer, int sndbufsize)
+{
+    if (!avioutput_audio || !avioutput_enabled)
+       return;
+    if (avioutput_audio == AVIAUDIO_WAV)
+       AVIOuput_WAVWriteAudio (sndbuffer, sndbufsize);
+    else
+       AVIOuput_AVIWriteAudio (sndbuffer, sndbufsize);
+}
+
+static int getFromDC(LPBITMAPINFO lpbi)
+{
+    HDC hdc;
+    HBITMAP hbitmap = NULL;
+    HBITMAP hbitmapOld = NULL;
+    HDC hdcMem = NULL;
+    int ok = 1;
+
+    hdc = gethdc();
+    if (!hdc)
+       return 0;
+    // create a memory device context compatible with the application's current screen
+    hdcMem = CreateCompatibleDC(hdc);
+    hbitmap = CreateCompatibleBitmap(hdc, avioutput_width, avioutput_height);
+    hbitmapOld = SelectObject(hdcMem, hbitmap);
+    // probably not the best idea to use slow GDI functions for this,
+    // locking the surfaces and copying them by hand would be more efficient perhaps
+    // draw centered in frame
+    BitBlt(hdcMem, (avioutput_width / 2) - (actual_width / 2), (avioutput_height / 2) - (actual_height / 2), actual_width, actual_height, hdc, 0, 0, SRCCOPY);
+    SelectObject(hdcMem, hbitmapOld);
+    if(GetDIBits(hdc, hbitmap, 0, avioutput_height, lpVideo, (LPBITMAPINFO) lpbi, DIB_RGB_COLORS) == 0)
+    {
+       gui_message("GetDIBits() FAILED (%X)\n", GetLastError());
+       ok = 0;
+    }
+    DeleteObject(hbitmap);
+    DeleteDC(hdcMem);
+    releasehdc(hdc);
+    return ok;
+}
+
+static int rgb_type;
+
+void AVIOutput_RGBinfo(int rb, int gb, int bb, int rs, int gs, int bs)
+{
+    if (bs == 0 && gs == 5 && rs == 11)
+       rgb_type = 1;
+    else if (bs == 0 && gs == 8 && rs == 16)
+       rgb_type = 2;
+    else
+       rgb_type = 0;
+}
+
+extern int bufmem_width, bufmem_height;
+extern uae_u8 *bufmem_ptr;
+
+static int getFromBuffer(LPBITMAPINFO lpbi)
+{
+    int w, h, x, y;
+    uae_u8 *src;
+    uae_u8 *dst = lpVideo;
+
+    src = bufmem_ptr;
+    if (!src)
+       return 0;
+    w = bufmem_width;
+    h = bufmem_height;
+    dst += avioutput_width * gfxvidinfo.pixbytes * avioutput_height;
+    for (y = 0; y < (gfxvidinfo.height > avioutput_height ? avioutput_height : gfxvidinfo.height); y++) {
+       dst -= avioutput_width * gfxvidinfo.pixbytes;
+       for (x = 0; x < (gfxvidinfo.width > avioutput_width ? avioutput_width : gfxvidinfo.width); x++) {
+           if (gfxvidinfo.pixbytes == 1) {
+               dst[x] = src[x];
+           } else if (gfxvidinfo.pixbytes == 2) {
+               uae_u16 v = ((uae_u16*)src)[x];
+               uae_u16 v2 = v;
+               if (rgb_type) {
+                   v2 = v & 31;
+                   v2 |= (v >> 1) & (31 << 5);
+                   v2 |= (v >> 1) & (31 << 10);
+               }
+               ((uae_u16*)dst)[x] = v2;
+           } else if (gfxvidinfo.pixbytes == 4) {
+               uae_u32 v = ((uae_u32*)src)[x];
+               ((uae_u32*)dst)[x] = v;
+           }
+       }
+        src += gfxvidinfo.rowbytes;
+    }
+    return 1;
+}
+
+
+void AVIOutput_WriteVideo(void)
+{
+    DWORD written = 0;
+    int v;
+    unsigned int err;
+
+    if (avioutput_needs_restart)
+       dorestart ();
+
+    EnterCriticalSection(&AVIOutput_CriticalSection);
+
+    if(avioutput_video) {
+
+       if(!avioutput_init)
+           goto error;
+
+       if (newmode) {
+           actual_width = gfxvidinfo.width;
+           actual_height = gfxvidinfo.height;
+       } else {
+           actual_width = WIN32GFX_GetWidth();
+           actual_height = WIN32GFX_GetHeight();
+       }
+
+       if (!usedfilter || (usedfilter && usedfilter->x[0]) || WIN32GFX_IsPicassoScreen ())
+           v = getFromDC((LPBITMAPINFO)lpbi);
+       else
+           v = getFromBuffer((LPBITMAPINFO)lpbi);
+       if (!v)
+           goto error;
+
+       // GetDIBits tends to change this and ruins palettized output
+       lpbi->biClrUsed = (avioutput_bits <= 8) ? 1 << avioutput_bits : 0;
+
+       if(!frame_count)
+       {
+           if((err = AVIStreamSetFormat(AVIVideoStream, frame_count, lpbi, lpbi->biSize + (lpbi->biClrUsed * sizeof(RGBQUAD)))) != 0)
+           {
+               gui_message("AVIStreamSetFormat() FAILED (%X)\n", err);
+               goto error;
+           }
+       }
+                       
+       if((err = AVIStreamWrite(AVIVideoStream, frame_count, 1, lpVideo, lpbi->biSizeImage, 0, NULL, &written)) != 0)
+       {
+           gui_message("AVIStreamWrite() FAILED (%X)\n", err);
+           goto error;
+       }
+                       
+       frame_count++;
+       total_avi_size += written;
+                       
+       if(frame_end)
+       {
+           if(frame_count >= frame_end)
+           {
+               AVIOutput_End();
+           }
+       }
+       checkAVIsize (0);
+
+    } else {
+
+        gui_message("DirectDraw_GetDC() FAILED\n");
+        goto error;
+
+    }
+
+    LeaveCriticalSection(&AVIOutput_CriticalSection);
+    if ((frame_count % (avioutput_fps * 10)) == 0)
+       write_log ("AVIOutput: %d frames, (%d fps)\n", frame_count, avioutput_fps);
+    return;
+       
+error:
+
+    LeaveCriticalSection(&AVIOutput_CriticalSection);
+    AVIOutput_End();
+}
+
+static void writewavheader (uae_u32 size)
+{
+    uae_u16 tw;
+    uae_u32 tl;
+    int bits = 16, channels = currprefs.stereo ? 2 : 1;
+
+    fseek (wavfile, 0, SEEK_SET);
+    fwrite ("RIFF", 1, 4, wavfile);
+    tl = 0;
+    if (size)
+       tl = size - 8;
+    fwrite (&tl, 1, 4, wavfile);
+    fwrite ("WAVEfmt ", 1, 8, wavfile);
+    tl = 16;
+    fwrite (&tl, 1, 4, wavfile);
+    tw = 1;
+    fwrite (&tw, 1, 2, wavfile);
+    tw = channels;
+    fwrite (&tw, 1, 2, wavfile);
+    tl = currprefs.sound_freq;
+    fwrite (&tl, 1, 4, wavfile);
+    tl = currprefs.sound_freq * channels * bits / 8;
+    fwrite (&tl, 1, 4, wavfile);
+    tw = channels * bits / 8;
+    fwrite (&tw, 1, 2, wavfile);
+    tw = bits;
+    fwrite (&tw, 1, 2, wavfile);
+    fwrite ("data", 1, 4, wavfile);
+    tl = 0;
+    if (size)
+       tl = size - 44;
+    fwrite (&tl, 1, 4, wavfile);
+}
+
+void AVIOutput_Restart(void)
+{
+    avioutput_needs_restart = 1;
+}
+
+void AVIOutput_End(void)
+{
+       EnterCriticalSection(&AVIOutput_CriticalSection);
+       
+       avioutput_audio = avioutput_video = 0;
+       avioutput_enabled = 0;
+       
+       if(has)
+       {
+               acmStreamUnprepareHeader(has, &ash, 0);
+               acmStreamClose(has, 0);
+               has = NULL;
+       }
+       
+       if(AVIAudioStream)
+       {
+               AVIStreamRelease(AVIAudioStream);
+               AVIAudioStream = NULL;
+       }
+       
+       if(AVIVideoStream)
+       {
+               AVIStreamRelease(AVIVideoStream);
+               AVIVideoStream = NULL;
+       }
+       
+       if(AVIStreamInterface)
+       {
+               AVIStreamRelease(AVIStreamInterface);
+               AVIStreamInterface = NULL;
+       }
+       
+       if(pfile)
+       {
+               AVIFileRelease(pfile);
+               pfile = NULL;
+       }
+
+       StreamSizeAudio = frame_count = 0;
+       StreamSizeAudioExpected = 0;
+       partcnt = 0;
+
+       if (wavfile) {
+           writewavheader (ftell (wavfile));
+           fclose (wavfile);
+           wavfile = 0;
+       }
+           
+       
+       LeaveCriticalSection(&AVIOutput_CriticalSection);
+}
+
+void AVIOutput_Begin(void)
+{
+       AVISTREAMINFO avistreaminfo; // Structure containing information about the stream, including the stream type and its sample rate
+       int i, err;
+       char *ext1, *ext2;
+
+       if (avioutput_enabled) {
+           if (!avioutput_requested)
+               AVIOutput_End ();
+           return;
+       }
+       if (!avioutput_requested)
+           return;
+
+       reset_sound ();
+       if (avioutput_audio == AVIAUDIO_WAV) {
+           ext1 = ".wav"; ext2 = ".avi";
+       } else {
+           ext1 = ".avi"; ext2 = ".wav";
+       }
+       if (strlen (avioutput_filename) >= 4 && strcmpi (avioutput_filename + strlen (avioutput_filename) - 4, ext2))
+           avioutput_filename[strlen (avioutput_filename) - 4] = 0;
+       if (strlen (avioutput_filename) >= 4 && strcmpi (avioutput_filename + strlen (avioutput_filename) - 4, ext1))
+           strcat (avioutput_filename, ext1);
+       strcpy (avioutput_filename_tmp, avioutput_filename);
+       i = strlen (avioutput_filename_tmp) - 1;
+       while (i > 0 && avioutput_filename_tmp[i] != '.') i--;
+       if (i > 0)
+           avioutput_filename_tmp[i] = 0;
+
+       avioutput_needs_restart = 0;
+       avioutput_enabled = avioutput_audio || avioutput_video;
+       if(!avioutput_init || !avioutput_enabled)
+               goto error;
+       
+       // delete any existing file before writing AVI
+       SetFileAttributes(avioutput_filename, FILE_ATTRIBUTE_ARCHIVE);
+       DeleteFile(avioutput_filename);
+
+       if (avioutput_audio == AVIAUDIO_WAV) {
+           wavfile = fopen (avioutput_filename, "wb");
+           if (!wavfile) {
+               gui_message("Failed to open wave-file\n\nThis can happen if the path and or file name was entered incorrectly.\n");
+               goto error;
+           }
+           writewavheader (0);
+           write_log ("wave-output to '%s' started\n", avioutput_filename);
+           return;
+       }
+       
+       if(((err = AVIFileOpen(&pfile, avioutput_filename, OF_CREATE | OF_WRITE, NULL)) != 0))
+       {
+               gui_message("AVIFileOpen() FAILED (Error %X)\n\nThis can happen if the path and or file name was entered incorrectly.\nRequired *.avi extension.\n", err);
+               goto error;
+       }
+       
+       if(avioutput_audio)
+       {
+               memset(&avistreaminfo, 0, sizeof(AVISTREAMINFO));
+               avistreaminfo.fccType = streamtypeAUDIO;
+               avistreaminfo.fccHandler = 0; // This member is not used for audio streams.
+               avistreaminfo.dwFlags = 0;
+               //avistreaminfo.dwCaps =; // Capability flags; currently unused.
+               //avistreaminfo.wPriority =;
+               //avistreaminfo.wLanguage =;
+               avistreaminfo.dwScale = pwfxDst->nBlockAlign;
+               avistreaminfo.dwRate = pwfxDst->nAvgBytesPerSec;
+               avistreaminfo.dwStart = 0;
+               avistreaminfo.dwLength = -1;
+               avistreaminfo.dwInitialFrames = 0;
+               avistreaminfo.dwSuggestedBufferSize = 0; // Use zero if you do not know the correct buffer size.
+               avistreaminfo.dwQuality = -1; // -1 default quality value
+               avistreaminfo.dwSampleSize = pwfxDst->nBlockAlign;
+               //avistreaminfo.rcFrame; // doesn't apply to audio
+               //avistreaminfo.dwEditCount =; // Number of times the stream has been edited. The stream handler maintains this count.
+               //avistreaminfo.dwFormatChangeCount =; // Number of times the stream format has changed. The stream handler maintains this count.
+               strcpy(avistreaminfo.szName, "Audiostream"); // description of the stream.
+               
+               
+               // create the audio stream
+               if((err = AVIFileCreateStream(pfile, &AVIAudioStream, &avistreaminfo)) != 0)
+               {
+                       gui_message("AVIFileCreateStream() FAILED (%X)\n", err);
+                       goto error;
+               }
+               
+               if((err = AVIStreamSetFormat(AVIAudioStream, 0, pwfxDst, sizeof(WAVEFORMATEX) + pwfxDst->cbSize)) != 0)
+               {
+                       gui_message("AVIStreamSetFormat() FAILED (%X)\n", err);
+                       goto error;
+               }
+               
+               if((err = acmStreamOpen(&has, NULL, &wfxSrc, pwfxDst, NULL, 0, 0, ACM_STREAMOPENF_NONREALTIME)) != 0)
+               {
+                       gui_message("acmStreamOpen() FAILED (%X)\n", err);
+                       goto error;
+               }
+       }
+       
+       if(avioutput_video)
+       {
+               if(!(lpVideo = malloc(lpbi->biSizeImage)))
+               {
+                       goto error;
+               }
+               
+               // fill in the header for the video stream
+               memset(&avistreaminfo, 0, sizeof(AVISTREAMINFO));
+               avistreaminfo.fccType = streamtypeVIDEO; // stream type
+               
+               // unsure about this, as this is the uncompressed stream, not the compressed stream
+               //avistreaminfo.fccHandler = 0;
+               
+               // incase the amiga changes palette
+               if(lpbi->biBitCount < 24)
+                       avistreaminfo.dwFlags = AVISTREAMINFO_FORMATCHANGES;
+               
+               //avistreaminfo.dwCaps =; // Capability flags; currently unused
+               //avistreaminfo.wPriority =; // Priority of the stream
+               //avistreaminfo.wLanguage =; // Language of the stream
+               avistreaminfo.dwScale = 1;
+               avistreaminfo.dwRate = avioutput_fps; // our playback speed default (PAL 50fps), (NTSC 60fps)
+               avistreaminfo.dwStart = 0; // no delay
+               avistreaminfo.dwLength = 1; // initial length
+               //avistreaminfo.dwInitialFrames =; // audio only
+               avistreaminfo.dwSuggestedBufferSize = lpbi->biSizeImage;
+               avistreaminfo.dwQuality = -1; // drivers will use the default quality setting
+               avistreaminfo.dwSampleSize = 0; // variable video data samples
+               
+               SetRect(&avistreaminfo.rcFrame, 0, 0, lpbi->biWidth, lpbi->biHeight); // rectangle for stream
+               
+               //avistreaminfo.dwEditCount =; // Number of times the stream has been edited. The stream handler maintains this count.
+               //avistreaminfo.dwFormatChangeCount =; // Number of times the stream format has changed. The stream handler maintains this count.
+               strcpy(avistreaminfo.szName, "Videostream"); // description of the stream.
+               
+               // create the stream
+               if((err = AVIFileCreateStream(pfile, &AVIStreamInterface, &avistreaminfo)) != 0)
+               {
+                       gui_message("AVIFileCreateStream() FAILED (%X)\n", err);
+                       goto error;
+               }
+               
+               videoOptions.fccType = streamtypeVIDEO;
+               videoOptions.fccHandler = pcompvars->fccHandler;
+               videoOptions.dwKeyFrameEvery = pcompvars->lKey;
+               videoOptions.dwQuality = pcompvars->lQ;
+               
+               videoOptions.dwBytesPerSecond = pcompvars->lDataRate * 1024;
+               videoOptions.dwFlags = AVICOMPRESSF_VALID | AVICOMPRESSF_KEYFRAMES | AVICOMPRESSF_INTERLEAVE | AVICOMPRESSF_DATARATE;
+               
+               videoOptions.dwInterleaveEvery = 1;
+               
+               videoOptions.cbFormat = sizeof(BITMAPINFOHEADER);
+               videoOptions.lpFormat = lpbi;
+               
+               videoOptions.cbParms = pcompvars->cbState;
+               videoOptions.lpParms = pcompvars->lpState;
+               
+               // create a compressed stream from our uncompressed stream and a compression filter
+               if((err = AVIMakeCompressedStream(&AVIVideoStream, AVIStreamInterface, &videoOptions, NULL)) != AVIERR_OK)
+               {
+                       gui_message("AVIMakeCompressedStream() FAILED (%X)\n", err);
+                       goto error;
+               }
+       }
+       write_log ("AVIOutput enabled: video=%d audio=%d\n", avioutput_video, avioutput_audio);
+       return;
+       
+error:
+       
+       AVIOutput_End();
+}
+
+void AVIOutput_Release(void)
+{
+       AVIOutput_End();
+       
+       AVIOutput_ReleaseAudio();
+       AVIOutput_ReleaseVideo();
+       
+       if(avioutput_init)
+       {
+               AVIFileExit();
+               avioutput_init = 0;
+       }
+       
+       DeleteCriticalSection(&AVIOutput_CriticalSection);
+}
+
+void AVIOutput_Initialize(void)
+{
+       InitializeCriticalSection(&AVIOutput_CriticalSection);
+       
+       if(!avioutput_init)
+       {
+               AVIFileInit();
+               avioutput_init = 1;
+       }
+}
+
+#include <math.h>
+
+#define ADJUST_SIZE 10
+#define EXP 1.5
+
+void frame_drawn(void)
+{
+    double diff, skipmode;
+
+    if (!avioutput_video || !avioutput_enabled)
+       return;
+
+    AVIOutput_WriteVideo();
+
+    if (avioutput_audio && (frame_count % avioutput_fps) == 0) {
+       StreamSizeAudioExpected += currprefs.sound_freq;
+        diff = (StreamSizeAudio - StreamSizeAudioExpected) / sndbufsize;
+       skipmode = pow (diff < 0 ? -diff : diff, EXP);
+       if (diff < 0) skipmode = -skipmode;
+       if (skipmode < -ADJUST_SIZE) skipmode = -ADJUST_SIZE;
+       if (skipmode > ADJUST_SIZE) skipmode = ADJUST_SIZE;
+       sound_setadjust (skipmode);
+       write_log("AVIOutput: diff=%.2f skip=%.2f\n", diff, skipmode);
+    }
+}
+
+
+
diff --git a/od-win32/avioutput.h b/od-win32/avioutput.h
new file mode 100755 (executable)
index 0000000..9365eaf
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+  UAE - The Ultimate Amiga Emulator
+  
+  avioutput.h
+  
+  Copyright(c) 2001 - 2002 Â§ane
+*/
+
+extern int avioutput_video, avioutput_audio, avioutput_enabled, avioutput_requested;
+
+extern int avioutput_width, avioutput_height, avioutput_bits;
+extern int avioutput_fps, avioutput_framelimiter;
+
+extern char avioutput_filename[MAX_PATH];
+
+extern void AVIOutput_WriteAudio(uae_u8 *sndbuffer, int sndbufsize);
+extern void AVIOutput_WriteVideo(void);
+extern LPSTR AVIOutput_ChooseAudioCodec(HWND hwnd);
+extern LPSTR AVIOutput_ChooseVideoCodec(HWND hwnd);
+extern void AVIOutput_Restart(void);
+extern void AVIOutput_End(void);
+extern void AVIOutput_Begin(void);
+extern void AVIOutput_Release(void);
+extern void AVIOutput_Initialize(void);
+extern void AVIOutput_RGBinfo(int,int,int,int,int,int);
+
+#define AVIAUDIO_AVI 1
+#define AVIAUDIO_WAV 2
+
+/*
+extern int avioutput_pause;
+
+extern int avioutput_bits;
+
+extern int avioutput_fps;
+
+extern int avioutput_width, avioutput_height;
+
+extern int avioutput_video, avioutput_audio;
+
+extern int avioutput_init;
+
+extern int frame_count;
+
+extern char avioutput_filename[MAX_PATH];
+
+extern void AviOutputClearAudioCodec(HWND hwnd);
+extern void AviOutputClearVideoCodec(HWND hwnd);
+
+extern void avioutput_screenshot(void);
+
+extern void AVIWriteAudio(uae_u16* sndbuffer, int sndbufsize);
+extern void AVIWriteVideo(void);
+extern LPSTR AVIChooseAudioCodec(HWND hwnd);
+extern LPSTR AVIChooseVideoCodec(HWND hwnd);
+extern void AVIUninitialize(void);
+extern void AVIInitialize(void);
+*/
\ No newline at end of file
diff --git a/od-win32/blkdev_win32_aspi.c b/od-win32/blkdev_win32_aspi.c
new file mode 100755 (executable)
index 0000000..ac4b1f1
--- /dev/null
@@ -0,0 +1,827 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * WIN32 CDROM/HD low level access code (ASPI)
+  *
+  * Copyright 2002 Toni Wilen
+  *
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "memory.h"
+
+#include "threaddep/thread.h"
+#include "blkdev.h"
+#include "scsidev.h"
+#include "gui.h"
+
+#include <wnaspi32.h>
+
+#include "scsidef.h"
+
+int aspi_allow_misc = 1;
+int aspi_allow_all = 0;
+
+static int busses, AspiLoaded;
+static DWORD (*pfnGetASPI32SupportInfo)(void);
+static DWORD (*pfnSendASPI32Command)(LPSRB);
+static BOOL (*pfnGetASPI32Buffer)(PASPI32BUFF);
+static BOOL (*pfnFreeASPI32Buffer)(PASPI32BUFF);
+static BOOL (*pfnTranslateASPI32Address)(PDWORD, PDWORD);
+static HANDLE hAspiLib;
+static int scanphase;
+
+struct scsi_info {
+    int scsibus,target,lun;
+    int type;
+    int mediainserted;
+    uae_u8 *buf;
+    char label[100];
+    SCSI *handle;
+    int isatapi;
+};
+static struct scsi_info si[MAX_TOTAL_DEVICES];
+static int unitcnt;
+
+static int ha_inquiry(SCSI *scgp, int id, SRB_HAInquiry *ip)
+{
+    DWORD Status;
+       
+    ip->SRB_Cmd        = SC_HA_INQUIRY;
+    ip->SRB_HaId = id;
+    ip->SRB_Flags = 0;
+    ip->SRB_Hdr_Rsvd = 0;
+
+    Status = pfnSendASPI32Command((LPSRB)ip);
+    if (log_scsi)
+       write_log ("ASPI: S=%d ha=%d, ID=%d, M='%s', Id='%s'\n",
+           Status, ip->HA_Count, ip->HA_SCSI_ID, ip->HA_ManagerId, ip->HA_Identifier);
+    if (ip->SRB_Status != SS_COMP)
+       return -1;
+    return 0;
+}
+
+static int open_driver (SCSI *scgp)
+{
+    DWORD      astatus;
+    BYTE       HACount;
+    BYTE       ASPIStatus;
+    int        i;
+
+    /*
+     * Check if ASPI library is already loaded yet
+     */
+    if (AspiLoaded == TRUE)
+       return TRUE;
+    /*
+     * Load the ASPI library
+     */
+    hAspiLib = LoadLibrary("WNASPI32");
+    /*
+     * Check if ASPI library is loaded correctly
+     */
+    if (hAspiLib == NULL) {
+       write_log ("ASPI: failed to load wnaspi32.dll\n");
+       return FALSE;
+    }
+    /*
+     * Get a pointer to GetASPI32SupportInfo function
+     * and a pointer to SendASPI32Command function
+     */
+    pfnGetASPI32SupportInfo = (DWORD(*)(void))GetProcAddress(hAspiLib, "GetASPI32SupportInfo");
+    pfnSendASPI32Command = (DWORD(*)(LPSRB))GetProcAddress(hAspiLib, "SendASPI32Command");
+
+    if ((pfnGetASPI32SupportInfo == NULL) || (pfnSendASPI32Command == NULL)) {
+       write_log ("ASPI: obsolete wnaspi32.dll found\n");
+       return FALSE;
+    }
+
+    pfnGetASPI32Buffer = (BOOL(*)(PASPI32BUFF))GetProcAddress(hAspiLib, "GetASPI32Buffer");
+    pfnFreeASPI32Buffer = (BOOL(*)(PASPI32BUFF))GetProcAddress(hAspiLib, "FreeASPI32Buffer");
+    pfnTranslateASPI32Address = (BOOL(*)(PDWORD, PDWORD))GetProcAddress(hAspiLib, "TranslateASPI32Address");
+
+    /*
+     * Set AspiLoaded variable
+     */
+    AspiLoaded = TRUE;
+
+    astatus = pfnGetASPI32SupportInfo();
+
+    ASPIStatus = HIBYTE(LOWORD(astatus));
+    HACount    = LOBYTE(LOWORD(astatus));
+
+    write_log ("ASPI: open_driver %X HostASPIStatus=0x%x HACount=0x%x\n", astatus, ASPIStatus, HACount);
+
+    if (ASPIStatus != SS_COMP && ASPIStatus != SS_NO_ADAPTERS) {
+       write_log ("ASPI: Could not find any host adapters, ASPIStatus == 0x%02X\n", ASPIStatus);
+       return FALSE;
+    }
+    busses = HACount;
+
+    write_log ("ASPI: open_driver HostASPIStatus=0x%x HACount=0x%x\n", ASPIStatus, HACount);
+
+    for (i=0; i < busses; i++) {
+       SRB_HAInquiry   s;
+       ha_inquiry(scgp, i, &s);
+    }
+    return TRUE;
+}
+
+
+static void close_driver (void)
+{
+    if (!AspiLoaded) return;
+    AspiLoaded = FALSE;
+    pfnGetASPI32SupportInfo = NULL;
+    pfnSendASPI32Command = NULL;
+    pfnGetASPI32Buffer = NULL;
+    pfnFreeASPI32Buffer        = NULL;
+    pfnTranslateASPI32Address = NULL;
+    FreeLibrary(hAspiLib);
+    hAspiLib = NULL;
+}
+
+
+static int scsi_bufsize (SCSI *scgp, int amt)
+{
+    return 63*1024;
+}
+
+static int scsi_havebus (SCSI *scgp, int busno)
+{
+    if (busno < 0 || busno >= busses)
+       return FALSE;
+    return TRUE;
+}
+
+static void *scgo_getbuf (SCSI *scgp, long amt)
+{
+    scgp->bufbase = malloc((size_t)(amt));
+    return scgp->bufbase;
+}
+
+static void scsi_sfree (SCSI *scgp)
+{
+    if (scgp->cmdstart)
+       free(scgp->cmdstart);
+    if (scgp->cmdstop)
+       free(scgp->cmdstop);
+    if (scgp->scmd)
+       free(scgp->scmd);
+    if (scgp->inq)
+       free(scgp->inq);
+    if (scgp->cap)
+       free(scgp->cap);
+    if (scgp->local)
+       free(scgp->local);
+    if (scgp->errstr)
+       free(scgp->errstr);
+    free(scgp);
+}
+
+static SCSI *scsi_smalloc(void)
+{
+    SCSI *scgp;
+
+    scgp = (SCSI *)malloc(sizeof(*scgp));
+    if (scgp == NULL)
+        return 0;
+
+    memset (scgp, 0, sizeof (*scgp));
+    scgp->deftimeout = 20;
+    scgp->running = FALSE;
+
+    scgp->cmdstart = (struct timeval *)malloc(sizeof(struct timeval));
+    if (scgp->cmdstart == NULL)
+       goto err;
+    scgp->cmdstop = (struct timeval *)malloc(sizeof(struct timeval));
+    if (scgp->cmdstop == NULL)
+       goto err;
+    scgp->scmd = (struct scg_cmd *)malloc(sizeof(struct scg_cmd));
+    if (scgp->scmd == NULL)
+       goto err;
+    scgp->errstr = malloc(SCSI_ERRSTR_SIZE);
+    if (scgp->errstr == NULL)
+       goto err;
+    scgp->errptr = scgp->errbeg = scgp->errstr;
+    scgp->errstr[0] = '\0';
+    scgp->inq = (struct scsi_inquiry *)malloc(sizeof(struct scsi_inquiry));
+    if (scgp->inq == NULL)
+       goto err;
+    scgp->cap = (struct scsi_capacity *)malloc(sizeof(struct scsi_capacity));
+    if (scgp->cap == NULL)
+       goto err;
+    return scgp;
+err:
+    scsi_sfree(scgp);
+    return 0;
+}
+
+#define        MAX_SCG         16      /* Max # of SCSI controllers    */
+#define        MAX_TGT         16      /* Max # of SCSI Targets        */
+#define        MAX_LUN         8       /* Max # of SCSI LUNs           */
+
+struct scg_local {
+    int dummy;
+};
+#define scglocal(p)    ((struct scg_local *)((p)->local)) 
+
+static SCSI *openscsi (int busno, int tgt, int tlun)
+{
+    SCSI *scgp = scsi_smalloc ();
+
+    if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
+       errno = EINVAL;
+       if (log_scsi)
+           write_log ("ASPI: Illegal value for busno, target or lun '%d,%d,%d'\n", busno, tgt, tlun);
+       return 0;
+    }
+    /*
+     *  Check if variables are within the range
+     */
+    if (tgt >= 0 && tgt >= 0 && tlun >= 0) {
+       /*
+        * This is the non -scanbus case.
+        */
+       ;
+    } else if (tgt != -1 || tgt != -1 || tlun != -1) {
+       errno = EINVAL;
+       return 0;
+    }
+    if (scgp->local == NULL) {
+       scgp->local = malloc(sizeof(struct scg_local));
+       if (scgp->local == NULL)
+           return 0;
+    }
+    /*
+     * Try to open ASPI-Router
+     */
+    if (!open_driver(scgp))
+       return 0;
+    /*
+     * More than we have ...
+     */
+    if (busno >= busses) {
+       close_driver ();
+       return 0;
+    }
+    return scgp;
+}
+
+static void closescsi (SCSI *scgp)
+{
+    close_driver ();
+}
+
+static void scsi_debug (SCSI *scgp, SRB_ExecSCSICmd *s)
+{
+    if (!log_scsi)
+       return;
+    if (scanphase)
+       return;
+    write_log ("ASPI EXEC_SCSI: bus=%d,target=%d,lun=%d\n",
+       s->SRB_HaId, s->SRB_Target, s->SRB_Lun);
+    scsi_log_before (scgp->scmd->cdb.cmd_cdb, scgp->scmd->cdb_len,
+        (s->SRB_Flags & SRB_DIR_OUT) ? s->SRB_BufPointer : 0, s->SRB_BufLen);
+}
+
+
+static void copy_sensedata(SRB_ExecSCSICmd *cp, struct scg_cmd *sp)
+{
+    sp->sense_count    = cp->SRB_SenseLen;
+    if (sp->sense_count > sp->sense_len)
+       sp->sense_count = sp->sense_len;
+    memset(&sp->u_sense.Sense, 0x00, sizeof(sp->u_sense.Sense));
+    if(sp->sense_len > 0) {
+       int len = sp->sense_len;
+       if (len > sizeof(sp->u_sense.Sense)) len = sizeof(sp->u_sense.Sense);
+       memcpy(&sp->u_sense.Sense, cp->SenseArea, len);
+    }
+    sp->u_scb.cmd_scb[0] = cp->SRB_TargStat;
+}
+
+/*
+ * Set error flags
+ */
+static void set_error(SRB_ExecSCSICmd *cp, struct scg_cmd *sp)
+{
+    switch (cp->SRB_Status) {
+       case SS_COMP:                   /* 0x01 SRB completed without error  */
+       sp->error = SCG_NO_ERROR;
+       sp->ux_errno = 0;
+       break;
+       case SS_PENDING:                /* 0x00 SRB being processed          */
+       /*
+        * XXX Could SS_PENDING happen ???
+        */
+       case SS_ABORTED:                /* 0x02 SRB aborted                  */
+       case SS_ABORT_FAIL:             /* 0x03 Unable to abort SRB          */
+       case SS_ERR:                    /* 0x04 SRB completed with error     */
+       default:
+       sp->error = SCG_RETRYABLE;
+       sp->ux_errno = EIO;
+       break;
+       case SS_INVALID_CMD:            /* 0x80 Invalid ASPI command         */
+       case SS_INVALID_HA:             /* 0x81 Invalid host adapter number  */
+       case SS_NO_DEVICE:              /* 0x82 SCSI device not installed    */
+       case SS_INVALID_SRB:            /* 0xE0 Invalid parameter set in SRB */
+       case SS_ILLEGAL_MODE:           /* 0xE2 Unsupported Windows mode     */
+       case SS_NO_ASPI:                /* 0xE3 No ASPI managers             */
+       case SS_FAILED_INIT:            /* 0xE4 ASPI for windows failed init */
+       case SS_MISMATCHED_COMPONENTS:  /* 0xE7 The DLLs/EXEs of ASPI don't  */
+                                       /*      version check                */
+       case SS_NO_ADAPTERS:            /* 0xE8 No host adapters to manager  */
+       
+       case SS_ASPI_IS_SHUTDOWN:       /* 0xEA Call came to ASPI after      */
+                                       /*      PROCESS_DETACH               */
+       case SS_BAD_INSTALL:            /* 0xEB The DLL or other components  */
+                                       /*      are installed wrong          */
+       sp->error = SCG_FATAL;
+       sp->ux_errno = EINVAL;
+       break;
+       case SS_BUFFER_ALIGN:           /* 0xE1 Buffer not aligned (replaces */
+                                       /*      SS_OLD_MANAGER in Win32)     */
+       sp->error = SCG_FATAL;
+       sp->ux_errno = EFAULT;
+       break;
+
+       case SS_ASPI_IS_BUSY:           /* 0xE5 No resources available to    */
+                                       /*      execute command              */
+       sp->error = SCG_RETRYABLE;
+       sp->ux_errno = EBUSY;
+       break;
+
+       case SS_BUFFER_TO_BIG:          /* 0xE6 Correct spelling of 'too'    */
+       case SS_INSUFFICIENT_RESOURCES: /* 0xE9 Couldn't allocate resources  */
+                                       /*      needed to init               */
+       sp->error = SCG_RETRYABLE;
+       sp->ux_errno = ENOMEM;
+       break;
+    }
+}
+static int scsiabort(SCSI *scgp, SRB_ExecSCSICmd *sp)
+{
+    DWORD Status = 0;
+    SRB_Abort s;
+
+    if (log_scsi)
+       write_log ("ASPI: Attempting to abort SCSI command\n");
+    /*
+     * Set structure variables
+     */
+    s.SRB_Cmd  = SC_ABORT_SRB;                 /* ASPI command code = SC_ABORT_SRB     */
+    s.SRB_HaId = scg_scsibus(scgp);            /* ASPI host adapter number             */
+    s.SRB_Flags        = 0;                            /* Flags                                */
+    s.SRB_ToAbort      = (LPSRB)&sp;                   /* sp                                   */
+    /*
+     * Initiate SCSI abort
+     */
+    Status = pfnSendASPI32Command((LPSRB)&s);
+    /*
+     * Check condition
+     */
+    if (s.SRB_Status != SS_COMP) {
+       if (log_scsi)
+           write_log ("ASPI: Abort ERROR! 0x%08X\n", s.SRB_Status);
+       return FALSE;
+    }
+    if (log_scsi)
+       write_log ("ASPI: Abort SCSI command completed\n");
+    /*
+     * Everything went OK
+     */
+    return TRUE;
+}
+
+static int scsicmd(SCSI *scgp)
+{
+    struct scg_cmd *sp = scgp->scmd;
+    DWORD Status = 0;
+    DWORD EventStatus = WAIT_OBJECT_0;
+    HANDLE Event = NULL;
+    SRB_ExecSCSICmd s;
+
+    /*
+     * Initialize variables
+     */
+    sp->error = SCG_NO_ERROR;
+    sp->sense_count = 0;
+    sp->u_scb.cmd_scb[0] = 0;
+    sp->resid = 0;
+
+    memset(&s, 0, sizeof(s)); /* Clear SRB structure */
+
+    /*
+     * Check cbd_len > the maximum command pakket that can be handled by ASPI
+     */
+    if (sp->cdb_len > 16) {
+       sp->error = SCG_FATAL;
+       sp->ux_errno = EINVAL;
+       if (log_scsi)
+           write_log ("ASPI: sp->cdb_len > sizeof(SRB_ExecSCSICmd.CDBByte). Fatal error in scgo_send, exiting...\n");
+       return -1;
+    }
+    /*
+     * copy command into SRB
+     */
+    memcpy(&(s.CDBByte), &sp->cdb, sp->cdb_len);
+
+    Event = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+    /*
+     * Fill ASPI structure
+     */
+    s.SRB_Cmd  = SC_EXEC_SCSI_CMD; /* SCSI Command */
+    s.SRB_HaId = scg_scsibus(scgp); /* Host adapter number */
+    s.SRB_Flags        = SRB_EVENT_NOTIFY; /* Flags */
+    s.SRB_Target       = scg_target(scgp); /* Target SCSI ID */
+    s.SRB_Lun  = scg_lun(scgp); /* Target SCSI LUN */
+    s.SRB_BufLen       = sp->size; /* # of bytes transferred */
+    s.SRB_BufPointer= sp->addr;        /* pointer to data buffer */
+    s.SRB_CDBLen       = sp->cdb_len;  /* SCSI command length */
+    s.SRB_PostProc     = Event; /* Post proc event */
+    s.SRB_SenseLen     = SENSE_LEN; /* Lenght of sense buffer */
+    
+    /*
+     * Do we receive data from this ASPI command?
+     */
+    if (sp->flags & SCG_RECV_DATA) {
+       s.SRB_Flags |= SRB_DIR_IN;
+    } else {
+       /*
+        * Set direction to output
+        */
+       if (sp->size > 0)
+           s.SRB_Flags |= SRB_DIR_OUT;
+    }
+
+    scsi_debug (scgp,&s);
+
+    /*
+     * ------------ Send SCSI command --------------------------
+     */
+
+    ResetEvent (Event); /* Clear event handle */
+    Status = pfnSendASPI32Command((LPSRB)&s);/* Initiate SCSI command  */
+
+    if (Status == SS_PENDING) { /* If in progress */
+       /*
+        * Wait until command completes, or times out.
+        */
+       EventStatus = WaitForSingleObject(Event, sp->timeout * 1000);
+       if (EventStatus == WAIT_OBJECT_0)
+           ResetEvent(Event);  /* Clear event, time out */
+       if (s.SRB_Status == SS_PENDING) {/* Check if we got a timeout*/
+           scsiabort(scgp, &s);
+           ResetEvent(Event);  /* Clear event, time out */
+           CloseHandle(Event); /* Close the event handle */
+           sp->error = SCG_TIMEOUT;
+           return 1;           /* Return error */
+       }
+    }
+    CloseHandle (Event); /* Close the event handle  */
+
+    /*
+     * Check ASPI command status
+     */
+
+    if (log_scsi && !scanphase)
+       scsi_log_after ((s.SRB_Flags & SRB_DIR_IN) ? s.SRB_BufPointer : 0, s.SRB_BufLen,
+           sp->u_sense.cmd_sense, sp->sense_len);
+
+    if (s.SRB_Status != SS_COMP) {
+        if (log_scsi && s.SRB_Status != 0x82)
+           write_log ("ASPI: Error in scgo_send: s.SRB_Status is 0x%x\n", s.SRB_Status);
+       set_error(&s, sp); /* Set error flags */
+       copy_sensedata(&s, sp); /* Copy sense and status */
+       if (log_scsi && s.SRB_Status != 0x82)
+           write_log ("ASPI: Mapped to: error %d errno: %d\n", sp->error, sp->ux_errno);
+       return 1;
+    }
+    /*
+     * Return success
+     */
+    return 0;
+}
+
+static int inquiry (SCSI *scgp, void *bp, int cnt)
+{
+    struct scg_cmd *scmd = scgp->scmd;
+
+    memset(bp, 0, cnt);
+    memset(scmd, 0, sizeof(struct scg_cmd));
+    scmd->addr = bp;
+    scmd->size = cnt;
+    scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
+    scmd->cdb_len = SC_G0_CDBLEN;
+    scmd->sense_len = CCS_SENSE_LEN;
+    scmd->target = scgp->addr.target;
+    scmd->cdb.g0_cdb.cmd = SC_INQUIRY;
+    scmd->cdb.g0_cdb.lun = scgp->addr.lun;
+    scmd->cdb.g0_cdb.count = cnt;
+    scgp->scmd->timeout = 10 * 60;
+    if (scsicmd(scgp))
+        return -1;
+    return 0;
+}
+
+static int scsierr(SCSI *scgp)
+{
+    register struct scg_cmd *cp = scgp->scmd;
+
+    if(cp->error != SCG_NO_ERROR ||
+       cp->ux_errno != 0 || *(u_char *)&cp->scb != 0)
+        return -1;
+    return 0;
+}
+
+static void scan_scsi_bus (SCSI *scgp, int flags)
+{
+    /* add all units we find */
+    scanphase = 1;
+    for (scgp->addr.scsibus=0; scgp->addr.scsibus < 8; scgp->addr.scsibus++) {
+        if (!scsi_havebus(scgp, scgp->addr.scsibus))
+            continue;
+        for (scgp->addr.target=0; scgp->addr.target < 16; scgp->addr.target++) {
+            struct scsi_inquiry inq;
+            scgp->addr.lun = 0;
+            if (inquiry (scgp, &inq, sizeof(inq)))
+                continue;
+            for (scgp->addr.lun=0; scgp->addr.lun < 8; scgp->addr.lun++) {
+                if (!inquiry (scgp, &inq, sizeof(inq))) {
+                   write_log ("ASPI: %d:%d:%d ", scgp->addr.scsibus,scgp->addr.target,scgp->addr.lun);
+                   write_log ("'%.8s' ", inq.vendor_info);
+                   write_log ("'%.16s' ", inq.prod_ident);
+                   write_log ("'%.4s' ", inq.prod_revision);
+                   if (unitcnt < MAX_TOTAL_DEVICES) {
+                       struct scsi_info *cis = &si[unitcnt];
+                       int use = 0;
+                       write_log ("[");
+                       if (inq.type == INQ_ROMD) {
+                           write_log ("CDROM");
+                           use = 1;
+                       } else if (!flags && ((inq.type >= INQ_SEQD && inq.type < INQ_COMM && inq.type != INQ_PROCD && aspi_allow_misc) || aspi_allow_all)) {
+                           write_log ("%d", inq.type);
+                           use = 1;
+                       } else {
+                           write_log ("<%d>", inq.type);
+                       }
+                       if (inq.ansi_version == 0) {
+                           write_log (",ATAPI");
+                           cis->isatapi = 1;
+                       } else
+                           write_log (",SCSI");
+                       write_log("]");
+                       if (use) {
+                           unitcnt++;
+                           cis->buf = malloc (DEVICE_SCSI_BUFSIZE);
+                           cis->scsibus = scgp->addr.scsibus;
+                           cis->target = scgp->addr.target;
+                           cis->lun = scgp->addr.lun;
+                           cis->type = inq.type;
+                           sprintf (cis->label, "%.8s %.16s %.4s", inq.vendor_info, inq.prod_ident, inq.prod_revision);
+                       }
+                   }
+                   write_log ("\n");
+               }
+            }
+        }
+    }
+    scanphase = 0;
+}
+
+static void aspi_led (int unitnum)
+{
+    int type = si[unitnum].type;
+
+    if (type == INQ_ROMD)
+       gui_cd_led (1);
+    else if (type == INQ_DASD)
+       gui_hd_led (1);
+}
+
+static uae_sem_t scgp_sem;
+
+static uae_u8 *execscsicmd_out (int unitnum, uae_u8 *data, int len)
+{
+    SCSI *scgp = si[unitnum].handle;
+    int v;
+
+    uae_sem_wait (&scgp_sem);
+    scgp->scmd->cdb_len = len;
+    memcpy (scgp->scmd->cdb.cmd_cdb, data, len);
+    scgp->scmd->addr = 0;
+    scgp->scmd->size = 0;
+    scgp->addr.scsibus = si[unitnum].scsibus;
+    scgp->addr.target = si[unitnum].target;
+    scgp->addr.lun = si[unitnum].lun;
+    scgp->scmd->timeout = 80 * 60;
+    aspi_led (unitnum);
+    v = scsicmd (scgp);
+    aspi_led (unitnum);
+    uae_sem_post (&scgp_sem);
+    if (v)
+       return 0;
+    return data;
+}
+
+static uae_u8 *execscsicmd_in (int unitnum, uae_u8 *data, int len, int *outlen)
+{
+    SCSI *scgp = si[unitnum].handle;
+    int v;
+
+    uae_sem_wait (&scgp_sem);
+    scgp->scmd->cdb_len = len;
+    memcpy (scgp->scmd->cdb.cmd_cdb, data, len);
+    scgp->scmd->addr = si[unitnum].buf;
+    scgp->scmd->size = DEVICE_SCSI_BUFSIZE;
+    scgp->addr.scsibus = si[unitnum].scsibus;
+    scgp->addr.target = si[unitnum].target;
+    scgp->addr.lun = si[unitnum].lun;
+    scgp->scmd->timeout = 80 * 60;
+    aspi_led (unitnum);
+    v = scsicmd (scgp);
+    aspi_led (unitnum);
+    uae_sem_post (&scgp_sem);
+    if (v)
+       return 0;
+    if (outlen)
+       *outlen = scgp->scmd->size;
+    return si[unitnum].buf;
+}
+
+static SCSI *scsi_handle;
+
+static int open_scsi_bus (int flags)
+{
+    SCSI *scgp = openscsi (-1, -1, -1);
+    unitcnt = 0;
+    if (scgp) {
+       scan_scsi_bus (scgp, flags);
+        uae_sem_init (&scgp_sem, 0, 1);
+    }
+    scsi_handle = scgp;
+    return scgp ? 1 : 0;
+}
+
+static int mediacheck (int unitnum)
+{
+    uae_u8 cmd [6] = { 0,0,0,0,0,0 }; /* TEST UNIT READY */
+    if (si[unitnum].handle == 0)
+       return 0;
+    return execscsicmd_out (unitnum, cmd, sizeof(cmd)) ? 1 : 0;
+}
+
+static int open_scsi_device (int unitnum)
+{
+    if (unitnum >= unitcnt)
+       return 0;
+    if (log_scsi)
+       write_log ("ASPI: opening %d:%d:%d\n", si[unitnum].scsibus, si[unitnum].target, si[unitnum].lun);
+    si[unitnum].handle = openscsi (si[unitnum].scsibus, si[unitnum].target, si[unitnum].lun);
+    if (si[unitnum].handle)
+       si[unitnum].mediainserted = mediacheck (unitnum);
+    if (log_scsi)
+       write_log ("unit %d: %s\n", unitnum, si[unitnum].mediainserted ? "CD inserted" : "Drive empty");
+    return si[unitnum].handle ? 1 : 0;
+}
+
+static void close_scsi_device (int unitnum)
+{
+    if (unitnum >= unitcnt)
+       return;
+    if (!si[unitnum].handle)
+       return;
+    scsi_sfree (si[unitnum].handle);
+    si[unitnum].handle = 0;
+}
+
+static void close_scsi_bus (void)
+{
+    closescsi (scsi_handle);
+    scsi_handle = 0;
+}
+
+static int execscsicmd_direct (int unitnum, uaecptr acmd)
+{
+    int sactual = 0, i, parm;
+    SCSI *scgp = si[unitnum].handle;
+    struct scg_cmd *scmd = scgp->scmd;
+    uaecptr scsi_data = get_long (acmd + 0);
+    uae_u32 scsi_len = get_long (acmd + 4);
+    uaecptr scsi_cmd = get_long (acmd + 12);
+    int scsi_cmd_len = get_word (acmd + 16);
+    int scsi_cmd_len_org = scsi_cmd_len;
+    uae_u8 scsi_flags = get_byte (acmd + 20);
+    uaecptr scsi_sense = get_long (acmd + 22);
+    uae_u16 scsi_sense_len = get_word (acmd + 26);
+    int io_error = 0;
+    addrbank *bank_data = &get_mem_bank (scsi_data);
+    uae_u8 *scsi_datap, *scsi_datap_org;
+
+    /* do transfer directly to and from Amiga memory */
+    if (!bank_data || !bank_data->check (scsi_data, scsi_len))
+        return -5; /* IOERR_BADADDRESS */
+
+    uae_sem_wait (&scgp_sem);
+
+    /* the Amiga does not tell us how long the timeout shall be, so make it _very_ long (specified in seconds) */
+    scmd->timeout = 80 * 60;
+    scsi_datap = scsi_datap_org = scsi_len ? bank_data->xlateaddr (scsi_data) : 0;
+    scmd->flags = ((scsi_flags & 1) ? SCG_RECV_DATA : 0) | SCG_DISRE_ENA;
+    for (i = 0; i < scsi_cmd_len; i++)
+       scmd->cdb.cmd_cdb[i] = get_byte (scsi_cmd + i);
+    scmd->target = si[unitnum].target;
+    scmd->sense_len = (scsi_flags & 4) ? 4 : /* SCSIF_OLDAUTOSENSE */
+        (scsi_flags & 2) ? scsi_sense_len : /* SCSIF_AUTOSENSE */
+        -1;
+    scmd->sense_count = 0;
+    scmd->u_scb.cmd_scb[0] = 0;
+    scgp->addr.scsibus = si[unitnum].scsibus;
+    scgp->addr.target = si[unitnum].target;
+    scgp->addr.lun = si[unitnum].lun;
+    if (si[unitnum].isatapi)
+        scsi_atapi_fixup_pre (scmd->cdb.cmd_cdb, &scsi_cmd_len, &scsi_datap, &scsi_len, &parm);
+    scmd->addr = scsi_datap;
+    scmd->size = scsi_len;
+    scmd->cdb_len = scsi_cmd_len;
+    aspi_led (unitnum);
+    scsicmd (scgp);
+    aspi_led (unitnum);
+
+    put_word (acmd + 18, scmd->error == SCG_FATAL ? 0 : scsi_cmd_len_org); /* fake scsi_CmdActual */
+    put_byte (acmd + 21, scmd->u_scb.cmd_scb[0]); /* scsi_Status */
+    if (scmd->u_scb.cmd_scb[0]) {
+        io_error = 45; /* HFERR_BadStatus */
+        /* copy sense? */
+        for (sactual = 0; scsi_sense && sactual < scsi_sense_len && sactual < scmd->sense_count; sactual++)
+            put_byte (scsi_sense + sactual, scmd->u_sense.cmd_sense[sactual]);
+        put_long (acmd + 8, 0); /* scsi_Actual */
+    } else {
+        int i;
+        for (i = 0; i < scsi_sense_len; i++)
+            put_byte (scsi_sense + i, 0);
+        sactual = 0;
+        if (scmd->error != SCG_NO_ERROR) {
+           io_error = 20; /* io_Error, but not specified */
+           put_long (acmd + 8, 0); /* scsi_Actual */
+        } else {
+           io_error = 0;
+           if (si[unitnum].isatapi)
+               scsi_atapi_fixup_post (scmd->cdb.cmd_cdb, scsi_cmd_len, scsi_datap_org, scsi_datap, &scsi_len, parm);
+            put_long (acmd + 8, scsi_len - scmd->resid); /* scsi_Actual */
+        }
+    }
+    put_word (acmd + 28, sactual);
+
+    uae_sem_post (&scgp_sem);
+
+    if (scsi_datap != scsi_datap_org)
+       free (scsi_datap);
+
+    return io_error;
+}
+
+static struct device_info *info_device (int unitnum, struct device_info *di)
+{
+    if (unitnum >= unitcnt)
+       return 0;
+    di->bus = si[unitnum].scsibus;
+    di->target = si[unitnum].target;
+    di->lun = si[unitnum].lun;
+    di->media_inserted = mediacheck (unitnum); //si[unitnum].mediainserted;
+    di->write_protected = 1;
+    di->bytespersector = 2048;
+    di->cylinders = 1;
+    di->type = si[unitnum].type;
+    di->id = unitnum + 1;
+    strcpy (di->label, si[unitnum].label);
+    return di;
+}
+
+void win32_aspi_media_change (char driveletter, int insert)
+{
+    int i, now;
+
+    for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
+       now = mediacheck (i);
+       if (now != si[i].mediainserted) {
+           write_log ("ASPI: media change %c %d\n", driveletter, insert);
+           si[i].mediainserted = now;
+           scsi_do_disk_change (i + 1, insert);
+       }
+    }
+}
+
+static int check_isatapi (int unitnum)
+{
+    return si[unitnum].isatapi;
+}
+
+struct device_functions devicefunc_win32_aspi = {
+    open_scsi_bus, close_scsi_bus, open_scsi_device, close_scsi_device, info_device,
+    execscsicmd_out, execscsicmd_in, execscsicmd_direct,
+    0, 0, 0, 0, 0, 0, 0, check_isatapi
+};
diff --git a/od-win32/blkdev_win32_ioctl.c b/od-win32/blkdev_win32_ioctl.c
new file mode 100755 (executable)
index 0000000..d1996d2
--- /dev/null
@@ -0,0 +1,458 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * WIN32 CDROM/HD low level access code (IOCTL)
+  *
+  * Copyright 2002 Toni Wilen
+  *
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#ifdef WINDDK
+
+#include "config.h"
+#include "uae.h"
+#include "threaddep/thread.h"
+#include "blkdev.h"
+#include "scsidev.h"
+#include "gui.h"
+
+#include <devioctl.h>
+#include <ntddcdrm.h>
+
+struct dev_info_ioctl {
+    HANDLE h;
+    uae_u8 *tempbuffer;
+    char drvletter;
+    char devname[30];
+    int mediainserted;
+    int type;
+};
+
+static UINT errormode;
+
+static void seterrormode (void)
+{
+    errormode = SetErrorMode( SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX );
+}
+static void reseterrormode (void)
+{
+    SetErrorMode (errormode);
+}
+
+static struct dev_info_ioctl ciw32[MAX_TOTAL_DEVICES + 64 + 32];
+
+static void close_device (int unitnum);
+static int open_device (int unitnum);
+
+static int win32_error (int unitnum, const char *format,...)
+{
+    LPVOID lpMsgBuf;
+    va_list arglist;
+    char buf[1000];
+    DWORD err = GetLastError();
+
+    if (err == 34) {
+       write_log ("IOCTL: media change, re-opening device\n");
+       close_device (unitnum);
+       if (!open_device (unitnum))
+           write_log ("IOCTL: re-opening failed!\n");
+       return -1;
+    }
+    va_start (arglist, format );
+    vsprintf (buf, format, arglist);
+    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
+       NULL,err,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+       (LPTSTR) &lpMsgBuf,0,NULL);
+    if (log_scsi)
+       write_log ("IOCTL: unit=%d %s,%d: %s ", unitnum, buf, err, (char*)lpMsgBuf);
+    va_end( arglist );
+    return err;
+}
+
+
+/* pause/unpause CD audio */
+static int ioctl_command_pause (int unitnum, int paused)
+{
+    DWORD len;
+    int command = paused ? IOCTL_CDROM_PAUSE_AUDIO : IOCTL_CDROM_RESUME_AUDIO;
+    int cnt = 3;
+
+    while (cnt-- > 0) {
+        seterrormode ();
+       if (!DeviceIoControl(ciw32[unitnum].h, command, NULL, 0, NULL, 0, &len, NULL)) {
+           reseterrormode ();
+           if (win32_error (unitnum, paused ? "IOCTL_CDROM_PAUSE_AUDIO" : "IOCTL_CDROM_RESUME_AUDIO") < 0)
+               continue;
+           return 0;
+       }
+        reseterrormode ();
+       break;
+    }
+    return 1;
+}
+
+/* stop CD audio */
+static int ioctl_command_stop (int unitnum)
+{
+    DWORD len;
+    int cnt = 3;
+
+    while (cnt-- > 0) {
+        seterrormode ();
+       if(!DeviceIoControl(ciw32[unitnum].h, IOCTL_CDROM_STOP_AUDIO, NULL, 0, NULL, 0, &len, NULL)) {
+           reseterrormode ();
+           if (win32_error (unitnum, "IOCTL_CDROM_STOP_AUDIO") < 0)
+               continue;
+           return 0;
+       }
+       reseterrormode ();
+       break;
+    }
+    return 1;
+}
+
+/* play CD audio */
+static int ioctl_command_play (int unitnum, uae_u32 start, uae_u32 end, int scan)
+{
+    DWORD len;
+    CDROM_PLAY_AUDIO_MSF pa;
+    int cnt = 3;
+
+    while (cnt-- > 0) {
+       pa.StartingM = start >> 16;
+       pa.StartingS = start >> 8;
+       pa.StartingF = start >> 0;
+       pa.EndingM = end >> 16;
+       pa.EndingS = end >> 8;
+       pa.EndingF = end >> 0;
+       seterrormode ();
+       if (!DeviceIoControl(ciw32[unitnum].h, IOCTL_CDROM_PLAY_AUDIO_MSF, &pa, sizeof(pa), NULL, 0, &len, NULL)) {
+           reseterrormode ();
+           if (win32_error (unitnum, "IOCTL_CDROM_PLAY_AUDIO_MSF %02.%02.%02-%02.%02.%02",
+               pa.StartingM, pa.StartingS, pa.StartingF, pa.EndingM, pa.EndingS, pa.EndingF ) < 0) continue;
+           return 0;
+       }
+       reseterrormode ();
+       break;
+    }
+    return 1;
+}
+
+/* read qcode */
+static uae_u8 *ioctl_command_qcode (int unitnum)
+{
+    SUB_Q_CHANNEL_DATA qcd;
+    DWORD len;
+    ULONG in = 1;
+    uae_u8 *p = ciw32[unitnum].tempbuffer;
+    int cnt = 3;
+
+    memset (p, 0, 4 + 12);
+    p[1] = 0x15;
+    p[3] = 12;
+    while (cnt-- > 0) {
+       reseterrormode ();
+       if(!DeviceIoControl(ciw32[unitnum].h, IOCTL_CDROM_READ_Q_CHANNEL, &in, sizeof(in), &qcd, sizeof (qcd), &len, NULL)) {
+           reseterrormode ();
+           if (win32_error (unitnum, "IOCTL_CDROM_READ_Q_CHANNEL") < 0)
+               continue;
+           return 0;
+       }
+       break;
+    }
+    reseterrormode ();
+    p[1] = qcd.CurrentPosition.Header.AudioStatus;
+    p += 4;
+    p[1] = (qcd.CurrentPosition.Control << 0) | (qcd.CurrentPosition.ADR << 4);
+    p[2] = qcd.CurrentPosition.TrackNumber;
+    p[3] = qcd.CurrentPosition.IndexNumber;
+    p[5] = qcd.CurrentPosition.AbsoluteAddress[1];
+    p[6] = qcd.CurrentPosition.AbsoluteAddress[2];
+    p[7] = qcd.CurrentPosition.AbsoluteAddress[3];
+    p[9] = qcd.CurrentPosition.TrackRelativeAddress[1];
+    p[10] = qcd.CurrentPosition.TrackRelativeAddress[2];
+    p[11] = qcd.CurrentPosition.TrackRelativeAddress[3];
+    return ciw32[unitnum].tempbuffer;
+}
+
+static uae_u8 *ioctl_command_read (int unitnum, int sector)
+{
+    DWORD dtotal;
+    int cnt = 3;
+
+    while (cnt-- > 0) {
+       gui_cd_led (1);
+       seterrormode ();
+       if (SetFilePointer (ciw32[unitnum].h, sector  * 2048, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
+           reseterrormode ();
+           if (win32_error (unitnum, "SetFilePointer") < 0)
+               continue;
+           return 0;
+       }
+        reseterrormode ();
+       break;
+    }
+    cnt = 3;
+    while (cnt-- > 0) {
+       gui_cd_led (1);
+       if (!ReadFile (ciw32[unitnum].h, ciw32[unitnum].tempbuffer, 2048, &dtotal, 0)) {
+           reseterrormode ();
+           if (win32_error (unitnum, "ReadFile") < 0)
+               continue;
+           return 0;
+       }
+       reseterrormode ();
+       gui_cd_led (1);
+       break;
+    }
+    return ciw32[unitnum].tempbuffer;
+}
+
+static int ioctl_command_write (int unitnum, int sector, uae_u8 *data)
+{
+    return 0;
+}
+
+static int fetch_geometry (int unitnum, struct device_info *di)
+{
+    DISK_GEOMETRY geom;
+    DWORD len;
+    int cnt = 3;
+
+    while (cnt-- > 0) {
+        seterrormode ();
+       if (!DeviceIoControl(ciw32[unitnum].h, IOCTL_CDROM_GET_DRIVE_GEOMETRY, NULL, 0, &geom, sizeof(geom), &len, NULL)) {
+           reseterrormode ();
+           if (win32_error (unitnum, "IOCTL_CDROM_GET_DRIVE_GEOMETRY") < 0)
+               continue;
+           return 0;
+       }
+        reseterrormode ();
+       break;
+    }
+    if (di) {
+        di->cylinders = geom.Cylinders.LowPart;
+       di->sectorspertrack = geom.SectorsPerTrack;
+       di->trackspercylinder = geom.TracksPerCylinder;
+       di->bytespersector = geom.BytesPerSector;
+    }
+    return 1;
+}
+
+
+/* read toc */
+static uae_u8 *ioctl_command_toc (int unitnum)
+{
+    CDROM_TOC toc;
+    DWORD len;
+    int i;
+    uae_u8 *p = ciw32[unitnum].tempbuffer;
+    int cnt = 3;
+
+    gui_cd_led (1);
+    while (cnt-- > 0) {
+        seterrormode ();
+       if (!DeviceIoControl(ciw32[unitnum].h, IOCTL_CDROM_READ_TOC, NULL, 0, &toc, sizeof(toc), &len, NULL)) {
+           reseterrormode ();
+           if (!win32_error (unitnum, "IOCTL_CDROM_READ_TOC"))
+               continue;
+           return 0;
+       }
+        reseterrormode ();
+       break;
+    }
+
+    p[0] = ((toc.LastTrack + 4) * 11) >> 8;
+    p[1] = ((toc.LastTrack + 4) * 11) & 0xff;
+    p[2] = 1;
+    p[3] = toc.LastTrack;
+    p += 4;
+    memset (p, 0, 11);
+    p[0] = 1;
+    p[1] = (toc.TrackData[0].Control << 0) | (toc.TrackData[0].Adr << 4);
+    p[3] = 0xa0;
+    p[8] = 1;
+    p += 11;
+    memset (p, 0, 11);
+    p[0] = 1;
+    p[1] = 0x10;
+    p[3] = 0xa1;
+    p[8] = toc.LastTrack;
+    p += 11;
+    memset (p, 0, 11);
+    p[0] = 1;
+    p[1] = 0x10;
+    p[3] = 0xa2;
+    p[8] = toc.TrackData[toc.LastTrack].Address[1];
+    p[9] = toc.TrackData[toc.LastTrack].Address[2];
+    p[10] = toc.TrackData[toc.LastTrack].Address[3];
+    p += 11;
+    for (i = 0; i < toc.LastTrack; i++) {
+       memset (p, 0, 11);
+       p[0] = 1;
+       p[1] = (toc.TrackData[i].Control << 0) | (toc.TrackData[i].Adr << 4);
+       p[2] = 0;
+       p[3] = i + 1;
+       p[8] = toc.TrackData[i].Address[1];
+       p[9] = toc.TrackData[i].Address[2];
+       p[10] = toc.TrackData[i].Address[3];
+       p += 11;
+    }
+    gui_cd_led (1);
+    return ciw32[unitnum].tempbuffer;
+}
+
+/* open device level access to cd rom drive */
+static int sys_cddev_open (int unitnum)
+{
+    DWORD len;
+    struct dev_info_ioctl *ciw = &ciw32[unitnum];
+    DWORD flags;
+
+    /* buffer must be page aligned for device access */
+    ciw->tempbuffer = VirtualAlloc (NULL, 4096, MEM_COMMIT, PAGE_READWRITE);
+    if (!ciw->tempbuffer) {
+       write_log ("IOCTL: failed to allocate buffer");
+       return 1;
+    }
+    flags = GENERIC_READ;
+    ciw->h = CreateFile(ciw->devname, flags, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (ciw->h == INVALID_HANDLE_VALUE) {
+       flags |= GENERIC_WRITE;
+        ciw->h = CreateFile(ciw->devname, flags, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+        if (ciw->h == INVALID_HANDLE_VALUE) {
+           write_log ("IOCTL: failed to open device handle (%s)\n", ciw->devname);
+           goto error;
+       }
+    }
+    DeviceIoControl(ciw->h, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, NULL, 0, &len, NULL);
+    ciw->mediainserted = ioctl_command_toc (unitnum) ? 1 : 0;
+    write_log ("IOCTL: device '%s' opened succesfully (unit number=%d,media=%d)\n", ciw->devname, unitnum, ciw->mediainserted);
+    ioctl_command_stop (unitnum);
+    return 0;
+error:
+    win32_error (unitnum, "CreateFile");
+    VirtualFree (ciw->tempbuffer, 0, MEM_RELEASE);
+    ciw->tempbuffer = NULL;
+    CloseHandle (ciw->h);
+    ciw->h = NULL;
+    return -1;
+}
+
+static int unitcheck (int unitnum)
+{
+    if (unitnum >= MAX_TOTAL_DEVICES) {
+       if (unitnum < 'A' || unitnum > 'Z')
+           return 0;
+       return 1;
+    }
+    if (ciw32[unitnum].drvletter == 0)
+       return 0;
+    return 1;
+}
+
+/* close device handle */
+void sys_cddev_close (int unitnum)
+{
+    if (!unitcheck (unitnum))
+       return;
+    CloseHandle (ciw32[unitnum].h);
+    ciw32[unitnum].h = NULL;
+    VirtualFree (ciw32[unitnum].tempbuffer, 0, MEM_RELEASE);
+    ciw32[unitnum].tempbuffer = NULL;
+}
+
+static int open_device (int unitnum)
+{
+    if (!unitcheck (unitnum))
+       return 0;
+    if (sys_cddev_open (unitnum) == 0)
+       return 1;
+    return 0;
+}
+static void close_device (int unitnum)
+{
+    sys_cddev_close (unitnum);
+}
+
+static void close_bus (void)
+{
+}
+
+static int total_devices;
+
+static int open_bus (int flags)
+{
+    int dwDriveMask;
+    int drive, i;
+    char tmp[10];
+
+    for (i = 0; i < MAX_TOTAL_DEVICES; i++)
+       memset (&ciw32[i], 0, sizeof (struct dev_info_ioctl));
+    total_devices = 0;
+    dwDriveMask = GetLogicalDrives();
+    if (log_scsi)
+       write_log ("IOCTL: drive mask = %08.8X\n", dwDriveMask);
+    dwDriveMask >>= 2; // Skip A and B drives...
+    for( drive = 'C'; drive <= 'Z'; drive++) {
+       if (dwDriveMask & 1) {
+           int dt;
+           sprintf( tmp, "%c:\\", drive );
+           dt = GetDriveType (tmp);
+           if (log_scsi)
+               write_log ("IOCTL: drive %c type %d\n", drive, dt);
+           if (((flags & (1 << INQ_ROMD)) && dt == DRIVE_CDROM) || ((flags & (1 << INQ_DASD)) && dt == DRIVE_FIXED)) {
+               if (log_scsi)
+                   write_log ("IOCTL: drive %c: = unit %d\n", drive, total_devices);
+               ciw32[total_devices].drvletter = drive;
+               ciw32[total_devices].type = dt;
+               sprintf (ciw32[total_devices].devname,"\\\\.\\%c:", drive);
+               total_devices++;
+           }
+       }
+       dwDriveMask >>= 1;
+    }
+    return total_devices;
+}
+
+static struct device_info *info_device (int unitnum, struct device_info *di)
+{
+    if (!unitcheck (unitnum))
+       return 0;
+    di->bus = unitnum;
+    di->target = 0;
+    di->lun = 0;
+    di->media_inserted = 0;
+    if (fetch_geometry (unitnum, di)) // || ioctl_command_toc (unitnum))
+       di->media_inserted = 1;
+    di->write_protected = 1;
+    di->type = ciw32[unitnum].type == DRIVE_CDROM ? INQ_ROMD : INQ_DASD;
+    di->id = ciw32[unitnum].drvletter;
+    sprintf (di->label, "Drive %c:", ciw32[unitnum].drvletter);
+    return di;
+}
+
+void win32_ioctl_media_change (char driveletter, int insert)
+{
+    int i;
+
+    for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
+       if (ciw32[i].drvletter == driveletter && ciw32[i].mediainserted != insert) {
+           write_log ("IOCTL: media change %c %d\n", driveletter, insert);
+           ciw32[i].mediainserted = insert;
+           scsi_do_disk_change (driveletter, insert);
+       }
+    }
+}
+
+struct device_functions devicefunc_win32_ioctl = {
+    open_bus, close_bus, open_device, close_device, info_device,
+    0, 0, 0,
+    ioctl_command_pause, ioctl_command_stop, ioctl_command_play, ioctl_command_qcode,
+    ioctl_command_toc, ioctl_command_read, ioctl_command_write
+};
+
+#endif
diff --git a/od-win32/blkdev_win32_spti.c b/od-win32/blkdev_win32_spti.c
new file mode 100755 (executable)
index 0000000..85db9d1
--- /dev/null
@@ -0,0 +1,366 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * WIN32 CDROM/HD low level access code (SPTI)
+  *
+  * Copyright 2002 Toni Wilen
+  *
+  */
+
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#ifdef WINDDK
+
+#include "memory.h"
+#include "threaddep/thread.h"
+#include "blkdev.h"
+#include "scsidev.h"
+#include "gui.h"
+
+#include <stddef.h>
+
+#include <windows.h>
+#include <devioctl.h>
+#include <ntddscsi.h>
+
+typedef struct _SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER {
+  SCSI_PASS_THROUGH_DIRECT spt;
+  ULONG Filler;
+  UCHAR SenseBuf[32];
+} SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
+
+static int unitcnt = 0;
+
+struct dev_info_spti {
+    char drvletter;
+    char drvpath[10];
+    int mediainserted;
+    HANDLE handle;
+    int isatapi;
+};
+
+static uae_sem_t scgp_sem;
+static struct dev_info_spti dev_info[MAX_TOTAL_DEVICES];
+static uae_u8 *scsibuf;
+
+static int doscsi (HANDLE *h, SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER *swb, int *err)
+{
+    DWORD status, returned;
+    int i;
+
+    *err = 0;
+    if (log_scsi) {
+       write_log ("SCSI, H=%X: ", h);
+       scsi_log_before (swb->spt.Cdb, swb->spt.CdbLength,
+           swb->spt.DataIn == SCSI_IOCTL_DATA_OUT ? swb->spt.DataBuffer : 0,swb->spt.DataTransferLength);
+    }
+    gui_cd_led (1);
+    status = DeviceIoControl (h, IOCTL_SCSI_PASS_THROUGH_DIRECT,
+       swb, sizeof (SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER),
+       swb, sizeof (SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER),
+       &returned, NULL);
+    if (!status) {
+       int lasterror = GetLastError();
+       *err = lasterror;
+        write_log("SCSI ERROR, H=%X: ", h);
+       write_log("Error code = %d, LastError=%d\n", swb->spt.ScsiStatus, lasterror);
+       scsi_log_before (swb->spt.Cdb, swb->spt.CdbLength,
+           swb->spt.DataIn == SCSI_IOCTL_DATA_OUT ? swb->spt.DataBuffer : 0,swb->spt.DataTransferLength);
+    }
+    if (log_scsi)
+       scsi_log_after (swb->spt.DataIn == SCSI_IOCTL_DATA_IN ? swb->spt.DataBuffer : 0, swb->spt.DataTransferLength,
+           swb->SenseBuf, swb->spt.SenseInfoLength);
+    if (swb->spt.SenseInfoLength > 0)
+       return 0;
+    gui_cd_led (1);
+    return status;
+}
+
+
+#define MODE_SELECT_6  0x15
+#define MODE_SENSE_6   0x1A
+#define MODE_SELECT_10 0x55
+#define MODE_SENSE_10  0x5A
+
+static int execscsicmd (int unitnum, uae_u8 *data, int len, uae_u8 *inbuf, int inlen)
+{
+    SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb;
+    DWORD status;
+    int err, dolen;
+
+    uae_sem_wait (&scgp_sem);
+    memset (&swb, 0, sizeof (swb));
+    swb.spt.Length = sizeof (SCSI_PASS_THROUGH);
+    swb.spt.CdbLength = len;
+    if (inbuf) {
+       swb.spt.DataIn = SCSI_IOCTL_DATA_IN;
+       swb.spt.DataTransferLength = inlen;
+       swb.spt.DataBuffer = inbuf;
+       memset (inbuf, 0, inlen);
+    } else {
+       swb.spt.DataIn = SCSI_IOCTL_DATA_OUT;
+    }
+    swb.spt.TimeOutValue = 80 * 60;
+    swb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
+    swb.spt.SenseInfoLength = 32;
+    memcpy (swb.spt.Cdb, data, len);
+    status = doscsi (dev_info[unitnum].handle, &swb, &err);
+    uae_sem_post (&scgp_sem);
+    dolen = swb.spt.DataTransferLength;
+    if (!status)
+       return -1;
+    return dolen;
+}
+
+static int execscsicmd_direct (int unitnum, uaecptr acmd)
+{
+    SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb;
+    DWORD status;
+    int sactual = 0, i;
+    uaecptr scsi_data = get_long (acmd + 0);
+    uae_u32 scsi_len = get_long (acmd + 4);
+    uaecptr scsi_cmd = get_long (acmd + 12);
+    int scsi_cmd_len = get_word (acmd + 16);
+    int scsi_cmd_len_orig = scsi_cmd_len;
+    uae_u8 scsi_flags = get_byte (acmd + 20);
+    uaecptr scsi_sense = get_long (acmd + 22);
+    uae_u16 scsi_sense_len = get_word (acmd + 26);
+    int io_error = 0, err, parm;
+    addrbank *bank_data = &get_mem_bank (scsi_data);
+    uae_u8 *scsi_datap, *scsi_datap_org;
+
+    memset (&swb, 0, sizeof (swb));
+    swb.spt.Length = sizeof (SCSI_PASS_THROUGH);
+    swb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf);
+
+    /* do transfer directly to and from Amiga memory */
+    if (!bank_data || !bank_data->check (scsi_data, scsi_len))
+        return -5; /* IOERR_BADADDRESS */
+
+    uae_sem_wait (&scgp_sem);
+
+    /* the Amiga does not tell us how long the timeout shall be, so make it _very_ long (specified in seconds) */
+    swb.spt.TimeOutValue = 80 * 60;
+    scsi_datap = scsi_datap_org = scsi_len ? bank_data->xlateaddr (scsi_data) : 0;
+    swb.spt.DataIn = (scsi_flags & 1) ? SCSI_IOCTL_DATA_IN : SCSI_IOCTL_DATA_OUT;
+    for (i = 0; i < scsi_cmd_len; i++)
+       swb.spt.Cdb[i] = get_byte (scsi_cmd + i);
+    if (scsi_sense_len > 32)
+       scsi_sense_len = 32;
+    swb.spt.SenseInfoLength  = (scsi_flags & 4) ? 4 : /* SCSIF_OLDAUTOSENSE */
+        (scsi_flags & 2) ? scsi_sense_len : /* SCSIF_AUTOSENSE */
+        32;
+    if (dev_info[unitnum].isatapi)
+        scsi_atapi_fixup_pre (swb.spt.Cdb, &scsi_cmd_len, &scsi_datap, &scsi_len, &parm);
+    swb.spt.CdbLength = (UCHAR)scsi_cmd_len;
+    swb.spt.DataTransferLength = scsi_len;
+    swb.spt.DataBuffer = scsi_datap;
+
+    status = doscsi (dev_info[unitnum].handle, &swb, &err);
+
+    put_word (acmd + 18, status == 0 ? 0 : scsi_cmd_len_orig); /* fake scsi_CmdActual */
+    put_byte (acmd + 21, swb.spt.ScsiStatus); /* scsi_Status */
+    if (swb.spt.ScsiStatus) {
+        io_error = 45; /* HFERR_BadStatus */
+        /* copy sense? */
+        for (sactual = 0; scsi_sense && sactual < scsi_sense_len && sactual < swb.spt.SenseInfoLength; sactual++)
+            put_byte (scsi_sense + sactual, swb.SenseBuf[sactual]);
+        put_long (acmd + 8, 0); /* scsi_Actual */
+    } else {
+        int i;
+        for (i = 0; i < scsi_sense_len; i++)
+            put_byte (scsi_sense + i, 0);
+        sactual = 0;
+        if (status == 0) {
+           io_error = 20; /* io_Error, but not specified */
+           put_long (acmd + 8, 0); /* scsi_Actual */
+        } else {
+           scsi_len = swb.spt.DataTransferLength;
+           if (dev_info[unitnum].isatapi)
+               scsi_atapi_fixup_post (swb.spt.Cdb, scsi_cmd_len, scsi_datap_org, scsi_datap, &scsi_len, parm);
+           io_error = 0;
+            put_long (acmd + 8, scsi_len); /* scsi_Actual */
+        }
+    }
+    put_word (acmd + 28, sactual);
+    uae_sem_post (&scgp_sem);
+
+    if (scsi_datap != scsi_datap_org)
+       free (scsi_datap);
+
+    return io_error;
+}
+
+static uae_u8 *execscsicmd_out (int unitnum, uae_u8 *data, int len)
+{
+    int v = execscsicmd (unitnum, data, len, 0, 0);
+    if (v < 0)
+       return 0;
+    return data;
+}
+
+static uae_u8 *execscsicmd_in (int unitnum, uae_u8 *data, int len, int *outlen)
+{
+    int v = execscsicmd (unitnum, data, len, scsibuf, DEVICE_SCSI_BUFSIZE);
+    if (v < 0)
+       return 0;
+    if (v == 0)
+       return 0;
+    if (outlen)
+       *outlen = v;
+    return scsibuf;
+}
+
+static int adddrive (int unitnum, char drive)
+{
+    if (unitcnt >= MAX_TOTAL_DEVICES)
+       return 0;
+    sprintf (dev_info[unitcnt].drvpath, "\\\\.\\%c:", drive);
+    dev_info[unitcnt].drvletter = drive;
+    write_log ("SPTI: selected drive %c: (uaescsi.device:%d)\n", drive, unitnum);
+    unitcnt++;
+    return 1;
+}
+
+static int total_devices;
+
+static int open_scsi_bus (int flags)
+{
+    int dwDriveMask;
+    int drive, firstdrive;
+    char tmp[10], tmp2[10];
+    int i;
+
+    total_devices = 0;
+    firstdrive = 0;
+    uae_sem_init (&scgp_sem, 0, 1);
+    for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
+       memset (&dev_info[i], 0, sizeof (struct dev_info_spti));
+       dev_info[i].handle = INVALID_HANDLE_VALUE;
+    }
+    if (!scsibuf)
+       scsibuf = VirtualAlloc (NULL, DEVICE_SCSI_BUFSIZE, MEM_COMMIT, PAGE_READWRITE);
+    dwDriveMask = GetLogicalDrives ();
+    device_debug ("SPTI: drive mask = %08.8X\n", dwDriveMask);
+    dwDriveMask >>= 2; // Skip A and B drives...
+    for( drive = 'C'; drive <= 'Z'; drive++) {
+       if (dwDriveMask & 1) {
+           int dt;
+           sprintf( tmp, "%c:\\", drive );
+           sprintf( tmp2, "%c:\\.", drive );
+           dt = GetDriveType (tmp);
+           device_debug ("SPTI: drive %c type %d\n", drive, dt);
+           if (dt == DRIVE_CDROM) {
+               if (!firstdrive)
+                   firstdrive = drive;
+               if (adddrive (total_devices, drive))
+                   total_devices++;
+           }
+       }
+       dwDriveMask >>= 1;
+    }
+    return total_devices;
+}
+
+static void close_scsi_bus (void)
+{
+    VirtualFree (scsibuf, 0, MEM_RELEASE);
+    scsibuf = 0;
+}
+
+static int isatapi (int unitnum)
+{
+    uae_u8 cmd[6] = { 0x12,0,0,0,36,0 }; /* INQUIRY */
+    uae_u8 out[36];
+    int outlen = sizeof (out);
+    uae_u8 *p = execscsicmd_in (unitnum, cmd, sizeof (cmd), &outlen);
+    if (!p)
+       return 0;
+    if (outlen >= 2 && (p[0] & 31) == 5 && (p[2] & 7) == 0)
+       return 1;
+    return 0;
+}
+
+static int mediacheck (int unitnum)
+{
+    uae_u8 cmd [6] = { 0,0,0,0,0,0 }; /* TEST UNIT READY */
+    if (dev_info[unitnum].handle == INVALID_HANDLE_VALUE)
+       return 0;
+    return execscsicmd (unitnum, cmd, sizeof (cmd), 0, 0) >= 0 ? 1 : 0;
+}
+
+int open_scsi_device (int unitnum)
+{
+    HANDLE h;
+    char *dev;
+
+    dev = dev_info[unitnum].drvpath;
+    if (!dev[0])
+       return 0;
+    h = CreateFile(dev,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
+    dev_info[unitnum].handle = h;
+    if (h == INVALID_HANDLE_VALUE) {
+        write_log ("failed to open cd unit %d (%s)\n", unitnum, dev);
+    } else {
+        dev_info[unitnum].mediainserted = mediacheck (unitnum);
+       dev_info[unitnum].isatapi = isatapi (unitnum);
+       write_log ("cd unit %d %s opened (%s), %s\n", unitnum,
+           dev_info[unitnum].isatapi ? "[ATAPI]" : "[SCSI]", dev,
+           dev_info[unitnum].mediainserted ? "CD inserted" : "Drive empty");
+        return 1;
+    }
+    return 0;
+}
+
+static void close_scsi_device (int unitnum)
+{
+    write_log ("cd unit %d closed\n", unitnum);
+    if (dev_info[unitnum].handle != INVALID_HANDLE_VALUE)
+       CloseHandle (dev_info[unitnum].handle);
+    dev_info[unitnum].handle = INVALID_HANDLE_VALUE;
+}
+
+static struct device_info *info_device (int unitnum, struct device_info *di)
+{
+    if (unitnum >= MAX_TOTAL_DEVICES || dev_info[unitnum].handle == INVALID_HANDLE_VALUE)
+       return 0;
+    sprintf(di->label,"Drive %c", dev_info[unitnum].drvletter);
+    di->bus = 0;
+    di->target = unitnum;
+    di->lun = 0;
+    di->media_inserted = mediacheck (unitnum);
+    di->write_protected = 1;
+    di->bytespersector = 2048;
+    di->cylinders = 1;
+    di->type = INQ_ROMD;
+    di->id = dev_info[unitnum].drvletter;
+    return di;
+}
+
+void win32_spti_media_change (char driveletter, int insert)
+{
+    int i;
+
+    for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
+       if (dev_info[i].drvletter == driveletter && dev_info[i].mediainserted != insert) {
+           write_log ("SPTI: media change %c %d\n", driveletter, insert);
+           dev_info[i].mediainserted = insert;
+           scsi_do_disk_change (driveletter, insert);
+       }
+    }
+}
+
+static int check_isatapi (int unitnum)
+{
+    return dev_info[unitnum].isatapi;
+}
+
+struct device_functions devicefunc_win32_spti = {
+    open_scsi_bus, close_scsi_bus, open_scsi_device, close_scsi_device, info_device,
+    execscsicmd_out, execscsicmd_in, execscsicmd_direct,
+    0, 0, 0, 0, 0, 0, 0, check_isatapi
+};
+
+#endif
\ No newline at end of file
diff --git a/od-win32/bsdsock.c b/od-win32/bsdsock.c
new file mode 100755 (executable)
index 0000000..28f5261
--- /dev/null
@@ -0,0 +1,2574 @@
+/*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * bsdsocket.library emulation - Win32 OS-dependent part
+ *
+ * Copyright 1997,98 Mathias Ortmann
+ * Copyright 1999,2000 Brian King
+ *
+ * GNU Public License
+ *
+ */
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <winsock.h>
+#include <stddef.h>
+#include <process.h>
+
+#include "config.h"   
+#include "options.h"
+#include "memory.h"
+#include "custom.h"
+#include "events.h"
+#include "newcpu.h" 
+#include "autoconf.h"
+#include "bsdsocket.h"
+
+#include "osdep/exectasks.h"
+#include "threaddep/thread.h"
+#include "native2amiga.h"
+#include "resource.h"
+#include "win32gui.h"
+#include "wininet.h"
+#include "mmsystem.h"
+#include "win32.h"
+
+
+
+static HWND hSockWnd;
+static long FAR PASCAL SocketWindowProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
+
+extern HWND hAmigaWnd;
+int hWndSelector = 0; /* Set this to zero to get hSockWnd */
+CRITICAL_SECTION csSigQueueLock;
+
+DWORD threadid;
+#ifdef __GNUC__
+#define THREAD(func,arg) CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)func,(LPVOID)arg,0,&threadid)
+#else
+#define THREAD(func,arg) _beginthreadex( NULL, 0, func, (void *)arg, 0, (unsigned *)&threadid )
+#endif
+
+#define SETERRNO seterrno(sb,WSAGetLastError()-WSABASEERR)
+#define SETHERRNO setherrno(sb,WSAGetLastError()-WSABASEERR)
+#define WAITSIGNAL waitsig(sb)
+
+#define SETSIGNAL addtosigqueue(sb,0)
+#define CANCELSIGNAL cancelsig(sb)
+
+#define FIOSETOWN _IOW('f', 124, long)    /* set owner (struct Task *) */
+#define FIOGETOWN _IOR('f', 123, long)    /* get owner (struct Task *) */
+
+#define BEGINBLOCKING if (sb->ftable[sd-1] & SF_BLOCKING) sb->ftable[sd-1] |= SF_BLOCKINGINPROGRESS
+#define ENDBLOCKING sb->ftable[sd-1] &= ~SF_BLOCKINGINPROGRESS
+
+static WSADATA wsbData;
+
+int PASCAL WSAEventSelect(SOCKET,HANDLE,long);
+
+#define MAX_SELECT_THREADS 64
+static HANDLE hThreads[MAX_SELECT_THREADS];
+uae_u32 *threadargs[MAX_SELECT_THREADS];
+static HANDLE hEvents[MAX_SELECT_THREADS];
+
+#define MAX_GET_THREADS 64
+static HANDLE hGetThreads[MAX_GET_THREADS];
+uae_u32 *threadGetargs[MAX_GET_THREADS];
+static HANDLE hGetEvents[MAX_GET_THREADS];
+
+
+static HANDLE hSockThread;
+static HANDLE hSockReq, hSockReqHandled;
+static unsigned int __stdcall sock_thread(void *);
+
+CRITICAL_SECTION SockThreadCS;
+#define PREPARE_THREAD EnterCriticalSection( &SockThreadCS )
+#define TRIGGER_THREAD { SetEvent( hSockReq ); WaitForSingleObject( hSockReqHandled, INFINITE ); LeaveCriticalSection( &SockThreadCS ); }
+
+#define SOCKVER_MAJOR 2
+#define SOCKVER_MINOR 2
+
+#define SF_RAW_UDP 0x10000000
+#define SF_RAW_RAW 0x20000000
+#define SF_RAW_RUDP 0x08000000
+#define SF_RAW_RICMP 0x04000000
+
+typedef struct ip_option_information {
+    u_char Ttl;                /* Time To Live (used for traceroute) */
+    u_char Tos;        /* Type Of Service (usually 0) */
+    u_char Flags;      /* IP header flags (usually 0) */
+    u_char OptionsSize; /* Size of options data (usually 0, max 40) */
+    u_char FAR *OptionsData;   /* Options data buffer */
+} IPINFO, *PIPINFO, FAR *LPIPINFO;
+
+static int mySockStartup( void )
+{
+    int result = 0;
+    SOCKET dummy;
+    DWORD lasterror;
+
+    if (WSAStartup(MAKEWORD( SOCKVER_MAJOR, SOCKVER_MINOR ), &wsbData))
+    {
+           lasterror = WSAGetLastError();
+           
+           if( lasterror == WSAVERNOTSUPPORTED )
+           {
+               char szMessage[ MAX_PATH ];
+               WIN32GUI_LoadUIString( IDS_WSOCK2NEEDED, szMessage, MAX_PATH );
+                gui_message( szMessage );
+           }
+           else
+                write_log( "BSDSOCK: ERROR - Unable to initialize Windows socket layer! Error code: %d\n", lasterror );
+           return 0;
+    }
+
+    if (LOBYTE (wsbData.wVersion) != SOCKVER_MAJOR || HIBYTE (wsbData.wVersion) != SOCKVER_MINOR )
+    {
+       char szMessage[ MAX_PATH ];
+       WIN32GUI_LoadUIString( IDS_WSOCK2NEEDED, szMessage, MAX_PATH );
+        gui_message( szMessage );
+
+        return 0;
+    }
+    else
+    {
+        write_log( "BSDSOCK: using %s\n", wsbData.szDescription );
+       // make sure WSP/NSPStartup gets called from within the regular stack
+       // (Windows 95/98 need this)
+       if( ( dummy = socket( AF_INET,SOCK_STREAM,IPPROTO_TCP ) ) != INVALID_SOCKET ) 
+       {
+           closesocket( dummy );
+           result = 1;
+       }
+       else
+       {
+           write_log( "BSDSOCK: ERROR - WSPStartup/NSPStartup failed! Error code: %d\n",WSAGetLastError() );
+           result = 0;
+       }
+    }
+
+    return result;
+}
+
+static int socket_layer_initialized = 0;
+
+int init_socket_layer(void)
+{
+    int result = 0;
+
+#ifndef CAN_DO_STACK_MAGIC
+    currprefs.socket_emu = 0;
+#endif
+    if( currprefs.socket_emu )
+    {
+       if( ( result = mySockStartup() ) )
+       {
+               InitializeCriticalSection(&csSigQueueLock);
+
+           if( hSockThread == NULL )
+           {
+           WNDCLASS wc;    // Set up an invisible window and dummy wndproc
+               
+               InitializeCriticalSection( &SockThreadCS );
+               hSockReq = CreateEvent( NULL, FALSE, FALSE, NULL );
+               hSockReqHandled = CreateEvent( NULL, FALSE, FALSE, NULL );
+
+               wc.style = CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW;
+               wc.lpfnWndProc = SocketWindowProc;
+               wc.cbClsExtra = 0;
+               wc.cbWndExtra = 0;
+               wc.hInstance = 0;
+               wc.hIcon = LoadIcon (GetModuleHandle (NULL), MAKEINTRESOURCE( IDI_APPICON ) );
+               wc.hCursor = LoadCursor (NULL, IDC_ARROW);
+               wc.hbrBackground = GetStockObject (BLACK_BRUSH);
+               wc.lpszMenuName = 0;
+               wc.lpszClassName = "SocketFun";
+               if( RegisterClass (&wc) )
+                       {
+                       hSockWnd = CreateWindowEx ( 0,
+                                   "SocketFun", "WinUAE Socket Window",
+                                   WS_POPUP,
+                                   0, 0,
+                                   1, 1, 
+                                   NULL, NULL, 0, NULL);
+                       hSockThread = (void *)THREAD(sock_thread,NULL);
+                       }
+           }
+       }
+    }
+
+    socket_layer_initialized = result;
+
+    return result;
+}
+
+void deinit_socket_layer(void)
+{
+    int i;
+    if( currprefs.socket_emu )
+    {
+       WSACleanup();
+       if( socket_layer_initialized )
+       {
+           DeleteCriticalSection( &csSigQueueLock );
+           if( hSockThread )
+           {
+               DeleteCriticalSection( &SockThreadCS );
+               CloseHandle( hSockReq );
+               hSockReq = NULL;
+               CloseHandle( hSockReqHandled );
+               WaitForSingleObject( hSockThread, INFINITE );
+               CloseHandle( hSockThread );
+           }
+           for (i = 0; i < MAX_SELECT_THREADS; i++)
+           {
+               if (hThreads[i])
+               {
+                   CloseHandle( hThreads[i] );
+               }
+           }
+       }
+    }
+}
+
+#ifdef BSDSOCKET
+
+void locksigqueue(void)
+{
+    EnterCriticalSection(&csSigQueueLock);
+}
+
+void unlocksigqueue(void)
+{
+    LeaveCriticalSection(&csSigQueueLock);
+}
+
+// Asynchronous completion notification
+
+// We use window messages posted to hAmigaWnd in the range from 0xb000 to 0xb000+MAXPENDINGASYNC*2
+// Socket events cause even-numbered messages, task events odd-numbered messages
+// Message IDs are allocated on a round-robin basis and deallocated by the main thread.
+
+// WinSock tends to choke on WSAAsyncCancelMessage(s,w,m,0,0) called too often with an event pending
+
+// @@@ Enabling all socket event messages for every socket by default and basing things on that would
+// be cleaner (and allow us to write a select() emulation that doesn't need to be kludge-aborted).
+// However, the latency of the message queue is too high for that at the moment (setting up a dummy
+// window from a separate thread would fix that).
+
+// Blocking sockets with asynchronous event notification are currently not safe to use.
+
+struct socketbase *asyncsb[MAXPENDINGASYNC];
+SOCKET asyncsock[MAXPENDINGASYNC];
+uae_u32 asyncsd[MAXPENDINGASYNC];
+int asyncindex;
+
+int host_sbinit(SB)
+{
+       sb->sockAbort = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
+       
+       if (sb->sockAbort == INVALID_SOCKET) return 0;
+       if ((sb->hEvent = CreateEvent(NULL,FALSE,FALSE,NULL)) == NULL) return 0;
+
+       sb->mtable = calloc(sb->dtablesize,sizeof(*sb->mtable));
+       
+       return 1;
+}
+
+void host_closesocketquick(int s)
+{
+       BOOL true = 1;
+
+       if( s )
+       {
+           setsockopt((SOCKET)s,SOL_SOCKET,SO_DONTLINGER,(char *)&true,sizeof(true));
+           shutdown(s,1);
+           closesocket((SOCKET)s);
+       }
+}
+
+void host_sbcleanup(SB)
+{
+       int i;
+
+       for (i = 0; i < MAXPENDINGASYNC; i++) if (asyncsb[i] == sb) asyncsb[i] = NULL;
+
+       if (sb->hEvent != NULL) CloseHandle(sb->hEvent);
+       
+       for (i = sb->dtablesize; i--; )
+       {
+               if (sb->dtable[i] != (int)INVALID_SOCKET) host_closesocketquick(sb->dtable[i]);
+               
+               if (sb->mtable[i]) asyncsb[(sb->mtable[i]-0xb000)/2] = NULL;
+       }
+
+        shutdown(sb->sockAbort,1);
+       closesocket(sb->sockAbort);
+
+       free(sb->mtable);
+}
+
+void host_sbreset(void)
+{
+       memset(asyncsb,0,sizeof asyncsb);
+       memset(asyncsock,0,sizeof asyncsock);
+       memset(asyncsd,0,sizeof asyncsd);
+       memset(threadargs,0,sizeof threadargs);
+}
+
+void sockmsg(unsigned int msg, unsigned long wParam, unsigned long lParam)
+{
+       SB;
+       unsigned int index;
+       int sdi;
+
+       index = (msg-0xb000)/2;
+       sb = asyncsb[index];
+    
+       if (!(msg & 1))
+       {
+               // is this one really for us?
+               if ((SOCKET)wParam != asyncsock[index])
+               {
+                       // cancel socket event
+                       WSAAsyncSelect((SOCKET)wParam,hWndSelector ? hAmigaWnd : hSockWnd,0,0);
+                       return;
+               }
+
+               sdi = asyncsd[index]-1;
+
+               // asynchronous socket event?
+               if (sb && !(sb->ftable[sdi] & SF_BLOCKINGINPROGRESS) && sb->mtable[sdi])
+               {
+                       long wsbevents = WSAGETSELECTEVENT(lParam);
+                       int fmask = 0;
+
+                       // regular socket event?
+                       if (wsbevents & FD_READ) fmask = REP_READ;
+                       else if (wsbevents & FD_WRITE) fmask = REP_WRITE;
+                       else if (wsbevents & FD_OOB) fmask = REP_OOB;
+                       else if (wsbevents & FD_ACCEPT) fmask = REP_ACCEPT;
+                       else if (wsbevents & FD_CONNECT) fmask = REP_CONNECT;
+                       else if (wsbevents & FD_CLOSE) fmask = REP_CLOSE;
+
+                       // error?
+                       if (WSAGETSELECTERROR(lParam)) fmask |= REP_ERROR;
+
+                       // notify
+                       if (sb->ftable[sdi] & fmask) sb->ftable[sdi] |= fmask<<8;
+
+                       addtosigqueue(sb,1);
+                       return;
+               }
+       }
+
+       locksigqueue();
+
+       if (sb != NULL)
+       {
+
+
+               asyncsb[index] = NULL;
+
+               if (WSAGETASYNCERROR(lParam))
+               {
+                       seterrno(sb,WSAGETASYNCERROR(lParam)-WSABASEERR);
+                       if (sb->sb_errno >= 1001 && sb->sb_errno <= 1005) setherrno(sb,sb->sb_errno-1000);
+                       else if (sb->sb_errno == 55)    // ENOBUFS
+                               write_log("BSDSOCK: ERROR - Buffer overflow - %d bytes requested\n",WSAGETASYNCBUFLEN(lParam));
+               }
+               else seterrno(sb,0);
+
+
+               SETSIGNAL;
+       }
+       
+       unlocksigqueue();
+}
+
+static unsigned int allocasyncmsg(SB,uae_u32 sd,SOCKET s)
+{
+       int i;
+       locksigqueue();
+       
+       for (i = asyncindex+1; i != asyncindex; i++)
+       {
+               if (i == MAXPENDINGASYNC) i = 0;
+               
+               if (!asyncsb[i])
+               {
+                       asyncsb[i] = sb;
+                       if (++asyncindex == MAXPENDINGASYNC) asyncindex = 0;
+                       unlocksigqueue();
+                       
+                       if (s == INVALID_SOCKET)
+                       {
+                               return i*2+0xb001;
+                       }
+                       else
+                       {
+                               asyncsd[i] = sd;
+                               asyncsock[i] = s;
+                               return i*2+0xb000;
+                       }
+               }
+       }
+       
+       unlocksigqueue();
+
+       seterrno(sb,12); // ENOMEM
+       write_log("BSDSOCK: ERROR - Async operation completion table overflow\n");
+       
+       return 0;
+}
+
+static void cancelasyncmsg(unsigned int wMsg)
+{
+       SB;
+       
+       wMsg = (wMsg-0xb000)/2;
+
+       sb = asyncsb[wMsg];
+
+       if (sb != NULL)
+       {
+               asyncsb[wMsg] = NULL;
+               CANCELSIGNAL;
+       }
+}
+
+void sockabort(SB)
+{      
+    locksigqueue();
+
+    unlocksigqueue();
+}
+
+void setWSAAsyncSelect(SB, uae_u32 sd, SOCKET s, long lEvent )
+       {
+       if (sb->mtable[sd-1])
+               {
+               long wsbevents = 0;
+               long eventflags;
+               int i;
+               locksigqueue();
+       
+
+               eventflags = sb->ftable[sd-1]  & REP_ALL;
+
+               if (eventflags & REP_ACCEPT) wsbevents |= FD_ACCEPT;
+               if (eventflags & REP_CONNECT) wsbevents |= FD_CONNECT;
+               if (eventflags & REP_OOB) wsbevents |= FD_OOB;
+               if (eventflags & REP_READ) wsbevents |= FD_READ;
+               if (eventflags & REP_WRITE) wsbevents |= FD_WRITE;
+               if (eventflags & REP_CLOSE) wsbevents |= FD_CLOSE;
+               wsbevents |= lEvent;
+               i = (sb->mtable[sd-1]-0xb000)/2;
+               asyncsb[i] = sb;
+               asyncsd[i] = sd;
+               asyncsock[i] = s;
+               WSAAsyncSelect(s,hWndSelector ? hAmigaWnd : hSockWnd,sb->mtable[sd-1],wsbevents);
+
+               unlocksigqueue();
+               }
+       }
+
+
+// address cleaning
+static void prephostaddr(SOCKADDR_IN *addr)
+{
+    addr->sin_family = AF_INET;
+}
+
+static void prepamigaaddr(struct sockaddr *realpt, int len)
+{
+    // little endian address family value to the byte sin_family member
+    ((char *)realpt)[1] = *((char *)realpt);
+    
+    // set size of address
+    *((char *)realpt) = len;
+}
+
+
+int host_dup2socket(SB, int fd1, int fd2)
+       {
+    SOCKET s1,s2;
+
+    TRACE(("dup2socket(%d,%d) -> ",fd1,fd2));
+       fd1++;
+
+    s1 = getsock(sb, fd1);
+    if (s1 != INVALID_SOCKET)
+               {
+               if (fd2 != -1)
+                       {
+                   if ((unsigned int) (fd2) >= (unsigned int) sb->dtablesize) 
+                               {
+                               TRACE (("Bad file descriptor (%d)\n", fd2));
+                               seterrno (sb, 9);       /* EBADF */
+                               }
+                       fd2++;
+                       s2 = getsock(sb,fd2);
+                       if (s2 != INVALID_SOCKET)
+                               {
+                   shutdown(s2,1);
+                           closesocket(s2);
+                               }
+                       setsd(sb,fd2,s1);
+                   TRACE(("0\n"));
+                       return 0;
+                       }
+               else
+                       {
+                       fd2 = getsd(sb, 1);
+                       setsd(sb,fd2,s1);
+                   TRACE(("%d\n",fd2));
+                       return (fd2 - 1);
+                       }
+               }
+    TRACE(("-1\n"));
+       return -1;
+       }
+
+int host_socket(SB, int af, int type, int protocol)
+{
+    int sd;
+    SOCKET s;
+    unsigned long nonblocking = 1;
+
+    TRACE(("socket(%s,%s,%d) -> ",af == AF_INET ? "AF_INET" : "AF_other",type == SOCK_STREAM ? "SOCK_STREAM" : type == SOCK_DGRAM ? "SOCK_DGRAM " : "SOCK_RAW",protocol));
+
+    if ((s = socket(af,type,protocol)) == INVALID_SOCKET)
+    {
+       SETERRNO;
+       TRACE(("failed (%d)\n",sb->sb_errno));
+       return -1;
+    }
+    else
+        sd = getsd(sb,(int)s);
+
+       sb->ftable[sd-1] = SF_BLOCKING;
+    ioctlsocket(s,FIONBIO,&nonblocking);
+    TRACE(("%d\n",sd));
+
+       if (type == SOCK_RAW)
+               {
+               if (protocol==IPPROTO_UDP)
+                       {
+                       sb->ftable[sd-1] |= SF_RAW_UDP;
+                       }
+               if (protocol==IPPROTO_ICMP)
+                       {
+                       struct sockaddr_in sin;
+
+                       sin.sin_family = AF_INET;
+                       sin.sin_addr.s_addr = INADDR_ANY;
+                       bind(s,(struct sockaddr *)&sin,sizeof(sin)) ;
+                       }
+               if (protocol==IPPROTO_RAW)
+                       {
+                       sb->ftable[sd-1] |= SF_RAW_RAW;
+                       }
+               }
+       return sd-1;
+}
+
+uae_u32 host_bind(SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
+{
+    char buf[MAXADDRLEN];
+    uae_u32 success = 0;
+    SOCKET s;
+
+       sd++;
+    TRACE(("bind(%d,0x%lx,%d) -> ",sd,name,namelen));
+    s = getsock(sb, sd);
+
+    if (s != INVALID_SOCKET)
+    {
+       if (namelen <= sizeof buf)
+       {
+           memcpy(buf,get_real_address(name),namelen);
+           
+           // some Amiga programs set this field to bogus values
+           prephostaddr((SOCKADDR_IN *)buf);
+
+           if ((success = bind(s,(struct sockaddr *)buf,namelen)) != 0)
+           {
+               SETERRNO;
+               TRACE(("failed (%d)\n",sb->sb_errno));
+           }
+           else
+                TRACE(("OK\n"));
+       }
+       else
+            write_log("BSDSOCK: ERROR - Excessive namelen (%d) in bind()!\n",namelen);
+    }
+
+    return success;
+}
+
+uae_u32 host_listen(SB, uae_u32 sd, uae_u32 backlog)
+{
+    SOCKET s;
+    uae_u32 success = -1;
+       
+       sd++;
+    TRACE(("listen(%d,%d) -> ",sd,backlog));
+    s = getsock(sb, sd);
+
+    if (s != INVALID_SOCKET)
+    {
+       if ((success = listen(s,backlog)) != 0)
+       {
+           SETERRNO;
+           TRACE(("failed (%d)\n",sb->sb_errno));
+       }
+       else 
+            TRACE(("OK\n"));
+    }
+                   
+    return success;
+}
+
+void host_accept(SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
+{
+    struct sockaddr *rp_name,*rp_nameuae;
+       struct sockaddr sockaddr;
+    int hlen,hlenuae=0;
+    SOCKET s, s2;
+    int success = 0;
+    unsigned int wMsg;
+    
+    sd++;
+       if (name != 0 )
+               {
+               rp_nameuae = rp_name = (struct sockaddr *)get_real_address(name);
+           hlenuae = hlen = get_long(namelen);
+               if (hlenuae < sizeof(sockaddr))
+                       { // Fix for CNET BBS Windows must have 16 Bytes (sizeof(sockaddr)) otherwise Error WSAEFAULT
+                       rp_name = &sockaddr; 
+                       hlen = sizeof(sockaddr);
+                       }
+               }
+       else
+               {
+               rp_name = &sockaddr; 
+               hlen = sizeof(sockaddr);
+               }
+    TRACE(("accept(%d,%d,%d) -> ",sd,name,hlenuae));
+
+    s = (SOCKET)getsock(sb,(int)sd);
+    
+    if (s != INVALID_SOCKET)
+    {
+       BEGINBLOCKING;
+       
+       s2 = accept(s,rp_name,&hlen);
+
+       if (s2 == INVALID_SOCKET)
+       {
+           SETERRNO;
+
+           if (sb->ftable[sd-1] & SF_BLOCKING && sb->sb_errno == WSAEWOULDBLOCK-WSABASEERR)
+           {
+               if (sb->mtable[sd-1] || (wMsg = allocasyncmsg(sb,sd,s)) != 0)
+               {
+                       if (sb->mtable[sd-1] == 0)
+                               {
+                           WSAAsyncSelect(s,hWndSelector ? hAmigaWnd : hSockWnd,wMsg,FD_ACCEPT);
+                               }
+                       else
+                               {
+                               setWSAAsyncSelect(sb,sd,s,FD_ACCEPT);
+                               }
+
+                   WAITSIGNAL;
+
+                       if (sb->mtable[sd-1] == 0)
+                               {
+                               cancelasyncmsg(wMsg);
+                               }
+                       else
+                               {
+                               setWSAAsyncSelect(sb,sd,s,0);
+                               }
+                   
+                   if (sb->eintr)
+                   {
+                       TRACE(("[interrupted]\n"));
+                       ENDBLOCKING;
+                       return;
+                   }
+
+                   s2 = accept(s,rp_name,&hlen);
+
+                   if (s2 == INVALID_SOCKET)
+                   {
+                       SETERRNO;
+
+                       if (sb->sb_errno == WSAEWOULDBLOCK-WSABASEERR) write_log("BSDSOCK: ERRRO - accept() would block despite FD_ACCEPT message\n");
+                   }
+               }
+           }
+       }
+                       
+       if (s2 == INVALID_SOCKET)
+       {
+           sb->resultval = -1;
+           TRACE(("failed (%d)\n",sb->sb_errno));
+       }
+       else
+       {
+           sb->resultval = getsd(sb, s2);
+           sb->ftable[sb->resultval-1] = sb->ftable[sd-1];     // new socket inherits the old socket's properties
+               sb->resultval--;
+           if (rp_name != 0)
+                       { // 1.11.2002 XXX
+                       if (hlen <= hlenuae)
+                               { // Fix for CNET BBS Part 2
+                               prepamigaaddr(rp_name,hlen);
+                               if (namelen != 0)
+                                       {
+                                       put_long(namelen,hlen);
+                                       }
+                               }
+                       else
+                               { // Copy only the number of bytes requested
+                               if (hlenuae != 0)
+                                       {       
+                                       prepamigaaddr(rp_name,hlenuae);
+                                       memcpy(rp_nameuae,rp_name,hlenuae);
+                                       put_long(namelen,hlenuae);
+                                       }
+                               }
+                       }
+           TRACE(("%d/%d\n",sb->resultval,hlen));
+       }
+
+       ENDBLOCKING;
+    }
+
+       }
+
+typedef enum
+{
+    connect_req,
+    recvfrom_req,
+    sendto_req,
+    abort_req,
+    last_req
+} threadsock_e;
+
+struct threadsock_packet
+{
+    threadsock_e packet_type;
+    union
+    {
+        struct sendto_params
+        {
+            char *buf;
+            char *realpt;
+            uae_u32 sd;
+            uae_u32 msg;
+            uae_u32 len;
+            uae_u32 flags;
+            uae_u32 to;
+            uae_u32 tolen;
+        } sendto_s;
+        struct recvfrom_params
+        {
+            char *realpt;
+            uae_u32 addr;
+            uae_u32 len;
+            uae_u32 flags;
+            struct sockaddr *rp_addr;
+            int *hlen;
+        } recvfrom_s;
+        struct connect_params
+        {
+            char *buf;
+            uae_u32 namelen;
+        } connect_s;
+        struct abort_params
+        {
+            SOCKET *newsock;
+        } abort_s;
+    } params;
+    SOCKET s;
+    SB;
+} sockreq;
+
+BOOL HandleStuff( void )
+{
+    BOOL quit = FALSE;
+    SB = NULL;
+    BOOL handled = TRUE;
+    if( hSockReq )
+    {
+       // 100ms sleepiness might need some tuning...
+       //if(WaitForSingleObject( hSockReq, 100 ) == WAIT_OBJECT_0 )
+       {
+           switch( sockreq.packet_type )
+           {
+               case connect_req:
+                   sockreq.sb->resultval = connect(sockreq.s,(struct sockaddr *)(sockreq.params.connect_s.buf),sockreq.params.connect_s.namelen);
+               break;
+               case sendto_req:
+                   if( sockreq.params.sendto_s.to )
+                   {
+                       sockreq.sb->resultval = sendto(sockreq.s,sockreq.params.sendto_s.realpt,sockreq.params.sendto_s.len,sockreq.params.sendto_s.flags,(struct sockaddr *)(sockreq.params.sendto_s.buf),sockreq.params.sendto_s.tolen);
+                   }
+                   else
+                   {
+                       sockreq.sb->resultval = send(sockreq.s,sockreq.params.sendto_s.realpt,sockreq.params.sendto_s.len,sockreq.params.sendto_s.flags);
+                   }
+               break;
+               case recvfrom_req:
+                   if( sockreq.params.recvfrom_s.addr )
+                   {
+                       sockreq.sb->resultval = recvfrom( sockreq.s, sockreq.params.recvfrom_s.realpt, sockreq.params.recvfrom_s.len,
+                                                         sockreq.params.recvfrom_s.flags, sockreq.params.recvfrom_s.rp_addr,
+                                                         sockreq.params.recvfrom_s.hlen );
+
+                   }
+                   else
+                   {
+                       sockreq.sb->resultval = recv( sockreq.s, sockreq.params.recvfrom_s.realpt, sockreq.params.recvfrom_s.len,
+                                                     sockreq.params.recvfrom_s.flags );
+                   }
+               break;
+               case abort_req:
+                   *(sockreq.params.abort_s.newsock) = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
+                       if (*(sockreq.params.abort_s.newsock) != sb->sockAbort)
+                               {
+                               shutdown( sb->sockAbort, 1 );
+                               closesocket(sb->sockAbort);
+                               }
+                   handled = FALSE; /* Don't bother the SETERRNO section after the switch() */
+               break;
+               case last_req:
+               default:
+                   write_log( "BSDSOCK: Invalid sock-thread request!\n" );
+                   handled = FALSE;
+               break;
+           }
+           if( handled )
+           {
+               if( sockreq.sb->resultval == SOCKET_ERROR )
+               {
+                   sb = sockreq.sb;
+                       
+                   SETERRNO;
+               }
+           }
+           SetEvent( hSockReqHandled );
+       }
+    }
+    else
+    {
+       quit = TRUE;
+    }
+    return quit;
+}
+
+static long FAR PASCAL SocketWindowProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
+{
+    if( message >= 0xB000 && message < 0xB000+MAXPENDINGASYNC*2 )
+    {
+#if DEBUG_SOCKETS
+        write_log( "sockmsg(0x%x, 0x%x, 0x%x)\n", message, wParam, lParam );
+#endif
+        sockmsg( message, wParam, lParam );
+        return 0;
+    }
+    return DefWindowProc( hwnd, message, wParam, lParam );
+}
+
+
+
+static unsigned int __stdcall sock_thread(void *blah)
+{
+    unsigned int result = 0;
+       HANDLE WaitHandle;
+    MSG msg;
+
+       if( hSockWnd )
+       {
+    // Make sure we're outrunning the wolves
+               int pri;
+               pri = priorities[currprefs.win32_active_priority].value;
+               if (pri == THREAD_PRIORITY_HIGHEST)
+                       pri = THREAD_PRIORITY_TIME_CRITICAL;
+               else
+                       pri++;
+           SetThreadPriority( GetCurrentThread(), pri );
+           
+           while( TRUE )
+           {
+           if( hSockReq )
+                       {
+                       DWORD wait;
+                       WaitHandle = hSockReq;
+                       wait = MsgWaitForMultipleObjects (1, &WaitHandle, FALSE,INFINITE, QS_POSTMESSAGE);
+                       if (wait == WAIT_OBJECT_0)
+                               {
+                               if( HandleStuff() ) // See if its time to quit...
+                                       break;
+                               }
+                       if (wait == WAIT_OBJECT_0 +1)
+                               {
+                               Sleep(10);
+                               while( PeekMessage( &msg, NULL, WM_USER, 0xB000+MAXPENDINGASYNC*2, PM_REMOVE ) > 0 )
+                                       {
+                                       TranslateMessage( &msg );
+                                       DispatchMessage( &msg );
+                                       }
+                               }
+                       }
+           }
+       }
+    write_log( "BSDSOCK: We have exited our sock_thread()\n" );
+#ifndef __GNUC__
+    _endthreadex( result );
+#endif
+    return result;
+}
+
+
+void host_connect(SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
+{
+    SOCKET s;
+    int success = 0;
+    unsigned int wMsg;
+    char buf[MAXADDRLEN];
+
+
+       sd++;
+    TRACE(("connect(%d,0x%lx,%d) -> ",sd,name,namelen));
+
+    s = (SOCKET)getsock(sb,(int)sd);
+    
+    if (s != INVALID_SOCKET)
+    {
+       if (namelen <= MAXADDRLEN)
+       {
+           if (sb->mtable[sd-1] || (wMsg = allocasyncmsg(sb,sd,s)) != 0)
+           {
+               if (sb->mtable[sd-1] == 0)
+                       {
+                       WSAAsyncSelect(s,hWndSelector ? hAmigaWnd : hSockWnd,wMsg,FD_CONNECT);
+                       }
+               else
+                       {
+                       setWSAAsyncSelect(sb,sd,s,FD_CONNECT);
+                       }
+
+       
+               BEGINBLOCKING;
+                PREPARE_THREAD;
+
+               memcpy(buf,get_real_address(name),namelen);
+               prephostaddr((SOCKADDR_IN *)buf);
+               
+                sockreq.packet_type = connect_req;
+                sockreq.s = s;
+                sockreq.sb = sb;
+                sockreq.params.connect_s.buf = buf;
+                sockreq.params.connect_s.namelen = namelen;
+
+                TRIGGER_THREAD;
+
+
+               if (sb->resultval)
+               {
+                   if (sb->sb_errno == WSAEWOULDBLOCK-WSABASEERR)
+                   {
+                       if (sb->ftable[sd-1] & SF_BLOCKING)
+                       {
+                           seterrno(sb,0);
+                       
+       
+                               WAITSIGNAL;
+
+                           if (sb->eintr)
+                           {
+                               // Destroy socket to cancel abort, replace it with fake socket to enable proper closing.
+                               // This is in accordance with BSD behaviour.
+                                shutdown(s,1);
+                               closesocket(s);
+                               sb->dtable[sd-1] = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
+                           }
+                       }
+                       else
+                                       {
+                    seterrno(sb,36);   // EINPROGRESS
+
+                                       }
+                   }
+               else
+                       {
+                       CANCELSIGNAL; // Cancel pending signal
+
+                       }
+                       }
+
+                       ENDBLOCKING;
+                       if (sb->mtable[sd-1] == 0)
+                               {
+                               cancelasyncmsg(wMsg);
+                               }
+                       else
+                               {
+                               setWSAAsyncSelect(sb,sd,s,0);
+                               }
+                       }
+
+        }
+        else
+            write_log("BSDSOCK: WARNING - Excessive namelen (%d) in connect()!\n",namelen);
+    }
+    TRACE(("%d\n",sb->sb_errno));
+}
+
+void host_sendto(SB, uae_u32 sd, uae_u32 msg, uae_u32 len, uae_u32 flags, uae_u32 to, uae_u32 tolen)
+{
+    SOCKET s;
+    char *realpt;
+    unsigned int wMsg;
+    char buf[MAXADDRLEN];
+       int iCut;
+
+#ifdef TRACING_ENABLED
+    if (to)
+       TRACE(("sendto(%d,0x%lx,%d,0x%lx,0x%lx,%d) -> ",sd,msg,len,flags,to,tolen));
+    else
+       TRACE(("send(%d,0x%lx,%d,%d) -> ",sd,msg,len,flags));
+#endif
+       sd++;
+    s = getsock(sb,sd);
+
+    if (s != INVALID_SOCKET)
+    {
+        realpt = get_real_address(msg);
+               
+       if (to)
+       {
+           if (tolen > sizeof buf) write_log("BSDSOCK: WARNING - Target address in sendto() too large (%d)!\n",tolen);
+           else
+           {
+               memcpy(buf,get_real_address(to),tolen);
+               // some Amiga software sets this field to bogus values
+               prephostaddr((SOCKADDR_IN *)buf);
+           }
+       }
+       if (sb->ftable[sd-1]&SF_RAW_RAW)
+               {
+               if (*(realpt+9) == 0x1)
+                       { // ICMP
+                       struct sockaddr_in sin;
+                       shutdown(s,1);
+                       closesocket(s);
+                       s = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
+
+                       sin.sin_family = AF_INET;
+                       sin.sin_addr.s_addr = INADDR_ANY;
+                       sin.sin_port = (unsigned short) (*(realpt+21)&0xff)*256 + (unsigned short) (*(realpt+20)&0xff);
+                       bind(s,(struct sockaddr *)&sin,sizeof(sin)) ;
+
+                       sb->dtable[sd-1] = s;
+                       sb->ftable[sd-1]&= ~SF_RAW_RAW;
+                       sb->ftable[sd-1]|= SF_RAW_RICMP;
+                       }
+               if (*(realpt+9) == 0x11)
+                       { // UDP
+                       struct sockaddr_in sin;
+                       shutdown(s,1);
+                       closesocket(s);
+                       s = socket(AF_INET,SOCK_RAW,IPPROTO_UDP);
+
+                       sin.sin_family = AF_INET;
+                       sin.sin_addr.s_addr = INADDR_ANY;
+                       sin.sin_port = (unsigned short) (*(realpt+21)&0xff)*256 + (unsigned short) (*(realpt+20)&0xff);
+                       bind(s,(struct sockaddr *)&sin,sizeof(sin)) ;
+
+                       sb->dtable[sd-1] = s;
+                       sb->ftable[sd-1]&= ~SF_RAW_RAW;
+                       sb->ftable[sd-1]|= SF_RAW_RUDP;
+                       }
+               }
+               
+       BEGINBLOCKING;
+
+       for (;;)
+       {
+            PREPARE_THREAD;
+
+            sockreq.packet_type = sendto_req;
+            sockreq.s = s;
+            sockreq.sb = sb;
+            sockreq.params.sendto_s.realpt = realpt;
+            sockreq.params.sendto_s.buf = buf;
+            sockreq.params.sendto_s.sd = sd;
+            sockreq.params.sendto_s.msg = msg;
+            sockreq.params.sendto_s.len = len;
+            sockreq.params.sendto_s.flags = flags;
+            sockreq.params.sendto_s.to = to;
+            sockreq.params.sendto_s.tolen = tolen;
+
+                       if (sb->ftable[sd-1]&SF_RAW_UDP)
+                               {
+                               *(buf+2) = *(realpt+2);
+                               *(buf+3) = *(realpt+3);
+                               // Copy DST-Port
+                               iCut = 8;
+                               sockreq.params.sendto_s.realpt += iCut;
+                               sockreq.params.sendto_s.len -= iCut;
+                               }
+                       if (sb->ftable[sd-1]&SF_RAW_RUDP)
+                               {
+                               int iTTL;
+                               iTTL = (int) *(realpt+8)&0xff;
+                               setsockopt(s,IPPROTO_IP,4,(char*) &iTTL,sizeof(iTTL));
+                               *(buf+2) = *(realpt+22);
+                               *(buf+3) = *(realpt+23);
+                               // Copy DST-Port
+                               iCut = 28;
+                               sockreq.params.sendto_s.realpt += iCut;
+                               sockreq.params.sendto_s.len -= iCut;
+                               }
+                       if (sb->ftable[sd-1]&SF_RAW_RICMP)
+                               {
+                               int iTTL;
+                               iTTL = (int) *(realpt+8)&0xff;
+                               setsockopt(s,IPPROTO_IP,4,(char*) &iTTL,sizeof(iTTL));
+                               iCut = 20;
+                               sockreq.params.sendto_s.realpt += iCut;
+                               sockreq.params.sendto_s.len -= iCut;
+                               }
+
+                       
+
+            TRIGGER_THREAD;
+               if (sb->ftable[sd-1]&SF_RAW_UDP||sb->ftable[sd-1]&SF_RAW_RUDP||sb->ftable[sd-1]&SF_RAW_RICMP)
+                       {
+                       sb->resultval += iCut;
+                       }
+           if (sb->resultval == -1)
+           {
+               if (sb->sb_errno != WSAEWOULDBLOCK-WSABASEERR || !(sb->ftable[sd-1] & SF_BLOCKING)) break;
+           }
+           else
+           {
+               realpt += sb->resultval;
+               len -= sb->resultval;
+               
+               if (len <= 0) break;
+               else continue;
+           }
+
+           if (sb->mtable[sd-1] || (wMsg = allocasyncmsg(sb,sd,s)) != 0)
+           {
+               if (sb->mtable[sd-1] == 0)
+                       {
+                       WSAAsyncSelect(s,hWndSelector ? hAmigaWnd : hSockWnd,wMsg,FD_WRITE);
+                       }
+               else
+                       {
+                       setWSAAsyncSelect(sb,sd,s,FD_WRITE);
+                       }
+                       
+               WAITSIGNAL;
+               
+               if (sb->mtable[sd-1] == 0)
+                       {
+                       cancelasyncmsg(wMsg);
+                       }
+               else
+                       {
+                       setWSAAsyncSelect(sb,sd,s,0);
+                       }
+               
+               if (sb->eintr)
+               {
+                   TRACE(("[interrupted]\n"));
+                   return;
+               }
+           }
+           else break;
+       }
+
+       ENDBLOCKING;
+    }
+    else sb->resultval = -1;
+
+#ifdef TRACING_ENABLED
+    if (sb->resultval == -1)
+       TRACE(("failed (%d)\n",sb->sb_errno));
+    else
+       TRACE(("%d\n",sb->resultval));
+#endif
+
+}
+
+void host_recvfrom(SB, uae_u32 sd, uae_u32 msg, uae_u32 len, uae_u32 flags, uae_u32 addr, uae_u32 addrlen)
+{
+    SOCKET s;
+    char *realpt;
+    struct sockaddr *rp_addr = NULL;
+    int hlen;
+    unsigned int wMsg;
+
+#ifdef TRACING_ENABLED
+    if (addr)
+       TRACE(("recvfrom(%d,0x%lx,%d,0x%lx,0x%lx,%d) -> ",sd,msg,len,flags,addr,get_long(addrlen)));
+    else
+       TRACE(("recv(%d,0x%lx,%d,0x%lx) -> ",sd,msg,len,flags));
+#endif
+    sd++;
+    s = getsock(sb,sd);
+
+    if (s != INVALID_SOCKET)
+    {
+       realpt = get_real_address(msg);
+
+       if (addr)
+       {
+           hlen = get_long(addrlen);
+           rp_addr = (struct sockaddr *)get_real_address(addr);
+       }
+
+       BEGINBLOCKING;
+
+       for (;;)
+       {
+            PREPARE_THREAD;
+
+            sockreq.packet_type = recvfrom_req;
+            sockreq.s = s;
+            sockreq.sb = sb;
+            sockreq.params.recvfrom_s.addr = addr;
+            sockreq.params.recvfrom_s.flags = flags;
+            sockreq.params.recvfrom_s.hlen = &hlen;
+            sockreq.params.recvfrom_s.len = len;
+            sockreq.params.recvfrom_s.realpt = realpt;
+            sockreq.params.recvfrom_s.rp_addr = rp_addr;
+
+            TRIGGER_THREAD;
+           if (sb->resultval == -1)
+           {
+               if (sb->sb_errno == WSAEWOULDBLOCK-WSABASEERR && sb->ftable[sd-1] & SF_BLOCKING)
+               {
+                   if (sb->mtable[sd-1] || (wMsg = allocasyncmsg(sb,sd,s)) != 0)
+                   {
+                       if (sb->mtable[sd-1] == 0)
+                       {
+                           WSAAsyncSelect(s,hWndSelector ? hAmigaWnd : hSockWnd,wMsg,FD_READ|FD_CLOSE);
+                       }
+                       else
+                       {
+                           setWSAAsyncSelect(sb,sd,s,FD_READ|FD_CLOSE);
+                       }
+
+                       WAITSIGNAL;
+               
+                       if (sb->mtable[sd-1] == 0)
+                       {
+                           cancelasyncmsg(wMsg);
+                       }
+                       else
+                       {
+                           setWSAAsyncSelect(sb,sd,s,0);
+                       }
+
+               
+                       if (sb->eintr)
+                       {
+                           TRACE(("[interrupted]\n"));
+                           return;
+                       }
+                   }
+                   else break;
+               }
+               else break;
+           }
+           else break;
+       }
+       
+       ENDBLOCKING;
+
+       if (addr)
+       {
+           prepamigaaddr(rp_addr,hlen);
+           put_long(addrlen,hlen);
+       }
+    }
+    else sb->resultval = -1;
+
+#ifdef TRACING_ENABLED
+    if (sb->resultval == -1)
+       TRACE(("failed (%d)\n",sb->sb_errno));
+    else
+       TRACE(("%d\n",sb->resultval));
+#endif
+
+}
+
+uae_u32 host_shutdown(SB, uae_u32 sd, uae_u32 how)
+{
+    SOCKET s;
+    
+    TRACE(("shutdown(%d,%d) -> ",sd,how));
+    sd++;
+    s = getsock(sb,sd);
+
+    if (s != INVALID_SOCKET)
+    {
+       if (shutdown(s,how))
+       {
+           SETERRNO;
+           TRACE(("failed (%d)\n",sb->sb_errno));
+       }
+       else
+       {
+           TRACE(("OK\n"));
+           return 0;
+       }
+    }
+       
+    return -1;
+}
+
+void host_setsockopt(SB, uae_u32 sd, uae_u32 level, uae_u32 optname, uae_u32 optval, uae_u32 len)
+{
+    SOCKET s;
+    char buf[MAXADDRLEN];
+
+    TRACE(("setsockopt(%d,%d,0x%lx,0x%lx,%d) -> ",sd,(short)level,optname,optval,len));
+       sd++;
+    s = getsock(sb,sd);
+
+    if (s != INVALID_SOCKET)
+    {
+       if (len > sizeof buf)
+       {
+           write_log("BSDSOCK: WARNING - Excessive optlen in setsockopt() (%d)\n",len);
+           len = sizeof buf;
+       }       
+       if (level == IPPROTO_IP && optname == 2)
+               { // IP_HDRINCL emulated by icmp.dll
+               sb->resultval = 0;
+               return;
+               }
+       if (level == SOL_SOCKET && optname == SO_LINGER)
+       {
+           ((LINGER *)buf)->l_onoff = get_long(optval);
+           ((LINGER *)buf)->l_linger = get_long(optval+4);
+       }
+       else
+       {
+           if (len == 4) *(long *)buf = get_long(optval);
+           else if (len == 2) *(short *)buf = get_word(optval);
+           else write_log("BSDSOCK: ERROR - Unknown optlen (%d) in setsockopt(%d,%d)\n",level,optname);
+       }
+
+       // handle SO_EVENTMASK
+       if (level == 0xffff && optname == 0x2001)
+       {
+           long wsbevents = 0;
+           uae_u32 eventflags = get_long(optval);
+
+           sb->ftable[sd-1] = (sb->ftable[sd-1] & ~REP_ALL) | (eventflags & REP_ALL);
+
+           if (eventflags & REP_ACCEPT) wsbevents |= FD_ACCEPT;
+           if (eventflags & REP_CONNECT) wsbevents |= FD_CONNECT;
+           if (eventflags & REP_OOB) wsbevents |= FD_OOB;
+           if (eventflags & REP_READ) wsbevents |= FD_READ;
+           if (eventflags & REP_WRITE) wsbevents |= FD_WRITE;
+           if (eventflags & REP_CLOSE) wsbevents |= FD_CLOSE;
+           
+           if (sb->mtable[sd-1] || (sb->mtable[sd-1] = allocasyncmsg(sb,sd,s)))
+           {
+                   WSAAsyncSelect(s,hWndSelector ? hAmigaWnd : hSockWnd,sb->mtable[sd-1],wsbevents);
+                   sb->resultval = 0;
+           }
+           else sb->resultval = -1;
+       }
+       else sb->resultval = setsockopt(s,level,optname,buf,len);
+               
+       if (!sb->resultval)
+       {
+           TRACE(("OK\n"));
+           return;
+       }
+       else SETERRNO;
+               
+       TRACE(("failed (%d)\n",sb->sb_errno));
+    }
+}
+
+uae_u32 host_getsockopt(SB, uae_u32 sd, uae_u32 level, uae_u32 optname, uae_u32 optval, uae_u32 optlen)
+{
+       SOCKET s;
+       char buf[MAXADDRLEN];
+       int len = sizeof(buf);
+
+       TRACE(("getsockopt(%d,%d,0x%lx,0x%lx,0x%lx) -> ",sd,(short)level,optname,optval,optlen));
+       sd++;
+       s = getsock(sb,sd);
+       
+       if (s != INVALID_SOCKET)
+       {
+               if (!getsockopt(s,level,optname,buf,&len))
+               {
+                       if (level == SOL_SOCKET && optname == SO_LINGER)
+                       {
+                               put_long(optval,((LINGER *)buf)->l_onoff);
+                               put_long(optval+4,((LINGER *)buf)->l_linger);
+                       }
+                       else
+                       {
+                               if (len == 4) put_long(optval,*(long *)buf);
+                               else if (len == 2) put_word(optval,*(short *)buf);
+                               else write_log("BSDSOCK: ERROR - Unknown optlen (%d) in setsockopt(%d,%d)\n",level,optname);
+                       }
+
+//                     put_long(optlen,len); // some programs pass the actual ength instead of a pointer to the length, so...
+                       TRACE(("OK (%d,%d)\n",len,*(long *)buf));
+                       return 0;
+               }
+               else
+               {
+                       SETERRNO;
+                       TRACE(("failed (%d)\n",sb->sb_errno));
+               }
+       }
+
+       return -1;
+}
+
+uae_u32 host_getsockname(SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
+{
+       SOCKET s;
+       int len;
+       struct sockaddr *rp_name;
+
+       sd++;
+       len = get_long(namelen);
+       
+       TRACE(("getsockname(%d,0x%lx,%d) -> ",sd,name,len));
+       
+       s = getsock(sb,sd);
+       
+       if (s != INVALID_SOCKET)
+       {
+               rp_name = (struct sockaddr *)get_real_address(name);
+               
+               if (getsockname(s,rp_name,&len))
+               {
+                       SETERRNO;
+                       TRACE(("failed (%d)\n",sb->sb_errno));
+               }
+               else
+               {
+                       TRACE(("%d\n",len));
+                       prepamigaaddr(rp_name,len);
+                       put_long(namelen,len);
+                       return 0;
+               }
+       }       
+
+       return -1;
+}
+
+uae_u32 host_getpeername(SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
+{
+       SOCKET s;
+       int len;
+       struct sockaddr *rp_name;
+       
+       sd++;
+       len = get_long(namelen);
+       
+       TRACE(("getpeername(%d,0x%lx,%d) -> ",sd,name,len));
+       
+       s = getsock(sb,sd);
+       
+       if (s != INVALID_SOCKET)
+       {
+               rp_name = (struct sockaddr *)get_real_address(name);
+               
+               if (getpeername(s,rp_name,&len))
+               {
+                       SETERRNO;
+                       TRACE(("failed (%d)\n",sb->sb_errno));
+               }
+               else
+               {
+                       TRACE(("%d\n",len));
+                       prepamigaaddr(rp_name,len);
+                       put_long(namelen,len);
+                       return 0;
+               }
+       }       
+
+       return -1;
+}
+
+uae_u32 host_IoctlSocket(SB, uae_u32 sd, uae_u32 request, uae_u32 arg)
+{
+       SOCKET s;
+       uae_u32 data;
+       int success = SOCKET_ERROR;
+
+       TRACE(("IoctlSocket(%d,0x%lx,0x%lx) ",sd,request,arg));
+       sd++;
+       s = getsock(sb,sd);
+
+       if (s != INVALID_SOCKET)
+       {
+               switch (request)
+               {
+                       case FIOSETOWN:
+                           sb->ownertask = get_long(arg);
+                           success = 0;
+                       break;
+                       case FIOGETOWN:
+                           put_long(arg,sb->ownertask);
+                           success = 0;
+                       break;
+                       case FIONBIO:
+                               TRACE(("[FIONBIO] -> "));
+                               if (get_long(arg))
+                               {
+                                       TRACE(("nonblocking\n"));
+                                       sb->ftable[sd-1] &= ~SF_BLOCKING;
+                               }
+                               else
+                               {
+                                       TRACE(("blocking\n"));
+                                       sb->ftable[sd-1] |= SF_BLOCKING;
+                               }
+                               success = 0;
+                               break;
+                       case FIONREAD:
+                               ioctlsocket(s,request,(u_long *)&data);
+                               TRACE(("[FIONREAD] -> %d\n",data));
+                               put_long(arg,data);
+                               success = 0;
+                               break;
+                       case FIOASYNC:
+                               if (get_long(arg))
+                               {
+                                       sb->ftable[sd-1] |= REP_ALL;
+
+                                       TRACE(("[FIOASYNC] -> enabled\n"));
+                                       if (sb->mtable[sd-1] || (sb->mtable[sd-1] = allocasyncmsg(sb,sd,s)))
+                                       {
+                                               WSAAsyncSelect(s,hWndSelector ? hAmigaWnd : hSockWnd,sb->mtable[sd-1],FD_ACCEPT | FD_CONNECT | FD_OOB | FD_READ | FD_WRITE | FD_CLOSE);
+                                               success = 0;
+                                               break;
+                                       }
+                               }
+                               else write_log(("BSDSOCK: WARNING - FIOASYNC disabling unsupported.\n"));
+
+                               success = -1;
+                               break;
+                       default:
+                               write_log("BSDSOCK: WARNING - Unknown IoctlSocket request: 0x%08lx\n",request);
+                               seterrno(sb,22);        // EINVAL
+               }
+       }
+       
+       return success;
+}
+
+int host_CloseSocket(SB, int sd)
+{
+    unsigned int wMsg;
+    SOCKET s;
+       
+    TRACE(("CloseSocket(%d) -> ",sd));
+       sd++;
+
+    s = getsock(sb,sd);
+    if (s != INVALID_SOCKET)
+    {
+       if (sb->mtable[sd-1])
+       {
+           asyncsb[(sb->mtable[sd-1]-0xb000)/2] = NULL;
+           sb->mtable[sd-1] = 0;
+       }
+
+       if (checksd(sb ,sd) == TRUE)
+               return 0;
+
+
+
+       BEGINBLOCKING;
+
+       for (;;)
+       {
+            shutdown(s,1);
+           if (!closesocket(s))
+           {
+               releasesock(sb,sd);
+               TRACE(("OK\n"));
+               return 0;
+           }
+
+           SETERRNO;
+
+           if (sb->sb_errno != WSAEWOULDBLOCK-WSABASEERR || !(sb->ftable[sd-1] & SF_BLOCKING)) break;
+
+           if ((wMsg = allocasyncmsg(sb,sd,s)) != 0)
+           {
+               WSAAsyncSelect(s,hWndSelector ? hAmigaWnd : hSockWnd,wMsg,FD_CLOSE);
+
+       
+               WAITSIGNAL;
+               
+
+               cancelasyncmsg(wMsg);
+       
+               if (sb->eintr)
+               {
+                   TRACE(("[interrupted]\n"));
+                   break;
+               }
+           }
+           else break;
+       }
+
+        ENDBLOCKING;
+    }
+       
+    TRACE(("failed (%d)\n",sb->sb_errno));
+  
+    return -1;
+}
+
+// For the sake of efficiency, we do not malloc() the fd_sets here.
+// 64 sockets should be enough for everyone.
+static void makesocktable(SB, uae_u32 fd_set_amiga, struct fd_set *fd_set_win, int nfds, SOCKET addthis)
+{
+       int i, j;
+       uae_u32 currlong, mask;
+       SOCKET s;
+
+       if (addthis != INVALID_SOCKET)
+       {
+               *fd_set_win->fd_array = addthis;
+               fd_set_win->fd_count = 1;
+       }
+       else fd_set_win->fd_count = 0;
+
+       if (!fd_set_amiga)
+       {
+               fd_set_win->fd_array[fd_set_win->fd_count] = INVALID_SOCKET;
+               return;
+       }
+
+       if (nfds > sb->dtablesize)
+       {
+               write_log("BSDSOCK: ERROR - select()ing more sockets (%d) than socket descriptors available (%d)!\n",nfds,sb->dtablesize);
+               nfds = sb->dtablesize;
+       }
+
+       for (j = 0; ; j += 32, fd_set_amiga += 4)
+       {
+               currlong = get_long(fd_set_amiga);
+
+               mask = 1;
+               
+               for (i = 0; i < 32; i++, mask <<= 1)
+               {
+                       if (i+j > nfds)
+                       {
+                               fd_set_win->fd_array[fd_set_win->fd_count] = INVALID_SOCKET;
+                               return;
+                       }
+                       
+                       if (currlong & mask)
+                       {
+                               s = getsock(sb,j+i+1);
+                               
+                               if (s != INVALID_SOCKET)
+                               {
+                                       fd_set_win->fd_array[fd_set_win->fd_count++] = s;
+
+                                       if (fd_set_win->fd_count >= FD_SETSIZE)
+                                       {
+                                               write_log("BSDSOCK: ERROR - select()ing more sockets (%d) than the hard-coded fd_set limit (%d) - please report\n",nfds,FD_SETSIZE);
+                                               return;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       fd_set_win->fd_array[fd_set_win->fd_count] = INVALID_SOCKET;
+}
+
+static void makesockbitfield(SB, uae_u32 fd_set_amiga, struct fd_set *fd_set_win, int nfds)
+{
+       int n, i, j, val, mask;
+       SOCKET currsock;
+
+       for (n = 0; n < nfds; n += 32)
+       {
+               val = 0;
+               mask = 1;
+               
+               for (i = 0; i < 32; i++, mask <<= 1)
+               {
+                       if ((currsock = sb->dtable[n+i]) != INVALID_SOCKET)
+                       {
+                               for (j = fd_set_win->fd_count; j--; )
+                               {
+                                       if (fd_set_win->fd_array[j] == currsock)
+                                       {
+                                               val |= mask;
+                                               break;
+                                       }
+                               }
+                       }
+               }
+               put_long(fd_set_amiga,val);
+               fd_set_amiga += 4;
+       }
+}
+
+static void fd_zero(uae_u32 fdset, uae_u32 nfds)
+{
+       unsigned int i;
+       
+       for (i = 0; i < nfds; i += 32, fdset += 4) put_long(fdset,0);
+}
+
+// This seems to be the only way of implementing a cancelable WinSock2 select() call... sigh.
+static unsigned int __stdcall thread_WaitSelect(void *index2)
+{
+    uae_u32 index = (uae_u32)index2;
+    unsigned int result = 0;
+    long nfds;
+    uae_u32 readfds, writefds, exceptfds;
+    uae_u32 timeout;
+    struct fd_set readsocks, writesocks, exceptsocks;
+    struct timeval tv;
+    uae_u32 *args;
+
+    SB;
+
+    for (;;)
+    {
+           WaitForSingleObject(hEvents[index],INFINITE);
+
+           if ((args = threadargs[index]) != NULL)
+           {
+                   sb = (struct socketbase *)*args;
+                   nfds = args[1];
+                   readfds = args[2];
+                   writefds = args[3];
+                   exceptfds = args[4];
+                   timeout = args[5];
+           
+                   // construct descriptor tables
+                   makesocktable(sb,readfds,&readsocks,nfds,sb->sockAbort);
+                   if (writefds) makesocktable(sb,writefds,&writesocks,nfds,INVALID_SOCKET);
+                   if (exceptfds) makesocktable(sb,exceptfds,&exceptsocks,nfds,INVALID_SOCKET);
+           
+                   if (timeout)
+                   {
+                           tv.tv_sec = get_long(timeout);
+                           tv.tv_usec = get_long(timeout+4);
+                           TRACE(("(timeout: %d.%06d) ",tv.tv_sec,tv.tv_usec));
+                   }
+           
+                   TRACE(("-> "));
+           
+                   sb->resultval = select(nfds+1,&readsocks,writefds ? &writesocks : NULL,exceptfds ? &exceptsocks : NULL,timeout ? &tv : 0);
+                       if (sb->resultval == SOCKET_ERROR)
+                   { 
+                       // select was stopped by sb->sockAbort
+                       if (readsocks.fd_count > 1)
+                               {
+                               makesocktable(sb,readfds,&readsocks,nfds,INVALID_SOCKET);
+                               tv.tv_sec = 0;
+                               tv.tv_usec = 10000;
+                               // Check for 10ms if data is available
+                               sb->resultval = select(nfds+1,&readsocks,writefds ? &writesocks : NULL,exceptfds ? &exceptsocks : NULL,&tv);
+                               if (sb->resultval == 0)
+                                       { // Now timeout -> really no data available
+                                       if (GetLastError() != 0)
+                                               {
+                                               sb->resultval = SOCKET_ERROR;
+                                               // Set old resultval
+                                               }
+                                       }   
+                               }
+                   }
+                       if (FD_ISSET(sb->sockAbort,&readsocks))
+                               {
+                               if (sb->resultval != SOCKET_ERROR)
+                                       {
+                                       sb->resultval--;
+                                       }
+                               }
+                       else
+                               {
+                       sb->needAbort = 0;
+                               }
+
+                   if (sb->resultval == SOCKET_ERROR)
+                   {
+                           SETERRNO;
+                           TRACE(("failed (%d) - ",sb->sb_errno));
+                           if (readfds) fd_zero(readfds,nfds);
+                           if (writefds) fd_zero(writefds,nfds);
+                           if (exceptfds) fd_zero(exceptfds,nfds);
+                   }
+                   else
+                   {
+                           if (readfds) makesockbitfield(sb,readfds,&readsocks,nfds);
+                           if (writefds) makesockbitfield(sb,writefds,&writesocks,nfds);
+                           if (exceptfds) makesockbitfield(sb,exceptfds,&exceptsocks,nfds);
+                   }
+           
+                   SETSIGNAL;
+
+                   threadargs[index] = NULL;
+                   SetEvent(sb->hEvent);
+           }
+    }
+#ifndef __GNUC__
+    _endthreadex( result );
+#endif
+    return result;
+}
+
+void host_WaitSelect(SB, uae_u32 nfds, uae_u32 readfds, uae_u32 writefds, uae_u32 exceptfds, uae_u32 timeout, uae_u32 sigmp)
+{
+       uae_u32 sigs, wssigs;
+       int i;
+
+       wssigs = sigmp ? get_long(sigmp) : 0;
+
+       TRACE(("WaitSelect(%d,0x%lx,0x%lx,0x%lx,0x%lx,0x%lx) ",nfds,readfds,writefds,exceptfds,timeout,wssigs));
+
+       if (!readfds && !writefds && !exceptfds && !timeout && !wssigs)
+       {
+               sb->resultval = 0;
+               TRACE(("-> [ignored]\n"));
+               return;
+       }
+       if (wssigs)
+       {
+               m68k_dreg(regs,0) = 0;
+               m68k_dreg(regs,1) = wssigs;
+               sigs = CallLib(get_long(4),-0x132) & wssigs;    // SetSignal()
+               
+               if (sigs)
+               {
+                       TRACE(("-> [preempted by signals 0x%08lx]\n",sigs & wssigs));
+                       put_long(sigmp,sigs & wssigs);
+                       // Check for zero address -> otherwise WinUAE crashes
+                       if (readfds) fd_zero(readfds,nfds);
+                       if (writefds) fd_zero(writefds,nfds);
+                       if (exceptfds) fd_zero(exceptfds,nfds);
+                       sb->resultval = 0;
+                       seterrno(sb,0);
+                       return;
+               }
+       }
+       if (nfds == 0)
+               { // No sockets to check, only wait for signals
+               m68k_dreg(regs,0) = wssigs;
+               sigs = CallLib(get_long(4),-0x13e);     // Wait()
+
+               put_long(sigmp,sigs & wssigs);
+
+               if (readfds) fd_zero(readfds,nfds);
+               if (writefds) fd_zero(writefds,nfds);
+               if (exceptfds) fd_zero(exceptfds,nfds);
+               sb->resultval = 0;
+               return;
+               }
+
+       ResetEvent(sb->hEvent);
+
+       sb->needAbort = 1;
+
+       for (i = 0; i < MAX_SELECT_THREADS; i++) if (hThreads[i] && !threadargs[i]) break;
+
+       if (i >= MAX_SELECT_THREADS)
+       {
+           for (i = 0; i < MAX_SELECT_THREADS; i++)
+           {
+               if (!hThreads[i])
+               {
+                   if ((hEvents[i] = CreateEvent(NULL,FALSE,FALSE,NULL)) == NULL || (hThreads[i] = (void *)THREAD(thread_WaitSelect,i)) == NULL)
+                   {
+                       hThreads[i] = 0;
+                       write_log("BSDSOCK: ERROR - Thread/Event creation failed - error code: %d\n",GetLastError());
+                       seterrno(sb,12);        // ENOMEM
+                       sb->resultval = -1;
+                       return;
+                   }
+                   
+                   // this should improve responsiveness
+                   SetThreadPriority(hThreads[i],THREAD_PRIORITY_TIME_CRITICAL);
+                   break;
+               }
+           }
+       }
+       
+       if (i >= MAX_SELECT_THREADS) write_log("BSDSOCK: ERROR - Too many select()s\n");
+       else
+       {
+               SOCKET newsock = INVALID_SOCKET;
+
+               threadargs[i] = (uae_u32 *)&sb;
+
+               SetEvent(hEvents[i]);
+
+               m68k_dreg(regs,0) = (((uae_u32)1)<<sb->signal)|sb->eintrsigs|wssigs;
+               sigs = CallLib(get_long(4),-0x13e);     // Wait()
+/*
+               if ((1<<sb->signal) & sigs)
+               { // 2.3.2002/SR Fix for AmiFTP -> Thread is ready, no need to Abort
+                   sb->needAbort = 0;
+               }
+*/
+               if (sb->needAbort)
+               {
+                       if ((newsock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == INVALID_SOCKET)
+                               write_log("BSDSOCK: ERROR - Cannot create socket: %d\n",WSAGetLastError());
+                        shutdown(sb->sockAbort,1);
+                       if (newsock != sb->sockAbort)
+                               {
+                               shutdown(sb->sockAbort,1);
+                               closesocket(sb->sockAbort);
+                               }
+               }
+
+               WaitForSingleObject(sb->hEvent,INFINITE);
+
+               CANCELSIGNAL;
+
+               if (newsock != INVALID_SOCKET) sb->sockAbort = newsock;
+
+        if( sigmp )
+        {
+                   put_long(sigmp,sigs & wssigs);
+
+                   if (sigs & sb->eintrsigs)
+                   {
+                           TRACE(("[interrupted]\n"));
+                           sb->resultval = -1;
+                           seterrno(sb,4);     // EINTR
+                   }
+                   else if (sigs & wssigs)
+                   {
+                           TRACE(("[interrupted by signals 0x%08lx]\n",sigs & wssigs));
+                               if (readfds) fd_zero(readfds,nfds);
+                               if (writefds) fd_zero(writefds,nfds);
+                               if (exceptfds) fd_zero(exceptfds,nfds);
+                           seterrno(sb,0);
+                           sb->resultval = 0;
+                   }
+               if (sb->resultval >= 0)
+                       {
+                       TRACE(("%d\n",sb->resultval));
+                       }
+               else
+                       {
+                       TRACE(("%d errno %d\n",sb->resultval,sb->sb_errno));
+                       }
+               
+        }
+               else TRACE(("%d\n",sb->resultval));
+       }
+}
+
+uae_u32 host_Inet_NtoA(SB, uae_u32 in)
+{
+       char *addr;
+       struct in_addr ina;
+       uae_u32 scratchbuf;
+
+       *(uae_u32 *)&ina = htonl(in);
+
+       TRACE(("Inet_NtoA(%lx) -> ",in));
+
+       if ((addr = inet_ntoa(ina)) != NULL)
+       {
+               scratchbuf = m68k_areg(regs,6)+offsetof(struct UAEBSDBase,scratchbuf);
+               strncpyha(scratchbuf,addr,SCRATCHBUFSIZE);
+               TRACE(("%s\n",addr));
+               return scratchbuf;
+       }
+       else SETERRNO;
+
+       TRACE(("failed (%d)\n",sb->sb_errno));
+
+       return 0;
+}
+
+uae_u32 host_inet_addr(uae_u32 cp)
+{
+       uae_u32 addr;
+       char *cp_rp;
+
+       cp_rp = get_real_address(cp);
+
+       addr = htonl(inet_addr(cp_rp));
+
+       TRACE(("inet_addr(%s) -> 0x%08lx\n",cp_rp,addr));
+
+       return addr;
+}
+
+
+static unsigned int __stdcall thread_get(void *index2)
+{
+    uae_u32 index = (uae_u32)index2;
+    unsigned int result = 0;
+    uae_u32 *args;
+       uae_u32 name;
+       uae_u32 namelen;
+       long addrtype;
+       char *name_rp;
+       char *buf;
+       
+       
+       SB;
+
+    for (;;)
+    {
+           WaitForSingleObject(hGetEvents[index],INFINITE);
+
+           if ((args = threadGetargs[index]) != NULL)
+           {
+
+                       sb = (struct socketbase *)*args;
+                       if (args[1] == 0)
+                               { // gethostbyname or gethostbyaddr
+                               struct hostent *host;
+                               
+                               name = args[2];
+                               namelen = args[3];
+                               addrtype = args[4];
+                               buf = (char*) args[5];
+                               name_rp = get_real_address(name);
+                               
+                               if (addrtype == -1)
+                                       {
+                                       host = gethostbyname(name_rp);
+                                       }
+                               else
+                                       {
+                                       host = gethostbyaddr(name_rp,namelen,addrtype);
+                                       }
+                               if (threadGetargs[index] != -1)
+                                       { // No CTRL-C Signal
+                                       if (host == 0)
+                                               {
+                                               // Error occured 
+                                               SETERRNO;
+                                               TRACE(("failed (%d) - ",sb->sb_errno));
+                                               }
+                                       else
+                                               {
+                                               seterrno(sb,0);
+                                               memcpy(buf,host,sizeof(HOSTENT));
+                                               }
+                                       }
+                               }
+                       if (args[1] == 1)
+                               { // getprotobyname
+                               struct protoent  *proto;
+
+                               name = args[2];
+                               buf = (char*) args[5];
+                               name_rp = get_real_address(name);
+                               proto = getprotobyname (name_rp);
+                               if (threadGetargs[index] != -1)
+                                       { // No CTRL-C Signal
+                                       if (proto == 0)
+                                               {
+                                               // Error occured 
+                                               SETERRNO;
+                                               TRACE(("failed (%d) - ",sb->sb_errno));
+                                               }
+                                       else
+                                               {
+                                               seterrno(sb,0);
+                                               memcpy(buf,proto,sizeof(struct protoent));
+                                               }
+                                       }
+                               }
+                       if (args[1] == 2)
+                               { // getservbyport and getservbyname
+                               uae_u32 nameport;
+                               uae_u32 proto;
+                               uae_u32 type;
+                               char *proto_rp = 0;
+                               struct servent *serv;
+
+                               nameport = args[2];
+                               proto = args[3];
+                               type = args[4];
+                               buf = (char*) args[5];
+       
+                               if (proto) proto_rp = get_real_address(proto);
+
+                               if (type)
+                                       {
+                                       serv = getservbyport(nameport,proto_rp);
+                                       }
+                               else
+                                       {
+                                       name_rp = get_real_address(nameport);
+                                       serv = getservbyname(name_rp,proto_rp);
+                                       }
+                               if (threadGetargs[index] != -1)
+                                       { // No CTRL-C Signal
+                                       if (serv == 0)
+                                               {
+                                               // Error occured 
+                                               SETERRNO;
+                                               TRACE(("failed (%d) - ",sb->sb_errno));
+                                               }
+                                       else
+                                               {
+                                               seterrno(sb,0);
+                                               memcpy(buf,serv,sizeof(struct servent));
+                                               }
+                                       }
+                               }
+
+
+
+
+                   TRACE(("-> "));
+           
+                       if (threadGetargs[index] != -1)
+                               SETSIGNAL;
+
+                   threadGetargs[index] = NULL;
+
+                       }
+    }
+#ifndef __GNUC__
+    _endthreadex( result );
+#endif
+    return result;
+}
+
+void host_gethostbynameaddr(SB, uae_u32 name, uae_u32 namelen, long addrtype)
+{
+       HOSTENT *h;
+       int size, numaliases = 0, numaddr = 0;
+       uae_u32 aptr;
+       char *name_rp;
+       int i;
+
+       uae_u32 args[6];
+
+       uae_u32 addr;
+       uae_u32 *addr_list[2];
+
+       char buf[MAXGETHOSTSTRUCT];
+       unsigned int wMsg = 0;
+
+       char on = 1;
+       InternetSetOption(0,INTERNET_OPTION_SETTINGS_CHANGED,&on,strlen(&on));
+
+       name_rp = get_real_address(name);
+
+
+       if (addrtype == -1)
+       {
+               TRACE(("gethostbyname(%s) -> ",name_rp));
+               
+               // workaround for numeric host "names"
+               if ((addr = inet_addr(name_rp)) != INADDR_NONE)
+               {
+                       seterrno(sb,0);
+                       ((HOSTENT *)buf)->h_name = name_rp;
+                       ((HOSTENT *)buf)->h_aliases = NULL;
+                       ((HOSTENT *)buf)->h_addrtype = AF_INET;
+                       ((HOSTENT *)buf)->h_length = 4;
+                       ((HOSTENT *)buf)->h_addr_list = (char **)&addr_list;
+                       addr_list[0] = &addr;
+                       addr_list[1] = NULL;
+       
+                       goto kludge;
+               }
+       }
+       else
+       {
+               TRACE(("gethostbyaddr(0x%lx,0x%lx,%ld) -> ",name,namelen,addrtype));
+       }
+
+       args[0] = (uae_u32) sb;
+       args[1] = 0;
+       args[2] = name;
+       args[3] = namelen;
+       args[4] = addrtype;
+       args[5] = (uae_u32) &buf[0];
+
+       for (i = 0; i < MAX_GET_THREADS; i++) if (hGetThreads[i] && !threadGetargs[i]) break;
+
+       if (i >= MAX_GET_THREADS)
+       {
+           for (i = 0; i < MAX_GET_THREADS; i++)
+           {
+               if (!hGetThreads[i])
+               {
+                   if ((hGetEvents[i] = CreateEvent(NULL,FALSE,FALSE,NULL)) == NULL || (hGetThreads[i] = (void *)THREAD(thread_get,i)) == NULL)
+                   {
+                       hGetThreads[i] = 0;
+                       write_log("BSDSOCK: ERROR - Thread/Event creation failed - error code: %d\n",GetLastError());
+                       seterrno(sb,12);        // ENOMEM
+                       sb->resultval = -1;
+                       return;
+                   }
+                   break;
+               }
+           }
+       }
+       
+       if (i >= MAX_GET_THREADS) write_log("BSDSOCK: ERROR - Too many gethostbyname()s\n");
+       else
+       {
+               int pri;
+               pri = priorities[currprefs.win32_active_priority].value;
+       
+           SetThreadPriority(hGetThreads[i],pri);
+
+               threadGetargs[i] = (uae_u32 *)&args[0];
+
+               SetEvent(hGetEvents[i]);
+               }
+       sb->eintr = 0;
+       while ( threadGetargs[i] != 0 && sb->eintr == 0) 
+               {       
+               WAITSIGNAL;
+               if (sb->eintr == 1)
+                       threadGetargs[i] = -1;
+               }
+       
+       CANCELSIGNAL;
+       
+       if (!sb->sb_errno)
+       {
+kludge:
+               h = (HOSTENT *)buf;
+               
+               // compute total size of hostent
+               size = 28;
+               if (h->h_name != NULL) size += strlen(h->h_name)+1;
+
+               if (h->h_aliases != NULL)
+                       while (h->h_aliases[numaliases]) size += strlen(h->h_aliases[numaliases++])+5;
+
+               if (h->h_addr_list != NULL)
+               {
+                       while (h->h_addr_list[numaddr]) numaddr++;
+                       size += numaddr*(h->h_length+4);
+               }
+
+               if (sb->hostent)
+               {
+            uae_FreeMem( sb->hostent, sb->hostentsize );
+               }
+
+        sb->hostent = uae_AllocMem( size, 0 );
+
+               if (!sb->hostent)
+               {
+                       write_log("BSDSOCK: WARNING - gethostby%s() ran out of Amiga memory (couldn't allocate %ld bytes) while returning result of lookup for '%s'\n",addrtype == -1 ? "name" : "addr",size,(char *)name);
+                       seterrno(sb,12); // ENOMEM
+                       return;
+               }
+               
+               sb->hostentsize = size;
+               
+               aptr = sb->hostent+28+numaliases*4+numaddr*4;
+       
+               // transfer hostent to Amiga memory
+               put_long(sb->hostent+4,sb->hostent+20);
+               put_long(sb->hostent+8,h->h_addrtype);
+               put_long(sb->hostent+12,h->h_length);
+               put_long(sb->hostent+16,sb->hostent+24+numaliases*4);
+               
+               for (i = 0; i < numaliases; i++) put_long(sb->hostent+20+i*4,addstr(&aptr,h->h_aliases[i]));
+               put_long(sb->hostent+20+numaliases*4,0);
+               for (i = 0; i < numaddr; i++) put_long(sb->hostent+24+(numaliases+i)*4,addmem(&aptr,h->h_addr_list[i],h->h_length));
+               put_long(sb->hostent+24+numaliases*4+numaddr*4,0);
+               put_long(sb->hostent,aptr);
+               addstr(&aptr,h->h_name);
+
+               TRACE(("OK (%s)\n",h->h_name));
+               seterrno(sb,0);
+       }
+       else
+       {
+               TRACE(("failed (%d/%d)\n",sb->sb_errno,sb->sb_herrno));
+       }
+
+}
+
+void host_getprotobyname(SB, uae_u32 name)
+{
+       PROTOENT *p;
+       int size, numaliases = 0;
+       uae_u32 aptr;
+       char *name_rp;
+       int i;
+
+       uae_u32 args[6];
+
+
+       char buf[MAXGETHOSTSTRUCT];
+
+       name_rp = get_real_address(name);
+
+       TRACE(("getprotobyname(%s) -> ",name_rp));
+
+       args[0] = (uae_u32) sb;
+       args[1] = 1;
+       args[2] = name;
+       args[5] = (uae_u32) &buf[0];
+
+       for (i = 0; i < MAX_GET_THREADS; i++) if (hGetThreads[i] && !threadGetargs[i]) break;
+
+       if (i >= MAX_GET_THREADS)
+       {
+           for (i = 0; i < MAX_GET_THREADS; i++)
+           {
+               if (!hGetThreads[i])
+               {
+                   if ((hGetEvents[i] = CreateEvent(NULL,FALSE,FALSE,NULL)) == NULL || (hGetThreads[i] = (void *)THREAD(thread_get,i)) == NULL)
+                   {
+                       hGetThreads[i] = 0;
+                       write_log("BSDSOCK: ERROR - Thread/Event creation failed - error code: %d\n",GetLastError());
+                       seterrno(sb,12);        // ENOMEM
+                       sb->resultval = -1;
+                       return;
+                   }
+                   break;
+               }
+           }
+       }
+       
+       if (i >= MAX_GET_THREADS) write_log("BSDSOCK: ERROR - Too many getprotobyname()s\n");
+       else
+       {
+               int pri;
+               pri = priorities[currprefs.win32_active_priority].value;
+
+           SetThreadPriority(hGetThreads[i],pri);
+
+
+               threadGetargs[i] = (uae_u32 *)&args[0];
+
+               SetEvent(hGetEvents[i]);
+               }
+
+       sb->eintr = 0;
+       while ( threadGetargs[i] != 0 && sb->eintr == 0) 
+               {       
+               WAITSIGNAL;
+               if (sb->eintr == 1)
+                       threadGetargs[i] = -1;
+               }
+
+       CANCELSIGNAL;
+
+
+       if (!sb->sb_errno)
+       {
+               p = (PROTOENT *)buf;
+
+               // compute total size of protoent
+               size = 16;
+               if (p->p_name != NULL) size += strlen(p->p_name)+1;
+
+               if (p->p_aliases != NULL)
+                       while (p->p_aliases[numaliases]) size += strlen(p->p_aliases[numaliases++])+5;
+
+               if (sb->protoent)
+               {
+            uae_FreeMem( sb->protoent, sb->protoentsize );
+               }
+
+               sb->protoent = uae_AllocMem( size, 0 );
+
+               if (!sb->protoent)
+               {
+                       write_log("BSDSOCK: WARNING - getprotobyname() ran out of Amiga memory (couldn't allocate %ld bytes) while returning result of lookup for '%s'\n",size,(char *)name);
+                       seterrno(sb,12); // ENOMEM
+                       return;
+               }
+
+               sb->protoentsize = size;
+               
+               aptr = sb->protoent+16+numaliases*4;
+       
+               // transfer protoent to Amiga memory
+               put_long(sb->protoent+4,sb->protoent+12);
+               put_long(sb->protoent+8,p->p_proto);
+               
+               for (i = 0; i < numaliases; i++) put_long(sb->protoent+12+i*4,addstr(&aptr,p->p_aliases[i]));
+               put_long(sb->protoent+12+numaliases*4,0);
+               put_long(sb->protoent,aptr);
+               addstr(&aptr,p->p_name);
+               TRACE(("OK (%s, %d)\n",p->p_name,p->p_proto));
+               seterrno(sb,0);
+       }
+       else
+       {
+               TRACE(("failed (%d)\n",sb->sb_errno));
+       }
+
+}
+
+
+void host_getservbynameport(SB, uae_u32 nameport, uae_u32 proto, uae_u32 type)
+{
+       SERVENT *s;
+       int size, numaliases = 0;
+       uae_u32 aptr;
+       char *name_rp = NULL, *proto_rp = NULL;
+       int i;
+
+       char buf[MAXGETHOSTSTRUCT];
+       uae_u32 args[6];
+
+       if (proto) proto_rp = get_real_address(proto);
+
+       if (type)
+       {
+               TRACE(("getservbyport(%d,%s) -> ",nameport,proto_rp ? proto_rp : "NULL"));
+       }
+       else
+       {
+               name_rp = get_real_address(nameport);
+               TRACE(("getservbyname(%s,%s) -> ",name_rp,proto_rp ? proto_rp : "NULL"));
+       }
+
+       args[0] = (uae_u32) sb;
+       args[1] = 2;
+       args[2] = nameport;
+       args[3] = proto;
+       args[4] = type;
+       args[5] = (uae_u32) &buf[0];
+
+       for (i = 0; i < MAX_GET_THREADS; i++) if (hGetThreads[i] && !threadGetargs[i]) break;
+
+       if (i >= MAX_GET_THREADS)
+       {
+           for (i = 0; i < MAX_GET_THREADS; i++)
+           {
+               if (!hGetThreads[i])
+               {
+                   if ((hGetEvents[i] = CreateEvent(NULL,FALSE,FALSE,NULL)) == NULL || (hGetThreads[i] = (void *)THREAD(thread_get,i)) == NULL)
+                   {
+                       hGetThreads[i] = 0;
+                       write_log("BSDSOCK: ERROR - Thread/Event creation failed - error code: %d\n",GetLastError());
+                       seterrno(sb,12);        // ENOMEM
+                       sb->resultval = -1;
+                       return;
+                   }
+                   
+                   break;
+               }
+           }
+       }
+       
+       if (i >= MAX_GET_THREADS) write_log("BSDSOCK: ERROR - Too many getprotobyname()s\n");
+       else
+       {
+               int pri;
+               pri = priorities[currprefs.win32_active_priority].value;
+
+           SetThreadPriority(hGetThreads[i],pri);
+
+
+               threadGetargs[i] = (uae_u32 *)&args[0];
+
+               SetEvent(hGetEvents[i]);
+               }
+
+       sb->eintr = 0;
+       while ( threadGetargs[i] != 0 && sb->eintr == 0) 
+               {       
+               WAITSIGNAL;
+               if (sb->eintr == 1)
+                       threadGetargs[i] = -1;
+               }
+
+       CANCELSIGNAL;
+
+       if (!sb->sb_errno)
+       {
+               s = (SERVENT *)buf;
+
+               // compute total size of servent
+               size = 20;
+               if (s->s_name != NULL) size += strlen(s->s_name)+1;
+               if (s->s_proto != NULL) size += strlen(s->s_proto)+1;
+
+               if (s->s_aliases != NULL)
+                       while (s->s_aliases[numaliases]) size += strlen(s->s_aliases[numaliases++])+5;
+
+               if (sb->servent)
+               {
+            uae_FreeMem( sb->servent, sb->serventsize );
+               }
+
+        sb->servent = uae_AllocMem( size, 0 );
+
+               if (!sb->servent)
+               {
+                       write_log("BSDSOCK: WARNING - getservby%s() ran out of Amiga memory (couldn't allocate %ld bytes)\n",type ? "port" : "name",size);
+                       seterrno(sb,12); // ENOMEM
+                       return;
+               }
+
+               sb->serventsize = size;
+               
+               aptr = sb->servent+20+numaliases*4;
+       
+               // transfer servent to Amiga memory
+               put_long(sb->servent+4,sb->servent+16);
+               put_long(sb->servent+8,(unsigned short)htons(s->s_port));
+               
+               for (i = 0; i < numaliases; i++) put_long(sb->servent+16+i*4,addstr(&aptr,s->s_aliases[i]));
+               put_long(sb->servent+16+numaliases*4,0);
+               put_long(sb->servent,aptr);
+               addstr(&aptr,s->s_name);
+               put_long(sb->servent+12,aptr);
+               addstr(&aptr,s->s_proto);
+
+               TRACE(("OK (%s, %d)\n",s->s_name,(unsigned short)htons(s->s_port)));
+               seterrno(sb,0);
+       }
+       else
+       {
+               TRACE(("failed (%d)\n",sb->sb_errno));
+       }
+
+}
+
+
+
+uae_u32 host_gethostname(uae_u32 name, uae_u32 namelen)
+{
+       return gethostname(get_real_address(name),namelen);
+}
+
+#endif
diff --git a/od-win32/build68k_msvc/build68k_msvc.rc b/od-win32/build68k_msvc/build68k_msvc.rc
new file mode 100755 (executable)
index 0000000..3eee795
--- /dev/null
@@ -0,0 +1,61 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE 9, 1
+#pragma code_page(1252)
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE  
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE  
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE  
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/od-win32/build68k_msvc/build68k_msvc.vcproj b/od-win32/build68k_msvc/build68k_msvc.vcproj
new file mode 100755 (executable)
index 0000000..9a00c02
--- /dev/null
@@ -0,0 +1,153 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="7.10"
+       Name="build68k"
+       ProjectGUID="{AF3DBBDE-E006-4DC3-9A26-CB0D7D82AE3C}"
+       SccProjectName=""
+       SccLocalPath="">
+       <Platforms>
+               <Platform
+                       Name="Win32"/>
+       </Platforms>
+       <Configurations>
+               <Configuration
+                       Name="Release|Win32"
+                       OutputDirectory=".\Release"
+                       IntermediateDirectory=".\Release"
+                       ConfigurationType="1"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="FALSE"
+                       CharacterSet="2">
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalOptions=""
+                               InlineFunctionExpansion="1"
+                               AdditionalIncludeDirectories="..\..\include,..\..,..\"
+                               PreprocessorDefinitions="WIN32,NDEBUG,_CONSOLE"
+                               StringPooling="TRUE"
+                               RuntimeLibrary="4"
+                               EnableFunctionLevelLinking="TRUE"
+                               PrecompiledHeaderFile=".\Release/build68k_msvc.pch"
+                               AssemblerListingLocation=".\Release/"
+                               ObjectFile=".\Release/"
+                               ProgramDataBaseFileName=".\Release/"
+                               WarningLevel="3"
+                               SuppressStartupBanner="TRUE"
+                               CompileAs="0"/>
+                       <Tool
+                               Name="VCCustomBuildTool"/>
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalOptions="/MACHINE:I386"
+                               OutputFile="build68k.exe"
+                               LinkIncremental="1"
+                               SuppressStartupBanner="TRUE"
+                               ProgramDatabaseFile=".\Release/build68k.pdb"
+                               SubSystem="1"/>
+                       <Tool
+                               Name="VCMIDLTool"
+                               TypeLibraryName=".\Release/build68k_msvc.tlb"/>
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                               Description="creating cpudefs.c"
+                               CommandLine="build68k.exe &gt;..\..\cpudefs.c &lt;..\..\table68k"/>
+                       <Tool
+                               Name="VCPreBuildEventTool"/>
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                               Description="deleting cpudefs.c"
+                               CommandLine="del ..\..\cpudefs.c"/>
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="NDEBUG"
+                               Culture="1033"/>
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"/>
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"/>
+                       <Tool
+                               Name="VCWebDeploymentTool"/>
+                       <Tool
+                               Name="VCManagedWrapperGeneratorTool"/>
+                       <Tool
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+               </Configuration>
+               <Configuration
+                       Name="Debug|Win32"
+                       OutputDirectory=".\Debug"
+                       IntermediateDirectory=".\Debug"
+                       ConfigurationType="1"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="FALSE"
+                       CharacterSet="2">
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalOptions=""
+                               Optimization="0"
+                               AdditionalIncludeDirectories="..\..\include,..\..,..\"
+                               PreprocessorDefinitions="WIN32,_DEBUG,_CONSOLE,__STDC__"
+                               BasicRuntimeChecks="3"
+                               RuntimeLibrary="5"
+                               PrecompiledHeaderFile=".\Debug/build68k_msvc.pch"
+                               AssemblerListingLocation=".\Debug/"
+                               ObjectFile=".\Debug/"
+                               ProgramDataBaseFileName=".\Debug/"
+                               WarningLevel="3"
+                               SuppressStartupBanner="TRUE"
+                               DebugInformationFormat="4"
+                               CompileAs="0"/>
+                       <Tool
+                               Name="VCCustomBuildTool"/>
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalOptions="/MACHINE:I386"
+                               OutputFile="build68k.exe"
+                               LinkIncremental="2"
+                               SuppressStartupBanner="TRUE"
+                               GenerateDebugInformation="TRUE"
+                               ProgramDatabaseFile=".\Debug/build68k.pdb"
+                               SubSystem="1"/>
+                       <Tool
+                               Name="VCMIDLTool"
+                               TypeLibraryName=".\Debug/build68k_msvc.tlb"/>
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                               Description="creating cpudefs.c"
+                               CommandLine="build68k.exe &gt;..\..\cpudefs.c &lt;..\..\table68k"/>
+                       <Tool
+                               Name="VCPreBuildEventTool"/>
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                               Description="deleting cpudefs.c"
+                               CommandLine="del ..\..\cpudefs.c"/>
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="_DEBUG"
+                               Culture="1033"/>
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"/>
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"/>
+                       <Tool
+                               Name="VCWebDeploymentTool"/>
+                       <Tool
+                               Name="VCManagedWrapperGeneratorTool"/>
+                       <Tool
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="Source Files"
+                       Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
+                       <File
+                               RelativePath="..\..\build68k.c">
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/od-win32/caps/CapsAPI.h b/od-win32/caps/CapsAPI.h
new file mode 100755 (executable)
index 0000000..528a5fe
--- /dev/null
@@ -0,0 +1,118 @@
+#ifndef CAPSAPI_H
+#define CAPSAPI_H
+
+#define CAPS_FILEEXT "ipf"
+#define CAPS_FILEPFX ".ipf"
+
+// Flags provided for locking, in order:
+// 0: re-align data as index synced recording
+// 1: decode track to word aligned size
+// 2: generate cell density for variable density tracks
+// 3: generate density for automatically sized cells
+// 4: generate density for unformatted cells
+// 5: generate unformatted data
+// 6: generate unformatted data, that changes each revolution
+#define DI_LOCK_INDEX    DF_0
+#define DI_LOCK_ALIGN    DF_1
+#define DI_LOCK_DENVAR   DF_2
+#define DI_LOCK_DENAUTO  DF_3
+#define DI_LOCK_DENNOISE DF_4
+#define DI_LOCK_NOISE    DF_5
+#define DI_LOCK_NOISEREV DF_6
+#define DI_LOCK_MEMREF   DF_7
+
+#define CAPS_MAXPLATFORM 4
+#define CAPS_MTRS 5
+
+#pragma pack(push, 1)
+
+// decoded caps date.time
+struct CapsDateTimeExt {
+       UDWORD year;
+       UDWORD month;
+       UDWORD day;
+       UDWORD hour;
+       UDWORD min;
+       UDWORD sec;
+       UDWORD tick;
+};
+
+typedef struct CapsDateTimeExt *PCAPSDATETIMEEXT;
+
+// disk image information block
+struct CapsImageInfo {
+       UDWORD type;        // image type
+       UDWORD release;     // release ID
+       UDWORD revision;    // release revision ID
+       UDWORD mincylinder; // lowest cylinder number
+       UDWORD maxcylinder; // highest cylinder number
+       UDWORD minhead;     // lowest head number
+       UDWORD maxhead;     // highest head number
+       struct CapsDateTimeExt crdt; // image creation date.time
+       UDWORD platform[CAPS_MAXPLATFORM]; // intended platform(s)
+};
+
+typedef struct CapsImageInfo *PCAPSIMAGEINFO;
+
+// disk track information block
+struct CapsTrackInfo {
+       UDWORD type;       // track type
+       UDWORD cylinder;   // cylinder#
+       UDWORD head;       // head#
+       UDWORD sectorcnt;  // available sectors
+       UDWORD sectorsize; // sector size
+       UDWORD trackcnt;   // track variant count
+       PUBYTE trackbuf;   // track buffer memory 
+       UDWORD tracklen;   // track buffer memory length
+       PUBYTE trackdata[CAPS_MTRS]; // track data pointer if available
+       UDWORD tracksize[CAPS_MTRS]; // track data size
+       UDWORD timelen;  // timing buffer length
+       PUDWORD timebuf; // timing buffer
+};
+
+typedef struct CapsTrackInfo *PCAPSTRACKINFO;
+
+#pragma pack(pop)
+
+// image type
+enum {
+       ciitNA=0, // invalid image type
+       ciitFDD   // floppy disk
+};
+
+// platform IDs, not about configuration, but intended use
+enum {
+       ciipNA=0,    // invalid platform (dummy entry)
+       ciipAmiga,   // Amiga
+       ciipAtariST, // Atari ST
+       ciipPC       // PC
+};
+
+// track type
+enum {
+       ctitNA=0,  // invalid type
+       ctitNoise, // cells are unformatted (random size)
+       ctitAuto,  // automatic cell size, according to track size
+       ctitVar    // variable density
+};
+
+// image error status
+enum {
+       imgeOk,
+       imgeUnsupported,
+       imgeGeneric,
+       imgeOutOfRange,
+       imgeReadOnly,
+       imgeOpen,
+       imgeType,
+       imgeShort,
+       imgeTrackHeader,
+       imgeTrackStream,
+       imgeTrackData,
+       imgeDensityHeader,
+       imgeDensityStream,
+       imgeDensityData,
+       imgeIncompatible
+};
+
+#endif
diff --git a/od-win32/caps/CapsLib.h b/od-win32/caps/CapsLib.h
new file mode 100755 (executable)
index 0000000..bd2e4a6
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef CAPSLIB_H
+#define CAPSLIB_H
+
+#undef LIB_USER
+#ifdef CAPS_USER
+#define LIB_USER
+#endif
+#include "comlib.h"
+
+ExtSub SDWORD __cdecl CAPSInit();
+ExtSub SDWORD __cdecl CAPSExit();
+ExtSub SDWORD __cdecl CAPSAddImage();
+ExtSub SDWORD __cdecl CAPSRemImage(SDWORD id);
+ExtSub SDWORD __cdecl CAPSLockImage(SDWORD id, PCHAR name);
+ExtSub SDWORD __cdecl CAPSLockImageMemory(SDWORD id, PUBYTE buffer, UDWORD length, UDWORD flag);
+ExtSub SDWORD __cdecl CAPSUnlockImage(SDWORD id);
+ExtSub SDWORD __cdecl CAPSLoadImage(SDWORD id, UDWORD flag);
+ExtSub SDWORD __cdecl CAPSGetImageInfo(PCAPSIMAGEINFO pi, SDWORD id);
+ExtSub SDWORD __cdecl CAPSLockTrack(PCAPSTRACKINFO pi, SDWORD id, UDWORD cylinder, UDWORD head, UDWORD flag);
+ExtSub SDWORD __cdecl CAPSUnlockTrack(SDWORD id, UDWORD cylinder, UDWORD head);
+ExtSub SDWORD __cdecl CAPSUnlockAllTracks(SDWORD id);
+ExtSub PCHAR  __cdecl CAPSGetPlatformName(UDWORD pid);
+
+#endif
diff --git a/od-win32/caps/Comlib.h b/od-win32/caps/Comlib.h
new file mode 100755 (executable)
index 0000000..4eb091e
--- /dev/null
@@ -0,0 +1,20 @@
+#undef DllSub
+#undef DllVar
+#undef ExtSub
+#undef ExtVar
+
+#ifdef LIB_USER
+
+#define DllSub DllImport
+#define DllVar DllImport
+
+#else
+
+#define DllSub DllExport
+#define DllVar extern DllExport
+
+#endif
+
+#define ExtSub
+#define ExtVar
+
diff --git a/od-win32/caps/Comtype.h b/od-win32/caps/Comtype.h
new file mode 100755 (executable)
index 0000000..56bc025
--- /dev/null
@@ -0,0 +1,121 @@
+#ifndef COMTYPE_H
+#define COMTYPE_H
+
+typedef void *PVOID;
+typedef char *PCHAR;
+
+typedef unsigned char UBYTE;
+typedef unsigned short UWORD;
+typedef unsigned long UDWORD;
+typedef unsigned __int64 UQUAD;
+typedef signed char SBYTE;
+typedef signed short SWORD;
+typedef signed long SDWORD;
+typedef signed __int64 SQUAD;
+
+typedef UBYTE *PUBYTE;
+typedef UWORD *PUWORD;
+typedef UDWORD *PUDWORD;
+typedef UQUAD *PUQUAD;
+typedef SBYTE *PSBYTE;
+typedef SWORD *PSWORD;
+typedef SDWORD *PSDWORD;
+typedef SQUAD *PSQUAD;
+
+#define UCHAR_MIN 0
+#define USHRT_MIN 0
+#define ULONG_MIN 0
+
+#define UBYTE_MIN UCHAR_MIN
+#define UBYTE_MAX UCHAR_MAX
+#define UWORD_MIN USHRT_MIN
+#define UWORD_MAX USHRT_MAX
+#define UDWORD_MIN ULONG_MIN
+#define UDWORD_MAX ULONG_MAX
+#define SBYTE_MIN SCHAR_MIN
+#define SBYTE_MAX SCHAR_MAX
+#define SWORD_MIN SHRT_MIN
+#define SWORD_MAX SHRT_MAX
+#define SDWORD_MIN LONG_MIN
+#define SDWORD_MAX LONG_MAX
+
+enum {
+       DB_0,
+       DB_1,
+       DB_2,
+       DB_3,
+       DB_4,
+       DB_5,
+       DB_6,
+       DB_7,
+       DB_8,
+       DB_9,
+       DB_10,
+       DB_11,
+       DB_12,
+       DB_13,
+       DB_14,
+       DB_15,
+       DB_16,
+       DB_17,
+       DB_18,
+       DB_19,
+       DB_20,
+       DB_21,
+       DB_22,
+       DB_23,
+       DB_24,
+       DB_25,
+       DB_26,
+       DB_27,
+       DB_28,
+       DB_29,
+       DB_30,
+       DB_31
+};
+
+#define DF_0 (1UL<<DB_0)
+#define DF_1 (1UL<<DB_1)
+#define DF_2 (1UL<<DB_2)
+#define DF_3 (1UL<<DB_3)
+#define DF_4 (1UL<<DB_4)
+#define DF_5 (1UL<<DB_5)
+#define DF_6 (1UL<<DB_6)
+#define DF_7 (1UL<<DB_7)
+#define DF_8 (1UL<<DB_8)
+#define DF_9 (1UL<<DB_9)
+#define DF_10 (1UL<<DB_10)
+#define DF_11 (1UL<<DB_11)
+#define DF_12 (1UL<<DB_12)
+#define DF_13 (1UL<<DB_13)
+#define DF_14 (1UL<<DB_14)
+#define DF_15 (1UL<<DB_15)
+#define DF_16 (1UL<<DB_16)
+#define DF_17 (1UL<<DB_17)
+#define DF_18 (1UL<<DB_18)
+#define DF_19 (1UL<<DB_19)
+#define DF_20 (1UL<<DB_20)
+#define DF_21 (1UL<<DB_21)
+#define DF_22 (1UL<<DB_22)
+#define DF_23 (1UL<<DB_23)
+#define DF_24 (1UL<<DB_24)
+#define DF_25 (1UL<<DB_25)
+#define DF_26 (1UL<<DB_26)
+#define DF_27 (1UL<<DB_27)
+#define DF_28 (1UL<<DB_28)
+#define DF_29 (1UL<<DB_29)
+#define DF_30 (1UL<<DB_30)
+#define DF_31 (1UL<<DB_31)
+
+#define DllImport __declspec(dllimport)
+#define DllExport __declspec(dllexport)
+
+#define Naked __declspec(naked)
+
+#ifdef _DEBUG
+ #define NODEFAULT   ASSERT(0)
+#else
+ #define NODEFAULT   __assume(0)
+#endif
+
+#endif
diff --git a/od-win32/caps/caps_win32.c b/od-win32/caps/caps_win32.c
new file mode 100755 (executable)
index 0000000..8b6c81f
--- /dev/null
@@ -0,0 +1,129 @@
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#ifdef CAPS
+
+#include "caps_win32.h"
+#include "zfile.h"
+
+#include "ComType.h"
+#include "CapsAPI.h"
+#include "CapsLib.h"
+
+static SDWORD caps_cont[4]= {-1, -1, -1, -1};
+static int caps_locked[4];
+static int caps_flags = DI_LOCK_DENVAR|DI_LOCK_DENNOISE|DI_LOCK_NOISE;
+
+int caps_init (void)
+{
+    static int init, noticed;
+    int i;
+    HMODULE h;
+
+    if (init) return 1;
+    h = LoadLibrary ("CAPSImg.dll");
+    if (!h) {
+       if (noticed)
+           return 0;
+       gui_message (
+           "This disk image needs the C.A.P.S. plugin\nwhich is available from\nhttp//www.caps-project.org/download.shtml");
+       noticed = 1;
+       return 0;
+    }
+    if (GetProcAddress(h, "CAPSLockImageMemory") == 0) {
+       if (noticed)
+           return 0;
+       gui_message (
+           "You need updated C.A.P.S. plugin\nwhich is available from\nhttp//www.caps-project.org/download.shtml");
+       noticed = 1;
+       return 0;
+    }  
+    FreeLibrary (h);
+    init = 1;
+    for (i = 0; i < 4; i++)
+       caps_cont[i] = CAPSAddImage();
+    return 1;
+}
+
+void caps_unloadimage (int drv)
+{
+    if (!caps_locked[drv])
+       return;
+    CAPSUnlockAllTracks (caps_cont[drv]);
+    CAPSUnlockImage (caps_cont[drv]);
+    caps_locked[drv] = 0;
+}
+
+int caps_loadimage (struct zfile *zf, int drv, int *num_tracks)
+{
+    struct CapsImageInfo ci;
+    int len,ret ;
+    uae_u8 *buf;
+
+    if (!caps_init ())
+       return 0;
+    caps_unloadimage (drv);
+    zfile_fseek (zf, 0, SEEK_END);
+    len = zfile_ftell (zf);
+    zfile_fseek (zf, 0, SEEK_SET);
+    buf = xmalloc (len);
+    if (!buf)
+       return 0;
+    if (zfile_fread (buf, len, 1, zf) == 0)
+       return 0;
+    ret = CAPSLockImageMemory(caps_cont[drv], buf, len, 0);
+    free (buf);
+    if (ret != imgeOk) {
+       free (buf);
+       return 0;
+    }
+    caps_locked[drv] = 1;
+    CAPSGetImageInfo(&ci, caps_cont[drv]);
+    *num_tracks = (ci.maxcylinder - ci.mincylinder + 1) * (ci.maxhead - ci.minhead + 1);
+    CAPSLoadImage(caps_cont[drv], caps_flags);
+    return 1;
+}
+
+int caps_loadtrack (uae_u16 *mfmbuf, uae_u16 **trackpointers, uae_u16 **tracktiming, int drv, int track, int *tracklengths, int *revolutions)
+{
+    struct CapsTrackInfo ci;
+    int i, j, len;
+    uae_u16 *tt, *mfm;
+
+    *tracktiming = 0;
+    CAPSLockTrack(&ci, caps_cont[drv], track / 2, track & 1, caps_flags);
+    mfm = mfmbuf;
+    *revolutions = ci.trackcnt;
+    for (j = 0; j < ci.trackcnt; j++) {
+       len = ci.tracksize[j];
+       trackpointers[j] = mfm;
+       tracklengths[j] = len * 8;
+       for (i = 0; i < (len + 1) / 2; i++) {
+           uae_u8 *data = ci.trackdata[j]+ i * 2;
+           *mfm++ = 256 * *data + *(data + 1);
+       }
+    }
+#if 0
+    {
+       FILE *f=fopen("c:\\1.txt","wb");
+       fwrite (ci.trackdata[0], len, 1, f);
+       fclose (f);
+    }
+#endif
+    if (ci.timelen > 0) {
+       tt = xmalloc (ci.timelen * sizeof (uae_u16));
+       for (i = 0; i < ci.timelen; i++)
+           tt[i] = (uae_u16)ci.timebuf[i];
+       *tracktiming = tt;
+    }
+#if 0
+    write_log ("caps: drive: %d, track: %d, revolutions: %d, timing: %d\n",
+       drv, track, *revolutions, ci.timelen);
+    for (i = 0; i < *revolutions; i++)
+       write_log ("- %d: length: %d bits, %d bytes\n", i, tracklengths[i], tracklengths[i] / 8);
+#endif
+    return 1;
+}
+
+#endif
diff --git a/od-win32/caps/caps_win32.h b/od-win32/caps/caps_win32.h
new file mode 100755 (executable)
index 0000000..7fd0364
--- /dev/null
@@ -0,0 +1,5 @@
+int caps_init (void);
+void caps_unloadimage (int drv);
+int caps_loadimage (struct zfile *zf, int drv, int *num_tracks);
+int caps_loadtrack (uae_u16 *mfmbuf, uae_u16 **trackpointers, uae_u16 **tracktiming, int drv, int track, int *tracklengths, int *revolutions);
+
diff --git a/od-win32/config.h b/od-win32/config.h
new file mode 100755 (executable)
index 0000000..24aab3e
--- /dev/null
@@ -0,0 +1,77 @@
+ /* 
+  * UAE - The Un*x Amiga Emulator
+  * 
+  * User configuration options
+  *
+  * Copyright 1995 - 1998 Bernd Schmidt
+  */
+
+/*
+ * Please note: Many things are configurable with command line parameters,
+ * and you can put anything you can pass on the command line into a 
+ * configuration file ~/.uaerc. Please read the documentation for more
+ * information.
+ * 
+ * NOTE NOTE NOTE
+ * Whenever you change something in this file, you have to "make clean"
+ * afterwards.
+ * Don't remove the '#' signs. If you want to enable something, move it out
+ * of the C comment block, if you want to disable something, move it inside
+ * the block.
+ */
+
+/*
+ * When USE_COMPILER is defined, a m68k->i386 instruction compiler will be
+ * used. This is experimental. It has only been tested on a Linux/i386 ELF
+ * machine, although it might work on other i386 Unices.
+ * This is supposed to speed up application programs. It will not work very
+ * well for hardware bangers like games and demos, in fact it will be much
+ * slower. It can also be slower for some applications and/or benchmarks.
+ * It needs a lot of tuning. Please let me know your results with this.
+ * The second define, RELY_ON_LOADSEG_DETECTION, decides how the compiler 
+ * tries to detect self-modifying code. If it is not set, the first bytes
+ * of every compiled routine are used as checksum before executing the
+ * routine. If it is set, the UAE filesystem will perform some checks to 
+ * detect whether an executable is being loaded. This is less reliable
+ * (it won't work if you don't use the harddisk emulation, so don't try to
+ * use floppies or even the RAM disk), but much faster.
+ *
+ * @@@ NOTE: This option is unfortunately broken in this version. Don't
+ * try to use it. @@@
+ *
+#define USE_COMPILER
+#define RELY_ON_LOADSEG_DETECTION
+ */
+
+/*
+ * Set USER_PROGRAMS_BEHAVE to 1 or 2 to indicate that you are only running
+ * non-hardware banging programs which leave all the dirty work to the
+ * Kickstart. This affects the compiler. Any program that is _not_ in the ROM
+ * (i.e. everything but the Kickstart) will use faster memory access 
+ * functions.
+ * There is of course the problem that the Amiga doesn't really distinguish
+ * between user programs and the kernel. Not all of the OS is in the ROM,
+ * e.g. the parallel.device is on the disk and gets loaded into RAM at least
+ * with Kickstart 1.3 (don't know about newer Kickstarts). So you probably
+ * can't print, and some other stuff may also fail to work.
+ * A useless option, really, given the way lots of Amiga software is written.
+#define USER_PROGRAMS_BEHAVE 0
+ */
+
+/***************************************************************************
+ * Operating system/machine specific options
+ * Configure these for your CPU. The default settings should work on any
+ * machine, but may not give optimal performance everywhere.
+ * (These don't do very much yet, except HAVE_RDTSC
+ */
+
+/*
+ * Define this where unaligned-accesses don't break things, and are "fast enough"
+ */
+#define UNALIGNED_PROFITABLE
+
+/*
+ * PPros don't like branches. With this option, UAE tries to avoid them in some
+ * places.
+ */
+#define BRANCHES_ARE_EXPENSIVE
\ No newline at end of file
diff --git a/od-win32/dinput.c b/od-win32/dinput.c
new file mode 100755 (executable)
index 0000000..7f0cfbb
--- /dev/null
@@ -0,0 +1,1700 @@
+/*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * Win32 DirectInput/Windows XP RAWINPUT interface
+ *
+ * Copyright 2002 - 2004 Toni Wilen
+ */
+
+#define _WIN32_WINNT 0x501 /* make RAWINPUT available */
+
+#define DI_DEBUG
+//#define DI_DEBUG2
+
+#include "config.h"
+#include "sysconfig.h"
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <signal.h>
+
+#include <windows.h>
+#include <dinput.h>
+
+#include "sysdeps.h"
+#include "options.h"
+#include "inputdevice.h"
+#include "keybuf.h"
+#include "xwin.h"
+#include "uae.h"
+#include "catweasel.h"
+#include "keyboard.h"
+#include "custom.h"
+#include "dxwrap.h"
+
+#ifdef WINDDK
+#include <winioctl.h>
+#include <ntddkbd.h>
+#endif
+
+#include "win32.h"
+
+#define MAX_MAPPINGS 256
+
+#define DID_MOUSE 1
+#define DID_JOYSTICK 2
+#define DID_KEYBOARD 3
+
+struct didata {
+    int type;
+    int disabled;
+    int acquired;
+    int priority;
+    int superdevice;
+    GUID guid;
+    char *name;
+    char *sortname;
+
+    LPDIRECTINPUTDEVICE8 lpdi;
+    HANDLE rawinput;
+    int wininput;
+
+    int axles;
+    int buttons;
+    int axismappings[MAX_MAPPINGS];
+    char *axisname[MAX_MAPPINGS];
+    int axissort[MAX_MAPPINGS];
+    int axistype[MAX_MAPPINGS];
+    int buttonmappings[MAX_MAPPINGS];
+    char *buttonname[MAX_MAPPINGS];
+    int buttonsort[MAX_MAPPINGS];
+};
+
+#define DI_BUFFER 30
+
+static struct didata di_mouse[MAX_INPUT_DEVICES];
+static struct didata di_keyboard[MAX_INPUT_DEVICES];
+static struct didata di_joystick[MAX_INPUT_DEVICES];
+static int num_mouse, num_keyboard, num_joystick;
+static int dd_inited, mouse_inited, keyboard_inited, joystick_inited;
+static int stopoutput;
+static HANDLE kbhandle = INVALID_HANDLE_VALUE;
+static int oldleds, oldusedleds, newleds;
+static int normalmouse, supermouse, rawmouse, winmouse, winmousenumber;
+static int normalkb, superkb, rawkb;
+
+int no_rawinput;
+
+int dinput_winmouse (void)
+{
+    if (winmouse)
+       return winmousenumber;
+    return -1;
+}
+
+typedef BOOL (CALLBACK* REGISTERRAWINPUTDEVICES)
+    (PCRAWINPUTDEVICE, UINT, UINT);
+static REGISTERRAWINPUTDEVICES pRegisterRawInputDevices;
+typedef UINT (CALLBACK* GETRAWINPUTDATA)
+    (HRAWINPUT, UINT, LPVOID, PUINT, UINT);
+static GETRAWINPUTDATA pGetRawInputData;
+typedef UINT (CALLBACK* GETRAWINPUTDEVICELIST)
+    (PRAWINPUTDEVICEKUST, PUINT, UINT);
+static GETRAWINPUTDEVICELIST pGetRawInputDeviceList;
+typedef UINT (CALLBACK* GETRAWINPUTDEVICEINFO)
+    (HANDLE, UINT, LPVOID, PUINT);
+static GETRAWINPUTDEVICEINFO pGetRawInputDeviceInfo;
+typedef UINT (CALLBACK* GETRAWINPUTBUFFER)
+    (PRAWINPUT, PUINT, UINT);
+static GETRAWINPUTBUFFER pGetRawInputBuffer;
+typedef LRESULT (CALLBACK* DEFRAWINPUTPROC)
+    (PRAWINPUT*, INT, UINT);
+static DEFRAWINPUTPROC pDefRawInputProc;
+
+static int rawinput_available, rawinput_registered;
+
+static void unregister_rawinput (void)
+{
+}
+
+static int register_rawinput (void)
+{
+    RAWINPUTDEVICE rid[1];
+
+    if (!rawinput_available)
+       return 0;
+    memset (rid, 0, sizeof (rid));
+    /* mouse */
+    rid[0].usUsagePage = 1;
+    rid[0].usUsage = 2;
+    rid[0].dwFlags = 0;
+#if 0
+    /* keyboard */
+    rid[1].usUsagePage = 1;
+    rid[1].usUsage = 6;
+    rid[1].dwFlags = 0;
+#endif
+
+    if (pRegisterRawInputDevices(rid, sizeof (rid) / sizeof (RAWINPUTDEVICE), sizeof (RAWINPUTDEVICE)) == FALSE) {
+       write_log ("RAWINPUT registration failed %d\n", GetLastError ());
+       return 0;
+    }
+    rawinput_registered = 1;
+    return 1;
+}
+
+#define RDP_MOUSE "\\??\\Root#RDP_MOU#"
+
+static int initialize_rawinput (void)
+{
+    RAWINPUTDEVICELIST *ridl = 0;
+    int num = 500, gotnum, i, bufsize, vtmp;
+    int rnum_mouse, rnum_kb, rnum_raw;
+    uae_u8 *buf = 0;
+    int rmouse = 0, rkb = 0;
+    char tmp[100];
+
+    if (no_rawinput)
+       goto error;
+    pRegisterRawInputDevices = (REGISTERRAWINPUTDEVICES)GetProcAddress(
+       GetModuleHandle("user32.dll"), "RegisterRawInputDevices");
+    pGetRawInputData = (GETRAWINPUTDATA)GetProcAddress(
+       GetModuleHandle("user32.dll"), "GetRawInputData");
+    pGetRawInputDeviceList = (GETRAWINPUTDEVICELIST)GetProcAddress(
+       GetModuleHandle("user32.dll"), "GetRawInputDeviceList");
+    pGetRawInputDeviceInfo = (GETRAWINPUTDEVICEINFO)GetProcAddress(
+       GetModuleHandle("user32.dll"), "GetRawInputDeviceInfoA");
+    pGetRawInputBuffer = (GETRAWINPUTBUFFER)GetProcAddress(
+       GetModuleHandle("user32.dll"), "GetRawInputBuffer");
+    pDefRawInputProc = (DEFRAWINPUTPROC)GetProcAddress(
+       GetModuleHandle("user32.dll"), "DefRawInputProc");
+
+    if (!pRegisterRawInputDevices || !pGetRawInputData || !pGetRawInputDeviceList ||
+       !pGetRawInputDeviceInfo || !pGetRawInputBuffer || !pDefRawInputProc)
+       goto error;
+
+    ridl = malloc (sizeof(RAWINPUTDEVICELIST) * num);
+    memset (ridl, 0, sizeof (RAWINPUTDEVICELIST) * num);
+    bufsize = 1000;
+    buf = malloc (bufsize);
+
+    gotnum = pGetRawInputDeviceList(ridl, &num, sizeof (RAWINPUTDEVICELIST));
+    if (gotnum <= 0) {
+       write_log ("RAWINPUT didn't find any devices");
+       goto error;
+    }
+    write_log ("RAWINPUT: found %d devices\n", gotnum);
+    rnum_raw = rnum_mouse = rnum_kb = 0;
+    for (i = 0; i < gotnum; i++) {
+       int type = ridl[i].dwType;
+       HANDLE h = ridl[i].hDevice;
+        vtmp = bufsize;
+        pGetRawInputDeviceInfo (h, RIDI_DEVICENAME, buf, &vtmp);
+
+       if (!memcmp (RDP_MOUSE, buf, strlen (RDP_MOUSE)))
+           continue;
+       if (type == RIM_TYPEMOUSE)
+           rnum_mouse++;
+       if (type == RIM_TYPEKEYBOARD)
+           rnum_kb++;
+    }
+
+    for (i = 0; i < gotnum; i++) {
+       HANDLE h = ridl[i].hDevice;
+       int type = ridl[i].dwType;
+
+       if (/* type == RIM_TYPEKEYBOARD || */ type == RIM_TYPEMOUSE) {
+           struct didata *did = type == RIM_TYPEMOUSE ? di_mouse : di_keyboard;
+           PRID_DEVICE_INFO rdi;
+           int v, j;
+
+           vtmp = bufsize;
+           pGetRawInputDeviceInfo (h, RIDI_DEVICENAME, buf, &vtmp);
+
+           if (did == di_mouse) {
+               if (!memcmp (RDP_MOUSE, buf, strlen (RDP_MOUSE)))
+                   continue;
+               if (rnum_mouse < 2)
+                   continue;
+               if (num_mouse >= MAX_INPUT_DEVICES - 1) /* leave space for Windows mouse */
+                   continue;
+               did += num_mouse;
+               num_mouse++;
+               rmouse++;
+               v = rmouse;
+           } else if (did == di_keyboard) {
+               if (rnum_kb < 2)
+                   continue;
+               if (num_keyboard >= MAX_INPUT_DEVICES)
+                   continue;
+               did += num_keyboard;
+               num_keyboard++;
+               rkb++;
+               v = rkb;
+           }
+
+           rnum_raw++;
+           memset (did, 0, sizeof (*did));
+           for (j = 0; j < MAX_MAPPINGS; j++) {
+               did->axismappings[j] = -1;
+               did->buttonmappings[j] = -1;
+           }
+           sprintf (tmp, "%s", type == RIM_TYPEMOUSE ? "RAW Mouse" : "RAW Keyboard");
+           did->name = my_strdup (tmp);
+           did->rawinput = h;
+
+           write_log ("%p %s: ", h, type == RIM_TYPEMOUSE ? "mouse" : "keyboard");
+           did->sortname = my_strdup (buf);
+           write_log ("'%s'\n", buf);
+           vtmp = bufsize;
+           rdi = (PRID_DEVICE_INFO)buf;
+           rdi->cbSize = sizeof (RID_DEVICE_INFO);
+           pGetRawInputDeviceInfo (h, RIDI_DEVICEINFO, buf, &vtmp);
+           if (type == RIM_TYPEMOUSE) {
+               PRID_DEVICE_INFO_MOUSE rdim = &rdi->mouse;
+               write_log ("id=%d buttons=%d rate=%d", 
+                   rdim->dwId, rdim->dwNumberOfButtons, rdim->dwSampleRate);
+               did->buttons = rdim->dwNumberOfButtons;
+               did->axles = 3;
+               did->axistype[0] = 1;
+               did->axissort[0] = 0;
+               did->axisname[0] = my_strdup ("X-Axis");
+               did->axistype[1] = 1;
+               did->axissort[1] = 1;
+               did->axisname[1] = my_strdup ("Y-Axis");
+               did->axistype[2] = 1;
+               did->axissort[2] = 2;
+               did->axisname[2] = my_strdup ("Wheel");
+               for (j = 0; j < did->buttons; j++) {
+                   did->buttonsort[j] = j;
+                   sprintf (tmp, "Button %d", j + 1);
+                   did->buttonname[j] = my_strdup (tmp);
+               }
+               did->priority = -1;
+           } else {
+               PRID_DEVICE_INFO_KEYBOARD rdik = &rdi->keyboard;
+               write_log ("type=%d sub=%d mode=%d fkeys=%d indicators=%d tkeys=%d",
+                   rdik->dwType, rdik->dwSubType, rdik->dwKeyboardMode,
+                   rdik->dwNumberOfFunctionKeys, rdik->dwNumberOfIndicators, rdik->dwNumberOfKeysTotal);
+           }
+           write_log("\n");
+       }
+    }
+
+    free (ridl);
+    free (buf);
+    if (rnum_raw > 0)
+       rawinput_available = 1;
+    return 1;
+
+    error:
+    write_log ("RAWINPUT not available or failed to initialize\n");
+    free (ridl);
+    free (buf);
+    return 0;
+}
+
+static void initialize_windowsmouse (void)
+{
+    struct didata *did = di_mouse;
+    char tmp[100];
+    int j;
+
+    if (num_mouse >= MAX_INPUT_DEVICES)
+       return;
+    did += num_mouse;
+    num_mouse++;
+    did->name = my_strdup ("Windows mouse");
+    did->sortname = my_strdup ("Windows mouse");
+    did->buttons = 3;
+    did->axles = 3;
+    did->axistype[0] = 1;
+    did->axissort[0] = 0;
+    did->axisname[0] = my_strdup ("X-Axis");
+    did->axistype[1] = 1;
+    did->axissort[1] = 1;
+    did->axisname[1] = my_strdup ("Y-Axis");
+    did->axistype[2] = 1;
+    did->axissort[2] = 2;
+    did->axisname[2] = my_strdup ("Wheel");
+    for (j = 0; j < 3; j++) {
+        did->buttonsort[j] = j;
+        sprintf (tmp, "Button %d", j + 1);
+        did->buttonname[j] = my_strdup (tmp);
+    }
+    did->priority = 2;
+    did->wininput = 1;
+}
+
+static void handle_rawinput_2 (RAWINPUT *raw)
+{
+    int i, num;
+    struct didata *did;
+
+    if (raw->header.dwType == RIM_TYPEMOUSE) {
+       PRAWMOUSE rm = &raw->data.mouse;
+        
+       for (num = 0; num < num_mouse; num++) {
+           did = &di_mouse[num];
+           if (!did->disabled && did->rawinput == raw->header.hDevice)
+               break;
+       }
+#ifdef DI_DEBUG2
+       write_log ("HANDLE=%08.8x %04.4x %04.4x %04.4x %08.8x %3d %3d %08.8x M=%d\n",
+           raw->header.hDevice,
+           rm->usFlags, 
+           rm->usButtonFlags, 
+           rm->usButtonData, 
+           rm->ulRawButtons, 
+           rm->lLastX, 
+           rm->lLastY, 
+           rm->ulExtraInformation, num < num_mouse ? num + 1 : -1);
+#endif
+       if (num == num_mouse) {
+           return;
+       }
+
+       if (focus) {
+           if (mouseactive || isfullscreen ()) {
+               for (i = 0; i < (5 > did->buttons ? did->buttons : 5); i++) {
+                   if (rm->usButtonFlags & (3 << (i * 2)))
+                       setmousebuttonstate (num, i, (rm->usButtonFlags & (1 << (i * 2))) ? 1 : 0);
+               }
+               if (did->buttons > 5) {
+                   for (i = 5; i < did->buttons; i++)
+                       setmousebuttonstate (num, i, (rm->ulRawButtons & (1 << i)) ? 1 : 0);
+               }
+               if (did->buttons >= 3 && (rm->usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN)) {
+                   if (currprefs.win32_middle_mouse) {
+                       if (isfullscreen ())
+                           minimizewindow ();
+                       if (mouseactive)
+                           setmouseactive(0);
+                   }
+               }
+           }
+           if (rm->usButtonFlags & RI_MOUSE_WHEEL)
+               setmousestate (num, 2, (int)rm->usButtonData, 0);
+           setmousestate (num, 0, rm->lLastX, (rm->usFlags & MOUSE_MOVE_ABSOLUTE) ? 1 : 0);
+           setmousestate (num, 1, rm->lLastY, (rm->usFlags & MOUSE_MOVE_ABSOLUTE) ? 1 : 0);
+       }
+
+    } else if (raw->header.dwType == RIM_TYPEKEYBOARD) {
+#ifdef DI_DEBUG2
+       write_log ("HANDLE=%x CODE=%x Flags=%x VK=%x MSG=%x EXTRA=%x\n",
+           raw->header.hDevice,
+           raw->data.keyboard.MakeCode,
+           raw->data.keyboard.Flags,
+           raw->data.keyboard.VKey,
+           raw->data.keyboard.Message,
+           raw->data.keyboard.ExtraInformation);
+#endif
+    }
+}
+
+#if 0
+static void read_rawinput (void)
+{
+    RAWINPUT raw;
+    int size, ret;
+
+    for(;;) {
+       size = sizeof (RAWINPUT);
+       ret = pGetRawInputBuffer (&raw, &size, sizeof (RAWINPUTHEADER));
+       if (ret <= 0)
+           return;
+       handle_rawinput_2 (&raw);
+    }
+}
+#endif
+
+void handle_rawinput (DWORD lParam)
+{
+    UINT dwSize;
+    BYTE lpb[1000];
+    RAWINPUT *raw;
+
+    if (!rawinput_available)
+       return;
+    pGetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
+    if (dwSize >= sizeof (lpb))
+       return;
+    if (pGetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)) != dwSize )
+       return;
+    raw = (RAWINPUT*)lpb;
+    handle_rawinput_2 (raw);
+    pDefRawInputProc (&raw, 1, sizeof (RAWINPUTHEADER));
+}
+
+static void unacquire (LPDIRECTINPUTDEVICE8 lpdi, char *txt)
+{
+    if (lpdi) {
+       HRESULT hr = IDirectInputDevice8_Unacquire (lpdi);
+       if (hr != DI_OK && hr != DI_NOEFFECT)
+           write_log ("unacquire %s failed, %s\n", txt, DXError (hr));
+    }
+}
+static int acquire (LPDIRECTINPUTDEVICE8 lpdi, char *txt)
+{
+    HRESULT hr = DI_OK;
+    if (lpdi) {
+       hr = IDirectInputDevice8_Acquire (lpdi);
+       if (hr != DI_OK) {
+           write_log ("acquire %s failed, %s\n", txt, DXError (hr));
+       }
+    }
+    return hr == DI_OK ? 1 : 0;
+}
+
+static int setcoop (LPDIRECTINPUTDEVICE8 lpdi, DWORD mode, char *txt)
+{
+    HRESULT hr = DI_OK;
+    if (lpdi) {
+       hr = IDirectInputDevice8_SetCooperativeLevel (lpdi, hMainWnd, mode);
+       if (hr != DI_OK && hr != E_NOTIMPL)
+           write_log ("setcooperativelevel %s failed, %s\n", txt, DXError (hr));
+    }
+    return hr == DI_OK ? 1 : 0;
+}
+
+static void sortdd (struct didata *dd, int num, int type)
+{
+    int i, j;
+    struct didata ddtmp;
+    for (i = 0; i < num; i++) {
+       dd[i].type = type;
+       for (j = i + 1; j < num; j++) {
+           dd[j].type = type;
+           if (dd[i].priority < dd[j].priority || (dd[i].priority == dd[j].priority && strcmp (dd[i].sortname, dd[j].sortname) > 0)) {
+               memcpy (&ddtmp, &dd[i], sizeof(ddtmp));
+               memcpy (&dd[i], &dd[j], sizeof(ddtmp));
+               memcpy (&dd[j], &ddtmp, sizeof(ddtmp));
+           }
+       }
+    }
+    j = 1;
+    for (i = 0; i < num; i++) {
+       if (dd[i].rawinput) {
+           char *ntmp = dd[i].name;
+           char tmp[200];
+           sprintf (tmp, "%s %d", ntmp, j);
+           dd[i].name = my_strdup (tmp);
+           free (ntmp);
+           j++;
+       }
+    }
+}
+
+static void sortobjects (struct didata *did, int *mappings, int *sort, char **names, int *types, int num)
+{
+    int i, j, tmpi;
+    char *tmpc;
+
+    for (i = 0; i < num; i++) {
+        for (j = i + 1; j < num; j++) {
+           if (sort[i] > sort[j]) {
+               tmpi = mappings[i]; mappings[i] = mappings[j]; mappings[j] = tmpi;
+               tmpi = sort[i]; sort[i] = sort[j]; sort[j] = tmpi;
+               if (types) {
+                   tmpi = types[i]; types[i] = types[j]; types[j] = tmpi;
+               }
+               tmpc = names[i]; names[i] = names[j]; names[j] = tmpc;
+           }
+       }
+    }
+#ifdef DI_DEBUG
+    if (num > 0) {
+       write_log ("%s (GUID=%s):\n", did->name, outGUID (&did->guid));
+       for (i = 0; i < num; i++)
+           write_log ("%d '%s' (%d,%d)\n", mappings[i], names[i], sort[i], types ? types[i] : -1);
+    }
+#endif
+}
+
+static int isg (const GUID *g, const GUID *g2, int *dwofs, int v)
+{
+    if (!memcmp (g, g2, sizeof (GUID))) {
+       *dwofs = v;
+       return 1;
+    }
+    return 0;
+}
+
+static int makesort_joy (const GUID *g, int *dwofs)
+{
+    if (isg (g, &GUID_XAxis, dwofs, DIJOFS_X)) return -99;
+    if (isg (g, &GUID_YAxis, dwofs, DIJOFS_Y)) return -98;
+    if (isg (g, &GUID_ZAxis, dwofs, DIJOFS_Z)) return -97;
+    if (isg (g, &GUID_RxAxis, dwofs, DIJOFS_RX)) return -89;
+    if (isg (g, &GUID_RyAxis, dwofs, DIJOFS_RY)) return -88;
+    if (isg (g, &GUID_RzAxis, dwofs, DIJOFS_RZ)) return -87;
+    if (isg (g, &GUID_Slider, dwofs, DIJOFS_SLIDER(0))) return -79;
+    if (isg (g, &GUID_Slider, dwofs, DIJOFS_SLIDER(1))) return -78;
+    if (isg (g, &GUID_POV, dwofs, DIJOFS_POV(0))) return -69;
+    if (isg (g, &GUID_POV, dwofs, DIJOFS_POV(1))) return -68;
+    if (isg (g, &GUID_POV, dwofs, DIJOFS_POV(2))) return -67;
+    if (isg (g, &GUID_POV, dwofs, DIJOFS_POV(3))) return -66;
+    return *dwofs;
+}
+
+static int makesort_mouse (const GUID *g, int *dwofs)
+{
+    if (isg (g, &GUID_XAxis, dwofs, DIMOFS_X)) return -99;
+    if (isg (g, &GUID_YAxis, dwofs, DIMOFS_Y)) return -98;
+    if (isg (g, &GUID_ZAxis, dwofs, DIMOFS_Z)) return -97;
+    return *dwofs;
+}
+
+static BOOL CALLBACK EnumObjectsCallback (const DIDEVICEOBJECTINSTANCE* pdidoi, VOID *pContext)
+{
+    struct didata *did = pContext;
+    int i = 0;
+    char tmp[100];
+
+    if (pdidoi->dwType & DIDFT_AXIS) {
+       if (did->axles >= MAX_MAPPINGS)
+           return DIENUM_CONTINUE;
+       did->axismappings[did->axles] = pdidoi->dwOfs;
+       did->axisname[did->axles] = my_strdup (pdidoi->tszName);
+       if (did->type == DID_JOYSTICK)
+           did->axissort[did->axles] = makesort_joy (&pdidoi->guidType, &did->axismappings[did->axles]);
+       else if (did->type == DID_MOUSE)
+           did->axissort[did->axles] = makesort_mouse (&pdidoi->guidType, &did->axismappings[did->axles]);
+       did->axles++;
+    }
+    if (pdidoi->dwType & DIDFT_POV) {
+       int numpov = 0;
+       if (did->axles + 1 >= MAX_MAPPINGS)
+           return DIENUM_CONTINUE;
+       for (i = 0; i < did->axles; i++) {
+           if (did->axistype[i]) {
+               numpov++;
+               i++;
+           }
+       }
+       if (did->type == DID_JOYSTICK)
+           did->axissort[did->axles] = makesort_joy (&pdidoi->guidType, &did->axismappings[did->axles]);
+       else if (did->type == DID_MOUSE)
+           did->axissort[did->axles] = makesort_mouse (&pdidoi->guidType, &did->axismappings[did->axles]);
+       for (i = 0; i < 2; i++) {
+           did->axismappings[did->axles + i] = DIJOFS_POV(numpov);
+           sprintf (tmp, "%s (%d)", pdidoi->tszName, i + 1);
+           did->axisname[did->axles + i] = my_strdup (tmp);
+           did->axissort[did->axles + i] = did->axissort[did->axles];
+           did->axistype[did->axles + i] = 1;
+       }
+       did->axles += 2;
+    }
+    if (pdidoi->dwType & DIDFT_BUTTON) {
+       if (did->buttons >= MAX_MAPPINGS)
+           return DIENUM_CONTINUE;
+       did->buttonname[did->buttons] = my_strdup (pdidoi->tszName);
+       if (did->type == DID_JOYSTICK) {
+           did->buttonmappings[did->buttons] = DIJOFS_BUTTON(did->buttons); // pdidoi->dwOfs returns garbage!!
+           did->buttonsort[did->buttons] = makesort_joy (&pdidoi->guidType, &did->buttonmappings[did->buttons]);
+       } else if (did->type == DID_MOUSE) {
+           did->buttonmappings[did->buttons] = FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + did->buttons;
+           did->buttonsort[did->buttons] = makesort_mouse (&pdidoi->guidType, &did->buttonmappings[did->buttons]);
+       } else {
+           did->buttonmappings[did->buttons] = pdidoi->dwOfs;
+       }
+       did->buttons++;
+    }
+    return DIENUM_CONTINUE;
+}
+
+static BOOL CALLBACK di_enumcallback (LPCDIDEVICEINSTANCE lpddi, LPVOID *dd)
+{
+    struct didata *did;
+    int i, len, type;
+    char *typetxt;
+
+    type = lpddi->dwDevType & 0xff;
+    if (type == DI8DEVTYPE_MOUSE || type == DI8DEVTYPE_SCREENPOINTER) {
+       did = di_mouse;
+       typetxt = "Mouse";
+    } else if (type == DI8DEVTYPE_GAMEPAD  || type == DI8DEVTYPE_JOYSTICK ||
+       type == DI8DEVTYPE_FLIGHT || type == DI8DEVTYPE_DRIVING || type == DI8DEVTYPE_1STPERSON) {
+       did = di_joystick;
+       typetxt = "Game controller";
+    } else if (type == DI8DEVTYPE_KEYBOARD) {
+       did = di_keyboard;
+       typetxt = "Keyboard";
+    } else {
+       did = NULL;
+       typetxt = "Unknown";
+    }
+
+#ifdef DI_DEBUG
+    write_log ("GUID=%08.8X-%04.8X-%04.8X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X:\n",
+        lpddi->guidInstance.Data1, lpddi->guidInstance.Data2, lpddi->guidInstance.Data3,
+        lpddi->guidInstance.Data4[0], lpddi->guidInstance.Data4[1], lpddi->guidInstance.Data4[2], lpddi->guidInstance.Data4[3],
+        lpddi->guidInstance.Data4[4], lpddi->guidInstance.Data4[5], lpddi->guidInstance.Data4[6], lpddi->guidInstance.Data4[7]);
+    write_log ("'%s' '%s' %08.8X (%s)\n", lpddi->tszProductName, lpddi->tszInstanceName, lpddi->dwDevType, typetxt);
+#endif
+
+    if (did == di_mouse) {
+       if (num_mouse >= MAX_INPUT_DEVICES)
+           return DIENUM_CONTINUE;
+       did += num_mouse;
+       num_mouse++;
+    } else if (did == di_joystick) {
+       if (num_joystick >= MAX_INPUT_DEVICES)
+           return DIENUM_CONTINUE;
+       did += num_joystick;
+       num_joystick++;
+    } else if (did == di_keyboard) {
+       if (num_keyboard >= MAX_INPUT_DEVICES)
+           return DIENUM_CONTINUE;
+       did += num_keyboard;
+       num_keyboard++;
+    } else
+       return DIENUM_CONTINUE;
+
+    memset (did, 0, sizeof (*did));
+    for (i = 0; i < MAX_MAPPINGS; i++) {
+        did->axismappings[i] = -1;
+        did->buttonmappings[i] = -1;
+    }
+    len = strlen (lpddi->tszInstanceName) + 3 + 1;
+    did->name = malloc (len);
+    strcpy (did->name, lpddi->tszInstanceName);
+    did->guid = lpddi->guidInstance;
+    did->sortname = my_strdup (did->name);
+
+    if (!memcmp (&did->guid, &GUID_SysKeyboard, sizeof (GUID)) || !memcmp (&did->guid, &GUID_SysMouse, sizeof (GUID))) {
+       did->priority = 2;
+       did->superdevice = 1;
+       strcat (did->name, " *");
+    }
+    return DIENUM_CONTINUE;
+}
+
+extern HINSTANCE hInst;
+static LPDIRECTINPUT8 g_lpdi;
+
+static int di_do_init (void)
+{
+    HRESULT hr; 
+
+    num_mouse = num_joystick = num_keyboard = 0;
+    hr = DirectInput8Create (hInst, DIRECTINPUT_VERSION, &IID_IDirectInput8A, (LPVOID *)&g_lpdi, NULL); 
+    if (FAILED(hr)) {
+       write_log ("DirectInput8Create failed, %s\n", DXError (hr));
+       return 0;
+    }
+    memset (&di_mouse, 0, sizeof (di_mouse));
+    memset (&di_joystick, 0, sizeof (di_joystick));
+    memset (&di_keyboard, 0, sizeof (di_keyboard));
+
+    IDirectInput8_EnumDevices (g_lpdi, DI8DEVCLASS_ALL, di_enumcallback, 0, DIEDFL_ATTACHEDONLY);
+    initialize_rawinput ();
+    initialize_windowsmouse ();
+
+    sortdd (di_joystick, num_joystick, DID_JOYSTICK);
+    sortdd (di_mouse, num_mouse, DID_MOUSE);
+    sortdd (di_keyboard, num_keyboard, DID_KEYBOARD);
+
+    return 1;
+}
+
+static void di_dev_free (struct didata *did)
+{
+    free (did->name);
+    free (did->sortname);
+    memset (did, 0, sizeof (*did));
+}
+
+static int di_init (void)
+{
+    if (dd_inited++ > 0)
+       return 1;
+    if (!di_do_init ())
+       return 0;
+    return 1;
+}
+
+static void di_free (void)
+{
+    if (dd_inited == 0)
+       return;
+    dd_inited--;
+    if (dd_inited > 0)
+       return;
+    IDirectInput8_Release (g_lpdi);
+    g_lpdi = 0;
+    di_dev_free (di_mouse);
+    di_dev_free (di_joystick);
+    di_dev_free (di_keyboard);
+}
+
+static int get_mouse_num (void)
+{
+    return num_mouse;
+}
+
+static char *get_mouse_name (int mouse)
+{
+    return di_mouse[mouse].name;
+}
+
+static int get_mouse_widget_num (int mouse)
+{
+    return di_mouse[mouse].axles + di_mouse[mouse].buttons;
+}
+
+static int get_mouse_widget_first (int mouse, int type)
+{
+    switch (type)
+    {
+       case IDEV_WIDGET_BUTTON:
+       return di_mouse[mouse].axles;
+       case IDEV_WIDGET_AXIS:
+       return 0;
+    }
+    return -1;
+}
+
+static int get_mouse_widget_type (int mouse, int num, char *name, uae_u32 *code)
+{
+    struct didata *did = &di_mouse[mouse];
+
+    int axles = did->axles;
+    int buttons = did->buttons;
+    if (num >= axles && num < axles + buttons) {
+       if (name)
+           strcpy (name, did->buttonname[num - did->axles]);
+       return IDEV_WIDGET_BUTTON;
+    } else if (num < axles) {
+       if (name)
+           strcpy (name, did->axisname[num]);
+       return IDEV_WIDGET_AXIS;
+    }
+    return IDEV_WIDGET_NONE;
+}
+
+static int init_mouse (void)
+{
+    int i;
+    LPDIRECTINPUTDEVICE8 lpdi;
+    HRESULT hr; 
+    struct didata *did;
+
+    if (mouse_inited)
+       return 1;
+    di_init ();
+    mouse_inited = 1;
+    for (i = 0; i < num_mouse; i++) {
+       did = &di_mouse[i];
+       if (!did->disabled && !did->rawinput && !did->wininput) {
+           hr = IDirectInput8_CreateDevice (g_lpdi, &did->guid, &lpdi, NULL);
+           if (hr == DI_OK) {
+               hr = IDirectInputDevice8_SetDataFormat(lpdi, &c_dfDIMouse); 
+               IDirectInputDevice8_EnumObjects (lpdi, EnumObjectsCallback, (void*)did, DIDFT_ALL);
+               sortobjects (did, did->axismappings, did->axissort, did->axisname, did->axistype, did->axles);
+               sortobjects (did, did->buttonmappings, did->buttonsort, did->buttonname, 0, did->buttons);
+               did->lpdi = lpdi;
+           } else {
+               write_log ("mouse %d CreateDevice failed, %s\n", i, DXError (hr));
+           }
+       }
+    }
+    return 1;
+}
+
+static void close_mouse (void)
+{
+    int i;
+
+    if (!mouse_inited)
+       return;
+    mouse_inited = 0;
+    for (i = 0; i < num_mouse; i++) {
+       if (di_mouse[i].lpdi)
+           IDirectInputDevice8_Release (di_mouse[i].lpdi);
+       di_mouse[i].lpdi = 0;
+    }
+    supermouse = normalmouse = rawmouse = winmouse = 0;
+    di_free ();
+}
+
+static int acquire_mouse (int num, int flags)
+{
+    LPDIRECTINPUTDEVICE8 lpdi = di_mouse[num].lpdi;
+    DIPROPDWORD dipdw;
+    HRESULT hr;
+
+    unacquire (lpdi, "mouse");
+    if (lpdi) {
+       setcoop (lpdi, flags ? (DISCL_FOREGROUND | DISCL_EXCLUSIVE) : (DISCL_BACKGROUND | DISCL_NONEXCLUSIVE), "mouse");
+       dipdw.diph.dwSize = sizeof(DIPROPDWORD);
+       dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
+       dipdw.diph.dwObj = 0;
+       dipdw.diph.dwHow = DIPH_DEVICE;
+       dipdw.dwData = DI_BUFFER;
+       hr = IDirectInputDevice8_SetProperty (lpdi, DIPROP_BUFFERSIZE, &dipdw.diph);
+       if (hr != DI_OK)
+           write_log ("mouse setpropertry failed, %s\n", DXError (hr));
+       di_mouse[num].acquired = acquire (lpdi, "mouse") ? 1 : -1;
+    } else {
+       di_mouse[num].acquired = 1;
+    }
+    if (di_mouse[num].acquired) {
+       if (di_mouse[num].rawinput)
+           rawmouse++;
+       else if (di_mouse[num].superdevice)
+           supermouse++;
+       else if (di_mouse[num].wininput) {
+           winmouse++;
+           winmousenumber = num;
+       } else
+           normalmouse++;
+    }
+    if (!supermouse && rawmouse)
+       register_rawinput ();
+    return di_mouse[num].acquired > 0 ? 1 : 0;
+}
+
+static void unacquire_mouse (int num)
+{
+    unacquire (di_mouse[num].lpdi, "mouse");
+    if (di_mouse[num].acquired) {
+       if (di_mouse[num].rawinput)
+           rawmouse--;
+       else if (di_mouse[num].superdevice)
+           supermouse--;
+       else if (di_mouse[num].wininput)
+           winmouse--;
+       else
+           normalmouse--;
+       di_mouse[num].acquired = 0;
+    }
+}
+
+static void read_mouse (void)
+{
+    DIDEVICEOBJECTDATA didod[DI_BUFFER];
+    DWORD elements;
+    HRESULT hr;
+    int i, j, k;
+    int fs = isfullscreen();
+
+    for (i = 0; i < MAX_INPUT_DEVICES; i++) {
+       struct didata *did = &di_mouse[i];
+       LPDIRECTINPUTDEVICE8 lpdi = did->lpdi;
+       if (!lpdi)
+           continue;
+       elements = DI_BUFFER;
+       hr = IDirectInputDevice8_GetDeviceData (lpdi, sizeof (DIDEVICEOBJECTDATA), didod, &elements, 0);
+       if (hr == DI_OK) {
+           if (supermouse && !did->superdevice)
+               continue;
+           for (j = 0; j < elements; j++) {
+               int dimofs = didod[j].dwOfs;
+               int data = didod[j].dwData;
+               int state = (data & 0x80) ? 1 : 0;
+#ifdef DI_DEBUG2
+               write_log ("MOUSE: %d OFF=%d DATA=%d STATE=%d\n", i, dimofs, data, state);
+#endif
+               if (focus) {
+                   if (mouseactive || fs) {
+                       for (k = 0; k < did->axles; k++) {
+                           if (did->axismappings[k] == dimofs) {
+                               setmousestate (i, k, data, 0);
+                               break;
+                           }
+                       }
+                       for (k = 0; k < did->buttons; k++) {
+                           if (did->buttonmappings[k] == dimofs) {
+#ifdef SINGLEFILE
+                               if (k == 0)
+                                   uae_quit ();
+#endif
+                               if ((currprefs.win32_middle_mouse && k != 2) || !(currprefs.win32_middle_mouse)) {
+                                   setmousebuttonstate (i, k, state);
+                                   break;
+                               }
+                           }
+                       }
+                   }
+                   if (i == 0 && dimofs == DIMOFS_BUTTON2 && state) {
+                       if (currprefs.win32_middle_mouse) {
+                           if (isfullscreen ())
+                               minimizewindow ();
+                           if (mouseactive)
+                               setmouseactive(0);
+                       }
+                   }
+               }
+           }
+       } else if (hr == DIERR_INPUTLOST) {
+           acquire (lpdi, "mouse");
+       } else if (did->acquired &&  hr == DIERR_NOTACQUIRED) {
+           acquire (lpdi, "mouse");
+       }
+        IDirectInputDevice8_Poll (lpdi);
+    }
+}
+
+struct inputdevice_functions inputdevicefunc_mouse = {
+    init_mouse, close_mouse, acquire_mouse, unacquire_mouse, read_mouse,
+    get_mouse_num, get_mouse_name,
+    get_mouse_widget_num, get_mouse_widget_type,
+    get_mouse_widget_first
+};
+
+
+static int get_kb_num (void)
+{
+    return num_keyboard;
+}
+
+static char *get_kb_name (int kb)
+{
+    return di_keyboard[kb].name;
+}
+
+static int get_kb_widget_num (int kb)
+{
+    return di_keyboard[kb].buttons;
+}
+
+static int get_kb_widget_first (int kb, int type)
+{
+    return 0;
+}
+
+static int get_kb_widget_type (int kb, int num, char *name, uae_u32 *code)
+{
+    if (name)
+       strcpy (name, di_keyboard[kb].buttonname[num]);
+    if (code)
+       *code = di_keyboard[kb].buttonmappings[num];
+    return IDEV_WIDGET_KEY;
+}
+
+static int keyboard_german;
+
+static BYTE ledkeystate[256];
+
+static uae_u32 get_leds (void)
+{
+    uae_u32 led = 0;
+    if (os_winnt && kbhandle != INVALID_HANDLE_VALUE) {
+#ifdef WINDDK
+       KEYBOARD_INDICATOR_PARAMETERS InputBuffer;
+       KEYBOARD_INDICATOR_PARAMETERS OutputBuffer;
+       ULONG DataLength = sizeof(KEYBOARD_INDICATOR_PARAMETERS);
+       ULONG ReturnedLength;
+
+       memset (&InputBuffer, 0, sizeof (InputBuffer));
+       memset (&OutputBuffer, 0, sizeof (OutputBuffer));
+       if (!DeviceIoControl(kbhandle, IOCTL_KEYBOARD_QUERY_INDICATORS,
+           &InputBuffer, DataLength, &OutputBuffer, DataLength, &ReturnedLength, NULL))
+           return 0;
+       if (OutputBuffer.LedFlags & KEYBOARD_NUM_LOCK_ON) led |= KBLED_NUMLOCK;
+       if (OutputBuffer.LedFlags & KEYBOARD_CAPS_LOCK_ON) led |= KBLED_CAPSLOCK;
+       if (OutputBuffer.LedFlags & KEYBOARD_SCROLL_LOCK_ON) led |= KBLED_SCROLLLOCK;
+#endif
+    } else if (!os_winnt) {
+       GetKeyboardState (ledkeystate);
+       if (ledkeystate[VK_NUMLOCK] & 1) led |= KBLED_NUMLOCK;
+       if (ledkeystate[VK_CAPITAL] & 1) led |= KBLED_CAPSLOCK;
+       if (ledkeystate[VK_SCROLL] & 1) led |= KBLED_SCROLLLOCK;
+    }
+    return led;
+}
+
+static void set_leds (uae_u32 led)
+{
+    if (os_winnt && kbhandle != INVALID_HANDLE_VALUE) {
+#ifdef WINDDK
+       KEYBOARD_INDICATOR_PARAMETERS InputBuffer;
+       ULONG DataLength = sizeof(KEYBOARD_INDICATOR_PARAMETERS);
+       ULONG ReturnedLength;
+
+       memset (&InputBuffer, 0, sizeof (InputBuffer));
+       if (led & KBLED_NUMLOCK) InputBuffer.LedFlags |= KEYBOARD_NUM_LOCK_ON;
+       if (led & KBLED_CAPSLOCK) InputBuffer.LedFlags |= KEYBOARD_CAPS_LOCK_ON;
+       if (led & KBLED_SCROLLLOCK) InputBuffer.LedFlags |= KEYBOARD_SCROLL_LOCK_ON;
+       if (!DeviceIoControl(kbhandle, IOCTL_KEYBOARD_SET_INDICATORS,
+           &InputBuffer, DataLength, NULL, 0, &ReturnedLength, NULL))
+               write_log ("kbleds: DeviceIoControl() failed %d\n", GetLastError());
+#endif
+    } else if (!os_winnt) {
+       ledkeystate[VK_NUMLOCK] &= ~1;
+       if (led & KBLED_NUMLOCK)
+           ledkeystate[VK_NUMLOCK] = 1;
+       ledkeystate[VK_CAPITAL] &= ~1;
+       if (led & KBLED_CAPSLOCK)
+           ledkeystate[VK_CAPITAL] = 1;
+       ledkeystate[VK_SCROLL] &= ~1;
+       if (led & KBLED_SCROLLLOCK)
+           ledkeystate[VK_SCROLL] = 1;
+       SetKeyboardState (ledkeystate);
+     }
+}
+
+static void update_leds (void)
+{
+    if (!currprefs.keyboard_leds_in_use)
+       return;
+    if (newleds != oldusedleds) {
+       oldusedleds = newleds;
+       set_leds (newleds);
+    }
+}
+
+void indicator_leds (int num, int state)
+{
+    int i;
+
+    if (!currprefs.keyboard_leds_in_use)
+       return;
+    for (i = 0; i < 3; i++) {
+       if (currprefs.keyboard_leds[i] == num + 1) {
+           newleds &= ~(1 << i);
+           if (state) newleds |= (1 << i);
+       }
+    }
+}
+
+static int init_kb (void)
+{
+    int i;
+    LPDIRECTINPUTDEVICE8 lpdi;
+    DIPROPDWORD dipdw;
+    HRESULT hr;
+    HKL keyboardlayoutid;
+    WORD keyboardlangid;
+
+    if (keyboard_inited)
+       return 1;
+    di_init ();
+    oldusedleds = -1;
+    keyboard_inited = 1;
+    for (i = 0; i < num_keyboard; i++) {
+        struct didata *did = &di_keyboard[i];
+       if (!did->disabled && !did->rawinput && !did->wininput) {
+           hr = IDirectInput8_CreateDevice (g_lpdi, &did->guid, &lpdi, NULL);
+           if (hr == DI_OK) {
+               hr = IDirectInputDevice8_SetDataFormat(lpdi, &c_dfDIKeyboard); 
+               if (hr != DI_OK)
+                   write_log ("keyboard setdataformat failed, %s\n", DXError (hr));
+               dipdw.diph.dwSize = sizeof(DIPROPDWORD);
+               dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
+               dipdw.diph.dwObj = 0;
+               dipdw.diph.dwHow = DIPH_DEVICE;
+               dipdw.dwData = DI_BUFFER;
+               hr = IDirectInputDevice8_SetProperty (lpdi, DIPROP_BUFFERSIZE, &dipdw.diph);
+               if (hr != DI_OK)
+                   write_log ("keyboard setpropertry failed, %s\n", DXError (hr));
+               IDirectInputDevice8_EnumObjects (lpdi, EnumObjectsCallback, (void*)did, DIDFT_ALL);
+               sortobjects (did, did->axismappings, did->axissort, did->axisname, did->axistype, did->axles);
+               sortobjects (did, did->buttonmappings, did->buttonsort, did->buttonname, 0, did->buttons);
+               did->lpdi = lpdi;
+           } else
+               write_log ("keyboard CreateDevice failed, %s\n", DXError (hr));
+       }
+    }
+    keyboardlayoutid = GetKeyboardLayout(0);      
+    keyboardlangid = LOWORD(keyboardlayoutid);
+    keyboard_german = 0;
+    if (keyboardlangid == MAKELANGID (LANG_GERMAN, SUBLANG_GERMAN))
+       keyboard_german = 1;
+    return 1;
+}
+
+static void close_kb (void)
+{
+    int i;
+
+    if (keyboard_inited == 0)
+       return;
+    keyboard_inited = 0;
+
+    for (i = 0; i < num_keyboard; i++) {
+       if (di_keyboard[i].lpdi)
+           IDirectInputDevice8_Release (di_keyboard[i].lpdi);
+       di_keyboard[i].lpdi = 0;
+    }
+    di_free ();
+}
+
+#define MAX_KEYCODES 256
+static uae_u8 di_keycodes[MAX_INPUT_DEVICES][MAX_KEYCODES];
+static uae_u32 kb_do_refresh;
+
+int ispressed (int key)
+{
+    int i;
+    for (i = 0; i < MAX_INPUT_DEVICES; i++) {
+       if (di_keycodes[i][key])
+           return 1;
+    }
+    return 0;
+}
+
+void release_keys (void)
+{
+    int i, j;
+
+    for (j = 0; j < MAX_INPUT_DEVICES; j++) {
+       for (i = 0; i < MAX_KEYCODES; i++) {
+           if (di_keycodes[j][i]) {
+               my_kbd_handler (j, i, 0);
+               di_keycodes[j][i] = 0;
+           }
+       }
+    }
+}
+
+static int refresh_kb (LPDIRECTINPUTDEVICE8 lpdi, int num)
+{
+    HRESULT hr;
+    int i;
+    uae_u8 kc[256];
+
+    hr = IDirectInputDevice8_GetDeviceState (lpdi, sizeof (kc), kc);
+    if (hr == DI_OK) {
+       for (i = 0; i < sizeof (kc); i++) {
+           if (kc[i] & 0x80) kc[i] = 1; else kc[i] = 0;
+           if (kc[i] != di_keycodes[num][i]) {
+               write_log ("%02.2X -> %d\n", i, kc[i]);
+               di_keycodes[num][i] = kc[i];
+               my_kbd_handler (num, i, kc[i]);
+           }
+       }
+    } else if (hr == DIERR_INPUTLOST) {
+       acquire (lpdi, "keyboard");
+       IDirectInputDevice8_Poll (lpdi);
+       return 0;
+    }
+    IDirectInputDevice8_Poll (lpdi);
+    return 1;
+}
+
+
+static int keyhack (int scancode,int pressed, int num)
+{
+    static byte backslashstate,apostrophstate;
+    
+     //check ALT-F4 
+    if (pressed && !di_keycodes[num][DIK_F4] && scancode == DIK_F4 && di_keycodes[num][DIK_LALT] && !currprefs.win32_ctrl_F11_is_quit) {
+       uae_quit ();
+       return -1;
+    }
+#ifdef SINGLEFILE
+    if (pressed && scancode == DIK_ESCAPE) {
+       uae_quit ();
+       return -1;
+    }
+#endif
+
+    // release mouse if TAB and ALT is pressed 
+    if (pressed && di_keycodes[num][DIK_LALT] && scancode == DIK_TAB) {
+       disablecapture ();
+       return -1;
+    }
+
+    if (!keyboard_german)
+       return scancode;
+ //This code look so ugly because there is no Directinput
+ //key for # (called numbersign on win standard message)
+ //available
+ //so here need to change qulifier state and restore it when key
+ //is release
+    if (!keyboard_german)
+       return scancode;
+    if (scancode == DIK_BACKSLASH) // The # key
+    {
+       if (di_keycodes[num][DIK_LSHIFT] || di_keycodes[num][DIK_RSHIFT] || apostrophstate)
+        {   
+            if (pressed)
+            {   apostrophstate=1;
+                inputdevice_translatekeycode (num, DIK_RSHIFT, 0);
+                inputdevice_translatekeycode (num, DIK_LSHIFT, 0);
+                return 13;           // the german ' key
+            }
+            else
+            {
+                //best is add a real keystatecheck here but it still work so
+                apostrophstate=0;
+                return 13;
+            }
+
+        }
+        if (pressed)
+        {
+            inputdevice_translatekeycode (num, DIK_LALT, 1);
+            inputdevice_translatekeycode (num, DIK_LSHIFT,1);
+            return 4;           // the german # key        
+        }
+            else
+        {
+            inputdevice_translatekeycode (num, DIK_LALT,0);
+            inputdevice_translatekeycode (num, DIK_LSHIFT,0);
+            // Here is the same not nice but do the job
+            return 4;           // the german # key        
+            
+        }    
+    }
+    if ((di_keycodes[num][DIK_RALT]) || (backslashstate)) {
+       switch (scancode)
+       {
+           case 12:
+           if (pressed)
+           {   
+               backslashstate=1;
+               inputdevice_translatekeycode (num, DIK_RALT, 0);
+               return DIK_BACKSLASH;      
+           }
+           else
+           {
+           backslashstate=0;
+           return DIK_BACKSLASH;
+           }
+       }
+    }
+    return scancode;
+}
+
+static void read_kb (void)
+{
+    DIDEVICEOBJECTDATA didod[DI_BUFFER];
+    DWORD elements;
+    HRESULT hr;
+    LPDIRECTINPUTDEVICE8 lpdi;
+    int i, j;
+
+    update_leds ();
+    for (i = 0; i < MAX_INPUT_DEVICES; i++) {
+       struct didata *did = &di_keyboard[i];
+       lpdi = did->lpdi;
+       if (!lpdi)
+           continue;
+       if (kb_do_refresh & (1 << i)) {
+           if (!refresh_kb (lpdi, i))
+               continue;
+           kb_do_refresh &= ~(1 << i);
+       }
+       elements = DI_BUFFER;
+       hr = IDirectInputDevice8_GetDeviceData(lpdi, sizeof(DIDEVICEOBJECTDATA), didod, &elements, 0);
+       if (hr == DI_OK) {
+           if (did->superdevice && (normalkb || rawkb))
+               continue;
+           for (j = 0; j < elements; j++) {
+               int scancode = didod[j].dwOfs;
+               int pressed = (didod[j].dwData & 0x80) ? 1 : 0;
+               scancode = keyhack (scancode, pressed, i);
+               if (scancode < 0)
+                   continue;
+               di_keycodes[i][scancode] = pressed;
+               if (stopoutput == 0)
+                   my_kbd_handler (i, scancode, pressed);
+           }
+        } else if (hr == DIERR_INPUTLOST) {
+           acquire (lpdi, "keyboard");
+           kb_do_refresh |= 1 << i;
+       } else if (did->acquired &&  hr == DIERR_NOTACQUIRED) {
+           acquire (lpdi, "keyboard");
+       }
+       IDirectInputDevice8_Poll (lpdi);
+    }
+#ifdef CATWEASEL
+    {
+       char kc;
+       if (stopoutput == 0 && catweasel_read_keyboard (&kc))
+           inputdevice_do_keyboard (kc & 0x7f, kc & 0x80);
+    }
+#endif
+}
+
+void wait_keyrelease (void)
+{
+    int i, j, maxcount = 200, found;
+    stopoutput++;
+
+    while (maxcount-- > 0) {
+       sleep_millis (10);
+       read_kb ();
+       found = 0;
+       for (j = 0; j < MAX_INPUT_DEVICES; j++) {
+           for (i = 0; i < MAX_KEYCODES; i++) {
+               if (di_keycodes[j][i]) found = 1;
+           }
+       }
+       if (!found)
+           break;
+    }
+    release_keys ();
+
+    for (;;) {
+       int ok = 0, nok = 0;
+       for (i = 0; i < MAX_INPUT_DEVICES; i++) {
+           struct didata *did = &di_mouse[i];
+           DIMOUSESTATE dis;
+           LPDIRECTINPUTDEVICE8 lpdi = did->lpdi;
+           HRESULT hr;
+           int j;
+
+           if (!lpdi)
+               continue;
+           nok++;
+           hr = IDirectInputDevice8_GetDeviceState (lpdi, sizeof (dis), &dis);
+           if (hr == DI_OK) {
+               for (j = 0; j < 4; j++) {
+                   if (dis.rgbButtons[j] & 0x80) break;
+               }
+               if (j == 4) ok++;
+           } else {
+               ok++;
+           }
+       }
+       if (ok == nok) break;
+       sleep_millis (10);
+    }
+    stopoutput--;
+}
+
+static int acquire_kb (int num, int flags)
+{
+    DWORD mode = DISCL_NOWINKEY | DISCL_FOREGROUND | DISCL_EXCLUSIVE;
+    LPDIRECTINPUTDEVICE8 lpdi = di_keyboard[num].lpdi;
+
+    unacquire (lpdi, "keyboard");
+    setcoop (lpdi, mode, "keyboard");
+    kb_do_refresh = ~0;
+
+#ifdef WINDDK
+    if (currprefs.keyboard_leds_in_use) {
+       if (os_winnt) {
+           if (DefineDosDevice (DDD_RAW_TARGET_PATH, "Kbd","\\Device\\KeyboardClass0")) {
+               kbhandle = CreateFile("\\\\.\\Kbd", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
+               if (kbhandle == INVALID_HANDLE_VALUE)
+                   write_log ("kbled: CreateFile failed, error %d\n", GetLastError());
+           } else {
+               write_log ("kbled: DefineDosDevice failed, error %d\n", GetLastError());
+           }
+       }
+       oldleds = get_leds ();
+       if (oldusedleds < 0) 
+           oldusedleds = newleds = oldleds;
+       set_leds (oldusedleds);
+    }
+#endif
+    di_keyboard[num].acquired = -1;
+    if (acquire (lpdi, "keyboard")) {
+       if (di_keyboard[num].superdevice)
+           superkb++;
+       else
+           normalkb++;
+        di_keyboard[num].acquired = 1;
+    }
+    return di_keyboard[num].acquired > 0 ? 1 : 0;
+}
+
+static void unacquire_kb (int num)
+{
+    LPDIRECTINPUTDEVICE8 lpdi = di_keyboard[num].lpdi;
+
+    unacquire (lpdi, "keyboard");
+    if (di_keyboard[num].acquired) {
+       if (di_keyboard[num].superdevice)
+           superkb--;
+       else
+           normalkb--;
+        di_keyboard[num].acquired = 0;
+    }
+    release_keys ();
+
+#ifdef WINDDK
+    if (currprefs.keyboard_leds_in_use && oldusedleds >= 0) {
+       set_leds (oldleds);
+       oldusedleds = oldleds;
+       if (kbhandle != INVALID_HANDLE_VALUE) {
+           CloseHandle(kbhandle);
+           DefineDosDevice (DDD_REMOVE_DEFINITION, "Kbd", NULL);
+           kbhandle = INVALID_HANDLE_VALUE;
+       }
+    }
+#endif
+}
+
+struct inputdevice_functions inputdevicefunc_keyboard = {
+    init_kb, close_kb, acquire_kb, unacquire_kb, read_kb,
+    get_kb_num, get_kb_name,
+    get_kb_widget_num, get_kb_widget_type,
+    get_kb_widget_first
+};
+
+
+static int get_joystick_num (void)
+{
+    return num_joystick;
+}
+
+static int get_joystick_widget_num (int joy)
+{
+    return di_joystick[joy].axles + di_joystick[joy].buttons;
+}
+
+static int get_joystick_widget_type (int joy, int num, char *name, uae_u32 *code)
+{
+    struct didata *did = &di_joystick[joy];
+    if (num >= did->axles && num < did->axles + did->buttons) {
+       if (name)
+           strcpy (name, did->buttonname[num - did->axles]);
+       return IDEV_WIDGET_BUTTON;
+    } else if (num < di_joystick[joy].axles) {
+       if (name)
+           strcpy (name, did->axisname[num]);
+       return IDEV_WIDGET_AXIS;
+    }
+    return IDEV_WIDGET_NONE;
+}
+
+static int get_joystick_widget_first (int joy, int type)
+{
+    switch (type)
+    {
+       case IDEV_WIDGET_BUTTON:
+       return di_joystick[joy].axles;
+       case IDEV_WIDGET_AXIS:
+       return 0;
+    }
+    return -1;
+}
+
+static char *get_joystick_name (int joy)
+{
+    return di_joystick[joy].name;
+}
+
+static int isjoy (int pcport, int amigaport)
+{
+    if (pcport == 0)
+       return JSEM_ISJOY0 (amigaport, &currprefs);
+    else
+       return JSEM_ISJOY1 (amigaport, &currprefs);
+}
+
+static void read_joystick (void)
+{
+    DIDEVICEOBJECTDATA didod[DI_BUFFER];
+    LPDIRECTINPUTDEVICE8 lpdi;
+    DWORD elements;
+    HRESULT hr;
+    int i, j, k;
+
+    for (i = 0; i < MAX_INPUT_DEVICES; i++) {
+       struct didata *did = &di_joystick[i];
+       lpdi = did->lpdi;
+       if (!lpdi)
+           continue;
+       if (currprefs.input_selected_setting == 0) {
+           if (i >= 2)
+               break;
+           if (isjoy (i, 0)) {
+               if (JSEM_ISNUMPAD (0, &currprefs) || JSEM_ISCURSOR (0, &currprefs) || JSEM_ISSOMEWHEREELSE (0, &currprefs))
+                   continue;
+           } else if (isjoy (i, 1)) {
+               if (JSEM_ISNUMPAD (1, &currprefs) || JSEM_ISCURSOR (1, &currprefs) || JSEM_ISSOMEWHEREELSE (1, &currprefs))
+                   continue;
+           } else
+               continue;
+       }
+       elements = DI_BUFFER;
+       hr = IDirectInputDevice8_GetDeviceData (lpdi, sizeof (DIDEVICEOBJECTDATA), didod, &elements, 0);
+       if (hr == DI_OK) {
+           for (j = 0; j < elements; j++) {
+               int dimofs = didod[j].dwOfs;
+               int data = didod[j].dwData;
+               int data2 = data;
+               int state = (data & 0x80) ? 1 : 0;
+               data -= 32768;
+               
+               for (k = 0; k < did->buttons; k++) {
+                   if (did->buttonmappings[k] == dimofs) {
+#ifdef DI_DEBUG2
+                       write_log ("B:NUM=%d OFF=%d NAME=%s VAL=%d STATE=%d\n",
+                           k, dimofs, did->buttonname[k], data, state);
+#endif
+                       setjoybuttonstate (i, k, state);
+                       break;
+                   }
+               }
+               for (k = 0; k < did->axles; k++) {
+                   if (did->axismappings[k] == dimofs) {
+                       if (did->axistype[k]) {
+                           setjoystickstate (i, k, (data2 >= 20250 && data2 <= 33750) ? -1 : (data2 >= 2250 && data2 <= 15750) ? 1 : 0, 1);
+                           setjoystickstate (i, k + 1, ((data2 >= 29250 && data2 <= 33750) || (data2 >= 0 && data2 <= 6750)) ? -1 : (data2 >= 11250 && data2 <= 24750) ? 1 : 0, 1);
+#ifdef DI_DEBUG2
+                           write_log ("P:NUM=%d OFF=%d NAME=%s VAL=%d\n", k, dimofs, did->axisname[k], data2);
+#endif
+                       } else {
+#ifdef DI_DEBUG2
+                           if (data < -20000 || data > 20000)
+                               write_log ("A:NUM=%d OFF=%d NAME=%s VAL=%d\n", k, dimofs, did->axisname[k], data);
+#endif
+                           setjoystickstate (i, k, data, 32768);
+                       }
+                       break;
+                   }
+               }
+           }
+       } else if (hr == DIERR_INPUTLOST) {
+           acquire (lpdi, "joystick");
+       } else if (did->acquired &&  hr == DIERR_NOTACQUIRED) {
+           acquire (lpdi, "joystick");
+       }
+        IDirectInputDevice8_Poll (lpdi);
+    }
+#ifdef CATWEASEL
+    {
+       static uae_u8 odir, obut;
+       uae_u8 dir, dir2, but;
+       if (catweasel_read_joystick (&dir, &but)) {
+           if ((but & 0x80) != (obut & 0x80))
+               handle_input_event (INPUTEVENT_JOY1_FIRE_BUTTON, !(but & 0x80), 1, 0);
+           if ((but & 0x40) != (obut & 0x40))
+               handle_input_event (INPUTEVENT_JOY2_FIRE_BUTTON, !(but & 0x40), 1, 0);
+           dir2 = odir;
+           odir = dir;
+           obut = but;
+           if ((dir & 15) != (dir2 & 15)) {
+               handle_input_event (INPUTEVENT_JOY2_HORIZ, !(dir & 1) ? 1 : !(dir & 2) ? -1 : 0, 1, 0);
+               handle_input_event (INPUTEVENT_JOY2_VERT, !(dir & 4) ? 1 : !(dir & 8) ? -1 : 0, 1, 0);
+           }
+           dir >>= 4;
+           dir2 >>= 4;
+           if ((dir & 15) != (dir2 & 15)) {
+               handle_input_event (INPUTEVENT_JOY1_HORIZ, !(dir & 1) ? 1 : !(dir & 2) ? -1 : 0, 1, 0);
+               handle_input_event (INPUTEVENT_JOY1_VERT, !(dir & 4) ? 1 : !(dir & 8) ? -1 : 0, 1, 0);
+           }
+       }
+    }
+#endif
+}
+
+static int init_joystick (void)
+{
+    int i;
+    LPDIRECTINPUTDEVICE8 lpdi;
+    HRESULT hr;
+    struct didata *did;
+
+    if (joystick_inited)
+       return 1;
+    di_init ();
+    joystick_inited = 1;
+    for (i = 0; i < num_joystick; i++) {
+       did = &di_joystick[i];
+       if (!did->disabled) {
+           hr = IDirectInput8_CreateDevice (g_lpdi, &did->guid, &lpdi, NULL);
+           if (hr == DI_OK) {
+               hr = IDirectInputDevice8_SetDataFormat(lpdi, &c_dfDIJoystick);
+               if (hr == DI_OK) {
+                   did->lpdi = lpdi;
+                   IDirectInputDevice8_EnumObjects (lpdi, EnumObjectsCallback, (void*)did, DIDFT_ALL);
+                   sortobjects (did, did->axismappings, did->axissort, did->axisname, did->axistype, did->axles);
+                   sortobjects (did, did->buttonmappings, did->buttonsort, did->buttonname, 0, did->buttons);
+               }
+           } else
+               write_log ("joystick createdevice failed, %s\n", DXError (hr));
+       }
+    }
+    return 1;
+}
+
+static void close_joystick (void)
+{
+    int i;
+
+    if (!joystick_inited)
+       return;
+    joystick_inited = 0;
+    for (i = 0; i < num_joystick; i++) {
+       if (di_joystick[i].lpdi)
+           IDirectInputDevice8_Release (di_joystick[i].lpdi);
+       di_joystick[i].lpdi = 0;
+    }
+    di_free ();
+}
+
+static int acquire_joystick (int num, int flags)
+{
+    LPDIRECTINPUTDEVICE8 lpdi = di_joystick[num].lpdi;
+    DIPROPDWORD dipdw;
+    HRESULT hr;
+
+    unacquire (lpdi, "joystick");
+    setcoop (lpdi, flags ? (DISCL_FOREGROUND | DISCL_EXCLUSIVE) : (DISCL_BACKGROUND | DISCL_NONEXCLUSIVE), "joystick");
+    memset (&dipdw, 0, sizeof (dipdw));
+    dipdw.diph.dwSize = sizeof(DIPROPDWORD);
+    dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
+    dipdw.diph.dwObj = 0;
+    dipdw.diph.dwHow = DIPH_DEVICE;
+    dipdw.dwData = DI_BUFFER;
+    hr = IDirectInputDevice8_SetProperty (lpdi, DIPROP_BUFFERSIZE, &dipdw.diph);
+    if (hr != DI_OK)
+       write_log ("joystick setproperty failed, %s\n", DXError (hr));
+    di_joystick[num].acquired = acquire (lpdi, "joystick") ? 1 : -1;
+    return di_joystick[num].acquired > 0 ? 1 : 0;
+}
+
+static void unacquire_joystick (int num)
+{
+    unacquire (di_joystick[num].lpdi, "joystick");
+    di_joystick[num].acquired = 0;
+}
+
+struct inputdevice_functions inputdevicefunc_joystick = {
+    init_joystick, close_joystick, acquire_joystick, unacquire_joystick,
+    read_joystick, get_joystick_num, get_joystick_name,
+    get_joystick_widget_num, get_joystick_widget_type,
+    get_joystick_widget_first
+};
+
+int dinput_wmkey (uae_u32 key)
+{
+    if (normalkb || superkb || rawkb)
+       return 0;
+    if (((key >> 16) & 0xff) == 0x58)
+       return 1;
+    return 0;
+}
+
+void input_get_default_mouse (struct uae_input_device *uid)
+{
+    int i, port;
+
+    for (i = 0; i < num_mouse; i++) {
+       port = i & 1;
+       if (di_mouse[i].wininput)
+           port = 0;
+        uid[i].eventid[ID_AXIS_OFFSET + 0][0] = port ? INPUTEVENT_MOUSE2_HORIZ : INPUTEVENT_MOUSE1_HORIZ;
+       uid[i].eventid[ID_AXIS_OFFSET + 1][0] = port ? INPUTEVENT_MOUSE2_VERT : INPUTEVENT_MOUSE1_VERT;
+        uid[i].eventid[ID_AXIS_OFFSET + 2][0] = port ? 0 : INPUTEVENT_MOUSE1_WHEEL;
+       uid[i].eventid[ID_BUTTON_OFFSET + 0][0] = port ? INPUTEVENT_JOY2_FIRE_BUTTON : INPUTEVENT_JOY1_FIRE_BUTTON;
+       uid[i].eventid[ID_BUTTON_OFFSET + 1][0] = port ? INPUTEVENT_JOY2_2ND_BUTTON : INPUTEVENT_JOY1_2ND_BUTTON;
+       uid[i].eventid[ID_BUTTON_OFFSET + 2][0] = port ? INPUTEVENT_JOY2_3RD_BUTTON : INPUTEVENT_JOY1_3RD_BUTTON;
+    }
+    uid[0].enabled = 1;
+}
+
+void input_get_default_joystick (struct uae_input_device *uid)
+{
+    int i, port;
+
+    for (i = 0; i < num_mouse; i++) {
+       port = i & 1;
+        uid[i].eventid[ID_AXIS_OFFSET + 0][0] = port ? INPUTEVENT_JOY2_HORIZ : INPUTEVENT_JOY1_HORIZ;
+       uid[i].eventid[ID_AXIS_OFFSET + 1][0] = port ? INPUTEVENT_JOY2_VERT : INPUTEVENT_JOY1_VERT;
+       uid[i].eventid[ID_BUTTON_OFFSET + 0][0] = port ? INPUTEVENT_JOY2_FIRE_BUTTON : INPUTEVENT_JOY1_FIRE_BUTTON;
+       uid[i].eventid[ID_BUTTON_OFFSET + 1][0] = port ? INPUTEVENT_JOY2_2ND_BUTTON : INPUTEVENT_JOY1_2ND_BUTTON;
+       uid[i].eventid[ID_BUTTON_OFFSET + 2][0] = port ? INPUTEVENT_JOY2_3RD_BUTTON : INPUTEVENT_JOY1_3RD_BUTTON;
+    }
+    uid[0].enabled = 1;
+}
diff --git a/od-win32/direct3d.c b/od-win32/direct3d.c
new file mode 100755 (executable)
index 0000000..37a0332
--- /dev/null
@@ -0,0 +1,559 @@
+
+#include <windows.h>
+#include "sysconfig.h"
+#include "sysdeps.h"
+#include "config.h"
+#include "options.h"
+#include "xwin.h"
+#include "custom.h"
+#include "drawing.h"
+#include "dxwrap.h"
+#include "win32.h"
+#include "win32gfx.h"
+#include "gfxfilter.h"
+
+#include <d3d9.h>
+#include <d3dx9.h>
+
+#include "direct3d.h"
+
+static int tformat;
+static int d3d_enabled, scanlines_ok;
+static HINSTANCE d3dDLL;
+static LPDIRECT3D9 d3d;
+static D3DPRESENT_PARAMETERS dpp;
+static LPDIRECT3DDEVICE9 d3ddev;
+static D3DSURFACE_DESC dsdbb;
+static LPDIRECT3DTEXTURE9 texture, sltexture;
+
+static int twidth, theight, max_texture_w, max_texture_h;
+static int tin_w, tin_h, window_h, window_w;
+static int t_depth;
+static int required_sl_texture_w, required_sl_texture_h;
+static int vsync2, guimode;
+
+static char *D3D_ErrorText (HRESULT error)
+{
+    return "";
+}
+static char *D3D_ErrorString (HRESULT dival)
+{
+    static char dierr[200];
+    sprintf(dierr, "%08.8X S=%d F=%04.4X C=%04.4X (%d) (%s)",
+       dival, (dival & 0x80000000) ? 1 : 0,
+       HRESULT_FACILITY(dival),
+       HRESULT_CODE(dival),
+       HRESULT_CODE(dival),
+       D3D_ErrorText (dival));
+    return dierr;
+}
+
+void D3D_free (void)
+{
+    if (texture) {
+       IDirect3DTexture9_Release (texture);
+       texture = NULL;
+    }
+    if (sltexture) {
+       IDirect3DTexture9_Release (sltexture);
+       sltexture = NULL;
+    }
+
+    if (d3ddev) {
+       IDirect3DDevice9_Release (d3ddev);
+       d3ddev = NULL;
+    }
+    if (d3dDLL) {
+       FreeLibrary (d3dDLL);
+       d3dDLL = NULL;
+    }
+    d3d_enabled = 0;
+}
+
+static int restoredeviceobjects(void)
+{
+    // Store render target surface desc
+    LPDIRECT3DSURFACE9 bb;
+    HRESULT hr;
+    D3DXMATRIX matrix;
+    FLOAT aspect;
+    int v;
+
+    hr = IDirect3DDevice9_GetBackBuffer (d3ddev, 0, 0, D3DBACKBUFFER_TYPE_MONO, &bb);
+    if (!SUCCEEDED (hr)) {
+       write_log ("failed to create backbuffer: %s\n", D3D_ErrorString (hr));
+       return 0;
+    }
+    hr = IDirect3DSurface9_GetDesc (bb, &dsdbb);
+    hr = IDirect3DSurface9_Release (bb);
+
+    // Set up the texture 
+    hr = IDirect3DDevice9_SetTextureStageState(d3ddev, 0, D3DTSS_COLOROP,   D3DTOP_MODULATE);
+    hr = IDirect3DDevice9_SetTextureStageState(d3ddev, 0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+    hr = IDirect3DDevice9_SetTextureStageState(d3ddev, 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
+
+    // Set miscellaneous render states
+    hr = IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_DITHERENABLE, TRUE);
+    hr = IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ZENABLE, FALSE);
+
+    // Set the projection matrix
+    aspect = ((FLOAT)dsdbb.Width) / dsdbb.Height;
+    D3DXMatrixPerspectiveFovLH (&matrix, D3DX_PI/4, aspect, 1.0f, 100.0f);
+    hr = IDirect3DDevice9_SetTransform(d3ddev, D3DTS_PROJECTION, &matrix);
+
+    // turn off lighting
+    hr = IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_LIGHTING, FALSE);
+
+    switch (currprefs.gfx_filter_filtermode & 1)
+    {
+       case 0:
+       v = D3DTEXF_POINT;
+       break;
+       case 1:
+       default:
+       v = D3DTEXF_LINEAR;
+       break;
+    }
+    hr = IDirect3DDevice9_SetSamplerState(d3ddev, 0, D3DSAMP_MAGFILTER, v);
+    hr = IDirect3DDevice9_SetSamplerState(d3ddev, 0, D3DSAMP_MINFILTER, v);
+    return 1;
+}
+
+static int createtexture (int w, int h)
+{
+    HRESULT hr;
+    UINT ww = w;
+    UINT hh = h;
+    D3DFORMAT format = tformat;
+
+    hr = D3DXCheckTextureRequirements(d3ddev, &ww, &hh, NULL, 0, &format, D3DPOOL_MANAGED);
+    if (FAILED (hr)) {
+       write_log ("D3DXCheckTextureRequirements failed: %s\n", D3D_ErrorString (hr));
+    }
+    hr = D3DXCreateTexture(d3ddev, ww, hh, 0, 0, format, D3DPOOL_MANAGED, &texture);
+    if (FAILED (hr)) {
+       write_log ("D3DXCreateTexture failed: %s\n", D3D_ErrorString (hr));
+    }
+    twidth = ww;
+    theight = hh;
+    write_log ("D3D: %d*%d texture allocated, bits per pixel %d\n", ww, hh, t_depth);
+    return 1;
+}
+static int createsltexture (void)
+{
+    HRESULT hr;
+    UINT ww = required_sl_texture_w;
+    UINT hh = required_sl_texture_h;
+    D3DFORMAT format = D3DFMT_A4R4G4B4;
+
+    hr = D3DXCheckTextureRequirements(d3ddev, &ww, &hh, NULL, 0, &format, D3DPOOL_MANAGED);
+    if (FAILED (hr)) {
+       write_log ("SL D3DXCheckTextureRequirements failed: %s\n", D3D_ErrorString (hr));
+       return 0;
+    }
+    hr = D3DXCreateTexture(d3ddev, ww, hh, 0, 0, format, D3DPOOL_MANAGED, &sltexture);
+    if (FAILED (hr)) {
+       write_log ("SL D3DXCreateTexture failed: %s\n", D3D_ErrorString (hr));
+       return 0;
+    }
+    required_sl_texture_w = ww;
+    required_sl_texture_h = hh;
+    write_log ("D3D: SL %d*%d texture allocated\n", ww, hh);
+
+    scanlines_ok = 1;
+    return 1;
+}
+
+static void createscanlines (int force)
+{
+    HRESULT hr;
+    D3DLOCKED_RECT locked;
+    static int osl1, osl2, osl3;
+    int sl4, sl42;
+    int l1, l2;
+    int x, y, yy;
+    uae_u8 *sld, *p;
+
+    if (!scanlines_ok)
+       return;
+    if (osl1 == currprefs.gfx_filter_scanlines && osl3 == currprefs.gfx_filter_scanlinelevel && osl2 == currprefs.gfx_filter_scanlineratio && !force)
+       return;
+    osl1 = currprefs.gfx_filter_scanlines;
+    osl3 = currprefs.gfx_filter_scanlinelevel;
+    osl2 = currprefs.gfx_filter_scanlineratio;
+    sl4 = currprefs.gfx_filter_scanlines * 16 / 100;
+    sl42 = currprefs.gfx_filter_scanlinelevel * 16 / 100;
+    if (sl4 > 15) sl4 = 15;
+    if (sl42 > 15) sl42 = 15;
+    l1 = currprefs.gfx_filter_scanlineratio & 15;
+    l2 = currprefs.gfx_filter_scanlineratio >> 4;
+
+    hr = IDirect3DTexture9_LockRect(sltexture, 0, &locked, NULL, D3DLOCK_DISCARD);
+    if (FAILED (hr)) {
+        write_log ("SL IDirect3DTexture9_LockRect failed: %s\n", D3D_ErrorString (hr));
+       return;
+    }
+    sld = (uae_u8*)locked.pBits;
+    for (y = 0; y < window_h; y++)
+       memset (sld + y * locked.Pitch, 0, window_w * 2);
+    for (y = 1; y < window_h; y += l1 + l2) {
+       for (yy = 0; yy < l2 && y + yy < window_h; yy++) {
+           for (x = 0; x < window_w; x++) {
+               /* 16-bit, A4R4G4B4 */
+               uae_u8 sll = sl42;
+               p = &sld[(y + yy) * locked.Pitch + (x * 2)];
+               p[1] = (sl4 << 4) | (sll << 0);
+               p[0] = (sll << 4) | (sll << 0);
+           }
+       }
+    }
+    IDirect3DTexture9_UnlockRect (sltexture, 0);
+    if (scanlines_ok) {
+       /* enable alpha blending for scanlines */
+       IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHABLENDENABLE, TRUE);
+       IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
+       IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
+    } else {
+       IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHABLENDENABLE, FALSE);
+    }
+}
+
+
+const char *D3D_init (HWND ahwnd, int w_w, int w_h, int t_w, int t_h, int depth)
+{
+    HRESULT ret;
+    static char errmsg[100] = { 0 };
+    LPDIRECT3D9 (WINAPI *D3DCreate)(UINT);
+    D3DDISPLAYMODE mode;
+    D3DCAPS9 d3dCaps;
+
+    d3d_enabled = 0;
+    scanlines_ok = 0;
+    if (currprefs.gfx_filter != UAE_FILTER_DIRECT3D) {
+       strcpy (errmsg, "D3D: not enabled");
+       return errmsg;
+    }
+
+    d3dDLL = LoadLibrary("D3D9.DLL");
+    if (d3dDLL == NULL) {
+        strcpy (errmsg, "Direct3D: DirectX 9 or newer required");
+        return errmsg;
+    }
+    D3DCreate = (LPDIRECT3D9 (WINAPI *)(UINT))
+    GetProcAddress(d3dDLL, "Direct3DCreate9");
+    if(D3DCreate == NULL) {
+       D3D_free ();
+       strcpy (errmsg, "Direct3D: DirectX 9 or newer required");
+       return errmsg;
+    }
+    d3d = D3DCreate(D3D_SDK_VERSION);
+    if (d3d == NULL) {
+       D3D_free ();
+       strcpy (errmsg, "Direct3D: failed to create D3D object");
+       return errmsg;
+    }
+
+    IDirect3D9_GetAdapterDisplayMode(d3d, D3DADAPTER_DEFAULT, &mode);
+    IDirect3D9_GetDeviceCaps(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps);
+
+    memset (&dpp, 0, sizeof (dpp));
+    dpp.Windowed = currprefs.gfx_afullscreen ? FALSE : TRUE;
+    dpp.BackBufferFormat = mode.Format;
+    dpp.BackBufferCount = 1;
+    dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+    dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
+    dpp.BackBufferWidth = w_w;
+    dpp.BackBufferHeight = w_h;
+    dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
+    vsync2 = 0;
+    if (currprefs.gfx_afullscreen) {
+       dpp.FullScreen_RefreshRateInHz = currprefs.gfx_refreshrate;
+       if (currprefs.gfx_vsync > 0) {
+           dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
+           if (currprefs.gfx_vsync > 85) {
+               if (d3dCaps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO)
+                   dpp.PresentationInterval = D3DPRESENT_INTERVAL_TWO;
+               else
+                   vsync2 = 1;
+           }
+       }    
+    }
+  
+    ret = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, ahwnd,
+       D3DCREATE_SOFTWARE_VERTEXPROCESSING, &dpp, &d3ddev);
+    if(FAILED(ret)) {
+       sprintf (errmsg, "CreateDevice failed, %s\n", D3D_ErrorString (ret));
+       D3D_free ();
+       return errmsg;
+    }
+
+    max_texture_w = d3dCaps.MaxTextureWidth;
+    max_texture_h = d3dCaps.MaxTextureHeight;
+
+    write_log("D3D: max texture width: %d, max texture height: %d\n",
+       max_texture_w, max_texture_h);
+
+    if (max_texture_w < t_w || max_texture_h < t_h) {
+       sprintf (errmsg, "Direct3D: %d * %d or bigger texture support required\nYour card's maximum texture size is only %d * %d",
+           t_w, t_h, max_texture_w, max_texture_h);
+       return errmsg;
+    }
+
+    required_sl_texture_w = w_w;
+    required_sl_texture_h = w_h;
+    if (currprefs.gfx_filter_scanlines > 0 && (max_texture_w < w_w || max_texture_h < w_h)) {
+       gui_message ("Direct3D: %d * %d or bigger texture support required for scanlines (max is only %d * %d)\n"
+           "Scanlines disabled.",
+           required_sl_texture_w, required_sl_texture_h, max_texture_w, max_texture_h);
+       changed_prefs.gfx_filter_scanlines = currprefs.gfx_filter_scanlines = 0;
+    }
+
+    t_depth = depth;
+    switch (depth)
+    {
+       case 32:
+       if (currprefs.gfx_filter_scanlines)
+           tformat = D3DFMT_A8R8G8B8;
+       else
+           tformat = D3DFMT_X8R8G8B8;
+       break;
+       case 15:
+       case 16:
+       if (currprefs.gfx_filter_scanlines)
+           tformat = D3DFMT_A1R5G5B5;
+       else
+           tformat = D3DFMT_X1R5G5B5;
+       break;
+    }
+    restoredeviceobjects ();
+    window_w = w_w;
+    window_h = w_h;
+    tin_w = t_w;
+    tin_h = t_h;
+    createtexture (t_w, t_h);
+    if (currprefs.gfx_filter_scanlines > 0)
+       createsltexture ();
+    createscanlines (1);
+    d3d_enabled = 1;
+    return 0;
+}
+
+#define D3DFVF_TLVERTEX D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1
+
+typedef struct _D3DTLVERTEX {
+    float sx; /* Screen coordinates */
+    float sy;
+    float sz;
+    float rhw; /* Reciprocal of homogeneous w */
+    D3DCOLOR color; /* Vertex color */
+    float tu; /* Texture coordinates */
+    float tv;
+} D3DTLVERTEX, *LPD3DTLVERTEX;
+
+static void BlitRect(LPDIRECT3DDEVICE9 dev, LPDIRECT3DTEXTURE9 src,
+               float left, float top, float right, float bottom, D3DCOLOR col,float z)
+{
+    int i;
+    HRESULT hr;
+    D3DTLVERTEX verts[4];
+    float rhw = 1.0f / (z * 990.0f + 10.0f);
+
+    for (i = 0; i < 4; i++) {
+       verts[i].rhw = rhw;
+       verts[i].color = col;
+    }
+    verts[0].tu = 0.0f; verts[0].tv = 0.0f;
+    verts[0].sx = left - 0.5f; verts[0].sy = top - 0.5f; verts[0].sz = z;
+    verts[1].tu = 1.0f; verts[1].tv = 0.0f;
+    verts[1].sx = right - 0.5f; verts[1].sy = top - 0.5f; verts[1].sz = z;
+    verts[2].tu = 1.0f; verts[2].tv = 1.0f;
+    verts[2].sx = right - 0.5f; verts[2].sy = bottom - 0.5f; verts[2].sz = z;
+    verts[3].tu = 0.0f; verts[3].tv = 1.0f;
+    verts[3].sx = left - 0.5f; verts[3].sy = bottom - 0.5f; verts[3].sz = z;
+
+    // set the texture
+    hr = IDirect3DDevice9_SetTexture(dev, 0, src);
+    if (FAILED (hr))
+        write_log ("IDirect3DDevice9_SetTexture failed: %s\n", D3D_ErrorString (hr));
+
+    hr = IDirect3DDevice9_SetVertexShader(dev, NULL);
+    if (FAILED (hr))
+        write_log ("IDirect3DDevice9_SetVertexShader failed: %s\n", D3D_ErrorString (hr));
+    // configure shader for vertex type
+    hr = IDirect3DDevice9_SetFVF(dev, D3DFVF_TLVERTEX);
+    if (FAILED (hr))
+        write_log ("IDirect3DDevice9_SetFVF failed: %s\n", D3D_ErrorString (hr));
+
+    // draw the rectangle
+    hr = IDirect3DDevice9_DrawPrimitiveUP(dev, D3DPT_TRIANGLEFAN, 2, verts, sizeof(D3DTLVERTEX));
+    if (FAILED (hr))
+        write_log ("IDirect3DDevice9_DrawPrimitiveUP failed: %s\n", D3D_ErrorString (hr));
+}
+
+static void calc (float *xp, float *yp, float *sxp, float *syp)
+{
+    int xm, ym;
+    int fx, fy;
+    float x, y, sx, sy;
+
+    xm = currprefs.gfx_lores ? 2 : 1;
+    ym = currprefs.gfx_linedbl ? 1 : 2;
+    if (window_w >= 1024)
+       xm *= 2;
+    else if (window_w < 500)
+       xm /= 2;
+    if (window_h >= 960)
+       ym *= 2;
+    else if (window_h < 350)
+       ym /= 2;
+    fx = (tin_w * xm - window_w) / 2;
+    fy = (tin_h * ym - window_h) / 2;
+    x = (float)(window_w * currprefs.gfx_filter_horiz_offset / 100.0);
+    y = (float)(window_h * currprefs.gfx_filter_vert_offset / 100.0);
+    sx = x + (float)(twidth * window_w / tin_w) * ((currprefs.gfx_filter_horiz_zoom + 100) / 100.0);
+    sy = y + (float)(theight * window_h / tin_h) * ((currprefs.gfx_filter_vert_zoom + 100) / 100.0);
+    x -= fx; y -= fy;
+    sx += 2 * fx; sy += 2 * fy;
+    *xp = x; *yp = y;
+    *sxp = sx; *syp = sy;
+}
+
+void D3D_unlocktexture (void)
+{
+    float x, y, sx, sy;
+    IDirect3DTexture9_UnlockRect (texture, 0);
+    calc (&x, &y, &sx, &sy);
+    BlitRect (d3ddev, texture, x, y, sx, sy, 0xffffff, 0.1f);
+    if (scanlines_ok)
+       BlitRect (d3ddev, sltexture, 0, 0, required_sl_texture_w, required_sl_texture_h, 0xffffff, 0.2f);
+    IDirect3DDevice9_EndScene(d3ddev);
+    IDirect3DDevice9_Present (d3ddev, 0, 0, 0 ,0);
+    if (vsync2)
+       D3D_render ();
+}
+
+int D3D_locktexture (void)
+{
+    D3DLOCKED_RECT locked;
+    HRESULT hr;
+
+    if (FAILED(IDirect3DDevice9_TestCooperativeLevel(d3ddev)))
+       return 0;
+    IDirect3DDevice9_Clear(d3ddev, 0L, NULL, D3DCLEAR_TARGET, 0x00000000, 1.0f, 0L );
+
+    hr = IDirect3DDevice9_BeginScene(d3ddev);
+    if (FAILED (hr)) {
+       write_log ("IDirect3DDevice9_BeginScene failed: %s\n", D3D_ErrorString (hr));
+       return 0;
+    }
+    hr = IDirect3DTexture9_LockRect(texture, 0, &locked, NULL, D3DLOCK_DISCARD | D3DLOCK_NOSYSLOCK);
+    if (FAILED (hr)) {
+        write_log ("IDirect3DTexture9_LockRect failed: %s\n", D3D_ErrorString (hr));
+       D3D_unlocktexture ();
+       return 0;
+    }
+    gfxvidinfo.bufmem = locked.pBits;
+    gfxvidinfo.rowbytes = locked.Pitch;
+    init_row_map ();
+    return 1;
+}
+
+void D3D_render (void)
+{
+    float x, y, sx, sy;
+    HRESULT hr;
+
+    if (!d3d_enabled)
+       return;
+    if (FAILED(IDirect3DDevice9_TestCooperativeLevel(d3ddev)))
+       return;
+    IDirect3DDevice9_Clear(d3ddev, 0L, NULL, D3DCLEAR_TARGET, 0x00000000, 1.0f, 0L );
+    hr = IDirect3DDevice9_BeginScene(d3ddev);
+    if (FAILED (hr))
+       return;
+    calc (&x, &y, &sx, &sy);
+    BlitRect(d3ddev, texture, x, y, sx, sy, 0xffffff, 0.1f);
+    if (scanlines_ok)
+       BlitRect (d3ddev, sltexture, 0, 0, required_sl_texture_w, required_sl_texture_h, 0xffffff, 0.2f);
+    IDirect3DDevice9_EndScene(d3ddev);
+    IDirect3DDevice9_Present (d3ddev, 0, 0, 0 ,0);
+}
+
+void D3D_refresh (void)
+{
+    if (!d3d_enabled)
+       return;
+    createscanlines (1);
+    D3D_render ();
+}
+
+void D3D_getpixelformat (int depth,int *rb, int *gb, int *bb, int *rs, int *gs, int *bs, int *ab, int *as, int *a)
+{
+    switch (depth)
+    {
+       case 32:
+        *rb = 8;
+       *gb = 8;
+       *bb = 8;
+       *ab = 8;
+       *rs = 16;
+       *gs = 8;
+       *bs = 0;
+       *as = 24;
+       *a = 255;
+       break;
+       case 15:
+       case 16:
+        *rb = 5;
+       *gb = 5;
+       *bb = 5;
+       *ab = 1;
+       *rs = 10;
+       *gs = 5;
+       *bs = 0;
+       *as = 15;
+       *a = 1;
+       break;
+    }
+}
+
+void D3D_guimode (int guion)
+{
+    if (!d3d_enabled)
+       return;
+    IDirect3DDevice9_SetDialogBoxMode (d3ddev, guion);
+    guimode = guion;
+}
+
+HDC D3D_getDC(HDC hdc)
+{
+    static LPDIRECT3DSURFACE9 bb;
+    HRESULT hr;
+
+    if (!d3d_enabled)
+       return 0;
+    if (!hdc) {
+        hr = IDirect3DDevice9_GetBackBuffer (d3ddev, 0, 0, D3DBACKBUFFER_TYPE_MONO, &bb);
+       if (!SUCCEEDED (hr)) {
+           write_log ("failed to create backbuffer: %s\n", D3D_ErrorString (hr));
+           return 0;
+       }
+       if (IDirect3DSurface9_GetDC (bb, &hdc) == D3D_OK)
+           return hdc;
+       return 0;
+    }
+    IDirect3DSurface9_ReleaseDC (bb, hdc);
+    IDirect3DSurface9_Release (bb);
+    return 0;
+}
+
+int D3D_isenabled (void)
+{
+    return d3d_enabled;
+}
+
+
+
+
+
+
diff --git a/od-win32/direct3d.h b/od-win32/direct3d.h
new file mode 100755 (executable)
index 0000000..6e16be8
--- /dev/null
@@ -0,0 +1,12 @@
+
+extern void D3D_resize (int width, int height);
+extern void D3D_free ();
+extern const char *D3D_init (HWND ahwnd, int w_w, int w_h, int t_w, int t_h, int depth);
+extern void D3D_render (void);
+extern void D3D_getpixelformat (int depth,int *rb, int *bb, int *gb, int *rs, int *bs, int *gs, int *ab, int *ar, int *a);
+extern void D3D_refresh (void);
+extern int D3D_locktexture(void);
+extern void D3D_unlocktexture(void);
+extern void D3D_guimode (int guion);
+extern HDC D3D_getDC(HDC hdc);
+extern int D3D_isenabled (void);
diff --git a/od-win32/drivesound.c b/od-win32/drivesound.c
new file mode 100755 (executable)
index 0000000..4782c7b
--- /dev/null
@@ -0,0 +1,191 @@
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "zfile.h"
+#include "sounddep/sound.h"
+#include "dxwrap.h"
+
+#include <windows.h>
+#include <mmsystem.h>
+#include <dsound.h>
+
+static LPDIRECTSOUND lpDS;
+static LPDIRECTSOUNDBUFFER lpDSBprimary;
+
+#define DRIVESOUND_CLICK 0
+#define DRIVESOUND_STARTUP 1
+#define DRIVESOUND_SPIN 2
+#define DRIVESOUND_END 3
+
+static LPDIRECTSOUNDBUFFER samples[4][DRIVESOUND_END];
+static int drivesound_enabled, drive_enabled[4];
+static int click_frequency[4];
+static int minfreq, maxfreq;
+
+extern GUID sound_device_guid[];
+
+static void close_audio_ds (void)
+{
+    int i, j;
+
+    drivesound_enabled = 0;
+    for (i = 0; i < DRIVESOUND_END; i++) {
+       for (j = 0; j < 4; j++) {
+           if (samples[j][i])
+               IDirectSound_Release (samples[j][i]);
+           samples[j][i] = 0;
+           drive_enabled[j] = 0;
+       }
+    }
+    if (lpDSBprimary)
+       IDirectSound_Release (lpDSBprimary);
+    lpDSBprimary = 0;
+    if (lpDS) {
+       IDirectSound_Release (lpDS);
+       write_log ("DRIVESOUND: DirectSound driver freed\n");
+    }
+    lpDS = 0;
+}
+
+extern HWND hMainWnd;
+
+static int createsample (int drivenum, int samplenum, char *path)
+{
+    struct zfile *f;
+    uae_u8 *buf = 0;
+    int size, freq = 44100;
+    WAVEFORMATEX wavfmt;
+    DSBUFFERDESC sound_buffer;
+    HRESULT hr;
+    void *b1, *b2;
+    DWORD s1, s2;
+
+    f = zfile_fopen (path, "rb");
+    if (!f) {
+       write_log ("DRIVESOUND: can't open '%s'\n", path);
+       goto error;
+    }
+    zfile_fseek (f, 0, SEEK_END);
+    size = zfile_ftell (f);
+    buf = malloc (size);
+    zfile_fseek (f, 0, SEEK_SET);
+    zfile_fread (buf, size, 1, f);
+    zfile_fclose (f);
+
+    if (samplenum == DRIVESOUND_CLICK)
+       click_frequency[drivenum] = freq;
+    wavfmt.wFormatTag = WAVE_FORMAT_PCM;
+    wavfmt.nChannels = 2;
+    wavfmt.nSamplesPerSec = freq;
+    wavfmt.wBitsPerSample = 16;
+    wavfmt.nBlockAlign = 16 / 8 * wavfmt.nChannels;
+    wavfmt.nAvgBytesPerSec = wavfmt.nBlockAlign * freq;
+    memset (&sound_buffer, 0, sizeof (sound_buffer));
+    sound_buffer.dwSize = sizeof (sound_buffer);
+    sound_buffer.dwBufferBytes = size;
+    sound_buffer.lpwfxFormat = &wavfmt;
+    sound_buffer.dwFlags = DSBCAPS_LOCSOFTWARE  | DSBCAPS_GLOBALFOCUS;
+
+    hr = IDirectSound_CreateSoundBuffer( lpDS, &sound_buffer, &samples[drivenum][samplenum], NULL );
+    if (hr != DS_OK) {
+        write_log ("DRIVESOUND: Secondary CreateSoundBuffer(%s) failure: %s\n",
+           path, DXError (hr));
+        goto error;
+    }
+    hr = IDirectSoundBuffer_Lock (samples[drivenum][samplenum], 0, sndbufsize, &b1, &s1, &b2, &s2, DSBLOCK_ENTIREBUFFER);
+    if (hr != DS_OK) {
+        write_log ("DRIVESOUND: lock failed: %s\n", DXError (hr));
+        goto error;
+    }
+    memcpy (b1, buf, size >= s1 ? s1 : size);
+    if (b2)
+        memcpy (b2, buf + s1, size - s1);
+    IDirectSoundBuffer_Unlock (samples[drivenum][samplenum], b1, s1, b2, s2);
+    write_log ("DRIVESOUND: drive %d, sample %d (%s) loaded\n", drivenum, samplenum, path);
+
+    return 1;
+    error:
+    free (buf);
+    if (samples[drivenum][samplenum]) {
+       IDirectSound_Release (samples[drivenum][samplenum]);
+       samples[drivenum][samplenum] = 0;
+    }
+    return 0;
+}
+
+
+static int open_audio_ds (void)
+{
+    HRESULT hr;
+    int freq = currprefs.sound_freq;
+    
+    enumerate_sound_devices (0);
+    hr = DirectSoundCreate (&sound_device_guid[currprefs.win32_soundcard], &lpDS, NULL);
+    if (hr != DS_OK)  {
+        write_log ("SOUND: DirectSoundCreate() failure: %s\n", DXError (hr));
+        return 0;
+    }
+    hr = IDirectSound_SetCooperativeLevel (lpDS, hMainWnd, DSSCL_NORMAL);
+    if (hr != DS_OK) {
+        write_log ("SOUND: Can't set cooperativelevel: %s\n", DXError (hr));
+        goto error;
+    }
+
+    createsample(0, DRIVESOUND_CLICK, "drive_click.raw");
+    createsample(0, DRIVESOUND_STARTUP, "drive_startup.raw");
+    createsample(0, DRIVESOUND_SPIN, "drive_spin.raw");
+    drive_enabled[0] = 1;    
+
+    drivesound_enabled = 1;
+
+    return 1;
+
+error:
+    close_audio_ds ();
+    return 0;
+}
+
+int drivesound_init (void)
+{
+    return open_audio_ds ();
+}
+
+void drivesound_free (void)
+{
+    close_audio_ds ();
+}
+
+void drivesound_click (int num, int delay)
+{
+    HRESULT hr;
+    LPDIRECTSOUNDBUFFER dsb;
+
+    if (!drivesound_enabled || !drive_enabled[num])
+       return;
+    dsb = samples[num][DRIVESOUND_CLICK];
+    if (!dsb)
+       return;
+    hr = IDirectSoundBuffer_SetCurrentPosition (dsb, 0);
+    hr = IDirectSoundBuffer_Play (dsb, 0, 0, 0);
+}
+
+void drivesound_motor (int num, int status)
+{
+    HRESULT hr;
+
+    if (!drivesound_enabled || !drive_enabled[num])
+       return;
+    if (!status) {
+       if (samples[num][DRIVESOUND_STARTUP])
+           hr = IDirectSoundBuffer_Stop (samples[num][DRIVESOUND_STARTUP]);
+       if (samples[num][DRIVESOUND_SPIN])
+           hr = IDirectSoundBuffer_Stop (samples[num][DRIVESOUND_SPIN]);
+    } else {
+       if (status == 2 && samples[num][DRIVESOUND_STARTUP])
+           hr = IDirectSoundBuffer_Play (samples[num][DRIVESOUND_STARTUP], 0, 0, 0);
+       if (samples[num][DRIVESOUND_SPIN])
+           hr = IDirectSoundBuffer_Play (samples[num][DRIVESOUND_SPIN], 0, 0, DSBPLAY_LOOPING);
+    }
+}
diff --git a/od-win32/dxwrap.c b/od-win32/dxwrap.c
new file mode 100755 (executable)
index 0000000..9b77451
--- /dev/null
@@ -0,0 +1,2056 @@
+/*
+ * UAE - The Ultimate Amiga Emulator
+ *
+ * Win32 DirectX Wrappers, to simplify (?) my life.
+ *
+ * Copyright 1999 Brian King, under GNU Public License
+ *
+ */
+#ifndef _MSC_VER
+#define INITGUID
+#endif
+
+#include "config.h"
+#include "sysconfig.h"
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <windows.h>
+#include <sys/timeb.h>
+
+#ifdef _MSC_VER
+#include <mmsystem.h>
+#include <ddraw.h>
+#include <dsound.h>
+#include <dxerr8.h>
+#else
+#include "winstuff.h"
+#endif
+
+#include "sysdeps.h"
+#include "options.h"
+#include "picasso96.h"
+#include "dxwrap.h"
+#include "win32.h"
+#include "win32gfx.h"
+#include "machdep/rpt.h"
+#include "custom.h"
+
+static BOOL bColourKeyAvailable = FALSE;
+static BOOL bOverlayAvailable   = FALSE;
+static DDCAPS_DX7 drivercaps, helcaps;
+static DWORD overlayflags;
+static DDOVERLAYFX overlayfx;
+extern COLORREF g_dwBackgroundColor;
+static int flipinterval_supported;
+
+#define dxwrite_log
+
+static int restoresurface (LPDIRECTDRAWSURFACE7 surface)
+{
+    HRESULT hr = IDirectDrawSurface7_Restore (surface);
+    if (hr == DD_OK) {
+       HRESULT hr2;
+       DDBLTFX bltfx;
+       memset (&bltfx, 0, sizeof (bltfx));
+       bltfx.dwSize = sizeof (bltfx);
+       hr2 = IDirectDrawSurface7_Blt (surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &bltfx);
+       if (hr2 != DD_OK)
+           write_log("Surface clear failed: %s\n", DXError (hr2));
+    }
+    return hr;
+}
+/*
+ * FUNCTION:ShowDDCaps
+ *
+ * PURPOSE:print out the DirectDraw Capabilities
+ *
+ * PARAMETERS:
+ *   caps    - DDCAPS_DX7 structure
+ *   hw      - flag indicating if this 'caps' is for real hardware or the HEL
+ *
+ * RETURNS:    none
+ *
+ * NOTES:none
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+static void ShowDDCaps( DDCAPS_DX7 caps, int hw )
+{
+    static int shown = 0;
+    static BOOL reset_shown = FALSE;
+    if( currprefs.win32_logfile && shown >= 4 && !reset_shown)
+    {
+       shown = 0;
+       reset_shown = TRUE;
+    }
+
+    if( shown < 2)
+    {
+       dxwrite_log( "DirectDraw Capabilities for %s:\n", hw ? "Display Driver Hardware" : "Display Driver Emulation Layer" );
+       if( caps.dwCaps & DDCAPS_BLT )
+           dxwrite_log( "DDCAPS_BLT - Capable of blitting\n" );
+       if( caps.dwCaps & DDCAPS_BLTCOLORFILL )
+           dxwrite_log( "DDCAPS_BLTCOLORFILL - Color filling with blitter\n" );
+       if( caps.dwCaps & DDCAPS_BLTSTRETCH )
+           dxwrite_log( "DDCAPS_BLTSTRETCH - Stretch blitting\n" );
+       if( caps.dwCaps & DDCAPS_CANBLTSYSMEM )
+           dxwrite_log( "DDCAPS_CANBLTSYSMEM - Blits from system memory\n" );
+       if( caps.dwCaps & DDCAPS_CANCLIP )
+           dxwrite_log( "DDCAPS_CANCLIP - Can clip while blitting\n" );
+       if( caps.dwCaps & DDCAPS_CANCLIPSTRETCHED )
+           dxwrite_log( "DDCAPS_CANCLIPSTRETCHED - Can clip while stretch-blitting\n" );
+       if( caps.dwCaps & DDCAPS_COLORKEY )
+       {
+           dxwrite_log( "DDCAPS_COLORKEY - Can color-key with blits/overlays\n" );
+           bColourKeyAvailable = TRUE;
+       }
+       if( caps.dwCaps & DDCAPS_GDI )
+           dxwrite_log( "DDCAPS_GDI - Display h/w shared with GDI\n" );
+       if( caps.dwCaps & DDCAPS_NOHARDWARE )
+           dxwrite_log( "DDCAPS_NOHARDWARE - no h/w support!\n" );
+       if( caps.dwCaps & DDCAPS_OVERLAY )
+       {
+           dxwrite_log( "DDCAPS_OVERLAY - support for %d overlay(s)\n", caps.dwMaxVisibleOverlays );
+           if( bColourKeyAvailable )
+           {
+               if( caps.dwCKeyCaps & DDCKEYCAPS_DESTOVERLAY )
+               {
+                   dxwrite_log( "DDCKEYCAPS_DESTOVERLAY - colour-keyed overlays\n" );
+                   bOverlayAvailable = TRUE;
+               }
+           }
+       }
+       if( caps.dwCaps & DDCAPS_OVERLAYFOURCC )
+           dxwrite_log( "DDCAPS_OVERLAYFOURCC - overlay can do color-space conversions\n" );
+       if( caps.dwCaps & DDCAPS_OVERLAYSTRETCH )
+           dxwrite_log( "DDCAPS_OVERLAYSTRETCH - overlay can stretch with min=%d/max=%d\n", caps.dwMinOverlayStretch, caps.dwMaxOverlayStretch );
+       if( caps.dwCaps & DDCAPS_VBI )
+           dxwrite_log( "DDCAPS_VBI - h/w can generate a vertical-blanking interrupt\n" );
+       if( caps.dwCaps2 & DDCAPS2_CERTIFIED )
+           dxwrite_log( "DDCAPS2_CERTIFIED - certified driver\n" );
+       if( caps.dwCaps2 & DDCAPS2_CANRENDERWINDOWED )
+           dxwrite_log( "DDCAPS2_CANRENDERWINDOWED - GDI windows can be seen when in full-screen\n" );
+       if( caps.dwCaps2 & DDCAPS2_NOPAGELOCKREQUIRED )
+           dxwrite_log( "DDCAPS2_NOPAGELOCKREQUIRED - no page locking needed for DMA blits\n" );
+       if( caps.dwCaps2 & DDCAPS2_FLIPNOVSYNC )
+           dxwrite_log( "DDCAPS2_FLIPNOVSYNC - can pass DDFLIP_NOVSYNC to Flip calls\n" );
+       if( caps.dwCaps2 & DDCAPS2_FLIPINTERVAL ) {
+           dxwrite_log( "DDCAPS2_FLIPINTERVAL - can pass DDFLIP_INTERVALx to Flip calls\n" );
+           flipinterval_supported = 1;
+       }
+       
+       dxwrite_log( "Video memory: %d/%d\n", caps.dwVidMemFree, caps.dwVidMemTotal );
+    }
+    shown++;
+}
+
+const char *DXError (HRESULT ddrval)
+{
+    static char dderr[1000];
+    sprintf(dderr, "%08.8X S=%d F=%04.4X C=%04.4X (%d) (%s)",
+       ddrval, (ddrval & 0x80000000) ? 1 : 0,
+       HRESULT_FACILITY(ddrval),
+       HRESULT_CODE(ddrval),
+       HRESULT_CODE(ddrval),
+       DXGetErrorDescription8 (ddrval));
+    return dderr;
+}
+
+static struct DirectDrawSurfaceMapper DirectDrawState;
+
+static int lockcnt = 0;
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+static int LockStub( surface_type_e type )
+{
+    int result = 0;
+    HRESULT ddrval;
+    LPDIRECTDRAWSURFACE7 surface;
+    LPDDSURFACEDESC2 surfacedesc;
+
+    switch( type )
+    {
+    case primary_surface:
+       surface = DirectDrawState.primary.surface;
+       surfacedesc = &DirectDrawState.primary.desc;
+       break;
+    case secondary_surface:
+       surface = DirectDrawState.secondary.surface;
+        surfacedesc = &DirectDrawState.secondary.desc;
+       break;
+    case tertiary_surface:
+       surface = DirectDrawState.tertiary.surface;
+        surfacedesc = &DirectDrawState.tertiary.desc;
+       break;
+    case overlay_surface:
+       surface = DirectDrawState.overlay.surface;
+        surfacedesc = &DirectDrawState.overlay.desc;
+       break;
+    }
+
+    if( lockcnt )
+    {
+#ifdef _DEBUG
+       DebugBreak();
+#endif
+       return 1;
+    }
+
+    if( type == secondary_surface && DirectDrawState.flipping != single_buffer )
+    {
+       IDirectDrawSurface7_Restore( DirectDrawState.primary.surface );
+    }
+
+    while ( (ddrval = IDirectDrawSurface7_Lock( surface, NULL, surfacedesc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,
+                                                NULL ) ) != DD_OK )
+    {
+        if (ddrval == DDERR_SURFACELOST) {
+           ddrval = restoresurface (surface);
+            if (ddrval != DD_OK)
+            {
+                result = 0;
+                break;
+            }
+        }
+        else if (ddrval != DDERR_SURFACEBUSY) 
+        {
+           write_log ("lpDDS->Lock() failed - %s\n", DXError (ddrval));
+            result = 0;
+            break;
+        }
+    }
+    if( ddrval == DD_OK )
+        result = 1;
+    
+    if( result )
+        lockcnt++;
+
+    return result;
+}
+
+/* For a given surface-type, update our DirectDrawState structure */
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+int DirectDraw_SurfaceLock( surface_type_e surface_type )
+{
+    int result = 0;
+
+    if( surface_type == lockable_surface )
+        surface_type = DirectDraw_GetLockableType();
+
+    switch( surface_type )
+    {
+        case primary_surface:
+            DirectDrawState.primary.desc.dwSize = sizeof( DDSURFACEDESC2 );
+            result = LockStub( surface_type );
+        break;
+        case secondary_surface:
+            DirectDrawState.secondary.desc.dwSize = sizeof( DDSURFACEDESC2 );
+            result = LockStub( surface_type );
+        break;
+        case tertiary_surface:
+            DirectDrawState.tertiary.desc.dwSize = sizeof( DDSURFACEDESC2 );
+            result = LockStub( surface_type );
+        break;
+       case overlay_surface:
+           DirectDrawState.overlay.desc.dwSize = sizeof( DDSURFACEDESC2 );
+           result = LockStub( surface_type );
+        case lockable_surface:
+        case invalid_surface:
+        default:
+
+        break;
+    }
+    DirectDrawState.locked = result;
+
+    return result;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+char *DirectDraw_GetSurfacePointer( void )
+{
+    char *pixels = NULL;
+
+    /* Make sure that somebody has done a lock before returning the lpSurface member */
+    if( lockcnt )
+    {
+        pixels = DirectDrawState.lockable.lpdesc->lpSurface;
+    }
+    return pixels;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+LONG DirectDraw_GetSurfacePitch( void )
+{
+    LONG pitch = 0;
+
+    pitch = DirectDrawState.lockable.lpdesc->lPitch;
+    return pitch;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+DWORD DirectDraw_GetPixelFormatFlags( void )
+{
+    DWORD flags = 0;
+    flags = DirectDrawState.lockable.lpdesc->ddpfPixelFormat.dwFlags;
+    return flags;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+DWORD DirectDraw_GetSurfaceFlags( void )
+{
+    DWORD flags = 0;
+    flags = DirectDrawState.lockable.lpdesc->dwFlags;
+    return flags;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+DWORD DirectDraw_GetSurfaceBitCount( void )
+{
+    DWORD bits = 0;
+    //?????JGI begin:
+    if( DirectDrawState.lockable.lpdesc )
+       bits = DirectDrawState.lockable.lpdesc->ddpfPixelFormat.dwRGBBitCount;
+    else
+       bits = DirectDrawState.current.desc.ddpfPixelFormat.dwRGBBitCount;
+    //?????JGI end.
+    return bits;
+}
+
+/*
+ * FUNCTION:DirectDraw_GetPrimaryBitCount
+ *
+ * PURPOSE:Return the bit-depth of the primary surface
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS:    bit-depth
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   2001.08.25  Brian King             Creation
+ *
+ */
+DWORD DirectDraw_GetPrimaryBitCount( void )
+{
+    DWORD bits = 0;
+    memset(&DirectDrawState.primary.desc,0,sizeof(DirectDrawState.primary.desc));
+    DirectDrawState.primary.desc.dwSize = sizeof(DirectDrawState.primary.desc);
+
+    IDirectDrawSurface7_GetSurfaceDesc(DirectDrawState.primary.surface, &DirectDrawState.primary.desc);
+    bits = DirectDrawState.primary.desc.ddpfPixelFormat.dwRGBBitCount;
+    return bits;
+}
+
+void DirectDraw_GetPrimaryWidthHeight(int *w, int *h)
+{
+    memset(&DirectDrawState.primary.desc,0,sizeof(DirectDrawState.primary.desc));
+    DirectDrawState.primary.desc.dwSize = sizeof(DirectDrawState.primary.desc);
+
+    IDirectDrawSurface7_GetSurfaceDesc(DirectDrawState.primary.surface, &DirectDrawState.primary.desc);
+    *w = DirectDrawState.primary.desc.dwWidth;
+    *h = DirectDrawState.primary.desc.dwHeight;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+DWORD DirectDraw_GetPixelFormatBitMask( DirectDraw_Mask_e mask )
+{
+    DWORD result = 0;
+    switch( mask )
+    {
+        case red_mask:
+            result = DirectDrawState.lockable.lpdesc->ddpfPixelFormat.dwRBitMask;
+        break;
+        case green_mask:
+            result = DirectDrawState.lockable.lpdesc->ddpfPixelFormat.dwGBitMask;
+        break;
+        case blue_mask:
+            result = DirectDrawState.lockable.lpdesc->ddpfPixelFormat.dwBBitMask;
+        break;
+    }
+    return result;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+surface_type_e DirectDraw_GetLockableType( void )
+{
+    return DirectDrawState.surface_type;
+}
+
+/*
+ * FUNCTION:DirectDraw_IsLocked
+ *
+ * PURPOSE:Return whether we're currently locked or unlocked
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS:    TRUE if already locked, FALSE otherwise
+ *
+ * NOTES:Used by DX_Blit to possibly unlock during Blit operation
+ *
+ * HISTORY:
+ *   2000.04.30  Brian King             Creation
+ *
+ */
+BOOL DirectDraw_IsLocked( void )
+{
+    return DirectDrawState.locked ? TRUE : FALSE;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+static surface_type_e try_surface_locks( int want_fullscreen )
+{
+    surface_type_e result = invalid_surface;
+
+    if( DirectDrawState.isoverlay && DirectDraw_SurfaceLock( overlay_surface ) )
+    {
+       result = overlay_surface;
+       write_log( "try_surface_locks() returning overlay\n" );
+    }
+    else if( want_fullscreen && WIN32GFX_IsPicassoScreen() )
+    {
+       if( DirectDraw_SurfaceLock( primary_surface ) )
+       {
+           result = primary_surface;
+           write_log( "try_surface_locks() returning primary\n" );
+       }
+       else if( DirectDraw_SurfaceLock( secondary_surface ) )
+       {
+           result = secondary_surface;
+           write_log( "try_surface_locks() returning secondary\n" );
+       }
+    }
+    else
+    {
+        if( DirectDraw_SurfaceLock( secondary_surface ) )
+        {
+            result = secondary_surface;
+           write_log( "try_surface_locks() returning secondary\n" );
+        }
+    }
+
+    return result;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:Named this way for historical reasons
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+void ddraw_unlockscr( void )
+{
+    if( lockcnt > 0 )
+    {
+       lockcnt--;
+       IDirectDrawSurface7_Unlock( DirectDrawState.lockable.surface,
+                                   DirectDrawState.lockable.lpdesc->lpSurface );
+       DirectDrawState.locked = FALSE;
+    }
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+int DirectDraw_Start( GUID *guid )
+{
+    HRESULT ddrval;
+    DDCAPS_DX7 drivercaps, helcaps;
+
+    /* Prepare our DirectDrawState structure */
+    ZeroMemory( &DirectDrawState, sizeof( DirectDrawState ) );
+    ZeroMemory( &drivercaps, sizeof( drivercaps ) );
+    ZeroMemory( &helcaps, sizeof( helcaps ) );
+    drivercaps.dwSize = sizeof( drivercaps );
+    helcaps.dwSize = sizeof( helcaps );
+
+    ddrval = DirectDrawCreate( guid, &DirectDrawState.directdraw.ddx, NULL );
+    if (ddrval != DD_OK) {
+       if ( guid != NULL)
+           return 0;
+       goto oops;
+    }
+
+    DirectDrawState.initialized = TRUE;
+
+    ddrval = IDirectDraw_QueryInterface( DirectDrawState.directdraw.ddx,
+                                         &IID_IDirectDraw7,
+                                         (LPVOID *)&DirectDrawState.directdraw.dd );
+    if( ddrval != DD_OK )
+    {
+       gui_message("start_ddraw(): DirectX 7 or newer required");
+        DirectDraw_Release();
+       return 0;
+    }
+
+    DirectDraw_GetCaps( &drivercaps, &helcaps );
+    ShowDDCaps( drivercaps, 1 );
+    ShowDDCaps( helcaps, 0 );
+    if (DirectDraw_GetDisplayMode () == DD_OK)
+       return 1;
+    if (guid != NULL) {
+       DirectDraw_Release ();
+       return 0;
+    }
+
+  oops:
+    gui_message ("start_ddraw(): DirectDraw initialization failed with %s\n", DXError (ddrval));
+    DirectDraw_Release();
+    return 0;
+}
+
+#define releaser(x,y) if( x ) { y( x ); x = NULL; }
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+void DirectDraw_Release( void )
+{
+    releaser( DirectDrawState.lpDDC, IDirectDrawClipper_Release );
+    releaser( DirectDrawState.lpDDP, IDirectDrawPalette_Release );
+
+    if (DirectDrawState.directdraw.dd && DirectDrawState.modeset)
+    {
+       IDirectDraw7_RestoreDisplayMode( DirectDrawState.directdraw.dd );
+       IDirectDraw7_SetCooperativeLevel( DirectDrawState.directdraw.dd, hAmigaWnd, DDSCL_NORMAL);
+    }
+    DirectDrawState.modeset = 0;
+
+    releaser( DirectDrawState.overlay.surface, IDirectDrawSurface7_Release );
+    releaser( DirectDrawState.primary.surface, IDirectDrawSurface7_Release );
+
+    if( DirectDrawState.flipping == single_buffer)
+       releaser( DirectDrawState.secondary.surface, IDirectDrawSurface7_Release );
+
+    releaser( DirectDrawState.directdraw.dd, IDirectDraw_Release );
+
+    DirectDrawState.lockable.lpdesc = NULL;
+    DirectDrawState.lockable.lpdesc = NULL;
+    DirectDrawState.lockable.surface = NULL;
+    DirectDrawState.lockable.surface = NULL;
+
+    DirectDrawState.surface_type = invalid_surface;
+    DirectDrawState.initialized = FALSE;
+    DirectDrawState.isoverlay = FALSE;
+}
+
+/*
+ * FUNCTION:DirectDraw_SetCooperativeLevel
+ *
+ * PURPOSE:Wrapper for setting the cooperative level (fullscreen or normal)
+ *
+ * PARAMETERS:
+ *   window            Window to set the cooperative level for
+ *   want_fullscreen   fullscreen mode flag
+ *
+ * RETURNS:            result of underlying DirectDraw call
+ *
+ * NOTES:              Updates the .fullscreen and .window members.
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+HRESULT DirectDraw_SetCooperativeLevel( HWND window, int want_fullscreen )
+{
+    HRESULT ddrval;
+
+    ddrval = IDirectDraw7_SetCooperativeLevel( DirectDrawState.directdraw.dd,
+                                               window,
+                                               want_fullscreen ?
+                                               DDSCL_ALLOWREBOOT | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN  :
+                                               DDSCL_NORMAL );
+    if( ddrval == DD_OK )
+    {
+       DirectDrawState.fullscreen = want_fullscreen;
+       DirectDrawState.window = window;
+    }
+    return ddrval;
+}
+
+/*
+ * FUNCTION:DirectDraw_GetCooperativeLevel
+ *
+ * PURPOSE:Wrapper for setting the cooperative level (fullscreen or normal)
+ *
+ * PARAMETERS:
+ *   window            Window to set the cooperative level for
+ *   want_fullscreen   fullscreen mode flag
+ *
+ * RETURNS:            result of underlying DirectDraw call
+ *
+ * NOTES:              Updates the .fullscreen and .window members.
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+BOOL DirectDraw_GetCooperativeLevel( HWND *window, int *fullscreen )
+{
+    BOOL result = FALSE;
+
+    if( DirectDrawState.initialized )
+    {
+       *fullscreen = DirectDrawState.fullscreen;
+       *window = DirectDrawState.window;
+       result = TRUE;
+    }
+    return result;
+}
+
+/*
+ * FUNCTION:DirectDraw_SetDisplayMode
+ *
+ * PURPOSE:Change the display-mode to width x height pixels, with a given
+ *             vertical refresh-rate.
+ *
+ * PARAMETERS:
+ *   width   - width of display in pixels
+ *   height  - height of display in pixels
+ *   freq    - vertical refresh-rate in Hz
+ *
+ * RETURNS:
+ *   ddrval  - HRESULT indicating success (DD_OK) or failure
+ *
+ * NOTES:The freq parameter is only obeyed on when we're using DirectX 6
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+HRESULT DirectDraw_SetDisplayMode( int width, int height, int bits, int freq )
+{
+    HRESULT ddrval;
+
+    ddrval = IDirectDraw7_SetDisplayMode( DirectDrawState.directdraw.dd,
+                                          width, height, bits, freq, 0 );
+    DirectDrawState.modeset = 1;
+    return ddrval;
+}
+
+/*
+ * FUNCTION:DirectDraw_GetDisplayMode
+ *
+ * PURPOSE:Get the display-mode characteristics.
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS:
+ *   ddrval  - HRESULT indicating success (DD_OK) or failure
+ *
+ * NOTES:none
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+HRESULT DirectDraw_GetDisplayMode( void )
+{
+    HRESULT ddrval;
+
+    /* We fill in the current.desc in all cases */
+    DirectDrawState.current.desc.dwSize = sizeof( DDSURFACEDESC2 );
+    ddrval = IDirectDraw7_GetDisplayMode( DirectDrawState.directdraw.dd,
+                                         &DirectDrawState.current.desc );
+    return ddrval;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+HRESULT DirectDraw_GetCaps( DDCAPS_DX7 *driver_caps, DDCAPS_DX7 *hel_caps )
+{
+    HRESULT ddrval;
+
+    ddrval = IDirectDraw7_GetCaps( DirectDrawState.directdraw.dd,
+                                   driver_caps, hel_caps );
+    return ddrval;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+HRESULT DirectDraw_CreateClipper( void )
+{
+    HRESULT ddrval;
+    ddrval = IDirectDraw7_CreateClipper( DirectDrawState.directdraw.dd,
+                                         0,
+                                         &DirectDrawState.lpDDC,
+                                         NULL );
+    return ddrval;
+}
+
+static DWORD ConvertGDIColor( COLORREF dwGDIColor )
+{
+    COLORREF rgbT;
+    HDC hdc;
+    DWORD dw = CLR_INVALID;
+    DDSURFACEDESC2 ddsd,pdds;
+    HRESULT hr;
+
+    memset(&pdds,0,sizeof(pdds));
+    pdds.dwSize = sizeof(pdds);
+    IDirectDrawSurface7_GetSurfaceDesc(DirectDrawState.primary.surface, &pdds);
+
+    //  Use GDI SetPixel to color match for us
+    if( dwGDIColor != CLR_INVALID && IDirectDrawSurface7_GetDC(DirectDrawState.primary.surface, &hdc) == DD_OK)
+    {
+        rgbT = GetPixel(hdc, 0, 0);     // Save current pixel value
+        SetPixel(hdc, 0, 0, dwGDIColor);       // Set our value
+        IDirectDrawSurface7_ReleaseDC(DirectDrawState.primary.surface,hdc);
+    }
+
+    // Now lock the surface so we can read back the converted color
+    ddsd.dwSize = sizeof(ddsd);
+    hr = IDirectDrawSurface7_Lock(DirectDrawState.primary.surface, NULL, &ddsd, DDLOCK_WAIT, NULL );
+    if( hr == DD_OK)
+    {
+        dw = *(DWORD *) ddsd.lpSurface; 
+        if( ddsd.ddpfPixelFormat.dwRGBBitCount < 32 ) // Mask it to bpp
+            dw &= ( 1 << ddsd.ddpfPixelFormat.dwRGBBitCount ) - 1;
+       IDirectDrawSurface7_Unlock(DirectDrawState.primary.surface,NULL);
+    }
+
+    //  Now put the color that was there back.
+    if( dwGDIColor != CLR_INVALID && IDirectDrawSurface7_GetDC(DirectDrawState.primary.surface,&hdc) == DD_OK )
+    {
+        SetPixel( hdc, 0, 0, rgbT );
+       IDirectDrawSurface7_ReleaseDC(DirectDrawState.primary.surface,hdc);
+    }
+    
+    return dw;    
+}
+
+
+HRESULT DirectDraw_CreateOverlaySurface( int width, int height, int bits)
+{
+    DDSURFACEDESC2 ddsd;
+    DDPIXELFORMAT ddpfOverlayFormat;
+    HRESULT ddrval = DDERR_UNSUPPORTED;
+    DWORD dwDDSColor;
+
+    if( bOverlayAvailable )
+    {
+       write_log( "CreateOverlaySurface being called with %d-bits!\n", bits );
+       if( bits == 16 )
+       {
+           // Set the overlay format to 16 bit RGB 5:6:5
+           ZeroMemory( &ddpfOverlayFormat, sizeof(ddpfOverlayFormat) );
+           ddpfOverlayFormat.dwSize        = sizeof(ddpfOverlayFormat);
+           ddpfOverlayFormat.dwFlags       = DDPF_RGB;
+           ddpfOverlayFormat.dwRGBBitCount = 16;
+           ddpfOverlayFormat.dwRBitMask    = 0xF800; 
+           ddpfOverlayFormat.dwGBitMask    = 0x07E0;
+           ddpfOverlayFormat.dwBBitMask    = 0x001F; 
+       }
+       else if( bits == 32 )
+       {
+           // Set the overlay format to 32 bit ARGB 8:8:8:8
+           ZeroMemory( &ddpfOverlayFormat, sizeof(ddpfOverlayFormat) );
+           ddpfOverlayFormat.dwSize        = sizeof(ddpfOverlayFormat);
+           ddpfOverlayFormat.dwFlags       = DDPF_RGB;
+           ddpfOverlayFormat.dwRGBBitCount = 32;
+           ddpfOverlayFormat.dwRBitMask    = 0x00FF0000; 
+           ddpfOverlayFormat.dwGBitMask    = 0x0000FF00;
+           ddpfOverlayFormat.dwBBitMask    = 0x000000FF; 
+       }
+       else if( bits == 8 )
+       {
+           // Set the overlay format to 8 bit palette
+           ZeroMemory( &ddpfOverlayFormat, sizeof(ddpfOverlayFormat) );
+           ddpfOverlayFormat.dwSize        = sizeof(ddpfOverlayFormat);
+           ddpfOverlayFormat.dwFlags       = DDPF_RGB | DDPF_PALETTEINDEXED8;
+           ddpfOverlayFormat.dwRGBBitCount = 8;
+           ddpfOverlayFormat.dwRBitMask    = 0x00000000; 
+           ddpfOverlayFormat.dwGBitMask    = 0x00000000;
+           ddpfOverlayFormat.dwBBitMask    = 0x00000000; 
+       }
+       else
+       {
+           // We don't handle this case...
+           return DDERR_INVALIDPIXELFORMAT;
+       }
+    
+       // Setup the overlay surface's attributes in the surface descriptor
+       ZeroMemory( &ddsd, sizeof(ddsd) );
+       ddsd.dwSize            = sizeof(ddsd);
+       ddsd.dwFlags           = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
+       ddsd.ddsCaps.dwCaps    = DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY;
+       ddsd.dwWidth           = width;
+       ddsd.dwHeight          = height;
+       ddsd.ddpfPixelFormat   = ddpfOverlayFormat;
+
+       ZeroMemory(&overlayfx,sizeof(overlayfx));
+       overlayfx.dwSize = sizeof(overlayfx);
+       overlayflags = DDOVER_SHOW | DDOVER_DDFX | DDOVER_KEYDESTOVERRIDE;
+
+       dwDDSColor = ConvertGDIColor( g_dwBackgroundColor );
+       overlayfx.dckDestColorkey.dwColorSpaceLowValue  = dwDDSColor;
+       overlayfx.dckDestColorkey.dwColorSpaceHighValue = dwDDSColor;
+
+       // Attempt to create the surface with theses settings
+       ddrval = IDirectDraw7_CreateSurface ( DirectDrawState.directdraw.dd, &ddsd, &DirectDrawState.overlay.surface, NULL);
+       if( ddrval == DD_OK )
+       {
+#if 0
+           ddrval = IDirectDrawSurface7_QueryInterface( DirectDrawState.overlay.surface,
+                       &IID_IDirectDrawSurface7,(LPVOID *)&DirectDrawState.overlay.surface );
+#endif
+           DirectDrawState.isoverlay = 1;
+       }
+       else
+       {
+           DirectDrawState.isoverlay = 0;
+       }
+    }
+    else
+    {
+       write_log( "CreateOverlaySurface being called, but no overlay support with this card...!\n" );
+    }
+    return ddrval;
+}
+
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+HRESULT DirectDraw_CreateSurface( int width, int height )
+{
+    HRESULT ddrval;
+
+    DirectDrawState.flipping = single_buffer;
+
+    if( DirectDrawState.fullscreen ) // Create a flipping pair!
+    {
+       ZeroMemory( &DirectDrawState.primary.desc, sizeof( DDSURFACEDESC2 ) );
+       DirectDrawState.primary.desc.dwSize = sizeof( DDSURFACEDESC2 );
+       DirectDrawState.primary.desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
+       DirectDrawState.primary.desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
+       DirectDrawState.primary.desc.dwBackBufferCount = 2;
+       ddrval = IDirectDraw7_CreateSurface( DirectDrawState.directdraw.dd, 
+                                           &DirectDrawState.primary.desc,
+                                           &DirectDrawState.primary.surface,
+                                           NULL );
+       if( ddrval != DD_OK )
+       {
+           // Create a non-flipping pair, since the flipping pair creation failed...
+           ZeroMemory( &DirectDrawState.primary.desc, sizeof( DDSURFACEDESC2 ) );
+           DirectDrawState.primary.desc.dwSize = sizeof( DDSURFACEDESC2 );
+           DirectDrawState.primary.desc.dwFlags = DDSD_CAPS;
+           DirectDrawState.primary.desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+           ddrval = IDirectDraw7_CreateSurface( DirectDrawState.directdraw.dd, 
+                                               &DirectDrawState.primary.desc,
+                                               &DirectDrawState.primary.surface,
+                                               NULL );
+       }
+       else
+       {
+           DirectDrawState.flipping = triple_buffer;
+       }
+    }
+    else
+    {
+       // We're not full-screen, so you cannot create a flipping pair...
+
+       ZeroMemory( &DirectDrawState.primary.desc, sizeof( DDSURFACEDESC2 ) );
+       DirectDrawState.primary.desc.dwSize = sizeof( DDSURFACEDESC2 );
+       DirectDrawState.primary.desc.dwFlags = DDSD_CAPS;
+       DirectDrawState.primary.desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+       ddrval = IDirectDraw7_CreateSurface( DirectDrawState.directdraw.dd, 
+                                           &DirectDrawState.primary.desc,
+                                           &DirectDrawState.primary.surface,
+                                           NULL );
+    }
+
+    if( ddrval != DD_OK )
+    {
+       goto out;
+    }
+    else
+    {
+       write_log( "DDRAW: Primary %ssurface created in video-memory\n", DirectDrawState.flipping != single_buffer ? "flipping " : "" );
+    }
+
+    // Check if we can access the back-buffer of our flipping-pair (if present)
+    if( DirectDrawState.flipping != single_buffer )
+    {
+       DDSCAPS2 ddSCaps;
+       ZeroMemory(&ddSCaps, sizeof(ddSCaps));
+       ddSCaps.dwCaps = DDSCAPS_BACKBUFFER;
+
+       ddrval = IDirectDrawSurface7_GetAttachedSurface( DirectDrawState.primary.surface, &ddSCaps, &DirectDrawState.secondary.surface );
+       if( ddrval == DD_OK )
+       {
+           /* get third buffer */
+           ZeroMemory(&ddSCaps, sizeof(ddSCaps));
+           ddSCaps.dwCaps = DDSCAPS_FLIP;
+
+           ddrval = IDirectDrawSurface7_GetAttachedSurface( DirectDrawState.secondary.surface, &ddSCaps, &DirectDrawState.tertiary.surface );
+           if( ddrval == DD_OK )
+           {
+    #if 0
+               // Get our IDirectDrawSurface7 pointer
+               ddrval = IDirectDrawSurface7_QueryInterface( DirectDrawState.tertiary.surface,
+                                                           &IID_IDirectDrawSurface7,
+                                                           (LPVOID *)&DirectDrawState.tertiary.surface );
+               if( ddrval != DD_OK )
+               {
+                   goto out;
+               }
+    #endif
+           }
+           else
+           {
+               DirectDrawState.flipping = single_buffer;
+           }
+    #if 0
+           // Get our IDirectDrawSurface7 pointer
+           ddrval = IDirectDrawSurface_QueryInterface( DirectDrawState.secondary.surface,
+                                                       &IID_IDirectDrawSurface7,
+                                                       (LPVOID *)&DirectDrawState.secondary.surface );
+           if( ddrval != DD_OK )
+           {
+               goto out;
+           }
+#endif
+       }
+       else
+       {
+           DirectDrawState.flipping = single_buffer;
+       }
+    }
+
+#if 0
+    // Get our IDirectDrawSurface7 pointer
+    ddrval = IDirectDrawSurface7_QueryInterface( DirectDrawState.primary.surface,
+                                               &IID_IDirectDrawSurface7,
+                                               (LPVOID *)&DirectDrawState.primary.surface );
+
+    if( ddrval != DD_OK )
+    {
+       goto out;
+    }
+#endif
+
+    // We always want a secondary-buffer when creating our primary-surface.  If we're a flipping pair,
+    // the secondary buffer is already allocated.  If we failed to create a flipping pair, or because
+    // we're not full-screen, then lets create ourselves a back-buffer manually.
+    if( DirectDrawState.flipping == single_buffer )
+    {
+        ZeroMemory( &DirectDrawState.secondary.desc, sizeof( DDSURFACEDESC2 ) );
+        DirectDrawState.secondary.desc.dwSize = sizeof( DDSURFACEDESC2 );
+        DirectDrawState.secondary.desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+        DirectDrawState.secondary.desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+        DirectDrawState.secondary.desc.dwWidth = width;
+        DirectDrawState.secondary.desc.dwHeight = height;
+        ddrval = IDirectDraw7_CreateSurface( DirectDrawState.directdraw.dd, 
+                                            &DirectDrawState.secondary.desc,
+                                            &DirectDrawState.secondary.surface,
+                                            NULL );
+        if( ddrval != DD_OK )
+        {
+           write_log( "DDRAW:Secondary surface creation attempt #1 failed with %s\n", DXError(ddrval));
+            DirectDrawState.secondary.desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
+            ddrval = IDirectDraw7_CreateSurface( DirectDrawState.directdraw.dd, 
+                                                &DirectDrawState.secondary.desc,
+                                                &DirectDrawState.secondary.surface,
+                                                NULL );
+           if( ddrval == DD_OK )
+               write_log( "DDRAW: Secondary surface created in plain system-memory\n" );
+           else
+           {
+               goto out;
+           }
+        }
+        else
+        {
+            write_log( "DDRAW: Secondary surface created in video-memory\n" );
+        }
+#if 0
+       // Get our IDirectDrawSurface7 pointer
+        ddrval = IDirectDrawSurface7_QueryInterface( DirectDrawState.secondary.surface,
+                                                    &IID_IDirectDrawSurface7,
+                                                    (LPVOID *)&DirectDrawState.secondary.surface );
+        if( ddrval != DD_OK )
+        {
+           goto out;
+        }
+#endif
+    }
+out:
+    return ddrval;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+void DirectDraw_ClearSurfaces( void )
+{
+    DDBLTFX ddbltfx;
+    memset( &ddbltfx, 0, sizeof( ddbltfx ) );
+    ddbltfx.dwFillColor = 0;
+    ddbltfx.dwSize = sizeof( ddbltfx );
+
+    DirectDraw_Blt( secondary_surface, NULL, invalid_surface, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx );
+    if( DirectDrawState.isoverlay )
+       DirectDraw_Blt( overlay_surface, NULL, invalid_surface, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx );
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+int DirectDraw_DetermineLocking( int wantfull )
+{
+    int result = 0;
+
+    switch( DirectDrawState.surface_type = try_surface_locks( wantfull ) )
+    {
+    case invalid_surface:
+    case lockable_surface:
+        DirectDrawState.lockable.lpdesc = NULL;
+        DirectDrawState.lockable.lpdesc = NULL;
+        DirectDrawState.lockable.surface = NULL;
+        DirectDrawState.lockable.surface = NULL;
+        write_log( "set_ddraw: Couldn't lock primary, and no secondary available.\n" );
+        break;
+    case primary_surface:
+        DirectDrawState.lockable.lpdesc = &DirectDrawState.primary.desc;
+        DirectDrawState.lockable.lpdesc = &DirectDrawState.primary.desc;
+        DirectDrawState.lockable.surface = DirectDrawState.primary.surface;
+        DirectDrawState.lockable.surface = DirectDrawState.primary.surface;
+       result = 1;
+        break;
+    case overlay_surface:
+        DirectDrawState.lockable.lpdesc = &DirectDrawState.overlay.desc;
+        DirectDrawState.lockable.lpdesc = &DirectDrawState.overlay.desc;
+        DirectDrawState.lockable.surface = DirectDrawState.overlay.surface;
+        DirectDrawState.lockable.surface = DirectDrawState.overlay.surface;
+       result = 1;
+        break;
+    case secondary_surface:
+        DirectDrawState.lockable.lpdesc = &DirectDrawState.secondary.desc;
+        DirectDrawState.lockable.lpdesc = &DirectDrawState.secondary.desc;
+        DirectDrawState.lockable.surface = DirectDrawState.secondary.surface;
+        DirectDrawState.lockable.surface = DirectDrawState.secondary.surface;
+       result = 1;
+        break;
+    case tertiary_surface:
+        DirectDrawState.lockable.lpdesc = &DirectDrawState.tertiary.desc;
+        DirectDrawState.lockable.lpdesc = &DirectDrawState.tertiary.desc;
+        DirectDrawState.lockable.surface = DirectDrawState.tertiary.surface;
+        DirectDrawState.lockable.surface = DirectDrawState.tertiary.surface;
+       result = 1;
+        break;
+    }
+
+    if( DirectDrawState.lockable.surface )
+        DirectDraw_SurfaceUnlock();
+
+    return result;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+HRESULT DirectDraw_SetClipper( HWND hWnd )
+{
+    HRESULT ddrval;
+
+    ddrval = IDirectDrawSurface7_SetClipper( DirectDrawState.primary.surface,
+                                             hWnd ? DirectDrawState.lpDDC : NULL );
+    if( hWnd && ( ddrval == DD_OK ) )
+    {
+        ddrval = IDirectDrawClipper_SetHWnd( DirectDrawState.lpDDC, 0, hWnd );
+    }
+    return ddrval;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+HRESULT DirectDraw_GetClipList( LPRGNDATA cliplist, LPDWORD size )
+{
+    HRESULT ddrval;
+
+    ddrval = IDirectDrawClipper_GetClipList( DirectDrawState.lpDDC, NULL, cliplist, size );
+
+    return ddrval;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+BYTE DirectDraw_GetBytesPerPixel( void )
+{
+    int bpp;
+    bpp = ( DirectDrawState.lockable.lpdesc->ddpfPixelFormat.dwRGBBitCount + 7 ) >> 3;
+    return bpp;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+HRESULT DirectDraw_SetPalette( int remove )
+{
+    HRESULT ddrval;
+    if (DirectDrawState.primary.surface == NULL)
+       return DDERR_SURFACELOST;
+    ddrval = IDirectDrawSurface7_SetPalette (DirectDrawState.primary.surface,
+       remove ? NULL : DirectDrawState.lpDDP);
+    if (ddrval == DDERR_SURFACELOST) {
+       ddrval = restoresurface (DirectDrawState.primary.surface);
+       if (ddrval == DD_OK) {
+           ddrval = IDirectDrawSurface7_SetPalette (DirectDrawState.primary.surface,
+               remove ? NULL : DirectDrawState.lpDDP);
+       }
+    }
+    return ddrval;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+HRESULT DirectDraw_CreatePalette( LPPALETTEENTRY pal )
+{
+    HRESULT ddrval;
+    ddrval = IDirectDraw_CreatePalette( DirectDrawState.directdraw.dd,
+                                        DDPCAPS_8BIT | DDPCAPS_ALLOW256,
+                                        pal, &DirectDrawState.lpDDP, NULL);
+    if( ddrval == DD_OK )
+    {
+        ddrval = DirectDraw_SetPalette(0);
+    }
+    return ddrval;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+HRESULT DirectDraw_SetPaletteEntries( int start, int count, PALETTEENTRY *palette )
+{
+    HRESULT ddrval = DDERR_NOPALETTEATTACHED;
+    int i;
+    if( DirectDrawState.lpDDP )
+        ddrval = IDirectDrawPalette_SetEntries( DirectDrawState.lpDDP, 0, start, count, palette );
+    return ddrval;
+}
+
+/* Return one of the pixel formats declared in picasso96.h if the surface
+ * is usable for us, or RGBFB_NONE if it is not usable.  */
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+RGBFTYPE DirectDraw_GetSurfacePixelFormat( LPDDSURFACEDESC2 surface )
+{
+    int surface_is = 0;
+    DDPIXELFORMAT *pfp = NULL;
+    DWORD r, g, b;
+    DWORD surf_flags;
+
+    surf_flags = surface->dwFlags;
+    pfp = &surface->ddpfPixelFormat;
+
+    if( ( surf_flags & DDSD_PIXELFORMAT ) == 0x0 )
+       return RGBFB_NONE;
+
+    if ((pfp->dwFlags & DDPF_RGB) == 0)
+       return RGBFB_NONE;
+
+    r = pfp->dwRBitMask;
+    g = pfp->dwGBitMask;
+    b = pfp->dwBBitMask;
+    switch (pfp->dwRGBBitCount) {
+     case 8:
+       if ((pfp->dwFlags & DDPF_PALETTEINDEXED8) != 0)
+           return RGBFB_CHUNKY;
+       break;
+
+     case 16:
+       if (r == 0xF800 && g == 0x07E0 && b == 0x001F)
+           return RGBFB_R5G6B5PC;
+       if (r == 0x7C00 && g == 0x03E0 && b == 0x001F)
+           return RGBFB_R5G5B5PC;
+       if (b == 0xF800 && g == 0x07E0 && r == 0x001F)
+           return RGBFB_B5G6R5PC;
+       if (b == 0x7C00 && g == 0x03E0 && r == 0x001F)
+           return RGBFB_B5G5R5PC;
+       /* This happens under NT - with r == b == g == 0 !!! */
+       write_log ("Unknown 16 bit format %d %d %d\n", r, g, b);
+       break;
+
+     case 24:
+       if (r == 0xFF0000 && g == 0x00FF00 && b == 0x0000FF)
+           return RGBFB_B8G8R8;
+       if (r == 0x0000FF && g == 0x00FF00 && b == 0xFF0000)
+           return RGBFB_R8G8B8;
+       break;
+
+     case 32:
+       if (r == 0x00FF0000 && g == 0x0000FF00 && b == 0x000000FF)
+           return RGBFB_B8G8R8A8;
+       if (r == 0x000000FF && g == 0x0000FF00 && b == 0x00FF0000)
+           return RGBFB_R8G8B8A8;
+       if (r == 0xFF000000 && g == 0x00FF0000 && b == 0x0000FF00)
+           return RGBFB_A8B8G8R8;
+       if (r == 0x0000FF00 && g == 0x00FF0000 && b == 0xFF000000)
+           return RGBFB_A8R8G8B8;
+       break;
+       
+     default:
+       write_log ("Unknown %d bit format %d %d %d\n", pfp->dwRGBBitCount, r, g, b); /* %%% - BERND, and here too... */
+       break;
+    }
+    return RGBFB_NONE;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+RGBFTYPE DirectDraw_GetPixelFormat( void )
+{
+    RGBFTYPE type;
+    if( DirectDrawState.lockable.lpdesc )
+       type = DirectDraw_GetSurfacePixelFormat( DirectDrawState.lockable.lpdesc );
+    else
+       type = DirectDraw_GetSurfacePixelFormat( &DirectDrawState.current.desc );
+    return type;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+DWORD DirectDraw_CurrentWidth( void )
+{
+    DWORD width;
+    width = DirectDrawState.current.desc.dwWidth;
+    return width;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+DWORD DirectDraw_CurrentHeight( void )
+{
+    DWORD height;
+    height = DirectDrawState.current.desc.dwHeight;
+    return height;
+}
+
+int DirectDraw_GetVerticalBlankStatus (void)
+{
+    BOOL status;
+    if (IDirectDraw7_GetVerticalBlankStatus (DirectDrawState.directdraw.dd, &status) != DD_OK)
+       return -1;
+    return status;
+}
+
+DWORD DirectDraw_CurrentRefreshRate( void )
+{
+    DWORD height;
+    height = DirectDrawState.current.desc.dwRefreshRate;
+    return height;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+static int DirectDraw_BltFastStub4( LPDIRECTDRAWSURFACE7 dstsurf, DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 srcsurf, LPRECT srcrect )
+{
+    int result = 0;
+    HRESULT ddrval;
+
+    while( ( ddrval = IDirectDrawSurface7_BltFast( dstsurf, x, y, srcsurf, srcrect, DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT ) ) != DD_OK )
+    {
+        if (ddrval == DDERR_SURFACELOST) 
+        {
+           ddrval = restoresurface ( dstsurf );
+            if (ddrval != DD_OK)
+            {
+                break;
+            }
+        }
+        else if (ddrval != DDERR_SURFACEBUSY) 
+        {
+           write_log("BltFastStub7(): DirectDrawSURFACE7_BltFast() failed with %s\n", DXError (ddrval));
+            break;
+        }
+    }
+    if( ddrval == DD_OK )
+    {
+        result = 1;
+    }
+    return result;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+int DirectDraw_BltFast( surface_type_e dsttype, DWORD left, DWORD top, surface_type_e srctype, LPRECT srcrect )
+{
+    int result;
+
+    LPDIRECTDRAWSURFACE7 lpDDS4_dst, lpDDS4_src;
+    if( dsttype == primary_surface )
+    {
+        lpDDS4_dst = DirectDrawState.primary.surface;
+    }
+    else
+    {
+        lpDDS4_dst = DirectDrawState.secondary.surface;
+    }
+    if( srctype == primary_surface )
+    {
+        lpDDS4_src = DirectDrawState.primary.surface;
+    }
+    else
+    {
+        lpDDS4_src = DirectDrawState.secondary.surface;
+    }
+    result = DirectDraw_BltFastStub4( lpDDS4_dst, left, top, lpDDS4_src, srcrect );
+    return result;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+static int DirectDraw_BltStub( LPDIRECTDRAWSURFACE7 dstsurf, LPRECT dstrect, LPDIRECTDRAWSURFACE7 srcsurf, LPRECT srcrect, DWORD flags, LPDDBLTFX ddbltfx )
+{
+    int result = 0, errcnt = 0;
+    HRESULT ddrval;
+
+    while( ( ddrval = IDirectDrawSurface7_Blt( dstsurf, dstrect, srcsurf, srcrect, flags, ddbltfx ) ) != DD_OK )
+    {
+        if (ddrval == DDERR_SURFACELOST) 
+        {
+           if (errcnt > 10)
+               break;
+           errcnt++;
+           ddrval = restoresurface ( dstsurf );
+            if (ddrval != DD_OK)
+            {
+                break;
+            }
+        }
+        else if (ddrval != DDERR_SURFACEBUSY) 
+        {
+           write_log("BltStub(): DirectDrawSURFACE7_Blt() failed with %s\n", DXError (ddrval));
+            break;
+        }
+#if 0
+       else
+       {
+           write_log( "Blt() failed - %s\n", DXError (ddrval));
+           result = 0;
+           break;
+       }
+#endif
+    }
+    if( ddrval == DD_OK )
+    {
+        result = 1;
+    }
+    return result;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+
+int DirectDraw_Flip( int wait )
+{
+    int result = 0;
+    HRESULT ddrval = DD_OK;
+    DWORD flags = DDFLIP_WAIT;
+    int start = read_processor_time();
+    static int skip;
+
+    if( DirectDrawState.flipping == triple_buffer )
+    {
+       if (!currprefs.gfx_afullscreen && !currprefs.gfx_vsync) {
+           ddrval = IDirectDrawSurface7_Flip( DirectDrawState.primary.surface, NULL, flags | DDFLIP_NOVSYNC);
+       } else if (currprefs.gfx_vsync) {
+           if (vblank_skip >= 0) {
+               skip++;
+               if (vblank_skip > skip) {
+                   ddrval = IDirectDrawSurface7_Flip( DirectDrawState.primary.surface, NULL, flags | DDFLIP_NOVSYNC);
+               } else {
+                   skip = 0;
+                   ddrval = IDirectDrawSurface7_Flip( DirectDrawState.primary.surface, NULL, flags );
+                   idletime += read_processor_time() - start;
+               }
+           } else {
+               if (flipinterval_supported) {
+                   ddrval = IDirectDrawSurface7_Flip( DirectDrawState.primary.surface, NULL, flags | DDFLIP_INTERVAL2 );
+                   idletime += read_processor_time() - start;
+               } else {
+                   ddrval = IDirectDrawSurface7_Flip( DirectDrawState.primary.surface, NULL, flags );
+                   idletime += read_processor_time() - start;
+                   result = DirectDraw_BltFast( tertiary_surface, 0, 0, primary_surface, NULL );
+                   start = read_processor_time();
+                   ddrval = IDirectDrawSurface7_Flip( DirectDrawState.primary.surface, NULL, flags );
+                   idletime += read_processor_time() - start;
+               }
+           }
+       } else {
+           ddrval = IDirectDrawSurface7_Flip( DirectDrawState.primary.surface, NULL, flags );
+       }
+    } else if( DirectDrawState.flipping == double_buffer ) {
+       if (!currprefs.gfx_afullscreen && !currprefs.gfx_vsync) {
+           ddrval = IDirectDrawSurface7_Flip( DirectDrawState.primary.surface, NULL, flags | DDFLIP_NOVSYNC);
+       } else {
+           ddrval = IDirectDrawSurface7_Flip( DirectDrawState.primary.surface, NULL, flags );
+           idletime += read_processor_time() - start;
+       }
+    } else {
+       return 1;
+    }
+    if( ddrval == DD_OK )
+        result = 1;
+    else
+       write_log("FLIP: DirectDrawSurface_Flip() failed with %s\n", DXError (ddrval));
+    return result;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+int DirectDraw_Blt( surface_type_e dsttype, LPRECT dstrect,
+                    surface_type_e srctype, LPRECT srcrect,
+                    DWORD flags, LPDDBLTFX fx )
+{
+    int result;
+
+    LPDIRECTDRAWSURFACE7 lpDDS4_dst, lpDDS4_src;
+    
+    if( dsttype == primary_surface )
+    {
+       if( DirectDrawState.isoverlay )
+           lpDDS4_dst = DirectDrawState.overlay.surface;
+       else
+           lpDDS4_dst = DirectDrawState.primary.surface;
+    }
+    else if( dsttype == secondary_surface )
+    {
+        lpDDS4_dst = DirectDrawState.secondary.surface;
+    }
+    else if( dsttype == tertiary_surface )
+    {
+        lpDDS4_dst = DirectDrawState.tertiary.surface;
+    }
+    else
+    {
+       lpDDS4_dst = DirectDrawState.overlay.surface;
+    }
+
+    if( srctype == primary_surface )
+    {
+        lpDDS4_src = DirectDrawState.primary.surface;
+    }
+    else if( srctype == secondary_surface )
+    {
+        lpDDS4_src = DirectDrawState.secondary.surface;
+    }
+    else if( srctype == tertiary_surface )
+    {
+        lpDDS4_src = DirectDrawState.tertiary.surface;
+    }
+    else if( srctype == overlay_surface )
+    {
+       lpDDS4_src = DirectDrawState.overlay.surface;
+    }
+    else
+    {
+       lpDDS4_src = NULL; /* For using BltStub to do rect-fills */
+    }
+    result = DirectDraw_BltStub( lpDDS4_dst, dstrect, lpDDS4_src, srcrect, flags, fx );
+    return result;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+HRESULT DirectDraw_WaitForVerticalBlank( DWORD flags )
+{
+    HRESULT result;
+    result = IDirectDraw7_WaitForVerticalBlank( DirectDrawState.directdraw.dd, flags, NULL );
+    return result;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+HRESULT DirectDraw_EnumDisplayModes( DWORD flags, LPDDENUMMODESCALLBACK2 callback )
+{
+    HRESULT result;
+    result = IDirectDraw7_EnumDisplayModes( DirectDrawState.directdraw.dd, flags, NULL, NULL, callback );    
+    return result;
+}
+
+HRESULT DirectDraw_EnumDisplays(LPDDENUMCALLBACKEX callback )
+{
+    HRESULT result;
+    result = DirectDrawEnumerateEx (callback, 0, DDENUM_DETACHEDSECONDARYDEVICES | DDENUM_ATTACHEDSECONDARYDEVICES);
+    return result;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+HRESULT DirectDraw_FlipToGDISurface( void )
+{
+    HRESULT result = DDERR_GENERIC;
+    if( DirectDrawState.initialized )
+    {
+       result = IDirectDraw7_FlipToGDISurface( DirectDrawState.directdraw.dd );
+    }
+    return result;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+HRESULT DirectDraw_GetDC( HDC *hdc, surface_type_e surface )
+{
+    HRESULT result = ~DD_OK;
+    if( surface == primary_surface )
+        result = IDirectDrawSurface7_GetDC( DirectDrawState.primary.surface, hdc );
+    else if (surface == overlay_surface)
+        result = IDirectDrawSurface7_GetDC( DirectDrawState.overlay.surface, hdc );
+    else if (surface == secondary_surface)
+        result = IDirectDrawSurface7_GetDC( DirectDrawState.secondary.surface, hdc );
+    return result;
+}
+
+/*
+ * FUNCTION:
+ *
+ * PURPOSE:
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ * NOTES:
+ *
+ * HISTORY:
+ *   1999.08.02  Brian King             Creation
+ *
+ */
+HRESULT DirectDraw_ReleaseDC( HDC hdc, surface_type_e surface )
+{
+    HRESULT result;
+    if( surface == primary_surface )
+        result = IDirectDrawSurface7_ReleaseDC( DirectDrawState.primary.surface, hdc );
+    else if (surface == overlay_surface)
+        result = IDirectDrawSurface7_ReleaseDC( DirectDrawState.overlay.surface, hdc );
+    else
+        result = IDirectDrawSurface7_ReleaseDC( DirectDrawState.secondary.surface, hdc );
+    return result;
+}
+
+extern int display_change_requested;
+
+HRESULT DirectDraw_UpdateOverlay( RECT sr, RECT dr )
+{
+    HRESULT result = DD_OK;
+
+    if (DirectDrawState.isoverlay && DirectDrawState.overlay.surface)
+    {
+       if ((drivercaps.dwCaps & DDCAPS_ALIGNBOUNDARYSRC) && drivercaps.dwAlignBoundarySrc)
+           sr.left = (sr.left + drivercaps.dwAlignBoundarySrc / 2) & ~(drivercaps.dwAlignBoundarySrc - 1);
+       if ((drivercaps.dwCaps & DDCAPS_ALIGNSIZESRC) && drivercaps.dwAlignSizeSrc)
+           sr.right = sr.left + (sr.right - sr.left + drivercaps.dwAlignSizeSrc / 2) & ~(drivercaps.dwAlignSizeSrc - 1);
+       if ((drivercaps.dwCaps & DDCAPS_ALIGNBOUNDARYDEST) && drivercaps.dwAlignBoundaryDest)
+           dr.left = (dr.left + drivercaps.dwAlignBoundaryDest / 2) & ~(drivercaps.dwAlignBoundaryDest - 1);    
+       if ((drivercaps.dwCaps & DDCAPS_ALIGNSIZEDEST) && drivercaps.dwAlignSizeDest)
+           dr.right = dr.left + (dr.right - dr.left) & ~(drivercaps.dwAlignSizeDest - 1);
+       result = IDirectDrawSurface7_UpdateOverlay( DirectDrawState.overlay.surface, &sr, DirectDrawState.primary.surface, &dr, overlayflags, &overlayfx);
+       
+    }
+    if (result != DD_OK) {
+       if (result == DDERR_SURFACELOST)
+           display_change_requested++;
+       write_log ("UpdateOverlay failed %s\n", DXError (result));
+    }
+    return DD_OK;
+}
+
+char *outGUID (GUID *guid)
+{
+    static char gb[64];
+    if (guid == NULL)
+       return "NULL";
+    sprintf(gb, "%08.8X-%04.8X-%04.8X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X",
+       guid->Data1, guid->Data2, guid->Data3,
+       guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
+       guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
+    return gb;
+}
+
+
diff --git a/od-win32/dxwrap.h b/od-win32/dxwrap.h
new file mode 100755 (executable)
index 0000000..9ae22dd
--- /dev/null
@@ -0,0 +1,249 @@
+#ifndef __DXWRAP_H__
+#define __DXWRAP_H__
+
+#include "ddraw.h"
+
+struct ScreenResolution
+{
+    uae_u32 width;  /* in pixels */
+    uae_u32 height; /* in pixels */
+};
+
+#define MAX_PICASSO_MODES 300
+#define MAX_REFRESH_RATES 100
+struct PicassoResolution
+{
+    struct Resolutions *next;
+    struct ScreenResolution res;
+    int depth;   /* depth in bytes-per-pixel */
+    int refresh[MAX_REFRESH_RATES]; /* refresh-rates in Hz */
+    char name[25];
+    /* Bit mask of RGBFF_xxx values.  */
+    uae_u32 colormodes;
+};
+extern struct PicassoResolution *DisplayModes;
+extern GUID *displayGUID;
+
+#define MAX_DISPLAYS 10
+struct MultiDisplay {
+    int primary, disabled;
+    GUID guid;
+    char *name;
+    struct PicassoResolution *DisplayModes;
+};
+extern struct MultiDisplay Displays[MAX_DISPLAYS];
+
+typedef enum {
+    BLIT_FALSE,
+    BLIT_NOR,
+    BLIT_ONLYDST,
+    BLIT_NOTSRC,
+    BLIT_ONLYSRC,
+    BLIT_NOTDST,
+    BLIT_EOR,
+    BLIT_NAND,
+    BLIT_AND,
+    BLIT_NEOR,
+    BLIT_DST,
+    BLIT_NOTONLYSRC,
+    BLIT_SRC,
+    BLIT_NOTONLYDST,
+    BLIT_OR,
+    BLIT_TRUE,
+    BLIT_LAST
+} BLIT_OPCODE;
+
+/* Types for RGBFormat used */
+typedef enum {
+    RGBFB_NONE,                /* no valid RGB format (should not happen) */
+    RGBFB_CLUT,                /* palette mode, set colors when opening screen using
+                          tags or use SetRGB32/LoadRGB32(...) */
+    RGBFB_R8G8B8,      /* TrueColor RGB (8 bit each) */
+    RGBFB_B8G8R8,      /* TrueColor BGR (8 bit each) */
+    RGBFB_R5G6B5PC,    /* HiColor16 (5 bit R, 6 bit G, 5 bit B),
+                          format: gggbbbbbrrrrrggg */
+    RGBFB_R5G5B5PC,    /* HiColor15 (5 bit each), format: gggbbbbb0rrrrrgg */
+    RGBFB_A8R8G8B8,    /* 4 Byte TrueColor ARGB (A unused alpha channel) */
+    RGBFB_A8B8G8R8,    /* 4 Byte TrueColor ABGR (A unused alpha channel) */
+    RGBFB_R8G8B8A8,    /* 4 Byte TrueColor RGBA (A unused alpha channel) */
+    RGBFB_B8G8R8A8,    /* 4 Byte TrueColor BGRA (A unused alpha channel) */
+    RGBFB_R5G6B5,      /* HiColor16 (5 bit R, 6 bit G, 5 bit B),
+                          format: rrrrrggggggbbbbb */
+    RGBFB_R5G5B5,      /* HiColor15 (5 bit each), format: 0rrrrrgggggbbbbb */
+    RGBFB_B5G6R5PC,    /* HiColor16 (5 bit R, 6 bit G, 5 bit B),
+                          format: gggrrrrrbbbbbggg */
+    RGBFB_B5G5R5PC,    /* HiColor15 (5 bit each), format: gggrrrrr0bbbbbbgg */
+
+    /* By now, the following formats are for use with a hardware window only
+       (bitmap operations may be implemented incompletely) */
+
+    RGBFB_Y4U2V2,      /* 2 Byte TrueColor YUV (CCIR recommendation CCIR601).
+                          Each two-pixel unit is stored as one longword
+                          containing luminance (Y) for each of the two pixels,
+                          and chrominance (U,V) for alternate pixels.
+                          The missing chrominance values are generated by
+                          interpolation. (Y1-U0-Y0-V0) */
+    RGBFB_Y4U1V1,      /* 1 Byte TrueColor ACCUPAK. Four adjacent pixels form
+                          a packet of 5 bits Y (luminance) each pixel and 6 bits
+                          U and V (chrominance) shared by the four pixels */
+
+    RGBFB_MaxFormats
+} RGBFTYPE;
+
+#define RGBFF_NONE     (1<<RGBFB_NONE)
+#define RGBFF_CLUT     (1<<RGBFB_CLUT)
+#define RGBFF_R8G8B8   (1<<RGBFB_R8G8B8)
+#define RGBFF_B8G8R8   (1<<RGBFB_B8G8R8)
+#define RGBFF_R5G6B5PC (1<<RGBFB_R5G6B5PC)
+#define RGBFF_R5G5B5PC (1<<RGBFB_R5G5B5PC)
+#define RGBFF_A8R8G8B8 (1<<RGBFB_A8R8G8B8)
+#define RGBFF_A8B8G8R8 (1<<RGBFB_A8B8G8R8)
+#define RGBFF_R8G8B8A8 (1<<RGBFB_R8G8B8A8)
+#define RGBFF_B8G8R8A8 (1<<RGBFB_B8G8R8A8)
+#define RGBFF_R5G6B5   (1<<RGBFB_R5G6B5)
+#define RGBFF_R5G5B5   (1<<RGBFB_R5G5B5)
+#define RGBFF_B5G6R5PC (1<<RGBFB_B5G6R5PC)
+#define RGBFF_B5G5R5PC (1<<RGBFB_B5G5R5PC)
+#define RGBFF_Y4U2V2   (1<<RGBFB_Y4U2V2)
+#define RGBFF_Y4U1V1   (1<<RGBFB_Y4U1V1)
+
+#define RGBMASK_8BIT RGBFF_CLUT
+#define RGBMASK_16BIT (RGBFF_R5G6B5PC | RGBFF_B5G6R5PC | RGBFF_R5G6B5)
+#define RGBMASK_15BIT (RGBFF_R5G5B5PC | RGBFF_B5G5R5PC | RGBFF_R5G5B5)
+#define RGBMASK_24BIT (RGBFF_R8G8B8 | RGBFF_B8G8R8)
+#define RGBMASK_32BIT (RGBFF_A8R8G8B8 | RGBFF_A8B8G8R8 | RGBFF_R8G8B8A8 | RGBFF_B8G8R8A8)
+
+/************************************************************************/
+
+#define        RGBFF_PLANAR    RGBFF_NONE
+#define        RGBFF_CHUNKY    RGBFF_CLUT
+
+#define        RGBFB_PLANAR    RGBFB_NONE
+#define        RGBFB_CHUNKY    RGBFB_CLUT
+
+typedef enum
+{
+    red_mask,
+    green_mask,
+    blue_mask
+} DirectDraw_Mask_e;
+
+typedef enum
+{
+    invalid_surface,
+    primary_surface,
+    secondary_surface,
+    tertiary_surface,
+    overlay_surface,
+    lockable_surface
+} surface_type_e;
+
+typedef enum
+{
+    single_buffer,
+    double_buffer,
+    triple_buffer
+} flipping;
+
+struct DirectDrawSurfaceMapper
+{
+    int initialized;
+    int fullscreen;
+    int isoverlay;
+    int flipping;
+    int locked;
+    int modeset;
+    HWND window;
+    struct
+    {
+        LPDIRECTDRAW ddx;
+        LPDIRECTDRAW7 dd;
+    } directdraw;
+    struct
+    {
+        LPDIRECTDRAWSURFACE7 surface;
+        DDSURFACEDESC2 desc;
+    } primary;
+    struct
+    {
+        LPDIRECTDRAWSURFACE7 surface;
+        DDSURFACEDESC2 desc;
+    } secondary;
+    struct
+    {
+        LPDIRECTDRAWSURFACE7 surface;
+        DDSURFACEDESC2 desc;
+    } tertiary;
+    struct
+    {
+        LPDIRECTDRAWSURFACE7 surface;
+        DDSURFACEDESC2 desc;
+    } overlay;
+    struct
+    {
+        DDSURFACEDESC2 desc;
+    } current;
+    struct
+    {
+        LPDIRECTDRAWSURFACE7 surface;
+        LPDDSURFACEDESC2 lpdesc;
+    } lockable;
+    LPDIRECTDRAWCLIPPER lpDDC;
+    LPDIRECTDRAWPALETTE lpDDP;
+    LPDIRECTDRAWPALETTE lpOverlayDDP;
+    surface_type_e surface_type;
+};
+HRESULT DirectDraw_CreateOverlaySurface( int width, int height, int bits );
+int DirectDraw_Start( GUID *);
+void DirectDraw_Release( void );
+HRESULT DirectDraw_SetCooperativeLevel( HWND window, int want_fullscreen );
+BOOL DirectDraw_GetCooperativeLevel( HWND *window, int *fullscreen );
+HRESULT DirectDraw_SetDisplayMode( int width, int height, int bits, int freq );
+HRESULT DirectDraw_GetDisplayMode( void );
+HRESULT DirectDraw_CreateClipper( void );
+HRESULT DirectDraw_GetCaps( DDCAPS_DX7 *driver_caps, DDCAPS_DX7 *hel_caps );
+HRESULT DirectDraw_CreateSurface( int width, int height );
+void    DirectDraw_ClearSurfaces( void );
+HRESULT DirectDraw_SetClipper( HWND hWnd );
+HRESULT DirectDraw_GetClipList( LPRGNDATA cliplist, LPDWORD size );
+HRESULT DirectDraw_CreatePalette( LPPALETTEENTRY pal );
+HRESULT DirectDraw_SetPalette( int remove );
+HRESULT DirectDraw_SetPaletteEntries( int start, int count, PALETTEENTRY *palette );
+HRESULT DirectDraw_WaitForVerticalBlank( DWORD flags );
+HRESULT DirectDraw_EnumDisplayModes( DWORD flags, LPDDENUMMODESCALLBACK2 callback );
+HRESULT DirectDraw_EnumDisplays(LPDDENUMCALLBACKEX callback );
+HRESULT DirectDraw_FlipToGDISurface( void );
+HRESULT DirectDraw_GetDC( HDC *hdc, surface_type_e surface );
+HRESULT DirectDraw_ReleaseDC( HDC hdc, surface_type_e surface );
+int DirectDraw_Flip( int );
+HRESULT DirectDraw_UpdateOverlay(RECT sr, RECT dr);
+int DirectDraw_Blt( surface_type_e dsttype, LPRECT dstrect, surface_type_e srctype, LPRECT srcrect, DWORD flags, LPDDBLTFX fx );
+int DirectDraw_BltFast( surface_type_e dsttype, DWORD left, DWORD top, surface_type_e srctype, LPRECT srcrect );
+DWORD DirectDraw_GetPixelFormatBitMask( DirectDraw_Mask_e mask );
+RGBFTYPE DirectDraw_GetPixelFormat( void );
+DWORD DirectDraw_GetPixelFormatFlags( void );
+DWORD DirectDraw_GetSurfaceFlags( void );
+DWORD DirectDraw_GetSurfaceBitCount( void );
+DWORD DirectDraw_GetPrimaryBitCount( void );
+void DirectDraw_GetPrimaryWidthHeight(int *w, int *h);
+int DirectDraw_DetermineLocking( int wantfull );
+BYTE DirectDraw_GetBytesPerPixel( void );
+RGBFTYPE DirectDraw_GetSurfacePixelFormat( LPDDSURFACEDESC2 surface );
+surface_type_e DirectDraw_GetLockableType( void );
+int DirectDraw_SurfaceLock( surface_type_e surface_type );
+BOOL DirectDraw_IsLocked( void );
+char *DirectDraw_GetSurfacePointer( void );
+LONG DirectDraw_GetSurfacePitch( void );
+DWORD DirectDraw_CurrentWidth( void );
+DWORD DirectDraw_CurrentHeight( void );
+DWORD DirectDraw_CurrentRefreshRate (void);
+int DirectDraw_GetVerticalBlankStatus (void);
+
+extern void ddraw_unlockscr (void);
+#define DirectDraw_SurfaceUnlock() ddraw_unlockscr()
+
+extern const char *DXError (HRESULT hr);
+
+extern char *outGUID (GUID *guid);
+
+#endif
diff --git a/od-win32/fsdb_win32.c b/od-win32/fsdb_win32.c
new file mode 100755 (executable)
index 0000000..edca552
--- /dev/null
@@ -0,0 +1,184 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Library of functions to make emulated filesystem as independent as
+  * possible of the host filesystem's capabilities.
+  * This is the Win32 version.
+  *
+  * Copyright 1997 Mathias Ortmann
+  * Copyright 1999 Bernd Schmidt
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "fsdb.h"
+#include <windows.h>
+
+/* these are deadly (but I think allowed on the Amiga): */
+#define NUM_EVILCHARS 7
+static char evilchars[NUM_EVILCHARS] = { '\\', '*', '?', '\"', '<', '>', '|' };
+
+/* Return nonzero for any name we can't create on the native filesystem.  */
+int fsdb_name_invalid (const char *n)
+{
+    int i;
+    char a = n[0];
+    char b = (a == '\0' ? a : n[1]);
+    char c = (b == '\0' ? b : n[2]);
+    char d = (c == '\0' ? c : n[3]);
+    int l = strlen (n), ll;
+
+    if (a >= 'a' && a <= 'z')
+        a -= 32;
+    if (b >= 'a' && b <= 'z')
+        b -= 32;
+    if (c >= 'a' && c <= 'z')
+        c -= 32;
+
+    /* reserved dos devices */
+    ll = 0;
+    if (a == 'A' && b == 'U' && c == 'X') ll = 3; /* AUX  */
+    if (a == 'C' && b == 'O' && c == 'N') ll = 3; /* CON  */
+    if (a == 'P' && b == 'R' && c == 'N') ll = 3; /* PRN  */
+    if (a == 'N' && b == 'U' && c == 'L') ll = 3; /* NUL  */
+    if (a == 'L' && b == 'P' && c == 'T'  && (d >= '0' && d <= '9')) ll = 4;  /* LPT# */
+    if (a == 'C' && b == 'O' && c == 'M'  && (d >= '0' && d <= '9')) ll = 4; /* COM# */
+    /* AUX.anything, CON.anything etc.. are also illegal names */
+    if (ll && (l == ll || (l > ll && n[ll] == '.')))
+       return 1;
+
+    /* spaces and periods at the end are a no-no */
+    i = l - 1;
+    if (n[i] == '.' || n[i] == ' ')
+       return 1;
+
+    /* these characters are *never* allowed */
+    for (i = 0; i < NUM_EVILCHARS; i++) {
+        if (strchr (n, evilchars[i]) != 0)
+            return 1;
+    }
+
+    /* the reserved fsdb filename */
+    if (strcmp (n, FSDB_FILE) == 0)
+       return 1;
+    return 0; /* the filename passed all checks, now it should be ok */
+}
+
+uae_u32 filesys_parse_mask(uae_u32 mask)
+{
+    return mask ^ 0xf;
+}
+
+int fsdb_exists (char *nname)
+{
+    if (GetFileAttributes(nname) == 0xFFFFFFFF)
+       return 0;
+    return 1;
+}
+
+/* For an a_inode we have newly created based on a filename we found on the
+ * native fs, fill in information about this file/directory.  */
+int fsdb_fill_file_attrs (a_inode *aino)
+{
+    int mode;
+
+    if((mode = GetFileAttributes(aino->nname)) == 0xFFFFFFFF) {
+       write_log("GetFileAttributes('%s') failed! error=%d, aino=%p dir=%d\n", aino->nname,GetLastError(),aino,aino->dir);
+       return 0;
+    }
+
+    aino->dir = (mode & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0;
+    aino->amigaos_mode = A_FIBF_EXECUTE | A_FIBF_READ;
+    if (FILE_ATTRIBUTE_ARCHIVE & mode)
+       aino->amigaos_mode |= A_FIBF_ARCHIVE;
+    if (! (FILE_ATTRIBUTE_READONLY & mode))
+       aino->amigaos_mode |= A_FIBF_WRITE | A_FIBF_DELETE;
+    aino->amigaos_mode = filesys_parse_mask(aino->amigaos_mode);
+    return 1;
+}
+
+int fsdb_set_file_attrs (a_inode *aino, int mask)
+{
+    struct stat statbuf;
+    uae_u32 mode=0, tmpmask;
+
+    tmpmask = filesys_parse_mask(mask);
+
+    if (stat (aino->nname, &statbuf) == -1)
+       return ERROR_OBJECT_NOT_AROUND;
+
+    /* Unix dirs behave differently than AmigaOS ones.  */
+    /* windows dirs go where no dir has gone before...  */
+    if (! aino->dir) {
+       if ((tmpmask & (A_FIBF_READ | A_FIBF_DELETE)) == 0)
+           mode |= FILE_ATTRIBUTE_READONLY;
+       if (tmpmask & A_FIBF_ARCHIVE)
+           mode |= FILE_ATTRIBUTE_ARCHIVE;
+       else
+           mode &= ~FILE_ATTRIBUTE_ARCHIVE;
+
+       SetFileAttributes(aino->nname, mode);
+    }
+
+    aino->amigaos_mode = mask;
+    aino->dirty = 1;
+    return 0;
+}
+
+/* Return nonzero if we can represent the amigaos_mode of AINO within the
+ * native FS.  Return zero if that is not possible.  */
+int fsdb_mode_representable_p (const a_inode *aino)
+{
+    int mask = aino->amigaos_mode;
+    int m1;
+
+    if (aino->dir)
+       return aino->amigaos_mode == 0;
+
+    /* P or S set, or E or R clear, means we can't handle it.  */
+    if (mask & (A_FIBF_SCRIPT | A_FIBF_PURE | A_FIBF_EXECUTE | A_FIBF_READ))
+       return 0;
+    m1 = A_FIBF_DELETE | A_FIBF_WRITE;
+    /* If it's rwed, we are OK... */
+    if ((mask & m1) == 0)
+       return 1;
+    /* We can also represent r-e-, by setting the host's readonly flag.  */
+    if ((mask & m1) == m1)
+       return 1;
+    return 0;
+}
+
+char *fsdb_create_unique_nname (a_inode *base, const char *suggestion)
+{
+    char *c;
+    char tmp[256] = "__uae___";
+    int i;
+
+    strncat (tmp, suggestion, 240);
+       
+    /* replace the evil ones... */
+    for (i=0; i < NUM_EVILCHARS; i++)
+        while ((c = strchr (tmp, evilchars[i])) != 0)
+            *c = '_';
+
+    while ((c = strchr (tmp, '.')) != 0)
+        *c = '_';
+    while ((c = strchr (tmp, ' ')) != 0)
+        *c = '_';
+
+    for (;;) {
+       char *p = build_nname (base->nname, tmp);
+       if (access (p, R_OK) < 0 && errno == ENOENT) {
+           write_log ("unique name: %s\n", p);
+           return p;
+       }
+       free (p);
+
+       /* tmpnam isn't reentrant and I don't really want to hack configure
+        * right now to see whether tmpnam_r is available...  */
+       for (i = 0; i < 8; i++) {
+           tmp[i+8] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"[rand () % 63];
+       }
+    }
+}
diff --git a/od-win32/genblitter_msvc/genblitter_msvc.vcproj b/od-win32/genblitter_msvc/genblitter_msvc.vcproj
new file mode 100755 (executable)
index 0000000..a2a121c
--- /dev/null
@@ -0,0 +1,172 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="7.10"
+       Name="genblitter"
+       ProjectGUID="{765B0AF0-B8D3-4998-89AF-D6F939E1CD18}"
+       SccProjectName=""
+       SccLocalPath="">
+       <Platforms>
+               <Platform
+                       Name="Win32"/>
+       </Platforms>
+       <Configurations>
+               <Configuration
+                       Name="Release|Win32"
+                       OutputDirectory=".\Release"
+                       IntermediateDirectory=".\Release"
+                       ConfigurationType="1"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="FALSE"
+                       CharacterSet="2">
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalOptions=""
+                               InlineFunctionExpansion="1"
+                               AdditionalIncludeDirectories="..\..\include,..\..,..\"
+                               PreprocessorDefinitions="WIN32,NDEBUG,_CONSOLE"
+                               StringPooling="TRUE"
+                               RuntimeLibrary="4"
+                               EnableFunctionLevelLinking="TRUE"
+                               PrecompiledHeaderFile=".\Release/genblitter_msvc.pch"
+                               AssemblerListingLocation=".\Release/"
+                               ObjectFile=".\Release/"
+                               ProgramDataBaseFileName=".\Release/"
+                               WarningLevel="3"
+                               SuppressStartupBanner="TRUE"
+                               CompileAs="0"/>
+                       <Tool
+                               Name="VCCustomBuildTool"/>
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalOptions="/MACHINE:I386"
+                               OutputFile="genblitter.exe"
+                               LinkIncremental="1"
+                               SuppressStartupBanner="TRUE"
+                               ProgramDatabaseFile=".\Release/genblitter.pdb"
+                               SubSystem="1"/>
+                       <Tool
+                               Name="VCMIDLTool"
+                               TypeLibraryName=".\Release/genblitter_msvc.tlb"/>
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                               Description="generating blitter files"
+                               CommandLine="genblitter.exe i &gt;..\..\blit.h
+genblitter.exe f &gt;..\..\blitfunc.c
+genblitter.exe h &gt;..\..\blitfunc.h
+genblitter.exe t &gt;..\..\blittable.c
+"/>
+                       <Tool
+                               Name="VCPreBuildEventTool"/>
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                               Description="deleting blitter files"
+                               CommandLine="del ..\..\blit.h
+del ..\..\blitfunc.c
+del ..\..\blitfunc.h
+del ..\..\blittable.c
+"/>
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="NDEBUG"
+                               Culture="1033"/>
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"/>
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"/>
+                       <Tool
+                               Name="VCWebDeploymentTool"/>
+                       <Tool
+                               Name="VCManagedWrapperGeneratorTool"/>
+                       <Tool
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+               </Configuration>
+               <Configuration
+                       Name="Debug|Win32"
+                       OutputDirectory=".\Debug"
+                       IntermediateDirectory=".\Debug"
+                       ConfigurationType="1"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="FALSE"
+                       CharacterSet="2">
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalOptions=""
+                               Optimization="0"
+                               AdditionalIncludeDirectories="..\..\include,..\..,..\"
+                               PreprocessorDefinitions="WIN32,_DEBUG,_CONSOLE,__STDC__"
+                               BasicRuntimeChecks="3"
+                               RuntimeLibrary="5"
+                               PrecompiledHeaderFile=".\Debug/genblitter_msvc.pch"
+                               AssemblerListingLocation=".\Debug/"
+                               ObjectFile=".\Debug/"
+                               ProgramDataBaseFileName=".\Debug/"
+                               WarningLevel="3"
+                               SuppressStartupBanner="TRUE"
+                               DebugInformationFormat="4"
+                               CompileAs="0"/>
+                       <Tool
+                               Name="VCCustomBuildTool"/>
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalOptions="/MACHINE:I386"
+                               OutputFile="genblitter.exe"
+                               LinkIncremental="2"
+                               SuppressStartupBanner="TRUE"
+                               GenerateDebugInformation="TRUE"
+                               ProgramDatabaseFile=".\Debug/genblitter.pdb"
+                               SubSystem="1"/>
+                       <Tool
+                               Name="VCMIDLTool"
+                               TypeLibraryName=".\Debug/genblitter_msvc.tlb"/>
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                               Description="generating blitter files"
+                               CommandLine="genblitter.exe i &gt;..\..\blit.h
+genblitter.exe f &gt;..\..\blitfunc.c
+genblitter.exe h &gt;..\..\blitfunc.h
+genblitter.exe t &gt;..\..\blittable.c
+"/>
+                       <Tool
+                               Name="VCPreBuildEventTool"/>
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                               Description="deleting blitter files"
+                               CommandLine="del ..\..\blit.h
+del ..\..\blitfunc.c
+del ..\..\blitfunc.h
+del ..\..\blittable.c
+"/>
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="_DEBUG"
+                               Culture="1033"/>
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"/>
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"/>
+                       <Tool
+                               Name="VCWebDeploymentTool"/>
+                       <Tool
+                               Name="VCManagedWrapperGeneratorTool"/>
+                       <Tool
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="Source Files"
+                       Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
+                       <File
+                               RelativePath="..\..\blitops.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\genblitter.c">
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/od-win32/gencomp_msvc/gencomp_msvc.vcproj b/od-win32/gencomp_msvc/gencomp_msvc.vcproj
new file mode 100755 (executable)
index 0000000..d5b6836
--- /dev/null
@@ -0,0 +1,166 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="7.10"
+       Name="gencomp"
+       ProjectGUID="{54197DFF-9CAA-4A9F-B9C2-2881EA04EACB}"
+       SccProjectName=""
+       SccLocalPath="">
+       <Platforms>
+               <Platform
+                       Name="Win32"/>
+       </Platforms>
+       <Configurations>
+               <Configuration
+                       Name="Release|Win32"
+                       OutputDirectory=".\Release"
+                       IntermediateDirectory=".\Release"
+                       ConfigurationType="1"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="FALSE"
+                       CharacterSet="2">
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalOptions=""
+                               InlineFunctionExpansion="1"
+                               AdditionalIncludeDirectories="..\..\include,..\..,..\"
+                               PreprocessorDefinitions="WIN32,NDEBUG,_CONSOLE"
+                               StringPooling="TRUE"
+                               RuntimeLibrary="4"
+                               EnableFunctionLevelLinking="TRUE"
+                               PrecompiledHeaderFile=".\Release/gencomp_msvc.pch"
+                               AssemblerListingLocation=".\Release/"
+                               ObjectFile=".\Release/"
+                               ProgramDataBaseFileName=".\Release/"
+                               WarningLevel="3"
+                               SuppressStartupBanner="TRUE"
+                               CompileAs="0"/>
+                       <Tool
+                               Name="VCCustomBuildTool"/>
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalOptions="/MACHINE:I386"
+                               OutputFile="gencomp.exe"
+                               LinkIncremental="1"
+                               SuppressStartupBanner="TRUE"
+                               ProgramDatabaseFile=".\Release/gencomp.pdb"
+                               SubSystem="1"/>
+                       <Tool
+                               Name="VCMIDLTool"
+                               TypeLibraryName=".\Release/gencomp_msvc.tlb"/>
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                               Description="generating gencomp files"
+                               CommandLine="cd ..\..
+od-win32\gencomp_msvc\gencomp.exe
+"/>
+                       <Tool
+                               Name="VCPreBuildEventTool"/>
+                       <Tool
+                               Name="VCPreLinkEventTool"/>
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="NDEBUG"
+                               Culture="1033"/>
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"/>
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"/>
+                       <Tool
+                               Name="VCWebDeploymentTool"/>
+                       <Tool
+                               Name="VCManagedWrapperGeneratorTool"/>
+                       <Tool
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+               </Configuration>
+               <Configuration
+                       Name="Debug|Win32"
+                       OutputDirectory=".\Debug"
+                       IntermediateDirectory=".\Debug"
+                       ConfigurationType="1"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="FALSE"
+                       CharacterSet="2">
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalOptions=""
+                               Optimization="0"
+                               AdditionalIncludeDirectories="..\..\include,..\..,..\"
+                               PreprocessorDefinitions="WIN32,_DEBUG,_CONSOLE,__STDC__"
+                               BasicRuntimeChecks="3"
+                               RuntimeLibrary="5"
+                               UsePrecompiledHeader="2"
+                               PrecompiledHeaderFile=".\Debug/gencomp_msvc.pch"
+                               AssemblerListingLocation=".\Debug/"
+                               ObjectFile=".\Debug/"
+                               ProgramDataBaseFileName=".\Debug/"
+                               WarningLevel="3"
+                               SuppressStartupBanner="TRUE"
+                               DebugInformationFormat="4"
+                               CompileAs="0"/>
+                       <Tool
+                               Name="VCCustomBuildTool"/>
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalOptions="/MACHINE:I386"
+                               OutputFile="gencomp.exe"
+                               LinkIncremental="2"
+                               SuppressStartupBanner="TRUE"
+                               GenerateDebugInformation="TRUE"
+                               ProgramDatabaseFile=".\Debug/gencomp.pdb"
+                               SubSystem="1"/>
+                       <Tool
+                               Name="VCMIDLTool"
+                               TypeLibraryName=".\Debug/gencomp_msvc.tlb"/>
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                               Description="generating gencomp files"
+                               CommandLine="cd ..\..
+od-win32\gencomp_msvc\gencomp.exe
+"/>
+                       <Tool
+                               Name="VCPreBuildEventTool"/>
+                       <Tool
+                               Name="VCPreLinkEventTool"/>
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="_DEBUG"
+                               Culture="1033"/>
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"/>
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"/>
+                       <Tool
+                               Name="VCWebDeploymentTool"/>
+                       <Tool
+                               Name="VCManagedWrapperGeneratorTool"/>
+                       <Tool
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="Source Files"
+                       Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
+                       <File
+                               RelativePath="..\..\cpudefs.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\gencomp.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\missing.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\readcpu.c">
+                       </File>
+                       <File
+                               RelativePath="..\writelog.c">
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/od-win32/gencpu_msvc/gencpu_msvc.vcproj b/od-win32/gencpu_msvc/gencpu_msvc.vcproj
new file mode 100755 (executable)
index 0000000..7a3479b
--- /dev/null
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="7.10"
+       Name="gencpu"
+       ProjectGUID="{DEF7ACF7-050E-4069-BB99-5B5D93F60521}"
+       SccProjectName=""
+       SccLocalPath="">
+       <Platforms>
+               <Platform
+                       Name="Win32"/>
+       </Platforms>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       OutputDirectory=".\Debug"
+                       IntermediateDirectory=".\Debug"
+                       ConfigurationType="1"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="FALSE"
+                       CharacterSet="2">
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalOptions=""
+                               Optimization="0"
+                               AdditionalIncludeDirectories="..\..\include,..\..,..\"
+                               PreprocessorDefinitions="WIN32,_DEBUG,_CONSOLE,__STDC__"
+                               BasicRuntimeChecks="3"
+                               RuntimeLibrary="5"
+                               UsePrecompiledHeader="2"
+                               PrecompiledHeaderFile=".\Debug/gencpu_msvc.pch"
+                               AssemblerListingLocation=".\Debug/"
+                               ObjectFile=".\Debug/"
+                               ProgramDataBaseFileName=".\Debug/"
+                               WarningLevel="3"
+                               SuppressStartupBanner="TRUE"
+                               DebugInformationFormat="4"
+                               CompileAs="0"/>
+                       <Tool
+                               Name="VCCustomBuildTool"/>
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalOptions="/MACHINE:I386"
+                               OutputFile="gencpu.exe"
+                               LinkIncremental="2"
+                               SuppressStartupBanner="TRUE"
+                               GenerateDebugInformation="TRUE"
+                               ProgramDatabaseFile=".\Debug/gencpu.pdb"
+                               SubSystem="1"/>
+                       <Tool
+                               Name="VCMIDLTool"
+                               TypeLibraryName=".\Debug/gencpu_msvc.tlb"/>
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                               Description="generating gencpu files"
+                               CommandLine="cd ..\..
+od-win32\gencpu_msvc\gencpu.exe
+"/>
+                       <Tool
+                               Name="VCPreBuildEventTool"/>
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                               Description="deleting gencpu files"
+                               CommandLine="del ..\..\cputbl.h;del ..\..\cpustbl.c
+;del ..\..\cpuemu.c
+"/>
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="_DEBUG"
+                               Culture="1033"/>
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"/>
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"/>
+                       <Tool
+                               Name="VCWebDeploymentTool"/>
+                       <Tool
+                               Name="VCManagedWrapperGeneratorTool"/>
+                       <Tool
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       OutputDirectory=".\Release"
+                       IntermediateDirectory=".\Release"
+                       ConfigurationType="1"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="FALSE"
+                       CharacterSet="2">
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalOptions=""
+                               InlineFunctionExpansion="1"
+                               AdditionalIncludeDirectories="..\..\include,..\..,..\"
+                               PreprocessorDefinitions="WIN32,NDEBUG,_CONSOLE"
+                               StringPooling="TRUE"
+                               RuntimeLibrary="4"
+                               EnableFunctionLevelLinking="TRUE"
+                               PrecompiledHeaderFile=".\Release/gencpu_msvc.pch"
+                               AssemblerListingLocation=".\Release/"
+                               ObjectFile=".\Release/"
+                               ProgramDataBaseFileName=".\Release/"
+                               WarningLevel="3"
+                               SuppressStartupBanner="TRUE"
+                               CompileAs="0"/>
+                       <Tool
+                               Name="VCCustomBuildTool"/>
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalOptions="/MACHINE:I386"
+                               OutputFile="gencpu.exe"
+                               LinkIncremental="1"
+                               SuppressStartupBanner="TRUE"
+                               ProgramDatabaseFile=".\Release/gencpu.pdb"
+                               SubSystem="1"/>
+                       <Tool
+                               Name="VCMIDLTool"
+                               TypeLibraryName=".\Release/gencpu_msvc.tlb"/>
+                       <Tool
+                               Name="VCPostBuildEventTool"
+                               Description="generating gencpu files"
+                               CommandLine="cd ..\..
+od-win32\gencpu_msvc\gencpu.exe
+"/>
+                       <Tool
+                               Name="VCPreBuildEventTool"/>
+                       <Tool
+                               Name="VCPreLinkEventTool"
+                               Description="deleting gencpu files"
+                               CommandLine="del ..\..\cputbl.h
+del ..\..\cpustbl.c
+del ..\..\cpuemu.c
+"/>
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="NDEBUG"
+                               Culture="1033"/>
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"/>
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"/>
+                       <Tool
+                               Name="VCWebDeploymentTool"/>
+                       <Tool
+                               Name="VCManagedWrapperGeneratorTool"/>
+                       <Tool
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="Source Files"
+                       Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
+                       <File
+                               RelativePath="..\..\cpudefs.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\gencpu.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\missing.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\readcpu.c">
+                       </File>
+                       <File
+                               RelativePath="..\writelog.c">
+                       </File>
+               </Filter>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/od-win32/hardfile_win32.c b/od-win32/hardfile_win32.c
new file mode 100755 (executable)
index 0000000..783a024
--- /dev/null
@@ -0,0 +1,786 @@
+#define WIN32_LEAN_AND_MEAN
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "threaddep/thread.h"
+#include "filesys.h"
+#include "blkdev.h"
+
+#define hfd_log write_log
+
+#ifdef WINDDK
+#include <devioctl.h>  
+#include <ntddstor.h>
+#include <winioctl.h>
+#include <initguid.h>   // Guid definition
+#include <devguid.h>    // Device guids
+#include <setupapi.h>   // for SetupDiXxx functions.
+#include <cfgmgr32.h>   // for SetupDiXxx functions.
+#endif
+
+struct uae_driveinfo {
+    uae_u64 offset2;
+    uae_u64 size2;
+    char vendor_id[128];
+    char product_id[128];
+    char product_rev[128];
+    char product_serial[128];
+    char device_name[256];
+    char device_path[2048];
+    uae_u64 size;
+    uae_u64 offset;
+    int bytespersector;
+};
+
+#define CACHE_SIZE 16384
+#define CACHE_FLUSH_TIME 5
+
+/* safety check: only accept drives that:
+ * - contain RDSK in block 0
+ * - block 0 is zeroed
+ */
+
+int harddrive_dangerous, do_rdbdump;
+static int num_drives;
+static struct uae_driveinfo uae_drives[MAX_FILESYSTEM_UNITS];
+
+static void rdbdump (HANDLE *h, uae_u64 offset, uae_u8 *buf, int blocksize)
+{
+    static int cnt = 1;
+    int i, blocks;
+    char name[100];
+    FILE *f;
+
+    blocks = (buf[132] << 24) | (buf[133] << 16) | (buf[134] << 8) | (buf[135] << 0);
+    if (blocks < 0 || blocks > 100000)
+       return;
+    sprintf (name, "rdb_dump_%d.rdb", cnt);
+    f = fopen (name, "wb");
+    if (!f)
+       return;
+    for (i = 0; i <= blocks; i++) {
+        DWORD outlen, high;
+        high = (DWORD)(offset >> 32);
+       if (SetFilePointer (h, (DWORD)offset, &high, FILE_BEGIN) == INVALID_FILE_SIZE)
+           break;
+        ReadFile (h, buf, blocksize, &outlen, NULL);
+       fwrite (buf, 1, blocksize, f);
+       offset += blocksize;
+    }
+    fclose (f);
+    cnt++;
+}
+
+static int safetycheck (HANDLE *h, uae_u64 offset, uae_u8 *buf, int blocksize)
+{
+    int i, j, blocks = 63, empty = 1;
+    DWORD outlen, high;
+
+    for (j = 0; j < blocks; j++) {
+       high = (DWORD)(offset >> 32);
+       if (SetFilePointer (h, (DWORD)offset, &high, FILE_BEGIN) == INVALID_FILE_SIZE) {
+           write_log ("hd ignored, SetFilePointer failed, error %d\n", GetLastError());
+           return 0;
+       }
+       memset (buf, 0xaa, blocksize);
+       ReadFile (h, buf, blocksize, &outlen, NULL);
+       if (outlen != blocksize) {
+           write_log ("hd ignored, read error %d!\n", GetLastError());
+           return 0;
+       }
+       if (!memcmp (buf, "RDSK", 4)) {
+           if (do_rdbdump)
+               rdbdump (h, offset, buf, blocksize);
+           write_log ("hd accepted (rdb detected at block %d)\n", j);
+           return 1;
+       }
+       if (j == 0) {
+           for (i = 0; i < blocksize; i++) {
+               if (buf[i])
+                   empty = 0;
+           }
+       }
+       offset += blocksize;
+    }
+    if (harddrive_dangerous != 0x1234dead) {
+        if (!empty) {
+           write_log ("hd ignored, not empty and no RDB detected\n");
+           return 0;
+       }
+       write_log ("hd accepted (empty)\n");
+       return 1;
+    }
+    gui_message ("WARNING: Non-empty or Amiga formatted\n"
+       "harddrive detected and safety test was disabled\n\n"
+       "Harddrives marked with 'HD_*_' are not empty\n");
+    return 2;
+}
+
+static void trim (char *s)
+{
+    while(strlen(s) > 0 && s[strlen(s) - 1] == ' ')
+       s[strlen(s) - 1] = 0;
+}
+
+int isharddrive (char *name)
+{
+    int i;
+
+    for (i = 0; i < num_drives; i++) {
+       if (!strcmp (uae_drives[i].device_name, name))
+           return i;
+    }
+    return -1;
+}
+
+int hdf_open (struct hardfiledata *hfd, char *name)
+{
+    HANDLE h = INVALID_HANDLE_VALUE;
+    int i;
+    struct uae_driveinfo *udi;
+
+    hdf_close (hfd);
+    hfd->cache = VirtualAlloc (NULL, CACHE_SIZE, MEM_COMMIT, PAGE_READWRITE);
+    hfd->cache_valid = 0;
+    if (!hfd->cache) {
+       write_log ("VirtualAlloc(%d) failed, error %d\n", CACHE_SIZE, GetLastError());
+       return 0;
+    }
+    hfd_log ("hfd open: '%s'\n", name);
+    if (strlen (name) > 4 && !memcmp (name, "HD_", 3)) {
+       hdf_init ();
+       i = isharddrive (name);
+       if (i >= 0) {
+           udi = &uae_drives[i];
+           hfd->flags = 1;
+           h = CreateFile (udi->device_path, GENERIC_READ | (hfd->readonly ? 0 : GENERIC_WRITE), FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+               OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_NO_BUFFERING, NULL);
+           hfd->handle = h;
+           if (h == INVALID_HANDLE_VALUE) {
+               hdf_close (hfd);
+               return 0;
+           }
+           strncpy (hfd->vendor_id, udi->vendor_id, 8);
+           strncpy (hfd->product_id, udi->product_id, 16);
+           strncpy (hfd->product_rev, udi->product_rev, 4);
+           hfd->offset2 = hfd->offset = udi->offset;
+           hfd->size2 = hfd->size = udi->size;
+           if (hfd->offset != udi->offset2 || hfd->size != udi->size2) {
+               gui_message ("Harddrive safety check: fatal memory corruption\n");
+               abort ();
+           }
+           hfd->blocksize = udi->bytespersector;
+           if (hfd->offset == 0) {
+               if (!safetycheck (hfd->handle, 0, hfd->cache, hfd->blocksize)) {
+                   hdf_close (hfd);
+                   return 0;
+               }
+           }
+       }
+    } else {
+       h = CreateFile (name, GENERIC_READ | (hfd->readonly ? 0 : GENERIC_WRITE), hfd->readonly ? FILE_SHARE_READ : 0, NULL,
+           OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);
+        hfd->handle = h;
+        i = strlen (name) - 1;
+       while (i >= 0) {
+           if ((i > 0 && (name[i - 1] == '/' || name[i - 1] == '\\')) || i == 0) {
+               strcpy (hfd->vendor_id, "UAE");
+               strncpy (hfd->product_id, name + i, 15);
+               strcpy (hfd->product_rev, "0.2");
+               break;
+           }
+           i--;
+       }
+       if (h != INVALID_HANDLE_VALUE) {
+           DWORD ret, low, high;
+           high = 0;
+           ret = SetFilePointer (h, 0, &high, FILE_END);
+           if (ret == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) {
+               hdf_close (hfd);
+               return 0;
+           }
+           low = GetFileSize (h, &high);
+           if (low == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) {
+               hdf_close (hfd);
+               return 0;
+           }
+           low &= ~(hfd->blocksize - 1);
+           hfd->size = hfd->size2 = ((uae_u64)high << 32) | low;
+       } else {
+           write_log ("HDF '%s' failed to open. error = %d\n", name, GetLastError ());
+       }
+    }
+    hfd->handle = h;
+    if (hfd->handle != INVALID_HANDLE_VALUE) {
+       hfd_log ("HDF '%s' opened succesfully, handle=%p\n", name, hfd->handle);
+       return 1;
+    }
+    hdf_close (hfd);
+    return 0;
+}
+
+void hdf_close (struct hardfiledata *hfd)
+{
+    hfd_log ("close handle=%p\n", hfd->handle);
+    hfd->flags = 0;
+    if (hfd->handle && hfd->handle != INVALID_HANDLE_VALUE)
+       CloseHandle (hfd->handle);
+    hfd->handle = 0;
+    if (hfd->cache)
+       VirtualFree (hfd->cache, 0, MEM_RELEASE);
+    hfd->cache = 0;
+    hfd->cache_valid = 0;
+}
+
+int hdf_dup (struct hardfiledata *hfd, void *src)
+{
+    HANDLE duphandle;
+    if (src == 0 || src == INVALID_HANDLE_VALUE)
+       return 0;
+    if (!DuplicateHandle (GetCurrentProcess(), src, GetCurrentProcess() , &duphandle, 0, FALSE, DUPLICATE_SAME_ACCESS))
+       return 0;
+    hfd->handle = duphandle;
+    hfd->cache = VirtualAlloc (NULL, CACHE_SIZE, MEM_COMMIT, PAGE_READWRITE);
+    hfd->cache_valid = 0;
+    if (!hfd->cache) {
+       hdf_close (hfd);
+       return 0;
+    }
+    hfd_log ("dup handle %p->%p\n", src, duphandle);
+    return 1;
+}
+
+static int hdf_seek (struct hardfiledata *hfd, uae_u64 offset)
+{
+    DWORD high, ret;
+    
+    if (hfd->offset != hfd->offset2 || hfd->size != hfd->size2) {
+       gui_message ("hd: memory corruption detected in seek");
+       abort ();
+    }
+    if (offset >= hfd->size) {
+       gui_message ("hd: tried to seek out of bounds! (%I64X >= %I64X)\n", offset, hfd->size);
+       abort ();
+    }
+    offset += hfd->offset;
+    if (offset & (hfd->blocksize - 1)) {
+       gui_message ("hd: poscheck failed, offset not aligned to blocksize! (%I64X & %04.4X = %04.4X)\n", offset, hfd->blocksize, offset & (hfd->blocksize - 1));
+       abort ();
+    }
+    high = (DWORD)(offset >> 32);
+    ret = SetFilePointer (hfd->handle, (DWORD)offset, &high, FILE_BEGIN);
+    if (ret == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)
+       return -1;
+    return 0;
+}
+
+static void poscheck (struct hardfiledata *hfd, int len)
+{
+    DWORD high, ret, err;
+    uae_u64 pos;
+
+    if (hfd->offset != hfd->offset2 || hfd->size != hfd->size2) {
+       gui_message ("hd: memory corruption detected in poscheck");
+       abort ();
+    }
+    high = 0;
+    ret = SetFilePointer (hfd->handle, 0, &high, FILE_CURRENT);
+    err = GetLastError ();
+    if (ret == INVALID_FILE_SIZE && err != NO_ERROR) {
+       gui_message ("hd: poscheck failed. seek failure, error %d", err);
+       abort ();
+    }
+    if (len < 0) {
+       gui_message ("hd: poscheck failed, negative length! (%d)", len);
+       abort ();
+    }
+    pos = ((uae_u64)high) << 32 | ret;
+    if (pos < hfd->offset) {
+       gui_message ("hd: poscheck failed, offset out of bounds! (%I64d < %I64d)", pos, hfd->offset);
+       abort ();
+    }
+    if (pos >= hfd->offset + hfd->size || pos >= hfd->offset + hfd->size + len) {
+       gui_message ("hd: poscheck failed, offset out of bounds! (%I64d >= %I64d, LEN=%d)", pos, hfd->offset + hfd->size, len);
+       abort ();
+    }
+    if (pos & (hfd->blocksize - 1)) {
+       gui_message ("hd: poscheck failed, offset not aligned to blocksize! (%I64X & %04.4X = %04.4X\n", pos, hfd->blocksize, pos & hfd->blocksize);
+       abort ();
+    }
+}
+
+static int isincache (struct hardfiledata *hfd, uae_u64 offset, int len)
+{
+    if (!hfd->cache_valid)
+       return -1;
+    if (offset >= hfd->cache_offset && offset + len <= hfd->cache_offset + CACHE_SIZE)
+       return (int)(offset - hfd->cache_offset);
+    return -1;
+}
+
+#if 0
+void hfd_flush_cache (struct hardfiledata *hfd, int now)
+{
+    DWORD outlen = 0;
+    if (!hfd->cache_needs_flush || !hfd->cache_valid)
+       return;
+    if (now || time (NULL) > hfd->cache_needs_flush + CACHE_FLUSH_TIME) {
+       hdf_log ("flushed %d %d %d\n", now, time(NULL), hfd->cache_needs_flush);
+       hdf_seek (hfd, hfd->cache_offset);
+       poscheck (hfd, CACHE_SIZE);
+       WriteFile (hfd->handle, hfd->cache, CACHE_SIZE, &outlen, NULL);
+        hfd->cache_needs_flush = 0;
+    }
+}
+#endif
+
+#if 0
+int hdf_read (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
+{
+    DWORD outlen = 0;
+    hfd->cache_valid = 0;
+    hdf_seek (hfd, offset);
+    poscheck (hfd, len);
+    ReadFile (hfd->handle, hfd->cache, len, &outlen, NULL);
+    memcpy (buffer, hfd->cache, len);
+    return outlen;
+}
+#endif
+
+int hdf_read (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
+{
+    DWORD outlen = 0;
+    int coffset;
+
+    if (offset == 0)
+       hfd->cache_valid = 0;
+    coffset = isincache (hfd, offset, len);
+    if (coffset >= 0) {
+       memcpy (buffer, hfd->cache + coffset, len);
+       return len;
+    }
+    hfd->cache_offset = offset;
+    if (offset + CACHE_SIZE > hfd->offset + hfd->size)
+       hfd->cache_offset = hfd->offset + hfd->size - CACHE_SIZE;
+    hdf_seek (hfd, hfd->cache_offset);
+    poscheck (hfd, CACHE_SIZE);
+    ReadFile (hfd->handle, hfd->cache, CACHE_SIZE, &outlen, NULL);
+    hfd->cache_valid = 0;
+    if (outlen != CACHE_SIZE)
+       return 0;
+    hfd->cache_valid = 1;
+    coffset = isincache (hfd, offset, len);
+    if (coffset >= 0) {
+       memcpy (buffer, hfd->cache + coffset, len);
+       return len;
+    }
+    write_log ("hdf_read: cache bug! offset=%I64d len=%d\n", offset, len);
+    hfd->cache_valid = 0;
+    return 0;
+}
+
+int hdf_write (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
+{
+    DWORD outlen = 0;
+    hfd->cache_valid = 0;
+    hdf_seek (hfd, offset);
+    poscheck (hfd, len);
+    memcpy (hfd->cache, buffer, len);
+    WriteFile (hfd->handle, hfd->cache, len, &outlen, NULL);
+    return outlen;
+}
+
+#ifdef WINDDK
+
+/* see MS KB article Q264203 more more information */
+
+static BOOL GetDeviceProperty(HDEVINFO IntDevInfo, DWORD Index, DWORD *index2, uae_u8 *buffer)
+/*++
+
+Routine Description:
+
+    This routine enumerates the disk devices using the Device interface
+    GUID DiskClassGuid. Gets the Adapter & Device property from the port
+    driver. Then sends IOCTL through SPTI to get the device Inquiry data.
+
+Arguments:
+
+    IntDevInfo - Handles to the interface device information list
+
+    Index      - Device member 
+
+Return Value:
+
+  TRUE / FALSE. This decides whether to continue or not
+
+--*/
+{
+    STORAGE_PROPERTY_QUERY              query;
+    SP_DEVICE_INTERFACE_DATA            interfaceData;
+    PSP_DEVICE_INTERFACE_DETAIL_DATA    interfaceDetailData = NULL;
+    PSTORAGE_ADAPTER_DESCRIPTOR         adpDesc;
+    PSTORAGE_DEVICE_DESCRIPTOR          devDesc;
+    HANDLE                              hDevice = INVALID_HANDLE_VALUE;
+    BOOL                                status;
+    PUCHAR                              p;
+    UCHAR                               outBuf[20000];
+    ULONG                               length = 0,
+                                        returned = 0,
+                                        returnedLength;
+    DWORD                               interfaceDetailDataSize = 0,
+                                        reqSize,
+                                        errorCode, 
+                                        i, j;
+    DRIVE_LAYOUT_INFORMATION           *dli;
+    DISK_GEOMETRY                      dg;
+    int ret = -1;
+    struct uae_driveinfo *udi;
+    char orgname[1024];
+
+    interfaceData.cbSize = sizeof (SP_INTERFACE_DEVICE_DATA);
+
+    status = SetupDiEnumDeviceInterfaces ( 
+                IntDevInfo,             // Interface Device Info handle
+                0,                      // Device Info data
+                (LPGUID)&DiskClassGuid, // Interface registered by driver
+                Index,                  // Member
+                &interfaceData          // Device Interface Data
+                );
+
+    if ( status == FALSE ) {
+        errorCode = GetLastError();
+        if ( errorCode != ERROR_NO_MORE_ITEMS ) {
+            write_log ("SetupDiEnumDeviceInterfaces failed with error: %d\n", errorCode);
+        }
+       ret = 0;
+       goto end;
+    }
+        
+    //
+    // Find out required buffer size, so pass NULL 
+    //
+
+    status = SetupDiGetDeviceInterfaceDetail (
+                IntDevInfo,         // Interface Device info handle
+                &interfaceData,     // Interface data for the event class
+                NULL,               // Checking for buffer size
+                0,                  // Checking for buffer size
+                &reqSize,           // Buffer size required to get the detail data
+                NULL                // Checking for buffer size
+                );
+
+    //
+    // This call returns ERROR_INSUFFICIENT_BUFFER with reqSize 
+    // set to the required buffer size. Ignore the above error and
+    // pass a bigger buffer to get the detail data
+    //
+
+    if ( status == FALSE ) {
+        errorCode = GetLastError();
+        if ( errorCode != ERROR_INSUFFICIENT_BUFFER ) {
+            write_log("SetupDiGetDeviceInterfaceDetail failed with error: %d\n", errorCode);
+           ret = 0;
+           goto end;
+        }
+    }
+
+    //
+    // Allocate memory to get the interface detail data
+    // This contains the devicepath we need to open the device
+    //
+
+    interfaceDetailDataSize = reqSize;
+    interfaceDetailData = malloc (interfaceDetailDataSize);
+    if ( interfaceDetailData == NULL ) {
+        write_log ("Unable to allocate memory to get the interface detail data.\n");
+       ret = 0;
+       goto end;
+    }
+    interfaceDetailData->cbSize = sizeof (SP_INTERFACE_DEVICE_DETAIL_DATA);
+
+    status = SetupDiGetDeviceInterfaceDetail (
+                  IntDevInfo,               // Interface Device info handle
+                  &interfaceData,           // Interface data for the event class
+                  interfaceDetailData,      // Interface detail data
+                  interfaceDetailDataSize,  // Interface detail data size
+                  &reqSize,                 // Buffer size required to get the detail data
+                  NULL);                    // Interface device info
+
+    if ( status == FALSE ) {
+        write_log("Error in SetupDiGetDeviceInterfaceDetail failed with error: %d\n", GetLastError());
+       ret = 0;
+       goto end;
+    }
+
+    //
+    // Now we have the device path. Open the device interface
+    // to send Pass Through command
+
+    udi = &uae_drives[*index2];
+    strcpy (udi->device_path, interfaceDetailData->DevicePath);
+    write_log ("opening device '%s'\n", udi->device_path);
+    hDevice = CreateFile(
+                interfaceDetailData->DevicePath,    // device interface name
+                GENERIC_READ | GENERIC_WRITE,       // dwDesiredAccess
+                FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode
+                NULL,                               // lpSecurityAttributes
+                OPEN_EXISTING,                      // dwCreationDistribution
+                0,                                  // dwFlagsAndAttributes
+                NULL                                // hTemplateFile
+                );
+                
+    //
+    // We have the handle to talk to the device. 
+    // So we can release the interfaceDetailData buffer
+    //
+
+    free (interfaceDetailData);
+    interfaceDetailData = NULL;
+
+    if (hDevice == INVALID_HANDLE_VALUE) {
+        write_log ("CreateFile failed with error: %d\n", GetLastError());
+       ret = 1;
+       goto end;
+    }
+
+    query.PropertyId = StorageAdapterProperty;
+    query.QueryType = PropertyStandardQuery;
+
+    status = DeviceIoControl(
+                        hDevice,                
+                        IOCTL_STORAGE_QUERY_PROPERTY,
+                        &query,
+                        sizeof( STORAGE_PROPERTY_QUERY ),
+                        &outBuf,                   
+                        sizeof (outBuf),
+                        &returnedLength,      
+                        NULL                    
+                        );
+    if ( !status ) {
+        write_log("IOCTL_STORAGE_QUERY_PROPERTY failed with error code%d.\n", GetLastError());
+       ret = 1;
+       goto end;
+    }
+
+    adpDesc = (PSTORAGE_ADAPTER_DESCRIPTOR) outBuf;
+    query.PropertyId = StorageDeviceProperty;
+    query.QueryType = PropertyStandardQuery;
+    status = DeviceIoControl(
+                       hDevice,                
+                        IOCTL_STORAGE_QUERY_PROPERTY,
+                        &query,
+                        sizeof( STORAGE_PROPERTY_QUERY ),
+                        &outBuf,                   
+                        sizeof (outBuf),                      
+                        &returnedLength,
+                        NULL);
+        if ( !status ) {
+            write_log ("IOCTL_STORAGE_QUERY_PROPERTY failed with error code %d.\n", GetLastError());
+           ret = 1;
+           goto end;
+        }
+        devDesc = (PSTORAGE_DEVICE_DESCRIPTOR) outBuf;
+        p = (PUCHAR) outBuf; 
+        if (devDesc->DeviceType != INQ_DASD && devDesc->DeviceType != INQ_ROMD && devDesc->DeviceType != INQ_OPTD) {
+           ret = 1;
+           write_log ("not a direct access device, ignored (type=%d)\n", devDesc->DeviceType);
+           goto end;
+       }
+        if ( devDesc->VendorIdOffset && p[devDesc->VendorIdOffset] ) {
+            j = 0;
+            for ( i = devDesc->VendorIdOffset; p[i] != (UCHAR) NULL && i < returnedLength; i++ )
+               udi->vendor_id[j++] = p[i];
+        }
+        if ( devDesc->ProductIdOffset && p[devDesc->ProductIdOffset] ) {
+            j = 0;
+            for ( i = devDesc->ProductIdOffset; p[i] != (UCHAR) NULL && i < returnedLength; i++ )
+               udi->product_id[j++] = p[i];
+        }
+        if ( devDesc->ProductRevisionOffset && p[devDesc->ProductRevisionOffset] ) {
+           j = 0;
+           for ( i = devDesc->ProductRevisionOffset; p[i] != (UCHAR) NULL && i < returnedLength; i++ )
+               udi->product_rev[j++] = p[i];
+        }
+        if ( devDesc->SerialNumberOffset && p[devDesc->SerialNumberOffset] ) {
+           j = 0;
+           for ( i = devDesc->SerialNumberOffset; p[i] != (UCHAR) NULL && i < returnedLength; i++ )
+               udi->product_serial[j++] = p[i];
+        }
+       if (udi->vendor_id[0])
+           strcat (udi->device_name, udi->vendor_id);
+       if (udi->product_id[0]) {
+           if (udi->device_name[0])
+               strcat (udi->device_name, " ");
+           strcat (udi->device_name, udi->product_id);
+       }
+       if (udi->product_rev[0]) {
+           if (udi->device_name[0])
+               strcat (udi->device_name, " ");
+           strcat (udi->device_name, udi->product_rev);
+       }
+       if (udi->product_serial[0]) {
+           if (udi->device_name[0])
+               strcat (udi->device_name, " ");
+           strcat (udi->device_name, udi->product_serial);
+       }
+
+       write_log ("device id string: '%s'\n", udi->device_name);
+    if (!DeviceIoControl (hDevice, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, (void*)&dg, sizeof (dg), &returnedLength, NULL)) {
+        write_log ("IOCTL_DISK_GET_DRIVE_GEOMETRY failed with error code %d.\n", GetLastError());
+        ret = 1;
+        goto end;
+    }
+    udi->bytespersector = dg.BytesPerSector;
+    if (dg.BytesPerSector < 512) {
+       write_log ("unsupported blocksize < 512 (%d)\n", dg.BytesPerSector);
+       ret = 1;
+       goto end;
+    }
+    if (dg.BytesPerSector > 2048) {
+       write_log ("unsupported blocksize > 2048 (%d)\n", dg.BytesPerSector);
+       ret = 1;
+       goto end;
+    }
+    udi->offset = udi->offset2 = 0;
+    udi->size = udi->size2 = (uae_u64)dg.BytesPerSector * (uae_u64)dg.Cylinders.QuadPart * (uae_u64)dg.TracksPerCylinder * (uae_u64)dg.SectorsPerTrack;
+    write_log ("device size %I64d bytes\n", udi->size);
+
+    memset (outBuf, 0, sizeof (outBuf));
+    status = DeviceIoControl(hDevice, IOCTL_DISK_GET_DRIVE_LAYOUT, NULL, 0,
+        &outBuf, sizeof (outBuf), &returnedLength, NULL);
+    if (!status) {
+       write_log("IOCTL_DISK_GET_DRIVE_LAYOUT failed with error code%d.\n", GetLastError());
+       ret = 1;
+       goto end;
+    }
+    strcpy (orgname, udi->device_name);
+    trim (orgname);
+    dli = (DRIVE_LAYOUT_INFORMATION*)outBuf;
+    if (dli->PartitionCount) {
+        struct uae_driveinfo *udi2 = udi;
+        int nonzeropart = 0;
+        int gotpart = 0;
+       write_log ("%d MBR partitions found\n", dli->PartitionCount);
+       for (i = 0; i < dli->PartitionCount && (*index2) < MAX_FILESYSTEM_UNITS; i++) {
+           PARTITION_INFORMATION *pi = &dli->PartitionEntry[i];
+           if (pi->PartitionType == PARTITION_ENTRY_UNUSED)
+               continue;
+           write_log ("%d: num: %d type: %02.2X offset: %I64d size: %I64d, ", i, pi->PartitionNumber, pi->PartitionType, pi->StartingOffset.QuadPart, pi->PartitionLength.QuadPart);
+           if (pi->RecognizedPartition == 0) {
+               write_log ("unrecognized\n");
+               continue;
+           }
+           nonzeropart++;
+           if (pi->PartitionType != 0x76) {
+               write_log ("type not 0x76\n");
+               continue;
+           }
+           memmove (udi, udi2, sizeof (*udi));
+           udi->device_name[0] = 0;
+           udi->offset = udi->offset2 = pi->StartingOffset.QuadPart;
+           udi->size = udi->size2 = pi->PartitionLength.QuadPart;
+           write_log ("used\n");
+           if (safetycheck (hDevice, udi->offset, buffer, dg.BytesPerSector)) {
+               sprintf (udi->device_name, "HD_P#%d_%s", pi->PartitionNumber, orgname);
+               udi++;
+               (*index2)++;
+           }
+           gotpart = 1;
+       }
+       if (!nonzeropart) {
+           write_log ("empty MBR partition table detected, checking for RDB\n");
+       } else if (!gotpart) {
+           write_log ("non-empty MBR partition table detected, doing RDB check anyway\n");
+       } else if (harddrive_dangerous != 0x1234dead) {
+           ret = 1;
+           goto end;
+       }
+    } else {
+       write_log ("no MBR partition table detected, checking for RDB\n");
+    }
+
+    i = safetycheck (hDevice, 0, buffer, dg.BytesPerSector);
+    if (!i) {
+       ret = 1;
+       goto end;
+    }
+
+    write_log ("device accepted, start=%I64d, size=%I64d, block=%d\n", udi->offset, udi->size, udi->bytespersector);
+    if (i > 1)
+       sprintf (udi->device_name, "HD_*_%s", orgname);
+    else
+       sprintf (udi->device_name, "HD_%s", orgname);
+    while (isharddrive (udi->device_name) >= 0)
+       strcat (udi->device_name, "_");
+    (*index2)++;
+end:
+    free (interfaceDetailData);
+    if (hDevice != INVALID_HANDLE_VALUE)
+       CloseHandle (hDevice);
+    return ret;
+}
+#endif
+
+int hdf_init (void)
+{
+#ifdef WINDDK
+    HDEVINFO hIntDevInfo;
+#endif
+    DWORD index = 0, index2 = 0;
+    uae_u8 *buffer;
+    static int done;
+
+    if (done)
+       return num_drives;
+    done = 1;
+    num_drives = 0;
+#ifdef WINDDK
+    buffer = VirtualAlloc (NULL, 512, MEM_COMMIT, PAGE_READWRITE);
+    if (buffer) {
+       memset (uae_drives, 0, sizeof (uae_drives));
+       num_drives = 0;
+       hIntDevInfo = SetupDiGetClassDevs ((LPGUID)&DiskClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
+       if (hIntDevInfo != INVALID_HANDLE_VALUE) {
+           while (index < MAX_FILESYSTEM_UNITS) {
+               memset (uae_drives + index2, 0, sizeof (struct uae_driveinfo));
+               if (!GetDeviceProperty (hIntDevInfo, index, &index2, buffer))
+                   break;
+               index++;
+               num_drives = index2;
+           }
+           SetupDiDestroyDeviceInfoList(hIntDevInfo);
+       }
+       VirtualFree (buffer, 0, MEM_RELEASE);
+    }
+    num_drives = index2;
+    write_log ("Drive scan result: %d Amiga formatted drives detected\n", num_drives);
+#endif
+    return num_drives;
+}
+
+int hdf_getnumharddrives (void)
+{
+    return num_drives;
+}
+
+char *hdf_getnameharddrive (int index, int flags)
+{
+    static char name[512];
+    char tmp[32];
+    uae_u64 size = uae_drives[index].size;
+
+    if (flags & 1) {
+           if (size >= 1024 * 1024 * 1024)
+               sprintf (tmp, "%.1fG", ((double)(uae_u32)(size / (1024 * 1024))) / 1024.0);
+           else
+               sprintf (tmp, "%.1fM", ((double)(uae_u32)(size / (1024))) / 1024.0);
+       sprintf (name, "%s (%s)", uae_drives[index].device_name, tmp);
+       return name;
+    }
+    return uae_drives[index].device_name;
+}
+
+
+
diff --git a/od-win32/hq2x32 b/od-win32/hq2x32
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/od-win32/hq2x32.asm b/od-win32/hq2x32.asm
new file mode 100755 (executable)
index 0000000..28b769d
--- /dev/null
@@ -0,0 +1,1933 @@
+;hq2x filter
+;----------------------------------------------------------
+;Copyright (C) 2003 MaxSt ( maxst@hiend3d.com )
+;
+;This program is free software; you can redistribute it and/or
+;modify it under the terms of the GNU General Public License
+;as published by the Free Software Foundation; either
+;version 2 of the License, or (at your option) any later
+;version.
+;
+;This program is distributed in the hope that it will be useful,
+;but WITHOUT ANY WARRANTY; without even the implied warranty of
+;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;GNU General Public License for more details.
+;
+;You should have received a copy of the GNU General Public License
+;along with this program; if not, write to the Free Software
+;Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+GLOBAL _hq2x_32
+
+EXTERN _LUT16to32
+EXTERN _RGBtoYUV
+
+SECTION .bss
+linesleft resd 1
+xcounter  resd 1
+cross     resd 1
+nextline  resd 1
+prevline  resd 1
+w1        resd 1
+w2        resd 1
+w3        resd 1
+w4        resd 1
+w5        resd 1
+w6        resd 1
+w7        resd 1
+w8        resd 1
+w9        resd 1
+c1        resd 1
+c2        resd 1
+c3        resd 1
+c4        resd 1
+c5        resd 1
+c6        resd 1
+c7        resd 1
+c8        resd 1
+c9        resd 1
+
+SECTION .data
+
+reg_blank    dd  0,0
+const3       dd  0x00030003,0x00000003
+const5       dd  0x00050005,0x00000005
+const6       dd  0x00060006,0x00000006
+const14      dd  0x000E000E,0x0000000E
+threshold    dd  0x00300706,0x00000000
+
+SECTION .text
+
+%macro TestDiff 2
+    xor     ecx,ecx
+    mov     edx,[%1]
+    cmp     edx,[%2]
+    je      %%fin
+    mov     ecx,_RGBtoYUV
+    movd    mm1,[ecx+edx*4]
+    movq    mm5,mm1
+    mov     edx,[%2]
+    movd    mm2,[ecx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    ecx,mm1
+%%fin:
+%endmacro
+
+%macro DiffOrNot 4
+   TestDiff %1,%2
+   test ecx,ecx
+   jz   %%same
+   %3
+   jmp %%fin
+%%same:
+   %4
+%%fin
+%endmacro
+
+%macro DiffOrNot 6
+   TestDiff %1,%2
+   test ecx,ecx
+   jz   %%same
+   %3
+   %4
+   jmp %%fin
+%%same:
+   %5
+   %6
+%%fin
+%endmacro
+
+%macro DiffOrNot 8
+   TestDiff %1,%2
+   test ecx,ecx
+   jz   %%same
+   %3
+   %4
+   %5
+   jmp %%fin
+%%same:
+   %6
+   %7
+   %8
+%%fin
+%endmacro
+
+%macro DiffOrNot 10
+   TestDiff %1,%2
+   test ecx,ecx
+   jz %%same
+   %3
+   %4
+   %5
+   %6
+   jmp %%fin
+%%same:
+   %7
+   %8
+   %9
+   %10
+%%fin
+%endmacro
+
+%macro Interp1 3
+    mov edx,%2
+    shl edx,2
+    add edx,%3
+    sub edx,%2
+    shr edx,2
+    mov %1,edx
+%endmacro
+
+%macro Interp2 4
+    mov edx,%2
+    shl edx,1
+    add edx,%3
+    add edx,%4
+    shr edx,2
+    mov %1,edx
+%endmacro
+
+%macro Interp5 3
+    mov edx,%2
+    add edx,%3
+    shr edx,1
+    mov %1,edx
+%endmacro
+
+%macro Interp6 3
+    movd       mm1, eax
+    movd       mm2, %2
+    movd       mm3, %3
+    punpcklbw  mm1, [reg_blank]
+    punpcklbw  mm2, [reg_blank]
+    punpcklbw  mm3, [reg_blank]
+    pmullw     mm1, [const5]
+    psllw      mm2, 1
+    paddw      mm1, mm3
+    paddw      mm1, mm2
+    psrlw      mm1, 3
+    packuswb   mm1, [reg_blank]
+    movd       %1, mm1
+%endmacro
+
+%macro Interp7 3
+    movd       mm1, eax
+    movd       mm2, %2
+    movd       mm3, %3
+    punpcklbw  mm1, [reg_blank]
+    punpcklbw  mm2, [reg_blank]
+    punpcklbw  mm3, [reg_blank]
+    pmullw     mm1, [const6]
+    paddw      mm2, mm3
+    paddw      mm1, mm2
+    psrlw      mm1, 3
+    packuswb   mm1, [reg_blank]
+    movd       %1, mm1
+%endmacro
+
+%macro Interp9 3
+    movd       mm1, eax
+    movd       mm2, %2
+    movd       mm3, %3
+    punpcklbw  mm1, [reg_blank]
+    punpcklbw  mm2, [reg_blank]
+    punpcklbw  mm3, [reg_blank]
+    psllw      mm1, 1
+    paddw      mm2, mm3
+    pmullw     mm2, [const3]
+    paddw      mm1, mm2
+    psrlw      mm1, 3
+    packuswb   mm1, [reg_blank]
+    movd       %1, mm1
+%endmacro
+
+%macro Interp10 3
+    movd       mm1, eax
+    movd       mm2, %2
+    movd       mm3, %3
+    punpcklbw  mm1, [reg_blank]
+    punpcklbw  mm2, [reg_blank]
+    punpcklbw  mm3, [reg_blank]
+    pmullw     mm1, [const14]
+    paddw      mm2, mm3
+    paddw      mm1, mm2
+    psrlw      mm1, 4
+    packuswb   mm1, [reg_blank]
+    movd       %1, mm1
+%endmacro
+
+%macro PIXEL00_0 0
+    mov [edi],eax
+%endmacro
+
+%macro PIXEL00_10 0
+    Interp1 [edi],eax,[c1]
+%endmacro
+
+%macro PIXEL00_11 0
+    Interp1 [edi],eax,[c4]
+%endmacro
+
+%macro PIXEL00_12 0
+    Interp1 [edi],eax,[c2]
+%endmacro
+
+%macro PIXEL00_20 0
+    Interp2 [edi],eax,[c4],[c2]
+%endmacro
+
+%macro PIXEL00_21 0
+    Interp2 [edi],eax,[c1],[c2]
+%endmacro
+
+%macro PIXEL00_22 0
+    Interp2 [edi],eax,[c1],[c4]
+%endmacro
+
+%macro PIXEL00_60 0
+    Interp6 [edi],[c2],[c4]
+%endmacro
+
+%macro PIXEL00_61 0
+    Interp6 [edi],[c4],[c2]
+%endmacro
+
+%macro PIXEL00_70 0
+    Interp7 [edi],[c4],[c2]
+%endmacro
+
+%macro PIXEL00_90 0
+    Interp9 [edi],[c4],[c2]
+%endmacro
+
+%macro PIXEL00_100 0
+    Interp10 [edi],[c4],[c2]
+%endmacro
+
+%macro PIXEL01_0 0
+    mov [edi+4],eax
+%endmacro
+
+%macro PIXEL01_10 0
+    Interp1 [edi+4],eax,[c3]
+%endmacro
+
+%macro PIXEL01_11 0
+    Interp1 [edi+4],eax,[c2]
+%endmacro
+
+%macro PIXEL01_12 0
+    Interp1 [edi+4],eax,[c6]
+%endmacro
+
+%macro PIXEL01_20 0
+    Interp2 [edi+4],eax,[c2],[c6]
+%endmacro
+
+%macro PIXEL01_21 0
+    Interp2 [edi+4],eax,[c3],[c6]
+%endmacro
+
+%macro PIXEL01_22 0
+    Interp2 [edi+4],eax,[c3],[c2]
+%endmacro
+
+%macro PIXEL01_60 0
+    Interp6 [edi+4],[c6],[c2]
+%endmacro
+
+%macro PIXEL01_61 0
+    Interp6 [edi+4],[c2],[c6]
+%endmacro
+
+%macro PIXEL01_70 0
+    Interp7 [edi+4],[c2],[c6]
+%endmacro
+
+%macro PIXEL01_90 0
+    Interp9 [edi+4],[c2],[c6]
+%endmacro
+
+%macro PIXEL01_100 0
+    Interp10 [edi+4],[c2],[c6]
+%endmacro
+
+%macro PIXEL10_0 0
+    mov [edi+ebx],eax
+%endmacro
+
+%macro PIXEL10_10 0
+    Interp1 [edi+ebx],eax,[c7]
+%endmacro
+
+%macro PIXEL10_11 0
+    Interp1 [edi+ebx],eax,[c8]
+%endmacro
+
+%macro PIXEL10_12 0
+    Interp1 [edi+ebx],eax,[c4]
+%endmacro
+
+%macro PIXEL10_20 0
+    Interp2 [edi+ebx],eax,[c8],[c4]
+%endmacro
+
+%macro PIXEL10_21 0
+    Interp2 [edi+ebx],eax,[c7],[c4]
+%endmacro
+
+%macro PIXEL10_22 0
+    Interp2 [edi+ebx],eax,[c7],[c8]
+%endmacro
+
+%macro PIXEL10_60 0
+    Interp6 [edi+ebx],[c4],[c8]
+%endmacro
+
+%macro PIXEL10_61 0
+    Interp6 [edi+ebx],[c8],[c4]
+%endmacro
+
+%macro PIXEL10_70 0
+    Interp7 [edi+ebx],[c8],[c4]
+%endmacro
+
+%macro PIXEL10_90 0
+    Interp9 [edi+ebx],[c8],[c4]
+%endmacro
+
+%macro PIXEL10_100 0
+    Interp10 [edi+ebx],[c8],[c4]
+%endmacro
+
+%macro PIXEL11_0 0
+    mov [edi+ebx+4],eax
+%endmacro
+
+%macro PIXEL11_10 0
+    Interp1 [edi+ebx+4],eax,[c9]
+%endmacro
+
+%macro PIXEL11_11 0
+    Interp1 [edi+ebx+4],eax,[c6]
+%endmacro
+
+%macro PIXEL11_12 0
+    Interp1 [edi+ebx+4],eax,[c8]
+%endmacro
+
+%macro PIXEL11_20 0
+    Interp2 [edi+ebx+4],eax,[c6],[c8]
+%endmacro
+
+%macro PIXEL11_21 0
+    Interp2 [edi+ebx+4],eax,[c9],[c8]
+%endmacro
+
+%macro PIXEL11_22 0
+    Interp2 [edi+ebx+4],eax,[c9],[c6]
+%endmacro
+
+%macro PIXEL11_60 0
+    Interp6 [edi+ebx+4],[c8],[c6]
+%endmacro
+
+%macro PIXEL11_61 0
+    Interp6 [edi+ebx+4],[c6],[c8]
+%endmacro
+
+%macro PIXEL11_70 0
+    Interp7 [edi+ebx+4],[c6],[c8]
+%endmacro
+
+%macro PIXEL11_90 0
+    Interp9 [edi+ebx+4],[c6],[c8]
+%endmacro
+
+%macro PIXEL11_100 0
+    Interp10 [edi+ebx+4],[c6],[c8]
+%endmacro
+
+inbuffer     equ 8
+outbuffer    equ 12
+Xres         equ 16
+Yres         equ 20
+dstpitch     equ 24
+srcpitch     equ 28
+
+_hq2x_32:
+    push ebp
+    mov ebp,esp
+    pushad
+
+    mov     esi,[ebp+inbuffer]
+    mov     edi,[ebp+outbuffer]
+    mov     edx,[ebp+Yres]
+    mov     [linesleft],edx
+    mov     ebx,[ebp+Xres]
+    shl     ebx,1
+    mov     dword[prevline],0
+    mov     dword[nextline],ebx
+.loopy
+    mov     ecx,[ebp+Xres]
+    sub     ecx,2                 ; x={Xres-2, Xres-1} are special cases.
+    mov     dword[xcounter],ecx
+    ; x=0 - special case
+    mov     ebx,[prevline]
+    movq    mm5,[esi+ebx]
+    movq    mm6,[esi]
+    mov     ebx,[nextline]
+    movq    mm7,[esi+ebx]
+    movd    eax,mm5
+    movzx   edx,ax  
+    mov     [w1],edx
+    mov     [w2],edx
+    shr     eax,16
+    mov     [w3],eax
+    movd    eax,mm6
+    movzx   edx,ax  
+    mov     [w4],edx
+    mov     [w5],edx
+    shr     eax,16
+    mov     [w6],eax
+    movd    eax,mm7
+    movzx   edx,ax  
+    mov     [w7],edx
+    mov     [w8],edx
+    shr     eax,16
+    mov     [w9],eax
+    jmp     .flags
+.loopx
+    mov     ebx,[prevline]
+    movq    mm5,[esi+ebx-2]
+    movq    mm6,[esi-2]
+    mov     ebx,[nextline]
+    movq    mm7,[esi+ebx-2]
+    movd    eax,mm5
+    movzx   edx,ax  
+    mov     [w1],edx
+    shr     eax,16
+    mov     [w2],eax
+    psrlq   mm5,32
+    movd    eax,mm5
+    movzx   edx,ax  
+    mov     [w3],edx
+    movd    eax,mm6
+    movzx   edx,ax  
+    mov     [w4],edx
+    shr     eax,16
+    mov     [w5],eax
+    psrlq   mm6,32
+    movd    eax,mm6
+    movzx   edx,ax  
+    mov     [w6],edx
+    movd    eax,mm7
+    movzx   edx,ax  
+    mov     [w7],edx
+    shr     eax,16
+    mov     [w8],eax
+    psrlq   mm7,32
+    movd    eax,mm7
+    movzx   edx,ax  
+    mov     [w9],edx
+.flags
+    mov     ebx,_RGBtoYUV
+    mov     eax,[w5]
+    xor     ecx,ecx
+    movd    mm5,[ebx+eax*4]
+    mov     dword[cross],0
+
+    mov     edx,[w2]
+    cmp     eax,edx
+    je      .noflag2
+    or      dword[cross],1
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag2
+    or      ecx,2
+.noflag2
+    mov     edx,[w4]
+    cmp     eax,edx
+    je      .noflag4
+    or      dword[cross],2
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag4
+    or      ecx,8
+.noflag4
+    mov     edx,[w6]
+    cmp     eax,edx
+    je      .noflag6
+    or      dword[cross],4
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag6
+    or      ecx,16
+.noflag6
+    mov     edx,[w8]
+    cmp     eax,edx
+    je      .noflag8
+    or      dword[cross],8
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag8
+    or      ecx,64
+.noflag8
+    test    ecx,ecx
+    jnz     .testflag1
+    mov     ecx,[cross]
+    mov     ebx,_LUT16to32
+    mov     eax,[ebx+eax*4]
+    jmp     [FuncTable2+ecx*4]
+.testflag1
+    mov     edx,[w1]
+    cmp     eax,edx
+    je      .noflag1
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag1
+    or      ecx,1
+.noflag1
+    mov     edx,[w3]
+    cmp     eax,edx
+    je      .noflag3
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag3
+    or      ecx,4
+.noflag3
+    mov     edx,[w7]
+    cmp     eax,edx
+    je      .noflag7
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag7
+    or      ecx,32
+.noflag7
+    mov     edx,[w9]
+    cmp     eax,edx
+    je      .noflag9
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag9
+    or      ecx,128
+.noflag9
+    mov  ebx,_LUT16to32
+    mov  eax,[ebx+eax*4]
+    mov  edx,[w2]
+    mov  edx,[ebx+edx*4]
+    mov  [c2],edx
+    mov  edx,[w4]
+    mov  edx,[ebx+edx*4]
+    mov  [c4],edx
+    mov  edx,[w6]
+    mov  edx,[ebx+edx*4]
+    mov  [c6],edx
+    mov  edx,[w8]
+    mov  edx,[ebx+edx*4]
+    mov  [c8],edx
+    test ecx,0x005A
+    jz  .switch
+    mov  edx,[w1]
+    mov  edx,[ebx+edx*4]
+    mov  [c1],edx
+    mov  edx,[w3]
+    mov  edx,[ebx+edx*4]
+    mov  [c3],edx
+    mov  edx,[w7]
+    mov  edx,[ebx+edx*4]
+    mov  [c7],edx
+    mov  edx,[w9]
+    mov  edx,[ebx+edx*4]
+    mov  [c9],edx
+.switch
+    mov  ebx,[ebp+dstpitch]
+    jmp  [FuncTable+ecx*4]
+
+..@flag0
+..@flag1
+..@flag4
+..@flag32
+..@flag128
+..@flag5
+..@flag132
+..@flag160
+..@flag33
+..@flag129
+..@flag36
+..@flag133
+..@flag164
+..@flag161
+..@flag37
+..@flag165
+;    PIXEL00_20
+;    PIXEL01_20
+;    PIXEL10_20
+;    PIXEL11_20
+
+;   the same, only optimized
+    shl eax,1
+    mov ecx,eax
+    add ecx,[c2]
+    mov edx,ecx
+    add edx,[c4]
+    shr edx,2
+    mov [edi],edx
+    add ecx,[c6]
+    shr ecx,2
+    mov [edi+4],ecx
+    mov ecx,eax
+    add ecx,[c8]
+    mov edx,ecx
+    add edx,[c4]
+    shr edx,2
+    mov [edi+ebx],edx
+    add ecx,[c6]
+    shr ecx,2
+    mov [edi+ebx+4],ecx
+    jmp .loopx_end
+..@flag2
+..@flag34
+..@flag130
+..@flag162
+    PIXEL00_22
+    PIXEL01_21
+    PIXEL10_20
+    PIXEL11_20
+    jmp .loopx_end
+..@flag16
+..@flag17
+..@flag48
+..@flag49
+    PIXEL00_20
+    PIXEL01_22
+    PIXEL10_20
+    PIXEL11_21
+    jmp .loopx_end
+..@flag64
+..@flag65
+..@flag68
+..@flag69
+    PIXEL00_20
+    PIXEL01_20
+    PIXEL10_21
+    PIXEL11_22
+    jmp .loopx_end
+..@flag8
+..@flag12
+..@flag136
+..@flag140
+    PIXEL00_21
+    PIXEL01_20
+    PIXEL10_22
+    PIXEL11_20
+    jmp .loopx_end
+..@flag3
+..@flag35
+..@flag131
+..@flag163
+    PIXEL00_11
+    PIXEL01_21
+    PIXEL10_20
+    PIXEL11_20
+    jmp .loopx_end
+..@flag6
+..@flag38
+..@flag134
+..@flag166
+    PIXEL00_22
+    PIXEL01_12
+    PIXEL10_20
+    PIXEL11_20
+    jmp .loopx_end
+..@flag20
+..@flag21
+..@flag52
+..@flag53
+    PIXEL00_20
+    PIXEL01_11
+    PIXEL10_20
+    PIXEL11_21
+    jmp .loopx_end
+..@flag144
+..@flag145
+..@flag176
+..@flag177
+    PIXEL00_20
+    PIXEL01_22
+    PIXEL10_20
+    PIXEL11_12
+    jmp .loopx_end
+..@flag192
+..@flag193
+..@flag196
+..@flag197
+    PIXEL00_20
+    PIXEL01_20
+    PIXEL10_21
+    PIXEL11_11
+    jmp .loopx_end
+..@flag96
+..@flag97
+..@flag100
+..@flag101
+    PIXEL00_20
+    PIXEL01_20
+    PIXEL10_12
+    PIXEL11_22
+    jmp .loopx_end
+..@flag40
+..@flag44
+..@flag168
+..@flag172
+    PIXEL00_21
+    PIXEL01_20
+    PIXEL10_11
+    PIXEL11_20
+    jmp .loopx_end
+..@flag9
+..@flag13
+..@flag137
+..@flag141
+    PIXEL00_12
+    PIXEL01_20
+    PIXEL10_22
+    PIXEL11_20
+    jmp .loopx_end
+..@flag18
+..@flag50
+    PIXEL00_22
+    DiffOrNot w2,w6,PIXEL01_10,PIXEL01_20
+    PIXEL10_20
+    PIXEL11_21
+    jmp .loopx_end
+..@flag80
+..@flag81
+    PIXEL00_20
+    PIXEL01_22
+    PIXEL10_21
+    DiffOrNot w6,w8,PIXEL11_10,PIXEL11_20
+    jmp .loopx_end
+..@flag72
+..@flag76
+    PIXEL00_21
+    PIXEL01_20
+    DiffOrNot w8,w4,PIXEL10_10,PIXEL10_20
+    PIXEL11_22
+    jmp .loopx_end
+..@flag10
+..@flag138
+    DiffOrNot w4,w2,PIXEL00_10,PIXEL00_20
+    PIXEL01_21
+    PIXEL10_22
+    PIXEL11_20
+    jmp .loopx_end
+..@flag66
+    PIXEL00_22
+    PIXEL01_21
+    PIXEL10_21
+    PIXEL11_22
+    jmp .loopx_end
+..@flag24
+    PIXEL00_21
+    PIXEL01_22
+    PIXEL10_22
+    PIXEL11_21
+    jmp .loopx_end
+..@flag7
+..@flag39
+..@flag135
+    PIXEL00_11
+    PIXEL01_12
+    PIXEL10_20
+    PIXEL11_20
+    jmp .loopx_end
+..@flag148
+..@flag149
+..@flag180
+    PIXEL00_20
+    PIXEL01_11
+    PIXEL10_20
+    PIXEL11_12
+    jmp .loopx_end
+..@flag224
+..@flag228
+..@flag225
+    PIXEL00_20
+    PIXEL01_20
+    PIXEL10_12
+    PIXEL11_11
+    jmp .loopx_end
+..@flag41
+..@flag169
+..@flag45
+    PIXEL00_12
+    PIXEL01_20
+    PIXEL10_11
+    PIXEL11_20
+    jmp .loopx_end
+..@flag22
+..@flag54
+    PIXEL00_22
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20
+    PIXEL10_20
+    PIXEL11_21
+    jmp .loopx_end
+..@flag208
+..@flag209
+    PIXEL00_20
+    PIXEL01_22
+    PIXEL10_21
+    DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20
+    jmp .loopx_end
+..@flag104
+..@flag108
+    PIXEL00_21
+    PIXEL01_20
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20
+    PIXEL11_22
+    jmp .loopx_end
+..@flag11
+..@flag139
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20
+    PIXEL01_21
+    PIXEL10_22
+    PIXEL11_20
+    jmp .loopx_end
+..@flag19
+..@flag51
+    DiffOrNot w2,w6,PIXEL00_11,PIXEL01_10,PIXEL00_60,PIXEL01_90
+    PIXEL10_20
+    PIXEL11_21
+    jmp .loopx_end
+..@flag146
+..@flag178
+    PIXEL00_22
+    DiffOrNot w2,w6,PIXEL01_10,PIXEL11_12,PIXEL01_90,PIXEL11_61
+    PIXEL10_20
+    jmp .loopx_end
+..@flag84
+..@flag85
+    PIXEL00_20
+    DiffOrNot w6,w8,PIXEL01_11,PIXEL11_10,PIXEL01_60,PIXEL11_90
+    PIXEL10_21
+    jmp .loopx_end
+..@flag112
+..@flag113
+    PIXEL00_20
+    PIXEL01_22
+    DiffOrNot w6,w8,PIXEL10_12,PIXEL11_10,PIXEL10_61,PIXEL11_90
+    jmp .loopx_end
+..@flag200
+..@flag204
+    PIXEL00_21
+    PIXEL01_20
+    DiffOrNot w8,w4,PIXEL10_10,PIXEL11_11,PIXEL10_90,PIXEL11_60
+    jmp .loopx_end
+..@flag73
+..@flag77
+    DiffOrNot w8,w4,PIXEL00_12,PIXEL10_10,PIXEL00_61,PIXEL10_90
+    PIXEL01_20
+    PIXEL11_22
+    jmp .loopx_end
+..@flag42
+..@flag170
+    DiffOrNot w4,w2,PIXEL00_10,PIXEL10_11,PIXEL00_90,PIXEL10_60
+    PIXEL01_21
+    PIXEL11_20
+    jmp .loopx_end
+..@flag14
+..@flag142
+    DiffOrNot w4,w2,PIXEL00_10,PIXEL01_12,PIXEL00_90,PIXEL01_61
+    PIXEL10_22
+    PIXEL11_20
+    jmp .loopx_end
+..@flag67
+    PIXEL00_11
+    PIXEL01_21
+    PIXEL10_21
+    PIXEL11_22
+    jmp .loopx_end
+..@flag70
+    PIXEL00_22
+    PIXEL01_12
+    PIXEL10_21
+    PIXEL11_22
+    jmp .loopx_end
+..@flag28
+    PIXEL00_21
+    PIXEL01_11
+    PIXEL10_22
+    PIXEL11_21
+    jmp .loopx_end
+..@flag152
+    PIXEL00_21
+    PIXEL01_22
+    PIXEL10_22
+    PIXEL11_12
+    jmp .loopx_end
+..@flag194
+    PIXEL00_22
+    PIXEL01_21
+    PIXEL10_21
+    PIXEL11_11
+    jmp .loopx_end
+..@flag98
+    PIXEL00_22
+    PIXEL01_21
+    PIXEL10_12
+    PIXEL11_22
+    jmp .loopx_end
+..@flag56
+    PIXEL00_21
+    PIXEL01_22
+    PIXEL10_11
+    PIXEL11_21
+    jmp .loopx_end
+..@flag25
+    PIXEL00_12
+    PIXEL01_22
+    PIXEL10_22
+    PIXEL11_21
+    jmp .loopx_end
+..@flag26
+..@flag31
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20
+    PIXEL10_22
+    PIXEL11_21
+    jmp .loopx_end
+..@flag82
+..@flag214
+    PIXEL00_22
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20
+    PIXEL10_21
+    DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20
+    jmp .loopx_end
+..@flag88
+..@flag248
+    PIXEL00_21
+    PIXEL01_22
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20
+    DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20
+    jmp .loopx_end
+..@flag74
+..@flag107
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20
+    PIXEL01_21
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20
+    PIXEL11_22
+    jmp .loopx_end
+..@flag27
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20
+    PIXEL01_10
+    PIXEL10_22
+    PIXEL11_21
+    jmp .loopx_end
+..@flag86
+    PIXEL00_22
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20
+    PIXEL10_21
+    PIXEL11_10
+    jmp .loopx_end
+..@flag216
+    PIXEL00_21
+    PIXEL01_22
+    PIXEL10_10
+    DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20
+    jmp .loopx_end
+..@flag106
+    PIXEL00_10
+    PIXEL01_21
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20
+    PIXEL11_22
+    jmp .loopx_end
+..@flag30
+    PIXEL00_10
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20
+    PIXEL10_22
+    PIXEL11_21
+    jmp .loopx_end
+..@flag210
+    PIXEL00_22
+    PIXEL01_10
+    PIXEL10_21
+    DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20
+    jmp .loopx_end
+..@flag120
+    PIXEL00_21
+    PIXEL01_22
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20
+    PIXEL11_10
+    jmp .loopx_end
+..@flag75
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20
+    PIXEL01_21
+    PIXEL10_10
+    PIXEL11_22
+    jmp .loopx_end
+..@flag29
+    PIXEL00_12
+    PIXEL01_11
+    PIXEL10_22
+    PIXEL11_21
+    jmp .loopx_end
+..@flag198
+    PIXEL00_22
+    PIXEL01_12
+    PIXEL10_21
+    PIXEL11_11
+    jmp .loopx_end
+..@flag184
+    PIXEL00_21
+    PIXEL01_22
+    PIXEL10_11
+    PIXEL11_12
+    jmp .loopx_end
+..@flag99
+    PIXEL00_11
+    PIXEL01_21
+    PIXEL10_12
+    PIXEL11_22
+    jmp .loopx_end
+..@flag57
+    PIXEL00_12
+    PIXEL01_22
+    PIXEL10_11
+    PIXEL11_21
+    jmp .loopx_end
+..@flag71
+    PIXEL00_11
+    PIXEL01_12
+    PIXEL10_21
+    PIXEL11_22
+    jmp .loopx_end
+..@flag156
+    PIXEL00_21
+    PIXEL01_11
+    PIXEL10_22
+    PIXEL11_12
+    jmp .loopx_end
+..@flag226
+    PIXEL00_22
+    PIXEL01_21
+    PIXEL10_12
+    PIXEL11_11
+    jmp .loopx_end
+..@flag60
+    PIXEL00_21
+    PIXEL01_11
+    PIXEL10_11
+    PIXEL11_21
+    jmp .loopx_end
+..@flag195
+    PIXEL00_11
+    PIXEL01_21
+    PIXEL10_21
+    PIXEL11_11
+    jmp .loopx_end
+..@flag102
+    PIXEL00_22
+    PIXEL01_12
+    PIXEL10_12
+    PIXEL11_22
+    jmp .loopx_end
+..@flag153
+    PIXEL00_12
+    PIXEL01_22
+    PIXEL10_22
+    PIXEL11_12
+    jmp .loopx_end
+..@flag58
+    DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70
+    DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70
+    PIXEL10_11
+    PIXEL11_21
+    jmp .loopx_end
+..@flag83
+    PIXEL00_11
+    DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70
+    PIXEL10_21
+    DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70
+    jmp .loopx_end
+..@flag92
+    PIXEL00_21
+    PIXEL01_11
+    DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70
+    DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70
+    jmp .loopx_end
+..@flag202
+    DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70
+    PIXEL01_21
+    DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70
+    PIXEL11_11
+    jmp .loopx_end
+..@flag78
+    DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70
+    PIXEL01_12
+    DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70
+    PIXEL11_22
+    jmp .loopx_end
+..@flag154
+    DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70
+    DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70
+    PIXEL10_22
+    PIXEL11_12
+    jmp .loopx_end
+..@flag114
+    PIXEL00_22
+    DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70
+    PIXEL10_12
+    DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70
+    jmp .loopx_end
+..@flag89
+    PIXEL00_12
+    PIXEL01_22
+    DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70
+    DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70
+    jmp .loopx_end
+..@flag90
+    DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70
+    DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70
+    DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70
+    DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70
+    jmp .loopx_end
+..@flag55
+..@flag23
+    DiffOrNot w2,w6,PIXEL00_11,PIXEL01_0,PIXEL00_60,PIXEL01_90
+    PIXEL10_20
+    PIXEL11_21
+    jmp .loopx_end
+..@flag182
+..@flag150
+    PIXEL00_22
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL11_12,PIXEL01_90,PIXEL11_61
+    PIXEL10_20
+    jmp .loopx_end
+..@flag213
+..@flag212
+    PIXEL00_20
+    DiffOrNot w6,w8,PIXEL01_11,PIXEL11_0,PIXEL01_60,PIXEL11_90
+    PIXEL10_21
+    jmp .loopx_end
+..@flag241
+..@flag240
+    PIXEL00_20
+    PIXEL01_22
+    DiffOrNot w6,w8,PIXEL10_12,PIXEL11_0,PIXEL10_61,PIXEL11_90
+    jmp .loopx_end
+..@flag236
+..@flag232
+    PIXEL00_21
+    PIXEL01_20
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL11_11,PIXEL10_90,PIXEL11_60
+    jmp .loopx_end
+..@flag109
+..@flag105
+    DiffOrNot w8,w4,PIXEL00_12,PIXEL10_0,PIXEL00_61,PIXEL10_90
+    PIXEL01_20
+    PIXEL11_22
+    jmp .loopx_end
+..@flag171
+..@flag43
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL10_11,PIXEL00_90,PIXEL10_60
+    PIXEL01_21
+    PIXEL11_20
+    jmp .loopx_end
+..@flag143
+..@flag15
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL01_12,PIXEL00_90,PIXEL01_61
+    PIXEL10_22
+    PIXEL11_20
+    jmp .loopx_end
+..@flag124
+    PIXEL00_21
+    PIXEL01_11
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20
+    PIXEL11_10
+    jmp .loopx_end
+..@flag203
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20
+    PIXEL01_21
+    PIXEL10_10
+    PIXEL11_11
+    jmp .loopx_end
+..@flag62
+    PIXEL00_10
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20
+    PIXEL10_11
+    PIXEL11_21
+    jmp .loopx_end
+..@flag211
+    PIXEL00_11
+    PIXEL01_10
+    PIXEL10_21
+    DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20
+    jmp .loopx_end
+..@flag118
+    PIXEL00_22
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20
+    PIXEL10_12
+    PIXEL11_10
+    jmp .loopx_end
+..@flag217
+    PIXEL00_12
+    PIXEL01_22
+    PIXEL10_10
+    DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20
+    jmp .loopx_end
+..@flag110
+    PIXEL00_10
+    PIXEL01_12
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20
+    PIXEL11_22
+    jmp .loopx_end
+..@flag155
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20
+    PIXEL01_10
+    PIXEL10_22
+    PIXEL11_12
+    jmp .loopx_end
+..@flag188
+    PIXEL00_21
+    PIXEL01_11
+    PIXEL10_11
+    PIXEL11_12
+    jmp .loopx_end
+..@flag185
+    PIXEL00_12
+    PIXEL01_22
+    PIXEL10_11
+    PIXEL11_12
+    jmp .loopx_end
+..@flag61
+    PIXEL00_12
+    PIXEL01_11
+    PIXEL10_11
+    PIXEL11_21
+    jmp .loopx_end
+..@flag157
+    PIXEL00_12
+    PIXEL01_11
+    PIXEL10_22
+    PIXEL11_12
+    jmp .loopx_end
+..@flag103
+    PIXEL00_11
+    PIXEL01_12
+    PIXEL10_12
+    PIXEL11_22
+    jmp .loopx_end
+..@flag227
+    PIXEL00_11
+    PIXEL01_21
+    PIXEL10_12
+    PIXEL11_11
+    jmp .loopx_end
+..@flag230
+    PIXEL00_22
+    PIXEL01_12
+    PIXEL10_12
+    PIXEL11_11
+    jmp .loopx_end
+..@flag199
+    PIXEL00_11
+    PIXEL01_12
+    PIXEL10_21
+    PIXEL11_11
+    jmp .loopx_end
+..@flag220
+    PIXEL00_21
+    PIXEL01_11
+    DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70
+    DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20
+    jmp .loopx_end
+..@flag158
+    DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20
+    PIXEL10_22
+    PIXEL11_12
+    jmp .loopx_end
+..@flag234
+    DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70
+    PIXEL01_21
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20
+    PIXEL11_11
+    jmp .loopx_end
+..@flag242
+    PIXEL00_22
+    DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70
+    PIXEL10_12
+    DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20
+    jmp .loopx_end
+..@flag59
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20
+    DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70
+    PIXEL10_11
+    PIXEL11_21
+    jmp .loopx_end
+..@flag121
+    PIXEL00_12
+    PIXEL01_22
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20
+    DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70
+    jmp .loopx_end
+..@flag87
+    PIXEL00_11
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20
+    PIXEL10_21
+    DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70
+    jmp .loopx_end
+..@flag79
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20
+    PIXEL01_12
+    DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70
+    PIXEL11_22
+    jmp .loopx_end
+..@flag122
+    DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70
+    DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20
+    DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70
+    jmp .loopx_end
+..@flag94
+    DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20
+    DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70
+    DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70
+    jmp .loopx_end
+..@flag218
+    DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70
+    DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70
+    DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70
+    DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20
+    jmp .loopx_end
+..@flag91
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20
+    DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70
+    DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70
+    DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70
+    jmp .loopx_end
+..@flag229
+    PIXEL00_20
+    PIXEL01_20
+    PIXEL10_12
+    PIXEL11_11
+    jmp .loopx_end
+..@flag167
+    PIXEL00_11
+    PIXEL01_12
+    PIXEL10_20
+    PIXEL11_20
+    jmp .loopx_end
+..@flag173
+    PIXEL00_12
+    PIXEL01_20
+    PIXEL10_11
+    PIXEL11_20
+    jmp .loopx_end
+..@flag181
+    PIXEL00_20
+    PIXEL01_11
+    PIXEL10_20
+    PIXEL11_12
+    jmp .loopx_end
+..@flag186
+    DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70
+    DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70
+    PIXEL10_11
+    PIXEL11_12
+    jmp .loopx_end
+..@flag115
+    PIXEL00_11
+    DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70
+    PIXEL10_12
+    DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70
+    jmp .loopx_end
+..@flag93
+    PIXEL00_12
+    PIXEL01_11
+    DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70
+    DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70
+    jmp .loopx_end
+..@flag206
+    DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70
+    PIXEL01_12
+    DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70
+    PIXEL11_11
+    jmp .loopx_end
+..@flag205
+..@flag201
+    PIXEL00_12
+    PIXEL01_20
+    DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70
+    PIXEL11_11
+    jmp .loopx_end
+..@flag174
+..@flag46
+    DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70
+    PIXEL01_12
+    PIXEL10_11
+    PIXEL11_20
+    jmp .loopx_end
+..@flag179
+..@flag147
+    PIXEL00_11
+    DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70
+    PIXEL10_20
+    PIXEL11_12
+    jmp .loopx_end
+..@flag117
+..@flag116
+    PIXEL00_20
+    PIXEL01_11
+    PIXEL10_12
+    DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70
+    jmp .loopx_end
+..@flag189
+    PIXEL00_12
+    PIXEL01_11
+    PIXEL10_11
+    PIXEL11_12
+    jmp .loopx_end
+..@flag231
+    PIXEL00_11
+    PIXEL01_12
+    PIXEL10_12
+    PIXEL11_11
+    jmp .loopx_end
+..@flag126
+    PIXEL00_10
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20
+    PIXEL11_10
+    jmp .loopx_end
+..@flag219
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20
+    PIXEL01_10
+    PIXEL10_10
+    DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20
+    jmp .loopx_end
+..@flag125
+    DiffOrNot w8,w4,PIXEL00_12,PIXEL10_0,PIXEL00_61,PIXEL10_90
+    PIXEL01_11
+    PIXEL11_10
+    jmp .loopx_end
+..@flag221
+    PIXEL00_12
+    DiffOrNot w6,w8,PIXEL01_11,PIXEL11_0,PIXEL01_60,PIXEL11_90
+    PIXEL10_10
+    jmp .loopx_end
+..@flag207
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL01_12,PIXEL00_90,PIXEL01_61
+    PIXEL10_10
+    PIXEL11_11
+    jmp .loopx_end
+..@flag238
+    PIXEL00_10
+    PIXEL01_12
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL11_11,PIXEL10_90,PIXEL11_60
+    jmp .loopx_end
+..@flag190
+    PIXEL00_10
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL11_12,PIXEL01_90,PIXEL11_61
+    PIXEL10_11
+    jmp .loopx_end
+..@flag187
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL10_11,PIXEL00_90,PIXEL10_60
+    PIXEL01_10
+    PIXEL11_12
+    jmp .loopx_end
+..@flag243
+    PIXEL00_11
+    PIXEL01_10
+    DiffOrNot w6,w8,PIXEL10_12,PIXEL11_0,PIXEL10_61,PIXEL11_90
+    jmp .loopx_end
+..@flag119
+    DiffOrNot w2,w6,PIXEL00_11,PIXEL01_0,PIXEL00_60,PIXEL01_90
+    PIXEL10_12
+    PIXEL11_10
+    jmp .loopx_end
+..@flag237
+..@flag233
+    PIXEL00_12
+    PIXEL01_20
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL10_100
+    PIXEL11_11
+    jmp .loopx_end
+..@flag175
+..@flag47
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_100
+    PIXEL01_12
+    PIXEL10_11
+    PIXEL11_20
+    jmp .loopx_end
+..@flag183
+..@flag151
+    PIXEL00_11
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL01_100
+    PIXEL10_20
+    PIXEL11_12
+    jmp .loopx_end
+..@flag245
+..@flag244
+    PIXEL00_20
+    PIXEL01_11
+    PIXEL10_12
+    DiffOrNot w6,w8,PIXEL11_0,PIXEL11_100
+    jmp .loopx_end
+..@flag250
+    PIXEL00_10
+    PIXEL01_10
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20
+    DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20
+    jmp .loopx_end
+..@flag123
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20
+    PIXEL01_10
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20
+    PIXEL11_10
+    jmp .loopx_end
+..@flag95
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20
+    PIXEL10_10
+    PIXEL11_10
+    jmp .loopx_end
+..@flag222
+    PIXEL00_10
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20
+    PIXEL10_10
+    DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20
+    jmp .loopx_end
+..@flag252
+    PIXEL00_21
+    PIXEL01_11
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20
+    DiffOrNot w6,w8,PIXEL11_0,PIXEL11_100
+    jmp .loopx_end
+..@flag249
+    PIXEL00_12
+    PIXEL01_22
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL10_100
+    DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20
+    jmp .loopx_end
+..@flag235
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20
+    PIXEL01_21
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL10_100
+    PIXEL11_11
+    jmp .loopx_end
+..@flag111
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_100
+    PIXEL01_12
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20
+    PIXEL11_22
+    jmp .loopx_end
+..@flag63
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_100
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20
+    PIXEL10_11
+    PIXEL11_21
+    jmp .loopx_end
+..@flag159
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL01_100
+    PIXEL10_22
+    PIXEL11_12
+    jmp .loopx_end
+..@flag215
+    PIXEL00_11
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL01_100
+    PIXEL10_21
+    DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20
+    jmp .loopx_end
+..@flag246
+    PIXEL00_22
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20
+    PIXEL10_12
+    DiffOrNot w6,w8,PIXEL11_0,PIXEL11_100
+    jmp .loopx_end
+..@flag254
+    PIXEL00_10
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20
+    DiffOrNot w6,w8,PIXEL11_0,PIXEL11_100
+    jmp .loopx_end
+..@flag253
+    PIXEL00_12
+    PIXEL01_11
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL10_100
+    DiffOrNot w6,w8,PIXEL11_0,PIXEL11_100
+    jmp .loopx_end
+..@flag251
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20
+    PIXEL01_10
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL10_100
+    DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20
+    jmp .loopx_end
+..@flag239
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_100
+    PIXEL01_12
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL10_100
+    PIXEL11_11
+    jmp .loopx_end
+..@flag127
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_100
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20
+    PIXEL11_10
+    jmp .loopx_end
+..@flag191
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_100
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL01_100
+    PIXEL10_11
+    PIXEL11_12
+    jmp .loopx_end
+..@flag223
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL01_100
+    PIXEL10_10
+    DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20
+    jmp .loopx_end
+..@flag247
+    PIXEL00_11
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL01_100
+    PIXEL10_12
+    DiffOrNot w6,w8,PIXEL11_0,PIXEL11_100
+    jmp .loopx_end
+..@flag255
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_100
+    DiffOrNot w2,w6,PIXEL01_0,PIXEL01_100
+    DiffOrNot w8,w4,PIXEL10_0,PIXEL10_100
+    DiffOrNot w6,w8,PIXEL11_0,PIXEL11_100
+    jmp .loopx_end
+
+
+..@cross0
+    mov     ebx,[ebp+dstpitch]
+    mov     [edi],eax
+    mov     [edi+4],eax
+    mov     [edi+ebx],eax
+    mov     [edi+ebx+4],eax
+    jmp     .loopx_end
+..@cross1
+    mov     ecx,[w2] 
+    mov     edx,eax
+    shl     edx,2
+    add     edx,[ebx+ecx*4]
+    sub     edx,eax
+    shr     edx,2
+    mov     ebx,[ebp+dstpitch]
+    mov     [edi],edx
+    mov     [edi+4],edx
+    mov     [edi+ebx],eax
+    mov     [edi+ebx+4],eax
+    jmp     .loopx_end
+..@cross2
+    mov     ecx,[w4]
+    mov     edx,eax
+    shl     edx,2
+    add     edx,[ebx+ecx*4]
+    sub     edx,eax
+    shr     edx,2
+    mov     ebx,[ebp+dstpitch]
+    mov     [edi],edx
+    mov     [edi+4],eax
+    mov     [edi+ebx],edx
+    mov     [edi+ebx+4],eax
+    jmp     .loopx_end
+..@cross4
+    mov     ecx,[w6]
+    mov     edx,eax
+    shl     edx,2
+    add     edx,[ebx+ecx*4]
+    sub     edx,eax
+    shr     edx,2
+    mov     ebx,[ebp+dstpitch]
+    mov     [edi],eax
+    mov     [edi+4],edx
+    mov     [edi+ebx],eax
+    mov     [edi+ebx+4],edx
+    jmp     .loopx_end
+..@cross8
+    mov     ecx,[w8]
+    mov     edx,eax
+    shl     edx,2
+    add     edx,[ebx+ecx*4]
+    sub     edx,eax
+    shr     edx,2
+    mov     ebx,[ebp+dstpitch]
+    mov     [edi],eax
+    mov     [edi+4],eax
+    mov     [edi+ebx],edx
+    mov     [edi+ebx+4],edx
+    jmp     .loopx_end
+..@crossN
+    mov     edx,[w2]
+    mov     ecx,[ebx+edx*4]
+    mov     [c2],ecx
+    mov     edx,[w4]
+    mov     ecx,[ebx+edx*4]
+    mov     [c4],ecx
+    mov     edx,[w6]
+    mov     ecx,[ebx+edx*4]
+    mov     [c6],ecx
+    mov     edx,[w8]
+    mov     ecx,[ebx+edx*4]
+    mov     [c8],ecx
+    mov     ebx,[ebp+dstpitch]
+    jmp     ..@flag0
+
+.loopx_end
+    add     esi,2
+    add     edi,8
+    dec     dword[xcounter]
+    jle     .xres_2
+    jmp     .loopx
+.xres_2
+    ; x=Xres-2 - special case
+    jl      .xres_1
+    mov     ebx,[prevline]
+    movq    mm5,[esi+ebx-4]
+    movq    mm6,[esi-4]
+    mov     ebx,[nextline]
+    movq    mm7,[esi+ebx-4]
+    psrlq   mm5,16
+    psrlq   mm6,16
+    psrlq   mm7,16
+    movd    eax,mm5
+    movzx   edx,ax
+    mov     [w1],edx
+    shr     eax,16
+    mov     [w2],eax
+    psrlq   mm5,32
+    movd    eax,mm5
+    mov     [w3],eax
+    movd    eax,mm6
+    movzx   edx,ax
+    mov     [w4],edx
+    shr     eax,16
+    mov     [w5],eax
+    psrlq   mm6,32
+    movd    eax,mm6
+    mov     [w6],eax
+    movd    eax,mm7
+    movzx   edx,ax
+    mov     [w7],edx
+    shr     eax,16
+    mov     [w8],eax
+    psrlq   mm7,32
+    movd    eax,mm7
+    mov     [w9],eax
+    jmp     .flags
+.xres_1
+    cmp     dword[xcounter],-1
+    jl      .nexty
+    ; x=Xres-1 - special case
+    mov     ebx,[prevline]
+    movq    mm5,[esi+ebx-6]
+    movq    mm6,[esi-6]
+    mov     ebx,[nextline]
+    movq    mm7,[esi+ebx-6]
+    psrlq   mm5,32
+    psrlq   mm6,32
+    psrlq   mm7,32
+    movd    eax,mm5
+    movzx   edx,ax  
+    mov     [w1],edx
+    shr     eax,16
+    mov     [w2],eax
+    mov     [w3],eax
+    movd    eax,mm6
+    movzx   edx,ax  
+    mov     [w4],edx
+    shr     eax,16
+    mov     [w5],eax
+    mov     [w6],eax
+    movd    eax,mm7
+    movzx   edx,ax  
+    mov     [w7],edx
+    shr     eax,16
+    mov     [w8],eax
+    mov     [w9],eax
+    jmp     .flags
+.nexty
+    add     edi,ebx
+    add     esi,[ebp+srcpitch]
+    sub     esi,[ebp+Xres]
+    sub     esi,[ebp+Xres]
+    dec     dword[linesleft]
+    jz      .fin
+    mov     ebx,[ebp+Xres]
+    shl     ebx,1
+    cmp     dword[linesleft],1
+    je      .lastline
+    mov     dword[nextline],ebx
+    neg     ebx
+    mov     dword[prevline],ebx
+    jmp     .loopy
+.lastline
+    mov     dword[nextline],0
+    neg     ebx
+    mov     dword[prevline],ebx
+    jmp     .loopy
+.fin
+    emms
+    popad
+    mov esp,ebp
+    pop ebp
+    ret
+
+SECTION .data
+FuncTable
+    dd ..@flag0, ..@flag1, ..@flag2, ..@flag3, ..@flag4, ..@flag5, ..@flag6, ..@flag7
+    dd ..@flag8, ..@flag9, ..@flag10, ..@flag11, ..@flag12, ..@flag13, ..@flag14, ..@flag15
+    dd ..@flag16, ..@flag17, ..@flag18, ..@flag19, ..@flag20, ..@flag21, ..@flag22, ..@flag23
+    dd ..@flag24, ..@flag25, ..@flag26, ..@flag27, ..@flag28, ..@flag29, ..@flag30, ..@flag31
+    dd ..@flag32, ..@flag33, ..@flag34, ..@flag35, ..@flag36, ..@flag37, ..@flag38, ..@flag39
+    dd ..@flag40, ..@flag41, ..@flag42, ..@flag43, ..@flag44, ..@flag45, ..@flag46, ..@flag47
+    dd ..@flag48, ..@flag49, ..@flag50, ..@flag51, ..@flag52, ..@flag53, ..@flag54, ..@flag55
+    dd ..@flag56, ..@flag57, ..@flag58, ..@flag59, ..@flag60, ..@flag61, ..@flag62, ..@flag63
+    dd ..@flag64, ..@flag65, ..@flag66, ..@flag67, ..@flag68, ..@flag69, ..@flag70, ..@flag71
+    dd ..@flag72, ..@flag73, ..@flag74, ..@flag75, ..@flag76, ..@flag77, ..@flag78, ..@flag79
+    dd ..@flag80, ..@flag81, ..@flag82, ..@flag83, ..@flag84, ..@flag85, ..@flag86, ..@flag87
+    dd ..@flag88, ..@flag89, ..@flag90, ..@flag91, ..@flag92, ..@flag93, ..@flag94, ..@flag95
+    dd ..@flag96, ..@flag97, ..@flag98, ..@flag99, ..@flag100, ..@flag101, ..@flag102, ..@flag103
+    dd ..@flag104, ..@flag105, ..@flag106, ..@flag107, ..@flag108, ..@flag109, ..@flag110, ..@flag111
+    dd ..@flag112, ..@flag113, ..@flag114, ..@flag115, ..@flag116, ..@flag117, ..@flag118, ..@flag119
+    dd ..@flag120, ..@flag121, ..@flag122, ..@flag123, ..@flag124, ..@flag125, ..@flag126, ..@flag127
+    dd ..@flag128, ..@flag129, ..@flag130, ..@flag131, ..@flag132, ..@flag133, ..@flag134, ..@flag135
+    dd ..@flag136, ..@flag137, ..@flag138, ..@flag139, ..@flag140, ..@flag141, ..@flag142, ..@flag143
+    dd ..@flag144, ..@flag145, ..@flag146, ..@flag147, ..@flag148, ..@flag149, ..@flag150, ..@flag151
+    dd ..@flag152, ..@flag153, ..@flag154, ..@flag155, ..@flag156, ..@flag157, ..@flag158, ..@flag159
+    dd ..@flag160, ..@flag161, ..@flag162, ..@flag163, ..@flag164, ..@flag165, ..@flag166, ..@flag167
+    dd ..@flag168, ..@flag169, ..@flag170, ..@flag171, ..@flag172, ..@flag173, ..@flag174, ..@flag175
+    dd ..@flag176, ..@flag177, ..@flag178, ..@flag179, ..@flag180, ..@flag181, ..@flag182, ..@flag183
+    dd ..@flag184, ..@flag185, ..@flag186, ..@flag187, ..@flag188, ..@flag189, ..@flag190, ..@flag191
+    dd ..@flag192, ..@flag193, ..@flag194, ..@flag195, ..@flag196, ..@flag197, ..@flag198, ..@flag199
+    dd ..@flag200, ..@flag201, ..@flag202, ..@flag203, ..@flag204, ..@flag205, ..@flag206, ..@flag207
+    dd ..@flag208, ..@flag209, ..@flag210, ..@flag211, ..@flag212, ..@flag213, ..@flag214, ..@flag215
+    dd ..@flag216, ..@flag217, ..@flag218, ..@flag219, ..@flag220, ..@flag221, ..@flag222, ..@flag223
+    dd ..@flag224, ..@flag225, ..@flag226, ..@flag227, ..@flag228, ..@flag229, ..@flag230, ..@flag231
+    dd ..@flag232, ..@flag233, ..@flag234, ..@flag235, ..@flag236, ..@flag237, ..@flag238, ..@flag239
+    dd ..@flag240, ..@flag241, ..@flag242, ..@flag243, ..@flag244, ..@flag245, ..@flag246, ..@flag247
+    dd ..@flag248, ..@flag249, ..@flag250, ..@flag251, ..@flag252, ..@flag253, ..@flag254, ..@flag255
+
+FuncTable2
+    dd ..@cross0, ..@cross1, ..@cross2, ..@crossN,
+    dd ..@cross4, ..@crossN, ..@crossN, ..@crossN,
+    dd ..@cross8, ..@crossN, ..@crossN, ..@crossN,
+    dd ..@crossN, ..@crossN, ..@crossN, ..@crossN
+
diff --git a/od-win32/hq3x16.asm b/od-win32/hq3x16.asm
new file mode 100755 (executable)
index 0000000..1596d78
--- /dev/null
@@ -0,0 +1,2430 @@
+;hq3x filter
+;16bpp output
+;----------------------------------------------------------
+;Copyright (C) 2003 MaxSt ( maxst@hiend3d.com )
+;
+;This program is free software; you can redistribute it and/or
+;modify it under the terms of the GNU General Public License
+;as published by the Free Software Foundation; either
+;version 2 of the License, or (at your option) any later
+;version.
+;
+;This program is distributed in the hope that it will be useful,
+;but WITHOUT ANY WARRANTY; without even the implied warranty of
+;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;GNU General Public License for more details.
+;
+;You should have received a copy of the GNU General Public License
+;along with this program; if not, write to the Free Software
+;Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+GLOBAL _hq3x_16
+
+EXTERN _LUT16to32
+EXTERN _RGBtoYUV
+
+SECTION .bss
+firstline resd 1
+linesleft resd 1
+xcounter  resd 1
+cross     resd 1
+nextline  resd 1
+prevline  resd 1
+w1        resd 1    
+w2        resd 1
+w3        resd 1
+w4        resd 1
+w5        resd 1
+w6        resd 1
+w7        resd 1
+w8        resd 1
+w9        resd 1
+
+SECTION .data
+
+reg_blank    dd  0,0
+const7       dd  0x00070007,0x00000007
+threshold    dd  0x00300706,0x00000000
+zerolowbits  dd  0xF7DEF7DE
+
+SECTION .text
+
+%macro TestDiff 2
+    xor     ecx,ecx
+    mov     edx,[%1]
+    cmp     edx,[%2]
+    je      %%fin
+    mov     ecx,_RGBtoYUV
+    movd    mm1,[ecx+edx*4]
+    movq    mm5,mm1
+    mov     edx,[%2]
+    movd    mm2,[ecx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    ecx,mm1
+%%fin:
+%endmacro
+
+%macro DiffOrNot 4
+    TestDiff %1,%2
+    test ecx,ecx
+    jz   %%same
+    %3
+    jmp %%fin
+%%same:
+    %4
+%%fin
+%endmacro
+
+%macro DiffOrNot 6
+    TestDiff %1,%2
+    test ecx,ecx
+    jz   %%same
+    %3
+    %4
+    jmp %%fin
+%%same:
+    %5
+    %6
+%%fin
+%endmacro
+
+%macro DiffOrNot 8
+    TestDiff %1,%2
+    test ecx,ecx
+    jz   %%same
+    %3
+    %4
+    %5
+    jmp %%fin
+%%same:
+    %6
+    %7
+    %8
+%%fin
+%endmacro
+
+%macro DiffOrNot 10
+    TestDiff %1,%2
+    test ecx,ecx
+    jz %%same
+    %3
+    %4
+    %5
+    %6
+    jmp %%fin
+%%same:
+    %7
+    %8
+    %9
+    %10
+%%fin
+%endmacro
+
+%macro Interp1 3
+    mov edx,%2
+    mov ecx,%3
+    cmp edx,ecx
+    je  %%fin
+    and edx,[zerolowbits]
+    and ecx,[zerolowbits]
+    add ecx,edx
+    shr ecx,1
+    add ecx,0x0821
+    and ecx,[zerolowbits]
+    add edx,ecx
+    shr edx,1
+%%fin
+    mov %1,dx
+%endmacro
+
+%macro Interp2 4
+    mov edx,%3
+    mov ecx,%4
+    cmp edx,ecx
+    je  %%fin1
+    and edx,[zerolowbits]
+    and ecx,[zerolowbits]
+    add ecx,edx
+    shr ecx,1
+    add ecx,0x0821
+%%fin1
+    mov edx,%2
+    cmp edx,ecx
+    je  %%fin2
+    and ecx,[zerolowbits]
+    and edx,[zerolowbits]
+    add edx,ecx
+    shr edx,1
+%%fin2
+    mov %1,dx
+%endmacro
+
+%macro Interp3 2
+    mov        ecx, _LUT16to32
+    movd       mm1, [ecx+eax*4]
+    mov        edx, %2
+    movd       mm2, [ecx+edx*4]
+    punpcklbw  mm1, [reg_blank]
+    punpcklbw  mm2, [reg_blank]
+    pmullw     mm1, [const7]
+    paddw      mm1, mm2
+    psrlw      mm1, 5
+    packuswb   mm1, [reg_blank]
+    movd       edx, mm1
+    shl        dl,  2
+    shr        edx, 1
+    shl        dx,  3
+    shr        edx, 5
+    mov        %1,  dx
+%endmacro
+
+%macro Interp4 3
+    mov        ecx, _LUT16to32
+    movd       mm1, [ecx+eax*4]
+    mov        edx, %2
+    movd       mm2, [ecx+edx*4]
+    mov        edx, %3
+    movd       mm3, [ecx+edx*4]
+    punpcklbw  mm1, [reg_blank]
+    punpcklbw  mm2, [reg_blank]
+    punpcklbw  mm3, [reg_blank]
+    psllw      mm1, 1
+    paddw      mm2, mm3
+    pmullw     mm2, [const7]
+    paddw      mm1, mm2
+    psrlw      mm1, 6
+    packuswb   mm1, [reg_blank]
+    movd       edx, mm1
+    shl        dl,  2
+    shr        edx, 1
+    shl        dx,  3
+    shr        edx, 5
+    mov        %1,  dx
+%endmacro
+
+%macro Interp5 3
+    mov edx,%2
+    mov ecx,%3
+    cmp edx,ecx
+    je  %%fin
+    and edx,[zerolowbits]
+    and ecx,[zerolowbits]
+    add edx,ecx
+    shr edx,1
+%%fin
+    mov %1,dx
+%endmacro
+
+%macro PIXEL00_1M 0
+    Interp1 [edi],eax,[w1]
+%endmacro
+
+%macro PIXEL00_1U 0
+    Interp1 [edi],eax,[w2]
+%endmacro
+
+%macro PIXEL00_1L 0
+    Interp1 [edi],eax,[w4]
+%endmacro
+
+%macro PIXEL00_2 0
+    Interp2 [edi],eax,[w4],[w2]
+%endmacro
+
+%macro PIXEL00_4 0
+    Interp4 [edi],[w4],[w2]
+%endmacro
+
+%macro PIXEL00_5 0
+    Interp5 [edi],[w4],[w2]
+%endmacro
+
+%macro PIXEL00_C 0
+    mov [edi],ax
+%endmacro
+
+%macro PIXEL01_1 0
+    Interp1 [edi+2],eax,[w2]
+%endmacro
+
+%macro PIXEL01_3 0
+    Interp3 [edi+2],[w2]
+%endmacro
+
+%macro PIXEL01_6 0
+    Interp1 [edi+2],[w2],eax
+%endmacro
+
+%macro PIXEL01_C 0
+    mov [edi+2],ax
+%endmacro
+
+%macro PIXEL02_1M 0
+    Interp1 [edi+4],eax,[w3]
+%endmacro
+
+%macro PIXEL02_1U 0
+    Interp1 [edi+4],eax,[w2]
+%endmacro
+
+%macro PIXEL02_1R 0
+    Interp1 [edi+4],eax,[w6]
+%endmacro
+
+%macro PIXEL02_2 0
+    Interp2 [edi+4],eax,[w2],[w6]
+%endmacro
+
+%macro PIXEL02_4 0
+    Interp4 [edi+4],[w2],[w6]
+%endmacro
+
+%macro PIXEL02_5 0
+    Interp5 [edi+4],[w2],[w6]
+%endmacro
+
+%macro PIXEL02_C 0
+    mov [edi+4],ax
+%endmacro
+
+%macro PIXEL10_1 0
+    Interp1 [edi+ebx],eax,[w4]
+%endmacro
+
+%macro PIXEL10_3 0
+    Interp3 [edi+ebx],[w4]
+%endmacro
+
+%macro PIXEL10_6 0
+    Interp1 [edi+ebx],[w4],eax
+%endmacro
+
+%macro PIXEL10_C 0
+    mov [edi+ebx],ax
+%endmacro
+
+%macro PIXEL11 0
+    mov [edi+ebx+2],ax
+%endmacro
+
+%macro PIXEL12_1 0
+    Interp1 [edi+ebx+4],eax,[w6]
+%endmacro
+
+%macro PIXEL12_3 0
+    Interp3 [edi+ebx+4],[w6]
+%endmacro
+
+%macro PIXEL12_6 0
+    Interp1 [edi+ebx+4],[w6],eax
+%endmacro
+
+%macro PIXEL12_C 0
+    mov [edi+ebx+4],ax
+%endmacro
+
+%macro PIXEL20_1M 0
+    Interp1 [edi+ebx*2],eax,[w7]
+%endmacro
+
+%macro PIXEL20_1D 0
+    Interp1 [edi+ebx*2],eax,[w8]
+%endmacro
+
+%macro PIXEL20_1L 0
+    Interp1 [edi+ebx*2],eax,[w4]
+%endmacro
+
+%macro PIXEL20_2 0
+    Interp2 [edi+ebx*2],eax,[w8],[w4]
+%endmacro
+
+%macro PIXEL20_4 0
+    Interp4 [edi+ebx*2],[w8],[w4]
+%endmacro
+
+%macro PIXEL20_5 0
+    Interp5 [edi+ebx*2],[w8],[w4]
+%endmacro
+
+%macro PIXEL20_C 0
+    mov [edi+ebx*2],ax
+%endmacro
+
+%macro PIXEL21_1 0
+    Interp1 [edi+ebx*2+2],eax,[w8]
+%endmacro
+
+%macro PIXEL21_3 0
+    Interp3 [edi+ebx*2+2],[w8]
+%endmacro
+
+%macro PIXEL21_6 0
+    Interp1 [edi+ebx*2+2],[w8],eax
+%endmacro
+
+%macro PIXEL21_C 0
+    mov [edi+ebx*2+2],ax
+%endmacro
+
+%macro PIXEL22_1M 0
+    Interp1 [edi+ebx*2+4],eax,[w9]
+%endmacro
+
+%macro PIXEL22_1D 0
+    Interp1 [edi+ebx*2+4],eax,[w8]
+%endmacro
+
+%macro PIXEL22_1R 0
+    Interp1 [edi+ebx*2+4],eax,[w6]
+%endmacro
+
+%macro PIXEL22_2 0
+    Interp2 [edi+ebx*2+4],eax,[w6],[w8]
+%endmacro
+
+%macro PIXEL22_4 0
+    Interp4 [edi+ebx*2+4],[w6],[w8]
+%endmacro
+
+%macro PIXEL22_5 0
+    Interp5 [edi+ebx*2+4],[w6],[w8]
+%endmacro
+
+%macro PIXEL22_C 0
+    mov [edi+ebx*2+4],ax
+%endmacro
+
+inbuffer     equ 8
+outbuffer    equ 12
+Xres         equ 16
+Yres         equ 20
+srcpitch     equ 24
+dstpitch     equ 28
+
+_hq3x_16:
+    push ebp
+    mov ebp,esp
+    pushad
+
+    mov esi,[ebp+inbuffer]
+    mov edi,[ebp+outbuffer]
+    mov edx,[ebp+Yres]
+    mov [linesleft],edx
+    mov dword[firstline],1
+.loopy
+    mov ebx,[ebp+Xres]
+    shl ebx,1
+    movzx eax,word[esi]
+    mov [w5],eax
+    mov [w6],eax
+    mov edx,eax
+    xor ecx,ecx
+    cmp dword[firstline],1
+    je  .firstline
+    sub ecx,ebx
+    movzx eax,word[esi+ecx]
+.firstline
+    mov [prevline],ecx
+    mov [w2],eax
+    mov [w3],eax
+    xor ecx,ecx
+    cmp dword[linesleft],1
+    je  .lastline
+    add ecx,ebx
+    movzx edx,word[esi+ecx]
+.lastline
+    mov [nextline],ecx
+    mov [w8],edx
+    mov [w9],edx
+    mov ecx,[ebp+Xres]
+    mov dword[xcounter],ecx
+.loopx
+    mov eax,[w2]
+    mov ebx,[w5]
+    mov edx,[w8]
+    mov [w1],eax
+    mov [w4],ebx
+    mov [w7],edx
+    mov eax,[w3]
+    mov ebx,[w6]
+    mov edx,[w9]
+    mov [w2],eax
+    mov [w5],ebx
+    mov [w8],edx
+    cmp dword[xcounter],1
+    je .flags
+    movzx eax,word[esi+2]
+    mov [w6],eax
+    mov ebx,[prevline]
+    movzx edx,word[esi+ebx+2]
+    mov [w3],edx
+    mov ebx,[nextline]
+    movzx eax,word[esi+ebx+2]
+    mov [w9],eax
+.flags
+    mov     ebx,_RGBtoYUV
+    mov     eax,[w5]
+    xor     ecx,ecx
+    movd    mm5,[ebx+eax*4]
+    mov     dword[cross],0
+
+    mov     edx,[w2]
+    cmp     eax,edx
+    je      .noflag2
+    or      dword[cross],1
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag2
+    or      ecx,2
+.noflag2
+    mov     edx,[w4]
+    cmp     eax,edx
+    je      .noflag4
+    or      dword[cross],2
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag4
+    or      ecx,8
+.noflag4
+    mov     edx,[w6]
+    cmp     eax,edx
+    je      .noflag6
+    or      dword[cross],4
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag6
+    or      ecx,16
+.noflag6
+    mov     edx,[w8]
+    cmp     eax,edx
+    je      .noflag8
+    or      dword[cross],8
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag8
+    or      ecx,64
+.noflag8
+    test    ecx,ecx
+    jnz     .testflag1
+    mov     ecx,[cross]
+    mov     ebx,[ebp+dstpitch]
+    jmp     [FuncTable2+ecx*4]
+.testflag1
+    mov     edx,[w1]
+    cmp     eax,edx
+    je      .noflag1
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag1
+    or      ecx,1
+.noflag1
+    mov     edx,[w3]
+    cmp     eax,edx
+    je      .noflag3
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag3
+    or      ecx,4
+.noflag3
+    mov     edx,[w7]
+    cmp     eax,edx
+    je      .noflag7
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag7
+    or      ecx,32
+.noflag7
+    mov     edx,[w9]
+    cmp     eax,edx
+    je      .noflag9
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag9
+    or      ecx,128
+.noflag9
+    mov ebx,[ebp+dstpitch]
+    jmp [FuncTable+ecx*4]
+
+..@flag0
+..@flag1
+..@flag4
+..@flag32
+..@flag128
+..@flag5
+..@flag132
+..@flag160
+..@flag33
+..@flag129
+..@flag36
+..@flag133
+..@flag164
+..@flag161
+..@flag37
+..@flag165
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag2
+..@flag34
+..@flag130
+..@flag162
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag16
+..@flag17
+..@flag48
+..@flag49
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag64
+..@flag65
+..@flag68
+..@flag69
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag8
+..@flag12
+..@flag136
+..@flag140
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag3
+..@flag35
+..@flag131
+..@flag163
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag6
+..@flag38
+..@flag134
+..@flag166
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag20
+..@flag21
+..@flag52
+..@flag53
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag144
+..@flag145
+..@flag176
+..@flag177
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag192
+..@flag193
+..@flag196
+..@flag197
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag96
+..@flag97
+..@flag100
+..@flag101
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag40
+..@flag44
+..@flag168
+..@flag172
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag9
+..@flag13
+..@flag137
+..@flag141
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag18
+..@flag50
+    PIXEL00_1M
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_1M,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag80
+..@flag81
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_1M
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_1M,PIXEL12_3,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag72
+..@flag76
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_1M,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag10
+..@flag138
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag66
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag24
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag7
+..@flag39
+..@flag135
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag148
+..@flag149
+..@flag180
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag224
+..@flag228
+..@flag225
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag41
+..@flag169
+..@flag45
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag22
+..@flag54
+    PIXEL00_1M
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag208
+..@flag209
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_1M
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag104
+..@flag108
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag11
+..@flag139
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag19
+..@flag51
+    DiffOrNot w2,w6,PIXEL00_1L,PIXEL01_C,PIXEL02_1M,PIXEL12_C,PIXEL00_2,PIXEL01_6,PIXEL02_5,PIXEL12_1
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag146
+..@flag178
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_1M,PIXEL12_C,PIXEL22_1D,PIXEL01_1,PIXEL02_5,PIXEL12_6,PIXEL22_2
+    PIXEL00_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_2
+    PIXEL21_1
+    jmp .loopx_end
+..@flag84
+..@flag85
+    DiffOrNot w6,w8,PIXEL02_1U,PIXEL12_C,PIXEL21_C,PIXEL22_1M,PIXEL02_2,PIXEL12_6,PIXEL21_1,PIXEL22_5
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_1M
+    jmp .loopx_end
+..@flag112
+..@flag113
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL20_1L,PIXEL21_C,PIXEL22_1M,PIXEL12_1,PIXEL20_2,PIXEL21_6,PIXEL22_5
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    jmp .loopx_end
+..@flag200
+..@flag204
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_1M,PIXEL21_C,PIXEL22_1R,PIXEL10_1,PIXEL20_5,PIXEL21_6,PIXEL22_2
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL11
+    PIXEL12_1
+    jmp .loopx_end
+..@flag73
+..@flag77
+    DiffOrNot w8,w4,PIXEL00_1U,PIXEL10_C,PIXEL20_1M,PIXEL21_C,PIXEL00_2,PIXEL10_6,PIXEL20_5,PIXEL21_1
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL11
+    PIXEL12_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag42
+..@flag170
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL01_C,PIXEL10_C,PIXEL20_1D,PIXEL00_5,PIXEL01_1,PIXEL10_6,PIXEL20_2
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_1
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag14
+..@flag142
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL01_C,PIXEL02_1R,PIXEL10_C,PIXEL00_5,PIXEL01_6,PIXEL02_2,PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag67
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag70
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag28
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag152
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag194
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag98
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag56
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag25
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag26
+..@flag31
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL10_C,PIXEL00_4,PIXEL10_3
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_C,PIXEL12_C,PIXEL02_4,PIXEL12_3
+    PIXEL11
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag82
+..@flag214
+    PIXEL00_1M
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL01_3,PIXEL02_4
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    DiffOrNot w6,w8,PIXEL21_C,PIXEL22_C,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag88
+..@flag248
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL11
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL10_3,PIXEL20_4
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL22_C,PIXEL12_3,PIXEL22_4
+    jmp .loopx_end
+..@flag74
+..@flag107
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL00_4,PIXEL01_3
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL20_C,PIXEL21_C,PIXEL20_4,PIXEL21_3
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag27
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag86
+    PIXEL00_1M
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag216
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL20_1M
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag106
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag30
+    PIXEL00_1M
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3
+    PIXEL10_C
+    PIXEL11
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag210
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_1M
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag120
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag75
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag29
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag198
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag184
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag99
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag57
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag71
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag156
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag226
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag60
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag195
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag102
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag153
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag58
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag83
+    PIXEL00_1L
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag92
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag202
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag78
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag154
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag114
+    PIXEL00_1M
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1L
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag89
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag90
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag55
+..@flag23
+    DiffOrNot w2,w6,PIXEL00_1L,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL00_2,PIXEL01_6,PIXEL02_5,PIXEL12_1
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag182
+..@flag150
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL22_1D,PIXEL01_1,PIXEL02_5,PIXEL12_6,PIXEL22_2
+    PIXEL00_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_2
+    PIXEL21_1
+    jmp .loopx_end
+..@flag213
+..@flag212
+    DiffOrNot w6,w8,PIXEL02_1U,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL02_2,PIXEL12_6,PIXEL21_1,PIXEL22_5
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_1M
+    jmp .loopx_end
+..@flag241
+..@flag240
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL20_1L,PIXEL21_C,PIXEL22_C,PIXEL12_1,PIXEL20_2,PIXEL21_6,PIXEL22_5
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    jmp .loopx_end
+..@flag236
+..@flag232
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL22_1R,PIXEL10_1,PIXEL20_5,PIXEL21_6,PIXEL22_2
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL11
+    PIXEL12_1
+    jmp .loopx_end
+..@flag109
+..@flag105
+    DiffOrNot w8,w4,PIXEL00_1U,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL00_2,PIXEL10_6,PIXEL20_5,PIXEL21_1
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL11
+    PIXEL12_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag171
+..@flag43
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL20_1D,PIXEL00_5,PIXEL01_1,PIXEL10_6,PIXEL20_2
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_1
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag143
+..@flag15
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL02_1R,PIXEL10_C,PIXEL00_5,PIXEL01_6,PIXEL02_2,PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag124
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag203
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag62
+    PIXEL00_1M
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3
+    PIXEL10_C
+    PIXEL11
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag211
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_1M
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag118
+    PIXEL00_1M
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag217
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL20_1M
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag110
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag155
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag188
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag185
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag61
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag157
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag103
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag227
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag230
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag199
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag220
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_C
+    PIXEL11
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag158
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3
+    PIXEL10_C
+    PIXEL11
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag234
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag242
+    PIXEL00_1M
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_1L
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag59
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag121
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag87
+    PIXEL00_1L
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_1M
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag79
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3
+    PIXEL02_1R
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag122
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag94
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3
+    PIXEL10_C
+    PIXEL11
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag218
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag91
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag229
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag167
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag173
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag181
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag186
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag115
+    PIXEL00_1L
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1L
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag93
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag206
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag205
+..@flag201
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag174
+..@flag46
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag179
+..@flag147
+    PIXEL00_1L
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag117
+..@flag116
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1L
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag189
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag231
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag126
+    PIXEL00_1M
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3
+    PIXEL11
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag219
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3
+    PIXEL02_1M
+    PIXEL11
+    PIXEL20_1M
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag125
+    DiffOrNot w8,w4,PIXEL00_1U,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL00_2,PIXEL10_6,PIXEL20_5,PIXEL21_1
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL11
+    PIXEL12_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag221
+    DiffOrNot w6,w8,PIXEL02_1U,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL02_2,PIXEL12_6,PIXEL21_1,PIXEL22_5
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL10_C
+    PIXEL11
+    PIXEL20_1M
+    jmp .loopx_end
+..@flag207
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL02_1R,PIXEL10_C,PIXEL00_5,PIXEL01_6,PIXEL02_2,PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag238
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL22_1R,PIXEL10_1,PIXEL20_5,PIXEL21_6,PIXEL22_2
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL11
+    PIXEL12_1
+    jmp .loopx_end
+..@flag190
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL22_1D,PIXEL01_1,PIXEL02_5,PIXEL12_6,PIXEL22_2
+    PIXEL00_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL20_1D
+    PIXEL21_1
+    jmp .loopx_end
+..@flag187
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL20_1D,PIXEL00_5,PIXEL01_1,PIXEL10_6,PIXEL20_2
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_C
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag243
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL20_1L,PIXEL21_C,PIXEL22_C,PIXEL12_1,PIXEL20_2,PIXEL21_6,PIXEL22_5
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    jmp .loopx_end
+..@flag119
+    DiffOrNot w2,w6,PIXEL00_1L,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL00_2,PIXEL01_6,PIXEL02_5,PIXEL12_1
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag237
+..@flag233
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL20_C,PIXEL20_2
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag175
+..@flag47
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL00_2
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag183
+..@flag151
+    PIXEL00_1L
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_C,PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag245
+..@flag244
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1L
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_C,PIXEL22_2
+    jmp .loopx_end
+..@flag250
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL11
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL10_3,PIXEL20_4
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL22_C,PIXEL12_3,PIXEL22_4
+    jmp .loopx_end
+..@flag123
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL00_4,PIXEL01_3
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL20_C,PIXEL21_C,PIXEL20_4,PIXEL21_3
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag95
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL10_C,PIXEL00_4,PIXEL10_3
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_C,PIXEL12_C,PIXEL02_4,PIXEL12_3
+    PIXEL11
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag222
+    PIXEL00_1M
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL01_3,PIXEL02_4
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    DiffOrNot w6,w8,PIXEL21_C,PIXEL22_C,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag252
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL10_3,PIXEL20_4
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_C,PIXEL22_2
+    jmp .loopx_end
+..@flag249
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    DiffOrNot w8,w4,PIXEL20_C,PIXEL20_2
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL22_C,PIXEL12_3,PIXEL22_4
+    jmp .loopx_end
+..@flag235
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL00_4,PIXEL01_3
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL20_C,PIXEL20_2
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag111
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL00_2
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL20_C,PIXEL21_C,PIXEL20_4,PIXEL21_3
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag63
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL00_2
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_C,PIXEL12_C,PIXEL02_4,PIXEL12_3
+    PIXEL10_C
+    PIXEL11
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag159
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL10_C,PIXEL00_4,PIXEL10_3
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_C,PIXEL02_2
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag215
+    PIXEL00_1L
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_C,PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    DiffOrNot w6,w8,PIXEL21_C,PIXEL22_C,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag246
+    PIXEL00_1M
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL01_3,PIXEL02_4
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1L
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_C,PIXEL22_2
+    jmp .loopx_end
+..@flag254
+    PIXEL00_1M
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL01_3,PIXEL02_4
+    PIXEL11
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL10_3,PIXEL20_4
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_2
+    jmp .loopx_end
+..@flag253
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL20_C,PIXEL20_2
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_C,PIXEL22_2
+    jmp .loopx_end
+..@flag251
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL00_4,PIXEL01_3
+    PIXEL02_1M
+    PIXEL11
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_2,PIXEL21_3
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL22_C,PIXEL12_3,PIXEL22_4
+    jmp .loopx_end
+..@flag239
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL00_2
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL20_C,PIXEL20_2
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag127
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_2,PIXEL01_3,PIXEL10_3
+    DiffOrNot w2,w6,PIXEL02_C,PIXEL12_C,PIXEL02_4,PIXEL12_3
+    PIXEL11
+    DiffOrNot w8,w4,PIXEL20_C,PIXEL21_C,PIXEL20_4,PIXEL21_3
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag191
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL00_2
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_C,PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag223
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL10_C,PIXEL00_4,PIXEL10_3
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_2,PIXEL12_3
+    PIXEL11
+    PIXEL20_1M
+    DiffOrNot w6,w8,PIXEL21_C,PIXEL22_C,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag247
+    PIXEL00_1L
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_C,PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1L
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_C,PIXEL22_2
+    jmp .loopx_end
+..@flag255
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL00_2
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_C,PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL20_C,PIXEL20_2
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_C,PIXEL22_2
+    jmp .loopx_end
+
+..@cross0
+    mov edx,eax
+    shl eax,16
+    or  eax,edx
+    mov [edi],eax
+    mov [edi+4],ax
+    mov [edi+ebx],eax
+    mov [edi+ebx+4],ax
+    mov [edi+ebx*2],eax
+    mov [edi+ebx*2+4],ax
+    jmp .loopx_end
+..@cross1
+    mov edx,eax
+    shl eax,16
+    or  eax,edx
+    mov ecx,[w2]
+    and edx,[zerolowbits]
+    and ecx,[zerolowbits]
+    add ecx,edx
+    shr ecx,1
+    add ecx,0x0821
+    and ecx,[zerolowbits]
+    add edx,ecx
+    shr edx,1
+    mov [edi],dx
+    mov [edi+2],dx
+    mov [edi+4],dx
+    mov [edi+ebx],eax
+    mov [edi+ebx+4],ax
+    mov [edi+ebx*2],eax
+    mov [edi+ebx*2+4],ax
+    jmp .loopx_end
+..@cross2
+    mov edx,eax
+    shl eax,16
+    or  eax,edx
+    mov ecx,[w4]
+    and edx,[zerolowbits]
+    and ecx,[zerolowbits]
+    add ecx,edx
+    shr ecx,1
+    add ecx,0x0821
+    and ecx,[zerolowbits]
+    add edx,ecx
+    shr edx,1
+    mov [edi],dx
+    mov [edi+2],eax
+    mov [edi+ebx],dx
+    mov [edi+ebx+2],eax
+    mov [edi+ebx*2],dx
+    mov [edi+ebx*2+2],eax
+    jmp .loopx_end
+..@cross4
+    mov edx,eax
+    shl eax,16
+    or  eax,edx
+    mov ecx,[w6]
+    and edx,[zerolowbits]
+    and ecx,[zerolowbits]
+    add ecx,edx
+    shr ecx,1
+    add ecx,0x0821
+    and ecx,[zerolowbits]
+    add edx,ecx
+    shr edx,1
+    mov [edi],eax
+    mov [edi+4],dx
+    mov [edi+ebx],eax
+    mov [edi+ebx+4],dx
+    mov [edi+ebx*2],eax
+    mov [edi+ebx*2+4],dx
+    jmp .loopx_end
+..@cross8
+    mov edx,eax
+    shl eax,16
+    or  eax,edx
+    mov ecx,[w8]
+    and edx,[zerolowbits]
+    and ecx,[zerolowbits]
+    add ecx,edx
+    shr ecx,1
+    add ecx,0x0821
+    and ecx,[zerolowbits]
+    add edx,ecx
+    shr edx,1
+    mov [edi],eax
+    mov [edi+4],ax
+    mov [edi+ebx],eax
+    mov [edi+ebx+4],ax
+    mov [edi+ebx*2],dx
+    mov [edi+ebx*2+2],dx
+    mov [edi+ebx*2+4],dx
+    jmp .loopx_end
+
+.loopx_end
+    add esi,2
+    add edi,6
+    dec dword[xcounter]
+    jz  .nexty
+    jmp .loopx
+.nexty
+    mov dword[firstline],0
+    add edi,ebx
+    add edi,ebx
+    add esi,[ebp+srcpitch]
+    dec dword[linesleft]
+    jz  .fin
+    jmp .loopy
+.fin
+    emms
+    popad
+    mov esp,ebp
+    pop ebp
+    ret
+
+SECTION .data
+FuncTable
+    dd ..@flag0, ..@flag1, ..@flag2, ..@flag3, ..@flag4, ..@flag5, ..@flag6, ..@flag7
+    dd ..@flag8, ..@flag9, ..@flag10, ..@flag11, ..@flag12, ..@flag13, ..@flag14, ..@flag15
+    dd ..@flag16, ..@flag17, ..@flag18, ..@flag19, ..@flag20, ..@flag21, ..@flag22, ..@flag23
+    dd ..@flag24, ..@flag25, ..@flag26, ..@flag27, ..@flag28, ..@flag29, ..@flag30, ..@flag31
+    dd ..@flag32, ..@flag33, ..@flag34, ..@flag35, ..@flag36, ..@flag37, ..@flag38, ..@flag39
+    dd ..@flag40, ..@flag41, ..@flag42, ..@flag43, ..@flag44, ..@flag45, ..@flag46, ..@flag47
+    dd ..@flag48, ..@flag49, ..@flag50, ..@flag51, ..@flag52, ..@flag53, ..@flag54, ..@flag55
+    dd ..@flag56, ..@flag57, ..@flag58, ..@flag59, ..@flag60, ..@flag61, ..@flag62, ..@flag63
+    dd ..@flag64, ..@flag65, ..@flag66, ..@flag67, ..@flag68, ..@flag69, ..@flag70, ..@flag71
+    dd ..@flag72, ..@flag73, ..@flag74, ..@flag75, ..@flag76, ..@flag77, ..@flag78, ..@flag79
+    dd ..@flag80, ..@flag81, ..@flag82, ..@flag83, ..@flag84, ..@flag85, ..@flag86, ..@flag87
+    dd ..@flag88, ..@flag89, ..@flag90, ..@flag91, ..@flag92, ..@flag93, ..@flag94, ..@flag95
+    dd ..@flag96, ..@flag97, ..@flag98, ..@flag99, ..@flag100, ..@flag101, ..@flag102, ..@flag103
+    dd ..@flag104, ..@flag105, ..@flag106, ..@flag107, ..@flag108, ..@flag109, ..@flag110, ..@flag111
+    dd ..@flag112, ..@flag113, ..@flag114, ..@flag115, ..@flag116, ..@flag117, ..@flag118, ..@flag119
+    dd ..@flag120, ..@flag121, ..@flag122, ..@flag123, ..@flag124, ..@flag125, ..@flag126, ..@flag127
+    dd ..@flag128, ..@flag129, ..@flag130, ..@flag131, ..@flag132, ..@flag133, ..@flag134, ..@flag135
+    dd ..@flag136, ..@flag137, ..@flag138, ..@flag139, ..@flag140, ..@flag141, ..@flag142, ..@flag143
+    dd ..@flag144, ..@flag145, ..@flag146, ..@flag147, ..@flag148, ..@flag149, ..@flag150, ..@flag151
+    dd ..@flag152, ..@flag153, ..@flag154, ..@flag155, ..@flag156, ..@flag157, ..@flag158, ..@flag159
+    dd ..@flag160, ..@flag161, ..@flag162, ..@flag163, ..@flag164, ..@flag165, ..@flag166, ..@flag167
+    dd ..@flag168, ..@flag169, ..@flag170, ..@flag171, ..@flag172, ..@flag173, ..@flag174, ..@flag175
+    dd ..@flag176, ..@flag177, ..@flag178, ..@flag179, ..@flag180, ..@flag181, ..@flag182, ..@flag183
+    dd ..@flag184, ..@flag185, ..@flag186, ..@flag187, ..@flag188, ..@flag189, ..@flag190, ..@flag191
+    dd ..@flag192, ..@flag193, ..@flag194, ..@flag195, ..@flag196, ..@flag197, ..@flag198, ..@flag199
+    dd ..@flag200, ..@flag201, ..@flag202, ..@flag203, ..@flag204, ..@flag205, ..@flag206, ..@flag207
+    dd ..@flag208, ..@flag209, ..@flag210, ..@flag211, ..@flag212, ..@flag213, ..@flag214, ..@flag215
+    dd ..@flag216, ..@flag217, ..@flag218, ..@flag219, ..@flag220, ..@flag221, ..@flag222, ..@flag223
+    dd ..@flag224, ..@flag225, ..@flag226, ..@flag227, ..@flag228, ..@flag229, ..@flag230, ..@flag231
+    dd ..@flag232, ..@flag233, ..@flag234, ..@flag235, ..@flag236, ..@flag237, ..@flag238, ..@flag239
+    dd ..@flag240, ..@flag241, ..@flag242, ..@flag243, ..@flag244, ..@flag245, ..@flag246, ..@flag247
+    dd ..@flag248, ..@flag249, ..@flag250, ..@flag251, ..@flag252, ..@flag253, ..@flag254, ..@flag255
+
+FuncTable2
+    dd ..@cross0, ..@cross1, ..@cross2, ..@flag0,
+    dd ..@cross4, ..@flag0,  ..@flag0,  ..@flag0,
+    dd ..@cross8, ..@flag0,  ..@flag0,  ..@flag0,
+    dd ..@flag0,  ..@flag0,  ..@flag0,  ..@flag0
+
diff --git a/od-win32/hq3x32.asm b/od-win32/hq3x32.asm
new file mode 100755 (executable)
index 0000000..6c7e7c8
--- /dev/null
@@ -0,0 +1,2472 @@
+;hq3x filter
+;----------------------------------------------------------
+;Copyright (C) 2003 MaxSt ( maxst@hiend3d.com )
+;
+;This program is free software; you can redistribute it and/or
+;modify it under the terms of the GNU General Public License
+;as published by the Free Software Foundation; either
+;version 2 of the License, or (at your option) any later
+;version.
+;
+;This program is distributed in the hope that it will be useful,
+;but WITHOUT ANY WARRANTY; without even the implied warranty of
+;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;GNU General Public License for more details.
+;
+;You should have received a copy of the GNU General Public License
+;along with this program; if not, write to the Free Software
+;Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+GLOBAL _hq3x_32
+
+EXTERN _LUT16to32
+EXTERN _RGBtoYUV
+
+SECTION .bss
+firstline resd 1
+linesleft resd 1
+xcounter  resd 1
+cross     resd 1
+nextline  resd 1
+prevline  resd 1
+w1        resd 1
+w2        resd 1
+w3        resd 1
+w4        resd 1
+w5        resd 1
+w6        resd 1
+w7        resd 1
+w8        resd 1
+w9        resd 1
+c1        resd 1
+c2        resd 1
+c3        resd 1
+c4        resd 1
+c5        resd 1
+c6        resd 1
+c7        resd 1
+c8        resd 1
+c9        resd 1
+
+SECTION .data
+
+reg_blank    dd  0,0
+const7       dd  0x00070007,0x00000007
+threshold    dd  0x00300706,0x00000000
+
+SECTION .text
+
+%macro TestDiff 2
+    xor     ecx,ecx
+    mov     edx,[%1]
+    cmp     edx,[%2]
+    je      %%fin
+    mov     ecx,_RGBtoYUV
+    movd    mm1,[ecx+edx*4]
+    movq    mm5,mm1
+    mov     edx,[%2]
+    movd    mm2,[ecx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    ecx,mm1
+%%fin:
+%endmacro
+
+%macro DiffOrNot 4
+   TestDiff %1,%2
+   test ecx,ecx
+   jz   %%same
+   %3
+   jmp %%fin
+%%same:
+   %4
+%%fin
+%endmacro
+
+%macro DiffOrNot 6
+   TestDiff %1,%2
+   test ecx,ecx
+   jz   %%same
+   %3
+   %4
+   jmp %%fin
+%%same:
+   %5
+   %6
+%%fin
+%endmacro
+
+%macro DiffOrNot 8
+   TestDiff %1,%2
+   test ecx,ecx
+   jz   %%same
+   %3
+   %4
+   %5
+   jmp %%fin
+%%same:
+   %6
+   %7
+   %8
+%%fin
+%endmacro
+
+%macro DiffOrNot 10
+   TestDiff %1,%2
+   test ecx,ecx
+   jz %%same
+   %3
+   %4
+   %5
+   %6
+   jmp %%fin
+%%same:
+   %7
+   %8
+   %9
+   %10
+%%fin
+%endmacro
+
+%macro Interp1 3
+    mov edx,%2
+    shl edx,2
+    add edx,%3
+    sub edx,%2
+    shr edx,2
+    mov %1,edx
+%endmacro
+
+%macro Interp2 4
+    mov edx,%2
+    shl edx,1
+    add edx,%3
+    add edx,%4
+    shr edx,2
+    mov %1,edx
+%endmacro
+
+%macro Interp3 2
+    movd       mm1, eax
+    movd       mm2, %2
+    punpcklbw  mm1, [reg_blank]
+    punpcklbw  mm2, [reg_blank]
+    pmullw     mm1, [const7]
+    paddw      mm1, mm2
+    psrlw      mm1, 3
+    packuswb   mm1, [reg_blank]
+    movd       %1, mm1
+%endmacro
+
+%macro Interp4 3
+    movd       mm1, eax
+    movd       mm2, %2
+    movd       mm3, %3
+    punpcklbw  mm1, [reg_blank]
+    punpcklbw  mm2, [reg_blank]
+    punpcklbw  mm3, [reg_blank]
+    psllw      mm1, 1
+    paddw      mm2, mm3
+    pmullw     mm2, [const7]
+    paddw      mm1, mm2
+    psrlw      mm1, 4
+    packuswb   mm1, [reg_blank]
+    movd       %1, mm1
+%endmacro
+
+%macro Interp5 3
+    mov edx,%2
+    add edx,%3
+    shr edx,1
+    mov %1,edx
+%endmacro
+
+%macro PIXEL00_1M 0
+    Interp1 [edi],eax,[c1]
+%endmacro
+
+%macro PIXEL00_1U 0
+    Interp1 [edi],eax,[c2]
+%endmacro
+
+%macro PIXEL00_1L 0
+    Interp1 [edi],eax,[c4]
+%endmacro
+
+%macro PIXEL00_2 0
+    Interp2 [edi],eax,[c4],[c2]
+%endmacro
+
+%macro PIXEL00_4 0
+    Interp4 [edi],[c4],[c2]
+%endmacro
+
+%macro PIXEL00_5 0
+    Interp5 [edi],[c4],[c2]
+%endmacro
+
+%macro PIXEL00_C 0
+    mov [edi],eax
+%endmacro
+
+%macro PIXEL01_1 0
+    Interp1 [edi+4],eax,[c2]
+%endmacro
+
+%macro PIXEL01_3 0
+    Interp3 [edi+4],[c2]
+%endmacro
+
+%macro PIXEL01_6 0
+    Interp1 [edi+4],[c2],eax
+%endmacro
+
+%macro PIXEL01_C 0
+    mov [edi+4],eax
+%endmacro
+
+%macro PIXEL02_1M 0
+    Interp1 [edi+8],eax,[c3]
+%endmacro
+
+%macro PIXEL02_1U 0
+    Interp1 [edi+8],eax,[c2]
+%endmacro
+
+%macro PIXEL02_1R 0
+    Interp1 [edi+8],eax,[c6]
+%endmacro
+
+%macro PIXEL02_2 0
+    Interp2 [edi+8],eax,[c2],[c6]
+%endmacro
+
+%macro PIXEL02_4 0
+    Interp4 [edi+8],[c2],[c6]
+%endmacro
+
+%macro PIXEL02_5 0
+    Interp5 [edi+8],[c2],[c6]
+%endmacro
+
+%macro PIXEL02_C 0
+    mov [edi+8],eax
+%endmacro
+
+%macro PIXEL10_1 0
+    Interp1 [edi+ebx],eax,[c4]
+%endmacro
+
+%macro PIXEL10_3 0
+    Interp3 [edi+ebx],[c4]
+%endmacro
+
+%macro PIXEL10_6 0
+    Interp1 [edi+ebx],[c4],eax
+%endmacro
+
+%macro PIXEL10_C 0
+    mov [edi+ebx],eax
+%endmacro
+
+%macro PIXEL11 0
+    mov [edi+ebx+4],eax
+%endmacro
+
+%macro PIXEL12_1 0
+    Interp1 [edi+ebx+8],eax,[c6]
+%endmacro
+
+%macro PIXEL12_3 0
+    Interp3 [edi+ebx+8],[c6]
+%endmacro
+
+%macro PIXEL12_6 0
+    Interp1 [edi+ebx+8],[c6],eax
+%endmacro
+
+%macro PIXEL12_C 0
+    mov [edi+ebx+8],eax
+%endmacro
+
+%macro PIXEL20_1M 0
+    Interp1 [edi+ebx*2],eax,[c7]
+%endmacro
+
+%macro PIXEL20_1D 0
+    Interp1 [edi+ebx*2],eax,[c8]
+%endmacro
+
+%macro PIXEL20_1L 0
+    Interp1 [edi+ebx*2],eax,[c4]
+%endmacro
+
+%macro PIXEL20_2 0
+    Interp2 [edi+ebx*2],eax,[c8],[c4]
+%endmacro
+
+%macro PIXEL20_4 0
+    Interp4 [edi+ebx*2],[c8],[c4]
+%endmacro
+
+%macro PIXEL20_5 0
+    Interp5 [edi+ebx*2],[c8],[c4]
+%endmacro
+
+%macro PIXEL20_C 0
+    mov [edi+ebx*2],eax
+%endmacro
+
+%macro PIXEL21_1 0
+    Interp1 [edi+ebx*2+4],eax,[c8]
+%endmacro
+
+%macro PIXEL21_3 0
+    Interp3 [edi+ebx*2+4],[c8]
+%endmacro
+
+%macro PIXEL21_6 0
+    Interp1 [edi+ebx*2+4],[c8],eax
+%endmacro
+
+%macro PIXEL21_C 0
+    mov [edi+ebx*2+4],eax
+%endmacro
+
+%macro PIXEL22_1M 0
+    Interp1 [edi+ebx*2+8],eax,[c9]
+%endmacro
+
+%macro PIXEL22_1D 0
+    Interp1 [edi+ebx*2+8],eax,[c8]
+%endmacro
+
+%macro PIXEL22_1R 0
+    Interp1 [edi+ebx*2+8],eax,[c6]
+%endmacro
+
+%macro PIXEL22_2 0
+    Interp2 [edi+ebx*2+8],eax,[c6],[c8]
+%endmacro
+
+%macro PIXEL22_4 0
+    Interp4 [edi+ebx*2+8],[c6],[c8]
+%endmacro
+
+%macro PIXEL22_5 0
+    Interp5 [edi+ebx*2+8],[c6],[c8]
+%endmacro
+
+%macro PIXEL22_C 0
+    mov [edi+ebx*2+8],eax
+%endmacro
+
+inbuffer     equ 8
+outbuffer    equ 12
+Xres         equ 16
+Yres         equ 20
+dstpitch     equ 24
+srcpitch     equ 28
+dstpitch2    equ 32
+
+_hq3x_32:
+    push ebp
+    mov ebp,esp
+    pushad
+
+    mov esi,[ebp+inbuffer]
+    mov edi,[ebp+outbuffer]
+    mov edx,[ebp+Yres]
+    mov [linesleft],edx
+    mov dword[firstline],1
+.loopy
+    mov ebx,[ebp+Xres]
+    shl ebx,1
+    movzx eax,word[esi]
+    mov [w5],eax
+    mov [w6],eax
+    mov edx,eax
+    xor ecx,ecx
+    cmp dword[firstline],1
+    je  .firstline
+    sub ecx,ebx
+    movzx eax,word[esi+ecx]
+.firstline
+    mov [prevline],ecx
+    mov [w2],eax
+    mov [w3],eax
+    xor ecx,ecx
+    cmp dword[linesleft],1
+    je  .lastline
+    add ecx,ebx
+    movzx edx,word[esi+ecx]
+.lastline
+    mov [nextline],ecx
+    mov [w8],edx
+    mov [w9],edx
+    mov ecx,[ebp+Xres]
+    mov dword[xcounter],ecx
+.loopx
+    mov eax,[w2]
+    mov ebx,[w5]
+    mov edx,[w8]
+    mov [w1],eax
+    mov [w4],ebx
+    mov [w7],edx
+    mov eax,[w3]
+    mov ebx,[w6]
+    mov edx,[w9]
+    mov [w2],eax
+    mov [w5],ebx
+    mov [w8],edx
+    cmp dword[xcounter],1
+    je .flags
+    movzx eax,word[esi+2]
+    mov [w6],eax
+    mov ebx,[prevline]
+    movzx edx,word[esi+ebx+2]
+    mov [w3],edx
+    mov ebx,[nextline]
+    movzx eax,word[esi+ebx+2]
+    mov [w9],eax
+.flags
+    mov     ebx,_RGBtoYUV
+    mov     eax,[w5]
+    xor     ecx,ecx
+    movd    mm5,[ebx+eax*4]
+    mov     dword[cross],0
+
+    mov     edx,[w2]
+    cmp     eax,edx
+    je      .noflag2
+    or      dword[cross],1
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag2
+    or      ecx,2
+.noflag2
+    mov     edx,[w4]
+    cmp     eax,edx
+    je      .noflag4
+    or      dword[cross],2
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag4
+    or      ecx,8
+.noflag4
+    mov     edx,[w6]
+    cmp     eax,edx
+    je      .noflag6
+    or      dword[cross],4
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag6
+    or      ecx,16
+.noflag6
+    mov     edx,[w8]
+    cmp     eax,edx
+    je      .noflag8
+    or      dword[cross],8
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag8
+    or      ecx,64
+.noflag8
+    test    ecx,ecx
+    jnz     .testflag1
+    mov     ecx,[cross]
+    mov     ebx,_LUT16to32
+    mov     eax,[ebx+eax*4]
+    jmp     [FuncTable2+ecx*4]
+.testflag1
+    mov     edx,[w1]
+    cmp     eax,edx
+    je      .noflag1
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag1
+    or      ecx,1
+.noflag1
+    mov     edx,[w3]
+    cmp     eax,edx
+    je      .noflag3
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag3
+    or      ecx,4
+.noflag3
+    mov     edx,[w7]
+    cmp     eax,edx
+    je      .noflag7
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag7
+    or      ecx,32
+.noflag7
+    mov     edx,[w9]
+    cmp     eax,edx
+    je      .noflag9
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag9
+    or      ecx,128
+.noflag9
+    mov ebx,_LUT16to32
+    mov eax,[ebx+eax*4]
+    mov edx,[w2]
+    mov edx,[ebx+edx*4]
+    mov [c2],edx
+    mov edx,[w4]
+    mov edx,[ebx+edx*4]
+    mov [c4],edx
+    mov edx,[w6]
+    mov edx,[ebx+edx*4]
+    mov [c6],edx
+    mov edx,[w8]
+    mov edx,[ebx+edx*4]
+    mov [c8],edx
+    test ecx,0x005A
+    jz  .switch
+    mov edx,[w1]
+    mov edx,[ebx+edx*4]
+    mov [c1],edx
+    mov edx,[w3]
+    mov edx,[ebx+edx*4]
+    mov [c3],edx
+    mov edx,[w7]
+    mov edx,[ebx+edx*4]
+    mov [c7],edx
+    mov edx,[w9]
+    mov edx,[ebx+edx*4]
+    mov [c9],edx
+.switch
+    mov ebx,[ebp+dstpitch]
+    jmp [FuncTable+ecx*4]
+
+..@flag0
+..@flag1
+..@flag4
+..@flag32
+..@flag128
+..@flag5
+..@flag132
+..@flag160
+..@flag33
+..@flag129
+..@flag36
+..@flag133
+..@flag164
+..@flag161
+..@flag37
+..@flag165
+;    PIXEL00_2
+;    PIXEL01_1
+;    PIXEL02_2
+;    PIXEL10_1
+;    PIXEL11
+;    PIXEL12_1
+;    PIXEL20_2
+;    PIXEL21_1
+;    PIXEL22_2
+
+;   the same, only optimized
+    mov ecx,eax
+    shl ecx,1
+    add ecx,[c2]
+    mov edx,ecx
+    add edx,[c4]
+    shr edx,2
+    mov [edi],edx
+    mov edx,ecx
+    add edx,eax
+    shr edx,2
+    mov [edi+4],edx
+    add ecx,[c6]
+    shr ecx,2
+    mov [edi+8],ecx
+    mov ecx,eax
+    shl ecx,2
+    sub ecx,eax
+    mov edx,ecx
+    add edx,[c4]
+    shr edx,2
+    mov [edi+ebx],edx
+    mov [edi+ebx+4],eax
+    add ecx,[c6]
+    shr ecx,2
+    mov [edi+ebx+8],ecx
+    mov ecx,eax
+    shl ecx,1
+    add ecx,[c8]
+    mov edx,ecx
+    add edx,[c4]
+    shr edx,2
+    mov [edi+ebx*2],edx
+    mov edx,ecx
+    add edx,eax
+    shr edx,2
+    mov [edi+ebx*2+4],edx
+    add ecx,[c6]
+    shr ecx,2
+    mov [edi+ebx*2+8],ecx
+    jmp .loopx_end
+..@flag2
+..@flag34
+..@flag130
+..@flag162
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag16
+..@flag17
+..@flag48
+..@flag49
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag64
+..@flag65
+..@flag68
+..@flag69
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag8
+..@flag12
+..@flag136
+..@flag140
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag3
+..@flag35
+..@flag131
+..@flag163
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag6
+..@flag38
+..@flag134
+..@flag166
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag20
+..@flag21
+..@flag52
+..@flag53
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag144
+..@flag145
+..@flag176
+..@flag177
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag192
+..@flag193
+..@flag196
+..@flag197
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag96
+..@flag97
+..@flag100
+..@flag101
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag40
+..@flag44
+..@flag168
+..@flag172
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag9
+..@flag13
+..@flag137
+..@flag141
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag18
+..@flag50
+    PIXEL00_1M
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_1M,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag80
+..@flag81
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_1M
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_1M,PIXEL12_3,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag72
+..@flag76
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_1M,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag10
+..@flag138
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag66
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag24
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag7
+..@flag39
+..@flag135
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag148
+..@flag149
+..@flag180
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag224
+..@flag228
+..@flag225
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag41
+..@flag169
+..@flag45
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag22
+..@flag54
+    PIXEL00_1M
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag208
+..@flag209
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_1M
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag104
+..@flag108
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag11
+..@flag139
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag19
+..@flag51
+    DiffOrNot w2,w6,PIXEL00_1L,PIXEL01_C,PIXEL02_1M,PIXEL12_C,PIXEL00_2,PIXEL01_6,PIXEL02_5,PIXEL12_1
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag146
+..@flag178
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_1M,PIXEL12_C,PIXEL22_1D,PIXEL01_1,PIXEL02_5,PIXEL12_6,PIXEL22_2
+    PIXEL00_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_2
+    PIXEL21_1
+    jmp .loopx_end
+..@flag84
+..@flag85
+    DiffOrNot w6,w8,PIXEL02_1U,PIXEL12_C,PIXEL21_C,PIXEL22_1M,PIXEL02_2,PIXEL12_6,PIXEL21_1,PIXEL22_5
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_1M
+    jmp .loopx_end
+..@flag112
+..@flag113
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL20_1L,PIXEL21_C,PIXEL22_1M,PIXEL12_1,PIXEL20_2,PIXEL21_6,PIXEL22_5
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    jmp .loopx_end
+..@flag200
+..@flag204
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_1M,PIXEL21_C,PIXEL22_1R,PIXEL10_1,PIXEL20_5,PIXEL21_6,PIXEL22_2
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL11
+    PIXEL12_1
+    jmp .loopx_end
+..@flag73
+..@flag77
+    DiffOrNot w8,w4,PIXEL00_1U,PIXEL10_C,PIXEL20_1M,PIXEL21_C,PIXEL00_2,PIXEL10_6,PIXEL20_5,PIXEL21_1
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL11
+    PIXEL12_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag42
+..@flag170
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL01_C,PIXEL10_C,PIXEL20_1D,PIXEL00_5,PIXEL01_1,PIXEL10_6,PIXEL20_2
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_1
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag14
+..@flag142
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL01_C,PIXEL02_1R,PIXEL10_C,PIXEL00_5,PIXEL01_6,PIXEL02_2,PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag67
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag70
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag28
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag152
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag194
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag98
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag56
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag25
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag26
+..@flag31
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL10_C,PIXEL00_4,PIXEL10_3
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_C,PIXEL12_C,PIXEL02_4,PIXEL12_3
+    PIXEL11
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag82
+..@flag214
+    PIXEL00_1M
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL01_3,PIXEL02_4
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    DiffOrNot w6,w8,PIXEL21_C,PIXEL22_C,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag88
+..@flag248
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL11
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL10_3,PIXEL20_4
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL22_C,PIXEL12_3,PIXEL22_4
+    jmp .loopx_end
+..@flag74
+..@flag107
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL00_4,PIXEL01_3
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL20_C,PIXEL21_C,PIXEL20_4,PIXEL21_3
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag27
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag86
+    PIXEL00_1M
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag216
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL20_1M
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag106
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag30
+    PIXEL00_1M
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3
+    PIXEL10_C
+    PIXEL11
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag210
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_1M
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag120
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag75
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag29
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag198
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag184
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag99
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag57
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag71
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag156
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag226
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag60
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag195
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag102
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag153
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag58
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag83
+    PIXEL00_1L
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag92
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag202
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag78
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag154
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag114
+    PIXEL00_1M
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1L
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag89
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag90
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag55
+..@flag23
+    DiffOrNot w2,w6,PIXEL00_1L,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL00_2,PIXEL01_6,PIXEL02_5,PIXEL12_1
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag182
+..@flag150
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL22_1D,PIXEL01_1,PIXEL02_5,PIXEL12_6,PIXEL22_2
+    PIXEL00_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_2
+    PIXEL21_1
+    jmp .loopx_end
+..@flag213
+..@flag212
+    DiffOrNot w6,w8,PIXEL02_1U,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL02_2,PIXEL12_6,PIXEL21_1,PIXEL22_5
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_1M
+    jmp .loopx_end
+..@flag241
+..@flag240
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL20_1L,PIXEL21_C,PIXEL22_C,PIXEL12_1,PIXEL20_2,PIXEL21_6,PIXEL22_5
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    jmp .loopx_end
+..@flag236
+..@flag232
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL22_1R,PIXEL10_1,PIXEL20_5,PIXEL21_6,PIXEL22_2
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL11
+    PIXEL12_1
+    jmp .loopx_end
+..@flag109
+..@flag105
+    DiffOrNot w8,w4,PIXEL00_1U,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL00_2,PIXEL10_6,PIXEL20_5,PIXEL21_1
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL11
+    PIXEL12_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag171
+..@flag43
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL20_1D,PIXEL00_5,PIXEL01_1,PIXEL10_6,PIXEL20_2
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_1
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag143
+..@flag15
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL02_1R,PIXEL10_C,PIXEL00_5,PIXEL01_6,PIXEL02_2,PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag124
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag203
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag62
+    PIXEL00_1M
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3
+    PIXEL10_C
+    PIXEL11
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag211
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_1M
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag118
+    PIXEL00_1M
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag217
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL20_1M
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag110
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag155
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag188
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag185
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag61
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag157
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag103
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag227
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag230
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag199
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag220
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_C
+    PIXEL11
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag158
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3
+    PIXEL10_C
+    PIXEL11
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag234
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag242
+    PIXEL00_1M
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_1L
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag59
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag121
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag87
+    PIXEL00_1L
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_1M
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag79
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3
+    PIXEL02_1R
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag122
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag94
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3
+    PIXEL10_C
+    PIXEL11
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag218
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag91
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag229
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag167
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag173
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag181
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag186
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag115
+    PIXEL00_1L
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1L
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag93
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag206
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag205
+..@flag201
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag174
+..@flag46
+    DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag179
+..@flag147
+    PIXEL00_1L
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag117
+..@flag116
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1L
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2
+    jmp .loopx_end
+..@flag189
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag231
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag126
+    PIXEL00_1M
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3
+    PIXEL11
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag219
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3
+    PIXEL02_1M
+    PIXEL11
+    PIXEL20_1M
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag125
+    DiffOrNot w8,w4,PIXEL00_1U,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL00_2,PIXEL10_6,PIXEL20_5,PIXEL21_1
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL11
+    PIXEL12_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag221
+    DiffOrNot w6,w8,PIXEL02_1U,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL02_2,PIXEL12_6,PIXEL21_1,PIXEL22_5
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL10_C
+    PIXEL11
+    PIXEL20_1M
+    jmp .loopx_end
+..@flag207
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL02_1R,PIXEL10_C,PIXEL00_5,PIXEL01_6,PIXEL02_2,PIXEL10_1
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag238
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL22_1R,PIXEL10_1,PIXEL20_5,PIXEL21_6,PIXEL22_2
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL11
+    PIXEL12_1
+    jmp .loopx_end
+..@flag190
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL22_1D,PIXEL01_1,PIXEL02_5,PIXEL12_6,PIXEL22_2
+    PIXEL00_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL20_1D
+    PIXEL21_1
+    jmp .loopx_end
+..@flag187
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL20_1D,PIXEL00_5,PIXEL01_1,PIXEL10_6,PIXEL20_2
+    PIXEL02_1M
+    PIXEL11
+    PIXEL12_C
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag243
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL20_1L,PIXEL21_C,PIXEL22_C,PIXEL12_1,PIXEL20_2,PIXEL21_6,PIXEL22_5
+    PIXEL00_1L
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL10_1
+    PIXEL11
+    jmp .loopx_end
+..@flag119
+    DiffOrNot w2,w6,PIXEL00_1L,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL00_2,PIXEL01_6,PIXEL02_5,PIXEL12_1
+    PIXEL10_1
+    PIXEL11
+    PIXEL20_1L
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag237
+..@flag233
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL20_C,PIXEL20_2
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag175
+..@flag47
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL00_2
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_2
+    jmp .loopx_end
+..@flag183
+..@flag151
+    PIXEL00_1L
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_C,PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_2
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag245
+..@flag244
+    PIXEL00_2
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1L
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_C,PIXEL22_2
+    jmp .loopx_end
+..@flag250
+    PIXEL00_1M
+    PIXEL01_C
+    PIXEL02_1M
+    PIXEL11
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL10_3,PIXEL20_4
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL22_C,PIXEL12_3,PIXEL22_4
+    jmp .loopx_end
+..@flag123
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL00_4,PIXEL01_3
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL20_C,PIXEL21_C,PIXEL20_4,PIXEL21_3
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag95
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL10_C,PIXEL00_4,PIXEL10_3
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_C,PIXEL12_C,PIXEL02_4,PIXEL12_3
+    PIXEL11
+    PIXEL20_1M
+    PIXEL21_C
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag222
+    PIXEL00_1M
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL01_3,PIXEL02_4
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    DiffOrNot w6,w8,PIXEL21_C,PIXEL22_C,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag252
+    PIXEL00_1M
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL10_3,PIXEL20_4
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_C,PIXEL22_2
+    jmp .loopx_end
+..@flag249
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    DiffOrNot w8,w4,PIXEL20_C,PIXEL20_2
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL22_C,PIXEL12_3,PIXEL22_4
+    jmp .loopx_end
+..@flag235
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL00_4,PIXEL01_3
+    PIXEL02_1M
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL20_C,PIXEL20_2
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag111
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL00_2
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL20_C,PIXEL21_C,PIXEL20_4,PIXEL21_3
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag63
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL00_2
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_C,PIXEL12_C,PIXEL02_4,PIXEL12_3
+    PIXEL10_C
+    PIXEL11
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag159
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL10_C,PIXEL00_4,PIXEL10_3
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_C,PIXEL02_2
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag215
+    PIXEL00_1L
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_C,PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1M
+    DiffOrNot w6,w8,PIXEL21_C,PIXEL22_C,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag246
+    PIXEL00_1M
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL01_3,PIXEL02_4
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1L
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_C,PIXEL22_2
+    jmp .loopx_end
+..@flag254
+    PIXEL00_1M
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL01_3,PIXEL02_4
+    PIXEL11
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL10_3,PIXEL20_4
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_2
+    jmp .loopx_end
+..@flag253
+    PIXEL00_1U
+    PIXEL01_1
+    PIXEL02_1U
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL20_C,PIXEL20_2
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_C,PIXEL22_2
+    jmp .loopx_end
+..@flag251
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL00_4,PIXEL01_3
+    PIXEL02_1M
+    PIXEL11
+    DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_2,PIXEL21_3
+    DiffOrNot w6,w8,PIXEL12_C,PIXEL22_C,PIXEL12_3,PIXEL22_4
+    jmp .loopx_end
+..@flag239
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL00_2
+    PIXEL01_C
+    PIXEL02_1R
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_1
+    DiffOrNot w8,w4,PIXEL20_C,PIXEL20_2
+    PIXEL21_C
+    PIXEL22_1R
+    jmp .loopx_end
+..@flag127
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_2,PIXEL01_3,PIXEL10_3
+    DiffOrNot w2,w6,PIXEL02_C,PIXEL12_C,PIXEL02_4,PIXEL12_3
+    PIXEL11
+    DiffOrNot w8,w4,PIXEL20_C,PIXEL21_C,PIXEL20_4,PIXEL21_3
+    PIXEL22_1M
+    jmp .loopx_end
+..@flag191
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL00_2
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_C,PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1D
+    PIXEL21_1
+    PIXEL22_1D
+    jmp .loopx_end
+..@flag223
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL10_C,PIXEL00_4,PIXEL10_3
+    DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_2,PIXEL12_3
+    PIXEL11
+    PIXEL20_1M
+    DiffOrNot w6,w8,PIXEL21_C,PIXEL22_C,PIXEL21_3,PIXEL22_4
+    jmp .loopx_end
+..@flag247
+    PIXEL00_1L
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_C,PIXEL02_2
+    PIXEL10_1
+    PIXEL11
+    PIXEL12_C
+    PIXEL20_1L
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_C,PIXEL22_2
+    jmp .loopx_end
+..@flag255
+    DiffOrNot w4,w2,PIXEL00_C,PIXEL00_2
+    PIXEL01_C
+    DiffOrNot w2,w6,PIXEL02_C,PIXEL02_2
+    PIXEL10_C
+    PIXEL11
+    PIXEL12_C
+    DiffOrNot w8,w4,PIXEL20_C,PIXEL20_2
+    PIXEL21_C
+    DiffOrNot w6,w8,PIXEL22_C,PIXEL22_2
+    jmp .loopx_end
+
+..@cross0
+    mov     ebx,[ebp+dstpitch]
+    mov     [edi],eax
+    mov     [edi+4],eax
+    mov     [edi+8],eax
+    mov     [edi+ebx],eax
+    mov     [edi+ebx+4],eax
+    mov     [edi+ebx+8],eax
+    mov     [edi+ebx*2],eax
+    mov     [edi+ebx*2+4],eax
+    mov     [edi+ebx*2+8],eax
+    jmp     .loopx_end
+..@cross1
+    mov     ecx,[w2] 
+    mov     edx,eax
+    shl     edx,2
+    add     edx,[ebx+ecx*4]
+    sub     edx,eax
+    shr     edx,2
+    mov     ebx,[ebp+dstpitch]
+    mov     [edi],edx
+    mov     [edi+4],edx
+    mov     [edi+8],edx
+    mov     [edi+ebx],eax
+    mov     [edi+ebx+4],eax
+    mov     [edi+ebx+8],eax
+    mov     [edi+ebx*2],eax
+    mov     [edi+ebx*2+4],eax
+    mov     [edi+ebx*2+8],eax
+    jmp     .loopx_end
+..@cross2
+    mov     ecx,[w4]
+    mov     edx,eax
+    shl     edx,2
+    add     edx,[ebx+ecx*4]
+    sub     edx,eax
+    shr     edx,2
+    mov     ebx,[ebp+dstpitch]
+    mov     [edi],edx
+    mov     [edi+4],eax
+    mov     [edi+8],eax
+    mov     [edi+ebx],edx
+    mov     [edi+ebx+4],eax
+    mov     [edi+ebx+8],eax
+    mov     [edi+ebx*2],edx
+    mov     [edi+ebx*2+4],eax
+    mov     [edi+ebx*2+8],eax
+    jmp     .loopx_end
+..@cross4
+    mov     ecx,[w6]
+    mov     edx,eax
+    shl     edx,2
+    add     edx,[ebx+ecx*4]
+    sub     edx,eax
+    shr     edx,2
+    mov     ebx,[ebp+dstpitch]
+    mov     [edi],eax
+    mov     [edi+4],eax
+    mov     [edi+8],edx
+    mov     [edi+ebx],eax
+    mov     [edi+ebx+4],eax
+    mov     [edi+ebx+8],edx
+    mov     [edi+ebx*2],eax
+    mov     [edi+ebx*2+4],eax
+    mov     [edi+ebx*2+8],edx
+    jmp     .loopx_end
+..@cross8
+    mov     ecx,[w8]
+    mov     edx,eax
+    shl     edx,2
+    add     edx,[ebx+ecx*4]
+    sub     edx,eax
+    shr     edx,2
+    mov     ebx,[ebp+dstpitch]
+    mov     [edi],eax
+    mov     [edi+4],eax
+    mov     [edi+8],eax
+    mov     [edi+ebx],eax
+    mov     [edi+ebx+4],eax
+    mov     [edi+ebx+8],eax
+    mov     [edi+ebx*2],edx
+    mov     [edi+ebx*2+4],edx
+    mov     [edi+ebx*2+8],edx
+    jmp     .loopx_end
+..@crossN
+    mov     edx,[w2]
+    mov     ecx,[ebx+edx*4]
+    mov     [c2],ecx
+    mov     edx,[w4]
+    mov     ecx,[ebx+edx*4]
+    mov     [c4],ecx
+    mov     edx,[w6]
+    mov     ecx,[ebx+edx*4]
+    mov     [c6],ecx
+    mov     edx,[w8]
+    mov     ecx,[ebx+edx*4]
+    mov     [c8],ecx
+    mov     ebx,[ebp+dstpitch]
+    jmp     ..@flag0
+
+.loopx_end
+    add esi,2
+    add edi,12
+    dec dword[xcounter]
+    jz  .nexty
+    jmp .loopx
+.nexty
+    mov dword[firstline],0
+    add esi,[ebp+srcpitch]
+       add edi,[ebp+dstpitch2]
+    dec dword[linesleft]
+    jz  .fin
+    jmp .loopy
+.fin
+    emms
+    popad
+    mov esp,ebp
+    pop ebp
+    ret
+
+SECTION .data
+FuncTable
+    dd ..@flag0, ..@flag1, ..@flag2, ..@flag3, ..@flag4, ..@flag5, ..@flag6, ..@flag7
+    dd ..@flag8, ..@flag9, ..@flag10, ..@flag11, ..@flag12, ..@flag13, ..@flag14, ..@flag15
+    dd ..@flag16, ..@flag17, ..@flag18, ..@flag19, ..@flag20, ..@flag21, ..@flag22, ..@flag23
+    dd ..@flag24, ..@flag25, ..@flag26, ..@flag27, ..@flag28, ..@flag29, ..@flag30, ..@flag31
+    dd ..@flag32, ..@flag33, ..@flag34, ..@flag35, ..@flag36, ..@flag37, ..@flag38, ..@flag39
+    dd ..@flag40, ..@flag41, ..@flag42, ..@flag43, ..@flag44, ..@flag45, ..@flag46, ..@flag47
+    dd ..@flag48, ..@flag49, ..@flag50, ..@flag51, ..@flag52, ..@flag53, ..@flag54, ..@flag55
+    dd ..@flag56, ..@flag57, ..@flag58, ..@flag59, ..@flag60, ..@flag61, ..@flag62, ..@flag63
+    dd ..@flag64, ..@flag65, ..@flag66, ..@flag67, ..@flag68, ..@flag69, ..@flag70, ..@flag71
+    dd ..@flag72, ..@flag73, ..@flag74, ..@flag75, ..@flag76, ..@flag77, ..@flag78, ..@flag79
+    dd ..@flag80, ..@flag81, ..@flag82, ..@flag83, ..@flag84, ..@flag85, ..@flag86, ..@flag87
+    dd ..@flag88, ..@flag89, ..@flag90, ..@flag91, ..@flag92, ..@flag93, ..@flag94, ..@flag95
+    dd ..@flag96, ..@flag97, ..@flag98, ..@flag99, ..@flag100, ..@flag101, ..@flag102, ..@flag103
+    dd ..@flag104, ..@flag105, ..@flag106, ..@flag107, ..@flag108, ..@flag109, ..@flag110, ..@flag111
+    dd ..@flag112, ..@flag113, ..@flag114, ..@flag115, ..@flag116, ..@flag117, ..@flag118, ..@flag119
+    dd ..@flag120, ..@flag121, ..@flag122, ..@flag123, ..@flag124, ..@flag125, ..@flag126, ..@flag127
+    dd ..@flag128, ..@flag129, ..@flag130, ..@flag131, ..@flag132, ..@flag133, ..@flag134, ..@flag135
+    dd ..@flag136, ..@flag137, ..@flag138, ..@flag139, ..@flag140, ..@flag141, ..@flag142, ..@flag143
+    dd ..@flag144, ..@flag145, ..@flag146, ..@flag147, ..@flag148, ..@flag149, ..@flag150, ..@flag151
+    dd ..@flag152, ..@flag153, ..@flag154, ..@flag155, ..@flag156, ..@flag157, ..@flag158, ..@flag159
+    dd ..@flag160, ..@flag161, ..@flag162, ..@flag163, ..@flag164, ..@flag165, ..@flag166, ..@flag167
+    dd ..@flag168, ..@flag169, ..@flag170, ..@flag171, ..@flag172, ..@flag173, ..@flag174, ..@flag175
+    dd ..@flag176, ..@flag177, ..@flag178, ..@flag179, ..@flag180, ..@flag181, ..@flag182, ..@flag183
+    dd ..@flag184, ..@flag185, ..@flag186, ..@flag187, ..@flag188, ..@flag189, ..@flag190, ..@flag191
+    dd ..@flag192, ..@flag193, ..@flag194, ..@flag195, ..@flag196, ..@flag197, ..@flag198, ..@flag199
+    dd ..@flag200, ..@flag201, ..@flag202, ..@flag203, ..@flag204, ..@flag205, ..@flag206, ..@flag207
+    dd ..@flag208, ..@flag209, ..@flag210, ..@flag211, ..@flag212, ..@flag213, ..@flag214, ..@flag215
+    dd ..@flag216, ..@flag217, ..@flag218, ..@flag219, ..@flag220, ..@flag221, ..@flag222, ..@flag223
+    dd ..@flag224, ..@flag225, ..@flag226, ..@flag227, ..@flag228, ..@flag229, ..@flag230, ..@flag231
+    dd ..@flag232, ..@flag233, ..@flag234, ..@flag235, ..@flag236, ..@flag237, ..@flag238, ..@flag239
+    dd ..@flag240, ..@flag241, ..@flag242, ..@flag243, ..@flag244, ..@flag245, ..@flag246, ..@flag247
+    dd ..@flag248, ..@flag249, ..@flag250, ..@flag251, ..@flag252, ..@flag253, ..@flag254, ..@flag255
+
+FuncTable2
+    dd ..@cross0, ..@cross1, ..@cross2, ..@crossN,
+    dd ..@cross4, ..@crossN, ..@crossN, ..@crossN,
+    dd ..@cross8, ..@crossN, ..@crossN, ..@crossN,
+    dd ..@crossN, ..@crossN, ..@crossN, ..@crossN
+
diff --git a/od-win32/hq4x32.asm b/od-win32/hq4x32.asm
new file mode 100755 (executable)
index 0000000..97b7fb7
--- /dev/null
@@ -0,0 +1,4014 @@
+;hq4x filter
+;----------------------------------------------------------
+;Copyright (C) 2003 MaxSt ( maxst@hiend3d.com )
+;
+;This program is free software; you can redistribute it and/or
+;modify it under the terms of the GNU General Public License
+;as published by the Free Software Foundation; either
+;version 2 of the License, or (at your option) any later
+;version.
+;
+;This program is distributed in the hope that it will be useful,
+;but WITHOUT ANY WARRANTY; without even the implied warranty of
+;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;GNU General Public License for more details.
+;
+;You should have received a copy of the GNU General Public License
+;along with this program; if not, write to the Free Software
+;Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+GLOBAL _hq4x_32
+
+EXTERN _LUT16to32
+EXTERN _RGBtoYUV
+
+SECTION .bss
+linesleft resd 1
+xcounter  resd 1
+cross     resd 1
+nextline  resd 1
+prevline  resd 1
+w1        resd 1
+w2        resd 1
+w3        resd 1
+w4        resd 1
+w5        resd 1
+w6        resd 1
+w7        resd 1
+w8        resd 1
+w9        resd 1
+c1        resd 1
+c2        resd 1
+c3        resd 1
+c4        resd 1
+c5        resd 1
+c6        resd 1
+c7        resd 1
+c8        resd 1
+c9        resd 1
+
+SECTION .data
+
+reg_blank    dd  0,0
+const3       dd  0x00030003,0x00000003
+const5       dd  0x00050005,0x00000005
+const6       dd  0x00060006,0x00000006
+const7       dd  0x00070007,0x00000007
+threshold    dd  0x00300706,0x00000000
+
+SECTION .text
+
+%macro AUXADDRESS 0
+    mov     ecx, edi
+    add     ecx, ebx
+    add     ecx, ebx
+%endmacro
+
+%macro TestDiff 2
+    mov     edx,[%1]
+    sub     edx,[%2]
+    jz      %%fin
+    mov     edx,[%1]
+    shl     edx,2
+    add     edx,_RGBtoYUV
+    movd    mm1,[edx]
+    movq    mm5,mm1
+    mov     edx,[%2]
+    shl     edx,2
+    add     edx,_RGBtoYUV
+    movd    mm2,[edx]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+%%fin:
+%endmacro
+
+%macro DiffOrNot 4
+   TestDiff %1,%2
+   test edx,edx
+   jz   %%same
+   %3
+   jmp %%fin
+%%same:
+   %4
+%%fin
+%endmacro
+
+%macro DiffOrNot 8
+   TestDiff %1,%2
+   test edx,edx
+   jz   %%same
+   %3
+   %4
+   %5
+   jmp %%fin
+%%same:
+   %6
+   %7
+   %8
+%%fin
+%endmacro
+
+%macro DiffOrNot 10
+   TestDiff %1,%2
+   test edx,edx
+   jz %%same
+   %3
+   %4
+   %5
+   %6
+   jmp %%fin
+%%same:
+   %7
+   %8
+   %9
+   %10
+%%fin
+%endmacro
+
+%macro DiffOrNot 14
+   TestDiff %1,%2
+   test edx,edx
+   jz %%same
+   %3
+   %4
+   %5
+   %6
+   %7
+   %8
+   jmp %%fin
+%%same:
+   %9
+   %10
+   %11
+   %12
+   %13
+   %14
+%%fin
+%endmacro
+
+%macro Interp1 3
+    mov edx,%2
+    shl edx,2
+    add edx,%3
+    sub edx,%2
+    shr edx,2
+    mov %1,edx
+%endmacro
+
+%macro Interp2 4
+    mov edx,%2
+    shl edx,1
+    add edx,%3
+    add edx,%4
+    shr edx,2
+    mov %1,edx
+%endmacro
+
+%macro Interp3 2
+    movd       mm1, eax
+    movd       mm2, %2
+    punpcklbw  mm1, [reg_blank]
+    punpcklbw  mm2, [reg_blank]
+    pmullw     mm1, [const7]
+    paddw      mm1, mm2
+    psrlw      mm1, 3
+    packuswb   mm1, [reg_blank]
+    movd       %1, mm1
+%endmacro
+
+%macro Interp5 3
+    mov edx,%2
+    add edx,%3
+    shr edx,1
+    mov %1,edx
+%endmacro
+
+%macro Interp6 3
+    movd       mm1, eax
+    movd       mm2, %2
+    movd       mm3, %3
+    punpcklbw  mm1, [reg_blank]
+    punpcklbw  mm2, [reg_blank]
+    punpcklbw  mm3, [reg_blank]
+    pmullw     mm1, [const5]
+    psllw      mm2, 1
+    paddw      mm1, mm3
+    paddw      mm1, mm2
+    psrlw      mm1, 3
+    packuswb   mm1, [reg_blank]
+    movd       %1, mm1
+%endmacro
+
+%macro Interp7 3
+    movd       mm1, eax
+    movd       mm2, %2
+    movd       mm3, %3
+    punpcklbw  mm1, [reg_blank]
+    punpcklbw  mm2, [reg_blank]
+    punpcklbw  mm3, [reg_blank]
+    pmullw     mm1, [const6]
+    paddw      mm2, mm3
+    paddw      mm1, mm2
+    psrlw      mm1, 3
+    packuswb   mm1, [reg_blank]
+    movd       %1, mm1
+%endmacro
+
+%macro Interp8 3
+    movd       mm1, %2
+    movd       mm2, %3
+    punpcklbw  mm1, [reg_blank]
+    punpcklbw  mm2, [reg_blank]
+    pmullw     mm1, [const5]
+    pmullw     mm2, [const3]
+    paddw      mm1, mm2
+    psrlw      mm1, 3
+    packuswb   mm1, [reg_blank]
+    movd       %1, mm1
+%endmacro
+
+%macro PIXEL00_0 0
+    mov [edi],eax
+%endmacro
+
+%macro PIXEL00_11 0
+    Interp1 [edi],eax,[c4]
+%endmacro
+
+%macro PIXEL00_12 0
+    Interp1 [edi],eax,[c2]
+%endmacro
+
+%macro PIXEL00_20 0
+    Interp2 [edi],eax,[c2],[c4]
+%endmacro
+
+%macro PIXEL00_50 0
+    Interp5 [edi],[c2],[c4]
+%endmacro
+
+%macro PIXEL00_80 0
+    Interp8 [edi],eax,[c1]
+%endmacro
+
+%macro PIXEL00_81 0
+    Interp8 [edi],eax,[c4]
+%endmacro
+
+%macro PIXEL00_82 0
+    Interp8 [edi],eax,[c2]
+%endmacro
+
+%macro PIXEL01_0 0
+    mov [edi+4],eax
+%endmacro
+
+%macro PIXEL01_10 0
+    Interp1 [edi+4],eax,[c1]
+%endmacro
+
+%macro PIXEL01_12 0
+    Interp1 [edi+4],eax,[c2]
+%endmacro
+
+%macro PIXEL01_14 0
+    Interp1 [edi+4],[c2],eax
+%endmacro
+
+%macro PIXEL01_21 0
+    Interp2 [edi+4],[c2],eax,[c4]
+%endmacro
+
+%macro PIXEL01_31 0
+    Interp3 [edi+4],[c4]
+%endmacro
+
+%macro PIXEL01_50 0
+    Interp5 [edi+4],[c2],eax
+%endmacro
+
+%macro PIXEL01_60 0
+    Interp6 [edi+4],[c2],[c4]
+%endmacro
+
+%macro PIXEL01_61 0
+    Interp6 [edi+4],[c2],[c1]
+%endmacro
+
+%macro PIXEL01_82 0
+    Interp8 [edi+4],eax,[c2]
+%endmacro
+
+%macro PIXEL01_83 0
+    Interp8 [edi+4],[c2],[c4]
+%endmacro
+
+%macro PIXEL02_0 0
+    mov [edi+8],eax
+%endmacro
+
+%macro PIXEL02_10 0
+    Interp1 [edi+8],eax,[c3]
+%endmacro
+
+%macro PIXEL02_11 0
+    Interp1 [edi+8],eax,[c2]
+%endmacro
+
+%macro PIXEL02_13 0
+    Interp1 [edi+8],[c2],eax
+%endmacro
+
+%macro PIXEL02_21 0
+    Interp2 [edi+8],[c2],eax,[c6]
+%endmacro
+
+%macro PIXEL02_32 0
+    Interp3 [edi+8],[c6]
+%endmacro
+
+%macro PIXEL02_50 0
+    Interp5 [edi+8],[c2],eax
+%endmacro
+
+%macro PIXEL02_60 0
+    Interp6 [edi+8],[c2],[c6]
+%endmacro
+
+%macro PIXEL02_61 0
+    Interp6 [edi+8],[c2],[c3]
+%endmacro
+
+%macro PIXEL02_81 0
+    Interp8 [edi+8],eax,[c2]
+%endmacro
+
+%macro PIXEL02_83 0
+    Interp8 [edi+8],[c2],[c6]
+%endmacro
+
+%macro PIXEL03_0 0
+    mov [edi+12],eax
+%endmacro
+
+%macro PIXEL03_11 0
+    Interp1 [edi+12],eax,[c2]
+%endmacro
+
+%macro PIXEL03_12 0
+    Interp1 [edi+12],eax,[c6]
+%endmacro
+
+%macro PIXEL03_20 0
+    Interp2 [edi+12],eax,[c2],[c6]
+%endmacro
+
+%macro PIXEL03_50 0
+    Interp5 [edi+12],[c2],[c6]
+%endmacro
+
+%macro PIXEL03_80 0
+    Interp8 [edi+12],eax,[c3]
+%endmacro
+
+%macro PIXEL03_81 0
+    Interp8 [edi+12],eax,[c2]
+%endmacro
+
+%macro PIXEL03_82 0
+    Interp8 [edi+12],eax,[c6]
+%endmacro
+
+%macro PIXEL10_0 0
+    mov [edi+ebx],eax
+%endmacro
+
+%macro PIXEL10_10 0
+    Interp1 [edi+ebx],eax,[c1]
+%endmacro
+
+%macro PIXEL10_11 0
+    Interp1 [edi+ebx],eax,[c4]
+%endmacro
+
+%macro PIXEL10_13 0
+    Interp1 [edi+ebx],[c4],eax
+%endmacro
+
+%macro PIXEL10_21 0
+    Interp2 [edi+ebx],[c4],eax,[c2]
+%endmacro
+
+%macro PIXEL10_32 0
+    Interp3 [edi+ebx],[c2]
+%endmacro
+
+%macro PIXEL10_50 0
+    Interp5 [edi+ebx],[c4],eax
+%endmacro
+
+%macro PIXEL10_60 0
+    Interp6 [edi+ebx],[c4],[c2]
+%endmacro
+
+%macro PIXEL10_61 0
+    Interp6 [edi+ebx],[c4],[c1]
+%endmacro
+
+%macro PIXEL10_81 0
+    Interp8 [edi+ebx],eax,[c4]
+%endmacro
+
+%macro PIXEL10_83 0
+    Interp8 [edi+ebx],[c4],[c2]
+%endmacro
+
+%macro PIXEL11_0 0
+    mov [edi+ebx+4],eax
+%endmacro
+
+%macro PIXEL11_30 0
+    Interp3 [edi+ebx+4],[c1]
+%endmacro
+
+%macro PIXEL11_31 0
+    Interp3 [edi+ebx+4],[c4]
+%endmacro
+
+%macro PIXEL11_32 0
+    Interp3 [edi+ebx+4],[c2]
+%endmacro
+
+%macro PIXEL11_70 0
+    Interp7 [edi+ebx+4],[c4],[c2]
+%endmacro
+
+%macro PIXEL12_0 0
+    mov [edi+ebx+8],eax
+%endmacro
+
+%macro PIXEL12_30 0
+    Interp3 [edi+ebx+8],[c3]
+%endmacro
+
+%macro PIXEL12_31 0
+    Interp3 [edi+ebx+8],[c2]
+%endmacro
+
+%macro PIXEL12_32 0
+    Interp3 [edi+ebx+8],[c6]
+%endmacro
+
+%macro PIXEL12_70 0
+    Interp7 [edi+ebx+8],[c6],[c2]
+%endmacro
+
+%macro PIXEL13_0 0
+    mov [edi+ebx+12],eax
+%endmacro
+
+%macro PIXEL13_10 0
+    Interp1 [edi+ebx+12],eax,[c3]
+%endmacro
+
+%macro PIXEL13_12 0
+    Interp1 [edi+ebx+12],eax,[c6]
+%endmacro
+
+%macro PIXEL13_14 0
+    Interp1 [edi+ebx+12],[c6],eax
+%endmacro
+
+%macro PIXEL13_21 0
+    Interp2 [edi+ebx+12],[c6],eax,[c2]
+%endmacro
+
+%macro PIXEL13_31 0
+    Interp3 [edi+ebx+12],[c2]
+%endmacro
+
+%macro PIXEL13_50 0
+    Interp5 [edi+ebx+12],[c6],eax
+%endmacro
+
+%macro PIXEL13_60 0
+    Interp6 [edi+ebx+12],[c6],[c2]
+%endmacro
+
+%macro PIXEL13_61 0
+    Interp6 [edi+ebx+12],[c6],[c3]
+%endmacro
+
+%macro PIXEL13_82 0
+    Interp8 [edi+ebx+12],eax,[c6]
+%endmacro
+
+%macro PIXEL13_83 0
+    Interp8 [edi+ebx+12],[c6],[c2]
+%endmacro
+
+%macro PIXEL20_0 0
+    mov [ecx],eax
+%endmacro
+
+%macro PIXEL20_10 0
+    Interp1 [ecx],eax,[c7]
+%endmacro
+
+%macro PIXEL20_12 0
+    Interp1 [ecx],eax,[c4]
+%endmacro
+
+%macro PIXEL20_14 0
+    Interp1 [ecx],[c4],eax
+%endmacro
+
+%macro PIXEL20_21 0
+    Interp2 [ecx],[c4],eax,[c8]
+%endmacro
+
+%macro PIXEL20_31 0
+    Interp3 [ecx],[c8]
+%endmacro
+
+%macro PIXEL20_50 0
+    Interp5 [ecx],[c4],eax
+%endmacro
+
+%macro PIXEL20_60 0
+    Interp6 [ecx],[c4],[c8]
+%endmacro
+
+%macro PIXEL20_61 0
+    Interp6 [ecx],[c4],[c7]
+%endmacro
+
+%macro PIXEL20_82 0
+    Interp8 [ecx],eax,[c4]
+%endmacro
+
+%macro PIXEL20_83 0
+    Interp8 [ecx],[c4],[c8]
+%endmacro
+
+%macro PIXEL21_0 0
+    mov [ecx+4],eax
+%endmacro
+
+%macro PIXEL21_30 0
+    Interp3 [ecx+4],[c7]
+%endmacro
+
+%macro PIXEL21_31 0
+    Interp3 [ecx+4],[c8]
+%endmacro
+
+%macro PIXEL21_32 0
+    Interp3 [ecx+4],[c4]
+%endmacro
+
+%macro PIXEL21_70 0
+    Interp7 [ecx+4],[c4],[c8]
+%endmacro
+
+%macro PIXEL22_0 0
+    mov [ecx+8],eax
+%endmacro
+
+%macro PIXEL22_30 0
+    Interp3 [ecx+8],[c9]
+%endmacro
+
+%macro PIXEL22_31 0
+    Interp3 [ecx+8],[c6]
+%endmacro
+
+%macro PIXEL22_32 0
+    Interp3 [ecx+8],[c8]
+%endmacro
+
+%macro PIXEL22_70 0
+    Interp7 [ecx+8],[c6],[c8]
+%endmacro
+
+%macro PIXEL23_0 0
+    mov [ecx+12],eax
+%endmacro
+
+%macro PIXEL23_10 0
+    Interp1 [ecx+12],eax,[c9]
+%endmacro
+
+%macro PIXEL23_11 0
+    Interp1 [ecx+12],eax,[c6]
+%endmacro
+
+%macro PIXEL23_13 0
+    Interp1 [ecx+12],[c6],eax
+%endmacro
+
+%macro PIXEL23_21 0
+    Interp2 [ecx+12],[c6],eax,[c8]
+%endmacro
+
+%macro PIXEL23_32 0
+    Interp3 [ecx+12],[c8]
+%endmacro
+
+%macro PIXEL23_50 0
+    Interp5 [ecx+12],[c6],eax
+%endmacro
+
+%macro PIXEL23_60 0
+    Interp6 [ecx+12],[c6],[c8]
+%endmacro
+
+%macro PIXEL23_61 0
+    Interp6 [ecx+12],[c6],[c9]
+%endmacro
+
+%macro PIXEL23_81 0
+    Interp8 [ecx+12],eax,[c6]
+%endmacro
+
+%macro PIXEL23_83 0
+    Interp8 [ecx+12],[c6],[c8]
+%endmacro
+
+%macro PIXEL30_0 0
+    mov [ecx+ebx],eax
+%endmacro
+
+%macro PIXEL30_11 0
+    Interp1 [ecx+ebx],eax,[c8]
+%endmacro
+
+%macro PIXEL30_12 0
+    Interp1 [ecx+ebx],eax,[c4]
+%endmacro
+
+%macro PIXEL30_20 0
+    Interp2 [ecx+ebx],eax,[c8],[c4]
+%endmacro
+
+%macro PIXEL30_50 0
+    Interp5 [ecx+ebx],[c8],[c4]
+%endmacro
+
+%macro PIXEL30_80 0
+    Interp8 [ecx+ebx],eax,[c7]
+%endmacro
+
+%macro PIXEL30_81 0
+    Interp8 [ecx+ebx],eax,[c8]
+%endmacro
+
+%macro PIXEL30_82 0
+    Interp8 [ecx+ebx],eax,[c4]
+%endmacro
+
+%macro PIXEL31_0 0
+    mov [ecx+ebx+4],eax
+%endmacro
+
+%macro PIXEL31_10 0
+    Interp1 [ecx+ebx+4],eax,[c7]
+%endmacro
+
+%macro PIXEL31_11 0
+    Interp1 [ecx+ebx+4],eax,[c8]
+%endmacro
+
+%macro PIXEL31_13 0
+    Interp1 [ecx+ebx+4],[c8],eax
+%endmacro
+
+%macro PIXEL31_21 0
+    Interp2 [ecx+ebx+4],[c8],eax,[c4]
+%endmacro
+
+%macro PIXEL31_32 0
+    Interp3 [ecx+ebx+4],[c4]
+%endmacro
+
+%macro PIXEL31_50 0
+    Interp5 [ecx+ebx+4],[c8],eax
+%endmacro
+
+%macro PIXEL31_60 0
+    Interp6 [ecx+ebx+4],[c8],[c4]
+%endmacro
+
+%macro PIXEL31_61 0
+    Interp6 [ecx+ebx+4],[c8],[c7]
+%endmacro
+
+%macro PIXEL31_81 0
+    Interp8 [ecx+ebx+4],eax,[c8]
+%endmacro
+
+%macro PIXEL31_83 0
+    Interp8 [ecx+ebx+4],[c8],[c4]
+%endmacro
+
+%macro PIXEL32_0 0
+    mov [ecx+ebx+8],eax
+%endmacro
+
+%macro PIXEL32_10 0
+    Interp1 [ecx+ebx+8],eax,[c9]
+%endmacro
+
+%macro PIXEL32_12 0
+    Interp1 [ecx+ebx+8],eax,[c8]
+%endmacro
+
+%macro PIXEL32_14 0
+    Interp1 [ecx+ebx+8],[c8],eax
+%endmacro
+
+%macro PIXEL32_21 0
+    Interp2 [ecx+ebx+8],[c8],eax,[c6]
+%endmacro
+
+%macro PIXEL32_31 0
+    Interp3 [ecx+ebx+8],[c6]
+%endmacro
+
+%macro PIXEL32_50 0
+    Interp5 [ecx+ebx+8],[c8],eax
+%endmacro
+
+%macro PIXEL32_60 0
+    Interp6 [ecx+ebx+8],[c8],[c6]
+%endmacro
+
+%macro PIXEL32_61 0
+    Interp6 [ecx+ebx+8],[c8],[c9]
+%endmacro
+
+%macro PIXEL32_82 0
+    Interp8 [ecx+ebx+8],eax,[c8]
+%endmacro
+
+%macro PIXEL32_83 0
+    Interp8 [ecx+ebx+8],[c8],[c6]
+%endmacro
+
+%macro PIXEL33_0 0
+    mov [ecx+ebx+12],eax
+%endmacro
+
+%macro PIXEL33_11 0
+    Interp1 [ecx+ebx+12],eax,[c6]
+%endmacro
+
+%macro PIXEL33_12 0
+    Interp1 [ecx+ebx+12],eax,[c8]
+%endmacro
+
+%macro PIXEL33_20 0
+    Interp2 [ecx+ebx+12],eax,[c8],[c6]
+%endmacro
+
+%macro PIXEL33_50 0
+    Interp5 [ecx+ebx+12],[c8],[c6]
+%endmacro
+
+%macro PIXEL33_80 0
+    Interp8 [ecx+ebx+12],eax,[c9]
+%endmacro
+
+%macro PIXEL33_81 0
+    Interp8 [ecx+ebx+12],eax,[c6]
+%endmacro
+
+%macro PIXEL33_82 0
+    Interp8 [ecx+ebx+12],eax,[c8]
+%endmacro
+
+inbuffer     equ 8
+outbuffer    equ 12
+Xres         equ 16
+Yres         equ 20
+dstpitch     equ 24
+srcpitch     equ 28
+
+_hq4x_32:
+    push ebp
+    mov ebp,esp
+    pushad
+
+    mov     esi,[ebp+inbuffer]
+    mov     edi,[ebp+outbuffer]
+    mov     edx,[ebp+Yres]
+    mov     [linesleft],edx
+    mov     ebx,[ebp+Xres]
+    shl     ebx,1
+    mov     dword[prevline],0
+    mov     dword[nextline],ebx
+.loopy
+    mov     ecx,[ebp+Xres]
+    sub     ecx,2                 ; x={Xres-2, Xres-1} are special cases.
+    mov     dword[xcounter],ecx
+    ; x=0 - special case
+    mov     ebx,[prevline]
+    movq    mm5,[esi+ebx]
+    movq    mm6,[esi]
+    mov     ebx,[nextline]
+    movq    mm7,[esi+ebx]
+    movd    eax,mm5
+    movzx   edx,ax  
+    mov     [w1],edx
+    mov     [w2],edx
+    shr     eax,16
+    mov     [w3],eax
+    movd    eax,mm6
+    movzx   edx,ax  
+    mov     [w4],edx
+    mov     [w5],edx
+    shr     eax,16
+    mov     [w6],eax
+    movd    eax,mm7
+    movzx   edx,ax  
+    mov     [w7],edx
+    mov     [w8],edx
+    shr     eax,16
+    mov     [w9],eax
+    jmp     .flags
+.loopx
+    mov     ebx,[prevline]
+    movq    mm5,[esi+ebx-2]
+    movq    mm6,[esi-2]
+    mov     ebx,[nextline]
+    movq    mm7,[esi+ebx-2]
+    movd    eax,mm5
+    movzx   edx,ax  
+    mov     [w1],edx
+    shr     eax,16
+    mov     [w2],eax
+    psrlq   mm5,32
+    movd    eax,mm5
+    movzx   edx,ax  
+    mov     [w3],edx
+    movd    eax,mm6
+    movzx   edx,ax  
+    mov     [w4],edx
+    shr     eax,16
+    mov     [w5],eax
+    psrlq   mm6,32
+    movd    eax,mm6
+    movzx   edx,ax  
+    mov     [w6],edx
+    movd    eax,mm7
+    movzx   edx,ax  
+    mov     [w7],edx
+    shr     eax,16
+    mov     [w8],eax
+    psrlq   mm7,32
+    movd    eax,mm7
+    movzx   edx,ax  
+    mov     [w9],edx
+.flags
+    mov     ebx,_RGBtoYUV
+    mov     eax,[w5]
+    xor     ecx,ecx
+    movd    mm5,[ebx+eax*4]
+    mov     dword[cross],0
+
+    mov     edx,[w2]
+    cmp     eax,edx
+    je      .noflag2
+    or      dword[cross],1
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag2
+    or      ecx,2
+.noflag2
+    mov     edx,[w4]
+    cmp     eax,edx
+    je      .noflag4
+    or      dword[cross],2
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag4
+    or      ecx,8
+.noflag4
+    mov     edx,[w6]
+    cmp     eax,edx
+    je      .noflag6
+    or      dword[cross],4
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag6
+    or      ecx,16
+.noflag6
+    mov     edx,[w8]
+    cmp     eax,edx
+    je      .noflag8
+    or      dword[cross],8
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag8
+    or      ecx,64
+.noflag8
+    cmp     dword[cross],0
+    jnz     .testflag1
+    mov     ebx,_LUT16to32
+    mov     eax,[ebx+eax*4]
+    mov     ebx,[ebp+dstpitch]
+    AUXADDRESS
+    mov     [edi],eax
+    mov     [edi+4],eax
+    mov     [edi+8],eax
+    mov     [edi+12],eax
+    mov     [edi+ebx],eax
+    mov     [edi+ebx+4],eax
+    mov     [edi+ebx+8],eax
+    mov     [edi+ebx+12],eax
+    mov     [ecx],eax
+    mov     [ecx+4],eax
+    mov     [ecx+8],eax
+    mov     [ecx+12],eax
+    mov     [ecx+ebx],eax
+    mov     [ecx+ebx+4],eax
+    mov     [ecx+ebx+8],eax
+    mov     [ecx+ebx+12],eax
+    jmp     .loopx_end
+.testflag1
+    mov     edx,[w1]
+    cmp     eax,edx
+    je      .noflag1
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag1
+    or      ecx,1
+.noflag1
+    mov     edx,[w3]
+    cmp     eax,edx
+    je      .noflag3
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag3
+    or      ecx,4
+.noflag3
+    mov     edx,[w7]
+    cmp     eax,edx
+    je      .noflag7
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag7
+    or      ecx,32
+.noflag7
+    mov     edx,[w9]
+    cmp     eax,edx
+    je      .noflag9
+    movq    mm1,mm5
+    movd    mm2,[ebx+edx*4]
+    psubusb mm1,mm2
+    psubusb mm2,mm5
+    por     mm1,mm2
+    psubusb mm1,[threshold]
+    movd    edx,mm1
+    test    edx,edx
+    jz      .noflag9
+    or      ecx,128
+.noflag9
+    mov  ebx,_LUT16to32
+    mov  eax,[ebx+eax*4]
+    mov  edx,[w2]
+    mov  edx,[ebx+edx*4]
+    mov  [c2],edx
+    mov  edx,[w4]
+    mov  edx,[ebx+edx*4]
+    mov  [c4],edx
+    mov  edx,[w6]
+    mov  edx,[ebx+edx*4]
+    mov  [c6],edx
+    mov  edx,[w8]
+    mov  edx,[ebx+edx*4]
+    mov  [c8],edx
+    test ecx,0x005A
+    jz  .switch
+    mov  edx,[w1]
+    mov  edx,[ebx+edx*4]
+    mov  [c1],edx
+    mov  edx,[w3]
+    mov  edx,[ebx+edx*4]
+    mov  [c3],edx
+    mov  edx,[w7]
+    mov  edx,[ebx+edx*4]
+    mov  [c7],edx
+    mov  edx,[w9]
+    mov  edx,[ebx+edx*4]
+    mov  [c9],edx
+.switch
+    mov  ebx,[ebp+dstpitch]
+    jmp  [FuncTable+ecx*4]
+
+..@flag0
+..@flag1
+..@flag4
+..@flag32
+..@flag128
+..@flag5
+..@flag132
+..@flag160
+..@flag33
+..@flag129
+..@flag36
+..@flag133
+..@flag164
+..@flag161
+..@flag37
+..@flag165
+    AUXADDRESS
+    PIXEL00_20
+    PIXEL01_60
+    PIXEL02_60
+    PIXEL03_20
+    PIXEL10_60
+    PIXEL11_70
+    PIXEL12_70
+    PIXEL13_60
+    PIXEL20_60
+    PIXEL21_70
+    PIXEL22_70
+    PIXEL23_60
+    PIXEL30_20
+    PIXEL31_60
+    PIXEL32_60
+    PIXEL33_20
+    jmp .loopx_end
+..@flag2
+..@flag34
+..@flag130
+..@flag162
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL10_61
+    PIXEL11_30
+    PIXEL12_30
+    PIXEL13_61
+    PIXEL20_60
+    PIXEL21_70
+    PIXEL22_70
+    PIXEL23_60
+    PIXEL30_20
+    PIXEL31_60
+    PIXEL32_60
+    PIXEL33_20
+    jmp .loopx_end
+..@flag16
+..@flag17
+..@flag48
+..@flag49
+    AUXADDRESS
+    PIXEL00_20
+    PIXEL01_60
+    PIXEL02_61
+    PIXEL03_80
+    PIXEL10_60
+    PIXEL11_70
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL20_60
+    PIXEL21_70
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_20
+    PIXEL31_60
+    PIXEL32_61
+    PIXEL33_80
+    jmp .loopx_end
+..@flag64
+..@flag65
+..@flag68
+..@flag69
+    AUXADDRESS
+    PIXEL00_20
+    PIXEL01_60
+    PIXEL02_60
+    PIXEL03_20
+    PIXEL10_60
+    PIXEL11_70
+    PIXEL12_70
+    PIXEL13_60
+    PIXEL20_61
+    PIXEL21_30
+    PIXEL22_30
+    PIXEL23_61
+    PIXEL30_80
+    PIXEL31_10
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag8
+..@flag12
+..@flag136
+..@flag140
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_61
+    PIXEL02_60
+    PIXEL03_20
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_70
+    PIXEL13_60
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_70
+    PIXEL23_60
+    PIXEL30_80
+    PIXEL31_61
+    PIXEL32_60
+    PIXEL33_20
+    jmp .loopx_end
+..@flag3
+..@flag35
+..@flag131
+..@flag163
+    AUXADDRESS
+    PIXEL00_81
+    PIXEL01_31
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL10_81
+    PIXEL11_31
+    PIXEL12_30
+    PIXEL13_61
+    PIXEL20_60
+    PIXEL21_70
+    PIXEL22_70
+    PIXEL23_60
+    PIXEL30_20
+    PIXEL31_60
+    PIXEL32_60
+    PIXEL33_20
+    jmp .loopx_end
+..@flag6
+..@flag38
+..@flag134
+..@flag166
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    PIXEL02_32
+    PIXEL03_82
+    PIXEL10_61
+    PIXEL11_30
+    PIXEL12_32
+    PIXEL13_82
+    PIXEL20_60
+    PIXEL21_70
+    PIXEL22_70
+    PIXEL23_60
+    PIXEL30_20
+    PIXEL31_60
+    PIXEL32_60
+    PIXEL33_20
+    jmp .loopx_end
+..@flag20
+..@flag21
+..@flag52
+..@flag53
+    AUXADDRESS
+    PIXEL00_20
+    PIXEL01_60
+    PIXEL02_81
+    PIXEL03_81
+    PIXEL10_60
+    PIXEL11_70
+    PIXEL12_31
+    PIXEL13_31
+    PIXEL20_60
+    PIXEL21_70
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_20
+    PIXEL31_60
+    PIXEL32_61
+    PIXEL33_80
+    jmp .loopx_end
+..@flag144
+..@flag145
+..@flag176
+..@flag177
+    AUXADDRESS
+    PIXEL00_20
+    PIXEL01_60
+    PIXEL02_61
+    PIXEL03_80
+    PIXEL10_60
+    PIXEL11_70
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL20_60
+    PIXEL21_70
+    PIXEL22_32
+    PIXEL23_32
+    PIXEL30_20
+    PIXEL31_60
+    PIXEL32_82
+    PIXEL33_82
+    jmp .loopx_end
+..@flag192
+..@flag193
+..@flag196
+..@flag197
+    AUXADDRESS
+    PIXEL00_20
+    PIXEL01_60
+    PIXEL02_60
+    PIXEL03_20
+    PIXEL10_60
+    PIXEL11_70
+    PIXEL12_70
+    PIXEL13_60
+    PIXEL20_61
+    PIXEL21_30
+    PIXEL22_31
+    PIXEL23_81
+    PIXEL30_80
+    PIXEL31_10
+    PIXEL32_31
+    PIXEL33_81
+    jmp .loopx_end
+..@flag96
+..@flag97
+..@flag100
+..@flag101
+    AUXADDRESS
+    PIXEL00_20
+    PIXEL01_60
+    PIXEL02_60
+    PIXEL03_20
+    PIXEL10_60
+    PIXEL11_70
+    PIXEL12_70
+    PIXEL13_60
+    PIXEL20_82
+    PIXEL21_32
+    PIXEL22_30
+    PIXEL23_61
+    PIXEL30_82
+    PIXEL31_32
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag40
+..@flag44
+..@flag168
+..@flag172
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_61
+    PIXEL02_60
+    PIXEL03_20
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_70
+    PIXEL13_60
+    PIXEL20_31
+    PIXEL21_31
+    PIXEL22_70
+    PIXEL23_60
+    PIXEL30_81
+    PIXEL31_81
+    PIXEL32_60
+    PIXEL33_20
+    jmp .loopx_end
+..@flag9
+..@flag13
+..@flag137
+..@flag141
+    AUXADDRESS
+    PIXEL00_82
+    PIXEL01_82
+    PIXEL02_60
+    PIXEL03_20
+    PIXEL10_32
+    PIXEL11_32
+    PIXEL12_70
+    PIXEL13_60
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_70
+    PIXEL23_60
+    PIXEL30_80
+    PIXEL31_61
+    PIXEL32_60
+    PIXEL33_20
+    jmp .loopx_end
+..@flag18
+..@flag50
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_50,PIXEL03_50,PIXEL12_0,PIXEL13_50
+    PIXEL10_61
+    PIXEL11_30
+    PIXEL20_60
+    PIXEL21_70
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_20
+    PIXEL31_60
+    PIXEL32_61
+    PIXEL33_80
+    jmp .loopx_end
+..@flag80
+..@flag81
+    AUXADDRESS
+    PIXEL00_20
+    PIXEL01_60
+    PIXEL02_61
+    PIXEL03_80
+    PIXEL10_60
+    PIXEL11_70
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL20_61
+    PIXEL21_30
+    DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_50,PIXEL32_50,PIXEL33_50
+    PIXEL30_80
+    PIXEL31_10
+    jmp .loopx_end
+..@flag72
+..@flag76
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_61
+    PIXEL02_60
+    PIXEL03_20
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_70
+    PIXEL13_60
+    DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_50,PIXEL21_0,PIXEL30_50,PIXEL31_50
+    PIXEL22_30
+    PIXEL23_61
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag10
+..@flag138
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_50,PIXEL01_50,PIXEL10_50,PIXEL11_0
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL12_30
+    PIXEL13_61
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_70
+    PIXEL23_60
+    PIXEL30_80
+    PIXEL31_61
+    PIXEL32_60
+    PIXEL33_20
+    jmp .loopx_end
+..@flag66
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL10_61
+    PIXEL11_30
+    PIXEL12_30
+    PIXEL13_61
+    PIXEL20_61
+    PIXEL21_30
+    PIXEL22_30
+    PIXEL23_61
+    PIXEL30_80
+    PIXEL31_10
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag24
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_61
+    PIXEL02_61
+    PIXEL03_80
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_80
+    PIXEL31_61
+    PIXEL32_61
+    PIXEL33_80
+    jmp .loopx_end
+..@flag7
+..@flag39
+..@flag135
+    AUXADDRESS
+    PIXEL00_81
+    PIXEL01_31
+    PIXEL02_32
+    PIXEL03_82
+    PIXEL10_81
+    PIXEL11_31
+    PIXEL12_32
+    PIXEL13_82
+    PIXEL20_60
+    PIXEL21_70
+    PIXEL22_70
+    PIXEL23_60
+    PIXEL30_20
+    PIXEL31_60
+    PIXEL32_60
+    PIXEL33_20
+    jmp .loopx_end
+..@flag148
+..@flag149
+..@flag180
+    AUXADDRESS
+    PIXEL00_20
+    PIXEL01_60
+    PIXEL02_81
+    PIXEL03_81
+    PIXEL10_60
+    PIXEL11_70
+    PIXEL12_31
+    PIXEL13_31
+    PIXEL20_60
+    PIXEL21_70
+    PIXEL22_32
+    PIXEL23_32
+    PIXEL30_20
+    PIXEL31_60
+    PIXEL32_82
+    PIXEL33_82
+    jmp .loopx_end
+..@flag224
+..@flag228
+..@flag225
+    AUXADDRESS
+    PIXEL00_20
+    PIXEL01_60
+    PIXEL02_60
+    PIXEL03_20
+    PIXEL10_60
+    PIXEL11_70
+    PIXEL12_70
+    PIXEL13_60
+    PIXEL20_82
+    PIXEL21_32
+    PIXEL22_31
+    PIXEL23_81
+    PIXEL30_82
+    PIXEL31_32
+    PIXEL32_31
+    PIXEL33_81
+    jmp .loopx_end
+..@flag41
+..@flag169
+..@flag45
+    AUXADDRESS
+    PIXEL00_82
+    PIXEL01_82
+    PIXEL02_60
+    PIXEL03_20
+    PIXEL10_32
+    PIXEL11_32
+    PIXEL12_70
+    PIXEL13_60
+    PIXEL20_31
+    PIXEL21_31
+    PIXEL22_70
+    PIXEL23_60
+    PIXEL30_81
+    PIXEL31_81
+    PIXEL32_60
+    PIXEL33_20
+    jmp .loopx_end
+..@flag22
+..@flag54
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50
+    PIXEL10_61
+    PIXEL11_30
+    PIXEL12_0
+    PIXEL20_60
+    PIXEL21_70
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_20
+    PIXEL31_60
+    PIXEL32_61
+    PIXEL33_80
+    jmp .loopx_end
+..@flag208
+..@flag209
+    AUXADDRESS
+    PIXEL00_20
+    PIXEL01_60
+    PIXEL02_61
+    PIXEL03_80
+    PIXEL10_60
+    PIXEL11_70
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL20_61
+    PIXEL21_30
+    PIXEL22_0
+    DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50
+    PIXEL30_80
+    PIXEL31_10
+    jmp .loopx_end
+..@flag104
+..@flag108
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_61
+    PIXEL02_60
+    PIXEL03_20
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_70
+    PIXEL13_60
+    DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50
+    PIXEL21_0
+    PIXEL22_30
+    PIXEL23_61
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag11
+..@flag139
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL11_0
+    PIXEL12_30
+    PIXEL13_61
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_70
+    PIXEL23_60
+    PIXEL30_80
+    PIXEL31_61
+    PIXEL32_60
+    PIXEL33_20
+    jmp .loopx_end
+..@flag19
+..@flag51
+    AUXADDRESS
+    DiffOrNot w2,w6,PIXEL00_81,PIXEL01_31,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL00_12,PIXEL01_14,PIXEL02_83,PIXEL03_50,PIXEL12_70,PIXEL13_21
+    PIXEL10_81
+    PIXEL11_31
+    PIXEL20_60
+    PIXEL21_70
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_20
+    PIXEL31_60
+    PIXEL32_61
+    PIXEL33_80
+    jmp .loopx_end
+..@flag146
+..@flag178
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL23_32,PIXEL33_82,PIXEL02_21,PIXEL03_50,PIXEL12_70,PIXEL13_83,PIXEL23_13,PIXEL33_11
+    PIXEL10_61
+    PIXEL11_30
+    PIXEL20_60
+    PIXEL21_70
+    PIXEL22_32
+    PIXEL30_20
+    PIXEL31_60
+    PIXEL32_82
+    jmp .loopx_end
+..@flag84
+..@flag85
+    AUXADDRESS
+    PIXEL00_20
+    PIXEL01_60
+    PIXEL02_81
+    DiffOrNot w6,w8,PIXEL03_81,PIXEL13_31,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL03_12,PIXEL13_14,PIXEL22_70,PIXEL23_83,PIXEL32_21,PIXEL33_50
+    PIXEL10_60
+    PIXEL11_70
+    PIXEL12_31
+    PIXEL20_61
+    PIXEL21_30
+    PIXEL30_80
+    PIXEL31_10
+    jmp .loopx_end
+..@flag112
+..@flag113
+    AUXADDRESS
+    PIXEL00_20
+    PIXEL01_60
+    PIXEL02_61
+    PIXEL03_80
+    PIXEL10_60
+    PIXEL11_70
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL20_82
+    PIXEL21_32
+    DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL30_82,PIXEL31_32,PIXEL32_10,PIXEL33_80,PIXEL22_70,PIXEL23_21,PIXEL30_11,PIXEL31_13,PIXEL32_83,PIXEL33_50
+    jmp .loopx_end
+..@flag200
+..@flag204
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_61
+    PIXEL02_60
+    PIXEL03_20
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_70
+    PIXEL13_60
+    DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL32_31,PIXEL33_81,PIXEL20_21,PIXEL21_70,PIXEL30_50,PIXEL31_83,PIXEL32_14,PIXEL33_12
+    PIXEL22_31
+    PIXEL23_81
+    jmp .loopx_end
+..@flag73
+..@flag77
+    AUXADDRESS
+    DiffOrNot w8,w4,PIXEL00_82,PIXEL10_32,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL00_11,PIXEL10_13,PIXEL20_83,PIXEL21_70,PIXEL30_50,PIXEL31_21
+    PIXEL01_82
+    PIXEL02_60
+    PIXEL03_20
+    PIXEL11_32
+    PIXEL12_70
+    PIXEL13_60
+    PIXEL22_30
+    PIXEL23_61
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag42
+..@flag170
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL20_31,PIXEL30_81,PIXEL00_50,PIXEL01_21,PIXEL10_83,PIXEL11_70,PIXEL20_14,PIXEL30_12
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL12_30
+    PIXEL13_61
+    PIXEL21_31
+    PIXEL22_70
+    PIXEL23_60
+    PIXEL31_81
+    PIXEL32_60
+    PIXEL33_20
+    jmp .loopx_end
+..@flag14
+..@flag142
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL02_32,PIXEL03_82,PIXEL10_10,PIXEL11_30,PIXEL00_50,PIXEL01_83,PIXEL02_13,PIXEL03_11,PIXEL10_21,PIXEL11_70
+    PIXEL12_32
+    PIXEL13_82
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_70
+    PIXEL23_60
+    PIXEL30_80
+    PIXEL31_61
+    PIXEL32_60
+    PIXEL33_20
+    jmp .loopx_end
+..@flag67
+    AUXADDRESS
+    PIXEL00_81
+    PIXEL01_31
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL10_81
+    PIXEL11_31
+    PIXEL12_30
+    PIXEL13_61
+    PIXEL20_61
+    PIXEL21_30
+    PIXEL22_30
+    PIXEL23_61
+    PIXEL30_80
+    PIXEL31_10
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag70
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    PIXEL02_32
+    PIXEL03_82
+    PIXEL10_61
+    PIXEL11_30
+    PIXEL12_32
+    PIXEL13_82
+    PIXEL20_61
+    PIXEL21_30
+    PIXEL22_30
+    PIXEL23_61
+    PIXEL30_80
+    PIXEL31_10
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag28
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_61
+    PIXEL02_81
+    PIXEL03_81
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_31
+    PIXEL13_31
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_80
+    PIXEL31_61
+    PIXEL32_61
+    PIXEL33_80
+    jmp .loopx_end
+..@flag152
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_61
+    PIXEL02_61
+    PIXEL03_80
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_32
+    PIXEL23_32
+    PIXEL30_80
+    PIXEL31_61
+    PIXEL32_82
+    PIXEL33_82
+    jmp .loopx_end
+..@flag194
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL10_61
+    PIXEL11_30
+    PIXEL12_30
+    PIXEL13_61
+    PIXEL20_61
+    PIXEL21_30
+    PIXEL22_31
+    PIXEL23_81
+    PIXEL30_80
+    PIXEL31_10
+    PIXEL32_31
+    PIXEL33_81
+    jmp .loopx_end
+..@flag98
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL10_61
+    PIXEL11_30
+    PIXEL12_30
+    PIXEL13_61
+    PIXEL20_82
+    PIXEL21_32
+    PIXEL22_30
+    PIXEL23_61
+    PIXEL30_82
+    PIXEL31_32
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag56
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_61
+    PIXEL02_61
+    PIXEL03_80
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL20_31
+    PIXEL21_31
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_81
+    PIXEL31_81
+    PIXEL32_61
+    PIXEL33_80
+    jmp .loopx_end
+..@flag25
+    AUXADDRESS
+    PIXEL00_82
+    PIXEL01_82
+    PIXEL02_61
+    PIXEL03_80
+    PIXEL10_32
+    PIXEL11_32
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_80
+    PIXEL31_61
+    PIXEL32_61
+    PIXEL33_80
+    jmp .loopx_end
+..@flag26
+..@flag31
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50
+    DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50
+    PIXEL11_0
+    PIXEL12_0
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_80
+    PIXEL31_61
+    PIXEL32_61
+    PIXEL33_80
+    jmp .loopx_end
+..@flag82
+..@flag214
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50
+    PIXEL10_61
+    PIXEL11_30
+    PIXEL12_0
+    PIXEL20_61
+    PIXEL21_30
+    PIXEL22_0
+    DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50
+    PIXEL30_80
+    PIXEL31_10
+    jmp .loopx_end
+..@flag88
+..@flag248
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_61
+    PIXEL02_61
+    PIXEL03_80
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_30
+    PIXEL13_10
+    DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50
+    PIXEL21_0
+    PIXEL22_0
+    DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50
+    jmp .loopx_end
+..@flag74
+..@flag107
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL11_0
+    PIXEL12_30
+    PIXEL13_61
+    DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50
+    PIXEL21_0
+    PIXEL22_30
+    PIXEL23_61
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag27
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL11_0
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_80
+    PIXEL31_61
+    PIXEL32_61
+    PIXEL33_80
+    jmp .loopx_end
+..@flag86
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50
+    PIXEL10_61
+    PIXEL11_30
+    PIXEL12_0
+    PIXEL20_61
+    PIXEL21_30
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_80
+    PIXEL31_10
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag216
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_61
+    PIXEL02_61
+    PIXEL03_80
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_0
+    DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50
+    PIXEL30_80
+    PIXEL31_10
+    jmp .loopx_end
+..@flag106
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_30
+    PIXEL13_61
+    DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50
+    PIXEL21_0
+    PIXEL22_30
+    PIXEL23_61
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag30
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_0
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_80
+    PIXEL31_61
+    PIXEL32_61
+    PIXEL33_80
+    jmp .loopx_end
+..@flag210
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL10_61
+    PIXEL11_30
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL20_61
+    PIXEL21_30
+    PIXEL22_0
+    DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50
+    PIXEL30_80
+    PIXEL31_10
+    jmp .loopx_end
+..@flag120
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_61
+    PIXEL02_61
+    PIXEL03_80
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_30
+    PIXEL13_10
+    DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50
+    PIXEL21_0
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag75
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL11_0
+    PIXEL12_30
+    PIXEL13_61
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_30
+    PIXEL23_61
+    PIXEL30_80
+    PIXEL31_10
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag29
+    AUXADDRESS
+    PIXEL00_82
+    PIXEL01_82
+    PIXEL02_81
+    PIXEL03_81
+    PIXEL10_32
+    PIXEL11_32
+    PIXEL12_31
+    PIXEL13_31
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_80
+    PIXEL31_61
+    PIXEL32_61
+    PIXEL33_80
+    jmp .loopx_end
+..@flag198
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    PIXEL02_32
+    PIXEL03_82
+    PIXEL10_61
+    PIXEL11_30
+    PIXEL12_32
+    PIXEL13_82
+    PIXEL20_61
+    PIXEL21_30
+    PIXEL22_31
+    PIXEL23_81
+    PIXEL30_80
+    PIXEL31_10
+    PIXEL32_31
+    PIXEL33_81
+    jmp .loopx_end
+..@flag184
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_61
+    PIXEL02_61
+    PIXEL03_80
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL20_31
+    PIXEL21_31
+    PIXEL22_32
+    PIXEL23_32
+    PIXEL30_81
+    PIXEL31_81
+    PIXEL32_82
+    PIXEL33_82
+    jmp .loopx_end
+..@flag99
+    AUXADDRESS
+    PIXEL00_81
+    PIXEL01_31
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL10_81
+    PIXEL11_31
+    PIXEL12_30
+    PIXEL13_61
+    PIXEL20_82
+    PIXEL21_32
+    PIXEL22_30
+    PIXEL23_61
+    PIXEL30_82
+    PIXEL31_32
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag57
+    AUXADDRESS
+    PIXEL00_82
+    PIXEL01_82
+    PIXEL02_61
+    PIXEL03_80
+    PIXEL10_32
+    PIXEL11_32
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL20_31
+    PIXEL21_31
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_81
+    PIXEL31_81
+    PIXEL32_61
+    PIXEL33_80
+    jmp .loopx_end
+..@flag71
+    AUXADDRESS
+    PIXEL00_81
+    PIXEL01_31
+    PIXEL02_32
+    PIXEL03_82
+    PIXEL10_81
+    PIXEL11_31
+    PIXEL12_32
+    PIXEL13_82
+    PIXEL20_61
+    PIXEL21_30
+    PIXEL22_30
+    PIXEL23_61
+    PIXEL30_80
+    PIXEL31_10
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag156
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_61
+    PIXEL02_81
+    PIXEL03_81
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_31
+    PIXEL13_31
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_32
+    PIXEL23_32
+    PIXEL30_80
+    PIXEL31_61
+    PIXEL32_82
+    PIXEL33_82
+    jmp .loopx_end
+..@flag226
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL10_61
+    PIXEL11_30
+    PIXEL12_30
+    PIXEL13_61
+    PIXEL20_82
+    PIXEL21_32
+    PIXEL22_31
+    PIXEL23_81
+    PIXEL30_82
+    PIXEL31_32
+    PIXEL32_31
+    PIXEL33_81
+    jmp .loopx_end
+..@flag60
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_61
+    PIXEL02_81
+    PIXEL03_81
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_31
+    PIXEL13_31
+    PIXEL20_31
+    PIXEL21_31
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_81
+    PIXEL31_81
+    PIXEL32_61
+    PIXEL33_80
+    jmp .loopx_end
+..@flag195
+    AUXADDRESS
+    PIXEL00_81
+    PIXEL01_31
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL10_81
+    PIXEL11_31
+    PIXEL12_30
+    PIXEL13_61
+    PIXEL20_61
+    PIXEL21_30
+    PIXEL22_31
+    PIXEL23_81
+    PIXEL30_80
+    PIXEL31_10
+    PIXEL32_31
+    PIXEL33_81
+    jmp .loopx_end
+..@flag102
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    PIXEL02_32
+    PIXEL03_82
+    PIXEL10_61
+    PIXEL11_30
+    PIXEL12_32
+    PIXEL13_82
+    PIXEL20_82
+    PIXEL21_32
+    PIXEL22_30
+    PIXEL23_61
+    PIXEL30_82
+    PIXEL31_32
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag153
+    AUXADDRESS
+    PIXEL00_82
+    PIXEL01_82
+    PIXEL02_61
+    PIXEL03_80
+    PIXEL10_32
+    PIXEL11_32
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_32
+    PIXEL23_32
+    PIXEL30_80
+    PIXEL31_61
+    PIXEL32_82
+    PIXEL33_82
+    jmp .loopx_end
+..@flag58
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0
+    DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12
+    PIXEL20_31
+    PIXEL21_31
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_81
+    PIXEL31_81
+    PIXEL32_61
+    PIXEL33_80
+    jmp .loopx_end
+..@flag83
+    AUXADDRESS
+    PIXEL00_81
+    PIXEL01_31
+    DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12
+    PIXEL10_81
+    PIXEL11_31
+    PIXEL20_61
+    PIXEL21_30
+    DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20
+    PIXEL30_80
+    PIXEL31_10
+    jmp .loopx_end
+..@flag92
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_61
+    PIXEL02_81
+    PIXEL03_81
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_31
+    PIXEL13_31
+    DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11
+    DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20
+    jmp .loopx_end
+..@flag202
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL12_30
+    PIXEL13_61
+    DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11
+    PIXEL22_31
+    PIXEL23_81
+    PIXEL32_31
+    PIXEL33_81
+    jmp .loopx_end
+..@flag78
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0
+    PIXEL02_32
+    PIXEL03_82
+    PIXEL12_32
+    PIXEL13_82
+    DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11
+    PIXEL22_30
+    PIXEL23_61
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag154
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0
+    DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_32
+    PIXEL23_32
+    PIXEL30_80
+    PIXEL31_61
+    PIXEL32_82
+    PIXEL33_82
+    jmp .loopx_end
+..@flag114
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12
+    PIXEL10_61
+    PIXEL11_30
+    PIXEL20_82
+    PIXEL21_32
+    DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20
+    PIXEL30_82
+    PIXEL31_32
+    jmp .loopx_end
+..@flag89
+    AUXADDRESS
+    PIXEL00_82
+    PIXEL01_82
+    PIXEL02_61
+    PIXEL03_80
+    PIXEL10_32
+    PIXEL11_32
+    PIXEL12_30
+    PIXEL13_10
+    DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11
+    DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20
+    jmp .loopx_end
+..@flag90
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0
+    DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12
+    DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11
+    DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20
+    jmp .loopx_end
+..@flag55
+..@flag23
+    AUXADDRESS
+    DiffOrNot w2,w6,PIXEL00_81,PIXEL01_31,PIXEL02_0,PIXEL03_0,PIXEL12_0,PIXEL13_0,PIXEL00_12,PIXEL01_14,PIXEL02_83,PIXEL03_50,PIXEL12_70,PIXEL13_21
+    PIXEL10_81
+    PIXEL11_31
+    PIXEL20_60
+    PIXEL21_70
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_20
+    PIXEL31_60
+    PIXEL32_61
+    PIXEL33_80
+    jmp .loopx_end
+..@flag182
+..@flag150
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL12_0,PIXEL13_0,PIXEL23_32,PIXEL33_82,PIXEL02_21,PIXEL03_50,PIXEL12_70,PIXEL13_83,PIXEL23_13,PIXEL33_11
+    PIXEL10_61
+    PIXEL11_30
+    PIXEL20_60
+    PIXEL21_70
+    PIXEL22_32
+    PIXEL30_20
+    PIXEL31_60
+    PIXEL32_82
+    jmp .loopx_end
+..@flag213
+..@flag212
+    AUXADDRESS
+    PIXEL00_20
+    PIXEL01_60
+    PIXEL02_81
+    DiffOrNot w6,w8,PIXEL03_81,PIXEL13_31,PIXEL22_0,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL03_12,PIXEL13_14,PIXEL22_70,PIXEL23_83,PIXEL32_21,PIXEL33_50
+    PIXEL10_60
+    PIXEL11_70
+    PIXEL12_31
+    PIXEL20_61
+    PIXEL21_30
+    PIXEL30_80
+    PIXEL31_10
+    jmp .loopx_end
+..@flag241
+..@flag240
+    AUXADDRESS
+    PIXEL00_20
+    PIXEL01_60
+    PIXEL02_61
+    PIXEL03_80
+    PIXEL10_60
+    PIXEL11_70
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL20_82
+    PIXEL21_32
+    DiffOrNot w6,w8,PIXEL22_0,PIXEL23_0,PIXEL30_82,PIXEL31_32,PIXEL32_0,PIXEL33_0,PIXEL22_70,PIXEL23_21,PIXEL30_11,PIXEL31_13,PIXEL32_83,PIXEL33_50
+    jmp .loopx_end
+..@flag236
+..@flag232
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_61
+    PIXEL02_60
+    PIXEL03_20
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_70
+    PIXEL13_60
+    DiffOrNot w8,w4,PIXEL20_0,PIXEL21_0,PIXEL30_0,PIXEL31_0,PIXEL32_31,PIXEL33_81,PIXEL20_21,PIXEL21_70,PIXEL30_50,PIXEL31_83,PIXEL32_14,PIXEL33_12
+    PIXEL22_31
+    PIXEL23_81
+    jmp .loopx_end
+..@flag109
+..@flag105
+    AUXADDRESS
+    DiffOrNot w8,w4,PIXEL00_82,PIXEL10_32,PIXEL20_0,PIXEL21_0,PIXEL30_0,PIXEL31_0,PIXEL00_11,PIXEL10_13,PIXEL20_83,PIXEL21_70,PIXEL30_50,PIXEL31_21
+    PIXEL01_82
+    PIXEL02_60
+    PIXEL03_20
+    PIXEL11_32
+    PIXEL12_70
+    PIXEL13_60
+    PIXEL22_30
+    PIXEL23_61
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag171
+..@flag43
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL11_0,PIXEL20_31,PIXEL30_81,PIXEL00_50,PIXEL01_21,PIXEL10_83,PIXEL11_70,PIXEL20_14,PIXEL30_12
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL12_30
+    PIXEL13_61
+    PIXEL21_31
+    PIXEL22_70
+    PIXEL23_60
+    PIXEL31_81
+    PIXEL32_60
+    PIXEL33_20
+    jmp .loopx_end
+..@flag143
+..@flag15
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL02_32,PIXEL03_82,PIXEL10_0,PIXEL11_0,PIXEL00_50,PIXEL01_83,PIXEL02_13,PIXEL03_11,PIXEL10_21,PIXEL11_70
+    PIXEL12_32
+    PIXEL13_82
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_70
+    PIXEL23_60
+    PIXEL30_80
+    PIXEL31_61
+    PIXEL32_60
+    PIXEL33_20
+    jmp .loopx_end
+..@flag124
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_61
+    PIXEL02_81
+    PIXEL03_81
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_31
+    PIXEL13_31
+    DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50
+    PIXEL21_0
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag203
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL11_0
+    PIXEL12_30
+    PIXEL13_61
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_31
+    PIXEL23_81
+    PIXEL30_80
+    PIXEL31_10
+    PIXEL32_31
+    PIXEL33_81
+    jmp .loopx_end
+..@flag62
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_0
+    PIXEL20_31
+    PIXEL21_31
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_81
+    PIXEL31_81
+    PIXEL32_61
+    PIXEL33_80
+    jmp .loopx_end
+..@flag211
+    AUXADDRESS
+    PIXEL00_81
+    PIXEL01_31
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL10_81
+    PIXEL11_31
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL20_61
+    PIXEL21_30
+    PIXEL22_0
+    DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50
+    PIXEL30_80
+    PIXEL31_10
+    jmp .loopx_end
+..@flag118
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50
+    PIXEL10_61
+    PIXEL11_30
+    PIXEL12_0
+    PIXEL20_82
+    PIXEL21_32
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_82
+    PIXEL31_32
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag217
+    AUXADDRESS
+    PIXEL00_82
+    PIXEL01_82
+    PIXEL02_61
+    PIXEL03_80
+    PIXEL10_32
+    PIXEL11_32
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_0
+    DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50
+    PIXEL30_80
+    PIXEL31_10
+    jmp .loopx_end
+..@flag110
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    PIXEL02_32
+    PIXEL03_82
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_32
+    PIXEL13_82
+    DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50
+    PIXEL21_0
+    PIXEL22_30
+    PIXEL23_61
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag155
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL11_0
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_32
+    PIXEL23_32
+    PIXEL30_80
+    PIXEL31_61
+    PIXEL32_82
+    PIXEL33_82
+    jmp .loopx_end
+..@flag188
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_61
+    PIXEL02_81
+    PIXEL03_81
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_31
+    PIXEL13_31
+    PIXEL20_31
+    PIXEL21_31
+    PIXEL22_32
+    PIXEL23_32
+    PIXEL30_81
+    PIXEL31_81
+    PIXEL32_82
+    PIXEL33_82
+    jmp .loopx_end
+..@flag185
+    AUXADDRESS
+    PIXEL00_82
+    PIXEL01_82
+    PIXEL02_61
+    PIXEL03_80
+    PIXEL10_32
+    PIXEL11_32
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL20_31
+    PIXEL21_31
+    PIXEL22_32
+    PIXEL23_32
+    PIXEL30_81
+    PIXEL31_81
+    PIXEL32_82
+    PIXEL33_82
+    jmp .loopx_end
+..@flag61
+    AUXADDRESS
+    PIXEL00_82
+    PIXEL01_82
+    PIXEL02_81
+    PIXEL03_81
+    PIXEL10_32
+    PIXEL11_32
+    PIXEL12_31
+    PIXEL13_31
+    PIXEL20_31
+    PIXEL21_31
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_81
+    PIXEL31_81
+    PIXEL32_61
+    PIXEL33_80
+    jmp .loopx_end
+..@flag157
+    AUXADDRESS
+    PIXEL00_82
+    PIXEL01_82
+    PIXEL02_81
+    PIXEL03_81
+    PIXEL10_32
+    PIXEL11_32
+    PIXEL12_31
+    PIXEL13_31
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_32
+    PIXEL23_32
+    PIXEL30_80
+    PIXEL31_61
+    PIXEL32_82
+    PIXEL33_82
+    jmp .loopx_end
+..@flag103
+    AUXADDRESS
+    PIXEL00_81
+    PIXEL01_31
+    PIXEL02_32
+    PIXEL03_82
+    PIXEL10_81
+    PIXEL11_31
+    PIXEL12_32
+    PIXEL13_82
+    PIXEL20_82
+    PIXEL21_32
+    PIXEL22_30
+    PIXEL23_61
+    PIXEL30_82
+    PIXEL31_32
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag227
+    AUXADDRESS
+    PIXEL00_81
+    PIXEL01_31
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL10_81
+    PIXEL11_31
+    PIXEL12_30
+    PIXEL13_61
+    PIXEL20_82
+    PIXEL21_32
+    PIXEL22_31
+    PIXEL23_81
+    PIXEL30_82
+    PIXEL31_32
+    PIXEL32_31
+    PIXEL33_81
+    jmp .loopx_end
+..@flag230
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    PIXEL02_32
+    PIXEL03_82
+    PIXEL10_61
+    PIXEL11_30
+    PIXEL12_32
+    PIXEL13_82
+    PIXEL20_82
+    PIXEL21_32
+    PIXEL22_31
+    PIXEL23_81
+    PIXEL30_82
+    PIXEL31_32
+    PIXEL32_31
+    PIXEL33_81
+    jmp .loopx_end
+..@flag199
+    AUXADDRESS
+    PIXEL00_81
+    PIXEL01_31
+    PIXEL02_32
+    PIXEL03_82
+    PIXEL10_81
+    PIXEL11_31
+    PIXEL12_32
+    PIXEL13_82
+    PIXEL20_61
+    PIXEL21_30
+    PIXEL22_31
+    PIXEL23_81
+    PIXEL30_80
+    PIXEL31_10
+    PIXEL32_31
+    PIXEL33_81
+    jmp .loopx_end
+..@flag220
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_61
+    PIXEL02_81
+    PIXEL03_81
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_31
+    PIXEL13_31
+    DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11
+    PIXEL22_0
+    DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50
+    jmp .loopx_end
+..@flag158
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0
+    DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50
+    PIXEL12_0
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_32
+    PIXEL23_32
+    PIXEL30_80
+    PIXEL31_61
+    PIXEL32_82
+    PIXEL33_82
+    jmp .loopx_end
+..@flag234
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL12_30
+    PIXEL13_61
+    DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50
+    PIXEL21_0
+    PIXEL22_31
+    PIXEL23_81
+    PIXEL32_31
+    PIXEL33_81
+    jmp .loopx_end
+..@flag242
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12
+    PIXEL10_61
+    PIXEL11_30
+    PIXEL20_82
+    PIXEL21_32
+    PIXEL22_0
+    DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50
+    PIXEL30_82
+    PIXEL31_32
+    jmp .loopx_end
+..@flag59
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50
+    DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12
+    PIXEL11_0
+    PIXEL20_31
+    PIXEL21_31
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_81
+    PIXEL31_81
+    PIXEL32_61
+    PIXEL33_80
+    jmp .loopx_end
+..@flag121
+    AUXADDRESS
+    PIXEL00_82
+    PIXEL01_82
+    PIXEL02_61
+    PIXEL03_80
+    PIXEL10_32
+    PIXEL11_32
+    PIXEL12_30
+    PIXEL13_10
+    DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50
+    PIXEL21_0
+    DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20
+    jmp .loopx_end
+..@flag87
+    AUXADDRESS
+    PIXEL00_81
+    PIXEL01_31
+    DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50
+    PIXEL10_81
+    PIXEL11_31
+    PIXEL12_0
+    PIXEL20_61
+    PIXEL21_30
+    DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20
+    PIXEL30_80
+    PIXEL31_10
+    jmp .loopx_end
+..@flag79
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50
+    PIXEL02_32
+    PIXEL03_82
+    PIXEL11_0
+    PIXEL12_32
+    PIXEL13_82
+    DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11
+    PIXEL22_30
+    PIXEL23_61
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag122
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0
+    DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12
+    DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50
+    PIXEL21_0
+    DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20
+    jmp .loopx_end
+..@flag94
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0
+    DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50
+    PIXEL12_0
+    DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11
+    DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20
+    jmp .loopx_end
+..@flag218
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0
+    DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12
+    DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11
+    PIXEL22_0
+    DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50
+    jmp .loopx_end
+..@flag91
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50
+    DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12
+    PIXEL11_0
+    DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11
+    DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20
+    jmp .loopx_end
+..@flag229
+    AUXADDRESS
+    PIXEL00_20
+    PIXEL01_60
+    PIXEL02_60
+    PIXEL03_20
+    PIXEL10_60
+    PIXEL11_70
+    PIXEL12_70
+    PIXEL13_60
+    PIXEL20_82
+    PIXEL21_32
+    PIXEL22_31
+    PIXEL23_81
+    PIXEL30_82
+    PIXEL31_32
+    PIXEL32_31
+    PIXEL33_81
+    jmp .loopx_end
+..@flag167
+    AUXADDRESS
+    PIXEL00_81
+    PIXEL01_31
+    PIXEL02_32
+    PIXEL03_82
+    PIXEL10_81
+    PIXEL11_31
+    PIXEL12_32
+    PIXEL13_82
+    PIXEL20_60
+    PIXEL21_70
+    PIXEL22_70
+    PIXEL23_60
+    PIXEL30_20
+    PIXEL31_60
+    PIXEL32_60
+    PIXEL33_20
+    jmp .loopx_end
+..@flag173
+    AUXADDRESS
+    PIXEL00_82
+    PIXEL01_82
+    PIXEL02_60
+    PIXEL03_20
+    PIXEL10_32
+    PIXEL11_32
+    PIXEL12_70
+    PIXEL13_60
+    PIXEL20_31
+    PIXEL21_31
+    PIXEL22_70
+    PIXEL23_60
+    PIXEL30_81
+    PIXEL31_81
+    PIXEL32_60
+    PIXEL33_20
+    jmp .loopx_end
+..@flag181
+    AUXADDRESS
+    PIXEL00_20
+    PIXEL01_60
+    PIXEL02_81
+    PIXEL03_81
+    PIXEL10_60
+    PIXEL11_70
+    PIXEL12_31
+    PIXEL13_31
+    PIXEL20_60
+    PIXEL21_70
+    PIXEL22_32
+    PIXEL23_32
+    PIXEL30_20
+    PIXEL31_60
+    PIXEL32_82
+    PIXEL33_82
+    jmp .loopx_end
+..@flag186
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0
+    DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12
+    PIXEL20_31
+    PIXEL21_31
+    PIXEL22_32
+    PIXEL23_32
+    PIXEL30_81
+    PIXEL31_81
+    PIXEL32_82
+    PIXEL33_82
+    jmp .loopx_end
+..@flag115
+    AUXADDRESS
+    PIXEL00_81
+    PIXEL01_31
+    DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12
+    PIXEL10_81
+    PIXEL11_31
+    PIXEL20_82
+    PIXEL21_32
+    DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20
+    PIXEL30_82
+    PIXEL31_32
+    jmp .loopx_end
+..@flag93
+    AUXADDRESS
+    PIXEL00_82
+    PIXEL01_82
+    PIXEL02_81
+    PIXEL03_81
+    PIXEL10_32
+    PIXEL11_32
+    PIXEL12_31
+    PIXEL13_31
+    DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11
+    DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20
+    jmp .loopx_end
+..@flag206
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0
+    PIXEL02_32
+    PIXEL03_82
+    PIXEL12_32
+    PIXEL13_82
+    DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11
+    PIXEL22_31
+    PIXEL23_81
+    PIXEL32_31
+    PIXEL33_81
+    jmp .loopx_end
+..@flag205
+..@flag201
+    AUXADDRESS
+    PIXEL00_82
+    PIXEL01_82
+    PIXEL02_60
+    PIXEL03_20
+    PIXEL10_32
+    PIXEL11_32
+    PIXEL12_70
+    PIXEL13_60
+    DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11
+    PIXEL22_31
+    PIXEL23_81
+    PIXEL32_31
+    PIXEL33_81
+    jmp .loopx_end
+..@flag174
+..@flag46
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0
+    PIXEL02_32
+    PIXEL03_82
+    PIXEL12_32
+    PIXEL13_82
+    PIXEL20_31
+    PIXEL21_31
+    PIXEL22_70
+    PIXEL23_60
+    PIXEL30_81
+    PIXEL31_81
+    PIXEL32_60
+    PIXEL33_20
+    jmp .loopx_end
+..@flag179
+..@flag147
+    AUXADDRESS
+    PIXEL00_81
+    PIXEL01_31
+    DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12
+    PIXEL10_81
+    PIXEL11_31
+    PIXEL20_60
+    PIXEL21_70
+    PIXEL22_32
+    PIXEL23_32
+    PIXEL30_20
+    PIXEL31_60
+    PIXEL32_82
+    PIXEL33_82
+    jmp .loopx_end
+..@flag117
+..@flag116
+    AUXADDRESS
+    PIXEL00_20
+    PIXEL01_60
+    PIXEL02_81
+    PIXEL03_81
+    PIXEL10_60
+    PIXEL11_70
+    PIXEL12_31
+    PIXEL13_31
+    PIXEL20_82
+    PIXEL21_32
+    DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20
+    PIXEL30_82
+    PIXEL31_32
+    jmp .loopx_end
+..@flag189
+    AUXADDRESS
+    PIXEL00_82
+    PIXEL01_82
+    PIXEL02_81
+    PIXEL03_81
+    PIXEL10_32
+    PIXEL11_32
+    PIXEL12_31
+    PIXEL13_31
+    PIXEL20_31
+    PIXEL21_31
+    PIXEL22_32
+    PIXEL23_32
+    PIXEL30_81
+    PIXEL31_81
+    PIXEL32_82
+    PIXEL33_82
+    jmp .loopx_end
+..@flag231
+    AUXADDRESS
+    PIXEL00_81
+    PIXEL01_31
+    PIXEL02_32
+    PIXEL03_82
+    PIXEL10_81
+    PIXEL11_31
+    PIXEL12_32
+    PIXEL13_82
+    PIXEL20_82
+    PIXEL21_32
+    PIXEL22_31
+    PIXEL23_81
+    PIXEL30_82
+    PIXEL31_32
+    PIXEL32_31
+    PIXEL33_81
+    jmp .loopx_end
+..@flag126
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_0
+    DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50
+    PIXEL21_0
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag219
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL11_0
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_0
+    DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50
+    PIXEL30_80
+    PIXEL31_10
+    jmp .loopx_end
+..@flag125
+    AUXADDRESS
+    DiffOrNot w8,w4,PIXEL00_82,PIXEL10_32,PIXEL20_0,PIXEL21_0,PIXEL30_0,PIXEL31_0,PIXEL00_11,PIXEL10_13,PIXEL20_83,PIXEL21_70,PIXEL30_50,PIXEL31_21
+    PIXEL01_82
+    PIXEL02_81
+    PIXEL03_81
+    PIXEL11_32
+    PIXEL12_31
+    PIXEL13_31
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag221
+    AUXADDRESS
+    PIXEL00_82
+    PIXEL01_82
+    PIXEL02_81
+    DiffOrNot w6,w8,PIXEL03_81,PIXEL13_31,PIXEL22_0,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL03_12,PIXEL13_14,PIXEL22_70,PIXEL23_83,PIXEL32_21,PIXEL33_50
+    PIXEL10_32
+    PIXEL11_32
+    PIXEL12_31
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL30_80
+    PIXEL31_10
+    jmp .loopx_end
+..@flag207
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL02_32,PIXEL03_82,PIXEL10_0,PIXEL11_0,PIXEL00_50,PIXEL01_83,PIXEL02_13,PIXEL03_11,PIXEL10_21,PIXEL11_70
+    PIXEL12_32
+    PIXEL13_82
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_31
+    PIXEL23_81
+    PIXEL30_80
+    PIXEL31_10
+    PIXEL32_31
+    PIXEL33_81
+    jmp .loopx_end
+..@flag238
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    PIXEL02_32
+    PIXEL03_82
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_32
+    PIXEL13_82
+    DiffOrNot w8,w4,PIXEL20_0,PIXEL21_0,PIXEL30_0,PIXEL31_0,PIXEL32_31,PIXEL33_81,PIXEL20_21,PIXEL21_70,PIXEL30_50,PIXEL31_83,PIXEL32_14,PIXEL33_12
+    PIXEL22_31
+    PIXEL23_81
+    jmp .loopx_end
+..@flag190
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL12_0,PIXEL13_0,PIXEL23_32,PIXEL33_82,PIXEL02_21,PIXEL03_50,PIXEL12_70,PIXEL13_83,PIXEL23_13,PIXEL33_11
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL20_31
+    PIXEL21_31
+    PIXEL22_32
+    PIXEL30_81
+    PIXEL31_81
+    PIXEL32_82
+    jmp .loopx_end
+..@flag187
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL11_0,PIXEL20_31,PIXEL30_81,PIXEL00_50,PIXEL01_21,PIXEL10_83,PIXEL11_70,PIXEL20_14,PIXEL30_12
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL21_31
+    PIXEL22_32
+    PIXEL23_32
+    PIXEL31_81
+    PIXEL32_82
+    PIXEL33_82
+    jmp .loopx_end
+..@flag243
+    AUXADDRESS
+    PIXEL00_81
+    PIXEL01_31
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL10_81
+    PIXEL11_31
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL20_82
+    PIXEL21_32
+    DiffOrNot w6,w8,PIXEL22_0,PIXEL23_0,PIXEL30_82,PIXEL31_32,PIXEL32_0,PIXEL33_0,PIXEL22_70,PIXEL23_21,PIXEL30_11,PIXEL31_13,PIXEL32_83,PIXEL33_50
+    jmp .loopx_end
+..@flag119
+    AUXADDRESS
+    DiffOrNot w2,w6,PIXEL00_81,PIXEL01_31,PIXEL02_0,PIXEL03_0,PIXEL12_0,PIXEL13_0,PIXEL00_12,PIXEL01_14,PIXEL02_83,PIXEL03_50,PIXEL12_70,PIXEL13_21
+    PIXEL10_81
+    PIXEL11_31
+    PIXEL20_82
+    PIXEL21_32
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_82
+    PIXEL31_32
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag237
+..@flag233
+    AUXADDRESS
+    PIXEL00_82
+    PIXEL01_82
+    PIXEL02_60
+    PIXEL03_20
+    PIXEL10_32
+    PIXEL11_32
+    PIXEL12_70
+    PIXEL13_60
+    PIXEL20_0
+    PIXEL21_0
+    PIXEL22_31
+    PIXEL23_81
+    DiffOrNot w8,w4,PIXEL30_0,PIXEL30_20
+    PIXEL31_0
+    PIXEL32_31
+    PIXEL33_81
+    jmp .loopx_end
+..@flag175
+..@flag47
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20
+    PIXEL01_0
+    PIXEL02_32
+    PIXEL03_82
+    PIXEL10_0
+    PIXEL11_0
+    PIXEL12_32
+    PIXEL13_82
+    PIXEL20_31
+    PIXEL21_31
+    PIXEL22_70
+    PIXEL23_60
+    PIXEL30_81
+    PIXEL31_81
+    PIXEL32_60
+    PIXEL33_20
+    jmp .loopx_end
+..@flag183
+..@flag151
+    AUXADDRESS
+    PIXEL00_81
+    PIXEL01_31
+    PIXEL02_0
+    DiffOrNot w2,w6,PIXEL03_0,PIXEL03_20
+    PIXEL10_81
+    PIXEL11_31
+    PIXEL12_0
+    PIXEL13_0
+    PIXEL20_60
+    PIXEL21_70
+    PIXEL22_32
+    PIXEL23_32
+    PIXEL30_20
+    PIXEL31_60
+    PIXEL32_82
+    PIXEL33_82
+    jmp .loopx_end
+..@flag245
+..@flag244
+    AUXADDRESS
+    PIXEL00_20
+    PIXEL01_60
+    PIXEL02_81
+    PIXEL03_81
+    PIXEL10_60
+    PIXEL11_70
+    PIXEL12_31
+    PIXEL13_31
+    PIXEL20_82
+    PIXEL21_32
+    PIXEL22_0
+    PIXEL23_0
+    PIXEL30_82
+    PIXEL31_32
+    PIXEL32_0
+    DiffOrNot w6,w8,PIXEL33_0,PIXEL33_20
+    jmp .loopx_end
+..@flag250
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_30
+    PIXEL13_10
+    DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50
+    PIXEL21_0
+    PIXEL22_0
+    DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50
+    jmp .loopx_end
+..@flag123
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL11_0
+    PIXEL12_30
+    PIXEL13_10
+    DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50
+    PIXEL21_0
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag95
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50
+    DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50
+    PIXEL11_0
+    PIXEL12_0
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_80
+    PIXEL31_10
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag222
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_0
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_0
+    DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50
+    PIXEL30_80
+    PIXEL31_10
+    jmp .loopx_end
+..@flag252
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_61
+    PIXEL02_81
+    PIXEL03_81
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_31
+    PIXEL13_31
+    DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50
+    PIXEL21_0
+    PIXEL22_0
+    PIXEL23_0
+    PIXEL32_0
+    DiffOrNot w6,w8,PIXEL33_0,PIXEL33_20
+    jmp .loopx_end
+..@flag249
+    AUXADDRESS
+    PIXEL00_82
+    PIXEL01_82
+    PIXEL02_61
+    PIXEL03_80
+    PIXEL10_32
+    PIXEL11_32
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL20_0
+    PIXEL21_0
+    PIXEL22_0
+    DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50
+    DiffOrNot w8,w4,PIXEL30_0,PIXEL30_20
+    PIXEL31_0
+    jmp .loopx_end
+..@flag235
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL11_0
+    PIXEL12_30
+    PIXEL13_61
+    PIXEL20_0
+    PIXEL21_0
+    PIXEL22_31
+    PIXEL23_81
+    DiffOrNot w8,w4,PIXEL30_0,PIXEL30_20
+    PIXEL31_0
+    PIXEL32_31
+    PIXEL33_81
+    jmp .loopx_end
+..@flag111
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20
+    PIXEL01_0
+    PIXEL02_32
+    PIXEL03_82
+    PIXEL10_0
+    PIXEL11_0
+    PIXEL12_32
+    PIXEL13_82
+    DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50
+    PIXEL21_0
+    PIXEL22_30
+    PIXEL23_61
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag63
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20
+    PIXEL01_0
+    DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50
+    PIXEL10_0
+    PIXEL11_0
+    PIXEL12_0
+    PIXEL20_31
+    PIXEL21_31
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL30_81
+    PIXEL31_81
+    PIXEL32_61
+    PIXEL33_80
+    jmp .loopx_end
+..@flag159
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50
+    PIXEL02_0
+    DiffOrNot w2,w6,PIXEL03_0,PIXEL03_20
+    PIXEL11_0
+    PIXEL12_0
+    PIXEL13_0
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_32
+    PIXEL23_32
+    PIXEL30_80
+    PIXEL31_61
+    PIXEL32_82
+    PIXEL33_82
+    jmp .loopx_end
+..@flag215
+    AUXADDRESS
+    PIXEL00_81
+    PIXEL01_31
+    PIXEL02_0
+    DiffOrNot w2,w6,PIXEL03_0,PIXEL03_20
+    PIXEL10_81
+    PIXEL11_31
+    PIXEL12_0
+    PIXEL13_0
+    PIXEL20_61
+    PIXEL21_30
+    PIXEL22_0
+    DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50
+    PIXEL30_80
+    PIXEL31_10
+    jmp .loopx_end
+..@flag246
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50
+    PIXEL10_61
+    PIXEL11_30
+    PIXEL12_0
+    PIXEL20_82
+    PIXEL21_32
+    PIXEL22_0
+    PIXEL23_0
+    PIXEL30_82
+    PIXEL31_32
+    PIXEL32_0
+    DiffOrNot w6,w8,PIXEL33_0,PIXEL33_20
+    jmp .loopx_end
+..@flag254
+    AUXADDRESS
+    PIXEL00_80
+    PIXEL01_10
+    DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50
+    PIXEL10_10
+    PIXEL11_30
+    PIXEL12_0
+    DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50
+    PIXEL21_0
+    PIXEL22_0
+    PIXEL23_0
+    PIXEL32_0
+    DiffOrNot w6,w8,PIXEL33_0,PIXEL33_20
+    jmp .loopx_end
+..@flag253
+    AUXADDRESS
+    PIXEL00_82
+    PIXEL01_82
+    PIXEL02_81
+    PIXEL03_81
+    PIXEL10_32
+    PIXEL11_32
+    PIXEL12_31
+    PIXEL13_31
+    PIXEL20_0
+    PIXEL21_0
+    PIXEL22_0
+    PIXEL23_0
+    DiffOrNot w8,w4,PIXEL30_0,PIXEL30_20
+    PIXEL31_0
+    PIXEL32_0
+    DiffOrNot w6,w8,PIXEL33_0,PIXEL33_20
+    jmp .loopx_end
+..@flag251
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50
+    PIXEL02_10
+    PIXEL03_80
+    PIXEL11_0
+    PIXEL12_30
+    PIXEL13_10
+    PIXEL20_0
+    PIXEL21_0
+    PIXEL22_0
+    DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50
+    DiffOrNot w8,w4,PIXEL30_0,PIXEL30_20
+    PIXEL31_0
+    jmp .loopx_end
+..@flag239
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20
+    PIXEL01_0
+    PIXEL02_32
+    PIXEL03_82
+    PIXEL10_0
+    PIXEL11_0
+    PIXEL12_32
+    PIXEL13_82
+    PIXEL20_0
+    PIXEL21_0
+    PIXEL22_31
+    PIXEL23_81
+    DiffOrNot w8,w4,PIXEL30_0,PIXEL30_20
+    PIXEL31_0
+    PIXEL32_31
+    PIXEL33_81
+    jmp .loopx_end
+..@flag127
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20
+    PIXEL01_0
+    DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50
+    PIXEL10_0
+    PIXEL11_0
+    PIXEL12_0
+    DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50
+    PIXEL21_0
+    PIXEL22_30
+    PIXEL23_10
+    PIXEL32_10
+    PIXEL33_80
+    jmp .loopx_end
+..@flag191
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20
+    PIXEL01_0
+    PIXEL02_0
+    DiffOrNot w2,w6,PIXEL03_0,PIXEL03_20
+    PIXEL10_0
+    PIXEL11_0
+    PIXEL12_0
+    PIXEL13_0
+    PIXEL20_31
+    PIXEL21_31
+    PIXEL22_32
+    PIXEL23_32
+    PIXEL30_81
+    PIXEL31_81
+    PIXEL32_82
+    PIXEL33_82
+    jmp .loopx_end
+..@flag223
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50
+    PIXEL02_0
+    DiffOrNot w2,w6,PIXEL03_0,PIXEL03_20
+    PIXEL11_0
+    PIXEL12_0
+    PIXEL13_0
+    PIXEL20_10
+    PIXEL21_30
+    PIXEL22_0
+    DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50
+    PIXEL30_80
+    PIXEL31_10
+    jmp .loopx_end
+..@flag247
+    AUXADDRESS
+    PIXEL00_81
+    PIXEL01_31
+    PIXEL02_0
+    DiffOrNot w2,w6,PIXEL03_0,PIXEL03_20
+    PIXEL10_81
+    PIXEL11_31
+    PIXEL12_0
+    PIXEL13_0
+    PIXEL20_82
+    PIXEL21_32
+    PIXEL22_0
+    PIXEL23_0
+    PIXEL30_82
+    PIXEL31_32
+    PIXEL32_0
+    DiffOrNot w6,w8,PIXEL33_0,PIXEL33_20
+    jmp .loopx_end
+..@flag255
+    AUXADDRESS
+    DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20
+    PIXEL01_0
+    PIXEL02_0
+    DiffOrNot w2,w6,PIXEL03_0,PIXEL03_20
+    PIXEL10_0
+    PIXEL11_0
+    PIXEL12_0
+    PIXEL13_0
+    PIXEL20_0
+    PIXEL21_0
+    PIXEL22_0
+    PIXEL23_0
+    DiffOrNot w8,w4,PIXEL30_0,PIXEL30_20
+    PIXEL31_0
+    PIXEL32_0
+    DiffOrNot w6,w8,PIXEL33_0,PIXEL33_20
+    jmp .loopx_end
+
+
+..@cross0
+    mov     ebx,[ebp+dstpitch]
+    AUXADDRESS
+    mov     [edi],eax
+    mov     [edi+4],eax
+    mov     [edi+8],eax
+    mov     [edi+12],eax
+    mov     [edi+ebx],eax
+    mov     [edi+ebx+4],eax
+    mov     [edi+ebx+8],eax
+    mov     [edi+ebx+12],eax
+    mov     [ecx],eax
+    mov     [ecx+4],eax
+    mov     [ecx+8],eax
+    mov     [ecx+12],eax
+    mov     [ecx+ebx],eax
+    mov     [ecx+ebx+4],eax
+    mov     [ecx+ebx+8],eax
+    mov     [ecx+ebx+12],eax
+    jmp     .loopx_end
+..@cross1
+    mov     ecx,[w2] 
+    mov     edx,eax
+    shl     edx,2
+    add     edx,[ebx+ecx*4]
+    sub     edx,eax
+    shr     edx,2
+    mov     [edi],edx
+    mov     [edi+4],edx
+    mov     [edi+8],edx
+    mov     [edi+12],edx
+    mov     ebx,[ebp+dstpitch]
+    AUXADDRESS
+    mov     [edi],edx
+    mov     [edi+4],edx
+    mov     [edi+ebx],eax
+    mov     [edi+ebx+4],eax
+    jmp     .loopx_end
+..@cross2
+    mov     ecx,[w4]
+    mov     edx,eax
+    shl     edx,2
+    add     edx,[ebx+ecx*4]
+    sub     edx,eax
+    shr     edx,2
+    mov     ebx,[ebp+dstpitch]
+    mov     [edi],edx
+    mov     [edi+4],eax
+    mov     [edi+ebx],edx
+    mov     [edi+ebx+4],eax
+    jmp     .loopx_end
+..@cross4
+    mov     ecx,[w6]
+    mov     edx,eax
+    shl     edx,2
+    add     edx,[ebx+ecx*4]
+    sub     edx,eax
+    shr     edx,2
+    mov     ebx,[ebp+dstpitch]
+    mov     [edi],eax
+    mov     [edi+4],edx
+    mov     [edi+ebx],eax
+    mov     [edi+ebx+4],edx
+    jmp     .loopx_end
+..@cross8
+    mov     ecx,[w8]
+    mov     edx,eax
+    shl     edx,2
+    add     edx,[ebx+ecx*4]
+    sub     edx,eax
+    shr     edx,2
+    mov     ebx,[ebp+dstpitch]
+    mov     [edi],eax
+    mov     [edi+4],eax
+    mov     [edi+ebx],edx
+    mov     [edi+ebx+4],edx
+    jmp     .loopx_end
+..@crossN
+    mov     edx,[w2]
+    mov     ecx,[ebx+edx*4]
+    mov     [c2],ecx
+    mov     edx,[w4]
+    mov     ecx,[ebx+edx*4]
+    mov     [c4],ecx
+    mov     edx,[w6]
+    mov     ecx,[ebx+edx*4]
+    mov     [c6],ecx
+    mov     edx,[w8]
+    mov     ecx,[ebx+edx*4]
+    mov     [c8],ecx
+    mov     ebx,[ebp+dstpitch]
+    jmp     ..@flag0
+
+.loopx_end
+    add     esi,2
+    add     edi,16
+    dec     dword[xcounter]
+    jle     .xres_2
+    jmp     .loopx
+.xres_2
+    ; x=Xres-2 - special case
+    jl      .xres_1
+    mov     ebx,[prevline]
+    movq    mm5,[esi+ebx-4]
+    movq    mm6,[esi-4]
+    mov     ebx,[nextline]
+    movq    mm7,[esi+ebx-4]
+    psrlq   mm5,16
+    psrlq   mm6,16
+    psrlq   mm7,16
+    movd    eax,mm5
+    movzx   edx,ax
+    mov     [w1],edx
+    shr     eax,16
+    mov     [w2],eax
+    psrlq   mm5,32
+    movd    eax,mm5
+    mov     [w3],eax
+    movd    eax,mm6
+    movzx   edx,ax
+    mov     [w4],edx
+    shr     eax,16
+    mov     [w5],eax
+    psrlq   mm6,32
+    movd    eax,mm6
+    mov     [w6],eax
+    movd    eax,mm7
+    movzx   edx,ax
+    mov     [w7],edx
+    shr     eax,16
+    mov     [w8],eax
+    psrlq   mm7,32
+    movd    eax,mm7
+    mov     [w9],eax
+    jmp     .flags
+.xres_1
+    cmp     dword[xcounter],-1
+    jl      .nexty
+    ; x=Xres-1 - special case
+    mov     ebx,[prevline]
+    movq    mm5,[esi+ebx-6]
+    movq    mm6,[esi-6]
+    mov     ebx,[nextline]
+    movq    mm7,[esi+ebx-6]
+    psrlq   mm5,32
+    psrlq   mm6,32
+    psrlq   mm7,32
+    movd    eax,mm5
+    movzx   edx,ax  
+    mov     [w1],edx
+    shr     eax,16
+    mov     [w2],eax
+    mov     [w3],eax
+    movd    eax,mm6
+    movzx   edx,ax  
+    mov     [w4],edx
+    shr     eax,16
+    mov     [w5],eax
+    mov     [w6],eax
+    movd    eax,mm7
+    movzx   edx,ax  
+    mov     [w7],edx
+    shr     eax,16
+    mov     [w8],eax
+    mov     [w9],eax
+    jmp     .flags
+.nexty
+    add     edi,ebx
+    add     edi,ebx
+    add     edi,ebx
+    add     esi,[ebp+srcpitch]
+    dec     dword[linesleft]
+    jz      .fin
+    mov     ebx,[ebp+Xres]
+    shl     ebx,1
+    cmp     dword[linesleft],1
+    je      .lastline
+    mov     dword[nextline],ebx
+    neg     ebx
+    mov     dword[prevline],ebx
+    jmp     .loopy
+.lastline
+    mov     dword[nextline],0
+    neg     ebx
+    mov     dword[prevline],ebx
+    jmp     .loopy
+.fin
+    emms
+    popad
+    mov esp,ebp
+    pop ebp
+    ret
+
+SECTION .data
+FuncTable
+    dd ..@flag0, ..@flag1, ..@flag2, ..@flag3, ..@flag4, ..@flag5, ..@flag6, ..@flag7
+    dd ..@flag8, ..@flag9, ..@flag10, ..@flag11, ..@flag12, ..@flag13, ..@flag14, ..@flag15
+    dd ..@flag16, ..@flag17, ..@flag18, ..@flag19, ..@flag20, ..@flag21, ..@flag22, ..@flag23
+    dd ..@flag24, ..@flag25, ..@flag26, ..@flag27, ..@flag28, ..@flag29, ..@flag30, ..@flag31
+    dd ..@flag32, ..@flag33, ..@flag34, ..@flag35, ..@flag36, ..@flag37, ..@flag38, ..@flag39
+    dd ..@flag40, ..@flag41, ..@flag42, ..@flag43, ..@flag44, ..@flag45, ..@flag46, ..@flag47
+    dd ..@flag48, ..@flag49, ..@flag50, ..@flag51, ..@flag52, ..@flag53, ..@flag54, ..@flag55
+    dd ..@flag56, ..@flag57, ..@flag58, ..@flag59, ..@flag60, ..@flag61, ..@flag62, ..@flag63
+    dd ..@flag64, ..@flag65, ..@flag66, ..@flag67, ..@flag68, ..@flag69, ..@flag70, ..@flag71
+    dd ..@flag72, ..@flag73, ..@flag74, ..@flag75, ..@flag76, ..@flag77, ..@flag78, ..@flag79
+    dd ..@flag80, ..@flag81, ..@flag82, ..@flag83, ..@flag84, ..@flag85, ..@flag86, ..@flag87
+    dd ..@flag88, ..@flag89, ..@flag90, ..@flag91, ..@flag92, ..@flag93, ..@flag94, ..@flag95
+    dd ..@flag96, ..@flag97, ..@flag98, ..@flag99, ..@flag100, ..@flag101, ..@flag102, ..@flag103
+    dd ..@flag104, ..@flag105, ..@flag106, ..@flag107, ..@flag108, ..@flag109, ..@flag110, ..@flag111
+    dd ..@flag112, ..@flag113, ..@flag114, ..@flag115, ..@flag116, ..@flag117, ..@flag118, ..@flag119
+    dd ..@flag120, ..@flag121, ..@flag122, ..@flag123, ..@flag124, ..@flag125, ..@flag126, ..@flag127
+    dd ..@flag128, ..@flag129, ..@flag130, ..@flag131, ..@flag132, ..@flag133, ..@flag134, ..@flag135
+    dd ..@flag136, ..@flag137, ..@flag138, ..@flag139, ..@flag140, ..@flag141, ..@flag142, ..@flag143
+    dd ..@flag144, ..@flag145, ..@flag146, ..@flag147, ..@flag148, ..@flag149, ..@flag150, ..@flag151
+    dd ..@flag152, ..@flag153, ..@flag154, ..@flag155, ..@flag156, ..@flag157, ..@flag158, ..@flag159
+    dd ..@flag160, ..@flag161, ..@flag162, ..@flag163, ..@flag164, ..@flag165, ..@flag166, ..@flag167
+    dd ..@flag168, ..@flag169, ..@flag170, ..@flag171, ..@flag172, ..@flag173, ..@flag174, ..@flag175
+    dd ..@flag176, ..@flag177, ..@flag178, ..@flag179, ..@flag180, ..@flag181, ..@flag182, ..@flag183
+    dd ..@flag184, ..@flag185, ..@flag186, ..@flag187, ..@flag188, ..@flag189, ..@flag190, ..@flag191
+    dd ..@flag192, ..@flag193, ..@flag194, ..@flag195, ..@flag196, ..@flag197, ..@flag198, ..@flag199
+    dd ..@flag200, ..@flag201, ..@flag202, ..@flag203, ..@flag204, ..@flag205, ..@flag206, ..@flag207
+    dd ..@flag208, ..@flag209, ..@flag210, ..@flag211, ..@flag212, ..@flag213, ..@flag214, ..@flag215
+    dd ..@flag216, ..@flag217, ..@flag218, ..@flag219, ..@flag220, ..@flag221, ..@flag222, ..@flag223
+    dd ..@flag224, ..@flag225, ..@flag226, ..@flag227, ..@flag228, ..@flag229, ..@flag230, ..@flag231
+    dd ..@flag232, ..@flag233, ..@flag234, ..@flag235, ..@flag236, ..@flag237, ..@flag238, ..@flag239
+    dd ..@flag240, ..@flag241, ..@flag242, ..@flag243, ..@flag244, ..@flag245, ..@flag246, ..@flag247
+    dd ..@flag248, ..@flag249, ..@flag250, ..@flag251, ..@flag252, ..@flag253, ..@flag254, ..@flag255
+
+
diff --git a/od-win32/ioport.c b/od-win32/ioport.c
new file mode 100755 (executable)
index 0000000..b7a6b4f
--- /dev/null
@@ -0,0 +1,275 @@
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <cia.h>
+
+//#define IOPORT_EMU
+#define io_log
+//#define io_log write_log
+
+typedef int bool;
+
+#include <windows.h>
+
+#ifndef IOPORT_EMU
+#include <WinIo.h>
+#endif
+
+static bool initialized;
+
+int ioport_init (void)
+{
+    if (initialized)
+       return 1;
+#ifndef IOPORT_EMU
+    initialized = InitializeWinIo();
+#else
+    initialized = 1;
+#endif
+    io_log ("io initialize returned %d\n", initialized);
+    return initialized;
+}
+
+void ioport_free (void)
+{
+#ifndef IOPORT_EMU
+    if (initialized)
+       ShutdownWinIo();
+#endif
+    io_log ("io freed\n");
+    initialized = 0;
+}
+
+uae_u8 ioport_read (int port)
+{
+    DWORD v = 0;
+#ifndef IOPORT_EMU
+    GetPortVal (port, &v, 1);
+#endif
+    io_log ("ioport_read %04.4X returned %02.2X\n", port, v);
+    return (uae_u8)v;
+}
+
+void ioport_write (int port, uae_u8 v)
+{
+#ifndef IOPORT_EMU
+    SetPortVal (port, v, 1);
+#endif
+    io_log ("ioport_write %04.4X %02.2X\n", port, v);
+}
+
+
+#ifndef PARALLEL_DIRECT
+
+void paraport_free (void) { }
+int paraport_init (void) { return 0; }
+int paraport_open (char *port) { return 0; }
+int parallel_direct_write_status (uae_u8 v, uae_u8 dir) { return 0; }
+int parallel_direct_read_status (uae_u8 *vp) { return 0; }
+int parallel_direct_write_data (uae_u8 v, uae_u8 dir) { return 0; }
+int parallel_direct_read_data (uae_u8 *v) { return 0; }
+
+#else
+
+#include <ParaPort.h>
+
+typedef BOOL (*closePort)(HANDLE);
+typedef BOOL (*executeCycle)(HANDLE, PARAPORT_CYCLE*, int);
+typedef BOOL (*getPortInfo)(HANDLE, PARAPORT_INFO*);
+typedef HANDLE* (*openPort)(const char*);
+static closePort pp_closeport;
+static executeCycle pp_executecycle;
+static getPortInfo pp_getportinfo;
+static openPort pp_openport;
+static HMODULE para;
+static HANDLE pport;
+
+void paraport_free (void)
+{
+    if (para) {
+       if (pport)
+           pp_closeport (pport);
+       pport = 0;      
+       FreeLibrary (para);
+       para = 0;
+    }
+}
+
+int paraport_init (void)
+{
+    char tmp[10];
+    int mask = 0, i;
+    HANDLE pp;
+
+    paraport_free ();
+    para = LoadLibrary("ParaPort.dll");
+    if (!para) {
+       write_log ("PARAPORT: no ParaPort.dll, direct parallel port emulation disabled\n");
+       return 0;
+    }
+    pp_closeport = (closePort)GetProcAddress (para, "closePort");
+    pp_executecycle = (executeCycle)GetProcAddress (para, "executeCycle");
+    pp_getportinfo = (getPortInfo)GetProcAddress (para, "getPortInfo");
+    pp_openport = (openPort)GetProcAddress (para, "openPort");
+    if (!pp_openport || !pp_closeport || !pp_executecycle) {
+       write_log ("PARAPORT: GetProcAddress() failed\n");
+       paraport_free ();
+    }
+    write_log("PARAPORT:");
+    for (i = 0; i < 4 ; i++) {
+       sprintf (tmp, "LPT%d", i + 1);
+       pp = pp_openport (tmp);
+       if (pp != INVALID_HANDLE_VALUE) {
+           mask |= 1 << i;
+           pp_closeport (pp);
+           write_log(" %s", tmp);
+       }
+       pp = 0;
+    }
+    if (!mask)
+       write_log ("no parallel ports detected");
+    write_log("\n");
+    return mask;
+}
+
+int paraport_open (char *port)
+{
+    static char oldport[10];
+
+    if (!para)
+       return 0;
+    if (pport && !strcmp (port, oldport))
+       return 1;
+    pport = pp_openport(port);
+    if (!pport) {
+       write_log ("PARAPORT: couldn't open '%s'\n", port);
+       paraport_free ();
+       return 0;
+    }
+    strcpy (oldport, port);
+    write_log("PARAPORT: port '%s' opened\n", port);
+    return 1;
+}
+
+
+int parallel_direct_write_status (uae_u8 v, uae_u8 dir)
+{
+    PARAPORT_CYCLE c[2];
+    int ok = 1;
+
+    if (!pport)
+       return 0;
+    memset (c + 0, 0, sizeof (PARAPORT_CYCLE));
+    c[0].MaskControl = PARAPORT_MASK_CONTROL_SELECTIN;
+    if ((dir & 1)) {
+       write_log ("PARAPORT: BUSY can't be output\n");
+       ok = 0;
+    }
+    if ((dir & 2)) {
+       write_log ("PARAPORT: POUT can't be output\n");
+       ok = 0;
+    }
+    if ((dir & 4) && (v & 4))
+       c[0].Control |= PARAPORT_MASK_CONTROL_SELECTIN;
+    if (!pp_executecycle (pport, c, 2)) {
+       write_log ("PARAPORT: write executeCycle failed, CTL=%02.2X DIR=%02.2X\n", v & 7, dir & 7);
+       return 0;
+    }
+    write_log ("PARAPORT: write CTL=%02.2X DIR=%02.2X\n", v & 7, dir & 7);
+    return ok;
+}
+
+int parallel_direct_read_status (uae_u8 *vp)
+{
+    PARAPORT_CYCLE c[1];
+    int ok = 1;
+    uae_u8 v = 0;
+
+    if (!pport)
+       return 0;
+    memset (c + 0, 0, sizeof (PARAPORT_CYCLE));
+    c[0].MaskStatus = PARAPORT_MASK_STATUS;
+    if (!pp_executecycle (pport, c, 1)) {
+       write_log ("PARAPORT: CTL read executeCycle failed\n");
+       return 0;
+    }
+    if (c[0].Status & PARAPORT_MASK_STATUS_SELECT)
+       v |= 4;
+    if (c[0].Status & PARAPORT_MASK_STATUS_PAPEREND)
+       v |= 2;
+    if (c[0].Status & PARAPORT_MASK_STATUS_BUSY)
+       v |= 1;
+    if (c[0].Status & PARAPORT_MASK_STATUS_ACKNOWLEDGE)
+       v |= 8;
+    write_log ("PARAPORT: read CTL=%02.2X\n", v);
+    v &= 7;
+    *vp &= ~7;
+    *vp |= v;
+    return ok;
+}
+
+int parallel_direct_write_data (uae_u8 v, uae_u8 dir)
+{
+    PARAPORT_CYCLE c[2];
+    int ok = 1;
+
+    if (!pport)
+       return 0;
+    if (dir != 0xff) {
+       write_log ("PARAPORT: unsupported mixed i/o attempted, DATA=%02.2X DIR=%02.2X, ignored\n", v, dir);
+       return 0;
+    }
+    memset (c + 0, 0, sizeof (PARAPORT_CYCLE));
+    memset (c + 1, 0, sizeof (PARAPORT_CYCLE));
+    c[0].Data = v;
+    c[0].MaskData = 0xff;
+    c[0].MaskControl = PARAPORT_MASK_CONTROL_STROBE;
+    c[0].Control = PARAPORT_MASK_CONTROL_STROBE;
+    c[0].RepeatFactor = 1;
+    c[1].MaskControl = PARAPORT_MASK_CONTROL_STROBE;
+    if (!pp_executecycle (pport, c, 2)) {
+       write_log ("PARAPORT: write executeCycle failed, data=%02.2X\n", v);
+       return 0;
+    }
+    write_log ("PARAPORT: write DATA=%02.2X\n", v);
+    return 1;
+}
+
+int parallel_direct_read_data (uae_u8 *v)
+{
+    static uae_u8 olda, oldb;
+    PARAPORT_CYCLE c[2];
+    int ok = 1;
+
+    if (!pport)
+       return 0;
+    memset (c + 0, 0, sizeof (PARAPORT_CYCLE));
+    memset (c + 1, 0, sizeof (PARAPORT_CYCLE));
+    c[0].MaskData = 0xff;
+    c[0].MaskControl = PARAPORT_MASK_CONTROL_DIRECTION | PARAPORT_MASK_CONTROL_STROBE;
+    c[0].Control = PARAPORT_MASK_CONTROL_DIRECTION | PARAPORT_MASK_CONTROL_STROBE;
+    c[0].RepeatFactor = 1;
+    c[1].MaskControl = PARAPORT_MASK_CONTROL_STROBE;
+    c[1].MaskData = 0;
+    if (!pp_executecycle (pport, c, 2)) {
+       write_log ("PARAPORT: DATA read executeCycle failed\n");
+       return 0;
+    }
+    *v = c[0].Data;
+    write_log("PARAPORT: read DATA=%02.2X\n", v);
+    return ok;
+}
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
diff --git a/od-win32/ioport.h b/od-win32/ioport.h
new file mode 100755 (executable)
index 0000000..c3eb5c7
--- /dev/null
@@ -0,0 +1,9 @@
+
+int ioport_init (void);
+void ioport_free (void);
+void ioport_write (int,uae_u8);
+uae_u8 ioport_read (int);
+
+int paraport_init (void);
+int paraport_open (char*);
+void paraport_free (void);
diff --git a/od-win32/keyboard_win32.c b/od-win32/keyboard_win32.c
new file mode 100755 (executable)
index 0000000..f91bdb1
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * Additional Win32 helper functions not calling any system routines
+ *
+ * (c) 1997 Mathias Ortmann
+ * (c) 1999-2001 Brian King
+ * (c) 2000-2001 Bernd Roesch
+ * (c) 2002 Toni Wilen
+ */
+
+#include "config.h"
+#include "sysconfig.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <signal.h>
+#include <windows.h>
+#include <dinput.h>
+
+#include "sysdeps.h"
+#include "uae.h"
+#include "gui.h"
+#include "options.h"
+#include "memory.h"
+#include "custom.h"
+#include "events.h"
+#include "newcpu.h"
+#include "keyboard.h"
+#include "inputdevice.h"
+#include "xwin.h"
+#include "drawing.h"
+#include "disk.h"
+#include "keybuf.h"
+#include "win32.h"
+#include "debug.h"
+#include "ar.h"
+#include "ahidsound.h"
+#include "savestate.h"
+#include "sound.h"
+
+extern void screenshot(int);
+
+//#define DBG_KEYBD 1
+//#define DEBUG_KBD
+
+static struct uae_input_device_kbr_default keytrans[] = {
+
+    { DIK_ESCAPE, INPUTEVENT_KEY_ESC },
+    
+    { DIK_F1, INPUTEVENT_KEY_F1 },
+    { DIK_F2, INPUTEVENT_KEY_F2 },
+    { DIK_F3, INPUTEVENT_KEY_F3 },
+    { DIK_F4, INPUTEVENT_KEY_F4 },
+    { DIK_F5, INPUTEVENT_KEY_F5 },
+    { DIK_F6, INPUTEVENT_KEY_F6 },
+    { DIK_F7, INPUTEVENT_KEY_F7 },
+    { DIK_F8, INPUTEVENT_KEY_F8 },
+    { DIK_F9, INPUTEVENT_KEY_F9 },
+    { DIK_F10, INPUTEVENT_KEY_F10 },
+
+    { DIK_1, INPUTEVENT_KEY_1 },
+    { DIK_2, INPUTEVENT_KEY_2 },
+    { DIK_3, INPUTEVENT_KEY_3 },
+    { DIK_4, INPUTEVENT_KEY_4 },
+    { DIK_5, INPUTEVENT_KEY_5 },
+    { DIK_6, INPUTEVENT_KEY_6 },
+    { DIK_7, INPUTEVENT_KEY_7 },
+    { DIK_8, INPUTEVENT_KEY_8 },
+    { DIK_9, INPUTEVENT_KEY_9 },
+    { DIK_0, INPUTEVENT_KEY_0 },
+
+    { DIK_TAB, INPUTEVENT_KEY_TAB },
+
+    { DIK_A, INPUTEVENT_KEY_A },
+    { DIK_B, INPUTEVENT_KEY_B },
+    { DIK_C, INPUTEVENT_KEY_C },
+    { DIK_D, INPUTEVENT_KEY_D },
+    { DIK_E, INPUTEVENT_KEY_E },
+    { DIK_F, INPUTEVENT_KEY_F },
+    { DIK_G, INPUTEVENT_KEY_G },
+    { DIK_H, INPUTEVENT_KEY_H },
+    { DIK_I, INPUTEVENT_KEY_I },
+    { DIK_J, INPUTEVENT_KEY_J },
+    { DIK_K, INPUTEVENT_KEY_K },
+    { DIK_L, INPUTEVENT_KEY_L },
+    { DIK_M, INPUTEVENT_KEY_M },
+    { DIK_N, INPUTEVENT_KEY_N },
+    { DIK_O, INPUTEVENT_KEY_O },
+    { DIK_P, INPUTEVENT_KEY_P },
+    { DIK_Q, INPUTEVENT_KEY_Q },
+    { DIK_R, INPUTEVENT_KEY_R },
+    { DIK_S, INPUTEVENT_KEY_S },
+    { DIK_T, INPUTEVENT_KEY_T },
+    { DIK_U, INPUTEVENT_KEY_U },
+    { DIK_W, INPUTEVENT_KEY_W },
+    { DIK_V, INPUTEVENT_KEY_V },
+    { DIK_X, INPUTEVENT_KEY_X },
+    { DIK_Y, INPUTEVENT_KEY_Y },
+    { DIK_Z, INPUTEVENT_KEY_Z },
+
+    { DIK_CAPITAL, INPUTEVENT_KEY_CAPS_LOCK },
+
+    { DIK_NUMPAD1, INPUTEVENT_KEY_NP_1 },
+    { DIK_NUMPAD2, INPUTEVENT_KEY_NP_2 },
+    { DIK_NUMPAD3, INPUTEVENT_KEY_NP_3 },
+    { DIK_NUMPAD4, INPUTEVENT_KEY_NP_4 },
+    { DIK_NUMPAD5, INPUTEVENT_KEY_NP_5 },
+    { DIK_NUMPAD6, INPUTEVENT_KEY_NP_6 },
+    { DIK_NUMPAD7, INPUTEVENT_KEY_NP_7 },
+    { DIK_NUMPAD8, INPUTEVENT_KEY_NP_8 },
+    { DIK_NUMPAD9, INPUTEVENT_KEY_NP_9 },
+    { DIK_NUMPAD0, INPUTEVENT_KEY_NP_0 },
+    { DIK_DECIMAL, INPUTEVENT_KEY_NP_PERIOD },
+    { DIK_ADD, INPUTEVENT_KEY_NP_ADD },
+    { DIK_SUBTRACT, INPUTEVENT_KEY_NP_SUB },
+    { DIK_MULTIPLY, INPUTEVENT_KEY_NP_MUL },
+    { DIK_DIVIDE, INPUTEVENT_KEY_NP_DIV },
+    { DIK_NUMPADENTER, INPUTEVENT_KEY_ENTER },
+
+    { DIK_MINUS, INPUTEVENT_KEY_SUB },
+    { DIK_EQUALS, INPUTEVENT_KEY_EQUALS },
+    { DIK_BACK, INPUTEVENT_KEY_BACKSPACE },
+    { DIK_RETURN, INPUTEVENT_KEY_RETURN },
+    { DIK_SPACE, INPUTEVENT_KEY_SPACE },
+
+    { DIK_LSHIFT, INPUTEVENT_KEY_SHIFT_LEFT },
+    { DIK_LCONTROL, INPUTEVENT_KEY_CTRL },
+    { DIK_LWIN, INPUTEVENT_KEY_AMIGA_LEFT },
+    { DIK_LMENU, INPUTEVENT_KEY_ALT_LEFT },
+    { DIK_RMENU, INPUTEVENT_KEY_ALT_RIGHT },
+    { DIK_RWIN, INPUTEVENT_KEY_AMIGA_RIGHT },
+    { DIK_APPS, INPUTEVENT_KEY_AMIGA_RIGHT },
+    { DIK_RCONTROL, INPUTEVENT_KEY_CTRL_RIGHT },
+    { DIK_RSHIFT, INPUTEVENT_KEY_SHIFT_RIGHT },
+
+    { DIK_UP, INPUTEVENT_KEY_CURSOR_UP },
+    { DIK_DOWN, INPUTEVENT_KEY_CURSOR_DOWN },
+    { DIK_LEFT, INPUTEVENT_KEY_CURSOR_LEFT },
+    { DIK_RIGHT, INPUTEVENT_KEY_CURSOR_RIGHT },
+
+    { DIK_INSERT, INPUTEVENT_KEY_AMIGA_LEFT },
+    { DIK_DELETE, INPUTEVENT_KEY_DEL },
+    { DIK_HOME, INPUTEVENT_KEY_AMIGA_RIGHT },
+    { DIK_NEXT, INPUTEVENT_KEY_HELP },
+
+    { DIK_LBRACKET, INPUTEVENT_KEY_LEFTBRACKET },
+    { DIK_RBRACKET, INPUTEVENT_KEY_RIGHTBRACKET },
+    { DIK_SEMICOLON, INPUTEVENT_KEY_SEMICOLON },
+    { DIK_APOSTROPHE, INPUTEVENT_KEY_SINGLEQUOTE },
+    { DIK_GRAVE, INPUTEVENT_KEY_BACKQUOTE },
+    { DIK_BACKSLASH, INPUTEVENT_KEY_BACKSLASH },
+    { DIK_COMMA, INPUTEVENT_KEY_COMMA },
+    { DIK_PERIOD, INPUTEVENT_KEY_PERIOD },
+    { DIK_SLASH, INPUTEVENT_KEY_DIV },
+    { DIK_OEM_102, INPUTEVENT_KEY_30 },
+
+    { DIK_BACK, INPUTEVENT_SPC_STATEREWIND },
+
+    { DIK_VOLUMEDOWN, INPUTEVENT_SPC_VOLUME_DOWN },
+    { DIK_VOLUMEUP, INPUTEVENT_SPC_VOLUME_UP },
+    { DIK_MUTE, INPUTEVENT_SPC_VOLUME_MUTE },
+
+    { -1, 0 }
+};
+
+extern int ispressed (int key);
+
+static int endpressed (void)
+{
+    return ispressed(DIK_END);
+}
+
+static int shiftpressed (void)
+{
+    return ispressed (DIK_LSHIFT) || ispressed (DIK_RSHIFT);
+}
+
+static int altpressed (void)
+{
+    return ispressed (DIK_LMENU) || ispressed (DIK_RMENU);
+}
+
+static int ctrlpressed (void)
+{
+    return ispressed (DIK_LCONTROL) || ispressed (DIK_RCONTROL);
+}
+
+static int capslockstate;
+
+int getcapslockstate (void)
+{
+    return capslockstate;
+}
+void setcapslockstate (int state)
+{
+    capslockstate = state;
+}
+
+int getcapslock (void)
+{
+    int newstate;
+
+    BYTE keyState[256];
+    GetKeyboardState (keyState);
+    newstate = keyState[VK_CAPITAL] & 1;
+    if (newstate != capslockstate)
+        inputdevice_translatekeycode (0, DIK_CAPITAL, newstate);
+    capslockstate = newstate;
+    return capslockstate;
+}
+
+#ifdef CD32
+extern int cd32_enabled;
+
+static int handlecd32 (int scancode, int state)
+{
+    int e = 0;
+    if (!cd32_enabled)
+       return 0;
+    switch (scancode)
+    {
+       case DIK_NUMPAD7:
+       e = INPUTEVENT_JOY2_CD32_GREEN;
+       break;
+       case DIK_NUMPAD9:
+       e = INPUTEVENT_JOY2_CD32_YELLOW;
+       break;
+       case DIK_NUMPAD1:
+       e = INPUTEVENT_JOY2_CD32_RED;
+       break;
+       case DIK_NUMPAD3:
+       e = INPUTEVENT_JOY2_CD32_BLUE;
+       break;
+       case DIK_DIVIDE:
+       e = INPUTEVENT_JOY2_CD32_RWD;
+       break;
+       case DIK_MULTIPLY:
+       e = INPUTEVENT_JOY2_CD32_PLAY;
+       break;
+       case DIK_SUBTRACT:
+       e = INPUTEVENT_JOY2_CD32_FFW;
+       break;
+    }
+    if (!e)
+       return 0;
+    handle_input_event (e, state, 1, 0);
+    return 1;
+}
+#endif
+
+void clearallkeys (void)
+{
+    inputdevice_updateconfig (&currprefs);
+}
+
+static int np[] = { DIK_NUMPAD0, 0, DIK_NUMPADPERIOD, 0, DIK_NUMPAD1, 1, DIK_NUMPAD2, 2,
+    DIK_NUMPAD3, 3, DIK_NUMPAD4, 4, DIK_NUMPAD5, 5, DIK_NUMPAD6, 6, DIK_NUMPAD7, 7,
+    DIK_NUMPAD8, 8, DIK_NUMPAD9, 9, -1 };
+
+void my_kbd_handler (int keyboard, int scancode, int newstate)
+{
+//    write_log( "keyboard = %d scancode = 0x%02.2x state = %d\n", keyboard, scancode, newstate ); 
+    if (newstate) {
+       switch (scancode)
+       {
+           case DIK_F12:
+           if (ctrlpressed ()) {
+               fullscreentoggle();
+           } else if (shiftpressed () || endpressed ()) {
+               disablecapture ();
+               activate_debugger ();
+           } else {
+               gui_display (-1);
+           }
+           return;
+           case DIK_F11:
+           if (currprefs.win32_ctrl_F11_is_quit) {
+               if (ctrlpressed()) {
+                   uae_quit();
+                   return;
+               }
+           }
+           break;
+           case DIK_F1:
+           case DIK_F2:
+           case DIK_F3:
+           case DIK_F4:
+           if (endpressed ()) {
+               if (shiftpressed ())
+                   disk_eject (scancode - DIK_F1);
+               else
+                   gui_display (scancode - DIK_F1);
+               return;
+           }
+           break;
+           case DIK_F5:
+           if (endpressed ()) {
+               gui_display (shiftpressed () ? 5 : 4);
+               return;
+           }
+           break;
+#if 0
+           case DIK_F6:
+           if (endpressed ()) {
+               if (shiftpressed ()) {
+                   if(savestate_filename && strlen (savestate_filename))
+                       savestate_state = STATE_DOSAVE;
+               } else {                
+                   if(savestate_filename && strlen (savestate_filename))
+                       savestate_state = STATE_DORESTORE;
+               }
+               return;
+           }
+#endif
+           break;
+           case DIK_NUMPAD0:
+           case DIK_NUMPAD1:
+           case DIK_NUMPAD2:
+           case DIK_NUMPAD3:
+           case DIK_NUMPAD4:
+           case DIK_NUMPAD5:
+           case DIK_NUMPAD6:
+           case DIK_NUMPAD7:
+           case DIK_NUMPAD8:
+           case DIK_NUMPAD9:
+           case DIK_NUMPADPERIOD:
+           if (endpressed ()) {
+               int i = 0, v = -1;
+               while (np[i] >= 0) {
+                   v = np[i + 1];
+                   if (np[i] == scancode)
+                       break;
+                   i+=2;
+               }
+               if (v >= 0)
+                   savestate_quick (v, shiftpressed() || ctrlpressed ());
+               return;
+           }
+           break;
+           case DIK_SYSRQ:
+           screenshot (endpressed() ? 1 : 0);
+           break;
+           case DIK_PAUSE:
+           if (endpressed ())
+               warpmode (-1);
+           else
+               pausemode (-1);
+           break;
+           case DIK_SCROLL:
+           toggle_inhibit_frame (IHF_SCROLLLOCK);
+           return;
+           case DIK_PRIOR:
+#ifdef ACTION_REPLAY
+           if (action_replay_freeze ())
+               return;
+#endif
+           break;
+           case DIK_NEXT:
+           break;
+           case DIK_NUMPADMINUS:
+           if (endpressed ())
+               sound_volume (-1);
+           break;
+           case DIK_NUMPADPLUS:
+           if (endpressed ())
+               sound_volume (1);
+           break;
+           case DIK_NUMPADSTAR:
+           if (endpressed ())
+               sound_volume (0);
+           break;
+           case DIK_NUMPADSLASH:
+           if (endpressed ())
+               savestate_dorewind (1);
+           break;
+       }
+    }
+    if (endpressed ())
+       return;
+
+    if (scancode == DIK_CAPITAL) {
+       if (!newstate)
+           return;
+       capslockstate = capslockstate ? 0 : 1;
+       newstate = capslockstate;
+    }
+
+    if (currprefs.input_selected_setting == 0) {
+#ifdef CD32
+        if (handlecd32 (scancode, newstate))
+           return;
+#endif
+    }
+    inputdevice_translatekeycode (keyboard, scancode, newstate);
+}
+
+void keyboard_settrans (void)
+{
+    inputdevice_setkeytranslation (keytrans);
+}
+
diff --git a/od-win32/machdep/m68k.h b/od-win32/machdep/m68k.h
new file mode 100755 (executable)
index 0000000..54cfbf5
--- /dev/null
@@ -0,0 +1,184 @@
+#ifndef M68K_H
+#define M68K_H
+
+ /* 
+  * UAE - The Un*x Amiga Emulator
+  * 
+  * MC68000 emulation - machine dependent bits
+  *
+  * Copyright 1996 Bernd Schmidt
+  */
+
+struct flag_struct {
+    unsigned int cznv;
+    unsigned int x;
+};
+
+#define FLAGVAL_Z 0x4000
+#define FLAGVAL_N 0x8000
+
+#define SET_ZFLG(y) (regflags.cznv = (regflags.cznv & ~0x4000) | (((y) ? 0x4000 : 0)))
+#define SET_CFLG(y) (regflags.cznv = (regflags.cznv & ~0x100) | (((y) ? 0x100 : 0)))
+#define SET_VFLG(y) (regflags.cznv = (regflags.cznv & ~0x1) | (((y) ? 1 : 0)))
+#define SET_NFLG(y) (regflags.cznv = (regflags.cznv & ~0x8000) | (((y) ? 0x8000 : 0)))
+#define SET_XFLG(y) (regflags.x = ((y) ? 1 : 0))
+
+#define GET_ZFLG ((regflags.cznv >> 14) & 1)
+#define GET_CFLG ((regflags.cznv >> 8) & 1)
+#define GET_VFLG ((regflags.cznv >> 0) & 1)
+#define GET_NFLG ((regflags.cznv >> 15) & 1)
+#define GET_XFLG (regflags.x & 1)
+
+#define CLEAR_CZNV (regflags.cznv = 0)
+#define GET_CZNV (regflags.cznv)
+#define IOR_CZNV(X) (regflags.cznv |= (X))
+#define SET_CZNV(X) (regflags.cznv = (X))
+
+#define COPY_CARRY (regflags.x = (regflags.cznv) >> 8)
+
+#ifdef X86_ASSEMBLY
+extern struct flag_struct regflags __asm__ ("regflags");
+#else
+extern struct flag_struct regflags;
+#endif
+
+static __inline__ int cctrue(int cc)
+{
+    uae_u32 cznv = regflags.cznv;
+    switch(cc){
+     case 0: return 1;                       /* T */
+     case 1: return 0;                       /* F */
+     case 2: return (cznv & 0x4100) == 0; /* !GET_CFLG && !GET_ZFLG;  HI */
+     case 3: return (cznv & 0x4100) != 0; /* GET_CFLG || GET_ZFLG;    LS */
+     case 4: return (cznv & 0x100) == 0;  /* !GET_CFLG;               CC */
+     case 5: return (cznv & 0x100) != 0;  /* GET_CFLG;                CS */
+     case 6: return (cznv & 0x4000) == 0; /* !GET_ZFLG;               NE */
+     case 7: return (cznv & 0x4000) != 0; /* GET_ZFLG;                EQ */
+     case 8: return (cznv & 0x01) == 0;   /* !GET_VFLG;               VC */
+     case 9: return (cznv & 0x01) != 0;   /* GET_VFLG;                VS */
+     case 10:return (cznv & 0x8000) == 0; /* !GET_NFLG;               PL */
+     case 11:return (cznv & 0x8000) != 0; /* GET_NFLG;                MI */
+     case 12:return (((cznv << 15) ^ cznv) & 0x8000) == 0; /* GET_NFLG == GET_VFLG;             GE */
+     case 13:return (((cznv << 15) ^ cznv) & 0x8000) != 0;/* GET_NFLG != GET_VFLG;             LT */
+     case 14:
+       cznv &= 0xc001;
+       return (((cznv << 15) ^ cznv) & 0xc000) == 0; /* !GET_ZFLG && (GET_NFLG == GET_VFLG);  GT */
+     case 15:
+       cznv &= 0xc001;
+       return (((cznv << 15) ^ cznv) & 0xc000) != 0; /* GET_ZFLG || (GET_NFLG != GET_VFLG);   LE */
+    }
+    abort();
+    return 0;
+}
+
+#ifdef X86_ASSEMBLY
+
+#define optflag_testl(v) \
+  __asm__ __volatile__ ("andl %0,%0\n\t" \
+                       "lahf\n\t" \
+                       "seto %%al\n\t" \
+                        "movb %%al,regflags\n\t" \
+                       "movb %%ah,regflags+1\n\t" \
+                       :: "r" (v) : "%eax","cc","memory")
+#define optflag_testw(v) \
+  __asm__ __volatile__ ("andw %w0,%w0\n\t" \
+                       "lahf\n\t" \
+                       "seto %%al\n\t" \
+                        "movb %%al,regflags\n\t" \
+                       "movb %%ah,regflags+1\n\t" \
+                       :: "r" (v) : "%eax","cc","memory")
+
+#define optflag_testb(v) \
+  __asm__ __volatile__ ("andb %b0,%b0\n\t" \
+                       "lahf\n\t" \
+                       "seto %%al\n\t" \
+                        "movb %%al,regflags\n\t" \
+                       "movb %%ah,regflags+1\n\t" \
+                       :: "q" (v) : "%eax","cc","memory")
+
+#define optflag_addl(v, s, d) do { \
+  __asm__ __volatile__ ("addl %k1,%k0\n\t" \
+                       "lahf\n\t" \
+                       "seto %%al\n\t" \
+                        "movb %%al,regflags\n\t" \
+                       "movb %%ah,regflags+1\n\t" \
+                       :"=r" (v) : "rmi" (s), "0" (d) : "%eax","cc","memory"); \
+    COPY_CARRY; \
+    } while (0)
+#define optflag_addw(v, s, d) do { \
+  __asm__ __volatile__ ("addw %w1,%w0\n\t" \
+                       "lahf\n\t" \
+                       "seto %%al\n\t" \
+                        "movb %%al,regflags\n\t" \
+                       "movb %%ah,regflags+1\n\t" \
+                       : "=r" (v) : "rmi" (s), "0" (d) : "%eax","cc","memory"); \
+    COPY_CARRY; \
+    } while (0)
+
+#define optflag_addb(v, s, d) do { \
+  __asm__ __volatile__ ("addb %b1,%b0\n\t" \
+                       "lahf\n\t" \
+                       "seto %%al\n\t" \
+                        "movb %%al,regflags\n\t" \
+                       "movb %%ah,regflags+1\n\t" \
+                       :"=q" (v) : "qmi" (s), "0" (d) : "%eax","cc","memory"); \
+    COPY_CARRY; \
+    } while (0)
+
+#define optflag_subl(v, s, d) do { \
+  __asm__ __volatile__ ("subl %k1,%k0\n\t" \
+                       "lahf\n\t" \
+                       "seto %%al\n\t" \
+                        "movb %%al,regflags\n\t" \
+                       "movb %%ah,regflags+1\n\t" \
+                       : "=r" (v) : "rmi" (s), "0" (d) : "%eax","cc","memory"); \
+    COPY_CARRY; \
+    } while (0)
+
+#define optflag_subw(v, s, d) do { \
+  __asm__ __volatile__ ("subw %w1,%w0\n\t" \
+                       "lahf\n\t" \
+                       "seto %%al\n\t" \
+                        "movb %%al,regflags\n\t" \
+                       "movb %%ah,regflags+1\n\t" \
+                       : "=r" (v) : "rmi" (s), "0" (d) : "%eax","cc","memory"); \
+    COPY_CARRY; \
+    } while (0)
+
+#define optflag_subb(v, s, d) do { \
+   __asm__ __volatile__ ("subb %b1,%b0\n\t" \
+                       "lahf\n\t" \
+                       "seto %%al\n\t" \
+                        "movb %%al,regflags\n\t" \
+                       "movb %%ah,regflags+1\n\t" \
+                       : "=q" (v) : "qmi" (s), "0" (d) : "%eax","cc","memory"); \
+    COPY_CARRY; \
+    } while (0)
+
+#define optflag_cmpl(s, d) \
+  __asm__ __volatile__ ("cmpl %k0,%k1\n\t" \
+                       "lahf\n\t" \
+                       "seto %%al\n\t" \
+                        "movb %%al,regflags\n\t" \
+                       "movb %%ah,regflags+1\n\t" \
+                       :: "rmi" (s), "r" (d) : "%eax","cc","memory")
+
+#define optflag_cmpw(s, d) \
+  __asm__ __volatile__ ("cmpw %w0,%w1\n\t" \
+                       "lahf\n\t" \
+                       "seto %%al\n\t" \
+                        "movb %%al,regflags\n\t" \
+                       "movb %%ah,regflags+1\n\t" \
+                       :: "rmi" (s), "r" (d) : "%eax","cc","memory");
+
+#define optflag_cmpb(s, d) \
+  __asm__ __volatile__ ("cmpb %b0,%b1\n\t" \
+                       "lahf\n\t" \
+                       "seto %%al\n\t" \
+                        "movb %%al,regflags\n\t" \
+                       "movb %%ah,regflags+1\n\t" \
+                       :: "qmi" (s), "q" (d) : "%eax","cc","memory")
+
+#endif
+
+#endif
\ No newline at end of file
diff --git a/od-win32/machdep/maccess.h b/od-win32/machdep/maccess.h
new file mode 100755 (executable)
index 0000000..13b2942
--- /dev/null
@@ -0,0 +1,234 @@
+#ifndef __MACCESS_H__
+#define __MACCESS_H__
+ /* 
+  * UAE - The Un*x Amiga Emulator
+  * 
+  * Memory access functions
+  *
+  * Copyright 1996 Bernd Schmidt
+  */
+
+#if defined( __GNUC__ ) && defined( X86_ASSEMBLY )
+
+#define X86_PPRO_OPT
+
+static __inline__ uae_u32 do_get_mem_long (uae_u32 *a)
+{
+    uae_u32 retval;
+
+    __asm__ ("bswap %0" : "=r" (retval) : "0" (*a) : "cc");
+    return retval;
+}
+
+static __inline__ uae_u32 do_get_mem_word (uae_u16 *a)
+{
+    uae_u32 retval;
+
+#ifdef X86_PPRO_OPT
+    __asm__ ("movzwl %w1,%k0\n\tshll $16,%k0\n\tbswap %k0\n" : "=&r" (retval) : "m" (*a) : "cc");
+#else
+    __asm__ ("xorl %k0,%k0\n\tmovw %w1,%w0\n\trolw $8,%w0" : "=&r" (retval) : "m" (*a) : "cc");
+#endif
+    return retval;
+}
+
+#define do_get_mem_byte(a) ((uae_u32)*(uae_u8 *)(a))
+
+static __inline__ void do_put_mem_long (uae_u32 *a, uae_u32 v)
+{
+    __asm__ ("bswap %0" : "=r" (v) : "0" (v) : "cc");
+    *a = v;
+}
+
+static __inline__ void do_put_mem_word (uae_u16 *a, uae_u32 v)
+{
+#ifdef X86_PPRO_OPT
+    __asm__ ("bswap %0" : "=&r" (v) : "0" (v << 16) : "cc");
+#else
+    __asm__ ("rolw $8,%w0" : "=r" (v) : "0" (v) : "cc");
+#endif
+    *a = v;
+}
+
+#define do_put_mem_byte(a,v) (*(uae_u8 *)(a) = (v))
+
+#if 0
+static __inline__ uae_u32 call_mem_get_func(mem_get_func func, uae_cptr addr)
+{
+    uae_u32 result;
+    __asm__("call %1"
+           : "=a" (result) : "r" (func), "a" (addr) : "cc", "edx", "ecx");
+    return result;
+}
+
+static __inline__ void call_mem_put_func(mem_put_func func, uae_cptr addr, uae_u32 v)
+{
+    __asm__("call %2"
+           : : "a" (addr), "d" (v), "r" (func) : "cc", "eax", "edx", "ecx", "memory");
+}
+#else
+
+#define call_mem_get_func(func,addr) ((*func)(addr))
+#define call_mem_put_func(func,addr,v) ((*func)(addr,v))
+
+#endif
+
+#undef NO_INLINE_MEMORY_ACCESS
+#undef MD_HAVE_MEM_1_FUNCS
+
+#ifdef MD_HAVE_MEM_1_FUNCS
+static __inline__ uae_u32 longget_1 (uae_cptr addr)
+{
+    uae_u32 result;
+
+    __asm__ ("andl $0x00FFFFFF,%1\n"
+            "\tcmpb $0,(%1,%3)\n"
+            "\tleal 1f,%%ecx\n"
+            "\tje longget_stub\n"
+            "\taddl address_space,%1\n"
+            "\tmovl (%1),%0\n"
+            "\tbswap %0\n"
+            "\t1:"
+            : "=c" (result), "=d" (addr) : "1" (addr), "r" (good_address_map) : "cc");
+    return result;
+}
+static __inline__ uae_u32 wordget_1 (uae_cptr addr)
+{
+    uae_u32 result;
+
+    __asm__ ("andl $0x00FFFFFF,%1\n"
+            "\tcmpb $0,(%1,%3)\n"
+            "\tleal 1f,%%ecx\n"
+            "\tje wordget_stub\n"
+            "\taddl address_space,%1\n"
+            "\tmovzwl (%1),%0\n"
+            "\trolw $8,%w0\n"
+            "\t1:"
+            : "=c" (result), "=d" (addr) : "1" (addr), "r" (good_address_map) : "cc");
+    return result;
+}
+static __inline__ uae_u32 byteget_1 (uae_cptr addr) 
+{
+    uae_u32 result;
+
+    __asm__ ("andl $0x00FFFFFF,%1\n"
+            "\tcmpb $0,(%1,%3)\n"
+            "\tleal 1f,%%ecx\n"
+            "\tje byteget_stub\n"
+            "\taddl address_space,%1\n"
+            "\tmovzbl (%1),%0\n"
+            "\t1:"
+            : "=c" (result), "=d" (addr) : "1" (addr), "r" (good_address_map) : "cc");
+    return result;
+}
+static __inline__ void longput_1 (uae_cptr addr, uae_u32 l)
+{
+    __asm__ __volatile__("andl $0x00FFFFFF,%0\n"
+            "\tcmpb $0,(%0,%3)\n"
+            "\tleal 1f,%%ecx\n"
+            "\tje longput_stub\n"
+            "\taddl address_space,%0\n"
+            "\tbswap %1\n"
+            "\tmovl %1,(%0)\n"
+            "\t1:"
+            : "=d" (addr), "=b" (l) : "0" (addr), "r" (good_address_map), "1" (l) : "cc", "memory", "ecx");
+}
+static __inline__ void wordput_1 (uae_cptr addr, uae_u32 w)
+{
+    __asm__ __volatile__("andl $0x00FFFFFF,%0\n"
+            "\tcmpb $0,(%0,%3)\n"
+            "\tleal 1f,%%ecx\n"
+            "\tje wordput_stub\n"
+            "\taddl address_space,%0\n"
+            "\trolw $8,%1\n"
+            "\tmovw %w1,(%0)\n"
+            "\t1:"
+            : "=d" (addr), "=b" (w) : "0" (addr), "r" (good_address_map), "1" (w) : "cc", "memory", "ecx");
+}
+static __inline__ void byteput_1 (uae_cptr addr, uae_u32 b)
+{
+    __asm__ __volatile__("andl $0x00FFFFFF,%0\n"
+            "\tcmpb $0,(%0,%3)\n"
+            "\tleal 1f,%%ecx\n"
+            "\tje byteput_stub\n"
+            "\taddl address_space,%0\n"
+            "\tmovb %b1,(%0)\n"
+            "\t1:"
+            : "=d" (addr), "=b" (b) : "0" (addr), "r" (good_address_map), "1" (b) : "cc", "memory", "ecx");
+}
+
+#endif
+
+#define ALIGN_POINTER_TO32(p) ((~(unsigned long)(p)) & 3)
+
+#else
+
+static __inline__ uae_u32 do_get_mem_long(uae_u32 *a)
+{
+#ifndef _MSC_VER
+    uae_u8 *b = (uae_u8 *)a;
+    return (*b << 24) | (*(b+1) << 16) | (*(b+2) << 8) | (*(b+3));
+#else
+    uae_u32 retval;
+    __asm
+    {
+       mov     eax, a
+       mov     ebx, [eax]
+       bswap   ebx
+       mov     retval, ebx
+    }
+    return retval;
+#endif
+}
+
+static __inline__ uae_u16 do_get_mem_word(uae_u16 *a)
+{
+    uae_u8 *b = (uae_u8 *)a;
+    
+    return (*b << 8) | (*(b+1));
+}
+
+#define do_get_mem_byte(a) ((uae_u32)*(uae_u8 *)(a))
+
+static __inline__ void do_put_mem_long(uae_u32 *a, uae_u32 v)
+{
+#ifndef _MSC_VER
+    uae_u8 *b = (uae_u8 *)a;
+    
+    *b = v >> 24;
+    *(b+1) = v >> 16;    
+    *(b+2) = v >> 8;
+    *(b+3) = v;
+#else
+    __asm
+    {
+       mov     eax, a
+       mov     ebx, v
+       bswap   ebx
+       mov     [eax], ebx
+    }
+#endif
+}
+
+static __inline__ void do_put_mem_word(uae_u16 *a, uae_u16 v)
+{
+    uae_u8 *b = (uae_u8 *)a;
+    
+    *b = v >> 8;
+    *(b+1) = (uae_u8)v;
+}
+
+static __inline__ void do_put_mem_byte(uae_u8 *a, uae_u8 v)
+{
+    *a = v;
+}
+
+#define call_mem_get_func(func, addr) ((*func)(addr))
+#define call_mem_put_func(func, addr, v) ((*func)(addr, v))
+
+#undef NO_INLINE_MEMORY_ACCESS
+#undef MD_HAVE_MEM_1_FUNCS
+
+#endif
+
+#endif
\ No newline at end of file
diff --git a/od-win32/machdep/rpt.h b/od-win32/machdep/rpt.h
new file mode 100755 (executable)
index 0000000..c371fd1
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Definitions for accessing cycle counters on a given machine, if possible.
+  *
+  * Copyright 1997, 1998 Bernd Schmidt
+  * Copyright 1999 Brian King - Win32 specific
+  */
+#ifndef _RPT_H_
+#define _RPT_H_
+
+#ifdef HIBERNATE_TEST
+extern int rpt_skip_trigger;
+#endif
+
+typedef unsigned long frame_time_t;
+
+/* For CPUs that lack the rdtsc instruction or systems that change CPU frequency on the fly (most laptops) */
+extern frame_time_t read_processor_time_qpc( void );
+extern int useqpc;
+
+#if defined( __GNUC__ )
+static inline frame_time_t read_processor_time (void)
+{
+    frame_time_t foo;
+    int dummy;
+
+    if( useqpc )
+        return read_processor_time_cyrix();
+
+    /* Don't assume the assembler knows rdtsc */
+    __asm__ __volatile__ (".byte 0x0f,0x31" : "=a" (foo), "=d" (dummy) :);
+    return foo;
+}
+#elif defined( __WATCOMC__ )
+extern frame_time_t read_processor_time (void);
+#pragma aux read_processor_time = \
+ "rdtsc" \
+ modify [eax edx] value [eax];
+#elif defined( _MSC_VER ) && !defined( _WIN32_WCE )
+
+STATIC_INLINE frame_time_t read_processor_time_qpc (void)
+{
+    LARGE_INTEGER counter;
+    QueryPerformanceCounter( &counter );
+    if (useqpc > 0)
+       return (frame_time_t)(counter.LowPart);
+    return (frame_time_t)(counter.QuadPart >> 6);
+}
+
+STATIC_INLINE frame_time_t read_processor_time (void)
+{
+    frame_time_t foo, bar;
+
+    if (useqpc) /* No RDTSC or RDTSC is not stable */
+       return read_processor_time_qpc();
+
+     __asm
+    {
+        rdtsc
+        mov foo, eax
+        mov bar, edx
+    }
+    /* very high speed CPU's RDTSC might overflow without this.. */
+    foo >>= 6;
+    foo |= bar << 26;
+#ifdef HIBERNATE_TEST
+    if (rpt_skip_trigger) {
+       foo += rpt_skip_trigger;
+       rpt_skip_trigger = 0;
+    }
+#endif
+    return foo;
+}
+#else
+static __inline__ frame_time_t read_processor_time (void)
+{
+    return 0;
+}
+#endif
+
+#endif
diff --git a/od-win32/machdep/support.c b/od-win32/machdep/support.c
new file mode 100755 (executable)
index 0000000..0e13f24
--- /dev/null
@@ -0,0 +1,294 @@
+ /* 
+  * UAE - The Un*x Amiga Emulator
+  * 
+  * Miscellaneous machine dependent support functions and definitions
+  *
+  * Copyright 1996 Bernd Schmidt
+  */
+
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "machdep/m68k.h"
+#include "events.h"
+
+#ifdef X86_ASSEMBLY
+
+#ifndef USE_UNDERSCORE
+#define LARGE_ALIGNMENT ".align 16\n"
+#else
+#define LARGE_ALIGNMENT ".align 4,0x90\n"
+#endif
+
+struct flag_struct regflags;
+
+/*
+ * Careful: No unique labels. Unfortunately, not each installation of GCC 
+ * comes with GAS. Bletch.
+ */
+
+int fast_memcmp(const void *foo, const void *bar, int len)
+{
+    int differs, baz;
+    __asm__ __volatile__ ("subl $4, %2\n"
+                         "jc  LLA2\n"
+                         "LLA1:\n"
+                         "movl (%0),%%ebx\n"
+                         "cmpl (%1),%%ebx\n"
+                         "jne LLA5\n"
+                         "addl $4, %0\n"
+                         "addl $4, %1\n"
+                         "subl $4, %2\n"
+                         "jnc  LLA1\n"
+                         "LLA2:\n"
+                         "addl $4, %2\n"
+                         "jz LLA4\n"
+                         "LLA3:\n"
+                         "movb (%0),%%bl\n"
+                         "cmpb (%1),%%bl\n"
+                         "jne LLA5\n"
+                         "incl %0\n"
+                         "incl %1\n"
+                         "decl %2\n"
+                         "jnz LLA3\n"
+                         "LLA4:\n"
+                         "movl $0, %3\n"
+                         "jmp LLA6\n"
+                         "LLA5:\n"
+                         "movl $1, %3\n"
+                         "LLA6:\n"
+                         : "=&r" (foo), "=&r" (bar), "=&rm" (len), "=rm" (differs),
+                           "=&b" (baz)
+                         : "0" (foo), "1" (bar), "2" (len), "3" (baz) : "cc");
+    return differs;
+}
+
+int memcmpy(void *foo, const void *bar, int len)
+{
+    int differs = 0, baz = 0, uupzuq = 0;
+
+    __asm__ __volatile__ ("subl %1, %2\n"
+                         "subl $16, %3\n"
+                         "jc LLB7\n"
+                         LARGE_ALIGNMENT
+                         "LLB8:\n"
+                         "movl (%2,%1),%%ebx\n"
+                         "movl (%1),%%ecx\n"
+                         "cmpl %%ebx, %%ecx\n"
+                         "jne LLC1\n"
+                         
+                         "movl 4(%2,%1),%%ebx\n"
+                         "movl 4(%1),%%ecx\n"
+                         "cmpl %%ebx, %%ecx\n"
+                         "jne LLC2\n"
+                         
+                         "movl 8(%2,%1),%%ebx\n"
+                         "movl 8(%1),%%ecx\n"
+                         "cmpl %%ebx, %%ecx\n"
+                         "jne LLC3\n"
+                         
+                         "movl 12(%2,%1),%%ebx\n"
+                         "movl 12(%1),%%ecx\n"
+                         "cmpl %%ebx, %%ecx\n"
+                         "jne LLC4\n"
+                         
+                         "addl $16, %1\n"
+                         "subl $16, %3\n"
+                         "jnc  LLB8\n"
+                         
+                         "LLB7:\n"
+                         "addl $16, %3\n"
+                         "subl $4, %3\n"
+                         "jc  LLB2\n"
+
+                         "LLB1:\n"
+                         "movl (%2,%1),%%ebx\n"
+                         "movl (%1),%%ecx\n"
+                         "cmpl %%ebx, %%ecx\n"
+                         "jne LLC5\n"
+                         "addl $4, %1\n"
+                         "subl $4, %3\n"
+                         "jnc  LLB1\n"
+                         
+                         "LLB2:\n"
+                         "addl $4, %3\n"
+                         "jz LLB9\n"
+                         
+                         "LLB3:\n"
+                         "movb (%2,%1),%%bl\n"
+                         "movb (%1),%%cl\n"
+                         "cmpb %%bl,%%cl\n"
+                         "jne LLC6\n"
+                         "incl %1\n"
+                         "decl %3\n"
+                         "jnz LLB3\n"
+                         
+                         "jmp LLB9\n"
+
+                         LARGE_ALIGNMENT
+                         /* Once we find a difference, we switch to plain memcpy() */
+                         "LLC01:\n"
+                         "movl (%2,%1),%%ebx\n"
+                         "LLC1:\n"
+                         "movl %%ebx, (%1)\n"
+                         
+                         "movl 4(%2,%1),%%ebx\n"
+                         "LLC2:\n"
+                         "movl %%ebx, 4(%1)\n"
+                         
+                         "movl 8(%2,%1),%%ebx\n"
+                         "LLC3:\n"
+                         "movl %%ebx, 8(%1)\n"
+                         
+                         "movl 12(%2,%1),%%ebx\n"
+                         "LLC4:\n"
+                         "movl %%ebx, 12(%1)\n"
+                         
+                         "addl $16, %1\n"
+#if 0
+                         "movl $1,%0\n"
+                         
+                         "addl %1,%2\n"
+                         "movl %3,%%ecx\n"
+                         "shrl $2,%%ecx\n"
+                         "je LLC02a\n"
+                         "rep\n"
+                         "movsl\n"
+                         "andl $3,%3\n"
+                         "je LLB9\n"
+                         "LLC02a:\n"
+                         "movb (%2),%%bl\n"
+                         
+                         "movb %%bl,(%1)\n"
+                         "incl %1\n"
+                         "decl %3\n"
+                         "jnz LLC02a\n"
+                         "jmp LLB9\n"
+#else
+#if 0
+                         "movl $1,%0\n"
+                         "jnc  LLB8\n"
+#else
+                         "subl $16, %3\n"
+                         "jnc LLC01\n"
+#endif
+
+                         "addl $16, %3\n"
+                         "subl $4, %3\n"
+                         "jc  LLC03\n"
+#endif
+                         
+                         "LLC02:\n"
+                         "movl (%2,%1),%%ebx\n"
+                         "LLC5:\n"
+                         "movl %%ebx, (%1)\n"
+                         "addl $4, %1\n"
+                         "subl $4, %3\n"
+                         "jnc  LLC02\n"
+                         
+                         "LLC03:\n"
+                         "addl $4, %3\n"
+                         "jz LLC05\n"
+                         
+                         "LLC04:\n"
+                         "movb (%2,%1),%%bl\n"
+                         "LLC6:\n"
+                         "movb %%bl,(%1)\n"
+                         "incl %1\n"
+                         "decl %3\n"
+                         "jnz LLC04\n"
+                         
+                         "LLC05:\n"
+                         "movl $1,%0\n"
+                         "LLB9:"
+                         : "=m" (differs)
+                         : "D" (foo), "S" (bar), "r" (len), "b" (baz), "c" (uupzuq), "0" (differs) : "cc", "memory");
+    /* Now tell the compiler that foo, bar and len have been modified 
+     * If someone finds a way to express all this cleaner in constraints that
+     * GCC 2.7.2 understands, please FIXME */
+    __asm__ __volatile__ ("" : "=rm" (foo), "=rm" (bar), "=rm" (len) : :  "ebx", "ecx", "edx", "eax", "esi", "memory");
+
+    return differs;
+}
+
+#else
+struct flag_struct regflags;
+
+int fast_memcmp(const void *foo, const void *bar, int len)
+{
+    return memcmp(foo, bar, len);
+}
+
+int memcmpy(void *foo, const void *bar, int len)
+{
+    int differs = memcmp(foo, bar, len);
+    memcpy(foo, bar, len);
+    return differs;
+}
+
+#endif
+
+/* All the Win32 configurations handle this in od-win32/win32.c */
+#ifndef _WIN32
+
+#include <signal.h>
+
+static volatile frame_time_t last_time, best_time;
+static volatile int loops_to_go;
+
+#ifdef __cplusplus
+static RETSIGTYPE alarmhandler(...)
+#else
+static RETSIGTYPE alarmhandler(int foo)
+#endif
+{
+    frame_time_t bar;
+    bar = read_processor_time ();
+    if (bar - last_time < best_time)
+       best_time = bar - last_time;
+    if (--loops_to_go > 0) {
+       signal (SIGALRM, alarmhandler);
+       last_time = read_processor_time();
+       alarm (1);
+    }
+}
+
+#ifdef __cplusplus
+static RETSIGTYPE illhandler(...)
+#else
+static RETSIGTYPE illhandler(int foo)
+#endif
+{
+    rpt_available = 0;
+}
+
+void machdep_init (void)
+{
+    rpt_available = 1;
+    signal (SIGILL, illhandler);
+    read_processor_time ();
+    signal (SIGILL, SIG_DFL);
+    if (! rpt_available) {
+       fprintf (stderr, "Your processor does not support the RDTSC instruction.\n");
+       return;
+    }
+    fprintf (stderr, "Calibrating delay loop.. ");
+    fflush (stderr);
+    best_time = (frame_time_t)-1;
+    loops_to_go = 5;
+    signal (SIGALRM, alarmhandler);
+    /* We want exact values... */
+    sync (); sync (); sync ();
+    last_time = read_processor_time();
+    alarm (1);
+    while (loops_to_go != 0)
+       usleep (1000000);
+    fprintf (stderr, "ok - %.2f BogoMIPS\n",
+            ((double)best_time / 1000000), best_time);
+    vsynctime = best_time / 50;
+}
+
+#endif
diff --git a/od-win32/makeexe.bat b/od-win32/makeexe.bat
new file mode 100755 (executable)
index 0000000..875fef6
--- /dev/null
@@ -0,0 +1,18 @@
+del *.zip
+copy d:\amiga\winuae.exe d:\projects\winuae\distribution
+copy resourcedll\release\resourcedll.dll d:\amiga\WinUAE_default.dll
+makensis.exe winuae
+cd d:\projects\winuae\distribution
+copy docs\windows\translation.txt d:\amiga
+zip -9 -r d:\projects\winuae\src\od-win32\winuae.zip *
+cd d:\projects\winuae\src\od-win32
+copy installwinuae.exe d:\amiga\InstallWinUAE%1.exe
+copy winuae.zip d:\amiga\WinUAE%1.zip
+cd d:\amiga
+zip -9 WinUAE%1_translation WinUAE_default.dll translation.txt
+del WinUAE_default.dll
+del translation.txt
+zip -9 WinUAEMini%1 winuae_mini.exe
+cd d:\projects\winuae\src\od-win32
+del *.zip
+
diff --git a/od-win32/md-fpp.h b/od-win32/md-fpp.h
new file mode 100755 (executable)
index 0000000..82cd75d
--- /dev/null
@@ -0,0 +1,141 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * MC68881 emulation
+  *
+  * Conversion routines for hosts with unknown floating point format.
+  *
+  * Copyright 1996 Herman ten Brugge
+  */
+
+#ifndef HAVE_to_single
+STATIC_INLINE double to_single (uae_u32 value)
+{
+    double frac;
+
+    if ((value & 0x7fffffff) == 0)
+        return (0.0);
+    frac = (double) ((value & 0x7fffff) | 0x800000) / 8388608.0;
+    if (value & 0x80000000)
+        frac = -frac;
+    return (ldexp (frac, ((value >> 23) & 0xff) - 127));
+}
+#endif
+
+#ifndef HAVE_from_single
+STATIC_INLINE uae_u32 from_single (double src)
+{
+    int expon;
+    uae_u32 tmp;
+    double frac;
+
+    if (src == 0.0)
+        return 0;
+    if (src < 0) {
+        tmp = 0x80000000;
+        src = -src;
+    } else {
+        tmp = 0;
+    }
+    frac = frexp (src, &expon);
+    frac += 0.5 / 16777216.0;
+    if (frac >= 1.0) {
+        frac /= 2.0;
+        expon++;
+    }
+    if (expon <= -127) return 0;
+    if (expon >= 127) expon = 127;
+    return (tmp | (((expon + 127 - 1) & 0xff) << 23) |
+            (((int) (frac * 16777216.0)) & 0x7fffff));
+}
+#endif
+
+#ifndef HAVE_to_exten
+STATIC_INLINE double to_exten(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
+{
+    double frac;
+
+    if ((wrd1 & 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0)
+        return 0.0;
+    frac = (double) wrd2 / 2147483648.0 +
+        (double) wrd3 / 9223372036854775808.0;
+    if (wrd1 & 0x80000000)
+        frac = -frac;
+    return ldexp (frac, ((wrd1 >> 16) & 0x7fff) - 16383);
+}
+#endif
+
+#ifndef HAVE_from_exten
+STATIC_INLINE void from_exten(double src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3)
+{
+    int expon;
+    double frac;
+
+    if (src == 0.0) {
+        *wrd1 = 0;
+        *wrd2 = 0;
+        *wrd3 = 0;
+        return;
+    }
+    if (src < 0) {
+        *wrd1 = 0x80000000;
+        src = -src;
+    } else {
+        *wrd1 = 0;
+    }
+    frac = frexp (src, &expon);
+    frac += 0.5 / 18446744073709551616.0;
+    if (frac >= 1.0) {
+        frac /= 2.0;
+        expon++;
+    }
+    *wrd1 |= (((expon + 16383 - 1) & 0x7fff) << 16);
+    *wrd2 = (uae_u32) (frac * 4294967296.0);
+    *wrd3 = (uae_u32) (frac * 18446744073709551616.0 - *wrd2 * 4294967296.0);
+}
+#endif
+
+#ifndef HAVE_to_double
+STATIC_INLINE double to_double(uae_u32 wrd1, uae_u32 wrd2)
+{
+    double frac;
+
+    if ((wrd1 & 0x7fffffff) == 0 && wrd2 == 0)
+        return 0.0;
+    frac = (double) ((wrd1 & 0xfffff) | 0x100000) / 1048576.0 +
+        (double) wrd2 / 4503599627370496.0;
+    if (wrd1 & 0x80000000)
+        frac = -frac;
+    return ldexp (frac, ((wrd1 >> 20) & 0x7ff) - 1023);
+}
+#endif
+
+#ifndef HAVE_from_double
+STATIC_INLINE void from_double(double src, uae_u32 * wrd1, uae_u32 * wrd2)
+{
+    int expon;
+    int tmp;
+    double frac;
+
+    if (src == 0.0) {
+        *wrd1 = 0;
+        *wrd2 = 0;
+        return;
+    }
+    if (src < 0) {
+        *wrd1 = 0x80000000;
+        src = -src;
+    } else {
+        *wrd1 = 0;
+    }
+    frac = frexp (src, &expon);
+    frac += 0.5 / 9007199254740992.0;
+    if (frac >= 1.0) {
+        frac /= 2.0;
+        expon++;
+    }
+    tmp = (uae_u32) (frac * 2097152.0);
+    *wrd1 |= (((expon + 1023 - 1) & 0x7ff) << 20) | (tmp & 0xfffff);
+    *wrd2 = (uae_u32) (frac * 9007199254740992.0 - tmp * 4294967296.0);
+}
+#endif
diff --git a/od-win32/midi.c b/od-win32/midi.c
new file mode 100755 (executable)
index 0000000..e01ab2a
--- /dev/null
@@ -0,0 +1,833 @@
+/*
+ * MODULE:      midi.c
+ *
+ * DESCRIPTION: MIDI-handling code for MIDI-I/O.  Parses the MIDI-output stream and
+ *   sends system-exclusive MIDI-messages out using midiOutLongMsg(), while using 
+ *   midiOutShortMsg() for normal MIDI-messages.  MIDI-input is passed byte-for-byte
+ *   up to the Amiga's serial-port.
+ *
+ * AUTHOR:      Brian_King@CodePoet.com
+ *
+ * COPYRIGHT:   Copyright 1999, 2000 under GNU Public License
+ *
+ * HISTORY:
+ *   1999.09.05  1.0    Brian King      - creation
+ *   2000.01.30  1.1    Brian King      - addition of midi-input
+ *   2002.05.xx  1.2    Bernd Roesch    - sysex in/MTC/Song Position pointer add
+ */ 
+
+#include "config.h"
+#include "sysconfig.h"
+#include <windows.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#ifdef _MSC_VER
+#include <mmsystem.h>
+#include <ddraw.h>
+#else
+#include "winstuff.h"
+#endif
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <io.h>
+
+#include "sysdeps.h"
+#include "options.h"
+#include "parser.h"
+#include "midi.h"
+#include "resource.h"
+#include "win32gui.h"
+
+//#define TRACING_ENABLED
+
+#ifdef TRACING_ENABLED
+#define TRACE(x)       do { write_log x; } while(0)
+#else
+#define TRACE(x)
+#endif
+#define MIDI_INBUFFERS 800  //use 13 MB Buffer with this settings
+                            //on my system it work ok with 10 but who 
+                            //know when windows rest for a while
+                            //with sysex size of 40 win can 8 sec sleep
+#define INBUFFLEN 16000       //if this is not enough a warning come
+static int overflow,only_one_time;
+BOOL midi_ready = FALSE;
+BOOL midi_in_ready = FALSE;
+extern int serdev;
+
+static HMIDIIN inHandle;
+static MIDIHDR midiin[MIDI_INBUFFERS];
+
+static char *inbuffer[ MIDI_INBUFFERS ] = { 0, 0} ;
+static long inbufferlength[ MIDI_INBUFFERS ] = { 0,0};
+
+static int in_allocated = 0;
+
+/* MIDI OUTPUT */
+
+static MidiOutStatus out_status;
+static HMIDIOUT outHandle;
+static MIDIHDR midiout[ MIDI_BUFFERS ];
+
+static char *outbuffer[ MIDI_BUFFERS ] = { 0, 0} ;
+static long outbufferlength[ MIDI_BUFFERS ] = { 0,0 };
+static int outbufferselect = 0;
+static int out_allocated = 0;
+static volatile exitin = 0;
+static CRITICAL_SECTION cs_proc;
+/*
+ * FUNCTION:   getmidiouterr
+ *
+ * PURPOSE:    Wrapper for midiOutGetErrorText()
+ *
+ * PARAMETERS:
+ *   err       Midi-out error number
+ *
+ * RETURNS:
+ *   MidiOutErrorMsg char-ptr
+ *
+ * NOTES:      none
+ *
+ * HISTORY:
+ *   1999.09.06  1.0    Brian King             - Creation
+ *
+ */
+static char MidiOutErrorMsg[ 256 ];
+static char *getmidiouterr( int err )
+{
+    midiOutGetErrorText( err, MidiOutErrorMsg, 256 );
+    return MidiOutErrorMsg;
+}
+
+/*
+ * FUNCTION:   MidiOut_Alloc
+ *
+ * PURPOSE:    Allocate the double-buffering needed for processing midi-out messages
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS:
+ *   allocated - the number of buffers allocated
+ *
+ * NOTES:      none
+ *
+ * HISTORY:
+ *   1999.09.06  1.0    Brian King             - Creation
+ *
+ */
+static int MidiOut_Alloc( void )
+{
+    int i;
+
+    if( !out_allocated ) 
+    {
+        for( i = 0; i < MIDI_BUFFERS; i++ ) 
+        {
+            if( !outbuffer[ i ] ) 
+            {
+                outbuffer[ i ] = (char *)xmalloc( BUFFLEN );
+                if( outbuffer[ i ] )
+                {
+                    outbufferlength[ i ] = BUFFLEN;
+                    out_allocated++;
+                }
+                else
+                {
+                    outbufferlength[ i ] = 0;
+                }
+            }
+        }
+        outbufferselect = 0;
+    }
+    else
+    {
+        write_log( "MIDI: ERROR - MidiOutAlloc() called twice?\n" );
+    }
+    return( out_allocated );
+}
+
+/*
+ * FUNCTION:   MidiOut_Free
+ *
+ * PURPOSE:    Free the double-buffering needed for processing midi-out messages
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS:    none
+ *
+ * NOTES:      none
+ *
+ * HISTORY:
+ *   1999.09.06  1.0    Brian King             - Creation
+ *
+ */
+static void MidiOut_Free( void )
+{
+    int i;
+
+    for( i = 0; i < out_allocated; i++ )
+    {
+        if( outbuffer[ i ] ) 
+               {
+            //out_allocated--;
+            free( outbuffer[i] );
+            outbufferlength[ i ] = 0;
+            outbuffer[ i ] = NULL;
+        }
+    }
+    outbufferselect = 0;
+       out_allocated = 0;
+}
+
+/*
+ * FUNCTION:   MidiOut_PrepareHeader
+ *
+ * PURPOSE:    Wrapper for midiOutPrepareHeader
+ *
+ * PARAMETERS:
+ *   midihdr   - MIDIHDR-ptr which we will prepare
+ *   data      - byte-ptr to data which MIDIHDR will contain
+ *   length    - length of data
+ *
+ * RETURNS:
+ *   result    - 1 for success, 0 otherwise
+ *
+ * NOTES:      none
+ *
+ * HISTORY:
+ *   1999.08.02  1.0    Brian King             - Creation
+ *
+ */
+static int MidiOut_PrepareHeader( LPMIDIHDR out, LPSTR data, DWORD length )
+{
+    int result = 1;
+
+    out->lpData = data;
+    out->dwBufferLength = length;
+    out->dwBytesRecorded = length;
+    out->dwUser = 0;
+    out->dwFlags = 0;
+
+    if( ( result = midiOutPrepareHeader( outHandle, out, sizeof( MIDIHDR ) ) ) )
+    {
+        write_log( "MIDI: error %s / %d\n", getmidiouterr(result), result );
+        result = 0;
+    }
+    return result;
+}
+
+/* MIDI INPUT */
+
+
+/*
+ * FUNCTION:   getmidiinerr
+ *
+ * PURPOSE:    Wrapper for midiInGetErrorText()
+ *
+ * PARAMETERS:
+ *   err       Midi-in error number
+ *
+ * RETURNS:
+ *   MidiInErrorMsg char-ptr
+ *
+ * NOTES:      none
+ *
+ * HISTORY:
+ *   1999.09.06  1.0    Brian King             - Creation
+ *
+ */
+static char MidiInErrorMsg[ 256 ];
+static char *getmidiinerr( int err )
+{
+    midiInGetErrorText( err, MidiInErrorMsg, 256 );
+    return MidiInErrorMsg;
+}
+
+/*
+ * FUNCTION:   MidiIn_Alloc
+ *
+ * PURPOSE:    Allocate the double-buffering needed for processing midi-out messages
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS:
+ *   allocated - the number of buffers allocated
+ *
+ * NOTES:      none
+ *
+ * HISTORY:
+ *   1999.09.06  1.0    Brian King             - Creation
+ *
+ */
+static int MidiIn_Alloc( void )
+{
+    int i;
+
+    if( !in_allocated ) 
+    {
+        for( i = 0; i < MIDI_INBUFFERS; i++ ) 
+        {
+            if( !inbuffer[ i ] ) 
+                       {
+                inbuffer[ i ] = (char *)xmalloc( INBUFFLEN );
+                if( inbuffer[ i ] )
+                {
+                    inbufferlength[ i ] = INBUFFLEN;
+                    in_allocated++;
+                }
+                else
+                {
+                    inbufferlength[ i ] = 0;
+                }
+            }
+        }
+    }
+    else
+    {
+        write_log( "MIDI: ERROR - MidiInAlloc() called twice?\n" );
+    }
+    return( in_allocated );
+}
+
+/*
+ * FUNCTION:   MidiIn_Free
+ *
+ * PURPOSE:    Free the double-buffering needed for processing midi-in messages
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS:    none
+ *
+ * NOTES:      none
+ *
+ * HISTORY:
+ *   1999.09.06  1.0    Brian King             - Creation
+ *
+ */
+static void MidiIn_Free( void )
+{
+    int i;
+
+    for( i = 0; i < in_allocated; i++ )
+    {
+        if( inbuffer[ i ] ) 
+        {
+            //in_allocated--;
+            free( inbuffer[i] );
+            inbufferlength[ i ] = 0;
+            inbuffer[ i ] = NULL;
+        }
+    }
+       in_allocated = 0;
+       only_one_time = 0;
+}
+
+static unsigned char plen[128] = { 
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+    1,1,2,1,0,0,0,0,0,0,0,0,0,0,0,0
+};
+
+#define DBGOUT_MIDI_BYTE(x) TRACE(( "MIDI: 0x%02x\n", (x) ))
+
+/*
+ * FUNCTION:   Midi_Parse
+ *
+ * PURPOSE:    Parse the MIDI data-stream based on the direction.
+ *
+ * PARAMETERS:
+ *   direction - Either midi_input or midi_output
+ *   data      - byte of MIDI data
+ *
+ * RETURNS:    none
+ *
+ * NOTES:      Written with much assistance from Todor Fay of Blue Ribbon
+ *             (Bars'n'Pipes) fame.
+ *
+ * HISTORY:
+ *   1999.08.02  1.0    Brian King             - Creation
+ *
+ */
+int Midi_Parse( midi_direction_e direction, BYTE *dataptr )
+{
+    int result = 0;
+    static unsigned short bufferindex;
+    static char *bufferpoint = 0;
+
+    if( direction == midi_output )
+    {
+       BYTE data = *dataptr;
+        DBGOUT_MIDI_BYTE( data );
+        if( data >= 0x80 )
+        {
+            if( data >= MIDI_CLOCK )
+            {
+                switch( data )
+                {
+                    case MIDI_CLOCK:
+                                       
+                        TRACE(( "MIDI: MIDI_CLOCK\n" ));
+                    break;
+                    case MIDI_START:
+                                               
+                        TRACE(( "MIDI: MIDI_START\n" ));
+                    break;
+                    case MIDI_CONTINUE:
+                                       
+                        TRACE(( "MIDI: MIDI_CONTINUE\n" ));
+                    break;
+                    case MIDI_STOP:
+                                               
+                        TRACE(( "MIDI: MIDI_STOP\n" ));
+                    break;
+                    default:
+
+                    break;
+                }
+            }
+                       /*
+            else if( data == MIDI_MTC )
+            {
+                out_status.timecode = 1;
+            }
+                       */
+            else if( out_status.sysex )
+            {
+                if( out_allocated )
+                {
+                    bufferpoint[ bufferindex++ ] = (char)MIDI_EOX;
+                    if( bufferindex >= BUFFLEN )
+                        bufferindex = BUFFLEN - 1;
+                    out_status.status = MIDI_SYSX;
+                    // Flush this buffer using midiOutLongMsg
+                    MidiOut_PrepareHeader( &midiout[ outbufferselect ], bufferpoint, bufferindex );
+                    midiOutLongMsg( outHandle, &midiout[ outbufferselect ], sizeof( MIDIHDR ) );
+
+                    outbufferselect = !outbufferselect;
+                    bufferpoint = outbuffer[ outbufferselect ];
+                    midiOutUnprepareHeader( outHandle, &midiout[ outbufferselect ], sizeof( MIDIHDR ) );
+                }
+                out_status.sysex = 0; // turn off MIDI_SYSX mode
+                out_status.unknown = 1; // now in an unknown state
+                if( data == MIDI_EOX )
+                    return 0;
+            }
+            out_status.status = data;
+            out_status.length = plen[ data & 0x7F ];
+            out_status.posn = 0;
+            out_status.unknown = 0;
+            if( data == MIDI_SYSX )
+            {
+                out_status.sysex = 1; // turn on MIDI_SYSX mode
+                if( out_allocated )
+                {
+                    bufferindex = 0;
+                    bufferpoint = outbuffer[ outbufferselect ];
+                    bufferpoint[ bufferindex++ ] = (char)MIDI_SYSX;
+                }
+                return 0;
+            }
+        } // data & 0x80
+/*             
+        else if( out_status.timecode )
+        {
+            out_status.timecode = 0;
+            out_status.status = MIDI_MTC;
+            out_status.byte1 = data;
+            // process MIDI_MTC msg
+            write_log( "MIDI OUT: MIDI_MTC message\n" );
+            return 0;
+        }*/
+        else if( out_status.sysex )
+        {
+            if( out_allocated )
+            {
+                bufferpoint[ bufferindex++ ] = data;
+                if( bufferindex >= BUFFLEN )
+                    bufferindex = BUFFLEN - 1;
+            }
+            return 0;
+        }
+        else if( out_status.unknown )
+        {
+            return 0;
+        }
+        else if( ++out_status.posn == 1 )
+        {
+            out_status.byte1 = data;
+        }
+        else
+        {
+            out_status.byte2 = data;
+        }
+        if( out_status.posn >= out_status.length )
+        {
+            out_status.posn = 0;
+           /* if( out_status.status == MIDI_SONGPP )
+            {
+                // Handle this by doing a process-midi-clock ??
+                write_log( "MIDI OUT: MIDI_SONGPP message\n" );
+                return 0;
+            }
+            else*/
+            {
+                // flush the packet using midiOutShortMessage
+                DWORD shortMsg = MAKELONG( MAKEWORD( out_status.status, out_status.byte1 ), MAKEWORD( out_status.byte2, 0 ) );
+                midiOutShortMsg( outHandle, shortMsg );
+                               
+            }
+        }
+    }
+    else // handle input-data
+    {
+       
+    }
+    return result;
+}
+
+/*
+ * FUNCTION:   MidiIn support and Callback function
+ *
+ * PURPOSE:    Translate Midi in messages to raw serial data
+
+ * NOTES:      Sysex in not supported
+ */
+  
+static unsigned char midibuf[BUFFLEN];
+static long midi_inptr = 0,midi_inlast = 0;
+
+static void  add1byte(char w) //put 1 Byte to Midibuffer
+{
+       if(midi_inlast >= BUFFLEN - 10) {
+           TRACE(("add1byte buffer full (%02.2X)\n", w));
+           return;
+       }
+       midibuf[midi_inlast++] = w;
+}
+static void  add2byte(long w) //put 2 Byte to Midibuffer
+{
+       if(midi_inlast >= BUFFLEN - 10) {
+           TRACE(("add2byte buffer full (%04.4X)\n", w));
+           return;
+       }
+       midibuf[midi_inlast++] = (uae_u8)w;
+       w = w>>8;
+       midibuf[midi_inlast++] = (uae_u8)w;
+}
+static void  add3byte(long w) //put 3 Byte to Midibuffer
+{
+       if(midi_inlast >= BUFFLEN - 10) {
+           TRACE(("add3byte buffer full (%08.8X)\n", w));
+           return;
+       }
+       midibuf[midi_inlast++] = (uae_u8)w;
+       w = w>>8;
+       midibuf[midi_inlast++] = (uae_u8)w;
+       w = w>>8;
+       midibuf[midi_inlast++] = (uae_u8)w;
+}
+
+int ismidibyte(void)
+{
+    if (midi_inptr < midi_inlast) 
+       return 1;
+    return 0;
+}    
+
+LONG getmidibyte(void) //return midibyte or -1 if none
+{   
+    int i;
+    LONG rv;
+
+    EnterCriticalSection (&cs_proc);
+    if (overflow == 1)
+    {
+       char szMessage[ MAX_PATH ];
+       WIN32GUI_LoadUIString(IDS_MIDIOVERFLOW, szMessage, MAX_PATH );
+       gui_message( szMessage );
+       overflow = 0;
+    }
+    TRACE(("getmidibyte(%02.2X)\n", midibuf[midi_inptr]));
+    if (midibuf[midi_inptr] >= 0xf0) // only check for free buffers if status sysex 
+    {
+       for (i = 0;i < MIDI_INBUFFERS;i++)
+       {
+           if (midiin[i].dwFlags==(MHDR_DONE|MHDR_PREPARED)){
+                // add a buffer if one is free
+               /*  midiInUnprepareHeader( inHandle,&midiin[i], sizeof(MIDIHDR));
+                 midiin[i].dwBufferLength = INBUFFLEN-1;
+                 midiin[i].dwBytesRecorded = INBUFFLEN-1;
+                 midiin[i].dwUser = 0;
+                 midiin[i].dwFlags = 0;
+                 midiInPrepareHeader(inHandle,&midiin[i], sizeof(MIDIHDR));*/
+                 LeaveCriticalSection(&cs_proc);
+                 midiInAddBuffer(inHandle,&midiin[i],sizeof(MIDIHDR));
+                 EnterCriticalSection(&cs_proc);
+           }   
+       }
+    }
+    if (midi_inptr < midi_inlast) 
+    {
+       rv = midibuf[midi_inptr++];
+    }  
+    else
+    {
+       midi_inptr = midi_inlast = 0;
+       rv = -1;
+    }
+    LeaveCriticalSection(&cs_proc);
+    return rv;
+}
+
+static void CALLBACK MidiInProc(HMIDIIN hMidiIn,UINT wMsg,DWORD dwInstance,DWORD dwParam1,DWORD dwParam2)    
+{
+       EnterCriticalSection (&cs_proc);
+       if(wMsg == MIM_ERROR)
+       {
+               TRACE(("MIDI Data Lost\n"));
+       }
+       if(wMsg == MIM_LONGDATA)
+       {
+               LPMIDIHDR midiin = (LPMIDIHDR)dwParam1;
+               static long synum;
+               TRACE(("MIM_LONGDATA %d\n", midiin->dwBytesRecorded));
+               if (exitin == 1) goto end;    //for safeness midi want close
+               if ((midi_inlast+midiin->dwBytesRecorded) >= (BUFFLEN-6))
+               {
+                       overflow = 1;
+                       TRACE(("MIDI overflow1\n"));
+                       //for safeness if buffer too full (should not occur)
+                       goto end;
+               }
+
+               if (midiin->dwBufferLength == midiin->dwBytesRecorded)
+               {
+               //for safeness if buffer too full (should not occur)
+                       overflow = 1;
+                       TRACE(("MIDI overflow2\n"));
+                       goto end;
+               }
+
+               memcpy(&midibuf[midi_inlast], midiin->lpData, midiin->dwBytesRecorded);
+               midi_inlast = midi_inlast + midiin->dwBytesRecorded;
+
+
+       }
+
+       if(wMsg == MM_MIM_DATA)
+       {
+               BYTE state = (BYTE)dwParam1;
+               TRACE(("MM_MIM_DATA %08.8X\n", dwParam1));
+               if(state == 254) goto end;
+               if(state < 0xf0) state = state & 0xf0;
+               //else {add1byte(state); goto end;}
+               switch (state)
+               {       
+                       case 0x80: //Note OFF
+                       add3byte(dwParam1);
+                       break;
+                       case 0x90: // Note On
+                       add3byte(dwParam1);
+                       break;
+                       case 0xa0: // Poly Press
+                       add3byte(dwParam1);
+                       break;
+                       case 0xb0: //CTRL Change
+                       add3byte(dwParam1);
+                       break;
+                       case 0xc0:  //ProgramChange
+                       add2byte(dwParam1);
+                       break;
+                       case 0xd0:   //ChanPress
+                       add2byte(dwParam1);
+                       break;
+                       case 0xe0:   //PitchBend
+                       add3byte(dwParam1);
+                       break;
+    //System Common Messages
+                       case 0xf1:   //QuarterFrame-message ... MIDI_Time_Code
+                       add2byte(dwParam1);
+                       break;
+                       case 0xf2:   //Song Position
+                       add3byte(dwParam1);
+                       break;
+                       case 0xf3:   //Song Select
+                       add2byte(dwParam1);
+                       break;
+                       case 0xf6:   //Tune Request
+                       add3byte(dwParam1);
+                       break;
+//System Real Time Messages
+                       case 0xf8:   //MIDI-Clock
+                       add1byte((char)dwParam1);
+                       break;
+                       case 0xfa:   //Start
+                       add1byte((char)dwParam1);
+                       break;
+                       case 0xfb:   //Continue
+                       add1byte((char)dwParam1);
+                       break;
+                       case 0xfc:   //Stop
+                       add1byte((char)dwParam1);
+                       break;
+                       case 0xfe:   //Active Sense (selden used)
+                       add1byte((char)dwParam1);
+                       break;
+                       case 0xff:   //Reset (selden used)
+                       add2byte(dwParam1);
+                       break;
+
+               }
+       }
+end:
+       LeaveCriticalSection(&cs_proc);
+  }
+/*
+ * FUNCTION:   Midi_Open
+ *
+ * PURPOSE:    Open the desired MIDI handles (output, and possibly input)
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS:
+ *   result    - 1 for success, 0 for failure
+ *
+ * NOTES:      none
+ *
+ * HISTORY:
+ *   1999.08.02  1.0    Brian King             - Creation
+ *
+ */
+int Midi_Open( void )
+{
+    unsigned long result = 0,i;
+    
+    if( ( result = midiOutOpen( &outHandle, currprefs.win32_midioutdev, 0, 0,CALLBACK_NULL ) ) )
+    {
+        write_log( "MIDI OUT: error %s / %d while opening port %d\n", getmidiouterr(result), result, currprefs.win32_midioutdev );
+        result = 0;
+    }
+    else
+    {
+        InitializeCriticalSection(&cs_proc);
+       // We don't need input for output...
+        if( ( currprefs.win32_midiindev >= 0 ) && 
+           ( result = midiInOpen( &inHandle, currprefs.win32_midiindev, (DWORD_PTR)MidiInProc, 0, CALLBACK_FUNCTION|MIDI_IO_STATUS) ) )
+        {
+            write_log( "MIDI IN: error %s / %d while opening port %d\n", getmidiinerr(result), result, currprefs.win32_midiindev );
+        }
+        else
+        {
+               
+               midi_in_ready = TRUE;
+           result=midiInStart(inHandle);
+       }
+       
+       if( MidiOut_Alloc() )
+       {
+           if( midi_in_ready )
+           {
+                       if( !MidiIn_Alloc() )
+                       {
+                   midiInClose( inHandle );
+                   midi_in_ready = FALSE; 
+                       }
+                       else
+                       {
+                         for (i=0;i<MIDI_INBUFFERS;i++)
+                         {
+                         midiin[i].lpData = inbuffer[i];
+                         midiin[i].dwBufferLength = INBUFFLEN-1;
+                         midiin[i].dwBytesRecorded = INBUFFLEN-1;
+                         midiin[i].dwUser = 0;
+                         midiin[i].dwFlags = 0;
+                         result=midiInPrepareHeader(inHandle,&midiin[i], sizeof(MIDIHDR));
+                         result=midiInAddBuffer(inHandle,&midiin[i],sizeof(MIDIHDR));
+                         }
+                                                       }
+               }
+               midi_ready = TRUE;
+           result = 1;
+           serdev = 1;
+       }
+       else
+       {
+           midiOutClose( outHandle );
+           if( midi_in_ready )
+           {
+               midiInClose( inHandle );
+               midi_in_ready = FALSE;
+           }
+           result = 0;
+           DeleteCriticalSection(&cs_proc);
+       }
+    }
+    return result;
+}
+
+/*
+ * FUNCTION:   Midi_Close
+ *
+ * PURPOSE:    Close all opened MIDI handles
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS:    none
+ *
+ * NOTES:      none
+ *
+ * HISTORY:
+ *   1999.08.02  1.0    Brian King             - Creation
+ *
+ */
+void Midi_Close( void )
+{
+    int i;
+    if( midi_ready )
+    {
+       midiOutReset(outHandle);
+       for( i = 0; i < MIDI_BUFFERS; i++ )
+       {
+           while( MIDIERR_STILLPLAYING == midiOutUnprepareHeader( outHandle, &midiout[i], sizeof(MIDIHDR) ) )
+               {
+               Sleep(100);
+           }
+       }
+               MidiOut_Free();
+       midiOutClose( outHandle );
+
+       if( midi_in_ready )
+       {
+           
+               
+               //while( MIDIERR_STILLPLAYING == midiInUnprepareHeader( inHandle, &midiin, sizeof(MIDIHDR)) )
+               exitin=1;//for safeness sure no callback come now
+               midiInReset(inHandle);
+                 for (i=0;i<MIDI_INBUFFERS;i++)
+                 {
+             midiInUnprepareHeader( inHandle,&midiin[i], sizeof(MIDIHDR));
+                 }
+           MidiIn_Free();
+           midiInClose( inHandle );
+           midi_in_ready = FALSE;
+               exitin = 0;
+       }
+       midi_ready = FALSE;
+       {
+           //Bernd Roesch:
+           //need for camd Midi Stuff(it close midi and reopen it but serial.c think the baudrate
+           //is the same and do not open midi), so setting serper to different value helps
+           extern  uae_u16 serper;
+           serper = 0x30;
+       }
+       write_log( "MIDI: closed.\n" );
+       DeleteCriticalSection(&cs_proc);
+    }
+}
diff --git a/od-win32/midi.h b/od-win32/midi.h
new file mode 100755 (executable)
index 0000000..a137c23
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * MODULE: midi.h
+ * AUTHOR: Brian King
+ * COPYRIGHT: Copyright 1999 under GNU Public License
+ * VERSION: 1.0
+ */
+#ifndef __MIDI_H__
+#define __MIDI_H__
+
+#define MIDI_BUFFERS 2
+#define BUFFLEN 32766
+
+#define MAXTEMPO        350
+#define MINTEMPO        10
+
+#define MIDI_NOTEOFF    0x80
+#define MIDI_NOTEON     0x90
+#define MIDI_PTOUCH     0xA0
+#define MIDI_CCHANGE    0xB0
+#define MIDI_PCHANGE    0xC0
+#define MIDI_MTOUCH     0xD0
+#define MIDI_PBEND      0xE0
+#define MIDI_SYSX       0xF0
+#define MIDI_MTC        0xF1
+#define MIDI_SONGPP     0xF2
+#define MIDI_SONGS      0xF3
+#define MIDI_EOX        0xF7
+#define MIDI_CLOCK      0xF8
+#define MIDI_START      0xFA
+#define MIDI_CONTINUE   0xFB
+#define MIDI_STOP       0xFC
+#define MIDI_SENSE      0xFE
+
+typedef struct mos
+{
+    BYTE status;
+    BYTE byte1;
+    BYTE byte2;
+    int length;
+    int posn;
+    int sysex;
+    int timecode;
+    int unknown;
+} MidiOutStatus;
+
+typedef enum
+{
+    midi_input,
+    midi_output
+} midi_direction_e;
+
+extern BOOL midi_ready;
+
+extern int Midi_Parse (midi_direction_e direction, BYTE *c);
+extern int Midi_Open (void);
+extern void Midi_Close (void);
+extern LONG getmidibyte(void);
+extern int ismidibyte(void);
+
+#endif
+
diff --git a/od-win32/midiin.c b/od-win32/midiin.c
new file mode 100755 (executable)
index 0000000..c982aac
--- /dev/null
@@ -0,0 +1,681 @@
+#include <intuition/intuition.h>
+#include <hardware/custom.h>
+#include <exec/ports.h>
+#include <exec/interrupts.h>
+#include <exec/memory.h>
+#include <exec/execbase.h>
+#include <proto/exec.h>
+#include <proto/graphics.h>
+#include <proto/intuition.h>
+#include <hardware/intbits.h>
+#include "/v.h"
+#include <tools.h>
+#include <libraries/dos.h>
+#include <string.h>
+
+struct MIDITool {
+    struct Tool tool;
+    unsigned short status;
+    unsigned short lownote, highnote;
+};
+
+static struct ToolMaster master;
+
+extern struct Functions *functions;
+
+static UWORD chip MidiIn[]=
+{
+/*-------- plane # 0 --------*/
+
+  0x0000,  0x0000,
+  0xffff,  0xfc00,
+  0xc000,  0x0c00,
+  0xc000,  0x0c00,
+  0xc000,  0x0c00,
+  0xc000,  0x0c00,
+  0xc400,  0x4c00,
+  0xc102,  0x0c00,
+  0xc030,  0x0c00,
+  0xc000,  0x0c00,
+  0xffff,  0xfc00,
+  0x0000,  0x0000,
+
+/*-------- plane # 1 --------*/
+
+  0x0000,  0x0000,
+  0x0000,  0x0c00,
+  0x3e31,  0xfc00,
+  0x3030,  0x3c00,
+  0x2000,  0x1f00,
+  0x0000,  0x0f00,
+  0x0000,  0x0f00,
+  0x2000,  0x1f00,
+  0x3000,  0x3c00,
+  0x3e01,  0xfc00,
+  0x7fff,  0xfc00,
+  0x0000,  0x0000
+};
+
+static struct Image MidiInimage=
+{
+  0,0,24,12,2,
+  MidiIn,
+  0x3,0x0,NULL
+};
+
+#define BUFFLEN 32766
+
+extern struct Custom far custom;
+
+static gettime(short lasttime)
+
+{
+    unsigned long time = ((custom.vhposr & 0xFF00) >> 8);
+    time += (custom.vposr << 8);
+    time &= 0x7FFF;
+    if (time == 0x1FF) time = lasttime;
+    return(time);
+}
+
+static short max;
+
+static void setmax()
+
+{
+    short i = max;
+    Disable();
+    max = gettime(0);
+    for (;;) {
+        i = gettime(i);
+        if (i >= max) max = i;
+        else break;
+    }
+    max -= 2;
+    Enable();
+}
+
+static short lasttime;
+
+static void reset()
+
+{
+    lasttime = gettime(lasttime);
+}
+
+static timeout()
+
+{
+    short newtime = gettime(lasttime);
+    if (newtime < lasttime) newtime += max;
+    return (newtime > (lasttime + 60));
+}
+
+    
+
+static char *buffer[2] = { 0, 0} ;
+static long bufferlength[2] = { 0,0 };
+static char bufferselect = 0;
+static char allocated = 0;
+
+allocbuffers()
+
+{
+    struct Track *track = functions->tracklist;
+    struct MIDITool *tool;
+    short sysex = 0;
+    short i;
+    for (;track;track = track->next) {
+        tool = (struct MIDITool *) track->toollist;
+        if (tool->tool.toolid == ID_MDIN) {
+            sysex |= tool->status;
+        }
+    }
+    if (sysex & 128) {
+        if (allocated < 2) {
+            for (i=0;i<2;i++) {
+                if (!buffer[i]) {
+                    buffer[i] = (char *) (*functions->myalloc)(BUFFLEN,MEMF_PUBLIC);
+                    if (buffer[i]) {
+                        bufferlength[i] = BUFFLEN;
+                        allocated++;
+                    }
+                    else bufferlength[i] = 0;
+                }
+            }
+            bufferselect = 0;
+        }
+    }
+    else {
+        if (allocated) {
+            for (i=0;i<2;i++) {
+                if (buffer[i]) {
+                    allocated--;
+                    (*functions->myfree)(buffer[i],bufferlength[i]);
+                    bufferlength[i] = 0;
+                    buffer[i] = 0;
+                }
+            }
+            bufferselect = 0;
+        }
+        allocated = 0;
+    }
+    return(allocated);
+}
+
+struct Tool *createtoolcode(copy)
+
+struct MIDITool *copy;
+
+{
+    struct MIDITool *tool;
+    tool = (struct MIDITool *) 
+        (*functions->myalloc)(sizeof(struct MIDITool),MEMF_CLEAR);
+    if (tool) {
+        if (copy) {
+            memcpy((char *)tool,(char *)copy,sizeof(struct MIDITool));
+            tool->tool.next = 0;
+            if (tool->status & 128) allocbuffers();
+        }
+        tool->tool.tooltype = TOOL_INPUT;
+        tool->tool.toolid = ID_MDIN;
+        tool->status = 0x7F;
+        tool->tool.touched = TOUCH_INIT;
+    }
+    return((struct Tool *)tool);
+}
+
+void deletetoolcode(tool)
+
+struct MIDITool *tool;
+
+{
+    if (tool->status & 128) {
+        tool->status = 0;
+        allocbuffers();
+    }
+    (*functions->myfree)(tool,sizeof(struct MIDITool));
+}
+
+extern struct NewWindow midiinNewWindowStructure1;
+
+static struct Menu TitleMenu = {
+    NULL,0,0,0,0,MENUENABLED,0,NULL
+};
+
+
+void edittoolcode(tool)
+
+struct MIDITool *tool;
+
+{
+    register struct IntuiMessage *message;
+    register struct Window *window;
+    register long class, code;
+    struct Gadget *gadget;
+    struct NewWindow *newwindow;
+    char menuname[100];
+    midiinNewWindowStructure1.Screen = functions->screen;
+    if (tool->tool.touched & TOUCH_EDIT) {
+        midiinNewWindowStructure1.LeftEdge = tool->tool.left;
+        midiinNewWindowStructure1.TopEdge = tool->tool.top;
+        midiinNewWindowStructure1.Width = tool->tool.width;
+        midiinNewWindowStructure1.Height = tool->tool.height;
+    }
+    if (!(tool->tool.touched & TOUCH_INIT)) tool->status = 0x7F;
+    newwindow = (struct NewWindow *) 
+        (*functions->DupeNewWindow)(&midiinNewWindowStructure1);
+    if (!newwindow) return;
+    newwindow->Title = 0;
+    newwindow->Flags |= BORDERLESS;
+    newwindow->Flags &= ~0xF;
+    window = (struct Window *) (*functions->FlashyOpenWindow)(newwindow);
+    if (!window) return;
+    (*functions->EmbossWindowOn)(window,WINDOWCLOSE|WINDOWDEPTH|WINDOWDRAG,
+        "Midi In",-1,-1,0,0);
+    tool->tool.window = window;
+    (*functions->EmbossOn)(window,1,1);
+    (*functions->EmbossOn)(window,2,1);
+    (*functions->EmbossOn)(window,3,1);
+    (*functions->EmbossOn)(window,4,1);
+    (*functions->EmbossOn)(window,5,1);
+    (*functions->EmbossOn)(window,6,1);
+    (*functions->EmbossOn)(window,7,1);
+    (*functions->SelectEmbossed)(window,1,tool->status & 1);
+    (*functions->SelectEmbossed)(window,2,tool->status & 4);
+    (*functions->SelectEmbossed)(window,3,tool->status & 8);
+    (*functions->SelectEmbossed)(window,4,tool->status & 16);
+    (*functions->SelectEmbossed)(window,5,tool->status & 32);
+    (*functions->SelectEmbossed)(window,6,tool->status & 64);
+    (*functions->SelectEmbossed)(window,7,tool->status & 128);
+    strcpy(menuname,"MIDI In v2.2 Â© 1991,1992 The Blue Ribbon SoundWorks");
+    TitleMenu.MenuName = menuname;
+    SetMenuStrip(window,&TitleMenu);
+    for (;;) {
+        message = (struct IntuiMessage *)(*functions->GetIntuiMessage)(window);
+        class = message->Class;
+        code = message->Code;
+        gadget = (struct Gadget *) message->IAddress;
+        class = (*functions->SystemGadgets)(window,class,gadget,code);
+        ReplyMsg((struct Message *)message);
+        if (class == CLOSEWINDOW) break;
+        else if (class == GADGETUP) {
+            class = gadget->GadgetID;
+            switch (class) {
+                case 1 :
+                    tool->status ^= 3;
+                    (*functions->SelectEmbossed)(window,1,tool->status & 1);
+                    break;
+                case 2 :
+                case 3 :
+                case 4 :
+                case 5 :
+                case 6 :
+                case 7 :
+                    class = 1 << (class);
+                    tool->status ^= class;
+                    if (class & 128) {
+                        if (!allocbuffers() && (tool->status & 128))
+                            tool->status &= ~128;
+                    }
+                    (*functions->SelectEmbossed)
+                        (window,gadget->GadgetID,tool->status & class);
+                    break;
+            }
+        }
+    }
+    ClearMenuStrip(window);
+    (*functions->EmbossOff)(window,1);
+    (*functions->EmbossOff)(window,2);
+    (*functions->EmbossOff)(window,3);
+    (*functions->EmbossOff)(window,4);
+    (*functions->EmbossOff)(window,5);
+    (*functions->EmbossOff)(window,6);
+    (*functions->EmbossOff)(window,7);
+    (*functions->EmbossWindowOff)(window);
+    tool->tool.window = 0;
+    tool->tool.left = window->LeftEdge;
+    tool->tool.top = window->TopEdge;
+    tool->tool.width = window->Width;
+    tool->tool.height = window->Height;
+    tool->tool.touched = TOUCH_INIT | TOUCH_EDIT;
+    (*functions->FlashyCloseWindow)(window);
+    (*functions->DeleteNewWindow)(newwindow);
+}
+
+struct Event *processeventcode(event)
+
+struct Event *event;
+
+{
+    event->tool = event->tool->next;
+    return(event);
+}
+
+extern long stdout;
+
+static struct Interrupt midiintin;
+
+static unsigned char plen[128] = { 
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+    1,1,2,1,0,0,0,0,0,0,0,0,0,0,0,0
+};
+
+/*printstring(string)
+
+struct String *string;
+
+{
+    short i;
+    unsigned long j;
+    if (string) {
+        dprintf("Length: %ld\n",string->length);
+        for (i=0;i<string->length;i++) {
+            j = string->string[i];
+            j &= 0xFF;
+            dprintf("%lx ",j);
+        }
+    }
+    else dprintf("No string");
+    dprintf("\n");
+}
+*/
+static struct Event eventarray[32];
+static unsigned short eventindex = 0;
+extern printf();
+
+struct Task *eventtask;
+long eventsignal;
+
+static void eventcode()
+
+{
+    register struct Event *event;
+    register unsigned short index;
+    register struct Track *track;
+    register struct Event *copy;
+    register struct MIDITool *tool;
+    register char channel;
+    register unsigned char status;
+    struct StringEvent *stringevent;
+    eventsignal = 1 << AllocSignal(-1);
+    index = 0;
+    for (;;) {
+        Wait(eventsignal);
+        for (;index != eventindex;) {
+            event = &eventarray[index];
+            status = 1 << ((event->status >> 4) - 8);
+            if (status == 2) {
+                if (!event->byte1) {
+                    index++;
+                    index &= 0x1F;
+                    continue;
+                }
+                if (event->byte2 && functions->remotecontrol[event->byte1]) {
+                    if (functions->processinputevent) {
+                        (*functions->processinputevent)
+                            (functions->remotecontrol[event->byte1]);
+                        index++;
+                        index &= 0x1F;
+                        continue;
+                    }
+                }
+            }
+            if (status == 128) {
+                if (functions->multiin) {
+                    for (track = functions->tracklist;track;track = track->next) {
+                        tool = (struct MIDITool *) track->toollist;
+                        if (tool->tool.toolid == ID_MDIN) {
+                            if (tool->status & 128) break;
+                        }
+                    }
+                }
+                else track = master.intrack;
+                if (track) {
+                    tool = (struct MIDITool *) track->toollist;
+                    stringevent = (struct StringEvent *) 
+                        (*functions->fastallocevent)();
+                    if (stringevent) {
+                        stringevent->type = EVENT_SYSX;
+                        stringevent->tool = tool->tool.next;
+                        stringevent->time = event->time;
+                        if (!event->tool) {
+                            index++;
+                            index &= 0x1F;
+                            continue;
+                        }
+                        stringevent->string = (struct String *)
+                            (*functions->myalloc)(event->data + 3,0);
+                        if (stringevent->string) {
+                            stringevent->string->length = event->data + 2;
+                            memcpy(stringevent->string->string,event->tool,
+                                event->data);
+                        }
+                        stringevent->status = MIDI_SYSX;
+                        (*functions->qevent)(stringevent);
+                    }
+                }
+                index++;
+                index &= 0x1F;
+                continue;
+            }
+            if (functions->multiin) {
+                channel = event->status & 15;
+                track = (struct Track *) functions->tracklist;
+                for (;track;track = track->next) {
+                    tool = (struct MIDITool *) track->toollist;
+                    if (tool && (tool->tool.toolid == ID_MDIN) && 
+                        (tool->status & status)) {
+                        if (track->channelin == channel) {
+                            break;
+                        }
+                    }
+                }
+            }
+            else {
+                track = master.intrack;
+            }
+            if (track) {
+                tool = (struct MIDITool *) track->toollist;
+                if (tool && (tool->tool.toolid == ID_MDIN) &&
+                    (tool->status & status)) {
+                    copy = (struct Event *) (*functions->fastallocevent)();
+                    if (copy) {
+                        copy->type = EVENT_VOICE;
+                        copy->tool = tool->tool.next;
+                        copy->status = (event->status & 0xF0);
+                        copy->byte1 = event->byte1;
+                        copy->byte2 = event->byte2;
+                        if (copy->status == MIDI_NOTEON) {
+                            if (!copy->byte2) copy->status = MIDI_NOTEOFF;
+                        }
+                        copy->time = event->time;
+                        (*functions->qevent)(copy);
+                    }
+                }
+            }
+            index++;
+            index &= 0x1F;
+            continue;
+        }
+    }
+}
+
+
+static void midiincode()
+
+/*      Midi in interrupt code.
+*/
+
+{
+    static unsigned char midiinlen;
+    static unsigned char midiinpos;
+    static char unknownstatus = 1;
+    static unsigned char sysexon = 0;
+    static unsigned char miditimecode = 0;
+    register struct Event *event;
+    static unsigned char status;
+    register unsigned short data;
+    struct Event timeevent;
+
+    static unsigned short bufferindex;
+    static char *bufferpoint = 0;
+
+    for (data = custom.serdatr;;data = custom.serdatr) {
+        if (!(data & 0x4000)) {
+            if (sysexon && master.readsysex && !timeout()) continue;
+            return;
+        }
+        if (data & 0x8000) unknownstatus = 1;
+        if (sysexon && master.readsysex) reset();
+        event = &eventarray[eventindex];
+        custom.intreq = INTF_RBF;
+        data &= 0xFF;
+        if (data & 0x80) {
+            if (data >= MIDI_CLOCK) {
+                if (data == MIDI_CLOCK) {
+                    timeevent.status = MIDI_CLOCK;
+                    if (functions->midiclock) 
+                        (*functions->processmidiclock)(&timeevent);
+                    continue;
+                }
+                if (data == MIDI_START) {
+                    timeevent.status = MIDI_START;
+                    if (functions->midiclock) 
+                        (*functions->processmidiclock)(&timeevent);
+                    continue;
+                }
+                if (data == MIDI_CONTINUE) {
+                    timeevent.status = MIDI_CONTINUE;
+                    if (functions->midiclock) 
+                        (*functions->processmidiclock)(&timeevent);
+                    continue;
+                }
+                if (data == MIDI_STOP) {
+                    timeevent.status = MIDI_STOP;
+                    if (functions->midiclock) 
+                        (*functions->processmidiclock)(&timeevent);
+                    continue;
+                }
+                continue;
+            }
+            else if (data == MIDI_MTC) {
+                miditimecode = 1;
+                continue;
+            }
+            else if (sysexon) {  /* End of Sysex. */
+                if (master.readsysex) {
+                    (*master.readsysex)(MIDI_EOX);
+                }
+                else if (allocated) {
+                    bufferpoint[bufferindex++] = MIDI_EOX;
+                    if (bufferindex >= BUFFLEN) bufferindex = (BUFFLEN - 1);
+                    eventindex++;
+                    eventindex &= 0x1F;
+                    event->status = MIDI_SYSX;
+                    event->time = functions->timenow;
+                    event->byte1 = bufferselect;
+                    event->data = bufferindex;
+                    event->tool = (struct Tool *) bufferpoint;
+                    Signal(eventtask,eventsignal);
+                    bufferselect = !bufferselect;
+                    if (bufferselect >= allocated) bufferselect = 0;
+                    bufferpoint = buffer[bufferselect];
+                }
+                sysexon = 0;
+                unknownstatus = 1;
+                if (data == MIDI_EOX) continue;
+            } 
+            status = data;
+            midiinlen = plen[data & 0x7F];
+            midiinpos = 0;
+            unknownstatus = 0;
+            if (data == MIDI_SYSX) {
+                sysexon = 1;
+                if (master.readsysex) {
+                    reset();
+                    (*master.readsysex)(MIDI_SYSX);
+                }
+                else if (allocated) {
+                    bufferindex = 0;
+                    bufferpoint = buffer[bufferselect];
+                    bufferpoint[bufferindex++] = MIDI_SYSX;
+                }
+                continue;
+            }
+        }
+        else if (miditimecode) {
+//          if (functions->smpteclock) {
+                timeevent.status = MIDI_MTC;
+                timeevent.byte1 = data;
+                (*functions->processsmpteclock)(&timeevent);
+//          }
+            miditimecode = 0;
+            continue;
+        }
+        else if (sysexon) {
+            if (master.readsysex) {
+                (*master.readsysex)(data);
+            }
+            else if (allocated) {
+                bufferpoint[bufferindex++] = data;
+                if (bufferindex >= BUFFLEN) bufferindex = (BUFFLEN - 1);
+            }
+            continue;
+        }
+        else if (unknownstatus) {
+            continue;
+        }
+        else if (++midiinpos == 1) event->byte1 = data;
+        else event->byte2 = data;
+        if (midiinpos >= midiinlen) {
+            event->status = status;
+            midiinpos = 0;
+            if (status == MIDI_SONGPP) {
+                if (functions->midiclock) 
+                    (*functions->processmidiclock)(event);
+                continue;
+            }
+            else {
+                eventindex++;
+                eventindex &= 0x1F;
+                event->time = functions->timenow;
+                Signal(eventtask,eventsignal);
+                continue;
+            }
+        }
+    }
+}
+\f
+
+void stealint();
+struct Interrupt *oldserin = 0;
+
+static void releaseint()
+
+{
+    custom.intena = INTF_RBF;
+    Disable();
+    SetIntVector(INTB_RBF,oldserin);
+    Enable();
+    if (oldserin) custom.intena = INTF_SETCLR | INTF_RBF;
+    functions->releasemidi = 0;
+    functions->stealmidi = stealint;
+}
+
+void removetoolcode()
+
+{
+    releaseint();
+    DeleteTask(eventtask);
+    functions->stealmidi = 0;
+}
+
+void stealint()
+
+{
+    midiintin.is_Node.ln_Name = "Midi receiver";
+    midiintin.is_Node.ln_Pri = 20;
+    midiintin.is_Node.ln_Type = NT_INTERRUPT;
+    midiintin.is_Code = midiincode;
+    Disable();
+    oldserin = (struct Interrupt *) SetIntVector(INTB_RBF,&midiintin);
+    Enable();
+    custom.serper = 114; 
+    custom.intena = INTF_SETCLR | INTF_RBF;
+    functions->releasemidi = releaseint;
+    functions->stealmidi = 0;
+}
+
+struct ToolMaster *inittoolmaster()
+
+{
+    midiintin.is_Node.ln_Name = "Midi receiver";
+    midiintin.is_Node.ln_Pri = 20;
+    midiintin.is_Node.ln_Type = NT_INTERRUPT;
+    midiintin.is_Code = midiincode;
+    eventtask = CreateTask("midi in",40,eventcode,4000);
+    if (functions->releasemidi) {
+        (*functions->releasemidi)();
+    }
+    functions->releasemidi = releaseint;
+    stealint();
+    memset((char *)&master,0,sizeof(struct ToolMaster));
+    master.toolid = ID_MDIN;
+    master.image = &MidiInimage;
+    strcpy(master.name,"MIDI In");
+    master.edittool = edittoolcode;
+    master.processevent = processeventcode;
+    master.createtool = createtoolcode;
+    master.deletetool = deletetoolcode;
+    master.tooltype = TOOL_INPUT | TOOL_MIDI;
+    master.toolsize = sizeof(struct MIDITool);
+    master.removetool = removetoolcode;
+    setmax();
+    return(&master);
+}
diff --git a/od-win32/mman.c b/od-win32/mman.c
new file mode 100755 (executable)
index 0000000..a05eb40
--- /dev/null
@@ -0,0 +1,320 @@
+// Implement mprotect() for Win32
+// Copyright (C) 2000, Brian King
+// GNU Public License
+
+#include <float.h>
+
+#include "sysconfig.h" 
+#include "sysdeps.h"
+#include "sys/mman.h"
+#include "include/memory.h"
+#include "options.h"
+#include "autoconf.h"
+
+static struct shmid_ds shmids[ MAX_SHMID ];
+static uae_u32 gfxoffs;
+
+uae_u32 natmem_offset = 0;
+
+void init_shm( void )
+{
+    int i;
+    LPVOID blah = NULL;
+#if 0
+    LPBYTE address = NULL; // Let the system decide where to put the memory...
+#else
+    LPBYTE address = (LPBYTE)0x10000000; // Letting the system decide doesn't seem to work on some systems
+#endif
+
+    canbang = 0;
+    gfxoffs = 0;
+    shm_start = 0;
+    for( i = 0; i < MAX_SHMID; i++ )
+    {
+       shmids[i].attached = 0;
+       shmids[i].key = -1;
+       shmids[i].size = 0;
+       shmids[i].addr = NULL;
+       shmids[i].name[0] = 0;
+    }
+    while( address < (LPBYTE)0xa0000000 )
+    {
+        blah = VirtualAlloc( address, 0x19000000, MEM_RESERVE, PAGE_EXECUTE_READWRITE );
+        if( blah == NULL )
+        {
+           address += 0x01000000;
+       }
+        else
+        {
+           natmem_offset = (uae_u32)blah + 0x1000000;
+           break;
+       }
+    }
+    if( natmem_offset )
+    {
+       write_log( "NATMEM: Our special area is 0x%x\n", natmem_offset );
+       VirtualFree( blah, 0, MEM_RELEASE );
+       canbang = 1;
+    }
+    else
+    {
+       write_log( "NATMEM: No special area could be allocated!\n" );
+    }
+}
+
+void mapped_free(uae_u8 *mem)
+{
+    shmpiece *x = shm_start;
+    while( x )
+    {
+       if( mem == x->native_address )
+           shmdt( x->native_address);
+       x = x->next;
+    }
+    x = shm_start;
+    while( x )
+    {
+       struct shmid_ds blah;
+       if( mem == x->native_address )
+       {
+           if( shmctl( x->id, IPC_STAT, &blah ) == 0 )
+           {
+               shmctl( x->id, IPC_RMID, &blah );
+           }
+           else
+           {
+               //free( x->native_address );
+               VirtualFree((LPVOID)mem, 0, MEM_DECOMMIT |MEM_RELEASE );
+           }
+       }
+       x = x->next;
+    }
+}
+
+static key_t get_next_shmkey( void )
+{
+    key_t result = -1;
+    int i;
+    for( i = 0; i < MAX_SHMID; i++ )
+    {
+       if( shmids[i].key == -1 )
+       {
+           shmids[i].key = i;
+           result = i;
+           break;
+       }
+    }
+    return result;
+}
+
+STATIC_INLINE key_t find_shmkey( key_t key )
+{
+    int result = -1;
+    if( shmids[key].key == key )
+    {
+       result = key;
+    }
+    return result;
+}
+
+int mprotect(void *addr, size_t len, int prot)
+{
+    int result = 0;
+  
+    return result;
+}
+
+void *shmat(int shmid, LPVOID shmaddr, int shmflg)
+{ 
+    void *result = (void *)-1;
+    BOOL got = FALSE;
+       
+#ifdef NATMEM_OFFSET
+    int size=shmids[shmid].size;
+    extern uae_u32 allocated_z3fastmem;
+    if(shmids[shmid].attached )
+       return shmids[shmid].attached;
+    if (shmaddr<natmem_offset){
+       if(!strcmp(shmids[shmid].name,"chip"))
+       {
+           shmaddr=natmem_offset;
+           got = TRUE;
+           if(!currprefs.fastmem_size)
+               size+=32;
+       }
+       if(!strcmp(shmids[shmid].name,"kick"))
+       {
+           shmaddr=natmem_offset+0xf80000;
+           got = TRUE;
+           size+=32;
+       }
+       if(!strcmp(shmids[shmid].name,"rom_e0"))
+       {
+           shmaddr=natmem_offset+0xe00000;
+           got = TRUE;
+       }
+       if(!strcmp(shmids[shmid].name,"rom_f0"))
+       {
+           shmaddr=natmem_offset+0xf00000;
+           got = TRUE;
+       }
+       if(!strcmp(shmids[shmid].name,"rtarea"))
+       {
+           shmaddr=natmem_offset+RTAREA_BASE;
+           got = TRUE;
+           size+=32;
+       }
+       if(!strcmp(shmids[shmid].name,"fast"))
+       {
+           shmaddr=natmem_offset+0x200000;
+           got = TRUE;
+           size+=32;
+       }
+       if(!strcmp(shmids[shmid].name,"z3")) {
+           shmaddr=natmem_offset+0x10000000;
+           if (allocated_z3fastmem<0x1000000)
+               gfxoffs=0x1000000;
+           else
+               gfxoffs=allocated_z3fastmem;
+           got = TRUE;
+       }
+       if(!strcmp(shmids[shmid].name,"gfx"))
+       {
+           shmaddr=natmem_offset+0x10000000+gfxoffs;
+           got = TRUE;
+           size+=32;
+           result=malloc(size);
+           shmids[shmid].attached=result;
+           return result;
+       }
+       if(!strcmp(shmids[shmid].name,"bogo"))
+       {
+           shmaddr=natmem_offset+0x00C00000;
+           got = TRUE;
+           size+=32;
+       }
+       if(!strcmp(shmids[shmid].name,"filesys"))
+       {
+           result=natmem_offset+0x10000;
+           shmids[shmid].attached=result;
+           return result;
+       }
+}
+#endif
+    
+    if( ( shmids[shmid].key == shmid ) && shmids[shmid].size )
+    {
+       got = FALSE;
+       if (got == FALSE) {
+           if (shmaddr)
+           {
+               result=(void*)VirtualFree(shmaddr,0,MEM_RELEASE);
+           }
+           result =VirtualAlloc(shmaddr,size,MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE );
+           if( result == NULL )
+           {
+               result = (void *)-1;
+           }
+           else
+           {
+               shmids[shmid].attached=result; 
+           }
+       } else {
+           shmids[shmid].attached = shmaddr;
+           result = shmaddr;
+       }
+    }
+    return result;
+}
+
+int shmdt(const void *shmaddr)
+{
+    return 0;
+}
+
+int shmget(key_t key, size_t size, int shmflg, char *name)
+{
+    int result = -1;
+
+    if( ( key == IPC_PRIVATE ) ||
+       ( ( shmflg & IPC_CREAT ) && ( find_shmkey( key ) == -1) ) )
+    {
+       write_log( "shmget of size %d for %s\n", size, name );
+       if( ( result = get_next_shmkey() ) != -1 )
+    {
+               
+        //blah = VirtualAlloc( 0, size,MEM_COMMIT, PAGE_EXECUTE_READWRITE );
+
+               shmids[result].size = size;
+               strcpy( shmids[result].name, name );
+           }
+               
+           else
+           {
+               result = -1;
+           }
+    }
+    return result;
+}
+
+int shmctl(int shmid, int cmd, struct shmid_ds *buf)
+{
+    int result = -1;
+
+    if( ( find_shmkey( shmid ) != -1 ) && buf )
+    {
+       switch( cmd )
+       {
+           case IPC_STAT:
+               *buf = shmids[shmid];
+               result = 0;
+           break;
+           case IPC_RMID:
+               shmids[shmid].key = -1;
+               shmids[shmid].name[0] = '\0';
+               shmids[shmid].size = 0;
+               result = 0;
+           break;
+       }
+    }
+    return result;
+}
+
+int isinf( double x )
+{
+#ifdef _MSC_VER
+    const int nClass = _fpclass(x);
+    int result;
+    if (nClass == _FPCLASS_NINF || nClass == _FPCLASS_PINF)  result = 1;
+    else
+ result = 0;
+#else
+    int result = 0;
+#endif
+
+    return result;
+}
+
+int isnan( double x )
+{
+#ifdef _MSC_VER
+    int result = _isnan(x);
+#else
+    int result = 0;
+#endif
+
+    return result;
+}
+
+void cache_free(void *cache)
+{
+    VirtualFree (cache, 0, MEM_RELEASE);
+}
+
+void *cache_alloc(int size)
+{
+    uae_u8 *cache;
+    cache = VirtualAlloc (NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+    return cache;
+}
+
diff --git a/od-win32/mman2.c b/od-win32/mman2.c
new file mode 100755 (executable)
index 0000000..9c4ccb4
--- /dev/null
@@ -0,0 +1,238 @@
+// Implement mprotect() for Win32
+// Copyright (C) 2000, Brian King
+// GNU Public License
+
+#include "sysconfig.h" 
+#include "sysdeps.h"
+#include "sys/mman.h"
+#include "include/memory.h"
+#include "options.h"
+#include <float.h>
+#include "autoconf.h"
+
+static struct shmid_ds shmids[ MAX_SHMID ];
+
+uae_u32 natmem_offset = 0;
+
+void init_shm( void )
+{
+    int i;
+    LPTSTR string = NULL;
+#if 0
+    LPBYTE address = NULL; // Let the system decide where to put the memory...
+#else
+    LPBYTE address = (LPBYTE)0x10000000; // Letting the system decide doesn't seem to work on some systems
+#endif
+
+    for( i = 0; i < MAX_SHMID; i++ ) {
+       shmids[i].attached = 0;
+       shmids[i].key = -1;
+       shmids[i].size = 0;
+       shmids[i].addr = NULL;
+       shmids[i].name[0] = 0;
+    }
+    natmem_offset = 0;
+     while( address < (LPBYTE)0x20000000 ) {
+       if (VirtualAlloc( address, 0x18800000, MEM_RESERVE, PAGE_EXECUTE_READWRITE )) {
+           natmem_offset = (uae_u32)address;
+           break;
+       }
+       address += 0x01000000;
+    }
+    if (natmem_offset) {
+       write_log( "NATMEM: Our special area is 0x%x\n", natmem_offset );
+       canbang = 1;
+       VirtualFree (natmem_offset, 0, MEM_RELEASE);
+    } else {
+       write_log( "NATMEM: No special area could be allocated!\n" );
+    }
+}
+
+static key_t get_next_shmkey( void )
+{
+    key_t result = -1;
+    int i;
+    for( i = 0; i < MAX_SHMID; i++ )
+    {
+       if( shmids[i].key == -1 )
+       {
+           shmids[i].key = i;
+           result = i;
+           break;
+       }
+    }
+    return result;
+}
+
+STATIC_INLINE key_t find_shmkey( key_t key )
+{
+    int result = -1;
+    if( shmids[key].key == key )
+    {
+       result = key;
+    }
+    return result;
+}
+
+int mprotect(void *addr, size_t len, int prot)
+{
+    int result = 0;
+  
+    return result;
+}
+
+void *shmat(int shmid, LPVOID shmaddr, int shmflg)
+{ 
+    char *result = (void *)-1;
+    BOOL locked = FALSE;
+       
+#ifdef NATMEM_OFFSET
+    int size=shmids[shmid].size;
+    extern uae_u32 allocated_z3fastmem;
+    if(shmids[shmid].attached )
+       return shmids[shmid].attached;
+    if (shmaddr<natmem_offset){
+       if(!strcmp(shmids[shmid].name,"chip"))
+       {
+           shmaddr=natmem_offset;
+           if(!currprefs.fastmem_size)
+               size+=32;
+       }
+       if(!strcmp(shmids[shmid].name,"kick"))
+       {
+           shmaddr=natmem_offset+0xf80000;
+           size+=32;
+       }
+       if(!strcmp(shmids[shmid].name,"rom_e0"))
+       {
+           shmaddr=natmem_offset+0xe00000;
+           size+=32;
+       }
+       if(!strcmp(shmids[shmid].name,"rom_f0"))
+       {
+           shmaddr=natmem_offset+0xf00000;
+           size+=32;
+       }
+       if(!strcmp(shmids[shmid].name,"rtarea"))
+       {
+           shmaddr=natmem_offset+RTAREA_BASE;
+           size+=32;
+       }
+       if(!strcmp(shmids[shmid].name,"fast"))
+       {
+           shmaddr=natmem_offset+0x200000;
+           size+=32;
+       }
+       if(!strcmp(shmids[shmid].name,"z3")) {
+           shmaddr=natmem_offset+0x10000000;
+       }
+       if(!strcmp(shmids[shmid].name,"gfx"))
+       {
+           shmaddr=natmem_offset+0x10000000+allocated_z3fastmem;
+           size+=32;
+       }
+       if(!strcmp(shmids[shmid].name,"bogo"))
+       {
+           shmaddr=natmem_offset+0x00C00000;
+           size+=32;
+       }
+    }
+#endif
+    
+    if( ( shmids[shmid].key == shmid ) && shmids[shmid].size )
+    {
+       if (shmaddr)
+       {
+           result=VirtualFree(shmaddr,0,MEM_RELEASE);
+       }
+       
+        result = VirtualAlloc(shmaddr,size,MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE );
+       if( result == NULL )
+       {
+           result = (void *)-1;
+       }
+       else
+       {
+           shmids[shmid].attached=result; 
+           //memset(result,0,size);
+       }
+    }
+    return result;
+}
+
+int shmdt(const void *shmaddr)
+{
+
+    return 0;
+}
+
+int shmget(key_t key, size_t size, int shmflg, char *name)
+{
+    int result = -1;
+
+    if( ( key == IPC_PRIVATE ) ||
+       ( ( shmflg & IPC_CREAT ) && ( find_shmkey( key ) == -1) ) )
+    {
+       write_log( "shmget of size %d for %s\n", size, name );
+       if( ( result = get_next_shmkey() ) != -1 )
+    {
+               shmids[result].size = size;
+               strcpy( shmids[result].name, name );
+           }
+               
+           else
+           {
+               result = -1;
+           }
+    }
+    return result;
+}
+
+int shmctl(int shmid, int cmd, struct shmid_ds *buf)
+{
+    int result = -1;
+
+    if( ( find_shmkey( shmid ) != -1 ) && buf )
+    {
+       switch( cmd )
+       {
+           case IPC_STAT:
+               *buf = shmids[shmid];
+               result = 0;
+           break;
+           case IPC_RMID:
+               shmids[shmid].key = -1;
+               shmids[shmid].name[0] = '\0';
+               shmids[shmid].size = 0;
+               result = 0;
+           break;
+       }
+    }
+    return result;
+}
+
+int isinf( double x )
+{
+#ifdef _MSC_VER
+    const int nClass = _fpclass(x);
+    int result;
+    if (nClass == _FPCLASS_NINF || nClass == _FPCLASS_PINF)  result = 1;
+    else
+ result = 0;
+#else
+    int result = 0;
+#endif
+
+    return result;
+}
+
+int isnan( double x )
+{
+#ifdef _MSC_VER
+    int result = _isnan(x);
+#else
+    int result = 0;
+#endif
+
+    return result;
+}
diff --git a/od-win32/opengl.c b/od-win32/opengl.c
new file mode 100755 (executable)
index 0000000..94baaf6
--- /dev/null
@@ -0,0 +1,467 @@
+/* 
+ * UAE - The Un*x Amiga Emulator
+ *
+ * OpenGL renderer
+ *
+ * Copyright 2002 Toni Wilen
+ */
+
+#include <windows.h>
+#include "sysconfig.h"
+#include "sysdeps.h"
+#include "config.h"
+#include "options.h"
+#include "xwin.h"
+#include "dxwrap.h"
+#include "opengl.h"
+#include "custom.h"
+#include "win32.h"
+#include "win32gfx.h"
+#include "gfxfilter.h"
+
+#ifdef OPENGL
+
+#include <gl\gl.h>
+#include <gl\glu.h>
+
+typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval);
+typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void);
+
+/* not defined in MSVC's opengl.h */
+#ifndef GL_UNSIGNED_SHORT_5_5_5_1_EXT
+#define GL_UNSIGNED_SHORT_5_5_5_1_EXT       0x8034
+#endif
+#ifndef GL_UNSIGNED_SHORT_4_4_4_4_EXT
+#define GL_UNSIGNED_SHORT_4_4_4_4_EXT       0x8033
+#endif
+
+static GLint max_texture_size;
+static GLint tex[4];
+static GLint scanlinetex;
+static int total_textures;
+static int required_texture_size;
+static int required_sl_texture_size;
+static GLint ti2d_internalformat, ti2d_format, ti2d_type;
+static GLint sl_ti2d_internalformat, sl_ti2d_format, sl_ti2d_type;
+static int w_width, w_height, t_width, t_height;
+static int packed_pixels;
+static int doublevsync;
+static int ogl_enabled;
+
+static HDC openglhdc;
+static HGLRC hrc;
+static HWND hwnd;
+static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
+static PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT;
+
+static PIXELFORMATDESCRIPTOR pfd;
+
+static void testerror (char *s)
+{
+    for (;;) {
+       GLint err = glGetError();
+       if (err == 0)
+           return;
+       write_log ("OpenGL error %d (%s)\n", err, s);
+    }
+}
+
+static int exact_log2 (int v)
+{
+    int l = 0;
+    while ((v >>= 1) != 0)
+       l++;
+    return l;
+}
+
+const char *OGL_init (HWND ahwnd, int w_w, int w_h, int t_w, int t_h, int depth)
+{
+    int PixelFormat;
+    const char *ext1;
+    static char errmsg[100] = { 0 };
+    static int init;
+
+    ogl_enabled = 0;
+    if (currprefs.gfx_filter != UAE_FILTER_OPENGL) {
+       strcpy (errmsg, "OPENGL: not enabled");
+       return errmsg;
+    }
+
+    w_width = w_w;
+    w_height = w_h;
+    t_width = t_w;
+    t_height = t_h;
+
+    memset (&pfd, 0, sizeof (pfd));
+    pfd.nSize = sizeof (PIXELFORMATDESCRIPTOR);
+    pfd.nVersion = 1;
+    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
+    pfd.cColorBits = depth;
+    pfd.cDepthBits = 0;
+    pfd.iLayerType = PFD_MAIN_PLANE;
+
+    hwnd = ahwnd;
+    openglhdc = GetDC (hwnd);
+    total_textures = 2;
+
+    if (currprefs.gfx_afullscreen && WIN32GFX_GetDepth (TRUE) < 15) {
+       strcpy (errmsg, "OPENGL: display depth must be at least 15 bit");
+       return errmsg;
+    }
+
+    if (!(PixelFormat = ChoosePixelFormat (openglhdc, &pfd))) {
+        strcpy (errmsg, "OPENGL: can't find suitable pixelformat");
+       return errmsg;
+    }
+    
+    if (!SetPixelFormat (openglhdc, PixelFormat, &pfd)) {
+        strcpy (errmsg, "OPENGL: can't set pixelformat");
+        return errmsg;
+    }
+    
+    if (!(hrc = wglCreateContext (openglhdc))) {
+        strcpy (errmsg, "OPENGL: can't create gl rendering context");
+        return errmsg;
+    }
+    
+    if (!wglMakeCurrent (openglhdc, hrc)) {
+        strcpy (errmsg, "OPENGL: can't activate gl rendering context");
+        return errmsg;
+    }
+    
+    glGetIntegerv (GL_MAX_TEXTURE_SIZE, &max_texture_size);
+    required_texture_size = 2 << exact_log2 (t_width > t_height ? t_width : t_height);
+    if (max_texture_size < t_width || max_texture_size < t_height) {
+       sprintf (errmsg, "OPENGL: %d * %d or bigger texture support required\nYour card's maximum texture size is only %d * %d",
+           required_texture_size, required_texture_size, max_texture_size, max_texture_size);
+       return errmsg;
+    }
+    required_sl_texture_size = 2 << exact_log2 (w_width > w_height ? w_width : w_height);
+    if (currprefs.gfx_filter_scanlines > 0 && (max_texture_size < w_width || max_texture_size < w_height)) {
+       gui_message ("OPENGL: %d * %d or bigger texture support required for scanlines (max is only %d * %d)\n"
+           "Scanlines disabled.",
+           required_sl_texture_size, required_sl_texture_size, max_texture_size, max_texture_size);
+       changed_prefs.gfx_filter_scanlines = currprefs.gfx_filter_scanlines = 0;
+    }
+
+    ext1 = glGetString (GL_EXTENSIONS);
+    if (!init)
+       write_log("OpenGL extensions: %s\n", ext1);
+    if (strstr (ext1, "EXT_packed_pixels"))
+       packed_pixels = 1;
+    if (strstr (ext1, "WGL_EXT_swap_control")) {
+       wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
+       wglGetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC)wglGetProcAddress("wglGetSwapIntervalEXT");
+       if (!wglGetSwapIntervalEXT || !wglSwapIntervalEXT) {
+           write_log ("OPENGL: WGL_EXT_swap_control extension found but no wglGetSwapIntervalEXT or wglSwapIntervalEXT found!?\n");
+           wglSwapIntervalEXT = 0;
+           wglGetSwapIntervalEXT = 0;
+       }
+
+    }
+
+    sl_ti2d_internalformat = GL_RGBA4;
+    sl_ti2d_format = GL_RGBA;
+    sl_ti2d_type = GL_UNSIGNED_SHORT_4_4_4_4_EXT;
+    ti2d_type = -1;
+    if (depth == 15 || depth == 16) {
+       if (!packed_pixels) {
+           gui_message (
+               "OPENGL: can't use 15/16 bit screen depths because EXT_packed_pixels extension was not found.\n"
+               "Falling back to 32-bit mode");
+           depth = 32;
+       }   
+       ti2d_internalformat = GL_RGB5_A1;
+        ti2d_format = GL_RGBA;
+        ti2d_type = GL_UNSIGNED_SHORT_5_5_5_1_EXT;
+    }
+    if (depth == 32) {
+       ti2d_internalformat = GL_RGBA;
+       ti2d_format = GL_RGBA;
+       ti2d_type = GL_UNSIGNED_BYTE;
+       if (!packed_pixels) {
+           sl_ti2d_internalformat = GL_RGBA;
+           sl_ti2d_format = GL_RGBA;
+           sl_ti2d_type = GL_UNSIGNED_BYTE;
+       }
+    }
+    if (ti2d_type < 0) {
+       sprintf (errmsg, "OPENGL: Only 15, 16 or 32 bit screen depths supported (was %d)", depth);
+       return errmsg;
+    }
+    
+    glGenTextures (total_textures, tex);
+
+    /* "bitplane" texture */
+    glBindTexture (GL_TEXTURE_2D, tex [0]);
+    glTexImage2D (GL_TEXTURE_2D, 0, ti2d_internalformat,
+       required_texture_size, required_texture_size,0,  ti2d_format, ti2d_type, 0);
+
+    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+    glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+    glClearColor (0.0, 0.0, 0.0, 0.0);
+    glShadeModel (GL_FLAT); 
+    glDisable (GL_DEPTH_TEST);
+    glEnable (GL_TEXTURE_2D);
+    glDisable (GL_LIGHTING);
+    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+    ogl_enabled = 1;
+    OGL_resize (w_width, w_height);
+    OGL_refresh ();
+    init = 1;
+
+    write_log("OPENGL: using texture depth %d texture size %d * %d scanline texture size %d * %d\n",
+       depth, required_texture_size, required_texture_size, required_sl_texture_size, required_sl_texture_size);
+    return 0;
+}
+
+static void createscanlines (int force)
+{
+    int x, y, yy;
+    uae_u8 *sld, *p;
+    int sl4, sl8, sl42, sl82;
+    int l1, l2;
+    static int osl1, osl2, osl3;
+
+    if (osl1 == currprefs.gfx_filter_scanlines && osl3 == currprefs.gfx_filter_scanlinelevel && osl2 == currprefs.gfx_filter_scanlineratio && !force)
+       return;
+    osl1 = currprefs.gfx_filter_scanlines;
+    osl3 = currprefs.gfx_filter_scanlinelevel;
+    osl2 = currprefs.gfx_filter_scanlineratio;
+    if (!currprefs.gfx_filter_scanlines) {
+        glDisable (GL_BLEND);
+       return;
+    }   
+
+    glEnable (GL_BLEND);
+    scanlinetex = tex[total_textures - 1];
+    glBindTexture (GL_TEXTURE_2D, scanlinetex);
+    glTexImage2D (GL_TEXTURE_2D, 0, sl_ti2d_internalformat,
+        required_sl_texture_size, required_sl_texture_size, 0, sl_ti2d_format, sl_ti2d_type, 0);
+    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+    glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+    sl4 = currprefs.gfx_filter_scanlines * 16 / 100;
+    sl8 = currprefs.gfx_filter_scanlines * 256 / 100;
+    sl42 = currprefs.gfx_filter_scanlinelevel * 16 / 100;
+    sl82 = currprefs.gfx_filter_scanlinelevel * 256 / 100;
+    if (sl4 > 15) sl4 = 15;
+    if (sl8 > 255) sl8 = 255;
+    if (sl42 > 15) sl42 = 15;
+    if (sl82 > 255) sl82 = 255;
+    sld = malloc (w_width * w_height * 4);
+    memset (sld, 0, w_width * w_height * 4);
+    l1 = currprefs.gfx_filter_scanlineratio & 15;
+    l2 = currprefs.gfx_filter_scanlineratio >> 4;
+    if (!l1) l1 = 1;
+    if (!l2) l2 = 1;
+    for (y = 1; y < w_height; y += l1 + l2) {
+       for (yy = 0; yy < l2 && y + yy < w_height; yy++) {
+           for (x = 0; x < w_width; x++) {
+               if (packed_pixels) {
+                   /* 16-bit, R4G4B4A4 */
+                   uae_u8 sll = sl42;
+                   p = &sld[((y + yy) * w_width + x) * 2];
+                   p[0] = sl4 | (sll << 4);
+                   p[1] = (sll << 4) | (sll << 0);
+               } else {
+                   /* 32-bit, R8G8B8A8 */
+                   p = &sld[((y + yy) * w_width + x) * 4];
+                   p[0] = p[1] = p[2] = sl82;
+                   p[3] = sl8;
+               }
+           }
+       }
+    }
+    glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, w_width, w_height, sl_ti2d_format, sl_ti2d_type, sld);
+    free (sld);
+}
+
+static void setfilter (void)
+{
+    int filtering;
+    switch (currprefs.gfx_filter_filtermode & 1)
+    {
+       case 0:
+       filtering = GL_NEAREST;
+       break;
+       case 1:
+       default:
+       filtering = GL_LINEAR;
+       break;
+    }
+    if (currprefs.gfx_filter_scanlines > 0) {
+        glBindTexture (GL_TEXTURE_2D, scanlinetex);
+       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
+       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
+    }
+    glBindTexture (GL_TEXTURE_2D, tex[0]);
+    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
+    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
+}
+
+static void OGL_swapinterval (void)
+{
+    doublevsync = 0;
+    if (wglSwapIntervalEXT) {
+       int i1, i2;
+       i1 = (currprefs.gfx_vsync > 0 && currprefs.gfx_afullscreen) ? (currprefs.gfx_refreshrate > 85 ? 2 : 1) : 0;
+       if (turbo_emulation) i1 = 0;
+       wglSwapIntervalEXT (i1);
+       i2 = wglGetSwapIntervalEXT ();
+       if (i1 == 2 && i2 < i1) /* did display driver support SwapInterval == 2 ? */
+           doublevsync = 1; /* nope, we must wait for vblank twice */
+    }
+}
+
+void OGL_resize (int width, int height)
+{
+    if (!ogl_enabled)
+       return;
+
+    w_width = width;
+    w_height = height;
+    glViewport (0, 0, w_width, w_height);
+    glMatrixMode (GL_PROJECTION);
+    glLoadIdentity ();
+    glOrtho (0.0f, w_width, w_height, 0, -1.0f, 1.0f);
+    createscanlines (1);
+    setfilter ();
+    OGL_swapinterval ();
+}
+
+static void OGL_dorender (int newtex)
+{
+    float x1, y1, x2, y2;
+    uae_u8 *data = gfxvidinfo.bufmem;
+    int fx, fy, xm, ym;
+
+    xm = currprefs.gfx_lores ? 2 : 1;
+    ym = currprefs.gfx_linedbl ? 1 : 2;
+    if (w_width >= 1024)
+       xm *= 2;
+    else if (w_width < 500)
+       xm /= 2;
+    if (w_height >= 960)
+       ym *= 2;
+    else if (w_height < 350)
+       ym /= 2;
+    fx = (t_width * xm - w_width) / 2;
+    fy = (t_height * ym - w_height) / 2;
+
+    glClear (GL_COLOR_BUFFER_BIT);
+    glMatrixMode (GL_MODELVIEW);
+    glLoadIdentity ();
+
+    x1 = (float)(w_width * currprefs.gfx_filter_horiz_offset / 100.0);
+    y1 = (float)(w_height * currprefs.gfx_filter_vert_offset / 100.0);
+    x2 = x1 + (float)((required_texture_size * w_width / t_width) * (currprefs.gfx_filter_horiz_zoom + 100) / 100.0);
+    y2 = y1 + (float)((required_texture_size * w_height / t_height) * (currprefs.gfx_filter_vert_zoom + 100)/ 100.0);
+    x1 -= fx; y1 -= fy;
+    x2 += 2 * fx; y2 += 2 * fy;
+
+    glBindTexture (GL_TEXTURE_2D, tex[0]);
+    if (newtex)
+       glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, t_width, t_height, ti2d_format, ti2d_type, data);
+
+    glBegin (GL_QUADS);
+    glTexCoord2f (0, -1.0f); glVertex2f (x1, y1);
+    glTexCoord2f (0, 0); glVertex2f (x1, y2);
+    glTexCoord2f (1.0f, 0); glVertex2f (x2, y2);
+    glTexCoord2f (1.0f, -1.0f); glVertex2f (x2, y1);
+    glEnd();
+
+    if (currprefs.gfx_filter_scanlines > 0) {
+       float v = (float)required_sl_texture_size;
+       glBindTexture (GL_TEXTURE_2D, scanlinetex);
+       glBegin (GL_QUADS);
+        glTexCoord2f (0, -1.0f); glVertex2f (0, 0);
+       glTexCoord2f (0, 0); glVertex2f (0, v);
+       glTexCoord2f (1.0f, 0); glVertex2f (v, v);
+       glTexCoord2f (1.0f, -1.0f); glVertex2f (v, 0);
+       glEnd();
+    }
+}
+
+void OGL_render (void)
+{
+    if (!ogl_enabled)
+       return;
+
+    OGL_dorender (1);
+    SwapBuffers (openglhdc);
+    if (doublevsync) {
+       OGL_dorender (0);
+       SwapBuffers (openglhdc);
+    }
+}
+
+void OGL_refresh (void)
+{
+    if (!ogl_enabled)
+       return;
+
+    createscanlines (0);
+    setfilter ();
+    OGL_swapinterval ();
+    OGL_render ();
+ }
+
+void OGL_getpixelformat (int depth,int *rb, int *gb, int *bb, int *rs, int *gs, int *bs, int *ab, int *as, int *a)
+{
+    switch (depth)
+    {
+       case 32:
+        *rb = 8;
+       *gb = 8;
+       *bb = 8;
+       *ab = 8;
+       *rs = 0;
+       *gs = 8;
+       *bs = 16;
+       *as = 24;
+       *a = 255;
+       break;
+       case 15:
+       case 16:
+        *rb = 5;
+       *gb = 5;
+       *bb = 5;
+       *ab = 1;
+       *rs = 11;
+       *gs = 6;
+       *bs = 1;
+       *as = 0;
+       *a = 1;
+       break;
+    }
+}
+
+void OGL_free (void)
+{
+    if (hrc) {
+        wglMakeCurrent (NULL, NULL);
+        wglDeleteContext (hrc);
+        hrc = 0;
+    }
+    if (openglhdc) {
+       ReleaseDC (hwnd, openglhdc);
+       openglhdc = 0;
+    }
+    ogl_enabled = 0;
+}
+
+HDC OGL_getDC (HDC hdc)
+{
+    return openglhdc;
+}
+
+int OGL_isenabled (void)
+{
+    return ogl_enabled;
+}
+
+#endif
diff --git a/od-win32/opengl.h b/od-win32/opengl.h
new file mode 100755 (executable)
index 0000000..870c2b4
--- /dev/null
@@ -0,0 +1,9 @@
+
+extern void OGL_resize (int width, int height);
+extern void OGL_free ();
+extern const char *OGL_init (HWND ahwnd, int w_w, int w_h, int t_w, int t_h, int depth);
+extern void OGL_render (void);
+extern void OGL_getpixelformat (int depth,int *rb, int *bb, int *gb, int *rs, int *bs, int *gs, int *ab, int *ar, int *a);
+extern void OGL_refresh (void);
+extern HDC OGL_getDC (HDC hdc);
+extern int OGL_isenabled (void);
diff --git a/od-win32/osdep/exectasks.h b/od-win32/osdep/exectasks.h
new file mode 100755 (executable)
index 0000000..9baccd1
--- /dev/null
@@ -0,0 +1,51 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Stack magic definitions for autoconf.c
+  *
+  * Copyright 1997 Bernd Schmidt
+  */
+
+#include <setjmp.h>
+
+#define CAN_DO_STACK_MAGIC
+
+#ifdef CAN_DO_STACK_MAGIC
+#ifdef __GNUC__
+static inline void transfer_control(void *, int, void *, void *, int) __attribute__((noreturn));
+static inline void transfer_control(void *s, int size, void *pc, void *f, int has_retval)
+#else
+__declspec(noreturn) static __forceinline void transfer_control(void *s, int size, void *pc, void *f, int has_retval)
+#endif
+{
+    unsigned long *stacktop = (unsigned long *)((char *)s + size - 20);
+    stacktop[0] = 0xC0DEDBAD; /* return address */
+    stacktop[1] = (int)s; /* function arg 1: stack */
+    stacktop[2] = (int)f; /* function arg 2: trap function */
+    stacktop[3] = (int)stacktop; /* function arg 3: return value address */
+    stacktop[4] = has_retval;
+#ifdef __GNUC__
+    __asm__ __volatile__ ("movl %0,%%esp\n\tpushl %1\n\tret\n" : : "r" (stacktop), "r" (pc) : "memory");
+#elif defined( _MSC_VER ) /* VisualC++ */
+    __asm
+    {
+        mov    esp, stacktop
+        push   pc
+        ret
+    }
+#endif
+    /* Not reached. */
+    abort();
+}
+
+static __inline__ uae_u32 get_retval_from_stack (void *s, int size)
+{
+    return *(uae_u32 *)((char *)s + size - 20);
+}
+
+static __inline__ int stack_has_retval (void *s, int size)
+{
+    return *(int *)((char *)s + size - 4);
+}
+
+#endif
diff --git a/od-win32/parser.c b/od-win32/parser.c
new file mode 100755 (executable)
index 0000000..0c3c8ad
--- /dev/null
@@ -0,0 +1,532 @@
+/* 
+ * UAE - The Un*x Amiga Emulator
+ *
+ * Not a parser, but parallel and serial emulation for Win32
+ *
+ * Copyright 1997 Mathias Ortmann
+ * Copyright 1998-1999 Brian King - added MIDI output support
+ */
+
+#include "config.h"
+#include "sysconfig.h"
+#include <windows.h>
+#include <winspool.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#ifdef _MSC_VER
+#include <mmsystem.h>
+#include <ddraw.h>
+#include <commctrl.h>
+#include <commdlg.h>
+#else
+#include "winstuff.h"
+#endif
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <io.h>
+
+#include "sysdeps.h"
+#include "options.h"
+#include "gensound.h"
+#include "events.h"
+#include "uae.h"
+#include "include/memory.h"
+#include "custom.h"
+#include "autoconf.h"
+#include "od-win32/win32gui.h"
+#include "od-win32/parser.h"
+#include "od-win32/midi.h"
+#include "od-win32/ahidsound.h"
+#include "win32.h"
+#include "ioport.h"
+
+static UINT prttimer;
+static char prtbuf[PRTBUFSIZE];
+static int prtbufbytes,wantwrite;
+static HANDLE hPrt = INVALID_HANDLE_VALUE;
+static DWORD  dwJob;
+extern HWND hAmigaWnd;
+static int prtopen;
+extern void flushpixels(void);
+void DoSomeWeirdPrintingStuff( char val );
+static int uartbreak;
+
+static void flushprtbuf (void)
+{
+    DWORD written = 0;
+
+    if (hPrt != INVALID_HANDLE_VALUE)
+    {
+       if( WritePrinter( hPrt, prtbuf, prtbufbytes, &written ) )
+       {
+           if( written != prtbufbytes )
+               write_log( "PRINTER: Only wrote %d of %d bytes!\n", written, prtbufbytes );
+       }
+       else
+       {
+           write_log( "PRINTER: Couldn't write data!\n" );
+       }
+    }
+    else
+    {
+       write_log( "PRINTER: Not open!\n" );
+    }
+    prtbufbytes = 0;
+}
+
+void finishjob (void)
+{
+    flushprtbuf ();
+}
+static void DoSomeWeirdPrintingStuff( char val )
+{
+       //if (prttimer)
+       //KillTimer (hAmigaWnd, prttimer);
+    if (prtbufbytes < PRTBUFSIZE) {
+       prtbuf[prtbufbytes++] = val;
+       //prttimer = SetTimer (hAmigaWnd, 1, 2000, NULL);
+    } else {
+       flushprtbuf ();
+       *prtbuf = val;
+       prtbufbytes = 1;
+       prttimer = 0;
+    }
+}
+
+int isprinter (void)
+{
+    if (!strcasecmp(currprefs.prtname,"none"))
+       return 0;
+    if (!memcmp(currprefs.prtname,"LPT", 3)) {
+       paraport_open (currprefs.prtname);
+       return -1;
+    }
+    return 1;
+}
+
+static void openprinter( void )
+{
+    DOC_INFO_1 DocInfo;
+
+    closeprinter ();
+    if (!strcasecmp(currprefs.prtname,"none"))
+       return;
+    if( ( hPrt == INVALID_HANDLE_VALUE ) && *currprefs.prtname)
+    {
+       if( OpenPrinter(currprefs.prtname, &hPrt, NULL ) )
+       {
+           // Fill in the structure with info about this "document."
+           DocInfo.pDocName = "My Document";
+           DocInfo.pOutputFile = NULL;
+           DocInfo.pDatatype = "RAW";
+           // Inform the spooler the document is beginning.
+           if( (dwJob = StartDocPrinter( hPrt, 1, (LPSTR)&DocInfo )) == 0 )
+           {
+               ClosePrinter( hPrt );
+               hPrt = INVALID_HANDLE_VALUE;
+           }
+           else if( StartPagePrinter( hPrt ) )
+           {
+               prtopen = 1;
+           }
+       }
+       else
+       {
+           hPrt = INVALID_HANDLE_VALUE; // Stupid bug in Win32, where OpenPrinter fails, but hPrt ends up being zero
+       }
+    }
+    if( hPrt != INVALID_HANDLE_VALUE )
+    {
+       write_log( "PRINTER: Opening printer \"%s\" with handle 0x%x.\n", currprefs.prtname, hPrt );
+    }
+    else if( *currprefs.prtname )
+    {
+       write_log( "PRINTER: ERROR - Couldn't open printer \"%s\" for output.\n", currprefs.prtname );
+    }
+}
+
+void flushprinter (void)
+{
+    if (hPrt != INVALID_HANDLE_VALUE) {
+        SetJob(
+           hPrt,  // handle to printer object
+           dwJob,      // print job identifier
+           0,      // information level
+           0,     // job information buffer
+           5     // job command value
+       );
+       closeprinter();
+    }
+}
+
+void closeprinter( void )
+{
+    if( hPrt != INVALID_HANDLE_VALUE )
+    {
+       EndPagePrinter( hPrt );
+       EndDocPrinter( hPrt );
+       ClosePrinter( hPrt );
+       hPrt = INVALID_HANDLE_VALUE;
+       write_log( "PRINTER: Closing printer.\n" );
+    }
+    //KillTimer( hAmigaWnd, prttimer );
+    prttimer = 0;
+    prtopen = 0;
+}
+
+static void putprinter (char val)
+{
+    DoSomeWeirdPrintingStuff( val );
+}
+
+int doprinter (uae_u8 val)
+{
+    if (!prtopen)
+       openprinter ();
+    if (prtopen)
+        putprinter (val);
+    return prtopen;
+}
+
+static HANDLE hCom = INVALID_HANDLE_VALUE;
+static DCB dcb;
+static HANDLE writeevent;
+#define SERIAL_WRITE_BUFFER 100
+#define SERIAL_READ_BUFFER 100
+static uae_u8 outputbuffer[SERIAL_WRITE_BUFFER];
+static uae_u8 outputbufferout[SERIAL_WRITE_BUFFER];
+static uae_u8 inputbuffer[SERIAL_READ_BUFFER];
+static int datainoutput;
+static int dataininput, dataininputcnt;
+static OVERLAPPED writeol, readol;
+static writepending;
+
+int openser (char *sername)
+{
+    char buf[32];
+    COMMTIMEOUTS CommTimeOuts;
+
+    sprintf (buf, "\\.\\\\%s", sername);
+
+   if (!(writeevent = CreateEvent (NULL, TRUE, FALSE, NULL))) {
+       write_log ("SERIAL: Failed to create event!\n");
+       return 0;
+    }
+    SetEvent (writeevent);
+    writeol.hEvent = writeevent;
+    uartbreak = 0;
+    if ((hCom = CreateFile (buf, GENERIC_READ | GENERIC_WRITE,
+                           0,
+                           NULL,
+                           OPEN_EXISTING,
+                           FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+                           NULL)) != INVALID_HANDLE_VALUE) {
+       SetCommMask (hCom, EV_RXFLAG);
+       SetupComm (hCom, 65536,128);
+       PurgeComm (hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
+       CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;
+       CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
+       CommTimeOuts.ReadTotalTimeoutConstant = 0;
+       CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
+       CommTimeOuts.WriteTotalTimeoutConstant = 0;
+       SetCommTimeouts (hCom, &CommTimeOuts);
+
+       GetCommState (hCom, &dcb);
+
+       dcb.BaudRate = 9600;
+       dcb.ByteSize = 8;
+       dcb.Parity = NOPARITY;
+       dcb.StopBits = ONESTOPBIT;
+
+        dcb.fDsrSensitivity = FALSE;
+        dcb.fOutxDsrFlow = FALSE;
+        dcb.fDtrControl = DTR_CONTROL_DISABLE;
+   
+       if (currprefs.serial_hwctsrts) {
+           dcb.fOutxCtsFlow = TRUE;
+           dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
+       } else {
+           dcb.fRtsControl = RTS_CONTROL_DISABLE;
+           dcb.fOutxCtsFlow = FALSE;
+       }   
+
+       dcb.fTXContinueOnXoff = FALSE;
+       dcb.fOutX = FALSE;
+       dcb.fInX = FALSE;
+
+       dcb.fErrorChar = FALSE;
+       dcb.fNull = FALSE;
+       dcb.fAbortOnError = FALSE;
+       
+       dcb.XoffLim = 512;
+       dcb.XonLim = 2048;
+
+       if (SetCommState (hCom, &dcb)) {
+           write_log ("SERIAL: Using %s CTS/RTS=%d\n", sername, currprefs.serial_hwctsrts);
+           return 1;
+       }
+       write_log ("SERIAL: serial driver didn't accept new parameters\n");
+       CloseHandle (hCom);
+       hCom = INVALID_HANDLE_VALUE;
+    }
+    return 0;
+}
+
+void closeser (void)
+{
+    if (hCom != INVALID_HANDLE_VALUE)  {
+       CloseHandle (hCom);
+       hCom = INVALID_HANDLE_VALUE;
+    }
+    if (midi_ready)
+        Midi_Close();
+    if( writeevent )
+       CloseHandle( writeevent );
+    writeevent = 0;
+    uartbreak = 0;
+}
+
+static void outser (void)
+{
+    DWORD actual;
+    if (WaitForSingleObject (writeevent, 0) == WAIT_OBJECT_0 && datainoutput > 0) {
+        memcpy (outputbufferout, outputbuffer, datainoutput);
+        WriteFile (hCom, outputbufferout, datainoutput, &actual, &writeol);
+        datainoutput = 0;
+    }
+}
+
+void writeser (int c)
+{
+    if (midi_ready)
+    {
+       BYTE outchar = (BYTE)c;
+        Midi_Parse( midi_output, &outchar );
+    }
+    else
+    {
+       if (datainoutput + 1 < sizeof(outputbuffer)) {
+           outputbuffer[datainoutput++] = c;
+       } else {
+           write_log ("serial output buffer overflow, data will be lost\n");
+           datainoutput = 0;
+       }
+       outser ();
+    }
+}
+
+int checkserwrite (void)
+{
+    if (hCom == INVALID_HANDLE_VALUE)
+       return 1;
+    if (midi_ready) {
+       return 1;
+    } else {
+        outser ();
+       if (datainoutput >= sizeof (outputbuffer) - 1)
+           return 0;
+    }
+    return 1;
+}
+
+int readseravail (void)
+{
+    COMSTAT ComStat;
+    DWORD dwErrorFlags;
+    if (midi_ready) {
+       if (ismidibyte ())
+           return 1;
+    } else {
+       if (dataininput > dataininputcnt)
+           return 1;
+       if (hCom != INVALID_HANDLE_VALUE)  {
+           ClearCommError (hCom, &dwErrorFlags, &ComStat);
+           if (ComStat.cbInQue > 0)
+               return 1;
+       }
+    }
+    return 0;
+}
+
+int readser (int *buffer)
+{
+    COMSTAT ComStat;
+    DWORD dwErrorFlags;
+    DWORD actual;
+    
+    
+    if (midi_ready)
+    {
+       *buffer = getmidibyte ();
+       if (*buffer < 0)
+           return 0;
+       return 1;
+    }
+    else
+    {
+       if (dataininput > dataininputcnt) {
+           *buffer = inputbuffer[dataininputcnt++];
+           return 1;
+       }
+        dataininput = 0;
+       dataininputcnt = 0;
+       if (hCom != INVALID_HANDLE_VALUE) 
+       {
+           /* only try to read number of bytes in queue */
+           ClearCommError (hCom, &dwErrorFlags, &ComStat);
+           if (ComStat.cbInQue) 
+           {
+               int len = ComStat.cbInQue;
+               
+               if (len > sizeof (inputbuffer))
+                   len = sizeof (inputbuffer);
+               if (ReadFile (hCom, inputbuffer, len, &actual, &readol)) 
+               {
+                   dataininput = actual;
+                   dataininputcnt = 0;
+                   if (actual == 0)
+                       return 0;
+                   return readser (buffer);
+               }
+           }
+       }
+    }
+    return 0;
+}
+
+void serialuartbreak (int v)
+{
+    if (hCom == INVALID_HANDLE_VALUE)
+       return;
+
+    if (v)
+       EscapeCommFunction (hCom, SETBREAK);
+    else
+       EscapeCommFunction (hCom, CLRBREAK);
+}
+
+void getserstat (int *pstatus)
+{
+    DWORD stat;
+    int status = 0;
+
+    *pstatus = 0;
+    if (hCom == INVALID_HANDLE_VALUE)
+       return;
+    
+    GetCommModemStatus (hCom, &stat);
+    if (stat & MS_CTS_ON)
+        status |= TIOCM_CTS;
+    if (stat & MS_RLSD_ON)
+        status |= TIOCM_CAR;
+    if (stat & MS_DSR_ON)
+        status |= TIOCM_DSR;
+    if (stat & MS_RING_ON)
+        status |= TIOCM_RI;
+    *pstatus = status;
+}
+
+
+void setserstat (int mask, int onoff)
+{
+    if (hCom == INVALID_HANDLE_VALUE)
+       return;
+
+    if (mask & TIOCM_DTR)
+        EscapeCommFunction (hCom, onoff ? SETDTR : CLRDTR);
+    if (!currprefs.serial_hwctsrts) {
+       if (mask & TIOCM_RTS)
+           EscapeCommFunction (hCom, onoff ? SETRTS : CLRRTS);
+    }
+}
+
+int setbaud (long baud)
+{
+    if( baud == 31400 ) /* MIDI baud-rate */
+    {
+        if (!midi_ready)
+        {
+            if (Midi_Open())
+               write_log ("Midi enabled\n");
+        }
+        return 1;
+    }
+    else
+    {
+        if (midi_ready)
+        {
+            Midi_Close();
+        }
+        if (hCom != INVALID_HANDLE_VALUE) 
+        {
+           if (GetCommState (hCom, &dcb)) 
+            {
+               dcb.BaudRate = baud;
+               if (!SetCommState (hCom, &dcb)) {
+                   write_log ("SERIAL: Error setting baud rate %d!\n", baud);
+                   return 0;
+               }
+           } 
+            else
+            {
+               write_log ("SERIAL: setbaud internal error!\n");
+            }
+        }
+    }
+    return 1;
+}
+
+void hsyncstuff(void)
+//only generate Interrupts when 
+//writebuffer is complete flushed
+//check state of lwin rwin
+{
+    static int keycheck = 0;
+    static int installahi;
+    
+#ifdef AHI
+    { //begin ahi_sound
+       static int count;
+       if (ahi_on) {
+           count++;
+           //15625/count freebuffer check
+           if(count > 20) {
+               ahi_updatesound (1);
+               count = 0;
+           }
+       }
+       if (!installahi)
+       { 
+           uaecptr a = here (); //this install the ahisound
+           org (RTAREA_BASE + 0xFFC0);
+           calltrap (deftrap (ahi_demux));
+           dw (0x4e75);// rts
+           org (a);
+           installahi=1;
+       }
+    } //end ahi_sound
+#endif
+#ifdef PARALLEL_PORT
+    keycheck++;
+    if(keycheck==1000)
+    {
+       if (prtbufbytes)
+       {
+           flushprtbuf ();
+       } 
+       {
+           extern flashscreen;
+           int DX_Fill( int , int , int, int, uae_u32 , enum RGBFTYPE  );
+           //extern int warned_JIT_0xF10000;
+           //warned_JIT_0xF10000 = 0;
+           if (flashscreen) {
+               DX_Fill(0,0,300,40,0x000000,9);
+               flashscreen--;
+           }
+       }
+       keycheck = 0;
+    }
+#endif
+}
diff --git a/od-win32/parser.h b/od-win32/parser.h
new file mode 100755 (executable)
index 0000000..86a743c
--- /dev/null
@@ -0,0 +1,31 @@
+/* 
+ * UAE - The Un*x Amiga Emulator
+ *
+ * Not a parser, but parallel and serial emulation for Win32
+ *
+ * Copyright 1997 Mathias Ortmann
+ * Copyright 1998-1999 Brian King
+ */
+
+#define PRTBUFSIZE 4096
+
+int setbaud (long baud );
+void getserstat(int *status);
+void setserstat (int mask, int onoff);
+int readser (int *buffer);
+int readseravail (void);
+void writeser (int c);
+int openser (char *sername);
+void closeser (void);
+void doserout (void);
+void closeprinter (void);
+void flushprinter (void);
+int checkserwrite (void);
+void serialuartbreak (int);
+
+#define TIOCM_CAR 1
+#define TIOCM_DSR 2
+#define TIOCM_RI 4
+#define TIOCM_DTR 8
+#define TIOCM_RTS 16
+#define TIOCM_CTS 32
diff --git a/od-win32/picasso96_win.c b/od-win32/picasso96_win.c
new file mode 100755 (executable)
index 0000000..0bd9bb6
--- /dev/null
@@ -0,0 +1,3802 @@
+/*
+* UAE - The U*nix Amiga Emulator
+*
+* Picasso96 Support Module
+*
+* Copyright 1997-2001 Brian King <Brian_King@CodePoet.com>
+* Copyright 2000-2001 Bernd Roesch <>
+*
+* Theory of operation:
+* On the Amiga side, a Picasso card consists mainly of a memory area that
+* contains the frame buffer.  On the UAE side, we allocate a block of memory
+* that will hold the frame buffer.  This block is in normal memory, it is
+* never directly on the graphics card.  All graphics operations, which are
+* mainly reads and writes into this block and a few basic operations like
+* filling a rectangle, operate on this block of memory.
+* Since the memory is not on the graphics card, some work must be done to
+* synchronize the display with the data in the Picasso frame buffer.  There
+* are various ways to do this.  One possibility is to allocate a second
+* buffer of the same size, and perform all write operations twice.  Since
+* we never read from the second buffer, it can actually be placed in video
+* memory.  The X11 driver could be made to use the Picasso frame buffer as
+* the data buffer of an XImage, which could then be XPutImage()d from time
+* to time.  Another possibility is to translate all Picasso accesses into
+* Xlib (or GDI, or whatever your graphics system is) calls.  This possibility
+* is a bit tricky, since there is a risk of generating very many single pixel
+* accesses which may be rather slow.
+*
+* TODO:
+* - we want to add a manual switch to override SetSwitch for hardware banging
+*   programs started from a Picasso workbench.
+*/
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "threaddep/thread.h"
+#include "uae.h"
+#include "memory.h" 
+#include "custom.h"
+#include "events.h"
+#include "newcpu.h"
+#include "xwin.h"
+#include "savestate.h"
+#include "autoconf.h"
+
+#include "dxwrap.h"
+#include "picasso96_win.h"
+#include "win32gfx.h"
+
+int p96hack_vpos, p96hack_vpos2, p96refresh_active; 
+int have_done_picasso; /* For the JIT compiler */
+int picasso_is_special = PIC_WRITE; /* ditto */
+int picasso_is_special_read = PIC_READ; /* ditto */
+static int p96syncrate;
+int p96hsync_counter;
+#define SWAPSPEEDUP 
+#ifdef PICASSO96
+#ifdef DEBUG // Change this to _DEBUG for debugging
+#define P96TRACING_ENABLED 1
+#define P96TRACING_LEVEL 1
+#endif
+#define LOCK_UNLOCK_MADNESS //need for 7 times faster linedraw
+#define PIXEL_LOCK         //and scrollable screens
+#define MAXFLUSHPIXEL 1600 //pixel draw in a lock
+static void flushpixels(void);
+int pixelcount,palette_changed;
+struct pixel32{
+       uaecptr addr;
+    uae_u32 value;
+       int size;
+};
+struct pixel32 pixelbase[MAXFLUSHPIXEL+2];
+#ifdef P96TRACING_ENABLED
+#define P96TRACE(x)    do { write_log x; } while(0)
+#else
+#define P96TRACE(x)
+#endif
+
+#define GetBytesPerPixel(x) GetBytesPerPixel2(x,__FILE__,__LINE__)
+
+static uae_u32 REGPARAM2 gfxmem_lget (uaecptr) REGPARAM;
+static uae_u32 REGPARAM2 gfxmem_wget (uaecptr) REGPARAM;
+static uae_u32 REGPARAM2 gfxmem_bget (uaecptr) REGPARAM;
+static void REGPARAM2 gfxmem_lput (uaecptr, uae_u32) REGPARAM;
+static void REGPARAM2 gfxmem_wput (uaecptr, uae_u32) REGPARAM;
+static void REGPARAM2 gfxmem_bput (uaecptr, uae_u32) REGPARAM;
+static int REGPARAM2 gfxmem_check (uaecptr addr, uae_u32 size) REGPARAM;
+static uae_u8 *REGPARAM2 gfxmem_xlate (uaecptr addr) REGPARAM;
+
+static void write_gfx_long (uaecptr addr, uae_u32 value);
+static void write_gfx_word (uaecptr addr, uae_u16 value);
+static void write_gfx_byte (uaecptr addr, uae_u8 value);
+
+static uae_u8 all_ones_bitmap, all_zeros_bitmap; /* yuk */
+
+struct picasso96_state_struct picasso96_state;
+struct picasso_vidbuf_description picasso_vidinfo;
+
+/* These are the maximum resolutions... They are filled in by GetSupportedResolutions() */
+/* have to fill this in, otherwise problems occur on the Amiga side P96 s/w which expects
+/* data here. */
+struct ScreenResolution planar = { 320, 240 };
+struct ScreenResolution chunky = { 640, 480 };
+struct ScreenResolution hicolour = { 640, 480 };
+struct ScreenResolution truecolour = { 640, 480 };
+struct ScreenResolution alphacolour = { 640, 480 };
+
+static uae_u32 p2ctab[256][2];
+static int set_gc_called = 0;
+//fastscreen
+static uaecptr oldscr=0;
+#ifdef _DEBUG
+void PICASSO96_Unlock2( char *filename, int linenum )
+#else
+void PICASSO96_Unlock( void )
+#endif
+{
+#ifdef LOCK_UNLOCK_MADNESS
+#if defined( P96TRACING_ENABLED ) && P96TRACING_LEVEL > 1
+       // This format of output lets you double-click and jump to file/line
+       write_log( "%s(%d) : calling P96 UNLOCK with picasso_on=%d\n", filename, linenum, picasso_on );
+#endif
+    if( picasso_on )
+    {
+#ifdef PIXEL_LOCK
+       flushpixels();
+#endif 
+       gfx_unlock_picasso ();
+
+       //picasso96_state.HostAddress = NULL;
+    }
+#endif
+}
+
+#ifdef _DEBUG
+void PICASSO96_Lock2( char *filename, int linenum )
+#else
+void PICASSO96_Lock( void )
+#endif
+{
+#ifdef LOCK_UNLOCK_MADNESS
+#if defined( P96TRACING_ENABLED ) && P96TRACING_LEVEL > 1
+       // This format of output lets you double-click and jump to file/line
+       write_log( "%s(%d) : calling P96 LOCK with picasso_on=%d\n", filename, linenum, picasso_on );
+#endif
+    if( picasso_on /*&& !picasso96_state.HostAddress*/)
+    {
+       //gfx_unlock_picasso(); // forces the proper flushing
+       picasso96_state.HostAddress = gfx_lock_picasso ();
+    }
+#endif
+}
+
+#ifdef P96TRACING_ENABLED                  
+/*
+* Debugging dumps
+*/
+static void DumpModeInfoStructure (uaecptr amigamodeinfoptr)
+{
+    write_log ("ModeInfo Structure Dump:\n");
+    write_log ("  Node.ln_Succ  = 0x%x\n", get_long (amigamodeinfoptr));
+    write_log ("  Node.ln_Pred  = 0x%x\n", get_long (amigamodeinfoptr + 4));
+    write_log ("  Node.ln_Type  = 0x%x\n", get_byte (amigamodeinfoptr + 8));
+    write_log ("  Node.ln_Pri   = %d\n", get_byte (amigamodeinfoptr + 9));
+    /*write_log ("  Node.ln_Name  = %s\n", uaememptr->Node.ln_Name); */
+    write_log ("  OpenCount     = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_OpenCount));
+    write_log ("  Active        = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_Active));
+    write_log ("  Width         = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_Width));
+    write_log ("  Height        = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_Height));
+    write_log ("  Depth         = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_Depth));
+    write_log ("  Flags         = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_Flags));
+    write_log ("  HorTotal      = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorTotal));
+    write_log ("  HorBlankSize  = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorBlankSize));
+    write_log ("  HorSyncStart  = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorSyncStart));
+    write_log ("  HorSyncSize   = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorSyncSize));
+    write_log ("  HorSyncSkew   = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_HorSyncSkew));
+    write_log ("  HorEnableSkew = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_HorEnableSkew));
+    write_log ("  VerTotal      = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerTotal));
+    write_log ("  VerBlankSize  = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerBlankSize));
+    write_log ("  VerSyncStart  = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerSyncStart));
+    write_log ("  VerSyncSize   = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerSyncSize));
+    write_log ("  Clock         = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_first_union));
+    write_log ("  ClockDivide   = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_second_union));
+    write_log ("  PixelClock    = %d\n", get_long (amigamodeinfoptr + PSSO_ModeInfo_PixelClock));
+}
+
+static void DumpLibResolutionStructure (uaecptr amigalibresptr)
+{
+    int i;
+    uaecptr amigamodeinfoptr;
+    struct LibResolution *uaememptr = (struct LibResolution *)get_mem_bank(amigalibresptr).xlateaddr(amigalibresptr);
+    
+    write_log ("LibResolution Structure Dump:\n");
+    
+    if (get_long (amigalibresptr + PSSO_LibResolution_DisplayID) == 0xFFFFFFFF) {
+       write_log ("  Finished With LibResolutions...\n");
+    } else {
+       write_log ("  Name      = %s\n", uaememptr->P96ID);
+       write_log ("  DisplayID = 0x%x\n", get_long (amigalibresptr + PSSO_LibResolution_DisplayID));
+       write_log ("  Width     = %d\n", get_word (amigalibresptr + PSSO_LibResolution_Width));
+       write_log ("  Height    = %d\n", get_word (amigalibresptr + PSSO_LibResolution_Height));
+       write_log ("  Flags     = %d\n", get_word (amigalibresptr + PSSO_LibResolution_Flags));
+       for (i = 0; i < MAXMODES; i++) {
+           amigamodeinfoptr = get_long (amigalibresptr + PSSO_LibResolution_Modes + i*4);
+           write_log ("  ModeInfo[%d] = 0x%x\n", i, amigamodeinfoptr);
+           if (amigamodeinfoptr)
+               DumpModeInfoStructure (amigamodeinfoptr);
+       }
+       write_log ("  BoardInfo = 0x%x\n", get_long (amigalibresptr + PSSO_LibResolution_BoardInfo));
+    }
+}
+
+v
+
+static char binary_byte[9] = { 0,0,0,0,0,0,0,0,0 };
+
+static char *BuildBinaryString (uae_u8 value)
+{
+    int i;
+    for (i = 0; i < 8; i++) {
+       binary_byte[i] = (value & (1 << (7 - i))) ? '#' : '.';
+    }
+    return binary_byte;
+}
+
+static void DumpPattern (struct Pattern *patt)
+{
+    uae_u8 *mem;
+    int row, col;
+    for (row = 0; row < (1 << patt->Size); row++) {
+       mem = patt->Memory + row * 2;
+       for (col = 0; col < 2; col++) {
+           write_log ("%s ", BuildBinaryString (*mem++));
+       }
+       write_log ("\n");
+    }
+}
+
+static void DumpTemplate (struct Template *tmp, unsigned long w, unsigned long h)
+{
+    uae_u8 *mem = tmp->Memory;
+    unsigned int row, col, width;
+    width = (w + 7) >> 3;
+    write_log ("xoffset = %d, bpr = %d\n", tmp->XOffset, tmp->BytesPerRow);
+    for (row = 0; row < h; row++) {
+       mem = tmp->Memory + row * tmp->BytesPerRow;
+       for (col = 0; col < width; col++) {
+           write_log ("%s ", BuildBinaryString (*mem++));
+       }
+       write_log ("\n");
+    }
+}
+
+static void DumpLine( struct Line *line )
+{
+    if( line )
+    {
+       write_log( "Line->X = %d\n", line->X );
+       write_log( "Line->Y = %d\n", line->Y );
+       write_log( "Line->Length = %d\n", line->Length );
+       write_log( "Line->dX = %d\n", line->dX );
+       write_log( "Line->dY = %d\n", line->dY );
+       write_log( "Line->sDelta = %d\n", line->sDelta );
+       write_log( "Line->lDelta = %d\n", line->lDelta );
+       write_log( "Line->twoSDminusLD = %d\n", line->twoSDminusLD );
+       write_log( "Line->LinePtrn = %d\n", line->LinePtrn );
+       write_log( "Line->PatternShift = %d\n", line->PatternShift );
+       write_log( "Line->FgPen = 0x%x\n", line->FgPen );
+       write_log( "Line->BgPen = 0x%x\n", line->BgPen );
+       write_log( "Line->Horizontal = %d\n", line->Horizontal );
+       write_log( "Line->DrawMode = %d\n", line->DrawMode );
+       write_log( "Line->Xorigin = %d\n", line->Xorigin );
+       write_log( "Line->Yorigin = %d\n", line->Yorigin );
+    }
+}
+#endif
+
+static void ShowSupportedResolutions (void)
+{
+    int i = 0;
+    
+    write_log ("-----------------\n");
+    while (DisplayModes[i].depth >= 0) {
+       write_log ("%s\n", DisplayModes[i].name);
+       i++;
+    }
+    write_log ("-----------------\n");
+}
+
+static uae_u8 GetBytesPerPixel2(uae_u32 RGBfmt, char *file, int line)
+{
+    static BOOL bFailure = FALSE;
+
+    switch (RGBfmt) {
+    case RGBFB_CLUT:
+       return 1;
+       
+    case RGBFB_A8R8G8B8:
+    case RGBFB_A8B8G8R8:
+    case RGBFB_R8G8B8A8:
+    case RGBFB_B8G8R8A8:
+       return 4;
+       
+    case RGBFB_B8G8R8:
+    case RGBFB_R8G8B8:
+       return 3;
+       
+    case RGBFB_R5G5B5:
+    case RGBFB_R5G6B5:
+    case RGBFB_R5G6B5PC:
+    case RGBFB_R5G5B5PC:
+    case RGBFB_B5G6R5PC:
+    case RGBFB_B5G5R5PC:
+       return 2;
+    default:
+       write_log ("ERROR - GetBytesPerPixel() from %s@%d was unsuccessful with 0x%x?!\n", file, line, RGBfmt);
+       if( !bFailure )
+       {
+           bFailure = TRUE;
+           return GetBytesPerPixel(picasso_vidinfo.rgbformat);
+       }
+       else
+       {
+           abort();
+       }
+    }
+}
+
+/*
+* Amiga <-> native structure conversion functions
+*/
+
+static int CopyRenderInfoStructureA2U (uaecptr amigamemptr, struct RenderInfo *ri)
+{
+    uaecptr memp = get_long (amigamemptr + PSSO_RenderInfo_Memory);
+    
+    if (valid_address (memp, PSSO_RenderInfo_sizeof)) {
+       ri->Memory = get_real_address (memp);
+       ri->BytesPerRow = get_word (amigamemptr + PSSO_RenderInfo_BytesPerRow);
+       ri->RGBFormat = get_long (amigamemptr + PSSO_RenderInfo_RGBFormat);
+       return 1;
+    }
+    write_log ("ERROR - Invalid RenderInfo memory area...\n");
+    return 0;
+}
+
+static int CopyPatternStructureA2U (uaecptr amigamemptr, struct Pattern *pattern)
+{
+    uaecptr memp = get_long (amigamemptr + PSSO_Pattern_Memory);
+    if (valid_address (memp, PSSO_Pattern_sizeof)) {
+       pattern->Memory = get_real_address (memp);
+       pattern->XOffset = get_word (amigamemptr + PSSO_Pattern_XOffset);
+       pattern->YOffset = get_word (amigamemptr + PSSO_Pattern_YOffset);
+       pattern->FgPen = get_long (amigamemptr + PSSO_Pattern_FgPen);
+       pattern->BgPen = get_long (amigamemptr + PSSO_Pattern_BgPen);
+       pattern->Size = get_byte (amigamemptr + PSSO_Pattern_Size);
+       pattern->DrawMode = get_byte (amigamemptr + PSSO_Pattern_DrawMode);
+       return 1;
+    }
+    write_log ("ERROR - Invalid Pattern memory area...\n");
+    return 0;
+}
+
+static void CopyColorIndexMappingA2U (uaecptr amigamemptr, struct ColorIndexMapping *cim)
+{
+    int i;
+    cim->ColorMask = get_long (amigamemptr);
+    for (i = 0; i < 256; i++, amigamemptr += 4)
+       cim->Colors[i] = get_long (amigamemptr + 4);
+}
+
+static int CopyBitMapStructureA2U (uaecptr amigamemptr, struct BitMap *bm)
+{
+    int i;
+    
+    bm->BytesPerRow = get_word (amigamemptr + PSSO_BitMap_BytesPerRow);
+    bm->Rows = get_word (amigamemptr + PSSO_BitMap_Rows);
+    bm->Flags = get_byte (amigamemptr + PSSO_BitMap_Flags);
+    bm->Depth = get_byte (amigamemptr + PSSO_BitMap_Depth);
+    
+    /* ARGH - why is THIS happening? */
+    if( bm->Depth > 8 )
+       bm->Depth = 8;
+    
+    for (i = 0; i < bm->Depth; i++) {
+       uaecptr plane = get_long (amigamemptr + PSSO_BitMap_Planes + i*4);
+       switch (plane) {
+       case 0:
+           bm->Planes[i] = &all_zeros_bitmap;
+           break;
+       case 0xFFFFFFFF:
+           bm->Planes[i] = &all_ones_bitmap;
+           break;
+       default:
+           if (valid_address (plane, bm->BytesPerRow * bm->Rows))
+               bm->Planes[i] = get_real_address (plane);
+           else
+               return 0;
+           break;
+       }
+    }
+    return 1;
+}
+
+static int CopyTemplateStructureA2U (uaecptr amigamemptr, struct Template *tmpl)
+{
+    uaecptr memp = get_long (amigamemptr + PSSO_Template_Memory);
+    
+    if (valid_address (memp, sizeof(struct Template))) {
+       tmpl->Memory = get_real_address (memp);
+       tmpl->BytesPerRow = get_word (amigamemptr + PSSO_Template_BytesPerRow);
+       tmpl->XOffset = get_byte (amigamemptr + PSSO_Template_XOffset);
+       tmpl->DrawMode = get_byte (amigamemptr + PSSO_Template_DrawMode);
+       tmpl->FgPen = get_long (amigamemptr + PSSO_Template_FgPen);
+       tmpl->BgPen = get_long (amigamemptr + PSSO_Template_BgPen);
+       return 1;
+    }
+    write_log ("ERROR - Invalid Template memory area...\n");
+    return 0;
+}
+
+static int CopyLineStructureA2U( uaecptr amigamemptr, struct Line *line )
+{
+    if( valid_address( amigamemptr, sizeof( struct Line ) ) )
+    {
+       line->X = get_word( amigamemptr + PSSO_Line_X );
+       line->Y = get_word( amigamemptr + PSSO_Line_Y );
+       line->Length = get_word( amigamemptr + PSSO_Line_Length );
+       line->dX = get_word( amigamemptr + PSSO_Line_dX );
+       line->dY = get_word( amigamemptr + PSSO_Line_dY );
+       line->lDelta = get_word( amigamemptr + PSSO_Line_lDelta );
+       line->sDelta = get_word( amigamemptr + PSSO_Line_sDelta );
+       line->twoSDminusLD = get_word( amigamemptr + PSSO_Line_twoSDminusLD );
+       line->LinePtrn = get_word( amigamemptr + PSSO_Line_LinePtrn );
+       line->PatternShift = get_word( amigamemptr + PSSO_Line_PatternShift );
+       line->FgPen = get_long( amigamemptr + PSSO_Line_FgPen );
+       line->BgPen = get_long( amigamemptr + PSSO_Line_BgPen );
+       line->Horizontal = get_word( amigamemptr + PSSO_Line_Horizontal );
+       line->DrawMode = get_byte( amigamemptr + PSSO_Line_DrawMode );
+       line->Xorigin = get_word( amigamemptr + PSSO_Line_Xorigin );
+       line->Yorigin = get_word( amigamemptr + PSSO_Line_Yorigin );
+       return 1;
+    }
+    write_log( "ERROR - Invalid Line structure...\n" );
+    return 0;
+}
+
+static void CopyLibResolutionStructureU2A (struct LibResolution *libres, uaecptr amigamemptr)
+{
+    char *uaememptr = 0;
+    int i;
+    
+    uaememptr = gfxmem_xlate (amigamemptr); /* I know that amigamemptr is inside my gfxmem chunk, so I can just do the xlate() */
+    memset (uaememptr, 0, PSSO_LibResolution_sizeof); /* zero out our LibResolution structure */
+    strcpy (uaememptr + PSSO_LibResolution_P96ID, libres->P96ID);
+    put_long (amigamemptr + PSSO_LibResolution_DisplayID, libres->DisplayID);
+    put_word (amigamemptr + PSSO_LibResolution_Width, libres->Width);
+    put_word (amigamemptr + PSSO_LibResolution_Height, libres->Height);
+    put_word (amigamemptr + PSSO_LibResolution_Flags, libres->Flags);
+    for (i = 0; i < MAXMODES; i++)
+       put_long (amigamemptr + PSSO_LibResolution_Modes + i*4, libres->Modes[i]);
+#if 0
+    put_long (amigamemptr, libres->Node.ln_Succ);
+    put_long (amigamemptr + 4, libres->Node.ln_Pred);
+    put_byte (amigamemptr + 8, libres->Node.ln_Type);
+    put_byte (amigamemptr + 9, libres->Node.ln_Pri);
+#endif
+    put_long (amigamemptr + 10, amigamemptr + PSSO_LibResolution_P96ID);
+    put_long (amigamemptr + PSSO_LibResolution_BoardInfo, libres->BoardInfo);
+}
+
+/* list is Amiga address of list, in correct endian format for UAE
+* node is Amiga address of node, in correct endian format for UAE */
+static void AmigaListAddTail (uaecptr list, uaecptr node)
+{
+    uaecptr amigamemptr = 0;
+    
+    if (get_long (list + 8) == list) {
+       /* Empty list - set it up */
+       put_long (list, node);     /* point the lh_Head to our new node */
+       put_long (list + 4, 0);    /* set the lh_Tail to NULL */
+       put_long (list + 8, node); /* point the lh_TailPred to our new node */
+       
+       /* Adjust the new node - don't rely on it being zeroed out */
+       put_long (node, 0); /* ln_Succ */
+       put_long (node + 4, 0); /* ln_Pred */
+    } else {
+       amigamemptr = get_long (list + 8); /* get the lh_TailPred contents */
+       
+       put_long (list + 8, node); /* point the lh_TailPred to our new node */
+       
+       /* Adjust the previous lh_TailPred node */
+       put_long (amigamemptr, node); /* point the ln_Succ to our new node */
+       
+       /* Adjust the new node - don't rely on it being zeroed out */
+       put_long (node, 0); /* ln_Succ */
+       put_long (node + 4, amigamemptr); /* ln_Pred */
+    }
+}
+
+/*
+* Functions to perform an action on the real screen
+*/
+
+/*
+* Fill a rectangle on the screen.  src points to the start of a line of the
+* filled rectangle in the frame buffer; it can be used as a memcpy source if
+* there is no OS specific function to fill the rectangle.
+*/
+static void do_fillrect( uae_u8 *src, unsigned int x, unsigned int y, unsigned int width, unsigned int height, uae_u32 pen, int Bpp, RGBFTYPE rgbtype )
+{
+    uae_u8 *dst;
+   
+    /* Try OS specific fillrect function here; and return if successful.  Make sure we adjust for
+    * the pen values if we're doing 8-bit display-emulation on a 16-bit or higher screen. */
+#ifdef PIXEL_LOCK
+     flushpixels(); 
+#endif 
+
+    if( picasso_vidinfo.rgbformat == picasso96_state.RGBFormat )
+    {
+        if( DX_Fill( x, y, width, height, pen, rgbtype ) )
+               {
+#ifdef LOCK_UNLOCK_MADNESS
+    //PICASSO96_Unlock();
+#endif
+            return;
+               }
+    }
+    else
+    {   
+        if( DX_Fill( x, y, width, height, picasso_vidinfo.clut[src[0]], rgbtype ) )
+               {
+#ifdef LOCK_UNLOCK_MADNESS
+     //PICASSO96_Unlock();
+#endif
+          return;
+               } 
+
+    }
+   
+    P96TRACE(("P96_WARNING: do_fillrect() using fall-back routine!\n"));
+    
+    if( y+height > picasso_vidinfo.height )
+       height = picasso_vidinfo.height - y;
+    if( x+width > picasso_vidinfo.width )
+       width = picasso_vidinfo.width - x;
+
+    DX_Invalidate (y, y + height - 1);
+    if (! picasso_vidinfo.extra_mem)
+       {               
+#ifdef LOCK_UNLOCK_MADNESS
+     //PICASSO96_Unlock();
+#endif
+       pixelcount=0;
+          return;
+               } 
+    
+    width *= Bpp;
+#ifdef LOCK_UNLOCK_MADNESS
+    PICASSO96_Lock();
+    dst = picasso96_state.HostAddress;
+#else
+    dst = gfx_lock_picasso ();
+#endif
+    if (!dst)
+       goto out;
+    
+    dst += y*picasso_vidinfo.rowbytes + x*picasso_vidinfo.pixbytes;
+    if (picasso_vidinfo.rgbformat == picasso96_state.RGBFormat) 
+    {
+        if( Bpp == 1 )
+        {
+           while (height-- > 0)
+            {
+               memset( dst, pen, width );
+               dst += picasso_vidinfo.rowbytes;
+            } 
+        }
+        else
+        {
+           while (height-- > 0)
+            {
+               memcpy (dst, src, width);
+               dst += picasso_vidinfo.rowbytes;
+            } 
+        }
+    }
+    else
+    {
+       int psiz = GetBytesPerPixel (picasso_vidinfo.rgbformat);
+       if (picasso96_state.RGBFormat != RGBFB_CHUNKY)
+        {
+            write_log ("ERROR - do_fillrect() calling abort 1!\n");
+           abort ();
+        }
+       
+       while (height-- > 0) 
+        {
+           unsigned int i;
+           switch (psiz) 
+            {
+           case 2:
+               for (i = 0; i < width; i++)
+                   *((uae_u16 *)dst + i) = picasso_vidinfo.clut[src[i]];
+               break;
+           case 4:
+               for (i = 0; i < width; i++)
+                   *((uae_u32 *)dst + i) = picasso_vidinfo.clut[src[i]];
+               break;
+           default:
+               write_log ("ERROR - do_fillrect() calling abort 2!\n");
+               abort ();                       
+                break;
+           }
+           dst += picasso_vidinfo.rowbytes;
+       }
+    }
+out:;
+#ifndef LOCK_UNLOCK_MADNESS
+    gfx_unlock_picasso ();
+#else
+     PICASSO96_Unlock();
+#endif    
+}
+
+/*
+* This routine modifies the real screen buffer after a blit has been
+* performed in the save area. If can_do_blit is nonzero, the blit can
+* be performed within the real screen buffer; otherwise, this routine
+* must do it by hand using the data in the frame-buffer, calculated using
+* the RenderInfo data and our coordinates.
+*/
+static void do_blit( struct RenderInfo *ri, int Bpp, 
+                   unsigned int srcx, unsigned int srcy, unsigned int dstx, unsigned int dsty,
+                   unsigned int width, unsigned int height, BLIT_OPCODE opcode, int can_do_blit)
+{
+    uae_u8 *dstp, *srcp;
+    int orig_height = height;
+       
+    if( picasso96_state.BigAssBitmap && can_do_blit){
+       srcx=dstx;
+       srcy=dsty;
+       can_do_blit=0;
+    } //hack to use cpu rotines for scrolling in big Screens
+    
+    dstx=dstx-picasso96_state.XOffset;
+    dsty=dsty-picasso96_state.YOffset;
+    if((int)dstx<=0){
+       srcx=srcx-dstx;
+       dstx=0;
+    }
+    if((int)dsty<=0){
+       srcy=srcy-dsty;
+       dsty=0;
+    }
+
+#ifdef LOCK_UNLOCK_MADNESS
+#ifdef PIXEL_LOCK
+       flushpixels();
+#endif
+    //PICASSO96_Lock();
+#endif 
+    /* Is our x/y origin on-screen? */
+    if( dsty >= picasso_vidinfo.height )
+       return;
+    if( dstx >= picasso_vidinfo.width )
+       return;
+
+    /* Is our area in-range? */
+    if( dsty+height >= picasso_vidinfo.height )
+       height = picasso_vidinfo.height - dsty;
+    if( dstx+width >= picasso_vidinfo.width )
+       width = picasso_vidinfo.width - dstx;
+
+    if (can_do_blit) 
+    {
+       //
+       // Call OS blitting function that can do it in video memory.
+       // Should return if it was successful
+       //
+        if( DX_Blit( srcx, srcy, dstx, dsty, width, height, opcode ) )
+           return;
+    }
+#ifdef LOCK_UNLOCK_MADNESS
+        PICASSO96_Lock();
+#endif
+
+    srcp = ri->Memory + srcx*Bpp + srcy*ri->BytesPerRow;
+    
+    
+    DX_Invalidate (dsty, dsty + height - 1);
+    if (! picasso_vidinfo.extra_mem)
+       {
+    #ifdef LOCK_UNLOCK_MADNESS
+    goto out;  
+    #else 
+    return;
+    #endif     
+       }
+
+#ifdef LOCK_UNLOCK_MADNESS
+    dstp = picasso96_state.HostAddress;
+#else
+    dstp = gfx_lock_picasso ();
+#endif
+    if (dstp == 0)
+    {
+        write_log ("WARNING: do_blit() couldn't lock\n");
+       goto out;
+    }
+    
+    /* The areas can't overlap: the source is always in the Picasso frame buffer,
+    * and the destination is a different buffer owned by the graphics code.  */
+    dstp += dsty * picasso_vidinfo.rowbytes + dstx * picasso_vidinfo.pixbytes;
+    P96TRACE(("do_blit with srcp 0x%x, dstp 0x%x, dst_rowbytes %d, srcx %d, srcy %d, dstx %d, dsty %d, w %d, h %d, dst_pixbytes %d\n",
+        srcp, dstp, picasso_vidinfo.rowbytes, srcx, srcy, dstx, dsty, width, height, picasso_vidinfo.pixbytes));
+    P96TRACE(("gfxmem is at 0x%x\n",gfxmemory));
+       
+    if (picasso_vidinfo.rgbformat == picasso96_state.RGBFormat) 
+    {
+        P96TRACE(("do_blit type-a\n"));
+        width *= Bpp;
+        while (height-- > 0) 
+        {
+            memcpy (dstp, srcp, width);
+            srcp += ri->BytesPerRow;
+            dstp += picasso_vidinfo.rowbytes;
+        }
+    }
+    else
+    {
+        int psiz = GetBytesPerPixel (picasso_vidinfo.rgbformat);
+       P96TRACE(("do_blit type-b\n"));
+        if (picasso96_state.RGBFormat != RGBFB_CHUNKY)
+        {
+            write_log ("ERROR: do_blit() calling abort 1!\n");
+            abort ();
+        }
+        while (height-- > 0) 
+        {
+           unsigned int i;
+           switch (psiz) 
+            {
+           case 2:
+               for (i = 0; i < width; i++)
+                   *((uae_u16 *)dstp + i) = picasso_vidinfo.clut[srcp[i]];
+               break;
+           case 4:
+               for (i = 0; i < width; i++)
+                   *((uae_u32 *)dstp + i) = picasso_vidinfo.clut[srcp[i]];
+               break;
+           default:
+               write_log ("ERROR - do_blit() calling abort 2!\n");
+               abort ();
+                break;
+           }
+           srcp += ri->BytesPerRow;
+           dstp += picasso_vidinfo.rowbytes;
+       }
+    }
+    out:
+#ifndef LOCK_UNLOCK_MADNESS
+    gfx_unlock_picasso ();
+#else
+    PICASSO96_Unlock();
+#endif
+    ;
+}
+
+/*
+* Invert a rectangle on the screen.  a render-info is given,
+* so that do_blit can be used if
+* there is no OS specific function to invert the rectangle.
+*/
+static void do_invertrect( struct RenderInfo *ri, int Bpp, int x, int y, int width, int height)
+{
+   /* if( DX_InvertRect( x, y, width, height ) )
+       return;*/  //deactivate in 0.8.20 
+    P96TRACE(("do_invertrect falling back to do_blit!\n"));
+    do_blit (ri, Bpp, x, y, x, y, width, height, BLIT_SRC, 0);
+}
+                   
+static uaecptr wgfx_linestart;
+static uaecptr wgfx_lineend;
+static uaecptr wgfx_min, wgfx_max;
+static unsigned long wgfx_y;
+
+static void wgfx_do_flushline (void)
+{
+    uae_u8 *src, *dstp;
+       
+    /* Mark these lines as "dirty" */
+    DX_Invalidate (wgfx_y, wgfx_y);
+
+    if (! picasso_vidinfo.extra_mem) /* The "out" will flush the dirty lines directly */
+       goto out;
+    
+#ifdef LOCK_UNLOCK_MADNESS
+    dstp = picasso96_state.HostAddress;
+       
+#else
+    dstp = gfx_lock_picasso ();
+#endif
+     if (dstp == 0)
+       goto out;
+#if P96TRACING_LEVEL > 0
+    P96TRACE(("flushing %d\n", wgfx_y));
+#endif
+    src = gfxmemory + wgfx_min;
+    
+    if( picasso_vidinfo.rgbformat == picasso96_state.RGBFormat )
+    {
+#if P96TRACING_LEVEL > 0
+       P96TRACE(("flushing type-a\n"));
+#endif
+       dstp += wgfx_y * picasso_vidinfo.rowbytes + wgfx_min - wgfx_linestart;
+               memcpy (dstp, src, wgfx_max - wgfx_min);
+    }
+    else
+    {
+       int width = wgfx_max - wgfx_min;
+       int i;
+       int psiz = GetBytesPerPixel (picasso_vidinfo.rgbformat);
+       P96TRACE(("flushing type-b\n"));
+       if (picasso96_state.RGBFormat != RGBFB_CHUNKY)
+       {
+           write_log ("ERROR - wgfx_do_flushline() calling abort 1!\n");
+           abort ();
+       }
+       
+       dstp += wgfx_y * picasso_vidinfo.rowbytes + (wgfx_min - wgfx_linestart) * psiz;
+       switch (psiz) {
+       case 2:
+           for (i = 0; i < width; i++)
+               *((uae_u16 *)dstp + i) = picasso_vidinfo.clut[src[i]];
+           break;
+       case 4:
+           for (i = 0; i < width; i++)
+               *((uae_u32 *)dstp + i) = picasso_vidinfo.clut[src[i]];
+           break;
+       default:
+           write_log ("ERROR - wgfx_do_flushline() calling abort 2!\n");
+           abort ();                   
+           break;
+       }
+    }
+    
+out:
+#ifndef LOCK_UNLOCK_MADNESS
+    gfx_unlock_picasso ();
+#endif
+       
+    wgfx_linestart = 0xFFFFFFFF;
+}
+
+STATIC_INLINE void wgfx_flushline (void)
+{
+    if (wgfx_linestart == 0xFFFFFFFF || ! picasso_on)
+       return;
+    wgfx_do_flushline ();
+}
+
+static int renderinfo_is_current_screen (struct RenderInfo *ri)
+{
+    if (! picasso_on)
+       return 0;
+    if (ri->Memory != gfxmemory + (picasso96_state.Address - gfxmem_start))
+       return 0;
+    
+    return 1;
+}
+
+/*
+* Fill a rectangle in the screen.
+*/
+STATIC_INLINE void do_fillrect_frame_buffer( struct RenderInfo *ri, int X, int Y, int Width, int Height, uae_u32 Pen, int Bpp, RGBFTYPE RGBFormat )
+{
+    int cols;
+    uae_u8 *start, *oldstart;
+    uae_u8 *src, *dst;
+    int lines;
+
+    /* Do our virtual frame-buffer memory.  First, we do a single line fill by hand */
+    oldstart = start = src = ri->Memory + X*Bpp + Y*ri->BytesPerRow;
+    
+    switch (Bpp) 
+    {
+    case 1:
+       memset (start, Pen, Width);
+        break;
+    case 2:
+       for (cols = 0; cols < Width; cols++) 
+       {
+           do_put_mem_word ((uae_u16 *)start, (uae_u16)Pen);
+           start += 2;
+       }
+        break;
+    case 3:
+       for (cols = 0; cols < Width; cols++) 
+       {
+           do_put_mem_byte (start, (uae_u8)Pen);
+           start++;
+           *(uae_u16 *)(start) = (Pen & 0x00FFFF00) >> 8;
+           start+=2;
+       }
+        break;
+    case 4:
+       for (cols = 0; cols < Width; cols++) 
+       {
+           /**start = Pen; */
+           do_put_mem_long ((uae_u32 *)start, Pen);
+           start += 4;
+       }
+        break;
+    }
+    src = oldstart;
+    dst = src + ri->BytesPerRow;
+    /* next, we do the remaining line fills via memcpy() for > 1 BPP, otherwise some more memset() calls */
+    if( Bpp > 1 )
+    {
+       for (lines = 0; lines < (Height - 1); lines++, dst += ri->BytesPerRow)
+           memcpy (dst, src, Width * Bpp);
+    }
+    else
+    {
+       for (lines = 0; lines < (Height - 1); lines++, dst += ri->BytesPerRow)
+           memset( dst, Pen, Width );
+    }
+}
+
+void picasso_handle_vsync (void)
+{
+    DX_Invalidate(1,4000);      //so a flushpixel is done every vsync if pixel are in buffer
+    PICASSO96_Unlock();
+    if (palette_changed) {
+        DX_SetPalette (0,256);
+        palette_changed = 0;
+    }
+}
+
+static int set_panning_called = 0;
+
+/* Clear our screen, since we've got a new Picasso screen-mode, and refresh with the proper contents
+* This is called on several occasions:
+* 1. Amiga-->Picasso transition, via SetSwitch()
+* 2. Picasso-->Picasso transition, via SetPanning().
+* 3. whenever the graphics code notifies us that the screen contents have been lost.
+*/
+extern unsigned int new_beamcon0;
+void picasso_refresh( int call_setpalette )
+{
+    struct RenderInfo ri;
+   
+    if (! picasso_on)
+       return;
+    {  //for higher P96 mousedraw rate
+       /* HACK */
+       extern uae_u16 vtotal;
+       if (p96hack_vpos2){
+           vtotal=p96hack_vpos2;
+           new_beamcon0 |= 0x80;
+           p96refresh_active=1;
+       } else new_beamcon0 |= 0x20;
+               /* HACK until ntsc timing is fixed.. */
+    } //end for higher P96 mousedraw rate
+       
+    
+
+    have_done_picasso = 1;
+    
+    /* Make sure that the first time we show a Picasso video mode, we don't blit any crap.
+    * We can do this by checking if we have an Address yet.  */
+    if (picasso96_state.Address) {
+       unsigned int width, height;
+
+       /* blit the stuff from our static frame-buffer to the gfx-card */
+       ri.Memory = gfxmemory + (picasso96_state.Address - gfxmem_start);
+       ri.BytesPerRow = picasso96_state.BytesPerRow;
+       ri.RGBFormat = picasso96_state.RGBFormat;
+
+       if( set_panning_called )
+       {
+           width = ( picasso96_state.VirtualWidth < picasso96_state.Width ) ?
+               picasso96_state.VirtualWidth : picasso96_state.Width;
+           height = ( picasso96_state.VirtualHeight < picasso96_state.Height ) ?
+               picasso96_state.VirtualHeight : picasso96_state.Height;
+           // Let's put a black-border around the case where we've got a sub-screen...
+           if( !picasso96_state.BigAssBitmap )
+           {
+               if (picasso96_state.XOffset || picasso96_state.YOffset)
+                   DX_Fill( 0, 0, picasso96_state.Width, picasso96_state.Height, 0,
+                       picasso96_state.RGBFormat );
+           }
+       }
+       else
+       {
+           width = picasso96_state.Width;
+           height = picasso96_state.Height;
+       }
+       do_blit(&ri, picasso96_state.BytesPerPixel, 0, 0, 0, 0, width, height, BLIT_SRC, 0);
+    } 
+    else
+    {
+       write_log ("ERROR - picasso_refresh() can't refresh!\n");
+    }
+}
+
+
+/*
+* Functions to perform an action on the frame-buffer
+*/
+STATIC_INLINE void do_blitrect_frame_buffer( struct RenderInfo *ri, struct
+RenderInfo *dstri, unsigned long srcx, unsigned long srcy,
+    unsigned long dstx, unsigned long dsty, unsigned long width, unsigned
+long height, uae_u8 mask, BLIT_OPCODE opcode )
+{
+    
+    uae_u8 *src, *dst, *tmp, *tmp2, *tmp3;
+    uae_u8 Bpp = GetBytesPerPixel(ri->RGBFormat);
+    unsigned long total_width = width * Bpp;
+    unsigned long linewidth = (total_width + 15) & ~15;
+    unsigned long lines;
+    int can_do_visible_blit = 0;
+
+    src = ri->Memory + srcx*Bpp + srcy*ri->BytesPerRow;
+    dst = dstri->Memory + dstx*Bpp + dsty*dstri->BytesPerRow;
+    if (mask != 0xFF && Bpp > 1)
+    {
+    write_log ("WARNING - BlitRect() has mask 0x%x with Bpp %d.\n", mask, Bpp);
+    }
+    
+    if (mask == 0xFF || Bpp > 1) 
+    {
+    if( opcode == BLIT_SRC )
+    {
+        /* handle normal case efficiently */
+        if (ri->Memory == dstri->Memory && dsty == srcy) 
+        {
+        unsigned long i;
+        for (i = 0; i < height; i++, src += ri->BytesPerRow, dst += dstri->BytesPerRow)
+            memmove (dst, src, total_width);
+        }
+        else if (dsty < srcy) 
+        {
+        unsigned long i;
+        for (i = 0; i < height; i++, src += ri->BytesPerRow, dst += dstri->BytesPerRow)
+            memcpy (dst, src, total_width);
+        }
+        else
+        {
+        unsigned long i;
+        src += (height-1) * ri->BytesPerRow;
+        dst += (height-1) * dstri->BytesPerRow;
+        for (i = 0; i < height; i++, src -= ri->BytesPerRow, dst -= dstri->BytesPerRow)
+            memcpy (dst, src, total_width);
+        }
+        return;
+    }
+    else
+    {
+        uae_u8 *src2 = src;
+        uae_u8 *dst2 = dst;
+        uae_u32 *src2_32 = (uae_u32*)src;
+        uae_u32 *dst2_32 = (uae_u32*)dst;
+        unsigned int y;
+        
+        for( y = 0; y < height; y++ ) /* Vertical lines */
+        {
+        int bound = src + total_width - 4;
+        //copy now the longs
+        for( src2_32 = src, dst2_32 = dst; src2_32 < bound; src2_32++, dst2_32++ ) /* Horizontal bytes */
+        {
+            switch( opcode )
+            {
+            case BLIT_FALSE:
+            *dst2_32 = 0;
+            break;
+            case BLIT_NOR:
+            *dst2_32 = ~(*src2_32 | *dst2_32);
+            break;
+            case BLIT_ONLYDST:
+            *dst2_32 = *dst2_32 & ~(*src2_32);
+            break;
+            case BLIT_NOTSRC:
+            *dst2_32 = ~(*src2_32);
+            break;
+            case BLIT_ONLYSRC:
+            *dst2_32 = *src2_32 & ~(*dst2_32);
+            break;
+            case BLIT_NOTDST:
+            *dst2_32 = ~(*dst2_32);
+            break;
+            case BLIT_EOR:
+            *dst2_32 = *src2_32 ^ *dst2_32;
+            break;
+            case BLIT_NAND:
+            *dst2_32 = ~(*src2_32 & *dst2_32);
+            break;
+            case BLIT_AND:
+            *dst2_32 = *src2_32 & *dst2_32;
+            break;
+            case BLIT_NEOR:
+            *dst2_32 = ~(*src2_32 ^ *dst2_32);
+            break;
+            case BLIT_DST:
+            write_log( "do_blitrect_frame_buffer shouldn't get BLIT_DST!\n");
+            break;
+            case BLIT_NOTONLYSRC:
+            *dst2_32 = ~(*src2_32) | *dst2_32;
+            break;
+            case BLIT_SRC:
+            write_log( "do_blitrect_frame_buffer shouldn't get BLIT_SRC!\n");
+            break;
+            case BLIT_NOTONLYDST:
+            *dst2_32 = ~(*dst2_32) | *src2_32;
+            break;
+            case BLIT_OR:
+            *dst2_32 = *src2_32 | *dst2_32;
+            break;
+            case BLIT_TRUE:
+            *dst2_32 = 0xFFFFFFFF;
+            break;
+           case 30: //code for swap source with dest in byte
+           {       
+               uae_u32 temp;
+               temp = *src2_32;
+               *src2_32 = *dst2_32;
+               *dst2_32 = temp;
+           }
+           break;
+            case BLIT_LAST:
+            write_log( "do_blitrect_frame_buffer shouldn't get BLIT_LAST!\n");
+            break;
+            } /* switch opcode */
+        }// for end
+        //now copy the rest few bytes
+        for( src2 = src2_32, dst2 = dst2_32; src2 < src + total_width; src2++, dst2++ ) /* Horizontal bytes */
+        {
+            switch( opcode )
+            {
+            case BLIT_FALSE:
+            *dst2 = 0;
+            break;
+            case BLIT_NOR:
+            *dst2 = ~(*src2 | *dst2);
+            break;
+            case BLIT_ONLYDST:
+            *dst2 = *dst2 & ~(*src2);
+            break;
+            case BLIT_NOTSRC:
+            *dst2 = ~(*src2);
+            break;
+            case BLIT_ONLYSRC:
+            *dst2 = *src2 & ~(*dst2);
+            break;
+            case BLIT_NOTDST:
+            *dst2 = ~(*dst2);
+            break;
+            case BLIT_EOR:
+            *dst2 = *src2 ^ *dst2;
+            break;
+            case BLIT_NAND:
+            *dst2 = ~(*src2 & *dst2);
+            break;
+            case BLIT_AND:
+            *dst2 = *src2 & *dst2;
+            break;
+            case BLIT_NEOR:
+            *dst2 = ~(*src2 ^ *dst2);
+            break;
+            case BLIT_DST:
+            write_log( "do_blitrect_frame_buffer shouldn't get BLIT_DST!\n");
+            break;
+            case BLIT_NOTONLYSRC:
+            *dst2 = ~(*src2) | *dst2;
+            break;
+            case BLIT_SRC:
+            write_log( "do_blitrect_frame_buffer shouldn't get BLIT_SRC!\n");
+            break;
+            case BLIT_NOTONLYDST:
+            *dst2 = ~(*dst2) | *src2;
+            break;
+            case BLIT_OR:
+            *dst2 = *src2 | *dst2;
+            break;
+            case BLIT_TRUE:
+            *dst2 = 0xFF;
+            break;
+            case BLIT_LAST:
+            write_log( "do_blitrect_frame_buffer shouldn't get BLIT_LAST!\n");
+            break;
+            case 30: //code for swap source with dest in long
+                {
+                uae_u8 temp;
+                temp = *src2;
+                *src2 = *dst2;
+                *dst2 = temp;
+                }
+            break;
+            } /* switch opcode */
+        } /* for width */
+        src += ri->BytesPerRow;
+        dst += dstri->BytesPerRow;
+        } /* for height */
+    }
+    return;
+        }
+    
+    tmp3 = tmp2 = tmp = xmalloc (linewidth * height); /* allocate enough
+memory for the src-rect */
+    if (!tmp)
+    return;
+    
+    /* copy the src-rect into our temporary buffer space */
+    for (lines = 0; lines < height; lines++, src += ri->BytesPerRow, tmp2 +=
+linewidth) 
+    {
+    memcpy (tmp2, src, total_width);
+    }
+    
+    /* copy the temporary buffer to the destination */
+    for (lines = 0; lines < height; lines++, dst += dstri->BytesPerRow, tmp
++= linewidth) 
+    {
+    unsigned long cols;
+    for (cols = 0; cols < width; cols++) 
+    {
+        dst[cols] &= ~mask;
+        dst[cols] |= tmp[cols] & mask;
+    }
+    }
+    /* free the temp-buf */
+    free (tmp3);
+} 
+
+#if 0
+/*
+* Functions to perform an action on the frame-buffer
+*/
+STATIC_INLINE void do_blitrect_frame_buffer( struct RenderInfo *ri, struct RenderInfo *dstri, unsigned long srcx, unsigned long srcy,
+    unsigned long dstx, unsigned long dsty, unsigned long width, unsigned long height, uae_u8 mask, BLIT_OPCODE opcode )
+{
+    
+    uae_u8 *src, *dst, *tmp, *tmp2, *tmp3;
+    uae_u8 Bpp = GetBytesPerPixel(ri->RGBFormat);
+    unsigned long total_width = width * Bpp;
+    unsigned long linewidth = (total_width + 15) & ~15;
+    unsigned long lines;
+    int can_do_visible_blit = 0;
+
+    src = ri->Memory + srcx*Bpp + srcy*ri->BytesPerRow;
+    dst = dstri->Memory + dstx*Bpp + dsty*dstri->BytesPerRow;
+    if (mask != 0xFF && Bpp > 1)
+    {
+       write_log ("WARNING - BlitRect() has mask 0x%x with Bpp %d.\n", mask, Bpp);
+    }
+    
+    if (mask == 0xFF || Bpp > 1) 
+    {
+       if( opcode == BLIT_SRC )
+       {
+           /* handle normal case efficiently */
+           if (ri->Memory == dstri->Memory && dsty == srcy) 
+           {
+               unsigned long i;
+               for (i = 0; i < height; i++, src += ri->BytesPerRow, dst += dstri->BytesPerRow)
+                   memmove (dst, src, total_width);
+           }
+           else if (dsty < srcy) 
+           {
+               unsigned long i;
+               for (i = 0; i < height; i++, src += ri->BytesPerRow, dst += dstri->BytesPerRow)
+                   memcpy (dst, src, total_width);
+           }
+           else
+           {
+               unsigned long i;
+               src += (height-1) * ri->BytesPerRow;
+               dst += (height-1) * dstri->BytesPerRow;
+               for (i = 0; i < height; i++, src -= ri->BytesPerRow, dst -= dstri->BytesPerRow)
+                   memcpy (dst, src, total_width);
+           }
+           return;
+       }
+       else
+       {
+           uae_u8 *src2 = src;
+           uae_u8 *dst2 = dst;
+           unsigned int y;
+           
+           for( y = 0; y < height; y++ ) /* Vertical lines */
+           {
+               for( src2 = src, dst2 = dst; src2 < src + total_width; src2++, dst2++ ) /* Horizontal bytes */
+               {
+                   switch( opcode )
+                   {
+                   case BLIT_FALSE:
+                       *dst2 = 0;
+                       break;
+                   case BLIT_NOR:
+                       *dst2 = ~(*src2 | *dst2);
+                       break;
+                   case BLIT_ONLYDST:
+                       *dst2 = *dst2 & ~(*src2);
+                       break;
+                   case BLIT_NOTSRC:
+                       *dst2 = ~(*src2);
+                       break;
+                   case BLIT_ONLYSRC:
+                       *dst2 = *src2 & ~(*dst2);
+                       break;
+                   case BLIT_NOTDST:
+                       *dst2 = ~(*dst2);
+                       break;
+                   case BLIT_EOR:
+                       *dst2 = *src2 ^ *dst2;
+                       break;
+                   case BLIT_NAND:
+                       *dst2 = ~(*src2 & *dst2);
+                       break;
+                   case BLIT_AND:
+                       *dst2 = *src2 & *dst2;
+                       break;
+                   case BLIT_NEOR:
+                       *dst2 = ~(*src2 ^ *dst2);
+                       break;
+                   case BLIT_DST:
+                       write_log( "do_blitrect_frame_buffer shouldn't get BLIT_DST!\n" );
+                       break;
+                   case BLIT_NOTONLYSRC:
+                       *dst2 = ~(*src2) | *dst2;
+                       break;
+                   case BLIT_SRC:
+                       write_log( "do_blitrect_frame_buffer shouldn't get BLIT_SRC!\n" );
+                       break;
+                   case BLIT_NOTONLYDST:
+                       *dst2 = ~(*dst2) | *src2;
+                       break;
+                   case BLIT_OR:
+                       *dst2 = *src2 | *dst2;
+                       break;
+                   case BLIT_TRUE:
+                       *dst2 = 0xFF;
+                       break;
+                   case BLIT_LAST:
+                       write_log( "do_blitrect_frame_buffer shouldn't get BLIT_LAST!\n" );
+                       break;
+                   } /* switch opcode */
+               } /* for width */
+               src += ri->BytesPerRow;
+               dst += dstri->BytesPerRow;
+           } /* for height */
+       }
+       return;
+        }
+    
+    tmp3 = tmp2 = tmp = xmalloc (linewidth * height); /* allocate enough memory for the src-rect */
+    if (!tmp)
+       return;
+    
+    /* copy the src-rect into our temporary buffer space */
+    for (lines = 0; lines < height; lines++, src += ri->BytesPerRow, tmp2 += linewidth) 
+    {
+       memcpy (tmp2, src, total_width);
+    }
+    
+    /* copy the temporary buffer to the destination */
+    for (lines = 0; lines < height; lines++, dst += dstri->BytesPerRow, tmp += linewidth) 
+    {
+       unsigned long cols;
+       for (cols = 0; cols < width; cols++) 
+       {
+           dst[cols] &= ~mask;
+           dst[cols] |= tmp[cols] & mask;
+       }
+    }
+    /* free the temp-buf */
+    free (tmp3);
+}
+#endif
+
+/*
+DrawLine: 
+Synopsis: DrawLine(bi, ri, line, Mask, RGBFormat); 
+Inputs: a0: struct BoardInfo *bi 
+a1: struct RenderInfo *ri 
+a2: struct Line *line 
+d0.b: Mask 
+d7.l: RGBFormat 
+
+This function is used to paint a line on the board memory possibly using the blitter. It is called by Draw
+and obeyes the destination RGBFormat as well as ForeGround and BackGround pens and draw modes. 
+*/
+uae_u32 picasso_DrawLine (void)
+{
+    uae_u32 result = 0;
+#ifdef P96_DRAWLINE
+    struct Line line;
+    struct RenderInfo ri;
+    uae_u8 Mask = m68k_dreg( regs, 0 );
+    RGBFTYPE RGBFormat = m68k_dreg( regs, 7 );
+
+    CopyRenderInfoStructureA2U( m68k_areg( regs, 1 ), &ri );
+    CopyLineStructureA2U( m68k_areg( regs, 2 ), &line );
+#if defined( P96TRACING_ENABLED ) && P96TRACING_LEVEL > 0
+    DumpLine( &line );
+#endif
+#else
+    P96TRACE(("DrawLine() - not implemented!\n" ));
+#endif
+    return result;
+}
+
+#ifdef HARDWARE_SPRITE_EMULATION
+/*
+SetSprite: 
+Synopsis: SetSprite(bi, activate, RGBFormat); 
+Inputs: a0: struct BoardInfo *bi 
+d0: BOOL activate 
+d7: RGBFTYPE RGBFormat 
+
+This function activates or deactivates the hardware sprite. 
+*/
+uae_u32 picasso_SetSprite (void)
+{
+    uae_u32 result = 0;
+    uae_u32 activate = m68k_dreg( regs, 0 );
+    result = DX_ShowCursor( activate );
+    write_log ("SetSprite() - trying to %s cursor, result = %d\n", activate ? "show":"hide", result);
+    return result;
+}
+
+/*
+SetSpritePosition: 
+Synopsis: SetSpritePosition(bi, RGBFormat); 
+Inputs: a0: struct BoardInfo *bi 
+d7: RGBFTYPE RGBFormat 
+
+This function sets the hardware mouse sprite position according to the values in the BoardInfo structure.
+MouseX and MouseY are the coordinates relative to the screen bitmap. XOffset and YOffset must be subtracted
+to account for possible screen panning. 
+*/
+uae_u32 picasso_SetSpritePosition (void)
+{
+    uae_u32 result = 0;
+    uaecptr bi = m68k_areg( regs, 0 );
+    uae_u16 MouseX  = get_word( bi + PSSO_BoardInfo_MouseX ) - picasso96_state.XOffset;
+    uae_u16 MouseY  = get_word( bi + PSSO_BoardInfo_MouseY ) - picasso96_state.YOffset;
+    
+    // Keep these around, because we don't want flickering
+    static uae_u16 OldMouseX = -1;
+    static uae_u16 OldMouseY = -1;
+
+    // Bounds check MouseX and MouseY here, because sometimes they seem to go negative...
+    if( (uae_s16)MouseX < 0 )
+       MouseX = 0;
+    if( (uae_s16)MouseY < 0 )
+       MouseY = 0;
+
+    if( ( MouseX != OldMouseX ) || ( MouseY != OldMouseY ) )
+    {
+       result = DX_MoveCursor( MouseX, MouseY );
+       write_log ("SetSpritePosition() - moving cursor to (%d,%d), result = %d\n", MouseX, MouseY, result);
+       if( result )
+       {
+           OldMouseX = MouseX;
+           OldMouseY = MouseY;
+       }
+    }
+    return result;
+}
+
+/*
+SetSpriteImage: 
+Synopsis: SetSpriteImage(bi, RGBFormat); 
+Inputs: a0: struct BoardInfo *bi 
+d7: RGBFTYPE RGBFormat 
+
+This function gets new sprite image data from the MouseImage field of the BoardInfo structure and writes
+it to the board.
+
+There are three possible cases: 
+
+BIB_HIRESSPRITE is set:
+skip the first two long words and the following sprite data is arranged as an array of two longwords. Those form the
+two bit planes for one image line respectively. 
+
+BIB_HIRESSPRITE and BIB_BIGSPRITE are not set:
+skip the first two words and the following sprite data is arranged as an array of two words. Those form the two
+bit planes for one image line respectively. 
+
+BIB_HIRESSPRITE is not set and BIB_BIGSPRITE is set:
+skip the first two words and the following sprite data is arranged as an array of two words. Those form the two bit
+planes for one image line respectively. You have to double each pixel horizontally and vertically. All coordinates
+used in this case already assume a zoomed sprite, only the sprite data is not zoomed yet. You will have to
+compensate for this when accounting for hotspot offsets and sprite dimensions. 
+*/
+uae_u32 picasso_SetSpriteImage (void)
+{
+    uae_u32 result = 0;
+
+    return result;
+}
+
+/*
+SetSpriteColor: 
+Synopsis: SetSpriteColor(bi, index, red, green, blue, RGBFormat); 
+Inputs: a0: struct BoardInfo *bi 
+d0.b: index 
+d1.b: red 
+d2.b: green 
+d3.b: blue 
+d7: RGBFTYPE RGBFormat 
+
+This function changes one of the possible three colors of the hardware sprite. 
+*/
+uae_u32 picasso_SetSpriteColor (void)
+{
+    uae_u32 result = 0;
+
+    return result;
+}
+#endif
+
+/*
+* BOOL FindCard(struct BoardInfo *bi);       and
+*
+* FindCard is called in the first stage of the board initialisation and
+* configuration and is used to look if there is a free and unconfigured
+* board of the type the driver is capable of managing. If it finds one,
+* it immediately reserves it for use by Picasso96, usually by clearing
+* the CDB_CONFIGME bit in the flags field of the ConfigDev struct of
+* this expansion card. But this is only a common example, a driver can
+* do whatever it wants to mark this card as used by the driver. This
+* mechanism is intended to ensure that a board is only configured and
+* used by one driver. FindBoard also usually fills some fields of the
+* BoardInfo struct supplied by the caller, the rtg.library, for example
+* the MemoryBase, MemorySize and RegisterBase fields.
+*/
+uae_u32 picasso_FindCard (void)
+{
+    uaecptr AmigaBoardInfo = m68k_areg (regs, 0);
+
+    /* NOTES: See BoardInfo struct definition in Picasso96 dev info */
+    
+    if (allocated_gfxmem && !picasso96_state.CardFound) {
+       /* Fill in MemoryBase, MemorySize */
+       put_long (AmigaBoardInfo + PSSO_BoardInfo_MemoryBase, gfxmem_start);
+       /* size of memory, minus a 32K chunk: 16K for pattern bitmaps, 16K for resolution list */
+       put_long (AmigaBoardInfo + PSSO_BoardInfo_MemorySize, allocated_gfxmem - 32768);
+       picasso96_state.CardFound = 1; /* mark our "card" as being found */
+       return -1;
+    } else
+       return 0;
+}
+
+static void FillBoardInfo (uaecptr amigamemptr, struct LibResolution *res, struct PicassoResolution *dm)
+{
+    char *uaememptr;
+    switch (dm->depth) {
+    case 1:
+       res->Modes[CHUNKY] = amigamemptr;
+       break;
+    case 2:
+       res->Modes[HICOLOR] = amigamemptr;
+       break;
+    case 3:
+       res->Modes[TRUECOLOR] = amigamemptr;
+       break;
+    default:
+       res->Modes[TRUEALPHA] = amigamemptr;
+       break;
+    }
+    uaememptr = gfxmem_xlate(amigamemptr); /* I know that amigamemptr is inside my gfxmem chunk, so I can just do the xlate() */
+    memset(uaememptr, 0, PSSO_ModeInfo_sizeof); /* zero out our ModeInfo struct */
+    
+    put_word (amigamemptr + PSSO_ModeInfo_Width, dm->res.width);
+    put_word (amigamemptr + PSSO_ModeInfo_Height, dm->res.height);
+    put_byte (amigamemptr + PSSO_ModeInfo_Depth, dm->depth * 8);
+    put_byte (amigamemptr + PSSO_ModeInfo_Flags, 0);
+    put_word (amigamemptr + PSSO_ModeInfo_HorTotal, dm->res.width);
+    put_word (amigamemptr + PSSO_ModeInfo_HorBlankSize, 0);
+    put_word (amigamemptr + PSSO_ModeInfo_HorSyncStart, 0);
+    put_word (amigamemptr + PSSO_ModeInfo_HorSyncSize, 0);
+    put_byte (amigamemptr + PSSO_ModeInfo_HorSyncSkew, 0);
+    put_byte (amigamemptr + PSSO_ModeInfo_HorEnableSkew, 0);
+    
+    put_word (amigamemptr + PSSO_ModeInfo_VerTotal, dm->res.height);
+    put_word (amigamemptr + PSSO_ModeInfo_VerBlankSize, 0);
+    put_word (amigamemptr + PSSO_ModeInfo_VerSyncStart, 0);
+    put_word (amigamemptr + PSSO_ModeInfo_VerSyncSize, 0);
+    
+    put_byte (amigamemptr + PSSO_ModeInfo_first_union, 98);
+    put_byte (amigamemptr + PSSO_ModeInfo_second_union, 14);
+    
+    put_long (amigamemptr + PSSO_ModeInfo_PixelClock, dm->res.width * dm->res.height * (currprefs.gfx_refreshrate ? currprefs.gfx_refreshrate : default_freq));
+}
+
+static int AssignModeID( int i, int count )
+{
+    int result;
+    if( DisplayModes[i].res.width == 320 && DisplayModes[i].res.height == 200 )
+        result = 0x50001000;
+    else  if( DisplayModes[i].res.width == 320 && DisplayModes[i].res.height == 240 )
+        result = 0x50011000;
+    else if( DisplayModes[i].res.width == 640 && DisplayModes[i].res.height == 400 )
+        result = 0x50021000;
+    else if( DisplayModes[i].res.width == 640 && DisplayModes[i].res.height == 480 )
+       result = 0x50031000;
+    else if( DisplayModes[i].res.width == 800 && DisplayModes[i].res.height == 600 )
+       result = 0x50041000;
+    else if( DisplayModes[i].res.width == 1024 && DisplayModes[i].res.height == 768 )
+        result = 0x50051000;
+    else if( DisplayModes[i].res.width == 1152 && DisplayModes[i].res.height == 864 )
+        result = 0x50061000;
+    else if( DisplayModes[i].res.width == 1280 && DisplayModes[i].res.height == 1024 )
+        result = 0x50071000;
+    else if( DisplayModes[i].res.width == 1600 && DisplayModes[i].res.height == 1280 )
+        result = 0x50081000;
+    else
+       result = 0x50091000 + count * 0x10000;
+    return result;
+}
+
+/****************************************
+* InitCard()
+*
+* a2: BoardInfo structure ptr - Amiga-based address in Intel endian-format
+*
+* Job - fill in the following structure members:
+* gbi_RGBFormats: the pixel formats that the host-OS of UAE supports
+*     If UAE is running in a window, it should ONLY report the pixel format of the host-OS desktop
+*     If UAE is running full-screen, it should report ALL pixel formats that the host-OS can handle in full-screen
+*     NOTE: If full-screen, and the user toggles to windowed-mode, all hell will break loose visually.  Must inform
+*           user that they're doing something stupid (unless their desktop and full-screen colour modes match).
+* gbi_SoftSpriteFlags: should be the same as above for now, until actual cursor support is added
+* gbi_BitsPerCannon: could be 6 or 8 or ???, depending on the host-OS gfx-card
+* gbi_MaxHorResolution: fill this in for all modes (even if you don't support them)
+* gbi_MaxVerResolution: fill this in for all modes (even if you don't support them)
+*/
+uae_u32 picasso_InitCard (void)
+{
+    struct LibResolution res;
+    int i;
+    int ModeInfoStructureCount = 1, LibResolutionStructureCount = 0;
+    uaecptr amigamemptr = 0;
+    uaecptr AmigaBoardInfo = m68k_areg (regs, 2);
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_BitsPerCannon, DX_BitsPerCannon());
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_RGBFormats, picasso96_pixel_format);
+    put_long (AmigaBoardInfo + PSSO_BoardInfo_BoardType, BT_uaegfx);
+#ifdef HARDWARE_SPRITE_EMULATION
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_SoftSpriteFlags, 0);
+#else
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_SoftSpriteFlags, picasso96_pixel_format);
+#endif
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 0, planar.width);
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 2, chunky.width);
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 4, hicolour.width);
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 6, truecolour.width);
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 8, alphacolour.width);
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 0, planar.height);
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 2, chunky.height);
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 4, hicolour.height);
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 6, truecolour.height);
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 8, alphacolour.height);
+    
+    i = 0;
+    while (DisplayModes[i].depth >= 0) {    
+       int j = i;
+       /* Add a LibResolution structure to the ResolutionsList MinList in our BoardInfo */
+       res.DisplayID = AssignModeID( i, LibResolutionStructureCount );
+       res.BoardInfo = AmigaBoardInfo;
+       res.Width = DisplayModes[i].res.width;
+       res.Height = DisplayModes[i].res.height;
+       res.Flags = P96F_PUBLIC;
+       memcpy (res.P96ID, "P96-0:", 6);
+       sprintf (res.Name, "uaegfx:%dx%d", res.Width, res.Height);
+       res.Modes[PLANAR] = 0;
+       res.Modes[CHUNKY] = 0;
+       res.Modes[HICOLOR] = 0;
+       res.Modes[TRUECOLOR] = 0;
+       res.Modes[TRUEALPHA] = 0;
+       
+       do {
+           /* Handle this display mode's depth */
+           
+           /* New: Only add the modes when there is enough P96 RTG memory to hold the bitmap */
+           if( ( allocated_gfxmem - 32768 ) >
+               ( DisplayModes[i].res.width * DisplayModes[i].res.height * DisplayModes[i].depth ) )
+           {
+               amigamemptr = gfxmem_start + allocated_gfxmem - (PSSO_ModeInfo_sizeof * ModeInfoStructureCount++);
+               FillBoardInfo(amigamemptr, &res, &DisplayModes[i]);
+           }
+           i++;
+       } while (DisplayModes[i].depth >= 0
+           && DisplayModes[i].res.width == DisplayModes[j].res.width
+           && DisplayModes[i].res.height == DisplayModes[j].res.height);
+       
+       amigamemptr = gfxmem_start + allocated_gfxmem - 16384 + (PSSO_LibResolution_sizeof * LibResolutionStructureCount++);
+       CopyLibResolutionStructureU2A (&res, amigamemptr);
+#if defined P96TRACING_ENABLED && P96TRACING_LEVEL > 1
+       DumpLibResolutionStructure( amigamemptr);
+#endif
+       AmigaListAddTail (AmigaBoardInfo + PSSO_BoardInfo_ResolutionsList, amigamemptr);
+    }
+    
+    return -1;
+}
+
+extern int x_size, y_size;
+
+/*
+* SetSwitch:
+* a0:  struct BoardInfo
+* d0.w:        BOOL state
+* this function should set a board switch to let the Amiga signal pass
+* through when supplied with a 0 in d0 and to show the board signal if
+* a 1 is passed in d0. You should remember the current state of the
+* switch to avoid unneeded switching. If your board has no switch, then
+* simply supply a function that does nothing except a RTS.
+*
+* NOTE: Return the opposite of the switch-state. BDK
+*/
+uae_u32 picasso_SetSwitch (void)
+{
+    uae_u16 flag = m68k_dreg (regs, 0) & 0xFFFF;
+
+    /* Do not switch immediately.  Tell the custom chip emulation about the
+    * desired state, and wait for custom.c to call picasso_enablescreen
+    * whenever it is ready to change the screen state.  */
+    picasso_requested_on = flag;
+    write_log ("SetSwitch() - trying to show %s screen\n", flag ? "picasso96":"amiga");
+    
+    /* Put old switch-state in D0 */
+       
+    return !flag;
+}
+
+void picasso_enablescreen (int on)
+{  
+    wgfx_linestart = 0xFFFFFFFF;
+    picasso_refresh (1);
+    write_log ("SetSwitch() from threadid %d - showing %s screen\n", GetCurrentThreadId(), on ? "picasso96": "amiga");
+}
+
+/*
+* SetColorArray:
+* a0: struct BoardInfo
+* d0.w: startindex
+* d1.w: count
+* when this function is called, your driver has to fetch "count" color
+* values starting at "startindex" from the CLUT field of the BoardInfo
+* structure and write them to the hardware. The color values are always
+* between 0 and 255 for each component regardless of the number of bits
+* per cannon your board has. So you might have to shift the colors
+* before writing them to the hardware.
+*/
+uae_u32 picasso_SetColorArray (void)
+{
+/* Fill in some static UAE related structure about this new CLUT setting
+    * We need this for CLUT-based displays, and for mapping CLUT to hi/true colour */
+    uae_u16 start = m68k_dreg (regs, 0);
+    uae_u16 count = m68k_dreg (regs, 1);
+    int i;
+    uaecptr boardinfo = m68k_areg (regs, 0);
+    uaecptr clut = boardinfo + PSSO_BoardInfo_CLUT + start * 3;
+    
+    for (i = start; i < start + count; i++) {
+       int r = get_byte (clut);
+       int g = get_byte (clut + 1);
+       int b = get_byte (clut + 2);
+       
+       palette_changed |= (picasso96_state.CLUT[i].Red != r 
+           || picasso96_state.CLUT[i].Green != g
+           || picasso96_state.CLUT[i].Blue != b);
+       
+       picasso96_state.CLUT[i].Red = r; 
+       picasso96_state.CLUT[i].Green = g;
+       picasso96_state.CLUT[i].Blue = b;
+       clut += 3;
+    }
+    P96TRACE(("SetColorArray(%d,%d)\n", start, count));
+    return 1;
+}
+
+/*
+* SetDAC:
+* a0: struct BoardInfo
+* d7: RGBFTYPE RGBFormat
+* This function is called whenever the RGB format of the display changes,
+* e.g. from chunky to TrueColor. Usually, all you have to do is to set
+* the RAMDAC of your board accordingly.
+*/
+uae_u32 picasso_SetDAC (void)
+{
+/* Fill in some static UAE related structure about this new DAC setting
+    * Lets us keep track of what pixel format the Amiga is thinking about in our frame-buffer */
+    
+    P96TRACE(("SetDAC()\n"));
+    return 1;
+}
+
+
+static void init_picasso_screen( void )
+{
+    if( set_panning_called )
+    {
+       picasso96_state.Extent = picasso96_state.Address + ( picasso96_state.BytesPerRow * picasso96_state.VirtualHeight );
+    }
+    if (set_gc_called)
+    {  
+       gfx_set_picasso_modeinfo (picasso96_state.Width, picasso96_state.Height,
+           picasso96_state.GC_Depth, picasso96_state.RGBFormat);
+    }
+    if( ( picasso_vidinfo.width == picasso96_state.Width ) &&
+       ( picasso_vidinfo.height == picasso96_state.Height ) &&
+       ( picasso_vidinfo.depth == (picasso96_state.GC_Depth >> 3) ) &&
+       ( picasso_vidinfo.selected_rgbformat == picasso96_state.RGBFormat) ) 
+    {
+       DX_SetPalette (0, 256);
+       picasso_refresh (1); 
+    }
+}
+
+/*
+* SetGC:
+* a0: struct BoardInfo
+* a1: struct ModeInfo
+* d0: BOOL Border
+* This function is called whenever another ModeInfo has to be set. This
+* function simply sets up the CRTC and TS registers to generate the
+* timing used for that screen mode. You should not set the DAC, clocks
+* or linear start adress. They will be set when appropriate by their
+* own functions.
+*/
+uae_u32 picasso_SetGC (void)
+{
+    /* Fill in some static UAE related structure about this new ModeInfo setting */
+    uae_u32 border   = m68k_dreg (regs, 0);
+    uaecptr modeinfo = m68k_areg (regs, 1);
+    
+    picasso96_state.Width = get_word (modeinfo + PSSO_ModeInfo_Width);
+    picasso96_state.VirtualWidth = picasso96_state.Width; /* in case SetPanning doesn't get called */
+    
+    picasso96_state.Height = get_word (modeinfo + PSSO_ModeInfo_Height);
+    picasso96_state.VirtualHeight = picasso96_state.Height; /* in case SetPanning doesn't get called */
+    
+    picasso96_state.GC_Depth = get_byte (modeinfo + PSSO_ModeInfo_Depth);
+    picasso96_state.GC_Flags = get_byte (modeinfo + PSSO_ModeInfo_Flags);
+    
+    P96TRACE(("SetGC(%d,%d,%d,%d)\n", picasso96_state.Width, picasso96_state.Height, picasso96_state.GC_Depth, border ));
+    set_gc_called = 1;
+    init_picasso_screen ();
+    init_hz_p96 ();
+    return 1;
+}
+
+/*
+* SetPanning:
+* a0: struct BoardInfo
+* a1: UBYTE *Memory
+* d0: uae_u16 Width
+* d1: WORD XOffset
+* d2: WORD YOffset
+* d7: RGBFTYPE RGBFormat
+* This function sets the view origin of a display which might also be
+* overscanned. In register a1 you get the start address of the screen
+* bitmap on the Amiga side. You will have to subtract the starting
+* address of the board memory from that value to get the memory start
+* offset within the board. Then you get the offset in pixels of the
+* left upper edge of the visible part of an overscanned display. From
+* these values you will have to calculate the LinearStartingAddress
+* fields of the CRTC registers.
+
+  * NOTE: SetPanning() can be used to know when a Picasso96 screen is
+  * being opened.  Better to do the appropriate clearing of the
+  * background here than in SetSwitch() derived functions,
+  * because SetSwitch() is not called for subsequent Picasso screens.
+*/
+
+uae_u32 picasso_SetPanning (void)
+{   
+    uae_u16 Width = m68k_dreg (regs, 0);
+    uaecptr start_of_screen = m68k_areg (regs, 1);
+    uaecptr bi = m68k_areg( regs, 0 );
+    uaecptr bmeptr = get_long( bi + PSSO_BoardInfo_BitMapExtra );  /* Get our BoardInfo ptr's BitMapExtra ptr */
+    uae_u16 bme_width, bme_height;
+        
+    if(oldscr==0){
+       oldscr=start_of_screen;    
+    }
+    if ((oldscr!=start_of_screen)){
+       set_gc_called = 0;
+       oldscr=start_of_screen;
+    }
+
+    bme_width = get_word( bmeptr + PSSO_BitMapExtra_Width );
+    bme_height = get_word( bmeptr + PSSO_BitMapExtra_Height );
+    
+    picasso96_state.Address = start_of_screen; /* Amiga-side address */
+    picasso96_state.XOffset = (uae_s16)(m68k_dreg (regs, 1) & 0xFFFF);
+    picasso96_state.YOffset = (uae_s16)(m68k_dreg (regs, 2) & 0xFFFF);
+    picasso96_state.VirtualWidth = bme_width;
+    picasso96_state.VirtualHeight = bme_height;
+    if( ( bme_width > Width ) || ( bme_height > picasso96_state.Height ) ) // NOTE: These were != instead of > before...
+       picasso96_state.BigAssBitmap = 1;
+    else
+       picasso96_state.BigAssBitmap = 0;
+    picasso96_state.RGBFormat = m68k_dreg (regs, 7);
+    picasso96_state.BytesPerPixel = GetBytesPerPixel (picasso96_state.RGBFormat);
+    picasso96_state.BytesPerRow = bme_width * picasso96_state.BytesPerPixel;
+    
+    set_panning_called = 1;
+    P96TRACE(("SetPanning(%d, %d, %d) Start 0x%x, BPR %d Bpp %d RGBF %d\n",
+       Width, picasso96_state.XOffset, picasso96_state.YOffset,
+       start_of_screen, picasso96_state.BytesPerRow, picasso96_state.BytesPerPixel, picasso96_state.RGBFormat));
+    init_picasso_screen ();
+    set_panning_called = 0;
+    
+    return 1;
+}
+
+static void do_xor8 (uae_u8 *ptr, long len, uae_u32 val)
+{
+    int i;
+#if 0 && defined ALIGN_POINTER_TO32
+    int align_adjust = ALIGN_POINTER_TO32(ptr);
+    int len2;
+    
+    len -= align_adjust;
+    while (align_adjust) {
+       *ptr ^= val;
+       ptr++;
+       align_adjust--;
+    }
+    len2 = len >> 2;
+    len -= len2 << 2;
+    for (i = 0; i < len2; i++, ptr += 4) {
+       *(uae_u32 *)ptr ^= val;
+    }
+    while (len) {
+       *ptr ^= val;
+       ptr++;
+       len--;
+    }
+    return;
+#endif
+    for (i = 0; i < len; i++, ptr++) {
+       do_put_mem_byte (ptr, (uae_u8)( do_get_mem_byte (ptr) ^ val ) );
+    }
+}
+
+/*
+* InvertRect:
+* 
+* Inputs:
+* a0:struct BoardInfo *bi
+* a1:struct RenderInfo *ri
+* d0.w:X
+* d1.w:Y
+* d2.w:Width
+* d3.w:Height
+* d4.l:Mask
+* d7.l:RGBFormat
+* 
+* This function is used to invert a rectangular area on the board. It is called by BltBitMap,
+* BltPattern and BltTemplate.
+*/
+uae_u32 picasso_InvertRect (void)
+{
+    uaecptr renderinfo = m68k_areg (regs, 1);
+    unsigned long X = (uae_u16)m68k_dreg (regs, 0);
+    unsigned long Y = (uae_u16)m68k_dreg (regs, 1);
+    unsigned long Width = (uae_u16)m68k_dreg (regs, 2);
+    unsigned long Height = (uae_u16)m68k_dreg (regs, 3);
+    uae_u8 mask = (uae_u8)m68k_dreg (regs, 4);
+    int Bpp = GetBytesPerPixel (m68k_dreg (regs, 7));
+    uae_u32 xorval;
+    unsigned int lines;
+    struct RenderInfo ri;
+    uae_u8 *uae_mem, *rectstart;
+    unsigned long width_in_bytes;
+    uae_u32 result = 0;
+
+  
+#ifdef LOCK_UNLOCK_MADNESS
+    //PICASSO96_Unlock();
+#else 
+         wgfx_flushline ();    
+#endif
+    
+    if ( CopyRenderInfoStructureA2U (renderinfo, &ri))
+    {
+        P96TRACE(("InvertRect %dbpp 0x%lx\n", Bpp, (long)mask));
+    
+       if (mask != 0xFF && Bpp > 1) 
+       {
+           mask = 0xFF;
+       }
+
+       xorval = 0x01010101 * (mask & 0xFF);
+       width_in_bytes = Bpp * Width;
+       rectstart = uae_mem = ri.Memory + Y*ri.BytesPerRow + X*Bpp;
+    
+       for (lines = 0; lines < Height; lines++, uae_mem += ri.BytesPerRow)
+           do_xor8 (uae_mem, width_in_bytes, xorval);
+    
+       if (renderinfo_is_current_screen (&ri)) {
+           if (mask == 0xFF)
+               do_invertrect( &ri, Bpp, X, Y, Width, Height );
+           else
+               do_blit( &ri, Bpp, X, Y, X, Y, Width, Height, BLIT_SRC, 0);
+       }
+       result = 1;
+    }
+#ifdef LOCK_UNLOCK_MADNESS
+    //PICASSO96_Lock();
+#endif
+    return result; /* 1 if supported, 0 otherwise */
+}
+
+/***********************************************************
+FillRect:
+***********************************************************
+* a0:  struct BoardInfo *
+* a1:  struct RenderInfo *
+* d0:  WORD X
+* d1:  WORD Y
+* d2:  WORD Width
+* d3:  WORD Height
+* d4:  uae_u32 Pen
+* d5:  UBYTE Mask
+* d7:  uae_u32 RGBFormat
+***********************************************************/
+uae_u32 picasso_FillRect (void)
+{
+    uaecptr renderinfo = m68k_areg (regs, 1);
+    uae_u32 X = (uae_u16)m68k_dreg (regs, 0);
+    uae_u32 Y = (uae_u16)m68k_dreg (regs, 1);
+    uae_u32 Width = (uae_u16)m68k_dreg (regs, 2);
+    uae_u32 Height = (uae_u16)m68k_dreg (regs, 3);
+    uae_u32 Pen = m68k_dreg (regs, 4);
+    uae_u8 Mask = (uae_u8)m68k_dreg (regs, 5);
+    RGBFTYPE RGBFormat = m68k_dreg (regs, 7);
+    
+    uae_u8 *src;
+    uae_u8 *oldstart;
+    int Bpp;
+    struct RenderInfo ri;
+    uae_u32 result = 0;
+
+    special_mem|=picasso_is_special_read|picasso_is_special;     
+
+#ifdef LOCK_UNLOCK_MADNESS
+    //PICASSO96_Unlock(); // We need this, because otherwise we're still Locked from custom.c
+#else
+    wgfx_flushline ();
+#endif
+    
+    if ( CopyRenderInfoStructureA2U (renderinfo, &ri) && Y != 0xFFFF)
+    {
+       if (ri.RGBFormat != RGBFormat)
+           write_log ("Weird Stuff!\n");
+    
+       Bpp = GetBytesPerPixel (RGBFormat);
+    
+       P96TRACE(("FillRect(%d, %d, %d, %d) Pen 0x%x BPP %d BPR %d Mask 0x%x\n",
+           X, Y, Width, Height, Pen, Bpp, ri.BytesPerRow, Mask));
+    
+       if( Bpp > 1 )
+           Mask = 0xFF;
+    
+       if (Mask == 0xFF) 
+       {
+           if( ( Width == 1 ) || ( Height == 1 ) )
+           {
+               int i;
+               uaecptr addr;
+               if( renderinfo_is_current_screen( &ri ) )
+               {
+                   uae_u32 diff=gfxmem_start-(uae_u32)gfxmemory;
+                   addr = ri.Memory + X*Bpp + Y*ri.BytesPerRow + diff;
+                   if( Width == 1 )
+                   {
+                       for( i = 0; i < Height; i++ )
+                       {
+                           if( Bpp == 4 )
+                               gfxmem_lput( addr + (i*picasso96_state.BytesPerRow ), Pen );
+                           else if( Bpp == 2 )
+                               gfxmem_wput( addr + (i*picasso96_state.BytesPerRow ), Pen );
+                           else
+                               gfxmem_bput( addr + (i*picasso96_state.BytesPerRow ), Pen );
+                       }
+                   }
+                   else if( Height == 1 )
+                   {
+                       for( i = 0; i < Width; i++ )
+                       {
+                           if( Bpp == 4 )
+                               gfxmem_lput( addr + (i*Bpp), Pen );
+                           else if( Bpp == 2 )
+                               gfxmem_wput( addr + (i*Bpp), Pen );
+                           else
+                               gfxmem_bput( addr + (i*Bpp), Pen );
+                       }
+                   }
+                   return 1;
+               }
+           }
+
+           /* Do the fill-rect in the frame-buffer */
+           do_fillrect_frame_buffer( &ri, X, Y, Width, Height, Pen, Bpp, RGBFormat ); 
+           /* Now we do the on-screen display, if renderinfo points to it */
+           if (renderinfo_is_current_screen (&ri))
+           {
+               src = ri.Memory + X*Bpp + Y*ri.BytesPerRow;
+               X=X-picasso96_state.XOffset;
+               Y=Y-picasso96_state.YOffset;        
+               if((int)X<0){Width=Width+X;X=0;}
+               if((int)Width<1)return 1;
+               if((int)Y<0){Height=Height+Y;Y=0;}
+               if((int)Height<1)return 1;
+               /* Argh - why does P96Speed do this to me, with FillRect only?! */
+               if( ( X < picasso96_state.Width) &&
+                   ( Y < picasso96_state.Height) )
+               {
+                   if( X+Width > picasso96_state.Width)
+                       Width = picasso96_state.Width - X;
+                   if( Y+Height > picasso96_state.Height)
+                       Height = picasso96_state.Height - Y;
+
+                   do_fillrect( src, X, Y, Width, Height, Pen, Bpp, RGBFormat );
+               }
+           }
+           result = 1;
+       }
+       else
+       {
+           /* We get here only if Mask != 0xFF */
+           if (Bpp != 1) 
+           {
+               write_log( "WARNING - FillRect() has unhandled mask 0x%x with Bpp %d. Using fall-back routine.\n", Mask, Bpp );
+           }
+           else
+           {
+               Pen &= Mask;
+               Mask = ~Mask;
+               oldstart = ri.Memory + Y*ri.BytesPerRow + X*Bpp;
+               {
+                   uae_u8 *start = oldstart;
+                   uae_u8 *end = start + Height * ri.BytesPerRow;
+                   for (; start != end; start += ri.BytesPerRow) 
+                   {
+                       uae_u8 *p = start;
+                       unsigned long cols;
+                       for (cols = 0; cols < Width; cols++) 
+                       {
+                           uae_u32 tmpval = do_get_mem_byte (p + cols) & Mask;
+                           do_put_mem_byte (p + cols, (uae_u8)( Pen | tmpval ) );
+                       }
+                   }
+               }
+               if (renderinfo_is_current_screen (&ri))
+                   do_blit( &ri, Bpp, X, Y, X, Y, Width, Height, BLIT_SRC, 0);
+               result = 1;
+           }
+       }
+    }
+
+#ifdef LOCK_UNLOCK_MADNESS
+    //PICASSO96_Lock();
+#endif
+    return result;
+}
+
+/*
+* BlitRect() is a generic (any chunky pixel format) rectangle copier
+* NOTE: If dstri is NULL, then we're only dealing with one RenderInfo area, and called from picasso_BlitRect()
+*
+* OpCodes:
+* 0 = FALSE:   dst = 0
+* 1 = NOR:     dst = ~(src | dst)
+* 2 = ONLYDST: dst = dst & ~src
+* 3 = NOTSRC:  dst = ~src
+* 4 = ONLYSRC: dst = src & ~dst
+* 5 = NOTDST:  dst = ~dst
+* 6 = EOR:     dst = src^dst
+* 7 = NAND:    dst = ~(src & dst)
+* 8 = AND:     dst = (src & dst)
+* 9 = NEOR:    dst = ~(src ^ dst)
+*10 = DST:     dst = dst
+*11 = NOTONLYSRC: dst = ~src | dst
+*12 = SRC:     dst = src
+*13 = NOTONLYDST: dst = ~dst | src
+*14 = OR:      dst = src | dst
+*15 = TRUE:    dst = 0xFF
+*/
+struct blitdata
+{
+    struct RenderInfo ri_struct;
+    struct RenderInfo dstri_struct;
+    struct RenderInfo *ri; /* Self-referencing pointers */
+    struct RenderInfo *dstri;
+    unsigned long srcx;
+    unsigned long srcy;
+    unsigned long dstx;
+    unsigned long dsty;
+    unsigned long width;
+    unsigned long height;
+    uae_u8 mask;
+    BLIT_OPCODE opcode;
+} blitrectdata;
+
+STATIC_INLINE int BlitRectHelper( void )
+{
+    struct RenderInfo *ri = blitrectdata.ri;
+    struct RenderInfo *dstri = blitrectdata.dstri;
+    unsigned long srcx = blitrectdata.srcx;
+    unsigned long srcy = blitrectdata.srcy;
+    unsigned long dstx = blitrectdata.dstx;
+    unsigned long dsty = blitrectdata.dsty;
+    unsigned long width = blitrectdata.width;
+    unsigned long height = blitrectdata.height;
+    uae_u8 mask = blitrectdata.mask;
+    BLIT_OPCODE opcode = blitrectdata.opcode;
+    
+    uae_u8 Bpp = GetBytesPerPixel(ri->RGBFormat);
+    unsigned long total_width = width * Bpp;
+    unsigned long linewidth = (total_width + 15) & ~15;
+    int can_do_visible_blit = 0;
+    
+    if( opcode == BLIT_DST )
+    {
+       write_log( "WARNING: BlitRect() being called with opcode of BLIT_DST\n" );
+       return 1;
+    }
+    
+    /*
+    * If we have no destination RenderInfo, then we're dealing with a single-buffer action, called
+    * from picasso_BlitRect().  The code in do_blitrect_frame_buffer() deals with the frame-buffer,
+    * while the do_blit() code deals with the visible screen.
+    *
+    * If we have a destination RenderInfo, then we've been called from picasso_BlitRectNoMaskComplete()
+    * and we need to put the results on the screen from the frame-buffer.
+    */
+    if (dstri == NULL) 
+    {
+        if( mask != 0xFF && Bpp > 1 ) 
+        {
+            mask = 0xFF;
+        }
+        dstri = ri;
+        can_do_visible_blit = 1;
+    }
+    
+    /* Do our virtual frame-buffer memory first */
+    do_blitrect_frame_buffer( ri, dstri, srcx, srcy, dstx, dsty, width, height, mask, opcode );
+    /* Now we do the on-screen display, if renderinfo points to it */
+    if (renderinfo_is_current_screen (dstri))
+    {
+        if (mask == 0xFF || Bpp > 1) {
+           if( can_do_visible_blit )
+               do_blit( dstri, Bpp, srcx, srcy, dstx, dsty, width, height, opcode, 1 );
+           else
+               do_blit( dstri, Bpp, dstx, dsty, dstx, dsty, width, height, opcode, 0 );
+        } else {
+            do_blit( dstri, Bpp, dstx, dsty, dstx, dsty, width, height, opcode, 0 );
+        }
+        P96TRACE(("Did do_blit 1 in BlitRect()\n"));
+    }
+    else
+    {
+        P96TRACE(("Did not do_blit 1 in BlitRect()\n"));
+    }
+    
+    return 1;
+}
+
+STATIC_INLINE int BlitRect (uaecptr ri, uaecptr dstri,
+                           unsigned long srcx, unsigned long srcy, unsigned long dstx, unsigned long dsty,
+                           unsigned long width, unsigned long height, uae_u8 mask, BLIT_OPCODE opcode )
+{
+    /* Set up the params */
+    CopyRenderInfoStructureA2U( ri, &blitrectdata.ri_struct );
+    blitrectdata.ri = &blitrectdata.ri_struct;
+    if( dstri )
+    {
+       CopyRenderInfoStructureA2U( dstri, &blitrectdata.dstri_struct );
+       blitrectdata.dstri = &blitrectdata.dstri_struct;
+    }
+    else
+    {
+       blitrectdata.dstri = NULL;
+    }
+    blitrectdata.srcx = srcx;
+    blitrectdata.srcy = srcy;
+    blitrectdata.dstx = dstx;
+    blitrectdata.dsty = dsty;
+    blitrectdata.width = width;
+    blitrectdata.height = height;
+    blitrectdata.mask = mask;
+    blitrectdata.opcode = opcode;
+    
+    return BlitRectHelper();
+}
+
+/***********************************************************
+BlitRect:
+***********************************************************
+* a0:  struct BoardInfo
+* a1:  struct RenderInfo
+* d0:  WORD SrcX
+* d1:  WORD SrcY
+* d2:  WORD DstX
+* d3:  WORD DstY
+* d4:   WORD Width
+* d5:   WORD Height
+* d6:  UBYTE Mask
+* d7:  uae_u32 RGBFormat
+***********************************************************/
+uae_u32 picasso_BlitRect (void)
+{
+    uaecptr renderinfo = m68k_areg (regs, 1);
+    unsigned long srcx = (uae_u16)m68k_dreg (regs, 0);
+    unsigned long srcy = (uae_u16)m68k_dreg (regs, 1);
+    unsigned long dstx = (uae_u16)m68k_dreg (regs, 2);
+    unsigned long dsty = (uae_u16)m68k_dreg (regs, 3);
+    unsigned long width = (uae_u16)m68k_dreg (regs, 4);
+    unsigned long height = (uae_u16)m68k_dreg (regs, 5);
+    uae_u8  Mask = (uae_u8)m68k_dreg (regs, 6);
+    uae_u32 result = 0;
+
+    special_mem|=picasso_is_special_read|picasso_is_special;     
+   
+#ifdef LOCK_UNLOCK_MADNESS
+    //PICASSO96_Unlock();
+#else  
+    wgfx_flushline ();    
+#endif
+    
+    P96TRACE(("BlitRect(%d, %d, %d, %d, %d, %d, 0x%x)\n", srcx, srcy, dstx, dsty, width, height, Mask));
+    result = BlitRect(renderinfo, (uaecptr)NULL, srcx, srcy, dstx, dsty, width, height, Mask, BLIT_SRC );
+
+#ifdef LOCK_UNLOCK_MADNESS
+    //PICASSO96_Lock();
+#endif
+    return result;
+}
+
+/***********************************************************
+BlitRectNoMaskComplete:
+***********************************************************
+* a0:  struct BoardInfo
+* a1:  struct RenderInfo (src)
+* a2:   struct RenderInfo (dst)
+* d0:  WORD SrcX
+* d1:  WORD SrcY
+* d2:  WORD DstX
+* d3:  WORD DstY
+* d4:   WORD Width
+* d5:   WORD Height
+* d6:  UBYTE OpCode
+* d7:  uae_u32 RGBFormat
+* NOTE: MUST return 0 in D0 if we're not handling this operation
+*       because the RGBFormat or opcode aren't supported.
+*       OTHERWISE return 1
+***********************************************************/
+uae_u32 picasso_BlitRectNoMaskComplete (void)
+{
+    uaecptr srcri = m68k_areg (regs, 1);
+    uaecptr dstri = m68k_areg (regs, 2);
+    unsigned long srcx = (uae_u16)m68k_dreg (regs, 0);
+    unsigned long srcy = (uae_u16)m68k_dreg (regs, 1);
+    unsigned long dstx = (uae_u16)m68k_dreg (regs, 2);
+    unsigned long dsty = (uae_u16)m68k_dreg (regs, 3);
+    unsigned long width = (uae_u16)m68k_dreg (regs, 4);
+    unsigned long height = (uae_u16)m68k_dreg (regs, 5);
+    uae_u8 OpCode = m68k_dreg (regs, 6);
+    uae_u32 RGBFmt = m68k_dreg (regs, 7);
+    uae_u32 result = 0;
+
+    special_mem|=picasso_is_special_read|picasso_is_special;     
+    
+#ifdef LOCK_UNLOCK_MADNESS
+    //PICASSO96_Unlock();
+       
+#else   
+    wgfx_flushline ();   
+#endif
+    
+    P96TRACE(("BlitRectNoMaskComplete() op 0x%2x, xy(%4d,%4d) --> xy(%4d,%4d), wh(%4d,%4d)\n",
+       OpCode, srcx, srcy, dstx, dsty, width, height));
+    
+    result = BlitRect( srcri, dstri, srcx, srcy, dstx, dsty, width, height, 0xFF, OpCode );
+
+#ifdef LOCK_UNLOCK_MADNESS
+    //PICASSO96_Lock();
+#endif
+    return result;
+}
+
+/* This utility function is used both by BlitTemplate() and BlitPattern() */
+STATIC_INLINE void PixelWrite1(uae_u8 *mem, int bits, uae_u32 fgpen, uae_u32 mask)
+{
+    if (mask != 0xFF)
+       fgpen = (fgpen & mask) | (do_get_mem_byte (mem + bits) & ~mask);
+    do_put_mem_byte (mem + bits, fgpen);
+}
+
+STATIC_INLINE void PixelWrite2(uae_u8 *mem, int bits, uae_u32 fgpen)
+{
+    do_put_mem_word (((uae_u16 *)mem) + bits, fgpen);
+}
+
+STATIC_INLINE void PixelWrite3(uae_u8 *mem, int bits, uae_u32 fgpen)
+{
+    do_put_mem_byte (mem + bits*3, fgpen & 0x000000FF);
+    *(uae_u16 *)(mem + bits*3+1) = (fgpen & 0x00FFFF00) >> 8;
+}
+
+STATIC_INLINE void PixelWrite4(uae_u8 *mem, int bits, uae_u32 fgpen)
+{
+    do_put_mem_long (((uae_u32 *)mem) + bits, fgpen);
+}
+
+STATIC_INLINE void PixelWrite(uae_u8 *mem, int bits, uae_u32 fgpen, uae_u8 Bpp, uae_u32 mask)
+{
+    switch (Bpp) {
+    case 1:
+       if (mask != 0xFF)
+           fgpen = (fgpen & mask) | (do_get_mem_byte (mem + bits) & ~mask);
+       do_put_mem_byte (mem + bits, (uae_u8)fgpen);
+       break;
+    case 2:
+       do_put_mem_word (((uae_u16 *)mem) + bits, (uae_u16)fgpen);
+       break;
+    case 3:
+       do_put_mem_byte (mem + bits*3, (uae_u8)fgpen);
+       *(uae_u16 *)(mem + bits*3+1) = (fgpen & 0x00FFFF00) >> 8;
+       break;
+    case 4:
+       do_put_mem_long (((uae_u32 *)mem) + bits, fgpen);
+       break;
+    }
+}
+
+/*
+* BlitPattern:
+* 
+* Synopsis:BlitPattern(bi, ri, pattern, X, Y, Width, Height, Mask, RGBFormat);
+* Inputs:
+* a0:struct BoardInfo *bi
+* a1:struct RenderInfo *ri
+* a2:struct Pattern *pattern
+* d0.w:X
+* d1.w:Y
+* d2.w:Width
+* d3.w:Height
+* d4.w:Mask
+* d7.l:RGBFormat
+* 
+* This function is used to paint a pattern on the board memory using the blitter. It is called by
+* BltPattern, if a AreaPtrn is used with positive AreaPtSz. The pattern consists of a b/w image
+* using a single plane of image data which will be expanded repeatedly to the destination RGBFormat
+* using ForeGround and BackGround pens as well as draw modes. The width of the pattern data is
+* always 16 pixels (one word) and the height is calculated as 2^Size. The data must be shifted up
+* and to the left by XOffset and YOffset pixels at the beginning.
+*/
+uae_u32 picasso_BlitPattern (void)
+{
+    uaecptr rinf = m68k_areg (regs, 1);
+    uaecptr pinf = m68k_areg (regs, 2);
+    unsigned long X = (uae_u16)m68k_dreg (regs, 0);
+    unsigned long Y = (uae_u16)m68k_dreg (regs, 1);
+    unsigned long W = (uae_u16)m68k_dreg (regs, 2);
+    unsigned long H = (uae_u16)m68k_dreg (regs, 3);
+    uae_u8 Mask = (uae_u8)m68k_dreg (regs, 4);
+    uae_u32 RGBFmt = m68k_dreg (regs, 7);
+    uae_u8 Bpp = GetBytesPerPixel (RGBFmt);
+    int inversion = 0;
+    struct RenderInfo ri;
+    struct Pattern pattern;
+    unsigned long rows;
+    uae_u32 fgpen;
+    uae_u8 *uae_mem;
+    int xshift;
+    unsigned long ysize_mask;
+    uae_u32 result = 0;
+
+    special_mem|=picasso_is_special_read|picasso_is_special;     
+   
+#ifdef LOCK_UNLOCK_MADNESS
+    //PICASSO96_Unlock();
+       
+#else  
+    wgfx_flushline ();
+#endif
+    
+    if( CopyRenderInfoStructureA2U (rinf, &ri) && CopyPatternStructureA2U (pinf, &pattern))
+    {
+       Bpp = GetBytesPerPixel(ri.RGBFormat);
+       uae_mem = ri.Memory + Y*ri.BytesPerRow + X*Bpp; /* offset with address */
+    
+       if (pattern.DrawMode & INVERS)
+           inversion = 1;
+    
+       pattern.DrawMode &= 0x03;
+       if (Mask != 0xFF) 
+       {
+           if( Bpp > 1 )
+               Mask = 0xFF;
+
+           if( pattern.DrawMode == COMP)
+           {
+               write_log ("WARNING - BlitPattern() has unhandled mask 0x%x with COMP DrawMode. Using fall-back routine.\n", Mask);
+           }
+           else
+           {
+               result = 1;
+           }
+       }
+       else
+       {
+           result = 1;
+       }
+
+       if( result )
+       {
+           /* write_log ("BlitPattern() xy(%d,%d), wh(%d,%d) draw 0x%x, off(%d,%d), ph %d\n",
+           X, Y, W, H, pattern.DrawMode, pattern.XOffset, pattern.YOffset, 1 << pattern.Size); */
+    #ifdef P96TRACING_ENABLED
+           DumpPattern(&pattern);
+    #endif
+           ysize_mask = (1 << pattern.Size) - 1;
+           xshift = pattern.XOffset & 15;
+    
+           for (rows = 0; rows < H; rows++, uae_mem += ri.BytesPerRow) {
+               unsigned long prow = (rows + pattern.YOffset) & ysize_mask;
+               unsigned int d = do_get_mem_word (((uae_u16 *)pattern.Memory) + prow);
+               uae_u8 *uae_mem2 = uae_mem;
+               unsigned long cols;
+               
+               if (xshift != 0)
+                   d = (d << xshift) | (d >> (16 - xshift));
+               
+               for (cols = 0; cols < W; cols += 16, uae_mem2 += Bpp << 4) 
+               {
+                   long bits;
+                   long max = W - cols;
+                   unsigned int data = d;
+                   
+                   if (max > 16)
+                       max = 16;
+                   
+                   for (bits = 0; bits < max; bits++) 
+                   {
+                       int bit_set = data & 0x8000;
+                       data <<= 1;
+                       switch (pattern.DrawMode) {
+                       case JAM1:
+                           if (inversion)
+                               bit_set = !bit_set;
+                           if (bit_set)
+                               PixelWrite (uae_mem2, bits, pattern.FgPen, Bpp, Mask);
+                           break;
+                       case JAM2:
+                           if (inversion)
+                               bit_set = !bit_set;
+                           if (bit_set)
+                               PixelWrite (uae_mem2, bits, pattern.FgPen, Bpp, Mask);
+                           else
+                               PixelWrite (uae_mem2, bits, pattern.BgPen, Bpp, Mask);
+                           break;
+                       case COMP:
+                           if (bit_set) {
+                               fgpen = pattern.FgPen;
+                               
+                               switch (Bpp) {
+                               case 1:
+                                   {
+                                       uae_u8 *addr = uae_mem2 + bits;
+                                       do_put_mem_byte (addr, (uae_u8)( do_get_mem_byte (addr) ^ fgpen ) );
+                                   }
+                                   break;
+                               case 2:
+                                   {
+                                       uae_u16 *addr = ((uae_u16 *)uae_mem2) + bits;
+                                       do_put_mem_word (addr, (uae_u16)( do_get_mem_word (addr) ^ fgpen ) );
+                                   }
+                                   break;
+                               case 3:
+                                   {
+                                       uae_u32 *addr = (uae_u32 *)(uae_mem2 + bits * 3);
+                                       do_put_mem_long (addr, do_get_mem_long (addr) ^ (fgpen & 0x00FFFFFF));
+                                   }
+                                   break;
+                               case 4:
+                                   {
+                                       uae_u32 *addr = ((uae_u32 *)uae_mem2) + bits;
+                                       do_put_mem_long (addr, do_get_mem_long (addr) ^ fgpen);
+                                   }
+                                   break;
+                               }
+                           }
+                           break;
+                       }
+                   }
+               }
+           }
+    
+           /* If we need to update a second-buffer (extra_mem is set), then do it only if visible! */
+           if ( picasso_vidinfo.extra_mem && renderinfo_is_current_screen (&ri))
+               do_blit( &ri, Bpp, X, Y, X, Y, W, H, BLIT_SRC, 0);
+
+           result = 1;
+       }
+    }
+
+#ifdef LOCK_UNLOCK_MADNESS
+    //PICASSO96_Lock();
+#endif
+    return result;
+}
+
+/*************************************************
+BlitTemplate:
+**************************************************
+* Synopsis: BlitTemplate(bi, ri, template, X, Y, Width, Height, Mask, RGBFormat);
+* a0: struct BoardInfo *bi
+* a1: struct RenderInfo *ri
+* a2: struct Template *template
+* d0.w: X
+* d1.w: Y
+* d2.w: Width
+* d3.w: Height
+* d4.w: Mask
+* d7.l: RGBFormat
+*
+* This function is used to paint a template on the board memory using the blitter.
+* It is called by BltPattern and BltTemplate. The template consists of a b/w image
+* using a single plane of image data which will be expanded to the destination RGBFormat
+* using ForeGround and BackGround pens as well as draw modes.
+***********************************************************************************/
+uae_u32 picasso_BlitTemplate (void)
+{
+    uae_u8 inversion = 0;
+    uaecptr rinf = m68k_areg (regs, 1);
+    uaecptr tmpl = m68k_areg (regs, 2);
+    unsigned long X = (uae_u16)m68k_dreg (regs, 0);
+    unsigned long Y = (uae_u16)m68k_dreg (regs, 1);
+    unsigned long W = (uae_u16)m68k_dreg (regs, 2);
+    unsigned long H = (uae_u16)m68k_dreg (regs, 3);
+    uae_u16 Mask = (uae_u16)m68k_dreg (regs, 4);
+    struct Template tmp;
+    struct RenderInfo ri;
+    unsigned long rows;
+    int bitoffset;
+    uae_u32 fgpen;
+    uae_u8 *uae_mem, Bpp;
+    uae_u8 *tmpl_base;
+    uae_u32 result = 0;
+
+    special_mem|=picasso_is_special_read|picasso_is_special;     
+
+#ifdef LOCK_UNLOCK_MADNESS
+    PICASSO96_Unlock(); // @@@ We need to unlock here, because do_blit (later) needs to lock...
+#else
+    wgfx_flushline ();
+#endif
+    
+    if ( CopyRenderInfoStructureA2U (rinf, &ri) && CopyTemplateStructureA2U (tmpl, &tmp))
+    {
+       Bpp = GetBytesPerPixel(ri.RGBFormat);
+       uae_mem = ri.Memory + Y*ri.BytesPerRow + X*Bpp; /* offset into address */
+    
+       if (tmp.DrawMode & INVERS)
+           inversion = 1;
+    
+       tmp.DrawMode &= 0x03;
+
+       if (Mask != 0xFF) 
+       {
+           if( Bpp > 1 )
+               Mask = 0xFF;
+
+           if( tmp.DrawMode == COMP)
+           {
+               write_log ("WARNING - BlitTemplate() has unhandled mask 0x%x with COMP DrawMode. Using fall-back routine.\n", Mask);
+               flushpixels();  //only need in the windows Version
+               return 0;
+           }
+           else
+           {
+               result = 1;
+           }
+       }
+       else
+       {
+           result = 1;
+       }
+#if 1
+       if (tmp.DrawMode == COMP) {
+           /* workaround, let native blitter handle COMP mode */
+           flushpixels();
+           return 0;
+       }
+#endif
+       if( result )
+       {
+           P96TRACE(("BlitTemplate() xy(%d,%d), wh(%d,%d) draw 0x%x fg 0x%x bg 0x%x \n",
+               X, Y, W, H, tmp.DrawMode, tmp.FgPen, tmp.BgPen));
+    
+           bitoffset = tmp.XOffset % 8;
+    
+#if defined( P96TRACING_ENABLED ) && ( P96TRACING_LEVEL > 0 )
+           DumpTemplate(&tmp, W, H);
+#endif
+    
+           tmpl_base = tmp.Memory + tmp.XOffset/8;
+           
+           for (rows = 0; rows < H; rows++, uae_mem += ri.BytesPerRow, tmpl_base += tmp.BytesPerRow) {
+               unsigned long cols;
+               uae_u8 *tmpl_mem = tmpl_base;
+               uae_u8 *uae_mem2 = uae_mem;
+               unsigned int data = *tmpl_mem;
+               
+               for (cols = 0; cols < W; cols += 8, uae_mem2 += Bpp << 3) {
+                   unsigned int byte;
+                   long bits;
+                   long max = W - cols;
+                   
+                   if (max > 8)
+                       max = 8;
+                   
+                   data <<= 8;
+                   data |= *++tmpl_mem;
+                   
+                   byte = data >> (8 - bitoffset);
+                   
+                   for (bits = 0; bits < max; bits++) {
+                       int bit_set = (byte & 0x80);
+                       byte <<= 1;
+                       switch (tmp.DrawMode) {
+                       case JAM1:
+                           if (inversion)
+                               bit_set = !bit_set;
+                           if (bit_set) {
+                               fgpen = tmp.FgPen;
+                               PixelWrite(uae_mem2, bits, fgpen, Bpp, Mask);
+                           }
+                           break;
+                       case JAM2:
+                           if (inversion)
+                               bit_set = !bit_set;
+                           fgpen = tmp.BgPen;
+                           if (bit_set)
+                               fgpen = tmp.FgPen;
+                           
+                           PixelWrite(uae_mem2, bits, fgpen, Bpp, Mask);
+                           break;
+                       case COMP:
+                           if (bit_set) {
+                               fgpen = tmp.FgPen;
+                               
+                               switch (Bpp) {
+                               case 1:
+                                   {
+                                       uae_u8 *addr = uae_mem2 + bits;
+                                       do_put_mem_byte (addr, (uae_u8)( do_get_mem_byte (addr) ^ fgpen ) );
+                                   }
+                                   break;
+                               case 2:
+                                   {
+                                       uae_u16 *addr = ((uae_u16 *)uae_mem2) + bits;
+                                       do_put_mem_word (addr, (uae_u16)( do_get_mem_word (addr) ^ fgpen ) );
+                                   }
+                                   break;
+                               case 3:
+                                   {
+                                       uae_u32 *addr = (uae_u32 *)(uae_mem2 + bits * 3);
+                                       do_put_mem_long (addr, do_get_mem_long (addr) ^ (fgpen & 0x00FFFFFF));
+                                   }
+                                   break;
+                               case 4:
+                                   {
+                                       uae_u32 *addr = ((uae_u32 *)uae_mem2) + bits;
+                                       do_put_mem_long (addr, do_get_mem_long (addr) ^ fgpen);
+                                   }
+                                   break;
+                               }
+                           }
+                           break;
+                       }
+                   }
+               }
+           }
+           
+           /* If we need to update a second-buffer (extra_mem is set), then do it only if visible! */
+           if( picasso_vidinfo.extra_mem && renderinfo_is_current_screen( &ri ) )
+               do_blit( &ri, Bpp, X, Y, X, Y, W, H, BLIT_SRC, 0 );
+           
+           result = 1;
+       }
+}    
+#ifdef LOCK_UNLOCK_MADNESS
+    //PICASSO96_Lock();
+#endif
+    return 1;
+}
+
+/*
+* CalculateBytesPerRow:
+* a0:  struct BoardInfo
+* d0:  uae_u16 Width
+* d7:  RGBFTYPE RGBFormat
+* This function calculates the amount of bytes needed for a line of
+* "Width" pixels in the given RGBFormat.
+*/
+uae_u32 picasso_CalculateBytesPerRow (void)
+{
+    uae_u16 width = m68k_dreg (regs, 0);
+    uae_u32 type = m68k_dreg (regs, 7);
+    
+    width = GetBytesPerPixel(type)*width;
+    P96TRACE(("CalculateBytesPerRow() = %d\n",width));
+    
+    return width;
+}
+
+/*
+* SetDisplay:
+* a0:  struct BoardInfo
+* d0:  BOOL state
+* This function enables and disables the video display.
+* 
+* NOTE: return the opposite of the state
+*/
+uae_u32 picasso_SetDisplay (void)
+{
+    uae_u32 state = m68k_dreg (regs, 0);
+    P96TRACE (("SetDisplay(%d)\n", state));
+    return !state;
+}
+
+void picasso_handle_hsync (void)
+{
+    static int p96hsync;
+
+    if (WIN32GFX_IsPicassoScreen () && currprefs.gfx_pfullscreen && currprefs.gfx_vsync) {
+       if (DirectDraw_GetVerticalBlankStatus ())
+           p96hsync = 0;
+    } else {
+       p96hsync--;
+    }
+    if (p96hsync <= 0) {
+       rtarea[get_long(RTAREA_BASE + 36) + 12 - 1]++;
+        p96hsync = p96syncrate;
+    }
+}
+
+void init_hz_p96 (void)
+{
+    int rate;
+    p96syncrate = maxvpos * vblank_hz;
+    if (isfullscreen ()) {
+       rate = DirectDraw_CurrentRefreshRate ();
+       if (rate == 0)
+           rate = 60;
+    } else {
+       rate = currprefs.gfx_refreshrate;
+       if (rate <= 0)
+           rate = 60;
+    }
+    p96syncrate /= rate;
+}
+
+/* NOTE: Watch for those planeptrs of 0x00000000 and 0xFFFFFFFF for all zero / all one bitmaps !!!! */
+static void PlanarToChunky(struct RenderInfo *ri, struct BitMap *bm,
+                          unsigned long srcx, unsigned long srcy,
+                          unsigned long dstx, unsigned long dsty,
+                          unsigned long width, unsigned long height,
+                          uae_u8 mask)
+{
+    int j;
+    
+    uae_u8 *PLANAR[8], *image = ri->Memory + dstx * GetBytesPerPixel (ri->RGBFormat) + dsty*ri->BytesPerRow;
+    int Depth = bm->Depth;
+    unsigned long rows, bitoffset = srcx & 7;
+    long eol_offset;
+    
+    /* if (mask != 0xFF) 
+    write_log ("P2C - pixel-width = %d, bit-offset = %d\n", width, bitoffset); */
+    
+    /* Set up our bm->Planes[] pointers to the right horizontal offset */
+    for (j = 0; j < Depth; j++) {
+       uae_u8 *p = bm->Planes[j];
+       if (p != &all_zeros_bitmap && p != &all_ones_bitmap)
+           p += srcx/8 + srcy*bm->BytesPerRow;
+       PLANAR[j] = p;
+       if ((mask & (1 << j)) == 0)
+           PLANAR[j] = &all_zeros_bitmap;
+    }
+    eol_offset = (long)bm->BytesPerRow - (long)((width + 7) >> 3);
+    for (rows = 0; rows < height; rows++, image += ri->BytesPerRow) {
+       unsigned long cols;
+       
+       for (cols = 0; cols < width; cols += 8) {
+           int k;
+           uae_u32 a = 0, b = 0;
+           unsigned int msk = 0xFF;
+           long tmp = cols + 8 - width;
+           if (tmp > 0) {
+               msk <<= tmp;
+               b = do_get_mem_long ((uae_u32 *)(image + cols + 4));
+               if (tmp < 4)
+                   b &= 0xFFFFFFFF >> (32 - tmp * 8);
+               else if (tmp > 4) {
+                   a = do_get_mem_long ((uae_u32 *)(image + cols));
+                   a &= 0xFFFFFFFF >> (64 - tmp * 8);
+               }
+           }
+           for (k = 0; k < Depth; k++) {
+               unsigned int data;
+               if (PLANAR[k] == &all_zeros_bitmap)
+                   data = 0;
+               else if (PLANAR[k] == &all_ones_bitmap)
+                   data = 0xFF;
+               else {
+                   data = (uae_u8)(do_get_mem_word ((uae_u16 *)PLANAR[k]) >> (8 - bitoffset));
+                   PLANAR[k]++;
+               }
+               data &= msk;
+               a |= p2ctab[data][0] << k;
+               b |= p2ctab[data][1] << k;
+           }
+           do_put_mem_long ((uae_u32 *)(image + cols), a);
+           do_put_mem_long ((uae_u32 *)(image + cols + 4), b);
+       }
+       for (j = 0; j < Depth; j++) {
+           if (PLANAR[j] != &all_zeros_bitmap && PLANAR[j] != &all_ones_bitmap) {
+               PLANAR[j] += eol_offset;
+           }
+       }
+    }
+}
+
+/*
+* BlitPlanar2Chunky:
+* a0: struct BoardInfo *bi
+* a1: struct BitMap *bm - source containing planar information and assorted details
+* a2: struct RenderInfo *ri - dest area and its details
+* d0.w: SrcX
+* d1.w: SrcY
+* d2.w: DstX
+* d3.w: DstY
+* d4.w: SizeX
+* d5.w: SizeY
+* d6.b: MinTerm - uh oh!
+* d7.b: Mask - uh oh!
+*
+* This function is currently used to blit from planar bitmaps within system memory to chunky bitmaps
+* on the board. Watch out for plane pointers that are 0x00000000 (represents a plane with all bits "0")
+* or 0xffffffff (represents a plane with all bits "1").
+*/
+uae_u32 picasso_BlitPlanar2Chunky (void)
+{
+    uaecptr bm = m68k_areg (regs, 1);
+    uaecptr ri = m68k_areg (regs, 2);
+    unsigned long srcx = (uae_u16)m68k_dreg (regs, 0);
+    unsigned long srcy = (uae_u16)m68k_dreg (regs, 1);
+    unsigned long dstx = (uae_u16)m68k_dreg (regs, 2);
+    unsigned long dsty = (uae_u16)m68k_dreg (regs, 3);
+    unsigned long width = (uae_u16)m68k_dreg (regs, 4);
+    unsigned long height = (uae_u16)m68k_dreg (regs, 5);
+    uae_u8 minterm = m68k_dreg (regs, 6) & 0xFF;
+    uae_u8 mask = m68k_dreg (regs, 7) & 0xFF;
+    struct RenderInfo local_ri;
+    struct BitMap local_bm;
+    uae_u32 result = 0;
+
+    special_mem|=picasso_is_special_read|picasso_is_special;     
+   
+#ifdef LOCK_UNLOCK_MADNESS
+    //PICASSO96_Unlock();
+#else  
+    wgfx_flushline ();
+#endif
+    
+    if (minterm != 0x0C) {
+       write_log ("ERROR - BlitPlanar2Chunky() has minterm 0x%x, which I don't handle. Using fall-back routine.\n",
+           minterm);
+    }
+    else if( CopyRenderInfoStructureA2U (ri, &local_ri) && 
+            CopyBitMapStructureA2U (bm, &local_bm))
+    {
+       P96TRACE(("BlitPlanar2Chunky(%d, %d, %d, %d, %d, %d) Minterm 0x%x, Mask 0x%x, Depth %d\n",
+           srcx, srcy, dstx, dsty, width, height, minterm, mask, local_bm.Depth));
+       P96TRACE(("P2C - BitMap has %d BPR, %d rows\n", local_bm.BytesPerRow, local_bm.Rows));
+       PlanarToChunky (&local_ri, &local_bm, srcx, srcy, dstx, dsty, width, height, mask);
+       if (renderinfo_is_current_screen (&local_ri))
+       {
+           do_blit( &local_ri, GetBytesPerPixel( local_ri.RGBFormat ), dstx, dsty, dstx, dsty, width, height, BLIT_SRC, 0);
+       }
+       result = 1;
+    }
+
+#ifdef LOCK_UNLOCK_MADNESS
+    //PICASSO96_Lock();
+#endif
+    return result;
+}
+
+/* NOTE: Watch for those planeptrs of 0x00000000 and 0xFFFFFFFF for all zero / all one bitmaps !!!! */
+static void PlanarToDirect(struct RenderInfo *ri, struct BitMap *bm,
+                          unsigned long srcx, unsigned long srcy,
+                          unsigned long dstx, unsigned long dsty,
+                          unsigned long width, unsigned long height, uae_u8 mask,
+                          struct ColorIndexMapping *cim)
+{
+    int j;
+    int bpp = GetBytesPerPixel(ri->RGBFormat);
+    uae_u8 *PLANAR[8];
+    uae_u8 *image = ri->Memory + dstx * bpp + dsty * ri->BytesPerRow;
+    int Depth = bm->Depth;
+    unsigned long rows;
+    long eol_offset;
+    
+    if( !bpp )
+        return;
+    
+    /* Set up our bm->Planes[] pointers to the right horizontal offset */
+    for (j = 0; j < Depth; j++) {
+       uae_u8 *p = bm->Planes[j];
+       if (p != &all_zeros_bitmap && p != &all_ones_bitmap)
+           p += srcx/8 + srcy*bm->BytesPerRow;
+       PLANAR[j] = p;
+       if ((mask & (1 << j)) == 0)
+           PLANAR[j] = &all_zeros_bitmap;
+    }
+    
+    eol_offset = (long)bm->BytesPerRow - (long)((width + (srcx & 7)) >> 3);
+    for (rows = 0; rows < height; rows++, image += ri->BytesPerRow) {
+       unsigned long cols;
+       uae_u8 *image2 = image;
+       unsigned int bitoffs = 7 - (srcx & 7);
+       int i;
+       
+       for (cols = 0; cols < width; cols ++) {
+           int v = 0, k;
+           for (k = 0; k < Depth; k++) {
+               if (PLANAR[k] == &all_ones_bitmap)
+                   v |= 1 << k;
+               else if (PLANAR[k] != &all_zeros_bitmap) {
+                   v |= ((*PLANAR[k] >> bitoffs) & 1) << k;
+               }
+           }
+           
+           switch (bpp) {
+           case 2:
+               do_put_mem_word ((uae_u16 *)image2, (uae_u16)( cim->Colors[v] ) );
+               image2 += 2;
+               break;
+           case 3:
+               do_put_mem_byte (image2++, (uae_u8)cim->Colors[v] );
+               do_put_mem_word ((uae_u16 *)image2, (uae_u16)( (cim->Colors[v] & 0x00FFFF00) >> 8) );
+               image2 += 2;
+               break;
+           case 4:
+               do_put_mem_long ((uae_u32 *)image2, cim->Colors[v]);
+               image2 += 4;
+               break;
+           }
+           bitoffs--;
+           bitoffs &= 7;
+           if (bitoffs == 7) {
+               int k;
+               for (k = 0; k < Depth; k++) {
+                   if (PLANAR[k] != &all_zeros_bitmap && PLANAR[k] != &all_ones_bitmap) {
+                       PLANAR[k]++;
+                   }
+               }
+           }
+       }
+       
+       for (i = 0; i < Depth; i++) {
+           if (PLANAR[i] != &all_zeros_bitmap && PLANAR[i] != &all_ones_bitmap) {
+               PLANAR[i] += eol_offset;
+           }
+       }
+    }
+}
+
+/*
+* BlitPlanar2Direct: 
+* 
+* Synopsis:
+* BlitPlanar2Direct(bi, bm, ri, cim, SrcX, SrcY, DstX, DstY, SizeX, SizeY, MinTerm, Mask);
+* Inputs:
+* a0:struct BoardInfo *bi
+* a1:struct BitMap *bm
+* a2:struct RenderInfo *ri
+* a3:struct ColorIndexMapping *cmi
+* d0.w:SrcX
+* d1.w:SrcY
+* d2.w:DstX
+* d3.w:DstY
+* d4.w:SizeX
+* d5.w:SizeY
+* d6.b:MinTerm
+* d7.b:Mask
+* 
+* This function is currently used to blit from planar bitmaps within system memory to direct color
+* bitmaps (15, 16, 24 or 32 bit) on the board. Watch out for plane pointers that are 0x00000000 (represents
+* a plane with all bits "0") or 0xffffffff (represents a plane with all bits "1"). The ColorIndexMapping is
+* used to map the color index of each pixel formed by the bits in the bitmap's planes to a direct color value
+* which is written to the destination RenderInfo. The color mask and all colors within the mapping are words,
+* triple bytes or longwords respectively similar to the color values used in FillRect(), BlitPattern() or
+* BlitTemplate(). 
+*/
+uae_u32 picasso_BlitPlanar2Direct (void)
+{
+    uaecptr bm = m68k_areg (regs, 1);
+    uaecptr ri = m68k_areg (regs, 2);
+    uaecptr cim = m68k_areg (regs, 3);
+    unsigned long srcx = (uae_u16)m68k_dreg (regs, 0);
+    unsigned long srcy = (uae_u16)m68k_dreg (regs, 1);
+    unsigned long dstx = (uae_u16)m68k_dreg (regs, 2);
+    unsigned long dsty = (uae_u16)m68k_dreg (regs, 3);
+    unsigned long width = (uae_u16)m68k_dreg (regs, 4);
+    unsigned long height = (uae_u16)m68k_dreg (regs, 5);
+    uae_u8 minterm = m68k_dreg (regs, 6);
+    uae_u8 Mask = m68k_dreg (regs, 7);
+    struct RenderInfo local_ri;
+    struct BitMap local_bm;
+    struct ColorIndexMapping local_cim;
+    uae_u32 result = 0;
+
+    special_mem|=picasso_is_special_read|picasso_is_special;     
+    
+#ifdef LOCK_UNLOCK_MADNESS
+    //PICASSO96_Unlock();
+#else  
+    wgfx_flushline ();
+#endif
+    
+    if (minterm != 0x0C) {
+       write_log ("WARNING - BlitPlanar2Direct() has unhandled op-code 0x%x. Using fall-back routine.\n",
+           minterm);
+    }
+    else if( CopyRenderInfoStructureA2U (ri, &local_ri) &&
+            CopyBitMapStructureA2U (bm, &local_bm))
+    {
+       Mask = 0xFF;
+       CopyColorIndexMappingA2U (cim, &local_cim);
+       P96TRACE(("BlitPlanar2Direct(%d, %d, %d, %d, %d, %d) Minterm 0x%x, Mask 0x%x, Depth %d\n",
+           srcx, srcy, dstx, dsty, width, height, minterm, Mask, local_bm.Depth));
+       PlanarToDirect (&local_ri, &local_bm, srcx, srcy, dstx, dsty, width, height, Mask, &local_cim);
+       if (renderinfo_is_current_screen (&local_ri))
+           do_blit( &local_ri, GetBytesPerPixel( local_ri.RGBFormat ), dstx, dsty, dstx, dsty, width, height, BLIT_SRC, 0);
+       result = 1;
+    }
+#ifdef LOCK_UNLOCK_MADNESS
+    //PICASSO96_Lock();
+#endif
+    return result;
+}
+
+/* @@@ - Work to be done here!
+*
+* The address is the offset into our Picasso96 frame-buffer (pointed to by gfxmem_start)
+* where the value was put.
+*
+* Porting work: on some machines you may not need these functions, ie. if the memory for the
+* Picasso96 frame-buffer is directly viewable or directly blittable.  On Win32 with DirectX,
+* this is not the case.  So I provide some write-through functions (as per Mathias' orders!)
+*/
+#ifdef PIXEL_LOCK
+static void flushpixels( void )
+{
+    int i,y,x,xbytes,size;
+    uae_u8 *dst;
+    uaecptr addr,xminaddr=0,xmaxaddr,ydestaddr;
+    uae_u32 value;
+    
+    int lock=0;
+    
+    if (pixelcount==0)return;
+    if (!picasso_on) {
+       pixelcount=0;
+       return;
+    }
+          xmaxaddr=0;
+          //panoffset=picasso96_state.Address+(picasso96_state.XOffset*picasso96_state.BytesPerPixel)
+          //             +(picasso96_state.YOffset*picasso96_state.BytesPerRow);
+          
+          DX_Invalidate (1,4000);
+#ifndef _DEBUG
+          if(DirectDraw_IsLocked()==FALSE) {
+              dst = gfx_lock_picasso ();
+              lock=1;
+          } else 
+#endif
+              dst = picasso96_state.HostAddress;
+          if (!dst)goto out;
+          if( picasso_vidinfo.rgbformat != picasso96_state.RGBFormat )
+          {
+              int psiz = GetBytesPerPixel (picasso_vidinfo.rgbformat);
+              if (picasso96_state.RGBFormat != RGBFB_CHUNKY)
+              {
+                  write_log ("ERROR - flushpixels() has non RGBFB_CHUNKY mode!\n");
+                  goto out;
+              }
+              for (i=0;i<pixelcount;i++)
+              { 
+                  addr=pixelbase[i].addr;
+                  value=pixelbase[i].value;    
+                  y = addr / picasso96_state.BytesPerRow;
+                  
+                  if (! picasso_vidinfo.extra_mem)
+                      goto next2;         
+                  xbytes = addr - y * picasso96_state.BytesPerRow;
+                  //x = xbytes  / picasso96_state.BytesPerPixel;
+                  
+                  
+                  if (xbytes < picasso96_state.Width*picasso96_state.BytesPerPixel && y < picasso96_state.Height)
+                  {    
+                      if(psiz==4)
+                      {
+                          int i2;
+                          unsigned int addr,val;
+                          
+                          i2=pixelbase[i].size;
+                          addr=dst + y * picasso_vidinfo.rowbytes + ((xbytes)*4);
+                          if (i2==4)
+                          {
+                              *(uae_u32 *) addr=picasso_vidinfo.clut[((value)&0xff)];
+                              addr+=4;
+                              *(uae_u32 *) addr=picasso_vidinfo.clut[((value>>8)&0xff)];
+                              addr+=4;
+                              *(uae_u32 *) addr=picasso_vidinfo.clut[((value>>16)&0xff)];
+                              addr+=4;
+                              *(uae_u32 *) addr=picasso_vidinfo.clut[((value>>24)&0xff)];
+                              goto next2;
+                          }
+                          if (i2==2)
+                          {
+                              *(uae_u32 *) addr=picasso_vidinfo.clut[((value>>8)&0xff)];
+                              addr+=4;
+                              *(uae_u32 *) addr=picasso_vidinfo.clut[((value)&0xff)];
+                              goto next2;
+                          }
+                          if (i2==1)
+                          {
+                              *(uae_u32 *) addr=picasso_vidinfo.clut[(value&0xff)];
+                              goto next2;
+                          }
+                          
+                      }
+                      else
+                      {
+                          int i2;
+                          unsigned int addr,val;
+                          
+                          i2=pixelbase[i].size;
+                          addr=dst + y * picasso_vidinfo.rowbytes + ((xbytes)*2);
+                          if (i2==4)
+                          {
+                              *(uae_u16 *) addr=picasso_vidinfo.clut[((value)&0xff)];
+                              addr+=2;
+                              *(uae_u16 *) addr=picasso_vidinfo.clut[((value>>8)&0xff)];
+                              addr+=2;
+                              *(uae_u16 *) addr=picasso_vidinfo.clut[((value>>16)&0xff)];
+                              addr+=2;
+                              *(uae_u16 *) addr=picasso_vidinfo.clut[((value>>24)&0xff)];
+                              goto next2;
+                          }
+                          if (i2==2)
+                          {
+                              *(uae_u16 *) addr=picasso_vidinfo.clut[((value>>8)&0xff)];
+                              addr+=2;
+                              *(uae_u16 *) addr=picasso_vidinfo.clut[((value)&0xff)];
+                              goto next2;
+                          }
+                          if (i2==1)
+                          {
+                              *(uae_u16 *) addr=picasso_vidinfo.clut[(value&0xff)];
+                              goto next2;
+                          }
+                          
+                          
+                      }
+                  }
+                  
+next2:;}
+              goto out;  }
+          for (i=0;i<pixelcount;i++)
+          { 
+              addr=pixelbase[i].addr;
+              value=pixelbase[i].value;
+              if(addr>xminaddr && addr<xmaxaddr)
+              {
+                  if(pixelbase[i].size==4){
+#ifdef SWAPSPEEDUP
+    *(uae_u32 *)((addr-xminaddr)+ydestaddr)=value;    
+#else      
+   do_put_mem_long ((uae_u32 *)((addr-xminaddr)+ydestaddr),value);
+#endif                   
+                          goto next;
+                  }
+                  switch (pixelbase[i].size)
+                  {
+                  case 1:
+                      *(uae_u8 *)((addr-xminaddr)+ydestaddr) = value;
+                      break;
+                  case 2:
+                      do_put_mem_word ((uae_u16 *)((addr-xminaddr)+ydestaddr),value);
+                      break;   
+                  }    
+              }
+              else
+              {
+                  y = addr / picasso96_state.BytesPerRow;
+                  
+                  if (! picasso_vidinfo.extra_mem)
+                      goto next;
+                  ydestaddr=picasso_vidinfo.rowbytes*y+dst;
+                  xminaddr= y*picasso96_state.BytesPerRow;     
+                  //xmaxaddr=xminaddr+picasso96_state.BytesPerRow;
+                  xmaxaddr=xminaddr+(picasso_vidinfo.width*picasso_vidinfo.pixbytes);
+                  
+                  xbytes = addr - y * picasso96_state.BytesPerRow;
+                  //x = xbytes  / picasso96_state.BytesPerPixel;
+                  
+                  
+                  if (xbytes < picasso96_state.Width*picasso96_state.BytesPerPixel && y < picasso96_state.Height)
+                  {            
+                      switch (pixelbase[i].size)
+                      {
+                      case 1:
+                          *(uae_u8 *)(dst + y * picasso_vidinfo.rowbytes + xbytes) = value;
+                          break;
+                      case 2:
+                          do_put_mem_word ((uae_u16 *)(dst + y * picasso_vidinfo.rowbytes + xbytes), value);
+                          break;
+                      case 4:  
+#ifdef SWAPSPEEDUP
+          *(uae_u32 *)(dst + y * picasso_vidinfo.rowbytes + xbytes) = value;
+#else
+                                  do_put_mem_long ((uae_u32 *)(dst + y * picasso_vidinfo.rowbytes + xbytes), value);       
+#endif 
+                                  break;               
+                      }
+                      
+                  }
+                  else xmaxaddr=0;
+              }
+              
+next:; } 
+out:;if(lock)gfx_unlock_picasso ();
+    pixelcount=0;
+}
+#endif
+
+static void write_gfx_long (uaecptr addr, uae_u32 value)
+{
+    uaecptr oldaddr = addr;
+    int y;
+#ifdef LOCK_UNLOCK_MADNESS
+    int x, xbytes;
+    uae_u8 *dst;
+#ifdef PIXEL_LOCK
+            addr += gfxmem_start;
+    /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */
+    if (addr > picasso96_state.Address && addr + 4 < picasso96_state.Extent)
+    {
+       addr -= picasso96_state.Address+(picasso96_state.XOffset*picasso96_state.BytesPerPixel)
+           +(picasso96_state.YOffset*picasso96_state.BytesPerRow);
+       if ( pixelcount > MAXFLUSHPIXEL )
+           flushpixels();
+       pixelbase[pixelcount].addr=addr;
+       pixelbase[pixelcount].value=value;
+       pixelbase[pixelcount++].size=4;
+    }
+    return;
+#endif
+#endif
+       
+    if (!picasso_on)
+       return;
+    
+#ifndef LOCK_UNLOCK_MADNESS
+       /*
+       * Several writes to successive memory locations are a common access pattern.
+       * Try to optimize it.
+    */
+    if (addr >= wgfx_linestart && addr + 4 <= wgfx_lineend) {
+       if (addr < wgfx_min)
+           wgfx_min = addr;
+       if (addr + 4 > wgfx_max)
+           wgfx_max = addr + 4;
+       return;
+    } else
+    {
+#if P96TRACING_LEVEL > 0
+       P96TRACE(("write_gfx_long( 0x%x, 0x%x )\n", addr, value ));
+#endif
+       wgfx_flushline ();
+    }
+#endif
+
+      addr += gfxmem_start;
+    /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */
+    if (addr < picasso96_state.Address || addr + 4 > picasso96_state.Extent)
+       return;
+    addr -= picasso96_state.Address+(picasso96_state.XOffset*picasso96_state.BytesPerPixel)
+       +(picasso96_state.YOffset*picasso96_state.BytesPerRow);
+    y = addr / picasso96_state.BytesPerRow;
+    
+#ifdef LOCK_UNLOCK_MADNESS
+    //DX_Invalidate (y,y);    
+    if (! picasso_vidinfo.extra_mem) {
+       pixelcount=0;
+       return;
+    }
+    
+    xbytes = addr - y * picasso96_state.BytesPerRow;
+    //x = xbytes  / picasso96_state.BytesPerPixel;
+    
+    if (xbytes < (picasso96_state.Width*picasso96_state.BytesPerPixel) && y < picasso96_state.Height)
+    {
+        
+       dst = picasso96_state.HostAddress;
+       //dst = gfx_lock_picasso ();
+       if (dst) {
+           do_put_mem_long ((uae_u32 *)(dst + y * picasso_vidinfo.rowbytes + xbytes), value);       
+           //gfx_unlock_picasso ();
+       }
+       else
+           write_log("error\n");
+    }
+#else
+    if (y >= picasso96_state.Height)
+       return;
+    wgfx_linestart = picasso96_state.Address - gfxmem_start + y * picasso96_state.BytesPerRow;
+    wgfx_lineend = wgfx_linestart + picasso96_state.BytesPerRow;
+    wgfx_y = y;
+    wgfx_min = oldaddr;
+    wgfx_max = oldaddr + 4;
+#endif
+}
+
+static void write_gfx_word (uaecptr addr, uae_u16 value)
+{
+     uaecptr oldaddr = addr;
+    int y;
+#ifdef LOCK_UNLOCK_MADNESS
+    int x, xbytes;
+    uae_u8 *dst;
+#ifdef PIXEL_LOCK
+    addr += gfxmem_start;
+    /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */
+    if (addr > picasso96_state.Address && addr + 4 < picasso96_state.Extent)
+    {
+       addr -= picasso96_state.Address+(picasso96_state.XOffset*picasso96_state.BytesPerPixel)
+           +(picasso96_state.YOffset*picasso96_state.BytesPerRow);
+       if ( pixelcount > MAXFLUSHPIXEL )
+           flushpixels();
+       pixelbase[pixelcount].addr=addr;
+       pixelbase[pixelcount].value=value;
+       pixelbase[pixelcount++].size=2;
+    }
+    return;
+#endif   
+#endif
+    if (!picasso_on)
+       return;
+    
+#ifndef LOCK_UNLOCK_MADNESS
+    /*
+    * Several writes to successive memory locations are a common access pattern.
+    * Try to optimize it.
+    */
+    if (addr >= wgfx_linestart && addr + 2 <= wgfx_lineend) {
+       if (addr < wgfx_min)
+           wgfx_min = addr;
+       if (addr + 2 > wgfx_max)
+           wgfx_max = addr + 2;
+       return;
+    } else
+       wgfx_flushline ();
+#endif
+    
+    addr += gfxmem_start;
+    /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */
+    if (addr < picasso96_state.Address || addr + 2 > picasso96_state.Extent)
+       return;
+    addr -= picasso96_state.Address+(picasso96_state.XOffset*picasso96_state.BytesPerPixel)
+       +(picasso96_state.YOffset*picasso96_state.BytesPerRow);
+    
+    y = addr / picasso96_state.BytesPerRow;
+    
+#ifdef LOCK_UNLOCK_MADNESS
+    //DX_Invalidate (y, y);
+    if (! picasso_vidinfo.extra_mem) {
+       pixelcount=0;
+       return;
+    }
+    
+    xbytes = addr - y * picasso96_state.BytesPerRow;
+    //x = xbytes / picasso96_state.BytesPerPixel;
+    
+    if (x < (picasso96_state.Width*picasso96_state.BytesPerPixel) && y < picasso96_state.Height)
+    {
+       dst = picasso96_state.HostAddress;
+       
+       //dst = gfx_lock_picasso ();
+       if (dst) {
+           do_put_mem_word ((uae_u16 *)(dst + y * picasso_vidinfo.rowbytes + xbytes), value);
+           //gfx_unlock_picasso ();
+       }
+    }
+#else
+    if (y >= picasso96_state.Height)
+       return;
+    wgfx_linestart = picasso96_state.Address - gfxmem_start + y * picasso96_state.BytesPerRow;
+    wgfx_lineend = wgfx_linestart + picasso96_state.BytesPerRow;
+    wgfx_y = y;
+    wgfx_min = oldaddr;
+    wgfx_max = oldaddr + 2;
+#endif
+}
+
+static void write_gfx_byte (uaecptr addr, uae_u8 value)
+{
+    uaecptr oldaddr = addr;
+    int y;
+#ifdef LOCK_UNLOCK_MADNESS
+    int x, xbytes;
+    uae_u8 *dst;
+#ifdef PIXEL_LOCK
+         addr += gfxmem_start;
+    /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */
+    if (addr > picasso96_state.Address && addr + 4 < picasso96_state.Extent)
+    {
+       addr -= picasso96_state.Address+(picasso96_state.XOffset*picasso96_state.BytesPerPixel)
+           +(picasso96_state.YOffset*picasso96_state.BytesPerRow);
+       if ( pixelcount > MAXFLUSHPIXEL )
+           flushpixels();
+       pixelbase[pixelcount].addr=addr;
+       pixelbase[pixelcount].value=value;
+       pixelbase[pixelcount++].size=1;
+    }
+    return;
+#endif
+#endif
+    if (!picasso_on)
+       return;
+#ifndef LOCK_UNLOCK_MADNESS   
+       /*
+       * Several writes to successive memory locations are a common access pattern.
+       * Try to optimize it.
+    */
+    if (addr >= wgfx_linestart && addr + 4 <= wgfx_lineend) {
+       if (addr < wgfx_min)
+           wgfx_min = addr;
+       if (addr + 1 > wgfx_max)
+           wgfx_max = addr + 1;
+       return;
+    } else
+       wgfx_flushline ();
+#endif
+
+    addr += gfxmem_start;
+    /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */
+    if (addr < picasso96_state.Address || addr + 1 > picasso96_state.Extent)
+       return;
+    addr -= picasso96_state.Address+(picasso96_state.XOffset*picasso96_state.BytesPerPixel)
+       +(picasso96_state.YOffset*picasso96_state.BytesPerRow);
+    
+    y = addr / picasso96_state.BytesPerRow;
+    
+#ifdef LOCK_UNLOCK_MADNESS
+    //DX_Invalidate (y, y);
+    if (! picasso_vidinfo.extra_mem) {
+       pixelcount=0;
+       return;
+    }
+    
+    xbytes = addr - y * picasso96_state.BytesPerRow;
+    x = xbytes / picasso96_state.BytesPerPixel;
+    
+    if (x < picasso96_state.Width && y < picasso96_state.Height) 
+       {
+       dst = picasso96_state.HostAddress;
+               
+       //dst = gfx_lock_picasso ();
+       if (dst) {
+           *(uae_u8 *)(dst + y * picasso_vidinfo.rowbytes + xbytes) = value;
+           //gfx_unlock_picasso ();
+       }
+    }
+#else
+    if (y >= picasso96_state.Height)
+       return;
+    wgfx_linestart = picasso96_state.Address - gfxmem_start + y * picasso96_state.BytesPerRow;
+    wgfx_lineend = wgfx_linestart + picasso96_state.BytesPerRow;
+    wgfx_y = y;
+    wgfx_min = oldaddr;
+    wgfx_max = oldaddr + 1;
+#endif
+}
+
+static uae_u32 REGPARAM2 gfxmem_lget (uaecptr addr)
+{
+    uae_u32 *m;
+
+    special_mem|=picasso_is_special_read;  
+    addr -= gfxmem_start & gfxmem_mask;
+    addr &= gfxmem_mask;
+    m = (uae_u32 *)(gfxmemory + addr);
+    return do_get_mem_long(m);
+}
+
+static uae_u32 REGPARAM2 gfxmem_wget (uaecptr addr)
+{
+    uae_u16 *m;
+    special_mem|=picasso_is_special_read;  
+    addr -= gfxmem_start & gfxmem_mask;
+    addr &= gfxmem_mask;
+    m = (uae_u16 *)(gfxmemory + addr);
+    return do_get_mem_word(m);
+}
+
+static uae_u32 REGPARAM2 gfxmem_bget (uaecptr addr)
+{
+    special_mem|=picasso_is_special_read;  
+    addr -= gfxmem_start & gfxmem_mask;
+    addr &= gfxmem_mask;
+    return gfxmemory[addr];
+}
+
+static void REGPARAM2 gfxmem_lput (uaecptr addr, uae_u32 l)
+{
+    uae_u32 *m;
+#ifdef SWAPSPEEDUP
+       __asm {         //byteswap now
+       mov eax,l
+       bswap eax
+       mov l,eax
+       }
+#endif
+    special_mem|=picasso_is_special; 
+    addr -= gfxmem_start & gfxmem_mask;
+    addr &= gfxmem_mask;
+
+    m = (uae_u32 *)(gfxmemory + addr);
+/*                    //only write difference
+       __asm {
+       mov eax,m
+       mov eax,[eax]
+       bswap eax
+       cmp eax,l
+       jne l2
+       mov m,0
+l2:
+    }
+       if (!m) return;
+*/ 
+#ifdef SWAPSPEEDUP     
+      *m=l;
+#else
+        do_put_mem_long(m, l);
+#endif
+    /* write the long-word to our displayable memory */
+    write_gfx_long(addr, l);
+}
+
+static void REGPARAM2 gfxmem_wput (uaecptr addr, uae_u32 w)
+{
+    uae_u16 *m;
+    special_mem|=picasso_is_special; 
+    addr -= gfxmem_start & gfxmem_mask;
+    addr &= gfxmem_mask;
+    m = (uae_u16 *)(gfxmemory + addr);
+    do_put_mem_word(m, (uae_u16)w);
+    
+    /* write the word to our displayable memory */
+    write_gfx_word(addr, (uae_u16)w);
+}
+
+static void REGPARAM2 gfxmem_bput (uaecptr addr, uae_u32 b)
+{
+    special_mem|=picasso_is_special; 
+    addr -= gfxmem_start & gfxmem_mask;
+    addr &= gfxmem_mask;
+    gfxmemory[addr] = b;
+    
+    /* write the byte to our displayable memory */
+    write_gfx_byte(addr, (uae_u8)b);
+}
+
+static int REGPARAM2 gfxmem_check (uaecptr addr, uae_u32 size)
+{
+    addr -= gfxmem_start & gfxmem_mask;
+    addr &= gfxmem_mask;
+    return (addr + size) < allocated_gfxmem;
+}
+
+static uae_u8 *REGPARAM2 gfxmem_xlate (uaecptr addr)
+{
+    addr -= gfxmem_start & gfxmem_mask;
+    addr &= gfxmem_mask;
+    return gfxmemory + addr;
+}
+
+addrbank gfxmem_bank = {
+    gfxmem_lget, gfxmem_wget, gfxmem_bget,
+       gfxmem_lput, gfxmem_wput, gfxmem_bput,
+       gfxmem_xlate, gfxmem_check, NULL
+};
+
+/* Call this function first, near the beginning of code flow
+* Place in InitGraphics() which seems reasonable...
+* Also put it in reset_drawing() for safe-keeping.  */
+void InitPicasso96 (void)
+{
+    have_done_picasso = 0;
+    pixelcount = 0;
+    palette_changed = 0;
+//fastscreen
+    oldscr=0;
+//fastscreen
+    memset (&picasso96_state, 0, sizeof(struct picasso96_state_struct));
+    
+    if (1) {
+       int i, count;
+       
+       for (i = 0; i < 256; i++) {
+           p2ctab[i][0] = (((i & 128) ? 0x01000000 : 0)
+               | ((i & 64) ? 0x010000 : 0)
+               | ((i & 32) ? 0x0100 : 0)
+               | ((i & 16) ? 0x01 : 0));
+           p2ctab[i][1] = (((i & 8) ? 0x01000000 : 0)
+               | ((i & 4) ? 0x010000 : 0)
+               | ((i & 2) ? 0x0100 : 0)
+               | ((i & 1) ? 0x01 : 0));
+       }
+       count = 0;
+       while (DisplayModes[count].depth >= 0)
+           count++;
+       for (i = 0; i < count; i++) {
+           switch (DisplayModes[i].depth) {
+           case 1:
+               if (DisplayModes[i].res.width > chunky.width)
+                   chunky.width = DisplayModes[i].res.width;
+               if (DisplayModes[i].res.height > chunky.height)
+                   chunky.height = DisplayModes[i].res.height;
+               break;
+           case 2:
+               if (DisplayModes[i].res.width > hicolour.width)
+                   hicolour.width = DisplayModes[i].res.width;
+               if (DisplayModes[i].res.height > hicolour.height)
+                   hicolour.height = DisplayModes[i].res.height;
+               break;
+           case 3:
+               if (DisplayModes[i].res.width > truecolour.width)
+                   truecolour.width = DisplayModes[i].res.width;
+               if (DisplayModes[i].res.height > truecolour.height)
+                   truecolour.height = DisplayModes[i].res.height;
+               break;
+           case 4:
+               if (DisplayModes[i].res.width > alphacolour.width)
+                   alphacolour.width = DisplayModes[i].res.width;
+               if (DisplayModes[i].res.height > alphacolour.height)
+                   alphacolour.height = DisplayModes[i].res.height;
+               break;
+           }
+       }
+       //ShowSupportedResolutions ();
+    }
+}
+
+uae_u8 *restore_p96 (uae_u8 *src)
+{
+    return src;
+}
+
+uae_u8 *save_p96 (int *len)
+{
+    uae_u8 *dstbak,*dst;
+
+    //dstbak = dst = malloc (16 + 12 + 1 + 1);
+    return 0;
+}
+
+
+
+
+#endif
diff --git a/od-win32/picasso96_win.h b/od-win32/picasso96_win.h
new file mode 100755 (executable)
index 0000000..3f5fe9e
--- /dev/null
@@ -0,0 +1,561 @@
+/*
+ * UAE - The U*nix Amiga Emulator
+ *
+ * Picasso96 Support Module Header
+ *
+ * Copyright 1997 Brian King <Brian_King@Mitel.com, Brian_King@Cloanto.com>
+ */
+#ifndef __PICASSO96_H__
+#define __PICASSO96_H__
+
+#ifdef PICASSO96
+
+#include "dxwrap.h"
+
+#ifdef _DEBUG
+void PICASSO96_Lock2( char *filename, int linenum );
+#define PICASSO96_Lock() PICASSO96_Lock2( __FILE__, __LINE__ )
+
+void PICASSO96_Unlock2( char *filename, int linenum );
+#define PICASSO96_Unlock() PICASSO96_Unlock2( __FILE__, __LINE__ )
+#endif
+
+/* Define this if you provide the proper sprite functions */
+//#define HARDWARE_SPRITE_EMULATION
+
+//#include "newcpu.h"
+
+#define PIC_READ (S_READ|S_WRITE)
+#define PIC_WRITE (S_READ|S_WRITE)
+
+#define NOSIGNAL 0xFFFFFFFF
+
+/************************************************************************/
+/* Types for BoardType Identification
+ */
+typedef enum {
+       BT_NoBoard,
+       BT_oMniBus,
+       BT_Graffity,
+       BT_CyberVision,
+       BT_Domino,
+       BT_Merlin,
+       BT_PicassoII,
+       BT_Piccolo,
+       BT_RetinaBLT,
+       BT_Spectrum,
+       BT_PicassoIV,
+       BT_PiccoloSD64,
+       BT_A2410,
+       BT_Pixel64,
+       BT_uaegfx,
+       BT_CVision3D,
+       BT_Altais,
+       BT_Prototype1,
+       BT_Prototype2,
+       BT_Prototype3,
+       BT_Prototype4,
+       BT_Prototype5,
+       BT_MaxBoardTypes
+} BTYPE;
+
+/************************************************************************/
+/* Types for PaletteChipType Identification
+ */
+typedef enum {
+       PCT_Unknown,
+       PCT_S11483,                             // Sierra S11483: HiColor 15 bit, oMniBus, Domino
+       PCT_S15025,                             // Sierra S15025: TrueColor 32 bit, oMniBus
+       PCT_CirrusGD542x,               // Cirrus GD542x internal: TrueColor 24 bit
+       PCT_Domino,                             // is in fact a Sierra S11483
+       PCT_BT482,                              // BrookTree BT482: TrueColor 32 bit, Merlin
+       PCT_Music,                              // Music MU9C4910: TrueColor 24 bit, oMniBus
+       PCT_ICS5300,                    // ICS 5300: ...., Retina BLT Z3
+       PCT_CirrusGD5446,               // Cirrus GD5446 internal: TrueColor 24 bit
+       PCT_CirrusGD5434,               // Cirrus GD5434 internal: TrueColor 32 bit
+       PCT_S3Trio64,                   // S3 Trio64 internal: TrueColor 32 bit
+       PCT_A2410_xxx,                  // A2410 DAC, *type unknown*
+       PCT_S3ViRGE,                    // S3 ViRGE internal: TrueColor 32 bit
+       PCT_MaxPaletteChipTypes
+} PCTYPE;
+
+/************************************************************************/
+/* Types for GraphicsControllerType Identification
+ */
+typedef enum {
+       GCT_Unknown,
+       GCT_ET4000,
+       GCT_ETW32,      
+       GCT_CirrusGD542x,
+       GCT_NCR77C32BLT,        
+       GCT_CirrusGD5446,
+       GCT_CirrusGD5434,
+       GCT_S3Trio64,
+       GCT_TI34010,
+       GCT_S3ViRGE,
+       GCT_MaxGraphicsControllerTypes
+} GCTYPE;
+
+#define JAM1 0
+#define JAM2 1
+#define COMP 2
+#define INVERS 4
+
+/************************************************************************/
+
+enum {
+    PLANAR,
+    CHUNKY,
+    HICOLOR,
+    TRUECOLOR,
+    TRUEALPHA,
+    MAXMODES
+};
+
+/************************************************************************/
+struct MyCLUTEntry {
+    uae_u8 Red;
+    uae_u8 Green;
+    uae_u8 Blue;
+    uae_u8 Pad;
+};
+
+struct ColorIndexMapping {
+    uae_u32 ColorMask;
+    uae_u32 Colors[256];
+};
+
+struct CLUTEntry {
+    uae_u8 Red;
+    uae_u8 Green;
+    uae_u8 Blue;
+};
+
+#define PSSO_BitMap_BytesPerRow 0
+#define PSSO_BitMap_Rows 2
+#define PSSO_BitMap_Flags 4
+#define PSSO_BitMap_Depth 5
+#define PSSO_BitMap_pad 6
+#define PSSO_BitMap_Planes 8
+#define PSSO_BitMap_sizeof 40
+
+struct BitMap
+{
+    uae_u16 BytesPerRow;
+    uae_u16 Rows;
+    uae_u8 Flags;
+    uae_u8 Depth;
+    uae_u16 pad;
+    uae_u8 *Planes[8];
+};
+
+/************************************************************************/
+
+#define        SETTINGSNAMEMAXCHARS            30
+#define        BOARDNAMEMAXCHARS               30
+
+struct Settings {
+    uae_u32                                    BoardType;
+    /* a value discribing assignment to nth board local to boardtype
+     * to be used for reassignment when boards are added or removed.  */
+    uae_u16                                    LocalOrdering;
+    uae_s16                                    LastSelected;
+    char                                       NameField[SETTINGSNAMEMAXCHARS];
+    /* neu! */
+    char                                       *BoardName;
+};
+
+#define MAXRESOLUTIONNAMELENGTH 22
+
+/********************************
+ * only used within rtg.library *
+ ********************************/
+
+#define PSSO_LibResolution_P96ID 14
+#define PSSO_LibResolution_Name 20
+#define PSSO_LibResolution_DisplayID 42 /* Name + MAXRESOLUTIONNAMELENGTH */
+#define PSSO_LibResolution_Width 46
+#define PSSO_LibResolution_Height 48
+#define PSSO_LibResolution_Flags 50
+#define PSSO_LibResolution_Modes 52
+#define PSSO_LibResolution_BoardInfo (52 + MAXMODES*4)
+#define PSSO_LibResolution_sizeof (60 + MAXMODES*4)
+
+struct LibResolution {
+    char P96ID[6];
+    char Name[MAXRESOLUTIONNAMELENGTH];
+    uae_u32 DisplayID;
+    uae_u16 Width;
+    uae_u16 Height;
+    uae_u16 Flags;
+    uaecptr Modes[MAXMODES];
+    uaecptr BoardInfo;
+};
+
+#define        P96B_FAMILY     0                       /* obsolete (Resolution is an entire family) */
+#define        P96B_PUBLIC     1                       /* Resolution should be added to the public */
+#define        P96B_MONITOOL   2
+
+#define        P96F_FAMILY     (1<<P96B_FAMILY)        /* obsolete */
+#define        P96F_PUBLIC     (1<<P96B_PUBLIC)
+#define        P96F_MONITOOL   (1<<P96B_MONITOOL)
+
+#define PSSO_ModeInfo_OpenCount 14
+#define PSSO_ModeInfo_Active 16
+#define PSSO_ModeInfo_Width 18
+#define PSSO_ModeInfo_Height 20
+#define PSSO_ModeInfo_Depth 22
+#define PSSO_ModeInfo_Flags 23
+#define PSSO_ModeInfo_HorTotal 24
+#define PSSO_ModeInfo_HorBlankSize 26
+#define PSSO_ModeInfo_HorSyncStart 28
+#define PSSO_ModeInfo_HorSyncSize 30
+#define PSSO_ModeInfo_HorSyncSkew 32
+#define PSSO_ModeInfo_HorEnableSkew 33
+#define PSSO_ModeInfo_VerTotal 34
+#define PSSO_ModeInfo_VerBlankSize 36
+#define PSSO_ModeInfo_VerSyncStart 38
+#define PSSO_ModeInfo_VerSyncSize 40
+#define PSSO_ModeInfo_first_union 42
+#define PSSO_ModeInfo_second_union 43
+#define PSSO_ModeInfo_PixelClock 44
+#define PSSO_ModeInfo_sizeof 48
+
+#define PSSO_RenderInfo_Memory 0
+#define PSSO_RenderInfo_BytesPerRow 4
+#define PSSO_RenderInfo_pad 6
+#define PSSO_RenderInfo_RGBFormat 8
+#define PSSO_RenderInfo_sizeof 12
+
+struct RenderInfo {
+    uae_u8 *Memory;
+    uae_s16 BytesPerRow;
+    uae_s16 pad;
+    RGBFTYPE RGBFormat;
+    uaecptr AMemory;
+};
+
+#define PSSO_Pattern_Memory 0
+#define PSSO_Pattern_XOffset 4
+#define PSSO_Pattern_YOffset 6
+#define PSSO_Pattern_FgPen 8
+#define PSSO_Pattern_BgPen 12
+#define PSSO_Pattern_Size 16
+#define PSSO_Pattern_DrawMode 17
+#define PSSO_Pattern_sizeof 18
+struct Pattern {
+    char *Memory;
+    uae_u16 XOffset, YOffset;
+    uae_u32 FgPen, BgPen;
+    uae_u8 Size;                                       /* Width: 16, Height: (1<<pat_Size) */
+    uae_u8 DrawMode;
+};
+
+#define PSSO_Template_Memory 0
+#define PSSO_Template_BytesPerRow 4
+#define PSSO_Template_XOffset 6
+#define PSSO_Template_DrawMode 7
+#define PSSO_Template_FgPen 8
+#define PSSO_Template_BgPen 12
+#define PSSO_Template_sizeof 16
+
+struct Template {
+    char *Memory;
+    uae_s16 BytesPerRow;
+    uae_u8 XOffset;
+    uae_u8 DrawMode;
+    uae_u32 FgPen;
+    uae_u32 BgPen;
+};
+
+#define PSSO_Line_X 0
+#define PSSO_Line_Y 2
+#define PSSO_Line_Length 4
+#define PSSO_Line_dX 6
+#define PSSO_Line_dY 8
+#define PSSO_Line_sDelta 10
+#define PSSO_Line_lDelta 12
+#define PSSO_Line_twoSDminusLD 14
+#define PSSO_Line_LinePtrn 16
+#define PSSO_Line_PatternShift 18
+#define PSSO_Line_FgPen 20
+#define PSSO_Line_BgPen 24
+#define PSSO_Line_Horizontal 28
+#define PSSO_Line_DrawMode 30
+#define PSSO_Line_pad 31
+#define PSSO_Line_Xorigin 32
+#define PSSO_Line_Yorigin 34
+
+struct Line {
+       uae_u16                 X, Y;
+       uae_u16                 Length;
+       uae_s16                 dX, dY;
+       uae_s16                 sDelta, lDelta, twoSDminusLD;
+       uae_u16                 LinePtrn;
+       uae_u16                 PatternShift;
+       uae_u32                 FgPen, BgPen;
+       uae_u16                 Horizontal;
+       uae_u8                  DrawMode;
+       uae_s8                  pad;
+       uae_u16                 Xorigin, Yorigin;
+};
+
+#define PSSO_BitMapExtra_BoardNode        0
+#define PSSO_BitMapExtra_HashChain        8 /* BoardNode is 8-bytes */
+#define PSSO_BitMapExtra_Match           12
+#define PSSO_BitMapExtra_BitMap          16
+#define PSSO_BitMapExtra_BoardInfo       20
+#define PSSO_BitMapExtra_MemChunk        24
+#define PSSO_BitMapExtra_RenderInfo      28
+#define PSSO_BitMapExtra_Width           40 /* RenderInfo is 12-bytes */
+#define PSSO_BitMapExtra_Height          42
+#define PSSO_BitMapExtra_Flags           44
+#define PSSO_BitMapExtra_BaseLevel       46
+#define PSSO_BitMapExtra_CurrentLevel    48
+#define PSSO_BitMapExtra_CompanionMaster 50
+#define PSSO_BitMapExtra_Last            54
+
+#define PSSO_BoardInfo_RegisterBase                0
+#define PSSO_BoardInfo_MemoryBase                  PSSO_BoardInfo_RegisterBase + 4
+#define PSSO_BoardInfo_MemoryIOBase                PSSO_BoardInfo_MemoryBase + 4
+#define PSSO_BoardInfo_MemorySize                  PSSO_BoardInfo_MemoryIOBase + 4
+#define PSSO_BoardInfo_BoardName                   PSSO_BoardInfo_MemorySize + 4
+#define PSSO_BoardInfo_VBIName                     PSSO_BoardInfo_BoardName + 4
+#define PSSO_BoardInfo_CardBase                    PSSO_BoardInfo_VBIName + 32
+#define PSSO_BoardInfo_ChipBase                    PSSO_BoardInfo_CardBase + 4
+#define PSSO_BoardInfo_ExecBase                    PSSO_BoardInfo_ChipBase + 4
+#define PSSO_BoardInfo_UtilBase                    PSSO_BoardInfo_ExecBase + 4
+#define PSSO_BoardInfo_HardInterrupt               PSSO_BoardInfo_UtilBase + 4
+#define PSSO_BoardInfo_SoftInterrupt               PSSO_BoardInfo_HardInterrupt + 22 /* The HardInterrupt is 22-bytes */
+#define PSSO_BoardInfo_BoardLock                   PSSO_BoardInfo_SoftInterrupt + 22 /* The SoftInterrupt is 22-bytes */
+#define PSSO_BoardInfo_ResolutionsList             PSSO_BoardInfo_BoardLock + 46 /* On the BoardLock, we were having some fun... */
+#define PSSO_BoardInfo_BoardType                   PSSO_BoardInfo_ResolutionsList + 12 /* The ResolutionsList is 12-bytes */
+#define PSSO_BoardInfo_PaletteChipType             PSSO_BoardInfo_BoardType + 4
+#define PSSO_BoardInfo_GraphicsControllerType      PSSO_BoardInfo_PaletteChipType + 4
+#define PSSO_BoardInfo_MoniSwitch                  PSSO_BoardInfo_GraphicsControllerType + 4
+#define PSSO_BoardInfo_BitsPerCannon               PSSO_BoardInfo_MoniSwitch + 2
+#define PSSO_BoardInfo_Flags                       PSSO_BoardInfo_BitsPerCannon + 2
+#define PSSO_BoardInfo_SoftSpriteFlags             PSSO_BoardInfo_Flags + 4
+#define PSSO_BoardInfo_ChipFlags                   PSSO_BoardInfo_SoftSpriteFlags + 2
+#define PSSO_BoardInfo_CardFlags                   PSSO_BoardInfo_ChipFlags + 2
+#define PSSO_BoardInfo_BoardNum                    PSSO_BoardInfo_CardFlags + 4
+#define PSSO_BoardInfo_RGBFormats                  PSSO_BoardInfo_BoardNum + 2
+#define PSSO_BoardInfo_MaxHorValue                 PSSO_BoardInfo_RGBFormats + 2
+#define PSSO_BoardInfo_MaxVerValue                 PSSO_BoardInfo_MaxHorValue + MAXMODES*2
+#define PSSO_BoardInfo_MaxHorResolution            PSSO_BoardInfo_MaxVerValue + MAXMODES*2
+#define PSSO_BoardInfo_MaxVerResolution            PSSO_BoardInfo_MaxHorResolution + MAXMODES*2
+#define PSSO_BoardInfo_MaxMemorySize               PSSO_BoardInfo_MaxVerResolution + MAXMODES*2
+#define PSSO_BoardInfo_MaxChunkSize                PSSO_BoardInfo_MaxMemorySize + 4
+#define PSSO_BoardInfo_MemoryClock                 PSSO_BoardInfo_MaxChunkSize + 4
+#define PSSO_BoardInfo_PixelClockCount             PSSO_BoardInfo_MemoryClock + 4
+#define PSSO_BoardInfo_AllocCardMem                PSSO_BoardInfo_PixelClockCount + MAXMODES*4
+#define PSSO_BoardInfo_SpecialFeatures             PSSO_BoardInfo_AllocCardMem + 68*4 /* 68 function pointers */
+#define PSSO_BoardInfo_ModeInfo                    PSSO_BoardInfo_SpecialFeatures + 12 /* SpecialFeatures is 12-bytes */
+#define PSSO_BoardInfo_RGBFormat                   PSSO_BoardInfo_ModeInfo + 4
+#define PSSO_BoardInfo_XOffset                     PSSO_BoardInfo_RGBFormat + 4
+#define PSSO_BoardInfo_YOffset                     PSSO_BoardInfo_XOffset + 2
+#define PSSO_BoardInfo_Depth                       PSSO_BoardInfo_YOffset + 2
+#define PSSO_BoardInfo_ClearMask                   PSSO_BoardInfo_Depth + 1
+#define PSSO_BoardInfo_Border                      PSSO_BoardInfo_ClearMask + 1
+#define PSSO_BoardInfo_Mask                        PSSO_BoardInfo_Border + 2 /* BOOL type is only 2-bytes! */
+#define PSSO_BoardInfo_CLUT                        PSSO_BoardInfo_Mask + 4
+#define PSSO_BoardInfo_ViewPort                    PSSO_BoardInfo_CLUT + 3*256
+#define PSSO_BoardInfo_VisibleBitMap               PSSO_BoardInfo_ViewPort + 4
+#define PSSO_BoardInfo_BitMapExtra                 PSSO_BoardInfo_VisibleBitMap + 4
+#define PSSO_BoardInfo_BitMapList                  PSSO_BoardInfo_BitMapExtra + 4
+#define PSSO_BoardInfo_MemList                     PSSO_BoardInfo_BitMapList + 12 /* BitMapList is 12-bytes */
+#define PSSO_BoardInfo_MouseX                      PSSO_BoardInfo_MemList + 12 /* MemList is 12-bytes */
+#define PSSO_BoardInfo_MouseY                      PSSO_BoardInfo_MouseX + 2
+#define PSSO_BoardInfo_MouseWidth                  PSSO_BoardInfo_MouseY + 2
+#define PSSO_BoardInfo_MouseHeight                 PSSO_BoardInfo_MouseWidth + 1
+#define PSSO_BoardInfo_MouseXOffset                PSSO_BoardInfo_MouseHeight + 1
+#define PSSO_BoardInfo_MouseYOffset                PSSO_BoardInfo_MouseXOffset + 1
+#define PSSO_BoardInfo_MouseImage                  PSSO_BoardInfo_MouseYOffset + 1
+#define PSSO_BoardInfo_MousePens                   PSSO_BoardInfo_MouseImage + 4
+#define PSSO_BoardInfo_MouseRect                   PSSO_BoardInfo_MousePens + 4
+#define PSSO_BoardInfo_MouseChunky                 PSSO_BoardInfo_MouseRect + 8 /* MouseRect is 8-bytes */
+#define PSSO_BoardInfo_MouseRendered               PSSO_BoardInfo_MouseChunky + 4
+#define PSSO_BoardInfo_MouseSaveBuffer             PSSO_BoardInfo_MouseRendered + 4
+
+struct BoardInfo {
+    uae_u8 *RegisterBase, *MemoryBase, *MemoryIOBase;
+    uae_u32 MemorySize;
+    char *BoardName, VBIName[32];
+
+    uae_u16 MoniSwitch;
+    uae_u16 BitsPerCannon;
+    uae_u32 Flags;
+    uae_u16 SoftSpriteFlags;
+    uae_u16 ChipFlags; /* private, chip specific, not touched by RTG */
+    uae_u32 CardFlags; /* private, card specific, not touched by RTG */
+
+    uae_u16 BoardNum;
+    uae_s16 RGBFormats;
+
+    uae_u16 MaxHorValue[MAXMODES];
+    uae_u16 MaxVerValue[MAXMODES];
+    uae_u16 MaxHorResolution[MAXMODES];
+    uae_u16 MaxVerResolution[MAXMODES];
+    uae_u32 MaxMemorySize, MaxChunkSize;
+};
+
+/* BoardInfo flags */
+/*  0-15: hardware flags */
+/* 16-31: user flags */
+#define BIB_HARDWARESPRITE     0       /* board has hardware sprite */
+#define BIB_NOMEMORYMODEMIX    1       /* board does not support modifying planar bitmaps while displaying chunky and vice versa */
+#define BIB_NEEDSALIGNMENT     2       /* bitmaps have to be aligned (not yet supported!) */
+#define BIB_DBLSCANDBLSPRITEY  8       /* hardware sprite y position is doubled on doublescan display modes */
+#define BIB_ILACEHALFSPRITEY   9       /* hardware sprite y position is halved on interlace display modes */
+#define BIB_ILACEDBLROWOFFSET  10      /* doubled row offset in interlaced display modes needs additional horizontal bit */
+
+#define BIB_FLICKERFIXER       12      /* board can flicker fix Amiga RGB signal */
+#define BIB_VIDEOCAPTURE       13      /* board can capture video data to a memory area */
+#define BIB_VIDEOWINDOW                14      /* board can display a second mem area as a pip */
+#define BIB_BLITTER            15      /* board has blitter */
+
+#define BIB_HIRESSPRITE                16      /* mouse sprite has double resolution */
+#define BIB_BIGSPRITE          17      /* user wants big mouse sprite */
+#define BIB_BORDEROVERRIDE     18      /* user wants to override system overscan border prefs */
+#define BIB_BORDERBLANK                19      /* user wants border blanking */
+#define BIB_INDISPLAYCHAIN     20      /* board switches Amiga signal */
+#define BIB_QUIET              21      /* not yet implemented */
+#define BIB_NOMASKBLITS                22      /* perform blits without taking care of mask */
+#define BIB_NOC2PBLITS         23      /* use CPU for planar to chunky conversions */
+#define BIB_NOBLITTER          24      /* disable all blitter functions */
+
+#define BIB_IGNOREMASK BIB_NOMASKBLITS
+
+#define BIF_HARDWARESPRITE     (1<<BIB_HARDWARESPRITE)
+#define BIF_NOMEMORYMODEMIX    (1<<BIB_NOMEMORYMODEMIX)
+#define BIF_NEEDSALIGNMENT     (1<<BIB_NEEDSALIGNMENT)
+#define BIF_DBLSCANDBLSPRITEY  (1<<BIB_DBLSCANDBLSPRITEY)
+#define BIF_ILACEHALFSPRITEY   (1<<BIB_ILACEHALFSPRITEY)
+#define BIF_ILACEDBLROWOFFSET  (1<<BIB_ILACEDBLROWOFFSET)
+#define BIF_FLICKERFIXER       (1<<BIB_FLICKERFIXER)
+#define BIF_VIDEOCAPTURE       (1<<BIB_VIDEOCAPTURE)
+#define BIF_VIDEOWINDOW                (1<<BIB_VIDEOWINDOW)
+#define BIF_BLITTER            (1<<BIB_BLITTER)
+#define BIF_HIRESSPRITE                (1<<BIB_HIRESSPRITE)
+#define BIF_BIGSPRITE          (1<<BIB_BIGSPRITE)
+#define BIF_BORDEROVERRIDE     (1<<BIB_BORDEROVERRIDE)
+#define BIF_BORDERBLANK                (1<<BIB_BORDERBLANK)
+#define BIF_INDISPLAYCHAIN     (1<<BIB_INDISPLAYCHAIN)
+#define BIF_QUIET              (1<<BIB_QUIET)
+#define BIF_NOMASKBLITS                (1<<BIB_NOMASKBLITS)
+#define BIF_NOC2PBLITS         (1<<BIB_NOC2PBLITS)
+#define BIF_NOBLITTER          (1<<BIB_NOBLITTER)
+
+#define BIF_IGNOREMASK         BIF_NOMASKBLITS
+
+/************************************************************************/
+struct picasso96_state_struct
+{
+    uae_u32             RGBFormat;   /* true-colour, CLUT, hi-colour, etc.*/
+    struct MyCLUTEntry  CLUT[256];   /* Duh! */
+    uaecptr             Address;     /* Active screen address (Amiga-side)*/
+    uaecptr             Extent;      /* End address of screen (Amiga-side)*/
+    uae_u16             Width;       /* Active display width  (From SetGC)*/
+    uae_u16             VirtualWidth;/* Total screen width (From SetPanning)*/
+    uae_u16             BytesPerRow; /* Total screen width in bytes (FromSetGC) */
+    uae_u16             Height;      /* Active display height (From SetGC)*/
+    uae_u16             VirtualHeight; /* Total screen height */
+    uae_u8              GC_Depth;    /* From SetGC() */
+    uae_u8              GC_Flags;    /* From SetGC() */
+    long                XOffset;     /* From SetPanning() */
+    long                YOffset;     /* From SetPanning() */
+    uae_u8              SwitchState; /* From SetSwitch() - 0 is Amiga, 1 isPicasso */
+    uae_u8              BytesPerPixel;
+    uae_u8              CardFound;
+    //here follow winuae additional entrys
+    uae_u8  BigAssBitmap; /* Set to 1 when our Amiga screen is bigger than the displayable area */
+    unsigned int        Version;
+    uaecptr  HostAddress; /* Active screen address (PC-side) */
+    // host address is need because Windows
+    // support NO direct access all the time to gfx Card
+    // everytime windows can remove your surface from card so the mainrender place
+    // must be in memory
+};
+
+extern void InitPicasso96 (void);
+
+extern int GetNumResolutions( void );
+extern int GetDisplayModeIndex( uae_u32 x, uae_u32 y, uae_u32 d);
+extern uae_u32 picasso_SetDisplay (void);
+extern uae_u32 picasso_CalculateBytesPerRow (void);
+extern uae_u32 picasso_FillRect (void);
+extern uae_u32 picasso_BlitRect (void);
+extern uae_u32 picasso_InvertRect (void);
+extern uae_u32 picasso_SetPanning (void);
+extern uae_u32 picasso_SetGC (void);
+extern uae_u32 picasso_SetDAC (void);
+extern uae_u32 picasso_SetColorArray (void);
+extern uae_u32 picasso_SetSwitch (void);
+extern uae_u32 picasso_SetSwitch (void);
+extern uae_u32 picasso_FindCard (void);
+extern uae_u32 picasso_InitCard (void);
+extern uae_u32 picasso_BlitPlanar2Chunky (void);
+extern uae_u32 picasso_BlitPlanar2Direct (void);
+extern uae_u32 picasso_BlitTemplate (void);
+extern uae_u32 picasso_BlitPattern (void);
+extern uae_u32 picasso_BlitRectNoMaskComplete (void);
+extern uae_u32 picasso_SetSprite (void);
+extern uae_u32 picasso_SetSpritePosition (void);
+extern uae_u32 picasso_SetSpriteImage (void);
+extern uae_u32 picasso_SetSpriteColor (void);
+extern uae_u32 picasso_DrawLine (void);
+extern uae_u32 gfxmem_mask;
+extern uae_u8 *gfxmemory;
+
+extern int uaegfx_card_found;
+
+extern struct picasso96_state_struct picasso96_state;
+extern uae_u16 picasso96_pixel_format;
+
+#ifdef _WIN32
+extern unsigned int timer_id;
+#endif
+
+extern int  DX_InvertRect (int X, int Y, int Width, int Height);
+extern void DX_SetPalette (int start, int count);
+extern int  DX_BitsPerCannon (void);
+extern void DX_Invalidate (int first, int last);
+extern int  DX_Flip( void );
+extern int  DX_Blit( int srcx, int srcy, int dstx, int dsty, int w, int h, BLIT_OPCODE opcode );
+extern int  DX_Fill( int dstx, int dsty, int width, int height, uae_u32 color, RGBFTYPE rgbtype );
+extern uae_u32 DX_ShowCursor( uae_u32 activate );
+extern uae_u32 DX_MoveCursor( uae_u32 x, uae_u32 y );
+extern void picasso_enablescreen (int on);
+extern void picasso_refresh (int);
+extern void picasso_handle_vsync (void);
+extern void init_hz_p96 (void);
+extern void picasso_handle_hsync (void);
+
+extern uae_u8 *gfxmemory;
+
+/* This structure describes the UAE-side framebuffer for the Picasso
+ * screen.  */
+struct picasso_vidbuf_description {
+    int width, height, depth;
+    int rowbytes, pixbytes;
+    int extra_mem; /* nonzero if there's a second buffer that must be updated */
+    uae_u32 rgbformat;
+    uae_u32 selected_rgbformat;
+    uae_u32 clut[256];
+};
+
+extern struct picasso_vidbuf_description picasso_vidinfo;
+
+extern void gfx_set_picasso_modeinfo (uae_u32 w, uae_u32 h, uae_u32 d, RGBFTYPE rgbfmt);
+extern void gfx_set_picasso_baseaddr (uaecptr);
+extern void gfx_set_picasso_state (int on);
+extern uae_u8 *gfx_lock_picasso (void);
+extern void gfx_unlock_picasso (void);
+extern void picasso_clip_mouse (int *, int *);
+
+extern int p96refresh_active;
+extern int p96hsync_counter;
+
+#endif
+
+#endif
diff --git a/od-win32/posixemu.c b/od-win32/posixemu.c
new file mode 100755 (executable)
index 0000000..a7f907e
--- /dev/null
@@ -0,0 +1,527 @@
+/* 
+ * UAE - The Un*x Amiga Emulator
+ *
+ * Win32 interface
+ *
+ * Copyright 1997 Mathias Ortmann
+ */
+
+#include "config.h"
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <windows.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ddraw.h>
+#include <commctrl.h>
+#include <commdlg.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <io.h>
+#include <sys/types.h>
+#include <sys/timeb.h>
+#include <sys/utime.h>
+#include <process.h>
+#include "options.h"
+#include "posixemu.h"
+#include "threaddep/thread.h"
+#include "filesys.h"
+
+/* Our Win32 implementation of this function */
+void gettimeofday( struct timeval *tv, void *blah )
+{
+    struct timeb time;
+    ftime( &time );
+
+    tv->tv_sec = time.time;
+    tv->tv_usec = time.millitm * 1000;
+}
+
+/* convert time_t to/from AmigaDOS time */
+#define secs_per_day ( 24 * 60 * 60 )
+#define diff ( (8 * 365 + 2) * secs_per_day )
+
+void get_time(time_t t, long* days, long* mins, long* ticks)
+{
+    /* time_t is secs since 1-1-1970 */
+    /* days since 1-1-1978 */
+    /* mins since midnight */
+    /* ticks past minute @ 50Hz */
+
+    t -= diff;
+    *days = t / secs_per_day;
+    t -= *days * secs_per_day;
+    *mins = t / 60;
+    t -= *mins * 60;
+    *ticks = t * 50;
+}
+
+/* stdioemu, posixemu, mallocemu, and various file system helper routines */
+static DWORD lasterror;
+
+static int isillegal (unsigned char *str)
+{
+    int result = 0;
+    unsigned char a = *str, b = str[1], c = str[2];
+
+    if (a >= 'a' && a <= 'z')
+       a &= ~' ';
+    if (b >= 'a' && b <= 'z')
+       b &= ~' ';
+    if (c >= 'a' && c <= 'z')
+       c &= ~' ';
+
+    result = ( (a == 'A' && b == 'U' && c == 'X') ||
+               (a == 'C' && b == 'O' && c == 'N') ||
+               (a == 'P' && b == 'R' && c == 'N') ||
+               (a == 'N' && b == 'U' && c == 'L') );
+
+    return result;
+}
+
+static int checkspace (char *str, char s, char d)
+{
+    char *ptr = str;
+
+    while (*ptr && *ptr == s)
+       ptr++;
+
+    if (!*ptr || *ptr == '/' || *ptr == '\\') {
+       while (str < ptr)
+           *(str++) = d;
+       return 0;
+    }
+    return 1;
+}
+
+/* This is sick and incomplete... in the meantime, I have discovered six new illegal file name formats
+ * M$ sucks! */
+void fname_atow (const char *src, char *dst, int size)
+{
+    char *lastslash = dst, *strt = dst, *posn = NULL, *temp = NULL;
+    int i, j;
+
+    temp = xmalloc( size );
+
+    while (size-- > 0) {
+       if (!(*dst = *src++))
+           break;
+
+       if (*dst == '~' || *dst == '|' || *dst == '*' || *dst == '?') {
+           if (size > 2) {
+               sprintf (dst, "~%02x", *dst);
+               size -= 2;
+               dst += 2;
+           }
+       } else if (*dst == '/') {
+           if (checkspace (lastslash, ' ', (char)0xa0) && (dst - lastslash == 3 || (dst - lastslash > 3 && lastslash[3] == '.')) && isillegal (lastslash)) {
+               i = dst - lastslash - 3;
+               dst++;
+               for (j = i + 1; j--; dst--)
+                   *dst = dst[-1];
+               *(dst++) = (char)0xa0;
+               dst += i;
+               size--;
+           } else if (*lastslash == '.' && (dst - lastslash == 1 || (lastslash[1] == '.' && dst - lastslash == 2)) && size) {
+               *(dst++) = (char)0xa0;
+               size--;
+           }
+           *dst = '\\';
+           lastslash = dst + 1;
+       }
+       dst++;
+    }
+
+    if (checkspace (lastslash, ' ', (char)0xa0) && (dst - lastslash == 3 || (dst - lastslash > 3 && lastslash[3] == '.')) && isillegal (lastslash) && size > 1) {
+       i = dst - lastslash - 3;
+       dst++;
+       for (j = i + 1; j--; dst--)
+           *dst = dst[-1];
+       *(dst++) = (char)0xa0;
+    } else if (!strcmp (lastslash, ".") || !strcmp (lastslash, ".."))
+       strcat (lastslash, "\xa0");
+
+    /* Major kludge, because I can't find the problem... */
+    if( ( posn = strstr( strt, "..\xA0\\" ) ) == strt && temp)
+    {
+        strcpy( temp, "..\\" );
+        strcat( temp, strt + 4 );
+        strcpy( strt, temp );
+    }
+
+    /* Another major kludge, for the MUI installation... */
+    if( *strt == ' ' ) /* first char as a space is illegal in Windoze */
+    {
+        sprintf( temp, "~%02x%s", ' ', strt+1 );
+        strcpy( strt, temp );
+    }
+
+    free (temp);
+}
+
+static int hextol (char a)
+{
+    if (a >= '0' && a <= '9')
+       return a - '0';
+    if (a >= 'a' && a <= 'f')
+       return a - 'a' + 10;
+    if (a >= 'A' && a <= 'F')
+       return a - 'A' + 10;
+    return 2;
+}
+
+/* Win32 file name restrictions suck... */
+void fname_wtoa (unsigned char *ptr)
+{
+    unsigned char *lastslash = ptr;
+
+    while (*ptr) {
+       if (*ptr == '~') {
+           *ptr = hextol (ptr[1]) * 16 + hextol (ptr[2]);
+           strcpy (ptr + 1, ptr + 3);
+       } else if (*ptr == '\\') {
+           if (checkspace (lastslash, ' ', (char)0xa0) && ptr - lastslash > 3 && lastslash[3] == 0xa0 && isillegal (lastslash)) {
+               ptr--;
+               strcpy (lastslash + 3, lastslash + 4);
+           }
+           *ptr = '/';
+           lastslash = ptr + 1;
+       }
+       ptr++;
+    }
+
+    if (checkspace (lastslash, ' ', (char)0xa0) && ptr - lastslash > 3 && lastslash[3] == 0xa0 && isillegal (lastslash))
+       strcpy (lastslash + 3, lastslash + 4);
+}
+
+#ifndef HAVE_TRUNCATE
+int truncate (const char *name, long int len)
+{
+    HANDLE hFile;
+    BOOL bResult = FALSE;
+    int result = -1;
+
+#if 0
+    char buf[1024];
+
+    fname_atow(name,buf,sizeof buf);
+
+    if( ( hFile = CreateFile( buf, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+                              OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ) ) != INVALID_HANDLE_VALUE )
+    {
+        if( SetFilePointer( hFile, len, NULL, FILE_BEGIN ) == (DWORD)len )
+        {
+            if( SetEndOfFile( hFile ) == TRUE )
+                result = 0;
+        }
+        else
+        {
+            write_log( "SetFilePointer() failure for %s to posn %d\n", buf, len );
+        }
+        CloseHandle( hFile );
+    }
+    else
+    {
+        write_log( "CreateFile() failed to open %s\n", buf );
+    }
+#else
+    if( ( hFile = CreateFile( name, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+                              OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ) ) != INVALID_HANDLE_VALUE )
+    {
+        if( SetFilePointer( hFile, len, NULL, FILE_BEGIN ) == (DWORD)len )
+        {
+            if( SetEndOfFile( hFile ) == TRUE )
+                result = 0;
+        }
+        else
+        {
+            write_log( "SetFilePointer() failure for %s to posn %d\n", name, len );
+        }
+        CloseHandle( hFile );
+    }
+    else
+    {
+        write_log( "CreateFile() failed to open %s\n", name );
+    }
+#endif
+    if( result == -1 )
+        lasterror = GetLastError();
+    return result;
+}
+#endif
+
+DIR {
+    WIN32_FIND_DATA finddata;
+    HANDLE hDir;
+    int getnext;
+};
+
+DIR *posixemu_opendir(const char *path)
+{
+    char buf[1024];
+    DIR *dir;
+
+    if (!(dir = (DIR *)GlobalAlloc(GPTR,sizeof(DIR))))
+    {
+           lasterror = GetLastError();
+           return 0;
+    }
+#if 0
+    fname_atow(path,buf,sizeof buf-4);
+#else
+    strcpy( buf, path );
+#endif
+    strcat(buf,"\\*");
+
+    if ((dir->hDir = FindFirstFile(buf,&dir->finddata)) == INVALID_HANDLE_VALUE)
+    {
+           lasterror = GetLastError();
+           GlobalFree(dir);
+           return 0;
+    }
+
+    return dir;
+}
+
+struct dirent *posixemu_readdir(DIR *dir)
+{
+    if (dir->getnext)
+    {
+       if (!FindNextFile(dir->hDir,&dir->finddata))
+       {
+           lasterror = GetLastError();
+           return 0;
+       }
+    }
+    dir->getnext = TRUE;
+
+    fname_wtoa(dir->finddata.cFileName);
+    return (struct dirent *)dir->finddata.cFileName;
+}
+
+void posixemu_closedir(DIR *dir)
+{
+    FindClose(dir->hDir);
+    GlobalFree(dir);
+}
+
+static int w32fopendel(char *name, char *mode, int delflag)
+{
+       HANDLE hFile;
+
+       if ((hFile = CreateFile(name,
+               mode[1] == '+' ? GENERIC_READ | GENERIC_WRITE : GENERIC_READ,   // ouch :)
+               FILE_SHARE_READ | FILE_SHARE_WRITE,
+               NULL,
+               OPEN_EXISTING,
+               delflag ? FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE : FILE_ATTRIBUTE_NORMAL,
+               NULL)) == INVALID_HANDLE_VALUE)
+       {
+               lasterror = GetLastError();
+               hFile = 0;
+       }
+
+       return (int)hFile;                      /* return handle */
+}
+       
+DWORD getattr(const char *name, LPFILETIME lpft, size_t *size)
+{
+       HANDLE hFind;
+       WIN32_FIND_DATA fd;
+
+       if ((hFind = FindFirstFile(name,&fd)) == INVALID_HANDLE_VALUE)
+       {
+               lasterror = GetLastError();
+
+               fd.dwFileAttributes = GetFileAttributes(name);
+
+               return fd.dwFileAttributes;
+       }
+
+       FindClose(hFind);
+
+       if (lpft) *lpft = fd.ftLastWriteTime;
+       if (size) *size = fd.nFileSizeLow;
+
+       return fd.dwFileAttributes;
+}
+
+int isspecialdrive(const char *name)
+{
+    int v, err;
+    DWORD last = SetErrorMode (SEM_FAILCRITICALERRORS);
+    v = GetFileAttributes(name);
+    err = GetLastError ();
+    SetErrorMode (last);
+    if (v != INVALID_FILE_ATTRIBUTES)
+       return 0;
+    if (err == ERROR_NOT_READY)
+       return 1;
+    if (err)
+       return -1;
+    return 0;
+}
+
+int posixemu_stat(const char *name, struct stat *statbuf)
+{
+    DWORD attr;
+    FILETIME ft, lft;
+
+    if ((attr = getattr(name,&ft,(size_t*)&statbuf->st_size)) == (DWORD)~0)
+    {
+       lasterror = GetLastError();
+       return -1;
+    }
+    else
+    {
+       statbuf->st_mode = (attr & FILE_ATTRIBUTE_READONLY) ? FILEFLAG_READ : FILEFLAG_READ | FILEFLAG_WRITE;
+       if (attr & FILE_ATTRIBUTE_ARCHIVE) statbuf->st_mode |= FILEFLAG_ARCHIVE;
+       if (attr & FILE_ATTRIBUTE_DIRECTORY) statbuf->st_mode |= FILEFLAG_DIR;
+       FileTimeToLocalFileTime(&ft,&lft);
+       statbuf->st_mtime = (long)((*(__int64 *)&lft-((__int64)(369*365+89)*(__int64)(24*60*60)*(__int64)10000000))/(__int64)10000000);
+    }
+    return 0;
+}
+
+int posixemu_chmod(const char *name, int mode)
+{
+    DWORD attr = FILE_ATTRIBUTE_NORMAL;
+    if (!(mode & FILEFLAG_WRITE)) attr |= FILE_ATTRIBUTE_READONLY;
+    if (mode & FILEFLAG_ARCHIVE) attr |= FILE_ATTRIBUTE_ARCHIVE;
+    if (SetFileAttributes(name,attr)) return 1;
+    lasterror = GetLastError();
+    return -1;
+}
+
+void tmToSystemTime( struct tm *tmtime, LPSYSTEMTIME systime )
+{
+    if( tmtime == NULL )
+    {
+        GetSystemTime( systime );
+    }
+    else
+    {
+        systime->wDay       = tmtime->tm_mday;
+        systime->wDayOfWeek = tmtime->tm_wday;
+        systime->wMonth     = tmtime->tm_mon + 1;
+        systime->wYear      = tmtime->tm_year + 1900;
+        systime->wHour      = tmtime->tm_hour;
+        systime->wMinute    = tmtime->tm_min;
+        systime->wSecond    = tmtime->tm_sec;
+        systime->wMilliseconds = 0;
+    }
+}
+
+static int setfiletime(const char *name, unsigned int days, int minute, int tick, int tolocal)
+{
+    FILETIME LocalFileTime, FileTime;
+    HANDLE hFile;
+    int success;
+    if ((hFile = CreateFile(name, GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL)) == INVALID_HANDLE_VALUE)
+    {
+       lasterror = GetLastError();
+       return 0;
+    }
+
+    *(__int64 *)&LocalFileTime = (((__int64)(377*365+91+days)*(__int64)1440+(__int64)minute)*(__int64)(60*50)+(__int64)tick)*(__int64)200000;
+    
+    if (tolocal) {
+       if (!LocalFileTimeToFileTime(&LocalFileTime,&FileTime)) FileTime = LocalFileTime;
+    } else {
+       FileTime = LocalFileTime;
+    }
+    
+    if (!(success = SetFileTime(hFile,&FileTime,&FileTime,&FileTime))) lasterror = GetLastError();
+    CloseHandle(hFile);
+    
+    return success;
+}
+
+int posixemu_utime( const char *name, struct utimbuf *ttime )
+{
+    int result = -1, tolocal;
+    long days, mins, ticks, actime;
+
+    if (!ttime) {
+       actime = time (NULL);
+       tolocal = 0;
+    } else {
+       tolocal = 1;
+       actime = ttime->actime;
+    }
+    get_time(actime, &days, &mins, &ticks);
+
+    if( setfiletime( name, days, mins, ticks, tolocal ) )
+        result = 0;
+
+       return result;
+}
+
+#if 1
+/* pthread Win32 emulation */
+void sem_init (HANDLE * event, int manual_reset, int initial_state)
+{
+    if( *event )
+    {
+       if( initial_state )
+       {
+           SetEvent( *event );
+       }
+       else
+       {
+           ResetEvent( *event );
+       }
+    }
+    else
+    {
+        *event = CreateEvent (NULL, manual_reset, initial_state, NULL);
+    }
+}
+
+void sem_wait (HANDLE * event)
+{
+    WaitForSingleObject (*event, INFINITE);
+}
+
+void sem_post (HANDLE * event)
+{
+    SetEvent (*event);
+}
+
+int sem_trywait (HANDLE * event)
+{
+    return WaitForSingleObject (*event, 0) == WAIT_OBJECT_0 ? 0 : -1;
+}
+
+void sem_close (HANDLE * event)
+{
+    if( *event )
+    {
+       CloseHandle( *event );
+       *event = NULL;
+    }
+}
+
+typedef unsigned (__stdcall *BEGINTHREADEX_FUNCPTR)(void *);
+
+int start_penguin (void *(*f)(void *), void *arg, DWORD * foo)
+{
+    HANDLE hThread;
+    int result = 1;
+
+    hThread = (HANDLE)_beginthreadex( NULL, 0, (BEGINTHREADEX_FUNCPTR)f, arg, 0, foo );
+    if( hThread )
+        SetThreadPriority (hThread, THREAD_PRIORITY_HIGHEST);
+    else
+        result = 0;
+    return result;
+}
+
+#endif
+
+void set_thread_priority (int pri)
+{
+}
+
diff --git a/od-win32/posixemu.h b/od-win32/posixemu.h
new file mode 100755 (executable)
index 0000000..cfbb506
--- /dev/null
@@ -0,0 +1,7 @@
+/* posixemu prototypes */
+#ifndef __POSIXEMU_H__
+#define __POSIXEMU_H__
+void fname_atow (const char *src, char *dst, int size);
+void fname_wtoa (unsigned char *ptr);
+int w32fopendel(char *name, char *mode, int delflag);
+#endif
\ No newline at end of file
diff --git a/od-win32/resources/35floppy.ico b/od-win32/resources/35floppy.ico
new file mode 100755 (executable)
index 0000000..249005f
Binary files /dev/null and b/od-win32/resources/35floppy.ico differ
diff --git a/od-win32/resources/Mycomp.ico b/od-win32/resources/Mycomp.ico
new file mode 100755 (executable)
index 0000000..9260b94
Binary files /dev/null and b/od-win32/resources/Mycomp.ico differ
diff --git a/od-win32/resources/RCa00564 b/od-win32/resources/RCa00564
new file mode 100755 (executable)
index 0000000..6415f0b
Binary files /dev/null and b/od-win32/resources/RCa00564 differ
diff --git a/od-win32/resources/amigainfo.ico b/od-win32/resources/amigainfo.ico
new file mode 100755 (executable)
index 0000000..92ed436
Binary files /dev/null and b/od-win32/resources/amigainfo.ico differ
diff --git a/od-win32/resources/avioutput.ico b/od-win32/resources/avioutput.ico
new file mode 100755 (executable)
index 0000000..30b40d9
Binary files /dev/null and b/od-win32/resources/avioutput.ico differ
diff --git a/od-win32/resources/chip.ico b/od-win32/resources/chip.ico
new file mode 100755 (executable)
index 0000000..52d09a9
Binary files /dev/null and b/od-win32/resources/chip.ico differ
diff --git a/od-win32/resources/cpu.ico b/od-win32/resources/cpu.ico
new file mode 100755 (executable)
index 0000000..2e790a5
Binary files /dev/null and b/od-win32/resources/cpu.ico differ
diff --git a/od-win32/resources/drive.ico b/od-win32/resources/drive.ico
new file mode 100755 (executable)
index 0000000..1009e45
Binary files /dev/null and b/od-win32/resources/drive.ico differ
diff --git a/od-win32/resources/drive_click.wav b/od-win32/resources/drive_click.wav
new file mode 100755 (executable)
index 0000000..c21a5f8
Binary files /dev/null and b/od-win32/resources/drive_click.wav differ
diff --git a/od-win32/resources/drive_snatch.wav b/od-win32/resources/drive_snatch.wav
new file mode 100755 (executable)
index 0000000..5c36386
Binary files /dev/null and b/od-win32/resources/drive_snatch.wav differ
diff --git a/od-win32/resources/drive_spin.wav b/od-win32/resources/drive_spin.wav
new file mode 100755 (executable)
index 0000000..184524f
Binary files /dev/null and b/od-win32/resources/drive_spin.wav differ
diff --git a/od-win32/resources/drive_spinnd.wav b/od-win32/resources/drive_spinnd.wav
new file mode 100755 (executable)
index 0000000..184524f
Binary files /dev/null and b/od-win32/resources/drive_spinnd.wav differ
diff --git a/od-win32/resources/drive_startup.wav b/od-win32/resources/drive_startup.wav
new file mode 100755 (executable)
index 0000000..6456d8a
Binary files /dev/null and b/od-win32/resources/drive_startup.wav differ
diff --git a/od-win32/resources/file.ico b/od-win32/resources/file.ico
new file mode 100755 (executable)
index 0000000..c1661ad
Binary files /dev/null and b/od-win32/resources/file.ico differ
diff --git a/od-win32/resources/folder.ico b/od-win32/resources/folder.ico
new file mode 100755 (executable)
index 0000000..ae42edc
Binary files /dev/null and b/od-win32/resources/folder.ico differ
diff --git a/od-win32/resources/h_arrow.cur b/od-win32/resources/h_arrow.cur
new file mode 100755 (executable)
index 0000000..27d0f24
Binary files /dev/null and b/od-win32/resources/h_arrow.cur differ
diff --git a/od-win32/resources/joystick.ico b/od-win32/resources/joystick.ico
new file mode 100755 (executable)
index 0000000..8b9d7d7
Binary files /dev/null and b/od-win32/resources/joystick.ico differ
diff --git a/od-win32/resources/misc.ico b/od-win32/resources/misc.ico
new file mode 100755 (executable)
index 0000000..9d335ba
Binary files /dev/null and b/od-win32/resources/misc.ico differ
diff --git a/od-win32/resources/move_dow.ico b/od-win32/resources/move_dow.ico
new file mode 100755 (executable)
index 0000000..a348183
Binary files /dev/null and b/od-win32/resources/move_dow.ico differ
diff --git a/od-win32/resources/move_up.ico b/od-win32/resources/move_up.ico
new file mode 100755 (executable)
index 0000000..879cd92
Binary files /dev/null and b/od-win32/resources/move_up.ico differ
diff --git a/od-win32/resources/resource.h b/od-win32/resources/resource.h
new file mode 100755 (executable)
index 0000000..72279d5
--- /dev/null
@@ -0,0 +1,668 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by winuae.rc
+//
+#define IDS_KICKSTART                   1
+#define IDS_DISK                        2
+#define IDS_DISPLAY                     3
+#define IDS_HARDDISK                    4
+#define IDS_FLOPPY                      5
+#define IDS_ABOUT                       6
+#define IDS_LOADSAVE                    7
+#define IDS_AVIOUTPUT                   8
+#define IDS_PORTS                       9
+#define IDS_MISC1                       10
+#define IDS_MEMORY                      11
+#define IDS_CPU                         12
+#define IDS_CHIPSET                     13
+#define IDS_INPUT                       14
+#define IDS_OPENGL                      15
+#define IDS_MISC2                       16
+#define IDS_EXTTEXT                     100
+#define IDS_EXTACTUAL                   101
+#define IDS_SOUND                       102
+#define IDS_CDROM                       103
+#define IDS_FRAMERATE                   104
+#define IDS_SECOND                      105
+#define IDS_THIRD                       106
+#define IDD_KICKSTART                   107
+#define IDS_FOURTH                      107
+#define IDD_DISPLAY                     108
+#define IDS_FIFTH                       108
+#define IDD_MEMORY                      109
+#define IDS_SIXTH                       109
+#define IDD_FLOPPY                      110
+#define IDS_SEVENTH                     110
+#define IDD_CPU                         111
+#define IDS_EIGHTH                      111
+#define IDD_ABOUT                       112
+#define IDS_NINTH                       112
+#define IDD_HARDDISK                    113
+#define IDS_TENTH                       113
+#define IDS_SELECTADF                   114
+#define IDS_ADF                         115
+#define IDS_CHOOSEBLANK                 116
+#define IDS_SELECTHDF                   117
+#define IDS_HDF                         118
+#define IDS_SELECTUAE                   119
+#define IDS_UAE                         120
+#define IDS_SELECTROM                   121
+#define IDD_SOUND                       122
+#define IDS_ROM                         122
+#define IDI_APPICON                     123
+#define IDS_SELECTKEY                   123
+#define IDI_CPU                         124
+#define IDS_KEY                         124
+#define IDI_ABOUT                       125
+#define IDS_SELECTINFO                  125
+#define IDS_NONE                        126
+#define IDS_VOLUME                      127
+#define IDI_HARDDISK                    128
+#define IDS_PATH                        128
+#define IDS_RW                          129
+#define IDI_SOUND                       130
+#define IDS_SECTORS                     130
+#define IDS_SURFACES                    131
+#define IDS_RESERVED                    132
+#define IDS_BLOCKSIZE                   133
+#define IDI_FLOPPY                      134
+#define IDS_NAME                        134
+#define IDD_LOADSAVE                    135
+#define IDS_DESCRIPTION                 135
+#define IDS_ONEINSTANCE                 136
+#define IDI_PORTS                       137
+#define IDS_INSTALLDIRECTX              137
+#define IDD_PORTS                       138
+#define IDS_REGKEYCREATEFAILED          138
+#define IDS_COULDNOTLOADCONFIG          139
+#define IDD_CONTRIBUTORS                140
+#define IDS_NOHELP                      140
+#define IDD_MISC1                       141
+#define IDS_MUSTSELECTCONFIG            141
+#define IDD_HARDFILE                    142
+#define IDS_NOAGA                       142
+#define IDD_FILESYS                     143
+#define IDS_INVALIDCOMPORT              143
+#define IDS_WSOCK2NEEDED                144
+#define IDD_MISC2                       144
+#define IDS_UNSUPPORTEDPIXELFORMAT      145
+#define IDS_WAVEOUTOPENFAILURE          146
+#define IDS_MUSTENTERNAME               147
+#define IDS_MUSTSELECTCONFIGFORDELETE   148
+#define IDS_DELETECONFIGCONFIRMATION    149
+#define IDI_MISC1                       150
+#define IDS_DELETECONFIGTITLE           150
+#define IDC_MYHAND                      151
+#define IDS_GFXCARDCHECK                151
+#define IDD_DIALOG1                     152
+#define IDS_GFXCARDTITLE                152
+#define IDD_DEBUGGER                    152
+#define IDD_SETINFO                     153
+#define IDS_MUSTSELECTPATH              153
+#define IDI_ICON1                       153
+#define IDS_SETTINGSERROR               154
+#define IDD_CHIPSET                     154
+#define IDS_MUSTSELECTNAME              155
+#define IDI_MOVE_UP                     155
+#define IDS_MUSTSELECTFILE              156
+#define IDI_MOVE_DOWN                   156
+#define IDS_FAILEDHARDFILECREATION      157
+#define IDD_AVIOUTPUT                   157
+#define IDS_CREATIONERROR               158
+#define IDI_AVIOUTPUT                   158
+#define IDS_ERRORTITLE                  159
+#define IDS_SELECTFILESYSROOT           160
+#define IDD_OPENGL                      160
+#define IDS_DEFAULTMIDIOUT              161
+#define IDS_DEFAULTMIDIIN               162
+#define IDS_CONTRIBUTORS1               163
+#define IDD_HARDDRIVE                   163
+#define IDS_CONTRIBUTORS2               164
+#define IDS_INVALIDPRTPORT              165
+#define IDS_SELECTUSS                   166
+#define IDS_RESTOREUSS                  166
+#define IDS_USS                         167
+#define IDS_WRONGOSVERSION              168
+#define IDR_DRIVE_STARTUP_A500_1        168
+#define IDS_SELECTFLASH                 169
+#define IDR_DRIVE_CLICK_A500_1          169
+#define IDS_FLASH                       170
+#define IDR_DRIVE_SPIN_A500_1           170
+#define IDD_INPUT                       171
+#define IDS_INPUTHOSTWIDGET             171
+#define IDI_INPUT                       172
+#define IDS_INPUTAMIGAEVENT             172
+#define IDD_DISK                        172
+#define IDS_INPUTAUTOFIRE               173
+#define IDS_SAVEUSS                     174
+#define IDS_MIDIOVERFLOW                175
+#define IDS_HFDSIZE                     176
+#define IDS_DEVICE                      177
+#define IDS_BOOTPRI                     178
+#define IDS_WRONGDXVERSION              179
+#define IDI_MISC2                       180
+#define IDR_DRIVE_SNATCH_A500_1         181
+#define IDI_DISK                        182
+#define IDR_DRIVE_SPINND_A500_1         182
+#define IDD_PANEL                       183
+#define IDI_CONFIGFILE                  185
+#define IDM_SYSTRAY                     186
+#define IDI_FOLDER                      188
+#define IDI_DISPLAY                     190
+#define IDI_ROOT                        192
+#define IDI_ICON2                       194
+#define IDI_MEMORY                      194
+#define IDS_SOUND_MONO                  200
+#define IDS_SOUND_MIXED                 201
+#define IDS_SOUND_STEREO                202
+#define IDS_SOUND_INTERPOL_DISABLED     203
+#define IDS_SOUND_INTERPOL_RH           204
+#define IDS_SOUND_INTERPOL_CRUX         205
+#define IDS_SOUND_FILTER_OFF            206
+#define IDS_SOUND_FILTER_EMULATED       207
+#define IDS_SOUND_FILTER_ON             208
+#define IDS_INPUT_COMPATIBILITY         209
+#define IDS_INPUT_CUSTOM                210
+#define IDS_INPUT_COPY_DEFAULT          211
+#define IDS_INPUT_COPY_CUSTOM           212
+#define IDS_3D_NO_FILTER                213
+#define IDS_3D_BILINEAR                 214
+#define IDS_VSYNC_DEFAULT               215
+#define IDS_DRIVESOUND_NONE             216
+#define IDS_DRIVESOUND_DEFAULT_A500     217
+#define IDS_AVIOUTPUT_NOCODEC           218
+#define IDS_DISK_IMAGENAME              219
+#define IDS_DISK_DRIVENAME              220
+#define IDS_AGA8BIT                     221
+#define IDS_UNSUPPORTEDSCREENMODE       222
+#define IDS_UNSUPPORTEDSCREENMODE_1     223
+#define IDS_UNSUPPORTEDSCREENMODE_2     224
+#define IDS_UNSUPPORTEDSCREENMODE_3     225
+#define IDS_UNSUPPORTEDSCREENMODE_4     226
+#define IDS_FLOPPYTYPE35DD              227
+#define IDS_FLOPPYTYPE35HD              228
+#define IDS_FLOPPYTYPE525SD             229
+#define IDS_FLOPPYTYPEDISABLED          230
+#define IDS_STMENUNOFLOPPY              231
+#define IDS_TREEVIEW_HARDWARE           232
+#define IDS_TREEVIEW_HOST               233
+#define IDS_TREEVIEW_MISC               234
+#define IDS_TREEVIEW_SETTINGS           235
+#define IDS_WINUAETITLE_MMB             236
+#define IDS_IDS_WINUAETITLE_NORMAL      237
+#define IDS_WINUAETITLE_NORMAL          237
+#define IDC_RESOLUTION                  1021
+#define IDC_SERIAL                      1022
+#define IDC_REFRESHRATE                 1022
+#define IDC_ILLEGAL                     1023
+#define IDC_MIDILIST                    1023
+#define IDC_MIDIOUTLIST                 1023
+#define IDC_DA_MODE                     1023
+#define IDC_SHOWGUI                     1024
+#define IDC_MIDIINLIST                  1024
+#define IDC_RESOLUTION2                 1024
+#define IDC_DISPLAYSELECT               1024
+#define IDC_AUTOCONFIG                  1025
+#define IDC_PRINTERLIST                 1025
+#define IDC_CHIPMEM                     1026
+#define IDC_CREATELOGFILE               1026
+#define IDC_FASTMEM                     1027
+#define IDC_SHOWLEDS                    1027
+#define IDC_SLOWMEM                     1030
+#define IDC_PARALLEL                    1033
+#define IDC_JULIAN                      1040
+#define IDC_FASTTEXT                    1043
+#define IDC_FASTRAM                     1044
+#define IDC_CHIPRAM                     1045
+#define IDC_SLOWRAM                     1046
+#define IDC_Z3TEXT                      1047
+#define IDC_Z3FASTRAM                   1048
+#define IDC_Z3FASTMEM                   1049
+#define IDC_UAEHOME                     1070
+#define IDC_PICASSOHOME                 1071
+#define IDC_AMIGAHOME                   1072
+#define IDC_WINUAEHOME                  1073
+#define IDC_AIABHOME                    1074
+#define IDC_CLOANTOHOME                 1075
+#define IDC_THEROOTS                    1076
+#define IDC_CAPS                        1077
+#define IDC_RICHEDIT1                   1091
+#define IDC_RICHEDIT2                   1092
+#define IDC_CONTRIBUTORS                1124
+#define IDC_ASPECT                      1170
+#define IDC_BLIT32                      1173
+#define IDC_BLITIMM                     1174
+#define IDC_LORES                       1176
+#define IDC_VSYNC                       1177
+#define IDC_AFULLSCREEN                 1178
+#define IDC_FRAMERATE                   1185
+#define IDC_RATETEXT                    1186
+#define IDC_XSIZE                       1187
+#define IDC_YSIZE                       1188
+#define IDC_INPUTAUTOFIRERATE           1188
+#define IDC_LM_NORMAL                   1189
+#define IDC_INPUTSPEEDD                 1189
+#define IDC_LM_DOUBLED                  1190
+#define IDC_INPUTSPEEDA                 1190
+#define IDC_GFXCARDTEXT                 1191
+#define IDC_LM_SCANLINES                1191
+#define IDC_INPUTSPEEDM                 1191
+#define IDC_P96RAM                      1192
+#define IDC_PFULLSCREEN                 1192
+#define IDC_P96MEM                      1193
+#define IDC_DA_SLIDER                   1193
+#define IDC_CPU0                        1200
+#define IDC_CPU1                        1201
+#define IDC_CPU2                        1202
+#define IDC_CPU3                        1203
+#define IDC_CPU4                        1204
+#define IDC_CPU5                        1205
+#define IDC_CPU6                        1206
+#define IDC_SPEED                       1207
+#define IDC_CS_HOST                     1209
+#define IDC_CS_68000                    1210
+#define IDC_CS_ADJUSTABLE               1211
+#define IDC_CS_CPU_TEXT                 1212
+#define IDC_CS_CHIPSET_TEXT             1213
+#define IDC_COMPATIBLE                  1214
+#define IDC_TRUST0                      1215
+#define IDC_TRUST1                      1216
+#define IDC_TRUST2                      1217
+#define IDC_CACHE                       1218
+#define IDC_CYCLEEXACT                  1219
+#define IDC_CS_CPU_TEXT2                1219
+#define IDC_CPUIDLE                     1220
+#define IDC_SOUNDSETTINGS               1229
+#define IDC_8BIT                        1230
+#define IDC_16BIT                       1231
+#define IDC_11KHZ                       1232
+#define IDC_22KHZ                       1233
+#define IDC_44KHZ                       1234
+#define IDC_48KHZ                       1235
+#define IDC_SOUNDSIZE                   1236
+#define IDC_FREQUENCY                   1237
+#define IDC_SOUND0                      1238
+#define IDC_SOUND1                      1239
+#define IDC_SOUND2                      1240
+#define IDC_SOUND3                      1241
+#define IDC_SOUNDSTYLE                  1242
+#define IDC_SOUNDSTYLE0                 1243
+#define IDC_STEREO                      1244
+#define IDC_SOUNDSTYLE1                 1245
+#define IDC_SOUNDINTERPOLATION          1248
+#define IDC_INTERPOLATION0              1249
+#define IDC_INTERPOLATION1              1250
+#define IDC_INTERPOLATION2              1251
+#define IDC_STEREOMODE                  1252
+#define IDC_SOUNDINTERPOLATION2         1252
+#define IDC_STEREOMODE0                 1253
+#define IDC_STEREOMODE1                 1254
+#define IDC_STEREOMODE2                 1255
+#define IDC_SOUNDINTERPOLATION3         1256
+#define IDC_DF0TEXT                     1270
+#define IDC_DF1TEXT                     1271
+#define IDC_DF2TEXT                     1272
+#define IDC_DF3TEXT                     1273
+#define IDC_EJECT0                      1274
+#define IDC_EJECT1                      1275
+#define IDC_EJECT2                      1276
+#define IDC_EJECT3                      1277
+#define IDC_DF0                         1278
+#define IDC_DF1                         1279
+#define IDC_DF2                         1280
+#define IDC_DF3                         1281
+#define IDC_CREATE                      1282
+#define IDC_CREATE_RAW                  1283
+#define IDC_SNAPSHOTNAME                1284
+#define IDC_SNAPSHOT                    1285
+#define IDC_DOSAVESTATE                 1286
+#define IDC_DOLOADSTATE                 1287
+#define IDC_PORT0_JOY0                  1300
+#define IDC_PORT0_JOY1                  1301
+#define IDC_PORT0_MOUSE                 1302
+#define IDC_PORT0_KBDA                  1303
+#define IDC_PORT0_KBDB                  1304
+#define IDC_PORT0_KBDC                  1305
+#define IDC_PORT1_JOY0                  1306
+#define IDC_PORT1_JOY1                  1307
+#define IDC_PORT1_MOUSE                 1308
+#define IDC_PORT1_KBDA                  1309
+#define IDC_PORT1_KBDB                  1310
+#define IDC_PORT1_KBDC                  1311
+#define IDC_PORT0                       1312
+#define IDC_PORT1                       1313
+#define IDC_MIDIFRAME                   1314
+#define IDC_SERPARFRAME                 1315
+#define IDC_EDIT                        1334
+#define IDC_REMOVE                      1335
+#define IDC_VOLUMELIST                  1336
+#define IDC_UP                          1337
+#define IDC_DOWN                        1338
+#define IDC_NEW_FS                      1339
+#define IDC_NEW_HF                      1340
+#define IDC_NEW_HD                      1341
+#define IDC_PATH_NAME                   1362
+#define IDC_SELECTOR                    1363
+#define IDC_VOLUME_NAME                 1364
+#define IDC_HARDFILE_DEVICE             1364
+#define IDC_SECTORS                     1365
+#define IDC_VOLUME_DEVICE               1365
+#define IDC_HEADS                       1366
+#define IDC_RESERVED                    1367
+#define IDC_BLOCKSIZE                   1368
+#define IDC_HARDFILE_BOOTPRI            1369
+#define IDC_SECTORS_TEXT                1370
+#define IDC_SURFACES_TEXT               1371
+#define IDC_RESERVED_TEXT               1372
+#define IDC_RESERVED_TEXT2              1373
+#define IDC_BLOCKSIZE_TEXT              1374
+#define ID_OK                           1375
+#define IDC_HARDFILE_BOOTPRI_TEXT       1375
+#define IDC_PATH_FILESYS                1376
+#define IDC_HARDFILE_DIR_TEXT           1377
+#define IDC_HARDFILE_DEVICE_TEXT        1378
+#define IDC_RW                          1379
+#define IDC_HFRDB                       1380
+#define IDC_RW2                         1380
+#define IDC_RDB                         1380
+#define IDC_HARDFILE_FILESYS_TEXT       1380
+#define IDC_FILESYS_SELECTOR            1381
+#define IDC_ROMFILE                     1390
+#define IDC_KEYFILE                     1391
+#define IDC_KICKCHOOSER                 1392
+#define IDC_KEYCHOOSER                  1393
+#define IDC_ROMFILE2                    1394
+#define IDC_ROMCHOOSER2                 1395
+#define IDC_FLASHCHOOSER                1396
+#define IDC_FLASHFILE                   1397
+#define IDC_CARTFILE                    1398
+#define IDC_CARTCHOOSER                 1399
+#define IDC_SAVE                        1400
+#define IDC_LOAD                        1401
+#define IDC_DELETE                      1403
+#define IDC_CONFIGLIST                  1404
+#define IDC_EDITNAME                    1405
+#define IDC_EDITDESCRIPTION             1406
+#define IDC_QUICKSAVE                   1408
+#define IDC_QUICKLOAD                   1409
+#define IDC_EXIT                        1410
+#define IDC_EDITPATH                    1410
+#define IDC_CREATEHF                    1500
+#define IDC_HFSIZE                      1501
+#define IDC_LINEMODE                    1502
+#define IDC_SOCKETS                     1503
+#define IDC_RESETAMIGA                  1504
+#define IDC_QUITEMU                     1505
+#define IDC_TEST16BIT                   1506
+#define IDC_MAPDRIVES                   1507
+#define IDC_CPUTEXT                     1508
+#define IDC_SWAP                        1509
+#define IDC_CACHETEXT                   1509
+#define IDC_SELECTRESTEXT               1510
+#define IDC_SCREENRESTEXT               1511
+#define IDC_WIDTHTEXT                   1512
+#define IDC_WINDOWEDTEXT                1512
+#define IDC_HEIGHTTEXT                  1513
+#define IDC_SETTINGSTEXT                1514
+#define IDC_REFRESHTEXT                 1515
+#define IDC_SETTINGSTEXT2               1515
+#define IDC_DISABLE1                    1516
+#define IDC_DF1WP                       1516
+#define IDC_DISABLE2                    1517
+#define IDC_DF2WP                       1517
+#define IDC_DISABLE3                    1518
+#define IDC_XCENTER                     1518
+#define IDC_DF3WP                       1518
+#define IDC_YCENTER                     1519
+#define IDC_DISABLE0                    1519
+#define IDC_DF0WP                       1519
+#define IDC_OCS                         1520
+#define IDC_HDFLOPPY                    1520
+#define IDC_ECS_AGNUS                   1521
+#define IDC_ECS_DENISE                  1522
+#define IDC_ECS                         1523
+#define IDC_AGA                         1524
+#define IDC_NTSC                        1525
+#define IDC_NOSPEED                     1527
+#define IDC_NOSOUND                     1528
+#define IDC_INACTIVE_NOSOUND            1528
+#define IDC_MIDI                        1529
+#define IDC_NOSPEEDPAUSE                1529
+#define IDC_INACTIVE_PAUSE              1529
+#define IDC_KICKSHIFTER                 1530
+#define IDC_MIDI2                       1530
+#define IDC_HIGHPRIORITY                1530
+#define IDC_MINIMIZED_NOSOUND           1530
+#define IDC_MINIMIZED_PAUSE             1531
+#define IDC_D0                          1532
+#define IDC_STATE_CAPTURE               1532
+#define IDC_D1                          1533
+#define IDC_D2                          1534
+#define IDC_D3                          1535
+#define IDC_D4                          1536
+#define IDC_D5                          1537
+#define IDC_D6                          1538
+#define IDC_D7                          1539
+#define IDC_A0                          1540
+#define IDC_A1                          1541
+#define IDC_A2                          1542
+#define IDC_A3                          1543
+#define IDC_A4                          1544
+#define IDC_A5                          1545
+#define IDC_A6                          1546
+#define IDC_A7                          1547
+#define IDC_USP                         1548
+#define IDC_SSP                         1549
+#define IDC_PC                          1550
+#define IDC_T1                          1551
+#define IDC_T2                          1552
+#define IDC_T3                          1553
+#define IDC_SHARED                      1553
+#define IDC_T4                          1554
+#define IDC_SER_CTSRTS                  1554
+#define IDC_T5                          1555
+#define IDC_SERIAL_DIRECT               1555
+#define IDC_T6                          1556
+#define IDC_T7                          1557
+#define IDC_T8                          1558
+#define IDC_T9                          1559
+#define IDC_T10                         1560
+#define IDC_T11                         1561
+#define IDC_T12                         1562
+#define IDC_T13                         1563
+#define IDC_T14                         1564
+#define IDC_T15                         1565
+#define IDC_T16                         1566
+#define IDC_VIEWINFO                    1568
+#define IDC_SETINFO                     1569
+#define IDC_FLOPPYSLIDER                1570
+#define IDC_FLOPPYSLIDERTEXT            1571
+#define IDC_FLOPPYSPEED                 1572
+#define IDC_FLOPPYSPD                   1572
+#define IDC_GUILANGUAGE_LIST            1573
+#define IDC_SOUNDBUFFERRAM              1574
+#define IDC_SOUNDADJUST                 1575
+#define IDC_SOUNDBUFFERTEXT             1576
+#define IDC_SOUNDVOLUME                 1576
+#define IDC_SOUNDBUFFERMEM              1577
+#define IDC_HARDFLUSH                   1578
+#define IDC_SOUNDADJUSTNUM              1578
+#define IDC_CONSTJUMP                   1579
+#define IDC_SOUNDDRIVEVOLUME            1579
+#define IDC_JITFPU                      1580
+#define IDC_NOFLAGS                     1581
+#define IDC_CS_CACHE_TEXT               1582
+#define IDC_FORCE                       1583
+#define IDC_COLLISIONS                  1584
+#define IDC_DISASSEMBLY                 1585
+#define IDC_CTRLF11                     1586
+#define IDC_FASTCOPPER                  1588
+#define IDC_COLLISION0                  1589
+#define IDC_COLLISION1                  1590
+#define IDC_AUDIOSYNC                   1590
+#define IDC_COLLISION2                  1591
+#define IDC_COLLISION3                  1592
+#define IDC_SOUNDLAGSLIDER              1592
+#define IDC_SOUNDLAGCAPTION             1594
+#define IDC_FLOPPYTYPE                  1594
+#define IDC_SYNCPARAMS                  1595
+#define IDC_DF0TYPE                     1595
+#define IDC_SOUNDLAGTEXT                1596
+#define IDC_DF1TYPE                     1596
+#define IDC_DF2TYPE                     1597
+#define IDC_SOUNDSPEEDSLIDER            1598
+#define IDC_DF0TYPE4                    1598
+#define IDC_DF3TYPE                     1598
+#define IDC_SOUNDSPEEDTEXT              1599
+#define IDC_SOUNDSPEEDCAPTION           1600
+#define IDC_NOOVERLAY                   1601
+#define IDC_ROMFILE2TEXT                1602
+#define IDC_ROMTEXT                     1603
+#define IDC_KEYTEXT                     1604
+#define IDC_CD32                        1605
+#define IDC_AKIKOC2P                    1605
+#define IDC_FLASHTEXT                   1605
+#define IDC_SCSIDEVICE                  1606
+#define IDC_FLASHTEXT2                  1606
+#define IDC_AVIOUTPUT_PAL               1607
+#define IDC_ASPI                        1607
+#define IDC_INPUTTYPE                   1607
+#define IDC_AVIOUTPUT_NTSC              1608
+#define IDC_INPUTSELECTTEXT             1608
+#define IDC_KILLWINKEYS                 1608
+#define IDC_SCSIDEVICE2                 1608
+#define IDC_CLOCKSYNC                   1608
+#define IDC_NOUAEFSDB                   1608
+#define IDC_AVIOUTPUT_FPS               1609
+#define IDC_INPUTDEVICE                 1609
+#define IDC_MAPROM                      1609
+#define IDC_AVIOUTPUT_FILETEXT          1610
+#define IDC_INPUTDEVICETEXT             1610
+#define IDC_AVIOUTPUT_FILE              1611
+#define IDC_INPUTLIST                   1611
+#define IDC_AVIOUTPUT_FPS_STATIC        1612
+#define IDC_INPUTAMIGA                  1612
+#define IDC_AVIOUTPUT_VIDEO             1613
+#define IDC_INPUTAUTOFIRE               1613
+#define IDC_AVIOUTPUT_AUDIO             1614
+#define IDC_INPUTCOPYFROM               1614
+#define IDC_AVIOUTPUT_VIDEO_CODEC       1615
+#define IDC_OPENGLENABLE                1615
+#define IDC_INPUTDEVICEDISABLE          1615
+#define IDC_AVIOUTPUT_ACTIVATED         1615
+#define IDC_AVIOUTPUT_AUDIO_CODEC       1616
+#define IDC_OPENGLHZ                    1616
+#define IDC_INPUTAMIGACNT               1616
+#define IDC_AVIOUTPUT_BORDER_TRIM       1617
+#define IDC_OPENGLVZ                    1617
+#define IDC_AVIOUTPUT_AUDIO_STATIC      1618
+#define IDC_OPENGLHO                    1618
+#define IDC_AVIOUTPUT_VIDEO_STATIC      1619
+#define IDC_OPENGLVO                    1619
+#define IDC_AVIOUTPUT_8BIT              1620
+#define IDC_OPENGLHZV                   1620
+#define IDC_AVIOUTPUT_24BIT             1621
+#define IDC_OPENGLVZV                   1621
+#define IDC_AVIOUTPUT_WIDTH             1622
+#define IDC_OPENGLHOV                   1622
+#define IDC_AVIOUTPUT_HEIGHT            1623
+#define IDC_OPENGLVOV                   1623
+#define IDC_AVIOUTPUT_FRAME             1624
+#define IDC_OPENGLSL                    1624
+#define IDC_OPENGLSLR                   1625
+#define IDC_OPENGLSLV                   1626
+#define IDC_OPENGLBITS                  1627
+#define IDC_OPENGLMODE                  1627
+#define IDC_OPENGLFILTER                1628
+#define IDC_OPENGLDEFAULT               1629
+#define IDC_INPUTDEADZONE               1630
+#define IDC_OPENGLSL2                   1630
+#define IDC_INPUTCOPY                   1631
+#define IDC_OPENGLSL2V                  1631
+#define IDC_SCREENSHOT                  1632
+#define IDC_INPUTSWAP                   1632
+#define IDC_FLOPPYSPDTEXT               1633
+#define IDC_FLOPPYSPD_TEXT              1634
+#define IDC_KAILLERA                    1635
+#define IDC_HARDDRIVE                   1635
+#define IDC_INACTIVE_PRI                1635
+#define IDC_KAILLERA_CHAT               1636
+#define IDC_SOUNDPRIMARY                1636
+#define IDC_MINIMIZED_PRI               1636
+#define IDC_KAILLERA_CHAT_TEXT          1637
+#define IDC_VOLUME_BOOTPRI_TEXT         1637
+#define IDC_KAILLERA_CHAT_SEND          1638
+#define IDC_VOLUME_BOOTPRI              1638
+#define IDC_KAILLERA_LIST               1639
+#define IDC_KBLED1                      1639
+#define IDC_KAILLERAFELLOW              1640
+#define IDC_KBLED2                      1640
+#define IDC_SOUNDFILTER                 1640
+#define IDC_KAILLERAJOY                 1641
+#define IDC_KBLED3                      1641
+#define IDC_SOUNDCALIBRATE              1641
+#define IDC_KAILLERAJOYKEYBOARD         1642
+#define IDC_ACTIVEPRIORITY              1642
+#define IDC_ACTIVE_PRIORITY             1642
+#define IDC_SOUNDDRIVE                  1642
+#define IDC_KAILLERAOPTIONS             1643
+#define IDC_INACTIVE_PRIORITY           1643
+#define IDC_KAILLERASUPPRESSWARNINGS    1644
+#define IDC_ACTIVE_PRI                  1644
+#define IDC_KAILLERANONE                1645
+#define IDC_MINIMIZED_PRIORITY          1645
+#define IDC_AVIOUTPUT_FRAMELIMITER      1645
+#define IDC_KAILLERACONTROLS            1646
+#define IDC_STATE_RATE                  1646
+#define IDC_KAILLERANOFPSLIMIT          1647
+#define IDC_STATE_BUFFERSIZE            1647
+#define IDC_SOUNDDRIVESELECT            1647
+#define IDC_PANELTREE                   1647
+#define IDC_AVIOUTPUT_DIMENSIONS_STATIC 1648
+#define IDC_STATE_BUFFERSIZE_TEXT       1648
+#define IDC_CONFIGTREE                  1648
+#define IDC_AVIOUTPUT_OPTIONS           1649
+#define IDC_STATE_RATE_TEXT             1649
+#define IDC_DISKLISTREMOVE              1649
+#define IDC_SOUNDCARD                   1650
+#define IDC_CS_SOUND0                   1650
+#define IDC_SOUNDCARDLIST               1651
+#define IDC_CS_SOUND1                   1651
+#define IDC_SOUNDFREQ                   1652
+#define IDC_CS_SOUND2                   1652
+#define IDC_SOUNDCARD2                  1653
+#define IDC_SOUNDFREQTXT                1653
+#define IDC_PANEL_FRAME                 1653
+#define IDC_SOUNDFILTERTXT              1654
+#define IDC_PANEL_FRAME_OUTER           1654
+#define IDC_SOUNDSTEREO                 1655
+#define IDC_CONFIGTYPE                  1655
+#define IDC_SOUNDDRIVETXT               1656
+#define IDC_SOUNDSTEREOTXT              1657
+#define IDC_SOUNDINTERPOLATIONTXT       1658
+#define IDC_DISK                        1659
+#define IDC_DISKLIST                    1659
+#define ID__FLOPPYDRIVES                40004
+#define ID_FLOPPYDRIVES_DF0             40005
+#define ID_ST_CONFIGURATION             40010
+#define ID_ST_HELP                      40011
+#define ID_ST_QUIT                      40012
+#define ID_ST_EJECTALL                  40013
+#define ID_ST_DF0                       40014
+#define ID_ST_DF1                       40015
+#define ID_ST_DF2                       40016
+#define ID_ST_DF3                       40017
+#define ID_ST_RESET                     40019
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC                     1
+#define _APS_3D_CONTROLS                     1
+#define _APS_NEXT_RESOURCE_VALUE        196
+#define _APS_NEXT_COMMAND_VALUE         40020
+#define _APS_NEXT_CONTROL_VALUE         1656
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
diff --git a/od-win32/resources/resource.hm b/od-win32/resources/resource.hm
new file mode 100755 (executable)
index 0000000..d62039d
--- /dev/null
@@ -0,0 +1,11 @@
+// Microsoft Visual C++ generated Help ID include file.
+// Used by winuae.rc
+//
+#define HIDC_CREATELOGFILE              0x808d0402    // IDD_MISC1 [English (U.S.)]
+#define HIDC_EDITDESCRIPTION            0x8087057e    // IDD_LOADSAVE [English (U.S.)]
+#define HIDC_EDITNAME                   0x8087057d    // IDD_LOADSAVE [English (U.S.)]
+#define HIDC_EDITPATH                   0x80870582    // IDD_LOADSAVE [English (U.S.)]
+#define HIDC_LORES                      0x806c0498    // IDD_DISPLAY [English (U.S.)]
+#define HIDC_MAPDRIVES                  0x807105e3    // IDD_HARDDISK [English (U.S.)]
+#define HIDC_PFULLSCREEN                0x806c04a8    // IDD_DISPLAY [English (U.S.)]
+#define HIDC_TEST16BIT                  0x806c05e2    // IDD_DISPLAY [English (U.S.)]
diff --git a/od-win32/resources/root.ico b/od-win32/resources/root.ico
new file mode 100755 (executable)
index 0000000..50707e1
Binary files /dev/null and b/od-win32/resources/root.ico differ
diff --git a/od-win32/resources/screen.ico b/od-win32/resources/screen.ico
new file mode 100755 (executable)
index 0000000..ce897d6
Binary files /dev/null and b/od-win32/resources/screen.ico differ
diff --git a/od-win32/resources/sound.ico b/od-win32/resources/sound.ico
new file mode 100755 (executable)
index 0000000..c77c98d
Binary files /dev/null and b/od-win32/resources/sound.ico differ
diff --git a/od-win32/resources/winuae.exe.manifest b/od-win32/resources/winuae.exe.manifest
new file mode 100755 (executable)
index 0000000..dbd8012
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" 
+    manifestVersion="1.0">
+<assemblyIdentity
+    version="1.0.0.0"
+    processorArchitecture="x86"
+    name="WinUAE"
+        type="win32"
+        />
+<description></description>
+<dependency>
+   <dependentAssembly>
+     <assemblyIdentity type="win32"
+          name="Microsoft.Windows.Common-Controls"
+          version="6.0.0.0"
+          processorArchitecture="X86"
+          publicKeyToken="6595b64144ccf1df"
+          language="*"
+      />
+   </dependentAssembly>
+</dependency>
+</assembly>
\ No newline at end of file
diff --git a/od-win32/resources/winuae.ico b/od-win32/resources/winuae.ico
new file mode 100755 (executable)
index 0000000..ea35d3b
Binary files /dev/null and b/od-win32/resources/winuae.ico differ
diff --git a/od-win32/resources/winuae.rc b/od-win32/resources/winuae.rc
new file mode 100755 (executable)
index 0000000..4da9f16
--- /dev/null
@@ -0,0 +1,1253 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+// Generated Help ID header file
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "resource.hm"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+#include "dlgs.h"
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_KICKSTART DIALOGEX 0, 0, 300, 175
+STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD
+EXSTYLE WS_EX_CONTEXTHELP
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    GROUPBOX        "Boot-ROM Settings:",-1,5,12,290,90
+    RTEXT           "ROM File:",IDC_ROMTEXT,10,27,75,10
+    EDITTEXT        IDC_ROMFILE,90,22,185,15,ES_AUTOHSCROLL
+    PUSHBUTTON      "...",IDC_KICKCHOOSER,280,22,10,15
+    RTEXT           "Key File:",IDC_KEYTEXT,10,48,75,10
+    EDITTEXT        IDC_KEYFILE,90,43,185,15,ES_AUTOHSCROLL
+    PUSHBUTTON      "...",IDC_KEYCHOOSER,280,43,10,15
+    RTEXT           "Extended ROM File:",IDC_ROMFILE2TEXT,10,68,75,10
+    EDITTEXT        IDC_ROMFILE2,90,63,185,15,ES_AUTOHSCROLL
+    PUSHBUTTON      "...",IDC_ROMCHOOSER2,280,63,10,15
+    CONTROL         "MAPROM emulation",IDC_MAPROM,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,104,86,80,10
+    CONTROL         "ShapeShifter support",IDC_KICKSHIFTER,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,196,86,80,10
+    GROUPBOX        "Misc settings:",-1,5,105,290,59
+    RTEXT           "Flash RAM File:",IDC_FLASHTEXT,8,119,75,10
+    EDITTEXT        IDC_FLASHFILE,89,117,185,15,ES_AUTOHSCROLL
+    PUSHBUTTON      "...",IDC_FLASHCHOOSER,279,117,10,15
+    RTEXT           "Cartridge ROM File:",IDC_FLASHTEXT2,8,140,75,10
+    EDITTEXT        IDC_CARTFILE,89,137,185,15,ES_AUTOHSCROLL
+    PUSHBUTTON      "...",IDC_CARTCHOOSER,279,137,10,15
+END
+
+IDD_DISPLAY DIALOGEX 0, 0, 300, 194
+STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    GROUPBOX        "Screen",IDC_SCREENRESTEXT,12,0,199,67,BS_LEFT
+    RTEXT           "Fullscreen",IDC_SELECTRESTEXT,22,17,34,15,
+                    SS_CENTERIMAGE
+    COMBOBOX        IDC_DISPLAYSELECT,61,10,143,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+    COMBOBOX        IDC_RESOLUTION,61,27,77,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+    COMBOBOX        IDC_REFRESHRATE,143,27,61,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+    RTEXT           "Windowed",IDC_WINDOWEDTEXT,22,51,35,8
+    EDITTEXT        IDC_XSIZE,61,48,35,12,ES_NUMBER
+    EDITTEXT        IDC_YSIZE,103,48,35,12,ES_NUMBER
+    CONTROL         "VSync",IDC_VSYNC,"Button",BS_AUTOCHECKBOX | BS_LEFT | 
+                    WS_TABSTOP,145,49,54,10
+    GROUPBOX        "Settings",IDC_SETTINGSTEXT,12,77,199,73
+    CONTROL         "Full Screen",IDC_AFULLSCREEN,"Button",BS_AUTOCHECKBOX | 
+                    BS_LEFT | WS_TABSTOP,35,89,90,10
+    CONTROL         "Correct aspect ratio",IDC_ASPECT,"Button",
+                    BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,35,106,90,10
+    CONTROL         "Full Screen RTG",IDC_PFULLSCREEN,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,131,89,70,10,0,
+                    HIDC_PFULLSCREEN
+    CONTROL         "Lo-res",IDC_LORES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+                    131,106,70,10,0,HIDC_LORES
+    LTEXT           "Refresh:",IDC_REFRESHTEXT,34,129,28,8
+    CONTROL         "Slider1",IDC_FRAMERATE,"msctls_trackbar32",
+                    TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,64,124,75,20
+    CTEXT           "",IDC_RATETEXT,144,124,50,20,SS_SUNKEN | WS_BORDER
+    GROUPBOX        "Centering",IDC_STATIC,221,0,61,67
+    CONTROL         "Horizontal",IDC_XCENTER,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,229,16,45,10
+    CONTROL         "Vertical",IDC_YCENTER,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,229,32,39,10
+    GROUPBOX        "Line mode",IDC_LINEMODE,222,77,61,74
+    CONTROL         "Normal",IDC_LM_NORMAL,"Button",BS_AUTORADIOBUTTON | 
+                    BS_LEFT | WS_GROUP | WS_TABSTOP,233,89,38,10
+    CONTROL         "Doubled",IDC_LM_DOUBLED,"Button",BS_AUTORADIOBUTTON | 
+                    BS_LEFT | WS_TABSTOP,233,105,41,10
+    CONTROL         "Scanline",IDC_LM_SCANLINES,"Button",BS_AUTORADIOBUTTON | 
+                    BS_LEFT | WS_TABSTOP,233,121,40,10
+    COMBOBOX        IDC_DA_MODE,35,163,58,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | NOT WS_VISIBLE | WS_VSCROLL | 
+                    WS_TABSTOP
+    CONTROL         "",IDC_DA_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | NOT WS_VISIBLE | WS_TABSTOP,97,159,101,20
+    PUSHBUTTON      "Detect pixel format",IDC_TEST16BIT,221,163,67,14,0,0,
+                    HIDC_TEST16BIT
+END
+
+IDD_MEMORY DIALOGEX 0, 0, 300, 175
+STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD
+EXSTYLE WS_EX_CONTEXTHELP
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    GROUPBOX        "Memory Settings:",-1,14,40,274,93
+    RTEXT           "Chip:",-1,24,60,20,10,SS_CENTERIMAGE
+    CONTROL         "Slider1",IDC_CHIPMEM,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,54,55,50,20
+    CTEXT           "",IDC_CHIPRAM,104,55,35,20,SS_CENTERIMAGE | SS_SUNKEN | 
+                    WS_BORDER
+    RTEXT           "Fast:",IDC_FASTTEXT,24,85,20,10,SS_CENTERIMAGE
+    CONTROL         "Slider1",IDC_FASTMEM,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,54,80,50,20
+    CTEXT           "",IDC_FASTRAM,104,80,35,20,SS_CENTERIMAGE | SS_SUNKEN | 
+                    WS_BORDER
+    RTEXT           "Slow:",-1,149,60,20,10,SS_CENTERIMAGE
+    CONTROL         "Slider1",IDC_SLOWMEM,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,179,55,50,20
+    CTEXT           "",IDC_SLOWRAM,239,55,35,20,SS_CENTERIMAGE | SS_SUNKEN | 
+                    WS_BORDER
+    RTEXT           "Z3-Fast:",IDC_Z3TEXT,139,85,30,10,SS_CENTERIMAGE
+    CONTROL         "Slider1",IDC_Z3FASTMEM,"msctls_trackbar32",
+                    TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,179,80,60,20
+    CTEXT           "",IDC_Z3FASTRAM,239,80,35,20,SS_CENTERIMAGE | SS_SUNKEN | 
+                    WS_BORDER
+    RTEXT           "RTG (graphics card):",IDC_GFXCARDTEXT,96,110,76,10,
+                    SS_CENTERIMAGE
+    CONTROL         "Slider1",IDC_P96MEM,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,179,105,60,20
+    CTEXT           "",IDC_P96RAM,239,105,35,20,SS_CENTERIMAGE | SS_SUNKEN | 
+                    WS_BORDER
+END
+
+IDD_CPU DIALOGEX 0, 0, 300, 175
+STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD
+FONT 8, "MS Sans Serif", 0, 0, 0x0
+BEGIN
+    GROUPBOX        "CPU Type:",IDC_STATIC,5,5,80,134,BS_LEFT
+    CONTROL         "68000",IDC_CPU0,"Button",BS_AUTORADIOBUTTON | WS_GROUP | 
+                    WS_TABSTOP,10,18,34,10
+    CONTROL         "68010",IDC_CPU1,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,10,33,34,10
+    CONTROL         "68EC020",IDC_CPU2,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,10,48,45,10
+    CONTROL         "68EC020+FPU",IDC_CPU3,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,10,63,63,10
+    CONTROL         "68020",IDC_CPU4,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,10,78,34,10
+    CONTROL         "68020+FPU",IDC_CPU5,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,10,93,54,10
+    CONTROL         "68040",IDC_CPU6,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,10,108,36,10
+    CONTROL         "More compatible",IDC_COMPATIBLE,"Button",
+                    BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,10,123,
+                    70,10
+    GROUPBOX        "CPU Emulation Speed:",IDC_STATIC,90,5,205,86
+    CONTROL         "Fastest possible, but maintain chipset timing",
+                    IDC_CS_HOST,"Button",BS_AUTORADIOBUTTON | BS_LEFT | 
+                    WS_GROUP | WS_TABSTOP,95,18,195,10
+    CONTROL         "Match A500 speed",IDC_CS_68000,"Button",
+                    BS_AUTORADIOBUTTON | BS_LEFT | WS_TABSTOP,95,32,195,10
+    CONTROL         "Adjustable between CPU and chipset",IDC_CS_ADJUSTABLE,
+                    "Button",BS_AUTORADIOBUTTON | BS_LEFT | WS_TABSTOP,95,47,
+                    195,10
+    RTEXT           "CPU",IDC_CS_CPU_TEXT,96,71,15,10,SS_CENTERIMAGE | 
+                    WS_TABSTOP
+    CONTROL         "Slider1",IDC_SPEED,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,114,66,67,20
+    LTEXT           "Chipset",IDC_CS_CHIPSET_TEXT,182,71,25,10,
+                    SS_CENTERIMAGE | NOT WS_GROUP | WS_TABSTOP
+    RTEXT           "CPU Idle",IDC_CS_CPU_TEXT2,236,56,32,10,SS_CENTERIMAGE | 
+                    WS_TABSTOP
+    CONTROL         "",IDC_CPUIDLE,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,219,66,69,20
+    GROUPBOX        "JIT Settings:",IDC_STATIC,90,94,205,76
+    RTEXT           "Cache Size:",IDC_CS_CACHE_TEXT,95,109,45,10,
+                    SS_CENTERIMAGE | WS_TABSTOP
+    CONTROL         "Slider1",IDC_CACHE,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,140,104,115,20
+    EDITTEXT        IDC_CACHETEXT,255,109,30,12,ES_CENTER | ES_READONLY
+    CONTROL         "Hard Flush",IDC_HARDFLUSH,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,100,127,60,10
+    CONTROL         "Const Jump",IDC_CONSTJUMP,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,100,141,60,10
+    CONTROL         "FPU Support",IDC_JITFPU,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,100,154,60,10
+    CONTROL         "Force Settings",IDC_FORCE,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,165,127,61,10
+    CONTROL         "No Flags",IDC_NOFLAGS,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,165,141,60,10
+    CONTROL         "Direct",IDC_TRUST0,"Button",BS_AUTORADIOBUTTON | 
+                    WS_GROUP | WS_TABSTOP,230,127,34,10
+    CONTROL         "Indirect",IDC_TRUST1,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,230,141,45,10
+    CONTROL         "After Picasso96",IDC_TRUST2,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,230,154,64,10
+END
+
+IDD_FLOPPY DIALOGEX 0, 0, 300, 230
+STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD
+FONT 8, "MS Sans Serif", 0, 0, 0x0
+BEGIN
+    RTEXT           "DF0:",IDC_STATIC,16,6,20,10,SS_CENTERIMAGE
+    COMBOBOX        IDC_DF0TEXT,2,22,296,75,CBS_DROPDOWN | CBS_AUTOHSCROLL | 
+                    WS_VSCROLL | WS_TABSTOP
+    COMBOBOX        IDC_DF0TYPE,54,5,41,50,CBS_DROPDOWNLIST | WS_VSCROLL | 
+                    WS_TABSTOP
+    RTEXT           "Write Protected",IDC_STATIC,174,8,59,10,SS_CENTERIMAGE
+    CONTROL         "",IDC_DF0WP,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | 
+                    WS_TABSTOP,238,4,10,15
+    PUSHBUTTON      "Eject",IDC_EJECT0,253,4,30,15
+    PUSHBUTTON      "...",IDC_DF0,287,4,10,15
+    RTEXT           "DF1:",IDC_STATIC,16,41,20,10,SS_CENTERIMAGE
+    COMBOBOX        IDC_DF1TEXT,2,58,296,75,CBS_DROPDOWN | CBS_AUTOHSCROLL | 
+                    WS_VSCROLL | WS_TABSTOP
+    COMBOBOX        IDC_DF1TYPE,54,40,41,50,CBS_DROPDOWNLIST | WS_VSCROLL | 
+                    WS_TABSTOP
+    RTEXT           "Write Protected",IDC_STATIC,174,42,59,10,SS_CENTERIMAGE
+    CONTROL         "",IDC_DF1WP,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | 
+                    WS_TABSTOP,238,39,10,15
+    PUSHBUTTON      "Eject",IDC_EJECT1,253,39,30,15
+    PUSHBUTTON      "...",IDC_DF1,287,39,10,15
+    RTEXT           "DF2:",IDC_STATIC,16,77,20,10,SS_CENTERIMAGE
+    COMBOBOX        IDC_DF2TEXT,2,93,296,75,CBS_DROPDOWN | CBS_AUTOHSCROLL | 
+                    WS_VSCROLL | WS_TABSTOP
+    COMBOBOX        IDC_DF2TYPE,54,76,41,50,CBS_DROPDOWNLIST | WS_VSCROLL | 
+                    WS_TABSTOP
+    RTEXT           "Write Protected",IDC_STATIC,174,77,59,10,SS_CENTERIMAGE
+    CONTROL         "",IDC_DF2WP,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | 
+                    WS_TABSTOP,238,75,9,15
+    PUSHBUTTON      "Eject",IDC_EJECT2,253,75,30,15
+    PUSHBUTTON      "...",IDC_DF2,287,75,10,15
+    RTEXT           "DF3:",IDC_STATIC,16,113,20,9,SS_CENTERIMAGE
+    COMBOBOX        IDC_DF3TEXT,2,130,296,75,CBS_DROPDOWN | CBS_AUTOHSCROLL | 
+                    WS_VSCROLL | WS_TABSTOP
+    COMBOBOX        IDC_DF3TYPE,54,112,41,50,CBS_DROPDOWNLIST | WS_VSCROLL | 
+                    WS_TABSTOP
+    RTEXT           "Write Protected",IDC_STATIC,174,113,59,10,
+                    SS_CENTERIMAGE
+    CONTROL         "",IDC_DF3WP,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | 
+                    WS_TABSTOP,238,111,9,15
+    PUSHBUTTON      "Eject",IDC_EJECT3,253,111,30,15
+    PUSHBUTTON      "...",IDC_DF3,287,111,10,15
+    GROUPBOX        "New disk image",IDC_SETTINGSTEXT,5,152,289,35
+    COMBOBOX        IDC_FLOPPYTYPE,16,165,51,50,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    PUSHBUTTON      "Create Standard ""Floppy""",IDC_CREATE,76,165,97,15
+    PUSHBUTTON      "Create Custom ""Floppy""",IDC_CREATE_RAW,183,165,101,15
+    GROUPBOX        "Floppy drive emulation speed",IDC_SETTINGSTEXT2,5,188,
+                    289,35
+    CONTROL         "",IDC_FLOPPYSPD,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,32,198,116,20
+    EDITTEXT        IDC_FLOPPYSPDTEXT,169,201,107,12,ES_CENTER | ES_READONLY
+END
+
+IDD_HARDDISK DIALOGEX 0, 0, 300, 242
+STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD
+EXSTYLE WS_EX_CONTEXTHELP
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    CONTROL         "List1",IDC_VOLUMELIST,"SysListView32",LVS_REPORT | 
+                    LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | 
+                    LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,5,260,191
+    PUSHBUTTON      "",IDC_UP,270,52,25,15,BS_ICON
+    PUSHBUTTON      "",IDC_DOWN,270,132,25,15,BS_ICON
+    PUSHBUTTON      "Add &Directory...",IDC_NEW_FS,5,202,60,15
+    PUSHBUTTON      "Add &Hardfile...",IDC_NEW_HF,70,202,60,15
+    PUSHBUTTON      "Add Ha&rddrive",IDC_NEW_HD,135,202,60,15
+    CONTROL         "Add PC Drives at Startup",IDC_MAPDRIVES,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,5,222,105,10,0,
+                    HIDC_MAPDRIVES
+    PUSHBUTTON      "Remove",IDC_REMOVE,135,220,60,15
+    PUSHBUTTON      "&Properties",IDC_EDIT,200,220,60,15
+END
+
+IDD_SOUND DIALOGEX 0, 0, 300, 208
+STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    RTEXT           "Sound device:",IDC_SOUNDCARD,8,9,51,13,SS_CENTERIMAGE
+    COMBOBOX        IDC_SOUNDCARDLIST,64,9,229,50,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    GROUPBOX        "Sound Emulation",IDC_SOUNDSETTINGS,7,30,120,68
+    CONTROL         "Disabled",IDC_SOUND0,"Button",BS_AUTORADIOBUTTON | 
+                    WS_GROUP | WS_TABSTOP,15,45,43,10
+    CONTROL         "Disabled, but emulated",IDC_SOUND1,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,15,57,88,10
+    CONTROL         "Enabled",IDC_SOUND2,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,15,69,42,10
+    CONTROL         "Enabled, 100% accurate",IDC_SOUND3,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,15,81,93,10
+    GROUPBOX        "Settings",IDC_SOUNDINTERPOLATION2,133,30,160,68
+    RTEXT           "Frequency:",IDC_SOUNDFREQTXT,138,40,37,8,SS_CENTERIMAGE
+    COMBOBOX        IDC_SOUNDFREQ,140,49,67,75,CBS_DROPDOWN | WS_VSCROLL | 
+                    WS_TABSTOP
+    RTEXT           "Audio filter:",IDC_SOUNDFILTERTXT,140,65,36,8,
+                    SS_CENTERIMAGE
+    COMBOBOX        IDC_SOUNDFILTER,140,74,67,75,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    RTEXT           "Stereo mode:",IDC_SOUNDSTEREOTXT,223,40,41,8,
+                    SS_CENTERIMAGE
+    COMBOBOX        IDC_SOUNDSTEREO,220,49,67,75,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    RTEXT           "Interpolation:",IDC_SOUNDINTERPOLATIONTXT,222,65,41,8,
+                    SS_CENTERIMAGE
+    COMBOBOX        IDC_SOUNDINTERPOLATION,220,74,67,75,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    GROUPBOX        "Disk Drive Sound Emulation",IDC_STATIC,8,102,285,29
+    COMBOBOX        IDC_SOUNDDRIVE,15,113,32,75,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    COMBOBOX        IDC_SOUNDDRIVESELECT,55,113,120,75,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    CONTROL         "",IDC_SOUNDDRIVEVOLUME,"msctls_trackbar32",
+                    TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,183,109,107,19
+    GROUPBOX        "Sound buffer size",IDC_STATIC,7,136,120,29
+    CONTROL         "Slider1",IDC_SOUNDBUFFERRAM,"msctls_trackbar32",
+                    TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,14,144,106,19
+    CTEXT           "",IDC_SOUNDBUFFERMEM,134,144,40,16,SS_CENTERIMAGE | 
+                    SS_SUNKEN | WS_BORDER | WS_TABSTOP
+    GROUPBOX        "Sound driver lag compensation",IDC_STATIC,7,170,120,28
+    CONTROL         "Slider1",IDC_SOUNDADJUST,"msctls_trackbar32",
+                    TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,14,178,107,19
+    PUSHBUTTON      "Calibrate",IDC_SOUNDCALIBRATE,183,178,40,14
+    CTEXT           "",IDC_SOUNDADJUSTNUM,134,178,40,16,SS_CENTERIMAGE | 
+                    SS_SUNKEN | WS_BORDER | WS_TABSTOP
+    GROUPBOX        "Volume",IDC_STATIC,181,136,112,29
+    CONTROL         "",IDC_SOUNDVOLUME,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,183,144,107,19
+END
+
+IDD_LOADSAVE DIALOGEX 0, 0, 302, 240
+STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    CONTROL         "",IDC_CONFIGTREE,"SysTreeView32",TVS_HASLINES | 
+                    TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | WS_BORDER | 
+                    WS_TABSTOP,6,4,289,155,WS_EX_CLIENTEDGE
+    RTEXT           "Name:",IDC_STATIC,5,202,40,15,SS_CENTERIMAGE
+    EDITTEXT        IDC_EDITNAME,50,202,155,15,ES_AUTOHSCROLL,0,
+                    HIDC_EDITNAME
+    RTEXT           "Path:",IDC_STATIC,5,184,39,15,SS_CENTERIMAGE
+    EDITTEXT        IDC_EDITPATH,50,184,155,15,ES_AUTOHSCROLL | WS_DISABLED,
+                    0,HIDC_EDITPATH
+    RTEXT           "Description:",IDC_STATIC,5,163,40,15,SS_CENTERIMAGE
+    EDITTEXT        IDC_EDITDESCRIPTION,50,163,245,15,ES_AUTOHSCROLL,0,
+                    HIDC_EDITDESCRIPTION
+    GROUPBOX        "Extra Info",IDC_STATIC,210,179,85,38
+    PUSHBUTTON      "View",IDC_VIEWINFO,215,195,35,15
+    PUSHBUTTON      "Set",IDC_SETINFO,255,194,35,15
+    PUSHBUTTON      "Load",IDC_QUICKLOAD,5,222,40,15
+    PUSHBUTTON      "Save",IDC_QUICKSAVE,50,222,40,15
+    PUSHBUTTON      "Load From...",IDC_LOAD,125,222,45,15
+    PUSHBUTTON      "Save As...",IDC_SAVE,175,222,40,15
+    PUSHBUTTON      "Delete",IDC_DELETE,255,222,40,15
+END
+
+IDD_PORTS DIALOGEX 0, 0, 300, 202
+STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    RTEXT           "Serial:",IDC_STATIC,20,15,25,15,SS_CENTERIMAGE
+    COMBOBOX        IDC_SERIAL,50,15,95,65,CBS_DROPDOWNLIST | WS_VSCROLL | 
+                    WS_TABSTOP
+    CONTROL         "Shared",IDC_SHARED,"Button",BS_AUTOCHECKBOX | 
+                    BS_VCENTER | WS_TABSTOP,33,32,37,12
+    CONTROL         "RTS/CTS",IDC_SER_CTSRTS,"Button",BS_AUTOCHECKBOX | 
+                    BS_VCENTER | WS_TABSTOP,77,32,44,12
+    CONTROL         "Direct",IDC_SERIAL_DIRECT,"Button",BS_AUTOCHECKBOX | 
+                    BS_VCENTER | WS_TABSTOP,128,32,40,12
+    RTEXT           "Printer:",IDC_STATIC,155,15,25,15,SS_CENTERIMAGE
+    COMBOBOX        IDC_PRINTERLIST,185,15,95,134,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    RTEXT           "Out:",IDC_MIDI,10,64,34,15,SS_CENTERIMAGE
+    COMBOBOX        IDC_MIDIOUTLIST,50,64,95,130,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    RTEXT           "In:",IDC_MIDI2,150,64,29,15,SS_CENTERIMAGE
+    COMBOBOX        IDC_MIDIINLIST,185,64,95,134,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    GROUPBOX        "Amiga Mouse Port 0",IDC_PORT0,7,92,116,100
+    CONTROL         "PC Joystick 0",IDC_PORT0_JOY0,"Button",
+                    BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,20,102,90,10
+    CONTROL         "PC Joystick 1",IDC_PORT0_JOY1,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,20,116,90,10
+    CONTROL         "PC Mouse",IDC_PORT0_MOUSE,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,20,131,90,11
+    CONTROL         "Keyboard Layout ""A""",IDC_PORT0_KBDA,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,20,147,90,10
+    CONTROL         "Keyboard Layout ""B""",IDC_PORT0_KBDB,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,20,162,90,10
+    CONTROL         "Keyboard Layout ""C""",IDC_PORT0_KBDC,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,20,177,90,10
+    GROUPBOX        "Amiga Mouse Port 1",IDC_PORT1,175,92,115,100
+    CONTROL         "PC Joystick 0",IDC_PORT1_JOY0,"Button",
+                    BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,190,102,90,10
+    CONTROL         "PC Joystick 1",IDC_PORT1_JOY1,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,190,116,90,10
+    CONTROL         "PC Mouse",IDC_PORT1_MOUSE,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,190,131,90,11
+    CONTROL         "Keyboard Layout ""A""",IDC_PORT1_KBDA,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,190,147,90,10
+    CONTROL         "Keyboard Layout ""B""",IDC_PORT1_KBDB,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,190,162,90,10
+    CONTROL         "Keyboard Layout ""C""",IDC_PORT1_KBDC,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,190,177,90,10
+    PUSHBUTTON      "<-swap->",IDC_SWAP,130,132,40,14
+    GROUPBOX        "MIDI",IDC_MIDIFRAME,7,51,284,36
+    GROUPBOX        "Serial and Parallel",IDC_SERPARFRAME,7,3,284,45
+END
+
+IDD_CONTRIBUTORS DIALOGEX 0, 0, 411, 242
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | WS_POPUP | 
+    WS_VISIBLE | WS_CAPTION
+CAPTION "UAE Authors and Contributors..."
+FONT 8, "MS Sans Serif", 0, 0, 0x0
+BEGIN
+    DEFPUSHBUTTON   "Ok",ID_OK,177,219,53,14
+    CONTROL         "",IDC_CONTRIBUTORS,"RICHEDIT",TCS_HOTTRACK | 
+                    TCS_VERTICAL | TCS_RAGGEDRIGHT | TCS_OWNERDRAWFIXED | 
+                    TCS_MULTISELECT | WS_BORDER | WS_VSCROLL | WS_HSCROLL | 
+                    WS_TABSTOP,4,5,404,206
+END
+
+IDD_ABOUT DIALOGEX 0, 0, 300, 175
+STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD
+FONT 8, "MS Sans Serif", 0, 0, 0x0
+BEGIN
+    CONTROL         "",IDC_RICHEDIT1,"RICHEDIT",TCS_SCROLLOPPOSITE | 
+                    TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,45,10,
+                    210,15
+    CONTROL         "",IDC_RICHEDIT2,"RICHEDIT",TCS_SCROLLOPPOSITE | 
+                    TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,20,30,
+                    260,13
+    PUSHBUTTON      "Contributors",IDC_CONTRIBUTORS,110,55,80,15
+    CONTROL         "",IDC_CLOANTOHOME,"RICHEDIT",TCS_SCROLLOPPOSITE | 
+                    TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,20,90,80,
+                    20
+    CONTROL         "",IDC_UAEHOME,"RICHEDIT",TCS_SCROLLOPPOSITE | 
+                    TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,20,120,
+                    80,15
+    CONTROL         "",IDC_PICASSOHOME,"RICHEDIT",TCS_SCROLLOPPOSITE | 
+                    TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,200,90,
+                    80,20
+    CONTROL         "",IDC_AMIGAHOME,"RICHEDIT",TCS_SCROLLOPPOSITE | 
+                    TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,110,90,
+                    80,15
+    CONTROL         "",IDC_WINUAEHOME,"RICHEDIT",TCS_SCROLLOPPOSITE | 
+                    TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,200,120,
+                    80,15
+    CONTROL         "",IDC_AIABHOME,"RICHEDIT",TCS_SCROLLOPPOSITE | 
+                    TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,110,120,
+                    80,15
+    CONTROL         "",IDC_THEROOTS,"RICHEDIT",TCS_SCROLLOPPOSITE | 
+                    TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,33,143,
+                    110,15
+    CONTROL         "",IDC_CAPS,"RICHEDIT",TCS_SCROLLOPPOSITE | 
+                    TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,150,143,
+                    110,15
+END
+
+IDD_MISC1 DIALOGEX 0, 0, 300, 223
+STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    GROUPBOX        "Advanced:",IDC_STATIC,8,4,285,90
+    CONTROL         "Middle-Mouse-Button --> ALT-TAB",IDC_JULIAN,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,29,15,120,10
+    CONTROL         "Show GUI on startup",IDC_SHOWGUI,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,29,30,120,10
+    CONTROL         "On-Screen LEDs",IDC_SHOWLEDS,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,29,45,115,10
+    CONTROL         "UAEscsi.device",IDC_SCSIDEVICE,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,29,60,117,10
+    CONTROL         "BSDsocket.library emulation",IDC_SOCKETS,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,159,15,120,10
+    CONTROL         "Use CTRL-F11 to quit",IDC_CTRLF11,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,159,30,120,10
+    CONTROL         "Don't use RGB overlays",IDC_NOOVERLAY,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,159,45,120,10
+    CONTROL         "Use ASPI SCSI layer",IDC_ASPI,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,159,60,115,10
+    GROUPBOX        "Keyboard LEDs:",IDC_STATIC,7,99,85,73
+    COMBOBOX        IDC_KBLED1,22,112,56,65,CBS_DROPDOWNLIST | WS_VSCROLL | 
+                    WS_TABSTOP
+    COMBOBOX        IDC_KBLED2,22,131,56,65,CBS_DROPDOWNLIST | WS_VSCROLL | 
+                    WS_TABSTOP
+    COMBOBOX        IDC_KBLED3,22,151,56,65,CBS_DROPDOWNLIST | WS_VSCROLL | 
+                    WS_TABSTOP
+    GROUPBOX        "Logging:",IDC_STATIC,97,99,195,25
+    CONTROL         "Create log file",IDC_CREATELOGFILE,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,107,109,72,10,0,
+                    HIDC_CREATELOGFILE
+    CONTROL         "Illegal mem accesses",IDC_ILLEGAL,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,189,109,80,10
+    GROUPBOX        "State files:",IDC_STATIC,98,126,195,76
+    PUSHBUTTON      "Load state...",IDC_DOLOADSTATE,105,143,49,14
+    PUSHBUTTON      "Save state...",IDC_DOSAVESTATE,106,169,49,14
+    CONTROL         "Enable state recording",IDC_STATE_CAPTURE,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,188,142,88,10
+    RTEXT           "Recording rate (seconds)",IDC_STATE_RATE_TEXT,157,160,
+                    86,10,SS_CENTERIMAGE | WS_TABSTOP
+    COMBOBOX        IDC_STATE_RATE,248,158,38,65,CBS_DROPDOWN | WS_VSCROLL | 
+                    WS_TABSTOP
+    RTEXT           "Recording buffer (MB)",IDC_STATE_BUFFERSIZE_TEXT,157,
+                    180,83,10,SS_CENTERIMAGE | WS_TABSTOP
+    COMBOBOX        IDC_STATE_BUFFERSIZE,248,178,38,65,CBS_DROPDOWN | 
+                    WS_VSCROLL | WS_TABSTOP
+    CONTROL         "Disable UAEFSDB-support",IDC_NOUAEFSDB,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,29,76,115,10
+END
+
+IDD_HARDFILE DIALOGEX 0, 0, 229, 164
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | 
+    DS_CENTERMOUSE | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Volume Settings"
+FONT 8, "MS Sans Serif", 0, 0, 0x0
+BEGIN
+    GROUPBOX        "Hard File Settings",IDC_STATIC,10,5,210,90
+    RTEXT           "Path:",IDC_HARDFILE_DIR_TEXT,19,21,22,10
+    EDITTEXT        IDC_PATH_NAME,44,15,151,15,ES_AUTOHSCROLL
+    PUSHBUTTON      "...",IDC_SELECTOR,200,15,11,15
+    RTEXT           "FileSys:",IDC_HARDFILE_FILESYS_TEXT,16,36,26,10
+    EDITTEXT        IDC_PATH_FILESYS,44,34,89,15,ES_AUTOHSCROLL
+    PUSHBUTTON      "...",IDC_FILESYS_SELECTOR,139,34,11,15
+    CONTROL         "Read/Write",IDC_RW,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,160,37,50,10
+    RTEXT           "Device:",IDC_HARDFILE_DEVICE_TEXT,16,58,25,10
+    EDITTEXT        IDC_HARDFILE_DEVICE,44,54,32,15,ES_AUTOHSCROLL
+    RTEXT           "Surfaces:",IDC_SURFACES_TEXT,75,58,35,10
+    EDITTEXT        IDC_HEADS,115,54,27,15,ES_NUMBER
+    RTEXT           "Reserved:",IDC_RESERVED_TEXT,145,58,35,10
+    EDITTEXT        IDC_RESERVED,185,54,27,15,ES_NUMBER
+    RTEXT           "BootPri:",IDC_HARDFILE_BOOTPRI_TEXT,11,80,30,8
+    EDITTEXT        IDC_HARDFILE_BOOTPRI,44,75,32,15
+    RTEXT           "Sectors:",IDC_SECTORS_TEXT,80,80,30,10
+    EDITTEXT        IDC_SECTORS,115,75,27,15,ES_NUMBER
+    RTEXT           "Block-Size:",IDC_BLOCKSIZE_TEXT,145,80,35,10
+    EDITTEXT        IDC_BLOCKSIZE,185,75,27,15,ES_NUMBER
+    GROUPBOX        "New Hard File",IDC_STATIC,10,100,210,35
+    PUSHBUTTON      "Create",IDC_CREATEHF,20,115,85,14
+    EDITTEXT        IDC_HFSIZE,110,115,60,15,ES_NUMBER
+    LTEXT           "MB",IDC_RESERVED_TEXT2,174,118,39,9,NOT WS_GROUP
+    PUSHBUTTON      "OK",IDOK,115,143,50,14
+    PUSHBUTTON      "Cancel",IDCANCEL,171,143,50,14
+END
+
+IDD_FILESYS DIALOGEX 15, 25, 229, 111
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | 
+    DS_CENTERMOUSE | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Volume Settings"
+FONT 8, "MS Sans Serif", 0, 0, 0x0
+BEGIN
+    LTEXT           "Device Name:",-1,5,9,54,10
+    EDITTEXT        IDC_VOLUME_DEVICE,65,5,85,15,ES_AUTOHSCROLL
+    LTEXT           "Volume Label:",-1,5,31,54,10
+    EDITTEXT        IDC_VOLUME_NAME,65,25,85,15,ES_AUTOHSCROLL
+    LTEXT           "Path:",-1,5,51,44,10
+    EDITTEXT        IDC_PATH_NAME,65,46,139,15,ES_AUTOHSCROLL
+    PUSHBUTTON      "...",IDC_SELECTOR,210,46,10,15
+    CONTROL         "Read/Write",IDC_RW,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,5,70,50,10
+    RTEXT           "BootPri:",IDC_VOLUME_BOOTPRI_TEXT,68,70,30,8
+    EDITTEXT        IDC_VOLUME_BOOTPRI,106,68,27,15
+    PUSHBUTTON      "OK",IDOK,120,91,48,15
+    PUSHBUTTON      "Cancel",IDCANCEL,175,91,48,15
+END
+
+IDD_SETINFO DIALOGEX 0, 0, 229, 85
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | 
+    DS_CENTERMOUSE | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Info Settings"
+FONT 8, "MS Sans Serif", 0, 0, 0x0
+BEGIN
+    RTEXT           "Path:",-1,5,20,24,15,SS_CENTERIMAGE
+    EDITTEXT        IDC_PATH_NAME,35,20,169,15,ES_AUTOHSCROLL
+    PUSHBUTTON      "...",IDC_SELECTOR,210,20,10,15
+    PUSHBUTTON      "OK",IDOK,120,65,48,15
+    PUSHBUTTON      "Cancel",IDCANCEL,175,65,48,15
+END
+
+IDD_CHIPSET DIALOGEX 0, 65490, 300, 229
+STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD
+FONT 8, "MS Sans Serif", 0, 0, 0x0
+BEGIN
+    GROUPBOX        "Chipset type",IDC_STATIC,14,11,145,82
+    CONTROL         "OCS",IDC_OCS,"Button",BS_AUTORADIOBUTTON | WS_GROUP | 
+                    WS_TABSTOP,38,31,30,10
+    CONTROL         "ECS Agnus",IDC_ECS_AGNUS,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,38,47,50,10
+    CONTROL         "ECS Denise",IDC_ECS_DENISE,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,38,63,50,10
+    CONTROL         "Full ECS",IDC_ECS,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,102,31,42,10
+    CONTROL         "AGA",IDC_AGA,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
+                    102,47,30,10
+    CONTROL         "NTSC",IDC_NTSC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+                    102,64,35,10
+    GROUPBOX        "Misc chipset options",IDC_STATIC,168,11,114,82
+    CONTROL         "Fast Copper",IDC_FASTCOPPER,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,174,31,53,10
+    CONTROL         "Immediate Blitter",IDC_BLITIMM,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,174,47,75,10
+    CONTROL         "Cycle exact CPU and Blitter",IDC_CYCLEEXACT,"Button",
+                    BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,174,64,
+                    100,10
+    GROUPBOX        "Collision level",IDC_STATIC,14,97,267,48
+    CONTROL         "None",IDC_COLLISION0,"Button",BS_AUTORADIOBUTTON | 
+                    WS_GROUP | WS_TABSTOP,40,113,50,10
+    CONTROL         "Sprites only",IDC_COLLISION1,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,39,129,50,10
+    CONTROL         "Sprites and Sprites vs. Playfield",IDC_COLLISION2,
+                    "Button",BS_AUTORADIOBUTTON | WS_TABSTOP,104,113,114,10
+    CONTROL         "Full",IDC_COLLISION3,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,104,129,27,10
+    GROUPBOX        "Sound emulation",IDC_STATIC,13,150,268,65
+    CONTROL         "Disabled",IDC_CS_SOUND0,"Button",BS_AUTORADIOBUTTON | 
+                    WS_GROUP | WS_TABSTOP,39,167,102,10
+    CONTROL         "Emulated",IDC_CS_SOUND1,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,39,182,91,10
+    CONTROL         "Emulated, 100% accurate",IDC_CS_SOUND2,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,39,197,95,10
+END
+
+IDD_AVIOUTPUT DIALOGEX 0, 0, 198, 188
+STYLE DS_SETFONT | DS_CONTROL | WS_CHILD
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    GROUPBOX        "Output Properties:",IDC_STATIC,5,8,184,96
+    EDITTEXT        IDC_AVIOUTPUT_FILETEXT,26,21,120,12,ES_AUTOHSCROLL | 
+                    ES_READONLY | NOT WS_BORDER,WS_EX_CLIENTEDGE
+    PUSHBUTTON      "...",IDC_AVIOUTPUT_FILE,148,21,19,12
+    CONTROL         "Audio",IDC_AVIOUTPUT_AUDIO,"Button",BS_AUTOCHECKBOX | 
+                    BS_PUSHLIKE | BS_FLAT | WS_TABSTOP,26,36,32,11
+    CONTROL         "",IDC_AVIOUTPUT_AUDIO_STATIC,"Static",SS_LEFTNOWORDWRAP | 
+                    SS_CENTERIMAGE | SS_SUNKEN | WS_GROUP,60,36,107,11
+    CONTROL         "Video",IDC_AVIOUTPUT_VIDEO,"Button",BS_AUTOCHECKBOX | 
+                    BS_PUSHLIKE | BS_FLAT | WS_TABSTOP,26,50,32,11
+    CONTROL         "",IDC_AVIOUTPUT_VIDEO_STATIC,"Static",SS_LEFTNOWORDWRAP | 
+                    SS_CENTERIMAGE | SS_SUNKEN | WS_GROUP,60,50,107,11
+    CONTROL         "Disable frame rate limit while recording",
+                    IDC_AVIOUTPUT_FRAMELIMITER,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,28,68,142,10
+    CONTROL         "AVIOutput enabled",IDC_AVIOUTPUT_ACTIVATED,"Button",
+                    BS_AUTORADIOBUTTON | BS_PUSHLIKE | BS_FLAT,26,83,142,12
+    GROUPBOX        "Playback Rate:",IDC_STATIC,5,107,184,50
+    CONTROL         "PAL",IDC_AVIOUTPUT_PAL,"Button",BS_AUTORADIOBUTTON | 
+                    BS_PUSHLIKE | BS_FLAT,24,124,66,8
+    CONTROL         "NTSC",IDC_AVIOUTPUT_NTSC,"Button",BS_AUTORADIOBUTTON | 
+                    BS_PUSHLIKE | BS_FLAT,95,124,66,8
+    CONTROL         "Slider1",IDC_AVIOUTPUT_FPS,"msctls_trackbar32",TBS_BOTH | 
+                    TBS_NOTICKS | TBS_ENABLESELRANGE | WS_TABSTOP,21,137,120,
+                    11
+    LTEXT           "fps",IDC_AVIOUTPUT_FPS_STATIC,141,136,23,8
+    PUSHBUTTON      "Save Screenshot",IDC_SCREENSHOT,46,167,95,12
+END
+
+IDD_INPUT DIALOGEX 0, 0, 300, 242
+STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    COMBOBOX        IDC_INPUTTYPE,5,5,98,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+    COMBOBOX        IDC_INPUTDEVICE,109,4,167,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+    CONTROL         "",IDC_INPUTDEVICEDISABLE,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,282,7,9,8
+    CONTROL         "List1",IDC_INPUTLIST,"SysListView32",LVS_REPORT | 
+                    LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | 
+                    LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,22,290,146
+    COMBOBOX        IDC_INPUTAMIGACNT,5,174,24,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+    COMBOBOX        IDC_INPUTAMIGA,33,174,262,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+    RTEXT           "Joystick dead zone (%):",-1,8,196,76,10,SS_CENTERIMAGE
+    EDITTEXT        IDC_INPUTDEADZONE,89,195,25,12,ES_NUMBER
+    RTEXT           "Autofire rate (frames):",-1,9,212,68,10,SS_CENTERIMAGE
+    EDITTEXT        IDC_INPUTAUTOFIRERATE,89,210,25,12,ES_NUMBER
+    RTEXT           "Digital joy-mouse speed:",-1,121,196,76,10,
+                    SS_CENTERIMAGE
+    EDITTEXT        IDC_INPUTSPEEDD,207,195,25,12,ES_NUMBER
+    RTEXT           "Analog joy-mouse speed:",-1,120,212,80,10,
+                    SS_CENTERIMAGE
+    EDITTEXT        IDC_INPUTSPEEDA,207,211,25,12,ES_NUMBER
+    RTEXT           "Mouse speed:",-1,132,228,68,10,SS_CENTERIMAGE
+    EDITTEXT        IDC_INPUTSPEEDM,207,227,25,12,ES_NUMBER
+    PUSHBUTTON      "Copy from:",IDC_INPUTCOPY,249,195,45,14
+    COMBOBOX        IDC_INPUTCOPYFROM,249,211,45,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+    PUSHBUTTON      "Swap 1<>2",IDC_INPUTSWAP,249,226,45,14
+END
+
+IDD_OPENGL DIALOGEX 0, 0, 300, 193
+STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    GROUPBOX        "Filter settings:",-1,8,5,285,180
+    CONTROL         "Enable",IDC_OPENGLENABLE,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,26,23,38,10
+    COMBOBOX        IDC_OPENGLMODE,67,21,56,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+    COMBOBOX        IDC_OPENGLFILTER,128,21,65,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+    PUSHBUTTON      "Reset to defaults",IDC_OPENGLDEFAULT,197,21,73,14
+    RTEXT           "Horizontal Size",-1,25,52,57,10,SS_CENTERIMAGE
+    CONTROL         "Slider1",IDC_OPENGLHZ,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,89,45,158,19
+    CTEXT           "",IDC_OPENGLHZV,249,47,21,16,SS_CENTERIMAGE | SS_SUNKEN | 
+                    WS_BORDER | WS_TABSTOP
+    RTEXT           "Vertical Size",-1,26,72,57,10,SS_CENTERIMAGE
+    CONTROL         "Slider1",IDC_OPENGLVZ,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,89,65,157,19
+    CTEXT           "",IDC_OPENGLVZV,249,67,21,16,SS_CENTERIMAGE | SS_SUNKEN | 
+                    WS_BORDER | WS_TABSTOP
+    RTEXT           "Horizontal Position",-1,26,92,57,10,SS_CENTERIMAGE
+    CONTROL         "Slider1",IDC_OPENGLHO,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,89,85,157,19
+    CTEXT           "",IDC_OPENGLHOV,249,87,21,16,SS_CENTERIMAGE | SS_SUNKEN | 
+                    WS_BORDER | WS_TABSTOP
+    RTEXT           "Vertical Position",-1,26,111,57,10,SS_CENTERIMAGE
+    CONTROL         "Slider1",IDC_OPENGLVO,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,89,105,157,19
+    CTEXT           "",IDC_OPENGLVOV,249,107,21,16,SS_CENTERIMAGE | 
+                    SS_SUNKEN | WS_BORDER | WS_TABSTOP
+    RTEXT           "Scanlines",-1,27,141,57,10,SS_CENTERIMAGE
+    CONTROL         "Slider1",IDC_OPENGLSL,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,89,134,157,19
+    CTEXT           "",IDC_OPENGLSLV,249,135,21,16,SS_CENTERIMAGE | 
+                    SS_SUNKEN | WS_BORDER | WS_TABSTOP
+    COMBOBOX        IDC_OPENGLSLR,56,154,27,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+    CONTROL         "Slider1",IDC_OPENGLSL2,"msctls_trackbar32",
+                    TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,89,154,157,19
+    CTEXT           "",IDC_OPENGLSL2V,249,154,21,16,SS_CENTERIMAGE | 
+                    SS_SUNKEN | WS_BORDER | WS_TABSTOP
+END
+
+IDD_HARDDRIVE DIALOGEX 0, 0, 229, 66
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | 
+    DS_CENTERMOUSE | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Harddrive Settings"
+FONT 8, "MS Sans Serif", 0, 0, 0x0
+BEGIN
+    LTEXT           "Harddrive:",-1,7,11,35,10
+    COMBOBOX        IDC_HARDDRIVE,49,9,173,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+    CONTROL         "Read/Write",IDC_RW,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,15,30,50,10
+    DEFPUSHBUTTON   "OK",IDOK,116,47,50,14
+    PUSHBUTTON      "Cancel",IDCANCEL,172,47,50,14
+END
+
+IDD_MISC2 DIALOGEX 0, 0, 300, 92
+STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    GROUPBOX        "When Active:",IDC_STATIC,8,7,88,73
+    RTEXT           "Run at priority:",IDC_ACTIVE_PRI,14,17,45,10,
+                    SS_CENTERIMAGE | WS_TABSTOP
+    COMBOBOX        IDC_ACTIVE_PRIORITY,14,29,76,65,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    GROUPBOX        "When Inactive:",IDC_STATIC,102,7,92,73
+    RTEXT           "Run at priority:",IDC_INACTIVE_PRI,109,17,45,10,
+                    SS_CENTERIMAGE | WS_TABSTOP
+    COMBOBOX        IDC_INACTIVE_PRIORITY,109,29,76,65,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    CONTROL         "Pause emulation",IDC_INACTIVE_PAUSE,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,109,50,69,10
+    CONTROL         "Disable sound output",IDC_INACTIVE_NOSOUND,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,109,63,79,10
+    GROUPBOX        "When Minimized:",IDC_STATIC,199,7,92,73
+    RTEXT           "Run at priority:",IDC_MINIMIZED_PRI,207,18,45,10,
+                    SS_CENTERIMAGE | WS_TABSTOP
+    COMBOBOX        IDC_MINIMIZED_PRIORITY,207,30,76,65,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    CONTROL         "Pause emulation",IDC_MINIMIZED_PAUSE,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,207,50,69,10
+    CONTROL         "Disable sound output",IDC_MINIMIZED_NOSOUND,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,207,63,79,10
+END
+
+IDD_DISK DIALOGEX 0, 0, 300, 242
+STYLE DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_CONTROL | DS_CENTER | 
+    DS_CENTERMOUSE | WS_CHILD
+FONT 8, "MS Sans Serif", 0, 0, 0x0
+BEGIN
+    CONTROL         "",IDC_DISKLIST,"SysListView32",LVS_REPORT | 
+                    LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | 
+                    LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,4,6,262,211
+    PUSHBUTTON      "Remove disk image",IDC_DISKLISTREMOVE,94,222,93,15
+    PUSHBUTTON      "",IDC_UP,270,66,25,15,BS_ICON
+    PUSHBUTTON      "",IDC_DOWN,270,146,25,15,BS_ICON
+END
+
+IDD_PANEL DIALOGEX 0, 0, 420, 278
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | 
+    WS_SYSMENU
+EXSTYLE WS_EX_ACCEPTFILES | WS_EX_CONTROLPARENT
+CAPTION "WinUAE Properties"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+    CONTROL         "",IDC_PANELTREE,"SysTreeView32",TVS_HASLINES | 
+                    TVS_SHOWSELALWAYS | TVS_NOSCROLL | WS_BORDER | 
+                    WS_TABSTOP,5,5,101,248,WS_EX_CLIENTEDGE
+    GROUPBOX        "",IDC_PANEL_FRAME_OUTER,110,2,307,251
+    DEFPUSHBUTTON   "OK",IDOK,260,259,50,14
+    PUSHBUTTON      "Cancel",IDCANCEL,313,259,50,14
+    PUSHBUTTON      "Help",IDHELP,366,259,50,14,WS_DISABLED
+    PUSHBUTTON      "Reset",IDC_RESETAMIGA,6,259,47,14
+    PUSHBUTTON      "Quit",IDC_QUITEMU,57,259,47,14
+    GROUPBOX        "",IDC_PANEL_FRAME,112,4,303,247,NOT WS_VISIBLE
+END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "#include ""dlgs.h""\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "\r\n"
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_APPICON             ICON                    "winuae.ico"
+IDI_FLOPPY              ICON                    "35floppy.ico"
+IDI_ABOUT               ICON                    "amigainfo.ico"
+IDI_HARDDISK            ICON                    "Drive.ico"
+IDI_CPU                 ICON                    "cpu.ico"
+IDI_PORTS               ICON                    "joystick.ico"
+IDI_INPUT               ICON                    "joystick.ico"
+IDI_MISC1               ICON                    "misc.ico"
+IDI_MISC2               ICON                    "misc.ico"
+IDI_MOVE_UP             ICON                    "move_up.ico"
+IDI_MOVE_DOWN           ICON                    "move_dow.ico"
+IDI_AVIOUTPUT           ICON                    "avioutput.ico"
+IDI_DISK                ICON                    "Drive.ico"
+IDI_CONFIGFILE          ICON                    "file.ico"
+IDI_FOLDER              ICON                    "folder.ico"
+IDI_SOUND               ICON                    "sound.ico"
+IDI_DISPLAY             ICON                    "screen.ico"
+IDI_ROOT                ICON                    "root.ico"
+IDI_MEMORY              ICON                    "chip.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,8,26,0
+ PRODUCTVERSION 0,8,26,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "FileDescription", "WinUAE"
+            VALUE "FileVersion", "0.8.26"
+            VALUE "InternalName", "WinUAE"
+            VALUE "LegalCopyright", "© 1996-2004 under the GNU Public License (GPL)"
+            VALUE "OriginalFilename", "WinUAE.exe"
+            VALUE "ProductName", "WinUAE"
+            VALUE "ProductVersion", "0.8.26"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Cursor
+//
+
+IDC_MYHAND              CURSOR                  "H_arrow.cur"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO 
+BEGIN
+    IDD_DISPLAY, DIALOG
+    BEGIN
+        BOTTOMMARGIN, 175
+    END
+
+    IDD_FLOPPY, DIALOG
+    BEGIN
+        BOTTOMMARGIN, 175
+    END
+
+    IDD_HARDDISK, DIALOG
+    BEGIN
+        BOTTOMMARGIN, 175
+    END
+
+    IDD_SOUND, DIALOG
+    BEGIN
+        BOTTOMMARGIN, 206
+    END
+
+    IDD_PORTS, DIALOG
+    BEGIN
+        BOTTOMMARGIN, 175
+    END
+
+    IDD_CONTRIBUTORS, DIALOG
+    BEGIN
+        RIGHTMARGIN, 370
+        BOTTOMMARGIN, 212
+    END
+
+    IDD_MISC1, DIALOG
+    BEGIN
+        BOTTOMMARGIN, 215
+    END
+
+    IDD_CHIPSET, DIALOG
+    BEGIN
+        BOTTOMMARGIN, 215
+    END
+
+    IDD_AVIOUTPUT, DIALOG
+    BEGIN
+        RIGHTMARGIN, 164
+        BOTTOMMARGIN, 187
+    END
+
+    IDD_INPUT, DIALOG
+    BEGIN
+        BOTTOMMARGIN, 187
+    END
+
+    IDD_OPENGL, DIALOG
+    BEGIN
+        BOTTOMMARGIN, 175
+    END
+
+    IDD_DISK, DIALOG
+    BEGIN
+        BOTTOMMARGIN, 193
+    END
+
+    IDD_PANEL, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        TOPMARGIN, 7
+        HORZGUIDE, 241
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDM_SYSTRAY MENU 
+BEGIN
+    POPUP "Menu"
+    BEGIN
+        MENUITEM "Configuration",               ID_ST_CONFIGURATION
+        POPUP "Floppy Drives"
+        BEGIN
+            MENUITEM "Eject all drives",            ID_ST_EJECTALL
+            MENUITEM "DF0:",                        40014
+            MENUITEM "DF1:",                        ID_ST_DF1
+            MENUITEM "DF2:",                        ID_ST_DF2
+            MENUITEM "DF3:",                        ID_ST_DF3
+        END
+        MENUITEM "Reset",                       ID_ST_RESET
+        MENUITEM "Help",                        ID_ST_HELP
+        MENUITEM "Quit WinUAE",                 ID_ST_QUIT
+    END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// WAVE
+//
+
+IDR_DRIVE_STARTUP_A500_1 WAVE                    "drive_startup.wav"
+IDR_DRIVE_CLICK_A500_1  WAVE                    "drive_click.wav"
+IDR_DRIVE_SPIN_A500_1   WAVE                    "drive_spin.wav"
+IDR_DRIVE_SNATCH_A500_1 WAVE                    "drive_snatch.wav"
+IDR_DRIVE_SPINND_A500_1 WAVE                    "drive_spinnd.wav"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// RT_MANIFEST
+//
+
+1                       RT_MANIFEST             "winuae.exe.manifest"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE 
+BEGIN
+    IDS_KICKSTART           "ROM"
+    IDS_DISK                "Disk Swapper"
+    IDS_DISPLAY             "Display"
+    IDS_HARDDISK            "Hard Drives"
+    IDS_FLOPPY              "Disk Drives"
+    IDS_ABOUT               "About"
+    IDS_LOADSAVE            "Configurations"
+    IDS_AVIOUTPUT           "Output"
+    IDS_PORTS               "Game & I/O Ports"
+    IDS_MISC1               "Misc"
+    IDS_MEMORY              "RAM"
+    IDS_CPU                 "CPU"
+    IDS_CHIPSET             "Chipset"
+    IDS_INPUT               "Input"
+    IDS_OPENGL              "Filter"
+END
+
+STRINGTABLE 
+BEGIN
+    IDS_MISC2               "Priority"
+END
+
+STRINGTABLE 
+BEGIN
+    IDS_EXTTEXT             "Amiga Disk Files"
+    IDS_EXTACTUAL           "ADF"
+    IDS_SOUND               "Sound"
+    IDS_CDROM               "CD-ROM"
+    IDS_FRAMERATE           "Every %1Frame"
+    IDS_SECOND              "second "
+    IDS_THIRD               "third "
+    IDS_FOURTH              "fourth "
+    IDS_FIFTH               "fifth "
+    IDS_SIXTH               "sixth "
+    IDS_SEVENTH             "seventh "
+    IDS_EIGHTH              "eighth "
+END
+
+STRINGTABLE 
+BEGIN
+    IDS_NINTH               "ninth "
+    IDS_TENTH               "tenth "
+    IDS_SELECTADF           "Select an Amiga Disk File image..."
+    IDS_ADF                 "Amiga Disk Files"
+    IDS_CHOOSEBLANK         "Choose your blank Amiga Disk File..."
+    IDS_SELECTHDF           "Select a Hard Disk File..."
+    IDS_HDF                 "Hard Disk Files"
+    IDS_SELECTUAE           "Select a UAE Config-File..."
+    IDS_UAE                 "UAE Config Files"
+    IDS_SELECTROM           "Select an Amiga ROM file..."
+    IDS_ROM                 "Amiga Kickstart Files"
+    IDS_SELECTKEY           "Select an Amiga Key-File..."
+    IDS_KEY                 "Amiga Kickstart Key-Files"
+    IDS_SELECTINFO          "Select information for your config..."
+    IDS_NONE                "none"
+    IDS_VOLUME              "Volume"
+END
+
+STRINGTABLE 
+BEGIN
+    IDS_SELECTFILESYSROOT   "Please select your file-system root directory..."
+    IDS_DEFAULTMIDIOUT      "Default MIDI-Out Device"
+    IDS_CONTRIBUTORS1       "Bernd Schmidt - The Grand-Master\nSam Jordan - Custom-chip, floppy-DMA, etc.\nMathias Ortmann - Original WinUAE Main Guy, BSD Socket support\nBrian King - Picasso96 Support, Integrated GUI for WinUAE, previous WinUAE Main Guy\nToni Wilen - Core updates, WinUAE Main Guy\nGustavo Goedert/Peter Remmers/Michael Sontheimer/Tomi Hakala/Tim Gunn/Nemo Pohle - DOS Port Stuff\nSamuel Devulder/Olaf Barthel/Sam Jordan - Amiga Ports\nKrister Bergman - XFree86 and OS/2 Port\nA. Blanchard/Ernesto Corvi - MacOS Port\nChristian Bauer - BeOS Port\nIan Stephenson - NextStep Port\nPeter Teichmann - Acorn/RiscOS Port\nStefan Reinauer - ZorroII/III AutoConfig, Serial Support\nChristian Schmitt/Chris Hames - Serial Support\nHerman ten Brugge - 68020/68881 Emulation Code\nTauno Taipaleenmaki - Various UAE-Control/UAE-Library Support\nBrett Eden/Tim Gunn/Paolo Besser/Nemo Pohle - Various Docs and Web-Sites\nGeorg Veichtlbauer - Help File coordinator, German GUI\nFulvio Leonardi - Italian translator for WinUAE\n"
+    IDS_CONTRIBUTORS2       "Special thanks to Alexander Kneer and Tobias Abt (The Picasso96 Team)\n"
+    IDS_INVALIDPRTPORT      "The printer you have in this configuration is not valid on this machine.\n"
+    IDS_RESTOREUSS          "Restore a UAE Snap-Shot File"
+    IDS_USS                 "UAE Snap-Shot Files"
+    IDS_WRONGOSVERSION      "WinUAE is no longer supported on Windows NT.  Please upgrade to either Windows 2000 or Windows XP."
+    IDS_SELECTFLASH         "Select a flash/battery backed RAM file..."
+    IDS_FLASH               "UAE flash/battery backed RAM file"
+    IDS_INPUTHOSTWIDGET     "Input Source"
+    IDS_INPUTAMIGAEVENT     "Input Target"
+    IDS_INPUTAUTOFIRE       "Autofire"
+    IDS_SAVEUSS             "Save a UAE Snap-Shot File"
+    IDS_MIDIOVERFLOW        "Sysexbuffer overflow. Should not happen. Please report this to\nberndroesch1@compuserve.de"
+END
+
+STRINGTABLE 
+BEGIN
+    IDS_PATH                "Path"
+    IDS_RW                  "R/W"
+    IDS_SECTORS             "Sectors"
+    IDS_SURFACES            "Surfaces"
+    IDS_RESERVED            "Reserved"
+    IDS_BLOCKSIZE           "Block Size"
+    IDS_NAME                "Name"
+    IDS_DESCRIPTION         "Description"
+    IDS_ONEINSTANCE         "Only one instance of WinUAE can run at a time.\n"
+    IDS_INSTALLDIRECTX      "You have to install DirectX on your system before you can use UAE.\nRefer to the documentation for further details.\n"
+    IDS_REGKEYCREATEFAILED  "WinUAE could not create Registry keys!  You need administrator privileges.\n"
+    IDS_COULDNOTLOADCONFIG  "Could not load selected configuration!\n"
+    IDS_NOHELP              "Online help is disabled, because you have not installed the HtmlHelp system.  Go to http://msdn.microsoft.com/library/tools/htmlhelp/wkshp/download.htm to get HtmlHelp.\n"
+    IDS_MUSTSELECTCONFIG    "You must select a configuration or enter a name before selecting Load...\n"
+    IDS_INVALIDCOMPORT      "The COM-port you have in this configuration is not valid on this machine.\n"
+END
+
+STRINGTABLE 
+BEGIN
+    IDS_HFDSIZE             "Size"
+    IDS_DEVICE              "Device"
+    IDS_BOOTPRI             "BootPri"
+    IDS_WRONGDXVERSION      "WinUAE requires DirectX 8 or newer."
+END
+
+STRINGTABLE 
+BEGIN
+    IDS_WSOCK2NEEDED        "Please upgrade to Winsock2.\n"
+    IDS_UNSUPPORTEDPIXELFORMAT 
+                            "Error: Unsupported pixel format - use a different screen mode\n"
+    IDS_MUSTENTERNAME       "You must select a configuration or enter a name before selecting Save...\n"
+    IDS_MUSTSELECTCONFIGFORDELETE 
+                            "You must select a configuration or enter a name before selecting Delete...\n"
+    IDS_DELETECONFIGCONFIRMATION 
+                            "Are you sure you want to Delete this configuration?\n"
+    IDS_DELETECONFIGTITLE   "Confirm Delete"
+    IDS_GFXCARDCHECK        "WinUAE will now determine your graphic-card's 16-bit pixel format.\nYour screen will go black for two seconds, with a resolution of 640x480 @ 60Hz.\nThis procedure is necessary to properly display your Amiga software on 16-bit\ndisplay-modes, and should be done whenever you run WinUAE for the first time, or\ninstall a new graphics-card in your PC.  Proceed with this test?\n"
+    IDS_GFXCARDTITLE        "Pixel Format Detection"
+    IDS_MUSTSELECTPATH      "You must select a path!"
+    IDS_SETTINGSERROR       "Settings Error"
+    IDS_MUSTSELECTNAME      "You must select a name for the volume!"
+    IDS_MUSTSELECTFILE      "You must select a file!"
+    IDS_FAILEDHARDFILECREATION "Failed to create hard-file..."
+    IDS_CREATIONERROR       "Creation Error"
+    IDS_ERRORTITLE          "WinUAE Message"
+END
+
+STRINGTABLE 
+BEGIN
+    IDS_SOUND_MONO          "Mono"
+    IDS_SOUND_MIXED         "Mixed"
+    IDS_SOUND_STEREO        "Stereo"
+    IDS_SOUND_INTERPOL_DISABLED "Disabled"
+    IDS_SOUND_INTERPOL_RH   "RH"
+    IDS_SOUND_INTERPOL_CRUX "Crux"
+    IDS_SOUND_FILTER_OFF    "Always off"
+    IDS_SOUND_FILTER_EMULATED "Emulated"
+END
+
+STRINGTABLE 
+BEGIN
+    IDS_SOUND_FILTER_ON     "Always on"
+    IDS_INPUT_COMPATIBILITY "Compatibility mode"
+    IDS_INPUT_CUSTOM        "Configuration #%d"
+    IDS_INPUT_COPY_DEFAULT  "Default"
+    IDS_INPUT_COPY_CUSTOM   "Config #%d"
+    IDS_3D_NO_FILTER        "Point (%d-bit)"
+    IDS_3D_BILINEAR         "Bilinear (%d-bit)"
+    IDS_VSYNC_DEFAULT       "Default"
+    IDS_DRIVESOUND_NONE     "No sound"
+    IDS_DRIVESOUND_DEFAULT_A500 "A500 (WinUAE built-in)"
+    IDS_AVIOUTPUT_NOCODEC   "no codec selected"
+    IDS_DISK_IMAGENAME      "Disk image"
+    IDS_DISK_DRIVENAME      "Drive"
+    IDS_AGA8BIT             "AGA emulation requires 16 bit or higher display depth\nSwitching from 8-bit to 16-bit"
+    IDS_UNSUPPORTEDSCREENMODE 
+                            "The selected screen mode can't be displayed in a window, because %s\nSwitching to full-screen display."
+    IDS_UNSUPPORTEDSCREENMODE_1 
+                            "the desktop is running in an unknown color mode."
+END
+
+STRINGTABLE 
+BEGIN
+    IDS_UNSUPPORTEDSCREENMODE_2 
+                            "the desktop is running in 8 bit color depth, which UAE can't use in windowed mode."
+    IDS_UNSUPPORTEDSCREENMODE_3 
+                            "the desktop is too small for the specified window size"
+    IDS_UNSUPPORTEDSCREENMODE_4 
+                            "you selected a Picasso96 display with a color depth different from that of the desktop and an overlay was unavailable."
+    IDS_FLOPPYTYPE35DD      "3.5"" DD"
+    IDS_FLOPPYTYPE35HD      "3.5"" HD"
+    IDS_FLOPPYTYPE525SD     "5.25"" SD"
+    IDS_FLOPPYTYPEDISABLED  "Disabled"
+    IDS_STMENUNOFLOPPY      "No disk inserted"
+    IDS_TREEVIEW_HARDWARE   "Hardware"
+    IDS_TREEVIEW_HOST       "Host"
+    IDS_TREEVIEW_MISC       "Misc"
+    IDS_TREEVIEW_SETTINGS   "Settings"
+    IDS_WINUAETITLE_MMB     "[Mouse active - press Alt-Tab or middle-button to cancel]"
+    IDS_WINUAETITLE_NORMAL  "[Mouse active - press Alt-Tab to cancel]"
+END
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/od-win32/resources/winuae_minimal.rc b/od-win32/resources/winuae_minimal.rc
new file mode 100755 (executable)
index 0000000..73b1b10
--- /dev/null
@@ -0,0 +1,1136 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+// Generated Help ID header file
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "resource.hm"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+#include "dlgs.h"
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_KICKSTART DIALOGEX 0, 0, 300, 175
+STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CAPTION
+EXSTYLE WS_EX_CONTEXTHELP
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    GROUPBOX        "Boot-ROM Settings:",-1,5,12,290,90
+    RTEXT           "ROM File:",IDC_ROMTEXT,10,27,75,10
+    EDITTEXT        IDC_ROMFILE,90,22,185,15,ES_AUTOHSCROLL
+    PUSHBUTTON      "...",IDC_KICKCHOOSER,280,22,10,15
+    RTEXT           "Key File:",IDC_KEYTEXT,10,48,75,10
+    EDITTEXT        IDC_KEYFILE,90,43,185,15,ES_AUTOHSCROLL
+    PUSHBUTTON      "...",IDC_KEYCHOOSER,280,43,10,15
+    RTEXT           "Extended ROM File:",IDC_ROMFILE2TEXT,10,68,75,10
+    EDITTEXT        IDC_ROMFILE2,90,63,185,15,ES_AUTOHSCROLL
+    PUSHBUTTON      "...",IDC_ROMCHOOSER2,280,63,10,15
+    CONTROL         "ShapeShifter support",IDC_KICKSHIFTER,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,196,86,80,10
+    GROUPBOX        "Misc settings:",-1,5,105,290,59
+    RTEXT           "Flash RAM File:",IDC_FLASHTEXT,8,119,75,10
+    EDITTEXT        IDC_FLASHFILE,89,117,185,15,ES_AUTOHSCROLL
+    PUSHBUTTON      "...",IDC_FLASHCHOOSER,279,117,10,15
+    RTEXT           "Cartridge ROM File:",IDC_FLASHTEXT2,8,140,75,10
+    EDITTEXT        IDC_CARTFILE,89,137,185,15,ES_AUTOHSCROLL
+    PUSHBUTTON      "...",IDC_CARTCHOOSER,279,137,10,15
+    CONTROL         "MAPROM emulation",IDC_MAPROM,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,104,86,80,10
+END
+
+IDD_DISPLAY DIALOGEX 0, 0, 300, 175
+STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CAPTION
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    GROUPBOX        "Amiga screen resolution",IDC_SCREENRESTEXT,24,0,185,67,
+                    BS_LEFT
+    RTEXT           "Fullscreen",IDC_SELECTRESTEXT,27,17,34,15,
+                    SS_CENTERIMAGE
+    COMBOBOX        IDC_RESOLUTION,66,27,72,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+    COMBOBOX        IDC_REFRESHRATE,142,27,60,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+    RTEXT           "Windowed",IDC_WINDOWEDTEXT,27,51,35,8
+    EDITTEXT        IDC_XSIZE,66,48,30,12,ES_NUMBER
+    EDITTEXT        IDC_YSIZE,108,48,30,12,ES_NUMBER
+    CONTROL         "VSync",IDC_VSYNC,"Button",BS_AUTOCHECKBOX | BS_LEFT | 
+                    WS_TABSTOP,146,48,54,10
+    GROUPBOX        "Settings",IDC_SETTINGSTEXT,24,72,186,73
+    CONTROL         "Full Screen",IDC_AFULLSCREEN,"Button",BS_AUTOCHECKBOX | 
+                    BS_LEFT | WS_TABSTOP,35,84,90,10
+    CONTROL         "Correct aspect ratio",IDC_ASPECT,"Button",
+                    BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,35,101,90,10
+    CONTROL         "Full Screen RTG",IDC_PFULLSCREEN,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,131,84,70,10,0,
+                    HIDC_PFULLSCREEN
+    LTEXT           "Refresh:",IDC_REFRESHTEXT,34,124,28,8
+    CONTROL         "Slider1",IDC_FRAMERATE,"msctls_trackbar32",
+                    TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,64,119,75,20
+    CTEXT           "",IDC_RATETEXT,144,119,50,20,SS_SUNKEN | WS_BORDER
+    GROUPBOX        "Centering",IDC_STATIC,217,0,58,67
+    CONTROL         "Horizontal",IDC_XCENTER,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,225,16,45,10
+    CONTROL         "Vertical",IDC_YCENTER,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,225,32,39,10
+    GROUPBOX        "Line mode",IDC_LINEMODE,217,72,58,74
+    CONTROL         "Normal",IDC_LM_NORMAL,"Button",BS_AUTORADIOBUTTON | 
+                    BS_LEFT | WS_GROUP | WS_TABSTOP,225,84,38,10
+    CONTROL         "Doubled",IDC_LM_DOUBLED,"Button",BS_AUTORADIOBUTTON | 
+                    BS_LEFT | WS_TABSTOP,225,100,43,10
+    CONTROL         "Scanline",IDC_LM_SCANLINES,"Button",BS_AUTORADIOBUTTON | 
+                    BS_LEFT | WS_TABSTOP,225,116,40,10
+    COMBOBOX        IDC_DA_MODE,35,151,58,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | NOT WS_VISIBLE | WS_VSCROLL | 
+                    WS_TABSTOP
+    CONTROL         "",IDC_DA_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | NOT WS_VISIBLE | WS_TABSTOP,97,147,101,20
+    PUSHBUTTON      "Detect pixel format",IDC_TEST16BIT,211,151,64,14,0,0,
+                    HIDC_TEST16BIT
+    COMBOBOX        IDC_DISPLAYSELECT,66,10,136,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+    CONTROL         "Lo-res",IDC_LORES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+                    131,101,70,10,0,HIDC_LORES
+END
+
+IDD_MEMORY DIALOGEX 0, 0, 300, 175
+STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CAPTION
+EXSTYLE WS_EX_CONTEXTHELP
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    GROUPBOX        "Memory Settings:",-1,19,40,260,93
+    RTEXT           "Chip:",-1,24,60,20,10,SS_CENTERIMAGE
+    CONTROL         "Slider1",IDC_CHIPMEM,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,54,55,50,20
+    CTEXT           "",IDC_CHIPRAM,104,55,35,20,SS_CENTERIMAGE | SS_SUNKEN | 
+                    WS_BORDER
+    RTEXT           "Fast:",IDC_FASTTEXT,24,85,20,10,SS_CENTERIMAGE
+    CONTROL         "Slider1",IDC_FASTMEM,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,54,80,50,20
+    CTEXT           "",IDC_FASTRAM,104,80,35,20,SS_CENTERIMAGE | SS_SUNKEN | 
+                    WS_BORDER
+    RTEXT           "Slow:",-1,149,60,20,10,SS_CENTERIMAGE
+    CONTROL         "Slider1",IDC_SLOWMEM,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,179,55,50,20
+    CTEXT           "",IDC_SLOWRAM,239,55,35,20,SS_CENTERIMAGE | SS_SUNKEN | 
+                    WS_BORDER
+    RTEXT           "Z3-Fast:",IDC_Z3TEXT,139,85,30,10,SS_CENTERIMAGE
+    CONTROL         "Slider1",IDC_Z3FASTMEM,"msctls_trackbar32",
+                    TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,179,80,60,20
+    CTEXT           "",IDC_Z3FASTRAM,239,80,35,20,SS_CENTERIMAGE | SS_SUNKEN | 
+                    WS_BORDER
+    RTEXT           "RTG (graphics card):",IDC_GFXCARDTEXT,96,110,76,10,
+                    SS_CENTERIMAGE
+    CONTROL         "Slider1",IDC_P96MEM,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,179,105,60,20
+    CTEXT           "",IDC_P96RAM,239,105,35,20,SS_CENTERIMAGE | SS_SUNKEN | 
+                    WS_BORDER
+END
+
+IDD_CPU DIALOGEX 0, 0, 300, 175
+STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CAPTION
+FONT 8, "MS Sans Serif", 0, 0, 0x0
+BEGIN
+    GROUPBOX        "CPU Type:",IDC_STATIC,5,5,80,134,BS_LEFT
+    CONTROL         "68000",IDC_CPU0,"Button",BS_AUTORADIOBUTTON | WS_GROUP | 
+                    WS_TABSTOP,10,18,34,10
+    CONTROL         "68010",IDC_CPU1,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,10,33,34,10
+    CONTROL         "68EC020",IDC_CPU2,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,10,48,45,10
+    CONTROL         "68EC020+FPU",IDC_CPU3,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,10,63,63,10
+    CONTROL         "68020",IDC_CPU4,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,10,78,34,10
+    CONTROL         "68020+FPU",IDC_CPU5,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,10,93,54,10
+    CONTROL         "68040",IDC_CPU6,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,10,108,36,10
+    CONTROL         "More compatible",IDC_COMPATIBLE,"Button",
+                    BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,10,123,
+                    70,10
+    GROUPBOX        "CPU Emulation Speed:",IDC_STATIC,90,5,205,86
+    CONTROL         "Fastest possible, but maintain chipset timing",
+                    IDC_CS_HOST,"Button",BS_AUTORADIOBUTTON | BS_LEFT | 
+                    WS_GROUP | WS_TABSTOP,95,18,195,10
+    CONTROL         "Match A500 speed",IDC_CS_68000,"Button",
+                    BS_AUTORADIOBUTTON | BS_LEFT | WS_TABSTOP,95,32,195,10
+    CONTROL         "Adjustable between CPU and chipset",IDC_CS_ADJUSTABLE,
+                    "Button",BS_AUTORADIOBUTTON | BS_LEFT | WS_TABSTOP,95,47,
+                    195,10
+    RTEXT           "CPU",IDC_CS_CPU_TEXT,96,71,15,10,SS_CENTERIMAGE | 
+                    WS_TABSTOP
+    CONTROL         "Slider1",IDC_SPEED,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,114,66,67,20
+    LTEXT           "Chipset",IDC_CS_CHIPSET_TEXT,182,71,25,10,
+                    SS_CENTERIMAGE | NOT WS_GROUP | WS_TABSTOP
+    RTEXT           "CPU Idle",IDC_CS_CPU_TEXT2,236,56,32,10,SS_CENTERIMAGE | 
+                    WS_TABSTOP
+    CONTROL         "",IDC_CPUIDLE,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,219,66,69,20
+    GROUPBOX        "JIT Settings:",IDC_STATIC,90,94,205,76
+    RTEXT           "Cache Size:",IDC_CS_CACHE_TEXT,95,109,45,10,
+                    SS_CENTERIMAGE | WS_TABSTOP
+    CONTROL         "Slider1",IDC_CACHE,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,140,104,115,20
+    EDITTEXT        IDC_CACHETEXT,255,109,30,12,ES_CENTER | ES_READONLY
+    CONTROL         "Hard Flush",IDC_HARDFLUSH,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,100,127,60,10
+    CONTROL         "Const Jump",IDC_CONSTJUMP,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,100,141,60,10
+    CONTROL         "FPU Support",IDC_JITFPU,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,100,154,60,10
+    CONTROL         "Force Settings",IDC_FORCE,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,165,127,61,10
+    CONTROL         "No Flags",IDC_NOFLAGS,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,165,141,60,10
+    CONTROL         "Direct",IDC_TRUST0,"Button",BS_AUTORADIOBUTTON | 
+                    WS_GROUP | WS_TABSTOP,230,127,34,10
+    CONTROL         "Indirect",IDC_TRUST1,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,230,141,45,10
+    CONTROL         "After Picasso96",IDC_TRUST2,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,230,154,64,10
+END
+
+IDD_FLOPPY DIALOGEX 0, 0, 300, 175
+STYLE DS_SETFONT | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION
+FONT 8, "MS Sans Serif", 0, 0, 0x0
+BEGIN
+    RTEXT           "DF0:",IDC_STATIC,3,16,20,15,SS_CENTERIMAGE
+    COMBOBOX        IDC_DF0TYPE,28,16,41,50,CBS_DROPDOWNLIST | WS_VSCROLL | 
+                    WS_TABSTOP
+    EDITTEXT        IDC_DF0TEXT,74,15,130,15,ES_AUTOHSCROLL
+    PUSHBUTTON      "...",IDC_DF0,208,15,10,15
+    PUSHBUTTON      "Eject",IDC_EJECT0,222,15,30,15
+    CONTROL         "Write protect",IDC_DF0WP,"Button",BS_AUTOCHECKBOX | 
+                    BS_MULTILINE | WS_TABSTOP,256,16,39,15
+    RTEXT           "DF1:",IDC_STATIC,3,41,20,15,SS_CENTERIMAGE
+    COMBOBOX        IDC_DF1TYPE,28,41,41,50,CBS_DROPDOWNLIST | WS_VSCROLL | 
+                    WS_TABSTOP
+    EDITTEXT        IDC_DF1TEXT,74,40,130,15,ES_AUTOHSCROLL
+    PUSHBUTTON      "...",IDC_DF1,208,40,10,15
+    PUSHBUTTON      "Eject",IDC_EJECT1,222,40,30,15
+    CONTROL         "Write protect",IDC_DF1WP,"Button",BS_AUTOCHECKBOX | 
+                    BS_MULTILINE | WS_TABSTOP,256,40,39,15
+    RTEXT           "DF2:",IDC_STATIC,3,66,20,15,SS_CENTERIMAGE
+    COMBOBOX        IDC_DF2TYPE,28,66,41,50,CBS_DROPDOWNLIST | WS_VSCROLL | 
+                    WS_TABSTOP
+    EDITTEXT        IDC_DF2TEXT,74,65,130,15,ES_AUTOHSCROLL
+    PUSHBUTTON      "...",IDC_DF2,208,65,10,15
+    PUSHBUTTON      "Eject",IDC_EJECT2,222,65,30,15
+    CONTROL         "Write protect",IDC_DF2WP,"Button",BS_AUTOCHECKBOX | 
+                    BS_MULTILINE | WS_TABSTOP,256,65,39,15
+    RTEXT           "DF3:",IDC_STATIC,3,90,20,15,SS_CENTERIMAGE
+    COMBOBOX        IDC_DF3TYPE,28,91,41,50,CBS_DROPDOWNLIST | WS_VSCROLL | 
+                    WS_TABSTOP
+    EDITTEXT        IDC_DF3TEXT,74,90,130,15,ES_AUTOHSCROLL
+    PUSHBUTTON      "...",IDC_DF3,208,90,10,15
+    PUSHBUTTON      "Eject",IDC_EJECT3,222,90,30,15
+    CONTROL         "Write protect",IDC_DF3WP,"Button",BS_AUTOCHECKBOX | 
+                    BS_MULTILINE | WS_TABSTOP,256,90,39,15
+    COMBOBOX        IDC_FLOPPYTYPE,28,118,41,50,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    PUSHBUTTON      "Create Standard ""Floppy""",IDC_CREATE,74,118,97,15
+    PUSHBUTTON      "Create Custom ""Floppy""",IDC_CREATE_RAW,182,118,87,15
+    RTEXT           "Floppy Speed:",IDC_FLOPPYSPD_TEXT,9,149,45,10,
+                    SS_CENTERIMAGE | WS_TABSTOP
+    CONTROL         "",IDC_FLOPPYSPD,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,56,145,120,20
+    EDITTEXT        IDC_FLOPPYSPDTEXT,177,148,68,12,ES_CENTER | ES_READONLY
+END
+
+IDD_HARDDISK DIALOGEX 0, 0, 300, 175
+STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CAPTION
+EXSTYLE WS_EX_CONTEXTHELP
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    CONTROL         "List1",IDC_VOLUMELIST,"SysListView32",LVS_REPORT | 
+                    LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | 
+                    LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,5,260,125
+    PUSHBUTTON      "",IDC_UP,270,25,25,15,BS_ICON
+    PUSHBUTTON      "",IDC_DOWN,270,105,25,15,BS_ICON
+    PUSHBUTTON      "Add &Directory...",IDC_NEW_FS,5,135,60,15
+    PUSHBUTTON      "Add &Hardfile...",IDC_NEW_HF,70,135,60,15
+    PUSHBUTTON      "Add Ha&rddrive",IDC_NEW_HD,135,135,60,15
+    CONTROL         "Add PC Drives at Startup",IDC_MAPDRIVES,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,5,155,105,10,0,
+                    HIDC_MAPDRIVES
+    PUSHBUTTON      "Remove",IDC_REMOVE,135,153,60,15
+    PUSHBUTTON      "&Properties",IDC_EDIT,200,153,60,15
+END
+
+IDD_SOUND DIALOGEX 0, 0, 300, 175
+STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CAPTION
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    RTEXT           "Sound Card:",IDC_SOUNDCARD,11,9,41,13,SS_CENTERIMAGE
+    COMBOBOX        IDC_SOUNDCARDLIST,60,9,221,50,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    GROUPBOX        "Sound Emulation",IDC_SOUNDSETTINGS,7,25,120,58
+    CONTROL         "Disabled",IDC_SOUND0,"Button",BS_AUTORADIOBUTTON | 
+                    WS_GROUP | WS_TABSTOP,15,35,43,10
+    CONTROL         "Disabled, but emulated",IDC_SOUND1,"Button",
+                    BS_AUTORADIOBUTTON | BS_LEFT | WS_TABSTOP,15,47,88,10
+    CONTROL         "Enabled",IDC_SOUND2,"Button",BS_AUTORADIOBUTTON | 
+                    BS_LEFT | WS_TABSTOP,15,59,42,10
+    CONTROL         "Enabled, 100% accurate",IDC_SOUND3,"Button",
+                    BS_AUTORADIOBUTTON | BS_LEFT | WS_TABSTOP,15,71,93,10
+    GROUPBOX        "Settings",IDC_SOUNDINTERPOLATION2,133,25,160,58
+    RTEXT           "Frequency:",IDC_SOUNDFREQTXT,138,33,37,8,SS_CENTERIMAGE
+    COMBOBOX        IDC_SOUNDFREQ,140,42,67,75,CBS_DROPDOWN | WS_VSCROLL | 
+                    WS_TABSTOP
+    RTEXT           "Audio filter:",IDC_SOUNDFILTERTXT,140,58,36,8,
+                    SS_CENTERIMAGE
+    COMBOBOX        IDC_SOUNDFILTER,140,67,67,75,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    GROUPBOX        "Sound buffer size",IDC_STATIC,7,108,120,29
+    CONTROL         "Slider1",IDC_SOUNDBUFFERRAM,"msctls_trackbar32",
+                    TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,14,116,106,19
+    CTEXT           "",IDC_SOUNDBUFFERMEM,134,116,40,16,SS_CENTERIMAGE | 
+                    SS_SUNKEN | WS_BORDER | WS_TABSTOP
+    GROUPBOX        "Sound driver lag compensation",IDC_STATIC,7,139,120,28
+    CONTROL         "Slider1",IDC_SOUNDADJUST,"msctls_trackbar32",
+                    TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,14,147,107,19
+    CTEXT           "",IDC_SOUNDADJUSTNUM,134,152,40,16,SS_CENTERIMAGE | 
+                    SS_SUNKEN | WS_BORDER | WS_TABSTOP
+    PUSHBUTTON      "Calibrate",IDC_SOUNDCALIBRATE,134,135,40,14
+    COMBOBOX        IDC_SOUNDSTEREO,220,42,67,75,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    COMBOBOX        IDC_SOUNDINTERPOLATION,220,67,67,75,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    RTEXT           "Stereo mode:",IDC_SOUNDSTEREOTXT,223,33,41,8,
+                    SS_CENTERIMAGE
+    RTEXT           "Interpolation:",IDC_SOUNDINTERPOLATIONTXT,222,58,41,8,
+                    SS_CENTERIMAGE
+    GROUPBOX        "Volume",IDC_STATIC,181,108,112,29
+    CONTROL         "",IDC_SOUNDVOLUME,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,183,116,107,19
+    COMBOBOX        IDC_SOUNDDRIVE,15,92,32,75,CBS_DROPDOWNLIST | WS_VSCROLL | 
+                    WS_TABSTOP
+    COMBOBOX        IDC_SOUNDDRIVESELECT,55,92,120,75,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    GROUPBOX        "Disk Drive Sound Emulation",IDC_STATIC,8,83,285,25
+    CONTROL         "",IDC_SOUNDDRIVEVOLUME,"msctls_trackbar32",
+                    TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,183,88,107,19
+END
+
+IDD_LOADSAVE DIALOGEX 0, 0, 300, 175
+STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_BORDER
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    CONTROL         "List1",IDC_CONFIGLIST,"SysListView32",LVS_REPORT | 
+                    LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | 
+                    LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | 
+                    WS_TABSTOP,5,5,290,105,0,HIDC_CONFIGLIST
+    RTEXT           "Name:",IDC_STATIC,20,115,25,15,SS_CENTERIMAGE
+    EDITTEXT        IDC_EDITNAME,50,115,155,15,ES_AUTOHSCROLL,0,
+                    HIDC_EDITNAME
+    RTEXT           "Description:",IDC_STATIC,5,135,40,15,SS_CENTERIMAGE
+    EDITTEXT        IDC_EDITDESCRIPTION,50,135,155,15,ES_AUTOHSCROLL,0,
+                    HIDC_EDITDESCRIPTION
+    GROUPBOX        "Extra Info",IDC_STATIC,210,115,85,35
+    PUSHBUTTON      "View",IDC_VIEWINFO,215,130,35,15
+    PUSHBUTTON      "Set",IDC_SETINFO,255,130,35,15
+    PUSHBUTTON      "Load",IDC_QUICKLOAD,5,155,40,15
+    PUSHBUTTON      "Save",IDC_QUICKSAVE,50,155,40,15
+    PUSHBUTTON      "Load From...",IDC_LOAD,100,155,45,15
+    PUSHBUTTON      "Save As...",IDC_SAVE,150,155,40,15
+    PUSHBUTTON      "Delete",IDC_DELETE,200,155,40,15
+    PUSHBUTTON      "Exit",IDC_EXIT,250,155,40,15
+END
+
+IDD_PORTS DIALOGEX 0, 0, 300, 175
+STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_BORDER
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    RTEXT           "Serial:",IDC_STATIC,20,15,25,15,SS_CENTERIMAGE
+    COMBOBOX        IDC_SERIAL,50,15,95,65,CBS_DROPDOWNLIST | WS_VSCROLL | 
+                    WS_TABSTOP
+    CONTROL         "Shared",IDC_SHARED,"Button",BS_AUTOCHECKBOX | 
+                    BS_VCENTER | WS_TABSTOP,33,32,37,12
+    CONTROL         "RTS/CTS",IDC_SER_CTSRTS,"Button",BS_AUTOCHECKBOX | 
+                    BS_VCENTER | WS_TABSTOP,77,32,44,12
+    CONTROL         "Direct",IDC_SERIAL_DIRECT,"Button",BS_AUTOCHECKBOX | 
+                    BS_VCENTER | WS_TABSTOP,128,32,40,12
+    RTEXT           "Printer:",IDC_STATIC,155,15,25,15,SS_CENTERIMAGE
+    COMBOBOX        IDC_PRINTERLIST,185,15,95,134,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    RTEXT           "MIDI Out:",IDC_MIDI,10,47,34,15,SS_CENTERIMAGE
+    COMBOBOX        IDC_MIDIOUTLIST,50,47,95,130,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    RTEXT           "MIDI In:",IDC_MIDI2,150,47,29,15,SS_CENTERIMAGE
+    COMBOBOX        IDC_MIDIINLIST,185,47,95,134,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    GROUPBOX        "Amiga Mouse Port 0",IDC_PORT0,20,65,105,100
+    CONTROL         "PC Joystick 0",IDC_PORT0_JOY0,"Button",
+                    BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,30,75,90,10
+    CONTROL         "PC Joystick 1",IDC_PORT0_JOY1,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,30,89,90,10
+    CONTROL         "PC Mouse",IDC_PORT0_MOUSE,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,30,104,90,11
+    CONTROL         "Keyboard Layout ""A""",IDC_PORT0_KBDA,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,30,120,90,10
+    CONTROL         "Keyboard Layout ""B""",IDC_PORT0_KBDB,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,30,135,90,10
+    CONTROL         "Keyboard Layout ""C""",IDC_PORT0_KBDC,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,30,150,90,10
+    GROUPBOX        "Amiga Mouse Port 1",IDC_PORT1,175,65,105,100
+    CONTROL         "PC Joystick 0",IDC_PORT1_JOY0,"Button",
+                    BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,185,75,90,10
+    CONTROL         "PC Joystick 1",IDC_PORT1_JOY1,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,185,89,90,10
+    CONTROL         "PC Mouse",IDC_PORT1_MOUSE,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,185,104,90,11
+    CONTROL         "Keyboard Layout ""A""",IDC_PORT1_KBDA,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,185,120,90,10
+    CONTROL         "Keyboard Layout ""B""",IDC_PORT1_KBDB,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,185,135,90,10
+    CONTROL         "Keyboard Layout ""C""",IDC_PORT1_KBDC,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,185,150,90,10
+    PUSHBUTTON      "<-swap->",IDC_SWAP,130,105,40,14
+END
+
+IDD_CONTRIBUTORS DIALOG  0, 0, 300, 175
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | WS_POPUP | 
+    WS_VISIBLE | WS_CAPTION
+CAPTION "UAE Authors and Contributors..."
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "OK",ID_OK,135,155,29,14
+    CONTROL         "",IDC_CONTRIBUTORS,"RICHEDIT",TCS_HOTTRACK | 
+                    TCS_VERTICAL | TCS_RAGGEDRIGHT | TCS_OWNERDRAWFIXED | 
+                    TCS_MULTISELECT | WS_BORDER | WS_VSCROLL | WS_HSCROLL | 
+                    WS_TABSTOP,5,5,290,145
+END
+
+IDD_ABOUT DIALOGEX 0, 0, 300, 175
+STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_BORDER
+FONT 8, "MS Sans Serif", 0, 0, 0x0
+BEGIN
+    CONTROL         "",IDC_RICHEDIT1,"RICHEDIT",TCS_SCROLLOPPOSITE | 
+                    TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,45,10,
+                    210,15
+    CONTROL         "",IDC_RICHEDIT2,"RICHEDIT",TCS_SCROLLOPPOSITE | 
+                    TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,20,30,
+                    260,13
+    PUSHBUTTON      "Contributors",IDC_CONTRIBUTORS,110,55,80,15
+    CONTROL         "",IDC_CLOANTOHOME,"RICHEDIT",TCS_SCROLLOPPOSITE | 
+                    TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,20,90,80,
+                    20
+    CONTROL         "",IDC_UAEHOME,"RICHEDIT",TCS_SCROLLOPPOSITE | 
+                    TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,20,120,
+                    80,15
+    CONTROL         "",IDC_PICASSOHOME,"RICHEDIT",TCS_SCROLLOPPOSITE | 
+                    TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,200,90,
+                    80,20
+    CONTROL         "",IDC_AMIGAHOME,"RICHEDIT",TCS_SCROLLOPPOSITE | 
+                    TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,110,90,
+                    80,15
+    CONTROL         "",IDC_WINUAEHOME,"RICHEDIT",TCS_SCROLLOPPOSITE | 
+                    TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,200,120,
+                    80,15
+    CONTROL         "",IDC_AIABHOME,"RICHEDIT",TCS_SCROLLOPPOSITE | 
+                    TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,110,120,
+                    80,15
+    CONTROL         "",IDC_THEROOTS,"RICHEDIT",TCS_SCROLLOPPOSITE | 
+                    TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,33,143,
+                    110,15
+    CONTROL         "",IDC_CAPS,"RICHEDIT",TCS_SCROLLOPPOSITE | 
+                    TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,150,143,
+                    110,15
+END
+
+IDD_MISC1 DIALOGEX 0, 0, 300, 175
+STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CAPTION
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    GROUPBOX        "Advanced:",IDC_STATIC,20,4,260,73
+    CONTROL         "Middle-Mouse-Button --> ALT-TAB",IDC_JULIAN,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,26,15,120,10
+    CONTROL         "Show GUI on startup",IDC_SHOWGUI,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,26,30,120,10
+    CONTROL         "On-Screen LEDs",IDC_SHOWLEDS,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,26,45,115,10
+    CONTROL         "UAEscsi.device",IDC_SCSIDEVICE,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,26,60,66,10
+    CONTROL         "BSDsocket.library emulation",IDC_SOCKETS,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,156,15,120,10
+    CONTROL         "Use CTRL-F11 to quit",IDC_CTRLF11,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,156,30,120,10
+    CONTROL         "Don't use RGB overlays",IDC_NOOVERLAY,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,156,45,120,10
+    CONTROL         "Use ASPI SCSI layer",IDC_ASPI,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,156,60,115,10
+    GROUPBOX        "Keyboard LEDs:",IDC_STATIC,20,82,68,73
+    COMBOBOX        IDC_KBLED1,26,95,56,65,CBS_DROPDOWNLIST | WS_VSCROLL | 
+                    WS_TABSTOP
+    COMBOBOX        IDC_KBLED2,26,114,56,65,CBS_DROPDOWNLIST | WS_VSCROLL | 
+                    WS_TABSTOP
+    COMBOBOX        IDC_KBLED3,26,134,56,65,CBS_DROPDOWNLIST | WS_VSCROLL | 
+                    WS_TABSTOP
+    GROUPBOX        "Logging:",IDC_STATIC,97,82,183,25
+    CONTROL         "Create log file",IDC_CREATELOGFILE,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,107,92,72,10,0,
+                    HIDC_CREATELOGFILE
+    CONTROL         "Illegal mem accesses",IDC_ILLEGAL,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,189,92,80,10
+    PUSHBUTTON      "Reset Amiga",IDC_RESETAMIGA,129,127,49,14
+    PUSHBUTTON      "Quit",IDC_QUITEMU,199,126,49,14
+END
+
+IDD_HARDFILE DIALOGEX 0, 0, 229, 164
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | 
+    DS_CENTERMOUSE | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Volume Settings"
+FONT 8, "MS Sans Serif", 0, 0, 0x0
+BEGIN
+    RTEXT           "Path:",IDC_HARDFILE_DIR_TEXT,19,21,22,10
+    EDITTEXT        IDC_PATH_NAME,44,15,151,15,ES_AUTOHSCROLL
+    PUSHBUTTON      "...",IDC_SELECTOR,200,15,11,15
+    RTEXT           "Sectors:",IDC_SECTORS_TEXT,80,80,30,10
+    EDITTEXT        IDC_SECTORS,115,75,27,15,ES_NUMBER
+    RTEXT           "Surfaces:",IDC_SURFACES_TEXT,75,58,35,10
+    EDITTEXT        IDC_HEADS,115,54,27,15,ES_NUMBER
+    RTEXT           "Reserved:",IDC_RESERVED_TEXT,145,58,35,10
+    EDITTEXT        IDC_RESERVED,185,54,27,15,ES_NUMBER
+    CONTROL         "Read/Write",IDC_RW,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,160,37,50,10
+    PUSHBUTTON      "OK",IDOK,115,143,50,14
+    PUSHBUTTON      "Cancel",IDCANCEL,171,143,50,14
+    PUSHBUTTON      "Create",IDC_CREATEHF,20,115,85,14
+    GROUPBOX        "New Hard File",IDC_STATIC,10,100,210,35
+    EDITTEXT        IDC_HFSIZE,110,115,60,15,ES_NUMBER
+    LTEXT           "MB",IDC_RESERVED_TEXT2,174,118,39,9,NOT WS_GROUP
+    GROUPBOX        "Hard File Settings",IDC_STATIC,10,5,210,90
+    RTEXT           "Block-Size:",IDC_BLOCKSIZE_TEXT,145,80,35,10
+    EDITTEXT        IDC_BLOCKSIZE,185,75,27,15,ES_NUMBER
+    RTEXT           "BootPri:",IDC_HARDFILE_BOOTPRI_TEXT,11,80,30,8
+    EDITTEXT        IDC_HARDFILE_BOOTPRI,44,75,32,15
+    RTEXT           "Device:",IDC_HARDFILE_DEVICE_TEXT,16,58,25,10
+    EDITTEXT        IDC_HARDFILE_DEVICE,44,54,32,15,ES_AUTOHSCROLL
+    RTEXT           "FileSys:",IDC_HARDFILE_FILESYS_TEXT,16,36,26,10
+    EDITTEXT        IDC_PATH_FILESYS,44,34,89,15,ES_AUTOHSCROLL
+    PUSHBUTTON      "...",IDC_FILESYS_SELECTOR,139,34,11,15
+END
+
+IDD_FILESYS DIALOGEX 15, 25, 229, 111
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | 
+    DS_CENTERMOUSE | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Volume Settings"
+FONT 8, "MS Sans Serif", 0, 0, 0x0
+BEGIN
+    LTEXT           "Device Name:",-1,5,9,54,10
+    EDITTEXT        IDC_VOLUME_DEVICE,65,5,85,15,ES_AUTOHSCROLL
+    LTEXT           "Volume Label:",-1,5,31,54,10
+    EDITTEXT        IDC_VOLUME_NAME,65,25,85,15,ES_AUTOHSCROLL
+    LTEXT           "Path:",-1,5,51,44,10
+    EDITTEXT        IDC_PATH_NAME,65,46,139,15,ES_AUTOHSCROLL
+    PUSHBUTTON      "...",IDC_SELECTOR,210,46,10,15
+    CONTROL         "Read/Write",IDC_RW,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,5,70,50,10
+    RTEXT           "BootPri:",IDC_VOLUME_BOOTPRI_TEXT,68,70,30,8
+    EDITTEXT        IDC_VOLUME_BOOTPRI,106,68,27,15
+    PUSHBUTTON      "OK",IDOK,120,91,48,15
+    PUSHBUTTON      "Cancel",IDCANCEL,175,91,48,15
+END
+
+IDD_SETINFO DIALOG  0, 0, 229, 85
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | 
+    DS_CENTERMOUSE | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Info Settings"
+FONT 8, "MS Sans Serif"
+BEGIN
+    RTEXT           "Path:",-1,5,20,24,15,SS_CENTERIMAGE
+    EDITTEXT        IDC_PATH_NAME,35,20,169,15,ES_AUTOHSCROLL
+    PUSHBUTTON      "...",IDC_SELECTOR,210,20,10,15
+    PUSHBUTTON      "OK",IDOK,120,65,48,15
+    PUSHBUTTON      "Cancel",IDCANCEL,175,65,48,15
+END
+
+IDD_CHIPSET DIALOG  0, 65490, 300, 175
+STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CAPTION
+FONT 8, "MS Sans Serif"
+BEGIN
+    GROUPBOX        "Chipset type",-1,22,11,142,82
+    CONTROL         "OCS",IDC_OCS,"Button",BS_AUTORADIOBUTTON | WS_GROUP | 
+                    WS_TABSTOP,41,31,30,10
+    CONTROL         "ECS Agnus",IDC_ECS_AGNUS,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,41,47,50,10
+    CONTROL         "ECS Denise",IDC_ECS_DENISE,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,41,63,50,10
+    CONTROL         "Full ECS",IDC_ECS,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,105,31,42,10
+    CONTROL         "AGA",IDC_AGA,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
+                    105,47,30,10
+    CONTROL         "NTSC",IDC_NTSC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+                    105,64,35,10
+    GROUPBOX        "Misc chipset options",-1,171,11,111,82
+    CONTROL         "Fast Copper",IDC_FASTCOPPER,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,178,31,53,10
+    CONTROL         "Immediate Blitter",IDC_BLITIMM,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,178,47,75,10
+    CONTROL         "Cycle exact CPU and Blitter",IDC_CYCLEEXACT,"Button",
+                    BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,178,64,
+                    100,10
+    GROUPBOX        "Collision level",-1,22,95,261,48
+    CONTROL         "None",IDC_COLLISION0,"Button",BS_AUTORADIOBUTTON | 
+                    WS_GROUP | WS_TABSTOP,40,111,50,10
+    CONTROL         "Sprites only",IDC_COLLISION1,"Button",
+                    BS_AUTORADIOBUTTON | WS_TABSTOP,40,127,50,10
+    CONTROL         "Sprites and Sprites vs. Playfield",IDC_COLLISION2,
+                    "Button",BS_AUTORADIOBUTTON | WS_TABSTOP,104,111,114,10
+    CONTROL         "Full",IDC_COLLISION3,"Button",BS_AUTORADIOBUTTON | 
+                    WS_TABSTOP,104,127,27,10
+END
+
+IDD_AVIOUTPUT DIALOGEX 0, 0, 300, 167
+STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    GROUPBOX        "Output Properties:",IDC_STATIC,5,8,152,91
+    EDITTEXT        IDC_AVIOUTPUT_FILETEXT,10,18,120,12,ES_AUTOHSCROLL | 
+                    ES_READONLY | NOT WS_BORDER,WS_EX_CLIENTEDGE
+    PUSHBUTTON      "...",IDC_AVIOUTPUT_FILE,132,18,19,12
+    CONTROL         "Audio",IDC_AVIOUTPUT_AUDIO,"Button",BS_AUTOCHECKBOX | 
+                    BS_PUSHLIKE | BS_FLAT | WS_TABSTOP,10,33,32,11
+    CONTROL         "",IDC_AVIOUTPUT_AUDIO_STATIC,"Static",SS_LEFTNOWORDWRAP | 
+                    SS_CENTERIMAGE | SS_SUNKEN | WS_GROUP,44,33,107,11
+    CONTROL         "Video",IDC_AVIOUTPUT_VIDEO,"Button",BS_AUTOCHECKBOX | 
+                    BS_PUSHLIKE | BS_FLAT | WS_TABSTOP,10,47,32,11
+    CONTROL         "",IDC_AVIOUTPUT_VIDEO_STATIC,"Static",SS_LEFTNOWORDWRAP | 
+                    SS_CENTERIMAGE | SS_SUNKEN | WS_GROUP,44,47,107,11
+    CONTROL         "Disable frame rate limit while recording",
+                    IDC_AVIOUTPUT_FRAMELIMITER,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,12,65,142,10
+    CONTROL         "AVIOutput enabled",IDC_AVIOUTPUT_ACTIVATED,"Button",
+                    BS_AUTORADIOBUTTON | BS_PUSHLIKE | BS_FLAT,10,80,142,12
+    GROUPBOX        "Playback Rate:",IDC_STATIC,5,100,152,33
+    CONTROL         "PAL",IDC_AVIOUTPUT_PAL,"Button",BS_AUTORADIOBUTTON | 
+                    BS_PUSHLIKE | BS_FLAT,10,110,66,8
+    CONTROL         "NTSC",IDC_AVIOUTPUT_NTSC,"Button",BS_AUTORADIOBUTTON | 
+                    BS_PUSHLIKE | BS_FLAT,81,110,66,8
+    CONTROL         "Slider1",IDC_AVIOUTPUT_FPS,"msctls_trackbar32",TBS_BOTH | 
+                    TBS_NOTICKS | TBS_ENABLESELRANGE | WS_TABSTOP,7,120,120,
+                    11
+    LTEXT           "fps",IDC_AVIOUTPUT_FPS_STATIC,127,120,23,8
+    GROUPBOX        "Frame / Video Dimensions:",IDC_STATIC,161,8,133,143,NOT 
+                    WS_VISIBLE
+    LTEXT           "Width:",IDC_STATIC,169,24,22,8,NOT WS_VISIBLE
+    EDITTEXT        IDC_AVIOUTPUT_WIDTH,193,22,30,12,ES_NUMBER | NOT 
+                    WS_VISIBLE
+    LTEXT           "Height:",IDC_STATIC,230,24,25,8,NOT WS_VISIBLE
+    EDITTEXT        IDC_AVIOUTPUT_HEIGHT,256,22,30,12,ES_NUMBER | NOT 
+                    WS_VISIBLE
+    CTEXT           "Actual:",IDC_AVIOUTPUT_DIMENSIONS_STATIC,170,38,116,9,
+                    NOT WS_VISIBLE
+    CONTROL         "",IDC_AVIOUTPUT_FRAME,"Static",SS_BLACKFRAME | NOT 
+                    WS_VISIBLE,170,50,116,80
+    PUSHBUTTON      "Save Screenshot",IDC_SCREENSHOT,25,143,95,12
+END
+
+IDD_INPUT DIALOGEX 0, 0, 300, 175
+STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CAPTION
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    COMBOBOX        IDC_INPUTTYPE,5,5,98,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+    COMBOBOX        IDC_INPUTDEVICE,109,4,167,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+    CONTROL         "",IDC_INPUTDEVICEDISABLE,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,282,7,9,8
+    CONTROL         "List1",IDC_INPUTLIST,"SysListView32",LVS_REPORT | 
+                    LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | 
+                    LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,22,290,81
+    COMBOBOX        IDC_INPUTAMIGACNT,5,109,24,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+    COMBOBOX        IDC_INPUTAMIGA,33,109,219,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+    CONTROL         "Autofire",IDC_INPUTAUTOFIRE,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,257,111,37,10
+    RTEXT           "Joystick dead zone (%):",-1,8,128,76,10,SS_CENTERIMAGE
+    EDITTEXT        IDC_INPUTDEADZONE,89,127,25,12,ES_NUMBER
+    RTEXT           "Autofire rate (frames):",-1,9,144,68,10,SS_CENTERIMAGE
+    EDITTEXT        IDC_INPUTAUTOFIRERATE,89,142,25,12,ES_NUMBER
+    RTEXT           "Digital joy-mouse speed:",-1,121,128,76,10,
+                    SS_CENTERIMAGE
+    EDITTEXT        IDC_INPUTSPEEDD,207,127,25,12,ES_NUMBER
+    RTEXT           "Analog joy-mouse speed:",-1,120,144,80,10,
+                    SS_CENTERIMAGE
+    EDITTEXT        IDC_INPUTSPEEDA,207,143,25,12,ES_NUMBER
+    RTEXT           "Mouse speed:",-1,132,160,68,10,SS_CENTERIMAGE
+    EDITTEXT        IDC_INPUTSPEEDM,207,159,25,12,ES_NUMBER
+    PUSHBUTTON      "Copy from:",IDC_INPUTCOPY,249,127,45,14
+    COMBOBOX        IDC_INPUTCOPYFROM,249,143,45,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+    PUSHBUTTON      "Swap 1<>2",IDC_INPUTSWAP,249,158,45,14
+END
+
+IDD_OPENGL DIALOGEX 0, 0, 300, 175
+STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CAPTION
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    GROUPBOX        "Filter settings:",-1,19,12,260,151
+    CONTROL         "Enable",IDC_OPENGLENABLE,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,26,27,38,10
+    COMBOBOX        IDC_OPENGLMODE,67,25,56,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+    COMBOBOX        IDC_OPENGLFILTER,128,25,65,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+    PUSHBUTTON      "Reset to defaults",IDC_OPENGLDEFAULT,197,25,73,14
+    RTEXT           "Horizontal Size",-1,25,49,57,10,SS_CENTERIMAGE
+    CONTROL         "Slider1",IDC_OPENGLHZ,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,89,42,158,19
+    CTEXT           "",IDC_OPENGLHZV,249,44,21,16,SS_CENTERIMAGE | SS_SUNKEN | 
+                    WS_BORDER | WS_TABSTOP
+    RTEXT           "Vertical Size",-1,26,69,57,10,SS_CENTERIMAGE
+    CONTROL         "Slider1",IDC_OPENGLVZ,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,89,62,157,19
+    CTEXT           "",IDC_OPENGLVZV,249,64,21,16,SS_CENTERIMAGE | SS_SUNKEN | 
+                    WS_BORDER | WS_TABSTOP
+    RTEXT           "Horizontal Position",-1,26,89,57,10,SS_CENTERIMAGE
+    CONTROL         "Slider1",IDC_OPENGLHO,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,89,82,157,19
+    CTEXT           "",IDC_OPENGLHOV,249,84,21,16,SS_CENTERIMAGE | SS_SUNKEN | 
+                    WS_BORDER | WS_TABSTOP
+    RTEXT           "Vertical Position",-1,26,108,57,10,SS_CENTERIMAGE
+    CONTROL         "Slider1",IDC_OPENGLVO,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,89,102,157,19
+    CTEXT           "",IDC_OPENGLVOV,249,104,21,16,SS_CENTERIMAGE | 
+                    SS_SUNKEN | WS_BORDER | WS_TABSTOP
+    RTEXT           "Scanlines",-1,27,130,57,10,SS_CENTERIMAGE
+    CONTROL         "Slider1",IDC_OPENGLSL,"msctls_trackbar32",TBS_AUTOTICKS | 
+                    TBS_TOP | WS_TABSTOP,89,123,157,19
+    CTEXT           "",IDC_OPENGLSLV,249,124,21,16,SS_CENTERIMAGE | 
+                    SS_SUNKEN | WS_BORDER | WS_TABSTOP
+    COMBOBOX        IDC_OPENGLSLR,56,143,27,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+    CONTROL         "Slider1",IDC_OPENGLSL2,"msctls_trackbar32",
+                    TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,89,143,157,19
+    CTEXT           "",IDC_OPENGLSL2V,249,143,21,16,SS_CENTERIMAGE | 
+                    SS_SUNKEN | WS_BORDER | WS_TABSTOP
+END
+
+IDD_HARDDRIVE DIALOGEX 0, 0, 229, 66
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | 
+    DS_CENTERMOUSE | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Harddrive Settings"
+FONT 8, "MS Sans Serif", 0, 0, 0x0
+BEGIN
+    LTEXT           "Harddrive:",-1,7,11,35,10
+    COMBOBOX        IDC_HARDDRIVE,49,9,173,150,CBS_DROPDOWNLIST | 
+                    CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+    CONTROL         "Read/Write",IDC_RW,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,15,30,50,10
+    DEFPUSHBUTTON   "OK",IDOK,116,47,50,14
+    PUSHBUTTON      "Cancel",IDCANCEL,172,47,50,14
+END
+
+IDD_MISC2 DIALOGEX 0, 0, 300, 175
+STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CAPTION
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+    GROUPBOX        "When Active:",IDC_STATIC,8,7,88,73
+    RTEXT           "Run at priority:",IDC_ACTIVE_PRI,14,17,45,10,
+                    SS_CENTERIMAGE | WS_TABSTOP
+    COMBOBOX        IDC_ACTIVE_PRIORITY,14,29,76,65,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    GROUPBOX        "When Inactive:",IDC_STATIC,102,7,92,73
+    RTEXT           "Run at priority:",IDC_INACTIVE_PRI,109,17,45,10,
+                    SS_CENTERIMAGE | WS_TABSTOP
+    COMBOBOX        IDC_INACTIVE_PRIORITY,109,29,76,65,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    CONTROL         "Pause emulation",IDC_INACTIVE_PAUSE,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,109,50,69,10
+    CONTROL         "Disable sound output",IDC_INACTIVE_NOSOUND,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,109,63,79,10
+    GROUPBOX        "When Minimized:",IDC_STATIC,199,7,92,73
+    RTEXT           "Run at priority:",IDC_MINIMIZED_PRI,207,18,45,10,
+                    SS_CENTERIMAGE | WS_TABSTOP
+    COMBOBOX        IDC_MINIMIZED_PRIORITY,207,30,76,65,CBS_DROPDOWNLIST | 
+                    WS_VSCROLL | WS_TABSTOP
+    CONTROL         "Pause emulation",IDC_MINIMIZED_PAUSE,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,207,50,69,10
+    CONTROL         "Disable sound output",IDC_MINIMIZED_NOSOUND,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,207,63,79,10
+    GROUPBOX        "State files:",IDC_STATIC,10,92,281,63
+    PUSHBUTTON      "Load state...",IDC_DOLOADSTATE,21,108,49,14
+    PUSHBUTTON      "Save state...",IDC_DOSAVESTATE,21,132,49,14
+    CONTROL         "Enable state recording",IDC_STATE_CAPTURE,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,160,103,88,10
+    RTEXT           "Recording rate (seconds)",IDC_STATE_RATE_TEXT,153,118,
+                    86,10,SS_CENTERIMAGE | WS_TABSTOP
+    COMBOBOX        IDC_STATE_RATE,244,116,38,65,CBS_DROPDOWN | WS_VSCROLL | 
+                    WS_TABSTOP
+    RTEXT           "Recording buffer (MB)",IDC_STATE_BUFFERSIZE_TEXT,153,
+                    138,83,10,SS_CENTERIMAGE | WS_TABSTOP
+    COMBOBOX        IDC_STATE_BUFFERSIZE,244,136,38,65,CBS_DROPDOWN | 
+                    WS_VSCROLL | WS_TABSTOP
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO 
+BEGIN
+    IDD_KICKSTART, DIALOG
+    BEGIN
+        BOTTOMMARGIN, 174
+    END
+
+    IDD_SOUND, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 293
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 168
+    END
+
+    IDD_LOADSAVE, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 293
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 168
+    END
+
+    IDD_PORTS, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 293
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 168
+    END
+
+    IDD_CONTRIBUTORS, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 293
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 168
+    END
+
+    IDD_ABOUT, DIALOG
+    BEGIN
+        RIGHTMARGIN, 299
+        BOTTOMMARGIN, 174
+    END
+
+    IDD_MISC1, DIALOG
+    BEGIN
+        BOTTOMMARGIN, 174
+        HORZGUIDE, 91
+    END
+
+    IDD_HARDFILE, DIALOG
+    BEGIN
+        BOTTOMMARGIN, 146
+    END
+
+    IDD_FILESYS, DIALOG
+    BEGIN
+        BOTTOMMARGIN, 85
+    END
+
+    IDD_OPENGL, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 293
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 168
+    END
+
+    IDD_MISC2, DIALOG
+    BEGIN
+        BOTTOMMARGIN, 173
+        HORZGUIDE, 91
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "#include ""dlgs.h""\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "\r\n"
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_APPICON             ICON                    "winuae.ico"
+IDI_FLOPPY              ICON                    "35floppy.ico"
+IDI_ABOUT               ICON                    "amigainfo.ico"
+IDI_CDROM               ICON                    "Cddrive.ico"
+IDI_HARDDISK            ICON                    "Drive.ico"
+IDI_SOUND               ICON                    "Volume01.ico"
+IDI_DISPLAY             ICON                    "Monitr01.ico"
+IDI_OPENGL              ICON                    "Monitr01.ico"
+IDI_CPU                 ICON                    "cpu.ico"
+IDI_LOADSAVE            ICON                    "35floppy.ico"
+IDI_PORTS               ICON                    "joystick.ico"
+IDI_INPUT               ICON                    "joystick.ico"
+IDI_MEMORY              ICON                    "Mycomp.ico"
+IDI_MISC1               ICON                    "misc.ico"
+IDI_MISC2               ICON                    "misc.ico"
+IDI_MOVE_UP             ICON                    "move_up.ico"
+IDI_MOVE_DOWN           ICON                    "move_dow.ico"
+IDI_AVIOUTPUT           ICON                    "avioutput.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,8,25,0
+ PRODUCTVERSION 0,8,25,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "FileDescription", "WinUAE"
+            VALUE "FileVersion", "0.8.25"
+            VALUE "InternalName", "WinUAE"
+            VALUE "LegalCopyright", "© 1996-2004 under the GNU Public License (GPL)"
+            VALUE "OriginalFilename", "WinUAE.exe"
+            VALUE "ProductName", "WinUAE"
+            VALUE "ProductVersion", "0.8.25"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Cursor
+//
+
+IDC_MYHAND              CURSOR                  "H_arrow.cur"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE 
+BEGIN
+    IDS_KICKSTART           "ROM"
+    IDS_DISPLAY             "Display"
+    IDS_HARDDISK            "Hard Drives"
+    IDS_FLOPPY              "Floppies"
+    IDS_ABOUT               "About"
+    IDS_LOADSAVE            "Configurations"
+    IDS_AVIOUTPUT           "Output"
+    IDS_PORTS               "Game and I/O Ports"
+    IDS_MISC1               "Misc"
+    IDS_MEMORY              "RAM"
+    IDS_CPU                 "CPU"
+    IDS_CHIPSET             "Chipset"
+    IDS_INPUT               "Input"
+    IDS_OPENGL              "Filter"
+END
+
+STRINGTABLE 
+BEGIN
+    IDS_MISC2               "Priority and state files"
+END
+
+STRINGTABLE 
+BEGIN
+    IDS_EXTTEXT             "Amiga Disk Files"
+    IDS_EXTACTUAL           "ADF"
+    IDS_SOUND               "Sound"
+    IDS_CDROM               "CD-ROM"
+    IDS_FRAMERATE           "Every %1Frame"
+    IDS_SECOND              "second "
+    IDS_THIRD               "third "
+    IDS_FOURTH              "fourth "
+    IDS_FIFTH               "fifth "
+    IDS_SIXTH               "sixth "
+    IDS_SEVENTH             "seventh "
+    IDS_EIGHTH              "eighth "
+END
+
+STRINGTABLE 
+BEGIN
+    IDS_NINTH               "ninth "
+    IDS_TENTH               "tenth "
+    IDS_SELECTADF           "Select an Amiga Disk File image..."
+    IDS_ADF                 "Amiga Disk Files"
+    IDS_CHOOSEBLANK         "Choose your blank Amiga Disk File..."
+    IDS_SELECTHDF           "Select a Hard Disk File..."
+    IDS_HDF                 "Hard Disk Files"
+    IDS_SELECTUAE           "Select a UAE Config-File..."
+    IDS_UAE                 "UAE Config Files"
+    IDS_SELECTROM           "Select an Amiga ROM file..."
+    IDS_ROM                 "Amiga Kickstart Files"
+    IDS_SELECTKEY           "Select an Amiga Key-File..."
+    IDS_KEY                 "Amiga Kickstart Key-Files"
+    IDS_SELECTINFO          "Select information for your config..."
+    IDS_NONE                "none"
+    IDS_VOLUME              "Volume"
+END
+
+STRINGTABLE 
+BEGIN
+    IDS_SELECTFILESYSROOT   "Please select your file-system root directory..."
+    IDS_DEFAULTMIDIOUT      "Default MIDI-Out Device"
+    IDS_CONTRIBUTORS1       "Bernd Schmidt - The Grand-Master\nSam Jordan - Custom-chip, floppy-DMA, etc.\nMathias Ortmann - Original WinUAE Main Guy, BSD Socket support\nBrian King - Picasso96 Support, Integrated GUI for WinUAE, previous WinUAE Main Guy\nToni Wilen - Core updates, WinUAE Main Guy\nGustavo Goedert/Peter Remmers/Michael Sontheimer/Tomi Hakala/Tim Gunn/Nemo Pohle - DOS Port Stuff\nSamuel Devulder/Olaf Barthel/Sam Jordan - Amiga Ports\nKrister Bergman - XFree86 and OS/2 Port\nA. Blanchard/Ernesto Corvi - MacOS Port\nChristian Bauer - BeOS Port\nIan Stephenson - NextStep Port\nPeter Teichmann - Acorn/RiscOS Port\nStefan Reinauer - ZorroII/III AutoConfig, Serial Support\nChristian Schmitt/Chris Hames - Serial Support\nHerman ten Brugge - 68020/68881 Emulation Code\nTauno Taipaleenmaki - Various UAE-Control/UAE-Library Support\nBrett Eden/Tim Gunn/Paolo Besser/Nemo Pohle - Various Docs and Web-Sites\nGeorg Veichtlbauer - Help File coordinator, German GUI\nFulvio Leonardi - Italian translator for WinUAE\n"
+    IDS_CONTRIBUTORS2       "Special thanks to Alexander Kneer and Tobias Abt (The Picasso96 Team)\n"
+    IDS_INVALIDPRTPORT      "The printer you have in this configuration is not valid on this machine.\n"
+    IDS_RESTOREUSS          "Restore a UAE Snap-Shot File"
+    IDS_USS                 "UAE Snap-Shot Files"
+    IDS_WRONGOSVERSION      "WinUAE is no longer supported on Windows NT.  Please upgrade to either Windows 2000 or Windows XP."
+    IDS_SELECTFLASH         "Select a flash/battery backed RAM file..."
+    IDS_FLASH               "UAE flash/battery backed RAM file"
+    IDS_INPUTHOSTWIDGET     "Input Source"
+    IDS_INPUTAMIGAEVENT     "Input Target"
+    IDS_INPUTAUTOFIRE       "Autofire"
+    IDS_SAVEUSS             "Save a UAE Snap-Shot File"
+    IDS_MIDIOVERFLOW        "Sysexbuffer overflow. Should not happen. Please report this to\nberndroesch1@compuserve.de"
+END
+
+STRINGTABLE 
+BEGIN
+    IDS_PATH                "Path"
+    IDS_RW                  "R/W"
+    IDS_SECTORS             "Sectors"
+    IDS_SURFACES            "Surfaces"
+    IDS_RESERVED            "Reserved"
+    IDS_BLOCKSIZE           "Block Size"
+    IDS_NAME                "Name"
+    IDS_DESCRIPTION         "Description"
+    IDS_ONEINSTANCE         "Only one instance of WinUAE can run at a time.\n"
+    IDS_INSTALLDIRECTX      "You have to install DirectX on your system before you can use UAE.\nRefer to the documentation for further details.\n"
+    IDS_REGKEYCREATEFAILED  "WinUAE could not create Registry keys!  You need administrator privileges.\n"
+    IDS_COULDNOTLOADCONFIG  "Could not load selected configuration!\n"
+    IDS_NOHELP              "Online help is disabled, because you have not installed the HtmlHelp system.  Go to http://msdn.microsoft.com/library/tools/htmlhelp/wkshp/download.htm to get HtmlHelp.\n"
+    IDS_MUSTSELECTCONFIG    "You must select a configuration or enter a name before selecting Load...\n"
+    IDS_INVALIDCOMPORT      "The COM-port you have in this configuration is not valid on this machine.\n"
+END
+
+STRINGTABLE 
+BEGIN
+    IDS_HFDSIZE             "Size"
+    IDS_DEVICE              "Device"
+    IDS_BOOTPRI             "BootPri"
+    IDS_WRONGDXVERSION      "WinUAE requires DirectX 8 or newer."
+END
+
+STRINGTABLE 
+BEGIN
+    IDS_WSOCK2NEEDED        "Please upgrade to Winsock2.\n"
+    IDS_UNSUPPORTEDPIXELFORMAT 
+                            "Error: Unsupported pixel format - use a different screen mode\n"
+    IDS_WAVEOUTOPENFAILURE  "Could not open WAVEOUT sound device!\n"
+    IDS_MUSTENTERNAME       "You must select a configuration or enter a name before selecting Save...\n"
+    IDS_MUSTSELECTCONFIGFORDELETE 
+                            "You must select a configuration or enter a name before selecting Delete...\n"
+    IDS_DELETECONFIGCONFIRMATION 
+                            "Are you sure you want to Delete this configuration?\n"
+    IDS_DELETECONFIGTITLE   "Confirm Delete"
+    IDS_GFXCARDCHECK        "WinUAE will now determine your graphic-card's 16-bit pixel format.\nYour screen will go black for two seconds, with a resolution of 640x480 @ 60Hz.\nThis procedure is necessary to properly display your Amiga software on 16-bit\ndisplay-modes, and should be done whenever you run WinUAE for the first time, or\ninstall a new graphics-card in your PC.  Proceed with this test?\n"
+    IDS_GFXCARDTITLE        "Pixel Format Detection"
+    IDS_MUSTSELECTPATH      "You must select a path!"
+    IDS_SETTINGSERROR       "Settings Error"
+    IDS_MUSTSELECTNAME      "You must select a name for the volume!"
+    IDS_MUSTSELECTFILE      "You must select a file!"
+    IDS_FAILEDHARDFILECREATION "Failed to create hard-file..."
+    IDS_CREATIONERROR       "Creation Error"
+    IDS_ERRORTITLE          "WinUAE Message"
+END
+
+STRINGTABLE 
+BEGIN
+    IDS_SOUND_MONO          "Mono"
+    IDS_SOUND_MIXED         "Mixed"
+    IDS_SOUND_STEREO        "Stereo"
+    IDS_SOUND_INTERPOL_DISABLED "Disabled"
+    IDS_SOUND_INTERPOL_RH   "RH"
+    IDS_SOUND_INTERPOL_CRUX "Crux"
+    IDS_SOUND_FILTER_OFF    "Always off"
+    IDS_SOUND_FILTER_EMULATED "Emulated"
+END
+
+STRINGTABLE 
+BEGIN
+    IDS_SOUND_FILTER_ON     "Always on"
+    IDS_INPUT_COMPATIBILITY "Compatibility mode"
+    IDS_INPUT_CUSTOM        "Configuration #%d"
+    IDS_INPUT_COPY_DEFAULT  "Default"
+    IDS_INPUT_COPY_CUSTOM   "Config #%d"
+    IDS_3D_NO_FILTER        "No filter (%d-bit)"
+    IDS_3D_BILINEAR         "Bilinear (%d-bit)"
+    IDS_VSYNC_DEFAULT       "Default"
+    IDS_DRIVESOUND_NONE     "No sound"
+    IDS_DRIVESOUND_DEFAULT_A500 "A500 (WinUAE built-in)"
+    IDS_AVIOUTPUT_NOCODEC   "no codec selected"
+END
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
diff --git a/od-win32/scaler.c b/od-win32/scaler.c
new file mode 100755 (executable)
index 0000000..51fae9f
--- /dev/null
@@ -0,0 +1,1527 @@
+/* This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/* Scaler (except Scale2x) code borrowed from ScummVM project */
+
+#include "filter.h"
+
+static uint32 colorMask;
+static uint32 lowPixelMask;
+static uint32 qcolorMask;
+static uint32 qlowpixelMask;
+static uint32 redblueMask;
+static uint32 redMask;
+static uint32 greenMask;
+static uint32 blueMask;
+
+int Init_2xSaI (int rb, int gb, int bb, int rs, int gs, int bs)
+{
+       if (rb + gb + bb == 16) {
+               colorMask = 0xF7DEF7DE;
+               lowPixelMask = 0x08210821;
+               qcolorMask = 0xE79CE79C;
+               qlowpixelMask = 0x18631863;
+               redblueMask = 0xF81F;
+               redMask = 0xF800;
+               greenMask = 0x07E0;
+               blueMask = 0x001F;
+       } else if (rb + gb + bb == 15) {
+               colorMask = 0x7BDE7BDE;
+               lowPixelMask = 0x04210421;
+               qcolorMask = 0x739C739C;
+               qlowpixelMask = 0x0C630C63;
+               redblueMask = 0x7C1F;
+               redMask = 0x7C00;
+               greenMask = 0x03E0;
+               blueMask = 0x001F;
+       } else {
+               return 0;
+       }
+
+       return 1;
+}
+
+static _inline int GetResult(uint32 A, uint32 B, uint32 C, uint32 D)
+{ 
+       const bool ac = (A==C);
+       const bool bc = (B==C);
+       const int x1 = ac;
+       const int y1 = (bc & !ac);
+       const bool ad = (A==D);
+       const bool bd = (B==D);
+       const int x2 = ad;
+       const int y2 = (bd & !ad);
+       const int x = x1+x2;
+       const int y = y1+y2;
+       static const int rmap[3][3] = {
+                       {0, 0, -1},
+                       {0, 0, -1},
+                       {1, 1,  0}
+               };
+       return rmap[y][x];
+}
+
+static _inline uint32 INTERPOLATE(uint32 A, uint32 B) {
+       if (A != B) {
+               return (((A & colorMask) >> 1) + ((B & colorMask) >> 1) + (A & B & lowPixelMask));
+       } else
+               return A;
+}
+
+static _inline uint32 Q_INTERPOLATE(uint32 A, uint32 B, uint32 C, uint32 D) {
+       register uint32 x = ((A & qcolorMask) >> 2) + ((B & qcolorMask) >> 2) + ((C & qcolorMask) >> 2) + ((D & qcolorMask) >> 2);
+       register uint32 y = ((A & qlowpixelMask) + (B & qlowpixelMask) + (C & qlowpixelMask) + (D & qlowpixelMask)) >> 2;
+
+       y &= qlowpixelMask;
+       return x + y;
+}
+
+void Super2xSaI(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
+       const uint16 *bP;
+       uint16 *dP;
+       const uint32 nextlineSrc = srcPitch >> 1;
+
+       while (height--) {
+               int i;
+               bP = (const uint16 *)srcPtr;
+               dP = (uint16 *)dstPtr;
+
+               for (i = 0; i < width; ++i) {
+                       uint32 color4, color5, color6;
+                       uint32 color1, color2, color3;
+                       uint32 colorA0, colorA1, colorA2, colorA3;
+                       uint32 colorB0, colorB1, colorB2, colorB3;
+                       uint32 colorS1, colorS2;
+                       uint32 product1a, product1b, product2a, product2b;
+
+//---------------------------------------    B1 B2
+//                                         4  5  6 S2
+//                                         1  2  3 S1
+//                                           A1 A2
+
+                       colorB0 = *(bP - nextlineSrc - 1);
+                       colorB1 = *(bP - nextlineSrc);
+                       colorB2 = *(bP - nextlineSrc + 1);
+                       colorB3 = *(bP - nextlineSrc + 2);
+
+                       color4 = *(bP - 1);
+                       color5 = *(bP);
+                       color6 = *(bP + 1);
+                       colorS2 = *(bP + 2);
+
+                       color1 = *(bP + nextlineSrc - 1);
+                       color2 = *(bP + nextlineSrc);
+                       color3 = *(bP + nextlineSrc + 1);
+                       colorS1 = *(bP + nextlineSrc + 2);
+
+                       colorA0 = *(bP + 2 * nextlineSrc - 1);
+                       colorA1 = *(bP + 2 * nextlineSrc);
+                       colorA2 = *(bP + 2 * nextlineSrc + 1);
+                       colorA3 = *(bP + 2 * nextlineSrc + 2);
+
+//--------------------------------------
+                       if (color2 == color6 && color5 != color3) {
+                               product2b = product1b = color2;
+                       } else if (color5 == color3 && color2 != color6) {
+                               product2b = product1b = color5;
+                       } else if (color5 == color3 && color2 == color6) {
+                               register int r = 0;
+
+                               r += GetResult(color6, color5, color1, colorA1);
+                               r += GetResult(color6, color5, color4, colorB1);
+                               r += GetResult(color6, color5, colorA2, colorS1);
+                               r += GetResult(color6, color5, colorB2, colorS2);
+
+                               if (r > 0)
+                                       product2b = product1b = color6;
+                               else if (r < 0)
+                                       product2b = product1b = color5;
+                               else {
+                                       product2b = product1b = INTERPOLATE(color5, color6);
+                               }
+                       } else {
+                               if (color6 == color3 && color3 == colorA1 && color2 != colorA2 && color3 != colorA0)
+                                       product2b = Q_INTERPOLATE(color3, color3, color3, color2);
+                               else if (color5 == color2 && color2 == colorA2 && colorA1 != color3 && color2 != colorA3)
+                                       product2b = Q_INTERPOLATE(color2, color2, color2, color3);
+                               else
+                                       product2b = INTERPOLATE(color2, color3);
+
+                               if (color6 == color3 && color6 == colorB1 && color5 != colorB2 && color6 != colorB0)
+                                       product1b = Q_INTERPOLATE(color6, color6, color6, color5);
+                               else if (color5 == color2 && color5 == colorB2 && colorB1 != color6 && color5 != colorB3)
+                                       product1b = Q_INTERPOLATE(color6, color5, color5, color5);
+                               else
+                                       product1b = INTERPOLATE(color5, color6);
+                       }
+
+                       if (color5 == color3 && color2 != color6 && color4 == color5 && color5 != colorA2)
+                               product2a = INTERPOLATE(color2, color5);
+                       else if (color5 == color1 && color6 == color5 && color4 != color2 && color5 != colorA0)
+                               product2a = INTERPOLATE(color2, color5);
+                       else
+                               product2a = color2;
+
+                       if (color2 == color6 && color5 != color3 && color1 == color2 && color2 != colorB2)
+                               product1a = INTERPOLATE(color2, color5);
+                       else if (color4 == color2 && color3 == color2 && color1 != color5 && color2 != colorB0)
+                               product1a = INTERPOLATE(color2, color5);
+                       else
+                               product1a = color5;
+
+                       *(dP + 0) = (uint16) product1a;
+                       *(dP + 1) = (uint16) product1b;
+                       *(dP + dstPitch/2 + 0) = (uint16) product2a;
+                       *(dP + dstPitch/2 + 1) = (uint16) product2b;
+
+                       bP += 1;
+                       dP += 2;
+               }
+
+               srcPtr += srcPitch;
+               dstPtr += dstPitch * 2;
+       }
+}
+
+void SuperEagle(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
+       const uint16 *bP;
+       uint16 *dP;
+       const uint32 nextlineSrc = srcPitch >> 1;
+
+       while (height--) {
+               int i;
+               bP = (const uint16 *)srcPtr;
+               dP = (uint16 *)dstPtr;
+               for (i = 0; i < width; ++i) {
+                       uint32 color4, color5, color6;
+                       uint32 color1, color2, color3;
+                       uint32 colorA1, colorA2, colorB1, colorB2, colorS1, colorS2;
+                       uint32 product1a, product1b, product2a, product2b;
+
+                       colorB1 = *(bP - nextlineSrc);
+                       colorB2 = *(bP - nextlineSrc + 1);
+
+                       color4 = *(bP - 1);
+                       color5 = *(bP);
+                       color6 = *(bP + 1);
+                       colorS2 = *(bP + 2);
+
+                       color1 = *(bP + nextlineSrc - 1);
+                       color2 = *(bP + nextlineSrc);
+                       color3 = *(bP + nextlineSrc + 1);
+                       colorS1 = *(bP + nextlineSrc + 2);
+
+                       colorA1 = *(bP + 2 * nextlineSrc);
+                       colorA2 = *(bP + 2 * nextlineSrc + 1);
+
+                       // --------------------------------------
+                       if (color5 != color3)
+                       {
+                               if (color2 == color6)
+                               {
+                                       product1b = product2a = color2;
+                                       if ((color1 == color2) || (color6 == colorB2)) {
+                                               product1a = INTERPOLATE(color2, color5);
+                                               product1a = INTERPOLATE(color2, product1a);
+                                       } else {
+                                               product1a = INTERPOLATE(color5, color6);
+                                       }
+
+                                       if ((color6 == colorS2) || (color2 == colorA1)) {
+                                               product2b = INTERPOLATE(color2, color3);
+                                               product2b = INTERPOLATE(color2, product2b);
+                                       } else {
+                                               product2b = INTERPOLATE(color2, color3);
+                                       }
+                               }
+                               else
+                               {
+                                       product2b = product1a = INTERPOLATE(color2, color6);
+                                       product2b = Q_INTERPOLATE(color3, color3, color3, product2b);
+                                       product1a = Q_INTERPOLATE(color5, color5, color5, product1a);
+
+                                       product2a = product1b = INTERPOLATE(color5, color3);
+                                       product2a = Q_INTERPOLATE(color2, color2, color2, product2a);
+                                       product1b = Q_INTERPOLATE(color6, color6, color6, product1b);
+                               }
+                       }
+                       else //if (color5 == color3)
+                       {
+                               if (color2 != color6)
+                               {
+                                       product2b = product1a = color5;
+
+                                       if ((colorB1 == color5) || (color3 == colorS1)) {
+                                               product1b = INTERPOLATE(color5, color6);
+                                               product1b = INTERPOLATE(color5, product1b);
+                                       } else {
+                                               product1b = INTERPOLATE(color5, color6);
+                                       }
+
+                                       if ((color3 == colorA2) || (color4 == color5)) {
+                                               product2a = INTERPOLATE(color5, color2);
+                                               product2a = INTERPOLATE(color5, product2a);
+                                       } else {
+                                               product2a = INTERPOLATE(color2, color3);
+                                       }
+                               }
+                               else    //if (color2 != color6)
+                               {
+                                       register int r = 0;
+
+                                       r += GetResult(color6, color5, color1, colorA1);
+                                       r += GetResult(color6, color5, color4, colorB1);
+                                       r += GetResult(color6, color5, colorA2, colorS1);
+                                       r += GetResult(color6, color5, colorB2, colorS2);
+
+                                       if (r > 0) {
+                                               product1b = product2a = color2;
+                                               product1a = product2b = INTERPOLATE(color5, color6);
+                                       } else if (r < 0) {
+                                               product2b = product1a = color5;
+                                               product1b = product2a = INTERPOLATE(color5, color6);
+                                       } else {
+                                               product2b = product1a = color5;
+                                               product1b = product2a = color2;
+                                       }
+                               }
+                       }
+
+                       *(dP + 0) = (uint16) product1a;
+                       *(dP + 1) = (uint16) product1b;
+                       *(dP + dstPitch/2 + 0) = (uint16) product2a;
+                       *(dP + dstPitch/2 + 1) = (uint16) product2b;
+
+                       bP += 1;
+                       dP += 2;
+               }
+
+               srcPtr += srcPitch;
+               dstPtr += dstPitch * 2;
+       }
+}
+
+void _2xSaI(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
+       const uint16 *bP;
+       uint16 *dP;
+       const uint32 nextlineSrc = srcPitch >> 1;
+
+       while (height--) {
+               int i;
+               bP = (const uint16 *)srcPtr;
+               dP = (uint16 *)dstPtr;
+
+               for (i = 0; i < width; ++i) {
+
+                       register uint32 colorA, colorB;
+                       uint32 colorC, colorD,
+                               colorE, colorF, colorG, colorH, colorI, colorJ, colorK, colorL, colorM, colorN, colorO, colorP;
+                       uint32 product, product1, product2;
+
+//---------------------------------------
+// Map of the pixels:                    I|E F|J
+//                                       G|A B|K
+//                                       H|C D|L
+//                                       M|N O|P
+                       colorI = *(bP - nextlineSrc - 1);
+                       colorE = *(bP - nextlineSrc);
+                       colorF = *(bP - nextlineSrc + 1);
+                       colorJ = *(bP - nextlineSrc + 2);
+
+                       colorG = *(bP - 1);
+                       colorA = *(bP);
+                       colorB = *(bP + 1);
+                       colorK = *(bP + 2);
+
+                       colorH = *(bP + nextlineSrc - 1);
+                       colorC = *(bP + nextlineSrc);
+                       colorD = *(bP + nextlineSrc + 1);
+                       colorL = *(bP + nextlineSrc + 2);
+
+                       colorM = *(bP + 2 * nextlineSrc - 1);
+                       colorN = *(bP + 2 * nextlineSrc);
+                       colorO = *(bP + 2 * nextlineSrc + 1);
+                       colorP = *(bP + 2 * nextlineSrc + 2);
+
+                       if ((colorA == colorD) && (colorB != colorC)) {
+                               if (((colorA == colorE) && (colorB == colorL)) ||
+                                       ((colorA == colorC) && (colorA == colorF) && (colorB != colorE) && (colorB == colorJ))) {
+                                       product = colorA;
+                               } else {
+                                       product = INTERPOLATE(colorA, colorB);
+                               }
+
+                               if (((colorA == colorG) && (colorC == colorO)) ||
+                                       ((colorA == colorB) && (colorA == colorH) && (colorG != colorC)  && (colorC == colorM))) {
+                                       product1 = colorA;
+                               } else {
+                                       product1 = INTERPOLATE(colorA, colorC);
+                               }
+                               product2 = colorA;
+                       } else if ((colorB == colorC) && (colorA != colorD)) {
+                               if (((colorB == colorF) && (colorA == colorH)) ||
+                                       ((colorB == colorE) && (colorB == colorD) && (colorA != colorF) && (colorA == colorI))) {
+                                       product = colorB;
+                               } else {
+                                       product = INTERPOLATE(colorA, colorB);
+                               }
+
+                               if (((colorC == colorH) && (colorA == colorF)) ||
+                                       ((colorC == colorG) && (colorC == colorD) && (colorA != colorH) && (colorA == colorI))) {
+                                       product1 = colorC;
+                               } else {
+                                       product1 = INTERPOLATE(colorA, colorC);
+                               }
+                               product2 = colorB;
+                       } else if ((colorA == colorD) && (colorB == colorC)) {
+                               if (colorA == colorB) {
+                                       product = colorA;
+                                       product1 = colorA;
+                                       product2 = colorA;
+                               } else {
+                                       register int r = 0;
+
+                                       product1 = INTERPOLATE(colorA, colorC);
+                                       product = INTERPOLATE(colorA, colorB);
+
+                                       r += GetResult(colorA, colorB, colorG, colorE);
+                                       r -= GetResult(colorB, colorA, colorK, colorF);
+                                       r -= GetResult(colorB, colorA, colorH, colorN);
+                                       r += GetResult(colorA, colorB, colorL, colorO);
+
+                                       if (r > 0)
+                                               product2 = colorA;
+                                       else if (r < 0)
+                                               product2 = colorB;
+                                       else {
+                                               product2 = Q_INTERPOLATE(colorA, colorB, colorC, colorD);
+                                       }
+                               }
+                       } else {
+                               product2 = Q_INTERPOLATE(colorA, colorB, colorC, colorD);
+
+                               if ((colorA == colorC) && (colorA == colorF)
+                                               && (colorB != colorE) && (colorB == colorJ)) {
+                                       product = colorA;
+                               } else if ((colorB == colorE) && (colorB == colorD)
+                                                                        && (colorA != colorF) && (colorA == colorI)) {
+                                       product = colorB;
+                               } else {
+                                       product = INTERPOLATE(colorA, colorB);
+                               }
+
+                               if ((colorA == colorB) && (colorA == colorH)
+                                               && (colorG != colorC) && (colorC == colorM)) {
+                                       product1 = colorA;
+                               } else if ((colorC == colorG) && (colorC == colorD)
+                                                                        && (colorA != colorH) && (colorA == colorI)) {
+                                       product1 = colorC;
+                               } else {
+                                       product1 = INTERPOLATE(colorA, colorC);
+                               }
+                       }
+
+                       *(dP + 0) = (uint16) colorA;
+                       *(dP + 1) = (uint16) product;
+                       *(dP + dstPitch/2 + 0) = (uint16) product1;
+                       *(dP + dstPitch/2 + 1) = (uint16) product2;
+
+                       bP += 1;
+                       dP += 2;
+               }
+
+               srcPtr += srcPitch;
+               dstPtr += dstPitch * 2;
+       }
+}
+
+
+/*
+ * This file is part of the Advance project.
+ *
+ * Copyright (C) 1999-2002 Andrea Mazzoleni
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * This file contains a C and MMX implentation of the Scale2x effect.
+ *
+ * You can found an high level description of the effect at :
+ *
+ * http://scale2x.sourceforge.net/scale2x.html
+ *
+ * Alternatively at the previous license terms, you are allowed to use this
+ * code in your program with these conditions:
+ * - the program is not used in commercial activities.
+ * - the whole source code of the program is released with the binary.
+ * - derivative works of the program are allowed.
+ */
+
+#define MMX
+extern int cpu_mmx;
+
+/* Suggested in "Intel Optimization" for Pentium II */
+#define ASM_JUMP_ALIGN ".p2align 4\n"
+
+static void internal_scale2x_16_def(u16 *dst0, u16* dst1, const u16* src0, const u16* src1, const u16* src2, unsigned count) {
+  /* first pixel */
+  dst0[0] = src1[0];
+  dst1[0] = src1[0];
+  if (src1[1] == src0[0] && src2[0] != src0[0])
+    dst0[1] =src0[0];
+  else
+    dst0[1] =src1[0];
+  if (src1[1] == src2[0] && src0[0] != src2[0])
+    dst1[1] =src2[0];
+  else
+    dst1[1] =src1[0];
+  ++src0;
+  ++src1;
+  ++src2;
+  dst0 += 2;
+  dst1 += 2;
+
+  /* central pixels */
+  count -= 2;
+  while (count) {
+    if (src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0])
+      dst0[0] = src0[0];
+    else
+      dst0[0] = src1[0];
+    if (src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0])
+      dst0[1] =src0[0];
+    else
+      dst0[1] =src1[0];
+
+    if (src1[-1] == src2[0] && src0[0] != src2[0] && src1[1] != src2[0])
+      dst1[0] =src2[0];
+    else
+      dst1[0] =src1[0];
+    if (src1[1] == src2[0] && src0[0] != src2[0] && src1[-1] != src2[0])
+      dst1[1] =src2[0];
+    else
+      dst1[1] =src1[0];
+
+    ++src0;
+    ++src1;
+    ++src2;
+    dst0 += 2;
+    dst1 += 2;
+    --count;
+  }
+
+  /* last pixel */
+  if (src1[-1] == src0[0] && src2[0] != src0[0])
+    dst0[0] =src0[0];
+  else
+    dst0[0] =src1[0];
+  if (src1[-1] == src2[0] && src0[0] != src2[0])
+    dst1[0] =src2[0];
+  else
+    dst1[0] =src1[0];
+  dst0[1] =src1[0];
+  dst1[1] =src1[0];
+}
+
+static void internal_scale2x_32_def(u32* dst0,
+                                    u32* dst1,
+                                    const u32* src0,
+                                    const u32* src1,
+                                    const u32* src2,
+                                    unsigned count) {
+  /* first pixel */
+  dst0[0] = src1[0];
+  dst1[0] = src1[0];
+  if (src1[1] == src0[0] && src2[0] != src0[0])
+    dst0[1] = src0[0];
+  else
+    dst0[1] = src1[0];
+  if (src1[1] == src2[0] && src0[0] != src2[0])
+    dst1[1] = src2[0];
+  else
+    dst1[1] = src1[0];
+  ++src0;
+  ++src1;
+  ++src2;
+  dst0 += 2;
+  dst1 += 2;
+
+  /* central pixels */
+  count -= 2;
+  while (count) {
+    if (src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0])
+      dst0[0] = src0[0];
+    else
+      dst0[0] = src1[0];
+    if (src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0])
+      dst0[1] = src0[0];
+    else
+      dst0[1] = src1[0];
+
+    if (src1[-1] == src2[0] && src0[0] != src2[0] && src1[1] != src2[0])
+      dst1[0] = src2[0];
+    else
+      dst1[0] = src1[0];
+    if (src1[1] == src2[0] && src0[0] != src2[0] && src1[-1] != src2[0])
+      dst1[1] = src2[0];
+    else
+      dst1[1] = src1[0];
+
+    ++src0;
+    ++src1;
+    ++src2;
+    dst0 += 2;
+    dst1 += 2;
+    --count;
+  }
+
+  /* last pixel */
+  if (src1[-1] == src0[0] && src2[0] != src0[0])
+    dst0[0] = src0[0];
+  else
+    dst0[0] = src1[0];
+  if (src1[-1] == src2[0] && src0[0] != src2[0])
+    dst1[0] = src2[0];
+  else
+    dst1[0] = src1[0];
+  dst0[1] = src1[0];
+  dst1[1] = src1[0];
+}
+
+#ifdef MMX
+static void internal_scale2x_16_mmx_single(u16* dst, const u16* src0, const u16* src1, const u16* src2, unsigned count) {
+  /* always do the first and last run */
+  count -= 2*4;
+
+#ifdef __GNUC__        
+  __asm__ __volatile__(
+                       /* first run */
+                       /* set the current, current_pre, current_next registers */
+                       "pxor %%mm0,%%mm0\n" /* use a fake black out of screen */
+                       "movq 0(%1),%%mm7\n"
+                       "movq 8(%1),%%mm1\n"
+                       "psrlq $48,%%mm0\n"
+                       "psllq $48,%%mm1\n"
+                       "movq %%mm7,%%mm2\n"
+                       "movq %%mm7,%%mm3\n"
+                       "psllq $16,%%mm2\n"
+                       "psrlq $16,%%mm3\n"
+                       "por %%mm2,%%mm0\n"
+                       "por %%mm3,%%mm1\n"
+
+                       /* current_upper */
+                       "movq (%0),%%mm6\n"
+
+                       /* compute the upper-left pixel for dst0 on %%mm2 */
+                       /* compute the upper-right pixel for dst0 on %%mm4 */
+                       "movq %%mm0,%%mm2\n"
+                       "movq %%mm1,%%mm4\n"
+                       "movq %%mm0,%%mm3\n"
+                       "movq %%mm1,%%mm5\n"
+                       "pcmpeqw %%mm6,%%mm2\n"
+                       "pcmpeqw %%mm6,%%mm4\n"
+                       "pcmpeqw (%2),%%mm3\n"
+                       "pcmpeqw (%2),%%mm5\n"
+                       "pandn %%mm2,%%mm3\n"
+                       "pandn %%mm4,%%mm5\n"
+                       "movq %%mm0,%%mm2\n"
+                       "movq %%mm1,%%mm4\n"
+                       "pcmpeqw %%mm1,%%mm2\n"
+                       "pcmpeqw %%mm0,%%mm4\n"
+                       "pandn %%mm3,%%mm2\n"
+                       "pandn %%mm5,%%mm4\n"
+                       "movq %%mm2,%%mm3\n"
+                       "movq %%mm4,%%mm5\n"
+                       "pand %%mm6,%%mm2\n"
+                       "pand %%mm6,%%mm4\n"
+                       "pandn %%mm7,%%mm3\n"
+                       "pandn %%mm7,%%mm5\n"
+                       "por %%mm3,%%mm2\n"
+                       "por %%mm5,%%mm4\n"
+
+                       /* set *dst0 */
+                       "movq %%mm2,%%mm3\n"
+                       "punpcklwd %%mm4,%%mm2\n"
+                       "punpckhwd %%mm4,%%mm3\n"
+                       "movq %%mm2,(%3)\n"
+                       "movq %%mm3,8(%3)\n"
+
+                       /* next */
+                       "addl $8,%0\n"
+                       "addl $8,%1\n"
+                       "addl $8,%2\n"
+                       "addl $16,%3\n"
+
+                       /* central runs */
+                       "shrl $2,%4\n"
+                       "jz 1f\n"
+                       ASM_JUMP_ALIGN
+                       "0:\n"
+
+                       /* set the current, current_pre, current_next registers */
+                       "movq -8(%1),%%mm0\n"
+                       "movq (%1),%%mm7\n"
+                       "movq 8(%1),%%mm1\n"
+                       "psrlq $48,%%mm0\n"
+                       "psllq $48,%%mm1\n"
+                       "movq %%mm7,%%mm2\n"
+                       "movq %%mm7,%%mm3\n"
+                       "psllq $16,%%mm2\n"
+                       "psrlq $16,%%mm3\n"
+                       "por %%mm2,%%mm0\n"
+                       "por %%mm3,%%mm1\n"
+
+                       /* current_upper */
+                       "movq (%0),%%mm6\n"
+
+                       /* compute the upper-left pixel for dst0 on %%mm2 */
+                       /* compute the upper-right pixel for dst0 on %%mm4 */
+                       "movq %%mm0,%%mm2\n"
+                       "movq %%mm1,%%mm4\n"
+                       "movq %%mm0,%%mm3\n"
+                       "movq %%mm1,%%mm5\n"
+                       "pcmpeqw %%mm6,%%mm2\n"
+                       "pcmpeqw %%mm6,%%mm4\n"
+                       "pcmpeqw (%2),%%mm3\n"
+                       "pcmpeqw (%2),%%mm5\n"
+                       "pandn %%mm2,%%mm3\n"
+                       "pandn %%mm4,%%mm5\n"
+                       "movq %%mm0,%%mm2\n"
+                       "movq %%mm1,%%mm4\n"
+                       "pcmpeqw %%mm1,%%mm2\n"
+                       "pcmpeqw %%mm0,%%mm4\n"
+                       "pandn %%mm3,%%mm2\n"
+                       "pandn %%mm5,%%mm4\n"
+                       "movq %%mm2,%%mm3\n"
+                       "movq %%mm4,%%mm5\n"
+                       "pand %%mm6,%%mm2\n"
+                       "pand %%mm6,%%mm4\n"
+                       "pandn %%mm7,%%mm3\n"
+                       "pandn %%mm7,%%mm5\n"
+                       "por %%mm3,%%mm2\n"
+                       "por %%mm5,%%mm4\n"
+
+                       /* set *dst0 */
+                       "movq %%mm2,%%mm3\n"
+                       "punpcklwd %%mm4,%%mm2\n"
+                       "punpckhwd %%mm4,%%mm3\n"
+                       "movq %%mm2,(%3)\n"
+                       "movq %%mm3,8(%3)\n"
+
+                       /* next */
+                       "addl $8,%0\n"
+                       "addl $8,%1\n"
+                       "addl $8,%2\n"
+                       "addl $16,%3\n"
+
+                       "decl %4\n"
+                       "jnz 0b\n"
+                       "1:\n"
+
+                       /* final run */
+                       /* set the current, current_pre, current_next registers */
+                       "movq -8(%1),%%mm0\n"
+                       "movq (%1),%%mm7\n"
+                       "pxor %%mm1,%%mm1\n" /* use a fake black out of screen */
+                       "psrlq $48,%%mm0\n"
+                       "psllq $48,%%mm1\n"
+                       "movq %%mm7,%%mm2\n"
+                       "movq %%mm7,%%mm3\n"
+                       "psllq $16,%%mm2\n"
+                       "psrlq $16,%%mm3\n"
+                       "por %%mm2,%%mm0\n"
+                       "por %%mm3,%%mm1\n"
+
+                       /* current_upper */
+                       "movq (%0),%%mm6\n"
+
+                       /* compute the upper-left pixel for dst0 on %%mm2 */
+                       /* compute the upper-right pixel for dst0 on %%mm4 */
+                       "movq %%mm0,%%mm2\n"
+                       "movq %%mm1,%%mm4\n"
+                       "movq %%mm0,%%mm3\n"
+                       "movq %%mm1,%%mm5\n"
+                       "pcmpeqw %%mm6,%%mm2\n"
+                       "pcmpeqw %%mm6,%%mm4\n"
+                       "pcmpeqw (%2),%%mm3\n"
+                       "pcmpeqw (%2),%%mm5\n"
+                       "pandn %%mm2,%%mm3\n"
+                       "pandn %%mm4,%%mm5\n"
+                       "movq %%mm0,%%mm2\n"
+                       "movq %%mm1,%%mm4\n"
+                       "pcmpeqw %%mm1,%%mm2\n"
+                       "pcmpeqw %%mm0,%%mm4\n"
+                       "pandn %%mm3,%%mm2\n"
+                       "pandn %%mm5,%%mm4\n"
+                       "movq %%mm2,%%mm3\n"
+                       "movq %%mm4,%%mm5\n"
+                       "pand %%mm6,%%mm2\n"
+                       "pand %%mm6,%%mm4\n"
+                       "pandn %%mm7,%%mm3\n"
+                       "pandn %%mm7,%%mm5\n"
+                       "por %%mm3,%%mm2\n"
+                       "por %%mm5,%%mm4\n"
+
+                       /* set *dst0 */
+                       "movq %%mm2,%%mm3\n"
+                       "punpcklwd %%mm4,%%mm2\n"
+                       "punpckhwd %%mm4,%%mm3\n"
+                       "movq %%mm2,(%3)\n"
+                       "movq %%mm3,8(%3)\n"
+                       "emms\n"
+
+                       : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count)
+                       :
+                       : "cc"
+                       );
+#else
+  __asm {
+    mov eax, src0;
+    mov ebx, src1;
+    mov ecx, src2;
+    mov edx, dst;
+    mov esi, count;
+          
+    /* first run */
+    /* set the current, current_pre, current_next registers */
+    pxor mm0,mm0; /* use a fake black out of screen */
+    movq mm7, qword ptr [ebx];
+    movq mm1, qword ptr [ebx + 8];
+    psrlq mm0, 48;
+    psllq mm1, 48;
+    movq mm2, mm7;
+    movq mm3, mm7;
+    psllq mm2, 16;
+    psrlq mm3, 16;
+    por mm0, mm2;
+    por mm1, mm3;
+
+    /* current_upper */
+    movq mm6, qword ptr [eax];
+
+    /* compute the upper-left pixel for dst0 on %%mm2 */
+    /* compute the upper-right pixel for dst0 on %%mm4 */
+    movq mm2, mm0;
+    movq mm4, mm1;
+    movq mm3, mm0;
+    movq mm5, mm1;
+    pcmpeqw mm2, mm6;
+    pcmpeqw mm4, mm6;
+    pcmpeqw mm3, qword ptr [ecx];
+    pcmpeqw mm5, qword ptr [ecx];
+    pandn mm3,mm2;
+    pandn mm5,mm4;
+    movq mm2,mm0;
+    movq mm4,mm1;
+    pcmpeqw mm2,mm1;
+    pcmpeqw mm4,mm0;
+    pandn mm2,mm3;
+    pandn mm4,mm5;
+    movq mm3,mm2;
+    movq mm5,mm4;
+    pand mm2,mm6;
+    pand mm4,mm6;
+    pandn mm3,mm7;
+    pandn mm5,mm7;
+    por mm2,mm3;
+    por mm4,mm5;
+
+    /* set *dst0 */
+    movq mm3,mm2;
+    punpcklwd mm2,mm4;
+    punpckhwd mm3,mm4;
+    movq qword ptr [edx], mm2;
+    movq qword ptr [edx + 8], mm3;
+
+    /* next */
+    add eax, 8;
+    add ebx, 8;
+    add ecx, 8;
+    add edx, 16;
+
+    /* central runs */
+    shr esi, 2;
+    jz label1;
+    align 4;
+  label0:
+
+    /* set the current, current_pre, current_next registers */
+    movq mm0, qword ptr [ebx-8];
+    movq mm7, qword ptr [ebx];
+    movq mm1, qword ptr [ebx+8];
+    psrlq mm0,48;
+    psllq mm1,48;
+    movq mm2,mm7;
+    movq mm3,mm7;
+    psllq mm2,16;
+    psrlq mm3,16;
+    por mm0,mm2;
+    por mm1,mm3;
+
+    /* current_upper */
+    movq mm6, qword ptr [eax];
+
+    /* compute the upper-left pixel for dst0 on %%mm2 */
+    /* compute the upper-right pixel for dst0 on %%mm4 */
+    movq mm2,mm0;
+    movq mm4,mm1;
+    movq mm3,mm0;
+    movq mm5,mm1;
+    pcmpeqw mm2,mm6;
+    pcmpeqw mm4,mm6;
+    pcmpeqw mm3, qword ptr [ecx];
+    pcmpeqw mm5, qword ptr [ecx];
+    pandn mm3,mm2;
+    pandn mm5,mm4;
+    movq mm2,mm0;
+    movq mm4,mm1;
+    pcmpeqw mm2,mm1;
+    pcmpeqw mm4,mm0;
+    pandn mm2,mm3;
+    pandn mm4,mm5;
+    movq mm3,mm2;
+    movq mm5,mm4;
+    pand mm2,mm6;
+    pand mm4,mm6;
+    pandn mm3,mm7;
+    pandn mm5,mm7;
+    por mm2,mm3;
+    por mm4,mm5;
+
+    /* set *dst0 */
+    movq mm3,mm2;
+    punpcklwd mm2,mm4;
+    punpckhwd mm3,mm4;
+    movq qword ptr [edx], mm2;
+    movq qword ptr [edx+8], mm3;
+
+    /* next */
+    add eax,8;
+    add ebx,8;
+    add ecx,8;
+    add edx,16;
+          
+    dec esi;
+    jnz label0;
+  label1:
+
+    /* final run */
+    /* set the current, current_pre, current_next registers */
+    movq mm0, qword ptr [ebx-8];
+    movq mm7, qword ptr [ebx];
+    pxor mm1,mm1; /* use a fake black out of screen */
+    psrlq mm0,48;
+    psllq mm1,48;
+    movq mm2,mm7;
+    movq mm3,mm7;
+    psllq mm2,16;
+    psrlq mm3,16;
+    por mm0,mm2;
+    por mm1,mm3;
+
+    /* current_upper */
+    movq mm6, qword ptr [eax];
+
+    /* compute the upper-left pixel for dst0 on %%mm2 */
+    /* compute the upper-right pixel for dst0 on %%mm4 */
+    movq mm2,mm0;
+    movq mm4,mm1;
+    movq mm3,mm0;
+    movq mm5,mm1;
+    pcmpeqw mm2,mm6;
+    pcmpeqw mm4,mm6;
+    pcmpeqw mm3, qword ptr [ecx];
+    pcmpeqw mm5, qword ptr [ecx];
+    pandn mm3,mm2;
+    pandn mm5,mm4;
+    movq mm2,mm0;
+    movq mm4,mm1;
+    pcmpeqw mm2,mm1;
+    pcmpeqw mm4,mm0;
+    pandn mm2,mm3;
+    pandn mm4,mm5;
+    movq mm3,mm2;
+    movq mm5,mm4;
+    pand mm2,mm6;
+    pand mm4,mm6;
+    pandn mm3,mm7;
+    pandn mm5,mm7;
+    por mm2,mm3;
+    por mm4,mm5;
+
+    /* set *dst0 */
+    movq mm3,mm2;
+    punpcklwd mm2,mm4;
+    punpckhwd mm3,mm4;
+    movq qword ptr [edx], mm2;
+    movq qword ptr [edx+8], mm3;
+
+    mov src0, eax;
+    mov src1, ebx;
+    mov src2, ecx;
+    mov dst, edx;
+    mov count, esi;
+
+    emms;
+  }
+#endif
+}
+
+static void internal_scale2x_32_mmx_single(u32* dst, const u32* src0, const u32* src1, const u32* src2, unsigned count) {
+  /* always do the first and last run */
+  count -= 2*2;
+
+#ifdef __GNUC__
+  __asm__ __volatile__(
+                       /* first run */
+                       /* set the current, current_pre, current_next registers */
+                       "pxor %%mm0,%%mm0\n" /* use a fake black out of screen */
+                       "movq 0(%1),%%mm7\n"
+                       "movq 8(%1),%%mm1\n"
+                       "psrlq $32,%%mm0\n"
+                       "psllq $32,%%mm1\n"
+                       "movq %%mm7,%%mm2\n"
+                       "movq %%mm7,%%mm3\n"
+                       "psllq $32,%%mm2\n"
+                       "psrlq $32,%%mm3\n"
+                       "por %%mm2,%%mm0\n"
+                       "por %%mm3,%%mm1\n"
+
+                       /* current_upper */
+                       "movq (%0),%%mm6\n"
+
+                       /* compute the upper-left pixel for dst0 on %%mm2 */
+                       /* compute the upper-right pixel for dst0 on %%mm4 */
+                       "movq %%mm0,%%mm2\n"
+                       "movq %%mm1,%%mm4\n"
+                       "movq %%mm0,%%mm3\n"
+                       "movq %%mm1,%%mm5\n"
+                       "pcmpeqd %%mm6,%%mm2\n"
+                       "pcmpeqd %%mm6,%%mm4\n"
+                       "pcmpeqd (%2),%%mm3\n"
+                       "pcmpeqd (%2),%%mm5\n"
+                       "pandn %%mm2,%%mm3\n"
+                       "pandn %%mm4,%%mm5\n"
+                       "movq %%mm0,%%mm2\n"
+                       "movq %%mm1,%%mm4\n"
+                       "pcmpeqd %%mm1,%%mm2\n"
+                       "pcmpeqd %%mm0,%%mm4\n"
+                       "pandn %%mm3,%%mm2\n"
+                       "pandn %%mm5,%%mm4\n"
+                       "movq %%mm2,%%mm3\n"
+                       "movq %%mm4,%%mm5\n"
+                       "pand %%mm6,%%mm2\n"
+                       "pand %%mm6,%%mm4\n"
+                       "pandn %%mm7,%%mm3\n"
+                       "pandn %%mm7,%%mm5\n"
+                       "por %%mm3,%%mm2\n"
+                       "por %%mm5,%%mm4\n"
+
+                       /* set *dst0 */
+                       "movq %%mm2,%%mm3\n"
+                       "punpckldq %%mm4,%%mm2\n"
+                       "punpckhdq %%mm4,%%mm3\n"
+                       "movq %%mm2,(%3)\n"
+                       "movq %%mm3,8(%3)\n"
+
+                       /* next */
+                       "addl $8,%0\n"
+                       "addl $8,%1\n"
+                       "addl $8,%2\n"
+                       "addl $16,%3\n"
+
+                       /* central runs */
+                       "shrl $1,%4\n"
+                       "jz 1f\n"
+                       ASM_JUMP_ALIGN
+                       "0:\n"
+
+                       /* set the current, current_pre, current_next registers */
+                       "movq -8(%1),%%mm0\n"
+                       "movq (%1),%%mm7\n"
+                       "movq 8(%1),%%mm1\n"
+                       "psrlq $32,%%mm0\n"
+                       "psllq $32,%%mm1\n"
+                       "movq %%mm7,%%mm2\n"
+                       "movq %%mm7,%%mm3\n"
+                       "psllq $32,%%mm2\n"
+                       "psrlq $32,%%mm3\n"
+                       "por %%mm2,%%mm0\n"
+                       "por %%mm3,%%mm1\n"
+
+                       /* current_upper */
+                       "movq (%0),%%mm6\n"
+
+                       /* compute the upper-left pixel for dst0 on %%mm2 */
+                       /* compute the upper-right pixel for dst0 on %%mm4 */
+                       "movq %%mm0,%%mm2\n"
+                       "movq %%mm1,%%mm4\n"
+                       "movq %%mm0,%%mm3\n"
+                       "movq %%mm1,%%mm5\n"
+                       "pcmpeqd %%mm6,%%mm2\n"
+                       "pcmpeqd %%mm6,%%mm4\n"
+                       "pcmpeqd (%2),%%mm3\n"
+                       "pcmpeqd (%2),%%mm5\n"
+                       "pandn %%mm2,%%mm3\n"
+                       "pandn %%mm4,%%mm5\n"
+                       "movq %%mm0,%%mm2\n"
+                       "movq %%mm1,%%mm4\n"
+                       "pcmpeqd %%mm1,%%mm2\n"
+                       "pcmpeqd %%mm0,%%mm4\n"
+                       "pandn %%mm3,%%mm2\n"
+                       "pandn %%mm5,%%mm4\n"
+                       "movq %%mm2,%%mm3\n"
+                       "movq %%mm4,%%mm5\n"
+                       "pand %%mm6,%%mm2\n"
+                       "pand %%mm6,%%mm4\n"
+                       "pandn %%mm7,%%mm3\n"
+                       "pandn %%mm7,%%mm5\n"
+                       "por %%mm3,%%mm2\n"
+                       "por %%mm5,%%mm4\n"
+
+                       /* set *dst0 */
+                       "movq %%mm2,%%mm3\n"
+                       "punpckldq %%mm4,%%mm2\n"
+                       "punpckhdq %%mm4,%%mm3\n"
+                       "movq %%mm2,(%3)\n"
+                       "movq %%mm3,8(%3)\n"
+
+                       /* next */
+                       "addl $8,%0\n"
+                       "addl $8,%1\n"
+                       "addl $8,%2\n"
+                       "addl $16,%3\n"
+
+                       "decl %4\n"
+                       "jnz 0b\n"
+                       "1:\n"
+
+                       /* final run */
+                       /* set the current, current_pre, current_next registers */
+                       "movq -8(%1),%%mm0\n"
+                       "movq (%1),%%mm7\n"
+                       "pxor %%mm1,%%mm1\n" /* use a fake black out of screen */
+                       "psrlq $32,%%mm0\n"
+                       "psllq $32,%%mm1\n"
+                       "movq %%mm7,%%mm2\n"
+                       "movq %%mm7,%%mm3\n"
+                       "psllq $32,%%mm2\n"
+                       "psrlq $32,%%mm3\n"
+                       "por %%mm2,%%mm0\n"
+                       "por %%mm3,%%mm1\n"
+
+                       /* current_upper */
+                       "movq (%0),%%mm6\n"
+
+                       /* compute the upper-left pixel for dst0 on %%mm2 */
+                       /* compute the upper-right pixel for dst0 on %%mm4 */
+                       "movq %%mm0,%%mm2\n"
+                       "movq %%mm1,%%mm4\n"
+                       "movq %%mm0,%%mm3\n"
+                       "movq %%mm1,%%mm5\n"
+                       "pcmpeqd %%mm6,%%mm2\n"
+                       "pcmpeqd %%mm6,%%mm4\n"
+                       "pcmpeqd (%2),%%mm3\n"
+                       "pcmpeqd (%2),%%mm5\n"
+                       "pandn %%mm2,%%mm3\n"
+                       "pandn %%mm4,%%mm5\n"
+                       "movq %%mm0,%%mm2\n"
+                       "movq %%mm1,%%mm4\n"
+                       "pcmpeqd %%mm1,%%mm2\n"
+                       "pcmpeqd %%mm0,%%mm4\n"
+                       "pandn %%mm3,%%mm2\n"
+                       "pandn %%mm5,%%mm4\n"
+                       "movq %%mm2,%%mm3\n"
+                       "movq %%mm4,%%mm5\n"
+                       "pand %%mm6,%%mm2\n"
+                       "pand %%mm6,%%mm4\n"
+                       "pandn %%mm7,%%mm3\n"
+                       "pandn %%mm7,%%mm5\n"
+                       "por %%mm3,%%mm2\n"
+                       "por %%mm5,%%mm4\n"
+
+                       /* set *dst0 */
+                       "movq %%mm2,%%mm3\n"
+                       "punpckldq %%mm4,%%mm2\n"
+                       "punpckhdq %%mm4,%%mm3\n"
+                       "movq %%mm2,(%3)\n"
+                       "movq %%mm3,8(%3)\n"
+                       "emms\n"
+
+                       : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count)
+                       :
+                       : "cc"
+                       );
+#else
+  __asm {
+    mov eax, src0;
+    mov ebx, src1;
+    mov ecx, src2;
+    mov edx, dst;
+    mov esi, count;
+    
+    /* first run */
+    /* set the current, current_pre, current_next registers */
+    pxor mm0,mm0;
+    movq mm7,qword ptr [ebx];
+    movq mm1,qword ptr [ebx + 8];
+    psrlq mm0,32;
+    psllq mm1,32;
+    movq mm2,mm7;
+    movq mm3,mm7;
+    psllq mm2,32;
+    psrlq mm3,32;
+    por mm0,mm2;
+    por mm1,mm3;
+
+    /* current_upper */
+    movq mm6,qword ptr [eax];
+
+    /* compute the upper-left pixel for dst0 on %%mm2 */
+    /* compute the upper-right pixel for dst0 on %%mm4 */
+    movq mm2,mm0;
+    movq mm4,mm1;
+    movq mm3,mm0;
+    movq mm5,mm1;
+    pcmpeqd mm2,mm6;
+    pcmpeqd mm4,mm6;
+    pcmpeqd mm3,qword ptr [ecx];
+    pcmpeqd mm5,qword ptr [ecx];
+    pandn mm3,mm2;
+    pandn mm5,mm4;
+    movq mm2,mm0;
+    movq mm4,mm1;
+    pcmpeqd mm2,mm1;
+    pcmpeqd mm4,mm0;
+    pandn mm2,mm3;
+    pandn mm4,mm5;
+    movq mm3,mm2;
+    movq mm5,mm4;
+    pand mm2,mm6;
+    pand mm4,mm6;
+    pandn mm3,mm7;
+    pandn mm5,mm7;
+    por mm2,mm3;
+    por mm4,mm5;
+
+    /* set *dst0 */
+    movq mm3,mm2;
+    punpckldq mm2,mm4;
+    punpckhdq mm3,mm4;
+    movq qword ptr [edx],mm2;
+    movq qword ptr [edx+8],mm3;
+
+    /* next */
+    add eax,8;
+    add ebx,8;
+    add ecx,8;
+    add edx,16;
+
+    /* central runs */
+    shr esi,1;
+    jz label1;
+label0:
+    
+  /* set the current, current_pre, current_next registers */
+    movq mm0,qword ptr [ebx-8];
+    movq mm7,qword ptr [ebx];
+    movq mm1,qword ptr [ebx+8];
+    psrlq mm0,32;
+    psllq mm1,32;
+    movq mm2,mm7;
+    movq mm3,mm7;
+    psllq mm2,32;
+    psrlq mm3,32;
+    por mm0,mm2;
+    por mm1,mm3;
+
+    /* current_upper */
+    movq mm6,qword ptr[eax];
+
+    /* compute the upper-left pixel for dst0 on %%mm2 */
+    /* compute the upper-right pixel for dst0 on %%mm4 */
+    movq mm2,mm0;
+    movq mm4,mm1;
+    movq mm3,mm0;
+    movq mm5,mm1;
+    pcmpeqd mm2,mm6;
+    pcmpeqd mm4,mm6;
+    pcmpeqd mm3,qword ptr[ecx];
+    pcmpeqd mm5,qword ptr[ecx];
+    pandn mm3,mm2;
+    pandn mm5,mm4;
+    movq mm2,mm0;
+    movq mm4,mm1;
+    pcmpeqd mm2,mm1;
+    pcmpeqd mm4,mm0;
+    pandn mm2,mm3;
+    pandn mm4,mm5;
+    movq mm3,mm2;
+    movq mm5,mm4;
+    pand mm2,mm6;
+    pand mm4,mm6;
+    pandn mm3,mm7;
+    pandn mm5,mm7;
+    por mm2,mm3;
+    por mm4,mm5;
+
+    /* set *dst0 */
+    movq mm3,mm2;
+    punpckldq mm2,mm4;
+    punpckhdq mm3,mm4;
+    movq qword ptr [edx],mm2;
+    movq qword ptr [edx+8],mm3;
+
+    /* next */
+    add eax,8;
+    add ebx,8;
+    add ecx,8;
+    add edx,16;
+
+    dec esi;
+    jnz label0;
+label1:
+    
+    /* final run */
+    /* set the current, current_pre, current_next registers */
+    movq mm0,qword ptr [ebx-8];
+    movq mm7,qword ptr [ebx];
+    pxor mm1,mm1;
+    psrlq mm0,32;
+    psllq mm1,32;
+    movq mm2,mm7;
+    movq mm3,mm7;
+    psllq mm2,32;
+    psrlq mm3,32;
+    por mm0,mm2;
+    por mm1,mm3;
+
+    /* current_upper */
+    movq mm6,qword ptr [eax];
+
+    /* compute the upper-left pixel for dst0 on %%mm2 */
+    /* compute the upper-right pixel for dst0 on %%mm4 */
+    movq mm2,mm0;
+    movq mm4,mm1;
+    movq mm3,mm0;
+    movq mm5,mm1;
+    pcmpeqd mm2,mm6;
+    pcmpeqd mm4,mm6;
+    pcmpeqd mm3,qword ptr [ecx];
+    pcmpeqd mm5,qword ptr [ecx];
+    pandn mm3,mm2;
+    pandn mm5,mm4;
+    movq mm2,mm0;
+    movq mm4,mm1;
+    pcmpeqd mm2,mm1;
+    pcmpeqd mm4,mm0;
+    pandn mm2,mm3;
+    pandn mm4,mm5;
+    movq mm3,mm2;
+    movq mm5,mm4;
+    pand mm2,mm6;
+    pand mm4,mm6;
+    pandn mm3,mm7;
+    pandn mm5,mm7;
+    por mm2,mm3;
+    por mm4,mm5;
+
+    /* set *dst0 */
+    movq mm3,mm2;
+    punpckldq mm2,mm4;
+    punpckhdq mm3,mm4;
+    movq qword ptr [edx],mm2;
+    movq qword ptr [edx+8],mm3;
+
+    mov src0, eax;
+    mov src1, ebx;
+    mov src2, ecx;
+    mov dst, edx;
+    mov count, esi;
+
+    emms;
+  }
+#endif
+}
+
+static void internal_scale2x_16_mmx(u16* dst0, u16* dst1, const u16* src0, const u16* src1, const u16* src2, unsigned count) {
+  //   assert( count >= 2*4 );
+  internal_scale2x_16_mmx_single(dst0, src0, src1, src2, count);
+  internal_scale2x_16_mmx_single(dst1, src2, src1, src0, count);
+}
+
+static void internal_scale2x_32_mmx(u32* dst0, u32* dst1, const u32* src0, const u32* src1, const u32* src2, unsigned count) {
+  //   assert( count >= 2*2 );
+  internal_scale2x_32_mmx_single(dst0, src0, src1, src2, count);
+  internal_scale2x_32_mmx_single(dst1, src2, src1, src0, count);
+}
+#endif
+
+void AdMame2x(u8 *srcPtr, u32 srcPitch, /* u8 deltaPtr, */
+              u8 *dstPtr, u32 dstPitch, int width, int height)
+{
+  u16 *dst0 = (u16 *)dstPtr;
+  u16 *dst1 = dst0 + (dstPitch/2);
+  
+  u16 *src0 = (u16 *)srcPtr;
+  u16 *src1 = src0 + (srcPitch/2);
+  u16 *src2 = src1 + (srcPitch/2);
+#ifdef MMX
+  if(cpu_mmx) {
+    internal_scale2x_16_mmx(dst0, dst1, src0, src0, src1, width);
+
+    {  
+    int count = height;
+
+    count -= 2;
+    while(count) {
+      dst0 += dstPitch;
+      dst1 += dstPitch;
+      internal_scale2x_16_mmx(dst0, dst1, src0, src1, src2, width);
+      src0 = src1;
+      src1 = src2;
+      src2 += srcPitch/2;
+      --count;
+    }
+    }
+    dst0 += dstPitch;
+    dst1 += dstPitch;
+    internal_scale2x_16_mmx(dst0, dst1, src0, src1, src1, width);
+  } else {
+#endif
+    internal_scale2x_16_def(dst0, dst1, src0, src0, src1, width);
+
+    {
+    int count = height;
+
+    count -= 2;
+    while(count) {
+      dst0 += dstPitch;
+      dst1 += dstPitch;
+      internal_scale2x_16_def(dst0, dst1, src0, src1, src2, width);
+      src0 = src1;
+      src1 = src2;
+      src2 += srcPitch/2;
+      --count;
+    }
+    }
+    dst0 += dstPitch;
+    dst1 += dstPitch;
+    internal_scale2x_16_def(dst0, dst1, src0, src1, src1, width);
+#ifdef MMX
+  }
+#endif
+}
+
+void AdMame2x32(u8 *srcPtr, u32 srcPitch, /* u8 deltaPtr, */
+                u8 *dstPtr, u32 dstPitch, int width, int height)
+{
+  u32 *dst0 = (u32 *)dstPtr;
+  u32 *dst1 = dst0 + (dstPitch/4);
+  
+  u32 *src0 = (u32 *)srcPtr;
+  u32 *src1 = src0 + (srcPitch/4);
+  u32 *src2 = src1 + (srcPitch/4);
+#ifdef MMX
+  if(cpu_mmx) {
+    internal_scale2x_32_mmx(dst0, dst1, src0, src0, src1, width);
+  
+    {
+    int count = height;
+
+    count -= 2;
+    while(count) {
+      dst0 += dstPitch/2;
+      dst1 += dstPitch/2;
+      internal_scale2x_32_mmx(dst0, dst1, src0, src1, src2, width);
+      src0 = src1;
+      src1 = src2;
+      src2 += srcPitch/4;
+      --count;
+    }
+    }
+    dst0 += dstPitch/2;
+    dst1 += dstPitch/2;
+    internal_scale2x_32_mmx(dst0, dst1, src0, src1, src1, width);
+  } else {
+#endif
+    internal_scale2x_32_def(dst0, dst1, src0, src0, src1, width);
+    {
+    int count = height;
+
+    count -= 2;
+    while(count) {
+      dst0 += dstPitch/2;
+      dst1 += dstPitch/2;
+      internal_scale2x_32_def(dst0, dst1, src0, src1, src2, width);
+      src0 = src1;
+      src1 = src2;
+      src2 += srcPitch/4;
+      --count;
+    }
+    }
+    dst0 += dstPitch/2;
+    dst1 += dstPitch/2;
+    internal_scale2x_32_def(dst0, dst1, src0, src1, src1, width);
+#ifdef MMX
+  }
+#endif
+}
+
+
+
+unsigned int LUT16to32[65536];
+unsigned int RGBtoYUV[65536];
+
+void hq_init (int rb, int gb, int bb, int rs, int gs, int bs)
+{
+    int i, j, k, r, g, b, Y, u, v;
+    int rmask, gmask, bmask;
+
+    rmask = ((1 << rb) - 1) << rs;
+    gmask = ((1 << gb) - 1) << gs;
+    bmask = ((1 << bb) - 1) << bs;
+
+    for (i=0; i<65536; i++)
+       LUT16to32[i] = ((i & 0xF800) << 8) + ((i & 0x07E0) << 5) + ((i & 0x001F) << 3);
+
+    for (i=0; i<32; i++) {
+       for (j=0; j<64; j++) {
+           for (k=0; k<32; k++) {
+               r = i << 3;
+               g = j << 2;
+               b = k << 3;
+               Y = (r + g + b) >> 2;
+               u = 128 + ((r - b) >> 2);
+               v = 128 + ((-r + 2*g -b)>>3);
+               RGBtoYUV[ (i << 11) + (j << 5) + k ] = (Y<<16) + (u<<8) + v;
+           }
+       }
+    }
+}
+
diff --git a/od-win32/scaler2.c b/od-win32/scaler2.c
new file mode 100755 (executable)
index 0000000..6b215b2
--- /dev/null
@@ -0,0 +1,1522 @@
+/* This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/* Scaler (except Scale2x) code borrowed from ScummVM project */
+
+#include "filter.h"
+
+static uint32 colorMask;
+static uint32 lowPixelMask;
+static uint32 qcolorMask;
+static uint32 qlowpixelMask;
+static uint32 redblueMask;
+static uint32 redMask;
+static uint32 greenMask;
+static uint32 blueMask;
+
+int Init_2xSaI (int rb, int gb, int bb, int rs, int gs, int bs)
+{
+       if (rb + gb + bb == 16) {
+               colorMask = 0xF7DEF7DE;
+               lowPixelMask = 0x08210821;
+               qcolorMask = 0xE79CE79C;
+               qlowpixelMask = 0x18631863;
+               redblueMask = 0xF81F;
+               redMask = 0xF800;
+               greenMask = 0x07E0;
+               blueMask = 0x001F;
+       } else if (rb + gb + bb == 15) {
+               colorMask = 0x7BDE7BDE;
+               lowPixelMask = 0x04210421;
+               qcolorMask = 0x739C739C;
+               qlowpixelMask = 0x0C630C63;
+               redblueMask = 0x7C1F;
+               redMask = 0x7C00;
+               greenMask = 0x03E0;
+               blueMask = 0x001F;
+       } else {
+               return 0;
+       }
+
+       return 1;
+}
+
+static _inline int GetResult(uint32 A, uint32 B, uint32 C, uint32 D)
+{ 
+       const bool ac = (A==C);
+       const bool bc = (B==C);
+       const int x1 = ac;
+       const int y1 = (bc & !ac);
+       const bool ad = (A==D);
+       const bool bd = (B==D);
+       const int x2 = ad;
+       const int y2 = (bd & !ad);
+       const int x = x1+x2;
+       const int y = y1+y2;
+       static const int rmap[3][3] = {
+                       {0, 0, -1},
+                       {0, 0, -1},
+                       {1, 1,  0}
+               };
+       return rmap[y][x];
+}
+
+static _inline uint32 INTERPOLATE(uint32 A, uint32 B) {
+       if (A != B) {
+               return (((A & colorMask) >> 1) + ((B & colorMask) >> 1) + (A & B & lowPixelMask));
+       } else
+               return A;
+}
+
+static _inline uint32 Q_INTERPOLATE(uint32 A, uint32 B, uint32 C, uint32 D) {
+       register uint32 x = ((A & qcolorMask) >> 2) + ((B & qcolorMask) >> 2) + ((C & qcolorMask) >> 2) + ((D & qcolorMask) >> 2);
+       register uint32 y = ((A & qlowpixelMask) + (B & qlowpixelMask) + (C & qlowpixelMask) + (D & qlowpixelMask)) >> 2;
+
+       y &= qlowpixelMask;
+       return x + y;
+}
+
+void Super2xSaI(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
+       const uint16 *bP;
+       uint16 *dP;
+       const uint32 nextlineSrc = srcPitch >> 1;
+
+       while (height--) {
+               int i;
+               bP = (const uint16 *)srcPtr;
+               dP = (uint16 *)dstPtr;
+
+               for (i = 0; i < width; ++i) {
+                       uint32 color4, color5, color6;
+                       uint32 color1, color2, color3;
+                       uint32 colorA0, colorA1, colorA2, colorA3;
+                       uint32 colorB0, colorB1, colorB2, colorB3;
+                       uint32 colorS1, colorS2;
+                       uint32 product1a, product1b, product2a, product2b;
+
+//---------------------------------------    B1 B2
+//                                         4  5  6 S2
+//                                         1  2  3 S1
+//                                           A1 A2
+
+                       colorB0 = *(bP - nextlineSrc - 1);
+                       colorB1 = *(bP - nextlineSrc);
+                       colorB2 = *(bP - nextlineSrc + 1);
+                       colorB3 = *(bP - nextlineSrc + 2);
+
+                       color4 = *(bP - 1);
+                       color5 = *(bP);
+                       color6 = *(bP + 1);
+                       colorS2 = *(bP + 2);
+
+                       color1 = *(bP + nextlineSrc - 1);
+                       color2 = *(bP + nextlineSrc);
+                       color3 = *(bP + nextlineSrc + 1);
+                       colorS1 = *(bP + nextlineSrc + 2);
+
+                       colorA0 = *(bP + 2 * nextlineSrc - 1);
+                       colorA1 = *(bP + 2 * nextlineSrc);
+                       colorA2 = *(bP + 2 * nextlineSrc + 1);
+                       colorA3 = *(bP + 2 * nextlineSrc + 2);
+
+//--------------------------------------
+                       if (color2 == color6 && color5 != color3) {
+                               product2b = product1b = color2;
+                       } else if (color5 == color3 && color2 != color6) {
+                               product2b = product1b = color5;
+                       } else if (color5 == color3 && color2 == color6) {
+                               register int r = 0;
+
+                               r += GetResult(color6, color5, color1, colorA1);
+                               r += GetResult(color6, color5, color4, colorB1);
+                               r += GetResult(color6, color5, colorA2, colorS1);
+                               r += GetResult(color6, color5, colorB2, colorS2);
+
+                               if (r > 0)
+                                       product2b = product1b = color6;
+                               else if (r < 0)
+                                       product2b = product1b = color5;
+                               else {
+                                       product2b = product1b = INTERPOLATE(color5, color6);
+                               }
+                       } else {
+                               if (color6 == color3 && color3 == colorA1 && color2 != colorA2 && color3 != colorA0)
+                                       product2b = Q_INTERPOLATE(color3, color3, color3, color2);
+                               else if (color5 == color2 && color2 == colorA2 && colorA1 != color3 && color2 != colorA3)
+                                       product2b = Q_INTERPOLATE(color2, color2, color2, color3);
+                               else
+                                       product2b = INTERPOLATE(color2, color3);
+
+                               if (color6 == color3 && color6 == colorB1 && color5 != colorB2 && color6 != colorB0)
+                                       product1b = Q_INTERPOLATE(color6, color6, color6, color5);
+                               else if (color5 == color2 && color5 == colorB2 && colorB1 != color6 && color5 != colorB3)
+                                       product1b = Q_INTERPOLATE(color6, color5, color5, color5);
+                               else
+                                       product1b = INTERPOLATE(color5, color6);
+                       }
+
+                       if (color5 == color3 && color2 != color6 && color4 == color5 && color5 != colorA2)
+                               product2a = INTERPOLATE(color2, color5);
+                       else if (color5 == color1 && color6 == color5 && color4 != color2 && color5 != colorA0)
+                               product2a = INTERPOLATE(color2, color5);
+                       else
+                               product2a = color2;
+
+                       if (color2 == color6 && color5 != color3 && color1 == color2 && color2 != colorB2)
+                               product1a = INTERPOLATE(color2, color5);
+                       else if (color4 == color2 && color3 == color2 && color1 != color5 && color2 != colorB0)
+                               product1a = INTERPOLATE(color2, color5);
+                       else
+                               product1a = color5;
+
+                       *(dP + 0) = (uint16) product1a;
+                       *(dP + 1) = (uint16) product1b;
+                       *(dP + dstPitch/2 + 0) = (uint16) product2a;
+                       *(dP + dstPitch/2 + 1) = (uint16) product2b;
+
+                       bP += 1;
+                       dP += 2;
+               }
+
+               srcPtr += srcPitch;
+               dstPtr += dstPitch * 2;
+       }
+}
+
+void SuperEagle(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
+       const uint16 *bP;
+       uint16 *dP;
+       const uint32 nextlineSrc = srcPitch >> 1;
+
+       while (height--) {
+               int i;
+               bP = (const uint16 *)srcPtr;
+               dP = (uint16 *)dstPtr;
+               for (i = 0; i < width; ++i) {
+                       uint32 color4, color5, color6;
+                       uint32 color1, color2, color3;
+                       uint32 colorA1, colorA2, colorB1, colorB2, colorS1, colorS2;
+                       uint32 product1a, product1b, product2a, product2b;
+
+                       colorB1 = *(bP - nextlineSrc);
+                       colorB2 = *(bP - nextlineSrc + 1);
+
+                       color4 = *(bP - 1);
+                       color5 = *(bP);
+                       color6 = *(bP + 1);
+                       colorS2 = *(bP + 2);
+
+                       color1 = *(bP + nextlineSrc - 1);
+                       color2 = *(bP + nextlineSrc);
+                       color3 = *(bP + nextlineSrc + 1);
+                       colorS1 = *(bP + nextlineSrc + 2);
+
+                       colorA1 = *(bP + 2 * nextlineSrc);
+                       colorA2 = *(bP + 2 * nextlineSrc + 1);
+
+                       // --------------------------------------
+                       if (color5 != color3)
+                       {
+                               if (color2 == color6)
+                               {
+                                       product1b = product2a = color2;
+                                       if ((color1 == color2) || (color6 == colorB2)) {
+                                               product1a = INTERPOLATE(color2, color5);
+                                               product1a = INTERPOLATE(color2, product1a);
+                                       } else {
+                                               product1a = INTERPOLATE(color5, color6);
+                                       }
+
+                                       if ((color6 == colorS2) || (color2 == colorA1)) {
+                                               product2b = INTERPOLATE(color2, color3);
+                                               product2b = INTERPOLATE(color2, product2b);
+                                       } else {
+                                               product2b = INTERPOLATE(color2, color3);
+                                       }
+                               }
+                               else
+                               {
+                                       product2b = product1a = INTERPOLATE(color2, color6);
+                                       product2b = Q_INTERPOLATE(color3, color3, color3, product2b);
+                                       product1a = Q_INTERPOLATE(color5, color5, color5, product1a);
+
+                                       product2a = product1b = INTERPOLATE(color5, color3);
+                                       product2a = Q_INTERPOLATE(color2, color2, color2, product2a);
+                                       product1b = Q_INTERPOLATE(color6, color6, color6, product1b);
+                               }
+                       }
+                       else //if (color5 == color3)
+                       {
+                               if (color2 != color6)
+                               {
+                                       product2b = product1a = color5;
+
+                                       if ((colorB1 == color5) || (color3 == colorS1)) {
+                                               product1b = INTERPOLATE(color5, color6);
+                                               product1b = INTERPOLATE(color5, product1b);
+                                       } else {
+                                               product1b = INTERPOLATE(color5, color6);
+                                       }
+
+                                       if ((color3 == colorA2) || (color4 == color5)) {
+                                               product2a = INTERPOLATE(color5, color2);
+                                               product2a = INTERPOLATE(color5, product2a);
+                                       } else {
+                                               product2a = INTERPOLATE(color2, color3);
+                                       }
+                               }
+                               else    //if (color2 != color6)
+                               {
+                                       register int r = 0;
+
+                                       r += GetResult(color6, color5, color1, colorA1);
+                                       r += GetResult(color6, color5, color4, colorB1);
+                                       r += GetResult(color6, color5, colorA2, colorS1);
+                                       r += GetResult(color6, color5, colorB2, colorS2);
+
+                                       if (r > 0) {
+                                               product1b = product2a = color2;
+                                               product1a = product2b = INTERPOLATE(color5, color6);
+                                       } else if (r < 0) {
+                                               product2b = product1a = color5;
+                                               product1b = product2a = INTERPOLATE(color5, color6);
+                                       } else {
+                                               product2b = product1a = color5;
+                                               product1b = product2a = color2;
+                                       }
+                               }
+                       }
+
+                       *(dP + 0) = (uint16) product1a;
+                       *(dP + 1) = (uint16) product1b;
+                       *(dP + dstPitch/2 + 0) = (uint16) product2a;
+                       *(dP + dstPitch/2 + 1) = (uint16) product2b;
+
+                       bP += 1;
+                       dP += 2;
+               }
+
+               srcPtr += srcPitch;
+               dstPtr += dstPitch * 2;
+       }
+}
+
+void _2xSaI(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) {
+       const uint16 *bP;
+       uint16 *dP;
+       const uint32 nextlineSrc = srcPitch >> 1;
+
+       while (height--) {
+               int i;
+               bP = (const uint16 *)srcPtr;
+               dP = (uint16 *)dstPtr;
+
+               for (i = 0; i < width; ++i) {
+
+                       register uint32 colorA, colorB;
+                       uint32 colorC, colorD,
+                               colorE, colorF, colorG, colorH, colorI, colorJ, colorK, colorL, colorM, colorN, colorO, colorP;
+                       uint32 product, product1, product2;
+
+//---------------------------------------
+// Map of the pixels:                    I|E F|J
+//                                       G|A B|K
+//                                       H|C D|L
+//                                       M|N O|P
+                       colorI = *(bP - nextlineSrc - 1);
+                       colorE = *(bP - nextlineSrc);
+                       colorF = *(bP - nextlineSrc + 1);
+                       colorJ = *(bP - nextlineSrc + 2);
+
+                       colorG = *(bP - 1);
+                       colorA = *(bP);
+                       colorB = *(bP + 1);
+                       colorK = *(bP + 2);
+
+                       colorH = *(bP + nextlineSrc - 1);
+                       colorC = *(bP + nextlineSrc);
+                       colorD = *(bP + nextlineSrc + 1);
+                       colorL = *(bP + nextlineSrc + 2);
+
+                       colorM = *(bP + 2 * nextlineSrc - 1);
+                       colorN = *(bP + 2 * nextlineSrc);
+                       colorO = *(bP + 2 * nextlineSrc + 1);
+                       colorP = *(bP + 2 * nextlineSrc + 2);
+
+                       if ((colorA == colorD) && (colorB != colorC)) {
+                               if (((colorA == colorE) && (colorB == colorL)) ||
+                                       ((colorA == colorC) && (colorA == colorF) && (colorB != colorE) && (colorB == colorJ))) {
+                                       product = colorA;
+                               } else {
+                                       product = INTERPOLATE(colorA, colorB);
+                               }
+
+                               if (((colorA == colorG) && (colorC == colorO)) ||
+                                       ((colorA == colorB) && (colorA == colorH) && (colorG != colorC)  && (colorC == colorM))) {
+                                       product1 = colorA;
+                               } else {
+                                       product1 = INTERPOLATE(colorA, colorC);
+                               }
+                               product2 = colorA;
+                       } else if ((colorB == colorC) && (colorA != colorD)) {
+                               if (((colorB == colorF) && (colorA == colorH)) ||
+                                       ((colorB == colorE) && (colorB == colorD) && (colorA != colorF) && (colorA == colorI))) {
+                                       product = colorB;
+                               } else {
+                                       product = INTERPOLATE(colorA, colorB);
+                               }
+
+                               if (((colorC == colorH) && (colorA == colorF)) ||
+                                       ((colorC == colorG) && (colorC == colorD) && (colorA != colorH) && (colorA == colorI))) {
+                                       product1 = colorC;
+                               } else {
+                                       product1 = INTERPOLATE(colorA, colorC);
+                               }
+                               product2 = colorB;
+                       } else if ((colorA == colorD) && (colorB == colorC)) {
+                               if (colorA == colorB) {
+                                       product = colorA;
+                                       product1 = colorA;
+                                       product2 = colorA;
+                               } else {
+                                       register int r = 0;
+
+                                       product1 = INTERPOLATE(colorA, colorC);
+                                       product = INTERPOLATE(colorA, colorB);
+
+                                       r += GetResult(colorA, colorB, colorG, colorE);
+                                       r -= GetResult(colorB, colorA, colorK, colorF);
+                                       r -= GetResult(colorB, colorA, colorH, colorN);
+                                       r += GetResult(colorA, colorB, colorL, colorO);
+
+                                       if (r > 0)
+                                               product2 = colorA;
+                                       else if (r < 0)
+                                               product2 = colorB;
+                                       else {
+                                               product2 = Q_INTERPOLATE(colorA, colorB, colorC, colorD);
+                                       }
+                               }
+                       } else {
+                               product2 = Q_INTERPOLATE(colorA, colorB, colorC, colorD);
+
+                               if ((colorA == colorC) && (colorA == colorF)
+                                               && (colorB != colorE) && (colorB == colorJ)) {
+                                       product = colorA;
+                               } else if ((colorB == colorE) && (colorB == colorD)
+                                                                        && (colorA != colorF) && (colorA == colorI)) {
+                                       product = colorB;
+                               } else {
+                                       product = INTERPOLATE(colorA, colorB);
+                               }
+
+                               if ((colorA == colorB) && (colorA == colorH)
+                                               && (colorG != colorC) && (colorC == colorM)) {
+                                       product1 = colorA;
+                               } else if ((colorC == colorG) && (colorC == colorD)
+                                                                        && (colorA != colorH) && (colorA == colorI)) {
+                                       product1 = colorC;
+                               } else {
+                                       product1 = INTERPOLATE(colorA, colorC);
+                               }
+                       }
+
+                       *(dP + 0) = (uint16) colorA;
+                       *(dP + 1) = (uint16) product;
+                       *(dP + dstPitch/2 + 0) = (uint16) product1;
+                       *(dP + dstPitch/2 + 1) = (uint16) product2;
+
+                       bP += 1;
+                       dP += 2;
+               }
+
+               srcPtr += srcPitch;
+               dstPtr += dstPitch * 2;
+       }
+}
+
+
+/*
+ * This file is part of the Advance project.
+ *
+ * Copyright (C) 1999-2002 Andrea Mazzoleni
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * This file contains a C and MMX implentation of the Scale2x effect.
+ *
+ * You can found an high level description of the effect at :
+ *
+ * http://scale2x.sourceforge.net/scale2x.html
+ *
+ * Alternatively at the previous license terms, you are allowed to use this
+ * code in your program with these conditions:
+ * - the program is not used in commercial activities.
+ * - the whole source code of the program is released with the binary.
+ * - derivative works of the program are allowed.
+ */
+
+#define MMX
+extern int cpu_mmx;
+
+/* Suggested in "Intel Optimization" for Pentium II */
+#define ASM_JUMP_ALIGN ".p2align 4\n"
+
+static void internal_scale2x_16_def(u16 *dst0, u16* dst1, const u16* src0, const u16* src1, const u16* src2, unsigned count) {
+  /* first pixel */
+  dst0[0] = src1[0];
+  dst1[0] = src1[0];
+  if (src1[1] == src0[0] && src2[0] != src0[0])
+    dst0[1] =src0[0];
+  else
+    dst0[1] =src1[0];
+  if (src1[1] == src2[0] && src0[0] != src2[0])
+    dst1[1] =src2[0];
+  else
+    dst1[1] =src1[0];
+  ++src0;
+  ++src1;
+  ++src2;
+  dst0 += 2;
+  dst1 += 2;
+
+  /* central pixels */
+  count -= 2;
+  while (count) {
+    if (src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0])
+      dst0[0] = src0[0];
+    else
+      dst0[0] = src1[0];
+    if (src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0])
+      dst0[1] =src0[0];
+    else
+      dst0[1] =src1[0];
+
+    if (src1[-1] == src2[0] && src0[0] != src2[0] && src1[1] != src2[0])
+      dst1[0] =src2[0];
+    else
+      dst1[0] =src1[0];
+    if (src1[1] == src2[0] && src0[0] != src2[0] && src1[-1] != src2[0])
+      dst1[1] =src2[0];
+    else
+      dst1[1] =src1[0];
+
+    ++src0;
+    ++src1;
+    ++src2;
+    dst0 += 2;
+    dst1 += 2;
+    --count;
+  }
+
+  /* last pixel */
+  if (src1[-1] == src0[0] && src2[0] != src0[0])
+    dst0[0] =src0[0];
+  else
+    dst0[0] =src1[0];
+  if (src1[-1] == src2[0] && src0[0] != src2[0])
+    dst1[0] =src2[0];
+  else
+    dst1[0] =src1[0];
+  dst0[1] =src1[0];
+  dst1[1] =src1[0];
+}
+
+static void internal_scale2x_32_def(u32* dst0,
+                                    u32* dst1,
+                                    const u32* src0,
+                                    const u32* src1,
+                                    const u32* src2,
+                                    unsigned count) {
+  /* first pixel */
+  dst0[0] = src1[0];
+  dst1[0] = src1[0];
+  if (src1[1] == src0[0] && src2[0] != src0[0])
+    dst0[1] = src0[0];
+  else
+    dst0[1] = src1[0];
+  if (src1[1] == src2[0] && src0[0] != src2[0])
+    dst1[1] = src2[0];
+  else
+    dst1[1] = src1[0];
+  ++src0;
+  ++src1;
+  ++src2;
+  dst0 += 2;
+  dst1 += 2;
+
+  /* central pixels */
+  count -= 2;
+  while (count) {
+    if (src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0])
+      dst0[0] = src0[0];
+    else
+      dst0[0] = src1[0];
+    if (src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0])
+      dst0[1] = src0[0];
+    else
+      dst0[1] = src1[0];
+
+    if (src1[-1] == src2[0] && src0[0] != src2[0] && src1[1] != src2[0])
+      dst1[0] = src2[0];
+    else
+      dst1[0] = src1[0];
+    if (src1[1] == src2[0] && src0[0] != src2[0] && src1[-1] != src2[0])
+      dst1[1] = src2[0];
+    else
+      dst1[1] = src1[0];
+
+    ++src0;
+    ++src1;
+    ++src2;
+    dst0 += 2;
+    dst1 += 2;
+    --count;
+  }
+
+  /* last pixel */
+  if (src1[-1] == src0[0] && src2[0] != src0[0])
+    dst0[0] = src0[0];
+  else
+    dst0[0] = src1[0];
+  if (src1[-1] == src2[0] && src0[0] != src2[0])
+    dst1[0] = src2[0];
+  else
+    dst1[0] = src1[0];
+  dst0[1] = src1[0];
+  dst1[1] = src1[0];
+}
+
+#ifdef MMX
+static void internal_scale2x_16_mmx_single(u16* dst, const u16* src0, const u16* src1, const u16* src2, unsigned count) {
+  /* always do the first and last run */
+  count -= 2*4;
+
+#ifdef __GNUC__        
+  __asm__ __volatile__(
+                       /* first run */
+                       /* set the current, current_pre, current_next registers */
+                       "pxor %%mm0,%%mm0\n" /* use a fake black out of screen */
+                       "movq 0(%1),%%mm7\n"
+                       "movq 8(%1),%%mm1\n"
+                       "psrlq $48,%%mm0\n"
+                       "psllq $48,%%mm1\n"
+                       "movq %%mm7,%%mm2\n"
+                       "movq %%mm7,%%mm3\n"
+                       "psllq $16,%%mm2\n"
+                       "psrlq $16,%%mm3\n"
+                       "por %%mm2,%%mm0\n"
+                       "por %%mm3,%%mm1\n"
+
+                       /* current_upper */
+                       "movq (%0),%%mm6\n"
+
+                       /* compute the upper-left pixel for dst0 on %%mm2 */
+                       /* compute the upper-right pixel for dst0 on %%mm4 */
+                       "movq %%mm0,%%mm2\n"
+                       "movq %%mm1,%%mm4\n"
+                       "movq %%mm0,%%mm3\n"
+                       "movq %%mm1,%%mm5\n"
+                       "pcmpeqw %%mm6,%%mm2\n"
+                       "pcmpeqw %%mm6,%%mm4\n"
+                       "pcmpeqw (%2),%%mm3\n"
+                       "pcmpeqw (%2),%%mm5\n"
+                       "pandn %%mm2,%%mm3\n"
+                       "pandn %%mm4,%%mm5\n"
+                       "movq %%mm0,%%mm2\n"
+                       "movq %%mm1,%%mm4\n"
+                       "pcmpeqw %%mm1,%%mm2\n"
+                       "pcmpeqw %%mm0,%%mm4\n"
+                       "pandn %%mm3,%%mm2\n"
+                       "pandn %%mm5,%%mm4\n"
+                       "movq %%mm2,%%mm3\n"
+                       "movq %%mm4,%%mm5\n"
+                       "pand %%mm6,%%mm2\n"
+                       "pand %%mm6,%%mm4\n"
+                       "pandn %%mm7,%%mm3\n"
+                       "pandn %%mm7,%%mm5\n"
+                       "por %%mm3,%%mm2\n"
+                       "por %%mm5,%%mm4\n"
+
+                       /* set *dst0 */
+                       "movq %%mm2,%%mm3\n"
+                       "punpcklwd %%mm4,%%mm2\n"
+                       "punpckhwd %%mm4,%%mm3\n"
+                       "movq %%mm2,(%3)\n"
+                       "movq %%mm3,8(%3)\n"
+
+                       /* next */
+                       "addl $8,%0\n"
+                       "addl $8,%1\n"
+                       "addl $8,%2\n"
+                       "addl $16,%3\n"
+
+                       /* central runs */
+                       "shrl $2,%4\n"
+                       "jz 1f\n"
+                       ASM_JUMP_ALIGN
+                       "0:\n"
+
+                       /* set the current, current_pre, current_next registers */
+                       "movq -8(%1),%%mm0\n"
+                       "movq (%1),%%mm7\n"
+                       "movq 8(%1),%%mm1\n"
+                       "psrlq $48,%%mm0\n"
+                       "psllq $48,%%mm1\n"
+                       "movq %%mm7,%%mm2\n"
+                       "movq %%mm7,%%mm3\n"
+                       "psllq $16,%%mm2\n"
+                       "psrlq $16,%%mm3\n"
+                       "por %%mm2,%%mm0\n"
+                       "por %%mm3,%%mm1\n"
+
+                       /* current_upper */
+                       "movq (%0),%%mm6\n"
+
+                       /* compute the upper-left pixel for dst0 on %%mm2 */
+                       /* compute the upper-right pixel for dst0 on %%mm4 */
+                       "movq %%mm0,%%mm2\n"
+                       "movq %%mm1,%%mm4\n"
+                       "movq %%mm0,%%mm3\n"
+                       "movq %%mm1,%%mm5\n"
+                       "pcmpeqw %%mm6,%%mm2\n"
+                       "pcmpeqw %%mm6,%%mm4\n"
+                       "pcmpeqw (%2),%%mm3\n"
+                       "pcmpeqw (%2),%%mm5\n"
+                       "pandn %%mm2,%%mm3\n"
+                       "pandn %%mm4,%%mm5\n"
+                       "movq %%mm0,%%mm2\n"
+                       "movq %%mm1,%%mm4\n"
+                       "pcmpeqw %%mm1,%%mm2\n"
+                       "pcmpeqw %%mm0,%%mm4\n"
+                       "pandn %%mm3,%%mm2\n"
+                       "pandn %%mm5,%%mm4\n"
+                       "movq %%mm2,%%mm3\n"
+                       "movq %%mm4,%%mm5\n"
+                       "pand %%mm6,%%mm2\n"
+                       "pand %%mm6,%%mm4\n"
+                       "pandn %%mm7,%%mm3\n"
+                       "pandn %%mm7,%%mm5\n"
+                       "por %%mm3,%%mm2\n"
+                       "por %%mm5,%%mm4\n"
+
+                       /* set *dst0 */
+                       "movq %%mm2,%%mm3\n"
+                       "punpcklwd %%mm4,%%mm2\n"
+                       "punpckhwd %%mm4,%%mm3\n"
+                       "movq %%mm2,(%3)\n"
+                       "movq %%mm3,8(%3)\n"
+
+                       /* next */
+                       "addl $8,%0\n"
+                       "addl $8,%1\n"
+                       "addl $8,%2\n"
+                       "addl $16,%3\n"
+
+                       "decl %4\n"
+                       "jnz 0b\n"
+                       "1:\n"
+
+                       /* final run */
+                       /* set the current, current_pre, current_next registers */
+                       "movq -8(%1),%%mm0\n"
+                       "movq (%1),%%mm7\n"
+                       "pxor %%mm1,%%mm1\n" /* use a fake black out of screen */
+                       "psrlq $48,%%mm0\n"
+                       "psllq $48,%%mm1\n"
+                       "movq %%mm7,%%mm2\n"
+                       "movq %%mm7,%%mm3\n"
+                       "psllq $16,%%mm2\n"
+                       "psrlq $16,%%mm3\n"
+                       "por %%mm2,%%mm0\n"
+                       "por %%mm3,%%mm1\n"
+
+                       /* current_upper */
+                       "movq (%0),%%mm6\n"
+
+                       /* compute the upper-left pixel for dst0 on %%mm2 */
+                       /* compute the upper-right pixel for dst0 on %%mm4 */
+                       "movq %%mm0,%%mm2\n"
+                       "movq %%mm1,%%mm4\n"
+                       "movq %%mm0,%%mm3\n"
+                       "movq %%mm1,%%mm5\n"
+                       "pcmpeqw %%mm6,%%mm2\n"
+                       "pcmpeqw %%mm6,%%mm4\n"
+                       "pcmpeqw (%2),%%mm3\n"
+                       "pcmpeqw (%2),%%mm5\n"
+                       "pandn %%mm2,%%mm3\n"
+                       "pandn %%mm4,%%mm5\n"
+                       "movq %%mm0,%%mm2\n"
+                       "movq %%mm1,%%mm4\n"
+                       "pcmpeqw %%mm1,%%mm2\n"
+                       "pcmpeqw %%mm0,%%mm4\n"
+                       "pandn %%mm3,%%mm2\n"
+                       "pandn %%mm5,%%mm4\n"
+                       "movq %%mm2,%%mm3\n"
+                       "movq %%mm4,%%mm5\n"
+                       "pand %%mm6,%%mm2\n"
+                       "pand %%mm6,%%mm4\n"
+                       "pandn %%mm7,%%mm3\n"
+                       "pandn %%mm7,%%mm5\n"
+                       "por %%mm3,%%mm2\n"
+                       "por %%mm5,%%mm4\n"
+
+                       /* set *dst0 */
+                       "movq %%mm2,%%mm3\n"
+                       "punpcklwd %%mm4,%%mm2\n"
+                       "punpckhwd %%mm4,%%mm3\n"
+                       "movq %%mm2,(%3)\n"
+                       "movq %%mm3,8(%3)\n"
+                       "emms\n"
+
+                       : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count)
+                       :
+                       : "cc"
+                       );
+#else
+  __asm {
+    mov eax, src0;
+    mov ebx, src1;
+    mov ecx, src2;
+    mov edx, dst;
+    mov esi, count;
+          
+    /* first run */
+    /* set the current, current_pre, current_next registers */
+    pxor mm0,mm0; /* use a fake black out of screen */
+    movq mm7, qword ptr [ebx];
+    movq mm1, qword ptr [ebx + 8];
+    psrlq mm0, 48;
+    psllq mm1, 48;
+    movq mm2, mm7;
+    movq mm3, mm7;
+    psllq mm2, 16;
+    psrlq mm3, 16;
+    por mm0, mm2;
+    por mm1, mm3;
+
+    /* current_upper */
+    movq mm6, qword ptr [eax];
+
+    /* compute the upper-left pixel for dst0 on %%mm2 */
+    /* compute the upper-right pixel for dst0 on %%mm4 */
+    movq mm2, mm0;
+    movq mm4, mm1;
+    movq mm3, mm0;
+    movq mm5, mm1;
+    pcmpeqw mm2, mm6;
+    pcmpeqw mm4, mm6;
+    pcmpeqw mm3, qword ptr [ecx];
+    pcmpeqw mm5, qword ptr [ecx];
+    pandn mm3,mm2;
+    pandn mm5,mm4;
+    movq mm2,mm0;
+    movq mm4,mm1;
+    pcmpeqw mm2,mm1;
+    pcmpeqw mm4,mm0;
+    pandn mm2,mm3;
+    pandn mm4,mm5;
+    movq mm3,mm2;
+    movq mm5,mm4;
+    pand mm2,mm6;
+    pand mm4,mm6;
+    pandn mm3,mm7;
+    pandn mm5,mm7;
+    por mm2,mm3;
+    por mm4,mm5;
+
+    /* set *dst0 */
+    movq mm3,mm2;
+    punpcklwd mm2,mm4;
+    punpckhwd mm3,mm4;
+    movq qword ptr [edx], mm2;
+    movq qword ptr [edx + 8], mm3;
+
+    /* next */
+    add eax, 8;
+    add ebx, 8;
+    add ecx, 8;
+    add edx, 16;
+
+    /* central runs */
+    shr esi, 2;
+    jz label1;
+    align 4;
+  label0:
+
+    /* set the current, current_pre, current_next registers */
+    movq mm0, qword ptr [ebx-8];
+    movq mm7, qword ptr [ebx];
+    movq mm1, qword ptr [ebx+8];
+    psrlq mm0,48;
+    psllq mm1,48;
+    movq mm2,mm7;
+    movq mm3,mm7;
+    psllq mm2,16;
+    psrlq mm3,16;
+    por mm0,mm2;
+    por mm1,mm3;
+
+    /* current_upper */
+    movq mm6, qword ptr [eax];
+
+    /* compute the upper-left pixel for dst0 on %%mm2 */
+    /* compute the upper-right pixel for dst0 on %%mm4 */
+    movq mm2,mm0;
+    movq mm4,mm1;
+    movq mm3,mm0;
+    movq mm5,mm1;
+    pcmpeqw mm2,mm6;
+    pcmpeqw mm4,mm6;
+    pcmpeqw mm3, qword ptr [ecx];
+    pcmpeqw mm5, qword ptr [ecx];
+    pandn mm3,mm2;
+    pandn mm5,mm4;
+    movq mm2,mm0;
+    movq mm4,mm1;
+    pcmpeqw mm2,mm1;
+    pcmpeqw mm4,mm0;
+    pandn mm2,mm3;
+    pandn mm4,mm5;
+    movq mm3,mm2;
+    movq mm5,mm4;
+    pand mm2,mm6;
+    pand mm4,mm6;
+    pandn mm3,mm7;
+    pandn mm5,mm7;
+    por mm2,mm3;
+    por mm4,mm5;
+
+    /* set *dst0 */
+    movq mm3,mm2;
+    punpcklwd mm2,mm4;
+    punpckhwd mm3,mm4;
+    movq qword ptr [edx], mm2;
+    movq qword ptr [edx+8], mm3;
+
+    /* next */
+    add eax,8;
+    add ebx,8;
+    add ecx,8;
+    add edx,16;
+          
+    dec esi;
+    jnz label0;
+  label1:
+
+    /* final run */
+    /* set the current, current_pre, current_next registers */
+    movq mm0, qword ptr [ebx-8];
+    movq mm7, qword ptr [ebx];
+    pxor mm1,mm1; /* use a fake black out of screen */
+    psrlq mm0,48;
+    psllq mm1,48;
+    movq mm2,mm7;
+    movq mm3,mm7;
+    psllq mm2,16;
+    psrlq mm3,16;
+    por mm0,mm2;
+    por mm1,mm3;
+
+    /* current_upper */
+    movq mm6, qword ptr [eax];
+
+    /* compute the upper-left pixel for dst0 on %%mm2 */
+    /* compute the upper-right pixel for dst0 on %%mm4 */
+    movq mm2,mm0;
+    movq mm4,mm1;
+    movq mm3,mm0;
+    movq mm5,mm1;
+    pcmpeqw mm2,mm6;
+    pcmpeqw mm4,mm6;
+    pcmpeqw mm3, qword ptr [ecx];
+    pcmpeqw mm5, qword ptr [ecx];
+    pandn mm3,mm2;
+    pandn mm5,mm4;
+    movq mm2,mm0;
+    movq mm4,mm1;
+    pcmpeqw mm2,mm1;
+    pcmpeqw mm4,mm0;
+    pandn mm2,mm3;
+    pandn mm4,mm5;
+    movq mm3,mm2;
+    movq mm5,mm4;
+    pand mm2,mm6;
+    pand mm4,mm6;
+    pandn mm3,mm7;
+    pandn mm5,mm7;
+    por mm2,mm3;
+    por mm4,mm5;
+
+    /* set *dst0 */
+    movq mm3,mm2;
+    punpcklwd mm2,mm4;
+    punpckhwd mm3,mm4;
+    movq qword ptr [edx], mm2;
+    movq qword ptr [edx+8], mm3;
+
+    mov src0, eax;
+    mov src1, ebx;
+    mov src2, ecx;
+    mov dst, edx;
+    mov count, esi;
+
+    emms;
+  }
+#endif
+}
+
+static void internal_scale2x_32_mmx_single(u32* dst, const u32* src0, const u32* src1, const u32* src2, unsigned count) {
+  /* always do the first and last run */
+  count -= 2*2;
+
+#ifdef __GNUC__
+  __asm__ __volatile__(
+                       /* first run */
+                       /* set the current, current_pre, current_next registers */
+                       "pxor %%mm0,%%mm0\n" /* use a fake black out of screen */
+                       "movq 0(%1),%%mm7\n"
+                       "movq 8(%1),%%mm1\n"
+                       "psrlq $32,%%mm0\n"
+                       "psllq $32,%%mm1\n"
+                       "movq %%mm7,%%mm2\n"
+                       "movq %%mm7,%%mm3\n"
+                       "psllq $32,%%mm2\n"
+                       "psrlq $32,%%mm3\n"
+                       "por %%mm2,%%mm0\n"
+                       "por %%mm3,%%mm1\n"
+
+                       /* current_upper */
+                       "movq (%0),%%mm6\n"
+
+                       /* compute the upper-left pixel for dst0 on %%mm2 */
+                       /* compute the upper-right pixel for dst0 on %%mm4 */
+                       "movq %%mm0,%%mm2\n"
+                       "movq %%mm1,%%mm4\n"
+                       "movq %%mm0,%%mm3\n"
+                       "movq %%mm1,%%mm5\n"
+                       "pcmpeqd %%mm6,%%mm2\n"
+                       "pcmpeqd %%mm6,%%mm4\n"
+                       "pcmpeqd (%2),%%mm3\n"
+                       "pcmpeqd (%2),%%mm5\n"
+                       "pandn %%mm2,%%mm3\n"
+                       "pandn %%mm4,%%mm5\n"
+                       "movq %%mm0,%%mm2\n"
+                       "movq %%mm1,%%mm4\n"
+                       "pcmpeqd %%mm1,%%mm2\n"
+                       "pcmpeqd %%mm0,%%mm4\n"
+                       "pandn %%mm3,%%mm2\n"
+                       "pandn %%mm5,%%mm4\n"
+                       "movq %%mm2,%%mm3\n"
+                       "movq %%mm4,%%mm5\n"
+                       "pand %%mm6,%%mm2\n"
+                       "pand %%mm6,%%mm4\n"
+                       "pandn %%mm7,%%mm3\n"
+                       "pandn %%mm7,%%mm5\n"
+                       "por %%mm3,%%mm2\n"
+                       "por %%mm5,%%mm4\n"
+
+                       /* set *dst0 */
+                       "movq %%mm2,%%mm3\n"
+                       "punpckldq %%mm4,%%mm2\n"
+                       "punpckhdq %%mm4,%%mm3\n"
+                       "movq %%mm2,(%3)\n"
+                       "movq %%mm3,8(%3)\n"
+
+                       /* next */
+                       "addl $8,%0\n"
+                       "addl $8,%1\n"
+                       "addl $8,%2\n"
+                       "addl $16,%3\n"
+
+                       /* central runs */
+                       "shrl $1,%4\n"
+                       "jz 1f\n"
+                       ASM_JUMP_ALIGN
+                       "0:\n"
+
+                       /* set the current, current_pre, current_next registers */
+                       "movq -8(%1),%%mm0\n"
+                       "movq (%1),%%mm7\n"
+                       "movq 8(%1),%%mm1\n"
+                       "psrlq $32,%%mm0\n"
+                       "psllq $32,%%mm1\n"
+                       "movq %%mm7,%%mm2\n"
+                       "movq %%mm7,%%mm3\n"
+                       "psllq $32,%%mm2\n"
+                       "psrlq $32,%%mm3\n"
+                       "por %%mm2,%%mm0\n"
+                       "por %%mm3,%%mm1\n"
+
+                       /* current_upper */
+                       "movq (%0),%%mm6\n"
+
+                       /* compute the upper-left pixel for dst0 on %%mm2 */
+                       /* compute the upper-right pixel for dst0 on %%mm4 */
+                       "movq %%mm0,%%mm2\n"
+                       "movq %%mm1,%%mm4\n"
+                       "movq %%mm0,%%mm3\n"
+                       "movq %%mm1,%%mm5\n"
+                       "pcmpeqd %%mm6,%%mm2\n"
+                       "pcmpeqd %%mm6,%%mm4\n"
+                       "pcmpeqd (%2),%%mm3\n"
+                       "pcmpeqd (%2),%%mm5\n"
+                       "pandn %%mm2,%%mm3\n"
+                       "pandn %%mm4,%%mm5\n"
+                       "movq %%mm0,%%mm2\n"
+                       "movq %%mm1,%%mm4\n"
+                       "pcmpeqd %%mm1,%%mm2\n"
+                       "pcmpeqd %%mm0,%%mm4\n"
+                       "pandn %%mm3,%%mm2\n"
+                       "pandn %%mm5,%%mm4\n"
+                       "movq %%mm2,%%mm3\n"
+                       "movq %%mm4,%%mm5\n"
+                       "pand %%mm6,%%mm2\n"
+                       "pand %%mm6,%%mm4\n"
+                       "pandn %%mm7,%%mm3\n"
+                       "pandn %%mm7,%%mm5\n"
+                       "por %%mm3,%%mm2\n"
+                       "por %%mm5,%%mm4\n"
+
+                       /* set *dst0 */
+                       "movq %%mm2,%%mm3\n"
+                       "punpckldq %%mm4,%%mm2\n"
+                       "punpckhdq %%mm4,%%mm3\n"
+                       "movq %%mm2,(%3)\n"
+                       "movq %%mm3,8(%3)\n"
+
+                       /* next */
+                       "addl $8,%0\n"
+                       "addl $8,%1\n"
+                       "addl $8,%2\n"
+                       "addl $16,%3\n"
+
+                       "decl %4\n"
+                       "jnz 0b\n"
+                       "1:\n"
+
+                       /* final run */
+                       /* set the current, current_pre, current_next registers */
+                       "movq -8(%1),%%mm0\n"
+                       "movq (%1),%%mm7\n"
+                       "pxor %%mm1,%%mm1\n" /* use a fake black out of screen */
+                       "psrlq $32,%%mm0\n"
+                       "psllq $32,%%mm1\n"
+                       "movq %%mm7,%%mm2\n"
+                       "movq %%mm7,%%mm3\n"
+                       "psllq $32,%%mm2\n"
+                       "psrlq $32,%%mm3\n"
+                       "por %%mm2,%%mm0\n"
+                       "por %%mm3,%%mm1\n"
+
+                       /* current_upper */
+                       "movq (%0),%%mm6\n"
+
+                       /* compute the upper-left pixel for dst0 on %%mm2 */
+                       /* compute the upper-right pixel for dst0 on %%mm4 */
+                       "movq %%mm0,%%mm2\n"
+                       "movq %%mm1,%%mm4\n"
+                       "movq %%mm0,%%mm3\n"
+                       "movq %%mm1,%%mm5\n"
+                       "pcmpeqd %%mm6,%%mm2\n"
+                       "pcmpeqd %%mm6,%%mm4\n"
+                       "pcmpeqd (%2),%%mm3\n"
+                       "pcmpeqd (%2),%%mm5\n"
+                       "pandn %%mm2,%%mm3\n"
+                       "pandn %%mm4,%%mm5\n"
+                       "movq %%mm0,%%mm2\n"
+                       "movq %%mm1,%%mm4\n"
+                       "pcmpeqd %%mm1,%%mm2\n"
+                       "pcmpeqd %%mm0,%%mm4\n"
+                       "pandn %%mm3,%%mm2\n"
+                       "pandn %%mm5,%%mm4\n"
+                       "movq %%mm2,%%mm3\n"
+                       "movq %%mm4,%%mm5\n"
+                       "pand %%mm6,%%mm2\n"
+                       "pand %%mm6,%%mm4\n"
+                       "pandn %%mm7,%%mm3\n"
+                       "pandn %%mm7,%%mm5\n"
+                       "por %%mm3,%%mm2\n"
+                       "por %%mm5,%%mm4\n"
+
+                       /* set *dst0 */
+                       "movq %%mm2,%%mm3\n"
+                       "punpckldq %%mm4,%%mm2\n"
+                       "punpckhdq %%mm4,%%mm3\n"
+                       "movq %%mm2,(%3)\n"
+                       "movq %%mm3,8(%3)\n"
+                       "emms\n"
+
+                       : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count)
+                       :
+                       : "cc"
+                       );
+#else
+  __asm {
+    mov eax, src0;
+    mov ebx, src1;
+    mov ecx, src2;
+    mov edx, dst;
+    mov esi, count;
+    
+    /* first run */
+    /* set the current, current_pre, current_next registers */
+    pxor mm0,mm0;
+    movq mm7,qword ptr [ebx];
+    movq mm1,qword ptr [ebx + 8];
+    psrlq mm0,32;
+    psllq mm1,32;
+    movq mm2,mm7;
+    movq mm3,mm7;
+    psllq mm2,32;
+    psrlq mm3,32;
+    por mm0,mm2;
+    por mm1,mm3;
+
+    /* current_upper */
+    movq mm6,qword ptr [eax];
+
+    /* compute the upper-left pixel for dst0 on %%mm2 */
+    /* compute the upper-right pixel for dst0 on %%mm4 */
+    movq mm2,mm0;
+    movq mm4,mm1;
+    movq mm3,mm0;
+    movq mm5,mm1;
+    pcmpeqd mm2,mm6;
+    pcmpeqd mm4,mm6;
+    pcmpeqd mm3,qword ptr [ecx];
+    pcmpeqd mm5,qword ptr [ecx];
+    pandn mm3,mm2;
+    pandn mm5,mm4;
+    movq mm2,mm0;
+    movq mm4,mm1;
+    pcmpeqd mm2,mm1;
+    pcmpeqd mm4,mm0;
+    pandn mm2,mm3;
+    pandn mm4,mm5;
+    movq mm3,mm2;
+    movq mm5,mm4;
+    pand mm2,mm6;
+    pand mm4,mm6;
+    pandn mm3,mm7;
+    pandn mm5,mm7;
+    por mm2,mm3;
+    por mm4,mm5;
+
+    /* set *dst0 */
+    movq mm3,mm2;
+    punpckldq mm2,mm4;
+    punpckhdq mm3,mm4;
+    movq qword ptr [edx],mm2;
+    movq qword ptr [edx+8],mm3;
+
+    /* next */
+    add eax,8;
+    add ebx,8;
+    add ecx,8;
+    add edx,16;
+
+    /* central runs */
+    shr esi,1;
+    jz label1;
+label0:
+    
+  /* set the current, current_pre, current_next registers */
+    movq mm0,qword ptr [ebx-8];
+    movq mm7,qword ptr [ebx];
+    movq mm1,qword ptr [ebx+8];
+    psrlq mm0,32;
+    psllq mm1,32;
+    movq mm2,mm7;
+    movq mm3,mm7;
+    psllq mm2,32;
+    psrlq mm3,32;
+    por mm0,mm2;
+    por mm1,mm3;
+
+    /* current_upper */
+    movq mm6,qword ptr[eax];
+
+    /* compute the upper-left pixel for dst0 on %%mm2 */
+    /* compute the upper-right pixel for dst0 on %%mm4 */
+    movq mm2,mm0;
+    movq mm4,mm1;
+    movq mm3,mm0;
+    movq mm5,mm1;
+    pcmpeqd mm2,mm6;
+    pcmpeqd mm4,mm6;
+    pcmpeqd mm3,qword ptr[ecx];
+    pcmpeqd mm5,qword ptr[ecx];
+    pandn mm3,mm2;
+    pandn mm5,mm4;
+    movq mm2,mm0;
+    movq mm4,mm1;
+    pcmpeqd mm2,mm1;
+    pcmpeqd mm4,mm0;
+    pandn mm2,mm3;
+    pandn mm4,mm5;
+    movq mm3,mm2;
+    movq mm5,mm4;
+    pand mm2,mm6;
+    pand mm4,mm6;
+    pandn mm3,mm7;
+    pandn mm5,mm7;
+    por mm2,mm3;
+    por mm4,mm5;
+
+    /* set *dst0 */
+    movq mm3,mm2;
+    punpckldq mm2,mm4;
+    punpckhdq mm3,mm4;
+    movq qword ptr [edx],mm2;
+    movq qword ptr [edx+8],mm3;
+
+    /* next */
+    add eax,8;
+    add ebx,8;
+    add ecx,8;
+    add edx,16;
+
+    dec esi;
+    jnz label0;
+label1:
+    
+    /* final run */
+    /* set the current, current_pre, current_next registers */
+    movq mm0,qword ptr [ebx-8];
+    movq mm7,qword ptr [ebx];
+    pxor mm1,mm1;
+    psrlq mm0,32;
+    psllq mm1,32;
+    movq mm2,mm7;
+    movq mm3,mm7;
+    psllq mm2,32;
+    psrlq mm3,32;
+    por mm0,mm2;
+    por mm1,mm3;
+
+    /* current_upper */
+    movq mm6,qword ptr [eax];
+
+    /* compute the upper-left pixel for dst0 on %%mm2 */
+    /* compute the upper-right pixel for dst0 on %%mm4 */
+    movq mm2,mm0;
+    movq mm4,mm1;
+    movq mm3,mm0;
+    movq mm5,mm1;
+    pcmpeqd mm2,mm6;
+    pcmpeqd mm4,mm6;
+    pcmpeqd mm3,qword ptr [ecx];
+    pcmpeqd mm5,qword ptr [ecx];
+    pandn mm3,mm2;
+    pandn mm5,mm4;
+    movq mm2,mm0;
+    movq mm4,mm1;
+    pcmpeqd mm2,mm1;
+    pcmpeqd mm4,mm0;
+    pandn mm2,mm3;
+    pandn mm4,mm5;
+    movq mm3,mm2;
+    movq mm5,mm4;
+    pand mm2,mm6;
+    pand mm4,mm6;
+    pandn mm3,mm7;
+    pandn mm5,mm7;
+    por mm2,mm3;
+    por mm4,mm5;
+
+    /* set *dst0 */
+    movq mm3,mm2;
+    punpckldq mm2,mm4;
+    punpckhdq mm3,mm4;
+    movq qword ptr [edx],mm2;
+    movq qword ptr [edx+8],mm3;
+
+    mov src0, eax;
+    mov src1, ebx;
+    mov src2, ecx;
+    mov dst, edx;
+    mov count, esi;
+
+    emms;
+  }
+#endif
+}
+
+static void internal_scale2x_16_mmx(u16* dst0, u16* dst1, const u16* src0, const u16* src1, const u16* src2, unsigned count) {
+  //   assert( count >= 2*4 );
+  internal_scale2x_16_mmx_single(dst0, src0, src1, src2, count);
+  internal_scale2x_16_mmx_single(dst1, src2, src1, src0, count);
+}
+
+static void internal_scale2x_32_mmx(u32* dst0, u32* dst1, const u32* src0, const u32* src1, const u32* src2, unsigned count) {
+  //   assert( count >= 2*2 );
+  internal_scale2x_32_mmx_single(dst0, src0, src1, src2, count);
+  internal_scale2x_32_mmx_single(dst1, src2, src1, src0, count);
+}
+#endif
+
+void AdMame2x(u8 *srcPtr, u32 srcPitch, /* u8 deltaPtr, */
+              u8 *dstPtr, u32 dstPitch, int width, int height)
+{
+  u16 *dst0 = (u16 *)dstPtr;
+  u16 *dst1 = dst0 + (dstPitch/2);
+  
+  u16 *src0 = (u16 *)srcPtr;
+  u16 *src1 = src0 + (srcPitch/2);
+  u16 *src2 = src1 + (srcPitch/2);
+#ifdef MMX
+  if(cpu_mmx) {
+    internal_scale2x_16_mmx(dst0, dst1, src0, src0, src1, width);
+
+    {  
+    int count = height;
+
+    count -= 2;
+    while(count) {
+      dst0 += dstPitch;
+      dst1 += dstPitch;
+      internal_scale2x_16_mmx(dst0, dst1, src0, src1, src2, width);
+      src0 = src1;
+      src1 = src2;
+      src2 += srcPitch/2;
+      --count;
+    }
+    }
+    dst0 += dstPitch;
+    dst1 += dstPitch;
+    internal_scale2x_16_mmx(dst0, dst1, src0, src1, src1, width);
+  } else {
+#endif
+    internal_scale2x_16_def(dst0, dst1, src0, src0, src1, width);
+
+    {
+    int count = height;
+
+    count -= 2;
+    while(count) {
+      dst0 += dstPitch;
+      dst1 += dstPitch;
+      internal_scale2x_16_def(dst0, dst1, src0, src1, src2, width);
+      src0 = src1;
+      src1 = src2;
+      src2 += srcPitch/2;
+      --count;
+    }
+    }
+    dst0 += dstPitch;
+    dst1 += dstPitch;
+    internal_scale2x_16_def(dst0, dst1, src0, src1, src1, width);
+#ifdef MMX
+  }
+#endif
+}
+
+void AdMame2x32(u8 *srcPtr, u32 srcPitch, /* u8 deltaPtr, */
+                u8 *dstPtr, u32 dstPitch, int width, int height)
+{
+  u32 *dst0 = (u32 *)dstPtr;
+  u32 *dst1 = dst0 + (dstPitch/4);
+  
+  u32 *src0 = (u32 *)srcPtr;
+  u32 *src1 = src0 + (srcPitch/4);
+  u32 *src2 = src1 + (srcPitch/4);
+#ifdef MMX
+  if(cpu_mmx) {
+    internal_scale2x_32_mmx(dst0, dst1, src0, src0, src1, width);
+  
+    {
+    int count = height;
+
+    count -= 2;
+    while(count) {
+      dst0 += dstPitch/2;
+      dst1 += dstPitch/2;
+      internal_scale2x_32_mmx(dst0, dst1, src0, src1, src2, width);
+      src0 = src1;
+      src1 = src2;
+      src2 += srcPitch/4;
+      --count;
+    }
+    }
+    dst0 += dstPitch/2;
+    dst1 += dstPitch/2;
+    internal_scale2x_32_mmx(dst0, dst1, src0, src1, src1, width);
+  } else {
+#endif
+    internal_scale2x_32_def(dst0, dst1, src0, src0, src1, width);
+    {
+    int count = height;
+
+    count -= 2;
+    while(count) {
+      dst0 += dstPitch/2;
+      dst1 += dstPitch/2;
+      internal_scale2x_32_def(dst0, dst1, src0, src1, src2, width);
+      src0 = src1;
+      src1 = src2;
+      src2 += srcPitch/4;
+      --count;
+    }
+    }
+    dst0 += dstPitch/2;
+    dst1 += dstPitch/2;
+    internal_scale2x_32_def(dst0, dst1, src0, src1, src1, width);
+#ifdef MMX
+  }
+#endif
+}
+
+
+
+unsigned int LUT16to32[65536];
+unsigned int RGBtoYUV[65536];
+
+void hq_init(void)
+{
+    int i, j, k, r, g, b, Y, u, v;
+
+    for (i=0; i<65536; i++)
+       LUT16to32[i] = ((i & 0xF800) << 8) + ((i & 0x07E0) << 5) + ((i & 0x001F) << 3);
+
+    for (i=0; i<32; i++) {
+       for (j=0; j<64; j++) {
+           for (k=0; k<32; k++) {
+               r = i << 3;
+               g = j << 2;
+               b = k << 3;
+               Y = (r + g + b) >> 2;
+               u = 128 + ((r - b) >> 2);
+               v = 128 + ((-r + 2*g -b)>>3);
+               RGBtoYUV[ (i << 11) + (j << 5) + k ] = (Y<<16) + (u<<8) + v;
+           }
+       }
+    }
+}
+
diff --git a/od-win32/screenshot.c b/od-win32/screenshot.c
new file mode 100755 (executable)
index 0000000..a12b879
--- /dev/null
@@ -0,0 +1,186 @@
+#include <windows.h>
+#include <ddraw.h>
+
+#include <stdio.h>
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+#include "options.h"
+#include "custom.h"
+#include "picasso96.h"
+#include "dxwrap.h"
+#include "win32.h"
+#include "win32gfx.h"
+#include "direct3d.h"
+#include "opengl.h"
+
+static char config_filename[] = { 0 };
+
+static int toclipboard (BITMAPINFO *bi, void *bmp)
+{
+    int v = 0;
+    uae_u8 *dib = 0;
+    HANDLE hg;
+
+    if (!OpenClipboard (hMainWnd))
+       return v;
+    EmptyClipboard ();
+    hg = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, bi->bmiHeader.biSize + bi->bmiHeader.biSizeImage);
+    if (hg) {
+        dib = GlobalLock (hg);
+       if (dib) {
+           memcpy (dib, &bi->bmiHeader, bi->bmiHeader.biSize);
+           memcpy (dib + bi->bmiHeader.biSize, bmp, bi->bmiHeader.biSizeImage);
+       }
+        GlobalUnlock (hg);
+        if (SetClipboardData (CF_DIB, hg))
+           v = 1;
+    }
+    CloseClipboard ();
+    if (!v)
+       GlobalFree (hg);
+    return v;
+}
+
+/*
+Captures the Amiga display (DirectDraw, D3D or OpenGL) surface and saves it to file as a 24bit bitmap.
+*/
+void screenshot(int mode)
+{
+       static int recursive;
+       
+       FILE *fp = NULL;
+       
+       HDC surface_dc = NULL; // GDI-compatible device context for the surface
+       HBITMAP offscreen_bitmap = NULL; // bitmap that is converted to a DIB
+       HDC offscreen_dc = NULL; // offscreen DC that we can select offscreen bitmap into
+       
+       BITMAPINFO bi; // bitmap info
+       LPVOID lpvBits = NULL; // pointer to bitmap bits array
+       
+       unsigned int width = WIN32GFX_GetWidth();
+       unsigned int height = WIN32GFX_GetHeight();
+       
+       if(recursive)
+               return;
+       
+       recursive++;
+
+       surface_dc = gethdc ();
+
+       // need a HBITMAP to convert it to a DIB
+       if((offscreen_bitmap = CreateCompatibleBitmap(surface_dc, width, height)) == NULL)
+               goto oops; // error
+       
+       // The bitmap is empty, so let's copy the contents of the surface to it.
+       // For that we need to select it into a device context.
+       if((offscreen_dc = CreateCompatibleDC(surface_dc)) == NULL)
+               goto oops; // error
+       
+       {
+               // select offscreen_bitmap into offscreen_dc
+               HGDIOBJ hgdiobj = SelectObject(offscreen_dc, offscreen_bitmap);
+               
+               // now we can copy the contents of the surface to the offscreen bitmap
+               BitBlt(offscreen_dc, 0, 0, width, height, surface_dc, 0, 0, SRCCOPY);
+               
+               // de-select offscreen_bitmap
+               SelectObject(offscreen_dc, hgdiobj);
+       }
+       
+       ZeroMemory(&bi, sizeof(bi));
+       bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+       bi.bmiHeader.biWidth = width;
+       bi.bmiHeader.biHeight = height;
+       bi.bmiHeader.biPlanes = 1;
+       bi.bmiHeader.biBitCount = 24;
+       bi.bmiHeader.biCompression = BI_RGB;
+       bi.bmiHeader.biSizeImage = (((bi.bmiHeader.biWidth * bi.bmiHeader.biBitCount + 31) & ~31) / 8) * bi.bmiHeader.biHeight;
+       bi.bmiHeader.biXPelsPerMeter = 0;
+       bi.bmiHeader.biYPelsPerMeter = 0;
+       bi.bmiHeader.biClrUsed = 0;
+       bi.bmiHeader.biClrImportant = 0;
+
+       // Reserve memory for bitmap bits
+       if(!(lpvBits = malloc(bi.bmiHeader.biSizeImage)))
+               goto oops; // out of memory
+       
+       // Have GetDIBits convert offscreen_bitmap to a DIB (device-independent bitmap):
+       if(!GetDIBits(offscreen_dc, offscreen_bitmap, 0, bi.bmiHeader.biHeight, lpvBits, &bi, DIB_RGB_COLORS))
+               goto oops; // GetDIBits FAILED
+       
+       releasehdc (surface_dc);
+       surface_dc = 0;
+
+       if (mode == 0) {
+           toclipboard (&bi, lpvBits);
+       } else {
+               char filename[MAX_PATH];
+               char extension[] = "bmp";
+               char tmpstr[MAX_PATH];
+               int number = 0;
+               
+               tmpstr[0] = 0;
+               if(config_filename[0])
+                       sprintf (tmpstr, "%s_", config_filename);
+               
+               while(++number < 1000) // limit 999 iterations / screenshots
+               {
+                       sprintf(filename, "%s%cScreenShots%c%s%03.3d.%s", start_path, FSDB_DIR_SEPARATOR, FSDB_DIR_SEPARATOR, tmpstr, number, extension);
+                       
+                       if((fp = fopen(filename, "r")) == NULL) // does file not exist?
+                       {
+                               BITMAPFILEHEADER bfh;
+                               
+                               if((fp = fopen(filename, "wb")) == NULL)
+                                       goto oops; // error
+                               
+                               // write the file header, bitmap information and pixel data
+                               bfh.bfType = 19778;
+                               bfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + bi.bmiHeader.biSizeImage;
+                               bfh.bfReserved1 = 0;
+                               bfh.bfReserved2 = 0;
+                               bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
+                               
+                               if(fwrite(&bfh, 1, sizeof(BITMAPFILEHEADER), fp) < sizeof(BITMAPFILEHEADER))
+                                       goto oops; // failed to write bitmap file header
+                               
+                               if(fwrite(&bi, 1, sizeof(BITMAPINFOHEADER), fp) < sizeof(BITMAPINFOHEADER))
+                                       goto oops; // failed to write bitmap infomation header
+                               
+                               if(fwrite(lpvBits, 1, bi.bmiHeader.biSizeImage, fp) < bi.bmiHeader.biSizeImage)
+                                       goto oops; // failed to write the bitmap
+                               
+                               fclose(fp);
+                               
+                               write_log("Screenshot saved as \"%s\"\n", filename);
+                               
+                               break;
+                       }
+                       
+                       fclose(fp);
+                       fp = NULL;
+               }
+       }
+       
+oops:
+       if (surface_dc)
+           releasehdc (surface_dc);
+
+       if(offscreen_dc)
+               DeleteDC(offscreen_dc);
+       
+       if(offscreen_bitmap)
+               DeleteObject(offscreen_bitmap);
+       
+       if(lpvBits)
+               free(lpvBits);
+       
+       if(fp)
+               fclose(fp);
+       
+       recursive--;
+       
+       return;
+}
+
diff --git a/od-win32/scsidef.h b/od-win32/scsidef.h
new file mode 100755 (executable)
index 0000000..5126a9e
--- /dev/null
@@ -0,0 +1,388 @@
+
+/* required scsi structure definitions ripped from cdrtools package... */
+
+typedef int BOOL;
+typedef unsigned char Ucbit;
+typedef        unsigned long Ulong;
+typedef        unsigned int Uint;
+typedef        unsigned short Ushort;
+typedef        unsigned char Uchar;
+typedef unsigned long Int32_t;
+
+typedef void* caddr_t;
+
+#define _BIT_FIELDS_LTOH
+#define __PR(x)
+
+struct scsi_capacity {
+       Int32_t c_baddr;                /* must convert byteorder!! */
+       Int32_t c_bsize;                /* must convert byteorder!! */
+};
+
+typedef struct scg_ops {
+       int     (*scgo_send)            __PR((SCSI *scgp));
+
+       char *  (*scgo_version)         __PR((SCSI *scgp, int what));
+       int     (*scgo_open)            __PR((SCSI *scgp, char *device));
+       int     (*scgo_close)           __PR((SCSI *scgp));
+       long    (*scgo_maxdma)          __PR((SCSI *scgp, long amt));
+       void *  (*scgo_getbuf)          __PR((SCSI *scgp, long amt));
+       void    (*scgo_freebuf)         __PR((SCSI *scgp));
+
+
+       BOOL    (*scgo_havebus)         __PR((SCSI *scgp, int busno));
+       int     (*scgo_fileno)          __PR((SCSI *scgp, int busno, int tgt, int tlun));
+       int     (*scgo_initiator_id)    __PR((SCSI *scgp));
+       int     (*scgo_isatapi)         __PR((SCSI *scgp));
+       int     (*scgo_reset)           __PR((SCSI *scgp, int what));
+} scg_ops_t;
+
+typedef struct {
+       int     scsibus;        /* SCSI bus #    for next I/O           */
+       int     target;         /* SCSI target # for next I/O           */
+       int     lun;            /* SCSI lun #    for next I/O           */
+} scg_addr_t;
+
+typedef        struct scg_scsi SCSI;
+struct scg_scsi {
+       scg_ops_t *ops;         /* Ptr to low level SCSI transport ops  */
+       int     fd;             /* File descriptor for next I/O         */
+       scg_addr_t      addr;   /* SCSI address for next I/O            */
+       int     flags;          /* Libscg flags (see below)             */
+       int     dflags;         /* Drive specific flags (see below)     */
+       int     kdebug;         /* Kernel debug value for next I/O      */
+       int     debug;          /* Debug value for SCSI library         */
+       int     silent;         /* Be silent if value > 0               */
+       int     verbose;        /* Be verbose if value > 0              */
+       int     overbose;       /* Be verbose in open() if value > 0    */
+       int     disre_disable;
+       int     deftimeout;
+       int     noparity;       /* Do not use SCSI parity fo next I/O   */
+       int     dev;            /* from scsi_cdr.c                      */
+       struct scg_cmd *scmd;
+       char    *cmdname;
+       char    *curcmdname;
+       BOOL    running;
+       int     error;          /* libscg error number                  */
+
+       long    maxdma;         /* Max DMA limit for this open instance */
+       long    maxbuf;         /* Cur DMA buffer limit for this inst.  */
+                               /* This is the size behind bufptr       */
+       struct timeval  *cmdstart;
+       struct timeval  *cmdstop;
+       const char      **nonstderrs;
+       void    *local;         /* Local data from the low level code   */
+       void    *bufbase;       /* needed for scsi_freebuf()            */
+       void    *bufptr;        /* DMA buffer pointer for appl. use     */
+       char    *errstr;        /* Error string for scsi_open/sendmcd   */
+       char    *errbeg;        /* Pointer to begin of not flushed data */
+       char    *errptr;        /* Actual write pointer into errstr     */
+       void    *errfile;       /* FILE to write errors to. NULL for not*/
+                               /* writing and leaving errs in errstr   */
+
+       struct scsi_inquiry *inq;
+       struct scsi_capacity *cap;
+};
+#define        scg_scsibus(scgp)       (scgp)->addr.scsibus
+#define        scg_target(scgp)        (scgp)->addr.target
+#define        scg_lun(scgp)           (scgp)->addr.lun
+
+#define        SCSI_ERRSTR_SIZE        4096
+
+#define SC_TEST_UNIT_READY     0x00
+#define SC_REZERO_UNIT         0x01
+#define SC_REQUEST_SENSE       0x03
+#define SC_FORMAT              0x04
+#define SC_FORMAT_TRACK                0x06
+#define SC_REASSIGN_BLOCK      0x07            /* CCS only */
+#define SC_SEEK                        0x0b
+#define SC_TRANSLATE           0x0f            /* ACB4000 only */
+#define SC_INQUIRY             0x12            /* CCS only */
+#define SC_MODE_SELECT         0x15
+#define SC_RESERVE             0x16
+#define SC_RELEASE             0x17
+#define SC_MODE_SENSE          0x1a
+#define SC_START               0x1b
+#define SC_READ_DEFECT_LIST    0x37            /* CCS only, group 1 */
+#define SC_READ_BUFFER          0x3c            /* CCS only, group 1 */
+
+#if    defined(_BIT_FIELDS_LTOH)       /* Intel byteorder */
+struct scsi_g0cdb {            /* scsi group 0 command description block */
+       Uchar   cmd;            /* command code */
+       Ucbit   high_addr : 5;  /* high part of block address */
+       Ucbit   lun       : 3;  /* logical unit number */
+       Uchar   mid_addr;       /* middle part of block address */
+       Uchar   low_addr;       /* low part of block address */
+       Uchar   count;          /* transfer length */
+       Ucbit   link      : 1;  /* link (another command follows) */
+       Ucbit   fr        : 1;  /* flag request (interrupt at completion) */
+       Ucbit   rsvd      : 4;  /* reserved */
+       Ucbit   vu_56     : 1;  /* vendor unique (byte 5 bit 6) */
+       Ucbit   vu_57     : 1;  /* vendor unique (byte 5 bit 7) */
+};
+#else  /* Motorola byteorder */
+struct scsi_g0cdb {            /* scsi group 0 command description block */
+       Uchar   cmd;            /* command code */
+       Ucbit   lun       : 3;  /* logical unit number */
+       Ucbit   high_addr : 5;  /* high part of block address */
+       Uchar   mid_addr;       /* middle part of block address */
+       Uchar   low_addr;       /* low part of block address */
+       Uchar   count;          /* transfer length */
+       Ucbit   vu_57     : 1;  /* vendor unique (byte 5 bit 7) */
+       Ucbit   vu_56     : 1;  /* vendor unique (byte 5 bit 6) */
+       Ucbit   rsvd      : 4;  /* reserved */
+       Ucbit   fr        : 1;  /* flag request (interrupt at completion) */
+       Ucbit   link      : 1;  /* link (another command follows) */
+};
+#endif
+
+#if    defined(_BIT_FIELDS_LTOH)       /* Intel byteorder */
+struct scsi_g1cdb {            /* scsi group 1 command description block */
+       Uchar   cmd;            /* command code */
+       Ucbit   reladr    : 1;  /* address is relative */
+       Ucbit   res       : 4;  /* reserved bits 1-4 of byte 1 */
+       Ucbit   lun       : 3;  /* logical unit number */
+       Uchar   addr[4];        /* logical block address */
+       Uchar   res6;           /* reserved byte 6 */
+       Uchar   count[2];       /* transfer length */
+       Ucbit   link      : 1;  /* link (another command follows) */
+       Ucbit   fr        : 1;  /* flag request (interrupt at completion) */
+       Ucbit   rsvd      : 4;  /* reserved */
+       Ucbit   vu_96     : 1;  /* vendor unique (byte 5 bit 6) */
+       Ucbit   vu_97     : 1;  /* vendor unique (byte 5 bit 7) */
+};
+#else  /* Motorola byteorder */
+struct scsi_g1cdb {            /* scsi group 1 command description block */
+       Uchar   cmd;            /* command code */
+       Ucbit   lun       : 3;  /* logical unit number */
+       Ucbit   res       : 4;  /* reserved bits 1-4 of byte 1 */
+       Ucbit   reladr    : 1;  /* address is relative */
+       Uchar   addr[4];        /* logical block address */
+       Uchar   res6;           /* reserved byte 6 */
+       Uchar   count[2];       /* transfer length */
+       Ucbit   vu_97     : 1;  /* vendor unique (byte 5 bit 7) */
+       Ucbit   vu_96     : 1;  /* vendor unique (byte 5 bit 6) */
+       Ucbit   rsvd      : 4;  /* reserved */
+       Ucbit   fr        : 1;  /* flag request (interrupt at completion) */
+       Ucbit   link      : 1;  /* link (another command follows) */
+};
+#endif
+
+#if    defined(_BIT_FIELDS_LTOH)       /* Intel byteorder */
+struct scsi_g5cdb {            /* scsi group 5 command description block */
+       Uchar   cmd;            /* command code */
+       Ucbit   reladr    : 1;  /* address is relative */
+       Ucbit   res       : 4;  /* reserved bits 1-4 of byte 1 */
+       Ucbit   lun       : 3;  /* logical unit number */
+       Uchar   addr[4];        /* logical block address */
+       Uchar   count[4];       /* transfer length */
+       Uchar   res10;          /* reserved byte 10 */
+       Ucbit   link      : 1;  /* link (another command follows) */
+       Ucbit   fr        : 1;  /* flag request (interrupt at completion) */
+       Ucbit   rsvd      : 4;  /* reserved */
+       Ucbit   vu_B6     : 1;  /* vendor unique (byte B bit 6) */
+       Ucbit   vu_B7     : 1;  /* vendor unique (byte B bit 7) */
+};
+#else  /* Motorola byteorder */
+struct scsi_g5cdb {            /* scsi group 5 command description block */
+       Uchar   cmd;            /* command code */
+       Ucbit   lun       : 3;  /* logical unit number */
+       Ucbit   res       : 4;  /* reserved bits 1-4 of byte 1 */
+       Ucbit   reladr    : 1;  /* address is relative */
+       Uchar   addr[4];        /* logical block address */
+       Uchar   count[4];       /* transfer length */
+       Uchar   res10;          /* reserved byte 10 */
+       Ucbit   vu_B7     : 1;  /* vendor unique (byte B bit 7) */
+       Ucbit   vu_B6     : 1;  /* vendor unique (byte B bit 6) */
+       Ucbit   rsvd      : 4;  /* reserved */
+       Ucbit   fr        : 1;  /* flag request (interrupt at completion) */
+       Ucbit   link      : 1;  /* link (another command follows) */
+};
+#endif
+
+struct scsi_status {
+       Ucbit   vu_00   : 1;    /* vendor unique */
+       Ucbit   chk     : 1;    /* check condition: sense data available */
+       Ucbit   cm      : 1;    /* condition met */
+       Ucbit   busy    : 1;    /* device busy or reserved */
+       Ucbit   is      : 1;    /* intermediate status sent */
+       Ucbit   vu_05   : 1;    /* vendor unique */
+#define st_scsi2       vu_05   /* SCSI-2 modifier bit */
+       Ucbit   vu_06   : 1;    /* vendor unique */
+       Ucbit   st_rsvd : 1;    /* reserved */
+
+#ifdef SCSI_EXTENDED_STATUS
+#define        ext_st1 st_rsvd         /* extended status (next byte valid) */
+       /* byte 1 */
+       Ucbit   ha_er   : 1;    /* host adapter detected error */
+       Ucbit   reserved: 6;    /* reserved */
+       Ucbit   ext_st2 : 1;    /* extended status (next byte valid) */
+       /* byte 2 */
+       Uchar   byte2;          /* third byte */
+#endif /* SCSI_EXTENDED_STATUS */
+};
+
+#if    defined(_BIT_FIELDS_LTOH)       /* Intel byteorder */
+struct scsi_sense {            /* scsi sense for error classes 0-6 */
+       Ucbit   code    : 7;    /* error class/code */
+       Ucbit   adr_val : 1;    /* sense data is valid */
+#ifdef comment
+       Ucbit   high_addr:5;    /* high byte of block addr */
+       Ucbit   rsvd    : 3;
+#else
+       Uchar   high_addr;      /* high byte of block addr */
+#endif
+       Uchar   mid_addr;       /* middle byte of block addr */
+       Uchar   low_addr;       /* low byte of block addr */
+};
+#else  /* Motorola byteorder */
+struct scsi_sense {            /* scsi sense for error classes 0-6 */
+       Ucbit   adr_val : 1;    /* sense data is valid */
+       Ucbit   code    : 7;    /* error class/code */
+#ifdef comment
+       Ucbit   rsvd    : 3;
+       Ucbit   high_addr:5;    /* high byte of block addr */
+#else
+       Uchar   high_addr;      /* high byte of block addr */
+#endif
+       Uchar   mid_addr;       /* middle byte of block addr */
+       Uchar   low_addr;       /* low byte of block addr */
+};
+#endif
+
+#define        SCG_MAX_CMD     24      /* 24 bytes max. size is supported */
+#define        SCG_MAX_STATUS  3       /* XXX (sollte 4 allign.) Mamimum Status Len */
+#define        SCG_MAX_SENSE   32      /* Mamimum Sense Len for auto Req. Sense */
+
+#define        DEF_SENSE_LEN   16      /* Default Sense Len */
+#define        CCS_SENSE_LEN   18      /* Sense Len for CCS compatible devices */
+
+#define        SCG_RECV_DATA   0x0001          /* DMA direction to Sun */
+#define        SCG_DISRE_ENA   0x0002          /* enable disconnect/reconnect */
+
+#define SCG_NO_ERROR   0               /* cdb transported without error     */
+#define SCG_RETRYABLE  1               /* any other case e.g. SCSI bus busy */
+#define SCG_FATAL      2               /* could not select target           */
+#define SCG_TIMEOUT    3               /* driver timed out                  */
+
+#define        SC_G0_CDBLEN    6       /* Len of Group 0 commands */
+#define        SC_G1_CDBLEN    10      /* Len of Group 1 commands */
+#define        SC_G5_CDBLEN    12      /* Len of Group 5 commands */
+
+struct scg_cmd {
+       caddr_t addr;                   /* Address of data in user space */
+       int     size;                   /* DMA count for data transfer */
+       int     flags;                  /* see below for definition */
+       int     cdb_len;                /* Size of SCSI command in bytes */
+                                       /* NOTE: rel 4 uses this field only */
+                                       /* with commands not in group 1 or 2*/
+       int     sense_len;              /* for intr() if -1 don't get sense */
+       int     timeout;                /* timeout in seconds */
+                                       /* NOTE: actual resolution depends */
+                                       /* on driver implementation */
+       int     kdebug;                 /* driver kernel debug level */
+       int     resid;                  /* Bytes not transfered */
+       int     error;                  /* Error code from scgintr() */
+       int     ux_errno;               /* UNIX error code */
+       union {
+               struct  scsi_status Scb;/* Status returnd by command */
+               Uchar   cmd_scb[SCG_MAX_STATUS];
+       } u_scb;
+#define        scb     u_scb.Scb
+       union {
+               struct  scsi_sense Sense;/* Sense bytes from command */
+               Uchar   cmd_sense[SCG_MAX_SENSE];
+       } u_sense;
+#define        sense   u_sense.Sense
+       int     sense_count;            /* Number of bytes valid in sense */
+       int     target;                 /* SCSI target id */
+                                       /* NOTE: The SCSI target id field    */
+                                       /* does not need to be filled unless */
+                                       /* the low level transport is a real */
+                                       /* scg driver. In this case the low  */
+                                       /* level transport routine of libscg */
+                                       /* will fill in the needed value     */
+       union {                         /* SCSI command descriptor block */
+               struct  scsi_g0cdb g0_cdb;
+               struct  scsi_g1cdb g1_cdb;
+               struct  scsi_g5cdb g5_cdb;
+               Uchar   cmd_cdb[SCG_MAX_CMD];
+       } cdb;                          /* 24 bytes max. size is supported */
+};
+
+#if    defined(_BIT_FIELDS_LTOH)       /* Intel byteorder */
+struct scsi_inquiry {
+       Ucbit   type            : 5;    /*  0 */
+       Ucbit   qualifier       : 3;    /*  0 */
+
+       Ucbit   type_modifier   : 7;    /*  1 */
+       Ucbit   removable       : 1;    /*  1 */
+
+       Ucbit   ansi_version    : 3;    /*  2 */
+       Ucbit   ecma_version    : 3;    /*  2 */
+       Ucbit   iso_version     : 2;    /*  2 */
+
+       Ucbit   data_format     : 4;    /*  3 */
+       Ucbit   res3_54         : 2;    /*  3 */
+       Ucbit   termiop         : 1;    /*  3 */
+       Ucbit   aenc            : 1;    /*  3 */
+
+       Ucbit   add_len         : 8;    /*  4 */
+       Ucbit   sense_len       : 8;    /*  5 */ /* only Emulex ??? */
+       Ucbit   res2            : 8;    /*  6 */
+
+       Ucbit   softreset       : 1;    /*  7 */
+       Ucbit   cmdque          : 1;
+       Ucbit   res7_2          : 1;
+       Ucbit   linked          : 1;
+       Ucbit   sync            : 1;
+       Ucbit   wbus16          : 1;
+       Ucbit   wbus32          : 1;
+       Ucbit   reladr          : 1;    /*  7 */
+
+       char    vendor_info[8];         /*  8 */
+       char    prod_ident[16];         /* 16 */
+       char    prod_revision[4];       /* 32 */
+#ifdef comment
+       char    vendor_uniq[20];        /* 36 */
+       char    reserved[40];           /* 56 */
+#endif
+};                                     /* 96 */
+#else                                  /* Motorola byteorder */
+struct scsi_inquiry {
+       Ucbit   qualifier       : 3;    /*  0 */
+       Ucbit   type            : 5;    /*  0 */
+
+       Ucbit   removable       : 1;    /*  1 */
+       Ucbit   type_modifier   : 7;    /*  1 */
+
+       Ucbit   iso_version     : 2;    /*  2 */
+       Ucbit   ecma_version    : 3;
+       Ucbit   ansi_version    : 3;    /*  2 */
+
+       Ucbit   aenc            : 1;    /*  3 */
+       Ucbit   termiop         : 1;
+       Ucbit   res3_54         : 2;
+       Ucbit   data_format     : 4;    /*  3 */
+
+       Ucbit   add_len         : 8;    /*  4 */
+       Ucbit   sense_len       : 8;    /*  5 */ /* only Emulex ??? */
+       Ucbit   res2            : 8;    /*  6 */
+       Ucbit   reladr          : 1;    /*  7 */
+       Ucbit   wbus32          : 1;
+       Ucbit   wbus16          : 1;
+       Ucbit   sync            : 1;
+       Ucbit   linked          : 1;
+       Ucbit   res7_2          : 1;
+       Ucbit   cmdque          : 1;
+       Ucbit   softreset       : 1;
+       char    vendor_info[8];         /*  8 */
+       char    prod_ident[16];         /* 16 */
+       char    prod_revision[4];       /* 32 */
+#ifdef comment
+       char    vendor_uniq[20];        /* 36 */
+       char    reserved[40];           /* 56 */
+#endif
+};                                     /* 96 */
+#endif
+
diff --git a/od-win32/serial_win32.c b/od-win32/serial_win32.c
new file mode 100755 (executable)
index 0000000..224b134
--- /dev/null
@@ -0,0 +1,489 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  *  Serial Line Emulation
+  *
+  * (c) 1996, 1997 Stefan Reinauer <stepan@linux.de>
+  * (c) 1997 Christian Schmitt <schmitt@freiburg.linux.de>
+  *
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+#include "config.h"
+#include "options.h"
+#include "uae.h"
+#include "memory.h"
+#include "custom.h"
+#include "events.h"
+#include "newcpu.h"
+#include "cia.h"
+#include "serial.h"
+
+#include "od-win32/parser.h"
+
+#define SERIALDEBUG 0 /* 0, 1, 2 3 */
+#define SERIALHSDEBUG 0
+#define MODEMTEST   0 /* 0 or 1 */
+
+static int data_in_serdat; /* new data written to SERDAT */
+static int data_in_serdatr; /* new data received */
+static int data_in_sershift; /* data transferred from SERDAT to shift register */
+static uae_u16 serdatshift; /* serial shift register */
+static int ovrun;
+static int dtr;
+static int serial_period_hsyncs, serial_period_hsync_counter;
+static int ninebit;
+int serdev;
+
+void serial_open(void);
+void serial_close(void);
+
+uae_u16 serper, serdat, serdatr;
+
+static int allowed_baudrates[] =
+    { 0, 110, 300, 600, 1200, 2400, 4800, 9600, 14400,
+       19200, 31400, 38400, 57600, 115200, 128000, 256000, -1 };
+
+void SERPER (uae_u16 w)
+{
+    int baud = 0, i, per;
+    static int warned;
+
+    if (serper == w)  /* don't set baudrate if it's already ok */
+       return;
+    ninebit = 0;
+    serper = w;
+
+    if (w & 0x8000) {
+        if (!warned) {
+            write_log( "SERIAL: program uses 9bit mode PC=%x\n", m68k_getpc() );
+           warned++;
+        }
+        ninebit = 1;
+    }
+    w &= 0x7fff;
+
+    if (w < 13)
+       w = 13;
+
+    per = w;
+    if (per == 0) per = 1;
+    per = 3546895 / (per + 1);
+    if (per <= 0) per = 1;
+    i = 0;
+    while (allowed_baudrates[i] >= 0 && per > allowed_baudrates[i] * 100 / 97)
+       i++;
+    baud = allowed_baudrates[i];
+
+    serial_period_hsyncs = (((serper & 0x7fff) + 1) * 10) / maxhpos;
+    if (serial_period_hsyncs <= 0)
+       serial_period_hsyncs = 1;
+    serial_period_hsync_counter = 0;
+
+    write_log ("SERIAL: period=%d, baud=%d, hsyncs=%d PC=%x\n", w, baud, serial_period_hsyncs, m68k_getpc());
+
+    if (!currprefs.use_serial)
+       return;
+
+    if (ninebit)
+       baud *= 2;
+    if (currprefs.serial_direct) {
+       if (baud != 31400 && baud < 115200)
+           baud = 115200;
+       serial_period_hsyncs = 1;
+    }
+#ifdef SERIAL_PORT
+    setbaud (baud);
+#endif
+}
+
+static char dochar (int v)
+{
+    v &= 0xff;
+    if (v >= 32 && v < 127) return (char)v;
+    return '.';
+}
+
+static void checkreceive (int mode)
+{
+#ifdef SERIAL_PORT
+    static uae_u32 lastchartime;
+    static int ninebitdata;
+    struct timeval tv;
+    int recdata;
+
+    if (!currprefs.use_serial)
+       return;
+
+    if (!readseravail())
+       return;
+
+    if (data_in_serdatr) {
+        /* probably not needed but there may be programs that expect OVRUNs.. */
+       gettimeofday (&tv, NULL);
+       if (tv.tv_sec > lastchartime) {
+           ovrun = 1;
+           INTREQ (0x8000 | 0x0800);
+           while (readser (&recdata));
+           write_log ("SERIAL: overrun\n");
+       }
+       return;
+    }
+
+    if (ninebit) {
+       for (;;) {
+           if (!readser (&recdata))
+               return;
+           if (ninebitdata) {
+               serdatr = (ninebitdata & 1) << 8;
+               serdatr |= recdata;
+               serdatr |= 0x200;
+               ninebitdata = 0;
+               break;
+           } else {
+               ninebitdata = recdata;
+               if ((ninebitdata & ~1) != 0xa8) {
+                   write_log ("SERIAL: 9-bit serial emulation sync lost, %02.2X != %02.2X\n", ninebitdata & ~1, 0xa8);
+                   ninebitdata = 0;
+                   return;
+               }
+               continue;
+           }
+       }
+    } else {
+        if (!readser (&recdata))
+           return;
+       serdatr = recdata;
+        serdatr |= 0x100;
+    }
+    gettimeofday (&tv, NULL);
+    lastchartime = tv.tv_sec + 5;
+    data_in_serdatr = 1;
+    serial_check_irq ();
+#if SERIALDEBUG > 2
+    write_log ("SERIAL: received %02.2X (%c)\n", serdatr & 0xff, dochar (serdatr));
+#endif
+#endif
+}
+
+static void checksend (int mode)
+{
+    int bufstate = 0;
+
+#ifdef SERIAL_PORT
+    bufstate = checkserwrite ();
+#endif
+    if (!data_in_serdat && !data_in_sershift)
+       return;
+
+    if (!currprefs.use_serial)
+       bufstate = 1;
+
+    if (data_in_sershift && mode == 0 && bufstate)
+       data_in_sershift = 0;
+
+    if (data_in_serdat && !data_in_sershift) {
+       data_in_sershift = 1;
+       serdatshift = serdat;
+#ifdef SERIAL_PORT
+       if (currprefs.use_serial) {
+           if (ninebit)
+               writeser (((serdatshift >> 8) & 1) | 0xa8);
+           writeser (serdatshift);
+       }
+#endif
+       data_in_serdat = 0;
+        INTREQ (0x8000 | 0x0001);
+#if SERIALDEBUG > 2
+       write_log ("SERIAL: send %04.4X (%c)\n", serdatshift, dochar (serdatshift));
+#endif
+    }
+}    
+
+void serial_hsynchandler (void)
+{
+#ifdef AHI
+    extern void hsyncstuff(void);
+    hsyncstuff();
+#endif
+    if (serial_period_hsyncs == 0)
+       return;
+    serial_period_hsync_counter++;
+    if (serial_period_hsyncs == 1 || (serial_period_hsync_counter % (serial_period_hsyncs - 1)) == 0)
+       checkreceive (0);
+    if ((serial_period_hsync_counter % serial_period_hsyncs) == 0)
+       checksend (0);
+}
+
+/* Not (fully) implemented yet: (on windows this work)
+ *
+ *  -  Something's wrong with the Interrupts.
+ *     (NComm works, TERM does not. TERM switches to a
+ *     blind mode after a connect and wait's for the end
+ *     of an asynchronous read before switching blind
+ *     mode off again. It never gets there on UAE :-< )
+ *
+ */
+
+void SERDAT (uae_u16 w)
+{
+    serdat = w;
+
+    if (!(w & 0x3ff)) {
+#if SERIALDEBUG > 1
+       write_log ("SERIAL: zero serial word written?! PC=%x\n", m68k_getpc());
+#endif
+       return;
+    }
+
+#if SERIALDEBUG > 1
+    if (data_in_serdat) {
+       write_log ("SERIAL: program wrote to SERDAT but old byte wasn't fetched yet\n");
+    }
+#endif
+    
+    data_in_serdat = 1;
+    if (!data_in_sershift)
+       checksend (1);
+
+#if SERIALDEBUG > 2
+    write_log ("SERIAL: wrote 0x%04x (%c) PC=%x\n", w, dochar (w), m68k_getpc());
+#endif
+
+    return;
+}
+
+uae_u16 SERDATR (void)
+{
+    serdatr &= 0x03ff;
+    if (!data_in_serdat)
+       serdatr |= 0x2000;
+    if (!data_in_sershift)
+       serdatr |= 0x1000;
+    if (data_in_serdatr)
+       serdatr |= 0x4000;
+    if (ovrun)
+       serdatr |= 0x8000;
+#if SERIALDEBUG > 2
+    write_log( "SERIAL: read 0x%04.4x (%c) %x\n", serdatr, dochar (serdatr), m68k_getpc());
+#endif
+    ovrun = 0;
+    data_in_serdatr = 0;
+    return serdatr;
+}
+
+void serial_check_irq (void)
+{
+    if (data_in_serdatr)
+        INTREQ_0 (0x8000 | 0x0800);
+}
+
+void serial_dtr_on(void)
+{
+#if SERIALHSDEBUG > 0
+    write_log( "SERIAL: DTR on\n" );
+#endif
+    dtr = 1;
+    if (currprefs.serial_demand)
+       serial_open ();
+#ifdef SERIAL_PORT
+    setserstat(TIOCM_DTR, dtr);
+#endif
+}
+
+void serial_dtr_off(void)
+{
+#if SERIALHSDEBUG > 0
+    write_log( "SERIAL: DTR off\n" );
+#endif
+    dtr = 0;
+#ifdef SERIAL_PORT
+    if (currprefs.serial_demand)
+       serial_close ();
+    setserstat(TIOCM_DTR, dtr);
+#endif
+}
+
+void serial_flush_buffer(void)
+{
+}
+
+static uae_u8 oldserbits;
+
+static void serial_status_debug(char *s)
+{
+#if SERIALHSDEBUG > 1
+    write_log("%s: DTR=%d RTS=%d CD=%d CTS=%d DSR=%d\n", s,
+       (oldserbits & 0x80) ? 0 : 1, (oldserbits & 0x40) ? 0 : 1,
+       (oldserbits & 0x20) ? 0 : 1, (oldserbits & 0x10) ? 0 : 1, (oldserbits & 0x08) ? 0 : 1);
+#endif
+}
+
+uae_u8 serial_readstatus(uae_u8 dir)
+{
+    int status = 0;
+    uae_u8 serbits = oldserbits;
+
+#ifdef SERIAL_PORT
+    getserstat (&status);
+#endif
+    if (!(status & TIOCM_CAR)) {
+       if (!(serbits & 0x20)) {
+           serbits |= 0x20;
+#if SERIALHSDEBUG > 0
+           write_log( "SERIAL: CD off\n" );
+#endif
+       }
+    } else {
+       if (serbits & 0x20) {
+           serbits &= ~0x20;
+#if SERIALHSDEBUG > 0
+           write_log( "SERIAL: CD on\n" );
+#endif
+       }
+    }
+
+    if (!(status & TIOCM_DSR)) {
+        if (!(serbits & 0x08)) {
+           serbits |= 0x08;
+#if SERIALHSDEBUG > 0
+           write_log( "SERIAL: DSR off\n" );
+#endif
+        }
+    } else {
+        if (serbits & 0x08) {
+           serbits &= ~0x08;
+#if SERIALHSDEBUG > 0
+           write_log( "SERIAL: DSR on\n" );
+#endif
+       }
+    }
+
+    if (!(status & TIOCM_CTS)) {
+        if (!(serbits & 0x10)) {
+           serbits |= 0x10;
+#if SERIALHSDEBUG > 0
+           write_log( "SERIAL: CTS off\n" );
+#endif
+        }
+    } else {
+        if (serbits & 0x10) {
+           serbits &= ~0x10;
+#if SERIALHSDEBUG > 0
+           write_log( "SERIAL: CTS on\n" );
+#endif
+       }
+    }
+
+    serbits &= 0x08 | 0x10 | 0x20;
+    oldserbits &= ~(0x08 | 0x10 | 0x20);
+    oldserbits |= serbits;
+
+    serial_status_debug("read");
+
+    return oldserbits;
+}
+
+uae_u8 serial_writestatus (uae_u8 newstate, uae_u8 dir)
+{
+#ifdef SERIAL_PORT
+    if (((oldserbits ^ newstate) & 0x80) && (dir & 0x80)) {
+       if (newstate & 0x80)
+           serial_dtr_off();
+       else
+           serial_dtr_on();
+    }
+
+    if (!currprefs.serial_hwctsrts && (dir & 0x40)) {
+       if ((oldserbits ^ newstate) & 0x40) {
+           if (newstate & 0x40) {
+               setserstat (TIOCM_RTS, 0);
+#if SERIALHSDEBUG > 0
+               write_log ("SERIAL: RTS cleared\n");
+#endif
+           } else {
+               setserstat (TIOCM_RTS, 1);
+#if SERIALHSDEBUG > 0
+               write_log ("SERIAL: RTS set\n");
+#endif
+           }
+       }
+    }
+
+ #if 0 /* CIA io-pins can be read even when set to output.. */
+    if ((newstate & 0x20) != (oldserbits & 0x20) && (dir & 0x20))
+        write_log ("SERIAL: warning, program tries to use CD as an output!\n");
+    if ((newstate & 0x10) != (oldserbits & 0x10) && (dir & 0x10))
+        write_log ("SERIAL: warning, program tries to use CTS as an output!\n");
+    if ((newstate & 0x08) != (oldserbits & 0x08) && (dir & 0x08))
+        write_log ("SERIAL: warning, program tries to use DSR as an output!\n");
+#endif
+
+    if (((newstate ^ oldserbits) & 0x40) && !(dir & 0x40))
+        write_log ("SERIAL: warning, program tries to use RTS as an input!\n");
+    if (((newstate ^ oldserbits) & 0x80) && !(dir & 0x80))
+        write_log ("SERIAL: warning, program tries to use DTR as an input!\n");
+
+#endif
+
+    oldserbits &= ~(0x80 | 0x40);
+    newstate &= 0x80 | 0x40;
+    oldserbits |= newstate;
+    serial_status_debug("write");
+
+    return oldserbits;
+}
+
+void serial_open(void)
+{
+#ifdef SERIAL_PORT
+    if (serdev)
+       return;
+
+    if( !openser( currprefs.sername ) )
+    {
+        write_log( "SERIAL: Could not open device %s\n", currprefs.sername );
+        return;
+    }
+    serdev = 1;
+#endif
+}
+
+void serial_close (void)
+{
+#ifdef SERIAL_PORT
+    closeser();
+    serdev = 0;
+#endif
+}
+
+void serial_init (void)
+{
+#ifdef SERIAL_PORT
+    if (!currprefs.use_serial)
+       return;
+
+    if (!currprefs.serial_demand)
+       serial_open ();
+
+    serdat = 0x2000;
+#endif
+}
+
+void serial_exit (void)
+{
+#ifdef SERIAL_PORT
+    serial_close ();   /* serial_close can always be called because it */
+#endif
+    dtr = 0;           /* just closes *opened* filehandles which is ok */
+    oldserbits = 0;    /* when exiting.                                */
+}
+
+void serial_uartbreak (int v)
+{
+#ifdef SERIAL_PORT
+    serialuartbreak (v);
+#endif
+}
diff --git a/od-win32/sfhelper.c b/od-win32/sfhelper.c
new file mode 100755 (executable)
index 0000000..36578fe
--- /dev/null
@@ -0,0 +1,122 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+int main (int argc, char **argv)
+{
+    char *wu;
+    FILE *f;
+    uae_u8 *b, *p1, *p2, *p3, *cfgbuf, *databuf;
+    int size, size2, i, num, offset;    
+
+    if (argc < 4) {
+       printf("Usage: sfhelper.exe <winuae.exe> <config file> <file1> [<file2>..]");
+       return 0;
+    }
+    wu = argv[1];
+    f = fopen(wu,"rb");
+    if (!f) {
+       printf("Couldn't open '%s'\n", wu);
+       return 0;
+    }
+    fseek (f, 0, SEEK_END);
+    size = ftell(f);
+    fseek (f, 0, SEEK_SET);
+    b = malloc (size);
+    if (!b) {
+       printf ("out of memory, can't allocate %d bytes\n", size);
+       return 0;
+    }
+    fread (b, size, 1, f);
+    fclose (f);
+
+    cfgbuf = databuf = 0;
+    p1 = b;
+    while (p1 < b + size) {
+       if (*p1 == '_') {
+           if (!strcmp (p1, "_CONFIG_STARTS_HERE"))
+               cfgbuf = p1;
+           if (!strcmp (p1, "_DATA_STARTS_HERE"))
+               databuf = p1;
+       }
+        p1++;
+       if (cfgbuf && databuf)
+           break;
+    }
+
+    if (!cfgbuf || !databuf) {
+       printf ("couldn't find preallocated data buffer");
+       return 0;
+    }
+
+    while (*cfgbuf++);
+    printf ("processing config file...\n");
+    f = fopen(argv[2],"rb");
+    if (!f) {
+       printf ("Couldn't open config file '%s'\n", argv[2]);
+       return 0;
+    }
+    fread (cfgbuf, 1, 50000, f);
+    fclose (f);
+    printf ("done\n");
+
+    num = argc - 3;
+    offset = num * 256;
+    p1 = databuf + offset;
+    p2 = databuf;
+    while (*p2++);
+    memset (p2, 0, offset);
+    *p2++ = offset >> 24;
+    *p2++ = offset >> 16;
+    *p2++ = offset >> 8;
+    *p2++ = offset >> 0;
+    for (i = 0; i < num; i++) {
+       printf ("processing '%s'\n", argv[i + 3]);
+       f = fopen(argv[i + 3], "rb");
+       if (!f) {
+           printf ("Couldn't open '%s'\n", argv[i + 3]);
+           return 0;
+       }
+       fseek (f, 0, SEEK_END);
+       size2 = ftell (f);
+       fseek (f, 0, SEEK_SET);
+       fread (p1, 1, size2, f);
+       fclose (f);
+       *p2++ = size2 >> 24;
+       *p2++ = size2 >> 16;
+       *p2++ = size2 >> 8;
+       *p2++ = size2 >> 0;
+       p3 = argv[i + 3] + strlen (argv[i + 3]) - 1;
+       while (p3 > argv[i + 3] && *p3 != '/' && *p3 != '\\') p3--;
+       if (p3 > argv[i + 3])
+           p3++;
+       strcpy (p2, p3);
+       p2 += strlen (p2) + 1;
+       printf ("saved as '%s'\n", p3);
+    }
+    printf ("Writing updated '%s'\n", wu);
+    f = fopen(wu,"wb");
+    if (!f) {
+       printf("Couldn't open '%s' for writing\n", wu);
+       return 0;
+    }
+    fwrite (b, 1, size, f);
+    fclose (f);
+    printf ("done\n");
+    return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/od-win32/shm.c b/od-win32/shm.c
new file mode 100755 (executable)
index 0000000..ed970b5
--- /dev/null
@@ -0,0 +1,172 @@
+#include <float.h>
+
+#include "sysconfig.h" 
+#include "sysdeps.h"
+#include "sys/mman.h"
+#include "include/memory.h"
+#include "options.h"
+#include "autoconf.h"
+
+static void win32_error (const char *format,...)
+{
+    LPVOID lpMsgBuf;
+    va_list arglist;
+    char buf[1000];
+
+    va_start (arglist, format );
+    vsprintf (buf, format, arglist);
+    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
+       NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+       (LPTSTR) &lpMsgBuf,0,NULL);
+    write_log ("%s: %s",buf , (char*)lpMsgBuf);
+    va_end( arglist );
+}
+
+static struct shmid_ds shmids[ MAX_SHMID ];
+
+uae_u32 natmem_offset;
+
+void init_shm( void )
+{
+    int i;
+
+#ifdef NATMEM_OFFSET
+    uae_u32 addr;
+
+    canbang = 1;
+    for( i = 0; i < MAX_SHMID; i++ ) {
+       shmids[i].attached = 0;
+       shmids[i].key = -1;
+       shmids[i].size = 0;
+       shmids[i].addr = (void*)0xffffffff;
+       shmids[i].name[0] = 0;
+       shmids[i].filemapping = INVALID_HANDLE_VALUE;
+    }
+    addr = 0x10000000;
+    while( addr < 0xa0000000 ) {
+       if (VirtualAlloc( (LPVOID)addr, 0x18800000, MEM_RESERVE, PAGE_EXECUTE_READWRITE )) {
+           VirtualFree ( (LPVOID)addr, 0, MEM_RELEASE);
+           addr += 0x01000000;
+           natmem_offset = addr;
+           break;
+       }
+        addr += 0x01000000;
+    }
+    if (natmem_offset) {
+        write_log( "NATMEM: Our special area is 0x%x\n", natmem_offset);
+    } else {
+       canbang = 0;
+    }
+#endif
+}
+
+static key_t get_next_shmkey( void )
+{
+    key_t result = -1;
+    int i;
+    for( i = 0; i < MAX_SHMID; i++ )
+    {
+       if( shmids[i].key == -1 )
+       {
+           shmids[i].key = i;
+           result = i;
+           break;
+       }
+    }
+    return result;
+}
+
+STATIC_INLINE key_t find_shmkey( key_t key )
+{
+    int result = -1;
+    if( shmids[key].key == key )
+    {
+       result = key;
+    }
+    return result;
+}
+
+int mprotect(void *addr, size_t len, int prot)
+{
+    int result = 0;
+  
+    return result;
+}
+
+int shmget(key_t key, size_t size, int shmflg, char *name)
+{
+    int result = -1;
+
+    if( ( key == IPC_PRIVATE ) || ( ( shmflg & IPC_CREAT ) && ( find_shmkey( key ) == -1) ) ) {
+       write_log( "shmget of size %d for %s\n", size, name );
+       if( ( result = get_next_shmkey() ) != -1 ) {
+               HANDLE h = CreateFileMapping (NULL, 0, PAGE_READWRITE, 0, size, NULL);
+               if (h == NULL)
+                   win32_error ("CreateFileMapping %d\n", size);
+               shmids[result].filemapping = h;
+               shmids[result].size = size;
+               strcpy( shmids[result].name, name );
+       } else {
+           result = -1;
+       }
+    }
+    return result;
+}
+
+int shmctl(int shmid, int cmd, struct shmid_ds *buf)
+{
+    int result = -1;
+
+    return result;
+    if( ( find_shmkey( shmid ) != -1 ) && buf ) {
+       switch( cmd )
+       {
+           case IPC_STAT:
+           *buf = shmids[shmid];
+           result = 0;
+           break;
+           case IPC_RMID:
+           shmids[shmid].key = -1;
+           shmids[shmid].name[0] = '\0';
+           shmids[shmid].size = 0;
+           CloseHandle(shmids[shmid].filemapping);
+           shmids[shmid].filemapping = INVALID_HANDLE_VALUE;
+           result = 0;
+           break;
+       }
+    }
+    return result;
+}
+
+void *shmat(int shmid, LPVOID shmaddr, int shmflg)
+{ 
+    struct shmid_ds *shm = &shmids[shmid];
+
+    if(shm->addr == shmaddr )
+       return shm->addr;
+    shm->addr = MapViewOfFileEx (shm->filemapping, FILE_MAP_WRITE, 0, 0, shm->size, shmaddr);
+    if (addr == NULL)
+       win32_error("MapViewOfFileEx %08.8X", shmaddr);
+    write_log ("shmat %08.8X -> %08.8X\n", shmaddr, shm->addr);
+    shm->attached = 1;
+    return shm->addr;
+}
+
+int shmdt(const void *shmaddr)
+{
+    int i;
+    if (shmaddr == (void*)0xffffffff)
+       return 0;
+    write_log("shmdt: %08.8X\n", shmaddr);
+    if (UnmapViewOfFile ((LPCVOID)shmaddr) == FALSE) {
+       win32_error("UnmapViewOfFile %08.8X", shmaddr);
+       return 0;
+    }
+    for( i = 0; i < MAX_SHMID; i++ ) {
+        struct shmid_ds *shm = &shmids[i];
+       if (shm->addr == shmaddr) {
+           shm->addr = (void*)0xffffffff;
+       }
+    }
+    return -1;
+}
\ No newline at end of file
diff --git a/od-win32/soundcheck.c b/od-win32/soundcheck.c
new file mode 100755 (executable)
index 0000000..5bd1cb1
--- /dev/null
@@ -0,0 +1,562 @@
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <windows.h>
+#include <mmsystem.h>
+#include <dsound.h>
+#include <dxerr8.h>
+
+static int sounddata_frequency = 44100;
+static int sounddata_stereo = 2;
+static int sounddata_bufsize = 262144;
+
+#define write_log printf
+
+#define MAX_SOUND_DEVICES 10
+
+static char *sound_devices[MAX_SOUND_DEVICES];
+static GUID sound_device_guid[MAX_SOUND_DEVICES];
+static int num_sound_devices, devicenum;
+
+static LPDIRECTSOUND lpDS;
+static LPDIRECTSOUNDBUFFER lpDSBprimary;
+static LPDIRECTSOUNDBUFFER lpDSBsecondary;
+
+static uae_u8 sndbuffer[131072];
+static int dsoundbuf, snd_configsize;
+static DWORD writepos;
+static HWND hwnd;
+static LARGE_INTEGER qpf;
+
+static FILE *logfile;
+
+static void write_log2 (const char *format, ...)
+{
+    int count;
+    char buffer[1000];
+
+    va_list parms;
+    va_start (parms, format);
+    count = _vsnprintf( buffer, 1000-1, format, parms );
+    printf("%s", buffer);
+    if (logfile)
+       fwrite(buffer, 1, strlen(buffer), logfile);
+    va_end (parms);
+}
+
+static const char *DXError (HRESULT ddrval)
+{
+    static char dderr[200];
+    sprintf(dderr, "%08.8X S=%d F=%04.4X C=%04.4X (%d) (%s)",
+       ddrval, (ddrval & 0x80000000) ? 1 : 0,
+       HRESULT_FACILITY(ddrval),
+       HRESULT_CODE(ddrval),
+       HRESULT_CODE(ddrval),
+       DXGetErrorDescription8 (ddrval));
+    return dderr;
+}
+
+static void clearbuffer (void)
+{
+    void *buffer;
+    DWORD size;
+
+    HRESULT hr = IDirectSoundBuffer_Lock (lpDSBsecondary, 0, dsoundbuf, &buffer, &size, NULL, NULL, 0);
+    if (hr == DSERR_BUFFERLOST) {
+       IDirectSoundBuffer_Restore (lpDSBsecondary);
+       hr = IDirectSoundBuffer_Lock (lpDSBsecondary, 0, dsoundbuf, &buffer, &size, NULL, NULL, 0);
+    }
+    if (hr != DS_OK) {
+       write_log ("failed to Lock sound buffer (clear): %s\n", DXError (hr));
+       return;
+    }
+    memset (buffer, 0, size);
+    IDirectSoundBuffer_Unlock (lpDSBsecondary, buffer, size, NULL, 0);
+    memset (sndbuffer, 0, sizeof (sndbuffer));
+}
+
+static void pause_audio_ds (void)
+{
+    IDirectSoundBuffer_Stop (lpDSBsecondary);
+    clearbuffer ();
+}
+
+static void resume_audio_ds (void)
+{
+    HRESULT hr;
+    
+    clearbuffer ();
+    hr = IDirectSoundBuffer_Play (lpDSBsecondary, 0, 0, DSBPLAY_LOOPING);
+    if (hr != DS_OK)
+       write_log ("Play failed: %s\n", DXError (hr));
+    writepos = snd_configsize;
+}
+
+static int restore (DWORD hr)
+{
+    if (hr != DSERR_BUFFERLOST)
+       return 0;
+    hr = IDirectSoundBuffer_Restore (lpDSBsecondary);
+    if (hr != DS_OK)
+       return 1;
+    resume_audio_ds ();
+    return 1;
+}
+
+static void close_audio_ds (void)
+{
+    if (lpDSBsecondary)
+       IDirectSound_Release (lpDSBsecondary);
+    if (lpDSBprimary)
+       IDirectSound_Release (lpDSBprimary);
+    lpDSBsecondary = lpDSBprimary = 0;
+    if (lpDS)
+       IDirectSound_Release (lpDS);
+    lpDS = 0;
+}
+
+static int open_audio_ds (void)
+{
+    HRESULT hr;
+    DSBUFFERDESC sound_buffer;
+    DSCAPS DSCaps;
+    DSBCAPS DSBCaps;
+    WAVEFORMATEX wavfmt;
+    int minfreq, maxfreq;
+    int freq = sounddata_frequency;
+    
+    hr = DirectSoundCreate (&sound_device_guid[devicenum], &lpDS, NULL);
+    if (hr != DS_OK)  {
+        write_log ("SOUND: DirectSoundCreate() failure: %s\n", DXError (hr));
+        return 0;
+    }
+    memset (&DSCaps, 0, sizeof (DSCaps));
+    DSCaps.dwSize = sizeof(DSCaps);
+    hr = IDirectSound_GetCaps (lpDS, &DSCaps);
+    if (hr!= DS_OK) {
+       write_log ("SOUND: Error getting DirectSound capabilities: %s\n", DXError (hr));
+       goto error;
+    }
+    if (DSCaps.dwFlags & DSCAPS_EMULDRIVER) {
+       write_log ("SOUND: Emulated DirectSound driver detected, don't complain if sound quality is crap :)\n");
+    }
+    minfreq = DSCaps.dwMinSecondarySampleRate;
+    maxfreq = DSCaps.dwMaxSecondarySampleRate;
+    if (maxfreq > 11000) {
+       if (minfreq > freq) {
+           freq = minfreq;
+           sounddata_frequency = freq;
+           write_log("SOUND: minimum supported frequency: %d\n", minfreq);
+       }
+       if (maxfreq < freq) {
+           freq = maxfreq;
+           sounddata_frequency = freq;
+           write_log("SOUND: maximum supported frequency: %d\n", maxfreq);
+       }
+    } else {
+       write_log("SOUND: ignored weird min (%d) or max (%d) sample rate\n", minfreq, maxfreq);
+    }
+    
+    memset (&sound_buffer, 0, sizeof (sound_buffer));
+    sound_buffer.dwSize = sizeof (sound_buffer);
+    sound_buffer.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_GETCURRENTPOSITION2;
+    hr = IDirectSound_CreateSoundBuffer (lpDS, &sound_buffer, &lpDSBprimary, NULL);
+    if( hr != DS_OK )  {
+        write_log ("SOUND: Primary CreateSoundBuffer() failure: %s\n", DXError (hr));
+       goto error;
+    }
+
+    memset(&DSBCaps, 0, sizeof(DSBCaps));
+    DSBCaps.dwSize = sizeof(DSBCaps);
+    hr = IDirectSoundBuffer_GetCaps(lpDSBprimary, &DSBCaps);
+    if (hr != DS_OK) {
+       write_log ("SOUND: Primary GetCaps() failure: %s\n",  DXError (hr));
+       goto error;
+    }
+
+    wavfmt.wFormatTag = WAVE_FORMAT_PCM;
+    wavfmt.nChannels = sounddata_stereo ? 2 : 1;
+    wavfmt.nSamplesPerSec = freq;
+    wavfmt.wBitsPerSample = 16;
+    wavfmt.nBlockAlign = 16 / 8 * wavfmt.nChannels;
+    wavfmt.nAvgBytesPerSec = wavfmt.nBlockAlign * freq;
+
+    hr = IDirectSound_SetCooperativeLevel (lpDS, hwnd, DSSCL_PRIORITY);
+    if (hr != DS_OK) {
+        write_log ("SOUND: Can't set cooperativelevel: %s\n", DXError (hr));
+        goto error;
+    }
+
+    dsoundbuf = sounddata_bufsize;
+    if (dsoundbuf < DSBSIZE_MIN)
+        dsoundbuf = DSBSIZE_MIN;
+    if (dsoundbuf > DSBSIZE_MAX)
+        dsoundbuf = DSBSIZE_MAX;
+
+    memset (&sound_buffer, 0, sizeof (sound_buffer));
+    sound_buffer.dwSize = sizeof (sound_buffer);
+    sound_buffer.dwBufferBytes = dsoundbuf;
+    sound_buffer.lpwfxFormat = &wavfmt;
+    sound_buffer.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS | DSBCAPS_STATIC;
+
+    hr = IDirectSound_CreateSoundBuffer( lpDS, &sound_buffer, &lpDSBsecondary, NULL );
+    if (hr != DS_OK) {
+        write_log ("SOUND: Secondary CreateSoundBuffer() failure: %s\n", DXError (hr));
+        goto error;
+    }
+
+    hr = IDirectSoundBuffer_SetFormat (lpDSBprimary, &wavfmt);
+    if( hr != DS_OK )  {
+        write_log ("SOUND: Primary SetFormat() failure: %s\n", DXError (hr));
+        goto error;
+    }
+    
+    clearbuffer ();
+
+    return 1;
+
+error:
+    close_audio_ds ();
+    return 0;
+}
+
+static BOOL CALLBACK DSEnumProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName,  LPVOID lpContext)
+{
+    int i = num_sound_devices;
+    if (i == MAX_SOUND_DEVICES)
+       return TRUE;
+    if (lpGUID != NULL)
+       memcpy (&sound_device_guid[i], lpGUID, sizeof (GUID));
+    sound_devices[i] = my_strdup (lpszDesc);
+    num_sound_devices++;
+    return TRUE;
+}
+
+static HWND GetConsoleHwnd(void)
+{
+    #define MY_BUFSIZE 1024 // buffer size for console window titles
+    HWND hwndFound;         // this is what is returned to the caller
+    char pszNewWindowTitle[MY_BUFSIZE]; // contains fabricated WindowTitle
+    char pszOldWindowTitle[MY_BUFSIZE]; // contains original WindowTitle
+    // fetch current window title
+    GetConsoleTitle(pszOldWindowTitle, MY_BUFSIZE);
+    // format a "unique" NewWindowTitle
+    wsprintf(pszNewWindowTitle,"%d/%d",
+                GetTickCount(),
+                GetCurrentProcessId());
+    // change current window title
+    SetConsoleTitle(pszNewWindowTitle);
+    // ensure window title has been updated
+    Sleep(40);
+    // look for NewWindowTitle
+    hwndFound=FindWindow(NULL, pszNewWindowTitle);
+    // restore original window title
+    SetConsoleTitle(pszOldWindowTitle);
+    return(hwndFound);
+}
+
+static LARGE_INTEGER qpfc;
+
+static void storeqpf (void)
+{
+    QueryPerformanceCounter(&qpfc);
+}
+static double getqpf (void)
+{
+    LARGE_INTEGER qpfc2;
+    QueryPerformanceCounter(&qpfc2);
+    return (qpfc2.QuadPart - qpfc.QuadPart) / (qpf.QuadPart / 1000.0);
+}
+
+
+static int mm_timerres, timeon;
+static HANDLE timehandle;
+
+static int timeend (void)
+{
+    if (!timeon)
+       return 1;
+    timeon = 0;
+    if (timeEndPeriod (mm_timerres) == TIMERR_NOERROR)
+       return 1;
+    write_log ("TimeEndPeriod() failed\n");
+    return 0;
+}
+
+static int timebegin (void)
+{
+    if (timeon) {
+       timeend();
+       return timebegin();
+    }
+    timeon = 0;
+    if (timeBeginPeriod (mm_timerres) == TIMERR_NOERROR) {
+       timeon = 1;
+       return 1;
+    }
+    write_log ("TimeBeginPeriod() failed\n");
+    return 0;
+}
+
+static int init_mmtimer (void)
+{
+    TIMECAPS tc;
+    mm_timerres = 0;
+    if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR)
+       return 0;
+    mm_timerres = min(max(tc.wPeriodMin, 1), tc.wPeriodMax);
+    timehandle = CreateEvent (NULL, TRUE, FALSE, NULL);
+    return 1;
+}
+
+static int sm (int ms)
+{
+    UINT TimerEvent;
+    TimerEvent = timeSetEvent (ms, 0, timehandle, 0, TIME_ONESHOT | TIME_CALLBACK_EVENT_SET);
+    if (!TimerEvent) {
+       printf ("timeSetEvent() failed, exiting..\n");
+       return 0;
+    } else {
+       WaitForSingleObject (timehandle, ms);
+        ResetEvent (timehandle);
+       timeKillEvent (TimerEvent);
+    }
+    return 1;
+}
+
+static int getpos (void)
+{
+    DWORD playpos, safepos;
+    HRESULT hr;
+
+    hr = IDirectSoundBuffer_GetCurrentPosition (lpDSBsecondary, &playpos, &safepos);
+    if (hr != DS_OK) {
+       write_log ("GetCurrentPosition failed: %s\n", DXError (hr));
+       return -1;
+    }
+    return playpos;
+}
+
+static void runtest(void)
+{ 
+    int pos, spos, expected, len, freqdiff;
+    int lastpos, minpos, maxpos;
+    int mult = sounddata_stereo ? 4 : 2;
+    double qv;
+
+    sm (100);
+    write_log2 ("frequency: %d\n", sounddata_frequency);
+    pause_audio_ds ();
+    storeqpf ();
+    sm (100);
+    qv = getqpf ();
+    if (qv < 95 || qv > 105)
+       write_log2("timing mismatch, something wrong with your system timer (%.1fms)\n", qv);
+
+    resume_audio_ds ();
+    pos = 0;
+    storeqpf ();
+    while (pos == 0 && getqpf () < 1000) {
+       pos = getpos();
+    }
+    if (getqpf () >= 1000) {
+       printf ("sound didn't start!?\n");
+       return;
+    }
+    printf ("startup-delay: %d samples (%.1fms)\n", pos, getqpf());
+    minpos = 100000;
+    maxpos = -1;
+    lastpos = getpos();
+    while (pos < 20000) {
+       pos = getpos();
+       if (pos - lastpos <= 0)
+           continue;
+       if (pos - lastpos < minpos)
+           minpos = pos - lastpos;
+       if (pos - lastpos > maxpos)
+           maxpos = pos -lastpos;
+       lastpos = pos;
+    }
+    write_log2 ("position granularity: minimum %d, maximum %d samples\n", minpos, maxpos);
+    len = 200;
+    while (len <= 1400) {
+        pause_audio_ds ();
+        resume_audio_ds ();
+       while (pos > 1000)
+           pos = getpos();
+       while (pos < 1000)
+           pos = getpos();
+       spos = pos;
+       storeqpf ();
+       do {
+           qv = getqpf();
+       } while (qv < len);
+       pos = getpos();
+       pos -= spos;
+       expected = (int)(len / 1000.0 * sounddata_frequency * mult);
+       write_log2("%d samples, should be %d (%d samples, %.2f%%) %dms delay\n",
+           pos,  expected, pos - expected, (pos * 100.0 / expected), len);
+       if (len == 1000) {
+           freqdiff = expected - pos;
+       }
+       len += 400;
+    }
+    write_log2("real calculated frequency: %d\n",
+       sounddata_frequency - freqdiff);
+    pause_audio_ds ();
+}        
+
+static int selectdevice (void)
+{
+    int i, val;
+    for (i = 0; i < num_sound_devices; i++) {
+       printf ("%d: %s\n", i + 1, sound_devices[i]);
+    }
+    printf("select sound driver (1 - %d) and press return: ", num_sound_devices);
+    scanf ("%d", &val);
+    if (val < 1)
+       val = 1;
+    if (val > num_sound_devices)
+       val = 1;
+    val--;
+    printf("\n");
+    write_log2("testing '%s'\n", sound_devices[val]);
+    return val;
+}
+
+static int os_winnt, os_winnt_admin;
+
+static OSVERSIONINFO osVersion;
+
+static int osdetect (void)
+{
+    HANDLE hAccessToken;
+    UCHAR InfoBuffer[1024];
+    PTOKEN_GROUPS ptgGroups = (PTOKEN_GROUPS)InfoBuffer;
+    DWORD dwInfoBufferSize;
+    PSID psidAdministrators;
+    SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
+    UINT x;
+    BOOL bSuccess;
+
+    os_winnt = 0;
+    os_winnt_admin = 0;
+
+    osVersion.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
+    if( GetVersionEx( &osVersion ) )
+    {
+       if (osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT)
+           os_winnt = 1;
+    }
+
+    if (!os_winnt) {
+       return 1;
+    }
+
+    if(!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE,
+         &hAccessToken )) {
+         if(GetLastError() != ERROR_NO_TOKEN)
+            return 1;
+         // 
+         // retry against process token if no thread token exists
+         // 
+         if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY,
+            &hAccessToken))
+            return 1;
+      }
+
+      bSuccess = GetTokenInformation(hAccessToken,TokenGroups,InfoBuffer,
+         1024, &dwInfoBufferSize);
+
+      CloseHandle(hAccessToken);
+
+      if(!bSuccess )
+         return 1;
+
+      if(!AllocateAndInitializeSid(&siaNtAuthority, 2,
+         SECURITY_BUILTIN_DOMAIN_RID,
+         DOMAIN_ALIAS_RID_ADMINS,
+         0, 0, 0, 0, 0, 0,
+         &psidAdministrators))
+         return 1;
+
+   // assume that we don't find the admin SID.
+      bSuccess = FALSE;
+
+      for(x=0;x<ptgGroups->GroupCount;x++)
+      {
+         if( EqualSid(psidAdministrators, ptgGroups->Groups[x].Sid) )
+         {
+            bSuccess = TRUE;
+            break;
+         }
+
+      }
+      FreeSid(psidAdministrators);
+      os_winnt_admin = bSuccess ? 1 : 0;
+      return 1;
+   }
+
+static int srates[] = { 22050, 32000, 44100, 0 };
+
+int main (int argc, char **argv)
+{
+    int i;
+
+    logfile = fopen("soundlog.txt","w");
+    osdetect();
+    write_log2("OS: %s %d.%d%s\n", os_winnt ? "NT" : "W9X/ME", osVersion.dwMajorVersion, osVersion.dwMinorVersion, os_winnt_admin ? " (Admin)" : "");
+
+    init_mmtimer();
+    if (!QueryPerformanceFrequency(&qpf)) {
+       printf ("no QPF, exiting..\n");
+       goto end;
+    }
+    write_log2("QPF: %.2fMHz\n", qpf.QuadPart / 1000000.0);
+    hwnd = GetConsoleHwnd();
+    DirectSoundEnumerate ((LPDSENUMCALLBACK)DSEnumProc, 0);
+    devicenum = selectdevice ();
+    i = 0;
+    while (srates[i]) {
+        sounddata_frequency = srates[i];
+       if (open_audio_ds ()) {
+           if (!timebegin ()) {
+               printf ("no MM timer, exiting..\n");
+               goto end;
+           }
+           write_log2("\n");
+           runtest ();
+           timeend ();
+           close_audio_ds ();
+       } else break;
+       i++;
+    }
+end:
+    fclose(logfile);
+    return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/od-win32/sounddep/sound.c b/od-win32/sounddep/sound.c
new file mode 100755 (executable)
index 0000000..8865f05
--- /dev/null
@@ -0,0 +1,671 @@
+ /* 
+  * UAE - The Un*x Amiga Emulator
+  * 
+  * Win32 sound interface (DirectSound)
+  *
+  * Copyright 1997 Mathias Ortmann
+  * Copyright 1997-2001 Brian King
+  * Copyright 2000-2002 Bernd Roesch
+  * Copyright 2002-2003 Toni Wilen
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "memory.h"
+#include "events.h"
+#include "custom.h"
+#include "gensound.h"
+#include "sounddep/sound.h"
+#include "threaddep/thread.h"
+#include "ahidsound.h"
+#include "avioutput.h"
+#include "gui.h"
+#include "dxwrap.h"
+#include "win32.h"
+#include "savestate.h"
+#include "driveclick.h"
+
+#include <windows.h>
+#include <mmsystem.h>
+#include <dsound.h>
+
+#include <math.h>
+
+int dsound_hardware_mixing = 0;
+
+#define ADJUST_SIZE 10
+#define EXP 1.3
+
+#define FILTER_FREQUENCY 7000.0
+
+//#define SOUND_DEBUG
+
+static int obtainedfreq;
+static int have_sound;
+static int paused;
+static int mute;
+
+#define SND_MAX_BUFFER2 262144
+#define SND_MAX_BUFFER 512
+
+uae_u16 sndbuffer[SND_MAX_BUFFER];
+uae_u16 *sndbufpt;
+int sndbufsize;
+
+static int max_sndbufsize, snd_configsize, dsoundbuf;
+static double filter_mul1, filter_mul2;
+
+static uae_sem_t sound_sem, sound_init_sem;
+
+#define MAX_SOUND_DEVICES 10
+
+static char *sound_devices[MAX_SOUND_DEVICES];
+GUID sound_device_guid[MAX_SOUND_DEVICES];
+static int num_sound_devices;
+
+static LPDIRECTSOUND lpDS;
+static LPDIRECTSOUNDBUFFER lpDSBprimary;
+static LPDIRECTSOUNDBUFFER lpDSBsecondary;
+
+static DWORD writepos;
+
+int setup_sound (void)
+{
+    sound_available = 1;
+    return 1;
+}
+
+int scaled_sample_evtime_orig;
+static int lastfreq;
+void update_sound (int freq)
+{
+    if (freq < 0)
+       freq = lastfreq;
+    lastfreq = freq;
+    if (have_sound) {
+       if (currprefs.gfx_vsync && currprefs.gfx_afullscreen) {
+           if (currprefs.ntscmode)
+               scaled_sample_evtime_orig = (unsigned long)(MAXHPOS_NTSC * MAXVPOS_NTSC * freq * CYCLE_UNIT + obtainedfreq - 1) / obtainedfreq;
+           else
+               scaled_sample_evtime_orig = (unsigned long)(MAXHPOS_PAL * MAXVPOS_PAL * freq * CYCLE_UNIT + obtainedfreq - 1) / obtainedfreq;
+       } else {
+           scaled_sample_evtime_orig = (unsigned long)(312.0 * 50 * CYCLE_UNIT / (obtainedfreq  / 227.0));
+       }
+       scaled_sample_evtime = scaled_sample_evtime_orig;
+    }
+}
+
+static void clearbuffer (void)
+{
+    void *buffer;
+    DWORD size;
+
+    HRESULT hr = IDirectSoundBuffer_Lock (lpDSBsecondary, 0, dsoundbuf, &buffer, &size, NULL, NULL, 0);
+    if (hr == DSERR_BUFFERLOST) {
+       IDirectSoundBuffer_Restore (lpDSBsecondary);
+       hr = IDirectSoundBuffer_Lock (lpDSBsecondary, 0, dsoundbuf, &buffer, &size, NULL, NULL, 0);
+    }
+    if (hr != DS_OK) {
+       write_log ("failed to Lock sound buffer (clear): %s\n", DXError (hr));
+       return;
+    }
+    memset (buffer, 0, size);
+    IDirectSoundBuffer_Unlock (lpDSBsecondary, buffer, size, NULL, 0);
+    memset (sndbuffer, 0, sizeof (sndbuffer));
+}
+
+static void pause_audio_ds (void)
+{
+    IDirectSoundBuffer_Stop (lpDSBsecondary);
+    clearbuffer ();
+}
+
+static void resume_audio_ds (void)
+{
+    HRESULT hr;
+    
+    paused = 0;
+    clearbuffer ();
+    hr = IDirectSoundBuffer_Play (lpDSBsecondary, 0, 0, DSBPLAY_LOOPING);
+    if (hr != DS_OK)
+       write_log ("Play failed: %s\n", DXError (hr));
+    writepos = snd_configsize;
+}
+
+static int restore (DWORD hr)
+{
+    if (hr != DSERR_BUFFERLOST)
+       return 0;
+#ifdef SOUND_DEBUG
+    write_log ("sound buffer lost\n");
+#endif
+    hr = IDirectSoundBuffer_Restore (lpDSBsecondary);
+    if (hr != DS_OK) {
+       //write_log ("restore failed %s\n", DXError (hr));
+       return 1;
+    }
+    resume_audio_ds ();
+    return 1;
+}
+
+static LARGE_INTEGER qpfc, qpf;
+static void storeqpf (void)
+{
+    QueryPerformanceCounter(&qpfc);
+}
+static double getqpf (void)
+{
+    LARGE_INTEGER qpfc2;
+    QueryPerformanceCounter(&qpfc2);
+    return (qpfc2.QuadPart - qpfc.QuadPart) / (qpf.QuadPart / 1000.0);
+}
+
+static int getpos (void)
+{
+    DWORD playpos, safepos;
+    HRESULT hr;
+
+    hr = IDirectSoundBuffer_GetCurrentPosition (lpDSBsecondary, &playpos, &safepos);
+    if (hr != DS_OK) {
+       write_log ("GetCurrentPosition failed: %s\n", DXError (hr));
+       return -1;
+    }
+    return playpos;
+}
+
+static int calibrate (void)
+{
+    int len = 1000;
+    int pos, lastpos, tpos, expected, diff;
+    int mult = currprefs.stereo ? 4 : 2;
+    double qv, pct;
+
+    if (!QueryPerformanceFrequency(&qpf)) {
+       write_log ("no QPF, can't calibrate\n");
+       return 100 * 10;
+    }
+    pos = 1000;
+    pause_audio_ds ();
+    resume_audio_ds ();
+    while (pos >= 1000)
+        pos = getpos();
+    while (pos < 1000)
+        pos = getpos();
+    lastpos = getpos();
+    storeqpf ();
+    tpos = 0;
+    do {
+       pos = getpos();
+       if (pos < lastpos) {
+           tpos += dsoundbuf - lastpos + pos;
+       } else {
+           tpos += pos - lastpos;
+       }
+       lastpos = pos;
+        qv = getqpf();
+    } while (qv < len);
+    expected = (int)(len / 1000.0 * currprefs.sound_freq);
+    tpos /= mult;
+    diff = tpos - expected;
+    pct = tpos * 100.0 / expected;
+    write_log ("sound calibration: %d %d (%d %.2f%%)\n", tpos, expected, diff, pct);
+    return (int)(pct * 10);
+}
+
+static void close_audio_ds (void)
+{
+    if (lpDSBsecondary)
+       IDirectSound_Release (lpDSBsecondary);
+    if (lpDSBprimary)
+       IDirectSound_Release (lpDSBprimary);
+    lpDSBsecondary = lpDSBprimary = 0;
+    if (lpDS) {
+       IDirectSound_Release (lpDS);
+       write_log ("DirectSound driver freed\n");
+    }
+    lpDS = 0;
+}
+
+extern HWND hMainWnd;
+
+static void setvolume (void)
+{
+    HRESULT hr;
+    LONG vol = DSBVOLUME_MIN;
+
+    if (currprefs.sound_volume < 100 && !mute)
+        vol = (LONG)((DSBVOLUME_MIN / 2) + (-DSBVOLUME_MIN / 2) * log (1 + (2.718281828 - 1) * (1 - currprefs.sound_volume / 100.0)));
+    hr = IDirectSoundBuffer_SetVolume (lpDSBsecondary, vol);
+    if (hr != DS_OK)
+        write_log ("SOUND: SetVolume(%d) failed: %s\n", vol, DXError (hr));
+}
+
+static int open_audio_ds (int size)
+{
+    HRESULT hr;
+    DSBUFFERDESC sound_buffer;
+    DSCAPS DSCaps;
+    DSBCAPS DSBCaps;
+    WAVEFORMATEX wavfmt;
+    int minfreq, maxfreq;
+    int freq = currprefs.sound_freq;
+    
+    enumerate_sound_devices (0);
+    if (dsound_hardware_mixing) {
+       size <<= 3;
+    } else {
+       size <<= 1;
+       if (currprefs.stereo)
+           size <<= 1;
+    }
+    snd_configsize = size;
+    sndbufsize = size / 32;
+    if (sndbufsize > SND_MAX_BUFFER)
+        sndbufsize = SND_MAX_BUFFER;
+
+    hr = DirectSoundCreate (&sound_device_guid[currprefs.win32_soundcard], &lpDS, NULL);
+    if (hr != DS_OK)  {
+        write_log ("SOUND: DirectSoundCreate() failure: %s\n", DXError (hr));
+        return 0;
+    }
+    memset (&DSCaps, 0, sizeof (DSCaps));
+    DSCaps.dwSize = sizeof(DSCaps);
+    hr = IDirectSound_GetCaps (lpDS, &DSCaps);
+    if (hr!= DS_OK) {
+       write_log ("SOUND: Error getting DirectSound capabilities: %s\n", DXError (hr));
+       goto error;
+    }
+    if (DSCaps.dwFlags & DSCAPS_EMULDRIVER) {
+       write_log ("SOUND: Emulated DirectSound driver detected, don't complain if sound quality is crap :)\n");
+    }
+    minfreq = DSCaps.dwMinSecondarySampleRate;
+    maxfreq = DSCaps.dwMaxSecondarySampleRate;
+    if (maxfreq > 11000) {
+       if (minfreq > freq) {
+           freq = minfreq;
+           changed_prefs.sound_freq = currprefs.sound_freq = freq;
+           write_log("SOUND: minimum supported frequency: %d\n", minfreq);
+       }
+       if (maxfreq < freq) {
+           freq = maxfreq;
+           changed_prefs.sound_freq = currprefs.sound_freq = freq;
+           write_log("SOUND: maximum supported frequency: %d\n", maxfreq);
+       }
+    } else {
+       write_log("SOUND: ignored weird min (%d) or max (%d) sample rate\n", minfreq, maxfreq);
+    }
+    filter_mul1 = exp (-FILTER_FREQUENCY / freq);
+    filter_mul2 = 1 - filter_mul1;
+    
+    memset (&sound_buffer, 0, sizeof (sound_buffer));
+    sound_buffer.dwSize = sizeof (sound_buffer);
+    sound_buffer.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_GETCURRENTPOSITION2;
+    hr = IDirectSound_CreateSoundBuffer (lpDS, &sound_buffer, &lpDSBprimary, NULL);
+    if( hr != DS_OK )  {
+        write_log ("SOUND: Primary CreateSoundBuffer() failure: %s\n", DXError (hr));
+       goto error;
+    }
+
+    memset(&DSBCaps, 0, sizeof(DSBCaps));
+    DSBCaps.dwSize = sizeof(DSBCaps);
+    hr = IDirectSoundBuffer_GetCaps(lpDSBprimary, &DSBCaps);
+    if (hr != DS_OK) {
+       write_log ("SOUND: Primary GetCaps() failure: %s\n",  DXError (hr));
+       goto error;
+    }
+
+    wavfmt.wFormatTag = WAVE_FORMAT_PCM;
+    wavfmt.nChannels = dsound_hardware_mixing ? 4 : (currprefs.stereo ? 2 : 1);
+    wavfmt.nSamplesPerSec = freq;
+    wavfmt.wBitsPerSample = 16;
+    wavfmt.nBlockAlign = 16 / 8 * wavfmt.nChannels;
+    wavfmt.nAvgBytesPerSec = wavfmt.nBlockAlign * freq;
+
+    max_sndbufsize = size * 3;
+    if (max_sndbufsize > SND_MAX_BUFFER2)
+        max_sndbufsize = SND_MAX_BUFFER2;
+    dsoundbuf = max_sndbufsize * 2;
+    hr = IDirectSound_SetCooperativeLevel (lpDS, hMainWnd, DSSCL_PRIORITY);
+    if (hr != DS_OK) {
+        write_log ("SOUND: Can't set cooperativelevel: %s\n", DXError (hr));
+        goto error;
+    }
+    if (dsoundbuf < DSBSIZE_MIN)
+        dsoundbuf = DSBSIZE_MIN;
+    if (dsoundbuf > DSBSIZE_MAX)
+        dsoundbuf = DSBSIZE_MAX;
+    if (max_sndbufsize > dsoundbuf)
+        max_sndbufsize = dsoundbuf;
+
+    memset (&sound_buffer, 0, sizeof (sound_buffer));
+    sound_buffer.dwSize = sizeof (sound_buffer);
+    sound_buffer.dwBufferBytes = dsoundbuf;
+    sound_buffer.lpwfxFormat = &wavfmt;
+    sound_buffer.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS | DSBCAPS_STATIC;
+    sound_buffer.dwFlags |= DSBCAPS_CTRLVOLUME;
+
+    hr = IDirectSound_CreateSoundBuffer( lpDS, &sound_buffer, &lpDSBsecondary, NULL );
+    if (hr != DS_OK) {
+        write_log ("SOUND: Secondary CreateSoundBuffer() failure: %s\n", DXError (hr));
+        goto error;
+    }
+
+    hr = IDirectSoundBuffer_SetFormat (lpDSBprimary, &wavfmt);
+    if( hr != DS_OK )  {
+        write_log ("SOUND: Primary SetFormat() failure: %s\n", DXError (hr));
+        goto error;
+    }
+    setvolume ();
+
+    clearbuffer ();
+
+    init_sound_table16 ();
+    if (dsound_hardware_mixing)
+       sample_handler = sample16ss_handler;
+    else
+       sample_handler = currprefs.stereo ? sample16s_handler : sample16_handler;
+
+    write_log ("DS driver '%s'/%d/%d bits/%d Hz/buffer %d/dist %d\n",
+       sound_devices[currprefs.win32_soundcard], dsound_hardware_mixing ? 4 : (currprefs.stereo ? 2 : 1), 16, freq, max_sndbufsize, snd_configsize);
+    obtainedfreq = currprefs.sound_freq;
+
+    return 1;
+
+error:
+    close_audio_ds ();
+    return 0;
+}
+
+static int open_sound (void)
+{
+    int ret;
+    int size = currprefs.sound_maxbsiz;
+
+    if (!currprefs.produce_sound)
+       return 0;
+    /* Always interpret buffer size as number of samples, not as actual
+       buffer size.  Of course, since 8192 is the default, we'll have to
+       scale that to a sane value (assuming that otherwise 16 bits and
+       stereo would have been enabled and we'd have done the shift by
+       two anyway).  */
+    size >>= 2;
+    if (size & (size - 1))
+       size = DEFAULT_SOUND_MAXB;
+    if (size < 512)
+       size = 512;
+
+    ret = open_audio_ds (size);
+    if (!ret)
+       return 0;
+
+    have_sound = 1;
+    sound_available = 1;
+    update_sound (fake_vblank_hz);
+    sndbufpt = sndbuffer;
+    driveclick_init ();
+
+    return 1;
+}
+
+void close_sound (void)
+{
+    if (! have_sound)
+       return;
+    pause_sound ();
+    close_audio_ds ();
+    have_sound = 0;
+}
+
+int init_sound (void)
+{
+    if (have_sound)
+       return 1;
+    if (!open_sound ())
+       return 0;
+    paused = 1;
+    driveclick_reset ();
+    resume_sound ();
+    return 1;
+}
+
+void pause_sound (void)
+{
+    if (paused)
+       return;
+    paused = 1;
+    if (!have_sound)
+       return;
+    pause_audio_ds ();
+    clearbuffer();
+}
+
+void resume_sound (void)
+{
+    if (!paused)
+       return;
+    if (!have_sound)
+       return;
+    clearbuffer ();
+    resume_audio_ds ();
+}
+
+void reset_sound (void)
+{
+    if (!have_sound)
+       return;
+    clearbuffer ();
+}
+
+#ifdef JIT
+extern uae_u8* compiled_code;
+#else
+static int compiled_code;
+#endif
+extern int vsynctime_orig;
+
+#ifndef AVIOUTPUT
+static int avioutput_audio;
+#endif
+
+void sound_setadjust (double v)
+{
+    double mult;
+
+    mult = (1000.0 + currprefs.sound_adjust + v);
+    if ((currprefs.gfx_vsync && currprefs.gfx_afullscreen) || (avioutput_audio && !compiled_code)) {
+       vsynctime = vsynctime_orig;
+       scaled_sample_evtime = (long)(((double)scaled_sample_evtime_orig) * mult / 1000.0);
+    } else if (compiled_code) {
+       vsynctime = (long)(((double)vsynctime_orig) * mult / 1000.0);
+       scaled_sample_evtime = scaled_sample_evtime_orig;
+    } else
+       vsynctime = vsynctime_orig * 9 / 10;
+}
+
+static void finish_sound_buffer_ds (void)
+{
+    DWORD playpos, safepos;
+    HRESULT hr;
+    void *b1, *b2;
+    DWORD s1, s2;
+    int diff;
+    double vdiff, m, skipmode;
+
+    for (;;) {
+       hr = IDirectSoundBuffer_GetCurrentPosition (lpDSBsecondary, &playpos, &safepos);
+       if (hr != DS_OK) {
+           restore (hr);
+           //write_log ("GetCurrentPosition failed: %s\n", DirectSound_ErrorText (hr));
+           return;
+       }
+
+       if (savestate_state)
+           return;
+
+       if (writepos >= playpos)
+           diff = writepos - playpos;
+       else
+           diff = dsoundbuf - playpos + writepos;
+
+       if (diff >= max_sndbufsize) {
+           writepos = safepos + snd_configsize;
+           if (writepos >= dsoundbuf)
+               writepos -= dsoundbuf;
+           diff = snd_configsize;
+           break;
+       }
+
+       if (diff > max_sndbufsize * 6 / 8) {
+           sleep_millis_busy (1);
+           continue;
+       }
+       break;
+    }
+
+    hr = IDirectSoundBuffer_Lock (lpDSBsecondary, writepos, sndbufsize, &b1, &s1, &b2, &s2, 0);
+    if (restore (hr))
+       return;
+    if (hr != DS_OK) {
+        write_log ("lock failed: %s (%d %d)\n", DXError (hr), writepos, sndbufsize);
+        return;
+    }
+    memcpy (b1, sndbuffer, sndbufsize >= s1 ? s1 : sndbufsize);
+    if (b2)
+        memcpy (b2, (uae_u8*)sndbuffer + s1, sndbufsize - s1);
+    IDirectSoundBuffer_Unlock (lpDSBsecondary, b1, s1, b2, s2);
+
+    vdiff = diff - snd_configsize;
+    m = 100.0 * vdiff / max_sndbufsize;
+    skipmode = pow (m < 0 ? -m : m, EXP)/ 10.0;
+
+    if (m < 0) skipmode = -skipmode;
+    if (skipmode < -ADJUST_SIZE) skipmode = -ADJUST_SIZE;
+    if (skipmode > ADJUST_SIZE) skipmode = ADJUST_SIZE;
+
+#ifdef SOUND_DEBUG
+    if (!(timeframes % 10)) {
+       write_log ("b=%5d,%5d,%5d,%5d diff=%5d vdiff=%5.0f vdiff2=%5d skip=%+02.1f\n",
+           sndbufsize, snd_configsize, max_sndbufsize, dsoundbuf, diff, vdiff, diff - snd_configsize, skipmode);
+    }
+#endif
+
+    writepos += sndbufsize;
+    if (writepos >= dsoundbuf)
+       writepos -= dsoundbuf;
+
+    sound_setadjust (skipmode);
+}
+
+static void filtercheck (uae_s16 *sndbuffer, int len)
+{
+    int ch = dsound_hardware_mixing ? 4 : (currprefs.stereo ? 2 : 1);
+    int i;
+    static double cold[4];
+    double old0, old1, v;
+    
+    if (!currprefs.sound_filter)
+       return;
+    if (gui_data.powerled || currprefs.sound_filter == 2) {
+       if (ch == 1) {
+           old0 = cold[0];
+           for (i = 0; i < len; i++) {
+               v = old0 = old0 * filter_mul1 + filter_mul2 * sndbuffer[i];
+               if (v < -32768) v = -32768;
+               if (v > 32767) v = 32767;
+               sndbuffer[i] = (uae_s16)v;
+           }
+           cold[0] = old0;
+       } else {
+           old0 = cold[0];
+           old1 = cold[1];
+           for (i = 0; i < len; i += 2) {
+               v = old0 = old0 * filter_mul1 + filter_mul2 * sndbuffer[i];
+               if (v < -32768) v = -32768;
+               if (v > 32767) v = 32767;
+               sndbuffer[i] = (uae_s16)v;
+               v = old1 = old1 * filter_mul1 + filter_mul2 * sndbuffer[i + 1];
+               if (v < -32768) v = -32768;
+               if (v > 32767) v = 32767;
+               sndbuffer[i + 1] = (uae_s16)v;
+           }
+           cold[0] = old0;
+           cold[1] = old1;
+       }
+    }
+}
+
+void finish_sound_buffer (void)
+{
+    if (!have_sound || turbo_emulation)
+       return;
+    filtercheck ((uae_s16*)sndbuffer, sndbufsize / 2);
+#ifdef DRIVESOUND
+    driveclick_mix ((uae_s16*)sndbuffer, sndbufsize / 2);
+#endif
+#ifdef AVIOUTPUT
+    if (avioutput_audio)
+        AVIOutput_WriteAudio ((uae_u8*)sndbuffer, sndbufsize);
+    if (!avioutput_framelimiter && (avioutput_video || avioutput_audio))
+       return;
+#endif
+    finish_sound_buffer_ds ();
+}
+
+static BOOL CALLBACK DSEnumProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName,  LPVOID lpContext)
+{
+    int i = num_sound_devices;
+    if (i == MAX_SOUND_DEVICES)
+       return TRUE;
+    if (lpGUID != NULL)
+       memcpy (&sound_device_guid[i], lpGUID, sizeof (GUID));
+    sound_devices[i] = my_strdup (lpszDesc);
+    num_sound_devices++;
+    return TRUE;
+}
+
+char **enumerate_sound_devices (int *total)
+{
+    if (!num_sound_devices)
+        DirectSoundEnumerate ((LPDSENUMCALLBACK)DSEnumProc, 0);
+    if (total)
+       *total = num_sound_devices;
+    if (currprefs.win32_soundcard >= num_sound_devices)
+       currprefs.win32_soundcard = 0;
+    if (num_sound_devices)
+       return sound_devices;
+    return 0;
+}
+
+int sound_calibrate (HWND hwnd, struct uae_prefs *p)
+{
+    HWND old = hMainWnd;
+    int pct = 100 * 10;
+
+    hMainWnd = hwnd;
+    currprefs.sound_freq = p->sound_freq;
+    currprefs.stereo = p->stereo;
+    if (open_sound ()) {
+        SetThreadPriority ( GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
+       pct = calibrate ();
+        SetThreadPriority ( GetCurrentThread(), THREAD_PRIORITY_NORMAL);
+       close_sound ();
+    }
+    hMainWnd = old;
+    return pct;
+}
+
+void sound_volume (int dir)
+{
+    if (dir == 0)
+       mute = mute ? 0 : 1;
+    currprefs.sound_volume -= dir * 10;
+    if (currprefs.sound_volume < 0)
+       currprefs.sound_volume = 0;
+    if (currprefs.sound_volume > 100)
+       currprefs.sound_volume = 100;
+    changed_prefs.sound_volume = currprefs.sound_volume;
+    setvolume ();
+}
diff --git a/od-win32/sounddep/sound.h b/od-win32/sounddep/sound.h
new file mode 100755 (executable)
index 0000000..2bb8ea7
--- /dev/null
@@ -0,0 +1,51 @@
+/* 
+  * UAE - The Un*x Amiga Emulator
+  * 
+  * Support for Linux/USS sound
+  * 
+  * Copyright 1997 Bernd Schmidt
+  */
+
+extern int sound_fd;
+extern uae_u16 sndbuffer[];
+extern uae_u16 *sndbufpt;
+extern int sndbufsize;
+extern void finish_sound_buffer (void);
+extern int init_sound (void);
+extern void close_sound (void);
+extern int setup_sound (void);
+extern void resume_sound (void);
+extern void pause_sound (void);
+extern void reset_sound (void);
+extern void sound_setadjust (double);
+extern char **enumerate_sound_devices (int *total);
+extern int drivesound_init (void);
+extern void drivesound_free (void);
+extern void sound_volume (int);
+
+static __inline__ void check_sound_buffers (void)
+{
+    if ((char *)sndbufpt - (char *)sndbuffer >= sndbufsize) {
+       finish_sound_buffer ();
+       sndbufpt = sndbuffer;
+    }
+}
+
+#define PUT_SOUND_BYTE(b) do { *(uae_u8 *)sndbufpt = b; sndbufpt = (uae_u16 *)(((uae_u8 *)sndbufpt) + 1); } while (0)
+#define PUT_SOUND_WORD(b) do { *(uae_u16 *)sndbufpt = b; sndbufpt = (uae_u16 *)(((uae_u8 *)sndbufpt) + 2); } while (0)
+#define PUT_SOUND_BYTE_LEFT(b) PUT_SOUND_BYTE(b)
+#define PUT_SOUND_WORD_LEFT(b) PUT_SOUND_WORD(b)
+#define PUT_SOUND_BYTE_RIGHT(b) PUT_SOUND_BYTE(b)
+#define PUT_SOUND_WORD_RIGHT(b) PUT_SOUND_WORD(b)
+#define SOUND16_BASE_VAL 0
+#define SOUND8_BASE_VAL 128
+
+#define DEFAULT_SOUND_MAXB 16384
+#define DEFAULT_SOUND_MINB 16384
+#define DEFAULT_SOUND_BITS 16
+#define DEFAULT_SOUND_FREQ 44100
+#define HAVE_STEREO_SUPPORT
+
+#ifdef AHI
+#include "ahidsound.h"
+#endif
diff --git a/od-win32/srcrelease.bat b/od-win32/srcrelease.bat
new file mode 100755 (executable)
index 0000000..462f81f
--- /dev/null
@@ -0,0 +1,87 @@
+cd c:\projects\winuae_bak
+rm -rf bak
+mkdir bak
+copy /s c:\projects\winuae\src\*.* c:\projects\winuae_bak\bak\
+cd bak
+del *.obj *.ilk *.exe *.pdb *.pch *.idb /s
+
+del cpudefs.c
+del blit.h
+del blitfunc.c
+del blitfunc.h
+del blittable.c
+del cputbl.h
+del cpustbl.c
+del compemu.c
+del comptbl.h
+del compstbl.c
+del cpuemu_0.c
+del cpuemu_5.c
+del cpuemu_6.c
+
+cd od-win32
+
+cd build68k_msvc
+rm -f build68k.exe build68k_msvc.plg
+rm -rf debug
+rm -rf release
+cd ..
+
+cd genblitter_msvc
+rm -f genblitter.exe genblitter_msvc.plg
+rm -rf debug
+rm -rf release
+cd ..
+
+cd gencomp_msvc
+rm -f gencomp.exe gencomp_msvc.plg
+rm -rf debug
+rm -rf release
+cd ..
+
+cd gencpu_msvc
+rm -f gencpu.exe gencpu_msvc.plg
+rm -rf debug
+rm -rf release
+cd ..
+
+cd winuae_msvc
+rm -f winuae_msvc.plg
+rm -f winuae_msvc.ncb
+rm -rf debug
+rm -rf release
+cd ..
+
+cd miniuae
+rm -f winuae_msvc.plg
+rm -f winuae_msvc.ncb
+rm -rf debug
+rm -rf release
+cd ..
+
+cd winuae_nogui
+rm -rf debug
+rm -rf release
+cd ..
+
+cd soundcheck
+rm -rf debug
+rm -rf release
+cd ..
+
+cd singlefilehelper
+rm -rf debug
+rm -rf release
+cd ..
+
+cd resourcedll
+rm -rf debug
+rm -rf release
+cd ..
+cd ..
+
+zip -9 -r winuaesrc *
+
+move winuaesrc.zip d:\amiga
+cd c:\projects\winuae\src\od-win32
+
diff --git a/od-win32/support.c b/od-win32/support.c
new file mode 100755 (executable)
index 0000000..817f1bf
--- /dev/null
@@ -0,0 +1,17 @@
+ /* 
+  * UAE - The Un*x Amiga Emulator
+  * 
+  * Miscellaneous machine dependent support functions and definitions
+  *
+  * Copyright 1996 Bernd Schmidt
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "machdep/m68k.h"
+
+struct flag_struct regflags;
+
diff --git a/od-win32/sys/ipc.h b/od-win32/sys/ipc.h
new file mode 100755 (executable)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/od-win32/sys/mman.h b/od-win32/sys/mman.h
new file mode 100755 (executable)
index 0000000..eb8a81b
--- /dev/null
@@ -0,0 +1,47 @@
+// Implement MMAN and SHM functionality for Win32
+// Copyright (C) 2000, Brian King
+// GNU Public License
+
+#ifndef _MMAN_H_
+#define _MMAN_H_
+
+#include <windows.h>
+#include <stdio.h> // for size_t
+#include <time.h>
+#include <signal.h>
+
+#define MAX_SHMID 256
+
+extern uae_u32 natmem_offset;
+
+typedef int key_t;
+typedef USHORT ushort;
+
+/* One shmid data structure for each shared memory segment in the system. */
+struct shmid_ds {
+    key_t  key;
+    size_t size;
+    void  *addr;
+    char   name[ MAX_PATH ];
+    void   *attached;
+};
+
+int mprotect (void *addr, size_t len, int prot);
+void *shmat (int shmid, LPVOID shmaddr, int shmflg);
+int shmdt (const void *shmaddr);
+int shmget (key_t key, size_t size, int shmflg, char*);
+int shmctl (int shmid, int cmd, struct shmid_ds *buf);
+void init_shm (void);
+
+int isinf( double x );
+int isnan( double x );
+
+#define PROT_READ  0x01
+#define PROT_WRITE 0x02
+#define PROT_EXEC  0x04
+
+#define IPC_PRIVATE 0x01
+#define IPC_RMID    0x02
+#define IPC_CREAT   0x04
+#define IPC_STAT    0x08
+#endif
\ No newline at end of file
diff --git a/od-win32/sys/shm.h b/od-win32/sys/shm.h
new file mode 100755 (executable)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/od-win32/sysconfig.h b/od-win32/sysconfig.h
new file mode 100755 (executable)
index 0000000..fabbbbe
--- /dev/null
@@ -0,0 +1,465 @@
+
+#pragma warning (disable : 4761)
+
+#define DIRECTINPUT_VERSION  0x0800
+#define DIRECT3D_VERSION 0x0900
+#define SUPPORT_THREADS
+
+#define DRIVESOUND
+#define GFXFILTER
+
+#ifndef UAE_MINI
+
+#define FILESYS /* filesys emulation */
+#define UAE_FILESYS_THREADS
+#define AUTOCONFIG /* autoconfig support, fast ram, harddrives etc.. */
+#define JIT /* JIT compiler support */
+#undef USE_SDL
+#define NATMEM_OFFSET natmem_offset
+#define CAN_DO_STACK_MAGIC
+#define USE_NORMAL_CALLING_CONVENTION 1
+#define USE_X86_FPUCW 1
+#define WINDDK /* Windows DDK available, keyboard leds and harddrive support */
+#define CATWEASEL /* Catweasel MK2/3 support */
+#define AHI /* AHI sound emulation */
+#define AGA /* AGA chipset emulation */
+#define CD32 /* CD32 emulation */
+#define CDTV /* CDTV emulation */
+#define D3D /* D3D display support */
+#define OPENGL /* OpenGL display support */
+#define PARALLEL_PORT /* parallel port emulation */
+#define PARALLEL_DIRECT /* direct parallel port emulation */
+#define SERIAL_PORT /* serial port emulation */
+#define SCSIEMU /* uaescsi.device emulation */
+#define FPUEMU /* FPU emulation */
+#define CPUEMU_0 /* generic 680x0 emulation */
+#define CPUEMU_5 /* 68000+prefetch emulation */
+#define CPUEMU_6 /* cycle-exact cpu&blitter */
+#define ACTION_REPLAY /* Action Replay 1/2/3 support */
+#define PICASSO96 /* Picasso96 display card emulation */
+#define BSDSOCKET /* bsdsocket.library emulation */
+#define CAPS /* CAPS-image support */
+#define AVIOUTPUT /* Avioutput support */
+
+#else
+
+/* #define SINGLEFILE */
+
+#define CUSTOM_SIMPLE /* simplified custom chipset emulation */
+#define CPUEMU_0
+#define CPUEMU_68000_ONLY /* drop 68010+ commands from CPUEMU_0 */
+#ifndef UAE_NOGUI
+#define D3D
+#define OPENGL
+#endif
+#define CAPS
+#define CPUEMU_6
+#define CPUEMU_5
+
+#endif
+
+#ifdef _DEBUG
+#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#endif
+
+
+/* src/sysconfig.h.  Generated automatically by configure.  */
+/* src/sysconfig.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define if on AIX 3.
+   System headers sometimes define this.
+   We just want to avoid a redefinition error message.  */
+#ifndef _ALL_SOURCE
+/* #undef _ALL_SOURCE */
+#endif
+
+/* Define to empty if the keyword does not work.  */
+/* #undef const */
+
+/* Define if you have the getmntent function.  */
+/* #undef HAVE_GETMNTENT */
+
+/* Define if your struct stat has st_blocks.  */
+/* #undef HAVE_ST_BLOCKS */
+
+/* Define if utime(file, NULL) sets file's timestamp to the present.  */
+#define HAVE_UTIME_NULL 1
+
+/* Define as __inline if that's what the C compiler calls it.  */
+/* #undef inline */
+#define __inline__ __inline
+#define __volatile__ volatile
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+/* #undef mode_t */
+#define mode_t int
+
+/* Define to `long' if <sys/types.h> doesn't define.  */
+/* #undef off_t */
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+/* #undef pid_t */
+
+/* Define if you need to in order for stat and other things to work.  */
+/* #undef _POSIX_SOURCE */
+
+/* Define as the return type of signal handlers (int or void).  */
+#define RETSIGTYPE void
+
+/* Define if you have the ANSI C header files.  */
+#define STDC_HEADERS 1
+
+/* Define if you can safely include both <sys/time.h> and <time.h>.  */
+#ifdef __GNUC__
+#define TIME_WITH_SYS_TIME 1
+#endif
+
+#ifdef _WIN32_WCE
+#define NO_TIME_H 1
+#endif
+
+/* Define if your <sys/time.h> declares struct tm.  */
+/* #undef TM_IN_SYS_TIME */
+
+/* Define if the X Window System is missing or not being used.  */
+#define X_DISPLAY_MISSING 1
+
+/* Define if you have the Andrew File System.  */
+/* #undef AFS */
+
+/* Define if there is no specific function for reading the list of
+   mounted filesystems.  fread will be used to read /etc/mnttab.  [SVR2]  */
+/* #undef MOUNTED_FREAD */
+
+/* Define if (like SVR2) there is no specific function for reading the
+   list of mounted filesystems, and your system has these header files:
+   <sys/fstyp.h> and <sys/statfs.h>.  [SVR3]  */
+/* #undef MOUNTED_FREAD_FSTYP */
+
+/* Define if there is a function named getfsstat for reading the list
+   of mounted filesystems.  [DEC Alpha running OSF/1]  */
+/* #undef MOUNTED_GETFSSTAT */
+
+/* Define if there is a function named getmnt for reading the list of
+   mounted filesystems.  [Ultrix]  */
+/* #undef MOUNTED_GETMNT */
+
+/* Define if there is a function named getmntent for reading the list
+   of mounted filesystems, and that function takes a single argument.
+   [4.3BSD, SunOS, HP-UX, Dynix, Irix]  */
+/* #undef MOUNTED_GETMNTENT1 */
+
+/* Define if there is a function named getmntent for reading the list of
+   mounted filesystems, and that function takes two arguments.  [SVR4]  */
+/* #undef MOUNTED_GETMNTENT2 */
+
+/* Define if there is a function named getmntinfo for reading the list
+   of mounted filesystems.  [4.4BSD]  */
+/* #undef MOUNTED_GETMNTINFO */
+
+/* Define if there is a function named listmntent that can be used to
+   list all mounted filesystems. [UNICOS] */
+/* #undef MOUNTED_LISTMNTENT */
+
+/* Define if there is a function named mntctl that can be used to read
+   the list of mounted filesystems, and there is a system header file
+   that declares `struct vmount.'  [AIX]  */
+/* #undef MOUNTED_VMOUNT */
+
+/*  Define if  statfs takes 3 args.  [DEC Alpha running OSF/1]  */
+/* #undef STAT_STATFS3_OSF1 */
+
+/* Define if there is no specific function for reading filesystems usage
+   information and you have the <sys/filsys.h> header file.  [SVR2]  */
+/* #undef STAT_READ_FILSYS */
+
+/* Define if statfs takes 2 args and struct statfs has a field named f_bsize.
+   [4.3BSD, SunOS 4, HP-UX, AIX PS/2]  */
+/* #undef STAT_STATFS2_BSIZE */
+
+/* Define if statfs takes 2 args and struct statfs has a field named f_fsize.
+   [4.4BSD, NetBSD]  */
+/* #undef STAT_STATFS2_FSIZE */
+
+/* Define if statfs takes 2 args and the second argument has
+   type struct fs_data.  [Ultrix]  */
+/* #undef STAT_STATFS2_FS_DATA */
+
+/* Define if statfs takes 4 args.  [SVR3, Dynix, Irix, Dolphin]  */
+/* #undef STAT_STATFS4 */
+
+/* Define if there is a function named statvfs.  [SVR4]  */
+/* #undef STAT_STATVFS */
+
+/* Define if the block counts reported by statfs may be truncated to 2GB
+   and the correct values may be stored in the f_spare array.
+   [SunOS 4.1.2, 4.1.3, and 4.1.3_U1 are reported to have this problem.
+   SunOS 4.1.1 seems not to be affected.]  */
+/* #undef STATFS_TRUNCATES_BLOCK_COUNTS */
+
+/* The number of bytes in a __int64.  */
+#define SIZEOF___INT64 8
+
+/* The number of bytes in a char.  */
+#define SIZEOF_CHAR 1
+
+/* The number of bytes in a int.  */
+#define SIZEOF_INT 4
+
+/* The number of bytes in a long.  */
+#define SIZEOF_LONG 4
+
+/* The number of bytes in a long long.  */
+#define SIZEOF_LONG_LONG 0
+
+/* The number of bytes in a short.  */
+#define SIZEOF_SHORT 2
+
+/* Define if you have the bcopy function.  */
+/* #undef HAVE_BCOPY */
+
+/* Define if you have the cfmakeraw function.  */
+/* #undef HAVE_CFMAKERAW */
+
+/* Define if you have the endgrent function.  */
+/* #undef HAVE_ENDGRENT */
+
+/* Define if you have the endpwent function.  */
+/* #undef HAVE_ENDPWENT */
+
+/* Define if you have the fchdir function.  */
+/* #undef HAVE_FCHDIR */
+
+/* Define if you have the ftime function.  */
+/* #undef HAVE_FTIME */
+
+/* Define if you have the ftruncate function.  */
+/* #undef HAVE_FTRUNCATE */
+
+/* Define if you have the getcwd function.  */
+#define HAVE_GETCWD 1
+
+/* Define if you have the getmntinfo function.  */
+/* #undef HAVE_GETMNTINFO */
+
+/* Define if you have the getopt function.  */
+/* #undef HAVE_GETOPT */
+
+/* Define if you have the gettimeofday function.  */
+#ifndef _WIN32_WCE
+#define HAVE_GETTIMEOFDAY
+#endif
+
+/* Define if you have the isascii function.  */
+/* #undef HAVE_ISASCII */
+
+/* Define if you have the lchown function.  */
+/* #undef HAVE_LCHOWN */
+
+/* Define if you have the listmntent function.  */
+/* #undef HAVE_LISTMNTENT */
+
+/* Define if you have the memcpy function.  */
+/* #undef HAVE_MEMCPY */
+
+/* Define if you have the mkdir function.  */
+#define HAVE_MKDIR 1
+
+/* Define if you have the mkfifo function.  */
+/* #undef HAVE_MKFIFO */
+
+/* Define if you have the readdir_r function.  */
+/* #undef HAVE_READDIR_R */
+
+/* Define if you have the rmdir function.  */
+#define HAVE_RMDIR 1
+
+/* Define if you have the select function.  */
+/* #undef HAVE_SELECT */
+
+/* Define if you have the sigaction function.  */
+/* #undef HAVE_SIGACTION */
+
+/* Define if you have the strchr function.  */
+/* #undef HAVE_STRCHR */
+
+/* Define if you have the strdup function.  */
+#define HAVE_STRDUP 1
+
+/* Define if you have the strerror function.  */
+#define HAVE_STRERROR 1
+
+/* Define if you have the strrchr function.  */
+/* #undef HAVE_STRRCHR */
+
+/* Define if you have the strstr function.  */
+#define HAVE_STRSTR 1
+
+/* Define if you have the tcgetattr function.  */
+/* #undef HAVE_TCGETATTR */
+
+/* Define if you have the vfprintf function.  */
+#define HAVE_VFPRINTF 1
+
+/* Define if you have the vprintf function.  */
+#define HAVE_VPRINTF 1
+
+/* Define if you have the vsprintf function.  */
+#define HAVE_VSPRINTF 1
+
+/* Define if you have the <curses.h> header file.  */
+/* #undef HAVE_CURSES_H */
+
+/* Define if you have the <cybergraphx/cybergraphics.h> header file.  */
+/* #undef HAVE_CYBERGRAPHX_CYBERGRAPHICS_H */
+
+/* Define if you have the <ddraw.h> header file.  */
+#ifndef _WIN32_WCE
+#define HAVE_DDRAW_H 1
+#endif
+
+/* Define if you have the <devices/ahi.h> header file.  */
+/* #undef HAVE_DEVICES_AHI_H */
+
+/* Define if you have the <dirent.h> header file.  */
+/* #define HAVE_DIRENT_H 1 */
+
+/* Define if you have the <fcntl.h> header file.  */
+#ifndef _WIN32_WCE
+#define HAVE_FCNTL_H 1
+#endif
+
+/* Define if you have the <features.h> header file.  */
+/* #undef HAVE_FEATURES_H */
+
+/* Define if you have the <getopt.h> header file.  */
+/* #undef HAVE_GETOPT_H */
+
+/* Define if you have the <ggi/libggi.h> header file.  */
+/* #undef HAVE_GGI_LIBGGI_H */
+
+/* Define if you have the <libraries/cybergraphics.h> header file.  */
+/* #undef HAVE_LIBRARIES_CYBERGRAPHICS_H */
+
+/* Define if you have the <machine/joystick.h> header file.  */
+/* #undef HAVE_MACHINE_JOYSTICK_H */
+
+/* Define if you have the <machine/soundcard.h> header file.  */
+/* #undef HAVE_MACHINE_SOUNDCARD_H */
+
+/* Define if you have the <mntent.h> header file.  */
+/* #undef HAVE_MNTENT_H */
+
+/* Define if you have the <mnttab.h> header file.  */
+/* #undef HAVE_MNTTAB_H */
+
+/* Define if you have the <ncurses.h> header file.  */
+/* #undef HAVE_NCURSES_H */
+
+/* Define if you have the <ndir.h> header file.  */
+/* #undef HAVE_NDIR_H */
+
+/* Define if you have the <posix_opt.h> header file.  */
+/* #undef HAVE_POSIX_OPT_H */
+
+#ifndef _WIN32_WCE
+/* Define if you have the <string.h> header file.  */
+#define HAVE_STRING_H 1
+#endif
+
+/* Define if you have the <strings.h> header file.  */
+/* #undef HAVE_STRINGS_H */
+
+/* Define if you have the <sun/audioio.h> header file.  */
+/* #undef HAVE_SUN_AUDIOIO_H */
+
+/* Define if you have the <sys/audioio.h> header file.  */
+/* #undef HAVE_SYS_AUDIOIO_H */
+
+/* Define if you have the <sys/dir.h> header file.  */
+/* #undef HAVE_SYS_DIR_H */
+
+/* Define if you have the <sys/filsys.h> header file.  */
+/* #undef HAVE_SYS_FILSYS_H */
+
+/* Define if you have the <sys/fs/s5param.h> header file.  */
+/* #undef HAVE_SYS_FS_S5PARAM_H */
+
+/* Define if you have the <sys/fs_types.h> header file.  */
+/* #undef HAVE_SYS_FS_TYPES_H */
+
+/* Define if you have the <sys/fstyp.h> header file.  */
+/* #undef HAVE_SYS_FSTYP_H */
+
+/* Define if you have the <sys/ioctl.h> header file.  */
+/* #undef HAVE_SYS_IOCTL_H */
+
+/* Define if you have the <sys/ipc.h> header file.  */
+/* #undef HAVE_SYS_IPC_H */
+
+/* Define if you have the <sys/mount.h> header file.  */
+/* #undef HAVE_SYS_MOUNT_H */
+
+/* Define if you have the <sys/ndir.h> header file.  */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define if you have the <sys/param.h> header file.  */
+/* #undef HAVE_SYS_PARAM_H */
+
+/* Define if you have the <sys/shm.h> header file.  */
+/* #undef HAVE_SYS_SHM_H */
+
+/* Define if you have the <sys/soundcard.h> header file.  */
+/* #undef HAVE_SYS_SOUNDCARD_H */
+
+/* Define if you have the <sys/stat.h> header file.  */
+#ifndef _WIN32_WCE
+#define HAVE_SYS_STAT_H 1
+#endif
+
+/* Define if you have the <sys/statfs.h> header file.  */
+/* #undef HAVE_SYS_STATFS_H */
+
+/* Define if you have the <sys/statvfs.h> header file.  */
+/* #undef HAVE_SYS_STATVFS_H */
+
+/* Define if you have the <sys/termios.h> header file.  */
+/* #undef HAVE_SYS_TERMIOS_H */
+
+/* Define if you have the <sys/time.h> header file.  */
+#ifdef __GNUC__
+#define HAVE_SYS_TIME_H 1
+#endif
+
+/* Define if you have the <sys/types.h> header file.  */
+#ifndef _WIN32_WCE
+#define HAVE_SYS_TYPES_H 1
+#endif
+
+/* Define if you have the <sys/utime.h> header file.  */
+#ifndef _WIN32_WCE
+#define HAVE_SYS_UTIME_H 1
+#endif
+
+/* Define if you have the <sys/vfs.h> header file.  */
+/* #undef HAVE_SYS_VFS_H */
+
+/* Define if you have the <unistd.h> header file.  */
+#ifdef __GNUC__
+#define HAVE_UNISTD_H 1
+#endif
+
+/* Define if you have the <utime.h> header file.  */
+/* #undef HAVE_UTIME_H */
+
+/* Define if you have the <values.h> header file.  */
+#ifdef __GNUC__
+#define HAVE_VALUES_H 1
+#endif
+
+/* Define if you have the <windows.h> header file.  */
+#define HAVE_WINDOWS_H 1
+
+#define FSDB_DIR_SEPARATOR '\\'
diff --git a/od-win32/target.h b/od-win32/target.h
new file mode 100755 (executable)
index 0000000..4afd596
--- /dev/null
@@ -0,0 +1,25 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Target specific stuff, Win32 version
+  *
+  * Copyright 1997 Mathias Ortmann
+  */
+
+#ifdef _WIN32_WCE
+#define TARGET_NAME "WinCE"
+#define TARGET_NO_AUTOCONF
+#define TARGET_NO_ZFILE
+#define DONT_PARSE_CMDLINE
+#else
+#define TARGET_NAME "win32"
+#endif
+#define TARGET_PROVIDES_DEFAULT_PREFS
+#define TARGET_NO_DITHER
+
+#define NO_MAIN_IN_MAIN_C
+
+#define OPTIONSFILENAME "default.uae"
+
+#define DEFPRTNAME "none"
+#define DEFSERNAME "none"
diff --git a/od-win32/threaddep/thread.h b/od-win32/threaddep/thread.h
new file mode 100755 (executable)
index 0000000..551bb43
--- /dev/null
@@ -0,0 +1,64 @@
+
+#if 1
+
+typedef HANDLE uae_sem_t;
+typedef int uae_thread_id;
+extern void sem_close (void*);
+extern int sem_trywait (void*);
+extern void sem_post (void*);
+extern void sem_wait (void*t);
+extern void sem_init (void*, int manual_reset, int initial_state);
+extern int start_penguin (void *(*f)(void *), void *arg, DWORD * foo);
+extern void set_thread_priority (int);
+
+#define uae_sem_init sem_init
+#define uae_sem_destroy sem_close
+#define uae_sem_post sem_post
+#define uae_sem_wait sem_wait
+#define uae_sem_trywait sem_trywait
+#define uae_start_thread start_penguin
+
+#include "commpipe.h"
+
+#else
+
+/*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Threading support, using SDL
+  *
+  * Copyright 1997, 2001 Bernd Schmidt
+  */
+
+#include "SDL.h"
+#include "SDL_thread.h"
+
+/* Sempahores. We use POSIX semaphores; if you are porting this to a machine
+ * with different ones, make them look like POSIX semaphores. */
+typedef SDL_sem *uae_sem_t;
+
+#define uae_sem_init(PSEM, DUMMY, INIT) do { \
+    *PSEM = SDL_CreateSemaphore (INIT); \
+} while (0)
+#define uae_sem_destroy(PSEM) SDL_DestroySemaphore (*PSEM)
+#define uae_sem_post(PSEM) SDL_SemPost (*PSEM)
+#define uae_sem_wait(PSEM) SDL_SemWait (*PSEM)
+#define uae_sem_trywait(PSEM) SDL_SemTryWait (*PSEM)
+#define uae_sem_getvalue(PSEM) SDL_SemValue (*PSEM)
+
+#include "commpipe.h"
+extern void set_thread_priority (int);
+
+typedef SDL_Thread *uae_thread_id;
+#define BAD_THREAD NULL
+
+static __inline__ int uae_start_thread (void *(*f) (void *), void *arg, uae_thread_id *foo)
+{
+    *foo = SDL_CreateThread ((int (*)(void *))f, arg);
+    return *foo == 0;
+}
+
+/* Do nothing; thread exits if thread function returns.  */
+#define UAE_THREAD_EXIT do {} while (0)
+
+#endif
\ No newline at end of file
diff --git a/od-win32/unistd.h b/od-win32/unistd.h
new file mode 100755 (executable)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/od-win32/wcc.sh b/od-win32/wcc.sh
new file mode 100755 (executable)
index 0000000..db622a0
--- /dev/null
@@ -0,0 +1,266 @@
+#! /bin/sh
+#
+# Somewhat horrible shell script to convert GCC style options into Watcom
+# style.
+#
+# I put this into the public domain - if you think you can use it for
+# anything, use it.
+#
+# Written 1998 Bernd Schmidt
+
+realdirname () {
+  tmp_save_dir=`pwd`
+  cd $@
+  result=`pwd -P`
+  cd $tmp_save_dir
+  result=`echo $result |sed 's,/,\\\\,g'`
+}
+
+realfilename () {
+  case $@ in
+  */*)
+    tmp_save_dir=`pwd`
+    cd `echo $@ | sed 's,/[^/]*$,,'`
+    result=`pwd -P`/`basename $@`
+    cd $tmp_save_dir
+    ;;
+  *)
+    result=$@
+    ;;
+  esac
+  result=`echo $result |sed 's,/,\\\\,g'`
+}
+
+gcc_wsysinc1=`echo $INCLUDE | sed 's,;, ,g' | sed 's,.:,;\\0,g' |sed -e 's,;,//,g' -e 's,:,/,g' -e 's,\\\\,/,g'`
+for foo in $gcc_wsysinc1; do
+  gcc_wsysinc2="$gcc_wsysinc2 -I$foo"
+done
+gcc_spcdefs="-undef -U__GNUC__ -U__GNUC_MINOR__ -D_WIN32 -D__WATCOMC__ -D_STDCALL_SUPPORTED=1 -D__X86__ -D__386__=1 -DM_I386=1 -D_M_I386 -D_M_IX86=500 -D__NT__=1"
+
+mode=link
+options=
+srcfiles=
+asmfiles=
+objfiles=
+resfiles=
+outputfile=
+libraries=
+gnudefines=
+wccdefines=
+includes=
+gnuincludes=
+
+next_is_output=no
+next_is_include=no
+
+for arg in $@; do
+
+if test $next_is_output = yes; then
+  outputfile=$arg
+  next_is_output=no
+else if test $next_is_include = yes; then
+  includes="$includes $arg"
+  gnuincludes="$gnuincludes -I$arg"
+  next_is_include=no
+else
+  case $arg in
+# Passing /xxx options directly may be too risky - they could be confused for
+# file names - so use this escape.
+  --/--*)
+    options="$options `echo $arg |sed s,^--/--,/,`"
+    ;;
+
+  -I) next_is_include=yes
+    ;;
+
+  -I*)
+    includes="$includes `echo $arg | sed 's,^-I,,'`"
+    gnuincludes="$gnuincludes $arg"
+    ;;
+
+  -D*=*)
+    gnudefines="$gnudefines $arg"
+    wccdefines="$wccdefines `echo $arg |sed 's,^-D,/d,'`"
+    ;;
+
+  -D*)
+    gnudefines="$gnudefines $arg"
+    wccdefines="$wccdefines `echo $arg |sed 's,^-D,/d,'`="
+    ;;
+
+  -c) if [ "$mode" != "link" ]; then
+        echo "Bad argument"
+        exit 10
+      fi
+      mode=compile
+    ;;
+
+  -S) if [ "$mode" != "link" ]; then
+        echo "Bad argument"
+        exit 10
+      fi
+      mode=assemble
+    ;;
+
+  -E) if [ "$mode" != "link" ]; then
+        echo "Bad argument"
+        exit 10
+      fi
+      mode=preprocess
+    ;;
+
+  -g) options="$options /d2"
+    ;;
+
+  -o) next_is_output=yes
+    if [ "x$outputfile" != "x" ]; then
+      echo "Multiple output files!"
+      exit 10
+    fi
+    ;;
+
+  -l*) libraries="$libraries `echo $arg | sed 's,^-l,,'`"
+    ;;
+
+  *.c)
+    srcfiles="$srcfiles $arg"
+    ;;
+
+  *.S)
+    asmfiles="$asmfiles $arg"
+    ;;
+    
+  *.res)
+    realfilename $arg
+    resfiles="$resfiles $result"
+    ;;
+
+  *.o)
+    realfilename $arg
+    objfiles="$objfiles $result"
+    ;;
+
+  *) echo "Bad argument: $arg"
+    ;;
+  esac
+fi
+fi
+done
+
+#echo "Source files: $srcfiles"
+#echo "Object files: $objfiles"
+#echo "Output files: $outputfile"
+#echo "Libraries: $libraries"
+echo "Mode: $mode"
+#echo "Options: $options"
+
+if [ "$mode" != "link" -a "x$libraries" != "x" ]; then
+  echo "Libraries specified in non-link mode!"
+  exit 10
+fi
+
+prefiles=
+srccount=0
+for foo in $srcfiles; do
+  bar=wccsh-tmppre$srccount.i
+  prefiles="$prefiles $bar"
+  echo "gcc -E -nostdinc $gnuincludes $gcc_wsysinc2 $gcc_spcdefs $gnudefines $foo -o $bar"
+  if gcc -E -nostdinc $gnuincludes $gcc_wsysinc2 $gcc_spcdefs $gnudefines $foo -o $bar; then
+
+  else
+    exit 10
+  fi
+  if [ ! -f $bar ]; then
+    exit 10
+  fi
+  srccount=`expr $srccount + 1`
+done
+
+tmpobjs=
+if test $mode = compile -o $mode = link; then
+  tmpcnt=0
+  for foo in $asmfiles; do
+    bar=wccsh-tmpobj$tmpcnt.o
+    tmpcnt=`expr $tmpcnt + 1`
+    tmpobjs="$tmpobjs $bar"
+    echo "gcc -c $foo -o $bar"
+    gcc -c $foo -o $bar
+    srccount=`expr $srccount + 1`
+  done
+  for foo in $prefiles; do
+    bar=wccsh-tmpobj$tmpcnt.o
+    tmpcnt=`expr $tmpcnt + 1`
+    tmpobjs="$tmpobjs $bar"
+    sed -e '/^# [0123456789]*/s,^# ,#line ,' -e '/^#line/s,"[^"]*$,",' <$foo> wccsh_tmpsrc.c
+    echo "wcc386 $foo $options /fo=$bar"
+    wcc386 wccsh_tmpsrc.c $options /fo=wcc_tmp.o >&2
+    mv -f wcc_tmp.o $bar
+    if [ ! -f $bar ]; then
+      rm -f $prefiles $tmpobjs
+      exit 10
+    fi
+  done
+fi
+
+case $mode in
+  preprocess)
+    for foo in $prefiles; do
+      if [ "x$outputfile" = "x" ]; then
+        cat $foo
+      else
+        mv -f $foo $outputfile
+      fi
+    done
+    ;;
+
+  compile)
+    if [ "$srccount" != "1" -a "x$outputfile" != "x" ]; then
+      echo "cannot specify -o and -c with multiple compilations" >&2
+      exit 10
+    fi
+    if [ "x$outputfile" != "x" ]; then
+      echo Moving "'" $tmpobjs "'" to "'" $outputfile "'"
+      if mv $tmpobjs $outputfile 2>/dev/null; then
+      fi
+    fi
+    ;;
+
+  assemble)
+    ;;
+
+  link)
+    if [ "x$outputfile" = "x" ]; then
+      outputfile=a.out
+    fi
+    FILES=
+    for foo in $objfiles $tmpobjs; do
+      if [ "x$FILES" = "x" ]; then
+        FILES=$foo
+      else
+        FILES="$FILES,$foo"
+      fi
+    done
+    for foo in $resfiles; do
+      FILES="$FILES op resource=$foo"
+    done
+    for foo in $libraries; do
+      FILES="$FILES LIB $foo"
+    done
+#    echo Files: $FILES
+#    echo "wlink SYSTEM nt FIL $FILES NAME $outputfile"
+    wlink SYSTEM nt FIL $FILES NAME $outputfile >wccsh-linkerror.log
+    if grep "cannot open.*No such file or" wccsh-linkerror.log; then
+#      rm wccsh-linkerror.log
+      rm $outputfile
+      exit 10
+    fi
+#    rm wccsh-linkerror.log
+    if [ ! -f $outputfile ]; then
+      rm -f $prefiles $tmpobjs
+      exit 10
+    fi
+    ;;
+esac
+
+rm -f $prefiles $tmpobjs
+exit 0
diff --git a/od-win32/win32.c b/od-win32/win32.c
new file mode 100755 (executable)
index 0000000..cd9d795
--- /dev/null
@@ -0,0 +1,2120 @@
+/*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * Win32 interface
+ *
+ * Copyright 1997-1998 Mathias Ortmann
+ * Copyright 1997-1999 Brian King
+ */
+
+/* Uncomment this line if you want the logs time-stamped */
+/* #define TIMESTAMP_LOGS */
+
+#include "config.h"
+#include "sysconfig.h"
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <signal.h>
+
+#include <windows.h>
+#include <commctrl.h>
+#include <commdlg.h>
+#include <shellapi.h>
+#include <zmouse.h>
+#include <ddraw.h>
+#include <dbt.h>
+#include <math.h>
+#include <mmsystem.h>
+
+#include "sysdeps.h"
+#include "options.h"
+#include "sound.h"
+#include "uae.h"
+#include "memory.h"
+#include "custom.h"
+#include "events.h"
+#include "xwin.h"
+#include "keyboard.h"
+#include "inputdevice.h"
+#include "keybuf.h"
+#include "drawing.h"
+#include "dxwrap.h"
+#include "picasso96.h"
+#include "bsdsocket.h"
+#include "win32.h"
+#include "win32gfx.h"
+#include "win32gui.h"
+#include "resource.h"
+#include "autoconf.h"
+#include "gui.h"
+#include "newcpu.h"
+#include "sys/mman.h"
+#include "avioutput.h"
+#include "ahidsound.h"
+#include "zfile.h"
+#include "savestate.h"
+#include "ioport.h"
+#include "parser.h"
+#include "scsidev.h"
+#include "disk.h"
+
+extern void WIN32GFX_WindowMove ( void );
+extern void WIN32GFX_WindowSize ( void );
+unsigned long *win32_stackbase; 
+unsigned long *win32_freestack[42]; //EXTRA_STACK_SIZE
+
+extern FILE *debugfile;
+extern int console_logging;
+static OSVERSIONINFO osVersion;
+
+int useqpc = 0; /* Set to TRUE to use the QueryPerformanceCounter() function instead of rdtsc() */
+int cpu_mmx = 0;
+static int no_rdtsc;
+
+HINSTANCE hInst = NULL;
+HMODULE hUIDLL = NULL;
+HWND (WINAPI *pHtmlHelp)(HWND, LPCSTR, UINT, LPDWORD ) = NULL;
+HWND hAmigaWnd, hMainWnd;
+RECT amigawin_rect;
+static UINT TaskbarRestart;
+static int TaskbarRestartOk;
+
+char VersionStr[256];
+
+int in_sizemove;
+int manual_painting_needed;
+int manual_palette_refresh_needed;
+int win_x_diff, win_y_diff;
+
+int toggle_sound;
+int paraport_mask;
+
+HKEY hWinUAEKey    = NULL;
+COLORREF g_dwBackgroundColor  = RGB(10, 0, 10);
+
+static int emulation_paused;
+static int activatemouse = 1;
+static int ignore_messages_all;
+int pause_emulation;
+
+static int didmousepos;
+int mouseactive, focus;
+
+static int mm_timerres;
+static int timermode, timeon;
+static HANDLE timehandle;
+
+char *start_path;
+char help_file[ MAX_PATH ];
+extern int harddrive_dangerous, do_rdbdump, aspi_allow_all, dsound_hardware_mixing, no_rawinput;
+int log_scsi;
+
+static int timeend (void)
+{
+    if (!timeon)
+       return 1;
+    timeon = 0;
+    if (timeEndPeriod (mm_timerres) == TIMERR_NOERROR)
+       return 1;
+    write_log ("TimeEndPeriod() failed\n");
+    return 0;
+}
+
+static int timebegin (void)
+{
+    if (timeon) {
+       timeend();
+       return timebegin();
+    }
+    timeon = 0;
+    if (timeBeginPeriod (mm_timerres) == TIMERR_NOERROR) {
+       timeon = 1;
+       return 1;
+    }
+    write_log ("TimeBeginPeriod() failed\n");
+    return 0;
+}
+
+static void init_mmtimer (void)
+{
+    TIMECAPS tc;
+    mm_timerres = 0;
+    if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR)
+       return;
+    mm_timerres = min(max(tc.wPeriodMin, 1), tc.wPeriodMax);
+    timehandle = CreateEvent (NULL, TRUE, FALSE, NULL);
+}
+
+void sleep_millis (int ms)
+{
+    UINT TimerEvent;
+    int start = read_processor_time();
+    if (mm_timerres <= 0 || timermode) {
+       Sleep (ms);
+    } else {
+       TimerEvent = timeSetEvent (ms, 0, timehandle, 0, TIME_ONESHOT | TIME_CALLBACK_EVENT_SET);
+       if (!TimerEvent) {
+           Sleep (ms);
+       } else {
+           WaitForSingleObject (timehandle, ms);
+           ResetEvent (timehandle);
+           timeKillEvent (TimerEvent);
+       }
+    }
+    idletime += read_processor_time() - start;
+}
+
+void sleep_millis_busy (int ms)
+{
+    if (timermode < 0)
+       return;
+    sleep_millis (ms);
+}
+
+#include <process.h>
+static volatile int dummythread_die;
+static void dummythread (void *dummy)
+{
+    SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_LOWEST);
+    while (!dummythread_die);
+}
+
+static uae_u64 win32_read_processor_time (void)
+{
+    uae_u32 foo, bar;
+     __asm
+    {
+        rdtsc
+        mov foo, eax
+        mov bar, edx
+    }
+    return ((uae_u64)bar << 32) | foo;
+}
+
+static int figure_processor_speed (void)
+{
+    extern volatile frame_time_t vsynctime;
+    extern unsigned long syncbase;
+    uae_u64 clockrate, clockrateidle, qpfrate, ratea1, ratea2;
+    uae_u32 rate1, rate2;
+    double limit, clkdiv = 1, clockrate1000 = 0;
+    int i, ratecnt = 5;
+    LARGE_INTEGER freq;
+    int qpc_avail = 0;
+    int mmx = 0; 
+
+    rpt_available = no_rdtsc > 0 ? 0 : 1;
+    __try
+    {
+       __asm 
+       {
+           rdtsc
+       }
+    } __except( GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION ) {
+       rpt_available = 0;
+       write_log ("CLOCKFREQ: RDTSC not supported\n");
+    }
+    __try
+    {
+       __asm 
+       {
+           mov eax,1
+           cpuid
+           and edx,0x800000
+           mov mmx,edx
+       }
+       if (mmx)
+           cpu_mmx = 1;
+    } __except( GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION ) {
+    }
+
+    if (QueryPerformanceFrequency(&freq)) {
+       qpc_avail = 1;
+       write_log("CLOCKFREQ: QPF %.2fMHz\n", freq.QuadPart / 1000000.0);
+       qpfrate = freq.QuadPart;
+        /* we don't want 32-bit overflow */
+       if (qpfrate > 100000000) {
+           qpfrate >>= 6;
+           qpc_avail = -1;
+       }
+    } else {
+       write_log("CLOCKREQ: QPF not supported\n");
+    }
+
+    if (!rpt_available && !qpc_avail) {
+       pre_gui_message ("No timing reference found\n(no RDTSC or QPF support detected)\nWinUAE will exit\n");
+       return 0;
+    }
+
+    init_mmtimer();
+    SetThreadPriority ( GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
+    sleep_millis (100);
+    dummythread_die = -1;
+
+    if (qpc_avail || rpt_available)  {
+       int qpfinit = 0;
+
+       if (rpt_available) {
+           clockrateidle = win32_read_processor_time();
+           sleep_millis (500);
+           clockrateidle = (win32_read_processor_time() - clockrateidle) * 2;
+           dummythread_die = 0;
+           _beginthread(&dummythread, 0, 0);
+           sleep_millis (100);
+           clockrate = win32_read_processor_time();
+           sleep_millis (500);
+           clockrate = (win32_read_processor_time() - clockrate) * 2;
+           write_log("CLOCKFREQ: RDTSC %.2fMHz (busy) / %.2fMHz (idle)\n",
+               clockrate / 1000000.0, clockrateidle / 1000000.0);
+           clkdiv = (double)clockrate / (double)clockrateidle;
+           clockrate >>= 6;
+           clockrate1000 = clockrate / 1000.0;
+       }
+       if (rpt_available && qpc_avail && qpfrate / 950.0 >= clockrate1000) {
+           write_log ("CLOCKFREQ: Using QPF (QPF ~>= RDTSC)\n");
+           qpfinit = 1;
+       } else  if (((clkdiv <= 0.95 || clkdiv >= 1.05) && no_rdtsc == 0) || !rpt_available) {
+           if (rpt_available)
+               write_log ("CLOCKFREQ: CPU throttling detected, using QPF instead of RDTSC\n");
+           qpfinit = 1;
+       }
+       if (qpfinit) {
+           useqpc = qpc_avail;
+           rpt_available = 1;
+           clkdiv = 1.0;
+           clockrate = qpfrate;
+           clockrate1000 = clockrate / 1000.0;
+           if (dummythread_die < 0) {
+               dummythread_die = 0;
+               _beginthread(&dummythread, 0, 0);
+           }
+           if (!qpc_avail)
+               write_log ("No working timing reference detected\n");
+       }
+       timermode = 0;
+       if (mm_timerres) {
+           sleep_millis (50);
+           timebegin ();
+           sleep_millis (50);
+           ratea1 = 0;
+           write_log ("Testing MM-timer resolution:\n");
+           for (i = 0; i < ratecnt; i++) {
+               rate1 = read_processor_time();
+               sleep_millis (1);
+               rate1 = read_processor_time() - rate1;
+               write_log ("%1.2fms ", rate1 / clockrate1000);
+               ratea1 += rate1;
+           }
+           write_log("\n");
+           timeend ();
+           sleep_millis (50);
+       }
+       timermode = 1;
+       ratea2 = 0;
+       write_log ("Testing Sleep() resolution:\n");
+       for (i = 0; i < ratecnt; i++) {
+           rate2 = read_processor_time();
+           sleep_millis (1);
+           rate2 = read_processor_time() - rate2;
+           write_log ("%1.2fms ", rate2 / clockrate1000);
+           ratea2 += rate2;
+       }
+       write_log("\n");
+    }
+
+    SetThreadPriority ( GetCurrentThread(), THREAD_PRIORITY_NORMAL);
+    dummythread_die = 1;
+   
+    if (clkdiv >= 0.90 && clkdiv <= 1.10 && rpt_available) {
+       limit = 2.5;
+       if ((ratea2 / ratecnt) < limit * clockrate1000) { /* regular Sleep() is ok */
+           timermode = 1;
+           write_log ("Using Sleep() (resolution < %.1fms)\n", limit);
+       } else if (mm_timerres && (ratea1 / ratecnt) < limit * clockrate1000) { /* MM-timer is ok */
+           timermode = 0;
+           timebegin ();
+           write_log ("Using MultiMedia timers (resolution < %.1fms)\n", limit);
+       } else {
+           timermode = -1; /* both timers are bad, fall back to busy-wait */
+           write_log ("falling back to busy-loop waiting (timer resolution > %.1fms)\n", limit);
+       }
+    } else {
+       timermode = -1;
+       write_log ("forcing busy-loop wait mode\n");
+    }
+    syncbase = (unsigned long)clockrate;
+    return 1;
+}
+
+static void setcursor(int oldx, int oldy)
+{
+    int x = (amigawin_rect.right - amigawin_rect.left) / 2;
+    int y = (amigawin_rect.bottom - amigawin_rect.top) / 2;
+    if (oldx == x && oldy == y)
+       return;
+    SetCursorPos (amigawin_rect.left + x, amigawin_rect.top + y);
+}
+
+void setmouseactive (int active)
+{
+    int oldactive = mouseactive;
+    static int mousecapture, showcursor;
+    char txt[100], txt2[110];
+
+    if (active > 0 && ievent_alive > 0) {
+       mousehack_set (mousehack_follow);
+       return;
+    }
+    mousehack_set (mousehack_dontcare);
+    inputdevice_unacquire ();
+    mouseactive = active;
+    strcpy (txt, "WinUAE");
+    if (mouseactive > 0) {
+       focus = 1;
+        WIN32GUI_LoadUIString (currprefs.win32_middle_mouse ? IDS_WINUAETITLE_MMB : IDS_WINUAETITLE_NORMAL,
+           txt2, sizeof (txt2));
+       strcat (txt, " - ");
+       strcat (txt, txt2);
+    }
+    SetWindowText (hMainWnd, txt);
+    if (mousecapture) {
+       ClipCursor (0);
+       ReleaseCapture ();
+       mousecapture = 0;
+    }
+    if (showcursor) {
+       ShowCursor (TRUE);
+       showcursor = 0;
+    }
+    if (mouseactive) {
+       if (focus) {
+           if (!showcursor)
+               ShowCursor (FALSE);
+           showcursor = 1;
+           if (!isfullscreen()) {
+               if (!mousecapture) {
+                   SetCapture (hAmigaWnd);
+                   ClipCursor (&amigawin_rect);
+               }
+               mousecapture = 1;
+           }
+           setcursor (-1, -1);
+       }
+       inputdevice_acquire (mouseactive);
+    }
+}
+
+#ifndef AVIOUTPUT
+static int avioutput_video = 0;
+#endif
+
+void setpriority (int pri)
+{
+    static int priwarn;
+    SetThreadPriority ( GetCurrentThread(), pri);
+    if (pri == 2 && priwarn == 0) {
+       priwarn = 1;
+       gui_message("Priority = 2!");
+    }
+    write_log ("priority set to %d\n", pri);
+}
+
+static void winuae_active (HWND hWnd, int minimized)
+{
+    int ot, pri;
+
+    /* without this returning from hibernate-mode causes wrong timing
+     */
+    ot = timermode;
+    timermode = 0;
+    timebegin();
+    sleep_millis (2);
+    timermode = ot;
+    if (timermode != 0)
+       timeend();  
+
+    focus = 1;
+    write_log( "WinUAE now active via WM_ACTIVATE\n" );
+    pri = priorities[currprefs.win32_inactive_priority].value;
+#ifndef _DEBUG
+    if (!minimized)
+       pri = priorities[currprefs.win32_active_priority].value;
+#endif
+    setpriority (pri);
+
+    if (!minimized) {
+        if (!avioutput_video) {
+           clear_inhibit_frame( IHF_WINDOWHIDDEN );
+       }
+    }
+    if (emulation_paused > 0)
+       emulation_paused = -1;
+    ShowWindow (hWnd, SW_RESTORE);
+#ifdef AHI
+    ahi_close_sound ();
+#endif
+    close_sound ();
+#ifdef AHI
+    ahi_open_sound ();
+#endif
+    init_sound ();
+    if (WIN32GFX_IsPicassoScreen ())
+       WIN32GFX_EnablePicasso();
+    getcapslock ();
+    inputdevice_acquire (mouseactive);
+    wait_keyrelease ();
+    inputdevice_acquire (mouseactive);
+    if (isfullscreen())
+       setmouseactive (1);
+    manual_palette_refresh_needed = 1;
+}
+
+static void winuae_inactive (HWND hWnd, int minimized)
+{
+    int pri;
+
+    focus = 0;
+    write_log( "WinUAE now inactive via WM_ACTIVATE\n" );
+    wait_keyrelease ();
+    setmouseactive (0);
+    close_sound ();
+#ifdef AHI
+    ahi_close_sound ();
+#endif
+    init_sound ();
+#ifdef AHI
+    ahi_open_sound ();
+#endif
+    pri = priorities[currprefs.win32_inactive_priority].value;
+    if (!quit_program) {
+       if (minimized) {
+           inputdevice_unacquire ();
+           pri = priorities[currprefs.win32_iconified_priority].value;
+           if (currprefs.win32_iconified_nosound) {
+               close_sound ();
+    #ifdef AHI
+               ahi_close_sound ();
+    #endif
+           }
+           if (!avioutput_video) {
+               set_inhibit_frame( IHF_WINDOWHIDDEN );
+           }
+           if (currprefs.win32_iconified_pause) {
+               close_sound ();
+    #ifdef AHI
+               ahi_close_sound ();
+    #endif
+               emulation_paused = 1;
+           }
+       } else {
+           if (currprefs.win32_inactive_nosound) {
+               close_sound ();
+    #ifdef AHI
+               ahi_close_sound ();
+    #endif
+           }
+           if (currprefs.win32_inactive_pause) {
+               close_sound ();
+    #ifdef AHI
+               ahi_close_sound ();
+    #endif
+               emulation_paused = 1;
+           }
+       }
+    }
+    setpriority (pri);
+#ifdef FILESYS
+    filesys_flush_cache ();
+#endif
+}
+
+void minimizewindow (void)
+{
+    ShowWindow (hMainWnd, SW_MINIMIZE);
+}
+
+void disablecapture (void)
+{
+    setmouseactive (0);
+    close_sound ();
+#ifdef AHI
+    ahi_close_sound ();
+#endif
+}
+
+static long FAR PASCAL AmigaWindowProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    PAINTSTRUCT ps;
+    HDC hDC;
+    BOOL minimized;
+    LPMINMAXINFO lpmmi;
+    RECT rect;
+    int mx, my;
+    static int mm;
+
+    if (ignore_messages_all)
+       return DefWindowProc (hWnd, message, wParam, lParam);
+
+    if (hMainWnd == 0)
+       hMainWnd = hWnd;
+
+    switch( message ) 
+    {
+    case WM_ACTIVATE:
+       minimized = HIWORD( wParam );
+       if (LOWORD (wParam) != WA_INACTIVE)
+           winuae_active (hWnd, minimized);
+        else
+           winuae_inactive (hWnd, minimized);
+    break;
+
+    case WM_ACTIVATEAPP:
+       if (!wParam)
+           setmouseactive (0);
+       else if (gui_active && isfullscreen())
+           exit_gui (0);
+        manual_palette_refresh_needed = 1;
+    break;
+
+    case WM_PALETTECHANGED:
+        if( (HWND)wParam != hWnd )
+           WIN32GFX_PaletteChange();
+    break;
+
+    case WM_KEYDOWN:
+       if (dinput_wmkey ((uae_u32)lParam))
+           gui_display (-1);
+    return 0;
+
+    case WM_LBUTTONUP:
+       if (dinput_winmouse () > 0)
+           setmousebuttonstate (dinput_winmouse(), 0, 0);
+    return 0;
+    case WM_LBUTTONDOWN:
+    case WM_LBUTTONDBLCLK:
+       if (!mouseactive && !isfullscreen()) {
+           setmouseactive (1);
+       }
+       if (dinput_winmouse () > 0)
+           setmousebuttonstate (dinput_winmouse(), 0, 1);
+    return 0;
+    case WM_RBUTTONUP:
+       if (dinput_winmouse () > 0)
+           setmousebuttonstate (dinput_winmouse(), 1, 0);
+    return 0;
+    case WM_RBUTTONDOWN:
+    case WM_RBUTTONDBLCLK:
+       if (dinput_winmouse () > 0)
+           setmousebuttonstate (dinput_winmouse(), 1, 1);
+    return 0;
+    case WM_MBUTTONUP:
+       if (dinput_winmouse () > 0)
+           setmousebuttonstate (dinput_winmouse(), 2, 0);
+    return 0;
+    case WM_MBUTTONDOWN:
+    case WM_MBUTTONDBLCLK:
+       if (dinput_winmouse () > 0)
+           setmousebuttonstate (dinput_winmouse(), 2, 1);
+    return 0;
+    case WM_MOUSEWHEEL:
+       if (dinput_winmouse () > 0)
+           setmousestate (dinput_winmouse(), 2, ((short)HIWORD(wParam)), 0);
+    return 0;
+
+    case WM_PAINT:
+       notice_screen_contents_lost ();
+        hDC = BeginPaint (hWnd, &ps);
+        /* Check to see if this WM_PAINT is coming while we've got the GUI visible */
+        if (manual_painting_needed)
+           updatedisplayarea ();
+       EndPaint (hWnd, &ps);
+       if (manual_palette_refresh_needed) {
+           WIN32GFX_SetPalette();
+#ifdef PICASSO96
+           DX_SetPalette (0, 256);
+#endif
+           manual_palette_refresh_needed = 0;
+       }
+    break;
+
+    case WM_DROPFILES:
+       dragdrop (hWnd, (HDROP)wParam, &changed_prefs, -1);
+    break;
+     
+    case WM_TIMER:
+#ifdef PARALLEL_PORT
+       finishjob ();
+#endif
+    break;
+
+    case WM_CREATE:
+       DragAcceptFiles (hWnd, TRUE);
+    break;
+
+    case WM_CLOSE:
+       if( !currprefs.win32_ctrl_F11_is_quit )
+           uae_quit ();
+    return 0;
+
+    case WM_WINDOWPOSCHANGED:
+       GetWindowRect( hWnd, &amigawin_rect);
+    break;
+
+    case WM_MOUSEMOVE:
+        mx = (signed short) LOWORD (lParam);
+        my = (signed short) HIWORD (lParam);
+       if (dinput_winmouse () > 0) {
+           int mxx = (amigawin_rect.right - amigawin_rect.left) / 2;
+           int myy = (amigawin_rect.bottom - amigawin_rect.top) / 2;
+           mx = mx - mxx;
+           my = my - myy;
+           setmousestate (dinput_winmouse (), 0, mx, 0);
+           setmousestate (dinput_winmouse (), 1, my, 0);
+        } else if ((!mouseactive && !isfullscreen())) {
+           setmousestate (0, 0, mx, 1);
+           setmousestate (0, 1, my, 1);
+       } else {
+#if 0
+           int mxx = (amigawin_rect.right - amigawin_rect.left) / 2;
+           int myy = (amigawin_rect.bottom - amigawin_rect.top) / 2;
+           mx = mx - mxx;
+           my = my - myy;
+           setmousestate (0, 0, mx, 0);
+           setmousestate (0, 1, my, 0);
+#endif
+       }
+       if (mouseactive)
+           setcursor (LOWORD (lParam), HIWORD (lParam));
+    return 0;
+
+    case WM_MOVING:
+    case WM_MOVE:
+       WIN32GFX_WindowMove();
+    return TRUE;
+
+    case WM_SIZING:
+       WIN32GFX_WindowSize();
+    return TRUE;
+
+    case WM_SIZE:
+       WIN32GFX_WindowSize();
+    return 0;
+
+    case WM_GETMINMAXINFO:
+       rect.left=0;
+       rect.top=0;
+       lpmmi=(LPMINMAXINFO)lParam;
+       rect.right=320;
+       rect.bottom=256;
+       //AdjustWindowRectEx(&rect,WSTYLE,0,0);
+       lpmmi->ptMinTrackSize.x=rect.right-rect.left;
+       lpmmi->ptMinTrackSize.y=rect.bottom-rect.top;
+    return 0;
+
+#ifdef FILESYS
+    case WM_DEVICECHANGE:
+    {
+       extern void win32_spti_media_change (char driveletter, int insert);
+       extern void win32_ioctl_media_change (char driveletter, int insert);
+       extern void win32_aspi_media_change (char driveletter, int insert);
+       DEV_BROADCAST_HDR *pBHdr = (DEV_BROADCAST_HDR *)lParam;
+       if( pBHdr && ( pBHdr->dbch_devicetype == DBT_DEVTYP_VOLUME ) ) {
+           DEV_BROADCAST_VOLUME *pBVol = (DEV_BROADCAST_VOLUME *)lParam;
+           if( pBVol->dbcv_flags & DBTF_MEDIA ) {
+               if( pBVol->dbcv_unitmask ) {
+                   int inserted, i;
+                   char drive;
+                   for (i = 0; i <= 'Z'-'A'; i++) {
+                       if (pBVol->dbcv_unitmask & (1 << i)) {
+                           drive = 'A' + i;
+                           inserted = -1;
+                           if (wParam == DBT_DEVICEARRIVAL)
+                               inserted = 1;
+                           else if (wParam == DBT_DEVICEREMOVECOMPLETE)
+                               inserted = 0;
+       #ifdef WINDDK
+                           win32_spti_media_change (drive, inserted);
+                           win32_ioctl_media_change (drive, inserted);
+       #endif
+                           win32_aspi_media_change (drive, inserted);
+                       }
+                   }
+               }
+           }
+       }
+    }
+#endif
+    return TRUE;
+
+    case WM_SYSCOMMAND:
+       if (!manual_painting_needed && focus) {
+           switch (wParam) // Check System Calls
+           {
+               case SC_SCREENSAVE: // Screensaver Trying To Start?
+               case SC_MONITORPOWER: // Monitor Trying To Enter Powersave?
+               return 0; // Prevent From Happening
+           }
+       }
+    break;
+
+    case 0xff: // WM_INPUT:
+    handle_rawinput (lParam);
+    break;
+    
+     case WM_USER + 1: /* Systray icon */
+        switch (lParam)
+        {
+           case WM_LBUTTONDOWN:
+           SetForegroundWindow (hWnd);
+           break;
+           case WM_LBUTTONDBLCLK:
+           gui_display (-1);
+           break;
+           case WM_RBUTTONDOWN:
+           if (!gui_active)
+               systraymenu (hWnd);
+           else
+               SetForegroundWindow (hWnd);
+           break;
+        }
+       break;
+     case WM_COMMAND:
+       switch (wParam & 0xffff)
+       {
+           case ID_ST_CONFIGURATION:
+               gui_display (-1);
+           break;
+           case ID_ST_HELP:
+               if (pHtmlHelp)
+                   pHtmlHelp (NULL, help_file, 0, NULL);
+           break;
+           case ID_ST_QUIT:
+               uae_quit ();
+           break;
+           case ID_ST_RESET:
+               uae_reset (0);
+           break;
+           case ID_ST_EJECTALL:
+               disk_eject (0);
+               disk_eject (1);
+               disk_eject (2);
+               disk_eject (3);
+           break;
+           case ID_ST_DF0:
+               DiskSelection (hWnd, IDC_DF0, 0, &changed_prefs, 0);
+               disk_insert (0, changed_prefs.df[0]);
+           break;
+           case ID_ST_DF1:
+               DiskSelection (hWnd, IDC_DF1, 0, &changed_prefs, 0);
+               disk_insert (1, changed_prefs.df[0]);
+           break;
+           case ID_ST_DF2:
+               DiskSelection (hWnd, IDC_DF2, 0, &changed_prefs, 0);
+               disk_insert (2, changed_prefs.df[0]);
+           break;
+           case ID_ST_DF3:
+               DiskSelection (hWnd, IDC_DF3, 0, &changed_prefs, 0);
+               disk_insert (3, changed_prefs.df[0]);
+           break;
+       }
+       break;
+
+     default:
+        if (TaskbarRestartOk && message == TaskbarRestart)
+            systray (hWnd, 0);
+    break;
+    }
+
+    return DefWindowProc (hWnd, message, wParam, lParam);
+}
+
+static long FAR PASCAL MainWindowProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    PAINTSTRUCT ps;
+    RECT rc;
+    HDC hDC;
+
+    switch (message) {
+
+     case WM_MOUSEMOVE:
+     case WM_MOUSEWHEEL:
+     case WM_ACTIVATEAPP:
+     case WM_DROPFILES:
+     case WM_ACTIVATE:
+     case WM_SETCURSOR:
+     case WM_SYSCOMMAND:
+     case WM_KEYUP:
+     case WM_SYSKEYUP:
+     case WM_KEYDOWN:
+     case WM_SYSKEYDOWN:
+     case WM_LBUTTONDOWN:
+     case WM_LBUTTONUP:
+     case WM_LBUTTONDBLCLK:
+     case WM_MBUTTONDOWN:
+     case WM_MBUTTONUP:
+     case WM_MBUTTONDBLCLK:
+     case WM_RBUTTONDOWN:
+     case WM_RBUTTONUP:
+     case WM_RBUTTONDBLCLK:
+     case WM_MOVING:
+     case WM_MOVE:
+     case WM_SIZING:
+     case WM_SIZE:
+     case WM_GETMINMAXINFO:
+     case WM_CREATE:
+     case WM_DESTROY:
+     case WM_CLOSE:
+     case WM_HELP:
+     case WM_DEVICECHANGE:
+     case 0xff: // WM_INPUT
+     case WM_USER + 1:
+     case WM_COMMAND:
+       return AmigaWindowProc (hWnd, message, wParam, lParam);
+
+     case WM_DISPLAYCHANGE:
+       if (!isfullscreen() && !currprefs.gfx_filter && (wParam + 7) / 8 != DirectDraw_GetBytesPerPixel() )
+           WIN32GFX_DisplayChangeRequested();
+       break;
+
+     case WM_ENTERSIZEMOVE:
+       in_sizemove++;
+       break;
+
+     case WM_EXITSIZEMOVE:
+       in_sizemove--;
+       /* fall through */
+
+     case WM_WINDOWPOSCHANGED:
+       WIN32GFX_WindowMove();
+       if( hAmigaWnd && GetWindowRect (hAmigaWnd, &amigawin_rect) )
+       {
+           if (in_sizemove > 0)
+               break;
+
+           if( !isfullscreen() && hAmigaWnd )
+           {
+               static int store_xy;
+               RECT rc2;
+               if( GetWindowRect( hMainWnd, &rc2 )) {
+                   if (amigawin_rect.left & 3)
+                   {
+                       MoveWindow (hMainWnd, rc2.left+ 4 - amigawin_rect.left % 4, rc2.top,
+                                   rc2.right - rc2.left, rc2.bottom - rc2.top, TRUE);
+
+                   }
+                   if( hWinUAEKey && store_xy++)
+                   {
+                       DWORD left = rc2.left - win_x_diff;
+                       DWORD top = rc2.top - win_y_diff;
+                       RegSetValueEx( hWinUAEKey, "xPos", 0, REG_DWORD, (LPBYTE)&left, sizeof( LONG ) );
+                       RegSetValueEx( hWinUAEKey, "yPos", 0, REG_DWORD, (LPBYTE)&top, sizeof( LONG ) );
+                   }
+               }
+               return 0;
+           }
+       }
+       break;
+
+     case WM_PAINT:
+       hDC = BeginPaint (hWnd, &ps);
+       GetClientRect (hWnd, &rc);
+       DrawEdge (hDC, &rc, EDGE_SUNKEN, BF_RECT);
+       EndPaint (hWnd, &ps);
+       break;
+
+     case WM_NCLBUTTONDBLCLK:
+       if (wParam == HTCAPTION) {
+           WIN32GFX_ToggleFullScreen();
+           return 0;
+       }
+       break;
+
+
+    default:
+       if (TaskbarRestartOk && message == TaskbarRestart)
+           return AmigaWindowProc (hWnd, message, wParam, lParam);
+       break;
+
+    }
+
+    return DefWindowProc (hWnd, message, wParam, lParam);
+}
+
+void handle_events (void)
+{
+    MSG msg;
+    int was_paused = 0;
+
+    while (emulation_paused > 0 || pause_emulation) {
+       if ((emulation_paused > 0 || pause_emulation) && was_paused == 0) {
+           close_sound ();
+#ifdef AHI
+           ahi_close_sound ();
+#endif
+           was_paused = 1;
+           manual_painting_needed++;
+       }
+       if (PeekMessage (&msg, 0, 0, 0, PM_REMOVE)) {
+            TranslateMessage (&msg);
+           DispatchMessage (&msg);
+       }
+       sleep_millis (50);
+       inputdevicefunc_keyboard.read();
+       inputdevicefunc_mouse.read();
+       inputdevicefunc_joystick.read();
+    }
+    while (PeekMessage (&msg, 0, 0, 0, PM_REMOVE)) {
+        TranslateMessage (&msg);
+        DispatchMessage (&msg);
+    }
+    if (was_paused) {
+       init_sound ();
+#ifdef AHI
+        ahi_open_sound ();
+#endif
+       emulation_paused = 0;
+       manual_painting_needed--;
+    }
+
+}
+
+/* We're not a console-app anymore! */
+void setup_brkhandler (void)
+{
+}
+void remove_brkhandler (void)
+{
+}
+
+int WIN32_RegisterClasses( void )
+{
+    WNDCLASS wc;
+    HDC hDC = GetDC( NULL ); 
+
+    if( GetDeviceCaps( hDC, NUMCOLORS ) != -1 ) 
+        g_dwBackgroundColor = RGB( 255, 0, 255 );    
+    ReleaseDC( NULL, hDC );
+
+    wc.style = CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW | CS_DBLCLKS | CS_OWNDC;
+    wc.lpfnWndProc = AmigaWindowProc;
+    wc.cbClsExtra = 0;
+    wc.cbWndExtra = 0;
+    wc.hInstance = 0;
+    wc.hIcon = LoadIcon (GetModuleHandle (NULL), MAKEINTRESOURCE( IDI_APPICON ) );
+    wc.hCursor = LoadCursor (NULL, IDC_ARROW);
+    wc.lpszMenuName = 0;
+    wc.lpszClassName = "AmigaPowah";
+    wc.hbrBackground = CreateSolidBrush( g_dwBackgroundColor ); 
+    if (!RegisterClass (&wc))
+       return 0;
+
+    wc.style = CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
+    wc.lpfnWndProc = MainWindowProc;
+    wc.cbClsExtra = 0;
+    wc.cbWndExtra = 0;
+    wc.hInstance = 0;
+    wc.hIcon = LoadIcon (GetModuleHandle (NULL), MAKEINTRESOURCE( IDI_APPICON ) );
+    wc.hCursor = LoadCursor (NULL, IDC_ARROW);
+    wc.hbrBackground = CreateSolidBrush( g_dwBackgroundColor ); 
+    wc.lpszMenuName = 0;
+    wc.lpszClassName = "PCsuxRox";
+    if (!RegisterClass (&wc))
+       return 0;
+    return 1;
+}
+
+#ifdef __GNUC__
+#undef WINAPI
+#define WINAPI
+#endif
+
+static HINSTANCE hRichEdit = NULL, hHtmlHelp = NULL;
+
+int WIN32_CleanupLibraries( void )
+{
+    if (hRichEdit)
+       FreeLibrary (hRichEdit);
+    
+    if( hHtmlHelp )
+        FreeLibrary( hHtmlHelp );
+
+    if( hUIDLL )
+       FreeLibrary( hUIDLL );
+
+    return 1;
+}
+
+/* HtmlHelp Initialization - optional component */
+int WIN32_InitHtmlHelp( void )
+{
+    int result = 0;
+    if (zfile_exists (help_file)) {
+        if( hHtmlHelp = LoadLibrary( "HHCTRL.OCX" ) )
+       {
+           pHtmlHelp = ( HWND(WINAPI *)(HWND, LPCSTR, UINT, LPDWORD ) )GetProcAddress( hHtmlHelp, "HtmlHelpA" );
+           result = 1;
+       }
+    }
+    return result;
+}
+
+#if 0
+#define TESTING_LANGUAGES
+#define TEST_LANGID LANG_GERMAN
+//#define TEST_LANGID LANG_FRENCH
+//#define TEST_LANGID LANG_TURKISH
+#endif
+
+static HMODULE LoadGUI( void )
+{
+    HMODULE result = NULL;
+    LPCTSTR dllname = NULL;
+    LANGID language = GetUserDefaultLangID() & 0x3FF; // low 9-bits form the primary-language ID
+#ifdef TESTING_LANGUAGES
+    language = TEST_LANGID;
+#endif
+
+    switch( language )
+    {
+    case LANG_AFRIKAANS:
+       dllname = "WinUAE_Afrikaans.dll";
+       break;
+    case LANG_ARABIC:
+       dllname = "WinUAE_Arabic.dll";
+       break;
+    case LANG_ARMENIAN:
+       dllname = "WinUAE_Armenian.dll";
+       break;
+    case LANG_ASSAMESE:
+       dllname = "WinUAE_Assamese.dll";
+       break;
+    case LANG_AZERI:
+       dllname = "WinUAE_Azeri.dll";
+       break;
+    case LANG_BASQUE:
+       dllname = "WinUAE_Basque.dll";
+       break;
+    case LANG_BELARUSIAN:
+       dllname = "WinUAE_Belarusian.dll";
+       break;
+    case LANG_BENGALI:
+       dllname = "WinUAE_Bengali.dll";
+       break;
+    case LANG_BULGARIAN:
+       dllname = "WinUAE_Bulgarian.dll";
+       break;
+    case LANG_CATALAN:
+       dllname = "WinUAE_Catalan.dll";
+       break;
+    case LANG_CHINESE:
+       dllname = "WinUAE_Chinese.dll";
+       break;
+    case LANG_CROATIAN:
+       dllname = "WinUAE_CroatianSerbian.dll";
+       break;
+    case LANG_CZECH:
+       dllname = "WinUAE_Czech.dll";
+       break;
+    case LANG_DANISH:
+       dllname = "WinUAE_Danish.dll";
+       break;
+    case LANG_DUTCH:
+       dllname = "WinUAE_Dutch.dll";
+       break;
+    case LANG_ESTONIAN:
+       dllname = "WinUAE_Estonian.dll";
+       break;
+    case LANG_FAEROESE:
+       dllname = "WinUAE_Faeroese.dll";
+       break;
+    case LANG_FARSI:
+       dllname = "WinUAE_Farsi.dll";
+       break;
+    case LANG_FINNISH:
+       dllname = "WinUAE_Finnish.dll";
+       break;
+    case LANG_FRENCH:
+       dllname = "WinUAE_French.dll";
+       break;
+    case LANG_GEORGIAN:
+       dllname = "WinUAE_Georgian.dll";
+       break;
+    case LANG_GERMAN:
+       dllname = "WinUAE_German.dll";
+       break;
+    case LANG_GREEK:
+       dllname = "WinUAE_Greek.dll";
+       break;
+    case LANG_GUJARATI:
+       dllname = "WinUAE_Gujarati.dll";
+       break;
+    case LANG_HEBREW:
+       dllname = "WinUAE_Hebrew.dll";
+       break;
+    case LANG_HINDI:
+       dllname = "WinUAE_Hindi.dll";
+       break;
+    case LANG_HUNGARIAN:
+       dllname = "WinUAE_Hungarian.dll";
+       break;
+    case LANG_ICELANDIC:
+       dllname = "WinUAE_Icelandic.dll";
+       break;
+    case LANG_INDONESIAN:
+       dllname = "WinUAE_Indonesian.dll";
+       break;
+    case LANG_ITALIAN:
+       dllname = "WinUAE_Italian.dll";
+       break;
+    case LANG_JAPANESE:
+       dllname = "WinUAE_Japanese.dll";
+       break;
+    case LANG_KANNADA:
+       dllname = "WinUAE_Kannada.dll";
+       break;
+    case LANG_KASHMIRI:
+       dllname = "WinUAE_Kashmiri.dll";
+       break;
+    case LANG_KAZAK:
+       dllname = "WinUAE_Kazak.dll";
+       break;
+    case LANG_KONKANI:
+       dllname = "WinUAE_Konkani.dll";
+       break;
+    case LANG_KOREAN:
+       dllname = "WinUAE_Korean.dll";
+       break;
+    case LANG_LATVIAN:
+       dllname = "WinUAE_Latvian.dll";
+       break;
+    case LANG_LITHUANIAN:
+       dllname = "WinUAE_Lithuanian.dll";
+       break;
+    case LANG_MACEDONIAN:
+       dllname = "WinUAE_Macedonian.dll";
+       break;
+    case LANG_MALAY:
+       dllname = "WinUAE_Malay.dll";
+       break;
+    case LANG_MALAYALAM:
+       dllname = "WinUAE_Malayalam.dll";
+       break;
+    case LANG_MANIPURI:
+       dllname = "WinUAE_Manipuri.dll";
+       break;
+    case LANG_MARATHI:
+       dllname = "WinUAE_Marathi.dll";
+       break;
+    case LANG_NEPALI:
+       dllname = "WinUAE_Nepali.dll";
+       break;
+    case LANG_NORWEGIAN:
+       dllname = "WinUAE_Norwegian.dll";
+       break;
+    case LANG_ORIYA:
+       dllname = "WinUAE_Oriya.dll";
+       break;
+    case LANG_POLISH:
+       dllname = "WinUAE_Polish.dll";
+       break;
+    case LANG_PORTUGUESE:
+       dllname = "WinUAE_Portuguese.dll";
+       break;
+    case LANG_PUNJABI:
+       dllname = "WinUAE_Punjabi.dll";
+       break;
+    case LANG_ROMANIAN:
+       dllname = "WinUAE_Romanian.dll";
+       break;
+    case LANG_RUSSIAN:
+       dllname = "WinUAE_Russian.dll";
+       break;
+    case LANG_SANSKRIT:
+       dllname = "WinUAE_Sanskrit.dll";
+       break;
+    case LANG_SINDHI:
+       dllname = "WinUAE_Sindhi.dll";
+       break;
+    case LANG_SLOVAK:
+       dllname = "WinUAE_Slovak.dll";
+       break;
+    case LANG_SLOVENIAN:
+       dllname = "WinUAE_Slovenian.dll";
+       break;
+    case LANG_SPANISH:
+       dllname = "WinUAE_Spanish.dll";
+       break;
+    case LANG_SWAHILI:
+       dllname = "WinUAE_Swahili.dll";
+       break;
+    case LANG_SWEDISH:
+       dllname = "WinUAE_Swedish.dll";
+       break;
+    case LANG_TAMIL:
+       dllname = "WinUAE_Tamil.dll";
+       break;
+    case LANG_TATAR:
+       dllname = "WinUAE_Tatar.dll";
+       break;
+    case LANG_TELUGU:
+       dllname = "WinUAE_Telugu.dll";
+       break;
+    case LANG_THAI:
+       dllname = "WinUAE_Thai.dll";
+       break;
+    case LANG_TURKISH:
+       dllname = "WinUAE_Turkish.dll";
+       break;
+    case LANG_UKRAINIAN:
+       dllname = "WinUAE_Ukrainian.dll";
+       break;
+    case LANG_URDU:
+       dllname = "WinUAE_Urdu.dll";
+       break;
+    case LANG_UZBEK:
+       dllname = "WinUAE_Uzbek.dll";
+       break;
+    case LANG_VIETNAMESE:
+       dllname = "WinUAE_Vietnamese.dll";
+       break;
+    case 0x400:
+       dllname = "guidll.dll";
+       break;
+    }
+
+    if( dllname )
+    {
+       TCHAR  szFilename[ MAX_PATH ];
+       DWORD  dwVersionHandle, dwFileVersionInfoSize;
+       LPVOID lpFileVersionData = NULL;
+       BOOL   success = FALSE;
+       result = LoadLibrary( dllname );
+       if( result && GetModuleFileName( result, (LPTSTR)&szFilename, MAX_PATH ) )
+       {
+           dwFileVersionInfoSize = GetFileVersionInfoSize( szFilename, &dwVersionHandle );
+           if( dwFileVersionInfoSize )
+           {
+               if( lpFileVersionData = calloc( 1, dwFileVersionInfoSize ) )
+               {
+                   if( GetFileVersionInfo( szFilename, dwVersionHandle, dwFileVersionInfoSize, lpFileVersionData ) )
+                   {
+                       VS_FIXEDFILEINFO *vsFileInfo = NULL;
+                       UINT uLen;
+                       if( VerQueryValue( lpFileVersionData, TEXT("\\"), (void **)&vsFileInfo, &uLen ) )
+                       {
+                           if( vsFileInfo &&
+                               ( HIWORD(vsFileInfo->dwProductVersionMS) == UAEMAJOR ) 
+                               && ( LOWORD(vsFileInfo->dwProductVersionMS) == UAEMINOR ) 
+                               && ( HIWORD(vsFileInfo->dwProductVersionLS) == UAESUBREV )
+// Change this to an #if 1 when the WinUAE Release version (as opposed to UAE-core version) 
+// requires a GUI-DLL change...
+#if 0
+                               && ( LOWORD(vsFileInfo->dwProductVersionLS) == WINUAERELEASE) 
+#endif
+                               )
+                           {
+                               success = TRUE;
+                               write_log ("Translation DLL '%s' loaded and used\n", dllname);
+                           }
+                       }
+                   }
+                   free( lpFileVersionData );
+               }
+           }
+       }
+       if( result && !success )
+       {
+           FreeLibrary( result );
+           result = NULL;
+       }
+    }
+
+    return result;
+}
+
+
+/* try to load COMDLG32 and DDRAW, initialize csDraw */
+int WIN32_InitLibraries( void )
+{
+    int result = 1;
+    /* Determine our processor speed and capabilities */
+    if (!figure_processor_speed())
+       return 0;
+    
+    /* Make sure we do an InitCommonControls() to get some advanced controls */
+    InitCommonControls();
+    
+    hRichEdit = LoadLibrary( "RICHED32.DLL" );
+    
+    hUIDLL = LoadGUI();
+
+    return result;
+}
+
+int debuggable (void)
+{
+    return 0;
+}
+
+int needmousehack (void)
+{
+    return 1;
+}
+
+void LED (int a)
+{
+}
+
+void logging_init( void )
+{
+    static int started;
+    static int first;
+    char debugfilename[MAX_PATH];
+
+    if (first > 1) {
+       write_log ("** RESTART **\n");
+       return;
+    }
+    if (first == 1) {
+       if (debugfile)
+           fclose (debugfile);
+        debugfile = 0;
+    }
+#ifndef SINGLEFILE
+    if( currprefs.win32_logfile ) {
+       sprintf( debugfilename, "%swinuaelog.txt", start_path );
+       if( !debugfile )
+           debugfile = fopen( debugfilename, "wt" );
+    } else if (!first) {
+       sprintf( debugfilename, "%swinuaebootlog.txt", start_path );
+       if( !debugfile )
+           debugfile = fopen( debugfilename, "wt" );
+    }
+#endif
+    first++;
+    write_log ( "%s", VersionStr );
+    write_log (" (OS: %s %d.%d%s)", os_winnt ? "NT" : "W9X/ME", osVersion.dwMajorVersion, osVersion.dwMinorVersion, os_winnt_admin ? " Administrator privileges" : "");
+    write_log ("\n(c) 1995-2001 Bernd Schmidt   - Core UAE concept and implementation."
+              "\n(c) 1998-2004 Toni Wilen      - Win32 port, core code updates."
+              "\n(c) 1996-2001 Brian King      - Win32 port, Picasso96 RTG, and GUI."
+              "\n(c) 1996-1999 Mathias Ortmann - Win32 port and bsdsocket support."
+              "\n(c) 2000-2001 Bernd Meyer     - JIT engine."
+              "\n(c) 2000-2001 Bernd Roesch    - MIDI input, many fixes."
+              "\nPress F12 to show the Settings Dialog (GUI), Alt-F4 to quit."
+              "\nEnd+F1 changes floppy 0, End+F2 changes floppy 1, etc."
+              "\n");
+}
+
+void logging_cleanup( void )
+{
+    if( debugfile )
+        fclose( debugfile );
+    debugfile = 0;
+}
+
+void target_default_options (struct uae_prefs *p)
+{
+    p->win32_middle_mouse = 0;
+    p->win32_logfile = 0;
+    p->win32_iconified_nosound = 0;
+    p->win32_iconified_pause = 0;
+    p->win32_inactive_nosound = 0;
+    p->win32_inactive_pause = 0;
+    p->win32_no_overlay = 0;
+    p->win32_ctrl_F11_is_quit = 0;
+    p->win32_soundcard = 0;
+    p->win32_active_priority = 1;
+    p->win32_inactive_priority = 2;
+    p->win32_iconified_priority = 3;
+}
+
+void target_save_options (FILE *f, struct uae_prefs *p)
+{
+    cfgfile_write (f, "win32.middle_mouse=%s\n", p->win32_middle_mouse ? "true" : "false");
+    cfgfile_write (f, "win32.logfile=%s\n", p->win32_logfile ? "true" : "false");
+    cfgfile_write (f, "win32.map_drives=%s\n", p->win32_automount_drives ? "true" : "false" );
+    cfgfile_write (f, "win32.serial_port=%s\n", p->use_serial ? p->sername : "none" );
+    cfgfile_write (f, "win32.parallel_port=%s\n", p->prtname[0] ? p->prtname : "none" );
+
+    cfgfile_write (f, "win32.active_priority=%d\n", priorities[p->win32_active_priority].value);
+    cfgfile_write (f, "win32.inactive_priority=%d\n", priorities[p->win32_inactive_priority].value);
+    cfgfile_write (f, "win32.inactive_nosound=%s\n", p->win32_inactive_nosound ? "true" : "false");
+    cfgfile_write (f, "win32.inactive_pause=%s\n", p->win32_inactive_pause ? "true" : "false");
+    cfgfile_write (f, "win32.iconified_priority=%d\n", priorities[p->win32_iconified_priority].value);
+    cfgfile_write (f, "win32.iconified_nosound=%s\n", p->win32_iconified_nosound ? "true" : "false");
+    cfgfile_write (f, "win32.iconified_pause=%s\n", p->win32_iconified_pause ? "true" : "false");
+
+    cfgfile_write (f, "win32.ctrl_f11_is_quit=%s\n", p->win32_ctrl_F11_is_quit ? "true" : "false");
+    cfgfile_write (f, "win32.midiout_device=%d\n", p->win32_midioutdev );
+    cfgfile_write (f, "win32.midiin_device=%d\n", p->win32_midiindev );
+    cfgfile_write (f, "win32.no_overlay=%s\n", p->win32_no_overlay ? "true" : "false" );
+    cfgfile_write (f, "win32.aspi=%s\n", p->win32_aspi ? "true" : "false" );
+    cfgfile_write (f, "win32.soundcard=%d\n", p->win32_soundcard );
+    cfgfile_write (f, "win32.cpu_idle=%d\n", p->cpu_idle);
+}
+
+static int fetchpri (int pri, int defpri)
+{
+    int i = 0;
+    while (priorities[i].name) {
+        if (priorities[i].value == pri)
+           return i;
+        i++;
+    }
+    return defpri;
+}
+
+static const char *obsolete[] = {
+    "killwinkeys", "sound_force_primary", "iconified_highpriority",
+    "sound_sync", "sound_tweak", "directx6", "sound_style",
+    "file_path", "iconified_nospeed", "activepriority", 
+    0
+};
+
+
+int target_parse_option (struct uae_prefs *p, char *option, char *value)
+{
+    int i, v;
+    int result = (cfgfile_yesno (option, value, "middle_mouse", &p->win32_middle_mouse)
+           || cfgfile_yesno (option, value, "logfile", &p->win32_logfile)
+           || cfgfile_yesno  (option, value, "networking", &p->socket_emu)
+           || cfgfile_yesno (option, value, "no_overlay", &p->win32_no_overlay)
+           || cfgfile_yesno (option, value, "aspi", &p->win32_aspi)
+           || cfgfile_yesno  (option, value, "map_drives", &p->win32_automount_drives)
+           || cfgfile_yesno (option, value, "inactive_pause", &p->win32_inactive_pause)
+           || cfgfile_yesno (option, value, "inactive_nosound", &p->win32_inactive_nosound)
+           || cfgfile_yesno (option, value, "iconified_pause", &p->win32_iconified_pause)
+           || cfgfile_yesno (option, value, "iconified_nosound", &p->win32_iconified_nosound)
+           || cfgfile_yesno  (option, value, "ctrl_f11_is_quit", &p->win32_ctrl_F11_is_quit)
+           || cfgfile_intval (option, value, "midi_device", &p->win32_midioutdev, 1)
+           || cfgfile_intval (option, value, "midiout_device", &p->win32_midioutdev, 1)
+           || cfgfile_intval (option, value, "midiin_device", &p->win32_midiindev, 1)
+           || cfgfile_intval (option, value, "soundcard", &p->win32_soundcard, 1)
+           || cfgfile_string (option, value, "serial_port", &p->sername[0], 256)
+           || cfgfile_string (option, value, "parallel_port", &p->prtname[0], 256)
+           || cfgfile_intval  (option, value, "cpu_idle", &p->cpu_idle, 1));
+
+    if (cfgfile_intval (option, value, "active_priority", &v, 1)) {
+       p->win32_active_priority = fetchpri (v, 1);
+       return 1;
+    }
+    if (cfgfile_intval (option, value, "activepriority", &v, 1)) {
+       p->win32_active_priority = fetchpri (v, 1);
+       return 1;
+    }
+    if (cfgfile_intval (option, value, "inactive_priority", &v, 1)) {
+       p->win32_inactive_priority = fetchpri (v, 2);
+       return 1;
+    }
+    if (cfgfile_intval (option, value, "iconified_priority", &v, 1)) {
+       p->win32_iconified_priority = fetchpri (v, 3);
+       return 1;
+    }
+
+    v = -1;
+    if (cfgfile_yesno (option, value, "cpu_idle", &v)) {
+       if (v == 1)
+            p->cpu_idle = 60;
+    }
+
+    if (p->sername[0] == 'n')
+       p->use_serial = 0;
+    else
+       p->use_serial = 1;
+
+    i = 0;
+    while (obsolete[i]) {
+       if (!strcasecmp (obsolete[i], option)) {
+           write_log ("obsolete config entry '%s'\n", option);
+           return 1;
+       }
+       i++;
+    }
+
+    return result;
+}
+
+static void WIN32_HandleRegistryStuff( void )
+{
+    RGBFTYPE colortype      = RGBFB_NONE;
+    DWORD dwType            = REG_DWORD;
+    DWORD dwDisplayInfoSize = sizeof( colortype );
+    DWORD disposition;
+    char path[MAX_PATH] = "";
+    HKEY hWinUAEKeyLocal = NULL;
+
+    /* Create/Open the hWinUAEKey which points to our config-info */
+    if( RegCreateKeyEx( HKEY_CLASSES_ROOT, ".uae", 0, "", REG_OPTION_NON_VOLATILE,
+                          KEY_ALL_ACCESS, NULL, &hWinUAEKey, &disposition ) == ERROR_SUCCESS )
+    {
+       // Regardless of opening the existing key, or creating a new key, we will write the .uae filename-extension
+       // commands in.  This way, we're always up to date.
+
+        /* Set our (default) sub-key to point to the "WinUAE" key, which we then create */
+        RegSetValueEx( hWinUAEKey, "", 0, REG_SZ, (CONST BYTE *)"WinUAE", strlen( "WinUAE" ) + 1 );
+
+        if( ( RegCreateKeyEx( HKEY_CLASSES_ROOT, "WinUAE\\shell\\Edit\\command", 0, "", REG_OPTION_NON_VOLATILE,
+                              KEY_ALL_ACCESS, NULL, &hWinUAEKeyLocal, &disposition ) == ERROR_SUCCESS ) )
+        {
+            /* Set our (default) sub-key to BE the "WinUAE" command for editing a configuration */
+            sprintf( path, "%sWinUAE.exe -f \"%%1\" -s use_gui=yes", start_path );
+            RegSetValueEx( hWinUAEKeyLocal, "", 0, REG_SZ, (CONST BYTE *)path, strlen( path ) + 1 );
+        }
+               RegCloseKey( hWinUAEKeyLocal );
+
+        if( ( RegCreateKeyEx( HKEY_CLASSES_ROOT, "WinUAE\\shell\\Open\\command", 0, "", REG_OPTION_NON_VOLATILE,
+                              KEY_ALL_ACCESS, NULL, &hWinUAEKeyLocal, &disposition ) == ERROR_SUCCESS ) )
+        {
+            /* Set our (default) sub-key to BE the "WinUAE" command for launching a configuration */
+            sprintf( path, "%sWinUAE.exe -f \"%%1\"", start_path );
+            RegSetValueEx( hWinUAEKeyLocal, "", 0, REG_SZ, (CONST BYTE *)path, strlen( path ) + 1 );
+        }
+       RegCloseKey( hWinUAEKeyLocal );
+    }
+    RegCloseKey( hWinUAEKey );
+
+    /* Create/Open the hWinUAEKey which points our config-info */
+    if( RegCreateKeyEx( HKEY_CURRENT_USER, "Software\\Arabuusimiehet\\WinUAE", 0, "", REG_OPTION_NON_VOLATILE,
+                          KEY_ALL_ACCESS, NULL, &hWinUAEKey, &disposition ) == ERROR_SUCCESS )
+    {
+        if( disposition == REG_CREATED_NEW_KEY )
+        {
+            /* Create and initialize all our sub-keys to the default values */
+            colortype = 0;
+            RegSetValueEx( hWinUAEKey, "DisplayInfo", 0, REG_DWORD, (CONST BYTE *)&colortype, sizeof( colortype ) );
+            RegSetValueEx( hWinUAEKey, "xPos", 0, REG_DWORD, (CONST BYTE *)&colortype, sizeof( colortype ) );
+            RegSetValueEx( hWinUAEKey, "yPos", 0, REG_DWORD, (CONST BYTE *)&colortype, sizeof( colortype ) );
+            RegSetValueEx( hWinUAEKey, "xPosGUI", 0, REG_DWORD, (CONST BYTE *)&colortype, sizeof( colortype ) );
+            RegSetValueEx( hWinUAEKey, "yPosGUI", 0, REG_DWORD, (CONST BYTE *)&colortype, sizeof( colortype ) );
+            RegSetValueEx( hWinUAEKey, "FloppyPath", 0, REG_SZ, (CONST BYTE *)start_path, strlen( start_path ) + 1 );
+            RegSetValueEx( hWinUAEKey, "KickstartPath", 0, REG_SZ, (CONST BYTE *)start_path, strlen( start_path ) + 1 );
+            RegSetValueEx( hWinUAEKey, "hdfPath", 0, REG_SZ, (CONST BYTE *)start_path, strlen( start_path ) + 1 );
+        }
+       // Set this even when we're opening an existing key, so that the version info is always up to date.
+        RegSetValueEx( hWinUAEKey, "Version", 0, REG_SZ, (CONST BYTE *)VersionStr, strlen( VersionStr ) + 1 );
+        
+               RegQueryValueEx( hWinUAEKey, "DisplayInfo", 0, &dwType, (LPBYTE)&colortype, &dwDisplayInfoSize );
+               if( colortype == 0 ) /* No color information stored in the registry yet */
+               {
+                       char szMessage[ 4096 ];
+                       char szTitle[ MAX_PATH ];
+                       WIN32GUI_LoadUIString( IDS_GFXCARDCHECK, szMessage, 4096 );
+                       WIN32GUI_LoadUIString( IDS_GFXCARDTITLE, szTitle, MAX_PATH );
+                   
+                       if( MessageBox( NULL, szMessage, szTitle, 
+                       MB_YESNO | MB_ICONWARNING | MB_TASKMODAL | MB_SETFOREGROUND ) == IDYES )
+                       {
+                       ignore_messages_all++;
+                       colortype = WIN32GFX_FigurePixelFormats(0);
+                       ignore_messages_all--;
+                       RegSetValueEx( hWinUAEKey, "DisplayInfo", 0, REG_DWORD, (CONST BYTE *)&colortype, sizeof( colortype ) );
+                       }
+               }
+               if( colortype ) {
+                       /* Set the 16-bit pixel format for the appropriate modes */
+                       WIN32GFX_FigurePixelFormats( colortype );
+               }
+       }
+}
+
+static void betamessage (void)
+{
+}
+
+static void init_zlib (void)
+{
+    HMODULE h = LoadLibrary ("zlib1.dll");
+    if (h) {
+       is_zlib = 1;
+       FreeLibrary(h);
+    } else {
+       write_log ("zlib1.dll not found, gzip/zip support disabled\n");
+    }
+}
+
+static int dxdetect (void)
+{
+    /* believe or not but this is MS supported way of detecting DX8+ */
+    HMODULE h = LoadLibrary("D3D8.DLL");
+    char szWrongDXVersion[ MAX_PATH ];
+    if (h) {
+       FreeLibrary (h);
+       return 1;
+    }
+    WIN32GUI_LoadUIString( IDS_WRONGDXVERSION, szWrongDXVersion, MAX_PATH );
+    pre_gui_message( szWrongDXVersion );
+    return 0;
+}
+
+int os_winnt, os_winnt_admin;
+
+static int osdetect (void)
+{
+    HANDLE hAccessToken;
+    UCHAR InfoBuffer[1024];
+    PTOKEN_GROUPS ptgGroups = (PTOKEN_GROUPS)InfoBuffer;
+    DWORD dwInfoBufferSize;
+    PSID psidAdministrators;
+    SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
+    UINT x;
+    BOOL bSuccess;
+
+    os_winnt = 0;
+    os_winnt_admin = 0;
+
+    osVersion.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
+    if( GetVersionEx( &osVersion ) )
+    {
+       if( ( osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT ) &&
+           ( osVersion.dwMajorVersion <= 4 ) )
+       {
+           /* WinUAE not supported on this version of Windows... */
+           char szWrongOSVersion[ MAX_PATH ];
+           WIN32GUI_LoadUIString( IDS_WRONGOSVERSION, szWrongOSVersion, MAX_PATH );
+           pre_gui_message( szWrongOSVersion );
+           return FALSE;
+       }
+       if (osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT)
+           os_winnt = 1;
+    }
+
+    if (!os_winnt) {
+       return 1;
+    }
+
+    if(!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE,
+         &hAccessToken )) {
+         if(GetLastError() != ERROR_NO_TOKEN)
+            return 1;
+         // 
+         // retry against process token if no thread token exists
+         // 
+         if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY,
+            &hAccessToken))
+            return 1;
+      }
+
+      bSuccess = GetTokenInformation(hAccessToken,TokenGroups,InfoBuffer,
+         1024, &dwInfoBufferSize);
+
+      CloseHandle(hAccessToken);
+
+      if(!bSuccess )
+         return 1;
+
+      if(!AllocateAndInitializeSid(&siaNtAuthority, 2,
+         SECURITY_BUILTIN_DOMAIN_RID,
+         DOMAIN_ALIAS_RID_ADMINS,
+         0, 0, 0, 0, 0, 0,
+         &psidAdministrators))
+         return 1;
+
+   // assume that we don't find the admin SID.
+      bSuccess = FALSE;
+
+      for(x=0;x<ptgGroups->GroupCount;x++)
+      {
+         if( EqualSid(psidAdministrators, ptgGroups->Groups[x].Sid) )
+         {
+            bSuccess = TRUE;
+            break;
+         }
+
+      }
+      FreeSid(psidAdministrators);
+      os_winnt_admin = bSuccess ? 1 : 0;
+      return 1;
+   }
+
+
+static int PASCAL WinMain2 (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
+                   int nCmdShow)
+{
+    char *posn;
+    HANDLE hMutex;
+    char **argv;
+    int argc;
+    int i;
+    char tmp[2000];
+
+#ifdef __GNUC__
+    __asm__ ("leal -2300*1024(%%esp),%0" : "=r" (win32_stackbase) :);
+#else
+__asm{
+    mov eax,esp
+    sub eax,2300*1024
+    mov win32_stackbase,eax
+ }
+#endif
+
+#ifdef _DEBUG
+    {
+       int tmp = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
+       tmp |= _CRTDBG_CHECK_ALWAYS_DF;
+       tmp |= _CRTDBG_CHECK_CRT_DF;
+       //tmp |= _CRTDBG_DELAY_FREE_MEM_DF;
+       _CrtSetDbgFlag(tmp);
+    }
+#endif
+
+    if (!osdetect())
+       return 0;
+    if (!dxdetect())
+       return 0;
+
+    hInst = hInstance;
+    hMutex = CreateMutex( NULL, FALSE, "WinUAE Instantiated" ); // To tell the installer we're running
+#ifdef AVIOUTPUT
+    AVIOutput_Initialize();
+#endif
+
+#ifdef __MINGW32__
+    argc = _argc; argv = _argv;
+#else
+    argc = __argc; argv = __argv;
+#endif
+    for (i = 1; i < argc; i++) {
+       char *arg = argv[i];
+       if (!strcmp (arg, "-log")) console_logging = 1;
+#ifdef FILESYS
+       if (!strcmp (arg, "-rdbdump")) do_rdbdump = 1;
+       if (!strcmp (arg, "-disableharddrivesafetycheck")) harddrive_dangerous = 0x1234dead;
+       if (!strcmp (arg, "-noaspifiltering")) aspi_allow_all = 1;
+#endif
+       if (!strcmp (arg, "-dsaudiomix")) dsound_hardware_mixing = 1;
+       if (!strcmp (arg, "-nordtsc")) no_rdtsc = 1;
+       if (!strcmp (arg, "-forcerdtsc")) no_rdtsc = -1;
+       if (!strcmp (arg, "-norawinput")) no_rawinput = 1;
+       if (!strcmp (arg, "-scsilog")) log_scsi = 1;
+    }
+#if 0
+    argv = 0;
+    argv[0] = 0;
+#endif
+    /* Get our executable's root-path */
+    if( ( start_path = xmalloc( MAX_PATH ) ) )
+    {
+       GetModuleFileName( NULL, start_path, MAX_PATH );
+       if((posn = strrchr (start_path, '\\')))
+           posn[1] = 0;
+       sprintf (help_file, "%sWinUAE.chm", start_path );
+#ifndef SINGLEFILE
+       sprintf (tmp, "%sSaveStates", start_path);
+       CreateDirectory (tmp, NULL);
+       strcat (tmp, "\\default.uss");
+       strcpy (savestate_fname, tmp);
+       sprintf (tmp, "%sSaveImages", start_path);
+       CreateDirectory (tmp, NULL);
+       sprintf (tmp, "%sScreenShots", start_path);
+       CreateDirectory (tmp, NULL);
+#endif
+       sprintf( VersionStr, "WinUAE %d.%d.%d%s", UAEMAJOR, UAEMINOR, UAESUBREV, WINUAEBETA ? WINUAEBETASTR : "" );
+
+       logging_init ();
+
+       if( WIN32_RegisterClasses() && WIN32_InitLibraries() && DirectDraw_Start(NULL) )
+       {
+           struct foo {
+               DEVMODE actual_devmode;
+               char overrun[8];
+           } devmode;
+
+           DWORD i = 0;
+
+           DirectDraw_Release ();
+           write_log ("Enumerating display devices.. \n");
+           DirectDraw_EnumDisplays (displaysCallback);
+           write_log ("Sorting devices and modes..\n");
+           sortdisplays ();
+           write_log ("done\n");
+           
+           memset( &devmode, 0, sizeof(DEVMODE) + 8 );
+           devmode.actual_devmode.dmSize = sizeof(DEVMODE);
+           devmode.actual_devmode.dmDriverExtra = 8;
+#define ENUM_CURRENT_SETTINGS ((DWORD)-1)
+           if( EnumDisplaySettings( NULL, ENUM_CURRENT_SETTINGS, (LPDEVMODE)&devmode ) )
+           {
+               default_freq = devmode.actual_devmode.dmDisplayFrequency;
+               if( default_freq >= 70 )
+                   default_freq = 70;
+               else
+                   default_freq = 60;
+           }
+
+           WIN32_HandleRegistryStuff();
+           WIN32_InitHtmlHelp();
+           DirectDraw_Release();
+           betamessage ();
+           keyboard_settrans ();
+           init_zlib ();
+#ifdef PARALLEL_PORT
+           paraport_mask = paraport_init ();
+#endif
+           real_main (argc, argv);
+       }
+       free( start_path );
+    }
+       
+    if (mm_timerres && timermode == 0)
+       timeend ();
+#ifdef AVIOUTPUT
+    AVIOutput_Release ();
+#endif
+#ifdef AHI
+    ahi_close_sound ();
+#endif
+#ifdef PARALLEL_PORT
+    paraport_free ();
+    flushprinter ();
+    closeprinter ();
+#endif
+    WIN32_CleanupLibraries();
+    _fcloseall();
+    if( hWinUAEKey )
+       RegCloseKey( hWinUAEKey );
+    CloseHandle( hMutex );
+#ifdef _DEBUG
+    // show memory leaks
+    //_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
+#endif
+    return FALSE;
+}
+
+int execute_command (char *cmd)
+{
+    STARTUPINFO si;
+    PROCESS_INFORMATION pi;
+
+    memset (&si, 0, sizeof (si));
+    si.cb = sizeof (si);
+    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+    si.wShowWindow = SW_HIDE;
+    if( CreateProcess( NULL, cmd, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi ) )  {
+       WaitForSingleObject( pi.hProcess, INFINITE );
+       return 1;
+    }
+    return 0;
+}
+
+struct threadpriorities priorities[] = {
+    { "Highest", THREAD_PRIORITY_HIGHEST },
+    { "Above Normal", THREAD_PRIORITY_ABOVE_NORMAL },
+    { "Normal", THREAD_PRIORITY_NORMAL },
+    { "Below Normal", THREAD_PRIORITY_BELOW_NORMAL },
+    { "Low", THREAD_PRIORITY_LOWEST },
+    { 0, -1 }
+};
+
+static int drvsampleres[] = {
+    IDR_DRIVE_CLICK_A500_1, IDR_DRIVE_SPIN_A500_1, IDR_DRIVE_SPINND_A500_1,
+    IDR_DRIVE_STARTUP_A500_1, IDR_DRIVE_SNATCH_A500_1
+};
+#include "driveclick.h"
+int driveclick_loadresource (struct drvsample *s, int drivetype)
+{
+    int i, ok;
+
+    ok = 1;
+    for (i = 0; i < DS_END; i++) {
+        HRSRC res = FindResource(NULL, MAKEINTRESOURCE(drvsampleres[i]), "WAVE");
+       if (res != 0) {
+           HANDLE h = LoadResource(NULL, res);
+           int len = SizeofResource(NULL, res);
+           uae_u8 *p = LockResource(h);
+           s->p = decodewav (p, &len);
+           s->len = len;
+       } else {
+           ok = 0;
+       }
+       s++;
+    }
+    return ok;
+}
+
+#if 0
+#include <errorrep.h>
+#endif
+#include <dbghelp.h>
+typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
+    CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
+    CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
+    CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
+
+/* Gah, don't look at this crap, please.. */
+static void efix (DWORD *regp, void *p, void *ps, int *got)
+{
+    DWORD reg = *regp;
+    if (p >= (void*)reg && p < (void*)(reg + 32)) {
+       *regp = (DWORD)ps;
+       *got = 1;
+    }
+}
+
+static LONG WINAPI ExceptionFilter( struct _EXCEPTION_POINTERS * pExceptionPointers, DWORD ec)
+{
+    LONG lRet = EXCEPTION_CONTINUE_SEARCH;
+    PEXCEPTION_RECORD er = pExceptionPointers->ExceptionRecord;
+    PCONTEXT ctx = pExceptionPointers->ContextRecord;
+
+    /* Check possible access violation in 68010+/compatible mode disabled if PC points to non-existing memory */
+    if (ec == EXCEPTION_ACCESS_VIOLATION && !er->ExceptionFlags &&
+       er->NumberParameters >= 2 && !er->ExceptionInformation[0] && regs.pc_p) {
+           void *p = (void*)er->ExceptionInformation[1];
+           if (p >= (void*)regs.pc_p && p < (void*)(regs.pc_p + 32)) {
+               int got = 0;
+               uaecptr opc = m68k_getpc();
+               void *ps = get_real_address (0);
+               m68k_dumpstate (0, 0);
+               efix (&ctx->Eax, p, ps, &got);
+               efix (&ctx->Ebx, p, ps, &got);
+               efix (&ctx->Ecx, p, ps, &got);
+               efix (&ctx->Edx, p, ps, &got);
+               efix (&ctx->Esi, p, ps, &got);
+               efix (&ctx->Edi, p, ps, &got);
+#if 0
+               gui_message ("Experimental access violation trap code activated\n"
+                   "Trying to prevent WinUAE crash.\nFix %s (68KPC=%08.8X HOSTADDR=%p)\n",
+                       got ? "ok" : "failed", m68k_getpc(), p);
+#endif
+               write_log ("Access violation! (68KPC=%08.8X HOSTADDR=%p)\n", m68k_getpc(), p);
+               if (got == 0) {
+                   write_log ("failed to find and fix the problem (%p). crashing..\n", p);
+               } else {
+                   m68k_setpc (0);
+                   exception2 (opc, p);
+                   lRet = EXCEPTION_CONTINUE_EXECUTION;
+               }
+           }
+    }
+#ifndef _DEBUG
+    if (lRet == EXCEPTION_CONTINUE_SEARCH) {
+       char path[_MAX_PATH];
+       char path2[_MAX_PATH];
+       char msg[1024];
+       char *p;
+       HMODULE dll = NULL;
+       struct tm when;
+       __time64_t now;
+       
+       _time64(&now);
+       when = *_localtime64(&now);
+       if (GetModuleFileName(NULL, path, _MAX_PATH)) {
+           char *slash = strrchr (path, '\\');
+           strcpy (path2, path);
+           if (slash) {
+               strcpy (slash + 1, "DBGHELP.DLL");
+               dll = LoadLibrary (path);
+           }
+           slash = strrchr (path2, '\\');
+           if (slash)
+               p = slash + 1;
+           else
+               p = path2;
+           sprintf (p, "winuae_%d%02d%02d_%02d%02d%02d.dmp",
+               when.tm_year + 1900, when.tm_mon + 1, when.tm_mday, when.tm_hour, when.tm_min, when.tm_sec);
+           if (dll == NULL)
+               dll = LoadLibrary("DBGHELP.DLL");
+           if (dll) {
+               MINIDUMPWRITEDUMP dump = (MINIDUMPWRITEDUMP)GetProcAddress(dll, "MiniDumpWriteDump");
+               if (dump) {
+                   HANDLE f = CreateFile(path2, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+                   if (f != INVALID_HANDLE_VALUE) {
+                       MINIDUMP_EXCEPTION_INFORMATION exinfo;
+                       exinfo.ThreadId = GetCurrentThreadId();
+                       exinfo.ExceptionPointers = pExceptionPointers;
+                       exinfo.ClientPointers = 0;
+                       dump (GetCurrentProcess(), GetCurrentProcessId(), f, MiniDumpNormal, &exinfo, NULL, NULL);
+                       CloseHandle (f);
+                       sprintf (msg, "Crash detected. MiniDump saved as:\n%s\n", path2);
+                       MessageBox( NULL, msg, "Crash", MB_OK | MB_ICONWARNING | MB_TASKMODAL | MB_SETFOREGROUND );
+                   }
+               }
+           }
+       }
+    }
+#endif
+#if 0
+       HMODULE hFaultRepDll = LoadLibrary("FaultRep.dll") ;
+       if ( hFaultRepDll )
+       {
+           pfn_REPORTFAULT pfn = (pfn_REPORTFAULT)GetProcAddress( hFaultRepDll, "ReportFault");
+           if ( pfn )
+           {
+               EFaultRepRetVal rc = pfn( pExceptionPointers, 0) ;
+               lRet = EXCEPTION_EXECUTE_HANDLER;
+           }
+           FreeLibrary(hFaultRepDll );
+       }
+#endif
+    return lRet ;
+}
+
+void systray (HWND hwnd, int remove)
+{
+    NOTIFYICONDATA nid;
+
+    if (hwnd == NULL)
+       return;
+    if (!TaskbarRestartOk) {
+       TaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
+       TaskbarRestartOk = 1;
+    }
+    memset (&nid, 0, sizeof (nid));
+    nid.cbSize = sizeof (nid);
+    nid.hWnd = hwnd;
+    nid.hIcon = LoadIcon (hInst, (LPCSTR)MAKEINTRESOURCE(IDI_APPICON));
+    nid.uFlags = NIF_ICON | NIF_MESSAGE;
+    nid.uCallbackMessage = WM_USER + 1;
+    Shell_NotifyIcon (remove ? NIM_DELETE : NIM_ADD, &nid);
+}
+
+void systraymenu (HWND hwnd)
+{
+    POINT pt;
+    HMENU menu, menu2, drvmenu;
+    int drvs[] = { ID_ST_DF0, ID_ST_DF1, ID_ST_DF2, ID_ST_DF3, -1 };
+    int i;
+    char text[100];
+
+    winuae_inactive (hwnd, FALSE);
+    WIN32GUI_LoadUIString( IDS_STMENUNOFLOPPY, text, sizeof (text));
+    GetCursorPos (&pt);
+    menu = LoadMenu (hInst, MAKEINTRESOURCE (IDM_SYSTRAY));
+    if (!menu)
+       return;
+    menu2 = GetSubMenu (menu, 0);
+    drvmenu = GetSubMenu (menu2, 1);
+    EnableMenuItem (menu2, ID_ST_HELP, pHtmlHelp ? MF_ENABLED : MF_GRAYED);
+    i = 0;
+    while (drvs[i] >= 0) {
+       char s[MAX_PATH];
+       if (currprefs.df[i][0])
+           sprintf (s, "DF%d: [%s]", i, currprefs.df[i]);
+       else
+           sprintf (s, "DF%d: [%s]", i, text);
+       ModifyMenu (drvmenu, drvs[i], MF_BYCOMMAND | MF_STRING, drvs[i], s);
+       EnableMenuItem (menu2, drvs[i], currprefs.dfxtype[i] < 0 ? MF_GRAYED : MF_ENABLED);
+       i++;
+    }
+    if (!isfullscreen ())
+       SetForegroundWindow (hwnd);
+    TrackPopupMenu (menu2, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
+        pt.x, pt.y, 0, hwnd, NULL);
+    PostMessage (hwnd, WM_NULL, 0, 0);
+    DestroyMenu (menu);
+    winuae_active (hwnd, FALSE);
+}
+
+int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
+                   int nCmdShow)
+{
+    __try {
+       WinMain2 (hInstance, hPrevInstance, lpCmdLine, nCmdShow);
+        } __except(ExceptionFilter(GetExceptionInformation(), GetExceptionCode()))
+    {
+    }
+    return FALSE;
+}
+
+
diff --git a/od-win32/win32.h b/od-win32/win32.h
new file mode 100755 (executable)
index 0000000..a35201b
--- /dev/null
@@ -0,0 +1,95 @@
+/* 
+  * UAE - The Un*x Amiga Emulator
+  * 
+  * Win32-specific header file
+  * 
+  * (c) 1997-1999 Mathias Ortmann
+  * (c) 1998-2001 Brian King
+  */
+
+#ifndef __WIN32_H__
+#define __WIN32_H__
+
+#define IHF_WINDOWHIDDEN 6
+#define NORMAL_WINDOW_STYLE (WS_VISIBLE | WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU )
+
+extern HMODULE hUIDLL;
+extern HWND hAmigaWnd, hMainWnd;
+extern RECT amigawin_rect;
+extern int in_sizemove;
+extern int manual_painting_needed;
+extern int manual_palette_refresh_needed;
+extern int mouseactive, focus;
+#define WINUAEBETA 1
+#define WINUAEBETASTR " Beta 4"
+
+extern void my_kbd_handler (int, int, int);
+extern void clearallkeys(void);
+extern int getcapslock (void);
+
+void releasecapture (void);
+int WIN32_RegisterClasses( void );
+int WIN32_InitHtmlHelp( void );
+int WIN32_InitLibraries( void );
+int WIN32_CleanupLibraries( void );
+void WIN32_MouseDefaults( int, int );
+void WIN32_HandleRegistryStuff( void );
+extern void setup_brkhandler (void);
+extern void remove_brkhandler (void);
+extern void disablecapture (void);
+extern void fullscreentoggle (void);
+
+extern void setmouseactive (int active);
+extern void minimizewindow (void);
+extern uae_u32 OSDEP_minimize_uae(void);
+
+void finishjob (void);
+void updatedisplayarea (void);
+void init_colors (void);
+
+extern int pause_emulation;
+extern int sound_available;
+extern int framecnt;
+extern char prtname[];
+extern char VersionStr[256];
+extern int os_winnt, os_winnt_admin;
+extern int paraport_mask;
+extern int gui_active;
+
+/* For StatusBar when running in a Window */
+#define LED_NUM_PARTS 10
+#define LED_POWER_WIDTH 42
+#define LED_HD_WIDTH 24
+#define LED_CD_WIDTH 24
+#define LED_DRIVE_WIDTH 24
+#define LED_FPS_WIDTH 64
+#define LED_IDLE_WIDTH 64
+
+extern HKEY hWinUAEKey;
+extern int screen_is_picasso;
+extern HINSTANCE hInst;
+extern int win_x_diff, win_y_diff;
+
+extern void sleep_millis (int ms);
+extern void sleep_millis_busy (int ms);
+extern void screenshot(int mode);
+extern void wait_keyrelease (void);
+extern void keyboard_settrans (void);
+extern void setpriority (int pri);
+
+extern void handle_rawinput (DWORD lParam);
+
+#define DEFAULT_PRIORITY 2
+struct threadpriorities {
+    char *name;
+    int value;
+};
+extern struct threadpriorities priorities[];
+extern int dinput_wmkey (uae_u32 key);
+extern int dinput_winmouse (void);
+
+void systray (HWND hwnd, int remove);
+void systraymenu (HWND hwnd);
+void exit_gui (int);
+
+#endif
\ No newline at end of file
diff --git a/od-win32/win32_filesys.c b/od-win32/win32_filesys.c
new file mode 100755 (executable)
index 0000000..765e81e
--- /dev/null
@@ -0,0 +1,135 @@
+
+
+/* Determines if this drive-letter currently has a disk inserted */
+static int CheckRM( char *DriveName )
+{
+    char filename[ MAX_PATH ];
+    DWORD dwHold;
+    BOOL result = FALSE;
+
+    sprintf( filename, "%s.", DriveName );
+    dwHold = GetFileAttributes( filename );
+    if( dwHold != 0xFFFFFFFF )
+        result = TRUE;
+    return result;
+}
+
+/* This function makes sure the volume-name being requested is not already in use, or any of the following
+   illegal values: */
+static char *illegal_volumenames[] = { "SYS", "DEVS", "LIBS", "FONTS", "C", "L", "S" };
+
+static int valid_volumename( struct uaedev_mount_info *mountinfo, char *volumename, int fullcheck )
+{
+    int i, result = 1, illegal_count = sizeof( illegal_volumenames ) / sizeof( char *);
+    for( i = 0; i < illegal_count; i++ )
+    {
+        if( strcmp( volumename, illegal_volumenames[i] ) == 0 )
+        {
+            result = 0;
+            break;
+        }
+    }
+    /* if result is still good, we've passed the illegal names check, and must check for duplicates now */
+    if( result && fullcheck)
+    {
+        for( i = 0; i < mountinfo->num_units; i++ )
+        {
+            if( mountinfo->ui[i].volname && ( strcmp( mountinfo->ui[i].volname, volumename ) == 0 ) )
+            {
+                result = 0;
+                break;
+            }
+        }
+    }
+    return result;
+}
+
+/* Returns 1 if an actual volume-name was found, 2 if no volume-name (so uses some defaults) */
+static int get_volume_name( struct uaedev_mount_info *mtinf, char *volumepath, char *volumename, int size, int inserted, int drivetype, int fullcheck )
+{
+    int result = 2;
+    static int cd_number = 0;
+
+    if( inserted )
+    {
+       if( GetVolumeInformation( volumepath, volumename, size, NULL, NULL, NULL, NULL, 0 ) && volumename[0] && valid_volumename( mtinf, volumename, fullcheck ) )
+       {
+           // +++Bernd Roesch
+           if(!strcmp(volumename,"AmigaOS35"))strcpy(volumename,"AmigaOS3.5");
+           if(!strcmp(volumename,"AmigaOS39"))strcpy(volumename,"AmigaOS3.9");
+           // ---Bernd Roesch
+           result = 1;
+       }
+    }
+
+    if( result == 2 )
+    {
+        switch( drivetype )
+        {
+            case DRIVE_FIXED:
+                sprintf( volumename, "WinDH_%c", volumepath[0] );
+                break;
+            case DRIVE_CDROM:
+                sprintf( volumename, "WinCD_%c", volumepath[0] );
+                break;
+            case DRIVE_REMOVABLE:
+                sprintf( volumename, "WinRMV_%c", volumepath[0] );
+                break;
+            case DRIVE_REMOTE:
+                sprintf( volumename, "WinNET_%c", volumepath[0] );
+                break;
+            case DRIVE_RAMDISK:
+                sprintf( volumename, "WinRAM_%c", volumepath[0] );
+                break;
+            case DRIVE_UNKNOWN:
+            case DRIVE_NO_ROOT_DIR:
+            default:
+                result = 0;
+                break;
+        }
+    }
+
+    return result;
+}
+
+/* New function to actually handle add_filesys_unit() calls at start-up, as well as mount-all drives flag */
+void filesys_init( void )
+{
+    int drive, drivetype;
+    UINT errormode = SetErrorMode( SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX );
+    char volumename[MAX_PATH]="";
+    char volumepath[6];
+    DWORD dwDriveMask;
+    char *result = NULL;
+
+    if( currprefs.win32_automount_drives )
+    {
+        dwDriveMask = GetLogicalDrives();
+        dwDriveMask >>= 2; // Skip A and B drives...
+
+        for( drive = 'C'; drive <= 'Z'; ++drive )
+        {
+           sprintf( volumepath, "%c:\\", drive );
+           /* Is this drive-letter valid (it used to check for media in drive) */
+            if( ( dwDriveMask & 1 ) /* && CheckRM( volumepath ) */ ) 
+            {
+               BOOL inserted = CheckRM( volumepath ); /* Is there a disk inserted? */
+                drivetype = GetDriveType( volumepath );
+               if (drivetype != DRIVE_CDROM) {
+
+                   get_volume_name( currprefs.mountinfo, volumepath, volumename, MAX_PATH, inserted, drivetype, 1 );
+                   if( drivetype == DRIVE_REMOTE )
+                       strcat( volumepath, "." );
+                   else
+                       strcat( volumepath, ".." );
+
+                   result = add_filesys_unit (currprefs.mountinfo, 0, volumename, volumepath, 0, 0, 0, 0, 0, 0, 0);
+                   if( result )
+                       write_log( result );
+               }
+            } /* if drivemask */
+            dwDriveMask >>= 1;
+        }
+    }
+    SetErrorMode( errormode );
+}
diff --git a/od-win32/win32_nogui.c b/od-win32/win32_nogui.c
new file mode 100755 (executable)
index 0000000..219b655
--- /dev/null
@@ -0,0 +1,499 @@
+
+#include "config.h"
+#include "sysconfig.h"
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <signal.h>
+
+#include <windows.h>
+#include <commctrl.h>
+#include <commdlg.h>
+#include <shellapi.h>
+#include <zmouse.h>
+#include <ddraw.h>
+#include <dbt.h>
+#include <math.h>
+#include <mmsystem.h>
+
+#include "sysdeps.h"
+#include "options.h"
+#include "sound.h"
+#include "uae.h"
+#include "memory.h"
+#include "custom.h"
+#include "events.h"
+#include "xwin.h"
+#include "keyboard.h"
+#include "inputdevice.h"
+#include "keybuf.h"
+#include "drawing.h"
+
+HWND hMainWnd;
+HINSTANCE hInst;
+int mouseactive, focus;
+int os_winnt, os_winnt_admin, useqpc, cpu_mmx, pause_emulation;
+char *start_path;
+
+static int mm_timerres;
+static int timermode, timeon;
+static HANDLE timehandle;
+
+static int timeend (void)
+{
+    if (!timeon)
+       return 1;
+    timeon = 0;
+    if (timeEndPeriod (mm_timerres) == TIMERR_NOERROR)
+       return 1;
+    write_log ("TimeEndPeriod() failed\n");
+    return 0;
+}
+
+static int timebegin (void)
+{
+    if (timeon) {
+       timeend();
+       return timebegin();
+    }
+    timeon = 0;
+    if (timeBeginPeriod (mm_timerres) == TIMERR_NOERROR) {
+       timeon = 1;
+       return 1;
+    }
+    write_log ("TimeBeginPeriod() failed\n");
+    return 0;
+}
+
+static void init_mmtimer (void)
+{
+    TIMECAPS tc;
+    mm_timerres = 0;
+    if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR)
+       return;
+    mm_timerres = min(max(tc.wPeriodMin, 1), tc.wPeriodMax);
+    timehandle = CreateEvent (NULL, TRUE, FALSE, NULL);
+}
+
+void sleep_millis (int ms)
+{
+    UINT TimerEvent;
+
+    if (mm_timerres <= 0 || timermode) {
+       Sleep (ms);
+       return;
+    }
+    TimerEvent = timeSetEvent (ms, 0, timehandle, 0, TIME_ONESHOT | TIME_CALLBACK_EVENT_SET);
+    if (!TimerEvent) {
+       Sleep (ms);
+    } else {
+       WaitForSingleObject (timehandle, ms);
+        ResetEvent (timehandle);
+       timeKillEvent (TimerEvent);
+    }
+}
+
+void sleep_millis_busy (int ms)
+{
+    if (timermode < 0)
+       return;
+    sleep_millis (ms);
+}
+
+#include <process.h>
+static volatile int dummythread_die;
+static void dummythread (void *dummy)
+{
+    SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_LOWEST);
+    while (!dummythread_die);
+}
+
+static uae_u64 win32_read_processor_time (void)
+{
+    uae_u32 foo, bar;
+     __asm
+    {
+        rdtsc
+        mov foo, eax
+        mov bar, edx
+    }
+    return ((uae_u64)bar << 32) | foo;
+}
+
+static int figure_processor_speed (void)
+{
+    extern volatile frame_time_t vsynctime;
+    extern unsigned long syncbase;
+    uae_u64 clockrate, clockrateidle, qpfrate, ratea1, ratea2;
+    uae_u32 rate1, rate2;
+    double limit, clkdiv = 1, clockrate1000 = 0;
+    int i, ratecnt = 6;
+    LARGE_INTEGER freq;
+    int qpc_avail = 0;
+    int mmx = 0; 
+
+    rpt_available = 1;
+    __try
+    {
+       __asm 
+       {
+           rdtsc
+       }
+    } __except( GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION ) {
+       rpt_available = 0;
+       write_log ("CLOCKFREQ: RDTSC not supported\n");
+    }
+    __try
+    {
+       __asm 
+       {
+           mov eax,1
+           cpuid
+           and edx,0x800000
+           mov mmx,edx
+       }
+       if (mmx)
+           cpu_mmx = 1;
+    } __except( GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION ) {
+    }
+
+    if (QueryPerformanceFrequency(&freq)) {
+       qpc_avail = 1;
+       write_log("CLOCKFREQ: QPF %.2fMHz\n", freq.QuadPart / 1000000.0);
+       qpfrate = freq.QuadPart;
+        /* we don't want 32-bit overflow */
+       if (qpfrate > 100000000) {
+           qpfrate >>= 6;
+           qpc_avail = -1;
+       }
+    } else {
+       write_log("CLOCKREQ: QPF not supported\n");
+    }
+
+    if (!rpt_available && !qpc_avail)
+       return 0;
+
+    init_mmtimer();
+    SetThreadPriority ( GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
+    sleep_millis (100);
+    dummythread_die = -1;
+
+    if (qpc_avail || rpt_available)  {
+
+       if (rpt_available) {
+           clockrateidle = win32_read_processor_time();
+           sleep_millis (500);
+           clockrateidle = (win32_read_processor_time() - clockrateidle) * 2;
+           dummythread_die = 0;
+           _beginthread(&dummythread, 0, 0);
+           sleep_millis (100);
+           clockrate = win32_read_processor_time();
+           sleep_millis (500);
+           clockrate = (win32_read_processor_time() - clockrate) * 2;
+           write_log("CLOCKFREQ: RDTSC %.2fMHz (busy) / %.2fMHz (idle)\n",
+               clockrate / 1000000.0, clockrateidle / 1000000.0);
+           clkdiv = (double)clockrate / (double)clockrateidle;
+           clockrate >>= 6;
+           clockrate1000 = clockrate / 1000.0;
+       }
+       if (clkdiv <= 0.95 || clkdiv >= 1.05 || !rpt_available) {
+           if (rpt_available)
+               write_log ("CLOCKFREQ: CPU throttling detected, using QPF instead of RDTSC\n");
+           useqpc = qpc_avail;
+           rpt_available = 1;
+           clkdiv = 1.0;
+           clockrate = qpfrate;
+           clockrate1000 = clockrate / 1000.0;
+           if (dummythread_die < 0) {
+               dummythread_die = 0;
+               _beginthread(&dummythread, 0, 0);
+           }
+           if (!qpc_avail)
+               write_log ("No working timing reference detected\n");
+       }
+       timermode = 0;
+       if (mm_timerres) {
+           sleep_millis (50);
+           timebegin ();
+           sleep_millis (50);
+           ratea1 = 0;
+           write_log ("Testing MM-timer resolution:\n");
+           for (i = 0; i < ratecnt; i++) {
+               rate1 = read_processor_time();
+               sleep_millis (1);
+               rate1 = read_processor_time() - rate1;
+               write_log ("%1.2fms ", rate1 / clockrate1000);
+               ratea1 += rate1;
+           }
+           write_log("\n");
+           timeend ();
+           sleep_millis (50);
+       }
+       timermode = 1;
+       ratea2 = 0;
+       write_log ("Testing Sleep() resolution:\n");
+       for (i = 0; i < ratecnt; i++) {
+           rate2 = read_processor_time();
+           sleep_millis (1);
+           rate2 = read_processor_time() - rate2;
+           write_log ("%1.2fms ", rate2 / clockrate1000);
+           ratea2 += rate2;
+       }
+       write_log("\n");
+    }
+
+    SetThreadPriority ( GetCurrentThread(), THREAD_PRIORITY_NORMAL);
+    dummythread_die = 1;
+   
+    if (clkdiv >= 0.90 && clkdiv <= 1.10 && rpt_available) {
+       limit = 2.5;
+       if ((ratea2 / ratecnt) < limit * clockrate1000) { /* regular Sleep() is ok */
+           timermode = 1;
+           write_log ("Using Sleep() (resolution < %.1fms)\n", limit);
+       } else if (mm_timerres && (ratea1 / ratecnt) < limit * clockrate1000) { /* MM-timer is ok */
+           timermode = 0;
+           timebegin ();
+           write_log ("Using MultiMedia timers (resolution < %.1fms)\n", limit);
+       } else {
+           timermode = -1; /* both timers are bad, fall back to busy-wait */
+           write_log ("falling back to busy-loop waiting (timer resolution > %.1fms)\n", limit);
+       }
+    } else {
+       timermode = -1;
+       write_log ("forcing busy-loop wait mode\n");
+    }
+    syncbase = (unsigned long)clockrate;
+    return 1;
+}
+
+int needmousehack (void)
+{
+    return 0;
+}
+
+void gui_message (const char *format,...)
+{
+}
+
+void gui_led (int led, int on)
+{
+}
+
+void gui_fps (int fps)
+{
+}
+
+void gui_hd_led (int led)
+{
+}
+
+void gui_cd_led (int led)
+{
+}
+
+void gui_unlock (void)
+{
+}
+
+void gui_lock (void)
+{
+}
+
+int gui_update (void)
+{
+    return 0;
+}
+
+char *DXError (HRESULT ddrval)
+{
+    return "";
+}
+
+void setmouseactive (int active)
+{
+}
+
+void minimizewindow (void)
+{
+}
+
+int isfullscreen (void)
+{
+    return 0;
+}
+
+void fullscreentoggle (void)
+{
+}
+
+void disablecapture (void)
+{
+}
+
+void WIN32GUI_DisplayGUI (int shortcut)
+{
+}
+
+void flush_block (int a, int b)
+{
+}
+
+void flush_screen (int a, int b)
+{
+}
+
+void flush_line (int lineno)
+{
+}
+
+void flush_clear_screen (void)
+{
+}
+
+int lockscr (void)
+{
+    return 1;
+}
+
+void unlockscr (void)
+{
+}
+
+void machdep_init (void)
+{
+}
+
+void handle_events (void)
+{
+}
+
+int debuggable (void)
+{
+    return 0;
+}
+
+int graphics_init (void)
+{
+    return 1;
+}
+
+int graphics_setup (void)
+{
+    return 1;
+}
+
+void graphics_leave (void)
+{
+}
+
+extern FILE *debugfile;
+char VersionStr[256];
+static OSVERSIONINFO osVersion;
+void logging_init( void )
+{
+    static int started;
+    static int first;
+    char debugfilename[MAX_PATH];
+
+    if (first > 1) {
+       write_log ("** RESTART **\n");
+       return;
+    }
+    if (first == 1) {
+       if (debugfile)
+           fclose (debugfile);
+        debugfile = 0;
+    }
+    if( currprefs.win32_logfile ) {
+       sprintf( debugfilename, "%s\\winuaelog.txt", start_path );
+       if( !debugfile )
+           debugfile = fopen( debugfilename, "wt" );
+    } else if (!first) {
+       sprintf( debugfilename, "%s\\winuaebootlog.txt", start_path );
+       if( !debugfile )
+           debugfile = fopen( debugfilename, "wt" );
+    }
+    first++;
+    write_log ( "%s", VersionStr );
+    write_log (" (OS: %s %d.%d%s)", os_winnt ? "NT" : "W9X/ME", osVersion.dwMajorVersion, osVersion.dwMinorVersion, os_winnt_admin ? " Administrator privileges" : "");
+    write_log ("\n(c) 1995-2001 Bernd Schmidt   - Core UAE concept and implementation."
+              "\n(c) 1998-2003 Toni Wilen      - Win32 port, core code updates."
+              "\n(c) 1996-2001 Brian King      - Win32 port, Picasso96 RTG, and GUI."
+              "\n(c) 1996-1999 Mathias Ortmann - Win32 port and bsdsocket support."
+              "\n(c) 2000-2001 Bernd Meyer     - JIT engine."
+              "\n(c) 2000-2001 Bernd Roesch    - MIDI input, many fixes."
+              "\nPress F12 to show the Settings Dialog (GUI), Alt-F4 to quit."
+              "\nEnd+F1 changes floppy 0, End+F2 changes floppy 1, etc."
+              "\n");
+}
+
+void target_save_options (FILE *f, struct uae_prefs *p)
+{
+}
+
+int target_parse_option (struct uae_prefs *p, char *option, char *value)
+{
+    return 0;
+}
+
+int gui_init (void)
+{
+    return 1;
+}
+
+void gui_exit (void)
+{
+}
+
+void gui_filename (int num, const char *name)
+{
+}
+
+void setup_brkhandler (void)
+{
+}
+
+int check_prefs_changed_gfx (void)
+{
+    return 0;
+}
+
+void screenshot (int mode)
+{
+}
+
+int _stdcall WinMain (HINSTANCE hInstance, HINSTANCE prev, LPSTR cmd, int show)
+{
+    char **argv, *posn;
+    int argc;
+    hInst = hInstance;
+    argc = __argc; argv = __argv;
+    start_path = xmalloc( MAX_PATH );
+    GetModuleFileName( NULL, start_path, MAX_PATH );
+    if( ( posn = strrchr( start_path, '\\' ) ) )
+        *posn = 0;
+    real_main (argc, argv);
+    if (mm_timerres && timermode == 0)
+       timeend ();
+    free (start_path);
+    return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/od-win32/win32_scale2x.c b/od-win32/win32_scale2x.c
new file mode 100755 (executable)
index 0000000..1557b12
--- /dev/null
@@ -0,0 +1,198 @@
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+#include "config.h"
+#include "options.h"
+#include "xwin.h"
+#include "dxwrap.h"
+#include "win32.h"
+#include "win32gfx.h"
+#include "gfxfilter.h"
+
+struct uae_filter uaefilters[] =
+{
+    { UAE_FILTER_NULL, "Null filter", "null",
+    { 0, UAE_FILTER_MODE_16_16 | UAE_FILTER_MODE_32_32, 0, 0, 0 } },
+
+    { UAE_FILTER_DIRECT3D, "Direct3D", "direct3d", 1, 0, 0, 0, 0 },
+
+    { UAE_FILTER_OPENGL, "OpenGL", "opengl", 1, 0, 0, 0, 0 },
+
+    { UAE_FILTER_SCALE2X, "Scale2X", "scale2x", 0, 0, UAE_FILTER_MODE_16_16 | UAE_FILTER_MODE_32_32, 0, 0 },
+
+//    { UAE_FILTER_HQ, "hq", "hq", 0, 0, UAE_FILTER_MODE_16_32, UAE_FILTER_MODE_16_32, UAE_FILTER_MODE_16_32 },
+
+    { UAE_FILTER_SUPEREAGLE, "SuperEagle", "supereagle", 0, 0, UAE_FILTER_MODE_16_16, 0, 0 },
+
+    { UAE_FILTER_SUPER2XSAI, "Super2xSaI", "super2xsai", 0, 0, UAE_FILTER_MODE_16_16, 0, 0 },
+
+    { UAE_FILTER_2XSAI, "2xSaI", "2xsai", 0, 0, UAE_FILTER_MODE_16_16, 0, 0 },
+
+
+    { 0 }
+};
+
+
+static int dst_width, dst_height, amiga_width, amiga_height, amiga_depth, dst_depth, scale;
+uae_u8 *bufmem_ptr;
+int bufmem_width, bufmem_height;
+
+void S2X_configure (int rb, int gb, int bb, int rs, int gs, int bs)
+{
+    Init_2xSaI (rb, gb, bb, rs, gs, bs);
+    hq_init (rb, gb, bb, rs, gs, bs);
+    bufmem_ptr = 0;
+}
+
+void S2X_init (int dw, int dh, int aw, int ah, int mult, int ad, int dd)
+{
+    int flags;
+
+    flags = usedfilter->x[mult];
+    if (mult) {
+       if ((ad == 16 && !(flags & UAE_FILTER_MODE_16)) || (ad == 32 && !(flags & UAE_FILTER_MODE_32))) {
+           usedfilter = &uaefilters[0];
+           mult = 1;
+           changed_prefs.gfx_filter = usedfilter->type;
+       }
+    }
+    dst_width = dw;
+    dst_height = dh;
+    dst_depth = dd;
+    amiga_width = aw;
+    amiga_height = ah;
+    amiga_depth = ad;
+    scale = mult;
+}
+
+void S2X_render (void)
+{
+    int aw = amiga_width, ah = amiga_height, v, pitch;
+    uae_u8 *dptr, *sptr;
+    int ok = 0;
+
+    sptr = gfxvidinfo.bufmem;
+
+    v = currprefs.gfx_filter_horiz_offset;
+    v += (dst_width / scale - amiga_width) / 8;
+    sptr += -v * (amiga_depth / 8) * 4;
+    aw -= -v * 4;
+
+    v = currprefs.gfx_filter_vert_offset;
+    v += (dst_height / scale - amiga_height) / 8;
+    sptr += -v * gfxvidinfo.rowbytes * 4;
+    ah -= -v * 4;
+
+    if (aw * scale > dst_width)
+        aw = (dst_width / scale) & ~3;
+    if (ah * scale > dst_height)
+        ah = (dst_height / scale) & ~3;
+
+    if (ah < 16)
+       return;
+    if (aw < 16)
+       return;
+
+    bufmem_ptr = sptr;
+    bufmem_width = aw;
+    bufmem_height = ah;
+
+    if (!DirectDraw_SurfaceLock (lockable_surface))
+       return;
+
+    dptr = DirectDraw_GetSurfacePointer ();
+    pitch = DirectDraw_GetSurfacePitch();
+
+    if (usedfilter->type == UAE_FILTER_SCALE2X ) { /* 16+32/2X */
+
+        if (amiga_depth == 16 && dst_depth == 16) {
+           AdMame2x (sptr, gfxvidinfo.rowbytes, dptr, pitch, aw, ah);
+           ok = 1;
+       } else if (amiga_depth == 32 && dst_depth == 32) {
+           AdMame2x32 (sptr, gfxvidinfo.rowbytes, dptr, pitch, aw, ah);
+           ok = 1;
+       }
+
+    } else if (usedfilter->type == UAE_FILTER_HQ) { /* 32/2X+3X+4X */
+
+        int hqsrcpitch = gfxvidinfo.rowbytes - aw * amiga_depth / 8;
+       int hqdstpitch = pitch - aw * scale * dst_depth / 8;
+       int hqdstpitch2 = pitch * scale - aw * scale * dst_depth / 8;
+       if (scale == 2) {
+           if (amiga_depth == 16 && dst_depth == 32) {
+               hq2x_32 (sptr, dptr, aw, ah, hqdstpitch, hqsrcpitch, hqdstpitch2);
+               ok = 1;
+           }
+       } else if (scale == 3) {
+           if (amiga_depth == 16 && dst_depth == 16) {
+               hq3x_16 (sptr, dptr, aw, ah, hqdstpitch, hqsrcpitch, hqdstpitch2);
+               ok = 1;
+           } else if (amiga_depth == 16 && dst_depth == 32) {
+               hq3x_32 (sptr, dptr, aw, ah, hqdstpitch, hqsrcpitch, hqdstpitch2);
+               ok = 1;
+           }
+       } else if (scale == 4) {
+           if (amiga_depth == 16 && dst_depth == 32) {
+               hq4x_32 (sptr, dptr, aw, ah, hqdstpitch, hqsrcpitch, hqdstpitch2);
+               ok = 1;
+           }
+       }
+
+    } else if (usedfilter->type == UAE_FILTER_SUPEREAGLE) { /* 16/2X */
+
+       if (scale == 2 && amiga_depth == 16 && dst_depth == 16) {
+           SuperEagle (sptr, gfxvidinfo.rowbytes, dptr, pitch, aw, ah);
+           ok = 1;
+       }
+
+    } else if (usedfilter->type == UAE_FILTER_SUPER2XSAI) { /* 16/2X */
+
+       if (scale == 2 && amiga_depth == 16 && dst_depth == 16) {
+           Super2xSaI (sptr, gfxvidinfo.rowbytes, dptr, pitch, aw, ah);
+           ok = 1;
+       }
+
+    } else if (usedfilter->type == UAE_FILTER_2XSAI) { /* 16/2X */
+
+       if (scale == 2 && amiga_depth == 16 && dst_depth == 16) {
+           _2xSaI (sptr, gfxvidinfo.rowbytes, dptr, pitch, aw, ah);
+           ok = 1;
+       }
+
+    } else { /* null */
+
+       if (amiga_depth == dst_depth) {
+           int y;
+           for (y = 0; y < dst_height; y++) {
+               memcpy (dptr, sptr, dst_width * dst_depth / 8);
+               sptr += gfxvidinfo.rowbytes;
+               dptr += pitch;
+           }
+       }
+       ok = 1;
+
+    }
+
+    if (ok == 0) {
+        usedfilter = &uaefilters[0];
+        changed_prefs.gfx_filter = usedfilter->type;
+    }
+
+    DirectDraw_SurfaceUnlock ();
+
+}
+
+void S2X_refresh (void)
+{
+    int y, pitch;
+    uae_u8 *dptr;
+
+    if (!DirectDraw_SurfaceLock (lockable_surface))
+       return;
+    dptr = DirectDraw_GetSurfacePointer ();
+    pitch = DirectDraw_GetSurfacePitch();
+    for (y = 0; y < dst_height; y++)
+       memset (dptr + y * pitch, 0, dst_width * dst_depth / 8);
+    DirectDraw_SurfaceUnlock ();
+    S2X_render ();
+}
diff --git a/od-win32/win32gfx.c b/od-win32/win32gfx.c
new file mode 100755 (executable)
index 0000000..cc1a8b2
--- /dev/null
@@ -0,0 +1,2171 @@
+/*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * Win32 Drawing and DirectX interface
+ *
+ * Copyright 1997-1998 Mathias Ortmann
+ * Copyright 1997-2000 Brian King
+ */
+
+#include "config.h"
+#include "sysconfig.h"
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <windows.h>
+#include <commctrl.h>
+#include <ddraw.h>
+#include <shellapi.h>
+
+#include "sysdeps.h"
+#include "options.h"
+#include "uae.h"
+#include "memory.h"
+#include "custom.h"
+#include "events.h"
+#include "xwin.h"
+#include "keyboard.h"
+#include "drawing.h"
+#include "dxwrap.h"
+#include "picasso96_win.h"
+#include "win32.h"
+#include "win32gfx.h"
+#include "win32gui.h"
+#include "resource.h"
+#include "sound.h"
+#include "inputdevice.h"
+#include "opengl.h"
+#include "direct3d.h"
+#include "midi.h"
+#include "gui.h"
+#include "serial.h"
+#include "avioutput.h"
+#include "gfxfilter.h"
+#include "parser.h"
+
+#define AMIGA_WIDTH_MAX 736
+#define AMIGA_HEIGHT_MAX 564
+
+#define DM_DX_FULLSCREEN 1
+#define DM_W_FULLSCREEN 2
+#define DM_OVERLAY 4
+#define DM_OPENGL 8
+#define DM_DX_DIRECT 16
+#define DM_PICASSO96 32
+#define DM_DDRAW 64
+#define DM_DC 128
+#define DM_D3D 256
+#define DM_D3D_FULLSCREEN 512
+#define DM_SWSCALE 1024
+
+struct uae_filter *usedfilter;
+
+struct winuae_modes {
+    int fallback;
+    char *name;
+    unsigned int aflags;
+    unsigned int pflags;
+};
+struct winuae_currentmode {
+    struct winuae_modes *mode;
+    struct winuae_modes *pmode[2];
+    struct winuae_modes *amode[2];
+    unsigned int flags;
+    int current_width, current_height, current_depth, real_depth, pitch;
+    int amiga_width, amiga_height;
+    int frequency;
+    int mapping_is_mainscreen;
+    int initdone;
+    int modeindex;
+    LPPALETTEENTRY pal;
+};
+
+struct PicassoResolution *DisplayModes;
+struct MultiDisplay Displays[MAX_DISPLAYS];
+GUID *displayGUID;
+
+static struct winuae_currentmode currentmodestruct;
+int display_change_requested;
+extern int console_logging;
+
+#define SM_WINDOW 0
+#define SM_WINDOW_OVERLAY 1
+#define SM_FULLSCREEN_DX 2
+#define SM_OPENGL_WINDOW 3
+#define SM_OPENGL_FULLSCREEN_W 4
+#define SM_OPENGL_FULLSCREEN_DX 5
+#define SM_D3D_WINDOW 6
+#define SM_D3D_FULLSCREEN_DX 7
+#define SM_NONE 7
+
+static struct winuae_modes wmodes[] =
+{
+    {
+       0, "Windowed",
+       DM_DDRAW,
+       DM_PICASSO96 | DM_DDRAW
+    },
+    {
+       0, "Windowed Overlay",
+       DM_OVERLAY | DM_DX_DIRECT | DM_DDRAW,
+       DM_OVERLAY | DM_DX_DIRECT | DM_DDRAW | DM_PICASSO96
+    },
+    {
+       1, "Fullscreen",
+       DM_DX_FULLSCREEN | DM_DX_DIRECT | DM_DDRAW,
+       DM_DX_FULLSCREEN | DM_DX_DIRECT | DM_DDRAW | DM_PICASSO96
+    },
+    {
+       1, "Windowed OpenGL",
+       DM_OPENGL | DM_DC,
+       0
+    },
+    {
+       3, "Fullscreen OpenGL",
+       DM_OPENGL | DM_W_FULLSCREEN | DM_DC,
+       0
+    },
+    {
+       3, "DirectDraw Fullscreen OpenGL",
+       DM_OPENGL | DM_DX_FULLSCREEN | DM_DC,
+       0
+    },
+    {
+       0, "Windowed Direct3D",
+       DM_D3D,
+       0
+    },
+    {
+       0, "Fullscreen Direct3D",
+       DM_D3D | DM_D3D_FULLSCREEN,
+       0
+    },
+    {
+       0, "none",
+       0,
+       0
+    }
+};
+
+static struct winuae_currentmode *currentmode = &currentmodestruct;
+static int gfx_tempbitmap;
+
+static int modefallback (unsigned int mask)
+{
+    if (mask == DM_OVERLAY) {
+       if (currentmode->amode[0] == &wmodes[SM_WINDOW_OVERLAY])
+           currentmode->amode[0] = &wmodes[0];
+       if (currentmode->pmode[0] == &wmodes[SM_WINDOW_OVERLAY])
+           currentmode->pmode[0] = &wmodes[0];
+       return 1;
+    }
+    if (!picasso_on) {
+       if (currprefs.gfx_afullscreen) {
+           currprefs.gfx_afullscreen = changed_prefs.gfx_afullscreen = 0;
+           updatewinfsmode (&currprefs);
+           return 1;
+       } else {
+           if (currentmode->amode[0] == &wmodes[0])
+               return 0;
+           currentmode->amode[0] = &wmodes[0];
+           return 1;
+       }
+    } else {
+       if (currprefs.gfx_pfullscreen) {
+           currprefs.gfx_pfullscreen = changed_prefs.gfx_pfullscreen = 0;
+           return 1;
+       } else {
+           if (currentmode->pmode[0] == &wmodes[0]) {
+               currprefs.gfx_pfullscreen = changed_prefs.gfx_pfullscreen = 1;
+               return 1;
+           }
+           currentmode->pmode[0] = &wmodes[0];
+           return 1;
+       }
+    }
+    return 0;
+}
+
+int screen_is_picasso = 0;
+
+int WIN32GFX_IsPicassoScreen( void )
+{
+    return screen_is_picasso;
+}
+
+void WIN32GFX_DisablePicasso( void )
+{
+    picasso_requested_on = 0;
+    picasso_on = 0;
+}
+
+void WIN32GFX_EnablePicasso( void )
+{
+    picasso_requested_on = 1;
+}
+
+void WIN32GFX_DisplayChangeRequested( void )
+{
+    display_change_requested = 1;
+}
+
+int isscreen (void)
+{
+    return hMainWnd ? 1 : 0;
+}
+
+int isfullscreen (void)
+{
+    if (screen_is_picasso)
+       return currprefs.gfx_pfullscreen;
+    else
+       return currprefs.gfx_afullscreen;
+}
+
+int WIN32GFX_GetDepth (int real)
+{
+    if (!currentmode->real_depth)
+       return currentmode->current_depth;
+    return real ? currentmode->real_depth : currentmode->current_depth;
+}
+
+int WIN32GFX_GetWidth( void )
+{
+    return currentmode->current_width;
+}
+
+int WIN32GFX_GetHeight( void )
+{
+    return currentmode->current_height;
+}
+
+#include "dxwrap.h"
+
+static BOOL doInit (void);
+
+uae_u32 default_freq = 0;
+
+HWND hStatusWnd = NULL;
+HINSTANCE hDDraw = NULL;
+uae_u16 picasso96_pixel_format = RGBFF_CHUNKY;
+
+/* For the DX_Invalidate() and gfx_unlock_picasso() functions */
+static int p96_double_buffer_first, p96_double_buffer_last, p96_double_buffer_needs_flushing = 0;
+
+static char scrlinebuf[4096];  /* this is too large, but let's rather play on the safe side here */
+
+static int rgbformat_bits (RGBFTYPE t)
+{
+    unsigned long f = 1 << t;
+    return ((f & RGBMASK_8BIT) != 0 ? 8
+           : (f & RGBMASK_15BIT) != 0 ? 15
+           : (f & RGBMASK_16BIT) != 0 ? 16
+           : (f & RGBMASK_24BIT) != 0 ? 24
+           : (f & RGBMASK_32BIT) != 0 ? 32
+           : 0);
+}
+
+static DEVMODE dmScreenSettings;
+static volatile cdsthread_ret;
+
+static void cdsthread (void *dummy)
+{
+    int ret = ChangeDisplaySettings (&dmScreenSettings, CDS_FULLSCREEN);
+    if (ret != DISP_CHANGE_SUCCESSFUL && dmScreenSettings.dmDisplayFrequency > 0) {
+        dmScreenSettings.dmFields &= ~DM_DISPLAYFREQUENCY;
+        ret = ChangeDisplaySettings (&dmScreenSettings, CDS_FULLSCREEN);
+    }
+    if (ret != DISP_CHANGE_SUCCESSFUL) {
+       cdsthread_ret = 0;
+       return;
+    }
+    cdsthread_ret = 1;
+}
+
+#include <process.h>
+static int do_changedisplaysettings (int width, int height, int bits, int freq)
+{
+    memset (&dmScreenSettings, 0, sizeof(dmScreenSettings));
+    dmScreenSettings.dmSize = sizeof(dmScreenSettings);
+    dmScreenSettings.dmPelsWidth = width;
+    dmScreenSettings.dmPelsHeight = height;
+    dmScreenSettings.dmBitsPerPel = bits;
+    dmScreenSettings.dmDisplayFrequency = freq;
+    dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | (freq > 0 ? DM_DISPLAYFREQUENCY : 0);
+    cdsthread_ret = -1;
+    _beginthread (&cdsthread, 0, 0);
+    while (cdsthread_ret < 0)
+       Sleep (10);
+    return cdsthread_ret;
+}
+
+
+static int set_ddraw (void)
+{
+    HRESULT ddrval;
+    int bits = (currentmode->current_depth + 7) & ~7;
+    int width = currentmode->current_width;
+    int height = currentmode->current_height;
+    int freq = currentmode->frequency;
+    int dxfullscreen, wfullscreen, dd, overlay;
+
+    dxfullscreen = (currentmode->flags & DM_DX_FULLSCREEN) ? TRUE : FALSE;
+    wfullscreen = (currentmode->flags & DM_W_FULLSCREEN) ? TRUE : FALSE;
+    dd = (currentmode->flags & DM_DDRAW) ? TRUE : FALSE;
+    overlay = (currentmode->flags & DM_OVERLAY) ? TRUE : FALSE;
+
+    ddrval = DirectDraw_SetCooperativeLevel( hAmigaWnd, dxfullscreen);
+    if (ddrval != DD_OK)
+       goto oops;
+
+    if (dxfullscreen) 
+    {
+        write_log( "set_ddraw: Trying %dx%d, bits=%d, refreshrate=%d\n", width, height, bits, freq );
+        ddrval = DirectDraw_SetDisplayMode (width, height, bits, freq);
+        if (ddrval != DD_OK)
+        {
+           write_log ("set_ddraw: failed, trying without forced refresh rate\n");
+            ddrval = DirectDraw_SetDisplayMode (width, height, bits, 0);
+           if (ddrval != DD_OK) {
+               write_log( "set_ddraw: Couldn't SetDisplayMode()\n" );
+               goto oops;
+           }
+        }
+
+       ddrval = DirectDraw_GetDisplayMode();
+       if (ddrval != DD_OK)
+        {
+            write_log( "set_ddraw: Couldn't GetDisplayMode()\n" );
+           goto oops;
+        }
+    } else if (wfullscreen) {
+       if (!do_changedisplaysettings (width, height, bits, currentmode->frequency))
+           goto oops2;
+    }
+
+    if (dd) {
+        ddrval = DirectDraw_CreateClipper();
+        if (ddrval != DD_OK)
+       {
+           write_log( "set_ddraw: No clipping support\n" );
+           goto oops;
+       }
+       ddrval = DirectDraw_CreateSurface (width, height);
+       if (ddrval != DD_OK)
+       {
+           write_log( "set_ddraw: Couldn't CreateSurface() for primary because %s.\n", DXError( ddrval ) );
+           goto oops;
+       }
+       if (DirectDraw_GetPrimaryBitCount() != (unsigned)bits && overlay)
+       {
+           ddrval = DirectDraw_CreateOverlaySurface (width, height, bits);
+           if( ddrval != DD_OK )
+           {
+               write_log( "set_ddraw: Couldn't CreateOverlaySurface(%d,%d,%d) because %s.\n", width, height, bits, DXError( ddrval ) );
+               goto oops2;
+           }
+       }
+       else
+       {
+           overlay = 0;
+       }
+
+        DirectDraw_ClearSurfaces();
+
+       if( !DirectDraw_DetermineLocking( dxfullscreen ) )
+       {
+           write_log( "set_ddraw: Couldn't determine locking.\n" );
+           goto oops;
+       }
+
+       ddrval = DirectDraw_SetClipper( hAmigaWnd );
+
+       if (ddrval != DD_OK)
+       {
+           write_log( "set_ddraw: Couldn't SetHWnd()\n" );
+           goto oops;
+       }
+
+        if (bits == 8) {
+           ddrval = DirectDraw_CreatePalette( currentmode->pal );
+           if (ddrval != DD_OK)
+           {
+               write_log( "set_ddraw: Couldn't CreatePalette()\n" );
+               goto oops;
+           }
+       }
+       currentmode->pitch = DirectDraw_GetSurfacePitch();
+    }
+
+    write_log( "set_ddraw() called, and is %dx%d@%d-bytes\n", width, height, bits );
+    return 1;
+
+oops:
+    write_log("set_ddraw(): DirectDraw initialization failed with\n%s\n", DXError( ddrval ));
+oops2:
+    return 0;
+}
+
+static HRESULT CALLBACK modesCallback( LPDDSURFACEDESC2 modeDesc, LPVOID context )
+{
+    RGBFTYPE colortype;
+    int i, j, ct, depth;
+
+    colortype = DirectDraw_GetSurfacePixelFormat( modeDesc );
+    if (colortype == RGBFB_NONE || colortype == RGBFB_R8G8B8 || colortype == RGBFB_B8G8R8 )
+       return DDENUMRET_OK;
+    ct = 1 << colortype;
+    depth = 0;
+    if (ct & RGBMASK_8BIT)
+       depth = 1;
+    else if (ct & (RGBMASK_15BIT | RGBMASK_16BIT))
+       depth = 2;
+    else if (ct & RGBMASK_24BIT)
+       depth = 3;
+    else if (ct & RGBMASK_32BIT)
+       depth = 4;
+    if (depth == 0)
+       return DDENUMRET_OK;
+    i = 0;
+    while (DisplayModes[i].depth >= 0) {
+       if (DisplayModes[i].depth == depth && DisplayModes[i].res.width == modeDesc->dwWidth && DisplayModes[i].res.height == modeDesc->dwHeight) {
+           for (j = 0; j < MAX_REFRESH_RATES; j++) {
+               if (DisplayModes[i].refresh[j] == 0 || DisplayModes[i].refresh[j] == modeDesc->dwRefreshRate)
+                   break;
+           }
+           if (j < MAX_REFRESH_RATES) {
+               DisplayModes[i].refresh[j] = modeDesc->dwRefreshRate;
+               DisplayModes[i].refresh[j + 1] = 0;
+               return DDENUMRET_OK;
+           }
+       }
+       i++;
+    }
+    picasso96_pixel_format |= ct;
+    i = 0;
+    while (DisplayModes[i].depth >= 0)
+       i++;
+    if (i >= MAX_PICASSO_MODES - 1)
+       return DDENUMRET_OK;
+    DisplayModes[i].res.width = modeDesc->dwWidth;
+    DisplayModes[i].res.height = modeDesc->dwHeight;
+    DisplayModes[i].depth = depth;
+    DisplayModes[i].refresh[0] = modeDesc->dwRefreshRate;
+    DisplayModes[i].refresh[1] = 0;
+    DisplayModes[i].colormodes = ct;
+    DisplayModes[i + 1].depth = -1;
+    sprintf(DisplayModes[i].name, "%dx%d, %d-bit",
+        DisplayModes[i].res.width, DisplayModes[i].res.height, DisplayModes[i].depth * 8);
+    return DDENUMRET_OK;
+}
+
+static int resolution_compare (const void *a, const void *b)
+{
+    struct PicassoResolution *ma = (struct PicassoResolution *)a;
+    struct PicassoResolution *mb = (struct PicassoResolution *)b;
+    if (ma->res.width < mb->res.width)
+       return -1;
+    if (ma->res.width > mb->res.width)
+       return 1;
+    if (ma->res.height < mb->res.height)
+       return -1;
+    if (ma->res.height > mb->res.height)
+       return 1;
+    return ma->depth - mb->depth;
+}
+static void sortmodes (void)
+{
+    int        count = 0;
+    while (DisplayModes[count].depth >= 0)
+       count++;
+    qsort (DisplayModes, count, sizeof (struct PicassoResolution), resolution_compare);
+}
+
+static void modesList (void)
+{
+    int i, j;
+
+    i = 0;
+    while (DisplayModes[i].depth >= 0) {
+       write_log ("%d: %s (", i, DisplayModes[i].name);
+       j = 0;
+       while (DisplayModes[i].refresh[j] > 0) {
+           if (j > 0)
+               write_log(",");
+           write_log ("%d", DisplayModes[i].refresh[j]);
+           j++;
+       }
+       write_log(")\n");
+       i++;
+    }
+}
+
+BOOL CALLBACK displaysCallback (GUID *guid, LPSTR desc, LPSTR name, LPVOID ctx, HMONITOR hm)
+{
+    struct MultiDisplay *md = Displays;
+
+    while (md->name) {
+       if (md - Displays >= MAX_DISPLAYS)
+           return 0;
+       md++;
+    }
+    md->name = my_strdup (desc);
+    if (guid == 0)
+       md->primary = 1;
+    else
+       memcpy (&md->guid,  guid, sizeof (GUID));
+    write_log ("'%s' '%s' %s\n", desc, name, outGUID(guid));
+    return 1;
+}
+void sortdisplays (void)
+{
+    struct MultiDisplay *md1, *md2, tmp;
+    int i;
+
+    md1 = Displays;
+    while (md1->name) {
+       md2 = md1 + 1;
+       while (md2->name) {
+           if (md1->primary < md2->primary || (md1->primary == md2->primary && strcmp (md1->name, md2->name) > 0)) {
+               memcpy (&tmp, md1, sizeof (tmp));
+               memcpy (md1, md2, sizeof (tmp));
+               memcpy (md2, &tmp, sizeof (tmp));
+           }
+           md2++;
+       }
+       md1++;
+    }
+    md1 = Displays;
+    while (md1->name) {
+        DisplayModes = md1->DisplayModes = xmalloc (sizeof (struct PicassoResolution) * MAX_PICASSO_MODES);
+        DisplayModes[0].depth = -1;
+       md1->disabled = 1;
+       if (DirectDraw_Start (md1->primary ? NULL : &md1->guid)) {
+           if (DirectDraw_GetDisplayMode () == DD_OK) {
+               int w = DirectDraw_CurrentWidth ();
+               int h = DirectDraw_CurrentHeight ();
+               int b = DirectDraw_GetSurfaceBitCount ();
+               write_log ("W=%d H=%d B=%d\n", w, h, b);
+               DirectDraw_EnumDisplayModes (DDEDM_REFRESHRATES , modesCallback);
+               sortmodes ();
+               modesList ();
+               DirectDraw_Release ();
+               if (DisplayModes[0].depth >= 0)
+                   md1->disabled = 0;
+           }
+       }
+       i = 0;
+       while (DisplayModes[i].depth > 0)
+           i++;
+       write_log ("'%s', %d display modes (%s)\n", md1->name, i, md1->disabled ? "disabled" : "enabled");
+        md1++;
+    }
+    DisplayModes = Displays[0].DisplayModes;
+    displayGUID = NULL;
+}
+
+static int our_possible_depths[] = { 8, 15, 16, 24, 32 };
+
+RGBFTYPE WIN32GFX_FigurePixelFormats( RGBFTYPE colortype )
+{
+    HRESULT ddrval;
+    int got_16bit_mode = 0;
+    int window_created = 0;
+    struct PicassoResolution *dm;
+    int i;
+
+    DirectDraw_Start (NULL);
+    if( colortype == 0 ) /* Need to query a 16-bit display mode for its pixel-format.  Do this by opening such a screen */
+    {
+        hAmigaWnd = CreateWindowEx (WS_EX_TOPMOST,
+                              "AmigaPowah", VersionStr,
+                              WS_VISIBLE | WS_POPUP,
+                              CW_USEDEFAULT, CW_USEDEFAULT,
+                              1,//GetSystemMetrics (SM_CXSCREEN),
+                              1,//GetSystemMetrics (SM_CYSCREEN),
+                              0, NULL, 0, NULL);
+        if( hAmigaWnd )
+        {
+            window_created = 1;
+            ddrval = DirectDraw_SetCooperativeLevel( hAmigaWnd, TRUE ); /* TRUE indicates full-screen */
+            if( ddrval != DD_OK )
+            {
+               gui_message( "WIN32GFX_FigurePixelFormats: ERROR - %s\n", DXError(ddrval) );
+               goto out;
+            }
+        }
+        else
+        {
+            gui_message( "WIN32GFX_FigurePixelFormats: ERROR - test-window could not be created.\n" );
+        }
+    }
+    else
+    {
+        got_16bit_mode = 1;
+    }
+
+    i = 0;
+    while (DisplayModes[i].depth >= 0) {
+       dm = &DisplayModes[i++];
+        if (!got_16bit_mode) {
+           write_log ("figure_pixel_formats: Attempting %dx%d..\n", dm->res.width, dm->res.height);
+
+            ddrval = DirectDraw_SetDisplayMode( dm->res.width, dm->res.height, 16, 0 ); /* 0 for default freq */
+           if (ddrval != DD_OK)
+               continue;
+
+           ddrval = DirectDraw_GetDisplayMode();
+           if (ddrval != DD_OK)
+               continue;
+
+           colortype = DirectDraw_GetPixelFormat();
+           if (colortype != RGBFB_NONE)  {
+                /* Clear the 16-bit information, and get the real stuff! */
+                dm->colormodes &= ~(RGBFF_R5G6B5PC|RGBFF_R5G5B5PC|RGBFF_R5G6B5|RGBFF_R5G5B5|RGBFF_B5G6R5PC|RGBFF_B5G5R5PC);
+                dm->colormodes |= 1 << colortype;
+                got_16bit_mode = 1;
+                write_log( "Got real 16-bit colour-depth information: 0x%x\n", colortype );
+            }
+        } else if (dm->colormodes & (RGBFF_R5G6B5PC|RGBFF_R5G5B5PC|RGBFF_R5G6B5|RGBFF_R5G5B5|RGBFF_B5G6R5PC|RGBFF_B5G5R5PC) )  {
+            /* Clear the 16-bit information, and set the real stuff! */
+            dm->colormodes &= ~(RGBFF_R5G6B5PC|RGBFF_R5G5B5PC|RGBFF_R5G6B5|RGBFF_R5G5B5|RGBFF_B5G6R5PC|RGBFF_B5G5R5PC);
+            dm->colormodes |= 1 << colortype;
+        }
+    }
+
+    out:
+    if (window_created)
+    {
+        Sleep (1000);
+        DestroyWindow (hAmigaWnd);
+       hAmigaWnd = NULL;
+    }
+    DirectDraw_Release ();
+    return colortype;
+}
+
+/* DirectX will fail with "Mode not supported" if we try to switch to a full
+ * screen mode that doesn't match one of the dimensions we got during enumeration.
+ * So try to find a best match for the given resolution in our list.  */
+int WIN32GFX_AdjustScreenmode( uae_u32 *pwidth, uae_u32 *pheight, uae_u32 *ppixbits )
+{
+    struct PicassoResolution *best;
+    uae_u32 selected_mask = (*ppixbits == 8 ? RGBMASK_8BIT
+                            : *ppixbits == 15 ? RGBMASK_15BIT
+                            : *ppixbits == 16 ? RGBMASK_16BIT
+                            : *ppixbits == 24 ? RGBMASK_24BIT
+                            : RGBMASK_32BIT);
+    int pass, i = 0, index = 0;
+    
+    for (pass = 0; pass < 2; pass++) 
+    {
+       struct PicassoResolution *dm;
+       uae_u32 mask = (pass == 0
+                       ? selected_mask
+                       : RGBMASK_8BIT | RGBMASK_15BIT | RGBMASK_16BIT | RGBMASK_24BIT | RGBMASK_32BIT); /* %%% - BERND, were you missing 15-bit here??? */
+        i = 0;
+        index = 0;
+
+       best = &DisplayModes[0];
+       dm = &DisplayModes[1];
+
+       while (dm->depth >= 0) 
+        {
+           if ((dm->colormodes & mask) != 0) 
+            {
+               if (dm->res.width <= best->res.width && dm->res.height <= best->res.height
+                   && dm->res.width >= *pwidth && dm->res.height >= *pheight)
+                {
+                   best = dm;
+                    index = i;
+                }
+               if (dm->res.width >= best->res.width && dm->res.height >= best->res.height
+                   && dm->res.width <= *pwidth && dm->res.height <= *pheight)
+                {
+                   best = dm;
+                    index = i;
+                }
+           }
+           dm++;
+            i++;
+       }
+       if (best->res.width == *pwidth && best->res.height == *pheight)
+        {
+            selected_mask = mask; /* %%% - BERND, I added this - does it make sense?  Otherwise, I'd specify a 16-bit display-mode for my
+                                    Workbench (using -H 2, but SHOULD have been -H 1), and end up with an 8-bit mode instead*/
+           break;
+        }
+    }
+    *pwidth = best->res.width;
+    *pheight = best->res.height;
+    if( best->colormodes & selected_mask )
+       return index;
+
+    /* Ordering here is done such that 16-bit is preferred, followed by 15-bit, 8-bit, 32-bit and 24-bit */
+    if (best->colormodes & RGBMASK_16BIT)
+       *ppixbits = 16;
+    else if (best->colormodes & RGBMASK_15BIT) /* %%% - BERND, this possibility was missing? */
+       *ppixbits = 15;
+    else if (best->colormodes & RGBMASK_8BIT)
+       *ppixbits = 8;
+    else if (best->colormodes & RGBMASK_32BIT)
+       *ppixbits = 32;
+    else if (best->colormodes & RGBMASK_24BIT)
+       *ppixbits = 24;
+    else
+        index = -1;
+
+    return index;
+}
+
+// This function is only called for full-screen Amiga screen-modes, and simply flips
+// the front and back buffers.  Additionally, because the emulation is not always drawing
+// complete frames, we also need to update the back-buffer with the new contents we just
+// flipped to.  Thus, after our flip, we blit.
+static int DX_Flip( void )
+{
+    int result = 0;
+
+    result = DirectDraw_Flip(0);
+    if( result )
+    {
+//     result = DirectDraw_BltFast( primary_surface, 0, 0, secondary_surface, NULL );
+//     result = DirectDraw_BltFast( primary_surface, 0, 0, tertiary_surface, NULL );
+//     result = DirectDraw_BltFast( secondary_surface, 0, 0, primary_surface, NULL );
+//     result = DirectDraw_BltFast( secondary_surface, 0, 0, tertiary_surface, NULL );
+       result = DirectDraw_BltFast( tertiary_surface, 0, 0, primary_surface, NULL );
+//     result = DirectDraw_BltFast( tertiary_surface, 0, 0, secondary_surface, NULL );
+    }
+    return result;
+}
+
+void flush_line( int lineno )
+{
+
+}
+
+void flush_block (int a, int b)
+{
+
+}
+
+void flush_screen (int a, int b)
+{
+    if (currentmode->flags & DM_OPENGL) {
+#ifdef OPENGL
+       OGL_render ();
+#endif
+    } else if (currentmode->flags & DM_D3D) {
+       return;
+    } else if (currentmode->flags & DM_SWSCALE) {
+       S2X_render ();
+       if( currentmode->flags & DM_DX_FULLSCREEN )
+           DX_Flip ();
+       else if(DirectDraw_GetLockableType() != overlay_surface)
+           DX_Blit( 0, 0, 0, 0, WIN32GFX_GetWidth(), WIN32GFX_GetHeight(), BLIT_SRC );
+    } else if((currentmode->flags & DM_DDRAW) && DirectDraw_GetLockableType() == secondary_surface ) {
+       if( currentmode->flags & DM_DX_FULLSCREEN ) {
+           if( turbo_emulation || DX_Flip() == 0 )
+               DX_Blit (0, a, 0, a, currentmode->current_width, b - a + 1, BLIT_SRC);
+       } else if(DirectDraw_GetLockableType() != overlay_surface)
+           DX_Blit (0, a, 0, a, currentmode->current_width, b - a + 1, BLIT_SRC);
+    }
+}
+
+static uae_u8 *ddraw_dolock (void)
+{
+    static char *surface = NULL, *oldsurface;
+
+    if( !DirectDraw_SurfaceLock( lockable_surface ) )
+       return 0;
+
+    surface = DirectDraw_GetSurfacePointer();
+    oldsurface = gfxvidinfo.bufmem;
+    gfxvidinfo.bufmem = surface;
+    if (surface != oldsurface && !screen_is_picasso) 
+    {
+       init_row_map ();
+    }
+
+    clear_inhibit_frame (IHF_WINDOWHIDDEN);
+    return surface;
+}
+
+int lockscr (void)
+{
+    if (!isscreen ())
+       return 0;
+    if (currentmode->flags & DM_D3D) {
+#ifdef D3D
+       return D3D_locktexture ();
+#endif
+    } else if (currentmode->flags & DM_SWSCALE) {
+       return 1;
+    } else if (currentmode->flags & DM_DDRAW) {
+       return ddraw_dolock() != 0;
+    }
+    return 1;
+}
+
+void unlockscr (void)
+{
+    if (currentmode->flags & DM_D3D) {
+#ifdef D3D
+       D3D_unlocktexture ();
+#endif
+    } else if (currentmode->flags & DM_SWSCALE) {
+       return;
+    } else if (currentmode->flags & DM_DDRAW) {
+       ddraw_unlockscr ();
+    }
+}
+
+void flush_clear_screen (void)
+{
+    if (WIN32GFX_IsPicassoScreen())
+       return;
+    if (lockscr ()) {
+       int y;
+       for (y = 0; y < gfxvidinfo.height; y++) {
+           memset (gfxvidinfo.bufmem + y * gfxvidinfo.rowbytes, 0, gfxvidinfo.width * gfxvidinfo.pixbytes);
+       }
+       unlockscr ();
+       flush_screen (0, 0);
+    }
+}
+
+uae_u8 *gfx_lock_picasso (void)
+{
+    return ddraw_dolock ();
+}
+
+void gfx_unlock_picasso (void)
+{
+    DirectDraw_SurfaceUnlock();
+    if( p96_double_buffer_needs_flushing )
+    {
+       /* Here, our flush_block() will deal with a offscreen-plain (back-buffer) to visible-surface (front-buffer) */
+        if( DirectDraw_GetLockableType() == secondary_surface )
+       {
+           BOOL relock = FALSE;
+           if( DirectDraw_IsLocked() )
+           {
+               relock = TRUE;
+               unlockscr();
+           }
+           DX_Blit( 0, p96_double_buffer_first, 
+                    0, p96_double_buffer_first, 
+                    currentmode->current_width, p96_double_buffer_last - p96_double_buffer_first + 1, 
+                    BLIT_SRC );
+           if( relock )
+           {
+               lockscr();
+           }
+       }
+        p96_double_buffer_needs_flushing = 0;
+    }
+}
+
+void restore_desktop (void)
+{
+    if (currentmode->flags & DM_W_FULLSCREEN) {
+        ChangeDisplaySettings (NULL, 0);
+        ShowWindow (hAmigaWnd, SW_HIDE);
+    }
+}
+
+static void close_hwnds( void )
+{
+#ifdef AVIOUTPUT
+    AVIOutput_Restart ();
+#endif
+    setmouseactive (0);
+    if (hMainWnd)
+       systray(hMainWnd, TRUE);
+    if (hStatusWnd) {
+        ShowWindow( hStatusWnd, SW_HIDE );
+       DestroyWindow (hStatusWnd);
+    }
+    if (hAmigaWnd) {
+#ifdef OPENGL
+       OGL_free ();
+#endif
+#ifdef D3D
+       D3D_free ();
+#endif
+       if (currentmode->flags & DM_W_FULLSCREEN)
+           ChangeDisplaySettings (NULL, 0);
+        ShowWindow (hAmigaWnd, SW_HIDE);
+       DestroyWindow (hAmigaWnd);
+       if (hAmigaWnd == hMainWnd)
+           hMainWnd = 0;
+       hAmigaWnd = 0;
+    }
+    if (hMainWnd) {
+        ShowWindow (hMainWnd, SW_HIDE);
+       DestroyWindow (hMainWnd);
+    }
+    hMainWnd = 0;
+    hStatusWnd = 0;
+}
+
+static int open_windows (void)
+{
+    int need_fs = 0;
+    int ret, i;
+
+    in_sizemove = 0;
+    updatewinfsmode (&currprefs);
+
+    if( !DirectDraw_Start(displayGUID) )
+       return 0;
+    write_log ("DirectDraw GUID=%s\n", outGUID (displayGUID));
+
+#ifdef PICASSO96
+    if (screen_is_picasso) {
+       currentmode->current_width = picasso_vidinfo.width;
+       currentmode->current_height = picasso_vidinfo.height;
+       currentmode->current_depth = rgbformat_bits (picasso_vidinfo.selected_rgbformat);
+       currentmode->frequency = currprefs.gfx_refreshrate > default_freq ? currprefs.gfx_refreshrate : default_freq;
+    } else {
+#endif
+       currentmode->current_width = currprefs.gfx_width;
+       currentmode->current_height = currprefs.gfx_height;
+       currentmode->current_depth = (currprefs.color_mode == 0 ? 8
+                        : currprefs.color_mode == 1 ? 15
+                        : currprefs.color_mode == 2 ? 16
+                        : currprefs.color_mode == 3 ? 8
+                        : currprefs.color_mode == 4 ? 8 : 32);
+       currentmode->frequency = currprefs.gfx_refreshrate;
+#ifdef PICASSO96
+    }
+#endif
+    currentmode->amiga_width = currentmode->current_width;
+    currentmode->amiga_height = currentmode->current_height;
+
+    do {
+       ret = doInit ();
+    } while (ret < 0);
+
+    setmouseactive (1);
+    for (i = 0; i < NUM_LEDS; i++)
+       gui_led (i, 0);
+    gui_fps (0, 0);
+
+    return ret;
+}
+
+int check_prefs_changed_gfx (void)
+{
+    int c = 0;
+
+    c |= currprefs.gfx_width_fs != changed_prefs.gfx_width_fs ? 1 : 0;
+    c |= currprefs.gfx_height_fs != changed_prefs.gfx_height_fs ? 1 : 0;
+    c |= currprefs.gfx_width_win != changed_prefs.gfx_width_win ? 2 : 0;
+    c |= currprefs.gfx_height_win != changed_prefs.gfx_height_win ? 2 : 0;
+    c |= currprefs.color_mode != changed_prefs.color_mode ? 1 : 0;
+    c |= currprefs.gfx_afullscreen != changed_prefs.gfx_afullscreen ? 2 : 0;
+    c |= currprefs.gfx_pfullscreen != changed_prefs.gfx_pfullscreen ? 2 : 0;
+    c |= currprefs.gfx_vsync != changed_prefs.gfx_vsync ? 2 : 0;
+    c |= currprefs.gfx_refreshrate != changed_prefs.gfx_refreshrate? 1 : 0;
+    c |= currprefs.gfx_filter != changed_prefs.gfx_filter? 1 : 0;
+    c |= currprefs.gfx_filter_filtermode != changed_prefs.gfx_filter_filtermode? 1 : 0;
+    c |= currprefs.gfx_lores != changed_prefs.gfx_lores? 1 : 0;
+    c |= currprefs.gfx_linedbl != changed_prefs.gfx_linedbl? 1 : 0;
+    c |= currprefs.gfx_display != changed_prefs.gfx_display? 1 : 0;
+    if (display_change_requested || c) 
+    {
+       display_change_requested = 0;
+       fixup_prefs_dimensions (&changed_prefs);
+       currprefs.gfx_width_win = changed_prefs.gfx_width_win;
+       currprefs.gfx_height_win = changed_prefs.gfx_height_win;
+       currprefs.gfx_width_fs = changed_prefs.gfx_width_fs;
+       currprefs.gfx_height_fs = changed_prefs.gfx_height_fs;
+       currprefs.color_mode = changed_prefs.color_mode;
+        currprefs.gfx_afullscreen = changed_prefs.gfx_afullscreen;
+        currprefs.gfx_pfullscreen = changed_prefs.gfx_pfullscreen;
+        updatewinfsmode (&currprefs);
+        currprefs.gfx_vsync = changed_prefs.gfx_vsync;
+        currprefs.gfx_refreshrate = changed_prefs.gfx_refreshrate;
+       currprefs.gfx_filter = changed_prefs.gfx_filter;
+       currprefs.gfx_filter_filtermode = changed_prefs.gfx_filter_filtermode;
+       currprefs.gfx_lores = changed_prefs.gfx_lores;
+       currprefs.gfx_linedbl = changed_prefs.gfx_linedbl;
+       currprefs.gfx_display = changed_prefs.gfx_display;
+        inputdevice_unacquire ();
+       close_windows ();
+       graphics_init ();
+#ifdef PICASSO96
+       DX_SetPalette (0, 256);
+#endif
+       init_hz ();
+       pause_sound ();
+       resume_sound ();
+       inputdevice_acquire (mouseactive);
+       return 1;
+    }
+    if (currprefs.gfx_correct_aspect != changed_prefs.gfx_correct_aspect ||
+       currprefs.gfx_xcenter != changed_prefs.gfx_xcenter ||
+       currprefs.gfx_ycenter != changed_prefs.gfx_ycenter)
+    {
+       currprefs.gfx_correct_aspect = changed_prefs.gfx_correct_aspect;
+       currprefs.gfx_xcenter = changed_prefs.gfx_xcenter;
+       currprefs.gfx_ycenter = changed_prefs.gfx_ycenter;
+       return 1;
+    }
+
+    if (currprefs.leds_on_screen != changed_prefs.leds_on_screen ||
+        currprefs.keyboard_leds[0] != changed_prefs.keyboard_leds[0] ||
+        currprefs.keyboard_leds[1] != changed_prefs.keyboard_leds[1] ||
+        currprefs.keyboard_leds[2] != changed_prefs.keyboard_leds[2] ||
+        currprefs.win32_middle_mouse != changed_prefs.win32_middle_mouse ||
+       currprefs.win32_active_priority != changed_prefs.win32_active_priority ||
+       currprefs.win32_inactive_priority != changed_prefs.win32_inactive_priority ||
+       currprefs.win32_iconified_priority != changed_prefs.win32_iconified_priority ||
+       currprefs.win32_inactive_nosound != changed_prefs.win32_inactive_nosound ||
+       currprefs.win32_inactive_pause != changed_prefs.win32_inactive_pause ||
+       currprefs.win32_iconified_nosound != changed_prefs.win32_iconified_nosound ||
+       currprefs.win32_iconified_pause != changed_prefs.win32_iconified_pause ||
+       currprefs.win32_ctrl_F11_is_quit != changed_prefs.win32_ctrl_F11_is_quit)
+    {
+        currprefs.leds_on_screen = changed_prefs.leds_on_screen;
+        currprefs.keyboard_leds[0] = changed_prefs.keyboard_leds[0];
+        currprefs.keyboard_leds[1] = changed_prefs.keyboard_leds[1];
+        currprefs.keyboard_leds[2] = changed_prefs.keyboard_leds[2];
+        currprefs.win32_middle_mouse = changed_prefs.win32_middle_mouse;
+       currprefs.win32_active_priority = changed_prefs.win32_active_priority;
+       currprefs.win32_inactive_priority = changed_prefs.win32_inactive_priority;
+       currprefs.win32_iconified_priority = changed_prefs.win32_iconified_priority;
+       currprefs.win32_inactive_nosound = changed_prefs.win32_inactive_nosound;
+       currprefs.win32_inactive_pause = changed_prefs.win32_inactive_pause;
+       currprefs.win32_iconified_nosound = changed_prefs.win32_iconified_nosound;
+       currprefs.win32_iconified_pause = changed_prefs.win32_iconified_pause;
+       currprefs.win32_ctrl_F11_is_quit = changed_prefs.win32_ctrl_F11_is_quit;
+        inputdevice_unacquire ();
+        currprefs.keyboard_leds_in_use = currprefs.keyboard_leds[0] | currprefs.keyboard_leds[1] | currprefs.keyboard_leds[2];
+       pause_sound ();
+       resume_sound ();
+       inputdevice_acquire (mouseactive);
+#ifndef _DEBUG
+       setpriority (priorities[currprefs.win32_active_priority].value);
+#endif
+       return 1;
+    }
+
+    if (strcmp (currprefs.prtname, changed_prefs.prtname)) {
+       strcpy (currprefs.prtname, changed_prefs.prtname);
+#ifdef PARALLEL_PORT
+       closeprinter ();
+#endif
+    }
+    if (strcmp (currprefs.sername, changed_prefs.sername) || 
+       currprefs.serial_hwctsrts != changed_prefs.serial_hwctsrts ||
+       currprefs.serial_direct != changed_prefs.serial_direct ||
+       currprefs.serial_demand != changed_prefs.serial_demand) {
+       strcpy (currprefs.sername, changed_prefs.sername);
+       currprefs.serial_hwctsrts = changed_prefs.serial_hwctsrts;
+       currprefs.serial_demand = changed_prefs.serial_demand;
+       currprefs.serial_direct = changed_prefs.serial_direct;
+#ifdef SERIAL_PORT
+       serial_exit ();
+       serial_init ();
+#endif
+    }
+    if (currprefs.win32_midiindev != changed_prefs.win32_midiindev ||
+        currprefs.win32_midioutdev != changed_prefs.win32_midioutdev)
+    {
+       currprefs.win32_midiindev = changed_prefs.win32_midiindev;
+       currprefs.win32_midioutdev = changed_prefs.win32_midioutdev;
+#ifdef SERIAL_PORT
+       if (midi_ready) {
+           Midi_Close ();
+           Midi_Open ();
+       }
+#endif
+    }
+
+    if (currprefs.win32_automount_drives != changed_prefs.win32_automount_drives) {
+       currprefs.win32_automount_drives = changed_prefs.win32_automount_drives;
+    }
+    return 0;
+}
+
+/* Color management */
+
+static xcolnr xcol8[4096];
+static PALETTEENTRY colors256[256];
+static int ncols256 = 0;
+
+static int red_bits, green_bits, blue_bits, alpha_bits;
+static int red_shift, green_shift, blue_shift, alpha_shift;
+static int alpha;
+
+static int get_color (int r, int g, int b, xcolnr * cnp)
+{
+    if (ncols256 == 256)
+       return 0;
+    colors256[ncols256].peRed = r * 0x11;
+    colors256[ncols256].peGreen = g * 0x11;
+    colors256[ncols256].peBlue = b * 0x11;
+    colors256[ncols256].peFlags = 0;
+    *cnp = ncols256;
+    ncols256++;
+    return 1;
+}
+
+void init_colors (void)
+{
+    int i;
+    HRESULT ddrval;
+
+    if (ncols256 == 0) {
+       alloc_colors256 (get_color);
+       memcpy (xcol8, xcolors, sizeof xcol8);
+    }
+
+    /* init colors */
+    if (currentmode->flags & DM_OPENGL) {
+#ifdef OPENGL
+       OGL_getpixelformat (currentmode->current_depth,&red_bits,&green_bits,&blue_bits,&red_shift,&green_shift,&blue_shift,&alpha_bits,&alpha_shift,&alpha);
+#endif
+    } else if (currentmode->flags & DM_D3D) {
+#ifdef D3D
+       D3D_getpixelformat (currentmode->current_depth,&red_bits,&green_bits,&blue_bits,&red_shift,&green_shift,&blue_shift,&alpha_bits,&alpha_shift,&alpha);
+#endif
+    } else {
+       switch( currentmode->current_depth >> 3)
+       {
+           case 1:
+               memcpy (xcolors, xcol8, sizeof xcolors);
+               ddrval = DirectDraw_SetPaletteEntries( 0, 256, colors256 );
+               if (ddrval != DD_OK)
+                   write_log ("DX_SetPalette() failed with %s/%d\n", DXError (ddrval), ddrval);
+           break;
+
+           case 2:
+           case 3:
+           case 4:
+               red_bits = bits_in_mask( DirectDraw_GetPixelFormatBitMask( red_mask ) );
+               green_bits = bits_in_mask( DirectDraw_GetPixelFormatBitMask( green_mask ) );
+               blue_bits = bits_in_mask( DirectDraw_GetPixelFormatBitMask( blue_mask ) );
+               red_shift = mask_shift( DirectDraw_GetPixelFormatBitMask( red_mask ) );
+               green_shift = mask_shift( DirectDraw_GetPixelFormatBitMask( green_mask ) );
+               blue_shift = mask_shift( DirectDraw_GetPixelFormatBitMask( blue_mask ) );
+               alpha_bits = 0;
+               alpha_shift = 0;
+           break;
+       }
+    }
+    if (currentmode->current_depth > 8) {
+       if (!(currentmode->flags & DM_OPENGL|DM_D3D)) {
+           if (currentmode->current_depth != currentmode->real_depth) {
+               if (currentmode->current_depth == 16) {
+                   red_bits = 5; green_bits = 6; blue_bits = 5;
+                   red_shift = 11; green_shift = 5; blue_shift = 0;
+               } else {
+                   red_bits = green_bits = blue_bits = 8;
+                   red_shift = 16; green_shift = 8; blue_shift = 0;
+               }
+           }           
+       }
+       alloc_colors64k (red_bits, green_bits, blue_bits, red_shift,green_shift, blue_shift, alpha_bits, alpha_shift, alpha);
+       S2X_configure (red_bits, green_bits, blue_bits, red_shift,green_shift, blue_shift);
+#ifdef AVIOUTPUT
+       AVIOutput_RGBinfo (red_bits, green_bits, blue_bits, red_shift, green_shift, blue_shift);
+#endif
+    }
+    
+    switch (gfxvidinfo.pixbytes) 
+    {
+     case 2:
+       for (i = 0; i < 4096; i++)
+           xcolors[i] = xcolors[i] * 0x00010001;
+       gfxvidinfo.can_double = 1;
+       break;
+     case 1:
+       for (i = 0; i < 4096; i++)
+           xcolors[i] = xcolors[i] * 0x01010101;
+       gfxvidinfo.can_double = 1;
+       break;
+     default:
+       gfxvidinfo.can_double = 0;
+       break;
+    }
+}
+
+#ifdef PICASSO96
+void DX_SetPalette_vsync (void)
+{
+}
+
+void DX_SetPalette (int start, int count)
+{
+    HRESULT ddrval;
+
+    if (!screen_is_picasso)
+        return;
+
+    if( picasso96_state.RGBFormat != RGBFB_CHUNKY )
+        return;
+
+    if (picasso_vidinfo.pixbytes != 1) 
+    {
+       /* write_log ("DX Setpalette emulation\n"); */
+       /* This is the case when we're emulating a 256 color display.  */
+       while (count-- > 0) 
+        {
+           int r = picasso96_state.CLUT[start].Red;
+           int g = picasso96_state.CLUT[start].Green;
+           int b = picasso96_state.CLUT[start].Blue;
+           picasso_vidinfo.clut[start++] = (doMask256 (r, red_bits, red_shift)
+               | doMask256 (g, green_bits, green_shift)
+               | doMask256 (b, blue_bits, blue_shift));
+       }
+       notice_screen_contents_lost();
+       return;
+    }
+
+    /* Set our DirectX palette here */
+    if( currentmode->current_depth == 8 )
+    {
+       if (DirectDraw_SetPalette( 0 ) == DD_OK) {
+           ddrval = DirectDraw_SetPaletteEntries( start, count, (LPPALETTEENTRY)&(picasso96_state.CLUT[start] ) );
+           if (ddrval != DD_OK)
+               gui_message("DX_SetPalette() failed with %s/%d\n", DXError (ddrval), ddrval);
+       }
+    }
+    else
+    {
+       write_log ("ERROR - DX_SetPalette() pixbytes %d\n", currentmode->current_depth >> 3 );
+    }
+}
+
+void DX_Invalidate (int first, int last)
+{
+    p96_double_buffer_first = first;
+    if(last >= picasso_vidinfo.height )
+       last = picasso_vidinfo.height - 1;
+    p96_double_buffer_last  = last;
+    p96_double_buffer_needs_flushing = 1;
+}
+
+#endif
+
+int DX_BitsPerCannon (void)
+{
+    return 8;
+}
+
+static COLORREF BuildColorRef( int color, RGBFTYPE pixelformat )
+{
+    COLORREF result;
+
+    /* Do special case first */
+    if( pixelformat == RGBFB_CHUNKY )
+        result = color;
+    else
+        result = do_get_mem_long( &color );
+    return result;
+#if 0
+    int r,g,b;
+    write_log( "DX_Blit() called to fill with color of 0x%x, rgbtype of 0x%x\n", color, pixelformat );
+
+    switch( pixelformat )
+    {
+        case RGBFB_R5G6B5PC:
+            r = color & 0xF800 >> 11;
+            g = color & 0x07E0 >> 5;
+            b = color & 0x001F;
+        break;
+        case RGBFB_R5G5B5PC:
+            r = color & 0x7C00 >> 10;
+            g = color & 0x03E0 >> 5;
+            b = color & 0x001F;
+        break;
+        case RGBFB_B5G6R5PC:
+            r = color & 0x001F;
+            g = color & 0x07E0 >> 5;
+            b = color & 0xF800 >> 11;
+        break;
+        case RGBFB_B5G5R5PC:
+            r = color & 0x001F;
+            g = color & 0x03E0 >> 5;
+            b = color & 0x7C00 >> 10;
+        break;
+        case RGBFB_B8G8R8:
+            r = color & 0x00FF0000 >> 16;
+            g = color & 0x0000FF00 >> 8;
+            b = color & 0x000000FF;
+        break;
+        case RGBFB_A8B8G8R8:
+            r = color & 0xFF000000 >> 24;
+            g = color & 0x00FF0000 >> 16;
+            b = color & 0x0000FF00 >> 8;
+        break;
+        case RGBFB_R8G8B8:
+            r = color & 0x000000FF;
+            g = color & 0x0000FF00 >> 8;
+            b = color & 0x00FF0000 >> 16;
+        break;
+        case RGBFB_A8R8G8B8:
+            r = color & 0x0000FF00 >> 8;
+            g = color & 0x00FF0000 >> 16;
+            b = color & 0xFF000000 >> 24;
+        break;
+        default:
+            write_log( "Uknown 0x%x pixel-format\n", pixelformat );
+        break;
+    }
+    result = RGB(r,g,b);
+    write_log( "R = 0x%02x, G = 0x%02x, B = 0x%02x - result = 0x%08x\n", r, g, b, result );
+    return result;
+#endif
+}
+
+/* This is a general purpose DirectDrawSurface filling routine.  It can fill within primary surface.
+ * Definitions:
+ * - primary is the displayed (visible) surface in VRAM, which may have an associated offscreen surface (or back-buffer)
+ */
+int DX_Fill( int dstx, int dsty, int width, int height, uae_u32 color, RGBFTYPE rgbtype )
+{
+    int result = 0;
+    RECT dstrect;
+    RECT srcrect;
+    DDBLTFX ddbltfx;
+    memset( &ddbltfx, 0, sizeof( ddbltfx ) );
+    ddbltfx.dwFillColor = BuildColorRef( color, rgbtype );
+    ddbltfx.dwSize = sizeof( ddbltfx );
+
+    /* Set up our source rectangle.  This NEVER needs to be adjusted for windowed display, since the
+     * source is ALWAYS in an offscreen buffer, or we're in full-screen mode. */
+    SetRect( &srcrect, dstx, dsty, dstx+width, dsty+height );
+
+    /* Set up our destination rectangle, and adjust for blit to windowed display (if necessary ) */
+    SetRect( &dstrect, dstx, dsty, dstx+width, dsty+height );
+    if( !(currentmode->flags & (DM_DX_FULLSCREEN | DM_OVERLAY)))
+       OffsetRect( &dstrect, amigawin_rect.left, amigawin_rect.top );
+
+    /* Render our fill to the visible (primary) surface */
+    if( ( result = DirectDraw_Blt( primary_surface, &dstrect, invalid_surface, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx ) ) )
+    {
+       if( DirectDraw_GetLockableType() == secondary_surface )
+       {
+           /* We've colour-filled the visible, but still need to colour-fill the offscreen */
+           result = DirectDraw_Blt( secondary_surface, &srcrect, invalid_surface, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx );
+       }
+    }
+    return result;
+}
+
+/* This is a general purpose DirectDrawSurface blitting routine.  It can blit within primary surface
+ * Definitions:
+ * - primary is the displayed (visible) surface in VRAM, which may have an associated offscreen surface (or back-buffer)
+ */
+
+static DDBLTFX fx = { sizeof( DDBLTFX ) };
+
+static DWORD BLIT_OPCODE_TRANSLATION[ BLIT_LAST ] =
+{
+    BLACKNESS,  /* BLIT_FALSE */
+    NOTSRCERASE,/* BLIT_NOR */
+    -1,         /* BLIT_ONLYDST NOT SUPPORTED */
+    NOTSRCCOPY, /* BLIT_NOTSRC */
+    SRCERASE,   /* BLIT_ONLYSRC */
+    DSTINVERT,  /* BLIT_NOTDST */
+    SRCINVERT,  /* BLIT_EOR */
+    -1,         /* BLIT_NAND NOT SUPPORTED */
+    SRCAND,     /* BLIT_AND */
+    -1,         /* BLIT_NEOR NOT SUPPORTED */
+    -1,         /* NO-OP */
+    MERGEPAINT, /* BLIT_NOTONLYSRC */
+    SRCCOPY,    /* BLIT_SRC */
+    -1,         /* BLIT_NOTONLYDST NOT SUPPORTED */
+    SRCPAINT,   /* BLIT_OR */
+    WHITENESS   /* BLIT_TRUE */
+};
+
+int DX_Blit( int srcx, int srcy, int dstx, int dsty, int width, int height, BLIT_OPCODE opcode )
+{
+    int result = 0;
+    RECT dstrect;
+    RECT srcrect;
+    DWORD dwROP = BLIT_OPCODE_TRANSLATION[ opcode ];
+
+    /* Set up our source rectangle.  This NEVER needs to be adjusted for windowed display, since the
+     * source is ALWAYS in an offscreen buffer, or we're in full-screen mode. */
+    SetRect( &srcrect, srcx, srcy, srcx+width, srcy+height );
+
+    /* Set up our destination rectangle, and adjust for blit to windowed display (if necessary ) */
+    SetRect( &dstrect, dstx, dsty, dstx+width, dsty+height );
+    
+    if( !(currentmode->flags & (DM_DX_FULLSCREEN | DM_OVERLAY)))
+        OffsetRect( &dstrect, amigawin_rect.left, amigawin_rect.top );
+
+    if( dwROP == -1 )
+    {
+       /* Unsupported blit opcode! */
+       return 0;
+    }
+    else
+    {
+       fx.dwROP = dwROP;
+    }
+
+    /* Render our blit within the primary surface */
+    result = DirectDraw_Blt( primary_surface, &dstrect, DirectDraw_GetLockableType(), &srcrect, DDBLT_WAIT | DDBLT_ROP, &fx );
+
+    if( !result )
+    {
+       BLIT_OPCODE_TRANSLATION[ opcode ] = -1;
+    }
+    else if( DirectDraw_GetLockableType() == secondary_surface )
+    {
+       /* We've just blitted from the offscreen to the visible, but still need to blit from offscreen to offscreen
+        * NOTE: reset our destination rectangle again if its been modified above... */
+       if( ( srcx != dstx ) || ( srcy != dsty ) )
+       {
+           if(!(currentmode->flags & DM_DX_FULLSCREEN))
+               SetRect( &dstrect, dstx, dsty, dstx+width, dsty+height );
+            result = DirectDraw_Blt( secondary_surface, &dstrect, secondary_surface, &srcrect, DDBLT_WAIT | DDBLT_ROP, &fx );
+       }
+    }
+
+    return result;
+}
+
+void DX_WaitVerticalSync( void )
+{
+    DirectDraw_WaitForVerticalBlank (DDWAITVB_BLOCKBEGIN);
+}
+
+uae_u32 DX_ShowCursor( uae_u32 activate )
+{
+    uae_u32 result = 0;
+    if( ShowCursor( activate ) > 0 )
+       result = 1;
+    return result;
+}
+
+uae_u32 DX_MoveCursor( uae_u32 x, uae_u32 y )
+{
+    uae_u32 result = 0;
+
+    // We may need to adjust the x,y values for our window-offset
+    if(!(currentmode->flags & DM_DX_FULLSCREEN))
+    {
+       RECT rect;
+       if( GetWindowRect( hAmigaWnd, &rect ) )
+       {
+           x = rect.left + x;
+           y = rect.top + y;
+       }
+    }
+    if( SetCursorPos( x, y ) )
+       result = 1;
+    return result;
+}
+
+static void open_screen( void )
+{
+    close_windows ();
+    open_windows();
+#ifdef PICASSO96
+    DX_SetPalette (0, 256);
+#endif
+}
+
+#ifdef PICASSO96
+void gfx_set_picasso_state( int on )
+{
+    if (screen_is_picasso == on)
+       return;
+    screen_is_picasso = on;
+    open_screen();
+}
+
+void gfx_set_picasso_modeinfo( uae_u32 w, uae_u32 h, uae_u32 depth, RGBFTYPE rgbfmt )
+{
+    depth >>= 3;
+    if( ((unsigned)picasso_vidinfo.width == w ) &&
+           ( (unsigned)picasso_vidinfo.height == h ) &&
+           ( (unsigned)picasso_vidinfo.depth == depth ) &&
+           ( picasso_vidinfo.selected_rgbformat == rgbfmt) )
+       return;
+
+    picasso_vidinfo.selected_rgbformat = rgbfmt;
+    picasso_vidinfo.width = w;
+    picasso_vidinfo.height = h;
+    picasso_vidinfo.depth = depth;
+    picasso_vidinfo.extra_mem = 1;
+
+    if( screen_is_picasso ) 
+    {
+       open_screen();
+    }
+}
+#endif
+
+static void gfxmode_reset (void)
+{
+    usedfilter = 0;
+    if (currprefs.gfx_filter > 0) {
+       int i = 0;
+       while (uaefilters[i].name) {
+           if (uaefilters[i].type == currprefs.gfx_filter) {
+               usedfilter = &uaefilters[i];
+               break;
+           }
+           i++;
+       }
+    }
+    currentmode->amode[0] = &wmodes[currprefs.win32_no_overlay ? SM_WINDOW : SM_WINDOW_OVERLAY];
+    currentmode->amode[1] = &wmodes[SM_FULLSCREEN_DX];
+    currentmode->pmode[0] = &wmodes[currprefs.win32_no_overlay ? SM_WINDOW : SM_WINDOW_OVERLAY];
+    currentmode->pmode[1] = &wmodes[SM_FULLSCREEN_DX];
+#ifdef OPENGL
+    if (usedfilter && usedfilter->type == UAE_FILTER_OPENGL) {
+       currentmode->amode[0] = &wmodes[SM_OPENGL_WINDOW];
+       currentmode->amode[1] = &wmodes[SM_OPENGL_FULLSCREEN_W];
+    }
+#endif
+#ifdef D3D
+    if (usedfilter && usedfilter->type == UAE_FILTER_DIRECT3D) {
+       currentmode->amode[0] = &wmodes[SM_D3D_WINDOW];
+       currentmode->amode[1] = &wmodes[SM_D3D_FULLSCREEN_DX];
+    }
+#endif
+}
+
+void machdep_init (void)
+{
+    picasso_requested_on = 0;
+    picasso_on = 0;
+    screen_is_picasso = 0;
+    memset (currentmode, 0, sizeof (*currentmode));
+}
+
+int graphics_init (void)
+{
+    gfxmode_reset ();
+    return open_windows ();
+}
+
+int graphics_setup (void)
+{
+    if( !DirectDraw_Start (NULL) )
+       return 0;
+    DirectDraw_Release();
+#ifdef PICASSO96
+    InitPicasso96();
+#endif
+    return 1;
+}
+
+void graphics_leave (void)
+{
+    close_windows ();
+    dumpcustom ();
+}
+
+uae_u32 OSDEP_minimize_uae( void )
+{
+    return ShowWindow (hAmigaWnd, SW_MINIMIZE);
+}
+
+void close_windows (void)
+{
+    free (gfxvidinfo.realbufmem);
+    gfxvidinfo.realbufmem = 0;
+    DirectDraw_Release();
+    close_hwnds();
+}
+
+void WIN32GFX_ToggleFullScreen( void )
+{
+    display_change_requested = 1;
+    if (screen_is_picasso)
+       currprefs.gfx_pfullscreen ^= 1;
+    else
+       currprefs.gfx_afullscreen ^= 1;
+}
+
+static int create_windows (void)
+{
+    int fs = currentmode->flags & (DM_W_FULLSCREEN | DM_DX_FULLSCREEN | DM_D3D_FULLSCREEN);
+    if (!fs) 
+    {
+        RECT rc;
+        LONG stored_x = 1, stored_y = GetSystemMetrics( SM_CYMENU ) + GetSystemMetrics( SM_CYBORDER );
+        DWORD regkeytype;
+        DWORD regkeysize = sizeof(LONG);
+        HLOCAL hloc;
+       LPINT lpParts;
+       int cx = GetSystemMetrics(SM_CXBORDER), cy = GetSystemMetrics(SM_CYBORDER);
+       int oldx, oldy;
+
+        RegQueryValueEx( hWinUAEKey, "xPos", 0, &regkeytype, (LPBYTE)&stored_x, &regkeysize );
+        RegQueryValueEx( hWinUAEKey, "yPos", 0, &regkeytype, (LPBYTE)&stored_y, &regkeysize );
+
+       if( stored_x < GetSystemMetrics (SM_XVIRTUALSCREEN) )
+            stored_x = GetSystemMetrics (SM_XVIRTUALSCREEN);
+        if( stored_y < GetSystemMetrics (SM_YVIRTUALSCREEN) + GetSystemMetrics( SM_CYMENU ) + cy)
+            stored_y = GetSystemMetrics (SM_YVIRTUALSCREEN) + GetSystemMetrics( SM_CYMENU ) + cy;
+
+        if( stored_x > GetSystemMetrics( SM_CXVIRTUALSCREEN ) )
+            rc.left = 1;
+        else
+            rc.left = stored_x;
+        
+        if( stored_y > GetSystemMetrics( SM_CYVIRTUALSCREEN ) )
+            rc.top = 1;
+        else
+            rc.top = stored_y;
+
+        rc.right = rc.left + 2 + currentmode->current_width + 2;
+        rc.bottom = rc.top + 2 + currentmode->current_height + 2 + GetSystemMetrics (SM_CYMENU);
+
+       oldx = rc.left;
+       oldy = rc.top;
+       AdjustWindowRect (&rc, NORMAL_WINDOW_STYLE, FALSE);
+       win_x_diff = rc.left - oldx;
+       win_y_diff = rc.top - oldy;
+        hMainWnd = CreateWindowEx( picasso_on ? WS_EX_ACCEPTFILES : WS_EX_ACCEPTFILES | WS_EX_APPWINDOW,
+                                       "PCsuxRox", "WinUAE",
+                                      NORMAL_WINDOW_STYLE  | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
+                                      rc.left, rc.top,
+                                      rc.right - rc.left + 1, rc.bottom - rc.top + 1,
+                                      NULL, NULL, 0, NULL);
+
+       if (! hMainWnd)
+           return 0;
+       hStatusWnd = CreateStatusWindow (WS_CHILD | WS_VISIBLE, "", hMainWnd, 1);
+       if (hStatusWnd) 
+        {
+           GetClientRect (hMainWnd, &rc);
+           /* Allocate an array for holding the right edge coordinates. */
+           hloc = LocalAlloc (LHND, sizeof (int) * LED_NUM_PARTS);
+           if (hloc) 
+            {
+               lpParts = LocalLock (hloc);
+
+               /* Calculate the right edge coordinate for each part, and copy the coords
+                * to the array.  */
+               lpParts[0] = rc.right - (LED_DRIVE_WIDTH * 4) - LED_POWER_WIDTH - LED_IDLE_WIDTH - LED_FPS_WIDTH - LED_CD_WIDTH - LED_HD_WIDTH - 2;
+                lpParts[1] = lpParts[0] + LED_IDLE_WIDTH;
+                lpParts[2] = lpParts[1] + LED_FPS_WIDTH;
+               lpParts[3] = lpParts[2] + LED_POWER_WIDTH;
+               lpParts[4] = lpParts[3] + LED_CD_WIDTH;
+               lpParts[5] = lpParts[4] + LED_HD_WIDTH;
+               lpParts[6] = lpParts[5] + LED_DRIVE_WIDTH;
+               lpParts[7] = lpParts[6] + LED_DRIVE_WIDTH;
+               lpParts[8] = lpParts[7] + LED_DRIVE_WIDTH;
+               lpParts[9] = lpParts[8] + LED_DRIVE_WIDTH;
+
+               /* Create the parts */
+               SendMessage (hStatusWnd, SB_SETPARTS, (WPARAM) LED_NUM_PARTS, (LPARAM) lpParts);
+
+               LocalUnlock (hloc);
+               LocalFree (hloc);
+           }
+       }
+    }
+    else
+       hMainWnd = NULL;
+
+    hAmigaWnd = CreateWindowEx (fs ? WS_EX_ACCEPTFILES | WS_EX_TOPMOST : WS_EX_ACCEPTFILES | WS_EX_APPWINDOW,
+                               "AmigaPowah", "WinUAE",
+                               WS_CLIPCHILDREN | WS_CLIPSIBLINGS | (hMainWnd ? WS_VISIBLE | WS_CHILD : WS_VISIBLE | WS_POPUP),
+                               hMainWnd ? 2 : CW_USEDEFAULT, hMainWnd ? 2 : CW_USEDEFAULT,
+                               currentmode->current_width, currentmode->current_height,
+                               hMainWnd, NULL, 0, NULL);
+    
+    if (! hAmigaWnd) 
+    {
+        close_hwnds();
+       return 0;
+    }
+
+
+    systray (hMainWnd, FALSE);
+    if (hMainWnd != hAmigaWnd) {
+       ShowWindow (hMainWnd, SW_SHOWNORMAL);
+        UpdateWindow( hMainWnd );
+    }
+    if (hAmigaWnd) {
+       UpdateWindow (hAmigaWnd);
+       ShowWindow (hAmigaWnd, SW_SHOWNORMAL);
+    }
+
+    return 1;
+}
+
+static void setoverlay(void)
+{
+    RECT sr, dr, statusr;
+    POINT p = {0,0};
+    int maxwidth, maxheight, w, h;
+    HMONITOR hm;
+    MONITORINFO mi;
+
+    hm = MonitorFromWindow (hMainWnd, MONITOR_DEFAULTTONEAREST);
+    mi.cbSize = sizeof (mi);
+    if (!GetMonitorInfo (hm, &mi))
+       return;
+
+    GetClientRect(hMainWnd, &dr);
+    // adjust the dest-rect to avoid the status-bar
+    if( hStatusWnd )
+    {
+       if( GetWindowRect( hStatusWnd, &statusr ) )
+           dr.bottom = dr.bottom - ( statusr.bottom - statusr.top );
+    }
+
+    ClientToScreen( hMainWnd, &p );
+    dr.left = p.x + 2;
+    dr.top = p.y + 2;
+    dr.right += p.x;
+    dr.bottom += p.y;
+    /* overlay's coordinates are relative to monitor's top/left-corner */
+    dr.left -= mi.rcMonitor.left;
+    dr.top -= mi.rcMonitor.top;
+    dr.right -= mi.rcMonitor.left;
+    dr.bottom -= mi.rcMonitor.top;
+
+    w = currentmode->current_width * (currprefs.gfx_filter_horiz_zoom + 100) / 100;
+    h = currentmode->current_height * (currprefs.gfx_filter_vert_zoom + 100) / 100;
+
+    sr.left = 0;
+    sr.top = 0;
+    sr.right = currentmode->current_width;
+    sr.bottom = currentmode->current_height;
+
+    // Adjust our dst-rect to match the dimensions of our src-rect
+    if (dr.right - dr.left > sr.right - sr.left)
+       dr.right = dr.left + sr.right - sr.left;
+    if (dr.bottom - dr.top > sr.bottom - sr.top)
+       dr.bottom = dr.top + sr.bottom - sr.top;
+
+    sr.left = 0;
+    sr.top = 0;
+    sr.right = w;
+    sr.bottom = h;
+
+    maxwidth = mi.rcMonitor.right - mi.rcMonitor.left;
+    if (dr.right > maxwidth) {
+       sr.right = w - (dr.right - maxwidth);
+       dr.right = maxwidth;
+    }
+    maxheight = mi.rcMonitor.bottom - mi.rcMonitor.top;
+    if (dr.bottom > maxheight) {
+       sr.bottom = h - (dr.bottom - maxheight);
+       dr.bottom = maxheight;
+    }
+    if (dr.left < 0) {
+       sr.left = -dr.left;
+       dr.left = 0;
+    }
+    if (dr.top < 0) {
+       sr.top = -dr.top;
+       dr.top = 0;
+    }
+    DirectDraw_UpdateOverlay(sr, dr);
+}
+
+static void updatemodes (void)
+{
+    if (screen_is_picasso) {
+       currentmode->mode = currentmode->pmode[currprefs.gfx_pfullscreen];
+       currentmode->flags = currentmode->mode->pflags;
+    } else {
+       currentmode->mode = currentmode->amode[currprefs.gfx_afullscreen];
+       currentmode->flags = currentmode->mode->aflags;
+    }
+    currentmode->modeindex = currentmode->mode - &wmodes[0];
+
+    currentmode->flags &= ~DM_SWSCALE;
+    if (usedfilter && !usedfilter->x[0]) {
+        currentmode->flags |= DM_SWSCALE;
+        if (currentmode->current_depth < 15)
+           currentmode->current_depth = 16;
+    }
+}
+
+static BOOL doInit (void)
+{
+    int fs_warning = -1;
+    char tmpstr[300];
+    RGBFTYPE colortype;
+    int need_fs = 0;
+    int tmp_depth;
+    int ret = 0;
+    int mult = 0;
+
+    colortype = DirectDraw_GetPixelFormat();
+    gfxmode_reset ();
+
+    for (;;) {
+       updatemodes ();
+       currentmode->real_depth = 0;
+       tmp_depth = currentmode->current_depth;
+
+        write_log("W=%d H=%d B=%d CT=%d\n",
+           DirectDraw_CurrentWidth (), DirectDraw_CurrentHeight (), DirectDraw_GetSurfaceBitCount (), colortype);
+
+       if (currentmode->current_depth < 15 && (currprefs.chipset_mask & CSMASK_AGA) && isfullscreen () && !WIN32GFX_IsPicassoScreen()) {
+           static int warned;
+           if (!warned) {
+               char szMessage[ MAX_PATH ];
+               currentmode->current_depth = 16;
+               WIN32GUI_LoadUIString( IDS_AGA8BIT, szMessage, MAX_PATH );
+               gui_message(szMessage);
+           }
+           warned = 1;
+       }
+
+       if (!(currentmode->flags & DM_OVERLAY) && !isfullscreen() && !(currentmode->flags & (DM_OPENGL | DM_D3D))) {
+           write_log ("using desktop depth (%d -> %d) because not using overlay or opengl mode\n",
+               currentmode->current_depth, DirectDraw_GetSurfaceBitCount());
+           currentmode->current_depth = DirectDraw_GetSurfaceBitCount();
+           updatemodes ();
+       }
+
+       //If screen depth is equal to the desired window_depth then no overlay is needed.
+       if (!(currentmode->flags & (DM_OPENGL | DM_D3D)) && DirectDraw_GetSurfaceBitCount() == (unsigned)currentmode->current_depth) {
+           write_log ("ignored overlay because desktop depth == requested depth (%d)\n", currentmode->current_depth);
+           modefallback (DM_OVERLAY);
+           updatemodes ();
+       }
+    
+       if (colortype == RGBFB_NONE && !(currentmode->flags & DM_OVERLAY)) {
+           fs_warning = IDS_UNSUPPORTEDSCREENMODE_1;
+       } else if (colortype == RGBFB_CLUT && !(currentmode->flags & DM_OVERLAY)) {
+           fs_warning = IDS_UNSUPPORTEDSCREENMODE_2;
+       } else if (currentmode->current_width >= GetSystemMetrics(SM_CXVIRTUALSCREEN) || currentmode->current_height >= GetSystemMetrics(SM_CXVIRTUALSCREEN)) {
+           if (!console_logging)
+               fs_warning = IDS_UNSUPPORTEDSCREENMODE_3;
+#ifdef PICASSO96
+       } else if (screen_is_picasso && !currprefs.gfx_pfullscreen &&
+                 ( picasso_vidinfo.selected_rgbformat != RGBFB_CHUNKY ) &&
+                 ( picasso_vidinfo.selected_rgbformat != colortype ) &&
+                   !(currentmode->flags & DM_OVERLAY) )
+       {
+           fs_warning = IDS_UNSUPPORTEDSCREENMODE_4;
+#endif
+       }
+       if (fs_warning >= 0 && !isfullscreen ()) {
+           char szMessage[MAX_PATH], szMessage2[MAX_PATH];
+           WIN32GUI_LoadUIString( IDS_UNSUPPORTEDSCREENMODE, szMessage, MAX_PATH );
+           WIN32GUI_LoadUIString( fs_warning, szMessage2, MAX_PATH );
+           // Temporarily drop the DirectDraw stuff
+           DirectDraw_Release();
+           sprintf (tmpstr, szMessage, fs_warning);
+           gui_message (tmpstr);
+           DirectDraw_Start(displayGUID);
+           if (screen_is_picasso)
+               changed_prefs.gfx_pfullscreen = currprefs.gfx_pfullscreen = 1;
+           else
+               changed_prefs.gfx_afullscreen = currprefs.gfx_afullscreen = 1;
+           updatewinfsmode (&currprefs);
+           updatewinfsmode (&changed_prefs);
+           currentmode->current_depth = tmp_depth;
+           updatemodes ();
+       }
+       if (! create_windows ())
+           goto oops;
+#ifdef PICASSO96
+       if (screen_is_picasso) {
+           if (need_fs)
+               currprefs.gfx_pfullscreen = 1;
+           currentmode->pal = (LPPALETTEENTRY) & picasso96_state.CLUT;
+           if (! set_ddraw ()) {
+               if (!modefallback (0))
+                   goto oops;
+               close_windows ();
+               if (!DirectDraw_Start (displayGUID)) break;
+               continue;
+           }
+           picasso_vidinfo.rowbytes = DirectDraw_GetSurfacePitch();
+           picasso_vidinfo.pixbytes = DirectDraw_GetBytesPerPixel();
+           picasso_vidinfo.rgbformat = DirectDraw_GetPixelFormat();
+           break;
+       } else {
+#endif
+           if (need_fs) {
+               currprefs.gfx_afullscreen = 1;
+               updatewinfsmode (&currprefs);
+           }
+           currentmode->pal = colors256;
+           if (! set_ddraw ()) {
+               if (!modefallback (0))
+                   goto oops;
+               close_windows ();
+               if (!DirectDraw_Start (displayGUID)) break;
+               continue;
+           }
+           currentmode->real_depth = currentmode->current_depth;
+           if (currentmode->flags & (DM_OPENGL | DM_D3D | DM_SWSCALE)) {
+               currentmode->amiga_width = AMIGA_WIDTH_MAX >> (currprefs.gfx_lores ? 1 : 0);
+               currentmode->amiga_height = AMIGA_HEIGHT_MAX >> (currprefs.gfx_linedbl ? 0 : 1);
+               if (usedfilter) {
+                   if (usedfilter->x[0]) {
+                       currentmode->current_depth = (currprefs.gfx_filter_filtermode / 2) ? 32 : 16;
+                   } else {
+                       int j = 0, i = currprefs.gfx_filter_filtermode;
+                       while (i >= 0) {
+                           while (!usedfilter->x[j]) j++;
+                           if(i-- > 0)
+                               j++;
+                       }
+                       if ((usedfilter->x[j] & (UAE_FILTER_MODE_16 | UAE_FILTER_MODE_32)) == (UAE_FILTER_MODE_16 | UAE_FILTER_MODE_32)) {
+                           currentmode->current_depth = currentmode->real_depth;
+                       } else {
+                           currentmode->current_depth = (usedfilter->x[j] & UAE_FILTER_MODE_16) ? 16 : 32;
+                       }
+                       mult = j;
+                   }
+               }
+               currentmode->pitch = currentmode->amiga_width * currentmode->current_depth >> 3;
+           } else {
+               currentmode->amiga_width = currentmode->current_width;
+               currentmode->amiga_height = currentmode->current_height;
+           }
+           gfxvidinfo.pixbytes = currentmode->current_depth >> 3;
+           gfxvidinfo.bufmem = 0;
+           gfxvidinfo.linemem = 0;
+           gfxvidinfo.emergmem = scrlinebuf; // memcpy from system-memory to video-memory
+           gfxvidinfo.width = currentmode->amiga_width;
+           gfxvidinfo.height = currentmode->amiga_height;
+           gfxvidinfo.maxblocklines = 0; // flush_screen actually does everything
+           gfxvidinfo.rowbytes = currentmode->pitch;
+           break;
+#ifdef PICASSO96
+       }
+#endif
+    }
+
+    if ((currentmode->flags & DM_DDRAW) && !(currentmode->flags & (DM_D3D | DM_SWSCALE))) {
+       int flags;
+       if( !DirectDraw_SurfaceLock( lockable_surface ) )
+           goto oops;
+       flags = DirectDraw_GetPixelFormatFlags();
+       DirectDraw_SurfaceUnlock();
+        if (flags  & (DDPF_RGB | DDPF_PALETTEINDEXED8 | DDPF_RGBTOYUV )) {
+           write_log( "%s mode (bits: %d, pixbytes: %d)\n", currentmode->flags & DM_DX_FULLSCREEN ? "Full screen" : "Window",
+                  DirectDraw_GetSurfaceBitCount(), currentmode->current_depth >> 3 );
+       } else {
+           char szMessage[ MAX_PATH ];
+           WIN32GUI_LoadUIString( IDS_UNSUPPORTEDPIXELFORMAT, szMessage, MAX_PATH );
+           gui_message( szMessage);
+           goto oops;
+       }
+    } else if (!(currentmode->flags & DM_SWSCALE)) {
+       int size = currentmode->amiga_width * currentmode->amiga_height * gfxvidinfo.pixbytes;
+       gfxvidinfo.realbufmem = malloc (size);
+       gfxvidinfo.bufmem = gfxvidinfo.realbufmem;
+       gfxvidinfo.rowbytes = currentmode->amiga_width * gfxvidinfo.pixbytes;
+    } else if (!(currentmode->flags & DM_D3D)) {
+       int size = (currentmode->amiga_width * 2) * (currentmode->amiga_height * 3) * gfxvidinfo.pixbytes;
+       gfxvidinfo.realbufmem = malloc (size);
+       memset (gfxvidinfo.realbufmem, 0, size);
+       gfxvidinfo.bufmem = gfxvidinfo.realbufmem + (currentmode->amiga_width + (currentmode->amiga_width * 2) * currentmode->amiga_height) * gfxvidinfo.pixbytes;
+       gfxvidinfo.rowbytes = currentmode->amiga_width * 2 * gfxvidinfo.pixbytes;
+    }
+
+    init_row_map ();
+    init_colors ();
+
+    if (currentmode->flags & DM_OVERLAY)
+       setoverlay ();
+
+    if (currentmode->flags & DM_SWSCALE) {
+       S2X_init (currentmode->current_width, currentmode->current_height,
+           currentmode->amiga_width, currentmode->amiga_height,
+           mult, currentmode->current_depth, currentmode->real_depth);
+    }
+#ifdef OPENGL
+    if (currentmode->flags & DM_OPENGL) {
+       const char *err = OGL_init (hAmigaWnd, currentmode->current_width, currentmode->current_height,
+           currentmode->amiga_width, currentmode->amiga_height, currentmode->current_depth);
+       if (err) {
+           OGL_free ();
+           gui_message (err);
+           changed_prefs.gfx_filter = currprefs.gfx_filter = 0;
+           currentmode->current_depth = currentmode->real_depth;
+           gfxmode_reset ();
+           ret = -1;
+           goto oops;
+       }
+    }
+#endif
+#ifdef D3D
+    if (currentmode->flags & DM_D3D) {
+       const char *err = D3D_init (hAmigaWnd, currentmode->current_width, currentmode->current_height,
+           currentmode->amiga_width, currentmode->amiga_height, currentmode->current_depth);
+       if (err) {
+           D3D_free ();
+           gui_message (err);
+           changed_prefs.gfx_filter = currprefs.gfx_filter = 0;
+           currentmode->current_depth = currentmode->real_depth;
+           gfxmode_reset ();
+           ret = -1;
+           goto oops;
+       }
+    }
+#endif
+    return 1;
+
+oops:
+    close_hwnds();
+    return ret;
+}
+
+
+void WIN32GFX_PaletteChange( void )
+{
+    HRESULT hr;
+    if (!(currentmode->flags & DM_DDRAW) || (currentmode->flags & DM_D3D)) return;
+    if (currentmode->current_depth > 8)
+       return;
+    hr = DirectDraw_SetPalette( 1 ); /* Remove current palette */
+    if (hr != DD_OK)
+       write_log ("SetPalette(1) failed, %s\n", DXError (hr));
+    hr = DirectDraw_SetPalette( 0 ); /* Set our real palette */
+    if (hr != DD_OK)
+       write_log ("SetPalette(0) failed, %s\n", DXError (hr));
+}
+
+int WIN32GFX_ClearPalette( void )
+{
+    HRESULT hr;
+    if (currentmode->current_depth > 8)
+       return 1;
+    if (!(currentmode->flags & DM_DDRAW) || (currentmode->flags & DM_D3D)) return 1;
+    hr = DirectDraw_SetPalette( 1 ); /* Remove palette */
+    if (hr != DD_OK)
+       write_log ("SetPalette(1) failed, %s\n", DXError (hr));
+    return hr == DD_OK;
+}
+
+int WIN32GFX_SetPalette( void )
+{
+    HRESULT hr;
+    if (!(currentmode->flags & DM_DDRAW) || (currentmode->flags & DM_D3D)) return 1;
+    if (currentmode->current_depth > 8)
+       return 1;
+    hr = DirectDraw_SetPalette( 0 ); /* Set palette */
+    if (hr != DD_OK)
+       write_log ("SetPalette(0) failed, %s\n", DXError (hr));
+    return hr == DD_OK;
+}
+void WIN32GFX_WindowMove ( void )
+{
+    if (currentmode->flags & DM_OVERLAY)
+       setoverlay();
+}
+
+void WIN32GFX_WindowSize ( void )
+{
+}
+
+void updatedisplayarea (void)
+{
+    if (picasso_on)
+       return;
+    /* Update the display area */
+    if (currentmode->flags & DM_OPENGL) {
+#ifdef OPENGL
+       OGL_refresh ();
+#endif
+    } else if (currentmode->flags & DM_D3D) {
+#ifdef D3D
+       D3D_refresh ();
+#endif
+    } else if (currentmode->flags & DM_DDRAW) {
+       if (currentmode->flags & DM_SWSCALE) {
+           S2X_refresh ();
+           if( !isfullscreen() ) {
+               if(DirectDraw_GetLockableType() != overlay_surface)
+                   DX_Blit( 0, 0, 0, 0, WIN32GFX_GetWidth(), WIN32GFX_GetHeight(), BLIT_SRC );
+           } else {
+               DirectDraw_Blt( primary_surface, NULL, secondary_surface, NULL, DDBLT_WAIT, NULL );
+           }
+       } else {
+           if( !isfullscreen() ) {
+               if(DirectDraw_GetLockableType() != overlay_surface)
+                   DX_Blit( 0, 0, 0, 0, WIN32GFX_GetWidth(), WIN32GFX_GetHeight(), BLIT_SRC );
+           } else {
+               DirectDraw_Blt( primary_surface, NULL, secondary_surface, NULL, DDBLT_WAIT, NULL );
+           }
+       }
+    }
+}
+
+void updatewinfsmode (struct uae_prefs *p)
+{
+    int i;
+
+    fixup_prefs_dimensions (p);
+    if (p->gfx_afullscreen) {
+       p->gfx_width = p->gfx_width_fs;
+       p->gfx_height = p->gfx_height_fs;
+    } else {
+       p->gfx_width = p->gfx_width_win;
+       p->gfx_height = p->gfx_height_win;
+    }
+    displayGUID = NULL;
+    i = 0;
+    while (Displays[i].name) i++;
+    if (p->gfx_display >= i)
+       p->gfx_display = 0;
+    if (Displays[p->gfx_display].disabled)
+       p->gfx_display = 0;
+    if (i == 0) {
+       gui_message ("no display adapters! Exiting");
+       exit (0);
+    }
+    if (!Displays[p->gfx_display].primary)
+       displayGUID = &Displays[p->gfx_display].guid;
+}
+
+void fullscreentoggle (void)
+{
+    if(picasso_on)
+       changed_prefs.gfx_pfullscreen = !changed_prefs.gfx_pfullscreen;
+    else
+       changed_prefs.gfx_afullscreen = !changed_prefs.gfx_afullscreen;
+    updatewinfsmode (&changed_prefs);
+}
+
+HDC gethdc (void)
+{
+    HDC hdc = 0;
+#ifdef OPENGL
+    if (OGL_isenabled())
+       return OGL_getDC (0);
+#endif
+#ifdef D3D
+    if (D3D_isenabled())
+       return D3D_getDC (0);
+#endif
+    if(DirectDraw_GetDC(&hdc, DirectDraw_GetLockableType()) != DD_OK)
+        hdc = 0;
+    return hdc;
+}
+
+void releasehdc (HDC hdc)
+{
+#ifdef OPENGL
+    if (OGL_isenabled()) {
+       OGL_getDC (hdc);
+       return;
+    }
+#endif
+#ifdef D3D
+    if (D3D_isenabled()) {
+       D3D_getDC (hdc);
+       return;
+    }
+#endif
+    DirectDraw_ReleaseDC(hdc, DirectDraw_GetLockableType());
+}
\ No newline at end of file
diff --git a/od-win32/win32gfx.h b/od-win32/win32gfx.h
new file mode 100755 (executable)
index 0000000..2a9bb09
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef __WIN32GFX_H__
+#define __WIN32GFX_H__
+
+#include <ddraw.h>
+
+BOOL CALLBACK displaysCallback (GUID *guid, LPSTR desc, LPSTR name, LPVOID ctx, HMONITOR hm);
+extern void sortdisplays (void);
+
+int WIN32GFX_IsPicassoScreen( void );
+int WIN32GFX_GetWidth( void );
+int WIN32GFX_GetHeight( void );
+int WIN32GFX_GetDepth (int real);
+void WIN32GFX_DisplayChangeRequested( void );
+void WIN32GFX_ToggleFullScreen( void );
+void WIN32GFX_DisablePicasso( void );
+void WIN32GFX_EnablePicasso( void );
+void WIN32GFX_PaletteChange( void );
+int WIN32GFX_ClearPalette( void );
+int WIN32GFX_SetPalette( void );
+void WIN32GFX_WindowMove ( void );
+
+int DX_Blit( int srcx, int srcy, int dstx, int dsty, int width, int height, BLIT_OPCODE opcode );
+
+#ifndef _WIN32_WCE
+RGBFTYPE WIN32GFX_FigurePixelFormats( RGBFTYPE colortype );
+int WIN32GFX_AdjustScreenmode( uae_u32 *pwidth, uae_u32 *pheight, uae_u32 *ppixbits );
+#endif
+
+extern HWND hStatusWnd;
+extern HINSTANCE hDDraw;
+extern char *start_path;
+extern uae_u32 default_freq;
+
+extern HDC gethdc (void);
+extern void releasehdc (HDC hdc);
+extern void close_windows (void);
+extern void updatewinfsmode (struct uae_prefs *p);
+
+#endif
diff --git a/od-win32/win32gui.c b/od-win32/win32gui.c
new file mode 100755 (executable)
index 0000000..c7f5942
--- /dev/null
@@ -0,0 +1,6264 @@
+/*==========================================================================
+ *
+ *  Copyright (C) 1996 Brian King
+ *
+ *  File:       win32gui.c
+ *  Content:    Win32-specific gui features for UAE port.
+ *
+ ***************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <windows.h>
+#include <winspool.h>
+#include <winuser.h>
+#include <mmsystem.h>
+#include <commctrl.h>
+#include <commdlg.h>
+#include <dlgs.h>
+#include <process.h>
+#include <prsht.h>
+#include <richedit.h>
+#include <shellapi.h>
+#include <Shlobj.h>
+#include <ddraw.h>
+
+#include "config.h"
+#include "resource.h"
+#include "sysconfig.h"
+#include "sysdeps.h"
+#include "gui.h"
+#include "options.h"
+#include "memory.h"
+#include "custom.h"
+#include "events.h"
+#include "newcpu.h"
+#include "disk.h"
+#include "uae.h"
+#include "threaddep/thread.h"
+#include "filesys.h"
+#include "autoconf.h"
+#include "inputdevice.h"
+#include "xwin.h"
+#include "keyboard.h"
+#include "zfile.h"
+
+#include "dxwrap.h"
+#include "win32.h"
+#include "picasso96_win.h"
+#include "win32gui.h"
+#include "win32gfx.h"
+#include "sounddep/sound.h"
+#include "od-win32/parser.h"
+#include "od-win32/ahidsound.h"
+#include "target.h"
+#include "savestate.h"
+#include "avioutput.h"
+#include "opengl.h"
+#include "direct3d.h"
+#include "akiko.h"
+#include "gfxfilter.h"
+#include "driveclick.h"
+
+#define DISK_FORMAT_STRING "(*.adf;*.adz;*.gz;*.dms;*.fdi;*.ipf;*.zip;*.exe)\0*.adf;*.adz;*.gz;*.dms;*.fdi;*.ipf;*.zip;*.exe\0"
+#define ROM_FORMAT_STRING "(*.rom;*.zip;*.roz)\0*.rom;*.zip;*.roz\0"
+#define USS_FORMAT_STRING_RESTORE "(*.uss;*.gz;*.zip)\0*.uss;*.gz;*.zip\0"
+#define USS_FORMAT_STRING_SAVE "(*.uss)\0*.uss\0"
+
+static int allow_quit;
+static int full_property_sheet = 1;
+static struct uae_prefs *pguiprefs;
+struct uae_prefs workprefs;
+static int currentpage, currentpage_sub;
+int gui_active;
+
+extern HWND (WINAPI *pHtmlHelp)(HWND, LPCSTR, UINT, LPDWORD );
+#undef HtmlHelp
+#ifndef HH_DISPLAY_TOPIC
+#define HH_DISPLAY_TOPIC 0
+#endif
+#define HtmlHelp(a,b,c,d) if( pHtmlHelp ) (*pHtmlHelp)(a,b,c,(LPDWORD)d); else \
+{ char szMessage[MAX_PATH]; WIN32GUI_LoadUIString( IDS_NOHELP, szMessage, MAX_PATH ); gui_message( szMessage ); }
+
+extern HWND hAmigaWnd;
+extern char help_file[ MAX_PATH ];
+
+extern int mouseactive;
+extern char *start_path;
+
+extern char configname[256];
+static char config_filename[ MAX_PATH ] = "";
+
+static drive_specs blankdrive =
+{"", "", 1, 32, 1, 2, 0, 0};
+
+#define Error(x) MessageBox( NULL, (x), "WinUAE Error", MB_OK )
+
+void WIN32GUI_LoadUIString( DWORD id, char *string, DWORD dwStringLen )
+{
+    if( LoadString( hUIDLL ? hUIDLL : hInst, id, string, dwStringLen ) == 0 )
+       LoadString( hInst, id, string, dwStringLen );
+}
+
+static int C_PAGES;
+#define MAX_C_PAGES 30
+static int LOADSAVE_ID = -1, MEMORY_ID = -1, KICKSTART_ID = -1, CPU_ID = -1,
+    DISPLAY_ID = -1, HW3D_ID = -1, CHIPSET_ID = -1, SOUND_ID = -1, FLOPPY_ID = -1, DISK_ID = -1,
+    HARDDISK_ID = -1, PORTS_ID = -1, INPUT_ID = -1, MISC1_ID = -1, MISC2_ID = -1, AVIOUTPUT_ID = -1,
+    ABOUT_ID = -1;
+static HWND pages[MAX_C_PAGES];
+static HWND guiDlg;
+
+void exit_gui (int ok)
+{
+    if (guiDlg == NULL)
+       return;
+    SendMessage (guiDlg, WM_COMMAND, ok ? IDOK : IDCANCEL, 0);
+}
+
+static HICON hMoveUp = NULL, hMoveDown = NULL;
+static HWND cachedlist = NULL;
+
+#define MIN_CHIP_MEM 0
+#define MAX_CHIP_MEM 5
+#define MIN_FAST_MEM 0
+#define MAX_FAST_MEM 4
+#define MIN_SLOW_MEM 0
+#define MAX_SLOW_MEM 3
+#define MIN_Z3_MEM 0
+#define MAX_Z3_MEM 10
+#define MIN_P96_MEM 0
+#define MAX_P96_MEM 6
+#define MIN_M68K_PRIORITY 1
+#define MAX_M68K_PRIORITY 16
+#define MIN_CACHE_SIZE 0
+#define MAX_CACHE_SIZE 8
+#define MIN_REFRESH_RATE 1
+#define MAX_REFRESH_RATE 10
+#define MIN_SOUND_MEM 0
+#define MAX_SOUND_MEM 6
+
+static char szNone[ MAX_PATH ] = "None";
+
+static int cfgfile_doload (struct uae_prefs *p, const char *filename, int type)
+{
+    if (type == 0) {
+       if (p->mountinfo == currprefs.mountinfo)
+           currprefs.mountinfo = 0;
+       discard_prefs (p, 0);
+#ifdef FILESYS
+       free_mountinfo (currprefs.mountinfo);
+       currprefs.mountinfo = alloc_mountinfo ();
+#endif
+    }
+    default_prefs (p, type);
+    return cfgfile_load (p, filename, 0);
+}
+
+/* if drive is -1, show the full GUI, otherwise file-requester for DF[drive] */
+void gui_display( int shortcut )
+{
+    int flipflop = 0;
+    HRESULT hr;
+
+    gui_active = 1;
+#ifdef D3D
+    D3D_guimode (TRUE);
+#endif
+#ifdef CD32
+    akiko_entergui ();
+#endif
+    inputdevice_unacquire ();
+    clearallkeys ();
+#ifdef AHI
+    ahi_close_sound ();
+#endif
+    pause_sound ();
+    setmouseactive (0);
+
+    if( ( !WIN32GFX_IsPicassoScreen() && currprefs.gfx_afullscreen && ( currprefs.gfx_width < 640 || currprefs.gfx_height < 480 ) )
+#ifdef PICASSO96
+        || ( WIN32GFX_IsPicassoScreen() && currprefs.gfx_pfullscreen && ( picasso96_state.Width < 640 || picasso96_state.Height < 480 ) )
+#endif
+    ) {
+        flipflop = 1;
+    }
+    WIN32GFX_ClearPalette();
+    manual_painting_needed++; /* So that WM_PAINT will refresh the display */
+
+    hr = DirectDraw_FlipToGDISurface();
+    if (hr != DD_OK)
+       write_log ("FlipToGDISurface failed, %s\n", DXError (hr));
+
+    if( shortcut == -1 ) {
+       int ret;
+        if( flipflop )
+            ShowWindow( hAmigaWnd, SW_MINIMIZE );
+       ret = GetSettings (0, flipflop ? GetDesktopWindow () : hAmigaWnd);
+        if( flipflop )
+            ShowWindow( hAmigaWnd, SW_RESTORE );
+       if (!ret) {
+           savestate_state = 0;
+       }
+    } else if (shortcut >= 0 && shortcut < 4) {
+        DiskSelection( hAmigaWnd, IDC_DF0+shortcut, 0, &changed_prefs, 0 );
+    } else if (shortcut == 5) {
+        if (DiskSelection( hAmigaWnd, IDC_DOSAVESTATE, 9, &changed_prefs, 0 ))
+           save_state (savestate_fname, "Description!");
+    } else if (shortcut == 4) {
+        if (DiskSelection( hAmigaWnd, IDC_DOLOADSTATE, 10, &changed_prefs, 0 ))
+           savestate_state = STATE_DORESTORE;
+    }
+    manual_painting_needed--; /* So that WM_PAINT doesn't need to use custom refreshing */
+    manual_palette_refresh_needed = 1;
+    resume_sound ();
+#ifdef AHI
+    ahi_open_sound ();
+#endif
+    inputdevice_copyconfig (&changed_prefs, &currprefs);
+    inputdevice_config_change_test ();
+    clearallkeys ();
+    inputdevice_acquire (mouseactive);
+#ifdef CD32
+    akiko_exitgui ();
+#endif
+    setmouseactive (1);
+#ifdef D3D
+    D3D_guimode (FALSE);
+#endif
+#ifdef AVIOUTPUT
+    AVIOutput_Begin ();
+#endif
+    fpscounter_reset ();
+    gui_active = 0;
+
+}
+
+static void prefs_to_gui (struct uae_prefs *p)
+{
+    workprefs = *p;
+    updatewinfsmode (&workprefs);
+    /* Could also duplicate unknown lines, but no need - we never
+       modify those.  */
+#if 0
+#ifdef _DEBUG
+    if (workprefs.gfx_framerate < 5)
+       workprefs.gfx_framerate = 5;
+#endif
+#endif
+}
+
+static void gui_to_prefs (void)
+{
+    struct uaedev_mount_info *mi = currprefs.mountinfo;
+    /* Always copy our prefs to changed_prefs, ... */
+    //free_mountinfo (workprefs.mountinfo);
+    changed_prefs = workprefs;
+    updatewinfsmode (&changed_prefs);
+    currprefs.mountinfo = mi;
+}
+
+// Common routine for popping up a file-requester
+// flag - 0 for floppy loading, 1 for floppy creation, 2 for loading hdf, 3 for saving hdf
+// flag - 4 for loading .uae config-files, 5 for saving .uae config-files
+// flag = 6 for loading .rom files, 7 for loading .key files
+// flag = 8 for loading configurations
+// flag = 9 for saving snapshots
+// flag = 10 for loading snapshots
+// flag = 11 for selecting flash files
+// flag = 12 for loading anything
+// flag = 13 for selecting path
+int DiskSelection( HWND hDlg, WPARAM wParam, int flag, struct uae_prefs *prefs, char *path_out)
+{
+    OPENFILENAME openFileName;
+    char regfloppypath[MAX_PATH] = "";
+    char regrompath[MAX_PATH] = "";
+    char reghdfpath[MAX_PATH] = "";
+    DWORD dwType = REG_SZ;
+    DWORD dwRFPsize = MAX_PATH;
+    DWORD dwRRPsize = MAX_PATH;
+    DWORD dwRHPsize = MAX_PATH;
+    
+    char full_path[MAX_PATH] = "";
+    char file_name[MAX_PATH] = "";
+    char init_path[MAX_PATH] = "";
+    BOOL result = FALSE;
+    char *amiga_path = NULL;
+    char description[ CFG_DESCRIPTION_LENGTH ] = "";
+    char *p;
+    int all = 1;
+
+    char szTitle[ MAX_PATH ];
+    char szFormat[ MAX_PATH ];
+    char szFilter[ MAX_PATH ] = { 0 };
+    
+    memset (&openFileName, 0, sizeof (OPENFILENAME));
+    if( hWinUAEKey )
+    {
+        RegQueryValueEx( hWinUAEKey, "FloppyPath", 0, &dwType, (LPBYTE)regfloppypath, &dwRFPsize );
+        RegQueryValueEx( hWinUAEKey, "KickstartPath", 0, &dwType, (LPBYTE)regrompath, &dwRRPsize );
+        RegQueryValueEx( hWinUAEKey, "hdfPath", 0, &dwType, (LPBYTE)reghdfpath, &dwRHPsize );
+    }
+    
+    strncpy( init_path, start_path, MAX_PATH );
+    switch( flag )
+    {
+       case 0:
+       case 1:
+           if( regfloppypath[0] )
+               strncpy( init_path, regfloppypath, MAX_PATH );
+           else
+               strncat( init_path, "..\\shared\\adf\\", MAX_PATH );
+       break;
+       case 2:
+       case 3:
+           if( reghdfpath[0] )
+               strncpy( init_path, reghdfpath, MAX_PATH );
+           else
+               strncat( init_path, "..\\shared\\hdf\\", MAX_PATH );
+       break;
+       case 6:
+       case 7:
+       case 11:
+           if( regrompath[0] )
+               strncpy( init_path, regrompath, MAX_PATH );
+           else
+               strncat( init_path, "..\\shared\\rom\\", MAX_PATH );
+       break;
+       case 4:
+       case 5:
+       case 8:
+           strncat( init_path, "Configurations\\", MAX_PATH );
+       break;
+       case 9:
+       case 10:
+           strncat( init_path, "SaveStates\\", MAX_PATH );
+       break;
+       
+    }
+
+    openFileName.lStructSize = sizeof (OPENFILENAME);
+    openFileName.hwndOwner = hDlg;
+    openFileName.hInstance = hInst;
+    
+    switch (flag) {
+    case 0:
+       WIN32GUI_LoadUIString( IDS_SELECTADF, szTitle, MAX_PATH );
+       WIN32GUI_LoadUIString( IDS_ADF, szFormat, MAX_PATH );
+       sprintf( szFilter, "%s ", szFormat );
+       memcpy( szFilter + strlen( szFilter ), DISK_FORMAT_STRING, sizeof( DISK_FORMAT_STRING ) + 1 );
+
+       openFileName.lpstrTitle = szTitle;
+       openFileName.lpstrDefExt = "ADF";
+       openFileName.lpstrFilter = szFilter;
+       break;
+    case 1:
+       WIN32GUI_LoadUIString( IDS_CHOOSEBLANK, szTitle, MAX_PATH );
+       WIN32GUI_LoadUIString( IDS_ADF, szFormat, MAX_PATH );
+       sprintf( szFilter, "%s ", szFormat );
+       memcpy( szFilter + strlen( szFilter ), "(*.adf)\0*.adf\0", 15 );
+
+       openFileName.lpstrTitle = szTitle;
+       openFileName.lpstrDefExt = "ADF";
+       openFileName.lpstrFilter = szFilter;
+       break;
+    case 2:
+    case 3:
+       WIN32GUI_LoadUIString( IDS_SELECTHDF, szTitle, MAX_PATH );
+       WIN32GUI_LoadUIString( IDS_HDF, szFormat, MAX_PATH );
+       sprintf( szFilter, "%s ", szFormat );
+       memcpy( szFilter + strlen( szFilter ), "(*.hdf;*.rdf)\0*.hdf;*.rdf\0", 26 );
+
+       openFileName.lpstrTitle = szTitle;
+       openFileName.lpstrDefExt = "HDF";
+       openFileName.lpstrFilter = szFilter;
+       break;
+    case 4:
+    case 5:
+       WIN32GUI_LoadUIString( IDS_SELECTUAE, szTitle, MAX_PATH );
+       WIN32GUI_LoadUIString( IDS_UAE, szFormat, MAX_PATH );
+       sprintf( szFilter, "%s ", szFormat );
+       memcpy( szFilter + strlen( szFilter ), "(*.uae)\0*.uae\0", 15 );
+
+       openFileName.lpstrTitle  = szTitle;
+       openFileName.lpstrDefExt = "UAE";
+       openFileName.lpstrFilter = szFilter;
+       break;
+    case 6:
+       WIN32GUI_LoadUIString( IDS_SELECTROM, szTitle, MAX_PATH );
+       WIN32GUI_LoadUIString( IDS_ROM, szFormat, MAX_PATH );
+       sprintf( szFilter, "%s ", szFormat );
+       memcpy( szFilter + strlen( szFilter ), ROM_FORMAT_STRING, sizeof (ROM_FORMAT_STRING) + 1);
+
+        openFileName.lpstrTitle = szTitle;
+        openFileName.lpstrDefExt = "ROM";
+        openFileName.lpstrFilter = szFilter;
+        break;
+    case 7:
+       WIN32GUI_LoadUIString( IDS_SELECTKEY, szTitle, MAX_PATH );
+       WIN32GUI_LoadUIString( IDS_KEY, szFormat, MAX_PATH );
+       sprintf( szFilter, "%s ", szFormat );
+       memcpy( szFilter + strlen( szFilter ), "(*.key)\0*.key\0", 15 );
+
+       openFileName.lpstrTitle = szTitle;
+       openFileName.lpstrDefExt = "KEY";
+        openFileName.lpstrFilter = szFilter;
+        break;
+    case 9:
+    case 10:
+       WIN32GUI_LoadUIString( flag == 10 ? IDS_RESTOREUSS : IDS_SAVEUSS, szTitle, MAX_PATH );
+       WIN32GUI_LoadUIString( IDS_USS, szFormat, MAX_PATH );
+       sprintf( szFilter, "%s ", szFormat );
+       if (flag == 10) {
+           memcpy( szFilter + strlen( szFilter ), USS_FORMAT_STRING_RESTORE, sizeof (USS_FORMAT_STRING_RESTORE) + 1);
+           all = 1;
+       } else {
+           memcpy( szFilter + strlen( szFilter ), USS_FORMAT_STRING_SAVE, sizeof (USS_FORMAT_STRING_SAVE) + 1);
+           p = szFilter;
+           while (p[0] != 0 || p[1] !=0 ) p++;
+           p++;
+           strcpy (p, "Uncompressed (*.uss)");
+           p += strlen(p) + 1;
+           strcpy (p, "*.uss");
+           p += strlen(p) + 1;
+           strcpy (p, "RAM dump (*.dat)");
+           p += strlen(p) + 1;
+           strcpy (p, "*.dat");
+           p += strlen(p) + 1;
+           *p = 0;
+           all = 0;
+       }
+       openFileName.lpstrTitle  = szTitle;
+       openFileName.lpstrDefExt = "USS";
+       openFileName.lpstrFilter = szFilter;
+       break;
+    case 11:
+       WIN32GUI_LoadUIString( IDS_SELECTFLASH, szTitle, MAX_PATH );
+       WIN32GUI_LoadUIString( IDS_FLASH, szFormat, MAX_PATH );
+       sprintf( szFilter, "%s ", szFormat );
+       memcpy( szFilter + strlen( szFilter ), "(*.nvr)\0*.nvr\0", 15 );
+
+       openFileName.lpstrTitle  = szTitle;
+       openFileName.lpstrDefExt = "NVR";
+       openFileName.lpstrFilter = szFilter;
+       break;
+    case 8:
+    default:
+       WIN32GUI_LoadUIString( IDS_SELECTINFO, szTitle, MAX_PATH );
+
+       openFileName.lpstrTitle = szTitle;
+       openFileName.lpstrFilter = NULL;
+       openFileName.lpstrDefExt = NULL;
+       break;
+    }
+    if (all) {
+       p = szFilter;
+       while (p[0] != 0 || p[1] !=0 ) p++;
+       p++;
+       strcpy (p, "All files (*.*)");
+       p += strlen(p) + 1;
+       strcpy (p, "*.*");
+       p += strlen(p) + 1;
+       *p = 0;
+    }
+    openFileName.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_LONGNAMES | OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
+    openFileName.lpstrCustomFilter = NULL;
+    openFileName.nMaxCustFilter = 0;
+    openFileName.nFilterIndex = 0;
+    openFileName.lpstrFile = full_path;
+    openFileName.nMaxFile = MAX_PATH;
+    openFileName.lpstrFileTitle = file_name;
+    openFileName.nMaxFileTitle = MAX_PATH;
+    openFileName.lpstrInitialDir = init_path;
+    openFileName.lpfnHook = NULL;
+    openFileName.lpTemplateName = NULL;
+    openFileName.lCustData = 0;
+    if (flag == 1 || flag == 3 || flag == 5 || flag == 9 || flag == 11)
+    {
+       if( !(result = GetSaveFileName (&openFileName)) )
+           write_log ("GetSaveFileName() failed.\n");
+    }
+    else
+    {
+       if( !(result = GetOpenFileName (&openFileName)) )
+           write_log ("GetOpenFileName() failed.\n");
+    }
+
+    if (result)
+    {
+       switch (wParam) 
+        {
+       case IDC_PATH_NAME:
+       case IDC_PATH_FILESYS:
+           if( flag == 8 )
+           {
+               if( strstr( full_path, "Configurations\\" ) )
+               {
+                   strcpy( full_path, init_path );
+                   strcat( full_path, file_name );
+               }
+           }
+           SetDlgItemText (hDlg, wParam, full_path);
+            break;
+       case IDC_DF0:
+           SetDlgItemText (hDlg, IDC_DF0TEXT, full_path);
+           strcpy( prefs->df[0], full_path );
+            break;
+       case IDC_DF1:
+           SetDlgItemText (hDlg, IDC_DF1TEXT, full_path);
+           strcpy( prefs->df[1], full_path );
+            break;
+       case IDC_DF2:
+           SetDlgItemText (hDlg, IDC_DF2TEXT, full_path);
+           strcpy( prefs->df[2], full_path );
+            break;
+       case IDC_DF3:
+           SetDlgItemText (hDlg, IDC_DF3TEXT, full_path);
+           strcpy( prefs->df[3], full_path );
+            break;
+       case IDC_DOSAVESTATE:
+       case IDC_DOLOADSTATE:
+           savestate_initsave (full_path, openFileName.nFilterIndex);
+           break;
+       case IDC_CREATE:
+           disk_creatediskfile( full_path, 0, SendDlgItemMessage( hDlg, IDC_FLOPPYTYPE, CB_GETCURSEL, 0, 0L ));
+            break;
+       case IDC_CREATE_RAW:
+           disk_creatediskfile( full_path, 1, SendDlgItemMessage( hDlg, IDC_FLOPPYTYPE, CB_GETCURSEL, 0, 0L ));
+           break;
+       case IDC_LOAD:
+           if (cfgfile_doload(&workprefs, full_path, 0) == 0)
+           {
+               char szMessage[MAX_PATH];
+               WIN32GUI_LoadUIString (IDS_COULDNOTLOADCONFIG, szMessage, MAX_PATH);
+               gui_message (szMessage);
+           }
+           else
+           {
+               int type;
+               cfgfile_get_description (full_path, description, &type);
+               SetDlgItemText (hDlg, IDC_EDITDESCRIPTION, description);
+               SetDlgItemText (hDlg, IDC_EDITNAME, full_path);
+           }
+            break;
+       case IDC_SAVE:
+           SetDlgItemText( hDlg, IDC_EDITNAME, full_path );
+            break;
+       case IDC_ROMFILE:
+           SetDlgItemText( hDlg, IDC_ROMFILE, full_path );
+           strcpy( workprefs.romfile, full_path );
+           break;
+       case IDC_ROMFILE2:
+           SetDlgItemText( hDlg, IDC_ROMFILE2, full_path );
+           strcpy( workprefs.romextfile, full_path );
+           break;
+       case IDC_KEYFILE:
+           SetDlgItemText( hDlg, IDC_KEYFILE, full_path );
+           strcpy( workprefs.keyfile, full_path );
+           break;
+       case IDC_FLASHFILE:
+           SetDlgItemText( hDlg, IDC_FLASHFILE, full_path );
+           strcpy( workprefs.flashfile, full_path );
+           break;
+       case IDC_CARTFILE:
+           SetDlgItemText( hDlg, IDC_CARTFILE, full_path );
+           strcpy( workprefs.cartfile, full_path );
+           break;
+        }
+        if (path_out)
+           strcpy (path_out, full_path);
+        if( flag == 0 || flag == 1 )
+        {
+            amiga_path = strstr( openFileName.lpstrFile, openFileName.lpstrFileTitle );
+            if( amiga_path && amiga_path != openFileName.lpstrFile )
+            {
+                *amiga_path = 0;
+                if( hWinUAEKey )
+                    RegSetValueEx( hWinUAEKey, "FloppyPath", 0, REG_SZ, (CONST BYTE *)openFileName.lpstrFile, strlen( openFileName.lpstrFile ) );
+            }
+        }
+        else if( flag == 2 || flag == 3 )
+        {
+            amiga_path = strstr( openFileName.lpstrFile, openFileName.lpstrFileTitle );
+            if( amiga_path && amiga_path != openFileName.lpstrFile )
+            {
+                *amiga_path = 0;
+                if( hWinUAEKey )
+                    RegSetValueEx( hWinUAEKey, "hdfPath", 0, REG_SZ, (CONST BYTE *)openFileName.lpstrFile, strlen( openFileName.lpstrFile ) );
+            }
+        }
+        else if( flag == 6 || flag == 7 )
+        {
+            amiga_path = strstr( openFileName.lpstrFile, openFileName.lpstrFileTitle );
+            if( amiga_path && amiga_path != openFileName.lpstrFile )
+            {
+                *amiga_path = 0;
+                if( hWinUAEKey )
+                    RegSetValueEx( hWinUAEKey, "KickstartPath", 0, REG_SZ, (CONST BYTE *)openFileName.lpstrFile, strlen( openFileName.lpstrFile ) );
+            }
+        }
+    }
+    return result;
+}
+
+static BOOL CreateHardFile (HWND hDlg, UINT hfsizem)
+{
+    HANDLE hf;
+    int i = 0;
+    BOOL result = FALSE;
+    LONG highword = 0;
+    DWORD ret;
+    char init_path[MAX_PATH] = "";
+    uae_u64 hfsize;
+
+    hfsize = (uae_u64)hfsizem * 1024 * 1024;
+    DiskSelection (hDlg, IDC_PATH_NAME, 3, &workprefs, 0);
+    GetDlgItemText (hDlg, IDC_PATH_NAME, init_path, MAX_PATH);
+    if (*init_path && hfsize) {
+       SetCursor (LoadCursor(NULL, IDC_WAIT));
+       if ((hf = CreateFile (init_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL) ) != INVALID_HANDLE_VALUE) {
+           if (hfsize >= 0x80000000) {
+               highword = (DWORD)(hfsize >> 32);
+               ret = SetFilePointer (hf, (DWORD)hfsize, &highword, FILE_BEGIN);
+           } else {
+               ret = SetFilePointer (hf, (DWORD)hfsize, NULL, FILE_BEGIN);
+           }
+           if (ret == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
+                write_log ("SetFilePointer() failure for %s to posn %ud\n", init_path, hfsize);
+           else
+                result = SetEndOfFile (hf);
+            CloseHandle (hf);
+        } else {
+            write_log ("CreateFile() failed to create %s\n", init_path);
+        }
+       SetCursor (LoadCursor (NULL, IDC_ARROW));
+    }
+    return result;
+}
+
+static const char *memsize_names[] = {
+/* 0 */ szNone,
+/* 1 */ "256 K",
+/* 2 */ "512 K",
+/* 3 */ "1 MB",
+/* 4 */ "2 MB",
+/* 5 */ "4 MB",
+/* 6 */ "8 MB",
+/* 7 */ "16 MB",
+/* 8 */ "32 MB",
+/* 9 */ "64 MB",
+/* 10*/ "128 MB",
+/* 11*/ "256 MB",
+/* 12*/ "512 MB",
+/* 13*/ "1 GB",
+/* 14*/ "1.5MB",
+};
+
+static unsigned long memsizes[] = {
+/* 0 */ 0,
+/* 1 */ 0x00040000, /*  256-K */
+/* 2 */ 0x00080000, /*  512-K */
+/* 3 */ 0x00100000, /*  1-meg */
+/* 4 */ 0x00200000, /*  2-meg */
+/* 5 */ 0x00400000, /*  4-meg */
+/* 6 */ 0x00800000, /*  8-meg */
+/* 7 */ 0x01000000, /* 16-meg */
+/* 8 */ 0x02000000, /* 32-meg */
+/* 9 */ 0x04000000, /* 64-meg */
+/* 10*/ 0x08000000, //128 Meg
+/* 11*/ 0x10000000, //256 Meg 
+/* 12*/ 0x20000000, //512 Meg The correct size is set in mman.c
+/* 13*/ 0x40000000, //1GB
+/* 14*/ 0x00180000, //1.5MB
+};
+
+static int msi_chip[] = { 1, 2, 3, 4, 5, 6 };
+static int msi_bogo[] = { 0, 2, 3, 14, 4 };
+static int msi_fast[] = { 0, 3, 4, 5, 6 };
+static int msi_z3fast[] = { 0, 3, 4, 5, 6, 7, 8, 9, 10,11,12,13 };
+static int msi_gfx[] = { 0, 3, 4, 5, 6,7,8};
+
+static int CalculateHardfileSize (HWND hDlg)
+{
+    BOOL Translated = FALSE;
+    UINT mbytes = 0;
+
+    mbytes = GetDlgItemInt( hDlg, IDC_HFSIZE, &Translated, FALSE );
+    if (mbytes <= 0)
+       mbytes = 0;
+    if( !Translated )
+        mbytes = 0;
+    return mbytes;
+}
+
+static const char *nth[] = {
+    "", "second ", "third ", "fourth ", "fifth ", "sixth ", "seventh ", "eighth ", "ninth ", "tenth "
+};
+
+struct ConfigStruct {
+    char Name[MAX_PATH];
+    char Path[MAX_PATH];
+    char Fullpath[MAX_PATH];
+    char Description[CFG_DESCRIPTION_LENGTH];
+    int Type, Directory;
+    struct ConfigStruct *Parent, *Child;
+    HTREEITEM item;
+};
+
+static void GetConfigPath (char *path, struct ConfigStruct *parent, int noroot)
+{
+    if (parent == 0) {
+       path[0] = 0;
+       if (!noroot) {
+           if (start_path)
+               strcpy (path, start_path);
+           strcat (path, "Configurations\\");
+       }
+       return;
+    }
+    if (parent) {
+       GetConfigPath (path, parent->Parent, noroot);
+       strncat (path, parent->Name, MAX_PATH);
+       strncat (path, "\\", MAX_PATH);
+    }
+}
+
+void FreeConfigStruct (struct ConfigStruct *config)
+{
+    free (config);
+}
+struct ConfigStruct *AllocConfigStruct (void)
+{
+    struct ConfigStruct *config;
+
+    config = xcalloc (sizeof (struct ConfigStruct), 1);
+    return config;
+}
+
+static struct ConfigStruct **configstore;
+static int configstoresize, configstoreallocated;
+
+static struct ConfigStruct *GetConfigs (struct ConfigStruct *configparent, int usedirs)
+{
+    DWORD num_bytes = 0;
+    char path[MAX_PATH];
+    char path2[MAX_PATH];
+    char shortpath[MAX_PATH];
+    WIN32_FIND_DATA find_data;
+    struct ConfigStruct *config, *first;
+    HANDLE handle;
+
+    first = NULL;
+    GetConfigPath (path, configparent, FALSE);
+    GetConfigPath (shortpath, configparent, TRUE);
+    strcpy (path2, path);
+    strncat (path2, "*.*", MAX_PATH);
+    handle = FindFirstFile(path2, &find_data );
+    if (handle == INVALID_HANDLE_VALUE) {
+#ifndef SINGLEFILE
+        // Either the directory has no .CFG files, or doesn't exist.
+        // Create the directory, even if it already exists.  No harm, and don't check return codes, because
+        // we may be doing this on a read-only media like CD-ROM.
+       if (configparent == NULL) {
+           GetConfigPath (path, NULL, FALSE);
+           CreateDirectory (path, NULL);
+       }
+#endif
+       return NULL;
+    }
+    for (;;) {
+       config = NULL;
+       if (strcmp (find_data.cFileName, ".") && strcmp (find_data.cFileName, "..")) {
+           config = AllocConfigStruct ();
+           if ((find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && usedirs) {
+               struct ConfigStruct *child;
+               strcpy (config->Name, find_data.cFileName);
+               config->Directory = 1;
+               child = GetConfigs (config, usedirs);
+               if (child)
+                   config->Child = child;
+           } else if (!(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+               char path3[MAX_PATH];
+               strcpy (path3, path);
+               strncat (path3, find_data.cFileName, MAX_PATH);
+               if (cfgfile_get_description (path3, config->Description, &config->Type)) {
+                   strcpy (config->Name, find_data.cFileName);
+               } else {
+                   FreeConfigStruct (config);
+                   config = NULL;
+               }
+           }
+       }
+       if (config) {
+           strcpy (config->Path, shortpath);
+           strcpy (config->Fullpath, path);
+           config->Parent = configparent;
+           if (configstore == NULL || configstoreallocated == configstoresize) {
+               configstoreallocated += 100;
+               configstore = realloc (configstore, sizeof (struct ConfigStruct*) * configstoreallocated);
+           }
+           configstore[configstoresize++] = config;
+           if (first == NULL)
+               first = config;
+       }
+       if(FindNextFile (handle, &find_data) == 0) {
+           FindClose(handle);
+           break;
+       }
+    }
+    return first;
+}
+
+static void FreeConfigStore (void)
+{
+    int i;
+    for (i = 0; i < configstoresize; i++)
+       FreeConfigStruct (configstore[i]);
+    free (configstore);
+    configstore = 0;
+    configstoresize = configstoreallocated = 0;
+}
+static void CreateConfigStore (void)
+{
+    FreeConfigStore ();
+    GetConfigs (NULL, 1);
+}
+
+static char *HandleConfiguration (HWND hDlg, int flag, struct ConfigStruct *config)
+{
+    char name[MAX_PATH], desc[MAX_PATH];
+    char path[MAX_PATH];
+    static char full_path[MAX_PATH];
+    int type;
+
+    type = SendDlgItemMessage (hDlg, IDC_CONFIGTYPE, CB_GETCURSEL, 0, 0);
+    if (type == CB_ERR)
+       type = 0;
+    full_path[0] = 0;
+    GetDlgItemText (hDlg, IDC_EDITNAME, name, MAX_PATH);
+    GetDlgItemText (hDlg, IDC_EDITDESCRIPTION, desc, MAX_PATH);
+    if (config) {
+        strcpy (path, config->Fullpath);
+    } else {
+        strncpy (path, start_path, MAX_PATH);
+        strncat (path, "Configurations\\", MAX_PATH);
+    }
+    strncat (path, name, MAX_PATH);
+    strcpy (full_path, path);
+    switch (flag)
+    {
+       case CONFIG_SAVE_FULL:
+           DiskSelection( hDlg, IDC_SAVE, 5, &workprefs, 0);
+           strcpy (workprefs.description, desc);
+            cfgfile_save (&workprefs, path, type);
+       break;
+
+       case CONFIG_LOAD_FULL:
+           DiskSelection (hDlg, IDC_LOAD, 4, &workprefs, 0);
+           EnableWindow (GetDlgItem (hDlg, IDC_VIEWINFO), workprefs.info[0]);
+       break;
+               
+       case CONFIG_SAVE:
+           if (strlen (name) == 0) {
+               char szMessage[ MAX_PATH ];
+               WIN32GUI_LoadUIString( IDS_MUSTENTERNAME, szMessage, MAX_PATH );
+               gui_message( szMessage );
+           } else {
+               strcpy (workprefs.description, desc);
+               cfgfile_save (&workprefs, path, type);
+           }
+           break;
+        
+       case CONFIG_LOAD:
+           if (strlen (name) == 0) {
+               char szMessage[ MAX_PATH ];
+               WIN32GUI_LoadUIString( IDS_MUSTSELECTCONFIG, szMessage, MAX_PATH );
+               gui_message( szMessage );
+           } else {
+               if (cfgfile_doload (&workprefs, path, type) == 0) {
+                   char szMessage[ MAX_PATH ];
+                   WIN32GUI_LoadUIString( IDS_COULDNOTLOADCONFIG, szMessage, MAX_PATH );
+                   gui_message( szMessage );
+               } else {
+                   EnableWindow (GetDlgItem (hDlg, IDC_VIEWINFO), workprefs.info[0]);
+                }
+            break;
+
+           case CONFIG_DELETE:
+                if (strlen (name) == 0) {
+                   char szMessage[ MAX_PATH ];
+                   WIN32GUI_LoadUIString( IDS_MUSTSELECTCONFIGFORDELETE, szMessage, MAX_PATH );
+                   gui_message( szMessage );
+                } else {
+                   char szMessage[ MAX_PATH ];
+                   char szTitle[ MAX_PATH ];
+                   WIN32GUI_LoadUIString( IDS_DELETECONFIGCONFIRMATION, szMessage, MAX_PATH );
+                   WIN32GUI_LoadUIString( IDS_DELETECONFIGTITLE, szTitle, MAX_PATH );
+                    if( MessageBox( hDlg, szMessage, szTitle,
+                       MB_YESNO | MB_ICONWARNING | MB_APPLMODAL | MB_SETFOREGROUND ) == IDYES ) {
+                       DeleteFile (path);
+                       write_log ("deleted config '%s'\n", path);
+                    }
+                }
+            break;
+        }
+    }
+    return full_path;
+}
+
+
+static int disk_in_drive (int entry)
+{
+    int i;
+    for (i = 0; i < 4; i++) {
+       if (strlen (workprefs.dfxlist[entry]) > 0 && !strcmp (workprefs.dfxlist[entry], workprefs.df[i]))
+           return i;
+    }
+    return -1;
+}
+
+static int disk_swap (int entry, int col)
+{
+    int drv, i, drvs[4] = { -1, -1, -1, -1 };
+
+    for (i = 0; i < MAX_SPARE_DRIVES; i++) {
+       drv = disk_in_drive (i);
+       if (drv >= 0)
+           drvs[drv] = i;
+    }
+    if ((drv = disk_in_drive (entry)) >= 0) {
+       if (strcmp (workprefs.df[drv], currprefs.df[drv]))
+           strcpy (workprefs.df[drv], currprefs.df[drv]);
+       else
+           workprefs.df[drv][0] = 0;
+       if (drvs[0] < 0 || drvs[1] < 0 || drvs[2] < 0 || drvs[3] < 0) {
+           drv++;
+           while (drv < 4 && drvs[drv] >= 0)
+               drv++;
+           if (drv < 4 && workprefs.dfxtype[drv] >= 0)
+               strcpy (workprefs.df[drv], workprefs.dfxlist[entry]);
+       }
+       return 1;
+    }
+    for (i = 0; i < 4; i++) {
+       if (drvs[i] < 0 && workprefs.dfxtype[i] >= 0) {
+           strcpy (workprefs.df[i], workprefs.dfxlist[entry]);
+           return 1;
+       }
+    }
+    strcpy (workprefs.df[0], workprefs.dfxlist[entry]);
+    return 1;
+}
+
+static int input_selected_device, input_selected_widget;
+static int input_selected_event, input_selected_sub_num;
+
+static void set_lventry_input (HWND list, int index)
+{
+    int flags, i, sub;
+    char name[256];
+    char af[10];
+
+    inputdevice_get_mapped_name (input_selected_device, index, &flags, name, input_selected_sub_num);
+    if (flags & IDEV_MAPPED_AUTOFIRE_SET)
+       strcpy (af, "yes");
+    else if (flags & IDEV_MAPPED_AUTOFIRE_POSSIBLE)
+       strcpy (af, "no");
+    else
+       strcpy (af,"-");
+    ListView_SetItemText(list, index, 1, name);
+    ListView_SetItemText(list, index, 2, af);
+    sub = 0;
+    for (i = 0; i < MAX_INPUT_SUB_EVENT; i++) {
+       if (inputdevice_get_mapped_name (input_selected_device, index, &flags, name, i)) sub++;
+    }
+    sprintf (name, "%d", sub);
+    ListView_SetItemText(list, index, 3, name);
+}
+
+static void update_listview_input (HWND hDlg)
+{
+    int i;
+    for (i = 0; i < inputdevice_get_widget_num (input_selected_device); i++)
+       set_lventry_input (GetDlgItem (hDlg, IDC_INPUTLIST), i);
+}
+           
+static int clicked_entry = -1;
+
+#define LOADSAVE_COLUMNS 2
+#define INPUT_COLUMNS 4
+#define HARDDISK_COLUMNS 7
+#define DISK_COLUMNS 3
+#define MAX_COLUMN_HEADING_WIDTH 20
+
+#define LV_LOADSAVE 1
+#define LV_HARDDISK 2
+#define LV_INPUT 3
+#define LV_DISK 4
+
+static int listview_num_columns;
+static int listview_column_width[HARDDISK_COLUMNS];
+
+void InitializeListView( HWND hDlg )
+{
+    int lv_type;
+    HWND list;
+    LV_ITEM lvstruct;
+    LV_COLUMN lvcolumn;
+    RECT rect;
+    char column_heading[ HARDDISK_COLUMNS ][ MAX_COLUMN_HEADING_WIDTH ];
+    char blocksize_str[6] = "";
+    char readwrite_str[4] = "";
+    char size_str[32] = "";
+    char volname_str[ MAX_PATH ] = "";
+    char devname_str[ MAX_PATH ] = "";
+    char bootpri_str[6] = "";
+    int width = 0;
+    int items = 0, result = 0, i, entry = 0, temp = 0;
+    char tmp[10];
+
+    if (hDlg == pages[HARDDISK_ID]) {
+       listview_num_columns = HARDDISK_COLUMNS;
+       lv_type = LV_HARDDISK;
+       WIN32GUI_LoadUIString( IDS_DEVICE, column_heading[0], MAX_COLUMN_HEADING_WIDTH );
+       WIN32GUI_LoadUIString( IDS_VOLUME, column_heading[1], MAX_COLUMN_HEADING_WIDTH );
+       WIN32GUI_LoadUIString( IDS_PATH, column_heading[2], MAX_COLUMN_HEADING_WIDTH );
+       WIN32GUI_LoadUIString( IDS_RW, column_heading[3], MAX_COLUMN_HEADING_WIDTH );
+       WIN32GUI_LoadUIString( IDS_BLOCKSIZE, column_heading[4], MAX_COLUMN_HEADING_WIDTH );
+       WIN32GUI_LoadUIString( IDS_HFDSIZE, column_heading[5], MAX_COLUMN_HEADING_WIDTH );
+       WIN32GUI_LoadUIString( IDS_BOOTPRI, column_heading[6], MAX_COLUMN_HEADING_WIDTH );
+        list = GetDlgItem( hDlg, IDC_VOLUMELIST );
+    } else if (hDlg == pages[INPUT_ID]) {
+       listview_num_columns = INPUT_COLUMNS;
+       lv_type = LV_INPUT;
+       WIN32GUI_LoadUIString( IDS_INPUTHOSTWIDGET, column_heading[0], MAX_COLUMN_HEADING_WIDTH );
+       WIN32GUI_LoadUIString( IDS_INPUTAMIGAEVENT, column_heading[1], MAX_COLUMN_HEADING_WIDTH );
+       WIN32GUI_LoadUIString( IDS_INPUTAUTOFIRE, column_heading[2], MAX_COLUMN_HEADING_WIDTH );
+       strcpy (column_heading[3], "#");
+        list = GetDlgItem( hDlg, IDC_INPUTLIST );
+    } else {
+       listview_num_columns = DISK_COLUMNS;
+       lv_type = LV_DISK;
+       strcpy (column_heading[0], "#");
+       WIN32GUI_LoadUIString( IDS_DISK_IMAGENAME, column_heading[1], MAX_COLUMN_HEADING_WIDTH );
+       WIN32GUI_LoadUIString( IDS_DISK_DRIVENAME, column_heading[2], MAX_COLUMN_HEADING_WIDTH );
+       list = GetDlgItem (hDlg, IDC_DISK);
+    }
+
+    ListView_DeleteAllItems( list );
+
+    for( i = 0; i < listview_num_columns; i++ )
+        listview_column_width[i] = ListView_GetStringWidth( list, column_heading[i] ) + 15;
+
+    // If there are no columns, then insert some
+    lvcolumn.mask = LVCF_WIDTH;
+    if( ListView_GetColumn( list, 1, &lvcolumn ) == FALSE )
+    {
+        for( i = 0; i < listview_num_columns; i++ )
+        {
+            lvcolumn.mask     = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
+            lvcolumn.iSubItem = i;
+            lvcolumn.fmt      = LVCFMT_LEFT;
+            lvcolumn.pszText  = column_heading[i];
+            lvcolumn.cx       = listview_column_width[i];
+            ListView_InsertColumn( list, i, &lvcolumn );
+        }
+    }
+    if (lv_type == LV_INPUT)
+    {
+       for (i = 0; i < inputdevice_get_widget_num (input_selected_device); i++) {
+           char name[100];
+           inputdevice_get_widget_type (input_selected_device, i, name);
+           lvstruct.mask     = LVIF_TEXT | LVIF_PARAM;
+           lvstruct.pszText  = name;
+           lvstruct.lParam   = 0;
+           lvstruct.iItem    = i;
+           lvstruct.iSubItem = 0;
+           result = ListView_InsertItem( list, &lvstruct );
+           width = ListView_GetStringWidth( list, lvstruct.pszText ) + 15;
+           if( width > listview_column_width[ 0 ] )
+               listview_column_width[ 0 ] = width;
+           entry++;
+       }
+       listview_column_width [1] = 260;
+       listview_column_width [2] = 50;
+       listview_column_width [3] = 20;
+       update_listview_input (hDlg);
+    }
+    else if (lv_type == LV_DISK)
+    {
+       for (i = 0; i < MAX_SPARE_DRIVES; i++) {
+           int drv;
+           sprintf (tmp, "%d", i + 1);
+           lvstruct.mask     = LVIF_TEXT | LVIF_PARAM;
+           lvstruct.pszText  = tmp;
+           lvstruct.lParam   = 0;
+           lvstruct.iItem    = i;
+           lvstruct.iSubItem = 0;
+           result = ListView_InsertItem (list, &lvstruct);
+           ListView_SetItemText (list, result, 1, workprefs.dfxlist[i]);
+           drv = disk_in_drive (i);
+           tmp[0] = 0;
+           if (drv >= 0)
+               sprintf (tmp, "DF%d:", drv);
+           ListView_SetItemText (list, result, 2, tmp);
+           width = ListView_GetStringWidth( list, lvstruct.pszText ) + 15;
+           if (width > listview_column_width[0])
+               listview_column_width[ 0 ] = width;
+           entry++;
+       }
+       listview_column_width[0] = 30;
+       listview_column_width[1] = 308;
+       listview_column_width[2] = 50;
+
+    }
+    else if (lv_type == LV_HARDDISK)
+    {
+#ifdef FILESYS
+        for( i = 0; i < nr_units( currprefs.mountinfo ); i++ )
+        {
+           int secspertrack, surfaces, reserved, blocksize, bootpri;
+           uae_u64 size;
+           int cylinders, readonly, type;
+           char *volname, *devname, *rootdir;
+            char *failure;
+
+           failure = get_filesys_unit (currprefs.mountinfo, i,
+                                       &devname, &volname, &rootdir, &readonly,
+                                       &secspertrack, &surfaces, &reserved,
+                                       &cylinders, &size, &blocksize, &bootpri, 0);
+           type = is_hardfile (currprefs.mountinfo, i);
+           
+           if (size >= 1024 * 1024 * 1024)
+               sprintf (size_str, "%.1fG", ((double)(uae_u32)(size / (1024 * 1024))) / 1024.0);
+           else
+               sprintf (size_str, "%.1fM", ((double)(uae_u32)(size / (1024))) / 1024.0);
+            if (type == FILESYS_HARDFILE) {
+               sprintf (blocksize_str, "%d", blocksize);
+               strcpy (devname_str, devname);
+               strcpy (volname_str, "n/a");
+               sprintf (bootpri_str, "%d", bootpri);
+            } else if (type == FILESYS_HARDFILE_RDB || type == FILESYS_HARDDRIVE) {
+                sprintf (blocksize_str, "%d", blocksize);
+               strcpy (devname_str, "n/a");
+               strcpy (volname_str, "n/a");
+               strcpy (bootpri_str, "n/a");
+           } else {
+                strcpy (blocksize_str, "n/a");
+               strcpy (devname_str, devname);
+               strcpy (volname_str, volname);
+               strcpy (size_str, "n/a");
+               sprintf (bootpri_str, "%d", bootpri);
+            }
+            sprintf( readwrite_str, "%s", readonly ? "no" : "yes" );
+
+           lvstruct.mask     = LVIF_TEXT | LVIF_PARAM;
+            lvstruct.pszText  = devname_str;
+            lvstruct.lParam   = 0;
+            lvstruct.iItem    = i;
+            lvstruct.iSubItem = 0;
+            result = ListView_InsertItem (list, &lvstruct);
+            if (result != -1) {
+                width = ListView_GetStringWidth( list, devname_str) + 15;
+                if( width > listview_column_width[0] )
+                    listview_column_width[0] = width;
+
+               ListView_SetItemText( list, result, 1, volname_str );
+                width = ListView_GetStringWidth( list, volname_str ) + 15;
+                if( width > listview_column_width[ 1 ] )
+                    listview_column_width[ 1 ] = width;
+
+               listview_column_width [ 2 ] = 150;
+                ListView_SetItemText( list, result, 2, rootdir );
+                width = ListView_GetStringWidth( list, rootdir ) + 15;
+                if( width > listview_column_width[ 2 ] )
+                    listview_column_width[ 2 ] = width;
+
+               ListView_SetItemText( list, result, 3, readwrite_str );
+                width = ListView_GetStringWidth( list, readwrite_str ) + 15;
+                if( width > listview_column_width[ 3 ] )
+                    listview_column_width[ 3 ] = width;
+
+               ListView_SetItemText( list, result, 4, blocksize_str );
+                width = ListView_GetStringWidth( list, blocksize_str ) + 15;
+                if( width > listview_column_width[ 4 ] )
+                    listview_column_width[ 4 ] = width;
+
+               ListView_SetItemText( list, result, 5, size_str );
+                width = ListView_GetStringWidth( list, size_str ) + 15;
+                if( width > listview_column_width[ 5 ] )
+                    listview_column_width[ 5 ] = width;
+
+               ListView_SetItemText( list, result, 6, bootpri_str );
+                width = ListView_GetStringWidth( list, bootpri_str ) + 15;
+                if( width > listview_column_width[ 6 ] )
+                    listview_column_width[ 6 ] = width;
+           }
+        }
+#endif
+    }
+
+    if( result != -1 )
+    {
+        if( GetWindowRect( list, &rect ) )
+        {
+            ScreenToClient( hDlg, (LPPOINT)&rect );
+            ScreenToClient( hDlg, (LPPOINT)&rect.right );
+            if( listview_num_columns == 2 )
+            {
+                if( ( temp = rect.right - rect.left - listview_column_width[ 0 ] - 4 ) > listview_column_width[1] )
+                    listview_column_width[1] = temp;
+            }
+        }
+
+        // Adjust our column widths so that we can see the contents...
+        for( i = 0; i < listview_num_columns; i++ )
+        {
+            ListView_SetColumnWidth( list, i, listview_column_width[i] );
+        }
+
+        // Turn on full-row-select option
+        ListView_SetExtendedListViewStyle( list, LVS_EX_FULLROWSELECT );
+
+        // Redraw the items in the list...
+        items = ListView_GetItemCount( list );
+        ListView_RedrawItems( list, 0, items );
+    }
+}
+
+static int listview_find_selected (HWND list)
+{
+    int i, items;
+    items = ListView_GetItemCount (list);
+    for (i = 0; i < items; i++) {
+       if (ListView_GetItemState (list, i, LVIS_SELECTED) == LVIS_SELECTED)
+           return i;
+    }
+    return -1;
+}
+
+static int listview_entry_from_click (HWND list, int *column)
+{
+    POINT point;
+    DWORD pos = GetMessagePos ();
+    int items, entry;
+
+    point.x = LOWORD (pos);
+    point.y = HIWORD (pos);
+    ScreenToClient (list, &point);
+    entry = ListView_GetTopIndex (list);
+    items = entry + ListView_GetCountPerPage (list);
+    if (items > ListView_GetItemCount (list))
+       items = ListView_GetItemCount (list);
+
+    while (entry <= items) {
+       RECT rect;
+       /* Get the bounding rectangle of an item. If the mouse
+        * location is within the bounding rectangle of the item,
+        * you know you have found the item that was being clicked.  */
+       ListView_GetItemRect (list, entry, &rect, LVIR_BOUNDS);
+       if (PtInRect (&rect, point)) {
+           int i, x = 0;
+           UINT flag = LVIS_SELECTED | LVIS_FOCUSED;
+           ListView_SetItemState (list, entry, flag, flag);
+           for (i = 0; i < listview_num_columns && column; i++) {
+               if (x < point.x && x + listview_column_width[i] > point.x) {
+                   *column = i;
+                   break;
+               }
+               x += listview_column_width[i];
+           }
+           return entry;
+       }
+       entry++;
+    }
+    return -1;
+}
+
+static int CALLBACK InfoSettingsProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    static int recursive = 0;
+    
+    switch (msg) 
+    {
+       case WM_INITDIALOG:
+           recursive++;
+           SetDlgItemText (hDlg, IDC_PATH_NAME, workprefs.info);
+           recursive--;
+       return TRUE;
+       
+       case WM_COMMAND:
+           if (recursive)
+               break;
+           recursive++;
+       
+           switch( wParam ) 
+           {
+               case IDC_SELECTOR:
+                   DiskSelection (hDlg, IDC_PATH_NAME, 8, &workprefs, 0);
+               break;
+               case IDOK:
+                   EndDialog (hDlg, 1);
+               break;
+               case IDCANCEL:
+                   EndDialog (hDlg, 0);
+               break;
+           }
+       
+           GetDlgItemText( hDlg, IDC_PATH_NAME, workprefs.info, sizeof workprefs.info );
+           recursive--;
+       break;
+    }
+    return FALSE;
+}
+
+static HTREEITEM AddConfigNode (HWND hDlg, struct ConfigStruct *config, char *name, char *desc, char *path, int isdir, HTREEITEM parent)
+{
+    TVINSERTSTRUCT is;
+    HWND TVhDlg;
+    char s[MAX_PATH] = "";
+    char file_name[MAX_PATH], file_path[MAX_PATH];
+
+    GetDlgItemText (hDlg, IDC_EDITNAME, file_name, MAX_PATH);
+    GetDlgItemText (hDlg, IDC_EDITPATH, file_path, MAX_PATH);
+    TVhDlg = GetDlgItem(hDlg, IDC_CONFIGTREE);
+    memset (&is, 0, sizeof (is));
+    is.hInsertAfter = isdir < 0 ? TVI_ROOT : TVI_SORT;
+    is.hParent = parent;
+    is.itemex.mask = TVIF_TEXT | TVIF_STATE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
+    if (!strcmp (file_name, name) && !strcmp (file_path, path)) {
+       is.itemex.state |= TVIS_SELECTED;
+       is.itemex.stateMask |= TVIS_SELECTED;
+    }
+    if (isdir) {
+       strcat (s, " ");
+       is.itemex.state |= TVIS_BOLD;
+       is.itemex.stateMask |= TVIS_BOLD;
+    }
+    if (isdir < 0) {
+       is.itemex.state |= TVIS_EXPANDED;
+       is.itemex.stateMask |= TVIS_EXPANDED;
+    }
+    strcat (s, name);
+    if (desc && strlen(desc) > 0) {
+       strcat (s, " (");
+       strcat (s, desc);
+       strcat (s, ")");
+    }
+    is.itemex.pszText = s;
+    is.itemex.iImage = is.itemex.iSelectedImage = isdir > 0 ? 0 : (isdir < 0) ? 2 : 1;
+    is.itemex.lParam = (LPARAM)config;
+    return TreeView_InsertItem (TVhDlg, &is);
+}
+
+static void LoadConfigTreeView (HWND hDlg, int idx, HTREEITEM parent)
+{
+    struct ConfigStruct *cparent, *config;
+
+    if (configstoresize == 0)
+       return;
+    if (idx < 0) {
+       idx = 0;
+       for (;;) {
+           config = configstore[idx];
+           if (config->Parent == NULL)
+               break;
+           idx++;
+           if (idx >= configstoresize)
+               return;
+       }
+    }
+    cparent = configstore[idx]->Parent;
+    idx = 0;
+    for (;;) {
+        config = configstore[idx];
+       if (config->Parent == cparent) {
+           if (config->Directory && config->Child) {
+               HTREEITEM par = AddConfigNode (hDlg, config, config->Name, NULL, config->Path, 1, parent);
+               int idx2 = 0;
+               for (;;) {
+                   if (configstore[idx2] == config->Child) {
+                       config->item = par;
+                       LoadConfigTreeView (hDlg, idx2, par);
+                       break;
+                   }
+                   idx2++;
+                   if (idx2 >= configstoresize)
+                       break;
+               }
+           } else if (!config->Directory) {
+               config->item = AddConfigNode (hDlg, config, config->Name, config->Description, config->Path, 0, parent);
+           }
+       }
+       idx++;
+       if (idx >= configstoresize)
+           break;
+    }
+}
+
+static HTREEITEM InitializeConfigTreeView (HWND hDlg)
+{
+    HIMAGELIST himl = ImageList_Create (16, 16, ILC_COLOR8 | ILC_MASK, 3, 0);
+    HWND TVhDlg = GetDlgItem(hDlg, IDC_CONFIGTREE);
+    HTREEITEM parent;
+    char path[MAX_PATH];
+    int i;
+
+    if (himl) {
+       HICON icon;
+       icon = LoadIcon (hInst, (LPCSTR)MAKEINTRESOURCE(IDI_FOLDER));
+       ImageList_AddIcon (himl, icon);
+       icon = LoadIcon (hInst, (LPCSTR)MAKEINTRESOURCE(IDI_CONFIGFILE));
+       ImageList_AddIcon (himl, icon);
+       icon = LoadIcon (hInst, (LPCSTR)MAKEINTRESOURCE(IDI_ROOT));
+       ImageList_AddIcon (himl, icon);
+       TreeView_SetImageList (TVhDlg, himl, TVSIL_NORMAL);
+    }
+    for (i = 0; i < configstoresize; i++)
+       configstore[i]->item = NULL;
+    TreeView_DeleteAllItems (TVhDlg);
+    GetConfigPath (path, NULL, FALSE);
+    parent = AddConfigNode (hDlg, NULL, path, NULL, NULL, -1, NULL);
+    LoadConfigTreeView (hDlg, -1, parent);
+    return parent;
+}
+
+static void ConfigToRegistry (struct ConfigStruct *config)
+{
+    if (hWinUAEKey) {
+       char path[MAX_PATH];
+       strcpy (path, config->Path);
+       strncat (path, config->Name, MAX_PATH);
+       RegSetValueEx (hWinUAEKey, "ConfigFile", 0, REG_SZ, (CONST BYTE *)path, strlen(path));
+    }
+}
+
+static BOOL CALLBACK LoadSaveDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    char name_buf[MAX_PATH];
+    char *cfgfile;
+    static int recursive;
+    HTREEITEM root;
+    static struct ConfigStruct *config;
+    int i;
+    
+    switch (msg)
+    {
+    case WM_INITDIALOG:
+       recursive++;
+       pages[LOADSAVE_ID] = hDlg;
+       currentpage = LOADSAVE_ID;
+       EnableWindow (GetDlgItem( hDlg, IDC_VIEWINFO ), workprefs.info[0]);
+       SetDlgItemText (hDlg, IDC_EDITNAME, config_filename);
+       SetDlgItemText (hDlg, IDC_EDITPATH, "");
+       SetDlgItemText (hDlg, IDC_EDITDESCRIPTION, workprefs.description);
+       root = InitializeConfigTreeView (hDlg);
+       if (hWinUAEKey) {
+           DWORD dwType = REG_SZ;
+           DWORD dwRFPsize = sizeof (name_buf);
+           char path[MAX_PATH];
+           if (RegQueryValueEx (hWinUAEKey, "ConfigFile", 0, &dwType, (LPBYTE)name_buf, &dwRFPsize) == ERROR_SUCCESS) {
+               for (i = 0; i < configstoresize; i++) {
+                   strcpy (path, configstore[i]->Path);
+                   strncat (path, configstore[i]->Name, MAX_PATH);
+                   if (!strcmp (name_buf, path)) {
+                       config = configstore[i];
+                       break;
+                   }
+               }
+           }
+       }
+       if (config && config->item)
+           TreeView_SelectItem (GetDlgItem(hDlg, IDC_CONFIGTREE), config->item);
+       else
+           TreeView_SelectItem (GetDlgItem(hDlg, IDC_CONFIGTREE), root);
+/*
+       SendDlgItemMessage(hDlg, IDC_CONFIGTYPE, CB_RESETCONTENT, 0, 0);
+       SendDlgItemMessage(hDlg, IDC_CONFIGTYPE, CB_ADDSTRING, 0, (LPARAM)"Complete configuration file");
+       SendDlgItemMessage(hDlg, IDC_CONFIGTYPE, CB_ADDSTRING, 0, (LPARAM)"Hardware only configuration file");
+       SendDlgItemMessage(hDlg, IDC_CONFIGTYPE, CB_ADDSTRING, 0, (LPARAM)"Host only configuration file");
+       SendDlgItemMessage(hDlg, IDC_CONFIGTYPE, CB_SETCURSEL, currentpage_sub, 0);
+*/
+       recursive--;
+       return TRUE;
+
+    case WM_USER:
+       break;
+       
+    case WM_COMMAND:
+        switch (LOWORD (wParam))
+        {
+           case IDC_CONFIGTYPE:
+               if (HIWORD (wParam) == CBN_SELCHANGE) {
+                   currentpage_sub = SendDlgItemMessage (hDlg, IDC_CONFIGTYPE, CB_GETCURSEL, 0, 0);
+                   InitializeConfigTreeView (hDlg);
+               }
+           break;
+           case IDC_SAVE:
+               HandleConfiguration (hDlg, CONFIG_SAVE_FULL, config);
+               recursive++;
+               CreateConfigStore ();
+               InitializeConfigTreeView (hDlg);
+               recursive--;
+           break;
+           case IDC_QUICKSAVE:
+               HandleConfiguration (hDlg, CONFIG_SAVE, config);
+               recursive++;
+               CreateConfigStore ();
+               InitializeConfigTreeView (hDlg);
+               recursive--;
+           break;
+           case IDC_QUICKLOAD:
+               cfgfile = HandleConfiguration (hDlg, CONFIG_LOAD, config);
+               ConfigToRegistry (config);
+               if (full_property_sheet) {
+                   inputdevice_updateconfig (&workprefs);
+               } else {
+                   uae_restart (1, cfgfile);
+                   exit_gui(1);
+               }
+           break;
+           case IDC_LOAD:
+               cfgfile = HandleConfiguration (hDlg, CONFIG_LOAD_FULL, config);
+               ConfigToRegistry (config);
+               if (full_property_sheet) {
+                   inputdevice_updateconfig (&workprefs);
+               } else {
+                   uae_restart (1, cfgfile);
+                   exit_gui(1);
+               }
+           break;
+           case IDC_DELETE:
+               HandleConfiguration (hDlg, CONFIG_DELETE, config);
+               recursive++;
+               CreateConfigStore ();
+               InitializeConfigTreeView (hDlg);
+               recursive--;
+           break;
+           case IDC_VIEWINFO:
+               if (workprefs.info[0])
+               {
+                   if (strstr( workprefs.info, "Configurations\\"))
+                       sprintf( name_buf, "%s\\%s", start_path, workprefs.info );
+                   else
+                       strcpy( name_buf, workprefs.info );
+                   ShellExecute( NULL, NULL, name_buf, NULL, NULL, SW_SHOWNORMAL );
+               }
+           break;
+           case IDC_SETINFO:
+               if (DialogBox(hUIDLL ? hUIDLL : hInst, MAKEINTRESOURCE (IDD_SETINFO), hDlg, InfoSettingsProc))
+                   EnableWindow( GetDlgItem( hDlg, IDC_VIEWINFO ), workprefs.info[0] );
+           break;
+       }
+       break;
+       
+       case WM_NOTIFY:
+       {
+           LPNMHDR nm = (LPNMHDR)lParam;
+           if (nm->hwndFrom == GetDlgItem( hDlg, IDC_CONFIGTREE)) {
+               switch (nm->code)
+               {
+                   case NM_DBLCLK:
+                   {
+                       HTREEITEM ht = TreeView_GetSelection (GetDlgItem(hDlg, IDC_CONFIGTREE));
+                       if (ht != NULL) {
+                           TVITEMEX pitem;
+                           memset (&pitem, 0, sizeof (pitem));
+                           pitem.mask = TVIF_HANDLE | TVIF_PARAM;
+                           pitem.hItem = ht;
+                           if (TreeView_GetItem (GetDlgItem(hDlg, IDC_CONFIGTREE), &pitem)) {
+                               struct ConfigStruct *config = (struct ConfigStruct*)pitem.lParam;
+                               if (config && !config->Directory) {
+                                   cfgfile = HandleConfiguration (hDlg, CONFIG_LOAD, config);
+                                   ConfigToRegistry (config);
+                                   if (!full_property_sheet)
+                                       uae_restart (0, cfgfile);
+                                   exit_gui (1);
+                               }
+                           }
+                       }
+                       return TRUE;
+                   }
+                   break;
+                   case TVN_SELCHANGING:
+                   return FALSE;
+                   case TVN_SELCHANGED:
+                   {
+                       LPNMTREEVIEW tv = (LPNMTREEVIEW)lParam;
+                       config = (struct ConfigStruct*)tv->itemNew.lParam;
+                       if (config) {
+                           if (!config->Directory) {
+                               SetDlgItemText (hDlg, IDC_EDITNAME, config->Name);
+                               SetDlgItemText (hDlg, IDC_EDITDESCRIPTION, config->Description);
+                           }
+                           SetDlgItemText (hDlg, IDC_EDITPATH, config->Path);
+                       }
+                       return TRUE;
+                   }
+                   break;
+               }
+           }
+           break;
+       }
+    }
+    
+    return FALSE;
+}
+
+#define MAX_CONTRIBUTORS_LENGTH 2048
+
+static int CALLBACK ContributorsProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    CHARFORMAT CharFormat;
+    char szContributors1[ MAX_CONTRIBUTORS_LENGTH ];
+    char szContributors2[ MAX_CONTRIBUTORS_LENGTH ];
+    char szContributors[ MAX_CONTRIBUTORS_LENGTH*2 ];
+
+    switch (msg) {
+     case WM_COMMAND:
+       if (wParam == ID_OK) {
+           EndDialog (hDlg, 1);
+           return TRUE;
+       }
+       break;
+     case WM_INITDIALOG:
+       CharFormat.cbSize = sizeof (CharFormat);
+
+       WIN32GUI_LoadUIString( IDS_CONTRIBUTORS1, szContributors1, MAX_CONTRIBUTORS_LENGTH );
+       WIN32GUI_LoadUIString( IDS_CONTRIBUTORS2, szContributors2, MAX_CONTRIBUTORS_LENGTH );
+       sprintf( szContributors, "%s%s", szContributors1, szContributors2 );
+
+       SetDlgItemText (hDlg, IDC_CONTRIBUTORS, szContributors );
+       SendDlgItemMessage (hDlg, IDC_CONTRIBUTORS, EM_GETCHARFORMAT, 0, (LPARAM) & CharFormat);
+       CharFormat.dwMask |= CFM_SIZE | CFM_FACE;
+       CharFormat.yHeight = 10 * 20;   /* height in twips, where a twip is 1/20th of a point - for a pt.size of 18 */
+
+       strcpy (CharFormat.szFaceName, "Times New Roman");
+       SendDlgItemMessage (hDlg, IDC_CONTRIBUTORS, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) & CharFormat);
+       /* SendDlgItemMessage(hDlg, IDC_CONTRIBUTORS, EM_SETBKGNDCOLOR,0,GetSysColor( COLOR_3DFACE ) ); */
+
+       return TRUE;
+    }
+    return FALSE;
+}
+
+static void DisplayContributors (HWND hDlg)
+{
+    DialogBox( hUIDLL ? hUIDLL : hInst, MAKEINTRESOURCE (IDD_CONTRIBUTORS), hDlg, ContributorsProc);
+}
+
+#define NUM_URLS 8
+typedef struct url_info
+{
+    int   id;
+    BOOL  state;
+    char *display;
+    char *url;
+} urlinfo;
+
+static urlinfo urls[NUM_URLS] = 
+{
+    {IDC_CLOANTOHOME, FALSE, "Cloanto's Amiga Forever", "http://www.amigaforever.com/"},
+    {IDC_AMIGAHOME, FALSE, "Amiga Inc.", "http://www.amiga.com"},
+    {IDC_PICASSOHOME, FALSE, "Picasso96 Home Page", "http://www.picasso96.cogito.de/"}, 
+    {IDC_UAEHOME, FALSE, "UAE Home Page", "http://www.freiburg.linux.de/~uae/"},
+    {IDC_WINUAEHOME, FALSE, "WinUAE Home Page", "http://www.winuae.net/"},
+    {IDC_AIABHOME, FALSE, "AIAB", "http://aiab.emuunlim.com/"},
+    {IDC_THEROOTS, FALSE, "Back To The Roots", "http://back2roots.emuunlim.com/"},
+    {IDC_CAPS, FALSE, "CAPS", "http://caps-project.org/"}
+};
+
+static void SetupRichText( HWND hDlg, urlinfo *url )
+{
+    CHARFORMAT CharFormat;
+    CharFormat.cbSize = sizeof (CharFormat);
+
+    SetDlgItemText( hDlg, url->id, url->display );
+    SendDlgItemMessage( hDlg, url->id, EM_GETCHARFORMAT, 0, (LPARAM)&CharFormat );
+    CharFormat.dwMask   |= CFM_UNDERLINE | CFM_SIZE | CFM_FACE | CFM_COLOR;
+    CharFormat.dwEffects = url->state ? CFE_UNDERLINE : 0;
+    CharFormat.yHeight = 10 * 20;      /* height in twips, where a twip is 1/20th of a point - for a pt.size of 18 */
+
+    CharFormat.crTextColor = GetSysColor( COLOR_ACTIVECAPTION );
+    strcpy( CharFormat.szFaceName, "Tahoma" );
+    SendDlgItemMessage( hDlg, url->id, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&CharFormat );
+    SendDlgItemMessage( hDlg, url->id, EM_SETBKGNDCOLOR, 0, GetSysColor( COLOR_3DFACE ) );
+}
+
+static void url_handler(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+    static int last_rectangle = -1;
+    int i;
+    BOOL found = FALSE;
+    HCURSOR m_hCursor = NULL;
+    POINT point;
+    point.x = LOWORD (lParam);
+    point.y = HIWORD (lParam);
+    
+    for (i = 0; i < NUM_URLS; i++) 
+    {
+       RECT rect;
+       GetWindowRect( GetDlgItem( hDlg, urls[i].id), &rect );
+       ScreenToClient( hDlg, (POINT *) &rect );
+       ScreenToClient( hDlg, (POINT *) &(rect.right) );
+       if( PtInRect( &rect, point ) ) 
+        {
+            if( msg == WM_LBUTTONDOWN )
+            {
+               ShellExecute (NULL, NULL, urls[i].url , NULL, NULL, SW_SHOWNORMAL);
+                SetCursor( LoadCursor( NULL, MAKEINTRESOURCE(IDC_ARROW) ) );
+            }
+            else
+            {
+                if( ( i != last_rectangle ) )
+                {
+                   // try and load the system hand (Win2000+)
+                   m_hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_HAND) );
+                   if (!m_hCursor)
+                   {
+                       // retry with our fallback hand
+                       m_hCursor = LoadCursor(hInst, MAKEINTRESOURCE(IDC_MYHAND) );
+                   }
+                    SetCursor( m_hCursor );
+                    urls[i].state = TRUE;
+                    SetupRichText( hDlg, &urls[i] );
+
+                   if( last_rectangle != -1 )
+                   {
+                       urls[last_rectangle].state = FALSE;
+                       SetupRichText( hDlg, &urls[last_rectangle] );
+                   }
+                }
+            }
+           last_rectangle = i;
+            found = TRUE;
+           break;
+       }
+    }
+
+    if( !found && last_rectangle >= 0 )
+    {
+        SetCursor( LoadCursor( NULL, MAKEINTRESOURCE(IDC_ARROW) ) );
+        urls[last_rectangle].state = FALSE;
+        SetupRichText( hDlg, &urls[last_rectangle] );
+       last_rectangle = -1;
+    }
+}
+
+static void init_aboutdlg (HWND hDlg)
+{
+    CHARFORMAT CharFormat;
+    int i;
+
+    CharFormat.cbSize = sizeof (CharFormat);
+
+    SetDlgItemText (hDlg, IDC_RICHEDIT1, "WinUAE");
+    SendDlgItemMessage (hDlg, IDC_RICHEDIT1, EM_GETCHARFORMAT, 0, (LPARAM) & CharFormat);
+    CharFormat.dwMask |= CFM_BOLD | CFM_SIZE | CFM_FACE;
+    CharFormat.dwEffects = CFE_BOLD;
+    CharFormat.yHeight = 18 * 20;      /* height in twips, where a twip is 1/20th of a point - for a pt.size of 18 */
+
+    strcpy (CharFormat.szFaceName, "Times New Roman");
+    SendDlgItemMessage (hDlg, IDC_RICHEDIT1, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) & CharFormat);
+    SendDlgItemMessage (hDlg, IDC_RICHEDIT1, EM_SETBKGNDCOLOR, 0, GetSysColor (COLOR_3DFACE));
+
+    SetDlgItemText (hDlg, IDC_RICHEDIT2, VersionStr );
+    SendDlgItemMessage (hDlg, IDC_RICHEDIT2, EM_GETCHARFORMAT, 0, (LPARAM) & CharFormat);
+    CharFormat.dwMask |= CFM_SIZE | CFM_FACE;
+    CharFormat.yHeight = 10 * 20;
+    strcpy (CharFormat.szFaceName, "Times New Roman");
+    SendDlgItemMessage (hDlg, IDC_RICHEDIT2, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) & CharFormat);
+    SendDlgItemMessage (hDlg, IDC_RICHEDIT2, EM_SETBKGNDCOLOR, 0, GetSysColor (COLOR_3DFACE));
+
+    for( i = 0; i < NUM_URLS; i++ )
+    {
+        SetupRichText( hDlg, &urls[i] );
+    }
+}
+
+static BOOL CALLBACK AboutDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    switch( msg )
+    {
+       case WM_INITDIALOG:
+           pages[ABOUT_ID] = hDlg;
+           currentpage = ABOUT_ID;
+           init_aboutdlg (hDlg);
+           break;
+           
+       case WM_COMMAND:
+           if (wParam == IDC_CONTRIBUTORS) 
+           {
+               DisplayContributors (hDlg);
+           }
+           break;
+       case WM_SETCURSOR:
+           return TRUE;
+           break;
+       case WM_LBUTTONDOWN:
+       case WM_MOUSEMOVE:
+           url_handler( hDlg, msg, wParam, lParam );
+           break;
+    }
+    
+    return FALSE;
+}
+
+static void enable_for_displaydlg (HWND hDlg)
+{
+    int rtg = ! workprefs.address_space_24;
+#ifndef PICASSO96
+    rtg = FALSE;
+#endif
+    EnableWindow( GetDlgItem( hDlg, IDC_PFULLSCREEN ), rtg);
+    if (! full_property_sheet) 
+    {
+       /* Disable certain controls which are only to be set once at start-up... */
+        EnableWindow (GetDlgItem (hDlg, IDC_TEST16BIT), FALSE);
+    }
+    else
+    {
+        CheckDlgButton( hDlg, IDC_VSYNC, workprefs.gfx_vsync);
+        if (workprefs.gfx_filter) {
+           EnableWindow (GetDlgItem (hDlg, IDC_XCENTER), FALSE);
+           EnableWindow (GetDlgItem (hDlg, IDC_YCENTER), FALSE);
+           EnableWindow (GetDlgItem (hDlg, IDC_LM_SCANLINES), FALSE);
+           if (workprefs.gfx_linedbl == 2)
+               workprefs.gfx_linedbl = 1;
+           workprefs.gfx_xcenter = workprefs.gfx_ycenter = 0;
+       } else {
+           EnableWindow (GetDlgItem (hDlg, IDC_XCENTER), TRUE);
+           EnableWindow (GetDlgItem (hDlg, IDC_YCENTER), TRUE);
+           EnableWindow (GetDlgItem (hDlg, IDC_LM_SCANLINES), TRUE);
+       }
+    }
+}
+
+static void enable_for_chipsetdlg (HWND hDlg)
+{
+    int enable = workprefs.cpu_cycle_exact ? FALSE : TRUE;
+
+#if !defined (CPUEMU_6)
+    EnableWindow (GetDlgItem (hDlg, IDC_CYCLEEXACT), FALSE);
+#endif
+    EnableWindow (GetDlgItem (hDlg, IDC_FASTCOPPER), enable);
+    EnableWindow (GetDlgItem (hDlg, IDC_BLITIMM), enable);
+    if (enable == FALSE) {
+       workprefs.fast_copper = 0;
+       workprefs.immediate_blits = 0;
+       CheckDlgButton (hDlg, IDC_FASTCOPPER, FALSE);
+       CheckDlgButton (hDlg, IDC_BLITIMM, FALSE);
+    }
+}
+
+static void LoadNthString( DWORD value, char *nth, DWORD dwNthMax )
+{
+    switch( value )
+    {
+       case 1:
+           WIN32GUI_LoadUIString( IDS_SECOND, nth, dwNthMax );
+       break;
+
+       case 2:
+           WIN32GUI_LoadUIString( IDS_THIRD, nth, dwNthMax );  
+       break;
+       
+       case 3:
+           WIN32GUI_LoadUIString( IDS_FOURTH, nth, dwNthMax ); 
+       break;
+       
+       case 4:
+           WIN32GUI_LoadUIString( IDS_FIFTH, nth, dwNthMax );  
+       break;
+       
+       case 5:
+           WIN32GUI_LoadUIString( IDS_SIXTH, nth, dwNthMax );  
+       break;
+       
+       case 6:
+           WIN32GUI_LoadUIString( IDS_SEVENTH, nth, dwNthMax );        
+       break;
+       
+       case 7:
+           WIN32GUI_LoadUIString( IDS_EIGHTH, nth, dwNthMax ); 
+       break;
+       
+       case 8:
+           WIN32GUI_LoadUIString( IDS_NINTH, nth, dwNthMax );  
+       break;
+       
+       case 9:
+           WIN32GUI_LoadUIString( IDS_TENTH, nth, dwNthMax );  
+       break;
+       
+       default:
+           strcpy( nth, "" );
+    }
+}
+
+static int fakerefreshrates[] = { 50, 60, 100, 120, 0 };
+static int storedrefreshrates[MAX_REFRESH_RATES + 1];
+
+static void init_frequency_combo (HWND hDlg, int dmode)
+{
+    int i, j, freq, index, tmp;
+    char hz[20], hz2[20], txt[100];
+    
+    i = 0; index = 0;
+    while ((freq = DisplayModes[dmode].refresh[i]) > 0 && index < MAX_REFRESH_RATES) {
+       storedrefreshrates[index++] = freq;
+       i++;
+    }
+    i = 0;
+    while ((freq = fakerefreshrates[i]) > 0 && index < MAX_REFRESH_RATES) {
+       for (j = 0; j < index; j++) {
+           if (storedrefreshrates[j] == freq) break;
+       }
+       if (j == index)
+           storedrefreshrates[index++] = -freq;
+       i++;
+    }
+    storedrefreshrates[index] = 0;
+    for (i = 0; i < index; i++) {
+       for (j = i + 1; j < index; j++) {
+           if (abs(storedrefreshrates[i]) >= abs(storedrefreshrates[j])) {
+               tmp = storedrefreshrates[i];
+               storedrefreshrates[i] = storedrefreshrates[j];
+               storedrefreshrates[j] = tmp;
+           }
+       }
+    }
+
+    hz[0] = hz2[0] = 0;
+    SendDlgItemMessage(hDlg, IDC_REFRESHRATE, CB_RESETCONTENT, 0, 0);
+    WIN32GUI_LoadUIString (IDS_VSYNC_DEFAULT, txt, sizeof (txt));
+    SendDlgItemMessage( hDlg, IDC_REFRESHRATE, CB_ADDSTRING, 0, (LPARAM)txt);
+    for (i = 0; i < index; i++) {
+       freq = storedrefreshrates[i];
+       if (freq < 0) {
+           freq = -freq;
+           sprintf (hz, "(%dHz)", freq);
+       } else {
+           sprintf (hz, "%dHz", freq);
+       }
+       if (freq == 50 || freq == 100)
+           strcat (hz, " PAL");
+       if (freq == 60 || freq == 120)
+           strcat (hz, " NTSC");
+       if (abs(workprefs.gfx_refreshrate) == freq)
+           strcpy (hz2, hz);
+       SendDlgItemMessage( hDlg, IDC_REFRESHRATE, CB_ADDSTRING, 0, (LPARAM)hz);
+    }
+    index = CB_ERR;
+    if (hz2[0] >= 0)
+       index = SendDlgItemMessage( hDlg, IDC_REFRESHRATE, CB_SELECTSTRING, 0, (LPARAM)hz2 );
+    if (index == CB_ERR) {
+        WIN32GUI_LoadUIString (IDS_VSYNC_DEFAULT, txt, sizeof (txt));
+       SendDlgItemMessage( hDlg, IDC_REFRESHRATE, CB_SELECTSTRING, i, (LPARAM)txt);
+       workprefs.gfx_refreshrate = 0;
+    }
+}
+
+#define MAX_FRAMERATE_LENGTH 40
+#define MAX_NTH_LENGTH 20
+
+static int display_mode_index( uae_u32 x, uae_u32 y, uae_u32 d )
+{
+    int i;
+    i = 0;
+    while (DisplayModes[i].depth >= 0) {
+        if( DisplayModes[i].res.width == x &&
+            DisplayModes[i].res.height == y &&
+            DisplayModes[i].depth == d )
+            break;
+       i++;
+    }
+    if(DisplayModes[i].depth < 0)
+        i = -1;
+    return i;
+}
+
+#if 0
+static int da_mode_selected;
+
+static int *getp_da (void)
+{
+    int *p = 0;
+    switch (da_mode_selected)
+    {
+       case 0:
+       p = &workprefs.gfx_hue;
+       break;
+       case 1:
+       p = &workprefs.gfx_saturation;
+       break;
+       case 2:
+       p = &workprefs.gfx_luminance;
+       break;
+       case 3:
+       p = &workprefs.gfx_contrast;
+       break;
+       case 4:
+       p = &workprefs.gfx_gamma;
+       break;
+    }
+    return p;
+}
+
+static void handle_da (HWND hDlg)
+{
+    int *p;
+    int v;
+
+    p = getp_da ();
+    if (!p)
+       return;
+    v = SendDlgItemMessage (hDlg, IDC_DA_SLIDER, TBM_GETPOS, 0, 0) * 10;
+    if (v == *p)
+       return;
+    *p = v;
+    currprefs.gfx_hue = workprefs.gfx_hue;
+    currprefs.gfx_saturation = workprefs.gfx_saturation;
+    currprefs.gfx_luminance = workprefs.gfx_luminance;
+    currprefs.gfx_contrast = workprefs.gfx_contrast;
+    currprefs.gfx_gamma = workprefs.gfx_gamma;
+    init_colors ();
+    reset_drawing ();
+    redraw_frame ();
+    updatedisplayarea ();
+}
+
+void init_da (HWND hDlg)
+{
+    int *p;
+    SendDlgItemMessage(hDlg, IDC_DA_MODE, CB_RESETCONTENT, 0, 0);
+    SendDlgItemMessage(hDlg, IDC_DA_MODE, CB_ADDSTRING, 0, (LPARAM)"Hue");
+    SendDlgItemMessage(hDlg, IDC_DA_MODE, CB_ADDSTRING, 0, (LPARAM)"Saturation");
+    SendDlgItemMessage(hDlg, IDC_DA_MODE, CB_ADDSTRING, 0, (LPARAM)"Luminance");
+    SendDlgItemMessage(hDlg, IDC_DA_MODE, CB_ADDSTRING, 0, (LPARAM)"Contrast");
+    SendDlgItemMessage(hDlg, IDC_DA_MODE, CB_ADDSTRING, 0, (LPARAM)"Gamma");
+    if (da_mode_selected == CB_ERR)
+       da_mode_selected = 0;
+    SendDlgItemMessage (hDlg, IDC_DA_MODE, CB_SETCURSEL, da_mode_selected, 0);
+    SendDlgItemMessage (hDlg, IDC_DA_SLIDER, TBM_SETPAGESIZE, 0, 1);
+    SendDlgItemMessage (hDlg, IDC_DA_SLIDER, TBM_SETRANGE, TRUE, MAKELONG (-99, 99));
+    p = getp_da ();
+    if (p)
+        SendDlgItemMessage (hDlg, IDC_DA_SLIDER, TBM_SETPOS, TRUE, (*p) / 10);
+}
+#endif
+
+static void init_display_mode (HWND hDlg)
+{
+   int d, d2, index;
+
+   switch( workprefs.color_mode )
+    {
+    case 2:
+        d = 16;
+        break;
+    case 5:
+        d = 32;
+        break;
+    default:
+        d = 8;
+        break;
+    }
+
+    if( workprefs.gfx_afullscreen )
+    {
+        d2 = d;
+        if( ( index = WIN32GFX_AdjustScreenmode( &workprefs.gfx_width_fs, &workprefs.gfx_height_fs, &d2 ) ) >= 0 )
+        {
+            switch( d2 )
+            {
+            case 15:
+                workprefs.color_mode = 1;
+                d = 2;
+                break;
+            case 16:
+                workprefs.color_mode = 2;
+                d = 2;
+                break;
+            case 32:
+                workprefs.color_mode = 5;
+                d = 4;
+                break;
+            default:
+                workprefs.color_mode = 0;
+                d = 1;
+                break;
+            }
+        }
+    }
+    else
+    {
+        d = d / 8;
+    }
+
+    if ((index = display_mode_index (workprefs.gfx_width_fs, workprefs.gfx_height_fs, d)) >= 0) {
+        SendDlgItemMessage( hDlg, IDC_RESOLUTION, CB_SETCURSEL, index, 0 );
+        init_frequency_combo (hDlg, index);
+    }
+}
+
+static void values_to_displaydlg (HWND hDlg)
+{
+    char buffer[ MAX_FRAMERATE_LENGTH + MAX_NTH_LENGTH ];
+    char Nth[ MAX_NTH_LENGTH ];
+    LPSTR blah[1] = { Nth };
+    LPTSTR string = NULL;
+
+    init_display_mode (hDlg);
+
+    SetDlgItemInt( hDlg, IDC_XSIZE, workprefs.gfx_width_win, FALSE );
+    SetDlgItemInt( hDlg, IDC_YSIZE, workprefs.gfx_height_win, FALSE );
+
+    SendDlgItemMessage (hDlg, IDC_FRAMERATE, TBM_SETPOS, TRUE, workprefs.gfx_framerate);
+
+    WIN32GUI_LoadUIString( IDS_FRAMERATE, buffer, MAX_FRAMERATE_LENGTH );
+    LoadNthString( workprefs.gfx_framerate - 1, Nth, MAX_NTH_LENGTH );
+    if( FormatMessage( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+                      buffer, 0, 0, (LPTSTR)&string, MAX_FRAMERATE_LENGTH + MAX_NTH_LENGTH, (va_list *)blah ) == 0 )
+    {
+       DWORD dwLastError = GetLastError();
+        sprintf (buffer, "Every %s Frame", nth[workprefs.gfx_framerate - 1]);
+       SetDlgItemText( hDlg, IDC_RATETEXT, buffer );
+    }
+    else
+    {
+       SetDlgItemText( hDlg, IDC_RATETEXT, string );
+       LocalFree( string );
+    }
+
+    CheckRadioButton( hDlg, IDC_LM_NORMAL, IDC_LM_SCANLINES, IDC_LM_NORMAL + workprefs.gfx_linedbl );
+    CheckDlgButton (hDlg, IDC_AFULLSCREEN, workprefs.gfx_afullscreen);
+    CheckDlgButton (hDlg, IDC_PFULLSCREEN, workprefs.gfx_pfullscreen);
+    CheckDlgButton (hDlg, IDC_ASPECT, workprefs.gfx_correct_aspect);
+    CheckDlgButton (hDlg, IDC_LORES, workprefs.gfx_linedbl ? FALSE : TRUE);
+    CheckDlgButton (hDlg, IDC_LORES, workprefs.gfx_lores);
+    CheckDlgButton (hDlg, IDC_VSYNC, workprefs.gfx_vsync);
+    
+    CheckDlgButton (hDlg, IDC_XCENTER, workprefs.gfx_xcenter);
+    CheckDlgButton (hDlg, IDC_YCENTER, workprefs.gfx_ycenter);
+
+#if 0
+    init_da (hDlg);
+#endif
+}
+
+static void init_resolution_combo (HWND hDlg)
+{
+    int i = 0;
+    SendDlgItemMessage(hDlg, IDC_RESOLUTION, CB_RESETCONTENT, 0, 0);
+    while (DisplayModes[i].depth >= 0) {
+        SendDlgItemMessage( hDlg, IDC_RESOLUTION, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)DisplayModes[i].name);
+       i++;
+    }
+}
+static void init_displays_combo (HWND hDlg)
+{
+    int i = 0;
+    SendDlgItemMessage(hDlg, IDC_DISPLAYSELECT, CB_RESETCONTENT, 0, 0);
+    while (Displays[i].name) {
+       SendDlgItemMessage( hDlg, IDC_DISPLAYSELECT, CB_ADDSTRING, 0, (LPARAM)Displays[i].name);
+       i++;
+    }
+    if (workprefs.gfx_display >= i)
+       workprefs.gfx_display = 0;
+    SendDlgItemMessage( hDlg, IDC_DISPLAYSELECT, CB_SETCURSEL, workprefs.gfx_display, 0);
+}
+
+static void values_from_displaydlg (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    BOOL success = FALSE;
+    int gfx_width = workprefs.gfx_width_win;
+    int gfx_height = workprefs.gfx_height_win;
+
+    workprefs.gfx_pfullscreen    = IsDlgButtonChecked (hDlg, IDC_PFULLSCREEN);
+    workprefs.gfx_afullscreen    = IsDlgButtonChecked (hDlg, IDC_AFULLSCREEN);
+
+    workprefs.gfx_lores          = IsDlgButtonChecked (hDlg, IDC_LORES);
+    workprefs.gfx_correct_aspect = IsDlgButtonChecked (hDlg, IDC_ASPECT);
+    workprefs.gfx_linedbl = ( IsDlgButtonChecked( hDlg, IDC_LM_SCANLINES ) ? 2 :
+                              IsDlgButtonChecked( hDlg, IDC_LM_DOUBLED ) ? 1 : 0 );
+
+    workprefs.gfx_framerate = SendDlgItemMessage (hDlg, IDC_FRAMERATE, TBM_GETPOS, 0, 0);
+    workprefs.gfx_vsync = IsDlgButtonChecked (hDlg, IDC_VSYNC);
+
+    {
+       char buffer[ MAX_FRAMERATE_LENGTH ];
+       char Nth[ MAX_NTH_LENGTH ];
+       LPSTR blah[1] = { Nth };
+       LPTSTR string = NULL;
+
+       WIN32GUI_LoadUIString( IDS_FRAMERATE, buffer, MAX_FRAMERATE_LENGTH );
+       LoadNthString( workprefs.gfx_framerate - 1, Nth, MAX_NTH_LENGTH );
+       if( FormatMessage( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+                          buffer, 0, 0, (LPTSTR)&string, MAX_FRAMERATE_LENGTH + MAX_NTH_LENGTH, (va_list *)blah ) == 0 )
+       {
+           DWORD dwLastError = GetLastError();
+           sprintf (buffer, "Every %s Frame", nth[workprefs.gfx_framerate - 1]);
+           SetDlgItemText( hDlg, IDC_RATETEXT, buffer );
+       }
+       else
+       {
+           SetDlgItemText( hDlg, IDC_RATETEXT, string );
+           LocalFree( string );
+       }
+       workprefs.gfx_width_win  = GetDlgItemInt( hDlg, IDC_XSIZE, &success, FALSE );
+        if( !success )
+            workprefs.gfx_width_win = 800;
+       workprefs.gfx_height_win = GetDlgItemInt( hDlg, IDC_YSIZE, &success, FALSE );
+        if( !success )
+            workprefs.gfx_height_win = 600;
+    }
+    workprefs.gfx_xcenter = (IsDlgButtonChecked (hDlg, IDC_XCENTER) ? 2 : 0 ); /* Smart centering */
+    workprefs.gfx_ycenter = (IsDlgButtonChecked (hDlg, IDC_YCENTER) ? 2 : 0 ); /* Smart centering */
+
+    if (msg == WM_COMMAND && HIWORD (wParam) == CBN_SELCHANGE) 
+    {
+       if (LOWORD (wParam) == IDC_DISPLAYSELECT) {
+           LONG posn;
+           posn = SendDlgItemMessage (hDlg, IDC_DISPLAYSELECT, CB_GETCURSEL, 0, 0);
+           if (posn != CB_ERR && posn != workprefs.gfx_display) {
+               if (Displays[posn].disabled)
+                   posn = 0;
+               workprefs.gfx_display = posn;
+               DisplayModes = Displays[workprefs.gfx_display].DisplayModes;
+               init_resolution_combo (hDlg);
+               init_display_mode (hDlg);
+           }
+           return;
+       } else if (LOWORD (wParam) == IDC_RESOLUTION) {
+           LONG posn = SendDlgItemMessage (hDlg, IDC_RESOLUTION, CB_GETCURSEL, 0, 0);
+           if (posn == CB_ERR)
+               return;
+           workprefs.gfx_width_fs  = DisplayModes[posn].res.width;
+           workprefs.gfx_height_fs = DisplayModes[posn].res.height;
+           switch( DisplayModes[posn].depth )
+           {
+           case 2:
+               workprefs.color_mode = 2;
+               break;
+           case 3:
+           case 4:
+               workprefs.color_mode = 5;
+               break;
+           default:
+               workprefs.color_mode = 0;
+               break;
+           }
+           /* Set the Int boxes */
+           SetDlgItemInt( hDlg, IDC_XSIZE, workprefs.gfx_width_win, FALSE );
+           SetDlgItemInt( hDlg, IDC_YSIZE, workprefs.gfx_height_win, FALSE );
+           init_frequency_combo (hDlg, posn);
+       } else if (LOWORD (wParam) == IDC_REFRESHRATE) {
+           LONG posn1, posn2;
+           posn1 = SendDlgItemMessage (hDlg, IDC_REFRESHRATE, CB_GETCURSEL, 0, 0);
+           if (posn1 == CB_ERR)
+               return;
+           posn2 = SendDlgItemMessage (hDlg, IDC_RESOLUTION, CB_GETCURSEL, 0, 0);
+           if (posn2 == CB_ERR)
+               return;
+           if (posn1 == 0) {
+               workprefs.gfx_refreshrate = 0;
+           } else {
+               posn1--;
+               workprefs.gfx_refreshrate = storedrefreshrates[posn1];
+           }
+#if 0
+       } else if (LOWORD (wParam) == IDC_DA_MODE) {
+           da_mode_selected = SendDlgItemMessage (hDlg, IDC_DA_MODE, CB_GETCURSEL, 0, 0);
+           init_da (hDlg);
+           handle_da (hDlg);
+#endif
+       }
+    }
+
+    updatewinfsmode (&workprefs);
+}
+
+static int hw3d_changed;
+
+static BOOL CALLBACK DisplayDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    static int recursive = 0;
+    HKEY hPixelFormatKey;
+    RGBFTYPE colortype      = RGBFB_NONE;
+    DWORD dwType            = REG_DWORD;
+    DWORD dwDisplayInfoSize = sizeof( colortype );
+
+    switch (msg) 
+    {
+    case WM_INITDIALOG:
+       pages[DISPLAY_ID] = hDlg;
+       currentpage = DISPLAY_ID;
+       SendDlgItemMessage (hDlg, IDC_FRAMERATE, TBM_SETPAGESIZE, 0, 1);
+       SendDlgItemMessage (hDlg, IDC_FRAMERATE, TBM_SETRANGE, TRUE, MAKELONG (MIN_REFRESH_RATE, MAX_REFRESH_RATE));
+       init_displays_combo( hDlg );
+       init_resolution_combo( hDlg );
+#if 0
+       init_da (hDlg);
+#endif
+
+    case WM_USER:
+       recursive++;
+       values_to_displaydlg (hDlg);
+       enable_for_displaydlg (hDlg);
+       recursive--;
+        break;
+
+    case WM_HSCROLL:
+    case WM_COMMAND:
+       if (recursive > 0)
+           break;
+       recursive++;
+       if( ( wParam == IDC_TEST16BIT ) && DirectDraw_Start(NULL) )
+       {
+           if( RegOpenKeyEx( HKEY_CURRENT_USER, "Software\\Arabuusimiehet\\WinUAE", 0, KEY_ALL_ACCESS, &hPixelFormatKey ) == ERROR_SUCCESS )
+           {
+               char szMessage[ 4096 ];
+               char szTitle[ MAX_PATH ];
+               WIN32GUI_LoadUIString( IDS_GFXCARDCHECK, szMessage, 4096 );
+               WIN32GUI_LoadUIString( IDS_GFXCARDTITLE, szTitle, MAX_PATH );
+                   
+               if( MessageBox( NULL, szMessage, szTitle, 
+                               MB_YESNO | MB_ICONWARNING | MB_TASKMODAL | MB_SETFOREGROUND ) == IDYES )
+               {
+                   colortype = WIN32GFX_FigurePixelFormats(0);
+                   RegSetValueEx( hPixelFormatKey, "DisplayInfo", 0, REG_DWORD, (CONST BYTE *)&colortype, sizeof( colortype ) );
+               }
+               RegCloseKey( hPixelFormatKey );
+           }
+           DirectDraw_Release();
+       }
+       else
+       {
+#if 0
+           handle_da (hDlg);
+#endif
+           values_from_displaydlg (hDlg, msg, wParam, lParam);
+           enable_for_displaydlg( hDlg );
+       }
+       recursive--;
+       break;
+
+    }
+    if (hw3d_changed && recursive == 0) {
+       recursive++;
+        enable_for_displaydlg (hDlg);
+        values_to_displaydlg (hDlg);
+       hw3d_changed = 0;
+       recursive--;
+    }
+    return FALSE;
+}
+
+static void values_to_chipsetdlg (HWND hDlg)
+{
+    char Nth[ MAX_NTH_LENGTH ];
+    LPSTR blah[1] = { Nth };
+    LPTSTR string = NULL;
+    int which_button;
+
+    switch( workprefs.chipset_mask )
+    {
+    case 0:
+       CheckRadioButton( hDlg, IDC_OCS, IDC_AGA, IDC_OCS+0 );
+       break;
+    case CSMASK_ECS_AGNUS:
+       CheckRadioButton( hDlg, IDC_OCS, IDC_AGA, IDC_OCS+1 );
+       break;
+    case CSMASK_ECS_DENISE:
+       CheckRadioButton( hDlg, IDC_OCS, IDC_AGA, IDC_OCS+2 );
+       break;
+    case CSMASK_ECS_AGNUS | CSMASK_ECS_DENISE:
+       CheckRadioButton( hDlg, IDC_OCS, IDC_AGA, IDC_OCS+3 );
+       break;
+    case CSMASK_AGA:
+    case CSMASK_ECS_AGNUS | CSMASK_ECS_DENISE | CSMASK_AGA:
+       CheckRadioButton( hDlg, IDC_OCS, IDC_AGA, IDC_OCS+4 );
+       break;
+    }
+    CheckDlgButton (hDlg, IDC_NTSC, workprefs.ntscmode);
+    CheckDlgButton (hDlg, IDC_FASTCOPPER, workprefs.fast_copper);
+    CheckDlgButton (hDlg, IDC_BLITIMM, workprefs.immediate_blits);
+    CheckRadioButton (hDlg, IDC_COLLISION0, IDC_COLLISION3, IDC_COLLISION0 + workprefs.collision_level);
+    CheckDlgButton (hDlg, IDC_CYCLEEXACT, workprefs.cpu_cycle_exact);
+    switch (workprefs.produce_sound) {
+     case 0: which_button = IDC_CS_SOUND0; break;
+     case 1: case 2: which_button = IDC_CS_SOUND1; break;
+     default: which_button = IDC_CS_SOUND2; break;
+    }
+    CheckRadioButton( hDlg, IDC_CS_SOUND0, IDC_CS_SOUND2, which_button );
+}
+
+static void values_from_chipsetdlg (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    BOOL success = FALSE;
+    int n, snd;
+
+    workprefs.fast_copper = IsDlgButtonChecked (hDlg, IDC_FASTCOPPER);
+    workprefs.immediate_blits = IsDlgButtonChecked (hDlg, IDC_BLITIMM);
+    n = IsDlgButtonChecked (hDlg, IDC_CYCLEEXACT) ? 1 : 0;
+    if (workprefs.cpu_cycle_exact != n) {
+       workprefs.cpu_cycle_exact = workprefs.blitter_cycle_exact = n;
+       if (n) {
+           if (workprefs.cpu_level == 0)
+               workprefs.cpu_compatible = 1;
+           workprefs.immediate_blits = 0;
+           workprefs.fast_copper = 0;
+       }
+    }
+    workprefs.collision_level = IsDlgButtonChecked (hDlg, IDC_COLLISION0) ? 0
+                                : IsDlgButtonChecked (hDlg, IDC_COLLISION1) ? 1
+                                : IsDlgButtonChecked (hDlg, IDC_COLLISION2) ? 2 : 3;
+    workprefs.chipset_mask = IsDlgButtonChecked( hDlg, IDC_OCS ) ? 0
+                             : IsDlgButtonChecked( hDlg, IDC_ECS_AGNUS ) ? CSMASK_ECS_AGNUS
+                             : IsDlgButtonChecked( hDlg, IDC_ECS_DENISE ) ? CSMASK_ECS_DENISE
+                             : IsDlgButtonChecked( hDlg, IDC_ECS ) ? CSMASK_ECS_AGNUS | CSMASK_ECS_DENISE
+                             : CSMASK_AGA | CSMASK_ECS_AGNUS | CSMASK_ECS_DENISE;
+    n = IsDlgButtonChecked (hDlg, IDC_NTSC) ? 1 : 0;
+    if (workprefs.ntscmode != n) {
+       workprefs.ntscmode = n;
+#ifdef AVIOUTPUT
+       avioutput_fps = n ? VBLANK_HZ_NTSC : VBLANK_HZ_PAL;
+#endif
+    }
+    snd = IsDlgButtonChecked (hDlg, IDC_CS_SOUND0) ? 0
+       : IsDlgButtonChecked (hDlg, IDC_CS_SOUND1) ? 2 : 3;
+    if (snd == 0 || snd == 3) {
+       workprefs.produce_sound = snd;
+    } else if (snd == 2) {
+       if (workprefs.produce_sound == 0)
+           workprefs.produce_sound = 2;
+       else if (workprefs.produce_sound >= 2)
+           workprefs.produce_sound = 2;
+    }
+}
+
+static BOOL CALLBACK ChipsetDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    static int recursive = 0;
+    RGBFTYPE colortype      = RGBFB_NONE;
+    DWORD dwType            = REG_DWORD;
+    DWORD dwDisplayInfoSize = sizeof( colortype );
+
+    switch (msg) {
+    case WM_INITDIALOG:
+       pages[CHIPSET_ID] = hDlg;
+       currentpage = CHIPSET_ID;
+#ifndef AGA
+        EnableWindow (GetDlgItem (hDlg, IDC_AGA), FALSE);
+#endif
+
+    case WM_USER:
+       recursive++;
+       values_to_chipsetdlg (hDlg);
+       enable_for_chipsetdlg (hDlg);
+       recursive--;
+        break;
+
+    case WM_HSCROLL:
+    case WM_COMMAND:
+       if (recursive > 0)
+           break;
+       recursive++;
+       values_from_chipsetdlg (hDlg, msg, wParam, lParam);
+       enable_for_chipsetdlg( hDlg );
+       recursive--;
+       break;
+    }
+    return FALSE;
+}
+
+static void enable_for_memorydlg (HWND hDlg)
+{
+    int z3 = ! workprefs.address_space_24;
+    int fast = workprefs.chipmem_size <= 0x200000;
+
+#ifndef AUTOCONFIG
+    z3 = FALSE;
+    fast = FALSE;
+#endif
+    EnableWindow (GetDlgItem (hDlg, IDC_Z3TEXT), z3);
+    EnableWindow (GetDlgItem (hDlg, IDC_Z3FASTRAM), z3);
+    EnableWindow (GetDlgItem (hDlg, IDC_Z3FASTMEM), z3);
+    EnableWindow (GetDlgItem (hDlg, IDC_FASTMEM), fast);
+    EnableWindow (GetDlgItem (hDlg, IDC_FASTRAM), fast);
+    EnableWindow (GetDlgItem (hDlg, IDC_FASTTEXT), fast);
+    EnableWindow (GetDlgItem (hDlg, IDC_GFXCARDTEXT), z3);
+    EnableWindow (GetDlgItem (hDlg, IDC_P96RAM), z3);
+    EnableWindow (GetDlgItem (hDlg, IDC_P96MEM), z3);
+}
+
+static void values_to_memorydlg (HWND hDlg)
+{
+    uae_u32 mem_size = 0;
+
+    switch (workprefs.chipmem_size) {
+     case 0x00040000: mem_size = 0; break;
+     case 0x00080000: mem_size = 1; break;
+     case 0x00100000: mem_size = 2; break;
+     case 0x00200000: mem_size = 3; break;
+     case 0x00400000: mem_size = 4; break;
+     case 0x00800000: mem_size = 5; break;
+    }
+    SendDlgItemMessage (hDlg, IDC_CHIPMEM, TBM_SETPOS, TRUE, mem_size);
+    SetDlgItemText (hDlg, IDC_CHIPRAM, memsize_names[msi_chip[mem_size]]);
+
+    mem_size = 0;
+    switch (workprefs.fastmem_size) {
+     case 0x00000000: mem_size = 0; break;
+     case 0x00100000: mem_size = 1; break;
+     case 0x00200000: mem_size = 2; break;
+     case 0x00400000: mem_size = 3; break;
+     case 0x00800000: mem_size = 4; break;
+     case 0x01000000: mem_size = 5; break;
+    }
+    SendDlgItemMessage (hDlg, IDC_FASTMEM, TBM_SETPOS, TRUE, mem_size);
+    SetDlgItemText (hDlg, IDC_FASTRAM, memsize_names[msi_fast[mem_size]]);
+
+    mem_size = 0;
+    switch (workprefs.bogomem_size) {
+     case 0x00000000: mem_size = 0; break;
+     case 0x00080000: mem_size = 1; break;
+     case 0x00100000: mem_size = 2; break;
+     case 0x00180000: mem_size = 3; break;
+     case 0x00200000: mem_size = 4; break;
+    }
+    SendDlgItemMessage (hDlg, IDC_SLOWMEM, TBM_SETPOS, TRUE, mem_size);
+    SetDlgItemText (hDlg, IDC_SLOWRAM, memsize_names[msi_bogo[mem_size]]);
+
+    mem_size = 0;
+    switch (workprefs.z3fastmem_size) {
+     case 0x00000000: mem_size = 0; break; /*   0-megs */
+     case 0x00100000: mem_size = 1; break; /*   1-megs */
+     case 0x00200000: mem_size = 2; break; /*   2-megs */
+     case 0x00400000: mem_size = 3; break; /*   4-megs */
+     case 0x00800000: mem_size = 4; break; /*   8-megs */
+     case 0x01000000: mem_size = 5; break; /*  16-megs */
+     case 0x02000000: mem_size = 6; break; /*  32-megs */
+     case 0x04000000: mem_size = 7; break; /*  64-megs */
+     case 0x08000000: mem_size = 8; break; /* 128-megs */
+     case 0x10000000: mem_size = 9; break; /* 256-megs */
+     case 0x20000000: mem_size = 10; break; /* 512-megs */
+     case 0x40000000: mem_size = 11; break; /* 1 GB */
+
+    }
+    SendDlgItemMessage (hDlg, IDC_Z3FASTMEM, TBM_SETPOS, TRUE, mem_size);
+    SetDlgItemText (hDlg, IDC_Z3FASTRAM, memsize_names[msi_z3fast[mem_size]]);
+
+    mem_size = 0;
+    switch (workprefs.gfxmem_size) {
+     case 0x00000000: mem_size = 0; break;
+     case 0x00100000: mem_size = 1; break;
+     case 0x00200000: mem_size = 2; break;
+     case 0x00400000: mem_size = 3; break;
+     case 0x00800000: mem_size = 4; break;
+     case 0x01000000: mem_size = 5; break;
+     case 0x02000000: mem_size = 6; break;
+    }
+    SendDlgItemMessage (hDlg, IDC_P96MEM, TBM_SETPOS, TRUE, mem_size);
+    SetDlgItemText (hDlg, IDC_P96RAM, memsize_names[msi_gfx[mem_size]]);
+}
+
+static void fix_values_memorydlg (void)
+{
+    if (workprefs.chipmem_size > 0x200000)
+       workprefs.fastmem_size = 0;
+    if (workprefs.chipmem_size > 0x80000)
+       workprefs.chipset_mask |= CSMASK_ECS_AGNUS;
+}
+
+static BOOL CALLBACK MemoryDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    static int recursive = 0;
+    unsigned int max_z3_mem = MAX_Z3_MEM;
+    MEMORYSTATUS memstats;
+
+    switch (msg)
+    {
+    case WM_INITDIALOG:
+       pages[MEMORY_ID] = hDlg;
+       currentpage = MEMORY_ID;
+
+       memstats.dwLength = sizeof( memstats );
+       GlobalMemoryStatus( &memstats );
+       while( ( memstats.dwAvailPageFile + memstats.dwAvailPhys - 32000000) < (DWORD)( 1 << (max_z3_mem + 19) ) )
+           max_z3_mem--;
+
+       SendDlgItemMessage (hDlg, IDC_CHIPMEM, TBM_SETRANGE, TRUE, MAKELONG (MIN_CHIP_MEM, MAX_CHIP_MEM));
+       SendDlgItemMessage (hDlg, IDC_FASTMEM, TBM_SETRANGE, TRUE, MAKELONG (MIN_FAST_MEM, MAX_FAST_MEM));
+       SendDlgItemMessage (hDlg, IDC_SLOWMEM, TBM_SETRANGE, TRUE, MAKELONG (MIN_SLOW_MEM, MAX_SLOW_MEM));
+       SendDlgItemMessage (hDlg, IDC_Z3FASTMEM, TBM_SETRANGE, TRUE, MAKELONG (MIN_Z3_MEM, max_z3_mem));
+       SendDlgItemMessage (hDlg, IDC_P96MEM, TBM_SETRANGE, TRUE, MAKELONG (MIN_P96_MEM, MAX_P96_MEM));
+
+    case WM_USER:
+       recursive++;
+       fix_values_memorydlg ();
+       values_to_memorydlg (hDlg);
+       enable_for_memorydlg (hDlg);
+       recursive--;
+       break;
+
+    case WM_HSCROLL:
+       workprefs.chipmem_size = memsizes[msi_chip[SendMessage (GetDlgItem (hDlg, IDC_CHIPMEM), TBM_GETPOS, 0, 0)]];
+       workprefs.bogomem_size = memsizes[msi_bogo[SendMessage (GetDlgItem (hDlg, IDC_SLOWMEM), TBM_GETPOS, 0, 0)]];
+       workprefs.fastmem_size = memsizes[msi_fast[SendMessage (GetDlgItem (hDlg, IDC_FASTMEM), TBM_GETPOS, 0, 0)]];
+       workprefs.z3fastmem_size = memsizes[msi_z3fast[SendMessage (GetDlgItem (hDlg, IDC_Z3FASTMEM), TBM_GETPOS, 0, 0)]];
+       workprefs.gfxmem_size = memsizes[msi_gfx[SendMessage (GetDlgItem (hDlg, IDC_P96MEM), TBM_GETPOS, 0, 0)]];
+       fix_values_memorydlg ();
+       values_to_memorydlg (hDlg);
+       enable_for_memorydlg (hDlg);
+        break;
+
+    case WM_COMMAND:
+       if (recursive > 0)
+           break;
+       recursive++;
+       values_to_memorydlg (hDlg);
+       recursive--;
+       break;
+
+    }
+    return FALSE;
+}
+
+static void values_to_kickstartdlg (HWND hDlg)
+{
+    SetDlgItemText( hDlg, IDC_ROMFILE, workprefs.romfile );
+    SetDlgItemText( hDlg, IDC_ROMFILE2, workprefs.romextfile );
+    SetDlgItemText( hDlg, IDC_KEYFILE, workprefs.keyfile );
+    SetDlgItemText( hDlg, IDC_FLASHFILE, workprefs.flashfile );
+    SetDlgItemText( hDlg, IDC_CARTFILE, workprefs.cartfile );
+    CheckDlgButton( hDlg, IDC_KICKSHIFTER, workprefs.kickshifter );
+    CheckDlgButton( hDlg, IDC_MAPROM, workprefs.maprom );
+}
+
+static BOOL CALLBACK KickstartDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    switch( msg ) 
+    {
+    case WM_INITDIALOG:
+       pages[KICKSTART_ID] = hDlg;
+       currentpage = KICKSTART_ID;
+#if !defined(AUTOCONFIG)
+        EnableWindow( GetDlgItem( hDlg, IDC_MAPROM), FALSE );
+#endif
+#if !defined (CDTV) && !defined (CD32)
+        EnableWindow( GetDlgItem( hDlg, IDC_FLASHFILE), FALSE );
+        EnableWindow( GetDlgItem( hDlg, IDC_ROMFILE2), FALSE );
+#endif
+#if !defined (ACTION_REPLAY)
+        EnableWindow( GetDlgItem( hDlg, IDC_CARTFILE), FALSE );
+#endif
+#if defined (UAE_MINI)
+        EnableWindow( GetDlgItem( hDlg, IDC_KICKSHIFTER), FALSE );
+        EnableWindow( GetDlgItem( hDlg, IDC_ROMCHOOSER2), FALSE );
+        EnableWindow( GetDlgItem( hDlg, IDC_CARTCHOOSER), FALSE );
+        EnableWindow( GetDlgItem( hDlg, IDC_FLASHCHOOSER), FALSE );
+#endif 
+    case WM_USER:
+       values_to_kickstartdlg (hDlg);
+       return TRUE;
+
+    case WM_COMMAND:
+       switch( wParam ) 
+       {
+       case IDC_KICKCHOOSER:
+           DiskSelection( hDlg, IDC_ROMFILE, 6, &workprefs, 0);
+           break;
+
+       case IDC_ROMCHOOSER2:
+           DiskSelection( hDlg, IDC_ROMFILE2, 6, &workprefs, 0);
+           break;
+                   
+       case IDC_KEYCHOOSER:
+           DiskSelection( hDlg, IDC_KEYFILE, 7, &workprefs, 0);
+           break;
+                
+       case IDC_FLASHCHOOSER:
+           DiskSelection( hDlg, IDC_FLASHFILE, 11, &workprefs, 0);
+           break;
+
+       case IDC_CARTCHOOSER:
+           DiskSelection( hDlg, IDC_CARTFILE, 6, &workprefs, 0);
+           break;
+
+       case IDC_KICKSHIFTER:
+           workprefs.kickshifter = IsDlgButtonChecked( hDlg, IDC_KICKSHIFTER );
+           break;
+
+       case IDC_MAPROM:
+           workprefs.maprom = IsDlgButtonChecked( hDlg, IDC_MAPROM ) ? 0xe00000 : 0;
+           break;
+
+       default:
+           if( SendMessage( GetDlgItem( hDlg, IDC_ROMFILE ), EM_GETMODIFY, 0, 0 ) )
+           {
+               GetDlgItemText( hDlg, IDC_ROMFILE, workprefs.romfile, CFG_ROM_LENGTH);
+               SendMessage( GetDlgItem( hDlg, IDC_ROMFILE ), EM_SETMODIFY, 0, 0 );
+           }
+           if( SendMessage( GetDlgItem( hDlg, IDC_ROMFILE2 ), EM_GETMODIFY, 0, 0 ) )
+           {
+               GetDlgItemText( hDlg, IDC_ROMFILE2, workprefs.romextfile, CFG_ROM_LENGTH);
+               SendMessage( GetDlgItem( hDlg, IDC_ROMFILE2 ), EM_SETMODIFY, 0, 0 );
+           }
+           if( SendMessage( GetDlgItem( hDlg, IDC_KEYFILE ), EM_GETMODIFY, 0, 0 ) )
+           {
+               GetDlgItemText( hDlg, IDC_KEYFILE, workprefs.keyfile, CFG_KEY_LENGTH);
+               SendMessage( GetDlgItem( hDlg, IDC_KEYFILE ), EM_SETMODIFY, 0, 0 );
+           }
+           if( SendMessage( GetDlgItem( hDlg, IDC_FLASHFILE ), EM_GETMODIFY, 0, 0 ) )
+           {
+               GetDlgItemText( hDlg, IDC_FLASHFILE, workprefs.flashfile, CFG_ROM_LENGTH);
+               SendMessage( GetDlgItem( hDlg, IDC_FLASHFILE ), EM_SETMODIFY, 0, 0 );
+           }
+           if( SendMessage( GetDlgItem( hDlg, IDC_CARTFILE ), EM_GETMODIFY, 0, 0 ) )
+           {
+               GetDlgItemText( hDlg, IDC_CARTFILE, workprefs.cartfile, CFG_ROM_LENGTH);
+               SendMessage( GetDlgItem( hDlg, IDC_CARTFILE ), EM_SETMODIFY, 0, 0 );
+           }
+           break;
+       }
+       break;
+    }
+    return FALSE;
+}
+
+static void enable_for_miscdlg (HWND hDlg)
+{
+    if( !full_property_sheet )
+    {
+        EnableWindow( GetDlgItem( hDlg, IDC_JULIAN), TRUE);
+        EnableWindow( GetDlgItem( hDlg, IDC_CTRLF11), TRUE);
+        EnableWindow( GetDlgItem( hDlg, IDC_SOCKETS), FALSE);
+        EnableWindow( GetDlgItem( hDlg, IDC_SHOWGUI ), FALSE );
+        EnableWindow( GetDlgItem( hDlg, IDC_CREATELOGFILE ), FALSE );
+        EnableWindow( GetDlgItem( hDlg, IDC_ILLEGAL ), FALSE );
+        EnableWindow( GetDlgItem( hDlg, IDC_NOSPEED ), TRUE );
+        EnableWindow( GetDlgItem( hDlg, IDC_NOSPEEDPAUSE ), TRUE );
+        EnableWindow( GetDlgItem( hDlg, IDC_NOSOUND ), TRUE );
+       EnableWindow( GetDlgItem( hDlg, IDC_NOOVERLAY ), FALSE );
+        EnableWindow( GetDlgItem( hDlg, IDC_DOSAVESTATE ), TRUE );
+        EnableWindow( GetDlgItem( hDlg, IDC_ASPI ), FALSE );
+        EnableWindow( GetDlgItem( hDlg, IDC_SCSIDEVICE ), FALSE );
+        EnableWindow( GetDlgItem( hDlg, IDC_NOUAEFSDB ), FALSE );
+        EnableWindow( GetDlgItem( hDlg, IDC_CLOCKSYNC ), FALSE );
+        EnableWindow( GetDlgItem( hDlg, IDC_STATE_CAPTURE ), FALSE );
+        EnableWindow( GetDlgItem( hDlg, IDC_STATE_RATE ), FALSE );
+        EnableWindow( GetDlgItem( hDlg, IDC_STATE_BUFFERSIZE ), FALSE );
+    }
+    else
+    {
+#if !defined (FILESYS)
+        EnableWindow( GetDlgItem( hDlg, IDC_CLOCKSYNC ), FALSE );
+#endif
+#if !defined (BSDSOCKET)
+        EnableWindow( GetDlgItem( hDlg, IDC_SOCKETS), FALSE);
+#endif
+#if !defined (SCSIEMU)
+        EnableWindow( GetDlgItem( hDlg, IDC_SCSIDEVICE), FALSE);
+        EnableWindow( GetDlgItem( hDlg, IDC_ASPI ), FALSE );
+#endif
+        if( workprefs.win32_logfile )
+        {
+            EnableWindow( GetDlgItem( hDlg, IDC_ILLEGAL ), TRUE );
+        }
+        else
+        {
+            EnableWindow( GetDlgItem( hDlg, IDC_ILLEGAL ), FALSE );
+        }
+        EnableWindow( GetDlgItem( hDlg, IDC_DOSAVESTATE ), FALSE );
+       EnableWindow( GetDlgItem( hDlg, IDC_STATE_RATE ), workprefs.statecapture ? TRUE : FALSE );
+       EnableWindow( GetDlgItem( hDlg, IDC_STATE_BUFFERSIZE ), workprefs.statecapture ? TRUE : FALSE );
+
+    }
+}
+
+static void misc_kbled (HWND hDlg, int v, int nv)
+{
+    char *defname = v == IDC_KBLED1 ? "(NumLock)" : v == IDC_KBLED2 ? "(CapsLock)" : "(ScrollLock)";
+    SendDlgItemMessage (hDlg, v, CB_RESETCONTENT, 0, 0L);
+    SendDlgItemMessage (hDlg, v, CB_ADDSTRING, 0, (LPARAM)defname);
+    SendDlgItemMessage (hDlg, v, CB_ADDSTRING, 0, (LPARAM)"POWER");
+    SendDlgItemMessage (hDlg, v, CB_ADDSTRING, 0, (LPARAM)"DF0");
+    SendDlgItemMessage (hDlg, v, CB_ADDSTRING, 0, (LPARAM)"DF1");
+    SendDlgItemMessage (hDlg, v, CB_ADDSTRING, 0, (LPARAM)"DF2");
+    SendDlgItemMessage (hDlg, v, CB_ADDSTRING, 0, (LPARAM)"DF3");
+    SendDlgItemMessage (hDlg, v, CB_ADDSTRING, 0, (LPARAM)"HD");
+    SendDlgItemMessage (hDlg, v, CB_ADDSTRING, 0, (LPARAM)"CD");
+    SendDlgItemMessage (hDlg, v, CB_SETCURSEL, nv, 0);
+}
+
+static void misc_getkbled (HWND hDlg, int v, int n)
+{
+    int nv = SendDlgItemMessage(hDlg, v, CB_GETCURSEL, 0, 0L);
+    if (nv != CB_ERR) {
+       workprefs.keyboard_leds[n] = nv;
+       misc_kbled (hDlg, v, nv);
+    }
+    workprefs.keyboard_leds_in_use = workprefs.keyboard_leds[0] | workprefs.keyboard_leds[1] | workprefs.keyboard_leds[2];
+}
+
+static void misc_getpri (HWND hDlg, int v, int *n)
+{
+    int nv = SendDlgItemMessage(hDlg, v, CB_GETCURSEL, 0, 0L);
+    if (nv != CB_ERR)
+       *n = nv;
+}
+
+static void misc_addpri (HWND hDlg, int v, int pri)
+{
+    int i;
+    SendDlgItemMessage (hDlg, v, CB_RESETCONTENT, 0, 0L);
+    i = 0;
+    while (priorities[i].name) {
+       SendDlgItemMessage (hDlg, v, CB_ADDSTRING, 0, (LPARAM)priorities[i].name);
+       i++;
+    }
+    SendDlgItemMessage (hDlg, v, CB_SETCURSEL, pri, 0);
+}
+
+static void values_to_miscdlg (HWND hDlg)
+{
+    char txt[100];
+
+    CheckDlgButton( hDlg, IDC_SOCKETS, workprefs.socket_emu );
+    CheckDlgButton( hDlg, IDC_ILLEGAL, workprefs.illegal_mem);
+    CheckDlgButton( hDlg, IDC_SHOWGUI, workprefs.start_gui);
+    CheckDlgButton( hDlg, IDC_JULIAN, workprefs.win32_middle_mouse );
+    CheckDlgButton( hDlg, IDC_CREATELOGFILE, workprefs.win32_logfile );
+    CheckDlgButton( hDlg, IDC_INACTIVE_PAUSE, workprefs.win32_inactive_pause );
+    CheckDlgButton( hDlg, IDC_INACTIVE_NOSOUND, workprefs.win32_inactive_nosound );
+    CheckDlgButton( hDlg, IDC_MINIMIZED_PAUSE, workprefs.win32_iconified_pause );
+    CheckDlgButton( hDlg, IDC_MINIMIZED_NOSOUND, workprefs.win32_iconified_nosound );
+    CheckDlgButton( hDlg, IDC_CTRLF11, workprefs.win32_ctrl_F11_is_quit );
+    CheckDlgButton( hDlg, IDC_NOOVERLAY, workprefs.win32_no_overlay );
+    CheckDlgButton( hDlg, IDC_SHOWLEDS, workprefs.leds_on_screen );
+    CheckDlgButton( hDlg, IDC_SCSIDEVICE, workprefs.scsi );
+    CheckDlgButton( hDlg, IDC_NOUAEFSDB, workprefs.filesys_no_uaefsdb );
+    CheckDlgButton( hDlg, IDC_ASPI, workprefs.win32_aspi );
+    CheckDlgButton( hDlg, IDC_STATE_CAPTURE, workprefs.tod_hack );
+
+    if (!os_winnt) {
+       EnableWindow( GetDlgItem( hDlg, IDC_ASPI), FALSE );
+       CheckDlgButton( hDlg, IDC_ASPI, BST_CHECKED );
+    }
+
+    misc_kbled (hDlg, IDC_KBLED1, workprefs.keyboard_leds[0]);
+    misc_kbled (hDlg, IDC_KBLED2, workprefs.keyboard_leds[1]);
+    misc_kbled (hDlg, IDC_KBLED3, workprefs.keyboard_leds[2]);
+
+    misc_addpri (hDlg, IDC_ACTIVE_PRIORITY, workprefs.win32_active_priority);
+    misc_addpri (hDlg, IDC_INACTIVE_PRIORITY, workprefs.win32_inactive_priority);
+    misc_addpri (hDlg, IDC_MINIMIZED_PRIORITY, workprefs.win32_iconified_priority);
+
+    CheckDlgButton (hDlg, IDC_STATE_CAPTURE, workprefs.statecapture);
+
+    SendDlgItemMessage (hDlg, IDC_STATE_RATE, CB_RESETCONTENT, 0, 0);
+    SendDlgItemMessage (hDlg, IDC_STATE_RATE, CB_ADDSTRING, 0, (LPARAM)"1");
+    SendDlgItemMessage (hDlg, IDC_STATE_RATE, CB_ADDSTRING, 0, (LPARAM)"5");
+    SendDlgItemMessage (hDlg, IDC_STATE_RATE, CB_ADDSTRING, 0, (LPARAM)"10");
+    SendDlgItemMessage (hDlg, IDC_STATE_RATE, CB_ADDSTRING, 0, (LPARAM)"20");
+    SendDlgItemMessage (hDlg, IDC_STATE_RATE, CB_ADDSTRING, 0, (LPARAM)"30");
+    sprintf (txt, "%d", workprefs.statecapturerate / 50);
+    SendDlgItemMessage( hDlg, IDC_STATE_RATE, WM_SETTEXT, 0, (LPARAM)txt); 
+
+    SendDlgItemMessage (hDlg, IDC_STATE_BUFFERSIZE, CB_RESETCONTENT, 0, 0);
+    SendDlgItemMessage (hDlg, IDC_STATE_BUFFERSIZE, CB_ADDSTRING, 0, (LPARAM)"5");
+    SendDlgItemMessage (hDlg, IDC_STATE_BUFFERSIZE, CB_ADDSTRING, 0, (LPARAM)"10");
+    SendDlgItemMessage (hDlg, IDC_STATE_BUFFERSIZE, CB_ADDSTRING, 0, (LPARAM)"20");
+    SendDlgItemMessage (hDlg, IDC_STATE_BUFFERSIZE, CB_ADDSTRING, 0, (LPARAM)"50");
+    SendDlgItemMessage (hDlg, IDC_STATE_BUFFERSIZE, CB_ADDSTRING, 0, (LPARAM)"100");
+    sprintf (txt, "%d", workprefs.statecapturebuffersize / (1024 * 1024));
+    SendDlgItemMessage( hDlg, IDC_STATE_BUFFERSIZE, WM_SETTEXT, 0, (LPARAM)txt); 
+}
+
+static BOOL MiscDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    char txt[100];
+
+    switch (msg) 
+    {
+
+    case WM_USER:
+       values_to_miscdlg (hDlg);
+       enable_for_miscdlg (hDlg);
+       return TRUE;
+
+    case WM_COMMAND:
+
+       if (currentpage == MISC1_ID) {
+           misc_getkbled (hDlg, IDC_KBLED1, 0);
+           misc_getkbled (hDlg, IDC_KBLED2, 1);
+           misc_getkbled (hDlg, IDC_KBLED3, 2);
+       } else {
+           misc_getpri (hDlg, IDC_ACTIVE_PRIORITY, &workprefs.win32_active_priority);
+           misc_getpri (hDlg, IDC_INACTIVE_PRIORITY, &workprefs.win32_inactive_priority);
+           misc_getpri (hDlg, IDC_MINIMIZED_PRIORITY, &workprefs.win32_iconified_priority);
+           SendDlgItemMessage (hDlg, IDC_STATE_RATE, WM_GETTEXT, (WPARAM)sizeof (txt), (LPARAM)txt);
+           workprefs.statecapturerate = atol (txt) * 50;
+           SendDlgItemMessage (hDlg, IDC_STATE_BUFFERSIZE, WM_GETTEXT, (WPARAM)sizeof (txt), (LPARAM)txt);
+           workprefs.statecapturebuffersize = atol (txt) * 1024 * 1024;
+       }
+
+       switch( wParam )
+       {
+       case IDC_DOSAVESTATE:
+           if (DiskSelection( hDlg, wParam, 9, &workprefs, 0)) 
+               save_state (savestate_fname, "Description!");
+           break;
+       case IDC_DOLOADSTATE:
+           if (DiskSelection( hDlg, wParam, 10, &workprefs, 0))
+               savestate_state = STATE_DORESTORE;
+           break;
+       case IDC_STATE_CAPTURE:
+           workprefs.statecapture = IsDlgButtonChecked (hDlg, IDC_STATE_CAPTURE);
+           enable_for_miscdlg (hDlg);
+           break;
+       case IDC_SOCKETS:
+           workprefs.socket_emu = IsDlgButtonChecked (hDlg, IDC_SOCKETS);
+           break;
+       case IDC_ILLEGAL:
+           workprefs.illegal_mem = IsDlgButtonChecked (hDlg, IDC_ILLEGAL);
+           break;
+       case IDC_JULIAN:
+           workprefs.win32_middle_mouse = IsDlgButtonChecked( hDlg, IDC_JULIAN );
+           break;
+       case IDC_NOOVERLAY:
+           workprefs.win32_no_overlay = IsDlgButtonChecked( hDlg, IDC_NOOVERLAY );
+           break;
+       case IDC_SHOWLEDS:
+           workprefs.leds_on_screen = IsDlgButtonChecked( hDlg, IDC_SHOWLEDS );
+           break;
+       case IDC_SHOWGUI:
+           workprefs.start_gui = IsDlgButtonChecked (hDlg, IDC_SHOWGUI);
+           break;
+       case IDC_CREATELOGFILE:
+           workprefs.win32_logfile = IsDlgButtonChecked( hDlg, IDC_CREATELOGFILE );
+           enable_for_miscdlg( hDlg );
+           break;
+       case IDC_INACTIVE_PAUSE:
+           workprefs.win32_inactive_pause = IsDlgButtonChecked( hDlg, IDC_INACTIVE_PAUSE );
+           break;
+       case IDC_INACTIVE_NOSOUND:
+           workprefs.win32_inactive_nosound = IsDlgButtonChecked( hDlg, IDC_INACTIVE_NOSOUND );
+           break;
+       case IDC_MINIMIZED_PAUSE:
+           workprefs.win32_iconified_pause = IsDlgButtonChecked( hDlg, IDC_MINIMIZED_PAUSE );
+           break;
+       case IDC_MINIMIZED_NOSOUND:
+           workprefs.win32_iconified_nosound = IsDlgButtonChecked( hDlg, IDC_MINIMIZED_NOSOUND );
+           break;
+       case IDC_CTRLF11:
+           workprefs.win32_ctrl_F11_is_quit = IsDlgButtonChecked( hDlg, IDC_CTRLF11 );
+           break;
+       case IDC_SCSIDEVICE:
+           workprefs.scsi = IsDlgButtonChecked( hDlg, IDC_SCSIDEVICE );
+           break;
+       case IDC_NOUAEFSDB:
+           workprefs.filesys_no_uaefsdb = IsDlgButtonChecked( hDlg, IDC_NOUAEFSDB );
+           break;
+       case IDC_ASPI:
+           workprefs.win32_aspi = IsDlgButtonChecked( hDlg, IDC_ASPI );
+           break;
+       }
+       return TRUE;
+    }
+    return FALSE;
+}
+
+static BOOL CALLBACK MiscDlgProc1 (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    if (msg == WM_INITDIALOG) {
+       pages[MISC1_ID] = hDlg;
+       currentpage = MISC1_ID;
+       values_to_miscdlg (hDlg);
+       enable_for_miscdlg (hDlg);
+       return TRUE;
+    }
+    return MiscDlgProc (hDlg, msg, wParam, lParam);
+}
+
+static BOOL CALLBACK MiscDlgProc2 (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    if (msg == WM_INITDIALOG) {
+       pages[MISC2_ID] = hDlg;
+       currentpage = MISC2_ID;
+       values_to_miscdlg (hDlg);
+       enable_for_miscdlg (hDlg);
+       return TRUE;
+    }
+    return MiscDlgProc (hDlg, msg, wParam, lParam);
+}
+
+static int cpu_ids[]   = { IDC_CPU0, IDC_CPU0, IDC_CPU1, IDC_CPU1, IDC_CPU2, IDC_CPU4, IDC_CPU3, IDC_CPU5, IDC_CPU6, IDC_CPU6 };
+static int trust_ids[] = { IDC_TRUST0, IDC_TRUST1, IDC_TRUST1, IDC_TRUST2 };
+
+static void enable_for_cpudlg (HWND hDlg)
+{
+    BOOL enable = FALSE, enable2 = FALSE;
+    BOOL cpu_based_enable = FALSE;
+
+    EnableWindow (GetDlgItem (hDlg, IDC_COMPATIBLE), !workprefs.cpu_cycle_exact && !workprefs.cachesize);
+    /* These four items only get enabled when adjustable CPU style is enabled */
+    EnableWindow (GetDlgItem (hDlg, IDC_SPEED), workprefs.m68k_speed > 0);
+    EnableWindow (GetDlgItem (hDlg, IDC_CS_CPU_TEXT), workprefs.m68k_speed > 0);
+    EnableWindow (GetDlgItem (hDlg, IDC_CS_CHIPSET_TEXT), workprefs.m68k_speed > 0);
+    EnableWindow (GetDlgItem (hDlg, IDC_CPUTEXT), workprefs.m68k_speed > 0 );
+    EnableWindow (GetDlgItem (hDlg, IDC_CPUIDLE), workprefs.m68k_speed != 0 ? TRUE : FALSE);
+#if !defined(CPUEMU_0) || defined(CPUEMU_68000_ONLY)
+    EnableWindow (GetDlgItem (hDlg, IDC_CPU1), FALSE);
+    EnableWindow (GetDlgItem (hDlg, IDC_CPU2), FALSE);
+    EnableWindow (GetDlgItem (hDlg, IDC_CPU3), FALSE);
+    EnableWindow (GetDlgItem (hDlg, IDC_CPU4), FALSE);
+    EnableWindow (GetDlgItem (hDlg, IDC_CPU5), FALSE);
+    EnableWindow (GetDlgItem (hDlg, IDC_CPU6), FALSE);
+#endif
+
+    cpu_based_enable = ( workprefs.cpu_level >= 2 ) &&
+                      ( workprefs.address_space_24 == 0 );
+
+    enable = cpu_based_enable && ( workprefs.cachesize );
+#ifndef JIT
+    enable = FALSE;
+#endif
+    enable2 = enable && workprefs.compforcesettings;
+
+    EnableWindow( GetDlgItem( hDlg, IDC_TRUST0 ), enable2 );
+    EnableWindow( GetDlgItem( hDlg, IDC_TRUST1 ), enable2 );
+    EnableWindow( GetDlgItem( hDlg, IDC_TRUST2 ), enable2 );
+    EnableWindow( GetDlgItem( hDlg, IDC_HARDFLUSH ), enable2 );
+    EnableWindow( GetDlgItem( hDlg, IDC_CONSTJUMP ), enable2 );
+    EnableWindow( GetDlgItem( hDlg, IDC_JITFPU ), enable2 );
+    EnableWindow( GetDlgItem( hDlg, IDC_NOFLAGS ), enable2 );
+    EnableWindow( GetDlgItem( hDlg, IDC_CS_CACHE_TEXT ), cpu_based_enable );
+    EnableWindow( GetDlgItem( hDlg, IDC_CACHE ), cpu_based_enable );
+    EnableWindow( GetDlgItem( hDlg, IDC_CACHETEXT ), cpu_based_enable );
+    EnableWindow( GetDlgItem( hDlg, IDC_FORCE ), enable );
+
+#ifdef JIT
+    if( enable )
+    {
+       if(!canbang)
+       {
+           workprefs.compforcesettings = TRUE;
+           workprefs.comptrustbyte = 1;
+           workprefs.comptrustword = 1;
+           workprefs.comptrustlong = 1;
+           workprefs.comptrustnaddr= 1;
+       }
+    }
+    else
+    {
+       workprefs.cachesize = 0; // Disable JIT
+    }
+#endif
+}
+
+static void values_to_cpudlg (HWND hDlg)
+{
+    char cache[ 8 ] = "";
+    BOOL enable = FALSE;
+    BOOL cpu_based_enable = FALSE;
+
+    SendDlgItemMessage (hDlg, IDC_SPEED, TBM_SETPOS, TRUE, workprefs.m68k_speed <= 0 ? 1 : workprefs.m68k_speed / CYCLE_UNIT );
+    SetDlgItemInt( hDlg, IDC_CPUTEXT, workprefs.m68k_speed <= 0 ? 1 : workprefs.m68k_speed / CYCLE_UNIT, FALSE );
+    CheckDlgButton (hDlg, IDC_COMPATIBLE, workprefs.cpu_compatible);
+    SendDlgItemMessage (hDlg, IDC_CPUIDLE, TBM_SETPOS, TRUE, workprefs.cpu_idle == 0 ? 0 : 12 - workprefs.cpu_idle / 15);
+    CheckRadioButton (hDlg, IDC_CPU0, IDC_CPU6, cpu_ids[workprefs.cpu_level * 2 + !workprefs.address_space_24]);
+
+    if (workprefs.m68k_speed == -1)
+       CheckRadioButton( hDlg, IDC_CS_HOST, IDC_CS_ADJUSTABLE, IDC_CS_HOST );
+    else if (workprefs.m68k_speed == 0)
+       CheckRadioButton( hDlg, IDC_CS_HOST, IDC_CS_ADJUSTABLE, IDC_CS_68000 );
+    else
+       CheckRadioButton( hDlg, IDC_CS_HOST, IDC_CS_ADJUSTABLE, IDC_CS_ADJUSTABLE );
+
+    cpu_based_enable = ( workprefs.cpu_level >= 2 ) &&
+                      ( workprefs.address_space_24 == 0 );
+
+    enable = cpu_based_enable && ( workprefs.cachesize );
+
+#ifdef JIT
+    if( enable ) {
+       if( !canbang ) {
+           workprefs.compforcesettings = TRUE;
+           workprefs.comptrustbyte = 1;
+           workprefs.comptrustword = 1;
+           workprefs.comptrustlong = 1;
+           workprefs.comptrustnaddr= 1;
+       }
+    } else {
+#endif
+       workprefs.cachesize = 0; // Disable JIT
+#ifdef JIT
+    }
+#endif
+
+    if( !workprefs.compforcesettings ) {
+       workprefs.comptrustbyte = 0;
+       workprefs.comptrustword = 0;
+       workprefs.comptrustlong = 0;
+       workprefs.comptrustnaddr= 0;
+    }
+
+    CheckRadioButton( hDlg, IDC_TRUST0, IDC_TRUST2, trust_ids[ workprefs.comptrustbyte ] );
+
+    SendDlgItemMessage( hDlg, IDC_CACHE, TBM_SETPOS, TRUE, workprefs.cachesize / 1024 );
+    sprintf( cache, "%d MB", workprefs.cachesize / 1024 );
+    SetDlgItemText( hDlg, IDC_CACHETEXT, cache );
+
+    CheckDlgButton( hDlg, IDC_FORCE, workprefs.compforcesettings );
+    CheckDlgButton( hDlg, IDC_NOFLAGS, workprefs.compnf );
+    CheckDlgButton( hDlg, IDC_JITFPU, workprefs.compfpu );
+    CheckDlgButton( hDlg, IDC_HARDFLUSH, workprefs.comp_hardflush );
+    CheckDlgButton( hDlg, IDC_CONSTJUMP, workprefs.comp_constjump );
+}
+
+static void values_from_cpudlg (HWND hDlg)
+{
+    int newcpu, newtrust, oldcache;
+    
+    workprefs.cpu_compatible = workprefs.cpu_cycle_exact | (IsDlgButtonChecked (hDlg, IDC_COMPATIBLE) ? 1 : 0);
+    workprefs.m68k_speed = IsDlgButtonChecked (hDlg, IDC_CS_HOST) ? -1
+       : IsDlgButtonChecked (hDlg, IDC_CS_68000) ? 0
+       : SendMessage (GetDlgItem (hDlg, IDC_SPEED), TBM_GETPOS, 0, 0) * CYCLE_UNIT;
+    
+    newcpu = (IsDlgButtonChecked (hDlg, IDC_CPU0) ? 0
+       : IsDlgButtonChecked (hDlg, IDC_CPU1) ? 1
+       : IsDlgButtonChecked (hDlg, IDC_CPU2) ? 2
+       : IsDlgButtonChecked (hDlg, IDC_CPU3) ? 3
+       : IsDlgButtonChecked (hDlg, IDC_CPU4) ? 4
+       : IsDlgButtonChecked (hDlg, IDC_CPU5) ? 5 : 6);
+    /* When switching away from 68000, disable 24 bit addressing.  */
+    switch( newcpu )
+    {
+       case 0: // 68000
+       case 1: // 68010
+       case 2: // 68EC020
+       case 3: // 68EC020+FPU
+           workprefs.address_space_24 = 1;
+           workprefs.cpu_level = newcpu;
+       break;
+
+       case 4: // 68020
+       case 5: // 68020+FPU
+       case 6: // 68040
+           workprefs.address_space_24 = 0;
+           workprefs.cpu_level = newcpu - 2;
+       break;
+    }
+    newtrust = (IsDlgButtonChecked( hDlg, IDC_TRUST0 ) ? 0
+       : IsDlgButtonChecked( hDlg, IDC_TRUST1 ) ? 1 : 3 );
+    workprefs.comptrustbyte = newtrust;
+    workprefs.comptrustword = newtrust;
+    workprefs.comptrustlong = newtrust;
+    workprefs.comptrustnaddr= newtrust;
+
+    workprefs.compforcesettings = IsDlgButtonChecked( hDlg, IDC_FORCE );
+    workprefs.compnf            = IsDlgButtonChecked( hDlg, IDC_NOFLAGS );
+    workprefs.compfpu           = IsDlgButtonChecked( hDlg, IDC_JITFPU );
+    workprefs.comp_hardflush    = IsDlgButtonChecked( hDlg, IDC_HARDFLUSH );
+    workprefs.comp_constjump    = IsDlgButtonChecked( hDlg, IDC_CONSTJUMP );
+
+    oldcache = workprefs.cachesize;
+    workprefs.cachesize = SendMessage(GetDlgItem(hDlg, IDC_CACHE), TBM_GETPOS, 0, 0) * 1024;
+#ifdef JIT
+    if (oldcache == 0 && workprefs.cachesize > 0)
+       canbang = 1;
+#endif
+    workprefs.cpu_idle = SendMessage(GetDlgItem(hDlg, IDC_CPUIDLE), TBM_GETPOS, 0, 0);
+    if (workprefs.cpu_idle > 0)
+       workprefs.cpu_idle = (12 - workprefs.cpu_idle) * 15;
+
+    if (workprefs.cachesize > 0)
+       workprefs.cpu_compatible = 0;
+
+    if (pages[KICKSTART_ID])
+       SendMessage(pages[KICKSTART_ID], WM_USER, 0, 0 );
+    if (pages[DISPLAY_ID])
+       SendMessage(pages[DISPLAY_ID], WM_USER, 0, 0 );
+    if (pages[MEMORY_ID])
+        SendMessage(pages[MEMORY_ID], WM_USER, 0, 0 );
+}
+
+static BOOL CALLBACK CPUDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    static int recursive = 0;
+
+    switch (msg) {
+    case WM_INITDIALOG:
+       pages[CPU_ID] = hDlg;
+       currentpage = CPU_ID;
+       SendDlgItemMessage (hDlg, IDC_SPEED, TBM_SETRANGE, TRUE, MAKELONG (MIN_M68K_PRIORITY, MAX_M68K_PRIORITY));
+       SendDlgItemMessage (hDlg, IDC_SPEED, TBM_SETPAGESIZE, 0, 1);
+       SendDlgItemMessage (hDlg, IDC_CACHE, TBM_SETRANGE, TRUE, MAKELONG (MIN_CACHE_SIZE, MAX_CACHE_SIZE));
+       SendDlgItemMessage (hDlg, IDC_CACHE, TBM_SETPAGESIZE, 0, 1);
+       SendDlgItemMessage (hDlg, IDC_CPUIDLE, TBM_SETRANGE, TRUE, MAKELONG (0, 10));
+       SendDlgItemMessage (hDlg, IDC_CPUIDLE, TBM_SETPAGESIZE, 0, 1);
+
+    case WM_USER:
+       recursive++;
+       values_to_cpudlg (hDlg);
+       enable_for_cpudlg (hDlg);
+       recursive--;
+       return TRUE;
+
+    case WM_COMMAND:
+       if (recursive > 0)
+           break;
+       recursive++;
+       values_from_cpudlg (hDlg);
+       values_to_cpudlg (hDlg);
+       enable_for_cpudlg (hDlg);
+       recursive--;
+       break;
+
+    case WM_HSCROLL:
+       recursive++;
+       values_from_cpudlg( hDlg );
+       values_to_cpudlg( hDlg );
+       enable_for_cpudlg( hDlg );
+       recursive--;
+       break;
+    }
+    return FALSE;
+}
+
+static void enable_for_sounddlg (HWND hDlg)
+{
+    int numdevs;
+
+    enumerate_sound_devices (&numdevs);
+    if( numdevs == 0 )
+       EnableWindow( GetDlgItem( hDlg, IDC_SOUNDCARDLIST ), FALSE );
+    else
+       EnableWindow( GetDlgItem( hDlg, IDC_SOUNDCARDLIST ), workprefs.produce_sound );
+
+    EnableWindow( GetDlgItem( hDlg, IDC_FREQUENCY ), workprefs.produce_sound );
+    EnableWindow( GetDlgItem( hDlg, IDC_SOUNDFREQ ), workprefs.produce_sound ? TRUE : FALSE );
+    EnableWindow( GetDlgItem( hDlg, IDC_SOUNDSTEREO ), workprefs.produce_sound );
+    EnableWindow( GetDlgItem( hDlg, IDC_SOUNDINTERPOLATION ), workprefs.produce_sound );
+    EnableWindow( GetDlgItem( hDlg, IDC_SOUNDVOLUME ), workprefs.produce_sound );
+
+    EnableWindow( GetDlgItem( hDlg, IDC_SOUNDBUFFERMEM ), workprefs.produce_sound );
+    EnableWindow( GetDlgItem( hDlg, IDC_SOUNDBUFFERRAM ), workprefs.produce_sound );
+    EnableWindow( GetDlgItem( hDlg, IDC_SOUNDADJUST ), workprefs.produce_sound );
+    EnableWindow( GetDlgItem( hDlg, IDC_SOUNDADJUSTNUM ), workprefs.produce_sound );
+    EnableWindow( GetDlgItem( hDlg, IDC_SOUNDBUFFERTEXT ), workprefs.produce_sound );
+
+    EnableWindow( GetDlgItem( hDlg, IDC_SOUNDDRIVE ), workprefs.produce_sound );
+    EnableWindow( GetDlgItem( hDlg, IDC_SOUNDDRIVESELECT ), workprefs.produce_sound );
+    EnableWindow( GetDlgItem( hDlg, IDC_SOUNDDRIVEVOLUME ), workprefs.produce_sound );
+
+    EnableWindow( GetDlgItem( hDlg, IDC_AUDIOSYNC ), workprefs.produce_sound );
+    EnableWindow( GetDlgItem( hDlg, IDC_SOUNDFILTER ), workprefs.produce_sound );
+
+    EnableWindow( GetDlgItem( hDlg, IDC_SOUNDCALIBRATE ), workprefs.produce_sound && full_property_sheet);
+}
+
+static int exact_log2 (int v)
+{
+    int l = 0;
+    while ((v >>= 1) != 0)
+       l++;
+    return l;
+}
+
+static char *drivesounds;
+
+static void sound_loaddrivesamples (void)
+{
+    WIN32_FIND_DATA fd;
+    HANDLE h;
+    char *p;
+    int len = 0;
+    char dirname[1024];
+
+    free (drivesounds);
+    p = drivesounds = 0;
+    sprintf (dirname, "%s\\uae_data\\*.wav", start_path);
+    h = FindFirstFile (dirname, &fd);
+    if (h == INVALID_HANDLE_VALUE)
+       return;
+    for (;;) {
+       if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+           char *name = fd.cFileName;
+           if (strlen (name) > strlen (DS_NAME_CLICK) + 4 && !strncmp (name, DS_NAME_CLICK, strlen (DS_NAME_CLICK))) {
+               if (p - drivesounds < 1000) {
+                   char *oldp = p;
+                   len += 2000;
+                   drivesounds = p = realloc (drivesounds, len);
+                   if (oldp)
+                       p = p + strlen (p) + 1;
+               }
+               strcpy (p, name + strlen (DS_NAME_CLICK));
+               p[strlen(name) - 4] = 0;
+               p += strlen (p);
+               *p++ = 0;
+               *p = 0;
+           }
+       }
+       if (!FindNextFile (h, &fd))
+           break;
+    }
+    FindClose (h);
+}
+
+extern int soundpercent;
+
+static void update_soundgui (HWND hDlg)
+{
+    int bufsize;
+    char txt[20];
+
+    bufsize = exact_log2 (workprefs.sound_maxbsiz / 1024);
+    sprintf (txt, "%d (%dms)", bufsize, 1000 * (workprefs.sound_maxbsiz >> 1) / workprefs.sound_freq );
+    SetDlgItemText (hDlg, IDC_SOUNDBUFFERMEM, txt);
+
+    if (workprefs.sound_adjust < -100)
+       workprefs.sound_adjust = -100;
+    if (workprefs.sound_adjust > 30)
+       workprefs.sound_adjust = 30;
+    SendDlgItemMessage( hDlg, IDC_SOUNDADJUST, TBM_SETPOS, TRUE, workprefs.sound_adjust );
+   
+    sprintf (txt, "%.1f%%", workprefs.sound_adjust / 10.0);
+    SetDlgItemText (hDlg, IDC_SOUNDADJUSTNUM, txt);
+
+    SendDlgItemMessage( hDlg, IDC_SOUNDVOLUME, TBM_SETPOS, TRUE, 100 - workprefs.sound_volume );
+    SendDlgItemMessage( hDlg, IDC_SOUNDDRIVEVOLUME, TBM_SETPOS, TRUE, 100 - workprefs.dfxclickvolume );
+}
+
+static int soundfreqs[] = { 11025, 15000, 22050, 32000, 44100, 48000, 0 };
+
+static void values_to_sounddlg (HWND hDlg)
+{
+    int which_button;
+    int sound_freq = workprefs.sound_freq;
+    int produce_sound = workprefs.produce_sound;
+    int stereo = workprefs.stereo;
+    char txt[100], *p;
+    int i, idx, selected;
+
+    if (workprefs.sound_maxbsiz & (workprefs.sound_maxbsiz - 1))
+       workprefs.sound_maxbsiz = DEFAULT_SOUND_MAXB;
+
+    SendDlgItemMessage(hDlg, IDC_SOUNDFILTER, CB_RESETCONTENT, 0, 0);
+    WIN32GUI_LoadUIString (IDS_SOUND_FILTER_OFF, txt, sizeof (txt));
+    SendDlgItemMessage(hDlg, IDC_SOUNDFILTER, CB_ADDSTRING, 0, (LPARAM)txt);
+    WIN32GUI_LoadUIString (IDS_SOUND_FILTER_EMULATED, txt, sizeof (txt));
+    SendDlgItemMessage(hDlg, IDC_SOUNDFILTER, CB_ADDSTRING, 0, (LPARAM)txt);
+    WIN32GUI_LoadUIString (IDS_SOUND_FILTER_ON, txt, sizeof (txt));
+    SendDlgItemMessage(hDlg, IDC_SOUNDFILTER, CB_ADDSTRING, 0, (LPARAM)txt);
+    SendDlgItemMessage(hDlg, IDC_SOUNDFILTER, CB_SETCURSEL, workprefs.sound_filter, 0 );
+
+    SendDlgItemMessage(hDlg, IDC_SOUNDSTEREO, CB_RESETCONTENT, 0, 0);
+    WIN32GUI_LoadUIString (IDS_SOUND_MONO, txt, sizeof (txt));
+    SendDlgItemMessage(hDlg, IDC_SOUNDSTEREO, CB_ADDSTRING, 0, (LPARAM)txt);
+    WIN32GUI_LoadUIString (IDS_SOUND_MIXED, txt, sizeof (txt));
+    SendDlgItemMessage(hDlg, IDC_SOUNDSTEREO, CB_ADDSTRING, 0, (LPARAM)txt);
+    WIN32GUI_LoadUIString (IDS_SOUND_STEREO, txt, sizeof (txt));
+    SendDlgItemMessage(hDlg, IDC_SOUNDSTEREO, CB_ADDSTRING, 0, (LPARAM)txt);
+    which_button = 0;
+    if (workprefs.stereo) {
+       if (workprefs.mixed_stereo)
+           which_button = 1;
+       else
+           which_button = 2;
+    }
+    SendDlgItemMessage (hDlg, IDC_SOUNDSTEREO, CB_SETCURSEL, which_button, 0);
+
+    SendDlgItemMessage(hDlg, IDC_SOUNDINTERPOLATION, CB_RESETCONTENT, 0, 0);
+    WIN32GUI_LoadUIString (IDS_SOUND_INTERPOL_DISABLED, txt, sizeof (txt));
+    SendDlgItemMessage(hDlg, IDC_SOUNDINTERPOLATION, CB_ADDSTRING, 0, (LPARAM)txt);
+    WIN32GUI_LoadUIString (IDS_SOUND_INTERPOL_RH, txt, sizeof (txt));
+    SendDlgItemMessage(hDlg, IDC_SOUNDINTERPOLATION, CB_ADDSTRING, 0, (LPARAM)txt);
+    WIN32GUI_LoadUIString (IDS_SOUND_INTERPOL_CRUX, txt, sizeof (txt));
+    SendDlgItemMessage(hDlg, IDC_SOUNDINTERPOLATION, CB_ADDSTRING, 0, (LPARAM)txt);
+    SendDlgItemMessage (hDlg, IDC_SOUNDINTERPOLATION, CB_SETCURSEL, workprefs.sound_interpol, 0);
+
+    SendDlgItemMessage(hDlg, IDC_SOUNDFREQ, CB_RESETCONTENT, 0, 0);
+    i = 0;
+    selected = -1;
+    while (soundfreqs[i]) {
+       sprintf (txt, "%d", soundfreqs[i]);
+       SendDlgItemMessage( hDlg, IDC_SOUNDFREQ, CB_ADDSTRING, 0, (LPARAM)txt);
+       i++;
+    }
+    sprintf (txt, "%d", workprefs.sound_freq);
+    SendDlgItemMessage( hDlg, IDC_SOUNDFREQ, WM_SETTEXT, 0, (LPARAM)txt); 
+
+    switch (workprefs.produce_sound) {
+     case 0: which_button = IDC_SOUND0; break;
+     case 1: which_button = IDC_SOUND1; break;
+     case 2: which_button = IDC_SOUND2; break;
+     case 3: which_button = IDC_SOUND3; break;
+    }
+    CheckRadioButton( hDlg, IDC_SOUND0, IDC_SOUND3, which_button );
+
+    workprefs.sound_maxbsiz = 1 << exact_log2 (workprefs.sound_maxbsiz);
+    if (workprefs.sound_maxbsiz < 2048)
+       workprefs.sound_maxbsiz = 2048;
+    SendDlgItemMessage( hDlg, IDC_SOUNDBUFFERRAM, TBM_SETPOS, TRUE, exact_log2 (workprefs.sound_maxbsiz / 2048));
+
+    SendDlgItemMessage( hDlg, IDC_SOUNDVOLUME, TBM_SETPOS, TRUE, 0);
+    SendDlgItemMessage( hDlg, IDC_SOUNDDRIVEVOLUME, TBM_SETPOS, TRUE, 0);
+
+    SendDlgItemMessage( hDlg, IDC_SOUNDCARDLIST, CB_SETCURSEL, workprefs.win32_soundcard, 0 );
+
+    idx = SendDlgItemMessage (hDlg, IDC_SOUNDDRIVE, CB_GETCURSEL, 0, 0);
+    if (idx < 0)
+       idx = 0;
+    SendDlgItemMessage(hDlg, IDC_SOUNDDRIVE, CB_RESETCONTENT, 0, 0);
+    for (i = 0; i < 4; i++) {
+       sprintf (txt, "DF%d:", i);
+       SendDlgItemMessage( hDlg, IDC_SOUNDDRIVE, CB_ADDSTRING, 0, (LPARAM)txt);
+    }
+    SendDlgItemMessage (hDlg, IDC_SOUNDDRIVE, CB_SETCURSEL, idx, 0);
+    SendDlgItemMessage(hDlg, IDC_SOUNDDRIVESELECT, CB_RESETCONTENT, 0, 0);
+    WIN32GUI_LoadUIString (IDS_DRIVESOUND_NONE, txt, sizeof (txt));
+    SendDlgItemMessage(hDlg, IDC_SOUNDDRIVESELECT, CB_ADDSTRING, 0, (LPARAM)txt);
+    WIN32GUI_LoadUIString (IDS_DRIVESOUND_DEFAULT_A500, txt, sizeof (txt));
+    SendDlgItemMessage(hDlg, IDC_SOUNDDRIVESELECT, CB_ADDSTRING, 0, (LPARAM)txt);
+    p = drivesounds;
+    if (p) {
+       while (p[0]) {
+           SendDlgItemMessage(hDlg, IDC_SOUNDDRIVESELECT, CB_ADDSTRING, 0, (LPARAM)p);
+           p += strlen (p) + 1;
+       }
+    }
+    if (workprefs.dfxclick[idx] && workprefs.dfxclickexternal[idx][0]) {
+       p = drivesounds;
+       i = DS_BUILD_IN_SOUNDS + 1;
+       while (p && p[0]) {
+           if (!strcmpi (p, workprefs.dfxclickexternal[idx])) {
+               SendDlgItemMessage (hDlg, IDC_SOUNDDRIVESELECT, CB_SETCURSEL, i, 0);
+               break;
+           }
+           i++;
+           p += strlen (p) + 1;
+       }
+    } else {
+       SendDlgItemMessage (hDlg, IDC_SOUNDDRIVESELECT, CB_SETCURSEL, workprefs.dfxclick[idx], 0);
+    }
+
+    update_soundgui (hDlg);
+}
+
+static void values_from_sounddlg (HWND hDlg)
+{
+    int idx, i;
+    char txt[6];
+
+    idx = SendDlgItemMessage (hDlg, IDC_SOUNDFREQ, CB_GETCURSEL, 0, 0);
+    if (idx >= 0) {
+       workprefs.sound_freq = soundfreqs[idx];
+    } else {
+       SendDlgItemMessage (hDlg, IDC_SOUNDFREQ, WM_GETTEXT, (WPARAM)sizeof (txt), (LPARAM)txt);
+       workprefs.sound_freq = atol (txt);
+    }
+    if (workprefs.sound_freq < 8000)
+       workprefs.sound_freq = 8000;
+    if (workprefs.sound_freq > 96000)
+       workprefs.sound_freq = 96000;
+
+    workprefs.produce_sound = (IsDlgButtonChecked (hDlg, IDC_SOUND0) ? 0
+                              : IsDlgButtonChecked (hDlg, IDC_SOUND1) ? 1
+                              : IsDlgButtonChecked (hDlg, IDC_SOUND2) ? 2 : 3);
+    idx = SendDlgItemMessage (hDlg, IDC_SOUNDSTEREO, CB_GETCURSEL, 0, 0);
+    workprefs.mixed_stereo = 0;
+    workprefs.stereo = 0;
+    if (idx > 0) {
+       workprefs.stereo = 1;
+       if (idx == 1)
+           workprefs.mixed_stereo = 1;
+    }
+    workprefs.sound_interpol = SendDlgItemMessage (hDlg, IDC_SOUNDINTERPOLATION, CB_GETCURSEL, 0, 0);
+    workprefs.win32_soundcard = SendDlgItemMessage (hDlg, IDC_SOUNDCARDLIST, CB_GETCURSEL, 0, 0L);
+    workprefs.sound_filter = SendDlgItemMessage (hDlg, IDC_SOUNDFILTER, CB_GETCURSEL, 0, 0);
+
+    idx = SendDlgItemMessage (hDlg, IDC_SOUNDDRIVE, CB_GETCURSEL, 0, 0);
+    if (idx >= 0) {
+       i = SendDlgItemMessage (hDlg, IDC_SOUNDDRIVESELECT, CB_GETCURSEL, 0, 0);
+       if (i >= 0) {
+           if (i > DS_BUILD_IN_SOUNDS) {
+               int j = i - (DS_BUILD_IN_SOUNDS + 1);
+               char *p = drivesounds;
+               while (j-- > 0)
+                   p += strlen (p) + 1;
+               workprefs.dfxclick[idx] = -1;
+               strcpy (workprefs.dfxclickexternal[idx], p);
+           } else {
+               workprefs.dfxclick[idx] = i;
+               workprefs.dfxclickexternal[idx][0] = 0;
+           }
+       }
+    }
+}
+
+extern int sound_calibrate (HWND, struct uae_prefs*);
+
+static BOOL CALLBACK SoundDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    static int recursive = 0;
+    int numdevs;
+    int card;
+    char **sounddevs;
+
+    switch (msg) {
+    case WM_INITDIALOG:
+       sound_loaddrivesamples ();
+       SendDlgItemMessage (hDlg, IDC_SOUNDBUFFERRAM, TBM_SETRANGE, TRUE, MAKELONG (MIN_SOUND_MEM, MAX_SOUND_MEM));
+       SendDlgItemMessage (hDlg, IDC_SOUNDBUFFERRAM, TBM_SETPAGESIZE, 0, 1);
+
+       SendDlgItemMessage (hDlg, IDC_SOUNDVOLUME, TBM_SETRANGE, TRUE, MAKELONG (0, 100));
+       SendDlgItemMessage (hDlg, IDC_SOUNDVOLUME, TBM_SETPAGESIZE, 0, 1);
+
+       SendDlgItemMessage (hDlg, IDC_SOUNDDRIVEVOLUME, TBM_SETRANGE, TRUE, MAKELONG (0, 100));
+       SendDlgItemMessage (hDlg, IDC_SOUNDDRIVEVOLUME, TBM_SETPAGESIZE, 0, 1);
+
+       SendDlgItemMessage( hDlg, IDC_SOUNDADJUST, TBM_SETRANGE, TRUE, MAKELONG (-100, +30) );
+       SendDlgItemMessage( hDlg, IDC_SOUNDADJUST, TBM_SETPAGESIZE, 0, 1 );
+
+       SendDlgItemMessage( hDlg, IDC_SOUNDCARDLIST, CB_RESETCONTENT, 0, 0L );
+       sounddevs = enumerate_sound_devices (&numdevs);
+       for (card = 0; card < numdevs; card++)
+           SendDlgItemMessage (hDlg, IDC_SOUNDCARDLIST, CB_ADDSTRING, 0, (LPARAM)sounddevs[card]);
+       if (numdevs == 0)
+           workprefs.produce_sound = 0; /* No sound card in system, enable_for_sounddlg will accomodate this */
+
+       pages[SOUND_ID] = hDlg;
+       currentpage = SOUND_ID;
+
+    case WM_USER:
+       recursive++;
+       values_to_sounddlg (hDlg);
+       enable_for_sounddlg (hDlg);
+       recursive--;
+       return TRUE;
+
+    case WM_COMMAND:
+       if (recursive > 0)
+           break;
+       recursive++;
+       if ((wParam & 0xffff) == IDC_SOUNDCALIBRATE) {
+           int pct = sound_calibrate (hDlg, &workprefs);
+           workprefs.sound_adjust = (pct - 1000);
+           update_soundgui (hDlg);
+       } else if((wParam & 0xffff) == IDC_SOUNDDRIVE) {
+           int idx = SendDlgItemMessage (hDlg, IDC_SOUNDDRIVE, CB_GETCURSEL, 0, 0);;
+           if (idx >= 0)
+               SendDlgItemMessage (hDlg, IDC_SOUNDDRIVESELECT, CB_SETCURSEL, workprefs.dfxclick[idx], 0);
+       }
+       values_from_sounddlg (hDlg);
+       enable_for_sounddlg (hDlg);
+       recursive--;
+       break;
+
+     case WM_HSCROLL:
+       workprefs.sound_maxbsiz = 2048 << SendMessage( GetDlgItem( hDlg, IDC_SOUNDBUFFERRAM ), TBM_GETPOS, 0, 0 );
+       workprefs.sound_adjust = SendMessage( GetDlgItem( hDlg, IDC_SOUNDADJUST ), TBM_GETPOS, 0, 0 );
+       workprefs.sound_volume = 100 - SendMessage( GetDlgItem( hDlg, IDC_SOUNDVOLUME ), TBM_GETPOS, 0, 0 );
+       workprefs.dfxclickvolume = 100 - SendMessage( GetDlgItem( hDlg, IDC_SOUNDDRIVEVOLUME ), TBM_GETPOS, 0, 0 );
+       update_soundgui (hDlg);
+       break;
+    }
+    return FALSE;
+}
+
+#ifdef FILESYS
+
+struct fsvdlg_vals
+{
+    char volume[4096];
+    char device[4096];
+    char rootdir[4096];
+    int bootpri;
+    int rw;
+    int rdb;
+};
+
+static struct fsvdlg_vals empty_fsvdlg = { "", "", "", 0, 1, 0 };
+static struct fsvdlg_vals current_fsvdlg;
+
+struct hfdlg_vals
+{
+    char volumename[4096];
+    char devicename[4096];
+    char filename[4096];
+    char fsfilename[4096];
+    int sectors;
+    int reserved;
+    int surfaces;
+    int cylinders;
+    int blocksize;
+    int rw;
+    int rdb;
+    int bootpri;
+};
+
+static struct hfdlg_vals empty_hfdlg = { "", "", "", "", 32, 2, 1, 0, 512, 1, 0, 0 };
+static struct hfdlg_vals current_hfdlg;
+
+static int CALLBACK VolumeSettingsProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    static int recursive = 0;
+    BROWSEINFO browse_info;
+    char directory_path[MAX_PATH] = "";
+    LPITEMIDLIST browse;
+    char szTitle[ MAX_PATH ];
+
+    WIN32GUI_LoadUIString( IDS_SELECTFILESYSROOT, szTitle, MAX_PATH );
+
+    browse_info.hwndOwner = hDlg;
+    browse_info.pidlRoot = NULL;
+    browse_info.pszDisplayName = directory_path;
+    browse_info.lpszTitle = "";
+    browse_info.ulFlags = BIF_DONTGOBELOWDOMAIN | BIF_RETURNONLYFSDIRS;
+    browse_info.lpfn = NULL;
+    browse_info.iImage = 0;
+
+    switch (msg) {
+     case WM_INITDIALOG:
+       recursive++;
+       SetDlgItemText (hDlg, IDC_VOLUME_NAME, current_fsvdlg.volume);
+       SetDlgItemText (hDlg, IDC_VOLUME_DEVICE, current_fsvdlg.device);
+       SetDlgItemText (hDlg, IDC_PATH_NAME, current_fsvdlg.rootdir);
+        SetDlgItemInt (hDlg, IDC_VOLUME_BOOTPRI, current_fsvdlg.bootpri, TRUE);
+       CheckDlgButton (hDlg, IDC_RW, current_fsvdlg.rw);
+       recursive--;
+       return TRUE;
+
+     case WM_COMMAND:
+       if (recursive)
+           break;
+       recursive++;
+       if (HIWORD (wParam) == BN_CLICKED) {
+           switch (LOWORD (wParam)) {
+            case IDC_SELECTOR:
+               if ((browse = SHBrowseForFolder (&browse_info)) != NULL) {
+                   SHGetPathFromIDList (browse, directory_path);
+                   SetDlgItemText (hDlg, IDC_PATH_NAME, directory_path);
+               }
+               break;
+            case IDOK:
+                   if( strlen( current_fsvdlg.rootdir ) == 0 ) 
+                   {
+                       char szMessage[ MAX_PATH ];
+                       char szTitle[ MAX_PATH ];
+                       WIN32GUI_LoadUIString( IDS_MUSTSELECTPATH, szMessage, MAX_PATH );
+                       WIN32GUI_LoadUIString( IDS_SETTINGSERROR, szTitle, MAX_PATH );
+
+                       MessageBox( hDlg, szMessage, szTitle,
+                               MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
+                       break;
+                   }
+                   if( strlen( current_fsvdlg.volume ) == 0 )
+                   {
+                       char szMessage[ MAX_PATH ];
+                       char szTitle[ MAX_PATH ];
+                       WIN32GUI_LoadUIString( IDS_MUSTSELECTNAME, szMessage, MAX_PATH );
+                       WIN32GUI_LoadUIString( IDS_SETTINGSERROR, szTitle, MAX_PATH );
+
+                       MessageBox( hDlg, szMessage, szTitle,
+                               MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
+                       break;
+                   }
+               EndDialog (hDlg, 1);
+
+               break;
+            case IDCANCEL:
+               EndDialog (hDlg, 0);
+               break;
+           }
+       }
+       GetDlgItemText (hDlg, IDC_PATH_NAME, current_fsvdlg.rootdir, sizeof current_fsvdlg.rootdir);
+       GetDlgItemText (hDlg, IDC_VOLUME_NAME, current_fsvdlg.volume, sizeof current_fsvdlg.volume);
+       GetDlgItemText (hDlg, IDC_VOLUME_DEVICE, current_fsvdlg.device, sizeof current_fsvdlg.device);
+       current_fsvdlg.rw = IsDlgButtonChecked (hDlg, IDC_RW);
+       current_fsvdlg.bootpri = GetDlgItemInt( hDlg, IDC_VOLUME_BOOTPRI, NULL, TRUE );
+       recursive--;
+       break;
+    }
+    return FALSE;
+}
+
+static void sethardfile (HWND hDlg)
+{
+    SetDlgItemText (hDlg, IDC_PATH_NAME, current_hfdlg.filename);
+    SetDlgItemText (hDlg, IDC_PATH_FILESYS, current_hfdlg.fsfilename);
+    SetDlgItemText (hDlg, IDC_HARDFILE_DEVICE, current_hfdlg.devicename);
+    SetDlgItemInt( hDlg, IDC_SECTORS, current_hfdlg.sectors, FALSE);
+    SetDlgItemInt( hDlg, IDC_HEADS, current_hfdlg.surfaces, FALSE);
+    SetDlgItemInt( hDlg, IDC_RESERVED, current_hfdlg.reserved, FALSE);
+    SetDlgItemInt( hDlg, IDC_BLOCKSIZE, current_hfdlg.blocksize, FALSE);
+    SetDlgItemInt( hDlg, IDC_HARDFILE_BOOTPRI, current_hfdlg.bootpri, TRUE);
+    CheckDlgButton (hDlg, IDC_RW, current_hfdlg.rw);
+}
+
+static void hardfile_testrdb (HWND hDlg)
+{
+    void *f = zfile_fopen (current_hfdlg.filename, "rb");
+    char tmp[8] = { 0 };
+    if (!f)
+       return;
+    zfile_fread (tmp, 1, sizeof (tmp), f);
+    zfile_fclose (f);
+    if (memcmp (tmp, "RDSK\0\0\0", 7))
+       return;
+    current_hfdlg.sectors = 0;
+    current_hfdlg.surfaces = 0;
+    current_hfdlg.reserved = 0;
+    current_hfdlg.fsfilename[0] = 0;
+    current_hfdlg.bootpri = 0;
+    current_hfdlg.devicename[0] = 0;
+    sethardfile (hDlg);
+}
+
+static int CALLBACK HardfileSettingsProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    static int recursive = 0;
+    UINT setting;
+
+    switch (msg) {
+    case WM_INITDIALOG:
+       recursive++;
+       sethardfile (hDlg);
+       recursive--;
+       return TRUE;
+
+    case WM_COMMAND:
+       if (recursive)
+           break;
+       recursive++;
+
+       if (HIWORD (wParam) == BN_CLICKED) {
+           switch (LOWORD (wParam)) {
+           case IDC_CREATEHF:
+               setting = CalculateHardfileSize (hDlg);
+               if( !CreateHardFile(hDlg, setting) )
+               {
+                   char szMessage[ MAX_PATH ];
+                   char szTitle[ MAX_PATH ];
+                   WIN32GUI_LoadUIString( IDS_FAILEDHARDFILECREATION, szMessage, MAX_PATH );
+                   WIN32GUI_LoadUIString( IDS_CREATIONERROR, szTitle, MAX_PATH );
+
+                   MessageBox( hDlg, szMessage, szTitle,
+                               MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
+               }
+               break;
+           case IDC_SELECTOR:
+               DiskSelection (hDlg, IDC_PATH_NAME, 2, &workprefs, 0);
+               GetDlgItemText (hDlg, IDC_PATH_NAME, current_hfdlg.filename, sizeof current_hfdlg.filename);
+               hardfile_testrdb (hDlg);
+               break;
+           case IDC_FILESYS_SELECTOR:
+               DiskSelection (hDlg, IDC_PATH_FILESYS, 12, &workprefs, 0);
+               break;
+           case IDOK:
+               if( strlen( current_hfdlg.filename ) == 0 ) 
+               {
+                   char szMessage[ MAX_PATH ];
+                   char szTitle[ MAX_PATH ];
+                   WIN32GUI_LoadUIString( IDS_MUSTSELECTFILE, szMessage, MAX_PATH );
+                   WIN32GUI_LoadUIString( IDS_SETTINGSERROR, szTitle, MAX_PATH );
+
+                   MessageBox( hDlg, szMessage, szTitle,
+                               MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
+                   break;
+               }
+               EndDialog (hDlg, 1);
+               break;
+           case IDCANCEL:
+               EndDialog (hDlg, 0);
+               break;
+           }
+       }
+
+       GetDlgItemText (hDlg, IDC_PATH_NAME, current_hfdlg.filename, sizeof current_hfdlg.filename);
+       GetDlgItemText (hDlg, IDC_PATH_FILESYS, current_hfdlg.fsfilename, sizeof current_hfdlg.fsfilename);
+       GetDlgItemText (hDlg, IDC_HARDFILE_DEVICE, current_hfdlg.devicename, sizeof current_hfdlg.devicename);
+       current_hfdlg.sectors   = GetDlgItemInt( hDlg, IDC_SECTORS, NULL, FALSE );
+       current_hfdlg.reserved  = GetDlgItemInt( hDlg, IDC_RESERVED, NULL, FALSE );
+       current_hfdlg.surfaces  = GetDlgItemInt( hDlg, IDC_HEADS, NULL, FALSE );
+       current_hfdlg.blocksize = GetDlgItemInt( hDlg, IDC_BLOCKSIZE, NULL, FALSE );
+       current_hfdlg.bootpri = GetDlgItemInt( hDlg, IDC_HARDFILE_BOOTPRI, NULL, TRUE );
+       current_hfdlg.rw = IsDlgButtonChecked (hDlg, IDC_RW);
+       recursive--;
+
+       break;
+    }
+    return FALSE;
+}
+
+static int CALLBACK HarddriveSettingsProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    static int recursive = 0;
+    int i, posn, index;
+
+    switch (msg) {
+    case WM_INITDIALOG:
+       hdf_init ();
+       recursive++;
+       CheckDlgButton (hDlg, IDC_RW, current_hfdlg.rw);
+       SendDlgItemMessage(hDlg, IDC_HARDDRIVE, CB_RESETCONTENT, 0, 0);
+       index = -1;
+       for (i = 0; i < hdf_getnumharddrives(); i++) {
+            SendDlgItemMessage( hDlg, IDC_HARDDRIVE, CB_ADDSTRING, 0, (LPARAM)hdf_getnameharddrive(i, 1));
+           if (!strcmp (current_hfdlg.filename, hdf_getnameharddrive (i, 0))) index = i;
+       }
+       if (index >= 0)
+           SendDlgItemMessage (hDlg, IDC_HARDDRIVE, CB_SETCURSEL, index, 0);
+       recursive--;
+       return TRUE;
+
+    case WM_COMMAND:
+       if (recursive)
+           break;
+       recursive++;
+
+       if (HIWORD (wParam) == BN_CLICKED) {
+           switch (LOWORD (wParam)) {
+           case IDOK:
+               EndDialog (hDlg, 1);
+               break;
+           case IDCANCEL:
+               EndDialog (hDlg, 0);
+               break;
+           }
+       }
+
+        posn = SendDlgItemMessage (hDlg, IDC_HARDDRIVE, CB_GETCURSEL, 0, 0);
+       if (posn != CB_ERR)
+           strcpy (current_hfdlg.filename, hdf_getnameharddrive (posn, 0));
+       current_hfdlg.rw = IsDlgButtonChecked (hDlg, IDC_RW);
+       recursive--;
+       break;
+    }
+    return FALSE;
+}
+
+static void new_filesys (HWND hDlg)
+{
+    const char *result;
+
+    result = add_filesys_unit (currprefs.mountinfo, current_fsvdlg.device, current_fsvdlg.volume,
+                   current_fsvdlg.rootdir, ! current_fsvdlg.rw, 0, 0, 0, 0, current_fsvdlg.bootpri, 0);
+    if (result)
+       MessageBox (hDlg, result, "Bad directory",
+                   MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
+}
+
+static void new_hardfile (HWND hDlg)
+{
+    const char *result;
+
+    result = add_filesys_unit (currprefs.mountinfo, current_hfdlg.devicename, 0,
+                               current_hfdlg.filename, ! current_hfdlg.rw,
+                               current_hfdlg.sectors, current_hfdlg.surfaces,
+                              current_hfdlg.reserved, current_hfdlg.blocksize,
+                              current_hfdlg.bootpri, current_hfdlg.fsfilename);
+    if (result)
+       MessageBox (hDlg, result, "Bad hardfile",
+                   MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
+}
+
+static void new_harddrive (HWND hDlg)
+{
+    const char *result;
+
+    result = add_filesys_unit (currprefs.mountinfo, 0, 0,
+                               current_hfdlg.filename, ! current_hfdlg.rw, 0, 0,
+                              0, current_hfdlg.blocksize, 0, 0);
+    if (result)
+       MessageBox (hDlg, result, "Bad harddrive",
+                   MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
+}
+
+static void harddisk_remove (HWND hDlg)
+{
+    int entry = listview_find_selected (GetDlgItem (hDlg, IDC_VOLUMELIST));
+    if (entry < 0)
+       return;
+    kill_filesys_unit (currprefs.mountinfo, entry);
+}
+
+static void harddisk_move (HWND hDlg, int up)
+{
+    int entry = listview_find_selected (GetDlgItem (hDlg, IDC_VOLUMELIST));
+    if (entry < 0)
+       return;
+    move_filesys_unit (currprefs.mountinfo, entry, up ? entry - 1 : entry + 1);
+}
+
+static void harddisk_edit (HWND hDlg)
+{
+    int entry = listview_find_selected (GetDlgItem (hDlg, IDC_VOLUMELIST));
+    char *volname, *devname, *rootdir, *filesys;
+    int secspertrack, surfaces, cylinders, reserved, blocksize, readonly, type, bootpri;
+    uae_u64 size;
+    const char *failure;
+
+    if (entry < 0)
+       return;
+    
+    failure = get_filesys_unit (currprefs.mountinfo, entry, &devname, &volname, &rootdir, &readonly,
+                           &secspertrack, &surfaces, &reserved, &cylinders, &size,
+                           &blocksize, &bootpri, &filesys);
+
+    type = is_hardfile( currprefs.mountinfo, entry );
+    if( type == FILESYS_HARDFILE || type == FILESYS_HARDFILE_RDB )
+    {
+       current_hfdlg.sectors = secspertrack;
+       current_hfdlg.surfaces = surfaces;
+       current_hfdlg.reserved = reserved;
+       current_hfdlg.cylinders = cylinders;
+       current_hfdlg.blocksize = blocksize;
+
+       strncpy (current_hfdlg.filename, rootdir, (sizeof current_hfdlg.filename) - 1);
+       current_hfdlg.filename[(sizeof current_hfdlg.filename) - 1] = '\0';
+       current_hfdlg.fsfilename[0] = 0;
+       if (filesys) {
+           strncpy (current_hfdlg.fsfilename, filesys, (sizeof current_hfdlg.fsfilename) - 1);
+           current_hfdlg.fsfilename[(sizeof current_hfdlg.fsfilename) - 1] = '\0';
+       }
+       current_fsvdlg.device[0] = 0;
+       if (devname) {
+           strncpy (current_hfdlg.devicename, devname, (sizeof current_hfdlg.devicename) - 1);
+           current_hfdlg.devicename[(sizeof current_hfdlg.devicename) - 1] = '\0';
+       }
+       current_hfdlg.rw = !readonly;
+       current_hfdlg.bootpri = bootpri;
+       if (DialogBox( hUIDLL ? hUIDLL : hInst, MAKEINTRESOURCE (IDD_HARDFILE), hDlg, HardfileSettingsProc)) 
+        {
+           const char *result;
+           result = set_filesys_unit (currprefs.mountinfo, entry, current_hfdlg.devicename, 0, current_hfdlg.filename,
+                                      ! current_hfdlg.rw, current_hfdlg.sectors, current_hfdlg.surfaces,
+                                      current_hfdlg.reserved, current_hfdlg.blocksize, current_hfdlg.bootpri, current_hfdlg.fsfilename);
+           if (result)
+               MessageBox (hDlg, result, "Bad hardfile",
+               MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
+       }
+    }
+    else if (type == FILESYS_HARDDRIVE) /* harddisk */
+    {
+       current_hfdlg.rw = !readonly;
+       strncpy (current_hfdlg.filename, rootdir, (sizeof current_hfdlg.filename) - 1);
+       current_hfdlg.filename[(sizeof current_hfdlg.filename) - 1] = '\0';
+       if (DialogBox( hUIDLL ? hUIDLL : hInst, MAKEINTRESOURCE (IDD_HARDDRIVE), hDlg, HarddriveSettingsProc)) 
+        {
+           const char *result;
+           result = set_filesys_unit (currprefs.mountinfo, entry, 0, 0, current_hfdlg.filename,
+                                      ! current_hfdlg.rw, 0, 0,
+                                      0, current_hfdlg.blocksize, current_hfdlg.bootpri, 0);
+           if (result)
+               MessageBox (hDlg, result, "Bad harddrive",
+               MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
+       }
+    }
+    else /* Filesystem */
+    {
+       strncpy (current_fsvdlg.rootdir, rootdir, (sizeof current_fsvdlg.rootdir) - 1);
+       current_fsvdlg.rootdir[(sizeof current_fsvdlg.rootdir) - 1] = '\0';
+       strncpy (current_fsvdlg.volume, volname, (sizeof current_fsvdlg.volume) - 1);
+       current_fsvdlg.volume[(sizeof current_fsvdlg.volume) - 1] = '\0';
+       current_fsvdlg.device[0] = 0;
+       if (devname) {
+           strncpy (current_fsvdlg.device, devname, (sizeof current_fsvdlg.device) - 1);
+           current_fsvdlg.device[(sizeof current_fsvdlg.device) - 1] = '\0';
+       }
+       current_fsvdlg.rw = !readonly;
+       current_fsvdlg.bootpri = bootpri;
+       if (DialogBox( hUIDLL ? hUIDLL : hInst, MAKEINTRESOURCE (IDD_FILESYS), hDlg, VolumeSettingsProc)) {
+           const char *result;
+           result = set_filesys_unit (currprefs.mountinfo, entry, current_fsvdlg.device, current_fsvdlg.volume,
+                                      current_fsvdlg.rootdir, ! current_fsvdlg.rw, 0, 0, 0, 0, current_fsvdlg.bootpri, 0);
+           if (result)
+               MessageBox (hDlg, result, "Bad hardfile",
+               MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
+       }
+    }
+}
+
+static void harddiskdlg_button (HWND hDlg, int button)
+{
+    switch (button) {
+     case IDC_NEW_FS:
+       current_fsvdlg = empty_fsvdlg;
+       if (DialogBox( hUIDLL ? hUIDLL : hInst, MAKEINTRESOURCE (IDD_FILESYS), hDlg, VolumeSettingsProc))
+           new_filesys (hDlg);
+       break;
+
+     case IDC_NEW_HF:
+       current_hfdlg = empty_hfdlg;
+       if (DialogBox( hUIDLL ? hUIDLL : hInst, MAKEINTRESOURCE (IDD_HARDFILE), hDlg, HardfileSettingsProc))
+           new_hardfile (hDlg);
+       break;
+
+     case IDC_NEW_HD:
+       memset (&current_hfdlg, 0, sizeof (current_hfdlg));
+       if (DialogBox( hUIDLL ? hUIDLL : hInst, MAKEINTRESOURCE (IDD_HARDDRIVE), hDlg, HarddriveSettingsProc))
+           new_harddrive (hDlg);
+       break;
+
+     case IDC_EDIT:
+       harddisk_edit (hDlg);
+       break;
+
+     case IDC_REMOVE:
+       harddisk_remove (hDlg);
+       break;
+
+     case IDC_UP:
+       harddisk_move (hDlg, 1);
+       clicked_entry--;
+       break;
+
+     case IDC_DOWN:
+       harddisk_move (hDlg, 0);
+       clicked_entry++;
+       break;
+     
+    case IDC_MAPDRIVES:
+        workprefs.win32_automount_drives = IsDlgButtonChecked( hDlg, button );
+        break;
+    }
+}
+
+static void harddiskdlg_volume_notify (HWND hDlg, NM_LISTVIEW *nmlistview)
+{
+    HWND list = nmlistview->hdr.hwndFrom;
+    int dblclick = 0;
+    int entry = 0;
+
+    switch (nmlistview->hdr.code) {
+     case NM_DBLCLK:
+       dblclick = 1;
+       /* fall through */
+     case NM_CLICK:
+       entry = listview_entry_from_click (list, 0);
+       if (entry >= 0)
+       {
+           if(dblclick)
+               harddisk_edit (hDlg);
+           InitializeListView( hDlg );
+           clicked_entry = entry;
+           cachedlist = list;
+           // Hilite the current selected item
+           ListView_SetItemState( cachedlist, clicked_entry, LVIS_SELECTED, LVIS_SELECTED );
+       }
+       break;
+    }
+}
+
+static BOOL CALLBACK HarddiskDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+
+    switch (msg) {
+    case WM_INITDIALOG:
+       clicked_entry = 0;
+       pages[HARDDISK_ID] = hDlg;
+       currentpage = HARDDISK_ID;
+       SendMessage( GetDlgItem( hDlg, IDC_UP ), BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hMoveUp );
+       SendMessage( GetDlgItem( hDlg, IDC_DOWN ), BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hMoveDown );
+       EnableWindow (GetDlgItem(hDlg, IDC_NEW_HD), os_winnt ? TRUE : FALSE);
+       
+    case WM_USER:
+        CheckDlgButton( hDlg, IDC_MAPDRIVES, workprefs.win32_automount_drives );
+        InitializeListView( hDlg );
+       break;
+       
+    case WM_COMMAND:
+       if (HIWORD (wParam) == BN_CLICKED)
+       {
+           harddiskdlg_button (hDlg, LOWORD (wParam));
+           InitializeListView( hDlg );
+
+           if( clicked_entry < 0 )
+               clicked_entry = 0;
+           if( clicked_entry >= ListView_GetItemCount( cachedlist ) )
+               clicked_entry = ListView_GetItemCount( cachedlist ) - 1;
+
+           if( cachedlist && clicked_entry >= 0 )
+           {
+               // Hilite the current selected item
+               ListView_SetItemState( cachedlist, clicked_entry, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED );
+           }
+       }
+       break;
+       
+    case WM_NOTIFY:
+       if (((LPNMHDR) lParam)->idFrom == IDC_VOLUMELIST)
+           harddiskdlg_volume_notify (hDlg, (NM_LISTVIEW *) lParam);
+       return TRUE;
+    default:
+       return FALSE;
+    }
+    
+    return FALSE;
+}
+
+#endif
+
+static void out_floppyspeed (HWND hDlg)
+{
+    char txt[30];
+    if (workprefs.floppy_speed)
+       sprintf (txt, "%d%%%s", workprefs.floppy_speed, workprefs.floppy_speed == 100 ? " (compatible)" : "");
+    else
+        strcpy (txt, "Turbo");
+    SetDlgItemText (hDlg, IDC_FLOPPYSPDTEXT, txt);
+}
+
+#define BUTTONSPERFLOPPY 5
+static int floppybuttons[][BUTTONSPERFLOPPY] = {
+    { IDC_DF0TEXT,IDC_DF0,IDC_EJECT0,IDC_DF0TYPE,IDC_DF0WP },
+    { IDC_DF1TEXT,IDC_DF1,IDC_EJECT1,IDC_DF1TYPE,IDC_DF1WP },
+    { IDC_DF2TEXT,IDC_DF2,IDC_EJECT2,IDC_DF2TYPE,IDC_DF2WP },
+    { IDC_DF3TEXT,IDC_DF3,IDC_EJECT3,IDC_DF3TYPE,IDC_DF3WP }
+};
+    
+static void addfloppytype (HWND hDlg, int n)
+{
+    int f_text = floppybuttons[n][0];
+    int f_drive = floppybuttons[n][1];
+    int f_eject = floppybuttons[n][2];
+    int f_type = floppybuttons[n][3];
+    int f_wp = floppybuttons[n][4];
+    int nn = workprefs.dfxtype[n] + 1;
+    int state, i;
+    char *s, tmp[1000];
+    HKEY fkey;
+    DWORD size;
+    static int regread;
+
+    if (nn <= 0)
+       state = FALSE;
+    else
+       state = TRUE;
+    SendDlgItemMessage (hDlg, f_type, CB_SETCURSEL, nn, 0);
+
+    EnableWindow(GetDlgItem(hDlg, f_text), state);
+    EnableWindow(GetDlgItem(hDlg, f_eject), state);
+    EnableWindow(GetDlgItem(hDlg, f_drive), state);
+    CheckDlgButton(hDlg, f_wp, disk_getwriteprotect (workprefs.df[n]) && state == TRUE ? BST_CHECKED : 0);
+    EnableWindow(GetDlgItem(hDlg, f_wp), state && DISK_validate_filename (workprefs.df[n], 0, 0) ? TRUE : FALSE);
+
+    RegCreateKeyEx(hWinUAEKey , "DiskImageMRUList", 0, NULL, REG_OPTION_NON_VOLATILE,
+       KEY_ALL_ACCESS, NULL, &fkey, NULL);
+    if (!regread) {
+       char tmp2[1000];
+       DWORD size2;
+       int idx, idx2;
+
+       idx = 0;
+       for (;;) {
+           int err;
+           size = sizeof (tmp);
+           size2 = sizeof (tmp2);
+           err = RegEnumValue(fkey, idx, tmp, &size, NULL, NULL, tmp2, &size2);
+           if (err != ERROR_SUCCESS)
+               break;
+           if (strlen (tmp) == 7) {
+               idx2 = atol (tmp + 5) - 1;
+               if (idx2 >= 0)
+                   DISK_history_add (tmp2, idx2);
+           }
+           idx++;
+       }
+       regread = 1;
+    }
+    SendDlgItemMessage(hDlg, f_text, CB_RESETCONTENT, 0, 0);
+    SendDlgItemMessage(hDlg, f_text, WM_SETTEXT, 0, (LPARAM)workprefs.df[n]); 
+    i = 0;
+    while (s = DISK_history_get (i)) {
+       i++;
+       SendDlgItemMessage(hDlg, f_text, CB_ADDSTRING, 0, (LPARAM)s);
+       if (fkey) {
+           sprintf (tmp, "Image%02d", i);
+           RegSetValueEx(fkey, tmp, 0, REG_SZ, (CONST BYTE *)s, strlen(s));
+       }
+    }
+    if (fkey)
+       RegCloseKey (fkey);
+}
+
+static void getfloppytype (HWND hDlg, int n)
+{
+    int f_type = floppybuttons[n][3];
+    int val = SendDlgItemMessage (hDlg, f_type, CB_GETCURSEL, 0, 0L);
+    
+    if (val != CB_ERR && workprefs.dfxtype[n] != val - 1) {
+       workprefs.dfxtype[n] = val - 1;
+       addfloppytype (hDlg, n);
+    }
+}
+
+static void getfloppyname (HWND hDlg, int n)
+{
+    int val;
+    int f_text = floppybuttons[n][0];
+    char tmp[1000];
+
+    tmp[0] = 0;
+    val = SendDlgItemMessage (hDlg, f_text, CB_GETCURSEL, 0, 0L);
+    if (val == CB_ERR) {
+       SendDlgItemMessage (hDlg, f_text, WM_GETTEXT, (WPARAM)sizeof (tmp), (LPARAM)tmp);
+    } else {
+       char *s = DISK_history_get (val);
+       if (s)
+           strcpy (tmp, s);
+    }
+    strcpy (workprefs.df[n], tmp);
+    strcpy (changed_prefs.df[n], tmp);
+}
+
+static void addallfloppies (HWND hDlg)
+{
+    int i;
+    
+    for (i = 0; i < 4; i++)
+       addfloppytype (hDlg, i);
+}
+
+static void floppysetwriteprotect (HWND hDlg, int n, int protect)
+{
+    disk_setwriteprotect (n, workprefs.df[n], protect);
+    addfloppytype (hDlg, n);
+}
+
+static BOOL CALLBACK FloppyDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    static int recursive = 0;
+    int i;
+    switch (msg) 
+    {
+    case WM_INITDIALOG:
+    {
+       char ft35dd[100];
+       char ft35hd[100];
+       char ft525sd[100];
+       char ftdis[100];
+       WIN32GUI_LoadUIString(IDS_FLOPPYTYPE35DD, ft35dd, sizeof (ft35dd));
+       WIN32GUI_LoadUIString(IDS_FLOPPYTYPE35HD, ft35hd, sizeof (ft35hd));
+       WIN32GUI_LoadUIString(IDS_FLOPPYTYPE525SD, ft525sd, sizeof (ft525sd));
+       WIN32GUI_LoadUIString(IDS_FLOPPYTYPEDISABLED, ftdis, sizeof (ftdis));
+       pages[FLOPPY_ID] = hDlg;
+       if (workprefs.floppy_speed > 0 && workprefs.floppy_speed < 10)
+           workprefs.floppy_speed = 100;
+       currentpage = FLOPPY_ID;
+       SendDlgItemMessage (hDlg, IDC_FLOPPYSPD, TBM_SETRANGE, TRUE, MAKELONG (0, 4));
+       SendDlgItemMessage (hDlg, IDC_FLOPPYSPD, TBM_SETPAGESIZE, 0, 1);
+        SendDlgItemMessage (hDlg, IDC_FLOPPYTYPE, CB_RESETCONTENT, 0, 0L);
+       SendDlgItemMessage (hDlg, IDC_FLOPPYTYPE, CB_ADDSTRING, 0, (LPARAM)ft35dd);
+       SendDlgItemMessage (hDlg, IDC_FLOPPYTYPE, CB_ADDSTRING, 0, (LPARAM)ft35hd);
+       SendDlgItemMessage (hDlg, IDC_FLOPPYTYPE, CB_ADDSTRING, 0, (LPARAM)ft525sd);
+        SendDlgItemMessage (hDlg, IDC_FLOPPYTYPE, CB_SETCURSEL, 0, 0);
+       for (i = 0; i < 4; i++) {
+           int f_type = floppybuttons[i][3];
+           SendDlgItemMessage (hDlg, f_type, CB_RESETCONTENT, 0, 0L);
+           SendDlgItemMessage (hDlg, f_type, CB_ADDSTRING, 0, (LPARAM)ftdis);
+           SendDlgItemMessage (hDlg, f_type, CB_ADDSTRING, 0, (LPARAM)ft35dd);
+           SendDlgItemMessage (hDlg, f_type, CB_ADDSTRING, 0, (LPARAM)ft35hd);
+           SendDlgItemMessage (hDlg, f_type, CB_ADDSTRING, 0, (LPARAM)ft525sd);
+       }
+    }
+    case WM_USER:
+       recursive++;
+       SetDlgItemText (hDlg, IDC_DF0TEXT, workprefs.df[0]);
+       SetDlgItemText (hDlg, IDC_DF1TEXT, workprefs.df[1]);
+       SetDlgItemText (hDlg, IDC_DF2TEXT, workprefs.df[2]);
+       SetDlgItemText (hDlg, IDC_DF3TEXT, workprefs.df[3]);
+       SendDlgItemMessage (hDlg, IDC_FLOPPYSPD, TBM_SETPOS, TRUE,
+           workprefs.floppy_speed ? exact_log2 ((workprefs.floppy_speed) / 100) + 1 : 0);
+       out_floppyspeed (hDlg);
+        addallfloppies (hDlg);
+       recursive--;
+       break;
+           
+    case WM_COMMAND:
+       if (recursive > 0)
+           break;
+       recursive++;
+       switch (wParam) 
+       {
+       case IDC_DF0WP:
+           floppysetwriteprotect (hDlg, 0, IsDlgButtonChecked (hDlg, IDC_DF0WP));
+           break;
+       case IDC_DF1WP:
+           floppysetwriteprotect (hDlg, 1, IsDlgButtonChecked (hDlg, IDC_DF1WP));
+           break;
+       case IDC_DF2WP:
+           floppysetwriteprotect (hDlg, 2, IsDlgButtonChecked (hDlg, IDC_DF2WP));
+           break;
+       case IDC_DF3WP:
+           floppysetwriteprotect (hDlg, 3, IsDlgButtonChecked (hDlg, IDC_DF3WP));
+           break;
+       case IDC_DF0:
+           DiskSelection (hDlg, wParam, 0, &workprefs, 0);
+           disk_insert (0, workprefs.df[0]);
+           addfloppytype (hDlg, 0);
+           break;
+       case IDC_DF1:
+           DiskSelection (hDlg, wParam, 0, &workprefs, 0);
+           disk_insert (1, workprefs.df[1]);
+           addfloppytype (hDlg, 1);
+           break;
+       case IDC_DF2:
+           DiskSelection (hDlg, wParam, 0, &workprefs, 0);
+           disk_insert (2, workprefs.df[2]);
+           addfloppytype (hDlg, 2);
+           break;
+       case IDC_DF3:
+           DiskSelection (hDlg, wParam, 0, &workprefs, 0);
+           disk_insert (3, workprefs.df[3]);
+           addfloppytype (hDlg, 3);
+           break;
+       case IDC_EJECT0:
+           disk_eject(0);
+           SetDlgItemText (hDlg, IDC_DF0TEXT, "");
+           workprefs.df[0][0] = 0;
+           addfloppytype (hDlg, 0);
+           break;
+       case IDC_EJECT1:
+           disk_eject(1);
+           SetDlgItemText (hDlg, IDC_DF1TEXT, "");
+           workprefs.df[1][0] = 0;
+           addfloppytype (hDlg, 1);
+           break;
+       case IDC_EJECT2:
+           disk_eject(2);
+           SetDlgItemText (hDlg, IDC_DF2TEXT, "");
+           workprefs.df[2][0] = 0;
+           addfloppytype (hDlg, 2);
+           break;
+       case IDC_EJECT3:
+           disk_eject(3);
+           SetDlgItemText (hDlg, IDC_DF3TEXT, "");
+           workprefs.df[3][0] = 0;
+           addfloppytype (hDlg, 3);
+           break;
+       case IDC_CREATE:
+           DiskSelection (hDlg, wParam, 1, &workprefs, 0);
+           break;
+       case IDC_CREATE_RAW:
+           DiskSelection( hDlg, wParam, 1, &workprefs, 0);
+           break;
+       }
+       getfloppytype (hDlg, 0);
+       getfloppytype (hDlg, 1);
+       getfloppytype (hDlg, 2);
+       getfloppytype (hDlg, 3);
+       getfloppyname (hDlg, 0);
+       getfloppyname (hDlg, 1);
+       getfloppyname (hDlg, 2);
+       getfloppyname (hDlg, 3);
+       recursive--;
+       break;
+
+    case WM_HSCROLL:
+       workprefs.floppy_speed = SendMessage( GetDlgItem( hDlg, IDC_FLOPPYSPD ), TBM_GETPOS, 0, 0 );
+       if (workprefs.floppy_speed > 0) {
+           workprefs.floppy_speed--;
+           workprefs.floppy_speed = 1 << workprefs.floppy_speed;
+           workprefs.floppy_speed *= 100;
+       }
+       out_floppyspeed (hDlg);
+       break;
+    }
+
+    strcpy (changed_prefs.df[0], workprefs.df[0]);
+    strcpy (changed_prefs.df[1], workprefs.df[1]);
+    strcpy (changed_prefs.df[2], workprefs.df[2]);
+    strcpy (changed_prefs.df[3], workprefs.df[3]);
+    return FALSE;
+}
+
+static BOOL CALLBACK DiskDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    static int recursive = 0;
+    static int entry;
+    char tmp[256];
+
+    switch (msg) 
+    {
+    case WM_INITDIALOG:
+    pages[DISK_ID] = hDlg;
+    currentpage = DISK_ID;
+    InitializeListView(hDlg);
+    SendMessage( GetDlgItem( hDlg, IDC_UP ), BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hMoveUp );
+    SendMessage( GetDlgItem( hDlg, IDC_DOWN ), BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hMoveDown );
+    entry = -1;
+    break;
+    case WM_COMMAND:
+    {
+       switch (wParam)
+       {
+           case IDC_DISKLISTREMOVE:
+               if (entry >= 0) {
+                   workprefs.dfxlist[entry][0] = 0;
+                   InitializeListView (hDlg);
+               }
+               break;
+           case IDC_UP:
+               if (entry > 0) {
+                   strcpy (tmp, workprefs.dfxlist[entry - 1]);
+                   strcpy (workprefs.dfxlist[entry - 1], workprefs.dfxlist[entry]);
+                   strcpy (workprefs.dfxlist[entry], tmp);
+                   InitializeListView (hDlg);
+                   entry--;
+                   ListView_SetItemState (cachedlist, entry,
+                       LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
+               }
+               break;
+           case IDC_DOWN:
+               if (entry < MAX_SPARE_DRIVES - 1) {
+                   strcpy (tmp, workprefs.dfxlist[entry + 1]);
+                   strcpy (workprefs.dfxlist[entry + 1], workprefs.dfxlist[entry]);
+                   strcpy (workprefs.dfxlist[entry], tmp);
+                   InitializeListView (hDlg);
+                   entry++;
+                   ListView_SetItemState (cachedlist, entry,
+                       LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
+               }
+               break;
+       }
+    }
+    case WM_NOTIFY:
+        if (((LPNMHDR) lParam)->idFrom == IDC_DISKLIST) 
+        {
+           int dblclick = 0, col;
+           HWND list;
+           NM_LISTVIEW *nmlistview;
+           nmlistview = (NM_LISTVIEW *) lParam;
+           cachedlist = list = nmlistview->hdr.hwndFrom;
+           switch (nmlistview->hdr.code) 
+           {
+               case NM_DBLCLK:
+               dblclick = 1;
+               /* fall-through */
+               case NM_CLICK:
+               entry = listview_entry_from_click (list, &col);
+               if (entry >= 0) {
+                   if (col == 2) {
+                       if (disk_swap (entry, col))
+                           InitializeListView (hDlg);
+                   } else if (col == 1) {
+                       char path[MAX_PATH];
+                       if (dblclick && DiskSelection (hDlg, -1, 0, &changed_prefs, path)) {
+                           strcpy (workprefs.dfxlist[entry], path);
+                           InitializeListView (hDlg);
+                       }
+                   }
+               }
+               break;
+           }
+       }
+    }
+    return FALSE;
+}
+
+static PRINTER_INFO_1 *pInfo = NULL;
+static DWORD dwEnumeratedPrinters = 0;
+#define MAX_PRINTERS 10
+#define MAX_SERIALS 8
+static char comports[MAX_SERIALS][8];
+
+static int joy0idc[] = {
+    IDC_PORT0_JOY0, IDC_PORT0_JOY1, IDC_PORT0_MOUSE, IDC_PORT0_KBDA, IDC_PORT0_KBDB, IDC_PORT0_KBDC
+};
+
+static int joy1idc[] = {
+    IDC_PORT1_JOY0, IDC_PORT1_JOY1, IDC_PORT1_MOUSE, IDC_PORT1_KBDA, IDC_PORT1_KBDB, IDC_PORT1_KBDC
+};
+
+static BOOL bNoMidiIn = FALSE;
+
+static void enable_for_portsdlg( HWND hDlg )
+{
+    int i, v;
+
+    v = workprefs.input_selected_setting > 0 ? FALSE : TRUE;
+    for( i = 0; i < 6; i++ )
+    {
+        EnableWindow( GetDlgItem( hDlg, joy0idc[i] ), v );
+        EnableWindow( GetDlgItem( hDlg, joy1idc[i] ), v );
+    }
+    EnableWindow (GetDlgItem (hDlg, IDC_SWAP), v);
+#if !defined (SERIAL_PORT)
+    EnableWindow( GetDlgItem( hDlg, IDC_MIDIOUTLIST), FALSE );
+    EnableWindow( GetDlgItem( hDlg, IDC_MIDIINLIST), FALSE );
+    EnableWindow( GetDlgItem( hDlg, IDC_SHARED), FALSE );
+    EnableWindow( GetDlgItem( hDlg, IDC_SER_CTSRTS), FALSE );
+    EnableWindow( GetDlgItem( hDlg, IDC_SERIAL_DIRECT), FALSE );
+    EnableWindow( GetDlgItem( hDlg, IDC_SERIAL), FALSE );
+#endif
+#if !defined (PARALLEL_PORT)
+    EnableWindow( GetDlgItem( hDlg, IDC_PRINTERLIST), FALSE );
+#endif
+}
+
+static void UpdatePortRadioButtons( HWND hDlg )
+{
+    int which_button1, which_button2;
+
+    enable_for_portsdlg( hDlg );
+       which_button1 = joy0idc[workprefs.jport0];
+       if (CheckRadioButton (hDlg, IDC_PORT0_JOY0, IDC_PORT0_KBDC, which_button1) == 0)
+           which_button1 = 0;
+    else
+    {
+        EnableWindow( GetDlgItem( hDlg, joy1idc[workprefs.jport0] ), FALSE );
+    }
+       which_button2 = joy1idc[workprefs.jport1];
+    if( workprefs.jport1 == workprefs.jport0 )
+    {
+        if( which_button2 == IDC_PORT1_KBDC )
+            which_button2 = IDC_PORT1_KBDB;
+        else
+            which_button2++;
+    }
+       if (CheckRadioButton (hDlg, IDC_PORT1_JOY0, IDC_PORT1_KBDC, which_button2) == 0)
+           which_button2 = 0;
+    else
+    {
+        EnableWindow( GetDlgItem( hDlg, joy0idc[ workprefs.jport1 ] ), FALSE );
+    }
+}
+
+static void values_from_portsdlg (HWND hDlg)
+{
+    int item;
+    char tmp[256];
+    /* 0 - joystick 0
+     * 1 - joystick 1
+     * 2 - mouse
+     * 3 - numpad
+     * 4 - cursor keys
+     * 5 - elsewhere
+     */
+    if (IsDlgButtonChecked (hDlg, IDC_PORT0_JOY0)) {
+           workprefs.jport0 = 0;
+    }
+    if (IsDlgButtonChecked (hDlg, IDC_PORT0_JOY1)) {
+           workprefs.jport0 = 1;
+    }
+    if (IsDlgButtonChecked (hDlg, IDC_PORT0_MOUSE))
+           workprefs.jport0 = 2;
+    if (IsDlgButtonChecked (hDlg, IDC_PORT0_KBDA))
+           workprefs.jport0 = 3;
+    if (IsDlgButtonChecked (hDlg, IDC_PORT0_KBDB))
+           workprefs.jport0 = 4;
+    if (IsDlgButtonChecked (hDlg, IDC_PORT0_KBDC))
+           workprefs.jport0 = 5;
+
+    if (IsDlgButtonChecked (hDlg, IDC_PORT1_JOY0)) {
+           workprefs.jport1 = 0;
+    }
+    if (IsDlgButtonChecked (hDlg, IDC_PORT1_JOY1)) {
+           workprefs.jport1 = 1;
+    }
+    if (IsDlgButtonChecked (hDlg, IDC_PORT1_MOUSE))
+           workprefs.jport1 = 2;
+    if (IsDlgButtonChecked (hDlg, IDC_PORT1_KBDA))
+           workprefs.jport1 = 3;
+    if (IsDlgButtonChecked (hDlg, IDC_PORT1_KBDB))
+           workprefs.jport1 = 4;
+    if (IsDlgButtonChecked (hDlg, IDC_PORT1_KBDC))
+           workprefs.jport1 = 5;
+
+    item = SendDlgItemMessage( hDlg, IDC_PRINTERLIST, CB_GETCURSEL, 0, 0L );
+    if( item != CB_ERR )
+    {
+       int got = 0;
+       strcpy (tmp, workprefs.prtname);
+       if (item > 0) {
+           item--;
+           if (item < dwEnumeratedPrinters) {
+               strcpy (workprefs.prtname, pInfo[item].pName);
+               got = 1;
+           } else {
+               int i;
+               item -= dwEnumeratedPrinters;
+               for (i = 0; i < 4; i++) {
+                   if ((paraport_mask & (1 << i)) && item == 0) {
+                       sprintf (workprefs.prtname, "LPT%d", i + 1);
+                       got = 1;
+                       break;
+                   }
+                   item--;
+               }
+           }
+       }
+       if (!got)
+           strcpy( workprefs.prtname, "none" );
+#ifdef PARALLEL_PORT
+       if (strcmp (workprefs.prtname, tmp))
+           closeprinter ();
+#endif
+    }
+
+    workprefs.win32_midioutdev = SendDlgItemMessage( hDlg, IDC_MIDIOUTLIST, CB_GETCURSEL, 0, 0 );
+    workprefs.win32_midioutdev--; /* selection zero is always 'default midi device', so we make it -1 */
+
+    if( bNoMidiIn )
+    {
+       workprefs.win32_midiindev = -1;
+    }
+    else
+    {
+       workprefs.win32_midiindev = SendDlgItemMessage( hDlg, IDC_MIDIINLIST, CB_GETCURSEL, 0, 0 );
+    }
+
+    item = SendDlgItemMessage (hDlg, IDC_SERIAL, CB_GETCURSEL, 0, 0L);
+    switch( item ) 
+    {
+       case 1:
+       case 2:
+       case 3:
+       case 4:
+       case 5:
+       case 6:
+       case 7:
+       case 8:
+           workprefs.use_serial = 1;
+           strcpy (workprefs.sername, comports[item - 1]);
+           EnableWindow( GetDlgItem( hDlg, IDC_MIDIOUTLIST ), TRUE );
+           EnableWindow( GetDlgItem( hDlg, IDC_MIDIINLIST ), TRUE );
+       break;
+
+       default:
+           workprefs.use_serial = 0;
+           strcpy( workprefs.sername, "none" );
+           EnableWindow( GetDlgItem( hDlg, IDC_MIDIOUTLIST ), FALSE );
+           EnableWindow( GetDlgItem( hDlg, IDC_MIDIINLIST ), FALSE );
+       break;
+    }
+    workprefs.serial_demand = 0;
+    if( IsDlgButtonChecked( hDlg, IDC_SHARED ) )
+        workprefs.serial_demand = 1;
+    workprefs.serial_hwctsrts = 0;
+    if( IsDlgButtonChecked( hDlg, IDC_SER_CTSRTS ) )
+        workprefs.serial_hwctsrts = 1;
+    workprefs.serial_direct = 0;
+    if( IsDlgButtonChecked( hDlg, IDC_SERIAL_DIRECT ) )
+        workprefs.serial_direct = 1;
+}
+
+static void values_to_portsdlg (HWND hDlg)
+{
+    LONG item_height, result = 0;
+    RECT rect;
+
+    if( strcmp (workprefs.prtname, "none"))
+    {
+       int i, got = 1;
+       char tmp[10];
+       result = SendDlgItemMessage( hDlg, IDC_PRINTERLIST, CB_FINDSTRINGEXACT, -1, (LPARAM)workprefs.prtname );
+       for (i = 0; i < 4; i++) {
+           sprintf (tmp, "LPT%d", i + 1);
+           if (!strcmp (tmp, workprefs.prtname)) {
+               got = 0;
+               if (paraport_mask & (1 << i))
+                   got = 1;
+               break;
+           }
+       }
+       if( result < 0 || got == 0)
+       {
+           // Warn the user that their printer-port selection is not valid on this machine
+           char szMessage[ MAX_PATH ];
+           WIN32GUI_LoadUIString( IDS_INVALIDPRTPORT, szMessage, MAX_PATH );
+           gui_message( szMessage );
+           
+           // Disable the invalid parallel-port selection
+           strcpy( workprefs.prtname, "none" );
+
+           result = 0;
+       }
+    }
+    SendDlgItemMessage( hDlg, IDC_PRINTERLIST, CB_SETCURSEL, result, 0 );
+    SendDlgItemMessage( hDlg, IDC_MIDIOUTLIST, CB_SETCURSEL, workprefs.win32_midioutdev + 1, 0 ); /* we +1 here because 1st entry is 'default' */
+    if( !bNoMidiIn && ( workprefs.win32_midiindev >= 0 ) )
+       SendDlgItemMessage( hDlg, IDC_MIDIINLIST, CB_SETCURSEL, workprefs.win32_midiindev, 0 );
+    else
+       SendDlgItemMessage( hDlg, IDC_MIDIINLIST, CB_SETCURSEL, 0, 0 );
+    
+    CheckDlgButton( hDlg, IDC_SHARED, workprefs.serial_demand );
+    CheckDlgButton( hDlg, IDC_SER_CTSRTS, workprefs.serial_hwctsrts );
+    CheckDlgButton( hDlg, IDC_SERIAL_DIRECT, workprefs.serial_direct );
+    
+    if( strcasecmp( workprefs.sername, "none") == 0 ) 
+    {
+       SendDlgItemMessage (hDlg, IDC_SERIAL, CB_SETCURSEL, 0, 0L);
+        workprefs.use_serial = 0;
+    }
+    else
+    {
+       int t = (workprefs.sername[0] == '\0' ? 0 : workprefs.sername[3] - '0');
+       int i, result = -1;
+       for (i = 0; i < MAX_SERIALS; i++) {
+           if (!strcmp (comports[i], workprefs.sername)) {
+               result = SendDlgItemMessage( hDlg, IDC_SERIAL, CB_SETCURSEL, i + 1, 0L );
+               break;
+           }
+       }
+       if( result < 0 )
+       {
+           if (t > 0) {
+               // Warn the user that their COM-port selection is not valid on this machine
+               char szMessage[ MAX_PATH ];
+               WIN32GUI_LoadUIString( IDS_INVALIDCOMPORT, szMessage, MAX_PATH );
+               gui_message( szMessage );
+
+               // Select "none" as the COM-port
+               SendDlgItemMessage( hDlg, IDC_SERIAL, CB_SETCURSEL, 0L, 0L );           
+           }
+           // Disable the chosen serial-port selection
+           strcpy( workprefs.sername, "none" );
+           workprefs.use_serial = 0;
+       }
+       else
+       {
+           workprefs.use_serial = 1;
+       }
+    }
+
+    if( workprefs.use_serial )
+    {
+       EnableWindow( GetDlgItem( hDlg, IDC_MIDIOUTLIST ), TRUE );
+       if( !bNoMidiIn )
+           EnableWindow( GetDlgItem( hDlg, IDC_MIDIINLIST ), TRUE );
+    }
+    else
+    {
+       EnableWindow( GetDlgItem( hDlg, IDC_MIDIOUTLIST ), FALSE );
+       EnableWindow( GetDlgItem( hDlg, IDC_MIDIINLIST ), FALSE );
+    }
+    /* Retrieve the height, in pixels, of a list item. */
+    item_height = SendDlgItemMessage (hDlg, IDC_SERIAL, CB_GETITEMHEIGHT, 0, 0L);
+    if (item_height != CB_ERR) {
+       /* Get actual box position and size. */
+       GetWindowRect (GetDlgItem (hDlg, IDC_SERIAL), &rect);
+       rect.bottom = (rect.top + item_height * 5
+           + SendDlgItemMessage (hDlg, IDC_SERIAL, CB_GETITEMHEIGHT, (WPARAM) - 1, 0L)
+           + item_height);
+       SetWindowPos (GetDlgItem (hDlg, IDC_SERIAL), 0, 0, 0, rect.right - rect.left,
+           rect.bottom - rect.top, SWP_NOMOVE | SWP_NOZORDER);
+    }
+}
+
+static void init_portsdlg( HWND hDlg )
+{
+    int port, portcnt, numdevs;
+    COMMCONFIG cc;
+    DWORD size = sizeof(COMMCONFIG);
+
+    MIDIOUTCAPS midiOutCaps;
+    MIDIINCAPS midiInCaps;
+
+    SendDlgItemMessage (hDlg, IDC_SERIAL, CB_RESETCONTENT, 0, 0L);
+    SendDlgItemMessage (hDlg, IDC_SERIAL, CB_ADDSTRING, 0, (LPARAM)szNone );
+    portcnt = 0;
+    for( port = 0; port < MAX_SERIALS; port++ )
+    {
+        sprintf( comports[portcnt], "COM%d", port );
+        if( GetDefaultCommConfig( comports[portcnt], &cc, &size ) )
+        {
+            SendDlgItemMessage( hDlg, IDC_SERIAL, CB_ADDSTRING, 0, (LPARAM)comports[portcnt++] );
+       }
+    }
+
+    SendDlgItemMessage (hDlg, IDC_PRINTERLIST, CB_RESETCONTENT, 0, 0L);
+    SendDlgItemMessage (hDlg, IDC_PRINTERLIST, CB_ADDSTRING, 0, (LPARAM)szNone );
+    if( !pInfo ) {
+       int flags = PRINTER_ENUM_LOCAL | (os_winnt ? PRINTER_ENUM_CONNECTIONS : 0);
+       DWORD needed = 0;
+       EnumPrinters( flags, NULL, 1, (LPBYTE)pInfo, 0, &needed, &dwEnumeratedPrinters );
+       if (needed > 0) {
+           DWORD size = needed;
+           pInfo = calloc(1, size);
+           dwEnumeratedPrinters = 0;
+           EnumPrinters( flags, NULL, 1, (LPBYTE)pInfo, size, &needed, &dwEnumeratedPrinters );
+       }
+       if (dwEnumeratedPrinters == 0) {
+           free (pInfo);
+           pInfo = 0;
+       }
+    }
+    if (pInfo) {
+        for( port = 0; port < (int)dwEnumeratedPrinters; port++ )
+           SendDlgItemMessage( hDlg, IDC_PRINTERLIST, CB_ADDSTRING, 0, (LPARAM)pInfo[port].pName );
+    } else {
+       EnableWindow( GetDlgItem( hDlg, IDC_PRINTERLIST ), FALSE );
+    }
+    if (paraport_mask) {
+       int mask = paraport_mask;
+       int i = 1;
+       while (mask) {
+           if (mask & 1) {
+               char tmp[30];
+               sprintf (tmp, "LPT%d", i);
+               SendDlgItemMessage (hDlg, IDC_PRINTERLIST, CB_ADDSTRING, 0, (LPARAM)tmp);
+           }
+           i++;
+           mask >>= 1;
+       }
+    }
+
+    if( ( numdevs = midiOutGetNumDevs() ) == 0 )
+    {
+       EnableWindow( GetDlgItem( hDlg, IDC_MIDIOUTLIST ), FALSE );
+    }
+    else
+    {
+       char szMidiOut[ MAX_PATH ];
+       WIN32GUI_LoadUIString( IDS_DEFAULTMIDIOUT, szMidiOut, MAX_PATH );
+        SendDlgItemMessage( hDlg, IDC_MIDIOUTLIST, CB_RESETCONTENT, 0, 0L );
+        SendDlgItemMessage( hDlg, IDC_MIDIOUTLIST, CB_ADDSTRING, 0, (LPARAM)szMidiOut );
+
+        for( port = 0; port < numdevs; port++ )
+        {
+            if( midiOutGetDevCaps( port, &midiOutCaps, sizeof( midiOutCaps ) ) == MMSYSERR_NOERROR )
+            {
+                SendDlgItemMessage( hDlg, IDC_MIDIOUTLIST, CB_ADDSTRING, 0, (LPARAM)midiOutCaps.szPname );
+            }
+        }
+    }
+
+    if( ( numdevs = midiInGetNumDevs() ) == 0 )
+    {
+       EnableWindow( GetDlgItem( hDlg, IDC_MIDIINLIST ), FALSE );
+       bNoMidiIn = TRUE;
+    }
+    else
+    {
+        SendDlgItemMessage( hDlg, IDC_MIDIINLIST, CB_RESETCONTENT, 0, 0L );
+
+        for( port = 0; port < numdevs; port++ )
+        {
+            if( midiInGetDevCaps( port, &midiInCaps, sizeof( midiInCaps ) ) == MMSYSERR_NOERROR )
+            {
+                SendDlgItemMessage( hDlg, IDC_MIDIINLIST, CB_ADDSTRING, 0, (LPARAM)midiInCaps.szPname );
+            }
+        }
+    }
+}
+
+/* Handle messages for the Joystick Settings page of our property-sheet */
+static BOOL CALLBACK PortsDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    static int recursive = 0;
+    int temp;
+
+    switch (msg) 
+    {
+    case WM_INITDIALOG:
+       pages[PORTS_ID] = hDlg;
+       currentpage = PORTS_ID;
+       init_portsdlg( hDlg );
+       enable_for_portsdlg( hDlg );
+       values_to_portsdlg ( hDlg);
+       break;      
+    case WM_USER:
+       recursive++;
+       enable_for_portsdlg( hDlg );
+       UpdatePortRadioButtons( hDlg );
+       recursive--;
+       return TRUE;
+
+    case WM_COMMAND:
+        if (recursive > 0)
+           break;
+       recursive++;
+       if( wParam == IDC_SWAP )
+       {
+           temp = workprefs.jport0;
+           workprefs.jport0 = workprefs.jport1;
+           workprefs.jport1 = temp;
+           UpdatePortRadioButtons( hDlg );
+       }
+       else
+       {
+           values_from_portsdlg (hDlg);
+           UpdatePortRadioButtons( hDlg );
+       }
+        inputdevice_updateconfig (&workprefs);
+       inputdevice_config_change ();
+        recursive--;
+       break;
+    }
+    return FALSE;
+}
+
+static char *eventnames[INPUTEVENT_END];
+
+static void values_to_inputdlg (HWND hDlg)
+{
+    SendDlgItemMessage( hDlg, IDC_INPUTTYPE, CB_SETCURSEL, workprefs.input_selected_setting, 0 );
+    SendDlgItemMessage( hDlg, IDC_INPUTDEVICE, CB_SETCURSEL, input_selected_device, 0 );
+    SetDlgItemInt( hDlg, IDC_INPUTDEADZONE, workprefs.input_joystick_deadzone, FALSE );
+    SetDlgItemInt( hDlg, IDC_INPUTAUTOFIRERATE, workprefs.input_autofire_framecnt, FALSE );
+    SetDlgItemInt( hDlg, IDC_INPUTSPEEDD, workprefs.input_joymouse_speed, FALSE );
+    SetDlgItemInt( hDlg, IDC_INPUTSPEEDA, workprefs.input_joymouse_multiplier, FALSE );
+    SetDlgItemInt( hDlg, IDC_INPUTSPEEDM, workprefs.input_mouse_speed, FALSE );
+    CheckDlgButton ( hDlg, IDC_INPUTDEVICEDISABLE, inputdevice_get_device_status (input_selected_device) ? BST_CHECKED : BST_UNCHECKED);
+}
+
+static void init_inputdlg_2( HWND hDlg )
+{
+    char name1[256], name2[256];
+    int cnt, index, af, aftmp;
+
+    if (input_selected_widget < 0) {
+       EnableWindow( GetDlgItem( hDlg, IDC_INPUTAMIGA), FALSE );
+    } else {
+       EnableWindow( GetDlgItem( hDlg, IDC_INPUTAMIGA), TRUE );
+    }
+    SendDlgItemMessage (hDlg, IDC_INPUTAMIGA, CB_RESETCONTENT, 0, 0L);
+    SendDlgItemMessage (hDlg, IDC_INPUTAMIGA, CB_ADDSTRING, 0, (LPARAM)szNone);
+    index = -1; af = 0;
+    if (input_selected_widget >= 0) {
+       inputdevice_get_mapped_name (input_selected_device, input_selected_widget, 0, name1, input_selected_sub_num);
+       cnt = 1;
+       while(inputdevice_iterate (input_selected_device, input_selected_widget, name2, &aftmp)) {
+           free (eventnames[cnt]);
+           eventnames[cnt] = strdup (name2);
+           if (name1 && !strcmp (name1, name2)) {
+               index = cnt;
+               af = aftmp;
+           }
+           cnt++;
+           SendDlgItemMessage (hDlg, IDC_INPUTAMIGA, CB_ADDSTRING, 0, (LPARAM)name2);
+       }
+       if (index >= 0) {
+           SendDlgItemMessage( hDlg, IDC_INPUTAMIGA, CB_SETCURSEL, index, 0 );
+           SendDlgItemMessage( hDlg, IDC_INPUTAMIGACNT, CB_SETCURSEL, input_selected_sub_num, 0 );
+       }
+    }
+}
+
+static void init_inputdlg( HWND hDlg )
+{
+    int i;
+    DWORD size = sizeof(COMMCONFIG);
+    char buf[100], txt[100];
+
+    SendDlgItemMessage (hDlg, IDC_INPUTTYPE, CB_RESETCONTENT, 0, 0L);
+    WIN32GUI_LoadUIString (IDS_INPUT_COMPATIBILITY, buf, sizeof (buf));
+    SendDlgItemMessage (hDlg, IDC_INPUTTYPE, CB_ADDSTRING, 0, (LPARAM)buf);
+    WIN32GUI_LoadUIString (IDS_INPUT_CUSTOM, buf, sizeof (buf));
+    for (i = 0; i < 4; i++) {
+       sprintf (txt, buf, i + 1);
+       SendDlgItemMessage (hDlg, IDC_INPUTTYPE, CB_ADDSTRING, 0, (LPARAM)txt);
+    }
+
+    SendDlgItemMessage (hDlg, IDC_INPUTCOPYFROM, CB_RESETCONTENT, 0, 0L);
+    WIN32GUI_LoadUIString (IDS_INPUT_COPY_DEFAULT, buf, sizeof (buf));
+    SendDlgItemMessage (hDlg, IDC_INPUTCOPYFROM, CB_ADDSTRING, 0, (LPARAM)buf);
+    WIN32GUI_LoadUIString (IDS_INPUT_COPY_CUSTOM, buf, sizeof (buf));
+    for (i = 0; i < 4; i++) {
+       sprintf (txt, buf, i + 1);
+       SendDlgItemMessage (hDlg, IDC_INPUTCOPYFROM, CB_ADDSTRING, 0, (LPARAM)txt);
+    }
+
+    SendDlgItemMessage (hDlg, IDC_INPUTAMIGACNT, CB_RESETCONTENT, 0, 0L);
+    for (i = 0; i < MAX_INPUT_SUB_EVENT; i++) {
+       sprintf (buf, "%d", i + 1);
+       SendDlgItemMessage (hDlg, IDC_INPUTAMIGACNT, CB_ADDSTRING, 0, (LPARAM)buf);
+    }
+    SendDlgItemMessage( hDlg, IDC_INPUTAMIGACNT, CB_SETCURSEL, input_selected_sub_num, 0 );
+
+    SendDlgItemMessage (hDlg, IDC_INPUTDEVICE, CB_RESETCONTENT, 0, 0L);
+    for (i = 0; i < inputdevice_get_device_total (IDTYPE_JOYSTICK); i++) {
+       SendDlgItemMessage (hDlg, IDC_INPUTDEVICE, CB_ADDSTRING, 0, (LPARAM)inputdevice_get_device_name(IDTYPE_JOYSTICK, i));
+    }
+    for (i = 0; i < inputdevice_get_device_total (IDTYPE_MOUSE); i++) {
+       SendDlgItemMessage (hDlg, IDC_INPUTDEVICE, CB_ADDSTRING, 0, (LPARAM)inputdevice_get_device_name(IDTYPE_MOUSE, i));
+    }
+    for (i = 0; i < inputdevice_get_device_total (IDTYPE_KEYBOARD); i++) {
+       SendDlgItemMessage (hDlg, IDC_INPUTDEVICE, CB_ADDSTRING, 0, (LPARAM)inputdevice_get_device_name(IDTYPE_KEYBOARD, i));
+    }
+    InitializeListView(hDlg);
+    init_inputdlg_2 (hDlg);
+    values_to_inputdlg (hDlg);
+}
+
+static void enable_for_inputdlg (HWND hDlg)
+{
+    int v = workprefs.input_selected_setting == 0 ? FALSE : TRUE;
+    EnableWindow (GetDlgItem (hDlg, IDC_INPUTLIST), v);
+    EnableWindow (GetDlgItem (hDlg, IDC_INPUTAMIGA), v);
+    EnableWindow (GetDlgItem (hDlg, IDC_INPUTAMIGACNT), v);
+    EnableWindow (GetDlgItem (hDlg, IDC_INPUTDEADZONE), TRUE);
+    EnableWindow (GetDlgItem (hDlg, IDC_INPUTAUTOFIRERATE), v);
+    EnableWindow (GetDlgItem (hDlg, IDC_INPUTSPEEDA), v);
+    EnableWindow (GetDlgItem (hDlg, IDC_INPUTSPEEDD), v);
+    EnableWindow (GetDlgItem (hDlg, IDC_INPUTSPEEDM), TRUE);
+    EnableWindow (GetDlgItem (hDlg, IDC_INPUTCOPY), v);
+    EnableWindow (GetDlgItem (hDlg, IDC_INPUTCOPYFROM), v);
+    EnableWindow (GetDlgItem (hDlg, IDC_INPUTSWAP), TRUE);
+    EnableWindow (GetDlgItem (hDlg, IDC_INPUTDEVICEDISABLE), workprefs.input_selected_setting == 0 ? FALSE : TRUE);
+}
+
+static void clearinputlistview (HWND hDlg)
+{
+    ListView_DeleteAllItems( GetDlgItem( hDlg, IDC_INPUTLIST ) );
+}
+
+static void values_from_inputdlg (HWND hDlg)
+{
+    int item, doselect = 0, v;
+    BOOL success;
+
+    v  = GetDlgItemInt( hDlg, IDC_INPUTDEADZONE, &success, FALSE );
+    if (success) {
+       currprefs.input_joystick_deadzone = workprefs.input_joystick_deadzone = v;
+       currprefs.input_joystick_deadzone = workprefs.input_joymouse_deadzone = v;
+    }
+    v  = GetDlgItemInt( hDlg, IDC_INPUTAUTOFIRERATE, &success, FALSE );
+    if (success)
+       currprefs.input_autofire_framecnt = workprefs.input_autofire_framecnt = v;
+    v  = GetDlgItemInt( hDlg, IDC_INPUTSPEEDD, &success, FALSE );
+    if (success)
+       currprefs.input_joymouse_speed = workprefs.input_joymouse_speed = v;
+    v  = GetDlgItemInt( hDlg, IDC_INPUTSPEEDA, &success, FALSE );
+    if (success)
+       currprefs.input_joymouse_multiplier = workprefs.input_joymouse_multiplier = v;
+    v  = GetDlgItemInt( hDlg, IDC_INPUTSPEEDM, &success, FALSE );
+    if (success)
+       currprefs.input_mouse_speed = workprefs.input_mouse_speed = v;
+
+    item = SendDlgItemMessage( hDlg, IDC_INPUTAMIGACNT, CB_GETCURSEL, 0, 0L );
+    if (item != CB_ERR && input_selected_sub_num != item) {
+       input_selected_sub_num = item;
+       doselect = 0;
+        init_inputdlg_2 (hDlg);
+       update_listview_input (hDlg);
+       return;
+    }
+
+    item = SendDlgItemMessage( hDlg, IDC_INPUTTYPE, CB_GETCURSEL, 0, 0L );
+    if( item != CB_ERR ) {
+       if (item != workprefs.input_selected_setting) {
+           workprefs.input_selected_setting = item;
+           input_selected_widget = -1;
+           inputdevice_updateconfig (&workprefs);
+           enable_for_inputdlg( hDlg );
+           InitializeListView (hDlg);
+           doselect = 1;
+       }
+    }
+    item = SendDlgItemMessage( hDlg, IDC_INPUTDEVICE, CB_GETCURSEL, 0, 0L );
+    if( item != CB_ERR ) {
+       if (item != input_selected_device) {
+           input_selected_device = item;
+           input_selected_widget = -1;
+           input_selected_event = -1;
+           InitializeListView (hDlg);
+           init_inputdlg_2 (hDlg);
+           values_to_inputdlg (hDlg);
+           doselect = 1;
+       }
+    }
+    item = SendDlgItemMessage( hDlg, IDC_INPUTAMIGA, CB_GETCURSEL, 0, 0L );
+    if( item != CB_ERR) {
+       input_selected_event = item;
+       doselect = 1;
+    }
+
+    if (doselect && input_selected_device >= 0 && input_selected_event >= 0) {
+       int flags;
+       inputdevice_get_mapped_name (input_selected_device, input_selected_widget,
+           &flags, 0, input_selected_sub_num);
+       inputdevice_set_mapping (input_selected_device, input_selected_widget,
+           eventnames[input_selected_event], (flags & IDEV_MAPPED_AUTOFIRE_SET) ? 1 : 0,
+           input_selected_sub_num);
+       update_listview_input (hDlg);
+        inputdevice_updateconfig (&workprefs);
+    }
+}
+
+static void input_swap (HWND hDlg)
+{
+    inputdevice_swap_ports (&workprefs, input_selected_device);
+    init_inputdlg (hDlg);
+}
+
+static void input_copy (HWND hDlg)
+{
+    int dst = workprefs.input_selected_setting;
+    int src = SendDlgItemMessage( hDlg, IDC_INPUTCOPYFROM, CB_GETCURSEL, 0, 0L );
+    if (src == CB_ERR)
+       return;
+    inputdevice_copy_single_config (&workprefs, src, workprefs.input_selected_setting, input_selected_device);
+    init_inputdlg (hDlg);
+}
+
+static void input_toggleautofire (void)
+{
+    int af, flags, event;
+    char name[256];
+    if (input_selected_device < 0 || input_selected_widget < 0)
+       return;
+    event = inputdevice_get_mapped_name (input_selected_device, input_selected_widget,
+       &flags, name, input_selected_sub_num);
+    if (event <= 0)
+       return;
+    af = (flags & IDEV_MAPPED_AUTOFIRE_SET) ? 0 : 1;
+    inputdevice_set_mapping (input_selected_device, input_selected_widget,
+       name, af, input_selected_sub_num);
+}
+
+static BOOL CALLBACK InputDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    char name_buf[MAX_PATH] = "", desc_buf[128] = "";
+    char *posn = NULL;
+    HWND list;
+    int dblclick = 0;
+    NM_LISTVIEW *nmlistview;
+    int items = 0, entry = 0;
+    static int recursive;
+
+    switch (msg) 
+    {
+    case WM_INITDIALOG:
+       pages[INPUT_ID] = hDlg;
+       currentpage = INPUT_ID;
+       inputdevice_updateconfig (&workprefs);
+       inputdevice_config_change ();
+       input_selected_widget = -1;
+       init_inputdlg( hDlg );
+           
+    case WM_USER:
+       recursive++;
+       enable_for_inputdlg (hDlg);
+       values_to_inputdlg (hDlg);
+       recursive--;
+       return TRUE;
+    case WM_COMMAND:
+        if (recursive)
+           break;
+       recursive++;
+       switch (wParam)
+       {
+           case IDC_INPUTCOPY:
+           input_copy (hDlg);
+           break;
+           case IDC_INPUTSWAP:
+           input_swap (hDlg);
+           break;
+           case IDC_INPUTDEVICEDISABLE:
+           inputdevice_set_device_status (input_selected_device, IsDlgButtonChecked( hDlg, IDC_INPUTDEVICEDISABLE) ? 1 : 0);
+           break;
+           default:
+           values_from_inputdlg (hDlg);
+           break;
+       }
+       enable_for_portsdlg (hDlg);
+       inputdevice_config_change ();
+       recursive--;
+       break;
+    case WM_NOTIFY:
+        if (((LPNMHDR) lParam)->idFrom == IDC_INPUTLIST) 
+        {
+           int row;
+           nmlistview = (NM_LISTVIEW *) lParam;
+           list = nmlistview->hdr.hwndFrom;
+           switch (nmlistview->hdr.code) 
+           {
+               case NM_DBLCLK:
+               dblclick = 1;
+               /* fall-through */
+               case NM_CLICK:
+               entry = listview_entry_from_click (list, &row);
+               if (entry >= 0) {
+                   int oldentry = input_selected_widget;
+                   input_selected_widget = entry;
+                   if (row == 2 && entry == oldentry)
+                       input_toggleautofire ();
+                   if (row == 3) {
+                       input_selected_sub_num++;
+                       if (input_selected_sub_num >= MAX_INPUT_SUB_EVENT)
+                           input_selected_sub_num = 0;
+                       SendDlgItemMessage( hDlg, IDC_INPUTAMIGACNT, CB_SETCURSEL, input_selected_sub_num, 0);
+                   }
+               } else {
+                   input_selected_widget = -1;
+               }
+               update_listview_input (hDlg);
+               init_inputdlg_2 (hDlg);
+           }
+       }
+    }
+    return FALSE;
+}
+
+static int scanlineratios[] = { 1,1,1,2,1,3, 2,1,2,2,2,3, 3,1,3,2,3,3, 0,0 };
+static int scanlineindexes[100];
+
+static void enable_for_hw3ddlg (HWND hDlg)
+{
+    int v = workprefs.gfx_filter ? TRUE : FALSE;
+    int vv = FALSE, vv2 = FALSE;
+    struct uae_filter *uf;
+    int i;
+
+    uf = &uaefilters[0];
+    i = 0;
+    while (uaefilters[i].name) {
+       if (workprefs.gfx_filter == uaefilters[i].type) {
+           uf = &uaefilters[i];
+           break;
+       }
+       i++;
+    }
+    if (v && (uf->x[0] || uf->x[1] || uf->x[2] || uf->x[3] || uf->x[4]))
+       vv = TRUE;
+    if (v && uf->x[0])
+       vv2 = TRUE;
+    EnableWindow (GetDlgItem (hDlg, IDC_OPENGLENABLE), TRUE);
+    EnableWindow (GetDlgItem (hDlg, IDC_OPENGLBITS), v);
+    CheckDlgButton( hDlg, IDC_OPENGLENABLE, v );
+    EnableWindow (GetDlgItem (hDlg, IDC_OPENGLHZ), vv2);
+    EnableWindow (GetDlgItem (hDlg, IDC_OPENGLVZ), vv2);
+    EnableWindow (GetDlgItem (hDlg, IDC_OPENGLHO), v);
+    EnableWindow (GetDlgItem (hDlg, IDC_OPENGLVO), v);
+    EnableWindow (GetDlgItem (hDlg, IDC_OPENGLSLR), vv2);
+    EnableWindow (GetDlgItem (hDlg, IDC_OPENGLSL), vv2);
+    EnableWindow (GetDlgItem (hDlg, IDC_OPENGLSL2), vv2);
+    EnableWindow (GetDlgItem (hDlg, IDC_OPENGLDEFAULT), v);
+    EnableWindow (GetDlgItem (hDlg, IDC_OPENGLFILTER), vv);
+}
+
+static void makefilter(char *s, int x, int flags)
+{
+    sprintf (s, "%dx", x);
+    if ((flags & (UAE_FILTER_MODE_16_16 | UAE_FILTER_MODE_32_32)) == (UAE_FILTER_MODE_16_16 | UAE_FILTER_MODE_32_32)) {
+       strcat (s, " (16bit/32bit)");
+       return;
+    }
+    if (flags & UAE_FILTER_MODE_16)
+       strcat (s, " (16bit)");
+    if (flags & UAE_FILTER_MODE_32)
+       strcat (s, " (32bit)");
+}
+
+static void values_to_hw3ddlg (HWND hDlg)
+{
+    char txt[100], tmp[100];
+    int i, j, nofilter, fltnum, modenum;
+    struct uae_filter *uf;
+
+    SendDlgItemMessage( hDlg, IDC_OPENGLHZ, TBM_SETRANGE, TRUE, MAKELONG (-99, +99) );
+    SendDlgItemMessage( hDlg, IDC_OPENGLHZ, TBM_SETPAGESIZE, 0, 1 );
+    SendDlgItemMessage( hDlg, IDC_OPENGLVZ, TBM_SETRANGE, TRUE, MAKELONG (-99, +99) );
+    SendDlgItemMessage( hDlg, IDC_OPENGLVZ, TBM_SETPAGESIZE, 0, 1 );
+    SendDlgItemMessage( hDlg, IDC_OPENGLHO, TBM_SETRANGE, TRUE, MAKELONG (-99, +99) );
+    SendDlgItemMessage( hDlg, IDC_OPENGLHO, TBM_SETPAGESIZE, 0, 1 );
+    SendDlgItemMessage( hDlg, IDC_OPENGLVO, TBM_SETRANGE, TRUE, MAKELONG (-50, +50) );
+    SendDlgItemMessage( hDlg, IDC_OPENGLVO, TBM_SETPAGESIZE, 0, 1 );
+    SendDlgItemMessage( hDlg, IDC_OPENGLSL, TBM_SETRANGE, TRUE, MAKELONG (   0, +100) );
+    SendDlgItemMessage( hDlg, IDC_OPENGLSL, TBM_SETPAGESIZE, 0, 10 );
+    SendDlgItemMessage( hDlg, IDC_OPENGLSL2, TBM_SETRANGE, TRUE, MAKELONG (   0, +100) );
+    SendDlgItemMessage( hDlg, IDC_OPENGLSL2, TBM_SETPAGESIZE, 0, 10 );
+
+    SendDlgItemMessage (hDlg, IDC_OPENGLBITS, CB_RESETCONTENT, 0, 0L);
+
+    uf = &uaefilters[0];
+    nofilter = 0; fltnum = 0;
+    i = 0; j = 0;
+    while (uaefilters[i].name) {
+       switch (uaefilters[i].type)
+       {
+#ifndef D3D
+           case UAE_FILTER_DIRECT3D:
+           nofilter = 1;
+           break;
+#endif
+#ifndef OPENGL
+           case UAE_FILTER_OPENGL:
+           nofilter = 1;
+           break;
+#endif
+           default:
+           nofilter = 0;
+           break;
+       }
+       if (nofilter == 0) {
+           SendDlgItemMessage (hDlg, IDC_OPENGLBITS, CB_ADDSTRING, 0, (LPARAM)uaefilters[i].name);
+           if (uaefilters[i].type == workprefs.gfx_filter) {
+               uf = &uaefilters[i];
+               fltnum = j;
+           }
+           j++;
+       }
+       i++;
+    }
+    SendDlgItemMessage( hDlg, IDC_OPENGLBITS, CB_SETCURSEL, fltnum, 0 );
+
+    SendDlgItemMessage (hDlg, IDC_OPENGLFILTER, CB_RESETCONTENT, 0, 0L);
+    if (uf->x[0]) {
+       WIN32GUI_LoadUIString (IDS_3D_NO_FILTER, txt, sizeof (txt));
+       sprintf (tmp, txt, 16);
+        SendDlgItemMessage (hDlg, IDC_OPENGLFILTER, CB_ADDSTRING, 0, (LPARAM)tmp);
+       WIN32GUI_LoadUIString (IDS_3D_BILINEAR, txt, sizeof (txt));
+       sprintf (tmp, txt, 16);
+       SendDlgItemMessage (hDlg, IDC_OPENGLFILTER, CB_ADDSTRING, 0, (LPARAM)tmp);
+       WIN32GUI_LoadUIString (IDS_3D_NO_FILTER, txt, sizeof (txt));
+       sprintf (tmp, txt, 32);
+        SendDlgItemMessage (hDlg, IDC_OPENGLFILTER, CB_ADDSTRING, 0, (LPARAM)tmp);
+       WIN32GUI_LoadUIString (IDS_3D_BILINEAR, txt, sizeof (txt));
+       sprintf (tmp, txt, 32);
+       SendDlgItemMessage (hDlg, IDC_OPENGLFILTER, CB_ADDSTRING, 0, (LPARAM)tmp);
+       modenum = 4;
+    } else {
+       workprefs.gfx_filter_horiz_zoom = 0;
+       workprefs.gfx_filter_vert_zoom = 0;
+       modenum = 0;
+       for (i = 1; i <= 4; i++) {
+           if (uf->x[i]) {
+               makefilter (tmp, i, uf->x[i]);
+               SendDlgItemMessage (hDlg, IDC_OPENGLFILTER, CB_ADDSTRING, 0, (LPARAM)tmp);
+               modenum++;
+           }
+       }
+    }
+    if (workprefs.gfx_filter_filtermode >= modenum)
+       workprefs.gfx_filter_filtermode = 0;
+    SendDlgItemMessage (hDlg, IDC_OPENGLFILTER, CB_SETCURSEL, workprefs.gfx_filter_filtermode, 0);
+
+    SendDlgItemMessage (hDlg, IDC_OPENGLSLR, CB_RESETCONTENT, 0, 0L);
+    i = j = 0;
+    while (scanlineratios[i * 2]) {
+       int sl = scanlineratios[i * 2] * 16 + scanlineratios[i * 2 + 1];
+       sprintf (txt, "%d:%d", scanlineratios[i * 2], scanlineratios[i * 2 + 1]);
+       if (workprefs.gfx_filter_scanlineratio == sl)
+           j = i;
+        SendDlgItemMessage (hDlg, IDC_OPENGLSLR, CB_ADDSTRING, 0, (LPARAM)txt);
+       scanlineindexes[i] = sl;
+       i++;
+    }
+    SendDlgItemMessage( hDlg, IDC_OPENGLSLR, CB_SETCURSEL, j, 0 );
+
+    SendDlgItemMessage( hDlg, IDC_OPENGLHZ, TBM_SETPOS, TRUE, workprefs.gfx_filter_horiz_zoom);
+    SendDlgItemMessage( hDlg, IDC_OPENGLVZ, TBM_SETPOS, TRUE, workprefs.gfx_filter_vert_zoom);
+    SendDlgItemMessage( hDlg, IDC_OPENGLHO, TBM_SETPOS, TRUE, workprefs.gfx_filter_horiz_offset);
+    SendDlgItemMessage( hDlg, IDC_OPENGLVO, TBM_SETPOS, TRUE, workprefs.gfx_filter_vert_offset);
+    SendDlgItemMessage( hDlg, IDC_OPENGLSL, TBM_SETPOS, TRUE, workprefs.gfx_filter_scanlines);
+    SendDlgItemMessage( hDlg, IDC_OPENGLSL2, TBM_SETPOS, TRUE, workprefs.gfx_filter_scanlinelevel);
+    SetDlgItemInt( hDlg, IDC_OPENGLHZV, workprefs.gfx_filter_horiz_zoom, TRUE );
+    SetDlgItemInt( hDlg, IDC_OPENGLVZV, workprefs.gfx_filter_vert_zoom, TRUE );
+    SetDlgItemInt( hDlg, IDC_OPENGLHOV, workprefs.gfx_filter_horiz_offset, TRUE );
+    SetDlgItemInt( hDlg, IDC_OPENGLVOV, workprefs.gfx_filter_vert_offset, TRUE );
+    SetDlgItemInt( hDlg, IDC_OPENGLSLV, workprefs.gfx_filter_scanlines, TRUE );
+    SetDlgItemInt( hDlg, IDC_OPENGLSL2V, workprefs.gfx_filter_scanlinelevel, TRUE );
+}
+
+static void values_from_hw3ddlg (HWND hDlg)
+{
+}
+
+static BOOL CALLBACK hw3dDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    static int recursive;
+    int item;
+
+    switch (msg) 
+    {
+    case WM_INITDIALOG:
+       pages[HW3D_ID] = hDlg;
+       currentpage = HW3D_ID;
+       enable_for_hw3ddlg (hDlg);
+           
+    case WM_USER:
+       recursive++;
+       enable_for_hw3ddlg( hDlg );
+       values_to_hw3ddlg (hDlg);
+       recursive--;
+       return TRUE;
+    case WM_COMMAND:
+       if (wParam == IDC_OPENGLDEFAULT) {
+           currprefs.gfx_filter_horiz_zoom = workprefs.gfx_filter_horiz_zoom = 0;
+           currprefs.gfx_filter_vert_zoom = workprefs.gfx_filter_vert_zoom = 0;
+           currprefs.gfx_filter_horiz_offset = workprefs.gfx_filter_horiz_offset = 0;
+           currprefs.gfx_filter_vert_offset = workprefs.gfx_filter_vert_offset = 0;
+           values_to_hw3ddlg (hDlg);
+       }
+       item = SendDlgItemMessage( hDlg, IDC_OPENGLSLR, CB_GETCURSEL, 0, 0L );
+       if (item != CB_ERR)
+           currprefs.gfx_filter_scanlineratio = workprefs.gfx_filter_scanlineratio = scanlineindexes[item];
+       item = SendDlgItemMessage( hDlg, IDC_OPENGLMODE, CB_GETCURSEL, 0, 0L );
+       if (item != CB_ERR) {
+           int of = workprefs.gfx_filter;
+           int off = workprefs.gfx_filter_filtermode;
+           workprefs.gfx_filter = 0;
+           if (IsDlgButtonChecked( hDlg, IDC_OPENGLENABLE)) {
+               workprefs.gfx_filter = uaefilters[item].type;
+               item = SendDlgItemMessage( hDlg, IDC_OPENGLFILTER, CB_GETCURSEL, 0, 0L );
+               if (item != CB_ERR)
+                   workprefs.gfx_filter_filtermode = item;
+               if (of != workprefs.gfx_filter || off != workprefs.gfx_filter_filtermode) {
+                   values_to_hw3ddlg (hDlg);
+                   enable_for_hw3ddlg (hDlg);
+                   hw3d_changed = 1;
+               }
+           } else {
+               enable_for_hw3ddlg (hDlg);
+           }
+       }
+       updatedisplayarea ();
+       break;
+    case WM_HSCROLL:
+       currprefs.gfx_filter_horiz_zoom = workprefs.gfx_filter_horiz_zoom = SendMessage( GetDlgItem( hDlg, IDC_OPENGLHZ ), TBM_GETPOS, 0, 0 );
+       currprefs.gfx_filter_vert_zoom = workprefs.gfx_filter_vert_zoom = SendMessage( GetDlgItem( hDlg, IDC_OPENGLVZ ), TBM_GETPOS, 0, 0 );
+       currprefs.gfx_filter_horiz_offset = workprefs.gfx_filter_horiz_offset = SendMessage( GetDlgItem( hDlg, IDC_OPENGLHO ), TBM_GETPOS, 0, 0 );
+       currprefs.gfx_filter_vert_offset = workprefs.gfx_filter_vert_offset = SendMessage( GetDlgItem( hDlg, IDC_OPENGLVO ), TBM_GETPOS, 0, 0 );
+       currprefs.gfx_filter_scanlines = workprefs.gfx_filter_scanlines = SendMessage( GetDlgItem( hDlg, IDC_OPENGLSL ), TBM_GETPOS, 0, 0 );
+       currprefs.gfx_filter_scanlinelevel = workprefs.gfx_filter_scanlinelevel = SendMessage( GetDlgItem( hDlg, IDC_OPENGLSL2 ), TBM_GETPOS, 0, 0 );
+       SetDlgItemInt( hDlg, IDC_OPENGLHZV, workprefs.gfx_filter_horiz_zoom, TRUE );
+       SetDlgItemInt( hDlg, IDC_OPENGLVZV, workprefs.gfx_filter_vert_zoom, TRUE );
+       SetDlgItemInt( hDlg, IDC_OPENGLHOV, workprefs.gfx_filter_horiz_offset, TRUE );
+        SetDlgItemInt( hDlg, IDC_OPENGLVOV, workprefs.gfx_filter_vert_offset, TRUE );
+        SetDlgItemInt( hDlg, IDC_OPENGLSLV, workprefs.gfx_filter_scanlines, TRUE );
+       SetDlgItemInt( hDlg, IDC_OPENGLSL2V, workprefs.gfx_filter_scanlinelevel, TRUE );
+       updatedisplayarea ();
+       WIN32GFX_WindowMove ();
+       break;
+    }
+    return FALSE;
+}
+
+#ifdef AVIOUTPUT
+static void values_to_avioutputdlg(HWND hDlg)
+{
+       char tmpstr[256];
+       
+        updatewinfsmode (&workprefs);
+       SetDlgItemText(hDlg, IDC_AVIOUTPUT_FILETEXT, avioutput_filename);
+       
+       sprintf(tmpstr, "%d fps", avioutput_fps);
+       SendMessage(GetDlgItem(hDlg, IDC_AVIOUTPUT_FPS_STATIC), WM_SETTEXT, (WPARAM) 0, (LPARAM) tmpstr);
+       
+       sprintf(tmpstr, "Actual: %d x %d", workprefs.gfx_width, workprefs.gfx_height);
+       SendMessage(GetDlgItem(hDlg, IDC_AVIOUTPUT_DIMENSIONS_STATIC), WM_SETTEXT, (WPARAM) 0, (LPARAM) tmpstr);
+       
+       switch(avioutput_fps)
+       {
+       case VBLANK_HZ_PAL:
+               CheckRadioButton(hDlg, IDC_AVIOUTPUT_PAL, IDC_AVIOUTPUT_NTSC, IDC_AVIOUTPUT_PAL);
+               break;
+               
+       case VBLANK_HZ_NTSC:
+               CheckRadioButton(hDlg, IDC_AVIOUTPUT_PAL, IDC_AVIOUTPUT_NTSC, IDC_AVIOUTPUT_NTSC);
+               break;
+               
+       default:
+               CheckDlgButton(hDlg, IDC_AVIOUTPUT_PAL, BST_UNCHECKED);
+               CheckDlgButton(hDlg, IDC_AVIOUTPUT_NTSC, BST_UNCHECKED);
+               break;
+       }
+       
+        CheckDlgButton (hDlg, IDC_AVIOUTPUT_FRAMELIMITER, avioutput_framelimiter ? FALSE : TRUE);
+        CheckDlgButton (hDlg, IDC_AVIOUTPUT_ACTIVATED, avioutput_requested ? BST_CHECKED : BST_UNCHECKED);
+}
+
+static void values_from_avioutputdlg(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+       int tmp;
+
+        updatewinfsmode (&workprefs);
+       tmp = SendMessage(GetDlgItem(hDlg, IDC_AVIOUTPUT_FPS), TBM_GETPOS, 0, 0);
+       if (tmp < 1)
+           tmp = 1;
+       if (tmp != avioutput_fps) {
+           avioutput_fps = tmp;
+           AVIOutput_Restart ();
+       }
+       avioutput_framelimiter = IsDlgButtonChecked (hDlg, IDC_AVIOUTPUT_FRAMELIMITER) ? 0 : 1;
+}
+
+static char aviout_videoc[200], aviout_audioc[200];
+
+static void enable_for_avioutputdlg(HWND hDlg)
+{
+
+        EnableWindow(GetDlgItem(hDlg, IDC_SCREENSHOT), full_property_sheet ? FALSE : TRUE);
+
+       EnableWindow(GetDlgItem(hDlg, IDC_AVIOUTPUT_PAL), TRUE);
+       EnableWindow(GetDlgItem(hDlg, IDC_AVIOUTPUT_NTSC), TRUE);
+       EnableWindow(GetDlgItem(hDlg, IDC_AVIOUTPUT_FPS), TRUE);
+       EnableWindow(GetDlgItem(hDlg, IDC_AVIOUTPUT_FILE), TRUE);
+        CheckDlgButton (hDlg, IDC_AVIOUTPUT_FRAMELIMITER, avioutput_framelimiter ? FALSE : TRUE);
+               
+               if(workprefs.produce_sound < 2)
+               {
+                       EnableWindow(GetDlgItem(hDlg, IDC_AVIOUTPUT_AUDIO), FALSE);
+                       EnableWindow(GetDlgItem(hDlg, IDC_AVIOUTPUT_AUDIO_STATIC), FALSE);
+                       avioutput_audio = 0;
+               }
+               else
+               {
+                       EnableWindow(GetDlgItem(hDlg, IDC_AVIOUTPUT_AUDIO), TRUE);
+                       EnableWindow(GetDlgItem(hDlg, IDC_AVIOUTPUT_AUDIO_STATIC), TRUE);
+                       
+               }
+               
+               if(!avioutput_audio)
+               {
+                       CheckDlgButton(hDlg, IDC_AVIOUTPUT_AUDIO, BST_UNCHECKED);
+                       WIN32GUI_LoadUIString (IDS_AVIOUTPUT_NOCODEC, aviout_audioc, sizeof (aviout_audioc));
+               }
+               SetWindowText(GetDlgItem(hDlg, IDC_AVIOUTPUT_AUDIO_STATIC), aviout_audioc);
+               
+               if(!avioutput_video)
+               {
+                       CheckDlgButton(hDlg, IDC_AVIOUTPUT_VIDEO, BST_UNCHECKED);
+                       WIN32GUI_LoadUIString (IDS_AVIOUTPUT_NOCODEC, aviout_videoc, sizeof (aviout_videoc));
+               }
+               SetWindowText(GetDlgItem(hDlg, IDC_AVIOUTPUT_VIDEO_STATIC), aviout_videoc);
+
+}
+
+static BOOL CALLBACK AVIOutputDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+       static int recursive = 0;
+       
+       switch(msg)
+       {
+       case WM_INITDIALOG:
+               pages[AVIOUTPUT_ID] = hDlg;
+               currentpage = AVIOUTPUT_ID;
+               enable_for_avioutputdlg(hDlg);
+               SendDlgItemMessage(hDlg, IDC_AVIOUTPUT_FPS, TBM_SETRANGE, TRUE, MAKELONG(1, VBLANK_HZ_NTSC));
+               SendDlgItemMessage(hDlg, IDC_AVIOUTPUT_FPS, TBM_SETPOS, TRUE, VBLANK_HZ_PAL);
+               SendMessage(hDlg, WM_HSCROLL, (WPARAM) NULL, (LPARAM) NULL);
+               
+       case WM_USER:
+               recursive++;
+               
+               values_to_avioutputdlg(hDlg);
+               enable_for_avioutputdlg(hDlg);
+               
+               recursive--;
+               return TRUE;
+               
+       case WM_HSCROLL:
+               {
+                       recursive++;
+                       
+                       values_from_avioutputdlg(hDlg, msg, wParam, lParam);
+                       values_to_avioutputdlg(hDlg);
+                       enable_for_avioutputdlg(hDlg);
+                       
+                       recursive--;
+                       
+                       return TRUE;
+               }
+               
+               
+       case WM_COMMAND:
+               if(recursive > 0)
+                       break;
+               
+               recursive++;
+               
+               switch(wParam)
+               {
+               case IDC_AVIOUTPUT_ACTIVATED:
+                   avioutput_requested = !avioutput_requested;
+                   SendMessage(hDlg, WM_HSCROLL, (WPARAM) NULL, (LPARAM) NULL);
+                   if (!avioutput_requested)
+                       AVIOutput_End ();
+                   break;
+
+               case IDC_SCREENSHOT:
+                       screenshot(1);
+                       break;
+                       
+               case IDC_AVIOUTPUT_PAL:
+                       SendDlgItemMessage(hDlg, IDC_AVIOUTPUT_FPS, TBM_SETPOS, TRUE, VBLANK_HZ_PAL);
+                       SendMessage(hDlg, WM_HSCROLL, (WPARAM) NULL, (LPARAM) NULL);
+                       break;
+                       
+               case IDC_AVIOUTPUT_NTSC:
+                       SendDlgItemMessage(hDlg, IDC_AVIOUTPUT_FPS, TBM_SETPOS, TRUE, VBLANK_HZ_NTSC);
+                       SendMessage(hDlg, WM_HSCROLL, (WPARAM) NULL, (LPARAM) NULL);
+                       break;
+                       
+               case IDC_AVIOUTPUT_AUDIO:
+                       {
+                               if (avioutput_enabled)
+                                   AVIOutput_End ();
+                               if(IsDlgButtonChecked(hDlg, IDC_AVIOUTPUT_AUDIO) == BST_CHECKED)
+                               {
+                                       LPSTR string;
+                                       
+                                       aviout_audioc[0] = 0;
+                                       if(string = AVIOutput_ChooseAudioCodec(hDlg))
+                                       {
+                                               avioutput_audio = AVIAUDIO_AVI;
+                                               strcpy (aviout_audioc, string);
+                                               SetWindowText(GetDlgItem(hDlg, IDC_AVIOUTPUT_AUDIO_STATIC), string);
+                                       }
+                                       else
+                                               avioutput_audio = 0;
+                               }
+                               else
+                                       avioutput_audio = 0;
+                               
+                               break;
+                       }
+                       
+               case IDC_AVIOUTPUT_VIDEO:
+                       {
+                               if (avioutput_enabled)
+                                   AVIOutput_End ();
+                               if(IsDlgButtonChecked(hDlg, IDC_AVIOUTPUT_VIDEO) == BST_CHECKED)
+                               {
+                                       LPSTR string;
+                                       aviout_videoc[0] = 0;
+                                       if(string = AVIOutput_ChooseVideoCodec(hDlg))
+                                       {
+                                               avioutput_video = 1;
+                                               strcpy (aviout_videoc, string);
+                                               SetWindowText(GetDlgItem(hDlg, IDC_AVIOUTPUT_VIDEO_STATIC), string);
+                                       }
+                                       else
+                                               avioutput_video = 0;
+                               }
+                               else
+                                       avioutput_video = 0;
+                               
+                               break;
+                       }
+                       
+               case IDC_AVIOUTPUT_FILE:
+                       {
+                               OPENFILENAME ofn;
+                               
+                               ZeroMemory(&ofn, sizeof(OPENFILENAME));
+                               ofn.lStructSize = sizeof(OPENFILENAME);
+                               ofn.hwndOwner = hDlg;
+                               ofn.hInstance = hInst;
+                               ofn.Flags = OFN_EXTENSIONDIFFERENT | OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR;
+                               ofn.lpstrCustomFilter = NULL;
+                               ofn.nMaxCustFilter = 0;
+                               ofn.nFilterIndex = 0;
+                               ofn.lpstrFile = avioutput_filename;
+                               ofn.nMaxFile = MAX_PATH;
+                               ofn.lpstrFileTitle = NULL;
+                               ofn.nMaxFileTitle = 0;
+                               ofn.lpstrInitialDir = NULL;
+                               ofn.lpfnHook = NULL;
+                               ofn.lpTemplateName = NULL;
+                               ofn.lCustData = 0;
+                               ofn.lpstrFilter = "Video Clip (*.avi)\0*.avi\0Wave Sound (*.wav)\0";
+                               
+                               if(!GetSaveFileName(&ofn))
+                                       break;
+                               if (ofn.nFilterIndex == 2) {
+                                   avioutput_audio = AVIAUDIO_WAV;
+                                   SetWindowText(GetDlgItem(hDlg, IDC_AVIOUTPUT_AUDIO_STATIC), "Wave (internal)");
+                                   if (strlen (avioutput_filename) > 4 && !stricmp (avioutput_filename + strlen (avioutput_filename) - 4, ".avi"))
+                                       strcpy (avioutput_filename + strlen (avioutput_filename) - 4, ".wav");
+                               }
+                               break;
+                       }
+               }
+               
+               values_from_avioutputdlg(hDlg, msg, wParam, lParam);
+               values_to_avioutputdlg(hDlg);
+               enable_for_avioutputdlg(hDlg);
+               
+               recursive--;
+               
+               return TRUE;
+       }
+       return FALSE;
+}
+#endif
+
+struct GUIPAGE {
+    PROPSHEETPAGE pp;
+    HTREEITEM tv;
+    int himg;
+    int idx;
+    char *help;
+};
+
+static struct GUIPAGE ppage[MAX_C_PAGES];
+#define PANEL_X 174
+#define PANEL_Y 12
+#define PANEL_WIDTH 456
+#define PANEL_HEIGHT 396
+
+static HWND updatePanel (HWND hDlg, int id)
+{
+    static HWND chwnd;
+    RECT r1c, r1w, r2c, r2w, r3c, r3w;
+    int w, h, pw, ph, x , y;
+
+    if (chwnd != NULL) {
+       ShowWindow (chwnd, FALSE);
+       DestroyWindow (chwnd);
+    }
+    if (id < 0) {
+       if (!isfullscreen ()) {
+           RECT r;
+           LONG left, top;
+           GetWindowRect (hDlg, &r);
+           left = r.left;
+           top = r.top;
+           RegSetValueEx (hWinUAEKey, "xPosGUI", 0, REG_DWORD, (LPBYTE)&left, sizeof(LONG));
+           RegSetValueEx (hWinUAEKey, "yPosGUI", 0, REG_DWORD, (LPBYTE)&top, sizeof(LONG));
+       }
+       EnableWindow (GetDlgItem (hDlg, IDHELP), FALSE);
+       return NULL;
+    }
+    GetWindowRect (GetDlgItem (hDlg, IDC_PANEL_FRAME), &r1w);
+    GetClientRect (GetDlgItem (hDlg, IDC_PANEL_FRAME), &r1c);
+    GetWindowRect (hDlg, &r2w);
+    GetClientRect (hDlg, &r2c);
+    chwnd = CreateDialogParam (hInst, ppage[id].pp.pszTemplate, hDlg, ppage[id].pp.pfnDlgProc, id);
+    GetWindowRect (hDlg, &r3w);
+    GetClientRect (chwnd, &r3c);
+    x = r1w.left - r2w.left;
+    y = r1w.top - r2w.top;
+    w = r3c.right - r3c.left + 1;
+    h = r3c.bottom - r3c.top + 1;
+    pw = r1w.right - r1w.left + 1;
+    ph = r1w.bottom - r1w.top + 1;
+    SetWindowPos (chwnd, HWND_TOP, 0, 0, 0, 0,
+       SWP_NOSIZE | SWP_NOOWNERZORDER);
+    GetWindowRect (chwnd, &r3w);
+    GetClientRect (chwnd, &r3c);
+    x -= r3w.left - r2w.left - 1;
+    y -= r3w.top - r2w.top - 1;
+    SetWindowPos (chwnd, HWND_TOP, x + (pw - w) / 2, y + (ph - h) / 2, 0, 0,
+       SWP_NOSIZE | SWP_NOOWNERZORDER);
+    ShowWindow (chwnd, TRUE);
+    EnableWindow (GetDlgItem (hDlg, IDHELP), pHtmlHelp && ppage[currentpage].help ? TRUE : FALSE);
+    return chwnd;
+}
+
+static HTREEITEM CreateFolderNode (HWND TVhDlg, int nameid, HTREEITEM parent, int nodeid, int sub)
+{
+    TVINSERTSTRUCT is;
+    char txt[100];
+
+    memset (&is, 0, sizeof (is));
+    is.hInsertAfter = TVI_LAST;
+    is.hParent = parent;
+    is.itemex.mask = TVIF_TEXT | TVIF_PARAM | TVIF_STATE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+    WIN32GUI_LoadUIString (nameid, txt, sizeof (txt));
+    is.itemex.pszText = txt;
+    is.itemex.lParam = (LPARAM)(nodeid | (sub << 16));
+    is.itemex.iImage = C_PAGES;
+    is.itemex.iSelectedImage = C_PAGES;
+    is.itemex.state = TVIS_BOLD | TVIS_EXPANDED;
+    is.itemex.stateMask = TVIS_BOLD | TVIS_EXPANDED;
+    return TreeView_InsertItem (TVhDlg, &is);
+}
+
+static void CreateNode (HWND TVhDlg, int page, HTREEITEM parent)
+{
+    TVINSERTSTRUCT is;
+    struct GUIPAGE *p;
+
+    if (page < 0)
+       return;
+    p = &ppage[page];
+    memset (&is, 0, sizeof (is));
+    is.hInsertAfter = TVI_LAST;
+    is.hParent = parent;
+    is.itemex.mask = TVIF_TEXT | TVIF_PARAM | TVIF_STATE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+    is.itemex.pszText = p->pp.pszTitle;
+    is.itemex.lParam = (LPARAM)p->idx;
+    is.itemex.iImage = p->himg;
+    is.itemex.iSelectedImage = is.itemex.iImage;
+    p->tv = TreeView_InsertItem (TVhDlg, &is);
+}
+#define CN(page) CreateNode(TVhDlg, page, p);
+
+static void createTreeView (HWND hDlg, int currentpage)
+{
+    HWND TVhDlg;
+    int i;
+    HIMAGELIST himl;
+    HTREEITEM p, root;
+
+    himl = ImageList_Create (16, 16, ILC_COLOR8 | ILC_MASK, C_PAGES + 1, 0);
+    if (himl) {
+       HICON icon;
+       for (i = 0; i < C_PAGES; i++) {
+           icon = LoadIcon (hInst, (LPCSTR)ppage[i].pp.pszIcon);
+           ppage[i].himg = ImageList_AddIcon (himl, icon);
+       }
+        icon = LoadIcon (hInst, MAKEINTRESOURCE (IDI_ROOT));
+        ImageList_AddIcon (himl, icon);
+    }
+    TVhDlg = GetDlgItem(hDlg, IDC_PANELTREE);
+    TreeView_SetImageList (TVhDlg, himl, TVSIL_NORMAL);
+
+    p = root = CreateFolderNode (TVhDlg, IDS_TREEVIEW_SETTINGS, NULL, ABOUT_ID, 0);
+    CN(ABOUT_ID);
+    CN(LOADSAVE_ID);
+
+    p = CreateFolderNode (TVhDlg, IDS_TREEVIEW_HARDWARE, root, LOADSAVE_ID, CONFIG_TYPE_HARDWARE);
+    CN(CPU_ID);
+    CN(CHIPSET_ID);
+    CN(KICKSTART_ID);
+    CN(MEMORY_ID);
+    CN(FLOPPY_ID);
+    CN(HARDDISK_ID);
+
+    p = CreateFolderNode (TVhDlg, IDS_TREEVIEW_HOST, root, LOADSAVE_ID, CONFIG_TYPE_HOST);
+    CN(DISPLAY_ID);
+    CN(SOUND_ID);
+    CN(PORTS_ID);
+    CN(INPUT_ID);
+    CN(AVIOUTPUT_ID);
+    CN(HW3D_ID);
+    CN(DISK_ID);
+    CN(MISC1_ID);
+    CN(MISC2_ID);
+
+    TreeView_SelectItem (TVhDlg, ppage[currentpage].tv);
+}
+
+static void centerWindow (HWND hDlg)
+{
+    RECT rc, rcDlg, rcOwner;
+    HWND owner = GetParent(hDlg);
+    LONG x = 0, y = 0;
+
+    if (owner == NULL)
+       owner = GetDesktopWindow();
+    if (!isfullscreen ()) {
+        DWORD regkeytype;
+       DWORD regkeysize = sizeof(LONG);
+        if (RegQueryValueEx (hWinUAEKey, "xPosGUI", 0, &regkeytype, (LPBYTE)&x, &regkeysize) != ERROR_SUCCESS)
+           x = 0;
+        if (RegQueryValueEx (hWinUAEKey, "yPosGUI", 0, &regkeytype, (LPBYTE)&y, &regkeysize) != ERROR_SUCCESS)
+           y = 0;
+    } else {
+       GetWindowRect (owner, &rcOwner);
+       GetWindowRect (hDlg, &rcDlg);
+       CopyRect (&rc, &rcOwner);
+       OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top); 
+       OffsetRect(&rc, -rc.left, -rc.top); 
+       OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom);
+       x = rcOwner.left + (rc.right / 2);
+       y = rcOwner.top + (rc.bottom / 2);
+    }
+    SetForegroundWindow (hDlg);
+    SetWindowPos (hDlg,  HWND_TOP, x, y, 0, 0, SWP_NOSIZE);
+}
+
+int dragdrop (HWND hDlg, HDROP hd, struct uae_prefs *prefs, int currentpage)
+{
+    int cnt, i, drv, list;
+    char file[MAX_PATH];
+    POINT pt;
+    int ret = 0;
+
+    DragQueryPoint (hd, &pt);
+    cnt = DragQueryFile (hd, 0xffffffff, NULL, 0);
+    if (!cnt)
+       return 0;
+    drv = 0;
+    for (i = 0; i < cnt; i++) {
+       struct zfile *f;
+       DragQueryFile (hd, i, file, sizeof (file));
+       f = zfile_fopen (file, "rb");
+       if (f) {
+           int type = zfile_gettype (f);
+           switch (type)
+           {
+               case  ZFILE_DISKIMAGE:
+                   if (currentpage == DISK_ID) {
+                       list = 0;
+                       while (list < MAX_SPARE_DRIVES) {
+                           if (!strcasecmp (prefs->dfxlist[list], file))
+                               break;
+                           list++;
+                       }
+                       if (list == MAX_SPARE_DRIVES) {
+                           list = 0;
+                           while (list < MAX_SPARE_DRIVES) {
+                               if (!prefs->dfxlist[list][0]) {
+                                   strcpy (prefs->dfxlist[list], file);
+                                   break;
+                               }
+                               list++;
+                           }
+                       }
+                   } else {
+                       strcpy (workprefs.df[drv], file);
+                       disk_insert (drv, file);
+                       if (drv < 3 && workprefs.dfxtype[drv + 1] >= 0)
+                           drv++;
+                   }
+               break;
+               case ZFILE_ROM:
+                   strcpy (prefs->romfile, file);
+               break;
+               case ZFILE_KEY:
+                   strcpy (prefs->keyfile, file);
+               break;
+               case ZFILE_NVR:
+                   strcpy (prefs->flashfile, file);
+               break;
+               case ZFILE_CONFIGURATION:
+                   if (cfgfile_doload (&workprefs, file, 0)) {
+                       if (full_property_sheet) {
+                           inputdevice_updateconfig (&workprefs);
+                           if (!workprefs.start_gui)
+                               ret = 1;
+                       } else {
+                           uae_restart (workprefs.start_gui, file);
+                           ret = 1;
+                       }
+                   }
+               break;
+               case ZFILE_STATEFILE:
+                   savestate_state = STATE_DORESTORE;
+                   strcpy (savestate_fname, file);
+                   ret = 1;
+               break;
+           }
+       }
+    }
+    DragFinish (hd);
+    return ret;
+}
+
+static BOOL CALLBACK DialogProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    static int recursive = 0;
+       
+    switch(msg)
+    {
+       case WM_INITDIALOG:
+           guiDlg = hDlg;
+           SendMessage(hDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon (GetModuleHandle (NULL), MAKEINTRESOURCE(IDI_APPICON)));
+           centerWindow (hDlg);
+           createTreeView (hDlg, currentpage);
+           updatePanel (hDlg, currentpage);
+           EnableWindow( GetDlgItem( hDlg, IDC_RESETAMIGA ), full_property_sheet ? FALSE : TRUE);
+           return TRUE;
+       case WM_DROPFILES:
+           if (dragdrop (hDlg, (HDROP)wParam, (gui_active || full_property_sheet) ? &workprefs : &changed_prefs, currentpage))
+               SendMessage (hDlg, WM_COMMAND, IDOK, 0);
+           updatePanel (hDlg, currentpage);
+           return FALSE;
+       case WM_NOTIFY:
+           switch (((LPNMHDR)lParam)->code)
+           {
+               case TVN_SELCHANGING:
+               return FALSE;
+               case TVN_SELCHANGED:
+               {
+                   LPNMTREEVIEW tv = (LPNMTREEVIEW)lParam;
+                   currentpage = tv->itemNew.lParam & 0xffff;
+                   currentpage_sub = tv->itemNew.lParam >> 16;
+                   updatePanel (hDlg, currentpage);
+                   return TRUE;
+               }
+               break;
+           }
+           break;
+       case WM_COMMAND:
+           switch (wParam) 
+           {
+               case IDC_RESETAMIGA:
+                   uae_reset (0);
+                   SendMessage (hDlg, WM_COMMAND, IDOK, 0);
+                   break;
+               case IDC_QUITEMU:
+                   uae_quit ();
+                   SendMessage (hDlg, WM_COMMAND, IDCANCEL, 0);
+                   break;
+               case IDHELP:
+                   if (pHtmlHelp && ppage[currentpage].help)
+                       HtmlHelp (NULL, help_file, HH_DISPLAY_TOPIC, ppage[currentpage].help);
+                   return TRUE;
+               case IDOK:
+                   updatePanel (hDlg, -1);
+                   EndDialog (hDlg, 1);
+                   gui_to_prefs ();
+                   guiDlg = NULL;
+                   return TRUE;
+               case IDCANCEL:
+                   updatePanel (hDlg, -1);
+                   EndDialog (hDlg, 0);
+                   if (allow_quit) 
+                   {
+                       quit_program = 1;
+                       regs.spcflags |= SPCFLAG_BRK;
+                   }
+                   guiDlg = NULL;
+                   return TRUE;
+           }
+       break;
+    }
+    return FALSE;
+}
+
+
+static int init_page (int tmpl, int icon, int title,
+               BOOL (CALLBACK FAR *func) (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam), char *help)
+{
+    static id = 0;
+    LPTSTR lpstrTitle;
+    ppage[id].pp.pszTemplate = MAKEINTRESOURCE (tmpl);
+    ppage[id].pp.pszIcon = MAKEINTRESOURCE (icon);
+    lpstrTitle = calloc (1, MAX_PATH);
+    LoadString( hUIDLL, title, lpstrTitle, MAX_PATH );
+    ppage[id].pp.pszTitle = lpstrTitle;
+    ppage[id].pp.pfnDlgProc = func;
+    ppage[id].help = help;
+    ppage[id].idx = id;
+    id++;
+    return id - 1;
+}
+
+static int GetSettings (int all_options, HWND hwnd)
+{
+    static int init_called = 0;
+    int psresult;
+
+    full_property_sheet = all_options;
+    allow_quit = all_options;
+    pguiprefs = &currprefs;
+    default_prefs (&workprefs, 0);
+
+    WIN32GUI_LoadUIString( IDS_NONE, szNone, MAX_PATH );
+
+    prefs_to_gui (&changed_prefs);
+
+    if( !init_called )
+    {
+       LOADSAVE_ID = init_page (IDD_LOADSAVE, IDI_CONFIGFILE, IDS_LOADSAVE, LoadSaveDlgProc, "gui/configurations.htm");
+       MEMORY_ID = init_page (IDD_MEMORY, IDI_MEMORY, IDS_MEMORY, MemoryDlgProc, "gui/ram.htm");
+       KICKSTART_ID = init_page (IDD_KICKSTART, IDI_MEMORY, IDS_KICKSTART, KickstartDlgProc, "gui/rom.htm");
+       CPU_ID = init_page (IDD_CPU, IDI_CPU, IDS_CPU, CPUDlgProc, "gui/cpu.htm");
+       DISPLAY_ID = init_page (IDD_DISPLAY, IDI_DISPLAY, IDS_DISPLAY, DisplayDlgProc, "gui/display.htm");
+#if defined(OPENGL) || defined (D3D)
+       HW3D_ID = init_page (IDD_OPENGL, IDI_DISPLAY, IDS_OPENGL, hw3dDlgProc, "gui/opengl.htm");
+#endif
+       CHIPSET_ID = init_page (IDD_CHIPSET, IDI_CPU, IDS_CHIPSET, ChipsetDlgProc, "gui/chipset.htm");
+       SOUND_ID = init_page (IDD_SOUND, IDI_SOUND, IDS_SOUND, SoundDlgProc, "gui/sound.htm");
+       FLOPPY_ID = init_page (IDD_FLOPPY, IDI_FLOPPY, IDS_FLOPPY, FloppyDlgProc, "gui/floppies.htm");
+       DISK_ID = init_page (IDD_DISK, IDI_FLOPPY, IDS_DISK, DiskDlgProc, "gui/disk.htm");
+#ifdef FILESYS
+       HARDDISK_ID = init_page (IDD_HARDDISK, IDI_HARDDISK, IDS_HARDDISK, HarddiskDlgProc, "gui/hard-drives.htm");
+#endif
+       PORTS_ID = init_page (IDD_PORTS, IDI_PORTS, IDS_PORTS, PortsDlgProc, "gui/ports.htm");
+       INPUT_ID = init_page (IDD_INPUT, IDI_INPUT, IDS_INPUT, InputDlgProc, "gui/input.htm");
+       MISC1_ID = init_page (IDD_MISC1, IDI_MISC1, IDS_MISC1, MiscDlgProc1, "gui/misc.htm");
+       MISC2_ID = init_page (IDD_MISC2, IDI_MISC2, IDS_MISC2, MiscDlgProc2, "gui/misc.htm");
+#ifdef AVIOUTPUT
+       AVIOUTPUT_ID = init_page (IDD_AVIOUTPUT, IDI_AVIOUTPUT, IDS_AVIOUTPUT, AVIOutputDlgProc, "gui/output.htm");
+#endif
+       ABOUT_ID = init_page (IDD_ABOUT, IDI_ABOUT, IDS_ABOUT, AboutDlgProc, NULL);
+       C_PAGES = ABOUT_ID + 1;
+       init_called = 1;
+       currentpage = LOADSAVE_ID;
+       hMoveUp = (HICON)LoadImage( hInst, MAKEINTRESOURCE( IDI_MOVE_UP ), IMAGE_ICON, 16, 16, LR_LOADMAP3DCOLORS );
+       hMoveDown = (HICON)LoadImage( hInst, MAKEINTRESOURCE( IDI_MOVE_DOWN ), IMAGE_ICON, 16, 16, LR_LOADMAP3DCOLORS );
+    }
+
+    if (all_options)
+       CreateConfigStore ();
+    psresult = DialogBox (hInst, MAKEINTRESOURCE (IDD_PANEL), hwnd, DialogProc);
+
+    if (quit_program)
+        psresult = -2;
+
+    full_property_sheet = 0;
+    return psresult;
+}
+
+int gui_init (void)
+{
+    int ret;
+    
+    ret = GetSettings(1, GetDesktopWindow ());
+    if (ret > 0) {
+#ifdef AVIOUTPUT
+       AVIOutput_Begin ();
+#endif
+    }
+    return ret;
+}
+
+int gui_update (void)
+{
+    return 1;
+}
+
+void gui_exit (void)
+{
+    FreeConfigStore ();
+#ifdef PARALLEL_PORT
+    closeprinter(); // Bernd Roesch
+#endif
+}
+
+extern HWND hStatusWnd;
+struct gui_info gui_data;
+
+void check_prefs_changed_gui( void )
+{
+}
+
+void gui_hd_led (int led)
+{
+    static int resetcounter;
+
+    int old = gui_data.hd;
+    if (led == 0) {
+       resetcounter--;
+       if (resetcounter > 0)
+           return;
+    }
+    gui_data.hd = led;
+    resetcounter = 6;
+    if (old != gui_data.hd)
+       gui_led (5, gui_data.hd);
+}
+
+void gui_cd_led (int led)
+{
+    static int resetcounter;
+
+    int old = gui_data.cd;
+    if (led == 0) {
+       resetcounter--;
+       if (resetcounter > 0)
+           return;
+    }
+    gui_data.cd = led;
+    resetcounter = 6;
+    if (old != gui_data.cd)
+       gui_led (6, gui_data.cd);
+}
+
+void gui_fps (int fps, int idle)
+{
+    gui_data.fps = fps;
+    gui_data.idle = idle;
+    gui_led (7, 0);
+    gui_led (8, 0);
+}
+
+void gui_led (int led, int on)
+{
+    WORD type;
+    static char drive_text[NUM_LEDS * 16];
+    char *ptr;
+    int pos = -1;
+
+    indicator_leds (led, on);
+    if( hStatusWnd )
+    {
+        if (on)
+           type = SBT_POPOUT;
+       else
+           type = 0;
+       if (led >= 1 && led <= 4) {
+           pos = 5 + (led - 1);
+           ptr = drive_text + pos * 16;
+           if (gui_data.drive_disabled[led - 1])
+               strcpy (ptr, "");
+           else
+               sprintf (ptr , "%02d", gui_data.drive_track[led - 1]);
+       } else if (led == 0) {
+           pos = 2;
+           ptr = strcpy (drive_text + pos * 16, "Power");
+       } else if (led == 5) {
+           pos = 3;
+           ptr = strcpy (drive_text + pos * 16, "HD");
+       } else if (led == 6) {
+           pos = 4;
+           ptr = strcpy (drive_text + pos * 16, "CD");
+       } else if (led == 7) {
+           pos = 1;
+           ptr = drive_text + pos * 16;
+           sprintf(ptr, "FPS: %.1f", (double)((gui_data.fps + 5) / 10.0));
+       } else if (led == 8) {
+           pos = 0;
+           ptr = drive_text + pos * 16;
+           sprintf(ptr, "CPU: %.0f%%", (double)((gui_data.idle) / 10.0));
+       }
+       if (pos >= 0)
+           PostMessage (hStatusWnd, SB_SETTEXT, (WPARAM) ((pos + 1) | type), (LPARAM) ptr);
+    }
+}
+
+void gui_filename (int num, const char *name)
+{
+}
+
+void gui_message (const char *format,...)
+{
+    char msg[2048];
+    char szTitle[ MAX_PATH ];
+    va_list parms;
+    int flipflop = 0;
+    int fullscreen = 0;
+    int focuso = focus;
+    HWND window = NULL;
+
+    if( DirectDraw_GetCooperativeLevel( &window, &fullscreen ) && fullscreen )
+        flipflop = 1;
+    pause_sound ();
+    if( flipflop )
+        ShowWindow( window, SW_MINIMIZE );
+
+    va_start (parms, format);
+    vsprintf( msg, format, parms );
+    va_end (parms);
+    write_log( msg );
+
+    WIN32GUI_LoadUIString( IDS_ERRORTITLE, szTitle, MAX_PATH );
+
+    MessageBox( NULL, msg, szTitle, MB_OK | MB_ICONWARNING | MB_TASKMODAL | MB_SETFOREGROUND );
+
+    if( flipflop )
+        ShowWindow( window, SW_RESTORE );
+    resume_sound();
+    setmouseactive( focuso );
+}
+
+void pre_gui_message (const char *format,...)
+{
+    char msg[2048];
+    char szTitle[ MAX_PATH ];
+    va_list parms;
+
+    va_start (parms, format);
+    vsprintf( msg, format, parms );
+    va_end (parms);
+    write_log( msg );
+
+    WIN32GUI_LoadUIString( IDS_ERRORTITLE, szTitle, MAX_PATH );
+
+    MessageBox( NULL, msg, szTitle, MB_OK | MB_ICONWARNING | MB_TASKMODAL | MB_SETFOREGROUND );
+
+}
+
+void gui_lock (void)
+{
+}
+
+void gui_unlock (void)
+{
+}
diff --git a/od-win32/win32gui.h b/od-win32/win32gui.h
new file mode 100755 (executable)
index 0000000..5fd5a54
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef WIN32GUI_H
+#define WIN32GUI_H
+
+#define MAXJOYSTICKS 2
+
+#define MAX_BUFFER_SIZE    256
+#define NUM_DRIVES         16
+
+typedef struct
+{
+    char path[256];
+    char name[256];
+    uae_u16 rw;
+    uae_u8  sectors;
+    uae_u8  surfaces;
+    uae_u8  reserved;
+    uae_u8  hardfile;
+    uae_u16 spare;
+} drive_specs;
+
+extern drive_specs drives[NUM_DRIVES];
+
+#define CFG_DESCRIPTION_LENGTH 128
+#define CFG_SER_LENGTH 256
+#define CFG_ROM_LENGTH 256
+#define CFG_PAR_LENGTH 256
+#define CFG_KEY_LENGTH 256
+
+#define CONFIG_VERSION_MAJOR 1
+#define CONFIG_VERSION_MINOR 2
+
+#define DIRECT_SOUND_ENABLED 0x01
+#define AHI_ENABLED          0x02
+
+#define CONFIG_SAVE   0
+#define CONFIG_LOAD   1
+#define CONFIG_SAVE_FULL 2
+#define CONFIG_LOAD_FULL 3
+#define CONFIG_DELETE 4
+
+void WIN32GUI_LoadUIString( DWORD id, char *string, DWORD dwStringLen );
+extern int GetSettings (int all_options, HWND);
+extern int DiskSelection( HWND hDlg, WPARAM wParam, int flag, struct uae_prefs *prefs, char *);
+void InitializeListView( HWND hDlg );
+extern void pre_gui_message (const char*,...);
+int dragdrop (HWND hDlg, HDROP hd, struct uae_prefs *prefs, int currentpage);
+
+#endif
diff --git a/od-win32/winuae.nsi b/od-win32/winuae.nsi
new file mode 100755 (executable)
index 0000000..89c59d2
--- /dev/null
@@ -0,0 +1,42 @@
+Name "WinUAE"
+OutFile "InstallWinUAE.exe"
+Caption "WinUAE installer"
+ShowInstDetails show
+
+; Some default compiler settings (uncomment and change at will):
+SetCompress auto ; (can be off or force)
+SetDatablockOptimize on ; (can be off)
+CRCCheck on ; (can be off)
+; AutoCloseWindow false ; (can be true for the window go away automatically at end)
+; ShowInstDetails hide ; (can be show to have them shown, or nevershow to disable)
+; SetDateSave off ; (can be on to have files restored to their orginal date)
+
+InstallDir "$PROGRAMFILES\WinUAE"
+InstallDirRegKey HKEY_CURRENT_USER "SOFTWARE\Arabuusimiehet\WinUAE" "InstallDir"
+DirShow show ; (make this hide to not let the user change it)
+DirText "Select the directory to install WinUAE in:"
+Icon "d:\projects\winuae\src\od-win32\resources\winuae.ico"
+WindowIcon on
+AllowRootDirInstall true
+AutoCloseWindow true
+
+Section "" ; (default section)
+SetOutPath "$INSTDIR"
+File "d:\projects\winuae\distribution\*"
+SetOutPath "$INSTDIR\Amiga Programs"
+File "d:\projects\winuae\distribution\Amiga Programs\*"
+SetOutPath "$INSTDIR\Docs"
+File "d:\projects\winuae\distribution\Docs\*"
+SetOutPath "$INSTDIR\Docs\Windows"
+File "d:\projects\winuae\distribution\Docs\Windows\*"
+CreateDirectory "$INSTDIR\Configurations"
+WriteRegStr HKEY_CURRENT_USER "SOFTWARE\Arabuusimiehet\WinUAE" "InstallDir" "$INSTDIR"
+
+ExecShell open "$INSTDIR\Docs\Readme.txt"
+
+; add files / whatever that need to be installed here.
+
+SectionEnd ; end of default section
+
+; eof
+
diff --git a/od-win32/winuae_msvc/winuae_msvc.vcproj b/od-win32/winuae_msvc/winuae_msvc.vcproj
new file mode 100755 (executable)
index 0000000..61ae3e9
--- /dev/null
@@ -0,0 +1,584 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+       ProjectType="Visual C++"
+       Version="7.10"
+       Name="winuae"
+       SccProjectName=""
+       SccLocalPath="">
+       <Platforms>
+               <Platform
+                       Name="Win32"/>
+       </Platforms>
+       <Configurations>
+               <Configuration
+                       Name="Debug|Win32"
+                       OutputDirectory=".\Debug"
+                       IntermediateDirectory=".\Debug"
+                       ConfigurationType="1"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="FALSE"
+                       CharacterSet="2">
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               AdditionalOptions=""
+                               Optimization="0"
+                               AdditionalIncludeDirectories="..\..\include,..\..,..\,..\resources,..\osdep,..\sounddep"
+                               PreprocessorDefinitions="WINVER=0x0500,_DEBUG,WIN32,_WINDOWS,ZLIB_DLL,OPENGL_SUPPORT,_WIN32_IE 0x0500 "
+                               ExceptionHandling="FALSE"
+                               BasicRuntimeChecks="3"
+                               RuntimeLibrary="1"
+                               BufferSecurityCheck="TRUE"
+                               RuntimeTypeInfo="TRUE"
+                               PrecompiledHeaderFile=".\Debug/winuae_msvc.pch"
+                               AssemblerListingLocation=".\Debug/"
+                               ObjectFile=".\Debug/"
+                               ProgramDataBaseFileName=".\Debug/"
+                               WarningLevel="3"
+                               SuppressStartupBanner="TRUE"
+                               Detect64BitPortabilityProblems="FALSE"
+                               DebugInformationFormat="4"
+                               CompileAs="0"/>
+                       <Tool
+                               Name="VCCustomBuildTool"/>
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalOptions="/MACHINE:I386"
+                               AdditionalDependencies="opengl32.lib glu32.lib ws2_32.lib ddraw.lib dxguid.lib winmm.lib comctl32.lib version.lib vfw32.lib msacm32.lib zdll.lib dsound.lib dinput8.lib d3d9.lib d3dx9.lib winio.lib setupapi.lib wininet.lib capsimg.lib dxerr8.lib"
+                               OutputFile="d:\amiga\winuae.exe"
+                               LinkIncremental="2"
+                               SuppressStartupBanner="TRUE"
+                               DelayLoadDLLs="zlib1.dll;winio.dll;setupapi.dll;capsimg.dll"
+                               GenerateDebugInformation="TRUE"
+                               ProgramDatabaseFile=".\Debug/winuae.pdb"
+                               SubSystem="2"
+                               StackReserveSize="2621440"
+                               StackCommitSize="2621440"/>
+                       <Tool
+                               Name="VCMIDLTool"
+                               PreprocessorDefinitions="_DEBUG"
+                               MkTypLibCompatible="TRUE"
+                               SuppressStartupBanner="TRUE"
+                               TargetEnvironment="1"
+                               TypeLibraryName=".\Debug/winuae_msvc.tlb"/>
+                       <Tool
+                               Name="VCPostBuildEventTool"/>
+                       <Tool
+                               Name="VCPreBuildEventTool"/>
+                       <Tool
+                               Name="VCPreLinkEventTool"/>
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="_DEBUG"
+                               Culture="1033"/>
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"/>
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"/>
+                       <Tool
+                               Name="VCWebDeploymentTool"/>
+                       <Tool
+                               Name="VCManagedWrapperGeneratorTool"/>
+                       <Tool
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+               </Configuration>
+               <Configuration
+                       Name="Release|Win32"
+                       OutputDirectory="d:\amiga"
+                       IntermediateDirectory=".\Release"
+                       ConfigurationType="1"
+                       UseOfMFC="0"
+                       ATLMinimizesCRunTimeLibraryUsage="FALSE"
+                       CharacterSet="2"
+                       WholeProgramOptimization="FALSE">
+                       <Tool
+                               Name="VCCLCompilerTool"
+                               Optimization="2"
+                               GlobalOptimizations="TRUE"
+                               InlineFunctionExpansion="1"
+                               EnableIntrinsicFunctions="TRUE"
+                               ImproveFloatingPointConsistency="TRUE"
+                               FavorSizeOrSpeed="1"
+                               OptimizeForProcessor="2"
+                               AdditionalIncludeDirectories="..\..\include,..\..,..\,..\resources,..\osdep,..\sounddep"
+                               PreprocessorDefinitions="WINVER=0x0500,WIN32,NDEBUG,_WINDOWS,ZLIB_DLL,_WIN32_IE 0x0500 "
+                               StringPooling="TRUE"
+                               ExceptionHandling="FALSE"
+                               RuntimeLibrary="0"
+                               BufferSecurityCheck="FALSE"
+                               EnableFunctionLevelLinking="TRUE"
+                               EnableEnhancedInstructionSet="0"
+                               TreatWChar_tAsBuiltInType="FALSE"
+                               RuntimeTypeInfo="FALSE"
+                               UsePrecompiledHeader="0"
+                               PrecompiledHeaderFile=".\Release/winuae_msvc.pch"
+                               AssemblerListingLocation=".\Release/"
+                               ObjectFile=".\Release/"
+                               ProgramDataBaseFileName=".\Release/"
+                               WarningLevel="3"
+                               SuppressStartupBanner="TRUE"
+                               CompileAs="1"
+                               ForcedIncludeFiles=""/>
+                       <Tool
+                               Name="VCCustomBuildTool"/>
+                       <Tool
+                               Name="VCLinkerTool"
+                               AdditionalOptions="/MACHINE:I386"
+                               AdditionalDependencies="opengl32.lib glu32.lib ws2_32.lib ddraw.lib dxguid.lib winmm.lib comctl32.lib version.lib vfw32.lib msacm32.lib zdll.lib dsound.lib dinput8.lib d3d9.lib d3dx9.lib winio.lib setupapi.lib wininet.lib capsimg.lib dxerr8.lib"
+                               OutputFile="d:\amiga\winuae.exe"
+                               LinkIncremental="1"
+                               SuppressStartupBanner="TRUE"
+                               DelayLoadDLLs="zlib1.dll;winio.dll;setupapi.dll;capsimg.dll"
+                               GenerateDebugInformation="TRUE"
+                               ProgramDatabaseFile=".\Release/winuae.pdb"
+                               SubSystem="2"
+                               StackReserveSize="2621440"
+                               StackCommitSize="2621440"
+                               OptimizeReferences="2"
+                               EnableCOMDATFolding="2"
+                               OptimizeForWindows98="0"/>
+                       <Tool
+                               Name="VCMIDLTool"
+                               PreprocessorDefinitions="NDEBUG"
+                               MkTypLibCompatible="TRUE"
+                               SuppressStartupBanner="TRUE"
+                               TargetEnvironment="1"
+                               TypeLibraryName=".\Release/winuae_msvc.tlb"/>
+                       <Tool
+                               Name="VCPostBuildEventTool"/>
+                       <Tool
+                               Name="VCPreBuildEventTool"/>
+                       <Tool
+                               Name="VCPreLinkEventTool"/>
+                       <Tool
+                               Name="VCResourceCompilerTool"
+                               PreprocessorDefinitions="NDEBUG"
+                               Culture="1033"/>
+                       <Tool
+                               Name="VCWebServiceProxyGeneratorTool"/>
+                       <Tool
+                               Name="VCXMLDataGeneratorTool"/>
+                       <Tool
+                               Name="VCWebDeploymentTool"/>
+                       <Tool
+                               Name="VCManagedWrapperGeneratorTool"/>
+                       <Tool
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+               </Configuration>
+       </Configurations>
+       <References>
+       </References>
+       <Files>
+               <Filter
+                       Name="Resource Files"
+                       Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
+                       <File
+                               RelativePath="..\resources\35floppy.ico">
+                       </File>
+                       <File
+                               RelativePath="..\resources\amigainfo.ico">
+                       </File>
+                       <File
+                               RelativePath="..\resources\avioutput.ico">
+                       </File>
+                       <File
+                               RelativePath="..\resources\chip.ico">
+                       </File>
+                       <File
+                               RelativePath="..\resources\cpu.ico">
+                       </File>
+                       <File
+                               RelativePath="..\resources\Drive.ico">
+                       </File>
+                       <File
+                               RelativePath="..\resources\file.ico">
+                       </File>
+                       <File
+                               RelativePath="..\resources\folder.ico">
+                       </File>
+                       <File
+                               RelativePath="..\resources\H_arrow.cur">
+                       </File>
+                       <File
+                               RelativePath="..\resources\joystick.ico">
+                       </File>
+                       <File
+                               RelativePath="..\resources\misc.ico">
+                       </File>
+                       <File
+                               RelativePath="..\resources\move_dow.ico">
+                       </File>
+                       <File
+                               RelativePath="..\resources\move_up.ico">
+                       </File>
+                       <File
+                               RelativePath="..\resources\root.ico">
+                       </File>
+                       <File
+                               RelativePath="..\resources\screen.ico">
+                       </File>
+                       <File
+                               RelativePath="..\resources\sound.ico">
+                       </File>
+                       <File
+                               RelativePath="..\resources\winuae.ico">
+                       </File>
+                       <File
+                               RelativePath="..\resources\winuae.rc">
+                               <FileConfiguration
+                                       Name="Debug|Win32">
+                                       <Tool
+                                               Name="VCResourceCompilerTool"
+                                               AdditionalIncludeDirectories="\projects\winuae\src\od-win32\resources;$(NoInherit)"/>
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32">
+                                       <Tool
+                                               Name="VCResourceCompilerTool"
+                                               AdditionalIncludeDirectories="\projects\winuae\src\od-win32\resources;$(NoInherit)"/>
+                               </FileConfiguration>
+                       </File>
+               </Filter>
+               <Filter
+                       Name="win32"
+                       Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
+                       <File
+                               RelativePath="..\ahidsound.c">
+                       </File>
+                       <File
+                               RelativePath="..\avioutput.c">
+                       </File>
+                       <File
+                               RelativePath="..\blkdev_win32_aspi.c">
+                       </File>
+                       <File
+                               RelativePath="..\blkdev_win32_ioctl.c">
+                       </File>
+                       <File
+                               RelativePath="..\blkdev_win32_spti.c">
+                       </File>
+                       <File
+                               RelativePath="..\bsdsock.c">
+                       </File>
+                       <File
+                               RelativePath="..\caps\caps_win32.c">
+                       </File>
+                       <File
+                               RelativePath="..\dinput.c">
+                       </File>
+                       <File
+                               RelativePath="..\direct3d.c">
+                       </File>
+                       <File
+                               RelativePath="..\dxwrap.c">
+                       </File>
+                       <File
+                               RelativePath="..\fsdb_win32.c">
+                       </File>
+                       <File
+                               RelativePath="..\hardfile_win32.c">
+                       </File>
+                       <File
+                               RelativePath="..\ioport.c">
+                       </File>
+                       <File
+                               RelativePath="..\keyboard_win32.c">
+                       </File>
+                       <File
+                               RelativePath="..\midi.c">
+                       </File>
+                       <File
+                               RelativePath="..\mman.c">
+                       </File>
+                       <File
+                               RelativePath="..\opengl.c">
+                       </File>
+                       <File
+                               RelativePath="..\parser.c">
+                       </File>
+                       <File
+                               RelativePath="..\picasso96_win.c">
+                       </File>
+                       <File
+                               RelativePath="..\posixemu.c">
+                       </File>
+                       <File
+                               RelativePath="..\scaler.c">
+                       </File>
+                       <File
+                               RelativePath="..\screenshot.c">
+                       </File>
+                       <File
+                               RelativePath="..\serial_win32.c">
+                       </File>
+                       <File
+                               RelativePath="..\sounddep\sound.c">
+                       </File>
+                       <File
+                               RelativePath="..\support.c">
+                       </File>
+                       <File
+                               RelativePath="..\win32.c">
+                       </File>
+                       <File
+                               RelativePath="..\win32_scale2x.c">
+                       </File>
+                       <File
+                               RelativePath="..\win32gfx.c">
+                       </File>
+                       <File
+                               RelativePath="..\win32gui.c">
+                       </File>
+                       <File
+                               RelativePath="..\writelog.c">
+                       </File>
+               </Filter>
+               <Filter
+                       Name="common"
+                       Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
+                       <File
+                               RelativePath="..\..\akiko.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\ar.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\audio.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\autoconf.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\blitfunc.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\blittable.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\blitter.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\blkdev.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\bsdsocket.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\catweasel.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\cdrom.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\cfgfile.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\cia.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\compiler.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\cpudefs.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\cpuemu_0.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\cpuemu_5.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\cpuemu_6.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\cpustbl.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\custom.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\debug.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\disk.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\drawing.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\driveclick.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\enforcer.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\ersatz.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\expansion.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\fdi2raw.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\filesys.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\fpp.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\fsdb.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\fsusage.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\gfxlib.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\gfxutil.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\hardfile.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\identify.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\inputdevice.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\keybuf.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\main.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\memory.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\missing.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\native2amiga.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\newcpu.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\readcpu.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\savestate.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\scsiemul.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\uaeexe.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\uaelib.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\unzip.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\zfile.c">
+                       </File>
+               </Filter>
+               <Filter
+                       Name="jit"
+                       Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
+                       <File
+                               RelativePath="..\..\compemu.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\compemu_fpp.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\compemu_support.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\compstbl.c">
+                       </File>
+               </Filter>
+               <Filter
+                       Name="dms"
+                       Filter="">
+                       <File
+                               RelativePath="..\..\dms\cdata.h">
+                       </File>
+                       <File
+                               RelativePath="..\..\dms\crc_csum.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\dms\getbits.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\dms\maketbl.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\dms\pfile.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\dms\tables.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\dms\u_deep.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\dms\u_heavy.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\dms\u_init.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\dms\u_medium.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\dms\u_quick.c">
+                       </File>
+                       <File
+                               RelativePath="..\..\dms\u_rle.c">
+                       </File>
+               </Filter>
+               <File
+                       RelativePath="..\resources\drive_click.wav">
+               </File>
+               <File
+                       RelativePath="..\resources\drive_snatch.wav">
+               </File>
+               <File
+                       RelativePath="..\resources\drive_spin.wav">
+               </File>
+               <File
+                       RelativePath="..\resources\drive_spinnd.wav">
+               </File>
+               <File
+                       RelativePath="..\resources\drive_startup.wav">
+               </File>
+               <File
+                       RelativePath="..\hq2x32.obj">
+               </File>
+               <File
+                       RelativePath="..\hq3x16.obj">
+               </File>
+               <File
+                       RelativePath="..\hq3x32.obj">
+               </File>
+               <File
+                       RelativePath="..\hq4x32.obj">
+               </File>
+               <File
+                       RelativePath="..\resources\resource.h">
+               </File>
+               <File
+                       RelativePath="..\resources\resource.hm">
+               </File>
+               <File
+                       RelativePath="..\resources\winuae.exe.manifest">
+               </File>
+       </Files>
+       <Globals>
+       </Globals>
+</VisualStudioProject>
diff --git a/od-win32/wrc.sh b/od-win32/wrc.sh
new file mode 100755 (executable)
index 0000000..ec63268
--- /dev/null
@@ -0,0 +1,75 @@
+#! /bin/sh
+#
+
+realdirname () {
+  tmp_save_dir=`pwd`
+  cd $@
+  result=`pwd -P`
+  cd $tmp_save_dir
+  result=`echo $result |sed 's,/,\\\\,g'`
+}
+
+realfilename () {
+  case $@ in
+  */*)
+    tmp_save_dir=`pwd`
+    cd `echo $@ | sed 's,/[^/]*$,,'`
+    result=`pwd -P`/`basename $@`
+    cd $tmp_save_dir
+    ;;
+  *)
+    result=$@
+    ;;
+  esac
+  result=`echo $result |sed 's,/,\\\\,g'`
+}
+
+next_is_include=no
+resfiles=
+srcfiles=
+exefile=
+
+for arg in $@; do
+
+if test $next_is_include = yes; then
+  realdirname $arg
+  includes="$includes /i=$result"
+  next_is_include=no
+else
+  case $arg in
+  -I) next_is_include=yes
+    ;;
+
+  -I*)
+    foo=`echo $arg | sed 's,^-I,,'`
+    realdirname $foo
+    includes="$includes /i=$result"
+    ;;
+
+  *.rc)
+    realfilename $arg
+    srcfiles="$srcfiles $result"
+    ;;
+
+  *.res)
+    realfilename $arg
+    resfiles="$resfiles $result"
+    ;;
+
+  *.exe)
+    realfilename $arg
+    exefile=$result
+    ;;
+
+  *) echo "Bad argument: $arg"
+    ;;
+  esac
+fi
+done
+
+echo "wrc /bt=nt /dWIN32 /d_WIN32 /d__NT__ /r $includes $srcfiles"
+if test -z "$exefile"; then
+  wrc /bt=nt /dWIN32 /d_WIN32 /d__NT__ /r $includes $srcfiles
+else
+  wrc $resfiles $exefile
+fi
diff --git a/od-win32/writelog.c b/od-win32/writelog.c
new file mode 100755 (executable)
index 0000000..91c7dfd
--- /dev/null
@@ -0,0 +1,118 @@
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <windows.h>
+
+#define SHOW_CONSOLE 0
+
+static int consoleopen = 0;
+static HANDLE stdinput,stdoutput;
+
+FILE *debugfile = NULL;
+int console_logging;
+
+#define WRITE_LOG_BUF_SIZE 4096
+
+/* console functions for debugger */
+
+static void openconsole(void)
+{
+    if(consoleopen) return;
+    AllocConsole();
+    stdinput=GetStdHandle(STD_INPUT_HANDLE);
+    stdoutput=GetStdHandle(STD_OUTPUT_HANDLE);
+    SetConsoleMode(stdinput,ENABLE_PROCESSED_INPUT|ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT|ENABLE_PROCESSED_OUTPUT);
+    consoleopen = 1;
+}
+
+void console_out (const char *format,...)
+{
+    va_list parms;
+    char buffer[WRITE_LOG_BUF_SIZE];
+    DWORD temp;
+
+    va_start (parms, format);
+    _vsnprintf( buffer, WRITE_LOG_BUF_SIZE-1, format, parms );
+    va_end (parms);
+    openconsole();
+    WriteConsole(stdoutput,buffer,strlen(buffer),&temp,0);
+}
+
+int console_get (char *out, int maxlen)
+{
+    DWORD len,totallen;
+
+    totallen=0;
+    while(maxlen>0) 
+    {
+           ReadConsole(stdinput,out,1,&len,0);
+           if(*out == 13) break;
+           out++;
+           maxlen--;
+           totallen++;
+    }
+    *out=0;
+    return totallen;
+}
+
+void console_flush (void)
+{
+}
+
+void write_dlog (const char *format, ...)
+{
+    int count;
+    DWORD numwritten;
+    char buffer[WRITE_LOG_BUF_SIZE];
+
+    va_list parms;
+    va_start (parms, format);
+    count = _vsnprintf( buffer, WRITE_LOG_BUF_SIZE-1, format, parms );
+    if (SHOW_CONSOLE || console_logging) {
+       openconsole();
+       WriteConsole(stdoutput,buffer,strlen(buffer),&numwritten,0);
+    }
+    if( debugfile ) {
+       fprintf( debugfile, buffer );
+       fflush (debugfile);
+    }
+    va_end (parms);
+}
+void write_log (const char *format, ...)
+{
+    int count;
+    DWORD numwritten;
+    char buffer[WRITE_LOG_BUF_SIZE];
+
+    va_list parms;
+    va_start (parms, format);
+    count = _vsnprintf( buffer, WRITE_LOG_BUF_SIZE-1, format, parms );
+    if (SHOW_CONSOLE || console_logging) {
+       openconsole();
+       WriteConsole(stdoutput,buffer,strlen(buffer),&numwritten,0);
+    }
+    if( debugfile ) {
+       fprintf( debugfile, buffer );
+       fflush (debugfile);
+    }
+    va_end (parms);
+}
+
+void f_out (void *f, const char *format, ...)
+{
+    int count;
+    DWORD numwritten;
+    char buffer[ WRITE_LOG_BUF_SIZE ];
+
+    va_list parms;
+    va_start (parms, format);
+    count = _vsnprintf( buffer, WRITE_LOG_BUF_SIZE-1, format, parms );
+    if (f == 0) {
+       write_log (buffer);
+    } else {
+       openconsole();
+       WriteConsole(stdoutput,buffer,strlen(buffer),&numwritten,0);
+       va_end (parms);
+    }
+}
diff --git a/picasso96.c b/picasso96.c
new file mode 100755 (executable)
index 0000000..e873cf2
--- /dev/null
@@ -0,0 +1,2899 @@
+/*
+ * UAE - The U*nix Amiga Emulator
+ *
+ * Picasso96 Support Module
+ *
+ * Copyright 1997 Brian King <Brian_King@Mitel.com, Brian_King@Cloanto.com>
+ *
+ * Theory of operation:
+ * On the Amiga side, a Picasso card consists mainly of a memory area that
+ * contains the frame buffer.  On the UAE side, we allocate a block of memory
+ * that will hold the frame buffer.  This block is in normal memory, it is
+ * never directly on the graphics card.  All graphics operations, which are
+ * mainly reads and writes into this block and a few basic operations like
+ * filling a rectangle, operate on this block of memory.
+ * Since the memory is not on the graphics card, some work must be done to
+ * synchronize the display with the data in the Picasso frame buffer.  There
+ * are various ways to do this.  One possibility is to allocate a second
+ * buffer of the same size, and perform all write operations twice.  Since
+ * we never read from the second buffer, it can actually be placed in video
+ * memory.  The X11 driver could be made to use the Picasso frame buffer as
+ * the data buffer of an XImage, which could then be XPutImage()d from time
+ * to time.  Another possibility is to translate all Picasso accesses into
+ * Xlib (or GDI, or whatever your graphics system is) calls.  This possibility
+ * is a bit tricky, since there is a risk of generating very many single pixel
+ * accesses which may be rather slow.
+ *
+ * TODO:
+ * - add panning capability
+ * - we want to add a manual switch to override SetSwitch for hardware banging
+ *   programs started from a Picasso workbench.
+ */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "threaddep/thread.h"
+#include "uae.h"
+#include "memory.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "xwin.h"
+#include "picasso96.h"
+
+#ifdef JIT
+int have_done_picasso=0; /* For the JIT compiler */
+int picasso_is_special=PIC_WRITE; /* ditto */
+int picasso_is_special_read=PIC_READ; /* ditto */
+#endif
+
+#ifdef PICASSO96
+
+int p96hack_vpos, p96hack_vpos2, p96refresh_active;
+
+#define P96TRACING_ENABLED 0
+#if P96TRACING_ENABLED
+#define P96TRACE(x)    do { write_log x; } while(0)
+#else
+#define P96TRACE(x)
+#endif
+
+static uae_u32 gfxmem_lget (uaecptr) REGPARAM;
+static uae_u32 gfxmem_wget (uaecptr) REGPARAM;
+static uae_u32 gfxmem_bget (uaecptr) REGPARAM;
+static void gfxmem_lput (uaecptr, uae_u32) REGPARAM;
+static void gfxmem_wput (uaecptr, uae_u32) REGPARAM;
+static void gfxmem_bput (uaecptr, uae_u32) REGPARAM;
+static int gfxmem_check (uaecptr addr, uae_u32 size) REGPARAM;
+static uae_u8 *gfxmem_xlate (uaecptr addr) REGPARAM;
+
+static void write_gfx_long (uaecptr addr, uae_u32 value);
+static void write_gfx_word (uaecptr addr, uae_u16 value);
+static void write_gfx_byte (uaecptr addr, uae_u8 value);
+
+static uae_u8 all_ones_bitmap, all_zeros_bitmap;
+
+struct picasso96_state_struct picasso96_state;
+struct picasso_vidbuf_description picasso_vidinfo;
+
+/* These are the maximum resolutions... They are filled in by GetSupportedResolutions() */
+/* have to fill this in, otherwise problems occur
+ * @@@ ??? what problems?
+ */
+struct ScreenResolution planar = { 320, 240 };
+struct ScreenResolution chunky = { 640, 480 };
+struct ScreenResolution hicolour = { 640, 480 };
+struct ScreenResolution truecolour = { 640, 480 };
+struct ScreenResolution alphacolour = { 640, 480 };
+
+uae_u16 picasso96_pixel_format = RGBFF_CHUNKY;
+
+struct PicassoResolution DisplayModes[MAX_PICASSO_MODES];
+
+static int mode_count = 0;
+
+static int set_gc_called = 0;
+static int set_panning_called = 0;
+/* Address of the screen in the Amiga frame buffer at the time of the last
+   SetPanning call.  */
+static uaecptr oldscr;
+
+static uae_u32 p2ctab[256][2];
+
+/*
+ * Debugging dumps
+ */
+
+static void DumpModeInfoStructure (uaecptr amigamodeinfoptr)
+{
+    write_log ("ModeInfo Structure Dump:\n");
+    write_log ("  Node.ln_Succ  = 0x%x\n", get_long (amigamodeinfoptr));
+    write_log ("  Node.ln_Pred  = 0x%x\n", get_long (amigamodeinfoptr + 4));
+    write_log ("  Node.ln_Type  = 0x%x\n", get_byte (amigamodeinfoptr + 8));
+    write_log ("  Node.ln_Pri   = %d\n", get_byte (amigamodeinfoptr + 9));
+    /*write_log ("  Node.ln_Name  = %s\n", uaememptr->Node.ln_Name); */
+    write_log ("  OpenCount     = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_OpenCount));
+    write_log ("  Active        = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_Active));
+    write_log ("  Width         = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_Width));
+    write_log ("  Height        = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_Height));
+    write_log ("  Depth         = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_Depth));
+    write_log ("  Flags         = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_Flags));
+    write_log ("  HorTotal      = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorTotal));
+    write_log ("  HorBlankSize  = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorBlankSize));
+    write_log ("  HorSyncStart  = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorSyncStart));
+    write_log ("  HorSyncSize   = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorSyncSize));
+    write_log ("  HorSyncSkew   = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_HorSyncSkew));
+    write_log ("  HorEnableSkew = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_HorEnableSkew));
+    write_log ("  VerTotal      = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerTotal));
+    write_log ("  VerBlankSize  = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerBlankSize));
+    write_log ("  VerSyncStart  = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerSyncStart));
+    write_log ("  VerSyncSize   = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerSyncSize));
+    write_log ("  Clock         = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_first_union));
+    write_log ("  ClockDivide   = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_second_union));
+    write_log ("  PixelClock    = %d\n", get_long (amigamodeinfoptr + PSSO_ModeInfo_PixelClock));
+}
+
+static void DumpLibResolutionStructure (uaecptr amigalibresptr)
+{
+    int i;
+    uaecptr amigamodeinfoptr;
+    struct LibResolution *uaememptr = (struct LibResolution *) get_mem_bank (amigalibresptr).xlateaddr (amigalibresptr);
+
+    return;
+
+    write_log ("LibResolution Structure Dump:\n");
+
+    if (get_long (amigalibresptr + PSSO_LibResolution_DisplayID) == 0xFFFFFFFF) {
+       write_log ("  Finished With LibResolutions...\n");
+    } else {
+       write_log ("  Name      = %s\n", uaememptr->P96ID);
+       write_log ("  DisplayID = 0x%x\n", get_long (amigalibresptr + PSSO_LibResolution_DisplayID));
+       write_log ("  Width     = %d\n", get_word (amigalibresptr + PSSO_LibResolution_Width));
+       write_log ("  Height    = %d\n", get_word (amigalibresptr + PSSO_LibResolution_Height));
+       write_log ("  Flags     = %d\n", get_word (amigalibresptr + PSSO_LibResolution_Flags));
+       for (i = 0; i < MAXMODES; i++) {
+           amigamodeinfoptr = get_long (amigalibresptr + PSSO_LibResolution_Modes + i * 4);
+           write_log ("  ModeInfo[%d] = 0x%x\n", i, amigamodeinfoptr);
+           if (amigamodeinfoptr)
+               DumpModeInfoStructure (amigamodeinfoptr);
+       }
+       write_log ("  BoardInfo = 0x%x\n", get_long (amigalibresptr + PSSO_LibResolution_BoardInfo));
+    }
+}
+
+static char binary_byte[9];
+
+static char *BuildBinaryString (uae_u8 value)
+{
+    int i;
+    for (i = 0; i < 8; i++) {
+       binary_byte[i] = (value & (1 << (7 - i))) ? '#' : '.';
+    }
+    binary_byte[8] = '\0';
+    return binary_byte;
+}
+
+static void DumpPattern (struct Pattern *patt)
+{
+/*
+    uae_u8 *mem;
+    int row, col;
+    for (row = 0; row < (1 << patt->Size); row++) {
+       mem = patt->Memory + row * 2;
+       for (col = 0; col < 2; col++) {
+           write_log ("%s", BuildBinaryString (*mem++));
+       }
+       write_log ("\n");
+    }
+*/
+}
+
+static void DumpTemplate (struct Template *tmp, uae_u16 w, uae_u16 h)
+{
+/*
+    uae_u8 *mem = tmp->Memory;
+    int row, col, width;
+    width = (w + 7) >> 3;
+    write_log ("xoffset = %d, bpr = %d\n", tmp->XOffset, tmp->BytesPerRow);
+    for (row = 0; row < h; row++) {
+       mem = tmp->Memory + row * tmp->BytesPerRow;
+       for (col = 0; col < width; col++) {
+           write_log ("%s", BuildBinaryString (*mem++));
+       }
+       write_log ("\n");
+    }
+*/
+  }
+
+int picasso_nr_resolutions (void)
+{
+    return mode_count;
+}
+
+static void ShowSupportedResolutions (void)
+{
+    int i;
+
+    return;
+
+    for (i = 0; i < mode_count; i++)
+       write_log ("%s\n", DisplayModes[i].name);
+}
+
+static uae_u8 GetBytesPerPixel (uae_u32 RGBfmt)
+{
+    switch (RGBfmt) {
+    case RGBFB_CLUT:
+       return 1;
+
+    case RGBFB_A8R8G8B8:
+    case RGBFB_A8B8G8R8:
+    case RGBFB_R8G8B8A8:
+    case RGBFB_B8G8R8A8:
+       return 4;
+
+    case RGBFB_B8G8R8:
+    case RGBFB_R8G8B8:
+       return 3;
+
+    case RGBFB_R5G5B5:
+    case RGBFB_R5G6B5:
+    case RGBFB_R5G6B5PC:
+    case RGBFB_R5G5B5PC:
+    case RGBFB_B5G6R5PC:
+    case RGBFB_B5G5R5PC:
+       return 2;
+    default:
+       write_log ("ERROR - GetBytesPerPixel() was unsuccessful with 0x%x?!\n", RGBfmt);
+       return 0;
+    }
+}
+
+/*
+ * Amiga <-> native structure conversion functions
+ */
+
+static int CopyRenderInfoStructureA2U (uaecptr amigamemptr, struct RenderInfo *ri)
+{
+    uaecptr memp = get_long (amigamemptr + PSSO_RenderInfo_Memory);
+
+    if (valid_address (memp, PSSO_RenderInfo_sizeof)) {
+       ri->AMemory=memp;
+       ri->Memory = get_real_address (memp);
+       ri->BytesPerRow = get_word (amigamemptr + PSSO_RenderInfo_BytesPerRow);
+       ri->RGBFormat = get_long (amigamemptr + PSSO_RenderInfo_RGBFormat);
+       return 1;
+    }
+    write_log ("ERROR - Invalid RenderInfo memory area...\n");
+    return 0;
+}
+
+static int CopyPatternStructureA2U (uaecptr amigamemptr, struct Pattern *pattern)
+{
+    uaecptr memp = get_long (amigamemptr + PSSO_Pattern_Memory);
+    if (valid_address (memp, PSSO_Pattern_sizeof)) {
+       pattern->Memory = get_real_address (memp);
+       pattern->XOffset = get_word (amigamemptr + PSSO_Pattern_XOffset);
+       pattern->YOffset = get_word (amigamemptr + PSSO_Pattern_YOffset);
+       pattern->FgPen = get_long (amigamemptr + PSSO_Pattern_FgPen);
+       pattern->BgPen = get_long (amigamemptr + PSSO_Pattern_BgPen);
+       pattern->Size = get_byte (amigamemptr + PSSO_Pattern_Size);
+       pattern->DrawMode = get_byte (amigamemptr + PSSO_Pattern_DrawMode);
+       return 1;
+    }
+    write_log ("ERROR - Invalid Pattern memory area...\n");
+    return 0;
+}
+
+static void CopyColorIndexMappingA2U (uaecptr amigamemptr, struct ColorIndexMapping *cim)
+{
+    int i;
+    cim->ColorMask = get_long (amigamemptr);
+    for (i = 0; i < 256; i++, amigamemptr += 4)
+       cim->Colors[i] = get_long (amigamemptr + 4);
+}
+
+static int CopyBitMapStructureA2U (uaecptr amigamemptr, struct BitMap *bm)
+{
+    int i;
+
+    bm->BytesPerRow = get_word (amigamemptr + PSSO_BitMap_BytesPerRow);
+    bm->Rows = get_word (amigamemptr + PSSO_BitMap_Rows);
+    bm->Flags = get_byte (amigamemptr + PSSO_BitMap_Flags);
+    bm->Depth = get_byte (amigamemptr + PSSO_BitMap_Depth);
+
+    for (i = 0; i < bm->Depth; i++) {
+       uaecptr plane = get_long (amigamemptr + PSSO_BitMap_Planes + i * 4);
+       switch (plane) {
+       case 0:
+           bm->Planes[i] = &all_zeros_bitmap;
+           break;
+       case 0xFFFFFFFF:
+           bm->Planes[i] = &all_ones_bitmap;
+           break;
+       default:
+           if (valid_address (plane, bm->BytesPerRow * bm->Rows))
+               bm->Planes[i] = get_real_address (plane);
+           else
+               return 0;
+           break;
+       }
+    }
+    return 1;
+}
+
+static int CopyTemplateStructureA2U (uaecptr amigamemptr, struct Template *tmpl)
+{
+    uaecptr memp = get_long (amigamemptr + PSSO_Template_Memory);
+
+    if (valid_address (memp, 1 /* FIXME */ )) {
+       tmpl->Memory = get_real_address (memp);
+       tmpl->BytesPerRow = get_word (amigamemptr + PSSO_Template_BytesPerRow);
+       tmpl->XOffset = get_byte (amigamemptr + PSSO_Template_XOffset);
+       tmpl->DrawMode = get_byte (amigamemptr + PSSO_Template_DrawMode);
+       tmpl->FgPen = get_long (amigamemptr + PSSO_Template_FgPen);
+       tmpl->BgPen = get_long (amigamemptr + PSSO_Template_BgPen);
+       return 1;
+    }
+    write_log ("ERROR - Invalid Template memory area...\n");
+    return 0;
+}
+
+static void CopyLibResolutionStructureU2A (struct LibResolution *libres, uaecptr amigamemptr)
+{
+    char *uaememptr = 0;
+    int i;
+
+    uaememptr = gfxmem_xlate (amigamemptr);    /* I know that amigamemptr is inside my gfxmem chunk, so I can just do the xlate() */
+    memset (uaememptr, 0, PSSO_LibResolution_sizeof);  /* zero out our LibResolution structure */
+    strcpy (uaememptr + PSSO_LibResolution_P96ID, libres->P96ID);
+    put_long (amigamemptr + PSSO_LibResolution_DisplayID, libres->DisplayID);
+    put_word (amigamemptr + PSSO_LibResolution_Width, libres->Width);
+    put_word (amigamemptr + PSSO_LibResolution_Height, libres->Height);
+    put_word (amigamemptr + PSSO_LibResolution_Flags, libres->Flags);
+    for (i = 0; i < MAXMODES; i++)
+       put_long (amigamemptr + PSSO_LibResolution_Modes + i * 4, libres->Modes[i]);
+#if 0
+    put_long (amigamemptr, libres->Node.ln_Succ);
+    put_long (amigamemptr + 4, libres->Node.ln_Pred);
+    put_byte (amigamemptr + 8, libres->Node.ln_Type);
+    put_byte (amigamemptr + 9, libres->Node.ln_Pri);
+#endif
+    put_long (amigamemptr + 10, amigamemptr + PSSO_LibResolution_P96ID);
+    put_long (amigamemptr + PSSO_LibResolution_BoardInfo, libres->BoardInfo);
+}
+
+/* list is Amiga address of list, in correct endian format for UAE
+ * node is Amiga address of node, in correct endian format for UAE */
+static void AmigaListAddTail (uaecptr list, uaecptr node)
+{
+    uaecptr amigamemptr = 0;
+
+    if (get_long (list + 8) == list) {
+       /* Empty list - set it up */
+       put_long (list, node);  /* point the lh_Head to our new node */
+       put_long (list + 4, 0); /* set the lh_Tail to NULL */
+       put_long (list + 8, node);      /* point the lh_TailPred to our new node */
+
+       /* Adjust the new node - don't rely on it being zeroed out */
+       put_long (node, 0);     /* ln_Succ */
+       put_long (node + 4, 0); /* ln_Pred */
+    } else {
+       amigamemptr = get_long (list + 8);      /* get the lh_TailPred contents */
+
+       put_long (list + 8, node);      /* point the lh_TailPred to our new node */
+
+       /* Adjust the previous lh_TailPred node */
+       put_long (amigamemptr, node);   /* point the ln_Succ to our new node */
+
+       /* Adjust the new node - don't rely on it being zeroed out */
+       put_long (node, 0);     /* ln_Succ */
+       put_long (node + 4, amigamemptr);       /* ln_Pred */
+    }
+}
+
+/*
+ * Functions to perform an action on the real screen
+ */
+
+/*
+ * Fill a rectangle on the screen.  src points to the start of a line of the
+ * filled rectangle in the frame buffer; it can be used as a memcpy source if
+ * there is no OS specific function to fill the rectangle.
+ */
+
+static void do_fillrect (uae_u8 *src, int x, int y, int width, int height,
+                        uae_u32 pen, int Bpp, RGBFTYPE rgbtype)
+{
+    uae_u8 *dst;
+
+    P96TRACE (("do_fillrect (src:%08x x:%d y:%d w:%d h%d pen:%08x)\n", src, x, y, width, height, pen));
+
+    /* Clipping.  */
+    x -= picasso96_state.XOffset;
+    y -= picasso96_state.YOffset;
+    if (x < 0) {
+       width += x;
+       x = 0;
+    }
+    if (y < 0) {
+       height += y;
+       y = 0;
+    }
+    if (x + width > picasso96_state.Width)
+       width = picasso96_state.Width - x;
+    if (y + height > picasso96_state.Height)
+       height = picasso96_state.Height - y;
+
+    if (width <= 0 || height <= 0)
+       return;
+
+    /* Try OS specific fillrect function here; and return if successful.  Make sure we adjust for
+     * the pen values if we're doing 8-bit display-emulation on a 16-bit or higher screen. */
+    if (picasso_vidinfo.rgbformat == picasso96_state.RGBFormat) {
+#      ifndef WORDS_BIGENDIAN
+            if (Bpp > 1)
+               pen = (pen & 0x000000FF) << 24
+                   | (pen & 0x0000FF00) << 8
+                   | (pen & 0x00FF0000) >> 8
+                   | (pen & 0xFF000000) >> 24;
+#      endif
+        if (DX_Fill (x, y, width, height, pen, rgbtype))
+            return;
+    } else {
+       if (DX_Fill (x, y, width, height, picasso_vidinfo.clut[src[0]], rgbtype))
+            return;
+    }
+
+    P96TRACE ("P96_WARNING: do_fillrect() using fall-back routine!\n");
+
+    DX_Invalidate (y, y + height - 1);
+    if (!picasso_vidinfo.extra_mem)
+       return;
+
+    width *= picasso96_state.BytesPerPixel;
+    dst = gfx_lock_picasso ();
+    if (!dst)
+       goto out;
+
+    dst += y * picasso_vidinfo.rowbytes + x * picasso_vidinfo.pixbytes;
+    if (picasso_vidinfo.rgbformat == picasso96_state.RGBFormat) {
+       if (Bpp == 1) {
+           while (height-- > 0) {
+               memset (dst, pen, width);
+               dst += picasso_vidinfo.rowbytes;
+           }
+       } else {
+           while (height-- > 0) {
+               memcpy (dst, src, width);
+               dst += picasso_vidinfo.rowbytes;
+           }
+       }
+    } else {
+       int psiz = GetBytesPerPixel (picasso_vidinfo.rgbformat);
+       if (picasso96_state.RGBFormat != RGBFB_CHUNKY)
+           abort ();
+
+       while (height-- > 0) {
+           int i;
+           switch (psiz) {
+           case 2:
+               for (i = 0; i < width; i++)
+                   *((uae_u16 *) dst + i) = picasso_vidinfo.clut[src[i]];
+               break;
+           case 4:
+               for (i = 0; i < width; i++)
+                   *((uae_u32 *) dst + i) = picasso_vidinfo.clut[src[i]];
+               break;
+           default:
+               abort ();
+           }
+           dst += picasso_vidinfo.rowbytes;
+       }
+    }
+  out:
+    gfx_unlock_picasso ();
+}
+
+/*
+ * This routine modifies the real screen buffer after a blit has been
+ * performed in the save area. If can_do_blit is nonzero, the blit can
+ * be performed within the real screen buffer; otherwise, this routine
+ * must do it by hand using the data in the save area, pointed to by
+ * srcp.
+ */
+
+static void do_blit (struct RenderInfo *ri, int Bpp, int srcx, int srcy,
+                    int dstx, int dsty, int width, int height,
+                    BLIT_OPCODE opcode, int can_do_blit)
+{
+    int xoff = picasso96_state.XOffset;
+    int yoff = picasso96_state.YOffset;
+    uae_u8 *srcp, *dstp;
+
+//    write_log ("do_blit (sx:%d sy:%d op:%d cando:%d)\n", srcx, srcy, opcode, can_do_blit);
+    /* Clipping.  */
+    dstx -= xoff;
+    dsty -= yoff;
+    if (srcy < yoff || srcx < xoff
+       || srcx - xoff + width > picasso96_state.Width
+       || srcy - yoff + height > picasso96_state.Height)
+    {
+       can_do_blit = 0;
+    }
+    if (dstx < 0) {
+       srcx -= dstx;
+       width += dstx;
+       dstx = 0;
+    }
+    if (dsty < 0) {
+       srcy -= dsty;
+       height += dsty;
+       dsty = 0;
+    }
+    if (dstx + width > picasso96_state.Width)
+       width = picasso96_state.Width - dstx;
+    if (dsty + height > picasso96_state.Height)
+       height = picasso96_state.Height - dsty;
+    if (width <= 0 || height <= 0)
+       return;
+
+    /* If this RenderInfo points at something else than the currently visible
+     * screen, we must ignore the blit.  */
+    if (can_do_blit) {
+       /*
+        * Call OS blitting function that can do it in video memory.
+        * Should return if it was successful
+        */
+        if (DX_Blit (srcx, srcy, dstx, dsty, width, height, opcode))
+           return;
+    }
+
+    /* If no OS blit available, we do a copy from the P96 framebuffer in Amiga
+       memory to the host's frame buffer.  */
+
+    DX_Invalidate (dsty, dsty + height - 1);
+    if (!picasso_vidinfo.extra_mem)
+       return;
+
+    dstp = gfx_lock_picasso ();
+    if (dstp == 0)
+       goto out;
+    dstp += dsty * picasso_vidinfo.rowbytes + dstx * picasso_vidinfo.pixbytes;
+    P96TRACE(("do_blit with srcp 0x%x, dstp 0x%x, dst_rowbytes %d, srcx %d, srcy %d, dstx %d, dsty %d, w %d, h %d, dst_pixbytes %d\n",
+        srcp, dstp, picasso_vidinfo.rowbytes, srcx, srcy, dstx, dsty, width, height, picasso_vidinfo.pixbytes));
+    P96TRACE(("gfxmem is at 0x%x\n",gfxmemory));
+
+    srcp = ri->Memory + srcx * Bpp + srcy * ri->BytesPerRow;
+    DX_Invalidate (dsty, dsty + height - 1);
+   
+    if (picasso_vidinfo.rgbformat == picasso96_state.RGBFormat) {
+       width *= Bpp;
+       while (height-- > 0) {
+           memcpy (dstp, srcp, width);
+           srcp += ri->BytesPerRow;
+           dstp += picasso_vidinfo.rowbytes;
+       }
+    } else {
+       int psiz = GetBytesPerPixel (picasso_vidinfo.rgbformat);
+       if (picasso96_state.RGBFormat != RGBFB_CHUNKY)
+           abort ();
+
+       while (height-- > 0) {
+           int i;
+           switch (psiz) {
+           case 2:
+               for (i = 0; i < width; i++)
+                   *((uae_u16 *) dstp + i) = picasso_vidinfo.clut[srcp[i]];
+               break;
+           case 4:
+               for (i = 0; i < width; i++)
+                   *((uae_u32 *) dstp + i) = picasso_vidinfo.clut[srcp[i]];
+               break;
+           default:
+               abort ();
+           }
+           srcp += ri->BytesPerRow;
+           dstp += picasso_vidinfo.rowbytes;
+       }
+    }
+  out:
+    gfx_unlock_picasso ();
+}
+
+/*
+ * Invert a rectangle on the screen.
+ */
+
+static void do_invertrect (struct RenderInfo *ri, int Bpp, int x, int y, int width, int height)
+{
+#if 0
+    /* Clipping.  */
+    x -= picasso96_state.XOffset;
+    y -= picasso96_state.YOffset;
+    if (x < 0) {
+       width += x;
+       x = 0;
+    }
+    if (y < 0) {
+       height += y;
+       y = 0;
+    }
+    if (x + width > picasso96_state.Width)
+       width = picasso96_state.Width - x;
+    if (y + height > picasso96_state.Height)
+       height = picasso96_state.Height - y;
+
+    if (width <= 0 || height <= 0)
+       return;
+
+#endif
+    /* TODO: Try OS specific invertrect function here; and return if successful.  */
+
+    do_blit (ri, Bpp, x, y, x, y, width, height, BLIT_SRC, 0);
+}
+
+static uaecptr wgfx_linestart;
+static uaecptr wgfx_lineend;
+static uaecptr wgfx_min, wgfx_max;
+static long wgfx_y;
+
+static void wgfx_do_flushline (void)
+{
+    int src_y = wgfx_y;
+    long x0, x1, width;
+    uae_u8 *src, *dstp;
+    int Bpp = GetBytesPerPixel (picasso_vidinfo.rgbformat);
+    int fb_bpp = picasso96_state.BytesPerPixel;
+
+    wgfx_y -= picasso96_state.YOffset;
+    if (wgfx_y < 0 || wgfx_y >= picasso96_state.Height)
+       goto out1;
+
+    DX_Invalidate (wgfx_y, wgfx_y);
+    if (!picasso_vidinfo.extra_mem)
+       goto out1;
+
+    x0 = wgfx_min - wgfx_linestart;
+    width = wgfx_max - wgfx_min;
+    x0 -= picasso96_state.XOffset * fb_bpp;
+    if (x0 < 0) {
+       width += x0;
+       wgfx_min += x0;
+       x0 = 0;
+    }
+    if (x0 + width > picasso96_state.Width * fb_bpp)
+       width = picasso96_state.Width * fb_bpp - x0;
+
+    dstp = gfx_lock_picasso ();
+    if (dstp == 0)
+       goto out;
+
+    P96TRACE(("flushing %d\n", wgfx_y));
+    src = gfxmemory + wgfx_min;
+
+    if (picasso_vidinfo.rgbformat == picasso96_state.RGBFormat) {
+       dstp += wgfx_y * picasso_vidinfo.rowbytes + x0;
+       memcpy (dstp, src, width);
+    } else {
+       int i;
+
+       if (picasso96_state.RGBFormat != RGBFB_CHUNKY)
+           abort ();
+
+       dstp += wgfx_y * picasso_vidinfo.rowbytes + x0 * Bpp;
+       switch (Bpp) {
+       case 2:
+           for (i = 0; i < width; i++)
+               *((uae_u16 *) dstp + i) = picasso_vidinfo.clut[src[i]];
+           break;
+       case 4:
+           for (i = 0; i < width; i++)
+               *((uae_u32 *) dstp + i) = picasso_vidinfo.clut[src[i]];
+           break;
+       default:
+           abort ();
+       }
+    }
+
+  out:
+    gfx_unlock_picasso ();
+  out1:
+    wgfx_linestart = 0xFFFFFFFF;
+}
+
+STATIC_INLINE void wgfx_flushline (void)
+{
+    if (wgfx_linestart == 0xFFFFFFFF || !picasso_on)
+       return;
+    wgfx_do_flushline ();
+}
+
+static int renderinfo_is_current_screen (struct RenderInfo *ri)
+{
+    if (!picasso_on)
+       return 0;
+    if (ri->Memory != gfxmemory + (picasso96_state.Address - gfxmem_start))
+       return 0;
+
+    return 1;
+}
+
+/* Clear our screen, since we've got a new Picasso screen-mode, and refresh with the proper contents
+ * This is called on several occasions:
+ * 1. Amiga-->Picasso transition, via SetSwitch()
+ * 2. Picasso-->Picasso transition, via SetPanning().
+ * 3. whenever the graphics code notifies us that the screen contents have been lost.
+ */
+extern unsigned int new_beamcon0;
+
+void picasso_refresh (int call_setpalette)
+{
+    struct RenderInfo ri;
+
+    if (!picasso_on)
+       return;
+
+    { // for higher P96 mousedraw rate
+       extern uae_u16 vtotal;
+       if (p96hack_vpos2) {
+           vtotal = p96hack_vpos2;
+           new_beamcon0 |= 0x80;
+           p96refresh_active=1;
+       } else new_beamcon0 |= 0x20;
+    }
+
+#ifdef JIT
+    have_done_picasso=1;
+#endif
+
+    /* Make sure that the first time we show a Picasso video mode, we don't blit any crap.
+     * We can do this by checking if we have an Address yet.  */
+    if (picasso96_state.Address) {
+       unsigned int width, height;
+       /* blit the stuff from our static frame-buffer to the gfx-card */
+       ri.Memory = gfxmemory + (picasso96_state.Address - gfxmem_start);
+       ri.BytesPerRow = picasso96_state.BytesPerRow;
+       ri.RGBFormat = picasso96_state.RGBFormat;
+
+        if (set_panning_called) {
+           width = picasso96_state.VirtualWidth;
+           height = picasso96_state.VirtualHeight;
+       } else {
+           width = picasso96_state.Width;
+           height = picasso96_state.Height;
+       }
+
+       do_blit (&ri, picasso96_state.BytesPerPixel, 0, 0, 0, 0, width, height, BLIT_SRC, 0);
+    } else
+       write_log ("ERROR - picasso_refresh() can't refresh!\n");
+}
+
+/*
+* Functions to perform an action on the frame-buffer
+*/
+STATIC_INLINE void do_blitrect_frame_buffer (struct RenderInfo *ri,
+                                            struct RenderInfo *dstri,
+                                            unsigned long srcx, unsigned long srcy,
+                                            unsigned long dstx, unsigned long dsty,
+                                            unsigned long width, unsigned long height,
+                                            uae_u8 mask, BLIT_OPCODE opcode)
+{
+    uae_u8 *src, *dst, *tmp, *tmp2, *tmp3;
+    uae_u8 Bpp = GetBytesPerPixel (ri->RGBFormat);
+    unsigned long total_width = width * Bpp;
+    unsigned long linewidth = (total_width + 15) & ~15;
+    unsigned long lines;
+    int can_do_visible_blit = 0;
+
+    src = ri->Memory + srcx*Bpp + srcy*ri->BytesPerRow;
+    dst = dstri->Memory + dstx*Bpp + dsty*dstri->BytesPerRow;
+
+    if (mask != 0xFF && Bpp > 1) {
+       write_log ("WARNING - BlitRect() has mask 0x%x with Bpp %d.\n", mask, Bpp);
+    }
+
+    if (mask == 0xFF || Bpp > 1) {
+       if( opcode == BLIT_SRC ) {
+           /* handle normal case efficiently */
+           if (ri->Memory == dstri->Memory && dsty == srcy) {
+               unsigned long i;
+               for (i = 0; i < height; i++, src += ri->BytesPerRow, dst += dstri->BytesPerRow)
+                   memmove (dst, src, total_width);
+           } else if (dsty < srcy) {
+               unsigned long i;
+               for (i = 0; i < height; i++, src += ri->BytesPerRow, dst += dstri->BytesPerRow)
+                   memcpy (dst, src, total_width);
+           } else {
+               unsigned long i;
+               src += (height-1) * ri->BytesPerRow;
+               dst += (height-1) * dstri->BytesPerRow;
+               for (i = 0; i < height; i++, src -= ri->BytesPerRow, dst -= dstri->BytesPerRow)
+                   memcpy (dst, src, total_width);
+           }
+           return;
+       } else {
+           uae_u8  *src2 = src;
+           uae_u8  *dst2 = dst;
+           uae_u32 *src2_32 = (uae_u32*)src;
+           uae_u32 *dst2_32 = (uae_u32*)dst;
+           unsigned int y;
+
+           for (y = 0; y < height; y++) {
+               int bound = src + total_width - 4;
+                   //copy now the longs
+                   for( src2_32 = src, dst2_32 = dst; src2_32 < bound; src2_32++, dst2_32++ ) {
+                       switch( opcode ) {
+                           case BLIT_FALSE:
+                               *dst2_32 = 0;
+                               break;
+                           case BLIT_NOR:
+                               *dst2_32 = ~(*src2_32 | *dst2_32);
+                               break;
+                           case BLIT_ONLYDST:
+                               *dst2_32 = *dst2_32 & ~(*src2_32);
+                               break;
+                           case BLIT_NOTSRC:
+                               *dst2_32 = ~(*src2_32);
+                               break;
+                           case BLIT_ONLYSRC:
+                               *dst2_32 = *src2_32 & ~(*dst2_32);
+                               break;
+                           case BLIT_NOTDST:
+                               *dst2_32 = ~(*dst2_32);
+                               break;
+                           case BLIT_EOR:
+                               *dst2_32 = *src2_32 ^ *dst2_32;
+                               break;
+                           case BLIT_NAND:
+                               *dst2_32 = ~(*src2_32 & *dst2_32);
+                               break;
+                           case BLIT_AND:
+                               *dst2_32 = *src2_32 & *dst2_32;
+                               break;
+                           case BLIT_NEOR:
+                               *dst2_32 = ~(*src2_32 ^ *dst2_32);
+                               break;
+                           case BLIT_DST:
+                               write_log( "do_blitrect_frame_buffer shouldn't get BLIT_DST!\n");
+                               break;
+                           case BLIT_NOTONLYSRC:
+                               *dst2_32 = ~(*src2_32) | *dst2_32;
+                               break;
+                           case BLIT_SRC:
+                               write_log( "do_blitrect_frame_buffer shouldn't get BLIT_SRC!\n");
+                               break;
+                           case BLIT_NOTONLYDST:
+                               *dst2_32 = ~(*dst2_32) | *src2_32;
+                               break;
+                           case BLIT_OR:
+                               *dst2_32 = *src2_32 | *dst2_32;
+                               break;
+                           case BLIT_TRUE:
+                               *dst2_32 = 0xFFFFFFFF;
+                               break;
+                           case 30: //code for swap source with dest in byte
+                               {
+                                   uae_u32    temp;
+                                   temp =     *src2_32;
+                                   *src2_32 = *dst2_32;
+                                   *dst2_32 = temp;
+                               }
+                               break;
+                           case BLIT_LAST:
+                               write_log( "do_blitrect_frame_buffer shouldn't get BLIT_LAST!\n");
+                               break;
+                       } /* switch opcode */
+                   } // for end
+                   //now copy the rest few bytes
+                   for (src2 = src2_32, dst2 = dst2_32; src2 < src + total_width; src2++, dst2++ ) {
+                       switch( opcode ) {
+                           case BLIT_FALSE:
+                               *dst2 = 0;
+                               break;
+                           case BLIT_NOR:
+                               *dst2 = ~(*src2 | *dst2);
+                               break;
+                           case BLIT_ONLYDST:
+                               *dst2 = *dst2 & ~(*src2);
+                               break;
+                           case BLIT_NOTSRC:
+                               *dst2 = ~(*src2);
+                               break;
+                           case BLIT_ONLYSRC:
+                               *dst2 = *src2 & ~(*dst2);
+                               break;
+                           case BLIT_NOTDST:
+                               *dst2 = ~(*dst2);
+                               break;
+                           case BLIT_EOR:
+                               *dst2 = *src2 ^ *dst2;
+                               break;
+                           case BLIT_NAND:
+                               *dst2 = ~(*src2 & *dst2);
+                               break;
+                           case BLIT_AND:
+                               *dst2 = *src2 & *dst2;
+                               break;
+                           case BLIT_NEOR:
+                               *dst2 = ~(*src2 ^ *dst2);
+                               break;
+                           case BLIT_DST:
+                               write_log( "do_blitrect_frame_buffer shouldn't get BLIT_DST!\n");
+                               break;
+                           case BLIT_NOTONLYSRC:
+                               *dst2 = ~(*src2) | *dst2;
+                               break;
+                           case BLIT_SRC:
+                               write_log( "do_blitrect_frame_buffer shouldn't get BLIT_SRC!\n");
+                               break;
+                           case BLIT_NOTONLYDST:
+                               *dst2 = ~(*dst2) | *src2;
+                               break;
+                           case BLIT_OR:
+                               *dst2 = *src2 | *dst2;
+                               break;
+                           case BLIT_TRUE:
+                               *dst2 = 0xFF;
+                               break;
+                           case BLIT_LAST:
+                               write_log( "do_blitrect_frame_buffer shouldn't get BLIT_LAST!\n");
+                               break;
+                           case 30: //code for swap source with dest in long
+                               {
+                                   uae_u8 temp;
+                                   temp = *src2;
+                                   *src2 = *dst2;
+                                   *dst2 = temp;
+                               }
+                               break;
+                       } /* switch opcode */
+                   } /* for width */
+               src += ri->BytesPerRow;
+               dst += dstri->BytesPerRow;
+           } /* for height */
+       }
+        return;
+    }
+    // (mask != 0xFF && Bpp <= 1)
+    tmp3 = tmp2 = tmp = xmalloc (linewidth * height); /* allocate enough memory for the src-rect */
+    if (!tmp)
+       return;
+
+    /* copy the src-rect into our temporary buffer space */
+    for (lines = 0; lines < height; lines++, src += ri->BytesPerRow, tmp2 += linewidth)
+       memcpy (tmp2, src, total_width);
+
+    /* copy the temporary buffer to the destination */
+    for (lines = 0; lines < height; lines++, dst += dstri->BytesPerRow, tmp += linewidth) {
+       unsigned long cols;
+       for (cols = 0; cols < width; cols++) {
+           dst[cols] &= ~mask;
+           dst[cols] |= tmp[cols] & mask;
+       }
+    }
+    /* free the temp-buf */
+    free (tmp3);
+}
+
+/*
+ * BOOL FindCard(struct BoardInfo *bi);       and
+ *
+ * FindCard is called in the first stage of the board initialisation and
+ * configuration and is used to look if there is a free and unconfigured
+ * board of the type the driver is capable of managing. If it finds one,
+ * it immediately reserves it for use by Picasso96, usually by clearing
+ * the CDB_CONFIGME bit in the flags field of the ConfigDev struct of
+ * this expansion card. But this is only a common example, a driver can
+ * do whatever it wants to mark this card as used by the driver. This
+ * mechanism is intended to ensure that a board is only configured and
+ * used by one driver. FindBoard also usually fills some fields of the
+ * BoardInfo struct supplied by the caller, the rtg.library, for example
+ * the MemoryBase, MemorySize and RegisterBase fields.
+ */
+uae_u32 picasso_FindCard (void)
+{
+    uaecptr AmigaBoardInfo = m68k_areg (regs, 0);
+    /* NOTES: See BoardInfo struct definition in Picasso96 dev info */
+
+    if (allocated_gfxmem && !picasso96_state.CardFound) {
+       /* Fill in MemoryBase, MemorySize */
+       put_long (AmigaBoardInfo + PSSO_BoardInfo_MemoryBase, gfxmem_start);
+       /* size of memory, minus a 32K chunk: 16K for pattern bitmaps, 16K for resolution list */
+       put_long (AmigaBoardInfo + PSSO_BoardInfo_MemorySize, allocated_gfxmem - 32768);
+
+       picasso96_state.CardFound = 1;  /* mark our "card" as being found */
+       return -1;
+    } else
+       return 0;
+}
+
+static void FillBoardInfo (uaecptr amigamemptr, struct LibResolution *res, struct PicassoResolution *dm)
+{
+    char *uaememptr;
+    switch (dm->depth) {
+    case 1:
+       res->Modes[CHUNKY] = amigamemptr;
+       break;
+    case 2:
+       res->Modes[HICOLOR] = amigamemptr;
+       break;
+    case 3:
+       res->Modes[TRUECOLOR] = amigamemptr;
+       break;
+    default:
+       res->Modes[TRUEALPHA] = amigamemptr;
+       break;
+    }
+    uaememptr = gfxmem_xlate (amigamemptr);    /* I know that amigamemptr is inside my gfxmem chunk, so I can just do the xlate() */
+    memset (uaememptr, 0, PSSO_ModeInfo_sizeof);       /* zero out our ModeInfo struct */
+
+    put_word (amigamemptr + PSSO_ModeInfo_Width, dm->res.width);
+    put_word (amigamemptr + PSSO_ModeInfo_Height, dm->res.height);
+    put_byte (amigamemptr + PSSO_ModeInfo_Depth, dm->depth * 8);
+    put_byte (amigamemptr + PSSO_ModeInfo_Flags, 0);
+    put_word (amigamemptr + PSSO_ModeInfo_HorTotal, dm->res.width);
+    put_word (amigamemptr + PSSO_ModeInfo_HorBlankSize, 0);
+    put_word (amigamemptr + PSSO_ModeInfo_HorSyncStart, 0);
+    put_word (amigamemptr + PSSO_ModeInfo_HorSyncSize, 0);
+    put_byte (amigamemptr + PSSO_ModeInfo_HorSyncSkew, 0);
+    put_byte (amigamemptr + PSSO_ModeInfo_HorEnableSkew, 0);
+
+    put_word (amigamemptr + PSSO_ModeInfo_VerTotal, dm->res.height);
+    put_word (amigamemptr + PSSO_ModeInfo_VerBlankSize, 0);
+    put_word (amigamemptr + PSSO_ModeInfo_VerSyncStart, 0);
+    put_word (amigamemptr + PSSO_ModeInfo_VerSyncSize, 0);
+
+    put_byte (amigamemptr + PSSO_ModeInfo_first_union, 98);
+    put_byte (amigamemptr + PSSO_ModeInfo_second_union, 14);
+
+    put_long (amigamemptr + PSSO_ModeInfo_PixelClock, dm->res.width * dm->res.height * dm->refresh);
+}
+
+static uae_u32 AssignModeID (int i, int count)
+{
+    if (DisplayModes[i].res.width == 320 && DisplayModes[i].res.height == 200)
+       return 0x50001000;
+    else if (DisplayModes[i].res.width == 320 && DisplayModes[i].res.height == 240)
+       return 0x50011000;
+    else if (DisplayModes[i].res.width == 640 && DisplayModes[i].res.height == 400)
+       return 0x50021000;
+    else if (DisplayModes[i].res.width == 640 && DisplayModes[i].res.height == 480)
+       return 0x50031000;
+    else if (DisplayModes[i].res.width == 800 && DisplayModes[i].res.height == 600)
+       return 0x50041000;
+    else if (DisplayModes[i].res.width == 1024 && DisplayModes[i].res.height == 768)
+       return 0x50051000;
+    else if (DisplayModes[i].res.width == 1152 && DisplayModes[i].res.height == 864)
+       return 0x50061000;
+    else if (DisplayModes[i].res.width == 1280 && DisplayModes[i].res.height == 1024)
+       return 0x50071000;
+    else if (DisplayModes[i].res.width == 1600 && DisplayModes[i].res.height == 1280)
+       return 0x50081000;
+
+    return 0x50091000 + count * 0x10000;
+}
+
+/****************************************
+* InitCard()
+*
+* a2: BoardInfo structure ptr - Amiga-based address in Intel endian-format
+*
+* Job - fill in the following structure members:
+* gbi_RGBFormats: the pixel formats that the host-OS of UAE supports
+*     If UAE is running in a window, it should ONLY report the pixel format of the host-OS desktop
+*     If UAE is running full-screen, it should report ALL pixel formats that the host-OS can handle in full-screen
+*     NOTE: If full-screen, and the user toggles to windowed-mode, all hell will break loose visually.  Must inform
+*           user that they're doing something stupid (unless their desktop and full-screen colour modes match).
+* gbi_SoftSpriteFlags: should be the same as above for now, until actual cursor support is added
+* gbi_BitsPerCannon: could be 6 or 8 or ???, depending on the host-OS gfx-card
+* gbi_MaxHorResolution: fill this in for all modes (even if you don't support them)
+* gbi_MaxVerResolution: fill this in for all modes (even if you don't support them)
+*/
+uae_u32 picasso_InitCard (void)
+{
+    struct LibResolution res;
+    int i;
+    int ModeInfoStructureCount = 1, LibResolutionStructureCount = 0;
+    uaecptr amigamemptr = 0;
+    uaecptr AmigaBoardInfo = m68k_areg (regs, 2);
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_BitsPerCannon, DX_BitsPerCannon ());
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_RGBFormats, picasso96_pixel_format);
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_SoftSpriteFlags, picasso96_pixel_format);
+    put_long (AmigaBoardInfo + PSSO_BoardInfo_BoardType, BT_uaegfx);
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 0, planar.width);
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 2, chunky.width);
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 4, hicolour.width);
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 6, truecolour.width);
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 8, alphacolour.width);
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 0, planar.height);
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 2, chunky.height);
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 4, hicolour.height);
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 6, truecolour.height);
+    put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 8, alphacolour.height);
+
+    for (i = 0; i < mode_count;) {
+       int j = i;
+       /* Add a LibResolution structure to the ResolutionsList MinList in our BoardInfo */
+       res.DisplayID = AssignModeID (i, LibResolutionStructureCount);
+       res.BoardInfo = AmigaBoardInfo;
+       res.Width = DisplayModes[i].res.width;
+       res.Height = DisplayModes[i].res.height;
+       res.Flags = P96F_PUBLIC;
+       res.P96ID[0] = 'P';
+       res.P96ID[1] = '9';
+       res.P96ID[2] = '6';
+       res.P96ID[3] = '-';
+       res.P96ID[4] = '0';
+       res.P96ID[5] = ':';
+       strcpy (res.Name, "uaegfx:");
+       strncat (res.Name, DisplayModes[i].name, strchr (DisplayModes[i].name, ',') - DisplayModes[i].name);
+       res.Modes[PLANAR] = 0;
+       res.Modes[CHUNKY] = 0;
+       res.Modes[HICOLOR] = 0;
+       res.Modes[TRUECOLOR] = 0;
+       res.Modes[TRUEALPHA] = 0;
+
+       do {
+           /* Handle this display mode's depth */
+           /* Only add the modes when there is enough P96 RTG memory to hold the bitmap */
+           long required = DisplayModes[i].res.width * DisplayModes[i].res.height * DisplayModes[i].depth;
+           if (allocated_gfxmem - 32768 > required) {
+               amigamemptr = gfxmem_start + allocated_gfxmem - (PSSO_ModeInfo_sizeof * ModeInfoStructureCount++);
+               FillBoardInfo (amigamemptr, &res, &DisplayModes[i]);
+           }
+           i++;
+       } while (i < mode_count
+                && DisplayModes[i].res.width == DisplayModes[j].res.width
+                && DisplayModes[i].res.height == DisplayModes[j].res.height);
+
+       amigamemptr = gfxmem_start + allocated_gfxmem - 16384 + (PSSO_LibResolution_sizeof * LibResolutionStructureCount++);
+       CopyLibResolutionStructureU2A (&res, amigamemptr);
+       DumpLibResolutionStructure (amigamemptr);
+       AmigaListAddTail (AmigaBoardInfo + PSSO_BoardInfo_ResolutionsList, amigamemptr);
+    }
+
+    return 0;
+}
+
+extern int x_size, y_size;
+
+/*
+ * SetSwitch:
+ * a0: struct BoardInfo
+ * d0.w:       BOOL state
+ * this function should set a board switch to let the Amiga signal pass
+ * through when supplied with a 0 in d0 and to show the board signal if
+ * a 1 is passed in d0. You should remember the current state of the
+ * switch to avoid unneeded switching. If your board has no switch, then
+ * simply supply a function that does nothing except a RTS.
+ *
+ * NOTE: Return the opposite of the switch-state. BDK
+*/
+uae_u32 picasso_SetSwitch (void)
+{
+    uae_u16 flag = m68k_dreg (regs, 0) & 0xFFFF;
+
+    /* Do not switch immediately.  Tell the custom chip emulation about the
+     * desired state, and wait for custom.c to call picasso_enablescreen
+     * whenever it is ready to change the screen state.  */
+    picasso_requested_on = !!flag;
+#if 0
+    write_log ("SetSwitch() - trying to show %s screen\n", flag ? "picasso96" : "amiga");
+#endif
+
+    flush_icache(5);  /* Changing the screen mode might make gfx memory
+                        directly accessible, or no longer thus accessible */
+
+    /* Put old switch-state in D0 */
+    return !flag;
+}
+
+void picasso_enablescreen (int on)
+{
+    wgfx_linestart = 0xFFFFFFFF;
+    picasso_refresh (1);
+#if 0
+    write_log ("SetSwitch() - showing %s screen\n", on ? "picasso96" : "amiga");
+#endif
+}
+
+static int first_color_changed = 256;
+static int last_color_changed = -1;
+
+void picasso_handle_vsync (void)
+{
+    if (first_color_changed < last_color_changed) {
+       DX_SetPalette (first_color_changed, last_color_changed - first_color_changed);
+       /* If we're emulating a CLUT mode, we need to redraw the entire screen.  */
+       if (picasso_vidinfo.rgbformat != picasso96_state.RGBFormat)
+           picasso_refresh (1);
+    }
+
+    first_color_changed = 256;
+    last_color_changed = -1;
+}
+
+void picasso_clip_mouse (int *px, int *py)
+{
+    int xoff = picasso96_state.XOffset;
+    int yoff = picasso96_state.YOffset;
+    if (*px < -xoff)
+       *px = -xoff;
+    if (*px + xoff > picasso_vidinfo.width)
+       *px = picasso_vidinfo.width - xoff;
+    if (*py < -yoff)
+       *py = -yoff;
+    if (*py + yoff > picasso_vidinfo.height)
+       *py = picasso_vidinfo.height - yoff;
+}
+
+/*
+ * SetColorArray:
+ * a0: struct BoardInfo
+ * d0.w: startindex
+ * d1.w: count
+ * when this function is called, your driver has to fetch "count" color
+ * values starting at "startindex" from the CLUT field of the BoardInfo
+ * structure and write them to the hardware. The color values are always
+ * between 0 and 255 for each component regardless of the number of bits
+ * per cannon your board has. So you might have to shift the colors
+ * before writing them to the hardware.
+ */
+uae_u32 picasso_SetColorArray (void)
+{
+    /* Fill in some static UAE related structure about this new CLUT setting
+     * We need this for CLUT-based displays, and for mapping CLUT to hi/true colour */
+    uae_u16 start = m68k_dreg (regs, 0);
+    uae_u16 count = m68k_dreg (regs, 1);
+    int i;
+    uaecptr boardinfo = m68k_areg (regs, 0);
+    uaecptr clut = boardinfo + PSSO_BoardInfo_CLUT + start * 3;
+    int changed = 0;
+
+    for (i = start; i < start + count; i++) {
+       int r = get_byte (clut);
+       int g = get_byte (clut + 1);
+       int b = get_byte (clut + 2);
+
+       changed |= (picasso96_state.CLUT[i].Red != r || picasso96_state.CLUT[i].Green != g || picasso96_state.CLUT[i].Blue != b);
+
+       picasso96_state.CLUT[i].Red = r;
+       picasso96_state.CLUT[i].Green = g;
+       picasso96_state.CLUT[i].Blue = b;
+       clut += 3;
+    }
+    if (changed) {
+       if (start < first_color_changed)
+           first_color_changed = start;
+       if (start + count > last_color_changed)
+           last_color_changed = start + count;
+    }
+    /*write_log ("SetColorArray(%d,%d)\n", start, count); */
+    return 1;
+}
+
+/*
+ * SetDAC:
+ * a0: struct BoardInfo
+ * d7: RGBFTYPE RGBFormat
+ * This function is called whenever the RGB format of the display changes,
+ * e.g. from chunky to TrueColor. Usually, all you have to do is to set
+ * the RAMDAC of your board accordingly.
+ */
+uae_u32 picasso_SetDAC (void)
+{
+    /* Fill in some static UAE related structure about this new DAC setting
+     * Lets us keep track of what pixel format the Amiga is thinking about in our frame-buffer */
+
+    write_log ("SetDAC()\n");
+    return 1;
+}
+
+static void init_picasso_screen (void)
+{
+    int width = picasso96_state.Width;
+    int height = picasso96_state.Height;
+    int vwidth = picasso96_state.VirtualWidth;
+    int vheight = picasso96_state.VirtualHeight;
+    int xoff = 0;
+    int yoff = 0;
+
+    if (!set_gc_called)
+       return;
+
+    if (set_panning_called) {
+       picasso96_state.Extent = picasso96_state.Address + (picasso96_state.BytesPerRow * vheight);
+       xoff = picasso96_state.XOffset;
+       yoff = picasso96_state.YOffset;
+    }
+
+    gfx_set_picasso_modeinfo (width, height, picasso96_state.GC_Depth, picasso96_state.RGBFormat);
+    DX_SetPalette (0, 256);
+
+    wgfx_linestart = 0xFFFFFFFF;
+    picasso_refresh (1);
+}
+
+/*
+ * SetGC:
+ * a0: struct BoardInfo
+ * a1: struct ModeInfo
+ * d0: BOOL Border
+ * This function is called whenever another ModeInfo has to be set. This
+ * function simply sets up the CRTC and TS registers to generate the
+ * timing used for that screen mode. You should not set the DAC, clocks
+ * or linear start adress. They will be set when appropriate by their
+ * own functions.
+ */
+uae_u32 picasso_SetGC (void)
+{
+    /* Fill in some static UAE related structure about this new ModeInfo setting */
+    uaecptr modeinfo = m68k_areg (regs, 1);
+
+    picasso96_state.Width = get_word (modeinfo + PSSO_ModeInfo_Width);
+    picasso96_state.VirtualWidth = picasso96_state.Width;      /* in case SetPanning doesn't get called */
+
+    picasso96_state.Height = get_word (modeinfo + PSSO_ModeInfo_Height);
+    picasso96_state.VirtualHeight = picasso96_state.Height;
+
+    picasso96_state.GC_Depth = get_byte (modeinfo + PSSO_ModeInfo_Depth);
+    picasso96_state.GC_Flags = get_byte (modeinfo + PSSO_ModeInfo_Flags);
+
+    P96TRACE (("SetGC(%d,%d,%d)\n", picasso96_state.Width, picasso96_state.Height, picasso96_state.GC_Depth));
+
+    set_gc_called = 1;         /* @@@ when do we need to reset this? */
+    init_picasso_screen ();
+    return 1;
+}
+
+/*
+ * SetPanning:
+ * a0: struct BoardInfo
+ * a1: UBYTE *Memory
+ * d0: uae_u16 Width
+ * d1: WORD XOffset
+ * d2: WORD YOffset
+ * d7: RGBFTYPE RGBFormat
+ * This function sets the view origin of a display which might also be
+ * overscanned. In register a1 you get the start address of the screen
+ * bitmap on the Amiga side. You will have to subtract the starting
+ * address of the board memory from that value to get the memory start
+ * offset within the board. Then you get the offset in pixels of the
+ * left upper edge of the visible part of an overscanned display. From
+ * these values you will have to calculate the LinearStartingAddress
+ * fields of the CRTC registers.
+
+ * NOTE: SetPanning() can be used to know when a Picasso96 screen is
+ * being opened.  Better to do the appropriate clearing of the
+ * background here than in SetSwitch() derived functions,
+ * because SetSwitch() is not called for subsequent Picasso screens.
+ */
+uae_u32 picasso_SetPanning (void)
+{
+    uae_u16 Width = m68k_dreg (regs, 0);
+    uaecptr start_of_screen = m68k_areg (regs, 1);
+    uaecptr bi = m68k_areg (regs, 0);
+    uaecptr bmeptr = get_long (bi + PSSO_BoardInfo_BitMapExtra);        /* Get our BoardInfo ptr's BitMapExtra ptr */
+    int oldxoff = picasso96_state.XOffset;
+    int oldyoff = picasso96_state.YOffset;
+#if 0
+    /* @@@ This is in WinUAE, but it breaks things.  */
+    if (oldscr == 0) {
+       oldscr = start_of_screen;
+    }
+    if ((oldscr != start_of_screen)) {
+       set_gc_called = 0;
+       oldscr = start_of_screen;
+    }
+#endif
+
+    picasso96_state.Address = start_of_screen; /* Amiga-side address */
+    picasso96_state.XOffset = (uae_s16) m68k_dreg (regs, 1);
+    picasso96_state.YOffset = (uae_s16) m68k_dreg (regs, 2);
+    picasso96_state.VirtualWidth = get_word (bmeptr + PSSO_BitMapExtra_Width);
+    picasso96_state.VirtualHeight = get_word (bmeptr + PSSO_BitMapExtra_Height);
+    picasso96_state.RGBFormat = m68k_dreg (regs, 7);
+    picasso96_state.BytesPerPixel = GetBytesPerPixel (picasso96_state.RGBFormat);
+    picasso96_state.BytesPerRow = Width * picasso96_state.BytesPerPixel;
+
+    set_panning_called = 1;
+    P96TRACE (("SetPanning(%d, %d, %d) Start 0x%x, BPR %d\n",
+              Width, picasso96_state.XOffset, picasso96_state.YOffset, start_of_screen, picasso96_state.BytesPerRow));
+
+    init_picasso_screen ();
+
+    return 1;
+}
+
+static void do_xor8 (uae_u8 * ptr, long len, uae_u32 val)
+{
+    int i;
+#if 0 && defined ALIGN_POINTER_TO32
+    int align_adjust = ALIGN_POINTER_TO32 (ptr);
+    int len2;
+
+    len -= align_adjust;
+    while (align_adjust) {
+       *ptr ^= val;
+       ptr++;
+       align_adjust--;
+    }
+    len2 = len >> 2;
+    len -= len2 << 2;
+    for (i = 0; i < len2; i++, ptr += 4) {
+       *(uae_u32 *) ptr ^= val;
+    }
+    while (len) {
+       *ptr ^= val;
+       ptr++;
+       len--;
+    }
+    return;
+#endif
+    for (i = 0; i < len; i++, ptr++) {
+       do_put_mem_byte (ptr, do_get_mem_byte (ptr) ^ val);
+    }
+}
+
+/*
+ * InvertRect:
+ *
+ * Inputs:
+ * a0:struct BoardInfo *bi
+ * a1:struct RenderInfo *ri
+ * d0.w:X
+ * d1.w:Y
+ * d2.w:Width
+ * d3.w:Height
+ * d4.l:Mask
+ * d7.l:RGBFormat
+ *
+ * This function is used to invert a rectangular area on the board. It is called by BltBitMap,
+ * BltPattern and BltTemplate.
+ */
+uae_u32 picasso_InvertRect (void)
+{
+    uaecptr renderinfo = m68k_areg (regs, 1);
+    unsigned long X = (uae_u16)m68k_dreg (regs, 0);
+    unsigned long Y = (uae_u16)m68k_dreg (regs, 1);
+    unsigned long Width = (uae_u16)m68k_dreg (regs, 2);
+    unsigned long Height = (uae_u16)m68k_dreg (regs, 3);
+    uae_u8 mask = (uae_u8)m68k_dreg (regs, 4);
+    int Bpp = GetBytesPerPixel (m68k_dreg (regs, 7));
+    uae_u32 xorval;
+    unsigned int lines;
+    struct RenderInfo ri;
+    uae_u8 *uae_mem, *rectstart;
+    unsigned long width_in_bytes;
+    uae_u32 result = 0;
+
+    wgfx_flushline ();
+
+    if (CopyRenderInfoStructureA2U (renderinfo, &ri)) {
+       P96TRACE(("InvertRect %dbpp 0x%lx\n", Bpp, (long)mask));
+
+       if (mask != 0xFF && Bpp > 1)
+           mask = 0xFF;
+
+       xorval = 0x01010101 * (mask & 0xFF);
+       width_in_bytes = Bpp * Width;
+       rectstart = uae_mem = ri.Memory + Y*ri.BytesPerRow + X*Bpp;
+
+       for (lines = 0; lines < Height; lines++, uae_mem += ri.BytesPerRow)
+           do_xor8 (uae_mem, width_in_bytes, xorval);
+
+       if (renderinfo_is_current_screen (&ri)) {
+           if (mask == 0xFF)
+               do_invertrect (&ri, Bpp, X, Y, Width, Height);
+           else
+               do_blit( &ri, Bpp, X, Y, X, Y, Width, Height, BLIT_SRC, 0);
+        }
+        result = 1;
+    }
+    return result;
+}
+
+/*
+* Fill a rectangle in the screen.
+*/
+STATIC_INLINE void do_fillrect_frame_buffer (struct RenderInfo *ri, int X, int Y, int Width, int Height, uae_u32 Pen, int Bpp, RGBFTYPE RGBFormat)
+{
+    int cols;
+    uae_u8 *start, *oldstart;
+    uae_u8 *src, *dst;
+    int lines;
+
+    /* Do our virtual frame-buffer memory.  First, we do a single line fill by hand */
+    oldstart = start = src = ri->Memory + X * Bpp + Y * ri->BytesPerRow;
+
+    switch (Bpp) {
+       case 1:
+           memset (start, Pen, Width);
+           break;
+       case 2:
+           for (cols = 0; cols < Width; cols++) {
+               do_put_mem_word ((uae_u16 *)start, (uae_u16)Pen);
+               start += 2;
+           }
+           break;
+       case 3:
+           for (cols = 0; cols < Width; cols++) {
+               do_put_mem_byte (start, (uae_u8)Pen);
+               start++;
+               *(uae_u16 *)(start) = (Pen & 0x00FFFF00) >> 8;
+               start+=2;
+           }
+           break;
+       case 4:
+           for (cols = 0; cols < Width; cols++) {
+               do_put_mem_long ((uae_u32 *)start, Pen);
+               start += 4;
+           }
+           break;
+    } /* switch (Bpp) */
+
+    src = oldstart;
+    dst = src + ri->BytesPerRow;
+
+    /* next, we do the remaining line fills via memcpy() for > 1 BPP, otherwise some more memset() calls */
+    if (Bpp > 1) {
+       for (lines = 0; lines < (Height - 1); lines++, dst += ri->BytesPerRow)
+           memcpy (dst, src, Width * Bpp);
+    } else {
+       for (lines = 0; lines < (Height - 1); lines++, dst += ri->BytesPerRow)
+           memset( dst, Pen, Width );
+    }
+}
+
+/***********************************************************
+FillRect:
+***********************************************************
+* a0:  struct BoardInfo *
+* a1:  struct RenderInfo *
+* d0:  WORD X
+* d1:  WORD Y
+* d2:  WORD Width
+* d3:  WORD Height
+* d4:  uae_u32 Pen
+* d5:  UBYTE Mask
+* d7:  uae_u32 RGBFormat
+***********************************************************/
+uae_u32 picasso_FillRect (void)
+{
+    uaecptr renderinfo = m68k_areg (regs, 1);
+    uae_u32 X = (uae_u16)m68k_dreg (regs, 0);
+    uae_u32 Y = (uae_u16)m68k_dreg (regs, 1);
+    uae_u32 Width = (uae_u16)m68k_dreg (regs, 2);
+    uae_u32 Height = (uae_u16)m68k_dreg (regs, 3);
+    uae_u32 Pen = m68k_dreg (regs, 4);
+    uae_u8 Mask = (uae_u8)m68k_dreg (regs, 5);
+    RGBFTYPE RGBFormat = m68k_dreg (regs, 7);
+
+    uae_u8 *src;
+    uae_u8 *oldstart;
+    int Bpp;
+    struct RenderInfo ri;
+    uae_u32 result = 0;
+
+#ifdef JIT
+    special_mem|=picasso_is_special_read|picasso_is_special;
+#endif
+
+    wgfx_flushline ();
+
+    if (CopyRenderInfoStructureA2U (renderinfo, &ri) && Y != 0xFFFF) {
+       if (ri.RGBFormat != RGBFormat)
+           write_log ("Weird Stuff!\n");
+
+       Bpp = GetBytesPerPixel (RGBFormat);
+
+       P96TRACE(("FillRect(%d, %d, %d, %d) Pen 0x%x BPP %d BPR %d Mask 0x%x\n",
+           X, Y, Width, Height, Pen, Bpp, ri.BytesPerRow, Mask));
+
+       if (Bpp > 1)
+           Mask = 0xFF;
+
+       if (Mask == 0xFF) {
+           if ((Width == 1) || (Height == 1)) {
+               int i;
+               uaecptr addr;
+               if (renderinfo_is_current_screen (&ri)) {
+                    uae_u32 diff = gfxmem_start - (uae_u32)gfxmemory;
+                    addr = ri.Memory + X * Bpp + Y * ri.BytesPerRow + diff;
+
+                   if (Width == 1) {
+                       for (i = 0; i < Height; i++) {
+                           if( Bpp == 4 )
+                               gfxmem_lput (addr + (i * picasso96_state.BytesPerRow), Pen);
+                           else if (Bpp == 2)
+                               gfxmem_wput (addr + (i * picasso96_state.BytesPerRow), Pen);
+                           else
+                               gfxmem_bput (addr + (i * picasso96_state.BytesPerRow), Pen);
+                       }
+                   } else if (Height == 1) {
+                       for (i = 0; i < Width; i++) {
+                           if (Bpp == 4)
+                               gfxmem_lput (addr + (i*Bpp), Pen);
+                           else if (Bpp == 2)
+                               gfxmem_wput (addr + (i*Bpp), Pen);
+                           else
+                               gfxmem_bput( addr + (i*Bpp), Pen );
+                       }
+                   }
+                   return 1;
+               }
+           }
+
+           /* Do the fill-rect in the frame-buffer */
+           do_fillrect_frame_buffer (&ri, X, Y, Width, Height, Pen, Bpp, RGBFormat);
+
+           /* Now we do the on-screen display, if renderinfo points to it */
+           if (renderinfo_is_current_screen (&ri)) {
+               src = ri.Memory + X * Bpp + Y * ri.BytesPerRow;
+               X = X - picasso96_state.XOffset;
+               Y = Y - picasso96_state.YOffset;
+               if ((int)X < 0) {Width = Width + X; X=0;}
+               if ((int)Width < 1) return 1;
+               if ((int)Y < 0) {Height = Height + Y; Y=0;}
+               if ((int)Height < 1) return 1;
+
+               /* Argh - why does P96Speed do this to me, with FillRect only?! */
+               if ((X < picasso96_state.Width) && (Y < picasso96_state.Height)) {
+                   if (X + Width > picasso96_state.Width)
+                       Width = picasso96_state.Width - X;
+                   if (Y+Height > picasso96_state.Height)
+                       Height = picasso96_state.Height - Y;
+
+                   do_fillrect (src, X, Y, Width, Height, Pen, Bpp, RGBFormat);
+               }
+           }
+           result = 1;
+       } else {
+           /* We get here only if Mask != 0xFF */
+           if (Bpp != 1) {
+               write_log( "WARNING - FillRect() has unhandled mask 0x%x with Bpp %d. Using fall-back routine.\n", Mask, Bpp);
+           } else {
+               Pen &= Mask;
+               Mask = ~Mask;
+               oldstart = ri.Memory + Y * ri.BytesPerRow + X * Bpp;
+               {
+                   uae_u8 *start = oldstart;
+                   uae_u8 *end = start + Height * ri.BytesPerRow;
+                   for (; start != end; start += ri.BytesPerRow) {
+                       uae_u8 *p = start;
+                       unsigned long cols;
+                       for (cols = 0; cols < Width; cols++) {
+                           uae_u32 tmpval = do_get_mem_byte (p + cols) & Mask;
+                           do_put_mem_byte (p + cols, (uae_u8)(Pen | tmpval));
+                       }
+                   }
+               }
+               if (renderinfo_is_current_screen (&ri))
+                   do_blit( &ri, Bpp, X, Y, X, Y, Width, Height, BLIT_SRC, 0);
+               result = 1;
+           }
+        }
+    }
+    return result;
+}
+
+
+/*
+* BlitRect() is a generic (any chunky pixel format) rectangle copier
+* NOTE: If dstri is NULL, then we're only dealing with one RenderInfo area, and called from picasso_BlitRect()
+*
+* OpCodes:
+* 0 = FALSE:    dst = 0
+* 1 = NOR:      dst = ~(src | dst)
+* 2 = ONLYDST:  dst = dst & ~src
+* 3 = NOTSRC:   dst = ~src
+* 4 = ONLYSRC:  dst = src & ~dst
+* 5 = NOTDST:   dst = ~dst
+* 6 = EOR:      dst = src^dst
+* 7 = NAND:     dst = ~(src & dst)
+* 8 = AND:      dst = (src & dst)
+* 9 = NEOR:     dst = ~(src ^ dst)
+*10 = DST:      dst = dst
+*11 = NOTONLYSRC: dst = ~src | dst
+*12 = SRC:      dst = src
+*13 = NOTONLYDST: dst = ~dst | src
+*14 = OR:       dst = src | dst
+*15 = TRUE:     dst = 0xFF
+*/
+struct blitdata
+{
+    struct RenderInfo ri_struct;
+    struct RenderInfo dstri_struct;
+    struct RenderInfo *ri; /* Self-referencing pointers */
+    struct RenderInfo *dstri;
+    unsigned long srcx;
+    unsigned long srcy;
+    unsigned long dstx;
+    unsigned long dsty;
+    unsigned long width;
+    unsigned long height;
+    uae_u8 mask;
+    BLIT_OPCODE opcode;
+} blitrectdata;
+
+STATIC_INLINE int BlitRectHelper( void )
+{
+    struct RenderInfo *ri    = blitrectdata.ri;
+    struct RenderInfo *dstri = blitrectdata.dstri;
+    unsigned long srcx =   blitrectdata.srcx;
+    unsigned long srcy =   blitrectdata.srcy;
+    unsigned long dstx =   blitrectdata.dstx;
+    unsigned long dsty =   blitrectdata.dsty;
+    unsigned long width =  blitrectdata.width;
+    unsigned long height = blitrectdata.height;
+    uae_u8 mask = blitrectdata.mask;
+    BLIT_OPCODE opcode = blitrectdata.opcode;
+
+    uae_u8 Bpp = GetBytesPerPixel (ri->RGBFormat);
+    unsigned long total_width = width * Bpp;
+    unsigned long linewidth = (total_width + 15) & ~15;
+    int can_do_visible_blit = 0;
+
+    if (opcode == BLIT_DST) {
+        write_log( "WARNING: BlitRect() being called with opcode of BLIT_DST\n" );
+        return 1;
+    }
+
+    /*
+     * If we have no destination RenderInfo, then we're dealing with a single-buffer action, called
+     * from picasso_BlitRect().  The code in do_blitrect_frame_buffer() deals with the frame-buffer,
+     * while the do_blit() code deals with the visible screen.
+     *
+     * If we have a destination RenderInfo, then we've been called from picasso_BlitRectNoMaskComplete()
+     * and we need to put the results on the screen from the frame-buffer.
+     */
+    if (dstri == NULL) {
+        if (mask != 0xFF && Bpp > 1) {
+            mask = 0xFF;
+        }
+        dstri = ri;
+        can_do_visible_blit = 1;
+    }
+
+    /* Do our virtual frame-buffer memory first */
+    do_blitrect_frame_buffer (ri, dstri, srcx, srcy, dstx, dsty, width, height, mask, opcode);
+
+    /* Now we do the on-screen display, if renderinfo points to it */
+    if (renderinfo_is_current_screen (dstri)) {
+       if (mask == 0xFF || Bpp > 1) {
+           if (can_do_visible_blit)
+               do_blit (dstri, Bpp, srcx, srcy, dstx, dsty, width, height, opcode, 1);
+           else
+               do_blit (dstri, Bpp, dstx, dsty, dstx, dsty, width, height, opcode, 0);
+       } else
+           do_blit (dstri, Bpp, dstx, dsty, dstx, dsty, width, height, opcode, 0);
+
+       P96TRACE(("Did do_blit 1 in BlitRect()\n"));
+    } else {
+        P96TRACE(("Did not do_blit 1 in BlitRect()\n"));
+    }
+
+    return 1;
+}
+
+STATIC_INLINE int BlitRect (uaecptr ri, uaecptr dstri,
+                            unsigned long srcx, unsigned long srcy, unsigned long dstx, unsigned long dsty,
+                            unsigned long width, unsigned long height, uae_u8 mask, BLIT_OPCODE opcode )
+{
+    /* Set up the params */
+    CopyRenderInfoStructureA2U( ri, &blitrectdata.ri_struct );
+    blitrectdata.ri = &blitrectdata.ri_struct;
+
+    if (dstri) {
+       CopyRenderInfoStructureA2U( dstri, &blitrectdata.dstri_struct );
+       blitrectdata.dstri = &blitrectdata.dstri_struct;
+    } else
+       blitrectdata.dstri = NULL;
+
+    blitrectdata.srcx   = srcx;
+    blitrectdata.srcy   = srcy;
+    blitrectdata.dstx   = dstx;
+    blitrectdata.dsty   = dsty;
+    blitrectdata.width  = width;
+    blitrectdata.height = height;
+    blitrectdata.mask   = mask;
+    blitrectdata.opcode = opcode;
+
+    return BlitRectHelper();
+}
+
+/***********************************************************
+BlitRect:
+***********************************************************
+* a0:   struct BoardInfo
+* a1:   struct RenderInfo
+* d0:   WORD SrcX
+* d1:   WORD SrcY
+* d2:   WORD DstX
+* d3:   WORD DstY
+* d4:   WORD Width
+* d5:   WORD Height
+* d6:   UBYTE Mask
+* d7:   uae_u32 RGBFormat
+***********************************************************/
+uae_u32 picasso_BlitRect (void)
+{
+    uaecptr renderinfo   = m68k_areg (regs, 1);
+    unsigned long srcx   = (uae_u16)m68k_dreg (regs, 0);
+    unsigned long srcy   = (uae_u16)m68k_dreg (regs, 1);
+    unsigned long dstx   = (uae_u16)m68k_dreg (regs, 2);
+    unsigned long dsty   = (uae_u16)m68k_dreg (regs, 3);
+    unsigned long width  = (uae_u16)m68k_dreg (regs, 4);
+    unsigned long height = (uae_u16)m68k_dreg (regs, 5);
+    uae_u8  Mask         = (uae_u8) m68k_dreg (regs, 6);
+    uae_u32 result = 0;
+
+#ifdef JIT
+    special_mem|=picasso_is_special_read|picasso_is_special;
+#endif
+
+    wgfx_flushline ();
+
+    P96TRACE(("BlitRect(%d, %d, %d, %d, %d, %d, 0x%x)\n", srcx, srcy, dstx, dsty, width, height, Mask));
+    result = BlitRect (renderinfo, (uaecptr)NULL, srcx, srcy, dstx, dsty, width, height, Mask, BLIT_SRC);
+
+    return result;
+}
+
+/***********************************************************
+BlitRectNoMaskComplete:
+***********************************************************
+* a0:  struct BoardInfo
+* a1:  struct RenderInfo (src)
+* a2:   struct RenderInfo (dst)
+* d0:  WORD SrcX
+* d1:  WORD SrcY
+* d2:  WORD DstX
+* d3:  WORD DstY
+* d4:   WORD Width
+* d5:   WORD Height
+* d6:  UBYTE OpCode
+* d7:  uae_u32 RGBFormat
+* NOTE: MUST return 0 in D0 if we're not handling this operation
+*       because the RGBFormat or opcode aren't supported.
+*       OTHERWISE return 1
+***********************************************************/
+uae_u32 picasso_BlitRectNoMaskComplete (void)
+{
+    uaecptr srcri = m68k_areg (regs, 1);
+    uaecptr dstri = m68k_areg (regs, 2);
+    unsigned long srcx =   (uae_u16)m68k_dreg (regs, 0);
+    unsigned long srcy =   (uae_u16)m68k_dreg (regs, 1);
+    unsigned long dstx =   (uae_u16)m68k_dreg (regs, 2);
+    unsigned long dsty =   (uae_u16)m68k_dreg (regs, 3);
+    unsigned long width =  (uae_u16)m68k_dreg (regs, 4);
+    unsigned long height = (uae_u16)m68k_dreg (regs, 5);
+    uae_u8 OpCode =  m68k_dreg (regs, 6);
+    uae_u32 RGBFmt = m68k_dreg (regs, 7);
+    uae_u32 result = 0;
+
+#ifdef JIT
+    special_mem|=picasso_is_special_read|picasso_is_special;
+#endif
+
+    wgfx_flushline ();
+
+    P96TRACE(("BlitRectNoMaskComplete() op 0x%2x, xy(%4d,%4d) --> xy(%4d,%4d), wh(%4d,%4d)\n",
+        OpCode, srcx, srcy, dstx, dsty, width, height));
+
+    result = BlitRect (srcri, dstri, srcx, srcy, dstx, dsty, width, height, 0xFF, OpCode);
+
+    return result;
+}
+
+/* This utility function is used both by BlitTemplate() and BlitPattern() */
+STATIC_INLINE void PixelWrite1 (uae_u8 * mem, int bits, uae_u32 fgpen, uae_u32 mask)
+{
+    if (mask != 0xFF)
+       fgpen = (fgpen & mask) | (do_get_mem_byte (mem + bits) & ~mask);
+    do_put_mem_byte (mem + bits, fgpen);
+}
+
+STATIC_INLINE void PixelWrite2 (uae_u8 * mem, int bits, uae_u32 fgpen)
+{
+    do_put_mem_word (((uae_u16 *) mem) + bits, fgpen);
+}
+
+STATIC_INLINE void PixelWrite3 (uae_u8 * mem, int bits, uae_u32 fgpen)
+{
+    do_put_mem_byte (mem + bits * 3, fgpen & 0x000000FF);
+    *(uae_u16 *) (mem + bits * 3 + 1) = (fgpen & 0x00FFFF00) >> 8;
+}
+
+STATIC_INLINE void PixelWrite4 (uae_u8 * mem, int bits, uae_u32 fgpen)
+{
+    do_put_mem_long (((uae_u32 *) mem) + bits, fgpen);
+}
+
+STATIC_INLINE void PixelWrite (uae_u8 * mem, int bits, uae_u32 fgpen, uae_u8 Bpp, uae_u32 mask)
+{
+    switch (Bpp) {
+    case 1:
+       if (mask != 0xFF)
+           fgpen = (fgpen & mask) | (do_get_mem_byte (mem + bits) & ~mask);
+       do_put_mem_byte (mem + bits, fgpen);
+       break;
+    case 2:
+       do_put_mem_word (((uae_u16 *) mem) + bits, fgpen);
+       break;
+    case 3:
+       do_put_mem_byte (mem + bits * 3, fgpen & 0x000000FF);
+       *(uae_u16 *) (mem + bits * 3 + 1) = (fgpen & 0x00FFFF00) >> 8;
+       break;
+    case 4:
+       do_put_mem_long (((uae_u32 *) mem) + bits, fgpen);
+       break;
+    }
+}
+
+/*
+ * BlitPattern:
+ *
+ * Synopsis:BlitPattern(bi, ri, pattern, X, Y, Width, Height, Mask, RGBFormat);
+ * Inputs:
+ * a0:struct BoardInfo *bi
+ * a1:struct RenderInfo *ri
+ * a2:struct Pattern *pattern
+ * d0.w:X
+ * d1.w:Y
+ * d2.w:Width
+ * d3.w:Height
+ * d4.w:Mask
+ * d7.l:RGBFormat
+ *
+ * This function is used to paint a pattern on the board memory using the blitter. It is called by
+ * BltPattern, if a AreaPtrn is used with positive AreaPtSz. The pattern consists of a b/w image
+ * using a single plane of image data which will be expanded repeatedly to the destination RGBFormat
+ * using ForeGround and BackGround pens as well as draw modes. The width of the pattern data is
+ * always 16 pixels (one word) and the height is calculated as 2^Size. The data must be shifted up
+ * and to the left by XOffset and YOffset pixels at the beginning.
+ */
+uae_u32 picasso_BlitPattern (void)
+{
+    uaecptr rinf = m68k_areg (regs, 1);
+    uaecptr pinf = m68k_areg (regs, 2);
+    unsigned long X = (uae_u16)m68k_dreg (regs, 0);
+    unsigned long Y = (uae_u16)m68k_dreg (regs, 1);
+    unsigned long W = (uae_u16)m68k_dreg (regs, 2);
+    unsigned long H = (uae_u16)m68k_dreg (regs, 3);
+    uae_u8 Mask =     (uae_u8) m68k_dreg (regs, 4);
+    uae_u32 RGBFmt = m68k_dreg (regs, 7);
+    uae_u8 Bpp = GetBytesPerPixel (RGBFmt);
+    int inversion = 0;
+    struct RenderInfo ri;
+    struct Pattern pattern;
+    unsigned long rows;
+    uae_u32 fgpen;
+    uae_u8 *uae_mem;
+    int xshift;
+    unsigned long ysize_mask;
+    uae_u32 result = 0;
+
+#ifdef JIT
+    special_mem|=picasso_is_special_read|picasso_is_special;
+#endif
+
+    wgfx_flushline ();
+
+    if (CopyRenderInfoStructureA2U (rinf, &ri) && CopyPatternStructureA2U (pinf, &pattern)) {
+       Bpp = GetBytesPerPixel (ri.RGBFormat);
+       uae_mem = ri.Memory + Y*ri.BytesPerRow + X*Bpp; /* offset with address */
+
+       if (pattern.DrawMode & INVERS)
+           inversion = 1;
+
+       pattern.DrawMode &= 0x03;
+
+       if (Mask != 0xFF) {
+           if( Bpp > 1 )
+               Mask = 0xFF;
+
+           if( pattern.DrawMode == COMP)
+                write_log ("WARNING - BlitPattern() has unhandled mask 0x%x with COMP DrawMode. Using fall-back  routine.\n", Mask);
+           else
+               result = 1;
+       } else
+           result = 1;
+
+       if (result) {
+#           ifdef P96TRACING_ENABLED
+               DumpPattern(&pattern);
+#           endif
+           ysize_mask = (1 << pattern.Size) - 1;
+           xshift = pattern.XOffset & 15;
+
+           for (rows = 0; rows < H; rows++, uae_mem += ri.BytesPerRow) {
+               unsigned long prow = (rows + pattern.YOffset) & ysize_mask;
+               unsigned int d = do_get_mem_word (((uae_u16 *)pattern.Memory) + prow);
+               uae_u8 *uae_mem2 = uae_mem;
+               unsigned long cols;
+
+               if (xshift != 0)
+                   d = (d << xshift) | (d >> (16 - xshift));
+
+               for (cols = 0; cols < W; cols += 16, uae_mem2 += Bpp << 4) {
+                   long bits;
+                   long max = W - cols;
+                   unsigned int data = d;
+
+                   if (max > 16)
+                       max = 16;
+
+                   for (bits = 0; bits < max; bits++) {
+                       int bit_set = data & 0x8000;
+                       data <<= 1;
+                       switch (pattern.DrawMode) {
+                           case JAM1:
+                               if (inversion)
+                                   bit_set = !bit_set;
+                               if (bit_set)
+                                   PixelWrite (uae_mem2, bits, pattern.FgPen, Bpp, Mask);
+                               break;
+                           case JAM2:
+                               if (inversion)
+                                   bit_set = !bit_set;
+                               if (bit_set)
+                                   PixelWrite (uae_mem2, bits, pattern.FgPen, Bpp, Mask);
+                               else
+                                   PixelWrite (uae_mem2, bits, pattern.BgPen, Bpp, Mask);
+                               break;
+                           case COMP:
+                               if (bit_set) {
+                                   fgpen = pattern.FgPen;
+
+                                   switch (Bpp) {
+                                       case 1:
+                                           {
+                                               uae_u8 *addr = uae_mem2 + bits;
+                                               do_put_mem_byte (addr, (uae_u8)(do_get_mem_byte (addr) ^ fgpen));
+                                           }
+                                           break;
+                                       case 2:
+                                           {
+                                               uae_u16 *addr = ((uae_u16 *)uae_mem2) + bits;
+                                               do_put_mem_word (addr, (uae_u16)(do_get_mem_word (addr) ^ fgpen));
+                                           }
+                                           break;
+                                       case 3:
+                                           {
+                                               uae_u32 *addr = (uae_u32 *)(uae_mem2 + bits * 3);
+                                               do_put_mem_long (addr, do_get_mem_long (addr) ^ (fgpen & 0x00FFFFFF));
+                                           }
+                                           break;
+                                       case 4:
+                                           {
+                                               uae_u32 *addr = ((uae_u32 *)uae_mem2) + bits;
+                                               do_put_mem_long (addr, do_get_mem_long (addr) ^ fgpen);
+                                           }
+                                           break;
+                                   } /* switch (Bpp) */
+                               }
+                               break;
+                        } /* switch (pattern.DrawMode) */
+                    } /* for (bits) */
+                } /* for (cols) */
+            } /* for (rows) */
+
+           /* If we need to update a second-buffer (extra_mem is set), then do it only if visible! */
+            if (picasso_vidinfo.extra_mem && renderinfo_is_current_screen (&ri))
+               do_blit( &ri, Bpp, X, Y, X, Y, W, H, BLIT_SRC, 0);
+
+           result = 1;
+        }
+    }
+    return result;
+}
+
+/*************************************************
+BlitTemplate:
+**************************************************
+* Synopsis: BlitTemplate(bi, ri, template, X, Y, Width, Height, Mask, RGBFormat);
+* a0: struct BoardInfo *bi
+* a1: struct RenderInfo *ri
+* a2: struct Template *template
+* d0.w: X
+* d1.w: Y
+* d2.w: Width
+* d3.w: Height
+* d4.w: Mask
+* d7.l: RGBFormat
+*
+* This function is used to paint a template on the board memory using the blitter.
+* It is called by BltPattern and BltTemplate. The template consists of a b/w image
+* using a single plane of image data which will be expanded to the destination RGBFormat
+* using ForeGround and BackGround pens as well as draw modes.
+***********************************************************************************/
+uae_u32 picasso_BlitTemplate (void)
+{
+    uae_u8 inversion = 0;
+    uaecptr rinf = m68k_areg (regs, 1);
+    uaecptr tmpl = m68k_areg (regs, 2);
+    unsigned long X = (uae_u16)m68k_dreg (regs, 0);
+    unsigned long Y = (uae_u16)m68k_dreg (regs, 1);
+    unsigned long W = (uae_u16)m68k_dreg (regs, 2);
+    unsigned long H = (uae_u16)m68k_dreg (regs, 3);
+    uae_u16 Mask = (uae_u16)m68k_dreg (regs, 4);
+    struct Template tmp;
+    struct RenderInfo ri;
+    unsigned long rows;
+    int bitoffset;
+    uae_u32 fgpen;
+    uae_u8 *uae_mem, Bpp;
+    uae_u8 *tmpl_base;
+    uae_u32 result = 0;
+
+#ifdef JIT
+    special_mem|=picasso_is_special_read|picasso_is_special;
+#endif
+
+    wgfx_flushline ();
+
+    if (CopyRenderInfoStructureA2U (rinf, &ri) && CopyTemplateStructureA2U (tmpl, &tmp)) {
+       Bpp = GetBytesPerPixel (ri.RGBFormat);
+       uae_mem = ri.Memory + Y*ri.BytesPerRow + X*Bpp; /* offset into address */
+
+       if (tmp.DrawMode & INVERS)
+           inversion = 1;
+
+       tmp.DrawMode &= 0x03;
+
+       if (Mask != 0xFF) {
+           if (Bpp > 1)
+               Mask = 0xFF;
+
+           if (tmp.DrawMode == COMP) {
+               write_log ("WARNING - BlitTemplate() has unhandled mask 0x%x with COMP DrawMode. Using fall-back routine.\n", Mask);
+#              ifdef _WIN32
+                   flushpixels();  //only need in the windows Version
+#              endif
+               return 0;
+           } else
+                result = 1;
+        } else
+            result = 1;
+
+#if 1
+        if (tmp.DrawMode == COMP) {
+            /* workaround, let native blitter handle COMP mode */
+#          ifdef _WIN32
+               flushpixels();
+#          endif
+           return 0;
+       }
+#endif
+
+       if (result) {
+           P96TRACE (("BlitTemplate() xy(%d,%d), wh(%d,%d) draw 0x%x fg 0x%x bg 0x%x \n",
+               X, Y, W, H, tmp.DrawMode, tmp.FgPen, tmp.BgPen));
+
+           bitoffset = tmp.XOffset % 8;
+
+#          if defined( P96TRACING_ENABLED ) && ( P96TRACING_LEVEL > 0 )
+               DumpTemplate(&tmp, W, H);
+#          endif
+
+           tmpl_base = tmp.Memory + tmp.XOffset / 8;
+
+           for (rows = 0; rows < H; rows++, uae_mem += ri.BytesPerRow, tmpl_base += tmp.BytesPerRow) {
+               unsigned long cols;
+               uae_u8 *tmpl_mem = tmpl_base;
+               uae_u8 *uae_mem2 = uae_mem;
+               unsigned int data = *tmpl_mem;
+
+               for (cols = 0; cols < W; cols += 8, uae_mem2 += Bpp << 3) {
+                   unsigned int byte;
+                   long bits;
+                   long max = W - cols;
+
+                   if (max > 8)
+                       max = 8;
+
+                   data <<= 8;
+                   data |= *++tmpl_mem;
+
+                   byte = data >> (8 - bitoffset);
+
+                   for (bits = 0; bits < max; bits++) {
+                       int bit_set = (byte & 0x80);
+                       byte <<= 1;
+                       switch (tmp.DrawMode) {
+                           case JAM1:
+                               if (inversion)
+                                   bit_set = !bit_set;
+                               if (bit_set) {
+                                   fgpen = tmp.FgPen;
+                                   PixelWrite (uae_mem2, bits, fgpen, Bpp, Mask);
+                               }
+                               break;
+                           case JAM2:
+                               if (inversion)
+                                   bit_set = !bit_set;
+                               fgpen = tmp.BgPen;
+                               if (bit_set)
+                                   fgpen = tmp.FgPen;
+                               PixelWrite (uae_mem2, bits, fgpen, Bpp, Mask);
+                               break;
+                           case COMP:
+                               if (bit_set) {
+                                   fgpen = tmp.FgPen;
+
+                                   switch (Bpp) {
+                                       case 1:
+                                           {
+                                               uae_u8 *addr = uae_mem2 + bits;
+                                               do_put_mem_byte (addr, (uae_u8) (do_get_mem_byte (addr) ^ fgpen));
+                                           }
+                                           break;
+                                       case 2:
+                                           {
+                                               uae_u16 *addr = ((uae_u16 *)uae_mem2) + bits;
+                                               do_put_mem_word (addr, (uae_u16) (do_get_mem_word (addr) ^ fgpen));
+                                           }
+                                           break;
+                                       case 3:
+                                           {
+                                               uae_u32 *addr = (uae_u32 *)(uae_mem2 + bits * 3);
+                                               do_put_mem_long (addr, do_get_mem_long (addr) ^ (fgpen & 0x00FFFFFF));
+                                           }
+                                           break;
+                                       case 4:
+                                           {
+                                               uae_u32 *addr = ((uae_u32 *)uae_mem2) + bits;
+                                               do_put_mem_long (addr, do_get_mem_long (addr) ^ fgpen);
+                                           }
+                                           break;
+                                   } /* switch (Bpp) */
+                               } /* if (bit_set) */
+                               break;
+                       } /* switch (tmp.DrawMode) */
+                   } /* for (bits) */
+               } /* for (cols) */
+           } /* for (rows) */
+
+           /* If we need to update a second-buffer (extra_mem is set), then do it only if visible! */
+           if (picasso_vidinfo.extra_mem && renderinfo_is_current_screen (&ri))
+               do_blit (&ri, Bpp, X, Y, X, Y, W, H, BLIT_SRC, 0);
+       }
+    }
+    return 1;
+}
+
+/*
+ * CalculateBytesPerRow:
+ * a0:         struct BoardInfo
+ * d0:         uae_u16 Width
+ * d7: RGBFTYPE RGBFormat
+ * This function calculates the amount of bytes needed for a line of
+ * "Width" pixels in the given RGBFormat.
+ */
+uae_u32 picasso_CalculateBytesPerRow (void)
+{
+    uae_u16 width = m68k_dreg (regs, 0);
+    uae_u32 type = m68k_dreg (regs, 7);
+
+    width = GetBytesPerPixel (type) * width;
+    P96TRACE  (("CalculateBytesPerRow() = %d\n", width));
+
+    return width;
+}
+
+/*
+ * SetDisplay:
+ * a0: struct BoardInfo
+ * d0: BOOL state
+ * This function enables and disables the video display.
+ *
+ * NOTE: return the opposite of the state
+ */
+uae_u32 picasso_SetDisplay (void)
+{
+    uae_u32 state = m68k_dreg (regs, 0);
+    P96TRACE (("SetDisplay(%d)\n", state));
+    return !state;
+}
+
+/*
+ * WaitVerticalSync:
+ * a0: struct BoardInfo
+ * This function waits for the next horizontal retrace.
+ */
+uae_u32 picasso_WaitVerticalSync (void)
+{
+    /*write_log ("WaitVerticalSync()\n"); */
+    return 1;
+}
+
+/* NOTE: Watch for those planeptrs of 0x00000000 and 0xFFFFFFFF for all zero / all one bitmaps !!!! */
+static void PlanarToChunky (struct RenderInfo *ri, struct BitMap *bm,
+                           unsigned long srcx, unsigned long srcy,
+                           unsigned long dstx, unsigned long dsty, unsigned long width, unsigned long height, uae_u8 mask)
+{
+    int j;
+
+    uae_u8 *PLANAR[8], *image = ri->Memory + dstx * GetBytesPerPixel (ri->RGBFormat) + dsty * ri->BytesPerRow;
+    int Depth = bm->Depth;
+    unsigned long rows, bitoffset = srcx & 7;
+    long eol_offset;
+
+    /* if (mask != 0xFF) 
+       write_log ("P2C - pixel-width = %d, bit-offset = %d\n", width, bitoffset); */
+
+    /* Set up our bm->Planes[] pointers to the right horizontal offset */
+    for (j = 0; j < Depth; j++) {
+       uae_u8 *p = bm->Planes[j];
+       if (p != &all_zeros_bitmap && p != &all_ones_bitmap)
+           p += srcx / 8 + srcy * bm->BytesPerRow;
+       PLANAR[j] = p;
+       if ((mask & (1 << j)) == 0)
+           PLANAR[j] = &all_zeros_bitmap;
+    }
+    eol_offset = (long) bm->BytesPerRow - (long) ((width + 7) >> 3);
+    for (rows = 0; rows < height; rows++, image += ri->BytesPerRow) {
+       unsigned long cols;
+
+       for (cols = 0; cols < width; cols += 8) {
+           int k;
+           uae_u32 a = 0, b = 0;
+           unsigned int msk = 0xFF;
+           long tmp = cols + 8 - width;
+           if (tmp > 0) {
+               msk <<= tmp;
+               b = do_get_mem_long ((uae_u32 *) (image + cols + 4));
+               if (tmp < 4)
+                   b &= 0xFFFFFFFF >> (32 - tmp * 8);
+               else if (tmp > 4) {
+                   a = do_get_mem_long ((uae_u32 *) (image + cols));
+                   a &= 0xFFFFFFFF >> (64 - tmp * 8);
+               }
+           }
+           for (k = 0; k < Depth; k++) {
+               unsigned int data;
+               if (PLANAR[k] == &all_zeros_bitmap)
+                   data = 0;
+               else if (PLANAR[k] == &all_ones_bitmap)
+                   data = 0xFF;
+               else {
+                   data = (uae_u8) (do_get_mem_word ((uae_u16 *) PLANAR[k]) >> (8 - bitoffset));
+                   PLANAR[k]++;
+               }
+               data &= msk;
+               a |= p2ctab[data][0] << k;
+               b |= p2ctab[data][1] << k;
+           }
+           do_put_mem_long ((uae_u32 *) (image + cols), a);
+           do_put_mem_long ((uae_u32 *) (image + cols + 4), b);
+       }
+       for (j = 0; j < Depth; j++) {
+           if (PLANAR[j] != &all_zeros_bitmap && PLANAR[j] != &all_ones_bitmap) {
+               PLANAR[j] += eol_offset;
+           }
+       }
+    }
+}
+
+/*
+ * BlitPlanar2Chunky:
+ * a0: struct BoardInfo *bi
+ * a1: struct BitMap *bm - source containing planar information and assorted details
+ * a2: struct RenderInfo *ri - dest area and its details
+ * d0.w: SrcX
+ * d1.w: SrcY
+ * d2.w: DstX
+ * d3.w: DstY
+ * d4.w: SizeX
+ * d5.w: SizeY
+ * d6.b: MinTerm - uh oh!
+ * d7.b: Mask - uh oh!
+ *
+ * This function is currently used to blit from planar bitmaps within system memory to chunky bitmaps
+ * on the board. Watch out for plane pointers that are 0x00000000 (represents a plane with all bits "0")
+ * or 0xffffffff (represents a plane with all bits "1").
+ */
+uae_u32 picasso_BlitPlanar2Chunky (void)
+{
+    uaecptr bm = m68k_areg (regs, 1);
+    uaecptr ri = m68k_areg (regs, 2);
+    unsigned long srcx = (uae_u16) m68k_dreg (regs, 0);
+    unsigned long srcy = (uae_u16) m68k_dreg (regs, 1);
+    unsigned long dstx = (uae_u16) m68k_dreg (regs, 2);
+    unsigned long dsty = (uae_u16) m68k_dreg (regs, 3);
+    unsigned long width = (uae_u16) m68k_dreg (regs, 4);
+    unsigned long height = (uae_u16) m68k_dreg (regs, 5);
+    uae_u8 minterm = m68k_dreg (regs, 6) & 0xFF;
+    uae_u8 mask = m68k_dreg (regs, 7) & 0xFF;
+    struct RenderInfo local_ri;
+    struct BitMap local_bm;
+
+    wgfx_flushline ();
+
+    if (minterm != 0x0C) {
+       write_log ("ERROR - BlitPlanar2Chunky() has minterm 0x%x, which I don't handle. Using fall-back routine.\n", minterm);
+       return 0;
+    }
+    if (!CopyRenderInfoStructureA2U (ri, &local_ri)
+       || !CopyBitMapStructureA2U (bm, &local_bm))
+       return 0;
+
+    P96TRACE (("BlitPlanar2Chunky(%d, %d, %d, %d, %d, %d) Minterm 0x%x, Mask 0x%x, Depth %d\n",
+              srcx, srcy, dstx, dsty, width, height, minterm, mask, local_bm.Depth));
+    P96TRACE (("P2C - BitMap has %d BPR, %d rows\n", local_bm.BytesPerRow, local_bm.Rows));
+    PlanarToChunky (&local_ri, &local_bm, srcx, srcy, dstx, dsty, width, height, mask);
+    if (renderinfo_is_current_screen (&local_ri))
+       do_blit (&local_ri, GetBytesPerPixel (local_ri.RGBFormat), dstx, dsty, dstx, dsty, width, height, BLIT_SRC, 0);
+
+    return 1;
+}
+
+static void PlanarToDirect (struct RenderInfo *ri, struct BitMap *bm,
+                           unsigned long srcx, unsigned long srcy,
+                           unsigned long dstx, unsigned long dsty,
+                           unsigned long width, unsigned long height, uae_u8 mask, struct ColorIndexMapping *cim)
+{
+    int j;
+    int bpp = GetBytesPerPixel (ri->RGBFormat);
+    uae_u8 *PLANAR[8];
+    uae_u8 *image = ri->Memory + dstx * bpp + dsty * ri->BytesPerRow;
+    int Depth = bm->Depth;
+    unsigned long rows;
+    long eol_offset;
+
+    /* Set up our bm->Planes[] pointers to the right horizontal offset */
+    for (j = 0; j < Depth; j++) {
+       uae_u8 *p = bm->Planes[j];
+       if (p != &all_zeros_bitmap && p != &all_ones_bitmap)
+           p += srcx / 8 + srcy * bm->BytesPerRow;
+       PLANAR[j] = p;
+       if ((mask & (1 << j)) == 0)
+           PLANAR[j] = &all_zeros_bitmap;
+    }
+
+    eol_offset = (long) bm->BytesPerRow - (long) ((width + (srcx & 7)) >> 3);
+    for (rows = 0; rows < height; rows++, image += ri->BytesPerRow) {
+       unsigned long cols;
+       uae_u8 *image2 = image;
+       unsigned int bitoffs = 7 - (srcx & 7);
+       int i;
+
+       for (cols = 0; cols < width; cols++) {
+           int v = 0, k;
+           for (k = 0; k < Depth; k++) {
+               if (PLANAR[k] == &all_ones_bitmap)
+                   v |= 1 << k;
+               else if (PLANAR[k] != &all_zeros_bitmap) {
+                   v |= ((*PLANAR[k] >> bitoffs) & 1) << k;
+               }
+           }
+
+           switch (bpp) {
+           case 2:
+               do_put_mem_word ((uae_u16 *) image2, cim->Colors[v]);
+               image2 += 2;
+               break;
+           case 3:
+               do_put_mem_byte (image2++, cim->Colors[v] & 0x000000FF);
+               do_put_mem_word ((uae_u16 *) image2, (cim->Colors[v] & 0x00FFFF00) >> 8);
+               image2 += 2;
+               break;
+           case 4:
+               do_put_mem_long ((uae_u32 *) image2, cim->Colors[v]);
+               image2 += 4;
+               break;
+           }
+           bitoffs--;
+           bitoffs &= 7;
+           if (bitoffs == 7) {
+               int k;
+               for (k = 0; k < Depth; k++) {
+                   if (PLANAR[k] != &all_zeros_bitmap && PLANAR[k] != &all_ones_bitmap) {
+                       PLANAR[k]++;
+                   }
+               }
+           }
+       }
+
+       for (i = 0; i < Depth; i++) {
+           if (PLANAR[i] != &all_zeros_bitmap && PLANAR[i] != &all_ones_bitmap) {
+               PLANAR[i] += eol_offset;
+           }
+       }
+    }
+}
+
+/*
+ * BlitPlanar2Direct:
+ *
+ * Synopsis:
+ * BlitPlanar2Direct(bi, bm, ri, cim, SrcX, SrcY, DstX, DstY, SizeX, SizeY, MinTerm, Mask);
+ * Inputs:
+ * a0:struct BoardInfo *bi
+ * a1:struct BitMap *bm
+ * a2:struct RenderInfo *ri
+ * a3:struct ColorIndexMapping *cmi
+ * d0.w:SrcX
+ * d1.w:SrcY
+ * d2.w:DstX
+ * d3.w:DstY
+ * d4.w:SizeX
+ * d5.w:SizeY
+ * d6.b:MinTerm
+ * d7.b:Mask
+ *
+ * This function is currently used to blit from planar bitmaps within system memory to direct color
+ * bitmaps (15, 16, 24 or 32 bit) on the board. Watch out for plane pointers that are 0x00000000 (represents
+ * a plane with all bits "0") or 0xffffffff (represents a plane with all bits "1"). The ColorIndexMapping is
+ * used to map the color index of each pixel formed by the bits in the bitmap's planes to a direct color value
+ * which is written to the destination RenderInfo. The color mask and all colors within the mapping are words,
+ * triple bytes or longwords respectively similar to the color values used in FillRect(), BlitPattern() or
+ * BlitTemplate().
+ */
+
+uae_u32 picasso_BlitPlanar2Direct (void)
+{
+    uaecptr bm = m68k_areg (regs, 1);
+    uaecptr ri = m68k_areg (regs, 2);
+    uaecptr cim = m68k_areg (regs, 3);
+    unsigned long srcx = (uae_u16)m68k_dreg (regs, 0);
+    unsigned long srcy = (uae_u16)m68k_dreg (regs, 1);
+    unsigned long dstx = (uae_u16)m68k_dreg (regs, 2);
+    unsigned long dsty = (uae_u16)m68k_dreg (regs, 3);
+    unsigned long width = (uae_u16)m68k_dreg (regs, 4);
+    unsigned long height = (uae_u16)m68k_dreg (regs, 5);
+    uae_u8 minterm = m68k_dreg (regs, 6);
+    uae_u8 Mask = m68k_dreg (regs, 7);
+    struct RenderInfo local_ri;
+    struct BitMap local_bm;
+    struct ColorIndexMapping local_cim;
+    uae_u32 result = 0;
+
+#ifdef JIT
+    special_mem|=picasso_is_special_read|picasso_is_special;
+#endif
+
+    wgfx_flushline ();
+
+    if (minterm != 0x0C) {
+        write_log ("WARNING - BlitPlanar2Direct() has unhandled op-code 0x%x. Using fall-back routine.\n", minterm);
+    } else if (CopyRenderInfoStructureA2U (ri, &local_ri) && CopyBitMapStructureA2U (bm, &local_bm)) {
+       Mask = 0xFF;
+       CopyColorIndexMappingA2U (cim, &local_cim);
+
+       P96TRACE (("BlitPlanar2Direct(%d, %d, %d, %d, %d, %d) Minterm 0x%x, Mask 0x%x, Depth %d\n",
+           srcx, srcy, dstx, dsty, width, height, minterm, Mask, local_bm.Depth));
+
+       PlanarToDirect (&local_ri, &local_bm, srcx, srcy, dstx, dsty, width, height, Mask, &local_cim);
+       if (renderinfo_is_current_screen (&local_ri))
+           do_blit( &local_ri, GetBytesPerPixel( local_ri.RGBFormat ), dstx, dsty, dstx, dsty, width, height, BLIT_SRC, 0);
+       result = 1;
+    }
+    return result;
+}
+
+
+
+/* @@@ - Work to be done here!
+ *
+ * The address is the offset into our Picasso96 frame-buffer (pointed to by gfxmem_start)
+ * where the value was put.
+ *
+ * Porting work: on some machines you may not need these functions, ie. if the memory for the
+ * Picasso96 frame-buffer is directly viewable or directly blittable.  On Win32 with DirectX,
+ * this is not the case.  So I provide some write-through functions (as per Mathias' orders!)
+ */
+static void write_gfx_long (uaecptr addr, uae_u32 value)
+{
+    uaecptr oldaddr = addr;
+    int x, xbytes, y;
+    uae_u8 *dst;
+
+    if (!picasso_on)
+       return;
+
+    /*
+     * Several writes to successive memory locations are a common access pattern.
+     * Try to optimize it.
+     */
+    if (addr >= wgfx_linestart && addr + 4 <= wgfx_lineend) {
+       if (addr < wgfx_min)
+           wgfx_min = addr;
+       if (addr + 4 > wgfx_max)
+           wgfx_max = addr + 4;
+       return;
+    } else
+       wgfx_flushline ();
+
+    addr += gfxmem_start;
+    /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */
+    /* Shouldn't the "+4" be on the *first* addr, rather than the second?
+       and be a "+3" at  that? */
+    if (addr < picasso96_state.Address || addr + 4 > picasso96_state.Extent)
+       return;
+
+    addr -= picasso96_state.Address;
+    y = addr / picasso96_state.BytesPerRow;
+
+    if (y >= picasso96_state.VirtualHeight)
+       return;
+    wgfx_linestart = picasso96_state.Address - gfxmem_start + y * picasso96_state.BytesPerRow;
+    wgfx_lineend = wgfx_linestart + picasso96_state.BytesPerRow;
+    wgfx_y = y;
+    wgfx_min = oldaddr;
+    wgfx_max = oldaddr + 4;
+}
+
+static void write_gfx_word (uaecptr addr, uae_u16 value)
+{
+    uaecptr oldaddr = addr;
+    int x, xbytes, y;
+    uae_u8 *dst;
+
+    if (!picasso_on)
+       return;
+
+    /*
+     * Several writes to successive memory locations are a common access pattern.
+     * Try to optimize it.
+     */
+    if (addr >= wgfx_linestart && addr + 2 <= wgfx_lineend) {
+       if (addr < wgfx_min)
+           wgfx_min = addr;
+       if (addr + 2 > wgfx_max)
+           wgfx_max = addr + 2;
+       return;
+    } else
+       wgfx_flushline ();
+
+    addr += gfxmem_start;
+    /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */
+    if (addr < picasso96_state.Address || addr + 2 > picasso96_state.Extent)
+       return;
+
+    addr -= picasso96_state.Address;
+    y = addr / picasso96_state.BytesPerRow;
+
+    if (y >= picasso96_state.VirtualHeight)
+       return;
+    wgfx_linestart = picasso96_state.Address - gfxmem_start + y * picasso96_state.BytesPerRow;
+    wgfx_lineend = wgfx_linestart + picasso96_state.BytesPerRow;
+    wgfx_y = y;
+    wgfx_min = oldaddr;
+    wgfx_max = oldaddr + 2;
+}
+
+static void write_gfx_byte (uaecptr addr, uae_u8 value)
+{
+    uaecptr oldaddr = addr;
+    int x, xbytes, y;
+    uae_u8 *dst;
+
+    if (!picasso_on)
+       return;
+
+    /*
+     * Several writes to successive memory locations are a common access pattern.
+     * Try to optimize it.
+     */
+    if (addr >= wgfx_linestart && addr + 4 <= wgfx_lineend) {
+       if (addr < wgfx_min)
+           wgfx_min = addr;
+       if (addr + 1 > wgfx_max)
+           wgfx_max = addr + 1;
+       return;
+    } else
+       wgfx_flushline ();
+
+    addr += gfxmem_start;
+    /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */
+    if (addr < picasso96_state.Address || addr + 1 > picasso96_state.Extent)
+       return;
+
+    addr -= picasso96_state.Address;
+    y = addr / picasso96_state.BytesPerRow;
+
+    if (y >= picasso96_state.VirtualHeight)
+       return;
+    wgfx_linestart = picasso96_state.Address - gfxmem_start + y * picasso96_state.BytesPerRow;
+    wgfx_lineend = wgfx_linestart + picasso96_state.BytesPerRow;
+    wgfx_y = y;
+    wgfx_min = oldaddr;
+    wgfx_max = oldaddr + 1;
+}
+
+static uae_u32 REGPARAM2 gfxmem_lget (uaecptr addr)
+{
+    uae_u32 *m;
+
+#ifdef JIT
+    special_mem|=picasso_is_special_read;
+#endif
+    addr -= gfxmem_start & gfxmem_mask;
+    addr &= gfxmem_mask;
+    m = (uae_u32 *) (gfxmemory + addr);
+    return do_get_mem_long (m);
+}
+
+static uae_u32 REGPARAM2 gfxmem_wget (uaecptr addr)
+{
+    uae_u16 *m;
+
+#ifdef JIT
+    special_mem|=picasso_is_special_read;
+#endif
+    addr -= gfxmem_start & gfxmem_mask;
+    addr &= gfxmem_mask;
+    m = (uae_u16 *) (gfxmemory + addr);
+    return do_get_mem_word (m);
+}
+
+static uae_u32 REGPARAM2 gfxmem_bget (uaecptr addr)
+{
+#ifdef JIT
+    special_mem|=picasso_is_special_read;
+#endif
+    addr -= gfxmem_start & gfxmem_mask;
+    addr &= gfxmem_mask;
+    return gfxmemory[addr];
+}
+
+static void REGPARAM2 gfxmem_lput (uaecptr addr, uae_u32 l)
+{
+    uae_u32 *m;
+
+#ifdef JIT
+    special_mem|=picasso_is_special;
+#endif
+    addr -= gfxmem_start & gfxmem_mask;
+    addr &= gfxmem_mask;
+    m = (uae_u32 *) (gfxmemory + addr);
+    do_put_mem_long (m, l);
+
+    /* write the long-word to our displayable memory */
+    write_gfx_long (addr, l);
+}
+
+static void REGPARAM2 gfxmem_wput (uaecptr addr, uae_u32 w)
+{
+    uae_u16 *m;
+#ifdef JIT   
+    special_mem|=picasso_is_special; 
+#endif   
+    addr -= gfxmem_start & gfxmem_mask;
+    addr &= gfxmem_mask;
+    m = (uae_u16 *) (gfxmemory + addr);
+    do_put_mem_word (m, (uae_u16) w);
+
+    /* write the word to our displayable memory */
+    write_gfx_word (addr, (uae_u16) w);
+}
+
+static void REGPARAM2 gfxmem_bput (uaecptr addr, uae_u32 b)
+{
+#ifdef JIT   
+    special_mem|=picasso_is_special; 
+#endif   
+    addr -= gfxmem_start & gfxmem_mask;
+    addr &= gfxmem_mask;
+    gfxmemory[addr] = b;
+
+    /* write the byte to our displayable memory */
+    write_gfx_byte (addr, (uae_u8) b);
+}
+
+static int REGPARAM2 gfxmem_check (uaecptr addr, uae_u32 size)
+{
+    addr -= gfxmem_start & gfxmem_mask;
+    addr &= gfxmem_mask;
+    return (addr + size) < allocated_gfxmem;
+}
+
+static uae_u8 REGPARAM2 *gfxmem_xlate (uaecptr addr)
+{
+    addr -= gfxmem_start & gfxmem_mask;
+    addr &= gfxmem_mask;
+    return gfxmemory + addr;
+}
+
+addrbank gfxmem_bank = {
+    gfxmem_lget, gfxmem_wget, gfxmem_bget,
+    gfxmem_lput, gfxmem_wput, gfxmem_bput,
+    gfxmem_xlate, gfxmem_check, NULL
+};
+
+int picasso_display_mode_index (uae_u32 x, uae_u32 y, uae_u32 d)
+{
+    int i;
+    for (i = 0; i < mode_count; i++) {
+        if (DisplayModes[i].res.width == x
+           && DisplayModes[i].res.height == y
+           && DisplayModes[i].depth == d)
+            break;
+    }
+    if (i == mode_count)
+        i = -1;
+    return i;
+}
+
+static int resolution_compare (const void *a, const void *b)
+{
+    struct PicassoResolution *ma = (struct PicassoResolution *) a;
+    struct PicassoResolution *mb = (struct PicassoResolution *) b;
+    if (ma->res.width > mb->res.width)
+       return -1;
+    if (ma->res.width < mb->res.width)
+       return 1;
+    if (ma->res.height > mb->res.height)
+       return -1;
+    if (ma->res.height < mb->res.height)
+       return 1;
+    return ma->depth - mb->depth;
+}
+
+/* Call this function first, near the beginning of code flow
+ * NOTE: Don't stuff it in InitGraphics() which seems reasonable...
+ * Instead, put it in customreset() for safe-keeping.  */
+void InitPicasso96 (void)
+{
+    static int first_time = 1;
+
+    memset (&picasso96_state, 0, sizeof (struct picasso96_state_struct));
+
+    if (first_time) {
+       int i;
+
+       for (i = 0; i < 256; i++) {
+           p2ctab[i][0] = (((i & 128) ? 0x01000000 : 0)
+                           | ((i & 64) ? 0x010000 : 0)
+                           | ((i & 32) ? 0x0100 : 0)
+                           | ((i & 16) ? 0x01 : 0));
+           p2ctab[i][1] = (((i & 8) ? 0x01000000 : 0)
+                           | ((i & 4) ? 0x010000 : 0)
+                           | ((i & 2) ? 0x0100 : 0)
+                           | ((i & 1) ? 0x01 : 0));
+       }
+       mode_count = DX_FillResolutions (&picasso96_pixel_format);
+       qsort (DisplayModes, mode_count, sizeof (struct PicassoResolution), resolution_compare);
+
+       for (i = 0; i < mode_count; i++) {
+           sprintf (DisplayModes[i].name, "%dx%d, %d-bit, %d Hz",
+                    DisplayModes[i].res.width, DisplayModes[i].res.height, DisplayModes[i].depth * 8, DisplayModes[i].refresh);
+           switch (DisplayModes[i].depth) {
+           case 1:
+               if (DisplayModes[i].res.width > chunky.width)
+                   chunky.width = DisplayModes[i].res.width;
+               if (DisplayModes[i].res.height > chunky.height)
+                   chunky.height = DisplayModes[i].res.height;
+               break;
+           case 2:
+               if (DisplayModes[i].res.width > hicolour.width)
+                   hicolour.width = DisplayModes[i].res.width;
+               if (DisplayModes[i].res.height > hicolour.height)
+                   hicolour.height = DisplayModes[i].res.height;
+               break;
+           case 3:
+               if (DisplayModes[i].res.width > truecolour.width)
+                   truecolour.width = DisplayModes[i].res.width;
+               if (DisplayModes[i].res.height > truecolour.height)
+                   truecolour.height = DisplayModes[i].res.height;
+               break;
+           case 4:
+               if (DisplayModes[i].res.width > alphacolour.width)
+                   alphacolour.width = DisplayModes[i].res.width;
+               if (DisplayModes[i].res.height > alphacolour.height)
+                   alphacolour.height = DisplayModes[i].res.height;
+               break;
+           }
+       }
+       ShowSupportedResolutions ();
+
+       first_time = 0;
+    }
+}
+
+#endif
diff --git a/readcpu.c b/readcpu.c
new file mode 100755 (executable)
index 0000000..8c5ece1
--- /dev/null
+++ b/readcpu.c
@@ -0,0 +1,844 @@
+/*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * Read 68000 CPU specs from file "table68k"
+ *
+ * Copyright 1995,1996 Bernd Schmidt
+ */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+#include <ctype.h>
+
+#include "readcpu.h"
+
+int nr_cpuop_funcs;
+
+struct mnemolookup lookuptab[] = {
+    { i_ILLG, "ILLEGAL" },
+    { i_OR, "OR" },
+    { i_CHK, "CHK" },
+    { i_CHK2, "CHK2" },
+    { i_AND, "AND" },
+    { i_EOR, "EOR" },
+    { i_ORSR, "ORSR" },
+    { i_ANDSR, "ANDSR" },
+    { i_EORSR, "EORSR" },
+    { i_SUB, "SUB" },
+    { i_SUBA, "SUBA" },
+    { i_SUBX, "SUBX" },
+    { i_SBCD, "SBCD" },
+    { i_ADD, "ADD" },
+    { i_ADDA, "ADDA" },
+    { i_ADDX, "ADDX" },
+    { i_ABCD, "ABCD" },
+    { i_NEG, "NEG" },
+    { i_NEGX, "NEGX" },
+    { i_NBCD, "NBCD" },
+    { i_CLR, "CLR" },
+    { i_NOT, "NOT" },
+    { i_TST, "TST" },
+    { i_BTST, "BTST" },
+    { i_BCHG, "BCHG" },
+    { i_BCLR, "BCLR" },
+    { i_BSET, "BSET" },
+    { i_CMP, "CMP" },
+    { i_CMPM, "CMPM" },
+    { i_CMPA, "CMPA" },
+    { i_MVPRM, "MVPRM" },
+    { i_MVPMR, "MVPMR" },
+    { i_MOVE, "MOVE" },
+    { i_MOVEA, "MOVEA" },
+    { i_MVSR2, "MVSR2" },
+    { i_MV2SR, "MV2SR" },
+    { i_SWAP, "SWAP" },
+    { i_EXG, "EXG" },
+    { i_EXT, "EXT" },
+    { i_MVMEL, "MVMEL" },
+    { i_MVMLE, "MVMLE" },
+    { i_TRAP, "TRAP" },
+    { i_MVR2USP, "MVR2USP" },
+    { i_MVUSP2R, "MVUSP2R" },
+    { i_NOP, "NOP" },
+    { i_RESET, "RESET" },
+    { i_RTE, "RTE" },
+    { i_RTD, "RTD" },
+    { i_LINK, "LINK" },
+    { i_UNLK, "UNLK" },
+    { i_RTS, "RTS" },
+    { i_STOP, "STOP" },
+    { i_TRAPV, "TRAPV" },
+    { i_RTR, "RTR" },
+    { i_JSR, "JSR" },
+    { i_JMP, "JMP" },
+    { i_BSR, "BSR" },
+    { i_Bcc, "Bcc" },
+    { i_LEA, "LEA" },
+    { i_PEA, "PEA" },
+    { i_DBcc, "DBcc" },
+    { i_Scc, "Scc" },
+    { i_DIVU, "DIVU" },
+    { i_DIVS, "DIVS" },
+    { i_MULU, "MULU" },
+    { i_MULS, "MULS" },
+    { i_ASR, "ASR" },
+    { i_ASL, "ASL" },
+    { i_LSR, "LSR" },
+    { i_LSL, "LSL" },
+    { i_ROL, "ROL" },
+    { i_ROR, "ROR" },
+    { i_ROXL, "ROXL" },
+    { i_ROXR, "ROXR" },
+    { i_ASRW, "ASRW" },
+    { i_ASLW, "ASLW" },
+    { i_LSRW, "LSRW" },
+    { i_LSLW, "LSLW" },
+    { i_ROLW, "ROLW" },
+    { i_RORW, "RORW" },
+    { i_ROXLW, "ROXLW" },
+    { i_ROXRW, "ROXRW" },
+
+    { i_MOVE2C, "MOVE2C" },
+    { i_MOVEC2, "MOVEC2" },
+    { i_CAS, "CAS" },
+    { i_CAS2, "CAS2" },
+    { i_MULL, "MULL" },
+    { i_DIVL, "DIVL" },
+    { i_BFTST, "BFTST" },
+    { i_BFEXTU, "BFEXTU" },
+    { i_BFCHG, "BFCHG" },
+    { i_BFEXTS, "BFEXTS" },
+    { i_BFCLR, "BFCLR" },
+    { i_BFFFO, "BFFFO" },
+    { i_BFSET, "BFSET" },
+    { i_BFINS, "BFINS" },
+    { i_PACK, "PACK" },
+    { i_UNPK, "UNPK" },
+    { i_TAS, "TAS" },
+    { i_BKPT, "BKPT" },
+    { i_CALLM, "CALLM" },
+    { i_RTM, "RTM" },
+    { i_TRAPcc, "TRAPcc" },
+    { i_MOVES, "MOVES" },
+    { i_FPP, "FPP" },
+    { i_FDBcc, "FDBcc" },
+    { i_FScc, "FScc" },
+    { i_FTRAPcc, "FTRAPcc" },
+    { i_FBcc, "FBcc" },
+    { i_FBcc, "FBcc" },
+    { i_FSAVE, "FSAVE" },
+    { i_FRESTORE, "FRESTORE" },
+
+    { i_CINVL, "CINVL" },
+    { i_CINVP, "CINVP" },
+    { i_CINVA, "CINVA" },
+    { i_CPUSHL, "CPUSHL" },
+    { i_CPUSHP, "CPUSHP" },
+    { i_CPUSHA, "CPUSHA" },
+    { i_MOVE16, "MOVE16" },
+
+    { i_MMUOP, "MMUOP" },
+    { i_ILLG, "" },
+};
+
+struct instr *table68k;
+
+STATIC_INLINE amodes mode_from_str (const char *str)
+{
+    if (strncmp (str, "Dreg", 4) == 0) return Dreg;
+    if (strncmp (str, "Areg", 4) == 0) return Areg;
+    if (strncmp (str, "Aind", 4) == 0) return Aind;
+    if (strncmp (str, "Apdi", 4) == 0) return Apdi;
+    if (strncmp (str, "Aipi", 4) == 0) return Aipi;
+    if (strncmp (str, "Ad16", 4) == 0) return Ad16;
+    if (strncmp (str, "Ad8r", 4) == 0) return Ad8r;
+    if (strncmp (str, "absw", 4) == 0) return absw;
+    if (strncmp (str, "absl", 4) == 0) return absl;
+    if (strncmp (str, "PC16", 4) == 0) return PC16;
+    if (strncmp (str, "PC8r", 4) == 0) return PC8r;
+    if (strncmp (str, "Immd", 4) == 0) return imm;
+    abort ();
+    return 0;
+}
+
+STATIC_INLINE amodes mode_from_mr (int mode, int reg)
+{
+    switch (mode) {
+     case 0: return Dreg;
+     case 1: return Areg;
+     case 2: return Aind;
+     case 3: return Aipi;
+     case 4: return Apdi;
+     case 5: return Ad16;
+     case 6: return Ad8r;
+     case 7:
+       switch (reg) {
+        case 0: return absw;
+        case 1: return absl;
+        case 2: return PC16;
+        case 3: return PC8r;
+        case 4: return imm;
+        case 5:
+        case 6:
+        case 7: return am_illg;
+       }
+    }
+    abort ();
+    return 0;
+}
+
+static void build_insn (int insn)
+{
+    int find = -1;
+    int variants;
+    int isjmp = 0;
+    struct instr_def id;
+    const char *opcstr;
+    int i;
+
+    int flaglive = 0, flagdead = 0;
+
+    id = defs68k[insn];
+
+    /* Note: We treat anything with unknown flags as a jump. That
+       is overkill, but "the programmer" was lazy quite often, and
+       *this* programmer can't be bothered to work out what can and
+       can't trap. Usually, this will be overwritten with the gencomp
+       based information, anyway. */
+
+    for (i = 0; i < 5; i++) {
+       switch (id.flaginfo[i].flagset){
+       case fa_unset: break;
+       case fa_isjmp: isjmp = 1; break;
+       case fa_isbranch: isjmp = 1; break;
+       case fa_zero: flagdead |= 1 << i; break;
+       case fa_one: flagdead |= 1 << i; break;
+       case fa_dontcare: flagdead |= 1 << i; break;
+       case fa_unknown: isjmp = 1; flagdead = -1; goto out1;
+       case fa_set: flagdead |= 1 << i; break;
+       }
+    }
+
+  out1:
+    for (i = 0; i < 5; i++) {
+       switch (id.flaginfo[i].flaguse) {
+       case fu_unused: break;
+       case fu_isjmp: isjmp = 1; flaglive |= 1 << i; break;
+       case fu_maybecc: isjmp = 1; flaglive |= 1 << i; break;
+       case fu_unknown: isjmp = 1; flaglive |= 1 << i; break;
+       case fu_used: flaglive |= 1 << i; break;
+       }
+    }
+
+    opcstr = id.opcstr;
+    for (variants = 0; variants < (1 << id.n_variable); variants++) {
+       int bitcnt[lastbit];
+       int bitval[lastbit];
+       int bitpos[lastbit];
+       int i;
+       uae_u16 opc = id.bits;
+       uae_u16 msk, vmsk;
+       int pos = 0;
+       int mnp = 0;
+       int bitno = 0;
+       char mnemonic[10];
+
+       wordsizes sz = sz_long;
+       int srcgather = 0, dstgather = 0;
+       int usesrc = 0, usedst = 0;
+       int srctype = 0;
+       int srcpos = -1, dstpos = -1;
+
+       amodes srcmode = am_unknown, destmode = am_unknown;
+       int srcreg = -1, destreg = -1;
+
+       for (i = 0; i < lastbit; i++)
+           bitcnt[i] = bitval[i] = 0;
+
+       vmsk = 1 << id.n_variable;
+
+       for (i = 0, msk = 0x8000; i < 16; i++, msk >>= 1) {
+           if (!(msk & id.mask)) {
+               int currbit = id.bitpos[bitno++];
+               int bit_set;
+               vmsk >>= 1;
+               bit_set = variants & vmsk ? 1 : 0;
+               if (bit_set)
+                   opc |= msk;
+               bitpos[currbit] = 15 - i;
+               bitcnt[currbit]++;
+               bitval[currbit] <<= 1;
+               bitval[currbit] |= bit_set;
+           }
+       }
+
+       if (bitval[bitj] == 0) bitval[bitj] = 8;
+       /* first check whether this one does not match after all */
+       if (bitval[bitz] == 3 || bitval[bitC] == 1)
+           continue;
+       if (bitcnt[bitI] && (bitval[bitI] == 0x00 || bitval[bitI] == 0xff))
+           continue;
+
+       /* bitI and bitC get copied to biti and bitc */
+       if (bitcnt[bitI]) {
+           bitval[biti] = bitval[bitI]; bitpos[biti] = bitpos[bitI];
+       }
+       if (bitcnt[bitC])
+           bitval[bitc] = bitval[bitC];
+
+       pos = 0;
+       while (opcstr[pos] && !isspace(opcstr[pos])) {
+           if (opcstr[pos] == '.') {
+               pos++;
+               switch (opcstr[pos]) {
+
+               case 'B': sz = sz_byte; break;
+               case 'W': sz = sz_word; break;
+               case 'L': sz = sz_long; break;
+               case 'z':
+                   switch (bitval[bitz]) {
+                   case 0: sz = sz_byte; break;
+                   case 1: sz = sz_word; break;
+                   case 2: sz = sz_long; break;
+                   default: abort();
+                   }
+                   break;
+               default: abort();
+               }
+           } else {
+               mnemonic[mnp] = opcstr[pos];
+               if (mnemonic[mnp] == 'f') {
+                   find = -1;
+                   switch (bitval[bitf]) {
+                   case 0: mnemonic[mnp] = 'R'; break;
+                   case 1: mnemonic[mnp] = 'L'; break;
+                   default: abort();
+                   }
+               }
+               mnp++;
+           }
+           pos++;
+       }
+       mnemonic[mnp] = 0;
+
+       /* now, we have read the mnemonic and the size */
+       while (opcstr[pos] && isspace(opcstr[pos]))
+           pos++;
+
+       /* A goto a day keeps the D******a away. */
+       if (opcstr[pos] == 0)
+           goto endofline;
+
+       /* parse the source address */
+       usesrc = 1;
+       switch (opcstr[pos++]) {
+       case 'D':
+           srcmode = Dreg;
+           switch (opcstr[pos++]) {
+           case 'r': srcreg = bitval[bitr]; srcgather = 1; srcpos = bitpos[bitr]; break;
+           case 'R': srcreg = bitval[bitR]; srcgather = 1; srcpos = bitpos[bitR]; break;
+           default: abort();
+           }
+           break;
+       case 'A':
+           srcmode = Areg;
+           switch (opcstr[pos++]) {
+           case 'r': srcreg = bitval[bitr]; srcgather = 1; srcpos = bitpos[bitr]; break;
+           case 'R': srcreg = bitval[bitR]; srcgather = 1; srcpos = bitpos[bitR]; break;
+           default: abort();
+           }
+           switch (opcstr[pos]) {
+           case 'p': srcmode = Apdi; pos++; break;
+           case 'P': srcmode = Aipi; pos++; break;
+           }
+           break;
+       case 'L':
+           srcmode = absl;
+           break;
+       case '#':
+           switch (opcstr[pos++]) {
+           case 'z': srcmode = imm; break;
+           case '0': srcmode = imm0; break;
+           case '1': srcmode = imm1; break;
+           case '2': srcmode = imm2; break;
+           case 'i': srcmode = immi; srcreg = (uae_s32)(uae_s8)bitval[biti];
+               if (CPU_EMU_SIZE < 4) {
+                   /* Used for branch instructions */
+                   srctype = 1;
+                   srcgather = 1;
+                   srcpos = bitpos[biti];
+               }
+               break;
+           case 'j': srcmode = immi; srcreg = bitval[bitj];
+               if (CPU_EMU_SIZE < 3) {
+                   /* 1..8 for ADDQ/SUBQ and rotshi insns */
+                   srcgather = 1;
+                   srctype = 3;
+                   srcpos = bitpos[bitj];
+               }
+               break;
+           case 'J': srcmode = immi; srcreg = bitval[bitJ];
+               if (CPU_EMU_SIZE < 5) {
+                   /* 0..15 */
+                   srcgather = 1;
+                   srctype = 2;
+                   srcpos = bitpos[bitJ];
+               }
+               break;
+           case 'k': srcmode = immi; srcreg = bitval[bitk];
+               if (CPU_EMU_SIZE < 3) {
+                   srcgather = 1;
+                   srctype = 4;
+                   srcpos = bitpos[bitk];
+               }
+               break;
+           case 'K': srcmode = immi; srcreg = bitval[bitK];
+               if (CPU_EMU_SIZE < 5) {
+                   /* 0..15 */
+                   srcgather = 1;
+                   srctype = 5;
+                   srcpos = bitpos[bitK];
+               }
+               break;
+           case 'p': srcmode = immi; srcreg = bitval[bitK];
+               if (CPU_EMU_SIZE < 5) {
+                   /* 0..3 */
+                   srcgather = 1;
+                   srctype = 7;
+                   srcpos = bitpos[bitp];
+               }
+               break;
+           default: abort();
+           }
+           break;
+       case 'd':
+           srcreg = bitval[bitD];
+           srcmode = mode_from_mr(bitval[bitd],bitval[bitD]);
+           if (srcmode == am_illg)
+               continue;
+           if (CPU_EMU_SIZE < 2 &&
+               (srcmode == Areg || srcmode == Dreg || srcmode == Aind
+                || srcmode == Ad16 || srcmode == Ad8r || srcmode == Aipi
+                || srcmode == Apdi))
+               {
+                   srcgather = 1; srcpos = bitpos[bitD];
+               }
+           if (opcstr[pos] == '[') {
+               pos++;
+               if (opcstr[pos] == '!') {
+                   /* exclusion */
+                   do {
+                       pos++;
+                       if (mode_from_str(opcstr+pos) == srcmode)
+                           goto nomatch;
+                       pos += 4;
+                   } while (opcstr[pos] == ',');
+                   pos++;
+               } else {
+                   if (opcstr[pos+4] == '-') {
+                       /* replacement */
+                       if (mode_from_str(opcstr+pos) == srcmode)
+                           srcmode = mode_from_str(opcstr+pos+5);
+                       else
+                           goto nomatch;
+                       pos += 10;
+                   } else {
+                       /* normal */
+                       while(mode_from_str(opcstr+pos) != srcmode) {
+                           pos += 4;
+                           if (opcstr[pos] == ']')
+                               goto nomatch;
+                           pos++;
+                       }
+                       while(opcstr[pos] != ']') pos++;
+                       pos++;
+                       break;
+                   }
+               }
+           }
+           /* Some addressing modes are invalid as destination */
+           if (srcmode == imm || srcmode == PC16 || srcmode == PC8r)
+               goto nomatch;
+           break;
+       case 's':
+           srcreg = bitval[bitS];
+           srcmode = mode_from_mr(bitval[bits],bitval[bitS]);
+
+           if (srcmode == am_illg)
+               continue;
+           if (CPU_EMU_SIZE < 2 &&
+               (srcmode == Areg || srcmode == Dreg || srcmode == Aind
+                || srcmode == Ad16 || srcmode == Ad8r || srcmode == Aipi
+                || srcmode == Apdi))
+               {
+                   srcgather = 1; srcpos = bitpos[bitS];
+               }
+           if (opcstr[pos] == '[') {
+               pos++;
+               if (opcstr[pos] == '!') {
+                   /* exclusion */
+                   do {
+                       pos++;
+                       if (mode_from_str(opcstr+pos) == srcmode)
+                           goto nomatch;
+                       pos += 4;
+                   } while (opcstr[pos] == ',');
+                   pos++;
+               } else {
+                   if (opcstr[pos+4] == '-') {
+                       /* replacement */
+                       if (mode_from_str(opcstr+pos) == srcmode)
+                           srcmode = mode_from_str(opcstr+pos+5);
+                       else
+                           goto nomatch;
+                       pos += 10;
+                   } else {
+                       /* normal */
+                       while(mode_from_str(opcstr+pos) != srcmode) {
+                           pos += 4;
+                           if (opcstr[pos] == ']')
+                               goto nomatch;
+                           pos++;
+                       }
+                       while(opcstr[pos] != ']') pos++;
+                       pos++;
+                   }
+               }
+           }
+           break;
+       default: abort();
+       }
+       /* safety check - might have changed */
+       if (srcmode != Areg && srcmode != Dreg && srcmode != Aind
+           && srcmode != Ad16 && srcmode != Ad8r && srcmode != Aipi
+           && srcmode != Apdi && srcmode != immi)
+           {
+               srcgather = 0;
+           }
+       if (srcmode == Areg && sz == sz_byte)
+           goto nomatch;
+
+       if (opcstr[pos] != ',')
+           goto endofline;
+       pos++;
+
+       /* parse the destination address */
+       usedst = 1;
+       switch (opcstr[pos++]) {
+       case 'D':
+           destmode = Dreg;
+           switch (opcstr[pos++]) {
+           case 'r': destreg = bitval[bitr]; dstgather = 1; dstpos = bitpos[bitr]; break;
+           case 'R': destreg = bitval[bitR]; dstgather = 1; dstpos = bitpos[bitR]; break;
+           default: abort();
+           }
+            if (dstpos < 0 || dstpos >= 32)
+               abort ();
+           break;
+       case 'A':
+           destmode = Areg;
+           switch (opcstr[pos++]) {
+           case 'r': destreg = bitval[bitr]; dstgather = 1; dstpos = bitpos[bitr]; break;
+           case 'R': destreg = bitval[bitR]; dstgather = 1; dstpos = bitpos[bitR]; break;
+           case 'x': destreg = 0; dstgather = 0; dstpos = 0; break;
+           default: abort();
+           }
+            if (dstpos < 0 || dstpos >= 32)
+               abort ();
+           switch (opcstr[pos]) {
+           case 'p': destmode = Apdi; pos++; break;
+           case 'P': destmode = Aipi; pos++; break;
+           }
+           break;
+       case 'L':
+           destmode = absl;
+           break;
+       case '#':
+           switch (opcstr[pos++]) {
+           case 'z': destmode = imm; break;
+           case '0': destmode = imm0; break;
+           case '1': destmode = imm1; break;
+           case '2': destmode = imm2; break;
+           case 'i': destmode = immi; destreg = (uae_s32)(uae_s8)bitval[biti]; break;
+           case 'j': destmode = immi; destreg = bitval[bitj]; break;
+           case 'J': destmode = immi; destreg = bitval[bitJ]; break;
+           case 'k': destmode = immi; destreg = bitval[bitk]; break;
+           case 'K': destmode = immi; destreg = bitval[bitK]; break;
+           default: abort();
+           }
+           break;
+       case 'd':
+           destreg = bitval[bitD];
+           destmode = mode_from_mr(bitval[bitd],bitval[bitD]);
+           if (destmode == am_illg)
+               continue;
+           if (CPU_EMU_SIZE < 1 &&
+               (destmode == Areg || destmode == Dreg || destmode == Aind
+                || destmode == Ad16 || destmode == Ad8r || destmode == Aipi
+                || destmode == Apdi))
+               {
+                   dstgather = 1; dstpos = bitpos[bitD];
+               }
+
+           if (opcstr[pos] == '[') {
+               pos++;
+               if (opcstr[pos] == '!') {
+                   /* exclusion */
+                   do {
+                       pos++;
+                       if (mode_from_str(opcstr+pos) == destmode)
+                           goto nomatch;
+                       pos += 4;
+                   } while (opcstr[pos] == ',');
+                   pos++;
+               } else {
+                   if (opcstr[pos+4] == '-') {
+                       /* replacement */
+                       if (mode_from_str(opcstr+pos) == destmode)
+                           destmode = mode_from_str(opcstr+pos+5);
+                       else
+                           goto nomatch;
+                       pos += 10;
+                   } else {
+                       /* normal */
+                       while(mode_from_str(opcstr+pos) != destmode) {
+                           pos += 4;
+                           if (opcstr[pos] == ']')
+                               goto nomatch;
+                           pos++;
+                       }
+                       while(opcstr[pos] != ']') pos++;
+                       pos++;
+                       break;
+                   }
+               }
+           }
+           /* Some addressing modes are invalid as destination */
+           if (destmode == imm || destmode == PC16 || destmode == PC8r)
+               goto nomatch;
+           break;
+       case 's':
+           destreg = bitval[bitS];
+           destmode = mode_from_mr(bitval[bits],bitval[bitS]);
+
+           if (destmode == am_illg)
+               continue;
+           if (CPU_EMU_SIZE < 1 &&
+               (destmode == Areg || destmode == Dreg || destmode == Aind
+                || destmode == Ad16 || destmode == Ad8r || destmode == Aipi
+                || destmode == Apdi))
+               {
+                   dstgather = 1; dstpos = bitpos[bitS];
+               }
+
+           if (opcstr[pos] == '[') {
+               pos++;
+               if (opcstr[pos] == '!') {
+                   /* exclusion */
+                   do {
+                       pos++;
+                       if (mode_from_str(opcstr+pos) == destmode)
+                           goto nomatch;
+                       pos += 4;
+                   } while (opcstr[pos] == ',');
+                   pos++;
+               } else {
+                   if (opcstr[pos+4] == '-') {
+                       /* replacement */
+                       if (mode_from_str(opcstr+pos) == destmode)
+                           destmode = mode_from_str(opcstr+pos+5);
+                       else
+                           goto nomatch;
+                       pos += 10;
+                   } else {
+                       /* normal */
+                       while(mode_from_str(opcstr+pos) != destmode) {
+                           pos += 4;
+                           if (opcstr[pos] == ']')
+                               goto nomatch;
+                           pos++;
+                       }
+                       while(opcstr[pos] != ']') pos++;
+                       pos++;
+                   }
+               }
+           }
+           break;
+       default: abort();
+       }
+       /* safety check - might have changed */
+       if (destmode != Areg && destmode != Dreg && destmode != Aind
+           && destmode != Ad16 && destmode != Ad8r && destmode != Aipi
+           && destmode != Apdi)
+           {
+               dstgather = 0;
+           }
+
+       if (destmode == Areg && sz == sz_byte)
+           goto nomatch;
+#if 0
+       if (sz == sz_byte && (destmode == Aipi || destmode == Apdi)) {
+           dstgather = 0;
+       }
+#endif
+      endofline:
+       /* now, we have a match */
+       if (table68k[opc].mnemo != i_ILLG)
+           write_log ("Double match: %x: %s\n", opc, opcstr);
+       if (find == -1) {
+           for (find = 0;; find++) {
+               if (strcmp(mnemonic, lookuptab[find].name) == 0) {
+                   table68k[opc].mnemo = lookuptab[find].mnemo;
+                   break;
+               }
+               if (strlen(lookuptab[find].name) == 0) abort();
+           }
+       }
+       else {
+           table68k[opc].mnemo = lookuptab[find].mnemo;
+       }
+       table68k[opc].cc = bitval[bitc];
+       if (table68k[opc].mnemo == i_BTST
+           || table68k[opc].mnemo == i_BSET
+           || table68k[opc].mnemo == i_BCLR
+           || table68k[opc].mnemo == i_BCHG)
+           {
+               sz = destmode == Dreg ? sz_long : sz_byte;
+           }
+       table68k[opc].size = sz;
+       table68k[opc].sreg = srcreg;
+       table68k[opc].dreg = destreg;
+       table68k[opc].smode = srcmode;
+       table68k[opc].dmode = destmode;
+       table68k[opc].spos = srcgather ? srcpos : -1;
+       table68k[opc].dpos = dstgather ? dstpos : -1;
+       table68k[opc].suse = usesrc;
+       table68k[opc].duse = usedst;
+       table68k[opc].stype = srctype;
+       table68k[opc].plev = id.plevel;
+       table68k[opc].clev = id.cpulevel;
+#if 0
+       for (i = 0; i < 5; i++) {
+           table68k[opc].flaginfo[i].flagset = id.flaginfo[i].flagset;
+           table68k[opc].flaginfo[i].flaguse = id.flaginfo[i].flaguse;
+       }
+#endif
+       table68k[opc].flagdead = flagdead;
+       table68k[opc].flaglive = flaglive;
+       table68k[opc].isjmp = isjmp;
+      nomatch:
+       /* FOO! */;
+    }
+}
+
+
+void read_table68k (void)
+{
+    int i;
+
+    free (table68k);
+    table68k = (struct instr *)xmalloc (65536 * sizeof (struct instr));
+    for (i = 0; i < 65536; i++) {
+       table68k[i].mnemo = i_ILLG;
+       table68k[i].handler = -1;
+    }
+    for (i = 0; i < n_defs68k; i++) {
+       build_insn (i);
+    }
+}
+
+static int mismatch;
+
+static void handle_merges (long int opcode)
+{
+    uae_u16 smsk;
+    uae_u16 dmsk;
+    int sbitdst, dstend;
+    int srcreg, dstreg;
+
+    if (table68k[opcode].spos == -1) {
+       sbitdst = 1; smsk = 0;
+    } else {
+       switch (table68k[opcode].stype) {
+        case 0:
+           smsk = 7; sbitdst = 8; break;
+        case 1:
+           smsk = 255; sbitdst = 256; break;
+        case 2:
+           smsk = 15; sbitdst = 16; break;
+        case 3:
+           smsk = 7; sbitdst = 8; break;
+        case 4:
+           smsk = 7; sbitdst = 8; break;
+        case 5:
+           smsk = 63; sbitdst = 64; break;
+        case 7:
+           smsk = 3; sbitdst = 4; break;
+        default:
+           smsk = 0; sbitdst = 0;
+           abort();
+           break;
+       }
+       smsk <<= table68k[opcode].spos;
+    }
+    if (table68k[opcode].dpos == -1) {
+       dstend = 1; dmsk = 0;
+    } else {
+       dmsk = 7 << table68k[opcode].dpos;
+       dstend = 8;
+    }
+    for (srcreg=0; srcreg < sbitdst; srcreg++) {
+       for (dstreg=0; dstreg < dstend; dstreg++) {
+           uae_u16 code = (uae_u16)opcode;
+
+           code = (code & ~smsk) | (srcreg << table68k[opcode].spos);
+           code = (code & ~dmsk) | (dstreg << table68k[opcode].dpos);
+
+           /* Check whether this is in fact the same instruction.
+            * The instructions should never differ, except for the
+            * Bcc.(BW) case. */
+           if (table68k[code].mnemo != table68k[opcode].mnemo
+               || table68k[code].size != table68k[opcode].size
+               || table68k[code].suse != table68k[opcode].suse
+               || table68k[code].duse != table68k[opcode].duse)
+           {
+               mismatch++; continue;
+           }
+           if (table68k[opcode].suse
+               && (table68k[opcode].spos != table68k[code].spos
+                   || table68k[opcode].smode != table68k[code].smode
+                   || table68k[opcode].stype != table68k[code].stype))
+           {
+               mismatch++; continue;
+           }
+           if (table68k[opcode].duse
+               && (table68k[opcode].dpos != table68k[code].dpos
+                   || table68k[opcode].dmode != table68k[code].dmode))
+           {
+               mismatch++; continue;
+           }
+
+           if (code != opcode)
+               table68k[code].handler = opcode;
+       }
+    }
+}
+
+void do_merges (void)
+{
+    long int opcode;
+    int nr = 0;
+    mismatch = 0;
+    for (opcode = 0; opcode < 65536; opcode++) {
+       if (table68k[opcode].handler != -1 || table68k[opcode].mnemo == i_ILLG)
+           continue;
+       nr++;
+       handle_merges (opcode);
+    }
+    nr_cpuop_funcs = nr;
+}
+
+int get_no_mismatches (void)
+{
+    return mismatch;
+}
diff --git a/readdisk.c b/readdisk.c
new file mode 100755 (executable)
index 0000000..8b5e3a4
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * readdisk
+ *
+ * Read files from Amiga disk files
+ *
+ * Copyright 1996 Bernd Schmidt
+ * Copyright 1998 Jim Cooper
+ */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "uae.h"
+
+void write_log (const char *s,...)
+{
+    fprintf (stderr, "%s", s);
+}
+
+unsigned char filemem[901120];
+
+typedef struct afile {
+    struct afile *sibling;
+    unsigned char *data;
+    uae_u32 size;
+    char name[32];
+} afile;
+
+typedef struct directory {
+    struct directory *sibling;
+    struct directory *subdirs;
+    struct afile *files;
+    char name[32];
+} directory;
+
+static int secdatasize, secdataoffset;
+
+static uae_u32 readlong (unsigned char *buffer, int pos)
+{
+    return ((*(buffer + pos) << 24) + (*(buffer + pos + 1) << 16)
+           + (*(buffer + pos + 2) << 8) + *(buffer + pos + 3));
+}
+
+static afile *read_file (unsigned char *filebuf)
+{
+    afile *a = (afile *) xmalloc (sizeof (afile));
+    int sizeleft;
+    unsigned char *datapos;
+    uae_u32 numblocks, blockpos;
+
+    /* BCPL strings... Yuk. */
+    memset (a->name, 0, 32);
+    strncpy (a->name, (const char *) filebuf + 0x1B1, *(filebuf + 0x1B0));
+    sizeleft = a->size = readlong (filebuf, 0x144);
+    a->data = (unsigned char *) xmalloc (a->size);
+
+    numblocks = readlong (filebuf, 0x8);
+    blockpos = 0x134;
+    datapos = a->data;
+    while (numblocks) {
+       unsigned char *databuf = filemem + 512 * readlong (filebuf, blockpos);
+       int readsize = sizeleft > secdatasize ? secdatasize : sizeleft;
+       memcpy (datapos, databuf + secdataoffset, readsize);
+       datapos += readsize;
+       sizeleft -= readsize;
+
+       blockpos -= 4;
+       numblocks--;
+       if (!numblocks) {
+           uae_u32 nextflb = readlong (filebuf, 0x1F8);
+           if (nextflb) {
+               filebuf = filemem + 512 * nextflb;
+               blockpos = 0x134;
+               numblocks = readlong (filebuf, 0x8);
+               if (!filebuf) {
+                   write_log ("Disk structure corrupted. Use DISKDOCTOR to correct it.\n");
+                   abort ();
+               }
+           }
+       }
+    }
+    return a;
+}
+
+static directory *read_dir (unsigned char *dirbuf)
+{
+    directory *d = (directory *) xmalloc (sizeof (directory));
+    uae_u32 hashsize;
+    uae_u32 i;
+
+    memset (d->name, 0, 32);
+    strncpy (d->name, (const char *) dirbuf + 0x1B1, *(dirbuf + 0x1B0));
+    d->sibling = 0;
+    d->subdirs = 0;
+    d->files = 0;
+    hashsize = readlong (dirbuf, 0xc);
+    if (!hashsize)
+       hashsize = 72;
+    if (hashsize != 72)
+       write_log ("Warning: Hash table with != 72 entries.\n");
+    for (i = 0; i < hashsize; i++) {
+       uae_u32 subblock = readlong (dirbuf, 0x18 + 4 * i);
+
+       while (subblock) {
+           directory *subdir;
+           afile *subfile;
+           unsigned char *subbuf = filemem + 512 * subblock;
+           long dirtype;
+
+           dirtype = (uae_s32) readlong (subbuf, 0x1FC);
+           if (dirtype > 0) {
+               subdir = read_dir (subbuf);
+               subdir->sibling = d->subdirs;
+               d->subdirs = subdir;
+           } else if (dirtype < 0) {
+               subfile = read_file (subbuf);
+               subfile->sibling = d->files;
+               d->files = subfile;
+           } else {
+               write_log ("Disk structure corrupted. Use DISKDOCTOR to correct it.\n");
+               abort ();
+           }
+           subblock = readlong (subbuf, 0x1F0);
+       }
+    }
+    return d;
+}
+
+static void writedir (directory * dir)
+{
+    directory *subdir;
+    afile *f;
+
+    if (mkdir (dir->name, 0777) < 0 && errno != EEXIST) {
+       write_log ("Could not create directory \"%s\". Giving up.\n", dir->name);
+       exit (20);
+    }
+    if (chdir (dir->name) < 0) {
+       write_log ("Could not enter directory \"%s\". Giving up.\n", dir->name);
+       exit (20);
+    }
+    for (subdir = dir->subdirs; subdir; subdir = subdir->sibling)
+       writedir (subdir);
+    for (f = dir->files; f; f = f->sibling) {
+       int fd = creat (f->name, 0666);
+       if (fd < 0) {
+           write_log ("Could not create file. Giving up.\n");
+           exit (20);
+       }
+       write (fd, f->data, f->size);
+       close (fd);
+    }
+    chdir ("..");
+}
+
+int main (int argc, char **argv)
+{
+    directory *root;
+    FILE *inf;
+
+    if (argc < 2 || argc > 3) {
+       write_log ("Usage: readdisk <file> [<destdir>]\n");
+       exit (20);
+    }
+    inf = fopen (argv[1], "rb");
+    if (inf == NULL) {
+       write_log ("can't open file\n");
+       exit (20);
+    }
+    fread (filemem, 1, 901120, inf);
+
+    if (strncmp ((const char *) filemem, "DOS\0", 4) == 0
+       || strncmp ((const char *) filemem, "DOS\2", 4) == 0) {
+       secdatasize = 488;
+       secdataoffset = 24;
+    } else if (strncmp ((const char *) filemem, "DOS\1", 4) == 0
+              || strncmp ((const char *) filemem, "DOS\3", 4) == 0) {
+       secdatasize = 512;
+       secdataoffset = 0;
+    } else {
+       write_log ("Not a DOS disk.\n");
+       exit (20);
+    }
+    root = read_dir (filemem + 880 * 512);
+
+    if (argc == 3)
+       if (chdir (argv[2]) < 0) {
+           write_log ("Couldn't change to %s. Giving up.\n", argv[2]);
+           exit (20);
+       }
+    writedir (root);
+    return 0;
+}
diff --git a/rpc.c b/rpc.c
new file mode 100755 (executable)
index 0000000..8cf04d8
--- /dev/null
+++ b/rpc.c
@@ -0,0 +1,677 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * RiscPC Interface.
+  *
+  * (c) 1995 Bernd Schmidt
+  * (c) 1996 Gustavo Goedert
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "threaddep/thread.h"
+#include "memory.h"
+#include "custom.h"
+#include "keyboard.h"
+#include "xwin.h"
+#include "keybuf.h"
+#include "gui.h"
+
+typedef char flagtype;
+
+extern struct regstruct
+{
+    ULONG regs[16];
+    CPTR  usp,isp,msp;
+    UWORD sr;
+    flagtype t1;
+    flagtype t0;
+    flagtype s;
+    flagtype m;
+    flagtype x;
+    flagtype stopped;
+    int intmask;
+    ULONG pc;
+#ifdef USE_POINTER
+    UBYTE *pc_p;
+    UBYTE *pc_oldp;
+#endif
+
+    ULONG vbr,sfc,dfc;
+
+    double fp[8];
+    ULONG fpcr,fpsr,fpiar;
+    ULONG spcflags;
+    ULONG kick_mask;
+} regs;
+
+
+#include "OS:wimp.h"
+#include "OS:font.h"
+#include "OS:os.h"
+#include "OS:osbyte.h"
+#include "OS:osword.h"
+#include "OS:sound.h"
+
+
+void gui_process(void);
+
+
+#define A_base 0x300000
+#define A_switch (A_base+0)
+#define A_disk (A_base+1)
+#define A_sonst (A_base+5)
+#define A_hf (A_base+6)
+#define A_mount (A_base+7)
+#define A_rom (A_base+10)
+#define A_uaeask (A_base+11)
+
+int quit_program;
+int uae_running;
+int uae_startedup;
+
+wimp_MESSAGE_LIST(13) messages=
+  {A_switch, A_disk, A_disk+1, A_disk+2, A_disk+3, A_sonst, A_rom, A_mount,
+   A_mount+1, A_mount+2, A_uaeask, message_PREQUIT, 0};
+
+wimp_t taskhandle;
+wimp_t frontendhandle;
+wimp_block block;
+wimp_message mblock;
+int pollword;
+
+os_MODE_SELECTOR(3) uaemode={1,0,0,0,-1,0,128,3,255,-1,0};
+os_MODE_SELECTOR(3) wimpmode;
+
+extern void datavox_type(int channel, int type);
+extern void datavox_timed(int channel, int timed);
+extern void datavox_pitch(int channel, int pitch);
+extern void datavox_set_memory(int channel, char *start, char *end);
+extern void datavox_set_repeat(int channel, char *start, char *end);
+extern int datavox_allocate_channel(int key);
+extern void datavox_de_allocate_channel(int channel, int key);
+
+int sratecode;
+char sbuffer[44100];
+int deskvoice, uaechannel;
+
+extern int uaedevfd, numtracks;
+
+char mountpoint[64];
+char mountdir[256];
+
+char *scr;
+int screenrowbytes,screenrows;
+
+char pressed[128];
+char translate[128]=
+{        255,    255,     255,  AK_LSH, AK_CTRL,     AK_LALT,  AK_RSH,     AK_CTRL, //0
+     AK_RALT,    255,     255,     255,     255,         255,     255,         255, //8
+       AK_Q,   AK_3,    AK_4,    AK_5,   AK_F4,        AK_8,   AK_F7,    AK_MINUS, //16
+        255,  AK_LF,  AK_NP6,  AK_NP7,     255,         255,  AK_F10,         255, //24
+        255,   AK_W,    AK_E,    AK_T,    AK_7,        AK_I,    AK_9,        AK_0, //32
+        255,  AK_DN,  AK_NP8,  AK_NP9,     255,AK_BACKQUOTE, AK_LTGT,       AK_BS, //40
+       AK_1,   AK_2,    AK_D,    AK_R,    AK_6,        AK_U,    AK_O,        AK_P, //48
+ AK_LBRACKET,  AK_UP,AK_NPADD,AK_NPSUB,  AK_ENT,         255,     255,     AK_RAMI, //56
+ AK_CAPSLOCK,   AK_A,    AK_X,    AK_F,    AK_Y,        AK_J,    AK_K,         255, //64
+        255, AK_RET,AK_NPDIV,     255,AK_NPDEL,         255, AK_LAMI,    AK_QUOTE, //72
+        255,   AK_S,    AK_C,    AK_G,    AK_H,        AK_N,    AK_L,AK_SEMICOLON, //80
+ AK_RBRACKET, AK_DEL,     255,AK_NPMUL,     255,    AK_EQUAL, AK_LTGT,         255, //88
+      AK_TAB,   AK_Z,  AK_SPC,    AK_V,    AK_B,        AK_M,AK_COMMA,   AK_PERIOD, //96
+    AK_SLASH,AK_HELP,  AK_NP0,  AK_NP1,  AK_NP3,         255,     255,         255, //104
+        255,  AK_F1,   AK_F2,   AK_F3,   AK_F5,       AK_F6,   AK_F8,       AK_F9, //112
+AK_BACKSLASH,  AK_RT,  AK_NP4,  AK_NP5,  AK_NP2,         255,     255,         255};//120
+
+char dn0[256], dn1[256], dn2[256], dn3[256];
+int dc0=0, dc1=0, dc2=0, dc3=0;
+
+/***************************************************************************/
+
+
+void setup_brkhandler(void)
+{
+}
+
+void flush_line(int y)
+{
+}
+
+void flush_block(int a, int b)
+{
+}
+
+void flush_screen(int a, int b)
+{
+}
+
+void calc_adjustment(void)
+{
+}
+
+
+static int colors_allocated;
+
+static int get_color(int r, int g, int b, xcolnr *cnp)
+{
+    if (colors_allocated == 256)
+       return -1;
+    *cnp = colors_allocated;
+
+    os_writec(19);
+    os_writec(colors_allocated);
+    os_writec(16);
+    os_writec(r+(r<<4));
+    os_writec(g+(g<<4));
+    os_writec(b+(b<<4));
+    colors_allocated++;
+
+    return 1;
+}
+
+static void init_colors(void)
+{
+    int rw = 5, gw = 5, bw = 5;
+    colors_allocated = 0;
+
+    if (gfxvidinfo.pixbytes == 2)
+      alloc_colors64k(rw, gw, bw, 0, rw, rw+gw);
+    else
+      alloc_colors256(get_color);
+}
+
+void sound_output(char *b, int l)
+{
+  memcpy(sbuffer, b, l);
+  datavox_set_memory(uaechannel, sbuffer, sbuffer+l);
+  datavox_set_repeat(uaechannel, sbuffer, sbuffer+l);
+  datavox_type(uaechannel, 1);
+  datavox_pitch(uaechannel, sratecode);
+  sound_control(uaechannel, 256+127, 0, 255);
+}
+
+void init_mouse(void)
+{
+  oswordpointer_bbox_block bbox;
+
+  bbox.op=oswordpointer_OP_SET_BBOX;
+  bbox.x0=-32768;
+  bbox.y0=-32768;
+  bbox.x1=32767;
+  bbox.y1=32767;
+  oswordpointer_set_bbox(&bbox);
+}
+
+void setwimpmode(void)
+{
+  wimp_set_mode(&wimpmode);
+  while(osbyte2(145,0,0)!=0);
+}
+
+void setuaemode(void)
+{
+  os_vdu_var_list varlist[2]={149,-1};
+  int valuelist[1];
+  os_mode m;
+
+  m=osscreenmode_current();
+  memcpy(&wimpmode, m, os_SIZEOF_MODE_SELECTOR(3));
+
+  osscreenmode_select(&uaemode);
+  os_read_vdu_variables(varlist, valuelist);
+  scr=(void *)valuelist[0];
+  gfxvidinfo.bufmem=scr;
+
+  os_remove_cursors();
+
+  init_colors();
+  init_mouse();
+
+  flush_block(0, numscrlines-1);
+}
+
+void setwimpsound(void)
+{
+  int s,t;
+
+  sound_attach_voice(uaechannel, deskvoice, &s, &t);
+  datavox_de_allocate_channel(uaechannel, taskhandle);
+}
+
+void setuaesound(void)
+{
+  int s;
+
+  sound_volume(127);
+  uaechannel=datavox_allocate_channel(taskhandle);
+  printf("%d\n", uaechannel);
+  sound_attach_voice(uaechannel, 0, &s, &deskvoice);
+  sound_attach_named_voice(uaechannel, "DataVox-Voice");
+}
+
+int graphics_init(void)
+{
+  __uname_control=6;
+
+  switch(color_mode)
+  {
+    case 1:
+    case 2:
+    case 5:
+      uaemode.log2_bpp=4;
+      gfxvidinfo.pixbytes=2;
+      break;
+    default:
+      uaemode.log2_bpp=3;
+      gfxvidinfo.pixbytes=1;
+      break;
+  }
+
+  uaemode.xres=gfx_requested_width;
+  uaemode.yres=gfx_requested_height;
+
+  gfxvidinfo.rowbytes=gfx_requested_width*gfxvidinfo.pixbytes;
+  gfxvidinfo.maxlinetoscr=gfx_requested_width;
+  gfxvidinfo.maxline=gfx_requested_height;
+  gfxvidinfo.maxblocklines=0;
+
+  setuaemode();
+  setuaesound();
+
+  return 1;
+}
+
+void graphics_leave(void)
+{
+}
+
+
+void readmouse(void)
+{
+  int x,y;
+  bits buttons;
+  os_t t;
+
+  os_mouse(&x, &y, &buttons, &t);
+  lastmx=x>>1;
+  lastmy=gfx_requested_height-(y>>1);
+  buttonstate[0]=(buttons & 4)>>2;
+  buttonstate[1]=(buttons & 2)>>1;
+  buttonstate[2]=buttons & 1;
+  newmousecounters=0;
+}
+
+
+void processkey(char k, char release)
+{
+  if(k==29 && release==1)
+  {
+    uae_running=0;
+    setwimpmode();
+    setwimpsound();
+  }
+
+  if(translate[k]!=255)
+    record_key((translate[k]<<1)+release);
+}
+
+
+void readkeyboard(void)
+{
+  char c,l,k,q;
+
+  for(l=0, k=osbyte1(121, 0, 0), q=0; !q; l=k+1, k=osbyte1(121, l, 0))
+  {
+    if(k==0xff)
+    {
+      k=128;
+      q=1;
+    }
+    else
+    {
+      if(pressed[k]==0)
+      {
+       if (translate[k]!=0)
+         processkey(k, 0);
+       pressed[k]=1;
+      }
+    }
+    for(c=l; c<k; c++)
+    {
+      if(pressed[c]!=0)
+      {
+       if (translate[c]!=0)
+         processkey(c, 1);
+       pressed[c]=0;
+      }
+    }
+  }
+}
+
+void handle_events(void)
+{
+  readmouse();
+  readkeyboard();
+
+  if(dc0==1)
+  {
+    dc0=0;
+    disk_insert(0, dn0);
+    strncpy(df0, dn0, 255);
+  }
+
+  if(dc1==1)
+  {
+    dc1=0;
+    disk_insert(1, dn1);
+    strncpy(df1, dn1, 255);
+  }
+
+  if(dc2==1)
+  {
+    dc2=0;
+    disk_insert(2, dn2);
+    strncpy(df2, dn2, 255);
+  }
+
+  if(dc3==1)
+  {
+    dc3=0;
+    disk_insert(3, dn3);
+    strncpy(df3, dn3, 255);
+  }
+
+  if(dc0>1) dc0--;
+  if(dc1>1) dc1--;
+  if(dc2>1) dc2--;
+  if(dc3>1) dc3--;
+
+  if (uae_running==0)
+    gui_process();
+}
+
+int debuggable(void)
+{
+    return 0;
+}
+
+int needmousehack(void)
+{
+    return 0;
+}
+
+void LED(int on)
+{
+}
+
+static void sigchldhandler(int foo)
+{
+}
+
+
+/***************************************************************************/
+
+
+int gui_init(void)
+{
+  int vout;
+
+  quit_program=0;
+  uae_running=0;
+  uae_startedup=0;
+
+  taskhandle=wimp_initialise(wimp_VERSION_RO35, "UAE", &messages, &vout);
+  gui_process();
+
+  return 0;
+}
+
+void changedisk(int n, char *f)
+{
+  if(uae_startedup)
+  {
+    switch(n)
+    {
+      case 0:
+       if(strcmp(df0, f)!=0)
+       {
+         strncpy(dn0, f, 255);
+         dc0=3;
+         disk_eject(0);
+         strncpy(df0, "", 255);
+       }
+       break;
+      case 1:
+       if(strcmp(df1, f)!=0)
+       {
+         strncpy(dn1, f, 255);
+         dc1=3;
+         disk_eject(1);
+         strncpy(df1, "", 255);
+       }
+       break;
+      case 2:
+       if(strcmp(df2, f)!=0)
+       {
+         strncpy(dn2, f, 255);
+         dc2=3;
+         disk_eject(2);
+         strncpy(df2, "", 255);
+       }
+       break;
+      case 3:
+       if(strcmp(df3, f)!=0)
+       {
+         strncpy(dn3, f, 255);
+         dc3=3;
+         disk_eject(3);
+         strncpy(df3, "", 255);
+       }
+       break;
+    }
+  }
+  else
+  {
+    switch(n)
+    {
+      case 0:
+       strncpy(df0, f, 255);
+       break;
+      case 1:
+       strncpy(df1, f, 255);
+       break;
+      case 2:
+       strncpy(df2, f, 255);
+       break;
+      case 3:
+       strncpy(df3, f, 255);
+       break;
+    }
+  }
+}
+
+void setsonst(int *reserved)
+{
+  if(!uae_startedup)
+  {
+    gfx_requested_width=reserved[0];
+    gfx_requested_xcenter=reserved[1];
+    gfx_requested_lores=reserved[2];
+    gfx_requested_height=reserved[3];
+    gfx_requested_ycenter=reserved[4];
+    gfx_requested_linedbl=reserved[5];
+    gfx_requested_correct_aspect=reserved[6];
+    switch(reserved[7])
+    {
+      case 256:
+       color_mode=0;
+       break;
+      case 32768:
+       color_mode=1;
+       break;
+    }
+    framerate=reserved[8];
+    emul_accuracy=reserved[9];
+    blits_32bit_enabled=reserved[10];
+    immediate_blits=reserved[11];
+    fake_joystick=reserved[12];
+    bogomem_size=reserved[14];
+    chipmem_size=reserved[15];
+    fastmem_size=reserved[16];
+    produce_sound=reserved[17];
+    sound_desired_freq=reserved[18];
+    sound_desired_bsiz=reserved[19];
+  }
+}
+
+void sendtofront(int *reserved)
+{
+  int *words=mblock.data.reserved;
+
+  mblock.size=256;
+  mblock.sender=taskhandle;
+  mblock.my_ref=778;
+  mblock.your_ref=777;
+  switch(*reserved)
+  {
+    case 0:
+      mblock.action=A_disk;
+      if(dc0==0)
+       strncpy(words, df0, 235);
+      else
+       strncpy(words, dn0, 235);
+      break;
+    case 1:
+      mblock.action=A_disk+1;
+      if(dc0==0)
+       strncpy(words, df1, 235);
+      else
+       strncpy(words, dn1, 235);
+      break;
+    case 2:
+      mblock.action=A_disk+2;
+      if(dc0==0)
+       strncpy(words, df2, 235);
+      else
+       strncpy(words, dn2, 235);
+      break;
+    case 3:
+      mblock.action=A_disk+3;
+      if(dc0==0)
+       strncpy(words, df3, 235);
+      else
+       strncpy(words, dn3, 235);
+      break;
+  }
+  wimp_send_message(wimp_USER_MESSAGE, &mblock, frontendhandle);
+}
+
+void gui_messagereceive(void)
+{
+  switch(block.message.action)
+  {
+    case message_QUIT:
+      if(uae_startedup)
+      {
+       set_special (SPCFLAG_BRK);
+       quit_program=1;
+       uae_running=1;
+      }
+      else
+      {
+       if(uaedevfd!=-1)
+       {
+         close(uaedevfd);
+       }
+       wimp_close_down(taskhandle);
+      }
+      break;
+    case A_switch:
+      if(uae_startedup)
+      {
+       uae_running=1;
+       setuaemode();
+       setuaesound();
+      }
+      else
+      {
+       frontendhandle=block.message.sender;
+       uae_startedup=1;
+       uae_running=1;
+      }
+      break;
+    case A_disk:
+      changedisk(0, block.message.data.reserved);
+      break;
+    case A_disk+1:
+      changedisk(1, block.message.data.reserved);
+      break;
+    case A_disk+2:
+      changedisk(2, block.message.data.reserved);
+      break;
+    case A_disk+3:
+      changedisk(3, block.message.data.reserved);
+      break;
+    case A_sonst:
+      setsonst(block.message.data.reserved);
+      break;
+    case A_rom:
+      strncpy(romfile, block.message.data.reserved, 235);
+      break;
+    case A_mount:
+      strncpy(mountpoint, block.message.data.reserved, 63);
+      break;
+    case A_mount+1:
+      strncpy(mountdir, block.message.data.reserved, 235);
+      add_filesys_unit(mountpoint, mountdir, 0);
+      break;
+    case A_mount+2:
+      strncpy(mountdir, block.message.data.reserved, 235);
+      add_filesys_unit(mountpoint, mountdir, 1);
+      break;
+    case A_uaeask:
+      sendtofront(block.message.data.reserved);
+      break;
+  }
+}
+
+void gui_process(void)
+{
+  wimp_event_no event;
+
+  while(uae_running==0)
+  {
+    event=wimp_poll(wimp_MASK_NULL, &block, 0);
+
+    switch(event)
+    {
+      case wimp_USER_MESSAGE:
+      case wimp_USER_MESSAGE_RECORDED:
+       gui_messagereceive();
+       break;
+    }
+  }
+}
+
+void gui_exit(void)
+{
+}
+
+void gui_led(int led, int on)
+{
+}
+
+void gui_filename(int num, char *name)
+{
+}
+
+void gui_handle_events(void)
+{
+}
+
+int gui_update(void)
+{
+}
+
diff --git a/savestate.c b/savestate.c
new file mode 100755 (executable)
index 0000000..bf4a5f9
--- /dev/null
@@ -0,0 +1,1244 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Save/restore emulator state
+  *
+  * (c) 1999-2001 Toni Wilen
+  *
+  * see below for ASF-structure
+  */
+
+ /* Features:
+  *
+  * - full CPU state (68000/68010/68020)
+  * - FPU
+  * - full CIA-A and CIA-B state (with all internal registers)
+  * - saves all custom registers and audio internal state.
+  * - Chip, Bogo, Fast, Z3 and Picasso96 RAM supported
+  * - disk drive type, imagefile, track and motor state
+  * - Kickstart ROM version, address and size is saved. This data is not used during restore yet.
+  * - Action Replay state is saved
+  */
+
+ /* Notes:
+  *
+  * - blitter state is not saved, blitter is forced to finish immediately if it
+  *   was active
+  * - disk DMA state is completely saved 
+  * - does not ask for statefile name and description. Currently uses DF0's disk
+  *   image name (".adf" is replaced with ".asf")
+  * - only Amiga state is restored, harddisk support, autoconfig, expansion boards etc..
+  *   are not saved/restored (and probably never will).
+  * - use this for saving games that can't be saved to disk
+  */
+
+ /* Usage :
+  *
+  * save:
+  * 
+  * set savestate_state = STATE_DOSAVE, savestate_filename = "..."
+  *
+  * restore:
+  * 
+  * set savestate_state = STATE_DORESTORE, savestate_filename = "..."
+  *
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "memory.h"
+#include "zfile.h"
+#include "ar.h"
+#include "autoconf.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "savestate.h"
+#include "uae.h"
+
+int savestate_state;
+
+#define MAX_STATERECORDS 1024 /* must be power of 2 */
+struct staterecord {
+    uae_u8 *start;
+    uae_u8 *end;
+    uae_u8 *next;
+    uae_u8 *cpu;
+};
+static int replaycounter;
+static int replaylastreloaded = -1;
+static int frameextra;
+
+struct zfile *savestate_file;
+static uae_u8 *replaybuffer, *replaybufferend;
+static int savestate_docompress, savestate_ramdump;
+static int replaybuffersize;
+
+char savestate_fname[MAX_PATH];
+static struct staterecord staterecords[MAX_STATERECORDS];
+
+static unsigned long crc_table[256];
+static void make_crc_table()
+{
+    unsigned long c;
+    int n, k;
+    for (n = 0; n < 256; n++)  
+    {
+       c = (unsigned long)n;
+       for (k = 0; k < 8; k++) c = (c >> 1) ^ (c & 1 ? 0xedb88320L : 0);
+           crc_table[n] = c;
+    }
+}
+uae_u32 CRC32(uae_u32 crc, const uae_u8 *buf, int len)
+{
+    if (!crc_table[1]) make_crc_table();
+    crc = crc ^ 0xffffffffL;
+    while (len-- > 0) {
+       crc = crc_table[(crc ^ (*buf++)) & 0xff] ^ (crc >> 8);    
+    }
+    return crc ^ 0xffffffffL;
+}
+
+/* functions for reading/writing bytes, shorts and longs in big-endian
+ * format independent of host machine's endianess */
+
+void save_u32_func (uae_u8 **dstp, uae_u32 v)
+{
+    uae_u8 *dst = *dstp;
+    *dst++ = (uae_u8)(v >> 24);
+    *dst++ = (uae_u8)(v >> 16);
+    *dst++ = (uae_u8)(v >> 8);
+    *dst++ = (uae_u8)(v >> 0);
+    *dstp = dst;
+}
+void save_u16_func (uae_u8 **dstp, uae_u16 v)
+{
+    uae_u8 *dst = *dstp;
+    *dst++ = (uae_u8)(v >> 8);
+    *dst++ = (uae_u8)(v >> 0);
+    *dstp = dst;
+}
+void save_u8_func (uae_u8 **dstp, uae_u8 v)
+{
+    uae_u8 *dst = *dstp;
+    *dst++ = v;
+    *dstp = dst;
+}
+void save_string_func (uae_u8 **dstp, char *from)
+{
+    uae_u8 *dst = *dstp;
+    while(*from)
+       *dst++ = *from++;
+    *dst++ = 0;
+    *dstp = dst;
+}
+
+uae_u32 restore_u32_func (uae_u8 **dstp)
+{
+    uae_u32 v;
+    uae_u8 *dst = *dstp;
+    v = (dst[0] << 24) | (dst[1] << 16) | (dst[2] << 8) | (dst[3]);
+    *dstp = dst + 4;
+    return v;
+}
+uae_u16 restore_u16_func (uae_u8 **dstp)
+{
+    uae_u16 v;
+    uae_u8 *dst = *dstp;
+    v=(dst[0] << 8) | (dst[1]);
+    *dstp = dst + 2;
+    return v;
+}
+uae_u8 restore_u8_func (uae_u8 **dstp)
+{
+    uae_u8 v;
+    uae_u8 *dst = *dstp;
+    v = dst[0];
+    *dstp = dst + 1;
+    return v;
+}
+char *restore_string_func (uae_u8 **dstp)
+{
+    int len;
+    uae_u8 v;
+    uae_u8 *dst = *dstp;
+    char *top, *to;
+    len = strlen(dst) + 1;
+    top = to = malloc (len);
+    do {
+       v = *dst++;
+       *top++ = v;
+    } while(v);
+    *dstp = dst;
+    return to; 
+}
+
+/* read and write IFF-style hunks */
+
+static void save_chunk (struct zfile *f, uae_u8 *chunk, long len, char *name, int compress)
+{
+    uae_u8 tmp[8], *dst;
+    uae_u8 zero[4]= { 0, 0, 0, 0 };
+    uae_u32 flags;
+    size_t pos;
+    long chunklen, len2;
+
+    if (!chunk)
+       return;
+
+    if (compress < 0) {
+       zfile_fwrite (chunk, 1, len, f);
+       return;
+    }
+
+    /* chunk name */
+    zfile_fwrite (name, 1, 4, f);
+    pos = zfile_ftell (f);
+    /* chunk size */
+    dst = &tmp[0];
+    chunklen = len + 4 + 4 + 4;
+    save_u32 (chunklen);
+    zfile_fwrite (&tmp[0], 1, 4, f);
+    /* chunk flags */
+    flags = 0;
+    dst = &tmp[0];
+    save_u32 (flags | compress);
+    zfile_fwrite (&tmp[0], 1, 4, f);
+    /* chunk data */
+    if (compress) {
+       int tmplen = len;
+       dst = &tmp[0];
+       save_u32 (len);
+       zfile_fwrite (&tmp[0], 1, 4, f);
+       len = zfile_zcompress (f, chunk, len);
+       if (len > 0) {
+           zfile_fseek (f, pos, SEEK_SET);
+           dst = &tmp[0];
+           save_u32 (len + 4 + 4 + 4 + 4);
+           zfile_fwrite (&tmp[0], 1, 4, f);
+           zfile_fseek (f, 0, SEEK_END);
+       } else {
+           len = tmplen;
+           compress = 0;
+           zfile_fseek (f, -8, SEEK_CUR);
+           dst = &tmp[0];
+           save_u32 (flags);
+           zfile_fwrite (&tmp[0], 1, 4, f);
+       }
+    }
+    if (!compress)
+       zfile_fwrite (chunk, 1, len, f);
+    /* alignment */
+    len2 = 4 - (len & 3);
+    if (len2)
+       zfile_fwrite (zero, 1, len2, f);
+
+    write_log ("Chunk '%s' chunk size %d (%d)\n", name, chunklen, len);
+}
+
+static uae_u8 *restore_chunk (struct zfile *f, char *name, long *len, long *totallen, long *filepos)
+{
+    uae_u8 tmp[4], dummy[4], *mem, *src;
+    uae_u32 flags;
+    long len2;
+
+    /* chunk name */
+    zfile_fread (name, 1, 4, f);
+    name[4] = 0;
+    /* chunk size */
+    zfile_fread (tmp, 1, 4, f);
+    src = tmp;
+    len2 = restore_u32 () - 4 - 4 - 4;
+    if (len2 < 0)
+       len2 = 0;
+    *len = len2;
+    if (len2 == 0)
+       return 0;
+
+    /* chunk flags */
+    zfile_fread (tmp, 1, 4, f);
+    src = tmp;
+    flags = restore_u32 ();
+    *totallen = *len;
+    if (flags & 1) {
+       zfile_fread (tmp, 1, 4, f);
+       src = tmp;
+       *totallen = restore_u32();
+       *filepos = zfile_ftell (f) - 4 - 4 - 4;
+       len2 -= 4;
+    } else {
+        *filepos = zfile_ftell (f) - 4 - 4;
+    }
+    /* chunk data.  RAM contents will be loaded during the reset phase,
+       no need to malloc multiple megabytes here.  */
+    if (strcmp (name, "CRAM") != 0
+       && strcmp (name, "BRAM") != 0
+       && strcmp (name, "FRAM") != 0
+       && strcmp (name, "ZRAM") != 0
+       && strcmp (name, "PRAM") != 0)
+    {
+       /* without zeros at the end old state files may not work */
+       mem = calloc (1, len2 + 32); 
+       zfile_fread (mem, 1, len2, f);
+    } else {
+       mem = 0;
+       zfile_fseek (f, len2, SEEK_CUR);
+    }
+
+    /* alignment */
+    len2 = 4 - (len2 & 3);
+    if (len2)
+       zfile_fread (dummy, 1, len2, f);
+    return mem;
+}
+
+void restore_ram (long filepos, uae_u8 *memory)
+{
+    uae_u8 tmp[8];
+    uae_u8 *src = tmp;
+    int size, fullsize;
+    uae_u32 flags;
+    
+    zfile_fseek (savestate_file, filepos, SEEK_SET);
+    zfile_fread (tmp, 1, sizeof(tmp), savestate_file);
+    size = restore_u32();
+    flags = restore_u32();
+    size -= 4 + 4 + 4;
+    if (flags & 1) {
+        zfile_fread (tmp, 1, 4, savestate_file);
+        src = tmp;
+       fullsize = restore_u32();
+       size -= 4;
+       zfile_zuncompress (memory, fullsize, savestate_file, size);
+    } else {
+       zfile_fread (memory, 1, size, savestate_file);
+    }
+}
+
+static void restore_header (uae_u8 *src)
+{
+    char *emuname, *emuversion, *description;
+
+    restore_u32();
+    emuname = restore_string ();
+    emuversion = restore_string ();
+    description = restore_string ();
+    write_log ("Saved with: '%s %s', description: '%s'\n",
+       emuname,emuversion,description);
+    free (description);
+    free (emuversion);
+    free (emuname);
+}
+
+/* restore all subsystems */
+
+void restore_state (char *filename)
+{
+    struct zfile *f;
+    uae_u8 *chunk,*end;
+    char name[5], prevchunk[5];
+    long len, totallen;
+    long filepos;
+
+    chunk = 0;
+    f = zfile_fopen (filename, "rb");
+    if (!f)
+       goto error;
+    savestate_init ();
+
+    chunk = restore_chunk (f, name, &len, &totallen, &filepos);
+    if (!chunk || memcmp (name, "ASF ", 4)) {
+       write_log ("%s is not an AmigaStateFile\n",filename);
+       goto error;
+    }
+    savestate_file = f;
+    restore_header (chunk);
+    free (chunk);
+    changed_prefs.bogomem_size = 0;
+    changed_prefs.chipmem_size = 0;
+    changed_prefs.fastmem_size = 0;
+    savestate_state = STATE_RESTORE;
+    prevchunk[0] = 0;
+    for (;;) {
+       chunk = end = restore_chunk (f, name, &len, &totallen, &filepos);
+       if (!strcmp (name, prevchunk))
+           break;
+       strcpy (prevchunk, name);
+       write_log ("Chunk '%s' size %d\n", name, len);
+       if (!strcmp (name, "END "))
+           break;
+       if (!strcmp (name, "CRAM")) {
+           restore_cram (totallen, filepos);
+           continue;
+       } else if (!strcmp (name, "BRAM")) {
+           restore_bram (totallen, filepos);
+           continue;
+#ifdef AUTOCONFIG
+       } else if (!strcmp (name, "FRAM")) {
+           restore_fram (totallen, filepos);
+           continue;
+       } else if (!strcmp (name, "ZRAM")) {
+           restore_zram (totallen, filepos);
+           continue;
+#endif
+#ifdef PICASSO96
+       } else if (!strcmp (name, "PRAM")) {
+           restore_pram (totallen, filepos);
+           continue;
+#endif
+       } else if (!strcmp (name, "CPU "))
+           end = restore_cpu (chunk);
+#ifdef FPUEMU
+       else if (!strcmp (name, "FPU "))
+           end = restore_fpu (chunk);
+#endif
+       else if (!strcmp (name, "AGAC"))
+           end = restore_custom_agacolors (chunk);
+       else if (!strcmp (name, "SPR0"))
+           end = restore_custom_sprite (0, chunk);
+       else if (!strcmp (name, "SPR1"))
+           end = restore_custom_sprite (1, chunk);
+       else if (!strcmp (name, "SPR2"))
+           end = restore_custom_sprite (2, chunk);
+       else if (!strcmp (name, "SPR3"))
+           end = restore_custom_sprite (3, chunk);
+       else if (!strcmp (name, "SPR4"))
+           end = restore_custom_sprite (4, chunk);
+       else if (!strcmp (name, "SPR5"))
+           end = restore_custom_sprite (5, chunk);
+       else if (!strcmp (name, "SPR6"))
+           end = restore_custom_sprite (6, chunk);
+       else if (!strcmp (name, "SPR7"))
+           end = restore_custom_sprite (7, chunk);
+       else if (!strcmp (name, "CIAA"))
+           end = restore_cia (0, chunk);
+       else if (!strcmp (name, "CIAB"))
+           end = restore_cia (1, chunk);
+       else if (!strcmp (name, "CHIP"))
+           end = restore_custom (chunk);
+       else if (!strcmp (name, "AUD0"))
+           end = restore_audio (0, chunk);
+       else if (!strcmp (name, "AUD1"))
+           end = restore_audio (1, chunk);
+       else if (!strcmp (name, "AUD2"))
+           end = restore_audio (2, chunk);
+       else if (!strcmp (name, "AUD3"))
+           end = restore_audio (3, chunk);
+       else if (!strcmp (name, "BLIT"))
+           end = restore_blitter (chunk);
+       else if (!strcmp (name, "DISK"))
+           end = restore_floppy (chunk);
+       else if (!strcmp (name, "DSK0"))
+           end = restore_disk (0, chunk);
+       else if (!strcmp (name, "DSK1"))
+           end = restore_disk (1, chunk);
+       else if (!strcmp (name, "DSK2"))
+           end = restore_disk (2, chunk);
+       else if (!strcmp (name, "DSK3"))
+           end = restore_disk (3, chunk);
+       else if (!strcmp (name, "KEYB"))
+           end = restore_keyboard (chunk);
+#ifdef AUTOCONFIG
+       else if (!strcmp (name, "EXPA"))
+           end = restore_expansion (chunk);
+#endif
+       else if (!strcmp (name, "ROM "))
+           end = restore_rom (chunk);
+#ifdef PICASSO96
+       else if (!strcmp (name, "P96 "))
+           end = restore_p96 (chunk);
+#endif
+#ifdef ACTION_REPLAY
+       else if (!strcmp (name, "ACTR"))
+           end = restore_action_replay (chunk);
+#endif
+       else
+           write_log ("unknown chunk '%s' size %d bytes\n", name, len);
+       if (len != end - chunk)
+           write_log ("Chunk '%s' total size %d bytes but read %d bytes!\n",
+                      name, len, end - chunk);
+       free (chunk);
+    }
+    return;
+
+    error:
+    savestate_state = 0;
+    savestate_file = 0;
+    if (chunk)
+       free (chunk);
+    if (f)
+       zfile_fclose (f);
+}
+
+void savestate_restore_finish (void)
+{
+    if (savestate_state != STATE_RESTORE && savestate_state != STATE_REWIND)
+       return;
+    zfile_fclose (savestate_file);
+    savestate_file = 0;
+    savestate_state = 0;
+}
+
+/* 1=compressed,2=not compressed,3=ram dump */
+void savestate_initsave (char *filename, int mode)
+{
+    strcpy (savestate_fname, filename);
+    savestate_docompress = (mode == 1) ? 1 : 0;
+    savestate_ramdump = (mode == 3) ? 1 : 0;
+}
+
+static void save_rams (struct zfile *f, int comp)
+{
+    uae_u8 *dst;
+    int len;
+
+    dst = save_cram (&len);
+    save_chunk (f, dst, len, "CRAM", comp);
+    dst = save_bram (&len);
+    save_chunk (f, dst, len, "BRAM", comp);
+#ifdef AUTOCONFIG
+    dst = save_fram (&len);
+    save_chunk (f, dst, len, "FRAM", comp);
+    dst = save_zram (&len);
+    save_chunk (f, dst, len, "ZRAM", comp);
+#endif
+#ifdef PICASSO96
+    dst = save_pram (&len);
+    save_chunk (f, dst, len, "PRAM", comp);
+    dst = save_p96 (&len, 0);
+    save_chunk (f, dst, len, "P96 ", comp);
+#endif
+}
+
+/* Save all subsystems  */
+
+void save_state (char *filename, char *description)
+{
+    uae_u8 header[1000];
+    char tmp[100];
+    uae_u8 *dst;
+    struct zfile *f;
+    int len,i;
+    char name[5];
+    int comp = savestate_docompress;
+
+#ifdef FILESYS
+    if (nr_units (currprefs.mountinfo)) {
+       gui_message("WARNING: State saves do not support harddrive emulation");
+    }
+#endif
+
+    custom_prepare_savestate ();
+    f = zfile_fopen (filename, "wb");
+    if (!f)
+       return;
+    if (savestate_ramdump) {
+       save_rams (f, -1);
+        zfile_fclose (f);
+       return;
+    }
+
+    dst = header;
+    save_u32 (0);
+    save_string("UAE");
+    sprintf (tmp, "%d.%d.%d", UAEMAJOR, UAEMINOR, UAESUBREV);
+    save_string (tmp);
+    save_string (description);
+    save_chunk (f, header, dst-header, "ASF ", 0);
+
+    dst = save_cpu (&len, 0);
+    save_chunk (f, dst, len, "CPU ", 0);
+    free (dst);
+
+#ifdef FPUEMU
+    dst = save_fpu (&len,0 );
+    save_chunk (f, dst, len, "FPU ", 0);
+    free (dst);
+#endif
+
+    strcpy(name, "DSKx");
+    for (i = 0; i < 4; i++) {
+       dst = save_disk (i, &len, 0);
+       if (dst) {
+           name[3] = i + '0';
+           save_chunk (f, dst, len, name, 0);
+           free (dst);
+       }
+    }
+    dst = save_floppy (&len, 0);
+    save_chunk (f, dst, len, "DISK", 0);
+    free (dst);
+
+    dst = save_custom (&len, 0, 0);
+    save_chunk (f, dst, len, "CHIP", 0);
+    free (dst);
+
+    dst = save_blitter (&len, 0);
+    save_chunk (f, dst, len, "BLIT", 0);
+    free (dst);
+
+    dst = save_custom_agacolors (&len, 0);
+    save_chunk (f, dst, len, "AGAC", 0);
+    free (dst);
+
+    strcpy (name, "SPRx");
+    for (i = 0; i < 8; i++) {
+       dst = save_custom_sprite (i, &len, 0);
+       name[3] = i + '0';
+       save_chunk (f, dst, len, name, 0);
+       free (dst);
+    }
+
+    strcpy (name, "AUDx");
+    for (i = 0; i < 4; i++) {
+       dst = save_audio (i, &len, 0);
+       name[3] = i + '0';
+       save_chunk (f, dst, len, name, 0);
+       free (dst);
+    }
+
+    dst = save_cia (0, &len, 0);
+    save_chunk (f, dst, len, "CIAA", 0);
+    free (dst);
+
+    dst = save_cia (1, &len, 0);
+    save_chunk (f, dst, len, "CIAB", 0);
+    free (dst);
+
+    dst = save_keyboard (&len);
+    save_chunk (f, dst, len, "KEYB", 0);
+    free (dst);
+
+#ifdef AUTOCONFIG
+    dst = save_expansion (&len, 0);
+    save_chunk (f, dst, len, "EXPA", 0);
+#endif
+    save_rams (f, comp);
+
+    dst = save_rom (1, &len, 0);
+    do {
+       if (!dst)
+           break;
+       save_chunk (f, dst, len, "ROM ", 0);
+       free (dst);
+    } while ((dst = save_rom (0, &len, 0)));
+
+#ifdef ACTION_REPLAY
+    dst = save_action_replay (&len, 0);
+    save_chunk (f, dst, len, "ACTR", 0);
+#endif
+
+    zfile_fwrite ("END ", 1, 4, f);
+    zfile_fwrite ("\0\0\0\08", 1, 4, f);
+    write_log ("Save of '%s' complete\n", filename);
+    zfile_fclose (f);
+    savestate_state = 0;
+}
+
+void savestate_quick (int slot, int save)
+{
+    int i, len = strlen (savestate_fname);
+    i = len - 1;
+    while (i >= 0 && savestate_fname[i] != '_')
+       i--;
+    if (i < len - 6 || i <= 0) { /* "_?.uss" */
+       i = len - 1;
+       while (i >= 0 && savestate_fname[i] != '.')
+           i--;
+       if (i <= 0)
+           return;
+    }
+    strcpy (savestate_fname + i, ".uss");
+    if (slot > 0)
+       sprintf (savestate_fname + i, "_%d.uss", slot);
+    if (save) {
+       savestate_docompress = 1;
+       save_state (savestate_fname, "");
+    } else {
+       if (!zfile_exists (savestate_fname))
+           return;
+       savestate_state = STATE_DORESTORE;
+    }
+}
+
+static struct staterecord *canrewind (int pos)
+{
+    int i;
+    struct staterecord *st;
+
+    if (!replaybuffer)
+       return 0;
+    i = replaycounter;
+    st = &staterecords[i];
+    if (st->start)
+       return st;
+    return 0;
+}
+
+int savestate_dorewind (int pos)
+{
+    if (canrewind (pos)) {
+       savestate_state = STATE_DOREWIND;
+       return 1;
+    }
+    return 0;
+}
+
+void savestate_listrewind (void)
+{
+    int i = replaycounter;
+    int cnt;
+    uae_u8 *p;
+    uae_u32 pc;
+
+    cnt = 1;
+    for (;;) {
+       struct staterecord *st;
+       st = &staterecords[i];
+       if (!st->start)
+           break;
+       p = st->cpu + 17 * 4;
+       pc = restore_u32_func (&p);
+       console_out ("%d: PC=%08X %c\n", cnt, pc, regs.pc == pc ? '*' : ' ');
+       cnt++;
+       i--;
+       if (i < 0)
+           i += MAX_STATERECORDS;
+    }
+}
+
+void savestate_rewind (void)
+{
+    int len, i, dummy;
+    uae_u8 *p, *p2;
+    struct staterecord *st;
+
+    st = canrewind (1);
+    if (!st)
+       return;
+    frameextra = timeframes % currprefs.statecapturerate;
+    p =  st->start;
+    p2 = st->end;
+    write_log ("rewinding from %d\n", replaycounter);
+    p = restore_cpu (p);
+#ifdef FPUEMU
+    if (restore_u32_func (&p))
+       p = restore_fpu (p);
+#endif
+    for (i = 0; i < 4; i++) {
+       p = restore_disk (i, p);
+    }
+    p = restore_floppy (p);
+    p = restore_custom (p);
+    p = restore_blitter (p);
+    p = restore_custom_agacolors (p);
+    for (i = 0; i < 8; i++) {
+       p = restore_custom_sprite (i, p);
+    }
+    for (i = 0; i < 4; i++) {
+       p = restore_audio (i, p);
+    }
+    p = restore_cia (0, p);
+    p = restore_cia (1, p);
+#ifdef AUTOCONFIG
+    p = restore_expansion (p);
+#endif
+    len = restore_u32_func (&p);
+    memcpy (chipmemory, p, currprefs.chipmem_size > len ? len : currprefs.chipmem_size);
+    p += len;
+    len = restore_u32_func (&p);
+    memcpy (save_bram (&dummy), p, currprefs.bogomem_size > len ? len : currprefs.bogomem_size);
+    p += len;
+#ifdef AUTOCONFIG
+    len = restore_u32_func (&p);
+    memcpy (save_fram (&dummy), p, currprefs.fastmem_size > len ? len : currprefs.fastmem_size);
+    p += len;
+    len = restore_u32_func (&p);
+    memcpy (save_zram (&dummy), p, currprefs.z3fastmem_size > len ? len : currprefs.z3fastmem_size);
+    p += len;
+#endif
+#ifdef ACTION_REPLAY
+    if (restore_u32_func (&p))
+        p = restore_action_replay (p);
+#endif
+    p += 4;
+    if (p != p2) {
+       gui_message ("reload failure, address mismatch %p != %p", p, p2);
+       uae_reset (0);
+       return;
+    }
+    st->start = st->next = 0;
+    replaycounter--;
+    if (replaycounter < 0)
+       replaycounter += MAX_STATERECORDS;
+}
+
+#define BS 10000
+
+static int bufcheck (uae_u8 **pp, int len)
+{
+    uae_u8 *p = *pp;
+    if (p + len + BS >= replaybuffer + replaybuffersize) {
+       //write_log ("capture buffer wrap-around\n");
+       return 1;
+    }
+    return 0;
+}
+
+void savestate_capture (int force)
+{
+    uae_u8 *p, *p2, *p3, *dst;
+    int i, len, tlen, retrycnt;
+    struct staterecord *st, *stn;
+
+#ifdef FILESYS
+    if (nr_units (currprefs.mountinfo))
+       return;
+#endif
+    if (!replaybuffer)
+       return;
+    if (!force && (!currprefs.statecapture || !currprefs.statecapturerate || ((timeframes + frameextra) % currprefs.statecapturerate)))
+       return;
+
+    retrycnt = 0;
+retry2:
+    st = &staterecords[replaycounter];
+    if (st->next == 0) {
+       replaycounter = 0;
+       st = &staterecords[replaycounter];
+       st->next = replaybuffer;
+    }
+    stn = &staterecords[(replaycounter + 1) & (MAX_STATERECORDS - 1)];
+    p = p2 = st->next;
+    tlen = 0;
+    if (bufcheck (&p, 0))
+       goto retry;
+    stn->cpu = p;
+    save_cpu (&len, p);
+    tlen += len;
+    p += len;
+#ifdef FPUEMU
+    if (bufcheck (&p, 0))
+       goto retry;
+    p3 = p;
+    save_u32_func (&p, 0);
+    tlen += 4;
+    if (save_fpu (&len, p)) {
+       save_u32_func (&p3, 1);
+       tlen += len;
+       p += len;
+    }
+#endif
+    for (i = 0; i < 4; i++) {
+       if (bufcheck (&p, 0))
+           goto retry;
+       save_disk (i, &len, p);
+        tlen += len;
+        p += len;
+    }
+    if (bufcheck (&p, 0))
+       goto retry;
+    save_floppy (&len, p);
+    tlen += len;
+    p += len;
+    if (bufcheck (&p, 0))
+       goto retry;
+    save_custom (&len, p, 0);
+    tlen += len;
+    p += len;
+    if (bufcheck (&p, 0))
+       goto retry;
+    save_blitter (&len, p);
+    tlen += len;
+    p += len;
+    if (bufcheck (&p, 0))
+       goto retry;
+    save_custom_agacolors (&len, p);
+    tlen += len;
+    p += len;
+    for (i = 0; i < 8; i++) {
+        if (bufcheck (&p, 0))
+           goto retry;
+       save_custom_sprite (i, &len, p);
+        tlen += len;
+        p += len;
+    }
+    for (i = 0; i < 4; i++) {
+       if (bufcheck (&p, 0))
+           goto retry;
+       save_audio (i, &len, p);
+        tlen += len;
+        p += len;
+    }
+    if (bufcheck (&p, 0))
+       goto retry;
+    save_cia (0, &len, p);
+    tlen += len;
+    p += len;
+    if (bufcheck (&p, 0))
+       goto retry;
+    save_cia (1, &len, p);
+    tlen += len;
+    p += len;
+#ifdef AUTOCONFIG
+    if (bufcheck (&p, 0))
+       goto retry;
+    save_expansion (&len, p);
+    tlen += len;
+    p += len;
+#endif
+    dst = save_cram (&len);
+    if (bufcheck (&p, len))
+       goto retry;
+    save_u32_func (&p, len);
+    memcpy (p, dst, len);
+    tlen += len + 4;
+    p += len;
+    dst = save_bram (&len);
+    if (bufcheck (&p, len))
+       goto retry;
+    save_u32_func (&p, len);
+    memcpy (p, dst, len);
+    tlen += len + 4;
+    p += len;
+#ifdef AUTOCONFIG
+    dst = save_fram (&len);
+    if (bufcheck (&p, len))
+       goto retry;
+    save_u32_func (&p, len);
+    memcpy (p, dst, len);
+    tlen += len + 4;
+    p += len;
+    dst = save_zram (&len);
+    if (bufcheck (&p, len))
+       goto retry;
+    save_u32_func (&p, len);
+    memcpy (p, dst, len);
+    tlen += len + 4;
+    p += len;
+#endif
+#ifdef ACTION_REPLAY
+    if (bufcheck (&p, 0))
+       goto retry;
+    p3 = p;
+    save_u32_func (&p, 0);
+    tlen += 4;
+    if (save_action_replay (&len, p)) {
+       save_u32_func (&p3, 1);
+       tlen += len;
+       p += len;
+    }
+#endif
+    save_u32_func (&p, tlen);
+    stn->next = p;
+    stn->start = p2;
+    stn->end = p;
+    replaylastreloaded = -1;
+    replaycounter++;
+    replaycounter &= (MAX_STATERECORDS - 1);
+    i = (replaycounter + 1) & (MAX_STATERECORDS - 1);
+    staterecords[i].next = staterecords[i].start = 0;
+    i = replaycounter - 1;
+    while (i != replaycounter) {
+       if (i < 0)
+           i += MAX_STATERECORDS;
+       st = &staterecords[i];
+       if (p2 <= st->start && p >= st->end) {
+           st->start = st->next = 0;
+           break;
+       }
+       i--;
+    }
+    //write_log ("state capture %d (%d bytes)\n", replaycounter, p - p2);
+    return;
+retry:
+    staterecords[replaycounter].next = replaybuffer;
+    retrycnt++;
+    if (retrycnt > 1) {
+       write_log ("can't save, too small capture buffer\n");
+       return;
+    }
+    goto retry2;
+}
+
+void savestate_free (void)
+{
+    free (replaybuffer);
+    replaybuffer = 0;
+}
+
+void savestate_init (void)
+{
+    savestate_free ();
+    memset (staterecords, 0, sizeof (staterecords));
+    replaycounter = 0;
+    replaylastreloaded = -1;
+    frameextra = 0;
+    if (currprefs.statecapture && currprefs.statecapturebuffersize && currprefs.statecapturerate) {
+       replaybuffersize = currprefs.statecapturebuffersize;
+       replaybuffer = malloc (replaybuffersize);
+    }
+}
+
+/*
+
+My (Toni Wilen <twilen@arabuusimiehet.com>)
+proposal for Amiga-emulators' state-save format
+
+Feel free to comment...
+
+This is very similar to IFF-fileformat
+Every hunk must end to 4 byte boundary,
+fill with zero bytes if needed
+
+version 0.8
+
+HUNK HEADER (beginning of every hunk)
+
+        hunk name (4 ascii-characters)
+        hunk size (including header)
+        hunk flags             
+
+        bit 0 = chunk contents are compressed with zlib (maybe RAM chunks only?)
+
+HEADER
+
+        "ASF " (AmigaStateFile)
+        
+       statefile version
+        emulator name ("uae", "fellow" etc..)
+        emulator version string (example: "0.8.15")
+        free user writable comment string
+
+CPU
+
+         "CPU "
+
+        CPU model               4 (68000,68010 etc..)
+        CPU typeflags           bit 0=EC-model or not
+        D0-D7                   8*4=32
+        A0-A6                   7*4=32
+        PC                      4
+       unused                  4
+       68000 prefetch (IRC)    2
+       68000 prefetch (IR)     2
+        USP                     4
+        ISP                     4
+        SR/CCR                  2
+        flags                   4 (bit 0=CPU was HALTed)
+
+        CPU specific registers
+
+        68000: SR/CCR is last saved register
+        68010: save also DFC,SFC and VBR
+        68020: all 68010 registers and CAAR,CACR and MSP
+        etc..
+
+        DFC                     4 (010+)
+        SFC                     4 (010+)
+        VBR                     4 (010+)
+
+        CAAR                    4 (020-030)
+        CACR                    4 (020+)
+        MSP                     4 (020+)
+
+FPU (only if used)
+
+       "FPU "
+
+        FPU model               4 (68881/68882/68040)
+        FPU typeflags           4 (keep zero)
+
+        FP0-FP7                 4+4+2 (80 bits)
+        FPCR                    4
+        FPSR                    4
+        FPIAR                   4
+
+MMU (when and if MMU is supported in future..)
+
+        MMU model               4 (68851,68030,68040)
+
+        // 68040 fields
+
+        ITT0                    4
+        ITT1                    4
+        DTT0                    4
+        DTT1                    4
+        URP                     4
+        SRP                     4
+        MMUSR                   4
+        TC                      2
+
+               
+CUSTOM CHIPS
+
+        "CHIP"
+
+        chipset flags   4      OCS=0,ECSAGNUS=1,ECSDENISE=2,AGA=4
+                               ECSAGNUS and ECSDENISE can be combined
+
+        DFF000-DFF1FF   352    (0x120 - 0x17f and 0x0a0 - 0xdf excluded)
+
+        sprite registers (0x120 - 0x17f) saved with SPRx chunks
+        audio registers (0x0a0 - 0xdf) saved with AUDx chunks
+
+AGA COLORS
+
+        "AGAC"
+
+        AGA color               8 banks * 32 registers *
+        registers               LONG (XRGB) = 1024
+
+SPRITE
+
+        "SPR0" - "SPR7"
+
+
+        SPRxPT                  4
+        SPRxPOS                 2
+        SPRxCTL                 2
+        SPRxDATA                2
+        SPRxDATB                2
+        AGA sprite DATA/DATB    3 * 2 * 2
+        sprite "armed" status   1
+
+        sprites maybe armed in non-DMA mode
+        use bit 0 only, other bits are reserved
+
+
+AUDIO
+        "AUD0" "AUD1" "AUD2" "AUD3"
+
+        audio state             1
+        machine mode
+        AUDxVOL                 1
+       irq?                    1
+       data_written?           1
+        internal AUDxLEN        2
+        AUDxLEN                 2
+       internal AUDxPER        2
+       AUDxPER                 2
+        internal AUDxLC         4
+       AUDxLC                  4
+       evtime?                 4
+
+BLITTER
+
+        "BLIT"
+
+        internal blitter state
+
+        flags                   4
+        bit 0=blitter active
+        bit 1=fill carry bit
+        internal ahold          4
+       internal bhold          4
+       internal hsize          2
+       internal vsize          2
+
+CIA
+
+        "CIAA" and "CIAB"
+
+        BFE001-BFEF01   16*1 (CIAA)
+        BFD000-BFDF00   16*1 (CIAB)
+
+        internal registers
+
+        IRQ mask (ICR)  1 BYTE
+        timer latches   2 timers * 2 BYTES (LO/HI)
+        latched tod     3 BYTES (LO/MED/HI)
+        alarm           3 BYTES (LO/MED/HI)
+        flags           1 BYTE
+                        bit 0=tod latched (read)
+                        bit 1=tod stopped (write)
+       div10 counter   1 BYTE
+
+FLOPPY DRIVES
+
+        "DSK0" "DSK1" "DSK2" "DSK3"
+
+        drive state
+
+        drive ID-word           4
+        state                   1 (bit 0: motor on, bit 1: drive disabled, bit 2: current id bit)
+        rw-head track           1
+        dskready                1
+        id-mode                 1 (ID mode bit number 0-31)
+        floppy information
+
+        bits from               4
+        beginning of track
+        CRC of disk-image       4 (used during restore to check if image
+                                  is correct)
+        disk-image              null-terminated
+        file name
+
+INTERNAL FLOPPY CONTROLLER STATUS
+
+        "DISK"
+
+        current DMA word        2
+        DMA word bit offset     1
+        WORDSYNC found          1 (no=0,yes=1)
+        hpos of next bit        1
+        DSKLENGTH status        0=off,1=written once,2=written twice
+       unused                  2
+
+RAM SPACE 
+
+        "xRAM" (CRAM = chip, BRAM = bogo, FRAM = fast, ZFRAM = Z3)
+
+        start address           4 ("bank"=chip/slow/fast etc..)
+        of RAM "bank"
+        RAM "bank" size         4
+        RAM flags               4 (bit 0 = zlib compressed)
+        RAM "bank" contents
+
+ROM SPACE
+
+        "ROM "
+
+        ROM start               4
+        address
+        size of ROM             4
+        ROM type                4 KICK=0
+        ROM flags               4
+        ROM version             2
+        ROM revision            2
+        ROM CRC                 4 see below
+        ROM-image ID-string     null terminated, see below
+        path to rom image
+        ROM contents            (Not mandatory, use hunk size to check if
+                                this hunk contains ROM data or not)
+
+        Kickstart ROM:
+         ID-string is "Kickstart x.x"
+         ROM version: version in high word and revision in low word
+         Kickstart ROM version and revision can be found from ROM start
+         + 12 (version) and +14 (revision)
+
+        ROM version and CRC is only meant for emulator to automatically
+        find correct image from its ROM-directory during state restore.
+
+        Usually saving ROM contents is not good idea.
+
+
+END
+        hunk "END " ends, remember hunk size 8!
+
+
+EMULATOR SPECIFIC HUNKS
+
+Read only if "emulator name" in header is same as used emulator.
+Maybe useful for configuration?
+
+misc:
+
+- save only at position 0,0 before triggering VBLANK interrupt
+- all data must be saved in bigendian format
+- should we strip all paths from image file names?
+
+*/
diff --git a/scsi-none.c b/scsi-none.c
new file mode 100755 (executable)
index 0000000..a553ef9
--- /dev/null
@@ -0,0 +1,20 @@
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "threaddep/thread.h"
+#include "options.h"
+#include "memory.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "disk.h"
+#include "autoconf.h"
+#include "filesys.h"
+#include "execlib.h"
+#include "scsidev.h"
+
+uaecptr scsidev_startup (uaecptr resaddr) { return resaddr; }
+void scsidev_install (void) {}
+void scsidev_reset (void) {}
+void scsidev_start_threads (void) {}
+
diff --git a/scsidev.c b/scsidev.c
new file mode 100755 (executable)
index 0000000..7840d9c
--- /dev/null
+++ b/scsidev.c
@@ -0,0 +1,819 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * a SCSI device
+  *
+  * Copyright 1995 Bernd Schmidt
+  * Copyright 1999 Patrick Ohly
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "threaddep/thread.h"
+#include "options.h"
+#include "memory.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "disk.h"
+#include "autoconf.h"
+#include "filesys.h"
+#include "execlib.h"
+#include "native2amiga.h"
+#include "scsidev.h"
+
+#include <stdio.h>
+
+/* the new libscg should always have a scsi_close */
+#ifndef SCSI_CLOSE
+#define SCSI_CLOSE
+#endif
+
+typedef int BOOL;
+
+#include "scg/scgcmd.h"
+#include "scg/scsitransp.h"
+#include "scg/scsireg.h"
+
+/* our configure does not have a seperate UAE_SCSIDEV_THREADS */
+#if defined(UAE_FILESYS_THREADS) && !defined(SCSI_IS_NOT_THREAD_SAFE)
+#define UAE_SCSIDEV_THREADS
+#endif
+
+#undef DEBUGME
+
+/****************** generic SCSI stuff stolen from cdrecord and scsitransp.c ***********/
+static int scsierr(SCSI *scgp)
+{
+    register struct scg_cmd *cp = scgp->scmd;
+
+    if(cp->error != SCG_NO_ERROR ||
+       cp->ux_errno != 0 || *(u_char *)&cp->scb != 0)
+        return -1;
+    return 0;
+}
+
+static int inquiry (SCSI *scgp, void *bp, int cnt)
+{
+    struct scg_cmd *scmd = scgp->scmd;
+
+    memset(bp, cnt, '\0');
+    memset((caddr_t)scmd, sizeof(*scmd), '\0');
+    scmd->addr = bp;
+    scmd->size = cnt;
+    scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
+    scmd->cdb_len = SC_G0_CDBLEN;
+    scmd->sense_len = CCS_SENSE_LEN;
+    scmd->target = scgp->target;
+    scmd->cdb.g0_cdb.cmd = SC_INQUIRY;
+    scmd->cdb.g0_cdb.lun = scgp->lun;
+    scmd->cdb.g0_cdb.count = cnt;
+       
+    scgp->cmdname = "inquiry";
+
+    if (scsicmd(scgp) < 0)
+        return (-1);
+    return (0);
+}
+
+static void print_product(struct scsi_inquiry *ip)
+{
+    write_log ("'%.8s' ", ip->info);
+    write_log ("'%.16s' ", ip->ident);
+    write_log ("'%.4s' ", ip->revision);
+    if (ip->add_len < 31) {
+        write_log ("NON CCS ");
+    }
+}
+
+/* get integer value from env or return default value, if unset */
+static int getenvint (const char *varname, int def)
+{
+    const char *val = getenv (varname);
+    return val ? atoi (val) : def;
+}
+
+/* wrapper for the underlying combination of scsi_smalloc()/scsi_open() */
+static SCSI *openscsi (int scsibus, int target, int lun)
+{
+    SCSI *scgp = scsi_smalloc ();
+    if (!scgp) {
+        return NULL;
+    }
+
+    scgp->debug = getenvint ("UAE_SCSI_DEBUG", 0);
+    scgp->kdebug = getenvint ("UAE_SCSI_KDEBUG", 0);
+    scgp->silent = getenvint ("UAE_SCSI_SILENT", 1);
+        scgp->verbose = getenvint ("UAE_SCSI_VERBOSE", 0);
+    scgp->scsibus = scsibus;
+    scgp->target = target;
+    scgp->lun = lun;
+
+    if (!scsi_open(scgp, NULL, scsibus, target, lun)) {
+        scsi_sfree (scgp);
+        return NULL;
+    } else {
+        return scgp;
+    } 
+}
+
+static void closescsi (SCSI *scgp)
+{
+    scsi_close (scgp);
+    scsi_sfree (scgp);
+}
+
+/********************* start of our own code ************************/
+
+static int opencount = 0;
+static SCSI *scgp; /* SCSI handle which is to be used by the main thread */
+uae_sem_t scgp_sem;
+
+
+/****************** unit handling *******************/
+
+struct scsidevdata {
+    int bus, target, lun; /* the real values */
+    int aunit;            /* Amiga unit number, by default calculated like that: */
+#define BTL2UNIT(bus, target, lun) \
+      (2 * (bus) + (target) / 8) * 100 + \
+      (lun) * 10 + \
+      (target % 8)
+    SCSI *scgp;
+    long max_dma;
+    int isatapi;
+#ifdef UAE_SCSIDEV_THREADS
+    /* Threading stuff */
+    smp_comm_pipe requests;
+    uae_thread_id tid;
+    int thread_running;
+    uae_sem_t sync_sem;
+#endif
+};
+
+#define MAX_DRIVES 16
+static struct scsidevdata drives[MAX_DRIVES];
+static int num_drives;
+static struct scsidevdata *get_scsidev_data (int unit)
+{
+    int i;
+
+    for (i = 0; i < num_drives; i++) {
+        if (unit == drives[i].aunit) {
+            return &drives[i];
+        }
+    }
+    return NULL;
+}
+
+static struct scsidevdata *add_scsidev_data (int bus, int target, int lun, int aunit)
+{
+    if (num_drives + 1 < MAX_DRIVES) {
+        memset(&drives[num_drives], 0, sizeof(drives[num_drives]));
+        drives[num_drives].bus = bus;
+        drives[num_drives].target = target;
+        drives[num_drives].lun = lun;
+        drives[num_drives].aunit = aunit;
+#if !defined(UAE_SCSIDEV_THREADS)
+        drives[num_drives].scgp = scgp;
+        drives[num_drives].max_dma = scsi_bufsize (scgp, 512 * 1024);
+#endif
+        /* check if this drive is an ATAPI drive */
+        scgp->scsibus = bus;
+        scgp->target = target;
+        scgp->lun = lun;
+        drives[num_drives].isatapi = scsi_isatapi (scgp);
+        return &drives[num_drives++];
+    }
+
+    return NULL;
+}
+
+static void *scsidev_thread(void *);
+static int start_thread (struct scsidevdata *sdd)
+{
+#ifdef UAE_SCSIDEV_THREADS
+    if (sdd->thread_running)
+        return 1;
+    init_comm_pipe (&sdd->requests, 10, 1);
+    uae_sem_init (&sdd->sync_sem, 0, 0);
+    uae_start_thread (scsidev_thread, sdd, &sdd->tid);
+    uae_sem_wait (&sdd->sync_sem);
+    return sdd->thread_running;
+#else
+    return 1;
+#endif
+}
+    
+/************* Exec device functions ****************/
+
+
+static uae_u32 scsidev_open (void)
+{
+    uaecptr tmp1 = m68k_areg(regs, 1); /* IOReq */
+    uae_u32 unit = m68k_dreg (regs, 0);
+    struct scsidevdata *sdd;
+
+#ifdef DEBUGME
+    printf("scsidev_open(0x%x, %d)\n", tmp1, unit);
+#endif
+
+    /* Check unit number */
+    if ((sdd = get_scsidev_data (unit)) &&
+        start_thread (sdd)) {
+       opencount++;
+       put_word (m68k_areg(regs, 6)+32, get_word (m68k_areg(regs, 6)+32) + 1);
+       put_long (tmp1 + 24, unit); /* io_Unit */
+       put_byte (tmp1 + 31, 0); /* io_Error */
+       put_byte (tmp1 + 8, 7); /* ln_type = NT_REPLYMSG */
+       return 0;
+    }
+
+    put_long (tmp1 + 20, (uae_u32)-1);
+    put_byte (tmp1 + 31, (uae_u8)-1);
+    return (uae_u32)-1;
+}
+
+static uae_u32 scsidev_close (void)
+{
+#ifdef DEBUGME
+    printf("scsidev_close()\n");
+#endif
+
+    opencount--;
+    put_word (m68k_areg(regs, 6) + 32, get_word (m68k_areg(regs, 6) + 32) - 1);
+
+    return 0;
+}
+
+static uae_u32 scsidev_expunge (void)
+{
+ #ifdef DEBUGME
+    printf("scsidev_expunge()\n");
+#endif
+    return 0; /* Simply ignore this one... */
+}
+
+#define MODE_SELECT_6  0x15
+#define MODE_SENSE_6   0x1A
+#ifndef MODE_SENSE_10
+#define MODE_SELECT_10 0x55
+#define MODE_SENSE_10  0x5A
+#endif
+
+
+#ifdef DEBUG_CDR
+/* please ignore this code - it can be used to debug raw CD-R writing... */
+
+/*
+** convert time in (BCD) min:sec:frame to block address
+*/
+typedef signed char BYTE;
+typedef unsigned char UBYTE;
+typedef long LONG;
+typedef BYTE BCD;
+typedef BYTE WORD[2];
+#define BCD_DEC(x) (((x) >> 4) * 10 + ((x) & 0xF))
+static LONG TestNegativeTime(LONG block)
+{
+    /* block -151 == 99:59:74
+       -150 == 100:00:00 = 00:00:00 */
+    if (block > (97 * 60 * 75))
+    {
+        /* must be a negative block */
+        block -= 100 * 60 * 75;
+    }
+    return block;
+}
+static LONG BCDTime2Block(UBYTE min, UBYTE sec, UBYTE frame)
+{
+    return(TestNegativeTime((LONG)((BCD_DEC(min) * 60 + BCD_DEC(sec)) * 75 + BCD_DEC(frame) - 2 * 75)));
+}
+static LONG Time2Block(UBYTE min, UBYTE sec, UBYTE frame)
+{
+    return(TestNegativeTime((LONG)((min * 60 + sec) * 75 + frame - 2 * 75)));
+}
+static LONG BCDTime2Block_Pointer (UBYTE *p)
+{
+    return BCDTime2Block (p[0], p[1], p[2]);
+}
+static LONG Time2Block_Pointer (UBYTE *p)
+{
+    return Time2Block (p[0], p[1], p[2]);
+}
+#endif
+
+static void scsidev_do_scsi (struct scsidevdata *sdd, uaecptr request)
+{
+    SCSI *scgp = sdd->scgp;
+    struct scg_cmd *scmd = scgp->scmd;
+    uaecptr acmd = get_long (request + 40);
+    uaecptr scsi_data = get_long (acmd + 0);
+    uae_u32 scsi_len = get_long (acmd + 4);
+    uaecptr scsi_cmd = get_long (acmd + 12);
+    uae_u16 scsi_cmd_len = get_word (acmd + 16);
+    uae_u8 scsi_flags = get_byte (acmd + 20);
+    uaecptr scsi_sense = get_long (acmd + 22);
+    uae_u16 scsi_sense_len = get_word (acmd + 26);
+    int sactual = 0;
+    addrbank *bank_data = &get_mem_bank (scsi_data);
+    addrbank *bank_cmd  = &get_mem_bank (scsi_cmd);
+
+    /* do transfer directly to and from Amiga memory */
+    if (!bank_data || !bank_data->check (scsi_data, scsi_len) ||
+        !bank_cmd  || !bank_cmd->check (scsi_cmd, scsi_cmd_len)) {
+        put_byte (request + 31, (uae_u8)-5); /* IOERR_BADADDRESS */
+        return;
+    }
+
+#ifdef SCSI_IS_NOT_THREAD_SAFE
+    uae_sem_wait (&scgp_sem);
+#endif
+
+        scmd->timeout = 80 * 60; /* the Amiga does not tell us how long the timeout shall be, so make it _very_ long (specified in seconds) */
+    scmd->addr = bank_data->xlateaddr (scsi_data);
+    scmd->size = scsi_len;
+    scmd->flags = ((scsi_flags & 1) ? SCG_RECV_DATA : 0) | SCG_DISRE_ENA;
+    scmd->cdb_len = scsi_cmd_len;
+    memcpy(&scmd->cdb, bank_cmd->xlateaddr (scsi_cmd), scsi_cmd_len);
+    scmd->target = sdd->target;
+    scmd->sense_len = (scsi_flags & 4) ? 4 : /* SCSIF_OLDAUTOSENSE */
+        (scsi_flags & 2) ? scsi_sense_len : /* SCSIF_AUTOSENSE */
+        -1;
+    scmd->sense_count = 0;
+    *(uae_u8 *)&scmd->scb = 0;
+
+    #ifdef DEBUG_CDR
+    /* please ignore this code - it can be used to debug raw CD-R writing... */
+    if (!(scsi_len % 2368)) {
+        /* Structure for generating bytes 2353...2368 if writing in ultra raw mode */
+        typedef struct QDATAtag {
+            BYTE ControlAdr;
+            BCD Tno;
+            BCD Point;
+            BCD Min;
+            BCD Sec;
+            BCD Frame;
+            BYTE Zero;
+            BCD PMin;
+            BCD PSec;
+            BCD PFrame;
+            WORD Crc;
+            BYTE Reserved[3];
+            BYTE PChannel;
+        } QDATA;
+
+        int i = scsi_len / 2368;
+        QDATA *data = (QDATA *)&((unsigned char *)scmd->addr)[2352];
+        for (; i > 0; i--, data = (QDATA *)&((unsigned char *)data)[2368]) {
+            printf ("$%02x: $%02x $%02x | $%02x:$%02x:$%02x = %6ld | $%02x | $%02x:$%02x:$%02x = %6ld\n",
+                    (int)data->ControlAdr, (int)*(UBYTE *)&data->Tno, (int)*(UBYTE *)&data->Point,
+                    (int)*(UBYTE *)&data->Min, (int)*(UBYTE *)&data->Sec, (int)*(UBYTE *)&data->Frame,
+                    BCDTime2Block_Pointer (&data->Min) + 150,
+                    *(UBYTE *)&data->Zero,
+                    *(UBYTE *)&data->PMin, *(UBYTE *)&data->PSec, *(UBYTE *)&data->PFrame,
+                    BCDTime2Block_Pointer (&data->PMin));
+        }
+        fflush (stdout);
+    }
+    #endif
+    scgp->scsibus = sdd->bus;
+    scgp->target  = sdd->target;
+    scgp->lun     = sdd->lun;
+    scgp->cmdname = "???";
+    scgp->curcmdname = "???";
+
+    /* replace MODE_SELECT/SENSE_6 if we access a ATAPI drive,
+       otherwise send it now */
+    if (sdd->isatapi &&
+        (scmd->cdb.g0_cdb.cmd == MODE_SELECT_6 ||
+         scmd->cdb.g0_cdb.cmd == MODE_SENSE_6)) {
+        uae_u8 buffer[256 + 2], *data = scmd->addr, *tmp;
+        int len = 0, page_len, i;
+        int do_it = 1;
+        uae_u8 sp = scmd->cdb.g0_cdb.high_addr & 1;
+        uae_u8 alloc_len = scmd->cdb.g0_cdb.count;
+        uae_u8 pcf_page_code = scmd->cdb.g0_cdb.mid_addr;
+        uae_u8 cmd = scmd->cdb.g0_cdb.cmd;
+
+        memset (&scmd->cdb.g1_cdb, 0, sizeof(scmd->cdb.g1_cdb));
+        if (cmd == MODE_SELECT_6) {
+            /* expand parameter list */
+            tmp = data;
+            buffer[len++] = *tmp++;      /* first byte, should be 0 */
+            buffer[len++] = 0;           /* reserved */
+            buffer[len++] = *tmp++;      /* medium type */
+            buffer[len++] = 0; *tmp++;   /* ignore host application code */
+            for (i = 0; i < 4; i++) {
+                buffer[len++] = 0;
+            }
+            if (*tmp) {
+                /* skip block descriptor */
+                tmp += 8;
+            }
+            tmp++;
+            page_len = scsi_len - (tmp - data);
+            if (page_len > 0) {
+                memcpy (&buffer[len], tmp, page_len);
+                len += page_len;
+
+                scmd->cdb.g1_cdb.cmd = MODE_SELECT_10;
+                scmd->cdb.g1_cdb.lun = sdd->lun;
+                scmd->cdb.g1_cdb.res = 1 << 3; /* PF bit */
+                scmd->cdb.g1_cdb.reladr = sp;
+                scmd->cdb.g1_cdb.count[0] = len >> 8;
+                scmd->cdb.g1_cdb.count[1] = len;
+            } else {
+                do_it = 0;
+                scmd->error = 0;
+                *(uae_u8 *)&scmd->scb = 0;
+                scmd->ux_errno = 0;
+            }
+        } else {
+            /* MODE_SENSE_6 */
+            len = alloc_len + 2;
+            scmd->cdb.g1_cdb.cmd = MODE_SENSE_10;
+            scmd->cdb.g1_cdb.lun = sdd->lun;
+            scmd->cdb.g1_cdb.addr[0] = pcf_page_code;
+            scmd->cdb.g1_cdb.count[0] = len >> 8;
+            scmd->cdb.g1_cdb.count[1] = len;
+        }
+        if (do_it) {
+            scmd->cdb_len = 10;
+            scmd->addr = buffer;
+            scmd->size = len;
+            scmd->sense_count = 0;
+            *(uae_u8 *)&scmd->scb = 0;
+            
+            scsicmd (scgp);
+
+            if (cmd == MODE_SENSE_6 &&
+                !scmd->error &&
+                !scmd->ux_errno &&
+                !*(uae_u8 *)&scmd->scb) {
+                int req_len = len;
+                
+                /* compress result */
+                tmp = buffer;
+                len = 0;
+                tmp++;                 /* skip first byte of length - should better be zero */
+                data[len++] = *tmp++;  /* mode data length */
+                data[len++] = *tmp++;  /* medium type */
+                data[len++] = 0;       /* host application type */
+                data[len++] = 0;       /* block descr length */
+                tmp += 4;
+                if (*tmp) {
+                    /* skip block descr - should not happen */
+                    tmp += *tmp;
+                }
+                tmp++;
+                memcpy (&data[len], tmp, req_len - (tmp - buffer));
+            }
+        }
+    } else {
+        scsicmd (scgp);
+    }
+    
+    put_word (acmd + 18, scmd->error == SCG_FATAL ? 0 : scsi_cmd_len); /* fake scsi_CmdActual */
+    put_byte (acmd + 21, *(uae_u8 *)&scmd->scb); /* scsi_Status */
+    if (*(uae_u8 *)&scmd->scb) {
+        put_byte (request + 31, 45); /* HFERR_BadStatus */
+
+        /* copy sense? */
+        for (sactual = 0;
+             scsi_sense && sactual < scsi_sense_len && sactual < scmd->sense_count;
+             sactual++) {
+            put_byte (scsi_sense + sactual, scmd->u_sense.cmd_sense[sactual]);
+        }
+        put_long (acmd + 8, 0); /* scsi_Actual */
+    } else {
+        int i;
+        
+        for (i = 0; i < scsi_sense_len; i++) {
+            put_byte (scsi_sense + i, 0);
+        }
+        sactual = 0;
+
+        if (scmd->error != SCG_NO_ERROR ||
+            scmd->ux_errno != 0) {
+            /* we might have been limited by the hosts DMA limits,
+               which is usually indicated by ENOMEM */
+            if (scsi_len > (unsigned int)sdd->max_dma &&
+                scmd->ux_errno == ENOMEM) {
+                put_byte (request + 31, (uae_u8)-4); /* IOERR_BADLENGTH */
+            } else {
+                put_byte (request + 31, 20); /* io_Error, but not specified */
+                put_long (acmd + 8, 0); /* scsi_Actual */
+            }
+        } else {
+            put_byte (request + 31, 0);
+            put_long (acmd + 8, scsi_len - scmd->resid); /* scsi_Actual */
+        }
+    }
+    put_word (acmd + 28, sactual);
+
+#ifdef SCSI_IS_NOT_THREAD_SAFE
+    uae_sem_post (&scgp_sem);
+#endif
+}
+
+static void scsidev_do_io (struct scsidevdata *sdd, uaecptr request)
+{
+    uae_u32 tmp2, dataptr, offset;
+    
+    tmp2 = get_word (request+28); /* io_Command */
+    switch (tmp2) {
+     case 28:
+        /* HD_SCSICMD */
+        scsidev_do_scsi (sdd, request);
+        break;
+     default:
+       /* Command not understood. */
+       put_byte (request+31, (uae_u8)-3); /* io_Error */
+       break;
+    }
+#ifdef DEBUGME
+    printf ("scsidev: did io: sdd     = 0x%x\n", sdd);
+    printf ("scsidev: did io: request = %08lx\n", (unsigned long)request);
+    printf ("scsidev: did io: error   = %d\n", (int)get_word(request+31));
+#endif
+}
+
+
+static uae_u32 scsidev_beginio (void)
+{
+    uae_u32 request = m68k_areg(regs, 1);
+    int unit = get_long (request + 24);
+    struct scsidevdata *sdd = get_scsidev_data (unit);
+
+#ifdef DEBUGME
+    printf ("scsidev_begin_io: sdd     = 0x%x\n", sdd);
+    printf ("scsidev_begin_io: request = %08lx\n", (unsigned long)request);
+    printf ("scsidev_begin_io: cmd     = %d\n", (int)get_word(request+28));
+#endif
+
+    put_byte (request+8, NT_MESSAGE);
+    put_byte (request+31, 0); /* no error yet */
+
+#ifdef UAE_SCSIDEV_THREADS
+    {
+        uae_pt data;
+
+        /* clear IOF_QUICK */
+        put_byte (request+30, get_byte (request+30) & ~1);
+        /* forward to unit thread */
+        write_comm_pipe_u32 (&sdd->requests, request, 1);
+        return 0;
+    }
+#else
+    put_byte (request+30, get_byte (request+30) & ~1);
+    scsidev_do_io (sdd, request);
+    return get_byte (request+31); /* do we really have to return io_Error? */
+#endif
+}
+
+#ifdef UAE_SCSIDEV_THREADS
+static void *scsidev_thread (void *sddv)
+{
+    struct scsidevdata *sdd = sddv;
+
+#ifdef DEBUGME
+    printf ("scsidev_penguin: sdd  = 0x%x ready\n", sdd);
+#endif    
+    /* init SCSI */
+    if (!(sdd->scgp = openscsi (sdd->bus, sdd->target, sdd->lun)) ||
+        (sdd->max_dma = scsi_bufsize (sdd->scgp, 512 * 1024)) <= 0) {
+        sdd->thread_running = 0;
+        uae_sem_post (&sdd->sync_sem);
+        return 0;
+    }
+    sdd->thread_running = 1;
+    uae_sem_post (&sdd->sync_sem);
+
+    for (;;) {
+       uaecptr request;
+
+       request = (uaecptr)read_comm_pipe_u32_blocking (&sdd->requests);
+#ifdef DEBUGME
+        printf ("scsidev_penguin: sdd  = 0x%x\n", sdd);
+        printf ("scsidev_penguin: req  = %08lx\n", (unsigned long)request);
+        printf ("scsidev_penguin: cmd  = %d\n", (int)get_word(request+28));
+#endif
+        if (!request) {
+            printf ("scsidev_penguin: going down with 0x%x\n", sdd->sync_sem);
+           /* Death message received. */
+            sdd->thread_running = 0;
+           uae_sem_post (&sdd->sync_sem);
+           /* Die.  */
+           return 0;
+       }
+
+        scsidev_do_io (sdd, request);
+        uae_ReplyMsg (request);
+    }
+    return 0;
+}
+#endif
+
+
+static uae_u32 scsidev_abortio (void)
+{
+    return (uae_u32)-3;
+}
+
+static uae_u32 scsidev_init (void)
+{
+#ifdef DEBUGME
+    printf("scsidev_init()\n");
+#endif
+    
+    if (scgp) {
+        /* we still have everything in place */
+        return m68k_dreg (regs, 0); /* device base */
+    }
+    
+    /* init global SCSI */
+    if (!(scgp = openscsi (-1, -1, -1))) {
+        return 0;
+    }
+
+    uae_sem_init (&scgp_sem, 0, 1);
+
+    /* add all units we find */
+    for (scgp->scsibus=0; scgp->scsibus < 8; scgp->scsibus++) {
+        if (!scsi_havebus(scgp, scgp->scsibus))
+            continue;
+        printf("scsibus%d:\n", scgp->scsibus);
+        for (scgp->target=0; scgp->target < 16; scgp->target++) {
+            struct scsi_inquiry inq;
+            scgp->lun = 0;
+            if (inquiry (scgp, &inq, sizeof(inq))) {
+                continue;
+            }
+            for (scgp->lun=0; scgp->lun < 8; scgp->lun++) {
+                if (!inquiry (scgp, &inq, sizeof(inq))) {
+                    int aunit = BTL2UNIT(scgp->scsibus, scgp->target, scgp->lun);
+                    struct scsidevdata *sdd;
+                    
+                    write_log ("   %2.01d,%d (= %3.d): ", scgp->target, scgp->lun, aunit);
+                    print_product (&inq);
+                    sdd = add_scsidev_data (scgp->scsibus, scgp->target, scgp->lun, aunit);
+                    write_log (!sdd ? " - init failed ???" : sdd->isatapi ? " - ATAPI" : " - SCSI");
+                    write_log ("\n");
+               }
+            }
+        }
+    }
+    return m68k_dreg (regs, 0); /* device base */
+}
+
+static uaecptr ROM_scsidev_resname = 0,
+    ROM_scsidev_resid = 0,
+    ROM_scsidev_init = 0;
+
+uaecptr scsidev_startup (uaecptr resaddr)
+{
+#ifdef DEBUGME
+    printf("scsidev_startup(0x%x)\n", resaddr);
+#endif
+    /* Build a struct Resident. This will set up and initialize
+     * the uaescsi.device */
+    put_word(resaddr + 0x0, 0x4AFC);
+    put_long(resaddr + 0x2, resaddr);
+    put_long(resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */
+    put_word(resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */
+    put_word(resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */
+    put_long(resaddr + 0xE, ROM_scsidev_resname);
+    put_long(resaddr + 0x12, ROM_scsidev_resid);
+    put_long(resaddr + 0x16, ROM_scsidev_init); /* calls scsidev_init */
+    resaddr += 0x1A;
+
+    return resaddr;
+}
+
+void scsidev_install (void)
+{
+    uae_u32 functable, datatable;
+    uae_u32 initcode, openfunc, closefunc, expungefunc;
+    uae_u32 beginiofunc, abortiofunc;
+
+#ifdef DEBUGME
+    printf("scsidev_install(): 0x%x\n", here ());
+#endif
+
+    ROM_scsidev_resname = ds ("uaescsi.device");
+    ROM_scsidev_resid = ds ("UAE scsi.device 0.1");
+
+    /* initcode */
+    initcode = here ();
+    calltrap (deftrap (scsidev_init)); dw (RTS);
+    
+    /* Open */
+    openfunc = here ();
+    calltrap (deftrap (scsidev_open)); dw (RTS);
+
+    /* Close */
+    closefunc = here ();
+    calltrap (deftrap (scsidev_close)); dw (RTS);
+
+    /* Expunge */
+    expungefunc = here ();
+    calltrap (deftrap (scsidev_expunge)); dw (RTS);
+
+    /* BeginIO */
+    beginiofunc = here ();
+    calltrap (deftrap (scsidev_beginio));
+#ifndef UAE_SCSIDEV_THREADS
+    /* don't reply when using threads - native2amiga's Reply() does that */
+    dw (0x48E7); dw (0x8002); /* movem.l d0/a6,-(a7) */
+    dw (0x0829); dw (0); dw (30); /* btst #0,30(a1) */
+    dw (0x6608); /* bne.b +8 */
+    dw (0x2C78); dw (0x0004); /* move.l 4,a6 */
+    dw (0x4EAE); dw (-378); /* jsr ReplyMsg(a6) */
+    dw (0x4CDF); dw (0x4001); /* movem.l (a7)+,d0/a6 */
+#endif
+    dw (RTS);
+
+    /* AbortIO */
+    abortiofunc = here ();
+    calltrap (deftrap (scsidev_abortio)); dw (RTS);
+
+    /* FuncTable */
+    functable = here ();
+    dl (openfunc); /* Open */
+    dl (closefunc); /* Close */
+    dl (expungefunc); /* Expunge */
+    dl (EXPANSION_nullfunc); /* Null */
+    dl (beginiofunc); /* BeginIO */
+    dl (abortiofunc); /* AbortIO */
+    dl (0xFFFFFFFFul); /* end of table */
+
+    /* DataTable */
+    datatable = here ();
+    dw (0xE000); /* INITBYTE */
+    dw (0x0008); /* LN_TYPE */
+    dw (0x0300); /* NT_DEVICE */
+    dw (0xC000); /* INITLONG */
+    dw (0x000A); /* LN_NAME */
+    dl (ROM_scsidev_resname);
+    dw (0xE000); /* INITBYTE */
+    dw (0x000E); /* LIB_FLAGS */
+    dw (0x0600); /* LIBF_SUMUSED | LIBF_CHANGED */
+    dw (0xD000); /* INITWORD */
+    dw (0x0014); /* LIB_VERSION */
+    dw (0x0004); /* 0.4 */
+    dw (0xD000); /* INITWORD */
+    dw (0x0016); /* LIB_REVISION */
+    dw (0x0000); /* end of table already ??? */
+    dw (0xC000); /* INITLONG */
+    dw (0x0018); /* LIB_IDSTRING */
+    dl (ROM_scsidev_resid);
+    dw (0x0000); /* end of table */
+
+    ROM_scsidev_init = here ();
+    dl (0x00000100); /* size of device base */
+    dl (functable);
+    dl (datatable);
+    dl (initcode);
+}
+
+void scsidev_reset (void)
+{
+#ifdef DEBUGME
+    printf("scsidev_reset()\n");
+#endif
+
+#ifdef SCSI_CLOSE
+#ifdef UAE_SCSIDEV_THREADS
+    {
+        int i;
+
+        for (i = 0; i < num_drives; i++) {
+            if (!drives[i].thread_running) {
+                continue;
+            }
+            write_comm_pipe_int (&drives[i].requests, 0, 1);
+            uae_sem_wait (&drives[i].sync_sem);
+        }
+        num_drives = 0;
+    }
+#endif
+    
+    if (scgp) {
+        closescsi (scgp);
+        scgp = NULL;
+    }
+#endif
+    
+    opencount = 0;
+}
+
+void scsidev_start_threads (void)
+{
+#ifdef DEBUGME
+    printf("scsidev_start_threads()\n");
+#endif
+}
+
diff --git a/scsiemul.c b/scsiemul.c
new file mode 100755 (executable)
index 0000000..30765d1
--- /dev/null
@@ -0,0 +1,913 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * scsi.device emulation
+  *
+  * Copyright 1995 Bernd Schmidt
+  * Copyright 1999 Patrick Ohly
+  * Copyright 2001 Brian King
+  * Copyright 2002 Toni Wilen
+  *
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "uae.h"
+#include "threaddep/thread.h"
+#include "options.h"
+#include "memory.h"
+#include "custom.h"
+#include "events.h"
+#include "newcpu.h"
+#include "autoconf.h"
+#include "execlib.h"
+#include "native2amiga.h"
+#include "blkdev.h"
+#include "scsidev.h"
+
+#define CDDEV_COMMANDS
+
+#define UAEDEV_SCSI "uaescsi.device"
+#define UAEDEV_SCSI_ID 1
+#define UAEDEV_DISK "uaedisk.device"
+#define UAEDEV_DISK_ID 2
+
+#define MAX_ASYNC_REQUESTS 20
+#define MAX_OPEN_DEVICES 20
+
+#define CMD_INVALID    0
+#define CMD_RESET      1
+#define CMD_READ       2
+#define CMD_WRITE      3
+#define CMD_UPDATE     4
+#define CMD_CLEAR      5
+#define CMD_STOP       6
+#define CMD_START      7
+#define CMD_FLUSH      8
+#define CMD_MOTOR      9
+#define CMD_SEEK       10
+#define CMD_FORMAT     11
+#define CMD_REMOVE     12
+#define CMD_CHANGENUM  13
+#define CMD_CHANGESTATE        14
+#define CMD_PROTSTATUS 15
+#define CMD_GETDRIVETYPE 18
+#define CMD_GETNUMTRACKS 19
+#define CMD_ADDCHANGEINT 20
+#define CMD_REMCHANGEINT 21
+#define CMD_GETGEOMETRY        22
+
+#define CD_INFO                32
+#define CD_CONFIG      33
+#define CD_TOCMSF      34
+#define CD_TOCLSN      35
+#define CD_READXL      36
+#define CD_PLAYTRACK   37
+#define CD_PLAYMSF     38
+#define CD_PLAYLSN     39
+#define CD_PAUSE       40
+#define CD_SEARCH      41
+#define CD_QCODEMSF    42
+#define CD_QCODELSN    43
+#define CD_ATTENUATE   44
+#define CD_ADDFRAMEINT 45
+#define CD_REMFRAMEINT 46
+
+#define ASYNC_REQUEST_NONE 0
+#define ASYNC_REQUEST_TEMP 1
+#define ASYNC_REQUEST_CHANGEINT 10
+#define ASYNC_REQUEST_FRAMEINT 11
+#define ASYNC_REQUEST_PLAY 12
+#define ASYNC_REQUEST_READXL 13
+#define ASYNC_REQUEST_FRAMECALL 14
+
+struct devstruct {
+    int unitnum, aunit;
+    int opencnt;
+    int changenum;
+    int allow_scsi;
+    int allow_ioctl;
+    int drivetype;
+    int iscd;
+    volatile uaecptr d_request[MAX_ASYNC_REQUESTS];
+    volatile int d_request_type[MAX_ASYNC_REQUESTS];
+    volatile uae_u32 d_request_data[MAX_ASYNC_REQUESTS];
+    struct device_info di;
+
+    smp_comm_pipe requests;
+    uae_thread_id tid;
+    int thread_running;
+    uae_sem_t sync_sem;
+};
+
+struct priv_devstruct {
+    int inuse;
+    int unit;
+    int mode;
+    int scsi;
+    int ioctl;
+    int noscsi;
+    int type;
+    int flags; /* OpenDevice() */
+};
+
+static struct devstruct devst[MAX_TOTAL_DEVICES];
+static struct priv_devstruct pdevst[MAX_OPEN_DEVICES];
+
+static uae_sem_t change_sem;
+
+static struct device_info *devinfo (int mode, int unitnum, struct device_info *di)
+{
+    return sys_command_info (mode, unitnum, di);
+}
+
+static void io_log (char *msg, uaecptr request)
+{
+    if (log_scsi)
+        write_log ("%s: %08X %d %08.8X %d %d io_actual=%d io_error=%d\n",
+           msg, request,get_word(request + 28),get_long(request + 40),get_long(request + 36),get_long(request + 44),
+           get_long (request + 32), get_byte (request + 31));
+}
+
+void memcpyha (uae_u32 dst, char *src, int size)
+{
+    while (size--)
+       put_byte (dst++, *src++);
+}
+
+static struct devstruct *getdevstruct (int unit)
+{
+    int i;
+    for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
+       if (unit >= 0 && devst[i].aunit == unit) return &devst[i];
+    }
+    return 0;
+}
+
+static struct priv_devstruct *getpdevstruct (uaecptr request)
+{
+    int i = get_long (request + 24);
+    if (i < 0 || i >= MAX_OPEN_DEVICES || pdevst[i].inuse == 0) {
+       write_log ("uaescsi.device: corrupt iorequest %08.8X %d\n", request, i);
+       return 0;
+    }
+    return &pdevst[i];
+}
+
+static char *getdevname (int type)
+{
+    switch (type) {
+       case UAEDEV_SCSI_ID:
+       return UAEDEV_SCSI;
+       case UAEDEV_DISK_ID:
+       return UAEDEV_DISK;
+       default:
+       abort ();
+    }
+}
+
+static void *dev_thread (void *devs);
+static int start_thread (struct devstruct *dev)
+{
+    if (dev->thread_running)
+        return 1;
+    init_comm_pipe (&dev->requests, 100, 1);
+    uae_sem_init (&dev->sync_sem, 0, 0);
+    uae_start_thread (dev_thread, dev, &dev->tid);
+    uae_sem_wait (&dev->sync_sem);
+    return dev->thread_running;
+}
+
+static void dev_close_3 (struct devstruct *dev, struct priv_devstruct *pdev)
+{
+    if (!dev->opencnt) return;
+    dev->opencnt--;
+    if (!dev->opencnt) {
+       if (pdev->scsi)
+           sys_command_close (DF_SCSI, dev->unitnum);
+       if (pdev->ioctl)
+           sys_command_close (DF_IOCTL, dev->unitnum);
+       pdev->inuse = 0;
+        write_comm_pipe_u32 (&dev->requests, 0, 1);
+    }
+}
+
+static uae_u32 dev_close_2 (void)
+{
+    uae_u32 request = m68k_areg (regs, 1);
+    struct priv_devstruct *pdev = getpdevstruct (request);
+    struct devstruct *dev;
+
+    if (!pdev)
+       return 0;
+    dev = getdevstruct (pdev->unit);
+    if (log_scsi)
+       write_log ("%s:%d close, req=%08.8X\n", getdevname (pdev->type), pdev->unit, request);
+    if (!dev)
+       return 0;
+    dev_close_3 (dev, pdev);
+    put_long (request + 24, 0);
+    put_word (m68k_areg(regs, 6) + 32, get_word (m68k_areg(regs, 6) + 32) - 1);
+    return 0;
+}
+
+static uae_u32 dev_close (void)
+{
+    return dev_close_2 ();
+}
+static uae_u32 diskdev_close (void)
+{
+    return dev_close_2 ();
+}
+
+static int openfail (uaecptr ioreq, int error)
+{
+    put_long (ioreq + 20, -1);
+    put_byte (ioreq + 31, error);
+    return (uae_u32)-1;
+}
+
+static uae_u32 dev_open_2 (int type)
+{
+    uaecptr ioreq = m68k_areg(regs, 1);
+    uae_u32 unit = m68k_dreg (regs, 0);
+    uae_u32 flags = m68k_dreg (regs, 1);
+    struct devstruct *dev = getdevstruct (unit);
+    struct priv_devstruct *pdev = 0;
+    int i;
+
+    if (log_scsi)
+       write_log ("opening %s:%d ioreq=%08.8X\n", getdevname (type), unit, ioreq);
+    if (!dev)
+       return openfail (ioreq, 32); /* badunitnum */
+    if (!dev->opencnt) {
+        for (i = 0; i < MAX_OPEN_DEVICES; i++) {
+           pdev = &pdevst[i];
+           if (pdev->inuse == 0) break;
+       }
+       if (type == UAEDEV_SCSI_ID && sys_command_open (DF_SCSI, dev->unitnum)) {
+           pdev->scsi = 1;
+           pdev->mode = DF_SCSI;
+       }
+       if (type == UAEDEV_DISK_ID && sys_command_open (DF_IOCTL, dev->unitnum)) {
+           pdev->ioctl = 1;
+           pdev->mode = DF_IOCTL;
+       }
+       if (!pdev->scsi && !pdev->ioctl)
+           return openfail (ioreq, -1);
+        pdev->type = type;
+        pdev->unit = unit;
+       pdev->flags = flags;
+       pdev->inuse = 1;
+        put_long (ioreq + 24, pdev - pdevst);
+       start_thread (dev);
+    } else {
+        for (i = 0; i < MAX_OPEN_DEVICES; i++) {
+           pdev = &pdevst[i];
+           if (pdev->inuse && pdev->unit == unit) break;
+       }
+       if (i == MAX_OPEN_DEVICES)
+           return openfail (ioreq, -1);
+        put_long (ioreq + 24, pdev - pdevst);
+    }
+    dev->opencnt++;
+
+    put_word (m68k_areg(regs, 6) + 32, get_word (m68k_areg(regs, 6) + 32) + 1);
+    put_byte (ioreq + 31, 0);
+    put_byte (ioreq + 8, 7);
+    return 0;
+}
+
+static uae_u32 dev_open (void)
+{
+    return dev_open_2 (UAEDEV_SCSI_ID);
+}
+static uae_u32 diskdev_open (void)
+{
+    return dev_open_2 (UAEDEV_DISK_ID);
+}
+
+static uae_u32 dev_expunge (void)
+{
+    return 0;
+}
+static uae_u32 diskdev_expunge (void)
+{
+    return 0;
+}
+
+static int is_async_request (struct devstruct *dev, uaecptr request)
+{
+    int i = 0;
+    while (i < MAX_ASYNC_REQUESTS) {
+       if (dev->d_request[i] == request) return 1;
+       i++;
+    }
+    return 0;
+}
+
+void scsi_do_disk_change (int device_id, int insert)
+{
+    int i, j;
+    
+    uae_sem_wait (&change_sem);
+    for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
+       if (devst[i].di.id == device_id) {
+           devst[i].changenum++;
+           j = 0;
+           while (j < MAX_ASYNC_REQUESTS) {
+               if (devst[i].d_request_type[j] == ASYNC_REQUEST_CHANGEINT) {
+                   uae_Cause (devst[i].d_request_data[j]);
+               }
+               j++;
+           }
+       }
+    }
+    uae_sem_post (&change_sem);
+}
+
+static int add_async_request (struct devstruct *dev, uaecptr request, int type, uae_u32 data)
+{
+    int i;
+
+    if (log_scsi)
+       write_log ("async request %p (%d) added\n", request, type);
+    i = 0;
+    while (i < MAX_ASYNC_REQUESTS) {
+       if (dev->d_request[i] == request) {
+           dev->d_request_type[i] = type;
+           dev->d_request_data[i] = data;
+           return 0;
+       }
+       i++;
+    }
+    i = 0;
+    while (i < MAX_ASYNC_REQUESTS) {
+       if (dev->d_request[i] == 0) {
+           dev->d_request[i] = request;
+           dev->d_request_type[i] = type;
+           dev->d_request_data[i] = data;
+           return 0;
+       }
+       i++;
+    }
+    return -1;
+}
+
+static int release_async_request (struct devstruct *dev, uaecptr request)
+{
+    int i = 0;
+
+    if (log_scsi)
+       write_log ("async request %p removed\n", request);
+    while (i < MAX_ASYNC_REQUESTS) {
+       if (dev->d_request[i] == request) {
+           int type = dev->d_request_type[i];
+           dev->d_request[i] = 0;
+           dev->d_request_data[i] = 0;
+           dev->d_request_type[i] = 0;
+           return type;
+       }
+       i++;
+    }
+    return -1;
+}
+
+static void abort_async (struct devstruct *dev, uaecptr request, int errcode, int type)
+{
+    int i;
+    i = 0;
+    while (i < MAX_ASYNC_REQUESTS) {
+       if (dev->d_request[i] == request && dev->d_request_type[i] == ASYNC_REQUEST_TEMP) {
+           /* ASYNC_REQUEST_TEMP = request is processing */
+           sleep_millis (10);
+           i = 0;
+           continue;
+       }
+       i++;
+    }
+    i = release_async_request (dev, request);
+    if (i >= 0 && log_scsi)
+       write_log ("asyncronous request=%08.8X aborted, error=%d\n", request, errcode);
+}
+
+static int command_read (int mode, struct devstruct *dev, uaecptr data, int offset, int length, uae_u32 *io_actual)
+{
+    uae_u8 *temp;
+    int len, sector;
+
+    int startoffset = offset % dev->di.bytespersector;
+    offset -= startoffset;
+    sector = offset / dev->di.bytespersector;
+    *io_actual = 0;
+    while (length > 0) {
+       temp = sys_command_read (mode, dev->unitnum, sector);
+       if (!temp) return 20;
+       if (startoffset > 0) {
+           len = dev->di.bytespersector - startoffset;
+           if (len > length) len = length;
+           memcpyha (data, temp + startoffset, len);
+           length -= len;
+           data += len;
+           startoffset = 0;
+           *io_actual += len;
+       } else if (length >= dev->di.bytespersector) {
+           len = dev->di.bytespersector;
+           memcpyha (data, temp, len);
+           length -= len;
+           data += len;
+           *io_actual += len;
+       } else {
+           memcpyha (data, temp, length);
+           *io_actual += length;
+           length = 0;
+       }
+       sector++;
+    }
+    return 0;
+}
+
+static int dev_do_io (struct devstruct *dev, uaecptr request)
+{
+    uae_u32 command;
+    uae_u32 io_data = get_long (request + 40); // 0x28
+    uae_u32 io_length = get_long (request + 36); // 0x24
+    uae_u32 io_actual = get_long (request + 32); // 0x20
+    uae_u32 io_offset = get_long (request + 44); // 0x2c
+    uae_u32 io_error = 0;
+    int async = 0;
+    struct device_info di;
+    struct priv_devstruct *pdev = getpdevstruct (request);
+
+    if (!pdev)
+       return 0;
+    command = get_word (request+28);
+
+    switch (command)
+    {
+       case CMD_READ:
+       io_error = command_read (pdev->mode, dev, io_data, io_offset, io_length, &io_actual);
+       break;
+       case CMD_WRITE:
+       case CMD_FORMAT:
+       io_error = 28; /* writeprotect */
+       break;
+       case CMD_UPDATE:
+       case CMD_CLEAR:
+       case CMD_FLUSH:
+       case CMD_MOTOR:
+       case CMD_SEEK:
+       io_actual = 0;
+       break;
+       case CMD_REMOVE:
+       io_actual = 0;
+       break;
+       case CMD_CHANGENUM:
+       io_actual = dev->changenum;
+       break;
+       case CMD_CHANGESTATE:
+       io_actual = devinfo(pdev->mode, dev->unitnum, &di)->media_inserted ? 0 : 1;
+       break;
+       case CMD_PROTSTATUS:
+       io_actual = devinfo(pdev->mode, dev->unitnum, &di)->write_protected ? -1 : 0;
+       break;
+       case CMD_GETDRIVETYPE:
+       io_actual = dev->drivetype;
+       break;
+       case CMD_GETNUMTRACKS:
+       io_actual = dev->di.cylinders;
+       break;
+       case CMD_ADDCHANGEINT:
+       io_error = add_async_request (dev, request, ASYNC_REQUEST_CHANGEINT, io_data);
+       if (!io_error)
+           async = 1;
+       break;
+       case CMD_REMCHANGEINT:
+       release_async_request (dev, request);
+       break;
+        case 28: /* HD_SCSICMD */
+        if (dev->allow_scsi && pdev->scsi) {
+           uae_u32 sdd = get_long (request + 40);
+           io_error = sys_command_scsi_direct (dev->unitnum, sdd);
+           if (log_scsi)
+               write_log ("scsidev: did io: sdd %p request %p error %d\n", sdd, request, get_byte (request + 31));
+       }
+       break;
+       default:
+       io_error = -3;
+       break;
+    }
+    put_long (request + 32, io_actual);
+    put_byte (request + 31, io_error);
+    io_log ("dev_io",request);
+    return async;
+}
+
+static int dev_can_quick (uae_u32 command)
+{
+    switch (command)
+    {
+       case CMD_RESET:
+       case CMD_STOP:
+       case CMD_START:
+       case CMD_CHANGESTATE:
+       case CMD_PROTSTATUS:
+       case CMD_GETDRIVETYPE:
+       case CMD_GETNUMTRACKS:
+       return 1;
+    }
+    return 0;
+}
+
+static int dev_canquick (struct devstruct *dev, uaecptr request)
+{
+    uae_u32 command = get_word (request + 28);
+    return dev_can_quick (command);
+}
+
+static uae_u32 dev_beginio (void)
+{
+    uae_u32 request = m68k_areg(regs, 1);
+    uae_u8 flags = get_byte (request + 30);
+    int command = get_word (request + 28);
+    struct priv_devstruct *pdev = getpdevstruct (request);
+    struct devstruct *dev = getdevstruct (pdev->unit);
+
+    put_byte (request+8, NT_MESSAGE);
+    if (!dev || !pdev) {
+       put_byte (request + 31, 32);
+       return get_byte (request + 31);
+    }
+    put_byte (request+31, 0);
+    if ((flags & 1) && dev_canquick (dev, request)) {
+       if (dev_do_io (dev, request))
+           write_log ("device %s command %d bug with IO_QUICK\n", getdevname (pdev->type), command);
+       return get_byte (request + 31);
+    } else {
+        add_async_request (dev, request, ASYNC_REQUEST_TEMP, 0);
+        put_byte (request+30, get_byte (request + 30) & ~1);
+       write_comm_pipe_u32 (&dev->requests, request, 1);
+       return 0;
+    }
+}
+
+static void *dev_thread (void *devs)
+{
+    struct devstruct *dev = devs;
+
+    set_thread_priority (2);
+    dev->thread_running = 1;
+    uae_sem_post (&dev->sync_sem);
+    for (;;) {
+       uaecptr request = (uaecptr)read_comm_pipe_u32_blocking (&dev->requests);
+       uae_sem_wait (&change_sem);
+        if (!request) {
+           dev->thread_running = 0;
+           uae_sem_post (&dev->sync_sem);
+           uae_sem_post (&change_sem);
+           return 0;
+       } else if (dev_do_io (dev, request) == 0) {
+            put_byte (request + 30, get_byte (request + 30) & ~1);
+           release_async_request (dev, request);
+            uae_ReplyMsg (request);
+       } else {
+           if (log_scsi)
+               write_log ("async request %08.8X\n", request);
+       }
+       uae_sem_post (&change_sem);
+    }
+    return 0;
+}
+
+static uae_u32 dev_init_2 (int type)
+{
+    uae_u32 base = m68k_dreg (regs,0);
+    if (log_scsi)
+       write_log ("%s init\n", getdevname (type));
+    return base;
+}
+
+static uae_u32 dev_init (void)
+{
+    return dev_init_2 (UAEDEV_SCSI_ID);
+}
+static uae_u32 diskdev_init (void)
+{
+    return dev_init_2 (UAEDEV_DISK_ID);
+}
+
+static uae_u32 dev_abortio (void)
+{
+    uae_u32 request = m68k_areg(regs, 1);
+    struct priv_devstruct *pdev = getpdevstruct (request);
+    struct devstruct *dev;
+
+    if (!pdev) {
+       put_byte (request + 31, 32);
+       return get_byte (request + 31);
+    }
+    dev = getdevstruct (pdev->unit);
+    if (!dev) {
+       put_byte (request + 31, 32);
+       return get_byte (request + 31);
+    }
+    put_byte (request + 31, -2);
+    if (log_scsi)
+       write_log ("abortio %s unit=%d, request=%08.8X\n", getdevname (pdev->type), pdev->unit, request);
+    abort_async (dev, request, -2, 0);
+    return 0;
+}
+
+#define BTL2UNIT(bus, target, lun) (2 * (bus) + (target) / 8) * 100 + (lun) * 10 + (target % 8)
+
+static void dev_reset (void)
+{
+    int i, j;
+    struct devstruct *dev;
+    struct device_info *discsi, discsi2;
+    int unitnum = 0;
+
+    device_func_init (DEVICE_TYPE_SCSI);
+    for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
+       dev = &devst[i];
+       if (dev->opencnt > 0) {
+           for (j = 0; j < MAX_ASYNC_REQUESTS; j++) {
+               uaecptr request;
+               if (request = dev->d_request[i]) 
+                   abort_async (dev, request, 0, 0);
+           }
+           dev->opencnt = 1;
+           sys_command_close (DF_SCSI, dev->unitnum);
+           sys_command_close (DF_IOCTL, dev->unitnum);
+       }
+       memset (dev, 0, sizeof (struct devstruct));
+       dev->unitnum = dev->aunit = -1;
+    }
+    for (i = 0; i < MAX_OPEN_DEVICES; i++)
+       memset (&pdevst[i], 0, sizeof (struct priv_devstruct));
+
+    i = j = 0;
+    while (i < MAX_TOTAL_DEVICES) {
+       dev = &devst[i];
+       discsi = 0;
+       if (sys_command_open (DF_SCSI, j)) {
+           discsi = sys_command_info (DF_SCSI, j, &discsi2);
+           sys_command_close (DF_SCSI, j);
+       }
+        if (discsi) {
+            dev->unitnum = j;
+           dev->allow_scsi = 1;
+           dev->drivetype = discsi->type;
+           memcpy (&dev->di, discsi, sizeof (struct device_info));
+           if (discsi->type == INQ_ROMD)
+               dev->iscd = 1;
+       }
+       i++;
+       j++;
+    }
+    unitnum = 0;
+    for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
+        dev = &devst[i];
+       if (dev->unitnum >= 0 && dev->iscd) {
+           dev->aunit = unitnum;
+           unitnum++;
+       }
+    }
+    if (unitnum == 0)
+       unitnum = 1;
+    for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
+        dev = &devst[i];
+       if (dev->unitnum >= 0) {
+           if (!dev->iscd) {
+               dev->aunit = unitnum;
+               unitnum++;
+           }
+           write_log ("%s = %s:%d\n", dev->di.label, UAEDEV_SCSI, dev->aunit);
+       }
+    }
+}
+
+static uaecptr ROM_scsidev_resname = 0,
+    ROM_scsidev_resid = 0,
+    ROM_scsidev_init = 0;
+
+static uaecptr ROM_diskdev_resname = 0,
+    ROM_diskdev_resid = 0,
+    ROM_diskdev_init = 0;
+
+
+static uaecptr diskdev_startup (uaecptr resaddr)
+{
+    /* Build a struct Resident. This will set up and initialize
+     * the cd.device */
+    if (log_scsi)
+       write_log ("diskdev_startup(0x%x)\n", resaddr);
+    put_word(resaddr + 0x0, 0x4AFC);
+    put_long(resaddr + 0x2, resaddr);
+    put_long(resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */
+    put_word(resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */
+    put_word(resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */
+    put_long(resaddr + 0xE, ROM_diskdev_resname);
+    put_long(resaddr + 0x12, ROM_diskdev_resid);
+    put_long(resaddr + 0x16, ROM_diskdev_init);
+    resaddr += 0x1A;
+    return resaddr;
+}
+
+uaecptr scsidev_startup (uaecptr resaddr)
+{
+    if (!currprefs.scsi)
+       return resaddr;
+    if (log_scsi)
+       write_log ("scsidev_startup(0x%x)\n", resaddr);
+    /* Build a struct Resident. This will set up and initialize
+     * the uaescsi.device */
+    put_word(resaddr + 0x0, 0x4AFC);
+    put_long(resaddr + 0x2, resaddr);
+    put_long(resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */
+    put_word(resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */
+    put_word(resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */
+    put_long(resaddr + 0xE, ROM_scsidev_resname);
+    put_long(resaddr + 0x12, ROM_scsidev_resid);
+    put_long(resaddr + 0x16, ROM_scsidev_init); /* calls scsidev_init */
+    resaddr += 0x1A;
+    return resaddr;
+    return diskdev_startup (resaddr);
+}
+
+static void diskdev_install (void)
+{
+    uae_u32 functable, datatable;
+    uae_u32 initcode, openfunc, closefunc, expungefunc;
+    uae_u32 beginiofunc, abortiofunc;
+
+    if (!currprefs.scsi)
+       return;
+    if (log_scsi)
+       write_log ("diskdev_install(): 0x%x\n", here ());
+
+    ROM_diskdev_resname = ds (UAEDEV_DISK);
+    ROM_diskdev_resid = ds ("UAE disk.device 0.1");
+
+    /* initcode */
+    initcode = here ();
+    calltrap (deftrap (diskdev_init)); dw (RTS);
+    
+    /* Open */
+    openfunc = here ();
+    calltrap (deftrap (diskdev_open)); dw (RTS);
+
+    /* Close */
+    closefunc = here ();
+    calltrap (deftrap (diskdev_close)); dw (RTS);
+
+    /* Expunge */
+    expungefunc = here ();
+    calltrap (deftrap (diskdev_expunge)); dw (RTS);
+
+    /* BeginIO */
+    beginiofunc = here ();
+    calltrap (deftrap (dev_beginio));
+    dw (RTS);
+
+    /* AbortIO */
+    abortiofunc = here ();
+    calltrap (deftrap (dev_abortio)); dw (RTS);
+
+    /* FuncTable */
+    functable = here ();
+    dl (openfunc); /* Open */
+    dl (closefunc); /* Close */
+    dl (expungefunc); /* Expunge */
+    dl (EXPANSION_nullfunc); /* Null */
+    dl (beginiofunc); /* BeginIO */
+    dl (abortiofunc); /* AbortIO */
+    dl (0xFFFFFFFFul); /* end of table */
+
+    /* DataTable */
+    datatable = here ();
+    dw (0xE000); /* INITBYTE */
+    dw (0x0008); /* LN_TYPE */
+    dw (0x0300); /* NT_DEVICE */
+    dw (0xC000); /* INITLONG */
+    dw (0x000A); /* LN_NAME */
+    dl (ROM_diskdev_resname);
+    dw (0xE000); /* INITBYTE */
+    dw (0x000E); /* LIB_FLAGS */
+    dw (0x0600); /* LIBF_SUMUSED | LIBF_CHANGED */
+    dw (0xD000); /* INITWORD */
+    dw (0x0014); /* LIB_VERSION */
+    dw (0x0004); /* 0.4 */
+    dw (0xD000); /* INITWORD */
+    dw (0x0016); /* LIB_REVISION */
+    dw (0x0000); /* end of table already ??? */
+    dw (0xC000); /* INITLONG */
+    dw (0x0018); /* LIB_IDSTRING */
+    dl (ROM_diskdev_resid);
+    dw (0x0000); /* end of table */
+
+    ROM_diskdev_init = here ();
+    dl (0x00000100); /* size of device base */
+    dl (functable);
+    dl (datatable);
+    dl (initcode);
+}
+
+
+void scsidev_install (void)
+{
+    uae_u32 functable, datatable;
+    uae_u32 initcode, openfunc, closefunc, expungefunc;
+    uae_u32 beginiofunc, abortiofunc;
+
+    if (!currprefs.scsi)
+       return;
+    if (log_scsi)
+       write_log ("scsidev_install(): 0x%x\n", here ());
+
+    ROM_scsidev_resname = ds (UAEDEV_SCSI);
+    ROM_scsidev_resid = ds ("UAE scsi.device 0.2");
+
+    /* initcode */
+    initcode = here ();
+    calltrap (deftrap (dev_init)); dw (RTS);
+    
+    /* Open */
+    openfunc = here ();
+    calltrap (deftrap (dev_open)); dw (RTS);
+
+    /* Close */
+    closefunc = here ();
+    calltrap (deftrap (dev_close)); dw (RTS);
+
+    /* Expunge */
+    expungefunc = here ();
+    calltrap (deftrap (dev_expunge)); dw (RTS);
+
+    /* BeginIO */
+    beginiofunc = here ();
+    calltrap (deftrap (dev_beginio));
+    dw (RTS);
+
+    /* AbortIO */
+    abortiofunc = here ();
+    calltrap (deftrap (dev_abortio)); dw (RTS);
+
+    /* FuncTable */
+    functable = here ();
+    dl (openfunc); /* Open */
+    dl (closefunc); /* Close */
+    dl (expungefunc); /* Expunge */
+    dl (EXPANSION_nullfunc); /* Null */
+    dl (beginiofunc); /* BeginIO */
+    dl (abortiofunc); /* AbortIO */
+    dl (0xFFFFFFFFul); /* end of table */
+
+    /* DataTable */
+    datatable = here ();
+    dw (0xE000); /* INITBYTE */
+    dw (0x0008); /* LN_TYPE */
+    dw (0x0300); /* NT_DEVICE */
+    dw (0xC000); /* INITLONG */
+    dw (0x000A); /* LN_NAME */
+    dl (ROM_scsidev_resname);
+    dw (0xE000); /* INITBYTE */
+    dw (0x000E); /* LIB_FLAGS */
+    dw (0x0600); /* LIBF_SUMUSED | LIBF_CHANGED */
+    dw (0xD000); /* INITWORD */
+    dw (0x0014); /* LIB_VERSION */
+    dw (0x0004); /* 0.4 */
+    dw (0xD000); /* INITWORD */
+    dw (0x0016); /* LIB_REVISION */
+    dw (0x0000); /* end of table already ??? */
+    dw (0xC000); /* INITLONG */
+    dw (0x0018); /* LIB_IDSTRING */
+    dl (ROM_scsidev_resid);
+    dw (0x0000); /* end of table */
+
+    ROM_scsidev_init = here ();
+    dl (0x00000100); /* size of device base */
+    dl (functable);
+    dl (datatable);
+    dl (initcode);
+
+    diskdev_install ();
+}
+
+void scsidev_start_threads (void)
+{
+    if (!currprefs.scsi) /* quite useless.. */
+       return;
+    if (log_scsi)
+       write_log ("scsidev_start_threads()\n");
+    uae_sem_init (&change_sem, 0, 1);
+}
+
+void scsidev_reset (void)
+{
+    if (!currprefs.scsi)
+       return;
+    dev_reset ();
+}
\ No newline at end of file
diff --git a/sdl-joystick.c b/sdl-joystick.c
new file mode 100755 (executable)
index 0000000..a01d0ac
--- /dev/null
@@ -0,0 +1,157 @@
+ /* 
+  * UAE - The Un*x Amiga Emulator
+  * 
+  * SDL Joystick code
+  * 
+  * Copyright 1997 Bernd Schmidt
+  * Copyright 1998 Krister Walfridsson
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "memory.h"
+#include "custom.h"
+#include "inputdevice.h"
+#include "SDL.h"
+
+static int nr_joysticks;
+
+struct joyinfo {
+    SDL_Joystick *joy;
+    int axles;
+    int buttons;
+};
+
+static struct joyinfo joys[MAX_INPUT_DEVICES];
+
+static int isjoy (int pcport, int amigaport)
+{
+    if (pcport == 0)
+       return JSEM_ISJOY0 (amigaport, &currprefs);
+    else
+       return JSEM_ISJOY1 (amigaport, &currprefs);
+}
+
+static void read_joy(int nr)
+{
+    int num, i, axes, axis;
+    SDL_Joystick *joy;
+
+    if (currprefs.input_selected_setting == 0) {
+       if (nr >= 2)
+           return;
+       if (isjoy (nr, 0)) {
+           if (JSEM_ISNUMPAD (0, &currprefs) || JSEM_ISCURSOR (0, &currprefs) || JSEM_ISSOMEWHEREELSE (0, &currprefs))
+               return;
+       } else if (isjoy (nr, 1)) {
+           if (JSEM_ISNUMPAD (1, &currprefs) || JSEM_ISCURSOR (1, &currprefs) || JSEM_ISSOMEWHEREELSE (1, &currprefs))
+               return;
+       } else
+           return;
+    }
+    joy = joys[nr].joy;
+    axes = SDL_JoystickNumAxes (joy);
+    for (i = 0; i < axes; i++) {
+       axis = SDL_JoystickGetAxis (joy, i);
+       setjoystickstate (nr, i, axis, 32767);
+    }
+
+    num = SDL_JoystickNumButtons (joy);
+    for (i = 0; i < num; i++) {
+       int bs = SDL_JoystickGetButton (joy, i) ? 1 : 0;
+        setjoybuttonstate (nr, i, bs);
+    }
+}
+
+static int get_joystick_num (void)
+{
+    return nr_joysticks;
+}
+
+static int get_joystick_widget_num (int joy)
+{
+    return joys[joy].axles + joys[joy].buttons;
+}
+
+static int get_joystick_widget_type (int joy, int num, char *name)
+{
+    if (num >= joys[joy].axles && num < joys[joy].axles + joys[joy].buttons) {
+       if (name)
+           sprintf (name, "Button %d", num + 1 - joys[joy].axles);
+       return IDEV_WIDGET_BUTTON;
+    } else if (num < joys[joy].axles) {
+       if (name)
+           sprintf (name, "Axis %d", num + 1);
+       return IDEV_WIDGET_AXIS;
+    }
+    return IDEV_WIDGET_NONE;
+}
+
+static int get_joystick_widget_first (int joy, int type)
+{
+    switch (type)
+    {
+       case IDEV_WIDGET_BUTTON:
+       return joys[joy].axles;
+       case IDEV_WIDGET_AXIS:
+       return 0;
+    }
+    return -1;
+}
+
+static char *get_joystick_name (int joy)
+{
+    static char name[100];
+    sprintf (name, "%d: %s", joy + 1, SDL_JoystickName (joy));
+    return name;
+}
+
+static void read_joysticks (void)
+{
+    int i;
+    SDL_JoystickUpdate ();
+    for (i = 0; i < get_joystick_num(); i++)
+       read_joy (i);
+}
+
+static int init_joysticks (void)
+{
+    int i;
+    nr_joysticks = SDL_NumJoysticks ();
+    if (nr_joysticks > MAX_INPUT_DEVICES)
+       nr_joysticks = MAX_INPUT_DEVICES;
+    for (i = 0; i < get_joystick_num(); i++) {
+       joys[i].joy = SDL_JoystickOpen (i);
+       joys[i].axles = SDL_JoystickNumAxes (joys[i].joy);
+       joys[i].buttons = SDL_JoystickNumButtons (joys[i].joy);
+    }
+    return 1;
+}
+
+static void close_joysticks (void)
+{
+    int i;
+    for (i = 0; i < get_joystick_num(); i++) {
+       SDL_JoystickClose (joys[i].joy);
+       joys[i].joy = 0;
+    }
+}
+
+static int acquire_joy (int num, int flags)
+{
+    return 1;
+}
+
+static void unacquire_joy (int num)
+{
+}
+
+struct inputdevice_functions inputdevicefunc_joystick = {
+    init_joysticks, close_joysticks, acquire_joy, unacquire_joy,
+    read_joysticks, get_joystick_num, get_joystick_name,
+    get_joystick_widget_num, get_joystick_widget_type,
+    get_joystick_widget_first
+};
diff --git a/serial.c b/serial.c
new file mode 100755 (executable)
index 0000000..ad3fed0
--- /dev/null
+++ b/serial.c
@@ -0,0 +1,413 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  *  Serial Line Emulation
+  *
+  * (c) 1996, 1997 Stefan Reinauer <stepan@linux.de>
+  * (c) 1997 Christian Schmitt <schmitt@freiburg.linux.de>
+  *
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "uae.h"
+#include "memory.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "cia.h"
+
+#undef POSIX_SERIAL
+/* Some more or less good way to determine whether we can safely compile in
+ * the serial stuff. I'm certain it breaks compilation on some systems. */
+#if defined HAVE_SYS_TERMIOS_H && defined HAVE_POSIX_OPT_H && defined HAVE_SYS_IOCTL_H && defined HAVE_TCGETATTR
+#define POSIX_SERIAL
+#endif
+
+#ifdef POSIX_SERIAL
+#include <termios.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#endif
+
+#if !defined B300 || !defined B1200 || !defined B2400 || !defined B4800 || !defined B9600
+#undef POSIX_SERIAL
+#endif
+#if !defined B19200 || !defined B57600 || !defined B115200 || !defined B230400
+#undef POSIX_SERIAL
+#endif
+
+#ifndef O_NONBLOCK
+#define O_NONBLOCK O_NDELAY
+#endif
+
+#define SERIALDEBUG 1 /* 0, 1, 2 3 */
+#define MODEMTEST   0 /* 0 or 1 */
+
+void serial_open (void);
+void serial_close (void);
+void serial_init (void);
+void serial_exit (void);
+
+void serial_dtr_on (void);
+void serial_dtr_off (void);
+
+void serial_flush_buffer (void);
+static int serial_read (char *buffer);
+
+int serial_readstatus (void);
+uae_u16 serial_writestatus (int, int);
+
+uae_u16 SERDATR (void);
+
+int  SERDATS (void);
+void  SERPER (uae_u16 w);
+void  SERDAT (uae_u16 w);
+
+static char inbuf[1024], outbuf[1024];
+static int inptr, inlast, outlast;
+
+int waitqueue=0,
+    carrier=0,
+    serdev=0,
+    dsr=0,
+    dtr=0,
+    isbaeh=0,
+    doreadser=0,
+    serstat=-1;
+
+int sd = -1;
+
+#ifdef POSIX_SERIAL
+    struct termios tios;
+#endif
+
+uae_u16 serper=0,serdat;
+
+void SERPER (uae_u16 w)
+{
+    int baud=0, pspeed;
+
+    if (!currprefs.use_serial)
+       return;
+
+#if defined POSIX_SERIAL
+    if (serper == w)  /* don't set baudrate if it's already ok */
+       return;
+    serper=w;
+
+    if (w&0x8000)
+       write_log ("SERPER: 9bit transmission not implemented.\n");
+
+    switch (w & 0x7fff) {
+     /* These values should be calculated by the current
+      * color clock value (NTSC/PAL). But this solution is
+      * easy and it works.
+      */
+
+     case 0x2e9b:
+     case 0x2e14: baud=300; pspeed=B300; break;
+     case 0x170a:
+     case 0x0b85: baud=1200; pspeed=B1200; break;
+     case 0x05c2:
+     case 0x05b9: baud=2400; pspeed=B2400; break;
+     case 0x02e9:
+     case 0x02e1: baud=4800; pspeed=B4800; break;
+     case 0x0174:
+     case 0x0170: baud=9600; pspeed=B9600; break;
+     case 0x00b9:
+     case 0x00b8: baud=19200; pspeed=B19200; break;
+     case 0x005c:
+     case 0x005d: baud=38400; pspeed=B38400; break;
+     case 0x003d: baud=57600; pspeed=B57600; break;
+     case 0x001e: baud=115200; pspeed=B115200; break;
+     case 0x000f: baud=230400; pspeed=B230400; break;
+     default:
+       write_log ("SERPER: unsupported baudrate (0x%04x) %d\n",w&0x7fff,
+                (unsigned int)(3579546.471/(double)((w&0x7fff)+1)));  return;
+    }
+
+    /* Only access hardware when we own it */
+    if (serdev == 1) {
+       if (tcgetattr (sd, &tios) < 0) {
+           write_log ("SERPER: TCGETATTR failed\n");
+           return;
+       }
+
+       if (cfsetispeed (&tios, pspeed) < 0) {    /* set serial input speed */
+           write_log ("SERPER: CFSETISPEED (%d bps) failed\n", baud);
+           return;
+       }
+       if (cfsetospeed (&tios, pspeed) < 0) {    /* set serial output speed */
+           write_log ("SERPER: CFSETOSPEED (%d bps) failed\n", baud);
+           return;
+       }
+
+       if (tcsetattr (sd, TCSADRAIN, &tios) < 0) {
+           write_log ("SERPER: TCSETATTR failed\n");
+           return;
+       }
+    }
+#endif
+
+#if SERIALDEBUG > 0
+    if (serdev == 1)
+       write_log ("SERPER: baudrate set to %d bit/sec\n", baud);
+#endif
+}
+
+/* Not (fully) implemented yet:
+ *
+ *  -  Something's wrong with the Interrupts.
+ *     (NComm works, TERM does not. TERM switches to a
+ *     blind mode after a connect and wait's for the end
+ *     of an asynchronous read before switching blind
+ *     mode off again. It never gets there on UAE :-< )
+ *
+ *  -  RTS/CTS handshake, this is not really neccessary,
+ *     because you can use RTS/CTS "outside" without
+ *     passing it through to the emulated Amiga
+ *
+ *  -  ADCON-Register ($9e write, $10 read) Bit 11 (UARTBRK)
+ *     (see "Amiga Intern", pg 246)
+ */
+
+void SERDAT (uae_u16 w)
+{
+    unsigned char z;
+
+    if (!currprefs.use_serial)
+       return;
+
+    z = (unsigned char)(w&0xff);
+
+    if (currprefs.serial_demand && !dtr) {
+       if (!isbaeh) {
+           write_log("SERDAT: Baeh.. Your software needs SERIAL_ALWAYS to work properly.\n");
+           isbaeh=1;
+       }
+       return;
+    } else {
+       outbuf[outlast++] = z;
+       if (outlast == sizeof outbuf)
+           serial_flush_buffer();
+    }
+
+#if SERIALDEBUG > 2
+    write_log ("SERDAT: wrote 0x%04x\n", w);
+#endif
+
+    serdat|=0x2000; /* Set TBE in the SERDATR ... */
+    intreq|=1;      /* ... and in INTREQ register */
+    return;
+}
+
+uae_u16 SERDATR (void)
+{
+    if (!currprefs.use_serial)
+       return 0;
+#if SERIALDEBUG > 2
+    write_log ("SERDATR: read 0x%04x\n", serdat);
+#endif
+    waitqueue = 0;
+    return serdat;
+}
+
+int SERDATS (void)
+{
+    unsigned char z;
+
+    if (!serdev)           /* || (serdat&0x4000)) */
+       return 0;
+
+    if (waitqueue == 1) {
+       intreq |= 0x0800;
+       return 1;
+    }
+
+    if ((serial_read ((char *)&z)) == 1) {
+       waitqueue = 1;
+       serdat = 0x4100; /* RBF and STP set! */
+       serdat |= ((unsigned int)z) & 0xff;
+       intreq |= 0x0800; /* Set RBF flag (Receive Buffer full) */
+
+#if SERIALDEBUG > 1
+       write_log ("SERDATS: received 0x%02x --> serdat==0x%04x\n",
+                (unsigned int)z, (unsigned int)serdat);
+#endif
+       return 1;
+    }
+    return 0;
+}
+
+void serial_dtr_on(void)
+{
+#if SERIALDEBUG > 0
+    write_log ("DTR on.\n");
+#endif
+    dtr=1;
+
+    if (currprefs.serial_demand)
+       serial_open ();
+}
+
+void serial_dtr_off(void)
+{
+#if SERIALDEBUG > 0
+    write_log ("DTR off.\n");
+#endif
+    dtr=0;
+    if (currprefs.serial_demand)
+       serial_close ();
+}
+
+static int serial_read (char *buffer)
+{
+    if (inptr < inlast) {
+       *buffer = inbuf[inptr++];
+       return 1;
+    }
+
+    if (serdev == 1) {
+       inlast = read (sd, inbuf, sizeof inbuf);
+       inptr = 0;
+       if (inptr < inlast) {
+           *buffer = inbuf[inptr++];
+           return 1;
+       }
+    }
+
+    return 0;
+}
+
+void serial_flush_buffer(void)
+{
+    if (serdev == 1) {
+       if (outlast) {
+           if (sd != 0) {
+               write (sd, outbuf, outlast);
+           }
+       }
+       outlast = 0;
+    } else {
+      outlast = 0;
+      inptr = 0;
+      inlast = 0;
+    }
+}
+
+int serial_readstatus(void)
+{
+    int status = 0;
+
+#ifdef POSIX_SERIAL
+    ioctl (sd, TIOCMGET, &status);
+
+    if (status & TIOCM_CAR) {
+       if (!carrier) {
+           ciabpra |= 0x20; /* Push up Carrier Detect line */
+           carrier = 1;
+#if SERIALDEBUG > 0
+           write_log ("Carrier detect.\n");
+#endif
+       }
+    } else {
+       if (carrier) {
+           ciabpra &= ~0x20;
+           carrier = 0;
+#if SERIALDEBUG > 0
+           write_log ("Carrier lost.\n");
+#endif
+       }
+    }
+
+    if (status & TIOCM_DSR) {
+       if (!dsr) {
+           ciabpra |= 0x08; /* DSR ON */
+           dsr = 1;
+       }
+    } else {
+       if (dsr) {
+           ciabpra &= ~0x08;
+           dsr = 0;
+       }
+    }
+#endif
+    return status;
+}
+
+uae_u16 serial_writestatus (int old, int nw)
+{
+    if ((old & 0x80) == 0x80 && (nw & 0x80) == 0x00)
+       serial_dtr_on();
+    if ((old & 0x80) == 0x00 && (nw & 0x80) == 0x80)
+       serial_dtr_off();
+
+    if ((old & 0x40) != (nw & 0x40))
+       write_log ("RTS %s.\n", ((nw & 0x40) == 0x40) ? "set" : "cleared");
+
+    if ((old & 0x10) != (nw & 0x10))
+       write_log ("CTS %s.\n", ((nw & 0x10) == 0x10) ? "set" : "cleared");
+
+    return nw; /* This value could also be changed here */
+}
+
+void serial_open(void)
+{
+    if (serdev == 1)
+       return;
+
+    if ((sd = open (currprefs.sername, O_RDWR|O_NONBLOCK|O_BINARY, 0)) < 0) {
+       write_log ("Error: Could not open Device %s\n", currprefs.sername);
+       return;
+    }
+
+    serdev = 1;
+
+#ifdef POSIX_SERIAL
+    if (tcgetattr (sd, &tios) < 0) {           /* Initialize Serial tty */
+       write_log ("Serial: TCGETATTR failed\n");
+       return;
+    }
+    cfmakeraw (&tios);
+
+#ifndef MODEMTEST
+    tios.c_cflag &= ~CRTSCTS; /* Disable RTS/CTS */
+#else
+    tios.c_cflag |= CRTSCTS; /* Enabled for testing modems */
+#endif
+
+    if (tcsetattr (sd, TCSADRAIN, &tios) < 0) {
+       write_log ("Serial: TCSETATTR failed\n");
+       return;
+    }
+#endif
+}
+
+void serial_close (void)
+{
+    if (sd >= 0)
+       close (sd);
+    serdev = 0;
+}
+
+void serial_init (void)
+{
+    if (!currprefs.use_serial)
+       return;
+
+    if (!currprefs.serial_demand)
+       serial_open ();
+
+    serdat = 0x2000;
+    return;
+}
+
+void serial_exit (void)
+{
+    serial_close ();   /* serial_close can always be called because it */
+    dtr = 0;           /* just closes *opened* filehandles which is ok */
+    return;            /* when exiting.                                */
+}
diff --git a/svga.c b/svga.c
new file mode 100755 (executable)
index 0000000..df5dea6
--- /dev/null
+++ b/svga.c
@@ -0,0 +1,945 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * SVGAlib interface.
+  *
+  * (c) 1995 Bernd Schmidt
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <signal.h>
+#include <vga.h>
+#include <vgamouse.h>
+#include <vgakeyboard.h>
+
+#include "config.h"
+#include "options.h"
+#include "threaddep/thread.h"
+#include "uae.h"
+#include "memory.h"
+#include "keyboard.h"
+#include "xwin.h"
+#include "custom.h"
+#include "drawing.h"
+#include "keybuf.h"
+#include "newcpu.h"
+#include "tui.h"
+#include "gui.h"
+#include "picasso96.h"
+
+#define SCODE_CB_UP    103     /* Cursor key block. */
+#define SCODE_CB_LEFT  105
+#define SCODE_CB_RIGHT 106
+#define SCODE_CB_DOWN  108
+
+#define SCODE_INSERT   110
+#define SCODE_HOME     102
+#define SCODE_PGUP     104
+#define SCODE_DELETE   111
+#define SCODE_END      107
+#define SCODE_PGDN     109
+
+#define SCODE_PRTSCR   99
+#define SCODE_SLOCK    70
+#define SCODE_BREAK    119
+
+#define SCODE_NUMLOCK  69
+
+#define SCODE_KEYPAD0  82
+#define SCODE_KEYPAD1  79
+#define SCODE_KEYPAD2  80
+#define SCODE_KEYPAD3  81
+#define SCODE_KEYPAD4  75
+#define SCODE_KEYPAD5  76
+#define SCODE_KEYPAD6  77
+#define SCODE_KEYPAD7  71
+#define SCODE_KEYPAD8  72
+#define SCODE_KEYPAD9  73
+#define SCODE_KEYPADRET        96
+#define SCODE_KEYPADADD        78
+#define SCODE_KEYPADSUB        74
+#define SCODE_KEYPADMUL        55
+#define SCODE_KEYPADDIV        98
+#define SCODE_KEYPADDOT 83
+
+#define SCODE_Q                16
+#define SCODE_W                17
+#define SCODE_E                18
+#define SCODE_R                19
+#define SCODE_T                20
+#define SCODE_Y                21
+#define SCODE_U                22
+#define SCODE_I                23
+#define SCODE_O                24
+#define SCODE_P                25
+
+#define SCODE_A                30
+#define SCODE_S                31
+#define SCODE_D                32
+#define SCODE_F                33
+#define SCODE_G                34
+#define SCODE_H                35
+#define SCODE_J                36
+#define SCODE_K                37
+#define SCODE_L                38
+
+#define SCODE_Z                44
+#define SCODE_X                45
+#define SCODE_C                46
+#define SCODE_V                47
+#define SCODE_B                48
+#define SCODE_N                49
+#define SCODE_M                50
+
+#define SCODE_ESCAPE   1
+#define SCODE_ENTER    28
+#define SCODE_RCONTROL 97
+#define SCODE_CONTROL  97
+#define SCODE_RALT     100
+#define SCODE_LCONTROL 29
+#define SCODE_LALT     56
+#define SCODE_SPACE    57
+
+#define SCODE_F1       59
+#define SCODE_F2       60
+#define SCODE_F3       61
+#define SCODE_F4       62
+#define SCODE_F5       63
+#define SCODE_F6       64
+#define SCODE_F7       65
+#define SCODE_F8       66
+#define SCODE_F9       67
+#define SCODE_F10      68
+#define SCODE_F11      87
+#define SCODE_F12      88
+
+#define SCODE_0                11
+#define SCODE_1                2
+#define SCODE_2                3
+#define SCODE_3                4
+#define SCODE_4                5
+#define SCODE_5                6
+#define SCODE_6                7
+#define SCODE_7                8
+#define SCODE_8                9
+#define SCODE_9        10
+
+#define SCODE_LSHIFT   42
+#define SCODE_RSHIFT   54
+#define SCODE_TAB      15
+
+#define SCODE_BS       14
+
+#define SCODE_asciicircum      41
+
+#define SCODE_bracketleft      26
+#define SCODE_bracketright     27
+#define SCODE_comma    51
+#define SCODE_period   52
+#define SCODE_slash    53
+#define SCODE_semicolon        39
+#define SCODE_grave    40
+#define SCODE_minus    12
+#define SCODE_equal    13
+#define SCODE_numbersign       43
+#define SCODE_ltgt     86
+
+#define SCODE_LWIN95 125
+#define SCODE_RWIN95 126
+#define SCODE_MWIN95 127
+
+void setup_brkhandler(void)
+{
+}
+
+static int bitdepth, bit_unit, using_linear, vgamode, current_vgamode, gui_requested;
+static vga_modeinfo modeinfo;
+static char *linear_mem = NULL;
+static int need_dither;
+static int screen_is_picasso;
+static int picasso_vgamode = -1;
+static char picasso_invalid_lines[1200];
+
+static uae_u8 dither_buf[1000]; /* I hate having to think about array bounds */
+
+#define MAX_SCREEN_MODES 9
+
+static int x_size_table[MAX_SCREEN_MODES] = { 320, 320, 320, 640, 640, 800, 1024, 1152, 1280 };
+static int y_size_table[MAX_SCREEN_MODES] = { 200, 240, 400, 350, 480, 600, 768, 864, 1024 };
+
+static int vga_mode_table[MAX_SCREEN_MODES][MAX_COLOR_MODES+1] =
+ { { G320x200x256, G320x200x32K, G320x200x64K, G320x200x256, G320x200x16, G320x200x16M32 },
+   { G320x240x256, -1, -1, G320x240x256, -1, -1 },
+   { G320x400x256, -1, -1, G320x400x256, -1, -1 },
+   { -1, -1, -1, -1, G640x350x16, -1 },
+   { G640x480x256, G640x480x32K, G640x480x64K, G640x480x256, G640x480x16, G640x480x16M32 },
+   { G800x600x256, G800x600x32K, G800x600x64K, G800x600x256, G800x600x16, G800x600x16M32 },
+   { G1024x768x256, G1024x768x32K, G1024x768x64K, G1024x768x256, G1024x768x16, G1024x768x16M32 },
+   { G1152x864x256, G1152x864x32K, G1152x864x64K, G1152x864x256, G1152x864x16, G1152x864x16M32 },
+   { G1280x1024x256, G1280x1024x32K, G1280x1024x64K, G1280x1024x256, G1280x1024x16, G1280x1024x16M32 }
+ };
+
+static int mode_bitdepth[MAX_COLOR_MODES+1][3] =
+  { { 8, 8, 0 }, { 15, 16, 0 }, { 16, 16, 0 }, { 8, 8, 1 }, { 4, 8, 1 }, { 24, 32, 0 } };
+
+struct bstring *video_mode_menu = NULL;
+
+void flush_line(int y)
+{
+    int target_y = y;
+    char *addr;
+
+    if (linear_mem != NULL && !need_dither)
+       return;
+
+    addr = gfxvidinfo.linemem;
+    if (addr == NULL)
+       addr = gfxvidinfo.bufmem + y*gfxvidinfo.rowbytes;
+
+    if (linear_mem == NULL) {
+       if (target_y < modeinfo.height && target_y >= 0) {
+           if (need_dither) {
+               DitherLine (dither_buf, (uae_u16 *)addr, 0, y, gfxvidinfo.width, bit_unit);
+               addr = dither_buf;
+           }
+           vga_drawscanline(target_y, addr);
+       }
+    } else {
+       if (need_dither && target_y >= 0) {
+           DitherLine (linear_mem + modeinfo.linewidth * target_y, (uae_u16 *)addr, 0, y,
+                       gfxvidinfo.width, bit_unit);
+       }
+    }
+}
+
+void flush_block (int a, int b)
+{
+    abort();
+}
+
+void flush_screen (int a, int b)
+{
+}
+
+static int colors_allocated;
+static long palette_entries[256][3];
+
+static void restore_vga_colors (void)
+{
+    int i;
+    if (gfxvidinfo.pixbytes != 1)
+       return;
+    for (i = 0; i < 256; i++)
+       vga_setpalette (i, palette_entries[i][0], palette_entries[i][1], palette_entries[i][2]);
+}
+
+static int get_color (int r, int g, int b, xcolnr *cnp)
+{
+    if (colors_allocated == 256)
+       return -1;
+    *cnp = colors_allocated;
+    palette_entries[colors_allocated][0] = doMask (r, 6, 0);
+    palette_entries[colors_allocated][1] = doMask (g, 6, 0);
+    palette_entries[colors_allocated][2] = doMask (b, 6, 0);
+    vga_setpalette(colors_allocated, doMask (r, 6, 0), doMask (g, 6, 0), doMask (b, 6, 0));
+    colors_allocated++;
+    return 1;
+}
+
+static void init_colors (void)
+{
+    int i;
+    if (need_dither) {
+       setup_dither (bitdepth, get_color);
+    } else {
+       int rw = 5, gw = 5, bw = 5;
+       colors_allocated = 0;
+       if (currprefs.color_mode == 2) gw = 6;
+
+       switch (gfxvidinfo.pixbytes) {
+        case 4:
+           alloc_colors64k (8, 8, 8, 16, 8, 0);
+           break;
+        case 2:
+           alloc_colors64k (rw, gw, bw, gw+bw, bw, 0);
+           break;
+        case 1:
+           alloc_colors256 (get_color);
+           break;
+        default:
+           abort();
+       }
+    }
+    switch (gfxvidinfo.pixbytes) {
+     case 2:
+       for (i = 0; i < 4096; i++)
+           xcolors[i] = xcolors[i] * 0x00010001;
+       gfxvidinfo.can_double = 1;
+       break;
+     case 1:
+       for (i = 0; i < 4096; i++)
+           xcolors[i] = xcolors[i] * 0x01010101;
+       gfxvidinfo.can_double = 1;
+       break;
+     default:
+       gfxvidinfo.can_double = 0;
+       break;
+    }
+}
+
+static int keystate[256];
+
+static int scancode2amiga (int scancode)
+{
+    switch (scancode) {
+     case SCODE_A: return AK_A;
+     case SCODE_B: return AK_B;
+     case SCODE_C: return AK_C;
+     case SCODE_D: return AK_D;
+     case SCODE_E: return AK_E;
+     case SCODE_F: return AK_F;
+     case SCODE_G: return AK_G;
+     case SCODE_H: return AK_H;
+     case SCODE_I: return AK_I;
+     case SCODE_J: return AK_J;
+     case SCODE_K: return AK_K;
+     case SCODE_L: return AK_L;
+     case SCODE_M: return AK_M;
+     case SCODE_N: return AK_N;
+     case SCODE_O: return AK_O;
+     case SCODE_P: return AK_P;
+     case SCODE_Q: return AK_Q;
+     case SCODE_R: return AK_R;
+     case SCODE_S: return AK_S;
+     case SCODE_T: return AK_T;
+     case SCODE_U: return AK_U;
+     case SCODE_V: return AK_V;
+     case SCODE_W: return AK_W;
+     case SCODE_X: return AK_X;
+     case SCODE_Y: return AK_Y;
+     case SCODE_Z: return AK_Z;
+
+     case SCODE_0: return AK_0;
+     case SCODE_1: return AK_1;
+     case SCODE_2: return AK_2;
+     case SCODE_3: return AK_3;
+     case SCODE_4: return AK_4;
+     case SCODE_5: return AK_5;
+     case SCODE_6: return AK_6;
+     case SCODE_7: return AK_7;
+     case SCODE_8: return AK_8;
+     case SCODE_9: return AK_9;
+
+     case SCODE_KEYPAD0: return AK_NP0;
+     case SCODE_KEYPAD1: return AK_NP1;
+     case SCODE_KEYPAD2: return AK_NP2;
+     case SCODE_KEYPAD3: return AK_NP3;
+     case SCODE_KEYPAD4: return AK_NP4;
+     case SCODE_KEYPAD5: return AK_NP5;
+     case SCODE_KEYPAD6: return AK_NP6;
+     case SCODE_KEYPAD7: return AK_NP7;
+     case SCODE_KEYPAD8: return AK_NP8;
+     case SCODE_KEYPAD9: return AK_NP9;
+
+     case SCODE_KEYPADADD: return AK_NPADD;
+     case SCODE_KEYPADSUB: return AK_NPSUB;
+     case SCODE_KEYPADMUL: return AK_NPMUL;
+     case SCODE_KEYPADDIV: return AK_NPDIV;
+     case SCODE_KEYPADRET: return AK_ENT;
+     case SCODE_KEYPADDOT: return AK_NPDEL;
+
+     case SCODE_F1: return AK_F1;
+     case SCODE_F2: return AK_F2;
+     case SCODE_F3: return AK_F3;
+     case SCODE_F4: return AK_F4;
+     case SCODE_F5: return AK_F5;
+     case SCODE_F6: return AK_F6;
+     case SCODE_F7: return AK_F7;
+     case SCODE_F8: return AK_F8;
+     case SCODE_F9: return AK_F9;
+     case SCODE_F10: return AK_F10;
+
+     case SCODE_BS: return AK_BS;
+     case SCODE_LCONTROL: return AK_CTRL;
+     case SCODE_RCONTROL: return AK_RCTRL;
+     case SCODE_TAB: return AK_TAB;
+     case SCODE_LALT: return AK_LALT;
+     case SCODE_RALT: return AK_RALT;
+     case SCODE_ENTER: return AK_RET;
+     case SCODE_SPACE: return AK_SPC;
+     case SCODE_LSHIFT: return AK_LSH;
+     case SCODE_RSHIFT: return AK_RSH;
+     case SCODE_ESCAPE: return AK_ESC;
+
+     case SCODE_INSERT: return AK_HELP;
+     case SCODE_END: return AK_NPRPAREN;
+     case SCODE_HOME: return AK_NPLPAREN;
+
+     case SCODE_DELETE: return AK_DEL;
+     case SCODE_CB_UP: return AK_UP;
+     case SCODE_CB_DOWN: return AK_DN;
+     case SCODE_CB_LEFT: return AK_LF;
+     case SCODE_CB_RIGHT: return AK_RT;
+
+     case SCODE_PRTSCR: return AK_BACKSLASH;
+     case SCODE_asciicircum: return AK_BACKQUOTE;
+     case SCODE_bracketleft: return AK_LBRACKET;
+     case SCODE_bracketright: return AK_RBRACKET;
+     case SCODE_comma: return AK_COMMA;
+     case SCODE_period: return AK_PERIOD;
+     case SCODE_slash: return AK_SLASH;
+     case SCODE_semicolon: return AK_SEMICOLON;
+     case SCODE_grave: return AK_QUOTE;
+     case SCODE_minus: return AK_MINUS;
+     case SCODE_equal: return AK_EQUAL;
+
+       /* This one turns off screen updates. */
+     case SCODE_SLOCK: return AK_inhibit;
+
+     case SCODE_PGUP: case SCODE_RWIN95: return AK_RAMI;
+     case SCODE_PGDN: case SCODE_LWIN95: return AK_LAMI;
+
+/*#ifdef KBD_LANG_DE*/
+     case SCODE_numbersign: return AK_NUMBERSIGN;
+     case SCODE_ltgt: return AK_LTGT;
+/*#endif*/
+    }
+    return -1;
+}
+
+static void my_kbd_handler (int scancode, int newstate)
+{
+    int akey = scancode2amiga (scancode);
+
+    assert (scancode >= 0 && scancode < 0x100);
+    if (scancode == SCODE_F12) {
+       uae_quit ();
+    } else if (scancode == SCODE_F11) {
+       gui_requested = 1;
+    }
+    if (keystate[scancode] == newstate)
+       return;
+
+    keystate[scancode] = newstate;
+
+    if (akey == -1)
+       return;
+
+    if (newstate == KEY_EVENTPRESS) {
+       if (akey == AK_inhibit)
+           toggle_inhibit_frame (0);
+       else
+           record_key (akey << 1);
+    } else
+       record_key ((akey << 1) | 1);
+
+    /* "Affengriff" */
+    if ((keystate[AK_CTRL] || keystate[AK_RCTRL]) && keystate[AK_LAMI] && keystate[AK_RAMI])
+       uae_reset ();
+}
+
+static void leave_graphics_mode (void)
+{
+    keyboard_close ();
+    mouse_close ();
+    sleep (1); /* Maybe this will fix the "screen full of garbage" problem */
+    current_vgamode = TEXT;
+    vga_setmode (TEXT);
+}
+
+static int post_enter_graphics (void)
+{
+    vga_setmousesupport (1);
+    mouse_init("/dev/mouse", vga_getmousetype (), 10);
+    if (keyboard_init() != 0) {
+       leave_graphics_mode ();
+       write_log ("Are you sure you have a keyboard??\n");
+       return 0;
+    }
+    keyboard_seteventhandler (my_kbd_handler);
+    keyboard_translatekeys (DONT_CATCH_CTRLC);
+
+    mouse_setxrange (-1000, 1000);
+    mouse_setyrange (-1000, 1000);
+    mouse_setposition (0, 0);
+
+    return 1;
+}
+
+static int enter_graphics_mode (int which)
+{
+    int oldmode = current_vgamode;
+    vga_setmode (TEXT);
+    if (vga_setmode (which) < 0) {
+       sleep(1);
+       vga_setmode (TEXT);
+       write_log ("SVGAlib doesn't like my video mode (%d). Giving up.\n", which);
+       return 0;
+    }
+    current_vgamode = which;
+
+    linear_mem = 0;
+    if ((modeinfo.flags & CAPABLE_LINEAR) && ! currprefs.svga_no_linear) {
+       int val = vga_setlinearaddressing ();
+       int new_ul = val != -1 ? !need_dither : 0;
+       if (using_linear == -1)
+           using_linear = new_ul;
+       else
+           if (using_linear != new_ul) {
+               leave_graphics_mode ();
+               write_log ("SVGAlib feeling not sure about linear modes???\n");
+               abort ();
+           }
+       if (val != -1) {
+           linear_mem = (char *)vga_getgraphmem ();
+           write_log ("Using linear addressing: %p.\n", linear_mem);
+       }
+    }
+
+    return post_enter_graphics ();
+}
+
+static int enter_graphics_mode_picasso (int which)
+{
+    int oldmode = current_vgamode;
+    if (which == oldmode)
+       return 1;
+
+    vga_setmode (TEXT);
+    if (vga_setmode (which) < 0) {
+       sleep (1);
+       vga_setmode (TEXT);
+       write_log ("SVGAlib doesn't like my video mode (%d). Giving up.\n", which);
+       exit (1);
+    }
+    current_vgamode = which;
+
+    linear_mem = 0;
+    if ((modeinfo.flags & CAPABLE_LINEAR) && ! currprefs.svga_no_linear) {
+       int val = vga_setlinearaddressing ();
+       if (val != -1) {
+           linear_mem = (char *)vga_getgraphmem ();
+           write_log ("Using linear addressing: %p.\n", linear_mem);
+       }
+    }
+
+    keyboard_close ();
+    mouse_close ();
+    return post_enter_graphics ();
+}
+
+int graphics_setup (void)
+{
+    int i,j, count = 1;
+
+    vga_init();
+
+    current_vgamode = TEXT;
+
+    for (i = 0; i < MAX_SCREEN_MODES; i++) {
+       /* Ignore the larger modes which only make sense for Picasso screens.  */
+       if (x_size_table[i] > 800 || y_size_table[i] > 600)
+           continue;
+
+       for (j = 0; j < MAX_COLOR_MODES+1; j++) {
+           /* Delete modes which are not available on this card.  */
+           if (!vga_hasmode (vga_mode_table[i][j])) {
+               vga_mode_table[i][j] = -1;
+           }
+
+           if (vga_mode_table[i][j] != -1)
+               count++;
+       }
+    }
+
+    video_mode_menu = (struct bstring *)malloc (sizeof (struct bstring)*count);
+    memset (video_mode_menu, 0, sizeof (struct bstring)*count);
+    count = 0;
+
+    for (i = 0; i < MAX_SCREEN_MODES; i++) {
+       /* Ignore the larger modes which only make sense for Picasso screens.  */
+       if (x_size_table[i] > 800 || y_size_table[i] > 600)
+           continue;
+
+       for (j = 0; j < MAX_COLOR_MODES+1; j++) {
+           char buf[80];
+           if (vga_mode_table[i][j] == -1)
+               continue;
+
+           sprintf (buf, "%3dx%d, %s", x_size_table[i], y_size_table[i],
+                    colormodes[j]);
+           video_mode_menu[count].val = -1;
+           video_mode_menu[count++].data = strdup(buf);
+       }
+    }
+    video_mode_menu[count].val = -3;
+    video_mode_menu[count++].data = NULL;
+    return 1;
+}
+
+void vidmode_menu_selected(int m)
+{
+    int i, j;
+    for (i = 0; i < MAX_SCREEN_MODES; i++) {
+       /* Ignore the larger modes which only make sense for Picasso screens.  */
+       if (x_size_table[i] > 800 || y_size_table[i] > 600)
+           continue;
+       for (j = 0; j < MAX_COLOR_MODES+1; j++) {
+           if (vga_mode_table[i][j] != -1)
+               if (!m--)
+                   goto found;
+
+       }
+    }
+    abort();
+
+    found:
+    currprefs.gfx_width = x_size_table[i];
+    currprefs.gfx_height = y_size_table[i];
+    currprefs.color_mode = j;
+}
+
+static int select_mode_from_prefs (void)
+{
+    int mode_nr0, mode_nr;
+    int i;
+
+    if (currprefs.color_mode > 5)
+       write_log ("Bad color mode selected. Using default.\n"), currprefs.color_mode = 0;
+
+    mode_nr0 = 0;
+    for (i = 1; i < MAX_SCREEN_MODES; i++) {
+       if (x_size_table[mode_nr0] >= currprefs.gfx_width)
+           break;
+       if (x_size_table[i-1] != x_size_table[i])
+           mode_nr0 = i;
+    }
+    mode_nr = -1;
+    for (i = mode_nr0; i < MAX_SCREEN_MODES && x_size_table[i] == x_size_table[mode_nr0]; i++) {
+       if ((y_size_table[i] >= currprefs.gfx_height
+            || i + 1 == MAX_SCREEN_MODES
+            || x_size_table[i+1] != x_size_table[mode_nr0])
+           && vga_mode_table[i][currprefs.color_mode] != -1)
+       {
+           mode_nr = i;
+           break;
+       }
+    }
+    if (mode_nr == -1) {
+       write_log ("Sorry, this combination of color and video mode is not supported.\n");
+       return 0;
+    }
+    vgamode = vga_mode_table[mode_nr][currprefs.color_mode];
+    if (vgamode == -1) {
+       write_log ("Bug!\n");
+       abort ();
+    }
+    write_log ("Desired resolution: %dx%d, using: %dx%d\n",
+            currprefs.gfx_width, currprefs.gfx_height,
+            x_size_table[mode_nr], y_size_table[mode_nr]);
+
+    currprefs.gfx_width = x_size_table[mode_nr];
+    currprefs.gfx_height = y_size_table[mode_nr];
+
+    return 1;
+}
+
+int graphics_init (void)
+{
+    int i;
+    need_dither = 0;
+    screen_is_picasso = 0;
+
+    if (!select_mode_from_prefs ())
+       return 0;
+
+    bitdepth = mode_bitdepth[currprefs.color_mode][0];
+    bit_unit = mode_bitdepth[currprefs.color_mode][1];
+    need_dither = mode_bitdepth[currprefs.color_mode][2];
+
+    modeinfo = *vga_getmodeinfo (vgamode);
+
+    gfxvidinfo.pixbytes = modeinfo.bytesperpixel;
+    if (!need_dither) {
+       if (modeinfo.bytesperpixel == 0) {
+           printf("Got a bogus value from SVGAlib...\n");
+           gfxvidinfo.pixbytes = 1;
+       }
+    } else {
+       gfxvidinfo.pixbytes = 2;
+    }
+
+    using_linear = -1;
+
+    if (!enter_graphics_mode (vgamode))
+       return 0;
+
+    sleep(2);
+    gfxvidinfo.maxblocklines = 0;
+
+    gfxvidinfo.width = modeinfo.width;
+    gfxvidinfo.height = modeinfo.height;
+
+    if (linear_mem != NULL && !need_dither) {
+       gfxvidinfo.bufmem = linear_mem;
+       gfxvidinfo.rowbytes = modeinfo.linewidth;
+    } else {
+       gfxvidinfo.rowbytes = (modeinfo.width * gfxvidinfo.pixbytes + 3) & ~3;
+#if 1
+       gfxvidinfo.bufmem = malloc (gfxvidinfo.rowbytes);
+       gfxvidinfo.linemem = gfxvidinfo.bufmem;
+       memset (gfxvidinfo.bufmem, 0, gfxvidinfo.rowbytes);
+#else
+       gfxvidinfo.bufmem = malloc(gfxvidinfo.rowbytes * modeinfo.height);
+       memset (gfxvidinfo.bufmem, 0, gfxvidinfo.rowbytes * modeinfo.height);
+#endif
+       gfxvidinfo.emergmem = 0;
+    }
+    printf ("rowbytes %d\n", gfxvidinfo.rowbytes);
+    init_colors ();
+    buttonstate[0] = buttonstate[1] = buttonstate[2] = 0;
+    for(i = 0; i < 256; i++)
+       keystate[i] = 0;
+
+    lastmx = lastmy = 0;
+    newmousecounters = 0;
+
+    return 1;
+}
+
+void graphics_leave (void)
+{
+    leave_graphics_mode ();
+    dumpcustom();
+}
+
+void handle_events (void)
+{
+    int button = mouse_getbutton ();
+
+    gui_requested = 0;
+    keyboard_update ();
+    mouse_update ();
+    lastmx += mouse_getx ();
+    lastmy += mouse_gety ();
+    mouse_setposition (0, 0);
+
+    buttonstate[0] = button & 4;
+    buttonstate[1] = button & 2;
+    buttonstate[2] = button & 1;
+
+#ifdef PICASSO96
+    if (screen_is_picasso && !picasso_vidinfo.extra_mem) {
+       int i;
+       char *addr = gfxmemory + (picasso96_state.Address - gfxmem_start);
+       for (i = 0; i < picasso_vidinfo.height; i++, addr += picasso96_state.BytesPerRow) {
+           if (!picasso_invalid_lines[i])
+               continue;
+           picasso_invalid_lines[i] = 0;
+           vga_drawscanline (i, addr);
+       }
+    }
+#endif
+
+    if (!screen_is_picasso && gui_requested) {
+       leave_graphics_mode ();
+       gui_changesettings ();
+       enter_graphics_mode (vgamode);
+       if (linear_mem != NULL && !need_dither)
+           gfxvidinfo.bufmem = linear_mem;
+       restore_vga_colors ();
+       notice_screen_contents_lost ();
+    }
+}
+
+int check_prefs_changed_gfx (void)
+{
+    return 0;
+}
+
+int debuggable (void)
+{
+    return 0;
+}
+
+int needmousehack (void)
+{
+    return 0;
+}
+
+void LED (int on)
+{
+}
+
+#ifdef PICASSO96
+
+void DX_Invalidate (int first, int last)
+{
+    do {
+       picasso_invalid_lines[first] = 1;
+       first++;
+    } while (first <= last);
+}
+
+int DX_BitsPerCannon (void)
+{
+    return 8;
+}
+
+void DX_SetPalette(int start, int count)
+{
+    if (!screen_is_picasso || picasso_vidinfo.pixbytes != 1)
+       return;
+
+    while (count-- > 0) {
+       vga_setpalette(start, picasso96_state.CLUT[start].Red * 63 / 255,
+                      picasso96_state.CLUT[start].Green * 63 / 255,
+                      picasso96_state.CLUT[start].Blue * 63 / 255);
+       start++;
+    }
+}
+
+int DX_FillResolutions (uae_u16 *ppixel_format)
+{
+    int i, count = 0;
+    uae_u16 format = 0;
+
+    for (i = 0; i < MAX_SCREEN_MODES; i++) {
+       int mode = vga_mode_table[i][0];
+       if (mode != -1) {
+           DisplayModes[count].res.width = x_size_table[i];
+           DisplayModes[count].res.height = y_size_table[i];
+           DisplayModes[count].depth = 1;
+           DisplayModes[count].refresh = 75;
+           count++;
+           format |= RGBFF_CHUNKY;
+       }
+       mode = vga_mode_table[i][2];
+       if (mode != -1) {
+           DisplayModes[count].res.width = x_size_table[i];
+           DisplayModes[count].res.height = y_size_table[i];
+           DisplayModes[count].depth = 2;
+           DisplayModes[count].refresh = 75;
+           count++;
+           format |= RGBFF_R5G6B5PC;
+       }
+       mode = vga_mode_table[i][5];
+       if (mode != -1) {
+           DisplayModes[count].res.width = x_size_table[i];
+           DisplayModes[count].res.height = y_size_table[i];
+           DisplayModes[count].depth = 4;
+           DisplayModes[count].refresh = 75;
+           count++;
+           format |= RGBFF_B8G8R8A8;
+       }
+    }
+
+    *ppixel_format = format;
+    return count;
+}
+
+static void set_window_for_picasso (void)
+{
+    enter_graphics_mode_picasso (picasso_vgamode);
+    if (linear_mem != NULL)
+       picasso_vidinfo.extra_mem = 1;
+    else
+       picasso_vidinfo.extra_mem = 0;
+    printf ("em: %d\n", picasso_vidinfo.extra_mem);
+    DX_SetPalette (0, 256);
+}
+
+static void set_window_for_amiga (void)
+{
+    leave_graphics_mode ();
+    enter_graphics_mode (vgamode);
+    if (linear_mem != NULL && !need_dither)
+       gfxvidinfo.bufmem = linear_mem;
+
+    restore_vga_colors ();
+}
+
+void gfx_set_picasso_modeinfo (int w, int h, int depth, int rgbfmt)
+{
+    vga_modeinfo *info;
+    int i, mode;
+
+    for (i = 0; i < MAX_SCREEN_MODES; i++)
+       if (x_size_table[i] == w && y_size_table[i] == h)
+           break;
+    printf ("::: %d %d %d, %d\n", w, h, depth, i);
+    if (i == MAX_SCREEN_MODES)
+       abort ();
+    mode = (depth == 8 ? vga_mode_table[i][0]
+           : depth == 16 ? vga_mode_table[i][2]
+           : depth == 32 ? vga_mode_table[i][5]
+           : -1);
+    printf ("::: %d\n", mode);
+    if (mode == -1)
+       abort ();
+
+    info = vga_getmodeinfo (mode);
+    printf ("::: %d\n", info->linewidth);
+    picasso_vgamode = mode;
+    picasso_vidinfo.width = w;
+    picasso_vidinfo.height = h;
+    picasso_vidinfo.depth = depth;
+    picasso_vidinfo.pixbytes = depth>>3;
+    picasso_vidinfo.rowbytes = info->linewidth;
+    picasso_vidinfo.rgbformat = (depth == 8 ? RGBFB_CHUNKY
+                                : depth == 16 ? RGBFB_R5G6B5PC
+                                : RGBFB_B8G8R8A8);
+    if (screen_is_picasso)
+       set_window_for_picasso ();
+}
+
+void gfx_set_picasso_baseaddr (uaecptr a)
+{
+}
+
+void gfx_set_picasso_state (int on)
+{
+    if (on == screen_is_picasso)
+       return;
+    screen_is_picasso = on;
+    if (on)
+       set_window_for_picasso ();
+    else
+       set_window_for_amiga ();
+}
+
+uae_u8 *gfx_lock_picasso (void)
+{
+    return linear_mem;
+}
+void gfx_unlock_picasso (void)
+{
+}
+#endif
+
+int lockscr (void)
+{
+    return 1;
+}
+
+void unlockscr (void)
+{
+}
+
+void target_save_options (FILE *f, struct uae_prefs *p)
+{
+    fprintf (f, "svga.no_linear=%s\n", p->svga_no_linear ? "true" : "false");
+}
+
+int target_parse_option (struct uae_prefs *p, char *option, char *value)
+{
+    return (cfgfile_yesno (option, value, "no_linear", &p->svga_no_linear));
+}
+
+/* Dummy entry to make it compile */
+void DX_SetPalette_vsync(void)
+{}
diff --git a/svgancui.c b/svgancui.c
new file mode 100755 (executable)
index 0000000..d405fc9
--- /dev/null
@@ -0,0 +1,578 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * ncurses frontend for a text-based user interface.
+  *
+  * Copyright 1996 Bernd Schmidt
+  * If you find the routines in this file useful, you may use them in your
+  * programs without restrictions. Essentially, it's in the public domain.
+  *
+  */
+
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#ifdef HAVE_NCURSES_H
+#include <ncurses.h>
+#else
+#include <curses.h>
+#endif
+#include <ctype.h>
+
+#include "config.h"
+#include "options.h"
+#include "uae.h"
+#include "tui.h"
+
+#ifdef DONT_HAVE_ATTR_T
+typedef int attr_t;
+#endif
+
+static WINDOW *currwin;
+
+static WINDOW *winstack[10]; /* more than enough */
+static int winnr = 0;
+
+void tui_setup(void)
+{
+    int i;
+
+    for (i = 0; i < 10; i++)
+       winstack[i] = NULL;
+    /* From the ncurses manpage... */
+    initscr (); start_color (); cbreak(); noecho(); nonl (); intrflush (stdscr, FALSE); keypad (stdscr, TRUE);
+    currwin = stdscr;
+    if (has_colors ()) {
+       init_pair (1, COLOR_WHITE, COLOR_BLUE);
+       init_pair (2, COLOR_BLACK, COLOR_WHITE);
+       wattron (currwin, COLOR_PAIR (1) | A_BOLD);
+       wbkgd (currwin, ' ' | COLOR_PAIR (1));
+    }
+
+    winstack[0] = stdscr;
+    winnr = 1;
+}
+
+int tui_lines (void)
+{
+    return LINES;
+}
+
+int tui_cols (void)
+{
+    return COLS;
+}
+
+void tui_shutdown (void)
+{
+    endwin ();
+}
+
+void tui_refresh (void)
+{
+    int w;
+    for (w = 0; w < winnr; w++) {
+       touchwin (winstack[w]);
+       wnoutrefresh (winstack[w]);
+    }
+    doupdate ();
+}
+
+void tui_puts (const char *s)
+{
+    waddstr (currwin, s);
+}
+
+void tui_cursoff(void)
+{
+}
+
+void tui_curson (void)
+{
+}
+
+void tui_putc(char c)
+{
+    waddch (currwin, c);
+}
+
+void tui_cr (void)
+{
+    waddch (currwin, '\r');
+}
+
+char tui_getc(void)
+{
+    return getch ();
+}
+
+void tui_gotoxy (int x, int y)
+{
+    x--; y--;
+    wmove (currwin, y, x);
+}
+
+void tui_selwin (int w)
+{
+    currwin = winstack[w];
+}
+
+void tui_clrwin (int w)
+{
+    werase (winstack[w]);
+}
+
+void tui_drawbox(int w)
+{
+    wborder (winstack[w], 0, 0, 0, 0, 0, 0, 0, 0);
+}
+
+void tui_hline (int x1, int y1, int x2)
+{
+    wmove (currwin, y1-1, x1-1);
+    whline (currwin, 0, x2-x1+1);
+}
+
+int tui_dlog(int x1, int y1, int x2, int y2)
+{
+    x1--; y1--;
+    winstack[winnr] = newwin (y2 - y1, x2 - x1, y1, x1);
+    return winnr++;
+}
+
+void tui_dlogdie (int w)
+{
+    if (currwin == winstack[w])
+       currwin = stdscr;
+    delwin (winstack[w]);
+    winstack[w] = NULL;
+    while (winstack[winnr-1] == NULL)
+       winnr--;
+
+    for (w = 0; w < winnr; w++)
+       redrawwin (winstack[w]), wrefresh (winstack[w]);
+}
+
+int tui_gets (char *buf, int x, int y, int n)
+{
+    int i = 0;
+    for (;;) {
+       int c, j;
+
+       buf[i] = 0;
+       wmove (currwin, y, x);
+       for (j = 0; j < i; j++)
+           waddch (currwin, buf[j]);
+       for (; j < n; j++)
+           waddch (currwin, ' ');
+
+       wmove (currwin, y, x + i);
+       wrefresh (currwin);
+
+       c = getch ();
+
+       wmove (currwin, y, x + i);
+       if (c == 13)
+           return 1;
+       else if (c == 27)
+           return 0;
+       else if (i > 0 && c == KEY_BACKSPACE)
+           i--;
+       else if (i + 1 < n && !iscntrl (c))
+           buf[i++] = c;
+    }
+}
+
+int tui_wgets (char *buf, const char *title, int n)
+{
+    int l = strlen (title);
+    int ww = (l > n ? l : n) + 2;
+    int w = tui_dlog((tui_cols ()-ww)/2, tui_lines ()/2-1, (tui_cols ()+ww)/2, tui_lines ()/2+1);
+    int result;
+
+    tui_selwin (w); tui_drawbox(w);
+    wmove (currwin, 0, (ww-l)/2);
+    waddstr (currwin, title);
+    result = tui_gets (buf, 1, 1, n);
+    tui_dlogdie (w);
+    return result;
+}
+
+int tui_menubrowse (struct bstring *menu, int xoff, int yoff, int selected, int height)
+{
+    int count = 0, maxsel = 0, maxw = 0;
+    int i, j, w, s, yp, oldyp;
+    chtype moresave[6][2];
+    int xpos, ypos;
+
+    const char *mtitle = NULL;
+
+    for (i = 0; menu[i].val != -3; i++) {
+       int tmp;
+       if (menu[i].val == -4) {
+           if (maxsel < selected)
+               selected--;
+           continue;
+       }
+       if (menu[i].val != 0) {
+           count++;
+           if (menu[i].val != -2)
+               maxsel++;
+       } else
+           mtitle = menu[i].data;
+       if ((tmp = strlen (menu[i].data)) > maxw)
+           maxw = tmp;
+    }
+    if (height > count)
+       height = count;
+    maxw += 3;
+    if (strlen (mtitle ? mtitle : "") + 8 > maxw)
+       maxw = strlen (mtitle ? mtitle : "") + 8;
+    if (xoff > 0)
+       xpos = xoff;
+    else
+       xpos = tui_cols () + xoff - maxw - 1;
+    if (yoff > 0)
+       ypos = yoff;
+    else
+       ypos = tui_lines () + yoff - height - 2;
+    w = tui_dlog(xpos, ypos, xpos+maxw, ypos+height+1);
+    tui_selwin (w);
+    tui_drawbox(w);
+    if (mtitle != NULL) {
+       mvwaddstr (currwin, 0, 1, mtitle);
+    }
+    for (i = 0; i < 6; i++) {
+       moresave[i][0] = mvwinch (currwin, 0, maxw-6+i);
+       moresave[i][1] = mvwinch (currwin, height+1, maxw-6+i);
+    }
+    s = yp = 0; oldyp = -1;
+    for (;;) {
+       int c;
+       int s2;
+
+       while (selected < yp)
+           yp--;
+       while (selected >= yp + height)
+           yp++;
+       if (yp == 0)
+           for (i = 0; i < 6; i++)
+               mvwaddch (currwin, 0, maxw-6+i, moresave[i][0]);
+       else
+           mvwaddstr (currwin, 0, maxw-6, "(more)");
+       if (yp + height == count)
+           for (i = 0; i < 6; i++)
+               mvwaddch (currwin, height+1, maxw-6+i, moresave[i][1]);
+       else
+           mvwaddstr (currwin, height+1, maxw-6, "(more)");
+       for (i = s2 = j = 0; i < count; i++, j++) {
+           int k, x;
+           attr_t a = s2 == selected ? A_STANDOUT : 0;
+           while (menu[j].val == 0 || menu[j].val == -4)
+               j++;
+           if (i >= yp && i < yp+height) {
+               mvwaddch (currwin, 1+i-yp, 1, ' ' | a);
+               for (k = x = 0; menu[j].data[k]; k++, x++) {
+                   int a2 = 0;
+                   c = menu[j].data[k];
+                   if (c == '_')
+                       c = menu[j].data[++k], a2 = A_UNDERLINE;
+                   mvwaddch (currwin, 1+i-yp, 2+x, c | a | a2);
+               }
+               for (; x < maxw-2; x++) {
+                   mvwaddch (currwin, 1+i-yp, 2+x, ' ' | a);
+               }
+           }
+           if (menu[j].val != -2)
+               s2++;
+       }
+
+       tui_refresh ();
+       c = getch ();
+       if (c == 27) {
+           tui_dlogdie (w);
+           return -1;
+       } else if (c == KEY_ENTER || c == 13 || c == ' ') {
+           tui_dlogdie (w);
+           for (i = s2 = j = 0; s2 <= selected; j++) {
+               if (menu[j].val == -4) {
+                   i++; j++; continue;
+               }
+               while (menu[j].val == 0)
+                   j++;
+               if (s2 == selected)
+                   return i;
+               if (menu[j].val != -2)
+                   s2++, i++;
+           }
+           abort();
+       } else switch (c) {
+        case KEY_UP:
+           if (selected > 0)
+               selected--;
+           break;
+        case KEY_DOWN:
+           if (selected + 1 < count)
+               selected++;
+           break;
+        case KEY_PPAGE:
+           if (selected > height)
+               selected -= height;
+           else
+               selected = 0;
+           break;
+        case KEY_NPAGE:
+           if (selected + height < count)
+               selected += height;
+           else
+               selected = count-1;
+           break;
+        default:
+           for (j = i = 0; menu[i].val != -3; i++)
+               if (menu[i].val == toupper (c)) {
+                   tui_dlogdie (w);
+                   return j;
+               } else if (menu[i].val == -1 || menu[i].val == -4 || menu[i].val > 0) {
+                   j++;
+               }
+
+           break;
+       }
+    }
+    return -1; /* Can't get here */
+}
+
+void tui_errorbox(const char *err)
+{
+    const char *hak = "Hit any key";
+    int n = strlen (hak);
+    int l = strlen (err);
+    int ww = (l > n ? l : n) + 2;
+    int w = tui_dlog((tui_cols ()-ww)/2, tui_lines ()/2-1, (tui_cols ()+ww)/2, tui_lines ()/2+1);
+    tui_selwin (w); tui_drawbox(w);
+
+    wmove (currwin, 0, (ww-6)/2);
+    waddstr (currwin, "Error!");
+    wmove (currwin, 1, (ww-l)/2);
+    waddstr (currwin, err);
+    wmove (currwin, 2, (ww-n)/2);
+    waddstr (currwin, hak);
+
+    wrefresh (currwin);
+    for (;;) {
+       int c = getch ();
+       if (c == 13)
+           break;
+    }
+    tui_dlogdie (w);
+}
+
+static char *pattern;
+static int maxlen;
+
+static void put_filename (char *s, int x, int y, attr_t a)
+{
+    char buf[256];
+    int i;
+
+    tui_gotoxy (x,y);
+    if (strcmp (s, ".") == 0)
+       strcpy (buf, "(none)");
+    else
+       strcpy (buf, s);
+    buf[maxlen] = 0;
+    for (i = 0; i < strlen (buf); i++)
+       waddch (currwin, buf[i] | a);
+    for (; i < maxlen; i++)
+       waddch (currwin, ' ' | a);
+}
+
+static char fsbuf[256];
+
+static int selectfn (const struct dirent *de)
+{
+    int l1, l2;
+
+/*    l1 = strlen (pattern + 1);*/
+    l2 = strlen (de->d_name);
+
+    if (l2 >= tui_cols ()-10) /* Restrict length of filenames so we won't mess up the display */
+       return 0;
+
+    /* No pattern matching for now. But we don't show hidden files. */
+    if (strcmp (de->d_name, ".") != 0 && strcmp (de->d_name, "..") != 0
+       && de->d_name[0] == '.')
+       return 0;
+    if (l2 > maxlen)
+       maxlen = l2;
+    return 1;
+}
+
+static int my_alphasort (const void *a, const void *b)
+{
+    return strcmp ((*(struct dirent **) a)->d_name,
+                  (*(struct dirent **) b)->d_name);
+}
+
+char *tui_filereq(char *s, char *oldfile, const char *title)
+{
+    char cwd[256];
+    char *retval = fsbuf;
+    char *tmp;
+    int fin = 0;
+    chtype moresave[6][2];
+
+    /* Save wd */
+    if (getcwd (cwd, 256) == NULL)
+       return NULL;
+
+    /* Change into directory of old file */
+    strcpy (fsbuf, oldfile);
+    tmp = strrchr (fsbuf, '/');
+    if (tmp != NULL) {
+       *tmp = 0;
+       if (strlen (fsbuf) > 0)
+           chdir (fsbuf);
+    }
+
+    pattern = s;
+    if (s[0] != '*')
+       write_log ("Can't handle wildcard %s\n", s);
+    if (s[1] != 0 && strchr (s+1, '*') != NULL)
+       write_log ("Can't handle wildcard %s\n", s);
+    for (;!fin;) {
+       struct dirent **names;
+       int i, w, n, l, yp, oldyp, s;
+
+       maxlen = 0;
+       n = scandir (".", &names, selectfn, my_alphasort);
+
+       if (n <= 0)
+           return NULL;
+       if (title != NULL && strlen (title) + 6 > maxlen)
+           maxlen = strlen (title) + 6;
+       l = n;
+       if (l > 15)
+           l = 15;
+       yp = s = 0; oldyp = -1;
+       w = tui_dlog (tui_cols () - maxlen - 8, 5, tui_cols () - 5, 5 + l + 1);
+       tui_selwin (w); tui_drawbox (w);
+       if (title)
+           mvwaddstr (currwin, 0, 2, title);
+       for (i = 0; i < 6; i++) {
+           moresave[i][0] = mvwinch (currwin, 0, maxlen-3+i);
+           moresave[i][1] = mvwinch (currwin, l+1, maxlen-3+i);
+       }
+       for (;;) {
+           int c;
+           char tmp[256];
+           while (s < yp)
+               yp--;
+           while (s >= yp + l)
+               yp++;
+           if (oldyp != yp) {
+               oldyp = yp;
+               for (i = 0; i < l; i++) {
+                   put_filename (names[i + yp]->d_name, 3, 2 + i, 0);
+               }
+           }
+           put_filename (names[s]->d_name, 3, 2 + s - yp, A_STANDOUT);
+
+           if (yp == 0)
+               for (i = 0; i < 6; i++)
+                   mvwaddch (currwin, 0, maxlen-3+i, moresave[i][0]);
+           else
+               mvwaddstr (currwin, 0, maxlen-3, "(more)");
+           if (yp + l == n)
+               for (i = 0; i < 6; i++)
+                   mvwaddch (currwin, l+1, maxlen-3+i, moresave[i][1]);
+           else
+               mvwaddstr (currwin, l+1, maxlen-3, "(more)");
+
+           tui_refresh ();
+           c = getch ();
+           put_filename (names[s]->d_name, 3, 2 + s - yp, 0);
+           if (c == 27) {
+               retval = NULL; fin = 1;
+               break;
+           } else if (c == KEY_ENTER || c == 13 || c == ' ') {
+               int err;
+
+               if (strcmp (names[s]->d_name, ".") == 0) {
+                   fin = 1;
+                   strcpy (fsbuf, "");
+                   break;
+               }
+               err = chdir (names[s]->d_name);
+
+               if (err == 0)
+                   break;
+               else if (errno == ENOTDIR) {
+                   fin = 1;
+                   if (getcwd (fsbuf, 256) == NULL)
+                       retval = NULL;
+                   if (strlen (fsbuf) + strlen (names[s]->d_name) + 2 >= 256)
+                       retval = NULL;
+                   else {
+                       strcat(fsbuf, "/");
+                       strcat(fsbuf, names[s]->d_name);
+                   }
+                   break;
+               } /* else what? */
+           }
+           switch (c) {
+            case KEY_UP:
+               if (s > 0)
+                   s--;
+               break;
+            case KEY_DOWN:
+               if (s + 1 < n)
+                   s++;
+               break;
+            case KEY_PPAGE:
+               if (s > l)
+                   s -= l;
+               else
+                   s = 0;
+               break;
+            case KEY_NPAGE:
+               if (s + l < n)
+                   s += l;
+               else
+                   s = n - 1;
+               break;
+            default:
+               i = 0;
+               if (names[s]->d_name[0] == c)
+                   i = s+1;
+               for (; i < n*2; i++) {
+                   int j = i;
+                   if (i >= n)
+                       j -= n;
+                   if (names[j]->d_name[0] == c) {
+                       s = j;
+                       break;
+                   }
+               }
+           }
+       }
+#if 0
+       /* @@@ is this right? */
+       for (i = 0; i < n; i++)
+           free (names[i]);
+       free (names);
+#endif
+       tui_dlogdie (w);
+    }
+    chdir (cwd);
+    return retval;
+}
+
+int tui_backup_optionsfile (void)
+{
+    char tmp[257];
+    strcpy (tmp, optionsfile);
+    strcat (tmp, "~");
+    return rename (optionsfile, tmp);
+}
diff --git a/table68k b/table68k
new file mode 100755 (executable)
index 0000000..aeed755
--- /dev/null
+++ b/table68k
@@ -0,0 +1,260 @@
+% 0: bit 0
+% 1: bit 1
+% c: condition code
+% C: condition codes, except F
+% f: direction
+% i: immediate
+% I: immediate, except 00 and ff
+% j: immediate 1..8
+% J: immediate 0..15
+% k: immediate 0..7
+% K: immediate 0..63
+% p: immediate 0..3 (CINV and CPUSH: cache field)
+% s: source mode
+% S: source reg
+% d: dest mode
+% D: dest reg
+% r: reg
+% z: size
+%
+% Actually, a sssSSS may appear as a destination, and
+% vice versa. The only difference between sssSSS and
+% dddDDD are the valid addressing modes. There is
+% no match for immediate and pc-rel. addressing modes
+% in case of dddDDD.
+%
+% Arp: --> -(Ar)
+% ArP: --> (Ar)+
+% L: (xxx.L)
+%
+% Fields on a line: 
+% 16 chars bitpattern : 
+% CPU level / privildge level :
+%   CPU level 0: 68000
+%             1: 68010
+%             2: 68020
+%   privilege level 0: not privileged
+%                   1: unprivileged only on 68000 (check regs.s)
+%                   2: privileged                 (check regs.s)
+%                   3: privileged if size == word (check regs.s)
+% Flags set by instruction: XNZVC :
+% Flags used by instruction: XNZVC :
+%   - means flag unaffected / unused
+%   0 means flag reset
+%   1 means flag set
+%   ? means programmer was too lazy to check or instruction may trap
+%   + means instruction is conditional branch 
+%     everything else means flag set/used
+%   / means instruction is unconditional branch/call
+%   x means flag is unknown and well-behaved programs shouldn't check it
+% srcaddr status destaddr status :
+%   bitmasks of
+%   1 means fetched
+%   2 means stored
+%   4 means jump offset
+%   8 means jump address
+% instruction
+%
+
+0000 0000 0011 1100:00:XNZVC:XNZVC:10: ORSR.B  #1
+0000 0000 0111 1100:02:?????:?????:10: ORSR.W  #1
+0000 0zz0 11ss sSSS:20:?????:?????:11: CHK2.z  #1,s[!Dreg,Areg,Aipi,Apdi,Immd]
+0000 0000 zzdd dDDD:00:-NZ00:-----:13: OR.z    #z,d[!Areg]
+0000 0010 0011 1100:00:XNZVC:XNZVC:10: ANDSR.B #1
+0000 0010 0111 1100:02:?????:?????:10: ANDSR.W #1
+0000 0010 zzdd dDDD:00:-NZ00:-----:13: AND.z   #z,d[!Areg]
+0000 0100 zzdd dDDD:00:XNZVC:-----:13: SUB.z   #z,d[!Areg]
+0000 0110 zzdd dDDD:00:XNZVC:-----:13: ADD.z   #z,d[!Areg]
+0000 0110 11ss sSSS:20:?????:?????:10: CALLM   s[!Dreg,Areg,Aipi,Apdi,Immd]
+0000 0110 11ss sSSS:20:?????:?????:10: RTM     s[Dreg,Areg]
+0000 1000 00ss sSSS:00:--Z--:-----:11: BTST    #1,s[!Areg]
+0000 1000 01ss sSSS:00:--Z--:-----:13: BCHG    #1,s[!Areg,Immd]
+0000 1000 10ss sSSS:00:--Z--:-----:13: BCLR    #1,s[!Areg,Immd]
+0000 1000 11ss sSSS:00:--Z--:-----:13: BSET    #1,s[!Areg,Immd]
+0000 1010 0011 1100:00:XNZVC:XNZVC:10: EORSR.B #1
+0000 1010 0111 1100:02:?????:?????:10: EORSR.W #1
+0000 1010 zzdd dDDD:00:-NZ00:-----:13: EOR.z   #z,d[!Areg]
+0000 1100 zzss sSSS:00:-NZVC:-----:11: CMP.z   #z,s[!Areg,Immd]
+
+0000 1010 11ss sSSS:20:?????:?????:13: CAS.B   #1,s[!Dreg,Areg,Immd,PC8r,PC16]
+0000 1100 11ss sSSS:20:?????:?????:13: CAS.W   #1,s[!Dreg,Areg,Immd,PC8r,PC16]
+0000 1100 1111 1100:20:?????:?????:10: CAS2.W  #2
+0000 1110 zzss sSSS:22:?????:?????:13: MOVES.z #1,s[!Dreg,Areg,Immd,PC8r,PC16]
+0000 1110 11ss sSSS:20:?????:?????:13: CAS.L   #1,s[!Dreg,Areg,Immd,PC8r,PC16]
+0000 1110 1111 1100:20:?????:?????:10: CAS2.L  #2
+
+0000 rrr1 00dd dDDD:00:-----:-----:12: MVPMR.W d[Areg-Ad16],Dr
+0000 rrr1 01dd dDDD:00:-----:-----:12: MVPMR.L d[Areg-Ad16],Dr
+0000 rrr1 10dd dDDD:00:-----:-----:12: MVPRM.W Dr,d[Areg-Ad16]
+0000 rrr1 11dd dDDD:00:-----:-----:12: MVPRM.L Dr,d[Areg-Ad16]
+0000 rrr1 00ss sSSS:00:--Z--:-----:11: BTST    Dr,s[!Areg]
+0000 rrr1 01ss sSSS:00:--Z--:-----:13: BCHG    Dr,s[!Areg,Immd]
+0000 rrr1 10ss sSSS:00:--Z--:-----:13: BCLR    Dr,s[!Areg,Immd]
+0000 rrr1 11ss sSSS:00:--Z--:-----:13: BSET    Dr,s[!Areg,Immd]
+
+0001 DDDd ddss sSSS:00:-NZ00:-----:12: MOVE.B  s,d[!Areg]
+0010 DDDd ddss sSSS:00:-----:-----:12: MOVEA.L s,d[Areg]
+0010 DDDd ddss sSSS:00:-NZ00:-----:12: MOVE.L  s,d[!Areg]
+0011 DDDd ddss sSSS:00:-----:-----:12: MOVEA.W s,d[Areg]
+0011 DDDd ddss sSSS:00:-NZ00:-----:12: MOVE.W  s,d[!Areg]
+
+0100 0000 zzdd dDDD:00:XxZxC:X-Z--:30: NEGX.z  d[!Areg]
+0100 0000 11dd dDDD:01:?????:?????:10: MVSR2.W d[!Areg]
+0100 0010 zzdd dDDD:00:-0100:-----:20: CLR.z   d[!Areg]
+0100 0010 11dd dDDD:10:?????:?????:10: MVSR2.B d[!Areg]
+0100 0100 zzdd dDDD:00:XNZVC:-----:30: NEG.z   d[!Areg]
+0100 0100 11ss sSSS:00:XNZVC:-----:10: MV2SR.B s[!Areg]
+0100 0110 zzdd dDDD:00:-NZ00:-----:30: NOT.z   d[!Areg]
+0100 0110 11ss sSSS:02:?????:?????:10: MV2SR.W s[!Areg]
+0100 1000 0000 1rrr:20:-----:-----:31: LINK.L  Ar,#2
+0100 1000 00dd dDDD:00:X?Z?C:X-Z--:30: NBCD.B  d[!Areg]
+0100 1000 0100 1kkk:20:?????:?????:10: BKPT    #k
+0100 1000 01ss sSSS:00:-NZ00:-----:30: SWAP.W  s[Dreg]         
+0100 1000 01ss sSSS:00:-----:-----:00: PEA.L   s[!Dreg,Areg,Aipi,Apdi,Immd]
+0100 1000 10dd dDDD:00:-NZ00:-----:30: EXT.W   d[Dreg]         
+0100 1000 10dd dDDD:00:-----:-----:02: MVMLE.W #1,d[!Dreg,Areg,Aipi]
+0100 1000 11dd dDDD:00:-NZ00:-----:30: EXT.L   d[Dreg]         
+0100 1000 11dd dDDD:00:-----:-----:02: MVMLE.L #1,d[!Dreg,Areg,Aipi]
+0100 1001 11dd dDDD:00:-NZ00:-----:30: EXT.B   d[Dreg]         
+0100 1010 zzss sSSS:00:-NZ00:-----:10: TST.z   s
+0100 1010 11dd dDDD:00:?????:?????:30: TAS.B   d[!Areg]
+0100 1010 1111 1100:00:?????:?????:00: ILLEGAL
+0100 1100 00ss sSSS:20:-NZVC:-----:13: MULL.L  #1,s[!Areg]
+0100 1100 01ss sSSS:20:?????:?????:13: DIVL.L  #1,s[!Areg]
+0100 1100 10ss sSSS:00:-----:-----:01: MVMEL.W #1,s[!Dreg,Areg,Apdi,Immd]
+0100 1100 11ss sSSS:00:-----:-----:01: MVMEL.L #1,s[!Dreg,Areg,Apdi,Immd]
+0100 1110 0100 JJJJ:00:-----:XNZVC:10: TRAP    #J
+0100 1110 0101 0rrr:00:-----:-----:31: LINK.W  Ar,#1
+0100 1110 0101 1rrr:00:-----:-----:30: UNLK.L  Ar
+0100 1110 0110 0rrr:02:-----:-----:10: MVR2USP.L Ar
+0100 1110 0110 1rrr:02:-----:-----:20: MVUSP2R.L Ar
+0100 1110 0111 0000:02:-----:-----:00: RESET
+0100 1110 0111 0001:00:-----:-----:00: NOP
+0100 1110 0111 0010:02:XNZVC:-----:10: STOP    #1
+0100 1110 0111 0011:02:XNZVC:-----:00: RTE
+0100 1110 0111 0100:00:?????:?????:10: RTD     #1
+0100 1110 0111 0101:00:-----:-----:00: RTS
+0100 1110 0111 0110:00:-----:XNZVC:00: TRAPV
+0100 1110 0111 0111:00:XNZVC:-----:00: RTR
+0100 1110 0111 1010:12:?????:?????:10: MOVEC2  #1
+0100 1110 0111 1011:12:?????:?????:10: MOVE2C  #1
+0100 1110 10ss sSSS:00://///://///:80: JSR.L   s[!Dreg,Areg,Aipi,Apdi,Immd]
+0100 rrr1 00ss sSSS:00:?????:?????:11: CHK.L   s[!Areg],Dr
+0100 rrr1 10ss sSSS:00:?????:?????:11: CHK.W   s[!Areg],Dr
+0100 1110 11ss sSSS:00://///://///:80: JMP.L   s[!Dreg,Areg,Aipi,Apdi,Immd]
+0100 rrr1 11ss sSSS:00:-----:-----:02: LEA.L   s[!Dreg,Areg,Aipi,Apdi,Immd],Ar
+
+0101 jjj0 01dd dDDD:00:-----:-----:13: ADDA.W  #j,d[Areg]
+0101 jjj0 10dd dDDD:00:-----:-----:13: ADDA.L  #j,d[Areg]
+0101 jjj0 zzdd dDDD:00:XNZVC:-----:13: ADD.z   #j,d[!Areg]
+0101 jjj1 01dd dDDD:00:-----:-----:13: SUBA.W  #j,d[Areg]
+0101 jjj1 10dd dDDD:00:-----:-----:13: SUBA.L  #j,d[Areg]
+0101 jjj1 zzdd dDDD:00:XNZVC:-----:13: SUB.z   #j,d[!Areg]
+0101 cccc 1100 1rrr:00:-----:-++++:31: DBcc.W  Dr,#1
+0101 cccc 11dd dDDD:00:-----:-++++:20: Scc.B   d[!Areg]
+0101 cccc 1111 1010:20:?????:?????:10: TRAPcc  #1
+0101 cccc 1111 1011:20:?????:?????:10: TRAPcc  #2
+0101 cccc 1111 1100:20:?????:?????:00: TRAPcc
+
+% Bxx.L is 68020 only, but setting the CPU level to 2 would give illegal
+% instruction exceptions when compiling a 68000 only emulation, which isn't
+% what we want either.
+0110 0001 0000 0000:00://///://///:40: BSR.W   #1
+0110 0001 IIII IIII:00://///://///:40: BSR.B   #i
+0110 0001 1111 1111:00://///://///:40: BSR.L   #2
+0110 CCCC 0000 0000:00:-----:-++++:40: Bcc.W   #1
+0110 CCCC IIII IIII:00:-----:-++++:40: Bcc.B   #i
+0110 CCCC 1111 1111:00:-----:-++++:40: Bcc.L   #2
+
+0111 rrr0 iiii iiii:00:-NZ00:-----:12: MOVE.L  #i,Dr
+
+1000 rrr0 zzss sSSS:00:-NZ00:-----:13: OR.z    s[!Areg],Dr
+1000 rrr0 11ss sSSS:00:?????:?????:13: DIVU.W  s[!Areg],Dr
+1000 rrr1 00dd dDDD:00:XxZxC:X-Z--:13: SBCD.B  d[Dreg],Dr      
+1000 rrr1 00dd dDDD:00:XxZxC:X-Z--:13: SBCD.B  d[Areg-Apdi],Arp      
+1000 rrr1 zzdd dDDD:00:-NZ00:-----:13: OR.z    Dr,d[!Areg,Dreg]
+1000 rrr1 01dd dDDD:20:?????:?????:12: PACK    d[Dreg],Dr      
+1000 rrr1 01dd dDDD:20:?????:?????:12: PACK    d[Areg-Apdi],Arp      
+1000 rrr1 10dd dDDD:20:?????:?????:12: UNPK    d[Dreg],Dr      
+1000 rrr1 10dd dDDD:20:?????:?????:12: UNPK    d[Areg-Apdi],Arp      
+1000 rrr1 11ss sSSS:00:?????:?????:13: DIVS.W  s[!Areg],Dr
+
+1001 rrr0 zzss sSSS:00:XNZVC:-----:13: SUB.z   s,Dr
+1001 rrr0 11ss sSSS:00:-----:-----:13: SUBA.W  s,Ar
+1001 rrr1 zzdd dDDD:00:XNZVC:X-Z--:13: SUBX.z  d[Dreg],Dr      
+1001 rrr1 zzdd dDDD:00:XNZVC:X-Z--:13: SUBX.z  d[Areg-Apdi],Arp      
+1001 rrr1 zzdd dDDD:00:XNZVC:-----:13: SUB.z   Dr,d[!Areg,Dreg]
+1001 rrr1 11ss sSSS:00:-----:-----:13: SUBA.L  s,Ar
+
+1011 rrr0 zzss sSSS:00:-NZVC:-----:11: CMP.z   s,Dr
+1011 rrr0 11ss sSSS:00:-NZVC:-----:11: CMPA.W  s,Ar
+1011 rrr1 11ss sSSS:00:-NZVC:-----:11: CMPA.L  s,Ar
+1011 rrr1 zzdd dDDD:00:-NZVC:-----:11: CMPM.z  d[Areg-Aipi],ArP
+1011 rrr1 zzdd dDDD:00:-NZ00:-----:13: EOR.z   Dr,d[!Areg]
+
+1100 rrr0 zzss sSSS:00:-NZ00:-----:13: AND.z   s[!Areg],Dr
+1100 rrr0 11ss sSSS:00:-NZ00:-----:13: MULU.W  s[!Areg],Dr
+1100 rrr1 00dd dDDD:00:XxZxC:X-Z--:13: ABCD.B  d[Dreg],Dr      
+1100 rrr1 00dd dDDD:00:XxZxC:X-Z--:13: ABCD.B  d[Areg-Apdi],Arp      
+1100 rrr1 zzdd dDDD:00:-NZ00:-----:13: AND.z   Dr,d[!Areg,Dreg]
+1100 rrr1 01dd dDDD:00:-----:-----:33: EXG.L   Dr,d[Dreg]      
+1100 rrr1 01dd dDDD:00:-----:-----:33: EXG.L   Ar,d[Areg]            
+1100 rrr1 10dd dDDD:00:-----:-----:33: EXG.L   Dr,d[Areg]      
+1100 rrr1 11ss sSSS:00:-NZ00:-----:13: MULS.W  s[!Areg],Dr
+
+1101 rrr0 zzss sSSS:00:XNZVC:-----:13: ADD.z   s,Dr
+1101 rrr0 11ss sSSS:00:-----:-----:13: ADDA.W  s,Ar
+1101 rrr1 zzdd dDDD:00:XNZVC:X-Z--:13: ADDX.z  d[Dreg],Dr      
+1101 rrr1 zzdd dDDD:00:XNZVC:X-Z--:13: ADDX.z  d[Areg-Apdi],Arp      
+1101 rrr1 zzdd dDDD:00:XNZVC:-----:13: ADD.z   Dr,d[!Areg,Dreg]
+1101 rrr1 11ss sSSS:00:-----:-----:13: ADDA.L  s,Ar
+
+1110 jjjf zz00 0RRR:00:XNZVC:-----:13: ASf.z   #j,DR
+1110 jjjf zz00 1RRR:00:XNZ0C:-----:13: LSf.z   #j,DR
+1110 jjjf zz01 0RRR:00:XNZ0C:X----:13: ROXf.z  #j,DR
+1110 jjjf zz01 1RRR:00:-NZ0C:-----:13: ROf.z   #j,DR
+1110 rrrf zz10 0RRR:00:XNZVC:X----:13: ASf.z   Dr,DR
+1110 rrrf zz10 1RRR:00:XNZ0C:X----:13: LSf.z   Dr,DR
+1110 rrrf zz11 0RRR:00:XNZ0C:X----:13: ROXf.z  Dr,DR
+1110 rrrf zz11 1RRR:00:-NZ0C:-----:13: ROf.z   Dr,DR
+1110 000f 11dd dDDD:00:XNZVC:-----:13: ASfW.W  d[!Dreg,Areg]
+1110 001f 11dd dDDD:00:XNZ0C:-----:13: LSfW.W  d[!Dreg,Areg]
+1110 010f 11dd dDDD:00:XNZ0C:X----:13: ROXfW.W d[!Dreg,Areg]
+1110 011f 11dd dDDD:00:-NZ0C:-----:13: ROfW.W  d[!Dreg,Areg]
+
+1110 1000 11ss sSSS:20:?????:?????:11: BFTST   #1,s[!Areg,Apdi,Aipi,Immd]
+1110 1001 11ss sSSS:20:?????:?????:11: BFEXTU  #1,s[!Areg,Apdi,Aipi,Immd]
+1110 1010 11ss sSSS:20:?????:?????:13: BFCHG   #1,s[!Areg,Apdi,Aipi,Immd,PC8r,PC16]
+1110 1011 11ss sSSS:20:?????:?????:11: BFEXTS  #1,s[!Areg,Apdi,Aipi,Immd]
+1110 1100 11ss sSSS:20:?????:?????:13: BFCLR   #1,s[!Areg,Apdi,Aipi,Immd,PC8r,PC16]
+1110 1101 11ss sSSS:20:?????:?????:11: BFFFO   #1,s[!Areg,Apdi,Aipi,Immd]
+1110 1110 11ss sSSS:20:?????:?????:13: BFSET   #1,s[!Areg,Apdi,Aipi,Immd,PC8r,PC16]
+1110 1111 11ss sSSS:20:?????:?????:13: BFINS   #1,s[!Areg,Apdi,Aipi,Immd,PC8r,PC16]
+
+% floating point co processor
+1111 0010 00ss sSSS:30:?????:?????:11: FPP      #1,s
+1111 0010 01ss sSSS:30:?????:?????:11: FDBcc    #1,s[Areg-Dreg]
+1111 0010 01ss sSSS:30:?????:?????:11: FScc     #1,s[!Areg,Immd,PC8r,PC16]
+1111 0010 0111 1010:30:?????:?????:10: FTRAPcc  #1
+1111 0010 0111 1011:30:?????:?????:10: FTRAPcc  #2
+1111 0010 0111 1100:30:?????:?????:00: FTRAPcc
+1111 0010 10KK KKKK:30:?????:?????:11: FBcc     #K,#1
+1111 0010 11KK KKKK:30:?????:?????:11: FBcc     #K,#2
+1111 0011 00ss sSSS:32:?????:?????:20: FSAVE    s[!Dreg,Areg,Aipi,Immd,PC8r,PC16]
+1111 0011 01ss sSSS:32:?????:?????:10: FRESTORE s[!Dreg,Areg,Apdi,Immd]
+
+1111 0101 iiii iSSS:40:?????:?????:11: MMUOP    #i,s
+
+% 68040 instructions
+1111 0100 pp00 1rrr:42:-----:-----:02: CINVL    #p,Ar
+1111 0100 pp01 0rrr:42:-----:-----:02: CINVP    #p,Ar
+1111 0100 pp01 1rrr:42:-----:-----:00: CINVA    #p
+1111 0100 pp10 1rrr:42:-----:-----:02: CPUSHL   #p,Ar
+1111 0100 pp11 0rrr:42:-----:-----:02: CPUSHP   #p,Ar
+1111 0100 pp11 1rrr:42:-----:-----:00: CPUSHA   #p
+% destination register number is encoded in the following word
+1111 0110 0010 0rrr:40:-----:-----:12: MOVE16   ArP,AxP
+1111 0110 00ss sSSS:40:-----:-----:12: MOVE16   s[Dreg-Aipi],L
+1111 0110 00dd dDDD:40:-----:-----:12: MOVE16   L,d[Areg-Aipi]
+1111 0110 00ss sSSS:40:-----:-----:12: MOVE16   s[Aind],L
+1111 0110 00dd dDDD:40:-----:-----:12: MOVE16   L,d[Aipi-Aind]
diff --git a/tui.c b/tui.c
new file mode 100755 (executable)
index 0000000..f7f7d1b
--- /dev/null
+++ b/tui.c
@@ -0,0 +1,730 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Text-based user interface
+  * Sie haben es sich verdient!
+  *
+  * Copyright 1996 Tim Gunn, Bernd Schmidt
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include "config.h"
+#include "options.h"
+#include "threaddep/thread.h"
+#include "uae.h"
+#include "gensound.h"
+#include "joystick.h"
+#include "keybuf.h"
+#include "autoconf.h"
+#include "xwin.h"
+#include "tui.h"
+#include "gui.h"
+#include "memory.h"
+
+#define MAX_MENU_HEIGHT 15
+#define OPTION_COLUMN 3
+#define MENU_COL_OFFSET -2
+
+int mountok=0;
+
+void gui_led (int led, int on)
+{
+}
+void gui_filename (int num, const char *name)
+{
+}
+static void getline (char *p)
+{
+}
+void gui_handle_events (void)
+{
+}
+void gui_fps (int x)
+{
+}
+static void save_settings (void)
+{
+    FILE *f;
+    tui_backup_optionsfile ();
+    f = fopen (optionsfile, "w");
+    if (f == NULL) {
+       write_log ("Error saving options file!\n");
+       return;
+    }
+    save_options (f, &currprefs);
+    fclose (f);
+}
+
+void gui_exit()
+{
+}
+
+static struct bstring mainmenu[] = {
+    { "UAE configuration", 0 },
+    { "_Disk settings", 'D' },
+    { "_Video settings", 'V' },
+    { "_Memory settings", 'M' },
+    { "_CPU settings", 'C' },
+    { "_Hard disk settings", 'H' },
+    { "_Sound settings", 'S' },
+    { "_Other settings", 'O' },
+    { "S_ave settings", 'A' },
+    { "_Run UAE", 'R' },
+    { NULL, -3 }
+};
+
+static struct bstring mainmenu2[] = {
+    { "UAE configuration", 0 },
+    { "_Disk settings", 'D' },
+/*    { "_Video settings", 'V' },
+    { "_Memory settings", 'M' },
+    { "_Hard disk settings", 'H' },
+    { "_Sound settings", 'S' }, */
+    { "_Other settings", 'O' },
+    { "S_ave settings", 'A' },
+    { "R_eset UAE", 'E' },
+    { "_Quit UAE", 'Q' },
+    { "_Run UAE", 'R' },
+    { NULL, -3 }
+};
+
+static struct bstring diskmenu[] = {
+    { "Floppy disk settings", 0 },
+    { "Change DF_0:", '0' },
+    { "Change DF_1:", '1' },
+    { "Change DF_2:", '2' },
+    { "Change DF_3:", '3' },
+    { NULL, -3 }
+};
+
+static struct bstring videomenu[] = {
+    { "Video settings", 0 },
+    { "Change _width", 'W' },
+    { "Change _height", 'H' },
+    { "Change _color mode", 'C' },
+    { "Select predefined _mode", 'M' },
+    { "Toggle _low resolution", 'L' },
+    { "Change _X centering", 'X' },
+    { "Change _Y centering", 'Y' },
+    { "Toggle line _doubling", 'D' },
+    { "Toggle _aspect _correction", 'A' },
+    { "Change _framerate", 'F' },
+    { "_Graphics card memory", 'P'},
+    { NULL, -3 }
+};
+
+static struct bstring memorymenu[] = {
+    { "Memory settings", 0 },
+    { "Change _fastmem size", 'F' },
+    { "Change _chipmem size", 'C' },
+    { "Change _slowmem size", 'S' },
+    { "Select ROM _image", 'I' },
+    { NULL, -3 }
+};
+
+static struct bstring cpumenu[] = {
+    { "Change _CPU", 'C' },
+    { NULL, -3 }
+};
+
+static struct bstring soundmenu[] = {
+    { "Sound settings", 0 },
+    { "Change _sound emulation accuracy", 'S' },
+    { "Change m_inimum sound buffer size", 'I' },
+    { "Change m_aximum sound buffer size", 'A' },
+    { "Change number of _bits", 'B' },
+    { "Change output _frequency", 'F' },
+    { "Change s_tereo", 'T' },
+    { NULL , -3 }
+};
+
+static struct bstring miscmenu[] = {
+    { "Miscellaneous settings", 0 },
+    { "Toggle joystick port _0 emulation", '0' },
+    { "Toggle joystick port _1 emulation", '1' },
+    { "Set _CPU emulation speed", 'C' },
+    { NULL, -3 }
+};
+
+static struct bstring hdmenu[] = {
+/*    { "Harddisk/CDROM emulation settings", 0 },*/
+    { "_Add a mounted volume", 'A' },
+    { "Add a mounted _volume r/o", 'V' },
+    { "Add a hard_file", 'F' },
+    { "_Delete a mounted volume", 'D' },
+    { NULL, -3 }
+};
+
+static int makemenu (const char **menu, int x, int y)
+{
+    const char **m = menu;
+    int maxlen = 0, count = 0;
+    int w;
+
+    while (*m != NULL) {
+       int l = strlen (*m);
+       if (l > maxlen)
+           maxlen = l;
+       m++; count++;
+    }
+    w = tui_dlog (x, y, x + maxlen + 2, y + count + 1);
+    tui_drawbox (w);
+    tui_selwin (w);
+    y = 2;
+    while (*menu != NULL) {
+       tui_gotoxy (2, y++);
+       tui_puts (*menu++);
+    }
+    tui_selwin (0);
+    return w;
+}
+
+static char tmpbuf[256];
+
+static char *trimfilename(char *s, size_t n)
+{
+    size_t i;
+    if (n > 250)
+       n = 250;
+    if (strlen (s) == 0)
+       strcpy (tmpbuf, "none");
+    else if (strlen (s) < n)
+       strcpy (tmpbuf, s);
+    else {
+       tmpbuf[0] = '^';
+       strcpy (tmpbuf + 1, s + strlen (s) - n + 2);
+    }
+    for (i = strlen(tmpbuf); i < n; i++)
+       tmpbuf[i] = ' ';
+    tmpbuf[i] = 0;
+    return tmpbuf;
+}
+
+static void print_configuration (void)
+{
+    char tmp[256];
+    int y = 5;
+    int i;
+
+    tui_clrwin (0);
+
+    tui_drawbox (0);
+    tui_hline (2, 3, tui_cols () - 1);
+    sprintf (tmp, "UAE %d.%d.%d: The Un*x Amiga Emulator", UAEMAJOR, UAEMINOR, UAESUBREV);
+    tui_gotoxy ((tui_cols () - strlen(tmp))/2, 2); tui_puts (tmp);
+    strcpy(tmp, "Press RETURN/ENTER to run UAE, ESC to exit");
+    tui_gotoxy ((tui_cols () - strlen(tmp))/2, tui_lines ()); tui_puts (tmp);
+
+    tui_gotoxy (OPTION_COLUMN, y++); sprintf (tmp, "Disk file DF0: %s", trimfilename (currprefs.df[0], tui_cols () - 20)); tui_puts (tmp);
+    tui_gotoxy (OPTION_COLUMN, y++); sprintf (tmp, "Disk file DF1: %s", trimfilename (currprefs.df[1], tui_cols () - 20)); tui_puts (tmp);
+    tui_gotoxy (OPTION_COLUMN, y++); sprintf (tmp, "Disk file DF2: %s", trimfilename (currprefs.df[2], tui_cols () - 20)); tui_puts (tmp);
+    tui_gotoxy (OPTION_COLUMN, y++); sprintf (tmp, "Disk file DF3: %s", trimfilename (currprefs.df[3], tui_cols () - 20)); tui_puts (tmp);
+    y++;
+    tui_gotoxy (OPTION_COLUMN, y++);
+    sprintf (tmp, "VIDEO: %d:%d%s %s", currprefs.gfx_width, currprefs.gfx_height,
+           currprefs.gfx_lores ? " (lores)" : "", colormodes[currprefs.color_mode]);
+    tui_puts (tmp);
+
+    tui_gotoxy (OPTION_COLUMN+7, y++);
+    if (currprefs.gfx_linedbl)
+       tui_puts ("Doubling lines, ");
+    if (currprefs.gfx_correct_aspect)
+       tui_puts ("Aspect corrected");
+    else
+       tui_puts ("Not aspect corrected");
+    tui_gotoxy (OPTION_COLUMN+7, y++);
+    if (currprefs.gfx_xcenter)
+       tui_puts ("X centered");
+    if (currprefs.gfx_xcenter == 2)
+       tui_puts (" (clever)");
+    if (currprefs.gfx_ycenter && currprefs.gfx_xcenter)
+       tui_puts (", ");
+    if (currprefs.gfx_ycenter)
+       tui_puts ("Y centered ");
+    if (currprefs.gfx_ycenter == 2)
+       tui_puts (" (clever)");
+    tui_gotoxy (OPTION_COLUMN+7, y++);
+    tui_puts ("drawing every ");
+    switch (currprefs.gfx_framerate) {
+     case 1: break;
+     case 2: tui_puts ("2nd "); break;
+     case 3: tui_puts ("3rd "); break;
+     default: sprintf (tmp, "%dth ",currprefs.gfx_framerate); tui_puts (tmp); break;
+    }
+    tui_puts ("frame.    ");
+
+    tui_gotoxy (OPTION_COLUMN+7, y++);
+    if (currprefs.gfxmem_size) {
+       sprintf (tmp, "Picasso 96 %d MB", currprefs.gfxmem_size / 0x100000);
+       tui_puts(tmp);
+    } else
+       tui_puts ("Picasso 96 Off");
+    y++;
+
+    tui_gotoxy (OPTION_COLUMN, y++);
+    tui_puts ("CPU: ");
+    switch (currprefs.cpu_level) {
+     case 0: tui_puts ("68000"); break;
+     case 1: tui_puts ("68010"); break;
+     case 2: tui_puts ("68020"); break;
+     case 3: tui_puts ("68020/68881"); break;
+    }
+    if (currprefs.address_space_24 && currprefs.cpu_level > 1)
+       tui_puts (" (24 bit addressing)");
+    if (currprefs.cpu_compatible)
+       tui_puts (" (slow but compatible)");
+    tui_gotoxy (OPTION_COLUMN, y++);
+    sprintf (tmp, "MEMORY: %4dK chip; %4dK fast; %4dK slow",
+            currprefs.chipmem_size/1024,
+            currprefs.fastmem_size/1024,
+            currprefs.bogomem_size/1024);
+    tui_puts (tmp);
+
+    tui_gotoxy (OPTION_COLUMN, y++);
+    sprintf (tmp, "ROM IMAGE: %s", trimfilename (currprefs.romfile, tui_cols () - 50));
+    tui_puts (tmp);
+    tui_gotoxy (OPTION_COLUMN, y++);
+    if (!sound_available)
+       tui_puts ("SOUND: Not available");
+    else {
+       switch (currprefs.produce_sound) {
+        case 0: tui_puts ("SOUND: 0 (Off)"); break;
+        case 1: tui_puts ("SOUND: 1 (Off, but emulated)"); break;
+        case 2: tui_puts ("SOUND: 2 (On)"); break;
+        case 3: tui_puts ("SOUND: 3 (On, emulated perfectly)"); break;
+       }
+       tui_gotoxy (OPTION_COLUMN + 7, y++);
+       sprintf (tmp, "%d bits at %d Hz", currprefs.sound_bits, currprefs.sound_freq);
+       tui_puts (tmp);
+       tui_gotoxy (OPTION_COLUMN + 7, y++);
+       sprintf (tmp, "Minimum buffer size %d bytes, maximum %d bytes", currprefs.sound_minbsiz, currprefs.sound_maxbsiz);
+       tui_puts (tmp);
+    }
+
+    tui_gotoxy (OPTION_COLUMN,y++);
+    tui_puts ("GAME PORT 1: "); tui_puts (gameport_state (0));
+    tui_gotoxy (OPTION_COLUMN,y++);
+    tui_puts ("GAME PORT 2: "); tui_puts (gameport_state (1));
+
+    for (i = 0;; i++) {
+       char buf[256];
+
+       tui_gotoxy (OPTION_COLUMN+1,y++);
+       if (sprintf_filesys_unit (currprefs.mountinfo, buf, i) == -1)
+           break;
+       tui_puts (buf);
+    }
+}
+
+static void HDOptions (void)
+{
+    char *buff;
+    char tmp[256];
+    char mountvol[256];
+    char mountdir[256];
+    int c = 0;
+
+    for (;;){
+
+       tui_selwin(0);
+       print_configuration();
+
+       c = tui_menubrowse (hdmenu, MENU_COL_OFFSET, 5, c, MAX_MENU_HEIGHT);
+       if (c == -1)
+           break;
+       else switch (c) {
+        case 0:
+           tui_wgets (mountvol, "Enter mounted volume name", 10);
+           if (strlen (mountvol) == 0)
+               break;
+           if (mountvol[strlen(mountvol)-1]==':')
+               mountvol[strlen(mountvol)-1] = 0;
+           tui_wgets (mountdir, "Enter mounted volume path", 78);
+           add_filesys_unit (currprefs.mountinfo, mountvol, mountdir, 0, 0, 0, 0, 0);
+           break;
+        case 1:
+           tui_wgets (mountvol, "Enter mounted volume name", 10);
+           if (strlen (mountvol) == 0)
+               break;
+           if (mountvol[strlen (mountvol)-1]==':')
+               mountvol[strlen (mountvol)-1] = 0;
+           tui_wgets (mountdir, "Enter mounted volume path", 78);
+           add_filesys_unit (currprefs.mountinfo, mountvol, mountdir, 1, 0, 0, 0, 0);
+           break;
+        case 2:
+           buff = tui_filereq("*", "", "Select the hardfile to be mounted");
+           if (buff == NULL)
+               break;
+           strcpy (mountvol, buff);
+           tui_wgets (mountdir, "Enter number of sectors per track", 4);
+           tui_wgets (mountdir + 10, "Enter number of heads", 4);
+           tui_wgets (mountdir + 20, "Enter number of reserved blocks", 3);
+           tui_wgets (mountdir + 30, "Enter block size", 4);
+           buff = add_filesys_unit (currprefs.mountinfo, 0, mountvol, 1,
+                                    atoi (mountdir), atoi (mountdir + 10),
+                                    atoi (mountdir + 20), atoi (mountdir + 30));
+           if (buff)
+               tui_errorbox (buff);
+           break;
+        case 3:
+           tui_wgets (mountvol, "Enter number of volume to be removed (0 for UAE0:, etc.)", 2);
+           if (kill_filesys_unit (currprefs.mountinfo, atoi (mountvol)) == -1)
+               tui_errorbox ("Volume does not exist");
+           break;
+       }
+    }
+}
+
+static void DiskOptions (void)
+{
+    char tmp[256];
+    int c = 0;
+
+    for (;;) {
+       char *sel;
+
+       tui_selwin(0);
+       print_configuration();
+
+       c = tui_menubrowse (diskmenu, MENU_COL_OFFSET, 5, c, MAX_MENU_HEIGHT);
+       if (c == -1)
+           break;
+       else switch (c) {
+        case 0:
+        case 1:
+        case 2:
+        case 3:
+           sprintf (tmp, "Select a diskfile for DF%d:", c);
+           sel = tui_filereq("*.adf", currprefs.df[c], tmp);
+           if (sel == NULL)
+               break;
+           strcpy (currprefs.df[c], sel);
+           break;
+       }
+    }
+}
+
+static void VideoOptions (void)
+{
+    char tmp[256];
+    int c = 0;
+
+    for (c = 0; c < 10; c++)
+       if (videomenu[c].val == 'M') {
+           if (video_mode_menu == NULL)
+               videomenu[c].val = -4;
+           break;
+       }
+
+    c = 0;
+    for (;;) {
+
+       tui_selwin(0);
+       print_configuration();
+
+       c = tui_menubrowse (videomenu, MENU_COL_OFFSET, 5, c, MAX_MENU_HEIGHT);
+       if (c == -1)
+           break;
+       else switch (c) {
+        case 0:
+           tui_wgets (tmp, "Enter new video mode width", 4);
+           if (atoi (tmp) < 320 || atoi (tmp) > 1600 /* maybe we'll implement SHires */)
+               tui_errorbox ("Insane value for video mode width");
+           else
+               currprefs.gfx_width = atoi (tmp);
+           break;
+        case 1:
+           tui_wgets (tmp, "Enter new video mode height", 4);
+           if (atoi (tmp) < 200 || atoi (tmp) > 800 /* whatever */)
+               tui_errorbox ("Insane value for video mode height");
+           else
+               currprefs.gfx_height = atoi (tmp);
+           break;
+        case 2:
+           currprefs.color_mode++;
+           if (currprefs.color_mode > MAX_COLOR_MODES)
+               currprefs.color_mode=0;
+           break;
+        case 3:
+           c = tui_menubrowse (video_mode_menu, 4, 6, 0, 15);
+           if (c != -1)
+               vidmode_menu_selected(c);
+           c = 3;
+           break;
+        case 4:
+           currprefs.gfx_lores = !currprefs.gfx_lores;
+           break;
+        case 5:
+           currprefs.gfx_xcenter = (currprefs.gfx_xcenter + 1) % 3;
+           break;
+        case 6:
+           currprefs.gfx_ycenter = (currprefs.gfx_ycenter + 1) % 3;
+           break;
+        case 7:
+           currprefs.gfx_linedbl = !currprefs.gfx_linedbl;
+           break;
+        case 8:
+           currprefs.gfx_correct_aspect = !currprefs.gfx_correct_aspect;
+           break;
+        case 9:
+           currprefs.gfx_framerate++;
+           if (currprefs.gfx_framerate > 9)
+               currprefs.gfx_framerate=1;
+           break;
+        case 10:
+           currprefs.gfxmem_size += 0x100000;
+           if (currprefs.gfxmem_size > 0x800000)
+               currprefs.gfxmem_size = 0;
+           break;
+       }
+    }
+}
+
+static void MemoryOptions (void)
+{
+    char *tmp;
+    int c = 0;
+    for (;;) {
+
+       tui_selwin(0);
+       print_configuration ();
+
+       c = tui_menubrowse (memorymenu, MENU_COL_OFFSET, 5, c, MAX_MENU_HEIGHT);
+       if (c == -1)
+           break;
+       else switch (c) {
+        case 0:
+           if (currprefs.fastmem_size == 0)
+               currprefs.fastmem_size = 0x200000;
+           else if (currprefs.fastmem_size == 0x800000)
+               currprefs.fastmem_size = 0;
+           else
+               currprefs.fastmem_size <<= 1;
+           break;
+        case 1:
+           if (currprefs.chipmem_size == 0x800000)
+               currprefs.chipmem_size = 0x80000;
+           else
+               currprefs.chipmem_size <<= 1;
+           if (currprefs.chipmem_size > 0x200000)
+               currprefs.fastmem_size = 0;
+           break;
+        case 2:
+           if (currprefs.bogomem_size == 0)
+               currprefs.bogomem_size = 0x40000;
+           else if (currprefs.bogomem_size == 0x100000)
+               currprefs.bogomem_size = 0;
+           else
+               currprefs.bogomem_size <<= 1;
+           break;
+        case 3:
+           tmp = tui_filereq ("*.rom", currprefs.romfile, "Select a ROM image");
+           if (tmp != NULL)
+               strcpy (currprefs.romfile, tmp);
+           break;
+       }
+    }
+}
+
+static void CPUOptions (void)
+{
+    char *tmp;
+    int c = 0;
+    for (;;) {
+       tui_selwin(0);
+       print_configuration ();
+
+       c = tui_menubrowse (cpumenu, MENU_COL_OFFSET, 5, c, MAX_MENU_HEIGHT);
+       if (c == -1)
+           break;
+       else switch (c) {
+        case 0:
+           currprefs.cpu_level++;
+           if (currprefs.cpu_level > 3)
+               currprefs.cpu_level = 0;
+           /* Default to 32 bit addressing when switching from a 68000/68010 to a 32 bit CPU */
+           if (currprefs.cpu_level == 2)
+               currprefs.address_space_24 = 0;
+           if (currprefs.cpu_level != 0)
+               currprefs.cpu_compatible = 0;
+           break;
+       }
+    }
+}
+
+static void SoundOptions (void)
+{
+    char tmp[256];
+    int c = 0;
+    for (;;) {
+       tui_selwin(0);
+       print_configuration ();
+       c = tui_menubrowse (soundmenu, MENU_COL_OFFSET, 5, c, MAX_MENU_HEIGHT);
+       if (c == -1)
+           break;
+       else switch (c) {
+        case 0:
+           currprefs.produce_sound++;
+           if (currprefs.produce_sound > 3)
+               currprefs.produce_sound = 0;
+           break;
+
+        case 1:
+           tui_wgets (tmp, "Enter new minimum sound buffer size in bytes", 6);
+           if (atoi (tmp) < 128 || atoi (tmp) > 65536 || atoi (tmp) > currprefs.sound_maxbsiz)
+               tui_errorbox ("Insane value for minimum sound buffer size");
+           else
+               currprefs.sound_minbsiz = atoi (tmp);
+           break;
+
+        case 2:
+           tui_wgets (tmp, "Enter new maximum sound buffer size in bytes", 6);
+           if (atoi (tmp) < 128 || atoi (tmp) > 65536 || atoi (tmp) < currprefs.sound_minbsiz)
+               tui_errorbox ("Insane value for maximum sound buffer size");
+           else
+               currprefs.sound_maxbsiz = atoi (tmp);
+           break;
+
+        case 3:
+           tui_wgets (tmp, "Enter new number of bits", 3);
+           if (atoi (tmp)!= 8 && atoi (tmp) != 16)
+               tui_errorbox ("Unsupported number of bits");
+           else
+               currprefs.sound_bits = atoi (tmp);
+           break;
+
+        case 4:
+           tui_wgets (tmp, "Enter new sound output frequency", 6);
+           if (atoi (tmp) < 11025 || atoi (tmp) > 44100)
+               tui_errorbox ("Unsupported frequency");
+           else
+               currprefs.sound_freq = atoi (tmp);
+           break;
+        case 5:
+           currprefs.stereo = (currprefs.stereo + 1) % 3;
+           break;
+       }
+    }
+}
+
+static void OtherOptions (void)
+{
+    char tmp[256];
+    int c = 0;
+
+    for (;;) {
+       tui_selwin (0);
+       print_configuration ();
+       c = tui_menubrowse (miscmenu, MENU_COL_OFFSET, 5, c, MAX_MENU_HEIGHT);
+       if (c == -1) {
+           break;
+       } else switch (c) {
+        case 0:
+           currprefs.jport0 = (currprefs.jport0 + 1) % 6;
+           if (currprefs.jport0 == currprefs.jport1)
+             currprefs.jport1 = (currprefs.jport1 + 5) % 6;          
+           break;
+        case 1:
+           currprefs.jport1 = (currprefs.jport1 + 1) % 6;
+           if (currprefs.jport0 == currprefs.jport1)
+             currprefs.jport0 = (currprefs.jport0 + 5) % 6;
+           break;
+        case 2:
+           tui_wgets (tmp, "Enter new CPU emulation speed", 6);
+           if (atoi (tmp) < 1 || atoi (tmp) > 20)
+               tui_errorbox ("Unsupported CPU emulation speed");
+           else
+               currprefs.m68k_speed = atoi (tmp);
+           break;
+       }
+    }
+}
+
+static int do_gui (int mode)
+{
+    char cwd[1024];
+
+    if (getcwd (cwd, 1024) == NULL)
+       return 0;
+
+    tui_setup ();
+
+    for (;;) {
+       int c;
+
+       tui_selwin (0);
+       print_configuration ();
+       c = tui_menubrowse (mode == 0 ? mainmenu2 : mainmenu, MENU_COL_OFFSET, 4, 0, MAX_MENU_HEIGHT);
+       if (c == -1) {
+           tui_shutdown ();
+           return -2;
+       }
+       if (mode == 1) {
+           if (c == 8)
+               break;
+           switch (c) {
+            case 0: DiskOptions (); break;
+            case 1: VideoOptions (); break;
+            case 2: MemoryOptions (); break;
+            case 3: CPUOptions (); break;
+            case 4: HDOptions (); break;
+            case 5: SoundOptions (); break;
+            case 6: OtherOptions (); break;
+            case 7: save_settings (); break;
+           }
+       } else {
+           if (c == 5)
+               break;
+           switch (c) {
+            case 0: DiskOptions (); break;
+            case 1: OtherOptions (); break;
+            case 2: save_settings (); break;
+            case 3: uae_reset (); break;
+            case 4: uae_quit (); break;
+           }
+       }
+    }
+    tui_shutdown ();
+
+    chdir (cwd);
+    return 0;
+}
+
+int gui_init (void)
+{
+    return do_gui (1);
+}
+
+void gui_changesettings (void)
+{
+    struct uae_prefs oldprefs;
+    oldprefs = currprefs;
+
+    if (do_gui(0) == -2)
+       uae_quit ();
+    else {
+       changed_prefs = currprefs;
+       currprefs = oldprefs;
+       currprefs.jport0 = changed_prefs.jport0;
+       currprefs.jport1 = changed_prefs.jport1;
+       joystick_setting_changed ();
+    }
+}
+
+int gui_update (void)
+{
+    return 0;
+}
+
+void gui_lock (void)
+{
+}
+
+void gui_unlock (void)
+{
+}
diff --git a/uaeexe.c b/uaeexe.c
new file mode 100755 (executable)
index 0000000..82af30a
--- /dev/null
+++ b/uaeexe.c
@@ -0,0 +1,123 @@
+/*
+ *  uaeexe.c - UAE remote cli
+ *
+ *  (c) 1997 by Samuel Devulder
+ */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "uae.h"
+#include "memory.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "autoconf.h"
+#include "uaeexe.h"
+
+static struct uae_xcmd *first = NULL;
+static struct uae_xcmd *last  = NULL;
+static char running = 0;
+static uae_u32 uaeexe_server(void);
+
+/*
+ * Install the server
+ */
+void uaeexe_install(void)
+{
+    uaecptr loop;
+
+    loop = here ();
+    org(UAEEXE_ORG);
+    calltrap (deftrap (uaeexe_server));
+    dw(RTS);
+    org(loop);
+}
+
+/*
+ * Send command to the remote cli.
+ *
+ * To use this, just call uaeexe("command") and the command will be
+ * executed by the remote cli (provided you've started it in the
+ * s:user-startup for example). Be sure to add "run" if you want
+ * to launch the command asynchronously. Please note also that the
+ * remote cli works better if you've got the fifo-handler installed.
+ */
+int uaeexe(char *cmd)
+{
+    struct uae_xcmd *nw;
+
+    if (!running)
+       goto NORUN;
+
+    nw = (struct uae_xcmd *)malloc (sizeof *nw);
+    if (!nw)
+       goto NOMEM;
+    nw->cmd = (char *)malloc (strlen (cmd) + 1);
+    if (!nw->cmd) {
+       free (nw);
+       goto NOMEM;
+    }
+
+    strcpy (nw->cmd, cmd);
+    nw->prev = last;
+    nw->next = NULL;
+
+    if(!first) first  = nw;
+    if(last) {
+           last->next = nw;
+           last       = nw;
+    } else last       = nw;
+
+    return UAEEXE_OK;
+  NOMEM:
+    return UAEEXE_NOMEM;
+  NORUN:
+    write_log("Remote cli is not running.\n");
+    return UAEEXE_NOTRUNNING;
+}
+
+/*
+ * returns next command to be executed
+ */
+static char *get_cmd(void)
+{
+    struct uae_xcmd *cmd;
+    char *s;
+
+    if(!first) return NULL;
+    s = first->cmd; 
+    cmd = first; first = first->next;
+    if(!first) last = NULL;
+    free(cmd);
+    return s;
+}
+
+/*
+ * helper function
+ */
+#define ARG(x) (get_long (m68k_areg (regs, 7) + 4*(x+1)))
+static uae_u32 uaeexe_server(void)
+{
+    int len;
+    char *cmd;
+    char *dst;
+
+    if(ARG(0) && !running) {
+        running = 1;
+        write_log("Remote CLI started.\n");
+    }
+
+    cmd = get_cmd(); if(!cmd) return 0;
+    if(!ARG(0)) {running = 0;return 0;}
+
+    dst = (char *)get_real_address(ARG(0));
+    len = ARG(1);
+    strncpy(dst,cmd,len);
+    printf("Sending '%s' to remote cli\n",cmd); /**/
+    free(cmd);
+    return ARG(0);
+}
+
+
diff --git a/uaelib.c b/uaelib.c
new file mode 100755 (executable)
index 0000000..965c7b7
--- /dev/null
+++ b/uaelib.c
@@ -0,0 +1,434 @@
+/*
+ * UAE - The U*nix Amiga Emulator
+ *
+ * UAE Library v0.1
+ *
+ * (c) 1996 Tauno Taipaleenmaki <tataipal@raita.oulu.fi>
+ *
+ * Change UAE parameters and other stuff from inside the emulation.
+ */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include "config.h"
+#include "options.h"
+#include "threaddep/thread.h"
+#include "uae.h"
+#include "memory.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "xwin.h"
+#include "autoconf.h"
+#include "disk.h"
+#include "debug.h"
+#include "gensound.h"
+#include "picasso96.h"
+
+/*
+ * Returns UAE Version
+ */
+static uae_u32 emulib_GetVersion (void)
+{
+    return version;
+}
+
+/*
+ * Resets your amiga
+ */
+static uae_u32 emulib_HardReset (void)
+{
+    uae_reset(0);
+    return 0;
+}
+
+static uae_u32 emulib_Reset (void)
+{
+    uae_reset(0);
+    return 0;
+}
+
+/*
+ * Enables SOUND
+ */
+static uae_u32 emulib_EnableSound (uae_u32 val)
+{
+    if (!sound_available || currprefs.produce_sound == 2)
+       return 0;
+
+    currprefs.produce_sound = val;
+    return 1;
+}
+
+/*
+ * Enables FAKE JOYSTICK
+ */
+static uae_u32 emulib_EnableJoystick (uae_u32 val)
+{
+    currprefs.jport0 = val & 255;
+    currprefs.jport1 = (val >> 8) & 255;
+    return 1;
+}
+
+/*
+ * Sets the framerate
+ */
+static uae_u32 emulib_SetFrameRate (uae_u32 val)
+{
+    if (val == 0)
+       return 0;
+    else if (val > 20)
+       return 0;
+    else {
+       currprefs.gfx_framerate = val;
+       return 1;
+    }
+}
+
+/*
+ * Changes keyboard language settings
+ */
+static uae_u32 emulib_ChangeLanguage (uae_u32 which)
+{
+    if (which > 6)
+       return 0;
+    else {
+       switch (which) {
+        case 0:
+           currprefs.keyboard_lang = KBD_LANG_US;
+           break;
+        case 1:
+           currprefs.keyboard_lang = KBD_LANG_DK;
+           break;
+        case 2:
+           currprefs.keyboard_lang = KBD_LANG_DE;
+           break;
+        case 3:
+           currprefs.keyboard_lang = KBD_LANG_SE;
+           break;
+        case 4:
+           currprefs.keyboard_lang = KBD_LANG_FR;
+           break;
+        case 5:
+           currprefs.keyboard_lang = KBD_LANG_IT;
+           break;
+        case 6:
+           currprefs.keyboard_lang = KBD_LANG_ES;
+           break;
+        default:
+           break;
+       }
+       return 1;
+    }
+}
+
+/* The following ones don't work as we never realloc the arrays... */
+/*
+ * Changes chip memory size
+ *  (reboots)
+ */
+static uae_u32 emulib_ChgCMemSize (uae_u32 memsize)
+{
+    if (memsize != 0x80000 && memsize != 0x100000 &&
+       memsize != 0x200000) {
+       memsize = 0x200000;
+       write_log ("Unsupported chipmem size!\n");
+    }
+    m68k_dreg(regs, 0) = 0;
+
+    currprefs.chipmem_size = memsize;
+    uae_reset(0);
+    return 1;
+}
+
+/*
+ * Changes slow memory size
+ *  (reboots)
+ */
+static uae_u32 emulib_ChgSMemSize (uae_u32 memsize)
+{
+    if (memsize != 0x80000 && memsize != 0x100000 &&
+       memsize != 0x180000 && memsize != 0x1C0000) {
+       memsize = 0;
+       write_log ("Unsupported bogomem size!\n");
+    }
+
+    m68k_dreg(regs, 0) = 0;
+    currprefs.bogomem_size = memsize;
+    uae_reset (0);
+    return 1;
+}
+
+/*
+ * Changes fast memory size
+ *  (reboots)
+ */
+static uae_u32 emulib_ChgFMemSize (uae_u32 memsize)
+{
+    if (memsize != 0x100000 && memsize != 0x200000 &&
+       memsize != 0x400000 && memsize != 0x800000) {
+       memsize = 0;
+       write_log ("Unsupported fastmem size!\n");
+    }
+    m68k_dreg(regs, 0) = 0;
+    currprefs.fastmem_size = memsize;
+    uae_reset (0);
+    return 0;
+}
+
+/*
+ * Inserts a disk
+ */
+static uae_u32 emulib_InsertDisk (uaecptr name, uae_u32 drive)
+{
+    int i = 0;
+    char real_name[256];
+
+    if (drive > 3)
+       return 0;
+
+    while ((real_name[i] = get_byte (name + i)) != 0 && i++ != 254)
+       ;
+
+    if (i == 255)
+       return 0; /* ENAMETOOLONG */
+
+    strcpy (changed_prefs.df[drive], real_name);
+
+    return 1;
+}
+
+/*
+ * Exits the emulator
+ */
+static uae_u32 emulib_ExitEmu (void)
+{
+    uae_quit ();
+    return 1;
+}
+
+/*
+ * Gets UAE Configuration
+ */
+static uae_u32 emulib_GetUaeConfig (uaecptr place)
+{
+    int i;
+
+    put_long (place, version);
+    put_long (place + 4, allocated_chipmem);
+    put_long (place + 8, allocated_bogomem);
+    put_long (place + 12, allocated_fastmem);
+    put_long (place + 16, currprefs.gfx_framerate);
+    put_long (place + 20, currprefs.produce_sound);
+    put_long (place + 24, currprefs.jport0 | (currprefs.jport1 << 8));
+    put_long (place + 28, currprefs.keyboard_lang);
+    if (disk_empty (0))
+       put_byte (place + 32, 0);
+    else
+       put_byte (place + 32, 1);
+    if (disk_empty (1))
+       put_byte (place + 33, 0);
+    else
+       put_byte (place + 33, 1);
+    if (disk_empty(2))
+       put_byte (place + 34, 0);
+    else
+       put_byte (place + 34, 1);
+    if (disk_empty(3))
+       put_byte (place + 35, 0);
+    else
+       put_byte (place + 35, 1);
+
+    for (i = 0; i < 256; i++) {
+       put_byte ((place + 36 + i), currprefs.df[0][i]);
+       put_byte ((place + 36 + i + 256), currprefs.df[1][i]);
+       put_byte ((place + 36 + i + 512), currprefs.df[2][i]);
+       put_byte ((place + 36 + i + 768), currprefs.df[3][i]);
+    }
+    return 1;
+}
+
+/*
+ * Sets UAE Configuration
+ *
+ * NOT IMPLEMENTED YET
+ */
+static uae_u32 emulib_SetUaeConfig (uaecptr place)
+{
+    return 1;
+}
+
+/*
+ * Gets the name of the disk in the given drive
+ */
+static uae_u32 emulib_GetDisk (uae_u32 drive, uaecptr name)
+{
+    int i;
+    if (drive > 3)
+       return 0;
+
+    for (i = 0;i < 256; i++) {
+       put_byte (name + i, currprefs.df[drive][i]);
+    }
+    return 1;
+}
+
+/*
+ * Enter debugging state
+ */
+static uae_u32 emulib_Debug (void)
+{
+    activate_debugger ();
+    return 1;
+}
+
+/* We simply find the first "text" hunk, get the offset of its actual code segment (20 bytes away)
+ * and add that offset to the base address of the object.  Now we've got code to execute.
+ *
+ * @@@ Brian: does anything actually use this yet?
+ * @@@ Bernd: Not yet.  It needs to get much better.  Should spawn off a seperate task to handle the
+ *            function, and then somehow "signal" the Amiga caller that completion or error has
+ *            occurred.  I don't know how to do that, so right now it is a synchronous call.  Yuck!
+ *            Would be nice to implement jpg decompression functionality for the Amiga which used
+ *            the UAE Host to do all the work, for example.
+ * @@@ Brian: I disabled it to prevent people from starting to use it - if that happens, we're
+ *            stuck with this.
+ */
+static uae_u32 FindFunctionInObject (uae_u8 *objectptr)
+{
+    uae_u8 *text_hdr;
+    uae_u8 offset;
+    text_hdr = (uae_u8 *)strstr ("text", (char *)objectptr);
+    if (text_hdr != 0) {
+       offset = *(text_hdr + 19);
+       return (uae_u32)(objectptr + offset);
+    }
+    return 0;
+}
+
+#define CREATE_NATIVE_FUNC_PTR uae_u32 (* native_func)( uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, \
+                                                uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32)
+#define SET_NATIVE_FUNC(x) native_func = (uae_u32 (*)(uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32))(x)
+#define CALL_NATIVE_FUNC( d1,d2,d3,d4,d5,d6,d7,a1,a2,a3,a4,a5,a6 ) if(native_func) native_func( d1,d2,d3,d4,d5,d6,d7,a1,a2,a3,a4,a5,a6 )
+/* A0 - Contains a ptr to the native .obj data.  This ptr is Amiga-based. */
+/*      We simply find the first function in this .obj data, and execute it. */
+static uae_u32 emulib_ExecuteNativeCode (void)
+{
+#if 0
+    uaecptr object_AAM = m68k_areg( regs, 0 );
+    uae_u32 d1 = m68k_dreg( regs, 1 );
+    uae_u32 d2 = m68k_dreg( regs, 2 );
+    uae_u32 d3 = m68k_dreg( regs, 3 );
+    uae_u32 d4 = m68k_dreg( regs, 4 );
+    uae_u32 d5 = m68k_dreg( regs, 5 );
+    uae_u32 d6 = m68k_dreg( regs, 6 );
+    uae_u32 d7 = m68k_dreg( regs, 7 );
+    uae_u32 a1 = m68k_areg( regs, 1 );
+    uae_u32 a2 = m68k_areg( regs, 2 );
+    uae_u32 a3 = m68k_areg( regs, 3 );
+    uae_u32 a4 = m68k_areg( regs, 4 );
+    uae_u32 a5 = m68k_areg( regs, 5 );
+    uae_u32 a6 = m68k_areg( regs, 6 );
+
+    uae_u8* object_UAM = NULL;
+    CREATE_NATIVE_FUNC_PTR;
+
+    if( get_mem_bank( object_AAM ).check( object_AAM, 1 ) )
+       object_UAM = get_mem_bank( object_AAM).xlateaddr( object_AAM );
+
+    if( object_UAM )
+    {
+       SET_NATIVE_FUNC( FindFunctionInObject( object_UAM ) );
+       CALL_NATIVE_FUNC( d1, d2, d3, d4, d5, d6, d7, a1, a2, a3, a4, a5, a6);
+    }
+    return 1;
+#endif
+    return 0;
+}
+
+static uae_u32 emulib_Minimize (void)
+{
+    return OSDEP_minimize_uae();
+}
+
+static uae_u32 uaelib_demux (void)
+{
+#define ARG0 (get_long (m68k_areg (regs, 7) + 4))
+#define ARG1 (get_long (m68k_areg (regs, 7) + 8))
+#define ARG2 (get_long (m68k_areg (regs, 7) + 12))
+#define ARG3 (get_long (m68k_areg (regs, 7) + 16))
+#define ARG4 (get_long (m68k_areg (regs, 7) + 20))
+
+    switch (ARG0) {
+     case 0: return emulib_GetVersion ();
+     case 1: return emulib_GetUaeConfig (ARG1);
+     case 2: return emulib_SetUaeConfig (ARG1);
+     case 3: return emulib_HardReset ();
+     case 4: return emulib_Reset ();
+     case 5: return emulib_InsertDisk (ARG1, ARG2);
+     case 6: return emulib_EnableSound (ARG1);
+     case 7: return emulib_EnableJoystick (ARG1);
+     case 8: return emulib_SetFrameRate (ARG1);
+     case 9: return emulib_ChgCMemSize (ARG1);
+     case 10: return emulib_ChgSMemSize (ARG1);
+     case 11: return emulib_ChgFMemSize (ARG1);
+     case 12: return emulib_ChangeLanguage (ARG1);
+       /* The next call brings bad luck */
+     case 13: return emulib_ExitEmu ();
+     case 14: return emulib_GetDisk (ARG1, ARG2);
+     case 15: return emulib_Debug ();
+
+#ifdef PICASSO96
+     case 16: return picasso_FindCard ();
+     case 17: return picasso_FillRect ();
+     case 18: return picasso_SetSwitch ();
+     case 19: return picasso_SetColorArray ();
+     case 20: return picasso_SetDAC ();
+     case 21: return picasso_SetGC ();
+     case 22: return picasso_SetPanning ();
+     case 23: return picasso_CalculateBytesPerRow ();
+     case 24: return picasso_BlitPlanar2Chunky ();
+     case 25: return picasso_BlitRect ();
+     case 26: return picasso_SetDisplay ();
+     case 27: return picasso_BlitTemplate ();
+     case 28: return picasso_BlitRectNoMaskComplete ();
+     case 29: return picasso_InitCard ();
+     case 30: return picasso_BlitPattern ();
+     case 31: return picasso_InvertRect ();
+     case 32: return picasso_BlitPlanar2Direct ();
+     /* case 34: return picasso_WaitVerticalSync (); handled in asm-code */
+     case 35: return allocated_gfxmem ? 1 : 0;
+#ifdef HARDWARE_SPRITE_EMULATION
+     case 36: return picasso_SetSprite ();
+     case 37: return picasso_SetSpritePosition ();
+     case 38: return picasso_SetSpriteImage ();
+     case 39: return picasso_SetSpriteColor ();
+#endif
+     case 40: return picasso_DrawLine ();
+#endif
+     case 68: return emulib_Minimize ();
+     case 69: return emulib_ExecuteNativeCode ();
+
+     case 80: return currprefs.maprom ? currprefs.maprom : 0xffffffff;
+     case 81: return cfgfile_uaelib (ARG1, ARG2, ARG3, ARG4);
+    }
+    return 0;
+}
+
+/*
+ * Installs the UAE LIBRARY
+ */
+void emulib_install (void)
+{
+    uaecptr a = here ();
+    org (RTAREA_BASE + 0xFF60);
+    dw (0x4eb9);
+    dw ((RTAREA_BASE >> 16) | get_word(RTAREA_BASE + 36));
+    dw (get_word(RTAREA_BASE + 38) + 12);
+    calltrap (deftrap (uaelib_demux));
+    dw (RTS);
+    org (a);
+}
diff --git a/unzip.c b/unzip.c
new file mode 100755 (executable)
index 0000000..e311918
--- /dev/null
+++ b/unzip.c
@@ -0,0 +1,1283 @@
+/* unzip.c -- IO on .zip files using zlib 
+   Version 0.15 beta, Mar 19th, 1998,
+
+   Read unzip.h for more info
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "zlib.h"
+#include "unzip.h"
+#include "zfile.h"
+
+#ifdef STDC
+#  include <stddef.h>
+#  include <string.h>
+#  include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+    extern int errno;
+#else
+#   include <errno.h>
+#endif
+
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+
+
+#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \
+                      !defined(CASESENSITIVITYDEFAULT_NO)
+#define CASESENSITIVITYDEFAULT_NO
+#endif
+
+
+#ifndef UNZ_BUFSIZE
+#define UNZ_BUFSIZE (16384)
+#endif
+
+#ifndef UNZ_MAXFILENAMEINZIP
+#define UNZ_MAXFILENAMEINZIP (256)
+#endif
+
+#ifndef ALLOC
+# define ALLOC(size) (malloc(size))
+#endif
+#ifndef TRYFREE
+# define TRYFREE(p) {if (p) free(p);}
+#endif
+
+#define SIZECENTRALDIRITEM (0x2e)
+#define SIZEZIPLOCALHEADER (0x1e)
+
+
+/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
+
+#ifndef SEEK_CUR
+#define SEEK_CUR    1
+#endif
+
+#ifndef SEEK_END
+#define SEEK_END    2
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET    0
+#endif
+
+const char unz_copyright[] =
+   " unzip 0.15 Copyright 1998 Gilles Vollant ";
+
+/* unz_file_info_interntal contain internal info about a file in zipfile*/
+typedef struct unz_file_info_internal_s
+{
+    uLong offset_curfile;/* relative offset of local header 4 bytes */
+} unz_file_info_internal;
+
+
+/* file_in_zip_read_info_s contain internal information about a file in zipfile,
+    when reading and decompress it */
+typedef struct
+{
+       char  *read_buffer;         /* internal buffer for compressed data */
+       z_stream stream;            /* zLib stream structure for inflate */
+
+       uLong pos_in_zipfile;       /* position in byte on the zipfile, for fseek*/
+       uLong stream_initialised;   /* flag set if stream structure is initialised*/
+
+       uLong offset_local_extrafield;/* offset of the local extra field */
+       uInt  size_local_extrafield;/* size of the local extra field */
+       uLong pos_local_extrafield;   /* position in the local extra field in read*/
+
+       uLong crc32;                /* crc32 of all data uncompressed */
+       uLong crc32_wait;           /* crc32 we must obtain after decompress all */
+       uLong rest_read_compressed; /* number of byte to be decompressed */
+       uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/
+       struct zfile *file;                 /* io structore of the zipfile */
+       uLong compression_method;   /* compression method (0==store) */
+       uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
+} file_in_zip_read_info_s;
+
+
+/* unz_s contain internal information about the zipfile
+*/
+typedef struct
+{
+       struct zfile* file;                 /* io structore of the zipfile */
+       unz_global_info gi;       /* public global information */
+       uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
+       uLong num_file;             /* number of the current file in the zipfile*/
+       uLong pos_in_central_dir;   /* pos of the current file in the central dir*/
+       uLong current_file_ok;      /* flag about the usability of the current file*/
+       uLong central_pos;          /* position of the beginning of the central dir*/
+
+       uLong size_central_dir;     /* size of the central directory  */
+       uLong offset_central_dir;   /* offset of start of central directory with
+                                                                  respect to the starting disk number */
+
+       unz_file_info cur_file_info; /* public info about the current file in zip*/
+       unz_file_info_internal cur_file_info_internal; /* private info about it*/
+    file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current
+                                           file if we are decompressing it */
+} unz_s;
+
+
+/* ===========================================================================
+     Read a byte from a gz_stream; update next_in and avail_in. Return EOF
+   for end of file.
+   IN assertion: the stream s has been sucessfully opened for reading.
+*/
+
+
+local int unzlocal_getByte(fin,pi)
+       struct zfile *fin;
+       int *pi;
+{
+    unsigned char c;
+       int err = zfile_fread(&c, 1, 1, fin);
+    if (err==1)
+    {
+        *pi = (int)c;
+        return UNZ_OK;
+    }
+    else
+    {
+               return UNZ_EOF;
+    }
+}
+
+
+/* ===========================================================================
+   Reads a long in LSB order from the given gz_stream. Sets 
+*/
+local int unzlocal_getShort (fin,pX)
+       struct zfile* fin;
+    uLong *pX;
+{
+    uLong x ;
+    int i;
+    int err;
+
+    err = unzlocal_getByte(fin,&i);
+    x = (uLong)i;
+    
+    if (err==UNZ_OK)
+        err = unzlocal_getByte(fin,&i);
+    x += ((uLong)i)<<8;
+   
+    if (err==UNZ_OK)
+        *pX = x;
+    else
+        *pX = 0;
+    return err;
+}
+
+local int unzlocal_getLong (fin,pX)
+       struct zfile* fin;
+    uLong *pX;
+{
+    uLong x ;
+    int i;
+    int err;
+
+    err = unzlocal_getByte(fin,&i);
+    x = (uLong)i;
+    
+    if (err==UNZ_OK)
+        err = unzlocal_getByte(fin,&i);
+    x += ((uLong)i)<<8;
+
+    if (err==UNZ_OK)
+        err = unzlocal_getByte(fin,&i);
+    x += ((uLong)i)<<16;
+
+    if (err==UNZ_OK)
+        err = unzlocal_getByte(fin,&i);
+    x += ((uLong)i)<<24;
+   
+    if (err==UNZ_OK)
+        *pX = x;
+    else
+        *pX = 0;
+    return err;
+}
+
+
+/* My own strcmpi / strcasecmp */
+local int strcmpcasenosensitive_internal (fileName1,fileName2)
+       const char* fileName1;
+       const char* fileName2;
+{
+       for (;;)
+       {
+               char c1=*(fileName1++);
+               char c2=*(fileName2++);
+               if ((c1>='a') && (c1<='z'))
+                       c1 -= 0x20;
+               if ((c2>='a') && (c2<='z'))
+                       c2 -= 0x20;
+               if (c1=='\0')
+                       return ((c2=='\0') ? 0 : -1);
+               if (c2=='\0')
+                       return 1;
+               if (c1<c2)
+                       return -1;
+               if (c1>c2)
+                       return 1;
+       }
+}
+
+
+#ifdef  CASESENSITIVITYDEFAULT_NO
+#define CASESENSITIVITYDEFAULTVALUE 2
+#else
+#define CASESENSITIVITYDEFAULTVALUE 1
+#endif
+
+#ifndef STRCMPCASENOSENTIVEFUNCTION
+#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal
+#endif
+
+/* 
+   Compare two filename (fileName1,fileName2).
+   If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
+   If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
+                                                                or strcasecmp)
+   If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
+        (like 1 on Unix, 2 on Windows)
+
+*/
+extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity)
+       const char* fileName1;
+       const char* fileName2;
+       int iCaseSensitivity;
+{
+       if (iCaseSensitivity==0)
+               iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE;
+
+       if (iCaseSensitivity==1)
+               return strcmp(fileName1,fileName2);
+
+       return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2);
+} 
+
+#define BUFREADCOMMENT (0x400)
+
+/*
+  Locate the Central directory of a zipfile (at the end, just before
+    the global comment)
+*/
+local uLong unzlocal_SearchCentralDir(fin)
+       struct zfile *fin;
+{
+       unsigned char* buf;
+       uLong uSizeFile;
+       uLong uBackRead;
+       uLong uMaxBack=0xffff; /* maximum size of global comment */
+       uLong uPosFound=0;
+       
+       if (zfile_fseek(fin,0,SEEK_END) != 0)
+               return 0;
+
+
+       uSizeFile = zfile_ftell( fin );
+       
+       if (uMaxBack>uSizeFile)
+               uMaxBack = uSizeFile;
+
+       buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
+       if (buf==NULL)
+               return 0;
+
+       uBackRead = 4;
+       while (uBackRead<uMaxBack)
+       {
+               uLong uReadSize,uReadPos ;
+               int i;
+               if (uBackRead+BUFREADCOMMENT>uMaxBack) 
+                       uBackRead = uMaxBack;
+               else
+                       uBackRead+=BUFREADCOMMENT;
+               uReadPos = uSizeFile-uBackRead ;
+               
+               uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? 
+                     (BUFREADCOMMENT+4) : (uSizeFile-uReadPos);
+               if (zfile_fseek(fin,uReadPos,SEEK_SET)!=0)
+                       break;
+
+               if (zfile_fread(buf,(uInt)uReadSize,1,fin)!=1)
+                       break;
+
+                for (i=(int)uReadSize-3; (i--)>0;)
+                       if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && 
+                               ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
+                       {
+                               uPosFound = uReadPos+i;
+                               break;
+                       }
+
+               if (uPosFound!=0)
+                       break;
+       }
+       TRYFREE(buf);
+       return uPosFound;
+}
+
+/*
+  Open a Zip file. path contain the full pathname (by example,
+     on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer
+        "zlib/zlib109.zip".
+        If the zipfile cannot be opened (file don't exist or in not valid), the
+          return value is NULL.
+     Else, the return value is a unzFile Handle, usable with other function
+          of this unzip package.
+*/
+extern unzFile ZEXPORT unzOpen (fin)
+       struct zfile *fin;
+{
+       unz_s us;
+       unz_s *s;
+       uLong central_pos,uL;
+
+       uLong number_disk;          /* number of the current dist, used for 
+                                                                  spaning ZIP, unsupported, always 0*/
+       uLong number_disk_with_CD;  /* number the the disk with central dir, used
+                                                                  for spaning ZIP, unsupported, always 0*/
+       uLong number_entry_CD;      /* total number of entries in
+                                      the central dir 
+                                      (same than number_entry on nospan) */
+
+       int err=UNZ_OK;
+
+    if (unz_copyright[0]!=' ')
+        return NULL;
+
+       central_pos = unzlocal_SearchCentralDir(fin);
+       if (central_pos==0)
+               err=UNZ_ERRNO;
+
+       if (zfile_fseek(fin,central_pos,SEEK_SET)!=0)
+               err=UNZ_ERRNO;
+
+       /* the signature, already checked */
+       if (unzlocal_getLong(fin,&uL)!=UNZ_OK)
+               err=UNZ_ERRNO;
+
+       /* number of this disk */
+       if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK)
+               err=UNZ_ERRNO;
+
+       /* number of the disk with the start of the central directory */
+       if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK)
+               err=UNZ_ERRNO;
+
+       /* total number of entries in the central dir on this disk */
+       if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK)
+               err=UNZ_ERRNO;
+
+       /* total number of entries in the central dir */
+       if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if ((number_entry_CD!=us.gi.number_entry) ||
+               (number_disk_with_CD!=0) ||
+               (number_disk!=0))
+               err=UNZ_BADZIPFILE;
+
+       /* size of the central directory */
+       if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK)
+               err=UNZ_ERRNO;
+
+       /* offset of start of central directory with respect to the 
+             starting disk number */
+       if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK)
+               err=UNZ_ERRNO;
+
+       /* zipfile comment length */
+       if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if ((central_pos<us.offset_central_dir+us.size_central_dir) && 
+               (err==UNZ_OK))
+               err=UNZ_BADZIPFILE;
+
+       if (err!=UNZ_OK)
+               return NULL;
+
+       us.file=fin;
+       us.byte_before_the_zipfile = central_pos -
+                                   (us.offset_central_dir+us.size_central_dir);
+       us.central_pos = central_pos;
+    us.pfile_in_zip_read = NULL;
+       
+
+       s=(unz_s*)ALLOC(sizeof(unz_s));
+       *s=us;
+       unzGoToFirstFile((unzFile)s);   
+       return (unzFile)s;      
+}
+
+
+/*
+  Close a ZipFile opened with unzipOpen.
+  If there is files inside the .Zip opened with unzipOpenCurrentFile (see later),
+    these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
+  return UNZ_OK if there is no problem. */
+extern int ZEXPORT unzClose (file)
+       unzFile file;
+{
+       unz_s* s;
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+
+    if (s->pfile_in_zip_read!=NULL)
+        unzCloseCurrentFile(file);
+
+       zfile_fclose(s->file);
+       TRYFREE(s);
+       return UNZ_OK;
+}
+
+
+/*
+  Write info about the ZipFile in the *pglobal_info structure.
+  No preparation of the structure is needed
+  return UNZ_OK if there is no problem. */
+extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info)
+       unzFile file;
+       unz_global_info *pglobal_info;
+{
+       unz_s* s;
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+       *pglobal_info=s->gi;
+       return UNZ_OK;
+}
+
+
+/*
+   Translate date/time from Dos format to tm_unz (readable more easilty)
+*/
+local void unzlocal_DosDateToTmuDate (ulDosDate, ptm)
+    uLong ulDosDate;
+    tm_unz* ptm;
+{
+    uLong uDate;
+    uDate = (uLong)(ulDosDate>>16);
+    ptm->tm_mday = (uInt)(uDate&0x1f) ;
+    ptm->tm_mon =  (uInt)((((uDate)&0x1E0)/0x20)-1) ;
+    ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ;
+
+    ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800);
+    ptm->tm_min =  (uInt) ((ulDosDate&0x7E0)/0x20) ;
+    ptm->tm_sec =  (uInt) (2*(ulDosDate&0x1f)) ;
+}
+
+/*
+  Get Info about the current file in the zipfile, with internal only info
+*/
+local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file,
+                                                  unz_file_info *pfile_info,
+                                                  unz_file_info_internal 
+                                                  *pfile_info_internal,
+                                                  char *szFileName,
+                                                                                                 uLong fileNameBufferSize,
+                                                  void *extraField,
+                                                                                                 uLong extraFieldBufferSize,
+                                                  char *szComment,
+                                                                                                 uLong commentBufferSize));
+
+local int unzlocal_GetCurrentFileInfoInternal (file,
+                                              pfile_info,
+                                              pfile_info_internal,
+                                              szFileName, fileNameBufferSize,
+                                              extraField, extraFieldBufferSize,
+                                              szComment,  commentBufferSize)
+       unzFile file;
+       unz_file_info *pfile_info;
+       unz_file_info_internal *pfile_info_internal;
+       char *szFileName;
+       uLong fileNameBufferSize;
+       void *extraField;
+       uLong extraFieldBufferSize;
+       char *szComment;
+       uLong commentBufferSize;
+{
+       unz_s* s;
+       unz_file_info file_info;
+       unz_file_info_internal file_info_internal;
+       int err=UNZ_OK;
+       uLong uMagic;
+       long lSeek=0;
+
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+       if (zfile_fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0)
+               err=UNZ_ERRNO;
+
+
+       /* we check the magic */
+       if (err==UNZ_OK)
+               if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK)
+                       err=UNZ_ERRNO;
+               else if (uMagic!=0x02014b50)
+                       err=UNZ_BADZIPFILE;
+
+       if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+    unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);
+
+       if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       lSeek+=file_info.size_filename;
+       if ((err==UNZ_OK) && (szFileName!=NULL))
+       {
+               uLong uSizeRead ;
+               if (file_info.size_filename<fileNameBufferSize)
+               {
+                       *(szFileName+file_info.size_filename)='\0';
+                       uSizeRead = file_info.size_filename;
+               }
+               else
+                       uSizeRead = fileNameBufferSize;
+
+               if ((file_info.size_filename>0) && (fileNameBufferSize>0))
+                       if (zfile_fread(szFileName,(uInt)uSizeRead,1,s->file)!=1)
+                               err=UNZ_ERRNO;
+               lSeek -= uSizeRead;
+       }
+
+       
+       if ((err==UNZ_OK) && (extraField!=NULL))
+       {
+               uLong uSizeRead ;
+               if (file_info.size_file_extra<extraFieldBufferSize)
+                       uSizeRead = file_info.size_file_extra;
+               else
+                       uSizeRead = extraFieldBufferSize;
+
+               if (lSeek!=0)
+                       if (zfile_fseek(s->file,lSeek,SEEK_CUR)==0)
+                               lSeek=0;
+                       else
+                               err=UNZ_ERRNO;
+               if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
+                       if (zfile_fread(extraField,(uInt)uSizeRead,1,s->file)!=1)
+                               err=UNZ_ERRNO;
+               lSeek += file_info.size_file_extra - uSizeRead;
+       }
+       else
+               lSeek+=file_info.size_file_extra; 
+
+       
+       if ((err==UNZ_OK) && (szComment!=NULL))
+       {
+               uLong uSizeRead ;
+               if (file_info.size_file_comment<commentBufferSize)
+               {
+                       *(szComment+file_info.size_file_comment)='\0';
+                       uSizeRead = file_info.size_file_comment;
+               }
+               else
+                       uSizeRead = commentBufferSize;
+
+               if (lSeek!=0)
+                       if (zfile_fseek(s->file,lSeek,SEEK_CUR)==0)
+                               lSeek=0;
+                       else
+                               err=UNZ_ERRNO;
+               if ((file_info.size_file_comment>0) && (commentBufferSize>0))
+                       if (zfile_fread(szComment,(uInt)uSizeRead,1,s->file)!=1)
+                               err=UNZ_ERRNO;
+               lSeek+=file_info.size_file_comment - uSizeRead;
+       }
+       else
+               lSeek+=file_info.size_file_comment;
+
+       if ((err==UNZ_OK) && (pfile_info!=NULL))
+               *pfile_info=file_info;
+
+       if ((err==UNZ_OK) && (pfile_info_internal!=NULL))
+               *pfile_info_internal=file_info_internal;
+
+       return err;
+}
+
+
+
+/*
+  Write info about the ZipFile in the *pglobal_info structure.
+  No preparation of the structure is needed
+  return UNZ_OK if there is no problem.
+*/
+extern int ZEXPORT unzGetCurrentFileInfo (file,
+                                                  pfile_info,
+                                                  szFileName, fileNameBufferSize,
+                                                  extraField, extraFieldBufferSize,
+                                                  szComment,  commentBufferSize)
+       unzFile file;
+       unz_file_info *pfile_info;
+       char *szFileName;
+       uLong fileNameBufferSize;
+       void *extraField;
+       uLong extraFieldBufferSize;
+       char *szComment;
+       uLong commentBufferSize;
+{
+       return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL,
+                                                                                               szFileName,fileNameBufferSize,
+                                                                                               extraField,extraFieldBufferSize,
+                                                                                               szComment,commentBufferSize);
+}
+
+/*
+  Set the current file of the zipfile to the first file.
+  return UNZ_OK if there is no problem
+*/
+extern int ZEXPORT unzGoToFirstFile (file)
+       unzFile file;
+{
+       int err=UNZ_OK;
+       unz_s* s;
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+       s->pos_in_central_dir=s->offset_central_dir;
+       s->num_file=0;
+       err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+                                                                                        &s->cur_file_info_internal,
+                                                                                        NULL,0,NULL,0,NULL,0);
+       s->current_file_ok = (err == UNZ_OK);
+       return err;
+}
+
+
+/*
+  Set the current file of the zipfile to the next file.
+  return UNZ_OK if there is no problem
+  return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
+*/
+extern int ZEXPORT unzGoToNextFile (file)
+       unzFile file;
+{
+       unz_s* s;       
+       int err;
+
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+       if (!s->current_file_ok)
+               return UNZ_END_OF_LIST_OF_FILE;
+       if (s->num_file+1==s->gi.number_entry)
+               return UNZ_END_OF_LIST_OF_FILE;
+
+       s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
+                       s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ;
+       s->num_file++;
+       err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+                                                                                          &s->cur_file_info_internal,
+                                                                                          NULL,0,NULL,0,NULL,0);
+       s->current_file_ok = (err == UNZ_OK);
+       return err;
+}
+
+
+/*
+  Try locate the file szFileName in the zipfile.
+  For the iCaseSensitivity signification, see unzipStringFileNameCompare
+
+  return value :
+  UNZ_OK if the file is found. It becomes the current file.
+  UNZ_END_OF_LIST_OF_FILE if the file is not found
+*/
+extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity)
+       unzFile file;
+       const char *szFileName;
+       int iCaseSensitivity;
+{
+       unz_s* s;       
+       int err;
+
+       
+       uLong num_fileSaved;
+       uLong pos_in_central_dirSaved;
+
+
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+
+    if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP)
+        return UNZ_PARAMERROR;
+
+       s=(unz_s*)file;
+       if (!s->current_file_ok)
+               return UNZ_END_OF_LIST_OF_FILE;
+
+       num_fileSaved = s->num_file;
+       pos_in_central_dirSaved = s->pos_in_central_dir;
+
+       err = unzGoToFirstFile(file);
+
+       while (err == UNZ_OK)
+       {
+               char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
+               unzGetCurrentFileInfo(file,NULL,
+                                                               szCurrentFileName,sizeof(szCurrentFileName)-1,
+                                                               NULL,0,NULL,0);
+               if (unzStringFileNameCompare(szCurrentFileName,
+                                                                               szFileName,iCaseSensitivity)==0)
+                       return UNZ_OK;
+               err = unzGoToNextFile(file);
+       }
+
+       s->num_file = num_fileSaved ;
+       s->pos_in_central_dir = pos_in_central_dirSaved ;
+       return err;
+}
+
+
+/*
+  Read the local header of the current zipfile
+  Check the coherency of the local header and info in the end of central
+        directory about this file
+  store in *piSizeVar the size of extra info in local header
+        (filename and size of extra field data)
+*/
+local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar,
+                                                                                                       poffset_local_extrafield,
+                                                                                                       psize_local_extrafield)
+       unz_s* s;
+       uInt* piSizeVar;
+       uLong *poffset_local_extrafield;
+       uInt  *psize_local_extrafield;
+{
+       uLong uMagic,uData,uFlags;
+       uLong size_filename;
+       uLong size_extra_field;
+       int err=UNZ_OK;
+
+       *piSizeVar = 0;
+       *poffset_local_extrafield = 0;
+       *psize_local_extrafield = 0;
+
+       if (zfile_fseek(s->file,s->cur_file_info_internal.offset_curfile +
+                                                               s->byte_before_the_zipfile,SEEK_SET)!=0)
+               return UNZ_ERRNO;
+
+
+       if (err==UNZ_OK)
+               if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK)
+                       err=UNZ_ERRNO;
+               else if (uMagic!=0x04034b50)
+                       err=UNZ_BADZIPFILE;
+
+       if (unzlocal_getShort(s->file,&uData) != UNZ_OK)
+               err=UNZ_ERRNO;
+/*
+       else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))
+               err=UNZ_BADZIPFILE;
+*/
+       if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&uData) != UNZ_OK)
+               err=UNZ_ERRNO;
+       else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))
+               err=UNZ_BADZIPFILE;
+
+    if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&
+                         (s->cur_file_info.compression_method!=Z_DEFLATED))
+        err=UNZ_BADZIPFILE;
+
+       if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */
+               err=UNZ_ERRNO;
+       else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) &&
+                                     ((uFlags & 8)==0))
+               err=UNZ_BADZIPFILE;
+
+       if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */
+               err=UNZ_ERRNO;
+/*     else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) &&
+                                                         ((uFlags & 8)==0))
+               err=UNZ_BADZIPFILE;
+*/
+       if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */
+               err=UNZ_ERRNO;
+/*     else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && 
+                                                         ((uFlags & 8)==0))
+               err=UNZ_BADZIPFILE;
+*/
+
+       if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK)
+               err=UNZ_ERRNO;
+       else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))
+               err=UNZ_BADZIPFILE;
+
+       *piSizeVar += (uInt)size_filename;
+
+       if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK)
+               err=UNZ_ERRNO;
+       *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile +
+                                                                       SIZEZIPLOCALHEADER + size_filename;
+       *psize_local_extrafield = (uInt)size_extra_field;
+
+       *piSizeVar += (uInt)size_extra_field;
+
+       return err;
+}
+                                                                                               
+/*
+  Open for reading data the current file in the zipfile.
+  If there is no error and the file is opened, the return value is UNZ_OK.
+*/
+extern int ZEXPORT unzOpenCurrentFile (file)
+       unzFile file;
+{
+       int err=UNZ_OK;
+       int Store;
+       uInt iSizeVar;
+       unz_s* s;
+       file_in_zip_read_info_s* pfile_in_zip_read_info;
+       uLong offset_local_extrafield;  /* offset of the local extra field */
+       uInt  size_local_extrafield;    /* size of the local extra field */
+
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+       if (!s->current_file_ok)
+               return UNZ_PARAMERROR;
+
+    if (s->pfile_in_zip_read != NULL)
+        unzCloseCurrentFile(file);
+
+       if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar,
+                               &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)
+               return UNZ_BADZIPFILE;
+
+       pfile_in_zip_read_info = (file_in_zip_read_info_s*)
+                                                                           ALLOC(sizeof(file_in_zip_read_info_s));
+       if (pfile_in_zip_read_info==NULL)
+               return UNZ_INTERNALERROR;
+
+       pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE);
+       pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
+       pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
+       pfile_in_zip_read_info->pos_local_extrafield=0;
+
+       if (pfile_in_zip_read_info->read_buffer==NULL)
+       {
+               TRYFREE(pfile_in_zip_read_info);
+               return UNZ_INTERNALERROR;
+       }
+
+       pfile_in_zip_read_info->stream_initialised=0;
+       
+       if ((s->cur_file_info.compression_method!=0) &&
+        (s->cur_file_info.compression_method!=Z_DEFLATED))
+               err=UNZ_BADZIPFILE;
+       Store = s->cur_file_info.compression_method==0;
+
+       pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;
+       pfile_in_zip_read_info->crc32=0;
+       pfile_in_zip_read_info->compression_method =
+            s->cur_file_info.compression_method;
+       pfile_in_zip_read_info->file=s->file;
+       pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile;
+
+    pfile_in_zip_read_info->stream.total_out = 0;
+
+       if (!Store)
+       {
+         pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
+         pfile_in_zip_read_info->stream.zfree = (free_func)0;
+         pfile_in_zip_read_info->stream.opaque = (voidpf)0; 
+      
+         err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
+         if (err == Z_OK)
+           pfile_in_zip_read_info->stream_initialised=1;
+        /* windowBits is passed < 0 to tell that there is no zlib header.
+         * Note that in this case inflate *requires* an extra "dummy" byte
+         * after the compressed stream in order to complete decompression and
+         * return Z_STREAM_END. 
+         * In unzip, i don't wait absolutely Z_STREAM_END because I known the 
+         * size of both compressed and uncompressed data
+         */
+       }
+       pfile_in_zip_read_info->rest_read_compressed = 
+            s->cur_file_info.compressed_size ;
+       pfile_in_zip_read_info->rest_read_uncompressed = 
+            s->cur_file_info.uncompressed_size ;
+
+       
+       pfile_in_zip_read_info->pos_in_zipfile = 
+            s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + 
+                         iSizeVar;
+       
+       pfile_in_zip_read_info->stream.avail_in = (uInt)0;
+
+
+       s->pfile_in_zip_read = pfile_in_zip_read_info;
+    return UNZ_OK;
+}
+
+
+/*
+  Read bytes from the current file.
+  buf contain buffer where data must be copied
+  len the size of buf.
+
+  return the number of byte copied if somes bytes are copied
+  return 0 if the end of file was reached
+  return <0 with error code if there is an error
+    (UNZ_ERRNO for IO error, or zLib error for uncompress error)
+*/
+extern int ZEXPORT unzReadCurrentFile  (file, buf, len)
+       unzFile file;
+       voidp buf;
+       unsigned len;
+{
+       int err=UNZ_OK;
+       uInt iRead = 0;
+       unz_s* s;
+       file_in_zip_read_info_s* pfile_in_zip_read_info;
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+    pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+       if (pfile_in_zip_read_info==NULL)
+               return UNZ_PARAMERROR;
+
+
+       if ((pfile_in_zip_read_info->read_buffer == NULL))
+               return UNZ_END_OF_LIST_OF_FILE;
+       if (len==0)
+               return 0;
+
+       pfile_in_zip_read_info->stream.next_out = (Bytef*)buf;
+
+       pfile_in_zip_read_info->stream.avail_out = (uInt)len;
+       
+       if (len>pfile_in_zip_read_info->rest_read_uncompressed)
+               pfile_in_zip_read_info->stream.avail_out = 
+                 (uInt)pfile_in_zip_read_info->rest_read_uncompressed;
+
+       while (pfile_in_zip_read_info->stream.avail_out>0)
+       {
+               if ((pfile_in_zip_read_info->stream.avail_in==0) &&
+            (pfile_in_zip_read_info->rest_read_compressed>0))
+               {
+                       uInt uReadThis = UNZ_BUFSIZE;
+                       if (pfile_in_zip_read_info->rest_read_compressed<uReadThis)
+                               uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;
+                       if (uReadThis == 0)
+                               return UNZ_EOF;
+                       if (zfile_fseek(pfile_in_zip_read_info->file,
+                      pfile_in_zip_read_info->pos_in_zipfile + 
+                         pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0)
+                               return UNZ_ERRNO;
+                       if (zfile_fread(pfile_in_zip_read_info->read_buffer,uReadThis,1,
+                         pfile_in_zip_read_info->file)!=1)
+                               return UNZ_ERRNO;
+                       pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
+
+                       pfile_in_zip_read_info->rest_read_compressed-=uReadThis;
+                       
+                       pfile_in_zip_read_info->stream.next_in = 
+                (Bytef*)pfile_in_zip_read_info->read_buffer;
+                       pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;
+               }
+
+               if (pfile_in_zip_read_info->compression_method==0)
+               {
+                       uInt uDoCopy,i ;
+                       if (pfile_in_zip_read_info->stream.avail_out < 
+                            pfile_in_zip_read_info->stream.avail_in)
+                               uDoCopy = pfile_in_zip_read_info->stream.avail_out ;
+                       else
+                               uDoCopy = pfile_in_zip_read_info->stream.avail_in ;
+                               
+                       for (i=0;i<uDoCopy;i++)
+                               *(pfile_in_zip_read_info->stream.next_out+i) =
+                        *(pfile_in_zip_read_info->stream.next_in+i);
+                                       
+                       pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,
+                                                               pfile_in_zip_read_info->stream.next_out,
+                                                               uDoCopy);
+                       pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy;
+                       pfile_in_zip_read_info->stream.avail_in -= uDoCopy;
+                       pfile_in_zip_read_info->stream.avail_out -= uDoCopy;
+                       pfile_in_zip_read_info->stream.next_out += uDoCopy;
+                       pfile_in_zip_read_info->stream.next_in += uDoCopy;
+            pfile_in_zip_read_info->stream.total_out += uDoCopy;
+                       iRead += uDoCopy;
+               }
+               else
+               {
+                       uLong uTotalOutBefore,uTotalOutAfter;
+                       const Bytef *bufBefore;
+                       uLong uOutThis;
+                       int flush=Z_SYNC_FLUSH;
+
+                       uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;
+                       bufBefore = pfile_in_zip_read_info->stream.next_out;
+
+                       /*
+                       if ((pfile_in_zip_read_info->rest_read_uncompressed ==
+                                pfile_in_zip_read_info->stream.avail_out) &&
+                               (pfile_in_zip_read_info->rest_read_compressed == 0))
+                               flush = Z_FINISH;
+                       */
+                       err=inflate(&pfile_in_zip_read_info->stream,flush);
+
+                       uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;
+                       uOutThis = uTotalOutAfter-uTotalOutBefore;
+                       
+                       pfile_in_zip_read_info->crc32 = 
+                crc32(pfile_in_zip_read_info->crc32,bufBefore,
+                        (uInt)(uOutThis));
+
+                       pfile_in_zip_read_info->rest_read_uncompressed -=
+                uOutThis;
+
+                       iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
+            
+                       if (err==Z_STREAM_END)
+                               return (iRead==0) ? UNZ_EOF : iRead;
+                       if (err!=Z_OK) 
+                               break;
+               }
+       }
+
+       if (err==Z_OK)
+               return iRead;
+       return err;
+}
+
+
+/*
+  Give the current position in uncompressed data
+*/
+extern z_off_t ZEXPORT unztell (file)
+       unzFile file;
+{
+       unz_s* s;
+       file_in_zip_read_info_s* pfile_in_zip_read_info;
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+    pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+       if (pfile_in_zip_read_info==NULL)
+               return UNZ_PARAMERROR;
+
+       return (z_off_t)pfile_in_zip_read_info->stream.total_out;
+}
+
+
+/*
+  return 1 if the end of file was reached, 0 elsewhere 
+*/
+extern int ZEXPORT unzeof (file)
+       unzFile file;
+{
+       unz_s* s;
+       file_in_zip_read_info_s* pfile_in_zip_read_info;
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+    pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+       if (pfile_in_zip_read_info==NULL)
+               return UNZ_PARAMERROR;
+       
+       if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
+               return 1;
+       else
+               return 0;
+}
+
+
+
+/*
+  Read extra field from the current file (opened by unzOpenCurrentFile)
+  This is the local-header version of the extra field (sometimes, there is
+    more info in the local-header version than in the central-header)
+
+  if buf==NULL, it return the size of the local extra field that can be read
+
+  if buf!=NULL, len is the size of the buffer, the extra header is copied in
+       buf.
+  the return value is the number of bytes copied in buf, or (if <0) 
+       the error code
+*/
+extern int ZEXPORT unzGetLocalExtrafield (file,buf,len)
+       unzFile file;
+       voidp buf;
+       unsigned len;
+{
+       unz_s* s;
+       file_in_zip_read_info_s* pfile_in_zip_read_info;
+       uInt read_now;
+       uLong size_to_read;
+
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+    pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+       if (pfile_in_zip_read_info==NULL)
+               return UNZ_PARAMERROR;
+
+       size_to_read = (pfile_in_zip_read_info->size_local_extrafield - 
+                               pfile_in_zip_read_info->pos_local_extrafield);
+
+       if (buf==NULL)
+               return (int)size_to_read;
+       
+       if (len>size_to_read)
+               read_now = (uInt)size_to_read;
+       else
+               read_now = (uInt)len ;
+
+       if (read_now==0)
+               return 0;
+       
+       if (zfile_fseek(pfile_in_zip_read_info->file,
+              pfile_in_zip_read_info->offset_local_extrafield + 
+                         pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0)
+               return UNZ_ERRNO;
+
+       if (zfile_fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1)
+               return UNZ_ERRNO;
+
+       return (int)read_now;
+}
+
+/*
+  Close the file in zip opened with unzipOpenCurrentFile
+  Return UNZ_CRCERROR if all the file was read but the CRC is not good
+*/
+extern int ZEXPORT unzCloseCurrentFile (file)
+       unzFile file;
+{
+       int err=UNZ_OK;
+
+       unz_s* s;
+       file_in_zip_read_info_s* pfile_in_zip_read_info;
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+    pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+       if (pfile_in_zip_read_info==NULL)
+               return UNZ_PARAMERROR;
+
+
+       if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
+       {
+               if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
+                       err=UNZ_CRCERROR;
+       }
+
+
+       TRYFREE(pfile_in_zip_read_info->read_buffer);
+       pfile_in_zip_read_info->read_buffer = NULL;
+       if (pfile_in_zip_read_info->stream_initialised)
+               inflateEnd(&pfile_in_zip_read_info->stream);
+
+       pfile_in_zip_read_info->stream_initialised = 0;
+       TRYFREE(pfile_in_zip_read_info);
+
+    s->pfile_in_zip_read=NULL;
+
+       return err;
+}
+
+
+/*
+  Get the global comment string of the ZipFile, in the szComment buffer.
+  uSizeBuf is the size of the szComment buffer.
+  return the number of byte copied or an error code <0
+*/
+extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf)
+       unzFile file;
+       char *szComment;
+       uLong uSizeBuf;
+{
+       int err=UNZ_OK;
+       unz_s* s;
+       uLong uReadThis ;
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+
+       uReadThis = uSizeBuf;
+       if (uReadThis>s->gi.size_comment)
+               uReadThis = s->gi.size_comment;
+
+       if (zfile_fseek(s->file,s->central_pos+22,SEEK_SET)!=0)
+               return UNZ_ERRNO;
+
+       if (uReadThis>0)
+    {
+      *szComment='\0';
+         if (zfile_fread(szComment,(uInt)uReadThis,1,s->file)!=1)
+               return UNZ_ERRNO;
+    }
+
+       if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment))
+               *(szComment+s->gi.size_comment)='\0';
+       return (int)uReadThis;
+}
diff --git a/writelog.c b/writelog.c
new file mode 100755 (executable)
index 0000000..91e3598
--- /dev/null
@@ -0,0 +1,33 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * Standard write_log that writes to the console
+  *
+  * Copyright 2001 Bernd Schmidt
+  */
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+void write_log_standard (const char *fmt, ...)
+{
+    va_list ap;
+    va_start (ap, fmt);
+#ifdef HAVE_VFPRINTF
+    vfprintf (stderr, fmt, ap);
+#else
+    /* Technique stolen from GCC.  */
+    {
+       int x1, x2, x3, x4, x5, x6, x7, x8;
+       x1 = va_arg (ap, int);
+       x2 = va_arg (ap, int);
+       x3 = va_arg (ap, int);
+       x4 = va_arg (ap, int);
+       x5 = va_arg (ap, int);
+       x6 = va_arg (ap, int);
+       x7 = va_arg (ap, int);
+       x8 = va_arg (ap, int);
+       fprintf (stderr, fmt, x1, x2, x3, x4, x5, x6, x7, x8);
+    }
+#endif
+}
+
diff --git a/zfile.c b/zfile.c
new file mode 100755 (executable)
index 0000000..3cec8f2
--- /dev/null
+++ b/zfile.c
@@ -0,0 +1,735 @@
+ /*
+  * UAE - The Un*x Amiga Emulator
+  *
+  * routines to handle compressed file automatically
+  *
+  * (c) 1996 Samuel Devulder, Tim Gunn
+  *     2002 Toni Wilen
+  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "config.h"
+#include "options.h"
+#include "zfile.h"
+#include "unzip.h"
+#include "disk.h"
+#include "dms/pfile.h"
+
+#include <zlib.h>
+
+struct zfile {
+    char *name;
+    char *zipname;
+    FILE *f;
+    uae_u8 *data;
+    int size;
+    int seek;
+    int deleteafterclose;
+    struct zfile *next;
+};
+
+static struct zfile *zlist = 0;
+int is_zlib;
+
+static int zlib_test (void)
+{
+#ifdef _WIN32
+    static int zlibmsg;
+    if (is_zlib)
+       return 1;
+    if (zlibmsg)
+       return 0;
+    zlibmsg = 1;
+    gui_message("zip and gzip support disabled because zlib1.dll is missing");
+    return 0;
+#else
+    /* On non-Windows platforms, we can safely assume (I think) that if we got this
+     * far zlib is present - Rich */
+    return 1;
+#endif
+}
+
+static struct zfile *zfile_create (void)
+{
+    struct zfile *z;
+
+    z = malloc (sizeof *z);
+    if (!z)
+       return 0;
+    memset (z, 0, sizeof *z);
+    z->next = zlist;
+    zlist = z;
+    return z;
+}
+
+static void zfile_free (struct zfile *f)
+{
+    if (f->f)
+       fclose (f->f);
+    if (f->deleteafterclose) {
+       unlink (f->name);
+       write_log ("deleted temporary file '%s'\n", f->name);
+    }
+    free (f->name);
+    free (f->data);
+    free (f);
+}
+
+void zfile_exit (void)
+{
+    struct zfile *l;
+    while ((l = zlist)) {
+       zlist = l->next;
+       zfile_free (l);
+    }
+}
+
+void zfile_fclose (struct zfile *f)
+{
+    struct zfile *pl = NULL;
+    struct zfile *l  = zlist;
+    struct zfile *nxt;
+
+    if (!f)
+       return;
+    while (l != f) {
+       if (l == 0) {
+           write_log ("zfile: tried to free already freed filehandle!\n");
+           return;
+       }
+       pl = l;
+       l = l->next;
+    }
+    if (l) nxt = l->next;
+    zfile_free (f);
+    if (l == 0)
+       return;
+    if(!pl)
+       zlist = nxt;
+    else
+       pl->next = nxt;
+}
+
+static uae_u8 exeheader[]={0x00,0x00,0x03,0xf3,0x00,0x00,0x00,0x00};
+int zfile_gettype (struct zfile *z)
+{
+    uae_u8 buf[8];
+    char *ext;
+    
+    if (!z)
+       return ZFILE_UNKNOWN;
+    ext = strrchr (z->name, '.');
+    if (ext != NULL) {
+       ext++;
+       if (strcasecmp (ext, "adf") == 0)
+           return ZFILE_DISKIMAGE;
+       if (strcasecmp (ext, "adz") == 0)
+           return ZFILE_DISKIMAGE;
+       if (strcasecmp (ext, "roz") == 0)
+           return ZFILE_ROM;
+       if (strcasecmp (ext, "ipf") == 0)
+           return ZFILE_DISKIMAGE;
+       if (strcasecmp (ext, "fdi") == 0)
+           return ZFILE_DISKIMAGE;
+       if (strcasecmp (ext, "uss") == 0)
+           return ZFILE_STATEFILE;
+       if (strcasecmp (ext, "dms") == 0)
+           return ZFILE_DISKIMAGE;
+       if (strcasecmp (ext, "rom") == 0)
+           return ZFILE_ROM;
+       if (strcasecmp (ext, "key") == 0)
+           return ZFILE_KEY;
+       if (strcasecmp (ext, "nvr") == 0)
+           return ZFILE_NVR;
+       if (strcasecmp (ext, "uae") == 0)
+           return ZFILE_CONFIGURATION;
+    }
+    memset (buf, 0, sizeof (buf));
+    zfile_fread (buf, 8, 1, z);
+    zfile_fseek (z, -8, SEEK_CUR);
+    if (!memcmp (buf, exeheader, sizeof(buf)))
+       return ZFILE_DISKIMAGE;
+    return ZFILE_UNKNOWN;
+}
+
+#if 0
+#define TMP_PREFIX "uae_"
+
+static struct zfile *createinputfile (struct zfile *z)
+{
+    FILE *f;
+    struct zfile *z2;
+    char *name;
+
+    z2 = zfile_create ();
+    if (!z->data) {
+       z2->name = strdup (z->name);
+       return z2;
+    }
+    name = tempnam (0, TMP_PREFIX);
+    f = fopen (name, "wb");
+    if (!f) return 0;
+    write_log ("created temporary file '%s'\n", name);
+    fwrite (z->data, z->size, 1, f);
+    fclose (f);
+    z2->name = name;
+    z2->deleteafterclose = 1;
+    return z2;
+}
+
+static struct zfile *createoutputfile (struct zfile *z)
+{
+    struct zfile *z2;
+    char *name;
+
+    name = tempnam (0, TMP_PREFIX);
+    z2 = zfile_create ();
+    z2->name = name;
+    z2->deleteafterclose = 1;
+    write_log ("allocated temporary file name '%s'\n", name);
+    return z2;
+}
+
+/* we want to delete temporary files as early as possible */
+static struct zfile *updateoutputfile (struct zfile *z)
+{
+    struct zfile *z2 = 0;
+    int size;
+    FILE *f = fopen (z->name, "rb");
+    for (;;) {
+       if (!f)
+           break;
+        fseek (f, 0, SEEK_END);
+       size = ftell (f);
+       fseek (f, 0, SEEK_SET);
+       if (!size)
+           break;
+        z2 = zfile_fopen_empty (z->name, size);
+       if (!z2)
+           break;
+        fread (z2->data, size, 1, f);
+       fclose (f);
+       zfile_fclose (z);
+       return z2;
+    }
+    if (f)
+       fclose (f);
+    zfile_fclose (z);
+    zfile_fclose (z2);
+    return 0;
+}
+#endif
+
+static struct zfile *zuncompress (struct zfile *z);
+
+static struct zfile *gunzip (struct zfile *z)
+{
+    uae_u8 header[2 + 1 + 1 + 4 + 1 + 1];
+    z_stream zs;
+    int i, size, ret, first;
+    uae_u8 flags;
+    long offset;
+    char name[MAX_PATH];
+    uae_u8 buffer[8192];
+    struct zfile *z2;
+    uae_u8 b;
+
+    if (!zlib_test ())
+       return z;
+    strcpy (name, z->name);
+    memset (&zs, 0, sizeof (zs));
+    memset (header, 0, sizeof (header));
+    zfile_fread (header, sizeof (header), 1, z);
+    flags = header[3];
+    if (header[0] != 0x1f && header[1] != 0x8b)
+       return z;
+    if (flags & 2) /* multipart not supported */
+       return z;
+    if (flags & 32) /* encryption not supported */
+       return z;
+    if (flags & 4) { /* skip extra field */
+        zfile_fread (&b, 1, 1, z);
+       size = b;
+       zfile_fread (&b, 1, 1, z);
+       size |= b << 8;
+       zfile_fseek (z, size + 2, SEEK_CUR);
+    }
+    if (flags & 8) { /* get original file name */
+       i = 0;
+       do {
+           zfile_fread (name + i, 1, 1, z);
+       } while (name[i++]);
+    }
+    if (flags & 16) { /* skip comment */
+       i = 0;
+       do {
+           zfile_fread (&b, 1, 1, z);
+       } while (b);
+    }
+    offset = zfile_ftell (z);
+    zfile_fseek (z, -4, SEEK_END);
+    zfile_fread (&b, 1, 1, z);
+    size = b;
+    zfile_fread (&b, 1, 1, z);
+    size |= b << 8;
+    zfile_fread (&b, 1, 1, z);
+    size |= b << 16;
+    zfile_fread (&b, 1, 1, z);
+    size |= b << 24;
+    if (size < 8 || size > 10000000) /* safety check */
+       return z;
+    zfile_fseek (z, offset, SEEK_SET);
+    z2 = zfile_fopen_empty (name, size);
+    if (!z2)
+       return z;
+    zs.next_out = z2->data;
+    zs.avail_out = size;
+    first = 1;
+    do {
+       zs.next_in = buffer;
+       zs.avail_in = sizeof (buffer);
+       zfile_fread (buffer, sizeof (buffer), 1, z);
+       if (first) {
+           if (inflateInit2 (&zs, -MAX_WBITS) != Z_OK)
+               break;
+           first = 0;
+       }
+       ret = inflate (&zs, 0);
+    } while (ret == Z_OK);
+    inflateEnd (&zs);
+    if (ret != Z_STREAM_END || first != 0) {
+       zfile_fclose (z2);
+       return z;
+    }
+    zfile_fclose (z);
+    return z2;
+}
+
+
+static struct zfile *bunzip (const char *decompress, struct zfile *z)
+{
+    return z;
+}
+
+static struct zfile *lha (struct zfile *z)
+{
+    return z;
+}
+
+static struct zfile *dms (struct zfile *z)
+{
+    int ret;
+    struct zfile *zo;
+    
+    zo = zfile_fopen_empty ("zipped.dms", 1760 * 512);
+    if (!zo) return z;
+    ret = DMS_Process_File (z, zo, CMD_UNPACK, OPT_VERBOSE, 0, 0);
+    if (ret == NO_PROBLEM || ret == DMS_FILE_END) {
+       zfile_fclose (z);
+       return zo;
+    }
+    return z;
+}
+
+#if 0
+static struct zfile *dms (struct zfile *z)
+{
+    char cmd[2048];
+    struct zfile *zi = createinputfile (z);
+    struct zfile *zo = createoutputfile (z);
+    if (zi && zo) {
+       sprintf(cmd, "xdms -q u \"%s\" +\"%s\"", zi->name, zo->name);
+       execute_command (cmd);
+    }
+    zfile_fclose (zi);
+    zfile_fclose (z);
+    return updateoutputfile (zo);
+}
+#endif
+
+static char *ignoreextensions[] = 
+    { ".gif", ".jpg", ".png", ".xml", ".pdf", ".txt", 0 };
+static char *diskimageextensions[] =
+    { ".adf", ".adz", ".ipf", ".fdi", 0 };
+
+static void maybe_add_disk_history (char *zname, char *name)
+{
+    char tmp[2048];
+    int i;
+
+    i = 0;
+    while (diskimageextensions[i]) {
+       if (strlen (name) > 3 && !strcasecmp (name + strlen (name) - 4, diskimageextensions[i])) {
+           sprintf (tmp, "%s/%s", zname, name);
+           DISK_history_add (tmp, -1);
+       }
+       i++;
+    }
+}
+
+static struct zfile *unzip (struct zfile *z)
+{
+    unzFile uz;
+    unz_file_info file_info;
+    char filename_inzip[2048];
+    struct zfile *zf;
+    int err, zipcnt, select, i, we_have_file = 0;
+
+    if (!zlib_test ())
+       return z;
+    zf = 0;
+    uz = unzOpen (z);
+    if (!uz)
+       return z;
+    if (unzGoToFirstFile (uz) != UNZ_OK)
+       return z;
+    write_log("checking zip file '%s':\n", z->name);
+    zipcnt = 1;
+    for (;;) {
+       err = unzGetCurrentFileInfo(uz,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
+       if (err != UNZ_OK)
+           return z;
+       if (file_info.uncompressed_size > 0) {
+           write_log("'%s':%d ", filename_inzip, file_info.uncompressed_size);
+           i = 0;
+           while (ignoreextensions[i]) {
+               if (strlen(filename_inzip) > strlen (ignoreextensions[i]) &&
+                   !strcasecmp (ignoreextensions[i], filename_inzip + strlen (filename_inzip) - strlen (ignoreextensions[i])))
+                   break;
+               i++;
+           }
+           if (ignoreextensions[i]) {
+               write_log ("[ignored]");
+           } else {
+               maybe_add_disk_history (z->name, filename_inzip);
+               write_log ("[check]");
+               select = 0;
+               if (!z->zipname)
+                   select = 1;
+               if (z->zipname && !strcasecmp (z->zipname, filename_inzip))
+                   select = -1;
+               if (z->zipname && z->zipname[0] == '#' && atol (z->zipname + 1) == zipcnt)
+                   select = -1;
+               if (select && !we_have_file) {
+                   int err = unzOpenCurrentFile (uz);
+                   write_log ("[selected]");
+                   if (err == UNZ_OK) {
+                       zf = zfile_fopen_empty (filename_inzip, file_info.uncompressed_size);
+                       if (zf) {
+                           err = unzReadCurrentFile  (uz, zf->data, file_info.uncompressed_size);
+                           unzCloseCurrentFile (uz);
+                           if (err == 0 || err == file_info.uncompressed_size) {
+                               zf = zuncompress (zf);
+                               if (select < 0 || zfile_gettype (zf)) {
+                                   we_have_file = 1;
+                                   write_log("[ok]");
+                               }
+                           }
+                       }
+                       if (!we_have_file) {
+                           zfile_fclose (zf);
+                           zf = 0;
+                       }
+                   } else {
+                       write_log ("\nunzipping failed %d", err);
+                   }
+               }
+           }
+           write_log("\n");
+       }
+       zipcnt++;
+       err = unzGoToNextFile (uz);
+       if (err != UNZ_OK)
+           break;
+    }
+    if (zf) {
+       zfile_fclose (z);
+       z = zf;
+    }
+    return z;
+}
+
+static struct zfile *zuncompress (struct zfile *z)
+{
+    char *name = z->name;
+    char *ext = strrchr (name, '.');
+    uae_u8 header[4];
+
+    if (ext != NULL) {
+       ext++;
+       if (strcasecmp (ext, "lha") == 0
+           || strcasecmp (ext, "lzh") == 0)
+           return lha (z);
+       if (strcasecmp (ext, "zip") == 0)
+            return unzip (z);
+       if (strcasecmp (ext, "gz") == 0)
+            return gunzip (z);
+       if (strcasecmp (ext, "adz") == 0)
+            return gunzip (z);
+       if (strcasecmp (ext, "roz") == 0)
+            return gunzip (z);
+       if (strcasecmp (ext, "dms") == 0)
+            return dms (z);
+       memset (header, 0, sizeof (header));
+       zfile_fseek (z, 0, SEEK_SET);
+       zfile_fread (header, sizeof (header), 1, z);
+       zfile_fseek (z, 0, SEEK_SET);
+       if (header[0] == 0x1f && header[1] == 0x8b)
+           return gunzip (z);
+       if (header[0] == 'P' && header[1] == 'K')
+           return unzip (z);
+       if (header[0] == 'D' && header[1] == 'M' && header[2] == 'S' && header[3] == '!')
+           return dms (z);
+    }
+    return z;
+}
+
+static FILE *openzip (char *name, char *zippath)
+{
+    int i;
+    char v;
+    
+    i = strlen (name) - 2;
+    if (zippath)
+       zippath[0] = 0;
+    while (i > 0) {
+       if (name[i] == '/' || name[i] == '\\' && i > 4) {
+           v = name[i];
+           name[i] = 0;
+           if (!strcasecmp (name + i - 4, ".zip")) {
+               FILE *f = fopen (name, "rb");
+               if (f) {
+                   if (zippath)
+                       strcpy (zippath, name + i + 1);
+                   return f;
+               }
+           }
+           name[i] = v;
+       }
+       i--;
+    }
+    return 0;      
+}
+
+#ifdef SINGLEFILE
+extern uae_u8 singlefile_data[];
+
+static struct zfile *zfile_opensinglefile(struct zfile *l)
+{
+    uae_u8 *p = singlefile_data;
+    int size, offset;
+    char tmp[256], *s;
+
+    strcpy (tmp, l->name);
+    s = tmp + strlen (tmp) - 1;
+    while (*s != 0 && *s != '/' && *s != '\\') s--;
+    if (s > tmp)
+       s++;
+    write_log("loading from singlefile: '%s'\n", tmp);
+    while (*p++);
+    offset = (p[0] << 24)|(p[1] << 16)|(p[2] << 8)|(p[3] << 0);
+    p += 4;
+    for (;;) {
+       size = (p[0] << 24)|(p[1] << 16)|(p[2] << 8)|(p[3] << 0);
+       if (!size)
+           break;
+       if (!strcmpi (tmp, p + 4)) {
+           l->data = singlefile_data + offset;
+           l->size = size;
+           write_log ("found, size %d\n", size);
+           return l;
+       }
+       offset += size;
+       p += 4;
+       p += strlen (p) + 1;
+    }
+    write_log ("not found\n");
+    return 0;
+}
+#endif
+
+/*
+ * fopen() for a compressed file
+ */
+struct zfile *zfile_fopen (const char *name, const char *mode)
+{
+    struct zfile *l;
+    FILE *f;
+    char zipname[1000];
+
+    if( *name == '\0' )
+        return NULL;
+    l = zfile_create ();
+    l->name = strdup (name);
+#ifdef SINGLEFILE
+    if (zfile_opensinglefile (l))
+       return l;
+#endif
+    f = openzip (l->name, zipname);
+    if (f) {
+       if (strcmpi (mode, "rb")) {
+           zfile_fclose (l);
+           fclose (f);
+           return 0;
+       }
+       l->zipname = strdup (zipname);
+    }
+    if (!f) {
+       f = fopen (name, mode);
+       if (!f) {
+           zfile_fclose (l);
+           return 0;
+       }
+    }
+    l->f = f;
+    l = zuncompress (l);
+    return l;
+}
+
+int zfile_exists (const char *name)
+{
+    char fname[2000];
+    FILE *f;
+
+    strcpy (fname, name);
+    f = openzip (fname, 0);
+    if (!f)
+       f = fopen(name,"rb");
+    if (!f)
+       return 0;
+    fclose (f);
+    return 1;
+}
+
+int zfile_iscompressed (struct zfile *z)
+{
+    return z->data ? 1 : 0;
+}
+
+struct zfile *zfile_fopen_empty (const char *name, int size)
+{
+    struct zfile *l;
+    l = zfile_create ();
+    l->name = strdup (name);
+    l->data = malloc (size);
+    l->size = size;
+    memset (l->data, 0, size);
+    return l;
+}
+
+long zfile_ftell (struct zfile *z)
+{
+    if (z->data)
+       return z->seek;
+    return ftell (z->f);
+}
+
+int zfile_fseek (struct zfile *z, long offset, int mode)
+{
+    if (z->data) {
+       int old = z->seek;
+       switch (mode)
+       {
+           case SEEK_SET:
+           z->seek = offset;
+           break;
+           case SEEK_CUR:
+           z->seek += offset;
+           break;
+           case SEEK_END:
+           z->seek = z->size - offset;
+           break;
+       }
+       if (z->seek < 0) z->seek = 0;
+       if (z->seek > z->size) z->seek = z->size;
+       return old;
+    }
+    return fseek (z->f, offset, mode);
+}
+
+size_t zfile_fread  (void *b, size_t l1, size_t l2,struct zfile *z)
+{
+    long len = l1 * l2;
+    if (z->data) {
+       if (z->seek + len > z->size)
+           len = z->size - z->seek;
+       memcpy (b, z->data + z->seek, len);
+       z->seek += len;
+       return len;
+    }
+    return fread (b, l1, l2, z->f);
+}
+
+size_t zfile_fwrite  (void *b, size_t l1, size_t l2, struct zfile *z)
+{
+    long len = l1 * l2;
+    if (z->data) {
+       if (z->seek + len > z->size)
+           len = z->size - z->seek;
+       memcpy (z->data + z->seek, b, len);
+       z->seek += len;
+       return len;
+    }
+    return fwrite (b, l1, l2, z->f);
+}
+
+int zfile_zuncompress (void *dst, int dstsize, struct zfile *src, int srcsize)
+{
+    z_stream zs;
+    int v;
+    uae_u8 inbuf[4096];
+    int incnt;
+
+    if (!zlib_test ())
+       return 0;
+    memset (&zs, 0, sizeof(zs));
+    if (inflateInit (&zs) != Z_OK)
+       return 0;
+    zs.next_out = dst;
+    zs.avail_out = dstsize;
+    incnt = 0;
+    v = Z_OK;
+    while (v == Z_OK && zs.avail_out > 0) {
+       if (zs.avail_in == 0) {
+           int left = srcsize - incnt;
+           if (left == 0)
+               break;
+           if (left > sizeof (inbuf)) left = sizeof (inbuf);
+           zs.next_in = inbuf;
+           zs.avail_in = zfile_fread (inbuf, 1, left, src);
+           incnt += left;
+       }
+       v = inflate (&zs, 0);
+    }
+    inflateEnd (&zs);
+    return 0;
+}
+
+int zfile_zcompress (struct zfile *f, void *src, int size)
+{
+    int v;
+    z_stream zs;
+    uae_u8 outbuf[4096];
+
+    if (!is_zlib)
+       return 0;
+    memset (&zs, 0, sizeof (zs));
+    if (deflateInit (&zs, Z_DEFAULT_COMPRESSION) != Z_OK)
+       return 0;
+    zs.next_in = src;
+    zs.avail_in = size;
+    v = Z_OK;
+    while (v == Z_OK) {
+       zs.next_out = outbuf;
+        zs.avail_out = sizeof (outbuf);
+       v = deflate(&zs, Z_NO_FLUSH | Z_FINISH);
+       if (sizeof(outbuf) - zs.avail_out > 0)
+           zfile_fwrite (outbuf, 1, sizeof (outbuf) - zs.avail_out, f);
+    }
+    deflateEnd(&zs);
+    return zs.total_out;
+}
+
+