--- /dev/null
+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
--- /dev/null
+ /*
+ * 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);
+}
+
--- /dev/null
+ /*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+ /*
+ * 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;
+}
--- /dev/null
+ /*
+ * 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)
+{
+}
--- /dev/null
+ /* 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 }
+};
--- /dev/null
+ /*
+ * 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;
+
+}
--- /dev/null
+ /*
+ * 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");
+ }
+}
--- /dev/null
+ /*
+ * 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 */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+
+#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
--- /dev/null
+#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);
+}
--- /dev/null
+ /*
+ * 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);
+}
--- /dev/null
+ /*
+ * 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;
+}
--- /dev/null
+/*
+ * 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)®s.fpcr); return;
+ }
+ if (extra & 0x0800) {
+ FAIL(1);
+ return;
+ }
+ if (extra & 0x0400) {
+ mov_l_rm(opcode & 15,(uae_u32)®s.fpiar); return;
+ }
+ } else {
+ if (extra & 0x1000) {
+ mov_l_mr((uae_u32)®s.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)®s.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)®s.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)®s.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)®s.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);
+}
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+/* 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 */
+}
--- /dev/null
+#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*)®s)+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*)(®s.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)®s.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)®s.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)®s.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*)®s.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)®s.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)®s.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)®s.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)®s.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)®s.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)®s.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)®s.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)®s.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 */
+ }
+}
+
+
--- /dev/null
+ /*
+ * 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*)®flags);
+ 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)®flags, 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(®flags); assemble((uae_u8)~0x40);
+ assemble(0x08); assemble(0x05+ tmpr*8); assemble_long(®flags);
+ 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)®flags, tmpr, sz_long);
+ if (status == CC_AFTER_ROX)
+ compile_move_reg_to_mem_regoffs(-2, 4 + (uae_u32)®flags, 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)®flags);
+ } 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)®flags, tmpr, sz_long);
+
+ if (status & CC_X_FROM_86C) {
+ compile_move_reg_to_mem_regoffs(-2, 4 + (uae_u32)®flags, 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)®flags, 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)®flags, 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)®flags,
+ 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)®flags); 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(®flags);
+ assemble(0x81); assemble(0xC0 + 8*4 + tmpr); assemble_ulong(~0x40);
+ assemble(0x09); assemble(0x05 + 8*tmpr); assemble_long(®flags);
+ compile_move_reg_to_mem_regoffs(-2, 4 + (uae_u32)®flags, 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 */
--- /dev/null
+/*
+ * 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 = ¤t->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;
+}
--- /dev/null
+ /*
+ * 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(¤t_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, ¤t_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], ¤t_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
--- /dev/null
+ /*
+ * 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, ®s, 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, ®s, 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;
+}
--- /dev/null
+ /*
+ * 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;
+}
+
+
--- /dev/null
+
+/*
+ * 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;
+
+
--- /dev/null
+
+/*
+ * 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;
+}
+
+
--- /dev/null
+
+USHORT Calc_CheckSum(UCHAR *, ULONG);
+USHORT CreateCRC(UCHAR *, ULONG);
+
--- /dev/null
+
+/*
+ * 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);
+}
+
+
--- /dev/null
+
+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 *);
+
--- /dev/null
+
+/*
+ * 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;
+}
+
+
--- /dev/null
+
+extern USHORT left[], right[];
+
+USHORT make_table(USHORT nchar, UCHAR bitlen[], USHORT tablebits, USHORT table[]);
+
--- /dev/null
+
+/*
+ * 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++;
+ }
+
+}
+
+
--- /dev/null
+
+
+/* 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);
+
--- /dev/null
+
+/*
+ * 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,
+};
+
+
--- /dev/null
+
+extern UCHAR d_code[], d_len[];
+
--- /dev/null
+
+/*
+ * 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 */
+}
+
+
--- /dev/null
+
+
+USHORT Unpack_DEEP(UCHAR *, UCHAR *, USHORT);
+
+extern int init_deep_tabs;
+extern USHORT deep_text_loc;
+
--- /dev/null
+
+/*
+ * 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;
+}
+
+
--- /dev/null
+
+
+USHORT Unpack_HEAVY(UCHAR *, UCHAR *, UCHAR, USHORT);
+
+extern USHORT heavy_text_loc;
+
--- /dev/null
+
+/*
+ * 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);
+}
+
--- /dev/null
+
+void Init_Decrunchers(void);
+
--- /dev/null
+
+/*
+ * 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;
+}
+
+
--- /dev/null
+
+USHORT Unpack_MEDIUM(UCHAR *, UCHAR *, USHORT);
+
+extern USHORT medium_text_loc;
+
--- /dev/null
+
+/*
+ * 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;
+}
+
--- /dev/null
+
+USHORT Unpack_QUICK(UCHAR *, UCHAR *, USHORT);
+
+extern USHORT quick_text_loc;
+
--- /dev/null
+
+/*
+ * 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;
+}
+
+
--- /dev/null
+
+USHORT Unpack_RLE(UCHAR *, UCHAR *, USHORT);
+
--- /dev/null
+ /*
+ * 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 ();
+}
+
--- /dev/null
+ /*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+ /*
+ * 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 ();
+ }
+}
--- /dev/null
+ /*
+ * 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;
+}
--- /dev/null
+/*
+
+ 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;
+}
+
--- /dev/null
+ 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
--- /dev/null
+ /*
+ * 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 = ¤t_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"
--- /dev/null
+#! /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"
--- /dev/null
+ /*
+ * 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;
+}
--- /dev/null
+ /*
+ * 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);
+}
--- /dev/null
+ /*
+ * 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];
+ }
+ }
+}
--- /dev/null
+/* 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 */
--- /dev/null
+ /*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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)®s.pc,newad);\n"
+ "\tget_n_addr_jmp(newad,PC_P,scratchie);\n"
+ "\tmov_l_mr((uae_u32)®s.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)®s.pc,newad);\n"
+ "\tget_n_addr_jmp(newad,PC_P,scratchie);\n"
+ "\tmov_l_mr((uae_u32)®s.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)®s.pc,srca);\n"
+ "\tget_n_addr_jmp(srca,PC_P,scratchie);\n"
+ "\tmov_l_mr((uae_u32)®s.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)®s.pc,srca);\n"
+ "\tget_n_addr_jmp(srca,PC_P,scratchie);\n"
+ "\tmov_l_mr((uae_u32)®s.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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+ /*
+ * 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)
+{
+}
+
--- /dev/null
+ /*
+ * 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;
+}
--- /dev/null
+ /*
+ * 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
--- /dev/null
+ /*
+ * 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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+ /*
+ * 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);
+}
--- /dev/null
+ /*
+ * 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
+};
+
--- /dev/null
+
+
+#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);
--- /dev/null
+
+/* 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];
--- /dev/null
+ /*
+ * 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);
+
--- /dev/null
+ /*
+ * 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
--- /dev/null
+ /*
+ * 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
--- /dev/null
+
+#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);
--- /dev/null
+ /*
+ * 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);
--- /dev/null
+
+#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
--- /dev/null
+ /*
+ * 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*);
+
--- /dev/null
+ /*
+ * 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);
+}
--- /dev/null
+#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);
+
--- /dev/null
+ /*
+ * 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
--- /dev/null
+
+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
--- /dev/null
+ /*
+ * 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);
+
--- /dev/null
+ /*
+ * 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);
--- /dev/null
+ /*
+ * 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);
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+ /*
+ * 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_"
+
--- /dev/null
+#ifndef UAE__ENFORCER_H
+#define UAE__ENFORCER_H
+
+int enforcer_enable(void);
+int enforcer_disable(void);
+
+#endif
\ No newline at end of file
--- /dev/null
+ /*
+ * 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);
--- /dev/null
+#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
--- /dev/null
+#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)();
+ }
+ }
+}
--- /dev/null
+
+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
--- /dev/null
+ /*
+ * 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
--- /dev/null
+#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
--- /dev/null
+ /*
+ * 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);
--- /dev/null
+
+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;
--- /dev/null
+ /*
+ * 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"
--- /dev/null
+ /*
+ * 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
--- /dev/null
+ /*
+ * 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 *);
--- /dev/null
+/* 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));
--- /dev/null
+ /*
+ * 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];
--- /dev/null
+ /*
+ * 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);
+
--- /dev/null
+
+#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
--- /dev/null
+ /*
+ * 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);
--- /dev/null
+ /*
+ * 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[];
+
--- /dev/null
+ /*
+ * 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);
--- /dev/null
+ /*
+ * 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
+};
--- /dev/null
+ /*
+ * 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
--- /dev/null
+ /*
+ * 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
--- /dev/null
+ /*
+ * 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
--- /dev/null
+ /*
+ * 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
--- /dev/null
+ /*
+ * 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
--- /dev/null
+ /*
+ * 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
--- /dev/null
+ /*
+ * 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);
+
--- /dev/null
+
+#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
--- /dev/null
+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;
+
--- /dev/null
+ /*
+ * 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);
+
--- /dev/null
+ /*
+ * 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;
--- /dev/null
+ /*
+ * 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
--- /dev/null
+/* 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
--- /dev/null
+ /*
+ * 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
--- /dev/null
+ /*
+ * 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);
--- /dev/null
+ /*
+ * 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[];
--- /dev/null
+/*
+ * 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);
+
+
--- /dev/null
+/* 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 */
--- /dev/null
+ /*
+ * 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);
--- /dev/null
+ /*
+ * 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
--- /dev/null
+ /*
+ * 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;
+}
--- /dev/null
+/* 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)
+
--- /dev/null
+ /*
+ * 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;
+}
--- /dev/null
+ /*
+ * 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
--- /dev/null
+ /*
+ * 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;
+}
--- /dev/null
+ /*
+ * 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;
+}
--- /dev/null
+ /*
+ * 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 */
+}
--- /dev/null
+ /*
+ * 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));
+}
--- /dev/null
+ /*
+ * 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, ", &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, ", &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
+}
+
+
--- /dev/null
+ /*
+ * 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);
+}
--- /dev/null
+ /*
+ * 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)
+
--- /dev/null
+ /*
+ * 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
+};
--- /dev/null
+ /*
+ * 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
+
--- /dev/null
+ /*
+ * 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)
+{
+}
--- /dev/null
+ /*
+ * 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
+
--- /dev/null
+/*
+ * 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)®s;
+ 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
+ }
+}
--- /dev/null
+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;
+
+
--- /dev/null
+nasm -O1 -f win32 hq2x32.asm
+nasm -O1 -f win32 hq3x32.asm
+nasm -O1 -f win32 hq4x32.asm
--- /dev/null
+/*
+ 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);
+ }
+}
+
+
+
--- /dev/null
+/*
+ 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
--- /dev/null
+ /*
+ * 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
+};
--- /dev/null
+ /*
+ * 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
--- /dev/null
+ /*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+// 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
+
--- /dev/null
+<?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 >..\..\cpudefs.c <..\..\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 >..\..\cpudefs.c <..\..\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>
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
+
--- /dev/null
+#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
--- /dev/null
+
+#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
--- /dev/null
+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);
+
--- /dev/null
+ /*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+
+#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;
+}
+
+
+
+
+
+
--- /dev/null
+
+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);
--- /dev/null
+#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);
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
+
+
--- /dev/null
+#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
--- /dev/null
+ /*
+ * 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];
+ }
+ }
+}
--- /dev/null
+<?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 >..\..\blit.h
+genblitter.exe f >..\..\blitfunc.c
+genblitter.exe h >..\..\blitfunc.h
+genblitter.exe t >..\..\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 >..\..\blit.h
+genblitter.exe f >..\..\blitfunc.c
+genblitter.exe h >..\..\blitfunc.h
+genblitter.exe t >..\..\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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+#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;
+}
+
+
+
--- /dev/null
+;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
+
--- /dev/null
+;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
+
--- /dev/null
+;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
+
--- /dev/null
+;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
+
+
--- /dev/null
+
+#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
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+
+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);
--- /dev/null
+/*
+ * 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);
+}
+
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+/*
+ * 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
--- /dev/null
+ /*
+ * 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
--- /dev/null
+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
+
--- /dev/null
+ /*
+ * 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
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+#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);
+}
--- /dev/null
+// 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;
+}
+
--- /dev/null
+// 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+
+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);
--- /dev/null
+ /*
+ * 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
--- /dev/null
+/*
+ * 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
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+* 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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)
+{
+}
+
--- /dev/null
+/* 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
--- /dev/null
+//{{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
--- /dev/null
+// 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.)]
--- /dev/null
+<?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
--- /dev/null
+// 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
+
--- /dev/null
+// 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
+/////////////////////////////////////////////////////////////////////////////
+
+
--- /dev/null
+/* 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;
+ }
+ }
+ }
+}
+
--- /dev/null
+/* 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;
+ }
+ }
+ }
+}
+
--- /dev/null
+#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;
+}
+
--- /dev/null
+
+/* 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
+
--- /dev/null
+ /*
+ * 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
+}
--- /dev/null
+
+#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;
+}
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+#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
--- /dev/null
+#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;
+}
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+ /*
+ * 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 ();
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+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
+
--- /dev/null
+ /*
+ * 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;
+
--- /dev/null
+// 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
--- /dev/null
+
+#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 '\\'
--- /dev/null
+ /*
+ * 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"
--- /dev/null
+
+#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
--- /dev/null
+#! /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
--- /dev/null
+/*
+ * 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;
+}
+
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+
+
+/* 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 );
+}
--- /dev/null
+
+#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;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+
+#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 ();
+}
--- /dev/null
+/*
+ * 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 = ¤tmodestruct;
+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, ®keytype, (LPBYTE)&stored_x, ®keysize );
+ RegQueryValueEx( hWinUAEKey, "yPos", 0, ®keytype, (LPBYTE)&stored_y, ®keysize );
+
+ 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
--- /dev/null
+#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
--- /dev/null
+/*==========================================================================
+ *
+ * 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 (¤t_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, ®keytype, (LPBYTE)&x, ®keysize) != ERROR_SUCCESS)
+ x = 0;
+ if (RegQueryValueEx (hWinUAEKey, "yPosGUI", 0, ®keytype, (LPBYTE)&y, ®keysize) != 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)
+{
+}
--- /dev/null
+#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
--- /dev/null
+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
+
--- /dev/null
+<?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>
--- /dev/null
+#! /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
--- /dev/null
+
+#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);
+ }
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+ /*
+ * 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)
+{
+}
+
--- /dev/null
+ /*
+ * 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?
+
+*/
--- /dev/null
+#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) {}
+
--- /dev/null
+ /*
+ * 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
+}
+
--- /dev/null
+ /*
+ * 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
--- /dev/null
+ /*
+ * 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
+};
--- /dev/null
+ /*
+ * 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. */
+}
--- /dev/null
+ /*
+ * 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)
+{}
--- /dev/null
+ /*
+ * 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);
+}
--- /dev/null
+% 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]
--- /dev/null
+ /*
+ * 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)
+{
+}
--- /dev/null
+/*
+ * 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);
+}
+
+
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+ /*
+ * 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
+}
+
--- /dev/null
+ /*
+ * 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;
+}
+
+