From: Toni Wilen Date: Sun, 25 Apr 2004 15:28:03 +0000 (+0300) Subject: imported winuaesrc0826b4.zip X-Git-Tag: 2100~352 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=8d773b1c93ab1c3737d65378d91df657d87b7975;p=francis%2Fwinuae.git imported winuaesrc0826b4.zip --- 8d773b1c93ab1c3737d65378d91df657d87b7975 diff --git a/ChangeLog b/ChangeLog new file mode 100755 index 00000000..d7c5e21a --- /dev/null +++ b/ChangeLog @@ -0,0 +1,2347 @@ +9C0702 Correct an overflow problem in the CIA code. +9C0407 Sprite code updates; correct CIA memory access handlers (Toni). +9C0306 Make w/d representable for fsdb_win32. + Don't reorder children of directories; this causes duplicates in + exnext. + Reorder the code for the 9/10 vsynctime hack a bit. + Add code from Toni to remember the last value written to a custom + register and to return it when reading from a write-only reg - this + seems to match actual hardware behaviour. + Add some more blitter tweaks (Toni). +9C0227 When waking up the copper from a blitter wait, recheck that vpos is + larger than vcmp - especially with masking going on, this may not be + the case. + X11: When changing picasso resolution, reinitialize everything - our + bitmap might be too small otherwise. + When configuring hardfiles, use specified blocksize, not 512 (Toni). + In SPRxCTL_1, don't examine vstart position before computing it (Toni). +9C0225 Some cfgfile fixes, more blitter timing changes and one big sprite + statemachine update from Toni. + Some copper timing fixes. + Fix flag bit confusion in action_fh_from_lock (taken from earlier + WinUAE). +9C0220 Blitter timing update from Toni. + Copper timing "theory" changed (me/Toni). + If we have a rdtsc insn, always synchronize with realtime in + vsync_handler. + Don't reset the lof bit when restoring state. + When restoring disk image names, put them in changed_prefs (Toni) + Return error in action_seek if trying to seek past end of file (Bernd + Roesch). + SDL fixes by Maik Qualmann. + Fix for gtk warnings when updating floppy LEDs (Maik Qualmann). +9C0216 Fix the clockspeed detection - we were getting lots of alarm signals + even after it had finished. + Some tweaks for the GUI - and also fix the problem with waiting on the + GUI semaphore even if no GUI is present... + More accurate blitter timing (Toni). + Support for A1000 bootrom and CDTV/CD32 extended ROMs (Toni). + Fix filesystem lockup with "copy dh0: ram: all". + Fix for JIT and more than 2MB chipmem from Toni + Make fsdb_win32 accept more valid Windows filenames (Toni). +9C0215 Fix filesystem reset code that used to access freed memory. +9C0213 gtk UI fixes from Maik Qualmann. +9C0113 Configury & bsd compilation fixes from Krister Walfridsson. + Match up lock/unlock calls in wgfx_do_flushline (found by Axel + Doerfler). + Fix potential crash taking strlen of NULL in filesys.c (Axel Doerfler). + Set diskdmaen to 0 in dsk_dmafinished (Toni). +9B1230 lockscr/unlockscr fixes in drawing.c. + Add sdlgfx from Bernd [4] Lachner. + Filesystem asm code improvements from Toni (make it pic, call + setup_exter earlier in the boot sequence, etc.) + Also add Toni's patch to make rtarea position configurable (keep it + at 0xF00000 for now, though). + Avoid installing filesystem stuff if user didn't request to mount + directories. + BEAMCON0 is only available with ECS Agnus. + Revert some bogus parts of the write_log patch. +9B1219 Add some missing clipping to the Picasso code. + Limit number of illegal-mem warnings. +9B1217 Fix the GUI crash when changing floppies. + Changes to support programs that change between HAM/no HAM in the + middle of a line. + Some bug fixes, and a big fprintf->write_log patch from Alex Kazik. +9B1125 Panning support for Picasso96 (in part from WinUAE). + More state save fixes from Toni, and a small disk.c update as well + which corrects track/gap lengths. + More evolution of the AHI code. +9B1124 Merged a few more small pieces from WinUAE (larger pieces in case of + the Picasso code). + CLXCON2 was never called or statesaved. Fixed by Toni. + Sound sample frequency now always based on PAL timings. +9B1123 Goodness! Massive memory corruption bug in picasso96.c - passing + last color changed to DX_SetPalette instead of count. + Fixes for the AHI code. + Changed prefetch emulation to be more similar to the one MAME uses. + Trace mode fixes (Bernd Roesch & myself). +9B1122 Redo the ExNext code in the filesystem to make sure we always match + opendir with closedir and to fix some renaming problems. + Fix hd changing code in gtkui. +9B1121 Mini-merge of noncontroversial WinUAE filesys.c code. + Add harddisk page to gtkui. Also change gui behaviour to wait for + the user to unpause before starting the emulator. + Add Toni's drive-led display. + Fixed a rather amazing source of crashes (we could fail to notice + the end of the frame in some cases). + Default to scanline mode. + Some tweaks to the SDL driver and the Win32 gui, mostly buffer-size + related. + Moved C source files back from tools directory (but still build them + there) to preserve my CVS history. +9B1119 Move all the build tools (gencpu, cpuopti etc.) into their own + directory which is configured separately. This was necessary to + avoid picking up SDL CFLAGS (which can #define main to _SDL_main, and + that breaks if you don't link with SDL), and to make cross-compiling + at least a little more likely. + Remove sanity check for SDL header file - rely on sdl-config getting + things right (not that we have much choice). + Move thread support code past sound code in configure, and make sure + that SDL sound enables threads. + Move sername into options structure. + Check for existance of isinf/isnan before using them. + Rather large WinUAE merge - this tree compiles again under Windows. + Most of the additional features are missing though. +9B1118 Restore code to mirror banks for 24 bit address space which got lost + when all the JIT memory changes were put in. + Speed up the CPU time calibration code. + Fix the broken file selector handling in the gtk ui. Add kickstart + selector. + Don't call XCloseDisplay, it apparently leads to crashes. + Try to solve the "missing write_log" problem in a sane way. + SDL joystick support. + When configure detects win32, use fsdb_win32 rather than fsdb_unix. +9B1117 Proper masking for DDFSTOP; proper handling of AUDLEN == 0, changed + delayoffset code, gencpu BFINS fix, and lots of disk updates (all + Toni). + Some additional regs for move2c/movec2 (also by Toni IIRC) +9B1115 COLOR_READ typo fix (Toni). +9B1024 Filesystem reset leak fixes (Brian) + Allocate enough memory for custom state saving. + bploff renamed to bpl_off. + AGA copper cycle diagram (Toni) + Disable disk_data_used optimization. +9B0926 Delayed palette setting for Picasso modes. Also fixed problem with + palette setting in CLUT emulation - we need to redraw the entire + screen if that happens. +9B0921 Miscellaneous small bugfixes. Delete some obsolete code. +9B0907 Beginnings of SDL support. Exterminated some penguins. +9B0825 Some xwin.c fixes from Maik Qualmann. +9B0730 Some sprite state machine tweaks. Fix sprite vs. DIW comparison. + HAM linebuffer was too small by half - oops. + Make absolutely, positively sure that when hsync_handler calls + sync_copper_with_cpu, we don't take any invalid shortcuts. + Memory management changes for JIT (Bernie [2], mostly). +9B0729 Silly mistake - need to call flush_plane_data unless plfleft is + -1, even if no planes were enabled. +9B0728 Small hack to reduce the time we lose with unnecessary + disk_doupdate_read calls. + Avoid calling flush_plane_data if we have no bitplanes enabled. + Tweak the SPCFLAG_INT handling to make "Delirium" demo work. + Limit rate of DDF warning messages. + Adjust display parameters so that things are shifted to the left + even more. + Fix (hopefully) CIA & blitter saving code. +9B0727 Copper code reorganized; speedup code rewritten. Can now be + enabled with a GUI setting. + Fixed the delayoffset stuff. +9B0725 AGA sprites, and some patches to sprite/playfield collision code, + mostly by Toni. + Fixed a small sprite restore problem; added missing code to map + fastmem banks when restoring them. + Some more state saving updates from Toni. +9B0724 Fix a nasty bug in the copper SKIP instruction introduced by recent + changes. + Update the FAST_COPPER code. Not quite enabled yet. + More work on the memory configuration stuff. + Fix CPU type writeout in cfgfile.c (taken from WinUAE source). + Move the WOC demo BPLCON0 fix to compute_toscr_delay (Toni). + Added Toni's new disk patches, which include HD disk support by + Adil Temel. + Rewrote the memory and audio save/restore code. + Mask DDFSTOP with 0xFE, not 0xFC. +9B0723 Yet another new and correct copper state machine (this time for sure) + Fix some AGA problems in DDF speedup code. + In gencpu.c, branch insns return a hardcoded cycle count; this had + not been updated for the CYCLE_UNIT stuff. Fixed. + xwin.c: If mouse is grabbed, we don't need mousehack. + Don't clear audio state if produce_sound == 0; this causes problems + if we want to turn the sound back on. + If an audio channel had a period of PERIOD_MAX, allow AUDxPER to + set its evtime back to a reasonable value. + Massive cleanup of memory initialization code; it will now use changed + prefs on reset. Added some memory options to gtkui.c. + Added Toni's state saving code, then added gtkui options and code to + initiate saving/restoring. +9B0722 filesys.c: Fix writeout of hardfile params (Bernie [2]) + Add an A1000 Kickstart disk loader (Gerald Schnabel). Got rid of + the automount_uaedev code; we can detect the Kickstart version and + do the right thing. + Deleted a few unused variables (Toni) + Avoid aborting in decode_ham if Amiga code turns on the HAM bit but + has too few bitplanes (found by Toni). + Make the dummy mem bank return other values than 0; helps some + stupid memory detection code. + Implemented a little exec task lister for the debugger. + Added new debugger commands from Mark Cox. Improved his copper list + debugger by adding recorded timing information to it. + MOVE16 fixes from Gwenole Beauchesne. + xBCD fixes by Maik Qualmann, with some additional flag fixes by myself + (ABCD & SBCD behave exactly like on a 68000 now; dunno about NBCD). +9B0520 AGA bscan2 fixes and disk.c kickstart speedup fixes from Toni. + Remove bogus changes I made to one of Toni's earlier disk.c updates. + Call RethinkICRA/B from INTREQ (suggested by Toni). + Properly save mixed_stereo setting. + NEGX uses X and Z (Bernd Roesch). + Danish keyboard support (Jesper Bojesen). +9B0311 Repair "emulated but no output" sound setting. +9B0310 Fix massive bug introduced in do_cycles_slow with the rescaling + changes. + CLXCON logic updated for AGA (Toni). Change meaning of collision_level + and add support for it in cfgfile.c. +9B0309 Fix problem where a fsdb file could prevent deletion of otherwise + empty directory discovered by Torsten Enderling. + Rescale return values of CPU emulator functions. +9B0225 Undo parts of the audio changes that made the "accurate" setting the + default. +9B0221 Make fsdb_unix compile again. +9B0219 Fix ddf for cases where start isn't aligned to fetchunit. + Fix some problems with the sound code going into infinite loops or + crashing. + Try to re-add Toni's ddf delay fixes properly. + Added a fix from Krister Walfridsson for X11 SHM code. + Rename OBJECT_NOT_FOUND to OBJECT_NOT_AROUND (not sure why, but the + win32 port does this; Fellow picked it up as well...) + Give in and allocate ainos with xcalloc. + Import fsdb_win32 code from Fellow. + Some tidyup and fixes in fsdb code. + Lose the lastdiv10 variable, and update CIA timers when reading them + (mostly by Bernie [2] Meyer) + Move reset_uaedevices and get_new_device to filesys.c. Add extra + parameter to get_new_device. +9B0213 Fix mouse pointer jumping bug in X11 code (Ralf Hoffmann) + Scaled event handling by a factor of 512. This allows more accurate + sound output frequencies, as well as more fine grained CPU speed + settings. + Implemented totally untested emulator side AHI support. +9B0211 Partially reverted changes made to the audio event code in 0.8.0. + Implemented "mixed" stereo. +9B0210 Fixed invisible sprite bug - sprite_width got a new meaning, and not + everything had been updated. +9B0121 cycles => get_cycles () (from Bernie [2] Meyer's JIT patchkit) +9B0120 Final bugfix in speedup code (plfleft got set too early). +9B0118 Fixed SPEEDUP code for AGA. Speedup now starts when fetch_state is + fetched_plane0. +9B0115 First batch of AGA playfield changes (Toni & myself). +9B0110 Small fix for the m68k_run macro (Bernie [2] Meyer) +9B0109 Use ntscmode from prefs structure (Dwayne C. Litzenberger) + Some 040 FPU fixes (Bernie [2] Meyer) + Delay DSKREADY a while; fix other small disk bugs (Toni Wilen) +9A0902 F0FF10 is now a puts () calltrap. +9A0830 Add some missing initializations in filesys.c, thanks to debugging by + Harald Frank. +9A0827 Fix a crash with framerate != 1. + Don't allow programs to see left & right or top & bottom simultaneously + with the keyboard joystick replacements. (Gee, games on the CPC and on + the Amiga actually have something in common - some of them crash when + the joystick is pushed in too many directions at the same time...) +9A0825 Put in the new sprite code. This has existed for many months but + I've only now found the final bugs. + New version of Bernd Meyer's special_mem code. Also add his + set_special/unset_special code, the noflags changes for gencpu, + and a fix for cpuopti's string matching. + Tiny clarification in table68k. + Add 68040 support from Basilisk. + readcpu.h is now included from newcpu.h. +9A0824 Rather massive overhaul of the DDF code. Many other timing fixes + (copper state machine mostly) (Sam Jordan and myself) + Get rid of stupid optimizations in color recording. + Synchronize CPU and copper in custom_wget. +9A0816 Introduce variable "special_mem", set it in each memory handler + that doesn't work on real memory (Bernd Meyer). +9A0815 Fix a really stupid bug in cfgfile_strval. + Nonfunctional support for switching between windowed/fullscreen modes + in gtkui. + Add (semi-broken) support in the debugger to create a trace logfile. + Take out most port-specific flags handling; x86 version kept with + slight name changes to indicate that this is code is suitable for + other ports as well. Took out HAVE_GAS while I was in configure. +9A0811 Fix the line doubling slowdown. +9A0809 Software autofire. + Remove one line from Makefile.in in the hope it will fix the build + errors people are seeing. +9A0807 Tighten up some minor aspects of spcflags handling. + Fix an AGA bug in customreset. + Set default CPU speed to approximate a A500. Tweak gencpu so that the + timings for this are more accurate. + Ignore T0 bit if not emulating a 68020. + Add an option to set the number of emulated floppy drives. + Improve the mfmcode function a bit. Faster and more accurate. + More SCSI patches from Patrick. + Add gui_data structure from WinUAE. Turn on gui leds again. +9A0725 Fix incorrect define of m68k_run for non-x86 systems (could have + sworn I already fixed that). +9A0723 Some SCSI patches by Patrick Ohly (which I got two months ago... oops) + Filesystem fixes from Brian. + AGA updates from Toni. +9A0627 Apydia loader fixes from Toni. +9A0611 Fix bug in filesys.c causing in-use ainos to get discarded. Thanks + to Brian for the analysis. +9A0608 Added some disk.c changes from Toni and a crude hack of my own to + speed up disk accesses done by the Kickstart. +9A0330 Change blitter not to translate memory addresses to native. Had to + disable 32 bit blits. + Floppy code changes (Toni Wilen) + Delete GGI port. + Fix toggle_inhibit_frame (Brian). +9A0228 Some WARPUP fixes, and changes to accomodate broken Amiga gzip (Sam + Jordan). +9A0221 Tweak POTGO a bit. Seems to work with BC Kid now. +9A0220 Fix off-by-one errors in expansion.c (Toni Wilen). + Remove AGA checks in DDFSTRT/DDFSTOP (Toni Wilen). + Turn off/restrict some warning messages. +9A0209 Fix some problems where the blitter nasty flag wouldn't ever get reset. + cia.c: Set all parallel port related bits to 1 when reading. +9A0208 gencpu.c: Fix saved PC for division by zero exception (found by Sam + Jordan). +9A0131 update_copper: Mask until_hpos properly. + Delay values are masked to 3 bit in hires mode (Sam Jordan). +9A0102 Only delay horizontal copper wait if vertical position matches exactly. + Tweak vblank end position for sprites. + Calculate playfield borders more accurately for case where we have + sprites. +9A0101 Reintroduce ev_copper; use it sparingly for longer waits within a + single line (but _not_ to time reads). + Fix a dumb bug in yesterday's changes that screwed up scrolling. +991231 drawing.c: Cruftectomy. genp2c.c: Gone. X86.S: mostly gone. +991229 Always use NTSC vblank_lastline for sprite purposes. + Make sprite logic recognize vertical stop even if vertical start has + not been reached (found by Sam Jordan). + Prevent move2c/movec2 instructions from incrementing the PC if they + raise an illegal instruction exception (found by Toni Wilen). +991212 ncurses port compiles again. + Disable serial interrupts in custom.c; they break things. +991208 Add a missing decide_line call in update_copper_1. +991206 Fix copper emulation to use state machine figured out by Sam Jordan. +991205 Fix event table corruption in disksync_handler. +991113 gencpu.c: Fix a problem with BTST. +991110 fpp.c: Initial set of changes merging code from Lauri Pesonen. +991024 Add missing type in m68k_run1. + Divisions by zero clear overflow bit. +991023 Fix compilation problem for ! HAVE_STEREO_SUPPORT. +991022 Rewrite disk read code to transfer some DMA words every raster line. + fpp_movem_index1 and fpp_movem_index2 were reversed (Brian King, Sam + Jordan). + Fix accuracy of fpp fix insns (Sam Jordan). + Allow ports to define their own FP 68881/host conversion functions (Sam + Jordan). + Get rid of all the HAVE_GET_WORD_UNSWAPPED code. + Fix prefetch for insn opcodes (Sam Jordan). + Fix call insn syntax in X86.S. + Tidy up sound interpolation support. + Readd old command line arg parsing. + Change "long unsigned int" to "unsigned long" in a couple of places. + Use Sam's version of the filesys.c fixes (action_parent_fh, + action_change_mode). + Fix a place in disk.c where a mfm buffer was zeroed instead of 0xaa'ed + (Sam Jordan). +991006 CPU emulator fixes by Christian Bauer + tui.c compilation fixes by Christof Petig. + Fix operand in one insn in X86.S (Brian). + zfile.c fix for filenames with embedded spaces (Ingo Ruhnke). + linux-ppc configury patch (Holger Jakob). + s,static __inline__,STATIC_INLINE, (Sam Jordan). + cfgfile.c: Don't use "t" modifier in fopen (Sam Jordan). + serial.c: Don't close file if fd < 0 (Sam Jordan). + filesys.c: Open files on readonly devices with O_RDONLY (Sam Jordan). + Fix bugs in parent_fh and change_mode actions (Sam Jordan). + WARPUP patch (Sam Jordan). +990621 Initial version of Richard Hoffmann's sound interpolation patches. + Fix a crash in action_set_comment. + De-inline 68k trace code. +990508 Fix rdtsc asm statement to show that edx is clobbered. + gtkui.c: Add pause button (Patrick Ohly) + configure.in: Check for -mpreferred-stack-boundary compiler option + and use it if found to set a sane value. +990429 X11 patches by Patrick Ohly. + Filesystem code extended to keep a simple database with information + about each file that is not representable on the host FS, such as + script/pure bits or filenotes. +990417 Bits and pieces merged from the Win32 port; mostly options stuff. Got + rid of getopt; added chipset options to prefs structure. +990411 Patches by Patrick Ohly: SCSI support and timehack tool. +990410 Applied easy parts of Toni's latest AGA patches. +990315 Attempts to fix Picasso crashes in SVGAlib version. +990216 picasso96.c: Some optimizations. + cfgfile.c: Save target specific options. Allow simple/smart choice + for centering options. Delete mount_data junk, substitute immediately. + Whitespace handling fixes. Fix config_description typo. + m68k flag handling redone. +990212 Implement rotate instructions without loops. Some other m68k + optimizations. + Some configure.in fixes. +990122 gtkui.c: Fixes for gtk 1.1.13. +990113 genp2c.c: Don't include custom.h. +990109 Some fixes in cfgfile.c. Make svga.c compile again. +981229 Miscellaneous fixes in the new config file stuff. + In config files, allow 68ec020 as CPU type, and get rid of 24 bit + addressing option. + Make the get_disp_ea non-inline. + SGI sound support (Ari Heikkinen). + More updates by Brian: + audio.c: Handle frequency, too, when changing sound prefs. Do some + work in update_audio even if not generating sound output. + filesys.c: Request 50 buffers in our parampacket. + Assorted right control key fixes. + Some updates in od-win32 (not nearly done...) +981228 Config file and option handling redone; based on work by Brian. + Rename UAEn: devices to DHn: (Brian). + filesys.c: Implement ACTION_CHANGE_MODE, ACTION_PARENT_FH; add support + for variable hardfile blocksizes (Brian). + Some Picasso96 updates (Brian). +981226 Win32 fsusage.c fixes; zfile bug fix; gui_fps addition (Brian). +981221 Fix gtkui to work with newer versions of gtk. + Fix gencpu so that FPU emulation doesn't crash when unswapped word reads + are available. +981129 gencpu.c: Delete all the queue_amode stuff again. + xwin.c: Allow switching between DGA and window mode (Marcus Sundberg). + DGA seems broken in X 3.3.3, however :( +981011 Teach cpuopti.c about epilogues that increment esp by popping. +980930 Add BSD socket code (Mathias Ortmann). +980923 filesys.c: Implement FH_FROM_LOCK (Brian King) +980823 xwin.c: French keyboard patch (Raphaël Poss). +980810 Fix RDTSC detection (Raphaël Poss). + newcpu.c: Patch by Brian King to display what kind of CPU table is + built. +980716 More AGA patches: use new macro GET_PLANES to calculate number of + bitplanes from BPLCON0; adapt the copper code; add BPLPT[HL][78] and + BPLDAT[78] (Toni Wilen) +980715 Change sd-uss/sound.c not to keep a file open in setup_sound, to + support reconfiguration. +980713 Fix m68k detection in configure.in. Clear execbase after allocating + chipmem (Holger Jakob) + od-dos update, tui.c patches (Gustavo Goedert) + Get rid of --enable-sound, always enable sound. + Make svga.c compilable. +980712 md-ppc-gcc patches (Holger Jakob) +980707 gtk ui: Better CPU speed selection. + Move initializations from add_filesys_unit to set_filesys_unit. +980706 AGA patches by Toni Wilen: Call calcdiw when changing fmode; fix + references to bplcon variables to go through dp_for_drawing; ifdef out + some code that's too hard to fix for now. + "Fix" the AGA color code. In pfield_linetoscr_aga, add lframe_end and + diw_end parameters and use them. Add some fill_line code for AGA. Make + sure no code touches acolors if [AGA_CHIPSET != 0] + New function finish_line_aga. +980705 drawing.c/custom.c: Get rid of line_changed, replace with a single + variable thisline_changed. Pass it to hsync_record_line_state and + evaluate it there. Get rid of BORDER_PREV and BORDER_NEXT states; + add LINE_BLACK/LINE_REMEMBERED_AS_BLACK to implement scanlines option. + Remove code in pfield_draw_line that checks line_changed. +980702 filesys.c: New function move_filesys_unit. + Win32 GUI fixes. +980701 gtk UI beautification and code cleanup (Michael Krause) + Beginning to make audio code run-time configurable (mostly by Michael + Krause) + Fix off-by-one errors in memory check handlers (Jake Hamby) + configure: Add AM_CYGWIN32, AM_EXEEXT and AM_MINGW32 and fix some Win32 + configuration problems. + genp2c: Fix symbol name braindamage. + md-i386-{gcc,watcom}.c: Don't do machdep_init when [_WIN32]. + Many Win32 compilation fixes. + filesys.c: Attempt to fix the mount code chaos. +980629 MOVEP bug fixes (Philippe Gerin) + Comment out code using readdir_r again. +980628 gencpu.c: Generate an end label only when it's needed. + configure.in: Check for windows.h, ddraw.h, sys/utime.h; check sizeof + __int64; check whether a small DirectX program compiles; check for + Watcom C; don't do GNOME_FILEUTILS_CHECKS when compiling on Win32 + without GNU C; use AC_EGREP_CPP in some places instead of compiling a + file by hand; check for GAS .p2align feature; check for USE_UNDERSCORE + with a small test program; add code to set up od-win32/md-i386-watcom + directories when appropriate. + genp2c.c: Use GAS .p2align feature; don't generate .type directive. + Rename md-*/memory.h to md-*/maccess.h. + More fixes in Win32 code. + Add wcc.sh and wrc.sh, two scripts to make it possible to use the + Watcom C compiler and the resource compiler in a Cygwin32 build + environment. +980626 Change zfile.c not to use fopen_del. +980614 Delete ihf_sem stuff. + picasso_refresh now nonstatic and called by check_picasso after a + notice_screen_contents_lost call. + More functions to access filesystem mount information. + More Win32 code. +980613 Use an AC_TRY_LINK block to check for libpthread. +980611 Rename lockscr/unlockscr to gfx_{lock,unlock}_picasso and add new + functions lockscr/unlockscr which are now called by drawing.c. + xwin.c: Clear picasso_invalid_lines in graphics_subinit and when + doing an XPutImage for a refresh. + New function reset_all_systems, which is a bit misnamed at the moment + because it only resets the filesystem. Called from m68k_go when a + reset is needed. + In filesys_prepare_reset, examine unit_pipe instead of self to + determine whether a unit has a thread that needs to be killed. Move + the reset_state and reset_sync_sem variable to UnitInfo so they are + available at all times. + Don't need to call finish_drawing_frame if we do a reset, it was + done a couple of lines earlier. + In uae_reset, do nothing if any reset or quit operations are in + progress. + Make DMACONR static. +980609 Add memory size fields in struct uae_prefs. New variables + allocated_xxxmem for every block of memory that holds the actual + amount currently allocated, copied from the preferences at allocation + time. + Create a new structure "uaedev_mount_info" to hold filesystem mount + information. Add a pointer to one of those in struct uae_options, + and copy it from currprefs to a filesystem private place when + starting the filesystem threads to a work area. + Terminate filesystem threads during a reset, and restart the whole + filesystem code afterwards so that prefs changes are noticed. +980608 If check_prefs_changed_gfx returns nonzero, or if we switch from/to + picasso mode, call notice_new_xcolors and notice_screen_contents_lost. + Delete the frame_do_semup crap. +980606 Create config.h link in configure, not in Makefile. +980604 xwin.c: No longer need picasso_max[wh]. Improve picasso invalid lines + code a bit more. Fix some dithering bugs. + gtkui.c (add_checkbox_widget, add_radio_widget): New helper functions. + Patches by Marcus Sundberg: + Make X11 picasso clut emulation mode work in DGA + gfxutil.c (setup_dither): Free redvals. +980602 Split out init_aspect_maps from reset_drawing. + Call check_prefs_changed_gfx from vsync_handle_redraw, and initialize + row and aspect maps if it returns nonzero. + Use an enum instead of integer values to communicate between + hsync_handler and hsync_record_line_state. + gtkui.c: Use gtk_window_set_title (Marcus Sundberg) + xwin.h: Add lockscr/unlockscr prototypes. +980601 Move check_prefs_changed_xxx into vsync_handle_redraw. + Make ersatz.c a little more crash-proof. +980531 New graphics specs 'a' and 'p'. Support them in the X11 version. +980530 sysdeps.h, posixemu.c: Change (char *) to (const char *) in the + arguments of some of the posixemu functions. + sysdeps.h: Delete getopt declaration. Include "getopt.h" in main.c. + aclocal.m4: add fsusage.c support from Gnome. + fsusage.[ch]: New files from fileutils, slightly modified to fit + into UAE and to add Win32 support. Adapt do_info filesys.c to use + it, and delete all the old cruft. + Some updates for the Win32 port. +980529 Patches for X11 version by Marcus Sundberg (Picasso invalid lines + optimization, XShm availability check, cleanup, etc.) +980528 Add field emergmem to struct vidbuf_description, and change + pfield_draw_line to use it. +980516 Patches by Samuel Devulder and Holger Jakob: update Amiga port, + add support for compiling cpuemu.c in seveal steps again, add + cheatsearch in the debugger. +980515 GGI patches (Christian Schmitt). + sd-mme: New directory (Marcus Sundberg). + Changes in the X11 version to support mixed DGA/normal binaries, + hotkeys, and mouse grabbing (Marcus Sundberg) + xwin.c: Copy a bit of code from Win32 port that constrains + lastmx/lastmy to real coordinates when ievent_alive. +980510 gencpu.c: Slightly better flag generation code. + picasso96.c (wgfx_flushline): Don't do anything if Picasso screen + is invisible. +980508 Don't disable GGI if we can't find svgalib. + newcpu.[ch], gencpu.c, md-i386-gcc/memory.h: Implement unswapped + word reads for opcodes. +980505 drawing.c: add missing #ifdef X86_ASSEMBLY. +980504 More BSD fixes from Krister. + xwin.c: Call XAllocColorCells for dithered modes. Don't set image_mem + in get_image, instead arrange for it to store the address in a pointer + chosen by the caller. + picasso96.h: Add a clut array to picasso_vidinfo. + picasso96.c (do_fillrect, do_blit): Use picasso_vidinfo.pixbytes + instead of picasso96_state.BytesPerPixel where appropriate. + (do_fillrect, do_blit, wgfx_do_flushline): Handle the case when the + Amiga-side buffer is a 256 color palette mode and the native buffer + is truecolor by looking up colors in the new picasso_vidinfo.clut. + xwin.c: Adapt to support emulating a palette display in truecolor. + Make tui.c compile. +980501 picasso96.c: Make sure there's an unlockscr for every lockscr call. + In SetColorArray, detect when no colors changed. + configure.in, aclocal.m4, Makefile.in: Use AM_PATH_GTK from gtk + distribution. + New field rgbformat in picasso_vidinfo. Set it in xwin.c and svga.c. + custom.c (mousehack_helper): Use Picasso screen offsets correctly. +980427 Call decide_line in DIWSTOP. Implement DIWHIGH register. +980426 filesys.c (get_nname): Don't allow Unix "." and ".." directories. + gencpu.c: Approximate the number of cycles per instruction. Make + generated functions return that number, and use it in newcpu.c in + the do_cycles call. + custom.c, drawing.c: init_hardware_for_drawing_frame must be + called from init_drawing_frame. + Move read_processor_time specific stuff to new file md-xxx/rpt.h. + md-i386-gcc/support.c: Try to detect whether the CPU has RDTSC. + newcpu.c: m68k_speed == 0 means approximate A500 speed; + m68k-speed == -1 means use frame rate hack when available. Some + changes to support this. +980425 custom.c: New copper code. Unfortunately not much faster than the + old one. + Get rid of some unused variables throughout. + filesys.c: Use readdir_r when available. + picasso96.c: In BlitPattern, correctly handle the pattern offsets. + missing.c: Get rid of getopt. Add GNU getopt instead. + In SPRxPTH, SPRxPTL, call decide_sprites instead of decide_line. +980421 custom.c: Add an extra argument, hpos, to plenty of functions, and + use it instead of calling current_hpos. +980420 BeOS update (Christian Bauer). + When enabling additional planes in post_decide_line, update + thisline_decision.bplcon0. + Tweak copper timings. +980419 Extend post_decide_line to handle cases where some planes are + enabled much later in the line than the others. + In pfield_doline_unaligned_h, don't increment dataptr. + Split custom.c, move drawing code to new file drawing.c. New header + file drawing.h for declarations of shared stuff. + osemu.h: Delete junk. +980418 gtkui.c: Don't crash if -G option is given. + audio.c, custom.c: Don't use the generic event handling mechanism + for audio emulation, the overhead is too high. update_audio: New + function, handles audio updates "on demand" or every hsync (Idea by + Petter Schau). +980417 Some cleanups in custom.c to make splitting it up easier. +980416 custom.c: Don't use bplhires in do_modulos. +980415 readdisk.c: Support FFS (Jim Cooper). + BSD patches by Krister Walfridsson. + configure.in, Makefile.in: More fixes for build != source directory. + Arrange to build p2c_x86.o when using md-i386-gcc. + sysdeps.h: Include limits.h. + Remove silly code that restricted possible version numbers. +980320 configure.in: Check for vprintf. + Make write_log a varargs function. Provide a write_log_standard + function that is used by most systems. + Refuse to compile with non-ANSI compilers. + gencpu.c: Rearrange some of the generated code to reduce register + pressure. + +Release 0.7.0 +980401 gengenblitter.c: Complete rewrite. Much smaller, much faster, much + better results. + Check for -lXi to support newer versions of gtk+. +980316 gencpu.c (read_counts): Two silly bugs fixed. + main.c (save_options): Don't write out 'a' if cpu_level < 2 + configure.in: Changes to try to be compatible with Solaris /bin/sh. +980315 New UAE-Control version from Tauno & Cloanto. + Make configure set UNALIGNED_PROFITABLE for x86. + Get rid of "-o", add save command to tui.c and gtkui.c. + Fix some bugs in save_options. +980314 Many improvements in the gtk UI. Made CPU type changeable at run-time. + Make DGA && ! VIDMODE configuration compile. Kludge around the fact + that DGA misses colormap changes. Call XWarpPointer to try to avoid + the click-moves-framebuffer bug. + Make sure p2c.[ch] don't get deleted. +980313 Move all CPU_LEVEL handling from build68k.c to gencpu.c. In gencpu.c, + ignore all parameters and don't write to standard output, instead + hardcode all filenames and generate them all at once. Arrange to + generate code for all CPU emulator variants and to select them at + run-time. + Get rid of copper cheat mode, re-use "-C" option for CPU selection. +980312 In COPxLCL, mask out LSB (Axel Wefers). + newcpu.h: Always compile in both get_disp_ea versions with a different + name. Delete USE_POINTER option; always use pointer. Don't fill + prefetch in m68k_setpc, do it in callers where necessary. Compile in + two versions of get_ixxxx, with different names for prefetch and + non-prefetch. Change gencpu.c to use these appropriately. + Don't generate 16 small CPU emulation source files. With a decent + machine it's no problem to compile all the code in one file. Also turn + off -O3 for gcc, -O2 does fine since all the necessary __inline__s are + there, and the compiler takes less memory that way. + Don't include , 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 + 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, , cfmakeraw, + 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 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 and #include in some more places. + Modify gencpu.c and readcpu.c so that immediate types j and J (0..15 + and 1..8) can be merged. Replace HAVE_ONE_GIG... option with a new + CPU_EMU_SIZE option that can be set to a value in the range 0..5, + where 0 is minimum size and 5 is equivalent to HAVE_ONE_GIG... +960225 Remove multiplications in sound code, use a big lookup table. +960222 Go back to having only one memory bank table of type addrbank instead + of several function pointer arrays. Eliminate the HAVE_BROKEN_SOFTWARE + define by extending the memory bank table to 65536 entries. + Remove remaining DUALCPU code. Allow BTST src,imm instructions in + table68k. +960220 Back out filesys.c change from Stefan Reinauer: don't call V36 specific + functions in expansion.library. + Better fix for the filesys.c assign problems by Oliver Moehrke. + Make new playfield code conditional on EXPERIMENTAL_SCREEN_UPDATE. + Improve the 64bit variant of said code. Try to get alignment for + apixels by putting it into a union with a long. + Kill the child in gui_exit(). Make graphics_init() return a value and + check it in main.c to see whether graphics were initialized. If not, + call gui_exit() anyway. + Use new 256 color allocation routine from svga.c in xwin.c, too. + Make LOW_BANDWIDTH compile _and_ work (wow...). +960219 Fix bug in memory.c: When loading 256K Kickstart, copy 256K, not 128K. +960218 Finished the rest of the UI: reset, debug and quit buttons as well as + drive LEDs. New target linux-gui; all others use dummy file nogui.c + for now. +960217 The GUI now supports inserting and ejecting diskfiles and displays + their names. Two pipes are used now, one for reading and one for + writing. Properly wait for the process to start up. + Use sigaction() instead of signal() in debug.c. + More fixes for the new display routines: Need to do a final call to + pfield_*word_*res with the data shifted right from the last fetched + word. +960216 Copper & sprite bugfixes from Marco Nelissen. Better X keyboard support + from Bruno Coste. + Move my_strdup() from filesys.c to options.h + New files xui.c, uae-ui (shell script) and uae-ui.tk (wish script). + These create a GUI for the X version of the emulator. So far, the + power LED works. +960215 Don't rely on SVGAlib headers defining any keycodes at all. + Include Thorsten Frueauf's NetBSD patch. Apparently, the devname + variable in hardfile.c caused a namespace collision, so rename it to + uaedevname. Fastmem fixes, debugger help, and ConfigDev allocation in + hardfile and filesys from Stefan Reinauer. + xwin.c: Give the window a title. + Half-implemented the DIVU.L, DIVS.L, MULU.L and MULS.L instructions. +960213 AF sound system support from Marcus Sundberg. Win95 keyboard support + for SVGAlib from Thierry Lescot. Added most of Gustavo Goedert's MS-DOS + port. + When using the old pfield_*word_*res functions, the gen_pfield_tables() + function was undefined. + Hmmm, /dev/brain must have been unmounted when I wrote the new pfield_* + functions. Now they make sure they access the apixels array only with + addresses that are multiples of 16 bytes. +960212 Fix copy&paste bug in cia.c found by Marco Nelissen: Need to call + RethinkICRB() instead of RethinkICRA() for CIA B timers. + Added Stefan Reinauers autoconfig area/fastmem support. Added run-time + options for use_slow_mem and use_fast_mem. + Oops, the pfield_*word_*res() optimizations break completely on HPs and + Sparcs. Now use this optimization only if we are using GCC 2.7. + HPUX fixes in the Makefile. New target hpux-gcc. + The code for clearing the areas above and below the DIW was trying to + be a little too clever selecting the color. Just use the current + background color. + Added channel attachment to the sound code. Untested. +960211 Found some flag setting bugs in the rotate/shift instructions and in + addx/subx (which I thought I had already fixed) by reimplementing + DUALCPU mode to work with Ed's e68k. + Argh! The copper is completely disabled during DDF in Hires 4 bitplane + mode - so copper positions 0x30 and 0x34 are about 640 pixels apart. + The Kickstart uses FF39FFFE to wait for the end of line 256 instead of + FFDFFFFE as in all the other modes. This is implemented now, but + probably not 100% correct. + Added check whether SVGAlib doesn't support our mode. + If using GCC >= 2.7, define __attribute__((aligned(16))) as + BIG_ALIGNMENT in config.h. Use it for the apixels array to prevent + potential problems on the Alpha. + Tried to make the color selection routine produce better results in 256 + color mode. +960210 readdisk didn't work at all for large files - fixed. + In pfield_doline(), clear the apixels array if playfield DMA is off. + In SPRxCTL(), reset sprite mode when sprpos==sprctl==0 + Rewrite pfield_orword_hires() and friends to use lookup tables. No + noticeable improvement on my machine, but might be different on other + machines. Two versions of this code: one using 64bit longs on the Alpha. + New targets linux-debug and linux-prof. + Use 1MB slow mem. + -funroll-loops is a little excessive. Remove it. + Add support for linear addressing modes for SVGAlib version. Speedup + is 20-30% on my old 486 VLB. Now, would someone please fix SVGAlib to + support that for the S3-864 as well? + Set SVGAlib keyboard mode to DONT_CATCH_CTRLC. + Change custom.c, xwin.c and svga.c to keep track of the display window + and background color and to clear the areas above and below the display + window if necessary to remove garbage images from previous frames. + Set the LOF bit in the Kickstart replacement init routine. Also + initialize CIAs to Kick 1.3-like values. +960209 Some more -DHAVE_xxx_H options in the Makefile and filesys.c. DEC Alpha + fixes for filesys.c from Ed and Marcus. HPUX fixes. + New field in table68k for CPU type, parsed by readcpu and compared to + CPU_LEVEL which is defined in config.h. New instructions MOVE2C, MOVEC2 + and CAS. Also a new field for priviledge level that is used by gencpu to + generate tests for regs.s and Exception(8) calls if necessary. + Move parsing of table68k into a new file build68k.c. Generate a file + called cpudefs.c containing the information from table68k in + machine-readable form. Change readcpu.c to use the array found in + cpudefs.c. + Don't generate the d8(An,Dn) addressing mode in-line. Generate a call to + get_disp_ea(), which is an inline function in newcpu.h if UAE is + configured for 68000 emulation; for 68020 emulation, it is defined in + newcpu.c. + Debugger could crash on illegals because there was no mnemonic defined + in lookuptab[]. + Return zero for SERDATR. +960207 It seems that the copper stops completely if an attempt to write to a + specific register fails because of COPDANG. Apparently, the Kickstarts + use this to stop the copper with a 0x00000000 longword. This leaves the + question why they don't do 0xFFFFFFFE like everybody else. + Enable 512K slow memory by default. + Integrate Stefan Reinauers battclock patch that makes it work with + newer Kickstarts. + In cia.c, do the little index pulse hack even if dskdmaen==1, because + DMA is only enabled when dskdmaen==2 (Helps the "Mad Decision" demo). + Add solaris entry to Makefile (GCC, Openwin, -DHAVE_STATFS_H) + Define HAVE_STRINGS_H for SGIs, change filesys.c accordingly. +960206 Build a smaller table instead of cputbl.c. Use readcpu and the smaller + table to build the cpufunctbl array at run-time. + Nuked the other half of the old CPU emulator. Reimplemented debugger to + use the information generated by readcpu. + Define HAVE_STATFS_H for SGIs in the Makefile, and use that as a test + in filesys.c instead of #ifndef __linux. + Hack filesys.c, get_path() to support the assign command. + Add -fstrength-reduce and -funroll-loops in Makefile to make people + nervous. + Rewrite Sam Devulder's LOW_BANDWIDTH patch and add it to xwin.c. +960205 Forgot some PC-relative bit instructions in table68k. + Nuked half of the old CPU emulator. + Split gencpu.c into two parts, new one is called readcpu.c and just + parses the table68k file. Link it to the main program. + +960205 Release 0.4 +960203 filesys.c, action_read(): Slightly more efficient code (translate Amiga + address to real pointer). + Moved some common code in the generate_* functions in gencpu.c to a + separate function. +960202 Added an experimental fast disk option. Currently turned off by + default (it's not such a big win). + Attached sprite fixes (overlapping att. sprites looked bad, Katakis). + Add sleep(1) before resetting the console to text mode when using + SVGAlib: this might fix some screen corruption problems. + Add sprite/playfield priority checking to the most important case + (single playfield, no HAM). + In filesys.c, do_find(): open() returns -1 on error, not zero. + Return ERROR_OBJECT_WRONG_TYPE if do_find() is called for a directory + (fixes Champions of Krynn harddisk installation). +960201 Don't abort if sound driver not present, just set produce_sound to 0. + New files keybuf.c and keybuf.h to record keypresses in the right + order and without losing any. In cia.c, force 15 scanlines between + keypresses, just to be sure. + unixfs.device _does_ work with Kick 1.3: just don't trust what Kick 1.3 + sends in the startup packet. For now, disable more than one mount per + command line. + Started integrating Ernesto's new Mac sources. + Remove superfluous includes from some files. +960131 Added Ed's unixfs.device (great stuff). + Adding ULONGs to pointers is a bad idea on the Alpha if the ULONG value + really is signed. Add some casts to LONG in (pc_p + src) expressions + in genpu.c. + If DMACON is written and copper DMA is enabled, do a COPJMP1 at once. + Helps the "Interference" demo. +960129 More SGI fixes from Ed. Bugfixes and transdisk improvements from Marcus + Sundberg. + Remove EXTRA_DEFINES from Makefile. Breaks some systems. + Move common sprite code from pfield_doline() and pfield_doline_slow() + to new function pfield_sprite(). The same sprite may appear more than + once on the same line, so don't shift out the bits of sprdata[] and + sprdatb[] while displaying it (Turrican I). + In xwin.c and svga.c, barf if LINUX_SVGALIB doesn't match the file + being compiled. + Make all .o files depend on config.h in the Makefile. + No need to exit if sound driver unavailable, but -S given. + Small debugger fix: Missing space in output. + Fix for the sprite logic: Specifically, use a state variable indicating + whether the sprite has been restarted after a VSYNC. Fixes most + Turrican problems. +960124 Added Denis Sablic's patch for sound run-time option. + Added Ed Hanway's patch for better Makefile, X mouse cursor blanking + and more SGI compilation fixes. +960123 Include options.h everywhere. + Handle 8 bit GrayScale visuals like PseudoColor. + Remove C++ leftovers from joystick code. +960122 When using the joystick driver, the button test must come after + handle_events() in vsync_handler(). +960118 Removed all the remaining C++ comments. Changed all inline keywords to + __inline__. Define __inline__ if not using gcc. + Make proper prototypes for everything. Compile with maximum warnings + + -ansi + -pedantic. + Remove CIA_cycle(), obsolete. + Reimplemented the STOP optimization in newcpu.c. Removed DualCPU + support in CPU emulator. + Real nasty bug in pfield_doline() fixed: sprxpos could be evaluated as + negative, with not-so-amusing results. (Need to rewrite this in + Oberon to get array bounds checking :-) +960117 Heroic effort: Rewrote the thing in C. This might help fix some + problems with users being unable to compile it. + Fixed a problem in hsync_handler(): Only call flush_line() for lines + in the display window, i.e. when we did a prepare_line() before. + Better code for relative branches: Don't use setpc(getpc()+x) calls, + increment regs.pc_p instead. +960116 Reimplemented the function to load the Kickstart ROM. Use stdio instead + of fstreams since this apparently does not work on the Mac. Detect 256K + Kickstarts. Detect corrupt ROM images (calculate checksum). + Added Ernesto Corvi's Mac port. Changed it around a bit, so it + probably won't compile. +960115 Reinstate config.h options for X screen depth, so that DrawPixel() can + be inlined in custom.cc for speed. xlinebuffer is now incremented in + each call to DrawPixel() (for both X and SVGAlib) to get rid of some + address calculations. +960114 Fixed X generic pixel drawing routine for SHM. + Still trying to fix the harddisk emulation. + uae.device no longer breaks the debugger (can step through uae.device + functions now) + Bugs affecting performance: SPCFLAG_STOP never got reset, and DSKLEN() + would set SPCFLAG_DISK even if DMA was being turned off. + Made slow memory a run-time option. + Defer interrupts by one CPU instruction to give programs a chance to + read INTREQR ("Seeing is Believing" and "Substance" demos) + Added ScrollLock hack for X, too. +960113 SVGAlib version compiles again. Fixed SVGAlib mouse bug. + Fixed SHM bug: Maximum scanline is 313, not 312. + Sometimes, disk.cc missed a side change and would read the wrong data. + Fixed. Apparently, this was the worst compatibility problem. + Implemented trace mode. +960112 Changed layout of class amigamemory a little so that gcc can generate + better addressing modes. + Finally wrote functions in gencpu to generate MOVEMs. +960109 Integrated Ed Hanway's patches for better X support and run-time + configuration of some options. + Got rid of the direct VGA memory access. (Need to do this differently). + Changed the method of drawing lines: custom.cc now tells the graphics + code the line number and whether it needs to be doubleed before drawing + it. + Added Andre Beck's MIT-SHM patch. + Remove warnings for newcpu.cc. +960108 Fixed exceptions in op_illg(): Need to decrement PC. +960107 Added an "uae.device" resident module at 0xF00000. This emulates a hard + disk (fixed size 8MB for now). +960106 Moved some common code from pfield_doline() and pfield_doline_slow() to + a separate function. This fixes a potential HAM bug (two static vars + for the same value). + Sound support for Linux. Works only with graphics off and the CPU + slowed down. + Better SVGAlib keyboard support. +960105 Added AvailMem(), AllocMem(), AllocAbs() and FreeMem() dummies. + The Hardwired demo times the multiplication instructions and prints + "This demo don't like Axel" if they are too fast. Apparently, Axel has + a 68040. Added a WANT_SLOW_MULTIPLY option to config.h. + Fixed the fast blitter emulation (seems to work now). +960104 Fixed all the ChangeLog entries from 95 that said 96 (oops??!) + pfield_may_need_update() should check whether bitplane DMA is on. + Added ersatz.cc and ersatz.h. The purpose of these files is to + implement one or two Kickstart functions that are commonly called from + bootblocks. This should help support some games and demos that only use + the Kickstart as an initial track loader. So far, it's only good enough + for one program. +951223 More intelligent event handling in the CPU emulator. Slightly faster. +951222 Optimize CPU emulation by inlining cctrue(). Also, the real PC no + longer needs to be incremented each instruction. The real PC value + now has to be fetched by m68k_getpc(). + Added direct screen access for SVGAlib, but it didn't help much. I'll + probably remove it again. + The gencpu executable is 2M smaller if it allocates memory + dynamically. +951216 custom_bput() enhanced a little. Now remembers the value that was + written in the other half of the register. + Apparently, the USEx bits of BLTCON0 are ignored in line draw mode. + (Silents-Demo) + +951212 Release 0.3 +951212 Included Alessandro's battclock patch. + Fixed mouse autocalibration for wrong-aspect screens. +951210 Joystick support for Linux. + Better color matching for 256 color modes. + Rewrote most of the memory management in plain C, mainly to avoid the + various template bugs in some compilers, but also because gcc can't + handle the regparm attribute for virtual functions yet. +951209 Added Alessandro's patches for automatic mouse calibration. + Tried to optimize the blitter loop a bit. Doesn't work. +951205 Added Hannu's patches for diskfile write support. +951201 More portability fixes, especially for weird compilers that workstation + vendors ship. +951125 More keys for X, some keyboard support for SVGAlib (slightly + dangerous); beginnings of US keyboard support. +951124 256 color mode support for SVGAlib. FAST! +951123 Tiny tweak to central loops in playfield code results in much better + assembly. Apparently, GCC does not feel too good about optimizing + reference variables. +951113 Bug fix in the events code (nextevent must not be changed while events + are being processed). +951112 The playfield can now be drawn with the right aspect (i.e., every line + twice). Slower, but looks nicer and supports interlaced mode + (flickerfree!). The first 29 lines (blanking interval) are omitted + now to fit everything in 800x600. + Oops, disk drive identification did not work. Fixed, all four drives + appear now. + Oops, CIA_reset() was there all the time but never got called. + Optimized the planar->chunky conversion in pfield_doline() a little. + This really is time critical. +951111 If colors change on a line, we might still be able to use the full + line update, if the change occurred outside the DIW. Have to be a + little careful, though. + Playfield code now uses real pointers again, but makes sure it can + read enough bytes to complete the current line without segfaulting. + Oops, my "better estimate" (see below) was a mistake. Restored the + original 4 hw cycles per instruction relation. This slows down the + emulator while booting (more screen refreshs), but speeds up many + demos that otherwise spend most of their time waiting for a specific + raster position. + Playfield modulos must be added immediately when DDF stops. (WOC demo) + Portability fixes in disk.cc (null pointers). + Implemented average frame rate calculation ('c' in the debugger). + Debugger fixes. + Sprite fixes (height was wrong, wrong priorities in fast update) + Added an AutoConfig expansion RAM device. The OS seems to recognize + it, but breaks sometime later (seems to be the same bug that kills + the emulator when there's RAM at 0xC00000). + SVGAlib now has mouse support, too. + HAM mode implemented. +951110 Implemented fast complete line playfield update. Switches back if + necessary. Fixed attached sprites bug. + Copper wait no longer slows down the CPU emulation. (there were + lots of new copper bugs because of this, but I hope I fixed all + of them). + Changed cia?t? from UWORD to ULONG, since there were overflows in + the assertion (because of 65535+1 == 0). +951108 The DIVS remainder could have the wrong sign. + New HAVE_BROKEN_SOFTWARE define in config.h that makes the emulator + mask out the high byte of all addresses. + Wrote genblitter.cc and replaced the awful code in blitter_blit() + and blitter_line() with calls to the generated function. +951107 Implemented ?BCD. These don't really work yet. + +951106 Release 0.2 +951105 Fixed a bug in the new CIA timer code. + Fixed flag settings for some cases of ADDX/SUBX +951104 Changed the main loop a bit - call all the *cycle() functions only if + it is really necessary. I hope everything still works - at least it is + twice as fast now :-D + Improved mouse emulation - avoid overflows, permit "wraparound". + Added debugger 'g' command. + Removed some useless casts from the CPU emulator. + Added a configuration option to prevent checks for odd addresses. Only + very bad programs need this check. +951103 The sprite emulation sometimes did not work too well, especially with + dual playfield mode. Hopefully fixed. +951102 The 10 cycle counter is more like a 5 cycle counter in this + implementation. (Fine, that makes floppy loading even faster :-) + Implemented mouse movement. Totally out of sync with the X pointer, + but at least something. + Found out about the XAutoRepeatOff() function. Real useful. + DualCPU mode works again. + Corrected flag settings for CMPA.W. + Fixed DIV instructions: Don't change dest in case of overflow. +951031 The PC is now converted to a real pointer. This is safe (much safer + than converting bitplane pointers, since the PC always has to be valid) + and should speed things up a little. +951029 Some primitive event handling: 2 mouse buttons and 1 joystick button + are emulated, as well as parts of the keyboard (only german mapping). + Fixes: Delay values and sprite widths are always LoRes. Playfield 2 + uses colors 9..15. + Implemented a frame rate configuration option that can speed up the + emulation quite a bit. +951028 A-ha. The 68000 has one strange feature after all. MOVEM.W to Dn sign + extends the value to a longword. + Katakis expects that accessing odd addresses causes exception 3, so + we have to emulate this. *Sigh* + Do at least something with the index pulse bit. It's more or less a + toggle now. + Implemented sprites & dual playfields, both with small glitches. +951027 When LOF is set, the frame is one line longer. +951026 Implemented a preliminary diskfile type for special formats. Turrican + boots up correctly (crashes if I want to play a game, though). + Implemented EHB and added a few missing masking operations in the color + handling. + Fixed the absw addressing mode - need to sign extend here as well. +951025 Fixed another extremely stupid bug, this time in the playfield code. + Each pixel was calculated four times... + Increased the size of the apixels array - this was being overrun. +951024 Fixed an extremely stupid bug in flag settings for byte and word + operations. + The "sectors until gap" field must be in the range 1..11 instead of + 0..10, or very bad things will happen if it is used to calculate a + blit size. +951021 Don't use real pointers to fetch bitplane data - too many segfaults. + Delay the copper after executing an instruction, or wait sequences like + FFDF FFFE 0200 FFFE won't work. + Some programs expect that the CPU is completely turned off if the + blitter nasty bit is set. So be it. + The RSI Megademo chokes when disk DMA fetches two syncs. Leave one out. + The LOF bit wasn't set correctly. +951020 Blitter fixes: Load fill carry from FCI each line; keep the masked + value of bltadat in bltolda + Give the CPU twice as many "cycles" - this still is not even remotely + correct, but a better estimate. +951017 Added SVGAlib support. Unfortunately, my graphics card isn't fully + supported by the current SVGAlib version. +951015 More small optimizations to memory.h and custom.cc. + Added code for 256 color screens. The type of screen has to be + selected at compile time. +951014 Modified the memory management to be (hopefully) a little more + efficient. + Changed gencpu.cc to generate functions and a big function pointer + array instead of the old case labels. The generated C++ files now + compile a lot faster, and the code should be better as well. +951013 Implemented pseudo POTGOR to keep the RMB from being detected as + pressed all the time. + GenerateDecTab() generated TRAP incorrectly. + Made some more instructions (MOVE.B A0,D0 etc) illegal in gencpu.cc. + Fixed X colors. Fixed data fetching for HiRes screens. +951011 EXT.WL instructions set the flags. + Implemented second CPU emulator, plus "DualCPU" option. The new CPU + emulator is generated automatically from a file called table68k by + a program called gencpu. +951002 Removed version information from the file headers. + Removed some sillinesses in custom.cc. + DSKLEN bug fixed (mask out 0xC000). + Playfield code rewritten. Now supports horizontal scrolling. Implemented + some primitive color support. +950927 Fixed predecrement/postincrement addressing with byte size for the + stack pointer. +950926 Fixes to the disk code: Terminate disk DMA, flip disk side, read more + than just two sectors during disk DMA, fix checksum calculation. + Fixed copper comparison bugs. + +950901 Release 0.1 +950826 bugfix in GenerateDecTab(): LEA.W instructions were generated. +950312 New file disk.cc, for (guess what) disk support. Doesn't work yet. +950311 Multiplication instructions were generating 16 bit results. + Sign extension was wrong in some places. + Removed bugs in the blitter (one word width: ALWM & AFWM and line mode) + The Kickstart logo looks perfect now. + Playfield routine should check BPLCON0 instead of BLTCON0 +950309 ASR D8,D0 is not a valid instruction. + Bitplane pointers were not incremented. + Copper comparison didn't work. COP2LC and bitplane pointers were written + incorrectly. Fixed. + Something that bears a striking resemblance to the familiar Kickstart + logo now appears in my X window! +950306 ROR used to set the X flag. Bug fixes in GenerateDecTab. + More bug fixes in several 68000 instructions. + Improved blitter. ?????? KS1.3 doesn't seem to set BLTDMOD on a + line draw. What is this?? + Fixed stupid bugs in playfield code. +950305 fixed bugs in opcode generation and interrupt handling. Implemented + STOP. Fixed flag settings: Result wasn't masked. Ooops!! + ADDQ #imm,An doesn't set flags. + One-shot timer mode didn't work. + Implemented blitter, doesn't work. + Some primitive and slow playfield support, only to make the things that + hopefully will soon appear visible. +950304 CIA timers ought to work OK. Copper is emulated. + Emulator loops infinitely when trying to initialize the console.device +950303 experiments with X, figured out how to open a window and draw pixels. + No graphics emulation yet, though. +950301 Nearly all instructions work. + Fixed supervisor mode stack. + The memory manager now handles CIA chips. +950228 Bug fixes in 68000 code, exceptions and more instructions implemented + Memory management extended to handle custom chips as well. + Debugger improved. + Kickstart passes memory & CPU type test, builds up some system + structures. +950227 MC68000 & little debugger for tracing. It can execute the first couple + of KS1.3 instructions, but doesn't get past the memory test. +950225 Work begun diff --git a/akiko.c b/akiko.c new file mode 100755 index 00000000..31f7f581 --- /dev/null +++ b/akiko.c @@ -0,0 +1,1453 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * CD32 Akiko emulation + * + * - C2P + * - NVRAM + * - CDROM + * + * Copyright 2001, 2002 Toni Wilen + * + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "memory.h" +#include "events.h" +#include "savestate.h" +#include "blkdev.h" +#include "zfile.h" +#include "threaddep/thread.h" +#include "akiko.h" +#include "gui.h" + +#define AKIKO_DEBUG_NVRAM 0 +#define AKIKO_DEBUG_IO 0 +#define AKIKO_DEBUG_IO_CMD 0 + +int cd32_enabled; + +static int m68k_getpc(void) { return 0; } + +/* + * CD32 1Kb NVRAM (EEPROM) emulation + * + * NVRAM chip is 24C08 CMOS EEPROM (1024x8 bits = 1Kb) + * Chip interface is I2C (2 wire serial) + * Akiko addresses used: + * 0xb80030: bit 7 = SCL (clock), 6 = SDA (data) + * 0xb80032: 0xb80030 data direction register (0 = input, 1 = output) + * + * Because I don't have any experience on I2C, following code may be + * unnecessarily complex and not 100% correct.. + */ + +enum i2c { I2C_WAIT, I2C_START, I2C_DEVICEADDR, I2C_WORDADDR, I2C_DATA }; + +/* size of EEPROM, don't try to change, + * (hardcoded in Kickstart) + */ +#define NVRAM_SIZE 1024 +/* max size of one write request */ +#define NVRAM_PAGE_SIZE 16 + +static uae_u8 cd32_nvram[NVRAM_SIZE], nvram_writetmp[NVRAM_PAGE_SIZE]; +static int nvram_address, nvram_writeaddr; +static int nvram_rw; +static int bitcounter = -1, direction = -1; +static uae_u8 nvram_byte; +static int scl_out, scl_in, scl_dir, oscl, sda_out, sda_in, sda_dir, osda; +static int sda_dir_nvram; +static int state = I2C_WAIT; + +static void nvram_write (int offset, int len) +{ + struct zfile *f = zfile_fopen (currprefs.flashfile, "rb+"); + if (!f) { + f = zfile_fopen (currprefs.flashfile, "wb"); + if (!f) return; + zfile_fwrite (cd32_nvram, NVRAM_SIZE, 1, f); + } + zfile_fseek (f, offset, SEEK_SET); + zfile_fwrite (cd32_nvram + offset, len, 1, f); + zfile_fclose (f); +} + +static void nvram_read (void) +{ + struct zfile *f; + + f = zfile_fopen (currprefs.flashfile, "rb"); + memset (cd32_nvram, 0, NVRAM_SIZE); + if (!f) return; + zfile_fread (cd32_nvram, NVRAM_SIZE, 1, f); + zfile_fclose (f); +} + +static void i2c_do (void) +{ +#if AKIKO_DEBUG_NVRAM + int i; +#endif + sda_in = 1; + if (!sda_dir_nvram && scl_out && oscl) { + if (!sda_out && osda) { /* START-condition? */ + state = I2C_DEVICEADDR; + bitcounter = 0; + direction = -1; +#if AKIKO_DEBUG_NVRAM + write_log ("START\n"); +#endif + return; + } else if(sda_out && !osda) { /* STOP-condition? */ + state = I2C_WAIT; + bitcounter = -1; +#if AKIKO_DEBUG_NVRAM + write_log ("STOP\n"); +#endif + if (direction > 0) { + memcpy (cd32_nvram + (nvram_address & ~(NVRAM_PAGE_SIZE - 1)), nvram_writetmp, NVRAM_PAGE_SIZE); + nvram_write (nvram_address & ~(NVRAM_PAGE_SIZE - 1), NVRAM_PAGE_SIZE); + direction = -1; +#if AKIKO_DEBUG_NVRAM + write_log ("NVRAM write address %04.4X:", nvram_address & ~(NVRAM_PAGE_SIZE - 1)); + for (i = 0; i < NVRAM_PAGE_SIZE; i++) + write_log ("%02.2X", nvram_writetmp[i]); + write_log ("\n"); + +#endif + } + return; + } + } + if (bitcounter >= 0) { + if (direction) { + /* Amiga -> NVRAM */ + if (scl_out && !oscl) { + if (bitcounter == 8) { +#if AKIKO_DEBUG_NVRAM + write_log ("RB %02.2X ", nvram_byte, m68k_getpc()); +#endif + sda_in = 0; /* ACK */ + if (direction > 0) { + nvram_writetmp[nvram_writeaddr++] = nvram_byte; + nvram_writeaddr &= 15; + bitcounter = 0; + } else { + bitcounter = -1; + } + } else { + //write_log("NVRAM received bit %d, offset %d\n", sda_out, bitcounter); + nvram_byte <<= 1; + nvram_byte |= sda_out; + bitcounter++; + } + } + } else { + /* NVRAM -> Amiga */ + if (scl_out && !oscl && bitcounter < 8) { + if (bitcounter == 0) + nvram_byte = cd32_nvram[nvram_address]; + sda_dir_nvram = 1; + sda_in = (nvram_byte & 0x80) ? 1 : 0; + //write_log("NVRAM sent bit %d, offset %d\n", sda_in, bitcounter); + nvram_byte <<= 1; + bitcounter++; + if (bitcounter == 8) { +#if AKIKO_DEBUG_NVRAM + write_log ("NVRAM sent byte %02.2X address %04.4X PC=%08.8X\n", cd32_nvram[nvram_address], nvram_address, m68k_getpc()); +#endif + nvram_address++; + nvram_address &= NVRAM_SIZE - 1; + sda_dir_nvram = 0; + } + } + if(!sda_out && sda_dir && !scl_out) /* ACK from Amiga */ + bitcounter = 0; + } + if (bitcounter >= 0) return; + } + switch (state) + { + case I2C_DEVICEADDR: + if ((nvram_byte & 0xf0) != 0xa0) { + write_log ("WARNING: I2C_DEVICEADDR: device address != 0xA0\n"); + state = I2C_WAIT; + return; + } + nvram_rw = (nvram_byte & 1) ? 0 : 1; + if (nvram_rw) { + /* 2 high address bits, only fetched if WRITE = 1 */ + nvram_address &= 0xff; + nvram_address |= ((nvram_byte >> 1) & 3) << 8; + state = I2C_WORDADDR; + direction = -1; + } else { + state = I2C_DATA; + direction = 0; + sda_dir_nvram = 1; + } + bitcounter = 0; +#if AKIKO_DEBUG_NVRAM + write_log ("I2C_DEVICEADDR: rw %d, address %02.2Xxx PC=%08.8X\n", nvram_rw, nvram_address >> 8, m68k_getpc()); +#endif + break; + case I2C_WORDADDR: + nvram_address &= 0x300; + nvram_address |= nvram_byte; +#if AKIKO_DEBUG_NVRAM + write_log ("I2C_WORDADDR: address %04.4X PC=%08.8X\n", nvram_address, m68k_getpc()); +#endif + if (direction < 0) { + memcpy (nvram_writetmp, cd32_nvram + (nvram_address & ~(NVRAM_PAGE_SIZE - 1)), NVRAM_PAGE_SIZE); + nvram_writeaddr = nvram_address & (NVRAM_PAGE_SIZE - 1); + } + state = I2C_DATA; + bitcounter = 0; + direction = 1; + break; + } +} + +static void akiko_nvram_write (int offset, uae_u32 v) +{ + int sda; + switch (offset) + { + case 0: + oscl = scl_out; + scl_out = (v & 0x80) ? 1 : 0; + osda = sda_out; + sda_out = (v & 0x40) ? 1 : 0; + break; + case 2: + scl_dir = (v & 0x80) ? 1 : 0; + sda_dir = (v & 0x40) ? 1 : 0; + break; + default: + return; + } + sda = sda_out; + if (oscl != scl_out || osda != sda) { + i2c_do (); + oscl = scl_out; + osda = sda; + } +} + +static uae_u32 akiko_nvram_read (int offset) +{ + uae_u32 v = 0; + switch (offset) + { + case 0: + if (!scl_dir) + v |= scl_in ? 0x80 : 0x00; + else + v |= scl_out ? 0x80 : 0x00; + if (!sda_dir) + v |= sda_in ? 0x40 : 0x00; + else + v |= sda_out ? 0x40 : 0x00; + break; + case 2: + v |= scl_dir ? 0x80 : 0x00; + v |= sda_dir ? 0x40 : 0x00; + break; + } + return v; +} + +/* CD32 Chunky to Planar hardware emulation + * Akiko addresses used: + * 0xb80038-0xb8003b + */ + +static uae_u32 akiko_buffer[8]; +static int akiko_read_offset, akiko_write_offset; +static uae_u32 akiko_result[8]; + +static void akiko_c2p_do (void) +{ + int i; + + for (i = 0; i < 8; i++) akiko_result[i] = 0; + /* FIXME: better c2p algoritm than this piece of crap.... */ + for (i = 0; i < 8 * 32; i++) { + if (akiko_buffer[7 - (i >> 5)] & (1 << (i & 31))) + akiko_result[i & 7] |= 1 << (i >> 3); + } +} + +static void akiko_c2p_write (int offset, uae_u32 v) +{ + if (offset == 3) akiko_buffer[akiko_write_offset] = 0; + akiko_buffer[akiko_write_offset] |= v << ( 8 * (3 - offset)); + if (offset == 0) { + akiko_write_offset++; + akiko_write_offset &= 7; + } + akiko_read_offset = 0; +} + +static uae_u32 akiko_c2p_read (int offset) +{ + uae_u32 v; + + if (akiko_read_offset == 0 && offset == 3) + akiko_c2p_do (); + akiko_write_offset = 0; + v = akiko_result[akiko_read_offset]; + if (offset == 0) { + akiko_read_offset++; + akiko_read_offset &= 7; + } + return v >> (8 * (3 - offset)); +} + +/* CD32 CDROM hardware emulation + * Akiko addresses used: + * 0xb80004-0xb80028 + * + * I can't believe cd.device and custom loaders are fooled to think + * this piece of crap emulates real CD32 CDROM controller and drive :) + */ + +#define CDSTATUS_FRAME 0x80000000 +#define CDSTATUS_DATA_AVAILABLE 0x10000000 +#define CDSTATUS_DATASECTOR_ERROR 0x08000000 /* ?? */ +#define CDSTATUS_DATASECTOR 0x04000000 +#define CDSTATUS_UNKNOWN 0x02000000 + +#define CDS_ERROR 0x80 +#define CDS_PLAYING 0x08 + +static uae_u32 cdrom_status1, cdrom_status2; +static uae_u8 cdrom_status3; +static uae_u32 cdrom_address1, cdrom_address2; +static uae_u32 cdrom_longmask; +static uae_u32 cdrom_readmask_r, cdrom_readmask_w; +static uae_u8 cdrom_command_offset_complete; /* 0x19 */ +static uae_u8 cdrom_command_offset_todo; /* 0x1d */ +static uae_u8 cdrom_result_complete; /* 0x1a */ +static uae_u8 cdrom_result_last_pos; /* 0x1f */ +static uae_u8 cdrom_result_buffer[32]; +static uae_u8 cdrom_command_buffer[32]; +static uae_u8 cdrom_command; + +#define MAX_TOC_ENTRIES 103 /* tracks 1-99, A0,A1 and A2 */ +static int cdrom_toc_entries; +static int cdrom_toc_counter; +static uae_u8 cdrom_toc_buffer[MAX_TOC_ENTRIES*13]; + +static int cdrom_disk, cdrom_paused, cdrom_playing; +static int cdrom_command_active; +static int cdrom_command_length; +static int cdrom_checksum_error; +static int cdrom_data_offset, cdrom_speed, cdrom_sector_counter; +static int cdrom_current_sector; +static int cdrom_data_end, cdrom_leadout; +static int cdrom_dosomething; + +static uae_u8 *sector_buffer_1, *sector_buffer_2; +static int sector_buffer_sector_1, sector_buffer_sector_2; +#define SECTOR_BUFFER_SIZE 64 +static uae_u8 *sector_buffer_info_1, *sector_buffer_info_2; + +static int unitnum = -1; + +static uae_u8 frombcd (uae_u8 v) +{ + return (v >> 4) * 10 + (v & 15); +} + +static uae_u8 tobcd (uae_u8 v) +{ + return ((v / 10) << 4) | (v % 10); +} + +static int fromlongbcd (uae_u8 *p) +{ + return (frombcd (p[0]) << 16) | (frombcd (p[1]) << 8) | (frombcd (p[2]) << 0); +} + +/* convert minutes, seconds and frames -> logical sector number */ +static int msf2lsn (int msf) +{ + int sector = (((msf >> 16) & 0xff) * 60 * 75 + ((msf >> 8) & 0xff) * 75 + ((msf >> 0) & 0xff)) - 150; + if (sector < 0) + sector = 0; + return sector; +} + +/* convert logical sector number -> minutes, seconds and frames */ +static int lsn2msf (int sectors) +{ + int msf; + sectors += 150; + msf = (sectors / (75 * 60)) << 16; + msf |= ((sectors / 75) % 60) << 8; + msf |= (sectors % 75) << 0; + return msf; +} + +static void cdaudiostop (void) +{ + cdrom_playing = 0; + cdrom_paused = 0; + if (unitnum < 0) + return; + sys_command_pause (DF_IOCTL, unitnum, 0); + sys_command_stop (DF_IOCTL, unitnum); + sys_command_pause (DF_IOCTL, unitnum, 1); +} + +static uae_u32 last_play_end; +static int cd_play_audio (uae_u32 startmsf, uae_u32 endmsf, int scan) +{ + if (endmsf == 0xffffffff) + endmsf = last_play_end; + else + last_play_end = endmsf; + return sys_command_play (DF_IOCTL, unitnum,startmsf, endmsf, scan); +} + + +/* read qcode */ +static uae_u32 last_play_pos; +static int cd_qcode (uae_u8 *d) +{ + uae_u8 *buf, *s, as; + + if (d) + memset (d, 0, 11); + last_play_pos = 0; + buf = sys_command_qcode (DF_IOCTL, unitnum); + if (!buf) + return 0; + as = buf[1]; + if (as != 0x11 && as != 0x12 && as != 0x13 && as != 0x15) /* audio status ok? */ + return 0; + s = buf + 4; + last_play_pos = (s[9] << 16) | (s[10] << 8) | (s[11] << 0); + if (!d) + return 0; + /* ??? */ + d[0] = 0; + /* CtlAdr */ + d[1] = (s[1] >> 4) | (s[1] << 4); + /* Track */ + d[2] = tobcd (s[2]); + /* Index */ + d[3] = tobcd (s[3]); + /* TrackPos */ + d[4] = tobcd (s[9]); + d[5] = tobcd (s[10]); + d[6] = tobcd (s[11]); + /* DiskPos */ + d[7] = 0; + d[8] = tobcd (s[5]); + d[9] = tobcd (s[6]); + d[10] = tobcd (s[7]); + if (as == 0x15) { + /* Make sure end of disc position is passed. + */ + int lsn = msf2lsn ((s[5] << 16) | (s[6] << 8) | (s[7] << 0)); + int msf = lsn2msf (cdrom_leadout); + if (lsn >= cdrom_leadout || cdrom_leadout - lsn < 10) { + d[8] = tobcd ((uae_u8)(msf >> 16)); + d[9] = tobcd ((uae_u8)(msf >> 8)); + d[10] = tobcd ((uae_u8)(msf >> 0)); + } + } + + return 0; +} + +/* read toc */ +static int cdrom_toc (void) +{ + int i, j; + int datatrack = 0, secondtrack = 0; + uae_u8 *s, *d, *buf; + + cdrom_toc_counter = -1; + cdrom_toc_entries = 0; + buf = sys_command_toc (DF_IOCTL, unitnum); + if (!buf) + return 1; + i = (buf[0] << 8) | (buf[1] << 0); + i -= 2; + i /= 11; + if (i > MAX_TOC_ENTRIES) + return -1; + memset (cdrom_toc_buffer, 0, MAX_TOC_ENTRIES * 13); + cdrom_data_end = -1; + for (j = 0; j < i; j++) { + s = buf + 4 + j * 11; + d = &cdrom_toc_buffer[j * 13]; + d[1] = (s[1] >> 4) | (s[1] << 4); + d[3] = s[3] < 100 ? tobcd(s[3]) : s[3]; + d[8] = tobcd (s[8]); + d[9] = tobcd (s[9]); + d[10] = tobcd (s[10]); + if (s[3] == 1 && (s[1] & 0x0f) == 0x04) + datatrack = 1; + if (s[3] == 2) + secondtrack = msf2lsn ((s[8] << 16) | (s[9] << 8) | (s[10] << 0)); + if (s[3] == 0xa2) + cdrom_leadout = msf2lsn ((s[8] << 16) | (s[9] << 8) | (s[10] << 0)); + } + if (datatrack) { + if (secondtrack) + cdrom_data_end = secondtrack; + else + cdrom_data_end = cdrom_leadout; + } + cdrom_toc_entries = i; + return 0; +} + +/* open device */ +static int sys_cddev_open (void) +{ + int first = -1; + struct device_info di1, *di2; + int cd32unit = -1; + int audiounit = -1; + + for (unitnum = 0; unitnum < MAX_TOTAL_DEVICES; unitnum++) { + if (sys_command_open (DF_IOCTL, unitnum)) { + di2 = sys_command_info (DF_IOCTL, unitnum, &di1); + if (di2 && di2->type == INQ_ROMD) { + write_log ("%s: ", di2->label); + if (first < 0) + first = unitnum; + if (!cdrom_toc ()) { + if (cdrom_data_end > 0) { + uae_u8 *p = sys_command_read (DF_IOCTL, unitnum, 16); + if (p) { + if (!memcmp (p + 8, "CDTV", 4) || !memcmp (p + 8, "CD32", 4)) { + write_log ("CD32 or CDTV\n"); + if (cd32unit < 0) + cd32unit = unitnum; + } else { + write_log ("non CD32/CDTV data CD\n"); + } + } else { + write_log ("read error\n"); + } + } else { + write_log ("Audio CD\n"); + if (audiounit < 0) + audiounit = unitnum; + } + } else { + write_log ("can't read TOC\n"); + } + } + sys_command_close (DF_IOCTL, unitnum); + } + } + unitnum = audiounit; + if (cd32unit >= 0) + unitnum = cd32unit; + if (unitnum < 0) + unitnum = first; + if (unitnum < 0) + return 1; + if (!sys_command_open (DF_IOCTL, unitnum)) + write_log ("re-opening unit %d failed!\n", unitnum); + di2 = sys_command_info (DF_IOCTL, unitnum, &di1); + if (!di2) { + write_log ("unit %d info failed\n", unitnum); + sys_command_close (DF_IOCTL, unitnum); + return 1; + } + write_log ("using drive %s (unit %d, media %d)\n", di2->label, unitnum, di2->media_inserted); + /* make sure CD audio is not playing */ + cdaudiostop (); + return 0; +} + +/* close device */ +static void sys_cddev_close (void) +{ + cdaudiostop (); + sys_command_close (DF_IOCTL, unitnum); +} + +static int command_lengths[] = { 1,2,1,1,12,2,1,1,4,1,-1,-1,-1,-1,-1 }; + +static void cdrom_return_data (int len) +{ + uae_u32 cmd_buf = cdrom_address2; + int i; + uae_u8 checksum; + + if (len <= 0) return; +#if AKIKO_DEBUG_IO_CMD + write_log ("OUT:"); +#endif + checksum = 0xff; + for (i = 0; i < len; i++) { + checksum -= cdrom_result_buffer[i]; + put_byte (cmd_buf + ((cdrom_result_complete + i) & 0xff), cdrom_result_buffer[i]); +#if AKIKO_DEBUG_IO_CMD + write_log ("%02.2X ", cdrom_result_buffer[i]); +#endif + } + put_byte (cmd_buf + ((cdrom_result_complete + len) & 0xff), checksum); +#if AKIKO_DEBUG_IO_CMD + write_log ("%02.2X\n", checksum); +#endif + cdrom_result_complete += len + 1; + cdrom_status1 |= CDSTATUS_DATA_AVAILABLE; +} + +static int cdrom_command_something (void) +{ + return 0; +} + +static int cdrom_command_media_status (void) +{ + struct device_info di; + + cdrom_result_buffer[0] = 10; + cdrom_result_buffer[1] = sys_command_info (DF_IOCTL, unitnum, &di)->media_inserted ? 1 : 0; + return 2; +} + +/* check if cd drive door is open or closed */ +static int cdrom_command_door_status (void) +{ + struct device_info di; + if (unitnum >= 0 && !sys_command_info (DF_IOCTL, unitnum, &di)->media_inserted) { + cdrom_result_buffer[1] = 0x80; + cdrom_disk = 0; + } else { + cdrom_result_buffer[1] = 1; + cdrom_disk = 1; + } + if (unitnum >= 0) + cdrom_toc (); + cdrom_result_buffer[0] = cdrom_command; + return 20; +} + +/* return one TOC entry */ +static int cdrom_return_toc_entry (void) +{ + cdrom_result_buffer[0] = 6; + if (cdrom_toc_entries == 0) { + cdrom_result_buffer[1] = CDS_ERROR; + return 15; + } + cdrom_result_buffer[1] = 0; + memcpy (cdrom_result_buffer + 2, cdrom_toc_buffer + cdrom_toc_counter * 13, 13); + cdrom_toc_counter++; + if (cdrom_toc_counter >= cdrom_toc_entries) + cdrom_toc_counter = 0; + return 15; +} + +/* pause CD audio */ +static int cdrom_command_pause (void) +{ + cdrom_toc_counter = -1; + cdrom_result_buffer[0] = cdrom_command; + cdrom_result_buffer[1] = cdrom_playing ? CDS_PLAYING : 0; + if (!cdrom_playing) + return 2; + if (cdrom_paused) + return 2; + sys_command_pause (DF_IOCTL, unitnum,1); + cdrom_paused = 1; + return 2; +} + +/* unpause CD audio */ +static int cdrom_command_unpause (void) +{ + cdrom_result_buffer[0] = cdrom_command; + cdrom_result_buffer[1] = cdrom_playing ? CDS_PLAYING : 0; + if (!cdrom_paused) + return 2; + if (!cdrom_playing) + return 2; + cdrom_paused = 0; + sys_command_pause (DF_IOCTL, unitnum,0); + return 2; +} + +/* seek head/play CD audio/read data sectors */ +static int cdrom_command_multi (void) +{ + int seekpos = fromlongbcd (cdrom_command_buffer + 1); + int endpos = fromlongbcd (cdrom_command_buffer + 4); + + if (cdrom_playing) + cdaudiostop (); + cdrom_speed = (cdrom_command_buffer[8] & 0x40) ? 2 : 1; + cdrom_result_buffer[0] = cdrom_command; + cdrom_result_buffer[1] = 0; + if (!cdrom_disk) { + cdrom_result_buffer[1] |= CDS_ERROR; + return 2; + } + + if (cdrom_command_buffer[7] == 0x80) { /* data read */ + int cdrom_data_offset_end = msf2lsn (endpos); + cdrom_data_offset = msf2lsn (seekpos); +#if AKIKO_DEBUG_IO_CMD + write_log ("READ DATA FROM %06.6X (%d) TO %06.6X (%d) SPEED=%dx\n", seekpos, cdrom_data_offset, endpos, cdrom_data_offset_end, cdrom_speed); +#endif + cdrom_result_buffer[1] |= 0x02; + } else if (cdrom_command_buffer[10] & 4) { /* play audio */ + int scan = 0; + if (cdrom_command_buffer[7] & 0x04) + scan = 1; + else if (cdrom_command_buffer[7] & 0x08) + scan = -1; +#if AKIKO_DEBUG_IO_CMD + write_log ("PLAY FROM %06.6X to %06.6X SCAN=%d\n", seekpos, endpos, scan); +#endif + if (!cd_play_audio (seekpos, endpos, 0)) { + cdrom_result_buffer[1] = CDS_ERROR; + } else { + cdrom_playing = 1; + cdrom_result_buffer[1] |= CDS_PLAYING; + } + } else { +#if AKIKO_DEBUG_IO_CMD + write_log ("SEEKTO %06.6X\n",seekpos); +#endif + if (seekpos < 150) + cdrom_toc_counter = 0; + else + cdrom_toc_counter = -1; + } + return 2; +} + +/* return subq entry */ +static int cdrom_command_subq (void) +{ + cdrom_result_buffer[0] = cdrom_command; + cdrom_result_buffer[1] = 0; + if (cd_qcode (cdrom_result_buffer + 2)) + cdrom_result_buffer[1] = CDS_ERROR; + return 15; +} + +static void cdrom_run_command (void) +{ + uae_u32 cmd_buf = cdrom_address2 + 0x200; + int i, cmd_len; + uae_u8 checksum; + + for (;;) { + if (cdrom_command_active) + return; + if (cdrom_command_offset_complete == cdrom_command_offset_todo) + return; + cdrom_command = get_byte (cmd_buf + cdrom_command_offset_complete); + if ((cdrom_command & 0xf0) == 0) + return; + cdrom_checksum_error = 0; + cmd_len = command_lengths[cdrom_command & 0x0f]; + if (cmd_len < 0) { +#if AKIKO_DEBUG_IO_CMD + write_log ("unknown command\n"); +#endif + cmd_len = 1; + } +#if AKIKO_DEBUG_IO_CMD + write_log ("IN:"); +#endif + checksum = 0; + for (i = 0; i < cmd_len + 1; i++) { + cdrom_command_buffer[i] = get_byte (cmd_buf + ((cdrom_command_offset_complete + i) & 0xff)); + checksum += cdrom_command_buffer[i]; +#if AKIKO_DEBUG_IO_CMD + write_log ("%02.2X ", cdrom_command_buffer[i]); +#endif + } + if (checksum!=0xff) { +#if AKIKO_DEBUG_IO_CMD + write_log (" checksum error"); +#endif + cdrom_checksum_error = 1; + } +#if AKIKO_DEBUG_IO_CMD + write_log ("\n"); +#endif + cdrom_command_active = 1; + cdrom_command_length = cmd_len; + return; + } +} + +static void cdrom_run_command_run (void) +{ + int len; + + cdrom_command_offset_complete = (cdrom_command_offset_complete + cdrom_command_length + 1) & 0xff; + memset (cdrom_result_buffer, 0, sizeof(cdrom_result_buffer)); + switch (cdrom_command & 0x0f) + { + case 2: + len = cdrom_command_pause (); + break; + case 3: + len = cdrom_command_unpause (); + break; + case 4: + len = cdrom_command_multi (); + break; + case 5: + cdrom_dosomething = 1; + len = cdrom_command_something (); + break; + case 6: + len = cdrom_command_subq (); + break; + case 7: + len = cdrom_command_door_status (); + break; + default: + len = 0; + break; + } + if (len == 0) + return; + if (cdrom_checksum_error) + cdrom_result_buffer[1] |= 0x80; + cdrom_return_data (len); +} + +extern void encode_l2 (uae_u8 *p, int address); + +/* DMA transfer one CD sector */ +static void cdrom_run_read (void) +{ + int i, j, sector; + int read = 0; + uae_u8 buf[2352]; + int sec; + + if (!(cdrom_longmask & 0x04000000)) + return; + if (!cdrom_readmask_w) + return; + if (cdrom_data_offset<0) + return; + j = cdrom_sector_counter & 15; + if (unitnum >= 0 && cdrom_readmask_w & (1 << j)) { + sector = cdrom_current_sector = cdrom_data_offset + cdrom_sector_counter; + sec = sector - sector_buffer_sector_1; + if (sector_buffer_sector_1 >= 0 && sec >= 0 && sec < SECTOR_BUFFER_SIZE) { + if (sector_buffer_info_1[sec] != 0xff && sector_buffer_info_1[sec] != 0) { + memcpy (buf + 16, sector_buffer_1 + sec * 2048, 2048); + encode_l2 (buf, sector + 150); + buf[0] = 0; + buf[1] = 0; + buf[2] = 0; + buf[3] = cdrom_sector_counter; + for (i = 0; i < 2352; i++) + put_byte (cdrom_address1 + j * 4096 + i, buf[i]); + cdrom_readmask_r |= 1 << j; + } + if (sector_buffer_info_1[sec] != 0xff) + sector_buffer_info_1[sec]--; + } else + return; +#if AKIKO_DEBUG_IO_CMD + write_log("read sector=%d, scnt=%d -> %d\n", cdrom_data_offset, cdrom_sector_counter, sector); +#endif + cdrom_readmask_w &= ~(1 << j); + } + cdrom_sector_counter++; + if (cdrom_readmask_w == 0) + cdrom_status1 |= CDSTATUS_DATASECTOR; +} + +static uae_sem_t akiko_sem; + +static void akiko_handler (void) +{ + static int mediacheckcnt; + static int lastmediastate = -1; + struct device_info di; + + if (unitnum < 0) + return; + if (cdrom_result_complete > cdrom_result_last_pos && cdrom_result_complete - cdrom_result_last_pos < 100) { + cdrom_status1 |= CDSTATUS_DATA_AVAILABLE; + return; + } + if (cdrom_result_last_pos < cdrom_result_complete) + return; + if (mediacheckcnt > 0) + mediacheckcnt--; + if (mediacheckcnt == 0) { + int media = sys_command_info (DF_IOCTL, unitnum, &di)->media_inserted; + mediacheckcnt = 312 * 50 * 2; + if (media != lastmediastate) { + write_log ("media changed = %d\n", media); + lastmediastate = cdrom_disk = media; + cdrom_return_data (cdrom_command_media_status ()); + cdrom_toc (); + /* do not remove! first try may fail */ + cdrom_toc (); + return; + } + } + if (cdrom_toc_counter >= 0 && !cdrom_command_active && cdrom_dosomething) { + cdrom_return_data (cdrom_return_toc_entry ()); + cdrom_dosomething--; + return; + } +} + +static void akiko_internal (void) +{ + cdrom_run_command (); + if (cdrom_command_active > 0) { + cdrom_command_active--; + if (!cdrom_command_active) + cdrom_run_command_run (); + } +} + +extern int cd32_enabled; + +void AKIKO_hsync_handler (void) +{ + static int framecounter; + + if (!cd32_enabled) + return; + framecounter--; + if (framecounter <= 0) { + if (cdrom_playing || cdrom_toc_counter > 0) + gui_cd_led (1); + cdrom_run_read (); + framecounter = 1000000 / (74 * 75 * cdrom_speed); + cdrom_status1 |= CDSTATUS_FRAME; + } + akiko_internal (); + akiko_handler (); +} + + +static volatile int akiko_thread_running; + +/* cdrom data buffering thread */ +static void *akiko_thread (void *null) +{ + int i; + uae_u8 *tmp1; + uae_u8 *tmp2; + int tmp3; + uae_u8 *p; + int offset; + int sector; + + while(akiko_thread_running) { + uae_sem_wait (&akiko_sem); + sector = cdrom_current_sector; + for (i = 0; i < SECTOR_BUFFER_SIZE; i++) { + if (sector_buffer_info_1[i] == 0xff) break; + } + if (cdrom_data_end > 0 && sector >= 0 && (sector_buffer_sector_1 < 0 || sector < sector_buffer_sector_1 || sector >= sector_buffer_sector_1 + SECTOR_BUFFER_SIZE * 2 / 3 || i != SECTOR_BUFFER_SIZE)) { + memset (sector_buffer_info_2, 0, SECTOR_BUFFER_SIZE); +#if AKIKO_DEBUG_IO_CMD + write_log("filling buffer sector=%d (max=%d)\n", sector, cdrom_data_end); +#endif + sector_buffer_sector_2 = sector; + offset = 0; + while (offset < SECTOR_BUFFER_SIZE) { + p = 0; + if (sector < cdrom_data_end) + p = sys_command_read (DF_IOCTL, unitnum, sector); + if (p) + memcpy (sector_buffer_2 + offset * 2048, p, 2048); + sector_buffer_info_2[offset] = p ? 3 : 0; + offset++; + sector++; + } + tmp1 = sector_buffer_info_1; + sector_buffer_info_1 = sector_buffer_info_2; + sector_buffer_info_2 = tmp1; + tmp2 = sector_buffer_1; + sector_buffer_1 = sector_buffer_2; + sector_buffer_2 = tmp2; + tmp3 = sector_buffer_sector_1; + sector_buffer_sector_1 = sector_buffer_sector_2; + sector_buffer_sector_2 = tmp3; + } + uae_sem_post (&akiko_sem); + Sleep (10); + } + akiko_thread_running = -1; + return 0; +} + +static uae_u8 akiko_get_long (uae_u32 v, int offset) +{ + return v >> ((3 - offset) * 8); +} +static void akiko_put_long (uae_u32 *p, int offset, int v) +{ + *p &= ~(0xff << ((3 - offset) * 8)); + *p |= v << ((3 - offset) * 8); +} + +uae_u32 akiko_bget2 (uaecptr addr, int msg) +{ + uae_u8 v; + + addr &= 0xffff; + uae_sem_wait (&akiko_sem); + switch (addr) + { + /* "CAFE" = Akiko identification. + * Kickstart ignores Akiko C2P if this ID isn't correct */ + case 0x02: + v = 0xCA; + break; + case 0x03: + v = 0xFE; + break; + + /* CDROM control */ + case 0x04: + case 0x05: + case 0x06: + case 0x07: + v = akiko_get_long (cdrom_status1, addr - 0x04); + break; + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + v = akiko_get_long (cdrom_status2, addr - 0x08); + break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + v = akiko_get_long (cdrom_address1, addr - 0x10); + break; + case 0x14: + case 0x15: + case 0x16: + case 0x17: + v = akiko_get_long (cdrom_address2, addr - 0x14); + break; + case 0x18: + v = cdrom_status3; + break; + case 0x19: + v = cdrom_command_offset_complete; + break; + case 0x1a: + v = cdrom_result_complete; + break; + case 0x1f: + v = cdrom_result_last_pos; + break; + case 0x20: + case 0x21: + v = akiko_get_long (cdrom_readmask_r, addr - 0x20 + 2); + break; + case 0x24: + case 0x25: + case 0x26: + case 0x27: + v = akiko_get_long (cdrom_longmask, addr - 0x24); + break; + + /* NVRAM */ + case 0x30: + case 0x31: + case 0x32: + case 0x33: + v = akiko_nvram_read (addr - 0x30); + break; + + /* C2P */ + case 0x38: + case 0x39: + case 0x3a: + case 0x3b: + v = akiko_c2p_read (addr - 0x38); + break; + + default: + write_log ("akiko_bget: unknown address %08.8X\n", addr); + v = 0; + break; + } + akiko_internal (); + uae_sem_post (&akiko_sem); + if (msg && addr < 0x30 && AKIKO_DEBUG_IO) + write_log ("akiko_bget %08.8X: %08.8X %02.2X\n", m68k_getpc(), addr, v & 0xff); + return v; +} + +uae_u32 akiko_bget (uaecptr addr) +{ + return akiko_bget2 (addr, 1); +} + +uae_u32 akiko_wget (uaecptr addr) +{ + uae_u16 v; + addr &= 0xffff; + v = akiko_bget2 (addr + 1, 0); + v |= akiko_bget2 (addr + 0, 0) << 8; + if (addr < 0x30 && AKIKO_DEBUG_IO) + write_log ("akiko_wget %08.8X: %08.8X %04.4X\n", m68k_getpc(), addr, v & 0xffff); + return v; +} + +uae_u32 akiko_lget (uaecptr addr) +{ + uae_u32 v; + + addr &= 0xffff; + v = akiko_bget2 (addr + 3, 0); + v |= akiko_bget2 (addr + 2, 0) << 8; + v |= akiko_bget2 (addr + 1, 0) << 16; + v |= akiko_bget2 (addr + 0, 0) << 24; + if (addr < 0x30 && (addr != 4 && addr != 8) && AKIKO_DEBUG_IO) + write_log ("akiko_lget %08.8X: %08.8X %08.8X\n", m68k_getpc(), addr, v); + return v; +} + +void akiko_bput2 (uaecptr addr, uae_u32 v, int msg) +{ + uae_u32 tmp; + + addr &= 0xffff; + v &= 0xff; + if(msg && addr < 0x30 && AKIKO_DEBUG_IO) + write_log ("akiko_bput %08.8X: %08.8X=%02.2X\n", m68k_getpc(), addr, v & 0xff); + uae_sem_wait (&akiko_sem); + switch (addr) + { + case 0x04: + case 0x05: + case 0x06: + case 0x07: + akiko_put_long (&cdrom_status1, addr - 0x04, v); + break; + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + akiko_put_long (&cdrom_status2, addr - 0x08, v); + if (addr == 8) + cdrom_status1 &= cdrom_status2; + break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + akiko_put_long (&cdrom_address1, addr - 0x10, v); + break; + case 0x14: + case 0x15: + case 0x16: + case 0x17: + akiko_put_long (&cdrom_address2, addr - 0x14, v); + break; + case 0x18: + cdrom_status3 = v; + break; + case 0x19: + cdrom_command_offset_complete = v; + break; + case 0x1a: + cdrom_result_complete = v; + break; + case 0x1d: + cdrom_command_offset_todo = v; + break; + case 0x1f: + cdrom_result_last_pos = v; + break; + case 0x20: + cdrom_readmask_w |= (v << 8); + cdrom_readmask_r &= 0x00ff; + break; + case 0x21: + cdrom_readmask_w |= (v << 0); + cdrom_readmask_r &= 0xff00; + break; + case 0x24: + case 0x25: + case 0x26: + case 0x27: + tmp = cdrom_longmask; + akiko_put_long (&cdrom_longmask, addr - 0x24, v); + if ((cdrom_longmask & 0x04000000) && !(tmp & 0x04000000)) + cdrom_sector_counter = 0; + break; + + case 0x30: + case 0x31: + case 0x32: + case 0x33: + akiko_nvram_write (addr - 0x30, v); + break; + + case 0x38: + case 0x39: + case 0x3a: + case 0x3b: + akiko_c2p_write (addr - 0x38, v); + break; + + default: + write_log ("akiko_bput: unknown address %08.8X\n", addr); + break; + } + akiko_internal (); + uae_sem_post (&akiko_sem); +} + +void akiko_bput (uaecptr addr, uae_u32 v) +{ + akiko_bput2 (addr, v, 1); +} + +void akiko_wput (uaecptr addr, uae_u32 v) +{ + addr &= 0xfff; + if((addr < 0x30 && AKIKO_DEBUG_IO)) + write_log("akiko_wput %08.8X: %08.8X=%04.4X\n", m68k_getpc(), addr, v & 0xffff); + akiko_bput2 (addr + 1, v & 0xff, 0); + akiko_bput2 (addr + 0, v >> 8, 0); +} + +void akiko_lput (uaecptr addr, uae_u32 v) +{ + addr &= 0xffff; + if(addr < 0x30 && AKIKO_DEBUG_IO) + write_log("akiko_lput %08.8X: %08.8X=%08.8X\n", m68k_getpc(), addr, v); + akiko_bput2 (addr + 3, (v >> 0) & 0xff, 0); + akiko_bput2 (addr + 2, (v >> 8) & 0xff, 0); + akiko_bput2 (addr + 1, (v >> 16) & 0xff, 0); + akiko_bput2 (addr + 0, (v >> 24) & 0xff, 0); +} + +static uae_thread_id akiko_tid; + +void akiko_reset (void) +{ + cdaudiostop (); + nvram_read (); + state = I2C_WAIT; + bitcounter = -1; + direction = -1; + + cdrom_speed = 1; + cdrom_current_sector = -1; + + if (akiko_thread_running > 0) { + akiko_thread_running = 0; + while(akiko_thread_running == 0) + Sleep (10); + akiko_thread_running = 0; + } +} + +extern uae_u32 extendedkickmemory; + +static uae_u8 patchdata[]={0x0c,0x82,0x00,0x00,0x03,0xe8,0x64,0x00,0x00,0x46}; + +static void patchrom (void) +{ + int i; + uae_u8 *p = (uae_u8*)extendedkickmemory; + for (i = 0; i < 524288 - sizeof (patchdata); i++) { + if (!memcmp (p + i, patchdata, sizeof(patchdata))) { + p[i + 6] = 0x4e; + p[i + 7] = 0x71; + p[i + 8] = 0x4e; + p[i + 9] = 0x71; + write_log ("extended rom delay loop patched at 0x%p\n", i + 6 + 0xe00000); + return; + } + } + write_log ("couldn't patch extended rom\n"); +} + +static int cdromok = 0; + +void akiko_free (void) +{ + akiko_reset (); + if (unitnum >= 0) + sys_cddev_close (); + unitnum = -1; + free (sector_buffer_1); + free (sector_buffer_2); + free (sector_buffer_info_1); + free (sector_buffer_info_2); + sector_buffer_1 = 0; + sector_buffer_2 = 0; + sector_buffer_info_1 = 0; + sector_buffer_info_2 = 0; + cdromok = 0; +} + +int akiko_init (void) +{ + if (cdromok == 0) { + unitnum = -1; + if (!device_func_init(DEVICE_TYPE_ANY)) { + write_log ("no CDROM support\n"); + return 0; + } + if (!sys_cddev_open ()) { + cdromok = 1; + sector_buffer_1 = malloc (SECTOR_BUFFER_SIZE * 2048); + sector_buffer_2 = malloc (SECTOR_BUFFER_SIZE * 2048); + sector_buffer_info_1 = malloc (SECTOR_BUFFER_SIZE); + sector_buffer_info_2 = malloc (SECTOR_BUFFER_SIZE); + sector_buffer_sector_1 = -1; + sector_buffer_sector_2 = -1; + patchrom (); + } + } + if (!savestate_state) { + cdrom_playing = cdrom_paused = 0; + cdrom_data_offset = -1; + uae_sem_init (&akiko_sem, 0, 1); + } + if (cdromok && !akiko_thread_running) { + akiko_thread_running = 1; + uae_start_thread (akiko_thread, 0, &akiko_tid); + } + return 1; +} + +uae_u8 *save_akiko(int *len) +{ + uae_u8 *dstbak, *dst; + int i; + + dstbak = dst = malloc (1000); + save_u16 (0); + save_u16 (0xCAFE); + save_u32 (cdrom_status1); + save_u32 (cdrom_status2); + save_u32 (0); + save_u32 (cdrom_address1); + save_u32 (cdrom_address2); + save_u8 (cdrom_status3); + save_u8 (cdrom_command_offset_complete); + save_u8 (cdrom_result_complete); + save_u8 (0); + save_u8 (0); + save_u8 (cdrom_command_offset_todo); + save_u8 (0); + save_u8 (cdrom_result_last_pos); + save_u16 ((uae_u16)cdrom_readmask_w); + save_u16 (0); + save_u32 (cdrom_longmask); + save_u32 (0); + save_u32 (0); + save_u32 ((scl_dir ? 0x8000 : 0) | (sda_dir ? 0x4000 : 0)); + save_u32 (0); + save_u32 (0); + + for (i = 0; i < 8; i++) + save_u32 (akiko_buffer[i]); + save_u8 ((uae_u8)akiko_read_offset); + save_u8 ((uae_u8)akiko_write_offset); + + save_u32 ((cdrom_playing ? 1 : 0) | (cdrom_paused ? 2 : 0)); + if (cdrom_playing) + cd_qcode (0); + save_u32 (last_play_pos); + save_u32 (last_play_end); + save_u8 ((uae_u8)cdrom_toc_counter); + + *len = dst - dstbak; + return dstbak; +} + +uae_u8 *restore_akiko(uae_u8 *src) +{ + uae_u32 v; + int i; + + restore_u16 (); + restore_u16 (); + cdrom_status1 = restore_u32 (); + cdrom_status2 = restore_u32 (); + restore_u32(); + cdrom_address1 = restore_u32 (); + cdrom_address2 = restore_u32 (); + cdrom_status3 = restore_u8 (); + cdrom_command_offset_complete = restore_u8 (); + cdrom_result_complete = restore_u8 (); + restore_u8 (); + restore_u8 (); + cdrom_command_offset_todo = restore_u8 (); + restore_u8 (); + cdrom_result_last_pos = restore_u8 (); + cdrom_readmask_w = restore_u16 (); + restore_u16 (); + cdrom_longmask = restore_u32 (); + restore_u32(); + restore_u32(); + v = restore_u32(); + scl_dir = (v & 0x8000) ? 1 : 0; + sda_dir = (v & 0x4000) ? 1 : 0; + restore_u32(); + restore_u32(); + + for (i = 0; i < 8; i++) + akiko_buffer[i] = restore_u32 (); + akiko_read_offset = restore_u8 (); + akiko_write_offset = restore_u8 (); + akiko_c2p_do (); + + cdrom_playing = cdrom_paused = 0; + v = restore_u32 (); + if (v & 1) + cdrom_playing = 1; + if (v & 2) + cdrom_paused = 1; + last_play_pos = restore_u32 (); + last_play_end = restore_u32 (); + cdrom_toc_counter = restore_u8 (); + if (cdrom_toc_counter == 255) + cdrom_toc_counter = -1; + if (cdrom_playing) + sys_command_play (DF_IOCTL, unitnum, last_play_pos, last_play_end, 0); + + return src; +} +void akiko_entergui (void) +{ + if (cdrom_playing) + sys_command_pause (DF_IOCTL, unitnum, 1); +} +void akiko_exitgui (void) +{ + if (cdrom_playing) + sys_command_pause (DF_IOCTL, unitnum, 0); +} + diff --git a/akiko2.c b/akiko2.c new file mode 100755 index 00000000..8891692a --- /dev/null +++ b/akiko2.c @@ -0,0 +1,1393 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * CD32 Akiko emulation + * + * - C2P + * - NVRAM + * - CDROM + * + * Copyright 2001, 2002 Toni Wilen + * + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "memory.h" +#include "events.h" +#include "savestate.h" +#include "blkdev.h" +#include "zfile.h" +#include "threaddep/thread.h" +#include "akiko.h" + +#define AKIKO_DEBUG_NVRAM 0 +#define AKIKO_DEBUG_IO 1 +#define AKIKO_DEBUG_IO_CMD 1 + +int cd32_enabled; + +static int m68k_getpc(void) { return 0; } + +/* + * CD32 1Kb NVRAM (EEPROM) emulation + * + * NVRAM chip is 24C08 CMOS EEPROM (1024x8 bits = 1Kb) + * Chip interface is I2C (2 wire serial) + * Akiko addresses used: + * 0xb80030: bit 7 = SCL (clock), 6 = SDA (data) + * 0xb80032: 0xb80030 data direction register (0 = input, 1 = output) + * + * Because I don't have any experience on I2C, following code may be + * unnecessarily complex and not 100% correct.. + */ + +enum i2c { I2C_WAIT, I2C_START, I2C_DEVICEADDR, I2C_WORDADDR, I2C_DATA }; + +/* size of EEPROM, don't try to change, + * (hardcoded in Kickstart) + */ +#define NVRAM_SIZE 1024 +/* max size of one write request */ +#define NVRAM_PAGE_SIZE 16 + +static uae_u8 cd32_nvram[NVRAM_SIZE], nvram_writetmp[NVRAM_PAGE_SIZE]; +static int nvram_address, nvram_writeaddr; +static int nvram_rw; +static int bitcounter = -1, direction = -1; +static uae_u8 nvram_byte; +static int scl_out, scl_in, scl_dir, oscl, sda_out, sda_in, sda_dir, osda; +static int sda_dir_nvram; +static int state = I2C_WAIT; + +static void nvram_write (int offset, int len) +{ + struct zfile *f = zfile_fopen (currprefs.flashfile, "rb+"); + if (!f) { + f = zfile_fopen (currprefs.flashfile, "wb"); + if (!f) return; + zfile_fwrite (cd32_nvram, NVRAM_SIZE, 1, f); + zfile_fclose (f); + } + zfile_fseek (f, offset, SEEK_SET); + zfile_fwrite (cd32_nvram + offset, len, 1, f); + zfile_fclose (f); +} + +static void nvram_read (void) +{ + struct zfile *f; + + f = zfile_fopen (currprefs.flashfile, "rb"); + memset (cd32_nvram, 0, NVRAM_SIZE); + if (!f) return; + zfile_fread (cd32_nvram, NVRAM_SIZE, 1, f); + zfile_fclose (f); +} + +static void i2c_do (void) +{ +#if AKIKO_DEBUG_NVRAM + int i; +#endif + sda_in = 1; + if (!sda_dir_nvram && scl_out && oscl) { + if (!sda_out && osda) { /* START-condition? */ + state = I2C_DEVICEADDR; + bitcounter = 0; + direction = -1; +#if AKIKO_DEBUG_NVRAM + write_log ("START\n"); +#endif + return; + } else if(sda_out && !osda) { /* STOP-condition? */ + state = I2C_WAIT; + bitcounter = -1; +#if AKIKO_DEBUG_NVRAM + write_log ("STOP\n"); +#endif + if (direction > 0) { + memcpy (cd32_nvram + (nvram_address & ~(NVRAM_PAGE_SIZE - 1)), nvram_writetmp, NVRAM_PAGE_SIZE); + nvram_write (nvram_address & ~(NVRAM_PAGE_SIZE - 1), NVRAM_PAGE_SIZE); + direction = -1; +#if AKIKO_DEBUG_NVRAM + write_log ("NVRAM write address %04.4X:", nvram_address & ~(NVRAM_PAGE_SIZE - 1)); + for (i = 0; i < NVRAM_PAGE_SIZE; i++) + write_log ("%02.2X", nvram_writetmp[i]); + write_log ("\n"); + +#endif + } + return; + } + } + if (bitcounter >= 0) { + if (direction) { + /* Amiga -> NVRAM */ + if (scl_out && !oscl) { + if (bitcounter == 8) { +#if AKIKO_DEBUG_NVRAM + write_log ("RB %02.2X ", nvram_byte, m68k_getpc()); +#endif + sda_in = 0; /* ACK */ + if (direction > 0) { + nvram_writetmp[nvram_writeaddr++] = nvram_byte; + nvram_writeaddr &= 15; + bitcounter = 0; + } else { + bitcounter = -1; + } + } else { + //write_log("NVRAM received bit %d, offset %d\n", sda_out, bitcounter); + nvram_byte <<= 1; + nvram_byte |= sda_out; + bitcounter++; + } + } + } else { + /* NVRAM -> Amiga */ + if (scl_out && !oscl && bitcounter < 8) { + if (bitcounter == 0) + nvram_byte = cd32_nvram[nvram_address]; + sda_dir_nvram = 1; + sda_in = (nvram_byte & 0x80) ? 1 : 0; + //write_log("NVRAM sent bit %d, offset %d\n", sda_in, bitcounter); + nvram_byte <<= 1; + bitcounter++; + if (bitcounter == 8) { +#if AKIKO_DEBUG_NVRAM + write_log ("NVRAM sent byte %02.2X address %04.4X PC=%08.8X\n", cd32_nvram[nvram_address], nvram_address, m68k_getpc()); +#endif + nvram_address++; + nvram_address &= NVRAM_SIZE - 1; + sda_dir_nvram = 0; + } + } + if(!sda_out && sda_dir && !scl_out) /* ACK from Amiga */ + bitcounter = 0; + } + if (bitcounter >= 0) return; + } + switch (state) + { + case I2C_DEVICEADDR: + if ((nvram_byte & 0xf0) != 0xa0) { + write_log ("WARNING: I2C_DEVICEADDR: device address != 0xA0\n"); + state = I2C_WAIT; + return; + } + nvram_rw = (nvram_byte & 1) ? 0 : 1; + if (nvram_rw) { + /* 2 high address bits, only fetched if WRITE = 1 */ + nvram_address &= 0xff; + nvram_address |= ((nvram_byte >> 1) & 3) << 8; + state = I2C_WORDADDR; + direction = -1; + } else { + state = I2C_DATA; + direction = 0; + sda_dir_nvram = 1; + } + bitcounter = 0; +#if AKIKO_DEBUG_NVRAM + write_log ("I2C_DEVICEADDR: rw %d, address %02.2Xxx PC=%08.8X\n", nvram_rw, nvram_address >> 8, m68k_getpc()); +#endif + break; + case I2C_WORDADDR: + nvram_address &= 0x300; + nvram_address |= nvram_byte; +#if AKIKO_DEBUG_NVRAM + write_log ("I2C_WORDADDR: address %04.4X PC=%08.8X\n", nvram_address, m68k_getpc()); +#endif + if (direction < 0) { + memcpy (nvram_writetmp, cd32_nvram + (nvram_address & ~(NVRAM_PAGE_SIZE - 1)), NVRAM_PAGE_SIZE); + nvram_writeaddr = nvram_address & (NVRAM_PAGE_SIZE - 1); + } + state = I2C_DATA; + bitcounter = 0; + direction = 1; + break; + } +} + +static void akiko_nvram_write (int offset, uae_u32 v) +{ + int sda; + switch (offset) + { + case 0: + oscl = scl_out; + scl_out = (v & 0x80) ? 1 : 0; + osda = sda_out; + sda_out = (v & 0x40) ? 1 : 0; + break; + case 2: + scl_dir = (v & 0x80) ? 1 : 0; + sda_dir = (v & 0x40) ? 1 : 0; + break; + default: + return; + } + sda = sda_out; + if (oscl != scl_out || osda != sda) { + i2c_do (); + oscl = scl_out; + osda = sda; + } +} + +static uae_u32 akiko_nvram_read (int offset) +{ + uae_u32 v = 0; + switch (offset) + { + case 0: + if (!scl_dir) + v |= scl_in ? 0x80 : 0x00; + else + v |= scl_out ? 0x80 : 0x00; + if (!sda_dir) + v |= sda_in ? 0x40 : 0x00; + else + v |= sda_out ? 0x40 : 0x00; + break; + case 2: + v |= scl_dir ? 0x80 : 0x00; + v |= sda_dir ? 0x40 : 0x00; + break; + } + return v; +} + +/* CD32 Chunky to Planar hardware emulation + * Akiko addresses used: + * 0xb80038-0xb8003b + */ + +static uae_u32 akiko_buffer[8]; +static int akiko_read_offset, akiko_write_offset; +static uae_u32 akiko_result[8]; + +static void akiko_c2p_do (void) +{ + int i; + + for (i = 0; i < 8; i++) akiko_result[i] = 0; + /* FIXME: better c2p algoritm than this piece of crap.... */ + for (i = 0; i < 8 * 32; i++) { + if (akiko_buffer[7 - (i >> 5)] & (1 << (i & 31))) + akiko_result[i & 7] |= 1 << (i >> 3); + } +} + +static void akiko_c2p_write (int offset, uae_u32 v) +{ + if (offset == 3) akiko_buffer[akiko_write_offset] = 0; + akiko_buffer[akiko_write_offset] |= v << ( 8 * (3 - offset)); + if (offset == 0) { + akiko_write_offset++; + akiko_write_offset &= 7; + } + akiko_read_offset = 0; +} + +static uae_u32 akiko_c2p_read (int offset) +{ + uae_u32 v; + + if (akiko_read_offset == 0 && offset == 3) + akiko_c2p_do (); + akiko_write_offset = 0; + v = akiko_result[akiko_read_offset]; + if (offset == 0) { + akiko_read_offset++; + akiko_read_offset &= 7; + } + return v >> (8 * (3 - offset)); +} + +/* CD32 CDROM hardware emulation + * Akiko addresses used: + * 0xb80004-0xb80028 + * + * I can't believe cd.device and custom loaders are fooled to think + * this piece of crap emulates real CD32 CDROM controller and drive :) + */ + +#define CDSTATUS_FRAME 0x80000000 +#define CDSTATUS_DATA_AVAILABLE 0x10000000 +#define CDSTATUS_DATASECTOR_ERROR 0x08000000 /* ?? */ +#define CDSTATUS_DATASECTOR 0x04000000 + +#define CDS_ERROR 0x80 +#define CDS_PLAYING 0x08 + +static uae_u32 cdrom_status1, cdrom_status2; +static uae_u8 cdrom_status3; +static uae_u32 cdrom_address1, cdrom_address2; +static uae_u32 cdrom_longmask; +static uae_u32 cdrom_readmask_r, cdrom_readmask_w; +static uae_u8 cdrom_command_offset_complete; /* 0x19 */ +static uae_u8 cdrom_command_offset_todo; /* 0x1d */ +static uae_u8 cdrom_result_complete; /* 0x1a */ +static uae_u8 cdrom_result_last_pos; /* 0x1f */ +static uae_u8 cdrom_result_buffer[32]; +static uae_u8 cdrom_command_buffer[32]; +static uae_u8 cdrom_command; + +#define MAX_TOC_ENTRIES 103 /* tracks 1-99, A0,A1 and A2 */ +static int cdrom_toc_entries; +static int cdrom_toc_counter; +static uae_u8 cdrom_toc_buffer[MAX_TOC_ENTRIES*13]; + +static int cdrom_disk, cdrom_paused, cdrom_playing; +static int cdrom_command_active; +static int cdrom_command_length; +static int cdrom_checksum_error; +static int cdrom_data_offset, cdrom_speed, cdrom_sector_counter; +static int cdrom_current_sector; +static int cdrom_data_end, cdrom_leadout; +static int cdrom_dosomething; + +static uae_u8 *sector_buffer_1, *sector_buffer_2; +static int sector_buffer_sector_1, sector_buffer_sector_2; +#define SECTOR_BUFFER_SIZE 64 +static uae_u8 *sector_buffer_info_1, *sector_buffer_info_2; + +static int unitnum = -1; + +static uae_u8 frombcd (uae_u8 v) +{ + return (v >> 4) * 10 + (v & 15); +} + +static uae_u8 tobcd (uae_u8 v) +{ + return ((v / 10) << 4) | (v % 10); +} + +static int fromlongbcd (uae_u8 *p) +{ + return (frombcd (p[0]) << 16) | (frombcd (p[1]) << 8) | (frombcd (p[2]) << 0); +} + +/* convert minutes, seconds and frames -> logical sector number */ +static int msf2lsn (int msf) +{ + int sector = (((msf >> 16) & 0xff) * 60 * 75 + ((msf >> 8) & 0xff) * 75 + ((msf >> 0) & 0xff)) - 150; + if (sector < 0) + sector = 0; + return sector; +} + +/* convert logical sector number -> minutes, seconds and frames */ +static int lsn2msf (int sectors) +{ + int msf; + sectors += 150; + msf = (sectors / (75 * 60)) << 16; + msf |= ((sectors / 75) % 60) << 8; + msf |= (sectors % 75) << 0; + return msf; +} + +static uae_u32 last_play_end; +static int cd_play_audio (uae_u32 startmsf, uae_u32 endmsf, int scan) +{ + if (endmsf == 0xffffffff) + endmsf = last_play_end; + else + last_play_end = endmsf; + return sys_command_play (DF_IOCTL, unitnum,startmsf, endmsf, scan); +} + + +/* read qcode */ +static uae_u32 last_play_pos; +static int cd_qcode (uae_u8 *d) +{ + uae_u8 *buf, *s, as; + + if (d) + memset (d, 0, 11); + last_play_pos = 0; + buf = sys_command_qcode (DF_IOCTL, unitnum); + if (!buf) + return 0; + as = buf[1]; + if (as != 0x11 && as != 0x12 && as != 0x13 && as != 0x15) /* audio status ok? */ + return 0; + s = buf + 4; + last_play_pos = (s[9] << 16) | (s[10] << 8) | (s[11] << 0); + if (!d) + return 0; + /* ??? */ + d[0] = 0; + /* CtlAdr */ + d[1] = (s[1] >> 4) | (s[1] << 4); + /* Track */ + d[2] = tobcd (s[2]); + /* Index */ + d[3] = tobcd (s[3]); + /* TrackPos */ + d[4] = tobcd (s[9]); + d[5] = tobcd (s[10]); + d[6] = tobcd (s[11]); + /* DiskPos */ + d[7] = 0; + d[8] = tobcd (s[5]); + d[9] = tobcd (s[6]); + d[10] = tobcd (s[7]); + if (as == 0x15) { + /* Make sure end of disc position is passed. + */ + int lsn = msf2lsn ((s[5] << 16) | (s[6] << 8) | (s[7] << 0)); + int msf = lsn2msf (cdrom_leadout); + if (lsn >= cdrom_leadout || cdrom_leadout - lsn < 10) { + d[8] = tobcd ((uae_u8)(msf >> 16)); + d[9] = tobcd ((uae_u8)(msf >> 8)); + d[10] = tobcd ((uae_u8)(msf >> 0)); + } + } + + return 0; +} + +/* read toc */ +static int cdrom_toc (void) +{ + int i, j; + int datatrack = 0, secondtrack = 0; + uae_u8 *s, *d, *buf; + + cdrom_toc_counter = -1; + cdrom_toc_entries = 0; + buf = sys_command_toc (DF_IOCTL, unitnum); + if (!buf) + return 1; + i = (buf[0] << 8) | (buf[1] << 0); + i -= 2; + i /= 11; + if (i > MAX_TOC_ENTRIES) + return -1; + memset (cdrom_toc_buffer, 0, MAX_TOC_ENTRIES * 13); + cdrom_data_end = -1; + for (j = 0; j < i; j++) { + s = buf + 4 + j * 11; + d = &cdrom_toc_buffer[j * 13]; + d[1] = (s[1] >> 4) | (s[1] << 4); + d[3] = s[3] < 100 ? tobcd(s[3]) : s[3]; + d[8] = tobcd (s[8]); + d[9] = tobcd (s[9]); + d[10] = tobcd (s[10]); + if (s[3] == 1 && (s[1] & 0x0f) == 0x04) + datatrack = 1; + if (s[3] == 2) + secondtrack = msf2lsn ((s[8] << 16) | (s[9] << 8) | (s[10] << 0)); + if (s[3] == 0xa2) + cdrom_leadout = msf2lsn ((s[8] << 16) | (s[9] << 8) | (s[10] << 0)); + } + if (datatrack) { + if (secondtrack) + cdrom_data_end = secondtrack; + else + cdrom_data_end = cdrom_leadout; + } + cdrom_toc_entries = i; + return 0; +} + +/* open device */ +static int sys_cddev_open (void) +{ + int first = -1; + int found = 0; + struct device_info di1, *di2; + + for (unitnum = 0; unitnum < MAX_TOTAL_DEVICES; unitnum++) { + di2 = sys_command_info (DF_IOCTL, unitnum, &di1); + if (di2 && di2->type == INQ_ROMD) { + if (sys_command_open (DF_IOCTL, unitnum)) { + if (first < 0) + first = unitnum; + if (!cdrom_toc ()) { + found = 1; + break; + } + sys_command_close (DF_IOCTL, unitnum); + } + } + } + if (!found) { + if (first >= 0) { + unitnum = first; + sys_command_open (DF_IOCTL, unitnum); + } else { + unitnum = -1; + return 1; + } + } + /* make sure CD audio is not playing */ + sys_command_pause (DF_IOCTL, unitnum, 0); + sys_command_stop (DF_IOCTL, unitnum); + sys_command_pause (DF_IOCTL, unitnum, 1); + return 0; +} + +/* close device */ +static void sys_cddev_close (void) +{ + sys_command_pause (DF_IOCTL, unitnum, 0); + sys_command_stop (DF_IOCTL, unitnum); + sys_command_pause (DF_IOCTL, unitnum, 1); + sys_command_close (DF_IOCTL, unitnum); +} + +static int command_lengths[] = { 1,2,1,1,12,2,1,1,4,1,-1,-1,-1,-1,-1 }; + +static void cdrom_return_data (int len) +{ + uae_u32 cmd_buf = cdrom_address2; + int i; + uae_u8 checksum; + + if (len <= 0) return; +#if AKIKO_DEBUG_IO_CMD + write_log ("OUT:"); +#endif + checksum = 0xff; + for (i = 0; i < len; i++) { + checksum -= cdrom_result_buffer[i]; + put_byte (cmd_buf + ((cdrom_result_complete + i) & 0xff), cdrom_result_buffer[i]); +#if AKIKO_DEBUG_IO_CMD + write_log ("%02.2X ", cdrom_result_buffer[i]); +#endif + } + put_byte (cmd_buf + ((cdrom_result_complete + len) & 0xff), checksum); +#if AKIKO_DEBUG_IO_CMD + write_log ("%02.2X\n", checksum); +#endif + cdrom_result_complete += len + 1; + cdrom_status1 |= CDSTATUS_DATA_AVAILABLE; +} + +static int cdrom_command_something (void) +{ + return 0; +} + +static int cdrom_command_media_status (void) +{ + struct device_info di; + + cdrom_result_buffer[0] = cdrom_command; + cdrom_result_buffer[1] = sys_command_info (DF_IOCTL, unitnum, &di)->media_inserted ? 1 : 0; + return 2; +} + +/* check if cd drive door is open or closed */ +static int cdrom_command_door_status (void) +{ + struct device_info di; + if (!sys_command_info (DF_IOCTL, unitnum, &di)->media_inserted) { + cdrom_result_buffer[1] = 0x80; + cdrom_disk = 0; + } else { + cdrom_result_buffer[1] = 1; + cdrom_disk = 1; + } + cdrom_toc (); + cdrom_result_buffer[0] = cdrom_command; + return 20; +} + +/* return one TOC entry */ +static int cdrom_return_toc_entry (void) +{ + cdrom_result_buffer[0] = 6; + if (cdrom_toc_entries == 0) { + cdrom_result_buffer[1] = CDS_ERROR; + return 15; + } + cdrom_result_buffer[1] = 0; + memcpy (cdrom_result_buffer + 2, cdrom_toc_buffer + cdrom_toc_counter * 13, 13); + cdrom_toc_counter++; + if (cdrom_toc_counter >= cdrom_toc_entries) + cdrom_toc_counter = 0; + return 15; +} + +/* pause CD audio */ +static int cdrom_command_pause (void) +{ + cdrom_toc_counter = -1; + cdrom_result_buffer[0] = cdrom_command; + cdrom_result_buffer[1] = cdrom_playing ? CDS_PLAYING : 0; + if (!cdrom_playing) + return 2; + if (cdrom_paused) + return 2; + sys_command_pause (DF_IOCTL, unitnum, 1); + cdrom_paused = 1; + return 2; +} + +/* unpause CD audio */ +static int cdrom_command_unpause (void) +{ + cdrom_result_buffer[0] = cdrom_command; + cdrom_result_buffer[1] = cdrom_playing ? CDS_PLAYING : 0; + if (!cdrom_paused) + return 2; + if (!cdrom_playing) + return 2; + cdrom_paused = 0; + sys_command_pause (DF_IOCTL, unitnum, 0); + return 2; +} + +/* seek head/play CD audio/read data sectors */ +static int cdrom_command_multi (void) +{ + int seekpos = fromlongbcd (cdrom_command_buffer + 1); + int endpos = fromlongbcd (cdrom_command_buffer + 4); + + cdrom_playing = 0; + cdrom_speed = (cdrom_command_buffer[8] & 0x40) ? 2 : 1; + cdrom_result_buffer[0] = cdrom_command; + cdrom_result_buffer[1] = 0; + if (!cdrom_disk) { + cdrom_result_buffer[1] |= CDS_ERROR; + return 2; + } + + if (cdrom_command_buffer[7] == 0x80) { /* data read */ + int cdrom_data_offset_end = msf2lsn (endpos); + cdrom_data_offset = msf2lsn (seekpos); +#if AKIKO_DEBUG_IO_CMD + write_log ("READ DATA FROM %06.6X (%d) TO %06.6X (%d) SPEED=%dx\n", seekpos, cdrom_data_offset, endpos, cdrom_data_offset_end, cdrom_speed); +#endif + cdrom_result_buffer[1] |= 0x02; + } else if (cdrom_command_buffer[10] & 4) { /* play audio */ + int scan = 0; + if (cdrom_command_buffer[7] & 0x04) + scan = 1; + else if (cdrom_command_buffer[7] & 0x08) + scan = -1; +#if AKIKO_DEBUG_IO_CMD + write_log ("PLAY FROM %06.6X to %06.6X SCAN=%d\n", seekpos, endpos, scan); +#endif + if (!cd_play_audio (seekpos, endpos, 0)) { + cdrom_result_buffer[1] = CDS_ERROR; + } else { + cdrom_playing = 1; + cdrom_result_buffer[1] |= CDS_PLAYING; + } + } else { +#if AKIKO_DEBUG_IO_CMD + write_log ("SEEKTO %06.6X\n",seekpos); +#endif + if (seekpos < 150) + cdrom_toc_counter = 0; + else + cdrom_toc_counter = -1; + } + return 2; +} + +/* return subq entry */ +static int cdrom_command_subq (void) +{ + cdrom_result_buffer[0] = cdrom_command; + cdrom_result_buffer[1] = 0; + if (cd_qcode (cdrom_result_buffer + 2)) + cdrom_result_buffer[1] = CDS_ERROR; + return 15; +} + +static void cdrom_run_command (void) +{ + uae_u32 cmd_buf = cdrom_address2 + 0x200; + int i, cmd_len; + uae_u8 checksum; + + for (;;) { + if (cdrom_command_active) + return; + if (cdrom_command_offset_complete == cdrom_command_offset_todo) + return; + cdrom_command = get_byte (cmd_buf + cdrom_command_offset_complete); + if ((cdrom_command & 0xf0) == 0) + return; + cdrom_checksum_error = 0; + cmd_len = command_lengths[cdrom_command & 0x0f]; + if (cmd_len < 0) { +#if AKIKO_DEBUG_IO_CMD + write_log ("unknown command\n"); +#endif + cmd_len = 1; + } +#if AKIKO_DEBUG_IO_CMD + write_log ("IN:"); +#endif + checksum = 0; + for (i = 0; i < cmd_len + 1; i++) { + cdrom_command_buffer[i] = get_byte (cmd_buf + ((cdrom_command_offset_complete + i) & 0xff)); + checksum += cdrom_command_buffer[i]; +#if AKIKO_DEBUG_IO_CMD + write_log ("%02.2X ", cdrom_command_buffer[i]); +#endif + } + if (checksum!=0xff) { +#if AKIKO_DEBUG_IO_CMD + write_log (" checksum error"); +#endif + cdrom_checksum_error = 1; + } +#if AKIKO_DEBUG_IO_CMD + write_log ("\n"); +#endif + cdrom_command_active = 1; + cdrom_command_length = cmd_len; + return; + } +} + +static void cdrom_run_command_run (void) +{ + int len; + + cdrom_command_offset_complete = (cdrom_command_offset_complete + cdrom_command_length + 1) & 0xff; + memset (cdrom_result_buffer, 0, sizeof(cdrom_result_buffer)); + switch (cdrom_command & 0x0f) + { + case 2: + len = cdrom_command_pause (); + break; + case 3: + len = cdrom_command_unpause (); + break; + case 4: + len = cdrom_command_multi (); + break; + case 5: + cdrom_dosomething = 1; + len = cdrom_command_something (); + break; + case 6: + len = cdrom_command_subq (); + break; + case 7: + len = cdrom_command_door_status (); + break; + default: + len = 0; + break; + } + if (len == 0) + return; + if (cdrom_checksum_error) + cdrom_result_buffer[1] |= 0x80; + cdrom_return_data (len); +} + +extern void encode_l2 (uae_u8 *p, int address); + +/* DMA transfer one CD sector */ +static void cdrom_run_read (void) +{ + int i, j, sector; + int read = 0; + uae_u8 buf[2352]; + int sec; + + if (!(cdrom_longmask & 0x04000000)) + return; + if (!cdrom_readmask_w) + return; + if (cdrom_data_offset < 0) + return; + if (unitnum >= 0) { + for (j = 0; j < 16; j++) { + if (cdrom_readmask_w & (1 << j)) break; + } + sector = cdrom_current_sector = cdrom_data_offset + cdrom_sector_counter; + sec = sector - sector_buffer_sector_1; + if (sector_buffer_sector_1 >= 0 && sec >= 0 && sec < SECTOR_BUFFER_SIZE) { + if (sector_buffer_info_1[sec] != 0xff && sector_buffer_info_1[sec] != 0) { + memcpy (buf + 16, sector_buffer_1 + sec * 2048, 2048); + encode_l2 (buf, sector + 150); + buf[0] = 0; + buf[1] = 0; + buf[2] = 0; + buf[3] = cdrom_sector_counter; + for (i = 0; i < 2352; i++) + put_byte (cdrom_address1 + j * 4096 + i, buf[i]); + cdrom_readmask_r |= 1 << j; + } + if (sector_buffer_info_1[sec] != 0xff) + sector_buffer_info_1[sec]--; + } else + return; +#if AKIKO_DEBUG_IO_CMD + write_log("read sector=%d, scnt=%d -> %d\n", cdrom_data_offset, cdrom_sector_counter, sector); +#endif + cdrom_readmask_w &= ~(1 << j); + cdrom_status1 |= CDSTATUS_DATASECTOR; + } + cdrom_sector_counter++; +} + +static uae_sem_t akiko_sem; + +static void akiko_handler (void) +{ + static int mediacheckcnt; + struct device_info di; + + if (cdrom_result_complete > cdrom_result_last_pos && cdrom_result_complete - cdrom_result_last_pos < 100) { + cdrom_status1 |= CDSTATUS_DATA_AVAILABLE; + return; + } + if (cdrom_result_last_pos < cdrom_result_complete) + return; + if (mediacheckcnt > 0) + mediacheckcnt--; + if (mediacheckcnt == 0) { + int media = sys_command_info (DF_IOCTL, unitnum, &di)->media_inserted; + if (media != cdrom_disk) { + write_log ("media changed = %d\n", media); + cdrom_disk = media; + cdrom_return_data (cdrom_command_media_status ()); + cdrom_toc (); + return; + } + mediacheckcnt = 312 * 50 * 2; + } + if (cdrom_toc_counter >= 0 && !cdrom_command_active && cdrom_dosomething) { + cdrom_return_data (cdrom_return_toc_entry ()); + cdrom_dosomething--; + return; + } +} + +static void akiko_internal (void) +{ + cdrom_run_command (); + if (cdrom_command_active > 0) { + cdrom_command_active--; + if (!cdrom_command_active) + cdrom_run_command_run (); + } +} + +extern int cd32_enabled; + +void AKIKO_hsync_handler (void) +{ + static int framecounter; + + if (!cd32_enabled) + return; + framecounter--; + if (framecounter <= 0) { + cdrom_run_read (); + framecounter = 1000000 / (74 * 75 * cdrom_speed); + cdrom_status1 |= CDSTATUS_FRAME; + } + akiko_internal (); + akiko_handler (); +} + + +static volatile int akiko_thread_running; + +/* cdrom data buffering thread */ +static void *akiko_thread (void *null) +{ + int i; + uae_u8 *tmp1; + uae_u8 *tmp2; + int tmp3; + uae_u8 *p; + int offset; + int sector; + + while(akiko_thread_running) { + uae_sem_wait (&akiko_sem); + sector = cdrom_current_sector; + for (i = 0; i < SECTOR_BUFFER_SIZE; i++) { + if (sector_buffer_info_1[i] == 0xff) break; + } + if (cdrom_data_end > 0 && sector >= 0 && (sector_buffer_sector_1 < 0 || sector < sector_buffer_sector_1 || sector >= sector_buffer_sector_1 + SECTOR_BUFFER_SIZE * 2 / 3 || i != SECTOR_BUFFER_SIZE)) { + memset (sector_buffer_info_2, 0, SECTOR_BUFFER_SIZE); +#if AKIKO_DEBUG_IO_CMD + write_log("filling buffer sector=%d (max=%d)\n", sector, cdrom_data_end); +#endif + sector_buffer_sector_2 = sector; + offset = 0; + while (offset < SECTOR_BUFFER_SIZE) { + p = 0; + if (sector < cdrom_data_end) + p = sys_command_read (DF_IOCTL, unitnum, sector); + if (p) + memcpy (sector_buffer_2 + offset * 2048, p, 2048); + sector_buffer_info_2[offset] = p ? 3 : 0; + offset++; + sector++; + } + tmp1 = sector_buffer_info_1; + sector_buffer_info_1 = sector_buffer_info_2; + sector_buffer_info_2 = tmp1; + tmp2 = sector_buffer_1; + sector_buffer_1 = sector_buffer_2; + sector_buffer_2 = tmp2; + tmp3 = sector_buffer_sector_1; + sector_buffer_sector_1 = sector_buffer_sector_2; + sector_buffer_sector_2 = tmp3; + } + uae_sem_post (&akiko_sem); + Sleep (10); + } + akiko_thread_running = -1; + return 0; +} + +static uae_u8 akiko_get_long (uae_u32 v, int offset) +{ + return v >> ((3 - offset) * 8); +} +static void akiko_put_long (uae_u32 *p, int offset, int v) +{ + *p &= ~(0xff << ((3 - offset) * 8)); + *p |= v << ((3 - offset) * 8); +} + +uae_u32 akiko_bget2 (uaecptr addr, int msg) +{ + uae_u8 v; + + addr &= 0xffff; + uae_sem_wait (&akiko_sem); + switch (addr) + { + /* "CAFE" = Akiko identification. + * Kickstart ignores Akiko C2P if this ID isn't correct */ + case 0x02: + v = 0xCA; + break; + case 0x03: + v = 0xFE; + break; + + /* CDROM control */ + case 0x04: + case 0x05: + case 0x06: + case 0x07: + v = akiko_get_long (cdrom_status1, addr - 0x04); + break; + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + v = akiko_get_long (cdrom_status2, addr - 0x08); + break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + v = akiko_get_long (cdrom_address1, addr - 0x10); + break; + case 0x14: + case 0x15: + case 0x16: + case 0x17: + v = akiko_get_long (cdrom_address2, addr - 0x14); + break; + case 0x18: + v = cdrom_status3; + break; + case 0x19: + v = cdrom_command_offset_complete; + break; + case 0x1a: + v = cdrom_result_complete; + break; + case 0x1f: + v = cdrom_result_last_pos; + break; + case 0x20: + case 0x21: + v = akiko_get_long (cdrom_readmask_w, addr - 0x20 + 2); + break; + case 0x24: + case 0x25: + case 0x26: + case 0x27: + v = akiko_get_long (cdrom_longmask, addr - 0x24); + break; + + /* NVRAM */ + case 0x30: + case 0x31: + case 0x32: + case 0x33: + v = akiko_nvram_read (addr - 0x30); + break; + + /* C2P */ + case 0x38: + case 0x39: + case 0x3a: + case 0x3b: + v = akiko_c2p_read (addr - 0x38); + break; + + default: + write_log ("akiko_bget: unknown address %08.8X\n", addr); + v = 0; + break; + } + akiko_internal (); + uae_sem_post (&akiko_sem); + if (msg && addr < 0x30 && AKIKO_DEBUG_IO) + write_log ("akiko_bget %08.8X: %08.8X %02.2X\n", m68k_getpc(), addr, v & 0xff); + return v; +} + +uae_u32 akiko_bget (uaecptr addr) +{ + return akiko_bget2 (addr,1); +} + +uae_u32 akiko_wget (uaecptr addr) +{ + uae_u16 v; + addr &= 0xffff; + v = akiko_bget2 (addr + 1, 0); + v |= akiko_bget2 (addr + 0, 0) << 8; + if (addr < 0x30 && AKIKO_DEBUG_IO) + write_log ("akiko_wget %08.8X: %08.8X %04.4X\n", m68k_getpc(), addr, v & 0xffff); + return v; +} + +uae_u32 akiko_lget (uaecptr addr) +{ + uae_u32 v; + + addr &= 0xffff; + v = akiko_bget2 (addr + 3, 0); + v |= akiko_bget2 (addr + 2, 0) << 8; + v |= akiko_bget2 (addr + 1, 0) << 16; + v |= akiko_bget2 (addr + 0, 0) << 24; + if (addr < 0x30 && (addr != 4 && addr != 8) && AKIKO_DEBUG_IO) + write_log ("akiko_lget %08.8X: %08.8X %08.8X\n", m68k_getpc(), addr, v); + return v; +} + +void akiko_bput2 (uaecptr addr, uae_u32 v, int msg) +{ + uae_u32 tmp; + + addr &= 0xffff; + v &= 0xff; + if(msg && addr < 0x30 && AKIKO_DEBUG_IO) + write_log ("akiko_bput %08.8X: %08.8X=%02.2X\n", m68k_getpc(), addr, v & 0xff); + uae_sem_wait (&akiko_sem); + switch (addr) + { + case 0x04: + case 0x05: + case 0x06: + case 0x07: + akiko_put_long (&cdrom_status1, addr - 0x04, v); + break; + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + akiko_put_long (&cdrom_status2, addr - 0x08, v); + if (addr == 8) + cdrom_status1 &= cdrom_status2; + break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + akiko_put_long (&cdrom_address1, addr - 0x10, v); + break; + case 0x14: + case 0x15: + case 0x16: + case 0x17: + akiko_put_long (&cdrom_address2, addr - 0x14, v); + break; + case 0x18: + cdrom_status3 = v; + break; + case 0x19: + cdrom_command_offset_complete = v; + break; + case 0x1a: + cdrom_result_complete = v; + break; + case 0x1d: + cdrom_command_offset_todo = v; + break; + case 0x1f: + cdrom_result_last_pos = v; + break; + case 0x20: + cdrom_readmask_w |= (v << 8); + cdrom_readmask_r &= 0x00ff; + break; + case 0x21: + cdrom_readmask_w |= (v << 0); + cdrom_readmask_r &= 0xff00; + break; + case 0x24: + case 0x25: + case 0x26: + case 0x27: + tmp = cdrom_longmask; + akiko_put_long (&cdrom_longmask, addr - 0x24, v); + if ((cdrom_longmask & 0x04000000) && !(tmp & 0x04000000)) + cdrom_sector_counter = 0; + break; + + case 0x30: + case 0x31: + case 0x32: + case 0x33: + akiko_nvram_write (addr - 0x30, v); + break; + + case 0x38: + case 0x39: + case 0x3a: + case 0x3b: + akiko_c2p_write (addr - 0x38, v); + break; + + default: + write_log ("akiko_bput: unknown address %08.8X\n", addr); + break; + } + akiko_internal (); + uae_sem_post (&akiko_sem); +} + +void akiko_bput (uaecptr addr, uae_u32 v) +{ + akiko_bput2 (addr, v, 1); +} + +void akiko_wput (uaecptr addr, uae_u32 v) +{ + addr &= 0xfff; + if((addr < 0x30 && AKIKO_DEBUG_IO)) + write_log("akiko_wput %08.8X: %08.8X=%04.4X\n", m68k_getpc(), addr, v & 0xffff); + akiko_bput2 (addr + 1, v & 0xff, 0); + akiko_bput2 (addr + 0, v >> 8, 0); +} + +void akiko_lput (uaecptr addr, uae_u32 v) +{ + addr &= 0xffff; + if(addr < 0x30 && AKIKO_DEBUG_IO) + write_log("akiko_lput %08.8X: %08.8X=%08.8X\n", m68k_getpc(), addr, v); + akiko_bput2 (addr + 3, (v >> 0) & 0xff, 0); + akiko_bput2 (addr + 2, (v >> 8) & 0xff, 0); + akiko_bput2 (addr + 1, (v >> 16) & 0xff, 0); + akiko_bput2 (addr + 0, (v >> 24) & 0xff, 0); +} + +static uae_thread_id akiko_tid; + +void akiko_reset (void) +{ + nvram_read (); + state = I2C_WAIT; + bitcounter = -1; + direction = -1; + + cdrom_speed = 1; + cdrom_current_sector = -1; + + if (akiko_thread_running > 0) { + akiko_thread_running = 0; + while(akiko_thread_running == 0) + Sleep (10); + akiko_thread_running = 0; + } +} + +extern uae_u32 extendedkickmemory; + +static uae_u8 patchdata[]={0x0c,0x82,0x00,0x00,0x03,0xe8,0x64,0x00,0x00,0x46}; + +static void patchrom (void) +{ + int i; + uae_u8 *p = (uae_u8*)extendedkickmemory; + for (i = 0; i < 524288 - sizeof (patchdata); i++) { + if (!memcmp (p + i, patchdata, sizeof(patchdata))) { + p[i + 6] = 0x4e; + p[i + 7] = 0x71; + p[i + 8] = 0x4e; + p[i + 9] = 0x71; + write_log ("extended rom delay loop patched at 0x%p\n", i + 6 + 0xe00000); + return; + } + } + write_log ("couldn't patch extended rom\n"); +} + +void akiko_free (void) +{ + akiko_reset (); + if (unitnum >= 0) + sys_cddev_close (); + unitnum = -1; + free (sector_buffer_1); + free (sector_buffer_2); + free (sector_buffer_info_1); + free (sector_buffer_info_2); + sector_buffer_1 = 0; + sector_buffer_2 = 0; + sector_buffer_info_1 = 0; + sector_buffer_info_2 = 0; +} + +void akiko_init (void) +{ + static int cdromok = 0; + + if (cdromok == 0) { + unitnum = -1; + device_func_init(DEVICE_TYPE_ANY); + if (!sys_cddev_open ()) { + cdromok = 1; + sector_buffer_1 = malloc (SECTOR_BUFFER_SIZE * 2048); + sector_buffer_2 = malloc (SECTOR_BUFFER_SIZE * 2048); + sector_buffer_info_1 = malloc (SECTOR_BUFFER_SIZE); + sector_buffer_info_2 = malloc (SECTOR_BUFFER_SIZE); + sector_buffer_sector_1 = -1; + sector_buffer_sector_2 = -1; + patchrom (); + } + } + if (!savestate_state) { + cdrom_playing = cdrom_paused = 0; + cdrom_data_offset = -1; + uae_sem_init (&akiko_sem, 0, 1); + } + if (cdromok && !akiko_thread_running) { + akiko_thread_running = 1; + uae_start_thread (akiko_thread, 0, &akiko_tid); + } +} + +uae_u8 *save_akiko(int *len) +{ + uae_u8 *dstbak, *dst; + int i; + + dstbak = dst = malloc (1000); + save_u16 (0); + save_u16 (0xCAFE); + save_u32 (cdrom_status1); + save_u32 (cdrom_status2); + save_u32 (0); + save_u32 (cdrom_address1); + save_u32 (cdrom_address2); + save_u8 (cdrom_status3); + save_u8 (cdrom_command_offset_complete); + save_u8 (cdrom_result_complete); + save_u8 (0); + save_u8 (0); + save_u8 (cdrom_command_offset_todo); + save_u8 (0); + save_u8 (cdrom_result_last_pos); + save_u16 ((uae_u16)cdrom_readmask_w); + save_u16 (0); + save_u32 (cdrom_longmask); + save_u32 (0); + save_u32 (0); + save_u32 ((scl_dir ? 0x8000 : 0) | (sda_dir ? 0x4000 : 0)); + save_u32 (0); + save_u32 (0); + + for (i = 0; i < 8; i++) + save_u32 (akiko_buffer[i]); + save_u8 ((uae_u8)akiko_read_offset); + save_u8 ((uae_u8)akiko_write_offset); + + save_u32 ((cdrom_playing ? 1 : 0) | (cdrom_paused ? 2 : 0)); + if (cdrom_playing) + cd_qcode (0); + save_u32 (last_play_pos); + save_u32 (last_play_end); + save_u8 ((uae_u8)cdrom_toc_counter); + + *len = dst - dstbak; + return dstbak; +} + +uae_u8 *restore_akiko(uae_u8 *src) +{ + uae_u32 v; + int i; + + restore_u16 (); + restore_u16 (); + cdrom_status1 = restore_u32 (); + cdrom_status2 = restore_u32 (); + restore_u32(); + cdrom_address1 = restore_u32 (); + cdrom_address2 = restore_u32 (); + cdrom_status3 = restore_u8 (); + cdrom_command_offset_complete = restore_u8 (); + cdrom_result_complete = restore_u8 (); + restore_u8 (); + restore_u8 (); + cdrom_command_offset_todo = restore_u8 (); + restore_u8 (); + cdrom_result_last_pos = restore_u8 (); + cdrom_readmask_w = restore_u16 (); + restore_u16 (); + cdrom_longmask = restore_u32 (); + restore_u32(); + restore_u32(); + v = restore_u32(); + scl_dir = (v & 0x8000) ? 1 : 0; + sda_dir = (v & 0x4000) ? 1 : 0; + restore_u32(); + restore_u32(); + + for (i = 0; i < 8; i++) + akiko_buffer[i] = restore_u32 (); + akiko_read_offset = restore_u8 (); + akiko_write_offset = restore_u8 (); + akiko_c2p_do (); + + cdrom_playing = cdrom_paused = 0; + v = restore_u32 (); + if (v & 1) + cdrom_playing = 1; + if (v & 2) + cdrom_paused = 1; + last_play_pos = restore_u32 (); + last_play_end = restore_u32 (); + cdrom_toc_counter = restore_u8 (); + if (cdrom_toc_counter == 255) + cdrom_toc_counter = -1; + if (cdrom_playing) + sys_command_play (DF_IOCTL, unitnum, last_play_pos, last_play_end, 0); + + return src; +} \ No newline at end of file diff --git a/ar.c b/ar.c new file mode 100755 index 00000000..ddea11ce --- /dev/null +++ b/ar.c @@ -0,0 +1,1631 @@ +/* + * UAE Action Replay 1/2/3 and HRTMon support + * + * (c) 2000-2002 Toni Wilen + * (c) 2003 Mark Cox + * + * 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 + * + * AR2 or AR3: + * may + * the + * force + * be + * with + * you + * new (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> 16, hrtmem_size >> 16, hrtmem_size); +} + +static void hrtmon_unmap_banks() +{ + if(!hrtmemory) + return; + + map_banks (&dummy_bank, hrtmem_start >> 16, hrtmem_size >> 16, hrtmem_size); +} + + + +#define AR_VER_STR_OFFSET 0x4 /* offset in the rom where the version string begins. */ +#define AR_VER_STR_END 0x7c /* offset in the rom where the version string ends. */ +#define AR_VER_STR_LEN (AR_VER_STR_END - AR_VER_STR_OFFSET) +char arVersionString[AR_VER_STR_LEN+1]; + +/* This function extracts the version info for AR2 and AR3. */ + +void action_replay_version() +{ + char* tmp; + int iArVersionMajor = -1 ; + int iArVersionMinor = -1; + char* pNext; + char sArDate[11]; + *sArDate = '\0'; + + if (!armemory_rom) + return; + + if ( armodel == 1 ) + return; /* no support yet. */ + + /* Extract Version string */ + memcpy(arVersionString, armemory_rom+AR_VER_STR_OFFSET, AR_VER_STR_LEN); + arVersionString[AR_VER_STR_LEN]= '\0'; + tmp = strchr(arVersionString, 0x0d); + if ( tmp ) + { + *tmp = '\0'; + } +/* write_log_debug("Version string is : '%s'\n", arVersionString); */ + + tmp = strchr(arVersionString,')'); + if ( tmp ) + { + *tmp = '\0'; + tmp = strchr(arVersionString, '('); + if ( tmp ) + { + if ( *(tmp + 1 ) == 'V' ) + { + pNext = tmp + 2; + tmp = strchr(pNext, '.'); + if ( tmp ) + { + *tmp = '\0'; + iArVersionMajor = atoi(pNext); + pNext = tmp+1; + tmp = strchr(pNext, ' '); + if ( tmp ) + { + *tmp = '\0'; + iArVersionMinor = atoi(pNext); + } + pNext = tmp+1; + strcpy(sArDate, pNext); + } + + } + } + } + + if ( iArVersionMajor > 0 ) + { + write_log("Version of cart is '%d.%.02d', date is '%s'\n", iArVersionMajor, iArVersionMinor, sArDate); + } +} + +/* This function doesn't reset the Cart memory, it is just called during a memory reset */ +void action_replay_memory_reset(void) +{ + #ifdef ACTION_REPLAY + if ( armemory_rom ) + { + action_replay_hide(); + } + #endif + #ifdef ACTION_REPLAY_HRTMON + if ( hrtmemory ) + { + hrtmon_hide(); /* It is never really idle */ + } + #endif + #ifdef ACTION_REPLAY_COMMON + check_prefs_changed_carts(1); + #endif + action_replay_patch(); + action_replay_checksum_info(); +} + +uae_u8 *save_action_replay (int *len, uae_u8 *dstptr) +{ + uae_u8 *dstbak,*dst; + + *len = 1; + if (!armemory_ram || !armemory_rom || !armodel) + return 0; + *len = 1 + strlen(currprefs.cartfile) + 1 + arram_size + 256; + if (dstptr) + dstbak = dst = dstptr; + else + dstbak = dst = malloc (*len); + save_u8 (armodel); + strcpy (dst, currprefs.cartfile); + dst += strlen(dst) + 1; + memcpy (dst, armemory_ram, arram_size); + return dstbak; +} + +uae_u8 *restore_action_replay (uae_u8 *src) +{ + action_replay_unload (1); + armodel = restore_u8 (); + if (!armodel) + return src; + strncpy (changed_prefs.cartfile, src, 255); + strcpy (currprefs.cartfile, changed_prefs.cartfile); + src += strlen(src) + 1; + action_replay_load (); + if (armemory_ram) { + memcpy (armemory_ram, src, arram_size); + memcpy (ar_custom, armemory_ram + 0xf000, 2 * 256); + src += arram_size; + } + src += 256; + return src; +} diff --git a/audio.c b/audio.c new file mode 100755 index 00000000..b1b92db8 --- /dev/null +++ b/audio.c @@ -0,0 +1,1084 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * OS specific functions + * + * Copyright 1995, 1996, 1997 Bernd Schmidt + * Copyright 1996 Marcus Sundberg + * Copyright 1996 Manfred Thole + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "memory.h" +#include "custom.h" +#include "newcpu.h" +#include "autoconf.h" +#include "gensound.h" +#include "sounddep/sound.h" +#include "events.h" +#include "audio.h" +#include "savestate.h" +#include "driveclick.h" +#ifdef AVIOUTPUT +#include "avioutput.h" +#endif + +#define MAX_EV ~0ul +//#define DEBUG_AUDIO +#define DEBUG_CHANNEL_MASK 15 + +int audio_channel_mask = 15; + +static int debugchannel (int ch) +{ + if ((1 << ch) & DEBUG_CHANNEL_MASK) return 1; + return 0; +} + +struct audio_channel_data { + unsigned long adk_mask; + unsigned long evtime; + uae_u8 dmaen, intreq2; + uaecptr lc, pt; + int current_sample, last_sample; + int *voltbl; + int state; + int per; + int vol; + int len, wlen; + uae_u16 dat, dat2; + int request_word, request_word_skip; +}; + +STATIC_INLINE int current_hpos (void) +{ + return (get_cycles () - eventtab[ev_hsync].oldcycles) / CYCLE_UNIT; +} + +static struct audio_channel_data audio_channel[4]; +int sound_available = 0; +static int sound_table[64][256]; +void (*sample_handler) (void); + +unsigned long sample_evtime, scaled_sample_evtime; + +static unsigned long last_cycles, next_sample_evtime; + +void init_sound_table16 (void) +{ + int i,j; + + for (i = 0; i < 256; i++) + for (j = 0; j < 64; j++) + sound_table[j][i] = j * (uae_s8)i * (currprefs.stereo ? 2 : 1); +} + +void init_sound_table8 (void) +{ + int i,j; + + for (i = 0; i < 256; i++) + for (j = 0; j < 64; j++) + sound_table[j][i] = (j * (uae_s8)i * (currprefs.stereo ? 2 : 1)) / 256; +} + +#define MULTIPLICATION_PROFITABLE + +#ifdef MULTIPLICATION_PROFITABLE +typedef uae_s8 sample8_t; +#define DO_CHANNEL_1(v, c) do { (v) *= audio_channel[c].vol; } while (0) +#define SBASEVAL16(logn) ((logn) == 1 ? SOUND16_BASE_VAL >> 1 : SOUND16_BASE_VAL) +#define FINISH_DATA(data,b,logn) do { if (14 - (b) + (logn) > 0) (data) >>= 14 - (b) + (logn); else (data) <<= (b) - 14 - (logn); } while (0); +#else +typedef uae_u8 sample8_t; +#define DO_CHANNEL_1(v, c) do { (v) = audio_channel[c].voltbl[(v)]; } while (0) +#define SBASEVAL16(logn) SOUND16_BASE_VAL +#define FINISH_DATA(data,b,logn) +#endif + +/* Always put the right word before the left word. */ +#define DELAY_BUFFER 32 +static uae_u32 right_word_saved[DELAY_BUFFER]; +static uae_u32 left_word_saved[DELAY_BUFFER]; +static int saved_ptr; + +STATIC_INLINE void put_sound_word_right (uae_u32 w) +{ + if (currprefs.mixed_stereo) { + right_word_saved[saved_ptr] = w; + return; + } + PUT_SOUND_WORD_RIGHT (w); +} + +STATIC_INLINE void put_sound_word_left (uae_u32 w) +{ + if (currprefs.mixed_stereo) { + uae_u32 rold, lold, rnew, lnew, tmp; + + left_word_saved[saved_ptr] = w; + lnew = w - SOUND16_BASE_VAL; + rnew = right_word_saved[saved_ptr] - SOUND16_BASE_VAL; + + saved_ptr = (saved_ptr + 1) & (DELAY_BUFFER - 1); + lold = left_word_saved[saved_ptr] - SOUND16_BASE_VAL; + tmp = (rnew * 5 + lold * 3) >> 3; + tmp += SOUND16_BASE_VAL; + PUT_SOUND_WORD_RIGHT (tmp); + + rold = right_word_saved[saved_ptr] - SOUND16_BASE_VAL; + w = (lnew * 5 + rold * 3) >> 3; + } + PUT_SOUND_WORD_LEFT (w); +} + +#define DO_CHANNEL(v, c) do { (v) &= audio_channel[c].adk_mask; data += v; } while (0); + +void sample16_handler (void) +{ + uae_u32 data0 = audio_channel[0].current_sample; + uae_u32 data1 = audio_channel[1].current_sample; + uae_u32 data2 = audio_channel[2].current_sample; + uae_u32 data3 = audio_channel[3].current_sample; + DO_CHANNEL_1 (data0, 0); + DO_CHANNEL_1 (data1, 1); + DO_CHANNEL_1 (data2, 2); + DO_CHANNEL_1 (data3, 3); + data0 &= audio_channel[0].adk_mask; + data1 &= audio_channel[1].adk_mask; + data2 &= audio_channel[2].adk_mask; + data3 &= audio_channel[3].adk_mask; + data0 += data1; + data0 += data2; + data0 += data3; + { + uae_u32 data = SBASEVAL16(2) + data0; + FINISH_DATA (data, 16, 2); + PUT_SOUND_WORD (data); + } + check_sound_buffers (); +} + +void sample16i_rh_handler (void) +{ + unsigned long delta, ratio; + + uae_u32 data0 = audio_channel[0].current_sample; + uae_u32 data1 = audio_channel[1].current_sample; + uae_u32 data2 = audio_channel[2].current_sample; + uae_u32 data3 = audio_channel[3].current_sample; + uae_u32 data0p = audio_channel[0].last_sample; + uae_u32 data1p = audio_channel[1].last_sample; + uae_u32 data2p = audio_channel[2].last_sample; + uae_u32 data3p = audio_channel[3].last_sample; + DO_CHANNEL_1 (data0, 0); + DO_CHANNEL_1 (data1, 1); + DO_CHANNEL_1 (data2, 2); + DO_CHANNEL_1 (data3, 3); + DO_CHANNEL_1 (data0p, 0); + DO_CHANNEL_1 (data1p, 1); + DO_CHANNEL_1 (data2p, 2); + DO_CHANNEL_1 (data3p, 3); + + data0 &= audio_channel[0].adk_mask; + data0p &= audio_channel[0].adk_mask; + data1 &= audio_channel[1].adk_mask; + data1p &= audio_channel[1].adk_mask; + data2 &= audio_channel[2].adk_mask; + data2p &= audio_channel[2].adk_mask; + data3 &= audio_channel[3].adk_mask; + data3p &= audio_channel[3].adk_mask; + + /* linear interpolation and summing up... */ + delta = audio_channel[0].per; + ratio = ((audio_channel[0].evtime % delta) << 8) / delta; + data0 = (data0 * (256 - ratio) + data0p * ratio) >> 8; + delta = audio_channel[1].per; + ratio = ((audio_channel[1].evtime % delta) << 8) / delta; + data0 += (data1 * (256 - ratio) + data1p * ratio) >> 8; + delta = audio_channel[2].per; + ratio = ((audio_channel[2].evtime % delta) << 8) / delta; + data0 += (data2 * (256 - ratio) + data2p * ratio) >> 8; + delta = audio_channel[3].per; + ratio = ((audio_channel[3].evtime % delta) << 8) / delta; + data0 += (data3 * (256 - ratio) + data3p * ratio) >> 8; + { + uae_u32 data = SBASEVAL16(2) + data0; + FINISH_DATA (data, 16, 2); + PUT_SOUND_WORD (data); + } + check_sound_buffers (); +} + +void sample16i_crux_handler (void) +{ + uae_u32 data0 = audio_channel[0].current_sample; + uae_u32 data1 = audio_channel[1].current_sample; + uae_u32 data2 = audio_channel[2].current_sample; + uae_u32 data3 = audio_channel[3].current_sample; + uae_u32 data0p = audio_channel[0].last_sample; + uae_u32 data1p = audio_channel[1].last_sample; + uae_u32 data2p = audio_channel[2].last_sample; + uae_u32 data3p = audio_channel[3].last_sample; + DO_CHANNEL_1 (data0, 0); + DO_CHANNEL_1 (data1, 1); + DO_CHANNEL_1 (data2, 2); + DO_CHANNEL_1 (data3, 3); + DO_CHANNEL_1 (data0p, 0); + DO_CHANNEL_1 (data1p, 1); + DO_CHANNEL_1 (data2p, 2); + DO_CHANNEL_1 (data3p, 3); + + data0 &= audio_channel[0].adk_mask; + data0p &= audio_channel[0].adk_mask; + data1 &= audio_channel[1].adk_mask; + data1p &= audio_channel[1].adk_mask; + data2 &= audio_channel[2].adk_mask; + data2p &= audio_channel[2].adk_mask; + data3 &= audio_channel[3].adk_mask; + data3p &= audio_channel[3].adk_mask; + + { + struct audio_channel_data *cdp; + unsigned long ratio, ratio1; +#define INTERVAL (scaled_sample_evtime * 3) + cdp = audio_channel + 0; + ratio1 = cdp->per - cdp->evtime; + ratio = (ratio1 << 12) / INTERVAL; + if (cdp->evtime < scaled_sample_evtime || ratio1 >= INTERVAL) + ratio = 4096; + data0 = (data0 * ratio + data0p * (4096 - ratio)) >> 12; + + cdp = audio_channel + 1; + ratio1 = cdp->per - cdp->evtime; + ratio = (ratio1 << 12) / INTERVAL; + if (cdp->evtime < scaled_sample_evtime || ratio1 >= INTERVAL) + ratio = 4096; + data1 = (data1 * ratio + data1p * (4096 - ratio)) >> 12; + + cdp = audio_channel + 2; + ratio1 = cdp->per - cdp->evtime; + ratio = (ratio1 << 12) / INTERVAL; + if (cdp->evtime < scaled_sample_evtime || ratio1 >= INTERVAL) + ratio = 4096; + data2 = (data2 * ratio + data2p * (4096 - ratio)) >> 12; + + cdp = audio_channel + 3; + ratio1 = cdp->per - cdp->evtime; + ratio = (ratio1 << 12) / INTERVAL; + if (cdp->evtime < scaled_sample_evtime || ratio1 >= INTERVAL) + ratio = 4096; + data3 = (data3 * ratio + data3p * (4096 - ratio)) >> 12; + } + data1 += data2; + data0 += data3; + data0 += data1; + { + uae_u32 data = SBASEVAL16(2) + data0; + FINISH_DATA (data, 16, 2); + PUT_SOUND_WORD (data); + } + check_sound_buffers (); +} + +#ifdef HAVE_STEREO_SUPPORT +void sample16ss_handler (void) +{ + uae_u32 data0 = audio_channel[0].current_sample; + uae_u32 data1 = audio_channel[1].current_sample; + uae_u32 data2 = audio_channel[2].current_sample; + uae_u32 data3 = audio_channel[3].current_sample; + DO_CHANNEL_1 (data0, 0); + DO_CHANNEL_1 (data1, 1); + DO_CHANNEL_1 (data2, 2); + DO_CHANNEL_1 (data3, 3); + + data0 &= audio_channel[0].adk_mask; + data1 &= audio_channel[1].adk_mask; + data2 &= audio_channel[2].adk_mask; + data3 &= audio_channel[3].adk_mask; + + PUT_SOUND_WORD_LEFT (data0 << 2); + PUT_SOUND_WORD_RIGHT (data1 << 2); + PUT_SOUND_WORD_LEFT (data2 << 2); + PUT_SOUND_WORD_RIGHT (data3 << 2); + + check_sound_buffers (); +} + +void sample16s_handler (void) +{ + uae_u32 data0 = audio_channel[0].current_sample; + uae_u32 data1 = audio_channel[1].current_sample; + uae_u32 data2 = audio_channel[2].current_sample; + uae_u32 data3 = audio_channel[3].current_sample; + DO_CHANNEL_1 (data0, 0); + DO_CHANNEL_1 (data1, 1); + DO_CHANNEL_1 (data2, 2); + DO_CHANNEL_1 (data3, 3); + + data0 &= audio_channel[0].adk_mask; + data1 &= audio_channel[1].adk_mask; + data2 &= audio_channel[2].adk_mask; + data3 &= audio_channel[3].adk_mask; + + data0 += data3; + { + uae_u32 data = SBASEVAL16(1) + data0; + FINISH_DATA (data, 16, 1); + put_sound_word_right (data); + } + + data1 += data2; + { + uae_u32 data = SBASEVAL16(1) + data1; + FINISH_DATA (data, 16, 1); + put_sound_word_left (data); + } + + check_sound_buffers (); +} + +void sample16si_crux_handler (void) +{ + uae_u32 data0 = audio_channel[0].current_sample; + uae_u32 data1 = audio_channel[1].current_sample; + uae_u32 data2 = audio_channel[2].current_sample; + uae_u32 data3 = audio_channel[3].current_sample; + uae_u32 data0p = audio_channel[0].last_sample; + uae_u32 data1p = audio_channel[1].last_sample; + uae_u32 data2p = audio_channel[2].last_sample; + uae_u32 data3p = audio_channel[3].last_sample; + + DO_CHANNEL_1 (data0, 0); + DO_CHANNEL_1 (data1, 1); + DO_CHANNEL_1 (data2, 2); + DO_CHANNEL_1 (data3, 3); + DO_CHANNEL_1 (data0p, 0); + DO_CHANNEL_1 (data1p, 1); + DO_CHANNEL_1 (data2p, 2); + DO_CHANNEL_1 (data3p, 3); + + data0 &= audio_channel[0].adk_mask; + data0p &= audio_channel[0].adk_mask; + data1 &= audio_channel[1].adk_mask; + data1p &= audio_channel[1].adk_mask; + data2 &= audio_channel[2].adk_mask; + data2p &= audio_channel[2].adk_mask; + data3 &= audio_channel[3].adk_mask; + data3p &= audio_channel[3].adk_mask; + + { + struct audio_channel_data *cdp; + unsigned long ratio, ratio1; +#define INTERVAL (scaled_sample_evtime * 3) + cdp = audio_channel + 0; + ratio1 = cdp->per - cdp->evtime; + ratio = (ratio1 << 12) / INTERVAL; + if (cdp->evtime < scaled_sample_evtime || ratio1 >= INTERVAL) + ratio = 4096; + data0 = (data0 * ratio + data0p * (4096 - ratio)) >> 12; + + cdp = audio_channel + 1; + ratio1 = cdp->per - cdp->evtime; + ratio = (ratio1 << 12) / INTERVAL; + if (cdp->evtime < scaled_sample_evtime || ratio1 >= INTERVAL) + ratio = 4096; + data1 = (data1 * ratio + data1p * (4096 - ratio)) >> 12; + + cdp = audio_channel + 2; + ratio1 = cdp->per - cdp->evtime; + ratio = (ratio1 << 12) / INTERVAL; + if (cdp->evtime < scaled_sample_evtime || ratio1 >= INTERVAL) + ratio = 4096; + data2 = (data2 * ratio + data2p * (4096 - ratio)) >> 12; + + cdp = audio_channel + 3; + ratio1 = cdp->per - cdp->evtime; + ratio = (ratio1 << 12) / INTERVAL; + if (cdp->evtime < scaled_sample_evtime || ratio1 >= INTERVAL) + ratio = 4096; + data3 = (data3 * ratio + data3p * (4096 - ratio)) >> 12; + } + data1 += data2; + data0 += data3; + { + uae_u32 data = SBASEVAL16 (1) + data0; + FINISH_DATA (data, 16, 1); + put_sound_word_right (data); + } + + { + uae_u32 data = SBASEVAL16 (1) + data1; + FINISH_DATA (data, 16, 1); + put_sound_word_left (data); + } + check_sound_buffers (); +} + +void sample16si_rh_handler (void) +{ + unsigned long delta, ratio; + + uae_u32 data0 = audio_channel[0].current_sample; + uae_u32 data1 = audio_channel[1].current_sample; + uae_u32 data2 = audio_channel[2].current_sample; + uae_u32 data3 = audio_channel[3].current_sample; + uae_u32 data0p = audio_channel[0].last_sample; + uae_u32 data1p = audio_channel[1].last_sample; + uae_u32 data2p = audio_channel[2].last_sample; + uae_u32 data3p = audio_channel[3].last_sample; + + DO_CHANNEL_1 (data0, 0); + DO_CHANNEL_1 (data1, 1); + DO_CHANNEL_1 (data2, 2); + DO_CHANNEL_1 (data3, 3); + DO_CHANNEL_1 (data0p, 0); + DO_CHANNEL_1 (data1p, 1); + DO_CHANNEL_1 (data2p, 2); + DO_CHANNEL_1 (data3p, 3); + + data0 &= audio_channel[0].adk_mask; + data0p &= audio_channel[0].adk_mask; + data1 &= audio_channel[1].adk_mask; + data1p &= audio_channel[1].adk_mask; + data2 &= audio_channel[2].adk_mask; + data2p &= audio_channel[2].adk_mask; + data3 &= audio_channel[3].adk_mask; + data3p &= audio_channel[3].adk_mask; + + /* linear interpolation and summing up... */ + delta = audio_channel[0].per; + ratio = ((audio_channel[0].evtime % delta) << 8) / delta; + data0 = (data0 * (256 - ratio) + data0p * ratio) >> 8; + delta = audio_channel[1].per; + ratio = ((audio_channel[1].evtime % delta) << 8) / delta; + data1 = (data1 * (256 - ratio) + data1p * ratio) >> 8; + delta = audio_channel[2].per; + ratio = ((audio_channel[2].evtime % delta) << 8) / delta; + data1 += (data2 * (256 - ratio) + data2p * ratio) >> 8; + delta = audio_channel[3].per; + ratio = ((audio_channel[3].evtime % delta) << 8) / delta; + data0 += (data3 * (256 - ratio) + data3p * ratio) >> 8; + { + uae_u32 data = SBASEVAL16 (1) + data0; + FINISH_DATA (data, 16, 1); + put_sound_word_right (data); + } + + { + uae_u32 data = SBASEVAL16 (1) + data1; + FINISH_DATA (data, 16, 1); + put_sound_word_left (data); + } + check_sound_buffers (); +} + +#else +void sample16s_handler (void) +{ + sample16_handler(); +} +void sample16si_crux_handler (void) +{ + sample16i_crux_handler(); +} +void sample16si_rh_handler (void) +{ + sample16i_rh_handler(); +} +#endif + +void schedule_audio (void) +{ + unsigned long best = MAX_EV; + int i; + + eventtab[ev_audio].active = 0; + eventtab[ev_audio].oldcycles = get_cycles (); + for (i = 0; i < 4; i++) { + struct audio_channel_data *cdp = audio_channel + i; + if (cdp->evtime != MAX_EV) { + if (best > cdp->evtime) { + best = cdp->evtime; + eventtab[ev_audio].active = 1; + } + } + } + eventtab[ev_audio].evtime = get_cycles () + best; +} + +static int isirq (int nr) +{ + return INTREQR() & (0x80 << nr); +} + +static void setirq (int nr) +{ + INTREQ (0x8000 | (0x80 << nr)); +#ifdef DEBUG_AUDIO + if (debugchannel (nr)) + write_log ("SETIRQ %d %08.8X\n", nr, m68k_getpc()); +#endif +} + +static void newsample (int nr, sample8_t sample) +{ + struct audio_channel_data *cdp = audio_channel + nr; +#ifdef DEBUG_AUDIO + if (!debugchannel (nr)) sample = 0; +#endif + if (!(audio_channel_mask & (1 << nr))) + sample = 0; + cdp->last_sample = cdp->current_sample; + cdp->current_sample = sample; +} + +static void state23 (struct audio_channel_data *cdp) +{ + if (!cdp->dmaen) + return; + if (cdp->request_word >= 0) + return; + cdp->request_word = 0; + if (cdp->wlen == 1) { + cdp->wlen = cdp->len; + cdp->pt = cdp->lc; + cdp->intreq2 = 1; +#ifdef DEBUG_AUDIO + if (debugchannel (cdp - audio_channel)) + write_log ("Channel %d looped, LC=%08.8X LEN=%d\n", cdp - audio_channel, cdp->pt, cdp->wlen); +#endif + } else { + cdp->wlen = (cdp->wlen - 1) & 0xFFFF; + } +} + +static void audio_handler (int nr, int timed) +{ + struct audio_channel_data *cdp = audio_channel + nr; + + int audav = adkcon & (0x01 << nr); + int audap = adkcon & (0x10 << nr); + int napnav = (!audav && !audap) || audav; + int evtime = cdp->evtime; + + cdp->evtime = MAX_EV; + switch (cdp->state) + { + case 0: + cdp->request_word = 0; + cdp->request_word_skip = 0; + cdp->intreq2 = 0; + if (cdp->dmaen) { + cdp->state = 1; + cdp->wlen = cdp->len; + /* there are too many stupid sound routines that fail on "too" fast cpus.. */ + if (currprefs.cpu_level > 1) + cdp->pt = cdp->lc; +#ifdef DEBUG_AUDIO + if (debugchannel (nr)) + write_log ("%d:0>1: LEN=%d\n", nr, cdp->wlen); +#endif + audio_handler (nr, timed); + return; + } else if (!cdp->dmaen && cdp->request_word < 0 && !isirq (nr)) { + cdp->evtime = 0; + cdp->state = 2; + setirq (nr); + audio_handler (nr, timed); + return; + } + return; + + case 1: + if (!cdp->dmaen) { + cdp->state = 0; + return; + } + cdp->state = 5; + if (cdp->wlen != 1) + cdp->wlen = (cdp->wlen - 1) & 0xFFFF; + cdp->request_word = 2; + if (current_hpos () > maxhpos - 20) + cdp->request_word_skip = 1; + return; + + case 5: + if (!cdp->request_word) { + cdp->request_word = 2; + return; + } + setirq (nr); + if (!cdp->dmaen) { + cdp->state = 0; + cdp->request_word = 0; + return; + } + cdp->state = 2; + cdp->request_word = 3; + if (napnav) + cdp->request_word = 2; + cdp->dat = cdp->dat2; + return; + + case 2: + if (currprefs.produce_sound == 0) + cdp->per = PERIOD_MAX; + + if (!cdp->dmaen && isirq (nr) && ((cdp->per <= 30 ) || (evtime == 0 || evtime == MAX_EV || evtime == cdp->per))) { + cdp->state = 0; + cdp->evtime = MAX_EV; + cdp->request_word = 0; + return; + } + + state23 (cdp); + cdp->state = 3; + cdp->evtime = cdp->per; + newsample (nr, (cdp->dat >> 8) & 0xff); + cdp->dat <<= 8; + /* Period attachment? */ + if (audap) { + if (cdp->intreq2 && cdp->dmaen) + setirq (nr); + cdp->intreq2 = 0; + cdp->request_word = 1; + cdp->dat = cdp->dat2; + if (nr < 3) { + if (cdp->dat == 0) + (cdp+1)->per = PERIOD_MAX; + else if (cdp->dat < maxhpos * CYCLE_UNIT / 2 && currprefs.produce_sound < 3) + (cdp+1)->per = maxhpos * CYCLE_UNIT / 2; + else + (cdp+1)->per = cdp->dat * CYCLE_UNIT; + } + } + return; + + case 3: + if (currprefs.produce_sound == 0) + cdp->per = PERIOD_MAX; + state23 (cdp); + cdp->state = 2; + cdp->evtime = cdp->per; + newsample (nr, (cdp->dat >> 8) & 0xff); + cdp->dat <<= 8; + cdp->dat = cdp->dat2; + if (cdp->dmaen) { + if (napnav) + cdp->request_word = 1; + if (cdp->intreq2 && napnav) + setirq (nr); + } else { + if (napnav) + setirq (nr); + } + cdp->intreq2 = 0; + + /* Volume attachment? */ + if (audav) { + if (nr < 3) { + (cdp+1)->vol = cdp->dat; + #ifndef MULTIPLICATION_PROFITABLE + (cdp+1)->voltbl = sound_table[cdp->dat]; + #endif + } + } + return; + } +} + +void audio_reset (void) +{ + int i; + struct audio_channel_data *cdp; + +#ifdef AHI + ahi_close_sound (); +#endif + reset_sound (); + if (savestate_state != STATE_RESTORE) { + for (i = 0; i < 4; i++) { + cdp = &audio_channel[i]; + memset (cdp, 0, sizeof *audio_channel); + cdp->per = PERIOD_MAX - 1; + cdp->voltbl = sound_table[0]; + cdp->vol = 0; + cdp->evtime = MAX_EV; + } + } else { + for (i = 0; i < 4; i++) { + cdp = &audio_channel[i]; + cdp->dmaen = (dmacon & DMA_MASTER) && (dmacon & (1 << i)); + } + } + +#ifndef MULTIPLICATION_PROFITABLE + for (i = 0; i < 4; i++) + audio_channel[i].voltbl = sound_table[audio_channel[i].vol]; +#endif + + last_cycles = get_cycles (); + next_sample_evtime = scaled_sample_evtime; + schedule_audio (); + events_schedule (); +} + +STATIC_INLINE int sound_prefs_changed (void) +{ + return (changed_prefs.produce_sound != currprefs.produce_sound + || changed_prefs.win32_soundcard != currprefs.win32_soundcard + || changed_prefs.stereo != currprefs.stereo + || changed_prefs.mixed_stereo != currprefs.mixed_stereo + || changed_prefs.sound_maxbsiz != currprefs.sound_maxbsiz + || changed_prefs.sound_freq != currprefs.sound_freq + || changed_prefs.sound_adjust != currprefs.sound_adjust + || changed_prefs.sound_interpol != currprefs.sound_interpol + || changed_prefs.sound_volume != currprefs.sound_volume + || changed_prefs.sound_filter != currprefs.sound_filter); +} + +void check_prefs_changed_audio (void) +{ +#ifdef DRIVESOUND + driveclick_check_prefs (); +#endif + if (sound_available && sound_prefs_changed ()) { + close_sound (); +#ifdef AVIOUTPUT + AVIOutput_Restart (); +#endif + + currprefs.produce_sound = changed_prefs.produce_sound; + currprefs.win32_soundcard = changed_prefs.win32_soundcard; + currprefs.stereo = changed_prefs.stereo; + currprefs.mixed_stereo = changed_prefs.mixed_stereo; + currprefs.sound_adjust = changed_prefs.sound_adjust; + currprefs.sound_interpol = changed_prefs.sound_interpol; + currprefs.sound_freq = changed_prefs.sound_freq; + currprefs.sound_maxbsiz = changed_prefs.sound_maxbsiz; + currprefs.sound_filter = changed_prefs.sound_filter; + currprefs.sound_volume = changed_prefs.sound_volume; + if (currprefs.produce_sound >= 2) { + if (!init_audio ()) { + if (! sound_available) { + write_log ("Sound is not supported.\n"); + } else { + write_log ("Sorry, can't initialize sound.\n"); + currprefs.produce_sound = 0; + /* So we don't do this every frame */ + changed_prefs.produce_sound = 0; + } + } + } + last_cycles = get_cycles () - 1; + next_sample_evtime = scaled_sample_evtime; + compute_vsynctime (); + } + /* Select the right interpolation method. */ + if (sample_handler == sample16_handler + || sample_handler == sample16i_crux_handler + || sample_handler == sample16i_rh_handler) + sample_handler = (currprefs.sound_interpol == 0 ? sample16_handler + : currprefs.sound_interpol == 1 ? sample16i_rh_handler + : sample16i_crux_handler); + else if (sample_handler == sample16s_handler + || sample_handler == sample16si_crux_handler + || sample_handler == sample16si_rh_handler) + sample_handler = (currprefs.sound_interpol == 0 ? sample16s_handler + : currprefs.sound_interpol == 1 ? sample16si_rh_handler + : sample16si_crux_handler); + + if (currprefs.produce_sound == 0) { + eventtab[ev_audio].active = 0; + events_schedule (); + } +} + +void update_audio (void) +{ + unsigned long int n_cycles; + + if (currprefs.produce_sound == 0 || savestate_state == STATE_RESTORE) + return; + + n_cycles = get_cycles () - last_cycles; + for (;;) { + unsigned long int best_evtime = n_cycles + 1; + + if (audio_channel[0].evtime != MAX_EV && best_evtime > audio_channel[0].evtime) + best_evtime = audio_channel[0].evtime; + if (audio_channel[1].evtime != MAX_EV && best_evtime > audio_channel[1].evtime) + best_evtime = audio_channel[1].evtime; + if (audio_channel[2].evtime != MAX_EV && best_evtime > audio_channel[2].evtime) + best_evtime = audio_channel[2].evtime; + if (audio_channel[3].evtime != MAX_EV && best_evtime > audio_channel[3].evtime) + best_evtime = audio_channel[3].evtime; + + if (currprefs.produce_sound > 1 && best_evtime > next_sample_evtime) + best_evtime = next_sample_evtime; + + if (best_evtime > n_cycles) + break; + + if (audio_channel[0].evtime != MAX_EV) + audio_channel[0].evtime -= best_evtime; + if (audio_channel[1].evtime != MAX_EV) + audio_channel[1].evtime -= best_evtime; + if (audio_channel[2].evtime != MAX_EV) + audio_channel[2].evtime -= best_evtime; + if (audio_channel[3].evtime != MAX_EV) + audio_channel[3].evtime -= best_evtime; + + n_cycles -= best_evtime; + if (currprefs.produce_sound > 1) { + next_sample_evtime -= best_evtime; + if (next_sample_evtime == 0) { + next_sample_evtime = scaled_sample_evtime; + (*sample_handler) (); + } + } + if (audio_channel[0].evtime == 0) + audio_handler (0, 1); + if (audio_channel[1].evtime == 0) + audio_handler (1, 1); + if (audio_channel[2].evtime == 0) + audio_handler (2, 1); + if (audio_channel[3].evtime == 0) + audio_handler (3, 1); + } + last_cycles = get_cycles () - n_cycles; +} + +void audio_evhandler (void) +{ + update_audio (); + schedule_audio (); +} + +#ifdef CPUEMU_6 +extern uae_u8 cycle_line[]; +#endif +uae_u16 dmacon; + +void audio_hsync (int dmaaction) +{ + int nr, handle; + + if (currprefs.produce_sound == 0) + return; + + update_audio (); + handle = 0; + /* Sound data is fetched at the beginning of each line */ + for (nr = 0; nr < 4; nr++) { + struct audio_channel_data *cdp = audio_channel + nr; + int chan_ena = (dmacon & DMA_MASTER) && (dmacon & (1 << nr)); + int handle2 = 0; + + if (dmaaction && cdp->request_word > 0) { + + if (cdp->request_word_skip) { + cdp->request_word_skip = 0; + continue; + } + + if (cdp->state == 5) { + cdp->pt = cdp->lc; +#ifdef DEBUG_AUDIO + if (debugchannel (nr)) + write_log ("%d:>5: LEN=%d PT=%08.8X\n", nr, cdp->wlen, cdp->pt); +#endif + } + cdp->dat2 = chipmem_wget (cdp->pt); + if (cdp->request_word >= 2) + handle2 = 1; + if (chan_ena) { +#ifdef CPUEMU_6 + cycle_line[13 + nr * 2] |= CYCLE_AUDIO; +#endif + if (cdp->request_word == 1 || cdp->request_word == 2) + cdp->pt += 2; + } + cdp->request_word = -1; + + } + + if (cdp->dmaen != chan_ena) { +#ifdef DEBUG_AUDIO + if (debugchannel (nr)) + write_log ("AUD%dDMA %d->%d (%d) LEN=%d/%d %08.8X\n", nr, cdp->dmaen, chan_ena, + cdp->state, cdp->wlen, cdp->len, m68k_getpc()); +#endif + cdp->dmaen = chan_ena; + if (cdp->dmaen) + handle2 = 1; + } + if (handle2) + audio_handler (nr, 0); + handle |= handle2; + } + if (handle) { + schedule_audio (); + events_schedule (); + } +} + +void AUDxDAT (int nr, uae_u16 v) +{ + struct audio_channel_data *cdp = audio_channel + nr; + +#ifdef DEBUG_AUDIO + if (debugchannel (nr)) + write_log ("AUD%dDAT: %04.4X STATE=%d IRQ=%d %p\n", nr, + v, cdp->state, isirq(nr) ? 1 : 0, m68k_getpc()); +#endif + update_audio (); + cdp->dat2 = v; + cdp->request_word = -1; + cdp->request_word_skip = 0; + if (cdp->state == 0) { + cdp->state = 2; + audio_handler (nr, 0); + schedule_audio (); + events_schedule (); + } + } + +void AUDxLCH (int nr, uae_u16 v) +{ + update_audio (); + audio_channel[nr].lc = (audio_channel[nr].lc & 0xffff) | ((uae_u32)v << 16); +#ifdef DEBUG_AUDIO + if (debugchannel (nr)) + write_log ("AUD%dLCH: %04.4X %p\n", nr, v, m68k_getpc()); +#endif +} + +void AUDxLCL (int nr, uae_u16 v) +{ + update_audio (); + audio_channel[nr].lc = (audio_channel[nr].lc & ~0xffff) | (v & 0xFFFE); +#ifdef DEBUG_AUDIO + if (debugchannel (nr)) + write_log ("AUD%dLCL: %04.4X %p\n", nr, v, m68k_getpc()); +#endif +} + +void AUDxPER (int nr, uae_u16 v) +{ + unsigned long per = v * CYCLE_UNIT; + update_audio (); + + if (per == 0) + per = PERIOD_MAX - 1; + + if (per < maxhpos * CYCLE_UNIT / 2 && currprefs.produce_sound < 3) + per = maxhpos * CYCLE_UNIT / 2; + + if (audio_channel[nr].per == PERIOD_MAX - 1 && per != PERIOD_MAX - 1) { + audio_channel[nr].evtime = CYCLE_UNIT; + if (currprefs.produce_sound > 0) { + schedule_audio (); + events_schedule (); + } + } + + audio_channel[nr].per = per; +#ifdef DEBUG_AUDIO + if (debugchannel (nr)) + write_log ("AUD%dPER: %d %p\n", nr, v, m68k_getpc()); +#endif +} + +void AUDxLEN (int nr, uae_u16 v) +{ + update_audio (); + audio_channel[nr].len = v; +#ifdef DEBUG_AUDIO + if (debugchannel (nr)) + write_log ("AUD%dLEN: %d %p\n", nr, v, m68k_getpc()); +#endif +} + +void AUDxVOL (int nr, uae_u16 v) +{ + int v2 = v & 64 ? 63 : v & 63; + update_audio (); + audio_channel[nr].vol = v2; +#ifndef MULTIPLICATION_PROFITABLE + audio_channel[nr].voltbl = sound_table[v2]; +#endif +#ifdef DEBUG_AUDIO + if (debugchannel (nr)) + write_log ("AUD%dVOL: %d %p\n", nr, v2, m68k_getpc()); +#endif +} + +void update_adkmasks (void) +{ + unsigned long t = adkcon | (adkcon >> 4); + audio_channel[0].adk_mask = (((t >> 0) & 1) - 1); + audio_channel[1].adk_mask = (((t >> 1) & 1) - 1); + audio_channel[2].adk_mask = (((t >> 2) & 1) - 1); + audio_channel[3].adk_mask = (((t >> 3) & 1) - 1); +} + +int init_audio (void) +{ + return init_sound (); +} + +uae_u8 *restore_audio (int i, uae_u8 *src) +{ + struct audio_channel_data *acd; + uae_u16 p; + + acd = audio_channel + i; + acd->state = restore_u8 (); + acd->vol = restore_u8 (); + acd->intreq2 = restore_u8 (); + acd->request_word = restore_u8 (); + acd->len = restore_u16 (); + acd->wlen = restore_u16 (); + p = restore_u16 (); + acd->per = p ? p * CYCLE_UNIT : PERIOD_MAX; + p = restore_u16 (); + acd->lc = restore_u32 (); + acd->pt = restore_u32 (); + acd->evtime = restore_u32 (); + return src; +} + + +uae_u8 *save_audio (int i, int *len, uae_u8 *dstptr) +{ + struct audio_channel_data *acd; + uae_u8 *dst, *dstbak; + uae_u16 p; + + if (dstptr) + dstbak = dst = dstptr; + else + dstbak = dst = malloc (100); + acd = audio_channel + i; + save_u8 ((uae_u8)acd->state); + save_u8 (acd->vol); + save_u8 (acd->intreq2); + save_u8 (acd->request_word); + save_u16 (acd->len); + save_u16 (acd->wlen); + p = acd->per == PERIOD_MAX ? 0 : acd->per / CYCLE_UNIT; + save_u16 (p); + save_u16 (acd->dat2); + save_u32 (acd->lc); + save_u32 (acd->pt); + save_u32 (acd->evtime); + *len = dst - dstbak; + return dstbak; +} diff --git a/autoconf.c b/autoconf.c new file mode 100755 index 00000000..9ec9e294 --- /dev/null +++ b/autoconf.c @@ -0,0 +1,535 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * AutoConfig devices + * + * Copyright 1995, 1996 Bernd Schmidt + * Copyright 1996 Ed Hanway + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "uae.h" +#include "memory.h" +#include "custom.h" +#include "events.h" +#include "newcpu.h" +#include "compiler.h" +#include "autoconf.h" +#include "osdep/exectasks.h" + +/* We'll need a lot of these. */ +#define MAX_TRAPS 4096 +static TrapFunction traps[MAX_TRAPS]; +static int trapmode[MAX_TRAPS]; +static const char *trapstr[MAX_TRAPS]; +static uaecptr trapoldfunc[MAX_TRAPS]; + +static int max_trap; +int lasttrap; + +/* Stack management */ + +/* The mechanism for doing m68k calls from native code is as follows: + * + * m68k code executes, stack is main + * calltrap to execute_fn_on_extra_stack. new stack is allocated + * do_stack_magic is called for the first time + * current context is saved with setjmp [0] + * transfer_control is done + * native code executes on new stack + * native code calls call_m68k + * setjmp saves current context [1] + * longjmp back to execute_fn_on_extra_stack [0] + * pointer to new stack is saved on m68k stack. m68k return address set + * to RTAREA_BASE + 0xFF00. m68k PC set to called function + * m68k function executes, stack is main + * m68k function returns to RTAREA_BASE + 0xFF00 + * calltrap to m68k_mode_return + * do_stack_magic is called again + * current context is saved again with setjmp [0] + * this time, transfer_control is _not_ done, instead a longjmp[1] + * to the previously saved context + * native code executes again on temp stack + * native function returns to stack_stub + * longjmp[0] back to old context + * back again! + * + * A bearded man enters the room, carrying a bowl of spaghetti. + */ + +/* This _shouldn't_ crash with a stack size of 4096, but it does... + * might be a bug */ +#ifndef EXTRA_STACK_SIZE +#define EXTRA_STACK_SIZE 32768 +#endif + +static void *extra_stack_list = NULL; + +static void *get_extra_stack (void) +{ + void *s = extra_stack_list; + //if (s) + //extra_stack_list = *(void **)s; + if (!s) { +#ifndef _MSC_VER + s = xmalloc (EXTRA_STACK_SIZE); +#else + { + static long opencount=0; + extern unsigned long *win32_stackbase; + int i; + extern unsigned long *win32_freestack[42]; + for (i=0;i<41;i++) {//0 to MAX_SELECT_THREADS + if(!win32_freestack[i]) + break; //get a free block + } + s=win32_stackbase+(i*EXTRA_STACK_SIZE); + win32_freestack[i]=s; + } +#endif + } + return s; +} + +static void free_extra_stack (void *s) +{ + //*(void **)s = extra_stack_list; + //extra_stack_list = s; + { + int i; + extern unsigned long *win32_freestack[42]; + for (i=0;i<41;i++) {//0 to MAX_SELECT_THREADS + if(win32_freestack[i]==s) + break; //get a free block + } + win32_freestack[i]=0; + } +} + +static void stack_stub (void *s, TrapFunction f, uae_u32 *retval) +{ +#ifdef CAN_DO_STACK_MAGIC + /*printf("in stack_stub: %p %p %p %x\n", s, f, retval, (int)*retval);*/ + *retval = f (); + /*write_log ("returning from stack_stub\n");*/ + longjmp (((jmp_buf *)s)[0], 1); +#endif +} + +static void *current_extra_stack = NULL; +static uaecptr m68k_calladdr; + +static void do_stack_magic (TrapFunction f, void *s, int has_retval) +{ +#ifdef CAN_DO_STACK_MAGIC + uaecptr a7; + jmp_buf *j = (jmp_buf *)s; + switch (setjmp (j[0])) { + case 0: + /* Returning directly */ + current_extra_stack = s; + if (has_retval == -1) { + /*write_log ("finishing m68k mode return\n");*/ + longjmp (j[1], 1); + } + /*write_log ("calling native function\n");*/ + transfer_control (s, EXTRA_STACK_SIZE, stack_stub, f, has_retval); + /* not reached */ + abort (); + + case 1: + /*write_log ("native function complete\n");*/ + /* Returning normally. */ + if (stack_has_retval (s, EXTRA_STACK_SIZE)) + m68k_dreg (regs, 0) = get_retval_from_stack (s, EXTRA_STACK_SIZE); + free_extra_stack (s); + break; + + case 2: + /* Returning to do a m68k call. We're now back on the main stack. */ + a7 = m68k_areg(regs, 7) -= (sizeof (void *) + 7) & ~3; + /* Save stack to restore */ + *((void **)get_real_address (a7 + 4)) = s; + /* Save special return address: this address contains a + * calltrap that will longjmp to the right stack. */ + put_long (m68k_areg (regs, 7), RTAREA_BASE + 0xFF00); + m68k_setpc (m68k_calladdr); + fill_prefetch_slow (); + /*write_log ("native function calls m68k\n");*/ + break; + } + current_extra_stack = 0; +#endif +} + +static uae_u32 execute_fn_on_extra_stack (TrapFunction f, int has_retval) +{ +#ifdef CAN_DO_STACK_MAGIC + void *s = get_extra_stack (); + do_stack_magic (f, s, has_retval); +#endif + return 0; +} + +static uae_u32 m68k_mode_return (void) +{ +#ifdef CAN_DO_STACK_MAGIC + uaecptr a7 = m68k_areg(regs, 7); + void *s = *(void **)get_real_address(a7); + m68k_areg(regs, 7) += (sizeof (void *) + 3) & ~3; + /*write_log ("doing m68k mode return\n");*/ + do_stack_magic (NULL, s, -1); +#endif + return 0; +} + +static uae_u32 call_m68k (uaecptr addr, int saveregs) +{ + volatile uae_u32 retval = 0; + volatile int do_save = saveregs; + if (current_extra_stack == NULL) + abort(); +#ifdef CAN_DO_STACK_MAGIC + { + volatile struct regstruct saved_regs; + jmp_buf *j = (jmp_buf *)current_extra_stack; + + if (do_save) + saved_regs = regs; + m68k_calladdr = addr; + switch (setjmp(j[1])) { + case 0: + /*write_log ("doing call\n");*/ + /* Returning directly: now switch to main stack and do the call */ + longjmp (j[0], 2); + case 1: + /*write_log ("returning from call\n");*/ + retval = m68k_dreg (regs, 0); + if (do_save) + regs = saved_regs; + /* Returning after the call. */ + break; + } + } +#endif + return retval; +} + +uae_u32 CallLib (uaecptr base, uae_s16 offset) +{ + int i; + uaecptr olda6 = m68k_areg(regs, 6); + uae_u32 retval; +#if 0 + for (i = 0; i < n_libpatches; i++) { + if (libpatches[i].libbase == base && libpatches[i].functions[-offset/6] != NULL) + return (*libpatches[i].functions[-offset/6])(); + } +#endif + m68k_areg(regs, 6) = base; + retval = call_m68k(base + offset, 1); + m68k_areg(regs, 6) = olda6; + return retval; +} + +/* Commonly used autoconfig strings */ + +uaecptr EXPANSION_explibname, EXPANSION_doslibname, EXPANSION_uaeversion; +uaecptr EXPANSION_uaedevname, EXPANSION_explibbase = 0, EXPANSION_haveV36; +uaecptr EXPANSION_bootcode, EXPANSION_nullfunc; +uaecptr EXPANSION_cddevice; + +/* ROM tag area memory access */ + +uae_u8 *rtarea; + +static uae_u32 rtarea_lget (uaecptr) REGPARAM; +static uae_u32 rtarea_wget (uaecptr) REGPARAM; +static uae_u32 rtarea_bget (uaecptr) REGPARAM; +static void rtarea_lput (uaecptr, uae_u32) REGPARAM; +static void rtarea_wput (uaecptr, uae_u32) REGPARAM; +static void rtarea_bput (uaecptr, uae_u32) REGPARAM; +static uae_u8 *rtarea_xlate (uaecptr) REGPARAM; + +addrbank rtarea_bank = { + rtarea_lget, rtarea_wget, rtarea_bget, + rtarea_lput, rtarea_wput, rtarea_bput, + rtarea_xlate, default_check, NULL +}; + +uae_u8 REGPARAM2 *rtarea_xlate (uaecptr addr) +{ + addr &= 0xFFFF; + return rtarea + addr; +} + +uae_u32 REGPARAM2 rtarea_lget (uaecptr addr) +{ + special_mem |= S_READ; + addr &= 0xFFFF; + return (uae_u32)(rtarea_wget (addr) << 16) + rtarea_wget (addr+2); +} + +uae_u32 REGPARAM2 rtarea_wget (uaecptr addr) +{ + special_mem |= S_READ; + addr &= 0xFFFF; + return (rtarea[addr]<<8) + rtarea[addr+1]; +} + +uae_u32 REGPARAM2 rtarea_bget (uaecptr addr) +{ + special_mem |= S_READ; + addr &= 0xFFFF; + return rtarea[addr]; +} + +void REGPARAM2 rtarea_lput (uaecptr addr, uae_u32 value) +{ + special_mem |= S_WRITE; +} + +void REGPARAM2 rtarea_wput (uaecptr addr, uae_u32 value) +{ + special_mem |= S_WRITE; +} + +void REGPARAM2 rtarea_bput (uaecptr addr, uae_u32 value) +{ + special_mem |= S_WRITE; +} + +static const int trace_traps = 1; + +void REGPARAM2 call_calltrap(int func) +{ + uae_u32 retval = 0; + int has_retval = (trapmode[func] & TRAPFLAG_NO_RETVAL) == 0; + int implicit_rts = (trapmode[func] & TRAPFLAG_DORET) != 0; + + if (trapstr[func] && *trapstr[func] != 0 && trace_traps) + write_log ("TRAP: %s\n", trapstr[func]); + + /* For monitoring only? */ + if (traps[func] == NULL) { + m68k_setpc(trapoldfunc[func]); + fill_prefetch_slow (); + return; + } + + if (func < max_trap) { + if (trapmode[func] & TRAPFLAG_EXTRA_STACK) { + execute_fn_on_extra_stack(traps[func], has_retval); + return; + } + retval = (*traps[func])(); + } else + write_log ("illegal emulator trap\n"); + + if (has_retval) + m68k_dreg(regs, 0) = retval; + if (implicit_rts) { + m68k_do_rts (); + fill_prefetch_slow (); + } +} + +/* @$%&§ compiler bugs */ +static volatile int four = 4; + +uaecptr libemu_InstallFunctionFlags (TrapFunction f, uaecptr libbase, int offset, + int flags, const char *tracename) +{ + int i; + uaecptr retval; + uaecptr execbase = get_long (four); + int trnum; + uaecptr addr = here(); + calltrap (trnum = deftrap2 (f, flags, tracename)); + dw (RTS); + + m68k_areg(regs, 1) = libbase; + m68k_areg(regs, 0) = offset; + m68k_dreg(regs, 0) = addr; + retval = CallLib (execbase, -420); + + trapoldfunc[trnum] = retval; +#if 0 + for (i = 0; i < n_libpatches; i++) { + if (libpatches[i].libbase == libbase) + break; + } + if (i == n_libpatches) { + int j; + libpatches[i].libbase = libbase; + for (j = 0; j < 300; j++) + libpatches[i].functions[j] = NULL; + n_libpatches++; + } + libpatches[i].functions[-offset/6] = f; +#endif + return retval; +} + +/* some quick & dirty code to fill in the rt area and save me a lot of + * scratch paper + */ + +static int rt_addr; +static int rt_straddr; + +uae_u32 addr (int ptr) +{ + return (uae_u32)ptr + RTAREA_BASE; +} + +void db (uae_u8 data) +{ + rtarea[rt_addr++] = data; +} + +void dw (uae_u16 data) +{ + rtarea[rt_addr++] = (uae_u8)(data >> 8); + rtarea[rt_addr++] = (uae_u8)data; +} + +void dl (uae_u32 data) +{ + rtarea[rt_addr++] = data >> 24; + rtarea[rt_addr++] = data >> 16; + rtarea[rt_addr++] = data >> 8; + rtarea[rt_addr++] = data; +} + +/* store strings starting at the end of the rt area and working + * backward. store pointer at current address + */ + +uae_u32 ds (char *str) +{ + int len = strlen (str) + 1; + + rt_straddr -= len; + strcpy ((char *)rtarea + rt_straddr, str); + + return addr (rt_straddr); +} + +void calltrap (uae_u32 n) +{ + dw (0xA000 + n); +} + +void org (uae_u32 a) +{ + rt_addr = a - RTAREA_BASE; +} + +uae_u32 here (void) +{ + return addr (rt_addr); +} + +int deftrap2 (TrapFunction func, int mode, const char *str) +{ + int num = max_trap++; + traps[num] = func; + trapstr[num] = str; + trapmode[num] = mode; + return num; +} + +int deftrap (TrapFunction func) +{ + return deftrap2 (func, 0, ""); +} + +void align (int b) +{ + rt_addr = (rt_addr + b - 1) & ~(b - 1); +} + +static uae_u32 nullfunc(void) +{ + write_log ("Null function called\n"); + return 0; +} + +static uae_u32 getchipmemsize (void) +{ + return allocated_chipmem; +} + +static uae_u32 uae_puts (void) +{ + puts (get_real_address (m68k_areg (regs, 0))); + return 0; +} + +static void rtarea_init_mem (void) +{ + rtarea = mapped_malloc (0x10000, "rtarea"); + if (!rtarea) { + write_log ("virtual memory exhausted (rtarea)!\n"); + abort (); + } + rtarea_bank.baseaddr = rtarea; +} + +void rtarea_init (void) +{ + uae_u32 a; + char uaever[100]; + + rt_straddr = 0xFF00 - 2; + rt_addr = 0; + max_trap = 0; + + rtarea_init_mem (); + + sprintf (uaever, "uae-%d.%d.%d", UAEMAJOR, UAEMINOR, UAESUBREV); + + EXPANSION_uaeversion = ds (uaever); + EXPANSION_explibname = ds ("expansion.library"); + EXPANSION_doslibname = ds ("dos.library"); + EXPANSION_uaedevname = ds ("uae.device"); + + deftrap (NULL); /* Generic emulator trap */ + lasttrap = 0; + + EXPANSION_nullfunc = here (); + calltrap (deftrap (nullfunc)); + dw (RTS); + + a = here(); + /* Standard "return from 68k mode" trap */ + org (RTAREA_BASE + 0xFF00); + calltrap (deftrap2 (m68k_mode_return, TRAPFLAG_NO_RETVAL, "")); + + org (RTAREA_BASE + 0xFF80); + calltrap (deftrap2 (getchipmemsize, TRAPFLAG_DORET, "")); + + org (RTAREA_BASE + 0xFF10); + calltrap (deftrap2 (uae_puts, TRAPFLAG_NO_RETVAL, "")); + dw (RTS); + + org (a); + + filesys_install_code (); +} + +volatile int uae_int_requested = 0; + +void set_uae_int_flag (void) +{ + rtarea[0xFFFB] = uae_int_requested; +} + +void rtarea_setup(void) +{ +} diff --git a/blitops.c b/blitops.c new file mode 100755 index 00000000..eb2142db --- /dev/null +++ b/blitops.c @@ -0,0 +1,262 @@ + /* This file generated automatically - do not edit */ + +#include "genblitter.h" + +struct blitop blitops[256] = { + /* 00 */ { "0", 0 }, + /* 01 */ { "~(srca | srcb | srcc)", 7 }, + /* 02 */ { "(srcc & ~(srca | srcb))", 7 }, + /* 03 */ { "~(srca | srcb)", 3 }, + /* 04 */ { "(srcb & ~(srca | srcc))", 7 }, + /* 05 */ { "~(srca | srcc)", 5 }, + /* 06 */ { "(~srca & (srcb ^ srcc))", 7 }, + /* 07 */ { "~(srca | (srcb & srcc))", 7 }, + /* 08 */ { "(~srca & srcb & srcc)", 7 }, + /* 09 */ { "~(srca | (srcb ^ srcc))", 7 }, + /* 0a */ { "(~srca & srcc)", 5 }, + /* 0b */ { "~(srca | (srcb & ~srcc))", 7 }, + /* 0c */ { "(~srca & srcb)", 3 }, + /* 0d */ { "~(srca | (~srcb & srcc))", 7 }, + /* 0e */ { "(~srca & (srcb | srcc))", 7 }, + /* 0f */ { "~srca", 1 }, + /* 10 */ { "(srca & ~(srcb | srcc))", 7 }, + /* 11 */ { "~(srcb | srcc)", 6 }, + /* 12 */ { "(~srcb & (srca ^ srcc))", 7 }, + /* 13 */ { "~(srcb | (srca & srcc))", 7 }, + /* 14 */ { "(~srcc & (srca ^ srcb))", 7 }, + /* 15 */ { "~(srcc | (srca & srcb))", 7 }, + /* 16 */ { "(srca ^ ((srca & srcb) | (srcb ^ srcc)))", 7 }, + /* 17 */ { "~(srca ^ ((srca ^ srcb) & (srca ^ srcc)))", 7 }, + /* 18 */ { "((srca ^ srcb) & (srca ^ srcc))", 7 }, + /* 19 */ { "(srcb ^ (~srcc | (srca & srcb)))", 7 }, + /* 1a */ { "(srca ^ (srcc | (srca & srcb)))", 7 }, + /* 1b */ { "(srca ^ (srcc | ~(srca ^ srcb)))", 7 }, + /* 1c */ { "(srca ^ (srcb | (srca & srcc)))", 7 }, + /* 1d */ { "(srca ^ (srcb | ~(srca ^ srcc)))", 7 }, + /* 1e */ { "(srca ^ (srcb | srcc))", 7 }, + /* 1f */ { "~(srca & (srcb | srcc))", 7 }, + /* 20 */ { "(srca & ~srcb & srcc)", 7 }, + /* 21 */ { "~(srcb | (srca ^ srcc))", 7 }, + /* 22 */ { "(~srcb & srcc)", 6 }, + /* 23 */ { "~(srcb | (srca & ~srcc))", 7 }, + /* 24 */ { "((srca ^ srcb) & (srcb ^ srcc))", 7 }, + /* 25 */ { "(srca ^ (~srcc | (srca & srcb)))", 7 }, + /* 26 */ { "(srcb ^ (srcc | (srca & srcb)))", 7 }, + /* 27 */ { "~(srca ^ (srcc & (srca ^ srcb)))", 7 }, + /* 28 */ { "(srcc & (srca ^ srcb))", 7 }, + /* 29 */ { "~(srca ^ srcb ^ (srcc | (srca & srcb)))", 7 }, + /* 2a */ { "(srcc & ~(srca & srcb))", 7 }, + /* 2b */ { "~(srca ^ ((srca ^ srcb) & (srcb ^ srcc)))", 7 }, + /* 2c */ { "(srcb ^ (srca & (srcb | srcc)))", 7 }, + /* 2d */ { "(srca ^ (srcb | ~srcc))", 7 }, + /* 2e */ { "(srca ^ (srcb | (srca ^ srcc)))", 7 }, + /* 2f */ { "~(srca & (srcb | ~srcc))", 7 }, + /* 30 */ { "(srca & ~srcb)", 3 }, + /* 31 */ { "~(srcb | (~srca & srcc))", 7 }, + /* 32 */ { "(~srcb & (srca | srcc))", 7 }, + /* 33 */ { "~srcb", 2 }, + /* 34 */ { "(srcb ^ (srca | (srcb & srcc)))", 7 }, + /* 35 */ { "(srcb ^ (srca | ~(srcb ^ srcc)))", 7 }, + /* 36 */ { "(srcb ^ (srca | srcc))", 7 }, + /* 37 */ { "~(srcb & (srca | srcc))", 7 }, + /* 38 */ { "(srca ^ (srcb & (srca | srcc)))", 7 }, + /* 39 */ { "(srcb ^ (srca | ~srcc))", 7 }, + /* 3a */ { "(srcb ^ (srca | (srcb ^ srcc)))", 7 }, + /* 3b */ { "~(srcb & (srca | ~srcc))", 7 }, + /* 3c */ { "(srca ^ srcb)", 3 }, + /* 3d */ { "(srca ^ (srcb | ~(srca | srcc)))", 7 }, + /* 3e */ { "(srca ^ (srcb | (srca ^ (srca | srcc))))", 7 }, + /* 3f */ { "~(srca & srcb)", 3 }, + /* 40 */ { "(srca & srcb & ~srcc)", 7 }, + /* 41 */ { "~(srcc | (srca ^ srcb))", 7 }, + /* 42 */ { "((srca ^ srcc) & (srcb ^ srcc))", 7 }, + /* 43 */ { "(srca ^ (~srcb | (srca & srcc)))", 7 }, + /* 44 */ { "(srcb & ~srcc)", 6 }, + /* 45 */ { "~(srcc | (srca & ~srcb))", 7 }, + /* 46 */ { "(srcc ^ (srcb | (srca & srcc)))", 7 }, + /* 47 */ { "~(srca ^ (srcb & (srca ^ srcc)))", 7 }, + /* 48 */ { "(srcb & (srca ^ srcc))", 7 }, + /* 49 */ { "~(srca ^ srcc ^ (srcb | (srca & srcc)))", 7 }, + /* 4a */ { "(srcc ^ (srca & (srcb | srcc)))", 7 }, + /* 4b */ { "(srca ^ (~srcb | srcc))", 7 }, + /* 4c */ { "(srcb & ~(srca & srcc))", 7 }, + /* 4d */ { "(srca ^ ((srca ^ srcb) | ~(srca ^ srcc)))", 7 }, + /* 4e */ { "(srca ^ (srcc | (srca ^ srcb)))", 7 }, + /* 4f */ { "~(srca & (~srcb | srcc))", 7 }, + /* 50 */ { "(srca & ~srcc)", 5 }, + /* 51 */ { "~(srcc | (~srca & srcb))", 7 }, + /* 52 */ { "(srcc ^ (srca | (srcb & srcc)))", 7 }, + /* 53 */ { "~(srcb ^ (srca & (srcb ^ srcc)))", 7 }, + /* 54 */ { "(~srcc & (srca | srcb))", 7 }, + /* 55 */ { "~srcc", 4 }, + /* 56 */ { "(srcc ^ (srca | srcb))", 7 }, + /* 57 */ { "~(srcc & (srca | srcb))", 7 }, + /* 58 */ { "(srca ^ (srcc & (srca | srcb)))", 7 }, + /* 59 */ { "(srcc ^ (srca | ~srcb))", 7 }, + /* 5a */ { "(srca ^ srcc)", 5 }, + /* 5b */ { "(srca ^ (srcc | ~(srca | srcb)))", 7 }, + /* 5c */ { "(srcc ^ (srca | (srcb ^ srcc)))", 7 }, + /* 5d */ { "~(srcc & (srca | ~srcb))", 7 }, + /* 5e */ { "(srca ^ (srcc | (srca ^ (srca | srcb))))", 7 }, + /* 5f */ { "~(srca & srcc)", 5 }, + /* 60 */ { "(srca & (srcb ^ srcc))", 7 }, + /* 61 */ { "~(srcb ^ srcc ^ (srca | (srcb & srcc)))", 7 }, + /* 62 */ { "(srcc ^ (srcb & (srca | srcc)))", 7 }, + /* 63 */ { "(srcb ^ (~srca | srcc))", 7 }, + /* 64 */ { "(srcb ^ (srcc & (srca | srcb)))", 7 }, + /* 65 */ { "(srcc ^ (~srca | srcb))", 7 }, + /* 66 */ { "(srcb ^ srcc)", 6 }, + /* 67 */ { "(srcb ^ (srcc | ~(srca | srcb)))", 7 }, + /* 68 */ { "((srca & srcb) ^ (srcc & (srca | srcb)))", 7 }, + /* 69 */ { "~(srca ^ srcb ^ srcc)", 7 }, + /* 6a */ { "(srcc ^ (srca & srcb))", 7 }, + /* 6b */ { "~(srca ^ srcb ^ (srcc & (srca | srcb)))", 7 }, + /* 6c */ { "(srcb ^ (srca & srcc))", 7 }, + /* 6d */ { "~(srca ^ srcc ^ (srcb & (srca | srcc)))", 7 }, + /* 6e */ { "((~srca & srcb) | (srcb ^ srcc))", 7 }, + /* 6f */ { "(~srca | (srcb ^ srcc))", 7 }, + /* 70 */ { "(srca & ~(srcb & srcc))", 7 }, + /* 71 */ { "~(srca ^ ((srca ^ srcb) | (srca ^ srcc)))", 7 }, + /* 72 */ { "(srcb ^ (srcc | (srca ^ srcb)))", 7 }, + /* 73 */ { "~(srcb & (~srca | srcc))", 7 }, + /* 74 */ { "(srcc ^ (srcb | (srca ^ srcc)))", 7 }, + /* 75 */ { "~(srcc & (~srca | srcb))", 7 }, + /* 76 */ { "(srcb ^ (srcc | (srca ^ (srca & srcb))))", 7 }, + /* 77 */ { "~(srcb & srcc)", 6 }, + /* 78 */ { "(srca ^ (srcb & srcc))", 7 }, + /* 79 */ { "~(srcb ^ srcc ^ (srca & (srcb | srcc)))", 7 }, + /* 7a */ { "((srca & ~srcb) | (srca ^ srcc))", 7 }, + /* 7b */ { "(~srcb | (srca ^ srcc))", 7 }, + /* 7c */ { "((srca ^ srcb) | (srca & ~srcc))", 7 }, + /* 7d */ { "(~srcc | (srca ^ srcb))", 7 }, + /* 7e */ { "((srca ^ srcb) | (srca ^ srcc))", 7 }, + /* 7f */ { "~(srca & srcb & srcc)", 7 }, + /* 80 */ { "(srca & srcb & srcc)", 7 }, + /* 81 */ { "~((srca ^ srcb) | (srca ^ srcc))", 7 }, + /* 82 */ { "(srcc & ~(srca ^ srcb))", 7 }, + /* 83 */ { "(srca ^ (~srcb | (srca & ~srcc)))", 7 }, + /* 84 */ { "(srcb & ~(srca ^ srcc))", 7 }, + /* 85 */ { "(srca ^ (~srcc | (srca & ~srcb)))", 7 }, + /* 86 */ { "(srcb ^ srcc ^ (srca & (srcb | srcc)))", 7 }, + /* 87 */ { "~(srca ^ (srcb & srcc))", 7 }, + /* 88 */ { "(srcb & srcc)", 6 }, + /* 89 */ { "(srcb ^ (~srcc & (~srca | srcb)))", 7 }, + /* 8a */ { "(srcc & (~srca | srcb))", 7 }, + /* 8b */ { "(srca ^ (~srcb | (srca ^ srcc)))", 7 }, + /* 8c */ { "(srcb & (~srca | srcc))", 7 }, + /* 8d */ { "(srca ^ (~srcc | (srca ^ srcb)))", 7 }, + /* 8e */ { "(srca ^ ((srca ^ srcb) | (srca ^ srcc)))", 7 }, + /* 8f */ { "(~srca | (srcb & srcc))", 7 }, + /* 90 */ { "(srca & ~(srcb ^ srcc))", 7 }, + /* 91 */ { "(srcb ^ (~srcc | (~srca & srcb)))", 7 }, + /* 92 */ { "(srca ^ srcc ^ (srcb & (srca | srcc)))", 7 }, + /* 93 */ { "~(srcb ^ (srca & srcc))", 7 }, + /* 94 */ { "(srca ^ srcb ^ (srcc & (srca | srcb)))", 7 }, + /* 95 */ { "~(srcc ^ (srca & srcb))", 7 }, + /* 96 */ { "(srca ^ srcb ^ srcc)", 7 }, + /* 97 */ { "(srca ^ srcb ^ (srcc | ~(srca | srcb)))", 7 }, + /* 98 */ { "(srcb ^ (~srcc & (srca | srcb)))", 7 }, + /* 99 */ { "~(srcb ^ srcc)", 6 }, + /* 9a */ { "(srcc ^ (srca & ~srcb))", 7 }, + /* 9b */ { "~(srcb ^ (srcc & (srca | srcb)))", 7 }, + /* 9c */ { "(srcb ^ (srca & ~srcc))", 7 }, + /* 9d */ { "~(srcc ^ (srcb & (srca | srcc)))", 7 }, + /* 9e */ { "(srcb ^ srcc ^ (srca | (srcb & srcc)))", 7 }, + /* 9f */ { "~(srca & (srcb ^ srcc))", 7 }, + /* a0 */ { "(srca & srcc)", 5 }, + /* a1 */ { "(srca ^ (~srcc & (srca | ~srcb)))", 7 }, + /* a2 */ { "(srcc & (srca | ~srcb))", 7 }, + /* a3 */ { "(srcb ^ (~srca | (srcb ^ srcc)))", 7 }, + /* a4 */ { "(srca ^ (~srcc & (srca | srcb)))", 7 }, + /* a5 */ { "~(srca ^ srcc)", 5 }, + /* a6 */ { "(srcc ^ (~srca & srcb))", 7 }, + /* a7 */ { "~(srca ^ (srcc & (srca | srcb)))", 7 }, + /* a8 */ { "(srcc & (srca | srcb))", 7 }, + /* a9 */ { "~(srcc ^ (srca | srcb))", 7 }, + /* aa */ { "srcc", 4 }, + /* ab */ { "(srcc | ~(srca | srcb))", 7 }, + /* ac */ { "(srcb ^ (srca & (srcb ^ srcc)))", 7 }, + /* ad */ { "~(srcc ^ (srca | (srcb & srcc)))", 7 }, + /* ae */ { "(srcc | (~srca & srcb))", 7 }, + /* af */ { "(~srca | srcc)", 5 }, + /* b0 */ { "(srca & (~srcb | srcc))", 7 }, + /* b1 */ { "~(srca ^ (srcc | (srca ^ srcb)))", 7 }, + /* b2 */ { "(srca ^ ((srca ^ srcc) & (srcb ^ srcc)))", 7 }, + /* b3 */ { "(~srcb | (srca & srcc))", 7 }, + /* b4 */ { "(srca ^ (srcb & ~srcc))", 7 }, + /* b5 */ { "~(srcc ^ (srca & (srcb | srcc)))", 7 }, + /* b6 */ { "(srca ^ srcc ^ (srcb | (srca & srcc)))", 7 }, + /* b7 */ { "~(srcb & (srca ^ srcc))", 7 }, + /* b8 */ { "(srca ^ (srcb & (srca ^ srcc)))", 7 }, + /* b9 */ { "~(srcc ^ (srcb | (srca & srcc)))", 7 }, + /* ba */ { "(srcc | (srca & ~srcb))", 7 }, + /* bb */ { "(~srcb | srcc)", 6 }, + /* bc */ { "((srca ^ srcb) | (srca & srcc))", 7 }, + /* bd */ { "((srca ^ srcb) | ~(srca ^ srcc))", 7 }, + /* be */ { "(srcc | (srca ^ srcb))", 7 }, + /* bf */ { "(srcc | ~(srca & srcb))", 7 }, + /* c0 */ { "(srca & srcb)", 3 }, + /* c1 */ { "(srca ^ (~srcb & (srca | ~srcc)))", 7 }, + /* c2 */ { "(srca ^ (~srcb & (srca | srcc)))", 7 }, + /* c3 */ { "~(srca ^ srcb)", 3 }, + /* c4 */ { "(srcb & (srca | ~srcc))", 7 }, + /* c5 */ { "~(srcb ^ (srca | (srcb ^ srcc)))", 7 }, + /* c6 */ { "(srcb ^ (~srca & srcc))", 7 }, + /* c7 */ { "~(srca ^ (srcb & (srca | srcc)))", 7 }, + /* c8 */ { "(srcb & (srca | srcc))", 7 }, + /* c9 */ { "~(srcb ^ (srca | srcc))", 7 }, + /* ca */ { "(srcc ^ (srca & (srcb ^ srcc)))", 7 }, + /* cb */ { "~(srcb ^ (srca | (srcb & srcc)))", 7 }, + /* cc */ { "srcb", 2 }, + /* cd */ { "(srcb | ~(srca | srcc))", 7 }, + /* ce */ { "(srcb | (~srca & srcc))", 7 }, + /* cf */ { "(~srca | srcb)", 3 }, + /* d0 */ { "(srca & (srcb | ~srcc))", 7 }, + /* d1 */ { "~(srca ^ (srcb | (srca ^ srcc)))", 7 }, + /* d2 */ { "(srca ^ (~srcb & srcc))", 7 }, + /* d3 */ { "~(srcb ^ (srca & (srcb | srcc)))", 7 }, + /* d4 */ { "(srca ^ ((srca ^ srcb) & (srcb ^ srcc)))", 7 }, + /* d5 */ { "(~srcc | (srca & srcb))", 7 }, + /* d6 */ { "(srca ^ srcb ^ (srcc | (srca & srcb)))", 7 }, + /* d7 */ { "~(srcc & (srca ^ srcb))", 7 }, + /* d8 */ { "(srca ^ (srcc & (srca ^ srcb)))", 7 }, + /* d9 */ { "~(srcb ^ (srcc | (srca & srcb)))", 7 }, + /* da */ { "((srca & srcb) | (srca ^ srcc))", 7 }, + /* db */ { "~((srca ^ srcb) & (srcb ^ srcc))", 7 }, + /* dc */ { "(srcb | (srca & ~srcc))", 7 }, + /* dd */ { "(srcb | ~srcc)", 6 }, + /* de */ { "(srcb | (srca ^ srcc))", 7 }, + /* df */ { "(srcb | ~(srca & srcc))", 7 }, + /* e0 */ { "(srca & (srcb | srcc))", 7 }, + /* e1 */ { "~(srca ^ (srcb | srcc))", 7 }, + /* e2 */ { "(srcc ^ (srcb & (srca ^ srcc)))", 7 }, + /* e3 */ { "~(srca ^ (srcb | (srca & srcc)))", 7 }, + /* e4 */ { "(srcb ^ (srcc & (srca ^ srcb)))", 7 }, + /* e5 */ { "~(srca ^ (srcc | (srca & srcb)))", 7 }, + /* e6 */ { "((srca & srcb) | (srcb ^ srcc))", 7 }, + /* e7 */ { "~((srca ^ srcb) & (srca ^ srcc))", 7 }, + /* e8 */ { "(srca ^ ((srca ^ srcb) & (srca ^ srcc)))", 7 }, + /* e9 */ { "(srca ^ srcb ^ (~srcc | (srca & srcb)))", 7 }, + /* ea */ { "(srcc | (srca & srcb))", 7 }, + /* eb */ { "(srcc | ~(srca ^ srcb))", 7 }, + /* ec */ { "(srcb | (srca & srcc))", 7 }, + /* ed */ { "(srcb | ~(srca ^ srcc))", 7 }, + /* ee */ { "(srcb | srcc)", 6 }, + /* ef */ { "(~srca | srcb | srcc)", 7 }, + /* f0 */ { "srca", 1 }, + /* f1 */ { "(srca | ~(srcb | srcc))", 7 }, + /* f2 */ { "(srca | (~srcb & srcc))", 7 }, + /* f3 */ { "(srca | ~srcb)", 3 }, + /* f4 */ { "(srca | (srcb & ~srcc))", 7 }, + /* f5 */ { "(srca | ~srcc)", 5 }, + /* f6 */ { "(srca | (srcb ^ srcc))", 7 }, + /* f7 */ { "(srca | ~(srcb & srcc))", 7 }, + /* f8 */ { "(srca | (srcb & srcc))", 7 }, + /* f9 */ { "(srca | ~(srcb ^ srcc))", 7 }, + /* fa */ { "(srca | srcc)", 5 }, + /* fb */ { "(srca | ~srcb | srcc)", 7 }, + /* fc */ { "(srca | srcb)", 3 }, + /* fd */ { "(srca | srcb | ~srcc)", 7 }, + /* fe */ { "(srca | srcb | srcc)", 7 }, + /* ff */ { "0xFFFFFFFF", 0 } +}; diff --git a/blitter.c b/blitter.c new file mode 100755 index 00000000..7bd8b957 --- /dev/null +++ b/blitter.c @@ -0,0 +1,1062 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Custom chip emulation + * + * (c) 1995 Bernd Schmidt, Alessandro Bissacco + * (c) 2002 - 2003 Toni Wilen + */ + +//#define BLITTER_DEBUG +//#define BLITTER_SLOWDOWNDEBUG 4 + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "uae.h" +#include "memory.h" +#include "custom.h" +#include "events.h" +#include "newcpu.h" +#include "blitter.h" +#include "blit.h" +#include "savestate.h" + +uae_u16 oldvblts; +uae_u16 bltcon0,bltcon1; +uae_u32 bltapt,bltbpt,bltcpt,bltdpt; + +int blinea_shift; +static uae_u16 blinea, blineb; +static uaecptr bltcnxlpt,bltdnxlpt; +static int blitline, blitfc, blitfill, blitife, blitsing, blitdesc; +static int blitonedot,blitsign; +static int blit_add; +static int blit_modadda, blit_modaddb, blit_modaddc, blit_modaddd; +static int blit_ch, blit_starting; +static unsigned int blit_starts; +int blit_singlechannel; + +#ifdef BLITTER_DEBUG +static int blitter_dontdo; +#endif +#ifdef BLITTER_SLOWDOWNDEBUG +static int blitter_slowdowndebug; +#endif + +struct bltinfo blt_info; + +static uae_u8 blit_filltable[256][4][2]; +uae_u32 blit_masktable[BLITTER_MAX_WORDS]; +static uae_u16 blit_trashtable[BLITTER_MAX_WORDS]; +enum blitter_states bltstate; + +static int blit_cyclecounter, blit_maxcyclecounter, blit_slowdown, blit_cycles_total; +static int blit_linecyclecounter, blit_misscyclecounter; + +#ifdef CPUEMU_6 +extern uae_u8 cycle_line[]; +#endif + +static long blit_firstline_cycles; +static long blit_first_cycle; +static int blit_last_cycle, blit_dmacount, blit_dmacount2; +static int blit_linecycles, blit_extracycles; +static uae_u8 *blit_diag; + +static uae_u16 ddat1, ddat2; +static int ddat1use, ddat2use; + +static uae_u8 blit_cycle_diagram_finald[] = + { 0, 2, 0,4 }; + +static uae_u8 blit_cycle_diagram[][10] = +{ + { 0, 2, 0,0 }, /* 0 */ + { 0, 2, 4,0 }, /* 1 */ + { 0, 2, 3,0 }, /* 2 */ + { 2, 3, 0,3,4, 3,0 }, /* 3 */ + { 0, 3, 2,0,0 }, /* 4 */ + { 2, 3, 0,2,4, 2,0 }, /* 5 */ + { 0, 3, 2,3,0 }, /* 6 */ + { 3, 4, 0,2,3,4, 2,3,0 }, /* 7 */ + { 0, 2, 1,0 }, /* 8 */ + { 2, 2, 1,4, 1,0 }, /* 9 */ + { 0, 2, 1,3 }, /* A */ + { 3, 3, 1,3,4, 1,3,0 }, /* B */ + { 2, 3, 0,1,2, 1,2 }, /* C */ + { 3, 3, 1,2,4, 1,2,0 }, /* D */ + { 0, 3, 1,2,3 }, /* E */ + { 4, 4, 1,2,3,4, 1,2,3,0 } /* F */ +}; + +/* fill mode always adds C-channel to cycle-diagram */ +/* Reflect - Sound Vision freezes without this */ +static uae_u8 blit_cycle_diagram_fill[][10] = +{ + { 0, 2, 0,0 }, /* 0 */ + { 0, 3, 0,3,4 }, /* 1 */ + { 0, 2, 3,0 }, /* 2 */ + { 2, 3, 0,3,4, 3,0 }, /* 3 */ + { 0, 3, 2,0,0 }, /* 4 */ + { 3, 4, 0,2,0,4, 2,0,0 }, /* 5 */ + { 0, 3, 2,3,0 }, /* 6 */ + { 3, 4, 0,2,3,4, 2,3,0 }, /* 7 */ + { 0, 2, 1,0 }, /* 8 */ + { 3, 3, 1,0,4, 1,0,0}, /* 9 */ + { 0, 2, 1,3 }, /* A */ + { 3, 3, 1,3,4, 1,3,0 }, /* B */ + { 2, 3, 0,1,2, 1,2 }, /* C */ + { 4, 4, 1,2,0,4, 1,2,0,0 }, /* D */ + { 0, 3, 1,2,3 }, /* E */ + { 4, 4, 1,2,3,4, 1,2,3,0 } /* F */ +}; + +static uae_u8 blit_cycle_diagram_line[] = +{ + 0, 4, 0,0,0,4 /* total guess.. */ +}; + +void build_blitfilltable(void) +{ + unsigned int d, fillmask; + int i; + + for (i = 0; i < BLITTER_MAX_WORDS; i++) + blit_masktable[i] = 0xFFFF; + + for (d = 0; d < 256; d++) { + for (i = 0; i < 4; i++) { + int fc = i & 1; + uae_u8 data = d; + for (fillmask = 1; fillmask != 0x100; fillmask <<= 1) { + uae_u16 tmp = data; + if (fc) { + if (i & 2) + data |= fillmask; + else + data ^= fillmask; + } + if (tmp & fillmask) fc = !fc; + } + blit_filltable[d][i][0] = data; + blit_filltable[d][i][1] = fc; + } + } +} + +static void blitter_dump (void) +{ + write_log ("APT=%08.8X BPT=%08.8X CPT=%08.8X DPT=%08.8X\n", bltapt, bltbpt, bltcpt, bltdpt); + write_log ("CON0=%04.4X CON1=%04.4X ADAT=%04.4X BDAT=%04.4X CDAT=%04.4X\n", + bltcon0, bltcon1, blt_info.bltadat, blt_info.bltbdat, blt_info.bltcdat); + write_log ("AFWM=%04.4X ALWM=%04.4X AMOD=%04.4X BMOD=%04.4X CMOD=%04.4X DMOD=%04.4X\n", + blt_info.bltafwm, blt_info.bltalwm, + blt_info.bltamod & 0xffff, blt_info.bltbmod & 0xffff, blt_info.bltcmod & 0xffff, blt_info.bltdmod & 0xffff); +} + +STATIC_INLINE uae_u8 *blit_xlateptr(uaecptr bltpt, int bytecount) +{ + if (!chipmem_bank.check(bltpt,bytecount)) return NULL; + return chipmem_bank.xlateaddr(bltpt); +} + +STATIC_INLINE uae_u8 *blit_xlateptr_desc(uaecptr bltpt, int bytecount) +{ + if (!chipmem_bank.check(bltpt-bytecount, bytecount)) return NULL; + return chipmem_bank.xlateaddr(bltpt); +} + +static void blitter_done (void) +{ + ddat1use = ddat2use = 0; + bltstate = BLT_done; + blitter_done_notify (); + INTREQ(0x8040); + eventtab[ev_blitter].active = 0; + unset_special (SPCFLAG_BLTNASTY); +#ifdef BLITTER_DEBUG + write_log ("cycles %d, missed %d, total %d\n", + blit_cyclecounter, blit_misscyclecounter, blit_cyclecounter + blit_misscyclecounter); +#endif +} + +static void blitter_dofast(void) +{ + int i,j; + uaecptr bltadatptr = 0, bltbdatptr = 0, bltcdatptr = 0, bltddatptr = 0; + uae_u8 mt = bltcon0 & 0xFF; + + blit_masktable[0] = blt_info.bltafwm; + blit_masktable[blt_info.hblitsize - 1] &= blt_info.bltalwm; + + if (bltcon0 & 0x800) { + bltadatptr = bltapt; + bltapt += (blt_info.hblitsize*2 + blt_info.bltamod)*blt_info.vblitsize; + } + if (bltcon0 & 0x400) { + bltbdatptr = bltbpt; + bltbpt += (blt_info.hblitsize*2 + blt_info.bltbmod)*blt_info.vblitsize; + } + if (bltcon0 & 0x200) { + bltcdatptr = bltcpt; + bltcpt += (blt_info.hblitsize*2 + blt_info.bltcmod)*blt_info.vblitsize; + } + if (bltcon0 & 0x100) { + bltddatptr = bltdpt; + bltdpt += (blt_info.hblitsize*2 + blt_info.bltdmod)*blt_info.vblitsize; + } + + if (blitfunc_dofast[mt] && !blitfill) + (*blitfunc_dofast[mt])(bltadatptr, bltbdatptr, bltcdatptr, bltddatptr, &blt_info); + else { + uae_u32 blitbhold = blt_info.bltbhold; + uae_u32 preva = 0, prevb = 0; + uaecptr dstp = 0; + int dodst = 0; + + /*if (!blitfill) write_log ("minterm %x not present\n",mt); */ + for (j = 0; j < blt_info.vblitsize; j++) { + blitfc = !!(bltcon1 & 0x4); + for (i = 0; i < blt_info.hblitsize; i++) { + uae_u32 bltadat, blitahold; + uae_u16 bltbdat; + if (bltadatptr) { + blt_info.bltadat = bltadat = chipmem_wget (bltadatptr); + bltadatptr += 2; + } else + bltadat = blt_info.bltadat; + bltadat &= blit_masktable[i]; + blitahold = (((uae_u32)preva << 16) | bltadat) >> blt_info.blitashift; + preva = bltadat; + + if (bltbdatptr) { + blt_info.bltbdat = bltbdat = chipmem_wget (bltbdatptr); + bltbdatptr += 2; + blitbhold = (((uae_u32)prevb << 16) | bltbdat) >> blt_info.blitbshift; + prevb = bltbdat; + } + + if (bltcdatptr) { + blt_info.bltcdat = chipmem_wget (bltcdatptr); + bltcdatptr += 2; + } + if (dodst) chipmem_wput (dstp, blt_info.bltddat); + blt_info.bltddat = blit_func (blitahold, blitbhold, blt_info.bltcdat, mt) & 0xFFFF; + if (blitfill) { + uae_u16 d = blt_info.bltddat; + int ifemode = blitife ? 2 : 0; + int fc1 = blit_filltable[d & 255][ifemode + blitfc][1]; + blt_info.bltddat = (blit_filltable[d & 255][ifemode + blitfc][0] + + (blit_filltable[d >> 8][ifemode + fc1][0] << 8)); + blitfc = blit_filltable[d >> 8][ifemode + fc1][1]; + } + if (blt_info.bltddat) + blt_info.blitzero = 0; + if (bltddatptr) { + dodst = 1; + dstp = bltddatptr; + bltddatptr += 2; + } + } + if (bltadatptr) bltadatptr += blt_info.bltamod; + if (bltbdatptr) bltbdatptr += blt_info.bltbmod; + if (bltcdatptr) bltcdatptr += blt_info.bltcmod; + if (bltddatptr) bltddatptr += blt_info.bltdmod; + } + if (dodst) chipmem_wput (dstp, blt_info.bltddat); + blt_info.bltbhold = blitbhold; + } + blit_masktable[0] = 0xFFFF; + blit_masktable[blt_info.hblitsize - 1] = 0xFFFF; + + bltstate = BLT_done; +} + +static void blitter_dofast_desc(void) +{ + int i,j; + uaecptr bltadatptr = 0, bltbdatptr = 0, bltcdatptr = 0, bltddatptr = 0; + uae_u8 mt = bltcon0 & 0xFF; + + blit_masktable[0] = blt_info.bltafwm; + blit_masktable[blt_info.hblitsize - 1] &= blt_info.bltalwm; + + if (bltcon0 & 0x800) { + bltadatptr = bltapt; + bltapt -= (blt_info.hblitsize*2 + blt_info.bltamod)*blt_info.vblitsize; + } + if (bltcon0 & 0x400) { + bltbdatptr = bltbpt; + bltbpt -= (blt_info.hblitsize*2 + blt_info.bltbmod)*blt_info.vblitsize; + } + if (bltcon0 & 0x200) { + bltcdatptr = bltcpt; + bltcpt -= (blt_info.hblitsize*2 + blt_info.bltcmod)*blt_info.vblitsize; + } + if (bltcon0 & 0x100) { + bltddatptr = bltdpt; + bltdpt -= (blt_info.hblitsize*2 + blt_info.bltdmod)*blt_info.vblitsize; + } + if (blitfunc_dofast_desc[mt] && !blitfill) + (*blitfunc_dofast_desc[mt])(bltadatptr, bltbdatptr, bltcdatptr, bltddatptr, &blt_info); + else { + uae_u32 blitbhold = blt_info.bltbhold; + uae_u32 preva = 0, prevb = 0; + uaecptr dstp = 0; + int dodst = 0; + +/* if (!blitfill) write_log ("minterm %x not present\n",mt);*/ + for (j = 0; j < blt_info.vblitsize; j++) { + blitfc = !!(bltcon1 & 0x4); + for (i = 0; i < blt_info.hblitsize; i++) { + uae_u32 bltadat, blitahold; + uae_u16 bltbdat; + if (bltadatptr) { + bltadat = blt_info.bltadat = chipmem_wget (bltadatptr); + bltadatptr -= 2; + } else + bltadat = blt_info.bltadat; + bltadat &= blit_masktable[i]; + blitahold = (((uae_u32)bltadat << 16) | preva) >> blt_info.blitdownashift; + preva = bltadat; + + if (bltbdatptr) { + blt_info.bltbdat = bltbdat = chipmem_wget (bltbdatptr); + bltbdatptr -= 2; + blitbhold = (((uae_u32)bltbdat << 16) | prevb) >> blt_info.blitdownbshift; + prevb = bltbdat; + } + + if (bltcdatptr) { + blt_info.bltcdat = blt_info.bltbdat = chipmem_wget (bltcdatptr); + bltcdatptr -= 2; + } + if (dodst) chipmem_wput (dstp, blt_info.bltddat); + blt_info.bltddat = blit_func (blitahold, blitbhold, blt_info.bltcdat, mt) & 0xFFFF; + if (blitfill) { + uae_u16 d = blt_info.bltddat; + int ifemode = blitife ? 2 : 0; + int fc1 = blit_filltable[d & 255][ifemode + blitfc][1]; + blt_info.bltddat = (blit_filltable[d & 255][ifemode + blitfc][0] + + (blit_filltable[d >> 8][ifemode + fc1][0] << 8)); + blitfc = blit_filltable[d >> 8][ifemode + fc1][1]; + } + if (blt_info.bltddat) + blt_info.blitzero = 0; + if (bltddatptr) { + dstp = bltddatptr; + dodst = 1; + bltddatptr -= 2; + } + } + if (bltadatptr) bltadatptr -= blt_info.bltamod; + if (bltbdatptr) bltbdatptr -= blt_info.bltbmod; + if (bltcdatptr) bltcdatptr -= blt_info.bltcmod; + if (bltddatptr) bltddatptr -= blt_info.bltdmod; + } + if (dodst) chipmem_wput (dstp, blt_info.bltddat); + blt_info.bltbhold = blitbhold; + } + blit_masktable[0] = 0xFFFF; + blit_masktable[blt_info.hblitsize - 1] = 0xFFFF; + + bltstate = BLT_done; +} + +STATIC_INLINE int blitter_read(void) +{ + if (bltcon0 & 0x200) { + if (!dmaen(DMA_BLITTER)) + return 1; + blt_info.bltcdat = chipmem_bank.wget(bltcpt); + } + bltstate = BLT_work; + return (bltcon0 & 0x200) != 0; +} + +STATIC_INLINE int blitter_write(void) +{ + if (blt_info.bltddat) + blt_info.blitzero = 0; + /* D-channel state has no effect on linedraw, but C must be enabled or nothing is drawn! */ + if (bltcon0 & 0x200) { + if (!dmaen(DMA_BLITTER)) return 1; + chipmem_bank.wput(bltdpt, blt_info.bltddat); + bltdpt = bltcpt; /* believe it or not but try Cardamon or Cardamom without this.. */ + } + bltstate = BLT_next; + return (bltcon0 & 0x200) != 0; +} + +STATIC_INLINE void blitter_line_incx(void) +{ + if (++blinea_shift == 16) { + blinea_shift = 0; + bltcnxlpt += 2; + } +} + +STATIC_INLINE void blitter_line_decx(void) +{ + if (blinea_shift-- == 0) { + blinea_shift = 15; + bltcnxlpt -= 2; + } +} + +STATIC_INLINE void blitter_line_decy(void) +{ + bltcnxlpt -= blt_info.bltcmod; + blitonedot = 0; +} + +STATIC_INLINE void blitter_line_incy(void) +{ + bltcnxlpt += blt_info.bltcmod; + blitonedot = 0; +} + +static void blitter_line(void) +{ + uae_u16 blitahold = blinea >> blinea_shift; + uae_u16 blitbhold = blineb & 1 ? 0xFFFF : 0; + uae_u16 blitchold = blt_info.bltcdat; + blt_info.bltddat = 0; + + if (blitsing && blitonedot) + blitahold = 0; + blitonedot = 1; + blt_info.bltddat = blit_func(blitahold, blitbhold, blitchold, bltcon0 & 0xFF); + if (!blitsign){ + if (bltcon0 & 0x800) + bltapt += (uae_s16)blt_info.bltamod; + if (bltcon1 & 0x10){ + if (bltcon1 & 0x8) + blitter_line_decy(); + else + blitter_line_incy(); + } else { + if (bltcon1 & 0x8) + blitter_line_decx(); + else + blitter_line_incx(); + } + } else { + if (bltcon0 & 0x800) + bltapt += (uae_s16)blt_info.bltbmod; + } + if (bltcon1 & 0x10){ + if (bltcon1 & 0x4) + blitter_line_decx(); + else + blitter_line_incx(); + } else { + if (bltcon1 & 0x4) + blitter_line_decy(); + else + blitter_line_incy(); + } + blitsign = 0 > (uae_s16)bltapt; + bltstate = BLT_write; +} + +STATIC_INLINE void blitter_nxline(void) +{ + bltdpt = bltcpt = bltcnxlpt; + blineb = (blineb << 1) | (blineb >> 15); + if (--blt_info.vblitsize == 0) { + bltstate = BLT_done; + } else { + bltstate = BLT_read; + } +} + +static void actually_do_blit(void) +{ + if (blitline) { + do { + blitter_read(); + blitter_line(); + blitter_write(); + blitter_nxline(); + } while (bltstate != BLT_done); + } else { + if (blitdesc) + blitter_dofast_desc(); + else + blitter_dofast(); + bltstate = BLT_done; + } +} + +void blitter_handler(void) +{ + if (!dmaen(DMA_BLITTER)) { + eventtab[ev_blitter].active = 1; + eventtab[ev_blitter].oldcycles = get_cycles (); + eventtab[ev_blitter].evtime = 10 * CYCLE_UNIT + get_cycles (); /* wait a little */ + return; /* gotta come back later. */ + } + if (blit_slowdown > 0) { + eventtab[ev_blitter].active = 1; + eventtab[ev_blitter].oldcycles = get_cycles (); + eventtab[ev_blitter].evtime = blit_slowdown * CYCLE_UNIT + get_cycles (); + blit_slowdown = -1; + return; + } +#ifdef BLITTER_DEBUG + if (!blitter_dontdo) + actually_do_blit(); + else + bltstate = BLT_done; +#else + actually_do_blit (); +#endif + blitter_done (); +} + +STATIC_INLINE int channel_state (int cycles) +{ + if (cycles < blit_diag[0]) + return blit_diag[blit_diag[1] + 2 + cycles]; + return blit_diag[((cycles - blit_diag[0]) % blit_diag[1]) + 2]; +} + +#ifdef CPUEMU_6 + +static int blit_last_hpos; + +static int blitter_dma_cycles_line, blitter_dma_cycles_line_count; +static int blitter_cyclecounter; +static int blitter_hcounter1, blitter_hcounter2; +static int blitter_vcounter1, blitter_vcounter2; + + +static uae_u32 preva, prevb; +STATIC_INLINE uae_u16 blitter_doblit (void) +{ + uae_u32 blitahold; + uae_u16 bltadat, ddat; + uae_u8 mt = bltcon0 & 0xFF; + + bltadat = blt_info.bltadat; + if (blitter_hcounter1 == 0) + bltadat &= blt_info.bltafwm; + if (blitter_hcounter1 == blt_info.hblitsize - 1) + bltadat &= blt_info.bltalwm; + if (blitdesc) + blitahold = (((uae_u32)bltadat << 16) | preva) >> blt_info.blitdownashift; + else + blitahold = (((uae_u32)preva << 16) | bltadat) >> blt_info.blitashift; + preva = bltadat; + + ddat = blit_func (blitahold, blt_info.bltbhold, blt_info.bltcdat, mt) & 0xFFFF; + + if (bltcon1 & 0x18) { + uae_u16 d = ddat; + int ifemode = blitife ? 2 : 0; + int fc1 = blit_filltable[d & 255][ifemode + blitfc][1]; + ddat = (blit_filltable[d & 255][ifemode + blitfc][0] + + (blit_filltable[d >> 8][ifemode + fc1][0] << 8)); + blitfc = blit_filltable[d >> 8][ifemode + fc1][1]; + } + + if (ddat) + blt_info.blitzero = 0; + + return ddat; +} + + +int is_bitplane_dma (int hpos); + +STATIC_INLINE int blitter_doddma (void) +{ + int wd; + uae_u16 d; + + wd = 0; + if (blit_dmacount2 == 0) { + d = blitter_doblit (); + wd = -1; + } else if (ddat2use) { + d = ddat2; + ddat2use = 0; + wd = 2; + } else if (ddat1use) { + d = ddat1; + ddat1use = 0; + wd = 1; + } + if (wd) { + chipmem_wput (bltdpt, d); + bltdpt += blit_add; + blitter_hcounter2++; + if (blitter_hcounter2 == blt_info.hblitsize) { + blitter_hcounter2 = 0; + bltdpt += blit_modaddd; + blitter_vcounter2++; + if (blitter_vcounter2 > blitter_vcounter1) + blitter_vcounter1 = blitter_vcounter2; + } + if (blit_ch == 1) + blitter_hcounter1 = blitter_hcounter2; + } + return wd; +} + +STATIC_INLINE void blitter_dodma (int ch) +{ + + switch (ch) + { + case 1: + blt_info.bltadat = chipmem_wget (bltapt); + bltapt += blit_add; + break; + case 2: + blt_info.bltbdat = chipmem_wget (bltbpt); + bltbpt += blit_add; + if (blitdesc) + blt_info.bltbhold = (((uae_u32)blt_info.bltbdat << 16) | prevb) >> blt_info.blitdownbshift; + else + blt_info.bltbhold = (((uae_u32)prevb << 16) | blt_info.bltbdat) >> blt_info.blitbshift; + prevb = blt_info.bltbdat; + break; + case 3: + blt_info.bltcdat = chipmem_wget (bltcpt); + bltcpt += blit_add; + break; + } + + blitter_cyclecounter++; + if (blitter_cyclecounter >= blit_dmacount2) { + blitter_cyclecounter = 0; + ddat2 = ddat1; + ddat2use = ddat1use; + ddat1use = 0; + ddat1 = blitter_doblit (); + if (bltcon0 & 0x100) + ddat1use = 1; + blitter_hcounter1++; + if (blitter_hcounter1 == blt_info.hblitsize) { + blitter_hcounter1 = 0; + if (bltcon0 & 0x800) + bltapt += blit_modadda; + if (bltcon0 & 0x400) + bltbpt += blit_modaddb; + if (bltcon0 & 0x200) + bltcpt += blit_modaddc; + blitter_vcounter1++; + blitfc = !!(bltcon1 & 0x4); + } + } +} + +static void decide_blitter_line (int hpos) +{ + hpos++; + if (dmaen (DMA_BLITTER)) { + while (blit_last_hpos < hpos) { + int c = channel_state (blit_cyclecounter); + for (;;) { + if (c && (cycle_line[blit_last_hpos] || is_bitplane_dma (blit_last_hpos))) + break; + if (c) + cycle_line[blit_last_hpos] |= CYCLE_BLITTER; + blit_cyclecounter++; + blit_linecyclecounter++; + if (blit_linecyclecounter >= blit_diag[1]) { + blit_linecyclecounter = 0; + blitter_read(); + blitter_line(); + blitter_write(); + blitter_nxline(); + if (bltstate == BLT_done) { + blitter_done (); + return; + } + } + break; + } + blit_last_hpos++; + } + } else { + blit_last_hpos = hpos; + } + if (blit_last_hpos > maxhpos) + blit_last_hpos = 0; +} + +void decide_blitter (int hpos) +{ + if (bltstate == BLT_done) + return; + if (!currprefs.blitter_cycle_exact) { + blitter_handler (); + return; + } + if (blitline) { + decide_blitter_line (hpos); + return; + } + if (blit_starting && get_cycles () - blit_starts < 4 * CYCLE_UNIT) { + blit_last_hpos = hpos + 1; + return; + } + hpos++; + if (dmaen (DMA_BLITTER)) { + while (blit_last_hpos < hpos) { + int c = channel_state (blit_cyclecounter); +#ifdef BLITTER_SLOWDOWNDEBUG + blitter_slowdowndebug--; + if (blitter_slowdowndebug < 0) { + cycle_line[blit_last_hpos] |= CYCLE_BLITTER; + blitter_slowdowndebug = BLITTER_SLOWDOWNDEBUG; + } +#endif + for (;;) { + if (c && (cycle_line[blit_last_hpos] || is_bitplane_dma (blit_last_hpos))) { + blit_misscyclecounter++; + break; + } + if (c == 4) { + if (blitter_doddma ()) { + cycle_line[blit_last_hpos] |= CYCLE_BLITTER; + blit_cyclecounter++; + } + } else if (c) { + if (blitter_vcounter1 < blt_info.vblitsize) { + cycle_line[blit_last_hpos] |= CYCLE_BLITTER; + blitter_dodma (c); + } + blit_cyclecounter++; + } else { + blit_cyclecounter++; + /* check if blit with zero channels has ended */ + if (blit_cyclecounter >= blit_maxcyclecounter) { + blitter_done (); + return; + } + } + if (blitter_vcounter1 >= blt_info.vblitsize && blitter_vcounter2 >= blt_info.vblitsize) { + if (!ddat1use && !ddat2use) { + blitter_done (); + return; + } + if (blit_diag != blit_cycle_diagram_finald) { + blit_cyclecounter = 0; + blit_diag = blit_cycle_diagram_finald; + } + } + break; + } + blit_last_hpos++; + } + } else { + blit_last_hpos = hpos; + } + if (blit_last_hpos > maxhpos) + blit_last_hpos = 0; +} +#else +void decide_blitter (int hpos) { } +#endif + +static void blitter_force_finish (void) +{ + uae_u16 odmacon; + if (bltstate == BLT_done) + return; + if (bltstate != BLT_done) { + /* blitter is currently running + * force finish (no blitter state support yet) + */ + odmacon = dmacon; + dmacon |= DMA_MASTER | DMA_BLITTER; + write_log ("forcing blitter finish\n"); + if (currprefs.blitter_cycle_exact) { + while (bltstate != BLT_done) { + memset (cycle_line, 0, maxhpos); + decide_blitter (maxhpos); + } + } else { + actually_do_blit (); + } + blitter_done (); + dmacon = odmacon; + } +} + +static void blit_bltset (int con) +{ + int i; + + blitline = bltcon1 & 1; + blitfill = bltcon1 & 0x18; + blitdesc = bltcon1 & 2; + blit_ch = (bltcon0 & 0x0f00) >> 8; + + blit_singlechannel = 0; + if (blit_ch == 0 || blit_ch == 1 || blit_ch == 2 || blit_ch == 4 || blit_ch == 8) + blit_singlechannel = 1; + if (blitline) { + if (blt_info.hblitsize != 2) + write_log ("weird hblitsize in linemode: %d vsize=%d PC%=%x\n", blt_info.hblitsize, blt_info.vblitsize, m68k_getpc()); + blit_diag = blit_cycle_diagram_line; + } else { + if (con & 2) { + blitfc = !!(bltcon1 & 0x4); + blitife = bltcon1 & 0x8; + if ((bltcon1 & 0x18) == 0x18) { + /* Digital "Trash" demo does this; others too. Apparently, no + * negative effects. */ + static int warn = 1; + if (warn) + write_log ("warning: weird fill mode (further messages suppressed)\n"); + warn = 0; + blitife = 0; + } + } + if (blitfill && !blitdesc) { + static int warn = 1; + if (warn) + write_log ("warning: blitter fill without desc (further messages suppressed)\n"); + warn = 0; + } + blit_diag = blitfill ? blit_cycle_diagram_fill[blit_ch] : blit_cycle_diagram[blit_ch]; + } + if ((bltcon1 & 0x80) && (currprefs.chipset_mask & CSMASK_ECS_AGNUS)) + write_log("warning: BLTCON1 DOFF-bit set\n"); + + blit_dmacount = blit_dmacount2 = 0; + for (i = 0; i < blit_diag[1]; i++) { + int v = blit_diag[2 + i]; + if (v) + blit_dmacount++; + if (v > 0 && v < 4) + blit_dmacount2++; + } + + blt_info.blitashift = bltcon0 >> 12; + blt_info.blitdownashift = 16 - blt_info.blitashift; + blt_info.blitbshift = bltcon1 >> 12; + blt_info.blitdownbshift = 16 - blt_info.blitbshift; +} + +void blit_modset (void) +{ + int mult; + + blit_add = blitdesc ? -2 : 2; + mult = blitdesc ? -1 : 1; + blit_modadda = mult * blt_info.bltamod; + blit_modaddb = mult * blt_info.bltbmod; + blit_modaddc = mult * blt_info.bltcmod; + blit_modaddd = mult * blt_info.bltdmod; +} + +void reset_blit (int bltcon) +{ + if (bltstate == BLT_done) + return; + if (bltcon) + blit_bltset (bltcon); + blit_modset (); +} + +void do_blitter (int hpos) +{ + int cycles; + + blt_info.blitzero = 1; + bltstate = BLT_init; + preva = 0; + prevb = 0; + + blit_firstline_cycles = blit_first_cycle = get_cycles (); + blit_cyclecounter = blit_misscyclecounter = 0; + blit_last_cycle = 0; + blit_maxcyclecounter = 0; + blit_last_hpos = hpos; + + reset_blit (1|2); + + if (blitline) { + bltcnxlpt = bltcpt; + bltdnxlpt = bltdpt; + blitsing = bltcon1 & 0x2; + blinea = blt_info.bltadat; + blineb = (blt_info.bltbdat >> blt_info.blitbshift) | (blt_info.bltbdat << (16 - blt_info.blitbshift)); + blitsign = bltcon1 & 0x40; + blitonedot = 0; + cycles = blt_info.vblitsize; + } else { + blit_firstline_cycles = blit_first_cycle + blit_diag[1] * blt_info.hblitsize * CYCLE_UNIT; + cycles = blt_info.vblitsize * blt_info.hblitsize; + } + blit_cycles_total = cycles; + +#ifdef BLITTER_DEBUG + blitter_dontdo = 0; + if (1) { + write_log("blitstart: v=%03.3d h=%03.3d %dx%d %d (%d) d=%d f=%02.2X n=%d pc=%p l=%d dma=%d\n", + vpos, hpos, blt_info.hblitsize, blt_info.vblitsize, cycles, blit_ch, + blitdesc ? 1 : 0, blitfill, + dmaen(DMA_BLITPRI) ? 1 : 0, m68k_getpc(), blitline, dmaen(DMA_BLITTER)); + blitter_dump (); + } +#endif + + blit_slowdown = 0; + + unset_special (SPCFLAG_BLTNASTY); + if (dmaen(DMA_BLITPRI)) + set_special (SPCFLAG_BLTNASTY); + + if (blt_info.vblitsize == 0 || (blitline && blt_info.hblitsize != 2)) { + blitter_done (); + return; + } + + if (dmaen(DMA_BLITTER)) + bltstate = BLT_work; + + blit_maxcyclecounter = 0x7fffffff; + if (currprefs.blitter_cycle_exact) { + blitter_dma_cycles_line_count = 0; + blitter_hcounter1 = blitter_hcounter2 = 0; + blitter_vcounter1 = blitter_vcounter2 = 0; + if (blit_dmacount2 == blit_dmacount) + blitter_vcounter2 = blt_info.vblitsize; + blit_linecyclecounter = 0; + blitter_dma_cycles_line = blt_info.hblitsize * blit_dmacount2; + if (blit_ch == 0) + blit_maxcyclecounter = blt_info.hblitsize * blt_info.vblitsize; + blit_starts = get_cycles (); + blit_starting = 1; + return; + } + + if (currprefs.immediate_blits) + cycles = 1; + + eventtab[ev_blitter].active = 1; + eventtab[ev_blitter].oldcycles = get_cycles (); + eventtab[ev_blitter].evtime = cycles * blit_diag[1] * CYCLE_UNIT + get_cycles (); + events_schedule(); +} + + +void maybe_blit (int hpos, int hack) +{ + static int warned; + + if (bltstate == BLT_done) + return; + + if (!warned && dmaen (DMA_BLITTER)) { +#ifndef BLITTER_DEBUG + warned = 1; +#endif + write_log ("warning: Program does not wait for blitter %p\n", m68k_getpc()); + } + + if (currprefs.blitter_cycle_exact) { + decide_blitter (hpos); + return; + } + + if (!eventtab[ev_blitter].active) + write_log ("FOO!!?\n"); + if (hack == 1 && get_cycles() < blit_firstline_cycles) + return; + + blitter_handler (); +} + +int blitnasty (void) +{ + int cycles, ccnt; + if (bltstate == BLT_done) + return 0; + if (!dmaen(DMA_BLITTER)) + return 0; + if (blit_last_cycle >= blit_diag[0] && blit_dmacount == blit_diag[1]) + return 0; + cycles = (get_cycles () - blit_first_cycle) / CYCLE_UNIT; + ccnt = 0; + while (blit_last_cycle < cycles) { + int c = channel_state (blit_last_cycle++); + if (!c) + ccnt++; + } + return ccnt; +} + +/* very approximate emulation of blitter slowdown caused by bitplane DMA */ +void blitter_slowdown (int ddfstrt, int ddfstop, int totalcycles, int freecycles) +{ + static int oddfstrt, oddfstop, ototal, ofree; + static int cycles_used; + int slow; + + if (ddfstrt != oddfstrt || ddfstop != oddfstop || totalcycles != ototal || ofree != freecycles) { + int linecycles = ddfstop - ddfstrt; + cycles_used = 0; + if (linecycles > blit_cycles_total) + linecycles = blit_cycles_total; + if (linecycles < 0) + linecycles = 0; + if (totalcycles == 0) + return; + cycles_used = linecycles * (totalcycles - freecycles) / totalcycles; + oddfstrt = ddfstrt; + oddfstop = ddfstop; + ototal = totalcycles; + ofree = freecycles; + } + if (blit_slowdown < 0 || blitline || totalcycles == 0) + return; + slow = cycles_used * blit_dmacount / blit_diag[1]; + slow = slow * 7 / 10; + if (slow <= 0) + return; + blit_slowdown += slow; + blit_misscyclecounter += slow; + blit_cycles_total -= maxhpos; +} + +uae_u8 *restore_blitter (uae_u8 *src) +{ + uae_u32 flags = restore_u32(); + + bltstate = (flags & 1) ? BLT_init : BLT_done; + if (bltstate == BLT_init) { + write_log ("blitter was started but DMA was inactive during save\n"); + do_blitter (0); + } + return src; +} + +uae_u8 *save_blitter (int *len, uae_u8 *dstptr) +{ + uae_u8 *dstbak,*dst; + + if (bltstate != BLT_done && bltstate != BLT_init) { + write_log ("blitter was running, forcing immediate finish\n"); + /* blitter is active just now but we don't have blitter state support yet */ + blitter_force_finish (); + } + if (dstptr) + dstbak = dst = dstptr; + else + dstbak = dst = malloc (16); + save_u32((bltstate != BLT_done) ? 0 : 1); + *len = dst - dstbak; + return dstbak; + +} diff --git a/blkdev.c b/blkdev.c new file mode 100755 index 00000000..0cf3f8b7 --- /dev/null +++ b/blkdev.c @@ -0,0 +1,319 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * lowlevel device glue + * + */ + +#include "sysconfig.h" +#include "sysdeps.h" +#include "options.h" +#include "memory.h" + +#include "config.h" + +#include "blkdev.h" + +static struct device_functions *device_func[2]; +static int ioctl; + +#ifdef WIN32 + +#include "od-win32/win32.h" + +extern struct device_functions devicefunc_win32_aspi; +extern struct device_functions devicefunc_win32_spti; +extern struct device_functions devicefunc_win32_ioctl; + +static void install_driver (int flags) +{ + device_func[DF_SCSI] = &devicefunc_win32_aspi; +#ifdef WINDDK + if (os_winnt && os_winnt_admin) { + device_func[DF_IOCTL] = &devicefunc_win32_ioctl; + device_func[DF_SCSI] = &devicefunc_win32_spti; + } + if (currprefs.win32_aspi) { + device_func[DF_SCSI] = &devicefunc_win32_aspi; + device_func[DF_IOCTL] = 0; + } +#endif +} +#endif + +int sys_command_open (int mode, int unitnum) +{ + if (mode == DF_SCSI || !ioctl) + return device_func[DF_SCSI]->opendev (unitnum); + else + return device_func[DF_IOCTL]->opendev (unitnum); +} + +void sys_command_close (int mode, int unitnum) +{ + if (mode == DF_SCSI || !ioctl) + device_func[DF_SCSI]->closedev (unitnum); + else + device_func[DF_IOCTL]->closedev (unitnum); +} + +int device_func_init (int flags) +{ + static int initialized; + int support_scsi = 0, support_ioctl = 0; + int oflags = (flags & DEVICE_TYPE_SCSI) ? 0 : (1 << INQ_ROMD); + + if (initialized) + return initialized; + install_driver (flags); + if (device_func[DF_IOCTL]) + ioctl = 1; + else + ioctl = 0; + support_scsi = device_func[DF_SCSI]->openbus (oflags) ? 1 : 0; + if (ioctl) + support_ioctl = device_func[DF_IOCTL]->openbus (1 << INQ_ROMD) ? 1 : 0; + initialized = 1; + write_log ("support_scsi = %d support_ioctl = %d\n", support_scsi, support_ioctl); + return (support_scsi ? (1 << DF_SCSI) : 0) | (support_ioctl ? (1 << DF_IOCTL) : 0); +} + +static int audiostatus (int unitnum) +{ + uae_u8 cmd[10] = {0x42,2,0x40,1,0,0,0,DEVICE_SCSI_BUFSIZE>>8,DEVICE_SCSI_BUFSIZE&0xff,0}; + uae_u8 *p = device_func[DF_SCSI]->exec_in (unitnum, cmd, sizeof (cmd), 0); + if (!p) + return 0; + return p[1]; +} + +/* pause/unpause CD audio */ +void sys_command_pause (int mode, int unitnum, int paused) +{ + if (mode == DF_SCSI || !ioctl) { + int as = audiostatus (unitnum); + if ((paused && as == 0x11) && (!paused && as == 0x12)) { + uae_u8 cmd[10] = {0x4b,0,0,0,0,0,0,0,paused?0:1,0}; + device_func[DF_SCSI]->exec_out (unitnum, cmd, sizeof (cmd)); + } + return; + } + device_func[DF_IOCTL]->pause (unitnum, paused); +} + +/* stop CD audio */ +void sys_command_stop (int mode, int unitnum) +{ + if (mode == DF_SCSI || !ioctl) { + int as = audiostatus (unitnum); + if (as == 0x11) { + uae_u8 cmd[6] = {0x4e,0,0,0,0,0}; + device_func[DF_SCSI]->exec_out (unitnum, cmd, sizeof (cmd)); + } + return; + } + device_func[DF_IOCTL]->stop (unitnum); +} + +/* play CD audio */ +int sys_command_play (int mode, int unitnum,uae_u32 startmsf, uae_u32 endmsf, int scan) +{ + if (mode == DF_SCSI || !ioctl) { + uae_u8 cmd[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; +#if 0 + if (scan) { + cmd[0] = 0xba; + cmd[1] = scan < 0 ? 0x10 : 0x0; + cmd[3] = (uae_u8)(startmsf >> 16); + cmd[4] = (uae_u8)(startmsf >> 8); + cmd[5] = (uae_u8)(startmsf >> 0); + cmd[9] = 0x40; + } else { +#endif + cmd[0] = 0x47; + cmd[3] = (uae_u8)(startmsf >> 16); + cmd[4] = (uae_u8)(startmsf >> 8); + cmd[5] = (uae_u8)(startmsf >> 0); + cmd[6] = (uae_u8)(endmsf >> 16); + cmd[7] = (uae_u8)(endmsf >> 8); + cmd[8] = (uae_u8)(endmsf >> 0); +#if 0 + } +#endif + return device_func[DF_SCSI]->exec_out (unitnum, cmd, sizeof (cmd)) == 0 ? 0 : 1; + } + return device_func[DF_IOCTL]->play (unitnum, startmsf, endmsf, scan); +} + +/* read qcode */ +uae_u8 *sys_command_qcode (int mode, int unitnum) +{ + if (mode == DF_SCSI || !ioctl) { + uae_u8 cmd[10] = {0x42,2,0x40,1,0,0,0,DEVICE_SCSI_BUFSIZE>>8,DEVICE_SCSI_BUFSIZE&0xff,0}; + return device_func[DF_SCSI]->exec_in (unitnum, cmd, sizeof (cmd), 0); + } + return device_func[DF_IOCTL]->qcode (unitnum); +}; + +/* read table of contents */ +uae_u8 *sys_command_toc (int mode, int unitnum) +{ + if (mode == DF_SCSI || !ioctl) { + uae_u8 cmd [10] = { 0x43,0,2,0,0,0,1,DEVICE_SCSI_BUFSIZE>>8,DEVICE_SCSI_BUFSIZE&0xFF,0}; + return device_func[DF_SCSI]->exec_in (unitnum, cmd, sizeof(cmd), 0); + } + return device_func[DF_IOCTL]->toc (unitnum); +} + +/* read one sector */ +uae_u8 *sys_command_read (int mode, int unitnum, int offset) +{ + if (mode == DF_SCSI || !ioctl) { + uae_u8 cmd[12] = { 0xbe, 0, 0, 0, 0, 0, 0, 0, 1, 0x10, 0, 0 }; + cmd[3] = (uae_u8)(offset >> 16); + cmd[4] = (uae_u8)(offset >> 8); + cmd[5] = (uae_u8)(offset >> 0); + return device_func[DF_SCSI]->exec_in (unitnum, cmd, sizeof (cmd), 0); + } + return device_func[DF_IOCTL]->read (unitnum, offset); +} + +struct device_info *sys_command_info (int mode, int unitnum, struct device_info *di) +{ + if (mode == DF_SCSI || !ioctl) + return device_func[DF_SCSI]->info (unitnum, di); + else + return device_func[DF_IOCTL]->info (unitnum, di); +} + +#define MODE_SELECT_6 0x15 +#define MODE_SENSE_6 0x1a +#define MODE_SELECT_10 0x55 +#define MODE_SENSE_10 0x5a + +void scsi_atapi_fixup_pre (uae_u8 *scsi_cmd, int *len, uae_u8 **datap, int *datalenp, int *parm) +{ + uae_u8 cmd, *p, *data = *datap; + int l, datalen = *datalenp; + + *parm = 0; + cmd = scsi_cmd[0]; + if (cmd != MODE_SELECT_6 && cmd != MODE_SENSE_6) + return; + l = scsi_cmd[4]; + if (l > 4) + l += 4; + scsi_cmd[7] = l >> 8; + scsi_cmd[8] = l; + if (cmd == MODE_SELECT_6) { + scsi_cmd[0] = MODE_SELECT_10; + scsi_cmd[9] = scsi_cmd[5]; + scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = scsi_cmd[6] = 0; + *len = 10; + p = xmalloc (8 + datalen + 4); + if (datalen > 4) + memcpy (p + 8, data + 4, datalen - 4); + p[0] = 0; + p[1] = data[0]; + p[2] = data[1]; + p[3] = data[2]; + p[4] = p[5] = p[6] = 0; + p[7] = data[3]; + if (l > 8) + datalen += 4; + *parm = MODE_SELECT_10; + *datap = p; + } else { + scsi_cmd[0] = MODE_SENSE_10; + scsi_cmd[9] = scsi_cmd[5]; + scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = scsi_cmd[6] = 0; + if (l > 8) + datalen += 4; + *datap = xmalloc (datalen); + *len = 10; + *parm = MODE_SENSE_10; + } + *datalenp = datalen; +} + +void scsi_atapi_fixup_post (uae_u8 *scsi_cmd, int len, uae_u8 *olddata, uae_u8 *data, int *datalenp, int parm) +{ + int datalen = *datalenp; + if (!data || !datalen) + return; + if (parm == MODE_SENSE_10) { + olddata[0] = data[1]; + olddata[1] = data[2]; + olddata[2] = data[3]; + olddata[3] = data[7]; + datalen -= 4; + if (datalen > 4) + memcpy (olddata + 4, data + 8, datalen - 4); + *datalenp = datalen; + } +} + +static void scsi_atapi_fixup_inquiry (uaecptr req) +{ + uaecptr scsi_data = get_long (req + 0); + uae_u32 scsi_len = get_long (req + 4); + uaecptr scsi_cmd = get_long (req + 12); + uae_u8 cmd; + + cmd = get_byte (scsi_cmd); + /* CDROM INQUIRY: most Amiga programs expect ANSI version == 2 + * (ATAPI normally responds with zero) + */ + if (cmd == 0x12 && scsi_len > 2 && scsi_data) { + uae_u8 per = get_byte (scsi_data + 0); + uae_u8 b = get_byte (scsi_data + 2); + /* CDROM and ANSI version == 0 ? */ + if ((per & 31) == 5 && (b & 7) == 0) { + b |= 2; + put_byte (scsi_data + 2, b); + } + } +} + +int sys_command_scsi_direct (int unitnum, uaecptr request) +{ + int ret = device_func[DF_SCSI]->exec_direct (unitnum, request); + if (!ret && device_func[DF_SCSI]->isatapi(unitnum)) + scsi_atapi_fixup_inquiry (request); + return ret; +} + +void scsi_log_before (uae_u8 *cdb, int cdblen, uae_u8 *data, int datalen) +{ + int i; + for (i = 0; i < cdblen; i++) { + write_log("%s%02.2X", i > 0 ? "." : "", cdb[i]); + } + write_log("\n"); + if (data) { + write_log ("DATAOUT: %d\n", datalen); + for (i = 0; i < datalen && i < 100; i++) + write_log("%s%02.2X", i > 0 ? "." : "", data[i]); + if (datalen > 0) + write_log("\n"); + } +} + +void scsi_log_after (uae_u8 *data, int datalen, uae_u8 *sense, int senselen) +{ + int i; + if (data) { + write_log ("DATAIN: %d\n", datalen); + for (i = 0; i < datalen && i < 100; i++) + write_log("%s%02.2X", i > 0 ? "." : "", data[i]); + if (datalen > 0) + write_log("\n"); + } + if (senselen > 0) { + write_log("SENSE: "); + for (i = 0; i < senselen && i < 32; i++) { + write_log("%s%02.2X", i > 0 ? "." : "", sense[i]); + } + write_log("\n"); + } +} diff --git a/bsdsocket.c b/bsdsocket.c new file mode 100755 index 00000000..63dd7c77 --- /dev/null +++ b/bsdsocket.c @@ -0,0 +1,1408 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * bsdsocket.library emulation machine-independent part + * + * Copyright 1997, 1998 Mathias Ortmann + * + * Library initialization code (c) Tauno Taipaleenmaki + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include +#include + +#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 /* */ +#define SBTC_HERRNOSTRPTR 15 /* */ +#define SBTC_IOERRNOSTRPTR 16 /* */ +#define SBTC_S2ERRNOSTRPTR 17 /* */ +#define SBTC_S2WERRNOSTRPTR 18 /* */ +#define SBTC_ERRNOBYTEPTR 21 +#define SBTC_ERRNOWORDPTR 22 +#define SBTC_ERRNOLONGPTR 24 +#define SBTC_HERRNOLONGPTR 25 +#define SBTC_RELEASESTRPTR 29 + +static void tagcopy (uae_u32 currtag, uae_u32 currval, uae_u32 tagptr, uae_u32 * ptr) +{ + switch (currtag & 0x8001) { + case 0x0000: /* SBTM_GETVAL */ + + put_long (tagptr + 4, *ptr); + break; + case 0x8000: /* SBTM_GETREF */ + + put_long (currval, *ptr); + break; + case 0x0001: /* SBTM_SETVAL */ + + *ptr = currval; + break; + default: /* SBTM_SETREF */ + + *ptr = get_long (currval); + } +} + +static uae_u32 bsdsocklib_SocketBaseTagList (void) +{ + SB = SOCKETBASE; + uae_u32 tagptr = m68k_areg (regs, 0); + uae_u32 tagsprocessed = 1; + uae_u32 currtag; + uae_u32 currval; + + TRACE (("SocketBaseTagList(")); + + for (;;) { + currtag = get_long (tagptr); + currval = get_long (tagptr + 4); + tagsprocessed++; + + switch (currtag) { + case TAG_DONE: + TRACE (("TAG_DONE")); + tagsprocessed = 0; + goto done; + case TAG_IGNORE: + TRACE (("TAG_IGNORE")); + break; + case TAG_MORE: + TRACE (("TAG_MORE(0x%lx)", currval)); + tagptr = currval; + break; + case TAG_SKIP: + TRACE (("TAG_SKIP(%d)", currval)); + tagptr += currval * 8; + break; + + default: + if (currtag & TAG_USER) { + TRACE (("SBTM_")); + TRACE ((currtag & 0x0001 ? "SET" : "GET")); + TRACE ((currtag & 0x8000 ? "REF(" : "VAL(")); + + switch ((currtag >> 1) & SBTS_CODE) { + case SBTC_BREAKMASK: + TRACE (("SBTC_BREAKMASK),0x%lx", currval)); + tagcopy (currtag, currval, tagptr, &sb->eintrsigs); + break; + case SBTC_SIGEVENTMASK: + TRACE (("SBTC_SIGEVENTMASK),0x%lx", currval)); + tagcopy (currtag, currval, tagptr, &sb->eventsigs); + break; + case SBTC_SIGIOMASK: + TRACE (("SBTC_SIGEVENTMASK),0x%lx", currval)); + tagcopy (currtag, currval, tagptr, &sb->eventsigs); + break; + case SBTC_ERRNO: + TRACE (("SBTC_ERRNO),%d", currval)); + tagcopy (currtag, currval, tagptr, &sb->sb_errno); + break; + case SBTC_HERRNO: + TRACE (("SBTC_HERRNO),%d", currval)); + tagcopy (currtag, currval, tagptr, &sb->sb_herrno); + break; + case SBTC_ERRNOSTRPTR: + if (currtag & 1) { + TRACE (("ERRNOSTRPTR),invalid")); + } else { + unsigned long ulTmp; + if (currtag & 0x8000) + { /* SBTM_GETREF */ + ulTmp = get_long(currval); + } + else + { /* SBTM_GETVAL */ + ulTmp = currval; + } + TRACE (("ERRNOSTRPTR),%d", ulTmp)); + if (ulTmp < number_sys_error) + { + tagcopy (currtag, currval, tagptr, &errnotextptrs[ulTmp]); + } + else + { + tagcopy (currtag, currval, tagptr, &strErrptr); + } + } + break; + case SBTC_HERRNOSTRPTR: + if (currtag & 1) { + TRACE (("HERRNOSTRPTR),invalid")); + } else { + unsigned long ulTmp; + if (currtag & 0x8000) + { /* SBTM_GETREF */ + ulTmp = get_long(currval); + } + else + { /* SBTM_GETVAL */ + ulTmp = currval; + } + TRACE (("HERRNOSTRPTR),%d", ulTmp)); + if (ulTmp < number_host_error) + { + tagcopy (currtag, currval, tagptr, &herrnotextptrs[ulTmp]); + } + else + { + tagcopy (currtag, currval, tagptr, &strErrptr); + } + } + break; + case SBTC_ERRNOBYTEPTR: + TRACE (("SBTC_ERRNOBYTEPTR),0x%lx", currval)); + tagcopy (currtag, currval, tagptr, &sb->errnoptr); + sb->errnosize = 1; + break; + case SBTC_ERRNOWORDPTR: + TRACE (("SBTC_ERRNOWORDPTR),0x%lx", currval)); + tagcopy (currtag, currval, tagptr, &sb->errnoptr); + sb->errnosize = 2; + break; + case SBTC_ERRNOLONGPTR: + TRACE (("SBTC_ERRNOLONGPTR),0x%lx", currval)); + tagcopy (currtag, currval, tagptr, &sb->errnoptr); + sb->errnosize = 4; + break; + case SBTC_HERRNOLONGPTR: + TRACE (("SBTC_HERRNOLONGPTR),0x%lx", currval)); + tagcopy (currtag, currval, tagptr, &sb->herrnoptr); + sb->herrnosize = 4; + break; + default: + write_log ("bsdsocket: WARNING: Unsupported tag type (%x) in SocketBaseTagList()\n", currtag); + } + } else { + TRACE (("TAG_UNKNOWN(0x%x)", currtag)); + } + } + + TRACE ((",")); + tagptr += 8; + } + + done: + TRACE ((") -> %d\n", tagsprocessed)); + + return tagsprocessed; +} + +static uae_u32 bsdsocklib_GetSocketEvents (void) +{ + SB = SOCKETBASE; + int i; + int flags; + uae_u32 ptr = m68k_areg (regs, 0); + + TRACE (("GetSocketEvents(0x%x) -> ", ptr)); + + for (i = sb->dtablesize; i--; sb->eventindex++) { + if (sb->eventindex >= sb->dtablesize) + sb->eventindex = 0; + + if (sb->mtable[sb->eventindex]) { + flags = sb->ftable[sb->eventindex] & SET_ALL; + if (flags) { + sb->ftable[sb->eventindex] &= ~SET_ALL; + put_long (m68k_areg (regs, 0), flags >> 8); + TRACE (("%d (0x%x)\n", sb->eventindex + 1, flags >> 8)); + return sb->eventindex; // xxx + } + } + } + + TRACE (("-1\n")); + return -1; +} + +static uae_u32 bsdsocklib_getdtablesize (void) +{ + return get_socketbase ()->dtablesize; +} + +static uae_u32 bsdsocklib_null (void) +{ + return 0; +} + +extern uae_u32 sockfuncvecs[]; + +static uae_u32 bsdsocklib_init (void) +{ + uae_u32 tmp1; + int i; + write_log ("Creating UAE bsdsocket.library 4.1\n"); + if (SockLibBase) + bsdlib_reset (); + + m68k_areg (regs, 0) = functable; + m68k_areg (regs, 1) = datatable; + m68k_areg (regs, 2) = 0; + m68k_dreg (regs, 0) = LIBRARY_SIZEOF; + m68k_dreg (regs, 1) = 0; + tmp1 = CallLib (m68k_areg (regs, 6), -0x54); + + if (!tmp1) { + write_log ("bsdoscket: FATAL: Cannot create bsdsocket.library!\n"); + return 0; + } + m68k_areg (regs, 1) = tmp1; + CallLib (m68k_areg (regs, 6), -0x18c); + SockLibBase = tmp1; +#if 0 + m68k_areg (regs, 1) = ds ("dos.library"); + m68k_dreg (regs, 0) = 0; + dosbase = CallLib (m68k_areg (regs, 6), -552); + printf ("%08lx\n", dosbase); +#endif + + /* Install error strings in Amiga memory */ + tmp1 = 0; + for (i = number_sys_error; i--;) + tmp1 += strlen (errortexts[i])+1; + + for (i = number_host_error; i--;) + tmp1 += strlen (herrortexts[i])+1; + + tmp1 += strlen(strErr)+1; + + m68k_dreg (regs, 0) = tmp1; + m68k_dreg (regs, 1) = 0; + tmp1 = CallLib (get_long (4), -0xC6); + + if (!tmp1) { + write_log ("bsdsocket: FATAL: Ran out of memory while creating bsdsocket.library!\n"); + return 0; + } + for (i = 0; i < (int) (number_sys_error); i++) + errnotextptrs[i] = addstr (&tmp1, errortexts[i]); + + for (i = 0; i < (int) (number_host_error); i++) + herrnotextptrs[i] = addstr (&tmp1, herrortexts[i]); + + strErrptr = addstr (&tmp1, strErr); + + /* @@@ someone please implement a proper interrupt handler setup here :) */ + tmp1 = here (); + calltrap (deftrap2 (bsdsock_int_handler, TRAPFLAG_EXTRA_STACK | TRAPFLAG_NO_RETVAL, "")); + dw (0x4ef9); + dl (get_long (regs.vbr + 0x78)); + put_long (regs.vbr + 0x78, tmp1); + + m68k_dreg (regs, 0) = 1; + return 0; +} + +void bsdlib_reset (void) +{ + SB, *nsb; + int i; + + SockLibBase = 0; + + for (sb = socketbases; sb; sb = nsb) { + nsb = sb->next; + + host_sbcleanup (sb); + + free (sb->dtable); + free (sb->ftable); + + free (sb); + } + + socketbases = NULL; + sbsigqueue = NULL; + + for (i = 0; i < SOCKPOOLSIZE; i++) { + if (sockpoolids[i] != UNIQUE_ID) { + sockpoolids[i] = UNIQUE_ID; + host_closesocketquick (sockpoolsocks[i]); + } + } + + host_sbreset (); +} + +uae_u32 (*sockfuncs[])(void) = { + bsdsocklib_init, bsdsocklib_Open, bsdsocklib_Close, bsdsocklib_Expunge, + bsdsocklib_socket, bsdsocklib_bind, bsdsocklib_listen, bsdsocklib_accept, + bsdsocklib_connect, bsdsocklib_sendto, bsdsocklib_send, bsdsocklib_recvfrom, bsdsocklib_recv, + bsdsocklib_shutdown, bsdsocklib_setsockopt, bsdsocklib_getsockopt, bsdsocklib_getsockname, + bsdsocklib_getpeername, bsdsocklib_IoctlSocket, bsdsocklib_CloseSocket, bsdsocklib_WaitSelect, + bsdsocklib_SetSocketSignals, bsdsocklib_SetDTableSize, bsdsocklib_ObtainSocket, bsdsocklib_ReleaseSocket, + bsdsocklib_ReleaseCopyOfSocket, bsdsocklib_Errno, bsdsocklib_SetErrnoPtr, bsdsocklib_Inet_NtoA, + bsdsocklib_inet_addr, bsdsocklib_Inet_LnaOf, bsdsocklib_Inet_NetOf, bsdsocklib_Inet_MakeAddr, + bsdsocklib_inet_network, bsdsocklib_gethostbyname, bsdsocklib_gethostbyaddr, bsdsocklib_getnetbyname, + bsdsocklib_getnetbyaddr, bsdsocklib_getservbyname, bsdsocklib_getservbyport, bsdsocklib_getprotobyname, + bsdsocklib_getprotobynumber, bsdsocklib_vsyslog, bsdsocklib_Dup2Socket, bsdsocklib_sendmsg, + bsdsocklib_recvmsg, bsdsocklib_gethostname, bsdsocklib_gethostid, bsdsocklib_SocketBaseTagList, + bsdsocklib_GetSocketEvents +}; + +uae_u32 sockfuncvecs[sizeof (sockfuncs) / sizeof (*sockfuncs)]; + +void bsdlib_install (void) +{ + uae_u32 resname, resid; + uae_u32 begin, end; + uae_u32 func_place, data_place, init_place; + int i; + + if (!init_socket_layer ()) + return; + + memset (sockpoolids, UNIQUE_ID, sizeof (sockpoolids)); + + resname = ds ("bsdsocket.library"); + resid = ds ("UAE bsdsocket.library 4.1"); + + begin = here (); + dw (0x4AFC); /* RT_MATCHWORD */ + dl (begin); /* RT_MATCHTAG */ + dl (0); /* RT_ENDSKIP */ + dw (0x8004); /* RTF_AUTOINIT, RT_VERSION */ + dw (0x0970); /* NT_LIBRARY, RT_PRI */ + dl (resname); /* RT_NAME */ + dl (resid); /* RT_IDSTRING */ + dl (here () + 4); /* RT_INIT */ + dl (512); + func_place = here (); + dl (0); + data_place = here (); + dl (0); + init_place = here (); + dl (0); + + for (i = 0; i < (int) (sizeof (sockfuncs) / sizeof (sockfuncs[0])); i++) { + sockfuncvecs[i] = here (); + calltrap (deftrap2 (sockfuncs[i], TRAPFLAG_EXTRA_STACK, "")); + dw (RTS); + } + + /* FuncTable */ + functable = here (); + for (i = 1; i < 4; i++) + dl (sockfuncvecs[i]); /* Open / Close / Expunge */ + dl (EXPANSION_nullfunc); /* Null */ + for (i = 4; i < (int) (sizeof (sockfuncs) / sizeof (sockfuncs[0])); i++) + dl (sockfuncvecs[i]); + dl (0xFFFFFFFF); /* end of table */ + + /* DataTable */ + datatable = here (); + dw (0xE000); /* INITBYTE */ + dw (0x0008); /* LN_TYPE */ + dw (0x0900); /* NT_LIBRARY */ + dw (0xC000); /* INITLONG */ + dw (0x000A); /* LN_NAME */ + dl (resname); + dw (0xE000); /* INITBYTE */ + dw (0x000E); /* LIB_FLAGS */ + dw (0x0600); /* LIBF_SUMUSED | LIBF_CHANGED */ + dw (0xD000); /* INITWORD */ + dw (0x0014); /* LIB_VERSION */ + dw (0x0004); + dw (0xD000); + dw (0x0016); /* LIB_REVISION */ + dw (0x0001); + dw (0xC000); + dw (0x0018); /* LIB_IDSTRING */ + dl (resid); + dl (0x00000000); /* end of table */ + + end = here (); + + org (begin + 6); /* Load END value */ + dl (end); + + org (data_place); + dl (datatable); + + org (func_place); + dl (functable); + + org (init_place); + dl (*sockfuncvecs); + + org (end); +} + +#endif /* ! BSDSOCKET */ diff --git a/build68k.c b/build68k.c new file mode 100755 index 00000000..13848b2d --- /dev/null +++ b/build68k.c @@ -0,0 +1,247 @@ +/* + * UAE - The Un*x Amiga Emulator + * + * Read 68000 CPU specs from file "table68k" and build table68k.c + * + * Copyright 1995,1996 Bernd Schmidt + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include +#include + +#include "readcpu.h" + +static FILE *tablef; +static int nextch = 0; + +static void getnextch(void) +{ + do { + nextch = fgetc(tablef); + if (nextch == '%') { + do { + nextch = fgetc(tablef); + } while (nextch != EOF && nextch != '\n'); + } + } while (nextch != EOF && isspace(nextch)); +} + +static int nextchtohex(void) +{ + switch (isupper (nextch) ? tolower (nextch) : nextch) { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + case 'a': return 10; + case 'b': return 11; + case 'c': return 12; + case 'd': return 13; + case 'e': return 14; + case 'f': return 15; + default: abort(); + } +} + +int main(int argc, char **argv) +{ + int no_insns = 0; + + printf ("#include \"sysconfig.h\"\n"); + printf ("#include \"sysdeps.h\"\n"); + printf ("#include \"readcpu.h\"\n"); + printf ("struct instr_def defs68k[] = {\n"); +#if 0 + tablef = fopen("table68k","r"); + if (tablef == NULL) { + fprintf(stderr, "table68k not found\n"); + exit(1); + } +#else + tablef = stdin; +#endif + getnextch(); + while (nextch != EOF) { + int cpulevel, plevel, sduse; + int i; + + char patbits[16]; + char opcstr[256]; + int bitpos[16]; + int flagset[5], flaguse[5]; + + unsigned int bitmask,bitpattern; + int n_variable; + + n_variable = 0; + bitmask = bitpattern = 0; + memset (bitpos, 0, sizeof(bitpos)); + for(i=0; i<16; i++) { + int currbit; + bitmask <<= 1; + bitpattern <<= 1; + + switch (nextch) { + case '0': currbit = bit0; bitmask |= 1; break; + case '1': currbit = bit1; bitmask |= 1; bitpattern |= 1; break; + case 'c': currbit = bitc; break; + case 'C': currbit = bitC; break; + case 'f': currbit = bitf; break; + case 'i': currbit = biti; break; + case 'I': currbit = bitI; break; + case 'j': currbit = bitj; break; + case 'J': currbit = bitJ; break; + case 'k': currbit = bitk; break; + case 'K': currbit = bitK; break; + case 's': currbit = bits; break; + case 'S': currbit = bitS; break; + case 'd': currbit = bitd; break; + case 'D': currbit = bitD; break; + case 'r': currbit = bitr; break; + case 'R': currbit = bitR; break; + case 'z': currbit = bitz; break; + case 'p': currbit = bitp; break; + default: abort(); + } + if (!(bitmask & 1)) { + bitpos[n_variable] = currbit; + n_variable++; + } + + if (nextch == '0' || nextch == '1') + bitmask |= 1; + if (nextch == '1') + bitpattern |= 1; + patbits[i] = nextch; + getnextch(); + } + + while (isspace(nextch) || nextch == ':') /* Get CPU and privilege level */ + getnextch(); + + switch (nextch) { + case '0': cpulevel = 0; break; + case '1': cpulevel = 1; break; + case '2': cpulevel = 2; break; + case '3': cpulevel = 3; break; + case '4': cpulevel = 4; break; + case '5': cpulevel = 5; break; + case '6': cpulevel = 6; break; + case '7': cpulevel = 7; break; + default: abort(); + } + getnextch(); + + switch (nextch) { + case '0': plevel = 0; break; + case '1': plevel = 1; break; + case '2': plevel = 2; break; + case '3': plevel = 3; break; + default: abort(); + } + getnextch(); + + while (isspace(nextch)) /* Get flag set information */ + getnextch(); + + if (nextch != ':') + abort(); + + for(i = 0; i < 5; i++) { + getnextch(); + switch(nextch){ + case '-': flagset[i] = fa_unset; break; + case '/': flagset[i] = fa_isjmp; break; + case '+': flagset[i] = fa_isbranch; break; + case '0': flagset[i] = fa_zero; break; + case '1': flagset[i] = fa_one; break; + case 'x': flagset[i] = fa_dontcare; break; + case '?': flagset[i] = fa_unknown; break; + default: flagset[i] = fa_set; break; + } + } + + getnextch(); + while (isspace(nextch)) + getnextch(); + + if (nextch != ':') /* Get flag used information */ + abort(); + + for(i = 0; i < 5; i++) { + getnextch(); + switch(nextch){ + case '-': flaguse[i] = fu_unused; break; + case '/': flaguse[i] = fu_isjmp; break; + case '+': flaguse[i] = fu_maybecc; break; + case '?': flaguse[i] = fu_unknown; break; + default: flaguse[i] = fu_used; break; + } + } + + getnextch(); + while (isspace(nextch)) + getnextch(); + + if (nextch != ':') /* Get source/dest usage information */ + abort(); + + getnextch(); + sduse = nextchtohex() << 4; + getnextch(); + sduse |= nextchtohex(); + + getnextch(); + while (isspace(nextch)) + getnextch(); + + if (nextch != ':') + abort(); + + fgets(opcstr, 250, tablef); + getnextch(); + { + int j; + /* Remove superfluous spaces from the string */ + char *opstrp = opcstr, *osendp; + int slen = 0; + + while (isspace(*opstrp)) + opstrp++; + + osendp = opstrp; + while (*osendp) { + if (!isspace (*osendp)) + slen = osendp - opstrp + 1; + osendp++; + } + opstrp[slen] = 0; + + if (no_insns > 0) + printf(",\n"); + no_insns++; + printf("{ %d, %d, {", bitpattern, n_variable); + for (j = 0; j < 16; j++) { + printf("%d", bitpos[j]); + if (j < 15) + printf(","); + } + printf ("}, %d, %d, %d, { ", bitmask, cpulevel, plevel); + for(i = 0; i < 5; i++) { + printf("{ %d, %d }%c ", flaguse[i], flagset[i], i == 4 ? ' ' : ','); + } + printf("}, %d, \"%s\"}", sduse, opstrp); + } + } + printf("};\nint n_defs68k = %d;\n", no_insns); + return 0; +} diff --git a/catweasel.c b/catweasel.c new file mode 100755 index 00000000..e35370b3 --- /dev/null +++ b/catweasel.c @@ -0,0 +1,777 @@ + +#include "sysconfig.h" +#include "sysdeps.h" + +#ifdef CATWEASEL + +#include "config.h" +#include "options.h" +#include "memory.h" +#include "ioport.h" +#include "catweasel.h" +#include "uae.h" + +struct catweasel_contr cwc; + +static int cwhsync; +static int handshake; + +void catweasel_hsync (void) +{ + if (cwhsync <= 0) + return; + cwhsync--; + if (cwhsync == 0) { + if (handshake) + ioport_write (currprefs.catweasel_io + 0xd0, 0); + handshake = 0; + } +} + +int catweasel_read_joystick (uae_u8 *dir, uae_u8 *buttons) +{ + if (cwc.type != CATWEASEL_TYPE_MK3) + return 0; + *dir = ioport_read (currprefs.catweasel_io + 0xc0); + *buttons = ioport_read (currprefs.catweasel_io + 0xc8); + return 1; +} + +int catweasel_read_keyboard (uae_u8 *keycode) +{ + uae_u8 v; + if (cwc.type != CATWEASEL_TYPE_MK3) + return 0; + v = ioport_read (currprefs.catweasel_io + 0xd4); + if (!(v & 0x80)) + return 0; + if (handshake) + return 0; + *keycode = ioport_read (currprefs.catweasel_io + 0xd0); + ioport_write (currprefs.catweasel_io + 0xd0, 0); + handshake = 1; + cwhsync = 10; + return 1; +} + +uae_u32 catweasel_do_bget (uaecptr addr) +{ + if (cwc.type == CATWEASEL_TYPE_MK3) { + if ((currprefs.catweasel_io & 3) == 0 && addr >= 0xc0 && addr <= 0xfc) + return ioport_read (currprefs.catweasel_io + addr); + } else { + if (addr >= currprefs.catweasel_io && addr <= currprefs.catweasel_io + 8) { + return ioport_read (addr & 0x3ff); + } else if(addr >= 0x10000 + currprefs.catweasel_io && addr <= 0x10000 + currprefs.catweasel_io) { + return ioport_read (addr & 0x3ff); + } else if ((addr & 0x3ff) < 0x200 || (addr & 0x3ff) >= 0x400) { + write_log("catweasel_bget @%08.8X!\n",addr); + } + } + return 0; +} + +void catweasel_do_bput (uaecptr addr, uae_u32 b) +{ + if (cwc.type == CATWEASEL_TYPE_MK3) { + if ((currprefs.catweasel_io & 3) == 0 && addr >= 0xc0 && addr <= 0xfc) + ioport_write (currprefs.catweasel_io + addr, b); + } else { + if (addr >= currprefs.catweasel_io && addr <= currprefs.catweasel_io + 8) { + ioport_write (addr & 0x3ff, b); + } else if(addr >= 0x10000 + currprefs.catweasel_io && addr <= 0x10000 + currprefs.catweasel_io) { + ioport_write (addr & 0x3ff, b); + } else if ((addr & 0x3ff) < 0x200 || (addr & 0x3ff) >= 0x400) { + write_log("catweasel_bput @%08.8X=%02.2X!\n",addr,b); + } + } +} + +int catweasel_init (void) +{ + if (!currprefs.catweasel_io) + return 0; + if (!ioport_init ()) + return 0; + cwc.type = currprefs.catweasel_io >= 0x400 ? CATWEASEL_TYPE_MK3 : CATWEASEL_TYPE_MK1; + cwc.iobase = currprefs.catweasel_io; + catweasel_init_controller (&cwc); + return 1; +} + +void catweasel_free (void) +{ + if (!currprefs.catweasel_io) + return; + ioport_free (); +} + +#define outb(v,port) ioport_write(port,v) +#define inb(port) ioport_read(port) + +#define LONGEST_TRACK 16000 + +static uae_u8 mfmbuf[LONGEST_TRACK * 4]; +static uae_u8 tmpmfmbuffer[LONGEST_TRACK * 2]; + +static int bitshiftcompare(uae_u8 *src,int bit,int len,uae_u8 *comp) +{ + uae_u8 b; + int ones,zeros,len2; + + ones=zeros=0; + len2=len; + while(len--) { + b = (comp[0] << bit) | (comp[1] >> (8 - bit)); + if(b != *src) return 1; + if(b==0x00) zeros++; + if(b==0xff) ones++; + src++; + comp++; + } + if(ones==len2||zeros==len2) return 1; + return 0; +} + +static uae_u8 *mergepieces(uae_u8 *start,int len,int bits,uae_u8 *sync) +{ + uae_u8 *dst=tmpmfmbuffer; + uae_u8 b; + int size; + int shift; + + size=len-(sync-start); + memcpy(dst,sync,size); + dst+=size; + b=start[len]; + b&=~(255>>bits); + b|=start[0]>>bits; + *dst++=b; + shift=8-bits; + while(start<=sync+2000) { + *dst++=(start[0]<>(8-shift)); + start++; + } + return tmpmfmbuffer; +} + +#define SCANOFFSET 1 /* scanning range in bytes, -SCANOFFSET to SCANOFFSET */ +#define SCANOFFSET2 20 +#define SCANLENGHT 200 /* scanning length in bytes */ + +static uae_u8* scantrack(uae_u8 *sync1,uae_u8 *sync2,int *trackbytes,int *trackbits) +{ + int i,bits,bytes,matched; + uae_u8 *sync2bak=sync2; + + sync1+=SCANOFFSET2; + sync2+=SCANOFFSET2; + while(sync1 < sync2bak - 2*SCANOFFSET - SCANOFFSET2 - SCANLENGHT) { + matched=0x7fff; + for(i=0;i<2*SCANOFFSET*8;i++) { + bits=i&7; + bytes=-SCANOFFSET+(i>>3); + if(!bitshiftcompare(sync1,bits,SCANLENGHT,sync2+bytes)) { + if(matched==0x7fff) { + matched=i; + } else { + break; + } + } + } + if(matched!=0x7fff && i>=2*SCANOFFSET*8) { + bits=matched&7; + bytes=-SCANOFFSET+(matched>>3); + *trackbytes=sync2+bytes-sync1; + *trackbits=bits; + return mergepieces(sync1,*trackbytes,*trackbits,sync2bak); + } + sync1++; + sync2++; + } + return 0; +} + +static unsigned char threshtab[128]; + +static void codec_makethresh(int trycnt, const unsigned char *origt, unsigned char *t, int numthresh) +{ + static unsigned char tab[10] = { 0, 0, 0, 0, -1, -2, 1, 2, -1, 1 }; + + if (trycnt >= sizeof (tab)) + trycnt = sizeof (tab) - 1; + while(numthresh--) + t[numthresh] = origt[numthresh] + tab[trycnt]; +} + +static void codec_init_threshtab(int trycnt, const unsigned char *origt) +{ + static unsigned char old_thresholds[2] = { 0, 0 }; + unsigned char t[2]; + int a, i; + + codec_makethresh(trycnt, origt, t, 2); + + if(*(unsigned short*)t == *(unsigned short*)old_thresholds) + return; + + for(i=0,a=2; i<128; i++) { + if(i == t[0] || i == t[1]) + a++; + threshtab[i] = a; + } + + *(unsigned short*)&old_thresholds = *(unsigned short*)t; +} + +static __inline__ void CWSetCReg(catweasel_contr *c, unsigned char clear, unsigned char set) +{ + c->control_register = (c->control_register & ~clear) | set; + outb(c->control_register, c->io_sr); +} + +static void CWTriggerStep(catweasel_contr *c) +{ + CWSetCReg(c, c->crm_step, 0); + CWSetCReg(c, 0, c->crm_step); +} + +void catweasel_init_controller(catweasel_contr *c) +{ + int i, j; + + if(!c->iobase) + return; + + switch(c->type) { + case CATWEASEL_TYPE_MK1: + c->crm_sel0 = 1 << 5; + c->crm_sel1 = 1 << 4; + c->crm_mot0 = 1 << 3; + c->crm_mot1 = 1 << 7; + c->crm_dir = 1 << 1; + c->crm_step = 1 << 0; + c->srm_trk0 = 1 << 4; + c->srm_dchg = 1 << 5; + c->srm_writ = 1 << 1; + c->io_sr = c->iobase + 2; + c->io_mem = c->iobase; + break; + case CATWEASEL_TYPE_MK3: + c->crm_sel0 = 1 << 2; + c->crm_sel1 = 1 << 3; + c->crm_mot0 = 1 << 1; + c->crm_mot1 = 1 << 5; + c->crm_dir = 1 << 4; + c->crm_step = 1 << 7; + c->srm_trk0 = 1 << 2; + c->srm_dchg = 1 << 5; + c->srm_writ = 1 << 6; + c->srm_dskready = 1 << 4; + c->io_sr = c->iobase + 0xe8; + c->io_mem = c->iobase + 0xe0; + break; + default: + return; + } + + c->control_register = 255; + + /* select all drives, step inside */ + CWSetCReg(c, c->crm_dir | c->crm_sel0 | c->crm_sel1, 0); + for(i=0;i<2;i++) { + c->drives[i].number = i; + c->drives[i].contr = c; + c->drives[i].diskindrive = 0; + + /* select only the respective drive, step to track 0 */ + if(i == 0) { + CWSetCReg(c, c->crm_sel0, c->crm_dir | c->crm_sel1); + } else { + CWSetCReg(c, c->crm_sel1, c->crm_dir | c->crm_sel0); + } + + for(j = 0; j < 86 && (inb(c->io_sr) & c->srm_trk0); j++) { + CWTriggerStep(c); + sleep_millis(6); + } + + if(j < 86) { + c->drives[i].type = 1; + c->drives[i].track = 0; + } else { + c->drives[i].type = 0; + } + } + c->drives[0].sel = c->crm_sel0; + c->drives[0].mot = c->crm_mot0; + c->drives[1].sel = c->crm_sel1; + c->drives[1].mot = c->crm_mot1; + CWSetCReg(c, 0, c->crm_sel0 | c->crm_sel1); /* deselect all drives */ +} + +void catweasel_free_controller(catweasel_contr *c) +{ + if(!c->iobase) + return; + + /* all motors off, deselect all drives */ + CWSetCReg(c, 0, c->crm_mot0 | c->crm_mot1 | c->crm_sel0 | c->crm_sel1); +} + +void catweasel_set_motor(catweasel_drive *d, int on) +{ + CWSetCReg(d->contr, d->sel, 0); + if (on) + CWSetCReg(d->contr, d->mot, 0); + else + CWSetCReg(d->contr, 0, d->mot); + CWSetCReg(d->contr, 0, d->sel); +} + +int catweasel_step(catweasel_drive *d, int dir) +{ + catweasel_contr *c = d->contr; + CWSetCReg(c, d->sel, 0); + if (dir > 0) + CWSetCReg(c, c->crm_dir, 0); + else + CWSetCReg(c, 0, c->crm_dir); + CWTriggerStep (c); + CWSetCReg(c, 0, d->sel); + d->track += dir > 0 ? 1 : -1; + return 1; +} + +int catweasel_disk_changed(catweasel_drive *d) +{ + int ret; + CWSetCReg(d->contr, d->sel, 0); + ret = (inb(d->contr->io_sr) & d->contr->srm_dchg) ? 0 : 1; + CWSetCReg(d->contr, 0, d->sel); + return ret; +} + +int catweasel_diskready(catweasel_drive *d) +{ + int ret; + CWSetCReg(d->contr, d->sel, 0); + ret = (inb(d->contr->io_sr) & d->contr->srm_dskready) ? 0 : 1; + CWSetCReg(d->contr, 0, d->sel); + return ret; +} + +int catweasel_track0(catweasel_drive *d) +{ + int ret; + CWSetCReg(d->contr, d->sel, 0); + ret = (inb(d->contr->io_sr) & d->contr->srm_trk0) ? 0 : 1; + CWSetCReg(d->contr, 0, d->sel); + if (ret) + d->track = 0; + return ret; +} + +int catweasel_write_protected(catweasel_drive *d) +{ + int ret; + CWSetCReg(d->contr, d->sel, 0); + ret = !(inb(d->contr->io_sr) & 8); + CWSetCReg(d->contr, 0, d->sel); + return ret; +} + +uae_u8 catweasel_read_byte(catweasel_drive *d) +{ + return inb(d->contr->io_mem); +} + +static const unsigned char amiga_thresholds[] = { 0x22, 0x30 }; // 27, 38 for 5.25" + +#define FLOPPY_WRITE_LEN 6250 + +#define MFMMASK 0x55555555 +static uae_u32 getmfmlong (uae_u16 * mbuf) +{ + return (uae_u32)(((*mbuf << 16) | *(mbuf + 1)) & MFMMASK); +} + +static int drive_write_adf_amigados (uae_u16 *mbuf, uae_u16 *mend, uae_u8 *writebuffer, int track) +{ + int i, secwritten = 0; + uae_u32 odd, even, chksum, id, dlong; + uae_u8 *secdata; + uae_u8 secbuf[544]; + char sectable[22]; + int num_sectors = 11; + int ec = 0; + + memset (sectable, 0, sizeof (sectable)); + mend -= (4 + 16 + 8 + 512); + while (secwritten < num_sectors) { + int trackoffs; + + do { + while (*mbuf++ != 0x4489) { + if (mbuf >= mend) { + ec = 1; + goto err; + } + } + } while (*mbuf++ != 0x4489); + + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 2); + mbuf += 4; + id = (odd << 1) | even; + + trackoffs = (id & 0xff00) >> 8; + if (trackoffs > 10) { + ec = 2; + goto err; + } + chksum = odd ^ even; + for (i = 0; i < 4; i++) { + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 8); + mbuf += 2; + + dlong = (odd << 1) | even; + if (dlong) { + ec = 6; + goto err; + } + chksum ^= odd ^ even; + } /* could check here if the label is nonstandard */ + mbuf += 8; + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 2); + mbuf += 4; + if (((odd << 1) | even) != chksum) { + ec = 3; + goto err; + } + odd = (id & 0x00ff0000) >> 16; + if (odd != track) { + ec = 7; + goto err; + } + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 2); + mbuf += 4; + chksum = (odd << 1) | even; + secdata = secbuf + 32; + for (i = 0; i < 128; i++) { + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 256); + mbuf += 2; + dlong = (odd << 1) | even; + *secdata++ = dlong >> 24; + *secdata++ = dlong >> 16; + *secdata++ = dlong >> 8; + *secdata++ = dlong; + chksum ^= odd ^ even; + } + mbuf += 256; + if (chksum) { + ec = 4; + goto err; + } + sectable[trackoffs] = 1; + secwritten++; + memcpy (writebuffer + trackoffs * 512, secbuf + 32, 512); + } + if (secwritten == 0 || secwritten < 0) { + ec = 5; + goto err; + } + return 0; +err: + write_log ("mfm decode error %d. secwritten=%d\n", ec, secwritten); + for (i = 0; i < num_sectors; i++) + write_log ("%d:%d ", i, sectable[i]); + write_log ("\n"); + return ec; +} + +static void mfmcode (uae_u16 * mfm, int words) +{ + uae_u32 lastword = 0; + + while (words--) { + uae_u32 v = *mfm; + uae_u32 lv = (lastword << 16) | v; + uae_u32 nlv = 0x55555555 & ~lv; + uae_u32 mfmbits = (nlv << 1) & (nlv >> 1); + + *mfm++ = v | mfmbits; + lastword = v; + } +} + +#define FLOPPY_GAP_LEN 360 + +static int amigados_mfmcode (uae_u8 *src, uae_u16 *dst, int num_secs, int track) +{ + int sec; + memset (dst, 0xaa, FLOPPY_GAP_LEN * 2); + + for (sec = 0; sec < num_secs; sec++) { + uae_u8 secbuf[544]; + int i; + uae_u16 *mfmbuf = dst + 544 * sec + FLOPPY_GAP_LEN; + uae_u32 deven, dodd; + uae_u32 hck = 0, dck = 0; + + secbuf[0] = secbuf[1] = 0x00; + secbuf[2] = secbuf[3] = 0xa1; + secbuf[4] = 0xff; + secbuf[5] = track; + secbuf[6] = sec; + secbuf[7] = num_secs - sec; + + for (i = 8; i < 24; i++) + secbuf[i] = 0; + + mfmbuf[0] = mfmbuf[1] = 0xaaaa; + mfmbuf[2] = mfmbuf[3] = 0x4489; + + memcpy (secbuf + 32, src + sec * 512, 512); + deven = ((secbuf[4] << 24) | (secbuf[5] << 16) + | (secbuf[6] << 8) | (secbuf[7])); + dodd = deven >> 1; + deven &= 0x55555555; + dodd &= 0x55555555; + + mfmbuf[4] = dodd >> 16; + mfmbuf[5] = dodd; + mfmbuf[6] = deven >> 16; + mfmbuf[7] = deven; + + for (i = 8; i < 48; i++) + mfmbuf[i] = 0xaaaa; + for (i = 0; i < 512; i += 4) { + deven = ((secbuf[i + 32] << 24) | (secbuf[i + 33] << 16) + | (secbuf[i + 34] << 8) | (secbuf[i + 35])); + dodd = deven >> 1; + deven &= 0x55555555; + dodd &= 0x55555555; + mfmbuf[(i >> 1) + 32] = dodd >> 16; + mfmbuf[(i >> 1) + 33] = dodd; + mfmbuf[(i >> 1) + 256 + 32] = deven >> 16; + mfmbuf[(i >> 1) + 256 + 33] = deven; + } + + for (i = 4; i < 24; i += 2) + hck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1]; + + deven = dodd = hck; + dodd >>= 1; + mfmbuf[24] = dodd >> 16; + mfmbuf[25] = dodd; + mfmbuf[26] = deven >> 16; + mfmbuf[27] = deven; + + for (i = 32; i < 544; i += 2) + dck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1]; + + deven = dodd = dck; + dodd >>= 1; + mfmbuf[28] = dodd >> 16; + mfmbuf[29] = dodd; + mfmbuf[30] = deven >> 16; + mfmbuf[31] = deven; + mfmcode (mfmbuf + 4, 544 - 4); + + } + return (num_secs * 544 + FLOPPY_GAP_LEN) * 2 * 8; +} + +static uae_u16 amigamfmbuffer[LONGEST_TRACK]; +static uae_u8 amigabuffer[512*22]; + +/* search and align to 0x4489 WORDSYNC markers */ +static int isamigatrack(uae_u8 *mfmdata, uae_u8 *mfmdatae, uae_u16 *mfmdst, int track) +{ + uae_u16 *dst = amigamfmbuffer; + int len; + int shift, syncshift, sync,ret; + uae_u32 l; + uae_u16 w; + + sync = syncshift = shift = 0; + len = (mfmdatae - mfmdata) * 8; + if (len > LONGEST_TRACK * 8) + len = LONGEST_TRACK * 8; + while (len--) { + l = (mfmdata[0] << 16) | (mfmdata[1] << 8) | (mfmdata[2] << 0); + w = l >> (8 - shift); + if (w == 0x4489) { + sync = 1; + syncshift = 0; + } + if (sync) { + if (syncshift == 0) *dst++ = w; + syncshift ++; + if (syncshift == 16) syncshift = 0; + } + shift++; + if (shift == 8) { + mfmdata++; + shift = 0; + } + } + if (sync) { + ret=drive_write_adf_amigados (amigamfmbuffer, dst, amigabuffer, track); + if(!ret) + return amigados_mfmcode (amigabuffer, mfmdst, 11, track); + write_log ("decode error %d\n", ret); + } else { + write_log ("decode error: no sync found\n"); + } + return 0; +} + + + +int catweasel_fillmfm (catweasel_drive *d, uae_u16 *mfm, int side, int clock, int rawmode) +{ + int i, j, oldsync, syncs[10], synccnt, endcnt; + uae_u32 tt1 = 0, tt2 = 0; + uae_u8 *p1; + int bytes = 0, bits = 0; + static int lasttrack, trycnt; + + if (cwc.type == 0) + return 0; + if (d->contr->control_register & d->mot) + return 0; + if (!catweasel_read (d, side, 1, rawmode)) + return 0; + if(d->contr->type == CATWEASEL_TYPE_MK1) { + inb(d->contr->iobase + 1); + inb(d->contr->io_mem); /* ignore first byte */ + } else { + outb(0, d->contr->iobase + 0xe4); + } + catweasel_read_byte (d); + if (lasttrack == d->track) + trycnt++; + else + trycnt = 0; + lasttrack = d->track; + codec_init_threshtab(trycnt, amiga_thresholds); + i = 0; j = 0; + synccnt = 0; + oldsync = -1; + endcnt = 0; + while (j < LONGEST_TRACK * 4) { + uae_u8 b = catweasel_read_byte (d); + if (b >= 250) { + if (b == 255 - endcnt) { + endcnt++; + if (endcnt == 5) + break; + } else + endcnt = 0; + } + if (rawmode) { + if (b & 0x80) { + if (oldsync < j) { + syncs[synccnt++] = j; + oldsync = j + 300; + } + } + if (synccnt >= 3 && j > oldsync) + break; + } + b = threshtab[b & 0x7f]; + tt1 = (tt1 << b) + 1; + tt2 += b; + + if (tt2 >= 16) { + tt2 -= 16; + mfmbuf[j++] = tt1 >> (tt2 + 8); + mfmbuf[j++] = tt1 >> tt2; + } + i++; + } + write_log ("cyl=%d, side=%d, length %d, syncs %d\n", d->track, side, j, synccnt); + if (rawmode) { + if (synccnt >= 3) { + p1 = scantrack (mfmbuf + syncs[1], mfmbuf + syncs[2], &bytes, &bits); + if (p1) { + j = 0; + for (i = 0; i < bytes + 2; i+=2) { + mfm[j++] = (p1[i] << 8) | p1[i + 1]; + } + return bytes * 8 + bits; + } + } + } else { + return isamigatrack (mfmbuf, mfmbuf + j, mfm, d->track * 2 + side); + } + return 0; +} + +int catweasel_read(catweasel_drive *d, int side, int clock, int rawmode) +{ + int iobase = d->contr->iobase; + + CWSetCReg(d->contr, d->sel, 0); + if(d->contr->type == CATWEASEL_TYPE_MK1) { + CWSetCReg(d->contr, 1<<2, (!side)<<2); /* set disk side */ + + inb(iobase+1); /* ra reset */ + outb(clock*128, iobase+3); + + inb(iobase+1); + inb(iobase+0); +// inb(iobase+0); +// outb(0, iobase+3); /* don't store index pulse */ + + inb(iobase+1); + + inb(iobase+7); /* start reading */ + sleep_millis(rawmode ? 550 : 225); + outb(0, iobase+1); /* stop reading, don't reset RAM pointer */ + + outb(128, iobase+0); /* add data end mark */ + outb(128, iobase+0); + + inb(iobase+1); /* Reset RAM pointer */ + } else { + CWSetCReg(d->contr, 1<<6, (!side)<<6); /* set disk side */ + + outb(0, iobase + 0xe4); /* Reset memory pointer */ + switch(clock) { + case 0: /* 28MHz */ + outb(128, iobase + 0xec); + break; + case 1: /* 14MHz */ + outb(0, iobase + 0xec); + break; + } + inb(iobase + 0xe0); + inb(iobase + 0xe0); + outb(0, iobase + 0xec); /* no IRQs, no MFM predecode */ + inb(iobase + 0xe0); + outb(0, iobase + 0xec); /* don't store index pulse */ + + outb(0, iobase + 0xe4); /* Reset memory pointer */ + inb(iobase + 0xf0); /* start reading */ + sleep_millis(rawmode ? 550 : 225); + inb(iobase + 0xe4); /* stop reading, don't reset RAM pointer */ + + outb(255, iobase + 0xe0); /* add data end mark */ + outb(254, iobase + 0xe0); /* add data end mark */ + outb(253, iobase + 0xe0); /* add data end mark */ + outb(252, iobase + 0xe0); /* add data end mark */ + outb(251, iobase + 0xe0); /* add data end mark */ + outb(0, iobase + 0xe4); /* Reset memory pointer */ + } + CWSetCReg(d->contr, 0, d->sel); + return 1; +} + +#endif \ No newline at end of file diff --git a/cdrom.c b/cdrom.c new file mode 100755 index 00000000..f171b3c3 --- /dev/null +++ b/cdrom.c @@ -0,0 +1,236 @@ +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" + +/* CDROM MODE 1 EDC/ECC code (from Reed-Solomon library by Heiko Eissfeldt) */ + +/*****************************************************************/ +/* */ +/* CRC LOOKUP TABLE */ +/* ================ */ +/* The following CRC lookup table was generated automagically */ +/* by the Rocksoft^tm Model CRC Algorithm Table Generation */ +/* Program V1.0 using the following model parameters: */ +/* */ +/* Width : 4 bytes. */ +/* Poly : 0x8001801BL */ +/* Reverse : TRUE. */ +/* */ +/* For more information on the Rocksoft^tm Model CRC Algorithm, */ +/* see the document titled "A Painless Guide to CRC Error */ +/* Detection Algorithms" by Ross Williams */ +/* (ross@guest.adelaide.edu.au.). This document is likely to be */ +/* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft". */ +/* */ +/*****************************************************************/ + +static uae_u32 EDC_crctable[256] = +{ + 0x00000000L, 0x90910101L, 0x91210201L, 0x01B00300L, + 0x92410401L, 0x02D00500L, 0x03600600L, 0x93F10701L, + 0x94810801L, 0x04100900L, 0x05A00A00L, 0x95310B01L, + 0x06C00C00L, 0x96510D01L, 0x97E10E01L, 0x07700F00L, + 0x99011001L, 0x09901100L, 0x08201200L, 0x98B11301L, + 0x0B401400L, 0x9BD11501L, 0x9A611601L, 0x0AF01700L, + 0x0D801800L, 0x9D111901L, 0x9CA11A01L, 0x0C301B00L, + 0x9FC11C01L, 0x0F501D00L, 0x0EE01E00L, 0x9E711F01L, + 0x82012001L, 0x12902100L, 0x13202200L, 0x83B12301L, + 0x10402400L, 0x80D12501L, 0x81612601L, 0x11F02700L, + 0x16802800L, 0x86112901L, 0x87A12A01L, 0x17302B00L, + 0x84C12C01L, 0x14502D00L, 0x15E02E00L, 0x85712F01L, + 0x1B003000L, 0x8B913101L, 0x8A213201L, 0x1AB03300L, + 0x89413401L, 0x19D03500L, 0x18603600L, 0x88F13701L, + 0x8F813801L, 0x1F103900L, 0x1EA03A00L, 0x8E313B01L, + 0x1DC03C00L, 0x8D513D01L, 0x8CE13E01L, 0x1C703F00L, + 0xB4014001L, 0x24904100L, 0x25204200L, 0xB5B14301L, + 0x26404400L, 0xB6D14501L, 0xB7614601L, 0x27F04700L, + 0x20804800L, 0xB0114901L, 0xB1A14A01L, 0x21304B00L, + 0xB2C14C01L, 0x22504D00L, 0x23E04E00L, 0xB3714F01L, + 0x2D005000L, 0xBD915101L, 0xBC215201L, 0x2CB05300L, + 0xBF415401L, 0x2FD05500L, 0x2E605600L, 0xBEF15701L, + 0xB9815801L, 0x29105900L, 0x28A05A00L, 0xB8315B01L, + 0x2BC05C00L, 0xBB515D01L, 0xBAE15E01L, 0x2A705F00L, + 0x36006000L, 0xA6916101L, 0xA7216201L, 0x37B06300L, + 0xA4416401L, 0x34D06500L, 0x35606600L, 0xA5F16701L, + 0xA2816801L, 0x32106900L, 0x33A06A00L, 0xA3316B01L, + 0x30C06C00L, 0xA0516D01L, 0xA1E16E01L, 0x31706F00L, + 0xAF017001L, 0x3F907100L, 0x3E207200L, 0xAEB17301L, + 0x3D407400L, 0xADD17501L, 0xAC617601L, 0x3CF07700L, + 0x3B807800L, 0xAB117901L, 0xAAA17A01L, 0x3A307B00L, + 0xA9C17C01L, 0x39507D00L, 0x38E07E00L, 0xA8717F01L, + 0xD8018001L, 0x48908100L, 0x49208200L, 0xD9B18301L, + 0x4A408400L, 0xDAD18501L, 0xDB618601L, 0x4BF08700L, + 0x4C808800L, 0xDC118901L, 0xDDA18A01L, 0x4D308B00L, + 0xDEC18C01L, 0x4E508D00L, 0x4FE08E00L, 0xDF718F01L, + 0x41009000L, 0xD1919101L, 0xD0219201L, 0x40B09300L, + 0xD3419401L, 0x43D09500L, 0x42609600L, 0xD2F19701L, + 0xD5819801L, 0x45109900L, 0x44A09A00L, 0xD4319B01L, + 0x47C09C00L, 0xD7519D01L, 0xD6E19E01L, 0x46709F00L, + 0x5A00A000L, 0xCA91A101L, 0xCB21A201L, 0x5BB0A300L, + 0xC841A401L, 0x58D0A500L, 0x5960A600L, 0xC9F1A701L, + 0xCE81A801L, 0x5E10A900L, 0x5FA0AA00L, 0xCF31AB01L, + 0x5CC0AC00L, 0xCC51AD01L, 0xCDE1AE01L, 0x5D70AF00L, + 0xC301B001L, 0x5390B100L, 0x5220B200L, 0xC2B1B301L, + 0x5140B400L, 0xC1D1B501L, 0xC061B601L, 0x50F0B700L, + 0x5780B800L, 0xC711B901L, 0xC6A1BA01L, 0x5630BB00L, + 0xC5C1BC01L, 0x5550BD00L, 0x54E0BE00L, 0xC471BF01L, + 0x6C00C000L, 0xFC91C101L, 0xFD21C201L, 0x6DB0C300L, + 0xFE41C401L, 0x6ED0C500L, 0x6F60C600L, 0xFFF1C701L, + 0xF881C801L, 0x6810C900L, 0x69A0CA00L, 0xF931CB01L, + 0x6AC0CC00L, 0xFA51CD01L, 0xFBE1CE01L, 0x6B70CF00L, + 0xF501D001L, 0x6590D100L, 0x6420D200L, 0xF4B1D301L, + 0x6740D400L, 0xF7D1D501L, 0xF661D601L, 0x66F0D700L, + 0x6180D800L, 0xF111D901L, 0xF0A1DA01L, 0x6030DB00L, + 0xF3C1DC01L, 0x6350DD00L, 0x62E0DE00L, 0xF271DF01L, + 0xEE01E001L, 0x7E90E100L, 0x7F20E200L, 0xEFB1E301L, + 0x7C40E400L, 0xECD1E501L, 0xED61E601L, 0x7DF0E700L, + 0x7A80E800L, 0xEA11E901L, 0xEBA1EA01L, 0x7B30EB00L, + 0xE8C1EC01L, 0x7850ED00L, 0x79E0EE00L, 0xE971EF01L, + 0x7700F000L, 0xE791F101L, 0xE621F201L, 0x76B0F300L, + 0xE541F401L, 0x75D0F500L, 0x7460F600L, 0xE4F1F701L, + 0xE381F801L, 0x7310F900L, 0x72A0FA00L, 0xE231FB01L, + 0x71C0FC00L, 0xE151FD01L, 0xE0E1FE01L, 0x7070FF00L +}; + +/*****************************************************************/ +/* End of CRC Lookup Table */ +/*****************************************************************/ + +static uae_u8 rs_l12_alog[255] = { + 1, 2, 4, 8,16,32,64,128,29,58,116,232,205,135,19,38,76,152,45,90,180,117,234,201,143, 3, 6,12,24,48,96,192,157,39,78,156,37,74,148,53,106,212,181,119,238,193,159,35,70,140, 5,10,20,40,80,160,93,186,105,210,185,111,222,161,95,190,97,194,153,47,94,188,101,202,137,15,30,60,120,240,253,231,211,187,107,214,177,127,254,225,223,163,91,182,113,226,217,175,67,134,17,34,68,136,13,26,52,104,208,189,103,206,129,31,62,124,248,237,199,147,59,118,236,197,151,51,102,204,133,23,46,92,184,109,218,169,79,158,33,66,132,21,42,84,168,77,154,41,82,164,85,170,73,146,57,114,228,213,183,115,230,209,191,99,198,145,63,126,252,229,215,179,123,246,241,255,227,219,171,75,150,49,98,196,149,55,110,220,165,87,174,65,130,25,50,100,200,141, 7,14,28,56,112,224,221,167,83,166,81,162,89,178,121,242,249,239,195,155,43,86,172,69,138, 9,18,36,72,144,61,122,244,245,247,243,251,235,203,139,11,22,44,88,176,125,250,233,207,131,27,54,108,216,173,71,142,}; +static uae_u8 rs_l12_log[256] = { + 0, 0, 1,25, 2,50,26,198, 3,223,51,238,27,104,199,75, 4,100,224,14,52,141,239,129,28,193,105,248,200, 8,76,113, 5,138,101,47,225,36,15,33,53,147,142,218,240,18,130,69,29,181,194,125,106,39,249,185,201,154, 9,120,77,228,114,166, 6,191,139,98,102,221,48,253,226,152,37,179,16,145,34,136,54,208,148,206,143,150,219,189,241,210,19,92,131,56,70,64,30,66,182,163,195,72,126,110,107,58,40,84,250,133,186,61,202,94,155,159,10,21,121,43,78,212,229,172,115,243,167,87, 7,112,192,247,140,128,99,13,103,74,222,237,49,197,254,24,227,165,153,119,38,184,180,124,17,68,146,217,35,32,137,46,55,63,209,91,149,188,207,205,144,135,151,178,220,252,190,97,242,86,211,171,20,42,93,158,132,60,57,83,71,109,65,162,31,45,67,216,183,123,164,118,196,23,73,236,127,12,111,246,108,161,59,82,41,157,85,170,251,96,134,177,187,204,62,90,203,89,95,176,156,169,160,81,11,245,22,235,122,117,44,215,79,174,213,233,230,231,173,232,116,214,244,234,168,80,88,175,}; +static uae_u8 DQ[2][43] = { +{190,96,250,132,59,81,159,154,200,7,111,245,10,20,41,156,168,79,173,231,229,171,210,240,17,67,215,43,120,8,199,74,102,220,251,95,175,87,166,113,75,198,25,}, +{97,251,133,60,82,160,155,201,8,112,246,11,21,42,157,169,80,174,232,230,172,211,241,18,68,216,44,121,9,200,75,103,221,252,96,176,88,167,114,76,199,26,1,}, +}; +static uae_u8 DP[2][24] = { +{231,229,171,210,240,17,67,215,43,120,8,199,74,102,220,251,95,175,87,166,113,75,198,25,}, +{230,172,211,241,18,68,216,44,121,9,200,75,103,221,252,96,176,88,167,114,76,199,26,1,}, +}; + +/* data sector definitions for RSPC */ +/* user data bytes per frame */ +#define L2_RAW (1024*2) +/* parity bytes for 16 bit units */ +#define L2_Q (26*2*2) +#define L2_P (43*2*2) +#define RS_L12_BITS 8 + +static uae_u32 build_edc(uae_u8 *inout, int from, int upto) +{ + uae_u8 *p = inout + from; + uae_u32 result = 0; + for (; from <= upto; from++) + result = EDC_crctable[(result ^ *p++) & 0xff] ^ (result >> 8); + return result; +} + +static void encode_L2_Q(uae_u8 *inout) +{ + uae_u8 *Q; + int i,j; + + Q = inout + 4 + L2_RAW + 4 + 8 + L2_P; + memset(Q, 0, L2_Q); + for (j = 0; j < 26; j++) { + for (i = 0; i < 43; i++) { + uae_u8 data; + /* LSB */ + data = inout[(j*43*2+i*2*44) % (4 + L2_RAW + 4 + 8 + L2_P)]; + if (data != 0) { + uae_u32 base = rs_l12_log[data]; + uae_u32 sum = base + DQ[0][i]; + if (sum >= ((1 << RS_L12_BITS)-1)) + sum -= (1 << RS_L12_BITS)-1; + Q[0] ^= rs_l12_alog[sum]; + sum = base + DQ[1][i]; + if (sum >= ((1 << RS_L12_BITS)-1)) + sum -= (1 << RS_L12_BITS)-1; + Q[26*2] ^= rs_l12_alog[sum]; + } + /* MSB */ + data = inout[(j*43*2+i*2*44+1) % (4 + L2_RAW + 4 + 8 + L2_P)]; + if (data != 0) { + uae_u32 base = rs_l12_log[data]; + uae_u32 sum = base+DQ[0][i]; + if (sum >= ((1 << RS_L12_BITS)-1)) + sum -= (1 << RS_L12_BITS)-1; + Q[1] ^= rs_l12_alog[sum]; + sum = base + DQ[1][i]; + if (sum >= ((1 << RS_L12_BITS)-1)) + sum -= (1 << RS_L12_BITS)-1; + Q[26*2+1] ^= rs_l12_alog[sum]; + } + } + Q += 2; + } +} + +static void encode_L2_P(uae_u8 inout[4 + L2_RAW + 4 + 8 + L2_P]) +{ + uae_u8 *P; + int i,j; + + P = inout + 4 + L2_RAW + 4 + 8; + memset(P, 0, L2_P); + for (j = 0; j < 43; j++) { + for (i = 0; i < 24; i++) { + uae_u8 data; + /* LSB */ + data = inout[i*2*43]; + if (data != 0) { + uae_u32 base = rs_l12_log[data]; + uae_u32 sum = base + DP[0][i]; + if (sum >= ((1 << RS_L12_BITS)-1)) + sum -= (1 << RS_L12_BITS)-1; + P[0] ^= rs_l12_alog[sum]; + sum = base + DP[1][i]; + if (sum >= ((1 << RS_L12_BITS)-1)) + sum -= (1 << RS_L12_BITS)-1; + P[43*2] ^= rs_l12_alog[sum]; + } + /* MSB */ + data = inout[i*2*43+1]; + if (data != 0) { + uae_u32 base = rs_l12_log[data]; + uae_u32 sum = base + DP[0][i]; + if (sum >= ((1 << RS_L12_BITS)-1)) + sum -= (1 << RS_L12_BITS)-1; + P[1] ^= rs_l12_alog[sum]; + sum = base + DP[1][i]; + if (sum >= ((1 << RS_L12_BITS)-1)) + sum -= (1 << RS_L12_BITS)-1; + P[43*2+1] ^= rs_l12_alog[sum]; + } + } + P += 2; + inout += 2; + } +} + +static uae_u8 tobcd (uae_u8 v) +{ + return ((v / 10) << 4) | (v % 10); +} + +void encode_l2 (uae_u8 *p, int address) +{ + uae_u32 v; + + p[0] = 0x00; + memset (p + 1, 0xff, 11); + p[12] = tobcd ((uae_u8)(address / (60 * 75))); + p[13] = tobcd ((uae_u8)((address / 75) % 60)); + p[14] = tobcd ((uae_u8)(address % 75)); + p[15] = 1; /* MODE1 */ + v = build_edc (p, 0, 16 + 2048 - 1); + p[2064 + 0] = (uae_u8) (v >> 0); + p[2064 + 1] = (uae_u8) (v >> 8); + p[2064 + 2] = (uae_u8) (v >> 16); + p[2064 + 3] = (uae_u8) (v >> 24); + memset (p + 2064 + 4, 0, 8); + encode_L2_P (p + 12); + encode_L2_Q (p + 12); +} diff --git a/cfgfile.c b/cfgfile.c new file mode 100755 index 00000000..ff08248d --- /dev/null +++ b/cfgfile.c @@ -0,0 +1,1878 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Config file handling + * This still needs some thought before it's complete... + * + * Copyright 1998 Brian King, Bernd Schmidt + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include + +#include "config.h" +#include "options.h" +#include "threaddep/thread.h" +#include "uae.h" +#include "autoconf.h" +#include "events.h" +#include "custom.h" +#include "inputdevice.h" +#include "gfxfilter.h" +#include "savestate.h" +#include "memory.h" + +static int config_newfilesystem; +static struct strlist *temp_lines; + +/* @@@ need to get rid of this... just cut part of the manual and print that + * as a help text. */ +struct cfg_lines +{ + const char *config_label, *config_help; +}; + +static struct cfg_lines opttable[] = +{ + {"help", "Prints this help" }, + {"config_description", "" }, + {"config_info", "" }, + {"use_gui", "Enable the GUI? If no, then goes straight to emulator" }, + {"use_debugger", "Enable the debugger?" }, + {"cpu_speed", "can be max, real, or a number between 1 and 20" }, + {"cpu_type", "Can be 68000, 68010, 68020, 68020/68881" }, + {"cpu_compatible", "yes enables compatibility-mode" }, + {"cpu_24bit_addressing", "must be set to 'no' in order for Z3mem or P96mem to work" }, + {"autoconfig", "yes = add filesystems and extra ram" }, + {"log_illegal_mem", "print illegal memory access by Amiga software?" }, + {"fastmem_size", "Size in megabytes of fast-memory" }, + {"chipmem_size", "Size in megabytes of chip-memory" }, + {"bogomem_size", "Size in megabytes of bogo-memory at 0xC00000" }, + {"a3000mem_size", "Size in megabytes of A3000 memory" }, + {"gfxcard_size", "Size in megabytes of Picasso96 graphics-card memory" }, + {"z3mem_size", "Size in megabytes of Zorro-III expansion memory" }, + {"gfx_test_speed", "Test graphics speed?" }, + {"gfx_framerate", "Print every nth frame" }, + {"gfx_width", "Screen width" }, + {"gfx_height", "Screen height" }, + {"gfx_refreshrate", "Fullscreen refresh rate" }, + {"gfx_vsync", "Sync screen refresh to refresh rate" }, + {"gfx_lores", "Treat display as lo-res?" }, + {"gfx_linemode", "Can be none, double, or scanlines" }, + {"gfx_fullscreen_amiga", "Amiga screens are fullscreen?" }, + {"gfx_fullscreen_picasso", "Picasso screens are fullscreen?" }, + {"gfx_correct_aspect", "Correct aspect ratio?" }, + {"gfx_center_horizontal", "Center display horizontally?" }, + {"gfx_center_vertical", "Center display vertically?" }, + {"gfx_colour_mode", "" }, + {"32bit_blits", "Enable 32 bit blitter emulation" }, + {"immediate_blits", "Perform blits immediately" }, + {"show_leds", "LED display" }, + {"keyboard_leds", "Keyboard LEDs" }, + {"gfxlib_replacement", "Use graphics.library replacement?" }, + {"sound_output", "" }, + {"sound_frequency", "" }, + {"sound_bits", "" }, + {"sound_channels", "" }, + {"sound_max_buff", "" }, + {"comp_trustbyte", "How to access bytes in compiler (direct/indirect/indirectKS/afterPic" }, + {"comp_trustword", "How to access words in compiler (direct/indirect/indirectKS/afterPic" }, + {"comp_trustlong", "How to access longs in compiler (direct/indirect/indirectKS/afterPic" }, + {"comp_nf", "Whether to optimize away flag generation where possible" }, + {"comp_fpu", "Whether to provide JIT FPU emulation" }, + {"compforcesettings", "Whether to force the JIT compiler settings" }, + {"cachesize", "How many MB to use to buffer translated instructions"}, + {"override_dga_address","Address from which to map the frame buffer (upper 16 bits) (DANGEROUS!)"}, + {"avoid_cmov", "Set to yes on machines that lack the CMOV instruction" }, + {"avoid_dga", "Set to yes if the use of DGA extension creates problems" }, + {"avoid_vid", "Set to yes if the use of the Vidmode extension creates problems" }, + {"parallel_on_demand", "" }, + {"serial_on_demand", "" }, + {"scsi", "scsi.device emulation" }, + {"joyport0", "" }, + {"joyport1", "" }, + {"pci_devices", "List of PCI devices to make visible to the emulated Amiga" }, + {"kickstart_rom_file", "Kickstart ROM image, (C) Copyright Amiga, Inc." }, + {"kickstart_ext_rom_file", "Extended Kickstart ROM image, (C) Copyright Amiga, Inc." }, + {"kickstart_key_file", "Key-file for encrypted ROM images (from Cloanto's Amiga Forever)" }, + {"flash_ram_file", "Flash/battery backed RAM image file." }, + {"cart_file", "Freezer cartridge ROM image file." }, + {"floppy0", "Diskfile for drive 0" }, + {"floppy1", "Diskfile for drive 1" }, + {"floppy2", "Diskfile for drive 2" }, + {"floppy3", "Diskfile for drive 3" }, + {"hardfile", "access,sectors, surfaces, reserved, blocksize, path format" }, + {"filesystem", "access,'Amiga volume-name':'host directory path' - where 'access' can be 'read-only' or 'read-write'" }, + {"catweasel_io","Catweasel board io base address" } +}; + +static const char *guimode1[] = { "no", "yes", "nowait", 0 }; +static const char *guimode2[] = { "false", "true", "nowait", 0 }; +static const char *guimode3[] = { "0", "1", "nowait", 0 }; +static const char *csmode[] = { "ocs", "ecs_agnus", "ecs_denise", "ecs", "aga", 0 }; +static const char *linemode1[] = { "none", "double", "scanlines", 0 }; +static const char *linemode2[] = { "n", "d", "s", 0 }; +static const char *speedmode[] = { "max", "real", 0 }; +static const char *cpumode[] = { + "68000", "68000", "68010", "68010", "68ec020", "68020", "68ec020/68881", "68020/68881", + "68040", "68040", "xxxxx", "xxxxx", "68060", "68060", 0 +}; +static const char *portmode[] = { "joy0", "joy1", "mouse", "kbd1", "kbd2", "kbd3", 0 }; +static const char *colormode1[] = { "8bit", "15bit", "16bit", "8bit_dither", "4bit_dither", "32bit", 0 }; +static const char *colormode2[] = { "8", "15", "16", "8d", "4d", "32", 0 }; +static const char *soundmode1[] = { "none", "interrupts", "normal", "exact", 0 }; +static const char *soundmode2[] = { "none", "interrupts", "good", "best", 0 }; +static const char *centermode1[] = { "none", "simple", "smart", 0 }; +static const char *centermode2[] = { "false", "true", "smart", 0 }; +static const char *stereomode1[] = { "mono", "stereo", "mixed", 0 }; +static const char *stereomode2[] = { "m", "s", "x", 0 }; +static const char *stereomode3[] = { "1", "2", "3", 0 }; +static const char *interpolmode[] = { "none", "rh", "crux", 0 }; +static const char *collmode[] = { "none", "sprites", "playfields", "full", 0 }; +static const char *compmode[] = { "direct", "indirect", "indirectKS", "afterPic", 0 }; +static const char *flushmode[] = { "soft", "hard", 0 }; +static const char *kbleds[] = { "none", "POWER", "DF0", "DF1", "DF2", "DF3", "HD", "CD", 0 }; +static const char *soundfiltermode[] = { "off", "emulated", "on", 0 }; +#ifdef GFXFILTER +static const char *filtermode1[] = { "no_16", "bilinear_16", "no_32", "bilinear_32", 0 }; +static const char *filtermode2[] = { "0x", "1x", "2x", "3x", "4x", 0 }; +#endif + +static const char *obsolete[] = { + "accuracy","gfx_opengl","gfx_32bit_blits","32bit_blits", + "gfx_immediate_blits","gfx_ntsc","win32", + "sound_pri_cutoff", "sound_pri_time", 0 }; + +#define UNEXPANDED "$(FILE_PATH)" + +static int match_string (const char *table[], const char *str) +{ + int i; + for (i = 0; table[i] != 0; i++) + if (strcasecmp (table[i], str) == 0) + return i; + return -1; +} + +char *cfgfile_subst_path (const char *path, const char *subst, const char *file) +{ + /* @@@ use strcasecmp for some targets. */ + if (strlen (path) > 0 && strncmp (file, path, strlen (path)) == 0) { + int l; + char *p = xmalloc (strlen (file) + strlen (subst) + 2); + strcpy (p, subst); + l = strlen (p); + while (l > 0 && p[l - 1] == '/') + p[--l] = '\0'; + l = strlen (path); + while (file[l] == '/') + l++; + strcat (p, "/"); strcat (p, file + l); + return p; + } + return my_strdup (file); +} + +void cfgfile_write (FILE *f, char *format,...) +{ + va_list parms; + char tmp[1000]; + + va_start (parms, format); + vsprintf (tmp, format, parms); + fprintf (f, tmp); + va_end (parms); +} + +void save_options (FILE *f, struct uae_prefs *p, int type) +{ + struct strlist *sl; + char *str; + int i; + + cfgfile_write (f, "config_description=%s\n", p->description); + cfgfile_write (f, "config_hardware=%s\n", (type & CONFIG_TYPE_HARDWARE) ? "true" : "false"); + cfgfile_write (f, "config_host=%s\n", (type & CONFIG_TYPE_HOST) ? "true" : "false"); + if (p->info[0]) + cfgfile_write (f, "config_info=%s\n", p->info); + cfgfile_write (f, "config_version=%d.%d.%d\n", UAEMAJOR, UAEMINOR, UAESUBREV); + + for (sl = p->all_lines; sl; sl = sl->next) { + if (sl->unknown) + cfgfile_write (f, "%s=%s\n", sl->option, sl->value); + } + + cfgfile_write (f, "%s.rom_path=%s\n", TARGET_NAME, p->path_rom); + cfgfile_write (f, "%s.floppy_path=%s\n", TARGET_NAME, p->path_floppy); + cfgfile_write (f, "%s.hardfile_path=%s\n", TARGET_NAME, p->path_hardfile); + + target_save_options (f, p); + + cfgfile_write (f, "use_gui=%s\n", guimode1[p->start_gui]); + cfgfile_write (f, "use_debugger=%s\n", p->start_debugger ? "true" : "false"); + str = cfgfile_subst_path (p->path_rom, UNEXPANDED, p->romfile); + cfgfile_write (f, "kickstart_rom_file=%s\n", str); + free (str); + str = cfgfile_subst_path (p->path_rom, UNEXPANDED, p->romextfile); + cfgfile_write (f, "kickstart_ext_rom_file=%s\n", str); + free (str); + str = cfgfile_subst_path (p->path_rom, UNEXPANDED, p->keyfile); + cfgfile_write (f, "kickstart_key_file=%s\n", str); + free (str); + str = cfgfile_subst_path (p->path_rom, UNEXPANDED, p->flashfile); + cfgfile_write (f, "flash_file=%s\n", str); + free (str); + str = cfgfile_subst_path (p->path_rom, UNEXPANDED, p->cartfile); + cfgfile_write (f, "cart_file=%s\n", str); + free (str); + cfgfile_write (f, "kickshifter=%s\n", p->kickshifter ? "true" : "false"); + + p->nr_floppies = 4; + for (i = 0; i < 4; i++) { + str = cfgfile_subst_path (p->path_floppy, UNEXPANDED, p->df[i]); + cfgfile_write (f, "floppy%d=%s\n", i, str); + free (str); + cfgfile_write (f, "floppy%dtype=%d\n", i, p->dfxtype[i]); + cfgfile_write (f, "floppy%dsound=%d\n", i, p->dfxclick[i]); + if (p->dfxclick[i] < 0 && p->dfxclickexternal[i][0]) + cfgfile_write (f, "floppy%dsoundext=%s\n", i, p->dfxclickexternal[i]); + if (p->dfxtype[i] < 0 && p->nr_floppies > i) + p->nr_floppies = i; + } + for (i = 0; i < MAX_SPARE_DRIVES; i++) { + if (p->dfxlist[i][0]) + cfgfile_write (f, "diskimage%d=%s\n", i, p->dfxlist[i]); + } + + cfgfile_write (f, "nr_floppies=%d\n", p->nr_floppies); + cfgfile_write (f, "floppy_speed=%d\n", p->floppy_speed); + cfgfile_write (f, "floppy_volume=%d\n", p->dfxclickvolume); + cfgfile_write (f, "parallel_on_demand=%s\n", p->parallel_demand ? "true" : "false"); + cfgfile_write (f, "serial_on_demand=%s\n", p->serial_demand ? "true" : "false"); + cfgfile_write (f, "serial_hardware_ctsrts=%s\n", p->serial_hwctsrts ? "true" : "false"); + cfgfile_write (f, "serial_direct=%s\n", p->serial_direct ? "true" : "false"); + cfgfile_write (f, "scsi=%s\n", p->scsi ? "true" : "false"); + + cfgfile_write (f, "sound_output=%s\n", soundmode1[p->produce_sound]); + cfgfile_write (f, "sound_bits=%d\n", p->sound_bits); + cfgfile_write (f, "sound_channels=%s\n", stereomode1[p->stereo + p->mixed_stereo]); + cfgfile_write (f, "sound_max_buff=%d\n", p->sound_maxbsiz); + cfgfile_write (f, "sound_frequency=%d\n", p->sound_freq); + cfgfile_write (f, "sound_interpol=%s\n", interpolmode[p->sound_interpol]); + cfgfile_write (f, "sound_adjust=%d\n", p->sound_adjust); + cfgfile_write (f, "sound_filter=%s\n", soundfiltermode[p->sound_filter]); + cfgfile_write (f, "sound_volume=%d\n", p->sound_volume); + + cfgfile_write (f, "comp_trustbyte=%s\n", compmode[p->comptrustbyte]); + cfgfile_write (f, "comp_trustword=%s\n", compmode[p->comptrustword]); + cfgfile_write (f, "comp_trustlong=%s\n", compmode[p->comptrustlong]); + cfgfile_write (f, "comp_trustnaddr=%s\n", compmode[p->comptrustnaddr]); + cfgfile_write (f, "comp_nf=%s\n", p->compnf ? "true" : "false"); + cfgfile_write (f, "comp_constjump=%s\n", p->comp_constjump ? "true" : "false"); + cfgfile_write (f, "comp_oldsegv=%s\n", p->comp_oldsegv ? "true" : "false"); + + cfgfile_write (f, "comp_flushmode=%s\n", flushmode[p->comp_hardflush]); + cfgfile_write (f, "compforcesettings=%s\n", p->compforcesettings ? "true" : "false"); + cfgfile_write (f, "compfpu=%s\n", p->compfpu ? "true" : "false"); + cfgfile_write (f, "comp_midopt=%s\n", p->comp_midopt ? "true" : "false"); + cfgfile_write (f, "comp_lowopt=%s\n", p->comp_lowopt ? "true" : "false"); + cfgfile_write (f, "avoid_cmov=%s\n", p->avoid_cmov ? "true" : "false" ); + cfgfile_write (f, "avoid_dga=%s\n", p->avoid_dga ? "true" : "false" ); + cfgfile_write (f, "avoid_vid=%s\n", p->avoid_vid ? "true" : "false" ); + cfgfile_write (f, "cachesize=%d\n", p->cachesize); + if (p->override_dga_address) + cfgfile_write (f, "override_dga_address=0x%08x\n", p->override_dga_address); + + cfgfile_write (f, "joyport0=%s\n", portmode[p->jport0]); + cfgfile_write (f, "joyport1=%s\n", portmode[p->jport1]); + + cfgfile_write (f, "bsdsocket_emu=%s\n", p->socket_emu ? "true" : "false"); + + cfgfile_write (f, "synchronize_clock=%s\n", p->tod_hack ? "yes" : "no"); + cfgfile_write (f, "maprom=0x%x\n", p->maprom); + + cfgfile_write (f, "gfx_display=%d\n", p->gfx_display); + cfgfile_write (f, "gfx_framerate=%d\n", p->gfx_framerate); + cfgfile_write (f, "gfx_width=%d\n", p->gfx_width_win); /* compatibility with old versions */ + cfgfile_write (f, "gfx_height=%d\n", p->gfx_height_win); /* compatibility with old versions */ + cfgfile_write (f, "gfx_width_windowed=%d\n", p->gfx_width_win); + cfgfile_write (f, "gfx_height_windowed=%d\n", p->gfx_height_win); + cfgfile_write (f, "gfx_width_fullscreen=%d\n", p->gfx_width_fs); + cfgfile_write (f, "gfx_height_fullscreen=%d\n", p->gfx_height_fs); + cfgfile_write (f, "gfx_refreshrate=%d\n", p->gfx_refreshrate); + cfgfile_write (f, "gfx_vsync=%s\n", p->gfx_vsync ? "true" : "false"); + cfgfile_write (f, "gfx_lores=%s\n", p->gfx_lores ? "true" : "false"); + cfgfile_write (f, "gfx_linemode=%s\n", linemode1[p->gfx_linedbl]); + cfgfile_write (f, "gfx_correct_aspect=%s\n", p->gfx_correct_aspect ? "true" : "false"); + cfgfile_write (f, "gfx_fullscreen_amiga=%s\n", p->gfx_afullscreen ? "true" : "false"); + cfgfile_write (f, "gfx_fullscreen_picasso=%s\n", p->gfx_pfullscreen ? "true" : "false"); + cfgfile_write (f, "gfx_center_horizontal=%s\n", centermode1[p->gfx_xcenter]); + cfgfile_write (f, "gfx_center_vertical=%s\n", centermode1[p->gfx_ycenter]); + cfgfile_write (f, "gfx_colour_mode=%s\n", colormode1[p->color_mode]); + +#ifdef GFXFILTER + if (p->gfx_filter > 0) { + int i = 0; + struct uae_filter *uf; + while (uaefilters[i].name) { + uf = &uaefilters[i]; + if (uf->type == p->gfx_filter) { + cfgfile_write (f, "gfx_filter=%s\n", uf->cfgname); + if (uf->type == p->gfx_filter) { + if (uf->x[0]) { + cfgfile_write (f, "gfx_filter_mode=%s\n", filtermode1[p->gfx_filter_filtermode]); + } else { + int mt[4], i = 0; + if (uf->x[1]) mt[i++] = 1; + if (uf->x[2]) mt[i++] = 2; + if (uf->x[3]) mt[i++] = 3; + if (uf->x[4]) mt[i++] = 4; + cfgfile_write (f, "gfx_filter_mode=%dx\n", mt[p->gfx_filter_filtermode]); + } + } + } + i++; + } + } else { + cfgfile_write (f, "gfx_filter=no\n"); + } + + cfgfile_write (f, "gfx_filter_vert_zoom=%d\n", p->gfx_filter_vert_zoom); + cfgfile_write (f, "gfx_filter_horiz_zoom=%d\n", p->gfx_filter_horiz_zoom); + cfgfile_write (f, "gfx_filter_vert_offset=%d\n", p->gfx_filter_vert_offset); + cfgfile_write (f, "gfx_filter_horiz_offset=%d\n", p->gfx_filter_horiz_offset); + cfgfile_write (f, "gfx_filter_scanlines=%d\n", p->gfx_filter_scanlines); + cfgfile_write (f, "gfx_filter_scanlinelevel=%d\n", p->gfx_filter_scanlinelevel); + cfgfile_write (f, "gfx_filter_scanlineratio=%d\n", p->gfx_filter_scanlineratio); +#endif + + cfgfile_write (f, "immediate_blits=%s\n", p->immediate_blits ? "true" : "false"); + cfgfile_write (f, "fast_copper=%s\n", p->fast_copper ? "true" : "false"); + cfgfile_write (f, "ntsc=%s\n", p->ntscmode ? "true" : "false"); + cfgfile_write (f, "show_leds=%s\n", p->leds_on_screen ? "true" : "false"); + cfgfile_write (f, "keyboard_leds=numlock:%s,capslock:%s,scrolllock:%s\n", + kbleds[p->keyboard_leds[0]], kbleds[p->keyboard_leds[1]], kbleds[p->keyboard_leds[2]]); + if (p->chipset_mask & CSMASK_AGA) + cfgfile_write (f, "chipset=aga\n"); + else if ((p->chipset_mask & CSMASK_ECS_AGNUS) && (p->chipset_mask & CSMASK_ECS_DENISE)) + cfgfile_write (f, "chipset=ecs\n"); + else if (p->chipset_mask & CSMASK_ECS_AGNUS) + cfgfile_write (f, "chipset=ecs_agnus\n"); + else if (p->chipset_mask & CSMASK_ECS_DENISE) + cfgfile_write (f, "chipset=ecs_denise\n"); + else + cfgfile_write (f, "chipset=ocs\n"); + cfgfile_write (f, "collision_level=%s\n", collmode[p->collision_level]); + + cfgfile_write (f, "fastmem_size=%d\n", p->fastmem_size / 0x100000); + cfgfile_write (f, "a3000mem_size=%d\n", p->a3000mem_size / 0x100000); + cfgfile_write (f, "z3mem_size=%d\n", p->z3fastmem_size / 0x100000); + cfgfile_write (f, "bogomem_size=%d\n", p->bogomem_size / 0x40000); + cfgfile_write (f, "gfxcard_size=%d\n", p->gfxmem_size / 0x100000); + cfgfile_write (f, "chipmem_size=%d\n", (p->chipmem_size == 0x40000) ? 0 : p->chipmem_size / 0x80000); + + if (p->m68k_speed > 0) + cfgfile_write (f, "finegrain_cpu_speed=%d\n", p->m68k_speed); + else + cfgfile_write (f, "cpu_speed=%s\n", p->m68k_speed == -1 ? "max" : "real"); + + cfgfile_write (f, "cpu_type=%s\n", cpumode[p->cpu_level * 2 + !p->address_space_24]); + cfgfile_write (f, "cpu_compatible=%s\n", p->cpu_compatible ? "true" : "false"); + cfgfile_write (f, "cpu_cycle_exact=%s\n", p->cpu_cycle_exact ? "true" : "false"); + cfgfile_write (f, "blitter_cycle_exact=%s\n", p->blitter_cycle_exact ? "true" : "false"); + + cfgfile_write (f, "log_illegal_mem=%s\n", p->illegal_mem ? "true" : "false"); + cfgfile_write (f, "catweasel_io=0x%x\n", p->catweasel_io); + + cfgfile_write (f, "kbd_lang=%s\n", (p->keyboard_lang == KBD_LANG_DE ? "de" + : p->keyboard_lang == KBD_LANG_DK ? "dk" + : p->keyboard_lang == KBD_LANG_ES ? "es" + : p->keyboard_lang == KBD_LANG_US ? "us" + : p->keyboard_lang == KBD_LANG_SE ? "se" + : p->keyboard_lang == KBD_LANG_FR ? "fr" + : p->keyboard_lang == KBD_LANG_IT ? "it" + : "FOO")); + + cfgfile_write (f, "state_replay=%s\n", p->statecapture ? "yes" : "no"); + cfgfile_write (f, "state_replay_rate=%d\n", p->statecapturerate); + cfgfile_write (f, "state_replay_buffer=%d\n", p->statecapturebuffersize); + +#ifdef FILESYS + write_filesys_config (currprefs.mountinfo, UNEXPANDED, p->path_hardfile, f); + if (p->filesys_no_uaefsdb) + cfgfile_write (f, "filesys_no_fsdb=%s\n", p->filesys_no_uaefsdb ? "true" : "false"); +#endif + write_inputdevice_config (p, f); + + /* Don't write gfxlib/gfx_test_speed options. */ +} + +int cfgfile_yesno (char *option, char *value, char *name, int *location) +{ + if (strcmp (option, name) != 0) + return 0; + if (strcasecmp (value, "yes") == 0 || strcasecmp (value, "y") == 0 + || strcasecmp (value, "true") == 0 || strcasecmp (value, "t") == 0) + *location = 1; + else if (strcasecmp (value, "no") == 0 || strcasecmp (value, "n") == 0 + || strcasecmp (value, "false") == 0 || strcasecmp (value, "f") == 0) + *location = 0; + else + write_log ("Option `%s' requires a value of either `yes' or `no'.\n", option); + return 1; +} + +int cfgfile_intval (char *option, char *value, char *name, int *location, int scale) +{ + int base = 10; + char *endptr; + if (strcmp (option, name) != 0) + return 0; + /* I guess octal isn't popular enough to worry about here... */ + if (value[0] == '0' && value[1] == 'x') + value += 2, base = 16; + *location = strtol (value, &endptr, base) * scale; + + if (*endptr != '\0' || *value == '\0') + write_log ("Option `%s' requires a numeric argument.\n", option); + return 1; +} + +int cfgfile_strval (char *option, char *value, char *name, int *location, const char *table[], int more) +{ + int val; + if (strcmp (option, name) != 0) + return 0; + val = match_string (table, value); + if (val == -1) { + if (more) + return 0; + + write_log ("Unknown value for option `%s'.\n", option); + return 1; + } + *location = val; + return 1; +} + +int cfgfile_string (char *option, char *value, char *name, char *location, int maxsz) +{ + if (strcmp (option, name) != 0) + return 0; + strncpy (location, value, maxsz - 1); + location[maxsz - 1] = '\0'; + return 1; +} + +static int getintval (char **p, int *result, int delim) +{ + char *value = *p; + int base = 10; + char *endptr; + char *p2 = strchr (*p, delim); + + if (p2 == 0) + return 0; + + *p2++ = '\0'; + + if (value[0] == '0' && value[1] == 'x') + value += 2, base = 16; + *result = strtol (value, &endptr, base); + *p = p2; + + if (*endptr != '\0' || *value == '\0') + return 0; + + return 1; +} + +static int getintval2 (char **p, int *result, int delim) +{ + char *value = *p; + int base = 10; + char *endptr; + char *p2 = strchr (*p, delim); + + if (p2 == 0) { + p2 = strchr (*p, 0); + if (p2 == 0) { + *p = 0; + return 0; + } + } + if (*p2 != 0) + *p2++ = '\0'; + + if (value[0] == '0' && value[1] == 'x') + value += 2, base = 16; + *result = strtol (value, &endptr, base); + *p = p2; + + if (*endptr != '\0' || *value == '\0') { + *p = 0; + return 0; + } + + return 1; +} + +static void set_chipset_mask (struct uae_prefs *p, int val) +{ + p->chipset_mask = (val == 0 ? 0 + : val == 1 ? CSMASK_ECS_AGNUS + : val == 2 ? CSMASK_ECS_DENISE + : val == 3 ? CSMASK_ECS_DENISE | CSMASK_ECS_AGNUS + : CSMASK_AGA | CSMASK_ECS_DENISE | CSMASK_ECS_AGNUS); +} + +static int cfgfile_parse_host (struct uae_prefs *p, char *option, char *value) +{ + int i; + char *section = 0; + char *tmpp; + char tmpbuf[256]; + + if (memcmp (option, "input.", 6) == 0) { + read_inputdevice_config (p, option, value); + return 1; + } + + for (tmpp = option; *tmpp != '\0'; tmpp++) + if (isupper (*tmpp)) + *tmpp = tolower (*tmpp); + tmpp = strchr (option, '.'); + if (tmpp) { + section = option; + option = tmpp + 1; + *tmpp = '\0'; + if (strcmp (section, TARGET_NAME) == 0) { + /* We special case the various path options here. */ + if (cfgfile_string (option, value, "rom_path", p->path_rom, 256) + || cfgfile_string (option, value, "floppy_path", p->path_floppy, 256) + || cfgfile_string (option, value, "hardfile_path", p->path_hardfile, 256)) + return 1; + return target_parse_option (p, option, value); + } + return 0; + } + for (i = 0; i < MAX_SPARE_DRIVES; i++) { + sprintf (tmpbuf, "diskimage%d", i); + if (cfgfile_string (option, value, tmpbuf, p->dfxlist[i], 256)) + return 1; + } + + if (cfgfile_intval (option, value, "sound_max_buff", &p->sound_maxbsiz, 1) + || cfgfile_intval (option, value, "sound_bits", &p->sound_bits, 1) + || cfgfile_intval (option, value, "state_replay_rate", &p->statecapturerate, 1) + || cfgfile_intval (option, value, "state_replay_buffer", &p->statecapturebuffersize, 1) + || cfgfile_intval (option, value, "sound_frequency", &p->sound_freq, 1) + || cfgfile_intval (option, value, "sound_adjust", &p->sound_adjust, 1) + || cfgfile_intval (option, value, "sound_volume", &p->sound_volume, 1) + + || cfgfile_intval (option, value, "gfx_display", &p->gfx_display, 1) + || cfgfile_intval (option, value, "gfx_framerate", &p->gfx_framerate, 1) + || cfgfile_intval (option, value, "gfx_width_windowed", &p->gfx_width_win, 1) + || cfgfile_intval (option, value, "gfx_height_windowed", &p->gfx_height_win, 1) + || cfgfile_intval (option, value, "gfx_width_fullscreen", &p->gfx_width_fs, 1) + || cfgfile_intval (option, value, "gfx_height_fullscreen", &p->gfx_height_fs, 1) + || cfgfile_intval (option, value, "gfx_refreshrate", &p->gfx_refreshrate, 1) + +#ifdef GFXFILTER + || cfgfile_intval (option, value, "gfx_filter_vert_zoom", &p->gfx_filter_vert_zoom, 1) + || cfgfile_intval (option, value, "gfx_filter_horiz_zoom", &p->gfx_filter_horiz_zoom, 1) + || cfgfile_intval (option, value, "gfx_filter_vert_offset", &p->gfx_filter_vert_offset, 1) + || cfgfile_intval (option, value, "gfx_filter_horiz_offset", &p->gfx_filter_horiz_offset, 1) + || cfgfile_intval (option, value, "gfx_filter_scanlines", &p->gfx_filter_scanlines, 1) + || cfgfile_intval (option, value, "gfx_filter_scanlinelevel", &p->gfx_filter_scanlinelevel, 1) + || cfgfile_intval (option, value, "gfx_filter_scanlineratio", &p->gfx_filter_scanlineratio, 1) +#endif + || cfgfile_intval (option, value, "floppy0sound", &p->dfxclick[0], 1) + || cfgfile_intval (option, value, "floppy1sound", &p->dfxclick[1], 1) + || cfgfile_intval (option, value, "floppy2sound", &p->dfxclick[2], 1) + || cfgfile_intval (option, value, "floppy3sound", &p->dfxclick[3], 1) + || cfgfile_intval (option, value, "floppy_volume", &p->dfxclickvolume, 1) + || cfgfile_intval (option, value, "override_dga_address", &p->override_dga_address, 1)) + return 1; + + if (cfgfile_string (option, value, "floppy0soundext", p->dfxclickexternal[0], 256) + || cfgfile_string (option, value, "floppy1soundext", p->dfxclickexternal[1], 256) + || cfgfile_string (option, value, "floppy2soundext", p->dfxclickexternal[2], 256) + || cfgfile_string (option, value, "floppy3soundext", p->dfxclickexternal[3], 256) + || cfgfile_string (option, value, "config_info", p->info, 256) + || cfgfile_string (option, value, "config_description", p->description, 256)) + return 1; + + if (cfgfile_yesno (option, value, "use_debugger", &p->start_debugger) + || cfgfile_yesno (option, value, "state_replay", &p->statecapture) + || cfgfile_yesno (option, value, "avoid_cmov", &p->avoid_cmov) + || cfgfile_yesno (option, value, "avoid_dga", &p->avoid_dga) + || cfgfile_yesno (option, value, "avoid_vid", &p->avoid_vid) + || cfgfile_yesno (option, value, "log_illegal_mem", &p->illegal_mem) + || cfgfile_yesno (option, value, "filesys_no_fsdb", &p->filesys_no_uaefsdb) + || cfgfile_yesno (option, value, "gfx_vsync", &p->gfx_vsync) + || cfgfile_yesno (option, value, "gfx_lores", &p->gfx_lores) + || cfgfile_yesno (option, value, "gfx_correct_aspect", &p->gfx_correct_aspect) + || cfgfile_yesno (option, value, "gfx_fullscreen_amiga", &p->gfx_afullscreen) + || cfgfile_yesno (option, value, "gfx_fullscreen_picasso", &p->gfx_pfullscreen) + || cfgfile_yesno (option, value, "show_leds", &p->leds_on_screen) + || cfgfile_yesno (option, value, "synchronize_clock", &p->tod_hack) + || cfgfile_yesno (option, value, "bsdsocket_emu", &p->socket_emu)) + return 1; + + if (cfgfile_strval (option, value, "sound_output", &p->produce_sound, soundmode1, 1) + || cfgfile_strval (option, value, "sound_output", &p->produce_sound, soundmode2, 0) + || cfgfile_strval (option, value, "sound_interpol", &p->sound_interpol, interpolmode, 0) + || cfgfile_strval (option, value, "sound_filter", &p->sound_filter, soundfiltermode, 0) + || cfgfile_strval (option, value, "joyport0", &p->jport0, portmode, 0) + || cfgfile_strval (option, value, "joyport1", &p->jport1, portmode, 0) + || cfgfile_strval (option, value, "use_gui", &p->start_gui, guimode1, 1) + || cfgfile_strval (option, value, "use_gui", &p->start_gui, guimode2, 1) + || cfgfile_strval (option, value, "use_gui", &p->start_gui, guimode3, 0) + || cfgfile_strval (option, value, "gfx_linemode", &p->gfx_linedbl, linemode1, 1) + || cfgfile_strval (option, value, "gfx_linemode", &p->gfx_linedbl, linemode2, 0) + || cfgfile_strval (option, value, "gfx_center_horizontal", &p->gfx_xcenter, centermode1, 1) + || cfgfile_strval (option, value, "gfx_center_vertical", &p->gfx_ycenter, centermode1, 1) + || cfgfile_strval (option, value, "gfx_center_horizontal", &p->gfx_xcenter, centermode2, 0) + || cfgfile_strval (option, value, "gfx_center_vertical", &p->gfx_ycenter, centermode2, 0) + || cfgfile_strval (option, value, "gfx_colour_mode", &p->color_mode, colormode1, 1) + || cfgfile_strval (option, value, "gfx_colour_mode", &p->color_mode, colormode2, 0) + || cfgfile_strval (option, value, "gfx_color_mode", &p->color_mode, colormode1, 1) + || cfgfile_strval (option, value, "gfx_color_mode", &p->color_mode, colormode2, 0)) + return 1; + + +#ifdef GFXFILTER + if (strcmp (option,"gfx_filter") == 0) { + int i = 0; + p->gfx_filter = 0; + while(uaefilters[i].name) { + if (!strcmp (uaefilters[i].cfgname, value)) { + p->gfx_filter = uaefilters[i].type; + break; + } + i++; + } + return 1; + } + if (strcmp (option,"gfx_filter_mode") == 0) { + p->gfx_filter_filtermode = 0; + if (p->gfx_filter > 0) { + struct uae_filter *uf; + int i = 0; + while(uaefilters[i].name) { + uf = &uaefilters[i]; + if (uf->type == p->gfx_filter) { + if (uf->x[0]) { + cfgfile_strval (option, value, "gfx_filter_mode", &p->gfx_filter_filtermode, filtermode1, 0); + } else { + int mt[4], j; + i = 0; + if (uf->x[1]) mt[i++] = 1; + if (uf->x[2]) mt[i++] = 2; + if (uf->x[3]) mt[i++] = 3; + if (uf->x[4]) mt[i++] = 4; + cfgfile_strval (option, value, "gfx_filter_mode", &i, filtermode2, 0); + for (j = 0; j < i; j++) { + if (mt[j] == i) + p->gfx_filter_filtermode = j; + } + } + break; + } + i++; + } + } + return 1; + } +#endif + + if (strcmp (option, "gfx_width") == 0 || strcmp (option, "gfx_height") == 0) { + cfgfile_intval (option, value, "gfx_width", &p->gfx_width_win, 1); + cfgfile_intval (option, value, "gfx_height", &p->gfx_height_win, 1); + p->gfx_width_fs = p->gfx_width_win; + p->gfx_height_fs = p->gfx_height_win; + return 1; + } + + if (cfgfile_string (option, value, "statefile", tmpbuf, sizeof (tmpbuf))) { + savestate_state = STATE_DORESTORE; + strcpy (savestate_fname, tmpbuf); + return 1; + } + + if (cfgfile_strval (option, value, "sound_channels", &p->stereo, stereomode1, 1) + || cfgfile_strval (option, value, "sound_channels", &p->stereo, stereomode2, 1) + || cfgfile_strval (option, value, "sound_channels", &p->stereo, stereomode3, 0)) + { + p->mixed_stereo = 0; + if (p->stereo == 2) { + p->stereo = 1; + p->mixed_stereo = 1; + } + return 1; + } + + if (strcmp (option, "kbd_lang") == 0) { + KbdLang l; + if ((l = KBD_LANG_DE, strcasecmp (value, "de") == 0) + || (l = KBD_LANG_DK, strcasecmp (value, "dk") == 0) + || (l = KBD_LANG_SE, strcasecmp (value, "se") == 0) + || (l = KBD_LANG_US, strcasecmp (value, "us") == 0) + || (l = KBD_LANG_FR, strcasecmp (value, "fr") == 0) + || (l = KBD_LANG_IT, strcasecmp (value, "it") == 0) + || (l = KBD_LANG_ES, strcasecmp (value, "es") == 0)) + p->keyboard_lang = l; + else + write_log ("Unknown keyboard language\n"); + return 1; + } + + if (cfgfile_string (option, value, "config_version", tmpbuf, sizeof (tmpbuf))) { + char *tmpp2; + tmpp = strchr (value, '.'); + if (tmpp) { + *tmpp++ = 0; + tmpp2 = tmpp; + p->config_version = atol (tmpbuf) << 16; + tmpp = strchr (tmpp, '.'); + if (tmpp) { + *tmpp++ = 0; + p->config_version |= atol (tmpp2) << 8; + p->config_version |= atol (tmpp); + } + } + return 1; + } + + if (cfgfile_string (option, value, "keyboard_leds", tmpbuf, sizeof (tmpbuf))) { + char *tmpp2 = tmpbuf; + int i, num; + p->keyboard_leds[0] = p->keyboard_leds[1] = p->keyboard_leds[2] = 0; + p->keyboard_leds_in_use = 0; + strcat (tmpbuf, ","); + for (i = 0; i < 3; i++) { + tmpp = strchr (tmpp2, ':'); + if (!tmpp) + break; + *tmpp++= 0; + num = -1; + if (!strcasecmp (tmpp2, "numlock")) num = 0; + if (!strcasecmp (tmpp2, "capslock")) num = 1; + if (!strcasecmp (tmpp2, "scrolllock")) num = 2; + tmpp2 = tmpp; + tmpp = strchr (tmpp2, ','); + if (!tmpp) + break; + *tmpp++= 0; + if (num >= 0) { + p->keyboard_leds[num] = match_string (kbleds, tmpp2); + if (p->keyboard_leds[num]) p->keyboard_leds_in_use = 1; + } + tmpp2 = tmpp; + } + return 1; + } + + return 0; +} + +static int cfgfile_parse_hardware (struct uae_prefs *p, char *option, char *value) +{ + int tmpval; + int dummy; + char *section = 0; + + if (cfgfile_yesno (option, value, "immediate_blits", &p->immediate_blits) + || cfgfile_yesno (option, value, "fast_copper", &p->fast_copper) + || cfgfile_yesno (option, value, "kickshifter", &p->kickshifter) + || cfgfile_yesno (option, value, "ntsc", &p->ntscmode) + || cfgfile_yesno (option, value, "cpu_compatible", &p->cpu_compatible) + || cfgfile_yesno (option, value, "cpu_cycle_exact", &p->cpu_cycle_exact) + || cfgfile_yesno (option, value, "blitter_cycle_exact", &p->blitter_cycle_exact) + || cfgfile_yesno (option, value, "cpu_24bit_addressing", &p->address_space_24) + || cfgfile_yesno (option, value, "parallel_on_demand", &p->parallel_demand) + || cfgfile_yesno (option, value, "serial_on_demand", &p->serial_demand) + || cfgfile_yesno (option, value, "serial_hardware_ctsrts", &p->serial_hwctsrts) + || cfgfile_yesno (option, value, "serial_direct", &p->serial_direct) + || cfgfile_yesno (option, value, "comp_nf", &p->compnf) + || cfgfile_yesno (option, value, "comp_constjump", &p->comp_constjump) + || cfgfile_yesno (option, value, "comp_oldsegv", &p->comp_oldsegv) + || cfgfile_yesno (option, value, "compforcesettings", &p->compforcesettings) + || cfgfile_yesno (option, value, "compfpu", &p->compfpu) + || cfgfile_yesno (option, value, "comp_midopt", &p->comp_midopt) + || cfgfile_yesno (option, value, "comp_lowopt", &p->comp_lowopt) + || cfgfile_yesno (option, value, "scsi", &p->scsi)) + return 1; + if (cfgfile_intval (option, value, "cachesize", &p->cachesize, 1) + || cfgfile_intval (option, value, "fastmem_size", &p->fastmem_size, 0x100000) + || cfgfile_intval (option, value, "a3000mem_size", &p->a3000mem_size, 0x100000) + || cfgfile_intval (option, value, "z3mem_size", &p->z3fastmem_size, 0x100000) + || cfgfile_intval (option, value, "bogomem_size", &p->bogomem_size, 0x40000) + || cfgfile_intval (option, value, "gfxcard_size", &p->gfxmem_size, 0x100000) + || cfgfile_intval (option, value, "floppy_speed", &p->floppy_speed, 1) + || cfgfile_intval (option, value, "nr_floppies", &p->nr_floppies, 1) + || cfgfile_intval (option, value, "floppy0type", &p->dfxtype[0], 1) + || cfgfile_intval (option, value, "floppy1type", &p->dfxtype[1], 1) + || cfgfile_intval (option, value, "floppy2type", &p->dfxtype[2], 1) + || cfgfile_intval (option, value, "floppy3type", &p->dfxtype[3], 1) + || cfgfile_intval (option, value, "maprom", &p->maprom, 1) + || cfgfile_intval (option, value, "catweasel_io", &p->catweasel_io, 1)) + return 1; + if (cfgfile_strval (option, value, "comp_trustbyte", &p->comptrustbyte, compmode, 0) + || cfgfile_strval (option, value, "comp_trustword", &p->comptrustword, compmode, 0) + || cfgfile_strval (option, value, "comp_trustlong", &p->comptrustlong, compmode, 0) + || cfgfile_strval (option, value, "comp_trustnaddr", &p->comptrustnaddr, compmode, 0) + || cfgfile_strval (option, value, "collision_level", &p->collision_level, collmode, 0) + || cfgfile_strval (option, value, "comp_flushmode", &p->comp_hardflush, flushmode, 0)) + return 1; + if (cfgfile_string (option, value, "floppy0", p->df[0], 256) + || cfgfile_string (option, value, "floppy1", p->df[1], 256) + || cfgfile_string (option, value, "floppy2", p->df[2], 256) + || cfgfile_string (option, value, "floppy3", p->df[3], 256) + || cfgfile_string (option, value, "kickstart_rom_file", p->romfile, 256) + || cfgfile_string (option, value, "kickstart_ext_rom_file", p->romextfile, 256) + || cfgfile_string (option, value, "kickstart_key_file", p->keyfile, 256) + || cfgfile_string (option, value, "flash_file", p->flashfile, 256) + || cfgfile_string (option, value, "cart_file", p->cartfile, 256) + || cfgfile_string (option, value, "pci_devices", p->pci_devices, 256)) + return 1; + + if (cfgfile_intval (option, value, "chipmem_size", &dummy, 1)) { + if (!dummy) + p->chipmem_size = 0x40000; + else + p->chipmem_size = dummy * 0x80000; + return 1; + } + + if (cfgfile_strval (option, value, "chipset", &tmpval, csmode, 0)) { + set_chipset_mask (p, tmpval); + return 1; + } + + if (cfgfile_strval (option, value, "cpu_type", &p->cpu_level, cpumode, 0)) { + p->address_space_24 = p->cpu_level < 8 && !(p->cpu_level & 1); + p->cpu_level >>= 1; + return 1; + } + if (p->config_version < (21 << 16)) { + if (cfgfile_strval (option, value, "cpu_speed", &p->m68k_speed, speedmode, 1) + /* Broken earlier versions used to write this out as a string. */ + || cfgfile_strval (option, value, "finegraincpu_speed", &p->m68k_speed, speedmode, 1)) + { + p->m68k_speed--; + return 1; + } + } + + if (cfgfile_intval (option, value, "cpu_speed", &p->m68k_speed, 1)) { + p->m68k_speed *= CYCLE_UNIT; + return 1; + } + + if (cfgfile_intval (option, value, "finegrain_cpu_speed", &p->m68k_speed, 1)) { + if (OFFICIAL_CYCLE_UNIT > CYCLE_UNIT) { + int factor = OFFICIAL_CYCLE_UNIT / CYCLE_UNIT; + p->m68k_speed = (p->m68k_speed + factor - 1) / factor; + } + if (strcasecmp (value, "max") == 0) p->m68k_speed = -1; + return 1; + } + + if (strcmp (option, "filesystem") == 0 + || strcmp (option, "hardfile") == 0) + { + int secs, heads, reserved, bs, ro; + char *aname, *root; + char *tmpp = strchr (value, ','); + char *str; + + if (config_newfilesystem) + return 1; + + if (tmpp == 0) + goto invalid_fs; + + *tmpp++ = '\0'; + if (strcmp (value, "1") == 0 || strcasecmp (value, "ro") == 0 + || strcasecmp (value, "readonly") == 0 + || strcasecmp (value, "read-only") == 0) + ro = 1; + else if (strcmp (value, "0") == 0 || strcasecmp (value, "rw") == 0 + || strcasecmp (value, "readwrite") == 0 + || strcasecmp (value, "read-write") == 0) + ro = 0; + else + goto invalid_fs; + secs = 0; heads = 0; reserved = 0; bs = 0; + + value = tmpp; + if (strcmp (option, "filesystem") == 0) { + tmpp = strchr (value, ':'); + if (tmpp == 0) + goto invalid_fs; + *tmpp++ = '\0'; + aname = value; + root = tmpp; + } else { + if (! getintval (&value, &secs, ',') + || ! getintval (&value, &heads, ',') + || ! getintval (&value, &reserved, ',') + || ! getintval (&value, &bs, ',')) + goto invalid_fs; + root = value; + aname = 0; + } + str = cfgfile_subst_path (UNEXPANDED, p->path_hardfile, root); + tmpp = 0; +#ifdef FILESYS + tmpp = add_filesys_unit (currprefs.mountinfo, 0, aname, str, ro, secs, + heads, reserved, bs, 0, 0); +#endif + free (str); + if (tmpp) + write_log ("Error: %s\n", tmpp); + return 1; + + } + + if (strcmp (option, "filesystem2") == 0 + || strcmp (option, "hardfile2") == 0) + { + int secs, heads, reserved, bs, ro, bp; + char *dname, *aname, *root, *fs; + char *tmpp = strchr (value, ','); + char *str; + + config_newfilesystem = 1; + if (tmpp == 0) + goto invalid_fs; + + *tmpp++ = '\0'; + if (strcasecmp (value, "ro") == 0) + ro = 1; + else if (strcasecmp (value, "rw") == 0) + ro = 0; + else + goto invalid_fs; + secs = 0; heads = 0; reserved = 0; bs = 0; bp = 0; + fs = 0; + + value = tmpp; + if (strcmp (option, "filesystem2") == 0) { + tmpp = strchr (value, ':'); + if (tmpp == 0) + goto invalid_fs; + *tmpp++ = 0; + dname = value; + aname = tmpp; + tmpp = strchr (tmpp, ':'); + if (tmpp == 0) + goto invalid_fs; + *tmpp++ = 0; + root = tmpp; + tmpp = strchr (tmpp, ','); + if (tmpp == 0) + goto invalid_fs; + *tmpp++ = 0; + if (! getintval (&tmpp, &bp, 0)) + goto invalid_fs; + } else { + tmpp = strchr (value, ':'); + if (tmpp == 0) + goto invalid_fs; + *tmpp++ = '\0'; + dname = value; + root = tmpp; + tmpp = strchr (tmpp, ','); + if (tmpp == 0) + goto invalid_fs; + *tmpp++ = 0; + aname = 0; + if (! getintval (&tmpp, &secs, ',') + || ! getintval (&tmpp, &heads, ',') + || ! getintval (&tmpp, &reserved, ',') + || ! getintval (&tmpp, &bs, ',')) + goto invalid_fs; + if (getintval2 (&tmpp, &bp, ',')) { + fs = tmpp; + tmpp = strchr (tmpp, ','); + if (tmpp != 0) + *tmpp = 0; + } + } + str = cfgfile_subst_path (UNEXPANDED, p->path_hardfile, root); + tmpp = 0; +#ifdef FILESYS + tmpp = add_filesys_unit (currprefs.mountinfo, dname, aname, str, ro, secs, + heads, reserved, bs, bp, fs); +#endif + free (str); + if (tmpp) + write_log ("Error: %s\n", tmpp); + return 1; + + invalid_fs: + write_log ("Invalid filesystem/hardfile specification.\n"); + return 1; + } + + return 0; +} + +int cfgfile_parse_option (struct uae_prefs *p, char *option, char *value, int type) +{ + if (!strcmp (option, "config_hardware")) + return 1; + if (!strcmp (option, "config_host")) + return 1; + if (type == 0 || (type & CONFIG_TYPE_HARDWARE)) { + if (cfgfile_parse_hardware (p, option, value)) + return 1; + } + if (type == 0 || (type & CONFIG_TYPE_HOST)) { + if (cfgfile_parse_host (p, option, value)) + return 1; + } + if (type > 0) + return 1; + return 0; +} + +static int separate_line (char *line, char *line1b, char *line2b) +{ + char *line1, *line2; + int i; + + line1 = line; + line2 = strchr (line, '='); + if (! line2) { + write_log ("CFGFILE: line was incomplete with only %s\n", line1); + return 0; + } + *line2++ = '\0'; + strcpy (line1b, line1); + strcpy (line2b, line2); + + /* Get rid of whitespace. */ + i = strlen (line2); + while (i > 0 && (line2[i - 1] == '\t' || line2[i - 1] == ' ' + || line2[i - 1] == '\r' || line2[i - 1] == '\n')) + line2[--i] = '\0'; + line2 += strspn (line2, "\t \r\n"); + strcpy (line2b, line2); + i = strlen (line); + while (i > 0 && (line[i - 1] == '\t' || line[i - 1] == ' ' + || line[i - 1] == '\r' || line[i - 1] == '\n')) + line[--i] = '\0'; + line += strspn (line, "\t \r\n"); + strcpy (line1b, line); + return 1; +} + +static int isobsolete (char *s) +{ + int i = 0; + while (obsolete[i]) { + if (!strcasecmp (s, obsolete[i])) { + write_log ("obsolete config entry '%s'\n", s); + return 1; + } + i++; + } + if (strlen (s) >= 10 && !memcmp (s, "gfx_opengl", 10)) { + write_log ("obsolete config entry '%s\n", s); + return 1; + } + if (strlen (s) >= 6 && !memcmp (s, "gfx_3d", 6)) { + write_log ("obsolete config entry '%s\n", s); + return 1; + } + return 0; +} + +static void cfgfile_parse_separated_line (struct uae_prefs *p, char *line1b, char *line2b, int type) +{ + char line3b[2560], line4b[2560]; + struct strlist *sl; + int ret; + + strcpy (line3b, line1b); + strcpy (line4b, line2b); + ret = cfgfile_parse_option (p, line1b, line2b, type); + if (!isobsolete (line3b)) { + for (sl = p->all_lines; sl; sl = sl->next) { + if (sl->option && !strcasecmp (line1b, sl->option)) break; + } + if (!sl) { + struct strlist *u = xcalloc (sizeof (struct strlist), 1); + u->option = my_strdup(line3b); + u->value = my_strdup(line4b); + u->next = p->all_lines; + p->all_lines = u; + if (!ret) { + u->unknown = 1; + write_log ("unknown config entry: '%s=%s'\n", u->option, u->value); + } + } + } +} + +void cfgfile_parse_line (struct uae_prefs *p, char *line, int type) +{ + char line1b[2560], line2b[2560]; + + if (!separate_line (line, line1b, line2b)) + return; + cfgfile_parse_separated_line (p, line1b, line2b, type); + return; +} + +static void subst (char *p, char *f, int n) +{ + char *str = cfgfile_subst_path (UNEXPANDED, p, f); + strncpy (f, str, n - 1); + f[n - 1] = '\0'; + free (str); +} + +static char *cfg_fgets (char *line, int max, FILE *fh) +{ +#ifdef SINGLEFILE + extern char singlefile_config[]; + static char *sfile_ptr; + char *p; +#endif + + if (fh) + return fgets (line, max, fh); +#ifdef SINGLEFILE + if (sfile_ptr == 0) { + sfile_ptr = singlefile_config; + if (*sfile_ptr) { + write_log ("singlefile config found\n"); + while (*sfile_ptr++); + } + } + if (*sfile_ptr == 0) { + sfile_ptr = singlefile_config; + return 0; + } + p = sfile_ptr; + while (*p != 13 && *p != 10 && *p != 0) p++; + memset (line, 0, max); + memcpy (line, sfile_ptr, p - sfile_ptr); + sfile_ptr = p + 1; + if (*sfile_ptr == 13) + sfile_ptr++; + if (*sfile_ptr == 10) + sfile_ptr++; + return line; +#endif + return 0; +} + +static int cfgfile_load_2 (struct uae_prefs *p, const char *filename, int real, int *type) +{ + int i; + FILE *fh; + char line[2560], line1b[2560], line2b[2560]; + struct strlist *sl; + int type1 = 0, type2 = 0, askedtype = 0; + + if (type) { + askedtype = *type; + *type = 0; + } + if (real) { + p->config_version = 0; + config_newfilesystem = 0; + reset_inputdevice_config (p); + } + + fh = fopen (filename, "r"); +#ifndef SINGLEFILE + if (! fh) + return 0; +#endif + + while (cfg_fgets (line, sizeof (line), fh) != 0) { + int len = strlen (line); + /* Delete trailing whitespace. */ + while (len > 0 && strcspn (line + len - 1, "\t \r\n") == 0) { + line[--len] = '\0'; + } + if (strlen (line) > 0) { + if (line[0] == '#') + continue; + if (!separate_line (line, line1b, line2b)) + continue; + type1 = type2 = 0; + if (cfgfile_yesno (line1b, line2b, "config_hardware", &type1) || + cfgfile_yesno (line1b, line2b, "config_host", &type2)) { + if (type1 && type) + *type |= CONFIG_TYPE_HARDWARE; + if (type2 && type) + *type |= CONFIG_TYPE_HOST; + continue; + } + if (real) { + cfgfile_parse_separated_line (p, line1b, line2b, askedtype); + } else { + cfgfile_string (line1b, line2b, "config_description", p->description, 128); + } + } + } + + if (type && *type == 0) + *type = CONFIG_TYPE_HARDWARE | CONFIG_TYPE_HOST; + if (fh) + fclose (fh); + + if (!real) + return 1; + + for (sl = temp_lines; sl; sl = sl->next) { + sprintf (line, "%s=%s", sl->option, sl->value); + cfgfile_parse_line (p, line, 0); + } + + for (i = 0; i < 4; i++) + subst (p->path_floppy, p->df[i], sizeof p->df[i]); + subst (p->path_rom, p->romfile, sizeof p->romfile); + subst (p->path_rom, p->romextfile, sizeof p->romextfile); + subst (p->path_rom, p->keyfile, sizeof p->keyfile); + + return 1; +} + +int cfgfile_load (struct uae_prefs *p, const char *filename, int *type) +{ + write_log ("load config '%s'\n", filename); + return cfgfile_load_2 (p, filename, 1, type); +} + +int cfgfile_save (struct uae_prefs *p, const char *filename, int type) +{ + FILE *fh = fopen (filename, "w"); + write_log ("save config '%s'\n", filename); + if (! fh) + return 0; + + if (!type) + type = CONFIG_TYPE_HARDWARE | CONFIG_TYPE_HOST; + save_options (fh, p, type); + fclose (fh); + return 1; +} + +int cfgfile_get_description (const char *filename, char *description, int *type) +{ + int result = 0; + struct uae_prefs *p = xmalloc (sizeof (struct uae_prefs)); + strcpy (p->description, ""); + if (cfgfile_load_2 (p, filename, 0, type)) { + result = 1; + strcpy (description, p->description); + } + free (p); + return result; +} + +void cfgfile_show_usage (void) +{ + int i; + write_log ("UAE Configuration Help:\n" \ + "=======================\n"); + for (i = 0; i < sizeof opttable / sizeof *opttable; i++) + write_log ("%s: %s\n", opttable[i].config_label, opttable[i].config_help); +} + +/* This implements the old commandline option parsing. I've re-added this + because the new way of doing things is painful for me (it requires me + to type a couple hundred characters when invoking UAE). The following + is far less annoying to use. */ +static void parse_gfx_specs (struct uae_prefs *p, char *spec) +{ + char *x0 = my_strdup (spec); + char *x1, *x2; + + x1 = strchr (x0, ':'); + if (x1 == 0) + goto argh; + x2 = strchr (x1+1, ':'); + if (x2 == 0) + goto argh; + *x1++ = 0; *x2++ = 0; + + p->gfx_width_win = p->gfx_width_fs = atoi (x0); + p->gfx_height_win = p->gfx_height_fs = atoi (x1); + p->gfx_lores = strchr (x2, 'l') != 0; + p->gfx_xcenter = strchr (x2, 'x') != 0 ? 1 : strchr (x2, 'X') != 0 ? 2 : 0; + p->gfx_ycenter = strchr (x2, 'y') != 0 ? 1 : strchr (x2, 'Y') != 0 ? 2 : 0; + p->gfx_linedbl = strchr (x2, 'd') != 0; + p->gfx_linedbl += 2 * (strchr (x2, 'D') != 0); + p->gfx_afullscreen = strchr (x2, 'a') != 0; + p->gfx_pfullscreen = strchr (x2, 'p') != 0; + p->gfx_correct_aspect = strchr (x2, 'c') != 0; + + if (p->gfx_linedbl == 3) { + write_log ("You can't use both 'd' and 'D' modifiers in the display mode specification.\n"); + } + + free (x0); + return; + + argh: + write_log ("Bad display mode specification.\n"); + write_log ("The format to use is: \"width:height:modifiers\"\n"); + write_log ("Type \"uae -h\" for detailed help.\n"); + free (x0); +} + +static void parse_sound_spec (struct uae_prefs *p, char *spec) +{ + char *x0 = my_strdup (spec); + char *x1, *x2 = NULL, *x3 = NULL, *x4 = NULL, *x5 = NULL; + + x1 = strchr (x0, ':'); + if (x1 != NULL) { + *x1++ = '\0'; + x2 = strchr (x1 + 1, ':'); + if (x2 != NULL) { + *x2++ = '\0'; + x3 = strchr (x2 + 1, ':'); + if (x3 != NULL) { + *x3++ = '\0'; + x4 = strchr (x3 + 1, ':'); + if (x4 != NULL) { + *x4++ = '\0'; + x5 = strchr (x4 + 1, ':'); + } + } + } + } + p->produce_sound = atoi (x0); + if (x1) { + p->mixed_stereo = 0; + if (*x1 == 'S') + p->stereo = p->mixed_stereo = 1; + else if (*x1 == 's') + p->stereo = 1; + else + p->stereo = 0; + } + if (x2) + p->sound_bits = atoi (x2); + if (x3) + p->sound_freq = atoi (x3); + if (x4) + p->sound_maxbsiz = atoi (x4); + free (x0); + return; +} + + +static void parse_joy_spec (struct uae_prefs *p, char *spec) +{ + int v0 = 2, v1 = 0; + if (strlen(spec) != 2) + goto bad; + + switch (spec[0]) { + case '0': v0 = 0; break; + case '1': v0 = 1; break; + case 'M': case 'm': v0 = 2; break; + case 'A': case 'a': v0 = 3; break; + case 'B': case 'b': v0 = 4; break; + case 'C': case 'c': v0 = 5; break; + default: goto bad; + } + + switch (spec[1]) { + case '0': v1 = 0; break; + case '1': v1 = 1; break; + case 'M': case 'm': v1 = 2; break; + case 'A': case 'a': v1 = 3; break; + case 'B': case 'b': v1 = 4; break; + case 'C': case 'c': v1 = 5; break; + default: goto bad; + } + if (v0 == v1) + goto bad; + /* Let's scare Pascal programmers */ + if (0) +bad: + write_log ("Bad joystick mode specification. Use -J xy, where x and y\n" + "can be 0 for joystick 0, 1 for joystick 1, M for mouse, and\n" + "a, b or c for different keyboard settings.\n"); + + p->jport0 = v0; + p->jport1 = v1; +} + +static void parse_filesys_spec (int readonly, char *spec) +{ + char buf[256]; + char *s2; + + strncpy (buf, spec, 255); buf[255] = 0; + s2 = strchr (buf, ':'); + if (s2) { + *s2++ = '\0'; +#ifdef __DOS__ + { + char *tmp; + + while ((tmp = strchr (s2, '\\'))) + *tmp = '/'; + } +#endif + s2 = 0; +#ifdef FILESYS + s2 = add_filesys_unit (currprefs.mountinfo, 0, buf, s2, readonly, 0, 0, 0, 0, 0, 0); +#endif + if (s2) + write_log ("%s\n", s2); + } else { + write_log ("Usage: [-m | -M] VOLNAME:mount_point\n"); + } +} + +static void parse_hardfile_spec (char *spec) +{ + char *x0 = my_strdup (spec); + char *x1, *x2, *x3, *x4; + + x1 = strchr (x0, ':'); + if (x1 == NULL) + goto argh; + *x1++ = '\0'; + x2 = strchr (x1 + 1, ':'); + if (x2 == NULL) + goto argh; + *x2++ = '\0'; + x3 = strchr (x2 + 1, ':'); + if (x3 == NULL) + goto argh; + *x3++ = '\0'; + x4 = strchr (x3 + 1, ':'); + if (x4 == NULL) + goto argh; + *x4++ = '\0'; + x4 = 0; +#ifdef FILESYS + x4 = add_filesys_unit (currprefs.mountinfo, 0, 0, x4, 0, atoi (x0), atoi (x1), atoi (x2), atoi (x3), 0, 0); +#endif + if (x4) + write_log ("%s\n", x4); + + free (x0); + return; + + argh: + free (x0); + write_log ("Bad hardfile parameter specified - type \"uae -h\" for help.\n"); + return; +} + +static void parse_cpu_specs (struct uae_prefs *p, char *spec) +{ + if (*spec < '0' || *spec > '4') { + write_log ("CPU parameter string must begin with '0', '1', '2', '3' or '4'.\n"); + return; + } + + p->cpu_level = *spec++ - '0'; + p->address_space_24 = p->cpu_level < 2; + p->cpu_compatible = 0; + while (*spec != '\0') { + switch (*spec) { + case 'a': + if (p->cpu_level < 2) + write_log ("In 68000/68010 emulation, the address space is always 24 bit.\n"); + else if (p->cpu_level >= 4) + write_log ("In 68040/060 emulation, the address space is always 32 bit.\n"); + else + p->address_space_24 = 1; + break; + case 'c': + if (p->cpu_level != 0) + write_log ("The more compatible CPU emulation is only available for 68000\n" + "emulation, not for 68010 upwards.\n"); + else + p->cpu_compatible = 1; + break; + default: + write_log ("Bad CPU parameter specified - type \"uae -h\" for help.\n"); + break; + } + spec++; + } +} + +/* Returns the number of args used up (0 or 1). */ +int parse_cmdline_option (struct uae_prefs *p, char c, char *arg) +{ + struct strlist *u = xcalloc (sizeof (struct strlist), 1); + const char arg_required[] = "0123rKpImWSAJwNCZUFcblOdHRv"; + + if (strchr (arg_required, c) && ! arg) { + write_log ("Missing argument for option `-%c'!\n", c); + return 0; + } + + u->option = malloc (2); + u->option[0] = c; + u->option[1] = 0; + u->value = my_strdup(arg); + u->next = p->all_lines; + p->all_lines = u; + + switch (c) { + case 'h': usage (); exit (0); + + case '0': strncpy (p->df[0], arg, 255); p->df[0][255] = 0; break; + case '1': strncpy (p->df[1], arg, 255); p->df[1][255] = 0; break; + case '2': strncpy (p->df[2], arg, 255); p->df[2][255] = 0; break; + case '3': strncpy (p->df[3], arg, 255); p->df[3][255] = 0; break; + case 'r': strncpy (p->romfile, arg, 255); p->romfile[255] = 0; break; + case 'K': strncpy (p->keyfile, arg, 255); p->keyfile[255] = 0; break; + case 'p': strncpy (p->prtname, arg, 255); p->prtname[255] = 0; break; + /* case 'I': strncpy (p->sername, arg, 255); p->sername[255] = 0; currprefs.use_serial = 1; break; */ + case 'm': case 'M': parse_filesys_spec (c == 'M', arg); break; + case 'W': parse_hardfile_spec (arg); break; + case 'S': parse_sound_spec (p, arg); break; + case 'R': p->gfx_framerate = atoi (arg); break; + case 'x': p->no_xhair = 1; break; + case 'i': p->illegal_mem = 1; break; + case 'J': parse_joy_spec (p, arg); break; + + case 't': p->test_drawing_speed = 1; break; +#ifdef USE_X11_GFX + case 'L': p->x11_use_low_bandwidth = 1; break; + case 'T': p->x11_use_mitshm = 1; break; +#endif + case 'w': p->m68k_speed = atoi (arg); break; + + /* case 'g': p->use_gfxlib = 1; break; */ + case 'G': p->start_gui = 0; break; + case 'D': p->start_debugger = 1; break; + + case 'n': + if (strchr (arg, 'i') != 0) + p->immediate_blits = 1; + break; + + case 'v': + set_chipset_mask (p, atoi (arg)); + break; + + case 'C': + parse_cpu_specs (p, arg); + break; + + case 'Z': + p->z3fastmem_size = atoi (arg) * 0x100000; + break; + + case 'U': + p->gfxmem_size = atoi (arg) * 0x100000; + break; + + case 'F': + p->fastmem_size = atoi (arg) * 0x100000; + break; + + case 'b': + p->bogomem_size = atoi (arg) * 0x40000; + break; + + case 'c': + p->chipmem_size = atoi (arg) * 0x80000; + break; + + case 'l': + if (0 == strcasecmp(arg, "de")) + p->keyboard_lang = KBD_LANG_DE; + else if (0 == strcasecmp(arg, "dk")) + p->keyboard_lang = KBD_LANG_DK; + else if (0 == strcasecmp(arg, "us")) + p->keyboard_lang = KBD_LANG_US; + else if (0 == strcasecmp(arg, "se")) + p->keyboard_lang = KBD_LANG_SE; + else if (0 == strcasecmp(arg, "fr")) + p->keyboard_lang = KBD_LANG_FR; + else if (0 == strcasecmp(arg, "it")) + p->keyboard_lang = KBD_LANG_IT; + else if (0 == strcasecmp(arg, "es")) + p->keyboard_lang = KBD_LANG_ES; + break; + + case 'O': parse_gfx_specs (p, arg); break; + case 'd': + if (strchr (arg, 'S') != NULL || strchr (arg, 's')) { + write_log (" Serial on demand.\n"); + p->serial_demand = 1; + } + if (strchr (arg, 'P') != NULL || strchr (arg, 'p')) { + write_log (" Parallel on demand.\n"); + p->parallel_demand = 1; + } + + break; + + case 'H': + p->color_mode = atoi (arg); + if (p->color_mode < 0) { + write_log ("Bad color mode selected. Using default.\n"); + p->color_mode = 0; + } + break; + default: + write_log ("Unknown option `-%c'!\n", c); + break; + } + return !! strchr (arg_required, c); +} + +void cfgfile_addcfgparam (char *line) +{ + struct strlist *u; + char line1b[2560], line2b[2560]; + + if (!line) { + struct strlist **ps = &temp_lines; + while (*ps) { + struct strlist *s = *ps; + *ps = s->next; + free (s->value); + free (s->option); + free (s); + } + temp_lines = 0; + return; + } + if (!separate_line (line, line1b, line2b)) + return; + u = xcalloc (sizeof (struct strlist), 1); + u->option = my_strdup(line1b); + u->value = my_strdup(line2b); + u->next = temp_lines; + temp_lines = u; +} + + +uae_u32 cfgfile_uaelib(int mode, uae_u32 name, uae_u32 dst, uae_u32 maxlen) +{ + char tmp[2000]; + int i; + struct strlist *sl; + + if (mode) + return 0; + + for (i = 0; i < sizeof(tmp); i++) { + tmp[i] = get_byte (name + i); + if (tmp[i] == 0) + break; + } + tmp[sizeof(tmp) - 1] = 0; + if (tmp[0] == 0) + return 0; + for (sl = currprefs.all_lines; sl; sl = sl->next) { + if (!strcasecmp (sl->option, tmp)) + break; + } + + if (sl) { + for (i = 0; i < maxlen; i++) { + put_byte (dst + i, sl->value[i]); + if (sl->value[i] == 0) + break; + } + return dst; + } + return 0; +} + +static void default_prefs_mini (struct uae_prefs *p, int type) +{ + strcpy (p->description, "UAE default A500 configuration"); + + p->nr_floppies = 1; + p->dfxtype[0] = 0; + p->dfxtype[1] = -1; + p->cpu_level = 0; + p->address_space_24 = 1; + p->chipmem_size = 0x00080000; + p->bogomem_size = 0x00080000; +} + +#include "sounddep/sound.h" + +void default_prefs (struct uae_prefs *p, int type) +{ + memset (p, 0, sizeof (*p)); + strcpy (p->description, "UAE default configuration"); + + p->start_gui = 1; + p->start_debugger = 0; + + p->all_lines = 0; + /* Note to porters: please don't change any of these options! UAE is supposed + * to behave identically on all platforms if possible. */ + p->illegal_mem = 0; + p->no_xhair = 0; + p->use_serial = 0; + p->serial_demand = 0; + p->serial_hwctsrts = 1; + p->parallel_demand = 0; + + p->jport0 = 2; + p->jport1 = 0; + p->keyboard_lang = KBD_LANG_US; + + p->produce_sound = 3; + p->stereo = 0; + p->sound_bits = DEFAULT_SOUND_BITS; + p->sound_freq = DEFAULT_SOUND_FREQ; + p->sound_maxbsiz = DEFAULT_SOUND_MAXB; + p->sound_interpol = 0; + p->sound_filter = 0; + + p->comptrustbyte = 0; + p->comptrustword = 0; + p->comptrustlong = 0; + p->comptrustnaddr= 0; + p->compnf = 1; + p->comp_hardflush = 0; + p->comp_constjump = 1; + p->comp_oldsegv = 0; + p->compfpu = 1; + p->compforcesettings = 0; + p->cachesize = 0; + p->avoid_cmov = 0; + p->avoid_dga = 0; + p->avoid_vid = 0; + p->comp_midopt = 0; + p->comp_lowopt = 0; + p->override_dga_address = 0; + { + int i; + for (i = 0;i < 10; i++) + p->optcount[i] = -1; + p->optcount[0] = 4; /* How often a block has to be executed before it + is translated */ + p->optcount[1] = 0; /* How often to use the naive translation */ + p->optcount[2] = 0; + p->optcount[3] = 0; + p->optcount[4] = 0; + p->optcount[5] = 0; + } + p->gfx_framerate = 1; + p->gfx_width_win = p->gfx_width_fs = 800; + p->gfx_height_win = p->gfx_height_fs = 600; + p->gfx_lores = 0; + p->gfx_linedbl = 2; + p->gfx_afullscreen = 0; + p->gfx_pfullscreen = 0; + p->gfx_correct_aspect = 0; + p->gfx_xcenter = 0; + p->gfx_ycenter = 0; + p->color_mode = 0; + + p->x11_use_low_bandwidth = 0; + p->x11_use_mitshm = 0; + p->x11_hide_cursor = 1; + + p->svga_no_linear = 0; + + p->curses_reverse_video = 0; + + target_default_options (p); + + p->immediate_blits = 0; + p->collision_level = 2; + p->leds_on_screen = 0; + p->keyboard_leds_in_use = 0; + p->keyboard_leds[0] = p->keyboard_leds[1] = p->keyboard_leds[2] = 0; + p->fast_copper = 1; + p->scsi = 0; + p->cpu_idle = 0; + p->catweasel_io = 0; + p->tod_hack = 0; + p->maprom = 0; + + p->gfx_filter = 0; + p->gfx_filter_filtermode = 1; + p->gfx_filter_scanlineratio = (1 << 4) | 1; + + strcpy (p->df[0], "df0.adf"); + strcpy (p->df[1], "df1.adf"); + strcpy (p->df[2], "df2.adf"); + strcpy (p->df[3], "df3.adf"); + + strcpy (p->romfile, "kick.rom"); + strcpy (p->keyfile, ""); + strcpy (p->romextfile, ""); + strcpy (p->flashfile, ""); + strcpy (p->cartfile, ""); + + strcpy (p->path_rom, "./"); + strcpy (p->path_floppy, "./"); + strcpy (p->path_hardfile, "./"); + + strcpy (p->prtname, DEFPRTNAME); + strcpy (p->sername, DEFSERNAME); + +#ifdef CPUEMU_68000_ONLY + p->cpu_level = 0; + p->m68k_speed = 0; +#else + p->m68k_speed = -1; + p->cpu_level = 2; +#endif +#ifdef CPUEMU_0 + p->cpu_compatible = 0; + p->address_space_24 = 0; +#else + p->cpu_compatible = 1; + p->address_space_24 = 1; +#endif + p->cpu_cycle_exact = 0; + p->blitter_cycle_exact = 0; + p->chipset_mask = CSMASK_ECS_AGNUS; + + p->fastmem_size = 0x00000000; + p->a3000mem_size = 0x00000000; + p->z3fastmem_size = 0x00000000; + p->chipmem_size = 0x00200000; + p->bogomem_size = 0x00000000; + p->gfxmem_size = 0x00000000; + + p->nr_floppies = 2; + p->dfxtype[0] = 0; + p->dfxtype[1] = 0; + p->dfxtype[2] = -1; + p->dfxtype[3] = -1; + p->floppy_speed = 100; + p->dfxclickvolume = 33; + + p->statecapturebuffersize = 20 * 1024 * 1024; + p->statecapturerate = 5 * 50; + p->statecapture = 0; + +#ifdef FILESYS + p->mountinfo = alloc_mountinfo (); +#endif + +#ifdef UAE_MINI + default_prefs_mini (p); +#endif + + inputdevice_default_prefs (p); +} diff --git a/cia.c b/cia.c new file mode 100755 index 00000000..2cc108e4 --- /dev/null +++ b/cia.c @@ -0,0 +1,1409 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * CIA chip support + * + * Copyright 1995 Bernd Schmidt, Alessandro Bissacco + * Copyright 1996, 1997 Stefan Reinauer, Christian Schmitt + */ + + +#include "sysconfig.h" +#include "sysdeps.h" +#include + +#include "config.h" +#include "options.h" +#include "threaddep/thread.h" +#include "events.h" +#include "memory.h" +#include "custom.h" +#include "cia.h" +#include "serial.h" +#include "disk.h" +#include "xwin.h" +#include "keybuf.h" +#include "gui.h" +#include "savestate.h" +#include "inputdevice.h" +#include "zfile.h" +#include "ar.h" +#ifdef CD32 +#include "akiko.h" +#endif +#include "debug.h" + +//#define CIA_DEBUG +//#define DONGLE_DEBUG + +#define TOD_HACK + +#define DIV10 (10 * CYCLE_UNIT / 2) /* Yes, a bad identifier. */ + +/* battclock stuff */ +#define RTC_D_ADJ 8 +#define RTC_D_IRQ 4 +#define RTC_D_BUSY 2 +#define RTC_D_HOLD 1 +#define RTC_E_t1 8 +#define RTC_E_t0 4 +#define RTC_E_INTR 2 +#define RTC_E_MASK 1 +#define RTC_F_TEST 8 +#define RTC_F_24_12 4 +#define RTC_F_STOP 2 +#define RTC_F_RSET 1 + +static unsigned int clock_control_d = RTC_D_ADJ + RTC_D_HOLD; +static unsigned int clock_control_e = 0; +static unsigned int clock_control_f = RTC_F_24_12; + +static unsigned int ciaaicr, ciaaimask, ciabicr, ciabimask; +static unsigned int ciaacra, ciaacrb, ciabcra, ciabcrb; + +/* Values of the CIA timers. */ +static unsigned long ciaata, ciaatb, ciabta, ciabtb; +/* Computed by compute_passed_time. */ +static unsigned long ciaata_passed, ciaatb_passed, ciabta_passed, ciabtb_passed; + +static unsigned long ciaatod, ciabtod, ciaatol, ciabtol, ciaaalarm, ciabalarm; +static int ciaatlatch, ciabtlatch; +static int oldled, oldovl; + +unsigned int ciabpra; + +unsigned int gui_ledstate; + +static unsigned long ciaala, ciaalb, ciabla, ciablb; +static int ciaatodon, ciabtodon; +static unsigned int ciaapra, ciaaprb, ciaadra, ciaadrb, ciaasdr, ciaasdr_cnt; +static unsigned int ciabprb, ciabdra, ciabdrb, ciabsdr, ciabsdr_cnt; +static int div10; +static int kbstate, kback, ciaasdr_unread; +#ifdef TOD_HACK +static int tod_hack; +#endif + +static uae_u8 serbits; + +static void setclr (unsigned int *p, unsigned int val) +{ + if (val & 0x80) { + *p |= val & 0x7F; + } else { + *p &= ~val; + } +} + +#include "newcpu.h" + +static void RethinkICRA (void) +{ + if (ciaaimask & ciaaicr) { + ciaaicr |= 0x80; + INTREQ_0 (0x8000 | 0x0008); + } else { + ciaaicr &= 0x7F; + } +} + +static void RethinkICRB (void) +{ + if (ciabimask & ciabicr) { + ciabicr |= 0x80; + INTREQ_0 (0x8000 | 0x2000); + } else { + ciabicr &= 0x7F; + } +} + +void rethink_cias (void) +{ + RethinkICRA (); + RethinkICRB (); +} + +/* Figure out how many CIA timer cycles have passed for each timer since the + last call of CIA_calctimers. */ + +static void compute_passed_time (void) +{ + unsigned long int ccount = (get_cycles () - eventtab[ev_cia].oldcycles + div10); + unsigned long int ciaclocks = ccount / DIV10; + + ciaata_passed = ciaatb_passed = ciabta_passed = ciabtb_passed = 0; + + /* CIA A timers */ + if ((ciaacra & 0x21) == 0x01) { + assert ((ciaata+1) >= ciaclocks); + ciaata_passed = ciaclocks; + } + if ((ciaacrb & 0x61) == 0x01) { + assert ((ciaatb+1) >= ciaclocks); + ciaatb_passed = ciaclocks; + } + + /* CIA B timers */ + if ((ciabcra & 0x21) == 0x01) { + assert ((ciabta+1) >= ciaclocks); + ciabta_passed = ciaclocks; + } + if ((ciabcrb & 0x61) == 0x01) { + assert ((ciabtb+1) >= ciaclocks); + ciabtb_passed = ciaclocks; + } +} + +/* Called to advance all CIA timers to the current time. This expects that + one of the timer values will be modified, and CIA_calctimers will be called + in the same cycle. */ + +static void CIA_update (void) +{ + unsigned long int ccount = (get_cycles () - eventtab[ev_cia].oldcycles + div10); + unsigned long int ciaclocks = ccount / DIV10; + + int aovfla = 0, aovflb = 0, asp = 0, bovfla = 0, bovflb = 0, bsp = 0; + + div10 = ccount % DIV10; + + /* CIA A timers */ + if ((ciaacra & 0x21) == 0x01) { + assert ((ciaata+1) >= ciaclocks); + if ((ciaata+1) == ciaclocks) { + if ((ciaacra & 0x48) == 0x40 && ciaasdr_cnt > 0 && --ciaasdr_cnt == 0) + asp = 1; + aovfla = 1; + if ((ciaacrb & 0x61) == 0x41) { + if (ciaatb-- == 0) + aovflb = 1; + } + } + ciaata -= ciaclocks; + } + if ((ciaacrb & 0x61) == 0x01) { + assert ((ciaatb+1) >= ciaclocks); + if ((ciaatb+1) == ciaclocks) aovflb = 1; + ciaatb -= ciaclocks; + } + + /* CIA B timers */ + if ((ciabcra & 0x21) == 0x01) { + assert ((ciabta+1) >= ciaclocks); + if ((ciabta+1) == ciaclocks) { + if ((ciabcra & 0x48) == 0x40 && ciabsdr_cnt > 0 && --ciabsdr_cnt == 0) + bsp = 1; + bovfla = 1; + if ((ciabcrb & 0x61) == 0x41) { + if (ciabtb-- == 0) + bovflb = 1; + } + } + ciabta -= ciaclocks; + } + if ((ciabcrb & 0x61) == 0x01) { + assert ((ciabtb+1) >= ciaclocks); + if ((ciabtb+1) == ciaclocks) bovflb = 1; + ciabtb -= ciaclocks; + } + + if (aovfla) { + ciaaicr |= 1; RethinkICRA(); + ciaata = ciaala; + if (ciaacra & 0x8) ciaacra &= ~1; + } + if (aovflb) { + ciaaicr |= 2; RethinkICRA(); + ciaatb = ciaalb; + if (ciaacrb & 0x8) ciaacrb &= ~1; + } + if (asp) { + ciaaicr |= 8; RethinkICRA(); + } + if (bovfla) { + ciabicr |= 1; RethinkICRB(); + ciabta = ciabla; + if (ciabcra & 0x8) ciabcra &= ~1; + } + if (bovflb) { + ciabicr |= 2; RethinkICRB(); + ciabtb = ciablb; + if (ciabcrb & 0x8) ciabcrb &= ~1; + } + if (bsp) { + ciabicr |= 8; RethinkICRB(); + } +} + +/* Call this only after CIA_update has been called in the same cycle. */ + +static void CIA_calctimers (void) +{ + long int ciaatimea = -1, ciaatimeb = -1, ciabtimea = -1, ciabtimeb = -1; + + eventtab[ev_cia].oldcycles = get_cycles (); + if ((ciaacra & 0x21) == 0x01) { + ciaatimea = (DIV10 - div10) + DIV10 * ciaata; + } + if ((ciaacrb & 0x61) == 0x41) { + /* Timer B will not get any pulses if Timer A is off. */ + if (ciaatimea >= 0) { + /* If Timer A is in one-shot mode, and Timer B needs more than + * one pulse, it will not underflow. */ + if (ciaatb == 0 || (ciaacra & 0x8) == 0) { + /* Otherwise, we can determine the time of the underflow. */ + /* This may overflow, however. So just ignore this timer and + use the fact that we'll call CIA_handler for the A timer. */ +#if 0 + ciaatimeb = ciaatimea + ciaala * DIV10 * ciaatb; +#endif + } + } + } + if ((ciaacrb & 0x61) == 0x01) { + ciaatimeb = (DIV10 - div10) + DIV10 * ciaatb; + } + + if ((ciabcra & 0x21) == 0x01) { + ciabtimea = (DIV10 - div10) + DIV10 * ciabta; + } + if ((ciabcrb & 0x61) == 0x41) { + /* Timer B will not get any pulses if Timer A is off. */ + if (ciabtimea >= 0) { + /* If Timer A is in one-shot mode, and Timer B needs more than + * one pulse, it will not underflow. */ + if (ciabtb == 0 || (ciabcra & 0x8) == 0) { + /* Otherwise, we can determine the time of the underflow. */ +#if 0 + ciabtimeb = ciabtimea + ciabla * DIV10 * ciabtb; +#endif + } + } + } + if ((ciabcrb & 0x61) == 0x01) { + ciabtimeb = (DIV10 - div10) + DIV10 * ciabtb; + } + eventtab[ev_cia].active = (ciaatimea != -1 || ciaatimeb != -1 + || ciabtimea != -1 || ciabtimeb != -1); + if (eventtab[ev_cia].active) { + unsigned long int ciatime = ~0L; + if (ciaatimea != -1) ciatime = ciaatimea; + if (ciaatimeb != -1 && ciaatimeb < ciatime) ciatime = ciaatimeb; + if (ciabtimea != -1 && ciabtimea < ciatime) ciatime = ciabtimea; + if (ciabtimeb != -1 && ciabtimeb < ciatime) ciatime = ciabtimeb; + eventtab[ev_cia].evtime = ciatime + get_cycles (); + } + events_schedule(); +} + +void CIA_handler (void) +{ + CIA_update (); + CIA_calctimers (); +} + +void cia_diskindex (void) +{ + ciabicr |= 0x10; + RethinkICRB(); +} + +static void ciab_checkalarm (void) +{ + if (ciabtod != ciabalarm) + return; + ciabicr |= 4; RethinkICRB(); +} + +static void ciaa_checkalarm (void) +{ + if (ciaatod != ciaaalarm) + return; + ciaaicr |= 4; RethinkICRA(); +} + +void CIA_hsync_handler (void) +{ + static unsigned int keytime = 0, sleepyhead = 0; + + if (ciabtodon) { + ciabtod++; + ciabtod &= 0xFFFFFF; + ciab_checkalarm (); + } + + if (keys_available() && kback && (ciaacra & 0x40) == 0 && (++keytime & 15) == 0) { + /* + * This hack lets one possible ciaaicr cycle go by without any key + * being read, for every cycle in which a key is pulled out of the + * queue. If no hack is used, a lot of key events just get lost + * when you type fast. With a simple hack that waits for ciaasdr + * to be read before feeding it another, it will keep up until the + * queue gets about 14 characters ahead and then lose events, and + * the mouse pointer will freeze while typing is being taken in. + * With this hack, you can type 30 or 40 characters ahead with little + * or no lossage, and the mouse doesn't get stuck. The tradeoff is + * that the total slowness of typing appearing on screen is worse. + */ + if (ciaasdr_unread == 2) { + ciaasdr_unread = 0; + } else if (ciaasdr_unread == 0) { + switch (kbstate) { + case 0: + ciaasdr = (uae_s8)~0xFB; /* aaarghh... stupid compiler */ + kbstate++; + break; + case 1: + kbstate++; + ciaasdr = (uae_s8)~0xFD; + break; + case 2: + ciaasdr = ~get_next_key(); + ciaasdr_unread = 1; /* interlock to prevent lost keystrokes */ + break; + } + ciaaicr |= 8; + RethinkICRA(); + sleepyhead = 0; + } else if (!(++sleepyhead & 15)) { + ciaasdr_unread = 0; /* give up on this key event after unread for a long time */ + } + } +} + +#ifdef TOD_HACK +static void tod_hack_reset (void) +{ + struct timeval tv; + uae_u32 rate = currprefs.ntscmode ? 60 : 50; + gettimeofday (&tv, NULL); + tod_hack = (uae_u32)(((uae_u64)tv.tv_sec) * rate + tv.tv_usec / (1000000 / rate)); + tod_hack += ciaatod; +} +#endif + +void CIA_vsync_handler () +{ +#ifdef TOD_HACK + if (currprefs.tod_hack && ciaatodon) { + struct timeval tv; + uae_u32 t, nt, rate = currprefs.ntscmode ? 60 : 50; + gettimeofday (&tv, NULL); + t = (uae_u32)(((uae_u64)tv.tv_sec) * rate + tv.tv_usec / (1000000 / rate)); + nt = t - tod_hack; + if ((nt < ciaatod && ciaatod - nt < 10) || nt == ciaatod) + return; /* try not to count backwards */ + ciaatod = nt; + ciaatod &= 0xffffff; + ciaa_checkalarm (); + return; + } +#endif + if (ciaatodon) { + ciaatod++; + ciaatod &= 0xFFFFFF; + ciaa_checkalarm (); + } +} + +static void bfe001_change (void) +{ + uae_u8 v = ciaapra; + + v |= ~ciaadra; /* output is high when pin's direction is input */ + if ((v & 2) != oldled) { + int led = (v & 2) ? 0 : 1; + oldled = v & 2; + gui_led (0, led); + gui_ledstate &= ~1; + gui_data.powerled = led; + gui_ledstate |= led; + } + if ((v & 1) != oldovl) { + oldovl = v & 1; + if (!oldovl || ersatzkickfile) { + map_overlay (1); + } else if (!(currprefs.chipset_mask & CSMASK_AGA)) { + /* pin disconnected in AGA chipset, CD audio mute on/off on CD32 */ + map_overlay (0); + } + } +} + +#ifdef PARALLEL_PORT +extern int isprinter (void); +extern int doprinter (uae_u8); +#endif + +static uae_u8 ReadCIAA (unsigned int addr) +{ + unsigned int tmp; + + compute_passed_time (); + +#ifdef CIA_DEBUG + write_log("R_CIAA: %02.2X %08.8X\n", addr, m68k_getpc()); +#endif + + switch (addr & 0xf) { + case 0: +#ifdef ACTION_REPLAY + action_replay_ciaread(); +#endif + tmp = DISK_status() & 0x3c; + tmp |= handle_joystick_buttons (ciaadra); + tmp |= (ciaapra | (ciaadra ^ 3)) & 0x03; + if (ciaadra & 0x40) + tmp = (tmp & ~0x40) | (ciaapra & 0x40); + if (ciaadra & 0x80) + tmp = (tmp & ~0x80) | (ciaapra & 0x80); +#ifdef DONGLE_DEBUG + if (notinrom()) + write_log ("BFE001 R %02.2X %s\n", tmp, debuginfo(0)); +#endif + return tmp; + case 1: +#ifdef PARALLEL_PORT + if (isprinter () > 0) { + tmp = ciaaprb; + } else if (isprinter () < 0) { + uae_u8 v; + parallel_direct_read_data (&v); + tmp = v; + } else { + tmp = handle_parport_joystick (0, ciaaprb, ciaadrb); + } +#else + tmp = handle_parport_joystick (0, ciaaprb, ciaadrb); +#ifdef DONGLE_DEBUG + if (notinrom()) + write_log ("BFE101 R %02.2X %s\n", tmp, debuginfo(0)); +#endif +#endif + return tmp; + case 2: +#ifdef DONGLE_DEBUG + if (notinrom ()) + write_log ("BFE201 R %02.2X %s\n", ciaadra, debuginfo(0)); +#endif + return ciaadra; + case 3: +#ifdef DONGLE_DEBUG + if (notinrom ()) + write_log ("BFE301 R %02.2X %s\n", ciaadrb, debuginfo(0)); +#endif + return ciaadrb; + case 4: + return (uae_u8)((ciaata - ciaata_passed) & 0xff); + case 5: + return (uae_u8)((ciaata - ciaata_passed) >> 8); + case 6: + return (uae_u8)((ciaatb - ciaatb_passed) & 0xff); + case 7: + return (uae_u8)((ciaatb - ciaatb_passed) >> 8); + case 8: + if (ciaatlatch) { + ciaatlatch = 0; + return (uae_u8)ciaatol; + } else + return (uae_u8)ciaatod; + case 9: + if (ciaatlatch) + return (uae_u8)(ciaatol >> 8); + else + return (uae_u8)(ciaatod >> 8); + case 10: + ciaatlatch = 1; + ciaatol = ciaatod; /* ??? only if not already latched? */ + return (uae_u8)(ciaatol >> 16); + case 12: + if (ciaasdr_unread == 1) + ciaasdr_unread = 2; + return ciaasdr; + case 13: + tmp = ciaaicr; ciaaicr = 0; RethinkICRA(); + return tmp; + case 14: + return ciaacra; + case 15: + return ciaacrb; + } + return 0; +} + +static uae_u8 ReadCIAB (unsigned int addr) +{ + unsigned int tmp; + +#ifdef CIA_DEBUG + write_log("R_CIAB: %02.2X %08.8X\n", addr, m68k_getpc()); +#endif + + compute_passed_time (); + + switch (addr & 0xf) { + case 0: + tmp = 0; +#ifdef SERIAL_PORT + if (currprefs.use_serial) + tmp = serial_readstatus(ciabdra); +#endif +#ifdef PARALLEL_PORT + if (isprinter () > 0) { + tmp |= ciabpra & (0x04 | 0x02 | 0x01); + } else if (isprinter () < 0) { + uae_u8 v; + parallel_direct_read_status (&v); + tmp |= v & 7; + } else { + tmp |= handle_parport_joystick (1, ciabpra, ciabdra); + } +#endif +#ifdef DONGLE_DEBUG + if (notinrom ()) + write_log ("BFD000 R %02.2X %s\n", tmp, debuginfo(0)); +#endif + return tmp; + case 1: +#ifdef DONGLE_DEBUG + if (notinrom ()) + write_log ("BFD100 R %02.2X %s\n", ciabprb, debuginfo(0)); +#endif + return ciabprb; + case 2: + return ciabdra; + case 3: + return ciabdrb; + case 4: + return (uae_u8)((ciabta - ciabta_passed) & 0xff); + case 5: + return (uae_u8)((ciabta - ciabta_passed) >> 8); + case 6: + return (uae_u8)((ciabtb - ciabtb_passed) & 0xff); + case 7: + return (uae_u8)((ciabtb - ciabtb_passed) >> 8); + case 8: + if (ciabtlatch) { + ciabtlatch = 0; + return (uae_u8)ciabtol; + } else + return (uae_u8)ciabtod; + case 9: + if (ciabtlatch) + return (uae_u8)(ciabtol >> 8); + else + return (uae_u8)(ciabtod >> 8); + case 10: + ciabtlatch = 1; + ciabtol = ciabtod; + return (uae_u8)(ciabtol >> 16); + case 12: + return ciabsdr; + case 13: + tmp = ciabicr; ciabicr = 0; RethinkICRB(); + return tmp; + case 14: + return ciabcra; + case 15: + return ciabcrb; + } + return 0; +} + +static void WriteCIAA (uae_u16 addr,uae_u8 val) +{ +#ifdef CIA_DEBUG + write_log("W_CIAA: %02.2X %02.2X %08.8X\n", addr, val, m68k_getpc()); +#endif + switch (addr & 0xf) { + case 0: +#ifdef DONGLE_DEBUG + if (notinrom ()) + write_log ("BFE001 W %02.2X %s\n", val, debuginfo(0)); +#endif + ciaapra = (ciaapra & ~0xc3) | (val & 0xc3); + bfe001_change (); + handle_cd32_joystick_cia (ciaapra, ciaadra); + break; + case 1: +#ifdef DONGLE_DEBUG + if (notinrom ()) + write_log ("BFE101 W %02.2X %s\n", val, debuginfo(0)); +#endif + ciaaprb = val; +#ifdef PARALLEL_PORT + if (isprinter() > 0) { + doprinter (val); + ciaaicr |= 0x10; + } else if (isprinter() < 0) { + parallel_direct_write_data (val, ciaadrb); + ciaaicr |= 0x10; + } +#endif + break; + case 2: +#ifdef DONGLE_DEBUG + if (notinrom ()) + write_log ("BFE201 W %02.2X %s\n", val, debuginfo(0)); +#endif + ciaadra = val; bfe001_change (); break; + case 3: +#ifdef DONGLE_DEBUG + if (notinrom ()) + write_log ("BFE301 W %02.2X %s\n", val, debuginfo(0)); +#endif + ciaadrb = val; break; + case 4: + CIA_update (); + ciaala = (ciaala & 0xff00) | val; + CIA_calctimers (); + break; + case 5: + CIA_update (); + ciaala = (ciaala & 0xff) | (val << 8); + if ((ciaacra & 1) == 0) + ciaata = ciaala; + if (ciaacra & 8) { + ciaata = ciaala; + ciaacra |= 1; + } + CIA_calctimers (); + break; + case 6: + CIA_update (); + ciaalb = (ciaalb & 0xff00) | val; + CIA_calctimers (); + break; + case 7: + CIA_update (); + ciaalb = (ciaalb & 0xff) | (val << 8); + if ((ciaacrb & 1) == 0) + ciaatb = ciaalb; + if (ciaacrb & 8) { + ciaatb = ciaalb; + ciaacrb |= 1; + } + CIA_calctimers (); + break; + case 8: + if (ciaacrb & 0x80) { + ciaaalarm = (ciaaalarm & ~0xff) | val; + } else { + ciaatod = (ciaatod & ~0xff) | val; + ciaatodon = 1; + ciaa_checkalarm (); +#if 0 +#ifdef TOD_HACK + if (currprefs.tod_hack) + tod_hack_reset (); +#endif +#endif + } + break; + case 9: + if (ciaacrb & 0x80) { + ciaaalarm = (ciaaalarm & ~0xff00) | (val << 8); + } else { + ciaatod = (ciaatod & ~0xff00) | (val << 8); + ciaatodon = 0; + } + break; + case 10: + if (ciaacrb & 0x80) { + ciaaalarm = (ciaaalarm & ~0xff0000) | (val << 16); + } else { + ciaatod = (ciaatod & ~0xff0000) | (val << 16); + ciaatodon = 0; + } + break; + case 12: + CIA_update (); + ciaasdr = val; + if (ciaacra & 0x40) { + kback = 1; + } else { + ciaasdr_cnt = 0; + } + if ((ciaacra & 0x41) == 0x41) + ciaasdr_cnt = 8 * 2; + CIA_calctimers (); + break; + case 13: + setclr(&ciaaimask,val); + break; + case 14: + CIA_update (); + val &= 0x7f; /* bit 7 is unused */ + ciaacra = val; + if (ciaacra & 0x10) { + ciaacra &= ~0x10; + ciaata = ciaala; + } + if (ciaacra & 0x40) + kback = 1; + CIA_calctimers (); + break; + case 15: + CIA_update (); + ciaacrb = val; + if (ciaacrb & 0x10) { + ciaacrb &= ~0x10; + ciaatb = ciaalb; + } + CIA_calctimers (); + break; + } +} + +static void WriteCIAB (uae_u16 addr,uae_u8 val) +{ +#ifdef CIA_DEBUG + write_log("W_CIAB: %02.2X %02.2X %08.8X\n", addr, val, m68k_getpc()); +#endif + switch (addr & 0xf) { + case 0: +#ifdef DONGLE_DEBUG + if (notinrom ()) + write_log ("BFD000 W %02.2X %s\n", val, debuginfo(0)); +#endif + ciabpra = val; +#ifdef SERIAL_PORT + if (currprefs.use_serial) + serial_writestatus(ciabpra, ciabdra); +#endif +#ifdef PARALLEL_PORT + if (isprinter () < 0) + parallel_direct_write_status (val, ciabdra); +#endif + break; + case 1: +#ifdef DONGLE_DEBUG + if (notinrom ()) + write_log ("BFD100 W %02.2X %s\n", val, debuginfo(0)); +#endif + ciabprb = val; DISK_select(val); break; + case 2: +#ifdef DONGLE_DEBUG + if (notinrom ()) + write_log ("BFD200 W %02.2X %s\n", val, debuginfo(0)); +#endif + ciabdra = val; +#ifdef SERIAL_PORT + if (currprefs.use_serial) + serial_writestatus (ciabpra, ciabdra); +#endif + break; + case 3: +#ifdef DONGLE_DEBUG + if (notinrom ()) + write_log ("BFD300 W %02.2X %s\n", val, debuginfo(0)); +#endif + ciabdrb = val; break; + case 4: + CIA_update (); + ciabla = (ciabla & 0xff00) | val; + CIA_calctimers (); + break; + case 5: + CIA_update (); + ciabla = (ciabla & 0xff) | (val << 8); + if ((ciabcra & 1) == 0) + ciabta = ciabla; + if (ciabcra & 8) { + ciabta = ciabla; + ciabcra |= 1; + } + CIA_calctimers (); + break; + case 6: + CIA_update (); + ciablb = (ciablb & 0xff00) | val; + CIA_calctimers (); + break; + case 7: + CIA_update (); + ciablb = (ciablb & 0xff) | (val << 8); + if ((ciabcrb & 1) == 0) + ciabtb = ciablb; + if (ciabcrb & 8) { + ciabtb = ciablb; + ciabcrb |= 1; + } + CIA_calctimers (); + break; + case 8: + if (ciabcrb & 0x80) { + ciabalarm = (ciabalarm & ~0xff) | val; + } else { + ciabtod = (ciabtod & ~0xff) | val; + ciabtodon = 1; + ciab_checkalarm (); + } + break; + case 9: + if (ciabcrb & 0x80) { + ciabalarm = (ciabalarm & ~0xff00) | (val << 8); + } else { + ciabtod = (ciabtod & ~0xff00) | (val << 8); + ciabtodon = 0; + } + break; + case 10: + if (ciabcrb & 0x80) { + ciabalarm = (ciabalarm & ~0xff0000) | (val << 16); + } else { + ciabtod = (ciabtod & ~0xff0000) | (val << 16); + ciabtodon = 0; + } + break; + case 12: + CIA_update (); + ciabsdr = val; + if ((ciabcra & 0x41) == 0x41) + ciabsdr_cnt = 8 * 2; + if ((ciabcra & 0x40) == 0) + ciabsdr_cnt = 0; + CIA_calctimers (); + break; + case 13: + setclr(&ciabimask,val); + break; + case 14: + CIA_update (); + val &= 0x7f; /* bit 7 is unused */ + ciabcra = val; + if (ciabcra & 0x10) { + ciabcra &= ~0x10; + ciabta = ciabla; + } + CIA_calctimers (); + break; + case 15: + CIA_update (); + ciabcrb = val; + if (ciabcrb & 0x10) { + ciabcrb &= ~0x10; + ciabtb = ciablb; + } + CIA_calctimers (); + break; + } +} + +void CIA_reset (void) +{ +#ifdef TOD_HACK + tod_hack = 0; + if (currprefs.tod_hack) + tod_hack_reset (); +#endif + kback = 1; + kbstate = 0; + ciaasdr_unread = 0; + serbits = 0; + oldovl = -1; + oldled = -1; + + if (!savestate_state) { + ciaatlatch = ciabtlatch = 0; + ciaapra = 0; ciaadra = 0; + ciaatod = ciabtod = 0; ciaatodon = ciabtodon = 0; + ciaaicr = ciabicr = ciaaimask = ciabimask = 0; + ciaacra = ciaacrb = ciabcra = ciabcrb = 0x4; /* outmode = toggle; */ + ciaala = ciaalb = ciabla = ciablb = ciaata = ciaatb = ciabta = ciabtb = 0xFFFF; + ciaaalarm = ciabalarm = 0; + ciabpra = 0x8C; ciabdra = 0; + div10 = 0; + ciaasdr_cnt = 0; ciaasdr = 0; + ciabsdr_cnt = 0; ciabsdr = 0; + } + CIA_calctimers (); + if (! ersatzkickfile) + map_overlay (0); +#ifdef SERIAL_PORT + if (currprefs.use_serial && !savestate_state) + serial_dtr_off (); /* Drop DTR at reset */ +#endif + if (savestate_state) { + bfe001_change (); + /* select drives */ + DISK_select (ciabprb); + } +#ifdef CD32 + if (cd32_enabled) { + akiko_reset (); + if (!akiko_init ()) + cd32_enabled = 0; + } +#endif +} + +void dumpcia (void) +{ + write_log("A: CRA %02x CRB %02x ICR %02x IM %02x TOD %06x %c%c TA %04x (%04x) TB %04x (%04x)\n", + ciaacra, ciaacrb, ciaaicr, ciaaimask, ciaatod, + ciaatlatch ? 'L' : ' ', ciaatodon ? ' ' : 'S', ciaata, ciaala, ciaatb, ciaalb); + write_log("B: CRA %02x CRB %02x ICR %02x IM %02x TOD %06x %c%c TA %04x (%04x) TB %04x (%04x)\n", + ciabcra, ciabcrb, ciaaicr, ciabimask, ciabtod, + ciabtlatch ? 'L' : ' ', ciabtodon ? ' ' : 'S', ciabta, ciabla, ciabtb, ciablb); +} + +/* CIA memory access */ + +static uae_u32 cia_lget (uaecptr) REGPARAM; +static uae_u32 cia_wget (uaecptr) REGPARAM; +static uae_u32 cia_bget (uaecptr) REGPARAM; +static void cia_lput (uaecptr, uae_u32) REGPARAM; +static void cia_wput (uaecptr, uae_u32) REGPARAM; +static void cia_bput (uaecptr, uae_u32) REGPARAM; + +addrbank cia_bank = { + cia_lget, cia_wget, cia_bget, + cia_lput, cia_wput, cia_bput, + default_xlate, default_check, NULL +}; + + +#ifdef CD32 +extern uae_u32 akiko_lget (uaecptr addr); +extern uae_u32 akiko_wget (uaecptr addr); +extern uae_u32 akiko_bget (uaecptr addr); +extern void akiko_bput (uaecptr addr, uae_u32 value); +extern void akiko_wput (uaecptr addr, uae_u32 value); +extern void akiko_lput (uaecptr addr, uae_u32 value); +#endif + +/* e-clock is 10 CPU cycles, 6 cycles low, 4 high + * data transfer happens during 4 high cycles + */ + +#define ECLOCK_DATA_CYCLE 4 + +static void cia_wait_pre (void) +{ +#ifndef CUSTOM_SIMPLE + int div10 = (get_cycles () - eventtab[ev_cia].oldcycles) % DIV10; + int cycles; + + cycles = 2 * CYCLE_UNIT / 2; + if (div10 > DIV10 * ECLOCK_DATA_CYCLE / 10) { + cycles += DIV10 - div10; + cycles += DIV10 * ECLOCK_DATA_CYCLE / 10; + } else { + cycles += DIV10 * ECLOCK_DATA_CYCLE / 10 - div10; + } + do_cycles (cycles); +#endif +} + +static void cia_wait_post (void) +{ + do_cycles (2 * CYCLE_UNIT / 2); +} + +uae_u32 REGPARAM2 cia_bget (uaecptr addr) +{ + int r = (addr & 0xf00) >> 8; + uae_u8 v; + +#ifdef JIT + special_mem |= S_READ; +#endif +#ifdef CD32 + if (cd32_enabled && addr >= AKIKO_BASE && addr < AKIKO_BASE_END) + return akiko_bget (addr); +#endif + cia_wait_pre (); + v = 0xff; + switch ((addr >> 12) & 3) + { + case 0: + v = (addr & 1) ? ReadCIAA (r) : ReadCIAB (r); + break; + case 1: + v = (addr & 1) ? 0xff : ReadCIAB (r); + break; + case 2: + v = (addr & 1) ? ReadCIAA (r) : 0xff; + break; + } + cia_wait_post (); + return v; +} + +uae_u32 REGPARAM2 cia_wget (uaecptr addr) +{ + int r = (addr & 0xf00) >> 8; + uae_u16 v; + +#ifdef JIT + special_mem |= S_READ; +#endif +#ifdef CD32 + if (cd32_enabled && addr >= AKIKO_BASE && addr < AKIKO_BASE_END) + return akiko_wget (addr); +#endif + cia_wait_pre (); + v = 0xffff; + switch ((addr >> 12) & 3) + { + case 0: + v = (ReadCIAB (r) << 8) | ReadCIAA (r); + break; + case 1: + v = (ReadCIAB (r) << 8) | 0xff; + break; + case 2: + v = (0xff << 8) | ReadCIAA (r); + break; + } + cia_wait_post (); + return v; +} + +uae_u32 REGPARAM2 cia_lget (uaecptr addr) +{ + uae_u32 v; +#ifdef JIT + special_mem |= S_READ; +#endif +#ifdef CD32 + if (cd32_enabled && addr >= AKIKO_BASE && addr < AKIKO_BASE_END) + return akiko_lget (addr); +#endif + v = cia_wget (addr) << 16; + v |= cia_wget (addr + 2); + return v; +} + +void REGPARAM2 cia_bput (uaecptr addr, uae_u32 value) +{ + int r = (addr & 0xf00) >> 8; +#ifdef JIT + special_mem |= S_WRITE; +#endif +#ifdef CD32 + if (cd32_enabled && addr >= AKIKO_BASE && addr < AKIKO_BASE_END) { + akiko_bput (addr, value); + return; + } +#endif + cia_wait_pre (); + if ((addr & 0x2000) == 0) + WriteCIAB (r, value); + if ((addr & 0x1000) == 0) + WriteCIAA (r, value); + cia_wait_post (); +} + +void REGPARAM2 cia_wput (uaecptr addr, uae_u32 value) +{ + int r = (addr & 0xf00) >> 8; +#ifdef JIT + special_mem |= S_WRITE; +#endif +#ifdef CD32 + if (cd32_enabled && addr >= AKIKO_BASE && addr < AKIKO_BASE_END) { + akiko_wput (addr, value); + return; + } +#endif + cia_wait_pre (); + if ((addr & 0x2000) == 0) + WriteCIAB (r, value >> 8); + if ((addr & 0x1000) == 0) + WriteCIAA (r, value & 0xff); + cia_wait_post (); +} + +void REGPARAM2 cia_lput (uaecptr addr, uae_u32 value) +{ +#ifdef JIT + special_mem |= S_WRITE; +#endif +#ifdef CD32 + if (cd32_enabled && addr >= AKIKO_BASE && addr < AKIKO_BASE_END) { + akiko_lput (addr, value); + return; + } +#endif + cia_wput (addr, value >> 16); + cia_wput (addr + 2, value & 0xffff); +} + +#ifdef CDTV +/* CDTV batterybacked RAM emulation */ + +static uae_u8 cdtv_battram[4096]; +#define CDTV_NVRAM_MASK 4095 +#define CDTV_NVRAM_SIZE 2048 +int cdtv_enabled; + +static void cdtv_battram_reset (void) +{ + struct zfile *f = zfile_fopen (currprefs.flashfile,"rb"); + if (!f) + return; + zfile_fread (cdtv_battram, CDTV_NVRAM_SIZE,1 ,f); + zfile_fclose (f); +} + +static void cdtv_battram_write (int addr, int v) +{ + struct zfile *f; + int offset = addr & CDTV_NVRAM_MASK; + if (offset >= CDTV_NVRAM_SIZE) return; + if (cdtv_battram[offset] == v) return; + cdtv_battram[offset] = v; + f = zfile_fopen (currprefs.flashfile,"rb+"); + if (!f) + return; + zfile_fseek (f, offset, SEEK_SET); + zfile_fwrite (cdtv_battram + offset, 1, 1, f); + zfile_fclose (f); +} + +static uae_u8 cdtv_battram_read (int addr) +{ + uae_u8 v; + int offset; + offset = addr & CDTV_NVRAM_MASK; + if (offset >= CDTV_NVRAM_SIZE) return 0; + v = cdtv_battram[offset]; + return v; +} +#endif + +/* battclock memory access */ + +static uae_u32 clock_lget (uaecptr) REGPARAM; +static uae_u32 clock_wget (uaecptr) REGPARAM; +static uae_u32 clock_bget (uaecptr) REGPARAM; +static void clock_lput (uaecptr, uae_u32) REGPARAM; +static void clock_wput (uaecptr, uae_u32) REGPARAM; +static void clock_bput (uaecptr, uae_u32) REGPARAM; + +addrbank clock_bank = { + clock_lget, clock_wget, clock_bget, + clock_lput, clock_wput, clock_bput, + default_xlate, default_check, NULL +}; + +uae_u32 REGPARAM2 clock_lget (uaecptr addr) +{ + return (clock_wget (addr) << 16) | clock_wget (addr + 2); +} + +uae_u32 REGPARAM2 clock_wget (uaecptr addr) +{ + return (clock_bget (addr) << 8) | clock_bget (addr + 1); +} + +uae_u32 REGPARAM2 clock_bget (uaecptr addr) +{ + time_t t = time(0); + struct tm *ct; + +#ifdef CDTV + if (cdtv_enabled && addr >= 0xdc8000) + return cdtv_battram_read (addr); +#endif + ct = localtime (&t); +#ifdef JIT + special_mem |= S_READ; +#endif + switch (addr & 0x3f) { + case 0x03: return ct->tm_sec % 10; + case 0x07: return ct->tm_sec / 10; + case 0x0b: return ct->tm_min % 10; + case 0x0f: return ct->tm_min / 10; + case 0x13: return ct->tm_hour % 10; + case 0x17: return ct->tm_hour / 10; + case 0x1b: return ct->tm_mday % 10; + case 0x1f: return ct->tm_mday / 10; + case 0x23: return (ct->tm_mon+1) % 10; + case 0x27: return (ct->tm_mon+1) / 10; + case 0x2b: return ct->tm_year % 10; + case 0x2f: return ct->tm_year / 10; + case 0x33: return ct->tm_wday; /*Hack by -=SR=- */ + case 0x37: return clock_control_d; + case 0x3b: return clock_control_e; + case 0x3f: return clock_control_f; + } + return 0; +} + +void REGPARAM2 clock_lput (uaecptr addr, uae_u32 value) +{ + clock_wput (addr, value >> 16); + clock_wput (addr + 2, value); +} + +void REGPARAM2 clock_wput (uaecptr addr, uae_u32 value) +{ + clock_bput (addr, value >> 8); + clock_bput (addr + 1, value); +} + +void REGPARAM2 clock_bput (uaecptr addr, uae_u32 value) +{ +#ifdef JIT + special_mem |= S_WRITE; +#endif +#ifdef CDTV + if (cdtv_enabled && addr >= 0xdc8000) { + cdtv_battram_write (addr, value); + return; + } +#endif + switch (addr & 0x3f) { + case 0x37: clock_control_d = value; break; + case 0x3b: clock_control_e = value; break; + case 0x3f: clock_control_f = value; break; + } +} + +/* CIA-A and CIA-B save/restore code */ + +uae_u8 *restore_cia (int num, uae_u8 *src) +{ + uae_u8 b; + uae_u16 w; + uae_u32 l; + + /* CIA registers */ + b = restore_u8 (); /* 0 PRA */ + if (num) ciabpra = b; else ciaapra = b; + b = restore_u8 (); /* 1 PRB */ + if (num) ciabprb = b; else ciaaprb = b; + b = restore_u8 (); /* 2 DDRA */ + if (num) ciabdra = b; else ciaadra = b; + b = restore_u8 (); /* 3 DDRB */ + if (num) ciabdrb = b; else ciaadrb = b; + w = restore_u16 (); /* 4 TA */ + if (num) ciabta = w; else ciaata = w; + w = restore_u16 (); /* 6 TB */ + if (num) ciabtb = w; else ciaatb = w; + l = restore_u8 (); /* 8/9/A TOD */ + l |= restore_u8 () << 8; + l |= restore_u8 () << 16; + if (num) ciabtod = l; else ciaatod = l; + restore_u8 (); /* B unused */ + b = restore_u8 (); /* C SDR */ + if (num) ciabsdr = b; else ciaasdr = b; + b = restore_u8 (); /* D ICR INFORMATION (not mask!) */ + if (num) ciabicr = b; else ciaaicr = b; + b = restore_u8 (); /* E CRA */ + if (num) ciabcra = b; else ciaacra = b; + b = restore_u8 (); /* F CRB */ + if (num) ciabcrb = b; else ciaacrb = b; + +/* CIA internal data */ + + b = restore_u8 (); /* ICR MASK */ + if (num) ciabimask = b; else ciaaimask = b; + w = restore_u8 (); /* timer A latch */ + w |= restore_u8 () << 8; + if (num) ciabla = w; else ciaala = w; + w = restore_u8 (); /* timer B latch */ + w |= restore_u8 () << 8; + if (num) ciablb = w; else ciaalb = w; + w = restore_u8 (); /* TOD latched value */ + w |= restore_u8 () << 8; + w |= restore_u8 () << 16; + if (num) ciabtol = w; else ciaatol = w; + l = restore_u8 (); /* alarm */ + l |= restore_u8 () << 8; + l |= restore_u8 () << 16; + if (num) ciabalarm = l; else ciaaalarm = l; + b = restore_u8 (); + if (num) ciabtlatch = b & 1; else ciaatlatch = b & 1; /* is TOD latched? */ + if (num) ciabtodon = b & 2; else ciaatodon = b & 2; /* is TOD stopped? */ + b = restore_u8 (); + if (num) + div10 = CYCLE_UNIT * b; + b = restore_u8 (); + if (num) ciabsdr_cnt = b; else ciaasdr_cnt = b; + return src; +} + +uae_u8 *save_cia (int num, int *len, uae_u8 *dstptr) +{ + uae_u8 *dstbak,*dst, b; + uae_u16 t; + + if (dstptr) + dstbak = dst = dstptr; + else + dstbak = dst = malloc (16 + 12 + 1 + 1); + + compute_passed_time (); + + /* CIA registers */ + + b = num ? ciabpra : ciaapra; /* 0 PRA */ + save_u8 (b); + b = num ? ciabprb : ciaaprb; /* 1 PRB */ + save_u8 (b); + b = num ? ciabdra : ciaadra; /* 2 DDRA */ + save_u8 (b); + b = num ? ciabdrb : ciaadrb; /* 3 DDRB */ + save_u8 (b); + t = (num ? ciabta - ciabta_passed : ciaata - ciaata_passed);/* 4 TA */ + save_u16 (t); + t = (num ? ciabtb - ciabtb_passed : ciaatb - ciaatb_passed);/* 8 TB */ + save_u16 (t); + b = (num ? ciabtod : ciaatod); /* 8 TODL */ + save_u8 (b); + b = (num ? ciabtod >> 8 : ciaatod >> 8); /* 9 TODM */ + save_u8 (b); + b = (num ? ciabtod >> 16 : ciaatod >> 16); /* A TODH */ + save_u8 (b); + save_u8 (0); /* B unused */ + b = num ? ciabsdr : ciaasdr; /* C SDR */ + save_u8 (b); + b = num ? ciabicr : ciaaicr; /* D ICR INFORMATION (not mask!) */ + save_u8 (b); + b = num ? ciabcra : ciaacra; /* E CRA */ + save_u8 (b); + b = num ? ciabcrb : ciaacrb; /* F CRB */ + save_u8 (b); + + /* CIA internal data */ + + save_u8 (num ? ciabimask : ciaaimask); /* ICR */ + b = (num ? ciabla : ciaala); /* timer A latch LO */ + save_u8 (b); + b = (num ? ciabla >> 8 : ciaala >> 8); /* timer A latch HI */ + save_u8 (b); + b = (num ? ciablb : ciaalb); /* timer B latch LO */ + save_u8 (b); + b = (num ? ciablb >> 8 : ciaalb >> 8); /* timer B latch HI */ + save_u8 (b); + b = (num ? ciabtol : ciaatol); /* latched TOD LO */ + save_u8 (b); + b = (num ? ciabtol >> 8 : ciaatol >> 8); /* latched TOD MED */ + save_u8 (b); + b = (num ? ciabtol >> 16 : ciaatol >> 16); /* latched TOD HI */ + save_u8 (b); + b = (num ? ciabalarm : ciaaalarm); /* alarm LO */ + save_u8 (b); + b = (num ? ciabalarm >> 8 : ciaaalarm >>8 ); /* alarm MED */ + save_u8 (b); + b = (num ? ciabalarm >> 16 : ciaaalarm >> 16); /* alarm HI */ + save_u8 (b); + b = 0; + if (num) + b |= ciabtlatch ? 1 : 0; + else + b |= ciaatlatch ? 1 : 0; /* is TOD latched? */ + if (num) + b |= ciabtodon ? 2 : 0; + else + b |= ciaatodon ? 2 : 0; /* TOD stopped? */ + save_u8 (b); + save_u8 (div10 / CYCLE_UNIT); + save_u8 (num ? ciabsdr_cnt : ciaasdr_cnt); + *len = dst - dstbak; + return dstbak; +} diff --git a/compemu_fpp.c b/compemu_fpp.c new file mode 100755 index 00000000..377dcb92 --- /dev/null +++ b/compemu_fpp.c @@ -0,0 +1,1561 @@ +/* + * UAE - The Un*x Amiga Emulator + * + * MC68881 emulation + * + * Copyright 1996 Herman ten Brugge + * Adapted for JIT compilation (c) Bernd Meyer, 2000 + */ + +#include + +#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. +>=== 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); +} diff --git a/compemu_optimizer.c b/compemu_optimizer.c new file mode 100755 index 00000000..e48d57d7 --- /dev/null +++ b/compemu_optimizer.c @@ -0,0 +1,174 @@ +#if USE_OPTIMIZER +/* Welcome to the magical world of cpp ;-) */ + +#define USE_REGALLOC optlev>=2 + +#define opt_op0(dummy) opt_store_op0() +#define opt_op1(a1) opt_store_op1(OPT_##a1) +#define opt_op2(a1,a2) opt_store_op2(OPT_##a1,OPT_##a2) +#define opt_op3(a1,a2,a3) opt_store_op3(OPT_##a1,OPT_##a2,OPT_##a3) +#define opt_op4(a1,a2,a3,a4) opt_store_op4(OPT_##a1,OPT_##a2,OPT_##a3,OPT_##a4) +#define opt_op5(a1,a2,a3,a4,a5) opt_store_op5(OPT_##a1,OPT_##a2,OPT_##a3,OPT_##a4,OPT_##a5) + +#define direct0(dummy) () +#define direct1(a1) (DIR_##a1) +#define direct2(a1,a2) (DIR_##a1,DIR_##a2) +#define direct3(a1,a2,a3) (DIR_##a1,DIR_##a2,DIR_##a3) +#define direct4(a1,a2,a3,a4) (DIR_##a1,DIR_##a2,DIR_##a3,DIR_##a4) +#define direct5(a1,a2,a3,a4,a5) (DIR_##a1,DIR_##a2,DIR_##a3,DIR_##a4,DIR_##a5) + +#define OIMM 0 +#define OMEMR 0 +#define OMEMW 0 +#define OMEMRW 0 /* These are all 32 bit immediates */ +#define OR1 1 +#define OR2 2 +#define OR4 3 +#define OW1 4 +#define OW2 5 +#define OW4 6 +#define ORW1 7 +#define ORW2 8 +#define ORW4 9 + +#define OFW 10 +#define OFR 11 +#define OFRW 12 + +#define INST_END 98 +#define FLUSH 99 + +#define OPT_IMM OIMM, +#define OPT_MEMR OMEMR, +#define OPT_MEMW OMEMW, +#define OPT_MEMRW OMEMRW, +#define OPT_R1 OR1 , +#define OPT_R2 OR2 , +#define OPT_R4 OR4 , +#define OPT_W1 OW1 , +#define OPT_W2 OW2 , +#define OPT_W4 OW4 , +#define OPT_RW1 ORW1, +#define OPT_RW2 ORW2, +#define OPT_RW4 ORW4, + +#define OPT_FW OFW , +#define OPT_FR OFR , +#define OPT_FRW OFRW , + +#define DIR_IMM +#define DIR_MEMR +#define DIR_MEMW +#define DIR_MEMRW +#define DIR_R1 +#define DIR_R2 +#define DIR_R4 +#define DIR_W1 +#define DIR_W2 +#define DIR_W4 +#define DIR_RW1 +#define DIR_RW2 +#define DIR_RW4 + +#define DIR_FR +#define DIR_FW +#define DIR_FRW + +#undef MIDFUNC +#undef MENDFUNC + +#define MIDFUNC(nargs,func,args) \ + __inline__ void do_##func args + +#define MENDFUNC(nargs,func,args) \ + void func args \ + { \ + if (reg_alloc_run) { \ + opt_op##nargs##args; \ + } else { \ + do_##func direct##nargs##args; \ + } \ + } + +#undef COMPCALL +#define COMPCALL(func) do_##func + +int opt_index=0; + +static __inline__ void store_any(uae_u8 type, uae_u32 val) +{ + ra[opt_index].type=type; + ra[opt_index].reg=val; + opt_index++; + if (opt_index>=MAXREGOPT) { + printf("Oops! opt_index overflow....\n"); + abort(); + } +} + +static __inline__ void store_arg(uae_u8 type, uae_u32 val) +{ + if (typeORW4) + return; + store_any(type,val); +} + +static __inline__ void opt_store_op0(void) +{ + /* zilch */ +} + +static __inline__ void opt_store_op1(uae_u8 t1, uae_u32 a1) +{ + store_arg(t1,a1); + opt_store_op0(); +} + +static __inline__ void opt_store_op2(uae_u8 t1, uae_u32 a1, + uae_u8 t2, uae_u32 a2) +{ + store_arg(t2,a2); + opt_store_op1(t1,a1); +} + +static __inline__ void opt_store_op3(uae_u8 t1, uae_u32 a1, + uae_u8 t2, uae_u32 a2, + uae_u8 t3, uae_u32 a3) +{ + store_arg(t3,a3); + opt_store_op2(t1,a1,t2,a2); +} + +static __inline__ void opt_store_op4(uae_u8 t1, uae_u32 a1, + uae_u8 t2, uae_u32 a2, + uae_u8 t3, uae_u32 a3, + uae_u8 t4, uae_u32 a4) +{ + store_arg(t4,a4); + opt_store_op3(t1,a1,t2,a2,t3,a3); +} + +static __inline__ void opt_store_op5(uae_u8 t1, uae_u32 a1, + uae_u8 t2, uae_u32 a2, + uae_u8 t3, uae_u32 a3, + uae_u8 t4, uae_u32 a4, + uae_u8 t5, uae_u32 a5) +{ + store_arg(t5,a5); + opt_store_op4(t1,a1,t2,a2,t3,a3,t4,a4); +} + +static void opt_assert_empty(int line) +{ +} + +void empty_optimizer(void) +{ +} + +#else +static __inline__ void opt_emit_all(void) {} +static __inline__ void opt_assert_empty(int line) {} +void empty_optimizer(void) {} +#define USE_REGALLOC 0 +#endif diff --git a/compemu_optimizer_x86.c b/compemu_optimizer_x86.c new file mode 100755 index 00000000..52a1b91e --- /dev/null +++ b/compemu_optimizer_x86.c @@ -0,0 +1,421 @@ +#if USE_LOW_OPTIMIZER +/* Welcome to the magical world of cpp ;-) */ + +/* This was broken by the advent of FPU emulation. It also didn't + provide any useful speedup while it worked. *Sigh* Someone fix my + software, please ;-) */ + +#define MAXLOPTINST 100 + +#define LDECISION currprefs.comp_lowopt + +#define lopt_op0(dummy) lopt_store_op0( +#define lopt_op1(a1) lopt_store_op1(LOPT_##a1, +#define lopt_op2(a1,a2) lopt_store_op2(LOPT_##a1,LOPT_##a2, +#define lopt_op3(a1,a2,a3) lopt_store_op3(LOPT_##a1,LOPT_##a2,LOPT_##a3, +#define lopt_op4(a1,a2,a3,a4) lopt_store_op4(LOPT_##a1,LOPT_##a2,LOPT_##a3,LOPT_##a4, +#define lopt_op5(a1,a2,a3,a4,a5) lopt_store_op5(LOPT_##a1,LOPT_##a2,LOPT_##a3,LOPT_##a4,LOPT_##a5, + +#define ldirect0(dummy) () +#define ldirect1(a1) (LDIR_##a1) +#define ldirect2(a1,a2) (LDIR_##a1,LDIR_##a2) +#define ldirect3(a1,a2,a3) (LDIR_##a1,LDIR_##a2,LDIR_##a3) +#define ldirect4(a1,a2,a3,a4) (LDIR_##a1,LDIR_##a2,LDIR_##a3,LDIR_##a4) +#define ldirect5(a1,a2,a3,a4,a5) (LDIR_##a1,LDIR_##a2,LDIR_##a3,LDIR_##a4,LDIR_##a5) + +#define NONE 0 +#define READ 1 +#define WRITE 2 +#define RMW (READ|WRITE) + +#define SIZE1 4 +#define SIZE2 8 +#define SIZE4 12 +#define FLOAT 16 +#define SIZEMASK 12 + +#define LIMM NONE +#define LR1 (READ | SIZE1) +#define LR2 (READ | SIZE2) +#define LR4 (READ | SIZE4) +#define LW1 (WRITE | SIZE1) +#define LW2 (WRITE | SIZE2) +#define LW4 (WRITE | SIZE4) +#define LRW1 (RMW | SIZE1) +#define LRW2 (RMW | SIZE2) +#define LRW4 (RMW | SIZE4) +#define LFW (READ | FLOAT) +#define LFR (WRITE | FLOAT) +#define LFRW (RMW | FLOAT) +#define LMEMR NONE +#define LMEMW NONE +#define LMEMRW NONE + +#define LOPT_IMM LIMM, +#define LOPT_R1 LR1 , +#define LOPT_R2 LR2 , +#define LOPT_R4 LR4 , +#define LOPT_W1 LW1 , +#define LOPT_W2 LW2 , +#define LOPT_W4 LW4 , +#define LOPT_RW1 LRW1, +#define LOPT_RW2 LRW2, +#define LOPT_RW4 LRW4, +#define LOPT_FR LFR, +#define LOPT_FW LFW, +#define LOPT_FRW LFRW, +#define LOPT_MEMR LMEMR, +#define LOPT_MEMW LMEMW, +#define LOPT_MEMRW LMEMRW, + +#define LDIR_IMM +#define LDIR_R1 +#define LDIR_R2 +#define LDIR_R4 +#define LDIR_W1 +#define LDIR_W2 +#define LDIR_W4 +#define LDIR_RW1 +#define LDIR_RW2 +#define LDIR_RW4 +#define LDIR_FW +#define LDIR_FR +#define LDIR_FRW +#define LDIR_MEMR +#define LDIR_MEMW +#define LDIR_MEMRW + + +#undef LOWFUNC +#undef LENDFUNC + +#define LOWFUNC(flags,mem,nargs,func,args) \ + static __inline__ void do_##func args + +#define LENDFUNC(flags,mem,nargs,func,args) \ + static __inline__ void func args \ + { \ + if (LDECISION) { \ + lopt_op##nargs##args do_##func, mem, flags); \ + } else { \ + do_##func ldirect##nargs##args; \ + } \ + } + +typedef struct lopt_inst_rec { + void* func; + uae_u32 args[5]; + uae_u8 argtype[5]; + uae_s8 nargs; + uae_u8 mem; + uae_u8 flags; +} lopt_inst; + + + +static lopt_inst linst[MAXLOPTINST]; +static int lopt_index=0; + +static __inline__ int argsize(int type) +{ + return type&SIZEMASK; +} + +static __inline__ int reads_mem(int i) { + return linst[i].mem & READ; +} + + +static __inline__ int access_reg(int i, int r, int mode) +{ + int k; + for (k=0;k=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;inargs) { + case 0: ((lopt_handler0*)x->func)(); break; + case 1: ((lopt_handler1*)x->func)(x->args[0]); break; + case 2: ((lopt_handler2*)x->func)(x->args[0],x->args[1]); break; + case 3: ((lopt_handler3*)x->func)(x->args[0],x->args[1],x->args[2]); break; + case 4: ((lopt_handler4*)x->func)(x->args[0],x->args[1],x->args[2], + x->args[3]); break; + case 5: ((lopt_handler5*)x->func)(x->args[0],x->args[1],x->args[2], + x->args[3],x->args[4]); break; + default: abort(); + } + } + lopt_index=0; + inemit=0; +} + +static __inline__ void low_advance(void) +{ + lopt_index++; + if (lopt_index==MAXLOPTINST) + lopt_emit_all(); +} + +static __inline__ void lopt_store_op0(void* lfuncptr, uae_u32 lmem, + uae_u32 lflags) +{ + linst[lopt_index].func=lfuncptr; + linst[lopt_index].mem=lmem; + linst[lopt_index].flags=lflags; + linst[lopt_index].nargs=0; + low_advance(); +} + +static __inline__ void lopt_store_op1(uae_u8 t1, uae_u32 a1, + void* lfuncptr, uae_u32 lmem, + uae_u32 lflags) +{ + linst[lopt_index].func=lfuncptr; + linst[lopt_index].mem=lmem; + linst[lopt_index].flags=lflags; + linst[lopt_index].nargs=1; + linst[lopt_index].argtype[0]=t1; + linst[lopt_index].args[0]=a1; + low_advance(); +} + +static __inline__ void lopt_store_op2(uae_u8 t1, uae_u32 a1, + uae_u8 t2, uae_u32 a2, + void* lfuncptr, uae_u32 lmem, + uae_u32 lflags) +{ + linst[lopt_index].func=lfuncptr; + linst[lopt_index].mem=lmem; + linst[lopt_index].flags=lflags; + linst[lopt_index].nargs=2; + linst[lopt_index].argtype[0]=t1; + linst[lopt_index].args[0]=a1; + linst[lopt_index].argtype[1]=t2; + linst[lopt_index].args[1]=a2; + low_advance(); +} + +static __inline__ void lopt_store_op3(uae_u8 t1, uae_u32 a1, + uae_u8 t2, uae_u32 a2, + uae_u8 t3, uae_u32 a3, + void* lfuncptr, uae_u32 lmem, + uae_u32 lflags) +{ + linst[lopt_index].func=lfuncptr; + linst[lopt_index].mem=lmem; + linst[lopt_index].flags=lflags; + linst[lopt_index].nargs=3; + linst[lopt_index].argtype[0]=t1; + linst[lopt_index].args[0]=a1; + linst[lopt_index].argtype[1]=t2; + linst[lopt_index].args[1]=a2; + linst[lopt_index].argtype[2]=t3; + linst[lopt_index].args[2]=a3; + low_advance(); +} + +static __inline__ void lopt_store_op4(uae_u8 t1, uae_u32 a1, + uae_u8 t2, uae_u32 a2, + uae_u8 t3, uae_u32 a3, + uae_u8 t4, uae_u32 a4, + void* lfuncptr, uae_u32 lmem, + uae_u32 lflags) +{ + linst[lopt_index].func=lfuncptr; + linst[lopt_index].mem=lmem; + linst[lopt_index].flags=lflags; + linst[lopt_index].nargs=4; + linst[lopt_index].argtype[0]=t1; + linst[lopt_index].args[0]=a1; + linst[lopt_index].argtype[1]=t2; + linst[lopt_index].args[1]=a2; + linst[lopt_index].argtype[2]=t3; + linst[lopt_index].args[2]=a3; + linst[lopt_index].argtype[3]=t4; + linst[lopt_index].args[3]=a4; + low_advance(); +} + +static __inline__ void lopt_store_op5(uae_u8 t1, uae_u32 a1, + uae_u8 t2, uae_u32 a2, + uae_u8 t3, uae_u32 a3, + uae_u8 t4, uae_u32 a4, + uae_u8 t5, uae_u32 a5, + void* lfuncptr, uae_u32 lmem, + uae_u32 lflags) +{ + linst[lopt_index].func=lfuncptr; + linst[lopt_index].mem=lmem; + linst[lopt_index].flags=lflags; + linst[lopt_index].nargs=5; + linst[lopt_index].argtype[0]=t1; + linst[lopt_index].args[0]=a1; + linst[lopt_index].argtype[1]=t2; + linst[lopt_index].args[1]=a2; + linst[lopt_index].argtype[2]=t3; + linst[lopt_index].args[2]=a3; + linst[lopt_index].argtype[3]=t4; + linst[lopt_index].args[3]=a4; + linst[lopt_index].argtype[4]=t5; + linst[lopt_index].args[4]=a5; + low_advance(); +} + +static __inline__ void empty_low_optimizer(void) +{ + lopt_emit_all(); +} + +#else +static __inline__ void lopt_emit_all(void) {} +static __inline__ void empty_low_optimizer(void) {} +#endif diff --git a/compemu_raw_x86.c b/compemu_raw_x86.c new file mode 100755 index 00000000..3670a3cb --- /dev/null +++ b/compemu_raw_x86.c @@ -0,0 +1,3179 @@ +/* This should eventually end up in machdep/, but for now, x86 is the + only target, and it's easier this way... */ + +/************************************************************************* + * Some basic information about the the target CPU * + *************************************************************************/ + +#define EAX 0 +#define ECX 1 +#define EDX 2 +#define EBX 3 + +/* The register in which subroutines return an integer return value */ +#define REG_RESULT 0 + +/* The registers subroutines take their first and second argument in */ +#define REG_PAR1 0 +#define REG_PAR2 2 + +/* Three registers that are not used for any of the above */ +#define REG_NOPAR1 6 +#define REG_NOPAR2 5 +#define REG_NOPAR3 3 + +#define REG_PC_PRE 0 /* The register we use for preloading regs.pc_p */ +#define REG_PC_TMP 1 /* Another register that is not the above */ + +#define SHIFTCOUNT_NREG 1 /* Register that can be used for shiftcount. + -1 if any reg will do */ +#define MUL_NREG1 0 /* %eax will hold the low 32 bits after a 32x32 mul */ +#define MUL_NREG2 2 /* %edx will hold the high 32 bits */ + +uae_s8 always_used[]={4,-1}; +uae_s8 can_byte[]={0,1,2,3,-1}; +uae_s8 can_word[]={0,1,2,3,5,6,7,-1}; + +uae_u8 call_saved[]={0,0,0,0,1,0,0,0}; + +/* This *should* be the same as call_saved. But: + - We might not really know which registers are saved, and which aren't, + so we need to preserve some, but don't want to rely on everyone else + also saving those registers + - Special registers (such like the stack pointer) should not be "preserved" + by pushing, even though they are "saved" across function calls +*/ +uae_u8 need_to_preserve[]={1,1,1,1,0,1,1,1}; + +/* Whether classes of instructions do or don't clobber the native flags */ +#define CLOBBER_MOV +#define CLOBBER_LEA +#define CLOBBER_CMOV +#define CLOBBER_POP +#define CLOBBER_PUSH +#define CLOBBER_SUB clobber_flags() +#define CLOBBER_SBB clobber_flags() +#define CLOBBER_CMP clobber_flags() +#define CLOBBER_ADD clobber_flags() +#define CLOBBER_ADC clobber_flags() +#define CLOBBER_AND clobber_flags() +#define CLOBBER_OR clobber_flags() +#define CLOBBER_XOR clobber_flags() + +#define CLOBBER_ROL clobber_flags() +#define CLOBBER_ROR clobber_flags() +#define CLOBBER_SHLL clobber_flags() +#define CLOBBER_SHRL clobber_flags() +#define CLOBBER_SHRA clobber_flags() +#define CLOBBER_TEST clobber_flags() +#define CLOBBER_CL16 +#define CLOBBER_CL8 +#define CLOBBER_SE16 +#define CLOBBER_SE8 +#define CLOBBER_ZE16 +#define CLOBBER_ZE8 +#define CLOBBER_SW16 clobber_flags() +#define CLOBBER_SW32 +#define CLOBBER_SETCC +#define CLOBBER_MUL clobber_flags() +#define CLOBBER_BT clobber_flags() +#define CLOBBER_BSF clobber_flags() + +/************************************************************************* + * Actual encoding of the instructions on the target CPU * + *************************************************************************/ + +static int have_cmov=0; /* We need to generate different code if + we don't have cmov */ + +#include "compemu_optimizer_x86.c" + +static uae_u16 swap16(uae_u16 x) +{ + return ((x&0xff00)>>8)|((x&0x00ff)<<8); +} + +static uae_u32 swap32(uae_u32 x) +{ + return ((x&0xff00)<<8)|((x&0x00ff)<<24)|((x&0xff0000)>>8)|((x&0xff000000)>>24); +} + +static __inline__ int isbyte(uae_s32 x) +{ + return (x>=-128 && x<=127); +} + +LOWFUNC(NONE,WRITE,1,raw_push_l_r,(R4 r)) +{ + emit_byte(0x50+r); +} +LENDFUNC(NONE,WRITE,1,raw_push_l_r,(R4 r)) + +LOWFUNC(NONE,READ,1,raw_pop_l_r,(R4 r)) +{ + emit_byte(0x58+r); +} +LENDFUNC(NONE,READ,1,raw_pop_l_r,(R4 r)) + +LOWFUNC(WRITE,NONE,2,raw_bt_l_ri,(R4 r, IMM i)) +{ + emit_byte(0x0f); + emit_byte(0xba); + emit_byte(0xe0+r); + emit_byte(i); +} +LENDFUNC(WRITE,NONE,2,raw_bt_l_ri,(R4 r, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_bt_l_rr,(R4 r, R4 b)) +{ + emit_byte(0x0f); + emit_byte(0xa3); + emit_byte(0xc0+8*b+r); +} +LENDFUNC(WRITE,NONE,2,raw_bt_l_rr,(R4 r, R4 b)) + +LOWFUNC(WRITE,NONE,2,raw_btc_l_ri,(RW4 r, IMM i)) +{ + emit_byte(0x0f); + emit_byte(0xba); + emit_byte(0xf8+r); + emit_byte(i); +} +LENDFUNC(WRITE,NONE,2,raw_btc_l_ri,(RW4 r, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_btc_l_rr,(RW4 r, R4 b)) +{ + emit_byte(0x0f); + emit_byte(0xbb); + emit_byte(0xc0+8*b+r); +} +LENDFUNC(WRITE,NONE,2,raw_btc_l_rr,(RW4 r, R4 b)) + + +LOWFUNC(WRITE,NONE,2,raw_btr_l_ri,(RW4 r, IMM i)) +{ + emit_byte(0x0f); + emit_byte(0xba); + emit_byte(0xf0+r); + emit_byte(i); +} +LENDFUNC(WRITE,NONE,2,raw_btr_l_ri,(RW4 r, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_btr_l_rr,(RW4 r, R4 b)) +{ + emit_byte(0x0f); + emit_byte(0xb3); + emit_byte(0xc0+8*b+r); +} +LENDFUNC(WRITE,NONE,2,raw_btr_l_rr,(RW4 r, R4 b)) + +LOWFUNC(WRITE,NONE,2,raw_bts_l_ri,(RW4 r, IMM i)) +{ + emit_byte(0x0f); + emit_byte(0xba); + emit_byte(0xe8+r); + emit_byte(i); +} +LENDFUNC(WRITE,NONE,2,raw_bts_l_ri,(RW4 r, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_bts_l_rr,(RW4 r, R4 b)) +{ + emit_byte(0x0f); + emit_byte(0xab); + emit_byte(0xc0+8*b+r); +} +LENDFUNC(WRITE,NONE,2,raw_bts_l_rr,(RW4 r, R4 b)) + +LOWFUNC(WRITE,NONE,2,raw_sub_w_ri,(RW2 d, IMM i)) +{ + emit_byte(0x66); + if (isbyte(i)) { + emit_byte(0x83); + emit_byte(0xe8+d); + emit_byte(i); + } + else { + emit_byte(0x81); + emit_byte(0xe8+d); + emit_word(i); + } +} +LENDFUNC(WRITE,NONE,2,raw_sub_w_ri,(RW2 d, IMM i)) + + +LOWFUNC(NONE,WRITE,2,raw_mov_l_mi,(MEMW d, IMM s)) +{ + emit_byte(0xc7); + emit_byte(0x05); + emit_long(d); + emit_long(s); +} +LENDFUNC(NONE,WRITE,2,raw_mov_l_mi,(MEMW d, IMM s)) + +LOWFUNC(NONE,WRITE,2,raw_mov_w_mi,(MEMW d, IMM s)) +{ + emit_byte(0x66); + emit_byte(0xc7); + emit_byte(0x05); + emit_long(d); + emit_word(s); +} +LENDFUNC(NONE,WRITE,2,raw_mov_w_mi,(MEMW d, IMM s)) + +LOWFUNC(NONE,WRITE,2,raw_mov_b_mi,(MEMW d, IMM s)) +{ + emit_byte(0xc6); + emit_byte(0x05); + emit_long(d); + emit_byte(s); +} +LENDFUNC(NONE,WRITE,2,raw_mov_b_mi,(MEMW d, IMM s)) + +LOWFUNC(WRITE,RMW,2,raw_rol_b_mi,(MEMRW d, IMM i)) +{ + emit_byte(0xc0); + emit_byte(0x05); + emit_long(d); + emit_byte(i); +} +LENDFUNC(WRITE,RMW,2,raw_rol_b_mi,(MEMRW d, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_rol_b_ri,(RW1 r, IMM i)) +{ + emit_byte(0xc0); + emit_byte(0xc0+r); + emit_byte(i); +} +LENDFUNC(WRITE,NONE,2,raw_rol_b_ri,(RW1 r, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_rol_w_ri,(RW2 r, IMM i)) +{ + emit_byte(0x66); + emit_byte(0xc1); + emit_byte(0xc0+r); + emit_byte(i); +} +LENDFUNC(WRITE,NONE,2,raw_rol_w_ri,(RW2 r, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_rol_l_ri,(RW4 r, IMM i)) +{ + emit_byte(0xc1); + emit_byte(0xc0+r); + emit_byte(i); +} +LENDFUNC(WRITE,NONE,2,raw_rol_l_ri,(RW4 r, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_rol_l_rr,(RW4 d, R1 r)) +{ + emit_byte(0xd3); + emit_byte(0xc0+d); +} +LENDFUNC(WRITE,NONE,2,raw_rol_l_rr,(RW4 d, R1 r)) + +LOWFUNC(WRITE,NONE,2,raw_rol_w_rr,(RW2 d, R1 r)) +{ + emit_byte(0x66); + emit_byte(0xd3); + emit_byte(0xc0+d); +} +LENDFUNC(WRITE,NONE,2,raw_rol_w_rr,(RW2 d, R1 r)) + +LOWFUNC(WRITE,NONE,2,raw_rol_b_rr,(RW1 d, R1 r)) +{ + emit_byte(0xd2); + emit_byte(0xc0+d); +} +LENDFUNC(WRITE,NONE,2,raw_rol_b_rr,(RW1 d, R1 r)) + +LOWFUNC(WRITE,NONE,2,raw_shll_l_rr,(RW4 d, R1 r)) +{ + emit_byte(0xd3); + emit_byte(0xe0+d); +} +LENDFUNC(WRITE,NONE,2,raw_shll_l_rr,(RW4 d, R1 r)) + +LOWFUNC(WRITE,NONE,2,raw_shll_w_rr,(RW2 d, R1 r)) +{ + emit_byte(0x66); + emit_byte(0xd3); + emit_byte(0xe0+d); +} +LENDFUNC(WRITE,NONE,2,raw_shll_w_rr,(RW2 d, R1 r)) + +LOWFUNC(WRITE,NONE,2,raw_shll_b_rr,(RW1 d, R1 r)) +{ + emit_byte(0xd2); + emit_byte(0xe0+d); +} +LENDFUNC(WRITE,NONE,2,raw_shll_b_rr,(RW1 d, R1 r)) + +LOWFUNC(WRITE,NONE,2,raw_ror_b_ri,(RW1 r, IMM i)) +{ + emit_byte(0xc0); + emit_byte(0xc8+r); + emit_byte(i); +} +LENDFUNC(WRITE,NONE,2,raw_ror_b_ri,(RW1 r, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_ror_w_ri,(RW2 r, IMM i)) +{ + emit_byte(0x66); + emit_byte(0xc1); + emit_byte(0xc8+r); + emit_byte(i); +} +LENDFUNC(WRITE,NONE,2,raw_ror_w_ri,(RW2 r, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_ror_l_ri,(RW4 r, IMM i)) +{ + emit_byte(0xc1); + emit_byte(0xc8+r); + emit_byte(i); +} +LENDFUNC(WRITE,NONE,2,raw_ror_l_ri,(RW4 r, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_ror_l_rr,(RW4 d, R1 r)) +{ + emit_byte(0xd3); + emit_byte(0xc8+d); +} +LENDFUNC(WRITE,NONE,2,raw_ror_l_rr,(RW4 d, R1 r)) + +LOWFUNC(WRITE,NONE,2,raw_ror_w_rr,(RW2 d, R1 r)) +{ + emit_byte(0x66); + emit_byte(0xd3); + emit_byte(0xc8+d); +} +LENDFUNC(WRITE,NONE,2,raw_ror_w_rr,(RW2 d, R1 r)) + +LOWFUNC(WRITE,NONE,2,raw_ror_b_rr,(RW1 d, R1 r)) +{ + emit_byte(0xd2); + emit_byte(0xc8+d); +} +LENDFUNC(WRITE,NONE,2,raw_ror_b_rr,(RW1 d, R1 r)) + +LOWFUNC(WRITE,NONE,2,raw_shrl_l_rr,(RW4 d, R1 r)) +{ + emit_byte(0xd3); + emit_byte(0xe8+d); +} +LENDFUNC(WRITE,NONE,2,raw_shrl_l_rr,(RW4 d, R1 r)) + +LOWFUNC(WRITE,NONE,2,raw_shrl_w_rr,(RW2 d, R1 r)) +{ + emit_byte(0x66); + emit_byte(0xd3); + emit_byte(0xe8+d); +} +LENDFUNC(WRITE,NONE,2,raw_shrl_w_rr,(RW2 d, R1 r)) + +LOWFUNC(WRITE,NONE,2,raw_shrl_b_rr,(RW1 d, R1 r)) +{ + emit_byte(0xd2); + emit_byte(0xe8+d); +} +LENDFUNC(WRITE,NONE,2,raw_shrl_b_rr,(RW1 d, R1 r)) + +LOWFUNC(WRITE,NONE,2,raw_shra_l_rr,(RW4 d, R1 r)) +{ + emit_byte(0xd3); + emit_byte(0xf8+d); +} +LENDFUNC(WRITE,NONE,2,raw_shra_l_rr,(RW4 d, R1 r)) + +LOWFUNC(WRITE,NONE,2,raw_shra_w_rr,(RW2 d, R1 r)) +{ + emit_byte(0x66); + emit_byte(0xd3); + emit_byte(0xf8+d); +} +LENDFUNC(WRITE,NONE,2,raw_shra_w_rr,(RW2 d, R1 r)) + +LOWFUNC(WRITE,NONE,2,raw_shra_b_rr,(RW1 d, R1 r)) +{ + emit_byte(0xd2); + emit_byte(0xf8+d); +} +LENDFUNC(WRITE,NONE,2,raw_shra_b_rr,(RW1 d, R1 r)) + +LOWFUNC(WRITE,NONE,2,raw_shll_l_ri,(RW4 r, IMM i)) +{ + emit_byte(0xc1); + emit_byte(0xe0+r); + emit_byte(i); +} +LENDFUNC(WRITE,NONE,2,raw_shll_l_ri,(RW4 r, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_shll_w_ri,(RW2 r, IMM i)) +{ + emit_byte(0x66); + emit_byte(0xc1); + emit_byte(0xe0+r); + emit_byte(i); +} +LENDFUNC(WRITE,NONE,2,raw_shll_w_ri,(RW2 r, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_shll_b_ri,(RW1 r, IMM i)) +{ + emit_byte(0xc0); + emit_byte(0xe0+r); + emit_byte(i); +} +LENDFUNC(WRITE,NONE,2,raw_shll_b_ri,(RW1 r, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_shrl_l_ri,(RW4 r, IMM i)) +{ + emit_byte(0xc1); + emit_byte(0xe8+r); + emit_byte(i); +} +LENDFUNC(WRITE,NONE,2,raw_shrl_l_ri,(RW4 r, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_shrl_w_ri,(RW2 r, IMM i)) +{ + emit_byte(0x66); + emit_byte(0xc1); + emit_byte(0xe8+r); + emit_byte(i); +} +LENDFUNC(WRITE,NONE,2,raw_shrl_w_ri,(RW2 r, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_shrl_b_ri,(RW1 r, IMM i)) +{ + emit_byte(0xc0); + emit_byte(0xe8+r); + emit_byte(i); +} +LENDFUNC(WRITE,NONE,2,raw_shrl_b_ri,(RW1 r, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_shra_l_ri,(RW4 r, IMM i)) +{ + emit_byte(0xc1); + emit_byte(0xf8+r); + emit_byte(i); +} +LENDFUNC(WRITE,NONE,2,raw_shra_l_ri,(RW4 r, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_shra_w_ri,(RW2 r, IMM i)) +{ + emit_byte(0x66); + emit_byte(0xc1); + emit_byte(0xf8+r); + emit_byte(i); +} +LENDFUNC(WRITE,NONE,2,raw_shra_w_ri,(RW2 r, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_shra_b_ri,(RW1 r, IMM i)) +{ + emit_byte(0xc0); + emit_byte(0xf8+r); + emit_byte(i); +} +LENDFUNC(WRITE,NONE,2,raw_shra_b_ri,(RW1 r, IMM i)) + +LOWFUNC(WRITE,NONE,1,raw_sahf,(R2 dummy_ah)) +{ + emit_byte(0x9e); +} +LENDFUNC(WRITE,NONE,1,raw_sahf,(R2 dummy_ah)) + +LOWFUNC(NONE,NONE,1,raw_cpuid,(R4 dummy_eax)) +{ + emit_byte(0x0f); + emit_byte(0xa2); +} +LENDFUNC(NONE,NONE,1,raw_cpuid,(R4 dummy_eax)) + +LOWFUNC(READ,NONE,1,raw_lahf,(W2 dummy_ah)) +{ + emit_byte(0x9f); +} +LENDFUNC(READ,NONE,1,raw_lahf,(W2 dummy_ah)) + +LOWFUNC(READ,NONE,2,raw_setcc,(W1 d, IMM cc)) +{ + emit_byte(0x0f); + emit_byte(0x90+cc); + emit_byte(0xc0+d); +} +LENDFUNC(READ,NONE,2,raw_setcc,(W1 d, IMM cc)) + +LOWFUNC(READ,WRITE,2,raw_setcc_m,(MEMW d, IMM cc)) +{ + emit_byte(0x0f); + emit_byte(0x90+cc); + emit_byte(0x05); + emit_long(d); +} +LENDFUNC(READ,WRITE,2,raw_setcc_m,(MEMW d, IMM cc)) + +LOWFUNC(READ,NONE,3,raw_cmov_l_rr,(RW4 d, R4 s, IMM cc)) +{ + if (have_cmov) { + emit_byte(0x0f); + emit_byte(0x40+cc); + emit_byte(0xc0+8*d+s); + } + else { /* replacement using branch and mov */ + int uncc=(cc^1); + emit_byte(0x70+uncc); + emit_byte(2); /* skip next 2 bytes if not cc=true */ + emit_byte(0x89); + emit_byte(0xc0+8*s+d); + } +} +LENDFUNC(READ,NONE,3,raw_cmov_l_rr,(RW4 d, R4 s, IMM cc)) + +LOWFUNC(WRITE,NONE,2,raw_bsf_l_rr,(W4 d, R4 s)) +{ + emit_byte(0x0f); + emit_byte(0xbc); + emit_byte(0xc0+8*d+s); +} +LENDFUNC(WRITE,NONE,2,raw_bsf_l_rr,(W4 d, R4 s)) + +LOWFUNC(NONE,NONE,2,raw_sign_extend_16_rr,(W4 d, R2 s)) +{ + emit_byte(0x0f); + emit_byte(0xbf); + emit_byte(0xc0+8*d+s); +} +LENDFUNC(NONE,NONE,2,raw_sign_extend_16_rr,(W4 d, R2 s)) + +LOWFUNC(NONE,NONE,2,raw_sign_extend_8_rr,(W4 d, R1 s)) +{ + emit_byte(0x0f); + emit_byte(0xbe); + emit_byte(0xc0+8*d+s); +} +LENDFUNC(NONE,NONE,2,raw_sign_extend_8_rr,(W4 d, R1 s)) + +LOWFUNC(NONE,NONE,2,raw_zero_extend_16_rr,(W4 d, R2 s)) +{ + emit_byte(0x0f); + emit_byte(0xb7); + emit_byte(0xc0+8*d+s); +} +LENDFUNC(NONE,NONE,2,raw_zero_extend_16_rr,(W4 d, R2 s)) + +LOWFUNC(NONE,NONE,2,raw_zero_extend_8_rr,(W4 d, R1 s)) +{ + emit_byte(0x0f); + emit_byte(0xb6); + emit_byte(0xc0+8*d+s); +} +LENDFUNC(NONE,NONE,2,raw_zero_extend_8_rr,(W4 d, R1 s)) + +LOWFUNC(NONE,NONE,2,raw_imul_32_32,(RW4 d, R4 s)) +{ + emit_byte(0x0f); + emit_byte(0xaf); + emit_byte(0xc0+8*d+s); +} +LENDFUNC(NONE,NONE,2,raw_imul_32_32,(RW4 d, R4 s)) + +LOWFUNC(NONE,NONE,2,raw_imul_64_32,(RW4 d, RW4 s)) +{ + if (d!=MUL_NREG1 || s!=MUL_NREG2) + abort(); + emit_byte(0xf7); + emit_byte(0xea); +} +LENDFUNC(NONE,NONE,2,raw_imul_64_32,(RW4 d, RW4 s)) + +LOWFUNC(NONE,NONE,2,raw_mul_64_32,(RW4 d, RW4 s)) +{ + if (d!=MUL_NREG1 || s!=MUL_NREG2) { + printf("Bad register in MUL: d=%d, s=%d\n",d,s); + abort(); + } + emit_byte(0xf7); + emit_byte(0xe2); +} +LENDFUNC(NONE,NONE,2,raw_mul_64_32,(RW4 d, RW4 s)) + +LOWFUNC(NONE,NONE,2,raw_mul_32_32,(RW4 d, R4 s)) +{ + abort(); /* %^$&%^$%#^ x86! */ + emit_byte(0x0f); + emit_byte(0xaf); + emit_byte(0xc0+8*d+s); +} +LENDFUNC(NONE,NONE,2,raw_mul_32_32,(RW4 d, R4 s)) + +LOWFUNC(NONE,NONE,2,raw_mov_b_rr,(W1 d, R1 s)) +{ + emit_byte(0x88); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(NONE,NONE,2,raw_mov_b_rr,(W1 d, R1 s)) + +LOWFUNC(NONE,NONE,2,raw_mov_w_rr,(W2 d, R2 s)) +{ + emit_byte(0x66); + emit_byte(0x89); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(NONE,NONE,2,raw_mov_w_rr,(W2 d, R2 s)) + +LOWFUNC(NONE,READ,4,raw_mov_l_rrm_indexed,(W4 d,R4 baser, R4 index, IMM factor)) +{ + int isebp=(baser==5)?0x40:0; + int fi; + + switch(factor) { + case 1: fi=0; break; + case 2: fi=1; break; + case 4: fi=2; break; + case 8: fi=3; break; + default: abort(); + } + + + emit_byte(0x8b); + emit_byte(0x04+8*d+isebp); + emit_byte(baser+8*index+0x40*fi); + if (isebp) + emit_byte(0x00); +} +LENDFUNC(NONE,READ,4,raw_mov_l_rrm_indexed,(W4 d,R4 baser, R4 index, IMM factor)) + +LOWFUNC(NONE,READ,4,raw_mov_w_rrm_indexed,(W2 d, R4 baser, R4 index, IMM factor)) +{ + int fi; + int isebp; + + switch(factor) { + case 1: fi=0; break; + case 2: fi=1; break; + case 4: fi=2; break; + case 8: fi=3; break; + default: abort(); + } + isebp=(baser==5)?0x40:0; + + emit_byte(0x66); + emit_byte(0x8b); + emit_byte(0x04+8*d+isebp); + emit_byte(baser+8*index+0x40*fi); + if (isebp) + emit_byte(0x00); +} +LENDFUNC(NONE,READ,4,raw_mov_w_rrm_indexed,(W2 d, R4 baser, R4 index, IMM factor)) + +LOWFUNC(NONE,READ,4,raw_mov_b_rrm_indexed,(W1 d, R4 baser, R4 index, IMM factor)) +{ + int fi; + int isebp; + + switch(factor) { + case 1: fi=0; break; + case 2: fi=1; break; + case 4: fi=2; break; + case 8: fi=3; break; + default: abort(); + } + isebp=(baser==5)?0x40:0; + + emit_byte(0x8a); + emit_byte(0x04+8*d+isebp); + emit_byte(baser+8*index+0x40*fi); + if (isebp) + emit_byte(0x00); +} +LENDFUNC(NONE,READ,4,raw_mov_b_rrm_indexed,(W1 d, R4 baser, R4 index, IMM factor)) + +LOWFUNC(NONE,WRITE,4,raw_mov_l_mrr_indexed,(R4 baser, R4 index, IMM factor, R4 s)) +{ + int fi; + int isebp; + + switch(factor) { + case 1: fi=0; break; + case 2: fi=1; break; + case 4: fi=2; break; + case 8: fi=3; break; + default: abort(); + } + + + isebp=(baser==5)?0x40:0; + + emit_byte(0x89); + emit_byte(0x04+8*s+isebp); + emit_byte(baser+8*index+0x40*fi); + if (isebp) + emit_byte(0x00); +} +LENDFUNC(NONE,WRITE,4,raw_mov_l_mrr_indexed,(R4 baser, R4 index, IMM factor, R4 s)) + +LOWFUNC(NONE,WRITE,4,raw_mov_w_mrr_indexed,(R4 baser, R4 index, IMM factor, R2 s)) +{ + int fi; + int isebp; + + switch(factor) { + case 1: fi=0; break; + case 2: fi=1; break; + case 4: fi=2; break; + case 8: fi=3; break; + default: abort(); + } + isebp=(baser==5)?0x40:0; + + emit_byte(0x66); + emit_byte(0x89); + emit_byte(0x04+8*s+isebp); + emit_byte(baser+8*index+0x40*fi); + if (isebp) + emit_byte(0x00); +} +LENDFUNC(NONE,WRITE,4,raw_mov_w_mrr_indexed,(R4 baser, R4 index, IMM factor, R2 s)) + +LOWFUNC(NONE,WRITE,4,raw_mov_b_mrr_indexed,(R4 baser, R4 index, IMM factor, R1 s)) +{ + int fi; + int isebp; + + switch(factor) { + case 1: fi=0; break; + case 2: fi=1; break; + case 4: fi=2; break; + case 8: fi=3; break; + default: abort(); + } + isebp=(baser==5)?0x40:0; + + emit_byte(0x88); + emit_byte(0x04+8*s+isebp); + emit_byte(baser+8*index+0x40*fi); + if (isebp) + emit_byte(0x00); +} +LENDFUNC(NONE,WRITE,4,raw_mov_b_mrr_indexed,(R4 baser, R4 index, IMM factor, R1 s)) + +LOWFUNC(NONE,WRITE,5,raw_mov_l_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R4 s)) +{ + int fi; + + switch(factor) { + case 1: fi=0; break; + case 2: fi=1; break; + case 4: fi=2; break; + case 8: fi=3; break; + default: abort(); + } + + emit_byte(0x89); + emit_byte(0x84+8*s); + emit_byte(baser+8*index+0x40*fi); + emit_long(base); +} +LENDFUNC(NONE,WRITE,5,raw_mov_l_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R4 s)) + +LOWFUNC(NONE,WRITE,5,raw_mov_w_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R2 s)) +{ + int fi; + + switch(factor) { + case 1: fi=0; break; + case 2: fi=1; break; + case 4: fi=2; break; + case 8: fi=3; break; + default: abort(); + } + + emit_byte(0x66); + emit_byte(0x89); + emit_byte(0x84+8*s); + emit_byte(baser+8*index+0x40*fi); + emit_long(base); +} +LENDFUNC(NONE,WRITE,5,raw_mov_w_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R2 s)) + +LOWFUNC(NONE,WRITE,5,raw_mov_b_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R1 s)) +{ + int fi; + + switch(factor) { + case 1: fi=0; break; + case 2: fi=1; break; + case 4: fi=2; break; + case 8: fi=3; break; + default: abort(); + } + + emit_byte(0x88); + emit_byte(0x84+8*s); + emit_byte(baser+8*index+0x40*fi); + emit_long(base); +} +LENDFUNC(NONE,WRITE,5,raw_mov_b_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R1 s)) + +LOWFUNC(NONE,READ,5,raw_mov_l_brrm_indexed,(W4 d, IMM base, R4 baser, R4 index, IMM factor)) +{ + int fi; + + switch(factor) { + case 1: fi=0; break; + case 2: fi=1; break; + case 4: fi=2; break; + case 8: fi=3; break; + default: abort(); + } + + emit_byte(0x8b); + emit_byte(0x84+8*d); + emit_byte(baser+8*index+0x40*fi); + emit_long(base); +} +LENDFUNC(NONE,READ,5,raw_mov_l_brrm_indexed,(W4 d, IMM base, R4 baser, R4 index, IMM factor)) + +LOWFUNC(NONE,READ,5,raw_mov_w_brrm_indexed,(W2 d, IMM base, R4 baser, R4 index, IMM factor)) +{ + int fi; + + switch(factor) { + case 1: fi=0; break; + case 2: fi=1; break; + case 4: fi=2; break; + case 8: fi=3; break; + default: abort(); + } + + emit_byte(0x66); + emit_byte(0x8b); + emit_byte(0x84+8*d); + emit_byte(baser+8*index+0x40*fi); + emit_long(base); +} +LENDFUNC(NONE,READ,5,raw_mov_w_brrm_indexed,(W2 d, IMM base, R4 baser, R4 index, IMM factor)) + +LOWFUNC(NONE,READ,5,raw_mov_b_brrm_indexed,(W1 d, IMM base, R4 baser, R4 index, IMM factor)) +{ + int fi; + + switch(factor) { + case 1: fi=0; break; + case 2: fi=1; break; + case 4: fi=2; break; + case 8: fi=3; break; + default: abort(); + } + + emit_byte(0x8a); + emit_byte(0x84+8*d); + emit_byte(baser+8*index+0x40*fi); + emit_long(base); +} +LENDFUNC(NONE,READ,5,raw_mov_b_brrm_indexed,(W1 d, IMM base, R4 baser, R4 index, IMM factor)) + +LOWFUNC(NONE,READ,4,raw_mov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor)) +{ + int fi; + switch(factor) { + case 1: fi=0; break; + case 2: fi=1; break; + case 4: fi=2; break; + case 8: fi=3; break; + default: + fprintf(stderr,"Bad factor %d in mov_l_rm_indexed!\n",factor); + abort(); + } + emit_byte(0x8b); + emit_byte(0x04+8*d); + emit_byte(0x05+8*index+64*fi); + emit_long(base); +} +LENDFUNC(NONE,READ,4,raw_mov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor)) + +LOWFUNC(NONE,READ,5,raw_cmov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor, IMM cond)) +{ + int fi; + switch(factor) { + case 1: fi=0; break; + case 2: fi=1; break; + case 4: fi=2; break; + case 8: fi=3; break; + default: + fprintf(stderr,"Bad factor %d in mov_l_rm_indexed!\n",factor); + abort(); + } + if (have_cmov) { + emit_byte(0x0f); + emit_byte(0x40+cond); + emit_byte(0x04+8*d); + emit_byte(0x05+8*index+64*fi); + emit_long(base); + } + else { /* replacement using branch and mov */ + int uncc=(cond^1); + emit_byte(0x70+uncc); + emit_byte(7); /* skip next 7 bytes if not cc=true */ + emit_byte(0x8b); + emit_byte(0x04+8*d); + emit_byte(0x05+8*index+64*fi); + emit_long(base); + } +} +LENDFUNC(NONE,READ,5,raw_cmov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor, IMM cond)) + +LOWFUNC(NONE,READ,3,raw_cmov_l_rm,(W4 d, IMM mem, IMM cond)) +{ + if (have_cmov) { + emit_byte(0x0f); + emit_byte(0x40+cond); + emit_byte(0x05+8*d); + emit_long(mem); + } + else { /* replacement using branch and mov */ + int uncc=(cond^1); + emit_byte(0x70+uncc); + emit_byte(6); /* skip next 6 bytes if not cc=true */ + emit_byte(0x8b); + emit_byte(0x05+8*d); + emit_long(mem); + } +} +LENDFUNC(NONE,READ,3,raw_cmov_l_rm,(W4 d, IMM mem, IMM cond)) + +LOWFUNC(NONE,READ,3,raw_mov_l_rR,(W4 d, R4 s, IMM offset)) +{ + emit_byte(0x8b); + emit_byte(0x40+8*d+s); + emit_byte(offset); +} +LENDFUNC(NONE,READ,3,raw_mov_l_rR,(W4 d, R4 s, IMM offset)) + +LOWFUNC(NONE,READ,3,raw_mov_w_rR,(W2 d, R4 s, IMM offset)) +{ + emit_byte(0x66); + emit_byte(0x8b); + emit_byte(0x40+8*d+s); + emit_byte(offset); +} +LENDFUNC(NONE,READ,3,raw_mov_w_rR,(W2 d, R4 s, IMM offset)) + +LOWFUNC(NONE,READ,3,raw_mov_b_rR,(W1 d, R4 s, IMM offset)) +{ + emit_byte(0x8a); + emit_byte(0x40+8*d+s); + emit_byte(offset); +} +LENDFUNC(NONE,READ,3,raw_mov_b_rR,(W1 d, R4 s, IMM offset)) + +LOWFUNC(NONE,READ,3,raw_mov_l_brR,(W4 d, R4 s, IMM offset)) +{ + emit_byte(0x8b); + emit_byte(0x80+8*d+s); + emit_long(offset); +} +LENDFUNC(NONE,READ,3,raw_mov_l_brR,(W4 d, R4 s, IMM offset)) + +LOWFUNC(NONE,READ,3,raw_mov_w_brR,(W2 d, R4 s, IMM offset)) +{ + emit_byte(0x66); + emit_byte(0x8b); + emit_byte(0x80+8*d+s); + emit_long(offset); +} +LENDFUNC(NONE,READ,3,raw_mov_w_brR,(W2 d, R4 s, IMM offset)) + +LOWFUNC(NONE,READ,3,raw_mov_b_brR,(W1 d, R4 s, IMM offset)) +{ + emit_byte(0x8a); + emit_byte(0x80+8*d+s); + emit_long(offset); +} +LENDFUNC(NONE,READ,3,raw_mov_b_brR,(W1 d, R4 s, IMM offset)) + +LOWFUNC(NONE,WRITE,3,raw_mov_l_Ri,(R4 d, IMM i, IMM offset)) +{ + emit_byte(0xc7); + emit_byte(0x40+d); + emit_byte(offset); + emit_long(i); +} +LENDFUNC(NONE,WRITE,3,raw_mov_l_Ri,(R4 d, IMM i, IMM offset)) + +LOWFUNC(NONE,WRITE,3,raw_mov_w_Ri,(R4 d, IMM i, IMM offset)) +{ + emit_byte(0x66); + emit_byte(0xc7); + emit_byte(0x40+d); + emit_byte(offset); + emit_word(i); +} +LENDFUNC(NONE,WRITE,3,raw_mov_w_Ri,(R4 d, IMM i, IMM offset)) + +LOWFUNC(NONE,WRITE,3,raw_mov_b_Ri,(R4 d, IMM i, IMM offset)) +{ + emit_byte(0xc6); + emit_byte(0x40+d); + emit_byte(offset); + emit_byte(i); +} +LENDFUNC(NONE,WRITE,3,raw_mov_b_Ri,(R4 d, IMM i, IMM offset)) + +LOWFUNC(NONE,WRITE,3,raw_mov_l_Rr,(R4 d, R4 s, IMM offset)) +{ + emit_byte(0x89); + emit_byte(0x40+8*s+d); + emit_byte(offset); +} +LENDFUNC(NONE,WRITE,3,raw_mov_l_Rr,(R4 d, R4 s, IMM offset)) + +LOWFUNC(NONE,WRITE,3,raw_mov_w_Rr,(R4 d, R2 s, IMM offset)) +{ + emit_byte(0x66); + emit_byte(0x89); + emit_byte(0x40+8*s+d); + emit_byte(offset); +} +LENDFUNC(NONE,WRITE,3,raw_mov_w_Rr,(R4 d, R2 s, IMM offset)) + +LOWFUNC(NONE,WRITE,3,raw_mov_b_Rr,(R4 d, R1 s, IMM offset)) +{ + emit_byte(0x88); + emit_byte(0x40+8*s+d); + emit_byte(offset); +} +LENDFUNC(NONE,WRITE,3,raw_mov_b_Rr,(R4 d, R1 s, IMM offset)) + +LOWFUNC(NONE,NONE,3,raw_lea_l_brr,(W4 d, R4 s, IMM offset)) +{ + emit_byte(0x8d); + emit_byte(0x80+8*d+s); + emit_long(offset); +} +LENDFUNC(NONE,NONE,3,raw_lea_l_brr,(W4 d, R4 s, IMM offset)) + +LOWFUNC(NONE,NONE,5,raw_lea_l_brr_indexed,(W4 d, R4 s, R4 index, IMM factor, IMM offset)) +{ + int fi; + + switch(factor) { + case 1: fi=0; break; + case 2: fi=1; break; + case 4: fi=2; break; + case 8: fi=3; break; + default: abort(); + } + + emit_byte(0x8d); + emit_byte(0x84+8*d); + emit_byte(0x40*fi+8*index+s); + emit_long(offset); +} +LENDFUNC(NONE,NONE,5,raw_lea_l_brr_indexed,(W4 d, R4 s, R4 index, IMM factor, IMM offset)) + +LOWFUNC(NONE,NONE,4,raw_lea_l_rr_indexed,(W4 d, R4 s, R4 index, IMM factor)) +{ + int isebp=(s==5)?0x40:0; + int fi; + + switch(factor) { + case 1: fi=0; break; + case 2: fi=1; break; + case 4: fi=2; break; + case 8: fi=3; break; + default: abort(); + } + + emit_byte(0x8d); + emit_byte(0x04+8*d+isebp); + emit_byte(0x40*fi+8*index+s); + if (isebp) + emit_byte(0); +} +LENDFUNC(NONE,NONE,4,raw_lea_l_rr_indexed,(W4 d, R4 s, R4 index, IMM factor)) + +LOWFUNC(NONE,WRITE,3,raw_mov_l_bRr,(R4 d, R4 s, IMM offset)) +{ + emit_byte(0x89); + emit_byte(0x80+8*s+d); + emit_long(offset); +} +LENDFUNC(NONE,WRITE,3,raw_mov_l_bRr,(R4 d, R4 s, IMM offset)) + +LOWFUNC(NONE,WRITE,3,raw_mov_w_bRr,(R4 d, R2 s, IMM offset)) +{ + emit_byte(0x66); + emit_byte(0x89); + emit_byte(0x80+8*s+d); + emit_long(offset); +} +LENDFUNC(NONE,WRITE,3,raw_mov_w_bRr,(R4 d, R2 s, IMM offset)) + +LOWFUNC(NONE,WRITE,3,raw_mov_b_bRr,(R4 d, R1 s, IMM offset)) +{ + emit_byte(0x88); + emit_byte(0x80+8*s+d); + emit_long(offset); +} +LENDFUNC(NONE,WRITE,3,raw_mov_b_bRr,(R4 d, R1 s, IMM offset)) + +LOWFUNC(NONE,NONE,1,raw_bswap_32,(RW4 r)) +{ + emit_byte(0x0f); + emit_byte(0xc8+r); +} +LENDFUNC(NONE,NONE,1,raw_bswap_32,(RW4 r)) + +LOWFUNC(WRITE,NONE,1,raw_bswap_16,(RW2 r)) +{ + emit_byte(0x66); + emit_byte(0xc1); + emit_byte(0xc0+r); + emit_byte(0x08); +} +LENDFUNC(WRITE,NONE,1,raw_bswap_16,(RW2 r)) + +LOWFUNC(NONE,NONE,2,raw_mov_l_rr,(W4 d, R4 s)) +{ + emit_byte(0x89); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(NONE,NONE,2,raw_mov_l_rr,(W4 d, R4 s)) + +LOWFUNC(NONE,WRITE,2,raw_mov_l_mr,(IMM d, R4 s)) +{ + emit_byte(0x89); + emit_byte(0x05+8*s); + emit_long(d); +} +LENDFUNC(NONE,WRITE,2,raw_mov_l_mr,(IMM d, R4 s)) + +LOWFUNC(NONE,READ,2,raw_mov_l_rm,(W4 d, MEMR s)) +{ + emit_byte(0x8b); + emit_byte(0x05+8*d); + emit_long(s); +} +LENDFUNC(NONE,READ,2,raw_mov_l_rm,(W4 d, MEMR s)) + +LOWFUNC(NONE,WRITE,2,raw_mov_w_mr,(IMM d, R2 s)) +{ + emit_byte(0x66); + emit_byte(0x89); + emit_byte(0x05+8*s); + emit_long(d); +} +LENDFUNC(NONE,WRITE,2,raw_mov_w_mr,(IMM d, R2 s)) + +LOWFUNC(NONE,READ,2,raw_mov_w_rm,(W2 d, IMM s)) +{ + emit_byte(0x66); + emit_byte(0x8b); + emit_byte(0x05+8*d); + emit_long(s); +} +LENDFUNC(NONE,READ,2,raw_mov_w_rm,(W2 d, IMM s)) + +LOWFUNC(NONE,WRITE,2,raw_mov_b_mr,(IMM d, R1 s)) +{ + emit_byte(0x88); + emit_byte(0x05+8*s); + emit_long(d); +} +LENDFUNC(NONE,WRITE,2,raw_mov_b_mr,(IMM d, R1 s)) + +LOWFUNC(NONE,READ,2,raw_mov_b_rm,(W1 d, IMM s)) +{ + emit_byte(0x8a); + emit_byte(0x05+8*d); + emit_long(s); +} +LENDFUNC(NONE,READ,2,raw_mov_b_rm,(W1 d, IMM s)) + +LOWFUNC(NONE,NONE,2,raw_mov_l_ri,(W4 d, IMM s)) +{ + emit_byte(0xb8+d); + emit_long(s); +} +LENDFUNC(NONE,NONE,2,raw_mov_l_ri,(W4 d, IMM s)) + +LOWFUNC(NONE,NONE,2,raw_mov_w_ri,(W2 d, IMM s)) +{ + emit_byte(0x66); + emit_byte(0xb8+d); + emit_word(s); +} +LENDFUNC(NONE,NONE,2,raw_mov_w_ri,(W2 d, IMM s)) + +LOWFUNC(NONE,NONE,2,raw_mov_b_ri,(W1 d, IMM s)) +{ + emit_byte(0xb0+d); + emit_byte(s); +} +LENDFUNC(NONE,NONE,2,raw_mov_b_ri,(W1 d, IMM s)) + +LOWFUNC(RMW,RMW,2,raw_adc_l_mi,(MEMRW d, IMM s)) +{ + emit_byte(0x81); + emit_byte(0x15); + emit_long(d); + emit_long(s); +} +LENDFUNC(RMW,RMW,2,raw_adc_l_mi,(MEMRW d, IMM s)) + +LOWFUNC(WRITE,RMW,2,raw_add_l_mi,(IMM d, IMM s)) +{ + emit_byte(0x81); + emit_byte(0x05); + emit_long(d); + emit_long(s); +} +LENDFUNC(WRITE,RMW,2,raw_add_l_mi,(IMM d, IMM s)) + +LOWFUNC(WRITE,RMW,2,raw_add_w_mi,(IMM d, IMM s)) +{ + emit_byte(0x66); + emit_byte(0x81); + emit_byte(0x05); + emit_long(d); + emit_word(s); +} +LENDFUNC(WRITE,RMW,2,raw_add_w_mi,(IMM d, IMM s)) + +LOWFUNC(WRITE,RMW,2,raw_add_b_mi,(IMM d, IMM s)) +{ + emit_byte(0x80); + emit_byte(0x05); + emit_long(d); + emit_byte(s); +} +LENDFUNC(WRITE,RMW,2,raw_add_b_mi,(IMM d, IMM s)) + +LOWFUNC(WRITE,NONE,2,raw_test_l_ri,(R4 d, IMM i)) +{ + emit_byte(0xf7); + emit_byte(0xc0+d); + emit_long(i); +} +LENDFUNC(WRITE,NONE,2,raw_test_l_ri,(R4 d, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_test_l_rr,(R4 d, R4 s)) +{ + emit_byte(0x85); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(WRITE,NONE,2,raw_test_l_rr,(R4 d, R4 s)) + +LOWFUNC(WRITE,NONE,2,raw_test_w_rr,(R2 d, R2 s)) +{ + emit_byte(0x66); + emit_byte(0x85); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(WRITE,NONE,2,raw_test_w_rr,(R2 d, R2 s)) + +LOWFUNC(WRITE,NONE,2,raw_test_b_rr,(R1 d, R1 s)) +{ + emit_byte(0x84); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(WRITE,NONE,2,raw_test_b_rr,(R1 d, R1 s)) + +LOWFUNC(WRITE,NONE,2,raw_and_l_ri,(RW4 d, IMM i)) +{ + emit_byte(0x81); + emit_byte(0xe0+d); + emit_long(i); +} +LENDFUNC(WRITE,NONE,2,raw_and_l_ri,(RW4 d, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_and_w_ri,(RW2 d, IMM i)) +{ + emit_byte(0x66); + emit_byte(0x81); + emit_byte(0xe0+d); + emit_word(i); +} +LENDFUNC(WRITE,NONE,2,raw_and_w_ri,(RW2 d, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_and_l,(RW4 d, R4 s)) +{ + emit_byte(0x21); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(WRITE,NONE,2,raw_and_l,(RW4 d, R4 s)) + +LOWFUNC(WRITE,NONE,2,raw_and_w,(RW2 d, R2 s)) +{ + emit_byte(0x66); + emit_byte(0x21); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(WRITE,NONE,2,raw_and_w,(RW2 d, R2 s)) + +LOWFUNC(WRITE,NONE,2,raw_and_b,(RW1 d, R1 s)) +{ + emit_byte(0x20); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(WRITE,NONE,2,raw_and_b,(RW1 d, R1 s)) + +LOWFUNC(WRITE,NONE,2,raw_or_l_ri,(RW4 d, IMM i)) +{ + emit_byte(0x81); + emit_byte(0xc8+d); + emit_long(i); +} +LENDFUNC(WRITE,NONE,2,raw_or_l_ri,(RW4 d, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_or_l,(RW4 d, R4 s)) +{ + emit_byte(0x09); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(WRITE,NONE,2,raw_or_l,(RW4 d, R4 s)) + +LOWFUNC(WRITE,NONE,2,raw_or_w,(RW2 d, R2 s)) +{ + emit_byte(0x66); + emit_byte(0x09); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(WRITE,NONE,2,raw_or_w,(RW2 d, R2 s)) + +LOWFUNC(WRITE,NONE,2,raw_or_b,(RW1 d, R1 s)) +{ + emit_byte(0x08); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(WRITE,NONE,2,raw_or_b,(RW1 d, R1 s)) + +LOWFUNC(RMW,NONE,2,raw_adc_l,(RW4 d, R4 s)) +{ + emit_byte(0x11); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(RMW,NONE,2,raw_adc_l,(RW4 d, R4 s)) + +LOWFUNC(RMW,NONE,2,raw_adc_w,(RW2 d, R2 s)) +{ + emit_byte(0x66); + emit_byte(0x11); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(RMW,NONE,2,raw_adc_w,(RW2 d, R2 s)) + +LOWFUNC(RMW,NONE,2,raw_adc_b,(RW1 d, R1 s)) +{ + emit_byte(0x10); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(RMW,NONE,2,raw_adc_b,(RW1 d, R1 s)) + +LOWFUNC(WRITE,NONE,2,raw_add_l,(RW4 d, R4 s)) +{ + emit_byte(0x01); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(WRITE,NONE,2,raw_add_l,(RW4 d, R4 s)) + +LOWFUNC(WRITE,NONE,2,raw_add_w,(RW2 d, R2 s)) +{ + emit_byte(0x66); + emit_byte(0x01); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(WRITE,NONE,2,raw_add_w,(RW2 d, R2 s)) + +LOWFUNC(WRITE,NONE,2,raw_add_b,(RW1 d, R1 s)) +{ + emit_byte(0x00); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(WRITE,NONE,2,raw_add_b,(RW1 d, R1 s)) + +LOWFUNC(WRITE,NONE,2,raw_sub_l_ri,(RW4 d, IMM i)) +{ + if (isbyte(i)) { + emit_byte(0x83); + emit_byte(0xe8+d); + emit_byte(i); + } + else { + emit_byte(0x81); + emit_byte(0xe8+d); + emit_long(i); + } +} +LENDFUNC(WRITE,NONE,2,raw_sub_l_ri,(RW4 d, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_sub_b_ri,(RW1 d, IMM i)) +{ + emit_byte(0x80); + emit_byte(0xe8+d); + emit_byte(i); +} +LENDFUNC(WRITE,NONE,2,raw_sub_b_ri,(RW1 d, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_add_l_ri,(RW4 d, IMM i)) +{ + if (isbyte(i)) { + emit_byte(0x83); + emit_byte(0xc0+d); + emit_byte(i); + } + else { + emit_byte(0x81); + emit_byte(0xc0+d); + emit_long(i); + } +} +LENDFUNC(WRITE,NONE,2,raw_add_l_ri,(RW4 d, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_add_w_ri,(RW2 d, IMM i)) +{ + if (isbyte(i)) { + emit_byte(0x66); + emit_byte(0x83); + emit_byte(0xc0+d); + emit_byte(i); + } + else { + emit_byte(0x66); + emit_byte(0x81); + emit_byte(0xc0+d); + emit_word(i); + } +} +LENDFUNC(WRITE,NONE,2,raw_add_w_ri,(RW2 d, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_add_b_ri,(RW1 d, IMM i)) +{ + emit_byte(0x80); + emit_byte(0xc0+d); + emit_byte(i); +} +LENDFUNC(WRITE,NONE,2,raw_add_b_ri,(RW1 d, IMM i)) + +LOWFUNC(RMW,NONE,2,raw_sbb_l,(RW4 d, R4 s)) +{ + emit_byte(0x19); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(RMW,NONE,2,raw_sbb_l,(RW4 d, R4 s)) + +LOWFUNC(RMW,NONE,2,raw_sbb_w,(RW2 d, R2 s)) +{ + emit_byte(0x66); + emit_byte(0x19); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(RMW,NONE,2,raw_sbb_w,(RW2 d, R2 s)) + +LOWFUNC(RMW,NONE,2,raw_sbb_b,(RW1 d, R1 s)) +{ + emit_byte(0x18); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(RMW,NONE,2,raw_sbb_b,(RW1 d, R1 s)) + +LOWFUNC(WRITE,NONE,2,raw_sub_l,(RW4 d, R4 s)) +{ + emit_byte(0x29); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(WRITE,NONE,2,raw_sub_l,(RW4 d, R4 s)) + +LOWFUNC(WRITE,NONE,2,raw_sub_w,(RW2 d, R2 s)) +{ + emit_byte(0x66); + emit_byte(0x29); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(WRITE,NONE,2,raw_sub_w,(RW2 d, R2 s)) + +LOWFUNC(WRITE,NONE,2,raw_sub_b,(RW1 d, R1 s)) +{ + emit_byte(0x28); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(WRITE,NONE,2,raw_sub_b,(RW1 d, R1 s)) + +LOWFUNC(WRITE,NONE,2,raw_cmp_l,(R4 d, R4 s)) +{ + emit_byte(0x39); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(WRITE,NONE,2,raw_cmp_l,(R4 d, R4 s)) + +LOWFUNC(WRITE,NONE,2,raw_cmp_l_ri,(R4 r, IMM i)) +{ + emit_byte(0x81); + emit_byte(0xf8+r); + emit_long(i); +} +LENDFUNC(WRITE,NONE,2,raw_cmp_l_ri,(R4 r, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_cmp_w,(R2 d, R2 s)) +{ + emit_byte(0x66); + emit_byte(0x39); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(WRITE,NONE,2,raw_cmp_w,(R2 d, R2 s)) + +LOWFUNC(WRITE,NONE,2,raw_cmp_b_ri,(R1 d, IMM i)) +{ + emit_byte(0x80); + emit_byte(0xf8+d); + emit_byte(i); +} +LENDFUNC(WRITE,NONE,2,raw_cmp_b_ri,(R1 d, IMM i)) + +LOWFUNC(WRITE,NONE,2,raw_cmp_b,(R1 d, R1 s)) +{ + emit_byte(0x38); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(WRITE,NONE,2,raw_cmp_b,(R1 d, R1 s)) + +LOWFUNC(WRITE,READ,4,raw_cmp_l_rm_indexed,(R4 d, IMM offset, R4 index, IMM factor)) +{ + int fi; + + switch(factor) { + case 1: fi=0; break; + case 2: fi=1; break; + case 4: fi=2; break; + case 8: fi=3; break; + default: abort(); + } + emit_byte(0x39); + emit_byte(0x04+8*d); + emit_byte(5+8*index+0x40*fi); + emit_long(offset); +} +LENDFUNC(WRITE,READ,4,raw_cmp_l_rm_indexed,(R4 d, IMM offset, R4 index, IMM factor)) + +LOWFUNC(WRITE,NONE,2,raw_xor_l,(RW4 d, R4 s)) +{ + emit_byte(0x31); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(WRITE,NONE,2,raw_xor_l,(RW4 d, R4 s)) + +LOWFUNC(WRITE,NONE,2,raw_xor_w,(RW2 d, R2 s)) +{ + emit_byte(0x66); + emit_byte(0x31); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(WRITE,NONE,2,raw_xor_w,(RW2 d, R2 s)) + +LOWFUNC(WRITE,NONE,2,raw_xor_b,(RW1 d, R1 s)) +{ + emit_byte(0x30); + emit_byte(0xc0+8*s+d); +} +LENDFUNC(WRITE,NONE,2,raw_xor_b,(RW1 d, R1 s)) + +LOWFUNC(WRITE,RMW,2,raw_sub_l_mi,(MEMRW d, IMM s)) +{ + emit_byte(0x81); + emit_byte(0x2d); + emit_long(d); + emit_long(s); +} +LENDFUNC(WRITE,RMW,2,raw_sub_l_mi,(MEMRW d, IMM s)) + +LOWFUNC(WRITE,READ,2,raw_cmp_l_mi,(MEMR d, IMM s)) +{ + emit_byte(0x81); + emit_byte(0x3d); + emit_long(d); + emit_long(s); +} +LENDFUNC(WRITE,READ,2,raw_cmp_l_mi,(MEMR d, IMM s)) + +LOWFUNC(NONE,NONE,2,raw_xchg_l_rr,(RW4 r1, RW4 r2)) +{ + emit_byte(0x87); + emit_byte(0xc0+8*r1+r2); +} +LENDFUNC(NONE,NONE,2,raw_xchg_l_rr,(RW4 r1, RW4 r2)) + +LOWFUNC(READ,WRITE,0,raw_pushfl,(void)) +{ + emit_byte(0x9c); +} +LENDFUNC(READ,WRITE,0,raw_pushfl,(void)) + +LOWFUNC(WRITE,READ,0,raw_popfl,(void)) +{ + emit_byte(0x9d); +} +LENDFUNC(WRITE,READ,0,raw_popfl,(void)) + +/************************************************************************* + * Unoptimizable stuff --- jump * + *************************************************************************/ + +static __inline__ void raw_call_r(R4 r) +{ + lopt_emit_all(); + emit_byte(0xff); + emit_byte(0xd0+r); +} + +static __inline__ void raw_jmp_r(R4 r) +{ + lopt_emit_all(); + emit_byte(0xff); + emit_byte(0xe0+r); +} + +static __inline__ void raw_jmp_m_indexed(uae_u32 base, uae_u32 r, uae_u32 m) +{ + int mu; + switch(m) { + case 1: mu=0; break; + case 2: mu=1; break; + case 4: mu=2; break; + case 8: mu=3; break; + default: abort(); + } + lopt_emit_all(); + emit_byte(0xff); + emit_byte(0x24); + emit_byte(0x05+8*r+0x40*mu); + emit_long(base); +} + +static __inline__ void raw_jmp_m(uae_u32 base) +{ + lopt_emit_all(); + emit_byte(0xff); + emit_byte(0x25); + emit_long(base); +} + + +static __inline__ void raw_call(uae_u32 t) +{ + lopt_emit_all(); + emit_byte(0xe8); + emit_long(t-(uae_u32)target-4); +} + +static __inline__ void raw_jmp(uae_u32 t) +{ + lopt_emit_all(); + emit_byte(0xe9); + emit_long(t-(uae_u32)target-4); +} + +static __inline__ void raw_jl(uae_u32 t) +{ + lopt_emit_all(); + emit_byte(0x0f); + emit_byte(0x8c); + emit_long(t-(uae_u32)target-4); +} + +static __inline__ void raw_jz(uae_u32 t) +{ + lopt_emit_all(); + emit_byte(0x0f); + emit_byte(0x84); + emit_long(t-(uae_u32)target-4); +} + +static __inline__ void raw_jnz(uae_u32 t) +{ + lopt_emit_all(); + emit_byte(0x0f); + emit_byte(0x85); + emit_long(t-(uae_u32)target-4); +} + +static __inline__ void raw_jnz_l_oponly(void) +{ + lopt_emit_all(); + emit_byte(0x0f); + emit_byte(0x85); +} + +static __inline__ void raw_jcc_l_oponly(int cc) +{ + lopt_emit_all(); + emit_byte(0x0f); + emit_byte(0x80+cc); +} + +static __inline__ void raw_jnz_b_oponly(void) +{ + lopt_emit_all(); + emit_byte(0x75); +} + +static __inline__ void raw_jz_b_oponly(void) +{ + lopt_emit_all(); + emit_byte(0x74); +} + +static __inline__ void raw_jmp_l_oponly(void) +{ + lopt_emit_all(); + emit_byte(0xe9); +} + +static __inline__ void raw_jmp_b_oponly(void) +{ + lopt_emit_all(); + emit_byte(0xeb); +} + +static __inline__ void raw_ret(void) +{ + lopt_emit_all(); + emit_byte(0xc3); +} + +static __inline__ void raw_nop(void) +{ + lopt_emit_all(); + emit_byte(0x90); +} + + +/************************************************************************* + * Flag handling, to and fro UAE flag register * + *************************************************************************/ + + +#define FLAG_NREG1 0 /* Set to -1 if any register will do */ + +static __inline__ void raw_flags_to_reg(int r) +{ + raw_lahf(0); /* Most flags in AH */ + //raw_setcc(r,0); /* V flag in AL */ + raw_setcc_m((uae_u32)live.state[FLAGTMP].mem,0); + +#if 1 /* Let's avoid those nasty partial register stalls */ + //raw_mov_b_mr((uae_u32)live.state[FLAGTMP].mem,r); + raw_mov_b_mr(((uae_u32)live.state[FLAGTMP].mem)+1,r+4); + //live.state[FLAGTMP].status=CLEAN; + live.state[FLAGTMP].status=INMEM; + live.state[FLAGTMP].realreg=-1; + /* We just "evicted" FLAGTMP. */ + if (live.nat[r].nholds!=1) { + /* Huh? */ + abort(); + } + live.nat[r].nholds=0; +#endif +} + +#define FLAG_NREG2 0 /* Set to -1 if any register will do */ +static __inline__ void raw_reg_to_flags(int r) +{ + raw_cmp_b_ri(r,-127); /* set V */ + raw_sahf(0); +} + +/* Apparently, there are enough instructions between flag store and + flag reload to avoid the partial memory stall */ +static __inline__ void raw_load_flagreg(uae_u32 target, uae_u32 r) +{ +#if 1 + raw_mov_l_rm(target,(uae_u32)live.state[r].mem); +#else + raw_mov_b_rm(target,(uae_u32)live.state[r].mem); + raw_mov_b_rm(target+4,((uae_u32)live.state[r].mem)+1); +#endif +} + +/* FLAGX is byte sized, and we *do* write it at that size */ +static __inline__ void raw_load_flagx(uae_u32 target, uae_u32 r) +{ + if (live.nat[target].canbyte) + raw_mov_b_rm(target,(uae_u32)live.state[r].mem); + else if (live.nat[target].canword) + raw_mov_w_rm(target,(uae_u32)live.state[r].mem); + else + raw_mov_l_rm(target,(uae_u32)live.state[r].mem); +} + +#define NATIVE_FLAG_Z 0x40 +#define NATIVE_CC_EQ 4 +static __inline__ void raw_flags_set_zero(int f, int r, int t) +{ + // FIXME: this is really suboptimal + raw_pushfl(); + raw_pop_l_r(f); + raw_and_l_ri(f,~NATIVE_FLAG_Z); + raw_test_l_rr(r,r); + raw_mov_l_ri(r,0); + raw_mov_l_ri(t,NATIVE_FLAG_Z); + raw_cmov_l_rr(r,t,NATIVE_CC_EQ); + raw_or_l(f,r); + raw_push_l_r(f); + raw_popfl(); +} + +static __inline__ void raw_inc_sp(int off) +{ + raw_add_l_ri(4,off); +} + +/************************************************************************* + * Handling mistaken direct memory access * + *************************************************************************/ + + +#ifdef NATMEM_OFFSET +#ifdef _WIN32 // %%% BRIAN KING WAS HERE %%% +#include +#else +#include +#endif +#include + +#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;i1) { + 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=0) { + /* source is on top of stack, and we already have the dest */ + int dd=stackpos(d); + emit_byte(0xdd); + emit_byte(0xd0+dd); + } + else { + emit_byte(0xd9); + emit_byte(0xc0+ds); /* duplicate source on tos */ + tos_make(d); /* store to destination, pop if necessary */ + } +} +LENDFUNC(NONE,NONE,2,raw_fmov_rr,(FW d, FR s)) + +LOWFUNC(NONE,READ,4,raw_fldcw_m_indexed,(R4 index, IMM base)) +{ + emit_byte(0xd9); + emit_byte(0xa8+index); + emit_long(base); +} +LENDFUNC(NONE,READ,4,raw_fldcw_m_indexed,(R4 index, IMM base)) + + +LOWFUNC(NONE,NONE,2,raw_fsqrt_rr,(FW d, FR s)) +{ + int ds; + + if (d!=s) { + usereg(s); + ds=stackpos(s); + emit_byte(0xd9); + emit_byte(0xc0+ds); /* duplicate source */ + emit_byte(0xd9); + emit_byte(0xfa); /* take square root */ + tos_make(d); /* store to destination */ + } + else { + make_tos(d); + emit_byte(0xd9); + emit_byte(0xfa); /* take square root */ + } +} +LENDFUNC(NONE,NONE,2,raw_fsqrt_rr,(FW d, FR s)) + +LOWFUNC(NONE,NONE,2,raw_fabs_rr,(FW d, FR s)) +{ + int ds; + + if (d!=s) { + usereg(s); + ds=stackpos(s); + emit_byte(0xd9); + emit_byte(0xc0+ds); /* duplicate source */ + emit_byte(0xd9); + emit_byte(0xe1); /* take fabs */ + tos_make(d); /* store to destination */ + } + else { + make_tos(d); + emit_byte(0xd9); + emit_byte(0xe1); /* take fabs */ + } +} +LENDFUNC(NONE,NONE,2,raw_fabs_rr,(FW d, FR s)) + +LOWFUNC(NONE,NONE,2,raw_frndint_rr,(FW d, FR s)) +{ + int ds; + + if (d!=s) { + usereg(s); + ds=stackpos(s); + emit_byte(0xd9); + emit_byte(0xc0+ds); /* duplicate source */ + emit_byte(0xd9); + emit_byte(0xfc); /* take frndint */ + tos_make(d); /* store to destination */ + } + else { + make_tos(d); + emit_byte(0xd9); + emit_byte(0xfc); /* take frndint */ + } +} +LENDFUNC(NONE,NONE,2,raw_frndint_rr,(FW d, FR s)) + +LOWFUNC(NONE,NONE,2,raw_fcos_rr,(FW d, FR s)) +{ + int ds; + + if (d!=s) { + usereg(s); + ds=stackpos(s); + emit_byte(0xd9); + emit_byte(0xc0+ds); /* duplicate source */ + emit_byte(0xd9); + emit_byte(0xff); /* take cos */ + tos_make(d); /* store to destination */ + } + else { + make_tos(d); + emit_byte(0xd9); + emit_byte(0xff); /* take cos */ + } +} +LENDFUNC(NONE,NONE,2,raw_fcos_rr,(FW d, FR s)) + +LOWFUNC(NONE,NONE,2,raw_fsin_rr,(FW d, FR s)) +{ + int ds; + + if (d!=s) { + usereg(s); + ds=stackpos(s); + emit_byte(0xd9); + emit_byte(0xc0+ds); /* duplicate source */ + emit_byte(0xd9); + emit_byte(0xfe); /* take sin */ + tos_make(d); /* store to destination */ + } + else { + make_tos(d); + emit_byte(0xd9); + emit_byte(0xfe); /* take sin */ + } +} +LENDFUNC(NONE,NONE,2,raw_fsin_rr,(FW d, FR s)) + +double one=1; +LOWFUNC(NONE,NONE,2,raw_ftwotox_rr,(FW d, FR s)) +{ + int ds; + + usereg(s); + ds=stackpos(s); + emit_byte(0xd9); + emit_byte(0xc0+ds); /* duplicate source */ + + emit_byte(0xd9); + emit_byte(0xc0); /* duplicate top of stack. Now up to 8 high */ + emit_byte(0xd9); + emit_byte(0xfc); /* rndint */ + emit_byte(0xd9); + emit_byte(0xc9); /* swap top two elements */ + emit_byte(0xd8); + emit_byte(0xe1); /* subtract rounded from original */ + emit_byte(0xd9); + emit_byte(0xf0); /* f2xm1 */ + emit_byte(0xdc); + emit_byte(0x05); + emit_long((uae_u32)&one); /* Add '1' without using extra stack space */ + emit_byte(0xd9); + emit_byte(0xfd); /* and scale it */ + emit_byte(0xdd); + emit_byte(0xd9); /* take he rounded value off */ + tos_make(d); /* store to destination */ +} +LENDFUNC(NONE,NONE,2,raw_ftwotox_rr,(FW d, FR s)) + +LOWFUNC(NONE,NONE,2,raw_fetox_rr,(FW d, FR s)) +{ + int ds; + + usereg(s); + ds=stackpos(s); + emit_byte(0xd9); + emit_byte(0xc0+ds); /* duplicate source */ + emit_byte(0xd9); + emit_byte(0xea); /* fldl2e */ + emit_byte(0xde); + emit_byte(0xc9); /* fmulp --- multiply source by log2(e) */ + + emit_byte(0xd9); + emit_byte(0xc0); /* duplicate top of stack. Now up to 8 high */ + emit_byte(0xd9); + emit_byte(0xfc); /* rndint */ + emit_byte(0xd9); + emit_byte(0xc9); /* swap top two elements */ + emit_byte(0xd8); + emit_byte(0xe1); /* subtract rounded from original */ + emit_byte(0xd9); + emit_byte(0xf0); /* f2xm1 */ + emit_byte(0xdc); + emit_byte(0x05); + emit_long((uae_u32)&one); /* Add '1' without using extra stack space */ + emit_byte(0xd9); + emit_byte(0xfd); /* and scale it */ + emit_byte(0xdd); + emit_byte(0xd9); /* take he rounded value off */ + tos_make(d); /* store to destination */ +} +LENDFUNC(NONE,NONE,2,raw_fetox_rr,(FW d, FR s)) + +LOWFUNC(NONE,NONE,2,raw_flog2_rr,(FW d, FR s)) +{ + int ds; + + usereg(s); + ds=stackpos(s); + emit_byte(0xd9); + emit_byte(0xc0+ds); /* duplicate source */ + emit_byte(0xd9); + emit_byte(0xe8); /* push '1' */ + emit_byte(0xd9); + emit_byte(0xc9); /* swap top two */ + emit_byte(0xd9); + emit_byte(0xf1); /* take 1*log2(x) */ + tos_make(d); /* store to destination */ +} +LENDFUNC(NONE,NONE,2,raw_flog2_rr,(FW d, FR s)) + + +LOWFUNC(NONE,NONE,2,raw_fneg_rr,(FW d, FR s)) +{ + int ds; + + if (d!=s) { + usereg(s); + ds=stackpos(s); + emit_byte(0xd9); + emit_byte(0xc0+ds); /* duplicate source */ + emit_byte(0xd9); + emit_byte(0xe0); /* take fchs */ + tos_make(d); /* store to destination */ + } + else { + make_tos(d); + emit_byte(0xd9); + emit_byte(0xe0); /* take fchs */ + } +} +LENDFUNC(NONE,NONE,2,raw_fneg_rr,(FW d, FR s)) + +LOWFUNC(NONE,NONE,2,raw_fadd_rr,(FRW d, FR s)) +{ + int ds; + + usereg(s); + usereg(d); + + if (live.spos[s]==live.tos) { + /* Source is on top of stack */ + ds=stackpos(d); + emit_byte(0xdc); + emit_byte(0xc0+ds); /* add source to dest*/ + } + else { + make_tos(d); + ds=stackpos(s); + + emit_byte(0xd8); + emit_byte(0xc0+ds); /* add source to dest*/ + } +} +LENDFUNC(NONE,NONE,2,raw_fadd_rr,(FRW d, FR s)) + +LOWFUNC(NONE,NONE,2,raw_fsub_rr,(FRW d, FR s)) +{ + int ds; + + usereg(s); + usereg(d); + + if (live.spos[s]==live.tos) { + /* Source is on top of stack */ + ds=stackpos(d); + emit_byte(0xdc); + emit_byte(0xe8+ds); /* sub source from dest*/ + } + else { + make_tos(d); + ds=stackpos(s); + + emit_byte(0xd8); + emit_byte(0xe0+ds); /* sub src from dest */ + } +} +LENDFUNC(NONE,NONE,2,raw_fsub_rr,(FRW d, FR s)) + +LOWFUNC(NONE,NONE,2,raw_fcmp_rr,(FR d, FR s)) +{ + int ds; + + usereg(s); + usereg(d); + + make_tos(d); + ds=stackpos(s); + + emit_byte(0xdd); + emit_byte(0xe0+ds); /* cmp dest with source*/ +} +LENDFUNC(NONE,NONE,2,raw_fcmp_rr,(FR d, FR s)) + +LOWFUNC(NONE,NONE,2,raw_fmul_rr,(FRW d, FR s)) +{ + int ds; + + usereg(s); + usereg(d); + + if (live.spos[s]==live.tos) { + /* Source is on top of stack */ + ds=stackpos(d); + emit_byte(0xdc); + emit_byte(0xc8+ds); /* mul dest by source*/ + } + else { + make_tos(d); + ds=stackpos(s); + + emit_byte(0xd8); + emit_byte(0xc8+ds); /* mul dest by source*/ + } +} +LENDFUNC(NONE,NONE,2,raw_fmul_rr,(FRW d, FR s)) + +LOWFUNC(NONE,NONE,2,raw_fdiv_rr,(FRW d, FR s)) +{ + int ds; + + usereg(s); + usereg(d); + + if (live.spos[s]==live.tos) { + /* Source is on top of stack */ + ds=stackpos(d); + emit_byte(0xdc); + emit_byte(0xf8+ds); /* div dest by source */ + } + else { + make_tos(d); + ds=stackpos(s); + + emit_byte(0xd8); + emit_byte(0xf0+ds); /* div dest by source*/ + } +} +LENDFUNC(NONE,NONE,2,raw_fdiv_rr,(FRW d, FR s)) + +LOWFUNC(NONE,NONE,2,raw_frem_rr,(FRW d, FR s)) +{ + int ds; + + usereg(s); + usereg(d); + + make_tos2(d,s); + ds=stackpos(s); + + if (ds!=1) { + printf("Failed horribly in raw_frem_rr! ds is %d\n",ds); + abort(); + } + emit_byte(0xd9); + emit_byte(0xf8); /* take rem from dest by source */ +} +LENDFUNC(NONE,NONE,2,raw_frem_rr,(FRW d, FR s)) + +LOWFUNC(NONE,NONE,2,raw_frem1_rr,(FRW d, FR s)) +{ + int ds; + + usereg(s); + usereg(d); + + make_tos2(d,s); + ds=stackpos(s); + + if (ds!=1) { + printf("Failed horribly in raw_frem1_rr! ds is %d\n",ds); + abort(); + } + emit_byte(0xd9); + emit_byte(0xf5); /* take rem1 from dest by source */ +} +LENDFUNC(NONE,NONE,2,raw_frem1_rr,(FRW d, FR s)) + + +LOWFUNC(NONE,NONE,1,raw_ftst_r,(FR r)) +{ + make_tos(r); + emit_byte(0xd9); /* ftst */ + emit_byte(0xe4); +} +LENDFUNC(NONE,NONE,1,raw_ftst_r,(FR r)) + +static __inline__ void raw_fflags_into_flags(int r) +{ + int p; + + usereg(r); + p=stackpos(r); + + emit_byte(0xd9); + emit_byte(0xee); /* Push 0 */ + emit_byte(0xd9); + emit_byte(0xc9+p); /* swap top two around */ + if (have_cmov) { + // gb-- fucomi is for P6 cores only, not K6-2 then... + emit_byte(0xdb); + emit_byte(0xe9+p); /* fucomi them */ + } + else { + emit_byte(0xdd); + emit_byte(0xe1+p); /* fucom them */ + emit_byte(0x9b); + emit_byte(0xdf); + emit_byte(0xe0); /* fstsw ax */ + raw_sahf(0); /* sahf */ + } + emit_byte(0xdd); + emit_byte(0xd9+p); /* store value back, and get rid of 0 */ +} diff --git a/compemu_support.c b/compemu_support.c new file mode 100755 index 00000000..5143c61e --- /dev/null +++ b/compemu_support.c @@ -0,0 +1,6185 @@ +#define writemem_special writemem +#define readmem_special readmem + +#define USE_MATCHSTATE 0 +#define setzflg_uses_bsf 0 +#include "sysconfig.h" +#include "sysdeps.h" +#include "config.h" +#include "options.h" +#include "events.h" +#include "include/memory.h" +#include "custom.h" +#include "newcpu.h" +#include "compiler.h" +#include "comptbl.h" +#include "compemu.h" + +// %%% BRIAN KING WAS HERE %%% +extern int canbang; +#include +#include /* 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;inat[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;inat[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;ipc_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 : comptrustbyte is not 'direct' or 'afterpic'\n"); + if (currprefs.comptrustword!=0 && currprefs.comptrustword!=3) + stop = 1, write_log(" : comptrustword is not 'direct' or 'afterpic'\n"); + if (currprefs.comptrustlong!=0 && currprefs.comptrustlong!=3) + stop = 1, write_log(" : comptrustlong is not 'direct' or 'afterpic'\n"); + if (currprefs.comptrustnaddr!=0 && currprefs.comptrustnaddr!=3) + stop = 1, write_log(" : comptrustnaddr is not 'direct' or 'afterpic'\n"); + if (currprefs.compnf!=1) + stop = 1, write_log(" : compnf is not 'yes'\n"); + if (currprefs.cachesize<1024) + stop = 1, write_log(" : cachesize is less than 1024\n"); + if (currprefs.comp_hardflush) + stop = 1, write_log(" : comp_flushmode is 'hard'\n"); + if (!canbang) + stop = 1, write_log(" : 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;i0) { + 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=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) { + 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 && badness0) { + 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>=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;i1) + abort(); + if (live.nat[n].nholds && depthnat[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;is->nat[vton[i]].dirtysize) + tomem(i); + /* Fall-through! */ + case CLEAN: + if (vton[i]==-1 || + live.state[i].validsizenat[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;is->nat[n].dirtysize) + abort; + if (live.state[i].validsizenat[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=(uae_u32)kickmemory && + addr<(uae_u32)kickmemory+8*65536); +} + +static void flush_all(void) +{ + int i; + + log_flush(); + for (i=0;i0) + free_nreg(i); + + for (i=0;i0) + 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<> 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;idirect_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;ipc_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)currpcpmax_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;i1) { + 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 (ineeded_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_penv)); + //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_lenlen=max_pcp-min_pcp; + bi->min_pcp=min_pcp; + + remove_from_list(bi); + if (isinrom(min_pcp) && isinrom(max_pcp)) + add_to_dormant(bi); /* No need to checksum it on cache flush. + Please don't start changing ROMs in + flight! */ + else { + calc_checksum(bi,&(bi->c1),&(bi->c2)); + add_to_active(bi); + } + + log_dump(); + align_target(32); + current_compile_p=get_target(); + + raise_in_cl_list(bi); + bi->nexthandler=current_compile_p; + + /* We will flush soon, anyway, so let's do it now */ + if (current_compile_p>=max_compile_start) + flush_icache_hard(7); + + do_extra_cycles(totcycles); /* for the compilation time */ + } +} + + diff --git a/compiler.c b/compiler.c new file mode 100755 index 00000000..fd3ee040 --- /dev/null +++ b/compiler.c @@ -0,0 +1,4555 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * m68k emulation + * + * Copyright 1996 Bernd Schmidt + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "events.h" +#include "gui.h" +#include "memory.h" +#include "custom.h" +#include "newcpu.h" +#include "ersatz.h" +#include "blitter.h" +#include "debug.h" +#include "autoconf.h" +#include "compiler.h" + +#ifdef USE_COMPILER + +#include + +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 */ diff --git a/cpuopti.c b/cpuopti.c new file mode 100755 index 00000000..1582bf5f --- /dev/null +++ b/cpuopti.c @@ -0,0 +1,321 @@ +/* + * UAE - The Un*x Amiga Emulator + * + * cpuopti.c - Small optimizer for cpu*.s files + * Based on work by Tauno Taipaleenmaki + * + * Copyright 1996 Bernd Schmidt + */ + +#include "sysconfig.h" +#include "sysdeps.h" +#include + +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; +} diff --git a/custom.c b/custom.c new file mode 100755 index 00000000..90d2bfdd --- /dev/null +++ b/custom.c @@ -0,0 +1,5525 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Custom chip emulation + * + * Copyright 1995-2002 Bernd Schmidt + * Copyright 1995 Alessandro Bissacco + * Copyright 2000-2004 Toni Wilen + */ + +//#define CUSTOM_DEBUG +#define DEBUG_COPPER 0 +#define SPRITE_DEBUG 0 +#define SPRITE_DEBUG_MINY 0 +#define SPRITE_DEBUG_MAXY 400 +//#define DISABLE_SPRITES +#define SPR0_HPOS 0x15 +#define MAX_SPRITES 8 +#define SPRITE_COLLISIONS +#define SPEEDUP + +#include "sysconfig.h" +#include "sysdeps.h" + +#include +#include + +#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 diff --git a/debug.c b/debug.c new file mode 100755 index 00000000..c2b442e4 --- /dev/null +++ b/debug.c @@ -0,0 +1,1401 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Debugger + * + * (c) 1995 Bernd Schmidt + * + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include +#include + +#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 [
] Start execution at the current address or
\n" + " c Dump state of the CIA, disk drives and custom registers\n" + " r Dump state of the CPU\n" + " m
[] Memory dump starting at
\n" + " d
[] Disassembly starting at
\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
Add/remove breakpoint\n" + " fi Step forward until PC points to RTS/RTD or RTE\n" + " fi Step forward until PC points to \n" + " fl List breakpoints\n" + " fd Remove all breakpoints\n" + " f Step forward until <= PC <= \n" + " e Dump contents of all custom registers\n" + " i Dump contents of interrupt and trap vectors\n" + " o <1|2|addr> []View memory as Copper instructions\n" + " O Display bitplane offsets\n" + " O Offset a bitplane\n" + " H Show PC history instructions\n" + " M Search for *Tracker sound modules\n" + " C Search for values like energy or lifes in games\n" + " W
Write into Amiga memory\n" + " w
[]\n" + " Add/remove memory watchpoints\n" + " S Save a block of Amiga memory\n" + " s / [] []\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 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; +} diff --git a/disk.c b/disk.c new file mode 100755 index 00000000..c2a29fa7 --- /dev/null +++ b/disk.c @@ -0,0 +1,2601 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Floppy disk emulation + * + * Copyright 1995 Hannu Rummukainen + * Copyright 1995-2001 Bernd Schmidt + * Copyright 2000-2003 Toni Wilen + * + * High Density Drive Handling by Dr. Adil Temel (C) 2001 [atemel1@hotmail.com] + * + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "uae.h" +#include "config.h" +#include "options.h" +#include "threaddep/thread.h" +#include "memory.h" +#include "events.h" +#include "custom.h" +#include "ersatz.h" +#include "disk.h" +#include "gui.h" +#include "zfile.h" +#include "autoconf.h" +#include "newcpu.h" +#include "xwin.h" +#include "osemu.h" +#include "execlib.h" +#include "savestate.h" +#include "fdi2raw.h" +#include "catweasel.h" +#include "driveclick.h" +#ifdef CAPS +#include "caps/caps_win32.h" +#endif + +/* writable track length with normal 2us bitcell/300RPM motor (PAL) */ +#define FLOPPY_WRITE_LEN (currprefs.ntscmode ? (12798 / 2) : (12668 / 2)) /* 12667 PAL, 12797 NTSC */ +/* This works out to 350 */ +#define FLOPPY_GAP_LEN (FLOPPY_WRITE_LEN - 11 * 544) +/* (cycles/bitcell) << 8, normal = ((2us/280ns)<<8) = ~1830 */ +#define NORMAL_FLOPPY_SPEED (currprefs.ntscmode ? 1810 : 1829) + +#define DISK_DEBUG +#define DISK_DEBUG2 +#undef DISK_DEBUG +#undef DISK_DEBUG2 +#undef DEBUG_DRIVE_ID + +/* UAE-1ADF (ADF_EXT2) + * W reserved + * W number of tracks (default 2*80=160) + * + * W reserved + * W type, 0=normal AmigaDOS track, 1 = raw MFM + * L available space for track in bytes (must be even) + * L track length in bits + */ + +static int side, direction, writing; +static uae_u8 selected = 15, disabled; + +static uae_u8 *writebuffer[544 * 22]; + +#define DISK_INDEXSYNC 1 +#define DISK_WORDSYNC 2 + +/* A value of 5 works out to a guaranteed delay of 1/2 of a second + Higher values are dangerous, e.g. a value of 8 breaks the RSI + demo. */ +#define DSKREADY_TIME 5 +#define DSKREADY_DOWN_TIME 10 + +#if 0 +#define MAX_DISK_WORDS_PER_LINE 50 /* depends on floppy_speed */ +static uae_u32 dma_tab[MAX_DISK_WORDS_PER_LINE + 1]; +#endif +static int dskdmaen, dsklength, dsklen; +static uae_u16 dskbytr_val; +static uae_u32 dskpt; +static int dma_enable, bitoffset, syncoffset; +static uae_u16 word, dsksync; +/* Always carried through to the next line. */ +static int disk_hpos; + +typedef enum { TRACK_AMIGADOS, TRACK_RAW, TRACK_RAW1 } image_tracktype; +typedef struct { + uae_u16 len; + uae_u32 offs; + int bitlen, track; + unsigned int sync; + image_tracktype type; +} trackid; + +#define MAX_TRACKS 328 + +/* We have three kinds of Amiga floppy drives + * - internal A500/A2000 drive: + * ID is always DRIVE_ID_NONE (S.T.A.G expects this) + * - HD drive (A3000/A4000): + * ID is DRIVE_ID_35DD if DD floppy is inserted or drive is empty + * ID is DRIVE_ID_35HD if HD floppy is inserted + * - regular external drive: + * ID is always DRIVE_ID_35DD + */ + +#define DRIVE_ID_NONE 0x00000000 +#define DRIVE_ID_35DD 0xFFFFFFFF +#define DRIVE_ID_35HD 0xAAAAAAAA +#define DRIVE_ID_525SD 0x55555555 /* 40 track 5.25 drive , kickstart does not recognize this */ + +#define MAX_REVOLUTIONS 5 + +typedef enum { ADF_NORMAL, ADF_EXT1, ADF_EXT2, ADF_FDI, ADF_IPF, ADF_CATWEASEL } drive_filetype; +typedef struct { + struct zfile *diskfile; + struct zfile *writediskfile; + drive_filetype filetype; + trackid trackdata[MAX_TRACKS]; + trackid writetrackdata[MAX_TRACKS]; + int buffered_cyl, buffered_side; + int cyl; + int motoroff; + int state; + int wrprot; + uae_u16 bigmfmbuf[MAX_REVOLUTIONS * 0x8000]; + int revolutions; + int current_revolution; + uae_u16 *trackpointers[MAX_REVOLUTIONS]; + uae_u16 *tracktiming; + int tracklengths[MAX_REVOLUTIONS]; + int mfmpos; + int indexoffset; + int tracklen; + int prevtracklen; + int trackspeed; + int dmalen; + int num_tracks, write_num_tracks, num_secs; + int hard_num_cyls; + int dskchange; + int dskchange_time; + int dskready; + int dskready_time; + int dskready_down_time; + int steplimit; + int ddhd; /* 1=DD 2=HD */ + int drive_id_scnt; /* drive id shift counter */ + int idbit; + unsigned long drive_id; /* drive id to be reported */ + char newname[256]; /* storage space for new filename during eject delay */ + FDI *fdi; + int useturbo; + int floppybitcounter; /* number of bits left */ +#ifdef CATWEASEL + catweasel_drive *catweasel; +#else + int catweasel; +#endif +} drive; + +static uae_u16 bigmfmbufw[0x8000]; +static drive floppy[4]; +#define MAX_PREVIOUS_FLOPPIES 99 +static char dfxhistory[MAX_PREVIOUS_FLOPPIES][256]; + +static uae_u8 exeheader[]={0x00,0x00,0x03,0xf3,0x00,0x00,0x00,0x00}; +static uae_u8 bootblock[]={ + 0x44,0x4f,0x53,0x00,0xc0,0x20,0x0f,0x19,0x00,0x00,0x03,0x70,0x43,0xfa,0x00,0x18, + 0x4e,0xae,0xff,0xa0,0x4a,0x80,0x67,0x0a,0x20,0x40,0x20,0x68,0x00,0x16,0x70,0x00, + 0x4e,0x75,0x70,0xff,0x60,0xfa,0x64,0x6f,0x73,0x2e,0x6c,0x69,0x62,0x72,0x61,0x72, + 0x79 +}; + +#define FS_OFS_DATABLOCKSIZE 488 +#define FS_FLOPPY_BLOCKSIZE 512 +#define FS_EXTENSION_BLOCKS 72 +#define FS_FLOPPY_TOTALBLOCKS 1760 +#define FS_FLOPPY_RESERVED 2 + +static void writeimageblock (struct zfile *dst, uae_u8 *sector, int offset) +{ + zfile_fseek (dst, offset, SEEK_SET); + zfile_fwrite (sector, FS_FLOPPY_BLOCKSIZE, 1, dst); +} + +static void disk_checksum(uae_u8 *p, uae_u8 *c) +{ + uae_u32 cs = 0; + int i; + for (i = 0; i < FS_FLOPPY_BLOCKSIZE; i+= 4) cs += (p[i] << 24) | (p[i+1] << 16) | (p[i+2] << 8) | (p[i+3] << 0); + cs = -cs; + c[0] = cs >> 24; c[1] = cs >> 16; c[2] = cs >> 8; c[3] = cs >> 0; +} + +static int dirhash (unsigned char *name) +{ + unsigned long hash; + int i; + + hash = strlen (name); + for(i = 0; i < strlen (name); i++) { + hash = hash * 13; + hash = hash + toupper (name[i]); + hash = hash & 0x7ff; + } + hash = hash % ((FS_FLOPPY_BLOCKSIZE / 4) - 56); + return hash; +} + +static void disk_date (uae_u8 *p) +{ + time_t t; + struct tm *today; + int year, days, minutes, ticks; + char tmp[10]; + time (&t); + today = localtime( &t ); + strftime (tmp, sizeof(tmp), "%Y", today); + year = atol (tmp); + strftime (tmp, sizeof(tmp), "%j", today); + days = atol (tmp) - 1; + strftime (tmp, sizeof(tmp), "%H", today); + minutes = atol (tmp) * 60; + strftime (tmp, sizeof(tmp), "%M", today); + minutes += atol (tmp); + strftime (tmp, sizeof(tmp), "%S", today); + ticks = atol (tmp) * 50; + while (year > 1978) { + if ( !(year % 100) ? !(year % 400) : !(year % 4) ) days++; + days += 365; + year--; + } + p[0] = days >> 24; p[1] = days >> 16; p[2] = days >> 8; p[3] = days >> 0; + p[4] = minutes >> 24; p[5] = minutes >> 16; p[6] = minutes >> 8; p[7] = minutes >> 0; + p[8] = ticks >> 24; p[9] = ticks >> 16; p[10] = ticks >> 8; p[11] = ticks >> 0; +} + +static void createbootblock (uae_u8 *sector, int bootable) +{ + memset (sector, 0, FS_FLOPPY_BLOCKSIZE); + memcpy (sector, "DOS", 3); + if (bootable) + memcpy (sector, bootblock, sizeof(bootblock)); +} + +static void createrootblock (uae_u8 *sector, uae_u8 *disk_name) +{ + memset (sector, 0, FS_FLOPPY_BLOCKSIZE); + sector[0+3] = 2; + sector[12+3] = 0x48; + sector[312] = sector[313] = sector[314] = sector[315] = (uae_u8)0xff; + sector[316+2] = 881 >> 8; sector[316+3] = 881 & 255; + sector[432] = strlen (disk_name); + strcpy (sector + 433, disk_name); + sector[508 + 3] = 1; + disk_date (sector + 420); + memcpy (sector + 472, sector + 420, 3 * 4); + memcpy (sector + 484, sector + 420, 3 * 4); +} + +static int getblock (uae_u8 *bitmap) +{ + int i = 0; + while (bitmap[i] != 0xff) { + if (bitmap[i] == 0) { + bitmap[i] = 1; + return i; + } + i++; + } + return -1; +} + +static void pl (uae_u8 *sector, int offset, uae_u32 v) +{ + sector[offset + 0] = v >> 24; + sector[offset + 1] = v >> 16; + sector[offset + 2] = v >> 8; + sector[offset + 3] = v >> 0; +} + +static int createdirheaderblock (uae_u8 *sector, int parent, char *filename, uae_u8 *bitmap) +{ + int block = getblock (bitmap); + + memset (sector, 0, FS_FLOPPY_BLOCKSIZE); + pl (sector, 0, 2); + pl (sector, 4, block); + disk_date (sector + 512 - 92); + sector[512 - 80] = strlen (filename); + strcpy (sector + 512 - 79, filename); + pl (sector, 512 - 12, parent); + pl (sector, 512 - 4, 2); + return block; +} + +static int createfileheaderblock (struct zfile *z,uae_u8 *sector, int parent, char *filename, struct zfile *src, uae_u8 *bitmap) +{ + uae_u8 sector2[FS_FLOPPY_BLOCKSIZE]; + uae_u8 sector3[FS_FLOPPY_BLOCKSIZE]; + int block = getblock (bitmap); + int datablock = getblock (bitmap); + int datasec = 1; + int extensions; + int extensionblock, extensioncounter, headerextension = 1; + int size; + + zfile_fseek (src, 0, SEEK_END); + size = zfile_ftell (src); + zfile_fseek (src, 0, SEEK_SET); + extensions = (size + FS_OFS_DATABLOCKSIZE - 1) / FS_OFS_DATABLOCKSIZE; + + memset (sector, 0, FS_FLOPPY_BLOCKSIZE); + pl (sector, 0, 2); + pl (sector, 4, block); + pl (sector, 8, extensions > FS_EXTENSION_BLOCKS ? FS_EXTENSION_BLOCKS : extensions); + pl (sector, 16, datablock); + pl (sector, FS_FLOPPY_BLOCKSIZE - 188, size); + disk_date (sector + FS_FLOPPY_BLOCKSIZE - 92); + sector[FS_FLOPPY_BLOCKSIZE - 80] = strlen (filename); + strcpy (sector + FS_FLOPPY_BLOCKSIZE - 79, filename); + pl (sector, FS_FLOPPY_BLOCKSIZE - 12, parent); + pl (sector, FS_FLOPPY_BLOCKSIZE - 4, -3); + extensioncounter = 0; + extensionblock = 0; + + while (size > 0) { + int datablock2 = datablock; + int extensionblock2 = extensionblock; + if (extensioncounter == FS_EXTENSION_BLOCKS) { + extensioncounter = 0; + extensionblock = getblock (bitmap); + if (datasec > FS_EXTENSION_BLOCKS + 1) { + pl (sector3, 8, FS_EXTENSION_BLOCKS); + pl (sector3, FS_FLOPPY_BLOCKSIZE - 8, extensionblock); + pl (sector3, 4, extensionblock2); + disk_checksum(sector3, sector3 + 20); + writeimageblock (z, sector3, extensionblock2 * FS_FLOPPY_BLOCKSIZE); + } else { + pl (sector, 512 - 8, extensionblock); + } + memset (sector3, 0, FS_FLOPPY_BLOCKSIZE); + pl (sector3, 0, 16); + pl (sector3, FS_FLOPPY_BLOCKSIZE - 12, block); + pl (sector3, FS_FLOPPY_BLOCKSIZE - 4, -3); + } + memset (sector2, 0, FS_FLOPPY_BLOCKSIZE); + pl (sector2, 0, 8); + pl (sector2, 4, block); + pl (sector2, 8, datasec++); + pl (sector2, 12, size > FS_OFS_DATABLOCKSIZE ? FS_OFS_DATABLOCKSIZE : size); + zfile_fread (sector2 + 24, size > FS_OFS_DATABLOCKSIZE ? FS_OFS_DATABLOCKSIZE : size, 1, src); + size -= FS_OFS_DATABLOCKSIZE; + datablock = 0; + if (size > 0) datablock = getblock (bitmap); + pl (sector2, 16, datablock); + disk_checksum(sector2, sector2 + 20); + writeimageblock (z, sector2, datablock2 * FS_FLOPPY_BLOCKSIZE); + if (datasec <= FS_EXTENSION_BLOCKS + 1) + pl (sector, 512 - 204 - extensioncounter * 4, datablock2); + else + pl (sector3, 512 - 204 - extensioncounter * 4, datablock2); + extensioncounter++; + } + if (datasec > FS_EXTENSION_BLOCKS) { + pl (sector3, 8, extensioncounter); + disk_checksum(sector3, sector3 + 20); + writeimageblock (z, sector3, extensionblock * FS_FLOPPY_BLOCKSIZE); + } + disk_checksum(sector, sector + 20); + writeimageblock (z, sector, block * FS_FLOPPY_BLOCKSIZE); + return block; +} + +static void createbitmapblock (uae_u8 *sector, uae_u8 *bitmap) +{ + uae_u8 mask; + int i, j; + memset (sector, 0, FS_FLOPPY_BLOCKSIZE); + for (i = FS_FLOPPY_RESERVED; i < FS_FLOPPY_TOTALBLOCKS; i += 8) { + mask = 0; + for (j = 0; j < 8; j++) { + if (bitmap[i + j]) mask |= 1 << j; + } + sector[4 + i / 8] = mask; + } + disk_checksum(sector, sector + 0); +} + +static int createimagefromexe (struct zfile *src, struct zfile *dst) +{ + uae_u8 sector1[FS_FLOPPY_BLOCKSIZE], sector2[FS_FLOPPY_BLOCKSIZE]; + uae_u8 bitmap[FS_FLOPPY_TOTALBLOCKS + 8]; + int exesize; + int blocksize = FS_OFS_DATABLOCKSIZE; + int blocks, extensionblocks; + int totalblocks; + int fblock1, dblock1; + char *fname1 = "runme.exe"; + char *fname2 = "startup-sequence"; + char *dirname1 = "s"; + struct zfile *ss; + + memset (bitmap, 0, sizeof (bitmap)); + zfile_fseek (src, 0, SEEK_END); + exesize = zfile_ftell (src); + blocks = (exesize + blocksize - 1) / blocksize; + extensionblocks = (blocks + FS_EXTENSION_BLOCKS - 1) / FS_EXTENSION_BLOCKS; + /* bootblock=2, root=1, bitmap=1, startup-sequence=1+1, exefileheader=1 */ + totalblocks = 2 + 1 + 1 + 2 + 1 + blocks + extensionblocks; + if (totalblocks > FS_FLOPPY_TOTALBLOCKS) + return 0; + + bitmap[880] = 1; + bitmap[881] = 1; + bitmap[0] = 1; + bitmap[1] = 1; + + dblock1 = createdirheaderblock (sector2, 880, dirname1, bitmap); + ss = zfile_fopen_empty (fname1, strlen(fname1)); + zfile_fwrite (fname1, strlen(fname1), 1, ss); + fblock1 = createfileheaderblock (dst, sector1, dblock1, fname2, ss, bitmap); + zfile_fclose (ss); + pl (sector2, 24 + dirhash (fname2) * 4, fblock1); + disk_checksum(sector2, sector2 + 20); + writeimageblock (dst, sector2, dblock1 * FS_FLOPPY_BLOCKSIZE); + + fblock1 = createfileheaderblock (dst, sector1, 880, fname1, src, bitmap); + + createrootblock (sector1, "empty"); + pl (sector1, 24 + dirhash (fname1) * 4, fblock1); + pl (sector1, 24 + dirhash (dirname1) * 4, dblock1); + disk_checksum(sector1, sector1 + 20); + writeimageblock (dst, sector1, 880 * FS_FLOPPY_BLOCKSIZE); + + createbitmapblock (sector1, bitmap); + writeimageblock (dst, sector1, 881 * FS_FLOPPY_BLOCKSIZE); + + createbootblock (sector1, 1); + writeimageblock (dst, sector1, 0 * FS_FLOPPY_BLOCKSIZE); + + return 1; +} + +static int get_floppy_speed (void) +{ + int m = currprefs.floppy_speed; + if (m <= 10) m = 100; + m = NORMAL_FLOPPY_SPEED * 100 / m; + return m; +} + +static char *drive_id_name(drive *drv) +{ + switch(drv->drive_id) + { + case DRIVE_ID_35HD : return "3.5HD"; + case DRIVE_ID_525SD: return "5.25SD"; + case DRIVE_ID_35DD : return "3.5DD"; + } + return "UNKNOWN"; +} + +/* Simulate exact behaviour of an A3000T 3.5 HD disk drive. + * The drive reports to be a 3.5 DD drive whenever there is no + * disk or a 3.5 DD disk is inserted. Only 3.5 HD drive id is reported + * when a real 3.5 HD disk is inserted. -Adil + */ +static void drive_settype_id(drive *drv) +{ + int t = currprefs.dfxtype[drv - &floppy[0]]; + + switch (t) + { + case DRV_35_HD: + if (!drv->diskfile || drv->ddhd <= 1) + drv->drive_id = DRIVE_ID_35DD; + else + drv->drive_id = DRIVE_ID_35HD; + break; + case DRV_35_DD: + default: + drv->drive_id = DRIVE_ID_35DD; + break; + case DRV_525_SD: + drv->drive_id = DRIVE_ID_525SD; + break; + } +#ifdef DEBUG_DRIVE_ID + write_log("drive_settype_id: DF%d: set to %s\n", drv-floppy, drive_id_name(drv)); +#endif +} + +static void drive_image_free (drive *drv) +{ + switch (drv->filetype) + { + case ADF_IPF: +#ifdef CAPS + caps_unloadimage (drv - floppy); +#endif + break; + case ADF_FDI: + fdi2raw_header_free (drv->fdi); + drv->fdi = 0; + break; + } + drv->filetype = -1; + zfile_fclose (drv->diskfile); + drv->diskfile = 0; + zfile_fclose (drv->writediskfile); + drv->writediskfile = 0; +} + +static int drive_insert (drive * drv, int dnum, const char *fname); + +static void reset_drive(int i) +{ + drive *drv = &floppy[i]; + drive_image_free (drv); + drv->motoroff = 1; + disabled &= ~(1 << i); + gui_data.drive_disabled[i] = 0; + if (currprefs.dfxtype[i] < 0) { + disabled |= 1 << i; + gui_data.drive_disabled[i] = 1; + } + drv->dskchange_time = 0; + drv->buffered_cyl = -1; + drv->buffered_side = -1; + gui_led (i + 1, 0); + drive_settype_id (drv); + if (strlen (drv->newname) > 0) + strcpy (currprefs.df[i], drv->newname); + if (!drive_insert (drv, i, currprefs.df[i])) + disk_eject (i); +} + +/* code for track display */ +static void update_drive_gui (int num) +{ + drive *drv = floppy + num; + + if (drv->state == gui_data.drive_motor[num] + && drv->cyl == gui_data.drive_track[num] + && side == gui_data.drive_side + && ((writing && gui_data.drive_writing[num]) + || (!writing && !gui_data.drive_writing[num]))) { + return; + } + gui_data.drive_motor[num] = drv->state; + gui_data.drive_track[num] = drv->cyl; + gui_data.drive_side = side; + if (!gui_data.drive_writing[num]) + gui_data.drive_writing[num] = writing; + gui_ledstate &= ~(2 << num); + if (drv->state) + gui_ledstate |= 2 << num; + gui_led (num + 1, gui_data.drive_motor[num]); +} + +static void drive_fill_bigbuf (drive * drv,int); + +struct zfile *DISK_validate_filename (const char *fname, int leave_open, int *wrprot) +{ + struct zfile *f = zfile_fopen (fname, "r+b"); + if (f) { + if (wrprot) + *wrprot = 0; + } else { + if (wrprot) + *wrprot = 1; + f = zfile_fopen (fname, "rb"); + } + if (!leave_open) + zfile_fclose (f); + return f; +} + +static void updatemfmpos (drive *drv) +{ + if (drv->prevtracklen) + drv->mfmpos = drv->mfmpos * (drv->tracklen * 1000 / drv->prevtracklen) / 1000; + drv->mfmpos %= drv->tracklen; + drv->prevtracklen = drv->tracklen; +} + +static void track_reset (drive *drv) +{ + drv->tracklen = FLOPPY_WRITE_LEN * drv->ddhd * 2 * 8; + drv->trackspeed = get_floppy_speed (); + drv->revolutions = 0; + drv->tracklengths[0] = drv->tracklen; + drv->current_revolution = 0; + drv->trackpointers[0] = drv->bigmfmbuf; + drv->buffered_side = -1; + free (drv->tracktiming); + drv->tracktiming = 0; + memset (drv->bigmfmbuf, 0xaa, FLOPPY_WRITE_LEN * 2 * drv->ddhd); + updatemfmpos (drv); +} + +static int read_header_ext2 (struct zfile *diskfile, trackid *trackdata, int *num_tracks, int *ddhd) +{ + uae_u8 buffer[2 + 2 + 4 + 4]; + trackid *tid; + int offs; + int i; + + zfile_fseek (diskfile, 0, SEEK_SET); + zfile_fread (buffer, 1, 8, diskfile); + if (strncmp (buffer, "UAE-1ADF", 8)) + return 0; + zfile_fread (buffer, 1, 4, diskfile); + *num_tracks = buffer[2] * 256 + buffer[3]; + offs = 8 + 2 + 2 + (*num_tracks) * (2 + 2 + 4 + 4); + + for (i = 0; i < (*num_tracks); i++) { + tid = trackdata + i; + zfile_fread (buffer, 2 + 2 + 4 + 4, 1, diskfile); + tid->type = buffer[2] * 256 + buffer[3]; + tid->len = buffer[5] * 65536 + buffer[6] * 256 + buffer[7]; + tid->bitlen = buffer[9] * 65536 + buffer[10] * 256 + buffer[11]; + tid->offs = offs; + if (tid->len > 20000 && ddhd) + *ddhd = 2; + tid->track = i; + offs += tid->len; + } + return 1; +} + +static char *getwritefilename (const char *name) +{ + static char name1[1024]; + char name2[1024]; + int i; + + strcpy (name2, name); + i = strlen (name2) - 1; + while (i > 0) { + if (name2[i] == '.') { + name2[i] = 0; + break; + } + i--; + } + while (i > 0) { + if (name2[i] == '/' || name2[i] == '\\') { + i++; + break; + } + i--; + } + sprintf (name1, "%sSaveImages%c%s_save.adf", start_path, FSDB_DIR_SEPARATOR, name2 + i); + return name1; +} + +static struct zfile *getwritefile (const char *name, int *wrprot) +{ + return DISK_validate_filename (getwritefilename (name), 1, wrprot); +} + +static int iswritefileempty (const char *name) +{ + struct zfile *zf; + int wrprot; + uae_u8 buffer[8]; + trackid td[MAX_TRACKS]; + int tracks, ddhd, i, ret; + + zf = getwritefile (name, &wrprot); + if (!zf) return 1; + zfile_fread (buffer, sizeof (char), 8, zf); + if (strncmp ((char *) buffer, "UAE-1ADF", 8)) + return 0; + ret = read_header_ext2 (zf, td, &tracks, &ddhd); + zfile_fclose (zf); + if (!ret) + return 1; + for (i = 0; i < tracks; i++) { + if (td[i].bitlen) return 0; + } + return 1; +} + +static int openwritefile (drive *drv, int create) +{ + int wrprot = 0; + + drv->writediskfile = getwritefile (currprefs.df[drv - &floppy[0]], &wrprot); + if (drv->writediskfile) { + drv->wrprot = wrprot; + if (!read_header_ext2 (drv->writediskfile, drv->writetrackdata, &drv->write_num_tracks, 0)) { + zfile_fclose (drv->writediskfile); + drv->writediskfile = 0; + drv->wrprot = 1; + } else { + if (drv->write_num_tracks > drv->num_tracks) + drv->num_tracks = drv->write_num_tracks; + } + } else if (zfile_iscompressed (drv->diskfile)) { + drv->wrprot = 1; + } + return drv->writediskfile ? 1 : 0; +} + +static int diskfile_iswriteprotect (const char *fname, int *needwritefile, drive_type *drvtype) +{ + struct zfile *zf1, *zf2; + int wrprot1 = 0, wrprot2 = 1; + unsigned char buffer[25]; + + *needwritefile = 0; + *drvtype = DRV_35_DD; + zf1 = DISK_validate_filename (fname, 1, &wrprot1); + if (!zf1) return 1; + if (zfile_iscompressed (zf1)) { + wrprot1 = 1; + *needwritefile = 1; + } + zf2 = getwritefile (fname, &wrprot2); + zfile_fclose (zf2); + zfile_fread (buffer, sizeof (char), 25, zf1); + zfile_fclose (zf1); + if (strncmp ((char *) buffer, "CAPS", 4) == 0) { + *needwritefile = 1; + return wrprot2; + } + if (strncmp ((char *) buffer, "Formatted Disk Image file", 25) == 0) { + *needwritefile = 1; + return wrprot2; + } + if (strncmp ((char *) buffer, "UAE-1ADF", 8) == 0) { + if (wrprot1) + return wrprot2; + return wrprot1; + } + if (strncmp ((char *) buffer, "UAE--ADF", 8) == 0) { + *needwritefile = 1; + return wrprot2; + } + if (memcmp (exeheader, buffer, sizeof(exeheader)) == 0) + return 0; + if (wrprot1) + return wrprot2; + return wrprot1; +} + +static int drive_insert (drive * drv, int dnum, const char *fname) +{ + unsigned char buffer[2 + 2 + 4 + 4]; + trackid *tid; + int num_tracks; + + drive_image_free (drv); + drv->diskfile = DISK_validate_filename (fname, 1, &drv->wrprot); + drv->ddhd = 1; + drv->num_secs = 0; + drv->hard_num_cyls = currprefs.dfxtype[dnum] == DRV_525_SD ? 40 : 80; + free (drv->tracktiming); + drv->tracktiming = 0; + drv->useturbo = 0; + drv->indexoffset = 0; + + if (!drv->motoroff) { + drv->dskready_time = DSKREADY_TIME; + drv->dskready_down_time = 0; + } + + if (drv->diskfile == 0 && !drv->catweasel) { + track_reset (drv); + return 0; + } + strncpy (currprefs.df[dnum], fname, 255); + currprefs.df[dnum][255] = 0; + strncpy (changed_prefs.df[dnum], fname, 255); + changed_prefs.df[dnum][255] = 0; + gui_filename (dnum, fname); + + memset (buffer, 0, sizeof (buffer)); + if (drv->diskfile) + zfile_fread (buffer, sizeof (char), 8, drv->diskfile); + + if (drv->catweasel) { + + drv->wrprot = 1; + drv->filetype = ADF_CATWEASEL; + drv->num_tracks = 80; + drv->ddhd = 1; + +#ifdef CAPS + } else if (strncmp ((char *) buffer, "CAPS", 4) == 0) { + + drv->wrprot = 1; + if (!caps_loadimage (drv->diskfile, drv - floppy, &num_tracks)) { + zfile_fclose (drv->diskfile); + drv->diskfile = 0; + return 0; + } + drv->num_tracks = num_tracks; + drv->filetype = ADF_IPF; +#endif + } else if (drv->fdi = fdi2raw_header (drv->diskfile)) { + + drv->wrprot = 1; + drv->num_tracks = fdi2raw_get_last_track (drv->fdi); + drv->num_secs = fdi2raw_get_num_sector (drv->fdi); + drv->filetype = ADF_FDI; + + } else if (strncmp ((char *) buffer, "UAE-1ADF", 8) == 0) { + + read_header_ext2 (drv->diskfile, drv->trackdata, &drv->num_tracks, &drv->ddhd); + drv->filetype = ADF_EXT2; + drv->num_secs = 11; + if (drv->ddhd > 1) + drv->num_secs = 22; + + } else if (strncmp ((char *) buffer, "UAE--ADF", 8) == 0) { + int offs = 160 * 4 + 8; + int i; + + drv->wrprot = 1; + drv->filetype = ADF_EXT1; + drv->num_tracks = 160; + drv->num_secs = 11; + + for (i = 0; i < 160; i++) { + tid = &drv->trackdata[i]; + zfile_fread (buffer, 4, 1, drv->diskfile); + tid->sync = buffer[0] * 256 + buffer[1]; + tid->len = buffer[2] * 256 + buffer[3]; + tid->offs = offs; + if (tid->sync == 0) { + tid->type = TRACK_AMIGADOS; + tid->bitlen = 0; + } else { + tid->type = TRACK_RAW1; + tid->bitlen = tid->len * 8; + } + offs += tid->len; + } + + } else if (memcmp (exeheader, buffer, sizeof(exeheader)) == 0) { + + int i; + struct zfile *z = zfile_fopen_empty ("", 512 * 1760); + createimagefromexe (drv->diskfile, z); + drv->filetype = ADF_NORMAL; + zfile_fclose (drv->diskfile); + drv->diskfile = z; + drv->num_tracks = 160; + drv->num_secs = 11; + for (i = 0; i < drv->num_tracks; i++) { + tid = &drv->trackdata[i]; + tid->type = TRACK_AMIGADOS; + tid->len = 512 * drv->num_secs; + tid->bitlen = 0; + tid->offs = i * 512 * drv->num_secs; + } + drv->useturbo = 1; + + } else { + int i; + + drv->filetype = ADF_NORMAL; + + zfile_fseek (drv->diskfile, 0, SEEK_END); + i = zfile_ftell (drv->diskfile); + zfile_fseek (drv->diskfile, 0, SEEK_SET); + + /* High-density disk? */ + if (i >= 160 * 22 * 512) { + drv->num_tracks = i / (512 * (drv->num_secs = 22)); + drv->ddhd = 2; + } else + drv->num_tracks = i / (512 * (drv->num_secs = 11)); + + if (drv->num_tracks > MAX_TRACKS) + write_log ("Your diskfile is too big!\n"); + for (i = 0; i < drv->num_tracks; i++) { + tid = &drv->trackdata[i]; + tid->type = TRACK_AMIGADOS; + tid->len = 512 * drv->num_secs; + tid->bitlen = 0; + tid->offs = i * 512 * drv->num_secs; + } + } + openwritefile (drv, 0); + drive_settype_id(drv); /* Set DD or HD drive */ + drive_fill_bigbuf (drv, 1); + drv->mfmpos = (rand () | (rand () << 16)) % drv->tracklen; + drv->prevtracklen = 0; +#ifdef DRIVESOUND + driveclick_insert (drv - floppy, 0); +#endif + return 1; +} + +static void rand_shifter (drive *drv) +{ + int r = ((rand () >> 4) & 7) + 1; + while (r-- > 0) { + word <<= 1; + word |= (rand () & 0x1000) ? 1 : 0; + bitoffset++; + bitoffset &= 15; + } +} + +static int drive_empty (drive * drv) +{ +#ifdef CATWEASEL + if (drv->catweasel) + return catweasel_disk_changed (drv->catweasel) == 0; +#endif + return drv->diskfile == 0; +} + +static void drive_step (drive * drv) +{ +#if 0 + if (drv->dskready) { + drv->dskready = 0; + drv->dskready_time = DSKREADY_TIME; + } +#endif +#ifdef CATWEASEL + if (drv->catweasel) { + int dir = direction ? -1 : 1; + catweasel_step (drv->catweasel, dir); + drv->cyl += dir; + if (drv->cyl < 0) + drv->cyl = 0; + write_log ("%d -> %d\n", dir, drv->cyl); + return; + } +#endif + if (drv->steplimit) { +#ifdef DISK_DEBUG2 + write_dlog (" step ignored"); +#endif + return; + } + /* A1200's floppy drive needs at least 30 raster lines between steps + * but we'll use very small value for better compatibility with faster CPU emulation + * (stupid trackloaders with CPU delay loops) + */ + drv->steplimit = 2; + if (!drive_empty (drv)) + drv->dskchange = 0; + if (direction) { + if (drv->cyl) { + drv->cyl--; +#ifdef DRIVESOUND + driveclick_click (drv - floppy, drv->cyl); +#endif + } +/* else + write_log("program tried to step beyond track zero\n"); + "no-click" programs does that +*/ + } else { + int maxtrack = drv->hard_num_cyls; + if (drv->cyl < maxtrack + 3) { + drv->cyl++; +#ifdef CATWEASEL + if (drv->catweasel) + catweasel_step (drv->catweasel, 1); +#endif + } + if (drv->cyl >= maxtrack) + write_dlog ("program tried to step over track %d\n", maxtrack); +#ifdef DRIVESOUND + driveclick_click (drv - floppy, drv->cyl); +#endif + } + rand_shifter (drv); +#ifdef DISK_DEBUG2 + write_dlog (" ->step %d", drv->cyl); +#endif +} + +static int drive_track0 (drive * drv) +{ +#ifdef CATWEASEL + if (drv->catweasel) + return catweasel_track0 (drv->catweasel); +#endif + return drv->cyl == 0; +} + +static int drive_writeprotected (drive * drv) +{ +#ifdef CATWEASEL + if (drv->catweasel) + return 1; +#endif + return drv->wrprot || drv->diskfile == NULL; +} + +static int drive_running (drive * drv) +{ + return !drv->motoroff; +} + +static void drive_motor (drive * drv, int off) +{ + if (drv->motoroff && !off) { + drv->dskready_time = DSKREADY_TIME; + rand_shifter (drv); +#ifdef DRIVESOUND + driveclick_motor (drv - floppy, drv->dskready_down_time == 0 ? 2 : 1); +#endif +#ifdef DISK_DEBUG2 + write_dlog (" ->motor on"); +#endif + } + if (!drv->motoroff && off) { + drv->drive_id_scnt = 0; /* Reset id shift reg counter */ + drv->dskready_down_time = DSKREADY_DOWN_TIME; +#ifdef DRIVESOUND + driveclick_motor (drv - floppy, 0); +#endif +#ifdef DEBUG_DRIVE_ID + write_dlog("drive_motor: Selected DF%d: reset id shift reg.\n",drv-floppy); +#endif +#ifdef DISK_DEBUG2 + write_dlog (" ->motor off"); +#endif + } + drv->motoroff = off; + if (drv->motoroff) { + drv->dskready = 0; + drv->dskready_time = 0; + } +#ifdef CATWEASEL + if (drv->catweasel) + catweasel_set_motor (drv->catweasel, !drv->motoroff); +#endif +} + +static void read_floppy_data (struct zfile *diskfile, trackid *tid, int offset, unsigned char *dst, int len) +{ + if (len == 0) + return; + zfile_fseek (diskfile, tid->offs + offset, SEEK_SET); + zfile_fread (dst, 1, len, diskfile); +} + +/* Megalomania does not like zero MFM words... */ +static void mfmcode (uae_u16 * mfm, int words) +{ + uae_u32 lastword = 0; + + while (words--) { + uae_u32 v = *mfm; + uae_u32 lv = (lastword << 16) | v; + uae_u32 nlv = 0x55555555 & ~lv; + uae_u32 mfmbits = (nlv << 1) & (nlv >> 1); + + *mfm++ = v | mfmbits; + lastword = v; + } +} + +static void drive_fill_bigbuf (drive * drv, int force) +{ + int tr = drv->cyl * 2 + side; + trackid *ti = drv->trackdata + tr; + + if ((!drv->diskfile && !drv->catweasel) || tr >= drv->num_tracks) { + track_reset (drv); + return; + } + + if (!force && drv->catweasel) { + drv->buffered_cyl = -1; + return; + } + + if (!force && drv->buffered_cyl == drv->cyl && drv->buffered_side == side) + return; + drv->revolutions = 0; + drv->indexoffset = 0; + free (drv->tracktiming); + drv->tracktiming = 0; + + if (drv->writediskfile && drv->writetrackdata[tr].bitlen > 0) { + int i; + trackid *wti = &drv->writetrackdata[tr]; + drv->tracklen = wti->bitlen; + read_floppy_data (drv->writediskfile, wti, 0, (char *) drv->bigmfmbuf, (wti->bitlen + 7) / 8); + for (i = 0; i < (drv->tracklen + 15) / 16; i++) { + uae_u16 *mfm = drv->bigmfmbuf + i; + uae_u8 *data = (uae_u8 *) mfm; + *mfm = 256 * *data + *(data + 1); + } +#ifdef DISK_DEBUG + write_log ("track %d, length %d read from \"saveimage\"\n", tr, drv->tracklen); +#endif + } else if (drv->filetype == ADF_CATWEASEL) { +#ifdef CATWEASEL + drv->tracklen = 0; + if (!catweasel_disk_changed (drv->catweasel)) { + drv->tracklen = catweasel_fillmfm (drv->catweasel, drv->bigmfmbuf, side, drv->ddhd, 0); + } + drv->buffered_cyl = -1; + if (!drv->tracklen) { + track_reset (drv); + return; + } +#endif + } else if (drv->filetype == ADF_IPF) { + +#ifdef CAPS + caps_loadtrack (drv->bigmfmbuf, drv->trackpointers, &drv->tracktiming, drv - floppy, tr, drv->tracklengths, &drv->revolutions); + drv->tracklen = drv->tracklengths[0]; +#endif + + } else if (drv->filetype == ADF_FDI) { + + fdi2raw_loadtrack (drv->fdi, drv->bigmfmbuf, drv->trackpointers, &drv->tracktiming, tr, drv->tracklengths, &drv->revolutions, &drv->indexoffset); + drv->tracklen = drv->tracklengths[0]; + + } else if (ti->type == TRACK_AMIGADOS) { + + /* Normal AmigaDOS format track */ + int sec; + int dstmfmoffset = 0; + uae_u16 *dstmfmbuf = drv->bigmfmbuf; + int len = drv->num_secs * 544 + FLOPPY_GAP_LEN; + + memset (dstmfmbuf, 0xaa, len * 2); + dstmfmoffset += FLOPPY_GAP_LEN; + drv->tracklen = len * 2 * 8; + + for (sec = 0; sec < drv->num_secs; sec++) { + uae_u8 secbuf[544]; + uae_u16 mfmbuf[544]; + int i; + uae_u32 deven, dodd; + uae_u32 hck = 0, dck = 0; + + secbuf[0] = secbuf[1] = 0x00; + secbuf[2] = secbuf[3] = 0xa1; + secbuf[4] = 0xff; + secbuf[5] = tr; + secbuf[6] = sec; + secbuf[7] = drv->num_secs - sec; + + for (i = 8; i < 24; i++) + secbuf[i] = 0; + + read_floppy_data (drv->diskfile, ti, sec * 512, &secbuf[32], 512); + + mfmbuf[0] = mfmbuf[1] = 0xaaaa; + mfmbuf[2] = mfmbuf[3] = 0x4489; + + deven = ((secbuf[4] << 24) | (secbuf[5] << 16) + | (secbuf[6] << 8) | (secbuf[7])); + dodd = deven >> 1; + deven &= 0x55555555; + dodd &= 0x55555555; + + mfmbuf[4] = dodd >> 16; + mfmbuf[5] = dodd; + mfmbuf[6] = deven >> 16; + mfmbuf[7] = deven; + + for (i = 8; i < 48; i++) + mfmbuf[i] = 0xaaaa; + for (i = 0; i < 512; i += 4) { + deven = ((secbuf[i + 32] << 24) | (secbuf[i + 33] << 16) + | (secbuf[i + 34] << 8) | (secbuf[i + 35])); + dodd = deven >> 1; + deven &= 0x55555555; + dodd &= 0x55555555; + mfmbuf[(i >> 1) + 32] = dodd >> 16; + mfmbuf[(i >> 1) + 33] = dodd; + mfmbuf[(i >> 1) + 256 + 32] = deven >> 16; + mfmbuf[(i >> 1) + 256 + 33] = deven; + } + + for (i = 4; i < 24; i += 2) + hck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1]; + + deven = dodd = hck; + dodd >>= 1; + mfmbuf[24] = dodd >> 16; + mfmbuf[25] = dodd; + mfmbuf[26] = deven >> 16; + mfmbuf[27] = deven; + + for (i = 32; i < 544; i += 2) + dck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1]; + + deven = dodd = dck; + dodd >>= 1; + mfmbuf[28] = dodd >> 16; + mfmbuf[29] = dodd; + mfmbuf[30] = deven >> 16; + mfmbuf[31] = deven; + mfmcode (mfmbuf + 4, 544 - 4); + + for (i = 0; i < 544; i++) { + dstmfmbuf[dstmfmoffset % len] = mfmbuf[i]; + dstmfmoffset++; + } + + } + +#ifdef DISK_DEBUG + write_log ("amigados read track %d\n", tr); +#endif + } else { + int i; + int base_offset = ti->type == TRACK_RAW ? 0 : 1; + drv->tracklen = ti->bitlen + 16 * base_offset; + drv->bigmfmbuf[0] = ti->sync; + read_floppy_data (drv->diskfile, ti, 0, (char *) (drv->bigmfmbuf + base_offset), (ti->bitlen + 7) / 8); + for (i = base_offset; i < (drv->tracklen + 15) / 16; i++) { + uae_u16 *mfm = drv->bigmfmbuf + i; + uae_u8 *data = (uae_u8 *) mfm; + *mfm = 256 * *data + *(data + 1); + } +#if 0 && defined DISK_DEBUG + write_log ("rawtrack %d\n", tr); +#endif + } + drv->current_revolution = 0; + drv->tracklengths[0] = drv->tracklen; + drv->trackpointers[0] = drv->bigmfmbuf; + drv->buffered_side = side; + drv->buffered_cyl = drv->cyl; + if (drv->tracklen == 0) { + drv->tracklengths[0] = drv->tracklen = FLOPPY_WRITE_LEN * drv->ddhd * 2 * 8; + memset (drv->bigmfmbuf, 0, FLOPPY_WRITE_LEN * 2 * drv->ddhd); + } + drv->trackspeed = get_floppy_speed () * drv->tracklen / (2 * 8 * FLOPPY_WRITE_LEN * drv->ddhd); + updatemfmpos (drv); +} + +/* Update ADF_EXT2 track header */ +static void diskfile_update (struct zfile *diskfile, trackid *ti, int len, uae_u8 type) +{ + uae_u8 buf[2 + 2 + 4 + 4], *zerobuf; + + ti->bitlen = len; + zfile_fseek (diskfile, 8 + 4 + (2 + 2 + 4 + 4) * ti->track, SEEK_SET); + memset (buf, 0, sizeof buf); + ti->type = type; + buf[3] = ti->type; + do_put_mem_long ((uae_u32 *) (buf + 4), ti->len); + do_put_mem_long ((uae_u32 *) (buf + 8), ti->bitlen); + zfile_fwrite (buf, sizeof (buf), 1, diskfile); + if (ti->len > (len + 7) / 8) { + zerobuf = malloc (ti->len); + memset (zerobuf, 0, ti->len); + zfile_fseek (diskfile, ti->offs, SEEK_SET); + zfile_fwrite (zerobuf, 1, ti->len, diskfile); + free (zerobuf); + } +#ifdef DISK_DEBUG + write_log ("track %d, raw track length %d written (total size %d)\n", ti->track, (ti->bitlen + 7) / 8, ti->len); +#endif +} + +#define MFMMASK 0x55555555 +static uae_u32 getmfmlong (uae_u16 * mbuf) +{ + return ((*mbuf << 16) | *(mbuf + 1)) & MFMMASK; +} + +static int drive_write_adf_amigados (drive * drv) +{ + int i, secwritten = 0; + int fwlen = FLOPPY_WRITE_LEN * drv->ddhd; + int length = 2 * fwlen; + int drvsec = drv->num_secs; + uae_u32 odd, even, chksum, id, dlong; + uae_u8 *secdata; + uae_u8 secbuf[544]; + uae_u16 *mbuf = drv->bigmfmbuf; + uae_u16 *mend = mbuf + length; + char sectable[22]; + + if (!drvsec) + return 2; + memset (sectable, 0, sizeof (sectable)); + memcpy (mbuf + fwlen, mbuf, fwlen * sizeof (uae_u16)); + mend -= (4 + 16 + 8 + 512); + while (secwritten < drvsec) { + int trackoffs; + + do { + while (*mbuf++ != 0x4489) { + if (mbuf >= mend) + return 1; + } + } while (*mbuf++ != 0x4489); + + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 2); + mbuf += 4; + id = (odd << 1) | even; + + trackoffs = (id & 0xff00) >> 8; + if (trackoffs + 1 > drvsec) { + write_log ("Disk write: weird sector number %d\n", trackoffs); + if (drv->filetype == ADF_EXT2) + return 2; + continue; + } + chksum = odd ^ even; + for (i = 0; i < 4; i++) { + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 8); + mbuf += 2; + + dlong = (odd << 1) | even; + if (dlong) { + if (drv->filetype == ADF_EXT2) + return 6; + secwritten = -200; + } + chksum ^= odd ^ even; + } /* could check here if the label is nonstandard */ + mbuf += 8; + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 2); + mbuf += 4; + if (((odd << 1) | even) != chksum || ((id & 0x00ff0000) >> 16) != drv->cyl * 2 + side) { + write_log ("Disk write: checksum error on sector %d header\n", trackoffs); + if (drv->filetype == ADF_EXT2) + return 3; + continue; + } + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 2); + mbuf += 4; + chksum = (odd << 1) | even; + secdata = secbuf + 32; + for (i = 0; i < 128; i++) { + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 256); + mbuf += 2; + dlong = (odd << 1) | even; + *secdata++ = dlong >> 24; + *secdata++ = dlong >> 16; + *secdata++ = dlong >> 8; + *secdata++ = dlong; + chksum ^= odd ^ even; + } + mbuf += 256; + if (chksum) { + write_log ("Disk write: sector %d, data checksum error\n", trackoffs); + if (drv->filetype == ADF_EXT2) + return 4; + continue; + } + sectable[trackoffs] = 1; + secwritten++; + memcpy (writebuffer + trackoffs * 512, secbuf + 32, 512); + } + if (drv->filetype == ADF_EXT2 && (secwritten == 0 || secwritten < 0)) + return 5; + if (secwritten == 0) + write_log ("Disk write in unsupported format\n"); + if (secwritten < 0) + write_log ("Disk write: sector labels ignored\n"); + + if (drv->filetype == ADF_EXT2) + diskfile_update (drv->diskfile, &drv->trackdata[drv->cyl * 2 + side], drvsec * 512 * 8, TRACK_AMIGADOS); + for (i = 0; i < drvsec; i++) { + zfile_fseek (drv->diskfile, drv->trackdata[drv->cyl * 2 + side].offs + i * 512, SEEK_SET); + zfile_fwrite (writebuffer + i * 512, sizeof (uae_u8), 512, drv->diskfile); + } + + return 0; +} + +/* write raw track to disk file */ +static int drive_write_ext2 (uae_u16 *bigmfmbuf, struct zfile *diskfile, trackid *ti, int tracklen) +{ + int len, i; + + len = (tracklen + 7) / 8; + if (len > ti->len) { + write_log ("disk raw write: image file's track %d is too small (%d < %d)!\n", ti->track, ti->len, len); + return 0; + } + diskfile_update (diskfile, ti, tracklen, TRACK_RAW); + for (i = 0; i < ti->len / 2; i++) { + uae_u16 *mfm = bigmfmbuf + i; + uae_u16 *mfmw = bigmfmbufw + i; + uae_u8 *data = (uae_u8 *) mfm; + *mfmw = 256 * *data + *(data + 1); + } + zfile_fseek (diskfile, ti->offs, SEEK_SET); + zfile_fwrite (bigmfmbufw, 1, len, diskfile); + return 1; +} + +static void drive_write_data (drive * drv) +{ + int ret; + if (drive_writeprotected (drv)) { + /* read original track back because we didn't really write anything */ + drv->buffered_side = 2; + return; + } + if (drv->writediskfile) + drive_write_ext2 (drv->bigmfmbuf, drv->writediskfile, &drv->writetrackdata[drv->cyl * 2 + side], drv->tracklen); + + switch (drv->filetype) { + case ADF_NORMAL: + drive_write_adf_amigados (drv); + return; + case ADF_EXT1: + break; + case ADF_EXT2: + ret = drive_write_adf_amigados (drv); + if (ret) { + write_log("not an amigados track (error %d), writing as raw track\n",ret); + drive_write_ext2 (drv->bigmfmbuf, drv->diskfile, &drv->trackdata[drv->cyl * 2 + side], drv->tracklen); + } + return; + case ADF_IPF: + break; + } + free (drv->tracktiming); + drv->tracktiming = 0; +} + +static void drive_eject (drive * drv) +{ +#ifdef DRIVESOUND + driveclick_insert (drv - floppy, 1); +#endif + drive_image_free (drv); + drv->dskchange = 1; + drv->ddhd = 1; + drv->dskchange_time = 0; + drv->dskready = 0; + drv->dskready_time = 0; + drv->dskready_down_time = 0; + drive_settype_id(drv); /* Back to 35 DD */ +#ifdef DISK_DEBUG + write_dlog ("eject drive %d\n", drv - &floppy[0]); +#endif +} + +/* We use this function if we have no Kickstart ROM. + * No error checking - we trust our luck. */ +void DISK_ersatz_read (int tr, int sec, uaecptr dest) +{ + uae_u8 *dptr = get_real_address (dest); + zfile_fseek (floppy[0].diskfile, floppy[0].trackdata[tr].offs + sec * 512, SEEK_SET); + zfile_fread (dptr, 1, 512, floppy[0].diskfile); +} + +/* type: 0=regular, 1=ext2adf */ +/* adftype: 0=DD,1=HD,2=525SD */ +void disk_creatediskfile (char *name, int type, drive_type adftype) +{ + struct zfile *f; + int i, l, file_size, tracks, track_len; + char *chunk = NULL; + uae_u8 tmp[3*4]; + char *disk_name = "empty"; + + if (type == 1) tracks = 2 * 83; else tracks = 2 * 80; + file_size = 880 * 1024; + track_len = FLOPPY_WRITE_LEN * 2; + if (adftype == 1) { + file_size *= 2; + track_len *= 2; + } else if (adftype == 2) { + file_size /= 2; + tracks /= 2; + } + + f = zfile_fopen (name, "wb"); + chunk = xmalloc (16384); + if (f && chunk) { + memset(chunk,0,16384); + switch(type) + { + case 0: + for (i = 0; i < file_size; i += 11264) { + memset(chunk, 0, 11264); + if (i == 0) { + /* boot block */ + strcpy (chunk, "DOS"); + } else if (i == file_size / 2) { + int block = file_size / 1024; + /* root block */ + chunk[0+3] = 2; + chunk[12+3] = 0x48; + chunk[312] = chunk[313] = chunk[314] = chunk[315] = (uae_u8)0xff; + chunk[316+2] = (block + 1) >> 8; chunk[316+3] = (block + 1) & 255; + chunk[432] = strlen (disk_name); + strcpy (chunk + 433, disk_name); + chunk[508 + 3] = 1; + disk_date (chunk + 420); + memcpy (chunk + 472, chunk + 420, 3 * 4); + memcpy (chunk + 484, chunk + 420, 3 * 4); + disk_checksum(chunk, chunk + 20); + /* bitmap block */ + memset (chunk + 512 + 4, 0xff, 220); + chunk[512 + 112 + 2] = 0x3f; + disk_checksum(chunk + 512, chunk + 512); + + } + zfile_fwrite (chunk, 11264, 1, f); + } + break; + case 1: + l = track_len; + zfile_fwrite ("UAE-1ADF", 8, 1, f); + tmp[0] = 0; tmp[1] = 0; /* flags (reserved) */ + tmp[2] = 0; tmp[3] = tracks; /* number of tracks */ + zfile_fwrite (tmp, 4, 1, f); + tmp[0] = 0; tmp[1] = 0; /* flags (reserved) */ + tmp[2] = 0; tmp[3] = 1; /* track type */ + tmp[4] = 0; tmp[5] = 0; tmp[6]=(uae_u8)(l >> 8); tmp[7] = (uae_u8)l; + tmp[8] = 0; tmp[9] = 0; tmp[10] = 0; tmp[11] = 0; + for (i = 0; i < tracks; i++) zfile_fwrite (tmp, sizeof (tmp), 1, f); + for (i = 0; i < tracks; i++) zfile_fwrite (chunk, l, 1, f); + break; + } + } + free (chunk); + zfile_fclose (f); +} + +int disk_getwriteprotect (const char *name) +{ + int needwritefile; + drive_type drvtype; + return diskfile_iswriteprotect (name, &needwritefile, &drvtype); +} + +static void diskfile_readonly (const char *name, int readonly) +{ + struct stat st; + int mode, oldmode; + + if (stat (name, &st)) + return; + oldmode = mode = st.st_mode; + mode &= ~FILEFLAG_WRITE; + if (!readonly) mode |= FILEFLAG_WRITE; + if (mode != oldmode) + chmod (name, mode); +} + +static void setdskchangetime(drive *drv, int dsktime) +{ + int i; + /* prevent multiple disk insertions at the same time */ + if (drv->dskchange_time > 0) + return; + for (i = 0; i < 4; i++) { + if (&floppy[i] != drv && floppy[i].dskchange_time > 0 && floppy[i].dskchange_time + 5 >= dsktime) { + dsktime = floppy[i].dskchange_time + 5; + } + } + drv->dskchange_time = dsktime; +} + +int disk_setwriteprotect (int num, const char *name, int protect) +{ + int needwritefile, oldprotect; + struct zfile *zf1, *zf2; + int wrprot1, wrprot2, i; + char *name2; + drive_type drvtype; + + oldprotect = diskfile_iswriteprotect (name, &needwritefile, &drvtype); + zf1 = DISK_validate_filename (name, 1, &wrprot1); + if (!zf1) return 0; + if (zfile_iscompressed (zf1)) wrprot1 = 1; + zf2 = getwritefile (name, &wrprot2); + name2 = getwritefilename (name); + + if (needwritefile && zf2 == 0) + disk_creatediskfile (name2, 1, drvtype); + zfile_fclose (zf2); + if (protect && iswritefileempty (name)) { + for (i = 0; i < 4; i++) { + if (!strcmp (name, floppy[i].newname)) + drive_eject (&floppy[i]); + } + unlink (name2); + } + + if (!needwritefile) + diskfile_readonly (name, protect); + diskfile_readonly (name2, protect); + drive_eject (&floppy[num]); + setdskchangetime (&floppy[num], 20); + return 1; +} + +void disk_eject (int num) +{ + gui_filename (num, ""); + drive_eject (floppy + num); + *currprefs.df[num] = *changed_prefs.df[num] = 0; + floppy[num].newname[0] = 0; +} + +void DISK_history_add (const char *name, int idx) +{ + int i; + + if (idx >= 0) { + if (idx >= MAX_PREVIOUS_FLOPPIES) + return; + strcpy (dfxhistory[idx], name); + return; + } + if (name[0] == 0) + return; + for (i = 0; i < MAX_PREVIOUS_FLOPPIES; i++) { + if (!strcmp (dfxhistory[i], name)) { + while (i < MAX_PREVIOUS_FLOPPIES - 1) { + strcpy (dfxhistory[i], dfxhistory[i + 1]); + i++; + } + dfxhistory[MAX_PREVIOUS_FLOPPIES - 1][0] = 0; + break; + } + } + for (i = MAX_PREVIOUS_FLOPPIES - 2; i >= 0; i--) + strcpy (dfxhistory[i + 1], dfxhistory[i]); + strcpy (dfxhistory[0], name); +} + +char *DISK_history_get (int idx) +{ + if (idx >= MAX_PREVIOUS_FLOPPIES) + return 0; + if (dfxhistory[idx][0] == 0) + return 0; + return dfxhistory[idx]; +} + +void disk_insert (int num, const char *name) +{ + drive *drv = floppy + num; + strcpy (drv->newname, name); + strcpy (currprefs.df[num], name); + DISK_history_add (name, -1); + if (name[0] == 0) { + disk_eject (num); + } else if (!drive_empty(drv) || drv->dskchange_time > 0) { + drive_eject (drv); + /* set dskchange_time, disk_insert() will be + * called from DISK_check_change() after 2 second delay + * this makes sure that all programs detect disk change correctly + */ + setdskchangetime (drv, 20); + } else { + setdskchangetime (drv, 1); + } +} + +void DISK_check_change (void) +{ + int i; + + if (currprefs.floppy_speed != changed_prefs.floppy_speed) + currprefs.floppy_speed = changed_prefs.floppy_speed; + for (i = 0; i < 4; i++) { + drive *drv = floppy + i; + gui_lock (); + if (currprefs.dfxtype[i] != changed_prefs.dfxtype[i]) { + currprefs.dfxtype[i] = changed_prefs.dfxtype[i]; + reset_drive (i); + } + if (strcmp (currprefs.df[i], changed_prefs.df[i])) { + strcpy (currprefs.df[i], changed_prefs.df[i]); + disk_insert (i, currprefs.df[i]); + } + gui_unlock (); + if (drv->dskready_down_time > 0) + drv->dskready_down_time--; +#if 1 + /* emulate drive motor turn on time */ + if (drv->dskready_time) { + drv->dskready_time--; + if (drv->dskready_time == 0) + drv->dskready = 1; + } +#endif + /* delay until new disk image is inserted */ + if (drv->dskchange_time) { + drv->dskchange_time--; + if (drv->dskchange_time == 0) { + drive_insert (drv, i, drv->newname); +#ifdef DISK_DEBUG + write_dlog ("delayed insert, drive %d, image '%s'\n", i, drv->newname); +#endif + } + } + } +} + +int disk_empty (int num) +{ + return drive_empty (floppy + num); +} + +#ifdef DISK_DEBUG2 +static char *tobin(uae_u8 v) +{ + int i; + static char buf[10]; + for( i = 7; i >= 0; i--) + buf[7 - i] = v & (1 << i) ? '1' : '0'; + buf[i] = 0; + return buf; +} +#endif + +void DISK_select (uae_u8 data) +{ + int step_pulse, lastselected, dr; + static uae_u8 prevdata; + static int step; + +#ifdef DISK_DEBUG2 + write_dlog ("%08.8X %02.2X %s", m68k_getpc(), data, tobin(data)); +#endif + lastselected = selected; + selected = (data >> 3) & 15; + side = 1 - ((data >> 2) & 1); + direction = (data >> 1) & 1; + step_pulse = data & 1; + +#ifdef DISK_DEBUG2 + write_dlog (" %d%d%d%d% ", (selected & 1) ? 0 : 1, (selected & 2) ? 0 : 1, (selected & 4) ? 0 : 1, (selected & 8) ? 0 : 1); + if ((prevdata & 0x80) != (data & 0x80)) + write_dlog (" dskmotor %d ", (data & 0x80) ? 1 : 0); + if ((prevdata & 0x02) != (data & 0x02)) + write_dlog (" direct %d ", (data & 0x02) ? 1 : 0); + if ((prevdata & 0x04) != (data & 0x04)) + write_dlog (" side %d ", (data & 0x04) ? 1 : 0); +#endif + + selected |= disabled; + + if (step != step_pulse) { +#ifdef DISK_DEBUG2 + write_dlog (" dskstep %d ", step_pulse); +#endif + step = step_pulse; + if (step && !savestate_state) { + for (dr = 0; dr < 4; dr++) { + if (!(selected & (1 << dr))) { + drive_step (floppy + dr); + } + } + } + } + if (!savestate_state) { + for (dr = 0; dr < 4; dr++) { + drive *drv = floppy + dr; + /* motor on/off workings tested with small assembler code on real Amiga 1200. */ + /* motor/id flipflop is set only when drive select goes from high to low */ + if (!(selected & (1 << dr)) && (lastselected & (1 << dr)) ) { + drv->drive_id_scnt++; + drv->drive_id_scnt &= 31; + drv->idbit = (drv->drive_id & (1L << (31 - drv->drive_id_scnt))) ? 1 : 0; + if ((prevdata & 0x80) == 0 || (data & 0x80) == 0) { + /* motor off: if motor bit = 0 in prevdata or data -> turn motor on */ + drive_motor (drv, 0); + } else if (prevdata & 0x80) { + /* motor on: if motor bit = 1 in prevdata only (motor flag state in data has no effect) + -> turn motor off */ + drive_motor (drv, 1); + } + if (currprefs.dfxtype[dr] == DRV_35_DD) { + if (dr == 0) /* A500/A2000 internal drive always returns 0 */ + drv->idbit = 0; + else /* regular external DD drive always returns 1 */ + drv->idbit = 1; + } +#ifdef DEBUG_DRIVE_ID + write_dlog("DISK_status: sel %d id %s (%08.8X) [0x%08lx, bit #%02d: %d]\n", + dr, drive_id_name(drv), drv->drive_id, drv->drive_id << drv->drive_id_scnt, 31 - drv->drive_id_scnt, drv->idbit); +#endif + } + } + } + for (dr = 0; dr < 4; dr++) { + floppy[dr].state = (!(selected & (1 << dr))) | !floppy[dr].motoroff; + update_drive_gui (dr); + } + prevdata = data; +#ifdef DISK_DEBUG2 + write_log ("\n"); +#endif +} + +uae_u8 DISK_status (void) +{ + uae_u8 st = 0x3c; + int dr; + + for (dr = 0; dr < 4; dr++) { + drive *drv = floppy + dr; + if (!(selected & (1 << dr))) { + if (drive_running (drv)) { + if (drv->catweasel) { +#ifdef CATWEASEL + if (catweasel_diskready (drv->catweasel)) + st &= ~0x20; +#endif + } else { + if (drv->dskready) + st &= ~0x20; + } + } else { + /* report drive ID */ + if (drv->idbit) + st &= ~0x20; +#if 0 + if (dr == 0 && currprefs.dfxtype[dr] == DRV_35_DD && + drv->motoroff && drv->motorcycle + CYCLE_UNIT * 1 > get_cycles()) + st &= ~0x20, write_log("x %d\n", get_cycles()); +#endif + } + if (drive_track0 (drv)) + st &= ~0x10; + if (drive_writeprotected (drv)) + st &= ~8; + if (drv->catweasel) { +#ifdef CATWEASEL + if (catweasel_disk_changed (drv->catweasel)) + st &= ~4; +#endif + } else if (drv->dskchange && currprefs.dfxtype[dr] != DRV_525_SD) { + st &= ~4; + } + } + } + return st; +} + +static int unformatted (drive *drv) +{ + int tr = drv->cyl * 2 + side; + if (tr >= drv->num_tracks) + return 1; + if (drv->filetype == ADF_EXT2 && drv->trackdata[tr].bitlen == 0) + return 1; + return 0; +} + +/* get one bit from MFM bit stream */ +STATIC_INLINE uae_u32 getonebit (uae_u16 * mfmbuf, int mfmpos) +{ + uae_u16 *buf; + + buf = &mfmbuf[mfmpos >> 4]; + return (buf[0] & (1 << (15 - (mfmpos & 15)))) ? 1 : 0; +} + +void dumpdisk (void) +{ + int i, j, k; + uae_u16 w; + + for (i = 0; i < 4; i++) { + drive *drv = &floppy[i]; + if (!(disabled & (1 << i))) { + write_log ("Drive %d: motor %s cylinder %2d sel %s %s mfmpos %d/%d\n", + i, drv->motoroff ? "off" : " on", drv->cyl, (selected & (1 << i)) ? "no" : "yes", + drive_writeprotected(drv) ? "ro" : "rw", drv->mfmpos, drv->tracklen); + w = word; + for (j = 0; j < 15; j++) { + write_log ("%04.4X ", w); + for (k = 0; k < 16; k++) { + w <<= 1; + w |= getonebit (drv->bigmfmbuf, drv->mfmpos + j * 16 + k); + } + } + write_log ("\n"); + } + } + write_log ("side %d, dma %d, bitoffset %d, word %04.4X, dskbytr %04.4X adkcon %04.4X dsksync %04.4X\n", side, dskdmaen, bitoffset, word, dskbytr_val, adkcon, dsksync); +} + +static void disk_dmafinished (void) +{ + INTREQ (0x8002); + dskdmaen = 0; +#ifdef DISK_DEBUG + write_dlog("disk dma finished %08.8X\n", dskpt); +#endif +} + +extern void cia_diskindex (void); + +static int diskevent_flag; +static int disk_sync_cycle; + +void DISK_handler (void) +{ + int i, flag = diskevent_flag; + eventtab[ev_disk].active = 0; + DISK_update (disk_sync_cycle); + if (flag & DISK_WORDSYNC) { + INTREQ (0x8000 | 0x1000); + } + if (flag & DISK_INDEXSYNC) { + cia_diskindex (); +#if 0 + for (i = 0; i < 4; i++) { + drive *drv = &floppy[i]; + if (drv->dskready_time) { + drv->dskready_time--; + if (drv->dskready_time == 0) { + drv->dskready = 1; +#ifdef DISK_DEBUG + write_log ("%d: %d\n", i, drv->mfmpos); +#endif + } + } + } +#endif + } +} + +static void disk_doupdate_write (drive * drv, int floppybits) +{ + int dr; + int drives[4]; + + for (dr = 0; dr < 4 ; dr++) { + drive *drv2 = &floppy[dr]; + drives[dr] = 0; + if (drv2->motoroff) + continue; + if (selected & (1 << dr)) + continue; + drives[dr] = 1; + } + + while (floppybits >= drv->trackspeed) { + for (dr = 0; dr < 4; dr++) { + if (drives[dr]) { + floppy[dr].mfmpos++; + floppy[dr].mfmpos %= drv->tracklen; + } + } + if ((dmacon & 0x210) == 0x210 && dskdmaen == 3 && dsklength > 0) { + bitoffset++; + bitoffset &= 15; + if (!bitoffset) { + for (dr = 0; dr < 4 ; dr++) { + drive *drv2 = &floppy[dr]; + if (drives[dr]) + drv2->bigmfmbuf[drv2->mfmpos >> 4] = get_word (dskpt); + } + dskpt += 2; + dsklength--; + if (dsklength == 0) { + disk_dmafinished (); + drive_write_data (drv); + } + } + } + floppybits -= drv->trackspeed; + } +} + +static void updatetrackspeed (drive *drv, int mfmpos) +{ + if (dskdmaen < 3) { + uae_u16 *p = drv->trackpointers[drv->current_revolution] - drv->trackpointers[0] + drv->tracktiming; + p += mfmpos / 8; + drv->trackspeed = get_floppy_speed () * drv->tracklen / (2 * 8 * FLOPPY_WRITE_LEN * drv->ddhd); + drv->trackspeed = drv->trackspeed * p[0] / 1000; + if (drv->trackspeed < 700 || drv->trackspeed > 3000) { + write_log ("corrupted trackspeed value %d\n", drv->trackspeed); + assert (0); + } + } +} + +static void disk_doupdate_predict (drive * drv, int startcycle) +{ + int is_sync = 0; + int firstcycle = startcycle; + uae_u32 tword = word; + int mfmpos = drv->mfmpos; + + diskevent_flag = 0; + while (startcycle < (maxhpos << 8) && !diskevent_flag) { + int cycle = startcycle >> 8; + if (drv->tracktiming) + updatetrackspeed (drv, mfmpos); + if (dskdmaen != 3) { + tword <<= 1; + if (unformatted (drv)) + tword |= (rand() & 0x1000) ? 1 : 0; + else + tword |= getonebit (drv->trackpointers[drv->current_revolution], mfmpos); + if ((tword & 0xffff) == dsksync) + diskevent_flag |= DISK_WORDSYNC; + } + mfmpos++; + mfmpos %= drv->tracklen; + if (mfmpos == drv->indexoffset) + diskevent_flag |= DISK_INDEXSYNC; + startcycle += drv->trackspeed; + } + if (drv->tracktiming) + updatetrackspeed (drv, drv->mfmpos); + if (diskevent_flag) { + disk_sync_cycle = startcycle >> 8; + eventtab[ev_disk].oldcycles = get_cycles (); + eventtab[ev_disk].evtime = get_cycles () + startcycle - firstcycle; + eventtab[ev_disk].active = 1; + events_schedule (); + } +} + +#ifdef CPUEMU_6 +extern uae_u8 cycle_line[256]; +#endif + +static void disk_doupdate_read (drive * drv, int floppybits) +{ + int j = 0, k = 1, l = 0; + +/* + uae_u16 *mfmbuf = drv->bigmfmbuf; + dsksync = 0x4444; + adkcon |= 0x400; + drv->mfmpos = 0; + memset (mfmbuf, 0, 1000); + cycles = 0x1000000; + // 4444 4444 4444 aaaa aaaaa 4444 4444 4444 + // 4444 aaaa aaaa 4444 + mfmbuf[0] = 0x4444; + mfmbuf[1] = 0x4444; + mfmbuf[2] = 0x4444; + mfmbuf[3] = 0xaaaa; + mfmbuf[4] = 0xaaaa; + mfmbuf[5] = 0x4444; + mfmbuf[6] = 0x4444; + mfmbuf[7] = 0x4444; +*/ + while (floppybits >= drv->trackspeed) { + if (drv->tracktiming) + updatetrackspeed (drv, drv->mfmpos); + word <<= 1; + if (unformatted (drv)) + word |= (rand() & 0x1000) ? 1 : 0; + else + word |= getonebit (drv->trackpointers[drv->current_revolution], drv->mfmpos); + //write_log ("%08.8X bo=%d so=%d mfmpos=%d dma=%d\n", (word & 0xffffff), bitoffset, syncoffset, drv->mfmpos,dma_enable); + drv->mfmpos++; + drv->mfmpos %= drv->tracklen; + if (drv->mfmpos == drv->indexoffset) { + drv->current_revolution++; + if (drv->current_revolution >= drv->revolutions) + drv->current_revolution = 0; + drv->tracklen = drv->tracklengths[drv->current_revolution]; + drv->trackspeed = get_floppy_speed () * drv->tracklen / (2 * 8 * FLOPPY_WRITE_LEN * drv->ddhd); + } + + if (bitoffset == 15 && dma_enable && dskdmaen == 2 && dsklength >= 0) { + if (dsklength > 0) { + put_word (dskpt, word); + dskpt += 2; +#ifdef CPUEMU_6 + cycle_line[7] |= CYCLE_DISK; + cycle_line[9] |= CYCLE_DISK; +#endif + } +#if 0 + dma_tab[j++] = word; + if (j == MAX_DISK_WORDS_PER_LINE - 1) { + write_log ("Bug: Disk DMA buffer overflow!\n"); + j--; + } +#endif + dsklength--; + if (dsklength <= 0) + disk_dmafinished (); + } + if ((bitoffset & 7) == 7) { + dskbytr_val = word & 0xff; + dskbytr_val |= 0x8000; + } + if (word == dsksync) { + if (adkcon & 0x400) + bitoffset = 15; +#ifdef DISK_DEBUG + if (dma_enable == 0) + write_dlog ("Sync match, DMA started at %d\n", drv->mfmpos); +#endif + dma_enable = 1; + } + + bitoffset++; + bitoffset &= 15; + floppybits -= drv->trackspeed; + } +#if 0 + dma_tab[j] = 0xffffffff; +#endif +} + +#if 0 +/* disk DMA fetch happens on real Amiga at the beginning of next horizontal line + (cycles 9, 11 and 13 according to hardware manual) We transfer all DMA'd + data at cycle 0. I don't think any program cares about this small difference. +*/ +static void dodmafetch (void) +{ + int i; + + i = 0; + while (dma_tab[i] != 0xffffffff && dskdmaen != 3 && (dmacon & 0x210) == 0x210) { + put_word (dskpt, dma_tab[i++]); + dskpt += 2; + } + dma_tab[0] = 0xffffffff; +} +#endif + +/* this is very unoptimized. DSKBYTR is used very rarely, so it should not matter. */ + +uae_u16 DSKBYTR (int hpos) +{ + uae_u16 v; + + DISK_update (hpos); + v = dskbytr_val; + dskbytr_val &= ~0x8000; + if (word == dsksync) + v |= 0x1000; + if (dskdmaen && (dmacon & 0x210) == 0x210) + v |= 0x4000; + if (dsklen & 0x4000) + v |= 0x2000; +#ifdef DISK_DEBUG2 + write_dlog ("DSKBYTR=%04.4X hpos=%d\n", v, hpos); +#endif + return v; +} + +static void DISK_start (void) +{ + int dr; + + for (dr = 0; dr < 4; dr++) { + drive *drv = &floppy[dr]; + if (!(selected & (1 << dr))) { + int tr = drv->cyl * 2 + side; + trackid *ti = drv->trackdata + tr; + + if (dskdmaen == 3) { + drv->tracklen = FLOPPY_WRITE_LEN * drv->ddhd * 8 * 2; + drv->trackspeed = get_floppy_speed (); + updatemfmpos (drv); + } + /* Ugh. A nasty hack. Assume ADF_EXT1 tracks are always read + from the start. */ + if (ti->type == TRACK_RAW1) + drv->mfmpos = 0; + if (drv->catweasel) + drive_fill_bigbuf (drv, 1); + } + drv->floppybitcounter = 0; + } + dma_enable = (adkcon & 0x400) ? 0 : 1; +} + +static int linecounter; + +void DISK_update (int tohpos) +{ + int dr; + int cycles = (tohpos << 8) - disk_hpos; + int startcycle = disk_hpos; + + if (cycles <= 0) + return; + disk_hpos += cycles; + if (disk_hpos >= (maxhpos << 8)) + disk_hpos -= maxhpos << 8; + + for (dr = 0; dr < 4; dr++) { + drive *drv = &floppy[dr]; + if (drv->steplimit) + drv->steplimit--; + } + if (linecounter) { + linecounter--; + if (! linecounter) + disk_dmafinished (); + return; + } + +#if 0 + dodmafetch (); +#endif + + for (dr = 0; dr < 4; dr++) { + drive *drv = &floppy[dr]; + + if (drv->motoroff) + continue; + drv->floppybitcounter += cycles; + if (selected & (1 << dr)) { + drv->mfmpos += drv->floppybitcounter / drv->trackspeed; + drv->mfmpos %= drv->tracklen; + drv->floppybitcounter %= drv->trackspeed; + continue; + } + drive_fill_bigbuf (drv, 0); + drv->mfmpos %= drv->tracklen; + } + for (dr = 0; dr < 4; dr++) { + drive *drv = &floppy[dr]; + if (drv->motoroff) + continue; + if (selected & (1 << dr)) + continue; + if (dskdmaen == 3) + disk_doupdate_write (drv, drv->floppybitcounter); + else + disk_doupdate_read (drv, drv->floppybitcounter); + disk_doupdate_predict (drv, disk_hpos); + drv->floppybitcounter %= drv->trackspeed; + break; + } +} + +void DSKLEN (uae_u16 v, int hpos) +{ + int dr, prev = dsklen; + + DISK_update (hpos); + if ((v & 0x8000) && (dsklen & 0x8000)) { + dskdmaen = 2; + DISK_start (); + } + if (!(v & 0x8000)) { + if (dskdmaen) { + /* Megalomania and Knightmare does this */ +#ifdef DISK_DEBUG + if (dskdmaen == 2) + write_dlog ("warning: Disk read DMA aborted, %d words left PC=%x\n", dsklength, m68k_getpc()); +#endif + if (dskdmaen == 3) + write_dlog ("warning: Disk write DMA aborted, %d words left PC=%x\n", dsklength, m68k_getpc()); + dskdmaen = 0; + } + } + dsklen = v; + dsklength = dsklen & 0x3fff; + if (dsklength == 1) + dsklength = 0; + + if (dskdmaen == 0) + return; + + if ((v & 0x4000) && (prev & 0x4000)) { + if (dsklength == 0) + return; + dskdmaen = 3; + DISK_start (); + } + +#ifdef DISK_DEBUG + for (dr = 0; dr < 4; dr++) { + drive *drv = &floppy[dr]; + if (drv->motoroff) + continue; + if ((selected & (1 << dr)) == 0) + break; + } + if (dr == 4) + write_log ("disk %s DMA started but no drive selected!\n", + dskdmaen == 3 ? "write" : "read"); + else + write_log ("disk %s DMA started, drv=%x track %d mfmpos %d\n", + dskdmaen == 3 ? "write" : "read", selected ^ 15, + floppy[dr].cyl * 2 + side, floppy[dr].mfmpos); + write_dlog ("LEN=%04.4X (%d) SYNC=%04.4X PT=%08.8X ADKCON=%04.4X PC=%08.8X\n", + dsklength, dsklength, (adkcon & 0x400) ? dsksync : 0xffff, dskpt, adkcon, m68k_getpc()); +#endif + + /* Try to make floppy access from Kickstart faster. */ + if (dskdmaen != 2 && dskdmaen != 3) + return; + for (dr = 0; dr < 4; dr++) { + drive *drv = &floppy[dr]; + if (selected & (1 << dr)) + continue; + if (drv->filetype != ADF_NORMAL) + break; + } + if (dr < 4) /* no turbo mode if any selected drive has non-standard ADF */ + return; + { + int done = 0; + for (dr = 0; dr < 4; dr++) { + drive *drv = &floppy[dr]; + int pos, i; + + if (drv->motoroff) + continue; + if (!drv->useturbo && currprefs.floppy_speed > 0) + continue; + if (selected & (1 << dr)) + continue; + + pos = drv->mfmpos & ~15; + drive_fill_bigbuf (drv, 0); + + if (dskdmaen == 2) { /* TURBO read */ + + if (adkcon & 0x400) { + for (i = 0; i < drv->tracklen; i += 16) { + pos += 16; + pos %= drv->tracklen; + if (drv->bigmfmbuf[pos >> 4] == dsksync) { + /* must skip first disk sync marker */ + pos += 16; + pos %= drv->tracklen; + break; + } + } + if (i >= drv->tracklen) + return; + } + while (dsklength-- > 0) { + put_word (dskpt, drv->bigmfmbuf[pos >> 4]); + dskpt += 2; + pos += 16; + pos %= drv->tracklen; + } + INTREQ (0x9000); + done = 1; + + } else if (dskdmaen == 3) { /* TURBO write */ + + for (i = 0; i < dsklength; i++) { + drv->bigmfmbuf[pos >> 4] = get_word (dskpt + i * 2); + pos += 16; + pos %= drv->tracklen; + } + drive_write_data (drv); + done = 1; + } + } + if (done) { + linecounter = 2; + dskdmaen = 0; + return; + } + } +} + +void DSKSYNC (int hpos, uae_u16 v) +{ + if (v == dsksync) + return; + DISK_update (hpos); + dsksync = v; +} + +void DSKDAT (uae_u16 v) +{ + static int count = 0; + if (count < 5) { + count++; + write_dlog ("%04.4X written to DSKDAT. Not good. PC=%08.8X", v, m68k_getpc()); + if (count == 5) + write_log ("(further messages suppressed)"); + + write_log ("\n"); + } +} +void DSKPTH (uae_u16 v) +{ + dskpt = (dskpt & 0xffff) | ((uae_u32) v << 16); +} + +void DSKPTL (uae_u16 v) +{ + dskpt = (dskpt & ~0xffff) | (v); +} + +void DISK_free (void) +{ + int dr; + for (dr = 0; dr < 4; dr++) { + drive *drv = &floppy[dr]; + drive_image_free (drv); + } +} + +void DISK_init (void) +{ + int dr; + +#if 0 + dma_tab[0] = 0xffffffff; +#endif + for (dr = 0; dr < 4; dr++) { + drive *drv = &floppy[dr]; + /* reset all drive types to 3.5 DD */ + drive_settype_id (drv); + if (!drive_insert (drv, dr, currprefs.df[dr])) + disk_eject (dr); + } + if (disk_empty (0)) + write_log ("No disk in drive 0.\n"); +} + +void DISK_reset (void) +{ + int i; + + if (savestate_state) + return; + + //floppy[0].catweasel = &cwc.drives[0]; + disk_hpos = 0; + dskdmaen = 0; + disabled = 0; + for (i = 0; i < 4; i++) + reset_drive (i); +} + +/* Disk save/restore code */ + +void DISK_save_custom (uae_u32 *pdskpt, uae_u16 *pdsklength, uae_u16 *pdsksync, uae_u16 *pdskbytr) +{ + if(pdskpt) *pdskpt = dskpt; + if(pdsklength) *pdsklength = dsklength; + if(pdsksync) *pdsksync = dsksync; + if(pdskbytr) *pdskbytr = dskbytr_val; +} + +void DISK_restore_custom (uae_u32 pdskpt, uae_u16 pdsklength, uae_u16 pdskbytr) +{ + dskpt = pdskpt; + dsklength = pdsklength; + dskbytr_val = pdskbytr; +} + +uae_u8 *restore_disk(int num,uae_u8 *src) +{ + drive *drv; + int state, dfxtype; + + drv = &floppy[num]; + disabled &= ~(1 << num); + drv->drive_id = restore_u32 (); + drv->motoroff = 1; + drv->idbit = 0; + state = restore_u8 (); + if (state & 2) { + disabled |= 1 << num; + if (changed_prefs.nr_floppies > num) + changed_prefs.nr_floppies = num; + changed_prefs.dfxtype[num] = -1; + } else { + drv->motoroff = (state & 1) ? 0 : 1; + drv->idbit = (state & 4) ? 1 : 0; + if (changed_prefs.nr_floppies < num) + changed_prefs.nr_floppies = num; + switch (drv->drive_id) + { + case DRIVE_ID_35HD: + dfxtype = DRV_35_HD; + break; + case DRIVE_ID_525SD: + dfxtype = DRV_525_SD; + break; + default: + dfxtype = DRV_35_DD; + break; + } + changed_prefs.dfxtype[num] = dfxtype; + } + drv->cyl = restore_u8 (); + drv->dskready = restore_u8 (); + drv->drive_id_scnt = restore_u8 (); + drv->mfmpos = restore_u32 (); + drv->dskchange = 0; + drv->dskchange_time = 0; + restore_u32 (); + strncpy(changed_prefs.df[num],src,255); + src+=strlen(src)+1; + drive_insert (floppy + num, num, changed_prefs.df[num]); + if (drive_empty (floppy + num)) drv->dskchange = 1; + + return src; +} + +static uae_u32 getadfcrc (drive *drv) +{ + uae_u8 *b; + uae_u32 crc32; + int size; + + if (!drv->diskfile) + return 0; + zfile_fseek (drv->diskfile, 0, SEEK_END); + size = zfile_ftell (drv->diskfile); + b = malloc (size); + if (!b) + return 0; + zfile_fseek (drv->diskfile, 0, SEEK_SET); + zfile_fread (b, 1, size, drv->diskfile); + crc32 = CRC32 (0, b, size); + free (b); + return crc32; +} + +uae_u8 *save_disk(int num, int *len, uae_u8 *dstptr) +{ + uae_u8 *dstbak,*dst; + drive *drv; + + drv = &floppy[num]; + if (dstptr) + dstbak = dst = dstptr; + else + dstbak = dst = malloc (2+1+1+1+1+4+4+256); + save_u32 (drv->drive_id); /* drive type ID */ + save_u8 ((drv->motoroff ? 0:1) | ((disabled & (1 << num)) ? 2 : 0) | (drv->idbit ? 4 : 0)); + save_u8 (drv->cyl); /* cylinder */ + save_u8 (drv->dskready); /* dskready */ + save_u8 (drv->drive_id_scnt); /* id mode position */ + save_u32 (drv->mfmpos); /* disk position */ + save_u32 (getadfcrc (drv)); /* CRC of disk image */ + strcpy (dst, currprefs.df[num]);/* image name */ + dst += strlen(dst) + 1; + + *len = dst - dstbak; + return dstbak; +} + +/* internal floppy controller variables */ + +uae_u8 *restore_floppy(uae_u8 *src) +{ + word = restore_u16(); + bitoffset = restore_u8(); + dma_enable = restore_u8(); + disk_hpos = restore_u8() << 8; + dskdmaen = restore_u8(); + restore_u16 (); + //word |= restore_u16() << 16; + + return src; +} + +uae_u8 *save_floppy(int *len, uae_u8 *dstptr) +{ + uae_u8 *dstbak, *dst; + + /* flush dma buffer before saving */ +#if 0 + dodmafetch(); +#endif + if (dstptr) + dstbak = dst = dstptr; + else + dstbak = dst = malloc(2+1+1+1+1+2); + save_u16 (word); /* current fifo (low word) */ + save_u8 (bitoffset); /* dma bit offset */ + save_u8 (dma_enable); /* disk sync found */ + save_u8 (disk_hpos >> 8); /* next bit read position */ + save_u8 (dskdmaen); /* dma status */ + save_u16 (0); /* was current fifo (high word), but it was wrong???? */ + + *len = dst - dstbak; + return dstbak; +} + + diff --git a/dms/cdata.h b/dms/cdata.h new file mode 100755 index 00000000..b5e77e09 --- /dev/null +++ b/dms/cdata.h @@ -0,0 +1,80 @@ + +/* + * xDMS v1.3 - Portable DMS archive unpacker - Public Domain + * Written by Andre Rodrigues de la Rocha + * + * Main types of variables used in xDMS, some implementation + * dependant features and other global stuff + */ + + +#ifndef UCHAR +#define UCHAR unsigned char +#endif + +#ifndef USHORT +#define USHORT unsigned short +#endif + +#ifndef SHORT +#define SHORT short +#endif + +#ifndef ULONG +#define ULONG unsigned long +#endif + + + +#ifndef INLINE + #ifdef __cplusplus + #define INLINE inline + #else + #ifdef __GNUC__ + #define INLINE inline + #else + #ifdef __SASC + #define INLINE __inline + #else + #define INLINE static + #endif + #endif + #endif +#endif + + +#ifndef UNDER_DOS + #ifdef __MSDOS__ + #define UNDER_DOS + #else + #ifdef __MSDOS + #define UNDER_DOS + #else + #ifdef _OS2 + #define UNDER_DOS + #else + #ifdef _QC + #define UNDER_DOS + #endif + #endif + #endif + #endif +#endif + + +#ifndef DIR_CHAR + #ifdef UNDER_DOS + /* running under MSDOS or DOS-like OS */ + #define DIR_CHAR '\\' + #else + #define DIR_CHAR '/' + #endif +#endif + + +#define DIR_SEPARATORS ":\\/" + + +extern UCHAR *text; + + diff --git a/dms/crc_csum.c b/dms/crc_csum.c new file mode 100755 index 00000000..70337c62 --- /dev/null +++ b/dms/crc_csum.c @@ -0,0 +1,69 @@ + +/* + * xDMS v1.3 - Portable DMS archive unpacker - Public Domain + * Written by Andre Rodrigues de la Rocha + * + * CRC16 & CheckSum16 calculation functions + * CreateCRC was written (aparently) by Bjorn Stenberg + * + */ + + +#include "cdata.h" +#include "crc_csum.h" + + + +USHORT Calc_CheckSum(UCHAR *mem, ULONG size){ + USHORT u=0; + + while(size--) u += *mem++; + return (USHORT)(u & 0xffff); +} + + + +USHORT CreateCRC(UCHAR* mem, ULONG size ){ + static USHORT CRCTab[256]={ + 0x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241, + 0xC601,0x06C0,0x0780,0xC741,0x0500,0xC5C1,0xC481,0x0440, + 0xCC01,0x0CC0,0x0D80,0xCD41,0x0F00,0xCFC1,0xCE81,0x0E40, + 0x0A00,0xCAC1,0xCB81,0x0B40,0xC901,0x09C0,0x0880,0xC841, + 0xD801,0x18C0,0x1980,0xD941,0x1B00,0xDBC1,0xDA81,0x1A40, + 0x1E00,0xDEC1,0xDF81,0x1F40,0xDD01,0x1DC0,0x1C80,0xDC41, + 0x1400,0xD4C1,0xD581,0x1540,0xD701,0x17C0,0x1680,0xD641, + 0xD201,0x12C0,0x1380,0xD341,0x1100,0xD1C1,0xD081,0x1040, + 0xF001,0x30C0,0x3180,0xF141,0x3300,0xF3C1,0xF281,0x3240, + 0x3600,0xF6C1,0xF781,0x3740,0xF501,0x35C0,0x3480,0xF441, + 0x3C00,0xFCC1,0xFD81,0x3D40,0xFF01,0x3FC0,0x3E80,0xFE41, + 0xFA01,0x3AC0,0x3B80,0xFB41,0x3900,0xF9C1,0xF881,0x3840, + 0x2800,0xE8C1,0xE981,0x2940,0xEB01,0x2BC0,0x2A80,0xEA41, + 0xEE01,0x2EC0,0x2F80,0xEF41,0x2D00,0xEDC1,0xEC81,0x2C40, + 0xE401,0x24C0,0x2580,0xE541,0x2700,0xE7C1,0xE681,0x2640, + 0x2200,0xE2C1,0xE381,0x2340,0xE101,0x21C0,0x2080,0xE041, + 0xA001,0x60C0,0x6180,0xA141,0x6300,0xA3C1,0xA281,0x6240, + 0x6600,0xA6C1,0xA781,0x6740,0xA501,0x65C0,0x6480,0xA441, + 0x6C00,0xACC1,0xAD81,0x6D40,0xAF01,0x6FC0,0x6E80,0xAE41, + 0xAA01,0x6AC0,0x6B80,0xAB41,0x6900,0xA9C1,0xA881,0x6840, + 0x7800,0xB8C1,0xB981,0x7940,0xBB01,0x7BC0,0x7A80,0xBA41, + 0xBE01,0x7EC0,0x7F80,0xBF41,0x7D00,0xBDC1,0xBC81,0x7C40, + 0xB401,0x74C0,0x7580,0xB541,0x7700,0xB7C1,0xB681,0x7640, + 0x7200,0xB2C1,0xB381,0x7340,0xB101,0x71C0,0x7080,0xB041, + 0x5000,0x90C1,0x9181,0x5140,0x9301,0x53C0,0x5280,0x9241, + 0x9601,0x56C0,0x5780,0x9741,0x5500,0x95C1,0x9481,0x5440, + 0x9C01,0x5CC0,0x5D80,0x9D41,0x5F00,0x9FC1,0x9E81,0x5E40, + 0x5A00,0x9AC1,0x9B81,0x5B40,0x9901,0x59C0,0x5880,0x9841, + 0x8801,0x48C0,0x4980,0x8941,0x4B00,0x8BC1,0x8A81,0x4A40, + 0x4E00,0x8EC1,0x8F81,0x4F40,0x8D01,0x4DC0,0x4C80,0x8C41, + 0x4400,0x84C1,0x8581,0x4540,0x8701,0x47C0,0x4680,0x8641, + 0x8201,0x42C0,0x4380,0x8341,0x4100,0x81C1,0x8081,0x4040 + }; + register USHORT CRC = 0; + + while(size--) + CRC = (USHORT) (CRCTab[((CRC ^ *mem++) & 255)] ^ ((CRC >> 8) & 255)); + + return CRC; +} + + diff --git a/dms/crc_csum.h b/dms/crc_csum.h new file mode 100755 index 00000000..0fa92f50 --- /dev/null +++ b/dms/crc_csum.h @@ -0,0 +1,4 @@ + +USHORT Calc_CheckSum(UCHAR *, ULONG); +USHORT CreateCRC(UCHAR *, ULONG); + diff --git a/dms/getbits.c b/dms/getbits.c new file mode 100755 index 00000000..d4749770 --- /dev/null +++ b/dms/getbits.c @@ -0,0 +1,34 @@ + +/* + * xDMS v1.3 - Portable DMS archive unpacker - Public Domain + * Written by Andre Rodrigues de la Rocha + * Functions/macros to get a variable number of bits + * + */ + +#include "cdata.h" +#include "getbits.h" + + +ULONG mask_bits[]={ + 0x000000L,0x000001L,0x000003L,0x000007L,0x00000fL,0x00001fL, + 0x00003fL,0x00007fL,0x0000ffL,0x0001ffL,0x0003ffL,0x0007ffL, + 0x000fffL,0x001fffL,0x003fffL,0x007fffL,0x00ffffL,0x01ffffL, + 0x03ffffL,0x07ffffL,0x0fffffL,0x1fffffL,0x3fffffL,0x7fffffL, + 0xffffffL +}; + + +UCHAR *indata, bitcount; +ULONG bitbuf; + + + +void initbitbuf(UCHAR *in){ + bitbuf = 0; + bitcount = 0; + indata = in; + DROPBITS(0); +} + + diff --git a/dms/getbits.h b/dms/getbits.h new file mode 100755 index 00000000..f0c5adde --- /dev/null +++ b/dms/getbits.h @@ -0,0 +1,10 @@ + +extern ULONG mask_bits[], bitbuf; +extern UCHAR *indata, bitcount; + +#define GETBITS(n) ((USHORT)(bitbuf >> (bitcount-(n)))) +#define DROPBITS(n) {bitbuf &= mask_bits[bitcount-=(n)]; while (bitcount<16) {bitbuf = (bitbuf << 8) | *indata++; bitcount += 8;}} + + +void initbitbuf(UCHAR *); + diff --git a/dms/maketbl.c b/dms/maketbl.c new file mode 100755 index 00000000..c735988c --- /dev/null +++ b/dms/maketbl.c @@ -0,0 +1,92 @@ + +/* + * xDMS v1.3 - Portable DMS archive unpacker - Public Domain + * Written by Andre Rodrigues de la Rocha + * + * Makes decoding table for Heavy LZH decompression + * From UNIX LHA made by Masaru Oki + * + */ + + +#include "cdata.h" +#include "maketbl.h" + + +static SHORT c; +static USHORT n, tblsiz, len, depth, maxdepth, avail; +static USHORT codeword, bit, *tbl, TabErr; +static UCHAR *blen; + + +static USHORT mktbl(void); + + + +USHORT make_table(USHORT nchar, UCHAR bitlen[],USHORT tablebits, USHORT table[]){ + n = avail = nchar; + blen = bitlen; + tbl = table; + tblsiz = (USHORT) (1U << tablebits); + bit = (USHORT) (tblsiz / 2); + maxdepth = (USHORT)(tablebits + 1); + depth = len = 1; + c = -1; + codeword = 0; + TabErr = 0; + mktbl(); /* left subtree */ + if (TabErr) return TabErr; + mktbl(); /* right subtree */ + if (TabErr) return TabErr; + if (codeword != tblsiz) return 5; + return 0; +} + + + +static USHORT mktbl(void){ + USHORT i=0; + + if (TabErr) return 0; + + if (len == depth) { + while (++c < n) + if (blen[c] == len) { + i = codeword; + codeword += bit; + if (codeword > tblsiz) { + TabErr=1; + return 0; + } + while (i < codeword) tbl[i++] = (USHORT)c; + return (USHORT)c; + } + c = -1; + len++; + bit >>= 1; + } + depth++; + if (depth < maxdepth) { + mktbl(); + mktbl(); + } else if (depth > 32) { + TabErr = 2; + return 0; + } else { + if ((i = avail++) >= 2 * n - 1) { + TabErr = 3; + return 0; + } + left[i] = mktbl(); + right[i] = mktbl(); + if (codeword >= tblsiz) { + TabErr = 4; + return 0; + } + if (depth == maxdepth) tbl[codeword++] = i; + } + depth--; + return i; +} + + diff --git a/dms/maketbl.h b/dms/maketbl.h new file mode 100755 index 00000000..42abc3e7 --- /dev/null +++ b/dms/maketbl.h @@ -0,0 +1,5 @@ + +extern USHORT left[], right[]; + +USHORT make_table(USHORT nchar, UCHAR bitlen[], USHORT tablebits, USHORT table[]); + diff --git a/dms/pfile.c b/dms/pfile.c new file mode 100755 index 00000000..f7c2204a --- /dev/null +++ b/dms/pfile.c @@ -0,0 +1,416 @@ + +/* + * xDMS v1.3 - Portable DMS archive unpacker - Public Domain + * Written by Andre Rodrigues de la Rocha + * + * 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 +#include +#include +#include + +#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 + * + * Tables used in Medium and Deep compression modes + * + */ + + +#include "cdata.h" +#include "tables.h" + + +UCHAR d_code[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, + 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, + 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, + 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, + 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, + 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B, + 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F, + 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, + 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, + 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, + 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, +}; + + + +UCHAR d_len[256] = { + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, +}; + + diff --git a/dms/tables.h b/dms/tables.h new file mode 100755 index 00000000..9d557c39 --- /dev/null +++ b/dms/tables.h @@ -0,0 +1,3 @@ + +extern UCHAR d_code[], d_len[]; + diff --git a/dms/u_deep.c b/dms/u_deep.c new file mode 100755 index 00000000..e1e5dcaf --- /dev/null +++ b/dms/u_deep.c @@ -0,0 +1,207 @@ + +/* + * xDMS v1.3 - Portable DMS archive unpacker - Public Domain + * Written by Andre Rodrigues de la Rocha + * + * Lempel-Ziv-DynamicHuffman decompression functions used in Deep + * mode. + * Most routines ripped from LZHUF written by Haruyasu Yoshizaki + * + */ + +#include + +#include "cdata.h" +#include "tables.h" +#include "u_deep.h" +#include "getbits.h" + + +INLINE USHORT DecodeChar(void); +INLINE USHORT DecodePosition(void); +INLINE void update(USHORT c); +static void reconst(void); + + +USHORT deep_text_loc; +int init_deep_tabs=1; + + + +#define DBITMASK 0x3fff /* uses 16Kb dictionary */ + +#define F 60 /* lookahead buffer size */ +#define THRESHOLD 2 +#define N_CHAR (256 - THRESHOLD + F) /* kinds of characters (character code = 0..N_CHAR-1) */ +#define T (N_CHAR * 2 - 1) /* size of table */ +#define R (T - 1) /* position of root */ +#define MAX_FREQ 0x8000 /* updates tree when the */ + + +USHORT freq[T + 1]; /* frequency table */ + +USHORT prnt[T + N_CHAR]; /* pointers to parent nodes, except for the */ + /* elements [T..T + N_CHAR - 1] which are used to get */ + /* the positions of leaves corresponding to the codes. */ + +USHORT son[T]; /* pointers to child nodes (son[], son[] + 1) */ + + + +void Init_DEEP_Tabs(void){ + USHORT i, j; + + for (i = 0; i < N_CHAR; i++) { + freq[i] = 1; + son[i] = (USHORT)(i + T); + prnt[i + T] = i; + } + i = 0; j = N_CHAR; + while (j <= R) { + freq[j] = (USHORT) (freq[i] + freq[i + 1]); + son[j] = i; + prnt[i] = prnt[i + 1] = j; + i += 2; j++; + } + freq[T] = 0xffff; + prnt[R] = 0; + + init_deep_tabs = 0; +} + + + +USHORT Unpack_DEEP(UCHAR *in, UCHAR *out, USHORT origsize){ + USHORT i, j, c; + UCHAR *outend; + + initbitbuf(in); + + if (init_deep_tabs) Init_DEEP_Tabs(); + + outend = out+origsize; + while (out < outend) { + c = DecodeChar(); + if (c < 256) { + *out++ = text[deep_text_loc++ & DBITMASK] = (UCHAR)c; + } else { + j = (USHORT) (c - 255 + THRESHOLD); + i = (USHORT) (deep_text_loc - DecodePosition() - 1); + while (j--) *out++ = text[deep_text_loc++ & DBITMASK] = text[i++ & DBITMASK]; + } + } + + deep_text_loc = (USHORT)((deep_text_loc+60) & DBITMASK); + + return 0; +} + + + +INLINE USHORT DecodeChar(void){ + USHORT c; + + c = son[R]; + + /* travel from root to leaf, */ + /* choosing the smaller child node (son[]) if the read bit is 0, */ + /* the bigger (son[]+1} if 1 */ + while (c < T) { + c = son[c + GETBITS(1)]; + DROPBITS(1); + } + c -= T; + update(c); + return c; +} + + + +INLINE USHORT DecodePosition(void){ + USHORT i, j, c; + + i = GETBITS(8); DROPBITS(8); + c = (USHORT) (d_code[i] << 8); + j = d_len[i]; + i = (USHORT) (((i << j) | GETBITS(j)) & 0xff); DROPBITS(j); + + return (USHORT) (c | i) ; +} + + + +/* reconstruction of tree */ + +static void reconst(void){ + USHORT i, j, k, f, l; + + /* collect leaf nodes in the first half of the table */ + /* and replace the freq by (freq + 1) / 2. */ + j = 0; + for (i = 0; i < T; i++) { + if (son[i] >= T) { + freq[j] = (USHORT) ((freq[i] + 1) / 2); + son[j] = son[i]; + j++; + } + } + /* begin constructing tree by connecting sons */ + for (i = 0, j = N_CHAR; j < T; i += 2, j++) { + k = (USHORT) (i + 1); + f = freq[j] = (USHORT) (freq[i] + freq[k]); + for (k = (USHORT)(j - 1); f < freq[k]; k--); + k++; + l = (USHORT)((j - k) * 2); + memmove(&freq[k + 1], &freq[k], (size_t)l); + freq[k] = f; + memmove(&son[k + 1], &son[k], (size_t)l); + son[k] = i; + } + /* connect prnt */ + for (i = 0; i < T; i++) { + if ((k = son[i]) >= T) { + prnt[k] = i; + } else { + prnt[k] = prnt[k + 1] = i; + } + } +} + + + +/* increment frequency of given code by one, and update tree */ + +INLINE void update(USHORT c){ + USHORT i, j, k, l; + + if (freq[R] == MAX_FREQ) { + reconst(); + } + c = prnt[c + T]; + do { + k = ++freq[c]; + + /* if the order is disturbed, exchange nodes */ + if (k > freq[l = (USHORT)(c + 1)]) { + while (k > freq[++l]); + l--; + freq[c] = freq[l]; + freq[l] = k; + + i = son[c]; + prnt[i] = l; + if (i < T) prnt[i + 1] = l; + + j = son[l]; + son[l] = i; + + prnt[j] = c; + if (j < T) prnt[j + 1] = c; + son[c] = j; + + c = l; + } + } while ((c = prnt[c]) != 0); /* repeat up to root */ +} + + diff --git a/dms/u_deep.h b/dms/u_deep.h new file mode 100755 index 00000000..d87be1d9 --- /dev/null +++ b/dms/u_deep.h @@ -0,0 +1,7 @@ + + +USHORT Unpack_DEEP(UCHAR *, UCHAR *, USHORT); + +extern int init_deep_tabs; +extern USHORT deep_text_loc; + diff --git a/dms/u_heavy.c b/dms/u_heavy.c new file mode 100755 index 00000000..fff93d36 --- /dev/null +++ b/dms/u_heavy.c @@ -0,0 +1,175 @@ + +/* + * xDMS v1.3 - Portable DMS archive unpacker - Public Domain + * Written by Andre Rodrigues de la Rocha + * + * 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>= 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; i0){ + for (i=0; i + * + * Decruncher reinitialization + * + */ + +#include + +#include "cdata.h" +#include "u_init.h" +#include "u_quick.h" +#include "u_medium.h" +#include "u_deep.h" +#include "u_heavy.h" + + +void Init_Decrunchers(void){ + quick_text_loc = 251; + medium_text_loc = 0x3fbe; + heavy_text_loc = 0; + deep_text_loc = 0x3fc4; + init_deep_tabs = 1; + memset(text,0,0x3fc8); +} + diff --git a/dms/u_init.h b/dms/u_init.h new file mode 100755 index 00000000..9a74d581 --- /dev/null +++ b/dms/u_init.h @@ -0,0 +1,3 @@ + +void Init_Decrunchers(void); + diff --git a/dms/u_medium.c b/dms/u_medium.c new file mode 100755 index 00000000..6dd0b659 --- /dev/null +++ b/dms/u_medium.c @@ -0,0 +1,58 @@ + +/* + * xDMS v1.3 - Portable DMS archive unpacker - Public Domain + * Written by Andre Rodrigues de la Rocha + * + * Main decompression functions used in MEDIUM mode + * + */ + + +#include + +#include "cdata.h" +#include "u_medium.h" +#include "getbits.h" +#include "tables.h" + + +#define MBITMASK 0x3fff + + +USHORT medium_text_loc; + + + +USHORT Unpack_MEDIUM(UCHAR *in, UCHAR *out, USHORT origsize){ + USHORT i, j, c; + UCHAR u, *outend; + + + initbitbuf(in); + + outend = out+origsize; + while (out < outend) { + if (GETBITS(1)!=0) { + DROPBITS(1); + *out++ = text[medium_text_loc++ & MBITMASK] = (UCHAR)GETBITS(8); + DROPBITS(8); + } else { + DROPBITS(1); + c = GETBITS(8); DROPBITS(8); + j = (USHORT) (d_code[c]+3); + u = d_len[c]; + c = (USHORT) (((c << u) | GETBITS(u)) & 0xff); DROPBITS(u); + u = d_len[c]; + c = (USHORT) ((d_code[c] << 8) | (((c << u) | GETBITS(u)) & 0xff)); DROPBITS(u); + i = (USHORT) (medium_text_loc - c - 1); + + while(j--) *out++ = text[medium_text_loc++ & MBITMASK] = text[i++ & MBITMASK]; + + } + } + medium_text_loc = (USHORT)((medium_text_loc+66) & MBITMASK); + + return 0; +} + + diff --git a/dms/u_medium.h b/dms/u_medium.h new file mode 100755 index 00000000..3c1b4fc2 --- /dev/null +++ b/dms/u_medium.h @@ -0,0 +1,5 @@ + +USHORT Unpack_MEDIUM(UCHAR *, UCHAR *, USHORT); + +extern USHORT medium_text_loc; + diff --git a/dms/u_quick.c b/dms/u_quick.c new file mode 100755 index 00000000..74131c26 --- /dev/null +++ b/dms/u_quick.c @@ -0,0 +1,47 @@ + +/* + * xDMS v1.3 - Portable DMS archive unpacker - Public Domain + * Written by Andre Rodrigues de la Rocha + * + * + */ + + +#include + +#include "cdata.h" +#include "u_quick.h" +#include "getbits.h" + + +#define QBITMASK 0xff + + +USHORT quick_text_loc; + + +USHORT Unpack_QUICK(UCHAR *in, UCHAR *out, USHORT origsize){ + USHORT i, j; + UCHAR *outend; + + initbitbuf(in); + + outend = out+origsize; + while (out < outend) { + if (GETBITS(1)!=0) { + DROPBITS(1); + *out++ = text[quick_text_loc++ & QBITMASK] = (UCHAR)GETBITS(8); DROPBITS(8); + } else { + DROPBITS(1); + j = (USHORT) (GETBITS(2)+2); DROPBITS(2); + i = (USHORT) (quick_text_loc - GETBITS(8) - 1); DROPBITS(8); + while(j--) { + *out++ = text[quick_text_loc++ & QBITMASK] = text[i++ & QBITMASK]; + } + } + } + quick_text_loc = (USHORT)((quick_text_loc+5) & QBITMASK); + + return 0; +} + diff --git a/dms/u_quick.h b/dms/u_quick.h new file mode 100755 index 00000000..9518815b --- /dev/null +++ b/dms/u_quick.h @@ -0,0 +1,5 @@ + +USHORT Unpack_QUICK(UCHAR *, UCHAR *, USHORT); + +extern USHORT quick_text_loc; + diff --git a/dms/u_rle.c b/dms/u_rle.c new file mode 100755 index 00000000..ff46c561 --- /dev/null +++ b/dms/u_rle.c @@ -0,0 +1,42 @@ + +/* + * xDMS v1.3 - Portable DMS archive unpacker - Public Domain + * Written by Andre Rodrigues de la Rocha + * + * Run Length Encoding decompression function used in most + * modes after decompression by other algorithm + * + */ + +#include +#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) return 1; + memset(out,a,(size_t) n); + out += n; + } + } + return 0; +} + + diff --git a/dms/u_rle.h b/dms/u_rle.h new file mode 100755 index 00000000..0cf24938 --- /dev/null +++ b/dms/u_rle.h @@ -0,0 +1,3 @@ + +USHORT Unpack_RLE(UCHAR *, UCHAR *, USHORT); + diff --git a/drawing.c b/drawing.c new file mode 100755 index 00000000..e758bb86 --- /dev/null +++ b/drawing.c @@ -0,0 +1,2077 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Screen drawing functions + * + * Copyright 1995-2000 Bernd Schmidt + * Copyright 1995 Alessandro Bissacco + * Copyright 2000,2001 Toni Wilen + */ + +/* There are a couple of concepts of "coordinates" in this file. + - DIW coordinates + - DDF coordinates (essentially cycles, resolution lower than lores by a factor of 2) + - Pixel coordinates + * in the Amiga's resolution as determined by BPLCON0 ("Amiga coordinates") + * in the window resolution as determined by the preferences ("window coordinates"). + * in the window resolution, and with the origin being the topmost left corner of + the window ("native coordinates") + One note about window coordinates. The visible area depends on the width of the + window, and the centering code. The first visible horizontal window coordinate is + often _not_ 0, but the value of VISIBLE_LEFT_BORDER instead. + + One important thing to remember: DIW coordinates are in the lowest possible + resolution. + + To prevent extremely bad things (think pixels cut in half by window borders) from + happening, all ports should restrict window widths to be multiples of 16 pixels. */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include +#include + +#include "config.h" +#include "options.h" +#include "threaddep/thread.h" +#include "uae.h" +#include "memory.h" +#include "custom.h" +#include "newcpu.h" +#include "xwin.h" +#include "autoconf.h" +#include "gui.h" +#include "picasso96.h" +#include "drawing.h" +#include "compemu.h" +#include "savestate.h" + +int lores_factor, lores_shift; + +/* The shift factor to apply when converting between Amiga coordinates and window + coordinates. Zero if the resolution is the same, positive if window coordinates + have a higher resolution (i.e. we're stretching the image), negative if window + coordinates have a lower resolution (i.e. we're shrinking the image). */ +static int res_shift; + +static int interlace_seen = 0; +#define AUTO_LORES_FRAMES 10 +static int can_use_lores = 0; + +/* Lookup tables for dual playfields. The dblpf_*1 versions are for the case + that playfield 1 has the priority, dbplpf_*2 are used if playfield 2 has + priority. If we need an array for non-dual playfield mode, it has no number. */ +/* The dbplpf_ms? arrays contain a shift value. plf_spritemask is initialized + to contain two 16 bit words, with the appropriate mask if pf1 is in the + foreground being at bit offset 0, the one used if pf2 is in front being at + offset 16. */ + +static int dblpf_ms1[256], dblpf_ms2[256], dblpf_ms[256]; +static int dblpf_ind1[256], dblpf_ind2[256]; + +static int dblpf_2nd1[256], dblpf_2nd2[256]; + +static int dblpfofs[] = { 0, 2, 4, 8, 16, 32, 64, 128 }; + +static int sprite_offs[256]; + +static uae_u32 clxtab[256]; + +/* Video buffer description structure. Filled in by the graphics system + * dependent code. */ + +struct vidbuf_description gfxvidinfo; + +/* OCS/ECS color lookup table. */ +xcolnr xcolors[4096]; + +#ifdef AGA +static uae_u8 spriteagadpfpixels[MAX_PIXELS_PER_LINE * 2]; /* AGA dualplayfield sprite */ +/* AGA mode color lookup tables */ +unsigned int xredcolors[256], xgreencolors[256], xbluecolors[256]; +static int dblpf_ind1_aga[256], dblpf_ind2_aga[256]; +#else +static uae_u8 spriteagadpfpixels[1]; +static int dblpf_ind1_aga[1], dblpf_ind2_aga[1]; +#endif + +struct color_entry colors_for_drawing; + +/* The size of these arrays is pretty arbitrary; it was chosen to be "more + than enough". The coordinates used for indexing into these arrays are + almost, but not quite, Amiga coordinates (there's a constant offset). */ +union { + /* Let's try to align this thing. */ + double uupzuq; + long int cruxmedo; + uae_u8 apixels[MAX_PIXELS_PER_LINE * 2]; + uae_u16 apixels_w[MAX_PIXELS_PER_LINE * 2 / 2]; + uae_u32 apixels_l[MAX_PIXELS_PER_LINE * 2 / 4]; +} pixdata; + +uae_u16 spixels[2 * MAX_SPR_PIXELS]; +/* Eight bits for every pixel. */ +union sps_union spixstate; + +static uae_u32 ham_linebuf[MAX_PIXELS_PER_LINE * 2]; + +char *xlinebuffer; + +static int *amiga2aspect_line_map, *native2amiga_line_map; +static char *row_map[MAX_VIDHEIGHT]; +static int max_drawn_amiga_line; + +/* line_draw_funcs: pfield_do_linetoscr, pfield_do_fill_line, decode_ham */ +typedef void (*line_draw_func)(int, int); + +#define LINE_UNDECIDED 1 +#define LINE_DECIDED 2 +#define LINE_DECIDED_DOUBLE 3 +#define LINE_AS_PREVIOUS 4 +#define LINE_BLACK 5 +#define LINE_REMEMBERED_AS_BLACK 6 +#define LINE_DONE 7 +#define LINE_DONE_AS_PREVIOUS 8 +#define LINE_REMEMBERED_AS_PREVIOUS 9 + +static char *line_drawn; +static char linestate[(MAXVPOS + 1)*2 + 1]; + +uae_u8 line_data[(MAXVPOS + 1) * 2][MAX_PLANES * MAX_WORDS_PER_LINE * 2]; + +/* Centering variables. */ +static int min_diwstart, max_diwstop, prev_x_adjust; +/* The visible window: VISIBLE_LEFT_BORDER contains the left border of the visible + area, VISIBLE_RIGHT_BORDER the right border. These are in window coordinates. */ +static int visible_left_border, visible_right_border; +static int linetoscr_x_adjust_bytes; +static int thisframe_y_adjust, prev_y_adjust; +static int thisframe_y_adjust_real, max_ypos_thisframe, min_ypos_for_screen; +static int extra_y_adjust; +int thisframe_first_drawn_line, thisframe_last_drawn_line; + +/* A frame counter that forces a redraw after at least one skipped frame in + interlace mode. */ +static int last_redraw_point; + +static int first_drawn_line, last_drawn_line; +static int first_block_line, last_block_line; + +/* These are generated by the drawing code from the line_decisions array for + each line that needs to be drawn. These are basically extracted out of + bit fields in the hardware registers. */ +static int bplehb, bplham, bpldualpf, bpldualpfpri, bpldualpf2of, bplplanecnt, bplres; +static int plf1pri, plf2pri; +static uae_u32 plf_sprite_mask; +static int sbasecol[2] = { 16, 16 }; +static int brdsprt, brdblank; + +int picasso_requested_on; +int picasso_on; + +uae_sem_t gui_sem; +int inhibit_frame; + +int framecnt = 0; +static int frame_redraw_necessary; +static int picasso_redraw_necessary; + +STATIC_INLINE void count_frame (void) +{ + framecnt++; + if (framecnt >= currprefs.gfx_framerate) + framecnt = 0; +} + +int coord_native_to_amiga_x (int x) +{ + x += visible_left_border; + x <<= (1 - lores_shift); + return x + 2*DISPLAY_LEFT_SHIFT - 2*DIW_DDF_OFFSET; +} + +int coord_native_to_amiga_y (int y) +{ + return native2amiga_line_map[y] + thisframe_y_adjust - minfirstline; +} + +STATIC_INLINE int res_shift_from_window (int x) +{ + if (res_shift >= 0) + return x >> res_shift; + return x << -res_shift; +} + +STATIC_INLINE int res_shift_from_amiga (int x) +{ + if (res_shift >= 0) + return x >> res_shift; + return x << -res_shift; +} + +void notice_screen_contents_lost (void) +{ + picasso_redraw_necessary = 1; + frame_redraw_necessary = 2; +} + +static struct decision *dp_for_drawing; +static struct draw_info *dip_for_drawing; + +/* Record DIW of the current line for use by centering code. */ +void record_diw_line (int first, int last) +{ + if (last > max_diwstop) + max_diwstop = last; + if (first < min_diwstart) + min_diwstart = first; +} + +/* + * Screen update macros/functions + */ + +/* The important positions in the line: where do we start drawing the left border, + where do we start drawing the playfield, where do we start drawing the right border. + All of these are forced into the visible window (VISIBLE_LEFT_BORDER .. VISIBLE_RIGHT_BORDER). + PLAYFIELD_START and PLAYFIELD_END are in window coordinates. */ +static int playfield_start, playfield_end; +static int real_playfield_start, real_playfield_end; + +static int pixels_offset; +static int src_pixel; +/* How many pixels in window coordinates which are to the left of the left border. */ +static int unpainted; + +/* Initialize the variables necessary for drawing a line. + * This involves setting up start/stop positions and display window + * borders. */ +static void pfield_init_linetoscr (void) +{ + /* First, get data fetch start/stop in DIW coordinates. */ + int ddf_left = dp_for_drawing->plfleft * 2 + DIW_DDF_OFFSET; + int ddf_right = dp_for_drawing->plfright * 2 + DIW_DDF_OFFSET; + /* Compute datafetch start/stop in pixels; native display coordinates. */ + int native_ddf_left = coord_hw_to_window_x (ddf_left); + int native_ddf_right = coord_hw_to_window_x (ddf_right); + + int linetoscr_diw_start = dp_for_drawing->diwfirstword; + int linetoscr_diw_end = dp_for_drawing->diwlastword; + + if (dip_for_drawing->nr_sprites == 0) { + if (linetoscr_diw_start < native_ddf_left) + linetoscr_diw_start = native_ddf_left; + if (linetoscr_diw_end > native_ddf_right) + linetoscr_diw_end = native_ddf_right; + } + + /* Perverse cases happen. */ + if (linetoscr_diw_end < linetoscr_diw_start) + linetoscr_diw_end = linetoscr_diw_start; + + playfield_start = linetoscr_diw_start; + playfield_end = linetoscr_diw_end; + + if (playfield_start < visible_left_border) + playfield_start = visible_left_border; + if (playfield_start > visible_right_border) + playfield_start = visible_right_border; + if (playfield_end < visible_left_border) + playfield_end = visible_left_border; + if (playfield_end > visible_right_border) + playfield_end = visible_right_border; + + real_playfield_end = playfield_end; + real_playfield_start = playfield_start; +#ifdef AGA + if (brdsprt && dip_for_drawing->nr_sprites) { + int min = visible_right_border, max = visible_left_border, i; + for (i = 0; i < dip_for_drawing->nr_sprites; i++) { + int x; + x = curr_sprite_entries[dip_for_drawing->first_sprite_entry + i].pos; + if (x < min) min = x; + x = curr_sprite_entries[dip_for_drawing->first_sprite_entry + i].max; + if (x > max) max = x; + } + min += (DIW_DDF_OFFSET - DISPLAY_LEFT_SHIFT) << (2 - lores_shift); + max += (DIW_DDF_OFFSET - DISPLAY_LEFT_SHIFT) << (2 - lores_shift); + if (min < playfield_start) + playfield_start = min; + if (playfield_start < visible_left_border) + playfield_start = visible_left_border; + if (max > playfield_end) + playfield_end = max; + if (playfield_end > visible_right_border) + playfield_end = visible_right_border; + } +#endif + /* Now, compute some offsets. */ + + res_shift = lores_shift - bplres; + ddf_left -= DISPLAY_LEFT_SHIFT; + ddf_left <<= bplres; + pixels_offset = MAX_PIXELS_PER_LINE - ddf_left; + + unpainted = visible_left_border < playfield_start ? 0 : visible_left_border - playfield_start; + src_pixel = MAX_PIXELS_PER_LINE + res_shift_from_window (playfield_start - native_ddf_left + unpainted); + + if (dip_for_drawing->nr_sprites == 0) + return; + /* Must clear parts of apixels. */ + if (linetoscr_diw_start < native_ddf_left) { + int size = res_shift_from_window (native_ddf_left - linetoscr_diw_start); + linetoscr_diw_start = native_ddf_left; + memset (pixdata.apixels + MAX_PIXELS_PER_LINE - size, 0, size); + } + if (linetoscr_diw_end > native_ddf_right) { + int pos = res_shift_from_window (native_ddf_right - native_ddf_left); + int size = res_shift_from_window (linetoscr_diw_end - native_ddf_right); + linetoscr_diw_start = native_ddf_left; + memset (pixdata.apixels + MAX_PIXELS_PER_LINE + pos, 0, size); + } +} + +/* If C++ compilers didn't suck, we'd use templates. */ + +#define TYPE uae_u8 +#define LNAME linetoscr_8 +#define SRC_INC 1 +#define HDOUBLE 0 +#define AGAC 0 +#include "linetoscr.c" +#define LNAME linetoscr_8_stretch1 +#define SRC_INC 1 +#define HDOUBLE 1 +#define AGAC 0 +#include "linetoscr.c" +#define LNAME linetoscr_8_shrink1 +#define SRC_INC 2 +#define HDOUBLE 0 +#define AGAC 0 +#include "linetoscr.c" + +#ifdef AGA +#define LNAME linetoscr_8_aga +#define SRC_INC 1 +#define HDOUBLE 0 +#define AGAC 1 +#include "linetoscr.c" +#define LNAME linetoscr_8_stretch1_aga +#define SRC_INC 1 +#define HDOUBLE 1 +#define AGAC 1 +#include "linetoscr.c" +#define LNAME linetoscr_8_shrink1_aga +#define SRC_INC 2 +#define HDOUBLE 0 +#define AGAC 1 +#include "linetoscr.c" +#endif + +#undef TYPE + +#define TYPE uae_u16 +#define LNAME linetoscr_16 +#define SRC_INC 1 +#define HDOUBLE 0 +#define AGAC 0 +#include "linetoscr.c" +#define LNAME linetoscr_16_stretch1 +#define SRC_INC 1 +#define HDOUBLE 1 +#define AGAC 0 +#include "linetoscr.c" +#define LNAME linetoscr_16_shrink1 +#define SRC_INC 2 +#define HDOUBLE 0 +#define AGAC 0 +#include "linetoscr.c" + +#ifdef AGA +#define LNAME linetoscr_16_aga +#define SRC_INC 1 +#define HDOUBLE 0 +#define AGAC 1 +#include "linetoscr.c" +#define LNAME linetoscr_16_stretch1_aga +#define SRC_INC 1 +#define HDOUBLE 1 +#define AGAC 1 +#include "linetoscr.c" +#define LNAME linetoscr_16_shrink1_aga +#define SRC_INC 2 +#define HDOUBLE 0 +#define AGAC 1 +#include "linetoscr.c" +#endif + +#undef TYPE + +#define TYPE uae_u32 +#define LNAME linetoscr_32 +#define SRC_INC 1 +#define HDOUBLE 0 +#define AGAC 0 +#include "linetoscr.c" +#define LNAME linetoscr_32_stretch1 +#define SRC_INC 1 +#define HDOUBLE 1 +#define AGAC 0 +#include "linetoscr.c" +#define LNAME linetoscr_32_shrink1 +#define SRC_INC 2 +#define HDOUBLE 0 +#define AGAC 0 +#include "linetoscr.c" + +#ifdef AGA +#define LNAME linetoscr_32_aga +#define SRC_INC 1 +#define HDOUBLE 0 +#define AGAC 1 +#include "linetoscr.c" +#define LNAME linetoscr_32_stretch1_aga +#define SRC_INC 1 +#define HDOUBLE 1 +#define AGAC 1 +#include "linetoscr.c" +#define LNAME linetoscr_32_shrink1_aga +#define SRC_INC 2 +#define HDOUBLE 0 +#define AGAC 1 +#include "linetoscr.c" +#endif + +#undef TYPE + +static void fill_line_8 (char *buf, int start, int stop) +{ + uae_u8 *b = (uae_u8 *)buf; + int i; + xcolnr col = brdblank ? 0 : colors_for_drawing.acolors[0]; + for (i = start; i < stop; i++) + b[i] = (uae_u8)col; +} +static void fill_line_16 (char *buf, int start, int stop) +{ + uae_u16 *b = (uae_u16 *)buf; + int i; + xcolnr col = brdblank ? 0 : colors_for_drawing.acolors[0]; + for (i = start; i < stop; i++) + b[i] = (uae_u16)col; +} +static void fill_line_32 (char *buf, int start, int stop) +{ + uae_u32 *b = (uae_u32 *)buf; + int i; + xcolnr col = brdblank ? 0 : colors_for_drawing.acolors[0]; + for (i = start; i < stop; i++) + b[i] = col; +} + +STATIC_INLINE void fill_line (void) +{ + int shift; + int nints, nrem; + int *start; + xcolnr val; + + shift = 0; + if (gfxvidinfo.pixbytes == 2) + shift = 1; + if (gfxvidinfo.pixbytes == 4) + shift = 2; + + nints = gfxvidinfo.width >> (2-shift); + nrem = nints & 7; + nints &= ~7; + start = (int *)(((char *)xlinebuffer) + (visible_left_border << shift)); +#ifdef AGA + val = brdblank ? 0 : colors_for_drawing.acolors[0]; +#else + val = colors_for_drawing.acolors[0]; +#endif + if (gfxvidinfo.pixbytes == 2) + val |= val << 16; + for (; nints > 0; nints -= 8, start += 8) { + *start = val; + *(start+1) = val; + *(start+2) = val; + *(start+3) = val; + *(start+4) = val; + *(start+5) = val; + *(start+6) = val; + *(start+7) = val; + } + + switch (nrem) { + case 7: + *start++ = val; + case 6: + *start++ = val; + case 5: + *start++ = val; + case 4: + *start++ = val; + case 3: + *start++ = val; + case 2: + *start++ = val; + case 1: + *start = val; + } +} + +static int linetoscr_double_offset; + +static void pfield_do_linetoscr (int start, int stop) +{ +#ifdef AGA + if (currprefs.chipset_mask & CSMASK_AGA) { + if (res_shift == 0) + switch (gfxvidinfo.pixbytes) { + case 1: src_pixel = linetoscr_8_aga (src_pixel, start, stop); break; + case 2: src_pixel = linetoscr_16_aga (src_pixel, start, stop); break; + case 4: src_pixel = linetoscr_32_aga (src_pixel, start, stop); break; + } + else if (res_shift > 0) + switch (gfxvidinfo.pixbytes) { + case 1: src_pixel = linetoscr_8_stretch1_aga (src_pixel, start, stop); break; + case 2: src_pixel = linetoscr_16_stretch1_aga (src_pixel, start, stop); break; + case 4: src_pixel = linetoscr_32_stretch1_aga (src_pixel, start, stop); break; + } + else if (res_shift < 0) + switch (gfxvidinfo.pixbytes) { + case 1: src_pixel = linetoscr_8_shrink1_aga (src_pixel, start, stop); break; + case 2: src_pixel = linetoscr_16_shrink1_aga (src_pixel, start, stop); break; + case 4: src_pixel = linetoscr_32_shrink1_aga (src_pixel, start, stop); break; + } + } else { +#endif + if (res_shift == 0) + switch (gfxvidinfo.pixbytes) { + case 1: src_pixel = linetoscr_8 (src_pixel, start, stop); break; + case 2: src_pixel = linetoscr_16 (src_pixel, start, stop); break; + case 4: src_pixel = linetoscr_32 (src_pixel, start, stop); break; + } + else if (res_shift > 0) + switch (gfxvidinfo.pixbytes) { + case 1: src_pixel = linetoscr_8_stretch1 (src_pixel, start, stop); break; + case 2: src_pixel = linetoscr_16_stretch1 (src_pixel, start, stop); break; + case 4: src_pixel = linetoscr_32_stretch1 (src_pixel, start, stop); break; + } + else if (res_shift < 0) + switch (gfxvidinfo.pixbytes) { + case 1: src_pixel = linetoscr_8_shrink1 (src_pixel, start, stop); break; + case 2: src_pixel = linetoscr_16_shrink1 (src_pixel, start, stop); break; + case 4: src_pixel = linetoscr_32_shrink1 (src_pixel, start, stop); break; + } +#ifdef AGA + } +#endif +} + +static void pfield_do_fill_line (int start, int stop) +{ + switch (gfxvidinfo.pixbytes) { + case 1: fill_line_8 (xlinebuffer, start, stop); break; + case 2: fill_line_16 (xlinebuffer, start, stop); break; + case 4: fill_line_32 (xlinebuffer, start, stop); break; + } +} + +static void pfield_do_linetoscr_full (int double_line) +{ + char *oldxlb = (char *)xlinebuffer; + int old_src_pixel = src_pixel; + + pfield_do_linetoscr (playfield_start, playfield_end); + xlinebuffer = oldxlb + linetoscr_double_offset; + src_pixel = old_src_pixel; + pfield_do_linetoscr (playfield_start, playfield_end); +} + +static void dummy_worker (int start, int stop) +{ +} + +static unsigned int ham_lastcolor; + +static int ham_decode_pixel; + +/* Decode HAM in the invisible portion of the display (left of VISIBLE_LEFT_BORDER), + but don't draw anything in. This is done to prepare HAM_LASTCOLOR for later, + when decode_ham runs. */ +static void init_ham_decoding (void) +{ + int unpainted_amiga = res_shift_from_window (unpainted); + ham_decode_pixel = src_pixel; + ham_lastcolor = color_reg_get (&colors_for_drawing, 0); + + if (! bplham || (bplplanecnt != 6 && ((currprefs.chipset_mask & CSMASK_AGA) == 0 || bplplanecnt != 8))) { + if (unpainted_amiga > 0) { + int pv = pixdata.apixels[ham_decode_pixel + unpainted_amiga - 1]; +#ifdef AGA + if (currprefs.chipset_mask & CSMASK_AGA) + ham_lastcolor = colors_for_drawing.color_regs_aga[pv]; + else +#endif + ham_lastcolor = colors_for_drawing.color_regs_ecs[pv]; + } +#ifdef AGA + } else if (currprefs.chipset_mask & CSMASK_AGA) { + if (bplplanecnt == 8) { /* AGA mode HAM8 */ + while (unpainted_amiga-- > 0) { + int pv = pixdata.apixels[ham_decode_pixel++]; + switch (pv & 0x3) { + case 0x0: ham_lastcolor = colors_for_drawing.color_regs_aga[pv >> 2]; break; + case 0x1: ham_lastcolor &= 0xFFFF03; ham_lastcolor |= (pv & 0xFC); break; + case 0x2: ham_lastcolor &= 0x03FFFF; ham_lastcolor |= (pv & 0xFC) << 16; break; + case 0x3: ham_lastcolor &= 0xFF03FF; ham_lastcolor |= (pv & 0xFC) << 8; break; + } + } + } else if (bplplanecnt == 6) { /* AGA mode HAM6 */ + while (unpainted_amiga-- > 0) { + int pv = pixdata.apixels[ham_decode_pixel++]; + switch (pv & 0x30) { + case 0x00: ham_lastcolor = colors_for_drawing.color_regs_aga[pv]; break; + case 0x10: ham_lastcolor &= 0xFFFF00; ham_lastcolor |= (pv & 0xF) << 4; break; + case 0x20: ham_lastcolor &= 0x00FFFF; ham_lastcolor |= (pv & 0xF) << 20; break; + case 0x30: ham_lastcolor &= 0xFF00FF; ham_lastcolor |= (pv & 0xF) << 12; break; + } + } + } +#endif + } else { + if (bplplanecnt == 6) { /* OCS/ECS mode HAM6 */ + while (unpainted_amiga-- > 0) { + int pv = pixdata.apixels[ham_decode_pixel++]; + switch (pv & 0x30) { + case 0x00: ham_lastcolor = colors_for_drawing.color_regs_ecs[pv]; break; + case 0x10: ham_lastcolor &= 0xFF0; ham_lastcolor |= (pv & 0xF); break; + case 0x20: ham_lastcolor &= 0x0FF; ham_lastcolor |= (pv & 0xF) << 8; break; + case 0x30: ham_lastcolor &= 0xF0F; ham_lastcolor |= (pv & 0xF) << 4; break; + } + } + } + } +} + +static void decode_ham (int pix, int stoppos) +{ + int todraw_amiga = res_shift_from_window (stoppos - pix); + + if (! bplham || (bplplanecnt != 6 && ((currprefs.chipset_mask & CSMASK_AGA) == 0 || bplplanecnt != 8))) { + while (todraw_amiga-- > 0) { + int pv = pixdata.apixels[ham_decode_pixel]; +#ifdef AGA + if (currprefs.chipset_mask & CSMASK_AGA) + ham_lastcolor = colors_for_drawing.color_regs_aga[pv]; + else +#endif + ham_lastcolor = colors_for_drawing.color_regs_ecs[pv]; + + ham_linebuf[ham_decode_pixel++] = ham_lastcolor; + } +#ifdef AGA + } else if (currprefs.chipset_mask & CSMASK_AGA) { + if (bplplanecnt == 8) { /* AGA mode HAM8 */ + while (todraw_amiga-- > 0) { + int pv = pixdata.apixels[ham_decode_pixel]; + switch (pv & 0x3) { + case 0x0: ham_lastcolor = colors_for_drawing.color_regs_aga[pv >> 2]; break; + case 0x1: ham_lastcolor &= 0xFFFF03; ham_lastcolor |= (pv & 0xFC); break; + case 0x2: ham_lastcolor &= 0x03FFFF; ham_lastcolor |= (pv & 0xFC) << 16; break; + case 0x3: ham_lastcolor &= 0xFF03FF; ham_lastcolor |= (pv & 0xFC) << 8; break; + } + ham_linebuf[ham_decode_pixel++] = ham_lastcolor; + } + } else if (bplplanecnt == 6) { /* AGA mode HAM6 */ + while (todraw_amiga-- > 0) { + int pv = pixdata.apixels[ham_decode_pixel]; + switch (pv & 0x30) { + case 0x00: ham_lastcolor = colors_for_drawing.color_regs_aga[pv]; break; + case 0x10: ham_lastcolor &= 0xFFFF00; ham_lastcolor |= (pv & 0xF) << 4; break; + case 0x20: ham_lastcolor &= 0x00FFFF; ham_lastcolor |= (pv & 0xF) << 20; break; + case 0x30: ham_lastcolor &= 0xFF00FF; ham_lastcolor |= (pv & 0xF) << 12; break; + } + ham_linebuf[ham_decode_pixel++] = ham_lastcolor; + } + } +#endif + } else { + if (bplplanecnt == 6) { /* OCS/ECS mode HAM6 */ + while (todraw_amiga-- > 0) { + int pv = pixdata.apixels[ham_decode_pixel]; + switch (pv & 0x30) { + case 0x00: ham_lastcolor = colors_for_drawing.color_regs_ecs[pv]; break; + case 0x10: ham_lastcolor &= 0xFF0; ham_lastcolor |= (pv & 0xF); break; + case 0x20: ham_lastcolor &= 0x0FF; ham_lastcolor |= (pv & 0xF) << 8; break; + case 0x30: ham_lastcolor &= 0xF0F; ham_lastcolor |= (pv & 0xF) << 4; break; + } + ham_linebuf[ham_decode_pixel++] = ham_lastcolor; + } + } + } +} + +static void gen_pfield_tables (void) +{ + int i; + + /* For now, the AGA stuff is broken in the dual playfield case. We encode + * sprites in dpf mode by ORing the pixel value with 0x80. To make dual + * playfield rendering easy, the lookup tables contain are made linear for + * values >= 128. That only works for OCS/ECS, though. */ + + for (i = 0; i < 256; i++) { + int plane1 = (i & 1) | ((i >> 1) & 2) | ((i >> 2) & 4) | ((i >> 3) & 8); + int plane2 = ((i >> 1) & 1) | ((i >> 2) & 2) | ((i >> 3) & 4) | ((i >> 4) & 8); + + dblpf_2nd1[i] = plane1 == 0 ? (plane2 == 0 ? 0 : 2) : 1; + dblpf_2nd2[i] = plane2 == 0 ? (plane1 == 0 ? 0 : 1) : 2; + +#ifdef AGA + dblpf_ind1_aga[i] = plane1 == 0 ? plane2 : plane1; + dblpf_ind2_aga[i] = plane2 == 0 ? plane1 : plane2; +#endif + + dblpf_ms1[i] = plane1 == 0 ? (plane2 == 0 ? 16 : 8) : 0; + dblpf_ms2[i] = plane2 == 0 ? (plane1 == 0 ? 16 : 0) : 8; + dblpf_ms[i] = i == 0 ? 16 : 8; + if (plane2 > 0) + plane2 += 8; + dblpf_ind1[i] = i >= 128 ? i & 0x7F : (plane1 == 0 ? plane2 : plane1); + dblpf_ind2[i] = i >= 128 ? i & 0x7F : (plane2 == 0 ? plane1 : plane2); + + sprite_offs[i] = (i & 15) ? 0 : 2; + + clxtab[i] = ((((i & 3) && (i & 12)) << 9) + | (((i & 3) && (i & 48)) << 10) + | (((i & 3) && (i & 192)) << 11) + | (((i & 12) && (i & 48)) << 12) + | (((i & 12) && (i & 192)) << 13) + | (((i & 48) && (i & 192)) << 14)); + + } +} + +#define SPRITE_DEBUG 0 + +/* When looking at this function and the ones that inline it, bear in mind + what an optimizing compiler will do with this code. All callers of this + function only pass in constant arguments (except for E). This means + that many of the if statements will go away completely after inlining. */ +STATIC_INLINE void draw_sprites_1 (struct sprite_entry *e, int ham, int dualpf, + int doubling, int skip, int has_attach, int aga) +{ + int *shift_lookup = dualpf ? (bpldualpfpri ? dblpf_ms2 : dblpf_ms1) : dblpf_ms; + uae_u16 *buf = spixels + e->first_pixel; + uae_u8 *stbuf = spixstate.bytes + e->first_pixel; + int pos, window_pos; +#ifdef AGA + uae_u8 xor_val = (uae_u8)(dp_for_drawing->bplcon4 >> 8); +#endif + + buf -= e->pos; + stbuf -= e->pos; + + window_pos = e->pos + ((DIW_DDF_OFFSET - DISPLAY_LEFT_SHIFT) << (aga ? 1 : 0)); + if (skip) + window_pos >>= 1; + else if (doubling) + window_pos <<= 1; + window_pos += pixels_offset; + for (pos = e->pos; pos < e->max; pos += 1 << skip) { + int maskshift, plfmask; + unsigned int v = buf[pos]; + + /* The value in the shift lookup table is _half_ the shift count we + need. This is because we can't shift 32 bits at once (undefined + behaviour in C). */ + maskshift = shift_lookup[pixdata.apixels[window_pos]]; + plfmask = (plf_sprite_mask >> maskshift) >> maskshift; + v &= ~plfmask; + if (v != 0 || SPRITE_DEBUG) { + unsigned int vlo, vhi, col; + unsigned int v1 = v & 255; + /* OFFS determines the sprite pair with the highest priority that has + any bits set. E.g. if we have 0xFF00 in the buffer, we have sprite + pairs 01 and 23 cleared, and pairs 45 and 67 set, so OFFS will + have a value of 4. + 2 * OFFS is the bit number in V of the sprite pair, and it also + happens to be the color offset for that pair. */ + int offs; + if (v1 == 0) + offs = 4 + sprite_offs[v >> 8]; + else + offs = sprite_offs[v1]; + + /* Shift highest priority sprite pair down to bit zero. */ + v >>= offs * 2; + v &= 15; +#if SPRITE_DEBUG > 0 + v |= 1 | 4; +#endif + + if (has_attach && (stbuf[pos] & (3 << offs))) { + col = v; + if (aga) + col += sbasecol[1]; + else + col += 16; + } else { + /* This sequence computes the correct color value. We have to select + either the lower-numbered or the higher-numbered sprite in the pair. + We have to select the high one if the low one has all bits zero. + If the lower-numbered sprite has any bits nonzero, (VLO - 1) is in + the range of 0..2, and with the mask and shift, VHI will be zero. + If the lower-numbered sprite is zero, (VLO - 1) is a mask of + 0xFFFFFFFF, and we select the bits of the higher numbered sprite + in VHI. + This is _probably_ more efficient than doing it with branches. */ + vlo = v & 3; + vhi = (v & (vlo - 1)) >> 2; + col = (vlo | vhi); + if (aga) { + if (vhi > 0) + col += sbasecol[1]; + else + col += sbasecol[0]; + } else { + col += 16; + } + col += (offs * 2); + } + if (dualpf) { +#ifdef AGA + if (aga) { + spriteagadpfpixels[window_pos] = col; + if (doubling) + spriteagadpfpixels[window_pos + 1] = col; + } else { +#endif + col += 128; + if (doubling) + pixdata.apixels_w[window_pos >> 1] = col | (col << 8); + else + pixdata.apixels[window_pos] = col; +#ifdef AGA + } +#endif + } else if (ham) { + col = color_reg_get (&colors_for_drawing, col); +#ifdef AGA + if (aga) + col ^= xor_val; +#endif + ham_linebuf[window_pos] = col; + if (doubling) + ham_linebuf[window_pos + 1] = col; + } else { +#ifdef AGA + if (aga) + col ^= xor_val; +#endif + if (doubling) + pixdata.apixels_w[window_pos >> 1] = col | (col << 8); + else + pixdata.apixels[window_pos] = col; + } + } + window_pos += 1 << doubling; + } +} + +/* See comments above. Do not touch if you don't know what's going on. + * (We do _not_ want the following to be inlined themselves). */ +/* lores bitplane, lores sprites */ +static void draw_sprites_normal_sp_lo_nat (struct sprite_entry *e) { draw_sprites_1 (e, 0, 0, 0, 0, 0, 0); } +static void draw_sprites_normal_dp_lo_nat (struct sprite_entry *e) { draw_sprites_1 (e, 0, 1, 0, 0, 0, 0); } +static void draw_sprites_ham_sp_lo_nat (struct sprite_entry *e) { draw_sprites_1 (e, 1, 0, 0, 0, 0, 0); } +static void draw_sprites_normal_sp_lo_at (struct sprite_entry *e) { draw_sprites_1 (e, 0, 0, 0, 0, 1, 0); } +static void draw_sprites_normal_dp_lo_at (struct sprite_entry *e) { draw_sprites_1 (e, 0, 1, 0, 0, 1, 0); } +static void draw_sprites_ham_sp_lo_at (struct sprite_entry *e) { draw_sprites_1 (e, 1, 0, 0, 0, 1, 0); } +/* hires bitplane, lores sprites */ +static void draw_sprites_normal_sp_hi_nat (struct sprite_entry *e) { draw_sprites_1 (e, 0, 0, 1, 0, 0, 0); } +static void draw_sprites_normal_dp_hi_nat (struct sprite_entry *e) { draw_sprites_1 (e, 0, 1, 1, 0, 0, 0); } +static void draw_sprites_ham_sp_hi_nat (struct sprite_entry *e) { draw_sprites_1 (e, 1, 0, 1, 0, 0, 0); } +static void draw_sprites_normal_sp_hi_at (struct sprite_entry *e) { draw_sprites_1 (e, 0, 0, 1, 0, 1, 0); } +static void draw_sprites_normal_dp_hi_at (struct sprite_entry *e) { draw_sprites_1 (e, 0, 1, 1, 0, 1, 0); } +static void draw_sprites_ham_sp_hi_at (struct sprite_entry *e) { draw_sprites_1 (e, 1, 0, 1, 0, 1, 0); } + +#ifdef AGA +/* not very optimized */ +STATIC_INLINE void draw_sprites_aga (struct sprite_entry *e) +{ + int diff = RES_HIRES - bplres; + if (diff > 0) + draw_sprites_1 (e, dp_for_drawing->ham_seen, bpldualpf, 0, diff, e->has_attached, 1); + else + draw_sprites_1 (e, dp_for_drawing->ham_seen, bpldualpf, -diff, 0, e->has_attached, 1); +} +#endif + +STATIC_INLINE void draw_sprites_ecs (struct sprite_entry *e) +{ + if (e->has_attached) + if (bplres == 1) + if (dp_for_drawing->ham_seen) + draw_sprites_ham_sp_hi_at (e); + else + if (bpldualpf) + draw_sprites_normal_dp_hi_at (e); + else + draw_sprites_normal_sp_hi_at (e); + else + if (dp_for_drawing->ham_seen) + draw_sprites_ham_sp_lo_at (e); + else + if (bpldualpf) + draw_sprites_normal_dp_lo_at (e); + else + draw_sprites_normal_sp_lo_at (e); + else + if (bplres == 1) + if (dp_for_drawing->ham_seen) + draw_sprites_ham_sp_hi_nat (e); + else + if (bpldualpf) + draw_sprites_normal_dp_hi_nat (e); + else + draw_sprites_normal_sp_hi_nat (e); + else + if (dp_for_drawing->ham_seen) + draw_sprites_ham_sp_lo_nat (e); + else + if (bpldualpf) + draw_sprites_normal_dp_lo_nat (e); + else + draw_sprites_normal_sp_lo_nat (e); +} + +#ifdef AGA +/* clear possible bitplane data outside DIW area */ +static void clear_bitplane_border_aga (void) +{ + int len, shift = lores_shift - bplres; + uae_u8 v = 0; + if (shift < 0) { + shift = -shift; + len = (real_playfield_start - playfield_start) << shift; + memset (pixdata.apixels + pixels_offset + (playfield_start << shift), v, len); + len = (playfield_end - real_playfield_end) << shift; + memset (pixdata.apixels + pixels_offset + (real_playfield_end << shift), v, len); + } else { + len = (real_playfield_start - playfield_start) >> shift; + memset (pixdata.apixels + pixels_offset + (playfield_start >> shift), v, len); + len = (playfield_end - real_playfield_end) >> shift; + memset (pixdata.apixels + pixels_offset + (real_playfield_end >> shift), v, len); + } +} +#endif + +/* emulate OCS/ECS only undocumented "SWIV" hardware feature */ +static void weird_bitplane_fix (void) +{ + int i, shift = lores_shift - bplres; + + if (shift < 0) { + shift = -shift; + for (i = playfield_start << lores_shift; i < playfield_end << lores_shift; i++) { + if (pixdata.apixels[pixels_offset + i] > 16) + pixdata.apixels[pixels_offset + i] = 16; + } + } else { + for (i = playfield_start >> lores_shift; i < playfield_end >> lores_shift; i++) { + if (pixdata.apixels[pixels_offset + i] > 16) + pixdata.apixels[pixels_offset + i] = 16; + } + } +} + +#define MERGE(a,b,mask,shift) do {\ + uae_u32 tmp = mask & (a ^ (b >> shift)); \ + a ^= tmp; \ + b ^= (tmp << shift); \ +} while (0) + +#define GETLONG(P) (*(uae_u32 *)P) + +/* We use the compiler's inlining ability to ensure that PLANES is in effect a compile time + constant. That will cause some unnecessary code to be optimized away. + Don't touch this if you don't know what you are doing. */ +STATIC_INLINE void pfield_doline_1 (uae_u32 *pixels, int wordcount, int planes) +{ + while (wordcount-- > 0) { + uae_u32 b0, b1, b2, b3, b4, b5, b6, b7; + + b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0, b6 = 0, b7 = 0; + switch (planes) { + case 8: b0 = GETLONG ((uae_u32 *)real_bplpt[7]); real_bplpt[7] += 4; + case 7: b1 = GETLONG ((uae_u32 *)real_bplpt[6]); real_bplpt[6] += 4; + case 6: b2 = GETLONG ((uae_u32 *)real_bplpt[5]); real_bplpt[5] += 4; + case 5: b3 = GETLONG ((uae_u32 *)real_bplpt[4]); real_bplpt[4] += 4; + case 4: b4 = GETLONG ((uae_u32 *)real_bplpt[3]); real_bplpt[3] += 4; + case 3: b5 = GETLONG ((uae_u32 *)real_bplpt[2]); real_bplpt[2] += 4; + case 2: b6 = GETLONG ((uae_u32 *)real_bplpt[1]); real_bplpt[1] += 4; + case 1: b7 = GETLONG ((uae_u32 *)real_bplpt[0]); real_bplpt[0] += 4; + } + + MERGE (b0, b1, 0x55555555, 1); + MERGE (b2, b3, 0x55555555, 1); + MERGE (b4, b5, 0x55555555, 1); + MERGE (b6, b7, 0x55555555, 1); + + MERGE (b0, b2, 0x33333333, 2); + MERGE (b1, b3, 0x33333333, 2); + MERGE (b4, b6, 0x33333333, 2); + MERGE (b5, b7, 0x33333333, 2); + + MERGE (b0, b4, 0x0f0f0f0f, 4); + MERGE (b1, b5, 0x0f0f0f0f, 4); + MERGE (b2, b6, 0x0f0f0f0f, 4); + MERGE (b3, b7, 0x0f0f0f0f, 4); + + MERGE (b0, b1, 0x00ff00ff, 8); + MERGE (b2, b3, 0x00ff00ff, 8); + MERGE (b4, b5, 0x00ff00ff, 8); + MERGE (b6, b7, 0x00ff00ff, 8); + + MERGE (b0, b2, 0x0000ffff, 16); + do_put_mem_long (pixels, b0); + do_put_mem_long (pixels + 4, b2); + MERGE (b1, b3, 0x0000ffff, 16); + do_put_mem_long (pixels + 2, b1); + do_put_mem_long (pixels + 6, b3); + MERGE (b4, b6, 0x0000ffff, 16); + do_put_mem_long (pixels + 1, b4); + do_put_mem_long (pixels + 5, b6); + MERGE (b5, b7, 0x0000ffff, 16); + do_put_mem_long (pixels + 3, b5); + do_put_mem_long (pixels + 7, b7); + pixels += 8; + } +} + +/* See above for comments on inlining. These functions should _not_ + be inlined themselves. */ +static void pfield_doline_n1 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 1); } +static void pfield_doline_n2 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 2); } +static void pfield_doline_n3 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 3); } +static void pfield_doline_n4 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 4); } +static void pfield_doline_n5 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 5); } +static void pfield_doline_n6 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 6); } +#ifdef AGA +static void pfield_doline_n7 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 7); } +static void pfield_doline_n8 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 8); } +#endif + +static void pfield_doline (int lineno) +{ + int wordcount = dp_for_drawing->plflinelen; + uae_u32 *data = pixdata.apixels_l + MAX_PIXELS_PER_LINE/4; + +#ifdef SMART_UPDATE +#define DATA_POINTER(n) (line_data[lineno] + (n)*MAX_WORDS_PER_LINE*2) + real_bplpt[0] = DATA_POINTER (0); + real_bplpt[1] = DATA_POINTER (1); + real_bplpt[2] = DATA_POINTER (2); + real_bplpt[3] = DATA_POINTER (3); + real_bplpt[4] = DATA_POINTER (4); + real_bplpt[5] = DATA_POINTER (5); +#ifdef AGA + real_bplpt[6] = DATA_POINTER (6); + real_bplpt[7] = DATA_POINTER (7); +#endif +#endif + + switch (bplplanecnt) { + default: break; + case 0: memset (data, 0, wordcount * 32); break; + case 1: pfield_doline_n1 (data, wordcount); break; + case 2: pfield_doline_n2 (data, wordcount); break; + case 3: pfield_doline_n3 (data, wordcount); break; + case 4: pfield_doline_n4 (data, wordcount); break; + case 5: pfield_doline_n5 (data, wordcount); break; + case 6: pfield_doline_n6 (data, wordcount); break; +#ifdef AGA + case 7: pfield_doline_n7 (data, wordcount); break; + case 8: pfield_doline_n8 (data, wordcount); break; +#endif + } +} + +void init_row_map (void) +{ + int i; + if (gfxvidinfo.height > MAX_VIDHEIGHT) { + write_log ("Resolution too high, aborting\n"); + abort (); + } + for (i = 0; i < gfxvidinfo.height + 1; i++) + row_map[i] = gfxvidinfo.bufmem + gfxvidinfo.rowbytes * i; +} + +static void init_aspect_maps (void) +{ + int i, maxl; + double native_lines_per_amiga_line; + + if (native2amiga_line_map) + free (native2amiga_line_map); + if (amiga2aspect_line_map) + free (amiga2aspect_line_map); + + /* At least for this array the +1 is necessary. */ + amiga2aspect_line_map = (int *)malloc (sizeof (int) * (MAXVPOS + 1) * 2 + 1); + native2amiga_line_map = (int *)malloc (sizeof (int) * gfxvidinfo.height); + + if (currprefs.gfx_correct_aspect) + native_lines_per_amiga_line = ((double)gfxvidinfo.height + * (currprefs.gfx_lores ? 320 : 640) + / (currprefs.gfx_linedbl ? 512 : 256) + / gfxvidinfo.width); + else + native_lines_per_amiga_line = 1; + + maxl = (MAXVPOS + 1) * (currprefs.gfx_linedbl ? 2 : 1); + min_ypos_for_screen = minfirstline << (currprefs.gfx_linedbl ? 1 : 0); + max_drawn_amiga_line = -1; + for (i = 0; i < maxl; i++) { + int v = (int) ((i - min_ypos_for_screen) * native_lines_per_amiga_line); + if (v >= gfxvidinfo.height && max_drawn_amiga_line == -1) + max_drawn_amiga_line = i - min_ypos_for_screen; + if (i < min_ypos_for_screen || v >= gfxvidinfo.height) + v = -1; + amiga2aspect_line_map[i] = v; + } + if (currprefs.gfx_linedbl) + max_drawn_amiga_line >>= 1; + + if (currprefs.gfx_ycenter && !(currprefs.gfx_correct_aspect)) { + /* @@@ verify maxvpos vs. MAXVPOS */ + extra_y_adjust = (gfxvidinfo.height - (maxvpos << (currprefs.gfx_linedbl ? 1 : 0))) >> 1; + if (extra_y_adjust < 0) + extra_y_adjust = 0; + } + + for (i = 0; i < gfxvidinfo.height; i++) + native2amiga_line_map[i] = -1; + + if (native_lines_per_amiga_line < 1) { + /* Must omit drawing some lines. */ + for (i = maxl - 1; i > min_ypos_for_screen; i--) { + if (amiga2aspect_line_map[i] == amiga2aspect_line_map[i-1]) { + if (currprefs.gfx_linedbl && (i & 1) == 0 && amiga2aspect_line_map[i+1] != -1) { + /* If only the first line of a line pair would be omitted, + * omit the second one instead to avoid problems with line + * doubling. */ + amiga2aspect_line_map[i] = amiga2aspect_line_map[i+1]; + amiga2aspect_line_map[i+1] = -1; + } else + amiga2aspect_line_map[i] = -1; + } + } + } + + for (i = maxl-1; i >= min_ypos_for_screen; i--) { + int j; + if (amiga2aspect_line_map[i] == -1) + continue; + for (j = amiga2aspect_line_map[i]; j < gfxvidinfo.height && native2amiga_line_map[j] == -1; j++) + native2amiga_line_map[j] = i >> (currprefs.gfx_linedbl ? 1 : 0); + } +} + +/* + * A raster line has been built in the graphics buffer. Tell the graphics code + * to do anything necessary to display it. + */ +static void do_flush_line_1 (int lineno) +{ + if (lineno < first_drawn_line) + first_drawn_line = lineno; + if (lineno > last_drawn_line) + last_drawn_line = lineno; + + if (gfxvidinfo.maxblocklines == 0) + flush_line (lineno); + else { + if ((last_block_line+1) != lineno) { + if (first_block_line != -2) + flush_block (first_block_line, last_block_line); + first_block_line = lineno; + } + last_block_line = lineno; + if (last_block_line - first_block_line >= gfxvidinfo.maxblocklines) { + flush_block (first_block_line, last_block_line); + first_block_line = last_block_line = -2; + } + } +} + +STATIC_INLINE void do_flush_line (int lineno) +{ + do_flush_line_1 (lineno); +} + +/* + * One drawing frame has been finished. Tell the graphics code about it. + * Note that the actual flush_screen() call is a no-op for all reasonable + * systems. + */ + +STATIC_INLINE void do_flush_screen (int start, int stop) +{ + /* TODO: this flush operation is executed outside locked state! + Should be corrected. + (sjo 26.9.99) */ + + if (gfxvidinfo.maxblocklines != 0 && first_block_line != -2) { + flush_block (first_block_line, last_block_line); + } + unlockscr (); + if (start <= stop) + flush_screen (start, stop); + else if (currprefs.gfx_afullscreen && currprefs.gfx_vsync) + flush_screen (0, 0); /* vsync mode */ +} + +static int drawing_color_matches; +static enum { color_match_acolors, color_match_full } color_match_type; + +/* Set up colors_for_drawing to the state at the beginning of the currently drawn + line. Try to avoid copying color tables around whenever possible. */ +static void adjust_drawing_colors (int ctable, int need_full) +{ + if (drawing_color_matches != ctable) { + if (need_full) { + color_reg_cpy (&colors_for_drawing, curr_color_tables + ctable); + color_match_type = color_match_full; + } else { + memcpy (colors_for_drawing.acolors, curr_color_tables[ctable].acolors, + sizeof colors_for_drawing.acolors); + color_match_type = color_match_acolors; + } + drawing_color_matches = ctable; + } else if (need_full && color_match_type != color_match_full) { + color_reg_cpy (&colors_for_drawing, &curr_color_tables[ctable]); + color_match_type = color_match_full; + } +} + +STATIC_INLINE void do_color_changes (line_draw_func worker_border, line_draw_func worker_pfield) +{ + int i; + int lastpos = visible_left_border; + + for (i = dip_for_drawing->first_color_change; i <= dip_for_drawing->last_color_change; i++) { + int regno = curr_color_changes[i].regno; + unsigned int value = curr_color_changes[i].value; + int nextpos, nextpos_in_range; + if (i == dip_for_drawing->last_color_change) + nextpos = max_diwlastword; + else + nextpos = coord_hw_to_window_x (curr_color_changes[i].linepos * 2); + + nextpos_in_range = nextpos; + if (nextpos > visible_right_border) + nextpos_in_range = visible_right_border; + + if (nextpos_in_range > lastpos) { + if (lastpos < playfield_start) { + int t = nextpos_in_range <= playfield_start ? nextpos_in_range : playfield_start; + (*worker_border) (lastpos, t); + lastpos = t; + } + } + if (nextpos_in_range > lastpos) { + if (lastpos >= playfield_start && lastpos < playfield_end) { + int t = nextpos_in_range <= playfield_end ? nextpos_in_range : playfield_end; + (*worker_pfield) (lastpos, t); + lastpos = t; + } + } + if (nextpos_in_range > lastpos) { + if (lastpos >= playfield_end) + (*worker_border) (lastpos, nextpos_in_range); + lastpos = nextpos_in_range; + } + if (i != dip_for_drawing->last_color_change) { + if (regno == -1) + bplham = value; + else { + color_reg_set (&colors_for_drawing, regno, value); + colors_for_drawing.acolors[regno] = getxcolor (value); + } + } + if (lastpos >= visible_right_border) + break; + } +} + +/* We only save hardware registers during the hardware frame. Now, when + * drawing the frame, we expand the data into a slightly more useful + * form. */ +static void pfield_expand_dp_bplcon (void) +{ + bplres = dp_for_drawing->bplres; + bplplanecnt = dp_for_drawing->nr_planes; + bplham = dp_for_drawing->ham_at_start; + + if (bplres > 0) + can_use_lores = 0; + if (currprefs.chipset_mask & CSMASK_AGA) { + /* The KILLEHB bit exists in ECS, but is apparently meant for Genlock + * stuff, and it's set by some demos (e.g. Andromeda Seven Seas) */ + bplehb = ((dp_for_drawing->bplcon0 & 0x7010) == 0x6000 && !(dp_for_drawing->bplcon2 & 0x200)); + } else { + bplehb = (dp_for_drawing->bplcon0 & 0xFC00) == 0x6000; + } + plf1pri = dp_for_drawing->bplcon2 & 7; + plf2pri = (dp_for_drawing->bplcon2 >> 3) & 7; + plf_sprite_mask = 0xFFFF0000 << (4 * plf2pri); + plf_sprite_mask |= (0xFFFF << (4 * plf1pri)) & 0xFFFF; + bpldualpf = (dp_for_drawing->bplcon0 & 0x400) == 0x400; + bpldualpfpri = (dp_for_drawing->bplcon2 & 0x40) == 0x40; +#ifdef AGA + bpldualpf2of = (dp_for_drawing->bplcon3 >> 10) & 7; + sbasecol[0] = ((dp_for_drawing->bplcon4 >> 4) & 15) << 4; + sbasecol[1] = ((dp_for_drawing->bplcon4 >> 0) & 15) << 4; + + brdsprt = (currprefs.chipset_mask & CSMASK_AGA) && (dp_for_drawing->bplcon0 & 1) && (dp_for_drawing->bplcon3 & 0x02); + /* FIXME: we must update top and bottom borders when BRDBLANK changes */ + brdblank = (currprefs.chipset_mask & CSMASK_AGA) && (dp_for_drawing->bplcon0 & 1) && (dp_for_drawing->bplcon3 & 0x20); + if (brdblank) + brdsprt = 0; +#endif +} + +enum double_how { + dh_buf, + dh_line, + dh_emerg +}; + +STATIC_INLINE void pfield_draw_line (int lineno, int gfx_ypos, int follow_ypos) +{ + static int warned = 0; + int border = 0; + int do_double = 0; + enum double_how dh; + + dp_for_drawing = line_decisions + lineno; + dip_for_drawing = curr_drawinfo + lineno; + switch (linestate[lineno]) { + case LINE_REMEMBERED_AS_PREVIOUS: + if (!warned) + write_log ("Shouldn't get here... this is a bug.\n"), warned++; + return; + + case LINE_BLACK: + linestate[lineno] = LINE_REMEMBERED_AS_BLACK; + border = 2; + break; + + case LINE_REMEMBERED_AS_BLACK: + return; + + case LINE_AS_PREVIOUS: + dp_for_drawing--; + dip_for_drawing--; + if (dp_for_drawing->plfleft == -1) + border = 1; + linestate[lineno] = LINE_DONE_AS_PREVIOUS; + break; + + case LINE_DONE_AS_PREVIOUS: + /* fall through */ + case LINE_DONE: + return; + + case LINE_DECIDED_DOUBLE: + if (follow_ypos != -1) { + do_double = 1; + linetoscr_double_offset = gfxvidinfo.rowbytes * (follow_ypos - gfx_ypos); + linestate[lineno + 1] = LINE_DONE_AS_PREVIOUS; + } + + /* fall through */ + default: + if (dp_for_drawing->plfleft == -1) + border = 1; + linestate[lineno] = LINE_DONE; + break; + } + + dh = dh_line; + xlinebuffer = gfxvidinfo.linemem; + if (xlinebuffer == 0 && do_double + && (border == 0 || (border != 1 && dip_for_drawing->nr_color_changes > 0))) + xlinebuffer = gfxvidinfo.emergmem, dh = dh_emerg; + if (xlinebuffer == 0) + xlinebuffer = row_map[gfx_ypos], dh = dh_buf; + xlinebuffer -= linetoscr_x_adjust_bytes; + + if (border == 0) { + pfield_expand_dp_bplcon (); + + if (bplres == RES_LORES && ! currprefs.gfx_lores) + currprefs.gfx_lores = 2; + + pfield_init_linetoscr (); + pfield_doline (lineno); + + adjust_drawing_colors (dp_for_drawing->ctable, dp_for_drawing->ham_seen || bplehb); + + /* The problem is that we must call decode_ham() BEFORE we do the + sprites. */ + if (! border && dp_for_drawing->ham_seen) { + init_ham_decoding (); + if (dip_for_drawing->nr_color_changes == 0) { + /* The easy case: need to do HAM decoding only once for the + * full line. */ + decode_ham (visible_left_border, visible_right_border); + } else /* Argh. */ { + do_color_changes (dummy_worker, decode_ham); + adjust_drawing_colors (dp_for_drawing->ctable, dp_for_drawing->ham_seen || bplehb); + } + bplham = dp_for_drawing->ham_at_start; + } + + { + if (dip_for_drawing->nr_sprites) { + int i; +#ifdef AGA + if (brdsprt) + clear_bitplane_border_aga (); +#endif + for (i = 0; i < dip_for_drawing->nr_sprites; i++) { +#ifdef AGA + if (currprefs.chipset_mask & CSMASK_AGA) + draw_sprites_aga (curr_sprite_entries + dip_for_drawing->first_sprite_entry + i); + else +#endif + draw_sprites_ecs (curr_sprite_entries + dip_for_drawing->first_sprite_entry + i); + } + } + if (plf2pri > 5 && bplplanecnt > 4 && !(currprefs.chipset_mask & CSMASK_AGA)) + weird_bitplane_fix (); + } + + do_color_changes (pfield_do_fill_line, pfield_do_linetoscr); + if (dh == dh_emerg) + memcpy (row_map[gfx_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.pixbytes * gfxvidinfo.width); + + do_flush_line (gfx_ypos); + if (do_double) { + if (dh == dh_emerg) + memcpy (row_map[follow_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.pixbytes * gfxvidinfo.width); + else if (dh == dh_buf) + memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.pixbytes * gfxvidinfo.width); + do_flush_line (follow_ypos); + } + if (currprefs.gfx_lores == 2) + currprefs.gfx_lores = 0; + } else if (border == 1) { + adjust_drawing_colors (dp_for_drawing->ctable, 0); + + if (dip_for_drawing->nr_color_changes == 0) { + fill_line (); + do_flush_line (gfx_ypos); +#if 0 + if (dh == dh_emerg) + abort (); +#endif + if (do_double) { + if (dh == dh_buf) { + xlinebuffer = row_map[follow_ypos] - linetoscr_x_adjust_bytes; + fill_line (); + } + /* If dh == dh_line, do_flush_line will re-use the rendered line + * from linemem. */ + do_flush_line (follow_ypos); + } + return; + } + + playfield_start = visible_right_border; + playfield_end = visible_right_border; + + do_color_changes (pfield_do_fill_line, pfield_do_fill_line); + + if (dh == dh_emerg) + memcpy (row_map[gfx_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.pixbytes * gfxvidinfo.width); + + do_flush_line (gfx_ypos); + if (do_double) { + if (dh == dh_emerg) + memcpy (row_map[follow_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.pixbytes * gfxvidinfo.width); + else if (dh == dh_buf) + memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.pixbytes * gfxvidinfo.width); + /* If dh == dh_line, do_flush_line will re-use the rendered line + * from linemem. */ + do_flush_line (follow_ypos); + } + } else { + xcolnr tmp = colors_for_drawing.acolors[0]; + colors_for_drawing.acolors[0] = getxcolor (0); + fill_line (); + do_flush_line (gfx_ypos); + colors_for_drawing.acolors[0] = tmp; + } +} + +static void center_image (void) +{ + prev_x_adjust = visible_left_border; + prev_y_adjust = thisframe_y_adjust; + + if (currprefs.gfx_xcenter) { +#if 0 + if (min_diwstart && (max_diwstop - min_diwstart < gfxvidinfo.width) && (currprefs.gfx_xcenter == 2)) + visible_left_border = ((max_diwstop - min_diwstart - gfxvidinfo.width) / 2 + min_diwstart) & ~1; +#endif + if (max_diwstop - min_diwstart < gfxvidinfo.width && currprefs.gfx_xcenter == 2) + /* Try to center. */ + visible_left_border = ((max_diwstop - min_diwstart - gfxvidinfo.width) / 2 + min_diwstart) & ~1; + else + visible_left_border = max_diwstop - gfxvidinfo.width; + + /* Would the old value be good enough? If so, leave it as it is if we want to + * be clever. */ + if (currprefs.gfx_xcenter == 2) { + if (visible_left_border < prev_x_adjust && prev_x_adjust < min_diwstart) + visible_left_border = prev_x_adjust; + } + } else + visible_left_border = max_diwlastword - gfxvidinfo.width; + if (visible_left_border > max_diwlastword - 32) + visible_left_border = max_diwlastword - 32; + if (visible_left_border < 0) + visible_left_border = 0; + + linetoscr_x_adjust_bytes = visible_left_border * gfxvidinfo.pixbytes; + + visible_right_border = visible_left_border + gfxvidinfo.width; + if (visible_right_border > max_diwlastword) + visible_right_border = max_diwlastword; + + thisframe_y_adjust = minfirstline; + if (currprefs.gfx_ycenter && thisframe_first_drawn_line != -1) { +#if 0 + if (thisframe_first_drawn_line && (thisframe_last_drawn_line - thisframe_first_drawn_line < max_drawn_amiga_line) && currprefs.gfx_ycenter == 2) + thisframe_y_adjust = (thisframe_last_drawn_line - thisframe_first_drawn_line - max_drawn_amiga_line) / 2 + thisframe_first_drawn_line; +#endif + + if (thisframe_last_drawn_line - thisframe_first_drawn_line < max_drawn_amiga_line && currprefs.gfx_ycenter == 2) + thisframe_y_adjust = (thisframe_last_drawn_line - thisframe_first_drawn_line - max_drawn_amiga_line) / 2 + thisframe_first_drawn_line; + else + thisframe_y_adjust = thisframe_first_drawn_line; + + /* Would the old value be good enough? If so, leave it as it is if we want to + * be clever. */ + if (currprefs.gfx_ycenter == 2) { + if (thisframe_y_adjust != prev_y_adjust + && prev_y_adjust <= thisframe_first_drawn_line + && prev_y_adjust + max_drawn_amiga_line > thisframe_last_drawn_line) + thisframe_y_adjust = prev_y_adjust; + } + /* Make sure the value makes sense */ + if (thisframe_y_adjust + max_drawn_amiga_line > maxvpos) + thisframe_y_adjust = maxvpos - max_drawn_amiga_line; + if (thisframe_y_adjust < minfirstline) + thisframe_y_adjust = minfirstline; + } + thisframe_y_adjust_real = thisframe_y_adjust << (currprefs.gfx_linedbl ? 1 : 0); + max_ypos_thisframe = (maxvpos - thisframe_y_adjust) << (currprefs.gfx_linedbl ? 1 : 0); + + /* @@@ interlace_seen used to be (bplcon0 & 4), but this is probably + * better. */ + if (prev_x_adjust != visible_left_border || prev_y_adjust != thisframe_y_adjust) + frame_redraw_necessary |= interlace_seen && currprefs.gfx_linedbl ? 2 : 1; + + max_diwstop = 0; + min_diwstart = 10000; +} + +static void lores_reset (void) +{ + lores_factor = currprefs.gfx_lores ? 1 : 2; + lores_shift = currprefs.gfx_lores ? 0 : 1; +} + +static void init_drawing_frame (void) +{ + int i, maxline; + + if (can_use_lores > AUTO_LORES_FRAMES && 0) { + lores_factor = 1; + lores_shift = 0; + } else { + can_use_lores++; + lores_reset (); + } + + init_hardware_for_drawing_frame (); + + if (thisframe_first_drawn_line == -1) + thisframe_first_drawn_line = minfirstline; + if (thisframe_first_drawn_line > thisframe_last_drawn_line) + thisframe_last_drawn_line = thisframe_first_drawn_line; + + maxline = currprefs.gfx_linedbl ? (maxvpos + 1) * 2 + 1 : (maxvpos + 1) + 1; +#ifdef SMART_UPDATE + for (i = 0; i < maxline; i++) { + switch (linestate[i]) { + case LINE_DONE_AS_PREVIOUS: + linestate[i] = LINE_REMEMBERED_AS_PREVIOUS; + break; + case LINE_REMEMBERED_AS_BLACK: + break; + default: + linestate[i] = LINE_UNDECIDED; + break; + } + } +#else + memset (linestate, LINE_UNDECIDED, maxline); +#endif + last_drawn_line = 0; + first_drawn_line = 32767; + + first_block_line = last_block_line = -2; + if (currprefs.test_drawing_speed) + frame_redraw_necessary = 1; + else if (frame_redraw_necessary) + frame_redraw_necessary--; + + center_image (); + + thisframe_first_drawn_line = -1; + thisframe_last_drawn_line = -1; + + drawing_color_matches = -1; +} + +/* + * Some code to put status information on the screen. + */ + +#define TD_PADX 10 +#define TD_PADY 2 +#define TD_WIDTH 32 +#define TD_LED_WIDTH 24 +#define TD_LED_HEIGHT 4 + +#define TD_RIGHT 1 +#define TD_BOTTOM 2 + +static int td_pos = (TD_RIGHT|TD_BOTTOM); + +#define TD_NUM_WIDTH 7 +#define TD_NUM_HEIGHT 7 + +#define TD_TOTAL_HEIGHT (TD_PADY * 2 + TD_NUM_HEIGHT) + +#define NUMBERS_NUM 14 + +static char *numbers = { /* ugly */ +"+++++++--++++-+++++++++++++++++-++++++++++++++++++++++++++++++++++++++++++++-++++++-++++----++---+" +"+xxxxx+--+xx+-+xxxxx++xxxxx++x+-+x++xxxxx++xxxxx++xxxxx++xxxxx++xxxxx++xxxx+-+x++x+-+xxx++-+xx+-+x" +"+x+++x+--++x+-+++++x++++++x++x+++x++x++++++x++++++++++x++x+++x++x+++x++x++++-+x++x+-+x++x+--+x++x+" +"+x+-+x+---+x+-+xxxxx++xxxxx++xxxxx++xxxxx++xxxxx+--++x+-+xxxxx++xxxxx++x+----+xxxx+-+x++x+----+x+-" +"+x+++x+---+x+-+x++++++++++x++++++x++++++x++x+++x+--+x+--+x+++x++++++x++x++++-+x++x+-+x++x+---+x+x+" +"+xxxxx+---+x+-+xxxxx++xxxxx+----+x++xxxxx++xxxxx+--+x+--+xxxxx++xxxxx++xxxx+-+x++x+-+xxx+---+x++xx" +"+++++++---+++-++++++++++++++----+++++++++++++++++--+++--++++++++++++++++++++-++++++-++++----------" +}; + +STATIC_INLINE void putpixel (int x, xcolnr c8) +{ + switch(gfxvidinfo.pixbytes) + { + case 1: + xlinebuffer[x] = (uae_u8)c8; + break; + case 2: + { + uae_u16 *p = (uae_u16 *)xlinebuffer + x; + *p = (uae_u16)c8; + break; + } + case 3: + /* no 24 bit yet */ + break; + case 4: + { + uae_u32 *p = (uae_u32 *)xlinebuffer + x; + *p = c8; + break; + } + } +} + +static void write_tdnumber (int x, int y, int num) +{ + int j; + uae_u8 *numptr; + + numptr = numbers + num * TD_NUM_WIDTH + NUMBERS_NUM * TD_NUM_WIDTH * y; + for (j = 0; j < TD_NUM_WIDTH; j++) { + if (*numptr == 'x') + putpixel (x + j, xcolors[0xfff]); + else if (*numptr == '+') + putpixel (x + j, xcolors[0x000]); + numptr++; + } +} + +static void draw_status_line (int line) +{ + int x_start, y, j, led; + + if (td_pos & TD_RIGHT) + x_start = gfxvidinfo.width - TD_PADX - NUM_LEDS * TD_WIDTH; + else + x_start = TD_PADX; + + y = line - (gfxvidinfo.height - TD_TOTAL_HEIGHT); + xlinebuffer = gfxvidinfo.linemem; + if (xlinebuffer == 0) + xlinebuffer = row_map[line]; + + memset (xlinebuffer, 0, gfxvidinfo.width * gfxvidinfo.pixbytes); + + for (led = 0; led < NUM_LEDS; led++) { + int side, pos, num1 = -1, num2 = -1, num3 = -1, num4 = -1, x, off_rgb, on_rgb, c, on = 0; + if (led >= 1 && led <= 4) { + int track = gui_data.drive_track[led-1]; + pos = 5 + (led - 1); + if (!gui_data.drive_disabled[led - 1]) { + num1 = -1; + num2 = track / 10; + num3 = track % 10; + on = gui_data.drive_motor[led-1]; + } + side = gui_data.drive_side; + on_rgb = 0x0c0; + off_rgb = 0x030; + } else if (led == 0) { + pos = 2; + on = gui_data.powerled; + on_rgb = 0xc00; + off_rgb = 0x300; + } else if (led == 5) { + pos = 4; + on = gui_data.cd; + on_rgb = 0x00c; + off_rgb = 0x003; + num1 = -1; + num2 = 10; + num3 = 12; + } else if (led == 6) { + pos = 3; + on = gui_data.hd; + on_rgb = 0x00c; + off_rgb = 0x003; + num1 = -1; + num2 = 11; + num3 = 12; + } else if (led == 7) { + int fps = (gui_data.fps + 5) / 10; + pos = 1; + on_rgb = 0x000; + off_rgb = 0x000; + num1 = fps / 100; + num2 = (fps - num1 * 100) / 10; + num3 = fps % 10; + } else if (led == 8) { + int idle = (gui_data.idle + 5) / 10; + pos = 0; + on_rgb = 0x000; + off_rgb = 0x000; + num1 = idle / 100; + num2 = (idle - num1 * 100) / 10; + num3 = idle % 10; + num4 = 13; + } + + c = xcolors[on ? on_rgb : off_rgb]; + + x = x_start + pos * TD_WIDTH; + for (j = 0; j < TD_LED_WIDTH; j++) + putpixel (x + j, c); + + if (y >= TD_PADY && y - TD_PADY < TD_NUM_HEIGHT) { + if (num3 >= 0) { + int tn = num1 > 0 ? 3 : 2; + int offs = (TD_LED_WIDTH - tn * TD_NUM_WIDTH) / 2; + if (num1 > 0) { + write_tdnumber (x + offs, y - TD_PADY, num1); + offs += TD_NUM_WIDTH; + } + write_tdnumber (x + offs, y - TD_PADY, num2); + write_tdnumber (x + offs + TD_NUM_WIDTH, y - TD_PADY, num3); + if (num4 > 0) + write_tdnumber (x + offs + 2 * TD_NUM_WIDTH, y - TD_PADY, num4); + } + } + } +} + +void finish_drawing_frame (void) +{ + int i; + + if (! lockscr ()) { + notice_screen_contents_lost (); + return; + } + +#ifndef SMART_UPDATE + /* @@@ This isn't exactly right yet. FIXME */ + if (!interlace_seen) + do_flush_screen (first_drawn_line, last_drawn_line); + else + unlockscr (); + return; +#endif + for (i = 0; i < max_ypos_thisframe; i++) { + int where; + int i1 = i + min_ypos_for_screen; + int line = i + thisframe_y_adjust_real; + + if (linestate[line] == LINE_UNDECIDED) + break; + + where = amiga2aspect_line_map[i1]; + if (where >= gfxvidinfo.height - (currprefs.leds_on_screen ? TD_TOTAL_HEIGHT : 0)) + break; + if (where == -1) + continue; + + pfield_draw_line (line, where, amiga2aspect_line_map[i1 + 1]); + } + if (currprefs.leds_on_screen) { + for (i = 0; i < TD_TOTAL_HEIGHT; i++) { + int line = gfxvidinfo.height - TD_TOTAL_HEIGHT + i; + draw_status_line (line); + do_flush_line (line); + } + } + + do_flush_screen (first_drawn_line, last_drawn_line); +} + +void hardware_line_completed (int lineno) +{ +#ifndef SMART_UPDATE + { + int i, where; + /* l is the line that has been finished for drawing. */ + i = lineno - thisframe_y_adjust_real; + if (i >= 0 && i < max_ypos_thisframe) { + where = amiga2aspect_line_map[i+min_ypos_for_screen]; + if (where < gfxvidinfo.height && where != -1) + pfield_draw_line (lineno, where, amiga2aspect_line_map[i+min_ypos_for_screen+1]); + } + } +#endif +} + +STATIC_INLINE void check_picasso (void) +{ +#ifdef PICASSO96 + if (picasso_on && picasso_redraw_necessary) + picasso_refresh (1); + picasso_redraw_necessary = 0; + + if (picasso_requested_on == picasso_on) + return; + + picasso_on = picasso_requested_on; + + if (!picasso_on) + clear_inhibit_frame (IHF_PICASSO); + else + set_inhibit_frame (IHF_PICASSO); + + gfx_set_picasso_state (picasso_on); + picasso_enablescreen (picasso_requested_on); + + notice_screen_contents_lost (); + notice_new_xcolors (); +#endif +} + +void redraw_frame (void) +{ + last_drawn_line = 0; + first_drawn_line = 32767; + finish_drawing_frame (); + flush_screen (0, 0); +} + +void vsync_handle_redraw (int long_frame, int lof_changed) +{ + last_redraw_point++; + if (lof_changed || ! interlace_seen || last_redraw_point >= 2 || long_frame) { + last_redraw_point = 0; + interlace_seen = 0; + + if (framecnt == 0) { + finish_drawing_frame (); +#ifdef AVIOUTPUT + frame_drawn (); + } else if (picasso_on) { + frame_drawn (); +#endif + } + + /* At this point, we have finished both the hardware and the + * drawing frame. Essentially, we are outside of all loops and + * can do some things which would cause confusion if they were + * done at other times. + */ + + if (savestate_state == STATE_DORESTORE) { + savestate_state = STATE_RESTORE; + reset_drawing (); + uae_reset (0); + } else if (savestate_state == STATE_DOREWIND) { + savestate_state = STATE_REWIND; + reset_drawing (); + uae_reset (0); + } + + if (quit_program < 0) { + quit_program = -quit_program; + set_inhibit_frame (IHF_QUIT_PROGRAM); + set_special (SPCFLAG_BRK); +#ifdef FILESYS + filesys_prepare_reset (); +#endif + return; + } + + savestate_capture (0); + count_frame (); + check_picasso (); + + if (check_prefs_changed_gfx ()) { + reset_drawing (); + init_row_map (); + init_aspect_maps (); + notice_screen_contents_lost (); + notice_new_xcolors (); + } + + check_prefs_changed_audio (); + check_prefs_changed_comp (); + check_prefs_changed_custom (); + check_prefs_changed_cpu (); + + if (inhibit_frame != 0) + framecnt = 1; + + if (framecnt == 0) + init_drawing_frame (); + } else { + if (currprefs.gfx_afullscreen && currprefs.gfx_vsync) + flush_screen (0, 0); /* vsync mode */ + } + gui_hd_led (0); + gui_cd_led (0); +} + +void hsync_record_line_state (int lineno, enum nln_how how, int changed) +{ + char *state; + if (framecnt != 0) + return; + + state = linestate + lineno; + changed += frame_redraw_necessary; + + switch (how) { + case nln_normal: + *state = changed ? LINE_DECIDED : LINE_DONE; + break; + case nln_doubled: + *state = changed ? LINE_DECIDED_DOUBLE : LINE_DONE; + changed += state[1] != LINE_REMEMBERED_AS_PREVIOUS; + state[1] = changed ? LINE_AS_PREVIOUS : LINE_DONE_AS_PREVIOUS; + break; + case nln_nblack: + *state = changed ? LINE_DECIDED : LINE_DONE; + if (state[1] != LINE_REMEMBERED_AS_BLACK) + state[1] = LINE_BLACK; + break; + case nln_lower: + if (state[-1] == LINE_UNDECIDED) + state[-1] = LINE_BLACK; + *state = changed ? LINE_DECIDED : LINE_DONE; + break; + case nln_upper: + *state = changed ? LINE_DECIDED : LINE_DONE; + if (state[1] == LINE_UNDECIDED + || state[1] == LINE_REMEMBERED_AS_PREVIOUS + || state[1] == LINE_AS_PREVIOUS) + state[1] = LINE_BLACK; + break; + } +} + +void notice_interlace_seen (void) +{ + interlace_seen = 1; +} + +void reset_drawing (void) +{ + int i; + + max_diwstop = 0; + + lores_reset (); + + for (i = 0; i < sizeof linestate / sizeof *linestate; i++) + linestate[i] = LINE_UNDECIDED; + + init_aspect_maps (); + + if (line_drawn == 0) + line_drawn = (char *)malloc (gfxvidinfo.height); + + init_row_map(); + + last_redraw_point = 0; + + memset (spixels, 0, sizeof spixels); + memset (&spixstate, 0, sizeof spixstate); + + init_drawing_frame (); + + flush_clear_screen (); + notice_screen_contents_lost (); +} + +void drawing_init (void) +{ + gen_pfield_tables(); + + uae_sem_init (&gui_sem, 0, 1); +#ifdef PICASSO96 + InitPicasso96 (); + picasso_on = 0; + picasso_requested_on = 0; + gfx_set_picasso_state (0); +#endif + xlinebuffer = gfxvidinfo.bufmem; + inhibit_frame = 0; + + reset_drawing (); +} + diff --git a/driveclick.c b/driveclick.c new file mode 100755 index 00000000..9aecd6f0 --- /dev/null +++ b/driveclick.c @@ -0,0 +1,323 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Drive Click Emulation Support Functions + * + * Copyright 2004 James Bagg, Toni Wilen + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#ifdef DRIVESOUND + +#include "uae.h" +#include "config.h" +#include "options.h" +#include "sounddep/sound.h" +#include "zfile.h" +#include "events.h" + +#include "driveclick.h" + +static struct drvsample drvs[4][DS_END]; +static int freq = 44100; + +static int drv_starting[4], drv_spinning[4], drv_has_spun[4], drv_has_disk[4]; + +static int click_initialized; +#define DS_SHIFT 10 +static int sample_step; + +static uae_s16 *clickbuffer; + +uae_s16 *decodewav (uae_u8 *s, int *lenp) +{ + uae_s16 *dst; + uae_u8 *src = s; + int len; + + if (memcmp (s, "RIFF", 4)) + return 0; + if (memcmp (s + 8, "WAVE", 4)) + return 0; + s += 12; + len = *lenp; + while (s < src + len) { + if (!memcmp (s, "fmt ", 4)) + freq = s[8 + 4] | (s[8 + 5] << 8); + if (!memcmp (s, "data", 4)) { + s += 4; + len = s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24); + dst = xmalloc (len); + memcpy (dst, s + 4, len); + *lenp = len / 2; + return dst; + } + s += 8 + (s[4] | (s[5] << 8) | (s[6] << 16) | (s[7] << 24)); + } + return 0; +} + +static int loadsample (char *path, struct drvsample *ds) +{ + struct zfile *f; + uae_u8 *buf; + int size; + + f = zfile_fopen (path, "rb"); + if (!f) { + write_log ("driveclick: can't open '%s'\n", path); + return 0; + } + zfile_fseek (f, 0, SEEK_END); + size = zfile_ftell (f); + buf = malloc (size); + zfile_fseek (f, 0, SEEK_SET); + zfile_fread (buf, size, 1, f); + zfile_fclose (f); + ds->len = size; + ds->p = decodewav (buf, &ds->len); + free (buf); + return 1; +} + +static void freesample (struct drvsample *s) +{ + free (s->p); + s->p = 0; +} + +void driveclick_init(void) +{ + int v, vv, i, j; + char tmp[1000]; + + driveclick_free (); + vv = 0; + for (i = 0; i < 4; i++) { + if (currprefs.dfxclick[i]) { + if (currprefs.dfxclick[i] > 0) { + v = 0; + if (driveclick_loadresource (drvs[i], currprefs.dfxclick[i])) + v = 3; + } else if (currprefs.dfxclick[i] == -1) { + sprintf (tmp, "%suae_data%cdrive_click_%s", start_path, FSDB_DIR_SEPARATOR, currprefs.dfxclickexternal[i]); + v = loadsample (tmp, &drvs[i][DS_CLICK]); + sprintf (tmp, "%suae_data%cdrive_spin_%s", start_path, FSDB_DIR_SEPARATOR, currprefs.dfxclickexternal[i]); + v += loadsample (tmp, &drvs[i][DS_SPIN]); + sprintf (tmp, "%suae_data%cdrive_spinnd_%s", start_path, FSDB_DIR_SEPARATOR, currprefs.dfxclickexternal[i]); + v += loadsample (tmp, &drvs[i][DS_SPINND]); + sprintf (tmp, "%suae_data%cdrive_startup_%s", start_path, FSDB_DIR_SEPARATOR, currprefs.dfxclickexternal[i]); + v += loadsample (tmp, &drvs[i][DS_START]); + sprintf (tmp, "%suae_data%cdrive_snatch_%s", start_path, FSDB_DIR_SEPARATOR, currprefs.dfxclickexternal[i]); + v += loadsample (tmp, &drvs[i][DS_SNATCH]); + } + if (v == 0) { + int j; + for (j = 0; j < DS_END; j++) + freesample (&drvs[i][j]); + currprefs.dfxclick[i] = changed_prefs.dfxclick[i] = 0; + } + for (j = 0; j < DS_END; j++) + drvs[i][j].len <<= DS_SHIFT; + drvs[i][DS_CLICK].pos = drvs[i][DS_CLICK].len; + drvs[i][DS_SNATCH].pos = drvs[i][DS_SNATCH].len; + vv += currprefs.dfxclick[i]; + } + } + if (vv > 0) { + driveclick_reset (); + click_initialized = 1; + } +} + +void driveclick_reset (void) +{ + free (clickbuffer); + clickbuffer = xmalloc (sndbufsize); + sample_step = (freq << DS_SHIFT) / currprefs.sound_freq; +} + +void driveclick_free (void) +{ + int i, j; + + for (i = 0; i < 4; i++) { + for (j = 0; j < DS_END; j++) + freesample (&drvs[i][j]); + } + memset (drvs, 0, sizeof (drvs)); + free (clickbuffer); + clickbuffer = 0; + click_initialized = 0; +} + +STATIC_INLINE uae_s16 getsample(void) +{ + uae_s32 smp = 0; + int div = 0, i; + + for (i = 0; i < 4; i++) { + if (currprefs.dfxclick[i]) { + struct drvsample *ds_start = &drvs[i][DS_START]; + struct drvsample *ds_spin = drv_has_disk[i] ? &drvs[i][DS_SPIN] : &drvs[i][DS_SPINND]; + struct drvsample *ds_click = &drvs[i][DS_CLICK]; + struct drvsample *ds_snatch = &drvs[i][DS_SNATCH]; + div += 2; + if (drv_spinning[i] || drv_starting[i]) { + if (drv_starting[i] && drv_has_spun[i]) { + if (ds_start->p && ds_start->pos < ds_start->len) { + smp = ds_start->p[ds_start->pos >> DS_SHIFT]; + ds_start->pos += sample_step; + } else { + drv_starting[i] = 0; + } + } else if (drv_starting[i] && drv_has_spun[i] == 0) { + if (ds_snatch->p && ds_snatch->pos < ds_snatch->len) { + smp = ds_snatch->p[ds_snatch->pos >> DS_SHIFT]; + ds_snatch->pos += sample_step; + } else { + drv_starting[i] = 0; + ds_start->pos = ds_start->len; + drv_has_spun[i] = 1; + } + } + if (ds_spin->p && drv_starting[i] == 0) { + if (ds_spin->pos >= ds_spin->len) + ds_spin->pos -= ds_spin->len; + smp = ds_spin->p[ds_spin->pos >> DS_SHIFT]; + ds_spin->pos += sample_step; + } + } + if (ds_click->p && ds_click->pos < ds_click->len) { + smp += ds_click->p[ds_click->pos >> DS_SHIFT]; + ds_click->pos += sample_step; + } + } + } + if (!div) + return 0; + return smp / div; +} + +static int clickcnt; + +static void mix (void) +{ + int total = ((uae_u8*)sndbufpt - (uae_u8*)sndbuffer) / (currprefs.stereo ? 4 : 2); + if (currprefs.dfxclickvolume > 0) { + while (clickcnt < total) { + clickbuffer[clickcnt++] = getsample() * (100 - currprefs.dfxclickvolume) / 100; + } + } else { + while (clickcnt < total) { + clickbuffer[clickcnt++] = getsample(); + } + } + if (clickcnt > 0) + clickbuffer[clickcnt] = clickbuffer[clickcnt - 1]; +} + +STATIC_INLINE uae_s16 limit (uae_s32 v) +{ + if (v < -32768) + v = -32768; + if (v > 32767) + v = 32767; + return v; +} + +void driveclick_mix (uae_s16 *sndbuffer, int size) +{ + int i; + + if (!click_initialized) + return; + mix(); + clickcnt = 0; + if (currprefs.stereo) { + for (i = 0; i < size / 2; i++) { + uae_s16 s = clickbuffer[i]; + sndbuffer[0] = limit(((sndbuffer[0] + s) * 2) / 3); + sndbuffer[1] = limit(((sndbuffer[1] + s) * 2) / 3); + sndbuffer += 2; + } + } else { + for (i = 0; i < size; i++) { + sndbuffer[0] = limit(((sndbuffer[0] + clickbuffer[i]) * 2) / 3); + sndbuffer++; + } + } +} + +void driveclick_click (int drive, int startOffset) +{ + if (!click_initialized) + return; + if (!currprefs.dfxclick[drive]) + return; + mix(); + drvs[drive][DS_CLICK].pos = (startOffset * 4) << DS_SHIFT; + if (drvs[drive][DS_CLICK].pos > drvs[drive][DS_CLICK].len / 2) + drvs[drive][DS_CLICK].pos = drvs[drive][DS_CLICK].len / 2; +} + +void driveclick_motor (int drive, int running) +{ + if (!click_initialized) + return; + if (!currprefs.dfxclick[drive]) + return; + mix(); + if (running == 0) { + drv_starting[drive] = 0; + drv_spinning[drive] = 0; + } else { + if (drv_spinning[drive] == 0) { + drv_starting[drive] = 1; + drv_spinning[drive] = 1; + if (drv_has_disk[drive] && drv_has_spun[drive] == 0 && drvs[drive][DS_SNATCH].pos >= drvs[drive][DS_SNATCH].len) + drvs[drive][DS_SNATCH].pos = 0; + if (running == 2) + drvs[drive][DS_START].pos = 0; + drvs[drive][DS_SPIN].pos = 0; + } + } +} + +void driveclick_insert (int drive, int eject) +{ + if (!click_initialized) + return; + if (!currprefs.dfxclick[drive]) + return; + if (eject) + drv_has_spun[drive] = 0; + drv_has_disk[drive] = !eject; +} + +void driveclick_check_prefs (void) +{ + int i; + + if (currprefs.dfxclickvolume != changed_prefs.dfxclickvolume || + currprefs.dfxclick[0] != changed_prefs.dfxclick[0] || + currprefs.dfxclick[1] != changed_prefs.dfxclick[1] || + currprefs.dfxclick[2] != changed_prefs.dfxclick[2] || + currprefs.dfxclick[3] != changed_prefs.dfxclick[3] || + strcmp (currprefs.dfxclickexternal[0], changed_prefs.dfxclickexternal[0]) || + strcmp (currprefs.dfxclickexternal[1], changed_prefs.dfxclickexternal[1]) || + strcmp (currprefs.dfxclickexternal[2], changed_prefs.dfxclickexternal[2]) || + strcmp (currprefs.dfxclickexternal[3], changed_prefs.dfxclickexternal[3])) + { + currprefs.dfxclickvolume = changed_prefs.dfxclickvolume; + for (i = 0; i < 4; i++) { + currprefs.dfxclick[i] = changed_prefs.dfxclick[i]; + strcpy (currprefs.dfxclickexternal[i], changed_prefs.dfxclickexternal[i]); + } + driveclick_init (); + } +} + +#endif \ No newline at end of file diff --git a/enforcer.c b/enforcer.c new file mode 100755 index 00000000..74a5070a --- /dev/null +++ b/enforcer.c @@ -0,0 +1,588 @@ +/* + * UAE - The Un*x Amiga Emulator + * + * Enforcer Like Support + * + * Copyright 2000-2003 Bernd Roesch and Sebastian Bauer + */ + +#include + +#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=0;j--) + { + if (bestpc_array[i][j]) + { + bestpc_idxs[i] = j; + break; + } + } + } while (bestpc_idxs[i] == -1); + if (leave) break; + if (i) temppc = bestpc_array[i-1][bestpc_idxs[i-1]]; + else temppc = pc; + i--; /* will be increased in after continue */ + continue; + } + + sm68k_disasm(buf, instrcode, bestpc, NULL); + sprintf(lines[i],"%08lx : %-20s %s\n",bestpc,instrcode,buf); + temppc = bestpc; + } + + i--; + for (;i>=0;i--) + { + strcpy(enforcer_buf_ptr,lines[i]); + enforcer_buf_ptr += strlen(enforcer_buf_ptr); + } + + /* Now the instruction after the pc including the pc */ + temppc = pc; + for (i=0;i<(INSTRUCTIONLINES+1)/2;i++) + { + sm68k_disasm(buf, instrcode, temppc, &nextpc); + sprintf(enforcer_buf_ptr,"%08lx : %s %-20s %s\n",temppc,(i==0?"*":" "),instrcode,buf); + enforcer_buf_ptr += strlen(enforcer_buf_ptr); + temppc = nextpc; + } + + if (!native_task_name) native_task_name = "Unknown"; + sprintf(enforcer_buf_ptr,"Name: \"%s\"\n\n",native_task_name); + enforcer_buf_ptr += strlen(enforcer_buf_ptr); + + console_out(enforcer_buf); + write_log(enforcer_buf); + + enforcer_hit = 0; + flashscreen = 30; +} + +uae_u32 REGPARAM2 chipmem_lget2 (uaecptr addr) +{ + uae_u32 *m; + + addr -= chipmem_start & chipmem_mask; + addr &= chipmem_mask; + m = (uae_u32 *)(chipmemory + addr); + + if (ISILLEGAL(addr)) + enforcer_display_hit("LONG READ from",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr); + + return do_get_mem_long (m); +} + +uae_u32 REGPARAM2 chipmem_wget2(uaecptr addr) +{ + uae_u16 *m; + + addr -= chipmem_start & chipmem_mask; + addr &= chipmem_mask; + m = (uae_u16 *)(chipmemory + addr); + + if (ISILLEGAL(addr)) + enforcer_display_hit("WORD READ from",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr); + + return do_get_mem_word (m); +} + +uae_u32 REGPARAM2 chipmem_bget2 (uaecptr addr) +{ + addr -= chipmem_start & chipmem_mask; + addr &= chipmem_mask; + + if (ISILLEGAL(addr)) + enforcer_display_hit("BYTE READ from",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr); + + return chipmemory[addr]; +} + +void REGPARAM2 chipmem_lput2 (uaecptr addr, uae_u32 l) +{ + uae_u32 *m; + + addr -= chipmem_start & chipmem_mask; + addr &= chipmem_mask; + m = (uae_u32 *)(chipmemory + addr); + + if (ISILLEGAL(addr)) + enforcer_display_hit("LONG WRITE to",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr); + + do_put_mem_long (m, l); +} + +void REGPARAM2 chipmem_wput2 (uaecptr addr, uae_u32 w) +{ + uae_u16 *m; + + addr -= chipmem_start & chipmem_mask; + addr &= chipmem_mask; + m = (uae_u16 *)(chipmemory + addr); + + if (ISILLEGAL(addr)) + enforcer_display_hit("WORD WRITE to",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr); + + do_put_mem_word (m, w); +} + + +void REGPARAM2 chipmem_bput2 (uaecptr addr, uae_u32 b) +{ + addr -= chipmem_start & chipmem_mask; + addr &= chipmem_mask; + + if (ISILLEGAL(addr)) + enforcer_display_hit("BYTE WRITE to",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr); + chipmemory[addr] = b; +} + +int REGPARAM2 chipmem_check2 (uaecptr addr, uae_u32 size) +{ + addr -= chipmem_start & chipmem_mask; + addr &= chipmem_mask; + return (addr + size) <= allocated_chipmem; +} + +uae_u8 * REGPARAM2 chipmem_xlate2 (uaecptr addr) +{ + addr -= chipmem_start & chipmem_mask; + addr &= chipmem_mask; + return chipmemory + addr; +} + +uae_u32 REGPARAM2 dummy_lget2 (uaecptr addr) +{ + special_mem |= S_READ; + enforcer_display_hit("LONG READ from",(uae_u32)(regs.pc_p - NATMEM_OFFSET), addr); + return 0xbadedeef; +} + +#ifdef JIT +static int warned_JIT_0xF10000 = 0; +#endif + +uae_u32 REGPARAM2 dummy_wget2 (uaecptr addr) +{ + + special_mem |= S_READ; + +#ifdef JIT + if( addr >= 0x00F10000 && addr <= 0x00F7FFFF ) + { + if( !warned_JIT_0xF10000 ) + { + warned_JIT_0xF10000 = 1; + enforcer_display_hit("LONG READ from",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr); + } + return 0; + } +#endif + enforcer_display_hit("WORD READ from",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr); + return 0xbadf; +} + +uae_u32 REGPARAM2 dummy_bget2 (uaecptr addr) +{ + special_mem |= S_READ; + enforcer_display_hit("BYTE READ from",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr); + return 0xbadedeef; +} + +void REGPARAM2 dummy_lput2 (uaecptr addr, uae_u32 l) +{ + special_mem |= S_WRITE; + enforcer_display_hit("LONG WRITE to",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr); +} + +void REGPARAM2 dummy_wput2 (uaecptr addr, uae_u32 w) +{ + special_mem |= S_WRITE; + enforcer_display_hit("WORD WRITE to",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr); +} + +void REGPARAM2 dummy_bput2 (uaecptr addr, uae_u32 b) +{ + special_mem |= S_WRITE; + enforcer_display_hit("BYTE WRITE to",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr); +} + +int REGPARAM2 dummy_check2 (uaecptr addr, uae_u32 size) +{ + special_mem |= S_READ; + enforcer_display_hit("CHECK from ",(uae_u32)(regs.pc_p - NATMEM_OFFSET),addr); + return 0; +} + + +/************************************************************* + enable the enforcer like support, maybe later this make MMU + exceptions so enforcer can use it. Returns 1 if enforcer + is enabled +*************************************************************/ +int enforcer_enable(void) +{ + extern addrbank chipmem_bank,dummy_bank; + + if (!enforcer_installed) + { + saved_dummy_lget = dummy_bank.lget; + saved_dummy_wget = dummy_bank.wget; + saved_dummy_bget = dummy_bank.bget; + saved_dummy_lput = dummy_bank.lput; + saved_dummy_wput = dummy_bank.wput; + saved_dummy_bput = dummy_bank.bput; + saved_chipmem_lget = chipmem_bank.lget; + saved_chipmem_wget = chipmem_bank.wget; + saved_chipmem_bget = chipmem_bank.bget; + saved_chipmem_lput = chipmem_bank.lput; + saved_chipmem_wput = chipmem_bank.wput; + saved_chipmem_bput = chipmem_bank.bput; + saved_chipmem_xlate = chipmem_bank.xlateaddr; + saved_chipmem_check = chipmem_bank.check; + + dummy_bank.lget = dummy_lget2; + dummy_bank.wget = dummy_wget2; + dummy_bank.bget = dummy_bget2; + dummy_bank.lput = dummy_lput2; + dummy_bank.wput = dummy_wput2; + dummy_bank.bput = dummy_bput2; + chipmem_bank.lget = chipmem_lget2; + chipmem_bank.wget = chipmem_wget2; + chipmem_bank.bget = chipmem_bget2; + chipmem_bank.lput = chipmem_lput2; + chipmem_bank.wput = chipmem_wput2; + chipmem_bank.bput = chipmem_bput2; + chipmem_bank.xlateaddr = chipmem_xlate2; + chipmem_bank.check = chipmem_check2; + + enforcer_installed = 1; + } + return 1; +} + +/************************************************************* + Disable Enforcer like support +*************************************************************/ +int enforcer_disable(void) +{ + if (enforcer_installed) + { + dummy_bank.lget = saved_dummy_lget; + dummy_bank.wget = saved_dummy_wget; + dummy_bank.bget = saved_dummy_bget; + dummy_bank.lput = saved_dummy_lput; + dummy_bank.wput = saved_dummy_wput; + dummy_bank.bput = saved_dummy_bput; + chipmem_bank.lget = saved_chipmem_lget; + chipmem_bank.wget = saved_chipmem_wget; + chipmem_bank.bget = saved_chipmem_bget; + chipmem_bank.lput = saved_chipmem_lput; + chipmem_bank.wput = saved_chipmem_wput; + chipmem_bank.bput = saved_chipmem_bput; + chipmem_bank.xlateaddr = saved_chipmem_xlate; + chipmem_bank.check = saved_chipmem_check; + + enforcer_installed = 0; + } + return 1; +} + diff --git a/ersatz.c b/ersatz.c new file mode 100755 index 00000000..4b364fc0 --- /dev/null +++ b/ersatz.c @@ -0,0 +1,240 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * A "replacement" for a missing Kickstart + * Warning! Q&D + * + * (c) 1995 Bernd Schmidt + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "uae.h" +#include "memory.h" +#include "custom.h" +#include "newcpu.h" +#include "cpu_prefetch.h" +#include "cia.h" +#include "disk.h" +#include "ersatz.h" + +#define EOP_INIT 0 +#define EOP_NIMP 1 +#define EOP_SERVEINT 2 +#define EOP_DOIO 3 +#define EOP_OPENLIB 4 +#define EOP_AVAILMEM 5 +#define EOP_ALLOCMEM 6 +#define EOP_ALLOCABS 7 +#define EOP_LOOP 8 + +void init_ersatz_rom (uae_u8 *data) +{ + *data++ = 0x00; *data++ = 0x08; /* initial SP */ + *data++ = 0x00; *data++ = 0x00; + *data++ = 0x00; *data++ = 0xF8; /* initial PC */ + *data++ = 0x00; *data++ = 0x08; + + *data++ = 0xFF; *data++ = 0x0D; + *data++ = 0x00; *data++ = EOP_INIT; + *data++ = 0xFF; *data++ = 0x0D; + *data++ = 0x00; *data++ = EOP_NIMP; + + *data++ = 0xFF; *data++ = 0x0D; + *data++ = 0x00; *data++ = EOP_LOOP; + *data++ = 0xFF; *data++ = 0x0D; + *data++ = 0x00; *data++ = EOP_DOIO; + + *data++ = 0x4E; *data++ = 0x75; + *data++ = 0xFF; *data++ = 0x0D; + *data++ = 0x00; *data++ = EOP_SERVEINT; + *data++ = 0x4E; *data++ = 0x73; + + *data++ = 0xFF; *data++ = 0x0D; + *data++ = 0x00; *data++ = EOP_AVAILMEM; + *data++ = 0x4E; *data++ = 0x75; + *data++ = 0xFF; *data++ = 0x0D; + + *data++ = 0x00; *data++ = EOP_ALLOCMEM; + *data++ = 0x4E; *data++ = 0x75; + *data++ = 0xFF; *data++ = 0x0D; + *data++ = 0x00; *data++ = EOP_ALLOCABS; + + *data++ = 0x4E; *data++ = 0x75; +} + +static void ersatz_doio (void) +{ + uaecptr request = m68k_areg(regs, 1); + switch (get_word (request + 0x1C)) { + case 9: /* TD_MOTOR is harmless */ + case 2: case 0x8002: /* READ commands */ + break; + + default: + write_log ("Only CMD_READ supported in DoIO()\n"); + abort(); + } + { + uaecptr dest = get_long (request + 0x28); + int start = get_long (request + 0x2C) / 512; + int nsecs = get_long (request + 0x24) / 512; + int tr = start / 11; + int sec = start % 11; + while (nsecs--) { + DISK_ersatz_read (tr, sec, dest); + dest += 512; + if (++sec == 11) + sec = 0, tr++; + } + } +} + +static void ersatz_init (void) +{ + int f; + uaecptr request; + uaecptr a; + + if (disk_empty (0)) { + gui_message ("You need to have a diskfile in DF0 to use the Kickstart replacement!\n"); + uae_quit (); + m68k_setpc (0xF80010); + return; + } + + regs.s = 0; + /* Set some interrupt vectors */ + for (a = 8; a < 0xC0; a += 4) { + put_long (a, 0xF8001A); + } + regs.isp = regs.msp = regs.usp = 0x800; + m68k_areg(regs, 7) = 0x80000; + regs.intmask = 0; + + /* Build a dummy execbase */ + put_long (4, m68k_areg(regs, 6) = 0x676); + put_byte (0x676 + 0x129, 0); + for (f = 1; f < 105; f++) { + put_word (0x676 - 6*f, 0x4EF9); + put_long (0x676 - 6*f + 2, 0xF8000C); + } + /* Some "supported" functions */ + put_long (0x676 - 456 + 2, 0xF80014); + put_long (0x676 - 216 + 2, 0xF80020); + put_long (0x676 - 198 + 2, 0xF80026); + put_long (0x676 - 204 + 2, 0xF8002c); + put_long (0x676 - 210 + 2, 0xF8002a); + + /* Build an IORequest */ + request = 0x800; + put_word (request + 0x1C, 2); + put_long (request + 0x28, 0x4000); + put_long (request + 0x2C, 0); + put_long (request + 0x24, 0x200 * 4); + m68k_areg(regs, 1) = request; + ersatz_doio (); + /* kickstart disk loader */ + if (get_long(0x4000) == 0x4b49434b) { + /* a kickstart disk was found in drive 0! */ + write_log ("Loading Kickstart rom image from Kickstart disk\n"); + /* print some notes... */ + write_log ("NOTE: if UAE crashes set CPU to 68000 and/or chipmem size to 512KB!\n"); + + /* read rom image from kickstart disk */ + put_word (request + 0x1C, 2); + put_long (request + 0x28, 0xF80000); + put_long (request + 0x2C, 0x200); + put_long (request + 0x24, 0x200 * 512); + m68k_areg(regs, 1) = request; + ersatz_doio (); + + /* read rom image once again to mirror address space. + not elegant, but it works... */ + put_word (request + 0x1C, 2); + put_long (request + 0x28, 0xFC0000); + put_long (request + 0x2C, 0x200); + put_long (request + 0x24, 0x200 * 512); + m68k_areg(regs, 1) = request; + ersatz_doio (); + + disk_eject (0); + + m68k_setpc (0xFC0002); + fill_prefetch_slow (); + uae_reset (0); + ersatzkickfile = 0; + return; + } + + m68k_setpc (0x400C); + fill_prefetch_slow (); + + /* Init the hardware */ + put_long (0x3000, 0xFFFFFFFEul); + put_long (0xDFF080, 0x3000); + put_word (0xDFF088, 0); + put_word (0xDFF096, 0xE390); + put_word (0xDFF09A, 0xE02C); + put_word (0xDFF09E, 0x0000); + put_word (0xDFF092, 0x0038); + put_word (0xDFF094, 0x00D0); + put_word (0xDFF08E, 0x2C81); + put_word (0xDFF090, 0xF4C1); + put_word (0xDFF02A, 0x8000); + + put_byte (0xBFD100, 0xF7); + put_byte (0xBFEE01, 0); + put_byte (0xBFEF01, 0x08); + put_byte (0xBFDE00, 0x04); + put_byte (0xBFDF00, 0x84); + put_byte (0xBFDD00, 0x9F); + put_byte (0xBFED01, 0x9F); +} + +void ersatz_perform (uae_u16 what) +{ + switch (what) { + case EOP_INIT: + ersatz_init (); + break; + + case EOP_SERVEINT: + /* Just reset all the interrupt request bits */ + put_word (0xDFF09C, get_word (0xDFF01E) & 0x3FFF); + break; + + case EOP_DOIO: + ersatz_doio (); + break; + + case EOP_AVAILMEM: + m68k_dreg(regs, 0) = m68k_dreg(regs, 1) & 4 ? 0 : 0x70000; + break; + + case EOP_ALLOCMEM: + m68k_dreg(regs, 0) = m68k_dreg(regs, 1) & 4 ? 0 : 0x0F000; + break; + + case EOP_ALLOCABS: + m68k_dreg(regs, 0) = m68k_areg(regs, 1); + break; + + case EOP_NIMP: + write_log ("Unimplemented Kickstart function called\n"); + uae_quit (); + + /* fall through */ + case EOP_LOOP: + m68k_setpc (0xF80010); + break; + + case EOP_OPENLIB: + default: + write_log ("Internal error. Giving up.\n"); + abort (); + } +} diff --git a/expansion.c b/expansion.c new file mode 100755 index 00000000..3cbd1f2f --- /dev/null +++ b/expansion.c @@ -0,0 +1,1310 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * AutoConfig (tm) Expansions (ZorroII/III) + * + * Copyright 1996,1997 Stefan Reinauer + * Copyright 1997 Brian King + * - added gfxcard code + * + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "uae.h" +#include "memory.h" +#include "autoconf.h" +#include "picasso96.h" +#include "custom.h" +#include "newcpu.h" +#include "savestate.h" +#include "zfile.h" +#include "catweasel.h" + +#define MAX_EXPANSION_BOARDS 8 + +/* ********************************************************** */ +/* 00 / 02 */ +/* er_Type */ + +#define Z2_MEM_8MB 0x00 /* Size of Memory Block */ +#define Z2_MEM_4MB 0x07 +#define Z2_MEM_2MB 0x06 +#define Z2_MEM_1MB 0x05 +#define Z2_MEM_512KB 0x04 +#define Z2_MEM_256KB 0x03 +#define Z2_MEM_128KB 0x02 +#define Z2_MEM_64KB 0x01 +/* extended definitions */ +#define Z2_MEM_16MB 0x00 +#define Z2_MEM_32MB 0x01 +#define Z2_MEM_64MB 0x02 +#define Z2_MEM_128MB 0x03 +#define Z2_MEM_256MB 0x04 +#define Z2_MEM_512MB 0x05 +#define Z2_MEM_1GB 0x06 + +#define chainedconfig 0x08 /* Next config is part of the same card */ +#define rom_card 0x10 /* ROM vector is valid */ +#define add_memory 0x20 /* Link RAM into free memory list */ + +#define zorroII 0xc0 /* Type of Expansion Card */ +#define zorroIII 0x80 + +/* ********************************************************** */ +/* 04 - 06 & 10-16 */ + +/* Manufacturer */ +#define commodore_g 513 /* Commodore Braunschweig (Germany) */ +#define commodore 514 /* Commodore West Chester */ +#define gvp 2017 /* GVP */ +#define ass 2102 /* Advanced Systems & Software */ +#define hackers_id 2011 /* Special ID for test cards */ + +/* Card Type */ +#define commodore_a2091 3 /* A2091 / A590 Card from C= */ +#define commodore_a2091_ram 10 /* A2091 / A590 Ram on HD-Card */ +#define commodore_a2232 70 /* A2232 Multiport Expansion */ +#define ass_nexus_scsi 1 /* Nexus SCSI Controller */ + +#define gvp_series_2_scsi 11 +#define gvp_iv_24_gfx 32 + +/* ********************************************************** */ +/* 08 - 0A */ +/* er_Flags */ +#define Z3_MEM_64KB 0x02 +#define Z3_MEM_128KB 0x03 +#define Z3_MEM_256KB 0x04 +#define Z3_MEM_512KB 0x05 +#define Z3_MEM_1MB 0x06 /* Zorro III card subsize */ +#define Z3_MEM_2MB 0x07 +#define Z3_MEM_4MB 0x08 +#define Z3_MEM_6MB 0x09 +#define Z3_MEM_8MB 0x0a +#define Z3_MEM_10MB 0x0b +#define Z3_MEM_12MB 0x0c +#define Z3_MEM_14MB 0x0d +#define Z3_MEM_16MB 0x00 +#define Z3_MEM_AUTO 0x01 +#define Z3_MEM_defunct1 0x0e +#define Z3_MEM_defunct2 0x0f + +#define force_z3 0x10 /* *MUST* be set if card is Z3 */ +#define ext_size 0x20 /* Use extended size table for bits 0-2 of er_Type */ +#define no_shutup 0x40 /* Card cannot receive Shut_up_forever */ +#define care_addr 0x80 /* Adress HAS to be $200000-$9fffff */ + +/* ********************************************************** */ +/* 40-42 */ +/* ec_interrupt (unused) */ + +#define enable_irq 0x01 /* enable Interrupt */ +#define reset_card 0x04 /* Reset of Expansion Card - must be 0 */ +#define card_int2 0x10 /* READ ONLY: IRQ 2 active */ +#define card_irq6 0x20 /* READ ONLY: IRQ 6 active */ +#define card_irq7 0x40 /* READ ONLY: IRQ 7 active */ +#define does_irq 0x80 /* READ ONLY: Card currently throws IRQ */ + +/* ********************************************************** */ + +/* ROM defines (DiagVec) */ + +#define rom_4bit (0x00<<14) /* ROM width */ +#define rom_8bit (0x01<<14) +#define rom_16bit (0x02<<14) + +#define rom_never (0x00<<12) /* Never run Boot Code */ +#define rom_install (0x01<<12) /* run code at install time */ +#define rom_binddrv (0x02<<12) /* run code with binddrivers */ + +uaecptr ROM_filesys_resname, ROM_filesys_resid; +uaecptr ROM_filesys_diagentry; +uaecptr ROM_hardfile_resname, ROM_hardfile_resid; +uaecptr ROM_hardfile_init; + +/* ********************************************************** */ + +static void (*card_init[MAX_EXPANSION_BOARDS]) (void); +static void (*card_map[MAX_EXPANSION_BOARDS]) (void); + +static int ecard; + +/* ********************************************************** */ + +/* Please note: ZorroIII implementation seems to work different + * than described in the HRM. This claims that ZorroIII config + * address is 0xff000000 while the ZorroII config space starts + * at 0x00e80000. In reality, both, Z2 and Z3 cards are + * configured in the ZorroII config space. Kickstart 3.1 doesn't + * even do a single read or write access to the ZorroIII space. + * The original Amiga include files tell the same as the HRM. + * ZorroIII: If you set ext_size in er_Flags and give a Z2-size + * in er_Type you can very likely add some ZorroII address space + * to a ZorroIII card on a real Amiga. This is not implemented + * yet. + * -- Stefan + * + * Surprising that 0xFF000000 isn't used. Maybe it depends on the + * ROM. Anyway, the HRM says that Z3 cards may appear in Z2 config + * space, so what we are doing here is correct. + * -- Bernd + */ + +/* Autoconfig address space at 0xE80000 */ +static uae_u8 expamem[65536]; + +static uae_u8 expamem_lo; +static uae_u16 expamem_hi; + +/* + * Dummy entries to show that there's no card in a slot + */ + +static void expamem_map_clear (void) +{ + write_log ("expamem_map_clear() got called. Shouldn't happen.\n"); +} + +static void expamem_init_clear (void) +{ + memset (expamem, 0xff, sizeof expamem); +} +static void expamem_init_clear2 (void) +{ + expamem_init_clear(); + ecard = MAX_EXPANSION_BOARDS - 1; +} + +static uae_u32 expamem_lget (uaecptr) REGPARAM; +static uae_u32 expamem_wget (uaecptr) REGPARAM; +static uae_u32 expamem_bget (uaecptr) REGPARAM; +static void expamem_lput (uaecptr, uae_u32) REGPARAM; +static void expamem_wput (uaecptr, uae_u32) REGPARAM; +static void expamem_bput (uaecptr, uae_u32) REGPARAM; + +addrbank expamem_bank = { + expamem_lget, expamem_wget, expamem_bget, + expamem_lput, expamem_wput, expamem_bput, + default_xlate, default_check, NULL +}; + +static uae_u32 REGPARAM2 expamem_lget (uaecptr addr) +{ +#ifdef JIT + special_mem |= S_READ; +#endif + write_log ("warning: READ.L from address $%lx \n", addr); + return 0xfffffffful; +} + +static uae_u32 REGPARAM2 expamem_wget (uaecptr addr) +{ +#ifdef JIT + special_mem |= S_READ; +#endif + write_log ("warning: READ.W from address $%lx \n", addr); + return 0xffff; +} + +static uae_u32 REGPARAM2 expamem_bget (uaecptr addr) +{ +#ifdef JIT + special_mem |= S_READ; +#endif + addr &= 0xFFFF; + return expamem[addr]; +} + +static void REGPARAM2 expamem_write (uaecptr addr, uae_u32 value) +{ +#ifdef JIT + special_mem |= S_WRITE; +#endif + addr &= 0xffff; + if (addr == 00 || addr == 02 || addr == 0x40 || addr == 0x42) { + expamem[addr] = (value & 0xf0); + expamem[addr + 2] = (value & 0x0f) << 4; + } else { + expamem[addr] = ~(value & 0xf0); + expamem[addr + 2] = ~((value & 0x0f) << 4); + } +} + +static int REGPARAM2 expamem_type (void) +{ + return ((expamem[0] | expamem[2] >> 4) & 0xc0); +} + +static void REGPARAM2 expamem_lput (uaecptr addr, uae_u32 value) +{ +#ifdef JIT + special_mem |= S_WRITE; +#endif + write_log ("warning: WRITE.L to address $%lx : value $%lx\n", addr, value); +} + +static void REGPARAM2 expamem_wput (uaecptr addr, uae_u32 value) +{ +#ifdef JIT + special_mem |= S_WRITE; +#endif + if (expamem_type() != zorroIII) + write_log ("warning: WRITE.W to address $%lx : value $%x\n", addr, value); + else { + switch (addr & 0xff) { + case 0x44: + if (expamem_type() == zorroIII) { + // +Bernd Roesch + value = value - 0x3000; // maps to 0x10000000 + chipmem_wput (regs.regs[11] + 0x20, value); + chipmem_wput (regs.regs[11] + 0x28, value); + // -Bernd Roesch + expamem_hi = value; + (*card_map[ecard]) (); + write_log (" Card %d (Zorro%s) done.\n", ecard + 1, expamem_type() == 0xc0 ? "II" : "III"); + ++ecard; + if (ecard < MAX_EXPANSION_BOARDS) + (*card_init[ecard]) (); + else + expamem_init_clear2 (); + } + break; + } + } +} + +static void REGPARAM2 expamem_bput (uaecptr addr, uae_u32 value) +{ +#ifdef JIT + special_mem |= S_WRITE; +#endif + switch (addr & 0xff) { + case 0x30: + case 0x32: + expamem_hi = 0; + expamem_lo = 0; + expamem_write (0x48, 0x00); + break; + + case 0x48: + if (expamem_type () == zorroII) { + expamem_hi = value & 0xFF; + (*card_map[ecard]) (); + write_log (" Card %d (Zorro%s) done.\n", ecard + 1, expamem_type() == 0xc0 ? "II" : "III"); + ++ecard; + if (ecard < MAX_EXPANSION_BOARDS) + (*card_init[ecard]) (); + else + expamem_init_clear2 (); + } else if (expamem_type() == zorroIII) + expamem_lo = value; + break; + + case 0x4a: + if (expamem_type () == zorroII) + expamem_lo = value; + break; + + case 0x4c: + write_log (" Card %d (Zorro %s) had no success.\n", ecard + 1, expamem_type() == 0xc0 ? "II" : "III"); + ++ecard; + if (ecard < MAX_EXPANSION_BOARDS) + (*card_init[ecard]) (); + else + expamem_init_clear2 (); + break; + } +} + +/* ********************************************************** */ + +/* + * Fast Memory + */ + +static uae_u32 fastmem_mask; + +static uae_u32 fastmem_lget (uaecptr) REGPARAM; +static uae_u32 fastmem_wget (uaecptr) REGPARAM; +static uae_u32 fastmem_bget (uaecptr) REGPARAM; +static void fastmem_lput (uaecptr, uae_u32) REGPARAM; +static void fastmem_wput (uaecptr, uae_u32) REGPARAM; +static void fastmem_bput (uaecptr, uae_u32) REGPARAM; +static int fastmem_check (uaecptr addr, uae_u32 size) REGPARAM; +static uae_u8 *fastmem_xlate (uaecptr addr) REGPARAM; + +static uae_u32 fastmem_start; /* Determined by the OS */ +static uae_u8 *fastmemory; + +uae_u32 REGPARAM2 fastmem_lget (uaecptr addr) +{ + uae_u8 *m; + addr -= fastmem_start & fastmem_mask; + addr &= fastmem_mask; + m = fastmemory + addr; + return do_get_mem_long ((uae_u32 *)m); +} + +uae_u32 REGPARAM2 fastmem_wget (uaecptr addr) +{ + uae_u8 *m; + addr -= fastmem_start & fastmem_mask; + addr &= fastmem_mask; + m = fastmemory + addr; + return do_get_mem_word ((uae_u16 *)m); +} + +uae_u32 REGPARAM2 fastmem_bget (uaecptr addr) +{ + addr -= fastmem_start & fastmem_mask; + addr &= fastmem_mask; + return fastmemory[addr]; +} + +void REGPARAM2 fastmem_lput (uaecptr addr, uae_u32 l) +{ + uae_u8 *m; + addr -= fastmem_start & fastmem_mask; + addr &= fastmem_mask; + m = fastmemory + addr; + do_put_mem_long ((uae_u32 *)m, l); +} + +void REGPARAM2 fastmem_wput (uaecptr addr, uae_u32 w) +{ + uae_u8 *m; + addr -= fastmem_start & fastmem_mask; + addr &= fastmem_mask; + m = fastmemory + addr; + do_put_mem_word ((uae_u16 *)m, w); +} + +void REGPARAM2 fastmem_bput (uaecptr addr, uae_u32 b) +{ + addr -= fastmem_start & fastmem_mask; + addr &= fastmem_mask; + fastmemory[addr] = b; +} + +static int REGPARAM2 fastmem_check (uaecptr addr, uae_u32 size) +{ + addr -= fastmem_start & fastmem_mask; + addr &= fastmem_mask; + return (addr + size) <= allocated_fastmem; +} + +static uae_u8 REGPARAM2 *fastmem_xlate (uaecptr addr) +{ + addr -= fastmem_start & fastmem_mask; + addr &= fastmem_mask; + return fastmemory + addr; +} + +addrbank fastmem_bank = { + fastmem_lget, fastmem_wget, fastmem_bget, + fastmem_lput, fastmem_wput, fastmem_bput, + fastmem_xlate, fastmem_check, NULL +}; + + +#ifdef CATWEASEL + +/* + * Catweasel ZorroII + */ + +static uae_u32 catweasel_lget (uaecptr) REGPARAM; +static uae_u32 catweasel_wget (uaecptr) REGPARAM; +static uae_u32 catweasel_bget (uaecptr) REGPARAM; +static void catweasel_lput (uaecptr, uae_u32) REGPARAM; +static void catweasel_wput (uaecptr, uae_u32) REGPARAM; +static void catweasel_bput (uaecptr, uae_u32) REGPARAM; +static int catweasel_check (uaecptr addr, uae_u32 size) REGPARAM; +static uae_u8 *catweasel_xlate (uaecptr addr) REGPARAM; + +static uae_u32 catweasel_mask; +static uae_u32 catweasel_start; + +static uae_u32 REGPARAM2 catweasel_lget (uaecptr addr) +{ +#ifdef JIT + special_mem |= S_READ; +#endif + write_log("catweasel_lget @%08.8X!\n",addr); + return 0; +} + +static uae_u32 REGPARAM2 catweasel_wget (uaecptr addr) +{ +#ifdef JIT + special_mem |= S_READ; +#endif + write_log("catweasel_wget @%08.8X!\n",addr); + return 0; +} + +static uae_u32 REGPARAM2 catweasel_bget (uaecptr addr) +{ +#ifdef JIT + special_mem |= S_READ; +#endif + addr -= catweasel_start & catweasel_mask; + addr &= catweasel_mask; + return catweasel_do_bget (addr); +} + +static void REGPARAM2 catweasel_lput (uaecptr addr, uae_u32 l) +{ +#ifdef JIT + special_mem |= S_WRITE; +#endif + write_log("catweasel_lput @%08.8X=%08.8X!\n",addr,l); +} + +static void REGPARAM2 catweasel_wput (uaecptr addr, uae_u32 w) +{ +#ifdef JIT + special_mem |= S_WRITE; +#endif + write_log("catweasel_wput @%08.8X=%04.4X!\n",addr,w); +} + +static void REGPARAM2 catweasel_bput (uaecptr addr, uae_u32 b) +{ +#ifdef JIT + special_mem |= S_WRITE; +#endif + addr -= catweasel_start & catweasel_mask; + addr &= catweasel_mask; + catweasel_do_bput (addr, b); +} + +static int REGPARAM2 catweasel_check (uaecptr addr, uae_u32 size) +{ + write_log ("catweasel_check @%08.8X size %08.8X\n", addr, size); + return 0; +} + +static uae_u8 REGPARAM2 *catweasel_xlate (uaecptr addr) +{ + write_log ("catweasel_xlate @%08.8X size %08.8X\n", addr); + return 0; +} + +static addrbank catweasel_bank = { + catweasel_lget, catweasel_wget, catweasel_bget, + catweasel_lput, catweasel_wput, catweasel_bput, + catweasel_xlate, catweasel_check, NULL +}; + +static void expamem_map_catweasel (void) +{ + catweasel_start = ((expamem_hi | (expamem_lo >> 4)) << 16); + map_banks (&catweasel_bank, catweasel_start >> 16, 1, 0); + write_log ("Catweasel MK%d: mapped @$%lx\n", cwc.type, catweasel_start); +} + +static void expamem_init_catweasel (void) +{ + uae_u8 productid = cwc.type == CATWEASEL_TYPE_MK3 ? 66 : 200; + uae_u16 vendorid = cwc.type == CATWEASEL_TYPE_MK3 ? 4626 : 5001; + + catweasel_mask = (cwc.type == CATWEASEL_TYPE_MK3) ? 0xffff : 0x1ffff; + + expamem_init_clear(); + + expamem_write (0x00, (cwc.type == CATWEASEL_TYPE_MK3 ? Z2_MEM_64KB : Z2_MEM_128KB) | zorroII); + + expamem_write (0x04, productid); + + expamem_write (0x08, no_shutup); + + expamem_write (0x10, vendorid >> 8); + expamem_write (0x14, vendorid & 0xff); + + expamem_write (0x18, 0x00); /* ser.no. Byte 0 */ + expamem_write (0x1c, 0x00); /* ser.no. Byte 1 */ + expamem_write (0x20, 0x00); /* ser.no. Byte 2 */ + expamem_write (0x24, 0x00); /* ser.no. Byte 3 */ + + expamem_write (0x28, 0x00); /* Rom-Offset hi */ + expamem_write (0x2c, 0x00); /* ROM-Offset lo */ + + expamem_write (0x40, 0x00); /* Ctrl/Statusreg.*/ +} + +#endif + +/* + * CDTV DMAC + */ + +//#define CDTV_DEBUG + +static uae_u32 dmac_lget (uaecptr) REGPARAM; +static uae_u32 dmac_wget (uaecptr) REGPARAM; +static uae_u32 dmac_bget (uaecptr) REGPARAM; +static void dmac_lput (uaecptr, uae_u32) REGPARAM; +static void dmac_wput (uaecptr, uae_u32) REGPARAM; +static void dmac_bput (uaecptr, uae_u32) REGPARAM; + +static uae_u32 dmac_start = 0xe90000; +static uae_u8 dmacmemory[0x100]; + +static int cdtv_command_len; +static uae_u8 cdtv_command_buf[6]; + +static void cdtv_interrupt (int v) +{ + write_log ("cdtv int %d\n", v); + dmacmemory[0x41] = (1 << 4) | (1 << 6); + Interrupt (6); +} + +uae_u32 REGPARAM2 dmac_lget (uaecptr addr) +{ +#ifdef JIT + special_mem |= S_READ; +#endif +#ifdef CDTV_DEBUG + write_log ("dmac_lget %08.8X\n", addr); +#endif + return (dmac_wget (addr) << 16) | dmac_wget (addr + 2); +} + +uae_u32 REGPARAM2 dmac_wget (uaecptr addr) +{ +#ifdef JIT + special_mem |= S_READ; +#endif +#ifdef CDTV_DEBUG + write_log ("dmac_wget %08.8X PC=%X\n", addr, m68k_getpc()); +#endif + return (dmac_bget (addr) << 8) | dmac_bget (addr + 1); +} + +uae_u32 REGPARAM2 dmac_bget (uaecptr addr) +{ +#ifdef JIT + special_mem |= S_READ; +#endif +#ifdef CDTV_DEBUG + write_log ("dmac_bget %08.8X PC=%X\n", addr, m68k_getpc()); +#endif + addr -= dmac_start; + addr &= 65535; + switch (addr) + { + case 0xa3: + return 1; + } + return dmacmemory[addr]; +} + +static void REGPARAM2 dmac_lput (uaecptr addr, uae_u32 l) +{ +#ifdef JIT + special_mem |= S_WRITE; +#endif +#ifdef CDTV_DEBUG + write_log ("dmac_lput %08.8X = %08.8X\n", addr, l); +#endif + dmac_wput (addr, l >> 16); + dmac_wput (addr + 2, l); +} + +static void REGPARAM2 dmac_wput (uaecptr addr, uae_u32 w) +{ +#ifdef JIT + special_mem |= S_WRITE; +#endif +#ifdef CDTV_DEBUG + write_log ("dmac_wput %04.4X = %04.4X\n", addr, w & 65535); +#endif + dmac_bput (addr, w >> 8); + dmac_bput (addr, w); +} + +static void REGPARAM2 dmac_bput (uaecptr addr, uae_u32 b) +{ +#ifdef JIT + special_mem |= S_WRITE; +#endif +#ifdef CDTV_DEBUG + write_log ("dmac_bput %08.8X = %02.2X PC=%X\n", addr, b & 255, m68k_getpc()); +#endif + addr -= dmac_start; + addr &= 65535; +#ifdef CDTV_DEBUG + dmacmemory[addr] = b; + switch (addr) + { + case 0xa1: + if (cdtv_command_len >= sizeof (cdtv_command_buf)) + cdtv_command_len = sizeof (cdtv_command_buf) - 1; + cdtv_command_buf[cdtv_command_len++] = b; + if (cdtv_command_len == 6) { + cdtv_interrupt (1); + } + break; + case 0xa5: + cdtv_command_len = 0; + break; + case 0xe4: + dmacmemory[0x41] = 0; + write_log ("cdtv interrupt cleared\n"); + activate_debugger(); + break; + } +#endif +} + +addrbank dmac_bank = { + dmac_lget, dmac_wget, dmac_bget, + dmac_lput, dmac_wput, dmac_bput, + default_xlate, default_check, NULL +}; + +/* + * Filesystem device ROM + * This is very simple, the Amiga shouldn't be doing things with it. + */ + +static uae_u32 filesys_lget (uaecptr) REGPARAM; +static uae_u32 filesys_wget (uaecptr) REGPARAM; +static uae_u32 filesys_bget (uaecptr) REGPARAM; +static void filesys_lput (uaecptr, uae_u32) REGPARAM; +static void filesys_wput (uaecptr, uae_u32) REGPARAM; +static void filesys_bput (uaecptr, uae_u32) REGPARAM; + +static uae_u32 filesys_start; /* Determined by the OS */ +uae_u8 *filesysory; + +uae_u32 REGPARAM2 filesys_lget (uaecptr addr) +{ + uae_u8 *m; +#ifdef JIT + special_mem |= S_READ; +#endif + addr -= filesys_start & 65535; + addr &= 65535; + m = filesysory + addr; + return do_get_mem_long ((uae_u32 *)m); +} + +uae_u32 REGPARAM2 filesys_wget (uaecptr addr) +{ + uae_u8 *m; +#ifdef JIT + special_mem |= S_READ; +#endif + addr -= filesys_start & 65535; + addr &= 65535; + m = filesysory + addr; + return do_get_mem_word ((uae_u16 *)m); +} + +uae_u32 REGPARAM2 filesys_bget (uaecptr addr) +{ +#ifdef JIT + special_mem |= S_READ; +#endif + addr -= filesys_start & 65535; + addr &= 65535; + return filesysory[addr]; +} + +static void REGPARAM2 filesys_lput (uaecptr addr, uae_u32 l) +{ +#ifdef JIT + special_mem |= S_WRITE; +#endif + write_log ("filesys_lput called PC=%p\n", m68k_getpc()); +} + +static void REGPARAM2 filesys_wput (uaecptr addr, uae_u32 w) +{ +#ifdef JIT + special_mem |= S_WRITE; +#endif + write_log ("filesys_wput called PC=%p\n", m68k_getpc()); +} + +static void REGPARAM2 filesys_bput (uaecptr addr, uae_u32 b) +{ +#ifdef JIT + special_mem |= S_WRITE; +#endif + write_log ("filesys_bput called. This usually means that you are using\n"); + write_log ("Kickstart 1.2. Please give UAE the \"-a\" option next time\n"); + write_log ("you start it. If you are _not_ using Kickstart 1.2, then\n"); + write_log ("there's a bug somewhere.\n"); + write_log ("Exiting...\n"); + uae_quit (); +} + +static addrbank filesys_bank = { + filesys_lget, filesys_wget, filesys_bget, + filesys_lput, filesys_wput, filesys_bput, + default_xlate, default_check, NULL +}; + +/* + * Z3fastmem Memory + */ + +static uae_u32 z3fastmem_mask; + +static uae_u32 z3fastmem_lget (uaecptr) REGPARAM; +static uae_u32 z3fastmem_wget (uaecptr) REGPARAM; +static uae_u32 z3fastmem_bget (uaecptr) REGPARAM; +static void z3fastmem_lput (uaecptr, uae_u32) REGPARAM; +static void z3fastmem_wput (uaecptr, uae_u32) REGPARAM; +static void z3fastmem_bput (uaecptr, uae_u32) REGPARAM; +static int z3fastmem_check (uaecptr addr, uae_u32 size) REGPARAM; +static uae_u8 *z3fastmem_xlate (uaecptr addr) REGPARAM; + +static uae_u32 z3fastmem_start; /* Determined by the OS */ +static uae_u8 *z3fastmem; + +uae_u32 REGPARAM2 z3fastmem_lget (uaecptr addr) +{ + uae_u8 *m; + addr -= z3fastmem_start & z3fastmem_mask; + addr &= z3fastmem_mask; + m = z3fastmem + addr; + return do_get_mem_long ((uae_u32 *)m); +} + +uae_u32 REGPARAM2 z3fastmem_wget (uaecptr addr) +{ + uae_u8 *m; + addr -= z3fastmem_start & z3fastmem_mask; + addr &= z3fastmem_mask; + m = z3fastmem + addr; + return do_get_mem_word ((uae_u16 *)m); +} + +uae_u32 REGPARAM2 z3fastmem_bget (uaecptr addr) +{ + addr -= z3fastmem_start & z3fastmem_mask; + addr &= z3fastmem_mask; + return z3fastmem[addr]; +} + +void REGPARAM2 z3fastmem_lput (uaecptr addr, uae_u32 l) +{ + uae_u8 *m; + addr -= z3fastmem_start & z3fastmem_mask; + addr &= z3fastmem_mask; + m = z3fastmem + addr; + do_put_mem_long ((uae_u32 *)m, l); +} + +void REGPARAM2 z3fastmem_wput (uaecptr addr, uae_u32 w) +{ + uae_u8 *m; + addr -= z3fastmem_start & z3fastmem_mask; + addr &= z3fastmem_mask; + m = z3fastmem + addr; + do_put_mem_word ((uae_u16 *)m, w); +} + +void REGPARAM2 z3fastmem_bput (uaecptr addr, uae_u32 b) +{ + addr -= z3fastmem_start & z3fastmem_mask; + addr &= z3fastmem_mask; + z3fastmem[addr] = b; +} + +static int REGPARAM2 z3fastmem_check (uaecptr addr, uae_u32 size) +{ + addr -= z3fastmem_start & z3fastmem_mask; + addr &= z3fastmem_mask; + return (addr + size) <= allocated_z3fastmem; +} + +static uae_u8 REGPARAM2 *z3fastmem_xlate (uaecptr addr) +{ + addr -= z3fastmem_start & z3fastmem_mask; + addr &= z3fastmem_mask; + return z3fastmem + addr; +} + +addrbank z3fastmem_bank = { + z3fastmem_lget, z3fastmem_wget, z3fastmem_bget, + z3fastmem_lput, z3fastmem_wput, z3fastmem_bput, + z3fastmem_xlate, z3fastmem_check, NULL +}; + +/* Z3-based UAEGFX-card */ +uae_u32 gfxmem_mask; /* for memory.c */ +uae_u8 *gfxmemory; +uae_u32 gfxmem_start; + +/* ********************************************************** */ + +/* + * Expansion Card (ZORRO II) for 1/2/4/8 MB of Fast Memory + */ + +static void expamem_map_fastcard (void) +{ + fastmem_start = ((expamem_hi | (expamem_lo >> 4)) << 16); + map_banks (&fastmem_bank, fastmem_start >> 16, allocated_fastmem >> 16, allocated_fastmem); + write_log ("Fastcard: mapped @$%lx: %dMB fast memory\n", fastmem_start, allocated_fastmem >> 20); +} + +static void expamem_init_fastcard (void) +{ + expamem_init_clear(); + if (allocated_fastmem == 0x100000) + expamem_write (0x00, Z2_MEM_1MB + add_memory + zorroII); + else if (allocated_fastmem == 0x200000) + expamem_write (0x00, Z2_MEM_2MB + add_memory + zorroII); + else if (allocated_fastmem == 0x400000) + expamem_write (0x00, Z2_MEM_4MB + add_memory + zorroII); + else if (allocated_fastmem == 0x800000) + expamem_write (0x00, Z2_MEM_8MB + add_memory + zorroII); + + expamem_write (0x08, care_addr); + + expamem_write (0x04, 1); + + expamem_write (0x10, hackers_id >> 8); + expamem_write (0x14, hackers_id & 0xff); + + expamem_write (0x18, 0x00); /* ser.no. Byte 0 */ + expamem_write (0x1c, 0x00); /* ser.no. Byte 1 */ + expamem_write (0x20, 0x00); /* ser.no. Byte 2 */ + expamem_write (0x24, 0x01); /* ser.no. Byte 3 */ + + expamem_write (0x28, 0x00); /* Rom-Offset hi */ + expamem_write (0x2c, 0x00); /* ROM-Offset lo */ + + expamem_write (0x40, 0x00); /* Ctrl/Statusreg.*/ +} + +/* ********************************************************** */ + +/* + * Filesystem device + */ + +static void expamem_map_filesys (void) +{ + uaecptr a; + + filesys_start = ((expamem_hi | (expamem_lo >> 4)) << 16); + map_banks (&filesys_bank, filesys_start >> 16, 1, 0); + write_log ("Filesystem: mapped memory @$%lx.\n", filesys_start); + /* 68k code needs to know this. */ + a = here (); + org (RTAREA_BASE+0xFFFC); + dl (filesys_start + 0x2000); + org (a); +} + +static void expamem_init_filesys (void) +{ + /* struct DiagArea - the size has to be large enough to store several device ROMTags */ + uae_u8 diagarea[] = { 0x90, 0x00, /* da_Config, da_Flags */ + 0x02, 0x00, /* da_Size */ + 0x01, 0x00, /* da_DiagPoint */ + 0x01, 0x06 /* da_BootPoint */ + }; + + expamem_init_clear(); + expamem_write (0x00, Z2_MEM_64KB | rom_card | zorroII); + + expamem_write (0x08, no_shutup); + + expamem_write (0x04, 2); + expamem_write (0x10, hackers_id >> 8); + expamem_write (0x14, hackers_id & 0xff); + + expamem_write (0x18, 0x00); /* ser.no. Byte 0 */ + expamem_write (0x1c, 0x00); /* ser.no. Byte 1 */ + expamem_write (0x20, 0x00); /* ser.no. Byte 2 */ + expamem_write (0x24, 0x01); /* ser.no. Byte 3 */ + + /* er_InitDiagVec */ + expamem_write (0x28, 0x10); /* Rom-Offset hi */ + expamem_write (0x2c, 0x00); /* ROM-Offset lo */ + + expamem_write (0x40, 0x00); /* Ctrl/Statusreg.*/ + + /* Build a DiagArea */ + memcpy (expamem + 0x1000, diagarea, sizeof diagarea); + + /* Call DiagEntry */ + do_put_mem_word ((uae_u16 *)(expamem + 0x1100), 0x4EF9); /* JMP */ + do_put_mem_long ((uae_u32 *)(expamem + 0x1102), ROM_filesys_diagentry); + + /* What comes next is a plain bootblock */ + do_put_mem_word ((uae_u16 *)(expamem + 0x1106), 0x4EF9); /* JMP */ + do_put_mem_long ((uae_u32 *)(expamem + 0x1108), EXPANSION_bootcode); + + memcpy (filesysory, expamem, 0x3000); +} + +/* + * Zorro III expansion memory + */ + +static void expamem_map_z3fastmem (void) +{ + int z3fs = ((expamem_hi | (expamem_lo >> 4)) << 16); + + if (z3fastmem_start != z3fs) { + write_log("WARNING: Z3FAST mapping changed from $%lx to $%lx\n", z3fastmem_start, z3fs); + map_banks(&dummy_bank, z3fastmem_start >> 16, currprefs.z3fastmem_size >> 16, + allocated_z3fastmem); + z3fastmem_start = z3fs; + map_banks (&z3fastmem_bank, z3fastmem_start >> 16, currprefs.z3fastmem_size >> 16, + allocated_z3fastmem); + } + write_log ("Fastmem (32bit): mapped @$%lx: %d MB Zorro III fast memory \n", + z3fastmem_start, allocated_z3fastmem / 0x100000); +} + +static void expamem_init_z3fastmem (void) +{ + int code = (allocated_z3fastmem == 0x100000 ? Z2_MEM_1MB + : allocated_z3fastmem == 0x200000 ? Z2_MEM_2MB + : allocated_z3fastmem == 0x400000 ? Z2_MEM_4MB + : allocated_z3fastmem == 0x800000 ? Z2_MEM_8MB + : allocated_z3fastmem == 0x1000000 ? Z2_MEM_16MB + : allocated_z3fastmem == 0x2000000 ? Z2_MEM_32MB + : allocated_z3fastmem == 0x4000000 ? Z2_MEM_64MB + : allocated_z3fastmem == 0x8000000 ? Z2_MEM_128MB + : allocated_z3fastmem == 0x10000000 ? Z2_MEM_256MB + : allocated_z3fastmem == 0x20000000 ? Z2_MEM_512MB + : Z2_MEM_1GB); + expamem_init_clear(); + expamem_write (0x00, add_memory | zorroIII | code); + + expamem_write (0x08, no_shutup | force_z3 | (allocated_z3fastmem > 0x800000 ? ext_size : Z3_MEM_AUTO)); + + expamem_write (0x04, 3); + + expamem_write (0x10, hackers_id >> 8); + expamem_write (0x14, hackers_id & 0xff); + + expamem_write (0x18, 0x00); /* ser.no. Byte 0 */ + expamem_write (0x1c, 0x00); /* ser.no. Byte 1 */ + expamem_write (0x20, 0x00); /* ser.no. Byte 2 */ + expamem_write (0x24, 0x01); /* ser.no. Byte 3 */ + + expamem_write (0x28, 0x00); /* Rom-Offset hi */ + expamem_write (0x2c, 0x00); /* ROM-Offset lo */ + + expamem_write (0x40, 0x00); /* Ctrl/Statusreg.*/ + + z3fastmem_start = 0x10000000; + + map_banks (&z3fastmem_bank, z3fastmem_start >> 16, currprefs.z3fastmem_size >> 16, + allocated_z3fastmem); + +} + +#ifdef PICASSO96 +/* + * Fake Graphics Card (ZORRO III) - BDK + */ + +static void expamem_map_gfxcard (void) +{ + gfxmem_start = ((expamem_hi | (expamem_lo >> 4)) << 16); + map_banks (&gfxmem_bank, gfxmem_start >> 16, allocated_gfxmem >> 16, allocated_gfxmem); + write_log ("UAEGFX-card: mapped @$%lx \n", gfxmem_start); +} + +static void expamem_init_gfxcard (void) +{ + expamem_init_clear(); + expamem_write (0x00, zorroIII); + + switch (allocated_gfxmem) { + case 0x00100000: + expamem_write (0x08, no_shutup | force_z3 | Z3_MEM_1MB); + break; + case 0x00200000: + expamem_write (0x08, no_shutup | force_z3 | Z3_MEM_2MB); + break; + case 0x00400000: + expamem_write (0x08, no_shutup | force_z3 | Z3_MEM_4MB); + break; + case 0x00800000: + expamem_write (0x08, no_shutup | force_z3 | Z3_MEM_8MB); + break; + } + + expamem_write (0x04, 96); + + expamem_write (0x10, hackers_id >> 8); + expamem_write (0x14, hackers_id & 0xff); + + expamem_write (0x18, 0x00); /* ser.no. Byte 0 */ + expamem_write (0x1c, 0x00); /* ser.no. Byte 1 */ + expamem_write (0x20, 0x00); /* ser.no. Byte 2 */ + expamem_write (0x24, 0x01); /* ser.no. Byte 3 */ + + expamem_write (0x28, 0x00); /* Rom-Offset hi */ + expamem_write (0x2c, 0x00); /* ROM-Offset lo */ + + expamem_write (0x40, 0x00); /* Ctrl/Statusreg.*/ +} +#endif + +static long fast_filepos, z3_filepos, p96_filepos; + +static void allocate_expamem (void) +{ + currprefs.fastmem_size = changed_prefs.fastmem_size; + currprefs.z3fastmem_size = changed_prefs.z3fastmem_size; + currprefs.gfxmem_size = changed_prefs.gfxmem_size; + + if (allocated_fastmem != currprefs.fastmem_size) { + if (fastmemory) + mapped_free (fastmemory); + fastmemory = 0; + allocated_fastmem = currprefs.fastmem_size; + fastmem_mask = allocated_fastmem - 1; + + if (allocated_fastmem) { + fastmemory = mapped_malloc (allocated_fastmem, "fast"); + if (fastmemory == 0) { + write_log ("Out of memory for fastmem card.\n"); + allocated_fastmem = 0; + } + } + clearexec (); + } + if (allocated_z3fastmem != currprefs.z3fastmem_size) { + if (z3fastmem) + mapped_free (z3fastmem); + z3fastmem = 0; + + allocated_z3fastmem = currprefs.z3fastmem_size; + z3fastmem_mask = allocated_z3fastmem - 1; + + if (allocated_z3fastmem) { + z3fastmem = mapped_malloc (allocated_z3fastmem, "z3"); + if (z3fastmem == 0) { + write_log ("Out of memory for 32 bit fast memory.\n"); + allocated_z3fastmem = 0; + } + } + clearexec (); + } + if (allocated_gfxmem != currprefs.gfxmem_size) { + if (gfxmemory) + mapped_free (gfxmemory); + gfxmemory = 0; + + allocated_gfxmem = currprefs.gfxmem_size; + gfxmem_mask = allocated_gfxmem - 1; + + if (allocated_gfxmem) { + gfxmemory = mapped_malloc (allocated_gfxmem, "gfx"); + if (gfxmemory == 0) { + write_log ("Out of memory for graphics card memory\n"); + allocated_gfxmem = 0; + } + } + clearexec (); + } + + z3fastmem_bank.baseaddr = z3fastmem; + fastmem_bank.baseaddr = fastmemory; + + if (savestate_state == STATE_RESTORE) { + if (allocated_fastmem > 0) { + restore_ram (fast_filepos, fastmemory); + map_banks (&fastmem_bank, fastmem_start >> 16, currprefs.fastmem_size >> 16, + allocated_fastmem); + } + if (allocated_z3fastmem > 0) { + restore_ram (z3_filepos, z3fastmem); + map_banks (&z3fastmem_bank, z3fastmem_start >> 16, currprefs.z3fastmem_size >> 16, + allocated_z3fastmem); + } + if (allocated_gfxmem > 0 && gfxmem_start > 0) { + restore_ram (p96_filepos, gfxmemory); + map_banks (&gfxmem_bank, gfxmem_start >> 16, currprefs.gfxmem_size >> 16, + allocated_gfxmem); + } + } +} + +extern int cdtv_enabled; + +void expamem_reset (void) +{ + int do_mount = 1; + int cardno = 0; + ecard = 0; + + allocate_expamem (); + + if (cdtv_enabled) + map_banks (&dmac_bank, dmac_start >> 16, 0x10000 >> 16, 0x10000); + + /* check if Kickstart version is below 1.3 */ + if (! ersatzkickfile && kickstart_version + && (/* Kickstart 1.0 & 1.1! */ + kickstart_version == 0xFFFF + /* Kickstart < 1.3 */ + || kickstart_version < 34)) + { + /* warn user */ + write_log ("Kickstart version is below 1.3! Disabling autoconfig devices.\n"); + do_mount = 0; + } + /* No need for filesystem stuff if there aren't any mounted. */ + if (nr_units (currprefs.mountinfo) == 0) + do_mount = 0; + + if (fastmemory != NULL) { + card_init[cardno] = expamem_init_fastcard; + card_map[cardno++] = expamem_map_fastcard; + } + if (z3fastmem != NULL) { + card_init[cardno] = expamem_init_z3fastmem; + card_map[cardno++] = expamem_map_z3fastmem; + } +#ifdef PICASSO96 + if (gfxmemory != NULL) { + card_init[cardno] = expamem_init_gfxcard; + card_map[cardno++] = expamem_map_gfxcard; + } +#endif + if (do_mount && ! ersatzkickfile) { + card_init[cardno] = expamem_init_filesys; + card_map[cardno++] = expamem_map_filesys; + } +#ifdef CATWEASEL + if (catweasel_init ()) { + card_init[cardno] = expamem_init_catweasel; + card_map[cardno++] = expamem_map_catweasel; + } +#endif + while (cardno < MAX_EXPANSION_BOARDS) { + card_init[cardno] = expamem_init_clear; + card_map[cardno++] = expamem_map_clear; + } + + (*card_init[0]) (); +} + +void expansion_init (void) +{ + z3fastmem = 0; + gfxmemory = 0; + fastmemory = 0; + allocated_z3fastmem = 0; + allocated_gfxmem = 0; + allocated_fastmem = 0; + fastmem_mask = fastmem_start = 0; + fastmemory = 0; + gfxmem_mask = gfxmem_start = 0; + gfxmemory = 0; + catweasel_mask = catweasel_start = 0; + filesys_start = 0; + filesysory = 0; + z3fastmem_mask = z3fastmem_start = 0; + z3fastmem = 0; + + allocate_expamem (); + + filesysory = (uae_u8 *) mapped_malloc (0x10000, "filesys"); + if (!filesysory) { + write_log ("virtual memory exhausted (filesysory)!\n"); + exit (0); + } + filesys_bank.baseaddr = (uae_u8*)filesysory; + +} + +void expansion_cleanup (void) +{ + if (fastmemory) + mapped_free (fastmemory); + if (z3fastmem) + mapped_free (z3fastmem); + if (gfxmemory) + mapped_free (gfxmemory); + if (filesysory) + mapped_free (filesysory); + fastmemory = 0; + z3fastmem = 0; + gfxmemory = 0; + filesysory = 0; +#ifdef CATWEASEL + catweasel_free (); +#endif +} + +/* State save/restore code. */ + +uae_u8 *save_fram (int *len) +{ + *len = allocated_fastmem; + return fastmemory; +} + +uae_u8 *save_zram (int *len) +{ + *len = allocated_z3fastmem; + return z3fastmem; +} + +uae_u8 *save_pram (int *len) +{ + *len = allocated_gfxmem; + return gfxmemory; +} + +void restore_fram (int len, long filepos) +{ + fast_filepos = filepos; + changed_prefs.fastmem_size = len; +} + +void restore_zram (int len, long filepos) +{ + z3_filepos = filepos; + changed_prefs.z3fastmem_size = len; +} + +void restore_pram (int len, long filepos) +{ + p96_filepos = filepos; + changed_prefs.gfxmem_size = len; +} + +uae_u8 *save_expansion (int *len, uae_u8 *dstptr) +{ + static uae_u8 t[20]; + uae_u8 *dst = t, *dstbak = t; + if (dstptr) + dst = dstbak = dstptr; + save_u32 (fastmem_start); + save_u32 (z3fastmem_start); + save_u32 (gfxmem_start); + *len = 4 + 4 + 4; + return dstbak; +} + +uae_u8 *restore_expansion (uae_u8 *src) +{ + fastmem_start = restore_u32 (); + z3fastmem_start = restore_u32 (); + gfxmem_start = restore_u32 (); + return src; +} diff --git a/fdi2raw.c b/fdi2raw.c new file mode 100755 index 00000000..adc770bd --- /dev/null +++ b/fdi2raw.c @@ -0,0 +1,1841 @@ +/* + + FDI to raw bit stream converter + Copyright (c) 2001 by Toni Wilen + FDI 2.0 support + Copyright (c) 2003-2004 by Toni Wilen + 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 +#include +#include + +/* IF UAE */ +#include "sysconfig.h" +#include "sysdeps.h" +#include "zfile.h" +/* ELSE */ +//#include "types.h" + +#include "fdi2raw.h" + +#undef DEBUG +#define VERBOSE + +#include + +#ifdef DEBUG +static char *datalog(uae_u8 *src, int len) +{ + static char buf[1000]; + static int offset; + int i = 0, offset2; + + offset2 = offset; + buf[offset++]='\''; + while(len--) { + sprintf (buf + offset, "%02.2X", src[i]); + offset += 2; + i++; + if (i > 10) break; + } + buf[offset++]='\''; + buf[offset++] = 0; + if (offset >= 900) offset = 0; + return buf + offset2; +} +#else +static char *datalog(uae_u8 *src, int len) { return ""; } +#endif + +#ifdef DEBUG +#define debuglog write_log +#else +#define debuglog +#endif +#ifdef VERBOSE +#define outlog write_log +#else +#define outlog +#endif + +static int fdi_allocated; +#ifdef DEBUG +static void fdi_free (void *p) +{ + int size; + if (!p) + return; + size = ((int*)p)[-1]; + fdi_allocated -= size; + write_log ("%d freed (%d)\n", size, fdi_allocated); + free ((int*)p - 1); +} +static void *fdi_malloc (int size) +{ + void *p = xmalloc (size + sizeof (int)); + ((int*)p)[0] = size; + fdi_allocated += size; + write_log ("%d allocated (%d)\n", size, fdi_allocated); + return (int*)p + 1; +} +#else +#define fdi_free free +#define fdi_malloc xmalloc +#endif + +#define MAX_SRC_BUFFER 4194304 +#define MAX_DST_BUFFER 40000 +#define MAX_MFM_SYNC_BUFFER 60000 +#define MAX_TIMING_BUFFER 400000 +#define MAX_TRACKS 166 +#define MAX_REVOLUTIONS 4 + +struct fdi_cache { + uae_u8 *cache_buffer[MAX_REVOLUTIONS]; + uae_u8 *cache_buffer_timing; + int length[MAX_REVOLUTIONS]; + int indexoffset; +}; + +struct fdi { + uae_u8 *track_src_buffer; + uae_u8 *track_src; + int track_src_len; + uae_u8 *track_dst_buffer; + uae_u8 *track_dst; + uae_u16 *track_dst_buffer_timing; + uae_u8 track_len; + uae_u8 track_type; + int current_track; + int last_track; + int last_head; + int rotation_speed; + int bit_rate; + int disk_type; + int write_protect; + int err; + uae_u8 header[2048]; + int track_offsets[MAX_TRACKS]; + struct zfile *file; + int out; + int mfmsync_offset; + int *mfmsync_buffer; + /* sector described only */ + int index_offset; + int encoding_type; + /* bit handling */ + int nextdrop; + struct fdi_cache cache[MAX_TRACKS]; +}; + +#define get_u32(x) ((((x)[0])<<24)|(((x)[1])<<16)|(((x)[2])<<8)|((x)[3])) +#define get_u24(x) ((((x)[0])<<16)|(((x)[1])<<8)|((x)[2])) +STATIC_INLINE put_u32 (uae_u8 *d, uae_u32 v) +{ + d[0] = v >> 24; + d[1] = v >> 16; + d[2] = v >> 8; + d[3] = v; +} + +struct node { + uae_u16 v; + struct node *left; + struct node *right; +}; +typedef struct node NODE; + +static uae_u8 temp, temp2; + +static uae_u8 *expand_tree (uae_u8 *stream, NODE *node) +{ + if (temp & temp2) { + fdi_free (node->left); + node->left = 0; + fdi_free (node->right); + node->right = 0; + temp2 >>= 1; + if (!temp2) { + temp = *stream++; + temp2 = 0x80; + } + return stream; + } else { + uae_u8 *stream_temp; + temp2 >>= 1; + if (!temp2) { + temp = *stream++; + temp2 = 0x80; + } + node->left = fdi_malloc (sizeof (NODE)); + memset (node->left, 0, sizeof (NODE)); + stream_temp = expand_tree (stream, node->left); + node->right = fdi_malloc (sizeof (NODE)); + memset (node->right, 0, sizeof (NODE)); + return expand_tree (stream_temp, node->right); + } +} + +static uae_u8 *values_tree8 (uae_u8 *stream, NODE *node) +{ + if (node->left == 0) { + node->v = *stream++; + return stream; + } else { + uae_u8 *stream_temp = values_tree8 (stream, node->left); + return values_tree8 (stream_temp, node->right); + } +} + +static uae_u8 *values_tree16 (uae_u8 *stream, NODE *node) +{ + if (node->left == 0) { + uae_u16 high_8_bits = (*stream++) << 8; + node->v = high_8_bits | (*stream++); + return stream; + } else { + uae_u8 *stream_temp = values_tree16 (stream, node->left); + return values_tree16 (stream_temp, node->right); + } +} + +static void free_nodes (NODE *node) +{ + if (node) { + free_nodes (node->left); + free_nodes (node->right); + fdi_free (node); + } +} + +static uae_u32 sign_extend16 (uae_u32 v) +{ + if (v & 0x8000) + v |= 0xffff0000; + return v; +} + +static uae_u32 sign_extend8 (uae_u32 v) +{ + if (v & 0x80) + v |= 0xffffff00; + return v; +} + +static void fdi_decode (uae_u8 *stream, int size, uae_u8 *out) +{ + int i; + uae_u8 sign_extend, sixteen_bit, sub_stream_shift; + NODE root; + NODE *current_node; + + memset (out, 0, size * 4); + sub_stream_shift = 1; + while (sub_stream_shift) { + + //sub-stream header decode + sign_extend = *stream++; + sub_stream_shift = sign_extend & 0x7f; + sign_extend &= 0x80; + sixteen_bit = (*stream++) & 0x80; + + //huffman tree architecture decode + temp = *stream++; + temp2 = 0x80; + stream = expand_tree (stream, &root); + if (temp2 == 0x80) + stream--; + + //huffman output values decode + if (sixteen_bit) + stream = values_tree16 (stream, &root); + else + stream = values_tree8 (stream, &root); + + //sub-stream data decode + temp2 = 0; + for (i = 0; i < size; i++) { + uae_u32 v; + uae_u8 decode = 1; + current_node = &root; + while (decode) { + if (current_node->left == 0) { + decode = 0; + } else { + temp2 >>= 1; + if (!temp2) { + temp2 = 0x80; + temp = *stream++; + } + if (temp & temp2) + current_node = current_node->right; + else + current_node = current_node->left; + } + } + v = ((uae_u32*)out)[i]; + if (sign_extend) { + if (sixteen_bit) + v |= sign_extend16 (current_node->v) << sub_stream_shift; + else + v |= sign_extend8 (current_node->v) << sub_stream_shift; + } else { + v |= current_node->v << sub_stream_shift; + } + ((uae_u32*)out)[i] = v; + } + free_nodes (root.left); + free_nodes (root.right); + } +} + + +static int decode_raw_track (FDI *fdi) +{ + int size = get_u32(fdi->track_src); + memcpy (fdi->track_dst, fdi->track_src, (size + 7) >> 3); + fdi->track_src += (size + 7) >> 3; + return size; +} + +/* unknown track */ +static void zxx (FDI *fdi) +{ + outlog ("track %d: unknown track type 0x%02.2X\n", fdi->current_track, fdi->track_type); +// return -1; +} +/* unsupported track */ +static void zyy (FDI *fdi) +{ + outlog ("track %d: unsupported track type 0x%02.2X\n", fdi->current_track, fdi->track_type); +// return -1; +} +/* empty track */ +static void track_empty (FDI *fdi) +{ +// return 0; +} + +/* unknown sector described type */ +static void dxx (FDI *fdi) +{ + outlog ("\ntrack %d: unknown sector described type 0x%02.2X\n", fdi->current_track, fdi->track_type); + fdi->err = 1; +} +/* unsupported sector described type */ +static void dyy (FDI *fdi) +{ + outlog ("\ntrack %d: unsupported sector described 0x%02.2X\n", fdi->current_track, fdi->track_type); + fdi->err = 1; +} +/* add position of mfm sync bit */ +static void add_mfm_sync_bit (FDI *fdi) +{ + if (fdi->nextdrop) { + fdi->nextdrop = 0; + return; + } + fdi->mfmsync_buffer[fdi->mfmsync_offset++] = fdi->out; + if (fdi->out == 0) { + outlog ("illegal position for mfm sync bit, offset=%d\n",fdi->out); + fdi->err = 1; + } + if (fdi->mfmsync_offset >= MAX_MFM_SYNC_BUFFER) { + fdi->mfmsync_offset = 0; + outlog ("mfmsync buffer overflow\n"); + fdi->err = 1; + } + fdi->out++; +} + +#define BIT_BYTEOFFSET ((fdi->out) >> 3) +#define BIT_BITOFFSET (7-((fdi->out)&7)) + +/* add one bit */ +static void bit_add (FDI *fdi, int bit) +{ + if (fdi->nextdrop) { + fdi->nextdrop = 0; + return; + } + fdi->track_dst[BIT_BYTEOFFSET] &= ~(1 << BIT_BITOFFSET); + if (bit) + fdi->track_dst[BIT_BYTEOFFSET] |= (1 << BIT_BITOFFSET); + fdi->out++; + if (fdi->out >= MAX_DST_BUFFER * 8) { + outlog ("destination buffer overflow\n"); + fdi->err = 1; + fdi->out = 1; + } +} +/* add bit and mfm sync bit */ +static void bit_mfm_add (FDI *fdi, int bit) +{ + add_mfm_sync_bit (fdi); + bit_add (fdi, bit); +} +/* remove following bit */ +static void bit_drop_next (FDI *fdi) +{ + if (fdi->nextdrop > 0) { + outlog("multiple bit_drop_next() called"); + } else if (fdi->nextdrop < 0) { + fdi->nextdrop = 0; + debuglog(":DNN:"); + return; + } + debuglog(":DN:"); + fdi->nextdrop = 1; +} + +/* ignore next bit_drop_next() */ +static void bit_dedrop (FDI *fdi) +{ + if (fdi->nextdrop) { + outlog("bit_drop_next called before bit_dedrop"); + } + fdi->nextdrop = -1; + debuglog(":BDD:"); +} + +/* add one byte */ +static void byte_add (FDI *fdi, uae_u8 v) +{ + int i; + for (i = 7; i >= 0; i--) + bit_add (fdi, v & (1 << i)); +} +/* add one word */ +static void word_add (FDI *fdi, uae_u16 v) +{ + byte_add (fdi, (uae_u8)(v >> 8)); + byte_add (fdi, (uae_u8)v); +} +/* add one byte and mfm encode it */ +static void byte_mfm_add (FDI *fdi, uae_u8 v) +{ + int i; + for (i = 7; i >= 0; i--) + bit_mfm_add (fdi, v & (1 << i)); +} +/* add multiple bytes and mfm encode them */ +static void bytes_mfm_add (FDI *fdi, uae_u8 v, int len) +{ + int i; + for (i = 0; i < len; i++) byte_mfm_add (fdi, v); +} +/* add one mfm encoded word and re-mfm encode it */ +static void word_post_mfm_add (FDI *fdi, uae_u16 v) +{ + int i; + for (i = 14; i >= 0; i -= 2) + bit_mfm_add (fdi, v & (1 << i)); +} + +/* bit 0 */ +static void s00(FDI *fdi) { bit_add (fdi, 0); } +/* bit 1*/ +static void s01(FDI *fdi) { bit_add (fdi, 1); } +/* 4489 */ +static void s02(FDI *fdi) { word_add (fdi, 0x4489); } +/* 5224 */ +static void s03(FDI *fdi) { word_add (fdi, 0x5224); } +/* mfm sync bit */ +static void s04(FDI *fdi) { add_mfm_sync_bit (fdi); } +/* RLE MFM-encoded data */ +static void s08(FDI *fdi) +{ + int bytes = *fdi->track_src++; + uae_u8 byte = *fdi->track_src++; + if (bytes == 0) bytes = 256; + debuglog ("s08:len=%d,data=%02.2X",bytes,byte); + while(bytes--) byte_add (fdi, byte); +} +/* RLE MFM-decoded data */ +static void s09(FDI *fdi) +{ + int bytes = *fdi->track_src++; + uae_u8 byte = *fdi->track_src++; + if (bytes == 0) bytes = 256; + bit_drop_next (fdi); + debuglog ("s09:len=%d,data=%02.2X",bytes,byte); + while(bytes--) byte_mfm_add (fdi, byte); +} +/* MFM-encoded data */ +static void s0a(FDI *fdi) +{ + int i, bits = (fdi->track_src[0] << 8) | fdi->track_src[1]; + uae_u8 b; + fdi->track_src += 2; + debuglog ("s0a:bits=%d,data=%s", bits, datalog(fdi->track_src, (bits + 7) / 8)); + while (bits >= 8) { + byte_add (fdi, *fdi->track_src++); + bits -= 8; + } + if (bits > 0) { + i = 7; + b = *fdi->track_src++; + while (bits--) { + bit_add (fdi, b & (1 << i)); + i--; + } + } +} +/* MFM-encoded data */ +static void s0b(FDI *fdi) +{ + int i, bits = ((fdi->track_src[0] << 8) | fdi->track_src[1]) + 65536; + uae_u8 b; + fdi->track_src += 2; + debuglog ("s0b:bits=%d,data=%s", bits, datalog(fdi->track_src, (bits + 7) / 8)); + while (bits >= 8) { + byte_add (fdi, *fdi->track_src++); + bits -= 8; + } + if (bits > 0) { + i = 7; + b = *fdi->track_src++; + while (bits--) { + bit_add (fdi, b & (1 << i)); + i--; + } + } +} +/* MFM-decoded data */ +static void s0c(FDI *fdi) +{ + int i, bits = (fdi->track_src[0] << 8) | fdi->track_src[1]; + uae_u8 b; + fdi->track_src += 2; + bit_drop_next (fdi); + debuglog ("s0c:bits=%d,data=%s", bits, datalog(fdi->track_src, (bits + 7) / 8)); + while (bits >= 8) { + byte_mfm_add (fdi, *fdi->track_src++); + bits -= 8; + } + if (bits > 0) { + i = 7; + b = *fdi->track_src++; + while(bits--) { + bit_mfm_add (fdi, b & (1 << i)); + i--; + } + } +} +/* MFM-decoded data */ +static void s0d(FDI *fdi) +{ + int i, bits = ((fdi->track_src[0] << 8) | fdi->track_src[1]) + 65536; + uae_u8 b; + fdi->track_src += 2; + bit_drop_next (fdi); + debuglog ("s0d:bits=%d,data=%s", bits, datalog(fdi->track_src, (bits + 7) / 8)); + while (bits >= 8) { + byte_mfm_add (fdi, *fdi->track_src++); + bits -= 8; + } + if (bits > 0) { + i = 7; + b = *fdi->track_src++; + while(bits--) { + bit_mfm_add (fdi, b & (1 << i)); + i--; + } + } +} + +/* ***** */ +/* AMIGA */ +/* ***** */ + +/* just for testing integrity of Amiga sectors */ + +static void rotateonebit (uae_u8 *start, uae_u8 *end, int shift) +{ + if (shift == 0) + return; + while (start <= end) { + start[0] <<= shift; + start[0] |= start[1] >> (8 - shift); + start++; + } +} + +static int check_offset; +static uae_u16 getmfmword (uae_u8 *mbuf) +{ + uae_u32 v; + + v = (mbuf[0] << 8) | (mbuf[1] << 0); + if (check_offset == 0) + return v; + v <<= 8; + v |= mbuf[2]; + v >>= check_offset; + return v; +} + +#define MFMMASK 0x55555555 +static uae_u32 getmfmlong (uae_u8 * mbuf) +{ + return ((getmfmword (mbuf) << 16) | getmfmword (mbuf + 2)) & MFMMASK; +} + +static int amiga_check_track (FDI *fdi) +{ + int i, j, secwritten = 0; + int fwlen = fdi->out / 8; + int length = 2 * fwlen; + int drvsec = 11; + uae_u32 odd, even, chksum, id, dlong; + uae_u8 *secdata; + uae_u8 secbuf[544]; + uae_u8 bigmfmbuf[60000]; + uae_u8 *mbuf, *mbuf2, *mend; + char sectable[22]; + uae_u8 *raw = fdi->track_dst_buffer; + int slabel, off; + int ok = 1; + + memset (bigmfmbuf, 0, sizeof (bigmfmbuf)); + mbuf = bigmfmbuf; + check_offset = 0; + for (i = 0; i < (fdi->out + 7) / 8; i++) + *mbuf++ = raw[i]; + off = fdi->out & 7; +#if 1 + if (off > 0) { + mbuf--; + *mbuf &= ~((1 << (8 - off)) - 1); + } + j = 0; + while (i < (fdi->out + 7) / 8 + 600) { + *mbuf++ |= (raw[j] >> off) | ((raw[j + 1]) << (8 - off)); + j++; + i++; + } +#endif + mbuf = bigmfmbuf; + + memset (sectable, 0, sizeof (sectable)); + //memcpy (mbuf + fwlen, mbuf, fwlen * sizeof (uae_u16)); + mend = bigmfmbuf + length; + mend -= (4 + 16 + 8 + 512); + + while (secwritten < drvsec) { + int trackoffs; + + for (;;) { + rotateonebit (bigmfmbuf, mend, 1); + if (getmfmword (mbuf) == 0) + break; + if (secwritten == 10) { + mbuf[0] = 0x44; + mbuf[1] = 0x89; + } +// check_offset++; + if (check_offset > 7) { + check_offset = 0; + mbuf++; + if (mbuf >= mend || *mbuf == 0) + break; + } + if (getmfmword (mbuf) == 0x4489) + break; + } + if (mbuf >= mend || *mbuf == 0) + break; + + rotateonebit (bigmfmbuf, mend, check_offset); + check_offset = 0; + mbuf2 = mbuf; + + while (getmfmword (mbuf) == 0x4489) + mbuf+= 1 * 2; + + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 2 * 2); + mbuf += 4 * 2; + id = (odd << 1) | even; + + trackoffs = (id & 0xff00) >> 8; + if (trackoffs + 1 > drvsec) { + debuglog("illegal sector offset %d\n",trackoffs); + ok = 0; + mbuf = mbuf2; + continue; + } + if ((id >> 24) != 0xff) { + debuglog ("sector %d format type %02.2X?\n", trackoffs, id >> 24); + ok = 0; + } + chksum = odd ^ even; + slabel = 0; + for (i = 0; i < 4; i++) { + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 8 * 2); + mbuf += 2* 2; + + dlong = (odd << 1) | even; + if (dlong) slabel = 1; + chksum ^= odd ^ even; + } + mbuf += 8 * 2; + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 2 * 2); + mbuf += 4 * 2; + if (((odd << 1) | even) != chksum) { + debuglog("sector %d header crc error\n", trackoffs); + ok = 0; + mbuf = mbuf2; + continue; + } + debuglog("sector %d header crc ok\n", trackoffs); + if (((id & 0x00ff0000) >> 16) != (uae_u32)fdi->current_track) { + debuglog("illegal track number %d <> %d\n",fdi->current_track,(id & 0x00ff0000) >> 16); + ok++; + mbuf = mbuf2; + continue; + } + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 2 * 2); + mbuf += 4 * 2; + chksum = (odd << 1) | even; + secdata = secbuf + 32; + for (i = 0; i < 128; i++) { + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 256 * 2); + mbuf += 2 * 2; + dlong = (odd << 1) | even; + *secdata++ = (uae_u8) (dlong >> 24); + *secdata++ = (uae_u8) (dlong >> 16); + *secdata++ = (uae_u8) (dlong >> 8); + *secdata++ = (uae_u8) dlong; + chksum ^= odd ^ even; + } + mbuf += 256 * 2; + if (chksum) { + debuglog("sector %d data checksum error\n",trackoffs); + ok = 0; + } else if (sectable[trackoffs]) { + debuglog("sector %d already found?\n", trackoffs); + mbuf = mbuf2; + } else { + debuglog("sector %d ok\n",trackoffs); + if (slabel) debuglog("(non-empty sector header)\n"); + sectable[trackoffs] = 1; + secwritten++; + if (trackoffs == 9) + mbuf += 0x228; + } + } + for (i = 0; i < drvsec; i++) { + if (!sectable[i]) { + debuglog ("sector %d missing\n", i); + ok = 0; + } + } + return ok; +} + +static void amiga_data_raw (FDI *fdi, uae_u8 *secbuf, uae_u8 *crc, int len) +{ + int i; + uae_u8 crcbuf[4]; + + if (!crc) { + memset (crcbuf, 0, 4); + } else { + memcpy (crcbuf, crc ,4); + } + for (i = 0; i < 4; i++) + byte_mfm_add (fdi, crcbuf[i]); + for (i = 0; i < len; i++) + byte_mfm_add (fdi, secbuf[i]); +} + +static void amiga_data (FDI *fdi, uae_u8 *secbuf) +{ + uae_u16 mfmbuf[4 + 512]; + uae_u32 dodd, deven, dck; + int i; + + for (i = 0; i < 512; i += 4) { + deven = ((secbuf[i + 0] << 24) | (secbuf[i + 1] << 16) + | (secbuf[i + 2] << 8) | (secbuf[i + 3])); + dodd = deven >> 1; + deven &= 0x55555555; + dodd &= 0x55555555; + mfmbuf[(i >> 1) + 4] = (uae_u16) (dodd >> 16); + mfmbuf[(i >> 1) + 5] = (uae_u16) dodd; + mfmbuf[(i >> 1) + 256 + 4] = (uae_u16) (deven >> 16); + mfmbuf[(i >> 1) + 256 + 5] = (uae_u16) deven; + } + dck = 0; + for (i = 4; i < 4 + 512; i += 2) + dck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1]; + deven = dodd = dck; + dodd >>= 1; + deven &= 0x55555555; + dodd &= 0x55555555; + mfmbuf[0] = (uae_u16) (dodd >> 16); + mfmbuf[1] = (uae_u16) dodd; + mfmbuf[2] = (uae_u16) (deven >> 16); + mfmbuf[3] = (uae_u16) deven; + + for (i = 0; i < 4 + 512; i ++) + word_post_mfm_add (fdi, mfmbuf[i]); +} + +static void amiga_sector_header (FDI *fdi, uae_u8 *header, uae_u8 *data, int sector, int untilgap) +{ + uae_u8 headerbuf[4], databuf[16]; + uae_u32 deven, dodd, hck; + uae_u16 mfmbuf[24]; + int i; + + byte_mfm_add (fdi, 0); + byte_mfm_add (fdi, 0); + word_add (fdi, 0x4489); + word_add (fdi, 0x4489); + if (header) { + memcpy (headerbuf, header, 4); + } else { + headerbuf[0] = 0xff; + headerbuf[1] = (uae_u8)fdi->current_track; + headerbuf[2] = (uae_u8)sector; + headerbuf[3] = (uae_u8)untilgap; + } + if (data) + memcpy (databuf, data, 16); + else + memset (databuf, 0, 16); + + deven = ((headerbuf[0] << 24) | (headerbuf[1] << 16) + | (headerbuf[2] << 8) | (headerbuf[3])); + dodd = deven >> 1; + deven &= 0x55555555; + dodd &= 0x55555555; + mfmbuf[0] = (uae_u16) (dodd >> 16); + mfmbuf[1] = (uae_u16) dodd; + mfmbuf[2] = (uae_u16) (deven >> 16); + mfmbuf[3] = (uae_u16) deven; + for (i = 0; i < 16; i += 4) { + deven = ((databuf[i] << 24) | (databuf[i + 1] << 16) + | (databuf[i + 2] << 8) | (databuf[i + 3])); + dodd = deven >> 1; + deven &= 0x55555555; + dodd &= 0x55555555; + mfmbuf[(i >> 1) + 0 + 4] = (uae_u16) (dodd >> 16); + mfmbuf[(i >> 1) + 0 + 5] = (uae_u16) dodd; + mfmbuf[(i >> 1) + 8 + 4] = (uae_u16) (deven >> 16); + mfmbuf[(i >> 1) + 8 + 5] = (uae_u16) deven; + } + hck = 0; + for (i = 0; i < 4 + 16; i += 2) + hck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1]; + deven = dodd = hck; + dodd >>= 1; + deven &= 0x55555555; + dodd &= 0x55555555; + mfmbuf[20] = (uae_u16) (dodd >> 16); + mfmbuf[21] = (uae_u16) dodd; + mfmbuf[22] = (uae_u16) (deven >> 16); + mfmbuf[23] = (uae_u16) deven; + + for (i = 0; i < 4 + 16 + 4; i ++) + word_post_mfm_add (fdi, mfmbuf[i]); +} + +/* standard super-extended Amiga sector header */ +static void s20(FDI *fdi) +{ + bit_drop_next (fdi); + debuglog ("s20:header=%s,data=%s", datalog(fdi->track_src, 4), datalog(fdi->track_src + 4, 16)); + amiga_sector_header (fdi, fdi->track_src, fdi->track_src + 4, 0, 0); + fdi->track_src += 4 + 16; +} +/* standard extended Amiga sector header */ +static void s21(FDI *fdi) +{ + bit_drop_next (fdi); + debuglog ("s21:header=%s", datalog(fdi->track_src, 4)); + amiga_sector_header (fdi, fdi->track_src, 0, 0, 0); + fdi->track_src += 4; +} +/* standard Amiga sector header */ +static void s22(FDI *fdi) +{ + bit_drop_next (fdi); + debuglog("s22:sector=%d,untilgap=%d", fdi->track_src[0], fdi->track_src[1]); + amiga_sector_header (fdi, 0, 0, fdi->track_src[0], fdi->track_src[1]); + fdi->track_src += 2; +} +/* standard 512-byte, CRC-correct Amiga data */ +static void s23(FDI *fdi) +{ + debuglog("s23:data=%s", datalog (fdi->track_src, 512)); + amiga_data (fdi, fdi->track_src); + fdi->track_src += 512; +} +/* not-decoded, 128*2^x-byte, CRC-correct Amiga data */ +static void s24(FDI *fdi) +{ + int shift = *fdi->track_src++; + debuglog("s24:shift=%d,data=%s", shift, datalog (fdi->track_src, 128 << shift)); + amiga_data_raw (fdi, fdi->track_src, 0, 128 << shift); + fdi->track_src += 128 << shift; +} +/* not-decoded, 128*2^x-byte, CRC-incorrect Amiga data */ +static void s25(FDI *fdi) +{ + int shift = *fdi->track_src++; + debuglog("s25:shift=%d,crc=%s,data=%s", shift, datalog (fdi->track_src, 4), datalog (fdi->track_src + 4, 128 << shift)); + amiga_data_raw (fdi, fdi->track_src + 4, fdi->track_src, 128 << shift); + fdi->track_src += 4 + (128 << shift); +} +/* standard extended Amiga sector */ +static void s26(FDI *fdi) +{ + s21 (fdi); + debuglog("s26:data=%s", datalog (fdi->track_src, 512)); + amiga_data (fdi, fdi->track_src); + fdi->track_src += 512; +} +/* standard short Amiga sector */ +static void s27(FDI *fdi) +{ + s22 (fdi); + debuglog("s27:data=%s", datalog (fdi->track_src, 512)); + amiga_data (fdi, fdi->track_src); + fdi->track_src += 512; +} + +/* *** */ +/* IBM */ +/* *** */ + +static uae_u16 ibm_crc (uae_u8 byte, int reset) +{ + static uae_u16 crc; + int i; + + if (reset) crc = 0xcdb4; + for (i = 0; i < 8; i++) { + if (crc & 0x8000) { + crc <<= 1; + if (!(byte & 0x80)) crc ^= 0x1021; + } else { + crc <<= 1; + if (byte & 0x80) crc ^= 0x1021; + } + byte <<= 1; + } + return crc; +} + +static void ibm_data (FDI *fdi, uae_u8 *data, uae_u8 *crc, int len) +{ + int i; + uae_u8 crcbuf[2]; + uae_u16 crcv; + + word_add (fdi, 0x4489); + word_add (fdi, 0x4489); + word_add (fdi, 0x4489); + byte_mfm_add (fdi, 0xfb); + ibm_crc (0xfb, 1); + for (i = 0; i < len; i++) { + byte_mfm_add (fdi, data[i]); + crcv = ibm_crc (data[i], 0); + } + if (!crc) { + crc = crcbuf; + crc[0] = (uae_u8)(crcv >> 8); + crc[1] = (uae_u8)crcv; + } + byte_mfm_add (fdi, crc[0]); + byte_mfm_add (fdi, crc[1]); +} + +static void ibm_sector_header (FDI *fdi, uae_u8 *data, uae_u8 *crc, int secnum, int pre) +{ + uae_u8 secbuf[5]; + uae_u8 crcbuf[2]; + uae_u16 crcv; + int i; + + if (pre) + bytes_mfm_add (fdi, 0, 12); + word_add (fdi, 0x4489); + word_add (fdi, 0x4489); + word_add (fdi, 0x4489); + secbuf[0] = 0xfe; + if (secnum >= 0) { + secbuf[1] = (uae_u8)(fdi->current_track/2); + secbuf[2] = (uae_u8)(fdi->current_track%2); + secbuf[3] = (uae_u8)secnum; + secbuf[4] = 2; + } else { + memcpy (secbuf + 1, data, 4); + } + ibm_crc (secbuf[0], 1); + ibm_crc (secbuf[1], 0); + ibm_crc (secbuf[2], 0); + ibm_crc (secbuf[3], 0); + crcv = ibm_crc (secbuf[4], 0); + if (crc) { + memcpy (crcbuf, crc, 2); + } else { + crcbuf[0] = (uae_u8)(crcv >> 8); + crcbuf[1] = (uae_u8)crcv; + } + /* data */ + for (i = 0;i < 5; i++) + byte_mfm_add (fdi, secbuf[i]); + /* crc */ + byte_mfm_add (fdi, crcbuf[0]); + byte_mfm_add (fdi, crcbuf[1]); +} + +/* standard IBM index address mark */ +static void s10(FDI *fdi) +{ + bit_drop_next (fdi); + bytes_mfm_add (fdi, 0, 12); + word_add (fdi, 0x5224); + word_add (fdi, 0x5224); + word_add (fdi, 0x5224); + byte_mfm_add (fdi, 0xfc); +} +/* standard IBM pre-gap */ +static void s11(FDI *fdi) +{ + bit_drop_next (fdi); + bytes_mfm_add (fdi, 0x4e, 78); + bit_dedrop (fdi); + s10 (fdi); + bytes_mfm_add (fdi, 0x4e, 50); +} +/* standard ST pre-gap */ +static void s12(FDI *fdi) +{ + bit_drop_next (fdi); + bytes_mfm_add (fdi, 0x4e, 78); +} +/* standard extended IBM sector header */ +static void s13(FDI *fdi) +{ + bit_drop_next (fdi); + debuglog ("s13:header=%s", datalog (fdi->track_src, 4)); + ibm_sector_header (fdi, fdi->track_src, 0, -1, 1); + fdi->track_src += 4; +} +/* standard mini-extended IBM sector header */ +static void s14(FDI *fdi) +{ + debuglog ("s14:header=%s", datalog (fdi->track_src, 4)); + ibm_sector_header (fdi, fdi->track_src, 0, -1, 0); + fdi->track_src += 4; +} +/* standard short IBM sector header */ +static void s15(FDI *fdi) +{ + bit_drop_next (fdi); + debuglog ("s15:sector=%d", *fdi->track_src); + ibm_sector_header (fdi, 0, 0, *fdi->track_src++, 1); +} +/* standard mini-short IBM sector header */ +static void s16(FDI *fdi) +{ + debuglog ("s16:track=%d", *fdi->track_src); + ibm_sector_header (fdi, 0, 0, *fdi->track_src++, 0); +} +/* standard CRC-incorrect mini-extended IBM sector header */ +static void s17(FDI *fdi) +{ + debuglog ("s17:header=%s,crc=%s", datalog (fdi->track_src, 4), datalog (fdi->track_src + 4, 2)); + ibm_sector_header (fdi, fdi->track_src, fdi->track_src + 4, -1, 0); + fdi->track_src += 4 + 2; +} +/* standard CRC-incorrect mini-short IBM sector header */ +static void s18(FDI *fdi) +{ + debuglog ("s18:sector=%d,header=%s", *fdi->track_src, datalog (fdi->track_src + 1, 4)); + ibm_sector_header (fdi, 0, fdi->track_src + 1, *fdi->track_src, 0); + fdi->track_src += 1 + 4; +} +/* standard 512-byte CRC-correct IBM data */ +static void s19(FDI *fdi) +{ + debuglog ("s19:data=%s", datalog (fdi->track_src , 512)); + ibm_data (fdi, fdi->track_src, 0, 512); + fdi->track_src += 512; +} +/* standard 128*2^x-byte-byte CRC-correct IBM data */ +static void s1a(FDI *fdi) +{ + int shift = *fdi->track_src++; + debuglog ("s1a:shift=%d,data=%s", shift, datalog (fdi->track_src , 128 << shift)); + ibm_data (fdi, fdi->track_src, 0, 128 << shift); + fdi->track_src += 128 << shift; +} +/* standard 128*2^x-byte-byte CRC-incorrect IBM data */ +static void s1b(FDI *fdi) +{ + int shift = *fdi->track_src++; + debuglog ("s1b:shift=%d,crc=%s,data=%s", shift, datalog (fdi->track_src + (128 << shift), 2), datalog (fdi->track_src , 128 << shift)); + ibm_data (fdi, fdi->track_src, fdi->track_src + (128 << shift), 128 << shift); + fdi->track_src += (128 << shift) + 2; +} +/* standard extended IBM sector */ +static void s1c(FDI *fdi) +{ + int shift = fdi->track_src[3]; + s13 (fdi); + bytes_mfm_add (fdi, 0x4e, 22); + bytes_mfm_add (fdi, 0x00, 12); + ibm_data (fdi, fdi->track_src, 0, 128 << shift); + fdi->track_src += 128 << shift; +} +/* standard short IBM sector */ +static void s1d(FDI *fdi) +{ + s15 (fdi); + bytes_mfm_add (fdi, 0x4e, 22); + bytes_mfm_add (fdi, 0x00, 12); + s19 (fdi); +} + +/* end marker */ +static void sff(FDI *fdi) +{ +} + +typedef void (*decode_described_track_func)(FDI*); + +static decode_described_track_func decode_sectors_described_track[] = +{ + s00,s01,s02,s03,s04,dxx,dxx,dxx,s08,s09,s0a,s0b,s0c,s0d,dxx,dxx, /* 00-0F */ + s10,s11,s12,s13,s14,s15,s16,s17,s18,s19,s1a,s1b,s1c,s1d,dxx,dxx, /* 10-1F */ + s20,s21,s22,s23,s24,s25,s26,s27,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 20-2F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 30-3F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 40-4F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 50-5F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 60-6F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 70-7F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 80-8F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 90-9F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* A0-AF */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* B0-BF */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* C0-CF */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* D0-DF */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* E0-EF */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,sff /* F0-FF */ +}; + +static void track_amiga (struct fdi *fdi, int first_sector, int max_sector) +{ + int i; + + bit_add (fdi, 0); + bit_drop_next (fdi); + for (i = 0; i < max_sector; i++) { + amiga_sector_header (fdi, 0, 0, first_sector, max_sector - i); + amiga_data (fdi, fdi->track_src + first_sector * 512); + first_sector++; + if (first_sector >= max_sector) first_sector = 0; + } + bytes_mfm_add (fdi, 0, 260); /* gap */ +} +static void track_atari_st (struct fdi *fdi, int max_sector) +{ + int i, gap3; + uae_u8 *p = fdi->track_src; + + switch (max_sector) + { + case 9: + gap3 = 40; + break; + case 10: + gap3 = 24; + break; + } + s15 (fdi); + for (i = 0; i < max_sector; i++) { + byte_mfm_add (fdi, 0x4e); + byte_mfm_add (fdi, 0x4e); + ibm_sector_header (fdi, 0, 0, fdi->current_track, 1); + ibm_data (fdi, p + i * 512, 0, 512); + bytes_mfm_add (fdi, 0x4e, gap3); + } + bytes_mfm_add (fdi, 0x4e, 660 - gap3); + fdi->track_src += fdi->track_len * 256; +} +static void track_pc (struct fdi *fdi, int max_sector) +{ + int i, gap3; + uae_u8 *p = fdi->track_src; + + switch (max_sector) + { + case 8: + gap3 = 116; + break; + case 9: + gap3 = 54; + break; + default: + gap3 = 100; /* fixme */ + break; + } + s11 (fdi); + for (i = 0; i < max_sector; i++) { + byte_mfm_add (fdi, 0x4e); + byte_mfm_add (fdi, 0x4e); + ibm_sector_header (fdi, 0, 0, fdi->current_track, 1); + ibm_data (fdi, p + i * 512, 0, 512); + bytes_mfm_add (fdi, 0x4e, gap3); + } + bytes_mfm_add (fdi, 0x4e, 600 - gap3); + fdi->track_src += fdi->track_len * 256; +} + +/* amiga dd */ +static void track_amiga_dd (struct fdi *fdi) +{ + uae_u8 *p = fdi->track_src; + track_amiga (fdi, fdi->track_len >> 4, 11); + fdi->track_src = p + (fdi->track_len & 15) * 512; +} +/* amiga hd */ +static void track_amiga_hd (struct fdi *fdi) +{ + uae_u8 *p = fdi->track_src; + track_amiga (fdi, 0, 22); + fdi->track_src = p + fdi->track_len * 256; +} +/* atari st 9 sector */ +static void track_atari_st_9 (struct fdi *fdi) +{ + track_atari_st (fdi, 9); +} +/* atari st 10 sector */ +static void track_atari_st_10 (struct fdi *fdi) +{ + track_atari_st (fdi, 10); +} +/* pc 8 sector */ +static void track_pc_8 (struct fdi *fdi) +{ + track_pc (fdi, 8); +} +/* pc 9 sector */ +static void track_pc_9 (struct fdi *fdi) +{ + track_pc (fdi, 9); +} +/* pc 15 sector */ +static void track_pc_15 (struct fdi *fdi) +{ + track_pc (fdi, 15); +} +/* pc 18 sector */ +static void track_pc_18 (struct fdi *fdi) +{ + track_pc (fdi, 18); +} +/* pc 36 sector */ +static void track_pc_36 (struct fdi *fdi) +{ + track_pc (fdi, 36); +} + +typedef void (*decode_normal_track_func)(FDI*); + +static decode_normal_track_func decode_normal_track[] = +{ + track_empty, /* 0 */ + track_amiga_dd, track_amiga_hd, /* 1-2 */ + track_atari_st_9, track_atari_st_10, /* 3-4 */ + track_pc_8, track_pc_9, track_pc_15, track_pc_18, track_pc_36, /* 5-9 */ + zxx,zxx,zxx,zxx,zxx /* A-F */ +}; + +static void fix_mfm_sync (FDI *fdi) +{ + int i, pos, off1, off2, off3, mask1, mask2, mask3; + + for (i = 0; i < fdi->mfmsync_offset; i++) { + pos = fdi->mfmsync_buffer[i]; + off1 = (pos - 1) >> 3; + off2 = (pos + 1) >> 3; + off3 = pos >> 3; + mask1 = 1 << (7 - ((pos - 1) & 7)); + mask2 = 1 << (7 - ((pos + 1) & 7)); + mask3 = 1 << (7 - (pos & 7)); + if (!(fdi->track_dst[off1] & mask1) && !(fdi->track_dst[off2] & mask2)) + fdi->track_dst[off3] |= mask3; + else + fdi->track_dst[off3] &= ~mask3; + } +} + +static int handle_sectors_described_track (FDI *fdi) +{ + int oldout; + uae_u8 *start_src = fdi->track_src ; + fdi->encoding_type = *fdi->track_src++; + fdi->index_offset = get_u32(fdi->track_src); + fdi->index_offset >>= 8; + fdi->track_src += 3; + outlog ("sectors_described, index offset: %d\n",fdi->index_offset); + + do { + fdi->track_type = *fdi->track_src++; + outlog ("%06.6X %06.6X %02.2X:",fdi->track_src - start_src + 0x200, fdi->out/8, fdi->track_type); + oldout = fdi->out; + decode_sectors_described_track[fdi->track_type](fdi); + outlog(" %d\n", fdi->out - oldout); + oldout = fdi->out; + if (fdi->out < 0 || fdi->err) { + outlog ("\nin %d bytes, out %d bits\n", fdi->track_src - fdi->track_src_buffer, fdi->out); + return -1; + } + if (fdi->track_src - fdi->track_src_buffer >= fdi->track_src_len) { + outlog ("source buffer overrun, previous type: %02.2X\n", fdi->track_type); + return -1; + } + } while (fdi->track_type != 0xff); + outlog("\n"); + fix_mfm_sync (fdi); + return fdi->out; +} + +static uae_u8 *fdi_decompress (int pulses, uae_u8 *sizep, uae_u8 *src, int *dofree) +{ + uae_u32 size = get_u24 (sizep); + uae_u32 *dst2; + int len = size & 0x3fffff; + uae_u8 *dst; + int mode = size >> 22, i; + + *dofree = 0; + if (mode == 0 && pulses * 2 > len) + mode = 1; + if (mode == 0) { + dst2 = (uae_u32*)src; + for (i = 0; i < pulses; i++) { + *dst2++ = get_u32 (src); + src += 4; + } + dst = src; + } else if (mode == 1) { + dst = fdi_malloc (pulses *4); + *dofree = 1; + fdi_decode (src, pulses, dst); + } else { + dst = 0; + } + return dst; +} + +static void dumpstream(int track, uae_u8 *stream, int len) +{ + char name[100]; + FILE *f; + + sprintf (name, "track_%d.raw", track); + f = fopen(name, "wb"); + fwrite (stream, 1, len * 4, f); + fclose (f); +} + +static int bitoffset; + +STATIC_INLINE void addbit (uae_u8 *p, int bit) +{ + int off1 = bitoffset / 8; + int off2 = bitoffset % 8; + p[off1] |= bit << (7 - off2); + bitoffset++; +} + + +struct pulse_sample { + unsigned long size; + int number_of_bits; +}; + +#define FDI_MAX_ARRAY 6 /* change this value as you want */ +static int pulse_limitval = 20; +static struct pulse_sample psarray[FDI_MAX_ARRAY]; +static int array_index; +static unsigned long total; +static int totaldiv; + +static void init_array(unsigned long standard_MFM_2_bit_cell_size) +{ + int i; + + for (i = 0; i < FDI_MAX_ARRAY; i++) { + psarray[i].size = standard_MFM_2_bit_cell_size; // That is (total track length / 50000) for Amiga double density + total += psarray[i].size; + psarray[i].number_of_bits = 2; + totaldiv += psarray[i].number_of_bits; + } + array_index = 0; +} + +static void fdi2_mfm_decode(FDI *fdi, unsigned long totalavg, uae_u32 *avgp, uae_u8 *idx, int idx_off1, int idx_off2, int idx_off3, int maxidx, int pulses) +{ + unsigned long adjust; + unsigned long adjusted_pulse; + unsigned long standard_MFM_2_bit_cell_size = totalavg / 50000; + int real_size, i, j; + uae_u8 *d = fdi->track_dst_buffer; + uae_u16 *pt = fdi->track_dst_buffer_timing; + + adjust = 0; + total = 0; + totaldiv = 0; + init_array(standard_MFM_2_bit_cell_size); + bitoffset = 0; + for (i = 0; i < pulses; i++) + { + if (idx[idx_off1] + idx[idx_off2] >= maxidx) { + uae_u32 pulse = avgp[i]; + uae_u32 avg_size = total / totaldiv; /* this is the new average size for one MFM bit */ + /* you can try tighter ranges than 25%, or wider ranges. I would probably go for tighter... */ + if ((avg_size < ((standard_MFM_2_bit_cell_size / 2) - (pulse_limitval * standard_MFM_2_bit_cell_size / 200))) || + (avg_size > ((standard_MFM_2_bit_cell_size / 2) + (pulse_limitval * standard_MFM_2_bit_cell_size /200)))) + init_array(standard_MFM_2_bit_cell_size); + /* this is to prevent the average value from going too far + * from the theoretical value, otherwise it could progressively go to (2 * + * real value), or (real value / 2), etc. */ + if ((pulse > adjust) && (adjust < avg_size)) + adjusted_pulse = pulse - adjust; + else + adjusted_pulse = pulse; + adjusted_pulse = pulse; + real_size = 1; + do { + addbit (d, 0); + real_size++; + } while (adjusted_pulse > avg_size * real_size + avg_size / 2); + addbit (d, 1); +#if 1 + for (j = 0; j < real_size; j++) + *pt++ = (uae_u16)(adjusted_pulse / real_size); +#endif + /* Note that you should also consider values above 4! Too lazy to do it here ;-) */ + adjust = (real_size * avg_size) - pulse; + /* function to transform the value in real_size to '01', '001' or '0001', and append this to the decoded MFM stream */ + total -= psarray[array_index].size; + totaldiv -= psarray[array_index].number_of_bits; + psarray[array_index].size = pulse; + psarray[array_index].number_of_bits = real_size; + total += pulse; + totaldiv += real_size; + array_index++; + if (array_index >= FDI_MAX_ARRAY) + array_index = 0; + } + idx += idx_off3; + } + fdi->out = bitoffset; + write_log ("result bits: %d\n", bitoffset); +} + +static void fdi2_celltiming (FDI *fdi, unsigned long totalavg, int bitoffset) +{ + uae_u16 *pt2, *pt; + double avg_bit_len; + int timed = 0; + int i; + + avg_bit_len = (double)totalavg / (double)bitoffset; + pt2 = pt = fdi->track_dst_buffer_timing; + for (i = 0; i < bitoffset / 8; i++) { + double v = (pt2[0] + pt2[1] + pt2[2] + pt2[3] + pt2[4] + pt2[5] + pt2[6] + pt2[7]) / 8.0; + uae_u16 vv; + v = 1000.0 * v / avg_bit_len; + vv = (uae_u16)v; + *pt++ = vv; + if (vv > 1030 || vv < 970) + timed = 1; + pt2 += 8; + } + *pt++ = fdi->track_dst_buffer_timing[0]; + *pt = fdi->track_dst_buffer_timing[0]; + if (!timed) + fdi->track_dst_buffer_timing[0] = 0; +} + +static int decode_lowlevel_track (FDI *fdi, int *indexoffsetp, int track) +{ + uae_u8 *p1, *d; + uae_u32 *p2; + uae_u32 *avgp, *minp = 0, *maxp = 0; + uae_u8 *idxp = 0; + uae_u32 maxidx, minidx, totalavg, weakbits; + int i, len, pulses, indexoffset; + int avg_free, min_free = 0, max_free = 0, idx_free; + int idx_off1, idx_off2, idx_off3; + + d = fdi->track_dst; + p1 = fdi->track_src; + pulses = get_u32 (p1); + if (!pulses) + return -1; + p1 += 4; + len = 12; + avgp = (uae_u32*)fdi_decompress (pulses, p1 + 0, p1 + len, &avg_free); + //dumpstream(track, (uae_u8*)avgp, pulses); + len += get_u24 (p1 + 0) & 0x3fffff; + if (!avgp) + return -1; + if (get_u24 (p1 + 3) && get_u24 (p1 + 6)) { +#if 0 + minp = (uae_u32*)fdi_decompress (pulses, p1 + 3, p1 + len, &min_free); +#endif + len += get_u24 (p1 + 3) & 0x3fffff; +#if 0 + maxp = (uae_u32*)fdi_decompress (pulses, p1 + 6, p1 + len, &max_free); +#endif + len += get_u24 (p1 + 6) & 0x3fffff; + } + if (get_u24 (p1 + 9)) { + idx_off1 = 0; + idx_off2 = 1; + idx_off3 = 2; + idxp = fdi_decompress (pulses, p1 + 9, p1 + len, &idx_free); + if (idx_free) { + if (idxp[0] == 0 && idxp[1] == 0) { + idx_off1 = 2; + idx_off2 = 3; + } else { + idx_off1 = 1; + idx_off2 = 0; + } + idx_off3 = 4; + } + } else { + idxp = fdi_malloc (pulses * 2); + idx_free = 1; + for (i = 0; i < pulses; i++) { + idxp[i * 2 + 0] = 2; + idxp[i * 2 + 1] = 0; + } + idxp[0] = 1; + idxp[1] = 1; + } + + maxidx = 0; + minidx = 255; + indexoffset = 0; + p1 = idxp; + for (i = 0; i < pulses; i++) { + if (p1[idx_off1] + p1[idx_off2] > maxidx) + maxidx = p1[idx_off1] + p1[idx_off2]; + if (abs (p1[idx_off1] - p1[idx_off2]) < minidx) { + minidx = abs (p1[idx_off1] - p1[idx_off2]); + indexoffset = i; + } + p1 += idx_off3; + } + p1 = idxp; + p2 = avgp; + totalavg = 0; + weakbits = 0; + for (i = 0; i < pulses; i++) { + if (p1[idx_off1] + p1[idx_off2] >= maxidx) { + totalavg += *p2; + } else { + weakbits++; + } + p2++; + p1 += idx_off3; + } + len = totalavg / 100000; + outlog("totalavg=%d index=%d maxidx=%d weakbits=%d len=%d\n", + totalavg, indexoffset, maxidx, weakbits, len); + fdi2_mfm_decode (fdi, totalavg, avgp, idxp, idx_off1, idx_off2, idx_off3, maxidx, pulses); + outlog("number of bits=%d avg len=%.2f\n", bitoffset, (double)totalavg / bitoffset); + fdi2_celltiming (fdi, totalavg, bitoffset); + + *indexoffsetp = indexoffset; + if (avg_free) + fdi_free (avgp); + if (min_free) + fdi_free (minp); + if (max_free) + fdi_free (maxp); + if (idx_free) + fdi_free (idxp); + return bitoffset; +} + +static unsigned char fdiid[]={"Formatted Disk Image file"}; +static int bit_rate_table[16] = { 125,150,250,300,500,1000 }; + +void fdi2raw_header_free (FDI *fdi) +{ + int i, j; + + fdi_free (fdi->mfmsync_buffer); + fdi_free (fdi->track_src_buffer); + fdi_free (fdi->track_dst_buffer); + fdi_free (fdi->track_dst_buffer_timing); + for (i = 0; i < MAX_TRACKS; i++) { + struct fdi_cache *c = &fdi->cache[i]; + for (j = 0; j < MAX_REVOLUTIONS; j++) + fdi_free (c->cache_buffer[j]); + fdi_free (c->cache_buffer_timing); + } + fdi_free (fdi); +#ifdef DEBUG + write_log ("FREE: memory allocated %d\n", fdi_allocated); +#endif +} + +int fdi2raw_get_last_track (FDI *fdi) +{ + return fdi->last_track; +} + +int fdi2raw_get_num_sector (FDI *fdi) +{ + if (fdi->header[152] == 0x02) + return 22; + return 11; +} + +int fdi2raw_get_last_head (FDI *fdi) +{ + return fdi->last_head; +} + +int fdi2raw_get_rotation (FDI *fdi) +{ + return fdi->rotation_speed; +} + +int fdi2raw_get_bit_rate (FDI *fdi) +{ + return fdi->bit_rate; +} + +int fdi2raw_get_type (FDI *fdi) +{ + return fdi->disk_type; +} + +int fdi2raw_get_write_protect (FDI *fdi) +{ + return fdi->write_protect; +} + +FDI *fdi2raw_header(struct zfile *f) +{ + int i, offset, oldseek; + uae_u8 type, size; + FDI *fdi; + +#ifdef DEBUG + write_log ("ALLOC: memory allocated %d\n", fdi_allocated); +#endif + fdi = fdi_malloc(sizeof(FDI)); + memset (fdi, 0, sizeof (FDI)); + fdi->file = f; + oldseek = zfile_ftell (fdi->file); + zfile_fseek (fdi->file, 0, SEEK_SET); + zfile_fread (fdi->header, 2048, 1, fdi->file); + zfile_fseek (fdi->file, oldseek, SEEK_SET); + if (memcmp (fdiid, fdi->header, strlen (fdiid)) ) { + fdi_free(fdi); + return NULL; + } + if ((fdi->header[140] != 1 && fdi->header[140] != 2) || fdi->header[141] != 0) { + fdi_free(fdi); + return NULL; + } + + fdi->mfmsync_buffer = fdi_malloc (MAX_MFM_SYNC_BUFFER * sizeof(int)); + fdi->track_src_buffer = fdi_malloc (MAX_SRC_BUFFER); + fdi->track_dst_buffer = fdi_malloc (MAX_DST_BUFFER); + fdi->track_dst_buffer_timing = fdi_malloc (MAX_TIMING_BUFFER); + + fdi->last_track = ((fdi->header[142] << 8) + fdi->header[143]) + 1; + fdi->last_track *= fdi->header[144] + 1; + if (fdi->last_track > MAX_TRACKS) + fdi->last_track = MAX_TRACKS; + fdi->last_head = fdi->header[144]; + fdi->disk_type = fdi->header[145]; + fdi->rotation_speed = fdi->header[146] + 128; + fdi->write_protect = fdi->header[147] & 1; + outlog ("FDI version %d.%d\n", fdi->header[140], fdi->header[141]); + outlog ("last_track=%d rotation_speed=%d\n",fdi->last_track,fdi->rotation_speed); + + offset = 512; + i = fdi->last_track; + if (i > 180) { + offset += 512; + i -= 180; + while (i > 256) { + offset += 512; + i -= 256; + } + } + for (i = 0; i < fdi->last_track; i++) { + fdi->track_offsets[i] = offset; + type = fdi->header[152 + i * 2]; + size = fdi->header[152 + i * 2 + 1]; + if (type == 1) + offset += (size & 15) * 512; + else if ((type & 0xc0) == 0x80) + offset += (((type & 0x3f) << 8) | size) * 256; + else + offset += size * 256; + } + fdi->track_offsets[i] = offset; + + return fdi; +} + + +int fdi2raw_loadtrack (FDI *fdi, uae_u16 *mfmbuf, uae_u16 **trackpointers, uae_u16 **tracktiming, int track, int *tracklengths, int *revolutions, int *indexoffsetp) +{ + uae_u8 *p; + int outlen, i, j, indexoffset = 0; + struct fdi_cache *cache; + + *revolutions = 1; + *tracktiming = 0; + trackpointers[0] = mfmbuf; + + cache = &fdi->cache[track]; + if (cache->cache_buffer[0]) { + uae_u16 *tt; + *revolutions = 0; + for (j = 0; j < MAX_REVOLUTIONS && cache->cache_buffer[j]; j++) { + (*revolutions)++; + tracklengths[j] = cache->length[j]; + trackpointers[j] = mfmbuf; + for (i = 0; i < (tracklengths[j] + 15) / (2 * 8); i++) { + uae_u8 *data = cache->cache_buffer[j] + i * 2; + *mfmbuf++ = 256 * *data + *(data + 1); + } + } + if (cache->cache_buffer_timing) { + tt = xmalloc ((tracklengths[0] + 7) / 8 * sizeof (uae_u16)); + memcpy (tt, cache->cache_buffer_timing, (tracklengths[0] + 7) / 8 * sizeof (uae_u16)); + *tracktiming = tt; + } + *indexoffsetp = cache->indexoffset; + return 1; + } + + fdi->err = 0; + fdi->track_src_len = fdi->track_offsets[track + 1] - fdi->track_offsets[track]; + zfile_fseek (fdi->file, fdi->track_offsets[track], SEEK_SET); + zfile_fread (fdi->track_src_buffer, fdi->track_src_len, 1, fdi->file); + memset (fdi->track_dst_buffer, 0, MAX_DST_BUFFER); + fdi->track_dst_buffer_timing[0] = 0; + + fdi->current_track = track; + fdi->track_src = fdi->track_src_buffer; + fdi->track_dst = fdi->track_dst_buffer; + p = fdi->header + 152 + fdi->current_track * 2; + fdi->track_type = *p++; + fdi->track_len = *p++; + fdi->bit_rate = 0; + fdi->out = 0; + fdi->mfmsync_offset = 0; + + if ((fdi->track_type & 0xf0) == 0xf0 || (fdi->track_type & 0xf0) == 0xe0) + fdi->bit_rate = bit_rate_table[fdi->track_type & 0x0f]; + else + fdi->bit_rate = 250; + + outlog ("track %d: srclen: %d track_type: %02.2X, bitrate: %d\n", + fdi->current_track, fdi->track_src_len, fdi->track_type, fdi->bit_rate); + + if ((fdi->track_type & 0xc0) == 0x80) { + + outlen = decode_lowlevel_track (fdi, &indexoffset, track); + + } else if ((fdi->track_type & 0xf0) == 0xf0) { + + outlen = decode_raw_track (fdi); + + } else if ((fdi->track_type & 0xf0) == 0xe0) { + + outlen = handle_sectors_described_track (fdi); + + } else if ((fdi->track_type & 0xf0)) { + + zxx (fdi); + outlen = -1; + + } else if (fdi->track_type < 0x10) { + + decode_normal_track[fdi->track_type](fdi); + fix_mfm_sync (fdi); + outlen = fdi->out; + + } else { + + zxx (fdi); + outlen = -1; + + } + + if (fdi->err) + return 0; + + if (outlen > 0) { + for (j = 0; j < MAX_REVOLUTIONS; j++) { + fdi_free (cache->cache_buffer[j]); + cache->cache_buffer[j] = 0; + } + fdi_free (cache->cache_buffer_timing); + cache->cache_buffer_timing = 0; + cache->indexoffset = indexoffset; + cache->length[0] = outlen; + cache->cache_buffer[0] = fdi_malloc ((outlen + 7) / 8); + memcpy (cache->cache_buffer[0], fdi->track_dst_buffer, (outlen + 7) / 8); + if (fdi->track_dst_buffer_timing[0] > 0) { + cache->cache_buffer_timing = fdi_malloc ((outlen + 7) / 8 * sizeof (uae_u16)); + memcpy (cache->cache_buffer_timing, fdi->track_dst_buffer_timing, (outlen + 7) / 8 * sizeof (uae_u16)); + } + return fdi2raw_loadtrack (fdi, mfmbuf, trackpointers, tracktiming, track, tracklengths, revolutions, indexoffsetp); + } + return 0; +} + diff --git a/filesys.asm b/filesys.asm new file mode 100755 index 00000000..ade04726 --- /dev/null +++ b/filesys.asm @@ -0,0 +1,767 @@ + SECTION code,code +; This file can be translated with A68k or PhxAss and then linked with BLink +; to produce an Amiga executable. Make sure it does not contain any +; relocations, then run it through the filesys.sh script +; +; Patrick: It also works with SAS/C asm+slink, but I had to remove +; the .l from jsr.l and jmp.l. +; Toni Wilen: modified SECTION, compiles now with AsmOne and clones(?) +; Removed absolute RT_AREA references +; 2002.08.06 RDB automount/autoboot support (Toni Wilen) +; 2002.09.11 KS1.3 RDB support (TW) + +AllocMem = -198 +FreeMem = -210 + +; don't forget filesys.c! */ +PP_MAXSIZE = 4 * 96 +PP_FSSIZE = 400 +PP_FSPTR = 404 +PP_FSRES = 408 +PP_EXPLIB = 412 +PP_FSHDSTART = 416 +PP_TOTAL = (PP_FSHDSTART+140) + +NOTIFY_CLASS = $40000000 +NOTIFY_CODE = $1234 +NRF_SEND_MESSAGE = 1 +NRF_SEND_SIGNAL = 2 +NRF_WAIT_REPLY = 8 +NRF_NOTIFY_INITIAL = 16 +NRF_MAGIC = $80000000 + + dc.l 16 +our_seglist: + dc.l 0 ;/* NextSeg */ +start: + bra filesys_mainloop + dc.l make_dev-start + dc.l filesys_init-start + dc.l exter_server-start + dc.l bootcode-start + dc.l setup_exter-start + + dc.l p96vsyncfix1-start + +bootcode: + lea.l doslibname(pc),a1 + jsr -96(a6) ; FindResident + move.l d0,a0 + move.l 22(a0),d0 + move.l d0,a0 + jsr (a0) + rts + +filesys_init: + movem.l d0-d7/a0-a6,-(sp) + move.l 4.w,a6 + move.w #$FFFC,d0 ; filesys base + bsr getrtbase + move.l (a0),a5 + lea.l explibname(pc),a1 ; expansion lib name + moveq #36,d0 + moveq #0,d5 + jsr -552(a6) ; OpenLibrary + tst.l d0 + bne.b FSIN_explibok + lea.l explibname(pc),a1 ; expansion lib name + moveq #0,d0 + moveq #1,d5 + jsr -552(a6) ; OpenLibrary +FSIN_explibok: + move.l d0,a4 + move.l #PP_TOTAL,d0 + moveq #1,d1 ; MEMF_PUBLIC + jsr AllocMem(a6) + move.l d0,a3 ; param packet + move.l a4,PP_EXPLIB(a3) + + moveq #0,d6 +FSIN_init_units: + cmp.l $10c(a5),d6 + bcc.b FSIN_units_ok + move.l d6,-(sp) +FSIN_nextsub: + moveq #1,d7 + move.l a3,-(sp) + move.l a3,a0 + bsr.w make_dev + move.l (sp)+,a3 + cmp.l #-2,d0 + beq.s FSIN_nomoresub + swap d6 + addq.w #1,d6 + swap d6 + bra.s FSIN_nextsub +FSIN_nomoresub: + move.l (sp)+,d6 + addq.w #1,d6 + bra.b FSIN_init_units + +FSIN_units_ok: + move.l 4.w,a6 + move.l a4,a1 + jsr -414(a6) ; CloseLibrary + + ; add >2MB chip RAM to memory list + move.w #$FF80,d0 + bsr.w getrtbase + jsr (a0) + moveq.l #3,d1 + moveq.l #-10,d2 + move.l #$200000,a0 + sub.l a0,d0 + bcs.b FSIN_chip_done + beq.b FSIN_chip_done + moveq.l #0,d4 + move.l d4,a1 + jsr -618(a6) +FSIN_chip_done + + movem.l (sp)+,d0-d7/a0-a6 +general_ret: + rts + +exter_data: +exter_server: + movem.l a2,-(sp) + move.w #$FF50,d0 + bsr.w getrtbase + moveq.l #0,d0 + jsr (a0) + tst.l d0 + beq.w exter_server_exit + ; This is the hard part - we have to send some messages. + move.l 4.w,a6 +EXTS_loop: + move.w #$FF50,d0 ;exter_int_helper + bsr.w getrtbase + moveq.l #2,d0 + jsr (a0) + cmp.w #1,d0 + blt.b EXTS_done + bgt.b EXTS_signal_reply + jsr -366(a6) ; PutMsg + bra.b EXTS_loop +EXTS_signal_reply: + cmp.w #2,d0 + bgt.b EXTS_reply + move.l d1,d0 + jsr -$144(a6) ; Signal + bra.b EXTS_loop +EXTS_reply: + cmp.w #3,d0 + bgt.b EXTS_cause + jsr -$17a(a6) ; ReplyMsg + bra.b EXTS_loop +EXTS_cause: + cmp.w #4,d0 + bgt.b EXTS_notificationhack + jsr -$b4(a6) ; Cause + bra.b EXTS_loop +EXTS_notificationhack: + cmp.w #5,d0 + bgt.b EXTS_done + movem.l a0-a1,-(sp) + moveq #38,d0 + move.l #65536+1,d1 + jsr AllocMem(a6) + movem.l (sp)+,a0-a1 + move.l d0,a2 + move.b #8,8(a2) + move.l a0,14(a2) + move.w #38,18(a2) + move.l #NOTIFY_CLASS,20(a2) + move.w #NOTIFY_CODE,24(a2) + move.l a1,26(a2) + move.l 16(a1),a0 + move.l a2,a1 + jsr -366(a6) ; PutMsg + bra.w EXTS_loop +EXTS_done: + move.w #$FF50,d0 ;exter_int_helper + bsr.w getrtbase + moveq.l #4,d0 + jsr (a0) + moveq.l #1,d0 ; clear Z - it was for us. +exter_server_exit: + movem.l (sp)+,a2 + rts + +setup_exter: + movem.l d0-d1/a0-a1,-(sp) + moveq.l #26,d0 + move.l #$10001,d1 + jsr AllocMem(a6) + move.l d0,a1 + lea.l exter_name(pc),a0 + move.l a0,10(a1) + lea.l exter_data(pc),a0 + move.l a0,14(a1) + lea.l exter_server(pc),a0 + move.l a0,18(a1) + move.w #$0214,8(a1) + moveq.l #3,d0 + jsr -168(a6) ; AddIntServer + movem.l (sp)+,d0-d1/a0-a1 + rts + +addfs: ; a0 = first hunk, a1 = parmpacket + movem.l d0-d1/a0-a3/a6,-(sp) + move.l 4.w,a6 + move.l a0,a2 + move.l a1,a3 + move.l #62+128,d0 ; sizeof(FileSysEntry) + patchflags; + move.l #$10001,d1 + jsr -198(a6) + move.l d0,a0 + moveq #0,d0 + lea PP_FSHDSTART(a3),a1 +af1 move.b 0(a1,d0.w),14(a0,d0.w) + addq.w #1,d0 + cmp.w #140,d0 + bne.s af1 + move.l a2,d0 + lsr.l #2,d0 + move.l d0,54(a0) ;seglist + move.l a0,a1 + lea exter_name(pc),a0 + move.l a0,10(a1) ; name + move.l PP_FSRES(a3),a0 ; FileSystem.resource + lea 18(a0),a0 ; fsr_FileSysEntries + jsr -$f0(a6) ;AddHead + movem.l (sp)+,d0-d1/a0-a3/a6 + rts + +relocate: ;a0=pointer to executable, returns first segment in A0 + movem.l d1-d7/a1-a6,-(sp) + move.l 4.w,a6 + move.l a0,a2 + cmp.l #$3f3,(a2)+ + bne.w ree + addq.l #8,a2 ; skip name end and skip total hunks + 1 + move.l 4(a2),d7 ; last hunk + sub.l (a2),d7 ; first hunk + addq.l #8,a2 ; skip hunk to load first and hunk to load last + addq.l #1,d7 + move.l a2,a3 + move.l d7,d0 + add.l d0,d0 + add.l d0,d0 + add.l d0,a3 + move.l a2,a4 + + ; allocate hunks + sub.l a5,a5 ;prev segment + moveq #0,d6 +r15 move.l (a2),d2 ; hunk size (header) + lsl.l #2,d2 + moveq #1,d1 + btst #30,d3 ; chip mem? + beq.s r2 + bset #1,d1 +r2 bset #16,d1 + bclr #31,d3 + bclr #30,d3 + move.l d2,d0 + bne.s r17 + clr.l (a2)+ ; empty hunk + bra.s r18 +r17 addq.l #8,d0 ; size + pointer to next hunk + hunk size + jsr AllocMem(a6) + tst.l d0 + beq.w ree + move.l d0,a0 + move.l d2,(a0)+ ; store size + move.l a0,(a2)+ ; store new pointer + move.l a5,d1 + beq.s r10 + move.l a0,d0 + lsr.l #2,d0 + move.l d0,(a5) +r10 move.l a0,a5 +r18 addq.l #1,d6 + cmp.l d6,d7 + bne.s r15 + + moveq #0,d6 +r3 + move.l 0(a4,d6.l*4),a0 + addq.l #4,a0 + move.l (a3)+,d3 ; hunk type + move.l (a3)+,d4 ; hunk size + lsl.l #2,d4 + cmp.l #$3e9,d3 ;code + beq.s r4 + cmp.l #$3ea,d3 ;data + bne.s r5 +r4 + ; code and data + move.l d4,d0 +r6 tst.l d0 + beq.s r7 + move.b (a3)+,(a0)+ + subq.l #1,d0 + bra.s r6 +r5 + cmp.l #$3eb,d3 ;bss + bne.s ree + +r7 ; scan for reloc32 or hunk_end + move.l (a3)+,d3 + cmp.l #$3ec,d3 ;reloc32 + bne.s r13 + + ; relocate + move.l 0(a4,d6.l*4),a0 ; current hunk + addq.l #4,a0 +r11 move.l (a3)+,d0 ;number of relocs + beq.s r7 + move.l (a3)+,d1 ;hunk + move.l 0(a4,d1.l*4),d3 ;hunk start address + addq.l #4,d3 +r9 move.l (a3)+,d2 ;offset + add.l d3,0(a0,d2.l) + subq.l #1,d0 + bne.s r9 + bra.s r11 +r13 + cmp.l #$3f2,d3 ;end + bne.s ree + + addq.l #1,d6 + cmp.l d6,d7 + bne.w r3 + + moveq #1,d7 + move.l (a4),a0 +r0 move.l d7,d0 + movem.l (sp)+,d1-d7/a1-a6 + rts +ree move.w #30000,d0 +re1 move.w #$f00,$dff180 + move.w #$00f,$dff180 + move.w #$0f0,$dff180 + dbf d0,re1 + moveq #0,d7 + bra.s r0 + +fsres + movem.l d1/a0-a2/a6,-(sp) + move.l 4.w,a6 + lea $150(a6),a0 +fsres3 + tst.l (a0) + beq.s fsres1 + move.l 10(a0),a1 + lea fsresname(pc),a2 +fsres5 + move.b (a1)+,d0 + move.b (a2)+,d1 + cmp.b d1,d0 + bne.s fsres2 + tst.b d0 + beq.s fsres4 + bra.s fsres5 +fsres2 + move.l (a0),a0 + bra.s fsres3 + ; FileSystem.resource does not exist -> create it +fsres1 + moveq #32,d0 ; sizeof(FileSysResource) + move.l #$10001,d1 + jsr AllocMem(a6) + move.l d0,a2 + move.b #8,8(a2) ; NT_RESOURCE + lea fsresname(pc),a0 + move.l a0,10(a2) ; node name + lea exter_name(pc),a0 + move.l a0,14(a2) ; fsr_Creator + lea 18(a2),a0 + move.l a0,(a0) ; NewList() fsr_FileSysEntries + addq.l #4,(a0) + move.l a0,8(a0) + lea $150(a6),a0 ; ResourceList + move.l a2,a1 + jsr -$f6(a6) ; AddTail + move.l a2,a0 +fsres4 + move.l a0,d0 + movem.l (sp)+,d1/a0-a2/a6 + rts + +make_dev: ; IN: A0 param_packet, D6: unit_no, D7: boot, A4: expansionbase + + bsr.w fsres + move.l d0,PP_FSRES(a0) ; pointer to FileSystem.resource + move.l a0,-(sp) + move.w #$FFFC,d0 ; filesys base + bsr.w getrtbase + move.l (a0),a5 + move.w #$FF28,d0 ; fill in unit-dependent info (filesys_dev_storeinfo) + bsr.w getrtbase + move.l a0,a1 + move.l (sp)+,a0 + clr.l PP_FSSIZE(a0) ; filesystem size + clr.l PP_FSPTR(a0) ; filesystem memory + jsr (a1) + ; ret:0=virtual,1=hardfile,2=rdbhardfile,-1=hardfile-donotmount,-2=no more subunits + move.l d0,d3 + cmp.l #-2,d3 + beq.w general_ret + cmp.l #2,d3 + beq.s mountalways + + ; KS < V36: init regular hardfiles only if filesystem is loaded + and.l d5,d0 + beq.s mountalways ; >= 36 + tst.l PP_FSSIZE(a0) + beq.w general_ret ; no filesystem -> don't mount + +mountalways + ; allocate memory for loaded filesystem + move.l PP_FSSIZE(a0),d0 + beq.s nordbfs1 + move.l a0,-(sp) + moveq #1,d1 + move.l 4.w,a6 + jsr AllocMem(a6) + move.l (sp)+,a0 + move.l d0,PP_FSPTR(a0) +nordbfs1: + + tst.l d3 + bpl.s do_mount + + ; do not mount but we might need to load possible custom filesystem(s) + move.l a0,a1 + move.w #$FF20,d0 ; record in ui.startup (filesys_dev_remember) + bsr.w getrtbase + jsr (a0) + bra.w dont_mount + +do_mount: + move.l a4,a6 + move.l a0,-(sp) + jsr -144(a6) ; MakeDosNode() + move.l (sp)+,a0 ; parmpacket + move.l a0,a1 + move.l d0,a3 ; devicenode + move.w #$FF20,d0 ; record in ui.startup (filesys_dev_remember) + bsr.w getrtbase + jsr (a0) + moveq #0,d0 + move.l d0,8(a3) ; dn_Task + move.l d0,16(a3) ; dn_Handler + move.l d0,32(a3) ; dn_SegList + +dont_mount + tst.l PP_FSPTR(a1) ; filesystem? + beq.s nordbfs2 + move.l PP_FSPTR(a1),a0 + bsr.w relocate + movem.l d0/a0-a1,-(sp) + move.l PP_FSSIZE(a1),d0 + move.l PP_FSPTR(a1),a1 + move.l 4.w,a6 + jsr FreeMem(a6) + movem.l (sp)+,d0/a0-a1 + tst.l d0 + beq.s nordbfs2 + bsr.w addfs +nordbfs2: + + tst.l d3 + bmi.w general_ret + + move.w #$FF18,d0 ; update dn_SegList if needed (filesys_dev_bootfilesys) + bsr.w getrtbase + jsr (a0) + + move.l d3,d0 + move.b 79(a1),d3 ; bootpri + tst.l d0 + bne.b MKDV_doboot + +MKDV_is_filesys: + move.l #4000,20(a3) ; dn_StackSize + lea.l our_seglist(pc),a1 + move.l a1,d0 + lsr.l #2,d0 + move.l d0,32(a3) ; dn_SegList + moveq #-1,d0 + move.l d0,36(a3) ; dn_GlobalVec + +MKDV_doboot: + tst.l d7 + beq.b MKDV_noboot + + move.l 4.w,a6 + moveq.l #20,d0 + moveq.l #0,d1 + jsr AllocMem(a6) + move.l d0,a1 ; bootnode + moveq #0,d0 + move.l d0,(a1) + move.l d0,4(a1) + move.w d0,14(a1) + move.w #$1000,d0 + or.b d3,d0 + move.w d0,8(a1) + move.l $104(a5),10(a1) ; filesys_configdev + move.l a3,16(a1) ; devicenode + lea.l 74(a4),a0 ; MountList + jmp -270(a6) ; Enqueue() + +MKDV_noboot: + move.l a3,a0 + moveq #0,d1 + move.l d1,a1 + moveq #-1,d0 + move.l a4,a6 ; expansion base + jmp -150(a6) ; AddDosNode + +filesys_mainloop: + move.l 4.w,a6 + moveq.l #0,d0 + move.l d0,a1 + jsr -294(a6) ; FindTask + move.l d0,a0 + lea.l $5c(a0),a5 ; pr_MsgPort + + ; Open DOS library + lea.l doslibname(pc),a1 + moveq.l #0,d0 + jsr -552(a6) ; OpenLibrary + move.l d0,a2 + + ; Allocate some memory. Usage: + ; 0: lock chain + ; 4: command chain + ; 8: second thread's lock chain + ; 12: dummy message + ; 32: the volume (80+44+1 bytes) + move.l #80+44+1+20+12,d0 + move.l #$10001,d1 ; MEMF_PUBLIC | MEMF_CLEAR + jsr AllocMem(a6) + move.l d0,a3 + moveq.l #0,d6 + move.l d6,(a3) + move.l d6,4(a3) + move.l d6,8(a3) + + moveq.l #0,d5 ; No commands queued. + + ; Fetch our startup packet + move.l a5,a0 + jsr -384(a6) ; WaitPort + move.l a5,a0 + jsr -372(a6) ; GetMsg + move.l d0,a4 + move.l 10(a4),d3 ; ln_Name + move.w #$FF40,d0 ; startup_handler + bsr.w getrtbase + moveq.l #0,d0 + jsr (a0) + bra.w FSML_Reply + + ; We abuse some of the fields of the message we get. Offset 0 is + ; used for chaining unprocessed commands, and offset 1 is used for + ; indicating the status of a command. 0 means the command was handed + ; off to some UAE thread and did not complete yet, 1 means we didn't + ; even hand it over yet because we were afraid that might blow some + ; pipe limit, and -1 means the command was handed over and has completed + ; processing by now, so it's safe to reply to it. + +FSML_loop: + move.l a5,a0 + jsr -384(a6) ; WaitPort + move.l a5,a0 + jsr -372(a6) ; GetMsg + move.l d0,a4 + + ; notify reply? + cmp.w #38, 18(a4) + bne.s nonotif + cmp.l #NOTIFY_CLASS, 20(a4) + bne.s nonotif + cmp.w #NOTIFY_CODE, 24(a4) + bne.s nonotif + move.l 26(a4),a0 ; NotifyRequest + move.l 12(a0),d0 ; flags + and.l #NRF_WAIT_REPLY|NRF_MAGIC,d0 + cmp.l #NRF_WAIT_REPLY|NRF_MAGIC,d0 + bne.s nonoti + and.l #~NRF_MAGIC,12(a0) + move.l 16(a0),a0 + move.l a4,a1 + move.b #8,(a1) + jsr -366(a6) ; PutMsg + bra.s FSML_loop +nonoti + move.l a4,a1 + moveq #38,d0 + jsr FreeMem(a6) + bra.s FSML_loop + +nonotif + move.l 10(a4),d3 ; ln_Name + bne.b FSML_FromDOS + + ; It's a dummy packet indicating that some queued command finished. + move.w #$FF50,d0 ; exter_int_helper + bsr.w getrtbase + moveq.l #1,d0 + jsr (a0) + ; Go through the queue and reply all those that finished. + lea.l 4(a3),a2 + move.l (a2),a0 +FSML_check_old: + move.l a0,d0 + beq.b FSML_loop + move.l (a0),a1 + move.l d0,a0 + ; This field may be accessed concurrently by several UAE threads. + ; This _should_ be harmless on all reasonable machines. + move.l 4(a0),d0 + bpl.b FSML_check_next + movem.l a0/a1,-(a7) + move.l 10(a0),a4 + bsr.b ReplyOne + subq.l #1,d5 ; One command less in the queue + movem.l (a7)+,a0/a1 + move.l a1,(a2) + move.l a1,a0 + bra.b FSML_check_old +FSML_check_next: + move.l a0,a2 + move.l a1,a0 + bra.b FSML_check_old + +FSML_FromDOS: + ; Limit the number of outstanding started commands. We can handle an + ; unlimited number of unstarted commands. + cmp.l #20,d5 + bcs FSML_DoCommand + ; Too many commands queued. + moveq.l #1,d0 + move.l d0,4(a4) + bra.b FSML_Enqueue + +FSML_DoCommand: + bsr.b LockCheck ; Make sure there are enough locks for the C code to grab. + move.w #$FF30,d0 + bsr.w getrtbase + jsr (a0) + tst.l d0 + beq.b FSML_Reply + ; The command did not complete yet. Enqueue it and increase number of + ; queued commands + ; The C code already set 4(a4) to 0 + addq.l #1,d5 +FSML_Enqueue: + move.l 4(a3),(a4) + move.l a4,4(a3) + bra.w FSML_loop + +FSML_Reply: + move.l d3,a4 + bsr.b ReplyOne + bra.w FSML_loop + +ReplyOne: + move.l (a4),a1 ; dp_Link + move.l 4(a4),a0 ; dp_Port + move.l a5,4(a4) + jmp -366(a6) ; PutMsg + +; ugly code to avoid calling AllocMem / FreeMem from native C code. +; We keep a linked list of 3 locks. In theory, only one should ever +; be used. Before handling every packet, we check that the list has the +; right length. + +LockCheck: + move.l d5,-(a7) + moveq.l #-4,d5 ; Keep three locks + move.l (a3),a2 + move.l a2,d7 +LKCK_Loop: + move.l a2,d1 + beq LKCK_ListEnd + addq.l #1,d5 + beq.b LKCK_TooMany + move.l a2,a1 + move.l (a2),a2 + bra.b LKCK_Loop +LKCK_ListEnd: + addq.l #1,d5 + beq.b LKCK_ret + move.l d7,a2 + moveq.l #24,d0 ; sizeof Lock is 20, 4 for chain + moveq.l #1,d1 ; MEMF_PUBLIC + jsr AllocMem(a6) + addq.w #1,d6 + move.l d0,a2 + move.l d7,(a2) + move.l a2,d7 + bra.b LKCK_ListEnd +LKCK_TooMany: + move.l (a2),d0 ; We have too many, but we tolerate that to some extent. + beq.b LKCK_ret + move.l d0,a0 + move.l (a0),d0 + beq.b LKCK_ret + move.l d0,a0 + move.l (a0),d0 + beq.b LKCK_ret + + moveq.l #0,d0 ; Now we are sure that we really have too many. Delete some. + move.l d0,(a1) +LKCK_TooManyLoop: + move.l a2,a1 + move.l (a1),a2 + moveq.l #24,d0 + jsr FreeMem(a6) + add.l #$10000,d6 + move.l a2,d0 + bne.b LKCK_TooManyLoop +LKCK_ret: + move.l d7,(a3) + move.l (a7)+,d5 + rts + +getrtbase: + lea start-8-4(pc),a0 + and.l #$FFFF,d0 + add.l d0,a0 + rts + +p96flag dc.w 0 +p96vsyncfix1 + cmp.l #34,8(sp) ; picasso_WaitVerticalSync? + bne.s p961 + movem.l d0-d1/a0-a2/a6,-(sp) + move.l 4.w,a6 + sub.l a1,a1 + jsr -$126(a6) ; FindTask + move.l d0,a2 + move.l a2,a1 + moveq #-20,d0 + jsr -$12c(a6) ; SetTaskPri + lea p96flag(pc),a0 + move.w (a0),d1 +p962 cmp.w (a0),d1 + beq.s p962 + move.l a2,a1 + jsr -$12c(a6) ; SetTaskPri + moveq #1,d1 + movem.l (sp)+,d0-d1/a0-a2/a6 + addq.l #4,sp ; return directly to caller +p961 rts + + +exter_name: dc.b 'UAE filesystem',0 +doslibname: dc.b 'dos.library',0 +explibname: dc.b 'expansion.library',0 +fsresname: dc.b 'FileSystem.resource',0 + END diff --git a/filesys.c b/filesys.c new file mode 100755 index 00000000..02e29015 --- /dev/null +++ b/filesys.c @@ -0,0 +1,4351 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Unix file system handler for AmigaDOS + * + * Copyright 1996 Ed Hanway + * Copyright 1996, 1997 Bernd Schmidt + * + * Version 0.4: 970308 + * + * Based on example code (c) 1988 The Software Distillery + * and published in Transactor for the Amiga, Volume 2, Issues 2-5. + * (May - August 1989) + * + * Known limitations: + * Does not support ACTION_INHIBIT (big deal). + * Does not support several 2.0+ packet types. + * Does not support removable volumes. + * May not return the correct error code in some cases. + * Does not check for sane values passed by AmigaDOS. May crash the emulation + * if passed garbage values. + * Could do tighter checks on malloc return values. + * Will probably fail spectacularly in some cases if the filesystem is + * modified at the same time by another process while UAE is running. + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "threaddep/thread.h" +#include "options.h" +#include "uae.h" +#include "memory.h" +#include "custom.h" +#include "events.h" +#include "newcpu.h" +#include "filesys.h" +#include "autoconf.h" +#include "compiler.h" +#include "fsusage.h" +#include "native2amiga.h" +#include "scsidev.h" +#include "fsdb.h" +#include "zfile.h" +#include "gui.h" + +#define TRACING_ENABLED 0 +#if TRACING_ENABLED +#define TRACE(x) do { write_log x; } while(0) +#define DUMPLOCK(u,x) dumplock(u,x) +#else +#define TRACE(x) +#define DUMPLOCK(u,x) +#endif + +void xfree (void *p) +{ + free (p); +} + +static void aino_test (a_inode *aino) +{ +#ifdef AINO_DEBUG + a_inode *aino2 = aino, *aino3; + for (;;) { + if (!aino || !aino->next) + return; + if ((aino->checksum1 ^ aino->checksum2) != 0xaaaa5555) { + write_log ("PANIC: corrupted or freed but used aino detected!", aino); + } + aino3 = aino; + aino = aino->next; + if (aino->prev != aino3) { + write_log ("PANIC: corrupted aino linking!\n"); + break; + } + if (aino == aino2) break; + } +#endif +} + +static void aino_test_init (a_inode *aino) +{ +#ifdef AINO_DEBUG + aino->checksum1 = (uae_u32)aino; + aino->checksum2 = aino->checksum1 ^ 0xaaaa5555; +#endif +} + +static long dos_errno(void) +{ + int e = errno; + + switch (e) { + case ENOMEM: return ERROR_NO_FREE_STORE; + case EEXIST: return ERROR_OBJECT_EXISTS; + case EACCES: return ERROR_WRITE_PROTECTED; + case ENOENT: return ERROR_OBJECT_NOT_AROUND; + case ENOTDIR: return ERROR_OBJECT_WRONG_TYPE; + case ENOSPC: return ERROR_DISK_IS_FULL; + case EBUSY: return ERROR_OBJECT_IN_USE; + case EISDIR: return ERROR_OBJECT_WRONG_TYPE; +#if defined(ETXTBSY) + case ETXTBSY: return ERROR_OBJECT_IN_USE; +#endif +#if defined(EROFS) + case EROFS: return ERROR_DISK_WRITE_PROTECTED; +#endif +#if defined(ENOTEMPTY) +#if ENOTEMPTY != EEXIST + case ENOTEMPTY: return ERROR_DIRECTORY_NOT_EMPTY; +#endif +#endif + + default: + TRACE(("Unimplemented error %s\n", strerror(e))); + return ERROR_NOT_IMPLEMENTED; + } +} + +/* + * This _should_ be no issue for us, but let's rather use a guaranteed + * thread safe function if we have one. + * This used to be broken in glibc versions <= 2.0.1 (I think). I hope + * no one is using this these days. + * Michael Krause says it's also broken in libc5. ARRRGHHHHHH!!!! + */ +#if 0 && defined HAVE_READDIR_R + +static struct dirent *my_readdir (DIR *dirstream, struct dirent *space) +{ + struct dirent *loc; + if (readdir_r (dirstream, space, &loc) == 0) { + /* Success */ + return loc; + } + return 0; +} + +#else +#define my_readdir(dirstream, space) readdir(dirstream) +#endif + +uaecptr filesys_initcode; +static uae_u32 fsdevname, filesys_configdev; + +#define FS_STARTUP 0 +#define FS_GO_DOWN 1 + +#define DEVNAMES_PER_HDF 32 + +typedef struct { + char *devname; /* device name, e.g. UAE0: */ + uaecptr devname_amiga; + uaecptr startup; + char *volname; /* volume name, e.g. CDROM, WORK, etc. */ + char *rootdir; /* root unix directory */ + int readonly; /* disallow write access? */ + int bootpri; /* boot priority */ + int devno; + + struct hardfiledata hf; + + /* Threading stuff */ + smp_comm_pipe *volatile unit_pipe, *volatile back_pipe; + uae_thread_id tid; + struct _unit *self; + /* Reset handling */ + volatile uae_sem_t reset_sync_sem; + volatile int reset_state; + + /* RDB stuff */ + uaecptr rdb_devname_amiga[DEVNAMES_PER_HDF]; + int rdb_lowcyl; + int rdb_highcyl; + int rdb_cylblocks; + uae_u8 *rdb_filesysstore; + int rdb_filesyssize; + char *filesysdir; + + +} UnitInfo; + +struct uaedev_mount_info { + int num_units; + UnitInfo ui[MAX_FILESYSTEM_UNITS]; +}; + +static struct uaedev_mount_info *current_mountinfo; + +int nr_units (struct uaedev_mount_info *mountinfo) +{ + return mountinfo->num_units; +} + +int is_hardfile (struct uaedev_mount_info *mountinfo, int unit_no) +{ + if (mountinfo->ui[unit_no].volname) + return FILESYS_VIRTUAL; + if (mountinfo->ui[unit_no].hf.secspertrack == 0) { + if (mountinfo->ui[unit_no].hf.flags & 1) + return FILESYS_HARDDRIVE; + return FILESYS_HARDFILE_RDB; + } + return FILESYS_HARDFILE; +} + +static void close_filesys_unit (UnitInfo *uip) +{ + if (uip->hf.handle != 0) + hdf_close (&uip->hf); + if (uip->volname != 0) + xfree (uip->volname); + if (uip->devname != 0) + xfree (uip->devname); + if (uip->rootdir != 0) + xfree (uip->rootdir); + if (uip->unit_pipe) + xfree (uip->unit_pipe); + if (uip->back_pipe) + xfree (uip->back_pipe); + + uip->unit_pipe = 0; + uip->back_pipe = 0; + + uip->hf.handle = 0; + uip->volname = 0; + uip->devname = 0; + uip->rootdir = 0; +} + +char *get_filesys_unit (struct uaedev_mount_info *mountinfo, int nr, + char **devname, char **volname, char **rootdir, int *readonly, + int *secspertrack, int *surfaces, int *reserved, + int *cylinders, uae_u64 *size, int *blocksize, int *bootpri, char **filesysdir) +{ + UnitInfo *uip = mountinfo->ui + nr; + + if (nr >= mountinfo->num_units) + return "No slot allocated for this unit"; + + *volname = uip->volname ? my_strdup (uip->volname) : 0; + if (uip->devname == 0 || strlen(uip->devname) == 0) { + *devname = xmalloc (10); + sprintf (*devname, "DH%d", nr); + } else { + *devname = my_strdup (uip->devname); + } + *rootdir = uip->rootdir ? my_strdup (uip->rootdir) : 0; + *readonly = uip->readonly; + *secspertrack = uip->hf.secspertrack; + *surfaces = uip->hf.surfaces; + *reserved = uip->hf.reservedblocks; + *cylinders = uip->hf.nrcyls; + *blocksize = uip->hf.blocksize; + *size = uip->hf.size; + *bootpri = uip->bootpri; + if (filesysdir) + *filesysdir = uip->filesysdir ? my_strdup (uip->filesysdir) : 0; + return 0; +} + +static char *set_filesys_unit_1 (struct uaedev_mount_info *mountinfo, int nr, + char *devname, char *volname, char *rootdir, int readonly, + int secspertrack, int surfaces, int reserved, + int blocksize, int bootpri, char *filesysdir) +{ + UnitInfo *ui = mountinfo->ui + nr; + int v; + static char errmsg[1024]; + + if (nr >= mountinfo->num_units) + return "No slot allocated for this unit"; + + ui->devname = 0; + ui->volname = 0; + ui->rootdir = 0; + ui->unit_pipe = 0; + ui->back_pipe = 0; + ui->hf.handle = 0; + ui->bootpri = 0; + ui->filesysdir = 0; + + if (volname != 0) { + struct stat statbuf; + memset (&statbuf, 0, sizeof (statbuf)); + ui->volname = my_strdup (volname); + v = isspecialdrive (rootdir); + if (v < 0) { + sprintf (errmsg, "invalid drive '%s'", rootdir); + return errmsg; + } + if (v == 0) { + if (stat (rootdir, &statbuf) < 0) { + sprintf (errmsg, "directory '%s' not found", rootdir); + return errmsg; + } + if (!(statbuf.st_mode & FILEFLAG_WRITE)) { + write_log ("'%s' set to read-only\n", rootdir); + readonly = 1; + } + } + } else { + ui->hf.secspertrack = secspertrack; + ui->hf.surfaces = surfaces; + ui->hf.reservedblocks = reserved; + ui->hf.blocksize = blocksize; + ui->volname = 0; + ui->hf.readonly = readonly; + if (!hdf_open (&ui->hf, rootdir) && !readonly) { + ui->hf.readonly = readonly = 1; + hdf_open (&ui->hf, rootdir); + } + ui->hf.readonly = readonly; + if (ui->hf.handle == 0) + return "Hardfile not found"; + + if ((blocksize & (blocksize - 1)) != 0) + return "Bad blocksize"; + if ((secspertrack || surfaces || reserved) && + (secspertrack < 1 || surfaces < 1 || surfaces > 1023 || reserved < 0 || reserved > 1023) != 0) + { + return "Bad hardfile geometry"; + } + ui->hf.nrcyls = (int)(secspertrack * surfaces ? (ui->hf.size / blocksize) / (secspertrack * surfaces) : 0); + } + ui->self = 0; + ui->reset_state = FS_STARTUP; + ui->rootdir = my_strdup (rootdir); + ui->devname = my_strdup (devname); + if (filesysdir) + ui->filesysdir = my_strdup (filesysdir); + ui->readonly = readonly; + if (bootpri < -128) bootpri = -128; + if (bootpri > 127) bootpri = 127; + ui->bootpri = bootpri; + + return 0; +} + +char *set_filesys_unit (struct uaedev_mount_info *mountinfo, int nr, + char *devname, char *volname, char *rootdir, int readonly, + int secspertrack, int surfaces, int reserved, + int blocksize, int bootpri, char *filesysdir) +{ + char *result; + UnitInfo ui = mountinfo->ui[nr]; + + hdf_close (&ui.hf); + result = set_filesys_unit_1 (mountinfo, nr, devname, volname, rootdir, readonly, + secspertrack, surfaces, reserved, blocksize, bootpri, filesysdir); + if (result) + mountinfo->ui[nr] = ui; + else + close_filesys_unit (&ui); + + return result; +} + +char *add_filesys_unit (struct uaedev_mount_info *mountinfo, + char *devname, char *volname, char *rootdir, int readonly, + int secspertrack, int surfaces, int reserved, + int blocksize, int bootpri, char *filesysdir) +{ + char *retval; + int nr = mountinfo->num_units; + UnitInfo *uip = mountinfo->ui + nr; + + if (nr >= MAX_FILESYSTEM_UNITS) + return "Maximum number of file systems mounted"; + + mountinfo->num_units++; + retval = set_filesys_unit_1 (mountinfo, nr, devname, volname, rootdir, readonly, + secspertrack, surfaces, reserved, blocksize, bootpri, filesysdir); + if (retval) + mountinfo->num_units--; + return retval; +} + +int kill_filesys_unit (struct uaedev_mount_info *mountinfo, int nr) +{ + UnitInfo *uip = mountinfo->ui; + if (nr >= mountinfo->num_units || nr < 0) + return -1; + + close_filesys_unit (mountinfo->ui + nr); + + mountinfo->num_units--; + for (; nr < mountinfo->num_units; nr++) { + uip[nr] = uip[nr+1]; + } + return 0; +} + +int move_filesys_unit (struct uaedev_mount_info *mountinfo, int nr, int to) +{ + UnitInfo tmpui; + UnitInfo *uip = mountinfo->ui; + + if (nr >= mountinfo->num_units || nr < 0 + || to >= mountinfo->num_units || to < 0 + || to == nr) + return -1; + tmpui = uip[nr]; + if (to > nr) { + int i; + for (i = nr; i < to; i++) + uip[i] = uip[i + 1]; + } else { + int i; + for (i = nr; i > to; i--) + uip[i] = uip[i - 1]; + } + uip[to] = tmpui; + return 0; +} + +int sprintf_filesys_unit (struct uaedev_mount_info *mountinfo, char *buffer, int num) +{ + UnitInfo *uip = mountinfo->ui; + if (num >= mountinfo->num_units) + return -1; + + if (uip[num].volname != 0) + sprintf (buffer, "(DH%d:) Filesystem, %s: %s %s", num, uip[num].volname, + uip[num].rootdir, uip[num].readonly ? "ro" : ""); + else + sprintf (buffer, "(DH%d:) Hardfile, \"%s\", size %d Mbytes", num, + uip[num].rootdir, uip[num].hf.size / (1024 * 1024)); + return 0; +} + +void write_filesys_config (struct uaedev_mount_info *mountinfo, + const char *unexpanded, const char *default_path, FILE *f) +{ + UnitInfo *uip = mountinfo->ui; + int i; + + for (i = 0; i < mountinfo->num_units; i++) { + char *str; + str = cfgfile_subst_path (default_path, unexpanded, uip[i].rootdir); + if (uip[i].volname != 0) { + fprintf (f, "filesystem2=%s,%s:%s:%s,%d\n", uip[i].readonly ? "ro" : "rw", + uip[i].devname ? uip[i].devname : "", uip[i].volname, str, uip[i].bootpri); + fprintf (f, "filesystem=%s,%s:%s\n", uip[i].readonly ? "ro" : "rw", + uip[i].volname, str); + } else { + fprintf (f, "hardfile2=%s,%s:%s,%d,%d,%d,%d,%d,%s\n", + uip[i].readonly ? "ro" : "rw", + uip[i].devname ? uip[i].devname : "", str, + uip[i].hf.secspertrack, uip[i].hf.surfaces, uip[i].hf.reservedblocks, uip[i].hf.blocksize, + uip[i].bootpri,uip[i].filesysdir ? uip[i].filesysdir : ""); + fprintf (f, "hardfile=%s,%d,%d,%d,%d,%s\n", + uip[i].readonly ? "ro" : "rw", uip[i].hf.secspertrack, + uip[i].hf.surfaces, uip[i].hf.reservedblocks, uip[i].hf.blocksize, str); + } + xfree (str); + } +} + +struct uaedev_mount_info *alloc_mountinfo (void) +{ + struct uaedev_mount_info *info; + info = malloc (sizeof *info); + memset (info, 0, sizeof *info); + info->num_units = 0; + return info; +} + +struct uaedev_mount_info *dup_mountinfo (struct uaedev_mount_info *mip) +{ + int i; + struct uaedev_mount_info *i2 = alloc_mountinfo (); + + memcpy (i2, mip, sizeof *i2); + + for (i = 0; i < i2->num_units; i++) { + UnitInfo *uip = i2->ui + i; + if (uip->volname) + uip->volname = my_strdup (uip->volname); + if (uip->devname) + uip->devname = my_strdup (uip->devname); + if (uip->rootdir) + uip->rootdir = my_strdup (uip->rootdir); + if (uip->hf.handle) + hdf_dup (&uip->hf, uip->hf.handle); + } + return i2; +} + +void free_mountinfo (struct uaedev_mount_info *mip) +{ + int i; + if (!mip) + return; + for (i = 0; i < mip->num_units; i++) + close_filesys_unit (mip->ui + i); + xfree (mip); +} + +struct hardfiledata *get_hardfile_data (int nr) +{ + UnitInfo *uip = current_mountinfo->ui; + if (nr < 0 || nr >= current_mountinfo->num_units || uip[nr].volname != 0) + return 0; + return &uip[nr].hf; +} + +/* minimal AmigaDOS definitions */ + +/* field offsets in DosPacket */ +#define dp_Type 8 +#define dp_Res1 12 +#define dp_Res2 16 +#define dp_Arg1 20 +#define dp_Arg2 24 +#define dp_Arg3 28 +#define dp_Arg4 32 + +/* result codes */ +#define DOS_TRUE ((unsigned long)-1L) +#define DOS_FALSE (0L) + +/* Passed as type to Lock() */ +#define SHARED_LOCK -2 /* File is readable by others */ +#define ACCESS_READ -2 /* Synonym */ +#define EXCLUSIVE_LOCK -1 /* No other access allowed */ +#define ACCESS_WRITE -1 /* Synonym */ + +/* packet types */ +#define ACTION_CURRENT_VOLUME 7 +#define ACTION_LOCATE_OBJECT 8 +#define ACTION_RENAME_DISK 9 +#define ACTION_FREE_LOCK 15 +#define ACTION_DELETE_OBJECT 16 +#define ACTION_RENAME_OBJECT 17 +#define ACTION_COPY_DIR 19 +#define ACTION_SET_PROTECT 21 +#define ACTION_CREATE_DIR 22 +#define ACTION_EXAMINE_OBJECT 23 +#define ACTION_EXAMINE_NEXT 24 +#define ACTION_DISK_INFO 25 +#define ACTION_INFO 26 +#define ACTION_FLUSH 27 +#define ACTION_SET_COMMENT 28 +#define ACTION_PARENT 29 +#define ACTION_SET_DATE 34 +#define ACTION_FIND_WRITE 1004 +#define ACTION_FIND_INPUT 1005 +#define ACTION_FIND_OUTPUT 1006 +#define ACTION_END 1007 +#define ACTION_SEEK 1008 +#define ACTION_IS_FILESYSTEM 1027 +#define ACTION_READ 'R' +#define ACTION_WRITE 'W' + +/* 2.0+ packet types */ +#define ACTION_INHIBIT 31 +#define ACTION_SET_FILE_SIZE 1022 +#define ACTION_LOCK_RECORD 2008 +#define ACTION_FREE_RECORD 2009 +#define ACTION_SAME_LOCK 40 +#define ACTION_CHANGE_MODE 1028 +#define ACTION_FH_FROM_LOCK 1026 +#define ACTION_COPY_DIR_FH 1030 +#define ACTION_PARENT_FH 1031 +#define ACTION_EXAMINE_FH 1034 +#define ACTION_EXAMINE_ALL 1033 +#define ACTION_MAKE_LINK 1021 +#define ACTION_READ_LINK 1024 +#define ACTION_FORMAT 1020 +#define ACTION_IS_FILESYSTEM 1027 +#define ACTION_ADD_NOTIFY 4097 +#define ACTION_REMOVE_NOTIFY 4098 + +#define DISK_TYPE 0x444f5301 /* DOS\1 */ + +typedef struct { + uae_u32 uniq; + /* The directory we're going through. */ + a_inode *aino; + /* The file we're going to look up next. */ + a_inode *curr_file; +} ExamineKey; + +typedef struct key { + struct key *next; + a_inode *aino; + uae_u32 uniq; + int fd; + off_t file_pos; + int dosmode; + int createmode; + int notifyactive; +} Key; + +typedef struct notify { + struct notify *next; + uaecptr notifyrequest; + char *fullname; + char *partname; +} Notify; + +/* Since ACTION_EXAMINE_NEXT is so braindamaged, we have to keep + * some of these around + */ + +#define EXKEYS 100 +#define MAX_AINO_HASH 128 +#define NOTIFY_HASH_SIZE 127 + +/* handler state info */ + +typedef struct _unit { + struct _unit *next; + + /* Amiga stuff */ + uaecptr dosbase; + uaecptr volume; + uaecptr port; /* Our port */ + uaecptr locklist; + + /* Native stuff */ + uae_s32 unit; /* unit number */ + UnitInfo ui; /* unit startup info */ + char tmpbuf3[256]; + + /* Dummy message processing */ + uaecptr dummy_message; + volatile unsigned int cmds_sent; + volatile unsigned int cmds_complete; + volatile unsigned int cmds_acked; + + /* ExKeys */ + ExamineKey examine_keys[EXKEYS]; + int next_exkey; + unsigned long total_locked_ainos; + + /* Keys */ + struct key *keys; + uae_u32 key_uniq; + uae_u32 a_uniq; + + a_inode rootnode; + unsigned long aino_cache_size; + a_inode *aino_hash[MAX_AINO_HASH]; + unsigned long nr_cache_hits; + unsigned long nr_cache_lookups; + + struct notify *notifyhash[NOTIFY_HASH_SIZE]; + +} Unit; + +typedef uae_u8 *dpacket; +#define PUT_PCK_RES1(p,v) do { do_put_mem_long ((uae_u32 *)((p) + dp_Res1), (v)); } while (0) +#define PUT_PCK_RES2(p,v) do { do_put_mem_long ((uae_u32 *)((p) + dp_Res2), (v)); } while (0) +#define GET_PCK_TYPE(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Type)))) +#define GET_PCK_RES1(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Res1)))) +#define GET_PCK_RES2(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Res2)))) +#define GET_PCK_ARG1(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg1)))) +#define GET_PCK_ARG2(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg2)))) +#define GET_PCK_ARG3(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg3)))) +#define GET_PCK_ARG4(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg4)))) + +static char *char1 (uaecptr addr) +{ + static char buf[1024]; + int i = 0; + do { + buf[i] = get_byte(addr); + addr++; + } while (buf[i++] && i < sizeof(buf)); + return buf; +} + +static char *bstr1 (uaecptr addr) +{ + static char buf[256]; + int i; + int n = get_byte(addr); + addr++; + + for (i = 0; i < n; i++, addr++) + buf[i] = get_byte(addr); + buf[i] = 0; + return buf; +} + +static char *bstr (Unit *unit, uaecptr addr) +{ + int i; + int n = get_byte(addr); + + addr++; + for (i = 0; i < n; i++, addr++) + unit->tmpbuf3[i] = get_byte(addr); + unit->tmpbuf3[i] = 0; + return unit->tmpbuf3; +} + +static char *bstr_cut (Unit *unit, uaecptr addr) +{ + char *p = unit->tmpbuf3; + int i, colon_seen = 0; + int n = get_byte (addr); + + addr++; + for (i = 0; i < n; i++, addr++) { + uae_u8 c = get_byte(addr); + unit->tmpbuf3[i] = c; + if (c == '/' || (c == ':' && colon_seen++ == 0)) + p = unit->tmpbuf3 + i + 1; + } + unit->tmpbuf3[i] = 0; + return p; +} + +static Unit *units = 0; +static int unit_num = 0; + +static Unit* +find_unit (uaecptr port) +{ + Unit* u; + for (u = units; u; u = u->next) + if (u->port == port) + break; + + return u; +} + +static void prepare_for_open (char *name) +{ +#if 0 + struct stat statbuf; + int mode; + + if (-1 == stat (name, &statbuf)) + return; + + mode = statbuf.st_mode; + mode |= S_IRUSR; + mode |= S_IWUSR; + mode |= S_IXUSR; + chmod (name, mode); +#endif +} + +static void de_recycle_aino (Unit *unit, a_inode *aino) +{ + aino_test (aino); + if (aino->next == 0 || aino == &unit->rootnode) + return; + aino->next->prev = aino->prev; + aino->prev->next = aino->next; + aino->next = aino->prev = 0; + unit->aino_cache_size--; +} + +static void dispose_aino (Unit *unit, a_inode **aip, a_inode *aino) +{ + int hash = aino->uniq % MAX_AINO_HASH; + if (unit->aino_hash[hash] == aino) + unit->aino_hash[hash] = 0; + + if (aino->dirty && aino->parent) + fsdb_dir_writeback (aino->parent); + + *aip = aino->sibling; + xfree (aino->aname); + if (aino->comment) + xfree (aino->comment); + xfree (aino->nname); + xfree (aino); +} + +static void recycle_aino (Unit *unit, a_inode *new_aino) +{ + aino_test (new_aino); + if (new_aino->dir || new_aino->shlock > 0 + || new_aino->elock || new_aino == &unit->rootnode) + /* Still in use */ + return; + + TRACE (("Recycling; cache size %d, total_locked %d\n", + unit->aino_cache_size, unit->total_locked_ainos)); + if (unit->aino_cache_size > 5000 + unit->total_locked_ainos) { + /* Reap a few. */ + int i = 0; + while (i < 50) { + a_inode *parent = unit->rootnode.prev->parent; + a_inode **aip; + aip = &parent->child; + + aino_test (parent); + if (! parent->locked_children) { + for (;;) { + a_inode *aino = *aip; + aino_test (aino); + if (aino == 0) + break; + /* Not recyclable if next == 0 (i.e., not chained into + recyclable list), or if parent directory is being + ExNext()ed. */ + if (aino->next == 0) { + aip = &aino->sibling; + } else { + if (aino->shlock > 0 || aino->elock) + write_log ("panic: freeing locked a_inode!\n"); + + de_recycle_aino (unit, aino); + dispose_aino (unit, aip, aino); + i++; + } + } + } + /* In the previous loop, we went through all children of one + parent. Re-arrange the recycled list so that we'll find a + different parent the next time around. */ + do { + unit->rootnode.next->prev = unit->rootnode.prev; + unit->rootnode.prev->next = unit->rootnode.next; + unit->rootnode.next = unit->rootnode.prev; + unit->rootnode.prev = unit->rootnode.prev->prev; + unit->rootnode.prev->next = unit->rootnode.next->prev = &unit->rootnode; + } while (unit->rootnode.prev->parent == parent); + } +#if 0 + { + char buffer[40]; + sprintf (buffer, "%d ainos reaped.\n", i); + TRACE ((buffer)); + } +#endif + } + + aino_test (new_aino); + /* Chain it into circular list. */ + new_aino->next = unit->rootnode.next; + new_aino->prev = &unit->rootnode; + new_aino->prev->next = new_aino; + new_aino->next->prev = new_aino; + aino_test (new_aino->next); + aino_test (new_aino->prev); + + unit->aino_cache_size++; +} + +static void update_child_names (Unit *unit, a_inode *a, a_inode *parent) +{ + int l0 = strlen (parent->nname) + 2; + + while (a != 0) { + char *name_start; + char *new_name; + char dirsep[2] = { FSDB_DIR_SEPARATOR, '\0' }; + + a->parent = parent; + name_start = strrchr (a->nname, FSDB_DIR_SEPARATOR); + if (name_start == 0) { + write_log ("malformed file name"); + } + name_start++; + new_name = (char *)xmalloc (strlen (name_start) + l0); + strcpy (new_name, parent->nname); + strcat (new_name, dirsep); + strcat (new_name, name_start); + xfree (a->nname); + a->nname = new_name; + if (a->child) + update_child_names (unit, a->child, a); + a = a->sibling; + } +} + +static void move_aino_children (Unit *unit, a_inode *from, a_inode *to) +{ + aino_test (from); + aino_test (to); + to->child = from->child; + from->child = 0; + update_child_names (unit, to->child, to); +} + +static void delete_aino (Unit *unit, a_inode *aino) +{ + a_inode **aip; + + TRACE(("deleting aino %x\n", aino->uniq)); + + aino_test (aino); + aino->dirty = 1; + aino->deleted = 1; + de_recycle_aino (unit, aino); + + /* If any ExKeys are currently pointing at us, advance them. */ + if (aino->parent->exnext_count > 0) { + int i; + TRACE(("entering exkey validation\n")); + for (i = 0; i < EXKEYS; i++) { + ExamineKey *k = unit->examine_keys + i; + if (k->uniq == 0) + continue; + if (k->aino == aino->parent) { + TRACE(("Same parent found for %d\n", i)); + if (k->curr_file == aino) { + k->curr_file = aino->sibling; + TRACE(("Advancing curr_file\n")); + } + } + } + } + + aip = &aino->parent->child; + while (*aip != aino && *aip != 0) + aip = &(*aip)->sibling; + if (*aip != aino) { + write_log ("Couldn't delete aino.\n"); + return; + } + dispose_aino (unit, aip, aino); +} + +static a_inode *lookup_sub (a_inode *dir, uae_u32 uniq) +{ + a_inode **cp = &dir->child; + a_inode *c, *retval; + + for (;;) { + c = *cp; + if (c == 0) + return 0; + + if (c->uniq == uniq) { + retval = c; + break; + } + if (c->dir) { + a_inode *a = lookup_sub (c, uniq); + if (a != 0) { + retval = a; + break; + } + } + cp = &c->sibling; + } + if (! dir->locked_children) { + /* Move to the front to speed up repeated lookups. Don't do this if + an ExNext is going on in this directory, or we'll terminally + confuse it. */ + *cp = c->sibling; + c->sibling = dir->child; + dir->child = c; + } + return retval; +} + +static a_inode *lookup_aino (Unit *unit, uae_u32 uniq) +{ + a_inode *a; + int hash = uniq % MAX_AINO_HASH; + + if (uniq == 0) + return &unit->rootnode; + a = unit->aino_hash[hash]; + if (a == 0 || a->uniq != uniq) + a = lookup_sub (&unit->rootnode, uniq); + else + unit->nr_cache_hits++; + unit->nr_cache_lookups++; + unit->aino_hash[hash] = a; + aino_test (a); + return a; +} + +char *build_nname (const char *d, const char *n) +{ + char dsep[2] = { FSDB_DIR_SEPARATOR, '\0' }; + char *p = (char *) xmalloc (strlen (d) + strlen (n) + 2); + strcpy (p, d); + strcat (p, dsep); + strcat (p, n); + return p; +} + +char *build_aname (const char *d, const char *n) +{ + char *p = (char *) xmalloc (strlen (d) + strlen (n) + 2); + strcpy (p, d); + strcat (p, "/"); + strcat (p, n); + return p; +} + +/* This gets called to translate an Amiga name that some program used to + * a name that we can use on the native filesystem. */ +static char *get_nname (Unit *unit, a_inode *base, char *rel, + char **modified_rel) +{ + char *found; + char *p = 0; + + aino_test (base); + + *modified_rel = 0; + + /* If we have a mapping of some other aname to "rel", we must pretend + * it does not exist. + * This can happen for example if an Amiga program creates a + * file called ".". We can't represent this in our filesystem, + * so we create a special file "uae_xxx" and record the mapping + * aname "." -> nname "uae_xxx" in the database. Then, the Amiga + * program looks up "uae_xxx" (yes, it's contrived). The filesystem + * should not make the uae_xxx file visible to the Amiga side. */ + if (fsdb_used_as_nname (base, rel)) + return 0; + /* A file called "." (or whatever else is invalid on this filesystem) + * does not exist, as far as the Amiga side is concerned. */ + if (fsdb_name_invalid (rel)) + return 0; + + /* See if we have a file that has the same name as the aname we are + * looking for. */ + found = fsdb_search_dir (base->nname, rel); + if (found == 0) + return found; + if (found == rel) + return build_nname (base->nname, rel); + + *modified_rel = found; + return build_nname (base->nname, found); +} + +static char *create_nname (Unit *unit, a_inode *base, char *rel) +{ + char *p; + + aino_test (base); + /* We are trying to create a file called REL. */ + + /* If the name is used otherwise in the directory (or globally), we + * need a new unique nname. */ + if (fsdb_name_invalid (rel) || fsdb_used_as_nname (base, rel)) { +#if 0 + oh_dear: +#endif + if (currprefs.filesys_no_uaefsdb) { + write_log ("illegal filename '%s' and uaefsdb disabled\n", rel); + return 0; + } + p = fsdb_create_unique_nname (base, rel); + return p; + } + p = build_nname (base->nname, rel); +#if 0 + /* Delete this code once we know everything works. */ + if (access (p, R_OK) >= 0 || errno != ENOENT) { + write_log ("Filesystem in trouble... please report.\n"); + xfree (p); + goto oh_dear; + } +#endif + return p; +} + +/* + * This gets called if an ACTION_EXAMINE_NEXT happens and we hit an object + * for which we know the name on the native filesystem, but no corresponding + * Amiga filesystem name. + * @@@ For DOS filesystems, it might make sense to declare the new name + * "weak", so that it can get overriden by a subsequent call to get_nname(). + * That way, if someone does "dir :" and there is a file "foobar.inf", and + * someone else tries to open "foobar.info", get_nname() could maybe made to + * figure out that this is supposed to be the file "foobar.inf". + * DOS sucks... + */ +static char *get_aname (Unit *unit, a_inode *base, char *rel) +{ + return my_strdup (rel); +} + +static void init_child_aino (Unit *unit, a_inode *base, a_inode *aino) +{ + aino->uniq = ++unit->a_uniq; + if (unit->a_uniq == 0xFFFFFFFF) { + write_log ("Running out of a_inodes (prepare for big trouble)!\n"); + } + aino->shlock = 0; + aino->elock = 0; + + aino->dirty = 0; + aino->deleted = 0; + + /* For directories - this one isn't being ExNext()ed yet. */ + aino->locked_children = 0; + aino->exnext_count = 0; + /* But the parent might be. */ + if (base->exnext_count) { + unit->total_locked_ainos++; + base->locked_children++; + } + /* Update tree structure */ + aino->parent = base; + aino->child = 0; + aino->sibling = base->child; + base->child = aino; + aino->next = aino->prev = 0; + + aino_test_init (aino); + aino_test (aino); +} + +static a_inode *new_child_aino (Unit *unit, a_inode *base, char *rel) +{ + char *modified_rel; + char *nn; + a_inode *aino; + + TRACE(("new_child_aino %s, %s\n", base->aname, rel)); + + aino = fsdb_lookup_aino_aname (base, rel); + if (aino == 0) { + nn = get_nname (unit, base, rel, &modified_rel); + if (nn == 0) + return 0; + + aino = (a_inode *) xcalloc (sizeof (a_inode), 1); + if (aino == 0) + return 0; + aino->aname = modified_rel ? modified_rel : my_strdup (rel); + aino->nname = nn; + + aino->comment = 0; + aino->has_dbentry = 0; + + fsdb_fill_file_attrs (aino); + if (aino->dir) + fsdb_clean_dir (aino); + } + init_child_aino (unit, base, aino); + + recycle_aino (unit, aino); + TRACE(("created aino %x, lookup, amigaos_mode %d\n", aino->uniq, aino->amigaos_mode)); + return aino; +} + +static a_inode *create_child_aino (Unit *unit, a_inode *base, char *rel, int isdir) +{ + a_inode *aino = (a_inode *) xcalloc (sizeof (a_inode), 1); + if (aino == 0) + return 0; + + aino->nname = create_nname (unit, base, rel); + if (!aino->nname) { + free (aino); + return 0; + } + aino->aname = my_strdup (rel); + + init_child_aino (unit, base, aino); + aino->amigaos_mode = 0; + aino->dir = isdir; + + aino->comment = 0; + aino->has_dbentry = 0; + aino->dirty = 1; + + recycle_aino (unit, aino); + TRACE(("created aino %x, create\n", aino->uniq)); + return aino; +} + +static a_inode *lookup_child_aino (Unit *unit, a_inode *base, char *rel, uae_u32 *err) +{ + a_inode *c = base->child; + int l0 = strlen (rel); + + aino_test (base); + aino_test (c); + + if (base->dir == 0) { + *err = ERROR_OBJECT_WRONG_TYPE; + return 0; + } + + while (c != 0) { + int l1 = strlen (c->aname); + if (l0 <= l1 && same_aname (rel, c->aname + l1 - l0) + && (l0 == l1 || c->aname[l1-l0-1] == '/')) + break; + c = c->sibling; + } + if (c != 0) + return c; + c = new_child_aino (unit, base, rel); + if (c == 0) + *err = ERROR_OBJECT_NOT_AROUND; + return c; +} + +/* Different version because for this one, REL is an nname. */ +static a_inode *lookup_child_aino_for_exnext (Unit *unit, a_inode *base, char *rel, uae_u32 *err) +{ + a_inode *c = base->child; + int l0 = strlen (rel); + + aino_test (base); + aino_test (c); + + *err = 0; + while (c != 0) { + int l1 = strlen (c->nname); + /* Note: using strcmp here. */ + if (l0 <= l1 && strcmp (rel, c->nname + l1 - l0) == 0 + && (l0 == l1 || c->nname[l1-l0-1] == FSDB_DIR_SEPARATOR)) + break; + c = c->sibling; + } + if (c != 0) + return c; + c = fsdb_lookup_aino_nname (base, rel); + if (c == 0) { + c = xcalloc (sizeof (a_inode), 1); + if (c == 0) { + *err = ERROR_NO_FREE_STORE; + return 0; + } + + c->nname = build_nname (base->nname, rel); + c->aname = get_aname (unit, base, rel); + c->comment = 0; + c->has_dbentry = 0; + fsdb_fill_file_attrs (c); + if (c->dir) + fsdb_clean_dir (c); + } + init_child_aino (unit, base, c); + + recycle_aino (unit, c); + TRACE(("created aino %x, exnext\n", c->uniq)); + + return c; +} + +static a_inode *get_aino (Unit *unit, a_inode *base, const char *rel, uae_u32 *err) +{ + char *tmp; + char *p; + a_inode *curr; + int i; + + aino_test (base); + + *err = 0; + TRACE(("get_path(%s,%s)\n", base->aname, rel)); + + /* root-relative path? */ + for (i = 0; rel[i] && rel[i] != '/' && rel[i] != ':'; i++) + ; + if (':' == rel[i]) + rel += i+1; + + tmp = my_strdup (rel); + p = tmp; + curr = base; + + while (*p) { + /* start with a slash? go up a level. */ + if (*p == '/') { + if (curr->parent != 0) + curr = curr->parent; + p++; + } else { + a_inode *next; + + char *component_end; + component_end = strchr (p, '/'); + if (component_end != 0) + *component_end = '\0'; + next = lookup_child_aino (unit, curr, p, err); + if (next == 0) { + /* if only last component not found, return parent dir. */ + if (*err != ERROR_OBJECT_NOT_AROUND || component_end != 0) + curr = 0; + /* ? what error is appropriate? */ + break; + } + curr = next; + if (component_end) + p = component_end+1; + else + break; + + } + } + xfree (tmp); + return curr; +} + +static uae_u32 startup_handler (void) +{ + /* Just got the startup packet. It's in A4. DosBase is in A2, + * our allocated volume structure is in D6, A5 is a pointer to + * our port. */ + uaecptr rootnode = get_long (m68k_areg (regs, 2) + 34); + uaecptr dos_info = get_long (rootnode + 24) << 2; + uaecptr pkt = m68k_dreg (regs, 3); + uaecptr arg2 = get_long (pkt + dp_Arg2); + int i, namelen; + char* devname = bstr1 (get_long (pkt + dp_Arg1) << 2); + char* s; + Unit *unit; + UnitInfo *uinfo; + + /* find UnitInfo with correct device name */ + s = strchr (devname, ':'); + if (s) + *s = '\0'; + + for (i = 0; i < current_mountinfo->num_units; i++) { + /* Hardfile volume name? */ + if (current_mountinfo->ui[i].volname == 0) + continue; + + if (current_mountinfo->ui[i].startup == arg2) + break; + } + + if (i == current_mountinfo->num_units + || access (current_mountinfo->ui[i].rootdir, R_OK) != 0) + { + write_log ("Failed attempt to mount device\n", devname); + put_long (pkt + dp_Res1, DOS_FALSE); + put_long (pkt + dp_Res2, ERROR_DEVICE_NOT_MOUNTED); + return 1; + } + uinfo = current_mountinfo->ui + i; + + unit = (Unit *) xcalloc (sizeof (Unit), 1); + unit->next = units; + units = unit; + uinfo->self = unit; + + unit->volume = 0; + unit->port = m68k_areg (regs, 5); + unit->unit = unit_num++; + + unit->ui.devname = uinfo->devname; + unit->ui.volname = my_strdup (uinfo->volname); /* might free later for rename */ + unit->ui.rootdir = uinfo->rootdir; + unit->ui.readonly = uinfo->readonly; + unit->ui.unit_pipe = uinfo->unit_pipe; + unit->ui.back_pipe = uinfo->back_pipe; + unit->cmds_complete = 0; + unit->cmds_sent = 0; + unit->cmds_acked = 0; + for (i = 0; i < EXKEYS; i++) { + unit->examine_keys[i].aino = 0; + unit->examine_keys[i].curr_file = 0; + unit->examine_keys[i].uniq = 0; + } + unit->total_locked_ainos = 0; + unit->next_exkey = 1; + unit->keys = 0; + unit->a_uniq = unit->key_uniq = 0; + + unit->rootnode.aname = uinfo->volname; + unit->rootnode.nname = uinfo->rootdir; + unit->rootnode.sibling = 0; + unit->rootnode.next = unit->rootnode.prev = &unit->rootnode; + unit->rootnode.uniq = 0; + unit->rootnode.parent = 0; + unit->rootnode.child = 0; + unit->rootnode.dir = 1; + unit->rootnode.amigaos_mode = 0; + unit->rootnode.shlock = 0; + unit->rootnode.elock = 0; + unit->rootnode.comment = 0; + unit->rootnode.has_dbentry = 0; + aino_test_init (&unit->rootnode); + unit->aino_cache_size = 0; + for (i = 0; i < MAX_AINO_HASH; i++) + unit->aino_hash[i] = 0; + +/* write_comm_pipe_int (unit->ui.unit_pipe, -1, 1);*/ + + TRACE(("**** STARTUP volume %s\n", unit->ui.volname)); + + /* fill in our process in the device node */ + put_long ((get_long (pkt + dp_Arg3) << 2) + 8, unit->port); + unit->dosbase = m68k_areg (regs, 2); + + /* make new volume */ + unit->volume = m68k_areg (regs, 3) + 32; +#ifdef UAE_FILESYS_THREADS + unit->locklist = m68k_areg (regs, 3) + 8; +#else + unit->locklist = m68k_areg (regs, 3); +#endif + unit->dummy_message = m68k_areg (regs, 3) + 12; + + put_long (unit->dummy_message + 10, 0); + + put_long (unit->volume + 4, 2); /* Type = dt_volume */ + put_long (unit->volume + 12, 0); /* Lock */ + put_long (unit->volume + 16, 3800); /* Creation Date */ + put_long (unit->volume + 20, 0); + put_long (unit->volume + 24, 0); + put_long (unit->volume + 28, 0); /* lock list */ + put_long (unit->volume + 40, (unit->volume + 44) >> 2); /* Name */ + namelen = strlen (unit->ui.volname); + put_byte (unit->volume + 44, namelen); + for (i = 0; i < namelen; i++) + put_byte (unit->volume + 45 + i, unit->ui.volname[i]); + + /* link into DOS list */ + put_long (unit->volume, get_long (dos_info + 4)); + put_long (dos_info + 4, unit->volume >> 2); + + put_long (unit->volume + 8, unit->port); + put_long (unit->volume + 32, DISK_TYPE); + + put_long (pkt + dp_Res1, DOS_TRUE); + + fsdb_clean_dir (&unit->rootnode); + + return 0; +} + +static void +do_info (Unit *unit, dpacket packet, uaecptr info) +{ + struct fs_usage fsu; + + if (get_fs_usage (unit->ui.rootdir, 0, &fsu) != 0) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, dos_errno ()); + return; + } + + fsu.fsu_blocks >>= 1; + fsu.fsu_bavail >>= 1; + put_long (info, 0); /* errors */ + put_long (info + 4, unit->unit); /* unit number */ + put_long (info + 8, unit->ui.readonly ? 80 : 82); /* state */ + put_long (info + 12, fsu.fsu_blocks ); /* numblocks */ + put_long (info + 16, fsu.fsu_blocks - fsu.fsu_bavail); /* inuse */ + put_long (info + 20, 1024); /* bytesperblock */ + put_long (info + 24, DISK_TYPE); /* disk type */ + put_long (info + 28, unit->volume >> 2); /* volume node */ + put_long (info + 32, 0); /* inuse */ + PUT_PCK_RES1 (packet, DOS_TRUE); +} + +static void +action_disk_info (Unit *unit, dpacket packet) +{ + TRACE(("ACTION_DISK_INFO\n")); + do_info(unit, packet, GET_PCK_ARG1 (packet) << 2); +} + +static void +action_info (Unit *unit, dpacket packet) +{ + TRACE(("ACTION_INFO\n")); + do_info(unit, packet, GET_PCK_ARG2 (packet) << 2); +} + +static void free_key (Unit *unit, Key *k) +{ + Key *k1; + Key *prev = 0; + for (k1 = unit->keys; k1; k1 = k1->next) { + if (k == k1) { + if (prev) + prev->next = k->next; + else + unit->keys = k->next; + break; + } + prev = k1; + } + + if (k->fd >= 0) + close (k->fd); + + xfree(k); +} + +static Key *lookup_key (Unit *unit, uae_u32 uniq) +{ + Key *k; + /* It's hardly worthwhile to optimize this - most of the time there are + * only one or zero keys. */ + for (k = unit->keys; k; k = k->next) { + if (uniq == k->uniq) + return k; + } + write_log ("Error: couldn't find key!\n"); +#if 0 + exit(1); + /* NOTREACHED */ +#endif + /* There isn't much hope we will recover. Unix would kill the process, + * AmigaOS gets killed by it. */ + write_log ("Better reset that Amiga - the system is messed up.\n"); + return 0; +} + +static Key *new_key (Unit *unit) +{ + Key *k = (Key *) xmalloc(sizeof(Key)); + k->uniq = ++unit->key_uniq; + k->fd = -1; + k->file_pos = 0; + k->next = unit->keys; + unit->keys = k; + + return k; +} + +static void +dumplock (Unit *unit, uaecptr lock) +{ + a_inode *a; + TRACE(("LOCK: 0x%lx", lock)); + if (!lock) { + TRACE(("\n")); + return; + } + TRACE(("{ next=0x%lx, mode=%ld, handler=0x%lx, volume=0x%lx, aino %lx ", + get_long (lock) << 2, get_long (lock+8), + get_long (lock+12), get_long (lock+16), + get_long (lock + 4))); + a = lookup_aino (unit, get_long (lock + 4)); + if (a == 0) { + TRACE(("not found!")); + } else { + TRACE(("%s", a->nname)); + } + TRACE((" }\n")); +} + +static a_inode *find_aino (Unit *unit, uaecptr lock, const char *name, uae_u32 *err) +{ + a_inode *a; + + if (lock) { + a_inode *olda = lookup_aino (unit, get_long (lock + 4)); + if (olda == 0) { + /* That's the best we can hope to do. */ + a = get_aino (unit, &unit->rootnode, name, err); + } else { + TRACE(("aino: 0x%08lx", (unsigned long int)olda->uniq)); + TRACE((" \"%s\"\n", olda->nname)); + a = get_aino (unit, olda, name, err); + } + } else { + a = get_aino (unit, &unit->rootnode, name, err); + } + if (a) { + TRACE(("aino=\"%s\"\n", a->nname)); + } + aino_test (a); + return a; +} + +static uaecptr make_lock (Unit *unit, uae_u32 uniq, long mode) +{ + /* allocate lock from the list kept by the assembly code */ + uaecptr lock; + + lock = get_long (unit->locklist); + put_long (unit->locklist, get_long (lock)); + lock += 4; + + put_long (lock + 4, uniq); + put_long (lock + 8, mode); + put_long (lock + 12, unit->port); + put_long (lock + 16, unit->volume >> 2); + + /* prepend to lock chain */ + put_long (lock, get_long (unit->volume + 28)); + put_long (unit->volume + 28, lock >> 2); + + DUMPLOCK(unit, lock); + return lock; +} + +static uae_u32 notifyhash (char *s) +{ + uae_u32 hash = 0; + while (*s) hash = (hash << 5) + *s++; + return hash % NOTIFY_HASH_SIZE; +} + +static Notify *new_notify (Unit *unit, char *name) +{ + Notify *n = xmalloc(sizeof(Notify)); + int hash = notifyhash (name); + n->next = unit->notifyhash[hash]; + unit->notifyhash[hash] = n; + n->partname = name; + return n; +} + +static void free_notify (Unit *unit, int hash, Notify *n) +{ + Notify *n1, *prev = 0; + for (n1 = unit->notifyhash[hash]; n1; n1 = n1->next) { + if (n == n1) { + if (prev) + prev->next = n->next; + else + unit->notifyhash[hash] = n->next; + break; + } + prev = n1; + } + xfree(n); +} + +#define NOTIFY_CLASS 0x40000000 +#define NOTIFY_CODE 0x1234 + +#define NRF_SEND_MESSAGE 1 +#define NRF_SEND_SIGNAL 2 +#define NRF_WAIT_REPLY 8 +#define NRF_NOTIFY_INITIAL 16 +#define NRF_MAGIC (1 << 31) + +static void notify_send (Unit *unit, Notify *n) +{ + uaecptr nr = n->notifyrequest; + int flags = get_long (nr + 12); + + if (flags & NRF_SEND_MESSAGE) { + if (!(flags & NRF_WAIT_REPLY) || ((flags & NRF_WAIT_REPLY) && !(flags & NRF_MAGIC))) { + uae_NotificationHack (unit->port, nr); + } else if (flags & NRF_WAIT_REPLY) { + put_long (nr + 12, get_long (nr + 12) | NRF_MAGIC); + } + } else if (flags & NRF_SEND_SIGNAL) { + uae_Signal (get_long (nr + 16), 1 << get_byte (nr + 20)); + } +} + +static void notify_check (Unit *unit, a_inode *a) +{ + Notify *n; + int hash = notifyhash (a->aname); + for (n = unit->notifyhash[hash]; n; n = n->next) { + uaecptr nr = n->notifyrequest; + if (same_aname(n->partname, a->aname)) { + uae_u32 err; + a_inode *a2 = find_aino (unit, 0, n->fullname, &err); + if (err == 0 && a == a2) + notify_send (unit, n); + } + } + if (a->parent) { + hash = notifyhash (a->parent->aname); + for (n = unit->notifyhash[hash]; n; n = n->next) { + uaecptr nr = n->notifyrequest; + if (same_aname(n->partname, a->parent->aname)) { + uae_u32 err; + a_inode *a2 = find_aino (unit, 0, n->fullname, &err); + if (err == 0 && a->parent == a2) + notify_send (unit, n); + } + } + } +} + +static void +action_add_notify (Unit *unit, dpacket packet) +{ + uaecptr nr = GET_PCK_ARG1 (packet); + int flags; + Notify *n; + char *name, *p, *partname; + + TRACE(("ACTION_ADD_NOTIFY\n")); + + name = my_strdup (char1 (get_long (nr + 4))); + flags = get_long (nr + 12); + +#if 0 + write_log ("Notify:\n"); + write_log ("nr_Name '%s'\n", char1 (get_long (nr + 0))); + write_log ("nr_FullName '%s'\n", name); + write_log ("nr_UserData %08.8X\n", get_long (nr + 8)); + write_log ("nr_Flags %08.8X\n", flags); + if (flags & NRF_SEND_MESSAGE) { + write_log ("Message NotifyRequest, port = %08.8X\n", get_long (nr + 16)); + } else if (flags & NRF_SEND_SIGNAL) { + write_log ("Signal NotifyRequest, Task = %08.8X signal = %d\n", get_long (nr + 16), get_long (nr + 20)); + } else { + write_log ("corrupt NotifyRequest\n"); + } +#endif + + p = name + strlen (name) - 1; + if (p[0] == ':') p--; + while (p > name && p[0] != ':' && p[0] != '/') p--; + if (p[0] == ':' || p[0] == '/') p++; + partname = my_strdup (p); + n = new_notify (unit, partname); + n->notifyrequest = nr; + n->fullname = name; + if (flags & NRF_NOTIFY_INITIAL) { + uae_u32 err; + a_inode *a = find_aino (unit, 0, n->fullname, &err); + if (err == 0) + notify_send (unit, n); + } + PUT_PCK_RES1 (packet, DOS_TRUE); +} +static void +action_remove_notify (Unit *unit, dpacket packet) +{ + uaecptr nr = GET_PCK_ARG1 (packet); + Notify *n; + int hash; + + TRACE(("ACTION_REMOVE_NOTIFY\n")); + for (hash = 0; hash < NOTIFY_HASH_SIZE; hash++) { + for (n = unit->notifyhash[hash]; n; n = n->next) { + if (n->notifyrequest == nr) { + //write_log ("NotifyRequest %08.8X freed\n", n->notifyrequest); + xfree (n->fullname); + xfree (n->partname); + free_notify (unit, hash, n); + PUT_PCK_RES1 (packet, DOS_TRUE); + return; + } + } + } + //write_log ("Tried to free non-existing NotifyRequest %08.8X\n", nr); + PUT_PCK_RES1 (packet, DOS_TRUE); +} + +static void free_lock (Unit *unit, uaecptr lock) +{ + if (! lock) + return; + + if (lock == get_long (unit->volume + 28) << 2) { + put_long (unit->volume + 28, get_long (lock)); + } else { + uaecptr current = get_long (unit->volume + 28); + uaecptr next = 0; + while (current) { + next = get_long (current << 2); + if (lock == next << 2) + break; + current = next; + } + put_long (current << 2, get_long (lock)); + } + lock -= 4; + put_long (lock, get_long (unit->locklist)); + put_long (unit->locklist, lock); +} + +static void +action_lock (Unit *unit, dpacket packet) +{ + uaecptr lock = GET_PCK_ARG1 (packet) << 2; + uaecptr name = GET_PCK_ARG2 (packet) << 2; + long mode = GET_PCK_ARG3 (packet); + a_inode *a; + uae_u32 err; + + if (mode != SHARED_LOCK && mode != EXCLUSIVE_LOCK) { + TRACE(("Bad mode.\n")); + mode = SHARED_LOCK; + } + + TRACE(("ACTION_LOCK(0x%lx, \"%s\", %d)\n", lock, bstr (unit, name), mode)); + DUMPLOCK(unit, lock); + + a = find_aino (unit, lock, bstr (unit, name), &err); + if (err == 0 && (a->elock || (mode != SHARED_LOCK && a->shlock > 0))) { + err = ERROR_OBJECT_IN_USE; + } + /* Lock() doesn't do access checks. */ + if (err != 0) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, err); + return; + } + if (mode == SHARED_LOCK) + a->shlock++; + else + a->elock = 1; + de_recycle_aino (unit, a); + PUT_PCK_RES1 (packet, make_lock (unit, a->uniq, mode) >> 2); +} + +static void action_free_lock (Unit *unit, dpacket packet) +{ + uaecptr lock = GET_PCK_ARG1 (packet) << 2; + a_inode *a; + TRACE(("ACTION_FREE_LOCK(0x%lx)\n", lock)); + DUMPLOCK(unit, lock); + + a = lookup_aino (unit, get_long (lock + 4)); + if (a == 0) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND); + return; + } + if (a->elock) + a->elock = 0; + else + a->shlock--; + recycle_aino (unit, a); + free_lock(unit, lock); + + PUT_PCK_RES1 (packet, DOS_TRUE); +} + +static void +action_dup_lock (Unit *unit, dpacket packet) +{ + uaecptr lock = GET_PCK_ARG1 (packet) << 2; + a_inode *a; + TRACE(("ACTION_DUP_LOCK(0x%lx)\n", lock)); + DUMPLOCK(unit, lock); + + if (!lock) { + PUT_PCK_RES1 (packet, 0); + return; + } + a = lookup_aino (unit, get_long (lock + 4)); + if (a == 0) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND); + return; + } + /* DupLock()ing exclusive locks isn't possible, says the Autodoc, but + * at least the RAM-Handler seems to allow it. Let's see what happens + * if we don't. */ + if (a->elock) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE); + return; + } + a->shlock++; + de_recycle_aino (unit, a); + PUT_PCK_RES1 (packet, make_lock (unit, a->uniq, -2) >> 2); +} + +/* convert time_t to/from AmigaDOS time */ +const int secs_per_day = 24 * 60 * 60; +const int diff = (8 * 365 + 2) * (24 * 60 * 60); + +static void +get_time (time_t t, long* days, long* mins, long* ticks) +{ + /* time_t is secs since 1-1-1970 */ + /* days since 1-1-1978 */ + /* mins since midnight */ + /* ticks past minute @ 50Hz */ + + t -= diff; + *days = t / secs_per_day; + t -= *days * secs_per_day; + *mins = t / 60; + t -= *mins * 60; + *ticks = t * 50; +} + +static time_t +put_time (long days, long mins, long ticks) +{ + time_t t; + t = ticks / 50; + t += mins * 60; + t += days * secs_per_day; + t += diff; + + return t; +} + +static void free_exkey (Unit *unit, ExamineKey *ek) +{ + if (--ek->aino->exnext_count == 0) { + TRACE (("Freeing ExKey and reducing total_locked from %d by %d\n", + unit->total_locked_ainos, ek->aino->locked_children)); + unit->total_locked_ainos -= ek->aino->locked_children; + ek->aino->locked_children = 0; + } + ek->aino = 0; + ek->uniq = 0; +} + +static ExamineKey *lookup_exkey (Unit *unit, uae_u32 uniq) +{ + ExamineKey *ek; + int i; + + ek = unit->examine_keys; + for (i = 0; i < EXKEYS; i++, ek++) { + /* Did we find a free one? */ + if (ek->uniq == uniq) + return ek; + } + write_log ("Houston, we have a BIG problem.\n"); + return 0; +} + +/* This is so sick... who invented ACTION_EXAMINE_NEXT? What did he THINK??? */ +static ExamineKey *new_exkey (Unit *unit, a_inode *aino) +{ + uae_u32 uniq; + uae_u32 oldest = 0xFFFFFFFE; + ExamineKey *ek, *oldest_ek = 0; + int i; + + ek = unit->examine_keys; + for (i = 0; i < EXKEYS; i++, ek++) { + /* Did we find a free one? */ + if (ek->aino == 0) + continue; + if (ek->uniq < oldest) + oldest = (oldest_ek = ek)->uniq; + } + ek = unit->examine_keys; + for (i = 0; i < EXKEYS; i++, ek++) { + /* Did we find a free one? */ + if (ek->aino == 0) + goto found; + } + /* This message should usually be harmless. */ + write_log ("Houston, we have a problem (%s).\n", aino->nname); + free_exkey (unit, oldest_ek); + ek = oldest_ek; + found: + + uniq = unit->next_exkey; + if (uniq >= 0xFFFFFFFE) { + /* Things will probably go wrong, but most likely the Amiga will crash + * before this happens because of something else. */ + uniq = 1; + } + unit->next_exkey = uniq+1; + ek->aino = aino; + ek->curr_file = 0; + ek->uniq = uniq; + return ek; +} + +static void move_exkeys (Unit *unit, a_inode *from, a_inode *to) +{ + int i; + unsigned long tmp = 0; + for (i = 0; i < EXKEYS; i++) { + ExamineKey *k = unit->examine_keys + i; + if (k->uniq == 0) + continue; + if (k->aino == from) { + k->aino = to; + tmp++; + } + } + if (tmp != from->exnext_count) + write_log ("filesys.c: Bug in ExNext bookkeeping. BAD.\n"); + to->exnext_count = from->exnext_count; + to->locked_children = from->locked_children; + from->exnext_count = 0; + from->locked_children = 0; +} + +static void +get_fileinfo (Unit *unit, dpacket packet, uaecptr info, a_inode *aino) +{ + struct stat statbuf; + long days, mins, ticks; + int i, n; + char *x; + + /* No error checks - this had better work. */ + stat (aino->nname, &statbuf); + + if (aino->parent == 0) { + x = unit->ui.volname; + put_long (info + 4, 1); + put_long (info + 120, 1); + } else { + /* AmigaOS docs say these have to contain the same value. */ + put_long (info + 4, aino->dir ? 2 : -3); + put_long (info + 120, aino->dir ? 2 : -3); + x = aino->aname; + } + TRACE(("name=\"%s\"\n", x)); + n = strlen (x); + if (n > 106) + n = 106; + i = 8; + put_byte (info + i, n); i++; + while (n--) + put_byte (info + i, *x), i++, x++; + while (i < 108) + put_byte (info + i, 0), i++; + + put_long (info + 116, aino->amigaos_mode); + put_long (info + 124, statbuf.st_size); +#ifdef HAVE_ST_BLOCKS + put_long (info + 128, statbuf.st_blocks); +#else + put_long (info + 128, statbuf.st_size / 512 + 1); +#endif + get_time (statbuf.st_mtime, &days, &mins, &ticks); + put_long (info + 132, days); + put_long (info + 136, mins); + put_long (info + 140, ticks); + if (aino->comment == 0) + put_long (info + 144, 0); + else { + TRACE(("comment=\"%s\"\n", aino->comment)); + i = 144; + x = aino->comment; + if (! x) + x = ""; + n = strlen (x); + if (n > 78) + n = 78; + put_byte (info + i, n); i++; + while (n--) + put_byte (info + i, *x), i++, x++; + while (i < 224) + put_byte (info + i, 0), i++; + } + PUT_PCK_RES1 (packet, DOS_TRUE); +} + +static void action_examine_object (Unit *unit, dpacket packet) +{ + uaecptr lock = GET_PCK_ARG1 (packet) << 2; + uaecptr info = GET_PCK_ARG2 (packet) << 2; + a_inode *aino = 0; + + TRACE(("ACTION_EXAMINE_OBJECT(0x%lx,0x%lx)\n", lock, info)); + DUMPLOCK(unit, lock); + + if (lock != 0) + aino = lookup_aino (unit, get_long (lock + 4)); + if (aino == 0) + aino = &unit->rootnode; + + get_fileinfo (unit, packet, info, aino); + if (aino->dir) { + put_long (info, 0xFFFFFFFF); + } else + put_long (info, 0); +} + +/* Read a directory's contents, create a_inodes for each file, and + mark them as locked in memory so that recycle_aino will not reap + them. + We do this to avoid problems with the host OS: we don't want to + leave the directory open on the host side until all ExNext()s have + finished - they may never finish! */ + +static void populate_directory (Unit *unit, a_inode *base) +{ + DIR *d = opendir (base->nname); + a_inode *aino; + + if (!d) + return; + for (aino = base->child; aino; aino = aino->sibling) { + base->locked_children++; + unit->total_locked_ainos++; + } + TRACE(("Populating directory, child %p, locked_children %d\n", + base->child, base->locked_children)); + for (;;) { + struct dirent *de; + uae_u32 err; + + /* Find next file that belongs to the Amiga fs (skipping things + like "..", "." etc. */ + do { + de = my_readdir (d, &de_space); + } while (de && fsdb_name_invalid (de->d_name)); + if (! de) + break; + /* This calls init_child_aino, which will notice that the parent is + being ExNext()ed, and it will increment the locked counts. */ + aino = lookup_child_aino_for_exnext (unit, base, de->d_name, &err); + } + closedir (d); +} + +static void do_examine (Unit *unit, dpacket packet, ExamineKey *ek, uaecptr info) +{ + if (ek->curr_file == 0) + goto no_more_entries; + + get_fileinfo (unit, packet, info, ek->curr_file); + ek->curr_file = ek->curr_file->sibling; + TRACE (("curr_file set to %p %s\n", ek->curr_file, + ek->curr_file ? ek->curr_file->aname : "NULL")); + return; + + no_more_entries: + TRACE(("no more entries\n")); + free_exkey (unit, ek); + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES); +} + +static void action_examine_next (Unit *unit, dpacket packet) +{ + uaecptr lock = GET_PCK_ARG1 (packet) << 2; + uaecptr info = GET_PCK_ARG2 (packet) << 2; + a_inode *aino = 0; + ExamineKey *ek; + uae_u32 uniq; + + TRACE(("ACTION_EXAMINE_NEXT(0x%lx,0x%lx)\n", lock, info)); + DUMPLOCK(unit, lock); + + if (lock != 0) + aino = lookup_aino (unit, get_long (lock + 4)); + if (aino == 0) + aino = &unit->rootnode; + + uniq = get_long (info); + if (uniq == 0) { + write_log ("ExNext called for a file! (Houston?)\n"); + goto no_more_entries; + } else if (uniq == 0xFFFFFFFE) + goto no_more_entries; + else if (uniq == 0xFFFFFFFF) { + TRACE(("Creating new ExKey\n")); + ek = new_exkey (unit, aino); + if (ek) { + if (aino->exnext_count++ == 0) + populate_directory (unit, aino); + } + ek->curr_file = aino->child; + TRACE(("Initial curr_file: %p %s\n", ek->curr_file, + ek->curr_file ? ek->curr_file->aname : "NULL")); + } else { + TRACE(("Looking up ExKey\n")); + ek = lookup_exkey (unit, get_long (info)); + } + if (ek == 0) { + write_log ("Couldn't find a matching ExKey. Prepare for trouble.\n"); + goto no_more_entries; + } + put_long (info, ek->uniq); + do_examine (unit, packet, ek, info); + return; + + no_more_entries: + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES); +} + +static void do_find (Unit *unit, dpacket packet, int mode, int create, int fallback) +{ + uaecptr fh = GET_PCK_ARG1 (packet) << 2; + uaecptr lock = GET_PCK_ARG2 (packet) << 2; + uaecptr name = GET_PCK_ARG3 (packet) << 2; + a_inode *aino; + Key *k; + int fd; + uae_u32 err; + mode_t openmode; + int aino_created = 0; + + TRACE(("ACTION_FIND_*(0x%lx,0x%lx,\"%s\",%d,%d)\n", fh, lock, bstr (unit, name), mode, create)); + DUMPLOCK(unit, lock); + + aino = find_aino (unit, lock, bstr (unit, name), &err); + + if (aino == 0 || (err != 0 && err != ERROR_OBJECT_NOT_AROUND)) { + /* Whatever it is, we can't handle it. */ + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, err); + return; + } + if (err == 0) { + /* Object exists. */ + if (aino->dir) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_OBJECT_WRONG_TYPE); + return; + } + if (aino->elock || (create == 2 && aino->shlock > 0)) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE); + return; + } + if (create == 2 && (aino->amigaos_mode & A_FIBF_DELETE) != 0) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_DELETE_PROTECTED); + return; + } + if (create != 2) { + if ((((mode & aino->amigaos_mode) & A_FIBF_WRITE) != 0 || unit->ui.readonly) + && fallback) + { + mode &= ~A_FIBF_WRITE; + } + /* Kick 1.3 doesn't check read and write access bits - maybe it would be + * simpler just not to do that either. */ + if ((mode & A_FIBF_WRITE) != 0 && unit->ui.readonly) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED); + return; + } + if (((mode & aino->amigaos_mode) & A_FIBF_WRITE) != 0 + || mode == 0) + { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_WRITE_PROTECTED); + return; + } + if (((mode & aino->amigaos_mode) & A_FIBF_READ) != 0) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_READ_PROTECTED); + return; + } + } + } else if (create == 0) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, err); + return; + } else { + /* Object does not exist. aino points to containing directory. */ + aino = create_child_aino (unit, aino, my_strdup (bstr_cut (unit, name)), 0); + if (aino == 0) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_DISK_IS_FULL); /* best we can do */ + return; + } + aino_created = 1; + } + + prepare_for_open (aino->nname); + + openmode = (((mode & A_FIBF_READ) == 0 ? O_WRONLY + : (mode & A_FIBF_WRITE) == 0 ? O_RDONLY + : O_RDWR) + | (create ? O_CREAT : 0) + | (create == 2 ? O_TRUNC : 0)); + + fd = open (aino->nname, openmode | O_BINARY, 0777); + + if (fd < 0) { + if (aino_created) + delete_aino (unit, aino); + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, dos_errno ()); + return; + } + k = new_key (unit); + k->fd = fd; + k->aino = aino; + k->dosmode = mode; + k->createmode = create; + k->notifyactive = create ? 1 : 0; + + put_long (fh+36, k->uniq); + if (create == 2) + aino->elock = 1; + else + aino->shlock++; + de_recycle_aino (unit, aino); + PUT_PCK_RES1 (packet, DOS_TRUE); +} + +static void +action_fh_from_lock (Unit *unit, dpacket packet) +{ + uaecptr fh = GET_PCK_ARG1 (packet) << 2; + uaecptr lock = GET_PCK_ARG2 (packet) << 2; + a_inode *aino; + Key *k; + int fd; + mode_t openmode; + int mode; + + TRACE(("ACTION_FH_FROM_LOCK(0x%lx,0x%lx)\n",fh,lock)); + DUMPLOCK(unit,lock); + + if (!lock) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, 0); + return; + } + + aino = lookup_aino (unit, get_long (lock + 4)); + if (aino == 0) + aino = &unit->rootnode; + mode = aino->amigaos_mode; /* Use same mode for opened filehandle as existing Lock() */ + + prepare_for_open (aino->nname); + + TRACE ((" mode is %d\n", mode)); + openmode = (((mode & A_FIBF_READ) ? O_WRONLY + : (mode & A_FIBF_WRITE) ? O_RDONLY + : O_RDWR)); + + /* the files on CD really can have the write-bit set. */ + if (unit->ui.readonly) + openmode = O_RDONLY; + + fd = open (aino->nname, openmode | O_BINARY, 0777); + + if (fd < 0) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, dos_errno()); + return; + } + k = new_key (unit); + k->fd = fd; + k->aino = aino; + + put_long (fh+36, k->uniq); + /* I don't think I need to play with shlock count here, because I'm + opening from an existing lock ??? */ + + /* Is this right? I don't completely understand how this works. Do I + also need to free_lock() my lock, since nobody else is going to? */ + de_recycle_aino (unit, aino); + PUT_PCK_RES1 (packet, DOS_TRUE); + /* PUT_PCK_RES2 (packet, k->uniq); - this shouldn't be necessary, try without it */ +} + +static void +action_find_input (Unit *unit, dpacket packet) +{ + do_find(unit, packet, A_FIBF_READ|A_FIBF_WRITE, 0, 1); +} + +static void +action_find_output (Unit *unit, dpacket packet) +{ + if (unit->ui.readonly) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED); + return; + } + do_find(unit, packet, A_FIBF_READ|A_FIBF_WRITE, 2, 0); +} + +static void +action_find_write (Unit *unit, dpacket packet) +{ + if (unit->ui.readonly) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED); + return; + } + do_find(unit, packet, A_FIBF_READ|A_FIBF_WRITE, 1, 0); +} + +/* change file/dir's parent dir modification time */ +static void updatedirtime (a_inode *a1, int now) +{ + struct stat statbuf; + struct utimbuf ut; + long days, mins, ticks; + + if (!a1->parent) + return; + if (!now) { + if (stat (a1->nname, &statbuf) == -1) + return; + get_time (statbuf.st_mtime, &days, &mins, &ticks); + ut.actime = ut.modtime = put_time(days, mins, ticks); + utime (a1->parent->nname, &ut); + } else { + utime (a1->parent->nname, NULL); + } +} + +static void +action_end (Unit *unit, dpacket packet) +{ + Key *k; + TRACE(("ACTION_END(0x%lx)\n", GET_PCK_ARG1 (packet))); + + k = lookup_key (unit, GET_PCK_ARG1 (packet)); + if (k != 0) { + if (k->notifyactive) { + notify_check (unit, k->aino); + updatedirtime (k->aino, 1); + } + if (k->aino->elock) + k->aino->elock = 0; + else + k->aino->shlock--; + recycle_aino (unit, k->aino); + free_key (unit, k); + } + PUT_PCK_RES1 (packet, DOS_TRUE); + PUT_PCK_RES2 (packet, 0); +} + +static void +action_read (Unit *unit, dpacket packet) +{ + Key *k = lookup_key (unit, GET_PCK_ARG1 (packet)); + uaecptr addr = GET_PCK_ARG2 (packet); + long size = (uae_s32)GET_PCK_ARG3 (packet); + int actual; + + if (k == 0) { + PUT_PCK_RES1 (packet, DOS_FALSE); + /* PUT_PCK_RES2 (packet, EINVAL); */ + return; + } + TRACE(("ACTION_READ(%s,0x%lx,%ld)\n",k->aino->nname,addr,size)); + gui_hd_led (1); +#ifdef RELY_ON_LOADSEG_DETECTION + /* HACK HACK HACK HACK + * Try to detect a LoadSeg() */ + if (k->file_pos == 0 && size >= 4) { + unsigned char buf[4]; + off_t currpos = lseek(k->fd, 0, SEEK_CUR); + read(k->fd, buf, 4); + lseek(k->fd, currpos, SEEK_SET); + if (buf[0] == 0 && buf[1] == 0 && buf[2] == 3 && buf[3] == 0xF3) + possible_loadseg(); + } +#endif + if (valid_address (addr, size)) { + uae_u8 *realpt; + realpt = get_real_address (addr); + actual = read(k->fd, realpt, size); + + if (actual == 0) { + PUT_PCK_RES1 (packet, 0); + PUT_PCK_RES2 (packet, 0); + } else if (actual < 0) { + PUT_PCK_RES1 (packet, 0); + PUT_PCK_RES2 (packet, dos_errno()); + } else { + PUT_PCK_RES1 (packet, actual); + k->file_pos += actual; + } + } else { + char *buf; + unsigned long old, filesize; + + write_log ("unixfs warning: Bad pointer passed for read: %08x, size %d\n", addr, size); + /* ugh this is inefficient but easy */ + + old = lseek (k->fd, 0, SEEK_CUR); + filesize = lseek (k->fd, 0, SEEK_END); + lseek (k->fd, old, SEEK_SET); + if (size > filesize) + size = filesize; + + buf = (char *)malloc(size); + if (!buf) { + PUT_PCK_RES1 (packet, -1); + PUT_PCK_RES2 (packet, ERROR_NO_FREE_STORE); + return; + } + actual = read(k->fd, buf, size); + + if (actual < 0) { + PUT_PCK_RES1 (packet, 0); + PUT_PCK_RES2 (packet, dos_errno()); + } else { + int i; + PUT_PCK_RES1 (packet, actual); + for (i = 0; i < actual; i++) + put_byte(addr + i, buf[i]); + k->file_pos += actual; + } + xfree (buf); + } +} + +static void +action_write (Unit *unit, dpacket packet) +{ + Key *k = lookup_key (unit, GET_PCK_ARG1 (packet)); + uaecptr addr = GET_PCK_ARG2 (packet); + long size = GET_PCK_ARG3 (packet); + char *buf; + int i; + + if (k == 0) { + PUT_PCK_RES1 (packet, DOS_FALSE); + /* PUT_PCK_RES2 (packet, EINVAL); */ + return; + } + + gui_hd_led (1); + TRACE(("ACTION_WRITE(%s,0x%lx,%ld)\n",k->aino->nname,addr,size)); + + if (unit->ui.readonly) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED); + return; + } + + /* ugh this is inefficient but easy */ + buf = (char *)malloc(size); + if (!buf) { + PUT_PCK_RES1 (packet, -1); + PUT_PCK_RES2 (packet, ERROR_NO_FREE_STORE); + return; + } + + for (i = 0; i < size; i++) + buf[i] = get_byte(addr + i); + + PUT_PCK_RES1 (packet, write(k->fd, buf, size)); + if (GET_PCK_RES1 (packet) != size) + PUT_PCK_RES2 (packet, dos_errno ()); + if (GET_PCK_RES1 (packet) >= 0) + k->file_pos += GET_PCK_RES1 (packet); + + k->notifyactive = 1; + xfree (buf); +} + +static void +action_seek (Unit *unit, dpacket packet) +{ + Key *k = lookup_key (unit, GET_PCK_ARG1 (packet)); + long pos = (uae_s32)GET_PCK_ARG2 (packet); + long mode = (uae_s32)GET_PCK_ARG3 (packet); + off_t res; + long old; + int whence = SEEK_CUR; + + if (k == 0) { + PUT_PCK_RES1 (packet, -1); + PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK); + return; + } + + if (mode > 0) whence = SEEK_END; + if (mode < 0) whence = SEEK_SET; + + TRACE(("ACTION_SEEK(%s,%d,%d)\n", k->aino->nname, pos, mode)); + + old = lseek (k->fd, 0, SEEK_CUR); + { + uae_s32 temppos; + long filesize = lseek (k->fd, 0, SEEK_END); + lseek (k->fd, old, SEEK_SET); + + if (whence == SEEK_CUR) temppos = old + pos; + if (whence == SEEK_SET) temppos = pos; + if (whence == SEEK_END) temppos = filesize + pos; + if (filesize < temppos) { + res = -1; + PUT_PCK_RES1 (packet,res); + PUT_PCK_RES2 (packet, ERROR_SEEK_ERROR); + return; + } + } + res = lseek (k->fd, pos, whence); + + if (-1 == res) { + PUT_PCK_RES1 (packet, res); + PUT_PCK_RES2 (packet, ERROR_SEEK_ERROR); + } else + PUT_PCK_RES1 (packet, old); + k->file_pos = res; +} + +static void +action_set_protect (Unit *unit, dpacket packet) +{ + uaecptr lock = GET_PCK_ARG2 (packet) << 2; + uaecptr name = GET_PCK_ARG3 (packet) << 2; + uae_u32 mask = GET_PCK_ARG4 (packet); + a_inode *a; + uae_u32 err; + + TRACE(("ACTION_SET_PROTECT(0x%lx,\"%s\",0x%lx)\n", lock, bstr (unit, name), mask)); + + if (unit->ui.readonly) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED); + return; + } + + a = find_aino (unit, lock, bstr (unit, name), &err); + if (err != 0) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, err); + return; + } + + err = fsdb_set_file_attrs (a, mask); + if (err != 0) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, err); + } else { + PUT_PCK_RES1 (packet, DOS_TRUE); + } + notify_check (unit, a); +} + +static void action_set_comment (Unit * unit, dpacket packet) +{ + uaecptr lock = GET_PCK_ARG2 (packet) << 2; + uaecptr name = GET_PCK_ARG3 (packet) << 2; + uaecptr comment = GET_PCK_ARG4 (packet) << 2; + char *commented; + a_inode *a; + uae_u32 err; + + if (unit->ui.readonly) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED); + return; + } + + commented = bstr (unit, comment); + commented = strlen (commented) > 0 ? my_strdup (commented) : 0; + TRACE (("ACTION_SET_COMMENT(0x%lx,\"%s\")\n", lock, commented)); + + a = find_aino (unit, lock, bstr (unit, name), &err); + if (err != 0) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, err); + + maybe_free_and_out: + if (commented) + xfree (commented); + return; + } + PUT_PCK_RES1 (packet, DOS_TRUE); + PUT_PCK_RES2 (packet, 0); + if (a->comment == 0 && commented == 0) + goto maybe_free_and_out; + if (a->comment != 0 && commented != 0 && strcmp (a->comment, commented) == 0) + goto maybe_free_and_out; + if (a->comment) + xfree (a->comment); + a->comment = commented; + a->dirty = 1; + notify_check (unit, a); +} + +static void +action_same_lock (Unit *unit, dpacket packet) +{ + uaecptr lock1 = GET_PCK_ARG1 (packet) << 2; + uaecptr lock2 = GET_PCK_ARG2 (packet) << 2; + + TRACE(("ACTION_SAME_LOCK(0x%lx,0x%lx)\n",lock1,lock2)); + DUMPLOCK(unit, lock1); DUMPLOCK(unit, lock2); + + if (!lock1 || !lock2) { + PUT_PCK_RES1 (packet, lock1 == lock2 ? DOS_TRUE : DOS_FALSE); + } else { + PUT_PCK_RES1 (packet, get_long (lock1 + 4) == get_long (lock2 + 4) ? DOS_TRUE : DOS_FALSE); + } +} + +static void +action_change_mode (Unit *unit, dpacket packet) +{ +#define CHANGE_LOCK 0 +#define CHANGE_FH 1 + /* will be CHANGE_FH or CHANGE_LOCK value */ + long type = GET_PCK_ARG1 (packet); + /* either a file-handle or lock */ + uaecptr object = GET_PCK_ARG2 (packet) << 2; + /* will be EXCLUSIVE_LOCK/SHARED_LOCK if CHANGE_LOCK, + * or MODE_OLDFILE/MODE_NEWFILE/MODE_READWRITE if CHANGE_FH */ + long mode = GET_PCK_ARG3 (packet); + unsigned long uniq; + a_inode *a = NULL, *olda = NULL; + uae_u32 err = 0; + TRACE(("ACTION_CHANGE_MODE(0x%lx,%d,%d)\n",object,type,mode)); + + if (! object + || (type != CHANGE_FH && type != CHANGE_LOCK)) + { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK); + return; + } + + /* @@@ Brian: shouldn't this be good enough to support + CHANGE_FH? */ + if (type == CHANGE_FH) + mode = (mode == 1006 ? -1 : -2); + + if (type == CHANGE_LOCK) + uniq = get_long (object + 4); + else { + Key *k = lookup_key (unit, object); + if (!k) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND); + return; + } + uniq = k->aino->uniq; + } + a = lookup_aino (unit, uniq); + + if (! a) + err = ERROR_INVALID_LOCK; + else { + if (mode == -1) { + if (a->shlock > 1) + err = ERROR_OBJECT_IN_USE; + else { + a->shlock = 0; + a->elock = 1; + } + } else { /* Must be SHARED_LOCK == -2 */ + a->elock = 0; + a->shlock++; + } + } + + if (err) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, err); + return; + } else { + de_recycle_aino (unit, a); + PUT_PCK_RES1 (packet, DOS_TRUE); + } +} + +static void +action_parent_common (Unit *unit, dpacket packet, unsigned long uniq) +{ + a_inode *olda = lookup_aino (unit, uniq); + if (olda == 0) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK); + return; + } + + if (olda->parent == 0) { + PUT_PCK_RES1 (packet, 0); + PUT_PCK_RES2 (packet, 0); + return; + } + if (olda->parent->elock) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE); + return; + } + olda->parent->shlock++; + de_recycle_aino (unit, olda->parent); + PUT_PCK_RES1 (packet, make_lock (unit, olda->parent->uniq, -2) >> 2); +} + +static void +action_parent_fh (Unit *unit, dpacket packet) +{ + Key *k = lookup_key (unit, GET_PCK_ARG1 (packet)); + if (!k) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND); + return; + } + action_parent_common (unit, packet, k->aino->uniq); +} + +static void +action_parent (Unit *unit, dpacket packet) +{ + uaecptr lock = GET_PCK_ARG1 (packet) << 2; + + TRACE(("ACTION_PARENT(0x%lx)\n",lock)); + + if (!lock) { + PUT_PCK_RES1 (packet, 0); + PUT_PCK_RES2 (packet, 0); + return; + } + action_parent_common (unit, packet, get_long (lock + 4)); +} + +static void +action_create_dir (Unit *unit, dpacket packet) +{ + uaecptr lock = GET_PCK_ARG1 (packet) << 2; + uaecptr name = GET_PCK_ARG2 (packet) << 2; + a_inode *aino; + uae_u32 err; + + TRACE(("ACTION_CREATE_DIR(0x%lx,\"%s\")\n", lock, bstr (unit, name))); + + if (unit->ui.readonly) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED); + return; + } + + aino = find_aino (unit, lock, bstr (unit, name), &err); + if (aino == 0 || (err != 0 && err != ERROR_OBJECT_NOT_AROUND)) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, err); + return; + } + if (err == 0) { + /* Object exists. */ + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_OBJECT_EXISTS); + return; + } + /* Object does not exist. aino points to containing directory. */ + aino = create_child_aino (unit, aino, my_strdup (bstr_cut (unit, name)), 1); + if (aino == 0) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_DISK_IS_FULL); /* best we can do */ + return; + } + + if (mkdir (aino->nname, 0777) == -1) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, dos_errno()); + return; + } + aino->shlock = 1; + de_recycle_aino (unit, aino); + notify_check (unit, aino); + updatedirtime (aino, 0); + PUT_PCK_RES1 (packet, make_lock (unit, aino->uniq, -2) >> 2); +} + +static void +action_examine_fh (Unit *unit, dpacket packet) +{ + Key *k; + a_inode *aino = 0; + uaecptr info = GET_PCK_ARG2 (packet) << 2; + + TRACE(("ACTION_EXAMINE_FH(0x%lx,0x%lx)\n", + GET_PCK_ARG1 (packet), GET_PCK_ARG2 (packet) )); + + k = lookup_key (unit, GET_PCK_ARG1 (packet)); + if (k != 0) + aino = k->aino; + if (aino == 0) + aino = &unit->rootnode; + + get_fileinfo (unit, packet, info, aino); + if (aino->dir) + put_long (info, 0xFFFFFFFF); + else + put_long (info, 0); +} + +/* For a nice example of just how contradictory documentation can be, see the + * Autodoc for DOS:SetFileSize and the Packets.txt description of this packet... + * This implementation tries to mimic the behaviour of the Kick 3.1 ramdisk + * (which seems to match the Autodoc description). */ +static void +action_set_file_size (Unit *unit, dpacket packet) +{ + Key *k, *k1; + off_t offset = GET_PCK_ARG2 (packet); + long mode = (uae_s32)GET_PCK_ARG3 (packet); + int whence = SEEK_CUR; + + if (mode > 0) whence = SEEK_END; + if (mode < 0) whence = SEEK_SET; + + TRACE(("ACTION_SET_FILE_SIZE(0x%lx, %d, 0x%x)\n", GET_PCK_ARG1 (packet), offset, mode)); + + k = lookup_key (unit, GET_PCK_ARG1 (packet)); + if (k == 0) { + PUT_PCK_RES1 (packet, DOS_TRUE); + PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND); + return; + } + + k->notifyactive = 1; + /* If any open files have file pointers beyond this size, truncate only + * so far that these pointers do not become invalid. */ + for (k1 = unit->keys; k1; k1 = k1->next) { + if (k != k1 && k->aino == k1->aino) { + if (k1->file_pos > offset) + offset = k1->file_pos; + } + } + + /* Write one then truncate: that should give the right size in all cases. */ + offset = lseek (k->fd, offset, whence); + write (k->fd, /* whatever */(char *)&k1, 1); + if (k->file_pos > offset) + k->file_pos = offset; + lseek (k->fd, k->file_pos, SEEK_SET); + + /* Brian: no bug here; the file _must_ be one byte too large after writing + The write is supposed to guarantee that the file can't be smaller than + the requested size, the truncate guarantees that it can't be larger. + If we were to write one byte earlier we'd clobber file data. */ + if (truncate (k->aino->nname, offset) == -1) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, dos_errno ()); + return; + } + + PUT_PCK_RES1 (packet, offset); + PUT_PCK_RES2 (packet, 0); +} + +static void +action_delete_object (Unit *unit, dpacket packet) +{ + uaecptr lock = GET_PCK_ARG1 (packet) << 2; + uaecptr name = GET_PCK_ARG2 (packet) << 2; + a_inode *a; + uae_u32 err; + + TRACE(("ACTION_DELETE_OBJECT(0x%lx,\"%s\")\n", lock, bstr (unit, name))); + + if (unit->ui.readonly) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED); + return; + } + + a = find_aino (unit, lock, bstr (unit, name), &err); + + if (err != 0) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, err); + return; + } + if (a->amigaos_mode & A_FIBF_DELETE) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_DELETE_PROTECTED); + return; + } + if (a->shlock > 0 || a->elock) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE); + return; + } + if (a->dir) { + /* This should take care of removing the fsdb if no files remain. */ + fsdb_dir_writeback (a); + if (rmdir (a->nname) == -1) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, dos_errno()); + return; + } + } else { + if (unlink (a->nname) == -1) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, dos_errno()); + return; + } + } + notify_check (unit, a); + updatedirtime (a, 1); + if (a->child != 0) { + write_log ("Serious error in action_delete_object.\n"); + } else { + delete_aino (unit, a); + } + PUT_PCK_RES1 (packet, DOS_TRUE); +} + +static void +action_set_date (Unit *unit, dpacket packet) +{ + uaecptr lock = GET_PCK_ARG2 (packet) << 2; + uaecptr name = GET_PCK_ARG3 (packet) << 2; + uaecptr date = GET_PCK_ARG4 (packet); + a_inode *a; + struct utimbuf ut; + uae_u32 err; + + TRACE(("ACTION_SET_DATE(0x%lx,\"%s\")\n", lock, bstr (unit, name))); + + if (unit->ui.readonly) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED); + return; + } + + ut.actime = ut.modtime = put_time(get_long (date), get_long (date + 4), + get_long (date + 8)); + a = find_aino (unit, lock, bstr (unit, name), &err); + if (err == 0 && utime (a->nname, &ut) == -1) + err = dos_errno (); + if (err != 0) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, err); + } else + PUT_PCK_RES1 (packet, DOS_TRUE); + notify_check (unit, a); +} + +static void +action_rename_object (Unit *unit, dpacket packet) +{ + uaecptr lock1 = GET_PCK_ARG1 (packet) << 2; + uaecptr name1 = GET_PCK_ARG2 (packet) << 2; + uaecptr lock2 = GET_PCK_ARG3 (packet) << 2; + uaecptr name2 = GET_PCK_ARG4 (packet) << 2; + a_inode *a1, *a2; + uae_u32 err1, err2; + Key *k1, *knext; + int wehavekeys = 0; + + TRACE(("ACTION_RENAME_OBJECT(0x%lx,\"%s\",", lock1, bstr (unit, name1))); + TRACE(("0x%lx,\"%s\")\n", lock2, bstr (unit, name2))); + + if (unit->ui.readonly) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED); + return; + } + + a1 = find_aino (unit, lock1, bstr (unit, name1), &err1); + if (err1 != 0) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, err1); + return; + } + + /* rename always fails if file is open for writing */ + for (k1 = unit->keys; k1; k1 = knext) { + knext = k1->next; + if (k1->aino == a1 && k1->fd >= 0 && k1->createmode == 2) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE); + return; + } + } + + /* See whether the other name already exists in the filesystem. */ + a2 = find_aino (unit, lock2, bstr (unit, name2), &err2); + + if (a2 == a1) { + /* Renaming to the same name, but possibly different case. */ + if (strcmp (a1->aname, bstr_cut (unit, name2)) == 0) { + /* Exact match -> do nothing. */ + notify_check (unit, a1); + updatedirtime (a1, 1); + PUT_PCK_RES1 (packet, DOS_TRUE); + return; + } + a2 = a2->parent; + } else if (a2 == 0 || err2 != ERROR_OBJECT_NOT_AROUND) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, err2 == 0 ? ERROR_OBJECT_EXISTS : err2); + return; + } + + a2 = create_child_aino (unit, a2, bstr_cut (unit, name2), a1->dir); + if (a2 == 0) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_DISK_IS_FULL); /* best we can do */ + return; + } + + if (-1 == rename (a1->nname, a2->nname)) { + int ret = -1; + /* maybe we have open file handles that caused failure? */ + write_log ("rename '%s' -> '%s' failed, trying relocking..\n", a1->nname, a2->nname); + for (k1 = unit->keys; k1; k1 = knext) { + knext = k1->next; + if (k1->aino == a1 && k1->fd >= 0) { + wehavekeys++; + close (k1->fd); + write_log ("handle %d freed\n", k1->fd); + } + } + /* try again... */ + ret = rename (a1->nname, a2->nname); + for (k1 = unit->keys; k1; k1 = knext) { + knext = k1->next; + if (k1->aino == a1 && k1->fd >= 0) { + int mode = (k1->dosmode & A_FIBF_READ) == 0 ? O_WRONLY : (k1->dosmode & A_FIBF_WRITE) == 0 ? O_RDONLY : O_RDWR; + mode |= O_BINARY; + if (ret == -1) { + /* rename still failed, restore fd */ + k1->fd = open (a1->nname, mode, 0777); + write_log ("restoring old handle '%s' %d\n", a1->nname, k1->dosmode); + } else { + /* transfer fd to new name */ + k1->aino = a2; + k1->fd = open (a2->nname, mode, 0777); + write_log ("restoring new handle '%s' %d\n", a2->nname, k1->dosmode); + } + if (k1->fd < 0) { + write_log ("relocking failed '%s' -> '%s'\n", a1->nname, a2->nname); + free_key (unit, k1); + } else { + lseek (k1->fd, k1->file_pos, SEEK_SET); + } + } + } + if (ret == -1) { + delete_aino (unit, a2); + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, dos_errno ()); + return; + } + } + + notify_check (unit, a1); + notify_check (unit, a2); + a2->comment = a1->comment; + a1->comment = 0; + a2->amigaos_mode = a1->amigaos_mode; + a2->uniq = a1->uniq; + a2->elock = a1->elock; + a2->shlock = a1->shlock; + a2->has_dbentry = a1->has_dbentry; + a2->db_offset = a1->db_offset; + a2->dirty = 0; + move_exkeys (unit, a1, a2); + move_aino_children (unit, a1, a2); + delete_aino (unit, a1); + a2->dirty = 1; + if (a2->parent) + fsdb_dir_writeback (a2->parent); + updatedirtime (a2, 1); + if (a2->elock > 0 || a2->shlock > 0 || wehavekeys > 0) + de_recycle_aino (unit, a2); + PUT_PCK_RES1 (packet, DOS_TRUE); +} + +static void +action_current_volume (Unit *unit, dpacket packet) +{ + PUT_PCK_RES1 (packet, unit->volume >> 2); +} + +static void +action_rename_disk (Unit *unit, dpacket packet) +{ + uaecptr name = GET_PCK_ARG1 (packet) << 2; + int i; + int namelen; + + TRACE(("ACTION_RENAME_DISK(\"%s\")\n", bstr (unit, name))); + + if (unit->ui.readonly) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED); + return; + } + + /* get volume name */ + namelen = get_byte (name); name++; + xfree (unit->ui.volname); + unit->ui.volname = (char *) xmalloc (namelen + 1); + for (i = 0; i < namelen; i++, name++) + unit->ui.volname[i] = get_byte (name); + unit->ui.volname[i] = 0; + + put_byte (unit->volume + 44, namelen); + for (i = 0; i < namelen; i++) + put_byte (unit->volume + 45 + i, unit->ui.volname[i]); + + PUT_PCK_RES1 (packet, DOS_TRUE); +} + +static void +action_is_filesystem (Unit *unit, dpacket packet) +{ + PUT_PCK_RES1 (packet, DOS_TRUE); +} + +static void +action_flush (Unit *unit, dpacket packet) +{ + /* sync(); */ /* pretty drastic, eh */ + PUT_PCK_RES1 (packet, DOS_TRUE); +} + +/* We don't want multiple interrupts to be active at the same time. I don't + * know whether AmigaOS takes care of that, but this does. */ +static uae_sem_t singlethread_int_sem; + +static uae_u32 exter_int_helper (void) +{ + UnitInfo *uip = current_mountinfo->ui; + uaecptr port; + static int unit_no; + + switch (m68k_dreg (regs, 0)) { + case 0: + /* Determine whether a given EXTER interrupt is for us. */ + if (uae_int_requested) { + if (uae_sem_trywait (&singlethread_int_sem) != 0) + /* Pretend it isn't for us. We might get it again later. */ + return 0; + /* Clear the interrupt flag _before_ we do any processing. + * That way, we can get too many interrupts, but never not + * enough. */ + uae_int_requested = 0; + unit_no = 0; + return 1; + } + return 0; + case 1: + /* Release a message_lock. This is called as soon as the message is + * received by the assembly code. We use the opportunity to check + * whether we have some locks that we can give back to the assembler + * code. + * Note that this is called from the main loop, unlike the other cases + * in this switch statement which are called from the interrupt handler. + */ +#ifdef UAE_FILESYS_THREADS + { + Unit *unit = find_unit (m68k_areg (regs, 5)); + uaecptr msg = m68k_areg (regs, 4); + unit->cmds_complete = unit->cmds_acked; + while (comm_pipe_has_data (unit->ui.back_pipe)) { + uaecptr locks, lockend; + locks = read_comm_pipe_int_blocking (unit->ui.back_pipe); + lockend = locks; + while (get_long (lockend) != 0) + lockend = get_long (lockend); + put_long (lockend, get_long (m68k_areg (regs, 3))); + put_long (m68k_areg (regs, 3), locks); + } + } +#else + write_log ("exter_int_helper should not be called with arg 1!\n"); +#endif + break; + case 2: + /* Find work that needs to be done: + * return d0 = 0: none + * d0 = 1: PutMsg(), port in a0, message in a1 + * d0 = 2: Signal(), task in a1, signal set in d1 + * d0 = 3: ReplyMsg(), message in a1 + * d0 = 4: Cause(), interrupt in a1 + * d0 = 5: AllocMem(), size in d0, flags in d1, pointer to address at a0 + * d0 = 6: FreeMem(), memory in a1, size in d0 + */ + +#ifdef SUPPORT_THREADS + /* First, check signals/messages */ + while (comm_pipe_has_data (&native2amiga_pending)) { + int cmd = read_comm_pipe_int_blocking (&native2amiga_pending); + switch (cmd) { + case 0: /* Signal() */ + m68k_areg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending); + m68k_dreg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending); + return 2; + + case 1: /* PutMsg() */ + m68k_areg (regs, 0) = read_comm_pipe_u32_blocking (&native2amiga_pending); + m68k_areg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending); + return 1; + + case 2: /* ReplyMsg() */ + m68k_areg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending); + return 3; + + case 3: /* Cause() */ + m68k_areg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending); + return 4; + + case 4: /* NotifyHack() */ + m68k_areg (regs, 0) = read_comm_pipe_u32_blocking (&native2amiga_pending); + m68k_areg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending); + return 5; + + default: + write_log ("exter_int_helper: unknown native action %X\n", cmd); + break; + } + } +#endif + + /* Find some unit that needs a message sent, and return its port, + * or zero if all are done. + * Take care not to dereference self for units that didn't have their + * startup packet sent. */ + for (;;) { + if (unit_no >= current_mountinfo->num_units) + return 0; + + if (uip[unit_no].self != 0 + && uip[unit_no].self->cmds_acked == uip[unit_no].self->cmds_complete + && uip[unit_no].self->cmds_acked != uip[unit_no].self->cmds_sent) + break; + unit_no++; + } + uip[unit_no].self->cmds_acked = uip[unit_no].self->cmds_sent; + port = uip[unit_no].self->port; + if (port) { + m68k_areg (regs, 0) = port; + m68k_areg (regs, 1) = find_unit (port)->dummy_message; + unit_no++; + return 1; + } + break; + case 4: + /* Exit the interrupt, and release the single-threading lock. */ + uae_sem_post (&singlethread_int_sem); + break; + + default: + write_log ("Shouldn't happen in exter_int_helper.\n"); + break; + } + return 0; +} + +static int handle_packet (Unit *unit, dpacket pck) +{ + uae_s32 type = GET_PCK_TYPE (pck); + PUT_PCK_RES2 (pck, 0); + switch (type) { + case ACTION_LOCATE_OBJECT: action_lock (unit, pck); break; + case ACTION_FREE_LOCK: action_free_lock (unit, pck); break; + case ACTION_COPY_DIR: action_dup_lock (unit, pck); break; + case ACTION_DISK_INFO: action_disk_info (unit, pck); break; + case ACTION_INFO: action_info (unit, pck); break; + case ACTION_EXAMINE_OBJECT: action_examine_object (unit, pck); break; + case ACTION_EXAMINE_NEXT: action_examine_next (unit, pck); break; + case ACTION_FIND_INPUT: action_find_input (unit, pck); break; + case ACTION_FIND_WRITE: action_find_write (unit, pck); break; + case ACTION_FIND_OUTPUT: action_find_output (unit, pck); break; + case ACTION_END: action_end (unit, pck); break; + case ACTION_READ: action_read (unit, pck); break; + case ACTION_WRITE: action_write (unit, pck); break; + case ACTION_SEEK: action_seek (unit, pck); break; + case ACTION_SET_PROTECT: action_set_protect (unit, pck); break; + case ACTION_SET_COMMENT: action_set_comment (unit, pck); break; + case ACTION_SAME_LOCK: action_same_lock (unit, pck); break; + case ACTION_PARENT: action_parent (unit, pck); break; + case ACTION_CREATE_DIR: action_create_dir (unit, pck); break; + case ACTION_DELETE_OBJECT: action_delete_object (unit, pck); break; + case ACTION_RENAME_OBJECT: action_rename_object (unit, pck); break; + case ACTION_SET_DATE: action_set_date (unit, pck); break; + case ACTION_CURRENT_VOLUME: action_current_volume (unit, pck); break; + case ACTION_RENAME_DISK: action_rename_disk (unit, pck); break; + case ACTION_IS_FILESYSTEM: action_is_filesystem (unit, pck); break; + case ACTION_FLUSH: action_flush (unit, pck); break; + + /* 2.0+ packet types */ + case ACTION_SET_FILE_SIZE: action_set_file_size (unit, pck); break; + case ACTION_EXAMINE_FH: action_examine_fh (unit, pck); break; + case ACTION_FH_FROM_LOCK: action_fh_from_lock (unit, pck); break; + case ACTION_CHANGE_MODE: action_change_mode (unit, pck); break; + case ACTION_PARENT_FH: action_parent_fh (unit, pck); break; + case ACTION_ADD_NOTIFY: action_add_notify (unit, pck); break; + case ACTION_REMOVE_NOTIFY: action_remove_notify (unit, pck); break; + + /* unsupported packets */ + case ACTION_LOCK_RECORD: + case ACTION_FREE_RECORD: + case ACTION_COPY_DIR_FH: + case ACTION_EXAMINE_ALL: + case ACTION_MAKE_LINK: + case ACTION_READ_LINK: + case ACTION_FORMAT: + default: + TRACE(("*** UNSUPPORTED PACKET %ld\n", type)); + return 0; + } + return 1; +} + +#ifdef UAE_FILESYS_THREADS +static void *filesys_thread (void *unit_v) +{ + UnitInfo *ui = (UnitInfo *)unit_v; + + set_thread_priority (2); + for (;;) { + uae_u8 *pck; + uae_u8 *msg; + uae_u32 morelocks; + + pck = (uae_u8 *)read_comm_pipe_pvoid_blocking (ui->unit_pipe); + msg = (uae_u8 *)read_comm_pipe_pvoid_blocking (ui->unit_pipe); + morelocks = (uae_u32)read_comm_pipe_int_blocking (ui->unit_pipe); + + if (ui->reset_state == FS_GO_DOWN) { + if (pck != 0) + continue; + /* Death message received. */ + uae_sem_post (&ui->reset_sync_sem); + /* Die. */ + return 0; + } + + put_long (get_long (morelocks), get_long (ui->self->locklist)); + put_long (ui->self->locklist, morelocks); + if (! handle_packet (ui->self, pck)) { + PUT_PCK_RES1 (pck, DOS_FALSE); + PUT_PCK_RES2 (pck, ERROR_ACTION_NOT_KNOWN); + } + /* Mark the packet as processed for the list scan in the assembly code. */ + do_put_mem_long ((uae_u32 *)(msg + 4), -1); + /* Acquire the message lock, so that we know we can safely send the + * message. */ + ui->self->cmds_sent++; + /* The message is sent by our interrupt handler, so make sure an interrupt + * happens. */ + uae_int_requested = 1; + /* Send back the locks. */ + if (get_long (ui->self->locklist) != 0) + write_comm_pipe_int (ui->back_pipe, (int)(get_long (ui->self->locklist)), 0); + put_long (ui->self->locklist, 0); + } + return 0; +} +#endif + +/* Talk about spaghetti code... */ +static uae_u32 filesys_handler (void) +{ + Unit *unit = find_unit (m68k_areg (regs, 5)); + uaecptr packet_addr = m68k_dreg (regs, 3); + uaecptr message_addr = m68k_areg (regs, 4); + uae_u8 *pck; + uae_u8 *msg; + if (! valid_address (packet_addr, 36) || ! valid_address (message_addr, 14)) { + write_log ("Bad address passed for packet.\n"); + goto error2; + } + pck = get_real_address (packet_addr); + msg = get_real_address (message_addr); + +#if 0 + if (unit->reset_state == FS_GO_DOWN) + /* You might as well queue it, if you live long enough */ + return 1; +#endif + + do_put_mem_long ((uae_u32 *)(msg + 4), -1); + if (!unit || !unit->volume) { + write_log ("Filesystem was not initialized.\n"); + goto error; + } +#ifdef UAE_FILESYS_THREADS + { + uae_u32 morelocks; + if (!unit->ui.unit_pipe) + goto error; + /* Get two more locks and hand them over to the other thread. */ + morelocks = get_long (m68k_areg (regs, 3)); + put_long (m68k_areg (regs, 3), get_long (get_long (morelocks))); + put_long (get_long (morelocks), 0); + + /* The packet wasn't processed yet. */ + do_put_mem_long ((uae_u32 *)(msg + 4), 0); + write_comm_pipe_pvoid (unit->ui.unit_pipe, (void *)pck, 0); + write_comm_pipe_pvoid (unit->ui.unit_pipe, (void *)msg, 0); + write_comm_pipe_int (unit->ui.unit_pipe, (int)morelocks, 1); + /* Don't reply yet. */ + return 1; + } +#endif + + if (! handle_packet (unit, pck)) { + error: + PUT_PCK_RES1 (pck, DOS_FALSE); + PUT_PCK_RES2 (pck, ERROR_ACTION_NOT_KNOWN); + } + TRACE(("reply: %8lx, %ld\n", GET_PCK_RES1 (pck), GET_PCK_RES2 (pck))); + + error2: + + return 0; +} + +void filesys_start_threads (void) +{ + UnitInfo *uip; + int i; + + current_mountinfo = currprefs.mountinfo; + uip = current_mountinfo->ui; + for (i = 0; i < current_mountinfo->num_units; i++) { + UnitInfo *ui = &uip[i]; + ui->unit_pipe = 0; + ui->back_pipe = 0; + ui->startup = 0; + ui->reset_state = 0; + ui->self = 0; +#ifdef UAE_FILESYS_THREADS + if (is_hardfile (current_mountinfo, i) == FILESYS_VIRTUAL) { + ui->unit_pipe = (smp_comm_pipe *)xmalloc (sizeof (smp_comm_pipe)); + ui->back_pipe = (smp_comm_pipe *)xmalloc (sizeof (smp_comm_pipe)); + init_comm_pipe (uip[i].unit_pipe, 100, 3); + init_comm_pipe (uip[i].back_pipe, 100, 1); + uae_start_thread (filesys_thread, (void *)(uip + i), &uip[i].tid); + } +#endif + } +} + +void filesys_reset (void) +{ + Unit *u, *u1; + + /* We get called once from customreset at the beginning of the program + * before filesys_start_threads has been called. Survive that. */ + if (current_mountinfo == 0) + return; + + for (u = units; u; u = u1) { + u1 = u->next; + xfree (u); + } + unit_num = 0; + units = 0; + current_mountinfo = 0; +} + +static void free_all_ainos (Unit *u, a_inode *parent) +{ + a_inode *a; + while (a = parent->child) { + free_all_ainos (u, a); + dispose_aino (u, &parent->child, a); + } +} + +void filesys_flush_cache (void) +{ +} + +void filesys_prepare_reset (void) +{ + UnitInfo *uip = current_mountinfo->ui; + Unit *u; + int i; + +#ifdef UAE_FILESYS_THREADS + for (i = 0; i < current_mountinfo->num_units; i++) { + if (uip[i].unit_pipe != 0) { + uae_sem_init (&uip[i].reset_sync_sem, 0, 0); + uip[i].reset_state = FS_GO_DOWN; + /* send death message */ + write_comm_pipe_int (uip[i].unit_pipe, 0, 0); + write_comm_pipe_int (uip[i].unit_pipe, 0, 0); + write_comm_pipe_int (uip[i].unit_pipe, 0, 1); + uae_sem_wait (&uip[i].reset_sync_sem); + } + } +#endif + u = units; + while (u != 0) { + free_all_ainos (u, &u->rootnode); + u->rootnode.next = u->rootnode.prev = &u->rootnode; + u->aino_cache_size = 0; + u = u->next; + } +} + +static uae_u32 filesys_diagentry (void) +{ + uaecptr resaddr = m68k_areg (regs, 2) + 0x10; + uaecptr start = resaddr; + uaecptr residents, tmp; + + TRACE (("filesystem: diagentry called\n")); + + filesys_configdev = m68k_areg (regs, 3); + + do_put_mem_long ((uae_u32 *)(filesysory + 0x2100), EXPANSION_explibname); + do_put_mem_long ((uae_u32 *)(filesysory + 0x2104), filesys_configdev); + do_put_mem_long ((uae_u32 *)(filesysory + 0x2108), EXPANSION_doslibname); + do_put_mem_long ((uae_u32 *)(filesysory + 0x210c), current_mountinfo->num_units); + + uae_sem_init (&singlethread_int_sem, 0, 1); + if (ROM_hardfile_resid != 0) { + /* Build a struct Resident. This will set up and initialize + * the uae.device */ + put_word (resaddr + 0x0, 0x4AFC); + put_long (resaddr + 0x2, resaddr); + put_long (resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */ + put_word (resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */ + put_word (resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */ + put_long (resaddr + 0xE, ROM_hardfile_resname); + put_long (resaddr + 0x12, ROM_hardfile_resid); + put_long (resaddr + 0x16, ROM_hardfile_init); /* calls filesys_init */ + } + resaddr += 0x1A; + tmp = resaddr; + + /* The good thing about this function is that it always gets called + * when we boot. So we could put all sorts of stuff that wants to be done + * here. + * We can simply add more Resident structures here. Although the Amiga OS + * only knows about the one at address DiagArea + 0x10, we scan for other + * Resident structures and call InitResident() for them at the end of the + * diag entry. */ + + resaddr = scsidev_startup(resaddr); + native2amiga_startup(); + + /* scan for Residents and return pointer to array of them */ + residents = resaddr; + while (tmp < residents && tmp > start) { + if (get_word (tmp) == 0x4AFC && + get_long (tmp + 0x2) == tmp) { + put_word (resaddr, 0x227C); /* movea.l #tmp,a1 */ + put_long (resaddr + 2, tmp); + put_word (resaddr + 6, 0x7200); /* moveq.l #0,d1 */ + put_long (resaddr + 8, 0x4EAEFF9A); /* jsr -$66(a6) ; InitResident */ + resaddr += 12; + tmp = get_long (tmp + 0x6); + } else { + tmp++; + } + } + /* call setup_exter */ + put_word (resaddr + 0, 0x2079); + put_long (resaddr + 2, RTAREA_BASE + 28 + 4); /* move.l RTAREA_BASE+32,a0 */ + put_word (resaddr + 6, 0xd1fc); + put_long (resaddr + 8, RTAREA_BASE + 8 + 4); /* add.l #RTAREA_BASE+12,a0 */ + put_word (resaddr + 12, 0x4e90); /* jsr (a0) */ + put_word (resaddr + 14, 0x7001); /* moveq.l #1,d0 */ + put_word (resaddr + 16, RTS); + + m68k_areg (regs, 0) = residents; + return 1; +} + +/* don't forget filesys.asm! */ +#define PP_MAXSIZE 4 * 96 +#define PP_FSSIZE 400 +#define PP_FSPTR 404 +#define PP_FSRES 408 +#define PP_EXPLIB 412 +#define PP_FSHDSTART 416 + +static uae_u32 filesys_dev_bootfilesys (void) +{ + uaecptr devicenode = m68k_areg (regs, 3); + uaecptr parmpacket = m68k_areg (regs, 1); + uaecptr fsres = get_long (parmpacket + PP_FSRES); + uaecptr fsnode; + uae_u32 dostype, dostype2; + UnitInfo *uip = current_mountinfo->ui; + int no = m68k_dreg (regs, 6); + int unit_no = no & 65535; + int type = is_hardfile (current_mountinfo, unit_no); + + if (type == FILESYS_VIRTUAL) + return 0; + dostype = get_long (parmpacket + 80); + fsnode = get_long (fsres + 18); + while (get_long (fsnode)) { + dostype2 = get_long (fsnode + 14); + if (dostype2 == dostype) { + if (get_long (fsnode + 22) & (1 << 7)) { + put_long (devicenode + 32, get_long (fsnode + 54)); /* dn_SegList */ + put_long (devicenode + 36, -1); /* dn_GlobalVec */ + } + return 1; + } + fsnode = get_long (fsnode); + } + return 0; +} + +/* Remember a pointer AmigaOS gave us so we can later use it to identify + * which unit a given startup message belongs to. */ +static uae_u32 filesys_dev_remember (void) +{ + int no = m68k_dreg (regs, 6); + int unit_no = no & 65535; + int sub_no = no >> 16; + UnitInfo *uip = ¤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" diff --git a/filesys.sh b/filesys.sh new file mode 100755 index 00000000..72a14185 --- /dev/null +++ b/filesys.sh @@ -0,0 +1,7 @@ +#! /bin/sh +# Script to convert an Amiga executable named filesys into a series of +# dw(...) statements. +# This assumes that the first four lines only contain hunk information. +# That is what you get if you assemble/link with a68k/blink +od -v -t xC -w8 filesys |tail -n +5 | sed -e "s,^.......,," \ + -e "s,[0123456789abcdefABCDEF][0123456789abcdefABCDEF],db(0x&);,g" diff --git a/fpp.c b/fpp.c new file mode 100755 index 00000000..56190b9b --- /dev/null +++ b/fpp.c @@ -0,0 +1,1453 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * MC68881 emulation + * + * Copyright 1996 Herman ten Brugge + */ + +#define __USE_ISOC9X /* We might be able to pick up a NaN */ +#include + +#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. to register needs FPSR updated. + * See page 3-73 in Motorola 68K programmers reference manual. + * %%%FPU */ + if ((extra & 0x44) == 0x40) + fround (reg); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x01: /* FINT */ + /* need to take the current rounding mode into account */ + regs.fp[reg] = (fptype)toint(src); + break; + case 0x02: /* FSINH */ + regs.fp[reg] = sinh (src); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x03: /* FINTRZ */ + regs.fp[reg] = (int) src; + MAKE_FPSR (regs.fp[reg]); + break; + case 0x04: /* FSQRT */ + case 0x41: + case 0x45: + regs.fp[reg] = sqrt (src); + if ((extra & 0x44) == 0x40) + fround (reg); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x06: /* FLOGNP1 */ + regs.fp[reg] = log (src + 1.0); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x08: /* FETOXM1 */ + regs.fp[reg] = exp (src) - 1.0; + MAKE_FPSR (regs.fp[reg]); + break; + case 0x09: /* FTANH */ + regs.fp[reg] = tanh (src); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x0a: /* FATAN */ + regs.fp[reg] = atan (src); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x0c: /* FASIN */ + regs.fp[reg] = asin (src); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x0d: /* FATANH */ +#if 1 /* The BeBox doesn't have atanh, and it isn't in the HPUX libm either */ + regs.fp[reg] = log ((1 + src) / (1 - src)) / 2; +#else + regs.fp[reg] = atanh (src); +#endif + MAKE_FPSR (regs.fp[reg]); + break; + case 0x0e: /* FSIN */ + regs.fp[reg] = sin (src); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x0f: /* FTAN */ + regs.fp[reg] = tan (src); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x10: /* FETOX */ + regs.fp[reg] = exp (src); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x11: /* FTWOTOX */ + regs.fp[reg] = pow (2.0, src); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x12: /* FTENTOX */ + regs.fp[reg] = pow (10.0, src); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x14: /* FLOGN */ + regs.fp[reg] = log (src); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x15: /* FLOG10 */ + regs.fp[reg] = log10 (src); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x16: /* FLOG2 */ + regs.fp[reg] = log (src) / log (2.0); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x18: /* FABS */ + case 0x58: + case 0x5c: + regs.fp[reg] = src < 0 ? -src : src; + if ((extra & 0x44) == 0x40) + fround (reg); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x19: /* FCOSH */ + regs.fp[reg] = cosh (src); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x1a: /* FNEG */ + case 0x5a: + case 0x5e: + regs.fp[reg] = -src; + if ((extra & 0x44) == 0x40) + fround (reg); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x1c: /* FACOS */ + regs.fp[reg] = acos (src); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x1d: /* FCOS */ + regs.fp[reg] = cos (src); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x1e: /* FGETEXP */ + { + int expon; + frexp (src, &expon); + regs.fp[reg] = (double) (expon - 1); + MAKE_FPSR (regs.fp[reg]); + } + break; + case 0x1f: /* FGETMAN */ + { + int expon; + regs.fp[reg] = frexp (src, &expon) * 2.0; + MAKE_FPSR (regs.fp[reg]); + } + break; + case 0x20: /* FDIV */ + case 0x60: + case 0x64: + regs.fp[reg] /= src; + if ((extra & 0x44) == 0x40) + fround (reg); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x21: /* FMOD */ + regs.fp[reg] = regs.fp[reg] - (double) ((int) (regs.fp[reg] / src)) * src; + MAKE_FPSR (regs.fp[reg]); + break; + case 0x22: /* FADD */ + case 0x62: + case 0x66: + regs.fp[reg] += src; + if ((extra & 0x44) == 0x40) + fround (reg); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x23: /* FMUL */ + case 0x63: + case 0x67: + regs.fp[reg] *= src; + if ((extra & 0x44) == 0x40) + fround (reg); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x24: /* FSGLDIV */ + regs.fp[reg] /= src; + MAKE_FPSR (regs.fp[reg]); + break; + case 0x25: /* FREM */ + regs.fp[reg] = regs.fp[reg] - (double) ((int) (regs.fp[reg] / src + 0.5)) * src; + MAKE_FPSR (regs.fp[reg]); + break; + case 0x26: /* FSCALE */ + regs.fp[reg] *= exp (log (2.0) * src); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x27: /* FSGLMUL */ + regs.fp[reg] *= src; + MAKE_FPSR (regs.fp[reg]); + break; + case 0x28: /* FSUB */ + case 0x68: + case 0x6c: + regs.fp[reg] -= src; + if ((extra & 0x44) == 0x40) + fround (reg); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x30: /* FSINCOS */ + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + regs.fp[reg] = sin (src); + regs.fp[extra & 7] = cos (src); + MAKE_FPSR (regs.fp[reg]); + break; + case 0x38: /* FCMP */ + { + fptype tmp = regs.fp[reg] - src; + regs.fpsr = 0; + MAKE_FPSR (tmp); + } + break; + case 0x3a: /* FTST */ + regs.fpsr = 0; + MAKE_FPSR (src); + break; + default: + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); + break; + } + return; + } + m68k_setpc (m68k_getpc () - 4); + op_illg (opcode); +} + +#endif + +uae_u8 *restore_fpu (uae_u8 *src) +{ + int model, i; + + model = restore_u32(); + restore_u32 (); + if (currprefs.cpu_level == 2) { + currprefs.cpu_level++; + init_m68k_full (); + } + changed_prefs.cpu_level = currprefs.cpu_level; + for (i = 0; i < 8; i++) { + uae_u32 w1 = restore_u32 (); + uae_u32 w2 = restore_u32 (); + uae_u32 w3 = restore_u16 (); + regs.fp[i] = to_exten (w1, w2, w3); + } + regs.fpcr = restore_u32 (); + regs.fpsr = restore_u32 (); + regs.fpiar = restore_u32 (); + return src; +} + +uae_u8 *save_fpu (int *len, uae_u8 *dstptr) +{ + uae_u8 *dstbak,*dst; + int model,i; + + *len = 0; + switch (currprefs.cpu_level) + { + case 3: + model = 68881; + break; + case 4: + model = 68040; + break; + case 6: + model = 68060; + break; + default: + return 0; + } + if (dstptr) + dstbak = dst = dstptr; + else + dstbak = dst = malloc(4+4+8*10+4+4+4); + save_u32 (model); + save_u32 (0); + for (i = 0; i < 8; i++) { + uae_u32 w1, w2, w3; + from_exten (regs.fp[i], &w1, &w2, &w3); + save_u32 (w1); + save_u32 (w2); + save_u16 (w3); + } + save_u32 (regs.fpcr); + save_u32 (regs.fpsr); + save_u32 (regs.fpiar); + *len = dst - dstbak; + return dstbak; +} diff --git a/fsdb.c b/fsdb.c new file mode 100755 index 00000000..369b705b --- /dev/null +++ b/fsdb.c @@ -0,0 +1,334 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Library of functions to make emulated filesystem as independent as + * possible of the host filesystem's capabilities. + * + * Copyright 1999 Bernd Schmidt + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "threaddep/thread.h" +#include "options.h" +#include "uae.h" +#include "memory.h" +#include "custom.h" +#include "newcpu.h" +#include "filesys.h" +#include "autoconf.h" +#include "compiler.h" +#include "fsusage.h" +#include "native2amiga.h" +#include "scsidev.h" +#include "fsdb.h" + +/* The on-disk format is as follows: + * Offset 0, 1 byte, valid + * Offset 1, 4 bytes, mode + * Offset 5, 257 bytes, aname + * Offset 263, 257 bytes, nname + * Offset 518, 81 bytes, comment + */ + +char *nname_begin (char *nname) +{ + char *p = strrchr (nname, FSDB_DIR_SEPARATOR); + if (p) + return p + 1; + return nname; +} + +/* Find the name REL in directory DIRNAME. If we find a file that + * has exactly the same name, return REL. If we find a file that + * has the same name when compared case-insensitively, return a + * malloced string that contains the name we found. If no file + * exists that compares equal to REL, return 0. */ +char *fsdb_search_dir (const char *dirname, char *rel) +{ + char *p = 0; + struct dirent *de; + DIR *dir = opendir (dirname); + + /* This really shouldn't happen... */ + if (! dir) + return 0; + + while (p == 0 && (de = readdir (dir)) != 0) { + if (strcmp (de->d_name, rel) == 0) + p = rel; + else if (strcasecmp (de->d_name, rel) == 0) + p = my_strdup (de->d_name); + } + closedir (dir); + return p; +} + +static FILE *get_fsdb (a_inode *dir, const char *mode) +{ + char *n; + FILE *f; + + n = build_nname (dir->nname, FSDB_FILE); + f = fopen (n, mode); + free (n); + return f; +} + +static void kill_fsdb (a_inode *dir) +{ + char *n = build_nname (dir->nname, FSDB_FILE); + unlink (n); + free (n); +} + +static void fsdb_fixup (FILE *f, char *buf, int size, a_inode *base) +{ + char *nname; + int ret; + + if (buf[0] == 0) + return; + nname = build_nname (base->nname, buf + 5 + 257); + ret = fsdb_exists (nname); + if (ret) { + free (nname); + return; + } + write_log ("uaefsdb '%s' deleted\n", nname); + /* someone deleted this file/dir outside of emulation.. */ + buf[0] = 0; + free (nname); +} + +/* Prune the db file the first time this directory is opened in a session. */ +void fsdb_clean_dir (a_inode *dir) +{ + char buf[1 + 4 + 257 + 257 + 81]; + char *n = build_nname (dir->nname, FSDB_FILE); + FILE *f = fopen (n, "r+b"); + off_t pos1 = 0, pos2; + + if (f == 0) { + free (n); + return; + } + for (;;) { + pos2 = ftell (f); + if (fread (buf, 1, sizeof buf, f) < sizeof buf) + break; + fsdb_fixup (f, buf, sizeof buf, dir); + if (buf[0] == 0) + continue; + if (pos1 != pos2) { + fseek (f, pos1, SEEK_SET); + fwrite (buf, 1, sizeof buf, f); + fseek (f, pos2 + sizeof buf, SEEK_SET); + } + pos1 += sizeof buf; + } + fclose (f); + truncate (n, pos1); + free (n); +} + +static a_inode *aino_from_buf (a_inode *base, char *buf, long off) +{ + uae_u32 mode; + a_inode *aino = (a_inode *) xcalloc (sizeof (a_inode), 1); + + mode = do_get_mem_long ((uae_u32 *)(buf + 1)); + buf += 5; + aino->aname = my_strdup (buf); + buf += 257; + aino->nname = build_nname (base->nname, buf); + buf += 257; + aino->comment = *buf != '\0' ? my_strdup (buf) : 0; + fsdb_fill_file_attrs (aino); + aino->amigaos_mode = mode; + aino->has_dbentry = 1; + aino->dirty = 0; + aino->db_offset = off; + write_log("aino=%d a='%s' n='%s' c='%s' mode=%d dir=%d\n",off,aino->aname,aino->nname,aino->comment,aino->amigaos_mode,aino->dir); + return aino; +} + +a_inode *fsdb_lookup_aino_aname (a_inode *base, const char *aname) +{ + FILE *f = get_fsdb (base, "r+b"); + + if (f == 0) + return 0; + + for (;;) { + char buf[1 + 4 + 257 + 257 + 81]; + if (fread (buf, 1, sizeof buf, f) < sizeof buf) + break; + if (buf[0] != 0 && same_aname (buf + 5, aname)) { + long pos = ftell (f) - sizeof buf; + fclose (f); + return aino_from_buf (base, buf, pos); + } + } + fclose (f); + return 0; +} + +a_inode *fsdb_lookup_aino_nname (a_inode *base, const char *nname) +{ + FILE *f = get_fsdb (base, "r+b"); + + if (f == 0) + return 0; + + for (;;) { + char buf[1 + 4 + 257 + 257 + 81]; + if (fread (buf, 1, sizeof buf, f) < sizeof buf) + break; + if (buf[0] != 0 && strcmp (buf + 5 + 257, nname) == 0) { + long pos = ftell (f) - sizeof buf; + fclose (f); + return aino_from_buf (base, buf, pos); + } + } + fclose (f); + return 0; +} + +int fsdb_used_as_nname (a_inode *base, const char *nname) +{ + FILE *f = get_fsdb (base, "r+b"); + char buf[1 + 4 + 257 + 257 + 81]; + + if (f == 0) + return 0; + for (;;) { + if (fread (buf, 1, sizeof buf, f) < sizeof buf) + break; + if (buf[0] == 0) + continue; + if (strcmp (buf + 5 + 257, nname) == 0) { + fclose (f); + return 1; + } + } + fclose (f); + return 0; +} + +static int needs_dbentry (a_inode *aino) +{ + const char *nn_begin; + + if (aino->deleted) + return 0; + + if (! fsdb_mode_representable_p (aino) || aino->comment != 0) + return 1; + + nn_begin = nname_begin (aino->nname); + return strcmp (nn_begin, aino->aname) != 0; +} + +static void write_aino (FILE *f, a_inode *aino) +{ + char buf[1 + 4 + 257 + 257 + 81]; + buf[0] = aino->needs_dbentry; + do_put_mem_long ((uae_u32 *)(buf + 1), aino->amigaos_mode); + strncpy (buf + 5, aino->aname, 256); + buf[5 + 256] = '\0'; + strncpy (buf + 5 + 257, nname_begin (aino->nname), 256); + buf[5 + 257 + 256] = '\0'; + strncpy (buf + 5 + 2*257, aino->comment ? aino->comment : "", 80); + buf[5 + 2 * 257 + 80] = '\0'; + aino->db_offset = ftell (f); + fwrite (buf, 1, sizeof buf, f); + aino->has_dbentry = aino->needs_dbentry; + write_log ("%d '%s' '%s' written\n", aino->db_offset, aino->aname, aino->nname); +} + +/* Write back the db file for a directory. */ + +void fsdb_dir_writeback (a_inode *dir) +{ + FILE *f; + int changes_needed = 0; + int entries_needed = 0; + a_inode *aino; + uae_u8 *tmpbuf; + int size, i; + + /* First pass: clear dirty bits where unnecessary, and see if any work + * needs to be done. */ + for (aino = dir->child; aino; aino = aino->sibling) { +/* + int old_needs_dbentry = aino->needs_dbentry || aino->has_dbentry; + aino->needs_dbentry = needs_dbentry (aino); + entries_needed |= aino->has_dbentry | aino->needs_dbentry; +*/ + int old_needs_dbentry = aino->has_dbentry; + int need = needs_dbentry (aino); + aino->needs_dbentry = need; + entries_needed |= need; + if (! aino->dirty) + continue; + if (! aino->needs_dbentry && ! old_needs_dbentry) + aino->dirty = 0; + else + changes_needed = 1; + } + if (! entries_needed) { + kill_fsdb (dir); + return; + } + + if (! changes_needed) + return; + + f = get_fsdb (dir, "r+b"); + if (f == 0) { + if (currprefs.filesys_no_uaefsdb) + return; + f = get_fsdb (dir, "w+b"); + if (f == 0) + /* This shouldn't happen... */ + return; + } + fseek (f, 0, SEEK_END); + size = ftell (f); + fseek (f, 0, SEEK_SET); + tmpbuf = 0; + if (size > 0) { + tmpbuf = malloc (size); + fread (tmpbuf, 1, size, f); + } + write_log ("**** updating '%s'\n", dir->aname); + + for (aino = dir->child; aino; aino = aino->sibling) { + if (! aino->dirty) + continue; + aino->dirty = 0; + + i = 0; + while (!aino->has_dbentry && i < size) { + if (!strcmp (tmpbuf + i + 5, aino->aname)) { + aino->has_dbentry = 1; + aino->db_offset = i; + } + i += 1 + 4 + 257 + 257 + 81; + } + + if (! aino->has_dbentry) { + fseek (f, 0, SEEK_END); + aino->has_dbentry = 1; + } else { + fseek (f, aino->db_offset, SEEK_SET); + } + write_aino (f, aino); + } + write_log ("end\n"); + fclose (f); + free (tmpbuf); +} diff --git a/fsdb_unix.c b/fsdb_unix.c new file mode 100755 index 00000000..e2b22326 --- /dev/null +++ b/fsdb_unix.c @@ -0,0 +1,105 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Library of functions to make emulated filesystem as independent as + * possible of the host filesystem's capabilities. + * This is the Unix version. + * + * Copyright 1999 Bernd Schmidt + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "fsdb.h" + +/* Return nonzero for any name we can't create on the native filesystem. */ +int fsdb_name_invalid (const char *n) +{ + if (strcmp (n, FSDB_FILE) == 0) + return 1; + if (n[0] != '.') + return 0; + if (n[1] == '\0') + return 1; + return n[1] == '.' && n[2] == '\0'; +} + +/* For an a_inode we have newly created based on a filename we found on the + * native fs, fill in information about this file/directory. */ +int fsdb_fill_file_attrs (a_inode *aino) +{ + struct stat statbuf; + /* This really shouldn't happen... */ + if (stat (aino->nname, &statbuf) == -1) + return 0; + aino->dir = S_ISDIR (statbuf.st_mode) ? 1 : 0; + aino->amigaos_mode = ((S_IXUSR & statbuf.st_mode ? 0 : A_FIBF_EXECUTE) + | (S_IWUSR & statbuf.st_mode ? 0 : A_FIBF_WRITE) + | (S_IRUSR & statbuf.st_mode ? 0 : A_FIBF_READ)); + return 1; +} + +int fsdb_set_file_attrs (a_inode *aino, int mask) +{ + struct stat statbuf; + int mode; + + if (stat (aino->nname, &statbuf) == -1) + return ERROR_OBJECT_NOT_AROUND; + + mode = statbuf.st_mode; + /* Unix dirs behave differently than AmigaOS ones. */ + if (! aino->dir) { + if (mask & A_FIBF_READ) + mode &= ~S_IRUSR; + else + mode |= S_IRUSR; + + if (mask & A_FIBF_WRITE) + mode &= ~S_IWUSR; + else + mode |= S_IWUSR; + + if (mask & A_FIBF_EXECUTE) + mode &= ~S_IXUSR; + else + mode |= S_IXUSR; + + chmod (aino->nname, mode); + } + + aino->amigaos_mode = mask; + aino->dirty = 1; + return 0; +} + +/* Return nonzero if we can represent the amigaos_mode of AINO within the + * native FS. Return zero if that is not possible. */ +int fsdb_mode_representable_p (const a_inode *aino) +{ + if (aino->dir) + return aino->amigaos_mode == 0; + return (aino->amigaos_mode & (A_FIBF_DELETE | A_FIBF_SCRIPT | A_FIBF_PURE)) == 0; +} + +char *fsdb_create_unique_nname (a_inode *base, const char *suggestion) +{ + char tmp[256] = "__uae___"; + strncat (tmp, suggestion, 240); + for (;;) { + int i; + char *p = build_nname (base->nname, tmp); + if (access (p, R_OK) < 0 && errno == ENOENT) { + printf ("unique name: %s\n", p); + return p; + } + free (p); + + /* tmpnam isn't reentrant and I don't really want to hack configure + * right now to see whether tmpnam_r is available... */ + for (i = 0; i < 8; i++) { + tmp[i] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"[random () % 63]; + } + } +} diff --git a/fsusage.c b/fsusage.c new file mode 100755 index 00000000..206e7065 --- /dev/null +++ b/fsusage.c @@ -0,0 +1,355 @@ +/* fsusage.c -- return space usage of mounted filesystems + Copyright (C) 1991, 1992, 1996 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "sysconfig.h" + +#include +#include + +#ifdef HAVE_SYS_STAT_H +#include +#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 +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 +#endif + +#if HAVE_SYS_PARAM_H +# include +#endif + +#if HAVE_SYS_MOUNT_H +# include +#endif + +#if HAVE_SYS_VFS_H +# include +#endif + +#if HAVE_SYS_FS_S5PARAM_H /* Fujitsu UXP/V */ +# include +#endif + +#if defined (HAVE_SYS_FILSYS_H) && !defined (_CRAY) +# include /* SVR2 */ +#endif + +#if HAVE_FCNTL_H +# include +#endif + +#if HAVE_SYS_STATFS_H +# include +#endif + +#if HAVE_DUSTAT_H /* AIX PS/2 */ +# include +#endif + +#if HAVE_SYS_STATVFS_H /* SVR4 */ +# include +int statvfs (); +#endif + +/* Read LEN bytes at PTR from descriptor DESC, retrying if interrupted. + Return the actual number of bytes read, zero for EOF, or negative + for an error. */ + +int +safe_read (desc, ptr, len) + int desc; + char *ptr; + int len; +{ + int n_chars; + + if (len <= 0) + return len; + +#ifdef EINTR + do + { + n_chars = read (desc, ptr, len); + } + while (n_chars < 0 && errno == EINTR); +#else + n_chars = read (desc, ptr, len); +#endif + + return n_chars; +} + +/* Fill in the fields of FSP with information about space usage for + the filesystem on which PATH resides. + DISK is the device on which PATH is mounted, for space-getting + methods that need to know it. + Return 0 if successful, -1 if not. When returning -1, ensure that + ERRNO is either a system error value, or zero if DISK is NULL + on a system that requires a non-NULL value. */ +int +get_fs_usage (path, disk, fsp) + const char *path; + const char *disk; + struct fs_usage *fsp; +{ +#ifdef STAT_STATFS3_OSF1 +# define CONVERT_BLOCKS(B) adjust_blocks ((B), fsd.f_fsize, 512) + + struct statfs fsd; + + if (statfs (path, &fsd, sizeof (struct statfs)) != 0) + return -1; + +#endif /* STAT_STATFS3_OSF1 */ + +#ifdef STAT_STATFS2_FS_DATA /* Ultrix */ +# define CONVERT_BLOCKS(B) adjust_blocks ((B), 1024, 512) + + struct fs_data fsd; + + if (statfs (path, &fsd) != 1) + return -1; + fsp->fsu_blocks = CONVERT_BLOCKS (fsd.fd_req.btot); + fsp->fsu_bfree = CONVERT_BLOCKS (fsd.fd_req.bfree); + fsp->fsu_bavail = CONVERT_BLOCKS (fsd.fd_req.bfreen); + fsp->fsu_files = fsd.fd_req.gtot; + fsp->fsu_ffree = fsd.fd_req.gfree; + +#endif /* STAT_STATFS2_FS_DATA */ + +#ifdef STAT_READ_FILSYS /* SVR2 */ +# ifndef SUPERBOFF +# define SUPERBOFF (SUPERB * 512) +# endif +# define CONVERT_BLOCKS(B) \ + adjust_blocks ((B), (fsd.s_type == Fs2b ? 1024 : 512), 512) + + struct filsys fsd; + int fd; + + if (! disk) + { + errno = 0; + return -1; + } + + fd = open (disk, O_RDONLY); + if (fd < 0) + return -1; + lseek (fd, (long) SUPERBOFF, 0); + if (safe_read (fd, (char *) &fsd, sizeof fsd) != sizeof fsd) + { + close (fd); + return -1; + } + close (fd); + fsp->fsu_blocks = CONVERT_BLOCKS (fsd.s_fsize); + fsp->fsu_bfree = CONVERT_BLOCKS (fsd.s_tfree); + fsp->fsu_bavail = CONVERT_BLOCKS (fsd.s_tfree); + fsp->fsu_files = (fsd.s_isize - 2) * INOPB * (fsd.s_type == Fs2b ? 2 : 1); + fsp->fsu_ffree = fsd.s_tinode; + +#endif /* STAT_READ_FILSYS */ + +#ifdef STAT_STATFS2_BSIZE /* 4.3BSD, SunOS 4, HP-UX, AIX */ +# define CONVERT_BLOCKS(B) adjust_blocks ((B), fsd.f_bsize, 512) + + struct statfs fsd; + + if (statfs (path, &fsd) < 0) + return -1; + +# ifdef STATFS_TRUNCATES_BLOCK_COUNTS + + /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the + struct statfs are truncated to 2GB. These conditions detect that + truncation, presumably without botching the 4.1.1 case, in which + the values are not truncated. The correct counts are stored in + undocumented spare fields. */ + if (fsd.f_blocks == 0x1fffff && fsd.f_spare[0] > 0) + { + fsd.f_blocks = fsd.f_spare[0]; + fsd.f_bfree = fsd.f_spare[1]; + fsd.f_bavail = fsd.f_spare[2]; + } +# endif /* STATFS_TRUNCATES_BLOCK_COUNTS */ + +#endif /* STAT_STATFS2_BSIZE */ + +#ifdef STAT_STATFS2_FSIZE /* 4.4BSD */ +# define CONVERT_BLOCKS(B) adjust_blocks ((B), fsd.f_fsize, 512) + + struct statfs fsd; + + if (statfs (path, &fsd) < 0) + return -1; + +#endif /* STAT_STATFS2_FSIZE */ + +#ifdef STAT_STATFS4 /* SVR3, Dynix, Irix, AIX */ +# if _AIX || defined(_CRAY) +# define CONVERT_BLOCKS(B) adjust_blocks ((B), fsd.f_bsize, 512) +# ifdef _CRAY +# define f_bavail f_bfree +# endif +# else +# define CONVERT_BLOCKS(B) (B) +# ifndef _SEQUENT_ /* _SEQUENT_ is DYNIX/ptx */ +# ifndef DOLPHIN /* DOLPHIN 3.8.alfa/7.18 has f_bavail */ +# define f_bavail f_bfree +# endif +# endif +# endif + + struct statfs fsd; + + if (statfs (path, &fsd, sizeof fsd, 0) < 0) + return -1; + /* Empirically, the block counts on most SVR3 and SVR3-derived + systems seem to always be in terms of 512-byte blocks, + no matter what value f_bsize has. */ + +#endif /* STAT_STATFS4 */ + +#ifdef STAT_STATVFS /* SVR4 */ +# define CONVERT_BLOCKS(B) \ + adjust_blocks ((B), fsd.f_frsize ? fsd.f_frsize : fsd.f_bsize, 512) + + struct statvfs fsd; + + if (statvfs (path, &fsd) < 0) + return -1; + /* f_frsize isn't guaranteed to be supported. */ + +#endif /* STAT_STATVFS */ + +#if !defined(STAT_STATFS2_FS_DATA) && !defined(STAT_READ_FILSYS) + /* !Ultrix && !SVR2 */ + + fsp->fsu_blocks = CONVERT_BLOCKS (fsd.f_blocks); + fsp->fsu_bfree = CONVERT_BLOCKS (fsd.f_bfree); + fsp->fsu_bavail = CONVERT_BLOCKS (fsd.f_bavail); + fsp->fsu_files = fsd.f_files; + fsp->fsu_ffree = fsd.f_ffree; + +#endif /* not STAT_STATFS2_FS_DATA && not STAT_READ_FILSYS */ + + return 0; +} + +#if defined(_AIX) && defined(_I386) +/* AIX PS/2 does not supply statfs. */ + +int +statfs (path, fsb) + char *path; + struct statfs *fsb; +{ + struct stat stats; + struct dustat fsd; + + if (stat (path, &stats)) + return -1; + if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd))) + return -1; + fsb->f_type = 0; + fsb->f_bsize = fsd.du_bsize; + fsb->f_blocks = fsd.du_fsize - fsd.du_isize; + fsb->f_bfree = fsd.du_tfree; + fsb->f_bavail = fsd.du_tfree; + fsb->f_files = (fsd.du_isize - 2) * fsd.du_inopb; + fsb->f_ffree = fsd.du_tinode; + fsb->f_fsid.val[0] = fsd.du_site; + fsb->f_fsid.val[1] = fsd.du_pckno; + return 0; +} + +#endif /* _AIX && _I386 */ + +#endif /* ! _WIN32 */ diff --git a/genblitter.c b/genblitter.c new file mode 100755 index 00000000..0cb3204c --- /dev/null +++ b/genblitter.c @@ -0,0 +1,271 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Optimized blitter minterm function generator + * + * Copyright 1995,1996 Bernd Schmidt + * Copyright 1996 Alessandro Bissacco + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "genblitter.h" + +/* Here is the minterm table used in blitter function generation */ + +static unsigned char blttbl[]= { + 0x00, 0x0a, 0x2a, 0x30, 0x3a, 0x3c, 0x4a, 0x6a, 0x8a, 0x8c, 0x9a, 0xa8, + 0xaa, 0xb1, 0xca, 0xcc, 0xd8, 0xe2, 0xea, 0xf0, 0xfa, 0xfc +}; + +static void generate_include(void) +{ + int minterm; + printf("STATIC_INLINE uae_u32 blit_func(uae_u32 srca, uae_u32 srcb, uae_u32 srcc, uae_u8 mt)\n{\nswitch(mt){\n"); + for (minterm = 0; minterm < 256; minterm++) { + printf("case 0x%x:\n", minterm); + printf("\treturn %s;\n", blitops[minterm].s); + } + printf("}\n"); + printf("return 0;\n"); /* No, sir, it doesn't! */ + printf("}\n"); +} + +static void generate_func(void) +{ + unsigned int i; + printf("#include \"sysconfig.h\"\n"); + printf("#include \"sysdeps.h\"\n"); + printf("#include \"config.h\"\n"); + printf("#include \"options.h\"\n"); + printf("#include \"custom.h\"\n"); + printf("#include \"memory.h\"\n"); + printf("#include \"blitter.h\"\n"); + printf("#include \"blitfunc.h\"\n\n"); + + for (i = 0; i < sizeof(blttbl); i++) { + int active = blitops[blttbl[i]].used; + int a_is_on = active & 1, b_is_on = active & 2, c_is_on = active & 4; + printf("void blitdofast_%x (uaecptr pta, uaecptr ptb, uaecptr ptc, uaecptr ptd, struct bltinfo *b)\n",blttbl[i]); + printf("{\n"); + printf("int i,j;\n"); + printf("uae_u32 totald = 0;\n"); +#if 0 + printf("if (currprefs.blits_32bit_enabled && b->hblitsize > 1"); + if (a_is_on) printf(" && !b->blitashift && b->bltafwm==0xffff && b->bltalwm==0xffff"); + if (b_is_on) printf(" && !b->blitbshift"); + printf(") {\n"); + if (a_is_on) printf("uae_u32 srca=((uae_u32)b->bltadat << 16) | b->bltadat;\n"); + if (b_is_on) printf("uae_u32 srcb=((uae_u32)b->bltbdat << 16) | b->bltbdat;\n"); + if (c_is_on) printf("uae_u32 srcc=((uae_u32)b->bltcdat << 16) | b->bltcdat;\n"); + printf("uae_u32 dest;\n"); + printf("int count=b->hblitsize/2, oddword=b->hblitsize&1;\n"); + printf("for (j=0;jvblitsize;j++) {\n"); + printf("\tfor(i=0;ibltamod;\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;jvblitsize;j++) {\n"); + printf("\tfor(i=0;ibltamod;\n"); + if (b_is_on) printf("\tif (ptb) ptb -= b->bltbmod;\n"); + if (c_is_on) printf("\tif (ptc) ptc -= b->bltcmod;\n"); + printf("\tif (ptd) ptd-=b->bltdmod;\n"); + printf("}\n"); + if (a_is_on) printf("if (pta) b->bltadat = (*(pta + b->bltamod + 2) << 8) | *(pta + b->bltamod + 1);\n"); /* Maybe not necessary, but I don't want problems */ + if (b_is_on) printf("if (ptb) b->bltbdat = (*(ptb + b->bltbmod + 2) << 8) | *(ptb + b->bltbmod + 1);\n"); + if (c_is_on) printf("if (ptc) b->bltcdat = (*(ptc + b->bltcmod + 2) << 8) | *(ptc + b->bltcmod + 1);\n"); + printf("if (ptd) b->bltddat = (*(ptd + b->bltdmod + 2) << 8) | *(ptd + b->bltdmod + 1);\n"); + + printf("} else {\n"); +#endif + if (a_is_on) printf("uae_u32 preva = 0;\n"); + if (b_is_on) printf("uae_u32 prevb = 0, srcb = b->bltbhold;\n"); + printf("uae_u32 srcc = b->bltcdat;\n"); + printf("uae_u32 dstd=0;\n"); + printf("uaecptr dstp = 0;\n"); + printf("for (j = 0; j < b->vblitsize; j++) {\n"); + printf("\tfor (i = 0; i < b->hblitsize; i++) {\n\t\tuae_u32 bltadat, srca;\n"); + if (c_is_on) printf("\t\tif (ptc) { srcc = chipmem_wget (ptc); ptc -= 2; }\n"); + if (b_is_on) printf("\t\tif (ptb) {\n\t\t\tuae_u32 bltbdat = blt_info.bltbdat = chipmem_wget (ptb); ptb -= 2;\n"); + if (b_is_on) printf("\t\t\tsrcb = ((bltbdat << 16) | prevb) >> b->blitdownbshift;\n"); + if (b_is_on) printf("\t\t\tprevb = bltbdat;\n\t\t}\n"); + if (a_is_on) printf("\t\tif (pta) { bltadat = blt_info.bltadat = chipmem_wget (pta); pta -= 2; } else { bltadat = blt_info.bltadat; }\n"); + if (a_is_on) printf("\t\tbltadat &= blit_masktable[i];\n"); + if (a_is_on) printf("\t\tsrca = (((uae_u32)bltadat << 16) | preva) >> b->blitdownashift;\n"); + if (a_is_on) printf("\t\tpreva = bltadat;\n"); + printf("\t\tif (dstp) chipmem_wput (dstp, dstd);\n"); + printf("\t\tdstd = (%s) & 0xFFFF;\n", blitops[blttbl[i]].s); + printf("\t\ttotald |= dstd;\n"); + printf("\t\tif (ptd) { dstp = ptd; ptd -= 2; }\n"); + printf("\t}\n"); + if (a_is_on) printf("\tif (pta) pta -= b->bltamod;\n"); + if (b_is_on) printf("\tif (ptb) ptb -= b->bltbmod;\n"); + if (c_is_on) printf("\tif (ptc) ptc -= b->bltcmod;\n"); + printf("\tif (ptd) ptd -= b->bltdmod;\n"); + printf("}\n"); + if (b_is_on) printf("b->bltbhold = srcb;\n"); + printf("b->bltcdat = srcc;\n"); + printf("\t\tif (dstp) chipmem_wput (dstp, dstd);\n"); +#if 0 + printf("}\n"); +#endif + printf("if (totald != 0) b->blitzero = 0;\n"); + printf("}\n"); + } +} + +static void generate_table(void) +{ + unsigned int index = 0; + unsigned int i; + printf("#include \"sysconfig.h\"\n"); + printf("#include \"sysdeps.h\"\n"); + printf("#include \"config.h\"\n"); + printf("#include \"options.h\"\n"); + printf("#include \"custom.h\"\n"); + printf("#include \"memory.h\"\n"); + printf("#include \"blitter.h\"\n"); + printf("#include \"blitfunc.h\"\n\n"); + printf("blitter_func *blitfunc_dofast[256] = {\n"); + for (i = 0; i < 256; i++) { + if (index < sizeof(blttbl) && i == blttbl[index]) { + printf("blitdofast_%x",i); + index++; + } + else printf("0"); + if (i < 255) printf(", "); + if ((i & 7) == 7) printf("\n"); + } + printf("};\n\n"); + + index = 0; + printf("blitter_func *blitfunc_dofast_desc[256] = {\n"); + for (i = 0; i < 256; i++) { + if (index < sizeof(blttbl) && i == blttbl[index]) { + printf("blitdofast_desc_%x",i); + index++; + } + else printf("0"); + if (i < 255) printf(", "); + if ((i & 7) == 7) printf("\n"); + } + printf("};\n"); +} + +static void generate_header(void) +{ + unsigned int i; + for (i = 0; i < sizeof(blttbl); i++) { + printf("extern blitter_func blitdofast_%x;\n",blttbl[i]); + printf("extern blitter_func blitdofast_desc_%x;\n",blttbl[i]); + } +} + +int main(int argc, char **argv) +{ + char mode = 'i'; + + if (argc == 2) mode = *argv[1]; + switch (mode) { + case 'i': generate_include(); + break; + case 'f': generate_func(); + break; + case 't': generate_table(); + break; + case 'h': generate_header(); + break; + default: abort(); + } + return 0; +} + diff --git a/gencomp.c b/gencomp.c new file mode 100755 index 00000000..9d381336 --- /dev/null +++ b/gencomp.c @@ -0,0 +1,3118 @@ +/* + * UAE - The Un*x Amiga Emulator + * + * MC68000 compilation generator + * + * Based on work Copyright 1995, 1996 Bernd Schmidt. Changes Copyright 2000 + * Bernd Meyer + */ + +#include "sysconfig.h" +#include "sysdeps.h" +#include + +#include "readcpu.h" + +#include +#include + +#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 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; +} diff --git a/gencpu.c b/gencpu.c new file mode 100755 index 00000000..81f597d0 --- /dev/null +++ b/gencpu.c @@ -0,0 +1,3147 @@ +/* + * UAE - The Un*x Amiga Emulator + * + * MC68000 emulation generator + * + * This is a fairly stupid program that generates a lot of case labels that + * can be #included in a switch statement. + * As an alternative, it can generate functions that handle specific + * MC68000 instructions, plus a prototype header file and a function pointer + * array to look up the function for an opcode. + * Error checking is bad, an illegal table68k file will cause the program to + * call abort(). + * The generated code is sometimes sub-optimal, an optimizing compiler should + * take care of this. + * + * The source for the insn timings is Markt & Technik's Amiga Magazin 8/1992. + * + * Copyright 1995, 1996, 1997, 1998, 1999, 2000 Bernd Schmidt + */ + +#include "sysconfig.h" +#include "sysdeps.h" +#include + +#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,"#.B"); + break; + case sz_word: + strcpy (buffer,"#.W"); + break; + case sz_long: + strcpy (buffer,"#.L"); + break; + default: + break; + } + break; + case imm0: + strcpy (buffer,"#.B"); + break; + case imm1: + strcpy (buffer,"#.W"); + break; + case imm2: + strcpy (buffer,"#.L"); + break; + case immi: + strcpy (buffer,"#"); + break; + + default: + break; + } + return buffer; +} + +static char *outopcode (int opcode) +{ + static char out[100]; + struct instr *ins; + int i; + + ins = &table68k[opcode]; + for (i = 0; lookuptab[i].name[0]; i++) { + if (ins->mnemo == lookuptab[i].mnemo) + break; + } + strcpy (out, lookuptab[i].name); + if (ins->size == sz_byte) + strcat (out,".B"); + if (ins->size == sz_word) + strcat (out,".W"); + if (ins->size == sz_long) + strcat (out,".L"); + strcat (out," "); + if (ins->suse) + strcat (out, decodeEA (ins->smode, ins->size)); + if (ins->duse) { + if (ins->suse) strcat (out,","); + strcat (out, decodeEA (ins->dmode, ins->size)); + } + return out; +} + +static void generate_one_opcode (int rp) +{ + int i; + uae_u16 smsk, dmsk; + long int opcode = opcode_map[rp]; + + if (table68k[opcode].mnemo == i_ILLG + || table68k[opcode].clev > cpu_level) + return; + + for (i = 0; lookuptab[i].name[0]; i++) { + if (table68k[opcode].mnemo == lookuptab[i].mnemo) + break; + } + + if (table68k[opcode].handler != -1) + return; + + if (opcode_next_clev[rp] != cpu_level) { + fprintf (stblfile, "{ CPUFUNC(op_%04lx_%d), 0, %ld }, /* %s */\n", opcode, opcode_last_postfix[rp], + opcode, lookuptab[i].name); + return; + } + fprintf (stblfile, "{ CPUFUNC(op_%04lx_%d), 0, %ld }, /* %s */\n", opcode, postfix, opcode, lookuptab[i].name); + fprintf (headerfile, "extern cpuop_func op_%04lx_%d_nf;\n", opcode, postfix); + fprintf (headerfile, "extern cpuop_func op_%04lx_%d_ff;\n", opcode, postfix); + printf ("/* %s */\n", outopcode (opcode)); + printf ("unsigned long REGPARAM2 CPUFUNC(op_%04lx_%d)(uae_u32 opcode)\n{\n", opcode, postfix); + + switch (table68k[opcode].stype) { + case 0: smsk = 7; break; + case 1: smsk = 255; break; + case 2: smsk = 15; break; + case 3: smsk = 7; break; + case 4: smsk = 7; break; + case 5: smsk = 63; break; + case 7: smsk = 3; break; + default: abort (); + } + dmsk = 7; + + next_cpu_level = -1; + if (table68k[opcode].suse + && table68k[opcode].smode != imm && table68k[opcode].smode != imm0 + && table68k[opcode].smode != imm1 && table68k[opcode].smode != imm2 + && table68k[opcode].smode != absw && table68k[opcode].smode != absl + && table68k[opcode].smode != PC8r && table68k[opcode].smode != PC16) + { + if (table68k[opcode].spos == -1) { + if (((int) table68k[opcode].sreg) >= 128) + printf ("\tuae_u32 srcreg = (uae_s32)(uae_s8)%d;\n", (int) table68k[opcode].sreg); + else + printf ("\tuae_u32 srcreg = %d;\n", (int) table68k[opcode].sreg); + } else { + char source[100]; + int pos = table68k[opcode].spos; + + if (pos) + sprintf (source, "((opcode >> %d) & %d)", pos, smsk); + else + sprintf (source, "(opcode & %d)", smsk); + + if (table68k[opcode].stype == 3) + printf ("\tuae_u32 srcreg = imm8_table[%s];\n", source); + else if (table68k[opcode].stype == 1) + printf ("\tuae_u32 srcreg = (uae_s32)(uae_s8)%s;\n", source); + else + printf ("\tuae_u32 srcreg = %s;\n", source); + } + } + if (table68k[opcode].duse + /* Yes, the dmode can be imm, in case of LINK or DBcc */ + && table68k[opcode].dmode != imm && table68k[opcode].dmode != imm0 + && table68k[opcode].dmode != imm1 && table68k[opcode].dmode != imm2 + && table68k[opcode].dmode != absw && table68k[opcode].dmode != absl) + { + if (table68k[opcode].dpos == -1) { + if (((int) table68k[opcode].dreg) >= 128) + printf ("\tuae_u32 dstreg = (uae_s32)(uae_s8)%d;\n", (int) table68k[opcode].dreg); + else + printf ("\tuae_u32 dstreg = %d;\n", (int) table68k[opcode].dreg); + } else { + int pos = table68k[opcode].dpos; +#if 0 + /* Check that we can do the little endian optimization safely. */ + if (pos < 8 && (dmsk >> (8 - pos)) != 0) + abort (); +#endif + if (pos) + printf ("\tuae_u32 dstreg = (opcode >> %d) & %d;\n", + pos, dmsk); + else + printf ("\tuae_u32 dstreg = opcode & %d;\n", dmsk); + } + } + need_endlabel = 0; + endlabelno++; + sprintf (endlabelstr, "endlabel%d", endlabelno); + gen_opcode (opcode); + if (need_endlabel) + printf ("%s: ;\n", endlabelstr); + returncycles ("", insn_n_cycles); + if (using_ce) + printf ("return 0;\n"); + printf ("}\n"); + opcode_next_clev[rp] = next_cpu_level; + opcode_last_postfix[rp] = postfix; +} + +static void generate_func (void) +{ + int j, rp; + + /* sam: this is for people with low memory (eg. me :)) */ + printf ("\n" + "#if !defined(PART_1) && !defined(PART_2) && " + "!defined(PART_3) && !defined(PART_4) && " + "!defined(PART_5) && !defined(PART_6) && " + "!defined(PART_7) && !defined(PART_8)" + "\n" + "#define PART_1 1\n" + "#define PART_2 1\n" + "#define PART_3 1\n" + "#define PART_4 1\n" + "#define PART_5 1\n" + "#define PART_6 1\n" + "#define PART_7 1\n" + "#define PART_8 1\n" + "#endif\n\n"); + + rp = 0; + for(j=1;j<=8;++j) { + int k = (j*nr_cpuop_funcs)/8; + printf ("#ifdef PART_%d\n",j); + for (; rp < k; rp++) + generate_one_opcode (rp); + printf ("#endif\n\n"); + } + + fprintf (stblfile, "{ 0, 0, 0 }};\n"); +} + +int main (int argc, char **argv) +{ + int i, rp; + char fname[100]; + + read_table68k (); + do_merges (); + + opcode_map = (int *) xmalloc (sizeof (int) * nr_cpuop_funcs); + opcode_last_postfix = (int *) xmalloc (sizeof (int) * nr_cpuop_funcs); + opcode_next_clev = (int *) xmalloc (sizeof (int) * nr_cpuop_funcs); + counts = (unsigned long *) xmalloc (65536 * sizeof (unsigned long)); + read_counts (); + + /* It would be a lot nicer to put all in one file (we'd also get rid of + * cputbl.h that way), but cpuopti can't cope. That could be fixed, but + * I don't dare to touch the 68k version. */ + + headerfile = fopen ("cputbl.h", "wb"); + + stblfile = fopen ("cpustbl.c", "wb"); + generate_includes (stblfile); + + using_prefetch = 0; + using_exception_3 = 1; + using_ce = 0; + + for (i = 0; i < 7; i++) { + postfix = i; + if (i == 0 || i == 5 || i == 6) { + if (i > 0) + fprintf (stblfile,"#endif\n"); + fprintf (stblfile, "#ifdef CPUEMU_%d\n", postfix); + sprintf (fname, "cpuemu_%d.c", postfix); + freopen (fname, "wb", stdout); + generate_includes (stdout); + } + cpu_level = 4 - i; + if (i == 5 || i == 6) { + cpu_level = 0; + using_prefetch = 1; + using_exception_3 = 1; + if (i == 6) using_ce = 1; + for (rp = 0; rp < nr_cpuop_funcs; rp++) + opcode_next_clev[rp] = 0; + } + fprintf (stblfile, "struct cputbl CPUFUNC(op_smalltbl_%d)[] = {\n", postfix); + generate_func (); + } + fprintf (stblfile,"#endif\n"); + + free (table68k); + return 0; +} diff --git a/gengenblitter.c b/gengenblitter.c new file mode 100755 index 00000000..a5659bf3 --- /dev/null +++ b/gengenblitter.c @@ -0,0 +1,452 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Optimized blitter minterm function generator + * + * Copyright 1995,1996 Bernd Schmidt + * Copyright 1996 Alessandro Bissacco + * + * Overkill, n: cf. genblitter + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" + +static void nop(int); + +#define xmalloc malloc +#define xfree free +#define xrealloc realloc + +typedef struct tree_n { + enum tree_op { op_and, op_or, op_xor, op_not, op_a, op_b, op_c, op_d, op_e, op_f } op; + struct tree_n *left, *right; +} *tree; + +static struct tree_n TRA = { op_a, NULL, NULL }; +static struct tree_n TRB = { op_b, NULL, NULL }; +static struct tree_n TRC = { op_c, NULL, NULL }; +static struct tree_n TRD = { op_d, NULL, NULL }; +static struct tree_n TRE = { op_e, NULL, NULL }; +static struct tree_n TRF = { op_f, NULL, NULL }; +static tree tree_a = &TRA; +static tree tree_b = &TRB; +static tree tree_c = &TRC; +static tree tree_d = &TRD; +static tree tree_e = &TRE; +static tree tree_f = &TRF; + +typedef struct { + tree *trees; + int space; + int ntrees; +} tree_vec; + +STATIC_INLINE int issrc (tree t) +{ + return t == tree_a || t == tree_b || t == tree_c || t == tree_d || t == tree_e || t == tree_f; +} + +static tree new_op_tree(enum tree_op op, tree l, tree r) +{ + tree t; + if (op == op_not && l->op == op_not) { + t = l->left; + xfree(l); + return t; + } + t = (tree)xmalloc(sizeof(struct tree_n)); + t->left = l; + t->right = r; + t->op = op; + return t; +} + +static int opidx (tree t) +{ + switch (t->op) { + case op_a: + return 0; + case op_b: + return 1; + case op_c: + return 2; + case op_d: + return 3; + case op_e: + return 4; + case op_f: + return 5; + default: + return -1; + } +} + +static int tree_cst (tree t, unsigned int *src, unsigned int *notsrc) +{ + int idx = opidx (t); + if (idx >= 0) { + src[idx] = 1; + return 0; + } + switch (t->op) { + case op_not: + idx = opidx (t->left); + if (idx >= 0) { + notsrc[idx] = 1; + return 3; + } + return 3 + tree_cst (t->left, src, notsrc); + + case op_and: + case op_xor: + case op_or: + return 4 + tree_cst (t->left, src, notsrc) + tree_cst (t->right, src, notsrc); + + default: + abort (); + } +} + +static int tree_cost (tree t) +{ + int i, cost; + unsigned int src[6], notsrc[6]; + memset (src, 0, sizeof src); + memset (notsrc, 0, sizeof notsrc); + + cost = tree_cst (t, src, notsrc); + for (i = 0; i < 6; i++) + if (src[i] && notsrc[i]) + cost++; + return cost; +} + +static int add_vec(tree_vec *tv, tree t) +{ + int i; +#if 0 + if (! tree_isnormal(t)) + nop(2); +#endif + if (tv->ntrees == tv->space) { + tv->trees = (tree *)xrealloc(tv->trees, sizeof(tree)*(tv->space += 40)); + } + tv->trees[tv->ntrees++] = t; + + return 1; +} + +static void init_vec(tree_vec *tv) +{ + tv->ntrees = tv->space = 0; + tv->trees = NULL; +} + +static void do_sprint_tree (char *s, tree t) +{ + enum tree_op op = t->op; + switch (op) { + case op_a: + strcat (s, "srca"); + break; + case op_b: + strcat (s, "srcb"); + break; + case op_c: + strcat (s, "srcc"); + break; + case op_d: + strcat (s, "srcd"); + break; + case op_e: + strcat (s, "srce"); + break; + case op_f: + strcat (s, "srcf"); + break; + + case op_and: + case op_or: + case op_xor: + { + + char *c = op == op_and ? " & " : op == op_or ? " | " : " ^ "; + strcat (s, "("); + do_sprint_tree (s, t->left); + strcat (s, c); + while (t->right->op == op) { + t = t->right; + do_sprint_tree (s, t->left); + strcat (s, c); + } + do_sprint_tree(s, t->right); + strcat (s, ")"); + } + break; + + case op_not: + strcat (s, "~"); + do_sprint_tree (s, t->left); + break; + } +} + +static tree_vec size_trees[20]; + +static struct tree_n bad_tree = { op_and, &bad_tree, &bad_tree }; + +static unsigned int used_mask[256]; +static tree best_trees[256]; +static unsigned int best_cost[256]; +static int n_unknown; + +static unsigned long which_fn (tree t) +{ + switch (t->op) { + case op_a: + return 0xf0; + case op_b: + return 0xcc; + case op_c: + return 0xaa; + case op_and: + return which_fn (t->left) & which_fn (t->right); + case op_or: + return which_fn (t->left) | which_fn (t->right); + case op_xor: + return which_fn (t->left) ^ which_fn (t->right); + case op_not: + return 0xFF & ~which_fn (t->left); + default: + abort (); + } +} + +static unsigned long tree_used_mask (tree t) +{ + switch (t->op) { + case op_a: + return 1; + case op_b: + return 2; + case op_c: + return 4; + case op_and: + case op_or: + case op_xor: + return tree_used_mask (t->left) | tree_used_mask (t->right); + case op_not: + return tree_used_mask (t->left); + default: + abort (); + } +} + +static void candidate (tree_vec *v, tree t) +{ + unsigned long fn = which_fn (t); + unsigned int cost = tree_cost (t); + if (best_trees[fn] == 0) + n_unknown--; + if (cost < best_cost[fn]) + best_trees[fn] = t, best_cost[fn] = cost; + add_vec (v, t); +} + +static void cand_and_not (tree_vec *v, tree t) +{ + candidate (v, t); + t = new_op_tree (op_not, t, 0); + candidate (v, t); +} + +static void try_tree (tree_vec *v, tree t) +{ + int fnl = which_fn (t->left); + int fnr = which_fn (t->right); + int fn = which_fn (t); + if (fn == fnl + || fn == fnr + || fn == 0 + || fn == 0xFF + || (tree_used_mask (t) & ~used_mask[fn]) != 0 + || best_cost[fn] + 6 < tree_cost (t)) + { + xfree (t); + return; + } + cand_and_not (v, t); +} + +static void find_best_trees (void) +{ + int i, size, do_stop; + for (i = 0; i < 256; i++) { + best_trees[i] = i == 0 || i == 255 ? &bad_tree : 0; + best_cost[i] = 65535; + } + n_unknown = 254; + + init_vec (size_trees); + cand_and_not (size_trees, tree_a); + cand_and_not (size_trees, tree_b); + cand_and_not (size_trees, tree_c); + + do_stop = 0; + for (size = 2; ! do_stop && size < 20; size++) { + int split, last_split; + tree_vec *sv = size_trees + size - 1; + + if (n_unknown == 0) + do_stop = 1; + last_split = (size >> 1) + 1; + for (split = 1; split < last_split; split++) { + int szl = split; + int szr = size - split; + tree_vec *lv = size_trees + szl - 1; + tree_vec *rv = size_trees + szr - 1; + int i; + + for (i = 0; i < lv->ntrees; i++) { + tree l = lv->trees[i]; + int j; + for (j = szl == szr ? i + 1 : 0; j < rv->ntrees; j++) { + tree r = rv->trees[j]; + + if (l->op != op_and || r->op != op_and) { + tree tmp = (l->op == op_and + ? new_op_tree (op_and, r, l) + : new_op_tree (op_and, l, r)); + try_tree (sv, tmp); + } + if (l->op != op_or || r->op != op_or) { + tree tmp = (l->op == op_or + ? new_op_tree (op_or, r, l) + : new_op_tree (op_or, l, r)); + try_tree (sv, tmp); + } + if (l->op != op_xor || r->op != op_xor) { + tree tmp = (l->op == op_xor + ? new_op_tree (op_xor, r, l) + : new_op_tree (op_xor, l, r)); + try_tree (sv, tmp); + } + } + } + } + /* An additional pass doesn't seem to create better solutions + * (not that much of a surprise). */ + if (n_unknown == 0) + do_stop = 1; + } +} + +static int bitset (int mt, int bit) +{ + return mt & (1 << bit); +} + +static unsigned int generate_expr (int minterm) +{ + int bits = 0; + int i; + int expr_dc[8], nexp = 0; + int expr_used[8]; + + if (minterm == 0 || minterm == 0xFF) + return 0; + + for (i = 0; i < 8; i++) { + if (bitset (minterm, i) && !bitset (bits, i)) { + int j; + int dontcare = 0; + int firstand = 1; + int bitbucket[8], bitcount; + + bits |= 1< + +#include "sysconfig.h" +#include "sysdeps.h" + +/* We can't include custom.h here. */ +#define MAX_WORDS_PER_LINE 50 + + +static char *gen_ind (char *a, int b) +{ + char buf[200]; + sprintf (buf, "%d(%s)", b, a); + return strdup (buf); +} + +static char *gen_indx (char *a, int b, char *c, int d) +{ + char buf[200]; + sprintf (buf, "%d(%s,%s,%d)", b, a, c, d); + return strdup (buf); +} + +static char *gen_indsx (char *a, char *sym, int b, char *c, int d) +{ + char buf[200]; + sprintf (buf, "%s+%d(%s,%s,%d)", sym, b, a, c, d); + return strdup (buf); +} + +#define reg(a) "%" a +#define ind(a,b) #b"("a")" +#define imm(a) "$"#a +#ifdef USE_UNDERSCORE +#define sym(a) "_"#a +#else +#define sym(a) #a +#endif +#define indx(a,b,c,d) #b"("a","c","#d")" +#define indsx(a,s,b,c,d) s"+"#b"("a","c","#d")" + +static int labelno = 0; + +static int get_label (void) +{ + return labelno++; +} +static void declare_label (int nr) +{ + printf (".L%d:\n", nr); +} +static int new_label (void) +{ + int nr = get_label (); + declare_label (nr); + return nr; +} +static void gen_label (int nr) { printf (".L%d", nr); } +static void jnz (int nr) { printf ("\tjnz "); gen_label (nr); printf ("\n"); } +static void jnc (int nr) { printf ("\tjnc "); gen_label (nr); printf ("\n"); } +static void jc (int nr) { printf ("\tjc "); gen_label (nr); printf ("\n"); } +static void jmp (int nr) { printf ("\tjmp "); gen_label (nr); printf ("\n"); } +static void movl (char *src, char *dst) { printf ("\tmovl %s,%s\n", src, dst); } +static void movw (char *src, char *dst) { printf ("\tmovl %s,%s\n", src, dst); } +static void movb (char *src, char *dst) { printf ("\tmovl %s,%s\n", src, dst); } +static void movzbl (char *src, char *dst) { printf ("\tmovzbl %s,%s\n", src, dst); } +static void leal (char *src, char *dst) { printf ("\tleal %s,%s\n", src, dst); } +static void addl (char *src, char *dst) { printf ("\taddl %s,%s\n", src, dst); } +static void subl (char *src, char *dst) { printf ("\tsubl %s,%s\n", src, dst); } +static void cmpl (char *src, char *dst) { printf ("\tcmpl %s,%s\n", src, dst); } +static void andl (unsigned long mask, char *dst) { printf ("\tandl $0x%0lx,%s\n", mask, dst); } +static void orl (char *src, char *dst) { printf ("\torl %s,%s\n", src, dst); } +static void imull (unsigned long val, char *dst) { printf ("\timull $0x%08lx,%s\n", val, dst); } +static void decl (char *dst) { printf ("\tdecl %s\n", dst); } +static void incl (char *dst) { printf ("\tincl %s\n", dst); } +static void bswapl (char *dst) { printf ("\tbswap %s\n", dst); } +static void shrl (int count, char *dst) { printf ("\tshrl $%d,%s\n", count, dst); } +static void shll (int count, char *dst) { printf ("\tshll $%d,%s\n", count, dst); } +static void pushl (char *src) { printf ("\tpushl %s\n", src); } +static void popl (char *dst) { printf ("\tpopl %s\n", dst); } +static void ret (void) { printf ("\tret\n"); } +static void align (int a) { printf ("\t.p2align %d,0x90\n", a); } + +static void shiftleftl (int count, char *dst) +{ + if (count == 0) + return; + if (count < 0) + shrl (-count, dst); + else { + char *indb0; + switch (count) { + case 1: + addl (dst, dst); + break; + case 2: case 3: + indb0 = gen_indx ("", 0, dst, 1 << count); + leal (indb0, dst); + free (indb0); + break; + default: + shll (count, dst); + } + } +} + +static void declare_fn (char *name) +{ + printf ("\t.globl %s\n", name); +/* printf ("\t.type %s,@function\n", name); */ + align (5); + printf ("%s:\n", name); +} + +#define esi reg("esi") +#define edi reg("edi") +#define ebp reg("ebp") +#define esp reg("esp") +#define eax reg("eax") +#define ebx reg("ebx") +#define ecx reg("ecx") +#define edx reg("edx") + +/* Modes: + * 0: normal + * 1: only generate every second plane, set memory + * 2: only generate every second plane, starting at second plane, or to memory + */ + +/* Normal code: one pixel per bit */ +static void gen_x86_set_hires_h_toobad_k6_too_slow_someone_try_this_with_a_ppro (int pl, int mode) +{ + int plmul = mode == 0 ? 1 : 2; + int ploff = mode == 2 ? 1 : 0; + int i; + int loop; + char buf[40]; + char *indb0; + + sprintf (buf, sym (set_hires_h_%d_%d), pl, mode); + declare_fn (buf); + + pushl (ebp); + pushl (esi); + pushl (edi); + pushl (ebx); + + if (pl == 0) { + movl (ind (esp, 20), ebp); + movl (ind (esp, 24), esi); + } + movl (imm (0), edi); + + loop = get_label (); + jmp (loop); + align (5); + declare_label (loop); + + if (pl > 0) + movl (ind (esp, 24), esi); + if (mode == 2) { + if (pl > 0) + movl (ind (esp, 20), ebp); + movl (indx (ebp, 0, edi, 8), ecx); + movl (indx (ebp, 4, edi, 8), ebx); + } + for (i = 0; i <= pl; i+=2) { + int realpl = i * plmul + ploff; + char *data1 = (i == 0 && mode != 2 ? ecx : edx); + char *data2 = (i == 0 && mode != 2 ? ebx : eax); + + if (i < pl) { + indb0 = gen_indx (esi, (realpl + plmul)*MAX_WORDS_PER_LINE*2, edi, 1); + movzbl (indb0, ebp); + free (indb0); + imull (0x08040201, ebp); + } + + indb0 = gen_indx (esi, realpl*MAX_WORDS_PER_LINE*2, edi, 1); + movzbl (indb0, data2); + free (indb0); + + if (i == pl || i == pl - 1) + incl (edi); + imull (0x08040201, data2); + if (i < pl) { + movl (ebp, esi); + andl (0x08080808, ebp); + shiftleftl (realpl + plmul - 7, esi); + } + movl (data2, data1); + andl (0x08080808, data2); + shiftleftl (realpl - 7, data1); + if (i < pl) { + andl (0x01010101 << (realpl + plmul), esi); + } + andl (0x01010101 << realpl, data1); + shiftleftl (realpl - 3, data2); + if (i < pl) { + shiftleftl (realpl + plmul - 3, ebp); + } + if (i < pl) { + orl (esi, ecx); + movl (ind (esp, 24), esi); + orl (ebp, ebx); + } + if (i > 0 || mode == 2) { + orl (edx, ecx); + orl (eax, ebx); + } + } + if (pl > 0) + movl (ind (esp, 20), ebp); + cmpl (ind (esp, 28), edi); + movl (ecx, indx (ebp, -8, edi, 8)); + movl (ebx, indx (ebp, -4, edi, 8)); + jc (loop); + + popl (reg ("ebx")); + popl (reg ("edi")); + popl (reg ("esi")); + popl (reg ("ebp")); + ret (); + printf ("\n\n"); +} + +static void gen_x86_set_hires_h (int pl, int mode) +{ + int plmul = mode == 0 ? 1 : 2; + int ploff = mode == 2 ? 1 : 0; + int i; + int loop; + char buf[40]; + char *indb0; + + sprintf (buf, sym (set_hires_h_%d_%d), pl, mode); + declare_fn (buf); + + pushl (ebp); + pushl (esi); + pushl (edi); + pushl (ebx); + + if (pl == 0) { + movl (ind (esp, 20), ebp); + movl (ind (esp, 24), esi); + } + movl (imm (0), edi); + + loop = get_label (); + jmp (loop); + align (5); + declare_label (loop); + + if (pl > 0) + movl (ind (esp, 24), esi); + if (mode == 2) { + if (pl > 0) + movl (ind (esp, 20), ebp); + movl (indx (ebp, 0, edi, 8), ecx); + movl (indx (ebp, 4, edi, 8), ebx); + } + for (i = 0; i <= pl; i+=2) { + int realpl = i * plmul + ploff; + char *data1 = (i == 0 && mode != 2 ? ecx : edx); + char *data2 = (i == 0 && mode != 2 ? ebx : eax); + + if (i < pl) { + indb0 = gen_indx (esi, (realpl + plmul)*MAX_WORDS_PER_LINE*2, edi, 1); + movzbl (indb0, ebp); + free (indb0); + } + indb0 = gen_indx (esi, realpl*MAX_WORDS_PER_LINE*2, edi, 1); + movzbl (indb0, data2); + free (indb0); + if (i < pl) { + indb0 = gen_indsx ("", sym (hirestab_h), 0, ebp, 8); + movl (indb0, esi); + free (indb0); + indb0 = gen_indsx ("", sym (hirestab_h), 4, ebp, 8); + movl (indb0, ebp); + free (indb0); + } + if (i == pl || i == pl - 1) + incl (edi); + indb0 = gen_indsx ("", sym (hirestab_h), 0, data2, 8); + movl (indb0, data1); + free (indb0); + indb0 = gen_indsx ("", sym (hirestab_h), 4, data2, 8); + movl (indb0, data2); + free (indb0); + switch (realpl) { + case 0: + if (i < pl) { + addl (esi, esi); + addl (ebp, ebp); + if (plmul == 2) { + addl (esi, esi); + addl (ebp, ebp); + } + } + break; + case 1: + if (i < pl) { + indb0 = gen_indx ("", 0, esi, 4*plmul); + leal (indb0, esi); + free (indb0); + indb0 = gen_indx ("", 0, ebp, 4*plmul); + leal (indb0, ebp); + free (indb0); + } + addl (data1, data1); + addl (data2, data2); + break; + case 2: + if (i < pl) { + if (plmul == 1) + leal (indx ("", 0, esi, 8), esi); + else + shll (4, esi); + } + addl (data1, data1); + addl (data2, data2); + if (i < pl) { + if (plmul == 1) + leal (indx ("", 0, ebp, 8), ebp); + else + shll (4, ebp); + } + addl (data1, data1); + addl (data2, data2); + break; + case 3: + if (i < pl) + shll (3 + plmul, esi); + indb0 = gen_indx ("", 0, data1, 8); + leal (indb0, data1); + free (indb0); + if (i < pl) + shll (3 + plmul, ebp); + indb0 = gen_indx ("", 0, data2, 8); + leal (indb0, data2); + free (indb0); + break; + case 4: case 5: case 6: case 7: + shll (realpl, data1); + shll (realpl, data2); + if (i < pl) { + shll (realpl+plmul, esi); + shll (realpl+plmul, ebp); + } + break; + } + + if (i < pl) { + orl (esi, ecx); + orl (ebp, ebx); + if (i + 2 <= pl) + movl (ind (esp, 24), esi); + } + if (i + 2 > pl && pl > 0) + movl (ind (esp, 20), ebp); + if (i > 0 || mode == 2) { + orl (data1, ecx); + orl (data2, ebx); + } + } + + cmpl (ind (esp, 28), edi); + movl (ecx, indx (ebp, -8, edi, 8)); + movl (ebx, indx (ebp, -4, edi, 8)); + jc (loop); + + popl (reg ("ebx")); + popl (reg ("edi")); + popl (reg ("esi")); + popl (reg ("ebp")); + ret (); + printf ("\n\n"); +} + +/* Squeeze: every second bit does not generate a pixel + Not optimized, this mode isn't useful. */ +static void gen_x86_set_hires_l (int pl, int mode) +{ + int plmul = mode == 0 ? 1 : 2; + int ploff = mode == 2 ? 1 : 0; + int i; + int loop; + char buf[40]; + + sprintf (buf, sym (set_hires_l_%d_%d), pl, mode); + declare_fn (buf); + + pushl (ebp); + pushl (esi); + pushl (edi); + pushl (ebx); + + movl (ind (esp, 20), ebp); + movl (ind (esp, 24), esi); + movl (imm (0), edi); + + align (5); + loop = new_label (); + + if (mode == 2) { + movl (indx (ebp, 0, edi, 1), ecx); + } + + for (i = 0; i <= pl; i++) { + int realpl = i * plmul + ploff; + char *data1 = (i == 0 && mode != 2 ? ecx : edx); + char *indb0; + + indb0 = gen_indx (esi, realpl*MAX_WORDS_PER_LINE*2, edi, 1); + movzbl (indb0, data1); + free (indb0); + + indb0 = gen_indsx ("", sym (hirestab_l), 0, data1, 4); + movl (indb0, data1); + free (indb0); + if (i == pl) + incl (edi); + shiftleftl (realpl, data1); + if (i > 0 || mode == 2) { + orl (data1, ecx); + } + } + cmpl (ind (esp, 28), edi); + movl (ecx, indx (ebp, -4, edi, 4)); + jc (loop); + + popl (reg ("ebx")); + popl (reg ("edi")); + popl (reg ("esi")); + popl (reg ("ebp")); + ret (); + printf ("\n\n"); +} + +/* Stretch: two pixels per bit */ +static void gen_x86_set_lores_h (int pl, int mode) +{ + int plmul = mode == 0 ? 1 : 2; + int ploff = mode == 2 ? 1 : 0; + int i, j; + int loop; + char buf[40]; + + sprintf (buf, sym (set_lores_h_%d_%d), pl, mode); + declare_fn (buf); + + pushl (ebp); + pushl (esi); + pushl (edi); + pushl (ebx); + + movl (ind (esp, 20), ebp); + movl (ind (esp, 24), esi); + movl (imm (0), edi); + + align (5); + loop = new_label (); + + for (j = 0; j < 2; j++) { + if (mode == 2) { + movl (j ? ind (ebp, 8) : ind (ebp, 0), ecx); + movl (j ? ind (ebp, 12) : ind (ebp, 4), ebx); + } + + for (i = 0; i <= pl; i++) { + int realpl = i * plmul + ploff; + char *data1 = (i == 0 && mode != 2 ? ecx : edx); + char *data2 = (i == 0 && mode != 2 ? ebx : eax); + char *indb0; + + indb0 = gen_indx (esi, realpl*MAX_WORDS_PER_LINE*2, edi, 1); + movzbl (indb0, data2); + free (indb0); + addl (data2, data2); + indb0 = gen_indsx ("", sym (lorestab_h), 0 + j*8, data2, 8); + movl (indb0, data1); + free (indb0); + indb0 = gen_indsx ("", sym (lorestab_h), 4 + j*8, data2, 8); + movl (indb0, data2); + free (indb0); + shiftleftl (realpl, data1); + shiftleftl (realpl, data2); + if (i > 0 || mode == 2) { + orl (data1, ecx); + orl (data2, ebx); + } + } + movl (ecx, j ? ind (ebp, 8) : ind (ebp, 0)); + movl (ebx, j ? ind (ebp, 12) : ind (ebp, 4)); + } + incl (edi); + cmpl (ind (esp, 28), edi); + leal (ind (ebp, 16), ebp); + jc (loop); + + popl (reg ("ebx")); + popl (reg ("edi")); + popl (reg ("esi")); + popl (reg ("ebp")); + ret (); + printf ("\n\n"); +} + + +/* Normal code: one pixel per bit */ +static void gen_c_set_hires_h (int pl, int mode, int header) +{ + int plmul = mode == 0 ? 1 : 2; + int ploff = mode == 2 ? 1 : 0; + int i; + + if (header) + printf("extern "); + printf ("void set_hires_h_%d_%d (uae_u32 *app, uae_u8 *ptr, int len)", pl, mode); + if (header) { + printf (";\n"); + return; + } + + printf ("\n\{\n\tint i;\n\tfor (i = 0; i < len; i++) {\n\t\tuae_u32 v1, v2;\n"); + + if (mode == 2) { + printf ("\t\tv1 = app[i*2 + 0]; v2 = app[i*2 + 1];\n"); + } + + for (i = 0; i <= pl; i++) { + int realpl = i * plmul + ploff; + char *asgn = (i == 0 && mode != 2 ? "=" : "|="); + + printf ("\t\t{\n"); + printf ("\t\t\tunsigned int data = *(ptr + i + %d);\n", MAX_WORDS_PER_LINE*2*realpl); + + printf ("\t\t\tv1 %s hirestab_h[data][0] << %d;\n", asgn, realpl); + printf ("\t\t\tv2 %s hirestab_h[data][1] << %d;\n", asgn, realpl); + printf ("\t\t}\n"); + } + printf ("\t\tapp[i*2 + 0] = v1;\n"); + printf ("\t\tapp[i*2 + 1] = v2;\n"); + printf ("\t}\n"); + printf ("}\n\n"); +} + +/* Squeeze: every second bit does not generate a pixel + Not optimized, this mode isn't useful. */ +static void gen_c_set_hires_l (int pl, int mode, int header) +{ + int plmul = mode == 0 ? 1 : 2; + int ploff = mode == 2 ? 1 : 0; + int i; + + if (header) + printf("extern "); + printf ("void set_hires_l_%d_%d (uae_u32 *app, uae_u8 *ptr, int len)", pl, mode); + if (header) { + printf (";\n"); + return; + } + + printf ("\n\{\n\tint i;\n\tfor (i = 0; i < len; i++) {\n\t\tuae_u32 v1;\n"); + + if (mode == 2) { + printf ("\t\tv1 = app[i];\n"); + } + + for (i = 0; i <= pl; i++) { + int realpl = i * plmul + ploff; + char *asgn = (i == 0 && mode != 2 ? "=" : "|="); + + printf ("\t\t{\n"); + printf ("\t\t\tunsigned int data = *(ptr + i + %d);\n", MAX_WORDS_PER_LINE*2*realpl); + + printf ("\t\t\tv1 %s hirestab_l[data][0] << %d;\n", asgn, realpl); + printf ("\t\t}\n"); + } + printf ("\t\tapp[i] = v1;\n"); + printf ("\t}\n"); + printf ("}\n\n"); +} + +/* Stretch: two pixels per bit */ +static void gen_c_set_lores_h (int pl, int mode, int header) +{ + int plmul = mode == 0 ? 1 : 2; + int ploff = mode == 2 ? 1 : 0; + int i; + + if (header) + printf("extern "); + printf ("void set_lores_h_%d_%d (uae_u32 *app, uae_u8 *ptr, int len)", pl, mode); + if (header) { + printf (";\n"); + return; + } + + printf ("\n\{\n\tint i;\n\tfor (i = 0; i < len; i++) {\n\t\tuae_u32 v1, v2, v3, v4;\n"); + + if (mode == 2) { + printf ("\t\tv1 = app[i*4 + 0]; v2 = app[i*4 + 1]; v3 = app[i*4 + 2]; v4 = app[i*4 + 3];\n"); + } + + for (i = 0; i <= pl; i++) { + int realpl = i * plmul + ploff; + char *asgn = (i == 0 && mode != 2 ? "=" : "|="); + + printf ("\t\t{\n"); + printf ("\t\t\tunsigned int data = *(ptr + i + %d);\n", MAX_WORDS_PER_LINE*2*realpl); + + printf ("\t\t\tv1 %s lorestab_h[data][0] << %d;\n", asgn, realpl); + printf ("\t\t\tv2 %s lorestab_h[data][1] << %d;\n", asgn, realpl); + printf ("\t\t\tv3 %s lorestab_h[data][2] << %d;\n", asgn, realpl); + printf ("\t\t\tv4 %s lorestab_h[data][3] << %d;\n", asgn, realpl); + printf ("\t\t}\n"); + } + printf ("\t\tapp[i*4 + 0] = v1;\n"); + printf ("\t\tapp[i*4 + 1] = v2;\n"); + printf ("\t\tapp[i*4 + 2] = v3;\n"); + printf ("\t\tapp[i*4 + 3] = v4;\n"); + printf ("\t}\n"); + printf ("}\n\n"); +} + +int main(int argc, char **argv) +{ + int pl; + int outmode; + + if (argc != 2) + return 1; + if (strcmp (argv[1], "C") == 0) + outmode = 0; + else if (strcmp (argv[1], "H") == 0) + outmode = 1; + else if (strcmp (argv[1], "x86") == 0) + outmode = 2; + else + return 1; + + switch (outmode) { + case 0: + printf ("#include \"sysconfig.h\"\n"); + printf ("#include \"sysdeps.h\"\n"); + printf ("#include \"custom.h\"\n"); + printf ("#include \"p2c.h\"\n"); + break; + case 1: + printf ("#define MAX_WORDS_PER_LINE %d\n", MAX_WORDS_PER_LINE); + break; + case 2: + printf ("#define MAX_WORDS_PER_LINE %d\n", MAX_WORDS_PER_LINE); + printf (".text\n"); + break; + } + for (pl = 0; pl < 8; pl++) { + int j; + for (j = 0; j < (pl < 4 ? 3 : 1); j++) { + switch (outmode) { + case 0: case 1: + gen_c_set_hires_h (pl, j, outmode); + gen_c_set_hires_l (pl, j, outmode); + gen_c_set_lores_h (pl, j, outmode); + break; + case 2: + gen_x86_set_hires_h (pl, j); + gen_x86_set_hires_l (pl, j); + gen_x86_set_lores_h (pl, j); + break; + } + } + } + + return 0; +} diff --git a/gfxlib.c b/gfxlib.c new file mode 100755 index 00000000..8c821ad9 --- /dev/null +++ b/gfxlib.c @@ -0,0 +1,1682 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * graphics.library emulation + * + * Copyright 1996, 1997 Bernd Schmidt + * + * Ideas for this: + * Rewrite layers completely. When there are lots of windows on the screen + * it can take 3 minutes to update everything after resizing or moving one + * (at least with Kick 1.3). Hide the internal structure of the layers as far + * as possible, keep most of the data in emulator space so we save copying/ + * conversion time. Programs really shouldn't do anything directly with the + * Layer or ClipRect structures. + * This means that a lot of graphics.library functions will have to be + * rewritten as well. + * Once that's done, add support for non-planar bitmaps. Conveniently, the + * struct Bitmap has an unused pad field which we could abuse as some sort of + * type field. Need to add chunky<->planar conversion routines to get it + * going, plus variants of all the drawing functions for speed reasons. + * + * When it becomes necessary to convert a structure from Amiga memory, make + * a function with a name ending in ..FA, which takes a pointer to the + * native structure and a uaecptr and returns the native pointer. + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include + +#include "config.h" +#include "options.h" +#include "threaddep/thread.h" +#include "memory.h" +#include "custom.h" +#include "newcpu.h" +#include "xwin.h" +#include "autoconf.h" +#include "osemu.h" +#include "osdep/exectasks.h" + +#ifdef USE_EXECLIB + +/* Uniq list management. Should be in a separate file. */ +struct uniq_head { + struct uniq_head *next; + uae_u32 uniq; +}; + +typedef struct { + struct uniq_head *head; + uae_u32 uniq; +} uniq_list; + +#define UNIQ_INIT { NULL, 1 } + +static void init_uniq(uniq_list *list) +{ + list->head = NULL; + list->uniq = 1; +} + +static struct uniq_head *find_uniq (uniq_list *a, uae_u32 uniq) +{ + struct uniq_head *b = a->head; + while (b && b->uniq != uniq) + b = b->next; + if (!b) + write_log("Couldn't find structure. Bad\n"); + return b; +} + +static struct uniq_head *find_and_rem_uniq (uniq_list *a, uae_u32 uniq) +{ + struct uniq_head **b = &a->head, *c; + while (*b && (*b)->uniq != uniq) + b = &(*b)->next; + c = *b; + if (!c) + write_log("Couldn't find structure. Bad\n"); + else + *b = c->next; + return c; +} + +static void add_uniq (uniq_list *a, struct uniq_head *item, uaecptr amem) +{ + item->uniq = a->uniq++; + put_long(amem, item->uniq); + if (a->uniq == 0) + a->uniq++; + item->next = a->head; + a->head = item; +} + +/* Graphics stuff begins here */ +#define CLIPRECT_SIZE 40 +#define LAYER_SIZE 160 +#define LINFO_SIZE 102 + +static uaecptr gfxbase, layersbase; + +static void do_LockLayer(uaecptr layer) +{ +#if 0 /* Later.. */ + uaecptr sigsem = layer + 72; + m68k_areg(regs, 0) = sigsem; + CallLib(get_long(4), -564); +#else + m68k_areg(regs, 1) = layer; + CallLib(layersbase, -96); +#endif +} + +static void do_UnlockLayer(uaecptr layer) +{ + m68k_areg(regs, 0) = layer; + CallLib(layersbase, -102); +} + +static uae_u32 gfxlibname, layerslibname; + +struct Rectangle { + int MinX, MinY, MaxX, MaxY; +}; + +static int GFX_PointInRectangle(uaecptr rect, int x, int y) +{ + uae_s16 minx = get_word(rect); + uae_s16 miny = get_word(rect+2); + uae_s16 maxx = get_word(rect+4); + uae_s16 maxy = get_word(rect+6); + + if (x < minx || x > maxx || y < miny || y > maxy) + return 0; + return 1; +} + +static int GFX_RectContainsRect(struct Rectangle *r1, struct Rectangle *r2) +{ + return (r2->MinX >= r1->MinX && r2->MaxX <= r1->MaxX + && r2->MinY >= r1->MinY && r2->MaxY <= r1->MaxY); +} + +static struct Rectangle *GFX_RectFA(struct Rectangle *rp, uaecptr rect) +{ + rp->MinX = (uae_s16)get_word(rect); + rp->MinY = (uae_s16)get_word(rect+2); + rp->MaxX = (uae_s16)get_word(rect+4); + rp->MaxY = (uae_s16)get_word(rect+6); + return rp; +} + +static int GFX_Bitmap_WritePixel(uaecptr bitmap, int x, int y, uaecptr rp) +{ + int i, offs; + unsigned int bpr = get_word (bitmap); + unsigned int rows = get_word (bitmap + 2); + uae_u16 mask; + + uae_u8 planemask = get_byte(rp + 24); + uae_u8 fgpen = get_byte(rp + 25); + uae_u8 bgpen = get_byte(rp + 26); + uae_u8 drmd = get_byte(rp + 28); + uae_u8 pen = drmd & 4 ? bgpen : fgpen; + + if (x < 0 || y < 0 || x >= 8*bpr || y >= rows) + return -1; + + offs = y*bpr + (x & ~15)/8; + + for (i = 0; i < get_byte (bitmap + 5); i++) { + uaecptr planeptr; + uae_u16 data; + + if ((planemask & (1 << i)) == 0) + continue; + + planeptr = get_long(bitmap + 8 + i*4); + data = get_word(planeptr + offs); + + mask = 0x8000 >> (x & 15); + + if (drmd & 2) { + if ((pen & (1 << i)) != 0) + data ^=mask; + } else { + data &= ~mask; + if ((pen & (1 << i)) != 0) + data |= mask; + } + put_word(planeptr + offs, data); + } + return 0; +} + +int GFX_WritePixel(uaecptr rp, int x, int y) +{ + int v; + uaecptr layer = get_long(rp); + uaecptr bitmap = get_long(rp + 4); + uaecptr cliprect; + int x2, y2; + + if (bitmap == 0) { + write_log ("bogus RastPort in WritePixel\n"); + return -1; + } + + /* Easy case first */ + if (layer == 0) { + return GFX_Bitmap_WritePixel(bitmap, x, y, rp); + } + do_LockLayer(layer); + /* + * Now, in theory we ought to obtain the semaphore. + * Since we don't, the programs will happily write into the raster + * even though we are currently moving the window around. + * Not good. + */ + + x2 = x + (uae_s16)get_word(layer + 16); + y2 = y + (uae_s16)get_word(layer + 18); + + if (!GFX_PointInRectangle (layer + 16, x2, y2)) { + do_UnlockLayer(layer); + return -1; + } + /* Find the right ClipRect */ + cliprect = get_long(layer + 8); + while (cliprect != 0 && !GFX_PointInRectangle (cliprect + 16, x2, y2)) + cliprect = get_long(cliprect); + if (cliprect == 0) { + /* Don't complain: The "Dots" demo does this all the time. I + * suppose if we can't find a ClipRect, we aren't supposed to draw + * the dot. + */ + /*write_log ("Weirdness in WritePixel\n");*/ + v = -1; + } else if (get_long(cliprect + 8) == 0) { + v = GFX_Bitmap_WritePixel(bitmap, x2, y2, rp); + } else if (get_long(cliprect + 12) == 0) { + /* I don't really know what to do here... */ + v = 0; + } else { + /* This appears to be normal for smart refresh layers which are obscured */ + v = GFX_Bitmap_WritePixel (get_long(cliprect + 12), x2 - (uae_s16)get_word(cliprect + 16), + y2 - (uae_s16)get_word(cliprect + 18), rp); + } + do_UnlockLayer(layer); + return v; +} + + +static uae_u32 gfxl_WritePixel(void) { return GFX_WritePixel(m68k_areg(regs, 1), (uae_s16)m68k_dreg(regs, 0), (uae_s16)m68k_dreg(regs, 1)); } + +static uae_u32 gfxl_BltClear(void) +{ + uaecptr mem=m68k_areg(regs, 1); + uae_u8 *mptr = chipmem_bank.xlateaddr(m68k_areg(regs, 1)); + uae_u32 count=m68k_dreg(regs, 0); + uae_u32 flags=m68k_dreg(regs, 1); + unsigned int i; + uae_u32 pattern; + + if ((flags & 2) == 2){ + /* count is given in Rows / Bytes per row */ + count=(count & 0xFFFF) * (count >> 16); + } + + if ((mem & 1) != 0 || (count & 1) != 0) + write_log ("gfx: BltClear called with odd parameters\n"); + + /* Bit 2 set means use pattern (V36+ only, but we might as well emulate + * it always) */ + if ((flags & 4) == 0) + pattern = 0; + else + pattern= ((flags >> 16) & 0xFFFF) | (flags & 0xFFFF0000ul); + + if ((pattern & 0xFF) == ((pattern >> 8) & 0xFF)) { + memset(mptr, pattern, count); + return 0; + } + + for(i = 0; i < count; i += 4) + chipmem_bank.lput(mem+i, pattern); + + if ((count & 3) != 0) + chipmem_bank.wput(mem + i - 4, pattern); + + return 0; +} + +static uae_u32 gfxl_BltBitmap(void) +{ + uaecptr srcbitmap = m68k_areg(regs, 0), dstbitmap = m68k_areg(regs, 1); + int srcx = (uae_s16)m68k_dreg(regs, 0), srcy = (uae_s16)m68k_dreg(regs, 1); + int dstx = (uae_s16)m68k_dreg(regs, 2), dsty = (uae_s16)m68k_dreg(regs, 3); + int sizex = (uae_s16)m68k_dreg(regs, 4), sizey = (uae_s16)m68k_dreg(regs, 5); + uae_u8 minterm = (uae_u8)m68k_dreg(regs, 6), mask = m68k_dreg(regs, 7); + return 0; /* sam: a return was missing here ! */ +} + +static uaecptr amiga_malloc(int len) +{ + m68k_dreg(regs, 0) = len; + m68k_dreg(regs, 1) = 1; /* MEMF_PUBLIC */ + return CallLib(get_long(4), -198); /* AllocMem */ +} + +static void amiga_free(uaecptr addr, int len) +{ + m68k_areg(regs, 1) = addr; + m68k_dreg(regs, 0) = len; + CallLib(get_long(4), -210); /* FreeMem */ +} + +/* + * Region handling code + * + * General ideas stolen from xc/verylongpath/miregion.c + * + * The Clear code is untested. And and Or seem to work, Xor is only used + * by the 1.3 Prefs program and seems to work, too. + */ + +struct RegionRectangle { + struct RegionRectangle *Next,*Prev; + struct Rectangle bounds; +}; + +struct Region { + struct Rectangle bounds; + struct RegionRectangle *RegionRectangle; +}; + +struct RectList { + int count; + int space; + struct Rectangle bounds; + struct Rectangle *rects; +}; + +struct BandList { + int count; + int space; + int *miny, *maxy; +}; + +static void init_bandlist(struct BandList *bl) +{ + bl->count = 0; + bl->space = 20; + bl->miny = (int *)malloc(20*sizeof(int)); + bl->maxy = (int *)malloc(20*sizeof(int)); +} + +static void dup_bandlist(struct BandList *to, struct BandList *from) +{ + to->count = from->count; + to->space = to->count+4; + to->miny = (int *)malloc (to->space*sizeof(int)); + to->maxy = (int *)malloc (to->space*sizeof(int)); + memcpy(to->miny, from->miny, to->count*sizeof(int)); + memcpy(to->maxy, from->maxy, to->count*sizeof(int)); +} + +STATIC_INLINE void add_band(struct BandList *bl, int miny, int maxy, int pos) +{ + if (bl->count == bl->space) { + bl->space += 20; + bl->miny = (int *)realloc(bl->miny, bl->space*sizeof(int)); + bl->maxy = (int *)realloc(bl->maxy, bl->space*sizeof(int)); + } + memmove(bl->miny + pos + 1, bl->miny + pos, (bl->count - pos) * sizeof(int)); + memmove(bl->maxy + pos + 1, bl->maxy + pos, (bl->count - pos) * sizeof(int)); + bl->count++; + bl->miny[pos] = miny; + bl->maxy[pos] = maxy; +} + +static void init_rectlist(struct RectList *rl) +{ + rl->count = 0; + rl->space = 100; + rl->bounds.MinX = rl->bounds.MinY = rl->bounds.MaxX = rl->bounds.MaxY = 0; + rl->rects = (struct Rectangle *)malloc(100*sizeof(struct Rectangle)); +} + +static void dup_rectlist(struct RectList *to, struct RectList *from) +{ + to->count = from->count; + to->space = to->count+4; + to->bounds = from->bounds; + to->rects = (struct Rectangle *)malloc (to->space*sizeof(struct Rectangle)); + memcpy(to->rects, from->rects, to->count*sizeof(struct Rectangle)); +} + +STATIC_INLINE void add_rect(struct RectList *rl, struct Rectangle r) +{ + if (rl->count == 0) + rl->bounds = r; + else { + if (r.MinX < rl->bounds.MinX) + rl->bounds.MinX = r.MinX; + if (r.MinY < rl->bounds.MinY) + rl->bounds.MinY = r.MinY; + if (r.MaxX > rl->bounds.MaxX) + rl->bounds.MaxX = r.MaxX; + if (r.MaxY > rl->bounds.MaxY) + rl->bounds.MaxY = r.MaxY; + } + if (rl->count == rl->space) { + rl->space += 100; + rl->rects = (struct Rectangle *)realloc(rl->rects, rl->space*sizeof(struct Rectangle)); + } + rl->rects[rl->count++] = r; +} + +STATIC_INLINE void rem_rect(struct RectList *rl, int num) +{ + rl->count--; + if (num == rl->count) + return; + rl->rects[num] = rl->rects[rl->count]; +} + +static void free_rectlist(struct RectList *rl) +{ + free(rl->rects); +} + +static void free_bandlist(struct BandList *bl) +{ + free(bl->miny); + free(bl->maxy); +} + +static int regionrect_cmpfn(const void *a, const void *b) +{ + struct Rectangle *ra = (struct Rectangle *)a; + struct Rectangle *rb = (struct Rectangle *)b; + + if (ra->MinY < rb->MinY) + return -1; + if (ra->MinY > rb->MinY) + return 1; + if (ra->MinX < rb->MinX) + return -1; + if (ra->MinX > rb->MinX) + return 1; + if (ra->MaxX < rb->MaxX) + return -1; + return 1; +} + +STATIC_INLINE int min(int x, int y) +{ + return x < y ? x : y; +} + +STATIC_INLINE int max(int x, int y) +{ + return x > y ? x : y; +} + +static void add_rect_to_bands(struct BandList *bl, struct Rectangle *rect) +{ + int j; + struct Rectangle tmpr = *rect; + + for (j = 0; j < bl->count; j++) { + /* Is the current band before the rectangle? */ + if (bl->maxy[j] < tmpr.MinY) + continue; + /* Band already present? */ + if (bl->miny[j] == tmpr.MinY && bl->maxy[j] == tmpr.MaxY) + break; + /* Completely new band? Add it */ + if (bl->miny[j] > tmpr.MaxY) { + add_band(bl, tmpr.MinY, tmpr.MaxY, j); + break; + } + /* Now we know that the bands are overlapping. + * See whether they match in one point */ + if (bl->miny[j] == tmpr.MinY) { + int t; + if (bl->maxy[j] < tmpr.MaxY) { + /* Rectangle exceeds band */ + tmpr.MinY = bl->maxy[j]+1; + continue; + } + /* Rectangle splits band */ + t = bl->maxy[j]; + bl->maxy[j] = tmpr.MaxY; + tmpr.MinY = bl->maxy[j] + 1; + tmpr.MaxY = t; + continue; + } else if (bl->maxy[j] == tmpr.MaxY) { + int t; + if (bl->miny[j] > tmpr.MinY) { + /* Rectangle exceeds band */ + t = bl->miny[j]; + bl->miny[j] = tmpr.MinY; + bl->maxy[j] = t-1; + tmpr.MinY = t; + continue; + } + /* Rectangle splits band */ + bl->maxy[j] = tmpr.MinY - 1; + continue; + } + /* Bands overlap and match in no points. Get a new band and align */ + if (bl->miny[j] > tmpr.MinY) { + /* Rectangle begins before band, so make a new band before + * and adjust rectangle */ + add_band(bl, tmpr.MinY, bl->miny[j] - 1, j); + tmpr.MinY = bl->miny[j+1]; + } else { + /* Rectangle begins in band */ + add_band(bl, bl->miny[j], tmpr.MinY - 1, j); + bl->miny[j+1] = tmpr.MinY; + } + continue; + } + if (j == bl->count) + add_band(bl, tmpr.MinY, tmpr.MaxY, j); +} + +static void region_addbands(struct RectList *rl, struct BandList *bl) +{ + int i,j; + + for (i = 0; i < rl->count; i++) { + add_rect_to_bands(bl, rl->rects + i); + } +} + +static void merge_bands(struct BandList *dest, struct BandList *src) +{ + int i; + for (i = 0; i < src->count; i++) { + struct Rectangle tmp; + tmp.MinY = src->miny[i]; + tmp.MaxY = src->maxy[i]; + add_rect_to_bands(dest, &tmp); + } +} + +static void region_splitrects_band(struct RectList *rl, struct BandList *bl) +{ + int i,j; + for (i = 0; i < rl->count; i++) { + for (j = 0; j < bl->count; j++) { + if (bl->miny[j] == rl->rects[i].MinY && bl->maxy[j] == rl->rects[i].MaxY) + break; + if (rl->rects[i].MinY > bl->maxy[j]) + continue; + if (bl->miny[j] == rl->rects[i].MinY) { + struct Rectangle tmpr; + tmpr.MinX = rl->rects[i].MinX; + tmpr.MaxX = rl->rects[i].MaxX; + tmpr.MinY = bl->maxy[j] + 1; + tmpr.MaxY = rl->rects[i].MaxY; + add_rect(rl, tmpr); /* will be processed later */ + rl->rects[i].MaxY = bl->maxy[j]; + break; + } + write_log ("Foo..\n"); + } + } + qsort(rl->rects, rl->count, sizeof (struct Rectangle), regionrect_cmpfn); +} + +static void region_coalesce_rects(struct RectList *rl, int do_2nd_pass) +{ + int i,j; + + /* First pass: Coalesce horizontally */ + for (i = j = 0; i < rl->count;) { + int offs = 1; + while (i + offs < rl->count) { + if (rl->rects[i].MinY != rl->rects[i+offs].MinY + || rl->rects[i].MaxY != rl->rects[i+offs].MaxY + || rl->rects[i].MaxX+1 < rl->rects[i+offs].MinX) + break; + rl->rects[i].MaxX = rl->rects[i+offs].MaxX; + offs++; + } + rl->rects[j++] = rl->rects[i]; + i += offs; + } + rl->count = j; + + if (!do_2nd_pass) + return; + + /* Second pass: Coalesce bands */ + for (i = 0; i < rl->count;) { + int match = 0; + for (j = i + 1; j < rl->count; j++) + if (rl->rects[i].MinY != rl->rects[j].MinY) + break; + if (j < rl->count && rl->rects[i].MaxY + 1 == rl->rects[j].MinY) { + int k; + match = 1; + for (k = 0; i+k < j; k++) { + if (j+k >= rl->count + || rl->rects[j+k].MinY != rl->rects[j].MinY) + { + match = 0; break; + } + if (rl->rects[i+k].MinX != rl->rects[j+k].MinX + || rl->rects[i+k].MaxX != rl->rects[j+k].MaxX) + { + match = 0; + break; + } + } + if (j+k < rl->count && rl->rects[j+k].MinY == rl->rects[j].MinY) + match = 0; + if (match) { + for (k = 0; i+k < j; k++) + rl->rects[i+k].MaxY = rl->rects[j].MaxY; + memmove(rl->rects + j, rl->rects + j + k, (rl->count - j - k)*sizeof(struct Rectangle)); + rl->count -= k; + } + } + if (!match) + i = j; + } +} + +static int copy_rects (uaecptr region, struct RectList *rl) +{ + uaecptr regionrect; + int numrects = 0; + struct Rectangle b; + regionrect = get_long(region+8); + b.MinX = get_word(region); + b.MinY = get_word(region+2); + b.MaxX = get_word(region+4); + b.MaxY = get_word(region+6); + + while (regionrect != 0) { + struct Rectangle tmpr; + + tmpr.MinX = (uae_s16)get_word(regionrect+8) + b.MinX; + tmpr.MinY = (uae_s16)get_word(regionrect+10) + b.MinY; + tmpr.MaxX = (uae_s16)get_word(regionrect+12) + b.MinX; + tmpr.MaxY = (uae_s16)get_word(regionrect+14) + b.MinY; + add_rect(rl, tmpr); + regionrect = get_long(regionrect); + numrects++; + } + return numrects; +} + +static int rect_in_region(struct RectList *rl, struct Rectangle *r) +{ + int i; + int miny = r->MinY; + + for (i = 0; i < rl->count; i++) { + int j; + if (rl->rects[i].MaxY < miny) + continue; + if (rl->rects[i].MinY > miny) + break; + if (rl->rects[i].MaxX < r->MinX) + continue; + if (rl->rects[i].MinX > r->MaxX) + break; + /* Overlap! */ + j = i; + for (;;) { + if (rl->rects[j].MaxX > r->MaxX) { + miny = rl->rects[i].MaxY + 1; + break; + } + j++; + if (j == rl->count) + break; + if (rl->rects[j].MinX != rl->rects[j-1].MaxX+1) + break; + if (rl->rects[i].MinY != rl->rects[j].MinY) + break; + } + if (miny <= rl->rects[i].MaxY) + break; + } + return 0; +} + +typedef void (*regionop)(struct RectList *,struct RectList *,struct RectList *); + +static void region_do_ClearRegionRegion(struct RectList *rl1,struct RectList *rl2, + struct RectList *rl3) +{ + int i,j; + + for (i = j = 0; i < rl2->count && j < rl1->count;) { + struct Rectangle tmpr; + + while ((rl1->rects[j].MinY < rl2->rects[i].MinY + || (rl1->rects[j].MinY == rl2->rects[i].MinY + && rl1->rects[j].MaxX < rl2->rects[i].MinX)) + && j < rl1->count) + j++; + if (j >= rl1->count) + break; + while ((rl1->rects[j].MinY > rl2->rects[i].MinY + || (rl1->rects[j].MinY == rl2->rects[i].MinY + && rl1->rects[j].MinX > rl2->rects[i].MaxX)) + && i < rl2->count) + { + add_rect(rl3, rl2->rects[i]); + i++; + } + if (i >= rl2->count) + break; + + tmpr = rl2->rects[i]; + + while (i < rl2->count && j < rl1->count + && rl1->rects[j].MinY == tmpr.MinY + && rl2->rects[i].MinY == tmpr.MinY + && rl1->rects[j].MinX <= rl2->rects[i].MaxX + && rl1->rects[j].MaxX >= rl2->rects[i].MinX) + { + int oldmin = tmpr.MinX; + int oldmax = tmpr.MaxX; + if (tmpr.MinX < rl1->rects[j].MinX) { + tmpr.MaxX = rl1->rects[j].MinX - 1; + add_rect(rl3, tmpr); + } + if (oldmax <= rl1->rects[j].MaxX) { + i++; + if (i < rl2->count && rl2->rects[i].MinY == tmpr.MinY) + tmpr = rl2->rects[i]; + } else { + tmpr.MinX = rl1->rects[j].MaxX + 1; + tmpr.MaxX = oldmax; + j++; + } + } + } + for(; i < rl2->count; i++) + add_rect(rl3, rl2->rects[i]); +} + +static void region_do_AndRegionRegion(struct RectList *rl1,struct RectList *rl2, + struct RectList *rl3) +{ + int i,j; + + for (i = j = 0; i < rl2->count && j < rl1->count;) { + while ((rl1->rects[j].MinY < rl2->rects[i].MinY + || (rl1->rects[j].MinY == rl2->rects[i].MinY + && rl1->rects[j].MaxX < rl2->rects[i].MinX)) + && j < rl1->count) + j++; + if (j >= rl1->count) + break; + while ((rl1->rects[j].MinY > rl2->rects[i].MinY + || (rl1->rects[j].MinY == rl2->rects[i].MinY + && rl1->rects[j].MinX > rl2->rects[i].MaxX)) + && i < rl2->count) + i++; + if (i >= rl2->count) + break; + if (rl1->rects[j].MinY == rl2->rects[i].MinY + && rl1->rects[j].MinX <= rl2->rects[i].MaxX + && rl1->rects[j].MaxX >= rl2->rects[i].MinX) + { + /* We have an intersection! */ + struct Rectangle tmpr; + tmpr = rl2->rects[i]; + if (tmpr.MinX < rl1->rects[j].MinX) + tmpr.MinX = rl1->rects[j].MinX; + if (tmpr.MaxX > rl1->rects[j].MaxX) + tmpr.MaxX = rl1->rects[j].MaxX; + add_rect(rl3, tmpr); + if (rl1->rects[j].MaxX == rl2->rects[i].MaxX) + i++, j++; + else if (rl1->rects[j].MaxX > rl2->rects[i].MaxX) + i++; + else + j++; + } + } +} + +static void region_do_OrRegionRegion(struct RectList *rl1,struct RectList *rl2, + struct RectList *rl3) +{ + int i,j; + + for (i = j = 0; i < rl2->count && j < rl1->count;) { + while ((rl1->rects[j].MinY < rl2->rects[i].MinY + || (rl1->rects[j].MinY == rl2->rects[i].MinY + && rl1->rects[j].MaxX < rl2->rects[i].MinX)) + && j < rl1->count) + { + add_rect(rl3, rl1->rects[j]); + j++; + } + if (j >= rl1->count) + break; + while ((rl1->rects[j].MinY > rl2->rects[i].MinY + || (rl1->rects[j].MinY == rl2->rects[i].MinY + && rl1->rects[j].MinX > rl2->rects[i].MaxX)) + && i < rl2->count) + { + add_rect(rl3, rl2->rects[i]); + i++; + } + if (i >= rl2->count) + break; + if (rl1->rects[j].MinY == rl2->rects[i].MinY + && rl1->rects[j].MinX <= rl2->rects[i].MaxX + && rl1->rects[j].MaxX >= rl2->rects[i].MinX) + { + /* We have an intersection! */ + struct Rectangle tmpr; + tmpr = rl2->rects[i]; + if (tmpr.MinX > rl1->rects[j].MinX) + tmpr.MinX = rl1->rects[j].MinX; + if (tmpr.MaxX < rl1->rects[j].MaxX) + tmpr.MaxX = rl1->rects[j].MaxX; + i++; j++; + for (;;) { + int cont = 0; + if (j < rl1->count && rl1->rects[j].MinY == tmpr.MinY + && tmpr.MaxX+1 >= rl1->rects[j].MinX) { + if (tmpr.MaxX < rl1->rects[j].MaxX) + tmpr.MaxX = rl1->rects[j].MaxX; + j++; cont = 1; + } + if (i < rl2->count && rl2->rects[i].MinY == tmpr.MinY + && tmpr.MaxX+1 >= rl2->rects[i].MinX) { + if (tmpr.MaxX < rl2->rects[i].MaxX) + tmpr.MaxX = rl2->rects[i].MaxX; + i++; cont = 1; + } + if (!cont) + break; + } + add_rect(rl3, tmpr); + } + } + for(; i < rl2->count; i++) + add_rect(rl3, rl2->rects[i]); + for(; j < rl1->count; j++) + add_rect(rl3, rl1->rects[j]); +} + +static void region_do_XorRegionRegion(struct RectList *rl1,struct RectList *rl2, + struct RectList *rl3) +{ + int i,j; + + for (i = j = 0; i < rl2->count && j < rl1->count;) { + struct Rectangle tmpr1, tmpr2; + + while ((rl1->rects[j].MinY < rl2->rects[i].MinY + || (rl1->rects[j].MinY == rl2->rects[i].MinY + && rl1->rects[j].MaxX < rl2->rects[i].MinX)) + && j < rl1->count) + { + add_rect(rl3, rl1->rects[j]); + j++; + } + if (j >= rl1->count) + break; + while ((rl1->rects[j].MinY > rl2->rects[i].MinY + || (rl1->rects[j].MinY == rl2->rects[i].MinY + && rl1->rects[j].MinX > rl2->rects[i].MaxX)) + && i < rl2->count) + { + add_rect(rl3, rl2->rects[i]); + i++; + } + if (i >= rl2->count) + break; + + tmpr2 = rl2->rects[i]; + tmpr1 = rl1->rects[j]; + + while (i < rl2->count && j < rl1->count + && rl1->rects[j].MinY == tmpr1.MinY + && rl2->rects[i].MinY == tmpr1.MinY + && rl1->rects[j].MinX <= rl2->rects[i].MaxX + && rl1->rects[j].MaxX >= rl2->rects[i].MinX) + { + int oldmin2 = tmpr2.MinX; + int oldmax2 = tmpr2.MaxX; + int oldmin1 = tmpr1.MinX; + int oldmax1 = tmpr1.MaxX; + int need_1 = 0, need_2 = 0; + + if (tmpr2.MinX > tmpr1.MinX && tmpr2.MaxX < tmpr1.MaxX) + { + /* + * ########### + * **** + */ + tmpr1.MaxX = tmpr2.MinX - 1; + add_rect(rl3, tmpr1); + tmpr1.MaxX = oldmax1; + tmpr1.MinX = tmpr2.MaxX + 1; + add_rect(rl3, tmpr1); + need_2 = 1; + } else if (tmpr2.MinX > tmpr1.MinX && tmpr2.MaxX > tmpr1.MaxX) { + /* + * ########## + * ********* + */ + tmpr1.MaxX = tmpr2.MinX - 1; + add_rect(rl3, tmpr1); + tmpr2.MinX = oldmax1 + 1; + add_rect(rl3, tmpr2); + need_1 = 1; + } else if (tmpr2.MinX < tmpr1.MinX && tmpr2.MaxX < tmpr1.MaxX) { + /* + * ########## + * ********* + */ + tmpr2.MaxX = tmpr1.MinX - 1; + add_rect(rl3, tmpr2); + tmpr1.MinX = oldmax2 + 1; + add_rect(rl3, tmpr1); + need_2 = 1; + } else if (tmpr2.MinX < tmpr1.MinX && tmpr2.MaxX > tmpr1.MaxX) { + /* + * ### + * ********* + */ + tmpr2.MaxX = tmpr1.MinX - 1; + add_rect(rl3, tmpr2); + tmpr2.MaxX = oldmax2; + tmpr2.MinX = tmpr1.MaxX + 1; + add_rect(rl3, tmpr2); + need_1 = 1; + } else if (tmpr1.MinX == tmpr2.MinX && tmpr2.MaxX < tmpr1.MaxX) { + /* + * ############# + * ********* + */ + tmpr1.MinX = tmpr2.MaxX + 1; + need_2 = 1; + } else if (tmpr1.MinX == tmpr2.MinX && tmpr2.MaxX > tmpr1.MaxX) { + /* + * ######### + * ************* + */ + tmpr2.MinX = tmpr1.MaxX + 1; + need_1 = 1; + } else if (tmpr1.MinX < tmpr2.MinX && tmpr2.MaxX == tmpr1.MaxX) { + /* + * ############# + * ********* + */ + tmpr1.MaxX = tmpr2.MinX - 1; + add_rect(rl3, tmpr1); + need_2 = need_1 = 1; + } else if (tmpr1.MinX > tmpr2.MinX && tmpr2.MaxX == tmpr1.MaxX) { + /* + * ######### + * ************* + */ + tmpr2.MaxX = tmpr1.MinX - 1; + add_rect(rl3, tmpr2); + need_2 = need_1 = 1; + } else { + assert(tmpr1.MinX == tmpr2.MinX && tmpr2.MaxX == tmpr1.MaxX); + need_1 = need_2 = 1; + } + if (need_1) { + j++; + if (j < rl1->count && rl1->rects[j].MinY == tmpr1.MinY) + tmpr1 = rl1->rects[j]; + } + if (need_2) { + i++; + if (i < rl2->count && rl2->rects[i].MinY == tmpr2.MinY) + tmpr2 = rl2->rects[i]; + } + } + } + for(; i < rl2->count; i++) + add_rect(rl3, rl2->rects[i]); + for(; j < rl1->count; j++) + add_rect(rl3, rl1->rects[j]); +} + +static uae_u32 gfxl_perform_regionop(regionop op, int with_rect) +{ + int i,j,k; + uaecptr reg1; + uaecptr reg2; + uaecptr tmp, rpp; + struct RectList rl1, rl2, rl3; + struct BandList bl; + + int retval = 0; + int numrects2; + + init_rectlist(&rl1); init_rectlist(&rl2); init_rectlist(&rl3); + + if (with_rect) { + struct Rectangle tmpr; + reg2 = m68k_areg(regs, 0); + numrects2 = copy_rects(reg2, &rl2); + tmpr.MinX = get_word(m68k_areg(regs, 1)); + tmpr.MinY = get_word(m68k_areg(regs, 1) + 2); + tmpr.MaxX = get_word(m68k_areg(regs, 1) + 4); + tmpr.MaxY = get_word(m68k_areg(regs, 1) + 6); + add_rect(&rl1, tmpr); + } else { + reg1 = m68k_areg(regs, 0); + reg2 = m68k_areg(regs, 1); + + copy_rects(reg1, &rl1); + numrects2 = copy_rects(reg2, &rl2); + } + + init_bandlist(&bl); + region_addbands(&rl1, &bl); + region_addbands(&rl2, &bl); + region_splitrects_band(&rl1, &bl); + region_splitrects_band(&rl2, &bl); + region_coalesce_rects(&rl1, 0); + region_coalesce_rects(&rl2, 0); + + (*op)(&rl1, &rl2, &rl3); + region_coalesce_rects(&rl3, 1); + + rpp = reg2 + 8; + if (rl3.count < numrects2) { + while (numrects2-- != rl3.count) { + tmp = get_long(rpp); + put_long(rpp, get_long(tmp)); + amiga_free(tmp, 16); + } + if (rl3.count > 0) + put_long(get_long(rpp) + 4, rpp); + } else if (rl3.count > numrects2) { + while(numrects2++ != rl3.count) { + uaecptr prev = get_long(rpp); + tmp = amiga_malloc(16); + if (tmp == 0) + goto done; + put_long(tmp, prev); + put_long(tmp + 4, rpp); + if (prev != 0) + put_long(prev + 4, tmp); + put_long(rpp, tmp); + } + } + + if (rl3.count > 0) { + rpp = reg2 + 8; + for (i = 0; i < rl3.count; i++) { + uaecptr rr = get_long(rpp); + put_word(rr+8, rl3.rects[i].MinX - rl3.bounds.MinX); + put_word(rr+10, rl3.rects[i].MinY - rl3.bounds.MinY); + put_word(rr+12, rl3.rects[i].MaxX - rl3.bounds.MinX); + put_word(rr+14, rl3.rects[i].MaxY - rl3.bounds.MinY); + rpp = rr; + } + if (get_long(rpp) != 0) + write_log ("BUG\n"); + } + put_word(reg2+0, rl3.bounds.MinX); + put_word(reg2+2, rl3.bounds.MinY); + put_word(reg2+4, rl3.bounds.MaxX); + put_word(reg2+6, rl3.bounds.MaxY); + retval = 1; + + done: + free_rectlist(&rl1); free_rectlist(&rl2); free_rectlist(&rl3); + free_bandlist(&bl); + + return retval; +} + +static uae_u32 gfxl_AndRegionRegion(void) +{ + return gfxl_perform_regionop(region_do_AndRegionRegion, 0); +} +static uae_u32 gfxl_XorRegionRegion(void) +{ + return gfxl_perform_regionop(region_do_XorRegionRegion, 0); +} +static uae_u32 gfxl_OrRegionRegion(void) +{ + return gfxl_perform_regionop(region_do_OrRegionRegion, 0); +} + +static uae_u32 gfxl_ClearRectRegion(void) +{ + return gfxl_perform_regionop(region_do_ClearRegionRegion, 1); +} +static uae_u32 gfxl_OrRectRegion(void) +{ + return gfxl_perform_regionop(region_do_OrRegionRegion, 1); +} + +static uae_u32 gfxl_AndRectRegion(void) +{ + return gfxl_perform_regionop(region_do_AndRegionRegion, 1); +} + +static uae_u32 gfxl_XorRectRegion(void) +{ + return gfxl_perform_regionop(region_do_XorRegionRegion, 1); +} + + +/* Layers code */ + +static uae_u32 LY_TryLockLayer(uaecptr layer) +{ + uaecptr sigsem = layer + 72; + + m68k_areg(regs, 0) = sigsem; + return CallLib(get_long(4), -576); +} + +static void LY_LockLayer(uaecptr layer) +{ + uaecptr sigsem = layer + 72; + + m68k_areg(regs, 0) = sigsem; + CallLib(get_long(4), -564); +} + +static void LY_UnlockLayer(uaecptr layer) +{ + uaecptr sigsem = layer + 72; + + m68k_areg(regs, 0) = sigsem; + CallLib(get_long(4), -570); +} + +static void LY_LockLayerInfo(uaecptr li) +{ + uaecptr sigsem = li + 24; + + m68k_areg(regs, 0) = sigsem; + CallLib(get_long(4), -564); + put_byte(li+91, get_byte(li+91)+1); +} + +static void LY_UnlockLayerInfo(uaecptr li) +{ + uaecptr sigsem = li + 24; + + put_byte(li+91, get_byte(li+91)-1); + m68k_areg(regs, 0) = sigsem; + CallLib(get_long(4), -570); +} + +static void LY_LockLayers(uaecptr li) +{ + uaecptr l = get_long (li); + LY_LockLayerInfo(li); + while (l != 0) { + LY_LockLayer(l); + l = get_long(l); + } + LY_UnlockLayerInfo(li); +} + +static void LY_UnlockLayers(uaecptr li) +{ + uaecptr l = get_long (li); + LY_LockLayerInfo(li); + while (l != 0) { + LY_UnlockLayer(l); + l = get_long(l); + } + LY_UnlockLayerInfo(li); +} + +#define LAYER_CLUELESS 0x8000 /* Indicates we know nothing about the layer's regions. */ +#define LAYER_CR_CHANGED 0x4000 /* Indicates that the cliprects in Amiga memory need to be re-done */ +#define LAYER_REDO 0x2000 /* Indicates that we have regions, but they are bogus. */ + +static uae_u32 layer_uniq = 1; + +struct MyLayerInfo { + struct uniq_head head; + uaecptr amigaos_linfo; + uniq_list layer_list; +}; + +struct MyLayer { + struct uniq_head head; + uaecptr amigaos_layer, rastport; + struct Rectangle bounds; + struct RectList clipregion; + struct RectList obscured; + struct RectList visible; + struct BandList big_bands; /* created by obscuring layers */ + struct BandList small_bands; /* big_bands + those from clipregion */ + struct RectList damage; + struct BandList damage_bands; + struct MyLayerInfo *mli; +}; + +static uniq_list MyLayerInfo_list = UNIQ_INIT; + +static void LY_InitLayers(uaecptr li) +{ + memset (get_real_address(li), 0, 92); + put_long(li + 0, 0); /* top layer */ + put_long(li+84, 0); /* uniq: */ + m68k_areg(regs, 0) = li + 24; CallLib(get_long(4), -558); /* InitSemaphore() */ + put_word(li+88, 0); /* flags (???) */ + put_byte(li+89, 0); /* fatten_count */ + /* @@@ How big can I assume the structure? What's all this 1.0/1.1 cruft? */ +} + +static void LY_FattenLayerInfo(uaecptr li) +{ + struct MyLayerInfo *mli; + int fatten_count = get_byte (li + 89); + if (fatten_count == 0) { + mli = (struct MyLayerInfo *)malloc(sizeof(struct MyLayerInfo)); + add_uniq(&MyLayerInfo_list, &mli->head, li + 84); + init_uniq(&mli->layer_list); + mli->amigaos_linfo = li; + } + put_byte (li + 89, fatten_count + 1); +} + +static void LY_ThinLayerInfo(uaecptr li) +{ + int fatten_count = get_byte (li + 89)-1; + put_byte (li + 89, fatten_count); + if (fatten_count == 0) { + struct MyLayerInfo *mli = (struct MyLayerInfo *)find_and_rem_uniq(&MyLayerInfo_list, get_long(li+84)); + if (mli) + free(mli); + } +} + +static void build_cliprect (struct MyLayer *l, struct Rectangle *bounds, + int obscured, uaecptr *crp, uaecptr *prev) +{ + uaecptr cr = get_long (*crp); + if (cr == 0) { + put_long (*crp, cr = amiga_malloc(CLIPRECT_SIZE)); + put_long (cr, 0); + } + *prev = cr; + *crp = cr; + put_word (cr + 16, bounds->MinX); + put_word (cr + 18, bounds->MinY); + put_word (cr + 20, bounds->MaxX); + put_word (cr + 22, bounds->MaxY); + put_long (cr + 8, obscured ? l->amigaos_layer : 0); /* cheat */ + put_long (cr + 12, 0); /* no smart refresh yet */ +} + +static void build_cliprects (struct MyLayer *l) +{ + uaecptr layer = l->amigaos_layer; + uaecptr cr = layer + 8; + uaecptr prev = 0; + uae_u16 flags = get_word(layer + 30); + int i; + + if ((flags & LAYER_CR_CHANGED) == 0) + return; + put_word (layer + 30, flags & ~LAYER_CR_CHANGED); + for (i = 0; i < l->obscured.count; i++) { + build_cliprect (l, l->obscured.rects + i, 1, &cr, &prev); + } + for (i = 0; i < l->visible.count; i++) { + build_cliprect (l, l->visible.rects + i, 1, &cr, &prev); + } + while ((prev = get_long (cr))) { + put_long (cr, get_long (prev)); + amiga_free (prev, CLIPRECT_SIZE); + } +} + +static void propagate_clueless_redo (struct MyLayerInfo *mli) +{ + /* For all CLUELESS layers, set the REDO bit for all layers below it that overlap it + * and delete the data associated with them. */ + uaecptr current_l = get_long(mli->amigaos_linfo); + while (current_l) { + struct MyLayer *l = (struct MyLayer *)find_uniq(&mli->layer_list, get_long(current_l + 24)); + if ((get_word(l->amigaos_layer + 32) & LAYER_CLUELESS) != 0) { + uaecptr next_l = get_long(current_l); + put_word(l->amigaos_layer + 32, get_word(l->amigaos_layer + 32) | LAYER_REDO); + while (next_l) { + struct MyLayer *l2 = (struct MyLayer *)find_uniq(&mli->layer_list, get_long(next_l + 24)); + uae_u16 flags = get_word(l2->amigaos_layer + 32); + if (l2->bounds.MinX <= l->bounds.MaxX && l->bounds.MinX <= l2->bounds.MaxX + && l2->bounds.MinY <= l->bounds.MaxY && l->bounds.MinY <= l2->bounds.MaxY) + put_word(l2->amigaos_layer + 32, flags | LAYER_REDO); + if ((flags & (LAYER_REDO|LAYER_CLUELESS)) == 0) { + free_rectlist(&l->obscured); + free_rectlist(&l->visible); + free_bandlist(&l->big_bands); + free_bandlist(&l->small_bands); + } + next_l = get_long(next_l); + } + } + current_l = get_long(current_l); + } +} + +static void redo_layers(struct MyLayerInfo *mli, uaecptr bm) +{ + uaecptr current_l; + struct RectList tmp_rl; + + propagate_clueless_redo(mli); + current_l = get_long(mli->amigaos_linfo); + + while (current_l) { + struct MyLayer *l = (struct MyLayer *)find_uniq(&mli->layer_list, get_long(current_l + 24)); + uae_u16 flags = get_word(l->amigaos_layer + 32); + if ((flags & LAYER_REDO) != 0) { + uaecptr next_l = get_long(current_l+4); + int have_rects = 0; + + init_rectlist(&l->obscured); + init_bandlist(&l->big_bands); + add_rect_to_bands(&l->big_bands, &l->bounds); + + while (next_l) { + struct MyLayer *l2 = (struct MyLayer *)find_uniq(&mli->layer_list, get_long(next_l + 24)); + if (l2->visible.bounds.MinX <= l->bounds.MaxX && l->bounds.MinX <= l2->visible.bounds.MaxX + && l2->visible.bounds.MinY <= l->bounds.MaxY && l->bounds.MinY <= l2->visible.bounds.MaxY + && !rect_in_region (&l->obscured, &l2->visible.bounds)) + { + add_rect_to_bands(&l->big_bands, &l2->visible.bounds); + add_rect(&l->obscured, l2->visible.bounds); + have_rects++; + } + next_l = get_long(next_l+4); + } + init_rectlist(&l->visible); + init_rectlist(&tmp_rl); + add_rect (&tmp_rl, l->bounds); + + region_splitrects_band(&l->obscured, &l->big_bands); + region_splitrects_band(&tmp_rl, &l->big_bands); + region_do_ClearRegionRegion(&l->obscured, &tmp_rl, &l->visible); + flags |= LAYER_CR_CHANGED; + } + put_word (l->amigaos_layer + 32, flags & ~(LAYER_CLUELESS|LAYER_REDO)); + current_l = get_long(current_l); + } +} + +static struct MyLayer *LY_NewLayer(struct MyLayerInfo *mli, int x0, int x1, int y0, int y1, + uae_u16 flags, uaecptr bm, uaecptr sbm) +{ + struct MyLayer *l = (struct MyLayer *)malloc(sizeof (struct MyLayer)); + uaecptr layer = amiga_malloc(LAYER_SIZE); + memset (get_real_address(layer), 0, LAYER_SIZE); + l->amigaos_layer = layer; + + put_word(layer + 16, x0); /* bounds */ + put_word(layer + 18, y0); + put_word(layer + 20, x1); + put_word(layer + 22, y1); + put_word(layer + 30, flags | LAYER_CLUELESS); + put_long(layer + 32, flags & 4 ? sbm : 0); /* ClipRect */ + put_long(layer + 68, mli->amigaos_linfo); + m68k_areg(regs, 0) = layer + 72; CallLib(get_long(4), -558); /* InitSemaphore() */ + add_uniq(&mli->layer_list, &l->head, layer + 24); + l->mli = mli; + + l->bounds.MinX = x0; + l->bounds.MaxX = x1; + l->bounds.MinY = y0; + l->bounds.MaxY = y1; + return l; +} + +static void LY_DeleteLayer(uaecptr layer) +{ + uaecptr cr; + struct MyLayer *l = (struct MyLayer *)find_and_rem_uniq(&l->mli->layer_list, get_long (layer + 24)); + /* Free ClipRects */ + while ((cr = get_long (l->amigaos_layer + 8))) { + put_long (l->amigaos_layer + 8, get_long(cr)); + amiga_free(cr, CLIPRECT_SIZE); + } + amiga_free (l->amigaos_layer, LAYER_SIZE); + free(l); +} + +static uaecptr find_behindlayer_position(uaecptr li, uae_u16 flags) +{ + uaecptr where = li; + for (;;) { + uaecptr other = get_long (where); + /* End of list? */ + if (other == 0) + break; + /* Backdrop? */ + if ((get_word(other + 30) & 0x40) > (flags & 0x40)) + break; + where = other; + } + return where; +} + +static uaecptr LY_CreateLayer(uaecptr li, int x0, int x1, int y0, int y1, + uae_u16 flags, uaecptr bm, uaecptr sbm, uaecptr where) +{ + struct MyLayerInfo *mli = (struct MyLayerInfo *)find_uniq(&MyLayerInfo_list, get_long (li + 84)); + struct MyLayer *l; + + LY_LockLayerInfo(li); + + l = LY_NewLayer(mli, x0, x1, y0, y1, flags, bm, sbm); + /* Chain into list */ + put_long(l->amigaos_layer, get_long (where)); + put_long(l->amigaos_layer + 4, where == li ? 0 : where); + if (get_long (where) != 0) + put_long(get_long (where) + 4, l->amigaos_layer); + put_long(where, l->amigaos_layer); + redo_layers(mli, bm); + build_cliprects(l); + LY_UnlockLayerInfo(li); + return l->amigaos_layer; +} + +static void LY_DisposeLayerInfo(uaecptr li) +{ + LY_ThinLayerInfo(li); + amiga_free(li, LINFO_SIZE); +} + +static uae_u32 layers_NewLayerInfo(void) +{ + uaecptr li = amiga_malloc(LINFO_SIZE); + LY_InitLayers(li); + LY_FattenLayerInfo(li); + return li; +} +static uae_u32 layers_InitLayers(void) { LY_InitLayers (m68k_areg (regs, 0)); return 0; } +static uae_u32 layers_DisposeLayerInfo(void) { LY_DisposeLayerInfo (m68k_areg (regs, 0)); return 0; } + +static uae_u32 layers_FattenLayerInfo(void) { LY_FattenLayerInfo(m68k_areg(regs, 0)); return 0; } +static uae_u32 layers_ThinLayerInfo(void) { LY_ThinLayerInfo(m68k_areg(regs, 0)); return 0; } + +static uae_u32 layers_CreateUpfrontLayer(void) +{ + return LY_CreateLayer(m68k_areg(regs, 0), (uae_s32)m68k_dreg(regs, 0), + (uae_s32)m68k_dreg(regs, 1), (uae_s32)m68k_dreg(regs, 2), + (uae_s32)m68k_dreg(regs, 3), + m68k_dreg(regs, 4), + m68k_areg(regs, 1), m68k_areg(regs, 2), m68k_areg(regs, 0)); +} +static uae_u32 layers_CreateBehindLayer(void) +{ + return LY_CreateLayer(m68k_areg(regs, 0), (uae_s32)m68k_dreg(regs, 0), + (uae_s32)m68k_dreg(regs, 1), (uae_s32)m68k_dreg(regs, 2), + (uae_s32)m68k_dreg(regs, 3), + m68k_dreg(regs, 4), + m68k_areg(regs, 1), m68k_areg(regs, 2), + find_behindlayer_position (m68k_areg(regs, 0), m68k_dreg(regs, 4))); +} +static uae_u32 layers_DeleteLayer(void) { LY_DeleteLayer (m68k_areg (regs, 1)); return 0; } + +static void LY_LockLayer1(uaecptr layer) +{ + uaecptr li = get_long (layer + 68); + struct MyLayerInfo *mli = (struct MyLayerInfo *)find_uniq (&MyLayerInfo_list, get_long (li + 84)); + struct MyLayer *l = (struct MyLayer *)find_uniq (&mli->layer_list, get_long (layer + 24)); + + LY_LockLayer(layer); + build_cliprects (l); +} +static uae_u32 LY_TryLockLayer1(uaecptr layer) +{ + uaecptr li = get_long (layer + 68); + struct MyLayerInfo *mli = (struct MyLayerInfo *)find_uniq (&MyLayerInfo_list, get_long (li + 84)); + struct MyLayer *l = (struct MyLayer *)find_uniq (&mli->layer_list, get_long (layer + 24)); + + if (!LY_TryLockLayer(layer)) + return 0; + build_cliprects (l); + return 1; +} +static uae_u32 gfx_TryLockLayer(void) { return LY_TryLockLayer1 (m68k_areg(regs, 5)); } +static uae_u32 gfx_LockLayer(void) { LY_LockLayer1 (m68k_areg(regs, 5)); return 0; } +static uae_u32 gfx_UnlockLayer(void) { LY_UnlockLayer(m68k_areg(regs, 5)); return 0; } +static uae_u32 layers_LockLayer(void) { LY_LockLayer1 (m68k_areg(regs, 1)); return 0; } +static uae_u32 layers_LockLayers(void) { LY_LockLayers(m68k_areg(regs, 0)); return 0; } +static uae_u32 layers_LockLayerInfo(void) { LY_LockLayerInfo(m68k_areg(regs, 0)); return 0; } +static uae_u32 layers_UnlockLayer(void) { LY_UnlockLayer(m68k_areg(regs, 0)); return 0; } +static uae_u32 layers_UnlockLayers(void) { LY_UnlockLayers(m68k_areg(regs, 0)); return 0; } +static uae_u32 layers_UnlockLayerInfo(void) { LY_UnlockLayerInfo(m68k_areg(regs, 0)); return 0; } + +static uae_u32 layers_ScrollLayer(void) +{ + abort(); +} + +static uae_u32 layers_SizeLayer(void) +{ + abort(); +} + +static uae_u32 layers_MoveLayer(void) +{ + abort(); +} + +static uae_u32 layers_UpfrontLayer(void) +{ + abort(); +} + +static uae_u32 layers_BehindLayer(void) +{ + abort(); +} + +static uae_u32 layers_MoveLayerInFrontOf(void) +{ + abort(); +} + +static uae_u32 layers_BeginUpdate(void) +{ + return 1; +} + +static uae_u32 layers_EndUpdate(void) +{ + return 0; +} + +static uae_u32 layers_WhichLayer(void) +{ + abort(); +} + +static uae_u32 layers_InstallClipRegion(void) +{ + return 0; +} + +static uae_u32 layers_SwapBitsRastPortClipRect(void) +{ + abort(); +} + +/* + * Initialization + */ +static uae_u32 gfxlib_init(void) +{ + uae_u32 old_arr; + uaecptr sysbase=m68k_areg(regs, 6); + int i=0; + + /* Install new routines */ + m68k_dreg(regs, 0)=0; + m68k_areg(regs, 1)=gfxlibname; + gfxbase=CallLib(sysbase, -408); /* OpenLibrary */ + m68k_dreg(regs, 0)=0; + m68k_areg(regs, 1)=layerslibname; + layersbase=CallLib(sysbase, -408); /* OpenLibrary */ + + libemu_InstallFunctionFlags(gfxl_WritePixel, gfxbase, -324, TRAPFLAG_EXTRA_STACK, ""); + libemu_InstallFunctionFlags(gfxl_BltClear, gfxbase, -300, 0, ""); + libemu_InstallFunctionFlags(gfxl_AndRegionRegion, gfxbase, -624, TRAPFLAG_EXTRA_STACK, ""); + libemu_InstallFunctionFlags(gfxl_OrRegionRegion, gfxbase, -612, TRAPFLAG_EXTRA_STACK, ""); + libemu_InstallFunctionFlags(gfxl_XorRegionRegion, gfxbase, -618, TRAPFLAG_EXTRA_STACK, ""); + libemu_InstallFunctionFlags(gfxl_AndRectRegion, gfxbase, -504, TRAPFLAG_EXTRA_STACK, ""); + libemu_InstallFunctionFlags(gfxl_OrRectRegion, gfxbase, -510, TRAPFLAG_EXTRA_STACK, ""); + libemu_InstallFunctionFlags(gfxl_XorRectRegion, gfxbase, -558, TRAPFLAG_EXTRA_STACK, ""); + libemu_InstallFunctionFlags(gfxl_ClearRectRegion, gfxbase, -522, TRAPFLAG_EXTRA_STACK, ""); + +#if 0 +#define MAYBE_FUNCTION(a) NULL +#else +#define MAYBE_FUNCTION(a) (a) +#endif +#if 0 + libemu_InstallFunctionFlags(MAYBE_FUNCTION(gfx_TryLockLayer), gfxbase, -654, TRAPFLAG_EXTRA_STACK|TRAPFLAG_NO_RETVAL, "AttemptLockLayerRom"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(gfx_LockLayer), gfxbase, -432, TRAPFLAG_EXTRA_STACK|TRAPFLAG_NO_RETVAL, "LockLayerRom"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(gfx_UnlockLayer), gfxbase, -438, TRAPFLAG_EXTRA_STACK|TRAPFLAG_NO_RETVAL, "UnlockLayerRom"); + + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_InitLayers), layersbase, -30, TRAPFLAG_EXTRA_STACK, "InitLayers"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_CreateUpfrontLayer), layersbase, -36, TRAPFLAG_EXTRA_STACK, "CreateUpfrontLayer"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_CreateBehindLayer), layersbase, -42, TRAPFLAG_EXTRA_STACK, "CreateBehindLayer"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_UpfrontLayer), layersbase, -48, TRAPFLAG_EXTRA_STACK, "UpfrontLayer"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_BehindLayer), layersbase, -54, TRAPFLAG_EXTRA_STACK, "BehindLayer"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_MoveLayer), layersbase, -60, TRAPFLAG_EXTRA_STACK, "MoveLayer"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_SizeLayer), layersbase, -66, TRAPFLAG_EXTRA_STACK, "SizeLayer"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_ScrollLayer), layersbase, -72, TRAPFLAG_EXTRA_STACK, "ScrollLayer"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_BeginUpdate), layersbase, -78, TRAPFLAG_EXTRA_STACK, "BeginUpdate"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_EndUpdate), layersbase, -84, TRAPFLAG_EXTRA_STACK, "EndUpdate"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_DeleteLayer), layersbase, -90, TRAPFLAG_EXTRA_STACK, "DeleteLayer"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_LockLayer), layersbase, -96, TRAPFLAG_EXTRA_STACK, "LockLayer"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_UnlockLayer), layersbase, -102, TRAPFLAG_EXTRA_STACK, "UnlockLayer"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_LockLayers), layersbase, -108, TRAPFLAG_EXTRA_STACK, "LockLayers"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_UnlockLayers), layersbase, -114, TRAPFLAG_EXTRA_STACK, "UnlockLayers"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_LockLayerInfo), layersbase, -120, TRAPFLAG_EXTRA_STACK, "LockLayerInfo"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_SwapBitsRastPortClipRect), layersbase, -126, TRAPFLAG_EXTRA_STACK, "SwapBitsRastPortClipRect"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_WhichLayer), layersbase, -132, TRAPFLAG_EXTRA_STACK, "WhichLayer"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_UnlockLayerInfo), layersbase, -138, TRAPFLAG_EXTRA_STACK, "UnlockLayerInfo"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_NewLayerInfo), layersbase, -144, TRAPFLAG_EXTRA_STACK, "NewLayerInfo"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_DisposeLayerInfo), layersbase, -150, TRAPFLAG_EXTRA_STACK, "DisposeLayerInfo"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_FattenLayerInfo), layersbase, -156, TRAPFLAG_EXTRA_STACK, "FattenLayerInfo"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_ThinLayerInfo), layersbase, -162, TRAPFLAG_EXTRA_STACK, "ThinLayerInfo"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_MoveLayerInFrontOf), layersbase, -168, TRAPFLAG_EXTRA_STACK, "MoveLayerInFrontOf"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_InstallClipRegion), layersbase, -174, TRAPFLAG_EXTRA_STACK, "InstallClipRegion"); +#if 0 + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_), layersbase, -180, TRAPFLAG_EXTRA_STACK, "MoveSizeLayer"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_), layersbase, -186, TRAPFLAG_EXTRA_STACK, "CreateUpfrontHookLayer"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_), layersbase, -192, TRAPFLAG_EXTRA_STACK, "CreateBehindHookLayer"); + libemu_InstallFunctionFlags(MAYBE_FUNCTION(layers_), layersbase, -198, TRAPFLAG_EXTRA_STACK, "InstallLayerHook"); +#endif +#endif + return 0; +} + +/* + * Install the gfx-library-replacement + */ +void gfxlib_install(void) +{ + uae_u32 begin, end, resname, resid; + int i; + + if (! currprefs.use_gfxlib) + return; + + write_log ("Warning: you enabled the graphics.library replacement with -g\n" + "This may be buggy right now, and will not speed things up much.\n"); + + resname = ds ("UAEgfxlib.resource"); + resid = ds ("UAE gfxlib 0.1"); + + gfxlibname = ds ("graphics.library"); + layerslibname = ds ("layers.library"); + + begin = here(); + dw(0x4AFC); /* RTC_MATCHuae_s16 */ + dl(begin); /* our start address */ + dl(0); /* Continue scan here */ + dw(0x0101); /* RTF_COLDSTART; Version 1 */ + dw(0x0805); /* NT_RESOURCE; pri 5 */ + dl(resname); /* name */ + dl(resid); /* ID */ + dl(here() + 4); /* Init area: directly after this */ + + calltrap(deftrap2(gfxlib_init, TRAPFLAG_EXTRA_STACK, "")); dw(RTS); + + end = here(); + org(begin + 6); + dl(end); + + org(end); +} +#else + +void gfxlib_install (void) +{ +} + +#endif diff --git a/gfxutil.c b/gfxutil.c new file mode 100755 index 00000000..695d08de --- /dev/null +++ b/gfxutil.c @@ -0,0 +1,528 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Common code needed by all the various graphics systems. + * + * (c) 1996 Bernd Schmidt, Ed Hanway, Samuel Devulder + */ + +#include "sysconfig.h" +#include "sysdeps.h" +#include "custom.h" +#include "xwin.h" + +#define RED 0 +#define GRN 1 +#define BLU 2 + +/* + * dither matrix + */ +static uae_u8 dither[4][4] = +{ + { 0, 8, 2, 10 }, + { 12, 4, 14, 6 }, + { 3, 11, 1, 9 }, + { 14 /* 15 */, 7, 13, 5 } +}; + + +unsigned long doMask (int p, int bits, int shift) +{ + /* scale to 0..255, shift to align msb with mask, and apply mask */ + unsigned long val = p << 24; + if (!bits) + return 0; + val >>= (32 - bits); + val <<= shift; + + return val; +} + +int bits_in_mask (unsigned long mask) +{ + int n = 0; + while (mask) { + n += mask & 1; + mask >>= 1; + } + return n; +} + +int mask_shift (unsigned long mask) +{ + int n = 0; + while (!(mask & 1)) { + n++; + mask >>= 1; + } + return n; +} + +unsigned long doMask256 (int p, int bits, int shift) +{ + /* p is a value from 0 to 255 (Amiga color value) + * shift to align msb with mask, and apply mask */ + + unsigned long val = p * 0x01010101UL; + val >>= (32 - bits); + val <<= shift; + + return val; +} + +static unsigned int doColor (int i, int bits, int shift) +{ + int shift2; + if(bits >= 8) shift2 = 0; else shift2 = 8 - bits; + return (i >> shift2) << shift; +} + +static unsigned int doAlpha (int alpha, int bits, int shift) +{ + return (alpha & ((1 << bits) - 1)) << shift; +} + +#if 0 +static void colormodify (int *r, int *g, int *b) +{ + double h, l, s; + + RGBToHLS (*r, *g, *b, &h, &l, &s); + + h = h + currprefs.gfx_hue / 10.0; + if (h > 359) h = 359; + if (h < 0) h = 0; + s = s + currprefs.gfx_saturation / 30.0; + if (s > 99) s = 99; + if (s < 0) s = 0; + l = l + currprefs.gfx_luminance / 30.0; + l = (l - currprefs.gfx_contrast / 30.0) / (100 - 2 * currprefs.gfx_contrast / 30.0) * 100; + l = pow (l / 100.0, (currprefs.gfx_gamma + 1000) / 1000.0) * 100.0; + if (l > 99) l = 99; + if (l < 0) l = 0; + HLSToRGB (h, l, s, r, g, b); +} +#endif + +void alloc_colors64k (int rw, int gw, int bw, int rs, int gs, int bs, int aw, int as, int alpha) +{ + int i; + + for (i = 0; i < 4096; i++) { + int r = (i >> 8) << 4; + int g = ((i >> 4) & 0xF) << 4; + int b = (i & 0xF) << 4; + //colormodify (&r, &g, &b); + xcolors[i] = doMask(r, rw, rs) | doMask(g, gw, gs) | doMask(b, bw, bs) | doAlpha (alpha, aw, as); + } +#ifdef AGA + /* create AGA color tables */ + for(i = 0; i < 256; i++) { + xredcolors[i] = doColor (i, rw, rs) | doAlpha (alpha, aw, as); + xgreencolors[i] = doColor (i, gw, gs) | doAlpha (alpha, aw, as); + xbluecolors[i] = doColor (i, bw, bs) | doAlpha (alpha, aw, as);; + } +#endif +} + +static int allocated[4096]; +static int color_diff[4096]; +static int newmaxcol = 0; + +void setup_maxcol (int max) +{ + newmaxcol = max; +} + +void alloc_colors256 (allocfunc_type allocfunc) +{ + int nb_cols[3]; /* r,g,b */ + int maxcol = newmaxcol == 0 ? 256 : newmaxcol; + int i,j,k,l; + + xcolnr *map; + + map = (xcolnr *)malloc (sizeof(xcolnr) * maxcol); + if (!map) { + write_log ("Not enough mem for colormap!\n"); + abort (); + } + + /* + * compute #cols per components + */ + for (i = 1; i*i*i <= maxcol; ++i) + ; + --i; + + nb_cols[RED] = i; + nb_cols[GRN] = i; + nb_cols[BLU] = i; + + /* + * set the colormap + */ + l = 0; + for (i = 0; i < nb_cols[RED]; ++i) { + int r = (i * 15) / (nb_cols[RED] - 1); + for (j = 0; j < nb_cols[GRN]; ++j) { + int g = (j * 15) / (nb_cols[GRN] - 1); + for (k = 0; k < nb_cols[BLU]; ++k) { + int b = (k * 15) / (nb_cols[BLU] - 1); + int result; + result = allocfunc (r, g, b, map + l); + l++; + } + } + } +/* printf("%d color(s) lost\n",maxcol - l);*/ + + /* + * for each component compute the mapping + */ + { + int diffr, diffg, diffb, maxdiff = 0, won = 0, lost; + int r, d = 8; + for (r = 0; r < 16; ++r) { + int cr, g, q; + + k = nb_cols[RED]-1; + cr = (r * k) / 15; + q = (r * k) % 15; + if (q > d && cr < k) ++cr; + diffr = abs (cr*k - r); + for (g = 0; g < 16; ++g) { + int cg, b; + + k = nb_cols[GRN]-1; + cg = (g * k) / 15; + q = (g * k) % 15; + if (q > d && cg < k) ++cg; + diffg = abs (cg*k - g); + for (b = 0; b < 16; ++b) { + int cb, rgb = (r << 8) | (g << 4) | b; + + k = nb_cols[BLU]-1; + cb = (b * k) / 15; + q = (b * k) % 15; + if (q > d && cb < k) ++cb; + diffb = abs (cb*k - b); + xcolors[rgb] = map[(cr * nb_cols[GRN] + cg) * nb_cols[BLU] + cb]; + color_diff[rgb] = diffr + diffg + diffb; + if (color_diff[rgb] > maxdiff) + maxdiff = color_diff[rgb]; + } + } + } + while (maxdiff > 0 && l < maxcol) { + int newmaxdiff = 0; + lost = 0; won++; + for (r = 15; r >= 0; r--) { + int g; + + for (g = 15; g >= 0; g--) { + int b; + + for (b = 15; b >= 0; b--) { + int rgb = (r << 8) | (g << 4) | b; + + if (color_diff[rgb] == maxdiff) { + int result; + + if (l >= maxcol) + lost++; + else { + result = allocfunc (r, g, b, xcolors + rgb); + l++; + } + color_diff[rgb] = 0; + } else if (color_diff[rgb] > newmaxdiff) + newmaxdiff = color_diff[rgb]; + + } + } + } + maxdiff = newmaxdiff; + } +/* printf("%d color(s) lost, %d stages won\n",lost, won);*/ + } + free (map); +} + +/* + * This dithering process works by letting UAE run internaly in 12bit + * mode and doing the dithering on the fly when rendering to the display. + * The dithering algorithm is quite fast but uses lot of memory (4*8*2^12 = + * 128Kb). I don't think that is a trouble right now, but when UAE will + * emulate AGA and work internaly in 24bit mode, that dithering algorithm + * will need 4*8*2^24 = 512Mb. Obviously that fast algorithm will not be + * tractable. However, we could then use an other algorithm, slower, but + * far more reasonable (I am thinking about the one that is used in DJPEG). + */ + +uae_u8 cidx[4][8*4096]; /* fast, but memory hungry =:-( */ + +/* + * Compute dithering structures + */ +void setup_greydither_maxcol (int maxcol, allocfunc_type allocfunc) +{ + int i,j,k; + xcolnr *map; + + for (i = 0; i < 4096; i++) + xcolors[i] = i; + + map = (xcolnr *)malloc (sizeof(xcolnr) * maxcol); + if (!map) { + write_log ("Not enough mem for colormap!\n"); + abort(); + } + + /* + * set the colormap + */ + for (i = 0; i < maxcol; ++i) { + int c, result; + c = (15 * i + (maxcol-1)/2) / (maxcol - 1); + result = allocfunc(c, c, c, map + i); + /* @@@ check for errors */ + } + + /* + * for each componant compute the mapping + */ + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + int r, d = dither[i][j]*17; + for (r = 0; r<16; ++r) { + int g; + for (g = 0; g < 16; ++g) { + int b; + for (b = 0; b < 16; ++b) { + int rgb = (r << 8) | (g << 4) | b; + int c,p,q; + + c = (77 * r + + 151 * g + + 28 * b) / 15; /* c in 0..256 */ + + k = maxcol-1; + p = (c * k) / 256; + q = (c * k) % 256; + if (q /*/ k*/> d /*/ k*/ && p < k) ++p; +/* sam: ^^^^^^^ */ +/* It seems that produces better output */ + cidx[i][rgb + (j+4)*4096] = + cidx[i][rgb + j*4096] = (uae_u8)map[p]; + } + } + } + } + } + free (map); +} + +void setup_greydither (int bits, allocfunc_type allocfunc) +{ + setup_greydither_maxcol(1 << bits, allocfunc); +} + +void setup_dither (int bits, allocfunc_type allocfunc) +{ + int nb_cols[3]; /* r,g,b */ + int maxcol = 1 << bits; + int i,j,k,l; + + xcolnr *map; + int *redvals, *grnvals, *bluvals; + + map = (xcolnr *)malloc (sizeof(xcolnr) * maxcol); + if (!map) { + write_log ("Not enough mem for colormap!\n"); + abort(); + } + + for (i = 0; i < 4096; i++) + xcolors[i] = i; + + /* + * compute #cols per components + */ + for (i = 1; i*i*i <= maxcol; ++i) + ; + --i; + + nb_cols[RED] = i; + nb_cols[GRN] = i; + nb_cols[BLU] = i; + + if (nb_cols[RED]*(++i)*nb_cols[BLU] <= maxcol) { + nb_cols[GRN] = i; + if ((i)*nb_cols[GRN]*nb_cols[BLU] <= maxcol) + nb_cols[RED] = i; + } + + redvals = (int *)malloc (sizeof(int) * maxcol); + grnvals = redvals + nb_cols[RED]; + bluvals = grnvals + nb_cols[GRN]; + /* + * set the colormap + */ + l = 0; + for (i = 0; i < nb_cols[RED]; ++i) { + int r = (i * 15) / (nb_cols[RED] - 1); + redvals[i] = r; + for (j = 0; j < nb_cols[GRN]; ++j) { + int g = (j * 15) / (nb_cols[GRN] - 1); + grnvals[j] = g; + for (k = 0; k < nb_cols[BLU]; ++k) { + int b = (k * 15) / (nb_cols[BLU] - 1); + int result; + bluvals[k] = b; + result = allocfunc(r, g, b, map + l); + l++; + } + } + } +/* write_log ("%d color(s) lost\n",maxcol - l);*/ + + /* + * for each component compute the mapping + */ + { + int r; + for (r = 0; r < 16; ++r) { + int g; + for (g = 0; g < 16; ++g) { + int b; + for (b = 0; b < 16; ++b) { + int rgb = (r << 8) | (g << 4) | b; + + for (i = 0; i < 4; ++i) for (j = 0; j < 4; ++j) { + int d = dither[i][j]; + int cr, cg, cb, k, q; +#if 0 /* Slightly different algorithm. Needs some tuning. */ + int rederr = 0, grnerr = 0, bluerr = 0; + + k = nb_cols[RED]-1; + cr = r * k / 15; + q = r * k - 15*cr; + if (cr < 0) + cr = 0; + else if (q / k > d / k && rederr <= 0) + ++cr; + if (cr > k) cr = k; + rederr += redvals[cr]-r; + + k = nb_cols[GRN]-1; + cg = g * k / 15; + q = g * k - 15*cg; + if (cg < 0) + cg = 0; + else if (q / k > d / k && grnerr <= 0) + ++cg; + if (cg > k) cg = k; + grnerr += grnvals[cg]-g; + + k = nb_cols[BLU]-1; + cb = b * k / 15; + q = b * k - 15*cb; + if (cb < 0) + cb = 0; + else if (q / k > d / k && bluerr <= 0) + ++cb; + if (cb > k) cb = k; + bluerr += bluvals[cb]-b; +#else + k = nb_cols[RED]-1; + cr = r * k / 15; + q = r * k - 15*cr; + if (cr < 0) + cr = 0; + else if (q /*/ k*/ > d /*/ k*/) + ++cr; + if (cr > k) cr = k; + + k = nb_cols[GRN]-1; + cg = g * k / 15; + q = g * k - 15*cg; + if (cg < 0) + cg = 0; + else if (q /*/ k*/ > d /*/ k*/) + ++cg; + if (cg > k) cg = k; + + k = nb_cols[BLU]-1; + cb = b * k / 15; + q = b * k - 15*cb; + if (cb < 0) + cb = 0; + else if (q /*/ k*/ > d /*/ k*/) + ++cb; + if (cb > k) cb = k; +#endif + cidx[i][rgb + (j+4)*4096] = cidx[i][rgb + j*4096] = (uae_u8)map[(cr*nb_cols[GRN]+cg)*nb_cols[BLU]+cb]; + } + } + } + } + } + free (redvals); + free (map); +} + +#if !defined X86_ASSEMBLY +/* + * Dither the line. + * Make sure you call this only with (len & 3) == 0, or you'll just make + * yourself unhappy. + */ + +void DitherLine (uae_u8 *l, uae_u16 *r4g4b4, int x, int y, uae_s16 len, int bits) +{ + uae_u8 *dith = cidx[y&3]+(x&3)*4096; + uae_u8 d = 0; + int bitsleft = 8; + + if (bits == 8) { + while (len > 0) { + *l++ = dith[0*4096 + *r4g4b4++]; + *l++ = dith[1*4096 + *r4g4b4++]; + *l++ = dith[2*4096 + *r4g4b4++]; + *l++ = dith[3*4096 + *r4g4b4++]; + len -= 4; + } + return; + } + + while (len) { + int v; + v = dith[0*4096 + *r4g4b4++]; + bitsleft -= bits; + d |= (v << bitsleft); + if (!bitsleft) + *l++ = d, bitsleft = 8, d = 0; + + v = dith[1*4096 + *r4g4b4++]; + bitsleft -= bits; + d |= (v << bitsleft); + if (!bitsleft) + *l++ = d, bitsleft = 8, d = 0; + + v = dith[2*4096 + *r4g4b4++]; + bitsleft -= bits; + d |= (v << bitsleft); + if (!bitsleft) + *l++ = d, bitsleft = 8, d = 0; + + v = dith[3*4096 + *r4g4b4++]; + bitsleft -= bits; + d |= (v << bitsleft); + if (!bitsleft) + *l++ = d, bitsleft = 8, d = 0; + len -= 4; + } +} +#endif diff --git a/gtkui.c b/gtkui.c new file mode 100755 index 00000000..a536030c --- /dev/null +++ b/gtkui.c @@ -0,0 +1,1912 @@ +/* + * UAE - the Un*x Amiga Emulator + * + * Yet Another User Interface for the X11 version + * + * Copyright 1997, 1998 Bernd Schmidt + * Copyright 1998 Michael Krause + * + * The Tk GUI doesn't work. + * The X Forms Library isn't available as source, and there aren't any + * binaries compiled against glibc + * + * So let's try this... + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "uae.h" +#include "memory.h" +#include "custom.h" +#include "gui.h" +#include "newcpu.h" +#include "autoconf.h" +#include "threaddep/thread.h" +#include "sounddep/sound.h" +#include "savestate.h" +#include "compemu.h" + +#include +#include + +/* One of the 1.1.6 "features" is a gratuitous name change */ +#ifndef HAVE_GTK_FEATURES_1_1_6 +#define gtk_container_set_border_width gtk_container_border_width +#endif +/* Likewise for 1.1.8. */ +#ifndef HAVE_GTK_FEATURES_1_1_8 +#define gtk_label_set_text gtk_label_set +#endif +/* This is beginning to suck... */ +#ifndef HAVE_GTK_FEATURES_1_1_13 +#define gtk_toggle_button_set_active gtk_toggle_button_set_state +#endif + +static int gui_active; + +static GtkWidget *gui_window; + +static GtkWidget *pause_uae_widget, *snap_save_widget, *snap_load_widget; + +static GtkWidget *chipsize_widget[5]; +static GtkWidget *bogosize_widget[4]; +static GtkWidget *fastsize_widget[5]; +static GtkWidget *z3size_widget[10]; +static GtkWidget *p96size_widget[7]; +static GtkWidget *rom_text_widget, *key_text_widget; +static GtkWidget *rom_change_widget, *key_change_widget; + +static GtkWidget *disk_insert_widget[4], *disk_eject_widget[4], *disk_text_widget[4]; +static char *new_disk_string[4]; + +static GtkAdjustment *cpuspeed_adj; +static GtkWidget *cpuspeed_widgets[4], *cpuspeed_scale; +static GtkWidget *cpu_widget[5], *a24m_widget, *ccpu_widget; +static GtkWidget *sound_widget[4], *sound_bits_widget[2], *sound_freq_widget[3], *sound_ch_widget[3]; + +static GtkWidget *coll_widget[4], *cslevel_widget[4]; +static GtkWidget *fcop_widget; + +static GtkAdjustment *framerate_adj; +static GtkWidget *bimm_widget, *b32_widget, *afscr_widget, *pfscr_widget; + +static GtkWidget *compbyte_widget[4], *compword_widget[4], *complong_widget[4]; +static GtkWidget *compaddr_widget[4], *compnf_widget[2], *comp_midopt_widget[2]; +static GtkWidget *comp_lowopt_widget[2], *compfpu_widget[2], *comp_hardflush_widget[2]; +static GtkWidget *comp_constjump_widget[2]; +static GtkAdjustment *cachesize_adj; + +static GtkWidget *joy_widget[2][6]; + +static GtkWidget *led_widgets[5]; +static GdkColor led_on[5], led_off[5]; +static unsigned int prevledstate; + +static GtkWidget *hdlist_widget; +static int selected_hd_row; +static GtkWidget *hdchange_button, *hddel_button; +static GtkWidget *volname_entry, *path_entry; +static GtkWidget *dirdlg; +static char dirdlg_volname[256], dirdlg_path[256]; + +static smp_comm_pipe to_gui_pipe, from_gui_pipe; +static uae_sem_t gui_sem, gui_init_sem, gui_quit_sem; /* gui_sem protects the DFx fields */ + +static volatile int quit_gui = 0, quitted_gui = 0; + +static void save_config (void) +{ + FILE *f; + char tmp[257]; + + /* Backup the options file. */ + strcpy (tmp, optionsfile); + strcat (tmp, "~"); + rename (optionsfile, tmp); + + f = fopen (optionsfile, "w"); + if (f == NULL) { + write_log ("Error saving options file!\n"); + return; + } + save_options (f, &currprefs); + fclose (f); +} + +static int nr_for_led (GtkWidget *led) +{ + int i; + i = 0; + while (led_widgets[i] != led) + i++; + return i; +} + +static void enable_disk_buttons (int enable) +{ + int i; + for (i = 0; i < 4; i++) { + gtk_widget_set_sensitive (disk_insert_widget[i], enable); + gtk_widget_set_sensitive (disk_eject_widget[i], enable); + } +} + +static void enable_snap_buttons (int enable) +{ + gtk_widget_set_sensitive (snap_save_widget, enable); + gtk_widget_set_sensitive (snap_load_widget, enable); +} + +static void set_cpu_state (void) +{ + int i; + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (a24m_widget), changed_prefs.address_space_24 != 0); + gtk_widget_set_sensitive (a24m_widget, changed_prefs.cpu_level > 1 && changed_prefs.cpu_level < 4); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ccpu_widget), changed_prefs.cpu_compatible != 0); + gtk_widget_set_sensitive (ccpu_widget, changed_prefs.cpu_level == 0); + gtk_widget_set_sensitive (cpuspeed_scale, changed_prefs.m68k_speed > 0); + for (i = 0; i < 10; i++) + gtk_widget_set_sensitive (z3size_widget[i], + changed_prefs.cpu_level >= 2 && ! changed_prefs.address_space_24); +} + +static void set_cpu_widget (void) +{ + int nr = changed_prefs.cpu_level; + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cpu_widget[nr]), TRUE); + nr = currprefs.m68k_speed + 1 < 3 ? currprefs.m68k_speed + 1 : 2; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cpuspeed_widgets[nr]), TRUE); + +} + +static void set_gfx_state (void) +{ + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bimm_widget), currprefs.immediate_blits != 0); +#if 0 + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b32_widget), currprefs.blits_32bit_enabled != 0); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (afscr_widget), currprefs.gfx_afullscreen != 0); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pfscr_widget), currprefs.gfx_pfullscreen != 0); +#endif +} + +static void set_chipset_state (void) +{ + int t0 = 0; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (coll_widget[currprefs.collision_level]), TRUE); + if (currprefs.chipset_mask & CSMASK_AGA) + t0 = 3; + else if (currprefs.chipset_mask & CSMASK_ECS_DENISE) + t0 = 2; + else if (currprefs.chipset_mask & CSMASK_ECS_AGNUS) + t0 = 1; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cslevel_widget[t0]), TRUE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fcop_widget), currprefs.fast_copper != 0); +} + +static void set_sound_state (void) +{ + int stereo = currprefs.stereo + currprefs.mixed_stereo; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sound_widget[currprefs.produce_sound]), 1); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sound_ch_widget[stereo]), 1); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sound_bits_widget[currprefs.sound_bits == 16]), 1); +} + +static void set_mem_state (void) +{ + int t, t2; + + t = 0; + t2 = currprefs.chipmem_size; + while (t < 4 && t2 > 0x80000) + t++, t2 >>= 1; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (chipsize_widget[t]), 1); + + t = 0; + t2 = currprefs.bogomem_size; + while (t < 3 && t2 >= 0x80000) + t++, t2 >>= 1; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bogosize_widget[t]), 1); + + t = 0; + t2 = currprefs.fastmem_size; + while (t < 4 && t2 >= 0x100000) + t++, t2 >>= 1; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fastsize_widget[t]), 1); + + t = 0; + t2 = currprefs.z3fastmem_size; + while (t < 9 && t2 >= 0x100000) + t++, t2 >>= 1; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (z3size_widget[t]), 1); + + t = 0; + t2 = currprefs.gfxmem_size; + while (t < 6 && t2 >= 0x100000) + t++, t2 >>= 1; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (p96size_widget[t]), 1); + + gtk_label_set_text (GTK_LABEL (rom_text_widget), currprefs.romfile); + gtk_label_set_text (GTK_LABEL (key_text_widget), currprefs.keyfile); +} + +static void set_comp_state (void) +{ + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (compbyte_widget[currprefs.comptrustbyte]), 1); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (compword_widget[currprefs.comptrustword]), 1); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (complong_widget[currprefs.comptrustlong]), 1); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (compaddr_widget[currprefs.comptrustnaddr]), 1); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (compnf_widget[currprefs.compnf]), 1); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (comp_hardflush_widget[currprefs.comp_hardflush]), 1); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (comp_constjump_widget[currprefs.comp_constjump]), 1); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (compfpu_widget[currprefs.compfpu]), 1); +#if USE_OPTIMIZER + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (comp_midopt_widget[currprefs.comp_midopt]), 1); +#endif +#if USE_LOW_OPTIMIZER + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (comp_lowopt_widget[currprefs.comp_lowopt]), 1); +#endif +} + +static void set_joy_state (void) +{ + int j0t = changed_prefs.jport0; + int j1t = changed_prefs.jport1; + int i; + + if (j0t == j1t) { + /* Can't happen */ + j0t++; + j0t %= 6; + } + for (i = 0; i < 6; i++) { + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (joy_widget[0][i]), j0t == i); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (joy_widget[1][i]), j1t == i); + gtk_widget_set_sensitive (joy_widget[0][i], j1t != i); + gtk_widget_set_sensitive (joy_widget[1][i], j0t != i); + } +} + +static void set_hd_state (void) +{ + char texts[9][256]; + char *tptrs[] = { texts[0], texts[1], texts[2], texts[3], texts[4], texts[5], texts[6], texts[7], texts[8] }; + int nr = nr_units (currprefs.mountinfo); + int i; + + gtk_clist_freeze (GTK_CLIST (hdlist_widget)); + gtk_clist_clear (GTK_CLIST (hdlist_widget)); + for (i = 0; i < nr; i++) { + int secspertrack, surfaces, reserved, blocksize, size; + int cylinders, readonly; + char *volname, *rootdir; + char *failure; + + /* We always use currprefs.mountinfo for the GUI. The filesystem + code makes a private copy which is updated every reset. */ + failure = get_filesys_unit (currprefs.mountinfo, i, + &volname, &rootdir, &readonly, + &secspertrack, &surfaces, &reserved, + &cylinders, &size, &blocksize); + + if (is_hardfile (currprefs.mountinfo, i)) { + sprintf (texts[0], "DH%d", i ); + sprintf (texts[3], "%d", surfaces); + sprintf (texts[4], "%d", cylinders); + sprintf (texts[5], "%d", secspertrack); + sprintf (texts[6], "%d", reserved); + sprintf (texts[7], "%d", size); + sprintf (texts[8], "%d", blocksize); + } else { + strcpy (texts[0], volname); + strcpy (texts[3], "n/a"); + strcpy (texts[4], "n/a"); + strcpy (texts[5], "n/a"); + strcpy (texts[6], "n/a"); + strcpy (texts[7], "n/a"); + strcpy (texts[8], "n/a"); + } + strcpy (texts[1], rootdir); + strcpy (texts[2], readonly ? "y" : "n"); + gtk_clist_append (GTK_CLIST (hdlist_widget), tptrs); + } + gtk_clist_thaw (GTK_CLIST (hdlist_widget)); + gtk_widget_set_sensitive (hdchange_button, FALSE); + gtk_widget_set_sensitive (hddel_button, FALSE); +} + +static void draw_led (int nr) +{ + GtkWidget *thing = led_widgets[nr]; + GdkWindow *window = thing->window; + GdkGC *gc = gdk_gc_new (window); + GdkColor *col; + + if (gui_ledstate & (1 << nr)) + col = led_on + nr; + else + col = led_off + nr; + gdk_gc_set_foreground (gc, col); + gdk_draw_rectangle (window, gc, 1, 0, 0, -1, -1); + gdk_gc_destroy (gc); +} + +static int my_idle (void) +{ + unsigned int leds = gui_ledstate; + int i; + + if (quit_gui) { + gtk_main_quit (); + goto out; + } + while (comm_pipe_has_data (&to_gui_pipe)) { + int cmd = read_comm_pipe_int_blocking (&to_gui_pipe); + int n; + switch (cmd) { + case 0: + n = read_comm_pipe_int_blocking (&to_gui_pipe); + gtk_label_set_text (GTK_LABEL (disk_text_widget[n]), currprefs.df[n]); + break; + case 1: + /* Initialization. */ + set_cpu_widget (); + set_cpu_state (); + set_gfx_state (); + set_joy_state (); + set_sound_state (); + set_comp_state (); + set_mem_state (); + set_hd_state (); + set_chipset_state (); + + gtk_widget_show (gui_window); + uae_sem_post (&gui_init_sem); + gui_active = 1; + break; + } + } + + for (i = 0; i < 5; i++) { + unsigned int mask = 1 << i; + unsigned int on = leds & mask; + + if (on == (prevledstate & mask)) + continue; + +/* printf(": %d %d\n", i, on);*/ + draw_led (i); + } + prevledstate = leds; +out: + return 1; +} + +static int find_current_toggle (GtkWidget **widgets, int count) +{ + int i; + for (i = 0; i < count; i++) + if (GTK_TOGGLE_BUTTON (*widgets++)->active) + return i; + write_log ("GTKUI: Can't happen!\n"); + return -1; +} + +static void joy_changed (void) +{ + if (! gui_active) + return; + + changed_prefs.jport0 = find_current_toggle (joy_widget[0], 6); + changed_prefs.jport1 = find_current_toggle (joy_widget[1], 6); + set_joy_state (); +} + +static void coll_changed (void) +{ + changed_prefs.collision_level = find_current_toggle (coll_widget, 4); +} + +static void cslevel_changed (void) +{ + int t = find_current_toggle (cslevel_widget, 4); + int t1 = 0; + if (t > 0) + t1 |= CSMASK_ECS_AGNUS; + if (t > 1) + t1 |= CSMASK_ECS_DENISE; + if (t > 2) + t1 |= CSMASK_AGA; + changed_prefs.chipset_mask = t1; +} + +static void custom_changed (void) +{ + changed_prefs.gfx_framerate = framerate_adj->value; + changed_prefs.immediate_blits = GTK_TOGGLE_BUTTON (bimm_widget)->active; + changed_prefs.fast_copper = GTK_TOGGLE_BUTTON (fcop_widget)->active; +#if 0 + changed_prefs.blits_32bit_enabled = GTK_TOGGLE_BUTTON (b32_widget)->active; + changed_prefs.gfx_afullscreen = GTK_TOGGLE_BUTTON (afscr_widget)->active; + changed_prefs.gfx_pfullscreen = GTK_TOGGLE_BUTTON (pfscr_widget)->active; +#endif +} + +static void cpuspeed_changed (void) +{ + int which = find_current_toggle (cpuspeed_widgets, 3); + changed_prefs.m68k_speed = (which == 0 ? -1 + : which == 1 ? 0 + : cpuspeed_adj->value); + set_cpu_state (); +} + +static void cputype_changed (void) +{ + int i, oldcl; + if (! gui_active) + return; + + oldcl = changed_prefs.cpu_level; + + changed_prefs.cpu_level = find_current_toggle (cpu_widget, 5); + changed_prefs.cpu_compatible = GTK_TOGGLE_BUTTON (ccpu_widget)->active; + changed_prefs.address_space_24 = GTK_TOGGLE_BUTTON (a24m_widget)->active; + + if (changed_prefs.cpu_level != 0) + changed_prefs.cpu_compatible = 0; + /* 68000/68010 always have a 24 bit address space. */ + if (changed_prefs.cpu_level < 2) + changed_prefs.address_space_24 = 1; + /* Changing from 68000/68010 to 68020 should set a sane default. */ + else if (oldcl < 2) + changed_prefs.address_space_24 = 0; + + set_cpu_state (); +} + +static void chipsize_changed (void) +{ + int t = find_current_toggle (chipsize_widget, 5); + changed_prefs.chipmem_size = 0x80000 << t; + for (t = 0; t < 5; t++) + gtk_widget_set_sensitive (fastsize_widget[t], changed_prefs.chipmem_size <= 0x200000); + if (changed_prefs.chipmem_size > 0x200000) { + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fastsize_widget[0]), 1); + changed_prefs.fastmem_size = 0; + } +} + +static void bogosize_changed (void) +{ + int t = find_current_toggle (bogosize_widget, 4); + changed_prefs.bogomem_size = (0x40000 << t) & ~0x40000; +} + +static void fastsize_changed (void) +{ + int t = find_current_toggle (fastsize_widget, 5); + changed_prefs.fastmem_size = (0x80000 << t) & ~0x80000; +} + +static void z3size_changed (void) +{ + int t = find_current_toggle (z3size_widget, 10); + changed_prefs.z3fastmem_size = (0x80000 << t) & ~0x80000; +} + +static void p96size_changed (void) +{ + int t = find_current_toggle (p96size_widget, 7); + changed_prefs.gfxmem_size = (0x80000 << t) & ~0x80000; +} + +static void sound_changed (void) +{ + changed_prefs.produce_sound = find_current_toggle (sound_widget, 4); + changed_prefs.stereo = find_current_toggle (sound_ch_widget, 3); + changed_prefs.mixed_stereo = 0; + if (changed_prefs.stereo == 2) + changed_prefs.mixed_stereo = changed_prefs.stereo = 1; + changed_prefs.sound_bits = (find_current_toggle (sound_bits_widget, 2) + 1) * 8; +} + +static void comp_changed (void) +{ + changed_prefs.cachesize=cachesize_adj->value; + changed_prefs.comptrustbyte = find_current_toggle (compbyte_widget, 4); + changed_prefs.comptrustword = find_current_toggle (compword_widget, 4); + changed_prefs.comptrustlong = find_current_toggle (complong_widget, 4); + changed_prefs.comptrustnaddr = find_current_toggle (compaddr_widget, 4); + changed_prefs.compnf = find_current_toggle (compnf_widget, 2); + changed_prefs.comp_hardflush = find_current_toggle (comp_hardflush_widget, 2); + changed_prefs.comp_constjump = find_current_toggle (comp_constjump_widget, 2); + changed_prefs.compfpu= find_current_toggle (compfpu_widget, 2); +#if USE_OPTIMIZER + changed_prefs.comp_midopt = find_current_toggle (comp_midopt_widget, 2); +#endif +#if USE_LOW_OPTIMIZER + changed_prefs.comp_lowopt = find_current_toggle (comp_lowopt_widget, 2); +#endif +} + +static void did_reset (void) +{ + if (quit_gui) + return; + + write_comm_pipe_int (&from_gui_pipe, 2, 1); +} + +static void did_debug (void) +{ + if (quit_gui) + return; + + write_comm_pipe_int (&from_gui_pipe, 3, 1); +} + +static void did_quit (void) +{ + if (quit_gui) + return; + + write_comm_pipe_int (&from_gui_pipe, 4, 1); +} + +static void did_eject (GtkWidget *w, gpointer data) +{ + if (quit_gui) + return; + + write_comm_pipe_int (&from_gui_pipe, 0, 0); + write_comm_pipe_int (&from_gui_pipe, (int)data, 1); +} + +static void pause_uae (GtkWidget *widget, gpointer data) +{ + if (quit_gui) + return; + + write_comm_pipe_int (&from_gui_pipe, GTK_TOGGLE_BUTTON (widget)->active ? 5 : 6, 1); +} + +static void end_pause_uae (void) +{ + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pause_uae_widget), FALSE); +} + +static int filesel_active = -1; +static GtkWidget *disk_selector; + +static int snapsel_active = -1; +static char *gui_snapname, *gui_romname, *gui_keyname; + +static void did_close_insert (gpointer data) +{ + filesel_active = -1; + enable_disk_buttons (1); +} + +static void did_insert_select (GtkObject *o) +{ + char *s = gtk_file_selection_get_filename (GTK_FILE_SELECTION (disk_selector)); + printf ("%d %s\n", filesel_active, s); + if (quit_gui) + return; + + uae_sem_wait (&gui_sem); + if (new_disk_string[filesel_active] != 0) + free (new_disk_string[filesel_active]); + new_disk_string[filesel_active] = strdup (s); + uae_sem_post (&gui_sem); + write_comm_pipe_int (&from_gui_pipe, 1, 0); + write_comm_pipe_int (&from_gui_pipe, filesel_active, 1); + filesel_active = -1; + enable_disk_buttons (1); + gtk_widget_destroy (disk_selector); +} + +static char fsbuffer[100]; + +static GtkWidget *make_file_selector (const char *title, + void (*insertfunc)(GtkObject *), + void (*closefunc)(gpointer)) +{ + GtkWidget *p = gtk_file_selection_new (title); + gtk_signal_connect (GTK_OBJECT (p), "destroy", (GtkSignalFunc) closefunc, p); + + gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (p)->ok_button), + "clicked", (GtkSignalFunc) insertfunc, + GTK_OBJECT (p)); + gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (p)->cancel_button), + "clicked", (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (p)); + +#if 0 + gtk_window_set_title (GTK_WINDOW (p), title); +#endif + + gtk_widget_show (p); + return p; +} + +static void filesel_set_path (GtkWidget *p, const char *path) +{ + size_t len = strlen (path); + if (len > 0 && ! access (path, R_OK)) { + char *tmp = xmalloc (len + 2); + strcpy (tmp, path); + strcat (tmp, "/"); + gtk_file_selection_set_filename (GTK_FILE_SELECTION (p), + tmp); + } +} + +static void did_insert (GtkWidget *w, gpointer data) +{ + int n = (int)data; + if (filesel_active != -1) + return; + filesel_active = n; + enable_disk_buttons (0); + + sprintf (fsbuffer, "Select a disk image file for DF%d", n); + disk_selector = make_file_selector (fsbuffer, did_insert_select, did_close_insert); + filesel_set_path (disk_selector, currprefs.path_floppy); +} + +static gint driveled_event (GtkWidget *thing, GdkEvent *event) +{ + int lednr = nr_for_led (thing); + + switch (event->type) { + case GDK_MAP: + draw_led (lednr); + break; + case GDK_EXPOSE: + draw_led (lednr); + break; + default: + break; + } + + return 0; +} + +static GtkWidget *snap_selector; + +static void did_close_snap (gpointer gdata) +{ + snapsel_active = -1; + enable_snap_buttons (1); +} + +static void did_snap_select (GtkObject *o) +{ + char *s = gtk_file_selection_get_filename (GTK_FILE_SELECTION (snap_selector)); + + if (quit_gui) + return; + + uae_sem_wait (&gui_sem); + gui_snapname = strdup (s); + uae_sem_post (&gui_sem); + write_comm_pipe_int (&from_gui_pipe, 7, 0); + write_comm_pipe_int (&from_gui_pipe, snapsel_active, 1); + snapsel_active = -1; + enable_snap_buttons (1); + gtk_widget_destroy (snap_selector); +} + +static void did_loadstate (void) +{ + if (snapsel_active != -1) + return; + snapsel_active = STATE_DORESTORE; + enable_snap_buttons (0); + + snap_selector = make_file_selector ("Select a state file to restore", + did_snap_select, did_close_snap); +} + +static void did_savestate (void) +{ + if (snapsel_active != -1) + return; + snapsel_active = STATE_DOSAVE; + enable_snap_buttons (0); + + snap_selector = make_file_selector ("Select a filename for the state file", + did_snap_select, did_close_snap); +} + +static GtkWidget *rom_selector; + +static void did_close_rom (gpointer gdata) +{ + gtk_widget_set_sensitive (rom_change_widget, 1); +} + +static void did_rom_select (GtkObject *o) +{ + char *s = gtk_file_selection_get_filename (GTK_FILE_SELECTION (rom_selector)); + + if (quit_gui) + return; + + gtk_widget_set_sensitive (rom_change_widget, 1); + + uae_sem_wait (&gui_sem); + gui_romname = strdup (s); + uae_sem_post (&gui_sem); + write_comm_pipe_int (&from_gui_pipe, 8, 0); + gtk_label_set_text (GTK_LABEL (rom_text_widget), gui_romname); + gtk_widget_destroy (rom_selector); +} + +static void did_romchange (GtkWidget *w, gpointer data) +{ + gtk_widget_set_sensitive (rom_change_widget, 0); + + rom_selector = make_file_selector ("Select a ROM file", + did_rom_select, did_close_rom); + filesel_set_path (rom_selector, currprefs.path_rom); +} + +static GtkWidget *key_selector; + +static void did_close_key (gpointer gdata) +{ + gtk_widget_set_sensitive (key_change_widget, 1); +} + +static void did_key_select (GtkObject *o) +{ + char *s = gtk_file_selection_get_filename (GTK_FILE_SELECTION (key_selector)); + + if (quit_gui) + return; + + gtk_widget_set_sensitive (key_change_widget, 1); + + uae_sem_wait (&gui_sem); + gui_keyname = strdup (s); + uae_sem_post (&gui_sem); + write_comm_pipe_int (&from_gui_pipe, 9, 0); + gtk_label_set_text (GTK_LABEL (key_text_widget), gui_keyname); + gtk_widget_destroy (key_selector); +} + +static void did_keychange (GtkWidget *w, gpointer data) +{ + gtk_widget_set_sensitive (key_change_widget, 0); + + key_selector = make_file_selector ("Select a Kickstart key file", + did_key_select, did_close_key); + filesel_set_path (key_selector, currprefs.path_rom); +} + +static void add_empty_vbox (GtkWidget *tobox) +{ + GtkWidget *thing = gtk_vbox_new (FALSE, 0); + gtk_widget_show (thing); + gtk_box_pack_start (GTK_BOX (tobox), thing, TRUE, TRUE, 0); +} + +static void add_empty_hbox (GtkWidget *tobox) +{ + GtkWidget *thing = gtk_hbox_new (FALSE, 0); + gtk_widget_show (thing); + gtk_box_pack_start (GTK_BOX (tobox), thing, TRUE, TRUE, 0); +} + +static void add_centered_to_vbox (GtkWidget *vbox, GtkWidget *w) +{ + GtkWidget *hbox = gtk_hbox_new (TRUE, 0); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); +} + +static GtkWidget *make_labelled_widget (const char *str, GtkWidget *thing) +{ + GtkWidget *label = gtk_label_new (str); + GtkWidget *hbox2 = gtk_hbox_new (FALSE, 4); + + gtk_widget_show (label); + gtk_widget_show (thing); + + gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (hbox2), thing, FALSE, TRUE, 0); + + return hbox2; +} + +static GtkWidget *add_labelled_widget_centered (const char *str, GtkWidget *thing, GtkWidget *vbox) +{ + GtkWidget *w = make_labelled_widget (str, thing); + gtk_widget_show (w); + add_centered_to_vbox (vbox, w); + return w; +} + +static int make_radio_group (const char **labels, GtkWidget *tobox, + GtkWidget **saveptr, gint t1, gint t2, + void (*sigfunc) (void), int count, GSList *group) +{ + int t = 0; + + while (*labels && (count == -1 || count-- > 0)) { + GtkWidget *thing = gtk_radio_button_new_with_label (group, *labels++); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (thing)); + + *saveptr++ = thing; + gtk_widget_show (thing); + gtk_box_pack_start (GTK_BOX (tobox), thing, t1, t2, 0); + gtk_signal_connect (GTK_OBJECT (thing), "clicked", (GtkSignalFunc) sigfunc, NULL); + t++; + } + return t; +} + +static GtkWidget *make_radio_group_box (const char *title, const char **labels, + GtkWidget **saveptr, int horiz, + void (*sigfunc) (void)) +{ + GtkWidget *frame, *newbox; + + frame = gtk_frame_new (title); + newbox = (horiz ? gtk_hbox_new : gtk_vbox_new) (FALSE, 4); + gtk_widget_show (newbox); + gtk_container_set_border_width (GTK_CONTAINER (newbox), 4); + gtk_container_add (GTK_CONTAINER (frame), newbox); + make_radio_group (labels, newbox, saveptr, horiz, !horiz, sigfunc, -1, NULL); + return frame; +} + +static GtkWidget *make_radio_group_box_1 (const char *title, const char **labels, + GtkWidget **saveptr, int horiz, + void (*sigfunc) (void), int elts_per_column) +{ + GtkWidget *frame, *newbox; + GtkWidget *column; + GSList *group = 0; + + frame = gtk_frame_new (title); + column = (horiz ? gtk_vbox_new : gtk_hbox_new) (FALSE, 4); + gtk_container_add (GTK_CONTAINER (frame), column); + gtk_widget_show (column); + + while (*labels) { + int count; + newbox = (horiz ? gtk_hbox_new : gtk_vbox_new) (FALSE, 4); + gtk_widget_show (newbox); + gtk_container_set_border_width (GTK_CONTAINER (newbox), 4); + gtk_container_add (GTK_CONTAINER (column), newbox); + count = make_radio_group (labels, newbox, saveptr, horiz, !horiz, sigfunc, elts_per_column, group); + labels += count; + saveptr += count; + group = gtk_radio_button_group (GTK_RADIO_BUTTON (saveptr[-1])); + } + return frame; +} + +static GtkWidget *make_led (int nr) +{ + GtkWidget *subframe, *the_led, *thing; + GdkColormap *colormap; + + the_led = gtk_vbox_new (FALSE, 0); + gtk_widget_show (the_led); + + thing = gtk_preview_new (GTK_PREVIEW_COLOR); + gtk_box_pack_start (GTK_BOX (the_led), thing, TRUE, TRUE, 0); + gtk_widget_show (thing); + + subframe = gtk_frame_new (NULL); + gtk_box_pack_start (GTK_BOX (the_led), subframe, TRUE, TRUE, 0); + gtk_widget_show (subframe); + + thing = gtk_drawing_area_new (); + gtk_drawing_area_size (GTK_DRAWING_AREA (thing), 20, 5); + gtk_widget_set_events (thing, GDK_EXPOSURE_MASK); + gtk_container_add (GTK_CONTAINER (subframe), thing); + colormap = gtk_widget_get_colormap (thing); + led_on[nr].red = nr == 0 ? 0xEEEE : 0xCCCC; + led_on[nr].green = nr == 0 ? 0: 0xFFFF; + led_on[nr].blue = 0; + led_on[nr].pixel = 0; + led_off[nr].red = 0; + led_off[nr].green = 0; + led_off[nr].blue = 0; + led_off[nr].pixel = 0; + gdk_color_alloc (colormap, led_on + nr); + gdk_color_alloc (colormap, led_off + nr); + led_widgets[nr] = thing; + gtk_signal_connect (GTK_OBJECT (thing), "event", + (GtkSignalFunc) driveled_event, (gpointer) thing); + gtk_widget_show (thing); + + thing = gtk_preview_new (GTK_PREVIEW_COLOR); + gtk_box_pack_start (GTK_BOX (the_led), thing, TRUE, TRUE, 0); + gtk_widget_show (thing); + + return the_led; +} + +static GtkWidget *make_file_container (const char *title, GtkWidget *vbox) +{ + GtkWidget *thing = gtk_frame_new (title); + GtkWidget *buttonbox = gtk_hbox_new (FALSE, 4); + + gtk_container_set_border_width (GTK_CONTAINER (buttonbox), 4); + gtk_container_add (GTK_CONTAINER (thing), buttonbox); + gtk_box_pack_start (GTK_BOX (vbox), thing, FALSE, TRUE, 0); + gtk_widget_show (buttonbox); + gtk_widget_show (thing); + + return buttonbox; +} + +static GtkWidget *make_file_widget (GtkWidget *buttonbox) +{ + GtkWidget *thing, *subthing; + GtkWidget *subframe = gtk_frame_new (NULL); + + gtk_frame_set_shadow_type (GTK_FRAME (subframe), GTK_SHADOW_ETCHED_OUT); + gtk_box_pack_start (GTK_BOX (buttonbox), subframe, TRUE, TRUE, 0); + gtk_widget_show (subframe); + subthing = gtk_vbox_new (FALSE, 0); + gtk_widget_show (subthing); + gtk_container_add (GTK_CONTAINER (subframe), subthing); + thing = gtk_label_new (""); + gtk_widget_show (thing); + gtk_box_pack_start (GTK_BOX (subthing), thing, TRUE, TRUE, 0); + + return thing; +} + +static void make_floppy_disks (GtkWidget *vbox) +{ + GtkWidget *thing, *subthing, *subframe, *buttonbox; + char buf[5]; + int i; + + add_empty_vbox (vbox); + + for (i = 0; i < 4; i++) { + /* Frame with an hbox and the "DFx:" title */ + sprintf (buf, "DF%d:", i); + buttonbox = make_file_container (buf, vbox); + + /* LED */ + subthing = make_led (i + 1); + gtk_box_pack_start (GTK_BOX (buttonbox), subthing, FALSE, TRUE, 0); + + /* Current file display */ + disk_text_widget[i] = make_file_widget (buttonbox); + + /* Now, the buttons. */ + thing = gtk_button_new_with_label ("Eject"); + gtk_box_pack_start (GTK_BOX (buttonbox), thing, FALSE, TRUE, 0); + gtk_widget_show (thing); + disk_eject_widget[i] = thing; + gtk_signal_connect (GTK_OBJECT (thing), "clicked", (GtkSignalFunc) did_eject, (gpointer) i); + + thing = gtk_button_new_with_label ("Insert"); + gtk_box_pack_start (GTK_BOX (buttonbox), thing, FALSE, TRUE, 0); + gtk_widget_show (thing); + disk_insert_widget[i] = thing; + gtk_signal_connect (GTK_OBJECT (thing), "clicked", (GtkSignalFunc) did_insert, (gpointer) i); + } + + add_empty_vbox (vbox); +} + +static GtkWidget *make_cpu_speed_sel (void) +{ + int t; + static const char *labels[] = { + "Optimize for host CPU speed","Approximate 68000/7MHz speed", "Adjustable", + NULL + }; + GtkWidget *frame, *newbox; + + frame = gtk_frame_new ("CPU speed"); + newbox = gtk_vbox_new (FALSE, 4); + gtk_widget_show (newbox); + gtk_container_set_border_width (GTK_CONTAINER (newbox), 4); + gtk_container_add (GTK_CONTAINER (frame), newbox); + make_radio_group (labels, newbox, cpuspeed_widgets, 0, 1, cpuspeed_changed, -1, NULL); + + t = currprefs.m68k_speed > 0 ? currprefs.m68k_speed : 4 * CYCLE_UNIT; + cpuspeed_adj = GTK_ADJUSTMENT (gtk_adjustment_new (t, 1.0, 5120.0, 1.0, 1.0, 1.0)); + gtk_signal_connect (GTK_OBJECT (cpuspeed_adj), "value_changed", + GTK_SIGNAL_FUNC (cpuspeed_changed), NULL); + + cpuspeed_scale = gtk_hscale_new (cpuspeed_adj); + gtk_range_set_update_policy (GTK_RANGE (cpuspeed_scale), GTK_UPDATE_DELAYED); + gtk_scale_set_digits (GTK_SCALE (cpuspeed_scale), 0); + gtk_scale_set_value_pos (GTK_SCALE (cpuspeed_scale), GTK_POS_RIGHT); + cpuspeed_scale = add_labelled_widget_centered ("Cycles per instruction:", cpuspeed_scale, newbox); + + return frame; +} + +static void make_cpu_widgets (GtkWidget *vbox) +{ + int i; + GtkWidget *newbox, *hbox, *frame; + GtkWidget *thing; + static const char *radiolabels[] = { + "68000", "68010", "68020", "68020+68881", "68040", + NULL + }; + + add_empty_vbox (vbox); + + hbox = gtk_hbox_new (FALSE, 0); + add_empty_vbox (hbox); + + newbox = make_radio_group_box ("CPU type", radiolabels, cpu_widget, 0, cputype_changed); + gtk_widget_show (newbox); + gtk_box_pack_start (GTK_BOX (hbox), newbox, FALSE, FALSE, 0); + + newbox = make_cpu_speed_sel (); + gtk_widget_show (newbox); + gtk_box_pack_start (GTK_BOX (hbox), newbox, FALSE, FALSE, 0); + + add_empty_vbox (hbox); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + frame = gtk_frame_new ("CPU flags"); + add_centered_to_vbox (vbox, frame); + gtk_widget_show (frame); + newbox = gtk_vbox_new (FALSE, 4); + gtk_widget_show (newbox); + gtk_container_set_border_width (GTK_CONTAINER (newbox), 4); + gtk_container_add (GTK_CONTAINER (frame), newbox); + + a24m_widget = gtk_check_button_new_with_label ("24 bit address space"); + add_centered_to_vbox (newbox, a24m_widget); + gtk_widget_show (a24m_widget); + ccpu_widget = gtk_check_button_new_with_label ("Slow but compatible"); + add_centered_to_vbox (newbox, ccpu_widget); + gtk_widget_show (ccpu_widget); + + add_empty_vbox (vbox); + + gtk_signal_connect (GTK_OBJECT (ccpu_widget), "clicked", + (GtkSignalFunc) cputype_changed, NULL); + gtk_signal_connect (GTK_OBJECT (a24m_widget), "clicked", + (GtkSignalFunc) cputype_changed, NULL); +} + +static void make_gfx_widgets (GtkWidget *vbox) +{ + GtkWidget *thing, *frame, *newbox, *hbox; + static const char *p96labels[] = { + "None", "1 MB", "2 MB", "4 MB", "8 MB", "16 MB", "32 MB", NULL + }; + + add_empty_vbox (vbox); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_widget_show (hbox); + add_centered_to_vbox (vbox, hbox); + + frame = make_radio_group_box_1 ("P96 RAM", p96labels, p96size_widget, 0, p96size_changed, 4); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, TRUE, 0); + + frame = gtk_frame_new ("Miscellaneous"); + gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0); + + gtk_widget_show (frame); + newbox = gtk_vbox_new (FALSE, 4); + gtk_widget_show (newbox); + gtk_container_set_border_width (GTK_CONTAINER (newbox), 4); + gtk_container_add (GTK_CONTAINER (frame), newbox); + + framerate_adj = GTK_ADJUSTMENT (gtk_adjustment_new (currprefs.gfx_framerate, 1.0, 21.0, 1.0, 1.0, 1.0)); + gtk_signal_connect (GTK_OBJECT (framerate_adj), "value_changed", + GTK_SIGNAL_FUNC (custom_changed), NULL); + + thing = gtk_hscale_new (framerate_adj); + gtk_range_set_update_policy (GTK_RANGE (thing), GTK_UPDATE_DELAYED); + gtk_scale_set_digits (GTK_SCALE (thing), 0); + gtk_scale_set_value_pos (GTK_SCALE (thing), GTK_POS_RIGHT); + add_labelled_widget_centered ("Framerate:", thing, newbox); + + b32_widget = gtk_check_button_new_with_label ("32 bit blitter"); + add_centered_to_vbox (newbox, b32_widget); +#if 0 + gtk_widget_show (b32_widget); +#endif + bimm_widget = gtk_check_button_new_with_label ("Immediate blits"); + add_centered_to_vbox (newbox, bimm_widget); + gtk_widget_show (bimm_widget); + + afscr_widget = gtk_check_button_new_with_label ("Amiga modes fullscreen"); + add_centered_to_vbox (newbox, afscr_widget); +#if 0 + gtk_widget_show (afscr_widget); +#endif + pfscr_widget = gtk_check_button_new_with_label ("Picasso modes fullscreen"); + add_centered_to_vbox (newbox, pfscr_widget); +#if 0 + gtk_widget_show (pfscr_widget); +#endif + add_empty_vbox (vbox); + + gtk_signal_connect (GTK_OBJECT (bimm_widget), "clicked", + (GtkSignalFunc) custom_changed, NULL); +#if 0 + gtk_signal_connect (GTK_OBJECT (b32_widget), "clicked", + (GtkSignalFunc) custom_changed, NULL); + gtk_signal_connect (GTK_OBJECT (afscr_widget), "clicked", + (GtkSignalFunc) custom_changed, NULL); + gtk_signal_connect (GTK_OBJECT (pfscr_widget), "clicked", + (GtkSignalFunc) custom_changed, NULL); +#endif +} + +static void make_chipset_widgets (GtkWidget *vbox) +{ + GtkWidget *frame, *newbox, *hbox; + static const char *colllabels[] = { + "None (fastest)", "Sprites only", "Sprites & playfields", "Full (very slow)", + NULL + }; + static const char *cslevellabels[] = { + "OCS", "ECS Agnus", "Full ECS", "AGA", NULL + }; + + add_empty_vbox (vbox); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_widget_show (hbox); + add_centered_to_vbox (vbox, hbox); + + newbox = make_radio_group_box ("Sprite collisions", colllabels, coll_widget, 0, coll_changed); + gtk_widget_show (newbox); + gtk_box_pack_start (GTK_BOX (hbox), newbox, FALSE, TRUE, 0); + + newbox = make_radio_group_box ("Chipset", cslevellabels, cslevel_widget, 0, cslevel_changed); + gtk_widget_show (newbox); + gtk_box_pack_start (GTK_BOX (hbox), newbox, FALSE, TRUE, 0); + + fcop_widget = gtk_check_button_new_with_label ("Enable copper speedup code"); + add_centered_to_vbox (vbox, fcop_widget); + gtk_widget_show (fcop_widget); + + gtk_signal_connect (GTK_OBJECT (fcop_widget), "clicked", + (GtkSignalFunc) custom_changed, NULL); + + add_empty_vbox (vbox); +} + +static void make_sound_widgets (GtkWidget *vbox) +{ + GtkWidget *frame, *newbox; + int i; + GtkWidget *hbox; + static const char *soundlabels1[] = { + "None", "No output", "Normal", "Accurate", + NULL + }, *soundlabels2[] = { + "8 bit", "16 bit", + NULL + }, *soundlabels3[] = { + "Mono", "Stereo", "Mixed", + NULL + }; + + add_empty_vbox (vbox); + + newbox = make_radio_group_box ("Mode", soundlabels1, sound_widget, 1, sound_changed); + gtk_widget_show (newbox); + add_centered_to_vbox (vbox, newbox); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_widget_show (hbox); + add_centered_to_vbox (vbox, hbox); + newbox = make_radio_group_box ("Channels", soundlabels3, sound_ch_widget, 1, sound_changed); + gtk_widget_show (newbox); + gtk_box_pack_start (GTK_BOX (hbox), newbox, FALSE, TRUE, 0); + newbox = make_radio_group_box ("Resolution", soundlabels2, sound_bits_widget, 1, sound_changed); + gtk_widget_show (newbox); + gtk_box_pack_start (GTK_BOX (hbox), newbox, FALSE, TRUE, 0); + + add_empty_vbox (vbox); +} + +static void make_mem_widgets (GtkWidget *vbox) +{ + GtkWidget *hbox = gtk_hbox_new (FALSE, 10); + GtkWidget *label, *frame; + + static const char *chiplabels[] = { + "512 KB", "1 MB", "2 MB", "4 MB", "8 MB", NULL + }; + static const char *bogolabels[] = { + "None", "512 KB", "1 MB", "1.8 MB", NULL + }; + static const char *fastlabels[] = { + "None", "1 MB", "2 MB", "4 MB", "8 MB", NULL + }; + static const char *z3labels[] = { + "None", "1 MB", "2 MB", "4 MB", "8 MB", + "16 MB", "32 MB", "64 MB", "128 MB", "256 MB", + NULL + }; + + add_empty_vbox (vbox); + + { + GtkWidget *buttonbox = make_file_container ("Kickstart ROM file:", vbox); + GtkWidget *thing = gtk_button_new_with_label ("Change"); + + /* Current file display */ + rom_text_widget = make_file_widget (buttonbox); + + gtk_box_pack_start (GTK_BOX (buttonbox), thing, FALSE, TRUE, 0); + gtk_widget_show (thing); + rom_change_widget = thing; + gtk_signal_connect (GTK_OBJECT (thing), "clicked", (GtkSignalFunc) did_romchange, 0); + } + + { + GtkWidget *buttonbox = make_file_container ("ROM key file for Cloanto Amiga Forever:", vbox); + GtkWidget *thing = gtk_button_new_with_label ("Change"); + + /* Current file display */ + key_text_widget = make_file_widget (buttonbox); + + gtk_box_pack_start (GTK_BOX (buttonbox), thing, FALSE, TRUE, 0); + gtk_widget_show (thing); + key_change_widget = thing; + gtk_signal_connect (GTK_OBJECT (thing), "clicked", (GtkSignalFunc) did_keychange, 0); + } + + gtk_widget_show (hbox); + add_centered_to_vbox (vbox, hbox); + + add_empty_vbox (vbox); + + label = gtk_label_new ("These settings take effect after the next reset."); + gtk_widget_show (label); + add_centered_to_vbox (vbox, label); + + frame = make_radio_group_box ("Chip Mem", chiplabels, chipsize_widget, 0, chipsize_changed); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, TRUE, 0); + + frame = make_radio_group_box ("Slow Mem", bogolabels, bogosize_widget, 0, bogosize_changed); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, TRUE, 0); + + frame = make_radio_group_box ("Fast Mem", fastlabels, fastsize_widget, 0, fastsize_changed); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, TRUE, 0); + + frame = make_radio_group_box_1 ("Z3 Mem", z3labels, z3size_widget, 0, z3size_changed, 5); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, TRUE, 0); +} + +static void make_comp_widgets (GtkWidget *vbox) +{ + GtkWidget *frame, *newbox; + int i; + GtkWidget *hbox; + static const char *complabels1[] = { + "Direct", "Indirect", "Indirect for KS", "Direct after Picasso", + NULL + },*complabels2[] = { + "Direct", "Indirect", "Indirect for KS", "Direct after Picasso", + NULL + },*complabels3[] = { + "Direct", "Indirect", "Indirect for KS", "Direct after Picasso", + NULL + },*complabels3a[] = { + "Direct", "Indirect", "Indirect for KS", "Direct after Picasso", + NULL + }, *complabels4[] = { + "Always generate", "Only generate when needed", + NULL + }, *complabels5[] = { + "Disable", "Enable", + NULL + }, *complabels6[] = { + "Disable", "Enable", + NULL + }, *complabels7[] = { + "Disable", "Enable", + NULL + }, *complabels8[] = { + "Soft", "Hard", + NULL + }, *complabels9[] = { + "Disable", "Enable", + NULL + }; + GtkWidget *thing; + + add_empty_vbox (vbox); + + newbox = make_radio_group_box ("Byte access", complabels1, compbyte_widget, 1, comp_changed); + gtk_widget_show (newbox); + add_centered_to_vbox (vbox, newbox); + newbox = make_radio_group_box ("Word access", complabels2, compword_widget, 1, comp_changed); + gtk_widget_show (newbox); + add_centered_to_vbox (vbox, newbox); + newbox = make_radio_group_box ("Long access", complabels3, complong_widget, 1, comp_changed); + gtk_widget_show (newbox); + add_centered_to_vbox (vbox, newbox); + newbox = make_radio_group_box ("Address lookup", complabels3a, compaddr_widget, 1, comp_changed); + gtk_widget_show (newbox); + add_centered_to_vbox (vbox, newbox); + + newbox = make_radio_group_box ("Flags", complabels4, compnf_widget, 1, comp_changed); + gtk_widget_show (newbox); + add_centered_to_vbox (vbox, newbox); + + newbox = make_radio_group_box ("Icache flushes", complabels8, comp_hardflush_widget, 1, comp_changed); + gtk_widget_show (newbox); + add_centered_to_vbox (vbox, newbox); + + newbox = make_radio_group_box ("Compile through uncond branch", complabels9, comp_constjump_widget, 1, comp_changed); + gtk_widget_show (newbox); + add_centered_to_vbox (vbox, newbox); + + newbox = make_radio_group_box ("JIT FPU compiler", complabels7, compfpu_widget, 1, comp_changed); + gtk_widget_show (newbox); + add_centered_to_vbox (vbox, newbox); + +#if USE_OPTIMIZER + newbox = make_radio_group_box ("Mid Level Optimizer", complabels5, comp_midopt_widget, 1, comp_changed); + gtk_widget_show (newbox); + add_centered_to_vbox (vbox, newbox); +#endif + +#if USE_LOW_OPTIMIZER + newbox = make_radio_group_box ("Low Level Optimizer", complabels6, comp_lowopt_widget, 1, comp_changed); + gtk_widget_show (newbox); + add_centered_to_vbox (vbox, newbox); +#endif + + cachesize_adj = GTK_ADJUSTMENT (gtk_adjustment_new (currprefs.cachesize, 0.0, 16384.0, 1.0, 1.0, 1.0)); + gtk_signal_connect (GTK_OBJECT (cachesize_adj), "value_changed", + GTK_SIGNAL_FUNC (comp_changed), NULL); + + thing = gtk_hscale_new (cachesize_adj); + gtk_range_set_update_policy (GTK_RANGE (thing), GTK_UPDATE_DELAYED); + gtk_scale_set_digits (GTK_SCALE (thing), 0); + gtk_scale_set_value_pos (GTK_SCALE (thing), GTK_POS_RIGHT); + add_labelled_widget_centered ("Translation buffer(kB):", thing, vbox); + + add_empty_vbox (vbox); +} + + +static void make_joy_widgets (GtkWidget *dvbox) +{ + int i; + GtkWidget *hbox = gtk_hbox_new (FALSE, 10); + static const char *joylabels[] = { + "Joystick 0", "Joystick 1", "Mouse", "Numeric pad", + "Cursor keys/Right Ctrl", "T/F/H/B/Left Alt", + NULL + }; + + add_empty_vbox (dvbox); + gtk_widget_show (hbox); + add_centered_to_vbox (dvbox, hbox); + + for (i = 0; i < 2; i++) { + GtkWidget *vbox, *frame; + GtkWidget *thing; + char buffer[20]; + int j; + + sprintf (buffer, "Port %d", i); + frame = make_radio_group_box (buffer, joylabels, joy_widget[i], 0, joy_changed); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, TRUE, 0); + } + + add_empty_vbox (dvbox); +} + +static int hd_change_mode; + +static void newdir_ok (void) +{ + int n; + strcpy (dirdlg_volname, gtk_entry_get_text (GTK_ENTRY (volname_entry))); + strcpy (dirdlg_path, gtk_entry_get_text (GTK_ENTRY (path_entry))); + + n = strlen (dirdlg_volname); + /* Strip colons from the end. */ + if (n > 0) { + if (dirdlg_volname[n - 1] == ':') + dirdlg_volname[n - 1] = '\0'; + } + if (strlen (dirdlg_volname) == 0 || strlen (dirdlg_path) == 0) { + /* Uh, no messageboxes in gtk? */ + } else if (hd_change_mode) { + set_filesys_unit (currprefs.mountinfo, selected_hd_row, dirdlg_volname, dirdlg_path, + 0, 0, 0, 0, 0); + set_hd_state (); + } else { + add_filesys_unit (currprefs.mountinfo, dirdlg_volname, dirdlg_path, + 0, 0, 0, 0, 0); + set_hd_state (); + } + gtk_widget_destroy (dirdlg); +} + +static GtkWidget *create_dirdlg (const char *title) +{ + GtkWidget *vbox, *hbox, *thing, *label1, *button; + + dirdlg = gtk_dialog_new (); + + gtk_window_set_title (GTK_WINDOW (dirdlg), title); + gtk_window_set_position (GTK_WINDOW (dirdlg), GTK_WIN_POS_MOUSE); + gtk_window_set_modal (GTK_WINDOW (dirdlg), TRUE); + gtk_widget_show (dirdlg); + + vbox = GTK_DIALOG (dirdlg)->vbox; + hbox = gtk_hbox_new (FALSE, 10); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 10); + label1 = gtk_label_new ("Path:"); + gtk_box_pack_start (GTK_BOX (hbox), label1, FALSE, TRUE, 10); + gtk_widget_show (label1); + thing = gtk_entry_new_with_max_length (255); + gtk_box_pack_start (GTK_BOX (hbox), thing, TRUE, TRUE, 10); + gtk_widget_show (thing); + path_entry = thing; + + hbox = gtk_hbox_new (FALSE, 10); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 10); + thing = gtk_label_new ("Volume name:"); + gtk_box_pack_start (GTK_BOX (hbox), thing, FALSE, TRUE, 10); + gtk_widget_show (thing); + thing = gtk_entry_new_with_max_length (255); + gtk_box_pack_start (GTK_BOX (hbox), thing, TRUE, TRUE, 10); + gtk_widget_show (thing); + gtk_widget_set_usize (thing, 200, -1); + volname_entry = thing; + + hbox = GTK_DIALOG (dirdlg)->action_area; + button = gtk_button_new_with_label ("OK"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC(newdir_ok), NULL); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Cancel"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + GTK_OBJECT (dirdlg)); + gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); + gtk_widget_show (button); +} + +static void did_newdir (void) +{ + hd_change_mode = 0; + create_dirdlg ("Add a new mounted directory"); +} +static void did_newhdf (void) +{ + hd_change_mode = 0; +} + +static void did_hdchange (void) +{ + int secspertrack, surfaces, reserved, blocksize, size; + int cylinders, readonly; + char *volname, *rootdir; + char *failure; + + failure = get_filesys_unit (currprefs.mountinfo, selected_hd_row, + &volname, &rootdir, &readonly, + &secspertrack, &surfaces, &reserved, + &cylinders, &size, &blocksize); + + hd_change_mode = 1; + if (is_hardfile (currprefs.mountinfo, selected_hd_row)) { + } else { + create_dirdlg ("Change a mounted directory"); + gtk_entry_set_text (GTK_ENTRY (volname_entry), volname); + gtk_entry_set_text (GTK_ENTRY (path_entry), rootdir); + } +} +static void did_hddel (void) +{ + kill_filesys_unit (currprefs.mountinfo, selected_hd_row); + set_hd_state (); +} + +static void hdselect (GtkWidget *widget, gint row, gint column, GdkEventButton *bevent, + gpointer user_data) +{ + selected_hd_row = row; + gtk_widget_set_sensitive (hdchange_button, TRUE); + gtk_widget_set_sensitive (hddel_button, TRUE); +} + +static void hdunselect (GtkWidget *widget, gint row, gint column, GdkEventButton *bevent, + gpointer user_data) +{ + gtk_widget_set_sensitive (hdchange_button, FALSE); + gtk_widget_set_sensitive (hddel_button, FALSE); +} + + +static GtkWidget *make_buttons (const char *label, GtkWidget *box, void (*sigfunc) (void), GtkWidget *(*create)(const char *label)) +{ + GtkWidget *thing = create (label); + gtk_widget_show (thing); + gtk_signal_connect (GTK_OBJECT (thing), "clicked", (GtkSignalFunc) sigfunc, NULL); + gtk_box_pack_start (GTK_BOX (box), thing, TRUE, TRUE, 0); + + return thing; +} +#define make_button(label, box, sigfunc) make_buttons(label, box, sigfunc, gtk_button_new_with_label) + +static void make_hd_widgets (GtkWidget *dvbox) +{ + GtkWidget *thing, *buttonbox, *hbox; + char *titles [] = { + "Volume", "File/Directory", "R/O", "Heads", "Cyl.", "Sec.", "Rsrvd", "Size", "Blksize" + }; + + thing = gtk_clist_new_with_titles (9, titles); + gtk_clist_set_selection_mode (GTK_CLIST (thing), GTK_SELECTION_SINGLE); + gtk_signal_connect (GTK_OBJECT (thing), "select_row", (GtkSignalFunc) hdselect, NULL); + gtk_signal_connect (GTK_OBJECT (thing), "unselect_row", (GtkSignalFunc) hdunselect, NULL); + hdlist_widget = thing; + gtk_widget_set_usize (thing, -1, 200); + + gtk_widget_show (thing); + add_centered_to_vbox (dvbox, thing); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (dvbox), hbox, FALSE, TRUE, 0); + + /* The buttons */ + buttonbox = gtk_hbox_new (TRUE, 4); + gtk_widget_show (buttonbox); + gtk_box_pack_start (GTK_BOX (hbox), buttonbox, TRUE, TRUE, 0); + make_button ("New filesystem...", buttonbox, did_newdir); +#if 0 /* later... */ + make_button ("New hardfile...", buttonbox, did_newhdf); +#endif + hdchange_button = make_button ("Change...", buttonbox, did_hdchange); + hddel_button = make_button ("Delete", buttonbox, did_hddel); + + thing = gtk_label_new ("These settings take effect after the next reset."); + gtk_widget_show (thing); + add_centered_to_vbox (dvbox, thing); +} + +static void make_about_widgets (GtkWidget *dvbox) +{ + GtkWidget *thing; + GtkStyle *style; + GdkFont *font; + char t[20]; + + add_empty_vbox (dvbox); + + sprintf (t, "UAE %d.%d.%d", UAEMAJOR, UAEMINOR, UAESUBREV); + thing = gtk_label_new (t); + gtk_widget_show (thing); + add_centered_to_vbox (dvbox, thing); + + font = gdk_font_load ("-*-helvetica-medium-r-normal--*-240-*-*-*-*-*-*"); + if (font) { + style = gtk_style_copy (GTK_WIDGET (thing)->style); + gdk_font_unref (style->font); + style->font = font; + gdk_font_ref (style->font); + gtk_widget_push_style (style); + gtk_widget_set_style (thing, style); + } + thing = gtk_label_new ("Choose your settings, then deselect the Pause button to start!"); + gtk_widget_show (thing); + add_centered_to_vbox (dvbox, thing); + + add_empty_vbox (dvbox); +} + + +static void create_guidlg (void) +{ + GtkWidget *window, *notebook; + GtkWidget *buttonbox, *vbox, *hbox; + GtkWidget *thing; + int i; + int argc = 1; + char *a[] = {"UAE"}; + char **argv = a; + static const struct _pages { + const char *title; + void (*createfunc)(GtkWidget *); + } pages[] = { + /* ??? If this isn't the first page, there are errors in draw_led. */ + { "Floppy disks", make_floppy_disks }, + { "Memory", make_mem_widgets }, + { "CPU emulation", make_cpu_widgets }, + { "Graphics", make_gfx_widgets }, + { "Chipset", make_chipset_widgets }, + { "Sound", make_sound_widgets }, + { "JIT", make_comp_widgets }, + { "Game ports", make_joy_widgets }, + { "Harddisks", make_hd_widgets }, + { "About", make_about_widgets } + }; + + gtk_init (&argc, &argv); + gtk_rc_parse ("uaegtkrc"); + + gui_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (gui_window), "UAE control"); + + vbox = gtk_vbox_new (FALSE, 4); + gtk_container_add (GTK_CONTAINER (gui_window), vbox); + gtk_container_set_border_width (GTK_CONTAINER (gui_window), 10); + + /* First line - buttons and power LED */ + hbox = gtk_hbox_new (FALSE, 10); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + + /* The buttons */ + buttonbox = gtk_hbox_new (TRUE, 4); + gtk_widget_show (buttonbox); + gtk_box_pack_start (GTK_BOX (hbox), buttonbox, TRUE, TRUE, 0); + make_button ("Reset", buttonbox, did_reset); + make_button ("Debug", buttonbox, did_debug); + make_button ("Quit", buttonbox, did_quit); + make_button ("Save config", buttonbox, save_config); + pause_uae_widget = make_buttons ("Pause", buttonbox, pause_uae, gtk_toggle_button_new_with_label); + + /* The LED */ + thing = make_led (0); + thing = make_labelled_widget ("Power:", thing); + gtk_widget_show (thing); + gtk_box_pack_start (GTK_BOX (hbox), thing, FALSE, TRUE, 0); + + /* More buttons */ + buttonbox = gtk_hbox_new (TRUE, 4); + gtk_widget_show (buttonbox); + gtk_box_pack_start (GTK_BOX (vbox), buttonbox, TRUE, TRUE, 0); + snap_save_widget = make_button ("Save state", buttonbox, did_savestate); + snap_load_widget = make_button ("Load state", buttonbox, did_loadstate); + + /* Place a separator below those buttons. */ + thing = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), thing, FALSE, TRUE, 0); + gtk_widget_show (thing); + + /* Now the notebook */ + notebook = gtk_notebook_new (); + gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0); + gtk_widget_show (notebook); + + for (i = 0; i < sizeof pages / sizeof (struct _pages); i++) { + thing = gtk_vbox_new (FALSE, 4); + gtk_widget_show (thing); + gtk_container_set_border_width (GTK_CONTAINER (thing), 10); + pages[i].createfunc (thing); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), thing, gtk_label_new (pages[i].title)); + } + + /* Put "about" screen first. */ + gtk_notebook_set_page (GTK_NOTEBOOK (notebook), i - 1); + enable_disk_buttons (1); + enable_snap_buttons (1); + + gtk_widget_show (vbox); + + filesel_active = -1; + snapsel_active = -1; + + gtk_timeout_add (1000, (GtkFunction)my_idle, 0); +} + +static void *gtk_gui_thread (void *dummy) +{ + gtk_main (); + + quitted_gui = 1; + uae_sem_post (&gui_quit_sem); + return 0; +} + +void gui_changesettings(void) +{ + +} + +void gui_fps (int x) +{ +} + +void gui_led (int num, int on) +{ + if (no_gui) + return; + +/* if (num == 0) + return; + printf("LED %d %d\n", num, on); + write_comm_pipe_int (&to_gui_pipe, 1, 0); + write_comm_pipe_int (&to_gui_pipe, num == 0 ? 4 : num - 1, 0); + write_comm_pipe_int (&to_gui_pipe, on, 1); + printf("#LED %d %d\n", num, on);*/ +} + +void gui_filename (int num, const char *name) +{ + if (no_gui) + return; + + write_comm_pipe_int (&to_gui_pipe, 0, 0); + write_comm_pipe_int (&to_gui_pipe, num, 1); + +/* gui_update ();*/ +} + +void gui_handle_events (void) +{ + int pause_uae = FALSE; + + if (no_gui) + return; + + do { + while (pause_uae || comm_pipe_has_data (&from_gui_pipe)) { + int cmd = read_comm_pipe_int_blocking (&from_gui_pipe); + int n; + switch (cmd) { + case 0: + n = read_comm_pipe_int_blocking (&from_gui_pipe); + changed_prefs.df[n][0] = '\0'; + break; + case 1: + n = read_comm_pipe_int_blocking (&from_gui_pipe); + uae_sem_wait (&gui_sem); + strncpy (changed_prefs.df[n], new_disk_string[n], 255); + free (new_disk_string[n]); + new_disk_string[n] = 0; + changed_prefs.df[n][255] = '\0'; + uae_sem_post (&gui_sem); + break; + case 2: + uae_reset (); + end_pause_uae (); + break; + case 3: + activate_debugger (); + end_pause_uae (); + break; + case 4: + uae_quit (); + end_pause_uae (); + break; + case 5: + pause_uae = TRUE; + break; + case 6: + pause_uae = FALSE; + break; + case 7: + printf ("STATESAVE\n"); + savestate_state = read_comm_pipe_int_blocking (&from_gui_pipe); + uae_sem_wait (&gui_sem); + savestate_filename = gui_snapname; + uae_sem_post (&gui_sem); + break; + case 8: + uae_sem_wait (&gui_sem); + strncpy (changed_prefs.romfile, gui_romname, 255); + changed_prefs.romfile[255] = '\0'; + free (gui_romname); + uae_sem_post (&gui_sem); + break; + case 9: + uae_sem_wait (&gui_sem); + strncpy (changed_prefs.keyfile, gui_keyname, 255); + changed_prefs.keyfile[255] = '\0'; + free (gui_keyname); + uae_sem_post (&gui_sem); + break; + } + } + } while (pause_uae); +} + +void gui_update_gfx (void) +{ +#if 0 /* This doesn't work... */ + set_gfx_state (); +#endif +} + +int gui_init (void) +{ + uae_thread_id tid; + + gui_active = 0; + + init_comm_pipe (&to_gui_pipe, 20, 1); + init_comm_pipe (&from_gui_pipe, 20, 1); + uae_sem_init (&gui_sem, 0, 1); + uae_sem_init (&gui_init_sem, 0, 0); + uae_sem_init (&gui_quit_sem, 0, 0); + + create_guidlg (); + uae_start_thread (gtk_gui_thread, NULL, &tid); + gui_update (); + + if (currprefs.start_gui == 1) { + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pause_uae_widget), TRUE); + write_comm_pipe_int (&from_gui_pipe, 5, 1); + /* Handle events until Pause is unchecked. */ + gui_handle_events (); + /* Quit requested? */ + if (quit_program == -1) { + gui_exit (); + return -2; + } + } + + return 1; +} + +int gui_update (void) +{ + if (no_gui) + return 0; + + write_comm_pipe_int (&to_gui_pipe, 1, 1); + uae_sem_wait (&gui_init_sem); + return 0; +} + +void gui_exit (void) +{ + if (no_gui) + return; + + quit_gui = 1; + uae_sem_wait (&gui_quit_sem); +} + +void gui_lock (void) +{ + uae_sem_wait (&gui_sem); +} + +void gui_unlock (void) +{ + uae_sem_post (&gui_sem); +} diff --git a/hardfile.c b/hardfile.c new file mode 100755 index 00000000..c5ec6ad5 --- /dev/null +++ b/hardfile.c @@ -0,0 +1,825 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Hardfile emulation + * + * Copyright 1995 Bernd Schmidt + * 2002 Toni Wilen (scsi emulation, 64-bit support) + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "threaddep/thread.h" +#include "options.h" +#include "memory.h" +#include "custom.h" +#include "newcpu.h" +#include "disk.h" +#include "autoconf.h" +#include "filesys.h" +#include "execlib.h" +#include "native2amiga.h" +#include "gui.h" +#include "uae.h" + +#define CMD_INVALID 0 +#define CMD_RESET 1 +#define CMD_READ 2 +#define CMD_WRITE 3 +#define CMD_UPDATE 4 +#define CMD_CLEAR 5 +#define CMD_STOP 6 +#define CMD_START 7 +#define CMD_FLUSH 8 +#define CMD_MOTOR 9 +#define CMD_SEEK 10 +#define CMD_FORMAT 11 +#define CMD_REMOVE 12 +#define CMD_CHANGENUM 13 +#define CMD_CHANGESTATE 14 +#define CMD_PROTSTATUS 15 +#define CMD_GETDRIVETYPE 18 +#define CMD_GETNUMTRACKS 19 +#define CMD_ADDCHANGEINT 20 +#define CMD_REMCHANGEINT 21 +#define CMD_GETGEOMETRY 22 +#define HD_SCSICMD 28 + +/* Trackdisk64 support */ +#define TD_READ64 24 +#define TD_WRITE64 25 +#define TD_SEEK64 26 +#define TD_FORMAT64 27 + +/* New Style Devices (NSD) support */ +#define DRIVE_NEWSTYLE 0x4E535459L /* 'NSTY' */ +#define NSCMD_DEVICEQUERY 0x4000 +#define NSCMD_TD_READ64 0xc000 +#define NSCMD_TD_WRITE64 0xc001 +#define NSCMD_TD_SEEK64 0xc002 +#define NSCMD_TD_FORMAT64 0xc003 + +#undef DEBUGME +//#define DEBUGME +#ifdef DEBUGME +#define hf_log write_log +#define hf_log2 write_log +#define scsi_log write_log +#else +#define hf_log +#define hf_log2 +#define scsi_log +#endif + +#define MAX_ASYNC_REQUESTS 50 +#define ASYNC_REQUEST_NONE 0 +#define ASYNC_REQUEST_TEMP 1 +#define ASYNC_REQUEST_CHANGEINT 10 + +static struct hardfileprivdata { + volatile uaecptr d_request[MAX_ASYNC_REQUESTS]; + volatile int d_request_type[MAX_ASYNC_REQUESTS]; + volatile uae_u32 d_request_data[MAX_ASYNC_REQUESTS]; + smp_comm_pipe requests; + uae_thread_id tid; + int thread_running; + uae_sem_t sync_sem; + int opencount; +}; + +static uae_sem_t change_sem; + +static struct hardfileprivdata hardfpd[MAX_FILESYSTEM_UNITS]; + +static uae_u32 nscmd_cmd; + +static void wl (uae_u8 *p, int v) +{ + p[0] = v >> 24; + p[1] = v >> 16; + p[2] = v >> 8; + p[3] = v; +} +static int rl (uae_u8 *p) +{ + return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]); +} + +static uae_u64 cmd_read (struct hardfiledata *hfd, uaecptr dataptr, uae_u64 offset, uae_u64 len) +{ + uae_u64 got = 0; + uae_u8 buffer[FILESYS_MAX_BLOCKSIZE]; + + gui_hd_led (1); + hf_log2 ("cmd_read: %p %04.4x-%08.8x %08.8x\n", dataptr, (uae_u32)(offset >> 32), (uae_u32)offset, (uae_u32)len); + while (len > 0) { + int i, got2; + got2 = hdf_read (hfd, buffer, offset, hfd->blocksize); + if (got2 != hfd->blocksize) + break; + for (i = 0; i < got2; i++) + put_byte(dataptr + i, buffer[i]); + len -= got2; + got += got2; + dataptr += got2; + offset += got2; + } + return got; +} + +static uae_u64 cmd_write (struct hardfiledata *hfd, uaecptr dataptr, uae_u64 offset, uae_u64 len) +{ + uae_u64 got = 0; + uae_u8 buffer[FILESYS_MAX_BLOCKSIZE]; + + gui_hd_led (1); + hf_log2 ("cmd_write: %p %04.4x-%08.8x %08.8x\n", dataptr, (uae_u32)(offset >> 32), (uae_u32)offset, (uae_u32)len); + while (len > 0) { + int i, got2; + for (i = 0; i < hfd->blocksize; i++) + buffer[i] = get_byte (dataptr + i); + got2 = hdf_write (hfd, buffer, offset, hfd->blocksize); + if (got2 != hfd->blocksize) + break; + len -= got2; + got += got2; + dataptr += got2; + offset += got2; + } + return got; +} + +static int handle_scsi (uaecptr request, struct hardfiledata *hfd) +{ + uae_u32 acmd = get_long (request + 40); + uaecptr scsi_data = get_long (acmd + 0); + uae_u32 scsi_len = get_long (acmd + 4); + uaecptr scsi_cmd = get_long (acmd + 12); + uae_u16 scsi_cmd_len = get_word (acmd + 16); + uae_u8 scsi_flags = get_byte (acmd + 20); + uaecptr scsi_sense = get_long (acmd + 22); + uae_u16 scsi_sense_len = get_word (acmd + 26); + uae_u8 cmd = get_byte (scsi_cmd); + uae_u8 cmdbuf[256]; + int status, ret = 0, lr, ls; + uae_u32 i; + uae_u8 r[256], s[256]; + uae_u64 len, offset; + + scsi_sense_len = (scsi_flags & 4) ? 4 : /* SCSIF_OLDAUTOSENSE */ + (scsi_flags & 2) ? scsi_sense_len : /* SCSIF_AUTOSENSE */ + 32; + status = 0; + memset (r, 0, sizeof (r)); + lr = 0; ls = 0; + scsi_log ("hdf scsiemu: cmd=%02.2X,%d flags=%02.2X sense=%p,%d data=%p,%d\n", + cmd, scsi_cmd_len, scsi_flags, scsi_sense, scsi_sense_len, scsi_data, scsi_len); + for (i = 0; i < scsi_cmd_len; i++) { + cmdbuf[i] = get_byte (scsi_cmd + i); + scsi_log ("%02.2X%c", get_byte (scsi_cmd + i), i < scsi_cmd_len - 1 ? '.' : ' '); + } + scsi_log ("\n"); + + switch (cmd) + { + case 0x00: /* TEST UNIT READY */ + break; + case 0x08: /* READ (6) */ + offset = ((cmdbuf[1] & 31) << 16) | (cmdbuf[2] << 8) | cmdbuf[3]; + offset *= hfd->blocksize; + len = cmdbuf[4]; + if (!len) len = 256; + len *= hfd->blocksize; + scsi_len = (uae_u32)cmd_read (hfd, scsi_data, offset, len); + break; + case 0x0a: /* WRITE (6) */ + offset = ((cmdbuf[1] & 31) << 16) | (cmdbuf[2] << 8) | cmdbuf[3]; + offset *= hfd->blocksize; + len = cmdbuf[4]; + if (!len) len = 256; + len *= hfd->blocksize; + scsi_len = (uae_u32)cmd_write (hfd, scsi_data, offset, len); + break; + case 0x12: /* INQUIRY */ + len = cmdbuf[4]; + r[2] = 2; /* supports SCSI-2 */ + r[3] = 2; /* response data format */ + r[4] = 32; /* additional length */ + r[7] = 0x20; /* 16 bit bus */ + i = 0; /* vendor id */ + while (i < 8 && hfd->vendor_id[i]) { + r[8 + i] = hfd->vendor_id[i]; + i++; + } + while (i < 8) { + r[8 + i] = 32; + i++; + } + i = 0; /* product id */ + while (i < 16 && hfd->product_id[i]) { + r[16 + i] = hfd->product_id[i]; + i++; + } + while (i < 16) { + r[16 + i] = 32; + i++; + } + i = 0; /* product revision */ + while (i < 4 && hfd->product_rev[i]) { + r[32 + i] = hfd->product_rev[i]; + i++; + } + while (i < 4) { + r[32 + i] = 32; + i++; + } + scsi_len = lr = len < 36 ? (uae_u32)len : 36; + break; + case 0x25: /* READ_CAPACITY */ + wl (r, (uae_u32)(hfd->size / hfd->blocksize - 1)); + wl (r + 4, hfd->blocksize); + scsi_len = lr = 8; + break; + case 0x28: /* READ (10) */ + offset = rl (cmdbuf + 2); + offset *= hfd->blocksize; + len = rl (cmdbuf + 7 - 2) & 0xffff; + len *= hfd->blocksize; + scsi_len = (uae_u32)cmd_read (hfd, scsi_data, offset, len); + break; + case 0x2a: /* WRITE (10) */ + offset = rl (cmdbuf + 2); + offset *= hfd->blocksize; + len = rl (cmdbuf + 7 - 2) & 0xffff; + len *= hfd->blocksize; + scsi_len = (uae_u32)cmd_write (hfd, scsi_data, offset, len); + break; + case 0xa8: /* READ (12) */ + offset = rl (cmdbuf + 2); + offset *= hfd->blocksize; + len = rl (cmdbuf + 6); + len *= hfd->blocksize; + scsi_len = (uae_u32)cmd_read (hfd, scsi_data, offset, len); + break; + case 0xaa: /* WRITE (12) */ + offset = rl (cmdbuf + 2); + offset *= hfd->blocksize; + len = rl (cmdbuf + 6); + len *= hfd->blocksize; + scsi_len = (uae_u32)cmd_write (hfd, scsi_data, offset, len); + break; + default: + lr = -1; + write_log ("unsupported scsi command 0x%02.2X\n", cmd); + status = 2; /* CHECK CONDITION */ + s[0] = 0x70; + s[2] = 5; /* ILLEGAL REQUEST */ + s[12] = 0x24; /* ILLEGAL FIELD IN CDB */ + ls = 12; + break; + } + put_word (acmd + 18, status != 0 ? 0 : scsi_cmd_len); /* fake scsi_CmdActual */ + put_byte (acmd + 21, status); /* scsi_Status */ + if (lr > 0) { + scsi_log ("RD:"); + i = 0; + while (i < lr && i < scsi_len) { + if (i < 24) + scsi_log ("%02.2X%c", r[i], i < scsi_len - 1 ? '.' : ' '); + put_byte (scsi_data + i, r[i]); + i++; + } + scsi_log ("\n"); + } + i = 0; + if (ls > 0 && scsi_sense) { + while (i < ls && i < scsi_sense_len) { + put_byte (scsi_sense + i, s[i]); + i++; + } + } + while (i < scsi_sense_len && scsi_sense) { + put_byte (scsi_sense + i, 0); + i++; + } + if (lr < 0) { + put_long (acmd + 8, 0); /* scsi_Actual */ + ret = 20; + } else { + put_long (acmd + 8, scsi_len); /* scsi_Actual */ + } + return ret; +} + +static int add_async_request (struct hardfileprivdata *hfpd, uaecptr request, int type, uae_u32 data) +{ + int i; + + i = 0; + while (i < MAX_ASYNC_REQUESTS) { + if (hfpd->d_request[i] == request) { + hfpd->d_request_type[i] = type; + hfpd->d_request_data[i] = data; + hf_log ("old async request %p (%d) added\n", request, type); + return 0; + } + i++; + } + i = 0; + while (i < MAX_ASYNC_REQUESTS) { + if (hfpd->d_request[i] == 0) { + hfpd->d_request[i] = request; + hfpd->d_request_type[i] = type; + hfpd->d_request_data[i] = data; + hf_log ("async request %p (%d) added (total=%d)\n", request, type, i); + return 0; + } + i++; + } + hf_log ("async request overflow %p!\n", request); + return -1; +} + +static int release_async_request (struct hardfileprivdata *hfpd, uaecptr request) +{ + int i = 0; + + while (i < MAX_ASYNC_REQUESTS) { + if (hfpd->d_request[i] == request) { + int type = hfpd->d_request_type[i]; + hfpd->d_request[i] = 0; + hfpd->d_request_data[i] = 0; + hfpd->d_request_type[i] = 0; + hf_log ("async request %p removed\n", request); + return type; + } + i++; + } + hf_log ("tried to remove non-existing request %p\n", request); + return -1; +} + +static void abort_async (struct hardfileprivdata *hfpd, uaecptr request, int errcode, int type) +{ + int i; + hf_log ("aborting async request %p\n", request); + i = 0; + while (i < MAX_ASYNC_REQUESTS) { + if (hfpd->d_request[i] == request && hfpd->d_request_type[i] == ASYNC_REQUEST_TEMP) { + /* ASYNC_REQUEST_TEMP = request is processing */ + sleep_millis (1); + i = 0; + continue; + } + i++; + } + i = release_async_request (hfpd, request); + if (i >= 0) + hf_log ("asyncronous request=%08.8X aborted, error=%d\n", request, errcode); +} + +static void *hardfile_thread (void *devs); +static int start_thread (int unit) +{ + struct hardfileprivdata *hfpd = &hardfpd[unit]; + + if (hfpd->thread_running) + return 1; + memset (hfpd, 0, sizeof (struct hardfileprivdata)); + init_comm_pipe (&hfpd->requests, 100, 1); + uae_sem_init (&hfpd->sync_sem, 0, 0); + uae_start_thread (hardfile_thread, hfpd, &hfpd->tid); + uae_sem_wait (&hfpd->sync_sem); + return hfpd->thread_running; +} + +static int mangleunit (int unit) +{ + if (unit <= 99) + return unit; + if (unit == 100) + return 8; + if (unit == 110) + return 9; + return -1; +} + +static uae_u32 hardfile_open (void) +{ + uaecptr tmp1 = m68k_areg(regs, 1); /* IOReq */ + int unit = mangleunit (m68k_dreg (regs, 0)); + struct hardfileprivdata *hfpd = &hardfpd[unit]; + + hf_log ("hardfile_open, unit %d (%d)\n", unit, m68k_dreg (regs, 0)); + /* Check unit number */ + if (unit >= 0 && get_hardfile_data (unit) && start_thread (unit)) { + hfpd->opencount++; + put_word (m68k_areg(regs, 6) + 32, get_word (m68k_areg(regs, 6) + 32) + 1); + put_long (tmp1 + 24, unit); /* io_Unit */ + put_byte (tmp1 + 31, 0); /* io_Error */ + put_byte (tmp1 + 8, 7); /* ln_type = NT_REPLYMSG */ + return 0; + } + + put_long (tmp1 + 20, (uae_u32)-1); + put_byte (tmp1 + 31, (uae_u8)-1); + return (uae_u32)-1; +} + +static uae_u32 hardfile_close (void) +{ + uaecptr request = m68k_areg(regs, 1); /* IOReq */ + int unit = mangleunit (get_long (request + 24)); + struct hardfileprivdata *hfpd = &hardfpd[unit]; + + if (!hfpd->opencount) return 0; + hfpd->opencount--; + if (hfpd->opencount == 0) + write_comm_pipe_u32 (&hfpd->requests, 0, 1); + put_word (m68k_areg(regs, 6) + 32, get_word (m68k_areg(regs, 6) + 32) - 1); + return 0; +} + +static uae_u32 hardfile_expunge (void) +{ + return 0; /* Simply ignore this one... */ +} + +static uae_u32 hardfile_do_io (struct hardfiledata *hfd, struct hardfileprivdata *hfpd, uaecptr request) +{ + uae_u32 dataptr, offset, actual = 0, cmd; + uae_u64 offset64; + int unit = get_long (request + 24); + uae_u32 error = 0, len; + int async = 0; + int bmask = hfd->blocksize - 1; + + cmd = get_word (request + 28); /* io_Command */ + dataptr = get_long (request + 40); + switch (cmd) + { + case CMD_READ: + if (dataptr & 1) + goto bad_command; + offset = get_long (request + 44); + if (offset & bmask) + goto bad_command; + len = get_long (request + 36); /* io_Length */ + if (len & bmask) + goto bad_command; + if (len + offset > hfd->size) + goto bad_command; + actual = (uae_u32)cmd_read (hfd, dataptr, offset, len); + break; + + case TD_READ64: + case NSCMD_TD_READ64: + if (dataptr & 1) + goto bad_command; + offset64 = get_long (request + 44) | ((uae_u64)get_long (request + 32) << 32); + if (offset64 & bmask) + goto bad_command; + len = get_long (request + 36); /* io_Length */ + if (len & bmask) + goto bad_command; + if (len + offset64 > hfd->size) + goto bad_command; + actual = (uae_u32)cmd_read (hfd, dataptr, offset64, len); + break; + + case CMD_WRITE: + case CMD_FORMAT: /* Format */ + if (hfd->readonly) { + error = 28; /* write protect */ + } else { + if (dataptr & 1) + goto bad_command; + offset = get_long (request + 44); + if (offset & bmask) + goto bad_command; + len = get_long (request + 36); /* io_Length */ + if (len & bmask) + goto bad_command; + if (len + offset > hfd->size) + goto bad_command; + actual = (uae_u32)cmd_write (hfd, dataptr, offset, len); + } + break; + + case TD_WRITE64: + case TD_FORMAT64: + case NSCMD_TD_WRITE64: + case NSCMD_TD_FORMAT64: + if (hfd->readonly) { + error = 28; /* write protect */ + } else { + if (dataptr & 1) + goto bad_command; + offset64 = get_long (request + 44) | ((uae_u64)get_long (request + 32) << 32); + if (offset64 & bmask) + goto bad_command; + len = get_long (request + 36); /* io_Length */ + if (len & bmask) + goto bad_command; + if (len + offset64 > hfd->size) + goto bad_command; + put_long (request + 32, (uae_u32)cmd_write (hfd, dataptr, offset64, len)); + } + break; + + bad_command: + break; + + case NSCMD_DEVICEQUERY: + put_long (dataptr + 4, 16); /* size */ + put_word (dataptr + 8, 5); /* NSDEVTYPE_TRACKDISK */ + put_word (dataptr + 10, 0); + put_long (dataptr + 12, nscmd_cmd); + actual = 16; + break; + + case CMD_GETDRIVETYPE: + actual = DRIVE_NEWSTYLE; + break; + + case CMD_GETNUMTRACKS: + hf_log ("CMD_GETNUMTRACKS - shouldn't happen\n"); + actual = 0; + break; + + case CMD_PROTSTATUS: + if (hfd->readonly) + actual = -1; + else + actual = 0; + break; + + case CMD_CHANGESTATE: + actual = 0; + break; + + /* Some commands that just do nothing and return zero */ + case CMD_UPDATE: + case CMD_CLEAR: + case CMD_MOTOR: + case CMD_SEEK: + case CMD_CHANGENUM: + case TD_SEEK64: + case NSCMD_TD_SEEK64: + break; + + case CMD_REMOVE: + break; + + case CMD_ADDCHANGEINT: + error = add_async_request (hfpd, request, ASYNC_REQUEST_CHANGEINT, get_long (request + 40)); + if (!error) + async = 1; + break; + case CMD_REMCHANGEINT: + release_async_request (hfpd, request); + break; + + case HD_SCSICMD: /* SCSI */ + if (hfd->nrcyls == 0) + error = handle_scsi (request, hfd); + else /* we don't want users trashing their "partition" hardfiles with hdtoolbox */ + error = -3; /* io_Error */ + break; + + default: + /* Command not understood. */ + error = -3; /* io_Error */ + break; + } + put_long (request + 32, actual); + put_byte (request + 31, error); + + hf_log2 ("hf: unit=%d, request=%p, cmd=%d offset=%u len=%d, actual=%d error%=%d\n", unit, request, + get_word(request + 28), get_long (request + 44), get_long (request + 36), actual, error); + + return async; +} + +static uae_u32 hardfile_abortio (void) +{ + uae_u32 request = m68k_areg(regs, 1); + int unit = mangleunit (get_long (request + 24)); + struct hardfiledata *hfd = get_hardfile_data (unit); + struct hardfileprivdata *hfpd = &hardfpd[unit]; + + hf_log2 ("uaehf.device abortio "); + if (!hfd) { + put_byte (request + 31, 32); + hf_log2 ("error\n"); + return get_byte (request + 31); + } + put_byte (request + 31, -2); + hf_log2 ("unit=%d, request=%08.8X\n", unit, request); + abort_async (hfpd, request, -2, 0); + return 0; +} + +static int hardfile_can_quick (uae_u32 command) +{ + switch (command) + { + case CMD_RESET: + case CMD_STOP: + case CMD_START: + case CMD_CHANGESTATE: + case CMD_PROTSTATUS: + case CMD_MOTOR: + case CMD_GETDRIVETYPE: + case CMD_GETNUMTRACKS: + case NSCMD_DEVICEQUERY: + return 1; + } + return 0; +} + +static int hardfile_canquick (struct hardfiledata *hfd, uaecptr request) +{ + uae_u32 command = get_word (request + 28); + return hardfile_can_quick (command); +} + +static uae_u32 hardfile_beginio (void) +{ + uae_u32 request = m68k_areg(regs, 1); + uae_u8 flags = get_byte (request + 30); + int cmd = get_word (request + 28); + int unit = mangleunit (get_long (request + 24)); + struct hardfiledata *hfd = get_hardfile_data (unit); + struct hardfileprivdata *hfpd = &hardfpd[unit]; + + put_byte (request + 8, NT_MESSAGE); + if (!hfd) { + put_byte (request + 31, 32); + return get_byte (request + 31); + } + put_byte (request + 31, 0); + if ((flags & 1) && hardfile_canquick (hfd, request)) { + hf_log ("hf quickio unit=%d request=%p cmd=%d\n", unit, request, cmd); + if (hardfile_do_io (hfd, hfpd, request)) + hf_log2 ("uaehf.device cmd %d bug with IO_QUICK\n", cmd); + return get_byte (request + 31); + } else { + hf_log2 ("hf asyncio unit=%d request=%p cmd=%d\n", unit, request, cmd); + add_async_request (hfpd, request, ASYNC_REQUEST_TEMP, 0); + put_byte (request + 30, get_byte (request + 30) & ~1); + write_comm_pipe_u32 (&hfpd->requests, request, 1); + return 0; + } +} + +static void *hardfile_thread (void *devs) +{ + struct hardfileprivdata *hfpd = devs; + + set_thread_priority (2); + hfpd->thread_running = 1; + uae_sem_post (&hfpd->sync_sem); + for (;;) { + uaecptr request = (uaecptr)read_comm_pipe_u32_blocking (&hfpd->requests); + uae_sem_wait (&change_sem); + if (!request) { + hfpd->thread_running = 0; + uae_sem_post (&hfpd->sync_sem); + uae_sem_post (&change_sem); + return 0; + } else if (hardfile_do_io (get_hardfile_data (hfpd - &hardfpd[0]), hfpd, request) == 0) { + put_byte (request + 30, get_byte (request + 30) & ~1); + release_async_request (hfpd, request); + uae_ReplyMsg (request); + } else { + hf_log2 ("async request %08.8X\n", request); + } + uae_sem_post (&change_sem); + } +} + +void hardfile_reset (void) +{ + int i, j; + struct hardfileprivdata *hfpd; + + for (i = 0; i < MAX_FILESYSTEM_UNITS; i++) { + hfpd = &hardfpd[i]; + if (hfpd->opencount > 0) { + for (j = 0; j < MAX_ASYNC_REQUESTS; j++) { + uaecptr request; + if (request = hfpd->d_request[i]) + abort_async (hfpd, request, 0, 0); + } + } + memset (hfpd, 0, sizeof (struct hardfileprivdata)); + } +} + +void hardfile_install (void) +{ + uae_u32 functable, datatable; + uae_u32 initcode, openfunc, closefunc, expungefunc; + uae_u32 beginiofunc, abortiofunc; + + uae_sem_init (&change_sem, 0, 1); + + ROM_hardfile_resname = ds ("uaehf.device"); + ROM_hardfile_resid = ds ("UAE hardfile.device 0.2"); + + nscmd_cmd = here (); + dw (NSCMD_DEVICEQUERY); + dw (CMD_RESET); + dw (CMD_READ); + dw (CMD_WRITE); + dw (CMD_UPDATE); + dw (CMD_CLEAR); + dw (CMD_START); + dw (CMD_STOP); + dw (CMD_FLUSH); + dw (CMD_MOTOR); + dw (CMD_SEEK); + dw (CMD_FORMAT); + dw (CMD_REMOVE); + dw (CMD_CHANGENUM); + dw (CMD_CHANGESTATE); + dw (CMD_PROTSTATUS); + dw (CMD_GETDRIVETYPE); + dw (CMD_ADDCHANGEINT); + dw (CMD_REMCHANGEINT); + dw (HD_SCSICMD); + dw (NSCMD_TD_READ64); + dw (NSCMD_TD_WRITE64); + dw (NSCMD_TD_SEEK64); + dw (NSCMD_TD_FORMAT64); + dw (0); + + /* initcode */ +#if 0 + initcode = here (); + calltrap (deftrap (hardfile_init)); dw (RTS); +#else + initcode = filesys_initcode; +#endif + /* Open */ + openfunc = here (); + calltrap (deftrap (hardfile_open)); dw (RTS); + + /* Close */ + closefunc = here (); + calltrap (deftrap (hardfile_close)); dw (RTS); + + /* Expunge */ + expungefunc = here (); + calltrap (deftrap (hardfile_expunge)); dw (RTS); + + /* BeginIO */ + beginiofunc = here (); + calltrap (deftrap (hardfile_beginio)); + dw (RTS); + + /* AbortIO */ + abortiofunc = here (); + calltrap (deftrap (hardfile_abortio)); dw (RTS); + + /* FuncTable */ + functable = here (); + dl (openfunc); /* Open */ + dl (closefunc); /* Close */ + dl (expungefunc); /* Expunge */ + dl (EXPANSION_nullfunc); /* Null */ + dl (beginiofunc); /* BeginIO */ + dl (abortiofunc); /* AbortIO */ + dl (0xFFFFFFFFul); /* end of table */ + + /* DataTable */ + datatable = here (); + dw (0xE000); /* INITBYTE */ + dw (0x0008); /* LN_TYPE */ + dw (0x0300); /* NT_DEVICE */ + dw (0xC000); /* INITLONG */ + dw (0x000A); /* LN_NAME */ + dl (ROM_hardfile_resname); + dw (0xE000); /* INITBYTE */ + dw (0x000E); /* LIB_FLAGS */ + dw (0x0600); /* LIBF_SUMUSED | LIBF_CHANGED */ + dw (0xD000); /* INITWORD */ + dw (0x0014); /* LIB_VERSION */ + dw (0x0004); /* 0.4 */ + dw (0xD000); + dw (0x0016); /* LIB_REVISION */ + dw (0x0000); + dw (0xC000); + dw (0x0018); /* LIB_IDSTRING */ + dl (ROM_hardfile_resid); + dw (0x0000); /* end of table */ + + ROM_hardfile_init = here (); + dl (0x00000100); /* ??? */ + dl (functable); + dl (datatable); + dl (initcode); +} diff --git a/identify.c b/identify.c new file mode 100755 index 00000000..8d1bae6a --- /dev/null +++ b/identify.c @@ -0,0 +1,400 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Routines for labelling amiga internals. + * + */ + +#include "sysconfig.h" +#include "sysdeps.h" +#include "memory.h" +#include "identify.h" + +struct mem_labels int_labels[] = +{ + { "Reset:SSP", 0x0000 }, + { "EXECBASE", 0x0004 }, + { "BUS ERROR", 0x0008 }, + { "ADR ERROR", 0x000C }, + { "ILLEG OPC", 0x0010 }, + { "DIV BY 0", 0x0014 }, + { "CHK", 0x0018 }, + { "TRAPV", 0x001C }, + { "PRIVIL VIO", 0x0020 }, + { "TRACE", 0x0024 }, + { "LINEA EMU", 0x0028 }, + { "LINEF EMU", 0x002C }, + { "INT Uninit", 0x003C }, + { "INT Unjust", 0x0060 }, + { "Lvl 1 Int", 0x0064 }, + { "Lvl 2 Int", 0x0068 }, + { "Lvl 3 Int", 0x006C }, + { "Lvl 4 Int", 0x0070 }, + { "Lvl 5 Int", 0x0074 }, + { "Lvl 6 Int", 0x0078 }, + { "NMI", 0x007C }, + { 0, 0 } +}; + +struct mem_labels trap_labels[] = +{ + { "TRAP 00", 0x0080 }, + { "TRAP 01", 0x0084 }, + { "TRAP 02", 0x0088 }, + { "TRAP 03", 0x008C }, + { "TRAP 04", 0x0090 }, + { "TRAP 05", 0x0094 }, + { "TRAP 06", 0x0098 }, + { "TRAP 07", 0x009C }, + { "TRAP 08", 0x00A0 }, + { "TRAP 09", 0x00A4 }, + { "TRAP 10", 0x00A8 }, + { "TRAP 11", 0x00AC }, + { "TRAP 12", 0x00B0 }, + { "TRAP 13", 0x00B4 }, + { "TRAP 14", 0x00B8 }, + { "TRAP 15", 0x00BC }, + { 0, 0 } +}; + +struct mem_labels mem_labels[] = +{ + { "CIAB PRA", 0xBFD000 }, + { "CIAB PRB", 0xBFD100 }, + { "CIAB DDRA", 0xBFD200 }, + { "CIAB DDRB", 0xBFD300 }, + { "CIAB TALO", 0xBFD400 }, + { "CIAB TAHI", 0xBFD500 }, + { "CIAB TBLO", 0xBFD600 }, + { "CIAB TBHI", 0xBFD700 }, + { "CIAB TDLO", 0xBFD800 }, + { "CIAB TDMD", 0xBFD900 }, + { "CIAB TDHI", 0xBFDA00 }, + { "CIAB SDR", 0xBFDC00 }, + { "CIAB ICR", 0xBFDD00 }, + { "CIAB CRA", 0xBFDE00 }, + { "CIAB CRB", 0xBFDF00 }, + { "CIAA PRA", 0xBFE001 }, + { "CIAA PRB", 0xBFE101 }, + { "CIAA DDRA", 0xBFE201 }, + { "CIAA DDRB", 0xBFE301 }, + { "CIAA TALO", 0xBFE401 }, + { "CIAA TAHI", 0xBFE501 }, + { "CIAA TBLO", 0xBFE601 }, + { "CIAA TBHI", 0xBFE701 }, + { "CIAA TDLO", 0xBFE801 }, + { "CIAA TDMD", 0xBFE901 }, + { "CIAA TDHI", 0xBFEA01 }, + { "CIAA SDR", 0xBFEC01 }, + { "CIAA ICR", 0xBFED01 }, + { "CIAA CRA", 0xBFEE01 }, + { "CIAA CRB", 0xBFEF01 }, + { "CLK S1", 0xDC0000 }, + { "CLK S10", 0xDC0004 }, + { "CLK MI1", 0xDC0008 }, + { "CLK MI10", 0xDC000C }, + { "CLK H1", 0xDC0010 }, + { "CLK H10", 0xDC0014 }, + { "CLK D1", 0xDC0018 }, + { "CLK D10", 0xDC001C }, + { "CLK MO1", 0xDC0020 }, + { "CLK MO10", 0xDC0024 }, + { "CLK Y1", 0xDC0028 }, + { "CLK Y10", 0xDC002E }, + { "CLK WEEK", 0xDC0030 }, + { "CLK CD", 0xDC0034 }, + { "CLK CE", 0xDC0038 }, + { "CLK CF", 0xDC003C }, + { NULL, 0 } +}; + +/* This table was generated from the list of AGA chip names in + * AGA.guide available on aminet. It could well have errors in it. */ + +struct customData custd[] = +{ +#if 0 + { "BLTDDAT", 0xdff000 }, /* Blitter dest. early read (dummy address) */ +#endif + { "DMACONR", 0xdff002 }, /* Dma control (and blitter status) read */ + { "VPOSR", 0xdff004 }, /* Read vert most sig. bits (and frame flop */ + { "VHPOSR", 0xdff006 }, /* Read vert and horiz position of beam */ +#if 0 + { "DSKDATR", 0xdff008 }, /* Disk data early read (dummy address) */ +#endif + { "JOY0DAT", 0xdff00A }, /* Joystick-mouse 0 data (vert,horiz) */ + { "JOT1DAT", 0xdff00C }, /* Joystick-mouse 1 data (vert,horiz) */ + { "CLXDAT", 0xdff00E }, /* Collision data reg. (read and clear) */ + { "ADKCONR", 0xdff010 }, /* Audio,disk control register read */ + { "POT0DAT", 0xdff012 }, /* Pot counter pair 0 data (vert,horiz) */ + { "POT1DAT", 0xdff014 }, /* Pot counter pair 1 data (vert,horiz) */ + { "POTGOR", 0xdff016 }, /* Pot pin data read */ + { "SERDATR", 0xdff018 }, /* Serial port data and status read */ + { "DSKBYTR", 0xdff01A }, /* Disk data byte and status read */ + { "INTENAR", 0xdff01C }, /* Interrupt enable bits read */ + { "INTREQR", 0xdff01E }, /* Interrupt request bits read */ + { "DSKPTH", 0xdff020 }, /* Disk pointer (high 5 bits) */ + { "DSKPTL", 0xdff022 }, /* Disk pointer (low 15 bits) */ + { "DSKLEN", 0xdff024 }, /* Disk lentgh */ + { "DSKDAT", 0xdff026 }, /* Disk DMA data write */ +#if 0 + { "REFPTR", 0xdff028 }, /* Refresh pointer */ +#endif + { "VPOSW", 0xdff02A }, /* Write vert most sig. bits(and frame flop) */ + { "VHPOSW", 0xdff02C }, /* Write vert and horiz pos of beam */ + { "COPCON", 0xdff02e }, /* Coprocessor control reg (CDANG) */ + { "SERDAT", 0xdff030 }, /* Serial port data and stop bits write */ + { "SERPER", 0xdff032 }, /* Serial port period and control */ + { "POTGO", 0xdff034 }, /* Pot count start,pot pin drive enable data */ + { "JOYTEST", 0xdff036 }, /* Write to all 4 joystick-mouse counters at once */ + { "STREQU", 0xdff038 }, /* Strobe for horiz sync with VB and EQU */ + { "STRVBL", 0xdff03A }, /* Strobe for horiz sync with VB (vert blank) */ + { "STRHOR", 0xdff03C }, /* Strobe for horiz sync */ + { "STRLONG", 0xdff03E }, /* Strobe for identification of long horiz line */ + { "BLTCON0", 0xdff040 }, /* Blitter control reg 0 */ + { "BLTCON1", 0xdff042 }, /* Blitter control reg 1 */ + { "BLTAFWM", 0xdff044 }, /* Blitter first word mask for source A */ + { "BLTALWM", 0xdff046 }, /* Blitter last word mask for source A */ + { "BLTCPTH", 0xdff048 }, /* Blitter pointer to source C (high 5 bits) */ + { "BLTCPTL", 0xdff04A }, /* Blitter pointer to source C (low 15 bits) */ + { "BLTBPTH", 0xdff04C }, /* Blitter pointer to source B (high 5 bits) */ + { "BLTBPTL", 0xdff04E }, /* Blitter pointer to source B (low 15 bits) */ + { "BLTAPTH", 0xdff050 }, /* Blitter pointer to source A (high 5 bits) */ + { "BLTAPTL", 0xdff052 }, /* Blitter pointer to source A (low 15 bits) */ + { "BPTDPTH", 0xdff054 }, /* Blitter pointer to destn D (high 5 bits) */ + { "BLTDPTL", 0xdff056 }, /* Blitter pointer to destn D (low 15 bits) */ + { "BLTSIZE", 0xdff058 }, /* Blitter start and size (win/width,height) */ + { "BLTCON0L", 0xdff05A }, /* Blitter control 0 lower 8 bits (minterms) */ + { "BLTSIZV", 0xdff05C }, /* Blitter V size (for 15 bit vert size) */ + { "BLTSIZH", 0xdff05E }, /* Blitter H size & start (for 11 bit H size) */ + { "BLTCMOD", 0xdff060 }, /* Blitter modulo for source C */ + { "BLTBMOD", 0xdff062 }, /* Blitter modulo for source B */ + { "BLTAMOD", 0xdff064 }, /* Blitter modulo for source A */ + { "BLTDMOD", 0xdff066 }, /* Blitter modulo for destn D */ +#if 0 + { "Unknown", 0xdff068 }, /* Unknown or Unused */ + { "Unknown", 0xdff06a }, /* Unknown or Unused */ + { "Unknown", 0xdff06c }, /* Unknown or Unused */ + { "Unknown", 0xdff06e }, /* Unknown or Unused */ +#endif + { "BLTCDAT", 0xdff070 }, /* Blitter source C data reg */ + { "BLTBDAT", 0xdff072 }, /* Blitter source B data reg */ + { "BLTADAT", 0xdff074 }, /* Blitter source A data reg */ + { "BLTDDAT", 0xdff076 }, /* Blitter destination reg */ +#if 0 + { "SPRHDAT", 0xdff078 }, /* Ext logic UHRES sprite pointer and data identifier */ + { "BPLHDAT", 0xdff07A }, /* Ext logic UHRES bit plane identifier */ +#endif + { "LISAID", 0xdff07C }, /* Chip revision level for Denise/Lisa */ + { "DSKSYNC", 0xdff07E }, /* Disk sync pattern reg for disk read */ + { "COP1LCH", 0xdff080 }, /* Coprocessor first location reg (high 5 bits) */ + { "COP1LCL", 0xdff082 }, /* Coprocessor first location reg (low 15 bits) */ + { "COP2LCH", 0xdff084 }, /* Coprocessor second reg (high 5 bits) */ + { "COP2LCL", 0xdff086 }, /* Coprocessor second reg (low 15 bits) */ + { "COPJMP1", 0xdff088 }, /* Coprocessor restart at first location */ + { "COPJMP2", 0xdff08A }, /* Coprocessor restart at second location */ +#if 0 + { "COPINS", 0xdff08C }, /* Coprocessor inst fetch identify */ +#endif + { "DIWSTRT", 0xdff08E }, /* Display window start (upper left vert-hor pos) */ + { "DIWSTOP", 0xdff090 }, /* Display window stop (lower right vert-hor pos) */ + { "DDFSTRT", 0xdff092 }, /* Display bit plane data fetch start.hor pos */ + { "DDFSTOP", 0xdff094 }, /* Display bit plane data fetch stop.hor pos */ + { "DMACON", 0xdff096 }, /* DMA control write (clear or set) */ + { "CLXCON", 0xdff098 }, /* Collision control */ + { "INTENA", 0xdff09A }, /* Interrupt enable bits (clear or set bits) */ + { "INTREQ", 0xdff09C }, /* Interrupt request bits (clear or set bits) */ + { "ADKCON", 0xdff09E }, /* Audio,disk,UART,control */ + { "AUD0LCH", 0xdff0A0 }, /* Audio channel 0 location (high 5 bits) */ + { "AUD0LCL", 0xdff0A2 }, /* Audio channel 0 location (low 15 bits) */ + { "AUD0LEN", 0xdff0A4 }, /* Audio channel 0 lentgh */ + { "AUD0PER", 0xdff0A6 }, /* Audio channel 0 period */ + { "AUD0VOL", 0xdff0A8 }, /* Audio channel 0 volume */ + { "AUD0DAT", 0xdff0AA }, /* Audio channel 0 data */ +#if 0 + { "Unknown", 0xdff0AC }, /* Unknown or Unused */ + { "Unknown", 0xdff0AE }, /* Unknown or Unused */ +#endif + { "AUD1LCH", 0xdff0B0 }, /* Audio channel 1 location (high 5 bits) */ + { "AUD1LCL", 0xdff0B2 }, /* Audio channel 1 location (low 15 bits) */ + { "AUD1LEN", 0xdff0B4 }, /* Audio channel 1 lentgh */ + { "AUD1PER", 0xdff0B6 }, /* Audio channel 1 period */ + { "AUD1VOL", 0xdff0B8 }, /* Audio channel 1 volume */ + { "AUD1DAT", 0xdff0BA }, /* Audio channel 1 data */ +#if 0 + { "Unknown", 0xdff0BC }, /* Unknown or Unused */ + { "Unknown", 0xdff0BE }, /* Unknown or Unused */ +#endif + { "AUD2LCH", 0xdff0C0 }, /* Audio channel 2 location (high 5 bits) */ + { "AUD2LCL", 0xdff0C2 }, /* Audio channel 2 location (low 15 bits) */ + { "AUD2LEN", 0xdff0C4 }, /* Audio channel 2 lentgh */ + { "AUD2PER", 0xdff0C6 }, /* Audio channel 2 period */ + { "AUD2VOL", 0xdff0C8 }, /* Audio channel 2 volume */ + { "AUD2DAT", 0xdff0CA }, /* Audio channel 2 data */ +#if 0 + { "Unknown", 0xdff0CC }, /* Unknown or Unused */ + { "Unknown", 0xdff0CE }, /* Unknown or Unused */ +#endif + { "AUD3LCH", 0xdff0D0 }, /* Audio channel 3 location (high 5 bits) */ + { "AUD3LCL", 0xdff0D2 }, /* Audio channel 3 location (low 15 bits) */ + { "AUD3LEN", 0xdff0D4 }, /* Audio channel 3 lentgh */ + { "AUD3PER", 0xdff0D6 }, /* Audio channel 3 period */ + { "AUD3VOL", 0xdff0D8 }, /* Audio channel 3 volume */ + { "AUD3DAT", 0xdff0DA }, /* Audio channel 3 data */ +#if 0 + { "Unknown", 0xdff0DC }, /* Unknown or Unused */ + { "Unknown", 0xdff0DE }, /* Unknown or Unused */ +#endif + { "BPL1PTH", 0xdff0E0 }, /* Bit plane pointer 1 (high 5 bits) */ + { "BPL1PTL", 0xdff0E2 }, /* Bit plane pointer 1 (low 15 bits) */ + { "BPL2PTH", 0xdff0E4 }, /* Bit plane pointer 2 (high 5 bits) */ + { "BPL2PTL", 0xdff0E6 }, /* Bit plane pointer 2 (low 15 bits) */ + { "BPL3PTH", 0xdff0E8 }, /* Bit plane pointer 3 (high 5 bits) */ + { "BPL3PTL", 0xdff0EA }, /* Bit plane pointer 3 (low 15 bits) */ + { "BPL4PTH", 0xdff0EC }, /* Bit plane pointer 4 (high 5 bits) */ + { "BPL4PTL", 0xdff0EE }, /* Bit plane pointer 4 (low 15 bits) */ + { "BPL5PTH", 0xdff0F0 }, /* Bit plane pointer 5 (high 5 bits) */ + { "BPL5PTL", 0xdff0F2 }, /* Bit plane pointer 5 (low 15 bits) */ + { "BPL6PTH", 0xdff0F4 }, /* Bit plane pointer 6 (high 5 bits) */ + { "BPL6PTL", 0xdff0F6 }, /* Bit plane pointer 6 (low 15 bits) */ + { "BPL7PTH", 0xdff0F8 }, /* Bit plane pointer 7 (high 5 bits) */ + { "BPL7PTL", 0xdff0FA }, /* Bit plane pointer 7 (low 15 bits) */ + { "BPL8PTH", 0xdff0FC }, /* Bit plane pointer 8 (high 5 bits) */ + { "BPL8PTL", 0xdff0FE }, /* Bit plane pointer 8 (low 15 bits) */ + { "BPLCON0", 0xdff100 }, /* Bit plane control reg (misc control bits) */ + { "BPLCON1", 0xdff102 }, /* Bit plane control reg (scroll val PF1,PF2) */ + { "BPLCON2", 0xdff104 }, /* Bit plane control reg (priority control) */ + { "BPLCON3", 0xdff106 }, /* Bit plane control reg (enhanced features) */ + { "BPL1MOD", 0xdff108 }, /* Bit plane modulo (odd planes,or active- fetch lines if bitplane scan-doubling is enabled */ + { "BPL2MOD", 0xdff10A }, /* Bit plane modulo (even planes or inactive- fetch lines if bitplane scan-doubling is enabled */ + { "BPLCON4", 0xdff10C }, /* Bit plane control reg (bitplane and sprite masks) */ + { "CLXCON2", 0xdff10e }, /* Extended collision control reg */ + { "BPL1DAT", 0xdff110 }, /* Bit plane 1 data (parallel to serial con- vert) */ + { "BPL2DAT", 0xdff112 }, /* Bit plane 2 data (parallel to serial con- vert) */ + { "BPL3DAT", 0xdff114 }, /* Bit plane 3 data (parallel to serial con- vert) */ + { "BPL4DAT", 0xdff116 }, /* Bit plane 4 data (parallel to serial con- vert) */ + { "BPL5DAT", 0xdff118 }, /* Bit plane 5 data (parallel to serial con- vert) */ + { "BPL6DAT", 0xdff11a }, /* Bit plane 6 data (parallel to serial con- vert) */ + { "BPL7DAT", 0xdff11c }, /* Bit plane 7 data (parallel to serial con- vert) */ + { "BPL8DAT", 0xdff11e }, /* Bit plane 8 data (parallel to serial con- vert) */ + { "SPR0PTH", 0xdff120 }, /* Sprite 0 pointer (high 5 bits) */ + { "SPR0PTL", 0xdff122 }, /* Sprite 0 pointer (low 15 bits) */ + { "SPR1PTH", 0xdff124 }, /* Sprite 1 pointer (high 5 bits) */ + { "SPR1PTL", 0xdff126 }, /* Sprite 1 pointer (low 15 bits) */ + { "SPR2PTH", 0xdff128 }, /* Sprite 2 pointer (high 5 bits) */ + { "SPR2PTL", 0xdff12A }, /* Sprite 2 pointer (low 15 bits) */ + { "SPR3PTH", 0xdff12C }, /* Sprite 3 pointer (high 5 bits) */ + { "SPR3PTL", 0xdff12E }, /* Sprite 3 pointer (low 15 bits) */ + { "SPR4PTH", 0xdff130 }, /* Sprite 4 pointer (high 5 bits) */ + { "SPR4PTL", 0xdff132 }, /* Sprite 4 pointer (low 15 bits) */ + { "SPR5PTH", 0xdff134 }, /* Sprite 5 pointer (high 5 bits) */ + { "SPR5PTL", 0xdff136 }, /* Sprite 5 pointer (low 15 bits) */ + { "SPR6PTH", 0xdff138 }, /* Sprite 6 pointer (high 5 bits) */ + { "SPR6PTL", 0xdff13A }, /* Sprite 6 pointer (low 15 bits) */ + { "SPR7PTH", 0xdff13C }, /* Sprite 7 pointer (high 5 bits) */ + { "SPR7PTL", 0xdff13E }, /* Sprite 7 pointer (low 15 bits) */ + { "SPR0POS", 0xdff140 }, /* Sprite 0 vert-horiz start pos data */ + { "SPR0CTL", 0xdff142 }, /* Sprite 0 position and control data */ + { "SPR0DATA", 0xdff144 }, /* Sprite 0 image data register A */ + { "SPR0DATB", 0xdff146 }, /* Sprite 0 image data register B */ + { "SPR1POS", 0xdff148 }, /* Sprite 1 vert-horiz start pos data */ + { "SPR1CTL", 0xdff14A }, /* Sprite 1 position and control data */ + { "SPR1DATA", 0xdff14C }, /* Sprite 1 image data register A */ + { "SPR1DATB", 0xdff14E }, /* Sprite 1 image data register B */ + { "SPR2POS", 0xdff150 }, /* Sprite 2 vert-horiz start pos data */ + { "SPR2CTL", 0xdff152 }, /* Sprite 2 position and control data */ + { "SPR2DATA", 0xdff154 }, /* Sprite 2 image data register A */ + { "SPR2DATB", 0xdff156 }, /* Sprite 2 image data register B */ + { "SPR3POS", 0xdff158 }, /* Sprite 3 vert-horiz start pos data */ + { "SPR3CTL", 0xdff15A }, /* Sprite 3 position and control data */ + { "SPR3DATA", 0xdff15C }, /* Sprite 3 image data register A */ + { "SPR3DATB", 0xdff15E }, /* Sprite 3 image data register B */ + { "SPR4POS", 0xdff160 }, /* Sprite 4 vert-horiz start pos data */ + { "SPR4CTL", 0xdff162 }, /* Sprite 4 position and control data */ + { "SPR4DATA", 0xdff164 }, /* Sprite 4 image data register A */ + { "SPR4DATB", 0xdff166 }, /* Sprite 4 image data register B */ + { "SPR5POS", 0xdff168 }, /* Sprite 5 vert-horiz start pos data */ + { "SPR5CTL", 0xdff16A }, /* Sprite 5 position and control data */ + { "SPR5DATA", 0xdff16C }, /* Sprite 5 image data register A */ + { "SPR5DATB", 0xdff16E }, /* Sprite 5 image data register B */ + { "SPR6POS", 0xdff170 }, /* Sprite 6 vert-horiz start pos data */ + { "SPR6CTL", 0xdff172 }, /* Sprite 6 position and control data */ + { "SPR6DATA", 0xdff174 }, /* Sprite 6 image data register A */ + { "SPR6DATB", 0xdff176 }, /* Sprite 6 image data register B */ + { "SPR7POS", 0xdff178 }, /* Sprite 7 vert-horiz start pos data */ + { "SPR7CTL", 0xdff17A }, /* Sprite 7 position and control data */ + { "SPR7DATA", 0xdff17C }, /* Sprite 7 image data register A */ + { "SPR7DATB", 0xdff17E }, /* Sprite 7 image data register B */ + { "COLOR00", 0xdff180 }, /* Color table 00 */ + { "COLOR01", 0xdff182 }, /* Color table 01 */ + { "COLOR02", 0xdff184 }, /* Color table 02 */ + { "COLOR03", 0xdff186 }, /* Color table 03 */ + { "COLOR04", 0xdff188 }, /* Color table 04 */ + { "COLOR05", 0xdff18A }, /* Color table 05 */ + { "COLOR06", 0xdff18C }, /* Color table 06 */ + { "COLOR07", 0xdff18E }, /* Color table 07 */ + { "COLOR08", 0xdff190 }, /* Color table 08 */ + { "COLOR09", 0xdff192 }, /* Color table 09 */ + { "COLOR10", 0xdff194 }, /* Color table 10 */ + { "COLOR11", 0xdff196 }, /* Color table 11 */ + { "COLOR12", 0xdff198 }, /* Color table 12 */ + { "COLOR13", 0xdff19A }, /* Color table 13 */ + { "COLOR14", 0xdff19C }, /* Color table 14 */ + { "COLOR15", 0xdff19E }, /* Color table 15 */ + { "COLOR16", 0xdff1A0 }, /* Color table 16 */ + { "COLOR17", 0xdff1A2 }, /* Color table 17 */ + { "COLOR18", 0xdff1A4 }, /* Color table 18 */ + { "COLOR19", 0xdff1A6 }, /* Color table 19 */ + { "COLOR20", 0xdff1A8 }, /* Color table 20 */ + { "COLOR21", 0xdff1AA }, /* Color table 21 */ + { "COLOR22", 0xdff1AC }, /* Color table 22 */ + { "COLOR23", 0xdff1AE }, /* Color table 23 */ + { "COLOR24", 0xdff1B0 }, /* Color table 24 */ + { "COLOR25", 0xdff1B2 }, /* Color table 25 */ + { "COLOR26", 0xdff1B4 }, /* Color table 26 */ + { "COLOR27", 0xdff1B6 }, /* Color table 27 */ + { "COLOR28", 0xdff1B8 }, /* Color table 28 */ + { "COLOR29", 0xdff1BA }, /* Color table 29 */ + { "COLOR30", 0xdff1BC }, /* Color table 30 */ + { "COLOR31", 0xdff1BE }, /* Color table 31 */ + { "HTOTAL", 0xdff1C0 }, /* Highest number count in horiz line (VARBEAMEN = 1) */ + { "HSSTOP", 0xdff1C2 }, /* Horiz line pos for HSYNC stop */ + { "HBSTRT", 0xdff1C4 }, /* Horiz line pos for HBLANK start */ + { "HBSTOP", 0xdff1C6 }, /* Horiz line pos for HBLANK stop */ + { "VTOTAL", 0xdff1C8 }, /* Highest numbered vertical line (VARBEAMEN = 1) */ + { "VSSTOP", 0xdff1CA }, /* Vert line for VBLANK start */ + { "VBSTRT", 0xdff1CC }, /* Vert line for VBLANK start */ + { "VBSTOP", 0xdff1CE }, /* Vert line for VBLANK stop */ +#if 0 + { "SPRHSTRT", 0xdff1D0 }, /* UHRES sprite vertical start */ + { "SPRHSTOP", 0xdff1D2 }, /* UHRES sprite vertical stop */ + { "BPLHSTRT", 0xdff1D4 }, /* UHRES bit plane vertical stop */ + { "BPLHSTOP", 0xdff1D6 }, /* UHRES bit plane vertical stop */ + { "HHPOSW", 0xdff1D8 }, /* DUAL mode hires H beam counter write */ + { "HHPOSR", 0xdff1DA }, /* DUAL mode hires H beam counter read */ +#endif + { "BEAMCON0", 0xdff1DC }, /* Beam counter control register (SHRES,UHRES,PAL) */ + { "HSSTRT", 0xdff1DE }, /* Horizontal sync start (VARHSY) */ + { "VSSTRT", 0xdff1E0 }, /* Vertical sync start (VARVSY) */ + { "HCENTER", 0xdff1E2 }, /* Horizontal pos for vsync on interlace */ + { "DIWHIGH", 0xdff1E4 }, /* Display window upper bits for start/stop */ +#if 0 + { "BPLHMOD", 0xdff1E6 }, /* UHRES bit plane modulo */ + { "SPRHPTH", 0xdff1E8 }, /* UHRES sprite pointer (high 5 bits) */ + { "SPRHPTL", 0xdff1EA }, /* UHRES sprite pointer (low 15 bits) */ + { "BPLHPTH", 0xdff1EC }, /* VRam (UHRES) bitplane pointer (hi 5 bits) */ + { "BPLHPTL", 0xdff1EE }, /* VRam (UHRES) bitplane pointer (lo 15 bits) */ + { "RESERVED", 0xdff1F0 }, /* Reserved (forever i guess!) */ + { "RESERVED", 0xdff1F2 }, /* Reserved (forever i guess!) */ + { "RESERVED", 0xdff1F4 }, /* Reserved (forever i guess!) */ + { "RESERVED", 0xdff1F6 }, /* Reserved (forever i guess!) */ + { "RESERVED", 0xdff1F8 }, /* Reserved (forever i guess!) */ + { "RESERVED", 0xdff1Fa }, /* Reserved (forever i guess!) */ +#endif + { "FMODE", 0xdff1FC }, /* Fetch mode register */ +#if 0 + { "NO-OP(NULL)", 0xdff1FE }, /* Can also indicate last 2 or 3 refresh + cycles or the restart of the COPPER after lockup.*/ +#endif +}; + diff --git a/include/akiko.h b/include/akiko.h new file mode 100755 index 00000000..8be20657 --- /dev/null +++ b/include/akiko.h @@ -0,0 +1,13 @@ + + +#define AKIKO_BASE 0xb80000 +#define AKIKO_BASE_END 0xb80100 /* ?? */ + +extern void akiko_reset (void); +extern int akiko_init (void); +extern void akiko_free (void); +extern int cd32_enabled; + +extern void akiko_entergui (void); +extern void akiko_exitgui (void); +extern void AKIKO_hsync_handler (void); diff --git a/include/ar.h b/include/ar.h new file mode 100755 index 00000000..03f36921 --- /dev/null +++ b/include/ar.h @@ -0,0 +1,69 @@ + +/* disable HRTMon support by commenting this out */ +#define ACTION_REPLAY_HRTMON + +#ifdef ACTION_REPLAY +#define ACTION_REPLAY_COMMON +#endif + +#ifdef ACTION_REPLAY_HRTMON +#define ACTION_REPLAY_COMMON +#endif + +#ifdef ACTION_REPLAY +/* disable Action Replay ROM/RAM hide by commenting this out */ +/* Better not disable this unless you do plenty of testing first. -Mark */ +#define ACTION_REPLAY_HIDE_CARTRIDGE +#endif + +#define ACTION_REPLAY_WAIT_PC -3 /* Wait for a specified Program counter */ +#define ACTION_REPLAY_INACTIVE -2 +#define ACTION_REPLAY_WAITRESET -1 +#define ACTION_REPLAY_IDLE 1 +#define ACTION_REPLAY_ACTIVATE 2 +#define ACTION_REPLAY_ACTIVE 3 +#define ACTION_REPLAY_DORESET 4 +#define ACTION_REPLAY_HIDE 5 + +extern int action_replay_freeze (void); + +extern uaecptr wait_for_pc; +extern int action_replay_flag; +extern int armodel; + +extern int is_ar_pc_in_rom(void); +extern int is_ar_pc_in_ram(void); +extern void action_replay_enter (void); +extern void action_replay_ciaread (void); +extern void action_replay_hide (void); +extern void action_replay_reset (void); +extern int action_replay_load (void); + +extern void action_replay_memory_reset(void); +extern void action_replay_init (int); +extern void action_replay_cleanup (void); +extern void action_replay_chipwrite(void); +extern void action_replay_map_banks(void); +extern void REGPARAM2 chipmem_lput_actionreplay23 (uaecptr addr, uae_u32 l) REGPARAM; +extern void REGPARAM2 chipmem_wput_actionreplay23 (uaecptr addr, uae_u32 w) REGPARAM; +extern void REGPARAM2 chipmem_bput_actionreplay1 (uaecptr addr, uae_u32 b) REGPARAM; +extern void REGPARAM2 chipmem_wput_actionreplay1 (uaecptr addr, uae_u32 w) REGPARAM; +extern void REGPARAM2 chipmem_lput_actionreplay1 (uaecptr addr, uae_u32 l) REGPARAM; + +extern void action_replay_version(void); + + +extern int hrtmon_flag; + +extern void hrtmon_enter (void); +extern void hrtmon_breakenter (void); +extern void hrtmon_ciaread (void); +extern void hrtmon_hide (void); +extern void hrtmon_reset (void); +extern int hrtmon_load (int); +extern void hrtmon_map_banks(void); + +/*extern uae_u8 *hrtmemory;*/ +extern uae_u32 hrtmem_start, hrtmem_size; + +extern uae_u8 ar_custom[2*256]; diff --git a/include/audio.h b/include/audio.h new file mode 100755 index 00000000..5ae517d3 --- /dev/null +++ b/include/audio.h @@ -0,0 +1,32 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Sound emulation stuff + * + * Copyright 1995, 1996, 1997 Bernd Schmidt + */ + +#define PERIOD_MAX ULONG_MAX + +extern void aud0_handler (void); +extern void aud1_handler (void); +extern void aud2_handler (void); +extern void aud3_handler (void); + +extern void AUDxDAT (int nr, uae_u16 value); +extern void AUDxVOL (int nr, uae_u16 value); +extern void AUDxPER (int nr, uae_u16 value); +extern void AUDxLCH (int nr, uae_u16 value); +extern void AUDxLCL (int nr, uae_u16 value); +extern void AUDxLEN (int nr, uae_u16 value); + +extern int init_audio (void); +extern void ahi_install (void); +extern void audio_reset (void); +extern void update_audio (void); +extern void schedule_audio (void); +extern void audio_evhandler (void); +extern void audio_hsync (int); +extern void update_adkmasks (void); +extern void update_sound (int freq); + diff --git a/include/autoconf.h b/include/autoconf.h new file mode 100755 index 00000000..4c3040c4 --- /dev/null +++ b/include/autoconf.h @@ -0,0 +1,93 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Autoconfig device support + * + * (c) 1996 Ed Hanway + */ + +typedef uae_u32 (*TrapFunction) (void); + +extern int lasttrap; +extern uae_u8 *rtarea; +extern void do_emultrap (int nr); + +extern uae_u32 addr (int); +extern void db (uae_u8); +extern void dw (uae_u16); +extern void dl (uae_u32); +extern uae_u32 ds (char *); +extern void calltrap (uae_u32); +extern void org (uae_u32); +extern uae_u32 here (void); +extern int deftrap2 (TrapFunction func, int mode, const char *str); +extern int deftrap (TrapFunction); +extern void align (int); +extern uae_u32 CallLib (uaecptr base, uae_s16 offset); +extern void call_calltrap (int nr) REGPARAM; + +extern volatile int uae_int_requested; +extern void set_uae_int_flag (void); + +#define RTS 0x4e75 +#define RTE 0x4e73 + +extern uaecptr EXPANSION_explibname, EXPANSION_doslibname, EXPANSION_uaeversion; +extern uaecptr EXPANSION_explibbase, EXPANSION_uaedevname, EXPANSION_haveV36; +extern uaecptr EXPANSION_bootcode, EXPANSION_nullfunc; + +extern uaecptr ROM_filesys_resname, ROM_filesys_resid; +extern uaecptr ROM_filesys_diagentry; +extern uaecptr ROM_hardfile_resname, ROM_hardfile_resid; +extern uaecptr ROM_hardfile_init; +extern uaecptr filesys_initcode; + +extern int nr_units (struct uaedev_mount_info *mountinfo); +extern int is_hardfile (struct uaedev_mount_info *mountinfo, int unit_no); +extern char *set_filesys_unit (struct uaedev_mount_info *mountinfo, int, + char *devname, char *volname, char *rootdir, int readonly, + int secs, int surfaces, int reserved, + int blocksize, int bootpri, char *filesysdir); +extern char *add_filesys_unit (struct uaedev_mount_info *mountinfo, + char *devname, char *volname, char *rootdir, int readonly, + int secs, int surfaces, int reserved, + int blocksize, int bootpri, char *filesysdir); +extern char *get_filesys_unit (struct uaedev_mount_info *mountinfo, int nr, + char **devname, char **volame, char **rootdir, int *readonly, + int *secspertrack, int *surfaces, int *reserved, + int *cylinders, uae_u64 *size, int *blocksize, int *bootpri, char **filesysdir); +extern int kill_filesys_unit (struct uaedev_mount_info *mountinfo, int); +extern int move_filesys_unit (struct uaedev_mount_info *mountinfo, int nr, int to); +extern int sprintf_filesys_unit (struct uaedev_mount_info *mountinfo, char *buffer, int num); +extern void write_filesys_config (struct uaedev_mount_info *mountinfo, const char *unexpanded, + const char *defaultpath, FILE *f); + +extern struct uaedev_mount_info *alloc_mountinfo (void); +extern struct uaedev_mount_info *dup_mountinfo (struct uaedev_mount_info *); +extern void free_mountinfo (struct uaedev_mount_info *); + +extern void filesys_reset (void); +extern void filesys_prepare_reset (void); +extern void filesys_start_threads (void); +extern void filesys_flush_cache (void); + +extern void filesys_install (void); +extern void filesys_install_code (void); +extern void filesys_store_devinfo (uae_u8 *); +extern void hardfile_install (void); +extern void hardfile_reset (void); +extern void emulib_install (void); +extern void expansion_init (void); +extern void expansion_cleanup (void); + +extern uae_u8* rtarea; + +#define TRAPFLAG_NO_REGSAVE 1 +#define TRAPFLAG_NO_RETVAL 2 +#define TRAPFLAG_EXTRA_STACK 4 +#define TRAPFLAG_DORET 8 + +extern uaecptr libemu_InstallFunction (TrapFunction, uaecptr, int, const char *); +extern uaecptr libemu_InstallFunctionFlags (TrapFunction, uaecptr, int, int, const char *); + +#define RTAREA_BASE 0xF00000 diff --git a/include/blitter.h b/include/blitter.h new file mode 100755 index 00000000..bc7d5016 --- /dev/null +++ b/include/blitter.h @@ -0,0 +1,60 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Blitter emulation + * + * (c) 1995 Bernd Schmidt + */ + +#if 0 +struct bltinfo { + int blitzero; + int blitashift,blitbshift,blitdownashift,blitdownbshift; + uae_u32 bltadat, bltbdat, bltcdat,bltddat,bltahold,bltbhold,bltafwm,bltalwm; + int vblitsize,hblitsize; + int bltamod,bltbmod,bltcmod,bltdmod; +}; +#else +struct bltinfo { + int blitzero; + int blitashift,blitbshift,blitdownashift,blitdownbshift; + uae_u16 bltadat, bltbdat, bltcdat,bltddat,bltahold,bltbhold,bltafwm,bltalwm; + int vblitsize,hblitsize; + int bltamod,bltbmod,bltcmod,bltdmod; +}; +#endif +extern enum blitter_states { + BLT_done, BLT_init, BLT_read, BLT_work, BLT_write, BLT_next +} bltstate; + +extern struct bltinfo blt_info; + +extern uae_u16 bltsize; +extern uae_u16 bltcon0,bltcon1; +extern int blinea_shift; +extern uae_u32 bltapt,bltbpt,bltcpt,bltdpt; +extern int blit_singlechannel; + +extern void maybe_blit (int, int); +extern void reset_blit (int); +extern int blitnasty (void); +extern int blitnnasty (int); +extern void blitter_handler (void); +extern void build_blitfilltable (void); +extern void do_blitter (int); +extern void decide_blitter (int hpos); +extern void blitter_done_notify (void); +extern void blitter_slowdown (int, int, int, int); + +typedef void blitter_func(uaecptr, uaecptr, uaecptr, uaecptr, struct bltinfo *); + +#define BLITTER_MAX_WORDS 2048 + +extern blitter_func *blitfunc_dofast[256]; +extern blitter_func *blitfunc_dofast_desc[256]; +extern uae_u32 blit_masktable[BLITTER_MAX_WORDS]; + +#define BLIT_MODE_IMMEDIATE -1 +#define BLIT_MODE_APPROXIMATE 0 +#define BLIT_MODE_COMPATIBLE 1 +#define BLIT_MODE_EXACT 2 diff --git a/include/blkdev.h b/include/blkdev.h new file mode 100755 index 00000000..51d613d2 --- /dev/null +++ b/include/blkdev.h @@ -0,0 +1,105 @@ + +#define MAX_TOTAL_DEVICES 8 +#define DEVICE_SCSI_BUFSIZE 4096 + +//#define device_debug write_log +#define device_debug + +#define INQ_DASD 0x00 /* Direct-access device (disk) */ +#define INQ_SEQD 0x01 /* Sequential-access device (tape) */ +#define INQ_PRTD 0x02 /* Printer device */ +#define INQ_PROCD 0x03 /* Processor device */ +#define INQ_OPTD 0x04 /* Write once device (optical disk) */ +#define INQ_WORM 0x04 /* Write once device (optical disk) */ +#define INQ_ROMD 0x05 /* CD-ROM device */ +#define INQ_SCAN 0x06 /* Scanner device */ +#define INQ_OMEM 0x07 /* Optical Memory device */ +#define INQ_JUKE 0x08 /* Medium Changer device (jukebox) */ +#define INQ_COMM 0x09 /* Communications device */ +#define INQ_IT8_1 0x0A /* IT8 */ +#define INQ_IT8_2 0x0B /* IT8 */ +#define INQ_STARR 0x0C /* Storage array device */ +#define INQ_ENCL 0x0D /* Enclosure services device */ +#define INQ_NODEV 0x1F /* Unknown or no device */ +#define INQ_NOTPR 0x1F /* Logical unit not present (SCSI-1) */ + +#define DEVICE_TYPE_ANY 1 +#define DEVICE_TYPE_SCSI 2 + +#define DF_SCSI 0 +#define DF_IOCTL 1 + +struct device_info { + int type; + int media_inserted; + int write_protected; + int cylinders; + int trackspercylinder; + int sectorspertrack; + int bytespersector; + int bus, target, lun; + int id; + char label[60]; +}; + +typedef int (*open_bus_func)(int flags); +typedef void (*close_bus_func)(void); +typedef int (*open_device_func)(int); +typedef void (*close_device_func)(int); +typedef struct device_info* (*info_device_func)(int, struct device_info*); +typedef uae_u8* (*execscsicmd_out_func)(int, uae_u8*, int); +typedef uae_u8* (*execscsicmd_in_func)(int, uae_u8*, int, int*); +typedef int (*execscsicmd_direct_func)(int, uaecptr); + +typedef int (*pause_func)(int, int); +typedef int (*stop_func)(int); +typedef int (*play_func)(int, uae_u32, uae_u32, int); +typedef uae_u8* (*qcode_func)(int); +typedef uae_u8* (*toc_func)(int); +typedef uae_u8* (*read_func)(int, int); +typedef int (*write_func)(int, int, uae_u8*); +typedef int (*isatapi_func)(int); + +struct device_functions { + open_bus_func openbus; + close_bus_func closebus; + open_device_func opendev; + close_device_func closedev; + info_device_func info; + execscsicmd_out_func exec_out; + execscsicmd_in_func exec_in; + execscsicmd_direct_func exec_direct; + + pause_func pause; + stop_func stop; + play_func play; + qcode_func qcode; + toc_func toc; + read_func read; + write_func write; + + isatapi_func isatapi; + + +}; + +extern struct device_functions *device_func[2]; + +extern int device_func_init(int flags); +extern int sys_command_open (int mode, int unitnum); +extern void sys_command_close (int mode, int unitnum); +extern struct device_info *sys_command_info (int mode, int unitnum, struct device_info *di); +extern void sys_command_pause (int mode, int unitnum, int paused); +extern void sys_command_stop (int mode, int unitnum); +extern int sys_command_play (int mode, int unitnum, uae_u32 startmsf, uae_u32 endmsf, int); +extern uae_u8 *sys_command_qcode (int mode, int unitnum); +extern uae_u8 *sys_command_toc (int mode, int unitnum); +extern uae_u8 *sys_command_read (int mode, int unitnum, int offset); +extern int sys_command_write (int mode, int unitnum, int offset, uae_u8 *data); +extern int sys_command_scsi_direct (int unitnum, uaecptr request); + +void scsi_atapi_fixup_pre (uae_u8 *scsi_cmd, int *len, uae_u8 **data, int *datalen, int *parm); +void scsi_atapi_fixup_post (uae_u8 *scsi_cmd, int len, uae_u8 *olddata, uae_u8 *data, int *datalen, int parm); + +void scsi_log_before (uae_u8 *cdb, int cdblen, uae_u8 *data, int datalen); +void scsi_log_after (uae_u8 *data, int datalen, uae_u8 *sense, int senselen); diff --git a/include/bsdsocket.h b/include/bsdsocket.h new file mode 100755 index 00000000..cacdcb03 --- /dev/null +++ b/include/bsdsocket.h @@ -0,0 +1,178 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * bsdsocket.library emulation + * + * Copyright 1997,98 Mathias Ortmann + * + */ + +//#define TRACING_ENABLED + +#ifdef TRACING_ENABLED +#define TRACE(x) do { write_log x; } while(0) +#else +#define TRACE(x) +#endif + +extern int init_socket_layer (void); +extern void deinit_socket_layer (void); + +/* inital size of per-process descriptor table (currently fixed) */ +#define DEFAULT_DTABLE_SIZE 64 + +#define SCRATCHBUFSIZE 128 + +#define MAXPENDINGASYNC 512 + +#define MAXADDRLEN 256 + +/* allocated and maintained on a per-task basis */ +struct socketbase { + struct socketbase *next; + struct socketbase *nextsig; /* queue for tasks to signal */ + + int dosignal; /* signal flag */ + uae_u32 ownertask; /* task that opened the library */ + int signal; /* signal allocated for that task */ + int sb_errno, sb_herrno; /* errno and herrno variables */ + uae_u32 errnoptr, herrnoptr; /* pointers */ + uae_u32 errnosize, herrnosize; /* pinter sizes */ + int dtablesize; /* current descriptor/flag etc. table size */ + int *dtable; /* socket descriptor table */ + int *ftable; /* socket flags */ + int resultval; + uae_u32 hostent; /* pointer to the current hostent structure (Amiga mem) */ + uae_u32 hostentsize; + uae_u32 protoent; /* pointer to the current protoent structure (Amiga mem) */ + uae_u32 protoentsize; + uae_u32 servent; /* pointer to the current servent structure (Amiga mem) */ + uae_u32 serventsize; + uae_u32 sigstosend; + uae_u32 eventsigs; /* EVENT sigmask */ + uae_u32 eintrsigs; /* EINTR sigmask */ + int eintr; /* interrupted by eintrsigs? */ + int eventindex; /* current socket looked at by GetSocketEvents() to prevent starvation */ + + /* host-specific fields below */ +#ifdef _WIN32 + unsigned int sockAbort; /* for aborting WinSock2 select() (damn Microsoft) */ + unsigned int sockAsync; /* for aborting WSBAsyncSelect() in window message handler */ + int needAbort; /* abort flag */ + void *hAsyncTask; /* async task handle */ + void *hEvent; /* thread event handle */ + unsigned int *mtable; /* window messages allocated for asynchronous event notification */ +#endif +} *socketbases; + + +#define LIBRARY_SIZEOF 36 + +struct UAEBSDBase { + char dummy[LIBRARY_SIZEOF]; + struct socketbase *sb; + char scratchbuf[SCRATCHBUFSIZE]; +}; + +/* socket flags */ +/* socket events to report */ +#define REP_ACCEPT 0x01 /* there is a connection to accept() */ +#define REP_CONNECT 0x02 /* connect() completed */ +#define REP_OOB 0x04 /* socket has out-of-band data */ +#define REP_READ 0x08 /* socket is readable */ +#define REP_WRITE 0x10 /* socket is writeable */ +#define REP_ERROR 0x20 /* asynchronous error on socket */ +#define REP_CLOSE 0x40 /* connection closed (graceful or not) */ +#define REP_ALL 0x7f +/* socket events that occurred */ +#define SET_ACCEPT 0x0100 /* there is a connection to accept() */ +#define SET_CONNECT 0x0200 /* connect() completed */ +#define SET_OOB 0x0400 /* socket has out-of-band data */ +#define SET_READ 0x0800 /* socket is readable */ +#define SET_WRITE 0x1000 /* socket is writeable */ +#define SET_ERROR 0x2000 /* asynchronous error on socket */ +#define SET_CLOSE 0x4000 /* connection closed (graceful or not) */ +#define SET_ALL 0x7f00 +/* socket properties */ +#define SF_BLOCKING 0x80000000 +#define SF_BLOCKINGINPROGRESS 0x40000000 + +struct socketbase *get_socketbase (void); + +extern uae_u32 addstr (uae_u32 *, char *); +extern uae_u32 addmem (uae_u32 *, char *, int len); + +extern char *strncpyah (char *, uae_u32, int); +extern char *strcpyah (char *, uae_u32); +extern uae_u32 strcpyha (uae_u32, char *); +extern uae_u32 strncpyha (uae_u32, char *, int); + +#define SB struct socketbase *sb + +extern void seterrno (SB, int); +extern void setherrno (SB, int); + +extern void sockmsg (unsigned int, unsigned long, unsigned long); +extern void sockabort (SB); + +extern void addtosigqueue (SB, int); +extern void removefromsigqueue (SB); +extern void sigsockettasks (void); +extern void locksigqueue (void); +extern void unlocksigqueue (void); + +extern BOOL checksd(SB, int sd); +extern void setsd(SB, int ,int ); +extern int getsd (SB, int); +extern int getsock (SB, int); +extern void releasesock (SB, int); + +extern void waitsig (SB); +extern void cancelsig (SB); + +extern int host_sbinit (SB); +extern void host_sbcleanup (SB); +extern void host_sbreset (void); +extern void host_closesocketquick (int); + +extern int host_dup2socket (SB, int, int); +extern int host_socket (SB, int, int, int); +extern uae_u32 host_bind (SB, uae_u32, uae_u32, uae_u32); +extern uae_u32 host_listen (SB, uae_u32, uae_u32); +extern void host_accept (SB, uae_u32, uae_u32, uae_u32); +extern void host_sendto (SB, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32); +extern void host_recvfrom (SB, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32); +extern uae_u32 host_shutdown (SB, uae_u32, uae_u32); +extern void host_setsockopt (SB, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32); +extern uae_u32 host_getsockopt (SB, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32); +extern uae_u32 host_getsockname (SB, uae_u32, uae_u32, uae_u32); +extern uae_u32 host_getpeername (SB, uae_u32, uae_u32, uae_u32); +extern uae_u32 host_IoctlSocket (SB, uae_u32, uae_u32, uae_u32); +extern uae_u32 host_shutdown (SB, uae_u32, uae_u32); +extern int host_CloseSocket (SB, int); +extern void host_connect (SB, uae_u32, uae_u32, uae_u32); +extern void host_WaitSelect (SB, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32); +extern uae_u32 host_SetSocketSignals (void); +extern uae_u32 host_getdtablesize (void); +extern uae_u32 host_ObtainSocket (void); +extern uae_u32 host_ReleaseSocket (void); +extern uae_u32 host_ReleaseCopyOfSocket (void); +extern uae_u32 host_Inet_NtoA (SB, uae_u32); +extern uae_u32 host_inet_addr (uae_u32); +extern uae_u32 host_Inet_LnaOf (void); +extern uae_u32 host_Inet_NetOf (void); +extern uae_u32 host_Inet_MakeAddr (void); +extern uae_u32 host_inet_network (void); +extern void host_gethostbynameaddr (SB, uae_u32, uae_u32, long); +extern uae_u32 host_getnetbyname (void); +extern uae_u32 host_getnetbyaddr (void); +extern void host_getservbynameport (SB, uae_u32, uae_u32, uae_u32); +extern void host_getprotobyname (SB, uae_u32); +extern uae_u32 host_getprotobynumber (void); +extern uae_u32 host_vsyslog (void); +extern uae_u32 host_Dup2Socket (void); +extern uae_u32 host_gethostname (uae_u32, uae_u32); + + +extern void bsdlib_install (void); +extern void bsdlib_reset (void); diff --git a/include/catweasel.h b/include/catweasel.h new file mode 100755 index 00000000..848221ef --- /dev/null +++ b/include/catweasel.h @@ -0,0 +1,85 @@ + +#ifdef CATWEASEL + +extern struct catweasel_contr cwc; +extern int catweasel_read_keyboard (uae_u8 *keycode); +extern int catweasel_init (void); +extern void catweasel_free (void); +extern uae_u32 catweasel_do_bget (uaecptr addr); +extern void catweasel_do_bput (uaecptr addr, uae_u32 b); +extern int catweasel_read_joystick (uae_u8 *dir, uae_u8 *buttons); +extern void catweasel_hsync (void); + +typedef struct catweasel_drive { + struct catweasel_contr *contr; /* The controller this drive belongs to */ + int number; /* Drive number: 0 or 1 */ + int type; /* 0 = not present, 1 = 3.5" */ + int track; /* current r/w head position (0..79) */ + int diskindrive; /* 0 = no disk, 1 = disk in drive */ + int wprot; /* 0 = not, 1 = write protected */ + unsigned char sel; + unsigned char mot; +} catweasel_drive; + +typedef struct catweasel_contr { + int type; /* see CATWEASEL_TYPE_* defines below */ + int iobase; /* 0 = not present (factory default is 0x320) */ + void (*msdelay)(int ms); /* microseconds delay routine, provided by host program */ + catweasel_drive drives[2]; /* at most two drives on each controller */ + int control_register; /* contents of control register */ + unsigned char crm_sel0; /* bit masks for the control / status register */ + unsigned char crm_sel1; + unsigned char crm_mot0; + unsigned char crm_mot1; + unsigned char crm_dir; + unsigned char crm_step; + unsigned char srm_trk0; + unsigned char srm_dchg; + unsigned char srm_writ; + unsigned char srm_dskready; + int io_sr; /* IO port of control / status register */ + int io_mem; /* IO port of memory register */ +} catweasel_contr; + +#define CATWEASEL_TYPE_NONE -1 +#define CATWEASEL_TYPE_MK1 1 +#define CATWEASEL_TYPE_MK3 3 + +/* Initialize a Catweasel controller; c->iobase and c->msdelay must have + been initialized -- msdelay might be used */ +void catweasel_init_controller(catweasel_contr *c); + +/* Reset the controller */ +void catweasel_free_controller(catweasel_contr *c); + +/* Set current drive select mask */ +void catweasel_select(catweasel_contr *c, int dr0, int dr1); + +/* Start/stop the drive's motor */ +void catweasel_set_motor(catweasel_drive *d, int on); + +/* Move the r/w head */ +int catweasel_step(catweasel_drive *d, int dir); + +/* Check for a disk change and update d->diskindrive + -- msdelay might be used. Returns 1 == disk has been changed */ +int catweasel_disk_changed(catweasel_drive *d); + +/* Check if disk in selected drive is write protected. */ +int catweasel_write_protected(catweasel_drive *d); + +/* Read data -- msdelay will be used */ +int catweasel_read(catweasel_drive *d, int side, int clock, int time); + +/* Write data -- msdelay will be used. If time == -1, the write will + be started at the index pulse and stopped at the next index pulse, + or earlier if the Catweasel RAM contains a 128 end byte. The + function returns after the write has finished. */ +int catweasel_write(catweasel_drive *d, int side, int clock, int time); + +int catweasel_fillmfm (catweasel_drive *d, uae_u16 *mfm, int side, int clock, int rawmode); + +int catweasel_diskready(catweasel_drive *d); +int catweasel_track0(catweasel_drive *d); + +#endif \ No newline at end of file diff --git a/include/cia.h b/include/cia.h new file mode 100755 index 00000000..dbf92371 --- /dev/null +++ b/include/cia.h @@ -0,0 +1,29 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * CIA chip support + * + * (c) 1995 Bernd Schmidt + */ + +extern void CIA_reset (void); +extern void CIA_vsync_handler (void); +extern void CIA_hsync_handler (void); +extern void CIA_handler (void); + +extern void diskindex_handler (void); + +extern void dumpcia (void); +extern void rethink_cias (void); +extern unsigned int ciaaicr,ciaaimask,ciabicr,ciabimask; +extern unsigned int ciaacra,ciaacrb,ciabcra,ciabcrb; +extern unsigned int ciabpra; +extern unsigned long ciaata,ciaatb,ciabta,ciabtb; +extern unsigned long ciaatod,ciabtod,ciaatol,ciabtol,ciaaalarm,ciabalarm; +extern int ciaatlatch,ciabtlatch; + +extern int parallel_direct_write_data (uae_u8, uae_u8); +extern int parallel_direct_read_data (uae_u8*); +extern int parallel_direct_write_status (uae_u8, uae_u8); +extern int parallel_direct_read_status (uae_u8*); + diff --git a/include/commpipe.h b/include/commpipe.h new file mode 100755 index 00000000..7c27d319 --- /dev/null +++ b/include/commpipe.h @@ -0,0 +1,157 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Communication between threads + * + * Copyright 1997, 2001 Bernd Schmidt + */ + +typedef union { + int i; + uae_u32 u32; + void *pv; +} uae_pt; + +/* These currently require the maximum size to be known at initialization + * time, but it wouldn't be hard to use a "normal" pipe as an extension once the + * user-level one gets full. + * We queue up to chunks pieces of data before signalling the other thread to + * avoid overhead. */ + +typedef struct { + uae_sem_t lock; + uae_sem_t reader_wait; + uae_sem_t writer_wait; + uae_pt *data; + int size, chunks; + volatile int rdp, wrp; + volatile int writer_waiting; + volatile int reader_waiting; +} smp_comm_pipe; + +static __inline__ void init_comm_pipe (smp_comm_pipe *p, int size, int chunks) +{ + memset (p, 0, sizeof (*p)); + p->data = (uae_pt *)malloc (size*sizeof (uae_pt)); + p->size = size; + p->chunks = chunks; + p->rdp = p->wrp = 0; + p->reader_waiting = 0; + p->writer_waiting = 0; + uae_sem_init (&p->lock, 0, 1); + uae_sem_init (&p->reader_wait, 0, 0); + uae_sem_init (&p->writer_wait, 0, 0); +} + +static __inline__ void destroy_comm_pipe (smp_comm_pipe *p) +{ + uae_sem_destroy (&p->lock); + uae_sem_destroy (&p->reader_wait); + uae_sem_destroy (&p->writer_wait); +} + +static __inline__ void maybe_wake_reader (smp_comm_pipe *p, int no_buffer) +{ + if (p->reader_waiting + && (no_buffer || ((p->wrp - p->rdp + p->size) % p->size) >= p->chunks)) + { + p->reader_waiting = 0; + uae_sem_post (&p->reader_wait); + } +} + +static __inline__ void write_comm_pipe_pt (smp_comm_pipe *p, uae_pt data, int no_buffer) +{ + int nxwrp = (p->wrp + 1) % p->size; + + if (p->reader_waiting) { + /* No need to do all the locking */ + p->data[p->wrp] = data; + p->wrp = nxwrp; + maybe_wake_reader (p, no_buffer); + return; + } + + uae_sem_wait (&p->lock); + if (nxwrp == p->rdp) { + /* Pipe full! */ + p->writer_waiting = 1; + uae_sem_post (&p->lock); + /* Note that the reader could get in between here and do a + * sem_post on writer_wait before we wait on it. That's harmless. + * There's a similar case in read_comm_pipe_int_blocking. */ + uae_sem_wait (&p->writer_wait); + uae_sem_wait (&p->lock); + } + p->data[p->wrp] = data; + p->wrp = nxwrp; + maybe_wake_reader (p, no_buffer); + uae_sem_post (&p->lock); +} + +static __inline__ uae_pt read_comm_pipe_pt_blocking (smp_comm_pipe *p) +{ + uae_pt data; + + uae_sem_wait (&p->lock); + if (p->rdp == p->wrp) { + p->reader_waiting = 1; + uae_sem_post (&p->lock); + uae_sem_wait (&p->reader_wait); + uae_sem_wait (&p->lock); + } + data = p->data[p->rdp]; + p->rdp = (p->rdp + 1) % p->size; + + /* We ignore chunks here. If this is a problem, make the size bigger in the init call. */ + if (p->writer_waiting) { + write_log ("read_comm_pipe_pt_blocking!\n"); + p->writer_waiting = 0; + uae_sem_post (&p->writer_wait); + } + uae_sem_post (&p->lock); + return data; +} + +static __inline__ int comm_pipe_has_data (smp_comm_pipe *p) +{ + return p->rdp != p->wrp; +} + +static __inline__ int read_comm_pipe_int_blocking (smp_comm_pipe *p) +{ + uae_pt foo = read_comm_pipe_pt_blocking (p); + return foo.i; +} +static __inline__ uae_u32 read_comm_pipe_u32_blocking (smp_comm_pipe *p) +{ + uae_pt foo = read_comm_pipe_pt_blocking (p); + return foo.u32; +} + +static __inline__ void *read_comm_pipe_pvoid_blocking (smp_comm_pipe *p) +{ + uae_pt foo = read_comm_pipe_pt_blocking (p); + return foo.pv; +} + +static __inline__ void write_comm_pipe_int (smp_comm_pipe *p, int data, int no_buffer) +{ + uae_pt foo; + foo.i = data; + write_comm_pipe_pt (p, foo, no_buffer); +} + +static __inline__ void write_comm_pipe_u32 (smp_comm_pipe *p, int data, int no_buffer) +{ + uae_pt foo; + foo.u32 = data; + write_comm_pipe_pt (p, foo, no_buffer); +} + +static __inline__ void write_comm_pipe_pvoid (smp_comm_pipe *p, void *data, int no_buffer) +{ + uae_pt foo; + foo.pv = data; + write_comm_pipe_pt (p, foo, no_buffer); +} diff --git a/include/compemu.h b/include/compemu.h new file mode 100755 index 00000000..a8b2a756 --- /dev/null +++ b/include/compemu.h @@ -0,0 +1,527 @@ +#define USE_OPTIMIZER 0 +#define USE_LOW_OPTIMIZER 0 +#define USE_ALIAS 1 +#define USE_F_ALIAS 1 +#define USE_SOFT_FLUSH 1 +#define USE_OFFSET 1 +#define COMP_DEBUG 1 + +#if COMP_DEBUG +#define Dif(x) if (x) +#else +#define Dif(x) if (0) +#endif + +#define SCALE 2 +#define MAXCYCLES (1000 * CYCLE_UNIT) +#define MAXREGOPT 65536 + +#define BYTES_PER_INST 10240 /* paranoid ;-) */ +#define LONGEST_68K_INST 16 /* The number of bytes the longest possible + 68k instruction takes */ +#define MAX_CHECKSUM_LEN 2048 /* The maximum size we calculate checksums + for. Anything larger will be flushed + unconditionally even with SOFT_FLUSH */ +#define MAX_HOLD_BI 3 /* One for the current block, and up to two + for jump targets */ + +#define INDIVIDUAL_INST 0 +#define FLAG_C 0x0010 +#define FLAG_V 0x0008 +#define FLAG_Z 0x0004 +#define FLAG_N 0x0002 +#define FLAG_X 0x0001 +#define FLAG_CZNV (FLAG_C | FLAG_Z | FLAG_N | FLAG_V) +#define FLAG_ZNV (FLAG_Z | FLAG_N | FLAG_V) + +#define KILLTHERAT 1 /* Set to 1 to avoid some partial_rat_stalls */ + +/* Whether to preserve registers across calls to JIT compiled routines */ +#if defined X86_ASSEMBLY +#define USE_PUSH_POP 0 +#else +#define USE_PUSH_POP 1 +#endif + +#define N_REGS 8 /* really only 7, but they are numbered 0,1,2,3,5,6,7 */ +#define N_FREGS 6 /* That leaves us two positions on the stack to play with */ + +/* Functions exposed to newcpu, or to what was moved from newcpu.c to + * compemu_support.c */ +extern void init_comp(void); +extern void flush(int save_regs); +extern void small_flush(int save_regs); +extern void set_target(uae_u8* t); +extern uae_u8* get_target(void); +extern void freescratch(void); +extern void build_comp(void); +extern void set_cache_state(int enabled); +extern int get_cache_state(void); +extern uae_u32 get_jitted_size(void); +#ifdef JIT +extern void flush_icache(int n); +#endif +extern void alloc_cache(void); +extern void compile_block(cpu_history* pc_hist, int blocklen, int totcyles); +extern void lopt_emit_all(void); +extern int check_for_cache_miss(void); + + +#define scaled_cycles(x) (currprefs.m68k_speed==-1?(((x)/SCALE)?(((x)/SCALE= REGALLOC */ +#define DECLARE(func) extern void func; extern void do_##func +#else +#define REGALLOC_O 2000000 +#define PEEPHOLE_O 2000000 +#define DECLARE(func) extern void func +#endif + + +/* What we expose to the outside */ +DECLARE(bt_l_ri(R4 r, IMM i)); +DECLARE(bt_l_rr(R4 r, R4 b)); +DECLARE(btc_l_ri(RW4 r, IMM i)); +DECLARE(btc_l_rr(RW4 r, R4 b)); +DECLARE(bts_l_ri(RW4 r, IMM i)); +DECLARE(bts_l_rr(RW4 r, R4 b)); +DECLARE(btr_l_ri(RW4 r, IMM i)); +DECLARE(btr_l_rr(RW4 r, R4 b)); +DECLARE(mov_l_rm(W4 d, IMM s)); +DECLARE(call_r(R4 r)); +DECLARE(sub_l_mi(IMM d, IMM s)); +DECLARE(mov_l_mi(IMM d, IMM s)); +DECLARE(mov_w_mi(IMM d, IMM s)); +DECLARE(mov_b_mi(IMM d, IMM s)); +DECLARE(rol_b_ri(RW1 r, IMM i)); +DECLARE(rol_w_ri(RW2 r, IMM i)); +DECLARE(rol_l_ri(RW4 r, IMM i)); +DECLARE(rol_l_rr(RW4 d, R1 r)); +DECLARE(rol_w_rr(RW2 d, R1 r)); +DECLARE(rol_b_rr(RW1 d, R1 r)); +DECLARE(shll_l_rr(RW4 d, R1 r)); +DECLARE(shll_w_rr(RW2 d, R1 r)); +DECLARE(shll_b_rr(RW1 d, R1 r)); +DECLARE(ror_b_ri(R1 r, IMM i)); +DECLARE(ror_w_ri(R2 r, IMM i)); +DECLARE(ror_l_ri(R4 r, IMM i)); +DECLARE(ror_l_rr(R4 d, R1 r)); +DECLARE(ror_w_rr(R2 d, R1 r)); +DECLARE(ror_b_rr(R1 d, R1 r)); +DECLARE(shrl_l_rr(RW4 d, R1 r)); +DECLARE(shrl_w_rr(RW2 d, R1 r)); +DECLARE(shrl_b_rr(RW1 d, R1 r)); +DECLARE(shra_l_rr(RW4 d, R1 r)); +DECLARE(shra_w_rr(RW2 d, R1 r)); +DECLARE(shra_b_rr(RW1 d, R1 r)); +DECLARE(shll_l_ri(RW4 r, IMM i)); +DECLARE(shll_w_ri(RW2 r, IMM i)); +DECLARE(shll_b_ri(RW1 r, IMM i)); +DECLARE(shrl_l_ri(RW4 r, IMM i)); +DECLARE(shrl_w_ri(RW2 r, IMM i)); +DECLARE(shrl_b_ri(RW1 r, IMM i)); +DECLARE(shra_l_ri(RW4 r, IMM i)); +DECLARE(shra_w_ri(RW2 r, IMM i)); +DECLARE(shra_b_ri(RW1 r, IMM i)); +DECLARE(setcc(W1 d, IMM cc)); +DECLARE(setcc_m(IMM d, IMM cc)); +DECLARE(cmov_l_rr(RW4 d, R4 s, IMM cc)); +DECLARE(cmov_l_rm(RW4 d, IMM s, IMM cc)); +DECLARE(bsf_l_rr(W4 d, R4 s)); +DECLARE(pop_m(IMM d)); +DECLARE(push_m(IMM d)); +DECLARE(pop_l(W4 d)); +DECLARE(push_l_i(IMM i)); +DECLARE(push_l(R4 s)); +DECLARE(clear_16(RW4 r)); +DECLARE(clear_8(RW4 r)); +DECLARE(sign_extend_16_rr(W4 d, R2 s)); +DECLARE(sign_extend_8_rr(W4 d, R1 s)); +DECLARE(zero_extend_16_rr(W4 d, R2 s)); +DECLARE(zero_extend_8_rr(W4 d, R1 s)); +DECLARE(imul_64_32(RW4 d, RW4 s)); +DECLARE(mul_64_32(RW4 d, RW4 s)); +DECLARE(imul_32_32(RW4 d, R4 s)); +DECLARE(mul_32_32(RW4 d, R4 s)); +DECLARE(mov_b_rr(W1 d, R1 s)); +DECLARE(mov_w_rr(W2 d, R2 s)); +DECLARE(mov_l_rrm_indexed(W4 d,R4 baser, R4 index, IMM factor)); +DECLARE(mov_w_rrm_indexed(W2 d, R4 baser, R4 index, IMM factor)); +DECLARE(mov_b_rrm_indexed(W1 d, R4 baser, R4 index, IMM factor)); +DECLARE(mov_l_mrr_indexed(R4 baser, R4 index, IMM factor, R4 s)); +DECLARE(mov_w_mrr_indexed(R4 baser, R4 index, IMM factor, R2 s)); +DECLARE(mov_b_mrr_indexed(R4 baser, R4 index, IMM factor, R1 s)); +DECLARE(mov_l_bmrr_indexed(IMM base, R4 baser, R4 index, IMM factor, R4 s)); +DECLARE(mov_w_bmrr_indexed(IMM base, R4 baser, R4 index, IMM factor, R2 s)); +DECLARE(mov_b_bmrr_indexed(IMM base, R4 baser, R4 index, IMM factor, R1 s)); +DECLARE(mov_l_brrm_indexed(W4 d, IMM base, R4 baser, R4 index, IMM factor)); +DECLARE(mov_w_brrm_indexed(W2 d, IMM base, R4 baser, R4 index, IMM factor)); +DECLARE(mov_b_brrm_indexed(W1 d, IMM base, R4 baser, R4 index, IMM factor)); +DECLARE(mov_l_rm_indexed(W4 d, IMM base, R4 index, IMM factor)); +DECLARE(mov_l_rR(W4 d, R4 s, IMM offset)); +DECLARE(mov_w_rR(W2 d, R4 s, IMM offset)); +DECLARE(mov_b_rR(W1 d, R4 s, IMM offset)); +DECLARE(mov_l_brR(W4 d, R4 s, IMM offset)); +DECLARE(mov_w_brR(W2 d, R4 s, IMM offset)); +DECLARE(mov_b_brR(W1 d, R4 s, IMM offset)); +DECLARE(mov_l_Ri(R4 d, IMM i, IMM offset)); +DECLARE(mov_w_Ri(R4 d, IMM i, IMM offset)); +DECLARE(mov_b_Ri(R4 d, IMM i, IMM offset)); +DECLARE(mov_l_Rr(R4 d, R4 s, IMM offset)); +DECLARE(mov_w_Rr(R4 d, R2 s, IMM offset)); +DECLARE(mov_b_Rr(R4 d, R1 s, IMM offset)); +DECLARE(lea_l_brr(W4 d, R4 s, IMM offset)); +DECLARE(lea_l_brr_indexed(W4 d, R4 s, R4 index, IMM factor, IMM offset)); +DECLARE(lea_l_rr_indexed(W4 d, R4 s, R4 index, IMM factor)); +DECLARE(mov_l_bRr(R4 d, R4 s, IMM offset)); +DECLARE(mov_w_bRr(R4 d, R2 s, IMM offset)); +DECLARE(mov_b_bRr(R4 d, R1 s, IMM offset)); +DECLARE(bswap_32(RW4 r)); +DECLARE(bswap_16(RW2 r)); +DECLARE(mov_l_rr(W4 d, R4 s)); +DECLARE(mov_l_mr(IMM d, R4 s)); +DECLARE(mov_w_mr(IMM d, R2 s)); +DECLARE(mov_w_rm(W2 d, IMM s)); +DECLARE(mov_b_mr(IMM d, R1 s)); +DECLARE(mov_b_rm(W1 d, IMM s)); +DECLARE(mov_l_ri(W4 d, IMM s)); +DECLARE(mov_w_ri(W2 d, IMM s)); +DECLARE(mov_b_ri(W1 d, IMM s)); +DECLARE(add_l_mi(IMM d, IMM s) ); +DECLARE(add_w_mi(IMM d, IMM s) ); +DECLARE(add_b_mi(IMM d, IMM s) ); +DECLARE(test_l_ri(R4 d, IMM i)); +DECLARE(test_l_rr(R4 d, R4 s)); +DECLARE(test_w_rr(R2 d, R2 s)); +DECLARE(test_b_rr(R1 d, R1 s)); +DECLARE(and_l_ri(RW4 d, IMM i)); +DECLARE(and_l(RW4 d, R4 s)); +DECLARE(and_w(RW2 d, R2 s)); +DECLARE(and_b(RW1 d, R1 s)); +DECLARE(or_l_ri(RW4 d, IMM i)); +DECLARE(or_l(RW4 d, R4 s)); +DECLARE(or_w(RW2 d, R2 s)); +DECLARE(or_b(RW1 d, R1 s)); +DECLARE(adc_l(RW4 d, R4 s)); +DECLARE(adc_w(RW2 d, R2 s)); +DECLARE(adc_b(RW1 d, R1 s)); +DECLARE(add_l(RW4 d, R4 s)); +DECLARE(add_w(RW2 d, R2 s)); +DECLARE(add_b(RW1 d, R1 s)); +DECLARE(sub_l_ri(RW4 d, IMM i)); +DECLARE(sub_w_ri(RW2 d, IMM i)); +DECLARE(sub_b_ri(RW1 d, IMM i)); +DECLARE(add_l_ri(RW4 d, IMM i)); +DECLARE(add_w_ri(RW2 d, IMM i)); +DECLARE(add_b_ri(RW1 d, IMM i)); +DECLARE(sbb_l(RW4 d, R4 s)); +DECLARE(sbb_w(RW2 d, R2 s)); +DECLARE(sbb_b(RW1 d, R1 s)); +DECLARE(sub_l(RW4 d, R4 s)); +DECLARE(sub_w(RW2 d, R2 s)); +DECLARE(sub_b(RW1 d, R1 s)); +DECLARE(cmp_l(R4 d, R4 s)); +DECLARE(cmp_l_ri(R4 r, IMM i)); +DECLARE(cmp_w(R2 d, R2 s)); +DECLARE(cmp_b(R1 d, R1 s)); +DECLARE(xor_l(RW4 d, R4 s)); +DECLARE(xor_w(RW2 d, R2 s)); +DECLARE(xor_b(RW1 d, R1 s)); +DECLARE(live_flags(void)); +DECLARE(dont_care_flags(void)); +DECLARE(duplicate_carry(void)); +DECLARE(restore_carry(void)); +DECLARE(start_needflags(void)); +DECLARE(end_needflags(void)); +DECLARE(make_flags_live(void)); +DECLARE(call_r_11(R4 r, W4 out1, R4 in1, IMM osize, IMM isize)); +DECLARE(call_r_02(R4 r, R4 in1, R4 in2, IMM isize1, IMM isize2)); +DECLARE(readmem_new(R4 address, W4 dest, IMM offset, IMM size, W4 tmp)); +DECLARE(writemem_new(R4 address, R4 source, IMM offset, IMM size, W4 tmp)); +DECLARE(forget_about(W4 r)); +DECLARE(nop(void)); + +DECLARE(f_forget_about(FW r)); +DECLARE(fmov_pi(FW r)); +DECLARE(fmov_log10_2(FW r)); +DECLARE(fmov_log2_e(FW r)); +DECLARE(fmov_loge_2(FW r)); +DECLARE(fmov_1(FW r)); +DECLARE(fmov_0(FW r)); +DECLARE(fmov_rm(FW r, MEMR m)); +DECLARE(fmovi_rm(FW r, MEMR m)); +DECLARE(fmovi_mr(MEMW m, FR r)); +DECLARE(fmovs_rm(FW r, MEMR m)); +DECLARE(fmovs_mr(MEMW m, FR r)); +DECLARE(fmov_mr(MEMW m, FR r)); +DECLARE(fmov_ext_mr(MEMW m, FR r)); +DECLARE(fmov_ext_rm(FW r, MEMR m)); +DECLARE(fmov_rr(FW d, FR s)); +DECLARE(fldcw_m_indexed(R4 index, IMM base)); +DECLARE(ftst_r(FR r)); +DECLARE(dont_care_fflags(void)); +DECLARE(fsqrt_rr(FW d, FR s)); +DECLARE(fabs_rr(FW d, FR s)); +DECLARE(frndint_rr(FW d, FR s)); +DECLARE(fsin_rr(FW d, FR s)); +DECLARE(fcos_rr(FW d, FR s)); +DECLARE(ftwotox_rr(FW d, FR s)); +DECLARE(fetox_rr(FW d, FR s)); +DECLARE(flog2_rr(FW d, FR s)); +DECLARE(fneg_rr(FW d, FR s)); +DECLARE(fadd_rr(FRW d, FR s)); +DECLARE(fsub_rr(FRW d, FR s)); +DECLARE(fmul_rr(FRW d, FR s)); +DECLARE(frem_rr(FRW d, FR s)); +DECLARE(frem1_rr(FRW d, FR s)); +DECLARE(fdiv_rr(FRW d, FR s)); +DECLARE(fcmp_rr(FR d, FR s)); +DECLARE(fflags_into_flags(W2 tmp)); + +extern int failure; +#define FAIL(x) do { failure|=x; } while (0) + +/* Convenience functions exposed to gencomp */ +extern uae_u32 m68k_pc_offset; +extern void readbyte(int address, int dest, int tmp); +extern void readword(int address, int dest, int tmp); +extern void readlong(int address, int dest, int tmp); +extern void writebyte(int address, int source, int tmp); +extern void writeword(int address, int source, int tmp); +extern void writelong(int address, int source, int tmp); +extern void writeword_clobber(int address, int source, int tmp); +extern void writelong_clobber(int address, int source, int tmp); +extern void get_n_addr(int address, int dest, int tmp); +extern void get_n_addr_jmp(int address, int dest, int tmp); +extern void calc_disp_ea_020(int base, uae_u32 dp, int target, int tmp); +extern int kill_rodent(int r); +extern void sync_m68k_pc(void); +extern uae_u32 get_const(int r); +extern int is_const(int r); +extern void register_branch(uae_u32 not_taken, uae_u32 taken, uae_u8 cond); +extern void empty_optimizer(void); + +#define comp_get_ibyte(o) do_get_mem_byte((uae_u8 *)(comp_pc_p + (o) + 1)) +#define comp_get_iword(o) do_get_mem_word((uae_u16 *)(comp_pc_p + (o))) +#define comp_get_ilong(o) do_get_mem_long((uae_u32 *)(comp_pc_p + (o))) + +/* Preferences handling */ +void check_prefs_changed_comp (void); + +struct blockinfo_t; + +typedef struct dep_t { + uae_u32* jmp_off; + struct blockinfo_t* target; + struct dep_t** prev_p; + struct dep_t* next; +} dependency; + +typedef struct blockinfo_t { + uae_s32 count; + cpuop_func* direct_handler_to_use; + cpuop_func* handler_to_use; + /* The direct handler does not check for the correct address */ + + cpuop_func* handler; + cpuop_func* direct_handler; + + cpuop_func* direct_pen; + cpuop_func* direct_pcc; + + uae_u8* nexthandler; + uae_u8* pc_p; + + uae_u32 c1; + uae_u32 c2; + uae_u32 len; + + struct blockinfo_t* next_same_cl; + struct blockinfo_t** prev_same_cl_p; + struct blockinfo_t* next; + struct blockinfo_t** prev_p; + + uae_u32 min_pcp; + uae_u8 optlevel; + uae_u8 needed_flags; + uae_u8 status; + uae_u8 havestate; + + dependency dep[2]; /* Holds things we depend on */ + dependency* deplist; /* List of things that depend on this */ + smallstate env; +} blockinfo; + +#define BI_NEW 0 +#define BI_COUNTING 1 +#define BI_TARGETTED 2 + +typedef struct { + uae_u8 type; + uae_u8 reg; + uae_u32 next; +} regacc; + +void execute_normal(void); +void exec_nostats(void); +void do_nothing(void); + diff --git a/include/compiler.h b/include/compiler.h new file mode 100755 index 00000000..544a00e6 --- /dev/null +++ b/include/compiler.h @@ -0,0 +1,115 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * m68k -> i386 compiler + * + * (c) 1995 Bernd Schmidt + */ + +typedef uaecptr (*code_execfunc)(void); + +struct code_page { + struct code_page *next; + uae_u32 allocmask; +}; + +struct hash_block { + struct hash_block *lru_next, *lru_prev; + struct hash_entry *he_first; + + struct code_page *cpage; + int alloclen; + uae_u32 page_allocmask; + char *compile_start; + + int nrefs; + + int translated:1; + int untranslatable:1; + int allocfailed:1; +}; + +struct hash_entry { + code_execfunc execute; /* For the sake of the stubs in X86.S */ + struct hash_entry *next,*prev; + struct hash_entry *next_same_block, *lru_next, *lru_prev; + struct hash_block *block; + + uaecptr addr; + uae_u32 matchword; + int ncalls:8; + int locked:1; + int cacheflush:1; +}; + +extern int nr_bbs_start; +extern uae_u8 nr_bbs_to_run; +extern code_execfunc exec_me; + +#ifdef USE_COMPILER +STATIC_INLINE void run_compiled_code(void) +{ + + /*if (regs.spcflags == SPCFLAG_EXEC && may_run_compiled) {*/ + while (regs.spcflags == SPCFLAG_EXEC) { + uaecptr newpc; + regs.spcflags = 0; + /* newpc = (*exec_me)();*/ + __asm__ __volatile__ ("pushl %%ebp; call *%1; popl %%ebp" : "=a" (newpc) : "r" (exec_me) : + "%eax", "%edx", "%ecx", "%ebx", + "%edi", "%esi", "memory", "cc"); + if (nr_bbs_to_run == 0) { + struct hash_entry *h = (struct hash_entry *)newpc; + regs.spcflags = SPCFLAG_EXEC; + exec_me = h->execute; + regs.pc = h->addr; + regs.pc_p = regs.pc_oldp = get_real_address(h->addr); + nr_bbs_to_run = nr_bbs_start; + } else + m68k_setpc_fast(newpc); + do_cycles(); + } +/*} else */ + regs.spcflags &= ~SPCFLAG_EXEC; +} + +extern void compiler_init(void); +extern void possible_loadseg(void); + +extern void m68k_do_rts(void); +extern void m68k_do_bsr(uaecptr, uae_s32); +extern void m68k_do_jsr(uaecptr, uaecptr); +extern void compiler_flush_jsr_stack(void); + +#else + +#define run_compiled_code() do { ; } while (0) +#define compiler_init() do { ; } while (0) +#define possible_loadseg() do { ; } while (0) +#define compiler_flush_jsr_stack() do { ; } while (0) + +STATIC_INLINE void m68k_do_rts(void) +{ + uaecptr pc = get_long (m68k_areg(regs, 7)); + m68k_areg(regs, 7) += 4; + if (pc & 1) + exception3 (0x4e75, m68k_getpc(), pc); + else + m68k_setpc(pc); +} + +STATIC_INLINE void m68k_do_bsr(uaecptr oldpc, uae_s32 offset) +{ + m68k_areg(regs, 7) -= 4; + put_long(m68k_areg(regs, 7), oldpc); + m68k_incpc(offset); +} + +STATIC_INLINE void m68k_do_jsr(uaecptr oldpc, uaecptr dest) +{ + m68k_areg(regs, 7) -= 4; + put_long(m68k_areg(regs, 7), oldpc); + m68k_setpc(dest); +} + +#endif diff --git a/include/cpu_prefetch.h b/include/cpu_prefetch.h new file mode 100755 index 00000000..f30f05f3 --- /dev/null +++ b/include/cpu_prefetch.h @@ -0,0 +1,126 @@ + +STATIC_INLINE uae_u32 get_word_prefetch (int o) +{ + uae_u32 v = regs.irc; + regs.irc = get_word (m68k_getpc() + o); + return v; +} +STATIC_INLINE uae_u32 get_long_prefetch (int o) +{ + uae_u32 v = get_word_prefetch (o) << 16; + v |= get_word_prefetch (o + 2); + return v; +} + +#ifdef CPUEMU_6 +STATIC_INLINE uae_u32 mem_access_delay_word_read_cycles (uaecptr addr, int *cycles) +{ + if (addr < 0x200000 || (addr >= 0xc00000 && addr < 0xe00000)) { + return wait_cpu_cycle_read_cycles (addr, 1, cycles); + } else if (!(addr >= 0xa00000 && addr < 0xc00000)) { + do_cycles_ce (4 * CYCLE_UNIT / 2); + *cycles = 4; + } + return get_word (addr); +} +STATIC_INLINE uae_u32 mem_access_delay_word_read (uaecptr addr) +{ + if (addr < 0x200000 || (addr >= 0xc00000 && addr < 0xe00000)) { + return wait_cpu_cycle_read (addr, 1); + } else if (!(addr >= 0xa00000 && addr < 0xc00000)) { + do_cycles_ce (4 * CYCLE_UNIT / 2); + } + return get_word (addr); +} +STATIC_INLINE uae_u32 mem_access_delay_byte_read (uaecptr addr) +{ + if (addr < 0x200000 || (addr >= 0xc00000 && addr < 0xe00000)) { + return wait_cpu_cycle_read (addr, 0); + } else if (!(addr >= 0xa00000 && addr < 0xc00000)) { + do_cycles_ce (4 * CYCLE_UNIT / 2); + } + return get_byte (addr); +} +STATIC_INLINE void mem_access_delay_byte_write (uaecptr addr, uae_u32 v) +{ + if (addr < 0x200000 || (addr >= 0xc00000 && addr < 0xe00000)) { + wait_cpu_cycle_write (addr, 0, v); + return; + } else if (!(addr >= 0xa00000 && addr < 0xc00000)) { + do_cycles_ce (4 * CYCLE_UNIT / 2); + } + put_byte (addr, v); +} +STATIC_INLINE void mem_access_delay_word_write (uaecptr addr, uae_u32 v) +{ + if (addr < 0x200000 || (addr >= 0xc00000 && addr < 0xe00000)) { + wait_cpu_cycle_write (addr, 1, v); + return; + } else if (!(addr >= 0xa00000 && addr < 0xc00000)) { + do_cycles_ce (4 * CYCLE_UNIT / 2); + } + put_word (addr, v); +} + +STATIC_INLINE uae_u32 get_word_ce (uaecptr addr) +{ + return mem_access_delay_word_read (addr); +} + +STATIC_INLINE uae_u32 get_byte_ce (uaecptr addr) +{ + return mem_access_delay_byte_read (addr); +} + +STATIC_INLINE uae_u32 get_word_ce_prefetch (int o) +{ + uae_u32 v = regs.irc; + regs.irc = get_word_ce (m68k_getpc() + o); + return v; +} + +STATIC_INLINE int get_word_ce_prefetch_cycles (int o) +{ + int cycles = 0; + regs.irc = mem_access_delay_word_read_cycles (m68k_getpc() + o, &cycles); + return cycles; +} + +STATIC_INLINE void put_word_ce (uaecptr addr, uae_u16 v) +{ + mem_access_delay_word_write (addr, v); +} + +STATIC_INLINE void put_byte_ce (uaecptr addr, uae_u8 v) +{ + mem_access_delay_byte_write (addr, v); +} + +STATIC_INLINE void m68k_do_rts_ce (void) +{ + uaecptr pc; + pc = get_word_ce (m68k_areg (regs, 7)) << 16; + pc |= get_word_ce (m68k_areg (regs, 7) + 2); + m68k_areg (regs, 7) += 4; + if (pc & 1) + exception3 (0x4e75, m68k_getpc(), pc); + else + m68k_setpc (pc); +} + +STATIC_INLINE void m68k_do_bsr_ce (uaecptr oldpc, uae_s32 offset) +{ + m68k_areg (regs, 7) -= 4; + put_word_ce (m68k_areg (regs, 7), oldpc >> 16); + put_word_ce (m68k_areg (regs, 7) + 2, oldpc); + m68k_incpc (offset); +} + +STATIC_INLINE void m68k_do_jsr_ce (uaecptr oldpc, uaecptr dest) +{ + m68k_areg (regs, 7) -= 4; + put_word_ce (m68k_areg (regs, 7), oldpc >> 16); + put_word_ce (m68k_areg (regs, 7) + 2, oldpc); + m68k_setpc (dest); +} +#endif \ No newline at end of file diff --git a/include/custom.h b/include/custom.h new file mode 100755 index 00000000..09a5dab9 --- /dev/null +++ b/include/custom.h @@ -0,0 +1,174 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * custom chip support + * + * (c) 1995 Bernd Schmidt + */ + +/* These are the masks that are ORed together in the chipset_mask option. + * If CSMASK_AGA is set, the ECS bits are guaranteed to be set as well. */ +#define CSMASK_ECS_AGNUS 1 +#define CSMASK_ECS_DENISE 2 +#define CSMASK_AGA 4 + +uae_u32 get_copper_address(int copno); + +extern void custom_init (void); +extern void customreset (void); +extern int intlev (void); +extern void dumpcustom (void); + +extern void do_disk (void); +extern void do_copper (void); + +extern void notice_new_xcolors (void); +extern void notice_screen_contents_lost (void); +extern void init_row_map (void); +extern void init_hz (void); + +extern int picasso_requested_on; +extern int picasso_on; +extern int turbo_emulation; + +/* Set to 1 to leave out the current frame in average frame time calculation. + * Useful if the debugger was active. */ +extern int bogusframe; + +extern uae_u16 dmacon; +extern uae_u16 intena,intreq; + +extern int current_hpos (void); +extern int vpos; + +extern int find_copper_record (uaecptr, int *, int *); + +extern int n_frames; + +STATIC_INLINE int dmaen (unsigned int dmamask) +{ + return (dmamask & dmacon) && (dmacon & 0x200); +} + +#define SPCFLAG_STOP 2 +#define SPCFLAG_COPPER 4 +#define SPCFLAG_INT 8 +#define SPCFLAG_BRK 16 +#define SPCFLAG_EXTRA_CYCLES 32 +#define SPCFLAG_TRACE 64 +#define SPCFLAG_DOTRACE 128 +/* #define SPCFLAG_DOINT 256 obsolete hack */ +#define SPCFLAG_BLTNASTY 512 +#define SPCFLAG_EXEC 1024 +#define SPCFLAG_ACTION_REPLAY 2048 +#define SPCFLAG_MODE_CHANGE 8192 +#define SPCFLAG_END_COMPILE 16384 + +extern uae_u16 adkcon; + +extern unsigned int joy0dir, joy1dir; +extern int joy0button, joy1button; + +extern void INTREQ (uae_u16); +extern void INTREQ_0 (uae_u16); +extern uae_u16 INTREQR (void); + +/* maximums for statically allocated tables */ + +#define MAXHPOS 256 +#define MAXVPOS 576 + +/* PAL/NTSC values */ + +#define MAXHPOS_PAL 227 +#define MAXHPOS_NTSC 227 +#define MAXVPOS_PAL 312 +#define MAXVPOS_NTSC 262 +#define VBLANK_ENDLINE_PAL 27 +#define VBLANK_ENDLINE_NTSC 28 +#define VBLANK_SPRITE_PAL 25 +#define VBLANK_SPRITE_NTSC 20 +#define VBLANK_HZ_PAL 50 +#define VBLANK_HZ_NTSC 60 + +extern int maxhpos, maxvpos, minfirstline, vblank_endline, numscrlines; +extern int vblank_hz, fake_vblank_hz, vblank_skip; +extern unsigned long syncbase; +#define NUMSCRLINES (maxvpos+1-minfirstline+1) + +#define DMA_AUD0 0x0001 +#define DMA_AUD1 0x0002 +#define DMA_AUD2 0x0004 +#define DMA_AUD3 0x0008 +#define DMA_DISK 0x0010 +#define DMA_SPRITE 0x0020 +#define DMA_BLITTER 0x0040 +#define DMA_COPPER 0x0080 +#define DMA_BITPLANE 0x0100 +#define DMA_MASTER 0x0200 +#define DMA_BLITPRI 0x0400 + +#define CYCLE_REFRESH 0x001 +#define CYCLE_DISK 0x002 +#define CYCLE_AUDIO 0x004 +#define CYCLE_SPRITE 0x008 +#define CYCLE_BITPLANE 0x010 +#define CYCLE_COPPER 0x020 +#define CYCLE_BLITTER 0x040 +#define CYCLE_BLITTER_F 0x080 +#define CYCLE_CPU 0x100 + +extern unsigned long frametime, timeframes; +extern int plfstrt, plfstop, plffirstline, plflastline; +extern uae_u16 htotal, vtotal; + +/* 100 words give you 1600 horizontal pixels. Should be more than enough for + * superhires. Don't forget to update the definition in genp2c.c as well. + * needs to be larger for superhires support */ +#ifdef CUSTOM_SIMPLE +#define MAX_WORDS_PER_LINE 50 +#else +#define MAX_WORDS_PER_LINE 100 +#endif + +extern uae_u32 hirestab_h[256][2]; +extern uae_u32 lorestab_h[256][4]; + +extern uae_u32 hirestab_l[256][1]; +extern uae_u32 lorestab_l[256][2]; + +#ifdef AGA +/* AGA mode color lookup tables */ +extern unsigned int xredcolors[256], xgreencolors[256], xbluecolors[256]; +#endif + +extern int bpl_off[8]; + +#define RES_LORES 0 +#define RES_HIRES 1 +#define RES_SUPERHIRES 2 + +/* calculate shift depending on resolution (replaced "decided_hires ? 4 : 8") */ +#define RES_SHIFT(res) ((res) == RES_LORES ? 8 : (res) == RES_HIRES ? 4 : 2) + +/* get resolution from bplcon0 */ +STATIC_INLINE int GET_RES (uae_u16 con0) +{ + int res = ((con0) & 0x8000) ? RES_HIRES : ((con0) & 0x40) ? RES_SUPERHIRES : RES_LORES; + return res; +} +/* get sprite width from FMODE */ +#define GET_SPRITEWIDTH(FMODE) ((((FMODE) >> 2) & 3) == 3 ? 64 : (((FMODE) >> 2) & 3) == 0 ? 16 : 32) +/* Compute the number of bitplanes from a value written to BPLCON0 */ +#define GET_PLANES(x) ((((x) >> 12) & 7) | (((x) & 0x10) >> 1)) + +extern void fpscounter_reset (void); +extern unsigned long idletime; + +struct customhack { + uae_u16 v; + int vpos, hpos; +}; +void customhack_put (struct customhack *ch, uae_u16 v, int hpos); +uae_u16 customhack_get (struct customhack *ch, int hpos); + diff --git a/include/debug.h b/include/debug.h new file mode 100755 index 00000000..6875898a --- /dev/null +++ b/include/debug.h @@ -0,0 +1,26 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Debugger + * + * (c) 1995 Bernd Schmidt + * + */ + +#define MAX_HIST 10000 + +extern int firsthist; +extern int lasthist; +extern int debugging; +#ifdef NEED_TO_DEBUG_BADLY +extern struct regstruct history[MAX_HIST]; +extern union flagu historyf[MAX_HIST]; +#else +extern uaecptr history[MAX_HIST]; +#endif +extern int exception_debugging; + +extern void debug(void); +extern void activate_debugger(void); +extern int notinrom (void); +extern const char *debuginfo(int); diff --git a/include/disk.h b/include/disk.h new file mode 100755 index 00000000..b1972efd --- /dev/null +++ b/include/disk.h @@ -0,0 +1,35 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * disk support + * + * (c) 1995 Bernd Schmidt + */ + +typedef enum { DRV_35_DD, DRV_35_HD, DRV_525_SD } drive_type; + +extern void DISK_init (void); +extern void DISK_free (void); +extern void DISK_select (uae_u8 data); +extern uae_u8 DISK_status (void); +extern void disk_eject (int num); +extern int disk_empty (int num); +extern void disk_insert (int num, const char *name); +extern void DISK_check_change (void); +extern struct zfile *DISK_validate_filename (const char *, int, int *); +extern void DISK_handler (void); +extern void DISK_update (int hpos); +extern void DISK_reset (void); +extern int disk_getwriteprotect (const char *name); +extern int disk_setwriteprotect (int num, const char *name, int protect); +extern void disk_creatediskfile (char *name, int type, drive_type adftype); +extern void dumpdisk (void); +extern void DISK_history_add (const char *name, int idx); +extern char *DISK_history_get (int idx); + +extern void DSKLEN (uae_u16 v, int hpos); +extern uae_u16 DSKBYTR (int hpos); +extern void DSKDAT (uae_u16); +extern void DSKSYNC (int, uae_u16); +extern void DSKPTL (uae_u16); +extern void DSKPTH (uae_u16); diff --git a/include/drawing.h b/include/drawing.h new file mode 100755 index 00000000..b5e8a9f5 --- /dev/null +++ b/include/drawing.h @@ -0,0 +1,285 @@ +/* + * Data used for communication between custom.c and drawing.c. + * + * Copyright 1996-1998 Bernd Schmidt + */ + +#define SMART_UPDATE 1 + +#ifdef SUPPORT_PENGUINS +#undef SMART_UPDATE +#define SMART_UPDATE 1 +#endif + +#ifdef AGA +#define MAX_PLANES 8 +#else +#define MAX_PLANES 6 +#endif + +/* According to the HRM, pixel data spends a couple of cycles somewhere in the chips + before it appears on-screen. */ +#define DIW_DDF_OFFSET 9 + +/* We ignore that many lores pixels at the start of the display. These are + * invisible anyway due to hardware DDF limits. */ +#define DISPLAY_LEFT_SHIFT 0x40 +#define PIXEL_XPOS(HPOS) (((HPOS)*2 - DISPLAY_LEFT_SHIFT + DIW_DDF_OFFSET - 1) << lores_shift) + +#define max_diwlastword (PIXEL_XPOS(0x1d4 >> 1)) + +extern int lores_factor, lores_shift, sprite_width; + +STATIC_INLINE int coord_hw_to_window_x (int x) +{ + x -= DISPLAY_LEFT_SHIFT; + return x << lores_shift; +} + +STATIC_INLINE int coord_window_to_hw_x (int x) +{ + x >>= lores_shift; + return x + DISPLAY_LEFT_SHIFT; +} + +STATIC_INLINE int coord_diw_to_window_x (int x) +{ + return (x - DISPLAY_LEFT_SHIFT + DIW_DDF_OFFSET - 1) << lores_shift; +} + +STATIC_INLINE int coord_window_to_diw_x (int x) +{ + x = coord_window_to_hw_x (x); + return x - DIW_DDF_OFFSET; +} + +extern int framecnt; + + +/* color values in two formats: 12 (OCS/ECS) or 24 (AGA) bit Amiga RGB (color_regs), + * and the native color value; both for each Amiga hardware color register. + * + * !!! See color_reg_xxx functions below before touching !!! + */ +struct color_entry { + uae_u16 color_regs_ecs[32]; +#ifndef AGA + xcolnr acolors[32]; +#else + xcolnr acolors[256]; + uae_u32 color_regs_aga[256]; +#endif +}; + +#ifdef AGA +/* convert 24 bit AGA Amiga RGB to native color */ +/* warning: ugly and works with little-endian cpu's only */ +#define CONVERT_RGB(c) \ + ( xbluecolors[((uae_u8*)(&c))[0]] | xgreencolors[((uae_u8*)(&c))[1]] | xredcolors[((uae_u8*)(&c))[2]] ) +#else +#define CONVERT_RGB(c) 0 +#endif + +STATIC_INLINE xcolnr getxcolor (int c) +{ +#ifdef AGA + if (currprefs.chipset_mask & CSMASK_AGA) + return CONVERT_RGB(c); + else +#endif + return xcolors[c]; +} + +/* functions for reading, writing, copying and comparing struct color_entry */ +STATIC_INLINE int color_reg_get (struct color_entry *ce, int c) +{ +#ifdef AGA + if (currprefs.chipset_mask & CSMASK_AGA) + return ce->color_regs_aga[c]; + else +#endif + return ce->color_regs_ecs[c]; +} +STATIC_INLINE void color_reg_set (struct color_entry *ce, int c, int v) +{ +#ifdef AGA + if (currprefs.chipset_mask & CSMASK_AGA) + ce->color_regs_aga[c] = v; + else +#endif + ce->color_regs_ecs[c] = v; +} +STATIC_INLINE int color_reg_cmp (struct color_entry *ce1, struct color_entry *ce2) +{ +#ifdef AGA + if (currprefs.chipset_mask & CSMASK_AGA) + return memcmp (ce1->color_regs_aga, ce2->color_regs_aga, sizeof (uae_u32) * 256); + else +#endif + return memcmp (ce1->color_regs_ecs, ce2->color_regs_ecs, sizeof (uae_u16) * 32); +} +/* ugly copy hack, is there better solution? */ +STATIC_INLINE void color_reg_cpy (struct color_entry *dst, struct color_entry *src) +{ +#ifdef AGA + if (currprefs.chipset_mask & CSMASK_AGA) + /* copy acolors and color_regs_aga */ + memcpy (dst->acolors, src->acolors, sizeof(struct color_entry) - sizeof(uae_u16) * 32); + else +#endif + /* copy first 32 acolors and color_regs_ecs */ + memcpy (dst->color_regs_ecs, src->color_regs_ecs, + sizeof(struct color_entry)); +} + +/* + * The idea behind this code is that at some point during each horizontal + * line, we decide how to draw this line. There are many more-or-less + * independent decisions, each of which can be taken at a different horizontal + * position. + * Sprites and color changes are handled specially: There isn't a single decision, + * but a list of structures containing information on how to draw the line. + */ + +struct color_change { + int linepos; + int regno; + unsigned long value; +}; + +/* 440 rather than 880, since sprites are always lores. */ +#ifdef CUSTOM_SIMPLE +#define MAX_PIXELS_PER_LINE 880 +#define MAX_VIDHEIGHT 800 +#else +#define MAX_PIXELS_PER_LINE 1760 +#define MAX_VIDHEIGHT 2048 +#endif + +/* No divisors for MAX_PIXELS_PER_LINE; we support AGA and may one day + want to use SHRES sprites. */ +#define MAX_SPR_PIXELS (((MAXVPOS + 1)*2 + 1) * MAX_PIXELS_PER_LINE) + +struct sprite_entry +{ + unsigned short pos; + unsigned short max; + unsigned int first_pixel; + unsigned int has_attached; +}; + +union sps_union { + uae_u8 bytes[2 * MAX_SPR_PIXELS]; + uae_u32 words[2 * MAX_SPR_PIXELS / 4]; +}; +extern union sps_union spixstate; +extern uae_u16 spixels[MAX_SPR_PIXELS * 2]; + +/* Way too much... */ +#define MAX_REG_CHANGE ((MAXVPOS + 1) * 2 * MAXHPOS) + +#ifdef OS_WITHOUT_MEMORY_MANAGEMENT +extern struct color_change *color_changes[2]; +#else +extern struct color_change color_changes[2][MAX_REG_CHANGE]; +#endif + +extern struct color_entry color_tables[2][(MAXVPOS+1) * 2]; +extern struct color_entry *curr_color_tables, *prev_color_tables; + +extern struct sprite_entry *curr_sprite_entries, *prev_sprite_entries; +extern struct color_change *curr_color_changes, *prev_color_changes; +extern struct draw_info *curr_drawinfo, *prev_drawinfo; + +/* struct decision contains things we save across drawing frames for + * comparison (smart update stuff). */ +struct decision { + /* Records the leftmost access of BPL1DAT. */ + int plfleft, plfright, plflinelen; + /* Display window: native coordinates, depend on lores state. */ + int diwfirstword, diwlastword; + int ctable; + + uae_u16 bplcon0, bplcon2; +#ifdef AGA + uae_u16 bplcon3, bplcon4; +#endif + uae_u8 nr_planes; + uae_u8 bplres; + unsigned int any_hires_sprites:1; + unsigned int ham_seen:1; + unsigned int ham_at_start:1; +}; + +/* Anything related to changes in hw registers during the DDF for one + * line. */ +struct draw_info { + int first_sprite_entry, last_sprite_entry; + int first_color_change, last_color_change; + int nr_color_changes, nr_sprites; +}; + +extern int next_sprite_entry; + +extern struct decision line_decisions[2 * (MAXVPOS+1) + 1]; +extern struct draw_info line_drawinfo[2][2 * (MAXVPOS+1) + 1]; + +extern uae_u8 line_data[(MAXVPOS+1) * 2][MAX_PLANES * MAX_WORDS_PER_LINE * 2]; + +extern uae_u8 *real_bplpt[8]; + +/* Functions in drawing.c. */ +extern int coord_native_to_amiga_y (int); +extern int coord_native_to_amiga_x (int); + +extern void record_diw_line (int first, int last); +extern void hardware_line_completed (int lineno); + +/* Determine how to draw a scan line. */ +enum nln_how { + /* All lines on a non-doubled display. */ + nln_normal, + /* Non-interlace, doubled display. */ + nln_doubled, + /* Interlace, doubled display, upper line. */ + nln_upper, + /* Interlace, doubled display, lower line. */ + nln_lower, + /* This line normal, next one black. */ + nln_nblack +}; + +extern void hsync_record_line_state (int lineno, enum nln_how, int changed); +extern void vsync_handle_redraw (int long_frame, int lof_changed); +extern void init_hardware_for_drawing_frame (void); +extern void finish_drawing_frame (void); +extern void reset_drawing (void); +extern void drawing_init (void); +extern void notice_interlace_seen (void); +extern void frame_drawn (void); +extern void redraw_frame (void); + +/* Finally, stuff that shouldn't really be shared. */ + +extern int thisframe_first_drawn_line, thisframe_last_drawn_line; +extern int diwfirstword,diwlastword; + +#define IHF_SCROLLLOCK 0 +#define IHF_QUIT_PROGRAM 1 +#define IHF_PICASSO 2 +#define IHF_SOUNDADJUST 3 + +extern int inhibit_frame; + +STATIC_INLINE void set_inhibit_frame (int bit) +{ + inhibit_frame |= 1 << bit; +} +STATIC_INLINE void clear_inhibit_frame (int bit) +{ + inhibit_frame &= ~(1 << bit); +} +STATIC_INLINE void toggle_inhibit_frame (int bit) +{ + inhibit_frame ^= 1 << bit; +} diff --git a/include/driveclick.h b/include/driveclick.h new file mode 100755 index 00000000..2cd70aef --- /dev/null +++ b/include/driveclick.h @@ -0,0 +1,40 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Drive Click emulation stuff + * + * Copyright 2004 James Bagg, Toni Wilen + */ + + +struct drvsample { + int len; + int pos; + uae_s16 *p; +}; + +#define DS_CLICK 0 +#define DS_SPIN 1 +#define DS_SPINND 2 +#define DS_START 3 +#define DS_SNATCH 4 +#define DS_END 5 + +extern void driveclick_click(int drive, int startOffset); +extern void driveclick_motor(int drive, int running); +extern void driveclick_insert(int drive, int eject); +extern void driveclick_init(void); +extern void driveclick_free(void); +extern void driveclick_reset(void); +extern void driveclick_mix(uae_s16*, int); +extern int driveclick_loadresource(struct drvsample*, int); +extern void driveclick_check_prefs (void); +extern uae_s16 *decodewav (uae_u8 *s, int *len); + +#define DS_BUILD_IN_SOUNDS 1 +#define DS_NAME_CLICK "drive_click_" +#define DS_NAME_SPIN "drive_spin_" +#define DS_NAME_SPIN_ND "drive_spinnd_" +#define DS_NAME_START "drive_start_" +#define DS_NAME_SNATCH "drive_snatch_" + diff --git a/include/enforcer.h b/include/enforcer.h new file mode 100755 index 00000000..c54efc02 --- /dev/null +++ b/include/enforcer.h @@ -0,0 +1,7 @@ +#ifndef UAE__ENFORCER_H +#define UAE__ENFORCER_H + +int enforcer_enable(void); +int enforcer_disable(void); + +#endif \ No newline at end of file diff --git a/include/ersatz.h b/include/ersatz.h new file mode 100755 index 00000000..4929db55 --- /dev/null +++ b/include/ersatz.h @@ -0,0 +1,11 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * A "replacement" for a missing Kickstart + * + * (c) 1995 Bernd Schmidt + */ + +extern void init_ersatz_rom (uae_u8 *data); +extern void ersatz_perform (uae_u16); +extern void DISK_ersatz_read (int,int, uaecptr); diff --git a/include/events.h b/include/events.h new file mode 100755 index 00000000..e65eba6a --- /dev/null +++ b/include/events.h @@ -0,0 +1,53 @@ +#ifndef EVENTS_H +#define EVENTS_H + + /* + * UAE - The Un*x Amiga Emulator + * + * Events + * These are best for low-frequency events. Having too many of them, + * or using them for events that occur too frequently, can cause massive + * slowdown. + * + * Copyright 1995-1998 Bernd Schmidt + */ + +#undef EVENT_DEBUG + +#include "machdep/rpt.h" + +extern volatile frame_time_t vsynctime, vsyncmintime; +extern void reset_frame_rate_hack (void); +extern int rpt_available; +extern unsigned long syncbase; + +extern void compute_vsynctime (void); +extern void init_eventtab (void); +extern void do_cycles_ce (long cycles); + +extern unsigned long currcycle, nextevent, is_lastline; +extern unsigned long sample_evtime; +typedef void (*evfunc)(void); + +struct ev +{ + int active; + unsigned long int evtime, oldcycles; + evfunc handler; +}; + +enum { + ev_hsync, ev_copper, ev_audio, ev_cia, ev_blitter, ev_disk, + ev_max +}; + +extern struct ev eventtab[ev_max]; + + +#ifdef JIT +#include "events_jit.h" +#else +#include "events_normal.h" +#endif + +#endif diff --git a/include/events_jit.h b/include/events_jit.h new file mode 100755 index 00000000..8b1995dc --- /dev/null +++ b/include/events_jit.h @@ -0,0 +1,197 @@ +#if 1 + +/* Let's see whether hiding this away somewhere where the compiler can't + see it will cure it of its silly urge to mis-optimize the comparison */ +extern long int diff32(frame_time_t x, frame_time_t y); + +STATIC_INLINE void events_schedule (void) +{ + int i; + + unsigned long int mintime = ~0L; + for (i = 0; i < ev_max; i++) { + if (eventtab[i].active) { + unsigned long int eventtime = eventtab[i].evtime - currcycle; +#ifdef EVENT_DEBUG + if (eventtime == 0) { + write_log("event %d bug\n",i); + } +#endif + if (eventtime < mintime) + mintime = eventtime; + } + } + nextevent = currcycle + mintime; +} + +extern signed long pissoff; + +STATIC_INLINE void cycles_do_special (void) +{ + if (pissoff >= 0) + pissoff = -1; +} + +STATIC_INLINE void do_extra_cycles (unsigned long cycles_to_add) +{ + pissoff -= cycles_to_add; +} + +STATIC_INLINE unsigned long int get_cycles (void) +{ + return currcycle; +} + +STATIC_INLINE void set_cycles (unsigned long int x) +{ + currcycle = x; +} + +STATIC_INLINE void do_cycles_slow (unsigned long cycles_to_add) +{ + if ((pissoff -= cycles_to_add) >= 0) + return; + + cycles_to_add = -pissoff; + pissoff = 0; + + if (is_lastline && eventtab[ev_hsync].evtime - currcycle <= cycles_to_add) { + int rpt = read_processor_time (); + int v = rpt - vsyncmintime; + if (v > (int)syncbase || v < -((int)syncbase)) + vsyncmintime = rpt; + if (v < 0) { + pissoff = 3000 * CYCLE_UNIT; + return; + } + } + while ((nextevent - currcycle) <= cycles_to_add) { + int i; + cycles_to_add -= (nextevent - currcycle); + currcycle = nextevent; + + for (i = 0; i < ev_max; i++) { + if (eventtab[i].active && eventtab[i].evtime == currcycle) { + (*eventtab[i].handler)(); + } + } + events_schedule(); + } + currcycle += cycles_to_add; +} + +#define do_cycles do_cycles_slow +#define countdown pissoff + +#else + +/* Let's see whether hiding this away somewhere where the compiler can't + see it will cure it of its silly urge to mis-optimize the comparison */ extern long int diff32(frame_time_t x, frame_time_t y); + +extern long cycles_to_next_event; +extern long max_cycles_to_next_event; +extern long cycles_to_hsync_event; +extern long pissoff; + +STATIC_INLINE void cycles_do_special(void) +{ + if (cycles_to_next_event >= 0) { + pissoff += cycles_to_next_event; + cycles_to_next_event = 0; + } +} + + +STATIC_INLINE void do_extra_cycles (unsigned long cycles_to_add) { + pissoff -= cycles_to_add; +} + +STATIC_INLINE unsigned long int get_cycles (void) +{ + if (cycles_to_next_event <= max_cycles_to_next_event) { + max_cycles_to_next_event = cycles_to_next_event; + return nextevent - cycles_to_next_event; + } else { + return nextevent - max_cycles_to_next_event; + } +} + +STATIC_INLINE void events_schedule (void) +{ + int i; + + unsigned long int curcycles = get_cycles(); + unsigned long int mintime = ~0L; + + cycles_to_hsync_event=eventtab[ev_hsync].evtime - curcycles; + for (i = 0; i < ev_max; i++) { + if (eventtab[i].active) { + unsigned long int eventtime = eventtab[i].evtime - curcycles; + if (eventtime < mintime) + mintime = eventtime; + } + } + nextevent = curcycles + mintime; + max_cycles_to_next_event = mintime; + cycles_to_next_event = mintime; + cycles_to_hsync_event = mintime - cycles_to_hsync_event; +} + +STATIC_INLINE void set_cycles (unsigned long int x) +{ + cycles_to_next_event = nextevent - x; + events_schedule (); +} + +STATIC_INLINE void do_cycles_slow (long cycles_to_add) +{ + cycles_to_next_event -= cycles_to_add; + if (cycles_to_next_event > 0) + return; + + cycles_to_next_event += pissoff; + pissoff=0; + + if (is_lastline + && /*cycles_to_next_event <= cycles_to_hsync_event*/ + eventtab[ev_hsync].evtime == nextevent) + { + frame_time_t now=read_processor_time(); + if (diff32(now, vsyncmintime)<0) + { + cycles_to_next_event += 3000 * CYCLE_UNIT; + return; + } + } + cycles_to_add=0; + while (cycles_to_next_event <= cycles_to_add) { + int i; + + cycles_to_add-=cycles_to_next_event; + cycles_to_next_event=0; + for (i = 0; i < ev_max; i++) { + if (eventtab[i].active && eventtab[i].evtime == nextevent) { + (*eventtab[i].handler) (); + } + } + events_schedule(); + } + cycles_to_next_event -= cycles_to_add; +} + +#define do_cycles do_cycles_slow +#define countdown cycles_to_next_event + +#endif + +/* This is a special-case function. Normally, all events should lie in the + future; they should only ever be active at the current cycle during + do_cycles. However, a snapshot is saved during do_cycles, and so when + restoring it, we may have other events pending. */ STATIC_INLINE void handle_active_events (void) { + int i; + for (i = 0; i < ev_max; i++) { + if (eventtab[i].active && eventtab[i].evtime == currcycle) { + (*eventtab[i].handler)(); + } + } +} diff --git a/include/events_normal.h b/include/events_normal.h new file mode 100755 index 00000000..88f78b3a --- /dev/null +++ b/include/events_normal.h @@ -0,0 +1,90 @@ + +STATIC_INLINE void cycles_do_special (void) +{ +} +STATIC_INLINE void set_cycles (int c) +{ +} + +STATIC_INLINE void events_schedule (void) +{ + int i; + + unsigned long int mintime = ~0L; + for (i = 0; i < ev_max; i++) { + if (eventtab[i].active) { + unsigned long int eventtime = eventtab[i].evtime - currcycle; + if (eventtime < mintime) + mintime = eventtime; + } + } + nextevent = currcycle + mintime; +} + +STATIC_INLINE void do_cycles_slow (unsigned long cycles_to_add) +{ + if (is_lastline && eventtab[ev_hsync].evtime - currcycle <= cycles_to_add + && (long int)(read_processor_time () - vsyncmintime) < 0) + return; + + while ((nextevent - currcycle) <= cycles_to_add) { + int i; + cycles_to_add -= (nextevent - currcycle); + currcycle = nextevent; + + for (i = 0; i < ev_max; i++) { + if (eventtab[i].active && eventtab[i].evtime == currcycle) { + (*eventtab[i].handler)(); + } + } + events_schedule(); + } + currcycle += cycles_to_add; +} + +STATIC_INLINE void do_cycles_fast (void) +{ + if (is_lastline && eventtab[ev_hsync].evtime - currcycle <= 1 + && (long int)(read_processor_time () - vsyncmintime) < 0) + return; + + currcycle++; + if (nextevent == currcycle) { + int i; + + for (i = 0; i < ev_max; i++) { + if (eventtab[i].active && eventtab[i].evtime == currcycle) { + (*eventtab[i].handler) (); + } + } + events_schedule(); + } + +} + +/* This is a special-case function. Normally, all events should lie in the + future; they should only ever be active at the current cycle during + do_cycles. However, a snapshot is saved during do_cycles, and so when + restoring it, we may have other events pending. */ +STATIC_INLINE void handle_active_events (void) +{ + int i; + for (i = 0; i < ev_max; i++) { + if (eventtab[i].active && eventtab[i].evtime == currcycle) { + (*eventtab[i].handler)(); + } + } +} + +STATIC_INLINE unsigned long get_cycles (void) +{ + return currcycle; +} + +extern void init_eventtab (void); + +#if /* M68K_SPEED == 1 */ 0 +#define do_cycles do_cycles_fast +#else +#define do_cycles do_cycles_slow +#endif diff --git a/include/execlib.h b/include/execlib.h new file mode 100755 index 00000000..362bc6ce --- /dev/null +++ b/include/execlib.h @@ -0,0 +1,45 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Miscellaneous bits for exec emulation + * + * Copyright 1996 Bernd Schmidt + */ + +#define CMD_INVALID 0 +#define CMD_RESET 1 +#define CMD_READ 2 +#define CMD_WRITE 3 +#define CMD_UPDATE 4 +#define CMD_CLEAR 5 +#define CMD_STOP 6 +#define CMD_START 7 +#define CMD_FLUSH 8 +#define CMD_NONSTD 9 + +#define TD_READ64 24 +#define TD_WRITE64 25 +#define TD_SEEK64 26 +#define TD_FORMAT64 27 + +#define NT_TASK 1 +#define NT_DEVICE 3 +#define NT_MSGPORT 4 +#define NT_MESSAGE 5 +#define NT_FREEMSG 6 +#define NT_REPLYMSG 7 +#define NT_RESOURCE 8 +#define NT_LIBRARY 9 +#define NT_SIGNALSEM 15 + +#ifndef MEMF_PUBLIC /* protection for AmigaDOS */ +#define MEMF_PUBLIC 1 +#define MEMF_CHIP 2 +#define MEMF_FAST 4 +#define MEMF_LOCAL 256 +#define MEMF_24BITDMA 512 +#define MEMF_CLEAR (1<<16) +#define MEMF_LARGEST (1<<17) +#define MEMF_REVERSE (1<<18) +#define MEMF_TOTAL (1<<19) +#endif diff --git a/include/fdi2raw.h b/include/fdi2raw.h new file mode 100755 index 00000000..e5ffa0c3 --- /dev/null +++ b/include/fdi2raw.h @@ -0,0 +1,27 @@ +#ifndef __FDI2RAW_H +#define __FDI2RAW_H + +//#include "types.h" +#include +typedef struct fdi FDI; + +#ifdef __cplusplus +extern "C" { +#endif + +extern int fdi2raw_loadtrack (FDI*, uae_u16 *mfmbuf, uae_u16 **trackpointers, uae_u16 **tracktiming, int track, int *tracklengths, int *revolutions, int *indexoffset); +extern FDI *fdi2raw_header(struct zfile *f); +extern void fdi2raw_header_free (FDI *); +extern int fdi2raw_get_last_track(FDI *); +extern int fdi2raw_get_num_sector (FDI *); +extern int fdi2raw_get_last_head(FDI *); +extern int fdi2raw_get_type (FDI *); +extern int fdi2raw_get_bit_rate (FDI *); +extern int fdi2raw_get_rotation (FDI *); +extern int fdi2raw_get_write_protect (FDI *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/filesys.h b/include/filesys.h new file mode 100755 index 00000000..cee3455a --- /dev/null +++ b/include/filesys.h @@ -0,0 +1,50 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Unix file system handler for AmigaDOS + * + * Copyright 1997 Bernd Schmidt + */ + +struct hardfiledata { + uae_u64 size; + uae_u64 offset; + int nrcyls; + int secspertrack; + int surfaces; + int reservedblocks; + int blocksize; + void *handle; + int readonly; + int flags; + uae_u8 *cache; + int cache_valid; + uae_u64 cache_offset; + char vendor_id[8 + 1]; + char product_id[16 + 1]; + char product_rev[4 + 1]; + char device_name[256]; + uae_u64 size2; + uae_u64 offset2; +}; + +#define FILESYS_VIRTUAL 0 +#define FILESYS_HARDFILE 1 +#define FILESYS_HARDFILE_RDB 2 +#define FILESYS_HARDDRIVE 3 + +#define MAX_FILESYSTEM_UNITS 20 + +struct uaedev_mount_info; + +extern struct hardfiledata *get_hardfile_data (int nr); +#define FILESYS_MAX_BLOCKSIZE 2048 +extern int hdf_open (struct hardfiledata *hfd, char *name); +extern int hdf_dup (struct hardfiledata *hfd, void *src); +extern void hdf_close (struct hardfiledata *hfd); +extern int hdf_read (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len); +extern int hdf_write (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len); +extern int hdf_getnumharddrives (void); +extern char *hdf_getnameharddrive (int index, int flags); +extern int hdf_init (void); +extern int isspecialdrive(const char *name); diff --git a/include/filter.h b/include/filter.h new file mode 100755 index 00000000..c31b34fc --- /dev/null +++ b/include/filter.h @@ -0,0 +1,56 @@ + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long u32; + +extern void S2X_refresh (void); +extern void S2X_render (void); +extern void S2X_init (int dw, int dh, int aw, int ah, int mult, int ad, int dd); + +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned long uint32; +typedef int bool; + +extern void S2X_configure (int rb, int gb, int bb, int rs, int gs, int bs); +extern int Init_2xSaI(int rb, int gb, int bb, int rs, int gs, int bs); +extern void Super2xSaI(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height); +extern void SuperEagle(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height); +extern void _2xSaI(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height); +extern void AdMame2x(u8 *srcPtr, u32 srcPitch, /* u8 deltaPtr, */ + u8 *dstPtr, u32 dstPitch, int width, int height); +extern void AdMame2x32(u8 *srcPtr, u32 srcPitch, /* u8 deltaPtr, */ + u8 *dstPtr, u32 dstPitch, int width, int height); + +extern void hq_init(int rb, int gb, int bb, int rs, int gs, int bs); +extern void hq2x_32(unsigned char*, unsigned char*, int, int, int, int, int); +extern void hq3x_32(unsigned char*, unsigned char*, int, int, int, int, int); +extern void hq3x_16(unsigned char*, unsigned char*, int, int, int, int, int); +extern void hq4x_32(unsigned char*, unsigned char*, int, int, int, int, int); + +#define UAE_FILTER_NULL 1 +#define UAE_FILTER_DIRECT3D 2 +#define UAE_FILTER_OPENGL 3 +#define UAE_FILTER_SCALE2X 4 +#define UAE_FILTER_SUPEREAGLE 5 +#define UAE_FILTER_SUPER2XSAI 6 +#define UAE_FILTER_2XSAI 7 +#define UAE_FILTER_HQ 8 + +#define UAE_FILTER_MODE_16 16 +#define UAE_FILTER_MODE_16_16 16 +#define UAE_FILTER_MODE_16_32 (16 | 8) +#define UAE_FILTER_MODE_32 32 +#define UAE_FILTER_MODE_32_32 32 +#define UAE_FILTER_MODE_32_16 (32 | 8) + + +struct uae_filter +{ + int type; + char *name, *cfgname; + int x[5]; +}; + +extern struct uae_filter uaefilters[]; +extern struct uae_filter *usedfilter; diff --git a/include/fpp-ieee-be.h b/include/fpp-ieee-be.h new file mode 100755 index 00000000..81e67b7b --- /dev/null +++ b/include/fpp-ieee-be.h @@ -0,0 +1,64 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * MC68881 emulation + * Support functions for IEEE compatible host CPUs. + * These functions use a GCC extension (type punning through unions) and + * should only be compiled with compilers that support this. + * + * Copyright 1999 Sam Jordan + */ + +STATIC_INLINE double to_single (uae_u32 value) +{ + union { + float f; + uae_u32 u; + } val; + + val.u = value; + return val.f; +} + +STATIC_INLINE uae_u32 from_single (double src) +{ + union { + float f; + uae_u32 u; + } val; + + val.f = src; + return val.u; +} + +STATIC_INLINE double to_double(uae_u32 wrd1, uae_u32 wrd2) +{ + union { + double d; + uae_u32 u[2]; + } val; + + val.u[0] = wrd1; + val.u[1] = wrd2; + return val.d; +} + +STATIC_INLINE void from_double(double src, uae_u32 * wrd1, uae_u32 * wrd2) +{ + union { + double d; + uae_u32 u[2]; + } val; + + val.d = src; + *wrd1 = val.u[0]; + *wrd2 = val.u[1]; +} + +#define HAVE_from_double +#define HAVE_to_double +#define HAVE_from_single +#define HAVE_to_single + +/* Get the rest of the conversion functions defined. */ +#include "fpp-unknown.h" diff --git a/include/fpp-unknown.h b/include/fpp-unknown.h new file mode 100755 index 00000000..26d5e1ff --- /dev/null +++ b/include/fpp-unknown.h @@ -0,0 +1,139 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * MC68881 emulation + * + * Conversion routines for hosts with unknown floating point format. + * + * Copyright 1996 Herman ten Brugge + */ + +#ifndef HAVE_to_single +STATIC_INLINE double to_single (uae_u32 value) +{ + double frac; + + if ((value & 0x7fffffff) == 0) + return (0.0); + frac = (double) ((value & 0x7fffff) | 0x800000) / 8388608.0; + if (value & 0x80000000) + frac = -frac; + return (ldexp (frac, ((value >> 23) & 0xff) - 127)); +} +#endif + +#ifndef HAVE_from_single +STATIC_INLINE uae_u32 from_single (double src) +{ + int expon; + uae_u32 tmp; + double frac; + + if (src == 0.0) + return 0; + if (src < 0) { + tmp = 0x80000000; + src = -src; + } else { + tmp = 0; + } + frac = frexp (src, &expon); + frac += 0.5 / 16777216.0; + if (frac >= 1.0) { + frac /= 2.0; + expon++; + } + return (tmp | (((expon + 127 - 1) & 0xff) << 23) | + (((int) (frac * 16777216.0)) & 0x7fffff)); +} +#endif + +#ifndef HAVE_to_exten +STATIC_INLINE double to_exten(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) +{ + double frac; + + if ((wrd1 & 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0) + return 0.0; + frac = (double) wrd2 / 2147483648.0 + + (double) wrd3 / 9223372036854775808.0; + if (wrd1 & 0x80000000) + frac = -frac; + return ldexp (frac, ((wrd1 >> 16) & 0x7fff) - 16383); +} +#endif + +#ifndef HAVE_from_exten +STATIC_INLINE void from_exten(double src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3) +{ + int expon; + double frac; + + if (src == 0.0) { + *wrd1 = 0; + *wrd2 = 0; + *wrd3 = 0; + return; + } + if (src < 0) { + *wrd1 = 0x80000000; + src = -src; + } else { + *wrd1 = 0; + } + frac = frexp (src, &expon); + frac += 0.5 / 18446744073709551616.0; + if (frac >= 1.0) { + frac /= 2.0; + expon++; + } + *wrd1 |= (((expon + 16383 - 1) & 0x7fff) << 16); + *wrd2 = (uae_u32) (frac * 4294967296.0); + *wrd3 = (uae_u32) (frac * 18446744073709551616.0 - *wrd2 * 4294967296.0); +} +#endif + +#ifndef HAVE_to_double +STATIC_INLINE double to_double(uae_u32 wrd1, uae_u32 wrd2) +{ + double frac; + + if ((wrd1 & 0x7fffffff) == 0 && wrd2 == 0) + return 0.0; + frac = (double) ((wrd1 & 0xfffff) | 0x100000) / 1048576.0 + + (double) wrd2 / 4503599627370496.0; + if (wrd1 & 0x80000000) + frac = -frac; + return ldexp (frac, ((wrd1 >> 20) & 0x7ff) - 1023); +} +#endif + +#ifndef HAVE_from_double +STATIC_INLINE void from_double(double src, uae_u32 * wrd1, uae_u32 * wrd2) +{ + int expon; + int tmp; + double frac; + + if (src == 0.0) { + *wrd1 = 0; + *wrd2 = 0; + return; + } + if (src < 0) { + *wrd1 = 0x80000000; + src = -src; + } else { + *wrd1 = 0; + } + frac = frexp (src, &expon); + frac += 0.5 / 9007199254740992.0; + if (frac >= 1.0) { + frac /= 2.0; + expon++; + } + tmp = (uae_u32) (frac * 2097152.0); + *wrd1 |= (((expon + 1023 - 1) & 0x7ff) << 20) | (tmp & 0xfffff); + *wrd2 = (uae_u32) (frac * 9007199254740992.0 - tmp * 4294967296.0); +} +#endif diff --git a/include/fsdb.h b/include/fsdb.h new file mode 100755 index 00000000..1c247d4d --- /dev/null +++ b/include/fsdb.h @@ -0,0 +1,114 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Library of functions to make emulated filesystem as independent as + * possible of the host filesystem's capabilities. + * + * Copyright 1999 Bernd Schmidt + */ + +#ifndef FSDB_FILE +#define FSDB_FILE "_UAEFSDB.___" +#endif + +#ifndef FSDB_DIR_SEPARATOR +#define FSDB_DIR_SEPARATOR '/' +#endif + +/* AmigaOS errors */ +#define ERROR_NO_FREE_STORE 103 +#define ERROR_OBJECT_IN_USE 202 +#define ERROR_OBJECT_EXISTS 203 +#define ERROR_DIR_NOT_FOUND 204 +#define ERROR_OBJECT_NOT_AROUND 205 +#define ERROR_ACTION_NOT_KNOWN 209 +#define ERROR_INVALID_LOCK 211 +#define ERROR_OBJECT_WRONG_TYPE 212 +#define ERROR_DISK_WRITE_PROTECTED 214 +#define ERROR_DIRECTORY_NOT_EMPTY 216 +#define ERROR_DEVICE_NOT_MOUNTED 218 +#define ERROR_SEEK_ERROR 219 +#define ERROR_DISK_IS_FULL 221 +#define ERROR_DELETE_PROTECTED 222 +#define ERROR_WRITE_PROTECTED 223 +#define ERROR_READ_PROTECTED 224 +#define ERROR_NO_MORE_ENTRIES 232 +#define ERROR_NOT_IMPLEMENTED 236 + +#define A_FIBF_SCRIPT (1<<6) +#define A_FIBF_PURE (1<<5) +#define A_FIBF_ARCHIVE (1<<4) +#define A_FIBF_READ (1<<3) +#define A_FIBF_WRITE (1<<2) +#define A_FIBF_EXECUTE (1<<1) +#define A_FIBF_DELETE (1<<0) + +/* AmigaOS "keys" */ +typedef struct a_inode_struct { +#ifdef AINO_DEBUG + uae_u32 checksum1; +#endif + /* Circular list of recycleable a_inodes. */ + struct a_inode_struct *next, *prev; + /* This a_inode's relatives in the directory structure. */ + struct a_inode_struct *parent; + struct a_inode_struct *child, *sibling; + /* AmigaOS name, and host OS name. The host OS name is a full path, the + * AmigaOS name is relative to the parent. */ + char *aname; + char *nname; + /* AmigaOS file comment, or NULL if file has none. */ + char *comment; + /* AmigaOS protection bits. */ + int amigaos_mode; + /* Unique number for identification. */ + uae_u32 uniq; + /* For a directory that is being ExNext()ed, the number of child ainos + which must be kept locked in core. */ + unsigned long locked_children; + /* How many ExNext()s are going on in this directory? */ + unsigned long exnext_count; + /* AmigaOS locking bits. */ + int shlock; + long db_offset; + unsigned int dir:1; + unsigned int elock:1; + /* Nonzero if this came from an entry in our database. */ + unsigned int has_dbentry:1; + /* Nonzero if this will need an entry in our database. */ + unsigned int needs_dbentry:1; + /* This a_inode possibly needs writing back to the database. */ + unsigned int dirty:1; + /* If nonzero, this represents a deleted file; the corresponding + * entry in the database must be cleared. */ + unsigned int deleted:1; +#ifdef AINO_DEBUG + uae_u32 checksum2; +#endif +} a_inode; + +extern char *nname_begin (char *); + +extern char *build_nname (const char *d, const char *n); +extern char *build_aname (const char *d, const char *n); + +/* Filesystem-independent functions. */ +extern void fsdb_clean_dir (a_inode *); +extern char *fsdb_search_dir (const char *dirname, char *rel); +extern void fsdb_dir_writeback (a_inode *); +extern int fsdb_used_as_nname (a_inode *base, const char *); +extern a_inode *fsdb_lookup_aino_aname (a_inode *base, const char *); +extern a_inode *fsdb_lookup_aino_nname (a_inode *base, const char *); +extern int fsdb_exists (char *nname); + +STATIC_INLINE int same_aname (const char *an1, const char *an2) +{ + return strcasecmp (an1, an2) == 0; +} + +/* Filesystem-dependent functions. */ +extern int fsdb_name_invalid (const char *n); +extern int fsdb_fill_file_attrs (a_inode *); +extern int fsdb_set_file_attrs (a_inode *, int); +extern int fsdb_mode_representable_p (const a_inode *); +extern char *fsdb_create_unique_nname (a_inode *base, const char *); diff --git a/include/fsusage.h b/include/fsusage.h new file mode 100755 index 00000000..227c5b45 --- /dev/null +++ b/include/fsusage.h @@ -0,0 +1,37 @@ +/* fsusage.h -- declarations for filesystem space usage info + Copyright (C) 1991, 1992 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Space usage statistics for a filesystem. Blocks are 512-byte. */ +struct fs_usage +{ + long fsu_blocks; /* Total blocks. */ + long fsu_bfree; /* Free blocks available to superuser. */ + long fsu_bavail; /* Free blocks available to non-superuser. */ + long fsu_files; /* Total file nodes. */ + long fsu_ffree; /* Free file nodes. */ +}; + +#ifndef __P +#if defined (__GNUC__) || (defined (__STDC__) && __STDC__) +#define __P(args) args +#else +#define __P(args) () +#endif /* GCC. */ +#endif /* Not __P. */ + +int get_fs_usage __P ((const char *path, const char *disk, + struct fs_usage *fsp)); diff --git a/include/genblitter.h b/include/genblitter.h new file mode 100755 index 00000000..3b333feb --- /dev/null +++ b/include/genblitter.h @@ -0,0 +1,15 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Optimized blitter minterm function generator + * + * Copyright 1995,1996 Bernd Schmidt + * Copyright 1996 Alessandro Bissacco + */ + +struct blitop { + const char *s; + int used; +}; + +extern struct blitop blitops[256]; diff --git a/include/gensound.h b/include/gensound.h new file mode 100755 index 00000000..82a05652 --- /dev/null +++ b/include/gensound.h @@ -0,0 +1,38 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Prototypes for general sound related functions + * This use to be called sound.h, but that causes confusion + * + * Copyright 1997 Bernd Schmidt + */ + +extern int sound_available; + +extern void (*sample_handler) (void); +/* sample_evtime is in normal Amiga cycles; scaled_sample_evtime is in our + event cycles. scaled_sample_evtime_ok is set to 1 by init_sound if the + port understands scaled_sample_evtime and set it to something sensible. */ +extern unsigned long sample_evtime, scaled_sample_evtime; +extern int scaled_sample_evtime_ok; + +/* Determine if we can produce any sound at all. This can be only a guess; + * if unsure, say yes. Any call to init_sound may change the value. */ +extern int setup_sound (void); + +extern int init_sound (void); +extern void close_sound (void); + +extern void sample16_handler (void); +extern void sample16i_rh_handler (void); +extern void sample16i_crux_handler (void); +extern void sample8_handler (void); +extern void sample16s_handler (void); +extern void sample16ss_handler (void); +extern void sample16si_rh_handler (void); +extern void sample16si_crux_handler (void); +extern void sample8s_handler (void); +extern void sample_ulaw_handler (void); +extern void init_sound_table16 (void); +extern void init_sound_table8 (void); + diff --git a/include/gfxfilter.h b/include/gfxfilter.h new file mode 100755 index 00000000..17708208 --- /dev/null +++ b/include/gfxfilter.h @@ -0,0 +1,60 @@ + +#ifdef GFXFILTER + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long u32; + +extern void S2X_refresh (void); +extern void S2X_render (void); +extern void S2X_init (int dw, int dh, int aw, int ah, int mult, int ad, int dd); + +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned long uint32; +typedef int bool; + +extern void S2X_configure (int rb, int gb, int bb, int rs, int gs, int bs); +extern int Init_2xSaI(int rb, int gb, int bb, int rs, int gs, int bs); +extern void Super2xSaI(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height); +extern void SuperEagle(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height); +extern void _2xSaI(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height); +extern void AdMame2x(u8 *srcPtr, u32 srcPitch, /* u8 deltaPtr, */ + u8 *dstPtr, u32 dstPitch, int width, int height); +extern void AdMame2x32(u8 *srcPtr, u32 srcPitch, /* u8 deltaPtr, */ + u8 *dstPtr, u32 dstPitch, int width, int height); + +extern void hq_init(int rb, int gb, int bb, int rs, int gs, int bs); +extern void hq2x_32(unsigned char*, unsigned char*, int, int, int, int, int); +extern void hq3x_32(unsigned char*, unsigned char*, int, int, int, int, int); +extern void hq3x_16(unsigned char*, unsigned char*, int, int, int, int, int); +extern void hq4x_32(unsigned char*, unsigned char*, int, int, int, int, int); + +#define UAE_FILTER_NULL 1 +#define UAE_FILTER_DIRECT3D 2 +#define UAE_FILTER_OPENGL 3 +#define UAE_FILTER_SCALE2X 4 +#define UAE_FILTER_SUPEREAGLE 5 +#define UAE_FILTER_SUPER2XSAI 6 +#define UAE_FILTER_2XSAI 7 +#define UAE_FILTER_HQ 8 + +#define UAE_FILTER_MODE_16 16 +#define UAE_FILTER_MODE_16_16 16 +#define UAE_FILTER_MODE_16_32 (16 | 8) +#define UAE_FILTER_MODE_32 32 +#define UAE_FILTER_MODE_32_32 32 +#define UAE_FILTER_MODE_32_16 (32 | 8) + + +struct uae_filter +{ + int type; + char *name, *cfgname; + int x[5]; +}; + +extern struct uae_filter uaefilters[]; +extern struct uae_filter *usedfilter; + +#endif diff --git a/include/gui.h b/include/gui.h new file mode 100755 index 00000000..6f78f0c4 --- /dev/null +++ b/include/gui.h @@ -0,0 +1,43 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Interface to the Tcl/Tk GUI + * + * Copyright 1996 Bernd Schmidt + */ + +extern int gui_init (void); +extern int gui_update (void); +extern void gui_exit (void); +extern void gui_led (int, int); +extern void gui_handle_events (void); +extern void gui_filename (int, const char *); +extern void gui_fps (int fps, int idle); +extern void gui_changesettings (void); +extern void gui_lock (void); +extern void gui_unlock (void); +extern void gui_hd_led (int); +extern void gui_cd_led (int); +extern unsigned int gui_ledstate; +extern void gui_display(int shortcut); + +extern int no_gui; + +struct gui_info +{ + uae_u8 drive_motor[4]; /* motor on off */ + uae_u8 drive_track[4]; /* rw-head track */ + uae_u8 drive_writing[4]; /* drive is writing */ + uae_u8 drive_disabled[4]; /* drive is disabled */ + uae_u8 powerled; /* state of power led */ + uae_u8 drive_side; /* floppy side */ + uae_u8 hd; /* harddrive */ + uae_u8 cd; /* CD */ + int fps, idle; +}; +#define NUM_LEDS (1 + 1 + 1 + 1 + 1 + 4) + +extern struct gui_info gui_data; + +/* Functions to be called when prefs are changed by non-gui code. */ +extern void gui_update_gfx (void); diff --git a/include/identify.h b/include/identify.h new file mode 100755 index 00000000..4da9bb84 --- /dev/null +++ b/include/identify.h @@ -0,0 +1,25 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Tables for labelling amiga internals. + * + */ + +struct mem_labels +{ + const char *name; + uae_u32 adr; +}; + +struct customData +{ + const char *name; + uae_u32 adr; +}; + + +extern struct mem_labels mem_labels[]; +extern struct mem_labels int_labels[]; +extern struct mem_labels trap_labels[]; +extern struct customData custd[]; + diff --git a/include/inputdevice.h b/include/inputdevice.h new file mode 100755 index 00000000..3ddbfdee --- /dev/null +++ b/include/inputdevice.h @@ -0,0 +1,129 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Joystick, mouse and keyboard emulation prototypes and definitions + * + * Copyright 1995 Bernd Schmidt + * Copyright 2001-2002 Toni Wilen + */ + + +#define IDTYPE_JOYSTICK 0 +#define IDTYPE_MOUSE 1 +#define IDTYPE_KEYBOARD 2 + +struct inputdevice_functions { + int (*init)(void); + void (*close)(void); + int (*acquire)(int,int); + void (*unacquire)(int); + void (*read)(void); + int (*get_num)(void); + char* (*get_name)(int); + int (*get_widget_num)(int); + int (*get_widget_type)(int,int,char*,uae_u32*); + int (*get_widget_first)(int,int); +}; +extern struct inputdevice_functions idev[3]; +extern struct inputdevice_functions inputdevicefunc_joystick; +extern struct inputdevice_functions inputdevicefunc_mouse; +extern struct inputdevice_functions inputdevicefunc_keyboard; +extern int pause_emulation; + +struct uae_input_device_kbr_default { + int scancode; + int event; +}; + +#define IDEV_WIDGET_NONE 0 +#define IDEV_WIDGET_BUTTON 1 +#define IDEV_WIDGET_AXIS 2 +#define IDEV_WIDGET_KEY 3 + +#define IDEV_MAPPED_AUTOFIRE_POSSIBLE 1 +#define IDEV_MAPPED_AUTOFIRE_SET 2 + +#define ID_BUTTON_OFFSET 0 +#define ID_BUTTON_TOTAL 32 +#define ID_AXIS_OFFSET 32 +#define ID_AXIS_TOTAL 32 + +extern int inputdevice_iterate (int devnum, int num, char *name, int *af); +extern int inputdevice_set_mapping (int devnum, int num, char *name, int af, int sub); +extern int inputdevice_get_mapped_name (int devnum, int num, int *pflags, char *name, int sub); +extern void inputdevice_copyconfig (struct uae_prefs *src, struct uae_prefs *dst); +extern void inputdevice_copy_single_config (struct uae_prefs *p, int src, int dst, int devnum); +extern void inputdevice_swap_ports (struct uae_prefs *p, int devnum); +extern void inputdevice_config_change (void); +extern int inputdevice_config_change_test (void); +extern int inputdevice_get_device_index (int devnum); +extern char *inputdevice_get_device_name (int type, int devnum); +extern int inputdevice_get_device_status (int devnum); +extern void inputdevice_set_device_status (int devnum, int enabled); +extern int inputdevice_get_device_total (int type); +extern int inputdevice_get_widget_num (int devnum); +extern int inputdevice_get_widget_type (int devnum, int num, char *name); + +extern void input_get_default_mouse (struct uae_input_device *uid); +extern void input_get_default_joystick (struct uae_input_device *uid); + +#define DEFEVENT(A, B, C, D, E, F) INPUTEVENT_ ## A, +enum inputevents { +INPUTEVENT_ZERO, +#include "inputevents.def" +INPUTEVENT_END +}; +#undef DEFEVENT + +enum mousestate { mousehack_unknown, mousehack_normal, mousehack_dontcare, mousehack_follow }; + +extern void handle_cd32_joystick_cia (uae_u8, uae_u8); +extern uae_u8 handle_parport_joystick (int port, uae_u8 pra, uae_u8 dra); +extern uae_u8 handle_joystick_buttons (uae_u8); +extern int getbuttonstate (int joy, int button); +extern int getjoystate (int joy); + +extern void mousehack_set (enum mousestate); +extern uae_u32 mousehack_helper (void); +extern void mousehack_handle (int sprctl, int sprpos); + +extern void setmousebuttonstateall (int mouse, uae_u32 buttonbits, uae_u32 buttonmask); +extern void setjoybuttonstateall (int joy, uae_u32 buttonbits, uae_u32 buttonmask); +extern void setjoybuttonstate (int joy, int button, int state); +extern void setmousebuttonstate (int mouse, int button, int state); +extern void setjoystickstate (int joy, int axle, int state, int max); +void setmousestate (int mouse, int axis, int data, int isabs); +extern void inputdevice_updateconfig (struct uae_prefs *prefs); + +extern int inputdevice_translatekeycode (int keyboard, int scancode, int state); +extern void inputdevice_setkeytranslation (struct uae_input_device_kbr_default *trans); +extern void handle_input_event (int nr, int state, int max, int autofire); +extern void inputdevice_do_keyboard (int code, int state); + +extern uae_u16 potgo_value; +extern uae_u16 POTGOR (void); +extern void POTGO (uae_u16 v); +extern uae_u16 POT0DAT (void); +extern uae_u16 POT1DAT (void); +extern void JOYTEST (uae_u16 v); +extern uae_u16 JOY0DAT (void); +extern uae_u16 JOY1DAT (void); + +extern void inputdevice_vsync (void); +extern void inputdevice_hsync (void); + +extern void write_inputdevice_config (struct uae_prefs *p, FILE *f); +extern void read_inputdevice_config (struct uae_prefs *p, char *option, char *value); +extern void reset_inputdevice_config (struct uae_prefs *pr); + +extern void inputdevice_init (void); +extern void inputdevice_close (void); +extern void inputdevice_default_prefs (struct uae_prefs *p); + +extern void inputdevice_acquire (int); +extern void inputdevice_unacquire (void); + +extern void indicator_leds (int num, int state); + +extern void warpmode (int mode); +extern void pausemode (int mode); diff --git a/include/keyboard.h b/include/keyboard.h new file mode 100755 index 00000000..dd1b4b0c --- /dev/null +++ b/include/keyboard.h @@ -0,0 +1,139 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Amiga keycodes + * + * (c) 1995 Bernd Schmidt + */ + +/* First, two dummies */ +#define AK_mousestuff 0x100 +#define AK_inhibit 0x101 +/* This mutates into AK_CTRL in keybuf.c. */ +#define AK_RCTRL 0x7f + +#define AK_A 0x20 +#define AK_B 0x35 +#define AK_C 0x33 +#define AK_D 0x22 +#define AK_E 0x12 +#define AK_F 0x23 +#define AK_G 0x24 +#define AK_H 0x25 +#define AK_I 0x17 +#define AK_J 0x26 +#define AK_K 0x27 +#define AK_L 0x28 +#define AK_M 0x37 +#define AK_N 0x36 +#define AK_O 0x18 +#define AK_P 0x19 +#define AK_Q 0x10 +#define AK_R 0x13 +#define AK_S 0x21 +#define AK_T 0x14 +#define AK_U 0x16 +#define AK_V 0x34 +#define AK_W 0x11 +#define AK_X 0x32 +#define AK_Y 0x15 +#define AK_Z 0x31 + +#define AK_0 0x0A +#define AK_1 0x01 +#define AK_2 0x02 +#define AK_3 0x03 +#define AK_4 0x04 +#define AK_5 0x05 +#define AK_6 0x06 +#define AK_7 0x07 +#define AK_8 0x08 +#define AK_9 0x09 + +#define AK_NP0 0x0F +#define AK_NP1 0x1D +#define AK_NP2 0x1E +#define AK_NP3 0x1F +#define AK_NP4 0x2D +#define AK_NP5 0x2E +#define AK_NP6 0x2F +#define AK_NP7 0x3D +#define AK_NP8 0x3E +#define AK_NP9 0x3F + +#define AK_NPDIV 0x5C +#define AK_NPMUL 0x5D +#define AK_NPSUB 0x4A +#define AK_NPADD 0x5E +#define AK_NPDEL 0x3C +#define AK_NPLPAREN 0x5A +#define AK_NPRPAREN 0x5B + +#define AK_F1 0x50 +#define AK_F2 0x51 +#define AK_F3 0x52 +#define AK_F4 0x53 +#define AK_F5 0x54 +#define AK_F6 0x55 +#define AK_F7 0x56 +#define AK_F8 0x57 +#define AK_F9 0x58 +#define AK_F10 0x59 + +#define AK_UP 0x4C +#define AK_DN 0x4D +#define AK_LF 0x4F +#define AK_RT 0x4E + +#define AK_SPC 0x40 +#define AK_BS 0x41 +#define AK_TAB 0x42 +#define AK_ENT 0x43 +#define AK_RET 0x44 +#define AK_ESC 0x45 +#define AK_DEL 0x46 + +#define AK_LSH 0x60 +#define AK_RSH 0x61 +#define AK_CAPSLOCK 0x62 +#define AK_CTRL 0x63 +#define AK_LALT 0x64 +#define AK_RALT 0x65 +#define AK_LAMI 0x66 +#define AK_RAMI 0x67 +#define AK_HELP 0x5F + +/* The following have different mappings on national keyboards */ + +#define AK_LBRACKET 0x1A +#define AK_RBRACKET 0x1B +#define AK_SEMICOLON 0x29 +#define AK_COMMA 0x38 +#define AK_PERIOD 0x39 +#define AK_SLASH 0x3A +#define AK_BACKSLASH 0x0D +#define AK_QUOTE 0x2A +#define AK_NUMBERSIGN 0x2B +#define AK_LTGT 0x30 +#define AK_BACKQUOTE 0x00 +#define AK_MINUS 0x0B +#define AK_EQUAL 0x0C + +#define AK_RESETWARNING 0x78 +#define AK_INIT_POWERUP 0xfd +#define AK_TERM_POWERUP 0xfe + +// KB LED stuff + +#define KBLED_NUMLOCK 1 +#define KBLED_CAPSLOCK 2 +#define KBLED_SCROLLLOCK 4 + +enum aks { AKS_ENTERGUI = 0x200, AKS_SCREENSHOT, AKS_FREEZEBUTTON, + AKS_FLOPPY0, AKS_FLOPPY1, AKS_FLOPPY2, AKS_FLOPPY3, + AKS_EFLOPPY0, AKS_EFLOPPY1, AKS_EFLOPPY2, AKS_EFLOPPY3, + AKS_TOGGLEFULLSCREEN, AKS_ENTERDEBUGGER, AKS_IRQ7, + AKS_PAUSE, AKS_WARP, AKS_INHIBITSCREEN, AKS_STATEREWIND, + AKS_VOLDOWN, AKS_VOLUP, AKS_VOLMUTE, AKS_QUIT, + AKS_STATESAVE, AKS_STATERESTORE +}; diff --git a/include/keybuf.h b/include/keybuf.h new file mode 100755 index 00000000..65e3cb20 --- /dev/null +++ b/include/keybuf.h @@ -0,0 +1,16 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Keyboard buffer. Not really needed for X, but for SVGAlib and possibly + * Mac and DOS ports. + * + * (c) 1996 Bernd Schmidt + */ + +extern int get_next_key (void); +extern int keys_available (void); +extern void record_key (int); +extern void keybuf_init (void); +extern void joystick_setting_changed (void); +extern int getcapslockstate (void); +extern void setcapslockstate (int); \ No newline at end of file diff --git a/include/mackbd.h b/include/mackbd.h new file mode 100755 index 00000000..bbd5764c --- /dev/null +++ b/include/mackbd.h @@ -0,0 +1,109 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Mac keycodes + * + * (c) 1996 Ernesto Corvi + */ + +#define kUpArrowKeyMap 0x7E /* key map offset for up arrow */ +#define kDownArrowKeyMap 0x7D /* key map offset for down arrow */ +#define kRightArrowKeyMap 0x7C /* key map offset for right arrow */ +#define kLeftArrowKeyMap 0x7B /* key map offset for left arrow */ + +#define kBackSpaceKeyMap 0x33 +#define kReturnKeyMap 0x24 +#define kEscapeKeyMap 0x35 +#define kLBracketKeyMap 0x21 +#define kRBracketKeyMap 0x1E +#define kCommaKeyMap 0x2B +#define kSlashKeyMap 0x2C +#define kSemiColonKeyMap 0x29 +#define kMinusKeyMap 0x1B +#define kEqualKeyMap 0x18 +#define kQuoteKeyMap 0x27 + +#define k0KeyMap 0x1D +#define k1KeyMap 0x12 +#define k2KeyMap 0x13 +#define k3KeyMap 0x14 +#define k4KeyMap 0x15 +#define k5KeyMap 0x17 +#define k6KeyMap 0x16 +#define k7KeyMap 0x1A +#define k8KeyMap 0x1C +#define k9KeyMap 0x19 + +#define kAKeyMap 0x00 +#define kBKeyMap 0x0B +#define kCKeyMap 0x08 +#define kDKeyMap 0x02 +#define kEKeyMap 0x0E +#define kFKeyMap 0x03 +#define kGKeyMap 0x05 +#define kHKeyMap 0x04 +#define kIKeyMap 0x22 +#define kJKeyMap 0x26 +#define kKKeyMap 0x28 +#define kLKeyMap 0x25 +#define kMKeyMap 0x2E +#define kNKeyMap 0x2D +#define kOKeyMap 0x1F +#define kPKeyMap 0x23 +#define kQKeyMap 0x0C +#define kRKeyMap 0x0F +#define kSKeyMap 0x01 +#define kTKeyMap 0x11 +#define kUKeyMap 0x20 +#define kVKeyMap 0x09 +#define kWKeyMap 0x0D +#define kXKeyMap 0x07 +#define kYKeyMap 0x10 +#define kZKeyMap 0x06 +#define kPeriodKeyMap 0x2F +#define kCommandKeyMap 0x37 +#define kSpaceBarMap 0x31 +#define kTabKeyMap 0x30 +#define kControlKeyMap 0x3B +#define kOptionKeyMap 0x3A +#define kCapsLockKeyMap 0x39 +#define kShiftKeyMap 0x38 +#define kPgUpKeyMap 0x74 +#define kPgDnKeyMap 0x79 +#define kBackSlash 0x2A + + +#define kF1KeyMap 0x7A +#define kF2KeyMap 0x78 +#define kF3KeyMap 0x63 +#define kF4KeyMap 0x76 +#define kF5KeyMap 0x60 +#define kF6KeyMap 0x61 +#define kF7KeyMap 0x62 +#define kF8KeyMap 0x64 +#define kF9KeyMap 0x65 +#define kF10KeyMap 0x6D +#define kF11KeyMap 0x67 +#define kF12KeyMap 0x6F + +#define kShiftRawKey 0x3F +#define kControlRawKey 0x3C +#define kOptionRawKey 0x3D +#define kCapsRawKey 0x3E +#define kCommandRawKey 0x30 +#define kUpRawKey 0x79 +#define kDownRawKey 0x7A +#define kLeftRawKey 0x7C +#define kRightRawKey 0x7B +#define kSpaceRawKey 0x36 + +#define kKP0KeyMap 0x52 +#define kKP1KeyMap 0x53 +#define kKP2KeyMap 0x54 +#define kKP3KeyMap 0x55 +#define kKP4KeyMap 0x56 +#define kKP5KeyMap 0x57 +#define kKP6KeyMap 0x58 +#define kKP7KeyMap 0x59 +#define kKP8KeyMap 0x5B +#define kKP9KeyMap 0x5C diff --git a/include/memory.h b/include/memory.h new file mode 100755 index 00000000..ffe4db1b --- /dev/null +++ b/include/memory.h @@ -0,0 +1,240 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * memory management + * + * Copyright 1995 Bernd Schmidt + */ + +extern void memory_reset (void); +extern void a1000_reset (void); + +#ifdef JIT +extern int special_mem; +#define S_READ 1 +#define S_WRITE 2 +extern void *cache_alloc (int); +extern void cache_free (void*); +#endif + +typedef uae_u32 (*mem_get_func)(uaecptr) REGPARAM; +typedef void (*mem_put_func)(uaecptr, uae_u32) REGPARAM; +typedef uae_u8 *(*xlate_func)(uaecptr) REGPARAM; +typedef int (*check_func)(uaecptr, uae_u32) REGPARAM; + +extern char *address_space, *good_address_map; +extern uae_u8 *chipmemory; + +extern uae_u32 allocated_chipmem; +extern uae_u32 allocated_fastmem; +extern uae_u32 allocated_bogomem; +extern uae_u32 allocated_gfxmem; +extern uae_u32 allocated_z3fastmem; +extern uae_u32 allocated_a3000mem; + +extern uae_u32 wait_cpu_cycle_read (uaecptr addr, int mode); +extern uae_u32 wait_cpu_cycle_read_cycles (uaecptr addr, int mode, int *cycles); +extern void wait_cpu_cycle_write (uaecptr addr, int mode, uae_u32 v); + +#undef DIRECT_MEMFUNCS_SUCCESSFUL +#include "machdep/maccess.h" + +#ifndef CAN_MAP_MEMORY +#undef USE_COMPILER +#endif + +#ifdef JIT +#if defined(USE_COMPILER) && !defined(USE_MAPPED_MEMORY) +#define USE_MAPPED_MEMORY +#endif +#endif + +#define kickmem_size 0x080000 + +#define chipmem_start 0x00000000 +#define bogomem_start 0x00C00000 +#define a3000mem_start 0x07000000 +#define kickmem_start 0x00F80000 + +extern int ersatzkickfile; +extern int cloanto_rom; +extern uae_u16 kickstart_version; + +extern uae_u8* baseaddr[]; + +typedef struct { + /* These ones should be self-explanatory... */ + mem_get_func lget, wget, bget; + mem_put_func lput, wput, bput; + /* Use xlateaddr to translate an Amiga address to a uae_u8 * that can + * be used to address memory without calling the wget/wput functions. + * This doesn't work for all memory banks, so this function may call + * abort(). */ + xlate_func xlateaddr; + /* To prevent calls to abort(), use check before calling xlateaddr. + * It checks not only that the memory bank can do xlateaddr, but also + * that the pointer points to an area of at least the specified size. + * This is used for example to translate bitplane pointers in custom.c */ + check_func check; + /* For those banks that refer to real memory, we can save the whole trouble + of going through function calls, and instead simply grab the memory + ourselves. This holds the memory address where the start of memory is + for this particular bank. */ + uae_u8 *baseaddr; +} addrbank; + +extern uae_u8 *filesysory; +extern uae_u8 *rtarea; + +extern addrbank chipmem_bank; +extern addrbank chipmem_bank_ce2; +extern addrbank kickmem_bank; +extern addrbank custom_bank; +extern addrbank clock_bank; +extern addrbank cia_bank; +extern addrbank rtarea_bank; +extern addrbank expamem_bank; +extern addrbank fastmem_bank; +extern addrbank gfxmem_bank; + +extern void rtarea_init (void); +extern void rtarea_setup (void); +extern void expamem_init (void); +extern void expamem_reset (void); + +extern uae_u32 gfxmem_start; +extern uae_u8 *gfxmemory; +extern uae_u32 gfxmem_mask; +extern int address_space_24; + +/* Default memory access functions */ + +extern int default_check(uaecptr addr, uae_u32 size) REGPARAM; +extern uae_u8 *default_xlate(uaecptr addr) REGPARAM; + +#define bankindex(addr) (((uaecptr)(addr)) >> 16) + +extern addrbank *mem_banks[65536]; +extern uae_u8 *baseaddr[65536]; +#define get_mem_bank(addr) (*mem_banks[bankindex(addr)]) +#define put_mem_bank(addr, b, realstart) do { \ + (mem_banks[bankindex(addr)] = (b)); \ + if ((b)->baseaddr) \ + baseaddr[bankindex(addr)] = (b)->baseaddr - (realstart); \ + else \ + baseaddr[bankindex(addr)] = (uae_u8*)(((long)b)+1); \ +} while (0) + +extern void memory_init (void); +extern void memory_cleanup (void); +extern void map_banks (addrbank *bank, int first, int count, int realsize); +extern void map_overlay (int chip); + +#ifndef NO_INLINE_MEMORY_ACCESS + +#define longget(addr) (call_mem_get_func(get_mem_bank(addr).lget, addr)) +#define wordget(addr) (call_mem_get_func(get_mem_bank(addr).wget, addr)) +#define byteget(addr) (call_mem_get_func(get_mem_bank(addr).bget, addr)) +#define longput(addr,l) (call_mem_put_func(get_mem_bank(addr).lput, addr, l)) +#define wordput(addr,w) (call_mem_put_func(get_mem_bank(addr).wput, addr, w)) +#define byteput(addr,b) (call_mem_put_func(get_mem_bank(addr).bput, addr, b)) + +#else + +extern uae_u32 alongget(uaecptr addr); +extern uae_u32 awordget(uaecptr addr); +extern uae_u32 longget(uaecptr addr); +extern uae_u32 wordget(uaecptr addr); +extern uae_u32 byteget(uaecptr addr); +extern void longput(uaecptr addr, uae_u32 l); +extern void wordput(uaecptr addr, uae_u32 w); +extern void byteput(uaecptr addr, uae_u32 b); + +#endif + +#ifndef MD_HAVE_MEM_1_FUNCS + +#define longget_1 longget +#define wordget_1 wordget +#define byteget_1 byteget +#define longput_1 longput +#define wordput_1 wordput +#define byteput_1 byteput + +#endif + +STATIC_INLINE uae_u32 get_long(uaecptr addr) +{ + return longget_1(addr); +} +STATIC_INLINE uae_u32 get_word(uaecptr addr) +{ + return wordget_1(addr); +} +STATIC_INLINE uae_u32 get_byte(uaecptr addr) +{ + return byteget_1(addr); +} +STATIC_INLINE void put_long(uaecptr addr, uae_u32 l) +{ + longput_1(addr, l); +} +STATIC_INLINE void put_word(uaecptr addr, uae_u32 w) +{ + wordput_1(addr, w); +} +STATIC_INLINE void put_byte(uaecptr addr, uae_u32 b) +{ + byteput_1(addr, b); +} + +STATIC_INLINE uae_u8 *get_real_address(uaecptr addr) +{ + return get_mem_bank(addr).xlateaddr(addr); +} + +STATIC_INLINE int valid_address(uaecptr addr, uae_u32 size) +{ + return get_mem_bank(addr).check(addr, size); +} + +/* For faster access in custom chip emulation. */ +extern uae_u32 chipmem_lget (uaecptr) REGPARAM; +extern uae_u32 chipmem_wget (uaecptr) REGPARAM; +extern uae_u32 chipmem_bget (uaecptr) REGPARAM; +extern void chipmem_lput (uaecptr, uae_u32) REGPARAM; +extern void chipmem_wput (uaecptr, uae_u32) REGPARAM; +extern void chipmem_bput (uaecptr, uae_u32) REGPARAM; + +extern uae_u32 chipmem_mask, kickmem_mask; +extern uae_u8 *kickmemory; +extern addrbank dummy_bank; + +/* 68020+ Chip RAM DMA contention emulation */ +extern uae_u32 chipmem_lget_ce2 (uaecptr) REGPARAM; +extern uae_u32 chipmem_wget_ce2 (uaecptr) REGPARAM; +extern uae_u32 chipmem_bget_ce2 (uaecptr) REGPARAM; +extern void chipmem_lput_ce2 (uaecptr, uae_u32) REGPARAM; +extern void chipmem_wput_ce2 (uaecptr, uae_u32) REGPARAM; +extern void chipmem_bput_c2 (uaecptr, uae_u32) REGPARAM; + +#ifdef NATMEM_OFFSET + +typedef struct shmpiece_reg { + uae_u8 *native_address; + int id; + uae_u32 size; + struct shmpiece_reg *next; + struct shmpiece_reg *prev; +} shmpiece; + +extern shmpiece *shm_start; + +#endif + +extern int canbang; + +extern uae_u8 *mapped_malloc (size_t, char *); +extern void mapped_free (uae_u8 *); +extern void clearexec (void); +extern void mapkick (void); \ No newline at end of file diff --git a/include/native2amiga.h b/include/native2amiga.h new file mode 100755 index 00000000..ca986dd0 --- /dev/null +++ b/include/native2amiga.h @@ -0,0 +1,56 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Call (some) Amiga Exec functions outside the main UAE thread + * and without stack magic. + * + * Copyright 1999 Patrick Ohly + * + * Uses the EXTER interrupt that is setup in filesys.c + * and some of it needs thread support. + */ + +/* + * The following functions do exactly the same thing as their + * Amiga counterpart, but can be called in situation where calling + * the exec.library functions is impossible. + */ +#ifdef SUPPORT_THREADS +void uae_Cause(uaecptr interrupt); +void uae_ReplyMsg(uaecptr msg); +void uae_PutMsg(uaecptr port, uaecptr msg); +void uae_Signal(uaecptr task, uae_u32 mask); +void uae_NotificationHack(uaecptr, uaecptr); +#endif +void uae_NewList(uaecptr list); + +/* + * The following functions are shortcuts for calling + * the exec.library function with CallLib(), so they + * are only available in a trap function. This trap + * function has to be setup with deftrap2() and + * TRAPFLAG_EXTRA_STACK and stack magic is required. + */ +uaecptr uae_AllocMem (uae_u32 size, uae_u32 flags); +void uae_FreeMem (uaecptr memory, uae_u32 size); + + +/* + * to be called when setting up the hardware + */ +void native2amiga_install (void); + +/* + * to be called when the Amiga boots, i.e. by filesys_diagentry() + */ +void native2amiga_startup (void); + +/**** internal stuff ****/ +#ifdef SUPPORT_THREADS +/* This pipe is filled by Signal() with pairs of + * (uae_u32)0/(uaecptr)task/(uae_u32)signal_set, + * by PutMsg() with (uae_u32)1/(uaecptr)port/(uaecptr)msg and by + * ReplyMsg() with (uae_u32)2/(uaecptr)msg. + * It's emptied via exter_int_helper by the EXTER interrupt. */ +extern smp_comm_pipe native2amiga_pending; +#endif diff --git a/include/newcpu.h b/include/newcpu.h new file mode 100755 index 00000000..379b00f5 --- /dev/null +++ b/include/newcpu.h @@ -0,0 +1,300 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * MC68000 emulation + * + * Copyright 1995 Bernd Schmidt + */ + +#include "readcpu.h" +#include "machdep/m68k.h" +#include "events.h" + +#ifndef SET_CFLG + +#define SET_CFLG(x) (CFLG = (x)) +#define SET_NFLG(x) (NFLG = (x)) +#define SET_VFLG(x) (VFLG = (x)) +#define SET_ZFLG(x) (ZFLG = (x)) +#define SET_XFLG(x) (XFLG = (x)) + +#define GET_CFLG CFLG +#define GET_NFLG NFLG +#define GET_VFLG VFLG +#define GET_ZFLG ZFLG +#define GET_XFLG XFLG + +#define CLEAR_CZNV do { \ + SET_CFLG (0); \ + SET_ZFLG (0); \ + SET_NFLG (0); \ + SET_VFLG (0); \ +} while (0) + +#define COPY_CARRY (SET_XFLG (GET_CFLG)) +#endif + +extern int areg_byteinc[]; +extern int imm8_table[]; + +extern int movem_index1[256]; +extern int movem_index2[256]; +extern int movem_next[256]; + +#ifdef FPUEMU +extern int fpp_movem_index1[256]; +extern int fpp_movem_index2[256]; +extern int fpp_movem_next[256]; +#endif + +extern int broken_in; + +typedef unsigned long cpuop_func (uae_u32) REGPARAM; + +struct cputbl { + cpuop_func *handler; + int specific; + uae_u32 opcode; +}; + +extern unsigned long op_illg (uae_u32) REGPARAM; + +typedef char flagtype; + +#ifdef FPUEMU +/* You can set this to long double to be more accurate. However, the + resulting alignment issues will cost a lot of performance in some + apps */ +#define USE_LONG_DOUBLE 0 + +#if USE_LONG_DOUBLE +typedef long double fptype; +#else +typedef double fptype; +#endif +#endif + +extern struct regstruct +{ + uae_u32 regs[16]; + uaecptr usp,isp,msp; + uae_u16 sr; + flagtype t1; + flagtype t0; + flagtype s; + flagtype m; + flagtype x; + flagtype stopped; + int intmask; + + uae_u32 pc; + uae_u8 *pc_p; + uae_u8 *pc_oldp; + + uae_u32 vbr,sfc,dfc; + +#ifdef FPUEMU + fptype fp[8]; + fptype fp_result; + + uae_u32 fpcr,fpsr,fpiar; + uae_u32 fpsr_highbyte; +#endif + + uae_u32 spcflags; + uae_u32 kick_mask; + uae_u32 address_space_mask; + + uae_u16 irc; + uae_u16 ir; + + uae_u8 panic; + uae_u32 panic_pc, panic_addr; + +} regs, lastint_regs; + +typedef struct { + uae_u16* location; + uae_u8 cycles; + uae_u8 specmem; + uae_u8 dummy2; + uae_u8 dummy3; +} cpu_history; + +struct blockinfo_t; + +typedef union { + cpuop_func* handler; + struct blockinfo_t* bi; +} cacheline; + +extern signed long pissoff; + +STATIC_INLINE uae_u32 munge24(uae_u32 x) +{ + return x & regs.address_space_mask; +} + +extern unsigned long irqcycles[15]; +extern int irqdelay[15]; + +STATIC_INLINE void set_special (uae_u32 x) +{ + regs.spcflags |= x; + cycles_do_special(); +} + +STATIC_INLINE void unset_special (uae_u32 x) +{ + regs.spcflags &= ~x; +} + +#define m68k_dreg(r,num) ((r).regs[(num)]) +#define m68k_areg(r,num) (((r).regs + 8)[(num)]) + +#if !defined USE_COMPILER +STATIC_INLINE void m68k_setpc (uaecptr newpc) +{ + regs.pc_p = regs.pc_oldp = get_real_address (newpc); + regs.pc = newpc; +} +#else +extern void m68k_setpc (uaecptr newpc); +#endif + +STATIC_INLINE uaecptr m68k_getpc (void) +{ + return regs.pc + ((char *)regs.pc_p - (char *)regs.pc_oldp); +} + +STATIC_INLINE uaecptr m68k_getpc_p (uae_u8 *p) +{ + return regs.pc + ((char *)p - (char *)regs.pc_oldp); +} + +#define get_ibyte(o) do_get_mem_byte((uae_u8 *)(regs.pc_p + (o) + 1)) +#define get_iword(o) do_get_mem_word((uae_u16 *)(regs.pc_p + (o))) +#define get_ilong(o) do_get_mem_long((uae_u32 *)(regs.pc_p + (o))) + +#define m68k_incpc(o) (regs.pc_p += (o)) + +/* These are only used by the 68020/68881 code, and therefore don't + * need to handle prefetch. */ +STATIC_INLINE uae_u32 next_ibyte (void) +{ + uae_u32 r = get_ibyte (0); + m68k_incpc (2); + return r; +} + +STATIC_INLINE uae_u32 next_iword (void) +{ + uae_u32 r = get_iword (0); + m68k_incpc (2); + return r; +} + +STATIC_INLINE uae_u32 next_ilong (void) +{ + uae_u32 r = get_ilong (0); + m68k_incpc (4); + return r; +} + +#ifdef USE_COMPILER +extern void m68k_setpc_fast (uaecptr newpc); +extern void m68k_setpc_bcc (uaecptr newpc); +extern void m68k_setpc_rte (uaecptr newpc); +#else +#define m68k_setpc_fast m68k_setpc +#define m68k_setpc_bcc m68k_setpc +#define m68k_setpc_rte m68k_setpc +#endif + +STATIC_INLINE void m68k_setstopped (int stop) +{ + regs.stopped = stop; + /* A traced STOP instruction drops through immediately without + actually stopping. */ + if (stop && (regs.spcflags & SPCFLAG_DOTRACE) == 0) + set_special (SPCFLAG_STOP); +} + +extern uae_u32 get_disp_ea_020 (uae_u32 base, uae_u32 dp); +extern uae_u32 get_disp_ea_000 (uae_u32 base, uae_u32 dp); + +extern uae_s32 ShowEA (void *, uae_u16 opcode, int reg, amodes mode, wordsizes size, char *buf); + +extern void MakeSR (void); +extern void MakeFromSR (void); +extern void Exception (int, uaecptr); +extern void Interrupt (int nr); +extern void dump_counts (void); +extern int m68k_move2c (int, uae_u32 *); +extern int m68k_movec2 (int, uae_u32 *); +extern void m68k_divl (uae_u32, uae_u32, uae_u16, uaecptr); +extern void m68k_mull (uae_u32, uae_u32, uae_u16); +extern void init_m68k (void); +extern void init_m68k_full (void); +extern void m68k_go (int); +extern void m68k_dumpstate (void *, uaecptr *); +extern void m68k_disasm (void *, uaecptr, uaecptr *, int); +extern void sm68k_disasm(char *, char *, uaecptr addr, uaecptr *nextpc); +extern void m68k_reset (void); + +extern void mmu_op (uae_u32, uae_u16); + +extern void fpp_opp (uae_u32, uae_u16); +extern void fdbcc_opp (uae_u32, uae_u16); +extern void fscc_opp (uae_u32, uae_u16); +extern void ftrapcc_opp (uae_u32,uaecptr); +extern void fbcc_opp (uae_u32, uaecptr, uae_u32); +extern void fsave_opp (uae_u32); +extern void frestore_opp (uae_u32); + +extern void exception3 (uae_u32 opcode, uaecptr addr, uaecptr fault); +extern void exception3i (uae_u32 opcode, uaecptr addr, uaecptr fault); +extern void exception2 (uaecptr addr, uaecptr fault); +extern void cpureset (void); + +extern void fill_prefetch_slow (void); + +#define CPU_OP_NAME(a) op ## a + +/* 68040 */ +extern struct cputbl op_smalltbl_0_ff[]; +/* 68020 + 68881 */ +extern struct cputbl op_smalltbl_1_ff[]; +/* 68020 */ +extern struct cputbl op_smalltbl_2_ff[]; +/* 68010 */ +extern struct cputbl op_smalltbl_3_ff[]; +/* 68000 */ +extern struct cputbl op_smalltbl_4_ff[]; +/* 68000 slow but compatible. */ +extern struct cputbl op_smalltbl_5_ff[]; +/* 68000 slow but compatible and cycle-exact. */ +extern struct cputbl op_smalltbl_6_ff[]; + +extern cpuop_func *cpufunctbl[65536] ASM_SYM_FOR_FUNC ("cpufunctbl"); + + +/* Flags for Bernie during development/debugging. Should go away eventually */ +#define DISTRUST_CONSISTENT_MEM 0 +#define TAGMASK 0x000fffff +#define TAGSIZE (TAGMASK+1) +#define MAXRUN 1024 + +extern uae_u8* start_pc_p; +extern uae_u32 start_pc; + +#define cacheline(x) (((uae_u32)x)&TAGMASK) + +void newcpu_showstate(void); + +#ifdef JIT +extern void flush_icache(int n); +extern void compemu_reset(void); +#else +#define flush_icache(X) do {} while (0) +#endif diff --git a/include/options.h b/include/options.h new file mode 100755 index 00000000..b41ec086 --- /dev/null +++ b/include/options.h @@ -0,0 +1,368 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Stuff + * + * Copyright 1995, 1996 Ed Hanway + * Copyright 1995-2001 Bernd Schmidt + */ + +#define UAEMAJOR 0 +#define UAEMINOR 8 +#define UAESUBREV 26 + +typedef enum { KBD_LANG_US, KBD_LANG_DK, KBD_LANG_DE, KBD_LANG_SE, KBD_LANG_FR, KBD_LANG_IT, KBD_LANG_ES } KbdLang; + +extern long int version; + +struct uaedev_mount_info; + +struct strlist { + struct strlist *next; + char *option, *value; + int unknown; +}; + +/* maximum number native input devices supported (single type) */ +#define MAX_INPUT_DEVICES 6 +/* maximum number of native input device's buttons and axles supported */ +#define MAX_INPUT_DEVICE_EVENTS 256 +/* 4 different customization settings */ +#define MAX_INPUT_SETTINGS 4 +#define MAX_INPUT_SUB_EVENT 4 +#define MAX_INPUT_SIMULTANEOUS_KEYS 4 + +struct uae_input_device { + char *name; + uae_s16 eventid[MAX_INPUT_DEVICE_EVENTS][MAX_INPUT_SUB_EVENT]; + uae_u16 flags[MAX_INPUT_DEVICE_EVENTS][MAX_INPUT_SUB_EVENT]; + uae_s16 extra[MAX_INPUT_DEVICE_EVENTS][MAX_INPUT_SIMULTANEOUS_KEYS]; + uae_u8 enabled; +}; + +#define MAX_SPARE_DRIVES 20 + +#define CONFIG_TYPE_HARDWARE 1 +#define CONFIG_TYPE_HOST 2 + +struct uae_prefs { + + struct strlist *all_lines; + + char description[256]; + char info[256]; + int config_version; + + int illegal_mem; + int no_xhair; + int use_serial; + int serial_demand; + int serial_hwctsrts; + int serial_direct; + int parallel_demand; + int use_gfxlib; + int socket_emu; + + int start_debugger; + int start_gui; + + KbdLang keyboard_lang; + int test_drawing_speed; + + int produce_sound; + int stereo; + int mixed_stereo; + int sound_bits; + int sound_freq; + int sound_maxbsiz; + int sound_interpol; + int sound_adjust; + int sound_filter; + int sound_volume; + + int comptrustbyte; + int comptrustword; + int comptrustlong; + int comptrustnaddr; + int compnf; + int compforcesettings; + int compfpu; + int comp_midopt; + int comp_lowopt; + + int comp_hardflush; + int comp_constjump; + int comp_oldsegv; + + int cachesize; + int optcount[10]; + + int avoid_cmov; + int avoid_dga; + int avoid_vid; + uae_u32 override_dga_address; + + int gfx_display; + int gfx_framerate; + int gfx_width_win, gfx_height_win; + int gfx_width_fs, gfx_height_fs; + int gfx_width, gfx_height; + int gfx_refreshrate; + int gfx_vsync; + int gfx_lores; + int gfx_linedbl; + int gfx_correct_aspect; + int gfx_afullscreen; + int gfx_pfullscreen; + int gfx_xcenter; + int gfx_ycenter; + int gfx_hue, gfx_saturation, gfx_luminance, gfx_contrast, gfx_gamma; + + int gfx_filter; + int gfx_filter_scanlines; + int gfx_filter_scanlineratio; + int gfx_filter_scanlinelevel; + int gfx_filter_horiz_zoom, gfx_filter_vert_zoom; + int gfx_filter_horiz_offset, gfx_filter_vert_offset; + int gfx_filter_filtermode; + int color_mode; + + int immediate_blits; + unsigned int chipset_mask; + int ntscmode; + int collision_level; + int leds_on_screen; + int keyboard_leds[3]; + int keyboard_leds_in_use; + int fast_copper; + int scsi; + int catweasel_io; + int cpu_idle; + int cpu_cycle_exact; + int blitter_cycle_exact; + int floppy_speed; + int tod_hack; + uae_u32 maprom; + + char df[4][256]; + char dfxlist[MAX_SPARE_DRIVES][256]; + char romfile[256]; + char romextfile[256]; + char keyfile[256]; + char flashfile[256]; + char cartfile[256]; + char pci_devices[256]; + char prtname[256]; + char sername[256]; + + char path_floppy[256]; + char path_hardfile[256]; + char path_rom[256]; + + int m68k_speed; + int cpu_level; + int cpu_compatible; + int address_space_24; + + uae_u32 z3fastmem_size; + uae_u32 fastmem_size; + uae_u32 chipmem_size; + uae_u32 bogomem_size; + uae_u32 a3000mem_size; + uae_u32 gfxmem_size; + + int kickshifter; + int filesys_no_uaefsdb; + + struct uaedev_mount_info *mountinfo; + + int nr_floppies; + int dfxtype[4]; + int dfxclick[4]; + char dfxclickexternal[4][256]; + int dfxclickvolume; + + /* Target specific options */ + int x11_use_low_bandwidth; + int x11_use_mitshm; + int x11_use_dgamode; + int x11_hide_cursor; + int svga_no_linear; + int win32_middle_mouse; + int win32_logfile; + + int win32_active_priority; + int win32_inactive_priority; + int win32_inactive_pause; + int win32_inactive_nosound; + int win32_iconified_priority; + int win32_iconified_pause; + int win32_iconified_nosound; + + int win32_no_overlay; /* If this is set, we won't try and use any RGB overlays */ + int win32_ctrl_F11_is_quit; + int win32_automount_drives; + int win32_midioutdev; + int win32_midiindev; + int win32_aspi; + int win32_soundcard; + + int curses_reverse_video; + + int statecapture; + int statecapturerate, statecapturebuffersize; + + /* input */ + + int jport0; + int jport1; + int input_selected_setting; + int input_joymouse_multiplier; + int input_joymouse_deadzone; + int input_joystick_deadzone; + int input_joymouse_speed; + int input_autofire_framecnt; + int input_mouse_speed; + struct uae_input_device joystick_settings[MAX_INPUT_SETTINGS + 1][MAX_INPUT_DEVICES]; + struct uae_input_device mouse_settings[MAX_INPUT_SETTINGS + 1][MAX_INPUT_DEVICES]; + struct uae_input_device keyboard_settings[MAX_INPUT_SETTINGS + 1][MAX_INPUT_DEVICES]; +}; + +/* Contains the filename of .uaerc */ +extern char optionsfile[]; +extern void save_options (FILE *, struct uae_prefs *, int); +extern void cfgfile_write (FILE *f, char *format,...); + +extern void default_prefs (struct uae_prefs *, int); +extern void discard_prefs (struct uae_prefs *, int); + +int parse_cmdline_option (struct uae_prefs *, char, char *); + +extern int cfgfile_yesno (char *option, char *value, char *name, int *location); +extern int cfgfile_intval (char *option, char *value, char *name, int *location, int scale); +extern int cfgfile_strval (char *option, char *value, char *name, int *location, const char *table[], int more); +extern int cfgfile_string (char *option, char *value, char *name, char *location, int maxsz); +extern char *cfgfile_subst_path (const char *path, const char *subst, const char *file); + +extern int target_parse_option (struct uae_prefs *, char *option, char *value); +extern void target_save_options (FILE *, struct uae_prefs *); +extern void target_default_options (struct uae_prefs *); + +extern int cfgfile_load (struct uae_prefs *, const char *filename, int *); +extern int cfgfile_save (struct uae_prefs *, const char *filename, int); +extern void cfgfile_parse_line (struct uae_prefs *p, char *, int); +extern int cfgfile_parse_option (struct uae_prefs *p, char *option, char *value, int); +extern int cfgfile_get_description (const char *filename, char *description, int*); +extern void cfgfile_show_usage (void); +extern uae_u32 cfgfile_uaelib(int mode, uae_u32 name, uae_u32 dst, uae_u32 maxlen); +extern void cfgfile_addcfgparam (char *); + +extern void fixup_prefs_dimensions (struct uae_prefs *prefs); + +extern void check_prefs_changed_custom (void); +extern void check_prefs_changed_cpu (void); +extern void check_prefs_changed_audio (void); +extern int check_prefs_changed_gfx (void); + +#define JSEM_DECODEVAL(n,v) ((n) == 0 ? (v)->jport0 : (v)->jport1) +/* Determine how port n is configured */ +#define JSEM_ISJOY0(n,v) (JSEM_DECODEVAL(n,v) == 0) +#define JSEM_ISJOY1(n,v) (JSEM_DECODEVAL(n,v) == 1) +#define JSEM_ISMOUSE(n,v) (JSEM_DECODEVAL(n,v) == 2) +#define JSEM_ISNUMPAD(n,v) (JSEM_DECODEVAL(n,v) == 3) +#define JSEM_ISCURSOR(n,v) (JSEM_DECODEVAL(n,v) == 4) +#define JSEM_ISSOMEWHEREELSE(n,v) (JSEM_DECODEVAL(n,v) == 5) +extern const char *gameport_state (int n); + +extern struct uae_prefs currprefs, changed_prefs; + +extern void machdep_init (void); + +/* AIX doesn't think it is Unix. Neither do I. */ +#if defined(_ALL_SOURCE) || defined(_AIX) +#undef __unix +#define __unix +#endif + +#define MAX_COLOR_MODES 5 + +/* #define NEED_TO_DEBUG_BADLY */ + +#if !defined(USER_PROGRAMS_BEHAVE) +#define USER_PROGRAMS_BEHAVE 0 +#endif + +/* Some memsets which know that they can safely overwrite some more memory + * at both ends and use that knowledge to align the pointers. */ + +#define QUADRUPLIFY(c) (((c) | ((c) << 8)) | (((c) | ((c) << 8)) << 16)) + +/* When you call this routine, bear in mind that it rounds the bounds and + * may need some padding for the array. */ + +#define fuzzy_memset(p, c, o, l) fuzzy_memset_1 ((p), QUADRUPLIFY (c), (o) & ~3, ((l) + 4) >> 2) +STATIC_INLINE void fuzzy_memset_1 (void *p, uae_u32 c, int offset, int len) +{ + uae_u32 *p2 = (uae_u32 *)((char *)p + offset); + int a = len & 7; + len >>= 3; + switch (a) { + case 7: p2--; goto l1; + case 6: p2-=2; goto l2; + case 5: p2-=3; goto l3; + case 4: p2-=4; goto l4; + case 3: p2-=5; goto l5; + case 2: p2-=6; goto l6; + case 1: p2-=7; goto l7; + case 0: if (!--len) return; break; + } + + for (;;) { + p2[0] = c; + l1: + p2[1] = c; + l2: + p2[2] = c; + l3: + p2[3] = c; + l4: + p2[4] = c; + l5: + p2[5] = c; + l6: + p2[6] = c; + l7: + p2[7] = c; + + if (!len) + break; + len--; + p2 += 8; + } +} + +/* This one knows it will never be asked to clear more than 32 bytes. Make sure you call this with a + constant for the length. */ +#define fuzzy_memset_le32(p, c, o, l) fuzzy_memset_le32_1 ((p), QUADRUPLIFY (c), (o) & ~3, ((l) + 7) >> 2) +STATIC_INLINE void fuzzy_memset_le32_1 (void *p, uae_u32 c, int offset, int len) +{ + uae_u32 *p2 = (uae_u32 *)((char *)p + offset); + + switch (len) { + case 9: p2[0] = c; p2[1] = c; p2[2] = c; p2[3] = c; p2[4] = c; p2[5] = c; p2[6] = c; p2[7] = c; p2[8] = c; break; + case 8: p2[0] = c; p2[1] = c; p2[2] = c; p2[3] = c; p2[4] = c; p2[5] = c; p2[6] = c; p2[7] = c; break; + case 7: p2[0] = c; p2[1] = c; p2[2] = c; p2[3] = c; p2[4] = c; p2[5] = c; p2[6] = c; break; + case 6: p2[0] = c; p2[1] = c; p2[2] = c; p2[3] = c; p2[4] = c; p2[5] = c; break; + case 5: p2[0] = c; p2[1] = c; p2[2] = c; p2[3] = c; p2[4] = c; break; + case 4: p2[0] = c; p2[1] = c; p2[2] = c; p2[3] = c; break; + case 3: p2[0] = c; p2[1] = c; p2[2] = c; break; + case 2: p2[0] = c; p2[1] = c; break; + case 1: p2[0] = c; break; + case 0: break; + default: printf("Hit the programmer.\n"); break; + } +} + +#if defined(AMIGA) && defined(__GNUC__) +#include "od-amiga/amiga-kludges.h" +#endif diff --git a/include/osemu.h b/include/osemu.h new file mode 100755 index 00000000..acd536b6 --- /dev/null +++ b/include/osemu.h @@ -0,0 +1,19 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * OS emulation prototypes + * + * Copyright 1996 Bernd Schmidt + */ + +STATIC_INLINE char *raddr(uaecptr p) +{ + return p == 0 ? NULL : (char *)get_real_address(p); +} + +extern void gfxlib_install(void); + +/* graphics.library */ + +extern int GFX_WritePixel(uaecptr rp, int x, int y); + diff --git a/include/picasso96.h b/include/picasso96.h new file mode 100755 index 00000000..bf13dd43 --- /dev/null +++ b/include/picasso96.h @@ -0,0 +1,587 @@ + +#ifdef WIN32 + +#include "picasso96_win.h" + +#else +/* + * UAE - The U*nix Amiga Emulator + * + * Picasso96 Support Module Header + * + * Copyright 1997 Brian King + */ + +#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< + * Copyright 1997 Christian Schmitt + */ + +extern void serial_init(void); +extern void serial_exit(void); +extern void serial_dtr_off(void); + +extern uae_u16 SERDATR(void); +extern int SERDATS(void); +extern void SERPER(uae_u16 w); +extern void SERDAT(uae_u16 w); + +extern uae_u8 serial_writestatus(uae_u8, uae_u8); +extern uae_u8 serial_readstatus (uae_u8); +extern void serial_uartbreak (int); +extern uae_u16 serdat; + +extern int doreadser, serstat; + +extern void serial_flush_buffer(void); + +extern void serial_hsynchandler (void); +extern void serial_check_irq (void); \ No newline at end of file diff --git a/include/sysconfig.h.win32 b/include/sysconfig.h.win32 new file mode 100755 index 00000000..85eb0b6e --- /dev/null +++ b/include/sysconfig.h.win32 @@ -0,0 +1,42 @@ +/* The number of bytes in a char. */ +#define SIZEOF_CHAR 1 + +/* The number of bytes in a int. */ +#define SIZEOF_INT 4 + +/* The number of bytes in a long. */ +#define SIZEOF_LONG 4 + +#ifdef __GNUC__ +/* The number of bytes in a long long. */ +#define SIZEOF_LONG_LONG 8 +#define SIZEOF___INT64 0 +#else +#define SIZEOF_LONG_LONG 0 +#define SIZEOF___INT64 8 +#endif + +/* The number of bytes in a short. */ +#define SIZEOF_SHORT 2 + +/* Define if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +// Windows-specific #defines +#ifndef __GNUC__ +#define REGPARAM +#define REGPARAM2 +#define __inline__ __inline +#define __asm__(a) ; +#define O_NDELAY 0 +#endif +#define lseek _lseek diff --git a/include/sysdeps.h b/include/sysdeps.h new file mode 100755 index 00000000..b60b92e7 --- /dev/null +++ b/include/sysdeps.h @@ -0,0 +1,491 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Try to include the right system headers and get other system-specific + * stuff right & other collected kludges. + * + * If you think about modifying this, think twice. Some systems rely on + * the exact order of the #include statements. That's also the reason + * why everything gets included unconditionally regardless of whether + * it's actually needed by the .c file. + * + * Copyright 1996, 1997 Bernd Schmidt + */ + +#include +#include +#include +#include +#include + +#ifndef __STDC__ +#ifndef _MSC_VER +#error "Your compiler is not ANSI. Get a real one." +#endif +#endif + +#include + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#ifdef HAVE_VALUES_H +#include +#endif + +#ifdef HAVE_STRINGS_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif + +#ifdef HAVE_UTIME_H +#include +#endif + +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#if HAVE_DIRENT_H +# include +#else +# define dirent direct +# if HAVE_SYS_NDIR_H +# include +# endif +# if HAVE_SYS_DIR_H +# include +# endif +# if HAVE_NDIR_H +# include +# endif +#endif + +#ifdef HAVE_SYS_UTIME_H +# include +#endif + +#include +#include + +#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 +#include +#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 +#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 // 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 +#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 +#define utimbuf _utimbuf +#define USE_ZFILE + +#undef S_ISDIR +#undef S_IWUSR +#undef S_IRUSR +#undef S_IXUSR +#define S_ISDIR(a) (a&FILEFLAG_DIR) +#define S_ISARC(a) (a&FILEFLAG_ARCHIVE) +#define S_IWUSR FILEFLAG_WRITE +#define S_IRUSR FILEFLAG_READ +#define S_IXUSR FILEFLAG_EXECUTE + +/* These are prototypes for functions from the Win32 posixemu file */ +extern void get_time(time_t t, long* days, long* mins, long* ticks); +extern time_t put_time (long days, long mins, long ticks); +extern DWORD getattr(const char *name, LPFILETIME lpft, size_t *size); + +/* #define DONT_HAVE_POSIX - don't need all of Mathias' posixemu_functions, just a subset (below) */ +#define chmod(a,b) posixemu_chmod ((a), (b)) +extern int posixemu_chmod (const char *, int); +#define stat(a,b) posixemu_stat ((a), (b)) +extern int posixemu_stat (const char *, struct stat *); +#define mkdir(x,y) mkdir(x) +#define truncate posixemu_truncate +extern int posixemu_truncate (const char *, long int); +#define utime posixemu_utime +extern int posixemu_utime (const char *, struct utimbuf *); +#define opendir posixemu_opendir +extern DIR * posixemu_opendir (const char *); +#define readdir posixemu_readdir +extern struct dirent* posixemu_readdir (DIR *); +#define closedir posixemu_closedir +extern void posixemu_closedir (DIR *); + +#endif + +#endif /* _WIN32 */ + +#ifdef DONT_HAVE_POSIX + +#define access posixemu_access +extern int posixemu_access (const char *, int); +#define open posixemu_open +extern int posixemu_open (const char *, int, int); +#define close posixemu_close +extern void posixemu_close (int); +#define read posixemu_read +extern int posixemu_read (int, char *, int); +#define write posixemu_write +extern int posixemu_write (int, const char *, int); +#undef lseek +#define lseek posixemu_seek +extern int posixemu_seek (int, int, int); +#define stat(a,b) posixemu_stat ((a), (b)) +extern int posixemu_stat (const char *, STAT *); +#define mkdir posixemu_mkdir +extern int mkdir (const char *, int); +#define rmdir posixemu_rmdir +extern int posixemu_rmdir (const char *); +#define unlink posixemu_unlink +extern int posixemu_unlink (const char *); +#define truncate posixemu_truncate +extern int posixemu_truncate (const char *, long int); +#define rename posixemu_rename +extern int posixemu_rename (const char *, const char *); +#define chmod posixemu_chmod +extern int posixemu_chmod (const char *, int); +#define tmpnam posixemu_tmpnam +extern void posixemu_tmpnam (char *); +#define utime posixemu_utime +extern int posixemu_utime (const char *, struct utimbuf *); +#define opendir posixemu_opendir +extern DIR * posixemu_opendir (const char *); +#define readdir posixemu_readdir +extern struct dirent* readdir (DIR *); +#define closedir posixemu_closedir +extern void closedir (DIR *); + +/* This isn't the best place for this, but it fits reasonably well. The logic + * is that you probably don't have POSIX errnos if you don't have the above + * functions. */ +extern long dos_errno (void); + +#endif + +#ifdef DONT_HAVE_STDIO + +extern FILE *stdioemu_fopen (const char *, const char *); +#define fopen(a,b) stdioemu_fopen(a, b) +extern int stdioemu_fseek (FILE *, int, int); +#define fseek(a,b,c) stdioemu_fseek(a, b, c) +extern int stdioemu_fread (char *, int, int, FILE *); +#define fread(a,b,c,d) stdioemu_fread(a, b, c, d) +extern int stdioemu_fwrite (const char *, int, int, FILE *); +#define fwrite(a,b,c,d) stdioemu_fwrite(a, b, c, d) +extern int stdioemu_ftell (FILE *); +#define ftell(a) stdioemu_ftell(a) +extern int stdioemu_fclose (FILE *); +#define fclose(a) stdioemu_fclose(a) + +#endif + +#ifdef DONT_HAVE_MALLOC + +#define malloc(a) mallocemu_malloc(a) +extern void *mallocemu_malloc (int size); +#define free(a) mallocemu_free(a) +extern void mallocemu_free (void *ptr); + +#endif + +#ifdef X86_ASSEMBLY +#define ASM_SYM_FOR_FUNC(a) __asm__(a) +#else +#define ASM_SYM_FOR_FUNC(a) +#endif + +#if defined USE_COMPILER +#undef NO_PREFETCH_BUFFER +#undef NO_EXCEPTION_3 +#define NO_EXCEPTION_3 +#define NO_PREFETCH_BUFFER +#endif + +#include "target.h" + +#ifdef UAE_CONSOLE +#undef write_log +#define write_log write_log_standard +#endif + +#if __GNUC__ - 1 > 1 || __GNUC_MINOR__ - 1 > 6 +extern void write_log (const char *, ...) __attribute__ ((format (printf, 1, 2))); +#else +extern void write_log (const char *, ...); +#endif +extern void write_dlog (const char *, ...); + +extern void console_out (const char *, ...); +extern void console_flush (void); +extern int console_get (char *, int); +extern void f_out (void *, const char *, ...); +extern void gui_message (const char *,...); +#define write_log_err write_log + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#ifndef STATIC_INLINE +#define STATIC_INLINE static __inline__ +#endif + +/* Every Amiga hardware clock cycle takes this many "virtual" cycles. This + used to be hardcoded as 1, but using higher values allows us to time some + stuff more precisely. + 512 is the official value from now on - it can't change, unless we want + _another_ config option "finegrain2_m68k_speed". + + We define this value here rather than in events.h so that gencpu.c sees + it. */ +#define CYCLE_UNIT 512 + +/* This one is used by cfgfile.c. We could reduce the CYCLE_UNIT back to 1, + I'm not 100% sure this code is bug free yet. */ +#define OFFICIAL_CYCLE_UNIT 512 + +/* + * You can specify numbers from 0 to 5 here. It is possible that higher + * numbers will make the CPU emulation slightly faster, but if the setting + * is too high, you will run out of memory while compiling. + * Best to leave this as it is. + */ +#define CPU_EMU_SIZE 0 diff --git a/include/tui.h b/include/tui.h new file mode 100755 index 00000000..d5c5f3be --- /dev/null +++ b/include/tui.h @@ -0,0 +1,39 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Text-based user interface + * Sie haben es sich verdient! + * + * Copyright 1996 Tim Gunn, Bernd Schmidt + */ + +extern void tui_setup(void); +extern void tui_shutdown(void); +extern void tui_refresh(void); + +extern void tui_curson(void); +extern void tui_cursoff(void); + +extern void tui_cr(void); +extern void tui_gotoxy(int, int); +extern void tui_puts(const char *); +extern void tui_putc(char); +extern char tui_getc(void); +extern int tui_gets(char *, int, int, int); +extern int tui_wgets(char *, const char *, int); +extern void tui_clrwin(int); +extern void tui_selwin(int); + +extern int tui_dlog(int, int, int, int); +extern int tui_menubrowse(struct bstring *, int, int, int, int); + +extern void tui_dlogdie(int); +extern char *tui_filereq(char *, char *, const char *); +extern void tui_drawbox(int); +extern void tui_hline(int, int, int); +extern void tui_errorbox(const char *); + +extern int tui_cols(void); +extern int tui_lines(void); + +extern int tui_backup_optionsfile(void); diff --git a/include/uae.h b/include/uae.h new file mode 100755 index 00000000..10338b68 --- /dev/null +++ b/include/uae.h @@ -0,0 +1,43 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Prototypes for main.c + * + * Copyright 1996 Bernd Schmidt + */ + +extern void do_start_program (void); +extern void do_leave_program (void); +extern void start_program (void); +extern void leave_program (void); +extern void real_main (int, char **); +extern void usage (void); +extern void parse_cmdline (int argc, char **argv); +extern void sleep_millis (int ms); + + +extern void uae_reset (int); +extern void uae_quit (void); +extern void uae_restart (int, char*); +extern void reset_all_systems (void); + +extern int quit_program; + +extern char warning_buffer[256]; +extern char *start_path; + +/* This structure is used to define menus. The val field can hold key + * shortcuts, or one of these special codes: + * -4: deleted entry, not displayed, not selectable, but does count in + * select value + * -3: end of table + * -2: line that is displayed, but not selectable + * -1: line that is selectable, but has no keyboard shortcut + * 0: Menu title + */ +struct bstring { + const char *data; + int val; +}; + +extern char *colormodes[]; diff --git a/include/uaeexe.h b/include/uaeexe.h new file mode 100755 index 00000000..e43e8cff --- /dev/null +++ b/include/uaeexe.h @@ -0,0 +1,21 @@ +/* + * uaeexe.h - launch executable in UAE + * + * (c) 1997 by Samuel Devulder + */ + +struct uae_xcmd { + struct uae_xcmd *prev,*next; + char *cmd; +}; + +#define UAEEXE_ORG 0xF0FF90 /* sam: I hope this slot is free */ + +#define UAEEXE_OK 0 +#define UAEEXE_NOTRUNNING 1 +#define UAEEXE_NOMEM 2 + +extern void uaeexe_install(void); +extern int uaeexe(char *cmd); + + diff --git a/include/unzip.h b/include/unzip.h new file mode 100755 index 00000000..091b8dfe --- /dev/null +++ b/include/unzip.h @@ -0,0 +1,275 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 0.15 beta, Mar 19th, 1998, + + Copyright (C) 1998 Gilles Vollant + + This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + Encryption and multi volume ZipFile (span) are not supported. + Old compressions used by old PKZip 1.x are not supported + + THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE + CAN CHANGE IN FUTURE VERSION !! + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + +*/ +/* for more info about .ZIP format, see + ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip */ + +#ifndef _unz_H +#define _unz_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((struct zfile *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer + "zlib/zlib111.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _unz_H */ diff --git a/include/xwin.h b/include/xwin.h new file mode 100755 index 00000000..81f71843 --- /dev/null +++ b/include/xwin.h @@ -0,0 +1,88 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Interface to the graphics system (X, SVGAlib) + * + * Copyright 1995-1997 Bernd Schmidt + */ + +typedef long int xcolnr; + +typedef int (*allocfunc_type)(int, int, int, xcolnr *); + +extern xcolnr xcolors[4096]; + +extern int buttonstate[3]; +extern int newmousecounters; +extern int lastmx, lastmy; +extern int ievent_alive; + +extern int graphics_setup (void); +extern int graphics_init (void); +extern void graphics_leave (void); +extern void handle_events (void); +extern void setup_brkhandler (void); +extern int isfullscreen (void); + +extern void flush_line (int); +extern void flush_block (int, int); +extern void flush_screen (int, int); +extern void flush_clear_screen (void); + +extern int lockscr (void); +extern void unlockscr (void); + +extern int debuggable (void); +extern int needmousehack (void); +extern void togglemouse (void); +extern void LED (int); +extern void screenshot (int); + +extern int bits_in_mask (unsigned long mask); +extern int mask_shift (unsigned long mask); +extern unsigned long doMask (int p, int bits, int shift); +extern unsigned long doMask256 (int p, int bits, int shift); +extern void setup_maxcol (int); +extern void alloc_colors256 (int (*)(int, int, int, xcolnr *)); +extern void alloc_colors64k (int, int, int, int, int, int, int, int, int); +extern void setup_greydither (int bits, allocfunc_type allocfunc); +extern void setup_greydither_maxcol (int maxcol, allocfunc_type allocfunc); +extern void setup_dither (int bits, allocfunc_type allocfunc); +extern void DitherLine (uae_u8 *l, uae_u16 *r4g4b4, int x, int y, uae_s16 len, int bits) ASM_SYM_FOR_FUNC("DitherLine"); + +struct vidbuf_description +{ + /* The graphics code has a choice whether it wants to use a large buffer + * for the whole display, or only a small buffer for a single line. + * If you use a large buffer: + * - set bufmem to point at it + * - set linemem to 0 + * - if memcpy within bufmem would be very slow, i.e. because bufmem is + * in graphics card memory, also set emergmem to point to a buffer + * that is large enough to hold a single line. + * - implement flush_line to be a no-op. + * If you use a single line buffer: + * - set bufmem and emergmem to 0 + * - set linemem to point at your buffer + * - implement flush_line to copy a single line to the screen + */ + uae_u8 *bufmem; + uae_u8 *realbufmem; + uae_u8 *linemem; + uae_u8 *emergmem; + int rowbytes; /* Bytes per row in the memory pointed at by bufmem. */ + int pixbytes; /* Bytes per pixel. */ + int width; + int height; + int maxblocklines; /* Set to 0 if you want calls to flush_line after each drawn line, or the number of + * lines that flush_block wants to/can handle (it isn't really useful to use another + * value than maxline here). */ + int can_double; /* Set if the high part of each entry in xcolors contains the same value + * as the low part, so that two pixels can be drawn at once. */ +}; + +extern struct vidbuf_description gfxvidinfo; + +/* For ports using tui.c, this should be built by graphics_setup(). */ +extern struct bstring *video_mode_menu; +extern void vidmode_menu_selected(int); diff --git a/include/zfile.h b/include/zfile.h new file mode 100755 index 00000000..8d6bd09d --- /dev/null +++ b/include/zfile.h @@ -0,0 +1,34 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * routines to handle compressed file automatically + * + * (c) 1996 Samuel Devulder + */ + +struct zfile; +extern int is_zlib; + +extern struct zfile *zfile_fopen (const char *, const char *); +extern struct zfile *zfile_fopen_empty (const char *name, int size); +extern int zfile_exists (const char *name); +extern void zfile_fclose (struct zfile *); +extern int zfile_fseek (struct zfile *z, long offset, int mode); +extern long zfile_ftell (struct zfile *z); +extern size_t zfile_fread (void *b, size_t l1, size_t l2, struct zfile *z); +extern size_t zfile_fwrite (void *b, size_t l1, size_t l2, struct zfile *z); +extern void zfile_exit (void); +extern int execute_command (char *); +extern int zfile_iscompressed (struct zfile *z); +extern int zfile_zcompress (struct zfile *dst, void *src, int size); +extern int zfile_zuncompress (void *dst, int dstsize, struct zfile *src, int srcsize); +extern int zfile_gettype (struct zfile *z); + +#define ZFILE_UNKNOWN 0 +#define ZFILE_CONFIGURATION 1 +#define ZFILE_DISKIMAGE 2 +#define ZFILE_ROM 3 +#define ZFILE_KEY 4 +#define ZFILE_HDF 5 +#define ZFILE_STATEFILE 6 +#define ZFILE_NVR 7 \ No newline at end of file diff --git a/inputdevice.c b/inputdevice.c new file mode 100755 index 00000000..aa27ae7b --- /dev/null +++ b/inputdevice.c @@ -0,0 +1,2253 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * joystick/mouse emulation + * + * Copyright 2001, 2002 Toni Wilen + * + * new fetures: + * - very configurable (and very complex to configure :) + * - supports multiple native input devices (joysticks and mice) + * - supports mapping joystick/mouse buttons to keys and vice versa + * - joystick mouse emulation (supports both ports) + * - supports parallel port joystick adapter + * - full cd32 pad support (supports both ports) + * - fully backward compatible with old joystick/mouse configuration + * + */ + +//#define DONGLE_DEBUG + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "keyboard.h" +#include "inputdevice.h" +#include "keybuf.h" +#include "custom.h" +#include "xwin.h" +#include "drawing.h" +#include "memory.h" +#include "events.h" +#include "newcpu.h" +#include "uae.h" +#include "picasso96.h" +#include "catweasel.h" +#include "debug.h" +#include "ar.h" +#include "gui.h" +#include "disk.h" +#include "sound.h" +#include "savestate.h" + +#define DIR_LEFT 1 +#define DIR_RIGHT 2 +#define DIR_UP 4 +#define DIR_DOWN 8 + +struct inputevent { + char *confname; + char *name; + int allow_mask; + int type; + int unit; + int data; +}; + +#define JOYBUTTON_1 0 /* fire/left mousebutton */ +#define JOYBUTTON_2 1 /* 2nd/right mousebutton */ +#define JOYBUTTON_3 2 /* 3rd/middle mousebutton */ +#define JOYBUTTON_CD32_PLAY 3 +#define JOYBUTTON_CD32_RWD 4 +#define JOYBUTTON_CD32_FFW 5 +#define JOYBUTTON_CD32_GREEN 6 +#define JOYBUTTON_CD32_YELLOW 7 +#define JOYBUTTON_CD32_RED 8 +#define JOYBUTTON_CD32_BLUE 9 + +#define INPUTEVENT_JOY1_CD32_FIRST INPUTEVENT_JOY1_CD32_PLAY +#define INPUTEVENT_JOY2_CD32_FIRST INPUTEVENT_JOY2_CD32_PLAY +#define INPUTEVENT_JOY1_CD32_LAST INPUTEVENT_JOY1_CD32_BLUE +#define INPUTEVENT_JOY2_CD32_LAST INPUTEVENT_JOY2_CD32_BLUE + +/* event masks */ +#define AM_KEY 1 /* keyboard allowed */ +#define AM_JOY_BUT 2 /* joystick buttons allowed */ +#define AM_JOY_AXIS 4 /* joystick axis allowed */ +#define AM_MOUSE_BUT 8 /* mouse buttons allowed */ +#define AM_MOUSE_AXIS 16 /* mouse direction allowed */ +#define AM_AF 32 /* supports autofire */ +#define AM_INFO 64 /* information data for gui */ +#define AM_DUMMY 128 /* placeholder */ +#define AM_K (AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF) /* keyboard */ + +/* event flags */ +#define ID_FLAG_AUTOFIRE 1 + +#define DEFEVENT(A, B, C, D, E, F) {#A, B, C, D, E, F }, +struct inputevent events[] = { +{0, 0, 0, 0, 0, 0}, +#include "inputevents.def" +{0, 0, 0, 0, 0, 0} +}; +#undef DEFEVENT + +static int sublevdir[2][MAX_INPUT_SUB_EVENT]; + +struct uae_input_device2 { + uae_u32 buttonmask; + int states[MAX_INPUT_DEVICE_EVENTS / 2]; +}; + +static struct uae_input_device2 joysticks2[MAX_INPUT_DEVICES]; +static struct uae_input_device2 mice2[MAX_INPUT_DEVICES]; + +static uae_u8 mouse_settings_reset[MAX_INPUT_SETTINGS][MAX_INPUT_DEVICES]; +static uae_u8 joystick_settings_reset[MAX_INPUT_SETTINGS][MAX_INPUT_DEVICES]; + +static int isdevice (struct uae_input_device *id) +{ + int i, j; + for (i = 0; i < MAX_INPUT_DEVICE_EVENTS; i++) { + for (j = 0; j < MAX_INPUT_SUB_EVENT; j++) { + if (id->eventid[i][j] > 0) + return 1; + } + } + return 0; +} + +static struct uae_input_device *joysticks; +static struct uae_input_device *mice; +static struct uae_input_device *keyboards; +static struct uae_input_device_kbr_default *keyboard_default; + +static double mouse_axis[MAX_INPUT_DEVICES][MAX_INPUT_DEVICE_EVENTS]; +static double oldm_axis[MAX_INPUT_DEVICES][MAX_INPUT_DEVICE_EVENTS]; + +static int mouse_x[MAX_INPUT_DEVICES], mouse_y[MAX_INPUT_DEVICE_EVENTS]; +static int mouse_delta[MAX_INPUT_DEVICES][MAX_INPUT_DEVICE_EVENTS]; +static int mouse_deltanoreset[MAX_INPUT_DEVICES][MAX_INPUT_DEVICE_EVENTS]; +static int joybutton[MAX_INPUT_DEVICES]; +static unsigned int joydir[MAX_INPUT_DEVICE_EVENTS]; +static int joydirpot[MAX_INPUT_DEVICE_EVENTS][2]; +static int mouse_frame_x[2], mouse_frame_y[2]; + +static int lastmx, lastmy; + +static int mouse_port[2]; +static int cd32_shifter[2]; +static int cd32_pad_enabled[2]; +static int parport_joystick_enabled; +static int oldmx[4], oldmy[4]; +static int oleft[4], oright[4], otop[4], obot[4]; +static int potgo_hsync; + +static int use_joysticks[MAX_INPUT_DEVICES]; +static int use_mice[MAX_INPUT_DEVICES]; +static int use_keyboards[MAX_INPUT_DEVICES]; + +#define INPUT_QUEUE_SIZE 16 +struct input_queue_struct { + int event, storedstate, state, max, framecnt, nextframecnt; +}; +static struct input_queue_struct input_queue[INPUT_QUEUE_SIZE]; + +static void out_config (FILE *f, int id, int num, char *s1, char *s2) +{ + cfgfile_write (f, "input.%d.%s%d=%s\n", id, s1, num, s2); + //write_log ("-input.%d.%s%d=%s\n", id, s1, num, s2); +} + +static void write_config2 (FILE *f, int idnum, int i, int offset, char *tmp1, struct uae_input_device *id) +{ + char tmp2[200], *p; + int event, got, j, k; + + p = tmp2; + got = 0; + for (j = 0; j < MAX_INPUT_SUB_EVENT; j++) { + event = id->eventid[i + offset][j]; + if (event <= 0) { + for (k = j + 1; k < MAX_INPUT_SUB_EVENT; k++) { + if (id->eventid[i + offset][k] > 0) break; + } + if (k == MAX_INPUT_SUB_EVENT) + break; + } + if (p > tmp2) { + *p++ = ','; + *p = 0; + } + if (event <= 0) + sprintf (p, "NULL"); + else + sprintf (p, "%s.%d", events[event].confname, id->flags[i + offset][j]); + p += strlen (p); + } + if (p > tmp2) + out_config (f, idnum, i, tmp1, tmp2); +} + +static void write_config (FILE *f, int idnum, int devnum, char *name, struct uae_input_device *id, struct uae_input_device2 *id2) +{ + char tmp1[100]; + int i; + + if (!isdevice (id)) + return; + cfgfile_write (f, "input.%d.%s.%d.disabled=%d\n", idnum, name, devnum, id->enabled ? 0 : 1); + sprintf (tmp1, "%s.%d.axis.", name, devnum); + for (i = 0; i < ID_AXIS_TOTAL; i++) + write_config2 (f, idnum, i, ID_AXIS_OFFSET, tmp1, id); + sprintf (tmp1, "%s.%d.button." ,name, devnum); + for (i = 0; i < ID_BUTTON_TOTAL; i++) + write_config2 (f, idnum, i, ID_BUTTON_OFFSET, tmp1, id); +} + +static void kbrlabel (char *s) +{ + while (*s) { + *s = toupper(*s); + if (*s == ' ') *s = '_'; + s++; + } +} + +static void write_kbr_config (FILE *f, int idnum, int devnum, struct uae_input_device *kbr) +{ + char tmp1[200], tmp2[200], tmp3[200], *p; + int i, j, k, event, skip; + + if (!keyboard_default) + return; + i = 0; + while (i < MAX_INPUT_DEVICE_EVENTS && kbr->extra[i][0] >= 0) { + skip = 0; + k = 0; + while (keyboard_default[k].scancode >= 0) { + if (keyboard_default[k].scancode == kbr->extra[i][0]) { + skip = 1; + for (j = 1; j < MAX_INPUT_SUB_EVENT; j++) { + if (kbr->flags[i][j] || kbr->eventid[i][j] > 0) + skip = 0; + } + if (keyboard_default[k].event != kbr->eventid[i][0] || kbr->flags[i][0] != 0) + skip = 0; + break; + } + k++; + } + if (kbr->eventid[i][0] == 0 && kbr->flags[i][0] == 0 && keyboard_default[k].scancode < 0) + skip = 1; + if (skip) { + i++; + continue; + } + p = tmp2; + p[0] = 0; + for (j = 0; j < MAX_INPUT_SUB_EVENT; j++) { + event = kbr->eventid[i][j]; + if (event <= 0) { + for (k = j + 1; k < MAX_INPUT_SUB_EVENT; k++) { + if (kbr->eventid[i][k] > 0) break; + } + if (k == MAX_INPUT_SUB_EVENT) + break; + } + if (p > tmp2) { + *p++ = ','; + *p = 0; + } + if (event > 0) + sprintf (p, "%s.%d", events[event].confname, kbr->flags[i][j]); + else + strcat (p, "NULL"); + p += strlen(p); + } + sprintf (tmp3, "%d", kbr->extra[i][0]); + kbrlabel (tmp3); + sprintf (tmp1, "keyboard.%d.button.%s", devnum, tmp3); + cfgfile_write (f, "input.%d.%s=%s\n", idnum, tmp1, tmp2); + i++; + } +} + +void write_inputdevice_config (struct uae_prefs *p, FILE *f) +{ + int i, id; + + cfgfile_write (f, "input.config=%d\n", p->input_selected_setting); + cfgfile_write (f, "input.joymouse_speed_analog=%d\n", p->input_joymouse_multiplier); + cfgfile_write (f, "input.joymouse_speed_digital=%d\n", p->input_joymouse_speed); + cfgfile_write (f, "input.joymouse_deadzone=%d\n", p->input_joymouse_deadzone); + cfgfile_write (f, "input.joystick_deadzone=%d\n", p->input_joystick_deadzone); + cfgfile_write (f, "input.mouse_speed=%d\n", p->input_mouse_speed); + cfgfile_write (f, "input.autofire=%d\n", p->input_autofire_framecnt); + for (id = 1; id <= MAX_INPUT_SETTINGS; id++) { + for (i = 0; i < MAX_INPUT_DEVICES; i++) + write_config (f, id, i, "joystick", &p->joystick_settings[id][i], &joysticks2[i]); + for (i = 0; i < MAX_INPUT_DEVICES; i++) + write_config (f, id, i, "mouse", &p->mouse_settings[id][i], &mice2[i]); + for (i = 0; i < MAX_INPUT_DEVICES; i++) + write_kbr_config (f, id, i, &p->keyboard_settings[id][i]); + } +} + +static int getnum (char **pp) +{ + char *p = *pp; + int v = atol (p); + + while (*p != 0 && *p !='.' && *p != ',') p++; + if (*p == '.' || *p == ',') p++; + *pp = p; + return v; +} +static char *getstring (char **pp) +{ + int i; + static char str[100]; + char *p = *pp; + + if (*p == 0) + return 0; + i = 0; + while (*p != 0 && *p !='.' && *p != ',') str[i++] = *p++; + if (*p == '.' || *p == ',') p++; + str[i] = 0; + *pp = p; + return str; +} + +void reset_inputdevice_config (struct uae_prefs *pr) +{ + memset (joystick_settings_reset, 0, sizeof (joystick_settings_reset)); + memset (mouse_settings_reset, 0, sizeof (mouse_settings_reset)); +} + +void read_inputdevice_config (struct uae_prefs *pr, char *option, char *value) +{ + struct uae_input_device *id = 0; + struct inputevent *ie; + int devnum, num, button, joystick, flags, i, subnum, idnum, keynum; + int mask; + char *p, *p2; + + option += 6; /* "input." */ + p = getstring (&option); + if (!strcasecmp (p, "config")) + pr->input_selected_setting = atol (value); + if (!strcasecmp (p, "joymouse_speed_analog")) + pr->input_joymouse_multiplier = atol (value); + if (!strcasecmp (p, "joymouse_speed_digital")) + pr->input_joymouse_speed = atol (value); + if (!strcasecmp (p, "joystick_deadzone")) + pr->input_joystick_deadzone = atol (value); + if (!strcasecmp (p, "joymouse_deadzone")) + pr->input_joymouse_deadzone = atol (value); + if (!strcasecmp (p, "mouse_speed")) + pr->input_mouse_speed = atol (value); + if (!strcasecmp (p, "autofire")) + pr->input_autofire_framecnt = atol (value); + idnum = atol (p); + if (idnum <= 0 || idnum > MAX_INPUT_SETTINGS) + return; + if (memcmp (option, "mouse.", 6) == 0) { + p = option + 6; + devnum = getnum (&p); + if (devnum < 0 || devnum >= MAX_INPUT_DEVICES) + return; + id = &pr->mouse_settings[idnum][devnum]; + if (!mouse_settings_reset[idnum][devnum]) { + memset (id, 0, sizeof (struct uae_input_device)); + id->enabled = 1; + } + mouse_settings_reset[idnum][devnum] = 1; + joystick = 0; + } else if (memcmp (option, "joystick.", 9) == 0) { + p = option + 9; + devnum = getnum (&p); + if (devnum < 0 || devnum >= MAX_INPUT_DEVICES) + return; + id = &pr->joystick_settings[idnum][devnum]; + if (!joystick_settings_reset[idnum][devnum]) { + memset (id, 0, sizeof (struct uae_input_device)); + id->enabled = 1; + } + joystick_settings_reset[idnum][devnum] = 1; + joystick = 1; + } else if (memcmp (option, "keyboard.", 9) == 0) { + joystick = -1; + p = option + 9; + devnum = getnum (&p); + if (devnum < 0 || devnum >= MAX_INPUT_DEVICES) + return; + id = &pr->keyboard_settings[idnum][devnum]; + } + if (!id) + return; + p2 = getstring (&p); + if (!p2) + return; + if (!strcmp (p2, "disabled")) { + int disabled; + p = value; + disabled = getnum (&p); + id->enabled = disabled == 0 ? 1 : 0; + return; + } + + if (joystick < 0) { + num = getnum (&p); + keynum = 0; + while (id->extra[keynum][0] >= 0) { + if (id->extra[keynum][0] == num) + break; + keynum++; + } + if (id->extra[keynum][0] < 0) + return; + } else { + button = -1; + if (!strcmp (p2, "axis")) + button = 0; + else if(!strcmp (p2, "button")) + button = 1; + if (button < 0) + return; + num = getnum (&p); + } + p = value; + + subnum = 0; + while (subnum < MAX_INPUT_SUB_EVENT) { + p2 = getstring (&p); + if (!p2) break; + i = 1; + while (events[i].name) { + if (!strcmp (events[i].confname, p2)) + break; + i++; + } + ie = &events[i]; + if (!ie->name) { + subnum++; + continue; + } + flags = getnum (&p); + if (joystick < 0) { + if (!(ie->allow_mask & AM_K)) + return; + id->eventid[keynum][subnum] = ie - events; + id->flags[keynum][subnum] = flags; + } else if (button) { + if (joystick) + mask = AM_JOY_BUT; + else + mask = AM_MOUSE_BUT; + if (!(ie->allow_mask & mask)) + return; + id->eventid[num + ID_BUTTON_OFFSET][subnum] = ie - events; + id->flags[num + ID_BUTTON_OFFSET][subnum] = flags; + } else { + if (joystick) + mask = AM_JOY_AXIS; + else + mask = AM_MOUSE_AXIS; + if (!(ie->allow_mask & mask)) + return; + id->eventid[num + ID_AXIS_OFFSET][subnum] = ie - events; + id->flags[num + ID_AXIS_OFFSET][subnum] = flags; + } + subnum++; + } +} + +/* Mousehack stuff */ + +#define defstepx (1<<16) +#define defstepy (1<<16) +#define defxoffs 0 +#define defyoffs 0 + +static const int docal = 60, xcaloff = 40, ycaloff = 20; +static const int calweight = 3; +static int lastsampledmx, lastsampledmy; +static int lastspr0x,lastspr0y,lastdiffx,lastdiffy,spr0pos,spr0ctl; +static int mstepx,mstepy,xoffs=defxoffs,yoffs=defyoffs; +static int sprvbfl; + +static enum mousestate mousestate; + +void mousehack_handle (int sprctl, int sprpos) +{ + if (!sprvbfl && ((sprpos & 0xff) << 2) > 2 * DISPLAY_LEFT_SHIFT) { + spr0ctl = sprctl; + spr0pos = sprpos; + sprvbfl = 2; + } +} + +static void mousehack_setunknown (void) +{ + mousestate = mousehack_unknown; +} + +static void mousehack_setdontcare (void) +{ + if (mousestate == mousehack_dontcare) + return; + + write_log ("Don't care mouse mode set\n"); + mousestate = mousehack_dontcare; + lastspr0x = lastmx; lastspr0y = lastmy; + mstepx = defstepx; mstepy = defstepy; +} + +static void mousehack_setfollow (void) +{ + if (mousestate == mousehack_follow) + return; + write_log ("Follow sprite mode set\n"); + mousestate = mousehack_follow; + lastdiffx = lastdiffy = 0; + sprvbfl = 0; + spr0ctl = spr0pos = 0; + mstepx = defstepx; mstepy = defstepy; +} + +void mousehack_set (int state) +{ + switch (state) + { + case mousehack_dontcare: + mousehack_setdontcare(); + break; + case mousehack_follow: + mousehack_setfollow(); + break; + default: + mousestate = state; + break; + } +} + +uae_u32 mousehack_helper (void) +{ + int mousexpos, mouseypos; + +#ifdef PICASSO96 + if (picasso_on) { + mousexpos = lastmx - picasso96_state.XOffset; + mouseypos = lastmy - picasso96_state.YOffset; + } else +#endif + { + if (mouse_y[0] >= gfxvidinfo.height) + mouse_y[0] = gfxvidinfo.height - 1; + mouseypos = coord_native_to_amiga_y (lastmy) << 1; + mousexpos = coord_native_to_amiga_x (lastmx); + } + + switch (m68k_dreg (regs, 0)) { + case 0: + return ievent_alive ? -1 : needmousehack (); + case 1: + ievent_alive = 10; + return mousexpos; + case 2: + return mouseypos; + } + return 0; +} + +void togglemouse (void) +{ + switch (mousestate) { + case mousehack_dontcare: mousehack_setfollow (); break; + case mousehack_follow: mousehack_setdontcare (); break; + default: break; /* Nnnnnghh! */ + } +} + +STATIC_INLINE int adjust (int val) +{ + if (val > 127) + return 127; + else if (val < -127) + return -127; + return val; +} + +static void do_mouse_hack (void) +{ + int spr0x = ((spr0pos & 0xff) << 2) | ((spr0ctl & 1) << 1); + int spr0y = ((spr0pos >> 8) | ((spr0ctl & 4) << 6)) << 1; + int diffx, diffy; + +#if 0 + if (ievent_alive > 0) { + mouse_x[0] = mouse_y[0] = 0; + return; + } +#endif + switch (mousestate) { + case mousehack_normal: +#if 0 + diffx = lastmx - lastsampledmx; + diffy = lastmy - lastsampledmy; + if (!newmousecounters) { + if (diffx > 127) diffx = 127; + if (diffx < -127) diffx = -127; + mouse_x[0] += diffx; + if (diffy > 127) diffy = 127; + if (diffy < -127) diffy = -127; + mouse_y[0] += diffy; + } + lastsampledmx += diffx; lastsampledmy += diffy; +#endif + break; + + case mousehack_dontcare: +#if 0 + diffx = adjust (((lastmx - lastspr0x) * mstepx) >> 16); + diffy = adjust (((lastmy - lastspr0y) * mstepy) >> 16); + lastspr0x = lastmx; lastspr0y = lastmy; + mouse_x[0] += diffx; mouse_y[0] += diffy; +#endif + break; + + case mousehack_follow: + if (sprvbfl && sprvbfl-- > 1) { + int mousexpos, mouseypos; + + if ((lastdiffx > docal || lastdiffx < -docal) + && lastspr0x != spr0x + && spr0x > plfstrt*4 + 34 + xcaloff + && spr0x < plfstop*4 - xcaloff) + { + int val = (lastdiffx << 16) / (spr0x - lastspr0x); + if (val >= 0x8000) + mstepx = (mstepx * (calweight - 1) + val) / calweight; + } + if ((lastdiffy > docal || lastdiffy < -docal) + && lastspr0y != spr0y + && spr0y > plffirstline + ycaloff + && spr0y < plflastline - ycaloff) + { + int val = (lastdiffy << 16) / (spr0y - lastspr0y); + if (val >= 0x8000) + mstepy = (mstepy * (calweight - 1) + val) / calweight; + } + if (mouse_y[0] >= gfxvidinfo.height) + mouse_y[0] = gfxvidinfo.height-1; + mouseypos = coord_native_to_amiga_y (lastmy) << 1; + mousexpos = coord_native_to_amiga_x (lastmx); + diffx = adjust ((((mousexpos + xoffs - spr0x) & ~1) * mstepx) >> 16); + diffy = adjust ((((mouseypos + yoffs - spr0y) & ~1) * mstepy) >> 16); + lastspr0x = spr0x; lastspr0y = spr0y; + lastdiffx = diffx; lastdiffy = diffy; + mouse_x[0] += diffx; mouse_y[0] += diffy; + } + break; + + default: + abort (); + } +} + +int getbuttonstate (int joy, int button) +{ + return joybutton[joy] & (1 << button); +} + +static void mouseupdate (int pct) +{ + int v, i; + + for (i = 0; i < 2; i++) { + + v = mouse_delta[i][0] * pct / 100; + mouse_x[i] += v; + if (!mouse_deltanoreset[i][0]) + mouse_delta[i][0] -= v; + + v = mouse_delta[i][1] * pct / 100; + mouse_y[i] += v; + if (!mouse_deltanoreset[i][1]) + mouse_delta[i][1] -= v; + + v = mouse_delta[i][2] * pct / 100; + if (v > 0) + record_key (0x7a << 1); + else if (v < 0) + record_key (0x7b << 1); + if (!mouse_deltanoreset[i][2]) + mouse_delta[i][2] = 0; + + if (mouse_frame_x[i] - mouse_x[i] > 127) + mouse_x[i] = mouse_frame_x[i] - 127; + if (mouse_frame_x[i] - mouse_x[i] < -127) + mouse_x[i] = mouse_frame_x[i] + 127; + + if (mouse_frame_y[i] - mouse_y[i] > 127) + mouse_y[i] = mouse_frame_y[i] - 127; + if (mouse_frame_y[i] - mouse_y[i] < -127) + mouse_y[i] = mouse_frame_y[i] + 127; + + if (pct == 100) { + if (!mouse_deltanoreset[i][0]) + mouse_delta[i][0] = 0; + if (!mouse_deltanoreset[i][1]) + mouse_delta[i][1] = 0; + if (!mouse_deltanoreset[i][2]) + mouse_delta[i][2] = 0; + mouse_frame_x[i] = mouse_x[i]; + mouse_frame_y[i] = mouse_y[i]; + } + + } +} + +static int input_read, input_vpos; +extern int vpos; +static void readinput (void) +{ + if (!input_read && (vpos & ~31) != (input_vpos & ~31)) { + idev[IDTYPE_JOYSTICK].read (); + idev[IDTYPE_MOUSE].read (); + mouseupdate ((vpos - input_vpos) * 100 / maxvpos); + input_vpos = vpos; + } + if (input_read) { + input_vpos = vpos; + input_read = 0; + } +} + +int getjoystate (int joy) +{ + int left = 0, right = 0, top = 0, bot = 0; + uae_u16 v = 0; + + readinput (); + if (joydir[joy] & DIR_LEFT) + left = 1; + if (joydir[joy] & DIR_RIGHT) + right = 1; + if (joydir[joy] & DIR_UP) + top = 1; + if (joydir[joy] & DIR_DOWN) + bot = 1; + if (mouse_port[joy]) { + if (joy == 0) + do_mouse_hack (); + } + v = (uae_u8)mouse_x[joy] | (mouse_y[joy] << 8); + if (left || right || top || bot || !mouse_port[joy]) { + if (left) + top = !top; + if (right) + bot = !bot; + v &= ~0x0303; + v |= bot | (right << 1) | (top << 8) | (left << 9); + } +// write_log ("%d:%d:%04.4X %p\n",vpos,joy,v,m68k_getpc()); +#ifdef DONGLE_DEBUG + if (notinrom ()) + write_log ("JOY%dDAT %04.4X %s\n", joy, v, debuginfo (0)); +#endif + return v; +} + +uae_u16 JOY0DAT (void) +{ + return getjoystate (0); +} +uae_u16 JOY1DAT (void) +{ + return getjoystate (1); +} + +void JOYTEST (uae_u16 v) +{ + mouse_x[0] &= 3; + mouse_y[0] &= 3; + mouse_x[1] &= 3; + mouse_y[1] &= 3; + mouse_x[0] |= v & 0xFC; + mouse_x[1] |= v & 0xFC; + mouse_y[0] |= (v >> 8) & 0xFC; + mouse_y[1] |= (v >> 8) & 0xFC; + mouse_frame_x[0] = mouse_x[0]; + mouse_frame_y[0] = mouse_y[0]; + mouse_frame_x[1] = mouse_x[1]; + mouse_frame_y[1] = mouse_y[1]; +// write_log ("%d:%04.4X %p\n",vpos,v,m68k_getpc()); +} + +static uae_u8 parconvert (uae_u8 v, int jd, int shift) +{ + if (jd & DIR_UP) + v &= ~(1 << shift); + if (jd & DIR_DOWN) + v &= ~(2 << shift); + if (jd & DIR_LEFT) + v &= ~(4 << shift); + if (jd & DIR_RIGHT) + v &= ~(8 << shift); + return v; +} + +/* io-pins floating: dir=1 -> return data, dir=0 -> always return 1 */ +uae_u8 handle_parport_joystick (int port, uae_u8 pra, uae_u8 dra) +{ + uae_u8 v; + switch (port) + { + case 0: + v = (pra & dra) | (dra ^ 0xff); + if (parport_joystick_enabled) { + v = parconvert (v, joydir[2], 0); + v = parconvert (v, joydir[3], 4); + } + return v; + case 1: + v = ((pra & dra) | (dra ^ 0xff)) & 0x7; + if (parport_joystick_enabled) { + if (getbuttonstate (2, 0)) v &= ~1; + if (getbuttonstate (3, 0)) v &= ~4; + } + return v; + default: + abort (); + } +} + +uae_u8 handle_joystick_buttons (uae_u8 dra) +{ + uae_u8 but = 0; + if (!getbuttonstate (0, JOYBUTTON_1) && !getbuttonstate (0, JOYBUTTON_CD32_RED)) + but |= 0x40; + if (!getbuttonstate (1, JOYBUTTON_1) && !getbuttonstate (1, JOYBUTTON_CD32_RED)) + but |= 0x80; + //write_log("%02.2X %02.2X %08.8X\n", but, dra, m68k_getpc()); + return but; +} + +/* joystick 1 button 1 is used as a output for incrementing shift register */ +void handle_cd32_joystick_cia (uae_u8 pra, uae_u8 dra) +{ + static int oldstate[2]; + if ((dra & 0x80) && (pra & 0x80) != oldstate[1]) { + if (!(pra & 0x80)) + cd32_shifter[1]--; + if (cd32_shifter[1] < 0) + cd32_shifter[1] = 8; + oldstate[1] = pra & 0x80; + } + if ((dra & 0x40) && (pra & 0x40) != oldstate[0]) { + if (!(pra & 0x40)) + cd32_shifter[0]--; + if (cd32_shifter[0] < 0) + cd32_shifter[0] = 8; + oldstate[0] = pra & 0x40; + } +} + +/* joystick port 1 button 3 is used as a output for clearing shift register */ +static void handle_cd32_joystick_potgo (uae_u16 potgo) +{ + + if (potgo & 0x2000) { + if (!(potgo & 0x1000)) + cd32_shifter[1] = 8; + } + if (potgo & 0x0200) { + if (!(potgo & 0x0100)) + cd32_shifter[0] = 8; + } +#if 0 + int v; + static int oldstate[2]; + if (potgo & 0x2000) { + v = potgo & 0x1000; + if (v != oldstate[1]) { + if (v == 0x0000) + cd32_shifter[1] = 8; + oldstate[1] = v; + } + } + if (potgo & 0x0200) { + v = potgo & 0x0100; + if (v != oldstate[0]) { + if (v == 0x0000) + cd32_shifter[0] = 8; + oldstate[0] = v; + } + } +#endif +} + +/* joystick port 1 button 2 is input for button state */ +static uae_u16 handle_joystick_potgor (uae_u16 potgor) +{ + int i; + + for (i = 0; i < 2; i++) { + uae_u16 mask8 = 0x0800 << (i * 4); + uae_u16 mask4 = 0x0400 << (i * 4); + uae_u16 mask2 = 0x0200 << (i * 4); + uae_u16 mask1 = 0x0100 << (i * 4); + + if (mouse_port[i]) { + /* mouse has pull-up resistors in button lines */ + if (!(potgor & mask2)) + potgor |= mask1; + if (!(potgor & mask8)) + potgor |= mask4; + } + if (potgo_hsync < 0) { + /* first 10 or so lines after potgo has started + * forces input-lines to zero + */ + if (!(potgor & mask2)) + potgor &= ~mask1; + if (!(potgor & mask8)) + potgor &= ~mask4; + } + + if (cd32_pad_enabled[i]) { + if (!(potgor & mask8)) + potgor |= mask4; + if (!(potgor & mask1) || !(potgor & mask8)) { + if (cd32_shifter[i] <= 0) + potgor &= ~mask4; + if (cd32_shifter[i] >= 2 && (joybutton[i] & ((1 << JOYBUTTON_CD32_PLAY) << (cd32_shifter[i] - 2)))) + potgor &= ~mask4; + } + } else { + if (getbuttonstate (i, JOYBUTTON_3)) + potgor &= ~mask1; + } + if (getbuttonstate (i, JOYBUTTON_2) || getbuttonstate (i, JOYBUTTON_CD32_BLUE)) + potgor &= ~mask4; + } + return potgor; +} + +uae_u16 potgo_value; +static uae_u16 potdats[2]; +static int inputdelay; + +void inputdevice_hsync (void) +{ + int joy; + + for (joy = 0; joy < 2; joy++) { + if (potgo_hsync >= 0) { + int active; + + active = 0; + if ((potgo_value >> 9) & 1) /* output? */ + active = ((potgo_value >> 8) & 1) ? 0 : 1; + if (potgo_hsync < joydirpot[joy][0]) + active = 1; + if (getbuttonstate (joy, JOYBUTTON_3)) + active = 1; + if (active) + potdats[joy] = ((potdats[joy] + 1) & 0xFF) | (potdats[joy] & 0xFF00); + + active = 0; + if ((potgo_value >> 11) & 1) /* output? */ + active = ((potgo_value >> 10) & 1) ? 0 : 1; + if (potgo_hsync < joydirpot[joy][1]) + active = 1; + if (getbuttonstate (joy, JOYBUTTON_2)) + active = 1; + if (active) + potdats[joy] += 0x100; + } + } + potgo_hsync++; + if (potgo_hsync > 255) + potgo_hsync = 255; + + +#ifdef CATWEASEL + catweasel_hsync (); +#endif + if (inputdelay > 0) { + inputdelay--; + if (inputdelay == 0) { + idev[IDTYPE_JOYSTICK].read (); + idev[IDTYPE_KEYBOARD].read (); + } + } +} + +uae_u16 POT0DAT (void) +{ + return potdats[0]; +} +uae_u16 POT1DAT (void) +{ + return potdats[1]; +} + +/* direction=input, data pin floating, last connected logic level or previous status + written when direction was ouput + * otherwise it is currently connected logic level. + * direction=output, data pin is current value, forced to zero if joystick button is pressed + * it takes some tens of microseconds before data pin changes state + */ + +void POTGO (uae_u16 v) +{ + int i; + + //write_log ("W:%d: %04.4X %p\n", vpos, v, m68k_getpc()); +#ifdef DONGLE_DEBUG + if (notinrom ()) + write_log ("POTGO %04.4X %s\n", v, debuginfo(0)); +#endif + potgo_value = potgo_value & 0x5500; /* keep state of data bits */ + potgo_value |= v & 0xaa00; /* get new direction bits */ + for (i = 0; i < 8; i += 2) { + uae_u16 dir = 0x0200 << i; + if (v & dir) { + uae_u16 data = 0x0100 << i; + potgo_value &= ~data; + potgo_value |= v & data; + } + } + if (v & 1) { + potdats[0] = potdats[1] = 0; + potgo_hsync = -15; + } + handle_cd32_joystick_potgo (v); +} + +uae_u16 POTGOR (void) +{ + uae_u16 v = handle_joystick_potgor (potgo_value) & 0x5500; +#ifdef DONGLE_DEBUG + if (notinrom ()) + write_log ("POTGOR %04.4X %s\n", v, debuginfo(0)); +#endif + //write_log("R:%d:%04.4X %d %p\n", vpos, v, cd32_shifter[1], m68k_getpc()); + return v; +} + +static int check_input_queue (int event) +{ + struct input_queue_struct *iq; + int i; + for (i = 0; i < INPUT_QUEUE_SIZE; i++) { + iq = &input_queue[i]; + if (iq->event == event) return i; + } + return -1; +} + +static void queue_input_event (int event, int state, int max, int framecnt, int autofire) +{ + struct input_queue_struct *iq; + int i = check_input_queue (event); + + if (state < 0 && i >= 0) { + iq = &input_queue[i]; + iq->nextframecnt = -1; + iq->framecnt = -1; + iq->event = 0; + if (iq->state == 0) + handle_input_event (event, 0, 1, 0); + } else if (i < 0) { + for (i = 0; i < INPUT_QUEUE_SIZE; i++) { + iq = &input_queue[i]; + if (iq->framecnt < 0) break; + } + if (i == INPUT_QUEUE_SIZE) { + write_log ("input queue overflow\n"); + return; + } + iq->event = event; + iq->state = iq->storedstate = state; + iq->max = max; + iq->framecnt = framecnt; + iq->nextframecnt = autofire > 0 ? framecnt : -1; + } +} + +static uae_u8 keybuf[256]; + +void inputdevice_do_keyboard (int code, int state) +{ + if (code < 0x80) { + uae_u8 key = code | (state ? 0x00 : 0x80); + keybuf[key & 0x7f] = (key & 0x80) ? 0 : 1; + if (((keybuf[AK_CTRL] || keybuf[AK_RCTRL]) && keybuf[AK_LAMI] && keybuf[AK_RAMI]) || key == AK_RESETWARNING) { + int r = keybuf[AK_LALT] | keybuf[AK_RALT]; + memset (keybuf, 0, sizeof (keybuf)); + uae_reset (r); + } + record_key ((uae_u8)((key << 1) | (key >> 7))); + //write_log("Amiga key %02.2X %d\n", key & 0x7f, key >> 7); + return; + } + if (state == 0) + return; + switch (code) + { + case AKS_ENTERGUI: + gui_display (-1); + break; + case AKS_SCREENSHOT: + screenshot (1); + break; +#ifdef ACTION_REPLAY + case AKS_FREEZEBUTTON: + action_replay_freeze (); + break; +#endif + case AKS_FLOPPY0: + gui_display (0); + break; + case AKS_FLOPPY1: + gui_display (1); + break; + case AKS_FLOPPY2: + gui_display (2); + break; + case AKS_FLOPPY3: + gui_display (3); + break; + case AKS_EFLOPPY0: + disk_eject (0); + break; + case AKS_EFLOPPY1: + disk_eject (1); + break; + case AKS_EFLOPPY2: + disk_eject (2); + break; + case AKS_EFLOPPY3: + disk_eject (3); + break; + case AKS_IRQ7: + Interrupt (7); + break; + case AKS_PAUSE: + pausemode (-1); + break; + case AKS_WARP: + warpmode (-1); + break; + case AKS_INHIBITSCREEN: + toggle_inhibit_frame (IHF_SCROLLLOCK); + break; + case AKS_STATEREWIND: + savestate_dorewind(1); + break; + case AKS_VOLDOWN: + sound_volume (-1); + break; + case AKS_VOLUP: + sound_volume (1); + break; + case AKS_VOLMUTE: + sound_volume (0); + break; + case AKS_QUIT: + uae_quit (); + break; + case AKS_STATESAVE: + savestate_quick (0, 1); + break; + case AKS_STATERESTORE: + savestate_quick (0, 0); + break; + } +} + +void handle_input_event (int nr, int state, int max, int autofire) +{ + struct inputevent *ie; + int joy; + + if (nr <= 0) return; + ie = &events[nr]; + //write_log("'%s' %d %d\n", ie->name, state, max); + if (autofire) { + if (state) + queue_input_event (nr, state, max, currprefs.input_autofire_framecnt, 1); + else + queue_input_event (nr, -1, 0, 0, 1); + } + switch (ie->unit) + { + case 1: /* ->JOY1 */ + case 2: /* ->JOY2 */ + case 3: /* ->Parallel port joystick adapter port #1 */ + case 4: /* ->Parallel port joystick adapter port #2 */ + joy = ie->unit - 1; + if (ie->type & 4) { + if (state) + joybutton[joy] |= 1 << ie->data; + else + joybutton[joy] &= ~(1 << ie->data); + } else if (ie->type & 8) { + /* real mouse / analog stick mouse emulation */ + int delta; + int deadzone = currprefs.input_joymouse_deadzone * max / 100; + if (max) { + if (state < deadzone && state > -deadzone) { + state = 0; + } else if (state < 0) { + state += deadzone; + } else { + state -= deadzone; + } + max -= deadzone; + delta = state * currprefs.input_joymouse_multiplier / max; + } else { + delta = state; + } + mouse_delta[joy][ie->data] += delta; + } else if (ie->type & 32) { + int speed = currprefs.input_joymouse_speed; + + /* button mouse emulation */ + if (state && (ie->data & DIR_LEFT)) { + mouse_delta[joy][0] = -speed; + mouse_deltanoreset[joy][0] = 1; + } else if (state && (ie->data & DIR_RIGHT)) { + mouse_delta[joy][0] = speed; + mouse_deltanoreset[joy][0] = 1; + } else + mouse_deltanoreset[joy][0] = 0; + + if (state && (ie->data & DIR_UP)) { + mouse_delta[joy][1] = -speed; + mouse_deltanoreset[joy][1] = 1; + } else if (state && (ie->data & DIR_DOWN)) { + mouse_delta[joy][1] = speed; + mouse_deltanoreset[joy][1] = 1; + } else + mouse_deltanoreset[joy][1] = 0; + + } else if (ie->type & 64) { /* analog (paddle) */ + int deadzone = currprefs.input_joymouse_deadzone * max / 100; + if (max) { + if (state < deadzone && state > -deadzone) { + state = 0; + } else if (state < 0) { + state += deadzone; + } else { + state -= deadzone; + } + state = state * max / (max - deadzone); + } + state = state / 256 + 128; + joydirpot[joy][ie->data] = state; + } else { + int left = oleft[joy], right = oright[joy], top = otop[joy], bot = obot[joy]; + if (ie->type & 16) { + /* button to axis mapping */ + if (ie->data & DIR_LEFT) left = oleft[joy] = state ? 1 : 0; + if (ie->data & DIR_RIGHT) right = oright[joy] = state ? 1 : 0; + if (ie->data & DIR_UP) top = otop[joy] = state ? 1 : 0; + if (ie->data & DIR_DOWN) bot = obot[joy] = state ? 1 : 0; + } else { + /* "normal" joystick axis */ + int deadzone = currprefs.input_joystick_deadzone * max / 100; + int neg, pos; + if (state < deadzone && state > -deadzone) + state = 0; + neg = state < 0 ? 1 : 0; + pos = state > 0 ? 1 : 0; + if (ie->data & DIR_LEFT) left = oleft[joy] = neg; + if (ie->data & DIR_RIGHT) right = oright[joy] = pos; + if (ie->data & DIR_UP) top = otop[joy] = neg; + if (ie->data & DIR_DOWN) bot = obot[joy] = pos; + } + joydir[joy] = 0; + if (left) joydir[joy] |= DIR_LEFT; + if (right) joydir[joy] |= DIR_RIGHT; + if (top) joydir[joy] |= DIR_UP; + if (bot) joydir[joy] |= DIR_DOWN; + } + break; + case 0: /* ->KEY */ + inputdevice_do_keyboard (ie->data, state); + break; + } +} + +void inputdevice_vsync (void) +{ + struct input_queue_struct *iq; + int i; + + for (i = 0; i < INPUT_QUEUE_SIZE; i++) { + iq = &input_queue[i]; + if (iq->framecnt > 0) { + iq->framecnt--; + if (iq->framecnt == 0) { + if (iq->state) iq->state = 0; else iq->state = iq->storedstate; + handle_input_event (iq->event, iq->state, iq->max, 0); + iq->framecnt = iq->nextframecnt; + } + } + } + mouseupdate (100); + inputdelay = rand () % (maxvpos - 1); + idev[IDTYPE_MOUSE].read (); + input_read = 1; + input_vpos = 0; +} + +static void setbuttonstateall (struct uae_input_device *id, struct uae_input_device2 *id2, int button, int state) +{ + int event, autofire, i; + uae_u32 mask = 1 << button; + uae_u32 omask = id2->buttonmask & mask; + uae_u32 nmask = (state ? 1 : 0) << button; + + if (button >= ID_BUTTON_TOTAL) + return; + for (i = 0; i < MAX_INPUT_SUB_EVENT; i++) { + event = id->eventid[ID_BUTTON_OFFSET + button][sublevdir[state <= 0 ? 0 : 1][i]]; + if (event <= 0) + continue; + autofire = (id->flags[ID_BUTTON_OFFSET + button][sublevdir[state <= 0 ? 0 : 1][i]] & ID_FLAG_AUTOFIRE) ? 1 : 0; + if (state < 0) { + handle_input_event (event, 1, 1, 0); + queue_input_event (event, 0, 1, 1, 0); /* send release event next frame */ + } else { + if ((omask ^ nmask) & mask) + handle_input_event (event, state, 1, autofire); + } + } + if ((omask ^ nmask) & mask) { + if (state) + id2->buttonmask |= mask; + else + id2->buttonmask &= ~mask; + } +} + + +/* - detect required number of joysticks and mice from configuration data + * - detect if CD32 pad emulation is needed + * - detect device type in ports (mouse or joystick) + */ + +static int iscd32 (int ei) +{ + if (ei >= INPUTEVENT_JOY1_CD32_FIRST && ei <= INPUTEVENT_JOY1_CD32_LAST) { + cd32_pad_enabled[0] = 1; + return 1; + } + if (ei >= INPUTEVENT_JOY2_CD32_FIRST && ei <= INPUTEVENT_JOY2_CD32_LAST) { + cd32_pad_enabled[1] = 1; + return 2; + } + return 0; +} + +static int isparport (int ei) +{ + if (ei > INPUTEVENT_PAR_JOY1_START && ei < INPUTEVENT_PAR_JOY_END) { + parport_joystick_enabled = 1; + return 1; + } + return 0; +} + +static int ismouse (int ei) +{ + if (ei >= INPUTEVENT_MOUSE1_FIRST && ei <= INPUTEVENT_MOUSE1_LAST) { + mouse_port[0] = 1; + return 1; + } + if (ei >= INPUTEVENT_MOUSE2_FIRST && ei <= INPUTEVENT_MOUSE2_LAST) { + mouse_port[1] = 1; + return 2; + } + return 0; +} + +#ifdef CD32 +extern int cd32_enabled; +#endif + +static void scanevents(struct uae_prefs *p) +{ + int i, j, k, ei; + struct inputevent *e; + int n_joy = idev[IDTYPE_JOYSTICK].get_num(); + int n_mouse = idev[IDTYPE_MOUSE].get_num(); + + cd32_pad_enabled[0] = cd32_pad_enabled[1] = 0; + parport_joystick_enabled = 0; + mouse_port[0] = mouse_port[1] = 0; + for (i = 0; i < MAX_INPUT_DEVICE_EVENTS; i++) + joydir[i] = 0; + + for (i = 0; i < MAX_INPUT_DEVICES; i++) { + use_joysticks[i] = 0; + use_mice[i] = 0; + for (k = 0; k < MAX_INPUT_SUB_EVENT; k++) { + for (j = 0; j < ID_BUTTON_TOTAL; j++) { + + if (joysticks[i].enabled && i < n_joy) { + ei = joysticks[i].eventid[ID_BUTTON_OFFSET + j][k]; + e = &events[ei]; + iscd32 (ei); + isparport (ei); + ismouse (ei); + if (joysticks[i].eventid[ID_BUTTON_OFFSET + j][k] > 0) + use_joysticks[i] = 1; + } + if (mice[i].enabled && i < n_mouse) { + ei = mice[i].eventid[ID_BUTTON_OFFSET + j][k]; + e = &events[ei]; + iscd32 (ei); + isparport (ei); + ismouse (ei); + if (mice[i].eventid[ID_BUTTON_OFFSET + j][k] > 0) + use_mice[i] = 1; + } + + } + + for (j = 0; j < ID_AXIS_TOTAL; j++) { + + if (joysticks[i].enabled && i < n_joy) { + ei = joysticks[i].eventid[ID_AXIS_OFFSET + j][k]; + iscd32 (ei); + isparport (ei); + ismouse (ei); + if (ei > 0) + use_joysticks[i] = 1; + } + if (mice[i].enabled && i < n_mouse) { + ei = mice[i].eventid[ID_AXIS_OFFSET + j][k]; + iscd32 (ei); + isparport (ei); + ismouse (ei); + if (ei > 0) + use_mice[i] = 1; + } + } + } + } + for (i = 0; i < MAX_INPUT_DEVICES; i++) { + use_keyboards[i] = 0; + if (keyboards[i].enabled && i < idev[IDTYPE_KEYBOARD].get_num()) { + j = 0; + while (keyboards[i].extra[j][0] >= 0) { + use_keyboards[i] = 1; + for (k = 0; k < MAX_INPUT_SUB_EVENT; k++) { + ei = keyboards[i].eventid[j][k]; + iscd32 (ei); + isparport (ei); + ismouse (ei); + } + j++; + } + } + } +} + +static void compatibility_mode (struct uae_prefs *prefs) +{ + int joy, i; + + for (i = 0; i < MAX_INPUT_DEVICES; i++) { + memset (&mice[i], 0, sizeof (*mice)); + memset (&joysticks[i], 0, sizeof (*joysticks)); + } + + /* mouse compatibility code */ + if (JSEM_ISMOUSE (0, prefs)) { + mice[0].eventid[ID_AXIS_OFFSET + 0][0] = INPUTEVENT_MOUSE1_HORIZ; + mice[0].eventid[ID_AXIS_OFFSET + 1][0] = INPUTEVENT_MOUSE1_VERT; + mice[0].eventid[ID_AXIS_OFFSET + 2][0] = INPUTEVENT_MOUSE1_WHEEL; + mice[0].eventid[ID_BUTTON_OFFSET + 0][0] = INPUTEVENT_JOY1_FIRE_BUTTON; + mice[0].eventid[ID_BUTTON_OFFSET + 1][0] = INPUTEVENT_JOY1_2ND_BUTTON; + mice[0].eventid[ID_BUTTON_OFFSET + 2][0] = INPUTEVENT_JOY1_3RD_BUTTON; + mice[0].enabled = 1; + } else if (JSEM_ISMOUSE (1, prefs)) { + mice[0].eventid[ID_AXIS_OFFSET + 0][0] = INPUTEVENT_MOUSE2_HORIZ; + mice[0].eventid[ID_AXIS_OFFSET + 1][0] = INPUTEVENT_MOUSE2_VERT; + mice[0].eventid[ID_BUTTON_OFFSET + 0][0] = INPUTEVENT_JOY2_FIRE_BUTTON; + mice[0].eventid[ID_BUTTON_OFFSET + 1][0] = INPUTEVENT_JOY2_2ND_BUTTON; + mice[0].eventid[ID_BUTTON_OFFSET + 2][0] = INPUTEVENT_JOY2_3RD_BUTTON; + mice[0].enabled = 1; + } + + /* joystick 2 compatibility code */ + joy = -1; + if (JSEM_ISJOY0 (1, prefs)) + joy = 0; + else if (JSEM_ISJOY1 (1, prefs)) + joy = 1; + if (joy >= 0) { + joysticks[joy].eventid[ID_AXIS_OFFSET + 0][0] = INPUTEVENT_JOY2_HORIZ; + joysticks[joy].eventid[ID_AXIS_OFFSET + 1][0] = INPUTEVENT_JOY2_VERT; +#ifdef CD32 + if (cd32_enabled) { + joysticks[joy].eventid[ID_BUTTON_OFFSET + 0][0] = INPUTEVENT_JOY2_FIRE_BUTTON; + joysticks[joy].eventid[ID_BUTTON_OFFSET + 1][0] = INPUTEVENT_JOY2_CD32_RED; + joysticks[joy].eventid[ID_BUTTON_OFFSET + 2][0] = INPUTEVENT_JOY2_CD32_BLUE; + joysticks[joy].eventid[ID_BUTTON_OFFSET + 3][0] = INPUTEVENT_JOY2_CD32_YELLOW; + joysticks[joy].eventid[ID_BUTTON_OFFSET + 4][0] = INPUTEVENT_JOY2_CD32_GREEN; + joysticks[joy].eventid[ID_BUTTON_OFFSET + 5][0] = INPUTEVENT_JOY2_CD32_FFW; + joysticks[joy].eventid[ID_BUTTON_OFFSET + 6][0] = INPUTEVENT_JOY2_CD32_RWD; + joysticks[joy].eventid[ID_BUTTON_OFFSET + 7][0] = INPUTEVENT_JOY2_CD32_PLAY; + } else { +#endif + joysticks[joy].eventid[ID_BUTTON_OFFSET + 0][0] = INPUTEVENT_JOY2_FIRE_BUTTON; + joysticks[joy].eventid[ID_BUTTON_OFFSET + 1][0] = INPUTEVENT_JOY2_2ND_BUTTON; + joysticks[joy].eventid[ID_BUTTON_OFFSET + 2][0] = INPUTEVENT_JOY2_3RD_BUTTON; +#ifdef CD32 + } +#endif + joysticks[joy].enabled = 1; + } + if (JSEM_ISNUMPAD (1, prefs) || JSEM_ISCURSOR (1, prefs) || JSEM_ISSOMEWHEREELSE (1, prefs)) { + joysticks[3].eventid[ID_AXIS_OFFSET + 0][0] = INPUTEVENT_JOY2_HORIZ; + joysticks[3].eventid[ID_AXIS_OFFSET + 1][0] = INPUTEVENT_JOY2_VERT; + joysticks[3].eventid[ID_BUTTON_OFFSET + 0][0] = INPUTEVENT_JOY2_FIRE_BUTTON; + joysticks[3].eventid[ID_BUTTON_OFFSET + 1][0] = INPUTEVENT_JOY2_2ND_BUTTON; + joysticks[3].eventid[ID_BUTTON_OFFSET + 2][0] = INPUTEVENT_JOY2_3RD_BUTTON; + joysticks[3].enabled = 1; + } + + + /* joystick 1 compatibility code */ + joy = -1; + if (JSEM_ISJOY0 (0, prefs)) + joy = 0; + else if (JSEM_ISJOY1 (0, prefs)) + joy = 1; + if (joy >= 0) { + joysticks[joy].eventid[ID_AXIS_OFFSET + 0][0] = INPUTEVENT_JOY1_HORIZ; + joysticks[joy].eventid[ID_AXIS_OFFSET + 1][0] = INPUTEVENT_JOY1_VERT; + joysticks[joy].eventid[ID_BUTTON_OFFSET + 0][0] = INPUTEVENT_JOY1_FIRE_BUTTON; + joysticks[joy].eventid[ID_BUTTON_OFFSET + 1][0] = INPUTEVENT_JOY1_2ND_BUTTON; + joysticks[joy].eventid[ID_BUTTON_OFFSET + 2][0] = INPUTEVENT_JOY1_3RD_BUTTON; + joysticks[joy].enabled = 1; + } + if (JSEM_ISNUMPAD (0, prefs) || JSEM_ISCURSOR (0, prefs) || JSEM_ISSOMEWHEREELSE (0, prefs)) { + joysticks[2].eventid[ID_AXIS_OFFSET + 0][0] = INPUTEVENT_JOY1_HORIZ; + joysticks[2].eventid[ID_AXIS_OFFSET + 1][0] = INPUTEVENT_JOY1_VERT; + joysticks[2].eventid[ID_BUTTON_OFFSET + 0][0] = INPUTEVENT_JOY1_FIRE_BUTTON; + joysticks[2].eventid[ID_BUTTON_OFFSET + 1][0] = INPUTEVENT_JOY1_2ND_BUTTON; + joysticks[2].eventid[ID_BUTTON_OFFSET + 2][0] = INPUTEVENT_JOY1_3RD_BUTTON; + joysticks[2].enabled = 1; + } +} + +void inputdevice_updateconfig (struct uae_prefs *prefs) +{ + int i; + + if (currprefs.jport0 != changed_prefs.jport0 + || currprefs.jport1 != changed_prefs.jport1) { + currprefs.jport0 = changed_prefs.jport0; + currprefs.jport1 = changed_prefs.jport1; + } + joybutton[0] = joybutton[1] = 0; + joydir[0] = joydir[1] = 0; + oldmx[0] = oldmx[1] = -1; + oldmy[0] = oldmy[1] = -1; + cd32_shifter[0] = cd32_shifter[1] = 8; + oleft[0] = oleft[1] = 0; + oright[0] = oright[1] = 0; + otop[0] = otop[1] = 0; + obot[0] = obot[1] = 0; + for (i = 0; i < 2; i++) { + mouse_deltanoreset[i][0] = 0; + mouse_delta[i][0] = 0; + mouse_deltanoreset[i][1] = 0; + mouse_delta[i][1] = 0; + mouse_deltanoreset[i][2] = 0; + mouse_delta[i][2] = 0; + } + memset (keybuf, 0, sizeof (keybuf)); + + for (i = 0; i < INPUT_QUEUE_SIZE; i++) + input_queue[i].framecnt = input_queue[i].nextframecnt = -1; + + for (i = 0; i < MAX_INPUT_SUB_EVENT; i++) { + sublevdir[0][i] = i; + sublevdir[1][i] = MAX_INPUT_SUB_EVENT - i - 1; + } + + joysticks = prefs->joystick_settings[prefs->input_selected_setting]; + mice = prefs->mouse_settings[prefs->input_selected_setting]; + keyboards = prefs->keyboard_settings[prefs->input_selected_setting]; + + memset (joysticks2, 0, sizeof (joysticks2)); + memset (mice2, 0, sizeof (mice2)); + if (prefs->input_selected_setting == 0) + compatibility_mode (prefs); + + joystick_setting_changed (); + + scanevents (prefs); + +#ifdef CD32 + if (currprefs.input_selected_setting == 0 && cd32_enabled) + cd32_pad_enabled[1] = 1; +#endif +} + +static void set_kbr_default (struct uae_prefs *p, int index, int num) +{ + int i, j, k, l; + struct uae_input_device_kbr_default *trans = keyboard_default; + struct uae_input_device *kbr; + struct inputdevice_functions *id = &idev[IDTYPE_KEYBOARD]; + uae_u32 scancode; + + if (!trans) + return; + for (j = 0; j < MAX_INPUT_DEVICES; j++) { + kbr = &p->keyboard_settings[index][j]; + for (i = 0; i < MAX_INPUT_DEVICE_EVENTS; i++) { + memset (kbr, 0, sizeof (struct uae_input_device)); + kbr->extra[i][0] = -1; + } + if (j < id->get_num ()) { + if (j == 0) + kbr->enabled = 1; + for (i = 0; i < id->get_widget_num (num); i++) { + id->get_widget_type (num, i, 0, &scancode); + kbr->extra[i][0] = scancode; + l = 0; + while (trans[l].scancode >= 0) { + if (kbr->extra[i][0] == trans[l].scancode) { + for (k = 0; k < MAX_INPUT_SUB_EVENT; k++) { + if (kbr->eventid[i][k] == 0) break; + } + if (k == MAX_INPUT_SUB_EVENT) { + write_log ("corrupt default keyboard mappings\n"); + return; + } + kbr->eventid[i][k] = trans[l].event; + break; + } + l++; + } + } + } + } +} + +void inputdevice_default_prefs (struct uae_prefs *p) +{ + int i; + + inputdevice_init (); + p->input_joymouse_multiplier = 20; + p->input_joymouse_deadzone = 33; + p->input_joystick_deadzone = 33; + p->input_joymouse_speed = 10; + p->input_mouse_speed = 100; + p->input_autofire_framecnt = 10; + for (i = 0; i <= MAX_INPUT_SETTINGS; i++) { + set_kbr_default (p, i, 0); + input_get_default_mouse (p->mouse_settings[i]); + input_get_default_joystick (p->joystick_settings[i]); + } +} + +void inputdevice_setkeytranslation (struct uae_input_device_kbr_default *trans) +{ + keyboard_default = trans; +} + +int inputdevice_translatekeycode (int keyboard, int scancode, int state) +{ + struct uae_input_device *na = &keyboards[keyboard]; + int j, k; + + if (!keyboards || scancode < 0) + return 0; + j = 0; + while (na->extra[j][0] >= 0) { + if (na->extra[j][0] == scancode) { + for (k = 0; k < MAX_INPUT_SUB_EVENT; k++) {/* send key release events in reverse order */ + int autofire = (na->flags[j][sublevdir[state == 0 ? 1 : 0][k]] & ID_FLAG_AUTOFIRE) ? 1 : 0; + int event = na->eventid[j][sublevdir[state == 0 ? 1 : 0][k]]; + handle_input_event (event, state, 1, autofire); + //write_log ("'%s' %d ('%s') %d\n", na->name, event, events[event].name, state); + } + return 1; + } + j++; + } + return 0; +} + +static struct inputdevice_functions idev[3]; + +void inputdevice_init (void) +{ + idev[IDTYPE_JOYSTICK] = inputdevicefunc_joystick; + idev[IDTYPE_JOYSTICK].init (); + idev[IDTYPE_MOUSE] = inputdevicefunc_mouse; + idev[IDTYPE_MOUSE].init (); + idev[IDTYPE_KEYBOARD] = inputdevicefunc_keyboard; + idev[IDTYPE_KEYBOARD].init (); +} + +void inputdevice_close (void) +{ + idev[IDTYPE_JOYSTICK].close (); + idev[IDTYPE_MOUSE].close (); + idev[IDTYPE_KEYBOARD].close (); +} + +static struct uae_input_device *get_uid (struct inputdevice_functions *id, int devnum) +{ + struct uae_input_device *uid = 0; + if (id == &idev[IDTYPE_JOYSTICK]) { + uid = &joysticks[devnum]; + } else if (id == &idev[IDTYPE_MOUSE]) { + uid = &mice[devnum]; + } else if (id == &idev[IDTYPE_KEYBOARD]) { + uid = &keyboards[devnum]; + } + return uid; +} + +static int get_event_data (struct inputdevice_functions *id, int devnum, int num, int *eventid, int *flags, int sub) +{ + struct uae_input_device *uid = get_uid (id, devnum); + int type = id->get_widget_type (devnum, num, 0, 0); + int i; + if (type == IDEV_WIDGET_BUTTON) { + i = num - id->get_widget_first (devnum, type); + *eventid = uid->eventid[ID_BUTTON_OFFSET + i][sub]; + *flags = uid->flags[ID_BUTTON_OFFSET + i][sub]; + return i; + } else if (type == IDEV_WIDGET_AXIS) { + i = num - id->get_widget_first (devnum, type); + *eventid = uid->eventid[ID_AXIS_OFFSET + i][sub]; + *flags = uid->flags[ID_AXIS_OFFSET + i][sub]; + return i; + } else if (type == IDEV_WIDGET_KEY) { + i = num - id->get_widget_first (devnum, type); + *eventid = uid->eventid[i][sub]; + *flags = uid->flags[i][sub]; + return i; + } + return -1; +} + +static int put_event_data (struct inputdevice_functions *id, int devnum, int num, int eventid, int flags, int sub) +{ + struct uae_input_device *uid = get_uid (id, devnum); + int type = id->get_widget_type (devnum, num, 0, 0); + int i; + if (type == IDEV_WIDGET_BUTTON) { + i = num - id->get_widget_first (devnum, type); + uid->eventid[ID_BUTTON_OFFSET + i][sub] = eventid; + uid->flags[ID_BUTTON_OFFSET + i][sub] = flags; + return i; + } else if (type == IDEV_WIDGET_AXIS) { + i = num - id->get_widget_first (devnum, type); + uid->eventid[ID_AXIS_OFFSET + i][sub] = eventid; + uid->flags[ID_AXIS_OFFSET + i][sub] = flags; + return i; + } else if (type == IDEV_WIDGET_KEY) { + i = num - id->get_widget_first (devnum, type); + uid->eventid[i][sub] = eventid; + uid->flags[i][sub] = flags; + return i; + } + return -1; +} + +static int is_event_used (struct inputdevice_functions *id, int devnum, int isnum, int isevent) +{ + struct uae_input_device *uid = get_uid (id, devnum); + int num, event, flag, sub; + + for (num = 0; num < id->get_widget_num (devnum); num++) { + for (sub = 0; sub < MAX_INPUT_SUB_EVENT; sub++) { + if (get_event_data (id, devnum, num, &event, &flag, sub) >= 0) { + if (event == isevent && isnum != num) + return 1; + } + } + } + return 0; +} + +int inputdevice_get_device_index (int devnum) +{ + if (devnum < idev[IDTYPE_JOYSTICK].get_num()) + return devnum; + else if (devnum < idev[IDTYPE_JOYSTICK].get_num() + idev[IDTYPE_MOUSE].get_num()) + return devnum - idev[IDTYPE_JOYSTICK].get_num(); + else + return devnum - idev[IDTYPE_JOYSTICK].get_num() - idev[IDTYPE_MOUSE].get_num(); +} + +static int gettype (int devnum) +{ + if (devnum < idev[IDTYPE_JOYSTICK].get_num()) + return IDTYPE_JOYSTICK; + else if (devnum < idev[IDTYPE_JOYSTICK].get_num() + idev[IDTYPE_MOUSE].get_num()) + return IDTYPE_MOUSE; + else if (devnum < idev[IDTYPE_JOYSTICK].get_num() + idev[IDTYPE_MOUSE].get_num() + idev[IDTYPE_KEYBOARD].get_num()) + return IDTYPE_KEYBOARD; + else + return -1; +} + +static struct inputdevice_functions *getidf (int devnum) +{ + return &idev[gettype (devnum)]; +} + + +/* returns number of devices of type "type" */ +int inputdevice_get_device_total (int type) +{ + return idev[type].get_num (); +} +/* returns the name of device */ +char *inputdevice_get_device_name (int type, int devnum) +{ + return idev[type].get_name (devnum); +} +/* returns state (enabled/disabled) */ +int inputdevice_get_device_status (int devnum) +{ + struct inputdevice_functions *idf = getidf (devnum); + struct uae_input_device *uid = get_uid (idf, inputdevice_get_device_index (devnum)); + return uid->enabled; +} + +/* set state (enabled/disabled) */ +void inputdevice_set_device_status (int devnum, int enabled) +{ + struct inputdevice_functions *idf = getidf (devnum); + struct uae_input_device *uid = get_uid (idf, inputdevice_get_device_index (devnum)); + uid->enabled = enabled; +} + +/* returns number of axis/buttons and keys from selected device */ +int inputdevice_get_widget_num (int devnum) +{ + struct inputdevice_functions *idf = getidf (devnum); + return idf->get_widget_num (inputdevice_get_device_index (devnum)); +} + +static void get_ename (struct inputevent *ie, char *out) +{ + if (!out) + return; + if (ie->allow_mask == AM_K) + sprintf (out, "%s (0x%02.2X)", ie->name, ie->data); + else + strcpy (out, ie->name); +} + +int inputdevice_iterate (int devnum, int num, char *name, int *af) +{ + struct inputdevice_functions *idf = getidf (devnum); + static int id_iterator; + struct inputevent *ie; + int mask, data, flags, type; + int devindex = inputdevice_get_device_index (devnum); + + *af = 0; + *name = 0; + for (;;) { + ie = &events[++id_iterator]; + if (!ie->confname) { + id_iterator = 0; + return 0; + } + mask = 0; + type = idf->get_widget_type (devindex, num, 0, 0); + if (type == IDEV_WIDGET_BUTTON) { + if (idf == &idev[IDTYPE_JOYSTICK]) { + mask |= AM_JOY_BUT; + } else { + mask |= AM_MOUSE_BUT; + } + } else if (type == IDEV_WIDGET_AXIS) { + if (idf == &idev[IDTYPE_JOYSTICK]) { + mask |= AM_JOY_AXIS; + } else { + mask |= AM_MOUSE_AXIS; + } + } else if (type == IDEV_WIDGET_KEY) { + mask |= AM_K; + } + if (ie->allow_mask & AM_INFO) { + struct inputevent *ie2 = ie + 1; + while (!(ie2->allow_mask & AM_INFO)) { + if (is_event_used (idf, devindex, ie2 - ie, -1)) { + ie2++; + continue; + } + if (ie2->allow_mask & mask) break; + ie2++; + } + if (!(ie2->allow_mask & AM_INFO)) + mask |= AM_INFO; + } + if (!(ie->allow_mask & mask)) + continue; + get_event_data (idf, devindex, num, &data, &flags, 0); + get_ename (ie, name); + *af = (flags & ID_FLAG_AUTOFIRE) ? 1 : 0; + return 1; + } +} + +int inputdevice_get_mapped_name (int devnum, int num, int *pflags, char *name, int sub) +{ + struct inputdevice_functions *idf = getidf (devnum); + struct uae_input_device *uid = get_uid (idf, inputdevice_get_device_index (devnum)); + int flags = 0, flag, data; + int devindex = inputdevice_get_device_index (devnum); + + if (name) + strcpy (name, ""); + if (pflags) + *pflags = 0; + if (uid == 0 || num < 0) + return 0; + if (get_event_data (idf, devindex, num, &data, &flag, sub) < 0) + return 0; + if (flag & ID_FLAG_AUTOFIRE) + flags |= IDEV_MAPPED_AUTOFIRE_SET; + if (!data) return 0; + if (events[data].allow_mask & AM_AF) + flags |= IDEV_MAPPED_AUTOFIRE_POSSIBLE; + if (pflags) + *pflags = flags; + get_ename (&events[data], name); + return data; +} + +int inputdevice_set_mapping (int devnum, int num, char *name, int af, int sub) +{ + struct inputdevice_functions *idf = getidf (devnum); + struct uae_input_device *uid = get_uid (idf, inputdevice_get_device_index (devnum)); + int eid, data, flag, amask; + char ename[256]; + int devindex = inputdevice_get_device_index (devnum); + + if (uid == 0 || num < 0) + return 0; + if (name) { + eid = 1; + while (events[eid].name) { + get_ename (&events[eid], ename); + if (!strcmp(ename, name)) break; + eid++; + } + if (!events[eid].name) + return 0; + if (events[eid].allow_mask & AM_INFO) + return 0; + } else { + eid = 0; + } + if (get_event_data (idf, devindex, num, &data, &flag, sub) < 0) + return 0; + if (data >= 0) { + amask = events[eid].allow_mask; + flag &= ~ID_FLAG_AUTOFIRE; + if (amask & AM_AF) + flag |= af ? ID_FLAG_AUTOFIRE : 0; + put_event_data (idf, devindex, num, eid, flag, sub); + return 1; + } + return 0; +} + +int inputdevice_get_widget_type (int devnum, int num, char *name) +{ + struct inputdevice_functions *idf = getidf (devnum); + return idf->get_widget_type (inputdevice_get_device_index (devnum), num, name, 0); +} + +static int config_change; + +void inputdevice_config_change (void) +{ + config_change = 1; +} + +int inputdevice_config_change_test (void) +{ + int v = config_change; + config_change = 0; + return v; +} + +void inputdevice_copyconfig (struct uae_prefs *src, struct uae_prefs *dst) +{ + int i, j; + + dst->input_selected_setting = src->input_selected_setting; + dst->input_joymouse_multiplier = src->input_joymouse_multiplier; + dst->input_joymouse_deadzone = src->input_joymouse_deadzone; + dst->input_joystick_deadzone = src->input_joystick_deadzone; + dst->input_joymouse_speed = src->input_joymouse_speed; + dst->input_mouse_speed = src->input_mouse_speed; + dst->input_autofire_framecnt = src->input_autofire_framecnt; + dst->jport0 = src->jport0; + dst->jport1 = src->jport1; + + for (i = 0; i < MAX_INPUT_SETTINGS + 1; i++) { + for (j = 0; j < MAX_INPUT_DEVICES; j++) { + memcpy (&dst->joystick_settings[i][j], &src->joystick_settings[i][j], sizeof (struct uae_input_device)); + memcpy (&dst->mouse_settings[i][j], &src->mouse_settings[i][j], sizeof (struct uae_input_device)); + memcpy (&dst->keyboard_settings[i][j], &src->keyboard_settings[i][j], sizeof (struct uae_input_device)); + } + } + + inputdevice_updateconfig (dst); +} + +void inputdevice_swap_ports (struct uae_prefs *p, int devnum) +{ + struct inputdevice_functions *idf = getidf (devnum); + struct uae_input_device *uid = get_uid (idf, inputdevice_get_device_index (devnum)); + int i, j, k, event, unit; + struct inputevent *ie, *ie2; + + for (i = 0; i < MAX_INPUT_DEVICE_EVENTS; i++) { + for (j = 0; j < MAX_INPUT_SUB_EVENT; j++) { + event = uid->eventid[i][j]; + if (event <= 0) + continue; + ie = &events[event]; + if (ie->unit <= 0) + continue; + unit = ie->unit; + k = 1; + while (events[k].confname) { + ie2 = &events[k]; + if (ie2->type == ie->type && ie2->data == ie->data && ie2->unit - 1 == ((ie->unit - 1) ^ 1) && ie2->allow_mask == ie->allow_mask) { + uid->eventid[i][j] = k; + break; + } + k++; + } + } + } +} + +void inputdevice_copy_single_config (struct uae_prefs *p, int src, int dst, int devnum) +{ + if (src == dst) + return; + if (devnum < 0 || gettype (devnum) == IDTYPE_JOYSTICK) + memcpy (p->joystick_settings[dst], p->joystick_settings[src], sizeof (struct uae_input_device) * MAX_INPUT_DEVICES); + if (devnum < 0 || gettype (devnum) == IDTYPE_MOUSE) + memcpy (p->mouse_settings[dst], p->mouse_settings[src], sizeof (struct uae_input_device) * MAX_INPUT_DEVICES); + if (devnum < 0 || gettype (devnum) == IDTYPE_KEYBOARD) + memcpy (p->keyboard_settings[dst], p->keyboard_settings[src], sizeof (struct uae_input_device) * MAX_INPUT_DEVICES); +} + +void inputdevice_acquire (int exclusive) +{ + int i; + + inputdevice_unacquire (); + for (i = 0; i < MAX_INPUT_DEVICES; i++) { + if (use_joysticks[i]) + idev[IDTYPE_JOYSTICK].acquire (i, 0); + } + for (i = 0; i < MAX_INPUT_DEVICES; i++) { + if (use_mice[i]) + idev[IDTYPE_MOUSE].acquire (i, 0); + } + for (i = 0; i < MAX_INPUT_DEVICES; i++) { + if (use_keyboards[i]) + idev[IDTYPE_KEYBOARD].acquire (i, 0); + } +} + +void inputdevice_unacquire (void) +{ + int i; + + for (i = 0; i < MAX_INPUT_DEVICES; i++) + idev[IDTYPE_JOYSTICK].unacquire (i); + for (i = 0; i < MAX_INPUT_DEVICES; i++) + idev[IDTYPE_MOUSE].unacquire (i); + for (i = 0; i < MAX_INPUT_DEVICES; i++) + idev[IDTYPE_KEYBOARD].unacquire (i); +} + +/* Call this function when host machine's joystick/joypad/etc button state changes + * This function translates button events to Amiga joybutton/joyaxis/keyboard events + */ + +/* button states: + * state = -1 -> mouse wheel turned or similar (button without release) + * state = 1 -> button pressed + * state = 0 -> button released + */ + +void setjoybuttonstate (int joy, int button, int state) +{ + if (!joysticks[joy].enabled) + return; + setbuttonstateall (&joysticks[joy], &joysticks2[joy], button, state ? 1 : 0); +} + +/* buttonmask = 1 = normal toggle button, 0 = mouse wheel turn or similar + */ +void setjoybuttonstateall (int joy, uae_u32 buttonbits, uae_u32 buttonmask) +{ + int i; + + if (!joysticks[joy].enabled) + return; + for (i = 0; i < ID_BUTTON_TOTAL; i++) { + if (buttonmask & (1 << i)) + setbuttonstateall (&joysticks[joy], &joysticks2[joy], i, (buttonbits & (1 << i)) ? 1 : 0); + else if (buttonbits & (1 << i)) + setbuttonstateall (&joysticks[joy], &joysticks2[joy], i, -1); + } +} +/* mouse buttons (just like joystick buttons) + */ +void setmousebuttonstateall (int mouse, uae_u32 buttonbits, uae_u32 buttonmask) +{ + int i; + + if (!mice[mouse].enabled) + return; + for (i = 0; i < ID_BUTTON_TOTAL; i++) { + if (buttonmask & (1 << i)) + setbuttonstateall (&mice[mouse], &mice2[mouse], i, (buttonbits & (1 << i)) ? 1 : 0); + else if (buttonbits & (1 << i)) + setbuttonstateall (&mice[mouse], &mice2[mouse], i, -1); + } +} + +void setmousebuttonstate (int mouse, int button, int state) +{ + if (!mice[mouse].enabled) + return; + setbuttonstateall (&mice[mouse], &mice2[mouse], button, state); +} + +/* same for joystick axis (analog or digital) + * (0 = center, -max = full left/top, max = full right/bottom) + */ +void setjoystickstate (int joy, int axis, int state, int max) +{ + struct uae_input_device *id = &joysticks[joy]; + struct uae_input_device2 *id2 = &joysticks2[joy]; + int deadzone = currprefs.input_joymouse_deadzone * max / 100; + int i, v1, v2; + + if (!joysticks[joy].enabled) + return; + v1 = state; + v2 = id2->states[axis]; + if (v1 < deadzone && v1 > -deadzone) + v1 = 0; + if (v2 < deadzone && v2 > -deadzone) + v2 = 0; + if (v1 == v2) + return; + for (i = 0; i < MAX_INPUT_SUB_EVENT; i++) + handle_input_event (id->eventid[ID_AXIS_OFFSET + axis][i], state, max, id->flags[ID_AXIS_OFFSET + axis][i]); + id2->states[axis] = state; +} + +void setmousestate (int mouse, int axis, int data, int isabs) +{ + int i, v; + double *mouse_p, *oldm_p, d, diff; + struct uae_input_device *id = &mice[mouse]; + static double fract1[MAX_INPUT_DEVICES][MAX_INPUT_DEVICE_EVENTS]; + static double fract2[MAX_INPUT_DEVICES][MAX_INPUT_DEVICE_EVENTS]; + + if (!mice[mouse].enabled) + return; + d = 0; + mouse_p = &mouse_axis[mouse][axis]; + oldm_p = &oldm_axis[mouse][axis]; + if (!isabs) { + *oldm_p = *mouse_p; + *mouse_p += data; + d = (*mouse_p - *oldm_p) * currprefs.input_mouse_speed / 100.0; + } else { + d = data - (int)(*oldm_p); + *oldm_p = data; + *mouse_p += d; + if (mouse == 0) { + if (axis == 0) + lastmx = data; + else + lastmy = data; + } + } + v = (int)(d > 0 ? d + 0.5 : d - 0.5); + fract1[mouse][axis] += d; + fract2[mouse][axis] += v; + diff = fract2[mouse][axis] - fract1[mouse][axis]; + if (diff > 1 || diff < -1) { + v -= (int)diff; + fract2[mouse][axis] -= diff; + } + for (i = 0; i < MAX_INPUT_SUB_EVENT; i++) + handle_input_event (id->eventid[ID_AXIS_OFFSET + axis][i], v, 0, 0); +} + +void warpmode (int mode) +{ + if (mode < 0) { + if (turbo_emulation) { + changed_prefs.gfx_framerate = currprefs.gfx_framerate = turbo_emulation; + turbo_emulation = 0; + } else { + turbo_emulation = currprefs.gfx_framerate; + } + } else if (mode == 0 && turbo_emulation > 0) { + changed_prefs.gfx_framerate = currprefs.gfx_framerate = turbo_emulation; + turbo_emulation = 0; + } else if (mode > 0 && !turbo_emulation) { + turbo_emulation = currprefs.gfx_framerate; + } + if (turbo_emulation) { + if (!currprefs.cpu_cycle_exact && !currprefs.blitter_cycle_exact) + changed_prefs.gfx_framerate = currprefs.gfx_framerate = 10; + pause_sound (); + } else { + resume_sound (); + } + compute_vsynctime (); +} + +void pausemode (int mode) +{ + if (mode < 0) + pause_emulation = pause_emulation ? 0 : 1; + else + pause_emulation = mode; +} diff --git a/inputevents.def b/inputevents.def new file mode 100755 index 00000000..aa0e99d6 --- /dev/null +++ b/inputevents.def @@ -0,0 +1,273 @@ +/* joystick/mouse port 1 */ + +DEFEVENT(JOYPORT1_START,"Joystick port 1", AM_INFO, 0,1,0) + +DEFEVENT(MOUSE1_FIRST, "", AM_DUMMY, 0,0,0) + +DEFEVENT(MOUSE1_HORIZ,"Mouse1 Horizontal",AM_MOUSE_AXIS|AM_JOY_AXIS,8,1,0) +DEFEVENT(MOUSE1_VERT,"Mouse1 Vertical",AM_MOUSE_AXIS|AM_JOY_AXIS,8,1,1) + +DEFEVENT(MOUSE1_LAST, "", AM_DUMMY, 0,0,0) + +DEFEVENT(MOUSE1_UP,"Mouse1 Up",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT,32,1,DIR_UP) +DEFEVENT(MOUSE1_DOWN,"Mouse1 Down",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT,32,1,DIR_DOWN) +DEFEVENT(MOUSE1_LEFT,"Mouse1 Left",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT,32,1,DIR_LEFT) +DEFEVENT(MOUSE1_RIGHT,"Mouse1 Right",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT,32,1,DIR_RIGHT) + +DEFEVENT(MOUSE1_WHEEL,"Mouse1 Wheel",AM_MOUSE_AXIS|AM_JOY_AXIS,8,1,2) + +DEFEVENT(JOY1_HORIZ,"Joy1 Horizontal",AM_JOY_AXIS,0,1,DIR_LEFT|DIR_RIGHT) +DEFEVENT(JOY1_VERT,"Joy1 Vertical",AM_JOY_AXIS,0,1,DIR_UP|DIR_DOWN) +DEFEVENT(JOY1_HORIZ_POT,"Joy1 Horizontal (Analog)",AM_JOY_AXIS,64,1,0) +DEFEVENT(JOY1_VERT_POT,"Joy1 Vertical (Analog)",AM_JOY_AXIS,64,1,1) + +DEFEVENT(JOY1_LEFT,"Joy1 Left",AM_KEY|AM_JOY_BUT|AM_AF,16,1,DIR_LEFT) +DEFEVENT(JOY1_RIGHT,"Joy1 Right",AM_KEY|AM_JOY_BUT|AM_AF,16,1,DIR_RIGHT) +DEFEVENT(JOY1_UP,"Joy1 Up",AM_KEY|AM_JOY_BUT|AM_AF,16,1,DIR_UP) +DEFEVENT(JOY1_DOWN,"Joy1 Down",AM_KEY|AM_JOY_BUT|AM_AF,16,1,DIR_DOWN) +DEFEVENT(JOY1_LEFT_UP,"Joy1 Left+Up",AM_KEY|AM_JOY_BUT|AM_AF,16,1,DIR_LEFT|DIR_UP) +DEFEVENT(JOY1_LEFT_DOWN,"Joy1 Left+Down",AM_KEY|AM_JOY_BUT|AM_AF,16,1,DIR_LEFT|DIR_DOWN) +DEFEVENT(JOY1_RIGHT_UP,"Joy1 Right+Up",AM_KEY|AM_JOY_BUT|AM_AF,16,1,DIR_RIGHT|DIR_UP) +DEFEVENT(JOY1_RIGHT_DOWN,"Joy1 Right+Down",AM_KEY|AM_JOY_BUT|AM_AF,16,1,DIR_RIGHT|DIR_DOWN) + +DEFEVENT(JOY1_FIRE_BUTTON,"Joy1 Fire/Mouse1 Left Button",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,1,JOYBUTTON_1) +DEFEVENT(JOY1_2ND_BUTTON,"Joy1 2nd Button/Mouse1 Right Button",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,1,JOYBUTTON_2) +DEFEVENT(JOY1_3RD_BUTTON,"Joy1 3rd Button/Mouse1 Middle Button",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,1,JOYBUTTON_3) +DEFEVENT(JOY1_CD32_PLAY,"Joy1 CD32 Play",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,1,JOYBUTTON_CD32_PLAY) +DEFEVENT(JOY1_CD32_RWD,"Joy1 CD32 RWD",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,1,JOYBUTTON_CD32_RWD) +DEFEVENT(JOY1_CD32_FFW,"Joy1 CD32 FFW",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,1,JOYBUTTON_CD32_FFW) +DEFEVENT(JOY1_CD32_GREEN,"Joy1 CD32 Green",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,1,JOYBUTTON_CD32_GREEN) +DEFEVENT(JOY1_CD32_YELLOW,"Joy1 CD32 Yellow",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,1,JOYBUTTON_CD32_YELLOW) +DEFEVENT(JOY1_CD32_RED,"Joy1 CD32 Red",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,1,JOYBUTTON_CD32_RED) +DEFEVENT(JOY1_CD32_BLUE,"Joy1 CD32 Blue",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,1,JOYBUTTON_CD32_BLUE) + +/* joystick/mouse port 2 */ + +DEFEVENT(JOYPORT2_START,"Joystick port 2", AM_INFO, 0,2,0) + +DEFEVENT(MOUSE2_FIRST, "", AM_DUMMY, 0,0,0) + +DEFEVENT(MOUSE2_HORIZ,"Mouse2 Horizontal",AM_MOUSE_AXIS|AM_JOY_AXIS,8,2,0) +DEFEVENT(MOUSE2_VERT,"Mouse2 Vertical",AM_MOUSE_AXIS|AM_JOY_AXIS,8,2,1) + +DEFEVENT(MOUSE2_LAST, "", AM_DUMMY, 0,0,0) + +DEFEVENT(MOUSE2_UP,"Mouse2 Up",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT,32,2,DIR_UP) +DEFEVENT(MOUSE2_DOWN,"Mouse2 Down",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT,32,2,DIR_DOWN) +DEFEVENT(MOUSE2_LEFT,"Mouse2 Left",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT,32,2,DIR_LEFT) +DEFEVENT(MOUSE2_RIGHT,"Mouse2 Right",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT,32,2,DIR_RIGHT) + +DEFEVENT(JOY2_HORIZ,"Joy2 Horizontal",AM_JOY_AXIS,0,2,DIR_LEFT|DIR_RIGHT) +DEFEVENT(JOY2_VERT,"Joy2 Vertical",AM_JOY_AXIS,0,2,DIR_UP|DIR_DOWN) +DEFEVENT(JOY2_HORIZ_POT,"Joy2 Horizontal (Analog)",AM_JOY_AXIS,64,2,0) +DEFEVENT(JOY2_VERT_POT,"Joy2 Vertical (Analog)",AM_JOY_AXIS,64,2,1) + +DEFEVENT(JOY2_LEFT,"Joy2 Left",AM_KEY|AM_JOY_BUT|AM_AF,16,2,DIR_LEFT) +DEFEVENT(JOY2_RIGHT,"Joy2 Right",AM_KEY|AM_JOY_BUT|AM_AF,16,2,DIR_RIGHT) +DEFEVENT(JOY2_UP,"Joy2 Up",AM_KEY|AM_JOY_BUT|AM_AF,16,2,DIR_UP) +DEFEVENT(JOY2_DOWN,"Joy2 Down",AM_KEY|AM_JOY_BUT|AM_AF,16,2,DIR_DOWN) +DEFEVENT(JOY2_LEFT_UP,"Joy2 Left+Up",AM_KEY|AM_JOY_BUT|AM_AF,16,2,DIR_LEFT|DIR_UP) +DEFEVENT(JOY2_LEFT_DOWN,"Joy2 Left+Down",AM_KEY|AM_JOY_BUT|AM_AF,16,2,DIR_LEFT|DIR_DOWN) +DEFEVENT(JOY2_RIGHT_UP,"Joy2 Right+Up",AM_KEY|AM_JOY_BUT|AM_AF,16,2,DIR_RIGHT|DIR_UP) +DEFEVENT(JOY2_RIGHT_DOWN,"Joy2 Right+Down",AM_KEY|AM_JOY_BUT|AM_AF,16,2,DIR_RIGHT|DIR_DOWN) + +DEFEVENT(JOY2_FIRE_BUTTON,"Joy2 Fire/Mouse1 Left Button",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,2,JOYBUTTON_1) +DEFEVENT(JOY2_2ND_BUTTON,"Joy2 2nd Button/Mouse1 Right Button",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,2,JOYBUTTON_2) +DEFEVENT(JOY2_3RD_BUTTON,"Joy2 3rd Button/Mouse1 Middle Button",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,2,JOYBUTTON_3) +DEFEVENT(JOY2_CD32_PLAY,"Joy2 CD32 Play",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,2,JOYBUTTON_CD32_PLAY) +DEFEVENT(JOY2_CD32_RWD,"Joy2 CD32 RWD",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,2,JOYBUTTON_CD32_RWD) +DEFEVENT(JOY2_CD32_FFW,"Joy2 CD32 FFW",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,2,JOYBUTTON_CD32_FFW) +DEFEVENT(JOY2_CD32_GREEN,"Joy2 CD32 Green",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,2,JOYBUTTON_CD32_GREEN) +DEFEVENT(JOY2_CD32_YELLOW,"Joy2 CD32 Yellow",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,2,JOYBUTTON_CD32_YELLOW) +DEFEVENT(JOY2_CD32_RED,"Joy2 CD32 Red",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,2,JOYBUTTON_CD32_RED) +DEFEVENT(JOY2_CD32_BLUE,"Joy2 CD32 Blue",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,2,JOYBUTTON_CD32_BLUE) + +/* parallel port joystick adapter */ + +DEFEVENT(PAR_JOY1_START, "Parallel port joystick adapter", AM_INFO, 0,3,0) + +DEFEVENT(PAR_JOY1_HORIZ,"Parallel Joy1 Horizontal",AM_JOY_AXIS,0,3,DIR_LEFT|DIR_RIGHT) +DEFEVENT(PAR_JOY1_VERT,"Parallel Joy1 Vertical",AM_JOY_AXIS,0,3,DIR_UP|DIR_DOWN) +DEFEVENT(PAR_JOY1_LEFT,"Parallel Joy1 Left",AM_KEY|AM_JOY_BUT|AM_AF,16,3,DIR_LEFT) +DEFEVENT(PAR_JOY1_RIGHT,"Parallel Joy1 Right",AM_KEY|AM_JOY_BUT|AM_AF,16,3,DIR_RIGHT) +DEFEVENT(PAR_JOY1_UP,"Parallel Joy1 Up",AM_KEY|AM_JOY_BUT|AM_AF,16,3,DIR_UP) +DEFEVENT(PAR_JOY1_DOWN,"Parallel Joy1 Down",AM_KEY|AM_JOY_BUT|AM_AF,16,3,DIR_DOWN) +DEFEVENT(PAR_JOY1_LEFT_UP,"Parallel Joy1 Left+Up",AM_KEY|AM_JOY_BUT|AM_AF,16,3,DIR_LEFT|DIR_UP) +DEFEVENT(PAR_JOY1_LEFT_DOWN,"Parallel Joy1 Left+Down",AM_KEY|AM_JOY_BUT|AM_AF,16,3,DIR_LEFT|DIR_DOWN) +DEFEVENT(PAR_JOY1_RIGHT_UP,"Parallel Joy1 Right+Up",AM_KEY|AM_JOY_BUT|AM_AF,16,3,DIR_RIGHT|DIR_UP) +DEFEVENT(PAR_JOY1_RIGHT_DOWN,"Parallel Joy1 Right+Down",AM_KEY|AM_JOY_BUT|AM_AF,16,3,DIR_RIGHT|DIR_DOWN) +DEFEVENT(PAR_JOY1_FIRE_BUTTON,"Parallel Joy1 Fire Button",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,3,JOYBUTTON_1) + +DEFEVENT(PAR_JOY2_START, "", AM_DUMMY, 0,4,0) + +DEFEVENT(PAR_JOY2_HORIZ,"Parallel Joy2 Horizontal",AM_JOY_AXIS,0,4,DIR_LEFT|DIR_RIGHT) +DEFEVENT(PAR_JOY2_VERT,"Parallel Joy2 Vertical",AM_JOY_AXIS,0,4,DIR_UP|DIR_DOWN) +DEFEVENT(PAR_JOY2_LEFT,"Parallel Joy2 Left",AM_KEY|AM_JOY_BUT|AM_AF,16,4,DIR_LEFT) +DEFEVENT(PAR_JOY2_RIGHT,"Parallel Joy2 Right",AM_KEY|AM_JOY_BUT|AM_AF,16,4,DIR_RIGHT) +DEFEVENT(PAR_JOY2_UP,"Parallel Joy2 Up",AM_KEY|AM_JOY_BUT|AM_AF,16,4,DIR_UP) +DEFEVENT(PAR_JOY2_DOWN,"Parallel Joy2 Down",AM_KEY|AM_JOY_BUT|AM_AF,16,4,DIR_DOWN) +DEFEVENT(PAR_JOY2_LEFT_UP,"Parallel Joy2 Left+Up",AM_KEY|AM_JOY_BUT|AM_AF,16,4,DIR_LEFT|DIR_UP) +DEFEVENT(PAR_JOY2_LEFT_DOWN,"Parallel Joy2 Left+Down",AM_KEY|AM_JOY_BUT|AM_AF,16,4,DIR_LEFT|DIR_DOWN) +DEFEVENT(PAR_JOY2_RIGHT_UP,"Parallel Joy2 Right+Up",AM_KEY|AM_JOY_BUT|AM_AF,16,4,DIR_RIGHT|DIR_UP) +DEFEVENT(PAR_JOY2_RIGHT_DOWN,"Parallel Joy2 Right+Down",AM_KEY|AM_JOY_BUT|AM_AF,16,4,DIR_RIGHT|DIR_DOWN) +DEFEVENT(PAR_JOY2_FIRE_BUTTON,"Parallel Joy2 Fire Button",AM_KEY|AM_JOY_BUT|AM_MOUSE_BUT|AM_AF,4,4,JOYBUTTON_1) + +DEFEVENT(PAR_JOY_END, "", AM_DUMMY, 0,0,0) + +/* keys */ + +DEFEVENT(KEY_START,"Keyboard",AM_INFO, 0,0,0) + +DEFEVENT(KEY_F1,"F1",AM_K,0,0,AK_F1) +DEFEVENT(KEY_F2,"F2",AM_K,0,0,AK_F2) +DEFEVENT(KEY_F3,"F3",AM_K,0,0,AK_F3) +DEFEVENT(KEY_F4,"F4",AM_K,0,0,AK_F4) +DEFEVENT(KEY_F5,"F5",AM_K,0,0,AK_F5) +DEFEVENT(KEY_F6,"F6",AM_K,0,0,AK_F6) +DEFEVENT(KEY_F7,"F7",AM_K,0,0,AK_F7) +DEFEVENT(KEY_F8,"F8",AM_K,0,0,AK_F8) +DEFEVENT(KEY_F9,"F9",AM_K,0,0,AK_F9) +DEFEVENT(KEY_F10,"F10",AM_K,0,0,AK_F10) + +/* "special" keys */ + +DEFEVENT(KEY_ESC,"ESC",AM_K,0,0,AK_ESC) +DEFEVENT(KEY_TAB,"Tab",AM_K,0,0,AK_TAB) +DEFEVENT(KEY_CTRL,"CTRL",AM_K,0,0,AK_CTRL) +DEFEVENT(KEY_CTRL_RIGHT,"Right CTRL",AM_K,0,0,AK_RCTRL) +DEFEVENT(KEY_CAPS_LOCK,"Caps Lock",AM_K,0,0,AK_CAPSLOCK) +DEFEVENT(KEY_SHIFT_LEFT,"Left Shift",AM_K,0,0,AK_LSH) +DEFEVENT(KEY_ALT_LEFT,"Left Alt",AM_K,0,0,AK_LALT) +DEFEVENT(KEY_AMIGA_LEFT,"Left Amiga",AM_K,0,0,AK_LAMI) +DEFEVENT(KEY_AMIGA_RIGHT,"Right Amiga",AM_K,0,0,AK_RAMI) +DEFEVENT(KEY_ALT_RIGHT,"Right Alt",AM_K,0,0,AK_RALT) +DEFEVENT(KEY_SHIFT_RIGHT,"Right Shift",AM_K,0,0,AK_RSH) +DEFEVENT(KEY_SPACE,"Space",AM_K,0,0,AK_SPC) +DEFEVENT(KEY_CURSOR_UP,"Cursor Up",AM_K,0,0,AK_UP) +DEFEVENT(KEY_CURSOR_DOWN,"Cursor Down",AM_K,0,0,AK_DN) +DEFEVENT(KEY_CURSOR_LEFT,"Cursor Left",AM_K,0,0,AK_LF) +DEFEVENT(KEY_CURSOR_RIGHT,"Cursor Right",AM_K,0,0,AK_RT) +DEFEVENT(KEY_HELP,"Help",AM_K,0,0,AK_HELP) +DEFEVENT(KEY_DEL,"Del",AM_K,0,0,AK_DEL) +DEFEVENT(KEY_BACKSPACE,"Backspace",AM_K,0,0,AK_BS) +DEFEVENT(KEY_RETURN,"Return",AM_K,0,0,AK_RET) + +/* numpad */ + +DEFEVENT(KEY_A,"A",AM_K,0,0,AK_A) +DEFEVENT(KEY_B,"B",AM_K,0,0,AK_B) +DEFEVENT(KEY_C,"C",AM_K,0,0,AK_C) +DEFEVENT(KEY_D,"D",AM_K,0,0,AK_D) +DEFEVENT(KEY_E,"E",AM_K,0,0,AK_E) +DEFEVENT(KEY_F,"F",AM_K,0,0,AK_F) +DEFEVENT(KEY_G,"G",AM_K,0,0,AK_G) +DEFEVENT(KEY_H,"H",AM_K,0,0,AK_H) +DEFEVENT(KEY_I,"I",AM_K,0,0,AK_I) +DEFEVENT(KEY_J,"J",AM_K,0,0,AK_J) +DEFEVENT(KEY_K,"K",AM_K,0,0,AK_K) +DEFEVENT(KEY_L,"L",AM_K,0,0,AK_L) +DEFEVENT(KEY_M,"M",AM_K,0,0,AK_M) +DEFEVENT(KEY_N,"N",AM_K,0,0,AK_N) +DEFEVENT(KEY_O,"O",AM_K,0,0,AK_O) +DEFEVENT(KEY_P,"P",AM_K,0,0,AK_P) +DEFEVENT(KEY_Q,"Q",AM_K,0,0,AK_Q) +DEFEVENT(KEY_R,"R",AM_K,0,0,AK_R) +DEFEVENT(KEY_S,"S",AM_K,0,0,AK_S) +DEFEVENT(KEY_T,"T",AM_K,0,0,AK_T) +DEFEVENT(KEY_U,"U",AM_K,0,0,AK_U) +DEFEVENT(KEY_V,"V",AM_K,0,0,AK_V) +DEFEVENT(KEY_W,"W",AM_K,0,0,AK_W) +DEFEVENT(KEY_X,"X",AM_K,0,0,AK_X) +DEFEVENT(KEY_Y,"Y",AM_K,0,0,AK_Y) +DEFEVENT(KEY_Z,"Z",AM_K,0,0,AK_Z) + +DEFEVENT(KEY_ENTER,"Numpad Enter",AM_K,0,0,AK_ENT) +DEFEVENT(KEY_NP_0,"Numpad 0",AM_K,0,0,AK_NP0) +DEFEVENT(KEY_NP_1,"Numpad 1",AM_K,0,0,AK_NP1) +DEFEVENT(KEY_NP_2,"Numpad 2",AM_K,0,0,AK_NP2) +DEFEVENT(KEY_NP_3,"Numpad 3",AM_K,0,0,AK_NP3) +DEFEVENT(KEY_NP_4,"Numpad 4",AM_K,0,0,AK_NP4) +DEFEVENT(KEY_NP_5,"Numpad 5",AM_K,0,0,AK_NP5) +DEFEVENT(KEY_NP_6,"Numpad 6",AM_K,0,0,AK_NP6) +DEFEVENT(KEY_NP_7,"Numpad 7",AM_K,0,0,AK_NP7) +DEFEVENT(KEY_NP_8,"Numpad 8",AM_K,0,0,AK_NP8) +DEFEVENT(KEY_NP_9,"Numpad 9",AM_K,0,0,AK_NP9) +DEFEVENT(KEY_NP_PERIOD,"Numpad Period",AM_K,0,0,AK_NPDEL) +DEFEVENT(KEY_NP_ADD,"Numpad Plus",AM_K,0,0,AK_NPADD) +DEFEVENT(KEY_NP_SUB,"Numpad Minus",AM_K,0,0,AK_NPSUB) +DEFEVENT(KEY_NP_MUL,"Numpad Multiply",AM_K,0,0,AK_NPMUL) +DEFEVENT(KEY_NP_DIV,"Numpad Divide",AM_K,0,0,AK_NPDIV) +DEFEVENT(KEY_NP_LPAREN,"Numpad Left Parenthesis",AM_K,0,0,AK_NPLPAREN) +DEFEVENT(KEY_NP_RPAREN,"Numpad Right Parenthesis",AM_K,0,0,AK_NPRPAREN) +DEFEVENT(KEY_2B,"Keycode 0x2b",AM_K,0,0,0x2b) +DEFEVENT(KEY_30,"Keycode 0x30",AM_K,0,0,0x30) + +DEFEVENT(KEY_BACKQUOTE,"Back Quote",AM_K,0,0,AK_BACKQUOTE) +DEFEVENT(KEY_1,"1",AM_K,0,0,AK_1) +DEFEVENT(KEY_2,"2",AM_K,0,0,AK_2) +DEFEVENT(KEY_3,"3",AM_K,0,0,AK_3) +DEFEVENT(KEY_4,"4",AM_K,0,0,AK_4) +DEFEVENT(KEY_5,"5",AM_K,0,0,AK_5) +DEFEVENT(KEY_6,"6",AM_K,0,0,AK_6) +DEFEVENT(KEY_7,"7",AM_K,0,0,AK_7) +DEFEVENT(KEY_8,"8",AM_K,0,0,AK_8) +DEFEVENT(KEY_9,"9",AM_K,0,0,AK_9) +DEFEVENT(KEY_0,"0",AM_K,0,0,AK_0) +DEFEVENT(KEY_SUB,"Minus",AM_K,0,0,AK_MINUS) +DEFEVENT(KEY_EQUALS,"Equals",AM_K,0,0,AK_EQUAL) +DEFEVENT(KEY_BACKSLASH,"Backslash",AM_K,0,0,AK_BACKSLASH) + +DEFEVENT(KEY_LEFTBRACKET,"Left Bracket",AM_K,0,0,AK_LBRACKET) +DEFEVENT(KEY_RIGHTBRACKET,"Right Bracket",AM_K,0,0,AK_RBRACKET) +DEFEVENT(KEY_SEMICOLON,"Semicolon",AM_K,0,0,AK_SEMICOLON) +DEFEVENT(KEY_SINGLEQUOTE,"Single Quote",AM_K,0,0,AK_QUOTE) +DEFEVENT(KEY_COMMA,"Comma",AM_K,0,0,AK_COMMA) +DEFEVENT(KEY_PERIOD,"Period",AM_K,0,0,AK_PERIOD) +DEFEVENT(KEY_DIV,"Slash",AM_K,0,0,AK_SLASH) + +// DEFEVENT(KEY_,"",AM_K,0,0,0x) + +/* mouse wheel "keys" */ + +DEFEVENT(MOUSEWHEEL_DOWN,"Mouse Wheel Down",AM_K,0,0,0x7a) +DEFEVENT(MOUSEWHEEL_UP,"Mouse Wheel Up",AM_K,0,0,0x7b) + +/* misc */ + +DEFEVENT(KEY_CDTV_STOP,"CDTV Stop",AM_K,0,0,0x72) +DEFEVENT(KEY_CDTV_PLAYPAUSE,"CDTV Play/Pause",AM_K,0,0,0x73) +DEFEVENT(KEY_CDTV_FF,"CDTV Fast Forward",AM_K,0,0,0x74) +DEFEVENT(KEY_CDTV_REW,"CDTV Rewind",AM_K,0,0,0x75) + +DEFEVENT(KEY_70,"Keycode 0x70",AM_K,0,0,0x70) +DEFEVENT(KEY_71,"Keycode 0x71",AM_K,0,0,0x71) +DEFEVENT(KEY_76,"Keycode 0x76",AM_K,0,0,0x76) +DEFEVENT(KEY_77,"Keycode 0x77",AM_K,0,0,0x77) +DEFEVENT(KEY_78,"Keycode 0x78 (Reset Warning)",AM_K,0,0,0x78) +DEFEVENT(KEY_79,"Keycode 0x79",AM_K,0,0,0x79) + +/* special */ + +DEFEVENT(SPC_ENTERGUI,"Enter GUI",AM_K,0,0,AKS_ENTERGUI) +DEFEVENT(SPC_SCREENSHOT,"Screenshot",AM_K,0,0,AKS_SCREENSHOT) +DEFEVENT(SPC_FREEZEBUTTON,"Activate Cartridge",AM_K,0,0,AKS_FREEZEBUTTON) +DEFEVENT(SPC_FLOPPY0,"Change disk in DF0:",AM_K,0,0,AKS_FLOPPY0) +DEFEVENT(SPC_FLOPPY1,"Change disk in DF1:",AM_K,0,0,AKS_FLOPPY1) +DEFEVENT(SPC_FLOPPY2,"Change disk in DF2:",AM_K,0,0,AKS_FLOPPY2) +DEFEVENT(SPC_FLOPPY3,"Change disk in DF3:",AM_K,0,0,AKS_FLOPPY3) +DEFEVENT(SPC_EFLOPPY0,"Eject disk in DF0:",AM_K,0,0,AKS_EFLOPPY0) +DEFEVENT(SPC_EFLOPPY1,"Eject disk in DF0:",AM_K,0,0,AKS_EFLOPPY1) +DEFEVENT(SPC_EFLOPPY2,"Eject disk in DF0:",AM_K,0,0,AKS_EFLOPPY2) +DEFEVENT(SPC_EFLOPPY3,"Eject disk in DF0:",AM_K,0,0,AKS_EFLOPPY3) +DEFEVENT(SPC_PAUSE,"Pause emulation",AM_K,0,0,AKS_PAUSE) +DEFEVENT(SPC_WARP,"Warp mode",AM_K,0,0,AKS_WARP) +DEFEVENT(SPC_INHIBITSCREEN,"Toggle screen updates",AM_K,0,0,AKS_INHIBITSCREEN) +DEFEVENT(SPC_IRQ7,"Level 7 interrupt",AM_K,0,0,AKS_IRQ7) +DEFEVENT(SPC_STATEREWIND,"Load previous state capture",AM_K,0,0,AKS_STATEREWIND) +DEFEVENT(SPC_VOLUME_DOWN,"Decrease volume level",AM_K,0,0,AKS_VOLDOWN) +DEFEVENT(SPC_VOLUME_UP,"Increase volume level",AM_K,0,0,AKS_VOLUP) +DEFEVENT(SPC_VOLUME_MUTE,"Mute/unmute volume",AM_K,0,0,AKS_VOLMUTE) +DEFEVENT(SPC_QUIT,"Quit emulator",AM_K,0,0,AKS_QUIT) +DEFEVENT(SPC_STATESAVE,"Save state",AM_K,0,0,AKS_STATESAVE) +DEFEVENT(SPC_STATERESTORE,"Restore state",AM_K,0,0,AKS_STATERESTORE) + diff --git a/keybuf.c b/keybuf.c new file mode 100755 index 00000000..f4ff6a57 --- /dev/null +++ b/keybuf.c @@ -0,0 +1,169 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Keyboard buffer. Not really needed for X, but for SVGAlib and possibly + * Mac and DOS ports. + * + * Note: it's possible to have two threads in UAE, one reading keystrokes + * and the other one writing them. Despite this, no synchronization effort + * is needed. This code should be perfectly thread safe. At least if you + * assume that integer store instructions are atomic. + * + * Copyright 1995, 1997 Bernd Schmidt + */ + +#include "sysconfig.h" +#include "sysdeps.h" +#include + +#include "config.h" +#include "options.h" +#include "keybuf.h" +#include "keyboard.h" +#include "inputdevice.h" +#include "custom.h" +#include "savestate.h" + +static int fakestate[3][6] = { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0 } }; + +static int *fs_np; +static int *fs_ck; +static int *fs_se; + +/* Not static so the DOS code can mess with them */ +int kpb_first, kpb_last; + +static int keybuf[256]; + +int keys_available (void) +{ + int val; + val = kpb_first != kpb_last; + return val; +} + +int get_next_key (void) +{ + int key; + assert (kpb_first != kpb_last); + + key = keybuf[kpb_last]; + if (++kpb_last == 256) + kpb_last = 0; + return key; +} + +static void do_fake (int nr) +{ + int *fake = fakestate[nr]; + + nr += 2; + setjoystickstate (nr, 0, fake[1] ? -100 : (fake[2] ? 100 : 0), 100); + setjoystickstate (nr, 1, fake[0] ? -100 : (fake[3] ? 100 : 0), 100); + setjoybuttonstate (nr, 0, fake[4]); + setjoybuttonstate (nr, 1, fake[5]); +} + +void record_key (int kc) +{ + int fs = 0; + int kpb_next = kpb_first + 1; + + //write_log ("got kc %02.2X\n", ((kc << 7) | (kc >> 1)) & 0xff); + if (kpb_next == 256) + kpb_next = 0; + if (kpb_next == kpb_last) { + write_log ("Keyboard buffer overrun. Congratulations.\n"); + return; + } + if (fs_np != 0) { + switch (kc >> 1) { + case AK_NP8: fs = 1; fs_np[0] = !(kc & 1); break; + case AK_NP4: fs = 1; fs_np[1] = !(kc & 1); break; + case AK_NP6: fs = 1; fs_np[2] = !(kc & 1); break; + case AK_NP2: fs = 1; fs_np[3] = !(kc & 1); break; + case AK_NP0: case AK_NP5: fs = 1; fs_np[4] = !(kc & 1); break; + case AK_NPDEL: case AK_NPDIV: case AK_ENT: fs = 1; fs_np[5] = !(kc & 1); break; + } + } + if (fs_ck != 0) { + switch (kc >> 1) { + case AK_UP: fs = 1; fs_ck[0] = !(kc & 1); break; + case AK_LF: fs = 1; fs_ck[1] = !(kc & 1); break; + case AK_RT: fs = 1; fs_ck[2] = !(kc & 1); break; + case AK_DN: fs = 1; fs_ck[3] = !(kc & 1); break; + case AK_RCTRL: fs = 1; fs_ck[4] = !(kc & 1); break; + case AK_RSH: fs = 1; fs_ck[5] = !(kc & 1); break; + } + } + if (fs_se != 0) { + switch (kc >> 1) { + case AK_T: fs = 1; fs_se[0] = !(kc & 1); break; + case AK_F: fs = 1; fs_se[1] = !(kc & 1); break; + case AK_H: fs = 1; fs_se[2] = !(kc & 1); break; + case AK_B: fs = 1; fs_se[3] = !(kc & 1); break; + case AK_LALT: fs = 1; fs_se[4] = !(kc & 1); break; + case AK_LSH: fs = 1; fs_se[5] = !(kc & 1); break; + } + } + + if (fs && currprefs.input_selected_setting == 0) { + if (JSEM_ISNUMPAD (0, &currprefs) || JSEM_ISCURSOR (0, &currprefs) || JSEM_ISSOMEWHEREELSE (0, &currprefs)) + do_fake (0); + if (JSEM_ISNUMPAD (1, &currprefs) || JSEM_ISCURSOR (1, &currprefs) || JSEM_ISSOMEWHEREELSE (1, &currprefs)) + do_fake (1); + return; + } else { + if ((kc >> 1) == AK_RCTRL) { + kc ^= AK_RCTRL << 1; + kc ^= AK_CTRL << 1; + } + } + + keybuf[kpb_first] = kc; + kpb_first = kpb_next; +} + +void joystick_setting_changed (void) +{ + fs_np = fs_ck = fs_se = 0; + + if (JSEM_ISNUMPAD (0, &currprefs)) + fs_np = fakestate[0]; + else if (JSEM_ISNUMPAD (1, &currprefs)) + fs_np = fakestate[1]; + + if (JSEM_ISCURSOR (0, &currprefs)) + fs_ck = fakestate[0]; + else if (JSEM_ISCURSOR (1, &currprefs)) + fs_ck = fakestate[1]; + + if (JSEM_ISSOMEWHEREELSE (0, &currprefs)) + fs_se = fakestate[0]; + else if (JSEM_ISSOMEWHEREELSE (1, &currprefs)) + fs_se = fakestate[1]; +} + +void keybuf_init (void) +{ + kpb_first = kpb_last = 0; + inputdevice_updateconfig (&currprefs); +} + + +uae_u8 *save_keyboard (int *len) +{ + uae_u8 *dst, *t; + dst = t = malloc (8); + save_u32 (getcapslockstate() ? 1 : 0); + save_u32 (0); + *len = 8; + return t; +} + +uae_u8 *restore_keyboard (uae_u8 *src) +{ + setcapslockstate (restore_u32 ()); + restore_u32 (); + return src; +} diff --git a/main.c b/main.c new file mode 100755 index 00000000..58dbb18b --- /dev/null +++ b/main.c @@ -0,0 +1,701 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Main program + * + * Copyright 1995 Ed Hanway + * Copyright 1995, 1996, 1997 Bernd Schmidt + */ +#include "sysconfig.h" +#include "sysdeps.h" +#include + +#include "config.h" +#include "options.h" +#include "threaddep/thread.h" +#include "uae.h" +#include "gensound.h" +#include "audio.h" +#include "sounddep/sound.h" +#include "events.h" +#include "memory.h" +#include "custom.h" +#include "serial.h" +#include "newcpu.h" +#include "disk.h" +#include "debug.h" +#include "xwin.h" +#include "inputdevice.h" +#include "keybuf.h" +#include "gui.h" +#include "zfile.h" +#include "autoconf.h" +#include "osemu.h" +#include "osdep/exectasks.h" +#include "compiler.h" +#include "picasso96.h" +#include "bsdsocket.h" +#include "uaeexe.h" +#include "native2amiga.h" +#include "scsidev.h" +#include "akiko.h" +#include "savestate.h" + +#ifdef USE_SDL +#include "SDL.h" +#endif + +long int version = 256*65536L*UAEMAJOR + 65536L*UAEMINOR + UAESUBREV; + +struct uae_prefs currprefs, changed_prefs; + +int no_gui = 0; +int joystickpresent = 0; +int cloanto_rom = 0; + +struct gui_info gui_data; + +char warning_buffer[256]; + +char optionsfile[256]; + +/* If you want to pipe printer output to a file, put something like + * "cat >>printerfile.tmp" above. + * The printer support was only tested with the driver "PostScript" on + * Amiga side, using apsfilter for linux to print ps-data. + * + * Under DOS it ought to be -p LPT1: or -p PRN: but you'll need a + * PostScript printer or ghostscript -=SR=- + */ + +/* Slightly stupid place for this... */ +/* ncurses.c might use quite a few of those. */ +char *colormodes[] = { "256 colors", "32768 colors", "65536 colors", + "256 colors dithered", "16 colors dithered", "16 million colors", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" +}; + +void discard_prefs (struct uae_prefs *p, int type) +{ + struct strlist **ps = &p->all_lines; + while (*ps) { + struct strlist *s = *ps; + *ps = s->next; + free (s->value); + free (s->option); + free (s); + } +#ifdef FILESYS + free_mountinfo (p->mountinfo); + p->mountinfo = alloc_mountinfo (); +#endif +} + +void fixup_prefs_dimensions (struct uae_prefs *prefs) +{ + if (prefs->gfx_width_fs < 320) + prefs->gfx_width_fs = 320; + if (prefs->gfx_height_fs < 200) + prefs->gfx_height_fs = 200; + if (prefs->gfx_height_fs > 1280) + prefs->gfx_height_fs = 1280; + prefs->gfx_width_fs += 7; /* X86.S wants multiples of 4 bytes, might be 8 in the future. */ + prefs->gfx_width_fs &= ~7; + if (prefs->gfx_width_win < 320) + prefs->gfx_width_win = 320; + if (prefs->gfx_height_win < 200) + prefs->gfx_height_win = 200; + if (prefs->gfx_height_win > 1280) + prefs->gfx_height_win = 1280; + prefs->gfx_width_win += 7; /* X86.S wants multiples of 4 bytes, might be 8 in the future. */ + prefs->gfx_width_win &= ~7; +} + +static void fix_options (void) +{ + int err = 0; + + if ((currprefs.chipmem_size & (currprefs.chipmem_size - 1)) != 0 + || currprefs.chipmem_size < 0x40000 + || currprefs.chipmem_size > 0x800000) + { + currprefs.chipmem_size = 0x200000; + write_log ("Unsupported chipmem size!\n"); + err = 1; + } + if (currprefs.chipmem_size > 0x80000) + currprefs.chipset_mask |= CSMASK_ECS_AGNUS; + + if ((currprefs.fastmem_size & (currprefs.fastmem_size - 1)) != 0 + || (currprefs.fastmem_size != 0 && (currprefs.fastmem_size < 0x100000 || currprefs.fastmem_size > 0x800000))) + { + currprefs.fastmem_size = 0; + write_log ("Unsupported fastmem size!\n"); + err = 1; + } + if ((currprefs.gfxmem_size & (currprefs.gfxmem_size - 1)) != 0 + || (currprefs.gfxmem_size != 0 && (currprefs.gfxmem_size < 0x100000 || currprefs.gfxmem_size > 0x2000000))) + { + write_log ("Unsupported graphics card memory size %lx!\n", currprefs.gfxmem_size); + currprefs.gfxmem_size = 0; + err = 1; + } + if ((currprefs.z3fastmem_size & (currprefs.z3fastmem_size - 1)) != 0 + || (currprefs.z3fastmem_size != 0 && (currprefs.z3fastmem_size < 0x100000 || currprefs.z3fastmem_size > 0x20000000))) + { + currprefs.z3fastmem_size = 0; + write_log ("Unsupported Zorro III fastmem size!\n"); + err = 1; + } + if (currprefs.address_space_24 && (currprefs.gfxmem_size != 0 || currprefs.z3fastmem_size != 0)) { + currprefs.z3fastmem_size = currprefs.gfxmem_size = 0; + write_log ("Can't use a graphics card or Zorro III fastmem when using a 24 bit\n" + "address space - sorry.\n"); + } + if (currprefs.bogomem_size != 0 && currprefs.bogomem_size != 0x80000 && currprefs.bogomem_size != 0x100000 && currprefs.bogomem_size != 0x180000) + { + currprefs.bogomem_size = 0; + write_log ("Unsupported bogomem size!\n"); + err = 1; + } + + if (currprefs.chipmem_size > 0x200000 && currprefs.fastmem_size != 0) { + write_log ("You can't use fastmem and more than 2MB chip at the same time!\n"); + currprefs.fastmem_size = 0; + err = 1; + } +#if 0 + if (currprefs.m68k_speed < -1 || currprefs.m68k_speed > 20) { + write_log ("Bad value for -w parameter: must be -1, 0, or within 1..20.\n"); + currprefs.m68k_speed = 4; + err = 1; + } +#endif + + if (currprefs.produce_sound < 0 || currprefs.produce_sound > 3) { + write_log ("Bad value for -S parameter: enable value must be within 0..3\n"); + currprefs.produce_sound = 0; + err = 1; + } + if (currprefs.comptrustbyte < 0 || currprefs.comptrustbyte > 3) { + fprintf (stderr, "Bad value for comptrustbyte parameter: value must be within 0..2\n"); + currprefs.comptrustbyte = 1; + err = 1; + } + if (currprefs.comptrustword < 0 || currprefs.comptrustword > 3) { + fprintf (stderr, "Bad value for comptrustword parameter: value must be within 0..2\n"); + currprefs.comptrustword = 1; + err = 1; + } + if (currprefs.comptrustlong < 0 || currprefs.comptrustlong > 3) { + fprintf (stderr, "Bad value for comptrustlong parameter: value must be within 0..2\n"); + currprefs.comptrustlong = 1; + err = 1; + } + if (currprefs.comptrustnaddr < 0 || currprefs.comptrustnaddr > 3) { + fprintf (stderr, "Bad value for comptrustnaddr parameter: value must be within 0..2\n"); + currprefs.comptrustnaddr = 1; + err = 1; + } + if (currprefs.compnf < 0 || currprefs.compnf > 1) { + fprintf (stderr, "Bad value for compnf parameter: value must be within 0..1\n"); + currprefs.compnf = 1; + err = 1; + } + if (currprefs.comp_hardflush < 0 || currprefs.comp_hardflush > 1) { + fprintf (stderr, "Bad value for comp_hardflush parameter: value must be within 0..1\n"); + currprefs.comp_hardflush = 1; + err = 1; + } + if (currprefs.comp_constjump < 0 || currprefs.comp_constjump > 1) { + fprintf (stderr, "Bad value for comp_constjump parameter: value must be within 0..1\n"); + currprefs.comp_constjump = 1; + err = 1; + } + if (currprefs.comp_oldsegv < 0 || currprefs.comp_oldsegv > 1) { + fprintf (stderr, "Bad value for comp_oldsegv parameter: value must be within 0..1\n"); + currprefs.comp_oldsegv = 1; + err = 1; + } + if (currprefs.cachesize < 0 || currprefs.cachesize > 16384) { + fprintf (stderr, "Bad value for cachesize parameter: value must be within 0..16384\n"); + currprefs.cachesize = 0; + err = 1; + } + + if (currprefs.cpu_level < 2 && currprefs.z3fastmem_size > 0) { + write_log ("Z3 fast memory can't be used with a 68000/68010 emulation. It\n" + "requires a 68020 emulation. Turning off Z3 fast memory.\n"); + currprefs.z3fastmem_size = 0; + err = 1; + } + if (currprefs.gfxmem_size > 0 && (currprefs.cpu_level < 2 || currprefs.address_space_24)) { + write_log ("Picasso96 can't be used with a 68000/68010 or 68EC020 emulation. It\n" + "requires a 68020 emulation. Turning off Picasso96.\n"); + currprefs.gfxmem_size = 0; + err = 1; + } +#ifndef BSDSOCKET + if (currprefs.socket_emu) { + write_log ("Compile-time option of BSDSOCKET_SUPPORTED was not enabled. You can't use bsd-socket emulation.\n"); + currprefs.socket_emu = 0; + err = 1; + } +#endif + + if (currprefs.nr_floppies < 0 || currprefs.nr_floppies > 4) { + write_log ("Invalid number of floppies. Using 4.\n"); + currprefs.nr_floppies = 4; + currprefs.dfxtype[0] = 0; + currprefs.dfxtype[1] = 0; + currprefs.dfxtype[2] = 0; + currprefs.dfxtype[3] = 0; + err = 1; + } + + if (currprefs.floppy_speed > 0 && currprefs.floppy_speed < 10) { + currprefs.floppy_speed = 100; + } + if (currprefs.input_mouse_speed < 1 || currprefs.input_mouse_speed > 1000) { + currprefs.input_mouse_speed = 100; + } + if (currprefs.cpu_cycle_exact || currprefs.blitter_cycle_exact) + currprefs.fast_copper = 0; + + if (currprefs.collision_level < 0 || currprefs.collision_level > 3) { + write_log ("Invalid collision support level. Using 1.\n"); + currprefs.collision_level = 1; + err = 1; + } + fixup_prefs_dimensions (&currprefs); + +#ifdef CPU_68000_ONLY + currprefs.cpu_level = 0; +#endif +#ifndef CPUEMU_0 + currprefs.cpu_compatible = 1; + currprefs.address_space_24 = 1; +#endif +#if !defined(CPUEMU_5) && !defined (CPUEMU_6) + currprefs.cpu_compatible = 0; + currprefs.address_space_24 = 0; +#endif +#if !defined (CPUEMU_6) + currprefs.cpu_cycle_exact = currprefs.blitter_cycle_exact = 0; +#endif +#ifndef AGA + currprefs.chipset_mask &= ~CSMASK_AGA; +#endif +#ifndef AUTOCONFIG + currprefs.z3fastmem_size = 0; + currprefs.fastmem_size = 0; + currprefs.gfxmem_size = 0; +#endif +#if !defined (BSDSOCKET) + currprefs.socket_emu = 0; +#endif +#if !defined (SCSIEMU) + currprefs.scsi = 0; + currprefs.win32_aspi = 0; +#endif + + if (err) + write_log ("Please use \"uae -h\" to get usage information.\n"); +} + +int quit_program = 0; +static int restart_program; +static char restart_config[256]; + +void uae_reset (int hardreset) +{ + if (quit_program == 0) { + quit_program = -2; + if (hardreset) + quit_program = -3; + } + +} + +void uae_quit (void) +{ + if (quit_program != -1) + quit_program = -1; +} + +void uae_restart (int opengui, char *cfgfile) +{ + uae_quit (); + restart_program = opengui ? 1 : 2; + restart_config[0] = 0; + if (cfgfile) + strcpy (restart_config, cfgfile); +} + +const char *gameport_state (int nr) +{ + if (JSEM_ISJOY0 (nr, &currprefs) && inputdevice_get_device_total (IDTYPE_JOYSTICK) > 0) + return "using joystick #0"; + else if (JSEM_ISJOY1 (nr, &currprefs) && inputdevice_get_device_total (IDTYPE_JOYSTICK) > 1) + return "using joystick #1"; + else if (JSEM_ISMOUSE (nr, &currprefs)) + return "using mouse"; + else if (JSEM_ISNUMPAD (nr, &currprefs)) + return "using numeric pad as joystick"; + else if (JSEM_ISCURSOR (nr, &currprefs)) + return "using cursor keys as joystick"; + else if (JSEM_ISSOMEWHEREELSE (nr, &currprefs)) + return "using T/F/H/B/Alt as joystick"; + + return "not connected"; +} + +#ifndef DONT_PARSE_CMDLINE + +void usage (void) +{ +} +static void parse_cmdline_2 (int argc, char **argv) +{ + int i; + + cfgfile_addcfgparam (0); + for (i = 1; i < argc; i++) { + if (strcmp (argv[i], "-cfgparam") == 0) { + if (i + 1 == argc) + write_log ("Missing argument for '-cfgparam' option.\n"); + else + cfgfile_addcfgparam (argv[++i]); + } + } +} + +static void parse_cmdline (int argc, char **argv) +{ + int i; + + for (i = 1; i < argc; i++) { + if (strcmp (argv[i], "-cfgparam") == 0) { + if (i + 1 < argc) + i++; + } else if (strncmp (argv[i], "-config=", 8) == 0) { +#ifdef FILESYS + free_mountinfo (currprefs.mountinfo); + currprefs.mountinfo = alloc_mountinfo (); +#endif + cfgfile_load (&currprefs, argv[i] + 8, 0); + } + /* Check for new-style "-f xxx" argument, where xxx is config-file */ + else if (strcmp (argv[i], "-f") == 0) { + if (i + 1 == argc) { + write_log ("Missing argument for '-f' option.\n"); + } else { +#ifdef FILESYS + free_mountinfo (currprefs.mountinfo); + currprefs.mountinfo = alloc_mountinfo (); +#endif + cfgfile_load (&currprefs, argv[++i], 0); + } + } else if (strcmp (argv[i], "-s") == 0) { + if (i + 1 == argc) + write_log ("Missing argument for '-s' option.\n"); + else + cfgfile_parse_line (&currprefs, argv[++i], 0); + } else if (strcmp (argv[i], "-h") == 0 || strcmp (argv[i], "-help") == 0) { + usage (); + exit (0); + } else { + if (argv[i][0] == '-' && argv[i][1] != '\0') { + const char *arg = argv[i] + 2; + int extra_arg = *arg == '\0'; + if (extra_arg) + arg = i + 1 < argc ? argv[i + 1] : 0; + if (parse_cmdline_option (&currprefs, argv[i][1], (char*)arg) && extra_arg) + i++; + } + } + } +} +#endif + +static void parse_cmdline_and_init_file (int argc, char **argv) +{ + + strcpy (optionsfile, ""); + +#ifdef OPTIONS_IN_HOME + { + char *home = getenv ("HOME"); + if (home != NULL && strlen (home) < 240) + { + strcpy (optionsfile, home); + strcat (optionsfile, "/"); + } + } +#endif + + parse_cmdline_2 (argc, argv); + + strcat (optionsfile, restart_config); + + if (! cfgfile_load (&currprefs, optionsfile, 0)) { + write_log ("failed to load config '%s'\n", optionsfile); +#ifdef OPTIONS_IN_HOME + /* sam: if not found in $HOME then look in current directory */ + strcpy (optionsfile, restart_config); + cfgfile_load (&currprefs, optionsfile); +#endif + } else { + write_log ("loaded config '%s'\n", optionsfile); + } + fix_options (); + + parse_cmdline (argc, argv); +} + +void reset_all_systems (void) +{ + init_eventtab (); + + memory_reset (); +#ifdef BSDSOCKET + bsdlib_reset (); +#endif +#ifdef FILESYS + filesys_reset (); + filesys_start_threads (); + hardfile_reset (); +#endif +#ifdef SCSIEMU + scsidev_reset (); + scsidev_start_threads (); +#endif +} + +/* Okay, this stuff looks strange, but it is here to encourage people who + * port UAE to re-use as much of this code as possible. Functions that you + * should be using are do_start_program() and do_leave_program(), as well + * as real_main(). Some OSes don't call main() (which is braindamaged IMHO, + * but unfortunately very common), so you need to call real_main() from + * whatever entry point you have. You may want to write your own versions + * of start_program() and leave_program() if you need to do anything special. + * Add #ifdefs around these as appropriate. + */ + +void do_start_program (void) +{ + /* Do a reset on startup. Whether this is elegant is debatable. */ + inputdevice_updateconfig (&currprefs); + quit_program = 2; + m68k_go (1); +} + +void do_leave_program (void) +{ + graphics_leave (); + inputdevice_close (); + DISK_free (); + close_sound (); + dump_counts (); +#ifdef SERIAL_PORT + serial_exit (); +#endif +#ifdef CD32 + akiko_free (); +#endif + if (! no_gui) + gui_exit (); +#ifdef USE_SDL + SDL_Quit (); +#endif +#ifdef AUTOCONFIG + expansion_cleanup (); +#endif + savestate_free (); + memory_cleanup (); + cfgfile_addcfgparam (0); +} + +void start_program (void) +{ + do_start_program (); +} + +void leave_program (void) +{ + do_leave_program (); +} + +static void real_main2 (int argc, char **argv) +{ +#if defined (NATMEM_OFFSET) && defined( _WIN32 ) && !defined( NO_WIN32_EXCEPTION_HANDLER ) + extern int EvalException ( LPEXCEPTION_POINTERS blah, int n_except ); + __try +#endif + { + +#ifdef USE_SDL + SDL_Init (SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_NOPARACHUTE); +#endif + + if (restart_config[0]) { +#ifdef FILESYS + free_mountinfo (currprefs.mountinfo); + currprefs.mountinfo = alloc_mountinfo (); +#endif + default_prefs (&currprefs, 0); + fix_options (); + } + + if (! graphics_setup ()) { + exit (1); + } + +#ifdef JIT + init_shm(); +#endif + +#ifdef FILESYS + rtarea_init (); + hardfile_install (); +#endif + + if (restart_config[0]) + parse_cmdline_and_init_file (argc, argv); + else + currprefs = changed_prefs; + + machdep_init (); + + if (! setup_sound ()) { + write_log ("Sound driver unavailable: Sound output disabled\n"); + currprefs.produce_sound = 0; + } + inputdevice_init (); + + changed_prefs = currprefs; + no_gui = ! currprefs.start_gui; + if (restart_program == 2) + no_gui = 1; + restart_program = 0; + if (! no_gui) { + int err = gui_init (); + struct uaedev_mount_info *mi = currprefs.mountinfo; + currprefs = changed_prefs; + currprefs.mountinfo = mi; + if (err == -1) { + write_log ("Failed to initialize the GUI\n"); + } else if (err == -2) { + return; + } + } + +#ifdef JIT + if (!(( currprefs.cpu_level >= 2 ) && ( currprefs.address_space_24 == 0 ) && ( currprefs.cachesize ))) + canbang = 0; +#endif + + logging_init(); /* Yes, we call this twice - the first case handles when the user has loaded + a config using the cmd-line. This case handles loads through the GUI. */ + fix_options (); + changed_prefs = currprefs; + + savestate_init (); +#ifdef SCSIEMU + scsidev_install (); +#endif +#ifdef AUTOCONFIG + /* Install resident module to get 8MB chipmem, if requested */ + rtarea_setup (); +#endif + + keybuf_init (); /* Must come after init_joystick */ + +#ifdef AUTOCONFIG + expansion_init (); +#endif + memory_init (); + memory_reset (); + +#ifdef FILESYS + filesys_install (); +#endif +#ifdef AUTOCONFIG + gfxlib_install (); + bsdlib_install (); + emulib_install (); + uaeexe_install (); + native2amiga_install (); +#endif + + custom_init (); /* Must come after memory_init */ +#ifdef SERIAL_PORT + serial_init (); +#endif + DISK_init (); + + reset_frame_rate_hack (); + init_m68k(); /* must come after reset_frame_rate_hack (); */ + + compiler_init (); + gui_update (); + + if (graphics_init ()) { + setup_brkhandler (); + if (currprefs.start_debugger && debuggable ()) + activate_debugger (); + +#ifdef WIN32 +#ifdef FILESYS + filesys_init (); /* New function, to do 'add_filesys_unit()' calls at start-up */ +#endif +#endif + if (sound_available && currprefs.produce_sound > 1 && ! init_audio ()) { + write_log ("Sound driver unavailable: Sound output disabled\n"); + currprefs.produce_sound = 0; + } + + start_program (); + } + + } +#if defined (NATMEM_OFFSET) && defined( _WIN32 ) && !defined( NO_WIN32_EXCEPTION_HANDLER ) + __except( EvalException( GetExceptionInformation(), GetExceptionCode() ) ) + { + // EvalException does the good stuff... + } +#endif +} + +void real_main (int argc, char **argv) +{ + restart_program = 1; +#ifdef _WIN32 + sprintf (restart_config, "%sConfigurations\\", start_path); +#endif + strcat (restart_config, OPTIONSFILENAME); + while (restart_program) { + changed_prefs = currprefs; + real_main2 (argc, argv); + leave_program (); + quit_program = 0; + } + zfile_exit (); +} + +#ifndef NO_MAIN_IN_MAIN_C +int main (int argc, char **argv) +{ + real_main (argc, argv); + return 0; +} +#endif + +#ifdef SINGLEFILE +uae_u8 singlefile_config[50000] = { "_CONFIG_STARTS_HERE" }; +uae_u8 singlefile_data[1500000] = { "_DATA_STARTS_HERE" }; +#endif diff --git a/memory.c b/memory.c new file mode 100755 index 00000000..1218c73b --- /dev/null +++ b/memory.c @@ -0,0 +1,1765 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Memory management + * + * (c) 1995 Bernd Schmidt + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "uae.h" +#include "memory.h" +#include "ersatz.h" +#include "zfile.h" +#include "custom.h" +#include "events.h" +#include "newcpu.h" +#include "autoconf.h" +#include "savestate.h" +#include "ar.h" + +#ifdef USE_MAPPED_MEMORY +#include +#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 +#include +#include +#include + +shmpiece *shm_start; + +static void dumplist(void) +{ + shmpiece *x = shm_start; + write_log ("Start Dump:\n"); + while (x) { + write_log ("this=%p,Native %p,id %d,prev=%p,next=%p,size=0x%08x\n", + x, x->native_address, x->id, x->prev, x->next, x->size); + x = x->next; + } + write_log ("End Dump:\n"); +} + +static shmpiece *find_shmpiece (uae_u8 *base) +{ + shmpiece *x = shm_start; + + while (x && x->native_address != base) + x = x->next; + if (!x) { + write_log ("NATMEM: Failure to find mapping at %p\n",base); + dumplist (); + canbang = 0; + return 0; + } + return x; +} + +static void delete_shmmaps (uae_u32 start, uae_u32 size) +{ + if (!canbang) + return; + + while (size) { + uae_u8 *base = mem_banks[bankindex (start)]->baseaddr; + if (base) { + shmpiece *x; + //base = ((uae_u8*)NATMEM_OFFSET)+start; + + x = find_shmpiece (base); + if (!x) + return; + + if (x->size > size) { + write_log ("NATMEM: Failure to delete mapping at %08x(size %08x, delsize %08x)\n",start,x->size,size); + dumplist (); + canbang = 0; + return; + } + shmdt (x->native_address); + size -= x->size; + start += x->size; + if (x->next) + x->next->prev = x->prev; /* remove this one from the list */ + if (x->prev) + x->prev->next = x->next; + else + shm_start = x->next; + free (x); + } else { + size -= 0x10000; + start += 0x10000; + } + } +} + +static void add_shmmaps (uae_u32 start, addrbank *what) +{ + shmpiece *x = shm_start; + shmpiece *y; + uae_u8 *base = what->baseaddr; + + if (!canbang) + return; + if (!base) + return; + + x = find_shmpiece (base); + if (!x) + return; + y = malloc (sizeof (shmpiece)); + *y = *x; + base = ((uae_u8 *) NATMEM_OFFSET) + start; + y->native_address = shmat (y->id, base, 0); + if (y->native_address == (void *) -1) { + write_log ("NATMEM: Failure to map existing at %08x(%p)\n",start,base); + dumplist (); + canbang = 0; + return; + } + y->next = shm_start; + y->prev = NULL; + if (y->next) + y->next->prev = y; + shm_start = y; +} + +uae_u8 *mapped_malloc (size_t s, char *file) +{ + int id; + void *answer; + shmpiece *x; + + if (!canbang) + return malloc (s); + + id = shmget (IPC_PRIVATE, s, 0x1ff, file); + if (id == -1) { + canbang = 0; + return mapped_malloc (s, file); + } + answer = shmat (id, 0, 0); + shmctl (id, IPC_RMID, NULL); + if (answer != (void *) -1) { + x = malloc (sizeof (shmpiece)); + x->native_address = answer; + x->id = id; + x->size = s; + x->next = shm_start; + x->prev = NULL; + if (x->next) + x->next->prev = x; + shm_start = x; + + return answer; + } + canbang = 0; + return mapped_malloc (s, file); +} + +#endif + +static void init_mem_banks (void) +{ + int i; + for (i = 0; i < 65536; i++) + put_mem_bank (i << 16, &dummy_bank, 0); +#ifdef NATMEM_OFFSET + delete_shmmaps (0, 0xFFFF0000); +#endif +} + +void clearexec (void) +{ + if (chipmemory) + memset (chipmemory + 4, 0, 4); +} + +static void allocate_memory (void) +{ + if (allocated_chipmem != currprefs.chipmem_size) { + if (chipmemory) + mapped_free (chipmemory); + chipmemory = 0; + + allocated_chipmem = currprefs.chipmem_size; + chipmem_mask = allocated_chipmem - 1; + + chipmemory = mapped_malloc (allocated_chipmem, "chip"); + if (chipmemory == 0) { + write_log ("Fatal error: out of memory for chipmem.\n"); + allocated_chipmem = 0; + } else + clearexec (); + } + + if (allocated_bogomem != currprefs.bogomem_size) { + if (bogomemory) + mapped_free (bogomemory); + bogomemory = 0; + + allocated_bogomem = currprefs.bogomem_size; + bogomem_mask = allocated_bogomem - 1; + + if (allocated_bogomem) { + bogomemory = mapped_malloc (allocated_bogomem, "bogo"); + if (bogomemory == 0) { + write_log ("Out of memory for bogomem.\n"); + allocated_bogomem = 0; + } + } + clearexec (); + } +#ifdef AUTOCONFIG + if (allocated_a3000mem != currprefs.a3000mem_size) { + if (a3000memory) + mapped_free (a3000memory); + a3000memory = 0; + + allocated_a3000mem = currprefs.a3000mem_size; + a3000mem_mask = allocated_a3000mem - 1; + + if (allocated_a3000mem) { + a3000memory = mapped_malloc (allocated_a3000mem, "a3000"); + if (a3000memory == 0) { + write_log ("Out of memory for a3000mem.\n"); + allocated_a3000mem = 0; + } + } + clearexec (); + } +#endif + if (savestate_state == STATE_RESTORE) { + restore_ram (chip_filepos, chipmemory); + if (allocated_bogomem > 0) + restore_ram (bogo_filepos, bogomemory); + } + chipmem_bank.baseaddr = chipmemory; +#ifdef AGA + chipmem_bank_ce2.baseaddr = chipmemory; +#endif + bogomem_bank.baseaddr = bogomemory; +} + +void map_overlay (int chip) +{ + int i = allocated_chipmem > 0x200000 ? (allocated_chipmem >> 16) : 32; + addrbank *cb; + + cb = &chipmem_bank; +#ifdef AGA + if (currprefs.cpu_cycle_exact && currprefs.cpu_level >= 2) + cb = &chipmem_bank_ce2; +#endif + if (chip) + map_banks (cb, 0, i, allocated_chipmem); + else + map_banks (&kickmem_bank, 0, i, 0x80000); + if (savestate_state != STATE_RESTORE && savestate_state != STATE_REWIND) + m68k_setpc(m68k_getpc()); +} + +void memory_reset (void) +{ + int custom_start; + + be_cnt = 0; + currprefs.chipmem_size = changed_prefs.chipmem_size; + currprefs.bogomem_size = changed_prefs.bogomem_size; + currprefs.a3000mem_size = changed_prefs.a3000mem_size; + + init_mem_banks (); + allocate_memory (); + + if (strcmp (currprefs.romfile, changed_prefs.romfile) != 0 + || strcmp (currprefs.keyfile, changed_prefs.keyfile) != 0) + { + ersatzkickfile = 0; + memcpy (currprefs.romfile, changed_prefs.romfile, sizeof currprefs.romfile); + memcpy (currprefs.keyfile, changed_prefs.keyfile, sizeof currprefs.keyfile); + if (savestate_state != STATE_RESTORE) + clearexec (); + load_extendedkickstart (); + if (!load_kickstart ()) { +#ifdef AUTOCONFIG + init_ersatz_rom (kickmemory); + ersatzkickfile = 1; +#endif + } + } + + custom_start = 0xC0; + + map_banks (&custom_bank, custom_start, 0xE0 - custom_start, 0); + map_banks (&cia_bank, 0xA0, 32, 0); + map_banks (&clock_bank, 0xDC, 1, 0); + + /* @@@ Does anyone have a clue what should be in the 0x200000 - 0xA00000 + * range on an Amiga without expansion memory? */ + custom_start = allocated_chipmem >> 16; + if (custom_start < 0x20 + (currprefs.fastmem_size >> 16)) + custom_start = 0x20 + (currprefs.fastmem_size >> 16); + map_banks (&dummy_bank, custom_start, 0xA0 - custom_start, 0); + /*map_banks (&mbres_bank, 0xDE, 1); */ + + if (bogomemory != 0) { + int t = allocated_bogomem >> 16; + if (t > 0x1C) + t = 0x1C; + map_banks (&bogomem_bank, 0xC0, t, allocated_bogomem); + } +#ifdef AUTOCONFIG + if (a3000memory != 0) + map_banks (&a3000mem_bank, a3000mem_start >> 16, allocated_a3000mem >> 16, + allocated_a3000mem); + + map_banks (&rtarea_bank, RTAREA_BASE >> 16, 1, 0); +#endif + + map_banks (&kickmem_bank, 0xF8, 8, 0); + if (currprefs.maprom) + map_banks (&kickram_bank, currprefs.maprom >> 16, 8, 0); + + if (a1000_bootrom) + a1000_handle_kickstart (1); +#ifdef AUTOCONFIG + map_banks (&expamem_bank, 0xE8, 1, 0); +#endif + + /* Map the chipmem into all of the lower 8MB */ + map_overlay (1); + +#ifdef CDTV + cdtv_enabled = 0; +#endif +#ifdef CD32 + cd32_enabled = 0; +#endif + + switch (extromtype ()) { + +#ifdef CDTV + case EXTENDED_ROM_CDTV: + map_banks (&extendedkickmem_bank, 0xF0, 4, 0); + cdtv_enabled = 1; + break; +#endif +#ifdef CD32 + case EXTENDED_ROM_CD32: + map_banks (&extendedkickmem_bank, 0xE0, 8, 0); + cd32_enabled = 1; + break; +#endif + default: + if (cloanto_rom && !currprefs.maprom) + map_banks (&kickmem_bank, 0xE0, 8, 0); + } + +#ifdef ACTION_REPLAY + action_replay_memory_reset(); + #ifdef ACTION_REPLAY_HRTMON + hrtmon_map_banks(); + #endif + + #ifndef ACTION_REPLAY_HIDE_CARTRIDGES + #ifdef ACTION_REPLAY + action_replay_map_banks(); + #endif + #endif +#endif +} + +void memory_init (void) +{ + allocated_chipmem = 0; + allocated_bogomem = 0; + kickmemory = 0; + extendedkickmemory = 0; + extendedkickmem_size = 0; + chipmemory = 0; +#ifdef AUTOCONFIG + allocated_a3000mem = 0; + a3000memory = 0; +#endif + bogomemory = 0; + + kickmemory = mapped_malloc (kickmem_size, "kick"); + memset (kickmemory, 0, kickmem_size); + kickmem_bank.baseaddr = kickmemory; + kickmem_mask = kickmem_size - 1; + currprefs.romfile[0] = 0; + currprefs.keyfile[0] = 0; +#ifdef AUTOCONFIG + init_ersatz_rom (kickmemory); + ersatzkickfile = 1; +#endif + +#ifdef ACTION_REPLAY + action_replay_load(); + action_replay_init(1); + + #ifdef ACTION_REPLAY_HRTM + hrtmon_load(1); + #endif +#endif + + init_mem_banks (); +} + +void memory_cleanup (void) +{ +#ifdef AUTOCONFIG + if (a3000memory) + mapped_free (a3000memory); + a3000memory = 0; +#endif + if (bogomemory) + mapped_free (bogomemory); + if (kickmemory) + mapped_free (kickmemory); + if (a1000_bootrom) + free (a1000_bootrom); + if (chipmemory) + mapped_free (chipmemory); + + bogomemory = 0; + kickmemory = 0; + a1000_bootrom = 0; + chipmemory = 0; + + #ifdef ACTION_REPLAY + action_replay_cleanup(); + #endif +} + +void map_banks (addrbank *bank, int start, int size, int realsize) +{ + int bnr; + unsigned long int hioffs = 0, endhioffs = 0x100; + addrbank *orgbank = bank; + uae_u32 realstart = start; + + flush_icache (1); /* Sure don't want to keep any old mappings around! */ +#ifdef NATMEM_OFFSET + delete_shmmaps (start << 16, size << 16); +#endif + + if (!realsize) + realsize = size << 16; + + if ((size << 16) < realsize) { + //write_log ("Please report to bmeyer@cs.monash.edu.au, and mention:\n"); + write_log ("Broken mapping, size=%x, realsize=%x\n", size, realsize); + write_log ("Start is %x\n", start); + write_log ("Reducing memory sizes, especially chipmem, may fix this problem\n"); + abort (); + } + + if (start >= 0x100) { + int real_left = 0; + for (bnr = start; bnr < start + size; bnr++) { + if (!real_left) { + realstart = bnr; + real_left = realsize >> 16; +#ifdef NATMEM_OFFSET + add_shmmaps (realstart << 16, bank); +#endif + } + put_mem_bank (bnr << 16, bank, realstart << 16); + real_left--; + } + return; + } + if (currprefs.address_space_24) + endhioffs = 0x10000; + for (hioffs = 0; hioffs < endhioffs; hioffs += 0x100) { + int real_left = 0; + for (bnr = start; bnr < start + size; bnr++) { + if (!real_left) { + realstart = bnr + hioffs; + real_left = realsize >> 16; +#ifdef NATMEM_OFFSET + add_shmmaps (realstart << 16, bank); +#endif + } + put_mem_bank ((bnr + hioffs) << 16, bank, realstart << 16); + real_left--; + } + } +} + + +/* memory save/restore code */ + +uae_u8 *save_cram (int *len) +{ + *len = allocated_chipmem; + return chipmemory; +} + +uae_u8 *save_bram (int *len) +{ + *len = allocated_bogomem; + return bogomemory; +} + +void restore_cram (int len, long filepos) +{ + chip_filepos = filepos; + changed_prefs.chipmem_size = len; +} + +void restore_bram (int len, long filepos) +{ + bogo_filepos = filepos; + changed_prefs.bogomem_size = len; +} + +uae_u8 *restore_rom (uae_u8 *src) +{ + restore_u32 (); + restore_u32 (); + restore_u32 (); + restore_u32 (); + restore_u32 (); + src += strlen (src) + 1; + if (src[0]) { + if (zfile_exists (src)) + strncpy (changed_prefs.romfile , src, 255); + src+=strlen(src)+1; + } + return src; +} + +uae_u8 *save_rom (int first, int *len, uae_u8 *dstptr) +{ + static int count; + uae_u8 *dst, *dstbak; + uae_u8 *mem_real_start; + int mem_start, mem_size, mem_type, i, saverom; + + saverom = 0; + if (first) + count = 0; + for (;;) { + mem_type = count; + switch (count) { + case 0: /* Kickstart ROM */ + mem_start = 0xf80000; + mem_real_start = kickmemory; + mem_size = kickmem_size; + /* 256KB or 512KB ROM? */ + for (i = 0; i < mem_size / 2 - 4; i++) { + if (longget (i + mem_start) != longget (i + mem_start + mem_size / 2)) + break; + } + if (i == mem_size / 2 - 4) { + mem_size /= 2; + mem_start += 262144; + } + mem_type = 0; + break; + default: + return 0; + } + count++; + if (mem_size) + break; + } + if (dstptr) + dstbak = dst = dstptr; + else + dstbak = dst = malloc (4 + 4 + 4 + 4 + 4 + mem_size); + save_u32 (mem_start); + save_u32 (mem_size); + save_u32 (mem_type); + save_u32 (longget (mem_start + 12)); /* version+revision */ + save_u32 (CRC32 (0, kickmemory, mem_size)); + sprintf (dst, "Kickstart %d.%d", wordget (mem_start + 12), wordget (mem_start + 14)); + dst += strlen (dst) + 1; + strcpy (dst, currprefs.romfile);/* rom image name */ + dst += strlen(dst) + 1; + if (saverom) { + for (i = 0; i < mem_size; i++) + *dst++ = byteget (mem_start + i); + } + *len = dst - dstbak; + return dstbak; +} diff --git a/missing.c b/missing.c new file mode 100755 index 00000000..d0c7ddc8 --- /dev/null +++ b/missing.c @@ -0,0 +1,44 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Various stuff missing in some OSes. + * + * Copyright 1997 Bernd Schmidt + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "uae.h" + +#ifndef HAVE_STRDUP + +char *my_strdup (const char *s) +{ + /* The casts to char * are there to shut up the compiler on HPUX */ + char *x = (char*)xmalloc(strlen((char *)s) + 1); + strcpy(x, (char *)s); + return x; +} + +#endif + +void *xmalloc (size_t n) +{ + void *a = malloc (n); + if (a == NULL) { + write_log ("virtual memory exhausted\n"); + abort (); + } + return a; +} + +void *xcalloc (size_t n, size_t size) +{ + void *a = calloc (n, size); + if (a == NULL) { + write_log ("virtual memory exhausted\n"); + abort (); + } + return a; +} diff --git a/native2amiga.c b/native2amiga.c new file mode 100755 index 00000000..f73286a8 --- /dev/null +++ b/native2amiga.c @@ -0,0 +1,114 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Call Amiga Exec functions outside the main UAE thread. + * + * Copyright 1999 Patrick Ohly + * + * Uses the EXTER interrupt that is setup in filesys.c + * and needs thread support. + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "threaddep/thread.h" +#include "options.h" +#include "memory.h" +#include "custom.h" +#include "newcpu.h" +#include "disk.h" +#include "autoconf.h" +#include "filesys.h" +#include "execlib.h" +#include "native2amiga.h" + +smp_comm_pipe native2amiga_pending; + +/* + * to be called when setting up the hardware + */ + +void native2amiga_install (void) +{ + init_comm_pipe (&native2amiga_pending, 10, 2); +} + +/* + * to be called when the Amiga boots, i.e. by filesys_diagentry() + */ +void native2amiga_startup (void) +{ +} + +#ifdef SUPPORT_THREADS + +void uae_Cause(uaecptr interrupt) +{ + write_comm_pipe_int (&native2amiga_pending, 3, 0); + write_comm_pipe_u32 (&native2amiga_pending, interrupt, 1); + + uae_int_requested = 1; +} + +void uae_ReplyMsg(uaecptr msg) +{ + write_comm_pipe_int (&native2amiga_pending, 2, 0); + write_comm_pipe_u32 (&native2amiga_pending, msg, 1); + + uae_int_requested = 1; +} + +void uae_PutMsg(uaecptr port, uaecptr msg) +{ + uae_pt data; + data.i = 1; + write_comm_pipe_int (&native2amiga_pending, 1, 0); + write_comm_pipe_u32 (&native2amiga_pending, port, 0); + write_comm_pipe_u32 (&native2amiga_pending, msg, 1); + + uae_int_requested = 1; +} + +void uae_Signal(uaecptr task, uae_u32 mask) +{ + write_comm_pipe_int (&native2amiga_pending, 0, 0); + write_comm_pipe_u32 (&native2amiga_pending, task, 0); + write_comm_pipe_int (&native2amiga_pending, mask, 1); + + uae_int_requested = 1; +} + +void uae_NotificationHack(uaecptr port, uaecptr nr) +{ + write_comm_pipe_int (&native2amiga_pending, 4, 0); + write_comm_pipe_int (&native2amiga_pending, port, 0); + write_comm_pipe_int (&native2amiga_pending, nr, 1); + + uae_int_requested = 1; +} + +#endif + +void uae_NewList(uaecptr list) +{ + put_long (list, list + 4); + put_long (list + 4, 0); + put_long (list + 8, list); +} + +uaecptr uae_AllocMem (uae_u32 size, uae_u32 flags) +{ + m68k_dreg (regs, 0) = size; + m68k_dreg (regs, 1) = flags; + write_log ("allocmem(%d,%08.8X)\n", size, flags); + return CallLib (get_long (4), -198); /* AllocMem */ +} + +void uae_FreeMem (uaecptr memory, uae_u32 size) +{ + m68k_dreg (regs, 0) = size; + m68k_areg (regs, 1) = memory; + CallLib (get_long (4), -0xD2); /* FreeMem */ +} diff --git a/ncurses.c b/ncurses.c new file mode 100755 index 00000000..03756271 --- /dev/null +++ b/ncurses.c @@ -0,0 +1,680 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * [n]curses output. + * + * There are 17 color modes: + * -H0/-H1 are black/white output + * -H2 through -H16 give you different color allocation strategies. On my + * system, -H14 seems to give nice results. + * + * Copyright 1997 Samuel Devulder, Bernd Schmidt + */ + +/****************************************************************************/ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include +#include + +/****************************************************************************/ + +#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 +#else +#include +#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> 8; + g = (i >> 4) & 15; + b = i & 15; + + xcolors[i] = (77 * r + 151 * g + 28 * b)/16; + if(xcolors[i] > maxc) + maxc = xcolors[i]; + m = r; + if (g > m) + m = g; + if (b > m) + m = b; + if (m == 0) { + xcolors[i] |= MYCOLOR_WHITE << 8; /* to get gray instead of black in dark areas */ + continue; + } + + if ((currprefs.color_mode & ~1) != 0) { + r1 = r*15 / m; + g1 = g*15 / m; + b1 = b*15 / m; + + comp = 8; + for (;;) { + if (b1 < comp) { + if (r1 < comp) + ctype = MYCOLOR_GREEN; + else if (g1 < comp) + ctype = MYCOLOR_RED; + else + ctype = MYCOLOR_YELLOW; + } else { + if (r1 < comp) { + if (g1 < comp) + ctype = MYCOLOR_BLUE; + else + ctype = MYCOLOR_CYAN; + } else if (g1 < comp) + ctype = MYCOLOR_MAGENTA; + else { + comp += 4; + if (comp == 12 && (currprefs.color_mode & 2) != 0) + continue; + ctype = MYCOLOR_WHITE; + } + } + break; + } + if (currprefs.color_mode & 8) { + if (ctype == MYCOLOR_BLUE && xcolors[i] > /*27*/50) + ctype = r1 > (g1+2) ? MYCOLOR_MAGENTA : MYCOLOR_CYAN; + if (ctype == MYCOLOR_RED && xcolors[i] > /*75*/ 90) + ctype = b1 > (g1+6) ? MYCOLOR_MAGENTA : MYCOLOR_YELLOW; + } + xcolors[i] |= ctype << 8; + } + } + if (currprefs.color_mode & 4) { + int j; + for (j = MYCOLOR_RED; j < MYCOLOR_WHITE; j++) { + int best = 0, maxv = 0; + int multi, divi; + + for (i = 0; i < 4096; i++) + if ((xcolors[i] & 255) > maxv && (xcolors[i] >> 8) == j) { + best = i; + maxv = (xcolors[best] & 255); + } + /* Now maxv is the highest intensity a color of type J is supposed to have. + * In reality, it will most likely only have intensity maxv*multi/divi. + * We try to correct this. */ + maxv = maxv * 256 / maxc; + + divi = 256; + switch (j) { + case MYCOLOR_RED: multi = 77; break; + case MYCOLOR_GREEN: multi = 151; break; + case MYCOLOR_BLUE: multi = 28; break; + case MYCOLOR_YELLOW: multi = 228; break; + case MYCOLOR_CYAN: multi = 179; break; + case MYCOLOR_MAGENTA: multi = 105; break; + default: abort(); + } +#if 1 /* This makes the correction less extreme */ + if (! (currprefs.color_mode & 8)) + multi = (multi + maxv) / 2; +#endif + for (i = 0; i < 4096; i++) { + int v = xcolors[i]; + if ((v >> 8) != j) + continue; + v &= 255; + /* I don't think either of these is completely correct, but + * the first one produces rather good results. */ +#if 1 + v = v * divi / multi; + if (v > maxc) + v = maxc; +#else + v = v * 256 / maxv); + if (v > maxc) + /*maxc = v*/abort(); +#endif + xcolors[i] = v | (j << 8); + } + } + } + x2graymap = (int *)malloc(sizeof(int) * (maxc+1)); +} + +static void curses_init(void) +{ + initscr (); + + start_color (); + if (! has_colors () || COLOR_PAIRS < 20 /* whatever */) + currprefs.color_mode &= 1; + else { + init_pair (1, COLOR_BLACK, COLOR_BLACK); + init_pair (2, COLOR_RED, COLOR_BLACK); + init_pair (3, COLOR_GREEN, COLOR_BLACK); + init_pair (4, COLOR_BLUE, COLOR_BLACK); + init_pair (5, COLOR_YELLOW, COLOR_BLACK); + init_pair (6, COLOR_CYAN, COLOR_BLACK); + init_pair (7, COLOR_MAGENTA, COLOR_BLACK); + init_pair (8, COLOR_WHITE, COLOR_BLACK); + } + printf ("curses_init: %d pairs available\n", COLOR_PAIRS); + + cbreak(); noecho(); + nonl (); intrflush(stdscr, FALSE); keypad(stdscr, TRUE); + nodelay(stdscr, TRUE); + leaveok(stdscr, TRUE); + + attron (A_NORMAL | COLOR_PAIR (0)); + bkgd(' '|COLOR_PAIR(0)); + +#ifdef NCURSES_MOUSE_VERSION + mousemask(BUTTON1_PRESSED | BUTTON1_RELEASED | + BUTTON2_PRESSED | BUTTON2_RELEASED | + BUTTON3_PRESSED | BUTTON3_RELEASED | + REPORT_MOUSE_POSITION, NULL); +#endif + + init_graychar(); + curses_on = 1; +} + +static void curses_exit(void) +{ +#ifdef NCURSES_MOUSE_VERSION + mousemask(0, NULL); +#endif + + nocbreak(); echo(); nl(); intrflush(stdscr, TRUE); + keypad(stdscr, FALSE); nodelay(stdscr, FALSE); leaveok(stdscr, FALSE); + endwin(); + curses_on = 0; +} + +/****************************************************************************/ + +static int getgraycol(int x, int y) +{ + uae_u8 *bufpt; + int xs, xl, ys, yl, c, cm; + + xl = x_map[x+1] - (xs = x_map[x]); + yl = y_map[y+1] - (ys = y_map[y]); + + bufpt = ((uae_u8 *)gfxvidinfo.bufmem) + ys*currprefs.gfx_width + xs; + + cm = c = 0; + for(y = 0; y < yl; y++, bufpt += currprefs.gfx_width) + for(x = 0; x < xl; x++) { + c += bufpt[x]; + ++cm; + } + if (cm) + c /= cm; + if (! currprefs.curses_reverse_video) + c = maxc - c; + return graychar[x2graymap[c]]; +} + +static int getcol(int x, int y) +{ + uae_u16 *bufpt; + int xs, xl, ys, yl, c, cm; + int bestcol = MYCOLOR_BLACK, bestccnt = 0; + unsigned char colcnt [8]; + + memset (colcnt, 0 , sizeof colcnt); + + xl = x_map[x+1] - (xs = x_map[x]); + yl = y_map[y+1] - (ys = y_map[y]); + + bufpt = ((uae_u16 *)gfxvidinfo.bufmem) + ys*currprefs.gfx_width + xs; + + cm = c = 0; + for(y = 0; y < yl; y++, bufpt += currprefs.gfx_width) + for(x = 0; x < xl; x++) { + int v = bufpt[x]; + int cnt; + + c += v & 0xFF; + cnt = ++colcnt[v >> 8]; + if (cnt > bestccnt) { + bestccnt = cnt; + bestcol = v >> 8; + } + ++cm; + } + if (cm) + c /= cm; + if (! currprefs.curses_reverse_video) + c = maxc - c; + return (graychar[x2graymap[c]] & ~A_COLOR) | COLOR_PAIR (mycolor2pair_map[bestcol]); +} + +static void flush_line_txt(int y) +{ + int x; + move (y,0); + if (currprefs.color_mode < 2) + for (x = 0; x < COLS; ++x) { + int c; + + c = getgraycol(x,y); + addch(c); + } + else + for (x = 0; x < COLS; ++x) { + int c; + + c = getcol(x,y); + addch(c); + } +} + +__inline__ void flush_line(int y) +{ + if(y < 0 || y >= currprefs.gfx_height) { +/* printf("flush_line out of window: %d\n", y); */ + return; + } + if(!curses_on) + return; + flush_line_txt(y_rev_map[y]); +} + +void flush_block (int ystart, int ystop) +{ + int y; + if(!curses_on) + return; + ystart = y_rev_map[ystart]; + ystop = y_rev_map[ystop]; + for(y = ystart; y <= ystop; ++y) + flush_line_txt(y); +} + +void flush_screen (int ystart, int ystop) +{ + if(!debugging && !curses_on) { + curses_init(); + flush_block(0, currprefs.gfx_height - 1); + } + refresh(); +} + +/****************************************************************************/ + +struct bstring *video_mode_menu = NULL; + +void vidmode_menu_selected(int a) +{ +} + +int graphics_setup(void) +{ + return 1; +} + +int graphics_init(void) +{ + int i; + + if (currprefs.color_mode > 16) + write_log ("Bad color mode selected. Using default.\n"), currprefs.color_mode = 0; + + init_colors(); + + curses_init(); + write_log("Using %s.\n",longname()); + + if (debugging) + curses_exit (); + + /* we have a 320x256x8 pseudo screen */ + + currprefs.gfx_width = 320; + currprefs.gfx_height = 256; + currprefs.gfx_lores = 1; + + gfxvidinfo.width = currprefs.gfx_width; + gfxvidinfo.height = currprefs.gfx_height; + gfxvidinfo.maxblocklines = 1000; + gfxvidinfo.pixbytes = currprefs.color_mode < 2 ? 1 : 2; + gfxvidinfo.rowbytes = gfxvidinfo.pixbytes * currprefs.gfx_width; + gfxvidinfo.bufmem = (char *)calloc(gfxvidinfo.rowbytes, currprefs.gfx_height+1); + gfxvidinfo.linemem = 0; + gfxvidinfo.emergmem = 0; + gfxvidinfo.can_double = 0; + switch (gfxvidinfo.pixbytes) { + case 1: + for (i = 0; i < 4096; i++) + xcolors[i] = xcolors[i] * 0x01010101; + gfxvidinfo.can_double = 1; + break; + case 2: + for (i = 0; i < 4096; i++) + xcolors[i] = xcolors[i] * 0x00010001; + gfxvidinfo.can_double = 1; + break; + } + if(!gfxvidinfo.bufmem) { + write_log("Not enough memory.\n"); + return 0; + } + + for (i = 0; i < sizeof x_map / sizeof *x_map; i++) + x_map[i] = (i * currprefs.gfx_width) / COLS; + for (i = 0; i < sizeof y_map / sizeof *y_map; i++) + y_map[i] = (i * currprefs.gfx_height) / LINES; + for (i = 0; i < sizeof y_map / sizeof *y_map - 1; i++) { + int l1 = y_map[i]; + int l2 = y_map[i+1]; + int j; + if (l2 >= sizeof y_rev_map / sizeof *y_rev_map) + break; + for (j = l1; j < l2; j++) + y_rev_map[j] = i; + } + + buttonstate[0] = buttonstate[1] = buttonstate[2] = 0; + for(i=0; i<256; i++) + keystate[i] = 0; + + lastmx = lastmy = 0; + newmousecounters = 0; + + return 1; +} + +/****************************************************************************/ + +void graphics_leave(void) +{ + curses_exit(); +} + +/****************************************************************************/ + +static int keycode2amiga(int ch) +{ + switch(ch) { + case KEY_A1: return AK_NP7; + case KEY_UP: return AK_NP8; + case KEY_A3: return AK_NP9; + case KEY_LEFT: return AK_NP4; + case KEY_B2: return AK_NP5; + case KEY_RIGHT: return AK_NP6; + case KEY_C1: return AK_NP1; + case KEY_DOWN: return AK_NP2; + case KEY_C3: return AK_NP3; + case KEY_ENTER: return AK_ENT; + case 13: return AK_RET; + case ' ': return AK_SPC; + case 27: return AK_ESC; + default: return -1; + } +} + +/***************************************************************************/ + +void handle_events(void) +{ + int ch; + int kc; + + /* Hack to simulate key release */ + for(kc = 0; kc < 256; ++kc) { + if(keystate[kc]) if(!--keystate[kc]) record_key((kc << 1) | 1); + } + if(buttonstate[0]) --buttonstate[0]; + if(buttonstate[1]) --buttonstate[1]; + if(buttonstate[2]) --buttonstate[2]; + + newmousecounters = 0; + if(!curses_on) return; + + while((ch = getch())!=ERR) { + if(ch == 12) {clearok(stdscr,TRUE);refresh();} +#ifdef NCURSES_MOUSE_VERSION + if(ch == KEY_MOUSE) { + MEVENT ev; + if(getmouse(&ev) == OK) { + lastmx = (ev.x*currprefs.gfx_width)/COLS; + lastmy = (ev.y*currprefs.gfx_height)/LINES; + if(ev.bstate & BUTTON1_PRESSED) buttonstate[0] = keydelay; + if(ev.bstate & BUTTON1_RELEASED) buttonstate[0] = 0; + if(ev.bstate & BUTTON2_PRESSED) buttonstate[1] = keydelay; + if(ev.bstate & BUTTON2_RELEASED) buttonstate[1] = 0; + if(ev.bstate & BUTTON3_PRESSED) buttonstate[2] = keydelay; + if(ev.bstate & BUTTON3_RELEASED) buttonstate[2] = 0; + } + } +#endif + if (ch == 6) ++lastmx; /* ^F */ + if (ch == 2) --lastmx; /* ^B */ + if (ch == 14) ++lastmy; /* ^N */ + if (ch == 16) --lastmy; /* ^P */ + if (ch == 11) {buttonstate[0] = keydelay;ch = 0;} /* ^K */ + if (ch == 25) {buttonstate[2] = keydelay;ch = 0;} /* ^Y */ + if (ch == 15) uae_reset (); /* ^O */ + if (ch == 17) uae_quit (); /* ^Q */ + if (ch == KEY_F(1)) { + curses_insert_disk(); + ch = 0; + } + + if(isupper(ch)) { + keystate[AK_LSH] = + keystate[AK_RSH] = keydelay; + record_key(AK_LSH << 1); + record_key(AK_RSH << 1); + kc = keycode2amiga(tolower(ch)); + keystate[kc] = keydelay; + record_key(kc << 1); + } else if((kc = keycode2amiga(ch)) >= 0) { + keystate[kc] = keydelay; + record_key(kc << 1); + } + } + gui_handle_events(); +} + +/***************************************************************************/ + +void target_specific_usage(void) +{ + printf("----------------------------------------------------------------------------\n"); + printf("[n]curses specific usage:\n"); + printf(" -x : Display reverse video.\n"); + printf("By default uae will assume a black on white display. If yours\n"); + printf("is light on dark, use -x. In case of graphics garbage, ^L will\n"); + printf("redisplay the screen. ^K simulate left mouse button, ^Y RMB.\n"); + printf("If you are using a xterm UAE can use the mouse. Else use ^F ^B\n"); + printf("^P ^N to emulate mouse mouvements.\n"); + printf("----------------------------------------------------------------------------\n"); +} + +/***************************************************************************/ + +int check_prefs_changed_gfx (void) +{ + return 0; +} + +int debuggable(void) +{ + return 1; +} + +int needmousehack(void) +{ + return 1; +} + +void LED(int on) +{ +} + +void write_log (const char *buf, ...) +{ + +} + +int lockscr (void) +{ + return 1; +} + +void unlockscr (void) +{ +} + +void target_save_options (FILE *f, struct uae_prefs *p) +{ + fprintf (f, "curses.reverse_video=%s\n", p->curses_reverse_video ? "true" : "false"); +} + +int target_parse_option (struct uae_prefs *p, char *option, char *value) +{ + return (cfgfile_yesno (option, value, "reverse_video", &p->curses_reverse_video)); +} diff --git a/newcpu.c b/newcpu.c new file mode 100755 index 00000000..b91e6663 --- /dev/null +++ b/newcpu.c @@ -0,0 +1,2567 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * MC68000 emulation + * + * (c) 1995 Bernd Schmidt + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "events.h" +#include "uae.h" +#include "memory.h" +#include "custom.h" +#include "newcpu.h" +#include "cpu_prefetch.h" +#include "autoconf.h" +#include "ersatz.h" +#include "debug.h" +#include "compiler.h" +#include "gui.h" +#include "savestate.h" +#include "blitter.h" +#include "ar.h" + +#ifdef JIT +#include "compemu.h" +#include +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 +} + + diff --git a/nogui.c b/nogui.c new file mode 100755 index 00000000..5e8830d5 --- /dev/null +++ b/nogui.c @@ -0,0 +1,88 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Interface to the Tcl/Tk GUI + * + * Copyright 1996 Bernd Schmidt + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "gui.h" + +static void sigchldhandler(int foo) +{ +} + +int gui_init (void) +{ + return 0; +} + +int gui_update (void) +{ + return 0; +} + +void gui_exit (void) +{ +} + +void gui_fps (int x) +{ +} + +void gui_led (int led, int on) +{ +} + +void gui_hd_led (int led) +{ +} + +void gui_cd_led (int led) +{ +} + +void gui_filename (int num, const char *name) +{ +} + +static void getline (char *p) +{ +} + +void gui_handle_events (void) +{ +} + +void gui_changesettings (void) +{ +} + +void gui_update_gfx (void) +{ +} + +void gui_lock (void) +{ +} + +void gui_unlock (void) +{ +} + +void gui_message (const char *format,...) +{ + char msg[2048]; + va_list parms; + + va_start (parms,format); + vsprintf ( msg, format, parms); + va_end (parms); + + write_log (msg); +} diff --git a/od-generic/exectasks.h b/od-generic/exectasks.h new file mode 100755 index 00000000..f6a93ca0 --- /dev/null +++ b/od-generic/exectasks.h @@ -0,0 +1,17 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * exec.library multitasking emulation + * + * Copyright 1996 Bernd Schmidt + */ + +struct switch_struct { + int dummy; +}; +/* Looks weird. I think I had a report once that some compiler chokes if + * the statement is empty. */ +#define EXEC_SWITCH_TASKS(run, ready) do { int i = 0; i++; } while(0) + +#define EXEC_SETUP_SWS(t) do { int i = 0; i++; } while(0) + diff --git a/od-generic/joystick.c b/od-generic/joystick.c new file mode 100755 index 00000000..5ec3561a --- /dev/null +++ b/od-generic/joystick.c @@ -0,0 +1,71 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Joystick emulation stubs + * + * Copyright 1997 Bernd Schmidt + * Copyright 2003 Richard Drummond + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "memory.h" +#include "custom.h" +#include "inputdevice.h" + +static int init_joysticks (void) +{ + return 1; +} + +static void close_joysticks (void) +{ +} + +static int acquire_joystick (int num, int flags) +{ + return 0; +} + +static void unacquire_joystick (int num) +{ +} + +static void read_joysticks (void) +{ +} + +static int get_joystick_num (void) +{ + return 0; +} + +static char *get_joystick_name (int joy) +{ + return 0; +} + +static int get_joystick_widget_num (int joy) +{ + return 0; +} + +static int get_joystick_widget_type (int joy, int num, char *name, uae_u32 *code) +{ + return IDEV_WIDGET_NONE; +} + +static int get_joystick_widget_first (int joy, int type) +{ + return -1; +} + +struct inputdevice_functions inputdevicefunc_joystick = { + init_joysticks, close_joysticks, acquire_joystick, unacquire_joystick, + read_joysticks, get_joystick_num, get_joystick_name, + get_joystick_widget_num, get_joystick_widget_type, + get_joystick_widget_first +}; diff --git a/od-generic/memory.h b/od-generic/memory.h new file mode 100755 index 00000000..5d21b6c1 --- /dev/null +++ b/od-generic/memory.h @@ -0,0 +1,11 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * See if this OS has mmap or equivalent + * + * Copyright 1996 Bernd Schmidt + */ + +#undef USE_MAPPED_MEMORY +#undef CAN_MAP_MEMORY + diff --git a/od-generic/sound.c b/od-generic/sound.c new file mode 100755 index 00000000..4c63521c --- /dev/null +++ b/od-generic/sound.c @@ -0,0 +1,43 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Support for the Mute sound system + * + * Copyright 1997 Bernd Schmidt + * Copyright 2003 Richard Drummond + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "memory.h" +#include "custom.h" +#include "audio.h" +#include "gensound.h" +#include "sounddep/sound.h" + +int init_sound (void) +{ + currprefs.produce_sound = 0; + return 1; +} + +int setup_sound (void) +{ + currprefs.produce_sound = 0; + return 1; +} + +void close_sound (void) +{ +} + +void update_sound (int freq) +{ +} + +void reset_sound (void) +{ +} diff --git a/od-generic/sound.h b/od-generic/sound.h new file mode 100755 index 00000000..1817268e --- /dev/null +++ b/od-generic/sound.h @@ -0,0 +1,27 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Support for the Mute sound system. + * + * Copyright 1997 Bernd Schmidt + */ + +static __inline__ void check_sound_buffers (void) +{ +} + +#define PUT_SOUND_BYTE(b) do { ; } while (0) +#define PUT_SOUND_WORD(b) do { ; } while (0) +#define SOUND16_BASE_VAL 0 +#define SOUND8_BASE_VAL 0 + +#define DEFAULT_SOUND_MINB 8192 +#define DEFAULT_SOUND_MAXB 8192 +#define DEFAULT_SOUND_BITS 16 +#define DEFAULT_SOUND_FREQ 44100 + +#define UNSUPPORTED_OPTION_B +#define UNSUPPORTED_OPTION_R +#define UNSUPPORTED_OPTION_b +#define UNSUPPORTED_OPTION_S + diff --git a/od-win32/ahidsound.c b/od-win32/ahidsound.c new file mode 100755 index 00000000..814ee6ca --- /dev/null +++ b/od-win32/ahidsound.c @@ -0,0 +1,901 @@ +/* + * UAE - The Un*x Amiga Emulator + * + * Win32 interface + * + * Copyright 1997 Mathias Ortmann + * Copyright 1997-2001 Brian King + * Copyright 2000-2002 Bernd Roesch + */ + + +#define NATIVBUFFNUM 4 +#define RECORDBUFFER 50 //survive 9 sec of blocking at 44100 + +#include "sysconfig.h" + +#ifdef __GNUC__ +#define INITGUID +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 +#include +#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 + +#include + +#include +#include +#include + +#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); // 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 + +#define ADJUST_SIZE 10 +#define EXP 1.5 + +void frame_drawn(void) +{ + double diff, skipmode; + + if (!avioutput_video || !avioutput_enabled) + return; + + AVIOutput_WriteVideo(); + + if (avioutput_audio && (frame_count % avioutput_fps) == 0) { + StreamSizeAudioExpected += currprefs.sound_freq; + diff = (StreamSizeAudio - StreamSizeAudioExpected) / sndbufsize; + skipmode = pow (diff < 0 ? -diff : diff, EXP); + if (diff < 0) skipmode = -skipmode; + if (skipmode < -ADJUST_SIZE) skipmode = -ADJUST_SIZE; + if (skipmode > ADJUST_SIZE) skipmode = ADJUST_SIZE; + sound_setadjust (skipmode); + write_log("AVIOutput: diff=%.2f skip=%.2f\n", diff, skipmode); + } +} + + + diff --git a/od-win32/avioutput.h b/od-win32/avioutput.h new file mode 100755 index 00000000..9365eaf7 --- /dev/null +++ b/od-win32/avioutput.h @@ -0,0 +1,58 @@ +/* + UAE - The Ultimate Amiga Emulator + + avioutput.h + + Copyright(c) 2001 - 2002 §ane +*/ + +extern int avioutput_video, avioutput_audio, avioutput_enabled, avioutput_requested; + +extern int avioutput_width, avioutput_height, avioutput_bits; +extern int avioutput_fps, avioutput_framelimiter; + +extern char avioutput_filename[MAX_PATH]; + +extern void AVIOutput_WriteAudio(uae_u8 *sndbuffer, int sndbufsize); +extern void AVIOutput_WriteVideo(void); +extern LPSTR AVIOutput_ChooseAudioCodec(HWND hwnd); +extern LPSTR AVIOutput_ChooseVideoCodec(HWND hwnd); +extern void AVIOutput_Restart(void); +extern void AVIOutput_End(void); +extern void AVIOutput_Begin(void); +extern void AVIOutput_Release(void); +extern void AVIOutput_Initialize(void); +extern void AVIOutput_RGBinfo(int,int,int,int,int,int); + +#define AVIAUDIO_AVI 1 +#define AVIAUDIO_WAV 2 + +/* +extern int avioutput_pause; + +extern int avioutput_bits; + +extern int avioutput_fps; + +extern int avioutput_width, avioutput_height; + +extern int avioutput_video, avioutput_audio; + +extern int avioutput_init; + +extern int frame_count; + +extern char avioutput_filename[MAX_PATH]; + +extern void AviOutputClearAudioCodec(HWND hwnd); +extern void AviOutputClearVideoCodec(HWND hwnd); + +extern void avioutput_screenshot(void); + +extern void AVIWriteAudio(uae_u16* sndbuffer, int sndbufsize); +extern void AVIWriteVideo(void); +extern LPSTR AVIChooseAudioCodec(HWND hwnd); +extern LPSTR AVIChooseVideoCodec(HWND hwnd); +extern void AVIUninitialize(void); +extern void AVIInitialize(void); +*/ \ No newline at end of file diff --git a/od-win32/blkdev_win32_aspi.c b/od-win32/blkdev_win32_aspi.c new file mode 100755 index 00000000..ac4b1f10 --- /dev/null +++ b/od-win32/blkdev_win32_aspi.c @@ -0,0 +1,827 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * WIN32 CDROM/HD low level access code (ASPI) + * + * Copyright 2002 Toni Wilen + * + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "memory.h" + +#include "threaddep/thread.h" +#include "blkdev.h" +#include "scsidev.h" +#include "gui.h" + +#include + +#include "scsidef.h" + +int aspi_allow_misc = 1; +int aspi_allow_all = 0; + +static int busses, AspiLoaded; +static DWORD (*pfnGetASPI32SupportInfo)(void); +static DWORD (*pfnSendASPI32Command)(LPSRB); +static BOOL (*pfnGetASPI32Buffer)(PASPI32BUFF); +static BOOL (*pfnFreeASPI32Buffer)(PASPI32BUFF); +static BOOL (*pfnTranslateASPI32Address)(PDWORD, PDWORD); +static HANDLE hAspiLib; +static int scanphase; + +struct scsi_info { + int scsibus,target,lun; + int type; + int mediainserted; + uae_u8 *buf; + char label[100]; + SCSI *handle; + int isatapi; +}; +static struct scsi_info si[MAX_TOTAL_DEVICES]; +static int unitcnt; + +static int ha_inquiry(SCSI *scgp, int id, SRB_HAInquiry *ip) +{ + DWORD Status; + + ip->SRB_Cmd = SC_HA_INQUIRY; + ip->SRB_HaId = id; + ip->SRB_Flags = 0; + ip->SRB_Hdr_Rsvd = 0; + + Status = pfnSendASPI32Command((LPSRB)ip); + if (log_scsi) + write_log ("ASPI: S=%d ha=%d, ID=%d, M='%s', Id='%s'\n", + Status, ip->HA_Count, ip->HA_SCSI_ID, ip->HA_ManagerId, ip->HA_Identifier); + if (ip->SRB_Status != SS_COMP) + return -1; + return 0; +} + +static int open_driver (SCSI *scgp) +{ + DWORD astatus; + BYTE HACount; + BYTE ASPIStatus; + int i; + + /* + * Check if ASPI library is already loaded yet + */ + if (AspiLoaded == TRUE) + return TRUE; + /* + * Load the ASPI library + */ + hAspiLib = LoadLibrary("WNASPI32"); + /* + * Check if ASPI library is loaded correctly + */ + if (hAspiLib == NULL) { + write_log ("ASPI: failed to load wnaspi32.dll\n"); + return FALSE; + } + /* + * Get a pointer to GetASPI32SupportInfo function + * and a pointer to SendASPI32Command function + */ + pfnGetASPI32SupportInfo = (DWORD(*)(void))GetProcAddress(hAspiLib, "GetASPI32SupportInfo"); + pfnSendASPI32Command = (DWORD(*)(LPSRB))GetProcAddress(hAspiLib, "SendASPI32Command"); + + if ((pfnGetASPI32SupportInfo == NULL) || (pfnSendASPI32Command == NULL)) { + write_log ("ASPI: obsolete wnaspi32.dll found\n"); + return FALSE; + } + + pfnGetASPI32Buffer = (BOOL(*)(PASPI32BUFF))GetProcAddress(hAspiLib, "GetASPI32Buffer"); + pfnFreeASPI32Buffer = (BOOL(*)(PASPI32BUFF))GetProcAddress(hAspiLib, "FreeASPI32Buffer"); + pfnTranslateASPI32Address = (BOOL(*)(PDWORD, PDWORD))GetProcAddress(hAspiLib, "TranslateASPI32Address"); + + /* + * Set AspiLoaded variable + */ + AspiLoaded = TRUE; + + astatus = pfnGetASPI32SupportInfo(); + + ASPIStatus = HIBYTE(LOWORD(astatus)); + HACount = LOBYTE(LOWORD(astatus)); + + write_log ("ASPI: open_driver %X HostASPIStatus=0x%x HACount=0x%x\n", astatus, ASPIStatus, HACount); + + if (ASPIStatus != SS_COMP && ASPIStatus != SS_NO_ADAPTERS) { + write_log ("ASPI: Could not find any host adapters, ASPIStatus == 0x%02X\n", ASPIStatus); + return FALSE; + } + busses = HACount; + + write_log ("ASPI: open_driver HostASPIStatus=0x%x HACount=0x%x\n", ASPIStatus, HACount); + + for (i=0; i < busses; i++) { + SRB_HAInquiry s; + ha_inquiry(scgp, i, &s); + } + return TRUE; +} + + +static void close_driver (void) +{ + if (!AspiLoaded) return; + AspiLoaded = FALSE; + pfnGetASPI32SupportInfo = NULL; + pfnSendASPI32Command = NULL; + pfnGetASPI32Buffer = NULL; + pfnFreeASPI32Buffer = NULL; + pfnTranslateASPI32Address = NULL; + FreeLibrary(hAspiLib); + hAspiLib = NULL; +} + + +static int scsi_bufsize (SCSI *scgp, int amt) +{ + return 63*1024; +} + +static int scsi_havebus (SCSI *scgp, int busno) +{ + if (busno < 0 || busno >= busses) + return FALSE; + return TRUE; +} + +static void *scgo_getbuf (SCSI *scgp, long amt) +{ + scgp->bufbase = malloc((size_t)(amt)); + return scgp->bufbase; +} + +static void scsi_sfree (SCSI *scgp) +{ + if (scgp->cmdstart) + free(scgp->cmdstart); + if (scgp->cmdstop) + free(scgp->cmdstop); + if (scgp->scmd) + free(scgp->scmd); + if (scgp->inq) + free(scgp->inq); + if (scgp->cap) + free(scgp->cap); + if (scgp->local) + free(scgp->local); + if (scgp->errstr) + free(scgp->errstr); + free(scgp); +} + +static SCSI *scsi_smalloc(void) +{ + SCSI *scgp; + + scgp = (SCSI *)malloc(sizeof(*scgp)); + if (scgp == NULL) + return 0; + + memset (scgp, 0, sizeof (*scgp)); + scgp->deftimeout = 20; + scgp->running = FALSE; + + scgp->cmdstart = (struct timeval *)malloc(sizeof(struct timeval)); + if (scgp->cmdstart == NULL) + goto err; + scgp->cmdstop = (struct timeval *)malloc(sizeof(struct timeval)); + if (scgp->cmdstop == NULL) + goto err; + scgp->scmd = (struct scg_cmd *)malloc(sizeof(struct scg_cmd)); + if (scgp->scmd == NULL) + goto err; + scgp->errstr = malloc(SCSI_ERRSTR_SIZE); + if (scgp->errstr == NULL) + goto err; + scgp->errptr = scgp->errbeg = scgp->errstr; + scgp->errstr[0] = '\0'; + scgp->inq = (struct scsi_inquiry *)malloc(sizeof(struct scsi_inquiry)); + if (scgp->inq == NULL) + goto err; + scgp->cap = (struct scsi_capacity *)malloc(sizeof(struct scsi_capacity)); + if (scgp->cap == NULL) + goto err; + return scgp; +err: + scsi_sfree(scgp); + return 0; +} + +#define MAX_SCG 16 /* Max # of SCSI controllers */ +#define MAX_TGT 16 /* Max # of SCSI Targets */ +#define MAX_LUN 8 /* Max # of SCSI LUNs */ + +struct scg_local { + int dummy; +}; +#define scglocal(p) ((struct scg_local *)((p)->local)) + +static SCSI *openscsi (int busno, int tgt, int tlun) +{ + SCSI *scgp = scsi_smalloc (); + + if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) { + errno = EINVAL; + if (log_scsi) + write_log ("ASPI: Illegal value for busno, target or lun '%d,%d,%d'\n", busno, tgt, tlun); + return 0; + } + /* + * Check if variables are within the range + */ + if (tgt >= 0 && tgt >= 0 && tlun >= 0) { + /* + * This is the non -scanbus case. + */ + ; + } else if (tgt != -1 || tgt != -1 || tlun != -1) { + errno = EINVAL; + return 0; + } + if (scgp->local == NULL) { + scgp->local = malloc(sizeof(struct scg_local)); + if (scgp->local == NULL) + return 0; + } + /* + * Try to open ASPI-Router + */ + if (!open_driver(scgp)) + return 0; + /* + * More than we have ... + */ + if (busno >= busses) { + close_driver (); + return 0; + } + return scgp; +} + +static void closescsi (SCSI *scgp) +{ + close_driver (); +} + +static void scsi_debug (SCSI *scgp, SRB_ExecSCSICmd *s) +{ + if (!log_scsi) + return; + if (scanphase) + return; + write_log ("ASPI EXEC_SCSI: bus=%d,target=%d,lun=%d\n", + s->SRB_HaId, s->SRB_Target, s->SRB_Lun); + scsi_log_before (scgp->scmd->cdb.cmd_cdb, scgp->scmd->cdb_len, + (s->SRB_Flags & SRB_DIR_OUT) ? s->SRB_BufPointer : 0, s->SRB_BufLen); +} + + +static void copy_sensedata(SRB_ExecSCSICmd *cp, struct scg_cmd *sp) +{ + sp->sense_count = cp->SRB_SenseLen; + if (sp->sense_count > sp->sense_len) + sp->sense_count = sp->sense_len; + memset(&sp->u_sense.Sense, 0x00, sizeof(sp->u_sense.Sense)); + if(sp->sense_len > 0) { + int len = sp->sense_len; + if (len > sizeof(sp->u_sense.Sense)) len = sizeof(sp->u_sense.Sense); + memcpy(&sp->u_sense.Sense, cp->SenseArea, len); + } + sp->u_scb.cmd_scb[0] = cp->SRB_TargStat; +} + +/* + * Set error flags + */ +static void set_error(SRB_ExecSCSICmd *cp, struct scg_cmd *sp) +{ + switch (cp->SRB_Status) { + case SS_COMP: /* 0x01 SRB completed without error */ + sp->error = SCG_NO_ERROR; + sp->ux_errno = 0; + break; + case SS_PENDING: /* 0x00 SRB being processed */ + /* + * XXX Could SS_PENDING happen ??? + */ + case SS_ABORTED: /* 0x02 SRB aborted */ + case SS_ABORT_FAIL: /* 0x03 Unable to abort SRB */ + case SS_ERR: /* 0x04 SRB completed with error */ + default: + sp->error = SCG_RETRYABLE; + sp->ux_errno = EIO; + break; + case SS_INVALID_CMD: /* 0x80 Invalid ASPI command */ + case SS_INVALID_HA: /* 0x81 Invalid host adapter number */ + case SS_NO_DEVICE: /* 0x82 SCSI device not installed */ + case SS_INVALID_SRB: /* 0xE0 Invalid parameter set in SRB */ + case SS_ILLEGAL_MODE: /* 0xE2 Unsupported Windows mode */ + case SS_NO_ASPI: /* 0xE3 No ASPI managers */ + case SS_FAILED_INIT: /* 0xE4 ASPI for windows failed init */ + case SS_MISMATCHED_COMPONENTS: /* 0xE7 The DLLs/EXEs of ASPI don't */ + /* version check */ + case SS_NO_ADAPTERS: /* 0xE8 No host adapters to manager */ + + case SS_ASPI_IS_SHUTDOWN: /* 0xEA Call came to ASPI after */ + /* PROCESS_DETACH */ + case SS_BAD_INSTALL: /* 0xEB The DLL or other components */ + /* are installed wrong */ + sp->error = SCG_FATAL; + sp->ux_errno = EINVAL; + break; + case SS_BUFFER_ALIGN: /* 0xE1 Buffer not aligned (replaces */ + /* SS_OLD_MANAGER in Win32) */ + sp->error = SCG_FATAL; + sp->ux_errno = EFAULT; + break; + + case SS_ASPI_IS_BUSY: /* 0xE5 No resources available to */ + /* execute command */ + sp->error = SCG_RETRYABLE; + sp->ux_errno = EBUSY; + break; + + case SS_BUFFER_TO_BIG: /* 0xE6 Correct spelling of 'too' */ + case SS_INSUFFICIENT_RESOURCES: /* 0xE9 Couldn't allocate resources */ + /* needed to init */ + sp->error = SCG_RETRYABLE; + sp->ux_errno = ENOMEM; + break; + } +} +static int scsiabort(SCSI *scgp, SRB_ExecSCSICmd *sp) +{ + DWORD Status = 0; + SRB_Abort s; + + if (log_scsi) + write_log ("ASPI: Attempting to abort SCSI command\n"); + /* + * Set structure variables + */ + s.SRB_Cmd = SC_ABORT_SRB; /* ASPI command code = SC_ABORT_SRB */ + s.SRB_HaId = scg_scsibus(scgp); /* ASPI host adapter number */ + s.SRB_Flags = 0; /* Flags */ + s.SRB_ToAbort = (LPSRB)&sp; /* sp */ + /* + * Initiate SCSI abort + */ + Status = pfnSendASPI32Command((LPSRB)&s); + /* + * Check condition + */ + if (s.SRB_Status != SS_COMP) { + if (log_scsi) + write_log ("ASPI: Abort ERROR! 0x%08X\n", s.SRB_Status); + return FALSE; + } + if (log_scsi) + write_log ("ASPI: Abort SCSI command completed\n"); + /* + * Everything went OK + */ + return TRUE; +} + +static int scsicmd(SCSI *scgp) +{ + struct scg_cmd *sp = scgp->scmd; + DWORD Status = 0; + DWORD EventStatus = WAIT_OBJECT_0; + HANDLE Event = NULL; + SRB_ExecSCSICmd s; + + /* + * Initialize variables + */ + sp->error = SCG_NO_ERROR; + sp->sense_count = 0; + sp->u_scb.cmd_scb[0] = 0; + sp->resid = 0; + + memset(&s, 0, sizeof(s)); /* Clear SRB structure */ + + /* + * Check cbd_len > the maximum command pakket that can be handled by ASPI + */ + if (sp->cdb_len > 16) { + sp->error = SCG_FATAL; + sp->ux_errno = EINVAL; + if (log_scsi) + write_log ("ASPI: sp->cdb_len > sizeof(SRB_ExecSCSICmd.CDBByte). Fatal error in scgo_send, exiting...\n"); + return -1; + } + /* + * copy command into SRB + */ + memcpy(&(s.CDBByte), &sp->cdb, sp->cdb_len); + + Event = CreateEvent(NULL, TRUE, FALSE, NULL); + + /* + * Fill ASPI structure + */ + s.SRB_Cmd = SC_EXEC_SCSI_CMD; /* SCSI Command */ + s.SRB_HaId = scg_scsibus(scgp); /* Host adapter number */ + s.SRB_Flags = SRB_EVENT_NOTIFY; /* Flags */ + s.SRB_Target = scg_target(scgp); /* Target SCSI ID */ + s.SRB_Lun = scg_lun(scgp); /* Target SCSI LUN */ + s.SRB_BufLen = sp->size; /* # of bytes transferred */ + s.SRB_BufPointer= sp->addr; /* pointer to data buffer */ + s.SRB_CDBLen = sp->cdb_len; /* SCSI command length */ + s.SRB_PostProc = Event; /* Post proc event */ + s.SRB_SenseLen = SENSE_LEN; /* Lenght of sense buffer */ + + /* + * Do we receive data from this ASPI command? + */ + if (sp->flags & SCG_RECV_DATA) { + s.SRB_Flags |= SRB_DIR_IN; + } else { + /* + * Set direction to output + */ + if (sp->size > 0) + s.SRB_Flags |= SRB_DIR_OUT; + } + + scsi_debug (scgp,&s); + + /* + * ------------ Send SCSI command -------------------------- + */ + + ResetEvent (Event); /* Clear event handle */ + Status = pfnSendASPI32Command((LPSRB)&s);/* Initiate SCSI command */ + + if (Status == SS_PENDING) { /* If in progress */ + /* + * Wait until command completes, or times out. + */ + EventStatus = WaitForSingleObject(Event, sp->timeout * 1000); + if (EventStatus == WAIT_OBJECT_0) + ResetEvent(Event); /* Clear event, time out */ + if (s.SRB_Status == SS_PENDING) {/* Check if we got a timeout*/ + scsiabort(scgp, &s); + ResetEvent(Event); /* Clear event, time out */ + CloseHandle(Event); /* Close the event handle */ + sp->error = SCG_TIMEOUT; + return 1; /* Return error */ + } + } + CloseHandle (Event); /* Close the event handle */ + + /* + * Check ASPI command status + */ + + if (log_scsi && !scanphase) + scsi_log_after ((s.SRB_Flags & SRB_DIR_IN) ? s.SRB_BufPointer : 0, s.SRB_BufLen, + sp->u_sense.cmd_sense, sp->sense_len); + + if (s.SRB_Status != SS_COMP) { + if (log_scsi && s.SRB_Status != 0x82) + write_log ("ASPI: Error in scgo_send: s.SRB_Status is 0x%x\n", s.SRB_Status); + set_error(&s, sp); /* Set error flags */ + copy_sensedata(&s, sp); /* Copy sense and status */ + if (log_scsi && s.SRB_Status != 0x82) + write_log ("ASPI: Mapped to: error %d errno: %d\n", sp->error, sp->ux_errno); + return 1; + } + /* + * Return success + */ + return 0; +} + +static int inquiry (SCSI *scgp, void *bp, int cnt) +{ + struct scg_cmd *scmd = scgp->scmd; + + memset(bp, 0, cnt); + memset(scmd, 0, sizeof(struct scg_cmd)); + scmd->addr = bp; + scmd->size = cnt; + scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; + scmd->cdb_len = SC_G0_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->target = scgp->addr.target; + scmd->cdb.g0_cdb.cmd = SC_INQUIRY; + scmd->cdb.g0_cdb.lun = scgp->addr.lun; + scmd->cdb.g0_cdb.count = cnt; + scgp->scmd->timeout = 10 * 60; + if (scsicmd(scgp)) + return -1; + return 0; +} + +static int scsierr(SCSI *scgp) +{ + register struct scg_cmd *cp = scgp->scmd; + + if(cp->error != SCG_NO_ERROR || + cp->ux_errno != 0 || *(u_char *)&cp->scb != 0) + return -1; + return 0; +} + +static void scan_scsi_bus (SCSI *scgp, int flags) +{ + /* add all units we find */ + scanphase = 1; + for (scgp->addr.scsibus=0; scgp->addr.scsibus < 8; scgp->addr.scsibus++) { + if (!scsi_havebus(scgp, scgp->addr.scsibus)) + continue; + for (scgp->addr.target=0; scgp->addr.target < 16; scgp->addr.target++) { + struct scsi_inquiry inq; + scgp->addr.lun = 0; + if (inquiry (scgp, &inq, sizeof(inq))) + continue; + for (scgp->addr.lun=0; scgp->addr.lun < 8; scgp->addr.lun++) { + if (!inquiry (scgp, &inq, sizeof(inq))) { + write_log ("ASPI: %d:%d:%d ", scgp->addr.scsibus,scgp->addr.target,scgp->addr.lun); + write_log ("'%.8s' ", inq.vendor_info); + write_log ("'%.16s' ", inq.prod_ident); + write_log ("'%.4s' ", inq.prod_revision); + if (unitcnt < MAX_TOTAL_DEVICES) { + struct scsi_info *cis = &si[unitcnt]; + int use = 0; + write_log ("["); + if (inq.type == INQ_ROMD) { + write_log ("CDROM"); + use = 1; + } else if (!flags && ((inq.type >= INQ_SEQD && inq.type < INQ_COMM && inq.type != INQ_PROCD && aspi_allow_misc) || aspi_allow_all)) { + write_log ("%d", inq.type); + use = 1; + } else { + write_log ("<%d>", inq.type); + } + if (inq.ansi_version == 0) { + write_log (",ATAPI"); + cis->isatapi = 1; + } else + write_log (",SCSI"); + write_log("]"); + if (use) { + unitcnt++; + cis->buf = malloc (DEVICE_SCSI_BUFSIZE); + cis->scsibus = scgp->addr.scsibus; + cis->target = scgp->addr.target; + cis->lun = scgp->addr.lun; + cis->type = inq.type; + sprintf (cis->label, "%.8s %.16s %.4s", inq.vendor_info, inq.prod_ident, inq.prod_revision); + } + } + write_log ("\n"); + } + } + } + } + scanphase = 0; +} + +static void aspi_led (int unitnum) +{ + int type = si[unitnum].type; + + if (type == INQ_ROMD) + gui_cd_led (1); + else if (type == INQ_DASD) + gui_hd_led (1); +} + +static uae_sem_t scgp_sem; + +static uae_u8 *execscsicmd_out (int unitnum, uae_u8 *data, int len) +{ + SCSI *scgp = si[unitnum].handle; + int v; + + uae_sem_wait (&scgp_sem); + scgp->scmd->cdb_len = len; + memcpy (scgp->scmd->cdb.cmd_cdb, data, len); + scgp->scmd->addr = 0; + scgp->scmd->size = 0; + scgp->addr.scsibus = si[unitnum].scsibus; + scgp->addr.target = si[unitnum].target; + scgp->addr.lun = si[unitnum].lun; + scgp->scmd->timeout = 80 * 60; + aspi_led (unitnum); + v = scsicmd (scgp); + aspi_led (unitnum); + uae_sem_post (&scgp_sem); + if (v) + return 0; + return data; +} + +static uae_u8 *execscsicmd_in (int unitnum, uae_u8 *data, int len, int *outlen) +{ + SCSI *scgp = si[unitnum].handle; + int v; + + uae_sem_wait (&scgp_sem); + scgp->scmd->cdb_len = len; + memcpy (scgp->scmd->cdb.cmd_cdb, data, len); + scgp->scmd->addr = si[unitnum].buf; + scgp->scmd->size = DEVICE_SCSI_BUFSIZE; + scgp->addr.scsibus = si[unitnum].scsibus; + scgp->addr.target = si[unitnum].target; + scgp->addr.lun = si[unitnum].lun; + scgp->scmd->timeout = 80 * 60; + aspi_led (unitnum); + v = scsicmd (scgp); + aspi_led (unitnum); + uae_sem_post (&scgp_sem); + if (v) + return 0; + if (outlen) + *outlen = scgp->scmd->size; + return si[unitnum].buf; +} + +static SCSI *scsi_handle; + +static int open_scsi_bus (int flags) +{ + SCSI *scgp = openscsi (-1, -1, -1); + unitcnt = 0; + if (scgp) { + scan_scsi_bus (scgp, flags); + uae_sem_init (&scgp_sem, 0, 1); + } + scsi_handle = scgp; + return scgp ? 1 : 0; +} + +static int mediacheck (int unitnum) +{ + uae_u8 cmd [6] = { 0,0,0,0,0,0 }; /* TEST UNIT READY */ + if (si[unitnum].handle == 0) + return 0; + return execscsicmd_out (unitnum, cmd, sizeof(cmd)) ? 1 : 0; +} + +static int open_scsi_device (int unitnum) +{ + if (unitnum >= unitcnt) + return 0; + if (log_scsi) + write_log ("ASPI: opening %d:%d:%d\n", si[unitnum].scsibus, si[unitnum].target, si[unitnum].lun); + si[unitnum].handle = openscsi (si[unitnum].scsibus, si[unitnum].target, si[unitnum].lun); + if (si[unitnum].handle) + si[unitnum].mediainserted = mediacheck (unitnum); + if (log_scsi) + write_log ("unit %d: %s\n", unitnum, si[unitnum].mediainserted ? "CD inserted" : "Drive empty"); + return si[unitnum].handle ? 1 : 0; +} + +static void close_scsi_device (int unitnum) +{ + if (unitnum >= unitcnt) + return; + if (!si[unitnum].handle) + return; + scsi_sfree (si[unitnum].handle); + si[unitnum].handle = 0; +} + +static void close_scsi_bus (void) +{ + closescsi (scsi_handle); + scsi_handle = 0; +} + +static int execscsicmd_direct (int unitnum, uaecptr acmd) +{ + int sactual = 0, i, parm; + SCSI *scgp = si[unitnum].handle; + struct scg_cmd *scmd = scgp->scmd; + uaecptr scsi_data = get_long (acmd + 0); + uae_u32 scsi_len = get_long (acmd + 4); + uaecptr scsi_cmd = get_long (acmd + 12); + int scsi_cmd_len = get_word (acmd + 16); + int scsi_cmd_len_org = scsi_cmd_len; + uae_u8 scsi_flags = get_byte (acmd + 20); + uaecptr scsi_sense = get_long (acmd + 22); + uae_u16 scsi_sense_len = get_word (acmd + 26); + int io_error = 0; + addrbank *bank_data = &get_mem_bank (scsi_data); + uae_u8 *scsi_datap, *scsi_datap_org; + + /* do transfer directly to and from Amiga memory */ + if (!bank_data || !bank_data->check (scsi_data, scsi_len)) + return -5; /* IOERR_BADADDRESS */ + + uae_sem_wait (&scgp_sem); + + /* the Amiga does not tell us how long the timeout shall be, so make it _very_ long (specified in seconds) */ + scmd->timeout = 80 * 60; + scsi_datap = scsi_datap_org = scsi_len ? bank_data->xlateaddr (scsi_data) : 0; + scmd->flags = ((scsi_flags & 1) ? SCG_RECV_DATA : 0) | SCG_DISRE_ENA; + for (i = 0; i < scsi_cmd_len; i++) + scmd->cdb.cmd_cdb[i] = get_byte (scsi_cmd + i); + scmd->target = si[unitnum].target; + scmd->sense_len = (scsi_flags & 4) ? 4 : /* SCSIF_OLDAUTOSENSE */ + (scsi_flags & 2) ? scsi_sense_len : /* SCSIF_AUTOSENSE */ + -1; + scmd->sense_count = 0; + scmd->u_scb.cmd_scb[0] = 0; + scgp->addr.scsibus = si[unitnum].scsibus; + scgp->addr.target = si[unitnum].target; + scgp->addr.lun = si[unitnum].lun; + if (si[unitnum].isatapi) + scsi_atapi_fixup_pre (scmd->cdb.cmd_cdb, &scsi_cmd_len, &scsi_datap, &scsi_len, &parm); + scmd->addr = scsi_datap; + scmd->size = scsi_len; + scmd->cdb_len = scsi_cmd_len; + aspi_led (unitnum); + scsicmd (scgp); + aspi_led (unitnum); + + put_word (acmd + 18, scmd->error == SCG_FATAL ? 0 : scsi_cmd_len_org); /* fake scsi_CmdActual */ + put_byte (acmd + 21, scmd->u_scb.cmd_scb[0]); /* scsi_Status */ + if (scmd->u_scb.cmd_scb[0]) { + io_error = 45; /* HFERR_BadStatus */ + /* copy sense? */ + for (sactual = 0; scsi_sense && sactual < scsi_sense_len && sactual < scmd->sense_count; sactual++) + put_byte (scsi_sense + sactual, scmd->u_sense.cmd_sense[sactual]); + put_long (acmd + 8, 0); /* scsi_Actual */ + } else { + int i; + for (i = 0; i < scsi_sense_len; i++) + put_byte (scsi_sense + i, 0); + sactual = 0; + if (scmd->error != SCG_NO_ERROR) { + io_error = 20; /* io_Error, but not specified */ + put_long (acmd + 8, 0); /* scsi_Actual */ + } else { + io_error = 0; + if (si[unitnum].isatapi) + scsi_atapi_fixup_post (scmd->cdb.cmd_cdb, scsi_cmd_len, scsi_datap_org, scsi_datap, &scsi_len, parm); + put_long (acmd + 8, scsi_len - scmd->resid); /* scsi_Actual */ + } + } + put_word (acmd + 28, sactual); + + uae_sem_post (&scgp_sem); + + if (scsi_datap != scsi_datap_org) + free (scsi_datap); + + return io_error; +} + +static struct device_info *info_device (int unitnum, struct device_info *di) +{ + if (unitnum >= unitcnt) + return 0; + di->bus = si[unitnum].scsibus; + di->target = si[unitnum].target; + di->lun = si[unitnum].lun; + di->media_inserted = mediacheck (unitnum); //si[unitnum].mediainserted; + di->write_protected = 1; + di->bytespersector = 2048; + di->cylinders = 1; + di->type = si[unitnum].type; + di->id = unitnum + 1; + strcpy (di->label, si[unitnum].label); + return di; +} + +void win32_aspi_media_change (char driveletter, int insert) +{ + int i, now; + + for (i = 0; i < MAX_TOTAL_DEVICES; i++) { + now = mediacheck (i); + if (now != si[i].mediainserted) { + write_log ("ASPI: media change %c %d\n", driveletter, insert); + si[i].mediainserted = now; + scsi_do_disk_change (i + 1, insert); + } + } +} + +static int check_isatapi (int unitnum) +{ + return si[unitnum].isatapi; +} + +struct device_functions devicefunc_win32_aspi = { + open_scsi_bus, close_scsi_bus, open_scsi_device, close_scsi_device, info_device, + execscsicmd_out, execscsicmd_in, execscsicmd_direct, + 0, 0, 0, 0, 0, 0, 0, check_isatapi +}; diff --git a/od-win32/blkdev_win32_ioctl.c b/od-win32/blkdev_win32_ioctl.c new file mode 100755 index 00000000..d1996d2f --- /dev/null +++ b/od-win32/blkdev_win32_ioctl.c @@ -0,0 +1,458 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * WIN32 CDROM/HD low level access code (IOCTL) + * + * Copyright 2002 Toni Wilen + * + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#ifdef WINDDK + +#include "config.h" +#include "uae.h" +#include "threaddep/thread.h" +#include "blkdev.h" +#include "scsidev.h" +#include "gui.h" + +#include +#include + +struct dev_info_ioctl { + HANDLE h; + uae_u8 *tempbuffer; + char drvletter; + char devname[30]; + int mediainserted; + int type; +}; + +static UINT errormode; + +static void seterrormode (void) +{ + errormode = SetErrorMode( SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX ); +} +static void reseterrormode (void) +{ + SetErrorMode (errormode); +} + +static struct dev_info_ioctl ciw32[MAX_TOTAL_DEVICES + 64 + 32]; + +static void close_device (int unitnum); +static int open_device (int unitnum); + +static int win32_error (int unitnum, const char *format,...) +{ + LPVOID lpMsgBuf; + va_list arglist; + char buf[1000]; + DWORD err = GetLastError(); + + if (err == 34) { + write_log ("IOCTL: media change, re-opening device\n"); + close_device (unitnum); + if (!open_device (unitnum)) + write_log ("IOCTL: re-opening failed!\n"); + return -1; + } + va_start (arglist, format ); + vsprintf (buf, format, arglist); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, + NULL,err,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf,0,NULL); + if (log_scsi) + write_log ("IOCTL: unit=%d %s,%d: %s ", unitnum, buf, err, (char*)lpMsgBuf); + va_end( arglist ); + return err; +} + + +/* pause/unpause CD audio */ +static int ioctl_command_pause (int unitnum, int paused) +{ + DWORD len; + int command = paused ? IOCTL_CDROM_PAUSE_AUDIO : IOCTL_CDROM_RESUME_AUDIO; + int cnt = 3; + + while (cnt-- > 0) { + seterrormode (); + if (!DeviceIoControl(ciw32[unitnum].h, command, NULL, 0, NULL, 0, &len, NULL)) { + reseterrormode (); + if (win32_error (unitnum, paused ? "IOCTL_CDROM_PAUSE_AUDIO" : "IOCTL_CDROM_RESUME_AUDIO") < 0) + continue; + return 0; + } + reseterrormode (); + break; + } + return 1; +} + +/* stop CD audio */ +static int ioctl_command_stop (int unitnum) +{ + DWORD len; + int cnt = 3; + + while (cnt-- > 0) { + seterrormode (); + if(!DeviceIoControl(ciw32[unitnum].h, IOCTL_CDROM_STOP_AUDIO, NULL, 0, NULL, 0, &len, NULL)) { + reseterrormode (); + if (win32_error (unitnum, "IOCTL_CDROM_STOP_AUDIO") < 0) + continue; + return 0; + } + reseterrormode (); + break; + } + return 1; +} + +/* play CD audio */ +static int ioctl_command_play (int unitnum, uae_u32 start, uae_u32 end, int scan) +{ + DWORD len; + CDROM_PLAY_AUDIO_MSF pa; + int cnt = 3; + + while (cnt-- > 0) { + pa.StartingM = start >> 16; + pa.StartingS = start >> 8; + pa.StartingF = start >> 0; + pa.EndingM = end >> 16; + pa.EndingS = end >> 8; + pa.EndingF = end >> 0; + seterrormode (); + if (!DeviceIoControl(ciw32[unitnum].h, IOCTL_CDROM_PLAY_AUDIO_MSF, &pa, sizeof(pa), NULL, 0, &len, NULL)) { + reseterrormode (); + if (win32_error (unitnum, "IOCTL_CDROM_PLAY_AUDIO_MSF %02.%02.%02-%02.%02.%02", + pa.StartingM, pa.StartingS, pa.StartingF, pa.EndingM, pa.EndingS, pa.EndingF ) < 0) continue; + return 0; + } + reseterrormode (); + break; + } + return 1; +} + +/* read qcode */ +static uae_u8 *ioctl_command_qcode (int unitnum) +{ + SUB_Q_CHANNEL_DATA qcd; + DWORD len; + ULONG in = 1; + uae_u8 *p = ciw32[unitnum].tempbuffer; + int cnt = 3; + + memset (p, 0, 4 + 12); + p[1] = 0x15; + p[3] = 12; + while (cnt-- > 0) { + reseterrormode (); + if(!DeviceIoControl(ciw32[unitnum].h, IOCTL_CDROM_READ_Q_CHANNEL, &in, sizeof(in), &qcd, sizeof (qcd), &len, NULL)) { + reseterrormode (); + if (win32_error (unitnum, "IOCTL_CDROM_READ_Q_CHANNEL") < 0) + continue; + return 0; + } + break; + } + reseterrormode (); + p[1] = qcd.CurrentPosition.Header.AudioStatus; + p += 4; + p[1] = (qcd.CurrentPosition.Control << 0) | (qcd.CurrentPosition.ADR << 4); + p[2] = qcd.CurrentPosition.TrackNumber; + p[3] = qcd.CurrentPosition.IndexNumber; + p[5] = qcd.CurrentPosition.AbsoluteAddress[1]; + p[6] = qcd.CurrentPosition.AbsoluteAddress[2]; + p[7] = qcd.CurrentPosition.AbsoluteAddress[3]; + p[9] = qcd.CurrentPosition.TrackRelativeAddress[1]; + p[10] = qcd.CurrentPosition.TrackRelativeAddress[2]; + p[11] = qcd.CurrentPosition.TrackRelativeAddress[3]; + return ciw32[unitnum].tempbuffer; +} + +static uae_u8 *ioctl_command_read (int unitnum, int sector) +{ + DWORD dtotal; + int cnt = 3; + + while (cnt-- > 0) { + gui_cd_led (1); + seterrormode (); + if (SetFilePointer (ciw32[unitnum].h, sector * 2048, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { + reseterrormode (); + if (win32_error (unitnum, "SetFilePointer") < 0) + continue; + return 0; + } + reseterrormode (); + break; + } + cnt = 3; + while (cnt-- > 0) { + gui_cd_led (1); + if (!ReadFile (ciw32[unitnum].h, ciw32[unitnum].tempbuffer, 2048, &dtotal, 0)) { + reseterrormode (); + if (win32_error (unitnum, "ReadFile") < 0) + continue; + return 0; + } + reseterrormode (); + gui_cd_led (1); + break; + } + return ciw32[unitnum].tempbuffer; +} + +static int ioctl_command_write (int unitnum, int sector, uae_u8 *data) +{ + return 0; +} + +static int fetch_geometry (int unitnum, struct device_info *di) +{ + DISK_GEOMETRY geom; + DWORD len; + int cnt = 3; + + while (cnt-- > 0) { + seterrormode (); + if (!DeviceIoControl(ciw32[unitnum].h, IOCTL_CDROM_GET_DRIVE_GEOMETRY, NULL, 0, &geom, sizeof(geom), &len, NULL)) { + reseterrormode (); + if (win32_error (unitnum, "IOCTL_CDROM_GET_DRIVE_GEOMETRY") < 0) + continue; + return 0; + } + reseterrormode (); + break; + } + if (di) { + di->cylinders = geom.Cylinders.LowPart; + di->sectorspertrack = geom.SectorsPerTrack; + di->trackspercylinder = geom.TracksPerCylinder; + di->bytespersector = geom.BytesPerSector; + } + return 1; +} + + +/* read toc */ +static uae_u8 *ioctl_command_toc (int unitnum) +{ + CDROM_TOC toc; + DWORD len; + int i; + uae_u8 *p = ciw32[unitnum].tempbuffer; + int cnt = 3; + + gui_cd_led (1); + while (cnt-- > 0) { + seterrormode (); + if (!DeviceIoControl(ciw32[unitnum].h, IOCTL_CDROM_READ_TOC, NULL, 0, &toc, sizeof(toc), &len, NULL)) { + reseterrormode (); + if (!win32_error (unitnum, "IOCTL_CDROM_READ_TOC")) + continue; + return 0; + } + reseterrormode (); + break; + } + + p[0] = ((toc.LastTrack + 4) * 11) >> 8; + p[1] = ((toc.LastTrack + 4) * 11) & 0xff; + p[2] = 1; + p[3] = toc.LastTrack; + p += 4; + memset (p, 0, 11); + p[0] = 1; + p[1] = (toc.TrackData[0].Control << 0) | (toc.TrackData[0].Adr << 4); + p[3] = 0xa0; + p[8] = 1; + p += 11; + memset (p, 0, 11); + p[0] = 1; + p[1] = 0x10; + p[3] = 0xa1; + p[8] = toc.LastTrack; + p += 11; + memset (p, 0, 11); + p[0] = 1; + p[1] = 0x10; + p[3] = 0xa2; + p[8] = toc.TrackData[toc.LastTrack].Address[1]; + p[9] = toc.TrackData[toc.LastTrack].Address[2]; + p[10] = toc.TrackData[toc.LastTrack].Address[3]; + p += 11; + for (i = 0; i < toc.LastTrack; i++) { + memset (p, 0, 11); + p[0] = 1; + p[1] = (toc.TrackData[i].Control << 0) | (toc.TrackData[i].Adr << 4); + p[2] = 0; + p[3] = i + 1; + p[8] = toc.TrackData[i].Address[1]; + p[9] = toc.TrackData[i].Address[2]; + p[10] = toc.TrackData[i].Address[3]; + p += 11; + } + gui_cd_led (1); + return ciw32[unitnum].tempbuffer; +} + +/* open device level access to cd rom drive */ +static int sys_cddev_open (int unitnum) +{ + DWORD len; + struct dev_info_ioctl *ciw = &ciw32[unitnum]; + DWORD flags; + + /* buffer must be page aligned for device access */ + ciw->tempbuffer = VirtualAlloc (NULL, 4096, MEM_COMMIT, PAGE_READWRITE); + if (!ciw->tempbuffer) { + write_log ("IOCTL: failed to allocate buffer"); + return 1; + } + flags = GENERIC_READ; + ciw->h = CreateFile(ciw->devname, flags, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (ciw->h == INVALID_HANDLE_VALUE) { + flags |= GENERIC_WRITE; + ciw->h = CreateFile(ciw->devname, flags, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (ciw->h == INVALID_HANDLE_VALUE) { + write_log ("IOCTL: failed to open device handle (%s)\n", ciw->devname); + goto error; + } + } + DeviceIoControl(ciw->h, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, NULL, 0, &len, NULL); + ciw->mediainserted = ioctl_command_toc (unitnum) ? 1 : 0; + write_log ("IOCTL: device '%s' opened succesfully (unit number=%d,media=%d)\n", ciw->devname, unitnum, ciw->mediainserted); + ioctl_command_stop (unitnum); + return 0; +error: + win32_error (unitnum, "CreateFile"); + VirtualFree (ciw->tempbuffer, 0, MEM_RELEASE); + ciw->tempbuffer = NULL; + CloseHandle (ciw->h); + ciw->h = NULL; + return -1; +} + +static int unitcheck (int unitnum) +{ + if (unitnum >= MAX_TOTAL_DEVICES) { + if (unitnum < 'A' || unitnum > 'Z') + return 0; + return 1; + } + if (ciw32[unitnum].drvletter == 0) + return 0; + return 1; +} + +/* close device handle */ +void sys_cddev_close (int unitnum) +{ + if (!unitcheck (unitnum)) + return; + CloseHandle (ciw32[unitnum].h); + ciw32[unitnum].h = NULL; + VirtualFree (ciw32[unitnum].tempbuffer, 0, MEM_RELEASE); + ciw32[unitnum].tempbuffer = NULL; +} + +static int open_device (int unitnum) +{ + if (!unitcheck (unitnum)) + return 0; + if (sys_cddev_open (unitnum) == 0) + return 1; + return 0; +} +static void close_device (int unitnum) +{ + sys_cddev_close (unitnum); +} + +static void close_bus (void) +{ +} + +static int total_devices; + +static int open_bus (int flags) +{ + int dwDriveMask; + int drive, i; + char tmp[10]; + + for (i = 0; i < MAX_TOTAL_DEVICES; i++) + memset (&ciw32[i], 0, sizeof (struct dev_info_ioctl)); + total_devices = 0; + dwDriveMask = GetLogicalDrives(); + if (log_scsi) + write_log ("IOCTL: drive mask = %08.8X\n", dwDriveMask); + dwDriveMask >>= 2; // Skip A and B drives... + for( drive = 'C'; drive <= 'Z'; drive++) { + if (dwDriveMask & 1) { + int dt; + sprintf( tmp, "%c:\\", drive ); + dt = GetDriveType (tmp); + if (log_scsi) + write_log ("IOCTL: drive %c type %d\n", drive, dt); + if (((flags & (1 << INQ_ROMD)) && dt == DRIVE_CDROM) || ((flags & (1 << INQ_DASD)) && dt == DRIVE_FIXED)) { + if (log_scsi) + write_log ("IOCTL: drive %c: = unit %d\n", drive, total_devices); + ciw32[total_devices].drvletter = drive; + ciw32[total_devices].type = dt; + sprintf (ciw32[total_devices].devname,"\\\\.\\%c:", drive); + total_devices++; + } + } + dwDriveMask >>= 1; + } + return total_devices; +} + +static struct device_info *info_device (int unitnum, struct device_info *di) +{ + if (!unitcheck (unitnum)) + return 0; + di->bus = unitnum; + di->target = 0; + di->lun = 0; + di->media_inserted = 0; + if (fetch_geometry (unitnum, di)) // || ioctl_command_toc (unitnum)) + di->media_inserted = 1; + di->write_protected = 1; + di->type = ciw32[unitnum].type == DRIVE_CDROM ? INQ_ROMD : INQ_DASD; + di->id = ciw32[unitnum].drvletter; + sprintf (di->label, "Drive %c:", ciw32[unitnum].drvletter); + return di; +} + +void win32_ioctl_media_change (char driveletter, int insert) +{ + int i; + + for (i = 0; i < MAX_TOTAL_DEVICES; i++) { + if (ciw32[i].drvletter == driveletter && ciw32[i].mediainserted != insert) { + write_log ("IOCTL: media change %c %d\n", driveletter, insert); + ciw32[i].mediainserted = insert; + scsi_do_disk_change (driveletter, insert); + } + } +} + +struct device_functions devicefunc_win32_ioctl = { + open_bus, close_bus, open_device, close_device, info_device, + 0, 0, 0, + ioctl_command_pause, ioctl_command_stop, ioctl_command_play, ioctl_command_qcode, + ioctl_command_toc, ioctl_command_read, ioctl_command_write +}; + +#endif diff --git a/od-win32/blkdev_win32_spti.c b/od-win32/blkdev_win32_spti.c new file mode 100755 index 00000000..85db9d18 --- /dev/null +++ b/od-win32/blkdev_win32_spti.c @@ -0,0 +1,366 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * WIN32 CDROM/HD low level access code (SPTI) + * + * Copyright 2002 Toni Wilen + * + */ + + +#include "sysconfig.h" +#include "sysdeps.h" + +#ifdef WINDDK + +#include "memory.h" +#include "threaddep/thread.h" +#include "blkdev.h" +#include "scsidev.h" +#include "gui.h" + +#include + +#include +#include +#include + +typedef struct _SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER { + SCSI_PASS_THROUGH_DIRECT spt; + ULONG Filler; + UCHAR SenseBuf[32]; +} SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER; + +static int unitcnt = 0; + +struct dev_info_spti { + char drvletter; + char drvpath[10]; + int mediainserted; + HANDLE handle; + int isatapi; +}; + +static uae_sem_t scgp_sem; +static struct dev_info_spti dev_info[MAX_TOTAL_DEVICES]; +static uae_u8 *scsibuf; + +static int doscsi (HANDLE *h, SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER *swb, int *err) +{ + DWORD status, returned; + int i; + + *err = 0; + if (log_scsi) { + write_log ("SCSI, H=%X: ", h); + scsi_log_before (swb->spt.Cdb, swb->spt.CdbLength, + swb->spt.DataIn == SCSI_IOCTL_DATA_OUT ? swb->spt.DataBuffer : 0,swb->spt.DataTransferLength); + } + gui_cd_led (1); + status = DeviceIoControl (h, IOCTL_SCSI_PASS_THROUGH_DIRECT, + swb, sizeof (SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER), + swb, sizeof (SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER), + &returned, NULL); + if (!status) { + int lasterror = GetLastError(); + *err = lasterror; + write_log("SCSI ERROR, H=%X: ", h); + write_log("Error code = %d, LastError=%d\n", swb->spt.ScsiStatus, lasterror); + scsi_log_before (swb->spt.Cdb, swb->spt.CdbLength, + swb->spt.DataIn == SCSI_IOCTL_DATA_OUT ? swb->spt.DataBuffer : 0,swb->spt.DataTransferLength); + } + if (log_scsi) + scsi_log_after (swb->spt.DataIn == SCSI_IOCTL_DATA_IN ? swb->spt.DataBuffer : 0, swb->spt.DataTransferLength, + swb->SenseBuf, swb->spt.SenseInfoLength); + if (swb->spt.SenseInfoLength > 0) + return 0; + gui_cd_led (1); + return status; +} + + +#define MODE_SELECT_6 0x15 +#define MODE_SENSE_6 0x1A +#define MODE_SELECT_10 0x55 +#define MODE_SENSE_10 0x5A + +static int execscsicmd (int unitnum, uae_u8 *data, int len, uae_u8 *inbuf, int inlen) +{ + SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb; + DWORD status; + int err, dolen; + + uae_sem_wait (&scgp_sem); + memset (&swb, 0, sizeof (swb)); + swb.spt.Length = sizeof (SCSI_PASS_THROUGH); + swb.spt.CdbLength = len; + if (inbuf) { + swb.spt.DataIn = SCSI_IOCTL_DATA_IN; + swb.spt.DataTransferLength = inlen; + swb.spt.DataBuffer = inbuf; + memset (inbuf, 0, inlen); + } else { + swb.spt.DataIn = SCSI_IOCTL_DATA_OUT; + } + swb.spt.TimeOutValue = 80 * 60; + swb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf); + swb.spt.SenseInfoLength = 32; + memcpy (swb.spt.Cdb, data, len); + status = doscsi (dev_info[unitnum].handle, &swb, &err); + uae_sem_post (&scgp_sem); + dolen = swb.spt.DataTransferLength; + if (!status) + return -1; + return dolen; +} + +static int execscsicmd_direct (int unitnum, uaecptr acmd) +{ + SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb; + DWORD status; + int sactual = 0, i; + uaecptr scsi_data = get_long (acmd + 0); + uae_u32 scsi_len = get_long (acmd + 4); + uaecptr scsi_cmd = get_long (acmd + 12); + int scsi_cmd_len = get_word (acmd + 16); + int scsi_cmd_len_orig = scsi_cmd_len; + uae_u8 scsi_flags = get_byte (acmd + 20); + uaecptr scsi_sense = get_long (acmd + 22); + uae_u16 scsi_sense_len = get_word (acmd + 26); + int io_error = 0, err, parm; + addrbank *bank_data = &get_mem_bank (scsi_data); + uae_u8 *scsi_datap, *scsi_datap_org; + + memset (&swb, 0, sizeof (swb)); + swb.spt.Length = sizeof (SCSI_PASS_THROUGH); + swb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf); + + /* do transfer directly to and from Amiga memory */ + if (!bank_data || !bank_data->check (scsi_data, scsi_len)) + return -5; /* IOERR_BADADDRESS */ + + uae_sem_wait (&scgp_sem); + + /* the Amiga does not tell us how long the timeout shall be, so make it _very_ long (specified in seconds) */ + swb.spt.TimeOutValue = 80 * 60; + scsi_datap = scsi_datap_org = scsi_len ? bank_data->xlateaddr (scsi_data) : 0; + swb.spt.DataIn = (scsi_flags & 1) ? SCSI_IOCTL_DATA_IN : SCSI_IOCTL_DATA_OUT; + for (i = 0; i < scsi_cmd_len; i++) + swb.spt.Cdb[i] = get_byte (scsi_cmd + i); + if (scsi_sense_len > 32) + scsi_sense_len = 32; + swb.spt.SenseInfoLength = (scsi_flags & 4) ? 4 : /* SCSIF_OLDAUTOSENSE */ + (scsi_flags & 2) ? scsi_sense_len : /* SCSIF_AUTOSENSE */ + 32; + if (dev_info[unitnum].isatapi) + scsi_atapi_fixup_pre (swb.spt.Cdb, &scsi_cmd_len, &scsi_datap, &scsi_len, &parm); + swb.spt.CdbLength = (UCHAR)scsi_cmd_len; + swb.spt.DataTransferLength = scsi_len; + swb.spt.DataBuffer = scsi_datap; + + status = doscsi (dev_info[unitnum].handle, &swb, &err); + + put_word (acmd + 18, status == 0 ? 0 : scsi_cmd_len_orig); /* fake scsi_CmdActual */ + put_byte (acmd + 21, swb.spt.ScsiStatus); /* scsi_Status */ + if (swb.spt.ScsiStatus) { + io_error = 45; /* HFERR_BadStatus */ + /* copy sense? */ + for (sactual = 0; scsi_sense && sactual < scsi_sense_len && sactual < swb.spt.SenseInfoLength; sactual++) + put_byte (scsi_sense + sactual, swb.SenseBuf[sactual]); + put_long (acmd + 8, 0); /* scsi_Actual */ + } else { + int i; + for (i = 0; i < scsi_sense_len; i++) + put_byte (scsi_sense + i, 0); + sactual = 0; + if (status == 0) { + io_error = 20; /* io_Error, but not specified */ + put_long (acmd + 8, 0); /* scsi_Actual */ + } else { + scsi_len = swb.spt.DataTransferLength; + if (dev_info[unitnum].isatapi) + scsi_atapi_fixup_post (swb.spt.Cdb, scsi_cmd_len, scsi_datap_org, scsi_datap, &scsi_len, parm); + io_error = 0; + put_long (acmd + 8, scsi_len); /* scsi_Actual */ + } + } + put_word (acmd + 28, sactual); + uae_sem_post (&scgp_sem); + + if (scsi_datap != scsi_datap_org) + free (scsi_datap); + + return io_error; +} + +static uae_u8 *execscsicmd_out (int unitnum, uae_u8 *data, int len) +{ + int v = execscsicmd (unitnum, data, len, 0, 0); + if (v < 0) + return 0; + return data; +} + +static uae_u8 *execscsicmd_in (int unitnum, uae_u8 *data, int len, int *outlen) +{ + int v = execscsicmd (unitnum, data, len, scsibuf, DEVICE_SCSI_BUFSIZE); + if (v < 0) + return 0; + if (v == 0) + return 0; + if (outlen) + *outlen = v; + return scsibuf; +} + +static int adddrive (int unitnum, char drive) +{ + if (unitcnt >= MAX_TOTAL_DEVICES) + return 0; + sprintf (dev_info[unitcnt].drvpath, "\\\\.\\%c:", drive); + dev_info[unitcnt].drvletter = drive; + write_log ("SPTI: selected drive %c: (uaescsi.device:%d)\n", drive, unitnum); + unitcnt++; + return 1; +} + +static int total_devices; + +static int open_scsi_bus (int flags) +{ + int dwDriveMask; + int drive, firstdrive; + char tmp[10], tmp2[10]; + int i; + + total_devices = 0; + firstdrive = 0; + uae_sem_init (&scgp_sem, 0, 1); + for (i = 0; i < MAX_TOTAL_DEVICES; i++) { + memset (&dev_info[i], 0, sizeof (struct dev_info_spti)); + dev_info[i].handle = INVALID_HANDLE_VALUE; + } + if (!scsibuf) + scsibuf = VirtualAlloc (NULL, DEVICE_SCSI_BUFSIZE, MEM_COMMIT, PAGE_READWRITE); + dwDriveMask = GetLogicalDrives (); + device_debug ("SPTI: drive mask = %08.8X\n", dwDriveMask); + dwDriveMask >>= 2; // Skip A and B drives... + for( drive = 'C'; drive <= 'Z'; drive++) { + if (dwDriveMask & 1) { + int dt; + sprintf( tmp, "%c:\\", drive ); + sprintf( tmp2, "%c:\\.", drive ); + dt = GetDriveType (tmp); + device_debug ("SPTI: drive %c type %d\n", drive, dt); + if (dt == DRIVE_CDROM) { + if (!firstdrive) + firstdrive = drive; + if (adddrive (total_devices, drive)) + total_devices++; + } + } + dwDriveMask >>= 1; + } + return total_devices; +} + +static void close_scsi_bus (void) +{ + VirtualFree (scsibuf, 0, MEM_RELEASE); + scsibuf = 0; +} + +static int isatapi (int unitnum) +{ + uae_u8 cmd[6] = { 0x12,0,0,0,36,0 }; /* INQUIRY */ + uae_u8 out[36]; + int outlen = sizeof (out); + uae_u8 *p = execscsicmd_in (unitnum, cmd, sizeof (cmd), &outlen); + if (!p) + return 0; + if (outlen >= 2 && (p[0] & 31) == 5 && (p[2] & 7) == 0) + return 1; + return 0; +} + +static int mediacheck (int unitnum) +{ + uae_u8 cmd [6] = { 0,0,0,0,0,0 }; /* TEST UNIT READY */ + if (dev_info[unitnum].handle == INVALID_HANDLE_VALUE) + return 0; + return execscsicmd (unitnum, cmd, sizeof (cmd), 0, 0) >= 0 ? 1 : 0; +} + +int open_scsi_device (int unitnum) +{ + HANDLE h; + char *dev; + + dev = dev_info[unitnum].drvpath; + if (!dev[0]) + return 0; + h = CreateFile(dev,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL); + dev_info[unitnum].handle = h; + if (h == INVALID_HANDLE_VALUE) { + write_log ("failed to open cd unit %d (%s)\n", unitnum, dev); + } else { + dev_info[unitnum].mediainserted = mediacheck (unitnum); + dev_info[unitnum].isatapi = isatapi (unitnum); + write_log ("cd unit %d %s opened (%s), %s\n", unitnum, + dev_info[unitnum].isatapi ? "[ATAPI]" : "[SCSI]", dev, + dev_info[unitnum].mediainserted ? "CD inserted" : "Drive empty"); + return 1; + } + return 0; +} + +static void close_scsi_device (int unitnum) +{ + write_log ("cd unit %d closed\n", unitnum); + if (dev_info[unitnum].handle != INVALID_HANDLE_VALUE) + CloseHandle (dev_info[unitnum].handle); + dev_info[unitnum].handle = INVALID_HANDLE_VALUE; +} + +static struct device_info *info_device (int unitnum, struct device_info *di) +{ + if (unitnum >= MAX_TOTAL_DEVICES || dev_info[unitnum].handle == INVALID_HANDLE_VALUE) + return 0; + sprintf(di->label,"Drive %c", dev_info[unitnum].drvletter); + di->bus = 0; + di->target = unitnum; + di->lun = 0; + di->media_inserted = mediacheck (unitnum); + di->write_protected = 1; + di->bytespersector = 2048; + di->cylinders = 1; + di->type = INQ_ROMD; + di->id = dev_info[unitnum].drvletter; + return di; +} + +void win32_spti_media_change (char driveletter, int insert) +{ + int i; + + for (i = 0; i < MAX_TOTAL_DEVICES; i++) { + if (dev_info[i].drvletter == driveletter && dev_info[i].mediainserted != insert) { + write_log ("SPTI: media change %c %d\n", driveletter, insert); + dev_info[i].mediainserted = insert; + scsi_do_disk_change (driveletter, insert); + } + } +} + +static int check_isatapi (int unitnum) +{ + return dev_info[unitnum].isatapi; +} + +struct device_functions devicefunc_win32_spti = { + open_scsi_bus, close_scsi_bus, open_scsi_device, close_scsi_device, info_device, + execscsicmd_out, execscsicmd_in, execscsicmd_direct, + 0, 0, 0, 0, 0, 0, 0, check_isatapi +}; + +#endif \ No newline at end of file diff --git a/od-win32/bsdsock.c b/od-win32/bsdsock.c new file mode 100755 index 00000000..28f52618 --- /dev/null +++ b/od-win32/bsdsock.c @@ -0,0 +1,2574 @@ +/* + * UAE - The Un*x Amiga Emulator + * + * bsdsocket.library emulation - Win32 OS-dependent part + * + * Copyright 1997,98 Mathias Ortmann + * Copyright 1999,2000 Brian King + * + * GNU Public License + * + */ +#include "sysconfig.h" +#include "sysdeps.h" + +#include +#include +#include + +#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)<signal)|sb->eintrsigs|wssigs; + sigs = CallLib(get_long(4),-0x13e); // Wait() +/* + if ((1<signal) & sigs) + { // 2.3.2002/SR Fix for AmiFTP -> Thread is ready, no need to Abort + sb->needAbort = 0; + } +*/ + if (sb->needAbort) + { + if ((newsock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == INVALID_SOCKET) + write_log("BSDSOCK: ERROR - Cannot create socket: %d\n",WSAGetLastError()); + shutdown(sb->sockAbort,1); + if (newsock != sb->sockAbort) + { + shutdown(sb->sockAbort,1); + closesocket(sb->sockAbort); + } + } + + WaitForSingleObject(sb->hEvent,INFINITE); + + CANCELSIGNAL; + + if (newsock != INVALID_SOCKET) sb->sockAbort = newsock; + + if( sigmp ) + { + put_long(sigmp,sigs & wssigs); + + if (sigs & sb->eintrsigs) + { + TRACE(("[interrupted]\n")); + sb->resultval = -1; + seterrno(sb,4); // EINTR + } + else if (sigs & wssigs) + { + TRACE(("[interrupted by signals 0x%08lx]\n",sigs & wssigs)); + if (readfds) fd_zero(readfds,nfds); + if (writefds) fd_zero(writefds,nfds); + if (exceptfds) fd_zero(exceptfds,nfds); + seterrno(sb,0); + sb->resultval = 0; + } + if (sb->resultval >= 0) + { + TRACE(("%d\n",sb->resultval)); + } + else + { + TRACE(("%d errno %d\n",sb->resultval,sb->sb_errno)); + } + + } + else TRACE(("%d\n",sb->resultval)); + } +} + +uae_u32 host_Inet_NtoA(SB, uae_u32 in) +{ + char *addr; + struct in_addr ina; + uae_u32 scratchbuf; + + *(uae_u32 *)&ina = htonl(in); + + TRACE(("Inet_NtoA(%lx) -> ",in)); + + if ((addr = inet_ntoa(ina)) != NULL) + { + scratchbuf = m68k_areg(regs,6)+offsetof(struct UAEBSDBase,scratchbuf); + strncpyha(scratchbuf,addr,SCRATCHBUFSIZE); + TRACE(("%s\n",addr)); + return scratchbuf; + } + else SETERRNO; + + TRACE(("failed (%d)\n",sb->sb_errno)); + + return 0; +} + +uae_u32 host_inet_addr(uae_u32 cp) +{ + uae_u32 addr; + char *cp_rp; + + cp_rp = get_real_address(cp); + + addr = htonl(inet_addr(cp_rp)); + + TRACE(("inet_addr(%s) -> 0x%08lx\n",cp_rp,addr)); + + return addr; +} + + +static unsigned int __stdcall thread_get(void *index2) +{ + uae_u32 index = (uae_u32)index2; + unsigned int result = 0; + uae_u32 *args; + uae_u32 name; + uae_u32 namelen; + long addrtype; + char *name_rp; + char *buf; + + + SB; + + for (;;) + { + WaitForSingleObject(hGetEvents[index],INFINITE); + + if ((args = threadGetargs[index]) != NULL) + { + + sb = (struct socketbase *)*args; + if (args[1] == 0) + { // gethostbyname or gethostbyaddr + struct hostent *host; + + name = args[2]; + namelen = args[3]; + addrtype = args[4]; + buf = (char*) args[5]; + name_rp = get_real_address(name); + + if (addrtype == -1) + { + host = gethostbyname(name_rp); + } + else + { + host = gethostbyaddr(name_rp,namelen,addrtype); + } + if (threadGetargs[index] != -1) + { // No CTRL-C Signal + if (host == 0) + { + // Error occured + SETERRNO; + TRACE(("failed (%d) - ",sb->sb_errno)); + } + else + { + seterrno(sb,0); + memcpy(buf,host,sizeof(HOSTENT)); + } + } + } + if (args[1] == 1) + { // getprotobyname + struct protoent *proto; + + name = args[2]; + buf = (char*) args[5]; + name_rp = get_real_address(name); + proto = getprotobyname (name_rp); + if (threadGetargs[index] != -1) + { // No CTRL-C Signal + if (proto == 0) + { + // Error occured + SETERRNO; + TRACE(("failed (%d) - ",sb->sb_errno)); + } + else + { + seterrno(sb,0); + memcpy(buf,proto,sizeof(struct protoent)); + } + } + } + if (args[1] == 2) + { // getservbyport and getservbyname + uae_u32 nameport; + uae_u32 proto; + uae_u32 type; + char *proto_rp = 0; + struct servent *serv; + + nameport = args[2]; + proto = args[3]; + type = args[4]; + buf = (char*) args[5]; + + if (proto) proto_rp = get_real_address(proto); + + if (type) + { + serv = getservbyport(nameport,proto_rp); + } + else + { + name_rp = get_real_address(nameport); + serv = getservbyname(name_rp,proto_rp); + } + if (threadGetargs[index] != -1) + { // No CTRL-C Signal + if (serv == 0) + { + // Error occured + SETERRNO; + TRACE(("failed (%d) - ",sb->sb_errno)); + } + else + { + seterrno(sb,0); + memcpy(buf,serv,sizeof(struct servent)); + } + } + } + + + + + TRACE(("-> ")); + + if (threadGetargs[index] != -1) + SETSIGNAL; + + threadGetargs[index] = NULL; + + } + } +#ifndef __GNUC__ + _endthreadex( result ); +#endif + return result; +} + +void host_gethostbynameaddr(SB, uae_u32 name, uae_u32 namelen, long addrtype) +{ + HOSTENT *h; + int size, numaliases = 0, numaddr = 0; + uae_u32 aptr; + char *name_rp; + int i; + + uae_u32 args[6]; + + uae_u32 addr; + uae_u32 *addr_list[2]; + + char buf[MAXGETHOSTSTRUCT]; + unsigned int wMsg = 0; + + char on = 1; + InternetSetOption(0,INTERNET_OPTION_SETTINGS_CHANGED,&on,strlen(&on)); + + name_rp = get_real_address(name); + + + if (addrtype == -1) + { + TRACE(("gethostbyname(%s) -> ",name_rp)); + + // workaround for numeric host "names" + if ((addr = inet_addr(name_rp)) != INADDR_NONE) + { + seterrno(sb,0); + ((HOSTENT *)buf)->h_name = name_rp; + ((HOSTENT *)buf)->h_aliases = NULL; + ((HOSTENT *)buf)->h_addrtype = AF_INET; + ((HOSTENT *)buf)->h_length = 4; + ((HOSTENT *)buf)->h_addr_list = (char **)&addr_list; + addr_list[0] = &addr; + addr_list[1] = NULL; + + goto kludge; + } + } + else + { + TRACE(("gethostbyaddr(0x%lx,0x%lx,%ld) -> ",name,namelen,addrtype)); + } + + args[0] = (uae_u32) sb; + args[1] = 0; + args[2] = name; + args[3] = namelen; + args[4] = addrtype; + args[5] = (uae_u32) &buf[0]; + + for (i = 0; i < MAX_GET_THREADS; i++) if (hGetThreads[i] && !threadGetargs[i]) break; + + if (i >= MAX_GET_THREADS) + { + for (i = 0; i < MAX_GET_THREADS; i++) + { + if (!hGetThreads[i]) + { + if ((hGetEvents[i] = CreateEvent(NULL,FALSE,FALSE,NULL)) == NULL || (hGetThreads[i] = (void *)THREAD(thread_get,i)) == NULL) + { + hGetThreads[i] = 0; + write_log("BSDSOCK: ERROR - Thread/Event creation failed - error code: %d\n",GetLastError()); + seterrno(sb,12); // ENOMEM + sb->resultval = -1; + return; + } + break; + } + } + } + + if (i >= MAX_GET_THREADS) write_log("BSDSOCK: ERROR - Too many gethostbyname()s\n"); + else + { + int pri; + pri = priorities[currprefs.win32_active_priority].value; + + SetThreadPriority(hGetThreads[i],pri); + + threadGetargs[i] = (uae_u32 *)&args[0]; + + SetEvent(hGetEvents[i]); + } + sb->eintr = 0; + while ( threadGetargs[i] != 0 && sb->eintr == 0) + { + WAITSIGNAL; + if (sb->eintr == 1) + threadGetargs[i] = -1; + } + + CANCELSIGNAL; + + if (!sb->sb_errno) + { +kludge: + h = (HOSTENT *)buf; + + // compute total size of hostent + size = 28; + if (h->h_name != NULL) size += strlen(h->h_name)+1; + + if (h->h_aliases != NULL) + while (h->h_aliases[numaliases]) size += strlen(h->h_aliases[numaliases++])+5; + + if (h->h_addr_list != NULL) + { + while (h->h_addr_list[numaddr]) numaddr++; + size += numaddr*(h->h_length+4); + } + + if (sb->hostent) + { + uae_FreeMem( sb->hostent, sb->hostentsize ); + } + + sb->hostent = uae_AllocMem( size, 0 ); + + if (!sb->hostent) + { + write_log("BSDSOCK: WARNING - gethostby%s() ran out of Amiga memory (couldn't allocate %ld bytes) while returning result of lookup for '%s'\n",addrtype == -1 ? "name" : "addr",size,(char *)name); + seterrno(sb,12); // ENOMEM + return; + } + + sb->hostentsize = size; + + aptr = sb->hostent+28+numaliases*4+numaddr*4; + + // transfer hostent to Amiga memory + put_long(sb->hostent+4,sb->hostent+20); + put_long(sb->hostent+8,h->h_addrtype); + put_long(sb->hostent+12,h->h_length); + put_long(sb->hostent+16,sb->hostent+24+numaliases*4); + + for (i = 0; i < numaliases; i++) put_long(sb->hostent+20+i*4,addstr(&aptr,h->h_aliases[i])); + put_long(sb->hostent+20+numaliases*4,0); + for (i = 0; i < numaddr; i++) put_long(sb->hostent+24+(numaliases+i)*4,addmem(&aptr,h->h_addr_list[i],h->h_length)); + put_long(sb->hostent+24+numaliases*4+numaddr*4,0); + put_long(sb->hostent,aptr); + addstr(&aptr,h->h_name); + + TRACE(("OK (%s)\n",h->h_name)); + seterrno(sb,0); + } + else + { + TRACE(("failed (%d/%d)\n",sb->sb_errno,sb->sb_herrno)); + } + +} + +void host_getprotobyname(SB, uae_u32 name) +{ + PROTOENT *p; + int size, numaliases = 0; + uae_u32 aptr; + char *name_rp; + int i; + + uae_u32 args[6]; + + + char buf[MAXGETHOSTSTRUCT]; + + name_rp = get_real_address(name); + + TRACE(("getprotobyname(%s) -> ",name_rp)); + + args[0] = (uae_u32) sb; + args[1] = 1; + args[2] = name; + args[5] = (uae_u32) &buf[0]; + + for (i = 0; i < MAX_GET_THREADS; i++) if (hGetThreads[i] && !threadGetargs[i]) break; + + if (i >= MAX_GET_THREADS) + { + for (i = 0; i < MAX_GET_THREADS; i++) + { + if (!hGetThreads[i]) + { + if ((hGetEvents[i] = CreateEvent(NULL,FALSE,FALSE,NULL)) == NULL || (hGetThreads[i] = (void *)THREAD(thread_get,i)) == NULL) + { + hGetThreads[i] = 0; + write_log("BSDSOCK: ERROR - Thread/Event creation failed - error code: %d\n",GetLastError()); + seterrno(sb,12); // ENOMEM + sb->resultval = -1; + return; + } + break; + } + } + } + + if (i >= MAX_GET_THREADS) write_log("BSDSOCK: ERROR - Too many getprotobyname()s\n"); + else + { + int pri; + pri = priorities[currprefs.win32_active_priority].value; + + SetThreadPriority(hGetThreads[i],pri); + + + threadGetargs[i] = (uae_u32 *)&args[0]; + + SetEvent(hGetEvents[i]); + } + + sb->eintr = 0; + while ( threadGetargs[i] != 0 && sb->eintr == 0) + { + WAITSIGNAL; + if (sb->eintr == 1) + threadGetargs[i] = -1; + } + + CANCELSIGNAL; + + + if (!sb->sb_errno) + { + p = (PROTOENT *)buf; + + // compute total size of protoent + size = 16; + if (p->p_name != NULL) size += strlen(p->p_name)+1; + + if (p->p_aliases != NULL) + while (p->p_aliases[numaliases]) size += strlen(p->p_aliases[numaliases++])+5; + + if (sb->protoent) + { + uae_FreeMem( sb->protoent, sb->protoentsize ); + } + + sb->protoent = uae_AllocMem( size, 0 ); + + if (!sb->protoent) + { + write_log("BSDSOCK: WARNING - getprotobyname() ran out of Amiga memory (couldn't allocate %ld bytes) while returning result of lookup for '%s'\n",size,(char *)name); + seterrno(sb,12); // ENOMEM + return; + } + + sb->protoentsize = size; + + aptr = sb->protoent+16+numaliases*4; + + // transfer protoent to Amiga memory + put_long(sb->protoent+4,sb->protoent+12); + put_long(sb->protoent+8,p->p_proto); + + for (i = 0; i < numaliases; i++) put_long(sb->protoent+12+i*4,addstr(&aptr,p->p_aliases[i])); + put_long(sb->protoent+12+numaliases*4,0); + put_long(sb->protoent,aptr); + addstr(&aptr,p->p_name); + TRACE(("OK (%s, %d)\n",p->p_name,p->p_proto)); + seterrno(sb,0); + } + else + { + TRACE(("failed (%d)\n",sb->sb_errno)); + } + +} + + +void host_getservbynameport(SB, uae_u32 nameport, uae_u32 proto, uae_u32 type) +{ + SERVENT *s; + int size, numaliases = 0; + uae_u32 aptr; + char *name_rp = NULL, *proto_rp = NULL; + int i; + + char buf[MAXGETHOSTSTRUCT]; + uae_u32 args[6]; + + if (proto) proto_rp = get_real_address(proto); + + if (type) + { + TRACE(("getservbyport(%d,%s) -> ",nameport,proto_rp ? proto_rp : "NULL")); + } + else + { + name_rp = get_real_address(nameport); + TRACE(("getservbyname(%s,%s) -> ",name_rp,proto_rp ? proto_rp : "NULL")); + } + + args[0] = (uae_u32) sb; + args[1] = 2; + args[2] = nameport; + args[3] = proto; + args[4] = type; + args[5] = (uae_u32) &buf[0]; + + for (i = 0; i < MAX_GET_THREADS; i++) if (hGetThreads[i] && !threadGetargs[i]) break; + + if (i >= MAX_GET_THREADS) + { + for (i = 0; i < MAX_GET_THREADS; i++) + { + if (!hGetThreads[i]) + { + if ((hGetEvents[i] = CreateEvent(NULL,FALSE,FALSE,NULL)) == NULL || (hGetThreads[i] = (void *)THREAD(thread_get,i)) == NULL) + { + hGetThreads[i] = 0; + write_log("BSDSOCK: ERROR - Thread/Event creation failed - error code: %d\n",GetLastError()); + seterrno(sb,12); // ENOMEM + sb->resultval = -1; + return; + } + + break; + } + } + } + + if (i >= MAX_GET_THREADS) write_log("BSDSOCK: ERROR - Too many getprotobyname()s\n"); + else + { + int pri; + pri = priorities[currprefs.win32_active_priority].value; + + SetThreadPriority(hGetThreads[i],pri); + + + threadGetargs[i] = (uae_u32 *)&args[0]; + + SetEvent(hGetEvents[i]); + } + + sb->eintr = 0; + while ( threadGetargs[i] != 0 && sb->eintr == 0) + { + WAITSIGNAL; + if (sb->eintr == 1) + threadGetargs[i] = -1; + } + + CANCELSIGNAL; + + if (!sb->sb_errno) + { + s = (SERVENT *)buf; + + // compute total size of servent + size = 20; + if (s->s_name != NULL) size += strlen(s->s_name)+1; + if (s->s_proto != NULL) size += strlen(s->s_proto)+1; + + if (s->s_aliases != NULL) + while (s->s_aliases[numaliases]) size += strlen(s->s_aliases[numaliases++])+5; + + if (sb->servent) + { + uae_FreeMem( sb->servent, sb->serventsize ); + } + + sb->servent = uae_AllocMem( size, 0 ); + + if (!sb->servent) + { + write_log("BSDSOCK: WARNING - getservby%s() ran out of Amiga memory (couldn't allocate %ld bytes)\n",type ? "port" : "name",size); + seterrno(sb,12); // ENOMEM + return; + } + + sb->serventsize = size; + + aptr = sb->servent+20+numaliases*4; + + // transfer servent to Amiga memory + put_long(sb->servent+4,sb->servent+16); + put_long(sb->servent+8,(unsigned short)htons(s->s_port)); + + for (i = 0; i < numaliases; i++) put_long(sb->servent+16+i*4,addstr(&aptr,s->s_aliases[i])); + put_long(sb->servent+16+numaliases*4,0); + put_long(sb->servent,aptr); + addstr(&aptr,s->s_name); + put_long(sb->servent+12,aptr); + addstr(&aptr,s->s_proto); + + TRACE(("OK (%s, %d)\n",s->s_name,(unsigned short)htons(s->s_port))); + seterrno(sb,0); + } + else + { + TRACE(("failed (%d)\n",sb->sb_errno)); + } + +} + + + +uae_u32 host_gethostname(uae_u32 name, uae_u32 namelen) +{ + return gethostname(get_real_address(name),namelen); +} + +#endif diff --git a/od-win32/build68k_msvc/build68k_msvc.rc b/od-win32/build68k_msvc/build68k_msvc.rc new file mode 100755 index 00000000..3eee795f --- /dev/null +++ b/od-win32/build68k_msvc/build68k_msvc.rc @@ -0,0 +1,61 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE 9, 1 +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/od-win32/build68k_msvc/build68k_msvc.vcproj b/od-win32/build68k_msvc/build68k_msvc.vcproj new file mode 100755 index 00000000..9a00c02c --- /dev/null +++ b/od-win32/build68k_msvc/build68k_msvc.vcproj @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/od-win32/caps/CapsAPI.h b/od-win32/caps/CapsAPI.h new file mode 100755 index 00000000..528a5fef --- /dev/null +++ b/od-win32/caps/CapsAPI.h @@ -0,0 +1,118 @@ +#ifndef CAPSAPI_H +#define CAPSAPI_H + +#define CAPS_FILEEXT "ipf" +#define CAPS_FILEPFX ".ipf" + +// Flags provided for locking, in order: +// 0: re-align data as index synced recording +// 1: decode track to word aligned size +// 2: generate cell density for variable density tracks +// 3: generate density for automatically sized cells +// 4: generate density for unformatted cells +// 5: generate unformatted data +// 6: generate unformatted data, that changes each revolution +#define DI_LOCK_INDEX DF_0 +#define DI_LOCK_ALIGN DF_1 +#define DI_LOCK_DENVAR DF_2 +#define DI_LOCK_DENAUTO DF_3 +#define DI_LOCK_DENNOISE DF_4 +#define DI_LOCK_NOISE DF_5 +#define DI_LOCK_NOISEREV DF_6 +#define DI_LOCK_MEMREF DF_7 + +#define CAPS_MAXPLATFORM 4 +#define CAPS_MTRS 5 + +#pragma pack(push, 1) + +// decoded caps date.time +struct CapsDateTimeExt { + UDWORD year; + UDWORD month; + UDWORD day; + UDWORD hour; + UDWORD min; + UDWORD sec; + UDWORD tick; +}; + +typedef struct CapsDateTimeExt *PCAPSDATETIMEEXT; + +// disk image information block +struct CapsImageInfo { + UDWORD type; // image type + UDWORD release; // release ID + UDWORD revision; // release revision ID + UDWORD mincylinder; // lowest cylinder number + UDWORD maxcylinder; // highest cylinder number + UDWORD minhead; // lowest head number + UDWORD maxhead; // highest head number + struct CapsDateTimeExt crdt; // image creation date.time + UDWORD platform[CAPS_MAXPLATFORM]; // intended platform(s) +}; + +typedef struct CapsImageInfo *PCAPSIMAGEINFO; + +// disk track information block +struct CapsTrackInfo { + UDWORD type; // track type + UDWORD cylinder; // cylinder# + UDWORD head; // head# + UDWORD sectorcnt; // available sectors + UDWORD sectorsize; // sector size + UDWORD trackcnt; // track variant count + PUBYTE trackbuf; // track buffer memory + UDWORD tracklen; // track buffer memory length + PUBYTE trackdata[CAPS_MTRS]; // track data pointer if available + UDWORD tracksize[CAPS_MTRS]; // track data size + UDWORD timelen; // timing buffer length + PUDWORD timebuf; // timing buffer +}; + +typedef struct CapsTrackInfo *PCAPSTRACKINFO; + +#pragma pack(pop) + +// image type +enum { + ciitNA=0, // invalid image type + ciitFDD // floppy disk +}; + +// platform IDs, not about configuration, but intended use +enum { + ciipNA=0, // invalid platform (dummy entry) + ciipAmiga, // Amiga + ciipAtariST, // Atari ST + ciipPC // PC +}; + +// track type +enum { + ctitNA=0, // invalid type + ctitNoise, // cells are unformatted (random size) + ctitAuto, // automatic cell size, according to track size + ctitVar // variable density +}; + +// image error status +enum { + imgeOk, + imgeUnsupported, + imgeGeneric, + imgeOutOfRange, + imgeReadOnly, + imgeOpen, + imgeType, + imgeShort, + imgeTrackHeader, + imgeTrackStream, + imgeTrackData, + imgeDensityHeader, + imgeDensityStream, + imgeDensityData, + imgeIncompatible +}; + +#endif diff --git a/od-win32/caps/CapsLib.h b/od-win32/caps/CapsLib.h new file mode 100755 index 00000000..bd2e4a63 --- /dev/null +++ b/od-win32/caps/CapsLib.h @@ -0,0 +1,24 @@ +#ifndef CAPSLIB_H +#define CAPSLIB_H + +#undef LIB_USER +#ifdef CAPS_USER +#define LIB_USER +#endif +#include "comlib.h" + +ExtSub SDWORD __cdecl CAPSInit(); +ExtSub SDWORD __cdecl CAPSExit(); +ExtSub SDWORD __cdecl CAPSAddImage(); +ExtSub SDWORD __cdecl CAPSRemImage(SDWORD id); +ExtSub SDWORD __cdecl CAPSLockImage(SDWORD id, PCHAR name); +ExtSub SDWORD __cdecl CAPSLockImageMemory(SDWORD id, PUBYTE buffer, UDWORD length, UDWORD flag); +ExtSub SDWORD __cdecl CAPSUnlockImage(SDWORD id); +ExtSub SDWORD __cdecl CAPSLoadImage(SDWORD id, UDWORD flag); +ExtSub SDWORD __cdecl CAPSGetImageInfo(PCAPSIMAGEINFO pi, SDWORD id); +ExtSub SDWORD __cdecl CAPSLockTrack(PCAPSTRACKINFO pi, SDWORD id, UDWORD cylinder, UDWORD head, UDWORD flag); +ExtSub SDWORD __cdecl CAPSUnlockTrack(SDWORD id, UDWORD cylinder, UDWORD head); +ExtSub SDWORD __cdecl CAPSUnlockAllTracks(SDWORD id); +ExtSub PCHAR __cdecl CAPSGetPlatformName(UDWORD pid); + +#endif diff --git a/od-win32/caps/Comlib.h b/od-win32/caps/Comlib.h new file mode 100755 index 00000000..4eb091e3 --- /dev/null +++ b/od-win32/caps/Comlib.h @@ -0,0 +1,20 @@ +#undef DllSub +#undef DllVar +#undef ExtSub +#undef ExtVar + +#ifdef LIB_USER + +#define DllSub DllImport +#define DllVar DllImport + +#else + +#define DllSub DllExport +#define DllVar extern DllExport + +#endif + +#define ExtSub +#define ExtVar + diff --git a/od-win32/caps/Comtype.h b/od-win32/caps/Comtype.h new file mode 100755 index 00000000..56bc0251 --- /dev/null +++ b/od-win32/caps/Comtype.h @@ -0,0 +1,121 @@ +#ifndef COMTYPE_H +#define COMTYPE_H + +typedef void *PVOID; +typedef char *PCHAR; + +typedef unsigned char UBYTE; +typedef unsigned short UWORD; +typedef unsigned long UDWORD; +typedef unsigned __int64 UQUAD; +typedef signed char SBYTE; +typedef signed short SWORD; +typedef signed long SDWORD; +typedef signed __int64 SQUAD; + +typedef UBYTE *PUBYTE; +typedef UWORD *PUWORD; +typedef UDWORD *PUDWORD; +typedef UQUAD *PUQUAD; +typedef SBYTE *PSBYTE; +typedef SWORD *PSWORD; +typedef SDWORD *PSDWORD; +typedef SQUAD *PSQUAD; + +#define UCHAR_MIN 0 +#define USHRT_MIN 0 +#define ULONG_MIN 0 + +#define UBYTE_MIN UCHAR_MIN +#define UBYTE_MAX UCHAR_MAX +#define UWORD_MIN USHRT_MIN +#define UWORD_MAX USHRT_MAX +#define UDWORD_MIN ULONG_MIN +#define UDWORD_MAX ULONG_MAX +#define SBYTE_MIN SCHAR_MIN +#define SBYTE_MAX SCHAR_MAX +#define SWORD_MIN SHRT_MIN +#define SWORD_MAX SHRT_MAX +#define SDWORD_MIN LONG_MIN +#define SDWORD_MAX LONG_MAX + +enum { + DB_0, + DB_1, + DB_2, + DB_3, + DB_4, + DB_5, + DB_6, + DB_7, + DB_8, + DB_9, + DB_10, + DB_11, + DB_12, + DB_13, + DB_14, + DB_15, + DB_16, + DB_17, + DB_18, + DB_19, + DB_20, + DB_21, + DB_22, + DB_23, + DB_24, + DB_25, + DB_26, + DB_27, + DB_28, + DB_29, + DB_30, + DB_31 +}; + +#define DF_0 (1UL< 0) { + tt = xmalloc (ci.timelen * sizeof (uae_u16)); + for (i = 0; i < ci.timelen; i++) + tt[i] = (uae_u16)ci.timebuf[i]; + *tracktiming = tt; + } +#if 0 + write_log ("caps: drive: %d, track: %d, revolutions: %d, timing: %d\n", + drv, track, *revolutions, ci.timelen); + for (i = 0; i < *revolutions; i++) + write_log ("- %d: length: %d bits, %d bytes\n", i, tracklengths[i], tracklengths[i] / 8); +#endif + return 1; +} + +#endif diff --git a/od-win32/caps/caps_win32.h b/od-win32/caps/caps_win32.h new file mode 100755 index 00000000..7fd03649 --- /dev/null +++ b/od-win32/caps/caps_win32.h @@ -0,0 +1,5 @@ +int caps_init (void); +void caps_unloadimage (int drv); +int caps_loadimage (struct zfile *zf, int drv, int *num_tracks); +int caps_loadtrack (uae_u16 *mfmbuf, uae_u16 **trackpointers, uae_u16 **tracktiming, int drv, int track, int *tracklengths, int *revolutions); + diff --git a/od-win32/config.h b/od-win32/config.h new file mode 100755 index 00000000..24aab3e0 --- /dev/null +++ b/od-win32/config.h @@ -0,0 +1,77 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * User configuration options + * + * Copyright 1995 - 1998 Bernd Schmidt + */ + +/* + * Please note: Many things are configurable with command line parameters, + * and you can put anything you can pass on the command line into a + * configuration file ~/.uaerc. Please read the documentation for more + * information. + * + * NOTE NOTE NOTE + * Whenever you change something in this file, you have to "make clean" + * afterwards. + * Don't remove the '#' signs. If you want to enable something, move it out + * of the C comment block, if you want to disable something, move it inside + * the block. + */ + +/* + * When USE_COMPILER is defined, a m68k->i386 instruction compiler will be + * used. This is experimental. It has only been tested on a Linux/i386 ELF + * machine, although it might work on other i386 Unices. + * This is supposed to speed up application programs. It will not work very + * well for hardware bangers like games and demos, in fact it will be much + * slower. It can also be slower for some applications and/or benchmarks. + * It needs a lot of tuning. Please let me know your results with this. + * The second define, RELY_ON_LOADSEG_DETECTION, decides how the compiler + * tries to detect self-modifying code. If it is not set, the first bytes + * of every compiled routine are used as checksum before executing the + * routine. If it is set, the UAE filesystem will perform some checks to + * detect whether an executable is being loaded. This is less reliable + * (it won't work if you don't use the harddisk emulation, so don't try to + * use floppies or even the RAM disk), but much faster. + * + * @@@ NOTE: This option is unfortunately broken in this version. Don't + * try to use it. @@@ + * +#define USE_COMPILER +#define RELY_ON_LOADSEG_DETECTION + */ + +/* + * Set USER_PROGRAMS_BEHAVE to 1 or 2 to indicate that you are only running + * non-hardware banging programs which leave all the dirty work to the + * Kickstart. This affects the compiler. Any program that is _not_ in the ROM + * (i.e. everything but the Kickstart) will use faster memory access + * functions. + * There is of course the problem that the Amiga doesn't really distinguish + * between user programs and the kernel. Not all of the OS is in the ROM, + * e.g. the parallel.device is on the disk and gets loaded into RAM at least + * with Kickstart 1.3 (don't know about newer Kickstarts). So you probably + * can't print, and some other stuff may also fail to work. + * A useless option, really, given the way lots of Amiga software is written. +#define USER_PROGRAMS_BEHAVE 0 + */ + +/*************************************************************************** + * Operating system/machine specific options + * Configure these for your CPU. The default settings should work on any + * machine, but may not give optimal performance everywhere. + * (These don't do very much yet, except HAVE_RDTSC + */ + +/* + * Define this where unaligned-accesses don't break things, and are "fast enough" + */ +#define UNALIGNED_PROFITABLE + +/* + * PPros don't like branches. With this option, UAE tries to avoid them in some + * places. + */ +#define BRANCHES_ARE_EXPENSIVE \ No newline at end of file diff --git a/od-win32/dinput.c b/od-win32/dinput.c new file mode 100755 index 00000000..7f0cfbb0 --- /dev/null +++ b/od-win32/dinput.c @@ -0,0 +1,1700 @@ +/* + * UAE - The Un*x Amiga Emulator + * + * Win32 DirectInput/Windows XP RAWINPUT interface + * + * Copyright 2002 - 2004 Toni Wilen + */ + +#define _WIN32_WINNT 0x501 /* make RAWINPUT available */ + +#define DI_DEBUG +//#define DI_DEBUG2 + +#include "config.h" +#include "sysconfig.h" + +#include +#include +#include + +#include +#include + +#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 +#include +#endif + +#include "win32.h" + +#define MAX_MAPPINGS 256 + +#define DID_MOUSE 1 +#define DID_JOYSTICK 2 +#define DID_KEYBOARD 3 + +struct didata { + int type; + int disabled; + int acquired; + int priority; + int superdevice; + GUID guid; + char *name; + char *sortname; + + LPDIRECTINPUTDEVICE8 lpdi; + HANDLE rawinput; + int wininput; + + int axles; + int buttons; + int axismappings[MAX_MAPPINGS]; + char *axisname[MAX_MAPPINGS]; + int axissort[MAX_MAPPINGS]; + int axistype[MAX_MAPPINGS]; + int buttonmappings[MAX_MAPPINGS]; + char *buttonname[MAX_MAPPINGS]; + int buttonsort[MAX_MAPPINGS]; +}; + +#define DI_BUFFER 30 + +static struct didata di_mouse[MAX_INPUT_DEVICES]; +static struct didata di_keyboard[MAX_INPUT_DEVICES]; +static struct didata di_joystick[MAX_INPUT_DEVICES]; +static int num_mouse, num_keyboard, num_joystick; +static int dd_inited, mouse_inited, keyboard_inited, joystick_inited; +static int stopoutput; +static HANDLE kbhandle = INVALID_HANDLE_VALUE; +static int oldleds, oldusedleds, newleds; +static int normalmouse, supermouse, rawmouse, winmouse, winmousenumber; +static int normalkb, superkb, rawkb; + +int no_rawinput; + +int dinput_winmouse (void) +{ + if (winmouse) + return winmousenumber; + return -1; +} + +typedef BOOL (CALLBACK* REGISTERRAWINPUTDEVICES) + (PCRAWINPUTDEVICE, UINT, UINT); +static REGISTERRAWINPUTDEVICES pRegisterRawInputDevices; +typedef UINT (CALLBACK* GETRAWINPUTDATA) + (HRAWINPUT, UINT, LPVOID, PUINT, UINT); +static GETRAWINPUTDATA pGetRawInputData; +typedef UINT (CALLBACK* GETRAWINPUTDEVICELIST) + (PRAWINPUTDEVICEKUST, PUINT, UINT); +static GETRAWINPUTDEVICELIST pGetRawInputDeviceList; +typedef UINT (CALLBACK* GETRAWINPUTDEVICEINFO) + (HANDLE, UINT, LPVOID, PUINT); +static GETRAWINPUTDEVICEINFO pGetRawInputDeviceInfo; +typedef UINT (CALLBACK* GETRAWINPUTBUFFER) + (PRAWINPUT, PUINT, UINT); +static GETRAWINPUTBUFFER pGetRawInputBuffer; +typedef LRESULT (CALLBACK* DEFRAWINPUTPROC) + (PRAWINPUT*, INT, UINT); +static DEFRAWINPUTPROC pDefRawInputProc; + +static int rawinput_available, rawinput_registered; + +static void unregister_rawinput (void) +{ +} + +static int register_rawinput (void) +{ + RAWINPUTDEVICE rid[1]; + + if (!rawinput_available) + return 0; + memset (rid, 0, sizeof (rid)); + /* mouse */ + rid[0].usUsagePage = 1; + rid[0].usUsage = 2; + rid[0].dwFlags = 0; +#if 0 + /* keyboard */ + rid[1].usUsagePage = 1; + rid[1].usUsage = 6; + rid[1].dwFlags = 0; +#endif + + if (pRegisterRawInputDevices(rid, sizeof (rid) / sizeof (RAWINPUTDEVICE), sizeof (RAWINPUTDEVICE)) == FALSE) { + write_log ("RAWINPUT registration failed %d\n", GetLastError ()); + return 0; + } + rawinput_registered = 1; + return 1; +} + +#define RDP_MOUSE "\\??\\Root#RDP_MOU#" + +static int initialize_rawinput (void) +{ + RAWINPUTDEVICELIST *ridl = 0; + int num = 500, gotnum, i, bufsize, vtmp; + int rnum_mouse, rnum_kb, rnum_raw; + uae_u8 *buf = 0; + int rmouse = 0, rkb = 0; + char tmp[100]; + + if (no_rawinput) + goto error; + pRegisterRawInputDevices = (REGISTERRAWINPUTDEVICES)GetProcAddress( + GetModuleHandle("user32.dll"), "RegisterRawInputDevices"); + pGetRawInputData = (GETRAWINPUTDATA)GetProcAddress( + GetModuleHandle("user32.dll"), "GetRawInputData"); + pGetRawInputDeviceList = (GETRAWINPUTDEVICELIST)GetProcAddress( + GetModuleHandle("user32.dll"), "GetRawInputDeviceList"); + pGetRawInputDeviceInfo = (GETRAWINPUTDEVICEINFO)GetProcAddress( + GetModuleHandle("user32.dll"), "GetRawInputDeviceInfoA"); + pGetRawInputBuffer = (GETRAWINPUTBUFFER)GetProcAddress( + GetModuleHandle("user32.dll"), "GetRawInputBuffer"); + pDefRawInputProc = (DEFRAWINPUTPROC)GetProcAddress( + GetModuleHandle("user32.dll"), "DefRawInputProc"); + + if (!pRegisterRawInputDevices || !pGetRawInputData || !pGetRawInputDeviceList || + !pGetRawInputDeviceInfo || !pGetRawInputBuffer || !pDefRawInputProc) + goto error; + + ridl = malloc (sizeof(RAWINPUTDEVICELIST) * num); + memset (ridl, 0, sizeof (RAWINPUTDEVICELIST) * num); + bufsize = 1000; + buf = malloc (bufsize); + + gotnum = pGetRawInputDeviceList(ridl, &num, sizeof (RAWINPUTDEVICELIST)); + if (gotnum <= 0) { + write_log ("RAWINPUT didn't find any devices"); + goto error; + } + write_log ("RAWINPUT: found %d devices\n", gotnum); + rnum_raw = rnum_mouse = rnum_kb = 0; + for (i = 0; i < gotnum; i++) { + int type = ridl[i].dwType; + HANDLE h = ridl[i].hDevice; + vtmp = bufsize; + pGetRawInputDeviceInfo (h, RIDI_DEVICENAME, buf, &vtmp); + + if (!memcmp (RDP_MOUSE, buf, strlen (RDP_MOUSE))) + continue; + if (type == RIM_TYPEMOUSE) + rnum_mouse++; + if (type == RIM_TYPEKEYBOARD) + rnum_kb++; + } + + for (i = 0; i < gotnum; i++) { + HANDLE h = ridl[i].hDevice; + int type = ridl[i].dwType; + + if (/* type == RIM_TYPEKEYBOARD || */ type == RIM_TYPEMOUSE) { + struct didata *did = type == RIM_TYPEMOUSE ? di_mouse : di_keyboard; + PRID_DEVICE_INFO rdi; + int v, j; + + vtmp = bufsize; + pGetRawInputDeviceInfo (h, RIDI_DEVICENAME, buf, &vtmp); + + if (did == di_mouse) { + if (!memcmp (RDP_MOUSE, buf, strlen (RDP_MOUSE))) + continue; + if (rnum_mouse < 2) + continue; + if (num_mouse >= MAX_INPUT_DEVICES - 1) /* leave space for Windows mouse */ + continue; + did += num_mouse; + num_mouse++; + rmouse++; + v = rmouse; + } else if (did == di_keyboard) { + if (rnum_kb < 2) + continue; + if (num_keyboard >= MAX_INPUT_DEVICES) + continue; + did += num_keyboard; + num_keyboard++; + rkb++; + v = rkb; + } + + rnum_raw++; + memset (did, 0, sizeof (*did)); + for (j = 0; j < MAX_MAPPINGS; j++) { + did->axismappings[j] = -1; + did->buttonmappings[j] = -1; + } + sprintf (tmp, "%s", type == RIM_TYPEMOUSE ? "RAW Mouse" : "RAW Keyboard"); + did->name = my_strdup (tmp); + did->rawinput = h; + + write_log ("%p %s: ", h, type == RIM_TYPEMOUSE ? "mouse" : "keyboard"); + did->sortname = my_strdup (buf); + write_log ("'%s'\n", buf); + vtmp = bufsize; + rdi = (PRID_DEVICE_INFO)buf; + rdi->cbSize = sizeof (RID_DEVICE_INFO); + pGetRawInputDeviceInfo (h, RIDI_DEVICEINFO, buf, &vtmp); + if (type == RIM_TYPEMOUSE) { + PRID_DEVICE_INFO_MOUSE rdim = &rdi->mouse; + write_log ("id=%d buttons=%d rate=%d", + rdim->dwId, rdim->dwNumberOfButtons, rdim->dwSampleRate); + did->buttons = rdim->dwNumberOfButtons; + did->axles = 3; + did->axistype[0] = 1; + did->axissort[0] = 0; + did->axisname[0] = my_strdup ("X-Axis"); + did->axistype[1] = 1; + did->axissort[1] = 1; + did->axisname[1] = my_strdup ("Y-Axis"); + did->axistype[2] = 1; + did->axissort[2] = 2; + did->axisname[2] = my_strdup ("Wheel"); + for (j = 0; j < did->buttons; j++) { + did->buttonsort[j] = j; + sprintf (tmp, "Button %d", j + 1); + did->buttonname[j] = my_strdup (tmp); + } + did->priority = -1; + } else { + PRID_DEVICE_INFO_KEYBOARD rdik = &rdi->keyboard; + write_log ("type=%d sub=%d mode=%d fkeys=%d indicators=%d tkeys=%d", + rdik->dwType, rdik->dwSubType, rdik->dwKeyboardMode, + rdik->dwNumberOfFunctionKeys, rdik->dwNumberOfIndicators, rdik->dwNumberOfKeysTotal); + } + write_log("\n"); + } + } + + free (ridl); + free (buf); + if (rnum_raw > 0) + rawinput_available = 1; + return 1; + + error: + write_log ("RAWINPUT not available or failed to initialize\n"); + free (ridl); + free (buf); + return 0; +} + +static void initialize_windowsmouse (void) +{ + struct didata *did = di_mouse; + char tmp[100]; + int j; + + if (num_mouse >= MAX_INPUT_DEVICES) + return; + did += num_mouse; + num_mouse++; + did->name = my_strdup ("Windows mouse"); + did->sortname = my_strdup ("Windows mouse"); + did->buttons = 3; + did->axles = 3; + did->axistype[0] = 1; + did->axissort[0] = 0; + did->axisname[0] = my_strdup ("X-Axis"); + did->axistype[1] = 1; + did->axissort[1] = 1; + did->axisname[1] = my_strdup ("Y-Axis"); + did->axistype[2] = 1; + did->axissort[2] = 2; + did->axisname[2] = my_strdup ("Wheel"); + for (j = 0; j < 3; j++) { + did->buttonsort[j] = j; + sprintf (tmp, "Button %d", j + 1); + did->buttonname[j] = my_strdup (tmp); + } + did->priority = 2; + did->wininput = 1; +} + +static void handle_rawinput_2 (RAWINPUT *raw) +{ + int i, num; + struct didata *did; + + if (raw->header.dwType == RIM_TYPEMOUSE) { + PRAWMOUSE rm = &raw->data.mouse; + + for (num = 0; num < num_mouse; num++) { + did = &di_mouse[num]; + if (!did->disabled && did->rawinput == raw->header.hDevice) + break; + } +#ifdef DI_DEBUG2 + write_log ("HANDLE=%08.8x %04.4x %04.4x %04.4x %08.8x %3d %3d %08.8x M=%d\n", + raw->header.hDevice, + rm->usFlags, + rm->usButtonFlags, + rm->usButtonData, + rm->ulRawButtons, + rm->lLastX, + rm->lLastY, + rm->ulExtraInformation, num < num_mouse ? num + 1 : -1); +#endif + if (num == num_mouse) { + return; + } + + if (focus) { + if (mouseactive || isfullscreen ()) { + for (i = 0; i < (5 > did->buttons ? did->buttons : 5); i++) { + if (rm->usButtonFlags & (3 << (i * 2))) + setmousebuttonstate (num, i, (rm->usButtonFlags & (1 << (i * 2))) ? 1 : 0); + } + if (did->buttons > 5) { + for (i = 5; i < did->buttons; i++) + setmousebuttonstate (num, i, (rm->ulRawButtons & (1 << i)) ? 1 : 0); + } + if (did->buttons >= 3 && (rm->usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN)) { + if (currprefs.win32_middle_mouse) { + if (isfullscreen ()) + minimizewindow (); + if (mouseactive) + setmouseactive(0); + } + } + } + if (rm->usButtonFlags & RI_MOUSE_WHEEL) + setmousestate (num, 2, (int)rm->usButtonData, 0); + setmousestate (num, 0, rm->lLastX, (rm->usFlags & MOUSE_MOVE_ABSOLUTE) ? 1 : 0); + setmousestate (num, 1, rm->lLastY, (rm->usFlags & MOUSE_MOVE_ABSOLUTE) ? 1 : 0); + } + + } else if (raw->header.dwType == RIM_TYPEKEYBOARD) { +#ifdef DI_DEBUG2 + write_log ("HANDLE=%x CODE=%x Flags=%x VK=%x MSG=%x EXTRA=%x\n", + raw->header.hDevice, + raw->data.keyboard.MakeCode, + raw->data.keyboard.Flags, + raw->data.keyboard.VKey, + raw->data.keyboard.Message, + raw->data.keyboard.ExtraInformation); +#endif + } +} + +#if 0 +static void read_rawinput (void) +{ + RAWINPUT raw; + int size, ret; + + for(;;) { + size = sizeof (RAWINPUT); + ret = pGetRawInputBuffer (&raw, &size, sizeof (RAWINPUTHEADER)); + if (ret <= 0) + return; + handle_rawinput_2 (&raw); + } +} +#endif + +void handle_rawinput (DWORD lParam) +{ + UINT dwSize; + BYTE lpb[1000]; + RAWINPUT *raw; + + if (!rawinput_available) + return; + pGetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER)); + if (dwSize >= sizeof (lpb)) + return; + if (pGetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)) != dwSize ) + return; + raw = (RAWINPUT*)lpb; + handle_rawinput_2 (raw); + pDefRawInputProc (&raw, 1, sizeof (RAWINPUTHEADER)); +} + +static void unacquire (LPDIRECTINPUTDEVICE8 lpdi, char *txt) +{ + if (lpdi) { + HRESULT hr = IDirectInputDevice8_Unacquire (lpdi); + if (hr != DI_OK && hr != DI_NOEFFECT) + write_log ("unacquire %s failed, %s\n", txt, DXError (hr)); + } +} +static int acquire (LPDIRECTINPUTDEVICE8 lpdi, char *txt) +{ + HRESULT hr = DI_OK; + if (lpdi) { + hr = IDirectInputDevice8_Acquire (lpdi); + if (hr != DI_OK) { + write_log ("acquire %s failed, %s\n", txt, DXError (hr)); + } + } + return hr == DI_OK ? 1 : 0; +} + +static int setcoop (LPDIRECTINPUTDEVICE8 lpdi, DWORD mode, char *txt) +{ + HRESULT hr = DI_OK; + if (lpdi) { + hr = IDirectInputDevice8_SetCooperativeLevel (lpdi, hMainWnd, mode); + if (hr != DI_OK && hr != E_NOTIMPL) + write_log ("setcooperativelevel %s failed, %s\n", txt, DXError (hr)); + } + return hr == DI_OK ? 1 : 0; +} + +static void sortdd (struct didata *dd, int num, int type) +{ + int i, j; + struct didata ddtmp; + for (i = 0; i < num; i++) { + dd[i].type = type; + for (j = i + 1; j < num; j++) { + dd[j].type = type; + if (dd[i].priority < dd[j].priority || (dd[i].priority == dd[j].priority && strcmp (dd[i].sortname, dd[j].sortname) > 0)) { + memcpy (&ddtmp, &dd[i], sizeof(ddtmp)); + memcpy (&dd[i], &dd[j], sizeof(ddtmp)); + memcpy (&dd[j], &ddtmp, sizeof(ddtmp)); + } + } + } + j = 1; + for (i = 0; i < num; i++) { + if (dd[i].rawinput) { + char *ntmp = dd[i].name; + char tmp[200]; + sprintf (tmp, "%s %d", ntmp, j); + dd[i].name = my_strdup (tmp); + free (ntmp); + j++; + } + } +} + +static void sortobjects (struct didata *did, int *mappings, int *sort, char **names, int *types, int num) +{ + int i, j, tmpi; + char *tmpc; + + for (i = 0; i < num; i++) { + for (j = i + 1; j < num; j++) { + if (sort[i] > sort[j]) { + tmpi = mappings[i]; mappings[i] = mappings[j]; mappings[j] = tmpi; + tmpi = sort[i]; sort[i] = sort[j]; sort[j] = tmpi; + if (types) { + tmpi = types[i]; types[i] = types[j]; types[j] = tmpi; + } + tmpc = names[i]; names[i] = names[j]; names[j] = tmpc; + } + } + } +#ifdef DI_DEBUG + if (num > 0) { + write_log ("%s (GUID=%s):\n", did->name, outGUID (&did->guid)); + for (i = 0; i < num; i++) + write_log ("%d '%s' (%d,%d)\n", mappings[i], names[i], sort[i], types ? types[i] : -1); + } +#endif +} + +static int isg (const GUID *g, const GUID *g2, int *dwofs, int v) +{ + if (!memcmp (g, g2, sizeof (GUID))) { + *dwofs = v; + return 1; + } + return 0; +} + +static int makesort_joy (const GUID *g, int *dwofs) +{ + if (isg (g, &GUID_XAxis, dwofs, DIJOFS_X)) return -99; + if (isg (g, &GUID_YAxis, dwofs, DIJOFS_Y)) return -98; + if (isg (g, &GUID_ZAxis, dwofs, DIJOFS_Z)) return -97; + if (isg (g, &GUID_RxAxis, dwofs, DIJOFS_RX)) return -89; + if (isg (g, &GUID_RyAxis, dwofs, DIJOFS_RY)) return -88; + if (isg (g, &GUID_RzAxis, dwofs, DIJOFS_RZ)) return -87; + if (isg (g, &GUID_Slider, dwofs, DIJOFS_SLIDER(0))) return -79; + if (isg (g, &GUID_Slider, dwofs, DIJOFS_SLIDER(1))) return -78; + if (isg (g, &GUID_POV, dwofs, DIJOFS_POV(0))) return -69; + if (isg (g, &GUID_POV, dwofs, DIJOFS_POV(1))) return -68; + if (isg (g, &GUID_POV, dwofs, DIJOFS_POV(2))) return -67; + if (isg (g, &GUID_POV, dwofs, DIJOFS_POV(3))) return -66; + return *dwofs; +} + +static int makesort_mouse (const GUID *g, int *dwofs) +{ + if (isg (g, &GUID_XAxis, dwofs, DIMOFS_X)) return -99; + if (isg (g, &GUID_YAxis, dwofs, DIMOFS_Y)) return -98; + if (isg (g, &GUID_ZAxis, dwofs, DIMOFS_Z)) return -97; + return *dwofs; +} + +static BOOL CALLBACK EnumObjectsCallback (const DIDEVICEOBJECTINSTANCE* pdidoi, VOID *pContext) +{ + struct didata *did = pContext; + int i = 0; + char tmp[100]; + + if (pdidoi->dwType & DIDFT_AXIS) { + if (did->axles >= MAX_MAPPINGS) + return DIENUM_CONTINUE; + did->axismappings[did->axles] = pdidoi->dwOfs; + did->axisname[did->axles] = my_strdup (pdidoi->tszName); + if (did->type == DID_JOYSTICK) + did->axissort[did->axles] = makesort_joy (&pdidoi->guidType, &did->axismappings[did->axles]); + else if (did->type == DID_MOUSE) + did->axissort[did->axles] = makesort_mouse (&pdidoi->guidType, &did->axismappings[did->axles]); + did->axles++; + } + if (pdidoi->dwType & DIDFT_POV) { + int numpov = 0; + if (did->axles + 1 >= MAX_MAPPINGS) + return DIENUM_CONTINUE; + for (i = 0; i < did->axles; i++) { + if (did->axistype[i]) { + numpov++; + i++; + } + } + if (did->type == DID_JOYSTICK) + did->axissort[did->axles] = makesort_joy (&pdidoi->guidType, &did->axismappings[did->axles]); + else if (did->type == DID_MOUSE) + did->axissort[did->axles] = makesort_mouse (&pdidoi->guidType, &did->axismappings[did->axles]); + for (i = 0; i < 2; i++) { + did->axismappings[did->axles + i] = DIJOFS_POV(numpov); + sprintf (tmp, "%s (%d)", pdidoi->tszName, i + 1); + did->axisname[did->axles + i] = my_strdup (tmp); + did->axissort[did->axles + i] = did->axissort[did->axles]; + did->axistype[did->axles + i] = 1; + } + did->axles += 2; + } + if (pdidoi->dwType & DIDFT_BUTTON) { + if (did->buttons >= MAX_MAPPINGS) + return DIENUM_CONTINUE; + did->buttonname[did->buttons] = my_strdup (pdidoi->tszName); + if (did->type == DID_JOYSTICK) { + did->buttonmappings[did->buttons] = DIJOFS_BUTTON(did->buttons); // pdidoi->dwOfs returns garbage!! + did->buttonsort[did->buttons] = makesort_joy (&pdidoi->guidType, &did->buttonmappings[did->buttons]); + } else if (did->type == DID_MOUSE) { + did->buttonmappings[did->buttons] = FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + did->buttons; + did->buttonsort[did->buttons] = makesort_mouse (&pdidoi->guidType, &did->buttonmappings[did->buttons]); + } else { + did->buttonmappings[did->buttons] = pdidoi->dwOfs; + } + did->buttons++; + } + return DIENUM_CONTINUE; +} + +static BOOL CALLBACK di_enumcallback (LPCDIDEVICEINSTANCE lpddi, LPVOID *dd) +{ + struct didata *did; + int i, len, type; + char *typetxt; + + type = lpddi->dwDevType & 0xff; + if (type == DI8DEVTYPE_MOUSE || type == DI8DEVTYPE_SCREENPOINTER) { + did = di_mouse; + typetxt = "Mouse"; + } else if (type == DI8DEVTYPE_GAMEPAD || type == DI8DEVTYPE_JOYSTICK || + type == DI8DEVTYPE_FLIGHT || type == DI8DEVTYPE_DRIVING || type == DI8DEVTYPE_1STPERSON) { + did = di_joystick; + typetxt = "Game controller"; + } else if (type == DI8DEVTYPE_KEYBOARD) { + did = di_keyboard; + typetxt = "Keyboard"; + } else { + did = NULL; + typetxt = "Unknown"; + } + +#ifdef DI_DEBUG + write_log ("GUID=%08.8X-%04.8X-%04.8X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X:\n", + lpddi->guidInstance.Data1, lpddi->guidInstance.Data2, lpddi->guidInstance.Data3, + lpddi->guidInstance.Data4[0], lpddi->guidInstance.Data4[1], lpddi->guidInstance.Data4[2], lpddi->guidInstance.Data4[3], + lpddi->guidInstance.Data4[4], lpddi->guidInstance.Data4[5], lpddi->guidInstance.Data4[6], lpddi->guidInstance.Data4[7]); + write_log ("'%s' '%s' %08.8X (%s)\n", lpddi->tszProductName, lpddi->tszInstanceName, lpddi->dwDevType, typetxt); +#endif + + if (did == di_mouse) { + if (num_mouse >= MAX_INPUT_DEVICES) + return DIENUM_CONTINUE; + did += num_mouse; + num_mouse++; + } else if (did == di_joystick) { + if (num_joystick >= MAX_INPUT_DEVICES) + return DIENUM_CONTINUE; + did += num_joystick; + num_joystick++; + } else if (did == di_keyboard) { + if (num_keyboard >= MAX_INPUT_DEVICES) + return DIENUM_CONTINUE; + did += num_keyboard; + num_keyboard++; + } else + return DIENUM_CONTINUE; + + memset (did, 0, sizeof (*did)); + for (i = 0; i < MAX_MAPPINGS; i++) { + did->axismappings[i] = -1; + did->buttonmappings[i] = -1; + } + len = strlen (lpddi->tszInstanceName) + 3 + 1; + did->name = malloc (len); + strcpy (did->name, lpddi->tszInstanceName); + did->guid = lpddi->guidInstance; + did->sortname = my_strdup (did->name); + + if (!memcmp (&did->guid, &GUID_SysKeyboard, sizeof (GUID)) || !memcmp (&did->guid, &GUID_SysMouse, sizeof (GUID))) { + did->priority = 2; + did->superdevice = 1; + strcat (did->name, " *"); + } + return DIENUM_CONTINUE; +} + +extern HINSTANCE hInst; +static LPDIRECTINPUT8 g_lpdi; + +static int di_do_init (void) +{ + HRESULT hr; + + num_mouse = num_joystick = num_keyboard = 0; + hr = DirectInput8Create (hInst, DIRECTINPUT_VERSION, &IID_IDirectInput8A, (LPVOID *)&g_lpdi, NULL); + if (FAILED(hr)) { + write_log ("DirectInput8Create failed, %s\n", DXError (hr)); + return 0; + } + memset (&di_mouse, 0, sizeof (di_mouse)); + memset (&di_joystick, 0, sizeof (di_joystick)); + memset (&di_keyboard, 0, sizeof (di_keyboard)); + + IDirectInput8_EnumDevices (g_lpdi, DI8DEVCLASS_ALL, di_enumcallback, 0, DIEDFL_ATTACHEDONLY); + initialize_rawinput (); + initialize_windowsmouse (); + + sortdd (di_joystick, num_joystick, DID_JOYSTICK); + sortdd (di_mouse, num_mouse, DID_MOUSE); + sortdd (di_keyboard, num_keyboard, DID_KEYBOARD); + + return 1; +} + +static void di_dev_free (struct didata *did) +{ + free (did->name); + free (did->sortname); + memset (did, 0, sizeof (*did)); +} + +static int di_init (void) +{ + if (dd_inited++ > 0) + return 1; + if (!di_do_init ()) + return 0; + return 1; +} + +static void di_free (void) +{ + if (dd_inited == 0) + return; + dd_inited--; + if (dd_inited > 0) + return; + IDirectInput8_Release (g_lpdi); + g_lpdi = 0; + di_dev_free (di_mouse); + di_dev_free (di_joystick); + di_dev_free (di_keyboard); +} + +static int get_mouse_num (void) +{ + return num_mouse; +} + +static char *get_mouse_name (int mouse) +{ + return di_mouse[mouse].name; +} + +static int get_mouse_widget_num (int mouse) +{ + return di_mouse[mouse].axles + di_mouse[mouse].buttons; +} + +static int get_mouse_widget_first (int mouse, int type) +{ + switch (type) + { + case IDEV_WIDGET_BUTTON: + return di_mouse[mouse].axles; + case IDEV_WIDGET_AXIS: + return 0; + } + return -1; +} + +static int get_mouse_widget_type (int mouse, int num, char *name, uae_u32 *code) +{ + struct didata *did = &di_mouse[mouse]; + + int axles = did->axles; + int buttons = did->buttons; + if (num >= axles && num < axles + buttons) { + if (name) + strcpy (name, did->buttonname[num - did->axles]); + return IDEV_WIDGET_BUTTON; + } else if (num < axles) { + if (name) + strcpy (name, did->axisname[num]); + return IDEV_WIDGET_AXIS; + } + return IDEV_WIDGET_NONE; +} + +static int init_mouse (void) +{ + int i; + LPDIRECTINPUTDEVICE8 lpdi; + HRESULT hr; + struct didata *did; + + if (mouse_inited) + return 1; + di_init (); + mouse_inited = 1; + for (i = 0; i < num_mouse; i++) { + did = &di_mouse[i]; + if (!did->disabled && !did->rawinput && !did->wininput) { + hr = IDirectInput8_CreateDevice (g_lpdi, &did->guid, &lpdi, NULL); + if (hr == DI_OK) { + hr = IDirectInputDevice8_SetDataFormat(lpdi, &c_dfDIMouse); + IDirectInputDevice8_EnumObjects (lpdi, EnumObjectsCallback, (void*)did, DIDFT_ALL); + sortobjects (did, did->axismappings, did->axissort, did->axisname, did->axistype, did->axles); + sortobjects (did, did->buttonmappings, did->buttonsort, did->buttonname, 0, did->buttons); + did->lpdi = lpdi; + } else { + write_log ("mouse %d CreateDevice failed, %s\n", i, DXError (hr)); + } + } + } + return 1; +} + +static void close_mouse (void) +{ + int i; + + if (!mouse_inited) + return; + mouse_inited = 0; + for (i = 0; i < num_mouse; i++) { + if (di_mouse[i].lpdi) + IDirectInputDevice8_Release (di_mouse[i].lpdi); + di_mouse[i].lpdi = 0; + } + supermouse = normalmouse = rawmouse = winmouse = 0; + di_free (); +} + +static int acquire_mouse (int num, int flags) +{ + LPDIRECTINPUTDEVICE8 lpdi = di_mouse[num].lpdi; + DIPROPDWORD dipdw; + HRESULT hr; + + unacquire (lpdi, "mouse"); + if (lpdi) { + setcoop (lpdi, flags ? (DISCL_FOREGROUND | DISCL_EXCLUSIVE) : (DISCL_BACKGROUND | DISCL_NONEXCLUSIVE), "mouse"); + dipdw.diph.dwSize = sizeof(DIPROPDWORD); + dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); + dipdw.diph.dwObj = 0; + dipdw.diph.dwHow = DIPH_DEVICE; + dipdw.dwData = DI_BUFFER; + hr = IDirectInputDevice8_SetProperty (lpdi, DIPROP_BUFFERSIZE, &dipdw.diph); + if (hr != DI_OK) + write_log ("mouse setpropertry failed, %s\n", DXError (hr)); + di_mouse[num].acquired = acquire (lpdi, "mouse") ? 1 : -1; + } else { + di_mouse[num].acquired = 1; + } + if (di_mouse[num].acquired) { + if (di_mouse[num].rawinput) + rawmouse++; + else if (di_mouse[num].superdevice) + supermouse++; + else if (di_mouse[num].wininput) { + winmouse++; + winmousenumber = num; + } else + normalmouse++; + } + if (!supermouse && rawmouse) + register_rawinput (); + return di_mouse[num].acquired > 0 ? 1 : 0; +} + +static void unacquire_mouse (int num) +{ + unacquire (di_mouse[num].lpdi, "mouse"); + if (di_mouse[num].acquired) { + if (di_mouse[num].rawinput) + rawmouse--; + else if (di_mouse[num].superdevice) + supermouse--; + else if (di_mouse[num].wininput) + winmouse--; + else + normalmouse--; + di_mouse[num].acquired = 0; + } +} + +static void read_mouse (void) +{ + DIDEVICEOBJECTDATA didod[DI_BUFFER]; + DWORD elements; + HRESULT hr; + int i, j, k; + int fs = isfullscreen(); + + for (i = 0; i < MAX_INPUT_DEVICES; i++) { + struct didata *did = &di_mouse[i]; + LPDIRECTINPUTDEVICE8 lpdi = did->lpdi; + if (!lpdi) + continue; + elements = DI_BUFFER; + hr = IDirectInputDevice8_GetDeviceData (lpdi, sizeof (DIDEVICEOBJECTDATA), didod, &elements, 0); + if (hr == DI_OK) { + if (supermouse && !did->superdevice) + continue; + for (j = 0; j < elements; j++) { + int dimofs = didod[j].dwOfs; + int data = didod[j].dwData; + int state = (data & 0x80) ? 1 : 0; +#ifdef DI_DEBUG2 + write_log ("MOUSE: %d OFF=%d DATA=%d STATE=%d\n", i, dimofs, data, state); +#endif + if (focus) { + if (mouseactive || fs) { + for (k = 0; k < did->axles; k++) { + if (did->axismappings[k] == dimofs) { + setmousestate (i, k, data, 0); + break; + } + } + for (k = 0; k < did->buttons; k++) { + if (did->buttonmappings[k] == dimofs) { +#ifdef SINGLEFILE + if (k == 0) + uae_quit (); +#endif + if ((currprefs.win32_middle_mouse && k != 2) || !(currprefs.win32_middle_mouse)) { + setmousebuttonstate (i, k, state); + break; + } + } + } + } + if (i == 0 && dimofs == DIMOFS_BUTTON2 && state) { + if (currprefs.win32_middle_mouse) { + if (isfullscreen ()) + minimizewindow (); + if (mouseactive) + setmouseactive(0); + } + } + } + } + } else if (hr == DIERR_INPUTLOST) { + acquire (lpdi, "mouse"); + } else if (did->acquired && hr == DIERR_NOTACQUIRED) { + acquire (lpdi, "mouse"); + } + IDirectInputDevice8_Poll (lpdi); + } +} + +struct inputdevice_functions inputdevicefunc_mouse = { + init_mouse, close_mouse, acquire_mouse, unacquire_mouse, read_mouse, + get_mouse_num, get_mouse_name, + get_mouse_widget_num, get_mouse_widget_type, + get_mouse_widget_first +}; + + +static int get_kb_num (void) +{ + return num_keyboard; +} + +static char *get_kb_name (int kb) +{ + return di_keyboard[kb].name; +} + +static int get_kb_widget_num (int kb) +{ + return di_keyboard[kb].buttons; +} + +static int get_kb_widget_first (int kb, int type) +{ + return 0; +} + +static int get_kb_widget_type (int kb, int num, char *name, uae_u32 *code) +{ + if (name) + strcpy (name, di_keyboard[kb].buttonname[num]); + if (code) + *code = di_keyboard[kb].buttonmappings[num]; + return IDEV_WIDGET_KEY; +} + +static int keyboard_german; + +static BYTE ledkeystate[256]; + +static uae_u32 get_leds (void) +{ + uae_u32 led = 0; + if (os_winnt && kbhandle != INVALID_HANDLE_VALUE) { +#ifdef WINDDK + KEYBOARD_INDICATOR_PARAMETERS InputBuffer; + KEYBOARD_INDICATOR_PARAMETERS OutputBuffer; + ULONG DataLength = sizeof(KEYBOARD_INDICATOR_PARAMETERS); + ULONG ReturnedLength; + + memset (&InputBuffer, 0, sizeof (InputBuffer)); + memset (&OutputBuffer, 0, sizeof (OutputBuffer)); + if (!DeviceIoControl(kbhandle, IOCTL_KEYBOARD_QUERY_INDICATORS, + &InputBuffer, DataLength, &OutputBuffer, DataLength, &ReturnedLength, NULL)) + return 0; + if (OutputBuffer.LedFlags & KEYBOARD_NUM_LOCK_ON) led |= KBLED_NUMLOCK; + if (OutputBuffer.LedFlags & KEYBOARD_CAPS_LOCK_ON) led |= KBLED_CAPSLOCK; + if (OutputBuffer.LedFlags & KEYBOARD_SCROLL_LOCK_ON) led |= KBLED_SCROLLLOCK; +#endif + } else if (!os_winnt) { + GetKeyboardState (ledkeystate); + if (ledkeystate[VK_NUMLOCK] & 1) led |= KBLED_NUMLOCK; + if (ledkeystate[VK_CAPITAL] & 1) led |= KBLED_CAPSLOCK; + if (ledkeystate[VK_SCROLL] & 1) led |= KBLED_SCROLLLOCK; + } + return led; +} + +static void set_leds (uae_u32 led) +{ + if (os_winnt && kbhandle != INVALID_HANDLE_VALUE) { +#ifdef WINDDK + KEYBOARD_INDICATOR_PARAMETERS InputBuffer; + ULONG DataLength = sizeof(KEYBOARD_INDICATOR_PARAMETERS); + ULONG ReturnedLength; + + memset (&InputBuffer, 0, sizeof (InputBuffer)); + if (led & KBLED_NUMLOCK) InputBuffer.LedFlags |= KEYBOARD_NUM_LOCK_ON; + if (led & KBLED_CAPSLOCK) InputBuffer.LedFlags |= KEYBOARD_CAPS_LOCK_ON; + if (led & KBLED_SCROLLLOCK) InputBuffer.LedFlags |= KEYBOARD_SCROLL_LOCK_ON; + if (!DeviceIoControl(kbhandle, IOCTL_KEYBOARD_SET_INDICATORS, + &InputBuffer, DataLength, NULL, 0, &ReturnedLength, NULL)) + write_log ("kbleds: DeviceIoControl() failed %d\n", GetLastError()); +#endif + } else if (!os_winnt) { + ledkeystate[VK_NUMLOCK] &= ~1; + if (led & KBLED_NUMLOCK) + ledkeystate[VK_NUMLOCK] = 1; + ledkeystate[VK_CAPITAL] &= ~1; + if (led & KBLED_CAPSLOCK) + ledkeystate[VK_CAPITAL] = 1; + ledkeystate[VK_SCROLL] &= ~1; + if (led & KBLED_SCROLLLOCK) + ledkeystate[VK_SCROLL] = 1; + SetKeyboardState (ledkeystate); + } +} + +static void update_leds (void) +{ + if (!currprefs.keyboard_leds_in_use) + return; + if (newleds != oldusedleds) { + oldusedleds = newleds; + set_leds (newleds); + } +} + +void indicator_leds (int num, int state) +{ + int i; + + if (!currprefs.keyboard_leds_in_use) + return; + for (i = 0; i < 3; i++) { + if (currprefs.keyboard_leds[i] == num + 1) { + newleds &= ~(1 << i); + if (state) newleds |= (1 << i); + } + } +} + +static int init_kb (void) +{ + int i; + LPDIRECTINPUTDEVICE8 lpdi; + DIPROPDWORD dipdw; + HRESULT hr; + HKL keyboardlayoutid; + WORD keyboardlangid; + + if (keyboard_inited) + return 1; + di_init (); + oldusedleds = -1; + keyboard_inited = 1; + for (i = 0; i < num_keyboard; i++) { + struct didata *did = &di_keyboard[i]; + if (!did->disabled && !did->rawinput && !did->wininput) { + hr = IDirectInput8_CreateDevice (g_lpdi, &did->guid, &lpdi, NULL); + if (hr == DI_OK) { + hr = IDirectInputDevice8_SetDataFormat(lpdi, &c_dfDIKeyboard); + if (hr != DI_OK) + write_log ("keyboard setdataformat failed, %s\n", DXError (hr)); + dipdw.diph.dwSize = sizeof(DIPROPDWORD); + dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); + dipdw.diph.dwObj = 0; + dipdw.diph.dwHow = DIPH_DEVICE; + dipdw.dwData = DI_BUFFER; + hr = IDirectInputDevice8_SetProperty (lpdi, DIPROP_BUFFERSIZE, &dipdw.diph); + if (hr != DI_OK) + write_log ("keyboard setpropertry failed, %s\n", DXError (hr)); + IDirectInputDevice8_EnumObjects (lpdi, EnumObjectsCallback, (void*)did, DIDFT_ALL); + sortobjects (did, did->axismappings, did->axissort, did->axisname, did->axistype, did->axles); + sortobjects (did, did->buttonmappings, did->buttonsort, did->buttonname, 0, did->buttons); + did->lpdi = lpdi; + } else + write_log ("keyboard CreateDevice failed, %s\n", DXError (hr)); + } + } + keyboardlayoutid = GetKeyboardLayout(0); + keyboardlangid = LOWORD(keyboardlayoutid); + keyboard_german = 0; + if (keyboardlangid == MAKELANGID (LANG_GERMAN, SUBLANG_GERMAN)) + keyboard_german = 1; + return 1; +} + +static void close_kb (void) +{ + int i; + + if (keyboard_inited == 0) + return; + keyboard_inited = 0; + + for (i = 0; i < num_keyboard; i++) { + if (di_keyboard[i].lpdi) + IDirectInputDevice8_Release (di_keyboard[i].lpdi); + di_keyboard[i].lpdi = 0; + } + di_free (); +} + +#define MAX_KEYCODES 256 +static uae_u8 di_keycodes[MAX_INPUT_DEVICES][MAX_KEYCODES]; +static uae_u32 kb_do_refresh; + +int ispressed (int key) +{ + int i; + for (i = 0; i < MAX_INPUT_DEVICES; i++) { + if (di_keycodes[i][key]) + return 1; + } + return 0; +} + +void release_keys (void) +{ + int i, j; + + for (j = 0; j < MAX_INPUT_DEVICES; j++) { + for (i = 0; i < MAX_KEYCODES; i++) { + if (di_keycodes[j][i]) { + my_kbd_handler (j, i, 0); + di_keycodes[j][i] = 0; + } + } + } +} + +static int refresh_kb (LPDIRECTINPUTDEVICE8 lpdi, int num) +{ + HRESULT hr; + int i; + uae_u8 kc[256]; + + hr = IDirectInputDevice8_GetDeviceState (lpdi, sizeof (kc), kc); + if (hr == DI_OK) { + for (i = 0; i < sizeof (kc); i++) { + if (kc[i] & 0x80) kc[i] = 1; else kc[i] = 0; + if (kc[i] != di_keycodes[num][i]) { + write_log ("%02.2X -> %d\n", i, kc[i]); + di_keycodes[num][i] = kc[i]; + my_kbd_handler (num, i, kc[i]); + } + } + } else if (hr == DIERR_INPUTLOST) { + acquire (lpdi, "keyboard"); + IDirectInputDevice8_Poll (lpdi); + return 0; + } + IDirectInputDevice8_Poll (lpdi); + return 1; +} + + +static int keyhack (int scancode,int pressed, int num) +{ + static byte backslashstate,apostrophstate; + + //check ALT-F4 + if (pressed && !di_keycodes[num][DIK_F4] && scancode == DIK_F4 && di_keycodes[num][DIK_LALT] && !currprefs.win32_ctrl_F11_is_quit) { + uae_quit (); + return -1; + } +#ifdef SINGLEFILE + if (pressed && scancode == DIK_ESCAPE) { + uae_quit (); + return -1; + } +#endif + + // release mouse if TAB and ALT is pressed + if (pressed && di_keycodes[num][DIK_LALT] && scancode == DIK_TAB) { + disablecapture (); + return -1; + } + + if (!keyboard_german) + return scancode; + + //This code look so ugly because there is no Directinput + //key for # (called numbersign on win standard message) + //available + //so here need to change qulifier state and restore it when key + //is release + if (!keyboard_german) + return scancode; + if (scancode == DIK_BACKSLASH) // The # key + { + if (di_keycodes[num][DIK_LSHIFT] || di_keycodes[num][DIK_RSHIFT] || apostrophstate) + { + if (pressed) + { apostrophstate=1; + inputdevice_translatekeycode (num, DIK_RSHIFT, 0); + inputdevice_translatekeycode (num, DIK_LSHIFT, 0); + return 13; // the german ' key + } + else + { + //best is add a real keystatecheck here but it still work so + apostrophstate=0; + return 13; + } + + } + if (pressed) + { + inputdevice_translatekeycode (num, DIK_LALT, 1); + inputdevice_translatekeycode (num, DIK_LSHIFT,1); + return 4; // the german # key + } + else + { + inputdevice_translatekeycode (num, DIK_LALT,0); + inputdevice_translatekeycode (num, DIK_LSHIFT,0); + // Here is the same not nice but do the job + return 4; // the german # key + + } + } + if ((di_keycodes[num][DIK_RALT]) || (backslashstate)) { + switch (scancode) + { + case 12: + if (pressed) + { + backslashstate=1; + inputdevice_translatekeycode (num, DIK_RALT, 0); + return DIK_BACKSLASH; + } + else + { + backslashstate=0; + return DIK_BACKSLASH; + } + } + } + return scancode; +} + +static void read_kb (void) +{ + DIDEVICEOBJECTDATA didod[DI_BUFFER]; + DWORD elements; + HRESULT hr; + LPDIRECTINPUTDEVICE8 lpdi; + int i, j; + + update_leds (); + for (i = 0; i < MAX_INPUT_DEVICES; i++) { + struct didata *did = &di_keyboard[i]; + lpdi = did->lpdi; + if (!lpdi) + continue; + if (kb_do_refresh & (1 << i)) { + if (!refresh_kb (lpdi, i)) + continue; + kb_do_refresh &= ~(1 << i); + } + elements = DI_BUFFER; + hr = IDirectInputDevice8_GetDeviceData(lpdi, sizeof(DIDEVICEOBJECTDATA), didod, &elements, 0); + if (hr == DI_OK) { + if (did->superdevice && (normalkb || rawkb)) + continue; + for (j = 0; j < elements; j++) { + int scancode = didod[j].dwOfs; + int pressed = (didod[j].dwData & 0x80) ? 1 : 0; + scancode = keyhack (scancode, pressed, i); + if (scancode < 0) + continue; + di_keycodes[i][scancode] = pressed; + if (stopoutput == 0) + my_kbd_handler (i, scancode, pressed); + } + } else if (hr == DIERR_INPUTLOST) { + acquire (lpdi, "keyboard"); + kb_do_refresh |= 1 << i; + } else if (did->acquired && hr == DIERR_NOTACQUIRED) { + acquire (lpdi, "keyboard"); + } + IDirectInputDevice8_Poll (lpdi); + } +#ifdef CATWEASEL + { + char kc; + if (stopoutput == 0 && catweasel_read_keyboard (&kc)) + inputdevice_do_keyboard (kc & 0x7f, kc & 0x80); + } +#endif +} + +void wait_keyrelease (void) +{ + int i, j, maxcount = 200, found; + stopoutput++; + + while (maxcount-- > 0) { + sleep_millis (10); + read_kb (); + found = 0; + for (j = 0; j < MAX_INPUT_DEVICES; j++) { + for (i = 0; i < MAX_KEYCODES; i++) { + if (di_keycodes[j][i]) found = 1; + } + } + if (!found) + break; + } + release_keys (); + + for (;;) { + int ok = 0, nok = 0; + for (i = 0; i < MAX_INPUT_DEVICES; i++) { + struct didata *did = &di_mouse[i]; + DIMOUSESTATE dis; + LPDIRECTINPUTDEVICE8 lpdi = did->lpdi; + HRESULT hr; + int j; + + if (!lpdi) + continue; + nok++; + hr = IDirectInputDevice8_GetDeviceState (lpdi, sizeof (dis), &dis); + if (hr == DI_OK) { + for (j = 0; j < 4; j++) { + if (dis.rgbButtons[j] & 0x80) break; + } + if (j == 4) ok++; + } else { + ok++; + } + } + if (ok == nok) break; + sleep_millis (10); + } + stopoutput--; +} + +static int acquire_kb (int num, int flags) +{ + DWORD mode = DISCL_NOWINKEY | DISCL_FOREGROUND | DISCL_EXCLUSIVE; + LPDIRECTINPUTDEVICE8 lpdi = di_keyboard[num].lpdi; + + unacquire (lpdi, "keyboard"); + setcoop (lpdi, mode, "keyboard"); + kb_do_refresh = ~0; + +#ifdef WINDDK + if (currprefs.keyboard_leds_in_use) { + if (os_winnt) { + if (DefineDosDevice (DDD_RAW_TARGET_PATH, "Kbd","\\Device\\KeyboardClass0")) { + kbhandle = CreateFile("\\\\.\\Kbd", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + if (kbhandle == INVALID_HANDLE_VALUE) + write_log ("kbled: CreateFile failed, error %d\n", GetLastError()); + } else { + write_log ("kbled: DefineDosDevice failed, error %d\n", GetLastError()); + } + } + oldleds = get_leds (); + if (oldusedleds < 0) + oldusedleds = newleds = oldleds; + set_leds (oldusedleds); + } +#endif + di_keyboard[num].acquired = -1; + if (acquire (lpdi, "keyboard")) { + if (di_keyboard[num].superdevice) + superkb++; + else + normalkb++; + di_keyboard[num].acquired = 1; + } + return di_keyboard[num].acquired > 0 ? 1 : 0; +} + +static void unacquire_kb (int num) +{ + LPDIRECTINPUTDEVICE8 lpdi = di_keyboard[num].lpdi; + + unacquire (lpdi, "keyboard"); + if (di_keyboard[num].acquired) { + if (di_keyboard[num].superdevice) + superkb--; + else + normalkb--; + di_keyboard[num].acquired = 0; + } + release_keys (); + +#ifdef WINDDK + if (currprefs.keyboard_leds_in_use && oldusedleds >= 0) { + set_leds (oldleds); + oldusedleds = oldleds; + if (kbhandle != INVALID_HANDLE_VALUE) { + CloseHandle(kbhandle); + DefineDosDevice (DDD_REMOVE_DEFINITION, "Kbd", NULL); + kbhandle = INVALID_HANDLE_VALUE; + } + } +#endif +} + +struct inputdevice_functions inputdevicefunc_keyboard = { + init_kb, close_kb, acquire_kb, unacquire_kb, read_kb, + get_kb_num, get_kb_name, + get_kb_widget_num, get_kb_widget_type, + get_kb_widget_first +}; + + +static int get_joystick_num (void) +{ + return num_joystick; +} + +static int get_joystick_widget_num (int joy) +{ + return di_joystick[joy].axles + di_joystick[joy].buttons; +} + +static int get_joystick_widget_type (int joy, int num, char *name, uae_u32 *code) +{ + struct didata *did = &di_joystick[joy]; + if (num >= did->axles && num < did->axles + did->buttons) { + if (name) + strcpy (name, did->buttonname[num - did->axles]); + return IDEV_WIDGET_BUTTON; + } else if (num < di_joystick[joy].axles) { + if (name) + strcpy (name, did->axisname[num]); + return IDEV_WIDGET_AXIS; + } + return IDEV_WIDGET_NONE; +} + +static int get_joystick_widget_first (int joy, int type) +{ + switch (type) + { + case IDEV_WIDGET_BUTTON: + return di_joystick[joy].axles; + case IDEV_WIDGET_AXIS: + return 0; + } + return -1; +} + +static char *get_joystick_name (int joy) +{ + return di_joystick[joy].name; +} + +static int isjoy (int pcport, int amigaport) +{ + if (pcport == 0) + return JSEM_ISJOY0 (amigaport, &currprefs); + else + return JSEM_ISJOY1 (amigaport, &currprefs); +} + +static void read_joystick (void) +{ + DIDEVICEOBJECTDATA didod[DI_BUFFER]; + LPDIRECTINPUTDEVICE8 lpdi; + DWORD elements; + HRESULT hr; + int i, j, k; + + for (i = 0; i < MAX_INPUT_DEVICES; i++) { + struct didata *did = &di_joystick[i]; + lpdi = did->lpdi; + if (!lpdi) + continue; + if (currprefs.input_selected_setting == 0) { + if (i >= 2) + break; + if (isjoy (i, 0)) { + if (JSEM_ISNUMPAD (0, &currprefs) || JSEM_ISCURSOR (0, &currprefs) || JSEM_ISSOMEWHEREELSE (0, &currprefs)) + continue; + } else if (isjoy (i, 1)) { + if (JSEM_ISNUMPAD (1, &currprefs) || JSEM_ISCURSOR (1, &currprefs) || JSEM_ISSOMEWHEREELSE (1, &currprefs)) + continue; + } else + continue; + } + elements = DI_BUFFER; + hr = IDirectInputDevice8_GetDeviceData (lpdi, sizeof (DIDEVICEOBJECTDATA), didod, &elements, 0); + if (hr == DI_OK) { + for (j = 0; j < elements; j++) { + int dimofs = didod[j].dwOfs; + int data = didod[j].dwData; + int data2 = data; + int state = (data & 0x80) ? 1 : 0; + data -= 32768; + + for (k = 0; k < did->buttons; k++) { + if (did->buttonmappings[k] == dimofs) { +#ifdef DI_DEBUG2 + write_log ("B:NUM=%d OFF=%d NAME=%s VAL=%d STATE=%d\n", + k, dimofs, did->buttonname[k], data, state); +#endif + setjoybuttonstate (i, k, state); + break; + } + } + for (k = 0; k < did->axles; k++) { + if (did->axismappings[k] == dimofs) { + if (did->axistype[k]) { + setjoystickstate (i, k, (data2 >= 20250 && data2 <= 33750) ? -1 : (data2 >= 2250 && data2 <= 15750) ? 1 : 0, 1); + setjoystickstate (i, k + 1, ((data2 >= 29250 && data2 <= 33750) || (data2 >= 0 && data2 <= 6750)) ? -1 : (data2 >= 11250 && data2 <= 24750) ? 1 : 0, 1); +#ifdef DI_DEBUG2 + write_log ("P:NUM=%d OFF=%d NAME=%s VAL=%d\n", k, dimofs, did->axisname[k], data2); +#endif + } else { +#ifdef DI_DEBUG2 + if (data < -20000 || data > 20000) + write_log ("A:NUM=%d OFF=%d NAME=%s VAL=%d\n", k, dimofs, did->axisname[k], data); +#endif + setjoystickstate (i, k, data, 32768); + } + break; + } + } + } + } else if (hr == DIERR_INPUTLOST) { + acquire (lpdi, "joystick"); + } else if (did->acquired && hr == DIERR_NOTACQUIRED) { + acquire (lpdi, "joystick"); + } + IDirectInputDevice8_Poll (lpdi); + } +#ifdef CATWEASEL + { + static uae_u8 odir, obut; + uae_u8 dir, dir2, but; + if (catweasel_read_joystick (&dir, &but)) { + if ((but & 0x80) != (obut & 0x80)) + handle_input_event (INPUTEVENT_JOY1_FIRE_BUTTON, !(but & 0x80), 1, 0); + if ((but & 0x40) != (obut & 0x40)) + handle_input_event (INPUTEVENT_JOY2_FIRE_BUTTON, !(but & 0x40), 1, 0); + dir2 = odir; + odir = dir; + obut = but; + if ((dir & 15) != (dir2 & 15)) { + handle_input_event (INPUTEVENT_JOY2_HORIZ, !(dir & 1) ? 1 : !(dir & 2) ? -1 : 0, 1, 0); + handle_input_event (INPUTEVENT_JOY2_VERT, !(dir & 4) ? 1 : !(dir & 8) ? -1 : 0, 1, 0); + } + dir >>= 4; + dir2 >>= 4; + if ((dir & 15) != (dir2 & 15)) { + handle_input_event (INPUTEVENT_JOY1_HORIZ, !(dir & 1) ? 1 : !(dir & 2) ? -1 : 0, 1, 0); + handle_input_event (INPUTEVENT_JOY1_VERT, !(dir & 4) ? 1 : !(dir & 8) ? -1 : 0, 1, 0); + } + } + } +#endif +} + +static int init_joystick (void) +{ + int i; + LPDIRECTINPUTDEVICE8 lpdi; + HRESULT hr; + struct didata *did; + + if (joystick_inited) + return 1; + di_init (); + joystick_inited = 1; + for (i = 0; i < num_joystick; i++) { + did = &di_joystick[i]; + if (!did->disabled) { + hr = IDirectInput8_CreateDevice (g_lpdi, &did->guid, &lpdi, NULL); + if (hr == DI_OK) { + hr = IDirectInputDevice8_SetDataFormat(lpdi, &c_dfDIJoystick); + if (hr == DI_OK) { + did->lpdi = lpdi; + IDirectInputDevice8_EnumObjects (lpdi, EnumObjectsCallback, (void*)did, DIDFT_ALL); + sortobjects (did, did->axismappings, did->axissort, did->axisname, did->axistype, did->axles); + sortobjects (did, did->buttonmappings, did->buttonsort, did->buttonname, 0, did->buttons); + } + } else + write_log ("joystick createdevice failed, %s\n", DXError (hr)); + } + } + return 1; +} + +static void close_joystick (void) +{ + int i; + + if (!joystick_inited) + return; + joystick_inited = 0; + for (i = 0; i < num_joystick; i++) { + if (di_joystick[i].lpdi) + IDirectInputDevice8_Release (di_joystick[i].lpdi); + di_joystick[i].lpdi = 0; + } + di_free (); +} + +static int acquire_joystick (int num, int flags) +{ + LPDIRECTINPUTDEVICE8 lpdi = di_joystick[num].lpdi; + DIPROPDWORD dipdw; + HRESULT hr; + + unacquire (lpdi, "joystick"); + setcoop (lpdi, flags ? (DISCL_FOREGROUND | DISCL_EXCLUSIVE) : (DISCL_BACKGROUND | DISCL_NONEXCLUSIVE), "joystick"); + memset (&dipdw, 0, sizeof (dipdw)); + dipdw.diph.dwSize = sizeof(DIPROPDWORD); + dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); + dipdw.diph.dwObj = 0; + dipdw.diph.dwHow = DIPH_DEVICE; + dipdw.dwData = DI_BUFFER; + hr = IDirectInputDevice8_SetProperty (lpdi, DIPROP_BUFFERSIZE, &dipdw.diph); + if (hr != DI_OK) + write_log ("joystick setproperty failed, %s\n", DXError (hr)); + di_joystick[num].acquired = acquire (lpdi, "joystick") ? 1 : -1; + return di_joystick[num].acquired > 0 ? 1 : 0; +} + +static void unacquire_joystick (int num) +{ + unacquire (di_joystick[num].lpdi, "joystick"); + di_joystick[num].acquired = 0; +} + +struct inputdevice_functions inputdevicefunc_joystick = { + init_joystick, close_joystick, acquire_joystick, unacquire_joystick, + read_joystick, get_joystick_num, get_joystick_name, + get_joystick_widget_num, get_joystick_widget_type, + get_joystick_widget_first +}; + +int dinput_wmkey (uae_u32 key) +{ + if (normalkb || superkb || rawkb) + return 0; + if (((key >> 16) & 0xff) == 0x58) + return 1; + return 0; +} + +void input_get_default_mouse (struct uae_input_device *uid) +{ + int i, port; + + for (i = 0; i < num_mouse; i++) { + port = i & 1; + if (di_mouse[i].wininput) + port = 0; + uid[i].eventid[ID_AXIS_OFFSET + 0][0] = port ? INPUTEVENT_MOUSE2_HORIZ : INPUTEVENT_MOUSE1_HORIZ; + uid[i].eventid[ID_AXIS_OFFSET + 1][0] = port ? INPUTEVENT_MOUSE2_VERT : INPUTEVENT_MOUSE1_VERT; + uid[i].eventid[ID_AXIS_OFFSET + 2][0] = port ? 0 : INPUTEVENT_MOUSE1_WHEEL; + uid[i].eventid[ID_BUTTON_OFFSET + 0][0] = port ? INPUTEVENT_JOY2_FIRE_BUTTON : INPUTEVENT_JOY1_FIRE_BUTTON; + uid[i].eventid[ID_BUTTON_OFFSET + 1][0] = port ? INPUTEVENT_JOY2_2ND_BUTTON : INPUTEVENT_JOY1_2ND_BUTTON; + uid[i].eventid[ID_BUTTON_OFFSET + 2][0] = port ? INPUTEVENT_JOY2_3RD_BUTTON : INPUTEVENT_JOY1_3RD_BUTTON; + } + uid[0].enabled = 1; +} + +void input_get_default_joystick (struct uae_input_device *uid) +{ + int i, port; + + for (i = 0; i < num_mouse; i++) { + port = i & 1; + uid[i].eventid[ID_AXIS_OFFSET + 0][0] = port ? INPUTEVENT_JOY2_HORIZ : INPUTEVENT_JOY1_HORIZ; + uid[i].eventid[ID_AXIS_OFFSET + 1][0] = port ? INPUTEVENT_JOY2_VERT : INPUTEVENT_JOY1_VERT; + uid[i].eventid[ID_BUTTON_OFFSET + 0][0] = port ? INPUTEVENT_JOY2_FIRE_BUTTON : INPUTEVENT_JOY1_FIRE_BUTTON; + uid[i].eventid[ID_BUTTON_OFFSET + 1][0] = port ? INPUTEVENT_JOY2_2ND_BUTTON : INPUTEVENT_JOY1_2ND_BUTTON; + uid[i].eventid[ID_BUTTON_OFFSET + 2][0] = port ? INPUTEVENT_JOY2_3RD_BUTTON : INPUTEVENT_JOY1_3RD_BUTTON; + } + uid[0].enabled = 1; +} diff --git a/od-win32/direct3d.c b/od-win32/direct3d.c new file mode 100755 index 00000000..37a03329 --- /dev/null +++ b/od-win32/direct3d.c @@ -0,0 +1,559 @@ + +#include +#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 +#include + +#include "direct3d.h" + +static int tformat; +static int d3d_enabled, scanlines_ok; +static HINSTANCE d3dDLL; +static LPDIRECT3D9 d3d; +static D3DPRESENT_PARAMETERS dpp; +static LPDIRECT3DDEVICE9 d3ddev; +static D3DSURFACE_DESC dsdbb; +static LPDIRECT3DTEXTURE9 texture, sltexture; + +static int twidth, theight, max_texture_w, max_texture_h; +static int tin_w, tin_h, window_h, window_w; +static int t_depth; +static int required_sl_texture_w, required_sl_texture_h; +static int vsync2, guimode; + +static char *D3D_ErrorText (HRESULT error) +{ + return ""; +} +static char *D3D_ErrorString (HRESULT dival) +{ + static char dierr[200]; + sprintf(dierr, "%08.8X S=%d F=%04.4X C=%04.4X (%d) (%s)", + dival, (dival & 0x80000000) ? 1 : 0, + HRESULT_FACILITY(dival), + HRESULT_CODE(dival), + HRESULT_CODE(dival), + D3D_ErrorText (dival)); + return dierr; +} + +void D3D_free (void) +{ + if (texture) { + IDirect3DTexture9_Release (texture); + texture = NULL; + } + if (sltexture) { + IDirect3DTexture9_Release (sltexture); + sltexture = NULL; + } + + if (d3ddev) { + IDirect3DDevice9_Release (d3ddev); + d3ddev = NULL; + } + if (d3dDLL) { + FreeLibrary (d3dDLL); + d3dDLL = NULL; + } + d3d_enabled = 0; +} + +static int restoredeviceobjects(void) +{ + // Store render target surface desc + LPDIRECT3DSURFACE9 bb; + HRESULT hr; + D3DXMATRIX matrix; + FLOAT aspect; + int v; + + hr = IDirect3DDevice9_GetBackBuffer (d3ddev, 0, 0, D3DBACKBUFFER_TYPE_MONO, &bb); + if (!SUCCEEDED (hr)) { + write_log ("failed to create backbuffer: %s\n", D3D_ErrorString (hr)); + return 0; + } + hr = IDirect3DSurface9_GetDesc (bb, &dsdbb); + hr = IDirect3DSurface9_Release (bb); + + // Set up the texture + hr = IDirect3DDevice9_SetTextureStageState(d3ddev, 0, D3DTSS_COLOROP, D3DTOP_MODULATE); + hr = IDirect3DDevice9_SetTextureStageState(d3ddev, 0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + hr = IDirect3DDevice9_SetTextureStageState(d3ddev, 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + + // Set miscellaneous render states + hr = IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_DITHERENABLE, TRUE); + hr = IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ZENABLE, FALSE); + + // Set the projection matrix + aspect = ((FLOAT)dsdbb.Width) / dsdbb.Height; + D3DXMatrixPerspectiveFovLH (&matrix, D3DX_PI/4, aspect, 1.0f, 100.0f); + hr = IDirect3DDevice9_SetTransform(d3ddev, D3DTS_PROJECTION, &matrix); + + // turn off lighting + hr = IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_LIGHTING, FALSE); + + switch (currprefs.gfx_filter_filtermode & 1) + { + case 0: + v = D3DTEXF_POINT; + break; + case 1: + default: + v = D3DTEXF_LINEAR; + break; + } + hr = IDirect3DDevice9_SetSamplerState(d3ddev, 0, D3DSAMP_MAGFILTER, v); + hr = IDirect3DDevice9_SetSamplerState(d3ddev, 0, D3DSAMP_MINFILTER, v); + return 1; +} + +static int createtexture (int w, int h) +{ + HRESULT hr; + UINT ww = w; + UINT hh = h; + D3DFORMAT format = tformat; + + hr = D3DXCheckTextureRequirements(d3ddev, &ww, &hh, NULL, 0, &format, D3DPOOL_MANAGED); + if (FAILED (hr)) { + write_log ("D3DXCheckTextureRequirements failed: %s\n", D3D_ErrorString (hr)); + } + hr = D3DXCreateTexture(d3ddev, ww, hh, 0, 0, format, D3DPOOL_MANAGED, &texture); + if (FAILED (hr)) { + write_log ("D3DXCreateTexture failed: %s\n", D3D_ErrorString (hr)); + } + twidth = ww; + theight = hh; + write_log ("D3D: %d*%d texture allocated, bits per pixel %d\n", ww, hh, t_depth); + return 1; +} +static int createsltexture (void) +{ + HRESULT hr; + UINT ww = required_sl_texture_w; + UINT hh = required_sl_texture_h; + D3DFORMAT format = D3DFMT_A4R4G4B4; + + hr = D3DXCheckTextureRequirements(d3ddev, &ww, &hh, NULL, 0, &format, D3DPOOL_MANAGED); + if (FAILED (hr)) { + write_log ("SL D3DXCheckTextureRequirements failed: %s\n", D3D_ErrorString (hr)); + return 0; + } + hr = D3DXCreateTexture(d3ddev, ww, hh, 0, 0, format, D3DPOOL_MANAGED, &sltexture); + if (FAILED (hr)) { + write_log ("SL D3DXCreateTexture failed: %s\n", D3D_ErrorString (hr)); + return 0; + } + required_sl_texture_w = ww; + required_sl_texture_h = hh; + write_log ("D3D: SL %d*%d texture allocated\n", ww, hh); + + scanlines_ok = 1; + return 1; +} + +static void createscanlines (int force) +{ + HRESULT hr; + D3DLOCKED_RECT locked; + static int osl1, osl2, osl3; + int sl4, sl42; + int l1, l2; + int x, y, yy; + uae_u8 *sld, *p; + + if (!scanlines_ok) + return; + if (osl1 == currprefs.gfx_filter_scanlines && osl3 == currprefs.gfx_filter_scanlinelevel && osl2 == currprefs.gfx_filter_scanlineratio && !force) + return; + osl1 = currprefs.gfx_filter_scanlines; + osl3 = currprefs.gfx_filter_scanlinelevel; + osl2 = currprefs.gfx_filter_scanlineratio; + sl4 = currprefs.gfx_filter_scanlines * 16 / 100; + sl42 = currprefs.gfx_filter_scanlinelevel * 16 / 100; + if (sl4 > 15) sl4 = 15; + if (sl42 > 15) sl42 = 15; + l1 = currprefs.gfx_filter_scanlineratio & 15; + l2 = currprefs.gfx_filter_scanlineratio >> 4; + + hr = IDirect3DTexture9_LockRect(sltexture, 0, &locked, NULL, D3DLOCK_DISCARD); + if (FAILED (hr)) { + write_log ("SL IDirect3DTexture9_LockRect failed: %s\n", D3D_ErrorString (hr)); + return; + } + sld = (uae_u8*)locked.pBits; + for (y = 0; y < window_h; y++) + memset (sld + y * locked.Pitch, 0, window_w * 2); + for (y = 1; y < window_h; y += l1 + l2) { + for (yy = 0; yy < l2 && y + yy < window_h; yy++) { + for (x = 0; x < window_w; x++) { + /* 16-bit, A4R4G4B4 */ + uae_u8 sll = sl42; + p = &sld[(y + yy) * locked.Pitch + (x * 2)]; + p[1] = (sl4 << 4) | (sll << 0); + p[0] = (sll << 4) | (sll << 0); + } + } + } + IDirect3DTexture9_UnlockRect (sltexture, 0); + if (scanlines_ok) { + /* enable alpha blending for scanlines */ + IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHABLENDENABLE, TRUE); + IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + } else { + IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHABLENDENABLE, FALSE); + } +} + + +const char *D3D_init (HWND ahwnd, int w_w, int w_h, int t_w, int t_h, int depth) +{ + HRESULT ret; + static char errmsg[100] = { 0 }; + LPDIRECT3D9 (WINAPI *D3DCreate)(UINT); + D3DDISPLAYMODE mode; + D3DCAPS9 d3dCaps; + + d3d_enabled = 0; + scanlines_ok = 0; + if (currprefs.gfx_filter != UAE_FILTER_DIRECT3D) { + strcpy (errmsg, "D3D: not enabled"); + return errmsg; + } + + d3dDLL = LoadLibrary("D3D9.DLL"); + if (d3dDLL == NULL) { + strcpy (errmsg, "Direct3D: DirectX 9 or newer required"); + return errmsg; + } + D3DCreate = (LPDIRECT3D9 (WINAPI *)(UINT)) + GetProcAddress(d3dDLL, "Direct3DCreate9"); + if(D3DCreate == NULL) { + D3D_free (); + strcpy (errmsg, "Direct3D: DirectX 9 or newer required"); + return errmsg; + } + d3d = D3DCreate(D3D_SDK_VERSION); + if (d3d == NULL) { + D3D_free (); + strcpy (errmsg, "Direct3D: failed to create D3D object"); + return errmsg; + } + + IDirect3D9_GetAdapterDisplayMode(d3d, D3DADAPTER_DEFAULT, &mode); + IDirect3D9_GetDeviceCaps(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps); + + memset (&dpp, 0, sizeof (dpp)); + dpp.Windowed = currprefs.gfx_afullscreen ? FALSE : TRUE; + dpp.BackBufferFormat = mode.Format; + dpp.BackBufferCount = 1; + dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; + dpp.BackBufferWidth = w_w; + dpp.BackBufferHeight = w_h; + dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + vsync2 = 0; + if (currprefs.gfx_afullscreen) { + dpp.FullScreen_RefreshRateInHz = currprefs.gfx_refreshrate; + if (currprefs.gfx_vsync > 0) { + dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; + if (currprefs.gfx_vsync > 85) { + if (d3dCaps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO) + dpp.PresentationInterval = D3DPRESENT_INTERVAL_TWO; + else + vsync2 = 1; + } + } + } + + ret = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, ahwnd, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, &dpp, &d3ddev); + if(FAILED(ret)) { + sprintf (errmsg, "CreateDevice failed, %s\n", D3D_ErrorString (ret)); + D3D_free (); + return errmsg; + } + + max_texture_w = d3dCaps.MaxTextureWidth; + max_texture_h = d3dCaps.MaxTextureHeight; + + write_log("D3D: max texture width: %d, max texture height: %d\n", + max_texture_w, max_texture_h); + + if (max_texture_w < t_w || max_texture_h < t_h) { + sprintf (errmsg, "Direct3D: %d * %d or bigger texture support required\nYour card's maximum texture size is only %d * %d", + t_w, t_h, max_texture_w, max_texture_h); + return errmsg; + } + + required_sl_texture_w = w_w; + required_sl_texture_h = w_h; + if (currprefs.gfx_filter_scanlines > 0 && (max_texture_w < w_w || max_texture_h < w_h)) { + gui_message ("Direct3D: %d * %d or bigger texture support required for scanlines (max is only %d * %d)\n" + "Scanlines disabled.", + required_sl_texture_w, required_sl_texture_h, max_texture_w, max_texture_h); + changed_prefs.gfx_filter_scanlines = currprefs.gfx_filter_scanlines = 0; + } + + t_depth = depth; + switch (depth) + { + case 32: + if (currprefs.gfx_filter_scanlines) + tformat = D3DFMT_A8R8G8B8; + else + tformat = D3DFMT_X8R8G8B8; + break; + case 15: + case 16: + if (currprefs.gfx_filter_scanlines) + tformat = D3DFMT_A1R5G5B5; + else + tformat = D3DFMT_X1R5G5B5; + break; + } + restoredeviceobjects (); + window_w = w_w; + window_h = w_h; + tin_w = t_w; + tin_h = t_h; + createtexture (t_w, t_h); + if (currprefs.gfx_filter_scanlines > 0) + createsltexture (); + createscanlines (1); + d3d_enabled = 1; + return 0; +} + +#define D3DFVF_TLVERTEX D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1 + +typedef struct _D3DTLVERTEX { + float sx; /* Screen coordinates */ + float sy; + float sz; + float rhw; /* Reciprocal of homogeneous w */ + D3DCOLOR color; /* Vertex color */ + float tu; /* Texture coordinates */ + float tv; +} D3DTLVERTEX, *LPD3DTLVERTEX; + +static void BlitRect(LPDIRECT3DDEVICE9 dev, LPDIRECT3DTEXTURE9 src, + float left, float top, float right, float bottom, D3DCOLOR col,float z) +{ + int i; + HRESULT hr; + D3DTLVERTEX verts[4]; + float rhw = 1.0f / (z * 990.0f + 10.0f); + + for (i = 0; i < 4; i++) { + verts[i].rhw = rhw; + verts[i].color = col; + } + verts[0].tu = 0.0f; verts[0].tv = 0.0f; + verts[0].sx = left - 0.5f; verts[0].sy = top - 0.5f; verts[0].sz = z; + verts[1].tu = 1.0f; verts[1].tv = 0.0f; + verts[1].sx = right - 0.5f; verts[1].sy = top - 0.5f; verts[1].sz = z; + verts[2].tu = 1.0f; verts[2].tv = 1.0f; + verts[2].sx = right - 0.5f; verts[2].sy = bottom - 0.5f; verts[2].sz = z; + verts[3].tu = 0.0f; verts[3].tv = 1.0f; + verts[3].sx = left - 0.5f; verts[3].sy = bottom - 0.5f; verts[3].sz = z; + + // set the texture + hr = IDirect3DDevice9_SetTexture(dev, 0, src); + if (FAILED (hr)) + write_log ("IDirect3DDevice9_SetTexture failed: %s\n", D3D_ErrorString (hr)); + + hr = IDirect3DDevice9_SetVertexShader(dev, NULL); + if (FAILED (hr)) + write_log ("IDirect3DDevice9_SetVertexShader failed: %s\n", D3D_ErrorString (hr)); + // configure shader for vertex type + hr = IDirect3DDevice9_SetFVF(dev, D3DFVF_TLVERTEX); + if (FAILED (hr)) + write_log ("IDirect3DDevice9_SetFVF failed: %s\n", D3D_ErrorString (hr)); + + // draw the rectangle + hr = IDirect3DDevice9_DrawPrimitiveUP(dev, D3DPT_TRIANGLEFAN, 2, verts, sizeof(D3DTLVERTEX)); + if (FAILED (hr)) + write_log ("IDirect3DDevice9_DrawPrimitiveUP failed: %s\n", D3D_ErrorString (hr)); +} + +static void calc (float *xp, float *yp, float *sxp, float *syp) +{ + int xm, ym; + int fx, fy; + float x, y, sx, sy; + + xm = currprefs.gfx_lores ? 2 : 1; + ym = currprefs.gfx_linedbl ? 1 : 2; + if (window_w >= 1024) + xm *= 2; + else if (window_w < 500) + xm /= 2; + if (window_h >= 960) + ym *= 2; + else if (window_h < 350) + ym /= 2; + fx = (tin_w * xm - window_w) / 2; + fy = (tin_h * ym - window_h) / 2; + x = (float)(window_w * currprefs.gfx_filter_horiz_offset / 100.0); + y = (float)(window_h * currprefs.gfx_filter_vert_offset / 100.0); + sx = x + (float)(twidth * window_w / tin_w) * ((currprefs.gfx_filter_horiz_zoom + 100) / 100.0); + sy = y + (float)(theight * window_h / tin_h) * ((currprefs.gfx_filter_vert_zoom + 100) / 100.0); + x -= fx; y -= fy; + sx += 2 * fx; sy += 2 * fy; + *xp = x; *yp = y; + *sxp = sx; *syp = sy; +} + +void D3D_unlocktexture (void) +{ + float x, y, sx, sy; + IDirect3DTexture9_UnlockRect (texture, 0); + calc (&x, &y, &sx, &sy); + BlitRect (d3ddev, texture, x, y, sx, sy, 0xffffff, 0.1f); + if (scanlines_ok) + BlitRect (d3ddev, sltexture, 0, 0, required_sl_texture_w, required_sl_texture_h, 0xffffff, 0.2f); + IDirect3DDevice9_EndScene(d3ddev); + IDirect3DDevice9_Present (d3ddev, 0, 0, 0 ,0); + if (vsync2) + D3D_render (); +} + +int D3D_locktexture (void) +{ + D3DLOCKED_RECT locked; + HRESULT hr; + + if (FAILED(IDirect3DDevice9_TestCooperativeLevel(d3ddev))) + return 0; + IDirect3DDevice9_Clear(d3ddev, 0L, NULL, D3DCLEAR_TARGET, 0x00000000, 1.0f, 0L ); + + hr = IDirect3DDevice9_BeginScene(d3ddev); + if (FAILED (hr)) { + write_log ("IDirect3DDevice9_BeginScene failed: %s\n", D3D_ErrorString (hr)); + return 0; + } + hr = IDirect3DTexture9_LockRect(texture, 0, &locked, NULL, D3DLOCK_DISCARD | D3DLOCK_NOSYSLOCK); + if (FAILED (hr)) { + write_log ("IDirect3DTexture9_LockRect failed: %s\n", D3D_ErrorString (hr)); + D3D_unlocktexture (); + return 0; + } + gfxvidinfo.bufmem = locked.pBits; + gfxvidinfo.rowbytes = locked.Pitch; + init_row_map (); + return 1; +} + +void D3D_render (void) +{ + float x, y, sx, sy; + HRESULT hr; + + if (!d3d_enabled) + return; + if (FAILED(IDirect3DDevice9_TestCooperativeLevel(d3ddev))) + return; + IDirect3DDevice9_Clear(d3ddev, 0L, NULL, D3DCLEAR_TARGET, 0x00000000, 1.0f, 0L ); + hr = IDirect3DDevice9_BeginScene(d3ddev); + if (FAILED (hr)) + return; + calc (&x, &y, &sx, &sy); + BlitRect(d3ddev, texture, x, y, sx, sy, 0xffffff, 0.1f); + if (scanlines_ok) + BlitRect (d3ddev, sltexture, 0, 0, required_sl_texture_w, required_sl_texture_h, 0xffffff, 0.2f); + IDirect3DDevice9_EndScene(d3ddev); + IDirect3DDevice9_Present (d3ddev, 0, 0, 0 ,0); +} + +void D3D_refresh (void) +{ + if (!d3d_enabled) + return; + createscanlines (1); + D3D_render (); +} + +void D3D_getpixelformat (int depth,int *rb, int *gb, int *bb, int *rs, int *gs, int *bs, int *ab, int *as, int *a) +{ + switch (depth) + { + case 32: + *rb = 8; + *gb = 8; + *bb = 8; + *ab = 8; + *rs = 16; + *gs = 8; + *bs = 0; + *as = 24; + *a = 255; + break; + case 15: + case 16: + *rb = 5; + *gb = 5; + *bb = 5; + *ab = 1; + *rs = 10; + *gs = 5; + *bs = 0; + *as = 15; + *a = 1; + break; + } +} + +void D3D_guimode (int guion) +{ + if (!d3d_enabled) + return; + IDirect3DDevice9_SetDialogBoxMode (d3ddev, guion); + guimode = guion; +} + +HDC D3D_getDC(HDC hdc) +{ + static LPDIRECT3DSURFACE9 bb; + HRESULT hr; + + if (!d3d_enabled) + return 0; + if (!hdc) { + hr = IDirect3DDevice9_GetBackBuffer (d3ddev, 0, 0, D3DBACKBUFFER_TYPE_MONO, &bb); + if (!SUCCEEDED (hr)) { + write_log ("failed to create backbuffer: %s\n", D3D_ErrorString (hr)); + return 0; + } + if (IDirect3DSurface9_GetDC (bb, &hdc) == D3D_OK) + return hdc; + return 0; + } + IDirect3DSurface9_ReleaseDC (bb, hdc); + IDirect3DSurface9_Release (bb); + return 0; +} + +int D3D_isenabled (void) +{ + return d3d_enabled; +} + + + + + + diff --git a/od-win32/direct3d.h b/od-win32/direct3d.h new file mode 100755 index 00000000..6e16be81 --- /dev/null +++ b/od-win32/direct3d.h @@ -0,0 +1,12 @@ + +extern void D3D_resize (int width, int height); +extern void D3D_free (); +extern const char *D3D_init (HWND ahwnd, int w_w, int w_h, int t_w, int t_h, int depth); +extern void D3D_render (void); +extern void D3D_getpixelformat (int depth,int *rb, int *bb, int *gb, int *rs, int *bs, int *gs, int *ab, int *ar, int *a); +extern void D3D_refresh (void); +extern int D3D_locktexture(void); +extern void D3D_unlocktexture(void); +extern void D3D_guimode (int guion); +extern HDC D3D_getDC(HDC hdc); +extern int D3D_isenabled (void); diff --git a/od-win32/drivesound.c b/od-win32/drivesound.c new file mode 100755 index 00000000..4782c7bb --- /dev/null +++ b/od-win32/drivesound.c @@ -0,0 +1,191 @@ +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "zfile.h" +#include "sounddep/sound.h" +#include "dxwrap.h" + +#include +#include +#include + +static LPDIRECTSOUND lpDS; +static LPDIRECTSOUNDBUFFER lpDSBprimary; + +#define DRIVESOUND_CLICK 0 +#define DRIVESOUND_STARTUP 1 +#define DRIVESOUND_SPIN 2 +#define DRIVESOUND_END 3 + +static LPDIRECTSOUNDBUFFER samples[4][DRIVESOUND_END]; +static int drivesound_enabled, drive_enabled[4]; +static int click_frequency[4]; +static int minfreq, maxfreq; + +extern GUID sound_device_guid[]; + +static void close_audio_ds (void) +{ + int i, j; + + drivesound_enabled = 0; + for (i = 0; i < DRIVESOUND_END; i++) { + for (j = 0; j < 4; j++) { + if (samples[j][i]) + IDirectSound_Release (samples[j][i]); + samples[j][i] = 0; + drive_enabled[j] = 0; + } + } + if (lpDSBprimary) + IDirectSound_Release (lpDSBprimary); + lpDSBprimary = 0; + if (lpDS) { + IDirectSound_Release (lpDS); + write_log ("DRIVESOUND: DirectSound driver freed\n"); + } + lpDS = 0; +} + +extern HWND hMainWnd; + +static int createsample (int drivenum, int samplenum, char *path) +{ + struct zfile *f; + uae_u8 *buf = 0; + int size, freq = 44100; + WAVEFORMATEX wavfmt; + DSBUFFERDESC sound_buffer; + HRESULT hr; + void *b1, *b2; + DWORD s1, s2; + + f = zfile_fopen (path, "rb"); + if (!f) { + write_log ("DRIVESOUND: can't open '%s'\n", path); + goto error; + } + zfile_fseek (f, 0, SEEK_END); + size = zfile_ftell (f); + buf = malloc (size); + zfile_fseek (f, 0, SEEK_SET); + zfile_fread (buf, size, 1, f); + zfile_fclose (f); + + if (samplenum == DRIVESOUND_CLICK) + click_frequency[drivenum] = freq; + wavfmt.wFormatTag = WAVE_FORMAT_PCM; + wavfmt.nChannels = 2; + wavfmt.nSamplesPerSec = freq; + wavfmt.wBitsPerSample = 16; + wavfmt.nBlockAlign = 16 / 8 * wavfmt.nChannels; + wavfmt.nAvgBytesPerSec = wavfmt.nBlockAlign * freq; + memset (&sound_buffer, 0, sizeof (sound_buffer)); + sound_buffer.dwSize = sizeof (sound_buffer); + sound_buffer.dwBufferBytes = size; + sound_buffer.lpwfxFormat = &wavfmt; + sound_buffer.dwFlags = DSBCAPS_LOCSOFTWARE | DSBCAPS_GLOBALFOCUS; + + hr = IDirectSound_CreateSoundBuffer( lpDS, &sound_buffer, &samples[drivenum][samplenum], NULL ); + if (hr != DS_OK) { + write_log ("DRIVESOUND: Secondary CreateSoundBuffer(%s) failure: %s\n", + path, DXError (hr)); + goto error; + } + hr = IDirectSoundBuffer_Lock (samples[drivenum][samplenum], 0, sndbufsize, &b1, &s1, &b2, &s2, DSBLOCK_ENTIREBUFFER); + if (hr != DS_OK) { + write_log ("DRIVESOUND: lock failed: %s\n", DXError (hr)); + goto error; + } + memcpy (b1, buf, size >= s1 ? s1 : size); + if (b2) + memcpy (b2, buf + s1, size - s1); + IDirectSoundBuffer_Unlock (samples[drivenum][samplenum], b1, s1, b2, s2); + write_log ("DRIVESOUND: drive %d, sample %d (%s) loaded\n", drivenum, samplenum, path); + + return 1; + error: + free (buf); + if (samples[drivenum][samplenum]) { + IDirectSound_Release (samples[drivenum][samplenum]); + samples[drivenum][samplenum] = 0; + } + return 0; +} + + +static int open_audio_ds (void) +{ + HRESULT hr; + int freq = currprefs.sound_freq; + + enumerate_sound_devices (0); + hr = DirectSoundCreate (&sound_device_guid[currprefs.win32_soundcard], &lpDS, NULL); + if (hr != DS_OK) { + write_log ("SOUND: DirectSoundCreate() failure: %s\n", DXError (hr)); + return 0; + } + hr = IDirectSound_SetCooperativeLevel (lpDS, hMainWnd, DSSCL_NORMAL); + if (hr != DS_OK) { + write_log ("SOUND: Can't set cooperativelevel: %s\n", DXError (hr)); + goto error; + } + + createsample(0, DRIVESOUND_CLICK, "drive_click.raw"); + createsample(0, DRIVESOUND_STARTUP, "drive_startup.raw"); + createsample(0, DRIVESOUND_SPIN, "drive_spin.raw"); + drive_enabled[0] = 1; + + drivesound_enabled = 1; + + return 1; + +error: + close_audio_ds (); + return 0; +} + +int drivesound_init (void) +{ + return open_audio_ds (); +} + +void drivesound_free (void) +{ + close_audio_ds (); +} + +void drivesound_click (int num, int delay) +{ + HRESULT hr; + LPDIRECTSOUNDBUFFER dsb; + + if (!drivesound_enabled || !drive_enabled[num]) + return; + dsb = samples[num][DRIVESOUND_CLICK]; + if (!dsb) + return; + hr = IDirectSoundBuffer_SetCurrentPosition (dsb, 0); + hr = IDirectSoundBuffer_Play (dsb, 0, 0, 0); +} + +void drivesound_motor (int num, int status) +{ + HRESULT hr; + + if (!drivesound_enabled || !drive_enabled[num]) + return; + if (!status) { + if (samples[num][DRIVESOUND_STARTUP]) + hr = IDirectSoundBuffer_Stop (samples[num][DRIVESOUND_STARTUP]); + if (samples[num][DRIVESOUND_SPIN]) + hr = IDirectSoundBuffer_Stop (samples[num][DRIVESOUND_SPIN]); + } else { + if (status == 2 && samples[num][DRIVESOUND_STARTUP]) + hr = IDirectSoundBuffer_Play (samples[num][DRIVESOUND_STARTUP], 0, 0, 0); + if (samples[num][DRIVESOUND_SPIN]) + hr = IDirectSoundBuffer_Play (samples[num][DRIVESOUND_SPIN], 0, 0, DSBPLAY_LOOPING); + } +} diff --git a/od-win32/dxwrap.c b/od-win32/dxwrap.c new file mode 100755 index 00000000..9b774515 --- /dev/null +++ b/od-win32/dxwrap.c @@ -0,0 +1,2056 @@ +/* + * UAE - The Ultimate Amiga Emulator + * + * Win32 DirectX Wrappers, to simplify (?) my life. + * + * Copyright 1999 Brian King, under GNU Public License + * + */ +#ifndef _MSC_VER +#define INITGUID +#endif + +#include "config.h" +#include "sysconfig.h" + +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#include +#include +#include +#include +#else +#include "winstuff.h" +#endif + +#include "sysdeps.h" +#include "options.h" +#include "picasso96.h" +#include "dxwrap.h" +#include "win32.h" +#include "win32gfx.h" +#include "machdep/rpt.h" +#include "custom.h" + +static BOOL bColourKeyAvailable = FALSE; +static BOOL bOverlayAvailable = FALSE; +static DDCAPS_DX7 drivercaps, helcaps; +static DWORD overlayflags; +static DDOVERLAYFX overlayfx; +extern COLORREF g_dwBackgroundColor; +static int flipinterval_supported; + +#define dxwrite_log + +static int restoresurface (LPDIRECTDRAWSURFACE7 surface) +{ + HRESULT hr = IDirectDrawSurface7_Restore (surface); + if (hr == DD_OK) { + HRESULT hr2; + DDBLTFX bltfx; + memset (&bltfx, 0, sizeof (bltfx)); + bltfx.dwSize = sizeof (bltfx); + hr2 = IDirectDrawSurface7_Blt (surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &bltfx); + if (hr2 != DD_OK) + write_log("Surface clear failed: %s\n", DXError (hr2)); + } + return hr; +} +/* + * FUNCTION:ShowDDCaps + * + * PURPOSE:print out the DirectDraw Capabilities + * + * PARAMETERS: + * caps - DDCAPS_DX7 structure + * hw - flag indicating if this 'caps' is for real hardware or the HEL + * + * RETURNS: none + * + * NOTES:none + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +static void ShowDDCaps( DDCAPS_DX7 caps, int hw ) +{ + static int shown = 0; + static BOOL reset_shown = FALSE; + if( currprefs.win32_logfile && shown >= 4 && !reset_shown) + { + shown = 0; + reset_shown = TRUE; + } + + if( shown < 2) + { + dxwrite_log( "DirectDraw Capabilities for %s:\n", hw ? "Display Driver Hardware" : "Display Driver Emulation Layer" ); + if( caps.dwCaps & DDCAPS_BLT ) + dxwrite_log( "DDCAPS_BLT - Capable of blitting\n" ); + if( caps.dwCaps & DDCAPS_BLTCOLORFILL ) + dxwrite_log( "DDCAPS_BLTCOLORFILL - Color filling with blitter\n" ); + if( caps.dwCaps & DDCAPS_BLTSTRETCH ) + dxwrite_log( "DDCAPS_BLTSTRETCH - Stretch blitting\n" ); + if( caps.dwCaps & DDCAPS_CANBLTSYSMEM ) + dxwrite_log( "DDCAPS_CANBLTSYSMEM - Blits from system memory\n" ); + if( caps.dwCaps & DDCAPS_CANCLIP ) + dxwrite_log( "DDCAPS_CANCLIP - Can clip while blitting\n" ); + if( caps.dwCaps & DDCAPS_CANCLIPSTRETCHED ) + dxwrite_log( "DDCAPS_CANCLIPSTRETCHED - Can clip while stretch-blitting\n" ); + if( caps.dwCaps & DDCAPS_COLORKEY ) + { + dxwrite_log( "DDCAPS_COLORKEY - Can color-key with blits/overlays\n" ); + bColourKeyAvailable = TRUE; + } + if( caps.dwCaps & DDCAPS_GDI ) + dxwrite_log( "DDCAPS_GDI - Display h/w shared with GDI\n" ); + if( caps.dwCaps & DDCAPS_NOHARDWARE ) + dxwrite_log( "DDCAPS_NOHARDWARE - no h/w support!\n" ); + if( caps.dwCaps & DDCAPS_OVERLAY ) + { + dxwrite_log( "DDCAPS_OVERLAY - support for %d overlay(s)\n", caps.dwMaxVisibleOverlays ); + if( bColourKeyAvailable ) + { + if( caps.dwCKeyCaps & DDCKEYCAPS_DESTOVERLAY ) + { + dxwrite_log( "DDCKEYCAPS_DESTOVERLAY - colour-keyed overlays\n" ); + bOverlayAvailable = TRUE; + } + } + } + if( caps.dwCaps & DDCAPS_OVERLAYFOURCC ) + dxwrite_log( "DDCAPS_OVERLAYFOURCC - overlay can do color-space conversions\n" ); + if( caps.dwCaps & DDCAPS_OVERLAYSTRETCH ) + dxwrite_log( "DDCAPS_OVERLAYSTRETCH - overlay can stretch with min=%d/max=%d\n", caps.dwMinOverlayStretch, caps.dwMaxOverlayStretch ); + if( caps.dwCaps & DDCAPS_VBI ) + dxwrite_log( "DDCAPS_VBI - h/w can generate a vertical-blanking interrupt\n" ); + if( caps.dwCaps2 & DDCAPS2_CERTIFIED ) + dxwrite_log( "DDCAPS2_CERTIFIED - certified driver\n" ); + if( caps.dwCaps2 & DDCAPS2_CANRENDERWINDOWED ) + dxwrite_log( "DDCAPS2_CANRENDERWINDOWED - GDI windows can be seen when in full-screen\n" ); + if( caps.dwCaps2 & DDCAPS2_NOPAGELOCKREQUIRED ) + dxwrite_log( "DDCAPS2_NOPAGELOCKREQUIRED - no page locking needed for DMA blits\n" ); + if( caps.dwCaps2 & DDCAPS2_FLIPNOVSYNC ) + dxwrite_log( "DDCAPS2_FLIPNOVSYNC - can pass DDFLIP_NOVSYNC to Flip calls\n" ); + if( caps.dwCaps2 & DDCAPS2_FLIPINTERVAL ) { + dxwrite_log( "DDCAPS2_FLIPINTERVAL - can pass DDFLIP_INTERVALx to Flip calls\n" ); + flipinterval_supported = 1; + } + + dxwrite_log( "Video memory: %d/%d\n", caps.dwVidMemFree, caps.dwVidMemTotal ); + } + shown++; +} + +const char *DXError (HRESULT ddrval) +{ + static char dderr[1000]; + sprintf(dderr, "%08.8X S=%d F=%04.4X C=%04.4X (%d) (%s)", + ddrval, (ddrval & 0x80000000) ? 1 : 0, + HRESULT_FACILITY(ddrval), + HRESULT_CODE(ddrval), + HRESULT_CODE(ddrval), + DXGetErrorDescription8 (ddrval)); + return dderr; +} + +static struct DirectDrawSurfaceMapper DirectDrawState; + +static int lockcnt = 0; + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +static int LockStub( surface_type_e type ) +{ + int result = 0; + HRESULT ddrval; + LPDIRECTDRAWSURFACE7 surface; + LPDDSURFACEDESC2 surfacedesc; + + switch( type ) + { + case primary_surface: + surface = DirectDrawState.primary.surface; + surfacedesc = &DirectDrawState.primary.desc; + break; + case secondary_surface: + surface = DirectDrawState.secondary.surface; + surfacedesc = &DirectDrawState.secondary.desc; + break; + case tertiary_surface: + surface = DirectDrawState.tertiary.surface; + surfacedesc = &DirectDrawState.tertiary.desc; + break; + case overlay_surface: + surface = DirectDrawState.overlay.surface; + surfacedesc = &DirectDrawState.overlay.desc; + break; + } + + if( lockcnt ) + { +#ifdef _DEBUG + DebugBreak(); +#endif + return 1; + } + + if( type == secondary_surface && DirectDrawState.flipping != single_buffer ) + { + IDirectDrawSurface7_Restore( DirectDrawState.primary.surface ); + } + + while ( (ddrval = IDirectDrawSurface7_Lock( surface, NULL, surfacedesc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, + NULL ) ) != DD_OK ) + { + if (ddrval == DDERR_SURFACELOST) { + ddrval = restoresurface (surface); + if (ddrval != DD_OK) + { + result = 0; + break; + } + } + else if (ddrval != DDERR_SURFACEBUSY) + { + write_log ("lpDDS->Lock() failed - %s\n", DXError (ddrval)); + result = 0; + break; + } + } + if( ddrval == DD_OK ) + result = 1; + + if( result ) + lockcnt++; + + return result; +} + +/* For a given surface-type, update our DirectDrawState structure */ +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +int DirectDraw_SurfaceLock( surface_type_e surface_type ) +{ + int result = 0; + + if( surface_type == lockable_surface ) + surface_type = DirectDraw_GetLockableType(); + + switch( surface_type ) + { + case primary_surface: + DirectDrawState.primary.desc.dwSize = sizeof( DDSURFACEDESC2 ); + result = LockStub( surface_type ); + break; + case secondary_surface: + DirectDrawState.secondary.desc.dwSize = sizeof( DDSURFACEDESC2 ); + result = LockStub( surface_type ); + break; + case tertiary_surface: + DirectDrawState.tertiary.desc.dwSize = sizeof( DDSURFACEDESC2 ); + result = LockStub( surface_type ); + break; + case overlay_surface: + DirectDrawState.overlay.desc.dwSize = sizeof( DDSURFACEDESC2 ); + result = LockStub( surface_type ); + case lockable_surface: + case invalid_surface: + default: + + break; + } + DirectDrawState.locked = result; + + return result; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +char *DirectDraw_GetSurfacePointer( void ) +{ + char *pixels = NULL; + + /* Make sure that somebody has done a lock before returning the lpSurface member */ + if( lockcnt ) + { + pixels = DirectDrawState.lockable.lpdesc->lpSurface; + } + return pixels; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +LONG DirectDraw_GetSurfacePitch( void ) +{ + LONG pitch = 0; + + pitch = DirectDrawState.lockable.lpdesc->lPitch; + return pitch; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +DWORD DirectDraw_GetPixelFormatFlags( void ) +{ + DWORD flags = 0; + flags = DirectDrawState.lockable.lpdesc->ddpfPixelFormat.dwFlags; + return flags; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +DWORD DirectDraw_GetSurfaceFlags( void ) +{ + DWORD flags = 0; + flags = DirectDrawState.lockable.lpdesc->dwFlags; + return flags; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +DWORD DirectDraw_GetSurfaceBitCount( void ) +{ + DWORD bits = 0; + //?????JGI begin: + if( DirectDrawState.lockable.lpdesc ) + bits = DirectDrawState.lockable.lpdesc->ddpfPixelFormat.dwRGBBitCount; + else + bits = DirectDrawState.current.desc.ddpfPixelFormat.dwRGBBitCount; + //?????JGI end. + return bits; +} + +/* + * FUNCTION:DirectDraw_GetPrimaryBitCount + * + * PURPOSE:Return the bit-depth of the primary surface + * + * PARAMETERS: none + * + * RETURNS: bit-depth + * + * NOTES: + * + * HISTORY: + * 2001.08.25 Brian King Creation + * + */ +DWORD DirectDraw_GetPrimaryBitCount( void ) +{ + DWORD bits = 0; + memset(&DirectDrawState.primary.desc,0,sizeof(DirectDrawState.primary.desc)); + DirectDrawState.primary.desc.dwSize = sizeof(DirectDrawState.primary.desc); + + IDirectDrawSurface7_GetSurfaceDesc(DirectDrawState.primary.surface, &DirectDrawState.primary.desc); + bits = DirectDrawState.primary.desc.ddpfPixelFormat.dwRGBBitCount; + return bits; +} + +void DirectDraw_GetPrimaryWidthHeight(int *w, int *h) +{ + memset(&DirectDrawState.primary.desc,0,sizeof(DirectDrawState.primary.desc)); + DirectDrawState.primary.desc.dwSize = sizeof(DirectDrawState.primary.desc); + + IDirectDrawSurface7_GetSurfaceDesc(DirectDrawState.primary.surface, &DirectDrawState.primary.desc); + *w = DirectDrawState.primary.desc.dwWidth; + *h = DirectDrawState.primary.desc.dwHeight; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +DWORD DirectDraw_GetPixelFormatBitMask( DirectDraw_Mask_e mask ) +{ + DWORD result = 0; + switch( mask ) + { + case red_mask: + result = DirectDrawState.lockable.lpdesc->ddpfPixelFormat.dwRBitMask; + break; + case green_mask: + result = DirectDrawState.lockable.lpdesc->ddpfPixelFormat.dwGBitMask; + break; + case blue_mask: + result = DirectDrawState.lockable.lpdesc->ddpfPixelFormat.dwBBitMask; + break; + } + return result; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +surface_type_e DirectDraw_GetLockableType( void ) +{ + return DirectDrawState.surface_type; +} + +/* + * FUNCTION:DirectDraw_IsLocked + * + * PURPOSE:Return whether we're currently locked or unlocked + * + * PARAMETERS: none + * + * RETURNS: TRUE if already locked, FALSE otherwise + * + * NOTES:Used by DX_Blit to possibly unlock during Blit operation + * + * HISTORY: + * 2000.04.30 Brian King Creation + * + */ +BOOL DirectDraw_IsLocked( void ) +{ + return DirectDrawState.locked ? TRUE : FALSE; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +static surface_type_e try_surface_locks( int want_fullscreen ) +{ + surface_type_e result = invalid_surface; + + if( DirectDrawState.isoverlay && DirectDraw_SurfaceLock( overlay_surface ) ) + { + result = overlay_surface; + write_log( "try_surface_locks() returning overlay\n" ); + } + else if( want_fullscreen && WIN32GFX_IsPicassoScreen() ) + { + if( DirectDraw_SurfaceLock( primary_surface ) ) + { + result = primary_surface; + write_log( "try_surface_locks() returning primary\n" ); + } + else if( DirectDraw_SurfaceLock( secondary_surface ) ) + { + result = secondary_surface; + write_log( "try_surface_locks() returning secondary\n" ); + } + } + else + { + if( DirectDraw_SurfaceLock( secondary_surface ) ) + { + result = secondary_surface; + write_log( "try_surface_locks() returning secondary\n" ); + } + } + + return result; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES:Named this way for historical reasons + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +void ddraw_unlockscr( void ) +{ + if( lockcnt > 0 ) + { + lockcnt--; + IDirectDrawSurface7_Unlock( DirectDrawState.lockable.surface, + DirectDrawState.lockable.lpdesc->lpSurface ); + DirectDrawState.locked = FALSE; + } +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +int DirectDraw_Start( GUID *guid ) +{ + HRESULT ddrval; + DDCAPS_DX7 drivercaps, helcaps; + + /* Prepare our DirectDrawState structure */ + ZeroMemory( &DirectDrawState, sizeof( DirectDrawState ) ); + ZeroMemory( &drivercaps, sizeof( drivercaps ) ); + ZeroMemory( &helcaps, sizeof( helcaps ) ); + drivercaps.dwSize = sizeof( drivercaps ); + helcaps.dwSize = sizeof( helcaps ); + + ddrval = DirectDrawCreate( guid, &DirectDrawState.directdraw.ddx, NULL ); + if (ddrval != DD_OK) { + if ( guid != NULL) + return 0; + goto oops; + } + + DirectDrawState.initialized = TRUE; + + ddrval = IDirectDraw_QueryInterface( DirectDrawState.directdraw.ddx, + &IID_IDirectDraw7, + (LPVOID *)&DirectDrawState.directdraw.dd ); + if( ddrval != DD_OK ) + { + gui_message("start_ddraw(): DirectX 7 or newer required"); + DirectDraw_Release(); + return 0; + } + + DirectDraw_GetCaps( &drivercaps, &helcaps ); + ShowDDCaps( drivercaps, 1 ); + ShowDDCaps( helcaps, 0 ); + if (DirectDraw_GetDisplayMode () == DD_OK) + return 1; + if (guid != NULL) { + DirectDraw_Release (); + return 0; + } + + oops: + gui_message ("start_ddraw(): DirectDraw initialization failed with %s\n", DXError (ddrval)); + DirectDraw_Release(); + return 0; +} + +#define releaser(x,y) if( x ) { y( x ); x = NULL; } + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +void DirectDraw_Release( void ) +{ + releaser( DirectDrawState.lpDDC, IDirectDrawClipper_Release ); + releaser( DirectDrawState.lpDDP, IDirectDrawPalette_Release ); + + if (DirectDrawState.directdraw.dd && DirectDrawState.modeset) + { + IDirectDraw7_RestoreDisplayMode( DirectDrawState.directdraw.dd ); + IDirectDraw7_SetCooperativeLevel( DirectDrawState.directdraw.dd, hAmigaWnd, DDSCL_NORMAL); + } + DirectDrawState.modeset = 0; + + releaser( DirectDrawState.overlay.surface, IDirectDrawSurface7_Release ); + releaser( DirectDrawState.primary.surface, IDirectDrawSurface7_Release ); + + if( DirectDrawState.flipping == single_buffer) + releaser( DirectDrawState.secondary.surface, IDirectDrawSurface7_Release ); + + releaser( DirectDrawState.directdraw.dd, IDirectDraw_Release ); + + DirectDrawState.lockable.lpdesc = NULL; + DirectDrawState.lockable.lpdesc = NULL; + DirectDrawState.lockable.surface = NULL; + DirectDrawState.lockable.surface = NULL; + + DirectDrawState.surface_type = invalid_surface; + DirectDrawState.initialized = FALSE; + DirectDrawState.isoverlay = FALSE; +} + +/* + * FUNCTION:DirectDraw_SetCooperativeLevel + * + * PURPOSE:Wrapper for setting the cooperative level (fullscreen or normal) + * + * PARAMETERS: + * window Window to set the cooperative level for + * want_fullscreen fullscreen mode flag + * + * RETURNS: result of underlying DirectDraw call + * + * NOTES: Updates the .fullscreen and .window members. + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +HRESULT DirectDraw_SetCooperativeLevel( HWND window, int want_fullscreen ) +{ + HRESULT ddrval; + + ddrval = IDirectDraw7_SetCooperativeLevel( DirectDrawState.directdraw.dd, + window, + want_fullscreen ? + DDSCL_ALLOWREBOOT | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN : + DDSCL_NORMAL ); + if( ddrval == DD_OK ) + { + DirectDrawState.fullscreen = want_fullscreen; + DirectDrawState.window = window; + } + return ddrval; +} + +/* + * FUNCTION:DirectDraw_GetCooperativeLevel + * + * PURPOSE:Wrapper for setting the cooperative level (fullscreen or normal) + * + * PARAMETERS: + * window Window to set the cooperative level for + * want_fullscreen fullscreen mode flag + * + * RETURNS: result of underlying DirectDraw call + * + * NOTES: Updates the .fullscreen and .window members. + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +BOOL DirectDraw_GetCooperativeLevel( HWND *window, int *fullscreen ) +{ + BOOL result = FALSE; + + if( DirectDrawState.initialized ) + { + *fullscreen = DirectDrawState.fullscreen; + *window = DirectDrawState.window; + result = TRUE; + } + return result; +} + +/* + * FUNCTION:DirectDraw_SetDisplayMode + * + * PURPOSE:Change the display-mode to width x height pixels, with a given + * vertical refresh-rate. + * + * PARAMETERS: + * width - width of display in pixels + * height - height of display in pixels + * freq - vertical refresh-rate in Hz + * + * RETURNS: + * ddrval - HRESULT indicating success (DD_OK) or failure + * + * NOTES:The freq parameter is only obeyed on when we're using DirectX 6 + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +HRESULT DirectDraw_SetDisplayMode( int width, int height, int bits, int freq ) +{ + HRESULT ddrval; + + ddrval = IDirectDraw7_SetDisplayMode( DirectDrawState.directdraw.dd, + width, height, bits, freq, 0 ); + DirectDrawState.modeset = 1; + return ddrval; +} + +/* + * FUNCTION:DirectDraw_GetDisplayMode + * + * PURPOSE:Get the display-mode characteristics. + * + * PARAMETERS: none + * + * RETURNS: + * ddrval - HRESULT indicating success (DD_OK) or failure + * + * NOTES:none + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +HRESULT DirectDraw_GetDisplayMode( void ) +{ + HRESULT ddrval; + + /* We fill in the current.desc in all cases */ + DirectDrawState.current.desc.dwSize = sizeof( DDSURFACEDESC2 ); + ddrval = IDirectDraw7_GetDisplayMode( DirectDrawState.directdraw.dd, + &DirectDrawState.current.desc ); + return ddrval; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +HRESULT DirectDraw_GetCaps( DDCAPS_DX7 *driver_caps, DDCAPS_DX7 *hel_caps ) +{ + HRESULT ddrval; + + ddrval = IDirectDraw7_GetCaps( DirectDrawState.directdraw.dd, + driver_caps, hel_caps ); + return ddrval; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +HRESULT DirectDraw_CreateClipper( void ) +{ + HRESULT ddrval; + ddrval = IDirectDraw7_CreateClipper( DirectDrawState.directdraw.dd, + 0, + &DirectDrawState.lpDDC, + NULL ); + return ddrval; +} + +static DWORD ConvertGDIColor( COLORREF dwGDIColor ) +{ + COLORREF rgbT; + HDC hdc; + DWORD dw = CLR_INVALID; + DDSURFACEDESC2 ddsd,pdds; + HRESULT hr; + + memset(&pdds,0,sizeof(pdds)); + pdds.dwSize = sizeof(pdds); + + IDirectDrawSurface7_GetSurfaceDesc(DirectDrawState.primary.surface, &pdds); + + // Use GDI SetPixel to color match for us + if( dwGDIColor != CLR_INVALID && IDirectDrawSurface7_GetDC(DirectDrawState.primary.surface, &hdc) == DD_OK) + { + rgbT = GetPixel(hdc, 0, 0); // Save current pixel value + SetPixel(hdc, 0, 0, dwGDIColor); // Set our value + IDirectDrawSurface7_ReleaseDC(DirectDrawState.primary.surface,hdc); + } + + // Now lock the surface so we can read back the converted color + ddsd.dwSize = sizeof(ddsd); + hr = IDirectDrawSurface7_Lock(DirectDrawState.primary.surface, NULL, &ddsd, DDLOCK_WAIT, NULL ); + if( hr == DD_OK) + { + dw = *(DWORD *) ddsd.lpSurface; + if( ddsd.ddpfPixelFormat.dwRGBBitCount < 32 ) // Mask it to bpp + dw &= ( 1 << ddsd.ddpfPixelFormat.dwRGBBitCount ) - 1; + IDirectDrawSurface7_Unlock(DirectDrawState.primary.surface,NULL); + } + + // Now put the color that was there back. + if( dwGDIColor != CLR_INVALID && IDirectDrawSurface7_GetDC(DirectDrawState.primary.surface,&hdc) == DD_OK ) + { + SetPixel( hdc, 0, 0, rgbT ); + IDirectDrawSurface7_ReleaseDC(DirectDrawState.primary.surface,hdc); + } + + return dw; +} + + +HRESULT DirectDraw_CreateOverlaySurface( int width, int height, int bits) +{ + DDSURFACEDESC2 ddsd; + DDPIXELFORMAT ddpfOverlayFormat; + HRESULT ddrval = DDERR_UNSUPPORTED; + DWORD dwDDSColor; + + if( bOverlayAvailable ) + { + write_log( "CreateOverlaySurface being called with %d-bits!\n", bits ); + if( bits == 16 ) + { + // Set the overlay format to 16 bit RGB 5:6:5 + ZeroMemory( &ddpfOverlayFormat, sizeof(ddpfOverlayFormat) ); + ddpfOverlayFormat.dwSize = sizeof(ddpfOverlayFormat); + ddpfOverlayFormat.dwFlags = DDPF_RGB; + ddpfOverlayFormat.dwRGBBitCount = 16; + ddpfOverlayFormat.dwRBitMask = 0xF800; + ddpfOverlayFormat.dwGBitMask = 0x07E0; + ddpfOverlayFormat.dwBBitMask = 0x001F; + } + else if( bits == 32 ) + { + // Set the overlay format to 32 bit ARGB 8:8:8:8 + ZeroMemory( &ddpfOverlayFormat, sizeof(ddpfOverlayFormat) ); + ddpfOverlayFormat.dwSize = sizeof(ddpfOverlayFormat); + ddpfOverlayFormat.dwFlags = DDPF_RGB; + ddpfOverlayFormat.dwRGBBitCount = 32; + ddpfOverlayFormat.dwRBitMask = 0x00FF0000; + ddpfOverlayFormat.dwGBitMask = 0x0000FF00; + ddpfOverlayFormat.dwBBitMask = 0x000000FF; + } + else if( bits == 8 ) + { + // Set the overlay format to 8 bit palette + ZeroMemory( &ddpfOverlayFormat, sizeof(ddpfOverlayFormat) ); + ddpfOverlayFormat.dwSize = sizeof(ddpfOverlayFormat); + ddpfOverlayFormat.dwFlags = DDPF_RGB | DDPF_PALETTEINDEXED8; + ddpfOverlayFormat.dwRGBBitCount = 8; + ddpfOverlayFormat.dwRBitMask = 0x00000000; + ddpfOverlayFormat.dwGBitMask = 0x00000000; + ddpfOverlayFormat.dwBBitMask = 0x00000000; + } + else + { + // We don't handle this case... + return DDERR_INVALIDPIXELFORMAT; + } + + // Setup the overlay surface's attributes in the surface descriptor + ZeroMemory( &ddsd, sizeof(ddsd) ); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; + ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY; + ddsd.dwWidth = width; + ddsd.dwHeight = height; + ddsd.ddpfPixelFormat = ddpfOverlayFormat; + + ZeroMemory(&overlayfx,sizeof(overlayfx)); + overlayfx.dwSize = sizeof(overlayfx); + overlayflags = DDOVER_SHOW | DDOVER_DDFX | DDOVER_KEYDESTOVERRIDE; + + dwDDSColor = ConvertGDIColor( g_dwBackgroundColor ); + overlayfx.dckDestColorkey.dwColorSpaceLowValue = dwDDSColor; + overlayfx.dckDestColorkey.dwColorSpaceHighValue = dwDDSColor; + + // Attempt to create the surface with theses settings + ddrval = IDirectDraw7_CreateSurface ( DirectDrawState.directdraw.dd, &ddsd, &DirectDrawState.overlay.surface, NULL); + if( ddrval == DD_OK ) + { +#if 0 + ddrval = IDirectDrawSurface7_QueryInterface( DirectDrawState.overlay.surface, + &IID_IDirectDrawSurface7,(LPVOID *)&DirectDrawState.overlay.surface ); +#endif + DirectDrawState.isoverlay = 1; + } + else + { + DirectDrawState.isoverlay = 0; + } + } + else + { + write_log( "CreateOverlaySurface being called, but no overlay support with this card...!\n" ); + } + return ddrval; +} + + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +HRESULT DirectDraw_CreateSurface( int width, int height ) +{ + HRESULT ddrval; + + DirectDrawState.flipping = single_buffer; + + if( DirectDrawState.fullscreen ) // Create a flipping pair! + { + ZeroMemory( &DirectDrawState.primary.desc, sizeof( DDSURFACEDESC2 ) ); + DirectDrawState.primary.desc.dwSize = sizeof( DDSURFACEDESC2 ); + DirectDrawState.primary.desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + DirectDrawState.primary.desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP; + DirectDrawState.primary.desc.dwBackBufferCount = 2; + ddrval = IDirectDraw7_CreateSurface( DirectDrawState.directdraw.dd, + &DirectDrawState.primary.desc, + &DirectDrawState.primary.surface, + NULL ); + if( ddrval != DD_OK ) + { + // Create a non-flipping pair, since the flipping pair creation failed... + ZeroMemory( &DirectDrawState.primary.desc, sizeof( DDSURFACEDESC2 ) ); + DirectDrawState.primary.desc.dwSize = sizeof( DDSURFACEDESC2 ); + DirectDrawState.primary.desc.dwFlags = DDSD_CAPS; + DirectDrawState.primary.desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + ddrval = IDirectDraw7_CreateSurface( DirectDrawState.directdraw.dd, + &DirectDrawState.primary.desc, + &DirectDrawState.primary.surface, + NULL ); + } + else + { + DirectDrawState.flipping = triple_buffer; + } + } + else + { + // We're not full-screen, so you cannot create a flipping pair... + + ZeroMemory( &DirectDrawState.primary.desc, sizeof( DDSURFACEDESC2 ) ); + DirectDrawState.primary.desc.dwSize = sizeof( DDSURFACEDESC2 ); + DirectDrawState.primary.desc.dwFlags = DDSD_CAPS; + DirectDrawState.primary.desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + ddrval = IDirectDraw7_CreateSurface( DirectDrawState.directdraw.dd, + &DirectDrawState.primary.desc, + &DirectDrawState.primary.surface, + NULL ); + } + + if( ddrval != DD_OK ) + { + goto out; + } + else + { + write_log( "DDRAW: Primary %ssurface created in video-memory\n", DirectDrawState.flipping != single_buffer ? "flipping " : "" ); + } + + // Check if we can access the back-buffer of our flipping-pair (if present) + if( DirectDrawState.flipping != single_buffer ) + { + DDSCAPS2 ddSCaps; + ZeroMemory(&ddSCaps, sizeof(ddSCaps)); + ddSCaps.dwCaps = DDSCAPS_BACKBUFFER; + + ddrval = IDirectDrawSurface7_GetAttachedSurface( DirectDrawState.primary.surface, &ddSCaps, &DirectDrawState.secondary.surface ); + if( ddrval == DD_OK ) + { + /* get third buffer */ + ZeroMemory(&ddSCaps, sizeof(ddSCaps)); + ddSCaps.dwCaps = DDSCAPS_FLIP; + + ddrval = IDirectDrawSurface7_GetAttachedSurface( DirectDrawState.secondary.surface, &ddSCaps, &DirectDrawState.tertiary.surface ); + if( ddrval == DD_OK ) + { + #if 0 + // Get our IDirectDrawSurface7 pointer + ddrval = IDirectDrawSurface7_QueryInterface( DirectDrawState.tertiary.surface, + &IID_IDirectDrawSurface7, + (LPVOID *)&DirectDrawState.tertiary.surface ); + if( ddrval != DD_OK ) + { + goto out; + } + #endif + } + else + { + DirectDrawState.flipping = single_buffer; + } + #if 0 + // Get our IDirectDrawSurface7 pointer + ddrval = IDirectDrawSurface_QueryInterface( DirectDrawState.secondary.surface, + &IID_IDirectDrawSurface7, + (LPVOID *)&DirectDrawState.secondary.surface ); + if( ddrval != DD_OK ) + { + goto out; + } +#endif + } + else + { + DirectDrawState.flipping = single_buffer; + } + } + +#if 0 + // Get our IDirectDrawSurface7 pointer + ddrval = IDirectDrawSurface7_QueryInterface( DirectDrawState.primary.surface, + &IID_IDirectDrawSurface7, + (LPVOID *)&DirectDrawState.primary.surface ); + + if( ddrval != DD_OK ) + { + goto out; + } +#endif + + // We always want a secondary-buffer when creating our primary-surface. If we're a flipping pair, + // the secondary buffer is already allocated. If we failed to create a flipping pair, or because + // we're not full-screen, then lets create ourselves a back-buffer manually. + if( DirectDrawState.flipping == single_buffer ) + { + ZeroMemory( &DirectDrawState.secondary.desc, sizeof( DDSURFACEDESC2 ) ); + DirectDrawState.secondary.desc.dwSize = sizeof( DDSURFACEDESC2 ); + DirectDrawState.secondary.desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + DirectDrawState.secondary.desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + DirectDrawState.secondary.desc.dwWidth = width; + DirectDrawState.secondary.desc.dwHeight = height; + ddrval = IDirectDraw7_CreateSurface( DirectDrawState.directdraw.dd, + &DirectDrawState.secondary.desc, + &DirectDrawState.secondary.surface, + NULL ); + if( ddrval != DD_OK ) + { + write_log( "DDRAW:Secondary surface creation attempt #1 failed with %s\n", DXError(ddrval)); + DirectDrawState.secondary.desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + ddrval = IDirectDraw7_CreateSurface( DirectDrawState.directdraw.dd, + &DirectDrawState.secondary.desc, + &DirectDrawState.secondary.surface, + NULL ); + if( ddrval == DD_OK ) + write_log( "DDRAW: Secondary surface created in plain system-memory\n" ); + else + { + goto out; + } + } + else + { + write_log( "DDRAW: Secondary surface created in video-memory\n" ); + } +#if 0 + // Get our IDirectDrawSurface7 pointer + ddrval = IDirectDrawSurface7_QueryInterface( DirectDrawState.secondary.surface, + &IID_IDirectDrawSurface7, + (LPVOID *)&DirectDrawState.secondary.surface ); + if( ddrval != DD_OK ) + { + goto out; + } +#endif + } +out: + return ddrval; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +void DirectDraw_ClearSurfaces( void ) +{ + DDBLTFX ddbltfx; + memset( &ddbltfx, 0, sizeof( ddbltfx ) ); + ddbltfx.dwFillColor = 0; + ddbltfx.dwSize = sizeof( ddbltfx ); + + DirectDraw_Blt( secondary_surface, NULL, invalid_surface, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx ); + if( DirectDrawState.isoverlay ) + DirectDraw_Blt( overlay_surface, NULL, invalid_surface, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx ); +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +int DirectDraw_DetermineLocking( int wantfull ) +{ + int result = 0; + + switch( DirectDrawState.surface_type = try_surface_locks( wantfull ) ) + { + case invalid_surface: + case lockable_surface: + DirectDrawState.lockable.lpdesc = NULL; + DirectDrawState.lockable.lpdesc = NULL; + DirectDrawState.lockable.surface = NULL; + DirectDrawState.lockable.surface = NULL; + write_log( "set_ddraw: Couldn't lock primary, and no secondary available.\n" ); + break; + case primary_surface: + DirectDrawState.lockable.lpdesc = &DirectDrawState.primary.desc; + DirectDrawState.lockable.lpdesc = &DirectDrawState.primary.desc; + DirectDrawState.lockable.surface = DirectDrawState.primary.surface; + DirectDrawState.lockable.surface = DirectDrawState.primary.surface; + result = 1; + break; + case overlay_surface: + DirectDrawState.lockable.lpdesc = &DirectDrawState.overlay.desc; + DirectDrawState.lockable.lpdesc = &DirectDrawState.overlay.desc; + DirectDrawState.lockable.surface = DirectDrawState.overlay.surface; + DirectDrawState.lockable.surface = DirectDrawState.overlay.surface; + result = 1; + break; + case secondary_surface: + DirectDrawState.lockable.lpdesc = &DirectDrawState.secondary.desc; + DirectDrawState.lockable.lpdesc = &DirectDrawState.secondary.desc; + DirectDrawState.lockable.surface = DirectDrawState.secondary.surface; + DirectDrawState.lockable.surface = DirectDrawState.secondary.surface; + result = 1; + break; + case tertiary_surface: + DirectDrawState.lockable.lpdesc = &DirectDrawState.tertiary.desc; + DirectDrawState.lockable.lpdesc = &DirectDrawState.tertiary.desc; + DirectDrawState.lockable.surface = DirectDrawState.tertiary.surface; + DirectDrawState.lockable.surface = DirectDrawState.tertiary.surface; + result = 1; + break; + } + + if( DirectDrawState.lockable.surface ) + DirectDraw_SurfaceUnlock(); + + return result; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +HRESULT DirectDraw_SetClipper( HWND hWnd ) +{ + HRESULT ddrval; + + ddrval = IDirectDrawSurface7_SetClipper( DirectDrawState.primary.surface, + hWnd ? DirectDrawState.lpDDC : NULL ); + if( hWnd && ( ddrval == DD_OK ) ) + { + ddrval = IDirectDrawClipper_SetHWnd( DirectDrawState.lpDDC, 0, hWnd ); + } + return ddrval; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +HRESULT DirectDraw_GetClipList( LPRGNDATA cliplist, LPDWORD size ) +{ + HRESULT ddrval; + + ddrval = IDirectDrawClipper_GetClipList( DirectDrawState.lpDDC, NULL, cliplist, size ); + + return ddrval; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +BYTE DirectDraw_GetBytesPerPixel( void ) +{ + int bpp; + bpp = ( DirectDrawState.lockable.lpdesc->ddpfPixelFormat.dwRGBBitCount + 7 ) >> 3; + return bpp; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +HRESULT DirectDraw_SetPalette( int remove ) +{ + HRESULT ddrval; + if (DirectDrawState.primary.surface == NULL) + return DDERR_SURFACELOST; + ddrval = IDirectDrawSurface7_SetPalette (DirectDrawState.primary.surface, + remove ? NULL : DirectDrawState.lpDDP); + if (ddrval == DDERR_SURFACELOST) { + ddrval = restoresurface (DirectDrawState.primary.surface); + if (ddrval == DD_OK) { + ddrval = IDirectDrawSurface7_SetPalette (DirectDrawState.primary.surface, + remove ? NULL : DirectDrawState.lpDDP); + } + } + return ddrval; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +HRESULT DirectDraw_CreatePalette( LPPALETTEENTRY pal ) +{ + HRESULT ddrval; + ddrval = IDirectDraw_CreatePalette( DirectDrawState.directdraw.dd, + DDPCAPS_8BIT | DDPCAPS_ALLOW256, + pal, &DirectDrawState.lpDDP, NULL); + if( ddrval == DD_OK ) + { + ddrval = DirectDraw_SetPalette(0); + } + return ddrval; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +HRESULT DirectDraw_SetPaletteEntries( int start, int count, PALETTEENTRY *palette ) +{ + HRESULT ddrval = DDERR_NOPALETTEATTACHED; + int i; + if( DirectDrawState.lpDDP ) + ddrval = IDirectDrawPalette_SetEntries( DirectDrawState.lpDDP, 0, start, count, palette ); + return ddrval; +} + +/* Return one of the pixel formats declared in picasso96.h if the surface + * is usable for us, or RGBFB_NONE if it is not usable. */ +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +RGBFTYPE DirectDraw_GetSurfacePixelFormat( LPDDSURFACEDESC2 surface ) +{ + int surface_is = 0; + DDPIXELFORMAT *pfp = NULL; + DWORD r, g, b; + DWORD surf_flags; + + surf_flags = surface->dwFlags; + pfp = &surface->ddpfPixelFormat; + + if( ( surf_flags & DDSD_PIXELFORMAT ) == 0x0 ) + return RGBFB_NONE; + + if ((pfp->dwFlags & DDPF_RGB) == 0) + return RGBFB_NONE; + + r = pfp->dwRBitMask; + g = pfp->dwGBitMask; + b = pfp->dwBBitMask; + switch (pfp->dwRGBBitCount) { + case 8: + if ((pfp->dwFlags & DDPF_PALETTEINDEXED8) != 0) + return RGBFB_CHUNKY; + break; + + case 16: + if (r == 0xF800 && g == 0x07E0 && b == 0x001F) + return RGBFB_R5G6B5PC; + if (r == 0x7C00 && g == 0x03E0 && b == 0x001F) + return RGBFB_R5G5B5PC; + if (b == 0xF800 && g == 0x07E0 && r == 0x001F) + return RGBFB_B5G6R5PC; + if (b == 0x7C00 && g == 0x03E0 && r == 0x001F) + return RGBFB_B5G5R5PC; + /* This happens under NT - with r == b == g == 0 !!! */ + write_log ("Unknown 16 bit format %d %d %d\n", r, g, b); + break; + + case 24: + if (r == 0xFF0000 && g == 0x00FF00 && b == 0x0000FF) + return RGBFB_B8G8R8; + if (r == 0x0000FF && g == 0x00FF00 && b == 0xFF0000) + return RGBFB_R8G8B8; + break; + + case 32: + if (r == 0x00FF0000 && g == 0x0000FF00 && b == 0x000000FF) + return RGBFB_B8G8R8A8; + if (r == 0x000000FF && g == 0x0000FF00 && b == 0x00FF0000) + return RGBFB_R8G8B8A8; + if (r == 0xFF000000 && g == 0x00FF0000 && b == 0x0000FF00) + return RGBFB_A8B8G8R8; + if (r == 0x0000FF00 && g == 0x00FF0000 && b == 0xFF000000) + return RGBFB_A8R8G8B8; + break; + + default: + write_log ("Unknown %d bit format %d %d %d\n", pfp->dwRGBBitCount, r, g, b); /* %%% - BERND, and here too... */ + break; + } + return RGBFB_NONE; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +RGBFTYPE DirectDraw_GetPixelFormat( void ) +{ + RGBFTYPE type; + if( DirectDrawState.lockable.lpdesc ) + type = DirectDraw_GetSurfacePixelFormat( DirectDrawState.lockable.lpdesc ); + else + type = DirectDraw_GetSurfacePixelFormat( &DirectDrawState.current.desc ); + return type; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +DWORD DirectDraw_CurrentWidth( void ) +{ + DWORD width; + width = DirectDrawState.current.desc.dwWidth; + return width; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +DWORD DirectDraw_CurrentHeight( void ) +{ + DWORD height; + height = DirectDrawState.current.desc.dwHeight; + return height; +} + +int DirectDraw_GetVerticalBlankStatus (void) +{ + BOOL status; + if (IDirectDraw7_GetVerticalBlankStatus (DirectDrawState.directdraw.dd, &status) != DD_OK) + return -1; + return status; +} + +DWORD DirectDraw_CurrentRefreshRate( void ) +{ + DWORD height; + height = DirectDrawState.current.desc.dwRefreshRate; + return height; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +static int DirectDraw_BltFastStub4( LPDIRECTDRAWSURFACE7 dstsurf, DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 srcsurf, LPRECT srcrect ) +{ + int result = 0; + HRESULT ddrval; + + while( ( ddrval = IDirectDrawSurface7_BltFast( dstsurf, x, y, srcsurf, srcrect, DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT ) ) != DD_OK ) + { + if (ddrval == DDERR_SURFACELOST) + { + ddrval = restoresurface ( dstsurf ); + if (ddrval != DD_OK) + { + break; + } + } + else if (ddrval != DDERR_SURFACEBUSY) + { + write_log("BltFastStub7(): DirectDrawSURFACE7_BltFast() failed with %s\n", DXError (ddrval)); + break; + } + } + if( ddrval == DD_OK ) + { + result = 1; + } + return result; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +int DirectDraw_BltFast( surface_type_e dsttype, DWORD left, DWORD top, surface_type_e srctype, LPRECT srcrect ) +{ + int result; + + LPDIRECTDRAWSURFACE7 lpDDS4_dst, lpDDS4_src; + if( dsttype == primary_surface ) + { + lpDDS4_dst = DirectDrawState.primary.surface; + } + else + { + lpDDS4_dst = DirectDrawState.secondary.surface; + } + if( srctype == primary_surface ) + { + lpDDS4_src = DirectDrawState.primary.surface; + } + else + { + lpDDS4_src = DirectDrawState.secondary.surface; + } + result = DirectDraw_BltFastStub4( lpDDS4_dst, left, top, lpDDS4_src, srcrect ); + return result; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +static int DirectDraw_BltStub( LPDIRECTDRAWSURFACE7 dstsurf, LPRECT dstrect, LPDIRECTDRAWSURFACE7 srcsurf, LPRECT srcrect, DWORD flags, LPDDBLTFX ddbltfx ) +{ + int result = 0, errcnt = 0; + HRESULT ddrval; + + while( ( ddrval = IDirectDrawSurface7_Blt( dstsurf, dstrect, srcsurf, srcrect, flags, ddbltfx ) ) != DD_OK ) + { + if (ddrval == DDERR_SURFACELOST) + { + if (errcnt > 10) + break; + errcnt++; + ddrval = restoresurface ( dstsurf ); + if (ddrval != DD_OK) + { + break; + } + } + else if (ddrval != DDERR_SURFACEBUSY) + { + write_log("BltStub(): DirectDrawSURFACE7_Blt() failed with %s\n", DXError (ddrval)); + break; + } +#if 0 + else + { + write_log( "Blt() failed - %s\n", DXError (ddrval)); + result = 0; + break; + } +#endif + } + if( ddrval == DD_OK ) + { + result = 1; + } + return result; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ + +int DirectDraw_Flip( int wait ) +{ + int result = 0; + HRESULT ddrval = DD_OK; + DWORD flags = DDFLIP_WAIT; + int start = read_processor_time(); + static int skip; + + if( DirectDrawState.flipping == triple_buffer ) + { + if (!currprefs.gfx_afullscreen && !currprefs.gfx_vsync) { + ddrval = IDirectDrawSurface7_Flip( DirectDrawState.primary.surface, NULL, flags | DDFLIP_NOVSYNC); + } else if (currprefs.gfx_vsync) { + if (vblank_skip >= 0) { + skip++; + if (vblank_skip > skip) { + ddrval = IDirectDrawSurface7_Flip( DirectDrawState.primary.surface, NULL, flags | DDFLIP_NOVSYNC); + } else { + skip = 0; + ddrval = IDirectDrawSurface7_Flip( DirectDrawState.primary.surface, NULL, flags ); + idletime += read_processor_time() - start; + } + } else { + if (flipinterval_supported) { + ddrval = IDirectDrawSurface7_Flip( DirectDrawState.primary.surface, NULL, flags | DDFLIP_INTERVAL2 ); + idletime += read_processor_time() - start; + } else { + ddrval = IDirectDrawSurface7_Flip( DirectDrawState.primary.surface, NULL, flags ); + idletime += read_processor_time() - start; + result = DirectDraw_BltFast( tertiary_surface, 0, 0, primary_surface, NULL ); + start = read_processor_time(); + ddrval = IDirectDrawSurface7_Flip( DirectDrawState.primary.surface, NULL, flags ); + idletime += read_processor_time() - start; + } + } + } else { + ddrval = IDirectDrawSurface7_Flip( DirectDrawState.primary.surface, NULL, flags ); + } + } else if( DirectDrawState.flipping == double_buffer ) { + if (!currprefs.gfx_afullscreen && !currprefs.gfx_vsync) { + ddrval = IDirectDrawSurface7_Flip( DirectDrawState.primary.surface, NULL, flags | DDFLIP_NOVSYNC); + } else { + ddrval = IDirectDrawSurface7_Flip( DirectDrawState.primary.surface, NULL, flags ); + idletime += read_processor_time() - start; + } + } else { + return 1; + } + if( ddrval == DD_OK ) + result = 1; + else + write_log("FLIP: DirectDrawSurface_Flip() failed with %s\n", DXError (ddrval)); + return result; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +int DirectDraw_Blt( surface_type_e dsttype, LPRECT dstrect, + surface_type_e srctype, LPRECT srcrect, + DWORD flags, LPDDBLTFX fx ) +{ + int result; + + LPDIRECTDRAWSURFACE7 lpDDS4_dst, lpDDS4_src; + + if( dsttype == primary_surface ) + { + if( DirectDrawState.isoverlay ) + lpDDS4_dst = DirectDrawState.overlay.surface; + else + lpDDS4_dst = DirectDrawState.primary.surface; + } + else if( dsttype == secondary_surface ) + { + lpDDS4_dst = DirectDrawState.secondary.surface; + } + else if( dsttype == tertiary_surface ) + { + lpDDS4_dst = DirectDrawState.tertiary.surface; + } + else + { + lpDDS4_dst = DirectDrawState.overlay.surface; + } + + if( srctype == primary_surface ) + { + lpDDS4_src = DirectDrawState.primary.surface; + } + else if( srctype == secondary_surface ) + { + lpDDS4_src = DirectDrawState.secondary.surface; + } + else if( srctype == tertiary_surface ) + { + lpDDS4_src = DirectDrawState.tertiary.surface; + } + else if( srctype == overlay_surface ) + { + lpDDS4_src = DirectDrawState.overlay.surface; + } + else + { + lpDDS4_src = NULL; /* For using BltStub to do rect-fills */ + } + result = DirectDraw_BltStub( lpDDS4_dst, dstrect, lpDDS4_src, srcrect, flags, fx ); + return result; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +HRESULT DirectDraw_WaitForVerticalBlank( DWORD flags ) +{ + HRESULT result; + result = IDirectDraw7_WaitForVerticalBlank( DirectDrawState.directdraw.dd, flags, NULL ); + return result; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +HRESULT DirectDraw_EnumDisplayModes( DWORD flags, LPDDENUMMODESCALLBACK2 callback ) +{ + HRESULT result; + result = IDirectDraw7_EnumDisplayModes( DirectDrawState.directdraw.dd, flags, NULL, NULL, callback ); + return result; +} + +HRESULT DirectDraw_EnumDisplays(LPDDENUMCALLBACKEX callback ) +{ + HRESULT result; + result = DirectDrawEnumerateEx (callback, 0, DDENUM_DETACHEDSECONDARYDEVICES | DDENUM_ATTACHEDSECONDARYDEVICES); + return result; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +HRESULT DirectDraw_FlipToGDISurface( void ) +{ + HRESULT result = DDERR_GENERIC; + if( DirectDrawState.initialized ) + { + result = IDirectDraw7_FlipToGDISurface( DirectDrawState.directdraw.dd ); + } + return result; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +HRESULT DirectDraw_GetDC( HDC *hdc, surface_type_e surface ) +{ + HRESULT result = ~DD_OK; + if( surface == primary_surface ) + result = IDirectDrawSurface7_GetDC( DirectDrawState.primary.surface, hdc ); + else if (surface == overlay_surface) + result = IDirectDrawSurface7_GetDC( DirectDrawState.overlay.surface, hdc ); + else if (surface == secondary_surface) + result = IDirectDrawSurface7_GetDC( DirectDrawState.secondary.surface, hdc ); + return result; +} + +/* + * FUNCTION: + * + * PURPOSE: + * + * PARAMETERS: + * + * RETURNS: + * + * NOTES: + * + * HISTORY: + * 1999.08.02 Brian King Creation + * + */ +HRESULT DirectDraw_ReleaseDC( HDC hdc, surface_type_e surface ) +{ + HRESULT result; + if( surface == primary_surface ) + result = IDirectDrawSurface7_ReleaseDC( DirectDrawState.primary.surface, hdc ); + else if (surface == overlay_surface) + result = IDirectDrawSurface7_ReleaseDC( DirectDrawState.overlay.surface, hdc ); + else + result = IDirectDrawSurface7_ReleaseDC( DirectDrawState.secondary.surface, hdc ); + return result; +} + +extern int display_change_requested; + +HRESULT DirectDraw_UpdateOverlay( RECT sr, RECT dr ) +{ + HRESULT result = DD_OK; + + if (DirectDrawState.isoverlay && DirectDrawState.overlay.surface) + { + if ((drivercaps.dwCaps & DDCAPS_ALIGNBOUNDARYSRC) && drivercaps.dwAlignBoundarySrc) + sr.left = (sr.left + drivercaps.dwAlignBoundarySrc / 2) & ~(drivercaps.dwAlignBoundarySrc - 1); + if ((drivercaps.dwCaps & DDCAPS_ALIGNSIZESRC) && drivercaps.dwAlignSizeSrc) + sr.right = sr.left + (sr.right - sr.left + drivercaps.dwAlignSizeSrc / 2) & ~(drivercaps.dwAlignSizeSrc - 1); + if ((drivercaps.dwCaps & DDCAPS_ALIGNBOUNDARYDEST) && drivercaps.dwAlignBoundaryDest) + dr.left = (dr.left + drivercaps.dwAlignBoundaryDest / 2) & ~(drivercaps.dwAlignBoundaryDest - 1); + if ((drivercaps.dwCaps & DDCAPS_ALIGNSIZEDEST) && drivercaps.dwAlignSizeDest) + dr.right = dr.left + (dr.right - dr.left) & ~(drivercaps.dwAlignSizeDest - 1); + result = IDirectDrawSurface7_UpdateOverlay( DirectDrawState.overlay.surface, &sr, DirectDrawState.primary.surface, &dr, overlayflags, &overlayfx); + + } + if (result != DD_OK) { + if (result == DDERR_SURFACELOST) + display_change_requested++; + write_log ("UpdateOverlay failed %s\n", DXError (result)); + } + return DD_OK; +} + +char *outGUID (GUID *guid) +{ + static char gb[64]; + if (guid == NULL) + return "NULL"; + sprintf(gb, "%08.8X-%04.8X-%04.8X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X", + guid->Data1, guid->Data2, guid->Data3, + guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], + guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); + return gb; +} + + diff --git a/od-win32/dxwrap.h b/od-win32/dxwrap.h new file mode 100755 index 00000000..9ae22ddf --- /dev/null +++ b/od-win32/dxwrap.h @@ -0,0 +1,249 @@ +#ifndef __DXWRAP_H__ +#define __DXWRAP_H__ + +#include "ddraw.h" + +struct ScreenResolution +{ + uae_u32 width; /* in pixels */ + uae_u32 height; /* in pixels */ +}; + +#define MAX_PICASSO_MODES 300 +#define MAX_REFRESH_RATES 100 +struct PicassoResolution +{ + struct Resolutions *next; + struct ScreenResolution res; + int depth; /* depth in bytes-per-pixel */ + int refresh[MAX_REFRESH_RATES]; /* refresh-rates in Hz */ + char name[25]; + /* Bit mask of RGBFF_xxx values. */ + uae_u32 colormodes; +}; +extern struct PicassoResolution *DisplayModes; +extern GUID *displayGUID; + +#define MAX_DISPLAYS 10 +struct MultiDisplay { + int primary, disabled; + GUID guid; + char *name; + struct PicassoResolution *DisplayModes; +}; +extern struct MultiDisplay Displays[MAX_DISPLAYS]; + +typedef enum { + BLIT_FALSE, + BLIT_NOR, + BLIT_ONLYDST, + BLIT_NOTSRC, + BLIT_ONLYSRC, + BLIT_NOTDST, + BLIT_EOR, + BLIT_NAND, + BLIT_AND, + BLIT_NEOR, + BLIT_DST, + BLIT_NOTONLYSRC, + BLIT_SRC, + BLIT_NOTONLYDST, + BLIT_OR, + BLIT_TRUE, + BLIT_LAST +} BLIT_OPCODE; + +/* Types for RGBFormat used */ +typedef enum { + RGBFB_NONE, /* no valid RGB format (should not happen) */ + RGBFB_CLUT, /* palette mode, set colors when opening screen using + tags or use SetRGB32/LoadRGB32(...) */ + RGBFB_R8G8B8, /* TrueColor RGB (8 bit each) */ + RGBFB_B8G8R8, /* TrueColor BGR (8 bit each) */ + RGBFB_R5G6B5PC, /* HiColor16 (5 bit R, 6 bit G, 5 bit B), + format: gggbbbbbrrrrrggg */ + RGBFB_R5G5B5PC, /* HiColor15 (5 bit each), format: gggbbbbb0rrrrrgg */ + RGBFB_A8R8G8B8, /* 4 Byte TrueColor ARGB (A unused alpha channel) */ + RGBFB_A8B8G8R8, /* 4 Byte TrueColor ABGR (A unused alpha channel) */ + RGBFB_R8G8B8A8, /* 4 Byte TrueColor RGBA (A unused alpha channel) */ + RGBFB_B8G8R8A8, /* 4 Byte TrueColor BGRA (A unused alpha channel) */ + RGBFB_R5G6B5, /* HiColor16 (5 bit R, 6 bit G, 5 bit B), + format: rrrrrggggggbbbbb */ + RGBFB_R5G5B5, /* HiColor15 (5 bit each), format: 0rrrrrgggggbbbbb */ + RGBFB_B5G6R5PC, /* HiColor16 (5 bit R, 6 bit G, 5 bit B), + format: gggrrrrrbbbbbggg */ + RGBFB_B5G5R5PC, /* HiColor15 (5 bit each), format: gggrrrrr0bbbbbbgg */ + + /* By now, the following formats are for use with a hardware window only + (bitmap operations may be implemented incompletely) */ + + RGBFB_Y4U2V2, /* 2 Byte TrueColor YUV (CCIR recommendation CCIR601). + Each two-pixel unit is stored as one longword + containing luminance (Y) for each of the two pixels, + and chrominance (U,V) for alternate pixels. + The missing chrominance values are generated by + interpolation. (Y1-U0-Y0-V0) */ + RGBFB_Y4U1V1, /* 1 Byte TrueColor ACCUPAK. Four adjacent pixels form + a packet of 5 bits Y (luminance) each pixel and 6 bits + U and V (chrominance) shared by the four pixels */ + + RGBFB_MaxFormats +} RGBFTYPE; + +#define RGBFF_NONE (1< + +/* these are deadly (but I think allowed on the Amiga): */ +#define NUM_EVILCHARS 7 +static char evilchars[NUM_EVILCHARS] = { '\\', '*', '?', '\"', '<', '>', '|' }; + +/* Return nonzero for any name we can't create on the native filesystem. */ +int fsdb_name_invalid (const char *n) +{ + int i; + char a = n[0]; + char b = (a == '\0' ? a : n[1]); + char c = (b == '\0' ? b : n[2]); + char d = (c == '\0' ? c : n[3]); + int l = strlen (n), ll; + + if (a >= 'a' && a <= 'z') + a -= 32; + if (b >= 'a' && b <= 'z') + b -= 32; + if (c >= 'a' && c <= 'z') + c -= 32; + + /* reserved dos devices */ + ll = 0; + if (a == 'A' && b == 'U' && c == 'X') ll = 3; /* AUX */ + if (a == 'C' && b == 'O' && c == 'N') ll = 3; /* CON */ + if (a == 'P' && b == 'R' && c == 'N') ll = 3; /* PRN */ + if (a == 'N' && b == 'U' && c == 'L') ll = 3; /* NUL */ + if (a == 'L' && b == 'P' && c == 'T' && (d >= '0' && d <= '9')) ll = 4; /* LPT# */ + if (a == 'C' && b == 'O' && c == 'M' && (d >= '0' && d <= '9')) ll = 4; /* COM# */ + /* AUX.anything, CON.anything etc.. are also illegal names */ + if (ll && (l == ll || (l > ll && n[ll] == '.'))) + return 1; + + /* spaces and periods at the end are a no-no */ + i = l - 1; + if (n[i] == '.' || n[i] == ' ') + return 1; + + /* these characters are *never* allowed */ + for (i = 0; i < NUM_EVILCHARS; i++) { + if (strchr (n, evilchars[i]) != 0) + return 1; + } + + /* the reserved fsdb filename */ + if (strcmp (n, FSDB_FILE) == 0) + return 1; + return 0; /* the filename passed all checks, now it should be ok */ +} + +uae_u32 filesys_parse_mask(uae_u32 mask) +{ + return mask ^ 0xf; +} + +int fsdb_exists (char *nname) +{ + if (GetFileAttributes(nname) == 0xFFFFFFFF) + return 0; + return 1; +} + +/* For an a_inode we have newly created based on a filename we found on the + * native fs, fill in information about this file/directory. */ +int fsdb_fill_file_attrs (a_inode *aino) +{ + int mode; + + if((mode = GetFileAttributes(aino->nname)) == 0xFFFFFFFF) { + write_log("GetFileAttributes('%s') failed! error=%d, aino=%p dir=%d\n", aino->nname,GetLastError(),aino,aino->dir); + return 0; + } + + aino->dir = (mode & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0; + aino->amigaos_mode = A_FIBF_EXECUTE | A_FIBF_READ; + if (FILE_ATTRIBUTE_ARCHIVE & mode) + aino->amigaos_mode |= A_FIBF_ARCHIVE; + if (! (FILE_ATTRIBUTE_READONLY & mode)) + aino->amigaos_mode |= A_FIBF_WRITE | A_FIBF_DELETE; + aino->amigaos_mode = filesys_parse_mask(aino->amigaos_mode); + return 1; +} + +int fsdb_set_file_attrs (a_inode *aino, int mask) +{ + struct stat statbuf; + uae_u32 mode=0, tmpmask; + + tmpmask = filesys_parse_mask(mask); + + if (stat (aino->nname, &statbuf) == -1) + return ERROR_OBJECT_NOT_AROUND; + + /* Unix dirs behave differently than AmigaOS ones. */ + /* windows dirs go where no dir has gone before... */ + if (! aino->dir) { + if ((tmpmask & (A_FIBF_READ | A_FIBF_DELETE)) == 0) + mode |= FILE_ATTRIBUTE_READONLY; + if (tmpmask & A_FIBF_ARCHIVE) + mode |= FILE_ATTRIBUTE_ARCHIVE; + else + mode &= ~FILE_ATTRIBUTE_ARCHIVE; + + SetFileAttributes(aino->nname, mode); + } + + aino->amigaos_mode = mask; + aino->dirty = 1; + return 0; +} + +/* Return nonzero if we can represent the amigaos_mode of AINO within the + * native FS. Return zero if that is not possible. */ +int fsdb_mode_representable_p (const a_inode *aino) +{ + int mask = aino->amigaos_mode; + int m1; + + if (aino->dir) + return aino->amigaos_mode == 0; + + /* P or S set, or E or R clear, means we can't handle it. */ + if (mask & (A_FIBF_SCRIPT | A_FIBF_PURE | A_FIBF_EXECUTE | A_FIBF_READ)) + return 0; + m1 = A_FIBF_DELETE | A_FIBF_WRITE; + /* If it's rwed, we are OK... */ + if ((mask & m1) == 0) + return 1; + /* We can also represent r-e-, by setting the host's readonly flag. */ + if ((mask & m1) == m1) + return 1; + return 0; +} + +char *fsdb_create_unique_nname (a_inode *base, const char *suggestion) +{ + char *c; + char tmp[256] = "__uae___"; + int i; + + strncat (tmp, suggestion, 240); + + /* replace the evil ones... */ + for (i=0; i < NUM_EVILCHARS; i++) + while ((c = strchr (tmp, evilchars[i])) != 0) + *c = '_'; + + while ((c = strchr (tmp, '.')) != 0) + *c = '_'; + while ((c = strchr (tmp, ' ')) != 0) + *c = '_'; + + for (;;) { + char *p = build_nname (base->nname, tmp); + if (access (p, R_OK) < 0 && errno == ENOENT) { + write_log ("unique name: %s\n", p); + return p; + } + free (p); + + /* tmpnam isn't reentrant and I don't really want to hack configure + * right now to see whether tmpnam_r is available... */ + for (i = 0; i < 8; i++) { + tmp[i+8] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"[rand () % 63]; + } + } +} diff --git a/od-win32/genblitter_msvc/genblitter_msvc.vcproj b/od-win32/genblitter_msvc/genblitter_msvc.vcproj new file mode 100755 index 00000000..a2a121c0 --- /dev/null +++ b/od-win32/genblitter_msvc/genblitter_msvc.vcproj @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/od-win32/gencomp_msvc/gencomp_msvc.vcproj b/od-win32/gencomp_msvc/gencomp_msvc.vcproj new file mode 100755 index 00000000..d5b68360 --- /dev/null +++ b/od-win32/gencomp_msvc/gencomp_msvc.vcproj @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/od-win32/gencpu_msvc/gencpu_msvc.vcproj b/od-win32/gencpu_msvc/gencpu_msvc.vcproj new file mode 100755 index 00000000..7a3479be --- /dev/null +++ b/od-win32/gencpu_msvc/gencpu_msvc.vcproj @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/od-win32/hardfile_win32.c b/od-win32/hardfile_win32.c new file mode 100755 index 00000000..783a0243 --- /dev/null +++ b/od-win32/hardfile_win32.c @@ -0,0 +1,786 @@ +#define WIN32_LEAN_AND_MEAN + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "threaddep/thread.h" +#include "filesys.h" +#include "blkdev.h" + +#define hfd_log write_log + +#ifdef WINDDK +#include +#include +#include +#include // Guid definition +#include // Device guids +#include // for SetupDiXxx functions. +#include // for SetupDiXxx functions. +#endif + +struct uae_driveinfo { + uae_u64 offset2; + uae_u64 size2; + char vendor_id[128]; + char product_id[128]; + char product_rev[128]; + char product_serial[128]; + char device_name[256]; + char device_path[2048]; + uae_u64 size; + uae_u64 offset; + int bytespersector; +}; + +#define CACHE_SIZE 16384 +#define CACHE_FLUSH_TIME 5 + +/* safety check: only accept drives that: + * - contain RDSK in block 0 + * - block 0 is zeroed + */ + +int harddrive_dangerous, do_rdbdump; +static int num_drives; +static struct uae_driveinfo uae_drives[MAX_FILESYSTEM_UNITS]; + +static void rdbdump (HANDLE *h, uae_u64 offset, uae_u8 *buf, int blocksize) +{ + static int cnt = 1; + int i, blocks; + char name[100]; + FILE *f; + + blocks = (buf[132] << 24) | (buf[133] << 16) | (buf[134] << 8) | (buf[135] << 0); + if (blocks < 0 || blocks > 100000) + return; + sprintf (name, "rdb_dump_%d.rdb", cnt); + f = fopen (name, "wb"); + if (!f) + return; + for (i = 0; i <= blocks; i++) { + DWORD outlen, high; + high = (DWORD)(offset >> 32); + if (SetFilePointer (h, (DWORD)offset, &high, FILE_BEGIN) == INVALID_FILE_SIZE) + break; + ReadFile (h, buf, blocksize, &outlen, NULL); + fwrite (buf, 1, blocksize, f); + offset += blocksize; + } + fclose (f); + cnt++; +} + +static int safetycheck (HANDLE *h, uae_u64 offset, uae_u8 *buf, int blocksize) +{ + int i, j, blocks = 63, empty = 1; + DWORD outlen, high; + + for (j = 0; j < blocks; j++) { + high = (DWORD)(offset >> 32); + if (SetFilePointer (h, (DWORD)offset, &high, FILE_BEGIN) == INVALID_FILE_SIZE) { + write_log ("hd ignored, SetFilePointer failed, error %d\n", GetLastError()); + return 0; + } + memset (buf, 0xaa, blocksize); + ReadFile (h, buf, blocksize, &outlen, NULL); + if (outlen != blocksize) { + write_log ("hd ignored, read error %d!\n", GetLastError()); + return 0; + } + if (!memcmp (buf, "RDSK", 4)) { + if (do_rdbdump) + rdbdump (h, offset, buf, blocksize); + write_log ("hd accepted (rdb detected at block %d)\n", j); + return 1; + } + if (j == 0) { + for (i = 0; i < blocksize; i++) { + if (buf[i]) + empty = 0; + } + } + offset += blocksize; + } + if (harddrive_dangerous != 0x1234dead) { + if (!empty) { + write_log ("hd ignored, not empty and no RDB detected\n"); + return 0; + } + write_log ("hd accepted (empty)\n"); + return 1; + } + gui_message ("WARNING: Non-empty or Amiga formatted\n" + "harddrive detected and safety test was disabled\n\n" + "Harddrives marked with 'HD_*_' are not empty\n"); + return 2; +} + +static void trim (char *s) +{ + while(strlen(s) > 0 && s[strlen(s) - 1] == ' ') + s[strlen(s) - 1] = 0; +} + +int isharddrive (char *name) +{ + int i; + + for (i = 0; i < num_drives; i++) { + if (!strcmp (uae_drives[i].device_name, name)) + return i; + } + return -1; +} + +int hdf_open (struct hardfiledata *hfd, char *name) +{ + HANDLE h = INVALID_HANDLE_VALUE; + int i; + struct uae_driveinfo *udi; + + hdf_close (hfd); + hfd->cache = VirtualAlloc (NULL, CACHE_SIZE, MEM_COMMIT, PAGE_READWRITE); + hfd->cache_valid = 0; + if (!hfd->cache) { + write_log ("VirtualAlloc(%d) failed, error %d\n", CACHE_SIZE, GetLastError()); + return 0; + } + hfd_log ("hfd open: '%s'\n", name); + if (strlen (name) > 4 && !memcmp (name, "HD_", 3)) { + hdf_init (); + i = isharddrive (name); + if (i >= 0) { + udi = &uae_drives[i]; + hfd->flags = 1; + h = CreateFile (udi->device_path, GENERIC_READ | (hfd->readonly ? 0 : GENERIC_WRITE), FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_NO_BUFFERING, NULL); + hfd->handle = h; + if (h == INVALID_HANDLE_VALUE) { + hdf_close (hfd); + return 0; + } + strncpy (hfd->vendor_id, udi->vendor_id, 8); + strncpy (hfd->product_id, udi->product_id, 16); + strncpy (hfd->product_rev, udi->product_rev, 4); + hfd->offset2 = hfd->offset = udi->offset; + hfd->size2 = hfd->size = udi->size; + if (hfd->offset != udi->offset2 || hfd->size != udi->size2) { + gui_message ("Harddrive safety check: fatal memory corruption\n"); + abort (); + } + hfd->blocksize = udi->bytespersector; + if (hfd->offset == 0) { + if (!safetycheck (hfd->handle, 0, hfd->cache, hfd->blocksize)) { + hdf_close (hfd); + return 0; + } + } + } + } else { + h = CreateFile (name, GENERIC_READ | (hfd->readonly ? 0 : GENERIC_WRITE), hfd->readonly ? FILE_SHARE_READ : 0, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); + hfd->handle = h; + i = strlen (name) - 1; + while (i >= 0) { + if ((i > 0 && (name[i - 1] == '/' || name[i - 1] == '\\')) || i == 0) { + strcpy (hfd->vendor_id, "UAE"); + strncpy (hfd->product_id, name + i, 15); + strcpy (hfd->product_rev, "0.2"); + break; + } + i--; + } + if (h != INVALID_HANDLE_VALUE) { + DWORD ret, low, high; + high = 0; + ret = SetFilePointer (h, 0, &high, FILE_END); + if (ret == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) { + hdf_close (hfd); + return 0; + } + low = GetFileSize (h, &high); + if (low == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) { + hdf_close (hfd); + return 0; + } + low &= ~(hfd->blocksize - 1); + hfd->size = hfd->size2 = ((uae_u64)high << 32) | low; + } else { + write_log ("HDF '%s' failed to open. error = %d\n", name, GetLastError ()); + } + } + hfd->handle = h; + if (hfd->handle != INVALID_HANDLE_VALUE) { + hfd_log ("HDF '%s' opened succesfully, handle=%p\n", name, hfd->handle); + return 1; + } + hdf_close (hfd); + return 0; +} + +void hdf_close (struct hardfiledata *hfd) +{ + hfd_log ("close handle=%p\n", hfd->handle); + hfd->flags = 0; + if (hfd->handle && hfd->handle != INVALID_HANDLE_VALUE) + CloseHandle (hfd->handle); + hfd->handle = 0; + if (hfd->cache) + VirtualFree (hfd->cache, 0, MEM_RELEASE); + hfd->cache = 0; + hfd->cache_valid = 0; +} + +int hdf_dup (struct hardfiledata *hfd, void *src) +{ + HANDLE duphandle; + if (src == 0 || src == INVALID_HANDLE_VALUE) + return 0; + if (!DuplicateHandle (GetCurrentProcess(), src, GetCurrentProcess() , &duphandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) + return 0; + hfd->handle = duphandle; + hfd->cache = VirtualAlloc (NULL, CACHE_SIZE, MEM_COMMIT, PAGE_READWRITE); + hfd->cache_valid = 0; + if (!hfd->cache) { + hdf_close (hfd); + return 0; + } + hfd_log ("dup handle %p->%p\n", src, duphandle); + return 1; +} + +static int hdf_seek (struct hardfiledata *hfd, uae_u64 offset) +{ + DWORD high, ret; + + if (hfd->offset != hfd->offset2 || hfd->size != hfd->size2) { + gui_message ("hd: memory corruption detected in seek"); + abort (); + } + if (offset >= hfd->size) { + gui_message ("hd: tried to seek out of bounds! (%I64X >= %I64X)\n", offset, hfd->size); + abort (); + } + offset += hfd->offset; + if (offset & (hfd->blocksize - 1)) { + gui_message ("hd: poscheck failed, offset not aligned to blocksize! (%I64X & %04.4X = %04.4X)\n", offset, hfd->blocksize, offset & (hfd->blocksize - 1)); + abort (); + } + high = (DWORD)(offset >> 32); + ret = SetFilePointer (hfd->handle, (DWORD)offset, &high, FILE_BEGIN); + if (ret == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) + return -1; + return 0; +} + +static void poscheck (struct hardfiledata *hfd, int len) +{ + DWORD high, ret, err; + uae_u64 pos; + + if (hfd->offset != hfd->offset2 || hfd->size != hfd->size2) { + gui_message ("hd: memory corruption detected in poscheck"); + abort (); + } + high = 0; + ret = SetFilePointer (hfd->handle, 0, &high, FILE_CURRENT); + err = GetLastError (); + if (ret == INVALID_FILE_SIZE && err != NO_ERROR) { + gui_message ("hd: poscheck failed. seek failure, error %d", err); + abort (); + } + if (len < 0) { + gui_message ("hd: poscheck failed, negative length! (%d)", len); + abort (); + } + pos = ((uae_u64)high) << 32 | ret; + if (pos < hfd->offset) { + gui_message ("hd: poscheck failed, offset out of bounds! (%I64d < %I64d)", pos, hfd->offset); + abort (); + } + if (pos >= hfd->offset + hfd->size || pos >= hfd->offset + hfd->size + len) { + gui_message ("hd: poscheck failed, offset out of bounds! (%I64d >= %I64d, LEN=%d)", pos, hfd->offset + hfd->size, len); + abort (); + } + if (pos & (hfd->blocksize - 1)) { + gui_message ("hd: poscheck failed, offset not aligned to blocksize! (%I64X & %04.4X = %04.4X\n", pos, hfd->blocksize, pos & hfd->blocksize); + abort (); + } +} + +static int isincache (struct hardfiledata *hfd, uae_u64 offset, int len) +{ + if (!hfd->cache_valid) + return -1; + if (offset >= hfd->cache_offset && offset + len <= hfd->cache_offset + CACHE_SIZE) + return (int)(offset - hfd->cache_offset); + return -1; +} + +#if 0 +void hfd_flush_cache (struct hardfiledata *hfd, int now) +{ + DWORD outlen = 0; + if (!hfd->cache_needs_flush || !hfd->cache_valid) + return; + if (now || time (NULL) > hfd->cache_needs_flush + CACHE_FLUSH_TIME) { + hdf_log ("flushed %d %d %d\n", now, time(NULL), hfd->cache_needs_flush); + hdf_seek (hfd, hfd->cache_offset); + poscheck (hfd, CACHE_SIZE); + WriteFile (hfd->handle, hfd->cache, CACHE_SIZE, &outlen, NULL); + hfd->cache_needs_flush = 0; + } +} +#endif + +#if 0 +int hdf_read (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) +{ + DWORD outlen = 0; + hfd->cache_valid = 0; + hdf_seek (hfd, offset); + poscheck (hfd, len); + ReadFile (hfd->handle, hfd->cache, len, &outlen, NULL); + memcpy (buffer, hfd->cache, len); + return outlen; +} +#endif + +int hdf_read (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) +{ + DWORD outlen = 0; + int coffset; + + if (offset == 0) + hfd->cache_valid = 0; + coffset = isincache (hfd, offset, len); + if (coffset >= 0) { + memcpy (buffer, hfd->cache + coffset, len); + return len; + } + hfd->cache_offset = offset; + if (offset + CACHE_SIZE > hfd->offset + hfd->size) + hfd->cache_offset = hfd->offset + hfd->size - CACHE_SIZE; + hdf_seek (hfd, hfd->cache_offset); + poscheck (hfd, CACHE_SIZE); + ReadFile (hfd->handle, hfd->cache, CACHE_SIZE, &outlen, NULL); + hfd->cache_valid = 0; + if (outlen != CACHE_SIZE) + return 0; + hfd->cache_valid = 1; + coffset = isincache (hfd, offset, len); + if (coffset >= 0) { + memcpy (buffer, hfd->cache + coffset, len); + return len; + } + write_log ("hdf_read: cache bug! offset=%I64d len=%d\n", offset, len); + hfd->cache_valid = 0; + return 0; +} + +int hdf_write (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) +{ + DWORD outlen = 0; + hfd->cache_valid = 0; + hdf_seek (hfd, offset); + poscheck (hfd, len); + memcpy (hfd->cache, buffer, len); + WriteFile (hfd->handle, hfd->cache, len, &outlen, NULL); + return outlen; +} + +#ifdef WINDDK + +/* see MS KB article Q264203 more more information */ + +static BOOL GetDeviceProperty(HDEVINFO IntDevInfo, DWORD Index, DWORD *index2, uae_u8 *buffer) +/*++ + +Routine Description: + + This routine enumerates the disk devices using the Device interface + GUID DiskClassGuid. Gets the Adapter & Device property from the port + driver. Then sends IOCTL through SPTI to get the device Inquiry data. + +Arguments: + + IntDevInfo - Handles to the interface device information list + + Index - Device member + +Return Value: + + TRUE / FALSE. This decides whether to continue or not + +--*/ +{ + STORAGE_PROPERTY_QUERY query; + SP_DEVICE_INTERFACE_DATA interfaceData; + PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetailData = NULL; + PSTORAGE_ADAPTER_DESCRIPTOR adpDesc; + PSTORAGE_DEVICE_DESCRIPTOR devDesc; + HANDLE hDevice = INVALID_HANDLE_VALUE; + BOOL status; + PUCHAR p; + UCHAR outBuf[20000]; + ULONG length = 0, + returned = 0, + returnedLength; + DWORD interfaceDetailDataSize = 0, + reqSize, + errorCode, + i, j; + DRIVE_LAYOUT_INFORMATION *dli; + DISK_GEOMETRY dg; + int ret = -1; + struct uae_driveinfo *udi; + char orgname[1024]; + + interfaceData.cbSize = sizeof (SP_INTERFACE_DEVICE_DATA); + + status = SetupDiEnumDeviceInterfaces ( + IntDevInfo, // Interface Device Info handle + 0, // Device Info data + (LPGUID)&DiskClassGuid, // Interface registered by driver + Index, // Member + &interfaceData // Device Interface Data + ); + + if ( status == FALSE ) { + errorCode = GetLastError(); + if ( errorCode != ERROR_NO_MORE_ITEMS ) { + write_log ("SetupDiEnumDeviceInterfaces failed with error: %d\n", errorCode); + } + ret = 0; + goto end; + } + + // + // Find out required buffer size, so pass NULL + // + + status = SetupDiGetDeviceInterfaceDetail ( + IntDevInfo, // Interface Device info handle + &interfaceData, // Interface data for the event class + NULL, // Checking for buffer size + 0, // Checking for buffer size + &reqSize, // Buffer size required to get the detail data + NULL // Checking for buffer size + ); + + // + // This call returns ERROR_INSUFFICIENT_BUFFER with reqSize + // set to the required buffer size. Ignore the above error and + // pass a bigger buffer to get the detail data + // + + if ( status == FALSE ) { + errorCode = GetLastError(); + if ( errorCode != ERROR_INSUFFICIENT_BUFFER ) { + write_log("SetupDiGetDeviceInterfaceDetail failed with error: %d\n", errorCode); + ret = 0; + goto end; + } + } + + // + // Allocate memory to get the interface detail data + // This contains the devicepath we need to open the device + // + + interfaceDetailDataSize = reqSize; + interfaceDetailData = malloc (interfaceDetailDataSize); + if ( interfaceDetailData == NULL ) { + write_log ("Unable to allocate memory to get the interface detail data.\n"); + ret = 0; + goto end; + } + interfaceDetailData->cbSize = sizeof (SP_INTERFACE_DEVICE_DETAIL_DATA); + + status = SetupDiGetDeviceInterfaceDetail ( + IntDevInfo, // Interface Device info handle + &interfaceData, // Interface data for the event class + interfaceDetailData, // Interface detail data + interfaceDetailDataSize, // Interface detail data size + &reqSize, // Buffer size required to get the detail data + NULL); // Interface device info + + if ( status == FALSE ) { + write_log("Error in SetupDiGetDeviceInterfaceDetail failed with error: %d\n", GetLastError()); + ret = 0; + goto end; + } + + // + // Now we have the device path. Open the device interface + // to send Pass Through command + + udi = &uae_drives[*index2]; + strcpy (udi->device_path, interfaceDetailData->DevicePath); + write_log ("opening device '%s'\n", udi->device_path); + hDevice = CreateFile( + interfaceDetailData->DevicePath, // device interface name + GENERIC_READ | GENERIC_WRITE, // dwDesiredAccess + FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode + NULL, // lpSecurityAttributes + OPEN_EXISTING, // dwCreationDistribution + 0, // dwFlagsAndAttributes + NULL // hTemplateFile + ); + + // + // We have the handle to talk to the device. + // So we can release the interfaceDetailData buffer + // + + free (interfaceDetailData); + interfaceDetailData = NULL; + + if (hDevice == INVALID_HANDLE_VALUE) { + write_log ("CreateFile failed with error: %d\n", GetLastError()); + ret = 1; + goto end; + } + + query.PropertyId = StorageAdapterProperty; + query.QueryType = PropertyStandardQuery; + + status = DeviceIoControl( + hDevice, + IOCTL_STORAGE_QUERY_PROPERTY, + &query, + sizeof( STORAGE_PROPERTY_QUERY ), + &outBuf, + sizeof (outBuf), + &returnedLength, + NULL + ); + if ( !status ) { + write_log("IOCTL_STORAGE_QUERY_PROPERTY failed with error code%d.\n", GetLastError()); + ret = 1; + goto end; + } + + adpDesc = (PSTORAGE_ADAPTER_DESCRIPTOR) outBuf; + query.PropertyId = StorageDeviceProperty; + query.QueryType = PropertyStandardQuery; + status = DeviceIoControl( + hDevice, + IOCTL_STORAGE_QUERY_PROPERTY, + &query, + sizeof( STORAGE_PROPERTY_QUERY ), + &outBuf, + sizeof (outBuf), + &returnedLength, + NULL); + if ( !status ) { + write_log ("IOCTL_STORAGE_QUERY_PROPERTY failed with error code %d.\n", GetLastError()); + ret = 1; + goto end; + } + devDesc = (PSTORAGE_DEVICE_DESCRIPTOR) outBuf; + p = (PUCHAR) outBuf; + if (devDesc->DeviceType != INQ_DASD && devDesc->DeviceType != INQ_ROMD && devDesc->DeviceType != INQ_OPTD) { + ret = 1; + write_log ("not a direct access device, ignored (type=%d)\n", devDesc->DeviceType); + goto end; + } + if ( devDesc->VendorIdOffset && p[devDesc->VendorIdOffset] ) { + j = 0; + for ( i = devDesc->VendorIdOffset; p[i] != (UCHAR) NULL && i < returnedLength; i++ ) + udi->vendor_id[j++] = p[i]; + } + if ( devDesc->ProductIdOffset && p[devDesc->ProductIdOffset] ) { + j = 0; + for ( i = devDesc->ProductIdOffset; p[i] != (UCHAR) NULL && i < returnedLength; i++ ) + udi->product_id[j++] = p[i]; + } + if ( devDesc->ProductRevisionOffset && p[devDesc->ProductRevisionOffset] ) { + j = 0; + for ( i = devDesc->ProductRevisionOffset; p[i] != (UCHAR) NULL && i < returnedLength; i++ ) + udi->product_rev[j++] = p[i]; + } + if ( devDesc->SerialNumberOffset && p[devDesc->SerialNumberOffset] ) { + j = 0; + for ( i = devDesc->SerialNumberOffset; p[i] != (UCHAR) NULL && i < returnedLength; i++ ) + udi->product_serial[j++] = p[i]; + } + if (udi->vendor_id[0]) + strcat (udi->device_name, udi->vendor_id); + if (udi->product_id[0]) { + if (udi->device_name[0]) + strcat (udi->device_name, " "); + strcat (udi->device_name, udi->product_id); + } + if (udi->product_rev[0]) { + if (udi->device_name[0]) + strcat (udi->device_name, " "); + strcat (udi->device_name, udi->product_rev); + } + if (udi->product_serial[0]) { + if (udi->device_name[0]) + strcat (udi->device_name, " "); + strcat (udi->device_name, udi->product_serial); + } + + write_log ("device id string: '%s'\n", udi->device_name); + if (!DeviceIoControl (hDevice, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, (void*)&dg, sizeof (dg), &returnedLength, NULL)) { + write_log ("IOCTL_DISK_GET_DRIVE_GEOMETRY failed with error code %d.\n", GetLastError()); + ret = 1; + goto end; + } + udi->bytespersector = dg.BytesPerSector; + if (dg.BytesPerSector < 512) { + write_log ("unsupported blocksize < 512 (%d)\n", dg.BytesPerSector); + ret = 1; + goto end; + } + if (dg.BytesPerSector > 2048) { + write_log ("unsupported blocksize > 2048 (%d)\n", dg.BytesPerSector); + ret = 1; + goto end; + } + udi->offset = udi->offset2 = 0; + udi->size = udi->size2 = (uae_u64)dg.BytesPerSector * (uae_u64)dg.Cylinders.QuadPart * (uae_u64)dg.TracksPerCylinder * (uae_u64)dg.SectorsPerTrack; + write_log ("device size %I64d bytes\n", udi->size); + + memset (outBuf, 0, sizeof (outBuf)); + status = DeviceIoControl(hDevice, IOCTL_DISK_GET_DRIVE_LAYOUT, NULL, 0, + &outBuf, sizeof (outBuf), &returnedLength, NULL); + if (!status) { + write_log("IOCTL_DISK_GET_DRIVE_LAYOUT failed with error code%d.\n", GetLastError()); + ret = 1; + goto end; + } + strcpy (orgname, udi->device_name); + trim (orgname); + dli = (DRIVE_LAYOUT_INFORMATION*)outBuf; + if (dli->PartitionCount) { + struct uae_driveinfo *udi2 = udi; + int nonzeropart = 0; + int gotpart = 0; + write_log ("%d MBR partitions found\n", dli->PartitionCount); + for (i = 0; i < dli->PartitionCount && (*index2) < MAX_FILESYSTEM_UNITS; i++) { + PARTITION_INFORMATION *pi = &dli->PartitionEntry[i]; + if (pi->PartitionType == PARTITION_ENTRY_UNUSED) + continue; + write_log ("%d: num: %d type: %02.2X offset: %I64d size: %I64d, ", i, pi->PartitionNumber, pi->PartitionType, pi->StartingOffset.QuadPart, pi->PartitionLength.QuadPart); + if (pi->RecognizedPartition == 0) { + write_log ("unrecognized\n"); + continue; + } + nonzeropart++; + if (pi->PartitionType != 0x76) { + write_log ("type not 0x76\n"); + continue; + } + memmove (udi, udi2, sizeof (*udi)); + udi->device_name[0] = 0; + udi->offset = udi->offset2 = pi->StartingOffset.QuadPart; + udi->size = udi->size2 = pi->PartitionLength.QuadPart; + write_log ("used\n"); + if (safetycheck (hDevice, udi->offset, buffer, dg.BytesPerSector)) { + sprintf (udi->device_name, "HD_P#%d_%s", pi->PartitionNumber, orgname); + udi++; + (*index2)++; + } + gotpart = 1; + } + if (!nonzeropart) { + write_log ("empty MBR partition table detected, checking for RDB\n"); + } else if (!gotpart) { + write_log ("non-empty MBR partition table detected, doing RDB check anyway\n"); + } else if (harddrive_dangerous != 0x1234dead) { + ret = 1; + goto end; + } + } else { + write_log ("no MBR partition table detected, checking for RDB\n"); + } + + i = safetycheck (hDevice, 0, buffer, dg.BytesPerSector); + if (!i) { + ret = 1; + goto end; + } + + write_log ("device accepted, start=%I64d, size=%I64d, block=%d\n", udi->offset, udi->size, udi->bytespersector); + if (i > 1) + sprintf (udi->device_name, "HD_*_%s", orgname); + else + sprintf (udi->device_name, "HD_%s", orgname); + while (isharddrive (udi->device_name) >= 0) + strcat (udi->device_name, "_"); + (*index2)++; +end: + free (interfaceDetailData); + if (hDevice != INVALID_HANDLE_VALUE) + CloseHandle (hDevice); + return ret; +} +#endif + +int hdf_init (void) +{ +#ifdef WINDDK + HDEVINFO hIntDevInfo; +#endif + DWORD index = 0, index2 = 0; + uae_u8 *buffer; + static int done; + + if (done) + return num_drives; + done = 1; + num_drives = 0; +#ifdef WINDDK + buffer = VirtualAlloc (NULL, 512, MEM_COMMIT, PAGE_READWRITE); + if (buffer) { + memset (uae_drives, 0, sizeof (uae_drives)); + num_drives = 0; + hIntDevInfo = SetupDiGetClassDevs ((LPGUID)&DiskClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE); + if (hIntDevInfo != INVALID_HANDLE_VALUE) { + while (index < MAX_FILESYSTEM_UNITS) { + memset (uae_drives + index2, 0, sizeof (struct uae_driveinfo)); + if (!GetDeviceProperty (hIntDevInfo, index, &index2, buffer)) + break; + index++; + num_drives = index2; + } + SetupDiDestroyDeviceInfoList(hIntDevInfo); + } + VirtualFree (buffer, 0, MEM_RELEASE); + } + num_drives = index2; + write_log ("Drive scan result: %d Amiga formatted drives detected\n", num_drives); +#endif + return num_drives; +} + +int hdf_getnumharddrives (void) +{ + return num_drives; +} + +char *hdf_getnameharddrive (int index, int flags) +{ + static char name[512]; + char tmp[32]; + uae_u64 size = uae_drives[index].size; + + if (flags & 1) { + if (size >= 1024 * 1024 * 1024) + sprintf (tmp, "%.1fG", ((double)(uae_u32)(size / (1024 * 1024))) / 1024.0); + else + sprintf (tmp, "%.1fM", ((double)(uae_u32)(size / (1024))) / 1024.0); + sprintf (name, "%s (%s)", uae_drives[index].device_name, tmp); + return name; + } + return uae_drives[index].device_name; +} + + + diff --git a/od-win32/hq2x32 b/od-win32/hq2x32 new file mode 100755 index 00000000..e69de29b diff --git a/od-win32/hq2x32.asm b/od-win32/hq2x32.asm new file mode 100755 index 00000000..28b769d5 --- /dev/null +++ b/od-win32/hq2x32.asm @@ -0,0 +1,1933 @@ +;hq2x filter +;---------------------------------------------------------- +;Copyright (C) 2003 MaxSt ( maxst@hiend3d.com ) +; +;This program is free software; you can redistribute it and/or +;modify it under the terms of the GNU General Public License +;as published by the Free Software Foundation; either +;version 2 of the License, or (at your option) any later +;version. +; +;This program is distributed in the hope that it will be useful, +;but WITHOUT ANY WARRANTY; without even the implied warranty of +;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;GNU General Public License for more details. +; +;You should have received a copy of the GNU General Public License +;along with this program; if not, write to the Free Software +;Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +GLOBAL _hq2x_32 + +EXTERN _LUT16to32 +EXTERN _RGBtoYUV + +SECTION .bss +linesleft resd 1 +xcounter resd 1 +cross resd 1 +nextline resd 1 +prevline resd 1 +w1 resd 1 +w2 resd 1 +w3 resd 1 +w4 resd 1 +w5 resd 1 +w6 resd 1 +w7 resd 1 +w8 resd 1 +w9 resd 1 +c1 resd 1 +c2 resd 1 +c3 resd 1 +c4 resd 1 +c5 resd 1 +c6 resd 1 +c7 resd 1 +c8 resd 1 +c9 resd 1 + +SECTION .data + +reg_blank dd 0,0 +const3 dd 0x00030003,0x00000003 +const5 dd 0x00050005,0x00000005 +const6 dd 0x00060006,0x00000006 +const14 dd 0x000E000E,0x0000000E +threshold dd 0x00300706,0x00000000 + +SECTION .text + +%macro TestDiff 2 + xor ecx,ecx + mov edx,[%1] + cmp edx,[%2] + je %%fin + mov ecx,_RGBtoYUV + movd mm1,[ecx+edx*4] + movq mm5,mm1 + mov edx,[%2] + movd mm2,[ecx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd ecx,mm1 +%%fin: +%endmacro + +%macro DiffOrNot 4 + TestDiff %1,%2 + test ecx,ecx + jz %%same + %3 + jmp %%fin +%%same: + %4 +%%fin +%endmacro + +%macro DiffOrNot 6 + TestDiff %1,%2 + test ecx,ecx + jz %%same + %3 + %4 + jmp %%fin +%%same: + %5 + %6 +%%fin +%endmacro + +%macro DiffOrNot 8 + TestDiff %1,%2 + test ecx,ecx + jz %%same + %3 + %4 + %5 + jmp %%fin +%%same: + %6 + %7 + %8 +%%fin +%endmacro + +%macro DiffOrNot 10 + TestDiff %1,%2 + test ecx,ecx + jz %%same + %3 + %4 + %5 + %6 + jmp %%fin +%%same: + %7 + %8 + %9 + %10 +%%fin +%endmacro + +%macro Interp1 3 + mov edx,%2 + shl edx,2 + add edx,%3 + sub edx,%2 + shr edx,2 + mov %1,edx +%endmacro + +%macro Interp2 4 + mov edx,%2 + shl edx,1 + add edx,%3 + add edx,%4 + shr edx,2 + mov %1,edx +%endmacro + +%macro Interp5 3 + mov edx,%2 + add edx,%3 + shr edx,1 + mov %1,edx +%endmacro + +%macro Interp6 3 + movd mm1, eax + movd mm2, %2 + movd mm3, %3 + punpcklbw mm1, [reg_blank] + punpcklbw mm2, [reg_blank] + punpcklbw mm3, [reg_blank] + pmullw mm1, [const5] + psllw mm2, 1 + paddw mm1, mm3 + paddw mm1, mm2 + psrlw mm1, 3 + packuswb mm1, [reg_blank] + movd %1, mm1 +%endmacro + +%macro Interp7 3 + movd mm1, eax + movd mm2, %2 + movd mm3, %3 + punpcklbw mm1, [reg_blank] + punpcklbw mm2, [reg_blank] + punpcklbw mm3, [reg_blank] + pmullw mm1, [const6] + paddw mm2, mm3 + paddw mm1, mm2 + psrlw mm1, 3 + packuswb mm1, [reg_blank] + movd %1, mm1 +%endmacro + +%macro Interp9 3 + movd mm1, eax + movd mm2, %2 + movd mm3, %3 + punpcklbw mm1, [reg_blank] + punpcklbw mm2, [reg_blank] + punpcklbw mm3, [reg_blank] + psllw mm1, 1 + paddw mm2, mm3 + pmullw mm2, [const3] + paddw mm1, mm2 + psrlw mm1, 3 + packuswb mm1, [reg_blank] + movd %1, mm1 +%endmacro + +%macro Interp10 3 + movd mm1, eax + movd mm2, %2 + movd mm3, %3 + punpcklbw mm1, [reg_blank] + punpcklbw mm2, [reg_blank] + punpcklbw mm3, [reg_blank] + pmullw mm1, [const14] + paddw mm2, mm3 + paddw mm1, mm2 + psrlw mm1, 4 + packuswb mm1, [reg_blank] + movd %1, mm1 +%endmacro + +%macro PIXEL00_0 0 + mov [edi],eax +%endmacro + +%macro PIXEL00_10 0 + Interp1 [edi],eax,[c1] +%endmacro + +%macro PIXEL00_11 0 + Interp1 [edi],eax,[c4] +%endmacro + +%macro PIXEL00_12 0 + Interp1 [edi],eax,[c2] +%endmacro + +%macro PIXEL00_20 0 + Interp2 [edi],eax,[c4],[c2] +%endmacro + +%macro PIXEL00_21 0 + Interp2 [edi],eax,[c1],[c2] +%endmacro + +%macro PIXEL00_22 0 + Interp2 [edi],eax,[c1],[c4] +%endmacro + +%macro PIXEL00_60 0 + Interp6 [edi],[c2],[c4] +%endmacro + +%macro PIXEL00_61 0 + Interp6 [edi],[c4],[c2] +%endmacro + +%macro PIXEL00_70 0 + Interp7 [edi],[c4],[c2] +%endmacro + +%macro PIXEL00_90 0 + Interp9 [edi],[c4],[c2] +%endmacro + +%macro PIXEL00_100 0 + Interp10 [edi],[c4],[c2] +%endmacro + +%macro PIXEL01_0 0 + mov [edi+4],eax +%endmacro + +%macro PIXEL01_10 0 + Interp1 [edi+4],eax,[c3] +%endmacro + +%macro PIXEL01_11 0 + Interp1 [edi+4],eax,[c2] +%endmacro + +%macro PIXEL01_12 0 + Interp1 [edi+4],eax,[c6] +%endmacro + +%macro PIXEL01_20 0 + Interp2 [edi+4],eax,[c2],[c6] +%endmacro + +%macro PIXEL01_21 0 + Interp2 [edi+4],eax,[c3],[c6] +%endmacro + +%macro PIXEL01_22 0 + Interp2 [edi+4],eax,[c3],[c2] +%endmacro + +%macro PIXEL01_60 0 + Interp6 [edi+4],[c6],[c2] +%endmacro + +%macro PIXEL01_61 0 + Interp6 [edi+4],[c2],[c6] +%endmacro + +%macro PIXEL01_70 0 + Interp7 [edi+4],[c2],[c6] +%endmacro + +%macro PIXEL01_90 0 + Interp9 [edi+4],[c2],[c6] +%endmacro + +%macro PIXEL01_100 0 + Interp10 [edi+4],[c2],[c6] +%endmacro + +%macro PIXEL10_0 0 + mov [edi+ebx],eax +%endmacro + +%macro PIXEL10_10 0 + Interp1 [edi+ebx],eax,[c7] +%endmacro + +%macro PIXEL10_11 0 + Interp1 [edi+ebx],eax,[c8] +%endmacro + +%macro PIXEL10_12 0 + Interp1 [edi+ebx],eax,[c4] +%endmacro + +%macro PIXEL10_20 0 + Interp2 [edi+ebx],eax,[c8],[c4] +%endmacro + +%macro PIXEL10_21 0 + Interp2 [edi+ebx],eax,[c7],[c4] +%endmacro + +%macro PIXEL10_22 0 + Interp2 [edi+ebx],eax,[c7],[c8] +%endmacro + +%macro PIXEL10_60 0 + Interp6 [edi+ebx],[c4],[c8] +%endmacro + +%macro PIXEL10_61 0 + Interp6 [edi+ebx],[c8],[c4] +%endmacro + +%macro PIXEL10_70 0 + Interp7 [edi+ebx],[c8],[c4] +%endmacro + +%macro PIXEL10_90 0 + Interp9 [edi+ebx],[c8],[c4] +%endmacro + +%macro PIXEL10_100 0 + Interp10 [edi+ebx],[c8],[c4] +%endmacro + +%macro PIXEL11_0 0 + mov [edi+ebx+4],eax +%endmacro + +%macro PIXEL11_10 0 + Interp1 [edi+ebx+4],eax,[c9] +%endmacro + +%macro PIXEL11_11 0 + Interp1 [edi+ebx+4],eax,[c6] +%endmacro + +%macro PIXEL11_12 0 + Interp1 [edi+ebx+4],eax,[c8] +%endmacro + +%macro PIXEL11_20 0 + Interp2 [edi+ebx+4],eax,[c6],[c8] +%endmacro + +%macro PIXEL11_21 0 + Interp2 [edi+ebx+4],eax,[c9],[c8] +%endmacro + +%macro PIXEL11_22 0 + Interp2 [edi+ebx+4],eax,[c9],[c6] +%endmacro + +%macro PIXEL11_60 0 + Interp6 [edi+ebx+4],[c8],[c6] +%endmacro + +%macro PIXEL11_61 0 + Interp6 [edi+ebx+4],[c6],[c8] +%endmacro + +%macro PIXEL11_70 0 + Interp7 [edi+ebx+4],[c6],[c8] +%endmacro + +%macro PIXEL11_90 0 + Interp9 [edi+ebx+4],[c6],[c8] +%endmacro + +%macro PIXEL11_100 0 + Interp10 [edi+ebx+4],[c6],[c8] +%endmacro + +inbuffer equ 8 +outbuffer equ 12 +Xres equ 16 +Yres equ 20 +dstpitch equ 24 +srcpitch equ 28 + +_hq2x_32: + push ebp + mov ebp,esp + pushad + + mov esi,[ebp+inbuffer] + mov edi,[ebp+outbuffer] + mov edx,[ebp+Yres] + mov [linesleft],edx + mov ebx,[ebp+Xres] + shl ebx,1 + mov dword[prevline],0 + mov dword[nextline],ebx +.loopy + mov ecx,[ebp+Xres] + sub ecx,2 ; x={Xres-2, Xres-1} are special cases. + mov dword[xcounter],ecx + ; x=0 - special case + mov ebx,[prevline] + movq mm5,[esi+ebx] + movq mm6,[esi] + mov ebx,[nextline] + movq mm7,[esi+ebx] + movd eax,mm5 + movzx edx,ax + mov [w1],edx + mov [w2],edx + shr eax,16 + mov [w3],eax + movd eax,mm6 + movzx edx,ax + mov [w4],edx + mov [w5],edx + shr eax,16 + mov [w6],eax + movd eax,mm7 + movzx edx,ax + mov [w7],edx + mov [w8],edx + shr eax,16 + mov [w9],eax + jmp .flags +.loopx + mov ebx,[prevline] + movq mm5,[esi+ebx-2] + movq mm6,[esi-2] + mov ebx,[nextline] + movq mm7,[esi+ebx-2] + movd eax,mm5 + movzx edx,ax + mov [w1],edx + shr eax,16 + mov [w2],eax + psrlq mm5,32 + movd eax,mm5 + movzx edx,ax + mov [w3],edx + movd eax,mm6 + movzx edx,ax + mov [w4],edx + shr eax,16 + mov [w5],eax + psrlq mm6,32 + movd eax,mm6 + movzx edx,ax + mov [w6],edx + movd eax,mm7 + movzx edx,ax + mov [w7],edx + shr eax,16 + mov [w8],eax + psrlq mm7,32 + movd eax,mm7 + movzx edx,ax + mov [w9],edx +.flags + mov ebx,_RGBtoYUV + mov eax,[w5] + xor ecx,ecx + movd mm5,[ebx+eax*4] + mov dword[cross],0 + + mov edx,[w2] + cmp eax,edx + je .noflag2 + or dword[cross],1 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag2 + or ecx,2 +.noflag2 + mov edx,[w4] + cmp eax,edx + je .noflag4 + or dword[cross],2 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag4 + or ecx,8 +.noflag4 + mov edx,[w6] + cmp eax,edx + je .noflag6 + or dword[cross],4 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag6 + or ecx,16 +.noflag6 + mov edx,[w8] + cmp eax,edx + je .noflag8 + or dword[cross],8 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag8 + or ecx,64 +.noflag8 + test ecx,ecx + jnz .testflag1 + mov ecx,[cross] + mov ebx,_LUT16to32 + mov eax,[ebx+eax*4] + jmp [FuncTable2+ecx*4] +.testflag1 + mov edx,[w1] + cmp eax,edx + je .noflag1 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag1 + or ecx,1 +.noflag1 + mov edx,[w3] + cmp eax,edx + je .noflag3 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag3 + or ecx,4 +.noflag3 + mov edx,[w7] + cmp eax,edx + je .noflag7 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag7 + or ecx,32 +.noflag7 + mov edx,[w9] + cmp eax,edx + je .noflag9 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag9 + or ecx,128 +.noflag9 + mov ebx,_LUT16to32 + mov eax,[ebx+eax*4] + mov edx,[w2] + mov edx,[ebx+edx*4] + mov [c2],edx + mov edx,[w4] + mov edx,[ebx+edx*4] + mov [c4],edx + mov edx,[w6] + mov edx,[ebx+edx*4] + mov [c6],edx + mov edx,[w8] + mov edx,[ebx+edx*4] + mov [c8],edx + test ecx,0x005A + jz .switch + mov edx,[w1] + mov edx,[ebx+edx*4] + mov [c1],edx + mov edx,[w3] + mov edx,[ebx+edx*4] + mov [c3],edx + mov edx,[w7] + mov edx,[ebx+edx*4] + mov [c7],edx + mov edx,[w9] + mov edx,[ebx+edx*4] + mov [c9],edx +.switch + mov ebx,[ebp+dstpitch] + jmp [FuncTable+ecx*4] + +..@flag0 +..@flag1 +..@flag4 +..@flag32 +..@flag128 +..@flag5 +..@flag132 +..@flag160 +..@flag33 +..@flag129 +..@flag36 +..@flag133 +..@flag164 +..@flag161 +..@flag37 +..@flag165 +; PIXEL00_20 +; PIXEL01_20 +; PIXEL10_20 +; PIXEL11_20 + +; the same, only optimized + shl eax,1 + mov ecx,eax + add ecx,[c2] + mov edx,ecx + add edx,[c4] + shr edx,2 + mov [edi],edx + add ecx,[c6] + shr ecx,2 + mov [edi+4],ecx + mov ecx,eax + add ecx,[c8] + mov edx,ecx + add edx,[c4] + shr edx,2 + mov [edi+ebx],edx + add ecx,[c6] + shr ecx,2 + mov [edi+ebx+4],ecx + jmp .loopx_end +..@flag2 +..@flag34 +..@flag130 +..@flag162 + PIXEL00_22 + PIXEL01_21 + PIXEL10_20 + PIXEL11_20 + jmp .loopx_end +..@flag16 +..@flag17 +..@flag48 +..@flag49 + PIXEL00_20 + PIXEL01_22 + PIXEL10_20 + PIXEL11_21 + jmp .loopx_end +..@flag64 +..@flag65 +..@flag68 +..@flag69 + PIXEL00_20 + PIXEL01_20 + PIXEL10_21 + PIXEL11_22 + jmp .loopx_end +..@flag8 +..@flag12 +..@flag136 +..@flag140 + PIXEL00_21 + PIXEL01_20 + PIXEL10_22 + PIXEL11_20 + jmp .loopx_end +..@flag3 +..@flag35 +..@flag131 +..@flag163 + PIXEL00_11 + PIXEL01_21 + PIXEL10_20 + PIXEL11_20 + jmp .loopx_end +..@flag6 +..@flag38 +..@flag134 +..@flag166 + PIXEL00_22 + PIXEL01_12 + PIXEL10_20 + PIXEL11_20 + jmp .loopx_end +..@flag20 +..@flag21 +..@flag52 +..@flag53 + PIXEL00_20 + PIXEL01_11 + PIXEL10_20 + PIXEL11_21 + jmp .loopx_end +..@flag144 +..@flag145 +..@flag176 +..@flag177 + PIXEL00_20 + PIXEL01_22 + PIXEL10_20 + PIXEL11_12 + jmp .loopx_end +..@flag192 +..@flag193 +..@flag196 +..@flag197 + PIXEL00_20 + PIXEL01_20 + PIXEL10_21 + PIXEL11_11 + jmp .loopx_end +..@flag96 +..@flag97 +..@flag100 +..@flag101 + PIXEL00_20 + PIXEL01_20 + PIXEL10_12 + PIXEL11_22 + jmp .loopx_end +..@flag40 +..@flag44 +..@flag168 +..@flag172 + PIXEL00_21 + PIXEL01_20 + PIXEL10_11 + PIXEL11_20 + jmp .loopx_end +..@flag9 +..@flag13 +..@flag137 +..@flag141 + PIXEL00_12 + PIXEL01_20 + PIXEL10_22 + PIXEL11_20 + jmp .loopx_end +..@flag18 +..@flag50 + PIXEL00_22 + DiffOrNot w2,w6,PIXEL01_10,PIXEL01_20 + PIXEL10_20 + PIXEL11_21 + jmp .loopx_end +..@flag80 +..@flag81 + PIXEL00_20 + PIXEL01_22 + PIXEL10_21 + DiffOrNot w6,w8,PIXEL11_10,PIXEL11_20 + jmp .loopx_end +..@flag72 +..@flag76 + PIXEL00_21 + PIXEL01_20 + DiffOrNot w8,w4,PIXEL10_10,PIXEL10_20 + PIXEL11_22 + jmp .loopx_end +..@flag10 +..@flag138 + DiffOrNot w4,w2,PIXEL00_10,PIXEL00_20 + PIXEL01_21 + PIXEL10_22 + PIXEL11_20 + jmp .loopx_end +..@flag66 + PIXEL00_22 + PIXEL01_21 + PIXEL10_21 + PIXEL11_22 + jmp .loopx_end +..@flag24 + PIXEL00_21 + PIXEL01_22 + PIXEL10_22 + PIXEL11_21 + jmp .loopx_end +..@flag7 +..@flag39 +..@flag135 + PIXEL00_11 + PIXEL01_12 + PIXEL10_20 + PIXEL11_20 + jmp .loopx_end +..@flag148 +..@flag149 +..@flag180 + PIXEL00_20 + PIXEL01_11 + PIXEL10_20 + PIXEL11_12 + jmp .loopx_end +..@flag224 +..@flag228 +..@flag225 + PIXEL00_20 + PIXEL01_20 + PIXEL10_12 + PIXEL11_11 + jmp .loopx_end +..@flag41 +..@flag169 +..@flag45 + PIXEL00_12 + PIXEL01_20 + PIXEL10_11 + PIXEL11_20 + jmp .loopx_end +..@flag22 +..@flag54 + PIXEL00_22 + DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20 + PIXEL10_20 + PIXEL11_21 + jmp .loopx_end +..@flag208 +..@flag209 + PIXEL00_20 + PIXEL01_22 + PIXEL10_21 + DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20 + jmp .loopx_end +..@flag104 +..@flag108 + PIXEL00_21 + PIXEL01_20 + DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20 + PIXEL11_22 + jmp .loopx_end +..@flag11 +..@flag139 + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20 + PIXEL01_21 + PIXEL10_22 + PIXEL11_20 + jmp .loopx_end +..@flag19 +..@flag51 + DiffOrNot w2,w6,PIXEL00_11,PIXEL01_10,PIXEL00_60,PIXEL01_90 + PIXEL10_20 + PIXEL11_21 + jmp .loopx_end +..@flag146 +..@flag178 + PIXEL00_22 + DiffOrNot w2,w6,PIXEL01_10,PIXEL11_12,PIXEL01_90,PIXEL11_61 + PIXEL10_20 + jmp .loopx_end +..@flag84 +..@flag85 + PIXEL00_20 + DiffOrNot w6,w8,PIXEL01_11,PIXEL11_10,PIXEL01_60,PIXEL11_90 + PIXEL10_21 + jmp .loopx_end +..@flag112 +..@flag113 + PIXEL00_20 + PIXEL01_22 + DiffOrNot w6,w8,PIXEL10_12,PIXEL11_10,PIXEL10_61,PIXEL11_90 + jmp .loopx_end +..@flag200 +..@flag204 + PIXEL00_21 + PIXEL01_20 + DiffOrNot w8,w4,PIXEL10_10,PIXEL11_11,PIXEL10_90,PIXEL11_60 + jmp .loopx_end +..@flag73 +..@flag77 + DiffOrNot w8,w4,PIXEL00_12,PIXEL10_10,PIXEL00_61,PIXEL10_90 + PIXEL01_20 + PIXEL11_22 + jmp .loopx_end +..@flag42 +..@flag170 + DiffOrNot w4,w2,PIXEL00_10,PIXEL10_11,PIXEL00_90,PIXEL10_60 + PIXEL01_21 + PIXEL11_20 + jmp .loopx_end +..@flag14 +..@flag142 + DiffOrNot w4,w2,PIXEL00_10,PIXEL01_12,PIXEL00_90,PIXEL01_61 + PIXEL10_22 + PIXEL11_20 + jmp .loopx_end +..@flag67 + PIXEL00_11 + PIXEL01_21 + PIXEL10_21 + PIXEL11_22 + jmp .loopx_end +..@flag70 + PIXEL00_22 + PIXEL01_12 + PIXEL10_21 + PIXEL11_22 + jmp .loopx_end +..@flag28 + PIXEL00_21 + PIXEL01_11 + PIXEL10_22 + PIXEL11_21 + jmp .loopx_end +..@flag152 + PIXEL00_21 + PIXEL01_22 + PIXEL10_22 + PIXEL11_12 + jmp .loopx_end +..@flag194 + PIXEL00_22 + PIXEL01_21 + PIXEL10_21 + PIXEL11_11 + jmp .loopx_end +..@flag98 + PIXEL00_22 + PIXEL01_21 + PIXEL10_12 + PIXEL11_22 + jmp .loopx_end +..@flag56 + PIXEL00_21 + PIXEL01_22 + PIXEL10_11 + PIXEL11_21 + jmp .loopx_end +..@flag25 + PIXEL00_12 + PIXEL01_22 + PIXEL10_22 + PIXEL11_21 + jmp .loopx_end +..@flag26 +..@flag31 + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20 + DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20 + PIXEL10_22 + PIXEL11_21 + jmp .loopx_end +..@flag82 +..@flag214 + PIXEL00_22 + DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20 + PIXEL10_21 + DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20 + jmp .loopx_end +..@flag88 +..@flag248 + PIXEL00_21 + PIXEL01_22 + DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20 + DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20 + jmp .loopx_end +..@flag74 +..@flag107 + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20 + PIXEL01_21 + DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20 + PIXEL11_22 + jmp .loopx_end +..@flag27 + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20 + PIXEL01_10 + PIXEL10_22 + PIXEL11_21 + jmp .loopx_end +..@flag86 + PIXEL00_22 + DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20 + PIXEL10_21 + PIXEL11_10 + jmp .loopx_end +..@flag216 + PIXEL00_21 + PIXEL01_22 + PIXEL10_10 + DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20 + jmp .loopx_end +..@flag106 + PIXEL00_10 + PIXEL01_21 + DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20 + PIXEL11_22 + jmp .loopx_end +..@flag30 + PIXEL00_10 + DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20 + PIXEL10_22 + PIXEL11_21 + jmp .loopx_end +..@flag210 + PIXEL00_22 + PIXEL01_10 + PIXEL10_21 + DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20 + jmp .loopx_end +..@flag120 + PIXEL00_21 + PIXEL01_22 + DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20 + PIXEL11_10 + jmp .loopx_end +..@flag75 + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20 + PIXEL01_21 + PIXEL10_10 + PIXEL11_22 + jmp .loopx_end +..@flag29 + PIXEL00_12 + PIXEL01_11 + PIXEL10_22 + PIXEL11_21 + jmp .loopx_end +..@flag198 + PIXEL00_22 + PIXEL01_12 + PIXEL10_21 + PIXEL11_11 + jmp .loopx_end +..@flag184 + PIXEL00_21 + PIXEL01_22 + PIXEL10_11 + PIXEL11_12 + jmp .loopx_end +..@flag99 + PIXEL00_11 + PIXEL01_21 + PIXEL10_12 + PIXEL11_22 + jmp .loopx_end +..@flag57 + PIXEL00_12 + PIXEL01_22 + PIXEL10_11 + PIXEL11_21 + jmp .loopx_end +..@flag71 + PIXEL00_11 + PIXEL01_12 + PIXEL10_21 + PIXEL11_22 + jmp .loopx_end +..@flag156 + PIXEL00_21 + PIXEL01_11 + PIXEL10_22 + PIXEL11_12 + jmp .loopx_end +..@flag226 + PIXEL00_22 + PIXEL01_21 + PIXEL10_12 + PIXEL11_11 + jmp .loopx_end +..@flag60 + PIXEL00_21 + PIXEL01_11 + PIXEL10_11 + PIXEL11_21 + jmp .loopx_end +..@flag195 + PIXEL00_11 + PIXEL01_21 + PIXEL10_21 + PIXEL11_11 + jmp .loopx_end +..@flag102 + PIXEL00_22 + PIXEL01_12 + PIXEL10_12 + PIXEL11_22 + jmp .loopx_end +..@flag153 + PIXEL00_12 + PIXEL01_22 + PIXEL10_22 + PIXEL11_12 + jmp .loopx_end +..@flag58 + DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70 + DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70 + PIXEL10_11 + PIXEL11_21 + jmp .loopx_end +..@flag83 + PIXEL00_11 + DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70 + PIXEL10_21 + DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70 + jmp .loopx_end +..@flag92 + PIXEL00_21 + PIXEL01_11 + DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70 + DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70 + jmp .loopx_end +..@flag202 + DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70 + PIXEL01_21 + DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70 + PIXEL11_11 + jmp .loopx_end +..@flag78 + DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70 + PIXEL01_12 + DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70 + PIXEL11_22 + jmp .loopx_end +..@flag154 + DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70 + DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70 + PIXEL10_22 + PIXEL11_12 + jmp .loopx_end +..@flag114 + PIXEL00_22 + DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70 + PIXEL10_12 + DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70 + jmp .loopx_end +..@flag89 + PIXEL00_12 + PIXEL01_22 + DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70 + DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70 + jmp .loopx_end +..@flag90 + DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70 + DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70 + DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70 + DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70 + jmp .loopx_end +..@flag55 +..@flag23 + DiffOrNot w2,w6,PIXEL00_11,PIXEL01_0,PIXEL00_60,PIXEL01_90 + PIXEL10_20 + PIXEL11_21 + jmp .loopx_end +..@flag182 +..@flag150 + PIXEL00_22 + DiffOrNot w2,w6,PIXEL01_0,PIXEL11_12,PIXEL01_90,PIXEL11_61 + PIXEL10_20 + jmp .loopx_end +..@flag213 +..@flag212 + PIXEL00_20 + DiffOrNot w6,w8,PIXEL01_11,PIXEL11_0,PIXEL01_60,PIXEL11_90 + PIXEL10_21 + jmp .loopx_end +..@flag241 +..@flag240 + PIXEL00_20 + PIXEL01_22 + DiffOrNot w6,w8,PIXEL10_12,PIXEL11_0,PIXEL10_61,PIXEL11_90 + jmp .loopx_end +..@flag236 +..@flag232 + PIXEL00_21 + PIXEL01_20 + DiffOrNot w8,w4,PIXEL10_0,PIXEL11_11,PIXEL10_90,PIXEL11_60 + jmp .loopx_end +..@flag109 +..@flag105 + DiffOrNot w8,w4,PIXEL00_12,PIXEL10_0,PIXEL00_61,PIXEL10_90 + PIXEL01_20 + PIXEL11_22 + jmp .loopx_end +..@flag171 +..@flag43 + DiffOrNot w4,w2,PIXEL00_0,PIXEL10_11,PIXEL00_90,PIXEL10_60 + PIXEL01_21 + PIXEL11_20 + jmp .loopx_end +..@flag143 +..@flag15 + DiffOrNot w4,w2,PIXEL00_0,PIXEL01_12,PIXEL00_90,PIXEL01_61 + PIXEL10_22 + PIXEL11_20 + jmp .loopx_end +..@flag124 + PIXEL00_21 + PIXEL01_11 + DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20 + PIXEL11_10 + jmp .loopx_end +..@flag203 + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20 + PIXEL01_21 + PIXEL10_10 + PIXEL11_11 + jmp .loopx_end +..@flag62 + PIXEL00_10 + DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20 + PIXEL10_11 + PIXEL11_21 + jmp .loopx_end +..@flag211 + PIXEL00_11 + PIXEL01_10 + PIXEL10_21 + DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20 + jmp .loopx_end +..@flag118 + PIXEL00_22 + DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20 + PIXEL10_12 + PIXEL11_10 + jmp .loopx_end +..@flag217 + PIXEL00_12 + PIXEL01_22 + PIXEL10_10 + DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20 + jmp .loopx_end +..@flag110 + PIXEL00_10 + PIXEL01_12 + DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20 + PIXEL11_22 + jmp .loopx_end +..@flag155 + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20 + PIXEL01_10 + PIXEL10_22 + PIXEL11_12 + jmp .loopx_end +..@flag188 + PIXEL00_21 + PIXEL01_11 + PIXEL10_11 + PIXEL11_12 + jmp .loopx_end +..@flag185 + PIXEL00_12 + PIXEL01_22 + PIXEL10_11 + PIXEL11_12 + jmp .loopx_end +..@flag61 + PIXEL00_12 + PIXEL01_11 + PIXEL10_11 + PIXEL11_21 + jmp .loopx_end +..@flag157 + PIXEL00_12 + PIXEL01_11 + PIXEL10_22 + PIXEL11_12 + jmp .loopx_end +..@flag103 + PIXEL00_11 + PIXEL01_12 + PIXEL10_12 + PIXEL11_22 + jmp .loopx_end +..@flag227 + PIXEL00_11 + PIXEL01_21 + PIXEL10_12 + PIXEL11_11 + jmp .loopx_end +..@flag230 + PIXEL00_22 + PIXEL01_12 + PIXEL10_12 + PIXEL11_11 + jmp .loopx_end +..@flag199 + PIXEL00_11 + PIXEL01_12 + PIXEL10_21 + PIXEL11_11 + jmp .loopx_end +..@flag220 + PIXEL00_21 + PIXEL01_11 + DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70 + DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20 + jmp .loopx_end +..@flag158 + DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70 + DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20 + PIXEL10_22 + PIXEL11_12 + jmp .loopx_end +..@flag234 + DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70 + PIXEL01_21 + DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20 + PIXEL11_11 + jmp .loopx_end +..@flag242 + PIXEL00_22 + DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70 + PIXEL10_12 + DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20 + jmp .loopx_end +..@flag59 + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20 + DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70 + PIXEL10_11 + PIXEL11_21 + jmp .loopx_end +..@flag121 + PIXEL00_12 + PIXEL01_22 + DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20 + DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70 + jmp .loopx_end +..@flag87 + PIXEL00_11 + DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20 + PIXEL10_21 + DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70 + jmp .loopx_end +..@flag79 + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20 + PIXEL01_12 + DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70 + PIXEL11_22 + jmp .loopx_end +..@flag122 + DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70 + DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70 + DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20 + DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70 + jmp .loopx_end +..@flag94 + DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70 + DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20 + DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70 + DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70 + jmp .loopx_end +..@flag218 + DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70 + DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70 + DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70 + DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20 + jmp .loopx_end +..@flag91 + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20 + DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70 + DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70 + DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70 + jmp .loopx_end +..@flag229 + PIXEL00_20 + PIXEL01_20 + PIXEL10_12 + PIXEL11_11 + jmp .loopx_end +..@flag167 + PIXEL00_11 + PIXEL01_12 + PIXEL10_20 + PIXEL11_20 + jmp .loopx_end +..@flag173 + PIXEL00_12 + PIXEL01_20 + PIXEL10_11 + PIXEL11_20 + jmp .loopx_end +..@flag181 + PIXEL00_20 + PIXEL01_11 + PIXEL10_20 + PIXEL11_12 + jmp .loopx_end +..@flag186 + DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70 + DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70 + PIXEL10_11 + PIXEL11_12 + jmp .loopx_end +..@flag115 + PIXEL00_11 + DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70 + PIXEL10_12 + DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70 + jmp .loopx_end +..@flag93 + PIXEL00_12 + PIXEL01_11 + DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70 + DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70 + jmp .loopx_end +..@flag206 + DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70 + PIXEL01_12 + DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70 + PIXEL11_11 + jmp .loopx_end +..@flag205 +..@flag201 + PIXEL00_12 + PIXEL01_20 + DiffOrNot w8,w4,PIXEL10_10,PIXEL10_70 + PIXEL11_11 + jmp .loopx_end +..@flag174 +..@flag46 + DiffOrNot w4,w2,PIXEL00_10,PIXEL00_70 + PIXEL01_12 + PIXEL10_11 + PIXEL11_20 + jmp .loopx_end +..@flag179 +..@flag147 + PIXEL00_11 + DiffOrNot w2,w6,PIXEL01_10,PIXEL01_70 + PIXEL10_20 + PIXEL11_12 + jmp .loopx_end +..@flag117 +..@flag116 + PIXEL00_20 + PIXEL01_11 + PIXEL10_12 + DiffOrNot w6,w8,PIXEL11_10,PIXEL11_70 + jmp .loopx_end +..@flag189 + PIXEL00_12 + PIXEL01_11 + PIXEL10_11 + PIXEL11_12 + jmp .loopx_end +..@flag231 + PIXEL00_11 + PIXEL01_12 + PIXEL10_12 + PIXEL11_11 + jmp .loopx_end +..@flag126 + PIXEL00_10 + DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20 + DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20 + PIXEL11_10 + jmp .loopx_end +..@flag219 + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20 + PIXEL01_10 + PIXEL10_10 + DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20 + jmp .loopx_end +..@flag125 + DiffOrNot w8,w4,PIXEL00_12,PIXEL10_0,PIXEL00_61,PIXEL10_90 + PIXEL01_11 + PIXEL11_10 + jmp .loopx_end +..@flag221 + PIXEL00_12 + DiffOrNot w6,w8,PIXEL01_11,PIXEL11_0,PIXEL01_60,PIXEL11_90 + PIXEL10_10 + jmp .loopx_end +..@flag207 + DiffOrNot w4,w2,PIXEL00_0,PIXEL01_12,PIXEL00_90,PIXEL01_61 + PIXEL10_10 + PIXEL11_11 + jmp .loopx_end +..@flag238 + PIXEL00_10 + PIXEL01_12 + DiffOrNot w8,w4,PIXEL10_0,PIXEL11_11,PIXEL10_90,PIXEL11_60 + jmp .loopx_end +..@flag190 + PIXEL00_10 + DiffOrNot w2,w6,PIXEL01_0,PIXEL11_12,PIXEL01_90,PIXEL11_61 + PIXEL10_11 + jmp .loopx_end +..@flag187 + DiffOrNot w4,w2,PIXEL00_0,PIXEL10_11,PIXEL00_90,PIXEL10_60 + PIXEL01_10 + PIXEL11_12 + jmp .loopx_end +..@flag243 + PIXEL00_11 + PIXEL01_10 + DiffOrNot w6,w8,PIXEL10_12,PIXEL11_0,PIXEL10_61,PIXEL11_90 + jmp .loopx_end +..@flag119 + DiffOrNot w2,w6,PIXEL00_11,PIXEL01_0,PIXEL00_60,PIXEL01_90 + PIXEL10_12 + PIXEL11_10 + jmp .loopx_end +..@flag237 +..@flag233 + PIXEL00_12 + PIXEL01_20 + DiffOrNot w8,w4,PIXEL10_0,PIXEL10_100 + PIXEL11_11 + jmp .loopx_end +..@flag175 +..@flag47 + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_100 + PIXEL01_12 + PIXEL10_11 + PIXEL11_20 + jmp .loopx_end +..@flag183 +..@flag151 + PIXEL00_11 + DiffOrNot w2,w6,PIXEL01_0,PIXEL01_100 + PIXEL10_20 + PIXEL11_12 + jmp .loopx_end +..@flag245 +..@flag244 + PIXEL00_20 + PIXEL01_11 + PIXEL10_12 + DiffOrNot w6,w8,PIXEL11_0,PIXEL11_100 + jmp .loopx_end +..@flag250 + PIXEL00_10 + PIXEL01_10 + DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20 + DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20 + jmp .loopx_end +..@flag123 + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20 + PIXEL01_10 + DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20 + PIXEL11_10 + jmp .loopx_end +..@flag95 + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20 + DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20 + PIXEL10_10 + PIXEL11_10 + jmp .loopx_end +..@flag222 + PIXEL00_10 + DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20 + PIXEL10_10 + DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20 + jmp .loopx_end +..@flag252 + PIXEL00_21 + PIXEL01_11 + DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20 + DiffOrNot w6,w8,PIXEL11_0,PIXEL11_100 + jmp .loopx_end +..@flag249 + PIXEL00_12 + PIXEL01_22 + DiffOrNot w8,w4,PIXEL10_0,PIXEL10_100 + DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20 + jmp .loopx_end +..@flag235 + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20 + PIXEL01_21 + DiffOrNot w8,w4,PIXEL10_0,PIXEL10_100 + PIXEL11_11 + jmp .loopx_end +..@flag111 + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_100 + PIXEL01_12 + DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20 + PIXEL11_22 + jmp .loopx_end +..@flag63 + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_100 + DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20 + PIXEL10_11 + PIXEL11_21 + jmp .loopx_end +..@flag159 + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20 + DiffOrNot w2,w6,PIXEL01_0,PIXEL01_100 + PIXEL10_22 + PIXEL11_12 + jmp .loopx_end +..@flag215 + PIXEL00_11 + DiffOrNot w2,w6,PIXEL01_0,PIXEL01_100 + PIXEL10_21 + DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20 + jmp .loopx_end +..@flag246 + PIXEL00_22 + DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20 + PIXEL10_12 + DiffOrNot w6,w8,PIXEL11_0,PIXEL11_100 + jmp .loopx_end +..@flag254 + PIXEL00_10 + DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20 + DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20 + DiffOrNot w6,w8,PIXEL11_0,PIXEL11_100 + jmp .loopx_end +..@flag253 + PIXEL00_12 + PIXEL01_11 + DiffOrNot w8,w4,PIXEL10_0,PIXEL10_100 + DiffOrNot w6,w8,PIXEL11_0,PIXEL11_100 + jmp .loopx_end +..@flag251 + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20 + PIXEL01_10 + DiffOrNot w8,w4,PIXEL10_0,PIXEL10_100 + DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20 + jmp .loopx_end +..@flag239 + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_100 + PIXEL01_12 + DiffOrNot w8,w4,PIXEL10_0,PIXEL10_100 + PIXEL11_11 + jmp .loopx_end +..@flag127 + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_100 + DiffOrNot w2,w6,PIXEL01_0,PIXEL01_20 + DiffOrNot w8,w4,PIXEL10_0,PIXEL10_20 + PIXEL11_10 + jmp .loopx_end +..@flag191 + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_100 + DiffOrNot w2,w6,PIXEL01_0,PIXEL01_100 + PIXEL10_11 + PIXEL11_12 + jmp .loopx_end +..@flag223 + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20 + DiffOrNot w2,w6,PIXEL01_0,PIXEL01_100 + PIXEL10_10 + DiffOrNot w6,w8,PIXEL11_0,PIXEL11_20 + jmp .loopx_end +..@flag247 + PIXEL00_11 + DiffOrNot w2,w6,PIXEL01_0,PIXEL01_100 + PIXEL10_12 + DiffOrNot w6,w8,PIXEL11_0,PIXEL11_100 + jmp .loopx_end +..@flag255 + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_100 + DiffOrNot w2,w6,PIXEL01_0,PIXEL01_100 + DiffOrNot w8,w4,PIXEL10_0,PIXEL10_100 + DiffOrNot w6,w8,PIXEL11_0,PIXEL11_100 + jmp .loopx_end + + +..@cross0 + mov ebx,[ebp+dstpitch] + mov [edi],eax + mov [edi+4],eax + mov [edi+ebx],eax + mov [edi+ebx+4],eax + jmp .loopx_end +..@cross1 + mov ecx,[w2] + mov edx,eax + shl edx,2 + add edx,[ebx+ecx*4] + sub edx,eax + shr edx,2 + mov ebx,[ebp+dstpitch] + mov [edi],edx + mov [edi+4],edx + mov [edi+ebx],eax + mov [edi+ebx+4],eax + jmp .loopx_end +..@cross2 + mov ecx,[w4] + mov edx,eax + shl edx,2 + add edx,[ebx+ecx*4] + sub edx,eax + shr edx,2 + mov ebx,[ebp+dstpitch] + mov [edi],edx + mov [edi+4],eax + mov [edi+ebx],edx + mov [edi+ebx+4],eax + jmp .loopx_end +..@cross4 + mov ecx,[w6] + mov edx,eax + shl edx,2 + add edx,[ebx+ecx*4] + sub edx,eax + shr edx,2 + mov ebx,[ebp+dstpitch] + mov [edi],eax + mov [edi+4],edx + mov [edi+ebx],eax + mov [edi+ebx+4],edx + jmp .loopx_end +..@cross8 + mov ecx,[w8] + mov edx,eax + shl edx,2 + add edx,[ebx+ecx*4] + sub edx,eax + shr edx,2 + mov ebx,[ebp+dstpitch] + mov [edi],eax + mov [edi+4],eax + mov [edi+ebx],edx + mov [edi+ebx+4],edx + jmp .loopx_end +..@crossN + mov edx,[w2] + mov ecx,[ebx+edx*4] + mov [c2],ecx + mov edx,[w4] + mov ecx,[ebx+edx*4] + mov [c4],ecx + mov edx,[w6] + mov ecx,[ebx+edx*4] + mov [c6],ecx + mov edx,[w8] + mov ecx,[ebx+edx*4] + mov [c8],ecx + mov ebx,[ebp+dstpitch] + jmp ..@flag0 + +.loopx_end + add esi,2 + add edi,8 + dec dword[xcounter] + jle .xres_2 + jmp .loopx +.xres_2 + ; x=Xres-2 - special case + jl .xres_1 + mov ebx,[prevline] + movq mm5,[esi+ebx-4] + movq mm6,[esi-4] + mov ebx,[nextline] + movq mm7,[esi+ebx-4] + psrlq mm5,16 + psrlq mm6,16 + psrlq mm7,16 + movd eax,mm5 + movzx edx,ax + mov [w1],edx + shr eax,16 + mov [w2],eax + psrlq mm5,32 + movd eax,mm5 + mov [w3],eax + movd eax,mm6 + movzx edx,ax + mov [w4],edx + shr eax,16 + mov [w5],eax + psrlq mm6,32 + movd eax,mm6 + mov [w6],eax + movd eax,mm7 + movzx edx,ax + mov [w7],edx + shr eax,16 + mov [w8],eax + psrlq mm7,32 + movd eax,mm7 + mov [w9],eax + jmp .flags +.xres_1 + cmp dword[xcounter],-1 + jl .nexty + ; x=Xres-1 - special case + mov ebx,[prevline] + movq mm5,[esi+ebx-6] + movq mm6,[esi-6] + mov ebx,[nextline] + movq mm7,[esi+ebx-6] + psrlq mm5,32 + psrlq mm6,32 + psrlq mm7,32 + movd eax,mm5 + movzx edx,ax + mov [w1],edx + shr eax,16 + mov [w2],eax + mov [w3],eax + movd eax,mm6 + movzx edx,ax + mov [w4],edx + shr eax,16 + mov [w5],eax + mov [w6],eax + movd eax,mm7 + movzx edx,ax + mov [w7],edx + shr eax,16 + mov [w8],eax + mov [w9],eax + jmp .flags +.nexty + add edi,ebx + add esi,[ebp+srcpitch] + sub esi,[ebp+Xres] + sub esi,[ebp+Xres] + dec dword[linesleft] + jz .fin + mov ebx,[ebp+Xres] + shl ebx,1 + cmp dword[linesleft],1 + je .lastline + mov dword[nextline],ebx + neg ebx + mov dword[prevline],ebx + jmp .loopy +.lastline + mov dword[nextline],0 + neg ebx + mov dword[prevline],ebx + jmp .loopy +.fin + emms + popad + mov esp,ebp + pop ebp + ret + +SECTION .data +FuncTable + dd ..@flag0, ..@flag1, ..@flag2, ..@flag3, ..@flag4, ..@flag5, ..@flag6, ..@flag7 + dd ..@flag8, ..@flag9, ..@flag10, ..@flag11, ..@flag12, ..@flag13, ..@flag14, ..@flag15 + dd ..@flag16, ..@flag17, ..@flag18, ..@flag19, ..@flag20, ..@flag21, ..@flag22, ..@flag23 + dd ..@flag24, ..@flag25, ..@flag26, ..@flag27, ..@flag28, ..@flag29, ..@flag30, ..@flag31 + dd ..@flag32, ..@flag33, ..@flag34, ..@flag35, ..@flag36, ..@flag37, ..@flag38, ..@flag39 + dd ..@flag40, ..@flag41, ..@flag42, ..@flag43, ..@flag44, ..@flag45, ..@flag46, ..@flag47 + dd ..@flag48, ..@flag49, ..@flag50, ..@flag51, ..@flag52, ..@flag53, ..@flag54, ..@flag55 + dd ..@flag56, ..@flag57, ..@flag58, ..@flag59, ..@flag60, ..@flag61, ..@flag62, ..@flag63 + dd ..@flag64, ..@flag65, ..@flag66, ..@flag67, ..@flag68, ..@flag69, ..@flag70, ..@flag71 + dd ..@flag72, ..@flag73, ..@flag74, ..@flag75, ..@flag76, ..@flag77, ..@flag78, ..@flag79 + dd ..@flag80, ..@flag81, ..@flag82, ..@flag83, ..@flag84, ..@flag85, ..@flag86, ..@flag87 + dd ..@flag88, ..@flag89, ..@flag90, ..@flag91, ..@flag92, ..@flag93, ..@flag94, ..@flag95 + dd ..@flag96, ..@flag97, ..@flag98, ..@flag99, ..@flag100, ..@flag101, ..@flag102, ..@flag103 + dd ..@flag104, ..@flag105, ..@flag106, ..@flag107, ..@flag108, ..@flag109, ..@flag110, ..@flag111 + dd ..@flag112, ..@flag113, ..@flag114, ..@flag115, ..@flag116, ..@flag117, ..@flag118, ..@flag119 + dd ..@flag120, ..@flag121, ..@flag122, ..@flag123, ..@flag124, ..@flag125, ..@flag126, ..@flag127 + dd ..@flag128, ..@flag129, ..@flag130, ..@flag131, ..@flag132, ..@flag133, ..@flag134, ..@flag135 + dd ..@flag136, ..@flag137, ..@flag138, ..@flag139, ..@flag140, ..@flag141, ..@flag142, ..@flag143 + dd ..@flag144, ..@flag145, ..@flag146, ..@flag147, ..@flag148, ..@flag149, ..@flag150, ..@flag151 + dd ..@flag152, ..@flag153, ..@flag154, ..@flag155, ..@flag156, ..@flag157, ..@flag158, ..@flag159 + dd ..@flag160, ..@flag161, ..@flag162, ..@flag163, ..@flag164, ..@flag165, ..@flag166, ..@flag167 + dd ..@flag168, ..@flag169, ..@flag170, ..@flag171, ..@flag172, ..@flag173, ..@flag174, ..@flag175 + dd ..@flag176, ..@flag177, ..@flag178, ..@flag179, ..@flag180, ..@flag181, ..@flag182, ..@flag183 + dd ..@flag184, ..@flag185, ..@flag186, ..@flag187, ..@flag188, ..@flag189, ..@flag190, ..@flag191 + dd ..@flag192, ..@flag193, ..@flag194, ..@flag195, ..@flag196, ..@flag197, ..@flag198, ..@flag199 + dd ..@flag200, ..@flag201, ..@flag202, ..@flag203, ..@flag204, ..@flag205, ..@flag206, ..@flag207 + dd ..@flag208, ..@flag209, ..@flag210, ..@flag211, ..@flag212, ..@flag213, ..@flag214, ..@flag215 + dd ..@flag216, ..@flag217, ..@flag218, ..@flag219, ..@flag220, ..@flag221, ..@flag222, ..@flag223 + dd ..@flag224, ..@flag225, ..@flag226, ..@flag227, ..@flag228, ..@flag229, ..@flag230, ..@flag231 + dd ..@flag232, ..@flag233, ..@flag234, ..@flag235, ..@flag236, ..@flag237, ..@flag238, ..@flag239 + dd ..@flag240, ..@flag241, ..@flag242, ..@flag243, ..@flag244, ..@flag245, ..@flag246, ..@flag247 + dd ..@flag248, ..@flag249, ..@flag250, ..@flag251, ..@flag252, ..@flag253, ..@flag254, ..@flag255 + +FuncTable2 + dd ..@cross0, ..@cross1, ..@cross2, ..@crossN, + dd ..@cross4, ..@crossN, ..@crossN, ..@crossN, + dd ..@cross8, ..@crossN, ..@crossN, ..@crossN, + dd ..@crossN, ..@crossN, ..@crossN, ..@crossN + diff --git a/od-win32/hq3x16.asm b/od-win32/hq3x16.asm new file mode 100755 index 00000000..1596d78b --- /dev/null +++ b/od-win32/hq3x16.asm @@ -0,0 +1,2430 @@ +;hq3x filter +;16bpp output +;---------------------------------------------------------- +;Copyright (C) 2003 MaxSt ( maxst@hiend3d.com ) +; +;This program is free software; you can redistribute it and/or +;modify it under the terms of the GNU General Public License +;as published by the Free Software Foundation; either +;version 2 of the License, or (at your option) any later +;version. +; +;This program is distributed in the hope that it will be useful, +;but WITHOUT ANY WARRANTY; without even the implied warranty of +;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;GNU General Public License for more details. +; +;You should have received a copy of the GNU General Public License +;along with this program; if not, write to the Free Software +;Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +GLOBAL _hq3x_16 + +EXTERN _LUT16to32 +EXTERN _RGBtoYUV + +SECTION .bss +firstline resd 1 +linesleft resd 1 +xcounter resd 1 +cross resd 1 +nextline resd 1 +prevline resd 1 +w1 resd 1 +w2 resd 1 +w3 resd 1 +w4 resd 1 +w5 resd 1 +w6 resd 1 +w7 resd 1 +w8 resd 1 +w9 resd 1 + +SECTION .data + +reg_blank dd 0,0 +const7 dd 0x00070007,0x00000007 +threshold dd 0x00300706,0x00000000 +zerolowbits dd 0xF7DEF7DE + +SECTION .text + +%macro TestDiff 2 + xor ecx,ecx + mov edx,[%1] + cmp edx,[%2] + je %%fin + mov ecx,_RGBtoYUV + movd mm1,[ecx+edx*4] + movq mm5,mm1 + mov edx,[%2] + movd mm2,[ecx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd ecx,mm1 +%%fin: +%endmacro + +%macro DiffOrNot 4 + TestDiff %1,%2 + test ecx,ecx + jz %%same + %3 + jmp %%fin +%%same: + %4 +%%fin +%endmacro + +%macro DiffOrNot 6 + TestDiff %1,%2 + test ecx,ecx + jz %%same + %3 + %4 + jmp %%fin +%%same: + %5 + %6 +%%fin +%endmacro + +%macro DiffOrNot 8 + TestDiff %1,%2 + test ecx,ecx + jz %%same + %3 + %4 + %5 + jmp %%fin +%%same: + %6 + %7 + %8 +%%fin +%endmacro + +%macro DiffOrNot 10 + TestDiff %1,%2 + test ecx,ecx + jz %%same + %3 + %4 + %5 + %6 + jmp %%fin +%%same: + %7 + %8 + %9 + %10 +%%fin +%endmacro + +%macro Interp1 3 + mov edx,%2 + mov ecx,%3 + cmp edx,ecx + je %%fin + and edx,[zerolowbits] + and ecx,[zerolowbits] + add ecx,edx + shr ecx,1 + add ecx,0x0821 + and ecx,[zerolowbits] + add edx,ecx + shr edx,1 +%%fin + mov %1,dx +%endmacro + +%macro Interp2 4 + mov edx,%3 + mov ecx,%4 + cmp edx,ecx + je %%fin1 + and edx,[zerolowbits] + and ecx,[zerolowbits] + add ecx,edx + shr ecx,1 + add ecx,0x0821 +%%fin1 + mov edx,%2 + cmp edx,ecx + je %%fin2 + and ecx,[zerolowbits] + and edx,[zerolowbits] + add edx,ecx + shr edx,1 +%%fin2 + mov %1,dx +%endmacro + +%macro Interp3 2 + mov ecx, _LUT16to32 + movd mm1, [ecx+eax*4] + mov edx, %2 + movd mm2, [ecx+edx*4] + punpcklbw mm1, [reg_blank] + punpcklbw mm2, [reg_blank] + pmullw mm1, [const7] + paddw mm1, mm2 + psrlw mm1, 5 + packuswb mm1, [reg_blank] + movd edx, mm1 + shl dl, 2 + shr edx, 1 + shl dx, 3 + shr edx, 5 + mov %1, dx +%endmacro + +%macro Interp4 3 + mov ecx, _LUT16to32 + movd mm1, [ecx+eax*4] + mov edx, %2 + movd mm2, [ecx+edx*4] + mov edx, %3 + movd mm3, [ecx+edx*4] + punpcklbw mm1, [reg_blank] + punpcklbw mm2, [reg_blank] + punpcklbw mm3, [reg_blank] + psllw mm1, 1 + paddw mm2, mm3 + pmullw mm2, [const7] + paddw mm1, mm2 + psrlw mm1, 6 + packuswb mm1, [reg_blank] + movd edx, mm1 + shl dl, 2 + shr edx, 1 + shl dx, 3 + shr edx, 5 + mov %1, dx +%endmacro + +%macro Interp5 3 + mov edx,%2 + mov ecx,%3 + cmp edx,ecx + je %%fin + and edx,[zerolowbits] + and ecx,[zerolowbits] + add edx,ecx + shr edx,1 +%%fin + mov %1,dx +%endmacro + +%macro PIXEL00_1M 0 + Interp1 [edi],eax,[w1] +%endmacro + +%macro PIXEL00_1U 0 + Interp1 [edi],eax,[w2] +%endmacro + +%macro PIXEL00_1L 0 + Interp1 [edi],eax,[w4] +%endmacro + +%macro PIXEL00_2 0 + Interp2 [edi],eax,[w4],[w2] +%endmacro + +%macro PIXEL00_4 0 + Interp4 [edi],[w4],[w2] +%endmacro + +%macro PIXEL00_5 0 + Interp5 [edi],[w4],[w2] +%endmacro + +%macro PIXEL00_C 0 + mov [edi],ax +%endmacro + +%macro PIXEL01_1 0 + Interp1 [edi+2],eax,[w2] +%endmacro + +%macro PIXEL01_3 0 + Interp3 [edi+2],[w2] +%endmacro + +%macro PIXEL01_6 0 + Interp1 [edi+2],[w2],eax +%endmacro + +%macro PIXEL01_C 0 + mov [edi+2],ax +%endmacro + +%macro PIXEL02_1M 0 + Interp1 [edi+4],eax,[w3] +%endmacro + +%macro PIXEL02_1U 0 + Interp1 [edi+4],eax,[w2] +%endmacro + +%macro PIXEL02_1R 0 + Interp1 [edi+4],eax,[w6] +%endmacro + +%macro PIXEL02_2 0 + Interp2 [edi+4],eax,[w2],[w6] +%endmacro + +%macro PIXEL02_4 0 + Interp4 [edi+4],[w2],[w6] +%endmacro + +%macro PIXEL02_5 0 + Interp5 [edi+4],[w2],[w6] +%endmacro + +%macro PIXEL02_C 0 + mov [edi+4],ax +%endmacro + +%macro PIXEL10_1 0 + Interp1 [edi+ebx],eax,[w4] +%endmacro + +%macro PIXEL10_3 0 + Interp3 [edi+ebx],[w4] +%endmacro + +%macro PIXEL10_6 0 + Interp1 [edi+ebx],[w4],eax +%endmacro + +%macro PIXEL10_C 0 + mov [edi+ebx],ax +%endmacro + +%macro PIXEL11 0 + mov [edi+ebx+2],ax +%endmacro + +%macro PIXEL12_1 0 + Interp1 [edi+ebx+4],eax,[w6] +%endmacro + +%macro PIXEL12_3 0 + Interp3 [edi+ebx+4],[w6] +%endmacro + +%macro PIXEL12_6 0 + Interp1 [edi+ebx+4],[w6],eax +%endmacro + +%macro PIXEL12_C 0 + mov [edi+ebx+4],ax +%endmacro + +%macro PIXEL20_1M 0 + Interp1 [edi+ebx*2],eax,[w7] +%endmacro + +%macro PIXEL20_1D 0 + Interp1 [edi+ebx*2],eax,[w8] +%endmacro + +%macro PIXEL20_1L 0 + Interp1 [edi+ebx*2],eax,[w4] +%endmacro + +%macro PIXEL20_2 0 + Interp2 [edi+ebx*2],eax,[w8],[w4] +%endmacro + +%macro PIXEL20_4 0 + Interp4 [edi+ebx*2],[w8],[w4] +%endmacro + +%macro PIXEL20_5 0 + Interp5 [edi+ebx*2],[w8],[w4] +%endmacro + +%macro PIXEL20_C 0 + mov [edi+ebx*2],ax +%endmacro + +%macro PIXEL21_1 0 + Interp1 [edi+ebx*2+2],eax,[w8] +%endmacro + +%macro PIXEL21_3 0 + Interp3 [edi+ebx*2+2],[w8] +%endmacro + +%macro PIXEL21_6 0 + Interp1 [edi+ebx*2+2],[w8],eax +%endmacro + +%macro PIXEL21_C 0 + mov [edi+ebx*2+2],ax +%endmacro + +%macro PIXEL22_1M 0 + Interp1 [edi+ebx*2+4],eax,[w9] +%endmacro + +%macro PIXEL22_1D 0 + Interp1 [edi+ebx*2+4],eax,[w8] +%endmacro + +%macro PIXEL22_1R 0 + Interp1 [edi+ebx*2+4],eax,[w6] +%endmacro + +%macro PIXEL22_2 0 + Interp2 [edi+ebx*2+4],eax,[w6],[w8] +%endmacro + +%macro PIXEL22_4 0 + Interp4 [edi+ebx*2+4],[w6],[w8] +%endmacro + +%macro PIXEL22_5 0 + Interp5 [edi+ebx*2+4],[w6],[w8] +%endmacro + +%macro PIXEL22_C 0 + mov [edi+ebx*2+4],ax +%endmacro + +inbuffer equ 8 +outbuffer equ 12 +Xres equ 16 +Yres equ 20 +srcpitch equ 24 +dstpitch equ 28 + +_hq3x_16: + push ebp + mov ebp,esp + pushad + + mov esi,[ebp+inbuffer] + mov edi,[ebp+outbuffer] + mov edx,[ebp+Yres] + mov [linesleft],edx + mov dword[firstline],1 +.loopy + mov ebx,[ebp+Xres] + shl ebx,1 + movzx eax,word[esi] + mov [w5],eax + mov [w6],eax + mov edx,eax + xor ecx,ecx + cmp dword[firstline],1 + je .firstline + sub ecx,ebx + movzx eax,word[esi+ecx] +.firstline + mov [prevline],ecx + mov [w2],eax + mov [w3],eax + xor ecx,ecx + cmp dword[linesleft],1 + je .lastline + add ecx,ebx + movzx edx,word[esi+ecx] +.lastline + mov [nextline],ecx + mov [w8],edx + mov [w9],edx + mov ecx,[ebp+Xres] + mov dword[xcounter],ecx +.loopx + mov eax,[w2] + mov ebx,[w5] + mov edx,[w8] + mov [w1],eax + mov [w4],ebx + mov [w7],edx + mov eax,[w3] + mov ebx,[w6] + mov edx,[w9] + mov [w2],eax + mov [w5],ebx + mov [w8],edx + cmp dword[xcounter],1 + je .flags + movzx eax,word[esi+2] + mov [w6],eax + mov ebx,[prevline] + movzx edx,word[esi+ebx+2] + mov [w3],edx + mov ebx,[nextline] + movzx eax,word[esi+ebx+2] + mov [w9],eax +.flags + mov ebx,_RGBtoYUV + mov eax,[w5] + xor ecx,ecx + movd mm5,[ebx+eax*4] + mov dword[cross],0 + + mov edx,[w2] + cmp eax,edx + je .noflag2 + or dword[cross],1 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag2 + or ecx,2 +.noflag2 + mov edx,[w4] + cmp eax,edx + je .noflag4 + or dword[cross],2 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag4 + or ecx,8 +.noflag4 + mov edx,[w6] + cmp eax,edx + je .noflag6 + or dword[cross],4 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag6 + or ecx,16 +.noflag6 + mov edx,[w8] + cmp eax,edx + je .noflag8 + or dword[cross],8 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag8 + or ecx,64 +.noflag8 + test ecx,ecx + jnz .testflag1 + mov ecx,[cross] + mov ebx,[ebp+dstpitch] + jmp [FuncTable2+ecx*4] +.testflag1 + mov edx,[w1] + cmp eax,edx + je .noflag1 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag1 + or ecx,1 +.noflag1 + mov edx,[w3] + cmp eax,edx + je .noflag3 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag3 + or ecx,4 +.noflag3 + mov edx,[w7] + cmp eax,edx + je .noflag7 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag7 + or ecx,32 +.noflag7 + mov edx,[w9] + cmp eax,edx + je .noflag9 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag9 + or ecx,128 +.noflag9 + mov ebx,[ebp+dstpitch] + jmp [FuncTable+ecx*4] + +..@flag0 +..@flag1 +..@flag4 +..@flag32 +..@flag128 +..@flag5 +..@flag132 +..@flag160 +..@flag33 +..@flag129 +..@flag36 +..@flag133 +..@flag164 +..@flag161 +..@flag37 +..@flag165 + PIXEL00_2 + PIXEL01_1 + PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_2 + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag2 +..@flag34 +..@flag130 +..@flag162 + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_2 + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag16 +..@flag17 +..@flag48 +..@flag49 + PIXEL00_2 + PIXEL01_1 + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag64 +..@flag65 +..@flag68 +..@flag69 + PIXEL00_2 + PIXEL01_1 + PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag8 +..@flag12 +..@flag136 +..@flag140 + PIXEL00_1M + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag3 +..@flag35 +..@flag131 +..@flag163 + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_2 + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag6 +..@flag38 +..@flag134 +..@flag166 + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_2 + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag20 +..@flag21 +..@flag52 +..@flag53 + PIXEL00_2 + PIXEL01_1 + PIXEL02_1U + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag144 +..@flag145 +..@flag176 +..@flag177 + PIXEL00_2 + PIXEL01_1 + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag192 +..@flag193 +..@flag196 +..@flag197 + PIXEL00_2 + PIXEL01_1 + PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag96 +..@flag97 +..@flag100 +..@flag101 + PIXEL00_2 + PIXEL01_1 + PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag40 +..@flag44 +..@flag168 +..@flag172 + PIXEL00_1M + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1D + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag9 +..@flag13 +..@flag137 +..@flag141 + PIXEL00_1U + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag18 +..@flag50 + PIXEL00_1M + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_1M,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3 + PIXEL10_1 + PIXEL11 + PIXEL20_2 + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag80 +..@flag81 + PIXEL00_2 + PIXEL01_1 + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL20_1M + DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_1M,PIXEL12_3,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag72 +..@flag76 + PIXEL00_1M + PIXEL01_1 + PIXEL02_2 + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_1M,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3 + PIXEL22_1M + jmp .loopx_end +..@flag10 +..@flag138 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3 + PIXEL02_1M + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag66 + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag24 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag7 +..@flag39 +..@flag135 + PIXEL00_1L + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_2 + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag148 +..@flag149 +..@flag180 + PIXEL00_2 + PIXEL01_1 + PIXEL02_1U + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag224 +..@flag228 +..@flag225 + PIXEL00_2 + PIXEL01_1 + PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag41 +..@flag169 +..@flag45 + PIXEL00_1U + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1D + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag22 +..@flag54 + PIXEL00_1M + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3 + PIXEL10_1 + PIXEL11 + PIXEL20_2 + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag208 +..@flag209 + PIXEL00_2 + PIXEL01_1 + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL20_1M + DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag104 +..@flag108 + PIXEL00_1M + PIXEL01_1 + PIXEL02_2 + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3 + PIXEL22_1M + jmp .loopx_end +..@flag11 +..@flag139 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3 + PIXEL02_1M + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag19 +..@flag51 + DiffOrNot w2,w6,PIXEL00_1L,PIXEL01_C,PIXEL02_1M,PIXEL12_C,PIXEL00_2,PIXEL01_6,PIXEL02_5,PIXEL12_1 + PIXEL10_1 + PIXEL11 + PIXEL20_2 + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag146 +..@flag178 + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_1M,PIXEL12_C,PIXEL22_1D,PIXEL01_1,PIXEL02_5,PIXEL12_6,PIXEL22_2 + PIXEL00_1M + PIXEL10_1 + PIXEL11 + PIXEL20_2 + PIXEL21_1 + jmp .loopx_end +..@flag84 +..@flag85 + DiffOrNot w6,w8,PIXEL02_1U,PIXEL12_C,PIXEL21_C,PIXEL22_1M,PIXEL02_2,PIXEL12_6,PIXEL21_1,PIXEL22_5 + PIXEL00_2 + PIXEL01_1 + PIXEL10_1 + PIXEL11 + PIXEL20_1M + jmp .loopx_end +..@flag112 +..@flag113 + DiffOrNot w6,w8,PIXEL12_C,PIXEL20_1L,PIXEL21_C,PIXEL22_1M,PIXEL12_1,PIXEL20_2,PIXEL21_6,PIXEL22_5 + PIXEL00_2 + PIXEL01_1 + PIXEL02_1M + PIXEL10_1 + PIXEL11 + jmp .loopx_end +..@flag200 +..@flag204 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_1M,PIXEL21_C,PIXEL22_1R,PIXEL10_1,PIXEL20_5,PIXEL21_6,PIXEL22_2 + PIXEL00_1M + PIXEL01_1 + PIXEL02_2 + PIXEL11 + PIXEL12_1 + jmp .loopx_end +..@flag73 +..@flag77 + DiffOrNot w8,w4,PIXEL00_1U,PIXEL10_C,PIXEL20_1M,PIXEL21_C,PIXEL00_2,PIXEL10_6,PIXEL20_5,PIXEL21_1 + PIXEL01_1 + PIXEL02_2 + PIXEL11 + PIXEL12_1 + PIXEL22_1M + jmp .loopx_end +..@flag42 +..@flag170 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL01_C,PIXEL10_C,PIXEL20_1D,PIXEL00_5,PIXEL01_1,PIXEL10_6,PIXEL20_2 + PIXEL02_1M + PIXEL11 + PIXEL12_1 + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag14 +..@flag142 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL01_C,PIXEL02_1R,PIXEL10_C,PIXEL00_5,PIXEL01_6,PIXEL02_2,PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag67 + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag70 + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag28 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag152 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag194 + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag98 + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag56 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag25 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag26 +..@flag31 + DiffOrNot w4,w2,PIXEL00_C,PIXEL10_C,PIXEL00_4,PIXEL10_3 + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_C,PIXEL12_C,PIXEL02_4,PIXEL12_3 + PIXEL11 + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag82 +..@flag214 + PIXEL00_1M + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL01_3,PIXEL02_4 + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1M + DiffOrNot w6,w8,PIXEL21_C,PIXEL22_C,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag88 +..@flag248 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL11 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL10_3,PIXEL20_4 + PIXEL21_C + DiffOrNot w6,w8,PIXEL12_C,PIXEL22_C,PIXEL12_3,PIXEL22_4 + jmp .loopx_end +..@flag74 +..@flag107 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL00_4,PIXEL01_3 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL20_C,PIXEL21_C,PIXEL20_4,PIXEL21_3 + PIXEL22_1M + jmp .loopx_end +..@flag27 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3 + PIXEL02_1M + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag86 + PIXEL00_1M + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3 + PIXEL10_1 + PIXEL11 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag216 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL20_1M + DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag106 + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3 + PIXEL22_1M + jmp .loopx_end +..@flag30 + PIXEL00_1M + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3 + PIXEL10_C + PIXEL11 + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag210 + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL20_1M + DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag120 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3 + PIXEL22_1M + jmp .loopx_end +..@flag75 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3 + PIXEL02_1M + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag29 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag198 + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag184 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag99 + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag57 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag71 + PIXEL00_1L + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag156 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag226 + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag60 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag195 + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag102 + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag153 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag58 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag83 + PIXEL00_1L + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag92 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag202 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + PIXEL01_C + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag78 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + PIXEL01_C + PIXEL02_1R + PIXEL10_C + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag154 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag114 + PIXEL00_1M + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1L + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag89 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag90 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag55 +..@flag23 + DiffOrNot w2,w6,PIXEL00_1L,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL00_2,PIXEL01_6,PIXEL02_5,PIXEL12_1 + PIXEL10_1 + PIXEL11 + PIXEL20_2 + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag182 +..@flag150 + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL22_1D,PIXEL01_1,PIXEL02_5,PIXEL12_6,PIXEL22_2 + PIXEL00_1M + PIXEL10_1 + PIXEL11 + PIXEL20_2 + PIXEL21_1 + jmp .loopx_end +..@flag213 +..@flag212 + DiffOrNot w6,w8,PIXEL02_1U,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL02_2,PIXEL12_6,PIXEL21_1,PIXEL22_5 + PIXEL00_2 + PIXEL01_1 + PIXEL10_1 + PIXEL11 + PIXEL20_1M + jmp .loopx_end +..@flag241 +..@flag240 + DiffOrNot w6,w8,PIXEL12_C,PIXEL20_1L,PIXEL21_C,PIXEL22_C,PIXEL12_1,PIXEL20_2,PIXEL21_6,PIXEL22_5 + PIXEL00_2 + PIXEL01_1 + PIXEL02_1M + PIXEL10_1 + PIXEL11 + jmp .loopx_end +..@flag236 +..@flag232 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL22_1R,PIXEL10_1,PIXEL20_5,PIXEL21_6,PIXEL22_2 + PIXEL00_1M + PIXEL01_1 + PIXEL02_2 + PIXEL11 + PIXEL12_1 + jmp .loopx_end +..@flag109 +..@flag105 + DiffOrNot w8,w4,PIXEL00_1U,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL00_2,PIXEL10_6,PIXEL20_5,PIXEL21_1 + PIXEL01_1 + PIXEL02_2 + PIXEL11 + PIXEL12_1 + PIXEL22_1M + jmp .loopx_end +..@flag171 +..@flag43 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL20_1D,PIXEL00_5,PIXEL01_1,PIXEL10_6,PIXEL20_2 + PIXEL02_1M + PIXEL11 + PIXEL12_1 + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag143 +..@flag15 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL02_1R,PIXEL10_C,PIXEL00_5,PIXEL01_6,PIXEL02_2,PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag124 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3 + PIXEL22_1M + jmp .loopx_end +..@flag203 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3 + PIXEL02_1M + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag62 + PIXEL00_1M + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3 + PIXEL10_C + PIXEL11 + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag211 + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL20_1M + DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag118 + PIXEL00_1M + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3 + PIXEL10_1 + PIXEL11 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag217 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL20_1M + DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag110 + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3 + PIXEL22_1M + jmp .loopx_end +..@flag155 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3 + PIXEL02_1M + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag188 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag185 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag61 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag157 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag103 + PIXEL00_1L + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag227 + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag230 + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag199 + PIXEL00_1L + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag220 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag158 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3 + PIXEL10_C + PIXEL11 + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag234 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + PIXEL01_C + PIXEL02_1M + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3 + PIXEL22_1R + jmp .loopx_end +..@flag242 + PIXEL00_1M + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL20_1L + DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag59 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3 + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag121 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3 + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag87 + PIXEL00_1L + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3 + PIXEL10_1 + PIXEL11 + PIXEL20_1M + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag79 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3 + PIXEL02_1R + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag122 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3 + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag94 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3 + PIXEL10_C + PIXEL11 + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag218 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL10_C + PIXEL11 + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag91 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3 + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag229 + PIXEL00_2 + PIXEL01_1 + PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag167 + PIXEL00_1L + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_2 + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag173 + PIXEL00_1U + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1D + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag181 + PIXEL00_2 + PIXEL01_1 + PIXEL02_1U + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag186 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag115 + PIXEL00_1L + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1L + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag93 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag206 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + PIXEL01_C + PIXEL02_1R + PIXEL10_C + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag205 +..@flag201 + PIXEL00_1U + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag174 +..@flag46 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + PIXEL01_C + PIXEL02_1R + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1D + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag179 +..@flag147 + PIXEL00_1L + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag117 +..@flag116 + PIXEL00_2 + PIXEL01_1 + PIXEL02_1U + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1L + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag189 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag231 + PIXEL00_1L + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag126 + PIXEL00_1M + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3 + PIXEL11 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3 + PIXEL22_1M + jmp .loopx_end +..@flag219 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3 + PIXEL02_1M + PIXEL11 + PIXEL20_1M + DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag125 + DiffOrNot w8,w4,PIXEL00_1U,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL00_2,PIXEL10_6,PIXEL20_5,PIXEL21_1 + PIXEL01_1 + PIXEL02_1U + PIXEL11 + PIXEL12_C + PIXEL22_1M + jmp .loopx_end +..@flag221 + DiffOrNot w6,w8,PIXEL02_1U,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL02_2,PIXEL12_6,PIXEL21_1,PIXEL22_5 + PIXEL00_1U + PIXEL01_1 + PIXEL10_C + PIXEL11 + PIXEL20_1M + jmp .loopx_end +..@flag207 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL02_1R,PIXEL10_C,PIXEL00_5,PIXEL01_6,PIXEL02_2,PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag238 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL22_1R,PIXEL10_1,PIXEL20_5,PIXEL21_6,PIXEL22_2 + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL11 + PIXEL12_1 + jmp .loopx_end +..@flag190 + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL22_1D,PIXEL01_1,PIXEL02_5,PIXEL12_6,PIXEL22_2 + PIXEL00_1M + PIXEL10_C + PIXEL11 + PIXEL20_1D + PIXEL21_1 + jmp .loopx_end +..@flag187 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL20_1D,PIXEL00_5,PIXEL01_1,PIXEL10_6,PIXEL20_2 + PIXEL02_1M + PIXEL11 + PIXEL12_C + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag243 + DiffOrNot w6,w8,PIXEL12_C,PIXEL20_1L,PIXEL21_C,PIXEL22_C,PIXEL12_1,PIXEL20_2,PIXEL21_6,PIXEL22_5 + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + jmp .loopx_end +..@flag119 + DiffOrNot w2,w6,PIXEL00_1L,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL00_2,PIXEL01_6,PIXEL02_5,PIXEL12_1 + PIXEL10_1 + PIXEL11 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag237 +..@flag233 + PIXEL00_1U + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL20_C,PIXEL20_2 + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag175 +..@flag47 + DiffOrNot w4,w2,PIXEL00_C,PIXEL00_2 + PIXEL01_C + PIXEL02_1R + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1D + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag183 +..@flag151 + PIXEL00_1L + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_C,PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag245 +..@flag244 + PIXEL00_2 + PIXEL01_1 + PIXEL02_1U + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1L + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_C,PIXEL22_2 + jmp .loopx_end +..@flag250 + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL11 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL10_3,PIXEL20_4 + PIXEL21_C + DiffOrNot w6,w8,PIXEL12_C,PIXEL22_C,PIXEL12_3,PIXEL22_4 + jmp .loopx_end +..@flag123 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL00_4,PIXEL01_3 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL20_C,PIXEL21_C,PIXEL20_4,PIXEL21_3 + PIXEL22_1M + jmp .loopx_end +..@flag95 + DiffOrNot w4,w2,PIXEL00_C,PIXEL10_C,PIXEL00_4,PIXEL10_3 + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_C,PIXEL12_C,PIXEL02_4,PIXEL12_3 + PIXEL11 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag222 + PIXEL00_1M + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL01_3,PIXEL02_4 + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + DiffOrNot w6,w8,PIXEL21_C,PIXEL22_C,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag252 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL10_3,PIXEL20_4 + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_C,PIXEL22_2 + jmp .loopx_end +..@flag249 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + DiffOrNot w8,w4,PIXEL20_C,PIXEL20_2 + PIXEL21_C + DiffOrNot w6,w8,PIXEL12_C,PIXEL22_C,PIXEL12_3,PIXEL22_4 + jmp .loopx_end +..@flag235 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL00_4,PIXEL01_3 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL20_C,PIXEL20_2 + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag111 + DiffOrNot w4,w2,PIXEL00_C,PIXEL00_2 + PIXEL01_C + PIXEL02_1R + PIXEL10_C + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL20_C,PIXEL21_C,PIXEL20_4,PIXEL21_3 + PIXEL22_1M + jmp .loopx_end +..@flag63 + DiffOrNot w4,w2,PIXEL00_C,PIXEL00_2 + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_C,PIXEL12_C,PIXEL02_4,PIXEL12_3 + PIXEL10_C + PIXEL11 + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag159 + DiffOrNot w4,w2,PIXEL00_C,PIXEL10_C,PIXEL00_4,PIXEL10_3 + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_C,PIXEL02_2 + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag215 + PIXEL00_1L + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_C,PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1M + DiffOrNot w6,w8,PIXEL21_C,PIXEL22_C,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag246 + PIXEL00_1M + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL01_3,PIXEL02_4 + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1L + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_C,PIXEL22_2 + jmp .loopx_end +..@flag254 + PIXEL00_1M + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL01_3,PIXEL02_4 + PIXEL11 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL10_3,PIXEL20_4 + DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_2 + jmp .loopx_end +..@flag253 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL20_C,PIXEL20_2 + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_C,PIXEL22_2 + jmp .loopx_end +..@flag251 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL00_4,PIXEL01_3 + PIXEL02_1M + PIXEL11 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_2,PIXEL21_3 + DiffOrNot w6,w8,PIXEL12_C,PIXEL22_C,PIXEL12_3,PIXEL22_4 + jmp .loopx_end +..@flag239 + DiffOrNot w4,w2,PIXEL00_C,PIXEL00_2 + PIXEL01_C + PIXEL02_1R + PIXEL10_C + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL20_C,PIXEL20_2 + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag127 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_2,PIXEL01_3,PIXEL10_3 + DiffOrNot w2,w6,PIXEL02_C,PIXEL12_C,PIXEL02_4,PIXEL12_3 + PIXEL11 + DiffOrNot w8,w4,PIXEL20_C,PIXEL21_C,PIXEL20_4,PIXEL21_3 + PIXEL22_1M + jmp .loopx_end +..@flag191 + DiffOrNot w4,w2,PIXEL00_C,PIXEL00_2 + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_C,PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag223 + DiffOrNot w4,w2,PIXEL00_C,PIXEL10_C,PIXEL00_4,PIXEL10_3 + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_2,PIXEL12_3 + PIXEL11 + PIXEL20_1M + DiffOrNot w6,w8,PIXEL21_C,PIXEL22_C,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag247 + PIXEL00_1L + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_C,PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1L + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_C,PIXEL22_2 + jmp .loopx_end +..@flag255 + DiffOrNot w4,w2,PIXEL00_C,PIXEL00_2 + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_C,PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL20_C,PIXEL20_2 + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_C,PIXEL22_2 + jmp .loopx_end + +..@cross0 + mov edx,eax + shl eax,16 + or eax,edx + mov [edi],eax + mov [edi+4],ax + mov [edi+ebx],eax + mov [edi+ebx+4],ax + mov [edi+ebx*2],eax + mov [edi+ebx*2+4],ax + jmp .loopx_end +..@cross1 + mov edx,eax + shl eax,16 + or eax,edx + mov ecx,[w2] + and edx,[zerolowbits] + and ecx,[zerolowbits] + add ecx,edx + shr ecx,1 + add ecx,0x0821 + and ecx,[zerolowbits] + add edx,ecx + shr edx,1 + mov [edi],dx + mov [edi+2],dx + mov [edi+4],dx + mov [edi+ebx],eax + mov [edi+ebx+4],ax + mov [edi+ebx*2],eax + mov [edi+ebx*2+4],ax + jmp .loopx_end +..@cross2 + mov edx,eax + shl eax,16 + or eax,edx + mov ecx,[w4] + and edx,[zerolowbits] + and ecx,[zerolowbits] + add ecx,edx + shr ecx,1 + add ecx,0x0821 + and ecx,[zerolowbits] + add edx,ecx + shr edx,1 + mov [edi],dx + mov [edi+2],eax + mov [edi+ebx],dx + mov [edi+ebx+2],eax + mov [edi+ebx*2],dx + mov [edi+ebx*2+2],eax + jmp .loopx_end +..@cross4 + mov edx,eax + shl eax,16 + or eax,edx + mov ecx,[w6] + and edx,[zerolowbits] + and ecx,[zerolowbits] + add ecx,edx + shr ecx,1 + add ecx,0x0821 + and ecx,[zerolowbits] + add edx,ecx + shr edx,1 + mov [edi],eax + mov [edi+4],dx + mov [edi+ebx],eax + mov [edi+ebx+4],dx + mov [edi+ebx*2],eax + mov [edi+ebx*2+4],dx + jmp .loopx_end +..@cross8 + mov edx,eax + shl eax,16 + or eax,edx + mov ecx,[w8] + and edx,[zerolowbits] + and ecx,[zerolowbits] + add ecx,edx + shr ecx,1 + add ecx,0x0821 + and ecx,[zerolowbits] + add edx,ecx + shr edx,1 + mov [edi],eax + mov [edi+4],ax + mov [edi+ebx],eax + mov [edi+ebx+4],ax + mov [edi+ebx*2],dx + mov [edi+ebx*2+2],dx + mov [edi+ebx*2+4],dx + jmp .loopx_end + +.loopx_end + add esi,2 + add edi,6 + dec dword[xcounter] + jz .nexty + jmp .loopx +.nexty + mov dword[firstline],0 + add edi,ebx + add edi,ebx + add esi,[ebp+srcpitch] + dec dword[linesleft] + jz .fin + jmp .loopy +.fin + emms + popad + mov esp,ebp + pop ebp + ret + +SECTION .data +FuncTable + dd ..@flag0, ..@flag1, ..@flag2, ..@flag3, ..@flag4, ..@flag5, ..@flag6, ..@flag7 + dd ..@flag8, ..@flag9, ..@flag10, ..@flag11, ..@flag12, ..@flag13, ..@flag14, ..@flag15 + dd ..@flag16, ..@flag17, ..@flag18, ..@flag19, ..@flag20, ..@flag21, ..@flag22, ..@flag23 + dd ..@flag24, ..@flag25, ..@flag26, ..@flag27, ..@flag28, ..@flag29, ..@flag30, ..@flag31 + dd ..@flag32, ..@flag33, ..@flag34, ..@flag35, ..@flag36, ..@flag37, ..@flag38, ..@flag39 + dd ..@flag40, ..@flag41, ..@flag42, ..@flag43, ..@flag44, ..@flag45, ..@flag46, ..@flag47 + dd ..@flag48, ..@flag49, ..@flag50, ..@flag51, ..@flag52, ..@flag53, ..@flag54, ..@flag55 + dd ..@flag56, ..@flag57, ..@flag58, ..@flag59, ..@flag60, ..@flag61, ..@flag62, ..@flag63 + dd ..@flag64, ..@flag65, ..@flag66, ..@flag67, ..@flag68, ..@flag69, ..@flag70, ..@flag71 + dd ..@flag72, ..@flag73, ..@flag74, ..@flag75, ..@flag76, ..@flag77, ..@flag78, ..@flag79 + dd ..@flag80, ..@flag81, ..@flag82, ..@flag83, ..@flag84, ..@flag85, ..@flag86, ..@flag87 + dd ..@flag88, ..@flag89, ..@flag90, ..@flag91, ..@flag92, ..@flag93, ..@flag94, ..@flag95 + dd ..@flag96, ..@flag97, ..@flag98, ..@flag99, ..@flag100, ..@flag101, ..@flag102, ..@flag103 + dd ..@flag104, ..@flag105, ..@flag106, ..@flag107, ..@flag108, ..@flag109, ..@flag110, ..@flag111 + dd ..@flag112, ..@flag113, ..@flag114, ..@flag115, ..@flag116, ..@flag117, ..@flag118, ..@flag119 + dd ..@flag120, ..@flag121, ..@flag122, ..@flag123, ..@flag124, ..@flag125, ..@flag126, ..@flag127 + dd ..@flag128, ..@flag129, ..@flag130, ..@flag131, ..@flag132, ..@flag133, ..@flag134, ..@flag135 + dd ..@flag136, ..@flag137, ..@flag138, ..@flag139, ..@flag140, ..@flag141, ..@flag142, ..@flag143 + dd ..@flag144, ..@flag145, ..@flag146, ..@flag147, ..@flag148, ..@flag149, ..@flag150, ..@flag151 + dd ..@flag152, ..@flag153, ..@flag154, ..@flag155, ..@flag156, ..@flag157, ..@flag158, ..@flag159 + dd ..@flag160, ..@flag161, ..@flag162, ..@flag163, ..@flag164, ..@flag165, ..@flag166, ..@flag167 + dd ..@flag168, ..@flag169, ..@flag170, ..@flag171, ..@flag172, ..@flag173, ..@flag174, ..@flag175 + dd ..@flag176, ..@flag177, ..@flag178, ..@flag179, ..@flag180, ..@flag181, ..@flag182, ..@flag183 + dd ..@flag184, ..@flag185, ..@flag186, ..@flag187, ..@flag188, ..@flag189, ..@flag190, ..@flag191 + dd ..@flag192, ..@flag193, ..@flag194, ..@flag195, ..@flag196, ..@flag197, ..@flag198, ..@flag199 + dd ..@flag200, ..@flag201, ..@flag202, ..@flag203, ..@flag204, ..@flag205, ..@flag206, ..@flag207 + dd ..@flag208, ..@flag209, ..@flag210, ..@flag211, ..@flag212, ..@flag213, ..@flag214, ..@flag215 + dd ..@flag216, ..@flag217, ..@flag218, ..@flag219, ..@flag220, ..@flag221, ..@flag222, ..@flag223 + dd ..@flag224, ..@flag225, ..@flag226, ..@flag227, ..@flag228, ..@flag229, ..@flag230, ..@flag231 + dd ..@flag232, ..@flag233, ..@flag234, ..@flag235, ..@flag236, ..@flag237, ..@flag238, ..@flag239 + dd ..@flag240, ..@flag241, ..@flag242, ..@flag243, ..@flag244, ..@flag245, ..@flag246, ..@flag247 + dd ..@flag248, ..@flag249, ..@flag250, ..@flag251, ..@flag252, ..@flag253, ..@flag254, ..@flag255 + +FuncTable2 + dd ..@cross0, ..@cross1, ..@cross2, ..@flag0, + dd ..@cross4, ..@flag0, ..@flag0, ..@flag0, + dd ..@cross8, ..@flag0, ..@flag0, ..@flag0, + dd ..@flag0, ..@flag0, ..@flag0, ..@flag0 + diff --git a/od-win32/hq3x32.asm b/od-win32/hq3x32.asm new file mode 100755 index 00000000..6c7e7c83 --- /dev/null +++ b/od-win32/hq3x32.asm @@ -0,0 +1,2472 @@ +;hq3x filter +;---------------------------------------------------------- +;Copyright (C) 2003 MaxSt ( maxst@hiend3d.com ) +; +;This program is free software; you can redistribute it and/or +;modify it under the terms of the GNU General Public License +;as published by the Free Software Foundation; either +;version 2 of the License, or (at your option) any later +;version. +; +;This program is distributed in the hope that it will be useful, +;but WITHOUT ANY WARRANTY; without even the implied warranty of +;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;GNU General Public License for more details. +; +;You should have received a copy of the GNU General Public License +;along with this program; if not, write to the Free Software +;Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +GLOBAL _hq3x_32 + +EXTERN _LUT16to32 +EXTERN _RGBtoYUV + +SECTION .bss +firstline resd 1 +linesleft resd 1 +xcounter resd 1 +cross resd 1 +nextline resd 1 +prevline resd 1 +w1 resd 1 +w2 resd 1 +w3 resd 1 +w4 resd 1 +w5 resd 1 +w6 resd 1 +w7 resd 1 +w8 resd 1 +w9 resd 1 +c1 resd 1 +c2 resd 1 +c3 resd 1 +c4 resd 1 +c5 resd 1 +c6 resd 1 +c7 resd 1 +c8 resd 1 +c9 resd 1 + +SECTION .data + +reg_blank dd 0,0 +const7 dd 0x00070007,0x00000007 +threshold dd 0x00300706,0x00000000 + +SECTION .text + +%macro TestDiff 2 + xor ecx,ecx + mov edx,[%1] + cmp edx,[%2] + je %%fin + mov ecx,_RGBtoYUV + movd mm1,[ecx+edx*4] + movq mm5,mm1 + mov edx,[%2] + movd mm2,[ecx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd ecx,mm1 +%%fin: +%endmacro + +%macro DiffOrNot 4 + TestDiff %1,%2 + test ecx,ecx + jz %%same + %3 + jmp %%fin +%%same: + %4 +%%fin +%endmacro + +%macro DiffOrNot 6 + TestDiff %1,%2 + test ecx,ecx + jz %%same + %3 + %4 + jmp %%fin +%%same: + %5 + %6 +%%fin +%endmacro + +%macro DiffOrNot 8 + TestDiff %1,%2 + test ecx,ecx + jz %%same + %3 + %4 + %5 + jmp %%fin +%%same: + %6 + %7 + %8 +%%fin +%endmacro + +%macro DiffOrNot 10 + TestDiff %1,%2 + test ecx,ecx + jz %%same + %3 + %4 + %5 + %6 + jmp %%fin +%%same: + %7 + %8 + %9 + %10 +%%fin +%endmacro + +%macro Interp1 3 + mov edx,%2 + shl edx,2 + add edx,%3 + sub edx,%2 + shr edx,2 + mov %1,edx +%endmacro + +%macro Interp2 4 + mov edx,%2 + shl edx,1 + add edx,%3 + add edx,%4 + shr edx,2 + mov %1,edx +%endmacro + +%macro Interp3 2 + movd mm1, eax + movd mm2, %2 + punpcklbw mm1, [reg_blank] + punpcklbw mm2, [reg_blank] + pmullw mm1, [const7] + paddw mm1, mm2 + psrlw mm1, 3 + packuswb mm1, [reg_blank] + movd %1, mm1 +%endmacro + +%macro Interp4 3 + movd mm1, eax + movd mm2, %2 + movd mm3, %3 + punpcklbw mm1, [reg_blank] + punpcklbw mm2, [reg_blank] + punpcklbw mm3, [reg_blank] + psllw mm1, 1 + paddw mm2, mm3 + pmullw mm2, [const7] + paddw mm1, mm2 + psrlw mm1, 4 + packuswb mm1, [reg_blank] + movd %1, mm1 +%endmacro + +%macro Interp5 3 + mov edx,%2 + add edx,%3 + shr edx,1 + mov %1,edx +%endmacro + +%macro PIXEL00_1M 0 + Interp1 [edi],eax,[c1] +%endmacro + +%macro PIXEL00_1U 0 + Interp1 [edi],eax,[c2] +%endmacro + +%macro PIXEL00_1L 0 + Interp1 [edi],eax,[c4] +%endmacro + +%macro PIXEL00_2 0 + Interp2 [edi],eax,[c4],[c2] +%endmacro + +%macro PIXEL00_4 0 + Interp4 [edi],[c4],[c2] +%endmacro + +%macro PIXEL00_5 0 + Interp5 [edi],[c4],[c2] +%endmacro + +%macro PIXEL00_C 0 + mov [edi],eax +%endmacro + +%macro PIXEL01_1 0 + Interp1 [edi+4],eax,[c2] +%endmacro + +%macro PIXEL01_3 0 + Interp3 [edi+4],[c2] +%endmacro + +%macro PIXEL01_6 0 + Interp1 [edi+4],[c2],eax +%endmacro + +%macro PIXEL01_C 0 + mov [edi+4],eax +%endmacro + +%macro PIXEL02_1M 0 + Interp1 [edi+8],eax,[c3] +%endmacro + +%macro PIXEL02_1U 0 + Interp1 [edi+8],eax,[c2] +%endmacro + +%macro PIXEL02_1R 0 + Interp1 [edi+8],eax,[c6] +%endmacro + +%macro PIXEL02_2 0 + Interp2 [edi+8],eax,[c2],[c6] +%endmacro + +%macro PIXEL02_4 0 + Interp4 [edi+8],[c2],[c6] +%endmacro + +%macro PIXEL02_5 0 + Interp5 [edi+8],[c2],[c6] +%endmacro + +%macro PIXEL02_C 0 + mov [edi+8],eax +%endmacro + +%macro PIXEL10_1 0 + Interp1 [edi+ebx],eax,[c4] +%endmacro + +%macro PIXEL10_3 0 + Interp3 [edi+ebx],[c4] +%endmacro + +%macro PIXEL10_6 0 + Interp1 [edi+ebx],[c4],eax +%endmacro + +%macro PIXEL10_C 0 + mov [edi+ebx],eax +%endmacro + +%macro PIXEL11 0 + mov [edi+ebx+4],eax +%endmacro + +%macro PIXEL12_1 0 + Interp1 [edi+ebx+8],eax,[c6] +%endmacro + +%macro PIXEL12_3 0 + Interp3 [edi+ebx+8],[c6] +%endmacro + +%macro PIXEL12_6 0 + Interp1 [edi+ebx+8],[c6],eax +%endmacro + +%macro PIXEL12_C 0 + mov [edi+ebx+8],eax +%endmacro + +%macro PIXEL20_1M 0 + Interp1 [edi+ebx*2],eax,[c7] +%endmacro + +%macro PIXEL20_1D 0 + Interp1 [edi+ebx*2],eax,[c8] +%endmacro + +%macro PIXEL20_1L 0 + Interp1 [edi+ebx*2],eax,[c4] +%endmacro + +%macro PIXEL20_2 0 + Interp2 [edi+ebx*2],eax,[c8],[c4] +%endmacro + +%macro PIXEL20_4 0 + Interp4 [edi+ebx*2],[c8],[c4] +%endmacro + +%macro PIXEL20_5 0 + Interp5 [edi+ebx*2],[c8],[c4] +%endmacro + +%macro PIXEL20_C 0 + mov [edi+ebx*2],eax +%endmacro + +%macro PIXEL21_1 0 + Interp1 [edi+ebx*2+4],eax,[c8] +%endmacro + +%macro PIXEL21_3 0 + Interp3 [edi+ebx*2+4],[c8] +%endmacro + +%macro PIXEL21_6 0 + Interp1 [edi+ebx*2+4],[c8],eax +%endmacro + +%macro PIXEL21_C 0 + mov [edi+ebx*2+4],eax +%endmacro + +%macro PIXEL22_1M 0 + Interp1 [edi+ebx*2+8],eax,[c9] +%endmacro + +%macro PIXEL22_1D 0 + Interp1 [edi+ebx*2+8],eax,[c8] +%endmacro + +%macro PIXEL22_1R 0 + Interp1 [edi+ebx*2+8],eax,[c6] +%endmacro + +%macro PIXEL22_2 0 + Interp2 [edi+ebx*2+8],eax,[c6],[c8] +%endmacro + +%macro PIXEL22_4 0 + Interp4 [edi+ebx*2+8],[c6],[c8] +%endmacro + +%macro PIXEL22_5 0 + Interp5 [edi+ebx*2+8],[c6],[c8] +%endmacro + +%macro PIXEL22_C 0 + mov [edi+ebx*2+8],eax +%endmacro + +inbuffer equ 8 +outbuffer equ 12 +Xres equ 16 +Yres equ 20 +dstpitch equ 24 +srcpitch equ 28 +dstpitch2 equ 32 + +_hq3x_32: + push ebp + mov ebp,esp + pushad + + mov esi,[ebp+inbuffer] + mov edi,[ebp+outbuffer] + mov edx,[ebp+Yres] + mov [linesleft],edx + mov dword[firstline],1 +.loopy + mov ebx,[ebp+Xres] + shl ebx,1 + movzx eax,word[esi] + mov [w5],eax + mov [w6],eax + mov edx,eax + xor ecx,ecx + cmp dword[firstline],1 + je .firstline + sub ecx,ebx + movzx eax,word[esi+ecx] +.firstline + mov [prevline],ecx + mov [w2],eax + mov [w3],eax + xor ecx,ecx + cmp dword[linesleft],1 + je .lastline + add ecx,ebx + movzx edx,word[esi+ecx] +.lastline + mov [nextline],ecx + mov [w8],edx + mov [w9],edx + mov ecx,[ebp+Xres] + mov dword[xcounter],ecx +.loopx + mov eax,[w2] + mov ebx,[w5] + mov edx,[w8] + mov [w1],eax + mov [w4],ebx + mov [w7],edx + mov eax,[w3] + mov ebx,[w6] + mov edx,[w9] + mov [w2],eax + mov [w5],ebx + mov [w8],edx + cmp dword[xcounter],1 + je .flags + movzx eax,word[esi+2] + mov [w6],eax + mov ebx,[prevline] + movzx edx,word[esi+ebx+2] + mov [w3],edx + mov ebx,[nextline] + movzx eax,word[esi+ebx+2] + mov [w9],eax +.flags + mov ebx,_RGBtoYUV + mov eax,[w5] + xor ecx,ecx + movd mm5,[ebx+eax*4] + mov dword[cross],0 + + mov edx,[w2] + cmp eax,edx + je .noflag2 + or dword[cross],1 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag2 + or ecx,2 +.noflag2 + mov edx,[w4] + cmp eax,edx + je .noflag4 + or dword[cross],2 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag4 + or ecx,8 +.noflag4 + mov edx,[w6] + cmp eax,edx + je .noflag6 + or dword[cross],4 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag6 + or ecx,16 +.noflag6 + mov edx,[w8] + cmp eax,edx + je .noflag8 + or dword[cross],8 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag8 + or ecx,64 +.noflag8 + test ecx,ecx + jnz .testflag1 + mov ecx,[cross] + mov ebx,_LUT16to32 + mov eax,[ebx+eax*4] + jmp [FuncTable2+ecx*4] +.testflag1 + mov edx,[w1] + cmp eax,edx + je .noflag1 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag1 + or ecx,1 +.noflag1 + mov edx,[w3] + cmp eax,edx + je .noflag3 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag3 + or ecx,4 +.noflag3 + mov edx,[w7] + cmp eax,edx + je .noflag7 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag7 + or ecx,32 +.noflag7 + mov edx,[w9] + cmp eax,edx + je .noflag9 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag9 + or ecx,128 +.noflag9 + mov ebx,_LUT16to32 + mov eax,[ebx+eax*4] + mov edx,[w2] + mov edx,[ebx+edx*4] + mov [c2],edx + mov edx,[w4] + mov edx,[ebx+edx*4] + mov [c4],edx + mov edx,[w6] + mov edx,[ebx+edx*4] + mov [c6],edx + mov edx,[w8] + mov edx,[ebx+edx*4] + mov [c8],edx + test ecx,0x005A + jz .switch + mov edx,[w1] + mov edx,[ebx+edx*4] + mov [c1],edx + mov edx,[w3] + mov edx,[ebx+edx*4] + mov [c3],edx + mov edx,[w7] + mov edx,[ebx+edx*4] + mov [c7],edx + mov edx,[w9] + mov edx,[ebx+edx*4] + mov [c9],edx +.switch + mov ebx,[ebp+dstpitch] + jmp [FuncTable+ecx*4] + +..@flag0 +..@flag1 +..@flag4 +..@flag32 +..@flag128 +..@flag5 +..@flag132 +..@flag160 +..@flag33 +..@flag129 +..@flag36 +..@flag133 +..@flag164 +..@flag161 +..@flag37 +..@flag165 +; PIXEL00_2 +; PIXEL01_1 +; PIXEL02_2 +; PIXEL10_1 +; PIXEL11 +; PIXEL12_1 +; PIXEL20_2 +; PIXEL21_1 +; PIXEL22_2 + +; the same, only optimized + mov ecx,eax + shl ecx,1 + add ecx,[c2] + mov edx,ecx + add edx,[c4] + shr edx,2 + mov [edi],edx + mov edx,ecx + add edx,eax + shr edx,2 + mov [edi+4],edx + add ecx,[c6] + shr ecx,2 + mov [edi+8],ecx + mov ecx,eax + shl ecx,2 + sub ecx,eax + mov edx,ecx + add edx,[c4] + shr edx,2 + mov [edi+ebx],edx + mov [edi+ebx+4],eax + add ecx,[c6] + shr ecx,2 + mov [edi+ebx+8],ecx + mov ecx,eax + shl ecx,1 + add ecx,[c8] + mov edx,ecx + add edx,[c4] + shr edx,2 + mov [edi+ebx*2],edx + mov edx,ecx + add edx,eax + shr edx,2 + mov [edi+ebx*2+4],edx + add ecx,[c6] + shr ecx,2 + mov [edi+ebx*2+8],ecx + jmp .loopx_end +..@flag2 +..@flag34 +..@flag130 +..@flag162 + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_2 + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag16 +..@flag17 +..@flag48 +..@flag49 + PIXEL00_2 + PIXEL01_1 + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag64 +..@flag65 +..@flag68 +..@flag69 + PIXEL00_2 + PIXEL01_1 + PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag8 +..@flag12 +..@flag136 +..@flag140 + PIXEL00_1M + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag3 +..@flag35 +..@flag131 +..@flag163 + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_2 + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag6 +..@flag38 +..@flag134 +..@flag166 + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_2 + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag20 +..@flag21 +..@flag52 +..@flag53 + PIXEL00_2 + PIXEL01_1 + PIXEL02_1U + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag144 +..@flag145 +..@flag176 +..@flag177 + PIXEL00_2 + PIXEL01_1 + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag192 +..@flag193 +..@flag196 +..@flag197 + PIXEL00_2 + PIXEL01_1 + PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag96 +..@flag97 +..@flag100 +..@flag101 + PIXEL00_2 + PIXEL01_1 + PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag40 +..@flag44 +..@flag168 +..@flag172 + PIXEL00_1M + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1D + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag9 +..@flag13 +..@flag137 +..@flag141 + PIXEL00_1U + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag18 +..@flag50 + PIXEL00_1M + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_1M,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3 + PIXEL10_1 + PIXEL11 + PIXEL20_2 + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag80 +..@flag81 + PIXEL00_2 + PIXEL01_1 + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL20_1M + DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_1M,PIXEL12_3,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag72 +..@flag76 + PIXEL00_1M + PIXEL01_1 + PIXEL02_2 + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_1M,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3 + PIXEL22_1M + jmp .loopx_end +..@flag10 +..@flag138 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3 + PIXEL02_1M + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag66 + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag24 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag7 +..@flag39 +..@flag135 + PIXEL00_1L + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_2 + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag148 +..@flag149 +..@flag180 + PIXEL00_2 + PIXEL01_1 + PIXEL02_1U + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag224 +..@flag228 +..@flag225 + PIXEL00_2 + PIXEL01_1 + PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag41 +..@flag169 +..@flag45 + PIXEL00_1U + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1D + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag22 +..@flag54 + PIXEL00_1M + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3 + PIXEL10_1 + PIXEL11 + PIXEL20_2 + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag208 +..@flag209 + PIXEL00_2 + PIXEL01_1 + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL20_1M + DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag104 +..@flag108 + PIXEL00_1M + PIXEL01_1 + PIXEL02_2 + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3 + PIXEL22_1M + jmp .loopx_end +..@flag11 +..@flag139 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3 + PIXEL02_1M + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag19 +..@flag51 + DiffOrNot w2,w6,PIXEL00_1L,PIXEL01_C,PIXEL02_1M,PIXEL12_C,PIXEL00_2,PIXEL01_6,PIXEL02_5,PIXEL12_1 + PIXEL10_1 + PIXEL11 + PIXEL20_2 + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag146 +..@flag178 + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_1M,PIXEL12_C,PIXEL22_1D,PIXEL01_1,PIXEL02_5,PIXEL12_6,PIXEL22_2 + PIXEL00_1M + PIXEL10_1 + PIXEL11 + PIXEL20_2 + PIXEL21_1 + jmp .loopx_end +..@flag84 +..@flag85 + DiffOrNot w6,w8,PIXEL02_1U,PIXEL12_C,PIXEL21_C,PIXEL22_1M,PIXEL02_2,PIXEL12_6,PIXEL21_1,PIXEL22_5 + PIXEL00_2 + PIXEL01_1 + PIXEL10_1 + PIXEL11 + PIXEL20_1M + jmp .loopx_end +..@flag112 +..@flag113 + DiffOrNot w6,w8,PIXEL12_C,PIXEL20_1L,PIXEL21_C,PIXEL22_1M,PIXEL12_1,PIXEL20_2,PIXEL21_6,PIXEL22_5 + PIXEL00_2 + PIXEL01_1 + PIXEL02_1M + PIXEL10_1 + PIXEL11 + jmp .loopx_end +..@flag200 +..@flag204 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_1M,PIXEL21_C,PIXEL22_1R,PIXEL10_1,PIXEL20_5,PIXEL21_6,PIXEL22_2 + PIXEL00_1M + PIXEL01_1 + PIXEL02_2 + PIXEL11 + PIXEL12_1 + jmp .loopx_end +..@flag73 +..@flag77 + DiffOrNot w8,w4,PIXEL00_1U,PIXEL10_C,PIXEL20_1M,PIXEL21_C,PIXEL00_2,PIXEL10_6,PIXEL20_5,PIXEL21_1 + PIXEL01_1 + PIXEL02_2 + PIXEL11 + PIXEL12_1 + PIXEL22_1M + jmp .loopx_end +..@flag42 +..@flag170 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL01_C,PIXEL10_C,PIXEL20_1D,PIXEL00_5,PIXEL01_1,PIXEL10_6,PIXEL20_2 + PIXEL02_1M + PIXEL11 + PIXEL12_1 + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag14 +..@flag142 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL01_C,PIXEL02_1R,PIXEL10_C,PIXEL00_5,PIXEL01_6,PIXEL02_2,PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag67 + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag70 + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag28 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag152 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag194 + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag98 + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag56 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag25 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag26 +..@flag31 + DiffOrNot w4,w2,PIXEL00_C,PIXEL10_C,PIXEL00_4,PIXEL10_3 + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_C,PIXEL12_C,PIXEL02_4,PIXEL12_3 + PIXEL11 + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag82 +..@flag214 + PIXEL00_1M + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL01_3,PIXEL02_4 + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1M + DiffOrNot w6,w8,PIXEL21_C,PIXEL22_C,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag88 +..@flag248 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL11 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL10_3,PIXEL20_4 + PIXEL21_C + DiffOrNot w6,w8,PIXEL12_C,PIXEL22_C,PIXEL12_3,PIXEL22_4 + jmp .loopx_end +..@flag74 +..@flag107 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL00_4,PIXEL01_3 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL20_C,PIXEL21_C,PIXEL20_4,PIXEL21_3 + PIXEL22_1M + jmp .loopx_end +..@flag27 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3 + PIXEL02_1M + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag86 + PIXEL00_1M + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3 + PIXEL10_1 + PIXEL11 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag216 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL20_1M + DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag106 + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3 + PIXEL22_1M + jmp .loopx_end +..@flag30 + PIXEL00_1M + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3 + PIXEL10_C + PIXEL11 + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag210 + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL20_1M + DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag120 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3 + PIXEL22_1M + jmp .loopx_end +..@flag75 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3 + PIXEL02_1M + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag29 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag198 + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag184 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag99 + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag57 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag71 + PIXEL00_1L + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag156 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag226 + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag60 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag195 + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag102 + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag153 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag58 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag83 + PIXEL00_1L + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag92 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag202 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + PIXEL01_C + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag78 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + PIXEL01_C + PIXEL02_1R + PIXEL10_C + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag154 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag114 + PIXEL00_1M + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1L + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag89 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag90 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag55 +..@flag23 + DiffOrNot w2,w6,PIXEL00_1L,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL00_2,PIXEL01_6,PIXEL02_5,PIXEL12_1 + PIXEL10_1 + PIXEL11 + PIXEL20_2 + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag182 +..@flag150 + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL22_1D,PIXEL01_1,PIXEL02_5,PIXEL12_6,PIXEL22_2 + PIXEL00_1M + PIXEL10_1 + PIXEL11 + PIXEL20_2 + PIXEL21_1 + jmp .loopx_end +..@flag213 +..@flag212 + DiffOrNot w6,w8,PIXEL02_1U,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL02_2,PIXEL12_6,PIXEL21_1,PIXEL22_5 + PIXEL00_2 + PIXEL01_1 + PIXEL10_1 + PIXEL11 + PIXEL20_1M + jmp .loopx_end +..@flag241 +..@flag240 + DiffOrNot w6,w8,PIXEL12_C,PIXEL20_1L,PIXEL21_C,PIXEL22_C,PIXEL12_1,PIXEL20_2,PIXEL21_6,PIXEL22_5 + PIXEL00_2 + PIXEL01_1 + PIXEL02_1M + PIXEL10_1 + PIXEL11 + jmp .loopx_end +..@flag236 +..@flag232 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL22_1R,PIXEL10_1,PIXEL20_5,PIXEL21_6,PIXEL22_2 + PIXEL00_1M + PIXEL01_1 + PIXEL02_2 + PIXEL11 + PIXEL12_1 + jmp .loopx_end +..@flag109 +..@flag105 + DiffOrNot w8,w4,PIXEL00_1U,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL00_2,PIXEL10_6,PIXEL20_5,PIXEL21_1 + PIXEL01_1 + PIXEL02_2 + PIXEL11 + PIXEL12_1 + PIXEL22_1M + jmp .loopx_end +..@flag171 +..@flag43 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL20_1D,PIXEL00_5,PIXEL01_1,PIXEL10_6,PIXEL20_2 + PIXEL02_1M + PIXEL11 + PIXEL12_1 + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag143 +..@flag15 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL02_1R,PIXEL10_C,PIXEL00_5,PIXEL01_6,PIXEL02_2,PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag124 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3 + PIXEL22_1M + jmp .loopx_end +..@flag203 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3 + PIXEL02_1M + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag62 + PIXEL00_1M + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3 + PIXEL10_C + PIXEL11 + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag211 + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL20_1M + DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag118 + PIXEL00_1M + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3 + PIXEL10_1 + PIXEL11 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag217 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL20_1M + DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag110 + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3 + PIXEL22_1M + jmp .loopx_end +..@flag155 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3 + PIXEL02_1M + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag188 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag185 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag61 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag157 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag103 + PIXEL00_1L + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag227 + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag230 + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag199 + PIXEL00_1L + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag220 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag158 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3 + PIXEL10_C + PIXEL11 + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag234 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + PIXEL01_C + PIXEL02_1M + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3 + PIXEL22_1R + jmp .loopx_end +..@flag242 + PIXEL00_1M + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL20_1L + DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag59 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3 + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag121 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3 + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag87 + PIXEL00_1L + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3 + PIXEL10_1 + PIXEL11 + PIXEL20_1M + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag79 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3 + PIXEL02_1R + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag122 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3 + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag94 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3 + PIXEL10_C + PIXEL11 + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag218 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL10_C + PIXEL11 + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag91 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3 + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag229 + PIXEL00_2 + PIXEL01_1 + PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag167 + PIXEL00_1L + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_2 + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag173 + PIXEL00_1U + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1D + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag181 + PIXEL00_2 + PIXEL01_1 + PIXEL02_1U + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag186 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag115 + PIXEL00_1L + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1L + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag93 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag206 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + PIXEL01_C + PIXEL02_1R + PIXEL10_C + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag205 +..@flag201 + PIXEL00_1U + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL20_1M,PIXEL20_2 + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag174 +..@flag46 + DiffOrNot w4,w2,PIXEL00_1M,PIXEL00_2 + PIXEL01_C + PIXEL02_1R + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1D + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag179 +..@flag147 + PIXEL00_1L + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_1M,PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag117 +..@flag116 + PIXEL00_2 + PIXEL01_1 + PIXEL02_1U + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1L + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_1M,PIXEL22_2 + jmp .loopx_end +..@flag189 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag231 + PIXEL00_1L + PIXEL01_C + PIXEL02_1R + PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1L + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag126 + PIXEL00_1M + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_4,PIXEL12_3 + PIXEL11 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_4,PIXEL21_3 + PIXEL22_1M + jmp .loopx_end +..@flag219 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_4,PIXEL01_3,PIXEL10_3 + PIXEL02_1M + PIXEL11 + PIXEL20_1M + DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag125 + DiffOrNot w8,w4,PIXEL00_1U,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL00_2,PIXEL10_6,PIXEL20_5,PIXEL21_1 + PIXEL01_1 + PIXEL02_1U + PIXEL11 + PIXEL12_C + PIXEL22_1M + jmp .loopx_end +..@flag221 + DiffOrNot w6,w8,PIXEL02_1U,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL02_2,PIXEL12_6,PIXEL21_1,PIXEL22_5 + PIXEL00_1U + PIXEL01_1 + PIXEL10_C + PIXEL11 + PIXEL20_1M + jmp .loopx_end +..@flag207 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL02_1R,PIXEL10_C,PIXEL00_5,PIXEL01_6,PIXEL02_2,PIXEL10_1 + PIXEL11 + PIXEL12_1 + PIXEL20_1M + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag238 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL22_1R,PIXEL10_1,PIXEL20_5,PIXEL21_6,PIXEL22_2 + PIXEL00_1M + PIXEL01_C + PIXEL02_1R + PIXEL11 + PIXEL12_1 + jmp .loopx_end +..@flag190 + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL22_1D,PIXEL01_1,PIXEL02_5,PIXEL12_6,PIXEL22_2 + PIXEL00_1M + PIXEL10_C + PIXEL11 + PIXEL20_1D + PIXEL21_1 + jmp .loopx_end +..@flag187 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL20_1D,PIXEL00_5,PIXEL01_1,PIXEL10_6,PIXEL20_2 + PIXEL02_1M + PIXEL11 + PIXEL12_C + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag243 + DiffOrNot w6,w8,PIXEL12_C,PIXEL20_1L,PIXEL21_C,PIXEL22_C,PIXEL12_1,PIXEL20_2,PIXEL21_6,PIXEL22_5 + PIXEL00_1L + PIXEL01_C + PIXEL02_1M + PIXEL10_1 + PIXEL11 + jmp .loopx_end +..@flag119 + DiffOrNot w2,w6,PIXEL00_1L,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL00_2,PIXEL01_6,PIXEL02_5,PIXEL12_1 + PIXEL10_1 + PIXEL11 + PIXEL20_1L + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag237 +..@flag233 + PIXEL00_1U + PIXEL01_1 + PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL20_C,PIXEL20_2 + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag175 +..@flag47 + DiffOrNot w4,w2,PIXEL00_C,PIXEL00_2 + PIXEL01_C + PIXEL02_1R + PIXEL10_C + PIXEL11 + PIXEL12_1 + PIXEL20_1D + PIXEL21_1 + PIXEL22_2 + jmp .loopx_end +..@flag183 +..@flag151 + PIXEL00_1L + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_C,PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_2 + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag245 +..@flag244 + PIXEL00_2 + PIXEL01_1 + PIXEL02_1U + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1L + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_C,PIXEL22_2 + jmp .loopx_end +..@flag250 + PIXEL00_1M + PIXEL01_C + PIXEL02_1M + PIXEL11 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL10_3,PIXEL20_4 + PIXEL21_C + DiffOrNot w6,w8,PIXEL12_C,PIXEL22_C,PIXEL12_3,PIXEL22_4 + jmp .loopx_end +..@flag123 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL00_4,PIXEL01_3 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL20_C,PIXEL21_C,PIXEL20_4,PIXEL21_3 + PIXEL22_1M + jmp .loopx_end +..@flag95 + DiffOrNot w4,w2,PIXEL00_C,PIXEL10_C,PIXEL00_4,PIXEL10_3 + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_C,PIXEL12_C,PIXEL02_4,PIXEL12_3 + PIXEL11 + PIXEL20_1M + PIXEL21_C + PIXEL22_1M + jmp .loopx_end +..@flag222 + PIXEL00_1M + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL01_3,PIXEL02_4 + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1M + DiffOrNot w6,w8,PIXEL21_C,PIXEL22_C,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag252 + PIXEL00_1M + PIXEL01_1 + PIXEL02_1U + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL10_3,PIXEL20_4 + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_C,PIXEL22_2 + jmp .loopx_end +..@flag249 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1M + PIXEL10_C + PIXEL11 + DiffOrNot w8,w4,PIXEL20_C,PIXEL20_2 + PIXEL21_C + DiffOrNot w6,w8,PIXEL12_C,PIXEL22_C,PIXEL12_3,PIXEL22_4 + jmp .loopx_end +..@flag235 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL00_4,PIXEL01_3 + PIXEL02_1M + PIXEL10_C + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL20_C,PIXEL20_2 + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag111 + DiffOrNot w4,w2,PIXEL00_C,PIXEL00_2 + PIXEL01_C + PIXEL02_1R + PIXEL10_C + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL20_C,PIXEL21_C,PIXEL20_4,PIXEL21_3 + PIXEL22_1M + jmp .loopx_end +..@flag63 + DiffOrNot w4,w2,PIXEL00_C,PIXEL00_2 + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_C,PIXEL12_C,PIXEL02_4,PIXEL12_3 + PIXEL10_C + PIXEL11 + PIXEL20_1D + PIXEL21_1 + PIXEL22_1M + jmp .loopx_end +..@flag159 + DiffOrNot w4,w2,PIXEL00_C,PIXEL10_C,PIXEL00_4,PIXEL10_3 + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_C,PIXEL02_2 + PIXEL11 + PIXEL12_C + PIXEL20_1M + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag215 + PIXEL00_1L + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_C,PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1M + DiffOrNot w6,w8,PIXEL21_C,PIXEL22_C,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag246 + PIXEL00_1M + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL01_3,PIXEL02_4 + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1L + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_C,PIXEL22_2 + jmp .loopx_end +..@flag254 + PIXEL00_1M + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL01_3,PIXEL02_4 + PIXEL11 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL10_3,PIXEL20_4 + DiffOrNot w6,w8,PIXEL12_C,PIXEL21_C,PIXEL22_C,PIXEL12_3,PIXEL21_3,PIXEL22_2 + jmp .loopx_end +..@flag253 + PIXEL00_1U + PIXEL01_1 + PIXEL02_1U + PIXEL10_C + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL20_C,PIXEL20_2 + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_C,PIXEL22_2 + jmp .loopx_end +..@flag251 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL00_4,PIXEL01_3 + PIXEL02_1M + PIXEL11 + DiffOrNot w8,w4,PIXEL10_C,PIXEL20_C,PIXEL21_C,PIXEL10_3,PIXEL20_2,PIXEL21_3 + DiffOrNot w6,w8,PIXEL12_C,PIXEL22_C,PIXEL12_3,PIXEL22_4 + jmp .loopx_end +..@flag239 + DiffOrNot w4,w2,PIXEL00_C,PIXEL00_2 + PIXEL01_C + PIXEL02_1R + PIXEL10_C + PIXEL11 + PIXEL12_1 + DiffOrNot w8,w4,PIXEL20_C,PIXEL20_2 + PIXEL21_C + PIXEL22_1R + jmp .loopx_end +..@flag127 + DiffOrNot w4,w2,PIXEL00_C,PIXEL01_C,PIXEL10_C,PIXEL00_2,PIXEL01_3,PIXEL10_3 + DiffOrNot w2,w6,PIXEL02_C,PIXEL12_C,PIXEL02_4,PIXEL12_3 + PIXEL11 + DiffOrNot w8,w4,PIXEL20_C,PIXEL21_C,PIXEL20_4,PIXEL21_3 + PIXEL22_1M + jmp .loopx_end +..@flag191 + DiffOrNot w4,w2,PIXEL00_C,PIXEL00_2 + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_C,PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_C + PIXEL20_1D + PIXEL21_1 + PIXEL22_1D + jmp .loopx_end +..@flag223 + DiffOrNot w4,w2,PIXEL00_C,PIXEL10_C,PIXEL00_4,PIXEL10_3 + DiffOrNot w2,w6,PIXEL01_C,PIXEL02_C,PIXEL12_C,PIXEL01_3,PIXEL02_2,PIXEL12_3 + PIXEL11 + PIXEL20_1M + DiffOrNot w6,w8,PIXEL21_C,PIXEL22_C,PIXEL21_3,PIXEL22_4 + jmp .loopx_end +..@flag247 + PIXEL00_1L + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_C,PIXEL02_2 + PIXEL10_1 + PIXEL11 + PIXEL12_C + PIXEL20_1L + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_C,PIXEL22_2 + jmp .loopx_end +..@flag255 + DiffOrNot w4,w2,PIXEL00_C,PIXEL00_2 + PIXEL01_C + DiffOrNot w2,w6,PIXEL02_C,PIXEL02_2 + PIXEL10_C + PIXEL11 + PIXEL12_C + DiffOrNot w8,w4,PIXEL20_C,PIXEL20_2 + PIXEL21_C + DiffOrNot w6,w8,PIXEL22_C,PIXEL22_2 + jmp .loopx_end + +..@cross0 + mov ebx,[ebp+dstpitch] + mov [edi],eax + mov [edi+4],eax + mov [edi+8],eax + mov [edi+ebx],eax + mov [edi+ebx+4],eax + mov [edi+ebx+8],eax + mov [edi+ebx*2],eax + mov [edi+ebx*2+4],eax + mov [edi+ebx*2+8],eax + jmp .loopx_end +..@cross1 + mov ecx,[w2] + mov edx,eax + shl edx,2 + add edx,[ebx+ecx*4] + sub edx,eax + shr edx,2 + mov ebx,[ebp+dstpitch] + mov [edi],edx + mov [edi+4],edx + mov [edi+8],edx + mov [edi+ebx],eax + mov [edi+ebx+4],eax + mov [edi+ebx+8],eax + mov [edi+ebx*2],eax + mov [edi+ebx*2+4],eax + mov [edi+ebx*2+8],eax + jmp .loopx_end +..@cross2 + mov ecx,[w4] + mov edx,eax + shl edx,2 + add edx,[ebx+ecx*4] + sub edx,eax + shr edx,2 + mov ebx,[ebp+dstpitch] + mov [edi],edx + mov [edi+4],eax + mov [edi+8],eax + mov [edi+ebx],edx + mov [edi+ebx+4],eax + mov [edi+ebx+8],eax + mov [edi+ebx*2],edx + mov [edi+ebx*2+4],eax + mov [edi+ebx*2+8],eax + jmp .loopx_end +..@cross4 + mov ecx,[w6] + mov edx,eax + shl edx,2 + add edx,[ebx+ecx*4] + sub edx,eax + shr edx,2 + mov ebx,[ebp+dstpitch] + mov [edi],eax + mov [edi+4],eax + mov [edi+8],edx + mov [edi+ebx],eax + mov [edi+ebx+4],eax + mov [edi+ebx+8],edx + mov [edi+ebx*2],eax + mov [edi+ebx*2+4],eax + mov [edi+ebx*2+8],edx + jmp .loopx_end +..@cross8 + mov ecx,[w8] + mov edx,eax + shl edx,2 + add edx,[ebx+ecx*4] + sub edx,eax + shr edx,2 + mov ebx,[ebp+dstpitch] + mov [edi],eax + mov [edi+4],eax + mov [edi+8],eax + mov [edi+ebx],eax + mov [edi+ebx+4],eax + mov [edi+ebx+8],eax + mov [edi+ebx*2],edx + mov [edi+ebx*2+4],edx + mov [edi+ebx*2+8],edx + jmp .loopx_end +..@crossN + mov edx,[w2] + mov ecx,[ebx+edx*4] + mov [c2],ecx + mov edx,[w4] + mov ecx,[ebx+edx*4] + mov [c4],ecx + mov edx,[w6] + mov ecx,[ebx+edx*4] + mov [c6],ecx + mov edx,[w8] + mov ecx,[ebx+edx*4] + mov [c8],ecx + mov ebx,[ebp+dstpitch] + jmp ..@flag0 + +.loopx_end + add esi,2 + add edi,12 + dec dword[xcounter] + jz .nexty + jmp .loopx +.nexty + mov dword[firstline],0 + add esi,[ebp+srcpitch] + add edi,[ebp+dstpitch2] + dec dword[linesleft] + jz .fin + jmp .loopy +.fin + emms + popad + mov esp,ebp + pop ebp + ret + +SECTION .data +FuncTable + dd ..@flag0, ..@flag1, ..@flag2, ..@flag3, ..@flag4, ..@flag5, ..@flag6, ..@flag7 + dd ..@flag8, ..@flag9, ..@flag10, ..@flag11, ..@flag12, ..@flag13, ..@flag14, ..@flag15 + dd ..@flag16, ..@flag17, ..@flag18, ..@flag19, ..@flag20, ..@flag21, ..@flag22, ..@flag23 + dd ..@flag24, ..@flag25, ..@flag26, ..@flag27, ..@flag28, ..@flag29, ..@flag30, ..@flag31 + dd ..@flag32, ..@flag33, ..@flag34, ..@flag35, ..@flag36, ..@flag37, ..@flag38, ..@flag39 + dd ..@flag40, ..@flag41, ..@flag42, ..@flag43, ..@flag44, ..@flag45, ..@flag46, ..@flag47 + dd ..@flag48, ..@flag49, ..@flag50, ..@flag51, ..@flag52, ..@flag53, ..@flag54, ..@flag55 + dd ..@flag56, ..@flag57, ..@flag58, ..@flag59, ..@flag60, ..@flag61, ..@flag62, ..@flag63 + dd ..@flag64, ..@flag65, ..@flag66, ..@flag67, ..@flag68, ..@flag69, ..@flag70, ..@flag71 + dd ..@flag72, ..@flag73, ..@flag74, ..@flag75, ..@flag76, ..@flag77, ..@flag78, ..@flag79 + dd ..@flag80, ..@flag81, ..@flag82, ..@flag83, ..@flag84, ..@flag85, ..@flag86, ..@flag87 + dd ..@flag88, ..@flag89, ..@flag90, ..@flag91, ..@flag92, ..@flag93, ..@flag94, ..@flag95 + dd ..@flag96, ..@flag97, ..@flag98, ..@flag99, ..@flag100, ..@flag101, ..@flag102, ..@flag103 + dd ..@flag104, ..@flag105, ..@flag106, ..@flag107, ..@flag108, ..@flag109, ..@flag110, ..@flag111 + dd ..@flag112, ..@flag113, ..@flag114, ..@flag115, ..@flag116, ..@flag117, ..@flag118, ..@flag119 + dd ..@flag120, ..@flag121, ..@flag122, ..@flag123, ..@flag124, ..@flag125, ..@flag126, ..@flag127 + dd ..@flag128, ..@flag129, ..@flag130, ..@flag131, ..@flag132, ..@flag133, ..@flag134, ..@flag135 + dd ..@flag136, ..@flag137, ..@flag138, ..@flag139, ..@flag140, ..@flag141, ..@flag142, ..@flag143 + dd ..@flag144, ..@flag145, ..@flag146, ..@flag147, ..@flag148, ..@flag149, ..@flag150, ..@flag151 + dd ..@flag152, ..@flag153, ..@flag154, ..@flag155, ..@flag156, ..@flag157, ..@flag158, ..@flag159 + dd ..@flag160, ..@flag161, ..@flag162, ..@flag163, ..@flag164, ..@flag165, ..@flag166, ..@flag167 + dd ..@flag168, ..@flag169, ..@flag170, ..@flag171, ..@flag172, ..@flag173, ..@flag174, ..@flag175 + dd ..@flag176, ..@flag177, ..@flag178, ..@flag179, ..@flag180, ..@flag181, ..@flag182, ..@flag183 + dd ..@flag184, ..@flag185, ..@flag186, ..@flag187, ..@flag188, ..@flag189, ..@flag190, ..@flag191 + dd ..@flag192, ..@flag193, ..@flag194, ..@flag195, ..@flag196, ..@flag197, ..@flag198, ..@flag199 + dd ..@flag200, ..@flag201, ..@flag202, ..@flag203, ..@flag204, ..@flag205, ..@flag206, ..@flag207 + dd ..@flag208, ..@flag209, ..@flag210, ..@flag211, ..@flag212, ..@flag213, ..@flag214, ..@flag215 + dd ..@flag216, ..@flag217, ..@flag218, ..@flag219, ..@flag220, ..@flag221, ..@flag222, ..@flag223 + dd ..@flag224, ..@flag225, ..@flag226, ..@flag227, ..@flag228, ..@flag229, ..@flag230, ..@flag231 + dd ..@flag232, ..@flag233, ..@flag234, ..@flag235, ..@flag236, ..@flag237, ..@flag238, ..@flag239 + dd ..@flag240, ..@flag241, ..@flag242, ..@flag243, ..@flag244, ..@flag245, ..@flag246, ..@flag247 + dd ..@flag248, ..@flag249, ..@flag250, ..@flag251, ..@flag252, ..@flag253, ..@flag254, ..@flag255 + +FuncTable2 + dd ..@cross0, ..@cross1, ..@cross2, ..@crossN, + dd ..@cross4, ..@crossN, ..@crossN, ..@crossN, + dd ..@cross8, ..@crossN, ..@crossN, ..@crossN, + dd ..@crossN, ..@crossN, ..@crossN, ..@crossN + diff --git a/od-win32/hq4x32.asm b/od-win32/hq4x32.asm new file mode 100755 index 00000000..97b7fb7c --- /dev/null +++ b/od-win32/hq4x32.asm @@ -0,0 +1,4014 @@ +;hq4x filter +;---------------------------------------------------------- +;Copyright (C) 2003 MaxSt ( maxst@hiend3d.com ) +; +;This program is free software; you can redistribute it and/or +;modify it under the terms of the GNU General Public License +;as published by the Free Software Foundation; either +;version 2 of the License, or (at your option) any later +;version. +; +;This program is distributed in the hope that it will be useful, +;but WITHOUT ANY WARRANTY; without even the implied warranty of +;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;GNU General Public License for more details. +; +;You should have received a copy of the GNU General Public License +;along with this program; if not, write to the Free Software +;Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +GLOBAL _hq4x_32 + +EXTERN _LUT16to32 +EXTERN _RGBtoYUV + +SECTION .bss +linesleft resd 1 +xcounter resd 1 +cross resd 1 +nextline resd 1 +prevline resd 1 +w1 resd 1 +w2 resd 1 +w3 resd 1 +w4 resd 1 +w5 resd 1 +w6 resd 1 +w7 resd 1 +w8 resd 1 +w9 resd 1 +c1 resd 1 +c2 resd 1 +c3 resd 1 +c4 resd 1 +c5 resd 1 +c6 resd 1 +c7 resd 1 +c8 resd 1 +c9 resd 1 + +SECTION .data + +reg_blank dd 0,0 +const3 dd 0x00030003,0x00000003 +const5 dd 0x00050005,0x00000005 +const6 dd 0x00060006,0x00000006 +const7 dd 0x00070007,0x00000007 +threshold dd 0x00300706,0x00000000 + +SECTION .text + +%macro AUXADDRESS 0 + mov ecx, edi + add ecx, ebx + add ecx, ebx +%endmacro + +%macro TestDiff 2 + mov edx,[%1] + sub edx,[%2] + jz %%fin + mov edx,[%1] + shl edx,2 + add edx,_RGBtoYUV + movd mm1,[edx] + movq mm5,mm1 + mov edx,[%2] + shl edx,2 + add edx,_RGBtoYUV + movd mm2,[edx] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 +%%fin: +%endmacro + +%macro DiffOrNot 4 + TestDiff %1,%2 + test edx,edx + jz %%same + %3 + jmp %%fin +%%same: + %4 +%%fin +%endmacro + +%macro DiffOrNot 8 + TestDiff %1,%2 + test edx,edx + jz %%same + %3 + %4 + %5 + jmp %%fin +%%same: + %6 + %7 + %8 +%%fin +%endmacro + +%macro DiffOrNot 10 + TestDiff %1,%2 + test edx,edx + jz %%same + %3 + %4 + %5 + %6 + jmp %%fin +%%same: + %7 + %8 + %9 + %10 +%%fin +%endmacro + +%macro DiffOrNot 14 + TestDiff %1,%2 + test edx,edx + jz %%same + %3 + %4 + %5 + %6 + %7 + %8 + jmp %%fin +%%same: + %9 + %10 + %11 + %12 + %13 + %14 +%%fin +%endmacro + +%macro Interp1 3 + mov edx,%2 + shl edx,2 + add edx,%3 + sub edx,%2 + shr edx,2 + mov %1,edx +%endmacro + +%macro Interp2 4 + mov edx,%2 + shl edx,1 + add edx,%3 + add edx,%4 + shr edx,2 + mov %1,edx +%endmacro + +%macro Interp3 2 + movd mm1, eax + movd mm2, %2 + punpcklbw mm1, [reg_blank] + punpcklbw mm2, [reg_blank] + pmullw mm1, [const7] + paddw mm1, mm2 + psrlw mm1, 3 + packuswb mm1, [reg_blank] + movd %1, mm1 +%endmacro + +%macro Interp5 3 + mov edx,%2 + add edx,%3 + shr edx,1 + mov %1,edx +%endmacro + +%macro Interp6 3 + movd mm1, eax + movd mm2, %2 + movd mm3, %3 + punpcklbw mm1, [reg_blank] + punpcklbw mm2, [reg_blank] + punpcklbw mm3, [reg_blank] + pmullw mm1, [const5] + psllw mm2, 1 + paddw mm1, mm3 + paddw mm1, mm2 + psrlw mm1, 3 + packuswb mm1, [reg_blank] + movd %1, mm1 +%endmacro + +%macro Interp7 3 + movd mm1, eax + movd mm2, %2 + movd mm3, %3 + punpcklbw mm1, [reg_blank] + punpcklbw mm2, [reg_blank] + punpcklbw mm3, [reg_blank] + pmullw mm1, [const6] + paddw mm2, mm3 + paddw mm1, mm2 + psrlw mm1, 3 + packuswb mm1, [reg_blank] + movd %1, mm1 +%endmacro + +%macro Interp8 3 + movd mm1, %2 + movd mm2, %3 + punpcklbw mm1, [reg_blank] + punpcklbw mm2, [reg_blank] + pmullw mm1, [const5] + pmullw mm2, [const3] + paddw mm1, mm2 + psrlw mm1, 3 + packuswb mm1, [reg_blank] + movd %1, mm1 +%endmacro + +%macro PIXEL00_0 0 + mov [edi],eax +%endmacro + +%macro PIXEL00_11 0 + Interp1 [edi],eax,[c4] +%endmacro + +%macro PIXEL00_12 0 + Interp1 [edi],eax,[c2] +%endmacro + +%macro PIXEL00_20 0 + Interp2 [edi],eax,[c2],[c4] +%endmacro + +%macro PIXEL00_50 0 + Interp5 [edi],[c2],[c4] +%endmacro + +%macro PIXEL00_80 0 + Interp8 [edi],eax,[c1] +%endmacro + +%macro PIXEL00_81 0 + Interp8 [edi],eax,[c4] +%endmacro + +%macro PIXEL00_82 0 + Interp8 [edi],eax,[c2] +%endmacro + +%macro PIXEL01_0 0 + mov [edi+4],eax +%endmacro + +%macro PIXEL01_10 0 + Interp1 [edi+4],eax,[c1] +%endmacro + +%macro PIXEL01_12 0 + Interp1 [edi+4],eax,[c2] +%endmacro + +%macro PIXEL01_14 0 + Interp1 [edi+4],[c2],eax +%endmacro + +%macro PIXEL01_21 0 + Interp2 [edi+4],[c2],eax,[c4] +%endmacro + +%macro PIXEL01_31 0 + Interp3 [edi+4],[c4] +%endmacro + +%macro PIXEL01_50 0 + Interp5 [edi+4],[c2],eax +%endmacro + +%macro PIXEL01_60 0 + Interp6 [edi+4],[c2],[c4] +%endmacro + +%macro PIXEL01_61 0 + Interp6 [edi+4],[c2],[c1] +%endmacro + +%macro PIXEL01_82 0 + Interp8 [edi+4],eax,[c2] +%endmacro + +%macro PIXEL01_83 0 + Interp8 [edi+4],[c2],[c4] +%endmacro + +%macro PIXEL02_0 0 + mov [edi+8],eax +%endmacro + +%macro PIXEL02_10 0 + Interp1 [edi+8],eax,[c3] +%endmacro + +%macro PIXEL02_11 0 + Interp1 [edi+8],eax,[c2] +%endmacro + +%macro PIXEL02_13 0 + Interp1 [edi+8],[c2],eax +%endmacro + +%macro PIXEL02_21 0 + Interp2 [edi+8],[c2],eax,[c6] +%endmacro + +%macro PIXEL02_32 0 + Interp3 [edi+8],[c6] +%endmacro + +%macro PIXEL02_50 0 + Interp5 [edi+8],[c2],eax +%endmacro + +%macro PIXEL02_60 0 + Interp6 [edi+8],[c2],[c6] +%endmacro + +%macro PIXEL02_61 0 + Interp6 [edi+8],[c2],[c3] +%endmacro + +%macro PIXEL02_81 0 + Interp8 [edi+8],eax,[c2] +%endmacro + +%macro PIXEL02_83 0 + Interp8 [edi+8],[c2],[c6] +%endmacro + +%macro PIXEL03_0 0 + mov [edi+12],eax +%endmacro + +%macro PIXEL03_11 0 + Interp1 [edi+12],eax,[c2] +%endmacro + +%macro PIXEL03_12 0 + Interp1 [edi+12],eax,[c6] +%endmacro + +%macro PIXEL03_20 0 + Interp2 [edi+12],eax,[c2],[c6] +%endmacro + +%macro PIXEL03_50 0 + Interp5 [edi+12],[c2],[c6] +%endmacro + +%macro PIXEL03_80 0 + Interp8 [edi+12],eax,[c3] +%endmacro + +%macro PIXEL03_81 0 + Interp8 [edi+12],eax,[c2] +%endmacro + +%macro PIXEL03_82 0 + Interp8 [edi+12],eax,[c6] +%endmacro + +%macro PIXEL10_0 0 + mov [edi+ebx],eax +%endmacro + +%macro PIXEL10_10 0 + Interp1 [edi+ebx],eax,[c1] +%endmacro + +%macro PIXEL10_11 0 + Interp1 [edi+ebx],eax,[c4] +%endmacro + +%macro PIXEL10_13 0 + Interp1 [edi+ebx],[c4],eax +%endmacro + +%macro PIXEL10_21 0 + Interp2 [edi+ebx],[c4],eax,[c2] +%endmacro + +%macro PIXEL10_32 0 + Interp3 [edi+ebx],[c2] +%endmacro + +%macro PIXEL10_50 0 + Interp5 [edi+ebx],[c4],eax +%endmacro + +%macro PIXEL10_60 0 + Interp6 [edi+ebx],[c4],[c2] +%endmacro + +%macro PIXEL10_61 0 + Interp6 [edi+ebx],[c4],[c1] +%endmacro + +%macro PIXEL10_81 0 + Interp8 [edi+ebx],eax,[c4] +%endmacro + +%macro PIXEL10_83 0 + Interp8 [edi+ebx],[c4],[c2] +%endmacro + +%macro PIXEL11_0 0 + mov [edi+ebx+4],eax +%endmacro + +%macro PIXEL11_30 0 + Interp3 [edi+ebx+4],[c1] +%endmacro + +%macro PIXEL11_31 0 + Interp3 [edi+ebx+4],[c4] +%endmacro + +%macro PIXEL11_32 0 + Interp3 [edi+ebx+4],[c2] +%endmacro + +%macro PIXEL11_70 0 + Interp7 [edi+ebx+4],[c4],[c2] +%endmacro + +%macro PIXEL12_0 0 + mov [edi+ebx+8],eax +%endmacro + +%macro PIXEL12_30 0 + Interp3 [edi+ebx+8],[c3] +%endmacro + +%macro PIXEL12_31 0 + Interp3 [edi+ebx+8],[c2] +%endmacro + +%macro PIXEL12_32 0 + Interp3 [edi+ebx+8],[c6] +%endmacro + +%macro PIXEL12_70 0 + Interp7 [edi+ebx+8],[c6],[c2] +%endmacro + +%macro PIXEL13_0 0 + mov [edi+ebx+12],eax +%endmacro + +%macro PIXEL13_10 0 + Interp1 [edi+ebx+12],eax,[c3] +%endmacro + +%macro PIXEL13_12 0 + Interp1 [edi+ebx+12],eax,[c6] +%endmacro + +%macro PIXEL13_14 0 + Interp1 [edi+ebx+12],[c6],eax +%endmacro + +%macro PIXEL13_21 0 + Interp2 [edi+ebx+12],[c6],eax,[c2] +%endmacro + +%macro PIXEL13_31 0 + Interp3 [edi+ebx+12],[c2] +%endmacro + +%macro PIXEL13_50 0 + Interp5 [edi+ebx+12],[c6],eax +%endmacro + +%macro PIXEL13_60 0 + Interp6 [edi+ebx+12],[c6],[c2] +%endmacro + +%macro PIXEL13_61 0 + Interp6 [edi+ebx+12],[c6],[c3] +%endmacro + +%macro PIXEL13_82 0 + Interp8 [edi+ebx+12],eax,[c6] +%endmacro + +%macro PIXEL13_83 0 + Interp8 [edi+ebx+12],[c6],[c2] +%endmacro + +%macro PIXEL20_0 0 + mov [ecx],eax +%endmacro + +%macro PIXEL20_10 0 + Interp1 [ecx],eax,[c7] +%endmacro + +%macro PIXEL20_12 0 + Interp1 [ecx],eax,[c4] +%endmacro + +%macro PIXEL20_14 0 + Interp1 [ecx],[c4],eax +%endmacro + +%macro PIXEL20_21 0 + Interp2 [ecx],[c4],eax,[c8] +%endmacro + +%macro PIXEL20_31 0 + Interp3 [ecx],[c8] +%endmacro + +%macro PIXEL20_50 0 + Interp5 [ecx],[c4],eax +%endmacro + +%macro PIXEL20_60 0 + Interp6 [ecx],[c4],[c8] +%endmacro + +%macro PIXEL20_61 0 + Interp6 [ecx],[c4],[c7] +%endmacro + +%macro PIXEL20_82 0 + Interp8 [ecx],eax,[c4] +%endmacro + +%macro PIXEL20_83 0 + Interp8 [ecx],[c4],[c8] +%endmacro + +%macro PIXEL21_0 0 + mov [ecx+4],eax +%endmacro + +%macro PIXEL21_30 0 + Interp3 [ecx+4],[c7] +%endmacro + +%macro PIXEL21_31 0 + Interp3 [ecx+4],[c8] +%endmacro + +%macro PIXEL21_32 0 + Interp3 [ecx+4],[c4] +%endmacro + +%macro PIXEL21_70 0 + Interp7 [ecx+4],[c4],[c8] +%endmacro + +%macro PIXEL22_0 0 + mov [ecx+8],eax +%endmacro + +%macro PIXEL22_30 0 + Interp3 [ecx+8],[c9] +%endmacro + +%macro PIXEL22_31 0 + Interp3 [ecx+8],[c6] +%endmacro + +%macro PIXEL22_32 0 + Interp3 [ecx+8],[c8] +%endmacro + +%macro PIXEL22_70 0 + Interp7 [ecx+8],[c6],[c8] +%endmacro + +%macro PIXEL23_0 0 + mov [ecx+12],eax +%endmacro + +%macro PIXEL23_10 0 + Interp1 [ecx+12],eax,[c9] +%endmacro + +%macro PIXEL23_11 0 + Interp1 [ecx+12],eax,[c6] +%endmacro + +%macro PIXEL23_13 0 + Interp1 [ecx+12],[c6],eax +%endmacro + +%macro PIXEL23_21 0 + Interp2 [ecx+12],[c6],eax,[c8] +%endmacro + +%macro PIXEL23_32 0 + Interp3 [ecx+12],[c8] +%endmacro + +%macro PIXEL23_50 0 + Interp5 [ecx+12],[c6],eax +%endmacro + +%macro PIXEL23_60 0 + Interp6 [ecx+12],[c6],[c8] +%endmacro + +%macro PIXEL23_61 0 + Interp6 [ecx+12],[c6],[c9] +%endmacro + +%macro PIXEL23_81 0 + Interp8 [ecx+12],eax,[c6] +%endmacro + +%macro PIXEL23_83 0 + Interp8 [ecx+12],[c6],[c8] +%endmacro + +%macro PIXEL30_0 0 + mov [ecx+ebx],eax +%endmacro + +%macro PIXEL30_11 0 + Interp1 [ecx+ebx],eax,[c8] +%endmacro + +%macro PIXEL30_12 0 + Interp1 [ecx+ebx],eax,[c4] +%endmacro + +%macro PIXEL30_20 0 + Interp2 [ecx+ebx],eax,[c8],[c4] +%endmacro + +%macro PIXEL30_50 0 + Interp5 [ecx+ebx],[c8],[c4] +%endmacro + +%macro PIXEL30_80 0 + Interp8 [ecx+ebx],eax,[c7] +%endmacro + +%macro PIXEL30_81 0 + Interp8 [ecx+ebx],eax,[c8] +%endmacro + +%macro PIXEL30_82 0 + Interp8 [ecx+ebx],eax,[c4] +%endmacro + +%macro PIXEL31_0 0 + mov [ecx+ebx+4],eax +%endmacro + +%macro PIXEL31_10 0 + Interp1 [ecx+ebx+4],eax,[c7] +%endmacro + +%macro PIXEL31_11 0 + Interp1 [ecx+ebx+4],eax,[c8] +%endmacro + +%macro PIXEL31_13 0 + Interp1 [ecx+ebx+4],[c8],eax +%endmacro + +%macro PIXEL31_21 0 + Interp2 [ecx+ebx+4],[c8],eax,[c4] +%endmacro + +%macro PIXEL31_32 0 + Interp3 [ecx+ebx+4],[c4] +%endmacro + +%macro PIXEL31_50 0 + Interp5 [ecx+ebx+4],[c8],eax +%endmacro + +%macro PIXEL31_60 0 + Interp6 [ecx+ebx+4],[c8],[c4] +%endmacro + +%macro PIXEL31_61 0 + Interp6 [ecx+ebx+4],[c8],[c7] +%endmacro + +%macro PIXEL31_81 0 + Interp8 [ecx+ebx+4],eax,[c8] +%endmacro + +%macro PIXEL31_83 0 + Interp8 [ecx+ebx+4],[c8],[c4] +%endmacro + +%macro PIXEL32_0 0 + mov [ecx+ebx+8],eax +%endmacro + +%macro PIXEL32_10 0 + Interp1 [ecx+ebx+8],eax,[c9] +%endmacro + +%macro PIXEL32_12 0 + Interp1 [ecx+ebx+8],eax,[c8] +%endmacro + +%macro PIXEL32_14 0 + Interp1 [ecx+ebx+8],[c8],eax +%endmacro + +%macro PIXEL32_21 0 + Interp2 [ecx+ebx+8],[c8],eax,[c6] +%endmacro + +%macro PIXEL32_31 0 + Interp3 [ecx+ebx+8],[c6] +%endmacro + +%macro PIXEL32_50 0 + Interp5 [ecx+ebx+8],[c8],eax +%endmacro + +%macro PIXEL32_60 0 + Interp6 [ecx+ebx+8],[c8],[c6] +%endmacro + +%macro PIXEL32_61 0 + Interp6 [ecx+ebx+8],[c8],[c9] +%endmacro + +%macro PIXEL32_82 0 + Interp8 [ecx+ebx+8],eax,[c8] +%endmacro + +%macro PIXEL32_83 0 + Interp8 [ecx+ebx+8],[c8],[c6] +%endmacro + +%macro PIXEL33_0 0 + mov [ecx+ebx+12],eax +%endmacro + +%macro PIXEL33_11 0 + Interp1 [ecx+ebx+12],eax,[c6] +%endmacro + +%macro PIXEL33_12 0 + Interp1 [ecx+ebx+12],eax,[c8] +%endmacro + +%macro PIXEL33_20 0 + Interp2 [ecx+ebx+12],eax,[c8],[c6] +%endmacro + +%macro PIXEL33_50 0 + Interp5 [ecx+ebx+12],[c8],[c6] +%endmacro + +%macro PIXEL33_80 0 + Interp8 [ecx+ebx+12],eax,[c9] +%endmacro + +%macro PIXEL33_81 0 + Interp8 [ecx+ebx+12],eax,[c6] +%endmacro + +%macro PIXEL33_82 0 + Interp8 [ecx+ebx+12],eax,[c8] +%endmacro + +inbuffer equ 8 +outbuffer equ 12 +Xres equ 16 +Yres equ 20 +dstpitch equ 24 +srcpitch equ 28 + +_hq4x_32: + push ebp + mov ebp,esp + pushad + + mov esi,[ebp+inbuffer] + mov edi,[ebp+outbuffer] + mov edx,[ebp+Yres] + mov [linesleft],edx + mov ebx,[ebp+Xres] + shl ebx,1 + mov dword[prevline],0 + mov dword[nextline],ebx +.loopy + mov ecx,[ebp+Xres] + sub ecx,2 ; x={Xres-2, Xres-1} are special cases. + mov dword[xcounter],ecx + ; x=0 - special case + mov ebx,[prevline] + movq mm5,[esi+ebx] + movq mm6,[esi] + mov ebx,[nextline] + movq mm7,[esi+ebx] + movd eax,mm5 + movzx edx,ax + mov [w1],edx + mov [w2],edx + shr eax,16 + mov [w3],eax + movd eax,mm6 + movzx edx,ax + mov [w4],edx + mov [w5],edx + shr eax,16 + mov [w6],eax + movd eax,mm7 + movzx edx,ax + mov [w7],edx + mov [w8],edx + shr eax,16 + mov [w9],eax + jmp .flags +.loopx + mov ebx,[prevline] + movq mm5,[esi+ebx-2] + movq mm6,[esi-2] + mov ebx,[nextline] + movq mm7,[esi+ebx-2] + movd eax,mm5 + movzx edx,ax + mov [w1],edx + shr eax,16 + mov [w2],eax + psrlq mm5,32 + movd eax,mm5 + movzx edx,ax + mov [w3],edx + movd eax,mm6 + movzx edx,ax + mov [w4],edx + shr eax,16 + mov [w5],eax + psrlq mm6,32 + movd eax,mm6 + movzx edx,ax + mov [w6],edx + movd eax,mm7 + movzx edx,ax + mov [w7],edx + shr eax,16 + mov [w8],eax + psrlq mm7,32 + movd eax,mm7 + movzx edx,ax + mov [w9],edx +.flags + mov ebx,_RGBtoYUV + mov eax,[w5] + xor ecx,ecx + movd mm5,[ebx+eax*4] + mov dword[cross],0 + + mov edx,[w2] + cmp eax,edx + je .noflag2 + or dword[cross],1 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag2 + or ecx,2 +.noflag2 + mov edx,[w4] + cmp eax,edx + je .noflag4 + or dword[cross],2 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag4 + or ecx,8 +.noflag4 + mov edx,[w6] + cmp eax,edx + je .noflag6 + or dword[cross],4 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag6 + or ecx,16 +.noflag6 + mov edx,[w8] + cmp eax,edx + je .noflag8 + or dword[cross],8 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag8 + or ecx,64 +.noflag8 + cmp dword[cross],0 + jnz .testflag1 + mov ebx,_LUT16to32 + mov eax,[ebx+eax*4] + mov ebx,[ebp+dstpitch] + AUXADDRESS + mov [edi],eax + mov [edi+4],eax + mov [edi+8],eax + mov [edi+12],eax + mov [edi+ebx],eax + mov [edi+ebx+4],eax + mov [edi+ebx+8],eax + mov [edi+ebx+12],eax + mov [ecx],eax + mov [ecx+4],eax + mov [ecx+8],eax + mov [ecx+12],eax + mov [ecx+ebx],eax + mov [ecx+ebx+4],eax + mov [ecx+ebx+8],eax + mov [ecx+ebx+12],eax + jmp .loopx_end +.testflag1 + mov edx,[w1] + cmp eax,edx + je .noflag1 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag1 + or ecx,1 +.noflag1 + mov edx,[w3] + cmp eax,edx + je .noflag3 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag3 + or ecx,4 +.noflag3 + mov edx,[w7] + cmp eax,edx + je .noflag7 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag7 + or ecx,32 +.noflag7 + mov edx,[w9] + cmp eax,edx + je .noflag9 + movq mm1,mm5 + movd mm2,[ebx+edx*4] + psubusb mm1,mm2 + psubusb mm2,mm5 + por mm1,mm2 + psubusb mm1,[threshold] + movd edx,mm1 + test edx,edx + jz .noflag9 + or ecx,128 +.noflag9 + mov ebx,_LUT16to32 + mov eax,[ebx+eax*4] + mov edx,[w2] + mov edx,[ebx+edx*4] + mov [c2],edx + mov edx,[w4] + mov edx,[ebx+edx*4] + mov [c4],edx + mov edx,[w6] + mov edx,[ebx+edx*4] + mov [c6],edx + mov edx,[w8] + mov edx,[ebx+edx*4] + mov [c8],edx + test ecx,0x005A + jz .switch + mov edx,[w1] + mov edx,[ebx+edx*4] + mov [c1],edx + mov edx,[w3] + mov edx,[ebx+edx*4] + mov [c3],edx + mov edx,[w7] + mov edx,[ebx+edx*4] + mov [c7],edx + mov edx,[w9] + mov edx,[ebx+edx*4] + mov [c9],edx +.switch + mov ebx,[ebp+dstpitch] + jmp [FuncTable+ecx*4] + +..@flag0 +..@flag1 +..@flag4 +..@flag32 +..@flag128 +..@flag5 +..@flag132 +..@flag160 +..@flag33 +..@flag129 +..@flag36 +..@flag133 +..@flag164 +..@flag161 +..@flag37 +..@flag165 + AUXADDRESS + PIXEL00_20 + PIXEL01_60 + PIXEL02_60 + PIXEL03_20 + PIXEL10_60 + PIXEL11_70 + PIXEL12_70 + PIXEL13_60 + PIXEL20_60 + PIXEL21_70 + PIXEL22_70 + PIXEL23_60 + PIXEL30_20 + PIXEL31_60 + PIXEL32_60 + PIXEL33_20 + jmp .loopx_end +..@flag2 +..@flag34 +..@flag130 +..@flag162 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + PIXEL02_10 + PIXEL03_80 + PIXEL10_61 + PIXEL11_30 + PIXEL12_30 + PIXEL13_61 + PIXEL20_60 + PIXEL21_70 + PIXEL22_70 + PIXEL23_60 + PIXEL30_20 + PIXEL31_60 + PIXEL32_60 + PIXEL33_20 + jmp .loopx_end +..@flag16 +..@flag17 +..@flag48 +..@flag49 + AUXADDRESS + PIXEL00_20 + PIXEL01_60 + PIXEL02_61 + PIXEL03_80 + PIXEL10_60 + PIXEL11_70 + PIXEL12_30 + PIXEL13_10 + PIXEL20_60 + PIXEL21_70 + PIXEL22_30 + PIXEL23_10 + PIXEL30_20 + PIXEL31_60 + PIXEL32_61 + PIXEL33_80 + jmp .loopx_end +..@flag64 +..@flag65 +..@flag68 +..@flag69 + AUXADDRESS + PIXEL00_20 + PIXEL01_60 + PIXEL02_60 + PIXEL03_20 + PIXEL10_60 + PIXEL11_70 + PIXEL12_70 + PIXEL13_60 + PIXEL20_61 + PIXEL21_30 + PIXEL22_30 + PIXEL23_61 + PIXEL30_80 + PIXEL31_10 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag8 +..@flag12 +..@flag136 +..@flag140 + AUXADDRESS + PIXEL00_80 + PIXEL01_61 + PIXEL02_60 + PIXEL03_20 + PIXEL10_10 + PIXEL11_30 + PIXEL12_70 + PIXEL13_60 + PIXEL20_10 + PIXEL21_30 + PIXEL22_70 + PIXEL23_60 + PIXEL30_80 + PIXEL31_61 + PIXEL32_60 + PIXEL33_20 + jmp .loopx_end +..@flag3 +..@flag35 +..@flag131 +..@flag163 + AUXADDRESS + PIXEL00_81 + PIXEL01_31 + PIXEL02_10 + PIXEL03_80 + PIXEL10_81 + PIXEL11_31 + PIXEL12_30 + PIXEL13_61 + PIXEL20_60 + PIXEL21_70 + PIXEL22_70 + PIXEL23_60 + PIXEL30_20 + PIXEL31_60 + PIXEL32_60 + PIXEL33_20 + jmp .loopx_end +..@flag6 +..@flag38 +..@flag134 +..@flag166 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + PIXEL02_32 + PIXEL03_82 + PIXEL10_61 + PIXEL11_30 + PIXEL12_32 + PIXEL13_82 + PIXEL20_60 + PIXEL21_70 + PIXEL22_70 + PIXEL23_60 + PIXEL30_20 + PIXEL31_60 + PIXEL32_60 + PIXEL33_20 + jmp .loopx_end +..@flag20 +..@flag21 +..@flag52 +..@flag53 + AUXADDRESS + PIXEL00_20 + PIXEL01_60 + PIXEL02_81 + PIXEL03_81 + PIXEL10_60 + PIXEL11_70 + PIXEL12_31 + PIXEL13_31 + PIXEL20_60 + PIXEL21_70 + PIXEL22_30 + PIXEL23_10 + PIXEL30_20 + PIXEL31_60 + PIXEL32_61 + PIXEL33_80 + jmp .loopx_end +..@flag144 +..@flag145 +..@flag176 +..@flag177 + AUXADDRESS + PIXEL00_20 + PIXEL01_60 + PIXEL02_61 + PIXEL03_80 + PIXEL10_60 + PIXEL11_70 + PIXEL12_30 + PIXEL13_10 + PIXEL20_60 + PIXEL21_70 + PIXEL22_32 + PIXEL23_32 + PIXEL30_20 + PIXEL31_60 + PIXEL32_82 + PIXEL33_82 + jmp .loopx_end +..@flag192 +..@flag193 +..@flag196 +..@flag197 + AUXADDRESS + PIXEL00_20 + PIXEL01_60 + PIXEL02_60 + PIXEL03_20 + PIXEL10_60 + PIXEL11_70 + PIXEL12_70 + PIXEL13_60 + PIXEL20_61 + PIXEL21_30 + PIXEL22_31 + PIXEL23_81 + PIXEL30_80 + PIXEL31_10 + PIXEL32_31 + PIXEL33_81 + jmp .loopx_end +..@flag96 +..@flag97 +..@flag100 +..@flag101 + AUXADDRESS + PIXEL00_20 + PIXEL01_60 + PIXEL02_60 + PIXEL03_20 + PIXEL10_60 + PIXEL11_70 + PIXEL12_70 + PIXEL13_60 + PIXEL20_82 + PIXEL21_32 + PIXEL22_30 + PIXEL23_61 + PIXEL30_82 + PIXEL31_32 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag40 +..@flag44 +..@flag168 +..@flag172 + AUXADDRESS + PIXEL00_80 + PIXEL01_61 + PIXEL02_60 + PIXEL03_20 + PIXEL10_10 + PIXEL11_30 + PIXEL12_70 + PIXEL13_60 + PIXEL20_31 + PIXEL21_31 + PIXEL22_70 + PIXEL23_60 + PIXEL30_81 + PIXEL31_81 + PIXEL32_60 + PIXEL33_20 + jmp .loopx_end +..@flag9 +..@flag13 +..@flag137 +..@flag141 + AUXADDRESS + PIXEL00_82 + PIXEL01_82 + PIXEL02_60 + PIXEL03_20 + PIXEL10_32 + PIXEL11_32 + PIXEL12_70 + PIXEL13_60 + PIXEL20_10 + PIXEL21_30 + PIXEL22_70 + PIXEL23_60 + PIXEL30_80 + PIXEL31_61 + PIXEL32_60 + PIXEL33_20 + jmp .loopx_end +..@flag18 +..@flag50 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_50,PIXEL03_50,PIXEL12_0,PIXEL13_50 + PIXEL10_61 + PIXEL11_30 + PIXEL20_60 + PIXEL21_70 + PIXEL22_30 + PIXEL23_10 + PIXEL30_20 + PIXEL31_60 + PIXEL32_61 + PIXEL33_80 + jmp .loopx_end +..@flag80 +..@flag81 + AUXADDRESS + PIXEL00_20 + PIXEL01_60 + PIXEL02_61 + PIXEL03_80 + PIXEL10_60 + PIXEL11_70 + PIXEL12_30 + PIXEL13_10 + PIXEL20_61 + PIXEL21_30 + DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_50,PIXEL32_50,PIXEL33_50 + PIXEL30_80 + PIXEL31_10 + jmp .loopx_end +..@flag72 +..@flag76 + AUXADDRESS + PIXEL00_80 + PIXEL01_61 + PIXEL02_60 + PIXEL03_20 + PIXEL10_10 + PIXEL11_30 + PIXEL12_70 + PIXEL13_60 + DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_50,PIXEL21_0,PIXEL30_50,PIXEL31_50 + PIXEL22_30 + PIXEL23_61 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag10 +..@flag138 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_50,PIXEL01_50,PIXEL10_50,PIXEL11_0 + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_61 + PIXEL20_10 + PIXEL21_30 + PIXEL22_70 + PIXEL23_60 + PIXEL30_80 + PIXEL31_61 + PIXEL32_60 + PIXEL33_20 + jmp .loopx_end +..@flag66 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + PIXEL02_10 + PIXEL03_80 + PIXEL10_61 + PIXEL11_30 + PIXEL12_30 + PIXEL13_61 + PIXEL20_61 + PIXEL21_30 + PIXEL22_30 + PIXEL23_61 + PIXEL30_80 + PIXEL31_10 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag24 + AUXADDRESS + PIXEL00_80 + PIXEL01_61 + PIXEL02_61 + PIXEL03_80 + PIXEL10_10 + PIXEL11_30 + PIXEL12_30 + PIXEL13_10 + PIXEL20_10 + PIXEL21_30 + PIXEL22_30 + PIXEL23_10 + PIXEL30_80 + PIXEL31_61 + PIXEL32_61 + PIXEL33_80 + jmp .loopx_end +..@flag7 +..@flag39 +..@flag135 + AUXADDRESS + PIXEL00_81 + PIXEL01_31 + PIXEL02_32 + PIXEL03_82 + PIXEL10_81 + PIXEL11_31 + PIXEL12_32 + PIXEL13_82 + PIXEL20_60 + PIXEL21_70 + PIXEL22_70 + PIXEL23_60 + PIXEL30_20 + PIXEL31_60 + PIXEL32_60 + PIXEL33_20 + jmp .loopx_end +..@flag148 +..@flag149 +..@flag180 + AUXADDRESS + PIXEL00_20 + PIXEL01_60 + PIXEL02_81 + PIXEL03_81 + PIXEL10_60 + PIXEL11_70 + PIXEL12_31 + PIXEL13_31 + PIXEL20_60 + PIXEL21_70 + PIXEL22_32 + PIXEL23_32 + PIXEL30_20 + PIXEL31_60 + PIXEL32_82 + PIXEL33_82 + jmp .loopx_end +..@flag224 +..@flag228 +..@flag225 + AUXADDRESS + PIXEL00_20 + PIXEL01_60 + PIXEL02_60 + PIXEL03_20 + PIXEL10_60 + PIXEL11_70 + PIXEL12_70 + PIXEL13_60 + PIXEL20_82 + PIXEL21_32 + PIXEL22_31 + PIXEL23_81 + PIXEL30_82 + PIXEL31_32 + PIXEL32_31 + PIXEL33_81 + jmp .loopx_end +..@flag41 +..@flag169 +..@flag45 + AUXADDRESS + PIXEL00_82 + PIXEL01_82 + PIXEL02_60 + PIXEL03_20 + PIXEL10_32 + PIXEL11_32 + PIXEL12_70 + PIXEL13_60 + PIXEL20_31 + PIXEL21_31 + PIXEL22_70 + PIXEL23_60 + PIXEL30_81 + PIXEL31_81 + PIXEL32_60 + PIXEL33_20 + jmp .loopx_end +..@flag22 +..@flag54 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50 + PIXEL10_61 + PIXEL11_30 + PIXEL12_0 + PIXEL20_60 + PIXEL21_70 + PIXEL22_30 + PIXEL23_10 + PIXEL30_20 + PIXEL31_60 + PIXEL32_61 + PIXEL33_80 + jmp .loopx_end +..@flag208 +..@flag209 + AUXADDRESS + PIXEL00_20 + PIXEL01_60 + PIXEL02_61 + PIXEL03_80 + PIXEL10_60 + PIXEL11_70 + PIXEL12_30 + PIXEL13_10 + PIXEL20_61 + PIXEL21_30 + PIXEL22_0 + DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50 + PIXEL30_80 + PIXEL31_10 + jmp .loopx_end +..@flag104 +..@flag108 + AUXADDRESS + PIXEL00_80 + PIXEL01_61 + PIXEL02_60 + PIXEL03_20 + PIXEL10_10 + PIXEL11_30 + PIXEL12_70 + PIXEL13_60 + DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50 + PIXEL21_0 + PIXEL22_30 + PIXEL23_61 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag11 +..@flag139 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50 + PIXEL02_10 + PIXEL03_80 + PIXEL11_0 + PIXEL12_30 + PIXEL13_61 + PIXEL20_10 + PIXEL21_30 + PIXEL22_70 + PIXEL23_60 + PIXEL30_80 + PIXEL31_61 + PIXEL32_60 + PIXEL33_20 + jmp .loopx_end +..@flag19 +..@flag51 + AUXADDRESS + DiffOrNot w2,w6,PIXEL00_81,PIXEL01_31,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL00_12,PIXEL01_14,PIXEL02_83,PIXEL03_50,PIXEL12_70,PIXEL13_21 + PIXEL10_81 + PIXEL11_31 + PIXEL20_60 + PIXEL21_70 + PIXEL22_30 + PIXEL23_10 + PIXEL30_20 + PIXEL31_60 + PIXEL32_61 + PIXEL33_80 + jmp .loopx_end +..@flag146 +..@flag178 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL23_32,PIXEL33_82,PIXEL02_21,PIXEL03_50,PIXEL12_70,PIXEL13_83,PIXEL23_13,PIXEL33_11 + PIXEL10_61 + PIXEL11_30 + PIXEL20_60 + PIXEL21_70 + PIXEL22_32 + PIXEL30_20 + PIXEL31_60 + PIXEL32_82 + jmp .loopx_end +..@flag84 +..@flag85 + AUXADDRESS + PIXEL00_20 + PIXEL01_60 + PIXEL02_81 + DiffOrNot w6,w8,PIXEL03_81,PIXEL13_31,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL03_12,PIXEL13_14,PIXEL22_70,PIXEL23_83,PIXEL32_21,PIXEL33_50 + PIXEL10_60 + PIXEL11_70 + PIXEL12_31 + PIXEL20_61 + PIXEL21_30 + PIXEL30_80 + PIXEL31_10 + jmp .loopx_end +..@flag112 +..@flag113 + AUXADDRESS + PIXEL00_20 + PIXEL01_60 + PIXEL02_61 + PIXEL03_80 + PIXEL10_60 + PIXEL11_70 + PIXEL12_30 + PIXEL13_10 + PIXEL20_82 + PIXEL21_32 + DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL30_82,PIXEL31_32,PIXEL32_10,PIXEL33_80,PIXEL22_70,PIXEL23_21,PIXEL30_11,PIXEL31_13,PIXEL32_83,PIXEL33_50 + jmp .loopx_end +..@flag200 +..@flag204 + AUXADDRESS + PIXEL00_80 + PIXEL01_61 + PIXEL02_60 + PIXEL03_20 + PIXEL10_10 + PIXEL11_30 + PIXEL12_70 + PIXEL13_60 + DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL32_31,PIXEL33_81,PIXEL20_21,PIXEL21_70,PIXEL30_50,PIXEL31_83,PIXEL32_14,PIXEL33_12 + PIXEL22_31 + PIXEL23_81 + jmp .loopx_end +..@flag73 +..@flag77 + AUXADDRESS + DiffOrNot w8,w4,PIXEL00_82,PIXEL10_32,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL00_11,PIXEL10_13,PIXEL20_83,PIXEL21_70,PIXEL30_50,PIXEL31_21 + PIXEL01_82 + PIXEL02_60 + PIXEL03_20 + PIXEL11_32 + PIXEL12_70 + PIXEL13_60 + PIXEL22_30 + PIXEL23_61 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag42 +..@flag170 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL20_31,PIXEL30_81,PIXEL00_50,PIXEL01_21,PIXEL10_83,PIXEL11_70,PIXEL20_14,PIXEL30_12 + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_61 + PIXEL21_31 + PIXEL22_70 + PIXEL23_60 + PIXEL31_81 + PIXEL32_60 + PIXEL33_20 + jmp .loopx_end +..@flag14 +..@flag142 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL02_32,PIXEL03_82,PIXEL10_10,PIXEL11_30,PIXEL00_50,PIXEL01_83,PIXEL02_13,PIXEL03_11,PIXEL10_21,PIXEL11_70 + PIXEL12_32 + PIXEL13_82 + PIXEL20_10 + PIXEL21_30 + PIXEL22_70 + PIXEL23_60 + PIXEL30_80 + PIXEL31_61 + PIXEL32_60 + PIXEL33_20 + jmp .loopx_end +..@flag67 + AUXADDRESS + PIXEL00_81 + PIXEL01_31 + PIXEL02_10 + PIXEL03_80 + PIXEL10_81 + PIXEL11_31 + PIXEL12_30 + PIXEL13_61 + PIXEL20_61 + PIXEL21_30 + PIXEL22_30 + PIXEL23_61 + PIXEL30_80 + PIXEL31_10 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag70 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + PIXEL02_32 + PIXEL03_82 + PIXEL10_61 + PIXEL11_30 + PIXEL12_32 + PIXEL13_82 + PIXEL20_61 + PIXEL21_30 + PIXEL22_30 + PIXEL23_61 + PIXEL30_80 + PIXEL31_10 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag28 + AUXADDRESS + PIXEL00_80 + PIXEL01_61 + PIXEL02_81 + PIXEL03_81 + PIXEL10_10 + PIXEL11_30 + PIXEL12_31 + PIXEL13_31 + PIXEL20_10 + PIXEL21_30 + PIXEL22_30 + PIXEL23_10 + PIXEL30_80 + PIXEL31_61 + PIXEL32_61 + PIXEL33_80 + jmp .loopx_end +..@flag152 + AUXADDRESS + PIXEL00_80 + PIXEL01_61 + PIXEL02_61 + PIXEL03_80 + PIXEL10_10 + PIXEL11_30 + PIXEL12_30 + PIXEL13_10 + PIXEL20_10 + PIXEL21_30 + PIXEL22_32 + PIXEL23_32 + PIXEL30_80 + PIXEL31_61 + PIXEL32_82 + PIXEL33_82 + jmp .loopx_end +..@flag194 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + PIXEL02_10 + PIXEL03_80 + PIXEL10_61 + PIXEL11_30 + PIXEL12_30 + PIXEL13_61 + PIXEL20_61 + PIXEL21_30 + PIXEL22_31 + PIXEL23_81 + PIXEL30_80 + PIXEL31_10 + PIXEL32_31 + PIXEL33_81 + jmp .loopx_end +..@flag98 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + PIXEL02_10 + PIXEL03_80 + PIXEL10_61 + PIXEL11_30 + PIXEL12_30 + PIXEL13_61 + PIXEL20_82 + PIXEL21_32 + PIXEL22_30 + PIXEL23_61 + PIXEL30_82 + PIXEL31_32 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag56 + AUXADDRESS + PIXEL00_80 + PIXEL01_61 + PIXEL02_61 + PIXEL03_80 + PIXEL10_10 + PIXEL11_30 + PIXEL12_30 + PIXEL13_10 + PIXEL20_31 + PIXEL21_31 + PIXEL22_30 + PIXEL23_10 + PIXEL30_81 + PIXEL31_81 + PIXEL32_61 + PIXEL33_80 + jmp .loopx_end +..@flag25 + AUXADDRESS + PIXEL00_82 + PIXEL01_82 + PIXEL02_61 + PIXEL03_80 + PIXEL10_32 + PIXEL11_32 + PIXEL12_30 + PIXEL13_10 + PIXEL20_10 + PIXEL21_30 + PIXEL22_30 + PIXEL23_10 + PIXEL30_80 + PIXEL31_61 + PIXEL32_61 + PIXEL33_80 + jmp .loopx_end +..@flag26 +..@flag31 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50 + DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50 + PIXEL11_0 + PIXEL12_0 + PIXEL20_10 + PIXEL21_30 + PIXEL22_30 + PIXEL23_10 + PIXEL30_80 + PIXEL31_61 + PIXEL32_61 + PIXEL33_80 + jmp .loopx_end +..@flag82 +..@flag214 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50 + PIXEL10_61 + PIXEL11_30 + PIXEL12_0 + PIXEL20_61 + PIXEL21_30 + PIXEL22_0 + DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50 + PIXEL30_80 + PIXEL31_10 + jmp .loopx_end +..@flag88 +..@flag248 + AUXADDRESS + PIXEL00_80 + PIXEL01_61 + PIXEL02_61 + PIXEL03_80 + PIXEL10_10 + PIXEL11_30 + PIXEL12_30 + PIXEL13_10 + DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50 + PIXEL21_0 + PIXEL22_0 + DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50 + jmp .loopx_end +..@flag74 +..@flag107 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50 + PIXEL02_10 + PIXEL03_80 + PIXEL11_0 + PIXEL12_30 + PIXEL13_61 + DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50 + PIXEL21_0 + PIXEL22_30 + PIXEL23_61 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag27 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50 + PIXEL02_10 + PIXEL03_80 + PIXEL11_0 + PIXEL12_30 + PIXEL13_10 + PIXEL20_10 + PIXEL21_30 + PIXEL22_30 + PIXEL23_10 + PIXEL30_80 + PIXEL31_61 + PIXEL32_61 + PIXEL33_80 + jmp .loopx_end +..@flag86 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50 + PIXEL10_61 + PIXEL11_30 + PIXEL12_0 + PIXEL20_61 + PIXEL21_30 + PIXEL22_30 + PIXEL23_10 + PIXEL30_80 + PIXEL31_10 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag216 + AUXADDRESS + PIXEL00_80 + PIXEL01_61 + PIXEL02_61 + PIXEL03_80 + PIXEL10_10 + PIXEL11_30 + PIXEL12_30 + PIXEL13_10 + PIXEL20_10 + PIXEL21_30 + PIXEL22_0 + DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50 + PIXEL30_80 + PIXEL31_10 + jmp .loopx_end +..@flag106 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + PIXEL02_10 + PIXEL03_80 + PIXEL10_10 + PIXEL11_30 + PIXEL12_30 + PIXEL13_61 + DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50 + PIXEL21_0 + PIXEL22_30 + PIXEL23_61 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag30 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50 + PIXEL10_10 + PIXEL11_30 + PIXEL12_0 + PIXEL20_10 + PIXEL21_30 + PIXEL22_30 + PIXEL23_10 + PIXEL30_80 + PIXEL31_61 + PIXEL32_61 + PIXEL33_80 + jmp .loopx_end +..@flag210 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + PIXEL02_10 + PIXEL03_80 + PIXEL10_61 + PIXEL11_30 + PIXEL12_30 + PIXEL13_10 + PIXEL20_61 + PIXEL21_30 + PIXEL22_0 + DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50 + PIXEL30_80 + PIXEL31_10 + jmp .loopx_end +..@flag120 + AUXADDRESS + PIXEL00_80 + PIXEL01_61 + PIXEL02_61 + PIXEL03_80 + PIXEL10_10 + PIXEL11_30 + PIXEL12_30 + PIXEL13_10 + DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50 + PIXEL21_0 + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag75 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50 + PIXEL02_10 + PIXEL03_80 + PIXEL11_0 + PIXEL12_30 + PIXEL13_61 + PIXEL20_10 + PIXEL21_30 + PIXEL22_30 + PIXEL23_61 + PIXEL30_80 + PIXEL31_10 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag29 + AUXADDRESS + PIXEL00_82 + PIXEL01_82 + PIXEL02_81 + PIXEL03_81 + PIXEL10_32 + PIXEL11_32 + PIXEL12_31 + PIXEL13_31 + PIXEL20_10 + PIXEL21_30 + PIXEL22_30 + PIXEL23_10 + PIXEL30_80 + PIXEL31_61 + PIXEL32_61 + PIXEL33_80 + jmp .loopx_end +..@flag198 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + PIXEL02_32 + PIXEL03_82 + PIXEL10_61 + PIXEL11_30 + PIXEL12_32 + PIXEL13_82 + PIXEL20_61 + PIXEL21_30 + PIXEL22_31 + PIXEL23_81 + PIXEL30_80 + PIXEL31_10 + PIXEL32_31 + PIXEL33_81 + jmp .loopx_end +..@flag184 + AUXADDRESS + PIXEL00_80 + PIXEL01_61 + PIXEL02_61 + PIXEL03_80 + PIXEL10_10 + PIXEL11_30 + PIXEL12_30 + PIXEL13_10 + PIXEL20_31 + PIXEL21_31 + PIXEL22_32 + PIXEL23_32 + PIXEL30_81 + PIXEL31_81 + PIXEL32_82 + PIXEL33_82 + jmp .loopx_end +..@flag99 + AUXADDRESS + PIXEL00_81 + PIXEL01_31 + PIXEL02_10 + PIXEL03_80 + PIXEL10_81 + PIXEL11_31 + PIXEL12_30 + PIXEL13_61 + PIXEL20_82 + PIXEL21_32 + PIXEL22_30 + PIXEL23_61 + PIXEL30_82 + PIXEL31_32 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag57 + AUXADDRESS + PIXEL00_82 + PIXEL01_82 + PIXEL02_61 + PIXEL03_80 + PIXEL10_32 + PIXEL11_32 + PIXEL12_30 + PIXEL13_10 + PIXEL20_31 + PIXEL21_31 + PIXEL22_30 + PIXEL23_10 + PIXEL30_81 + PIXEL31_81 + PIXEL32_61 + PIXEL33_80 + jmp .loopx_end +..@flag71 + AUXADDRESS + PIXEL00_81 + PIXEL01_31 + PIXEL02_32 + PIXEL03_82 + PIXEL10_81 + PIXEL11_31 + PIXEL12_32 + PIXEL13_82 + PIXEL20_61 + PIXEL21_30 + PIXEL22_30 + PIXEL23_61 + PIXEL30_80 + PIXEL31_10 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag156 + AUXADDRESS + PIXEL00_80 + PIXEL01_61 + PIXEL02_81 + PIXEL03_81 + PIXEL10_10 + PIXEL11_30 + PIXEL12_31 + PIXEL13_31 + PIXEL20_10 + PIXEL21_30 + PIXEL22_32 + PIXEL23_32 + PIXEL30_80 + PIXEL31_61 + PIXEL32_82 + PIXEL33_82 + jmp .loopx_end +..@flag226 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + PIXEL02_10 + PIXEL03_80 + PIXEL10_61 + PIXEL11_30 + PIXEL12_30 + PIXEL13_61 + PIXEL20_82 + PIXEL21_32 + PIXEL22_31 + PIXEL23_81 + PIXEL30_82 + PIXEL31_32 + PIXEL32_31 + PIXEL33_81 + jmp .loopx_end +..@flag60 + AUXADDRESS + PIXEL00_80 + PIXEL01_61 + PIXEL02_81 + PIXEL03_81 + PIXEL10_10 + PIXEL11_30 + PIXEL12_31 + PIXEL13_31 + PIXEL20_31 + PIXEL21_31 + PIXEL22_30 + PIXEL23_10 + PIXEL30_81 + PIXEL31_81 + PIXEL32_61 + PIXEL33_80 + jmp .loopx_end +..@flag195 + AUXADDRESS + PIXEL00_81 + PIXEL01_31 + PIXEL02_10 + PIXEL03_80 + PIXEL10_81 + PIXEL11_31 + PIXEL12_30 + PIXEL13_61 + PIXEL20_61 + PIXEL21_30 + PIXEL22_31 + PIXEL23_81 + PIXEL30_80 + PIXEL31_10 + PIXEL32_31 + PIXEL33_81 + jmp .loopx_end +..@flag102 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + PIXEL02_32 + PIXEL03_82 + PIXEL10_61 + PIXEL11_30 + PIXEL12_32 + PIXEL13_82 + PIXEL20_82 + PIXEL21_32 + PIXEL22_30 + PIXEL23_61 + PIXEL30_82 + PIXEL31_32 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag153 + AUXADDRESS + PIXEL00_82 + PIXEL01_82 + PIXEL02_61 + PIXEL03_80 + PIXEL10_32 + PIXEL11_32 + PIXEL12_30 + PIXEL13_10 + PIXEL20_10 + PIXEL21_30 + PIXEL22_32 + PIXEL23_32 + PIXEL30_80 + PIXEL31_61 + PIXEL32_82 + PIXEL33_82 + jmp .loopx_end +..@flag58 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0 + DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12 + PIXEL20_31 + PIXEL21_31 + PIXEL22_30 + PIXEL23_10 + PIXEL30_81 + PIXEL31_81 + PIXEL32_61 + PIXEL33_80 + jmp .loopx_end +..@flag83 + AUXADDRESS + PIXEL00_81 + PIXEL01_31 + DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12 + PIXEL10_81 + PIXEL11_31 + PIXEL20_61 + PIXEL21_30 + DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20 + PIXEL30_80 + PIXEL31_10 + jmp .loopx_end +..@flag92 + AUXADDRESS + PIXEL00_80 + PIXEL01_61 + PIXEL02_81 + PIXEL03_81 + PIXEL10_10 + PIXEL11_30 + PIXEL12_31 + PIXEL13_31 + DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11 + DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20 + jmp .loopx_end +..@flag202 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0 + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_61 + DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11 + PIXEL22_31 + PIXEL23_81 + PIXEL32_31 + PIXEL33_81 + jmp .loopx_end +..@flag78 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0 + PIXEL02_32 + PIXEL03_82 + PIXEL12_32 + PIXEL13_82 + DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11 + PIXEL22_30 + PIXEL23_61 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag154 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0 + DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12 + PIXEL20_10 + PIXEL21_30 + PIXEL22_32 + PIXEL23_32 + PIXEL30_80 + PIXEL31_61 + PIXEL32_82 + PIXEL33_82 + jmp .loopx_end +..@flag114 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12 + PIXEL10_61 + PIXEL11_30 + PIXEL20_82 + PIXEL21_32 + DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20 + PIXEL30_82 + PIXEL31_32 + jmp .loopx_end +..@flag89 + AUXADDRESS + PIXEL00_82 + PIXEL01_82 + PIXEL02_61 + PIXEL03_80 + PIXEL10_32 + PIXEL11_32 + PIXEL12_30 + PIXEL13_10 + DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11 + DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20 + jmp .loopx_end +..@flag90 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0 + DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12 + DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11 + DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20 + jmp .loopx_end +..@flag55 +..@flag23 + AUXADDRESS + DiffOrNot w2,w6,PIXEL00_81,PIXEL01_31,PIXEL02_0,PIXEL03_0,PIXEL12_0,PIXEL13_0,PIXEL00_12,PIXEL01_14,PIXEL02_83,PIXEL03_50,PIXEL12_70,PIXEL13_21 + PIXEL10_81 + PIXEL11_31 + PIXEL20_60 + PIXEL21_70 + PIXEL22_30 + PIXEL23_10 + PIXEL30_20 + PIXEL31_60 + PIXEL32_61 + PIXEL33_80 + jmp .loopx_end +..@flag182 +..@flag150 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL12_0,PIXEL13_0,PIXEL23_32,PIXEL33_82,PIXEL02_21,PIXEL03_50,PIXEL12_70,PIXEL13_83,PIXEL23_13,PIXEL33_11 + PIXEL10_61 + PIXEL11_30 + PIXEL20_60 + PIXEL21_70 + PIXEL22_32 + PIXEL30_20 + PIXEL31_60 + PIXEL32_82 + jmp .loopx_end +..@flag213 +..@flag212 + AUXADDRESS + PIXEL00_20 + PIXEL01_60 + PIXEL02_81 + DiffOrNot w6,w8,PIXEL03_81,PIXEL13_31,PIXEL22_0,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL03_12,PIXEL13_14,PIXEL22_70,PIXEL23_83,PIXEL32_21,PIXEL33_50 + PIXEL10_60 + PIXEL11_70 + PIXEL12_31 + PIXEL20_61 + PIXEL21_30 + PIXEL30_80 + PIXEL31_10 + jmp .loopx_end +..@flag241 +..@flag240 + AUXADDRESS + PIXEL00_20 + PIXEL01_60 + PIXEL02_61 + PIXEL03_80 + PIXEL10_60 + PIXEL11_70 + PIXEL12_30 + PIXEL13_10 + PIXEL20_82 + PIXEL21_32 + DiffOrNot w6,w8,PIXEL22_0,PIXEL23_0,PIXEL30_82,PIXEL31_32,PIXEL32_0,PIXEL33_0,PIXEL22_70,PIXEL23_21,PIXEL30_11,PIXEL31_13,PIXEL32_83,PIXEL33_50 + jmp .loopx_end +..@flag236 +..@flag232 + AUXADDRESS + PIXEL00_80 + PIXEL01_61 + PIXEL02_60 + PIXEL03_20 + PIXEL10_10 + PIXEL11_30 + PIXEL12_70 + PIXEL13_60 + DiffOrNot w8,w4,PIXEL20_0,PIXEL21_0,PIXEL30_0,PIXEL31_0,PIXEL32_31,PIXEL33_81,PIXEL20_21,PIXEL21_70,PIXEL30_50,PIXEL31_83,PIXEL32_14,PIXEL33_12 + PIXEL22_31 + PIXEL23_81 + jmp .loopx_end +..@flag109 +..@flag105 + AUXADDRESS + DiffOrNot w8,w4,PIXEL00_82,PIXEL10_32,PIXEL20_0,PIXEL21_0,PIXEL30_0,PIXEL31_0,PIXEL00_11,PIXEL10_13,PIXEL20_83,PIXEL21_70,PIXEL30_50,PIXEL31_21 + PIXEL01_82 + PIXEL02_60 + PIXEL03_20 + PIXEL11_32 + PIXEL12_70 + PIXEL13_60 + PIXEL22_30 + PIXEL23_61 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag171 +..@flag43 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL11_0,PIXEL20_31,PIXEL30_81,PIXEL00_50,PIXEL01_21,PIXEL10_83,PIXEL11_70,PIXEL20_14,PIXEL30_12 + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_61 + PIXEL21_31 + PIXEL22_70 + PIXEL23_60 + PIXEL31_81 + PIXEL32_60 + PIXEL33_20 + jmp .loopx_end +..@flag143 +..@flag15 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL02_32,PIXEL03_82,PIXEL10_0,PIXEL11_0,PIXEL00_50,PIXEL01_83,PIXEL02_13,PIXEL03_11,PIXEL10_21,PIXEL11_70 + PIXEL12_32 + PIXEL13_82 + PIXEL20_10 + PIXEL21_30 + PIXEL22_70 + PIXEL23_60 + PIXEL30_80 + PIXEL31_61 + PIXEL32_60 + PIXEL33_20 + jmp .loopx_end +..@flag124 + AUXADDRESS + PIXEL00_80 + PIXEL01_61 + PIXEL02_81 + PIXEL03_81 + PIXEL10_10 + PIXEL11_30 + PIXEL12_31 + PIXEL13_31 + DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50 + PIXEL21_0 + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag203 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50 + PIXEL02_10 + PIXEL03_80 + PIXEL11_0 + PIXEL12_30 + PIXEL13_61 + PIXEL20_10 + PIXEL21_30 + PIXEL22_31 + PIXEL23_81 + PIXEL30_80 + PIXEL31_10 + PIXEL32_31 + PIXEL33_81 + jmp .loopx_end +..@flag62 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50 + PIXEL10_10 + PIXEL11_30 + PIXEL12_0 + PIXEL20_31 + PIXEL21_31 + PIXEL22_30 + PIXEL23_10 + PIXEL30_81 + PIXEL31_81 + PIXEL32_61 + PIXEL33_80 + jmp .loopx_end +..@flag211 + AUXADDRESS + PIXEL00_81 + PIXEL01_31 + PIXEL02_10 + PIXEL03_80 + PIXEL10_81 + PIXEL11_31 + PIXEL12_30 + PIXEL13_10 + PIXEL20_61 + PIXEL21_30 + PIXEL22_0 + DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50 + PIXEL30_80 + PIXEL31_10 + jmp .loopx_end +..@flag118 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50 + PIXEL10_61 + PIXEL11_30 + PIXEL12_0 + PIXEL20_82 + PIXEL21_32 + PIXEL22_30 + PIXEL23_10 + PIXEL30_82 + PIXEL31_32 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag217 + AUXADDRESS + PIXEL00_82 + PIXEL01_82 + PIXEL02_61 + PIXEL03_80 + PIXEL10_32 + PIXEL11_32 + PIXEL12_30 + PIXEL13_10 + PIXEL20_10 + PIXEL21_30 + PIXEL22_0 + DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50 + PIXEL30_80 + PIXEL31_10 + jmp .loopx_end +..@flag110 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + PIXEL02_32 + PIXEL03_82 + PIXEL10_10 + PIXEL11_30 + PIXEL12_32 + PIXEL13_82 + DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50 + PIXEL21_0 + PIXEL22_30 + PIXEL23_61 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag155 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50 + PIXEL02_10 + PIXEL03_80 + PIXEL11_0 + PIXEL12_30 + PIXEL13_10 + PIXEL20_10 + PIXEL21_30 + PIXEL22_32 + PIXEL23_32 + PIXEL30_80 + PIXEL31_61 + PIXEL32_82 + PIXEL33_82 + jmp .loopx_end +..@flag188 + AUXADDRESS + PIXEL00_80 + PIXEL01_61 + PIXEL02_81 + PIXEL03_81 + PIXEL10_10 + PIXEL11_30 + PIXEL12_31 + PIXEL13_31 + PIXEL20_31 + PIXEL21_31 + PIXEL22_32 + PIXEL23_32 + PIXEL30_81 + PIXEL31_81 + PIXEL32_82 + PIXEL33_82 + jmp .loopx_end +..@flag185 + AUXADDRESS + PIXEL00_82 + PIXEL01_82 + PIXEL02_61 + PIXEL03_80 + PIXEL10_32 + PIXEL11_32 + PIXEL12_30 + PIXEL13_10 + PIXEL20_31 + PIXEL21_31 + PIXEL22_32 + PIXEL23_32 + PIXEL30_81 + PIXEL31_81 + PIXEL32_82 + PIXEL33_82 + jmp .loopx_end +..@flag61 + AUXADDRESS + PIXEL00_82 + PIXEL01_82 + PIXEL02_81 + PIXEL03_81 + PIXEL10_32 + PIXEL11_32 + PIXEL12_31 + PIXEL13_31 + PIXEL20_31 + PIXEL21_31 + PIXEL22_30 + PIXEL23_10 + PIXEL30_81 + PIXEL31_81 + PIXEL32_61 + PIXEL33_80 + jmp .loopx_end +..@flag157 + AUXADDRESS + PIXEL00_82 + PIXEL01_82 + PIXEL02_81 + PIXEL03_81 + PIXEL10_32 + PIXEL11_32 + PIXEL12_31 + PIXEL13_31 + PIXEL20_10 + PIXEL21_30 + PIXEL22_32 + PIXEL23_32 + PIXEL30_80 + PIXEL31_61 + PIXEL32_82 + PIXEL33_82 + jmp .loopx_end +..@flag103 + AUXADDRESS + PIXEL00_81 + PIXEL01_31 + PIXEL02_32 + PIXEL03_82 + PIXEL10_81 + PIXEL11_31 + PIXEL12_32 + PIXEL13_82 + PIXEL20_82 + PIXEL21_32 + PIXEL22_30 + PIXEL23_61 + PIXEL30_82 + PIXEL31_32 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag227 + AUXADDRESS + PIXEL00_81 + PIXEL01_31 + PIXEL02_10 + PIXEL03_80 + PIXEL10_81 + PIXEL11_31 + PIXEL12_30 + PIXEL13_61 + PIXEL20_82 + PIXEL21_32 + PIXEL22_31 + PIXEL23_81 + PIXEL30_82 + PIXEL31_32 + PIXEL32_31 + PIXEL33_81 + jmp .loopx_end +..@flag230 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + PIXEL02_32 + PIXEL03_82 + PIXEL10_61 + PIXEL11_30 + PIXEL12_32 + PIXEL13_82 + PIXEL20_82 + PIXEL21_32 + PIXEL22_31 + PIXEL23_81 + PIXEL30_82 + PIXEL31_32 + PIXEL32_31 + PIXEL33_81 + jmp .loopx_end +..@flag199 + AUXADDRESS + PIXEL00_81 + PIXEL01_31 + PIXEL02_32 + PIXEL03_82 + PIXEL10_81 + PIXEL11_31 + PIXEL12_32 + PIXEL13_82 + PIXEL20_61 + PIXEL21_30 + PIXEL22_31 + PIXEL23_81 + PIXEL30_80 + PIXEL31_10 + PIXEL32_31 + PIXEL33_81 + jmp .loopx_end +..@flag220 + AUXADDRESS + PIXEL00_80 + PIXEL01_61 + PIXEL02_81 + PIXEL03_81 + PIXEL10_10 + PIXEL11_30 + PIXEL12_31 + PIXEL13_31 + DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11 + PIXEL22_0 + DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50 + jmp .loopx_end +..@flag158 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0 + DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50 + PIXEL12_0 + PIXEL20_10 + PIXEL21_30 + PIXEL22_32 + PIXEL23_32 + PIXEL30_80 + PIXEL31_61 + PIXEL32_82 + PIXEL33_82 + jmp .loopx_end +..@flag234 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0 + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_61 + DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50 + PIXEL21_0 + PIXEL22_31 + PIXEL23_81 + PIXEL32_31 + PIXEL33_81 + jmp .loopx_end +..@flag242 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12 + PIXEL10_61 + PIXEL11_30 + PIXEL20_82 + PIXEL21_32 + PIXEL22_0 + DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50 + PIXEL30_82 + PIXEL31_32 + jmp .loopx_end +..@flag59 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50 + DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12 + PIXEL11_0 + PIXEL20_31 + PIXEL21_31 + PIXEL22_30 + PIXEL23_10 + PIXEL30_81 + PIXEL31_81 + PIXEL32_61 + PIXEL33_80 + jmp .loopx_end +..@flag121 + AUXADDRESS + PIXEL00_82 + PIXEL01_82 + PIXEL02_61 + PIXEL03_80 + PIXEL10_32 + PIXEL11_32 + PIXEL12_30 + PIXEL13_10 + DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50 + PIXEL21_0 + DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20 + jmp .loopx_end +..@flag87 + AUXADDRESS + PIXEL00_81 + PIXEL01_31 + DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50 + PIXEL10_81 + PIXEL11_31 + PIXEL12_0 + PIXEL20_61 + PIXEL21_30 + DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20 + PIXEL30_80 + PIXEL31_10 + jmp .loopx_end +..@flag79 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50 + PIXEL02_32 + PIXEL03_82 + PIXEL11_0 + PIXEL12_32 + PIXEL13_82 + DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11 + PIXEL22_30 + PIXEL23_61 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag122 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0 + DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12 + DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50 + PIXEL21_0 + DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20 + jmp .loopx_end +..@flag94 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0 + DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50 + PIXEL12_0 + DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11 + DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20 + jmp .loopx_end +..@flag218 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0 + DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12 + DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11 + PIXEL22_0 + DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50 + jmp .loopx_end +..@flag91 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50 + DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12 + PIXEL11_0 + DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11 + DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20 + jmp .loopx_end +..@flag229 + AUXADDRESS + PIXEL00_20 + PIXEL01_60 + PIXEL02_60 + PIXEL03_20 + PIXEL10_60 + PIXEL11_70 + PIXEL12_70 + PIXEL13_60 + PIXEL20_82 + PIXEL21_32 + PIXEL22_31 + PIXEL23_81 + PIXEL30_82 + PIXEL31_32 + PIXEL32_31 + PIXEL33_81 + jmp .loopx_end +..@flag167 + AUXADDRESS + PIXEL00_81 + PIXEL01_31 + PIXEL02_32 + PIXEL03_82 + PIXEL10_81 + PIXEL11_31 + PIXEL12_32 + PIXEL13_82 + PIXEL20_60 + PIXEL21_70 + PIXEL22_70 + PIXEL23_60 + PIXEL30_20 + PIXEL31_60 + PIXEL32_60 + PIXEL33_20 + jmp .loopx_end +..@flag173 + AUXADDRESS + PIXEL00_82 + PIXEL01_82 + PIXEL02_60 + PIXEL03_20 + PIXEL10_32 + PIXEL11_32 + PIXEL12_70 + PIXEL13_60 + PIXEL20_31 + PIXEL21_31 + PIXEL22_70 + PIXEL23_60 + PIXEL30_81 + PIXEL31_81 + PIXEL32_60 + PIXEL33_20 + jmp .loopx_end +..@flag181 + AUXADDRESS + PIXEL00_20 + PIXEL01_60 + PIXEL02_81 + PIXEL03_81 + PIXEL10_60 + PIXEL11_70 + PIXEL12_31 + PIXEL13_31 + PIXEL20_60 + PIXEL21_70 + PIXEL22_32 + PIXEL23_32 + PIXEL30_20 + PIXEL31_60 + PIXEL32_82 + PIXEL33_82 + jmp .loopx_end +..@flag186 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0 + DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12 + PIXEL20_31 + PIXEL21_31 + PIXEL22_32 + PIXEL23_32 + PIXEL30_81 + PIXEL31_81 + PIXEL32_82 + PIXEL33_82 + jmp .loopx_end +..@flag115 + AUXADDRESS + PIXEL00_81 + PIXEL01_31 + DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12 + PIXEL10_81 + PIXEL11_31 + PIXEL20_82 + PIXEL21_32 + DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20 + PIXEL30_82 + PIXEL31_32 + jmp .loopx_end +..@flag93 + AUXADDRESS + PIXEL00_82 + PIXEL01_82 + PIXEL02_81 + PIXEL03_81 + PIXEL10_32 + PIXEL11_32 + PIXEL12_31 + PIXEL13_31 + DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11 + DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20 + jmp .loopx_end +..@flag206 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0 + PIXEL02_32 + PIXEL03_82 + PIXEL12_32 + PIXEL13_82 + DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11 + PIXEL22_31 + PIXEL23_81 + PIXEL32_31 + PIXEL33_81 + jmp .loopx_end +..@flag205 +..@flag201 + AUXADDRESS + PIXEL00_82 + PIXEL01_82 + PIXEL02_60 + PIXEL03_20 + PIXEL10_32 + PIXEL11_32 + PIXEL12_70 + PIXEL13_60 + DiffOrNot w8,w4,PIXEL20_10,PIXEL21_30,PIXEL30_80,PIXEL31_10,PIXEL20_12,PIXEL21_0,PIXEL30_20,PIXEL31_11 + PIXEL22_31 + PIXEL23_81 + PIXEL32_31 + PIXEL33_81 + jmp .loopx_end +..@flag174 +..@flag46 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_80,PIXEL01_10,PIXEL10_10,PIXEL11_30,PIXEL00_20,PIXEL01_12,PIXEL10_11,PIXEL11_0 + PIXEL02_32 + PIXEL03_82 + PIXEL12_32 + PIXEL13_82 + PIXEL20_31 + PIXEL21_31 + PIXEL22_70 + PIXEL23_60 + PIXEL30_81 + PIXEL31_81 + PIXEL32_60 + PIXEL33_20 + jmp .loopx_end +..@flag179 +..@flag147 + AUXADDRESS + PIXEL00_81 + PIXEL01_31 + DiffOrNot w2,w6,PIXEL02_10,PIXEL03_80,PIXEL12_30,PIXEL13_10,PIXEL02_11,PIXEL03_20,PIXEL12_0,PIXEL13_12 + PIXEL10_81 + PIXEL11_31 + PIXEL20_60 + PIXEL21_70 + PIXEL22_32 + PIXEL23_32 + PIXEL30_20 + PIXEL31_60 + PIXEL32_82 + PIXEL33_82 + jmp .loopx_end +..@flag117 +..@flag116 + AUXADDRESS + PIXEL00_20 + PIXEL01_60 + PIXEL02_81 + PIXEL03_81 + PIXEL10_60 + PIXEL11_70 + PIXEL12_31 + PIXEL13_31 + PIXEL20_82 + PIXEL21_32 + DiffOrNot w6,w8,PIXEL22_30,PIXEL23_10,PIXEL32_10,PIXEL33_80,PIXEL22_0,PIXEL23_11,PIXEL32_12,PIXEL33_20 + PIXEL30_82 + PIXEL31_32 + jmp .loopx_end +..@flag189 + AUXADDRESS + PIXEL00_82 + PIXEL01_82 + PIXEL02_81 + PIXEL03_81 + PIXEL10_32 + PIXEL11_32 + PIXEL12_31 + PIXEL13_31 + PIXEL20_31 + PIXEL21_31 + PIXEL22_32 + PIXEL23_32 + PIXEL30_81 + PIXEL31_81 + PIXEL32_82 + PIXEL33_82 + jmp .loopx_end +..@flag231 + AUXADDRESS + PIXEL00_81 + PIXEL01_31 + PIXEL02_32 + PIXEL03_82 + PIXEL10_81 + PIXEL11_31 + PIXEL12_32 + PIXEL13_82 + PIXEL20_82 + PIXEL21_32 + PIXEL22_31 + PIXEL23_81 + PIXEL30_82 + PIXEL31_32 + PIXEL32_31 + PIXEL33_81 + jmp .loopx_end +..@flag126 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50 + PIXEL10_10 + PIXEL11_30 + PIXEL12_0 + DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50 + PIXEL21_0 + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag219 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50 + PIXEL02_10 + PIXEL03_80 + PIXEL11_0 + PIXEL12_30 + PIXEL13_10 + PIXEL20_10 + PIXEL21_30 + PIXEL22_0 + DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50 + PIXEL30_80 + PIXEL31_10 + jmp .loopx_end +..@flag125 + AUXADDRESS + DiffOrNot w8,w4,PIXEL00_82,PIXEL10_32,PIXEL20_0,PIXEL21_0,PIXEL30_0,PIXEL31_0,PIXEL00_11,PIXEL10_13,PIXEL20_83,PIXEL21_70,PIXEL30_50,PIXEL31_21 + PIXEL01_82 + PIXEL02_81 + PIXEL03_81 + PIXEL11_32 + PIXEL12_31 + PIXEL13_31 + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag221 + AUXADDRESS + PIXEL00_82 + PIXEL01_82 + PIXEL02_81 + DiffOrNot w6,w8,PIXEL03_81,PIXEL13_31,PIXEL22_0,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL03_12,PIXEL13_14,PIXEL22_70,PIXEL23_83,PIXEL32_21,PIXEL33_50 + PIXEL10_32 + PIXEL11_32 + PIXEL12_31 + PIXEL20_10 + PIXEL21_30 + PIXEL30_80 + PIXEL31_10 + jmp .loopx_end +..@flag207 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL02_32,PIXEL03_82,PIXEL10_0,PIXEL11_0,PIXEL00_50,PIXEL01_83,PIXEL02_13,PIXEL03_11,PIXEL10_21,PIXEL11_70 + PIXEL12_32 + PIXEL13_82 + PIXEL20_10 + PIXEL21_30 + PIXEL22_31 + PIXEL23_81 + PIXEL30_80 + PIXEL31_10 + PIXEL32_31 + PIXEL33_81 + jmp .loopx_end +..@flag238 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + PIXEL02_32 + PIXEL03_82 + PIXEL10_10 + PIXEL11_30 + PIXEL12_32 + PIXEL13_82 + DiffOrNot w8,w4,PIXEL20_0,PIXEL21_0,PIXEL30_0,PIXEL31_0,PIXEL32_31,PIXEL33_81,PIXEL20_21,PIXEL21_70,PIXEL30_50,PIXEL31_83,PIXEL32_14,PIXEL33_12 + PIXEL22_31 + PIXEL23_81 + jmp .loopx_end +..@flag190 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL12_0,PIXEL13_0,PIXEL23_32,PIXEL33_82,PIXEL02_21,PIXEL03_50,PIXEL12_70,PIXEL13_83,PIXEL23_13,PIXEL33_11 + PIXEL10_10 + PIXEL11_30 + PIXEL20_31 + PIXEL21_31 + PIXEL22_32 + PIXEL30_81 + PIXEL31_81 + PIXEL32_82 + jmp .loopx_end +..@flag187 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL11_0,PIXEL20_31,PIXEL30_81,PIXEL00_50,PIXEL01_21,PIXEL10_83,PIXEL11_70,PIXEL20_14,PIXEL30_12 + PIXEL02_10 + PIXEL03_80 + PIXEL12_30 + PIXEL13_10 + PIXEL21_31 + PIXEL22_32 + PIXEL23_32 + PIXEL31_81 + PIXEL32_82 + PIXEL33_82 + jmp .loopx_end +..@flag243 + AUXADDRESS + PIXEL00_81 + PIXEL01_31 + PIXEL02_10 + PIXEL03_80 + PIXEL10_81 + PIXEL11_31 + PIXEL12_30 + PIXEL13_10 + PIXEL20_82 + PIXEL21_32 + DiffOrNot w6,w8,PIXEL22_0,PIXEL23_0,PIXEL30_82,PIXEL31_32,PIXEL32_0,PIXEL33_0,PIXEL22_70,PIXEL23_21,PIXEL30_11,PIXEL31_13,PIXEL32_83,PIXEL33_50 + jmp .loopx_end +..@flag119 + AUXADDRESS + DiffOrNot w2,w6,PIXEL00_81,PIXEL01_31,PIXEL02_0,PIXEL03_0,PIXEL12_0,PIXEL13_0,PIXEL00_12,PIXEL01_14,PIXEL02_83,PIXEL03_50,PIXEL12_70,PIXEL13_21 + PIXEL10_81 + PIXEL11_31 + PIXEL20_82 + PIXEL21_32 + PIXEL22_30 + PIXEL23_10 + PIXEL30_82 + PIXEL31_32 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag237 +..@flag233 + AUXADDRESS + PIXEL00_82 + PIXEL01_82 + PIXEL02_60 + PIXEL03_20 + PIXEL10_32 + PIXEL11_32 + PIXEL12_70 + PIXEL13_60 + PIXEL20_0 + PIXEL21_0 + PIXEL22_31 + PIXEL23_81 + DiffOrNot w8,w4,PIXEL30_0,PIXEL30_20 + PIXEL31_0 + PIXEL32_31 + PIXEL33_81 + jmp .loopx_end +..@flag175 +..@flag47 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20 + PIXEL01_0 + PIXEL02_32 + PIXEL03_82 + PIXEL10_0 + PIXEL11_0 + PIXEL12_32 + PIXEL13_82 + PIXEL20_31 + PIXEL21_31 + PIXEL22_70 + PIXEL23_60 + PIXEL30_81 + PIXEL31_81 + PIXEL32_60 + PIXEL33_20 + jmp .loopx_end +..@flag183 +..@flag151 + AUXADDRESS + PIXEL00_81 + PIXEL01_31 + PIXEL02_0 + DiffOrNot w2,w6,PIXEL03_0,PIXEL03_20 + PIXEL10_81 + PIXEL11_31 + PIXEL12_0 + PIXEL13_0 + PIXEL20_60 + PIXEL21_70 + PIXEL22_32 + PIXEL23_32 + PIXEL30_20 + PIXEL31_60 + PIXEL32_82 + PIXEL33_82 + jmp .loopx_end +..@flag245 +..@flag244 + AUXADDRESS + PIXEL00_20 + PIXEL01_60 + PIXEL02_81 + PIXEL03_81 + PIXEL10_60 + PIXEL11_70 + PIXEL12_31 + PIXEL13_31 + PIXEL20_82 + PIXEL21_32 + PIXEL22_0 + PIXEL23_0 + PIXEL30_82 + PIXEL31_32 + PIXEL32_0 + DiffOrNot w6,w8,PIXEL33_0,PIXEL33_20 + jmp .loopx_end +..@flag250 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + PIXEL02_10 + PIXEL03_80 + PIXEL10_10 + PIXEL11_30 + PIXEL12_30 + PIXEL13_10 + DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50 + PIXEL21_0 + PIXEL22_0 + DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50 + jmp .loopx_end +..@flag123 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50 + PIXEL02_10 + PIXEL03_80 + PIXEL11_0 + PIXEL12_30 + PIXEL13_10 + DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50 + PIXEL21_0 + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag95 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50 + DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50 + PIXEL11_0 + PIXEL12_0 + PIXEL20_10 + PIXEL21_30 + PIXEL22_30 + PIXEL23_10 + PIXEL30_80 + PIXEL31_10 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag222 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50 + PIXEL10_10 + PIXEL11_30 + PIXEL12_0 + PIXEL20_10 + PIXEL21_30 + PIXEL22_0 + DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50 + PIXEL30_80 + PIXEL31_10 + jmp .loopx_end +..@flag252 + AUXADDRESS + PIXEL00_80 + PIXEL01_61 + PIXEL02_81 + PIXEL03_81 + PIXEL10_10 + PIXEL11_30 + PIXEL12_31 + PIXEL13_31 + DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50 + PIXEL21_0 + PIXEL22_0 + PIXEL23_0 + PIXEL32_0 + DiffOrNot w6,w8,PIXEL33_0,PIXEL33_20 + jmp .loopx_end +..@flag249 + AUXADDRESS + PIXEL00_82 + PIXEL01_82 + PIXEL02_61 + PIXEL03_80 + PIXEL10_32 + PIXEL11_32 + PIXEL12_30 + PIXEL13_10 + PIXEL20_0 + PIXEL21_0 + PIXEL22_0 + DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50 + DiffOrNot w8,w4,PIXEL30_0,PIXEL30_20 + PIXEL31_0 + jmp .loopx_end +..@flag235 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50 + PIXEL02_10 + PIXEL03_80 + PIXEL11_0 + PIXEL12_30 + PIXEL13_61 + PIXEL20_0 + PIXEL21_0 + PIXEL22_31 + PIXEL23_81 + DiffOrNot w8,w4,PIXEL30_0,PIXEL30_20 + PIXEL31_0 + PIXEL32_31 + PIXEL33_81 + jmp .loopx_end +..@flag111 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20 + PIXEL01_0 + PIXEL02_32 + PIXEL03_82 + PIXEL10_0 + PIXEL11_0 + PIXEL12_32 + PIXEL13_82 + DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50 + PIXEL21_0 + PIXEL22_30 + PIXEL23_61 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag63 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20 + PIXEL01_0 + DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50 + PIXEL10_0 + PIXEL11_0 + PIXEL12_0 + PIXEL20_31 + PIXEL21_31 + PIXEL22_30 + PIXEL23_10 + PIXEL30_81 + PIXEL31_81 + PIXEL32_61 + PIXEL33_80 + jmp .loopx_end +..@flag159 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50 + PIXEL02_0 + DiffOrNot w2,w6,PIXEL03_0,PIXEL03_20 + PIXEL11_0 + PIXEL12_0 + PIXEL13_0 + PIXEL20_10 + PIXEL21_30 + PIXEL22_32 + PIXEL23_32 + PIXEL30_80 + PIXEL31_61 + PIXEL32_82 + PIXEL33_82 + jmp .loopx_end +..@flag215 + AUXADDRESS + PIXEL00_81 + PIXEL01_31 + PIXEL02_0 + DiffOrNot w2,w6,PIXEL03_0,PIXEL03_20 + PIXEL10_81 + PIXEL11_31 + PIXEL12_0 + PIXEL13_0 + PIXEL20_61 + PIXEL21_30 + PIXEL22_0 + DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50 + PIXEL30_80 + PIXEL31_10 + jmp .loopx_end +..@flag246 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50 + PIXEL10_61 + PIXEL11_30 + PIXEL12_0 + PIXEL20_82 + PIXEL21_32 + PIXEL22_0 + PIXEL23_0 + PIXEL30_82 + PIXEL31_32 + PIXEL32_0 + DiffOrNot w6,w8,PIXEL33_0,PIXEL33_20 + jmp .loopx_end +..@flag254 + AUXADDRESS + PIXEL00_80 + PIXEL01_10 + DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50 + PIXEL10_10 + PIXEL11_30 + PIXEL12_0 + DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50 + PIXEL21_0 + PIXEL22_0 + PIXEL23_0 + PIXEL32_0 + DiffOrNot w6,w8,PIXEL33_0,PIXEL33_20 + jmp .loopx_end +..@flag253 + AUXADDRESS + PIXEL00_82 + PIXEL01_82 + PIXEL02_81 + PIXEL03_81 + PIXEL10_32 + PIXEL11_32 + PIXEL12_31 + PIXEL13_31 + PIXEL20_0 + PIXEL21_0 + PIXEL22_0 + PIXEL23_0 + DiffOrNot w8,w4,PIXEL30_0,PIXEL30_20 + PIXEL31_0 + PIXEL32_0 + DiffOrNot w6,w8,PIXEL33_0,PIXEL33_20 + jmp .loopx_end +..@flag251 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50 + PIXEL02_10 + PIXEL03_80 + PIXEL11_0 + PIXEL12_30 + PIXEL13_10 + PIXEL20_0 + PIXEL21_0 + PIXEL22_0 + DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50 + DiffOrNot w8,w4,PIXEL30_0,PIXEL30_20 + PIXEL31_0 + jmp .loopx_end +..@flag239 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20 + PIXEL01_0 + PIXEL02_32 + PIXEL03_82 + PIXEL10_0 + PIXEL11_0 + PIXEL12_32 + PIXEL13_82 + PIXEL20_0 + PIXEL21_0 + PIXEL22_31 + PIXEL23_81 + DiffOrNot w8,w4,PIXEL30_0,PIXEL30_20 + PIXEL31_0 + PIXEL32_31 + PIXEL33_81 + jmp .loopx_end +..@flag127 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20 + PIXEL01_0 + DiffOrNot w2,w6,PIXEL02_0,PIXEL03_0,PIXEL13_0,PIXEL02_50,PIXEL03_50,PIXEL13_50 + PIXEL10_0 + PIXEL11_0 + PIXEL12_0 + DiffOrNot w8,w4,PIXEL20_0,PIXEL30_0,PIXEL31_0,PIXEL20_50,PIXEL30_50,PIXEL31_50 + PIXEL21_0 + PIXEL22_30 + PIXEL23_10 + PIXEL32_10 + PIXEL33_80 + jmp .loopx_end +..@flag191 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20 + PIXEL01_0 + PIXEL02_0 + DiffOrNot w2,w6,PIXEL03_0,PIXEL03_20 + PIXEL10_0 + PIXEL11_0 + PIXEL12_0 + PIXEL13_0 + PIXEL20_31 + PIXEL21_31 + PIXEL22_32 + PIXEL23_32 + PIXEL30_81 + PIXEL31_81 + PIXEL32_82 + PIXEL33_82 + jmp .loopx_end +..@flag223 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL01_0,PIXEL10_0,PIXEL00_50,PIXEL01_50,PIXEL10_50 + PIXEL02_0 + DiffOrNot w2,w6,PIXEL03_0,PIXEL03_20 + PIXEL11_0 + PIXEL12_0 + PIXEL13_0 + PIXEL20_10 + PIXEL21_30 + PIXEL22_0 + DiffOrNot w6,w8,PIXEL23_0,PIXEL32_0,PIXEL33_0,PIXEL23_50,PIXEL32_50,PIXEL33_50 + PIXEL30_80 + PIXEL31_10 + jmp .loopx_end +..@flag247 + AUXADDRESS + PIXEL00_81 + PIXEL01_31 + PIXEL02_0 + DiffOrNot w2,w6,PIXEL03_0,PIXEL03_20 + PIXEL10_81 + PIXEL11_31 + PIXEL12_0 + PIXEL13_0 + PIXEL20_82 + PIXEL21_32 + PIXEL22_0 + PIXEL23_0 + PIXEL30_82 + PIXEL31_32 + PIXEL32_0 + DiffOrNot w6,w8,PIXEL33_0,PIXEL33_20 + jmp .loopx_end +..@flag255 + AUXADDRESS + DiffOrNot w4,w2,PIXEL00_0,PIXEL00_20 + PIXEL01_0 + PIXEL02_0 + DiffOrNot w2,w6,PIXEL03_0,PIXEL03_20 + PIXEL10_0 + PIXEL11_0 + PIXEL12_0 + PIXEL13_0 + PIXEL20_0 + PIXEL21_0 + PIXEL22_0 + PIXEL23_0 + DiffOrNot w8,w4,PIXEL30_0,PIXEL30_20 + PIXEL31_0 + PIXEL32_0 + DiffOrNot w6,w8,PIXEL33_0,PIXEL33_20 + jmp .loopx_end + + +..@cross0 + mov ebx,[ebp+dstpitch] + AUXADDRESS + mov [edi],eax + mov [edi+4],eax + mov [edi+8],eax + mov [edi+12],eax + mov [edi+ebx],eax + mov [edi+ebx+4],eax + mov [edi+ebx+8],eax + mov [edi+ebx+12],eax + mov [ecx],eax + mov [ecx+4],eax + mov [ecx+8],eax + mov [ecx+12],eax + mov [ecx+ebx],eax + mov [ecx+ebx+4],eax + mov [ecx+ebx+8],eax + mov [ecx+ebx+12],eax + jmp .loopx_end +..@cross1 + mov ecx,[w2] + mov edx,eax + shl edx,2 + add edx,[ebx+ecx*4] + sub edx,eax + shr edx,2 + mov [edi],edx + mov [edi+4],edx + mov [edi+8],edx + mov [edi+12],edx + mov ebx,[ebp+dstpitch] + AUXADDRESS + mov [edi],edx + mov [edi+4],edx + mov [edi+ebx],eax + mov [edi+ebx+4],eax + jmp .loopx_end +..@cross2 + mov ecx,[w4] + mov edx,eax + shl edx,2 + add edx,[ebx+ecx*4] + sub edx,eax + shr edx,2 + mov ebx,[ebp+dstpitch] + mov [edi],edx + mov [edi+4],eax + mov [edi+ebx],edx + mov [edi+ebx+4],eax + jmp .loopx_end +..@cross4 + mov ecx,[w6] + mov edx,eax + shl edx,2 + add edx,[ebx+ecx*4] + sub edx,eax + shr edx,2 + mov ebx,[ebp+dstpitch] + mov [edi],eax + mov [edi+4],edx + mov [edi+ebx],eax + mov [edi+ebx+4],edx + jmp .loopx_end +..@cross8 + mov ecx,[w8] + mov edx,eax + shl edx,2 + add edx,[ebx+ecx*4] + sub edx,eax + shr edx,2 + mov ebx,[ebp+dstpitch] + mov [edi],eax + mov [edi+4],eax + mov [edi+ebx],edx + mov [edi+ebx+4],edx + jmp .loopx_end +..@crossN + mov edx,[w2] + mov ecx,[ebx+edx*4] + mov [c2],ecx + mov edx,[w4] + mov ecx,[ebx+edx*4] + mov [c4],ecx + mov edx,[w6] + mov ecx,[ebx+edx*4] + mov [c6],ecx + mov edx,[w8] + mov ecx,[ebx+edx*4] + mov [c8],ecx + mov ebx,[ebp+dstpitch] + jmp ..@flag0 + +.loopx_end + add esi,2 + add edi,16 + dec dword[xcounter] + jle .xres_2 + jmp .loopx +.xres_2 + ; x=Xres-2 - special case + jl .xres_1 + mov ebx,[prevline] + movq mm5,[esi+ebx-4] + movq mm6,[esi-4] + mov ebx,[nextline] + movq mm7,[esi+ebx-4] + psrlq mm5,16 + psrlq mm6,16 + psrlq mm7,16 + movd eax,mm5 + movzx edx,ax + mov [w1],edx + shr eax,16 + mov [w2],eax + psrlq mm5,32 + movd eax,mm5 + mov [w3],eax + movd eax,mm6 + movzx edx,ax + mov [w4],edx + shr eax,16 + mov [w5],eax + psrlq mm6,32 + movd eax,mm6 + mov [w6],eax + movd eax,mm7 + movzx edx,ax + mov [w7],edx + shr eax,16 + mov [w8],eax + psrlq mm7,32 + movd eax,mm7 + mov [w9],eax + jmp .flags +.xres_1 + cmp dword[xcounter],-1 + jl .nexty + ; x=Xres-1 - special case + mov ebx,[prevline] + movq mm5,[esi+ebx-6] + movq mm6,[esi-6] + mov ebx,[nextline] + movq mm7,[esi+ebx-6] + psrlq mm5,32 + psrlq mm6,32 + psrlq mm7,32 + movd eax,mm5 + movzx edx,ax + mov [w1],edx + shr eax,16 + mov [w2],eax + mov [w3],eax + movd eax,mm6 + movzx edx,ax + mov [w4],edx + shr eax,16 + mov [w5],eax + mov [w6],eax + movd eax,mm7 + movzx edx,ax + mov [w7],edx + shr eax,16 + mov [w8],eax + mov [w9],eax + jmp .flags +.nexty + add edi,ebx + add edi,ebx + add edi,ebx + add esi,[ebp+srcpitch] + dec dword[linesleft] + jz .fin + mov ebx,[ebp+Xres] + shl ebx,1 + cmp dword[linesleft],1 + je .lastline + mov dword[nextline],ebx + neg ebx + mov dword[prevline],ebx + jmp .loopy +.lastline + mov dword[nextline],0 + neg ebx + mov dword[prevline],ebx + jmp .loopy +.fin + emms + popad + mov esp,ebp + pop ebp + ret + +SECTION .data +FuncTable + dd ..@flag0, ..@flag1, ..@flag2, ..@flag3, ..@flag4, ..@flag5, ..@flag6, ..@flag7 + dd ..@flag8, ..@flag9, ..@flag10, ..@flag11, ..@flag12, ..@flag13, ..@flag14, ..@flag15 + dd ..@flag16, ..@flag17, ..@flag18, ..@flag19, ..@flag20, ..@flag21, ..@flag22, ..@flag23 + dd ..@flag24, ..@flag25, ..@flag26, ..@flag27, ..@flag28, ..@flag29, ..@flag30, ..@flag31 + dd ..@flag32, ..@flag33, ..@flag34, ..@flag35, ..@flag36, ..@flag37, ..@flag38, ..@flag39 + dd ..@flag40, ..@flag41, ..@flag42, ..@flag43, ..@flag44, ..@flag45, ..@flag46, ..@flag47 + dd ..@flag48, ..@flag49, ..@flag50, ..@flag51, ..@flag52, ..@flag53, ..@flag54, ..@flag55 + dd ..@flag56, ..@flag57, ..@flag58, ..@flag59, ..@flag60, ..@flag61, ..@flag62, ..@flag63 + dd ..@flag64, ..@flag65, ..@flag66, ..@flag67, ..@flag68, ..@flag69, ..@flag70, ..@flag71 + dd ..@flag72, ..@flag73, ..@flag74, ..@flag75, ..@flag76, ..@flag77, ..@flag78, ..@flag79 + dd ..@flag80, ..@flag81, ..@flag82, ..@flag83, ..@flag84, ..@flag85, ..@flag86, ..@flag87 + dd ..@flag88, ..@flag89, ..@flag90, ..@flag91, ..@flag92, ..@flag93, ..@flag94, ..@flag95 + dd ..@flag96, ..@flag97, ..@flag98, ..@flag99, ..@flag100, ..@flag101, ..@flag102, ..@flag103 + dd ..@flag104, ..@flag105, ..@flag106, ..@flag107, ..@flag108, ..@flag109, ..@flag110, ..@flag111 + dd ..@flag112, ..@flag113, ..@flag114, ..@flag115, ..@flag116, ..@flag117, ..@flag118, ..@flag119 + dd ..@flag120, ..@flag121, ..@flag122, ..@flag123, ..@flag124, ..@flag125, ..@flag126, ..@flag127 + dd ..@flag128, ..@flag129, ..@flag130, ..@flag131, ..@flag132, ..@flag133, ..@flag134, ..@flag135 + dd ..@flag136, ..@flag137, ..@flag138, ..@flag139, ..@flag140, ..@flag141, ..@flag142, ..@flag143 + dd ..@flag144, ..@flag145, ..@flag146, ..@flag147, ..@flag148, ..@flag149, ..@flag150, ..@flag151 + dd ..@flag152, ..@flag153, ..@flag154, ..@flag155, ..@flag156, ..@flag157, ..@flag158, ..@flag159 + dd ..@flag160, ..@flag161, ..@flag162, ..@flag163, ..@flag164, ..@flag165, ..@flag166, ..@flag167 + dd ..@flag168, ..@flag169, ..@flag170, ..@flag171, ..@flag172, ..@flag173, ..@flag174, ..@flag175 + dd ..@flag176, ..@flag177, ..@flag178, ..@flag179, ..@flag180, ..@flag181, ..@flag182, ..@flag183 + dd ..@flag184, ..@flag185, ..@flag186, ..@flag187, ..@flag188, ..@flag189, ..@flag190, ..@flag191 + dd ..@flag192, ..@flag193, ..@flag194, ..@flag195, ..@flag196, ..@flag197, ..@flag198, ..@flag199 + dd ..@flag200, ..@flag201, ..@flag202, ..@flag203, ..@flag204, ..@flag205, ..@flag206, ..@flag207 + dd ..@flag208, ..@flag209, ..@flag210, ..@flag211, ..@flag212, ..@flag213, ..@flag214, ..@flag215 + dd ..@flag216, ..@flag217, ..@flag218, ..@flag219, ..@flag220, ..@flag221, ..@flag222, ..@flag223 + dd ..@flag224, ..@flag225, ..@flag226, ..@flag227, ..@flag228, ..@flag229, ..@flag230, ..@flag231 + dd ..@flag232, ..@flag233, ..@flag234, ..@flag235, ..@flag236, ..@flag237, ..@flag238, ..@flag239 + dd ..@flag240, ..@flag241, ..@flag242, ..@flag243, ..@flag244, ..@flag245, ..@flag246, ..@flag247 + dd ..@flag248, ..@flag249, ..@flag250, ..@flag251, ..@flag252, ..@flag253, ..@flag254, ..@flag255 + + diff --git a/od-win32/ioport.c b/od-win32/ioport.c new file mode 100755 index 00000000..b7a6b4f3 --- /dev/null +++ b/od-win32/ioport.c @@ -0,0 +1,275 @@ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include + +//#define IOPORT_EMU +#define io_log +//#define io_log write_log + +typedef int bool; + +#include + +#ifndef IOPORT_EMU +#include +#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 + +typedef BOOL (*closePort)(HANDLE); +typedef BOOL (*executeCycle)(HANDLE, PARAPORT_CYCLE*, int); +typedef BOOL (*getPortInfo)(HANDLE, PARAPORT_INFO*); +typedef HANDLE* (*openPort)(const char*); +static closePort pp_closeport; +static executeCycle pp_executecycle; +static getPortInfo pp_getportinfo; +static openPort pp_openport; +static HMODULE para; +static HANDLE pport; + +void paraport_free (void) +{ + if (para) { + if (pport) + pp_closeport (pport); + pport = 0; + FreeLibrary (para); + para = 0; + } +} + +int paraport_init (void) +{ + char tmp[10]; + int mask = 0, i; + HANDLE pp; + + paraport_free (); + para = LoadLibrary("ParaPort.dll"); + if (!para) { + write_log ("PARAPORT: no ParaPort.dll, direct parallel port emulation disabled\n"); + return 0; + } + pp_closeport = (closePort)GetProcAddress (para, "closePort"); + pp_executecycle = (executeCycle)GetProcAddress (para, "executeCycle"); + pp_getportinfo = (getPortInfo)GetProcAddress (para, "getPortInfo"); + pp_openport = (openPort)GetProcAddress (para, "openPort"); + if (!pp_openport || !pp_closeport || !pp_executecycle) { + write_log ("PARAPORT: GetProcAddress() failed\n"); + paraport_free (); + } + write_log("PARAPORT:"); + for (i = 0; i < 4 ; i++) { + sprintf (tmp, "LPT%d", i + 1); + pp = pp_openport (tmp); + if (pp != INVALID_HANDLE_VALUE) { + mask |= 1 << i; + pp_closeport (pp); + write_log(" %s", tmp); + } + pp = 0; + } + if (!mask) + write_log ("no parallel ports detected"); + write_log("\n"); + return mask; +} + +int paraport_open (char *port) +{ + static char oldport[10]; + + if (!para) + return 0; + if (pport && !strcmp (port, oldport)) + return 1; + pport = pp_openport(port); + if (!pport) { + write_log ("PARAPORT: couldn't open '%s'\n", port); + paraport_free (); + return 0; + } + strcpy (oldport, port); + write_log("PARAPORT: port '%s' opened\n", port); + return 1; +} + + +int parallel_direct_write_status (uae_u8 v, uae_u8 dir) +{ + PARAPORT_CYCLE c[2]; + int ok = 1; + + if (!pport) + return 0; + memset (c + 0, 0, sizeof (PARAPORT_CYCLE)); + c[0].MaskControl = PARAPORT_MASK_CONTROL_SELECTIN; + if ((dir & 1)) { + write_log ("PARAPORT: BUSY can't be output\n"); + ok = 0; + } + if ((dir & 2)) { + write_log ("PARAPORT: POUT can't be output\n"); + ok = 0; + } + if ((dir & 4) && (v & 4)) + c[0].Control |= PARAPORT_MASK_CONTROL_SELECTIN; + if (!pp_executecycle (pport, c, 2)) { + write_log ("PARAPORT: write executeCycle failed, CTL=%02.2X DIR=%02.2X\n", v & 7, dir & 7); + return 0; + } + write_log ("PARAPORT: write CTL=%02.2X DIR=%02.2X\n", v & 7, dir & 7); + return ok; +} + +int parallel_direct_read_status (uae_u8 *vp) +{ + PARAPORT_CYCLE c[1]; + int ok = 1; + uae_u8 v = 0; + + if (!pport) + return 0; + memset (c + 0, 0, sizeof (PARAPORT_CYCLE)); + c[0].MaskStatus = PARAPORT_MASK_STATUS; + if (!pp_executecycle (pport, c, 1)) { + write_log ("PARAPORT: CTL read executeCycle failed\n"); + return 0; + } + if (c[0].Status & PARAPORT_MASK_STATUS_SELECT) + v |= 4; + if (c[0].Status & PARAPORT_MASK_STATUS_PAPEREND) + v |= 2; + if (c[0].Status & PARAPORT_MASK_STATUS_BUSY) + v |= 1; + if (c[0].Status & PARAPORT_MASK_STATUS_ACKNOWLEDGE) + v |= 8; + write_log ("PARAPORT: read CTL=%02.2X\n", v); + v &= 7; + *vp &= ~7; + *vp |= v; + return ok; +} + +int parallel_direct_write_data (uae_u8 v, uae_u8 dir) +{ + PARAPORT_CYCLE c[2]; + int ok = 1; + + if (!pport) + return 0; + if (dir != 0xff) { + write_log ("PARAPORT: unsupported mixed i/o attempted, DATA=%02.2X DIR=%02.2X, ignored\n", v, dir); + return 0; + } + memset (c + 0, 0, sizeof (PARAPORT_CYCLE)); + memset (c + 1, 0, sizeof (PARAPORT_CYCLE)); + c[0].Data = v; + c[0].MaskData = 0xff; + c[0].MaskControl = PARAPORT_MASK_CONTROL_STROBE; + c[0].Control = PARAPORT_MASK_CONTROL_STROBE; + c[0].RepeatFactor = 1; + c[1].MaskControl = PARAPORT_MASK_CONTROL_STROBE; + if (!pp_executecycle (pport, c, 2)) { + write_log ("PARAPORT: write executeCycle failed, data=%02.2X\n", v); + return 0; + } + write_log ("PARAPORT: write DATA=%02.2X\n", v); + return 1; +} + +int parallel_direct_read_data (uae_u8 *v) +{ + static uae_u8 olda, oldb; + PARAPORT_CYCLE c[2]; + int ok = 1; + + if (!pport) + return 0; + memset (c + 0, 0, sizeof (PARAPORT_CYCLE)); + memset (c + 1, 0, sizeof (PARAPORT_CYCLE)); + c[0].MaskData = 0xff; + c[0].MaskControl = PARAPORT_MASK_CONTROL_DIRECTION | PARAPORT_MASK_CONTROL_STROBE; + c[0].Control = PARAPORT_MASK_CONTROL_DIRECTION | PARAPORT_MASK_CONTROL_STROBE; + c[0].RepeatFactor = 1; + c[1].MaskControl = PARAPORT_MASK_CONTROL_STROBE; + c[1].MaskData = 0; + if (!pp_executecycle (pport, c, 2)) { + write_log ("PARAPORT: DATA read executeCycle failed\n"); + return 0; + } + *v = c[0].Data; + write_log("PARAPORT: read DATA=%02.2X\n", v); + return ok; +} + +#endif + + + + + + + + + + + diff --git a/od-win32/ioport.h b/od-win32/ioport.h new file mode 100755 index 00000000..c3eb5c72 --- /dev/null +++ b/od-win32/ioport.h @@ -0,0 +1,9 @@ + +int ioport_init (void); +void ioport_free (void); +void ioport_write (int,uae_u8); +uae_u8 ioport_read (int); + +int paraport_init (void); +int paraport_open (char*); +void paraport_free (void); diff --git a/od-win32/keyboard_win32.c b/od-win32/keyboard_win32.c new file mode 100755 index 00000000..f91bdb1c --- /dev/null +++ b/od-win32/keyboard_win32.c @@ -0,0 +1,402 @@ +/* + * UAE - The Un*x Amiga Emulator + * + * Additional Win32 helper functions not calling any system routines + * + * (c) 1997 Mathias Ortmann + * (c) 1999-2001 Brian King + * (c) 2000-2001 Bernd Roesch + * (c) 2002 Toni Wilen + */ + +#include "config.h" +#include "sysconfig.h" + +#include +#include +#include +#include +#include + +#include "sysdeps.h" +#include "uae.h" +#include "gui.h" +#include "options.h" +#include "memory.h" +#include "custom.h" +#include "events.h" +#include "newcpu.h" +#include "keyboard.h" +#include "inputdevice.h" +#include "xwin.h" +#include "drawing.h" +#include "disk.h" +#include "keybuf.h" +#include "win32.h" +#include "debug.h" +#include "ar.h" +#include "ahidsound.h" +#include "savestate.h" +#include "sound.h" + +extern void screenshot(int); + +//#define DBG_KEYBD 1 +//#define DEBUG_KBD + +static struct uae_input_device_kbr_default keytrans[] = { + + { DIK_ESCAPE, INPUTEVENT_KEY_ESC }, + + { DIK_F1, INPUTEVENT_KEY_F1 }, + { DIK_F2, INPUTEVENT_KEY_F2 }, + { DIK_F3, INPUTEVENT_KEY_F3 }, + { DIK_F4, INPUTEVENT_KEY_F4 }, + { DIK_F5, INPUTEVENT_KEY_F5 }, + { DIK_F6, INPUTEVENT_KEY_F6 }, + { DIK_F7, INPUTEVENT_KEY_F7 }, + { DIK_F8, INPUTEVENT_KEY_F8 }, + { DIK_F9, INPUTEVENT_KEY_F9 }, + { DIK_F10, INPUTEVENT_KEY_F10 }, + + { DIK_1, INPUTEVENT_KEY_1 }, + { DIK_2, INPUTEVENT_KEY_2 }, + { DIK_3, INPUTEVENT_KEY_3 }, + { DIK_4, INPUTEVENT_KEY_4 }, + { DIK_5, INPUTEVENT_KEY_5 }, + { DIK_6, INPUTEVENT_KEY_6 }, + { DIK_7, INPUTEVENT_KEY_7 }, + { DIK_8, INPUTEVENT_KEY_8 }, + { DIK_9, INPUTEVENT_KEY_9 }, + { DIK_0, INPUTEVENT_KEY_0 }, + + { DIK_TAB, INPUTEVENT_KEY_TAB }, + + { DIK_A, INPUTEVENT_KEY_A }, + { DIK_B, INPUTEVENT_KEY_B }, + { DIK_C, INPUTEVENT_KEY_C }, + { DIK_D, INPUTEVENT_KEY_D }, + { DIK_E, INPUTEVENT_KEY_E }, + { DIK_F, INPUTEVENT_KEY_F }, + { DIK_G, INPUTEVENT_KEY_G }, + { DIK_H, INPUTEVENT_KEY_H }, + { DIK_I, INPUTEVENT_KEY_I }, + { DIK_J, INPUTEVENT_KEY_J }, + { DIK_K, INPUTEVENT_KEY_K }, + { DIK_L, INPUTEVENT_KEY_L }, + { DIK_M, INPUTEVENT_KEY_M }, + { DIK_N, INPUTEVENT_KEY_N }, + { DIK_O, INPUTEVENT_KEY_O }, + { DIK_P, INPUTEVENT_KEY_P }, + { DIK_Q, INPUTEVENT_KEY_Q }, + { DIK_R, INPUTEVENT_KEY_R }, + { DIK_S, INPUTEVENT_KEY_S }, + { DIK_T, INPUTEVENT_KEY_T }, + { DIK_U, INPUTEVENT_KEY_U }, + { DIK_W, INPUTEVENT_KEY_W }, + { DIK_V, INPUTEVENT_KEY_V }, + { DIK_X, INPUTEVENT_KEY_X }, + { DIK_Y, INPUTEVENT_KEY_Y }, + { DIK_Z, INPUTEVENT_KEY_Z }, + + { DIK_CAPITAL, INPUTEVENT_KEY_CAPS_LOCK }, + + { DIK_NUMPAD1, INPUTEVENT_KEY_NP_1 }, + { DIK_NUMPAD2, INPUTEVENT_KEY_NP_2 }, + { DIK_NUMPAD3, INPUTEVENT_KEY_NP_3 }, + { DIK_NUMPAD4, INPUTEVENT_KEY_NP_4 }, + { DIK_NUMPAD5, INPUTEVENT_KEY_NP_5 }, + { DIK_NUMPAD6, INPUTEVENT_KEY_NP_6 }, + { DIK_NUMPAD7, INPUTEVENT_KEY_NP_7 }, + { DIK_NUMPAD8, INPUTEVENT_KEY_NP_8 }, + { DIK_NUMPAD9, INPUTEVENT_KEY_NP_9 }, + { DIK_NUMPAD0, INPUTEVENT_KEY_NP_0 }, + { DIK_DECIMAL, INPUTEVENT_KEY_NP_PERIOD }, + { DIK_ADD, INPUTEVENT_KEY_NP_ADD }, + { DIK_SUBTRACT, INPUTEVENT_KEY_NP_SUB }, + { DIK_MULTIPLY, INPUTEVENT_KEY_NP_MUL }, + { DIK_DIVIDE, INPUTEVENT_KEY_NP_DIV }, + { DIK_NUMPADENTER, INPUTEVENT_KEY_ENTER }, + + { DIK_MINUS, INPUTEVENT_KEY_SUB }, + { DIK_EQUALS, INPUTEVENT_KEY_EQUALS }, + { DIK_BACK, INPUTEVENT_KEY_BACKSPACE }, + { DIK_RETURN, INPUTEVENT_KEY_RETURN }, + { DIK_SPACE, INPUTEVENT_KEY_SPACE }, + + { DIK_LSHIFT, INPUTEVENT_KEY_SHIFT_LEFT }, + { DIK_LCONTROL, INPUTEVENT_KEY_CTRL }, + { DIK_LWIN, INPUTEVENT_KEY_AMIGA_LEFT }, + { DIK_LMENU, INPUTEVENT_KEY_ALT_LEFT }, + { DIK_RMENU, INPUTEVENT_KEY_ALT_RIGHT }, + { DIK_RWIN, INPUTEVENT_KEY_AMIGA_RIGHT }, + { DIK_APPS, INPUTEVENT_KEY_AMIGA_RIGHT }, + { DIK_RCONTROL, INPUTEVENT_KEY_CTRL_RIGHT }, + { DIK_RSHIFT, INPUTEVENT_KEY_SHIFT_RIGHT }, + + { DIK_UP, INPUTEVENT_KEY_CURSOR_UP }, + { DIK_DOWN, INPUTEVENT_KEY_CURSOR_DOWN }, + { DIK_LEFT, INPUTEVENT_KEY_CURSOR_LEFT }, + { DIK_RIGHT, INPUTEVENT_KEY_CURSOR_RIGHT }, + + { DIK_INSERT, INPUTEVENT_KEY_AMIGA_LEFT }, + { DIK_DELETE, INPUTEVENT_KEY_DEL }, + { DIK_HOME, INPUTEVENT_KEY_AMIGA_RIGHT }, + { DIK_NEXT, INPUTEVENT_KEY_HELP }, + + { DIK_LBRACKET, INPUTEVENT_KEY_LEFTBRACKET }, + { DIK_RBRACKET, INPUTEVENT_KEY_RIGHTBRACKET }, + { DIK_SEMICOLON, INPUTEVENT_KEY_SEMICOLON }, + { DIK_APOSTROPHE, INPUTEVENT_KEY_SINGLEQUOTE }, + { DIK_GRAVE, INPUTEVENT_KEY_BACKQUOTE }, + { DIK_BACKSLASH, INPUTEVENT_KEY_BACKSLASH }, + { DIK_COMMA, INPUTEVENT_KEY_COMMA }, + { DIK_PERIOD, INPUTEVENT_KEY_PERIOD }, + { DIK_SLASH, INPUTEVENT_KEY_DIV }, + { DIK_OEM_102, INPUTEVENT_KEY_30 }, + + { DIK_BACK, INPUTEVENT_SPC_STATEREWIND }, + + { DIK_VOLUMEDOWN, INPUTEVENT_SPC_VOLUME_DOWN }, + { DIK_VOLUMEUP, INPUTEVENT_SPC_VOLUME_UP }, + { DIK_MUTE, INPUTEVENT_SPC_VOLUME_MUTE }, + + { -1, 0 } +}; + +extern int ispressed (int key); + +static int endpressed (void) +{ + return ispressed(DIK_END); +} + +static int shiftpressed (void) +{ + return ispressed (DIK_LSHIFT) || ispressed (DIK_RSHIFT); +} + +static int altpressed (void) +{ + return ispressed (DIK_LMENU) || ispressed (DIK_RMENU); +} + +static int ctrlpressed (void) +{ + return ispressed (DIK_LCONTROL) || ispressed (DIK_RCONTROL); +} + +static int capslockstate; + +int getcapslockstate (void) +{ + return capslockstate; +} +void setcapslockstate (int state) +{ + capslockstate = state; +} + +int getcapslock (void) +{ + int newstate; + + BYTE keyState[256]; + GetKeyboardState (keyState); + newstate = keyState[VK_CAPITAL] & 1; + if (newstate != capslockstate) + inputdevice_translatekeycode (0, DIK_CAPITAL, newstate); + capslockstate = newstate; + return capslockstate; +} + +#ifdef CD32 +extern int cd32_enabled; + +static int handlecd32 (int scancode, int state) +{ + int e = 0; + if (!cd32_enabled) + return 0; + switch (scancode) + { + case DIK_NUMPAD7: + e = INPUTEVENT_JOY2_CD32_GREEN; + break; + case DIK_NUMPAD9: + e = INPUTEVENT_JOY2_CD32_YELLOW; + break; + case DIK_NUMPAD1: + e = INPUTEVENT_JOY2_CD32_RED; + break; + case DIK_NUMPAD3: + e = INPUTEVENT_JOY2_CD32_BLUE; + break; + case DIK_DIVIDE: + e = INPUTEVENT_JOY2_CD32_RWD; + break; + case DIK_MULTIPLY: + e = INPUTEVENT_JOY2_CD32_PLAY; + break; + case DIK_SUBTRACT: + e = INPUTEVENT_JOY2_CD32_FFW; + break; + } + if (!e) + return 0; + handle_input_event (e, state, 1, 0); + return 1; +} +#endif + +void clearallkeys (void) +{ + inputdevice_updateconfig (&currprefs); +} + +static int np[] = { DIK_NUMPAD0, 0, DIK_NUMPADPERIOD, 0, DIK_NUMPAD1, 1, DIK_NUMPAD2, 2, + DIK_NUMPAD3, 3, DIK_NUMPAD4, 4, DIK_NUMPAD5, 5, DIK_NUMPAD6, 6, DIK_NUMPAD7, 7, + DIK_NUMPAD8, 8, DIK_NUMPAD9, 9, -1 }; + +void my_kbd_handler (int keyboard, int scancode, int newstate) +{ +// write_log( "keyboard = %d scancode = 0x%02.2x state = %d\n", keyboard, scancode, newstate ); + if (newstate) { + switch (scancode) + { + case DIK_F12: + if (ctrlpressed ()) { + fullscreentoggle(); + } else if (shiftpressed () || endpressed ()) { + disablecapture (); + activate_debugger (); + } else { + gui_display (-1); + } + return; + case DIK_F11: + if (currprefs.win32_ctrl_F11_is_quit) { + if (ctrlpressed()) { + uae_quit(); + return; + } + } + break; + case DIK_F1: + case DIK_F2: + case DIK_F3: + case DIK_F4: + if (endpressed ()) { + if (shiftpressed ()) + disk_eject (scancode - DIK_F1); + else + gui_display (scancode - DIK_F1); + return; + } + break; + case DIK_F5: + if (endpressed ()) { + gui_display (shiftpressed () ? 5 : 4); + return; + } + break; +#if 0 + case DIK_F6: + if (endpressed ()) { + if (shiftpressed ()) { + if(savestate_filename && strlen (savestate_filename)) + savestate_state = STATE_DOSAVE; + } else { + if(savestate_filename && strlen (savestate_filename)) + savestate_state = STATE_DORESTORE; + } + return; + } +#endif + break; + case DIK_NUMPAD0: + case DIK_NUMPAD1: + case DIK_NUMPAD2: + case DIK_NUMPAD3: + case DIK_NUMPAD4: + case DIK_NUMPAD5: + case DIK_NUMPAD6: + case DIK_NUMPAD7: + case DIK_NUMPAD8: + case DIK_NUMPAD9: + case DIK_NUMPADPERIOD: + if (endpressed ()) { + int i = 0, v = -1; + while (np[i] >= 0) { + v = np[i + 1]; + if (np[i] == scancode) + break; + i+=2; + } + if (v >= 0) + savestate_quick (v, shiftpressed() || ctrlpressed ()); + return; + } + break; + case DIK_SYSRQ: + screenshot (endpressed() ? 1 : 0); + break; + case DIK_PAUSE: + if (endpressed ()) + warpmode (-1); + else + pausemode (-1); + break; + case DIK_SCROLL: + toggle_inhibit_frame (IHF_SCROLLLOCK); + return; + case DIK_PRIOR: +#ifdef ACTION_REPLAY + if (action_replay_freeze ()) + return; +#endif + break; + case DIK_NEXT: + break; + case DIK_NUMPADMINUS: + if (endpressed ()) + sound_volume (-1); + break; + case DIK_NUMPADPLUS: + if (endpressed ()) + sound_volume (1); + break; + case DIK_NUMPADSTAR: + if (endpressed ()) + sound_volume (0); + break; + case DIK_NUMPADSLASH: + if (endpressed ()) + savestate_dorewind (1); + break; + } + } + if (endpressed ()) + return; + + if (scancode == DIK_CAPITAL) { + if (!newstate) + return; + capslockstate = capslockstate ? 0 : 1; + newstate = capslockstate; + } + + if (currprefs.input_selected_setting == 0) { +#ifdef CD32 + if (handlecd32 (scancode, newstate)) + return; +#endif + } + inputdevice_translatekeycode (keyboard, scancode, newstate); +} + +void keyboard_settrans (void) +{ + inputdevice_setkeytranslation (keytrans); +} + diff --git a/od-win32/machdep/m68k.h b/od-win32/machdep/m68k.h new file mode 100755 index 00000000..54cfbf55 --- /dev/null +++ b/od-win32/machdep/m68k.h @@ -0,0 +1,184 @@ +#ifndef M68K_H +#define M68K_H + + /* + * UAE - The Un*x Amiga Emulator + * + * MC68000 emulation - machine dependent bits + * + * Copyright 1996 Bernd Schmidt + */ + +struct flag_struct { + unsigned int cznv; + unsigned int x; +}; + +#define FLAGVAL_Z 0x4000 +#define FLAGVAL_N 0x8000 + +#define SET_ZFLG(y) (regflags.cznv = (regflags.cznv & ~0x4000) | (((y) ? 0x4000 : 0))) +#define SET_CFLG(y) (regflags.cznv = (regflags.cznv & ~0x100) | (((y) ? 0x100 : 0))) +#define SET_VFLG(y) (regflags.cznv = (regflags.cznv & ~0x1) | (((y) ? 1 : 0))) +#define SET_NFLG(y) (regflags.cznv = (regflags.cznv & ~0x8000) | (((y) ? 0x8000 : 0))) +#define SET_XFLG(y) (regflags.x = ((y) ? 1 : 0)) + +#define GET_ZFLG ((regflags.cznv >> 14) & 1) +#define GET_CFLG ((regflags.cznv >> 8) & 1) +#define GET_VFLG ((regflags.cznv >> 0) & 1) +#define GET_NFLG ((regflags.cznv >> 15) & 1) +#define GET_XFLG (regflags.x & 1) + +#define CLEAR_CZNV (regflags.cznv = 0) +#define GET_CZNV (regflags.cznv) +#define IOR_CZNV(X) (regflags.cznv |= (X)) +#define SET_CZNV(X) (regflags.cznv = (X)) + +#define COPY_CARRY (regflags.x = (regflags.cznv) >> 8) + +#ifdef X86_ASSEMBLY +extern struct flag_struct regflags __asm__ ("regflags"); +#else +extern struct flag_struct regflags; +#endif + +static __inline__ int cctrue(int cc) +{ + uae_u32 cznv = regflags.cznv; + switch(cc){ + case 0: return 1; /* T */ + case 1: return 0; /* F */ + case 2: return (cznv & 0x4100) == 0; /* !GET_CFLG && !GET_ZFLG; HI */ + case 3: return (cznv & 0x4100) != 0; /* GET_CFLG || GET_ZFLG; LS */ + case 4: return (cznv & 0x100) == 0; /* !GET_CFLG; CC */ + case 5: return (cznv & 0x100) != 0; /* GET_CFLG; CS */ + case 6: return (cznv & 0x4000) == 0; /* !GET_ZFLG; NE */ + case 7: return (cznv & 0x4000) != 0; /* GET_ZFLG; EQ */ + case 8: return (cznv & 0x01) == 0; /* !GET_VFLG; VC */ + case 9: return (cznv & 0x01) != 0; /* GET_VFLG; VS */ + case 10:return (cznv & 0x8000) == 0; /* !GET_NFLG; PL */ + case 11:return (cznv & 0x8000) != 0; /* GET_NFLG; MI */ + case 12:return (((cznv << 15) ^ cznv) & 0x8000) == 0; /* GET_NFLG == GET_VFLG; GE */ + case 13:return (((cznv << 15) ^ cznv) & 0x8000) != 0;/* GET_NFLG != GET_VFLG; LT */ + case 14: + cznv &= 0xc001; + return (((cznv << 15) ^ cznv) & 0xc000) == 0; /* !GET_ZFLG && (GET_NFLG == GET_VFLG); GT */ + case 15: + cznv &= 0xc001; + return (((cznv << 15) ^ cznv) & 0xc000) != 0; /* GET_ZFLG || (GET_NFLG != GET_VFLG); LE */ + } + abort(); + return 0; +} + +#ifdef X86_ASSEMBLY + +#define optflag_testl(v) \ + __asm__ __volatile__ ("andl %0,%0\n\t" \ + "lahf\n\t" \ + "seto %%al\n\t" \ + "movb %%al,regflags\n\t" \ + "movb %%ah,regflags+1\n\t" \ + :: "r" (v) : "%eax","cc","memory") +#define optflag_testw(v) \ + __asm__ __volatile__ ("andw %w0,%w0\n\t" \ + "lahf\n\t" \ + "seto %%al\n\t" \ + "movb %%al,regflags\n\t" \ + "movb %%ah,regflags+1\n\t" \ + :: "r" (v) : "%eax","cc","memory") + +#define optflag_testb(v) \ + __asm__ __volatile__ ("andb %b0,%b0\n\t" \ + "lahf\n\t" \ + "seto %%al\n\t" \ + "movb %%al,regflags\n\t" \ + "movb %%ah,regflags+1\n\t" \ + :: "q" (v) : "%eax","cc","memory") + +#define optflag_addl(v, s, d) do { \ + __asm__ __volatile__ ("addl %k1,%k0\n\t" \ + "lahf\n\t" \ + "seto %%al\n\t" \ + "movb %%al,regflags\n\t" \ + "movb %%ah,regflags+1\n\t" \ + :"=r" (v) : "rmi" (s), "0" (d) : "%eax","cc","memory"); \ + COPY_CARRY; \ + } while (0) +#define optflag_addw(v, s, d) do { \ + __asm__ __volatile__ ("addw %w1,%w0\n\t" \ + "lahf\n\t" \ + "seto %%al\n\t" \ + "movb %%al,regflags\n\t" \ + "movb %%ah,regflags+1\n\t" \ + : "=r" (v) : "rmi" (s), "0" (d) : "%eax","cc","memory"); \ + COPY_CARRY; \ + } while (0) + +#define optflag_addb(v, s, d) do { \ + __asm__ __volatile__ ("addb %b1,%b0\n\t" \ + "lahf\n\t" \ + "seto %%al\n\t" \ + "movb %%al,regflags\n\t" \ + "movb %%ah,regflags+1\n\t" \ + :"=q" (v) : "qmi" (s), "0" (d) : "%eax","cc","memory"); \ + COPY_CARRY; \ + } while (0) + +#define optflag_subl(v, s, d) do { \ + __asm__ __volatile__ ("subl %k1,%k0\n\t" \ + "lahf\n\t" \ + "seto %%al\n\t" \ + "movb %%al,regflags\n\t" \ + "movb %%ah,regflags+1\n\t" \ + : "=r" (v) : "rmi" (s), "0" (d) : "%eax","cc","memory"); \ + COPY_CARRY; \ + } while (0) + +#define optflag_subw(v, s, d) do { \ + __asm__ __volatile__ ("subw %w1,%w0\n\t" \ + "lahf\n\t" \ + "seto %%al\n\t" \ + "movb %%al,regflags\n\t" \ + "movb %%ah,regflags+1\n\t" \ + : "=r" (v) : "rmi" (s), "0" (d) : "%eax","cc","memory"); \ + COPY_CARRY; \ + } while (0) + +#define optflag_subb(v, s, d) do { \ + __asm__ __volatile__ ("subb %b1,%b0\n\t" \ + "lahf\n\t" \ + "seto %%al\n\t" \ + "movb %%al,regflags\n\t" \ + "movb %%ah,regflags+1\n\t" \ + : "=q" (v) : "qmi" (s), "0" (d) : "%eax","cc","memory"); \ + COPY_CARRY; \ + } while (0) + +#define optflag_cmpl(s, d) \ + __asm__ __volatile__ ("cmpl %k0,%k1\n\t" \ + "lahf\n\t" \ + "seto %%al\n\t" \ + "movb %%al,regflags\n\t" \ + "movb %%ah,regflags+1\n\t" \ + :: "rmi" (s), "r" (d) : "%eax","cc","memory") + +#define optflag_cmpw(s, d) \ + __asm__ __volatile__ ("cmpw %w0,%w1\n\t" \ + "lahf\n\t" \ + "seto %%al\n\t" \ + "movb %%al,regflags\n\t" \ + "movb %%ah,regflags+1\n\t" \ + :: "rmi" (s), "r" (d) : "%eax","cc","memory"); + +#define optflag_cmpb(s, d) \ + __asm__ __volatile__ ("cmpb %b0,%b1\n\t" \ + "lahf\n\t" \ + "seto %%al\n\t" \ + "movb %%al,regflags\n\t" \ + "movb %%ah,regflags+1\n\t" \ + :: "qmi" (s), "q" (d) : "%eax","cc","memory") + +#endif + +#endif \ No newline at end of file diff --git a/od-win32/machdep/maccess.h b/od-win32/machdep/maccess.h new file mode 100755 index 00000000..13b29421 --- /dev/null +++ b/od-win32/machdep/maccess.h @@ -0,0 +1,234 @@ +#ifndef __MACCESS_H__ +#define __MACCESS_H__ + /* + * UAE - The Un*x Amiga Emulator + * + * Memory access functions + * + * Copyright 1996 Bernd Schmidt + */ + +#if defined( __GNUC__ ) && defined( X86_ASSEMBLY ) + +#define X86_PPRO_OPT + +static __inline__ uae_u32 do_get_mem_long (uae_u32 *a) +{ + uae_u32 retval; + + __asm__ ("bswap %0" : "=r" (retval) : "0" (*a) : "cc"); + return retval; +} + +static __inline__ uae_u32 do_get_mem_word (uae_u16 *a) +{ + uae_u32 retval; + +#ifdef X86_PPRO_OPT + __asm__ ("movzwl %w1,%k0\n\tshll $16,%k0\n\tbswap %k0\n" : "=&r" (retval) : "m" (*a) : "cc"); +#else + __asm__ ("xorl %k0,%k0\n\tmovw %w1,%w0\n\trolw $8,%w0" : "=&r" (retval) : "m" (*a) : "cc"); +#endif + return retval; +} + +#define do_get_mem_byte(a) ((uae_u32)*(uae_u8 *)(a)) + +static __inline__ void do_put_mem_long (uae_u32 *a, uae_u32 v) +{ + __asm__ ("bswap %0" : "=r" (v) : "0" (v) : "cc"); + *a = v; +} + +static __inline__ void do_put_mem_word (uae_u16 *a, uae_u32 v) +{ +#ifdef X86_PPRO_OPT + __asm__ ("bswap %0" : "=&r" (v) : "0" (v << 16) : "cc"); +#else + __asm__ ("rolw $8,%w0" : "=r" (v) : "0" (v) : "cc"); +#endif + *a = v; +} + +#define do_put_mem_byte(a,v) (*(uae_u8 *)(a) = (v)) + +#if 0 +static __inline__ uae_u32 call_mem_get_func(mem_get_func func, uae_cptr addr) +{ + uae_u32 result; + __asm__("call %1" + : "=a" (result) : "r" (func), "a" (addr) : "cc", "edx", "ecx"); + return result; +} + +static __inline__ void call_mem_put_func(mem_put_func func, uae_cptr addr, uae_u32 v) +{ + __asm__("call %2" + : : "a" (addr), "d" (v), "r" (func) : "cc", "eax", "edx", "ecx", "memory"); +} +#else + +#define call_mem_get_func(func,addr) ((*func)(addr)) +#define call_mem_put_func(func,addr,v) ((*func)(addr,v)) + +#endif + +#undef NO_INLINE_MEMORY_ACCESS +#undef MD_HAVE_MEM_1_FUNCS + +#ifdef MD_HAVE_MEM_1_FUNCS +static __inline__ uae_u32 longget_1 (uae_cptr addr) +{ + uae_u32 result; + + __asm__ ("andl $0x00FFFFFF,%1\n" + "\tcmpb $0,(%1,%3)\n" + "\tleal 1f,%%ecx\n" + "\tje longget_stub\n" + "\taddl address_space,%1\n" + "\tmovl (%1),%0\n" + "\tbswap %0\n" + "\t1:" + : "=c" (result), "=d" (addr) : "1" (addr), "r" (good_address_map) : "cc"); + return result; +} +static __inline__ uae_u32 wordget_1 (uae_cptr addr) +{ + uae_u32 result; + + __asm__ ("andl $0x00FFFFFF,%1\n" + "\tcmpb $0,(%1,%3)\n" + "\tleal 1f,%%ecx\n" + "\tje wordget_stub\n" + "\taddl address_space,%1\n" + "\tmovzwl (%1),%0\n" + "\trolw $8,%w0\n" + "\t1:" + : "=c" (result), "=d" (addr) : "1" (addr), "r" (good_address_map) : "cc"); + return result; +} +static __inline__ uae_u32 byteget_1 (uae_cptr addr) +{ + uae_u32 result; + + __asm__ ("andl $0x00FFFFFF,%1\n" + "\tcmpb $0,(%1,%3)\n" + "\tleal 1f,%%ecx\n" + "\tje byteget_stub\n" + "\taddl address_space,%1\n" + "\tmovzbl (%1),%0\n" + "\t1:" + : "=c" (result), "=d" (addr) : "1" (addr), "r" (good_address_map) : "cc"); + return result; +} +static __inline__ void longput_1 (uae_cptr addr, uae_u32 l) +{ + __asm__ __volatile__("andl $0x00FFFFFF,%0\n" + "\tcmpb $0,(%0,%3)\n" + "\tleal 1f,%%ecx\n" + "\tje longput_stub\n" + "\taddl address_space,%0\n" + "\tbswap %1\n" + "\tmovl %1,(%0)\n" + "\t1:" + : "=d" (addr), "=b" (l) : "0" (addr), "r" (good_address_map), "1" (l) : "cc", "memory", "ecx"); +} +static __inline__ void wordput_1 (uae_cptr addr, uae_u32 w) +{ + __asm__ __volatile__("andl $0x00FFFFFF,%0\n" + "\tcmpb $0,(%0,%3)\n" + "\tleal 1f,%%ecx\n" + "\tje wordput_stub\n" + "\taddl address_space,%0\n" + "\trolw $8,%1\n" + "\tmovw %w1,(%0)\n" + "\t1:" + : "=d" (addr), "=b" (w) : "0" (addr), "r" (good_address_map), "1" (w) : "cc", "memory", "ecx"); +} +static __inline__ void byteput_1 (uae_cptr addr, uae_u32 b) +{ + __asm__ __volatile__("andl $0x00FFFFFF,%0\n" + "\tcmpb $0,(%0,%3)\n" + "\tleal 1f,%%ecx\n" + "\tje byteput_stub\n" + "\taddl address_space,%0\n" + "\tmovb %b1,(%0)\n" + "\t1:" + : "=d" (addr), "=b" (b) : "0" (addr), "r" (good_address_map), "1" (b) : "cc", "memory", "ecx"); +} + +#endif + +#define ALIGN_POINTER_TO32(p) ((~(unsigned long)(p)) & 3) + +#else + +static __inline__ uae_u32 do_get_mem_long(uae_u32 *a) +{ +#ifndef _MSC_VER + uae_u8 *b = (uae_u8 *)a; + return (*b << 24) | (*(b+1) << 16) | (*(b+2) << 8) | (*(b+3)); +#else + uae_u32 retval; + __asm + { + mov eax, a + mov ebx, [eax] + bswap ebx + mov retval, ebx + } + return retval; +#endif +} + +static __inline__ uae_u16 do_get_mem_word(uae_u16 *a) +{ + uae_u8 *b = (uae_u8 *)a; + + return (*b << 8) | (*(b+1)); +} + +#define do_get_mem_byte(a) ((uae_u32)*(uae_u8 *)(a)) + +static __inline__ void do_put_mem_long(uae_u32 *a, uae_u32 v) +{ +#ifndef _MSC_VER + uae_u8 *b = (uae_u8 *)a; + + *b = v >> 24; + *(b+1) = v >> 16; + *(b+2) = v >> 8; + *(b+3) = v; +#else + __asm + { + mov eax, a + mov ebx, v + bswap ebx + mov [eax], ebx + } +#endif +} + +static __inline__ void do_put_mem_word(uae_u16 *a, uae_u16 v) +{ + uae_u8 *b = (uae_u8 *)a; + + *b = v >> 8; + *(b+1) = (uae_u8)v; +} + +static __inline__ void do_put_mem_byte(uae_u8 *a, uae_u8 v) +{ + *a = v; +} + +#define call_mem_get_func(func, addr) ((*func)(addr)) +#define call_mem_put_func(func, addr, v) ((*func)(addr, v)) + +#undef NO_INLINE_MEMORY_ACCESS +#undef MD_HAVE_MEM_1_FUNCS + +#endif + +#endif \ No newline at end of file diff --git a/od-win32/machdep/rpt.h b/od-win32/machdep/rpt.h new file mode 100755 index 00000000..c371fd15 --- /dev/null +++ b/od-win32/machdep/rpt.h @@ -0,0 +1,82 @@ +/* + * UAE - The Un*x Amiga Emulator + * + * Definitions for accessing cycle counters on a given machine, if possible. + * + * Copyright 1997, 1998 Bernd Schmidt + * Copyright 1999 Brian King - Win32 specific + */ +#ifndef _RPT_H_ +#define _RPT_H_ + +#ifdef HIBERNATE_TEST +extern int rpt_skip_trigger; +#endif + +typedef unsigned long frame_time_t; + +/* For CPUs that lack the rdtsc instruction or systems that change CPU frequency on the fly (most laptops) */ +extern frame_time_t read_processor_time_qpc( void ); +extern int useqpc; + +#if defined( __GNUC__ ) +static inline frame_time_t read_processor_time (void) +{ + frame_time_t foo; + int dummy; + + if( useqpc ) + return read_processor_time_cyrix(); + + /* Don't assume the assembler knows rdtsc */ + __asm__ __volatile__ (".byte 0x0f,0x31" : "=a" (foo), "=d" (dummy) :); + return foo; +} +#elif defined( __WATCOMC__ ) +extern frame_time_t read_processor_time (void); +#pragma aux read_processor_time = \ + "rdtsc" \ + modify [eax edx] value [eax]; +#elif defined( _MSC_VER ) && !defined( _WIN32_WCE ) + +STATIC_INLINE frame_time_t read_processor_time_qpc (void) +{ + LARGE_INTEGER counter; + QueryPerformanceCounter( &counter ); + if (useqpc > 0) + return (frame_time_t)(counter.LowPart); + return (frame_time_t)(counter.QuadPart >> 6); +} + +STATIC_INLINE frame_time_t read_processor_time (void) +{ + frame_time_t foo, bar; + + if (useqpc) /* No RDTSC or RDTSC is not stable */ + return read_processor_time_qpc(); + + __asm + { + rdtsc + mov foo, eax + mov bar, edx + } + /* very high speed CPU's RDTSC might overflow without this.. */ + foo >>= 6; + foo |= bar << 26; +#ifdef HIBERNATE_TEST + if (rpt_skip_trigger) { + foo += rpt_skip_trigger; + rpt_skip_trigger = 0; + } +#endif + return foo; +} +#else +static __inline__ frame_time_t read_processor_time (void) +{ + return 0; +} +#endif + +#endif diff --git a/od-win32/machdep/support.c b/od-win32/machdep/support.c new file mode 100755 index 00000000..0e13f24f --- /dev/null +++ b/od-win32/machdep/support.c @@ -0,0 +1,294 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Miscellaneous machine dependent support functions and definitions + * + * Copyright 1996 Bernd Schmidt + */ + + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "machdep/m68k.h" +#include "events.h" + +#ifdef X86_ASSEMBLY + +#ifndef USE_UNDERSCORE +#define LARGE_ALIGNMENT ".align 16\n" +#else +#define LARGE_ALIGNMENT ".align 4,0x90\n" +#endif + +struct flag_struct regflags; + +/* + * Careful: No unique labels. Unfortunately, not each installation of GCC + * comes with GAS. Bletch. + */ + +int fast_memcmp(const void *foo, const void *bar, int len) +{ + int differs, baz; + __asm__ __volatile__ ("subl $4, %2\n" + "jc LLA2\n" + "LLA1:\n" + "movl (%0),%%ebx\n" + "cmpl (%1),%%ebx\n" + "jne LLA5\n" + "addl $4, %0\n" + "addl $4, %1\n" + "subl $4, %2\n" + "jnc LLA1\n" + "LLA2:\n" + "addl $4, %2\n" + "jz LLA4\n" + "LLA3:\n" + "movb (%0),%%bl\n" + "cmpb (%1),%%bl\n" + "jne LLA5\n" + "incl %0\n" + "incl %1\n" + "decl %2\n" + "jnz LLA3\n" + "LLA4:\n" + "movl $0, %3\n" + "jmp LLA6\n" + "LLA5:\n" + "movl $1, %3\n" + "LLA6:\n" + : "=&r" (foo), "=&r" (bar), "=&rm" (len), "=rm" (differs), + "=&b" (baz) + : "0" (foo), "1" (bar), "2" (len), "3" (baz) : "cc"); + return differs; +} + +int memcmpy(void *foo, const void *bar, int len) +{ + int differs = 0, baz = 0, uupzuq = 0; + + __asm__ __volatile__ ("subl %1, %2\n" + "subl $16, %3\n" + "jc LLB7\n" + LARGE_ALIGNMENT + "LLB8:\n" + "movl (%2,%1),%%ebx\n" + "movl (%1),%%ecx\n" + "cmpl %%ebx, %%ecx\n" + "jne LLC1\n" + + "movl 4(%2,%1),%%ebx\n" + "movl 4(%1),%%ecx\n" + "cmpl %%ebx, %%ecx\n" + "jne LLC2\n" + + "movl 8(%2,%1),%%ebx\n" + "movl 8(%1),%%ecx\n" + "cmpl %%ebx, %%ecx\n" + "jne LLC3\n" + + "movl 12(%2,%1),%%ebx\n" + "movl 12(%1),%%ecx\n" + "cmpl %%ebx, %%ecx\n" + "jne LLC4\n" + + "addl $16, %1\n" + "subl $16, %3\n" + "jnc LLB8\n" + + "LLB7:\n" + "addl $16, %3\n" + "subl $4, %3\n" + "jc LLB2\n" + + "LLB1:\n" + "movl (%2,%1),%%ebx\n" + "movl (%1),%%ecx\n" + "cmpl %%ebx, %%ecx\n" + "jne LLC5\n" + "addl $4, %1\n" + "subl $4, %3\n" + "jnc LLB1\n" + + "LLB2:\n" + "addl $4, %3\n" + "jz LLB9\n" + + "LLB3:\n" + "movb (%2,%1),%%bl\n" + "movb (%1),%%cl\n" + "cmpb %%bl,%%cl\n" + "jne LLC6\n" + "incl %1\n" + "decl %3\n" + "jnz LLB3\n" + + "jmp LLB9\n" + + LARGE_ALIGNMENT + /* Once we find a difference, we switch to plain memcpy() */ + "LLC01:\n" + "movl (%2,%1),%%ebx\n" + "LLC1:\n" + "movl %%ebx, (%1)\n" + + "movl 4(%2,%1),%%ebx\n" + "LLC2:\n" + "movl %%ebx, 4(%1)\n" + + "movl 8(%2,%1),%%ebx\n" + "LLC3:\n" + "movl %%ebx, 8(%1)\n" + + "movl 12(%2,%1),%%ebx\n" + "LLC4:\n" + "movl %%ebx, 12(%1)\n" + + "addl $16, %1\n" +#if 0 + "movl $1,%0\n" + + "addl %1,%2\n" + "movl %3,%%ecx\n" + "shrl $2,%%ecx\n" + "je LLC02a\n" + "rep\n" + "movsl\n" + "andl $3,%3\n" + "je LLB9\n" + "LLC02a:\n" + "movb (%2),%%bl\n" + + "movb %%bl,(%1)\n" + "incl %1\n" + "decl %3\n" + "jnz LLC02a\n" + "jmp LLB9\n" +#else +#if 0 + "movl $1,%0\n" + "jnc LLB8\n" +#else + "subl $16, %3\n" + "jnc LLC01\n" +#endif + + "addl $16, %3\n" + "subl $4, %3\n" + "jc LLC03\n" +#endif + + "LLC02:\n" + "movl (%2,%1),%%ebx\n" + "LLC5:\n" + "movl %%ebx, (%1)\n" + "addl $4, %1\n" + "subl $4, %3\n" + "jnc LLC02\n" + + "LLC03:\n" + "addl $4, %3\n" + "jz LLC05\n" + + "LLC04:\n" + "movb (%2,%1),%%bl\n" + "LLC6:\n" + "movb %%bl,(%1)\n" + "incl %1\n" + "decl %3\n" + "jnz LLC04\n" + + "LLC05:\n" + "movl $1,%0\n" + "LLB9:" + : "=m" (differs) + : "D" (foo), "S" (bar), "r" (len), "b" (baz), "c" (uupzuq), "0" (differs) : "cc", "memory"); + /* Now tell the compiler that foo, bar and len have been modified + * If someone finds a way to express all this cleaner in constraints that + * GCC 2.7.2 understands, please FIXME */ + __asm__ __volatile__ ("" : "=rm" (foo), "=rm" (bar), "=rm" (len) : : "ebx", "ecx", "edx", "eax", "esi", "memory"); + + return differs; +} + +#else +struct flag_struct regflags; + +int fast_memcmp(const void *foo, const void *bar, int len) +{ + return memcmp(foo, bar, len); +} + +int memcmpy(void *foo, const void *bar, int len) +{ + int differs = memcmp(foo, bar, len); + memcpy(foo, bar, len); + return differs; +} + +#endif + +/* All the Win32 configurations handle this in od-win32/win32.c */ +#ifndef _WIN32 + +#include + +static volatile frame_time_t last_time, best_time; +static volatile int loops_to_go; + +#ifdef __cplusplus +static RETSIGTYPE alarmhandler(...) +#else +static RETSIGTYPE alarmhandler(int foo) +#endif +{ + frame_time_t bar; + bar = read_processor_time (); + if (bar - last_time < best_time) + best_time = bar - last_time; + if (--loops_to_go > 0) { + signal (SIGALRM, alarmhandler); + last_time = read_processor_time(); + alarm (1); + } +} + +#ifdef __cplusplus +static RETSIGTYPE illhandler(...) +#else +static RETSIGTYPE illhandler(int foo) +#endif +{ + rpt_available = 0; +} + +void machdep_init (void) +{ + rpt_available = 1; + signal (SIGILL, illhandler); + read_processor_time (); + signal (SIGILL, SIG_DFL); + if (! rpt_available) { + fprintf (stderr, "Your processor does not support the RDTSC instruction.\n"); + return; + } + fprintf (stderr, "Calibrating delay loop.. "); + fflush (stderr); + best_time = (frame_time_t)-1; + loops_to_go = 5; + signal (SIGALRM, alarmhandler); + /* We want exact values... */ + sync (); sync (); sync (); + last_time = read_processor_time(); + alarm (1); + while (loops_to_go != 0) + usleep (1000000); + fprintf (stderr, "ok - %.2f BogoMIPS\n", + ((double)best_time / 1000000), best_time); + vsynctime = best_time / 50; +} + +#endif diff --git a/od-win32/makeexe.bat b/od-win32/makeexe.bat new file mode 100755 index 00000000..875fef64 --- /dev/null +++ b/od-win32/makeexe.bat @@ -0,0 +1,18 @@ +del *.zip +copy d:\amiga\winuae.exe d:\projects\winuae\distribution +copy resourcedll\release\resourcedll.dll d:\amiga\WinUAE_default.dll +makensis.exe winuae +cd d:\projects\winuae\distribution +copy docs\windows\translation.txt d:\amiga +zip -9 -r d:\projects\winuae\src\od-win32\winuae.zip * +cd d:\projects\winuae\src\od-win32 +copy installwinuae.exe d:\amiga\InstallWinUAE%1.exe +copy winuae.zip d:\amiga\WinUAE%1.zip +cd d:\amiga +zip -9 WinUAE%1_translation WinUAE_default.dll translation.txt +del WinUAE_default.dll +del translation.txt +zip -9 WinUAEMini%1 winuae_mini.exe +cd d:\projects\winuae\src\od-win32 +del *.zip + diff --git a/od-win32/md-fpp.h b/od-win32/md-fpp.h new file mode 100755 index 00000000..82cd75da --- /dev/null +++ b/od-win32/md-fpp.h @@ -0,0 +1,141 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * MC68881 emulation + * + * Conversion routines for hosts with unknown floating point format. + * + * Copyright 1996 Herman ten Brugge + */ + +#ifndef HAVE_to_single +STATIC_INLINE double to_single (uae_u32 value) +{ + double frac; + + if ((value & 0x7fffffff) == 0) + return (0.0); + frac = (double) ((value & 0x7fffff) | 0x800000) / 8388608.0; + if (value & 0x80000000) + frac = -frac; + return (ldexp (frac, ((value >> 23) & 0xff) - 127)); +} +#endif + +#ifndef HAVE_from_single +STATIC_INLINE uae_u32 from_single (double src) +{ + int expon; + uae_u32 tmp; + double frac; + + if (src == 0.0) + return 0; + if (src < 0) { + tmp = 0x80000000; + src = -src; + } else { + tmp = 0; + } + frac = frexp (src, &expon); + frac += 0.5 / 16777216.0; + if (frac >= 1.0) { + frac /= 2.0; + expon++; + } + if (expon <= -127) return 0; + if (expon >= 127) expon = 127; + return (tmp | (((expon + 127 - 1) & 0xff) << 23) | + (((int) (frac * 16777216.0)) & 0x7fffff)); +} +#endif + +#ifndef HAVE_to_exten +STATIC_INLINE double to_exten(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) +{ + double frac; + + if ((wrd1 & 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0) + return 0.0; + frac = (double) wrd2 / 2147483648.0 + + (double) wrd3 / 9223372036854775808.0; + if (wrd1 & 0x80000000) + frac = -frac; + return ldexp (frac, ((wrd1 >> 16) & 0x7fff) - 16383); +} +#endif + +#ifndef HAVE_from_exten +STATIC_INLINE void from_exten(double src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3) +{ + int expon; + double frac; + + if (src == 0.0) { + *wrd1 = 0; + *wrd2 = 0; + *wrd3 = 0; + return; + } + if (src < 0) { + *wrd1 = 0x80000000; + src = -src; + } else { + *wrd1 = 0; + } + frac = frexp (src, &expon); + frac += 0.5 / 18446744073709551616.0; + if (frac >= 1.0) { + frac /= 2.0; + expon++; + } + *wrd1 |= (((expon + 16383 - 1) & 0x7fff) << 16); + *wrd2 = (uae_u32) (frac * 4294967296.0); + *wrd3 = (uae_u32) (frac * 18446744073709551616.0 - *wrd2 * 4294967296.0); +} +#endif + +#ifndef HAVE_to_double +STATIC_INLINE double to_double(uae_u32 wrd1, uae_u32 wrd2) +{ + double frac; + + if ((wrd1 & 0x7fffffff) == 0 && wrd2 == 0) + return 0.0; + frac = (double) ((wrd1 & 0xfffff) | 0x100000) / 1048576.0 + + (double) wrd2 / 4503599627370496.0; + if (wrd1 & 0x80000000) + frac = -frac; + return ldexp (frac, ((wrd1 >> 20) & 0x7ff) - 1023); +} +#endif + +#ifndef HAVE_from_double +STATIC_INLINE void from_double(double src, uae_u32 * wrd1, uae_u32 * wrd2) +{ + int expon; + int tmp; + double frac; + + if (src == 0.0) { + *wrd1 = 0; + *wrd2 = 0; + return; + } + if (src < 0) { + *wrd1 = 0x80000000; + src = -src; + } else { + *wrd1 = 0; + } + frac = frexp (src, &expon); + frac += 0.5 / 9007199254740992.0; + if (frac >= 1.0) { + frac /= 2.0; + expon++; + } + tmp = (uae_u32) (frac * 2097152.0); + *wrd1 |= (((expon + 1023 - 1) & 0x7ff) << 20) | (tmp & 0xfffff); + *wrd2 = (uae_u32) (frac * 9007199254740992.0 - tmp * 4294967296.0); +} +#endif diff --git a/od-win32/midi.c b/od-win32/midi.c new file mode 100755 index 00000000..e01ab2a0 --- /dev/null +++ b/od-win32/midi.c @@ -0,0 +1,833 @@ +/* + * MODULE: midi.c + * + * DESCRIPTION: MIDI-handling code for MIDI-I/O. Parses the MIDI-output stream and + * sends system-exclusive MIDI-messages out using midiOutLongMsg(), while using + * midiOutShortMsg() for normal MIDI-messages. MIDI-input is passed byte-for-byte + * up to the Amiga's serial-port. + * + * AUTHOR: Brian_King@CodePoet.com + * + * COPYRIGHT: Copyright 1999, 2000 under GNU Public License + * + * HISTORY: + * 1999.09.05 1.0 Brian King - creation + * 2000.01.30 1.1 Brian King - addition of midi-input + * 2002.05.xx 1.2 Bernd Roesch - sysex in/MTC/Song Position pointer add + */ + +#include "config.h" +#include "sysconfig.h" +#include +#include +#include +#ifdef _MSC_VER +#include +#include +#else +#include "winstuff.h" +#endif +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "/v.h" +#include +#include +#include + +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;ilength;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; + } + } + } +} + + +void stealint(); +struct Interrupt *oldserin = 0; + +static void releaseint() + +{ + custom.intena = INTF_RBF; + Disable(); + SetIntVector(INTB_RBF,oldserin); + Enable(); + if (oldserin) custom.intena = INTF_SETCLR | INTF_RBF; + functions->releasemidi = 0; + functions->stealmidi = stealint; +} + +void removetoolcode() + +{ + releaseint(); + DeleteTask(eventtask); + functions->stealmidi = 0; +} + +void stealint() + +{ + midiintin.is_Node.ln_Name = "Midi receiver"; + midiintin.is_Node.ln_Pri = 20; + midiintin.is_Node.ln_Type = NT_INTERRUPT; + midiintin.is_Code = midiincode; + Disable(); + oldserin = (struct Interrupt *) SetIntVector(INTB_RBF,&midiintin); + Enable(); + custom.serper = 114; + custom.intena = INTF_SETCLR | INTF_RBF; + functions->releasemidi = releaseint; + functions->stealmidi = 0; +} + +struct ToolMaster *inittoolmaster() + +{ + midiintin.is_Node.ln_Name = "Midi receiver"; + midiintin.is_Node.ln_Pri = 20; + midiintin.is_Node.ln_Type = NT_INTERRUPT; + midiintin.is_Code = midiincode; + eventtask = CreateTask("midi in",40,eventcode,4000); + if (functions->releasemidi) { + (*functions->releasemidi)(); + } + functions->releasemidi = releaseint; + stealint(); + memset((char *)&master,0,sizeof(struct ToolMaster)); + master.toolid = ID_MDIN; + master.image = &MidiInimage; + strcpy(master.name,"MIDI In"); + master.edittool = edittoolcode; + master.processevent = processeventcode; + master.createtool = createtoolcode; + master.deletetool = deletetoolcode; + master.tooltype = TOOL_INPUT | TOOL_MIDI; + master.toolsize = sizeof(struct MIDITool); + master.removetool = removetoolcode; + setmax(); + return(&master); +} diff --git a/od-win32/mman.c b/od-win32/mman.c new file mode 100755 index 00000000..a05eb40c --- /dev/null +++ b/od-win32/mman.c @@ -0,0 +1,320 @@ +// Implement mprotect() for Win32 +// Copyright (C) 2000, Brian King +// GNU Public License + +#include + +#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 +#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 +#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 +#include + +typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval); +typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void); + +/* not defined in MSVC's opengl.h */ +#ifndef GL_UNSIGNED_SHORT_5_5_5_1_EXT +#define GL_UNSIGNED_SHORT_5_5_5_1_EXT 0x8034 +#endif +#ifndef GL_UNSIGNED_SHORT_4_4_4_4_EXT +#define GL_UNSIGNED_SHORT_4_4_4_4_EXT 0x8033 +#endif + +static GLint max_texture_size; +static GLint tex[4]; +static GLint scanlinetex; +static int total_textures; +static int required_texture_size; +static int required_sl_texture_size; +static GLint ti2d_internalformat, ti2d_format, ti2d_type; +static GLint sl_ti2d_internalformat, sl_ti2d_format, sl_ti2d_type; +static int w_width, w_height, t_width, t_height; +static int packed_pixels; +static int doublevsync; +static int ogl_enabled; + +static HDC openglhdc; +static HGLRC hrc; +static HWND hwnd; +static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT; +static PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT; + +static PIXELFORMATDESCRIPTOR pfd; + +static void testerror (char *s) +{ + for (;;) { + GLint err = glGetError(); + if (err == 0) + return; + write_log ("OpenGL error %d (%s)\n", err, s); + } +} + +static int exact_log2 (int v) +{ + int l = 0; + while ((v >>= 1) != 0) + l++; + return l; +} + +const char *OGL_init (HWND ahwnd, int w_w, int w_h, int t_w, int t_h, int depth) +{ + int PixelFormat; + const char *ext1; + static char errmsg[100] = { 0 }; + static int init; + + ogl_enabled = 0; + if (currprefs.gfx_filter != UAE_FILTER_OPENGL) { + strcpy (errmsg, "OPENGL: not enabled"); + return errmsg; + } + + w_width = w_w; + w_height = w_h; + t_width = t_w; + t_height = t_h; + + memset (&pfd, 0, sizeof (pfd)); + pfd.nSize = sizeof (PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.cColorBits = depth; + pfd.cDepthBits = 0; + pfd.iLayerType = PFD_MAIN_PLANE; + + hwnd = ahwnd; + openglhdc = GetDC (hwnd); + total_textures = 2; + + if (currprefs.gfx_afullscreen && WIN32GFX_GetDepth (TRUE) < 15) { + strcpy (errmsg, "OPENGL: display depth must be at least 15 bit"); + return errmsg; + } + + if (!(PixelFormat = ChoosePixelFormat (openglhdc, &pfd))) { + strcpy (errmsg, "OPENGL: can't find suitable pixelformat"); + return errmsg; + } + + if (!SetPixelFormat (openglhdc, PixelFormat, &pfd)) { + strcpy (errmsg, "OPENGL: can't set pixelformat"); + return errmsg; + } + + if (!(hrc = wglCreateContext (openglhdc))) { + strcpy (errmsg, "OPENGL: can't create gl rendering context"); + return errmsg; + } + + if (!wglMakeCurrent (openglhdc, hrc)) { + strcpy (errmsg, "OPENGL: can't activate gl rendering context"); + return errmsg; + } + + glGetIntegerv (GL_MAX_TEXTURE_SIZE, &max_texture_size); + required_texture_size = 2 << exact_log2 (t_width > t_height ? t_width : t_height); + if (max_texture_size < t_width || max_texture_size < t_height) { + sprintf (errmsg, "OPENGL: %d * %d or bigger texture support required\nYour card's maximum texture size is only %d * %d", + required_texture_size, required_texture_size, max_texture_size, max_texture_size); + return errmsg; + } + required_sl_texture_size = 2 << exact_log2 (w_width > w_height ? w_width : w_height); + if (currprefs.gfx_filter_scanlines > 0 && (max_texture_size < w_width || max_texture_size < w_height)) { + gui_message ("OPENGL: %d * %d or bigger texture support required for scanlines (max is only %d * %d)\n" + "Scanlines disabled.", + required_sl_texture_size, required_sl_texture_size, max_texture_size, max_texture_size); + changed_prefs.gfx_filter_scanlines = currprefs.gfx_filter_scanlines = 0; + } + + ext1 = glGetString (GL_EXTENSIONS); + if (!init) + write_log("OpenGL extensions: %s\n", ext1); + if (strstr (ext1, "EXT_packed_pixels")) + packed_pixels = 1; + if (strstr (ext1, "WGL_EXT_swap_control")) { + wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"); + wglGetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC)wglGetProcAddress("wglGetSwapIntervalEXT"); + if (!wglGetSwapIntervalEXT || !wglSwapIntervalEXT) { + write_log ("OPENGL: WGL_EXT_swap_control extension found but no wglGetSwapIntervalEXT or wglSwapIntervalEXT found!?\n"); + wglSwapIntervalEXT = 0; + wglGetSwapIntervalEXT = 0; + } + + } + + sl_ti2d_internalformat = GL_RGBA4; + sl_ti2d_format = GL_RGBA; + sl_ti2d_type = GL_UNSIGNED_SHORT_4_4_4_4_EXT; + ti2d_type = -1; + if (depth == 15 || depth == 16) { + if (!packed_pixels) { + gui_message ( + "OPENGL: can't use 15/16 bit screen depths because EXT_packed_pixels extension was not found.\n" + "Falling back to 32-bit mode"); + depth = 32; + } + ti2d_internalformat = GL_RGB5_A1; + ti2d_format = GL_RGBA; + ti2d_type = GL_UNSIGNED_SHORT_5_5_5_1_EXT; + } + if (depth == 32) { + ti2d_internalformat = GL_RGBA; + ti2d_format = GL_RGBA; + ti2d_type = GL_UNSIGNED_BYTE; + if (!packed_pixels) { + sl_ti2d_internalformat = GL_RGBA; + sl_ti2d_format = GL_RGBA; + sl_ti2d_type = GL_UNSIGNED_BYTE; + } + } + if (ti2d_type < 0) { + sprintf (errmsg, "OPENGL: Only 15, 16 or 32 bit screen depths supported (was %d)", depth); + return errmsg; + } + + glGenTextures (total_textures, tex); + + /* "bitplane" texture */ + glBindTexture (GL_TEXTURE_2D, tex [0]); + glTexImage2D (GL_TEXTURE_2D, 0, ti2d_internalformat, + required_texture_size, required_texture_size,0, ti2d_format, ti2d_type, 0); + + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + glClearColor (0.0, 0.0, 0.0, 0.0); + glShadeModel (GL_FLAT); + glDisable (GL_DEPTH_TEST); + glEnable (GL_TEXTURE_2D); + glDisable (GL_LIGHTING); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + ogl_enabled = 1; + OGL_resize (w_width, w_height); + OGL_refresh (); + init = 1; + + write_log("OPENGL: using texture depth %d texture size %d * %d scanline texture size %d * %d\n", + depth, required_texture_size, required_texture_size, required_sl_texture_size, required_sl_texture_size); + return 0; +} + +static void createscanlines (int force) +{ + int x, y, yy; + uae_u8 *sld, *p; + int sl4, sl8, sl42, sl82; + int l1, l2; + static int osl1, osl2, osl3; + + if (osl1 == currprefs.gfx_filter_scanlines && osl3 == currprefs.gfx_filter_scanlinelevel && osl2 == currprefs.gfx_filter_scanlineratio && !force) + return; + osl1 = currprefs.gfx_filter_scanlines; + osl3 = currprefs.gfx_filter_scanlinelevel; + osl2 = currprefs.gfx_filter_scanlineratio; + if (!currprefs.gfx_filter_scanlines) { + glDisable (GL_BLEND); + return; + } + + glEnable (GL_BLEND); + scanlinetex = tex[total_textures - 1]; + glBindTexture (GL_TEXTURE_2D, scanlinetex); + glTexImage2D (GL_TEXTURE_2D, 0, sl_ti2d_internalformat, + required_sl_texture_size, required_sl_texture_size, 0, sl_ti2d_format, sl_ti2d_type, 0); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + sl4 = currprefs.gfx_filter_scanlines * 16 / 100; + sl8 = currprefs.gfx_filter_scanlines * 256 / 100; + sl42 = currprefs.gfx_filter_scanlinelevel * 16 / 100; + sl82 = currprefs.gfx_filter_scanlinelevel * 256 / 100; + if (sl4 > 15) sl4 = 15; + if (sl8 > 255) sl8 = 255; + if (sl42 > 15) sl42 = 15; + if (sl82 > 255) sl82 = 255; + sld = malloc (w_width * w_height * 4); + memset (sld, 0, w_width * w_height * 4); + l1 = currprefs.gfx_filter_scanlineratio & 15; + l2 = currprefs.gfx_filter_scanlineratio >> 4; + if (!l1) l1 = 1; + if (!l2) l2 = 1; + for (y = 1; y < w_height; y += l1 + l2) { + for (yy = 0; yy < l2 && y + yy < w_height; yy++) { + for (x = 0; x < w_width; x++) { + if (packed_pixels) { + /* 16-bit, R4G4B4A4 */ + uae_u8 sll = sl42; + p = &sld[((y + yy) * w_width + x) * 2]; + p[0] = sl4 | (sll << 4); + p[1] = (sll << 4) | (sll << 0); + } else { + /* 32-bit, R8G8B8A8 */ + p = &sld[((y + yy) * w_width + x) * 4]; + p[0] = p[1] = p[2] = sl82; + p[3] = sl8; + } + } + } + } + glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, w_width, w_height, sl_ti2d_format, sl_ti2d_type, sld); + free (sld); +} + +static void setfilter (void) +{ + int filtering; + switch (currprefs.gfx_filter_filtermode & 1) + { + case 0: + filtering = GL_NEAREST; + break; + case 1: + default: + filtering = GL_LINEAR; + break; + } + if (currprefs.gfx_filter_scanlines > 0) { + glBindTexture (GL_TEXTURE_2D, scanlinetex); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); + } + glBindTexture (GL_TEXTURE_2D, tex[0]); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); +} + +static void OGL_swapinterval (void) +{ + doublevsync = 0; + if (wglSwapIntervalEXT) { + int i1, i2; + i1 = (currprefs.gfx_vsync > 0 && currprefs.gfx_afullscreen) ? (currprefs.gfx_refreshrate > 85 ? 2 : 1) : 0; + if (turbo_emulation) i1 = 0; + wglSwapIntervalEXT (i1); + i2 = wglGetSwapIntervalEXT (); + if (i1 == 2 && i2 < i1) /* did display driver support SwapInterval == 2 ? */ + doublevsync = 1; /* nope, we must wait for vblank twice */ + } +} + +void OGL_resize (int width, int height) +{ + if (!ogl_enabled) + return; + + w_width = width; + w_height = height; + glViewport (0, 0, w_width, w_height); + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); + glOrtho (0.0f, w_width, w_height, 0, -1.0f, 1.0f); + createscanlines (1); + setfilter (); + OGL_swapinterval (); +} + +static void OGL_dorender (int newtex) +{ + float x1, y1, x2, y2; + uae_u8 *data = gfxvidinfo.bufmem; + int fx, fy, xm, ym; + + xm = currprefs.gfx_lores ? 2 : 1; + ym = currprefs.gfx_linedbl ? 1 : 2; + if (w_width >= 1024) + xm *= 2; + else if (w_width < 500) + xm /= 2; + if (w_height >= 960) + ym *= 2; + else if (w_height < 350) + ym /= 2; + fx = (t_width * xm - w_width) / 2; + fy = (t_height * ym - w_height) / 2; + + glClear (GL_COLOR_BUFFER_BIT); + glMatrixMode (GL_MODELVIEW); + glLoadIdentity (); + + x1 = (float)(w_width * currprefs.gfx_filter_horiz_offset / 100.0); + y1 = (float)(w_height * currprefs.gfx_filter_vert_offset / 100.0); + x2 = x1 + (float)((required_texture_size * w_width / t_width) * (currprefs.gfx_filter_horiz_zoom + 100) / 100.0); + y2 = y1 + (float)((required_texture_size * w_height / t_height) * (currprefs.gfx_filter_vert_zoom + 100)/ 100.0); + x1 -= fx; y1 -= fy; + x2 += 2 * fx; y2 += 2 * fy; + + glBindTexture (GL_TEXTURE_2D, tex[0]); + if (newtex) + glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, t_width, t_height, ti2d_format, ti2d_type, data); + + glBegin (GL_QUADS); + glTexCoord2f (0, -1.0f); glVertex2f (x1, y1); + glTexCoord2f (0, 0); glVertex2f (x1, y2); + glTexCoord2f (1.0f, 0); glVertex2f (x2, y2); + glTexCoord2f (1.0f, -1.0f); glVertex2f (x2, y1); + glEnd(); + + if (currprefs.gfx_filter_scanlines > 0) { + float v = (float)required_sl_texture_size; + glBindTexture (GL_TEXTURE_2D, scanlinetex); + glBegin (GL_QUADS); + glTexCoord2f (0, -1.0f); glVertex2f (0, 0); + glTexCoord2f (0, 0); glVertex2f (0, v); + glTexCoord2f (1.0f, 0); glVertex2f (v, v); + glTexCoord2f (1.0f, -1.0f); glVertex2f (v, 0); + glEnd(); + } +} + +void OGL_render (void) +{ + if (!ogl_enabled) + return; + + OGL_dorender (1); + SwapBuffers (openglhdc); + if (doublevsync) { + OGL_dorender (0); + SwapBuffers (openglhdc); + } +} + +void OGL_refresh (void) +{ + if (!ogl_enabled) + return; + + createscanlines (0); + setfilter (); + OGL_swapinterval (); + OGL_render (); + } + +void OGL_getpixelformat (int depth,int *rb, int *gb, int *bb, int *rs, int *gs, int *bs, int *ab, int *as, int *a) +{ + switch (depth) + { + case 32: + *rb = 8; + *gb = 8; + *bb = 8; + *ab = 8; + *rs = 0; + *gs = 8; + *bs = 16; + *as = 24; + *a = 255; + break; + case 15: + case 16: + *rb = 5; + *gb = 5; + *bb = 5; + *ab = 1; + *rs = 11; + *gs = 6; + *bs = 1; + *as = 0; + *a = 1; + break; + } +} + +void OGL_free (void) +{ + if (hrc) { + wglMakeCurrent (NULL, NULL); + wglDeleteContext (hrc); + hrc = 0; + } + if (openglhdc) { + ReleaseDC (hwnd, openglhdc); + openglhdc = 0; + } + ogl_enabled = 0; +} + +HDC OGL_getDC (HDC hdc) +{ + return openglhdc; +} + +int OGL_isenabled (void) +{ + return ogl_enabled; +} + +#endif diff --git a/od-win32/opengl.h b/od-win32/opengl.h new file mode 100755 index 00000000..870c2b48 --- /dev/null +++ b/od-win32/opengl.h @@ -0,0 +1,9 @@ + +extern void OGL_resize (int width, int height); +extern void OGL_free (); +extern const char *OGL_init (HWND ahwnd, int w_w, int w_h, int t_w, int t_h, int depth); +extern void OGL_render (void); +extern void OGL_getpixelformat (int depth,int *rb, int *bb, int *gb, int *rs, int *bs, int *gs, int *ab, int *ar, int *a); +extern void OGL_refresh (void); +extern HDC OGL_getDC (HDC hdc); +extern int OGL_isenabled (void); diff --git a/od-win32/osdep/exectasks.h b/od-win32/osdep/exectasks.h new file mode 100755 index 00000000..9baccd17 --- /dev/null +++ b/od-win32/osdep/exectasks.h @@ -0,0 +1,51 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Stack magic definitions for autoconf.c + * + * Copyright 1997 Bernd Schmidt + */ + +#include + +#define CAN_DO_STACK_MAGIC + +#ifdef CAN_DO_STACK_MAGIC +#ifdef __GNUC__ +static inline void transfer_control(void *, int, void *, void *, int) __attribute__((noreturn)); +static inline void transfer_control(void *s, int size, void *pc, void *f, int has_retval) +#else +__declspec(noreturn) static __forceinline void transfer_control(void *s, int size, void *pc, void *f, int has_retval) +#endif +{ + unsigned long *stacktop = (unsigned long *)((char *)s + size - 20); + stacktop[0] = 0xC0DEDBAD; /* return address */ + stacktop[1] = (int)s; /* function arg 1: stack */ + stacktop[2] = (int)f; /* function arg 2: trap function */ + stacktop[3] = (int)stacktop; /* function arg 3: return value address */ + stacktop[4] = has_retval; +#ifdef __GNUC__ + __asm__ __volatile__ ("movl %0,%%esp\n\tpushl %1\n\tret\n" : : "r" (stacktop), "r" (pc) : "memory"); +#elif defined( _MSC_VER ) /* VisualC++ */ + __asm + { + mov esp, stacktop + push pc + ret + } +#endif + /* Not reached. */ + abort(); +} + +static __inline__ uae_u32 get_retval_from_stack (void *s, int size) +{ + return *(uae_u32 *)((char *)s + size - 20); +} + +static __inline__ int stack_has_retval (void *s, int size) +{ + return *(int *)((char *)s + size - 4); +} + +#endif diff --git a/od-win32/parser.c b/od-win32/parser.c new file mode 100755 index 00000000..0c3c8ad2 --- /dev/null +++ b/od-win32/parser.c @@ -0,0 +1,532 @@ +/* + * UAE - The Un*x Amiga Emulator + * + * Not a parser, but parallel and serial emulation for Win32 + * + * Copyright 1997 Mathias Ortmann + * Copyright 1998-1999 Brian King - added MIDI output support + */ + +#include "config.h" +#include "sysconfig.h" +#include +#include +#include +#include +#ifdef _MSC_VER +#include +#include +#include +#include +#else +#include "winstuff.h" +#endif +#include +#include +#include +#include + +#include "sysdeps.h" +#include "options.h" +#include "gensound.h" +#include "events.h" +#include "uae.h" +#include "include/memory.h" +#include "custom.h" +#include "autoconf.h" +#include "od-win32/win32gui.h" +#include "od-win32/parser.h" +#include "od-win32/midi.h" +#include "od-win32/ahidsound.h" +#include "win32.h" +#include "ioport.h" + +static UINT prttimer; +static char prtbuf[PRTBUFSIZE]; +static int prtbufbytes,wantwrite; +static HANDLE hPrt = INVALID_HANDLE_VALUE; +static DWORD dwJob; +extern HWND hAmigaWnd; +static int prtopen; +extern void flushpixels(void); +void DoSomeWeirdPrintingStuff( char val ); +static int uartbreak; + +static void flushprtbuf (void) +{ + DWORD written = 0; + + if (hPrt != INVALID_HANDLE_VALUE) + { + if( WritePrinter( hPrt, prtbuf, prtbufbytes, &written ) ) + { + if( written != prtbufbytes ) + write_log( "PRINTER: Only wrote %d of %d bytes!\n", written, prtbufbytes ); + } + else + { + write_log( "PRINTER: Couldn't write data!\n" ); + } + } + else + { + write_log( "PRINTER: Not open!\n" ); + } + prtbufbytes = 0; +} + +void finishjob (void) +{ + flushprtbuf (); +} + +static void DoSomeWeirdPrintingStuff( char val ) +{ + //if (prttimer) + //KillTimer (hAmigaWnd, prttimer); + if (prtbufbytes < PRTBUFSIZE) { + prtbuf[prtbufbytes++] = val; + //prttimer = SetTimer (hAmigaWnd, 1, 2000, NULL); + } else { + flushprtbuf (); + *prtbuf = val; + prtbufbytes = 1; + prttimer = 0; + } +} + +int isprinter (void) +{ + if (!strcasecmp(currprefs.prtname,"none")) + return 0; + if (!memcmp(currprefs.prtname,"LPT", 3)) { + paraport_open (currprefs.prtname); + return -1; + } + return 1; +} + +static void openprinter( void ) +{ + DOC_INFO_1 DocInfo; + + closeprinter (); + if (!strcasecmp(currprefs.prtname,"none")) + return; + if( ( hPrt == INVALID_HANDLE_VALUE ) && *currprefs.prtname) + { + if( OpenPrinter(currprefs.prtname, &hPrt, NULL ) ) + { + // Fill in the structure with info about this "document." + DocInfo.pDocName = "My Document"; + DocInfo.pOutputFile = NULL; + DocInfo.pDatatype = "RAW"; + // Inform the spooler the document is beginning. + if( (dwJob = StartDocPrinter( hPrt, 1, (LPSTR)&DocInfo )) == 0 ) + { + ClosePrinter( hPrt ); + hPrt = INVALID_HANDLE_VALUE; + } + else if( StartPagePrinter( hPrt ) ) + { + prtopen = 1; + } + } + else + { + hPrt = INVALID_HANDLE_VALUE; // Stupid bug in Win32, where OpenPrinter fails, but hPrt ends up being zero + } + } + if( hPrt != INVALID_HANDLE_VALUE ) + { + write_log( "PRINTER: Opening printer \"%s\" with handle 0x%x.\n", currprefs.prtname, hPrt ); + } + else if( *currprefs.prtname ) + { + write_log( "PRINTER: ERROR - Couldn't open printer \"%s\" for output.\n", currprefs.prtname ); + } +} + +void flushprinter (void) +{ + if (hPrt != INVALID_HANDLE_VALUE) { + SetJob( + hPrt, // handle to printer object + dwJob, // print job identifier + 0, // information level + 0, // job information buffer + 5 // job command value + ); + closeprinter(); + } +} + +void closeprinter( void ) +{ + if( hPrt != INVALID_HANDLE_VALUE ) + { + EndPagePrinter( hPrt ); + EndDocPrinter( hPrt ); + ClosePrinter( hPrt ); + hPrt = INVALID_HANDLE_VALUE; + write_log( "PRINTER: Closing printer.\n" ); + } + //KillTimer( hAmigaWnd, prttimer ); + prttimer = 0; + prtopen = 0; +} + +static void putprinter (char val) +{ + DoSomeWeirdPrintingStuff( val ); +} + +int doprinter (uae_u8 val) +{ + if (!prtopen) + openprinter (); + if (prtopen) + putprinter (val); + return prtopen; +} + +static HANDLE hCom = INVALID_HANDLE_VALUE; +static DCB dcb; +static HANDLE writeevent; +#define SERIAL_WRITE_BUFFER 100 +#define SERIAL_READ_BUFFER 100 +static uae_u8 outputbuffer[SERIAL_WRITE_BUFFER]; +static uae_u8 outputbufferout[SERIAL_WRITE_BUFFER]; +static uae_u8 inputbuffer[SERIAL_READ_BUFFER]; +static int datainoutput; +static int dataininput, dataininputcnt; +static OVERLAPPED writeol, readol; +static writepending; + +int openser (char *sername) +{ + char buf[32]; + COMMTIMEOUTS CommTimeOuts; + + sprintf (buf, "\\.\\\\%s", sername); + + if (!(writeevent = CreateEvent (NULL, TRUE, FALSE, NULL))) { + write_log ("SERIAL: Failed to create event!\n"); + return 0; + } + SetEvent (writeevent); + writeol.hEvent = writeevent; + uartbreak = 0; + if ((hCom = CreateFile (buf, GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, + NULL)) != INVALID_HANDLE_VALUE) { + SetCommMask (hCom, EV_RXFLAG); + SetupComm (hCom, 65536,128); + PurgeComm (hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); + CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF; + CommTimeOuts.ReadTotalTimeoutMultiplier = 0; + CommTimeOuts.ReadTotalTimeoutConstant = 0; + CommTimeOuts.WriteTotalTimeoutMultiplier = 0; + CommTimeOuts.WriteTotalTimeoutConstant = 0; + SetCommTimeouts (hCom, &CommTimeOuts); + + GetCommState (hCom, &dcb); + + dcb.BaudRate = 9600; + dcb.ByteSize = 8; + dcb.Parity = NOPARITY; + dcb.StopBits = ONESTOPBIT; + + dcb.fDsrSensitivity = FALSE; + dcb.fOutxDsrFlow = FALSE; + dcb.fDtrControl = DTR_CONTROL_DISABLE; + + if (currprefs.serial_hwctsrts) { + dcb.fOutxCtsFlow = TRUE; + dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; + } else { + dcb.fRtsControl = RTS_CONTROL_DISABLE; + dcb.fOutxCtsFlow = FALSE; + } + + dcb.fTXContinueOnXoff = FALSE; + dcb.fOutX = FALSE; + dcb.fInX = FALSE; + + dcb.fErrorChar = FALSE; + dcb.fNull = FALSE; + dcb.fAbortOnError = FALSE; + + dcb.XoffLim = 512; + dcb.XonLim = 2048; + + if (SetCommState (hCom, &dcb)) { + write_log ("SERIAL: Using %s CTS/RTS=%d\n", sername, currprefs.serial_hwctsrts); + return 1; + } + write_log ("SERIAL: serial driver didn't accept new parameters\n"); + CloseHandle (hCom); + hCom = INVALID_HANDLE_VALUE; + } + return 0; +} + +void closeser (void) +{ + if (hCom != INVALID_HANDLE_VALUE) { + CloseHandle (hCom); + hCom = INVALID_HANDLE_VALUE; + } + if (midi_ready) + Midi_Close(); + if( writeevent ) + CloseHandle( writeevent ); + writeevent = 0; + uartbreak = 0; +} + +static void outser (void) +{ + DWORD actual; + if (WaitForSingleObject (writeevent, 0) == WAIT_OBJECT_0 && datainoutput > 0) { + memcpy (outputbufferout, outputbuffer, datainoutput); + WriteFile (hCom, outputbufferout, datainoutput, &actual, &writeol); + datainoutput = 0; + } +} + +void writeser (int c) +{ + if (midi_ready) + { + BYTE outchar = (BYTE)c; + Midi_Parse( midi_output, &outchar ); + } + else + { + if (datainoutput + 1 < sizeof(outputbuffer)) { + outputbuffer[datainoutput++] = c; + } else { + write_log ("serial output buffer overflow, data will be lost\n"); + datainoutput = 0; + } + outser (); + } +} + +int checkserwrite (void) +{ + if (hCom == INVALID_HANDLE_VALUE) + return 1; + if (midi_ready) { + return 1; + } else { + outser (); + if (datainoutput >= sizeof (outputbuffer) - 1) + return 0; + } + return 1; +} + +int readseravail (void) +{ + COMSTAT ComStat; + DWORD dwErrorFlags; + if (midi_ready) { + if (ismidibyte ()) + return 1; + } else { + if (dataininput > dataininputcnt) + return 1; + if (hCom != INVALID_HANDLE_VALUE) { + ClearCommError (hCom, &dwErrorFlags, &ComStat); + if (ComStat.cbInQue > 0) + return 1; + } + } + return 0; +} + +int readser (int *buffer) +{ + COMSTAT ComStat; + DWORD dwErrorFlags; + DWORD actual; + + + if (midi_ready) + { + *buffer = getmidibyte (); + if (*buffer < 0) + return 0; + return 1; + } + else + { + if (dataininput > dataininputcnt) { + *buffer = inputbuffer[dataininputcnt++]; + return 1; + } + dataininput = 0; + dataininputcnt = 0; + if (hCom != INVALID_HANDLE_VALUE) + { + /* only try to read number of bytes in queue */ + ClearCommError (hCom, &dwErrorFlags, &ComStat); + if (ComStat.cbInQue) + { + int len = ComStat.cbInQue; + + if (len > sizeof (inputbuffer)) + len = sizeof (inputbuffer); + if (ReadFile (hCom, inputbuffer, len, &actual, &readol)) + { + dataininput = actual; + dataininputcnt = 0; + if (actual == 0) + return 0; + return readser (buffer); + } + } + } + } + return 0; +} + +void serialuartbreak (int v) +{ + if (hCom == INVALID_HANDLE_VALUE) + return; + + if (v) + EscapeCommFunction (hCom, SETBREAK); + else + EscapeCommFunction (hCom, CLRBREAK); +} + +void getserstat (int *pstatus) +{ + DWORD stat; + int status = 0; + + *pstatus = 0; + if (hCom == INVALID_HANDLE_VALUE) + return; + + GetCommModemStatus (hCom, &stat); + if (stat & MS_CTS_ON) + status |= TIOCM_CTS; + if (stat & MS_RLSD_ON) + status |= TIOCM_CAR; + if (stat & MS_DSR_ON) + status |= TIOCM_DSR; + if (stat & MS_RING_ON) + status |= TIOCM_RI; + *pstatus = status; +} + + +void setserstat (int mask, int onoff) +{ + if (hCom == INVALID_HANDLE_VALUE) + return; + + if (mask & TIOCM_DTR) + EscapeCommFunction (hCom, onoff ? SETDTR : CLRDTR); + if (!currprefs.serial_hwctsrts) { + if (mask & TIOCM_RTS) + EscapeCommFunction (hCom, onoff ? SETRTS : CLRRTS); + } +} + +int setbaud (long baud) +{ + if( baud == 31400 ) /* MIDI baud-rate */ + { + if (!midi_ready) + { + if (Midi_Open()) + write_log ("Midi enabled\n"); + } + return 1; + } + else + { + if (midi_ready) + { + Midi_Close(); + } + if (hCom != INVALID_HANDLE_VALUE) + { + if (GetCommState (hCom, &dcb)) + { + dcb.BaudRate = baud; + if (!SetCommState (hCom, &dcb)) { + write_log ("SERIAL: Error setting baud rate %d!\n", baud); + return 0; + } + } + else + { + write_log ("SERIAL: setbaud internal error!\n"); + } + } + } + return 1; +} + +void hsyncstuff(void) +//only generate Interrupts when +//writebuffer is complete flushed +//check state of lwin rwin +{ + static int keycheck = 0; + static int installahi; + +#ifdef AHI + { //begin ahi_sound + static int count; + if (ahi_on) { + count++; + //15625/count freebuffer check + if(count > 20) { + ahi_updatesound (1); + count = 0; + } + } + if (!installahi) + { + uaecptr a = here (); //this install the ahisound + org (RTAREA_BASE + 0xFFC0); + calltrap (deftrap (ahi_demux)); + dw (0x4e75);// rts + org (a); + installahi=1; + } + } //end ahi_sound +#endif +#ifdef PARALLEL_PORT + keycheck++; + if(keycheck==1000) + { + if (prtbufbytes) + { + flushprtbuf (); + } + { + extern flashscreen; + int DX_Fill( int , int , int, int, uae_u32 , enum RGBFTYPE ); + //extern int warned_JIT_0xF10000; + //warned_JIT_0xF10000 = 0; + if (flashscreen) { + DX_Fill(0,0,300,40,0x000000,9); + flashscreen--; + } + } + keycheck = 0; + } +#endif +} diff --git a/od-win32/parser.h b/od-win32/parser.h new file mode 100755 index 00000000..86a743c6 --- /dev/null +++ b/od-win32/parser.h @@ -0,0 +1,31 @@ +/* + * UAE - The Un*x Amiga Emulator + * + * Not a parser, but parallel and serial emulation for Win32 + * + * Copyright 1997 Mathias Ortmann + * Copyright 1998-1999 Brian King + */ + +#define PRTBUFSIZE 4096 + +int setbaud (long baud ); +void getserstat(int *status); +void setserstat (int mask, int onoff); +int readser (int *buffer); +int readseravail (void); +void writeser (int c); +int openser (char *sername); +void closeser (void); +void doserout (void); +void closeprinter (void); +void flushprinter (void); +int checkserwrite (void); +void serialuartbreak (int); + +#define TIOCM_CAR 1 +#define TIOCM_DSR 2 +#define TIOCM_RI 4 +#define TIOCM_DTR 8 +#define TIOCM_RTS 16 +#define TIOCM_CTS 32 diff --git a/od-win32/picasso96_win.c b/od-win32/picasso96_win.c new file mode 100755 index 00000000..0bd9bb69 --- /dev/null +++ b/od-win32/picasso96_win.c @@ -0,0 +1,3802 @@ +/* +* UAE - The U*nix Amiga Emulator +* +* Picasso96 Support Module +* +* Copyright 1997-2001 Brian King +* 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>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;ixminaddr && addr picasso96_state.Address && addr + 4 < picasso96_state.Extent) + { + addr -= picasso96_state.Address+(picasso96_state.XOffset*picasso96_state.BytesPerPixel) + +(picasso96_state.YOffset*picasso96_state.BytesPerRow); + if ( pixelcount > MAXFLUSHPIXEL ) + flushpixels(); + pixelbase[pixelcount].addr=addr; + pixelbase[pixelcount].value=value; + pixelbase[pixelcount++].size=4; + } + return; +#endif +#endif + + if (!picasso_on) + return; + +#ifndef LOCK_UNLOCK_MADNESS + /* + * Several writes to successive memory locations are a common access pattern. + * Try to optimize it. + */ + if (addr >= wgfx_linestart && addr + 4 <= wgfx_lineend) { + if (addr < wgfx_min) + wgfx_min = addr; + if (addr + 4 > wgfx_max) + wgfx_max = addr + 4; + return; + } else + { +#if P96TRACING_LEVEL > 0 + P96TRACE(("write_gfx_long( 0x%x, 0x%x )\n", addr, value )); +#endif + wgfx_flushline (); + } +#endif + + addr += gfxmem_start; + /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */ + if (addr < picasso96_state.Address || addr + 4 > picasso96_state.Extent) + return; + addr -= picasso96_state.Address+(picasso96_state.XOffset*picasso96_state.BytesPerPixel) + +(picasso96_state.YOffset*picasso96_state.BytesPerRow); + y = addr / picasso96_state.BytesPerRow; + +#ifdef LOCK_UNLOCK_MADNESS + //DX_Invalidate (y,y); + if (! picasso_vidinfo.extra_mem) { + pixelcount=0; + return; + } + + xbytes = addr - y * picasso96_state.BytesPerRow; + //x = xbytes / picasso96_state.BytesPerPixel; + + if (xbytes < (picasso96_state.Width*picasso96_state.BytesPerPixel) && y < picasso96_state.Height) + { + + dst = picasso96_state.HostAddress; + //dst = gfx_lock_picasso (); + if (dst) { + do_put_mem_long ((uae_u32 *)(dst + y * picasso_vidinfo.rowbytes + xbytes), value); + //gfx_unlock_picasso (); + } + else + write_log("error\n"); + } +#else + if (y >= picasso96_state.Height) + return; + wgfx_linestart = picasso96_state.Address - gfxmem_start + y * picasso96_state.BytesPerRow; + wgfx_lineend = wgfx_linestart + picasso96_state.BytesPerRow; + wgfx_y = y; + wgfx_min = oldaddr; + wgfx_max = oldaddr + 4; +#endif +} + +static void write_gfx_word (uaecptr addr, uae_u16 value) +{ + uaecptr oldaddr = addr; + int y; +#ifdef LOCK_UNLOCK_MADNESS + int x, xbytes; + uae_u8 *dst; +#ifdef PIXEL_LOCK + addr += gfxmem_start; + /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */ + if (addr > picasso96_state.Address && addr + 4 < picasso96_state.Extent) + { + addr -= picasso96_state.Address+(picasso96_state.XOffset*picasso96_state.BytesPerPixel) + +(picasso96_state.YOffset*picasso96_state.BytesPerRow); + if ( pixelcount > MAXFLUSHPIXEL ) + flushpixels(); + pixelbase[pixelcount].addr=addr; + pixelbase[pixelcount].value=value; + pixelbase[pixelcount++].size=2; + } + return; +#endif +#endif + if (!picasso_on) + return; + +#ifndef LOCK_UNLOCK_MADNESS + /* + * Several writes to successive memory locations are a common access pattern. + * Try to optimize it. + */ + if (addr >= wgfx_linestart && addr + 2 <= wgfx_lineend) { + if (addr < wgfx_min) + wgfx_min = addr; + if (addr + 2 > wgfx_max) + wgfx_max = addr + 2; + return; + } else + wgfx_flushline (); +#endif + + addr += gfxmem_start; + /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */ + if (addr < picasso96_state.Address || addr + 2 > picasso96_state.Extent) + return; + addr -= picasso96_state.Address+(picasso96_state.XOffset*picasso96_state.BytesPerPixel) + +(picasso96_state.YOffset*picasso96_state.BytesPerRow); + + y = addr / picasso96_state.BytesPerRow; + +#ifdef LOCK_UNLOCK_MADNESS + //DX_Invalidate (y, y); + if (! picasso_vidinfo.extra_mem) { + pixelcount=0; + return; + } + + xbytes = addr - y * picasso96_state.BytesPerRow; + //x = xbytes / picasso96_state.BytesPerPixel; + + if (x < (picasso96_state.Width*picasso96_state.BytesPerPixel) && y < picasso96_state.Height) + { + dst = picasso96_state.HostAddress; + + //dst = gfx_lock_picasso (); + if (dst) { + do_put_mem_word ((uae_u16 *)(dst + y * picasso_vidinfo.rowbytes + xbytes), value); + //gfx_unlock_picasso (); + } + } +#else + if (y >= picasso96_state.Height) + return; + wgfx_linestart = picasso96_state.Address - gfxmem_start + y * picasso96_state.BytesPerRow; + wgfx_lineend = wgfx_linestart + picasso96_state.BytesPerRow; + wgfx_y = y; + wgfx_min = oldaddr; + wgfx_max = oldaddr + 2; +#endif +} + +static void write_gfx_byte (uaecptr addr, uae_u8 value) +{ + uaecptr oldaddr = addr; + int y; +#ifdef LOCK_UNLOCK_MADNESS + int x, xbytes; + uae_u8 *dst; +#ifdef PIXEL_LOCK + addr += gfxmem_start; + /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */ + if (addr > picasso96_state.Address && addr + 4 < picasso96_state.Extent) + { + addr -= picasso96_state.Address+(picasso96_state.XOffset*picasso96_state.BytesPerPixel) + +(picasso96_state.YOffset*picasso96_state.BytesPerRow); + if ( pixelcount > MAXFLUSHPIXEL ) + flushpixels(); + pixelbase[pixelcount].addr=addr; + pixelbase[pixelcount].value=value; + pixelbase[pixelcount++].size=1; + } + return; +#endif +#endif + if (!picasso_on) + return; +#ifndef LOCK_UNLOCK_MADNESS + /* + * Several writes to successive memory locations are a common access pattern. + * Try to optimize it. + */ + if (addr >= wgfx_linestart && addr + 4 <= wgfx_lineend) { + if (addr < wgfx_min) + wgfx_min = addr; + if (addr + 1 > wgfx_max) + wgfx_max = addr + 1; + return; + } else + wgfx_flushline (); +#endif + + addr += gfxmem_start; + /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */ + if (addr < picasso96_state.Address || addr + 1 > picasso96_state.Extent) + return; + addr -= picasso96_state.Address+(picasso96_state.XOffset*picasso96_state.BytesPerPixel) + +(picasso96_state.YOffset*picasso96_state.BytesPerRow); + + y = addr / picasso96_state.BytesPerRow; + +#ifdef LOCK_UNLOCK_MADNESS + //DX_Invalidate (y, y); + if (! picasso_vidinfo.extra_mem) { + pixelcount=0; + return; + } + + xbytes = addr - y * picasso96_state.BytesPerRow; + x = xbytes / picasso96_state.BytesPerPixel; + + if (x < picasso96_state.Width && y < picasso96_state.Height) + { + dst = picasso96_state.HostAddress; + + //dst = gfx_lock_picasso (); + if (dst) { + *(uae_u8 *)(dst + y * picasso_vidinfo.rowbytes + xbytes) = value; + //gfx_unlock_picasso (); + } + } +#else + if (y >= picasso96_state.Height) + return; + wgfx_linestart = picasso96_state.Address - gfxmem_start + y * picasso96_state.BytesPerRow; + wgfx_lineend = wgfx_linestart + picasso96_state.BytesPerRow; + wgfx_y = y; + wgfx_min = oldaddr; + wgfx_max = oldaddr + 1; +#endif +} + +static uae_u32 REGPARAM2 gfxmem_lget (uaecptr addr) +{ + uae_u32 *m; + + special_mem|=picasso_is_special_read; + addr -= gfxmem_start & gfxmem_mask; + addr &= gfxmem_mask; + m = (uae_u32 *)(gfxmemory + addr); + return do_get_mem_long(m); +} + +static uae_u32 REGPARAM2 gfxmem_wget (uaecptr addr) +{ + uae_u16 *m; + special_mem|=picasso_is_special_read; + addr -= gfxmem_start & gfxmem_mask; + addr &= gfxmem_mask; + m = (uae_u16 *)(gfxmemory + addr); + return do_get_mem_word(m); +} + +static uae_u32 REGPARAM2 gfxmem_bget (uaecptr addr) +{ + special_mem|=picasso_is_special_read; + addr -= gfxmem_start & gfxmem_mask; + addr &= gfxmem_mask; + return gfxmemory[addr]; +} + +static void REGPARAM2 gfxmem_lput (uaecptr addr, uae_u32 l) +{ + uae_u32 *m; +#ifdef SWAPSPEEDUP + __asm { //byteswap now + mov eax,l + bswap eax + mov l,eax + } +#endif + special_mem|=picasso_is_special; + addr -= gfxmem_start & gfxmem_mask; + addr &= gfxmem_mask; + + m = (uae_u32 *)(gfxmemory + addr); +/* //only write difference + __asm { + mov eax,m + mov eax,[eax] + bswap eax + cmp eax,l + jne l2 + mov m,0 +l2: + } + if (!m) return; +*/ +#ifdef SWAPSPEEDUP + *m=l; +#else + do_put_mem_long(m, l); +#endif + /* write the long-word to our displayable memory */ + write_gfx_long(addr, l); +} + +static void REGPARAM2 gfxmem_wput (uaecptr addr, uae_u32 w) +{ + uae_u16 *m; + special_mem|=picasso_is_special; + addr -= gfxmem_start & gfxmem_mask; + addr &= gfxmem_mask; + m = (uae_u16 *)(gfxmemory + addr); + do_put_mem_word(m, (uae_u16)w); + + /* write the word to our displayable memory */ + write_gfx_word(addr, (uae_u16)w); +} + +static void REGPARAM2 gfxmem_bput (uaecptr addr, uae_u32 b) +{ + special_mem|=picasso_is_special; + addr -= gfxmem_start & gfxmem_mask; + addr &= gfxmem_mask; + gfxmemory[addr] = b; + + /* write the byte to our displayable memory */ + write_gfx_byte(addr, (uae_u8)b); +} + +static int REGPARAM2 gfxmem_check (uaecptr addr, uae_u32 size) +{ + addr -= gfxmem_start & gfxmem_mask; + addr &= gfxmem_mask; + return (addr + size) < allocated_gfxmem; +} + +static uae_u8 *REGPARAM2 gfxmem_xlate (uaecptr addr) +{ + addr -= gfxmem_start & gfxmem_mask; + addr &= gfxmem_mask; + return gfxmemory + addr; +} + +addrbank gfxmem_bank = { + gfxmem_lget, gfxmem_wget, gfxmem_bget, + gfxmem_lput, gfxmem_wput, gfxmem_bput, + gfxmem_xlate, gfxmem_check, NULL +}; + +/* Call this function first, near the beginning of code flow +* Place in InitGraphics() which seems reasonable... +* Also put it in reset_drawing() for safe-keeping. */ +void InitPicasso96 (void) +{ + have_done_picasso = 0; + pixelcount = 0; + palette_changed = 0; +//fastscreen + oldscr=0; +//fastscreen + memset (&picasso96_state, 0, sizeof(struct picasso96_state_struct)); + + if (1) { + int i, count; + + for (i = 0; i < 256; i++) { + p2ctab[i][0] = (((i & 128) ? 0x01000000 : 0) + | ((i & 64) ? 0x010000 : 0) + | ((i & 32) ? 0x0100 : 0) + | ((i & 16) ? 0x01 : 0)); + p2ctab[i][1] = (((i & 8) ? 0x01000000 : 0) + | ((i & 4) ? 0x010000 : 0) + | ((i & 2) ? 0x0100 : 0) + | ((i & 1) ? 0x01 : 0)); + } + count = 0; + while (DisplayModes[count].depth >= 0) + count++; + for (i = 0; i < count; i++) { + switch (DisplayModes[i].depth) { + case 1: + if (DisplayModes[i].res.width > chunky.width) + chunky.width = DisplayModes[i].res.width; + if (DisplayModes[i].res.height > chunky.height) + chunky.height = DisplayModes[i].res.height; + break; + case 2: + if (DisplayModes[i].res.width > hicolour.width) + hicolour.width = DisplayModes[i].res.width; + if (DisplayModes[i].res.height > hicolour.height) + hicolour.height = DisplayModes[i].res.height; + break; + case 3: + if (DisplayModes[i].res.width > truecolour.width) + truecolour.width = DisplayModes[i].res.width; + if (DisplayModes[i].res.height > truecolour.height) + truecolour.height = DisplayModes[i].res.height; + break; + case 4: + if (DisplayModes[i].res.width > alphacolour.width) + alphacolour.width = DisplayModes[i].res.width; + if (DisplayModes[i].res.height > alphacolour.height) + alphacolour.height = DisplayModes[i].res.height; + break; + } + } + //ShowSupportedResolutions (); + } +} + +uae_u8 *restore_p96 (uae_u8 *src) +{ + return src; +} + +uae_u8 *save_p96 (int *len) +{ + uae_u8 *dstbak,*dst; + + //dstbak = dst = malloc (16 + 12 + 1 + 1); + return 0; +} + + + + +#endif diff --git a/od-win32/picasso96_win.h b/od-win32/picasso96_win.h new file mode 100755 index 00000000..3f5fe9eb --- /dev/null +++ b/od-win32/picasso96_win.h @@ -0,0 +1,561 @@ +/* + * UAE - The U*nix Amiga Emulator + * + * Picasso96 Support Module Header + * + * Copyright 1997 Brian King + */ +#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< +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "options.h" +#include "posixemu.h" +#include "threaddep/thread.h" +#include "filesys.h" + +/* Our Win32 implementation of this function */ +void gettimeofday( struct timeval *tv, void *blah ) +{ + struct timeb time; + ftime( &time ); + + tv->tv_sec = time.time; + tv->tv_usec = time.millitm * 1000; +} + +/* convert time_t to/from AmigaDOS time */ +#define secs_per_day ( 24 * 60 * 60 ) +#define diff ( (8 * 365 + 2) * secs_per_day ) + +void get_time(time_t t, long* days, long* mins, long* ticks) +{ + /* time_t is secs since 1-1-1970 */ + /* days since 1-1-1978 */ + /* mins since midnight */ + /* ticks past minute @ 50Hz */ + + t -= diff; + *days = t / secs_per_day; + t -= *days * secs_per_day; + *mins = t / 60; + t -= *mins * 60; + *ticks = t * 50; +} + +/* stdioemu, posixemu, mallocemu, and various file system helper routines */ +static DWORD lasterror; + +static int isillegal (unsigned char *str) +{ + int result = 0; + unsigned char a = *str, b = str[1], c = str[2]; + + if (a >= 'a' && a <= 'z') + a &= ~' '; + if (b >= 'a' && b <= 'z') + b &= ~' '; + if (c >= 'a' && c <= 'z') + c &= ~' '; + + result = ( (a == 'A' && b == 'U' && c == 'X') || + (a == 'C' && b == 'O' && c == 'N') || + (a == 'P' && b == 'R' && c == 'N') || + (a == 'N' && b == 'U' && c == 'L') ); + + return result; +} + +static int checkspace (char *str, char s, char d) +{ + char *ptr = str; + + while (*ptr && *ptr == s) + ptr++; + + if (!*ptr || *ptr == '/' || *ptr == '\\') { + while (str < ptr) + *(str++) = d; + return 0; + } + return 1; +} + +/* This is sick and incomplete... in the meantime, I have discovered six new illegal file name formats + * M$ sucks! */ +void fname_atow (const char *src, char *dst, int size) +{ + char *lastslash = dst, *strt = dst, *posn = NULL, *temp = NULL; + int i, j; + + temp = xmalloc( size ); + + while (size-- > 0) { + if (!(*dst = *src++)) + break; + + if (*dst == '~' || *dst == '|' || *dst == '*' || *dst == '?') { + if (size > 2) { + sprintf (dst, "~%02x", *dst); + size -= 2; + dst += 2; + } + } else if (*dst == '/') { + if (checkspace (lastslash, ' ', (char)0xa0) && (dst - lastslash == 3 || (dst - lastslash > 3 && lastslash[3] == '.')) && isillegal (lastslash)) { + i = dst - lastslash - 3; + dst++; + for (j = i + 1; j--; dst--) + *dst = dst[-1]; + *(dst++) = (char)0xa0; + dst += i; + size--; + } else if (*lastslash == '.' && (dst - lastslash == 1 || (lastslash[1] == '.' && dst - lastslash == 2)) && size) { + *(dst++) = (char)0xa0; + size--; + } + *dst = '\\'; + lastslash = dst + 1; + } + dst++; + } + + if (checkspace (lastslash, ' ', (char)0xa0) && (dst - lastslash == 3 || (dst - lastslash > 3 && lastslash[3] == '.')) && isillegal (lastslash) && size > 1) { + i = dst - lastslash - 3; + dst++; + for (j = i + 1; j--; dst--) + *dst = dst[-1]; + *(dst++) = (char)0xa0; + } else if (!strcmp (lastslash, ".") || !strcmp (lastslash, "..")) + strcat (lastslash, "\xa0"); + + /* Major kludge, because I can't find the problem... */ + if( ( posn = strstr( strt, "..\xA0\\" ) ) == strt && temp) + { + strcpy( temp, "..\\" ); + strcat( temp, strt + 4 ); + strcpy( strt, temp ); + } + + /* Another major kludge, for the MUI installation... */ + if( *strt == ' ' ) /* first char as a space is illegal in Windoze */ + { + sprintf( temp, "~%02x%s", ' ', strt+1 ); + strcpy( strt, temp ); + } + + free (temp); +} + +static int hextol (char a) +{ + if (a >= '0' && a <= '9') + return a - '0'; + if (a >= 'a' && a <= 'f') + return a - 'a' + 10; + if (a >= 'A' && a <= 'F') + return a - 'A' + 10; + return 2; +} + +/* Win32 file name restrictions suck... */ +void fname_wtoa (unsigned char *ptr) +{ + unsigned char *lastslash = ptr; + + while (*ptr) { + if (*ptr == '~') { + *ptr = hextol (ptr[1]) * 16 + hextol (ptr[2]); + strcpy (ptr + 1, ptr + 3); + } else if (*ptr == '\\') { + if (checkspace (lastslash, ' ', (char)0xa0) && ptr - lastslash > 3 && lastslash[3] == 0xa0 && isillegal (lastslash)) { + ptr--; + strcpy (lastslash + 3, lastslash + 4); + } + *ptr = '/'; + lastslash = ptr + 1; + } + ptr++; + } + + if (checkspace (lastslash, ' ', (char)0xa0) && ptr - lastslash > 3 && lastslash[3] == 0xa0 && isillegal (lastslash)) + strcpy (lastslash + 3, lastslash + 4); +} + +#ifndef HAVE_TRUNCATE +int truncate (const char *name, long int len) +{ + HANDLE hFile; + BOOL bResult = FALSE; + int result = -1; + +#if 0 + char buf[1024]; + + fname_atow(name,buf,sizeof buf); + + if( ( hFile = CreateFile( buf, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ) ) != INVALID_HANDLE_VALUE ) + { + if( SetFilePointer( hFile, len, NULL, FILE_BEGIN ) == (DWORD)len ) + { + if( SetEndOfFile( hFile ) == TRUE ) + result = 0; + } + else + { + write_log( "SetFilePointer() failure for %s to posn %d\n", buf, len ); + } + CloseHandle( hFile ); + } + else + { + write_log( "CreateFile() failed to open %s\n", buf ); + } +#else + if( ( hFile = CreateFile( name, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ) ) != INVALID_HANDLE_VALUE ) + { + if( SetFilePointer( hFile, len, NULL, FILE_BEGIN ) == (DWORD)len ) + { + if( SetEndOfFile( hFile ) == TRUE ) + result = 0; + } + else + { + write_log( "SetFilePointer() failure for %s to posn %d\n", name, len ); + } + CloseHandle( hFile ); + } + else + { + write_log( "CreateFile() failed to open %s\n", name ); + } +#endif + if( result == -1 ) + lasterror = GetLastError(); + return result; +} +#endif + +DIR { + WIN32_FIND_DATA finddata; + HANDLE hDir; + int getnext; +}; + +DIR *posixemu_opendir(const char *path) +{ + char buf[1024]; + DIR *dir; + + if (!(dir = (DIR *)GlobalAlloc(GPTR,sizeof(DIR)))) + { + lasterror = GetLastError(); + return 0; + } +#if 0 + fname_atow(path,buf,sizeof buf-4); +#else + strcpy( buf, path ); +#endif + strcat(buf,"\\*"); + + if ((dir->hDir = FindFirstFile(buf,&dir->finddata)) == INVALID_HANDLE_VALUE) + { + lasterror = GetLastError(); + GlobalFree(dir); + return 0; + } + + return dir; +} + +struct dirent *posixemu_readdir(DIR *dir) +{ + if (dir->getnext) + { + if (!FindNextFile(dir->hDir,&dir->finddata)) + { + lasterror = GetLastError(); + return 0; + } + } + dir->getnext = TRUE; + + fname_wtoa(dir->finddata.cFileName); + return (struct dirent *)dir->finddata.cFileName; +} + +void posixemu_closedir(DIR *dir) +{ + FindClose(dir->hDir); + GlobalFree(dir); +} + +static int w32fopendel(char *name, char *mode, int delflag) +{ + HANDLE hFile; + + if ((hFile = CreateFile(name, + mode[1] == '+' ? GENERIC_READ | GENERIC_WRITE : GENERIC_READ, // ouch :) + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + delflag ? FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE : FILE_ATTRIBUTE_NORMAL, + NULL)) == INVALID_HANDLE_VALUE) + { + lasterror = GetLastError(); + hFile = 0; + } + + return (int)hFile; /* return handle */ +} + +DWORD getattr(const char *name, LPFILETIME lpft, size_t *size) +{ + HANDLE hFind; + WIN32_FIND_DATA fd; + + if ((hFind = FindFirstFile(name,&fd)) == INVALID_HANDLE_VALUE) + { + lasterror = GetLastError(); + + fd.dwFileAttributes = GetFileAttributes(name); + + return fd.dwFileAttributes; + } + + FindClose(hFind); + + if (lpft) *lpft = fd.ftLastWriteTime; + if (size) *size = fd.nFileSizeLow; + + return fd.dwFileAttributes; +} + +int isspecialdrive(const char *name) +{ + int v, err; + DWORD last = SetErrorMode (SEM_FAILCRITICALERRORS); + v = GetFileAttributes(name); + err = GetLastError (); + SetErrorMode (last); + if (v != INVALID_FILE_ATTRIBUTES) + return 0; + if (err == ERROR_NOT_READY) + return 1; + if (err) + return -1; + return 0; +} + +int posixemu_stat(const char *name, struct stat *statbuf) +{ + DWORD attr; + FILETIME ft, lft; + + if ((attr = getattr(name,&ft,(size_t*)&statbuf->st_size)) == (DWORD)~0) + { + lasterror = GetLastError(); + return -1; + } + else + { + statbuf->st_mode = (attr & FILE_ATTRIBUTE_READONLY) ? FILEFLAG_READ : FILEFLAG_READ | FILEFLAG_WRITE; + if (attr & FILE_ATTRIBUTE_ARCHIVE) statbuf->st_mode |= FILEFLAG_ARCHIVE; + if (attr & FILE_ATTRIBUTE_DIRECTORY) statbuf->st_mode |= FILEFLAG_DIR; + FileTimeToLocalFileTime(&ft,&lft); + statbuf->st_mtime = (long)((*(__int64 *)&lft-((__int64)(369*365+89)*(__int64)(24*60*60)*(__int64)10000000))/(__int64)10000000); + } + return 0; +} + +int posixemu_chmod(const char *name, int mode) +{ + DWORD attr = FILE_ATTRIBUTE_NORMAL; + if (!(mode & FILEFLAG_WRITE)) attr |= FILE_ATTRIBUTE_READONLY; + if (mode & FILEFLAG_ARCHIVE) attr |= FILE_ATTRIBUTE_ARCHIVE; + if (SetFileAttributes(name,attr)) return 1; + lasterror = GetLastError(); + return -1; +} + +void tmToSystemTime( struct tm *tmtime, LPSYSTEMTIME systime ) +{ + if( tmtime == NULL ) + { + GetSystemTime( systime ); + } + else + { + systime->wDay = tmtime->tm_mday; + systime->wDayOfWeek = tmtime->tm_wday; + systime->wMonth = tmtime->tm_mon + 1; + systime->wYear = tmtime->tm_year + 1900; + systime->wHour = tmtime->tm_hour; + systime->wMinute = tmtime->tm_min; + systime->wSecond = tmtime->tm_sec; + systime->wMilliseconds = 0; + } +} + +static int setfiletime(const char *name, unsigned int days, int minute, int tick, int tolocal) +{ + FILETIME LocalFileTime, FileTime; + HANDLE hFile; + int success; + if ((hFile = CreateFile(name, GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL)) == INVALID_HANDLE_VALUE) + { + lasterror = GetLastError(); + return 0; + } + + *(__int64 *)&LocalFileTime = (((__int64)(377*365+91+days)*(__int64)1440+(__int64)minute)*(__int64)(60*50)+(__int64)tick)*(__int64)200000; + + if (tolocal) { + if (!LocalFileTimeToFileTime(&LocalFileTime,&FileTime)) FileTime = LocalFileTime; + } else { + FileTime = LocalFileTime; + } + + if (!(success = SetFileTime(hFile,&FileTime,&FileTime,&FileTime))) lasterror = GetLastError(); + CloseHandle(hFile); + + return success; +} + +int posixemu_utime( const char *name, struct utimbuf *ttime ) +{ + int result = -1, tolocal; + long days, mins, ticks, actime; + + if (!ttime) { + actime = time (NULL); + tolocal = 0; + } else { + tolocal = 1; + actime = ttime->actime; + } + get_time(actime, &days, &mins, &ticks); + + if( setfiletime( name, days, mins, ticks, tolocal ) ) + result = 0; + + return result; +} + +#if 1 +/* pthread Win32 emulation */ +void sem_init (HANDLE * event, int manual_reset, int initial_state) +{ + if( *event ) + { + if( initial_state ) + { + SetEvent( *event ); + } + else + { + ResetEvent( *event ); + } + } + else + { + *event = CreateEvent (NULL, manual_reset, initial_state, NULL); + } +} + +void sem_wait (HANDLE * event) +{ + WaitForSingleObject (*event, INFINITE); +} + +void sem_post (HANDLE * event) +{ + SetEvent (*event); +} + +int sem_trywait (HANDLE * event) +{ + return WaitForSingleObject (*event, 0) == WAIT_OBJECT_0 ? 0 : -1; +} + +void sem_close (HANDLE * event) +{ + if( *event ) + { + CloseHandle( *event ); + *event = NULL; + } +} + +typedef unsigned (__stdcall *BEGINTHREADEX_FUNCPTR)(void *); + +int start_penguin (void *(*f)(void *), void *arg, DWORD * foo) +{ + HANDLE hThread; + int result = 1; + + hThread = (HANDLE)_beginthreadex( NULL, 0, (BEGINTHREADEX_FUNCPTR)f, arg, 0, foo ); + if( hThread ) + SetThreadPriority (hThread, THREAD_PRIORITY_HIGHEST); + else + result = 0; + return result; +} + +#endif + +void set_thread_priority (int pri) +{ +} + diff --git a/od-win32/posixemu.h b/od-win32/posixemu.h new file mode 100755 index 00000000..cfbb506a --- /dev/null +++ b/od-win32/posixemu.h @@ -0,0 +1,7 @@ +/* posixemu prototypes */ +#ifndef __POSIXEMU_H__ +#define __POSIXEMU_H__ +void fname_atow (const char *src, char *dst, int size); +void fname_wtoa (unsigned char *ptr); +int w32fopendel(char *name, char *mode, int delflag); +#endif \ No newline at end of file diff --git a/od-win32/resources/35floppy.ico b/od-win32/resources/35floppy.ico new file mode 100755 index 00000000..249005f3 Binary files /dev/null and b/od-win32/resources/35floppy.ico differ diff --git a/od-win32/resources/Mycomp.ico b/od-win32/resources/Mycomp.ico new file mode 100755 index 00000000..9260b94d Binary files /dev/null and b/od-win32/resources/Mycomp.ico differ diff --git a/od-win32/resources/RCa00564 b/od-win32/resources/RCa00564 new file mode 100755 index 00000000..6415f0b2 Binary files /dev/null and b/od-win32/resources/RCa00564 differ diff --git a/od-win32/resources/amigainfo.ico b/od-win32/resources/amigainfo.ico new file mode 100755 index 00000000..92ed436d Binary files /dev/null and b/od-win32/resources/amigainfo.ico differ diff --git a/od-win32/resources/avioutput.ico b/od-win32/resources/avioutput.ico new file mode 100755 index 00000000..30b40d93 Binary files /dev/null and b/od-win32/resources/avioutput.ico differ diff --git a/od-win32/resources/chip.ico b/od-win32/resources/chip.ico new file mode 100755 index 00000000..52d09a93 Binary files /dev/null and b/od-win32/resources/chip.ico differ diff --git a/od-win32/resources/cpu.ico b/od-win32/resources/cpu.ico new file mode 100755 index 00000000..2e790a54 Binary files /dev/null and b/od-win32/resources/cpu.ico differ diff --git a/od-win32/resources/drive.ico b/od-win32/resources/drive.ico new file mode 100755 index 00000000..1009e454 Binary files /dev/null and b/od-win32/resources/drive.ico differ diff --git a/od-win32/resources/drive_click.wav b/od-win32/resources/drive_click.wav new file mode 100755 index 00000000..c21a5f86 Binary files /dev/null and b/od-win32/resources/drive_click.wav differ diff --git a/od-win32/resources/drive_snatch.wav b/od-win32/resources/drive_snatch.wav new file mode 100755 index 00000000..5c363869 Binary files /dev/null and b/od-win32/resources/drive_snatch.wav differ diff --git a/od-win32/resources/drive_spin.wav b/od-win32/resources/drive_spin.wav new file mode 100755 index 00000000..184524f8 Binary files /dev/null and b/od-win32/resources/drive_spin.wav differ diff --git a/od-win32/resources/drive_spinnd.wav b/od-win32/resources/drive_spinnd.wav new file mode 100755 index 00000000..184524f8 Binary files /dev/null and b/od-win32/resources/drive_spinnd.wav differ diff --git a/od-win32/resources/drive_startup.wav b/od-win32/resources/drive_startup.wav new file mode 100755 index 00000000..6456d8a2 Binary files /dev/null and b/od-win32/resources/drive_startup.wav differ diff --git a/od-win32/resources/file.ico b/od-win32/resources/file.ico new file mode 100755 index 00000000..c1661ad2 Binary files /dev/null and b/od-win32/resources/file.ico differ diff --git a/od-win32/resources/folder.ico b/od-win32/resources/folder.ico new file mode 100755 index 00000000..ae42edc7 Binary files /dev/null and b/od-win32/resources/folder.ico differ diff --git a/od-win32/resources/h_arrow.cur b/od-win32/resources/h_arrow.cur new file mode 100755 index 00000000..27d0f242 Binary files /dev/null and b/od-win32/resources/h_arrow.cur differ diff --git a/od-win32/resources/joystick.ico b/od-win32/resources/joystick.ico new file mode 100755 index 00000000..8b9d7d74 Binary files /dev/null and b/od-win32/resources/joystick.ico differ diff --git a/od-win32/resources/misc.ico b/od-win32/resources/misc.ico new file mode 100755 index 00000000..9d335ba8 Binary files /dev/null and b/od-win32/resources/misc.ico differ diff --git a/od-win32/resources/move_dow.ico b/od-win32/resources/move_dow.ico new file mode 100755 index 00000000..a3481836 Binary files /dev/null and b/od-win32/resources/move_dow.ico differ diff --git a/od-win32/resources/move_up.ico b/od-win32/resources/move_up.ico new file mode 100755 index 00000000..879cd92d Binary files /dev/null and b/od-win32/resources/move_up.ico differ diff --git a/od-win32/resources/resource.h b/od-win32/resources/resource.h new file mode 100755 index 00000000..72279d53 --- /dev/null +++ b/od-win32/resources/resource.h @@ -0,0 +1,668 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by winuae.rc +// +#define IDS_KICKSTART 1 +#define IDS_DISK 2 +#define IDS_DISPLAY 3 +#define IDS_HARDDISK 4 +#define IDS_FLOPPY 5 +#define IDS_ABOUT 6 +#define IDS_LOADSAVE 7 +#define IDS_AVIOUTPUT 8 +#define IDS_PORTS 9 +#define IDS_MISC1 10 +#define IDS_MEMORY 11 +#define IDS_CPU 12 +#define IDS_CHIPSET 13 +#define IDS_INPUT 14 +#define IDS_OPENGL 15 +#define IDS_MISC2 16 +#define IDS_EXTTEXT 100 +#define IDS_EXTACTUAL 101 +#define IDS_SOUND 102 +#define IDS_CDROM 103 +#define IDS_FRAMERATE 104 +#define IDS_SECOND 105 +#define IDS_THIRD 106 +#define IDD_KICKSTART 107 +#define IDS_FOURTH 107 +#define IDD_DISPLAY 108 +#define IDS_FIFTH 108 +#define IDD_MEMORY 109 +#define IDS_SIXTH 109 +#define IDD_FLOPPY 110 +#define IDS_SEVENTH 110 +#define IDD_CPU 111 +#define IDS_EIGHTH 111 +#define IDD_ABOUT 112 +#define IDS_NINTH 112 +#define IDD_HARDDISK 113 +#define IDS_TENTH 113 +#define IDS_SELECTADF 114 +#define IDS_ADF 115 +#define IDS_CHOOSEBLANK 116 +#define IDS_SELECTHDF 117 +#define IDS_HDF 118 +#define IDS_SELECTUAE 119 +#define IDS_UAE 120 +#define IDS_SELECTROM 121 +#define IDD_SOUND 122 +#define IDS_ROM 122 +#define IDI_APPICON 123 +#define IDS_SELECTKEY 123 +#define IDI_CPU 124 +#define IDS_KEY 124 +#define IDI_ABOUT 125 +#define IDS_SELECTINFO 125 +#define IDS_NONE 126 +#define IDS_VOLUME 127 +#define IDI_HARDDISK 128 +#define IDS_PATH 128 +#define IDS_RW 129 +#define IDI_SOUND 130 +#define IDS_SECTORS 130 +#define IDS_SURFACES 131 +#define IDS_RESERVED 132 +#define IDS_BLOCKSIZE 133 +#define IDI_FLOPPY 134 +#define IDS_NAME 134 +#define IDD_LOADSAVE 135 +#define IDS_DESCRIPTION 135 +#define IDS_ONEINSTANCE 136 +#define IDI_PORTS 137 +#define IDS_INSTALLDIRECTX 137 +#define IDD_PORTS 138 +#define IDS_REGKEYCREATEFAILED 138 +#define IDS_COULDNOTLOADCONFIG 139 +#define IDD_CONTRIBUTORS 140 +#define IDS_NOHELP 140 +#define IDD_MISC1 141 +#define IDS_MUSTSELECTCONFIG 141 +#define IDD_HARDFILE 142 +#define IDS_NOAGA 142 +#define IDD_FILESYS 143 +#define IDS_INVALIDCOMPORT 143 +#define IDS_WSOCK2NEEDED 144 +#define IDD_MISC2 144 +#define IDS_UNSUPPORTEDPIXELFORMAT 145 +#define IDS_WAVEOUTOPENFAILURE 146 +#define IDS_MUSTENTERNAME 147 +#define IDS_MUSTSELECTCONFIGFORDELETE 148 +#define IDS_DELETECONFIGCONFIRMATION 149 +#define IDI_MISC1 150 +#define IDS_DELETECONFIGTITLE 150 +#define IDC_MYHAND 151 +#define IDS_GFXCARDCHECK 151 +#define IDD_DIALOG1 152 +#define IDS_GFXCARDTITLE 152 +#define IDD_DEBUGGER 152 +#define IDD_SETINFO 153 +#define IDS_MUSTSELECTPATH 153 +#define IDI_ICON1 153 +#define IDS_SETTINGSERROR 154 +#define IDD_CHIPSET 154 +#define IDS_MUSTSELECTNAME 155 +#define IDI_MOVE_UP 155 +#define IDS_MUSTSELECTFILE 156 +#define IDI_MOVE_DOWN 156 +#define IDS_FAILEDHARDFILECREATION 157 +#define IDD_AVIOUTPUT 157 +#define IDS_CREATIONERROR 158 +#define IDI_AVIOUTPUT 158 +#define IDS_ERRORTITLE 159 +#define IDS_SELECTFILESYSROOT 160 +#define IDD_OPENGL 160 +#define IDS_DEFAULTMIDIOUT 161 +#define IDS_DEFAULTMIDIIN 162 +#define IDS_CONTRIBUTORS1 163 +#define IDD_HARDDRIVE 163 +#define IDS_CONTRIBUTORS2 164 +#define IDS_INVALIDPRTPORT 165 +#define IDS_SELECTUSS 166 +#define IDS_RESTOREUSS 166 +#define IDS_USS 167 +#define IDS_WRONGOSVERSION 168 +#define IDR_DRIVE_STARTUP_A500_1 168 +#define IDS_SELECTFLASH 169 +#define IDR_DRIVE_CLICK_A500_1 169 +#define IDS_FLASH 170 +#define IDR_DRIVE_SPIN_A500_1 170 +#define IDD_INPUT 171 +#define IDS_INPUTHOSTWIDGET 171 +#define IDI_INPUT 172 +#define IDS_INPUTAMIGAEVENT 172 +#define IDD_DISK 172 +#define IDS_INPUTAUTOFIRE 173 +#define IDS_SAVEUSS 174 +#define IDS_MIDIOVERFLOW 175 +#define IDS_HFDSIZE 176 +#define IDS_DEVICE 177 +#define IDS_BOOTPRI 178 +#define IDS_WRONGDXVERSION 179 +#define IDI_MISC2 180 +#define IDR_DRIVE_SNATCH_A500_1 181 +#define IDI_DISK 182 +#define IDR_DRIVE_SPINND_A500_1 182 +#define IDD_PANEL 183 +#define IDI_CONFIGFILE 185 +#define IDM_SYSTRAY 186 +#define IDI_FOLDER 188 +#define IDI_DISPLAY 190 +#define IDI_ROOT 192 +#define IDI_ICON2 194 +#define IDI_MEMORY 194 +#define IDS_SOUND_MONO 200 +#define IDS_SOUND_MIXED 201 +#define IDS_SOUND_STEREO 202 +#define IDS_SOUND_INTERPOL_DISABLED 203 +#define IDS_SOUND_INTERPOL_RH 204 +#define IDS_SOUND_INTERPOL_CRUX 205 +#define IDS_SOUND_FILTER_OFF 206 +#define IDS_SOUND_FILTER_EMULATED 207 +#define IDS_SOUND_FILTER_ON 208 +#define IDS_INPUT_COMPATIBILITY 209 +#define IDS_INPUT_CUSTOM 210 +#define IDS_INPUT_COPY_DEFAULT 211 +#define IDS_INPUT_COPY_CUSTOM 212 +#define IDS_3D_NO_FILTER 213 +#define IDS_3D_BILINEAR 214 +#define IDS_VSYNC_DEFAULT 215 +#define IDS_DRIVESOUND_NONE 216 +#define IDS_DRIVESOUND_DEFAULT_A500 217 +#define IDS_AVIOUTPUT_NOCODEC 218 +#define IDS_DISK_IMAGENAME 219 +#define IDS_DISK_DRIVENAME 220 +#define IDS_AGA8BIT 221 +#define IDS_UNSUPPORTEDSCREENMODE 222 +#define IDS_UNSUPPORTEDSCREENMODE_1 223 +#define IDS_UNSUPPORTEDSCREENMODE_2 224 +#define IDS_UNSUPPORTEDSCREENMODE_3 225 +#define IDS_UNSUPPORTEDSCREENMODE_4 226 +#define IDS_FLOPPYTYPE35DD 227 +#define IDS_FLOPPYTYPE35HD 228 +#define IDS_FLOPPYTYPE525SD 229 +#define IDS_FLOPPYTYPEDISABLED 230 +#define IDS_STMENUNOFLOPPY 231 +#define IDS_TREEVIEW_HARDWARE 232 +#define IDS_TREEVIEW_HOST 233 +#define IDS_TREEVIEW_MISC 234 +#define IDS_TREEVIEW_SETTINGS 235 +#define IDS_WINUAETITLE_MMB 236 +#define IDS_IDS_WINUAETITLE_NORMAL 237 +#define IDS_WINUAETITLE_NORMAL 237 +#define IDC_RESOLUTION 1021 +#define IDC_SERIAL 1022 +#define IDC_REFRESHRATE 1022 +#define IDC_ILLEGAL 1023 +#define IDC_MIDILIST 1023 +#define IDC_MIDIOUTLIST 1023 +#define IDC_DA_MODE 1023 +#define IDC_SHOWGUI 1024 +#define IDC_MIDIINLIST 1024 +#define IDC_RESOLUTION2 1024 +#define IDC_DISPLAYSELECT 1024 +#define IDC_AUTOCONFIG 1025 +#define IDC_PRINTERLIST 1025 +#define IDC_CHIPMEM 1026 +#define IDC_CREATELOGFILE 1026 +#define IDC_FASTMEM 1027 +#define IDC_SHOWLEDS 1027 +#define IDC_SLOWMEM 1030 +#define IDC_PARALLEL 1033 +#define IDC_JULIAN 1040 +#define IDC_FASTTEXT 1043 +#define IDC_FASTRAM 1044 +#define IDC_CHIPRAM 1045 +#define IDC_SLOWRAM 1046 +#define IDC_Z3TEXT 1047 +#define IDC_Z3FASTRAM 1048 +#define IDC_Z3FASTMEM 1049 +#define IDC_UAEHOME 1070 +#define IDC_PICASSOHOME 1071 +#define IDC_AMIGAHOME 1072 +#define IDC_WINUAEHOME 1073 +#define IDC_AIABHOME 1074 +#define IDC_CLOANTOHOME 1075 +#define IDC_THEROOTS 1076 +#define IDC_CAPS 1077 +#define IDC_RICHEDIT1 1091 +#define IDC_RICHEDIT2 1092 +#define IDC_CONTRIBUTORS 1124 +#define IDC_ASPECT 1170 +#define IDC_BLIT32 1173 +#define IDC_BLITIMM 1174 +#define IDC_LORES 1176 +#define IDC_VSYNC 1177 +#define IDC_AFULLSCREEN 1178 +#define IDC_FRAMERATE 1185 +#define IDC_RATETEXT 1186 +#define IDC_XSIZE 1187 +#define IDC_YSIZE 1188 +#define IDC_INPUTAUTOFIRERATE 1188 +#define IDC_LM_NORMAL 1189 +#define IDC_INPUTSPEEDD 1189 +#define IDC_LM_DOUBLED 1190 +#define IDC_INPUTSPEEDA 1190 +#define IDC_GFXCARDTEXT 1191 +#define IDC_LM_SCANLINES 1191 +#define IDC_INPUTSPEEDM 1191 +#define IDC_P96RAM 1192 +#define IDC_PFULLSCREEN 1192 +#define IDC_P96MEM 1193 +#define IDC_DA_SLIDER 1193 +#define IDC_CPU0 1200 +#define IDC_CPU1 1201 +#define IDC_CPU2 1202 +#define IDC_CPU3 1203 +#define IDC_CPU4 1204 +#define IDC_CPU5 1205 +#define IDC_CPU6 1206 +#define IDC_SPEED 1207 +#define IDC_CS_HOST 1209 +#define IDC_CS_68000 1210 +#define IDC_CS_ADJUSTABLE 1211 +#define IDC_CS_CPU_TEXT 1212 +#define IDC_CS_CHIPSET_TEXT 1213 +#define IDC_COMPATIBLE 1214 +#define IDC_TRUST0 1215 +#define IDC_TRUST1 1216 +#define IDC_TRUST2 1217 +#define IDC_CACHE 1218 +#define IDC_CYCLEEXACT 1219 +#define IDC_CS_CPU_TEXT2 1219 +#define IDC_CPUIDLE 1220 +#define IDC_SOUNDSETTINGS 1229 +#define IDC_8BIT 1230 +#define IDC_16BIT 1231 +#define IDC_11KHZ 1232 +#define IDC_22KHZ 1233 +#define IDC_44KHZ 1234 +#define IDC_48KHZ 1235 +#define IDC_SOUNDSIZE 1236 +#define IDC_FREQUENCY 1237 +#define IDC_SOUND0 1238 +#define IDC_SOUND1 1239 +#define IDC_SOUND2 1240 +#define IDC_SOUND3 1241 +#define IDC_SOUNDSTYLE 1242 +#define IDC_SOUNDSTYLE0 1243 +#define IDC_STEREO 1244 +#define IDC_SOUNDSTYLE1 1245 +#define IDC_SOUNDINTERPOLATION 1248 +#define IDC_INTERPOLATION0 1249 +#define IDC_INTERPOLATION1 1250 +#define IDC_INTERPOLATION2 1251 +#define IDC_STEREOMODE 1252 +#define IDC_SOUNDINTERPOLATION2 1252 +#define IDC_STEREOMODE0 1253 +#define IDC_STEREOMODE1 1254 +#define IDC_STEREOMODE2 1255 +#define IDC_SOUNDINTERPOLATION3 1256 +#define IDC_DF0TEXT 1270 +#define IDC_DF1TEXT 1271 +#define IDC_DF2TEXT 1272 +#define IDC_DF3TEXT 1273 +#define IDC_EJECT0 1274 +#define IDC_EJECT1 1275 +#define IDC_EJECT2 1276 +#define IDC_EJECT3 1277 +#define IDC_DF0 1278 +#define IDC_DF1 1279 +#define IDC_DF2 1280 +#define IDC_DF3 1281 +#define IDC_CREATE 1282 +#define IDC_CREATE_RAW 1283 +#define IDC_SNAPSHOTNAME 1284 +#define IDC_SNAPSHOT 1285 +#define IDC_DOSAVESTATE 1286 +#define IDC_DOLOADSTATE 1287 +#define IDC_PORT0_JOY0 1300 +#define IDC_PORT0_JOY1 1301 +#define IDC_PORT0_MOUSE 1302 +#define IDC_PORT0_KBDA 1303 +#define IDC_PORT0_KBDB 1304 +#define IDC_PORT0_KBDC 1305 +#define IDC_PORT1_JOY0 1306 +#define IDC_PORT1_JOY1 1307 +#define IDC_PORT1_MOUSE 1308 +#define IDC_PORT1_KBDA 1309 +#define IDC_PORT1_KBDB 1310 +#define IDC_PORT1_KBDC 1311 +#define IDC_PORT0 1312 +#define IDC_PORT1 1313 +#define IDC_MIDIFRAME 1314 +#define IDC_SERPARFRAME 1315 +#define IDC_EDIT 1334 +#define IDC_REMOVE 1335 +#define IDC_VOLUMELIST 1336 +#define IDC_UP 1337 +#define IDC_DOWN 1338 +#define IDC_NEW_FS 1339 +#define IDC_NEW_HF 1340 +#define IDC_NEW_HD 1341 +#define IDC_PATH_NAME 1362 +#define IDC_SELECTOR 1363 +#define IDC_VOLUME_NAME 1364 +#define IDC_HARDFILE_DEVICE 1364 +#define IDC_SECTORS 1365 +#define IDC_VOLUME_DEVICE 1365 +#define IDC_HEADS 1366 +#define IDC_RESERVED 1367 +#define IDC_BLOCKSIZE 1368 +#define IDC_HARDFILE_BOOTPRI 1369 +#define IDC_SECTORS_TEXT 1370 +#define IDC_SURFACES_TEXT 1371 +#define IDC_RESERVED_TEXT 1372 +#define IDC_RESERVED_TEXT2 1373 +#define IDC_BLOCKSIZE_TEXT 1374 +#define ID_OK 1375 +#define IDC_HARDFILE_BOOTPRI_TEXT 1375 +#define IDC_PATH_FILESYS 1376 +#define IDC_HARDFILE_DIR_TEXT 1377 +#define IDC_HARDFILE_DEVICE_TEXT 1378 +#define IDC_RW 1379 +#define IDC_HFRDB 1380 +#define IDC_RW2 1380 +#define IDC_RDB 1380 +#define IDC_HARDFILE_FILESYS_TEXT 1380 +#define IDC_FILESYS_SELECTOR 1381 +#define IDC_ROMFILE 1390 +#define IDC_KEYFILE 1391 +#define IDC_KICKCHOOSER 1392 +#define IDC_KEYCHOOSER 1393 +#define IDC_ROMFILE2 1394 +#define IDC_ROMCHOOSER2 1395 +#define IDC_FLASHCHOOSER 1396 +#define IDC_FLASHFILE 1397 +#define IDC_CARTFILE 1398 +#define IDC_CARTCHOOSER 1399 +#define IDC_SAVE 1400 +#define IDC_LOAD 1401 +#define IDC_DELETE 1403 +#define IDC_CONFIGLIST 1404 +#define IDC_EDITNAME 1405 +#define IDC_EDITDESCRIPTION 1406 +#define IDC_QUICKSAVE 1408 +#define IDC_QUICKLOAD 1409 +#define IDC_EXIT 1410 +#define IDC_EDITPATH 1410 +#define IDC_CREATEHF 1500 +#define IDC_HFSIZE 1501 +#define IDC_LINEMODE 1502 +#define IDC_SOCKETS 1503 +#define IDC_RESETAMIGA 1504 +#define IDC_QUITEMU 1505 +#define IDC_TEST16BIT 1506 +#define IDC_MAPDRIVES 1507 +#define IDC_CPUTEXT 1508 +#define IDC_SWAP 1509 +#define IDC_CACHETEXT 1509 +#define IDC_SELECTRESTEXT 1510 +#define IDC_SCREENRESTEXT 1511 +#define IDC_WIDTHTEXT 1512 +#define IDC_WINDOWEDTEXT 1512 +#define IDC_HEIGHTTEXT 1513 +#define IDC_SETTINGSTEXT 1514 +#define IDC_REFRESHTEXT 1515 +#define IDC_SETTINGSTEXT2 1515 +#define IDC_DISABLE1 1516 +#define IDC_DF1WP 1516 +#define IDC_DISABLE2 1517 +#define IDC_DF2WP 1517 +#define IDC_DISABLE3 1518 +#define IDC_XCENTER 1518 +#define IDC_DF3WP 1518 +#define IDC_YCENTER 1519 +#define IDC_DISABLE0 1519 +#define IDC_DF0WP 1519 +#define IDC_OCS 1520 +#define IDC_HDFLOPPY 1520 +#define IDC_ECS_AGNUS 1521 +#define IDC_ECS_DENISE 1522 +#define IDC_ECS 1523 +#define IDC_AGA 1524 +#define IDC_NTSC 1525 +#define IDC_NOSPEED 1527 +#define IDC_NOSOUND 1528 +#define IDC_INACTIVE_NOSOUND 1528 +#define IDC_MIDI 1529 +#define IDC_NOSPEEDPAUSE 1529 +#define IDC_INACTIVE_PAUSE 1529 +#define IDC_KICKSHIFTER 1530 +#define IDC_MIDI2 1530 +#define IDC_HIGHPRIORITY 1530 +#define IDC_MINIMIZED_NOSOUND 1530 +#define IDC_MINIMIZED_PAUSE 1531 +#define IDC_D0 1532 +#define IDC_STATE_CAPTURE 1532 +#define IDC_D1 1533 +#define IDC_D2 1534 +#define IDC_D3 1535 +#define IDC_D4 1536 +#define IDC_D5 1537 +#define IDC_D6 1538 +#define IDC_D7 1539 +#define IDC_A0 1540 +#define IDC_A1 1541 +#define IDC_A2 1542 +#define IDC_A3 1543 +#define IDC_A4 1544 +#define IDC_A5 1545 +#define IDC_A6 1546 +#define IDC_A7 1547 +#define IDC_USP 1548 +#define IDC_SSP 1549 +#define IDC_PC 1550 +#define IDC_T1 1551 +#define IDC_T2 1552 +#define IDC_T3 1553 +#define IDC_SHARED 1553 +#define IDC_T4 1554 +#define IDC_SER_CTSRTS 1554 +#define IDC_T5 1555 +#define IDC_SERIAL_DIRECT 1555 +#define IDC_T6 1556 +#define IDC_T7 1557 +#define IDC_T8 1558 +#define IDC_T9 1559 +#define IDC_T10 1560 +#define IDC_T11 1561 +#define IDC_T12 1562 +#define IDC_T13 1563 +#define IDC_T14 1564 +#define IDC_T15 1565 +#define IDC_T16 1566 +#define IDC_VIEWINFO 1568 +#define IDC_SETINFO 1569 +#define IDC_FLOPPYSLIDER 1570 +#define IDC_FLOPPYSLIDERTEXT 1571 +#define IDC_FLOPPYSPEED 1572 +#define IDC_FLOPPYSPD 1572 +#define IDC_GUILANGUAGE_LIST 1573 +#define IDC_SOUNDBUFFERRAM 1574 +#define IDC_SOUNDADJUST 1575 +#define IDC_SOUNDBUFFERTEXT 1576 +#define IDC_SOUNDVOLUME 1576 +#define IDC_SOUNDBUFFERMEM 1577 +#define IDC_HARDFLUSH 1578 +#define IDC_SOUNDADJUSTNUM 1578 +#define IDC_CONSTJUMP 1579 +#define IDC_SOUNDDRIVEVOLUME 1579 +#define IDC_JITFPU 1580 +#define IDC_NOFLAGS 1581 +#define IDC_CS_CACHE_TEXT 1582 +#define IDC_FORCE 1583 +#define IDC_COLLISIONS 1584 +#define IDC_DISASSEMBLY 1585 +#define IDC_CTRLF11 1586 +#define IDC_FASTCOPPER 1588 +#define IDC_COLLISION0 1589 +#define IDC_COLLISION1 1590 +#define IDC_AUDIOSYNC 1590 +#define IDC_COLLISION2 1591 +#define IDC_COLLISION3 1592 +#define IDC_SOUNDLAGSLIDER 1592 +#define IDC_SOUNDLAGCAPTION 1594 +#define IDC_FLOPPYTYPE 1594 +#define IDC_SYNCPARAMS 1595 +#define IDC_DF0TYPE 1595 +#define IDC_SOUNDLAGTEXT 1596 +#define IDC_DF1TYPE 1596 +#define IDC_DF2TYPE 1597 +#define IDC_SOUNDSPEEDSLIDER 1598 +#define IDC_DF0TYPE4 1598 +#define IDC_DF3TYPE 1598 +#define IDC_SOUNDSPEEDTEXT 1599 +#define IDC_SOUNDSPEEDCAPTION 1600 +#define IDC_NOOVERLAY 1601 +#define IDC_ROMFILE2TEXT 1602 +#define IDC_ROMTEXT 1603 +#define IDC_KEYTEXT 1604 +#define IDC_CD32 1605 +#define IDC_AKIKOC2P 1605 +#define IDC_FLASHTEXT 1605 +#define IDC_SCSIDEVICE 1606 +#define IDC_FLASHTEXT2 1606 +#define IDC_AVIOUTPUT_PAL 1607 +#define IDC_ASPI 1607 +#define IDC_INPUTTYPE 1607 +#define IDC_AVIOUTPUT_NTSC 1608 +#define IDC_INPUTSELECTTEXT 1608 +#define IDC_KILLWINKEYS 1608 +#define IDC_SCSIDEVICE2 1608 +#define IDC_CLOCKSYNC 1608 +#define IDC_NOUAEFSDB 1608 +#define IDC_AVIOUTPUT_FPS 1609 +#define IDC_INPUTDEVICE 1609 +#define IDC_MAPROM 1609 +#define IDC_AVIOUTPUT_FILETEXT 1610 +#define IDC_INPUTDEVICETEXT 1610 +#define IDC_AVIOUTPUT_FILE 1611 +#define IDC_INPUTLIST 1611 +#define IDC_AVIOUTPUT_FPS_STATIC 1612 +#define IDC_INPUTAMIGA 1612 +#define IDC_AVIOUTPUT_VIDEO 1613 +#define IDC_INPUTAUTOFIRE 1613 +#define IDC_AVIOUTPUT_AUDIO 1614 +#define IDC_INPUTCOPYFROM 1614 +#define IDC_AVIOUTPUT_VIDEO_CODEC 1615 +#define IDC_OPENGLENABLE 1615 +#define IDC_INPUTDEVICEDISABLE 1615 +#define IDC_AVIOUTPUT_ACTIVATED 1615 +#define IDC_AVIOUTPUT_AUDIO_CODEC 1616 +#define IDC_OPENGLHZ 1616 +#define IDC_INPUTAMIGACNT 1616 +#define IDC_AVIOUTPUT_BORDER_TRIM 1617 +#define IDC_OPENGLVZ 1617 +#define IDC_AVIOUTPUT_AUDIO_STATIC 1618 +#define IDC_OPENGLHO 1618 +#define IDC_AVIOUTPUT_VIDEO_STATIC 1619 +#define IDC_OPENGLVO 1619 +#define IDC_AVIOUTPUT_8BIT 1620 +#define IDC_OPENGLHZV 1620 +#define IDC_AVIOUTPUT_24BIT 1621 +#define IDC_OPENGLVZV 1621 +#define IDC_AVIOUTPUT_WIDTH 1622 +#define IDC_OPENGLHOV 1622 +#define IDC_AVIOUTPUT_HEIGHT 1623 +#define IDC_OPENGLVOV 1623 +#define IDC_AVIOUTPUT_FRAME 1624 +#define IDC_OPENGLSL 1624 +#define IDC_OPENGLSLR 1625 +#define IDC_OPENGLSLV 1626 +#define IDC_OPENGLBITS 1627 +#define IDC_OPENGLMODE 1627 +#define IDC_OPENGLFILTER 1628 +#define IDC_OPENGLDEFAULT 1629 +#define IDC_INPUTDEADZONE 1630 +#define IDC_OPENGLSL2 1630 +#define IDC_INPUTCOPY 1631 +#define IDC_OPENGLSL2V 1631 +#define IDC_SCREENSHOT 1632 +#define IDC_INPUTSWAP 1632 +#define IDC_FLOPPYSPDTEXT 1633 +#define IDC_FLOPPYSPD_TEXT 1634 +#define IDC_KAILLERA 1635 +#define IDC_HARDDRIVE 1635 +#define IDC_INACTIVE_PRI 1635 +#define IDC_KAILLERA_CHAT 1636 +#define IDC_SOUNDPRIMARY 1636 +#define IDC_MINIMIZED_PRI 1636 +#define IDC_KAILLERA_CHAT_TEXT 1637 +#define IDC_VOLUME_BOOTPRI_TEXT 1637 +#define IDC_KAILLERA_CHAT_SEND 1638 +#define IDC_VOLUME_BOOTPRI 1638 +#define IDC_KAILLERA_LIST 1639 +#define IDC_KBLED1 1639 +#define IDC_KAILLERAFELLOW 1640 +#define IDC_KBLED2 1640 +#define IDC_SOUNDFILTER 1640 +#define IDC_KAILLERAJOY 1641 +#define IDC_KBLED3 1641 +#define IDC_SOUNDCALIBRATE 1641 +#define IDC_KAILLERAJOYKEYBOARD 1642 +#define IDC_ACTIVEPRIORITY 1642 +#define IDC_ACTIVE_PRIORITY 1642 +#define IDC_SOUNDDRIVE 1642 +#define IDC_KAILLERAOPTIONS 1643 +#define IDC_INACTIVE_PRIORITY 1643 +#define IDC_KAILLERASUPPRESSWARNINGS 1644 +#define IDC_ACTIVE_PRI 1644 +#define IDC_KAILLERANONE 1645 +#define IDC_MINIMIZED_PRIORITY 1645 +#define IDC_AVIOUTPUT_FRAMELIMITER 1645 +#define IDC_KAILLERACONTROLS 1646 +#define IDC_STATE_RATE 1646 +#define IDC_KAILLERANOFPSLIMIT 1647 +#define IDC_STATE_BUFFERSIZE 1647 +#define IDC_SOUNDDRIVESELECT 1647 +#define IDC_PANELTREE 1647 +#define IDC_AVIOUTPUT_DIMENSIONS_STATIC 1648 +#define IDC_STATE_BUFFERSIZE_TEXT 1648 +#define IDC_CONFIGTREE 1648 +#define IDC_AVIOUTPUT_OPTIONS 1649 +#define IDC_STATE_RATE_TEXT 1649 +#define IDC_DISKLISTREMOVE 1649 +#define IDC_SOUNDCARD 1650 +#define IDC_CS_SOUND0 1650 +#define IDC_SOUNDCARDLIST 1651 +#define IDC_CS_SOUND1 1651 +#define IDC_SOUNDFREQ 1652 +#define IDC_CS_SOUND2 1652 +#define IDC_SOUNDCARD2 1653 +#define IDC_SOUNDFREQTXT 1653 +#define IDC_PANEL_FRAME 1653 +#define IDC_SOUNDFILTERTXT 1654 +#define IDC_PANEL_FRAME_OUTER 1654 +#define IDC_SOUNDSTEREO 1655 +#define IDC_CONFIGTYPE 1655 +#define IDC_SOUNDDRIVETXT 1656 +#define IDC_SOUNDSTEREOTXT 1657 +#define IDC_SOUNDINTERPOLATIONTXT 1658 +#define IDC_DISK 1659 +#define IDC_DISKLIST 1659 +#define ID__FLOPPYDRIVES 40004 +#define ID_FLOPPYDRIVES_DF0 40005 +#define ID_ST_CONFIGURATION 40010 +#define ID_ST_HELP 40011 +#define ID_ST_QUIT 40012 +#define ID_ST_EJECTALL 40013 +#define ID_ST_DF0 40014 +#define ID_ST_DF1 40015 +#define ID_ST_DF2 40016 +#define ID_ST_DF3 40017 +#define ID_ST_RESET 40019 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_3D_CONTROLS 1 +#define _APS_NEXT_RESOURCE_VALUE 196 +#define _APS_NEXT_COMMAND_VALUE 40020 +#define _APS_NEXT_CONTROL_VALUE 1656 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/od-win32/resources/resource.hm b/od-win32/resources/resource.hm new file mode 100755 index 00000000..d62039db --- /dev/null +++ b/od-win32/resources/resource.hm @@ -0,0 +1,11 @@ +// Microsoft Visual C++ generated Help ID include file. +// Used by winuae.rc +// +#define HIDC_CREATELOGFILE 0x808d0402 // IDD_MISC1 [English (U.S.)] +#define HIDC_EDITDESCRIPTION 0x8087057e // IDD_LOADSAVE [English (U.S.)] +#define HIDC_EDITNAME 0x8087057d // IDD_LOADSAVE [English (U.S.)] +#define HIDC_EDITPATH 0x80870582 // IDD_LOADSAVE [English (U.S.)] +#define HIDC_LORES 0x806c0498 // IDD_DISPLAY [English (U.S.)] +#define HIDC_MAPDRIVES 0x807105e3 // IDD_HARDDISK [English (U.S.)] +#define HIDC_PFULLSCREEN 0x806c04a8 // IDD_DISPLAY [English (U.S.)] +#define HIDC_TEST16BIT 0x806c05e2 // IDD_DISPLAY [English (U.S.)] diff --git a/od-win32/resources/root.ico b/od-win32/resources/root.ico new file mode 100755 index 00000000..50707e1e Binary files /dev/null and b/od-win32/resources/root.ico differ diff --git a/od-win32/resources/screen.ico b/od-win32/resources/screen.ico new file mode 100755 index 00000000..ce897d66 Binary files /dev/null and b/od-win32/resources/screen.ico differ diff --git a/od-win32/resources/sound.ico b/od-win32/resources/sound.ico new file mode 100755 index 00000000..c77c98d0 Binary files /dev/null and b/od-win32/resources/sound.ico differ diff --git a/od-win32/resources/winuae.exe.manifest b/od-win32/resources/winuae.exe.manifest new file mode 100755 index 00000000..dbd80124 --- /dev/null +++ b/od-win32/resources/winuae.exe.manifest @@ -0,0 +1,22 @@ + + + + + + + + + + \ No newline at end of file diff --git a/od-win32/resources/winuae.ico b/od-win32/resources/winuae.ico new file mode 100755 index 00000000..ea35d3bc Binary files /dev/null and b/od-win32/resources/winuae.ico differ diff --git a/od-win32/resources/winuae.rc b/od-win32/resources/winuae.rc new file mode 100755 index 00000000..4da9f16a --- /dev/null +++ b/od-win32/resources/winuae.rc @@ -0,0 +1,1253 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +// Generated Help ID header file +#define APSTUDIO_HIDDEN_SYMBOLS +#include "resource.hm" +#undef APSTUDIO_HIDDEN_SYMBOLS + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" +#include "dlgs.h" +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_KICKSTART DIALOGEX 0, 0, 300, 175 +STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD +EXSTYLE WS_EX_CONTEXTHELP +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + GROUPBOX "Boot-ROM Settings:",-1,5,12,290,90 + RTEXT "ROM File:",IDC_ROMTEXT,10,27,75,10 + EDITTEXT IDC_ROMFILE,90,22,185,15,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_KICKCHOOSER,280,22,10,15 + RTEXT "Key File:",IDC_KEYTEXT,10,48,75,10 + EDITTEXT IDC_KEYFILE,90,43,185,15,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_KEYCHOOSER,280,43,10,15 + RTEXT "Extended ROM File:",IDC_ROMFILE2TEXT,10,68,75,10 + EDITTEXT IDC_ROMFILE2,90,63,185,15,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_ROMCHOOSER2,280,63,10,15 + CONTROL "MAPROM emulation",IDC_MAPROM,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,104,86,80,10 + CONTROL "ShapeShifter support",IDC_KICKSHIFTER,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,196,86,80,10 + GROUPBOX "Misc settings:",-1,5,105,290,59 + RTEXT "Flash RAM File:",IDC_FLASHTEXT,8,119,75,10 + EDITTEXT IDC_FLASHFILE,89,117,185,15,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_FLASHCHOOSER,279,117,10,15 + RTEXT "Cartridge ROM File:",IDC_FLASHTEXT2,8,140,75,10 + EDITTEXT IDC_CARTFILE,89,137,185,15,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_CARTCHOOSER,279,137,10,15 +END + +IDD_DISPLAY DIALOGEX 0, 0, 300, 194 +STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + GROUPBOX "Screen",IDC_SCREENRESTEXT,12,0,199,67,BS_LEFT + RTEXT "Fullscreen",IDC_SELECTRESTEXT,22,17,34,15, + SS_CENTERIMAGE + COMBOBOX IDC_DISPLAYSELECT,61,10,143,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_RESOLUTION,61,27,77,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_REFRESHRATE,143,27,61,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + RTEXT "Windowed",IDC_WINDOWEDTEXT,22,51,35,8 + EDITTEXT IDC_XSIZE,61,48,35,12,ES_NUMBER + EDITTEXT IDC_YSIZE,103,48,35,12,ES_NUMBER + CONTROL "VSync",IDC_VSYNC,"Button",BS_AUTOCHECKBOX | BS_LEFT | + WS_TABSTOP,145,49,54,10 + GROUPBOX "Settings",IDC_SETTINGSTEXT,12,77,199,73 + CONTROL "Full Screen",IDC_AFULLSCREEN,"Button",BS_AUTOCHECKBOX | + BS_LEFT | WS_TABSTOP,35,89,90,10 + CONTROL "Correct aspect ratio",IDC_ASPECT,"Button", + BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,35,106,90,10 + CONTROL "Full Screen RTG",IDC_PFULLSCREEN,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,131,89,70,10,0, + HIDC_PFULLSCREEN + CONTROL "Lo-res",IDC_LORES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 131,106,70,10,0,HIDC_LORES + LTEXT "Refresh:",IDC_REFRESHTEXT,34,129,28,8 + CONTROL "Slider1",IDC_FRAMERATE,"msctls_trackbar32", + TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,64,124,75,20 + CTEXT "",IDC_RATETEXT,144,124,50,20,SS_SUNKEN | WS_BORDER + GROUPBOX "Centering",IDC_STATIC,221,0,61,67 + CONTROL "Horizontal",IDC_XCENTER,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,229,16,45,10 + CONTROL "Vertical",IDC_YCENTER,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,229,32,39,10 + GROUPBOX "Line mode",IDC_LINEMODE,222,77,61,74 + CONTROL "Normal",IDC_LM_NORMAL,"Button",BS_AUTORADIOBUTTON | + BS_LEFT | WS_GROUP | WS_TABSTOP,233,89,38,10 + CONTROL "Doubled",IDC_LM_DOUBLED,"Button",BS_AUTORADIOBUTTON | + BS_LEFT | WS_TABSTOP,233,105,41,10 + CONTROL "Scanline",IDC_LM_SCANLINES,"Button",BS_AUTORADIOBUTTON | + BS_LEFT | WS_TABSTOP,233,121,40,10 + COMBOBOX IDC_DA_MODE,35,163,58,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | NOT WS_VISIBLE | WS_VSCROLL | + WS_TABSTOP + CONTROL "",IDC_DA_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | NOT WS_VISIBLE | WS_TABSTOP,97,159,101,20 + PUSHBUTTON "Detect pixel format",IDC_TEST16BIT,221,163,67,14,0,0, + HIDC_TEST16BIT +END + +IDD_MEMORY DIALOGEX 0, 0, 300, 175 +STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD +EXSTYLE WS_EX_CONTEXTHELP +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + GROUPBOX "Memory Settings:",-1,14,40,274,93 + RTEXT "Chip:",-1,24,60,20,10,SS_CENTERIMAGE + CONTROL "Slider1",IDC_CHIPMEM,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,54,55,50,20 + CTEXT "",IDC_CHIPRAM,104,55,35,20,SS_CENTERIMAGE | SS_SUNKEN | + WS_BORDER + RTEXT "Fast:",IDC_FASTTEXT,24,85,20,10,SS_CENTERIMAGE + CONTROL "Slider1",IDC_FASTMEM,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,54,80,50,20 + CTEXT "",IDC_FASTRAM,104,80,35,20,SS_CENTERIMAGE | SS_SUNKEN | + WS_BORDER + RTEXT "Slow:",-1,149,60,20,10,SS_CENTERIMAGE + CONTROL "Slider1",IDC_SLOWMEM,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,179,55,50,20 + CTEXT "",IDC_SLOWRAM,239,55,35,20,SS_CENTERIMAGE | SS_SUNKEN | + WS_BORDER + RTEXT "Z3-Fast:",IDC_Z3TEXT,139,85,30,10,SS_CENTERIMAGE + CONTROL "Slider1",IDC_Z3FASTMEM,"msctls_trackbar32", + TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,179,80,60,20 + CTEXT "",IDC_Z3FASTRAM,239,80,35,20,SS_CENTERIMAGE | SS_SUNKEN | + WS_BORDER + RTEXT "RTG (graphics card):",IDC_GFXCARDTEXT,96,110,76,10, + SS_CENTERIMAGE + CONTROL "Slider1",IDC_P96MEM,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,179,105,60,20 + CTEXT "",IDC_P96RAM,239,105,35,20,SS_CENTERIMAGE | SS_SUNKEN | + WS_BORDER +END + +IDD_CPU DIALOGEX 0, 0, 300, 175 +STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + GROUPBOX "CPU Type:",IDC_STATIC,5,5,80,134,BS_LEFT + CONTROL "68000",IDC_CPU0,"Button",BS_AUTORADIOBUTTON | WS_GROUP | + WS_TABSTOP,10,18,34,10 + CONTROL "68010",IDC_CPU1,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,10,33,34,10 + CONTROL "68EC020",IDC_CPU2,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,10,48,45,10 + CONTROL "68EC020+FPU",IDC_CPU3,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,10,63,63,10 + CONTROL "68020",IDC_CPU4,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,10,78,34,10 + CONTROL "68020+FPU",IDC_CPU5,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,10,93,54,10 + CONTROL "68040",IDC_CPU6,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,10,108,36,10 + CONTROL "More compatible",IDC_COMPATIBLE,"Button", + BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,10,123, + 70,10 + GROUPBOX "CPU Emulation Speed:",IDC_STATIC,90,5,205,86 + CONTROL "Fastest possible, but maintain chipset timing", + IDC_CS_HOST,"Button",BS_AUTORADIOBUTTON | BS_LEFT | + WS_GROUP | WS_TABSTOP,95,18,195,10 + CONTROL "Match A500 speed",IDC_CS_68000,"Button", + BS_AUTORADIOBUTTON | BS_LEFT | WS_TABSTOP,95,32,195,10 + CONTROL "Adjustable between CPU and chipset",IDC_CS_ADJUSTABLE, + "Button",BS_AUTORADIOBUTTON | BS_LEFT | WS_TABSTOP,95,47, + 195,10 + RTEXT "CPU",IDC_CS_CPU_TEXT,96,71,15,10,SS_CENTERIMAGE | + WS_TABSTOP + CONTROL "Slider1",IDC_SPEED,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,114,66,67,20 + LTEXT "Chipset",IDC_CS_CHIPSET_TEXT,182,71,25,10, + SS_CENTERIMAGE | NOT WS_GROUP | WS_TABSTOP + RTEXT "CPU Idle",IDC_CS_CPU_TEXT2,236,56,32,10,SS_CENTERIMAGE | + WS_TABSTOP + CONTROL "",IDC_CPUIDLE,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,219,66,69,20 + GROUPBOX "JIT Settings:",IDC_STATIC,90,94,205,76 + RTEXT "Cache Size:",IDC_CS_CACHE_TEXT,95,109,45,10, + SS_CENTERIMAGE | WS_TABSTOP + CONTROL "Slider1",IDC_CACHE,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,140,104,115,20 + EDITTEXT IDC_CACHETEXT,255,109,30,12,ES_CENTER | ES_READONLY + CONTROL "Hard Flush",IDC_HARDFLUSH,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,100,127,60,10 + CONTROL "Const Jump",IDC_CONSTJUMP,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,100,141,60,10 + CONTROL "FPU Support",IDC_JITFPU,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,100,154,60,10 + CONTROL "Force Settings",IDC_FORCE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,165,127,61,10 + CONTROL "No Flags",IDC_NOFLAGS,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,165,141,60,10 + CONTROL "Direct",IDC_TRUST0,"Button",BS_AUTORADIOBUTTON | + WS_GROUP | WS_TABSTOP,230,127,34,10 + CONTROL "Indirect",IDC_TRUST1,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,230,141,45,10 + CONTROL "After Picasso96",IDC_TRUST2,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,230,154,64,10 +END + +IDD_FLOPPY DIALOGEX 0, 0, 300, 230 +STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + RTEXT "DF0:",IDC_STATIC,16,6,20,10,SS_CENTERIMAGE + COMBOBOX IDC_DF0TEXT,2,22,296,75,CBS_DROPDOWN | CBS_AUTOHSCROLL | + WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_DF0TYPE,54,5,41,50,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + RTEXT "Write Protected",IDC_STATIC,174,8,59,10,SS_CENTERIMAGE + CONTROL "",IDC_DF0WP,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | + WS_TABSTOP,238,4,10,15 + PUSHBUTTON "Eject",IDC_EJECT0,253,4,30,15 + PUSHBUTTON "...",IDC_DF0,287,4,10,15 + RTEXT "DF1:",IDC_STATIC,16,41,20,10,SS_CENTERIMAGE + COMBOBOX IDC_DF1TEXT,2,58,296,75,CBS_DROPDOWN | CBS_AUTOHSCROLL | + WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_DF1TYPE,54,40,41,50,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + RTEXT "Write Protected",IDC_STATIC,174,42,59,10,SS_CENTERIMAGE + CONTROL "",IDC_DF1WP,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | + WS_TABSTOP,238,39,10,15 + PUSHBUTTON "Eject",IDC_EJECT1,253,39,30,15 + PUSHBUTTON "...",IDC_DF1,287,39,10,15 + RTEXT "DF2:",IDC_STATIC,16,77,20,10,SS_CENTERIMAGE + COMBOBOX IDC_DF2TEXT,2,93,296,75,CBS_DROPDOWN | CBS_AUTOHSCROLL | + WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_DF2TYPE,54,76,41,50,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + RTEXT "Write Protected",IDC_STATIC,174,77,59,10,SS_CENTERIMAGE + CONTROL "",IDC_DF2WP,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | + WS_TABSTOP,238,75,9,15 + PUSHBUTTON "Eject",IDC_EJECT2,253,75,30,15 + PUSHBUTTON "...",IDC_DF2,287,75,10,15 + RTEXT "DF3:",IDC_STATIC,16,113,20,9,SS_CENTERIMAGE + COMBOBOX IDC_DF3TEXT,2,130,296,75,CBS_DROPDOWN | CBS_AUTOHSCROLL | + WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_DF3TYPE,54,112,41,50,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + RTEXT "Write Protected",IDC_STATIC,174,113,59,10, + SS_CENTERIMAGE + CONTROL "",IDC_DF3WP,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | + WS_TABSTOP,238,111,9,15 + PUSHBUTTON "Eject",IDC_EJECT3,253,111,30,15 + PUSHBUTTON "...",IDC_DF3,287,111,10,15 + GROUPBOX "New disk image",IDC_SETTINGSTEXT,5,152,289,35 + COMBOBOX IDC_FLOPPYTYPE,16,165,51,50,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Create Standard ""Floppy""",IDC_CREATE,76,165,97,15 + PUSHBUTTON "Create Custom ""Floppy""",IDC_CREATE_RAW,183,165,101,15 + GROUPBOX "Floppy drive emulation speed",IDC_SETTINGSTEXT2,5,188, + 289,35 + CONTROL "",IDC_FLOPPYSPD,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,32,198,116,20 + EDITTEXT IDC_FLOPPYSPDTEXT,169,201,107,12,ES_CENTER | ES_READONLY +END + +IDD_HARDDISK DIALOGEX 0, 0, 300, 242 +STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD +EXSTYLE WS_EX_CONTEXTHELP +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + CONTROL "List1",IDC_VOLUMELIST,"SysListView32",LVS_REPORT | + LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | + LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,5,260,191 + PUSHBUTTON "",IDC_UP,270,52,25,15,BS_ICON + PUSHBUTTON "",IDC_DOWN,270,132,25,15,BS_ICON + PUSHBUTTON "Add &Directory...",IDC_NEW_FS,5,202,60,15 + PUSHBUTTON "Add &Hardfile...",IDC_NEW_HF,70,202,60,15 + PUSHBUTTON "Add Ha&rddrive",IDC_NEW_HD,135,202,60,15 + CONTROL "Add PC Drives at Startup",IDC_MAPDRIVES,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,5,222,105,10,0, + HIDC_MAPDRIVES + PUSHBUTTON "Remove",IDC_REMOVE,135,220,60,15 + PUSHBUTTON "&Properties",IDC_EDIT,200,220,60,15 +END + +IDD_SOUND DIALOGEX 0, 0, 300, 208 +STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + RTEXT "Sound device:",IDC_SOUNDCARD,8,9,51,13,SS_CENTERIMAGE + COMBOBOX IDC_SOUNDCARDLIST,64,9,229,50,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + GROUPBOX "Sound Emulation",IDC_SOUNDSETTINGS,7,30,120,68 + CONTROL "Disabled",IDC_SOUND0,"Button",BS_AUTORADIOBUTTON | + WS_GROUP | WS_TABSTOP,15,45,43,10 + CONTROL "Disabled, but emulated",IDC_SOUND1,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,15,57,88,10 + CONTROL "Enabled",IDC_SOUND2,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,15,69,42,10 + CONTROL "Enabled, 100% accurate",IDC_SOUND3,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,15,81,93,10 + GROUPBOX "Settings",IDC_SOUNDINTERPOLATION2,133,30,160,68 + RTEXT "Frequency:",IDC_SOUNDFREQTXT,138,40,37,8,SS_CENTERIMAGE + COMBOBOX IDC_SOUNDFREQ,140,49,67,75,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP + RTEXT "Audio filter:",IDC_SOUNDFILTERTXT,140,65,36,8, + SS_CENTERIMAGE + COMBOBOX IDC_SOUNDFILTER,140,74,67,75,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + RTEXT "Stereo mode:",IDC_SOUNDSTEREOTXT,223,40,41,8, + SS_CENTERIMAGE + COMBOBOX IDC_SOUNDSTEREO,220,49,67,75,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + RTEXT "Interpolation:",IDC_SOUNDINTERPOLATIONTXT,222,65,41,8, + SS_CENTERIMAGE + COMBOBOX IDC_SOUNDINTERPOLATION,220,74,67,75,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + GROUPBOX "Disk Drive Sound Emulation",IDC_STATIC,8,102,285,29 + COMBOBOX IDC_SOUNDDRIVE,15,113,32,75,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_SOUNDDRIVESELECT,55,113,120,75,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + CONTROL "",IDC_SOUNDDRIVEVOLUME,"msctls_trackbar32", + TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,183,109,107,19 + GROUPBOX "Sound buffer size",IDC_STATIC,7,136,120,29 + CONTROL "Slider1",IDC_SOUNDBUFFERRAM,"msctls_trackbar32", + TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,14,144,106,19 + CTEXT "",IDC_SOUNDBUFFERMEM,134,144,40,16,SS_CENTERIMAGE | + SS_SUNKEN | WS_BORDER | WS_TABSTOP + GROUPBOX "Sound driver lag compensation",IDC_STATIC,7,170,120,28 + CONTROL "Slider1",IDC_SOUNDADJUST,"msctls_trackbar32", + TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,14,178,107,19 + PUSHBUTTON "Calibrate",IDC_SOUNDCALIBRATE,183,178,40,14 + CTEXT "",IDC_SOUNDADJUSTNUM,134,178,40,16,SS_CENTERIMAGE | + SS_SUNKEN | WS_BORDER | WS_TABSTOP + GROUPBOX "Volume",IDC_STATIC,181,136,112,29 + CONTROL "",IDC_SOUNDVOLUME,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,183,144,107,19 +END + +IDD_LOADSAVE DIALOGEX 0, 0, 302, 240 +STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + CONTROL "",IDC_CONFIGTREE,"SysTreeView32",TVS_HASLINES | + TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | WS_BORDER | + WS_TABSTOP,6,4,289,155,WS_EX_CLIENTEDGE + RTEXT "Name:",IDC_STATIC,5,202,40,15,SS_CENTERIMAGE + EDITTEXT IDC_EDITNAME,50,202,155,15,ES_AUTOHSCROLL,0, + HIDC_EDITNAME + RTEXT "Path:",IDC_STATIC,5,184,39,15,SS_CENTERIMAGE + EDITTEXT IDC_EDITPATH,50,184,155,15,ES_AUTOHSCROLL | WS_DISABLED, + 0,HIDC_EDITPATH + RTEXT "Description:",IDC_STATIC,5,163,40,15,SS_CENTERIMAGE + EDITTEXT IDC_EDITDESCRIPTION,50,163,245,15,ES_AUTOHSCROLL,0, + HIDC_EDITDESCRIPTION + GROUPBOX "Extra Info",IDC_STATIC,210,179,85,38 + PUSHBUTTON "View",IDC_VIEWINFO,215,195,35,15 + PUSHBUTTON "Set",IDC_SETINFO,255,194,35,15 + PUSHBUTTON "Load",IDC_QUICKLOAD,5,222,40,15 + PUSHBUTTON "Save",IDC_QUICKSAVE,50,222,40,15 + PUSHBUTTON "Load From...",IDC_LOAD,125,222,45,15 + PUSHBUTTON "Save As...",IDC_SAVE,175,222,40,15 + PUSHBUTTON "Delete",IDC_DELETE,255,222,40,15 +END + +IDD_PORTS DIALOGEX 0, 0, 300, 202 +STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + RTEXT "Serial:",IDC_STATIC,20,15,25,15,SS_CENTERIMAGE + COMBOBOX IDC_SERIAL,50,15,95,65,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + CONTROL "Shared",IDC_SHARED,"Button",BS_AUTOCHECKBOX | + BS_VCENTER | WS_TABSTOP,33,32,37,12 + CONTROL "RTS/CTS",IDC_SER_CTSRTS,"Button",BS_AUTOCHECKBOX | + BS_VCENTER | WS_TABSTOP,77,32,44,12 + CONTROL "Direct",IDC_SERIAL_DIRECT,"Button",BS_AUTOCHECKBOX | + BS_VCENTER | WS_TABSTOP,128,32,40,12 + RTEXT "Printer:",IDC_STATIC,155,15,25,15,SS_CENTERIMAGE + COMBOBOX IDC_PRINTERLIST,185,15,95,134,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + RTEXT "Out:",IDC_MIDI,10,64,34,15,SS_CENTERIMAGE + COMBOBOX IDC_MIDIOUTLIST,50,64,95,130,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + RTEXT "In:",IDC_MIDI2,150,64,29,15,SS_CENTERIMAGE + COMBOBOX IDC_MIDIINLIST,185,64,95,134,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + GROUPBOX "Amiga Mouse Port 0",IDC_PORT0,7,92,116,100 + CONTROL "PC Joystick 0",IDC_PORT0_JOY0,"Button", + BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,20,102,90,10 + CONTROL "PC Joystick 1",IDC_PORT0_JOY1,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,20,116,90,10 + CONTROL "PC Mouse",IDC_PORT0_MOUSE,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,20,131,90,11 + CONTROL "Keyboard Layout ""A""",IDC_PORT0_KBDA,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,20,147,90,10 + CONTROL "Keyboard Layout ""B""",IDC_PORT0_KBDB,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,20,162,90,10 + CONTROL "Keyboard Layout ""C""",IDC_PORT0_KBDC,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,20,177,90,10 + GROUPBOX "Amiga Mouse Port 1",IDC_PORT1,175,92,115,100 + CONTROL "PC Joystick 0",IDC_PORT1_JOY0,"Button", + BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,190,102,90,10 + CONTROL "PC Joystick 1",IDC_PORT1_JOY1,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,190,116,90,10 + CONTROL "PC Mouse",IDC_PORT1_MOUSE,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,190,131,90,11 + CONTROL "Keyboard Layout ""A""",IDC_PORT1_KBDA,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,190,147,90,10 + CONTROL "Keyboard Layout ""B""",IDC_PORT1_KBDB,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,190,162,90,10 + CONTROL "Keyboard Layout ""C""",IDC_PORT1_KBDC,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,190,177,90,10 + PUSHBUTTON "<-swap->",IDC_SWAP,130,132,40,14 + GROUPBOX "MIDI",IDC_MIDIFRAME,7,51,284,36 + GROUPBOX "Serial and Parallel",IDC_SERPARFRAME,7,3,284,45 +END + +IDD_CONTRIBUTORS DIALOGEX 0, 0, 411, 242 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | WS_POPUP | + WS_VISIBLE | WS_CAPTION +CAPTION "UAE Authors and Contributors..." +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "Ok",ID_OK,177,219,53,14 + CONTROL "",IDC_CONTRIBUTORS,"RICHEDIT",TCS_HOTTRACK | + TCS_VERTICAL | TCS_RAGGEDRIGHT | TCS_OWNERDRAWFIXED | + TCS_MULTISELECT | WS_BORDER | WS_VSCROLL | WS_HSCROLL | + WS_TABSTOP,4,5,404,206 +END + +IDD_ABOUT DIALOGEX 0, 0, 300, 175 +STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + CONTROL "",IDC_RICHEDIT1,"RICHEDIT",TCS_SCROLLOPPOSITE | + TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,45,10, + 210,15 + CONTROL "",IDC_RICHEDIT2,"RICHEDIT",TCS_SCROLLOPPOSITE | + TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,20,30, + 260,13 + PUSHBUTTON "Contributors",IDC_CONTRIBUTORS,110,55,80,15 + CONTROL "",IDC_CLOANTOHOME,"RICHEDIT",TCS_SCROLLOPPOSITE | + TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,20,90,80, + 20 + CONTROL "",IDC_UAEHOME,"RICHEDIT",TCS_SCROLLOPPOSITE | + TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,20,120, + 80,15 + CONTROL "",IDC_PICASSOHOME,"RICHEDIT",TCS_SCROLLOPPOSITE | + TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,200,90, + 80,20 + CONTROL "",IDC_AMIGAHOME,"RICHEDIT",TCS_SCROLLOPPOSITE | + TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,110,90, + 80,15 + CONTROL "",IDC_WINUAEHOME,"RICHEDIT",TCS_SCROLLOPPOSITE | + TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,200,120, + 80,15 + CONTROL "",IDC_AIABHOME,"RICHEDIT",TCS_SCROLLOPPOSITE | + TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,110,120, + 80,15 + CONTROL "",IDC_THEROOTS,"RICHEDIT",TCS_SCROLLOPPOSITE | + TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,33,143, + 110,15 + CONTROL "",IDC_CAPS,"RICHEDIT",TCS_SCROLLOPPOSITE | + TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,150,143, + 110,15 +END + +IDD_MISC1 DIALOGEX 0, 0, 300, 223 +STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + GROUPBOX "Advanced:",IDC_STATIC,8,4,285,90 + CONTROL "Middle-Mouse-Button --> ALT-TAB",IDC_JULIAN,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,29,15,120,10 + CONTROL "Show GUI on startup",IDC_SHOWGUI,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,29,30,120,10 + CONTROL "On-Screen LEDs",IDC_SHOWLEDS,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,29,45,115,10 + CONTROL "UAEscsi.device",IDC_SCSIDEVICE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,29,60,117,10 + CONTROL "BSDsocket.library emulation",IDC_SOCKETS,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,159,15,120,10 + CONTROL "Use CTRL-F11 to quit",IDC_CTRLF11,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,159,30,120,10 + CONTROL "Don't use RGB overlays",IDC_NOOVERLAY,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,159,45,120,10 + CONTROL "Use ASPI SCSI layer",IDC_ASPI,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,159,60,115,10 + GROUPBOX "Keyboard LEDs:",IDC_STATIC,7,99,85,73 + COMBOBOX IDC_KBLED1,22,112,56,65,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + COMBOBOX IDC_KBLED2,22,131,56,65,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + COMBOBOX IDC_KBLED3,22,151,56,65,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + GROUPBOX "Logging:",IDC_STATIC,97,99,195,25 + CONTROL "Create log file",IDC_CREATELOGFILE,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,107,109,72,10,0, + HIDC_CREATELOGFILE + CONTROL "Illegal mem accesses",IDC_ILLEGAL,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,189,109,80,10 + GROUPBOX "State files:",IDC_STATIC,98,126,195,76 + PUSHBUTTON "Load state...",IDC_DOLOADSTATE,105,143,49,14 + PUSHBUTTON "Save state...",IDC_DOSAVESTATE,106,169,49,14 + CONTROL "Enable state recording",IDC_STATE_CAPTURE,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,188,142,88,10 + RTEXT "Recording rate (seconds)",IDC_STATE_RATE_TEXT,157,160, + 86,10,SS_CENTERIMAGE | WS_TABSTOP + COMBOBOX IDC_STATE_RATE,248,158,38,65,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP + RTEXT "Recording buffer (MB)",IDC_STATE_BUFFERSIZE_TEXT,157, + 180,83,10,SS_CENTERIMAGE | WS_TABSTOP + COMBOBOX IDC_STATE_BUFFERSIZE,248,178,38,65,CBS_DROPDOWN | + WS_VSCROLL | WS_TABSTOP + CONTROL "Disable UAEFSDB-support",IDC_NOUAEFSDB,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,29,76,115,10 +END + +IDD_HARDFILE DIALOGEX 0, 0, 229, 164 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | + DS_CENTERMOUSE | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Volume Settings" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + GROUPBOX "Hard File Settings",IDC_STATIC,10,5,210,90 + RTEXT "Path:",IDC_HARDFILE_DIR_TEXT,19,21,22,10 + EDITTEXT IDC_PATH_NAME,44,15,151,15,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_SELECTOR,200,15,11,15 + RTEXT "FileSys:",IDC_HARDFILE_FILESYS_TEXT,16,36,26,10 + EDITTEXT IDC_PATH_FILESYS,44,34,89,15,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_FILESYS_SELECTOR,139,34,11,15 + CONTROL "Read/Write",IDC_RW,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,160,37,50,10 + RTEXT "Device:",IDC_HARDFILE_DEVICE_TEXT,16,58,25,10 + EDITTEXT IDC_HARDFILE_DEVICE,44,54,32,15,ES_AUTOHSCROLL + RTEXT "Surfaces:",IDC_SURFACES_TEXT,75,58,35,10 + EDITTEXT IDC_HEADS,115,54,27,15,ES_NUMBER + RTEXT "Reserved:",IDC_RESERVED_TEXT,145,58,35,10 + EDITTEXT IDC_RESERVED,185,54,27,15,ES_NUMBER + RTEXT "BootPri:",IDC_HARDFILE_BOOTPRI_TEXT,11,80,30,8 + EDITTEXT IDC_HARDFILE_BOOTPRI,44,75,32,15 + RTEXT "Sectors:",IDC_SECTORS_TEXT,80,80,30,10 + EDITTEXT IDC_SECTORS,115,75,27,15,ES_NUMBER + RTEXT "Block-Size:",IDC_BLOCKSIZE_TEXT,145,80,35,10 + EDITTEXT IDC_BLOCKSIZE,185,75,27,15,ES_NUMBER + GROUPBOX "New Hard File",IDC_STATIC,10,100,210,35 + PUSHBUTTON "Create",IDC_CREATEHF,20,115,85,14 + EDITTEXT IDC_HFSIZE,110,115,60,15,ES_NUMBER + LTEXT "MB",IDC_RESERVED_TEXT2,174,118,39,9,NOT WS_GROUP + PUSHBUTTON "OK",IDOK,115,143,50,14 + PUSHBUTTON "Cancel",IDCANCEL,171,143,50,14 +END + +IDD_FILESYS DIALOGEX 15, 25, 229, 111 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | + DS_CENTERMOUSE | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Volume Settings" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + LTEXT "Device Name:",-1,5,9,54,10 + EDITTEXT IDC_VOLUME_DEVICE,65,5,85,15,ES_AUTOHSCROLL + LTEXT "Volume Label:",-1,5,31,54,10 + EDITTEXT IDC_VOLUME_NAME,65,25,85,15,ES_AUTOHSCROLL + LTEXT "Path:",-1,5,51,44,10 + EDITTEXT IDC_PATH_NAME,65,46,139,15,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_SELECTOR,210,46,10,15 + CONTROL "Read/Write",IDC_RW,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,5,70,50,10 + RTEXT "BootPri:",IDC_VOLUME_BOOTPRI_TEXT,68,70,30,8 + EDITTEXT IDC_VOLUME_BOOTPRI,106,68,27,15 + PUSHBUTTON "OK",IDOK,120,91,48,15 + PUSHBUTTON "Cancel",IDCANCEL,175,91,48,15 +END + +IDD_SETINFO DIALOGEX 0, 0, 229, 85 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | + DS_CENTERMOUSE | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Info Settings" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + RTEXT "Path:",-1,5,20,24,15,SS_CENTERIMAGE + EDITTEXT IDC_PATH_NAME,35,20,169,15,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_SELECTOR,210,20,10,15 + PUSHBUTTON "OK",IDOK,120,65,48,15 + PUSHBUTTON "Cancel",IDCANCEL,175,65,48,15 +END + +IDD_CHIPSET DIALOGEX 0, 65490, 300, 229 +STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + GROUPBOX "Chipset type",IDC_STATIC,14,11,145,82 + CONTROL "OCS",IDC_OCS,"Button",BS_AUTORADIOBUTTON | WS_GROUP | + WS_TABSTOP,38,31,30,10 + CONTROL "ECS Agnus",IDC_ECS_AGNUS,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,38,47,50,10 + CONTROL "ECS Denise",IDC_ECS_DENISE,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,38,63,50,10 + CONTROL "Full ECS",IDC_ECS,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,102,31,42,10 + CONTROL "AGA",IDC_AGA,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP, + 102,47,30,10 + CONTROL "NTSC",IDC_NTSC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 102,64,35,10 + GROUPBOX "Misc chipset options",IDC_STATIC,168,11,114,82 + CONTROL "Fast Copper",IDC_FASTCOPPER,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,174,31,53,10 + CONTROL "Immediate Blitter",IDC_BLITIMM,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,174,47,75,10 + CONTROL "Cycle exact CPU and Blitter",IDC_CYCLEEXACT,"Button", + BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,174,64, + 100,10 + GROUPBOX "Collision level",IDC_STATIC,14,97,267,48 + CONTROL "None",IDC_COLLISION0,"Button",BS_AUTORADIOBUTTON | + WS_GROUP | WS_TABSTOP,40,113,50,10 + CONTROL "Sprites only",IDC_COLLISION1,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,39,129,50,10 + CONTROL "Sprites and Sprites vs. Playfield",IDC_COLLISION2, + "Button",BS_AUTORADIOBUTTON | WS_TABSTOP,104,113,114,10 + CONTROL "Full",IDC_COLLISION3,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,104,129,27,10 + GROUPBOX "Sound emulation",IDC_STATIC,13,150,268,65 + CONTROL "Disabled",IDC_CS_SOUND0,"Button",BS_AUTORADIOBUTTON | + WS_GROUP | WS_TABSTOP,39,167,102,10 + CONTROL "Emulated",IDC_CS_SOUND1,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,39,182,91,10 + CONTROL "Emulated, 100% accurate",IDC_CS_SOUND2,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,39,197,95,10 +END + +IDD_AVIOUTPUT DIALOGEX 0, 0, 198, 188 +STYLE DS_SETFONT | DS_CONTROL | WS_CHILD +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + GROUPBOX "Output Properties:",IDC_STATIC,5,8,184,96 + EDITTEXT IDC_AVIOUTPUT_FILETEXT,26,21,120,12,ES_AUTOHSCROLL | + ES_READONLY | NOT WS_BORDER,WS_EX_CLIENTEDGE + PUSHBUTTON "...",IDC_AVIOUTPUT_FILE,148,21,19,12 + CONTROL "Audio",IDC_AVIOUTPUT_AUDIO,"Button",BS_AUTOCHECKBOX | + BS_PUSHLIKE | BS_FLAT | WS_TABSTOP,26,36,32,11 + CONTROL "",IDC_AVIOUTPUT_AUDIO_STATIC,"Static",SS_LEFTNOWORDWRAP | + SS_CENTERIMAGE | SS_SUNKEN | WS_GROUP,60,36,107,11 + CONTROL "Video",IDC_AVIOUTPUT_VIDEO,"Button",BS_AUTOCHECKBOX | + BS_PUSHLIKE | BS_FLAT | WS_TABSTOP,26,50,32,11 + CONTROL "",IDC_AVIOUTPUT_VIDEO_STATIC,"Static",SS_LEFTNOWORDWRAP | + SS_CENTERIMAGE | SS_SUNKEN | WS_GROUP,60,50,107,11 + CONTROL "Disable frame rate limit while recording", + IDC_AVIOUTPUT_FRAMELIMITER,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,28,68,142,10 + CONTROL "AVIOutput enabled",IDC_AVIOUTPUT_ACTIVATED,"Button", + BS_AUTORADIOBUTTON | BS_PUSHLIKE | BS_FLAT,26,83,142,12 + GROUPBOX "Playback Rate:",IDC_STATIC,5,107,184,50 + CONTROL "PAL",IDC_AVIOUTPUT_PAL,"Button",BS_AUTORADIOBUTTON | + BS_PUSHLIKE | BS_FLAT,24,124,66,8 + CONTROL "NTSC",IDC_AVIOUTPUT_NTSC,"Button",BS_AUTORADIOBUTTON | + BS_PUSHLIKE | BS_FLAT,95,124,66,8 + CONTROL "Slider1",IDC_AVIOUTPUT_FPS,"msctls_trackbar32",TBS_BOTH | + TBS_NOTICKS | TBS_ENABLESELRANGE | WS_TABSTOP,21,137,120, + 11 + LTEXT "fps",IDC_AVIOUTPUT_FPS_STATIC,141,136,23,8 + PUSHBUTTON "Save Screenshot",IDC_SCREENSHOT,46,167,95,12 +END + +IDD_INPUT DIALOGEX 0, 0, 300, 242 +STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + COMBOBOX IDC_INPUTTYPE,5,5,98,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_INPUTDEVICE,109,4,167,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + CONTROL "",IDC_INPUTDEVICEDISABLE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,282,7,9,8 + CONTROL "List1",IDC_INPUTLIST,"SysListView32",LVS_REPORT | + LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | + LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,22,290,146 + COMBOBOX IDC_INPUTAMIGACNT,5,174,24,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_INPUTAMIGA,33,174,262,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + RTEXT "Joystick dead zone (%):",-1,8,196,76,10,SS_CENTERIMAGE + EDITTEXT IDC_INPUTDEADZONE,89,195,25,12,ES_NUMBER + RTEXT "Autofire rate (frames):",-1,9,212,68,10,SS_CENTERIMAGE + EDITTEXT IDC_INPUTAUTOFIRERATE,89,210,25,12,ES_NUMBER + RTEXT "Digital joy-mouse speed:",-1,121,196,76,10, + SS_CENTERIMAGE + EDITTEXT IDC_INPUTSPEEDD,207,195,25,12,ES_NUMBER + RTEXT "Analog joy-mouse speed:",-1,120,212,80,10, + SS_CENTERIMAGE + EDITTEXT IDC_INPUTSPEEDA,207,211,25,12,ES_NUMBER + RTEXT "Mouse speed:",-1,132,228,68,10,SS_CENTERIMAGE + EDITTEXT IDC_INPUTSPEEDM,207,227,25,12,ES_NUMBER + PUSHBUTTON "Copy from:",IDC_INPUTCOPY,249,195,45,14 + COMBOBOX IDC_INPUTCOPYFROM,249,211,45,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Swap 1<>2",IDC_INPUTSWAP,249,226,45,14 +END + +IDD_OPENGL DIALOGEX 0, 0, 300, 193 +STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + GROUPBOX "Filter settings:",-1,8,5,285,180 + CONTROL "Enable",IDC_OPENGLENABLE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,26,23,38,10 + COMBOBOX IDC_OPENGLMODE,67,21,56,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_OPENGLFILTER,128,21,65,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Reset to defaults",IDC_OPENGLDEFAULT,197,21,73,14 + RTEXT "Horizontal Size",-1,25,52,57,10,SS_CENTERIMAGE + CONTROL "Slider1",IDC_OPENGLHZ,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,89,45,158,19 + CTEXT "",IDC_OPENGLHZV,249,47,21,16,SS_CENTERIMAGE | SS_SUNKEN | + WS_BORDER | WS_TABSTOP + RTEXT "Vertical Size",-1,26,72,57,10,SS_CENTERIMAGE + CONTROL "Slider1",IDC_OPENGLVZ,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,89,65,157,19 + CTEXT "",IDC_OPENGLVZV,249,67,21,16,SS_CENTERIMAGE | SS_SUNKEN | + WS_BORDER | WS_TABSTOP + RTEXT "Horizontal Position",-1,26,92,57,10,SS_CENTERIMAGE + CONTROL "Slider1",IDC_OPENGLHO,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,89,85,157,19 + CTEXT "",IDC_OPENGLHOV,249,87,21,16,SS_CENTERIMAGE | SS_SUNKEN | + WS_BORDER | WS_TABSTOP + RTEXT "Vertical Position",-1,26,111,57,10,SS_CENTERIMAGE + CONTROL "Slider1",IDC_OPENGLVO,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,89,105,157,19 + CTEXT "",IDC_OPENGLVOV,249,107,21,16,SS_CENTERIMAGE | + SS_SUNKEN | WS_BORDER | WS_TABSTOP + RTEXT "Scanlines",-1,27,141,57,10,SS_CENTERIMAGE + CONTROL "Slider1",IDC_OPENGLSL,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,89,134,157,19 + CTEXT "",IDC_OPENGLSLV,249,135,21,16,SS_CENTERIMAGE | + SS_SUNKEN | WS_BORDER | WS_TABSTOP + COMBOBOX IDC_OPENGLSLR,56,154,27,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + CONTROL "Slider1",IDC_OPENGLSL2,"msctls_trackbar32", + TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,89,154,157,19 + CTEXT "",IDC_OPENGLSL2V,249,154,21,16,SS_CENTERIMAGE | + SS_SUNKEN | WS_BORDER | WS_TABSTOP +END + +IDD_HARDDRIVE DIALOGEX 0, 0, 229, 66 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | + DS_CENTERMOUSE | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Harddrive Settings" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + LTEXT "Harddrive:",-1,7,11,35,10 + COMBOBOX IDC_HARDDRIVE,49,9,173,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + CONTROL "Read/Write",IDC_RW,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,15,30,50,10 + DEFPUSHBUTTON "OK",IDOK,116,47,50,14 + PUSHBUTTON "Cancel",IDCANCEL,172,47,50,14 +END + +IDD_MISC2 DIALOGEX 0, 0, 300, 92 +STYLE DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + GROUPBOX "When Active:",IDC_STATIC,8,7,88,73 + RTEXT "Run at priority:",IDC_ACTIVE_PRI,14,17,45,10, + SS_CENTERIMAGE | WS_TABSTOP + COMBOBOX IDC_ACTIVE_PRIORITY,14,29,76,65,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + GROUPBOX "When Inactive:",IDC_STATIC,102,7,92,73 + RTEXT "Run at priority:",IDC_INACTIVE_PRI,109,17,45,10, + SS_CENTERIMAGE | WS_TABSTOP + COMBOBOX IDC_INACTIVE_PRIORITY,109,29,76,65,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + CONTROL "Pause emulation",IDC_INACTIVE_PAUSE,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,109,50,69,10 + CONTROL "Disable sound output",IDC_INACTIVE_NOSOUND,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,109,63,79,10 + GROUPBOX "When Minimized:",IDC_STATIC,199,7,92,73 + RTEXT "Run at priority:",IDC_MINIMIZED_PRI,207,18,45,10, + SS_CENTERIMAGE | WS_TABSTOP + COMBOBOX IDC_MINIMIZED_PRIORITY,207,30,76,65,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + CONTROL "Pause emulation",IDC_MINIMIZED_PAUSE,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,207,50,69,10 + CONTROL "Disable sound output",IDC_MINIMIZED_NOSOUND,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,207,63,79,10 +END + +IDD_DISK DIALOGEX 0, 0, 300, 242 +STYLE DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_CONTROL | DS_CENTER | + DS_CENTERMOUSE | WS_CHILD +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + CONTROL "",IDC_DISKLIST,"SysListView32",LVS_REPORT | + LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | + LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,4,6,262,211 + PUSHBUTTON "Remove disk image",IDC_DISKLISTREMOVE,94,222,93,15 + PUSHBUTTON "",IDC_UP,270,66,25,15,BS_ICON + PUSHBUTTON "",IDC_DOWN,270,146,25,15,BS_ICON +END + +IDD_PANEL DIALOGEX 0, 0, 420, 278 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +EXSTYLE WS_EX_ACCEPTFILES | WS_EX_CONTROLPARENT +CAPTION "WinUAE Properties" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_PANELTREE,"SysTreeView32",TVS_HASLINES | + TVS_SHOWSELALWAYS | TVS_NOSCROLL | WS_BORDER | + WS_TABSTOP,5,5,101,248,WS_EX_CLIENTEDGE + GROUPBOX "",IDC_PANEL_FRAME_OUTER,110,2,307,251 + DEFPUSHBUTTON "OK",IDOK,260,259,50,14 + PUSHBUTTON "Cancel",IDCANCEL,313,259,50,14 + PUSHBUTTON "Help",IDHELP,366,259,50,14,WS_DISABLED + PUSHBUTTON "Reset",IDC_RESETAMIGA,6,259,47,14 + PUSHBUTTON "Quit",IDC_QUITEMU,57,259,47,14 + GROUPBOX "",IDC_PANEL_FRAME,112,4,303,247,NOT WS_VISIBLE +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "#include ""dlgs.h""\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APPICON ICON "winuae.ico" +IDI_FLOPPY ICON "35floppy.ico" +IDI_ABOUT ICON "amigainfo.ico" +IDI_HARDDISK ICON "Drive.ico" +IDI_CPU ICON "cpu.ico" +IDI_PORTS ICON "joystick.ico" +IDI_INPUT ICON "joystick.ico" +IDI_MISC1 ICON "misc.ico" +IDI_MISC2 ICON "misc.ico" +IDI_MOVE_UP ICON "move_up.ico" +IDI_MOVE_DOWN ICON "move_dow.ico" +IDI_AVIOUTPUT ICON "avioutput.ico" +IDI_DISK ICON "Drive.ico" +IDI_CONFIGFILE ICON "file.ico" +IDI_FOLDER ICON "folder.ico" +IDI_SOUND ICON "sound.ico" +IDI_DISPLAY ICON "screen.ico" +IDI_ROOT ICON "root.ico" +IDI_MEMORY ICON "chip.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,8,26,0 + PRODUCTVERSION 0,8,26,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "WinUAE" + VALUE "FileVersion", "0.8.26" + VALUE "InternalName", "WinUAE" + VALUE "LegalCopyright", "© 1996-2004 under the GNU Public License (GPL)" + VALUE "OriginalFilename", "WinUAE.exe" + VALUE "ProductName", "WinUAE" + VALUE "ProductVersion", "0.8.26" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Cursor +// + +IDC_MYHAND CURSOR "H_arrow.cur" + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_DISPLAY, DIALOG + BEGIN + BOTTOMMARGIN, 175 + END + + IDD_FLOPPY, DIALOG + BEGIN + BOTTOMMARGIN, 175 + END + + IDD_HARDDISK, DIALOG + BEGIN + BOTTOMMARGIN, 175 + END + + IDD_SOUND, DIALOG + BEGIN + BOTTOMMARGIN, 206 + END + + IDD_PORTS, DIALOG + BEGIN + BOTTOMMARGIN, 175 + END + + IDD_CONTRIBUTORS, DIALOG + BEGIN + RIGHTMARGIN, 370 + BOTTOMMARGIN, 212 + END + + IDD_MISC1, DIALOG + BEGIN + BOTTOMMARGIN, 215 + END + + IDD_CHIPSET, DIALOG + BEGIN + BOTTOMMARGIN, 215 + END + + IDD_AVIOUTPUT, DIALOG + BEGIN + RIGHTMARGIN, 164 + BOTTOMMARGIN, 187 + END + + IDD_INPUT, DIALOG + BEGIN + BOTTOMMARGIN, 187 + END + + IDD_OPENGL, DIALOG + BEGIN + BOTTOMMARGIN, 175 + END + + IDD_DISK, DIALOG + BEGIN + BOTTOMMARGIN, 193 + END + + IDD_PANEL, DIALOG + BEGIN + LEFTMARGIN, 7 + TOPMARGIN, 7 + HORZGUIDE, 241 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDM_SYSTRAY MENU +BEGIN + POPUP "Menu" + BEGIN + MENUITEM "Configuration", ID_ST_CONFIGURATION + POPUP "Floppy Drives" + BEGIN + MENUITEM "Eject all drives", ID_ST_EJECTALL + MENUITEM "DF0:", 40014 + MENUITEM "DF1:", ID_ST_DF1 + MENUITEM "DF2:", ID_ST_DF2 + MENUITEM "DF3:", ID_ST_DF3 + END + MENUITEM "Reset", ID_ST_RESET + MENUITEM "Help", ID_ST_HELP + MENUITEM "Quit WinUAE", ID_ST_QUIT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// WAVE +// + +IDR_DRIVE_STARTUP_A500_1 WAVE "drive_startup.wav" +IDR_DRIVE_CLICK_A500_1 WAVE "drive_click.wav" +IDR_DRIVE_SPIN_A500_1 WAVE "drive_spin.wav" +IDR_DRIVE_SNATCH_A500_1 WAVE "drive_snatch.wav" +IDR_DRIVE_SPINND_A500_1 WAVE "drive_spinnd.wav" + +///////////////////////////////////////////////////////////////////////////// +// +// RT_MANIFEST +// + +1 RT_MANIFEST "winuae.exe.manifest" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_KICKSTART "ROM" + IDS_DISK "Disk Swapper" + IDS_DISPLAY "Display" + IDS_HARDDISK "Hard Drives" + IDS_FLOPPY "Disk Drives" + IDS_ABOUT "About" + IDS_LOADSAVE "Configurations" + IDS_AVIOUTPUT "Output" + IDS_PORTS "Game & I/O Ports" + IDS_MISC1 "Misc" + IDS_MEMORY "RAM" + IDS_CPU "CPU" + IDS_CHIPSET "Chipset" + IDS_INPUT "Input" + IDS_OPENGL "Filter" +END + +STRINGTABLE +BEGIN + IDS_MISC2 "Priority" +END + +STRINGTABLE +BEGIN + IDS_EXTTEXT "Amiga Disk Files" + IDS_EXTACTUAL "ADF" + IDS_SOUND "Sound" + IDS_CDROM "CD-ROM" + IDS_FRAMERATE "Every %1Frame" + IDS_SECOND "second " + IDS_THIRD "third " + IDS_FOURTH "fourth " + IDS_FIFTH "fifth " + IDS_SIXTH "sixth " + IDS_SEVENTH "seventh " + IDS_EIGHTH "eighth " +END + +STRINGTABLE +BEGIN + IDS_NINTH "ninth " + IDS_TENTH "tenth " + IDS_SELECTADF "Select an Amiga Disk File image..." + IDS_ADF "Amiga Disk Files" + IDS_CHOOSEBLANK "Choose your blank Amiga Disk File..." + IDS_SELECTHDF "Select a Hard Disk File..." + IDS_HDF "Hard Disk Files" + IDS_SELECTUAE "Select a UAE Config-File..." + IDS_UAE "UAE Config Files" + IDS_SELECTROM "Select an Amiga ROM file..." + IDS_ROM "Amiga Kickstart Files" + IDS_SELECTKEY "Select an Amiga Key-File..." + IDS_KEY "Amiga Kickstart Key-Files" + IDS_SELECTINFO "Select information for your config..." + IDS_NONE "none" + IDS_VOLUME "Volume" +END + +STRINGTABLE +BEGIN + IDS_SELECTFILESYSROOT "Please select your file-system root directory..." + IDS_DEFAULTMIDIOUT "Default MIDI-Out Device" + IDS_CONTRIBUTORS1 "Bernd Schmidt - The Grand-Master\nSam Jordan - Custom-chip, floppy-DMA, etc.\nMathias Ortmann - Original WinUAE Main Guy, BSD Socket support\nBrian King - Picasso96 Support, Integrated GUI for WinUAE, previous WinUAE Main Guy\nToni Wilen - Core updates, WinUAE Main Guy\nGustavo Goedert/Peter Remmers/Michael Sontheimer/Tomi Hakala/Tim Gunn/Nemo Pohle - DOS Port Stuff\nSamuel Devulder/Olaf Barthel/Sam Jordan - Amiga Ports\nKrister Bergman - XFree86 and OS/2 Port\nA. Blanchard/Ernesto Corvi - MacOS Port\nChristian Bauer - BeOS Port\nIan Stephenson - NextStep Port\nPeter Teichmann - Acorn/RiscOS Port\nStefan Reinauer - ZorroII/III AutoConfig, Serial Support\nChristian Schmitt/Chris Hames - Serial Support\nHerman ten Brugge - 68020/68881 Emulation Code\nTauno Taipaleenmaki - Various UAE-Control/UAE-Library Support\nBrett Eden/Tim Gunn/Paolo Besser/Nemo Pohle - Various Docs and Web-Sites\nGeorg Veichtlbauer - Help File coordinator, German GUI\nFulvio Leonardi - Italian translator for WinUAE\n" + IDS_CONTRIBUTORS2 "Special thanks to Alexander Kneer and Tobias Abt (The Picasso96 Team)\n" + IDS_INVALIDPRTPORT "The printer you have in this configuration is not valid on this machine.\n" + IDS_RESTOREUSS "Restore a UAE Snap-Shot File" + IDS_USS "UAE Snap-Shot Files" + IDS_WRONGOSVERSION "WinUAE is no longer supported on Windows NT. Please upgrade to either Windows 2000 or Windows XP." + IDS_SELECTFLASH "Select a flash/battery backed RAM file..." + IDS_FLASH "UAE flash/battery backed RAM file" + IDS_INPUTHOSTWIDGET "Input Source" + IDS_INPUTAMIGAEVENT "Input Target" + IDS_INPUTAUTOFIRE "Autofire" + IDS_SAVEUSS "Save a UAE Snap-Shot File" + IDS_MIDIOVERFLOW "Sysexbuffer overflow. Should not happen. Please report this to\nberndroesch1@compuserve.de" +END + +STRINGTABLE +BEGIN + IDS_PATH "Path" + IDS_RW "R/W" + IDS_SECTORS "Sectors" + IDS_SURFACES "Surfaces" + IDS_RESERVED "Reserved" + IDS_BLOCKSIZE "Block Size" + IDS_NAME "Name" + IDS_DESCRIPTION "Description" + IDS_ONEINSTANCE "Only one instance of WinUAE can run at a time.\n" + IDS_INSTALLDIRECTX "You have to install DirectX on your system before you can use UAE.\nRefer to the documentation for further details.\n" + IDS_REGKEYCREATEFAILED "WinUAE could not create Registry keys! You need administrator privileges.\n" + IDS_COULDNOTLOADCONFIG "Could not load selected configuration!\n" + IDS_NOHELP "Online help is disabled, because you have not installed the HtmlHelp system. Go to http://msdn.microsoft.com/library/tools/htmlhelp/wkshp/download.htm to get HtmlHelp.\n" + IDS_MUSTSELECTCONFIG "You must select a configuration or enter a name before selecting Load...\n" + IDS_INVALIDCOMPORT "The COM-port you have in this configuration is not valid on this machine.\n" +END + +STRINGTABLE +BEGIN + IDS_HFDSIZE "Size" + IDS_DEVICE "Device" + IDS_BOOTPRI "BootPri" + IDS_WRONGDXVERSION "WinUAE requires DirectX 8 or newer." +END + +STRINGTABLE +BEGIN + IDS_WSOCK2NEEDED "Please upgrade to Winsock2.\n" + IDS_UNSUPPORTEDPIXELFORMAT + "Error: Unsupported pixel format - use a different screen mode\n" + IDS_MUSTENTERNAME "You must select a configuration or enter a name before selecting Save...\n" + IDS_MUSTSELECTCONFIGFORDELETE + "You must select a configuration or enter a name before selecting Delete...\n" + IDS_DELETECONFIGCONFIRMATION + "Are you sure you want to Delete this configuration?\n" + IDS_DELETECONFIGTITLE "Confirm Delete" + IDS_GFXCARDCHECK "WinUAE will now determine your graphic-card's 16-bit pixel format.\nYour screen will go black for two seconds, with a resolution of 640x480 @ 60Hz.\nThis procedure is necessary to properly display your Amiga software on 16-bit\ndisplay-modes, and should be done whenever you run WinUAE for the first time, or\ninstall a new graphics-card in your PC. Proceed with this test?\n" + IDS_GFXCARDTITLE "Pixel Format Detection" + IDS_MUSTSELECTPATH "You must select a path!" + IDS_SETTINGSERROR "Settings Error" + IDS_MUSTSELECTNAME "You must select a name for the volume!" + IDS_MUSTSELECTFILE "You must select a file!" + IDS_FAILEDHARDFILECREATION "Failed to create hard-file..." + IDS_CREATIONERROR "Creation Error" + IDS_ERRORTITLE "WinUAE Message" +END + +STRINGTABLE +BEGIN + IDS_SOUND_MONO "Mono" + IDS_SOUND_MIXED "Mixed" + IDS_SOUND_STEREO "Stereo" + IDS_SOUND_INTERPOL_DISABLED "Disabled" + IDS_SOUND_INTERPOL_RH "RH" + IDS_SOUND_INTERPOL_CRUX "Crux" + IDS_SOUND_FILTER_OFF "Always off" + IDS_SOUND_FILTER_EMULATED "Emulated" +END + +STRINGTABLE +BEGIN + IDS_SOUND_FILTER_ON "Always on" + IDS_INPUT_COMPATIBILITY "Compatibility mode" + IDS_INPUT_CUSTOM "Configuration #%d" + IDS_INPUT_COPY_DEFAULT "Default" + IDS_INPUT_COPY_CUSTOM "Config #%d" + IDS_3D_NO_FILTER "Point (%d-bit)" + IDS_3D_BILINEAR "Bilinear (%d-bit)" + IDS_VSYNC_DEFAULT "Default" + IDS_DRIVESOUND_NONE "No sound" + IDS_DRIVESOUND_DEFAULT_A500 "A500 (WinUAE built-in)" + IDS_AVIOUTPUT_NOCODEC "no codec selected" + IDS_DISK_IMAGENAME "Disk image" + IDS_DISK_DRIVENAME "Drive" + IDS_AGA8BIT "AGA emulation requires 16 bit or higher display depth\nSwitching from 8-bit to 16-bit" + IDS_UNSUPPORTEDSCREENMODE + "The selected screen mode can't be displayed in a window, because %s\nSwitching to full-screen display." + IDS_UNSUPPORTEDSCREENMODE_1 + "the desktop is running in an unknown color mode." +END + +STRINGTABLE +BEGIN + IDS_UNSUPPORTEDSCREENMODE_2 + "the desktop is running in 8 bit color depth, which UAE can't use in windowed mode." + IDS_UNSUPPORTEDSCREENMODE_3 + "the desktop is too small for the specified window size" + IDS_UNSUPPORTEDSCREENMODE_4 + "you selected a Picasso96 display with a color depth different from that of the desktop and an overlay was unavailable." + IDS_FLOPPYTYPE35DD "3.5"" DD" + IDS_FLOPPYTYPE35HD "3.5"" HD" + IDS_FLOPPYTYPE525SD "5.25"" SD" + IDS_FLOPPYTYPEDISABLED "Disabled" + IDS_STMENUNOFLOPPY "No disk inserted" + IDS_TREEVIEW_HARDWARE "Hardware" + IDS_TREEVIEW_HOST "Host" + IDS_TREEVIEW_MISC "Misc" + IDS_TREEVIEW_SETTINGS "Settings" + IDS_WINUAETITLE_MMB "[Mouse active - press Alt-Tab or middle-button to cancel]" + IDS_WINUAETITLE_NORMAL "[Mouse active - press Alt-Tab to cancel]" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/od-win32/resources/winuae_minimal.rc b/od-win32/resources/winuae_minimal.rc new file mode 100755 index 00000000..73b1b104 --- /dev/null +++ b/od-win32/resources/winuae_minimal.rc @@ -0,0 +1,1136 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +// Generated Help ID header file +#define APSTUDIO_HIDDEN_SYMBOLS +#include "resource.hm" +#undef APSTUDIO_HIDDEN_SYMBOLS + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" +#include "dlgs.h" +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_KICKSTART DIALOGEX 0, 0, 300, 175 +STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CAPTION +EXSTYLE WS_EX_CONTEXTHELP +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + GROUPBOX "Boot-ROM Settings:",-1,5,12,290,90 + RTEXT "ROM File:",IDC_ROMTEXT,10,27,75,10 + EDITTEXT IDC_ROMFILE,90,22,185,15,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_KICKCHOOSER,280,22,10,15 + RTEXT "Key File:",IDC_KEYTEXT,10,48,75,10 + EDITTEXT IDC_KEYFILE,90,43,185,15,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_KEYCHOOSER,280,43,10,15 + RTEXT "Extended ROM File:",IDC_ROMFILE2TEXT,10,68,75,10 + EDITTEXT IDC_ROMFILE2,90,63,185,15,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_ROMCHOOSER2,280,63,10,15 + CONTROL "ShapeShifter support",IDC_KICKSHIFTER,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,196,86,80,10 + GROUPBOX "Misc settings:",-1,5,105,290,59 + RTEXT "Flash RAM File:",IDC_FLASHTEXT,8,119,75,10 + EDITTEXT IDC_FLASHFILE,89,117,185,15,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_FLASHCHOOSER,279,117,10,15 + RTEXT "Cartridge ROM File:",IDC_FLASHTEXT2,8,140,75,10 + EDITTEXT IDC_CARTFILE,89,137,185,15,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_CARTCHOOSER,279,137,10,15 + CONTROL "MAPROM emulation",IDC_MAPROM,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,104,86,80,10 +END + +IDD_DISPLAY DIALOGEX 0, 0, 300, 175 +STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CAPTION +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + GROUPBOX "Amiga screen resolution",IDC_SCREENRESTEXT,24,0,185,67, + BS_LEFT + RTEXT "Fullscreen",IDC_SELECTRESTEXT,27,17,34,15, + SS_CENTERIMAGE + COMBOBOX IDC_RESOLUTION,66,27,72,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_REFRESHRATE,142,27,60,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + RTEXT "Windowed",IDC_WINDOWEDTEXT,27,51,35,8 + EDITTEXT IDC_XSIZE,66,48,30,12,ES_NUMBER + EDITTEXT IDC_YSIZE,108,48,30,12,ES_NUMBER + CONTROL "VSync",IDC_VSYNC,"Button",BS_AUTOCHECKBOX | BS_LEFT | + WS_TABSTOP,146,48,54,10 + GROUPBOX "Settings",IDC_SETTINGSTEXT,24,72,186,73 + CONTROL "Full Screen",IDC_AFULLSCREEN,"Button",BS_AUTOCHECKBOX | + BS_LEFT | WS_TABSTOP,35,84,90,10 + CONTROL "Correct aspect ratio",IDC_ASPECT,"Button", + BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,35,101,90,10 + CONTROL "Full Screen RTG",IDC_PFULLSCREEN,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,131,84,70,10,0, + HIDC_PFULLSCREEN + LTEXT "Refresh:",IDC_REFRESHTEXT,34,124,28,8 + CONTROL "Slider1",IDC_FRAMERATE,"msctls_trackbar32", + TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,64,119,75,20 + CTEXT "",IDC_RATETEXT,144,119,50,20,SS_SUNKEN | WS_BORDER + GROUPBOX "Centering",IDC_STATIC,217,0,58,67 + CONTROL "Horizontal",IDC_XCENTER,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,225,16,45,10 + CONTROL "Vertical",IDC_YCENTER,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,225,32,39,10 + GROUPBOX "Line mode",IDC_LINEMODE,217,72,58,74 + CONTROL "Normal",IDC_LM_NORMAL,"Button",BS_AUTORADIOBUTTON | + BS_LEFT | WS_GROUP | WS_TABSTOP,225,84,38,10 + CONTROL "Doubled",IDC_LM_DOUBLED,"Button",BS_AUTORADIOBUTTON | + BS_LEFT | WS_TABSTOP,225,100,43,10 + CONTROL "Scanline",IDC_LM_SCANLINES,"Button",BS_AUTORADIOBUTTON | + BS_LEFT | WS_TABSTOP,225,116,40,10 + COMBOBOX IDC_DA_MODE,35,151,58,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | NOT WS_VISIBLE | WS_VSCROLL | + WS_TABSTOP + CONTROL "",IDC_DA_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | NOT WS_VISIBLE | WS_TABSTOP,97,147,101,20 + PUSHBUTTON "Detect pixel format",IDC_TEST16BIT,211,151,64,14,0,0, + HIDC_TEST16BIT + COMBOBOX IDC_DISPLAYSELECT,66,10,136,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + CONTROL "Lo-res",IDC_LORES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 131,101,70,10,0,HIDC_LORES +END + +IDD_MEMORY DIALOGEX 0, 0, 300, 175 +STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CAPTION +EXSTYLE WS_EX_CONTEXTHELP +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + GROUPBOX "Memory Settings:",-1,19,40,260,93 + RTEXT "Chip:",-1,24,60,20,10,SS_CENTERIMAGE + CONTROL "Slider1",IDC_CHIPMEM,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,54,55,50,20 + CTEXT "",IDC_CHIPRAM,104,55,35,20,SS_CENTERIMAGE | SS_SUNKEN | + WS_BORDER + RTEXT "Fast:",IDC_FASTTEXT,24,85,20,10,SS_CENTERIMAGE + CONTROL "Slider1",IDC_FASTMEM,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,54,80,50,20 + CTEXT "",IDC_FASTRAM,104,80,35,20,SS_CENTERIMAGE | SS_SUNKEN | + WS_BORDER + RTEXT "Slow:",-1,149,60,20,10,SS_CENTERIMAGE + CONTROL "Slider1",IDC_SLOWMEM,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,179,55,50,20 + CTEXT "",IDC_SLOWRAM,239,55,35,20,SS_CENTERIMAGE | SS_SUNKEN | + WS_BORDER + RTEXT "Z3-Fast:",IDC_Z3TEXT,139,85,30,10,SS_CENTERIMAGE + CONTROL "Slider1",IDC_Z3FASTMEM,"msctls_trackbar32", + TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,179,80,60,20 + CTEXT "",IDC_Z3FASTRAM,239,80,35,20,SS_CENTERIMAGE | SS_SUNKEN | + WS_BORDER + RTEXT "RTG (graphics card):",IDC_GFXCARDTEXT,96,110,76,10, + SS_CENTERIMAGE + CONTROL "Slider1",IDC_P96MEM,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,179,105,60,20 + CTEXT "",IDC_P96RAM,239,105,35,20,SS_CENTERIMAGE | SS_SUNKEN | + WS_BORDER +END + +IDD_CPU DIALOGEX 0, 0, 300, 175 +STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CAPTION +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + GROUPBOX "CPU Type:",IDC_STATIC,5,5,80,134,BS_LEFT + CONTROL "68000",IDC_CPU0,"Button",BS_AUTORADIOBUTTON | WS_GROUP | + WS_TABSTOP,10,18,34,10 + CONTROL "68010",IDC_CPU1,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,10,33,34,10 + CONTROL "68EC020",IDC_CPU2,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,10,48,45,10 + CONTROL "68EC020+FPU",IDC_CPU3,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,10,63,63,10 + CONTROL "68020",IDC_CPU4,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,10,78,34,10 + CONTROL "68020+FPU",IDC_CPU5,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,10,93,54,10 + CONTROL "68040",IDC_CPU6,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,10,108,36,10 + CONTROL "More compatible",IDC_COMPATIBLE,"Button", + BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,10,123, + 70,10 + GROUPBOX "CPU Emulation Speed:",IDC_STATIC,90,5,205,86 + CONTROL "Fastest possible, but maintain chipset timing", + IDC_CS_HOST,"Button",BS_AUTORADIOBUTTON | BS_LEFT | + WS_GROUP | WS_TABSTOP,95,18,195,10 + CONTROL "Match A500 speed",IDC_CS_68000,"Button", + BS_AUTORADIOBUTTON | BS_LEFT | WS_TABSTOP,95,32,195,10 + CONTROL "Adjustable between CPU and chipset",IDC_CS_ADJUSTABLE, + "Button",BS_AUTORADIOBUTTON | BS_LEFT | WS_TABSTOP,95,47, + 195,10 + RTEXT "CPU",IDC_CS_CPU_TEXT,96,71,15,10,SS_CENTERIMAGE | + WS_TABSTOP + CONTROL "Slider1",IDC_SPEED,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,114,66,67,20 + LTEXT "Chipset",IDC_CS_CHIPSET_TEXT,182,71,25,10, + SS_CENTERIMAGE | NOT WS_GROUP | WS_TABSTOP + RTEXT "CPU Idle",IDC_CS_CPU_TEXT2,236,56,32,10,SS_CENTERIMAGE | + WS_TABSTOP + CONTROL "",IDC_CPUIDLE,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,219,66,69,20 + GROUPBOX "JIT Settings:",IDC_STATIC,90,94,205,76 + RTEXT "Cache Size:",IDC_CS_CACHE_TEXT,95,109,45,10, + SS_CENTERIMAGE | WS_TABSTOP + CONTROL "Slider1",IDC_CACHE,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,140,104,115,20 + EDITTEXT IDC_CACHETEXT,255,109,30,12,ES_CENTER | ES_READONLY + CONTROL "Hard Flush",IDC_HARDFLUSH,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,100,127,60,10 + CONTROL "Const Jump",IDC_CONSTJUMP,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,100,141,60,10 + CONTROL "FPU Support",IDC_JITFPU,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,100,154,60,10 + CONTROL "Force Settings",IDC_FORCE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,165,127,61,10 + CONTROL "No Flags",IDC_NOFLAGS,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,165,141,60,10 + CONTROL "Direct",IDC_TRUST0,"Button",BS_AUTORADIOBUTTON | + WS_GROUP | WS_TABSTOP,230,127,34,10 + CONTROL "Indirect",IDC_TRUST1,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,230,141,45,10 + CONTROL "After Picasso96",IDC_TRUST2,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,230,154,64,10 +END + +IDD_FLOPPY DIALOGEX 0, 0, 300, 175 +STYLE DS_SETFONT | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + RTEXT "DF0:",IDC_STATIC,3,16,20,15,SS_CENTERIMAGE + COMBOBOX IDC_DF0TYPE,28,16,41,50,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + EDITTEXT IDC_DF0TEXT,74,15,130,15,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_DF0,208,15,10,15 + PUSHBUTTON "Eject",IDC_EJECT0,222,15,30,15 + CONTROL "Write protect",IDC_DF0WP,"Button",BS_AUTOCHECKBOX | + BS_MULTILINE | WS_TABSTOP,256,16,39,15 + RTEXT "DF1:",IDC_STATIC,3,41,20,15,SS_CENTERIMAGE + COMBOBOX IDC_DF1TYPE,28,41,41,50,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + EDITTEXT IDC_DF1TEXT,74,40,130,15,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_DF1,208,40,10,15 + PUSHBUTTON "Eject",IDC_EJECT1,222,40,30,15 + CONTROL "Write protect",IDC_DF1WP,"Button",BS_AUTOCHECKBOX | + BS_MULTILINE | WS_TABSTOP,256,40,39,15 + RTEXT "DF2:",IDC_STATIC,3,66,20,15,SS_CENTERIMAGE + COMBOBOX IDC_DF2TYPE,28,66,41,50,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + EDITTEXT IDC_DF2TEXT,74,65,130,15,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_DF2,208,65,10,15 + PUSHBUTTON "Eject",IDC_EJECT2,222,65,30,15 + CONTROL "Write protect",IDC_DF2WP,"Button",BS_AUTOCHECKBOX | + BS_MULTILINE | WS_TABSTOP,256,65,39,15 + RTEXT "DF3:",IDC_STATIC,3,90,20,15,SS_CENTERIMAGE + COMBOBOX IDC_DF3TYPE,28,91,41,50,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + EDITTEXT IDC_DF3TEXT,74,90,130,15,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_DF3,208,90,10,15 + PUSHBUTTON "Eject",IDC_EJECT3,222,90,30,15 + CONTROL "Write protect",IDC_DF3WP,"Button",BS_AUTOCHECKBOX | + BS_MULTILINE | WS_TABSTOP,256,90,39,15 + COMBOBOX IDC_FLOPPYTYPE,28,118,41,50,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Create Standard ""Floppy""",IDC_CREATE,74,118,97,15 + PUSHBUTTON "Create Custom ""Floppy""",IDC_CREATE_RAW,182,118,87,15 + RTEXT "Floppy Speed:",IDC_FLOPPYSPD_TEXT,9,149,45,10, + SS_CENTERIMAGE | WS_TABSTOP + CONTROL "",IDC_FLOPPYSPD,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,56,145,120,20 + EDITTEXT IDC_FLOPPYSPDTEXT,177,148,68,12,ES_CENTER | ES_READONLY +END + +IDD_HARDDISK DIALOGEX 0, 0, 300, 175 +STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CAPTION +EXSTYLE WS_EX_CONTEXTHELP +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + CONTROL "List1",IDC_VOLUMELIST,"SysListView32",LVS_REPORT | + LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | + LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,5,260,125 + PUSHBUTTON "",IDC_UP,270,25,25,15,BS_ICON + PUSHBUTTON "",IDC_DOWN,270,105,25,15,BS_ICON + PUSHBUTTON "Add &Directory...",IDC_NEW_FS,5,135,60,15 + PUSHBUTTON "Add &Hardfile...",IDC_NEW_HF,70,135,60,15 + PUSHBUTTON "Add Ha&rddrive",IDC_NEW_HD,135,135,60,15 + CONTROL "Add PC Drives at Startup",IDC_MAPDRIVES,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,5,155,105,10,0, + HIDC_MAPDRIVES + PUSHBUTTON "Remove",IDC_REMOVE,135,153,60,15 + PUSHBUTTON "&Properties",IDC_EDIT,200,153,60,15 +END + +IDD_SOUND DIALOGEX 0, 0, 300, 175 +STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CAPTION +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + RTEXT "Sound Card:",IDC_SOUNDCARD,11,9,41,13,SS_CENTERIMAGE + COMBOBOX IDC_SOUNDCARDLIST,60,9,221,50,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + GROUPBOX "Sound Emulation",IDC_SOUNDSETTINGS,7,25,120,58 + CONTROL "Disabled",IDC_SOUND0,"Button",BS_AUTORADIOBUTTON | + WS_GROUP | WS_TABSTOP,15,35,43,10 + CONTROL "Disabled, but emulated",IDC_SOUND1,"Button", + BS_AUTORADIOBUTTON | BS_LEFT | WS_TABSTOP,15,47,88,10 + CONTROL "Enabled",IDC_SOUND2,"Button",BS_AUTORADIOBUTTON | + BS_LEFT | WS_TABSTOP,15,59,42,10 + CONTROL "Enabled, 100% accurate",IDC_SOUND3,"Button", + BS_AUTORADIOBUTTON | BS_LEFT | WS_TABSTOP,15,71,93,10 + GROUPBOX "Settings",IDC_SOUNDINTERPOLATION2,133,25,160,58 + RTEXT "Frequency:",IDC_SOUNDFREQTXT,138,33,37,8,SS_CENTERIMAGE + COMBOBOX IDC_SOUNDFREQ,140,42,67,75,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP + RTEXT "Audio filter:",IDC_SOUNDFILTERTXT,140,58,36,8, + SS_CENTERIMAGE + COMBOBOX IDC_SOUNDFILTER,140,67,67,75,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + GROUPBOX "Sound buffer size",IDC_STATIC,7,108,120,29 + CONTROL "Slider1",IDC_SOUNDBUFFERRAM,"msctls_trackbar32", + TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,14,116,106,19 + CTEXT "",IDC_SOUNDBUFFERMEM,134,116,40,16,SS_CENTERIMAGE | + SS_SUNKEN | WS_BORDER | WS_TABSTOP + GROUPBOX "Sound driver lag compensation",IDC_STATIC,7,139,120,28 + CONTROL "Slider1",IDC_SOUNDADJUST,"msctls_trackbar32", + TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,14,147,107,19 + CTEXT "",IDC_SOUNDADJUSTNUM,134,152,40,16,SS_CENTERIMAGE | + SS_SUNKEN | WS_BORDER | WS_TABSTOP + PUSHBUTTON "Calibrate",IDC_SOUNDCALIBRATE,134,135,40,14 + COMBOBOX IDC_SOUNDSTEREO,220,42,67,75,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_SOUNDINTERPOLATION,220,67,67,75,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + RTEXT "Stereo mode:",IDC_SOUNDSTEREOTXT,223,33,41,8, + SS_CENTERIMAGE + RTEXT "Interpolation:",IDC_SOUNDINTERPOLATIONTXT,222,58,41,8, + SS_CENTERIMAGE + GROUPBOX "Volume",IDC_STATIC,181,108,112,29 + CONTROL "",IDC_SOUNDVOLUME,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,183,116,107,19 + COMBOBOX IDC_SOUNDDRIVE,15,92,32,75,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + COMBOBOX IDC_SOUNDDRIVESELECT,55,92,120,75,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + GROUPBOX "Disk Drive Sound Emulation",IDC_STATIC,8,83,285,25 + CONTROL "",IDC_SOUNDDRIVEVOLUME,"msctls_trackbar32", + TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,183,88,107,19 +END + +IDD_LOADSAVE DIALOGEX 0, 0, 300, 175 +STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_BORDER +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + CONTROL "List1",IDC_CONFIGLIST,"SysListView32",LVS_REPORT | + LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | + LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | + WS_TABSTOP,5,5,290,105,0,HIDC_CONFIGLIST + RTEXT "Name:",IDC_STATIC,20,115,25,15,SS_CENTERIMAGE + EDITTEXT IDC_EDITNAME,50,115,155,15,ES_AUTOHSCROLL,0, + HIDC_EDITNAME + RTEXT "Description:",IDC_STATIC,5,135,40,15,SS_CENTERIMAGE + EDITTEXT IDC_EDITDESCRIPTION,50,135,155,15,ES_AUTOHSCROLL,0, + HIDC_EDITDESCRIPTION + GROUPBOX "Extra Info",IDC_STATIC,210,115,85,35 + PUSHBUTTON "View",IDC_VIEWINFO,215,130,35,15 + PUSHBUTTON "Set",IDC_SETINFO,255,130,35,15 + PUSHBUTTON "Load",IDC_QUICKLOAD,5,155,40,15 + PUSHBUTTON "Save",IDC_QUICKSAVE,50,155,40,15 + PUSHBUTTON "Load From...",IDC_LOAD,100,155,45,15 + PUSHBUTTON "Save As...",IDC_SAVE,150,155,40,15 + PUSHBUTTON "Delete",IDC_DELETE,200,155,40,15 + PUSHBUTTON "Exit",IDC_EXIT,250,155,40,15 +END + +IDD_PORTS DIALOGEX 0, 0, 300, 175 +STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_BORDER +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + RTEXT "Serial:",IDC_STATIC,20,15,25,15,SS_CENTERIMAGE + COMBOBOX IDC_SERIAL,50,15,95,65,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + CONTROL "Shared",IDC_SHARED,"Button",BS_AUTOCHECKBOX | + BS_VCENTER | WS_TABSTOP,33,32,37,12 + CONTROL "RTS/CTS",IDC_SER_CTSRTS,"Button",BS_AUTOCHECKBOX | + BS_VCENTER | WS_TABSTOP,77,32,44,12 + CONTROL "Direct",IDC_SERIAL_DIRECT,"Button",BS_AUTOCHECKBOX | + BS_VCENTER | WS_TABSTOP,128,32,40,12 + RTEXT "Printer:",IDC_STATIC,155,15,25,15,SS_CENTERIMAGE + COMBOBOX IDC_PRINTERLIST,185,15,95,134,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + RTEXT "MIDI Out:",IDC_MIDI,10,47,34,15,SS_CENTERIMAGE + COMBOBOX IDC_MIDIOUTLIST,50,47,95,130,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + RTEXT "MIDI In:",IDC_MIDI2,150,47,29,15,SS_CENTERIMAGE + COMBOBOX IDC_MIDIINLIST,185,47,95,134,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + GROUPBOX "Amiga Mouse Port 0",IDC_PORT0,20,65,105,100 + CONTROL "PC Joystick 0",IDC_PORT0_JOY0,"Button", + BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,30,75,90,10 + CONTROL "PC Joystick 1",IDC_PORT0_JOY1,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,30,89,90,10 + CONTROL "PC Mouse",IDC_PORT0_MOUSE,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,30,104,90,11 + CONTROL "Keyboard Layout ""A""",IDC_PORT0_KBDA,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,30,120,90,10 + CONTROL "Keyboard Layout ""B""",IDC_PORT0_KBDB,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,30,135,90,10 + CONTROL "Keyboard Layout ""C""",IDC_PORT0_KBDC,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,30,150,90,10 + GROUPBOX "Amiga Mouse Port 1",IDC_PORT1,175,65,105,100 + CONTROL "PC Joystick 0",IDC_PORT1_JOY0,"Button", + BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,185,75,90,10 + CONTROL "PC Joystick 1",IDC_PORT1_JOY1,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,185,89,90,10 + CONTROL "PC Mouse",IDC_PORT1_MOUSE,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,185,104,90,11 + CONTROL "Keyboard Layout ""A""",IDC_PORT1_KBDA,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,185,120,90,10 + CONTROL "Keyboard Layout ""B""",IDC_PORT1_KBDB,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,185,135,90,10 + CONTROL "Keyboard Layout ""C""",IDC_PORT1_KBDC,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,185,150,90,10 + PUSHBUTTON "<-swap->",IDC_SWAP,130,105,40,14 +END + +IDD_CONTRIBUTORS DIALOG 0, 0, 300, 175 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | WS_POPUP | + WS_VISIBLE | WS_CAPTION +CAPTION "UAE Authors and Contributors..." +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",ID_OK,135,155,29,14 + CONTROL "",IDC_CONTRIBUTORS,"RICHEDIT",TCS_HOTTRACK | + TCS_VERTICAL | TCS_RAGGEDRIGHT | TCS_OWNERDRAWFIXED | + TCS_MULTISELECT | WS_BORDER | WS_VSCROLL | WS_HSCROLL | + WS_TABSTOP,5,5,290,145 +END + +IDD_ABOUT DIALOGEX 0, 0, 300, 175 +STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_BORDER +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + CONTROL "",IDC_RICHEDIT1,"RICHEDIT",TCS_SCROLLOPPOSITE | + TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,45,10, + 210,15 + CONTROL "",IDC_RICHEDIT2,"RICHEDIT",TCS_SCROLLOPPOSITE | + TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,20,30, + 260,13 + PUSHBUTTON "Contributors",IDC_CONTRIBUTORS,110,55,80,15 + CONTROL "",IDC_CLOANTOHOME,"RICHEDIT",TCS_SCROLLOPPOSITE | + TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,20,90,80, + 20 + CONTROL "",IDC_UAEHOME,"RICHEDIT",TCS_SCROLLOPPOSITE | + TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,20,120, + 80,15 + CONTROL "",IDC_PICASSOHOME,"RICHEDIT",TCS_SCROLLOPPOSITE | + TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,200,90, + 80,20 + CONTROL "",IDC_AMIGAHOME,"RICHEDIT",TCS_SCROLLOPPOSITE | + TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,110,90, + 80,15 + CONTROL "",IDC_WINUAEHOME,"RICHEDIT",TCS_SCROLLOPPOSITE | + TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,200,120, + 80,15 + CONTROL "",IDC_AIABHOME,"RICHEDIT",TCS_SCROLLOPPOSITE | + TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,110,120, + 80,15 + CONTROL "",IDC_THEROOTS,"RICHEDIT",TCS_SCROLLOPPOSITE | + TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,33,143, + 110,15 + CONTROL "",IDC_CAPS,"RICHEDIT",TCS_SCROLLOPPOSITE | + TCS_RAGGEDRIGHT | TCS_MULTISELECT | WS_DISABLED,150,143, + 110,15 +END + +IDD_MISC1 DIALOGEX 0, 0, 300, 175 +STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CAPTION +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + GROUPBOX "Advanced:",IDC_STATIC,20,4,260,73 + CONTROL "Middle-Mouse-Button --> ALT-TAB",IDC_JULIAN,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,26,15,120,10 + CONTROL "Show GUI on startup",IDC_SHOWGUI,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,26,30,120,10 + CONTROL "On-Screen LEDs",IDC_SHOWLEDS,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,26,45,115,10 + CONTROL "UAEscsi.device",IDC_SCSIDEVICE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,26,60,66,10 + CONTROL "BSDsocket.library emulation",IDC_SOCKETS,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,156,15,120,10 + CONTROL "Use CTRL-F11 to quit",IDC_CTRLF11,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,156,30,120,10 + CONTROL "Don't use RGB overlays",IDC_NOOVERLAY,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,156,45,120,10 + CONTROL "Use ASPI SCSI layer",IDC_ASPI,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,156,60,115,10 + GROUPBOX "Keyboard LEDs:",IDC_STATIC,20,82,68,73 + COMBOBOX IDC_KBLED1,26,95,56,65,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + COMBOBOX IDC_KBLED2,26,114,56,65,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + COMBOBOX IDC_KBLED3,26,134,56,65,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + GROUPBOX "Logging:",IDC_STATIC,97,82,183,25 + CONTROL "Create log file",IDC_CREATELOGFILE,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,107,92,72,10,0, + HIDC_CREATELOGFILE + CONTROL "Illegal mem accesses",IDC_ILLEGAL,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,189,92,80,10 + PUSHBUTTON "Reset Amiga",IDC_RESETAMIGA,129,127,49,14 + PUSHBUTTON "Quit",IDC_QUITEMU,199,126,49,14 +END + +IDD_HARDFILE DIALOGEX 0, 0, 229, 164 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | + DS_CENTERMOUSE | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Volume Settings" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + RTEXT "Path:",IDC_HARDFILE_DIR_TEXT,19,21,22,10 + EDITTEXT IDC_PATH_NAME,44,15,151,15,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_SELECTOR,200,15,11,15 + RTEXT "Sectors:",IDC_SECTORS_TEXT,80,80,30,10 + EDITTEXT IDC_SECTORS,115,75,27,15,ES_NUMBER + RTEXT "Surfaces:",IDC_SURFACES_TEXT,75,58,35,10 + EDITTEXT IDC_HEADS,115,54,27,15,ES_NUMBER + RTEXT "Reserved:",IDC_RESERVED_TEXT,145,58,35,10 + EDITTEXT IDC_RESERVED,185,54,27,15,ES_NUMBER + CONTROL "Read/Write",IDC_RW,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,160,37,50,10 + PUSHBUTTON "OK",IDOK,115,143,50,14 + PUSHBUTTON "Cancel",IDCANCEL,171,143,50,14 + PUSHBUTTON "Create",IDC_CREATEHF,20,115,85,14 + GROUPBOX "New Hard File",IDC_STATIC,10,100,210,35 + EDITTEXT IDC_HFSIZE,110,115,60,15,ES_NUMBER + LTEXT "MB",IDC_RESERVED_TEXT2,174,118,39,9,NOT WS_GROUP + GROUPBOX "Hard File Settings",IDC_STATIC,10,5,210,90 + RTEXT "Block-Size:",IDC_BLOCKSIZE_TEXT,145,80,35,10 + EDITTEXT IDC_BLOCKSIZE,185,75,27,15,ES_NUMBER + RTEXT "BootPri:",IDC_HARDFILE_BOOTPRI_TEXT,11,80,30,8 + EDITTEXT IDC_HARDFILE_BOOTPRI,44,75,32,15 + RTEXT "Device:",IDC_HARDFILE_DEVICE_TEXT,16,58,25,10 + EDITTEXT IDC_HARDFILE_DEVICE,44,54,32,15,ES_AUTOHSCROLL + RTEXT "FileSys:",IDC_HARDFILE_FILESYS_TEXT,16,36,26,10 + EDITTEXT IDC_PATH_FILESYS,44,34,89,15,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_FILESYS_SELECTOR,139,34,11,15 +END + +IDD_FILESYS DIALOGEX 15, 25, 229, 111 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | + DS_CENTERMOUSE | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Volume Settings" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + LTEXT "Device Name:",-1,5,9,54,10 + EDITTEXT IDC_VOLUME_DEVICE,65,5,85,15,ES_AUTOHSCROLL + LTEXT "Volume Label:",-1,5,31,54,10 + EDITTEXT IDC_VOLUME_NAME,65,25,85,15,ES_AUTOHSCROLL + LTEXT "Path:",-1,5,51,44,10 + EDITTEXT IDC_PATH_NAME,65,46,139,15,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_SELECTOR,210,46,10,15 + CONTROL "Read/Write",IDC_RW,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,5,70,50,10 + RTEXT "BootPri:",IDC_VOLUME_BOOTPRI_TEXT,68,70,30,8 + EDITTEXT IDC_VOLUME_BOOTPRI,106,68,27,15 + PUSHBUTTON "OK",IDOK,120,91,48,15 + PUSHBUTTON "Cancel",IDCANCEL,175,91,48,15 +END + +IDD_SETINFO DIALOG 0, 0, 229, 85 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | + DS_CENTERMOUSE | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Info Settings" +FONT 8, "MS Sans Serif" +BEGIN + RTEXT "Path:",-1,5,20,24,15,SS_CENTERIMAGE + EDITTEXT IDC_PATH_NAME,35,20,169,15,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_SELECTOR,210,20,10,15 + PUSHBUTTON "OK",IDOK,120,65,48,15 + PUSHBUTTON "Cancel",IDCANCEL,175,65,48,15 +END + +IDD_CHIPSET DIALOG 0, 65490, 300, 175 +STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CAPTION +FONT 8, "MS Sans Serif" +BEGIN + GROUPBOX "Chipset type",-1,22,11,142,82 + CONTROL "OCS",IDC_OCS,"Button",BS_AUTORADIOBUTTON | WS_GROUP | + WS_TABSTOP,41,31,30,10 + CONTROL "ECS Agnus",IDC_ECS_AGNUS,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,41,47,50,10 + CONTROL "ECS Denise",IDC_ECS_DENISE,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,41,63,50,10 + CONTROL "Full ECS",IDC_ECS,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,105,31,42,10 + CONTROL "AGA",IDC_AGA,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP, + 105,47,30,10 + CONTROL "NTSC",IDC_NTSC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 105,64,35,10 + GROUPBOX "Misc chipset options",-1,171,11,111,82 + CONTROL "Fast Copper",IDC_FASTCOPPER,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,178,31,53,10 + CONTROL "Immediate Blitter",IDC_BLITIMM,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,178,47,75,10 + CONTROL "Cycle exact CPU and Blitter",IDC_CYCLEEXACT,"Button", + BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,178,64, + 100,10 + GROUPBOX "Collision level",-1,22,95,261,48 + CONTROL "None",IDC_COLLISION0,"Button",BS_AUTORADIOBUTTON | + WS_GROUP | WS_TABSTOP,40,111,50,10 + CONTROL "Sprites only",IDC_COLLISION1,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,40,127,50,10 + CONTROL "Sprites and Sprites vs. Playfield",IDC_COLLISION2, + "Button",BS_AUTORADIOBUTTON | WS_TABSTOP,104,111,114,10 + CONTROL "Full",IDC_COLLISION3,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,104,127,27,10 +END + +IDD_AVIOUTPUT DIALOGEX 0, 0, 300, 167 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + GROUPBOX "Output Properties:",IDC_STATIC,5,8,152,91 + EDITTEXT IDC_AVIOUTPUT_FILETEXT,10,18,120,12,ES_AUTOHSCROLL | + ES_READONLY | NOT WS_BORDER,WS_EX_CLIENTEDGE + PUSHBUTTON "...",IDC_AVIOUTPUT_FILE,132,18,19,12 + CONTROL "Audio",IDC_AVIOUTPUT_AUDIO,"Button",BS_AUTOCHECKBOX | + BS_PUSHLIKE | BS_FLAT | WS_TABSTOP,10,33,32,11 + CONTROL "",IDC_AVIOUTPUT_AUDIO_STATIC,"Static",SS_LEFTNOWORDWRAP | + SS_CENTERIMAGE | SS_SUNKEN | WS_GROUP,44,33,107,11 + CONTROL "Video",IDC_AVIOUTPUT_VIDEO,"Button",BS_AUTOCHECKBOX | + BS_PUSHLIKE | BS_FLAT | WS_TABSTOP,10,47,32,11 + CONTROL "",IDC_AVIOUTPUT_VIDEO_STATIC,"Static",SS_LEFTNOWORDWRAP | + SS_CENTERIMAGE | SS_SUNKEN | WS_GROUP,44,47,107,11 + CONTROL "Disable frame rate limit while recording", + IDC_AVIOUTPUT_FRAMELIMITER,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,12,65,142,10 + CONTROL "AVIOutput enabled",IDC_AVIOUTPUT_ACTIVATED,"Button", + BS_AUTORADIOBUTTON | BS_PUSHLIKE | BS_FLAT,10,80,142,12 + GROUPBOX "Playback Rate:",IDC_STATIC,5,100,152,33 + CONTROL "PAL",IDC_AVIOUTPUT_PAL,"Button",BS_AUTORADIOBUTTON | + BS_PUSHLIKE | BS_FLAT,10,110,66,8 + CONTROL "NTSC",IDC_AVIOUTPUT_NTSC,"Button",BS_AUTORADIOBUTTON | + BS_PUSHLIKE | BS_FLAT,81,110,66,8 + CONTROL "Slider1",IDC_AVIOUTPUT_FPS,"msctls_trackbar32",TBS_BOTH | + TBS_NOTICKS | TBS_ENABLESELRANGE | WS_TABSTOP,7,120,120, + 11 + LTEXT "fps",IDC_AVIOUTPUT_FPS_STATIC,127,120,23,8 + GROUPBOX "Frame / Video Dimensions:",IDC_STATIC,161,8,133,143,NOT + WS_VISIBLE + LTEXT "Width:",IDC_STATIC,169,24,22,8,NOT WS_VISIBLE + EDITTEXT IDC_AVIOUTPUT_WIDTH,193,22,30,12,ES_NUMBER | NOT + WS_VISIBLE + LTEXT "Height:",IDC_STATIC,230,24,25,8,NOT WS_VISIBLE + EDITTEXT IDC_AVIOUTPUT_HEIGHT,256,22,30,12,ES_NUMBER | NOT + WS_VISIBLE + CTEXT "Actual:",IDC_AVIOUTPUT_DIMENSIONS_STATIC,170,38,116,9, + NOT WS_VISIBLE + CONTROL "",IDC_AVIOUTPUT_FRAME,"Static",SS_BLACKFRAME | NOT + WS_VISIBLE,170,50,116,80 + PUSHBUTTON "Save Screenshot",IDC_SCREENSHOT,25,143,95,12 +END + +IDD_INPUT DIALOGEX 0, 0, 300, 175 +STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CAPTION +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + COMBOBOX IDC_INPUTTYPE,5,5,98,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_INPUTDEVICE,109,4,167,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + CONTROL "",IDC_INPUTDEVICEDISABLE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,282,7,9,8 + CONTROL "List1",IDC_INPUTLIST,"SysListView32",LVS_REPORT | + LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | + LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,22,290,81 + COMBOBOX IDC_INPUTAMIGACNT,5,109,24,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_INPUTAMIGA,33,109,219,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + CONTROL "Autofire",IDC_INPUTAUTOFIRE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,257,111,37,10 + RTEXT "Joystick dead zone (%):",-1,8,128,76,10,SS_CENTERIMAGE + EDITTEXT IDC_INPUTDEADZONE,89,127,25,12,ES_NUMBER + RTEXT "Autofire rate (frames):",-1,9,144,68,10,SS_CENTERIMAGE + EDITTEXT IDC_INPUTAUTOFIRERATE,89,142,25,12,ES_NUMBER + RTEXT "Digital joy-mouse speed:",-1,121,128,76,10, + SS_CENTERIMAGE + EDITTEXT IDC_INPUTSPEEDD,207,127,25,12,ES_NUMBER + RTEXT "Analog joy-mouse speed:",-1,120,144,80,10, + SS_CENTERIMAGE + EDITTEXT IDC_INPUTSPEEDA,207,143,25,12,ES_NUMBER + RTEXT "Mouse speed:",-1,132,160,68,10,SS_CENTERIMAGE + EDITTEXT IDC_INPUTSPEEDM,207,159,25,12,ES_NUMBER + PUSHBUTTON "Copy from:",IDC_INPUTCOPY,249,127,45,14 + COMBOBOX IDC_INPUTCOPYFROM,249,143,45,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Swap 1<>2",IDC_INPUTSWAP,249,158,45,14 +END + +IDD_OPENGL DIALOGEX 0, 0, 300, 175 +STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CAPTION +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + GROUPBOX "Filter settings:",-1,19,12,260,151 + CONTROL "Enable",IDC_OPENGLENABLE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,26,27,38,10 + COMBOBOX IDC_OPENGLMODE,67,25,56,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_OPENGLFILTER,128,25,65,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Reset to defaults",IDC_OPENGLDEFAULT,197,25,73,14 + RTEXT "Horizontal Size",-1,25,49,57,10,SS_CENTERIMAGE + CONTROL "Slider1",IDC_OPENGLHZ,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,89,42,158,19 + CTEXT "",IDC_OPENGLHZV,249,44,21,16,SS_CENTERIMAGE | SS_SUNKEN | + WS_BORDER | WS_TABSTOP + RTEXT "Vertical Size",-1,26,69,57,10,SS_CENTERIMAGE + CONTROL "Slider1",IDC_OPENGLVZ,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,89,62,157,19 + CTEXT "",IDC_OPENGLVZV,249,64,21,16,SS_CENTERIMAGE | SS_SUNKEN | + WS_BORDER | WS_TABSTOP + RTEXT "Horizontal Position",-1,26,89,57,10,SS_CENTERIMAGE + CONTROL "Slider1",IDC_OPENGLHO,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,89,82,157,19 + CTEXT "",IDC_OPENGLHOV,249,84,21,16,SS_CENTERIMAGE | SS_SUNKEN | + WS_BORDER | WS_TABSTOP + RTEXT "Vertical Position",-1,26,108,57,10,SS_CENTERIMAGE + CONTROL "Slider1",IDC_OPENGLVO,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,89,102,157,19 + CTEXT "",IDC_OPENGLVOV,249,104,21,16,SS_CENTERIMAGE | + SS_SUNKEN | WS_BORDER | WS_TABSTOP + RTEXT "Scanlines",-1,27,130,57,10,SS_CENTERIMAGE + CONTROL "Slider1",IDC_OPENGLSL,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_TOP | WS_TABSTOP,89,123,157,19 + CTEXT "",IDC_OPENGLSLV,249,124,21,16,SS_CENTERIMAGE | + SS_SUNKEN | WS_BORDER | WS_TABSTOP + COMBOBOX IDC_OPENGLSLR,56,143,27,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + CONTROL "Slider1",IDC_OPENGLSL2,"msctls_trackbar32", + TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,89,143,157,19 + CTEXT "",IDC_OPENGLSL2V,249,143,21,16,SS_CENTERIMAGE | + SS_SUNKEN | WS_BORDER | WS_TABSTOP +END + +IDD_HARDDRIVE DIALOGEX 0, 0, 229, 66 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | + DS_CENTERMOUSE | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Harddrive Settings" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + LTEXT "Harddrive:",-1,7,11,35,10 + COMBOBOX IDC_HARDDRIVE,49,9,173,150,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + CONTROL "Read/Write",IDC_RW,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,15,30,50,10 + DEFPUSHBUTTON "OK",IDOK,116,47,50,14 + PUSHBUTTON "Cancel",IDCANCEL,172,47,50,14 +END + +IDD_MISC2 DIALOGEX 0, 0, 300, 175 +STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CAPTION +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + GROUPBOX "When Active:",IDC_STATIC,8,7,88,73 + RTEXT "Run at priority:",IDC_ACTIVE_PRI,14,17,45,10, + SS_CENTERIMAGE | WS_TABSTOP + COMBOBOX IDC_ACTIVE_PRIORITY,14,29,76,65,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + GROUPBOX "When Inactive:",IDC_STATIC,102,7,92,73 + RTEXT "Run at priority:",IDC_INACTIVE_PRI,109,17,45,10, + SS_CENTERIMAGE | WS_TABSTOP + COMBOBOX IDC_INACTIVE_PRIORITY,109,29,76,65,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + CONTROL "Pause emulation",IDC_INACTIVE_PAUSE,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,109,50,69,10 + CONTROL "Disable sound output",IDC_INACTIVE_NOSOUND,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,109,63,79,10 + GROUPBOX "When Minimized:",IDC_STATIC,199,7,92,73 + RTEXT "Run at priority:",IDC_MINIMIZED_PRI,207,18,45,10, + SS_CENTERIMAGE | WS_TABSTOP + COMBOBOX IDC_MINIMIZED_PRIORITY,207,30,76,65,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + CONTROL "Pause emulation",IDC_MINIMIZED_PAUSE,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,207,50,69,10 + CONTROL "Disable sound output",IDC_MINIMIZED_NOSOUND,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,207,63,79,10 + GROUPBOX "State files:",IDC_STATIC,10,92,281,63 + PUSHBUTTON "Load state...",IDC_DOLOADSTATE,21,108,49,14 + PUSHBUTTON "Save state...",IDC_DOSAVESTATE,21,132,49,14 + CONTROL "Enable state recording",IDC_STATE_CAPTURE,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,160,103,88,10 + RTEXT "Recording rate (seconds)",IDC_STATE_RATE_TEXT,153,118, + 86,10,SS_CENTERIMAGE | WS_TABSTOP + COMBOBOX IDC_STATE_RATE,244,116,38,65,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP + RTEXT "Recording buffer (MB)",IDC_STATE_BUFFERSIZE_TEXT,153, + 138,83,10,SS_CENTERIMAGE | WS_TABSTOP + COMBOBOX IDC_STATE_BUFFERSIZE,244,136,38,65,CBS_DROPDOWN | + WS_VSCROLL | WS_TABSTOP +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_KICKSTART, DIALOG + BEGIN + BOTTOMMARGIN, 174 + END + + IDD_SOUND, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 293 + TOPMARGIN, 7 + BOTTOMMARGIN, 168 + END + + IDD_LOADSAVE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 293 + TOPMARGIN, 7 + BOTTOMMARGIN, 168 + END + + IDD_PORTS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 293 + TOPMARGIN, 7 + BOTTOMMARGIN, 168 + END + + IDD_CONTRIBUTORS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 293 + TOPMARGIN, 7 + BOTTOMMARGIN, 168 + END + + IDD_ABOUT, DIALOG + BEGIN + RIGHTMARGIN, 299 + BOTTOMMARGIN, 174 + END + + IDD_MISC1, DIALOG + BEGIN + BOTTOMMARGIN, 174 + HORZGUIDE, 91 + END + + IDD_HARDFILE, DIALOG + BEGIN + BOTTOMMARGIN, 146 + END + + IDD_FILESYS, DIALOG + BEGIN + BOTTOMMARGIN, 85 + END + + IDD_OPENGL, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 293 + TOPMARGIN, 7 + BOTTOMMARGIN, 168 + END + + IDD_MISC2, DIALOG + BEGIN + BOTTOMMARGIN, 173 + HORZGUIDE, 91 + END +END +#endif // APSTUDIO_INVOKED + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "#include ""dlgs.h""\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APPICON ICON "winuae.ico" +IDI_FLOPPY ICON "35floppy.ico" +IDI_ABOUT ICON "amigainfo.ico" +IDI_CDROM ICON "Cddrive.ico" +IDI_HARDDISK ICON "Drive.ico" +IDI_SOUND ICON "Volume01.ico" +IDI_DISPLAY ICON "Monitr01.ico" +IDI_OPENGL ICON "Monitr01.ico" +IDI_CPU ICON "cpu.ico" +IDI_LOADSAVE ICON "35floppy.ico" +IDI_PORTS ICON "joystick.ico" +IDI_INPUT ICON "joystick.ico" +IDI_MEMORY ICON "Mycomp.ico" +IDI_MISC1 ICON "misc.ico" +IDI_MISC2 ICON "misc.ico" +IDI_MOVE_UP ICON "move_up.ico" +IDI_MOVE_DOWN ICON "move_dow.ico" +IDI_AVIOUTPUT ICON "avioutput.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,8,25,0 + PRODUCTVERSION 0,8,25,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "WinUAE" + VALUE "FileVersion", "0.8.25" + VALUE "InternalName", "WinUAE" + VALUE "LegalCopyright", "© 1996-2004 under the GNU Public License (GPL)" + VALUE "OriginalFilename", "WinUAE.exe" + VALUE "ProductName", "WinUAE" + VALUE "ProductVersion", "0.8.25" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Cursor +// + +IDC_MYHAND CURSOR "H_arrow.cur" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_KICKSTART "ROM" + IDS_DISPLAY "Display" + IDS_HARDDISK "Hard Drives" + IDS_FLOPPY "Floppies" + IDS_ABOUT "About" + IDS_LOADSAVE "Configurations" + IDS_AVIOUTPUT "Output" + IDS_PORTS "Game and I/O Ports" + IDS_MISC1 "Misc" + IDS_MEMORY "RAM" + IDS_CPU "CPU" + IDS_CHIPSET "Chipset" + IDS_INPUT "Input" + IDS_OPENGL "Filter" +END + +STRINGTABLE +BEGIN + IDS_MISC2 "Priority and state files" +END + +STRINGTABLE +BEGIN + IDS_EXTTEXT "Amiga Disk Files" + IDS_EXTACTUAL "ADF" + IDS_SOUND "Sound" + IDS_CDROM "CD-ROM" + IDS_FRAMERATE "Every %1Frame" + IDS_SECOND "second " + IDS_THIRD "third " + IDS_FOURTH "fourth " + IDS_FIFTH "fifth " + IDS_SIXTH "sixth " + IDS_SEVENTH "seventh " + IDS_EIGHTH "eighth " +END + +STRINGTABLE +BEGIN + IDS_NINTH "ninth " + IDS_TENTH "tenth " + IDS_SELECTADF "Select an Amiga Disk File image..." + IDS_ADF "Amiga Disk Files" + IDS_CHOOSEBLANK "Choose your blank Amiga Disk File..." + IDS_SELECTHDF "Select a Hard Disk File..." + IDS_HDF "Hard Disk Files" + IDS_SELECTUAE "Select a UAE Config-File..." + IDS_UAE "UAE Config Files" + IDS_SELECTROM "Select an Amiga ROM file..." + IDS_ROM "Amiga Kickstart Files" + IDS_SELECTKEY "Select an Amiga Key-File..." + IDS_KEY "Amiga Kickstart Key-Files" + IDS_SELECTINFO "Select information for your config..." + IDS_NONE "none" + IDS_VOLUME "Volume" +END + +STRINGTABLE +BEGIN + IDS_SELECTFILESYSROOT "Please select your file-system root directory..." + IDS_DEFAULTMIDIOUT "Default MIDI-Out Device" + IDS_CONTRIBUTORS1 "Bernd Schmidt - The Grand-Master\nSam Jordan - Custom-chip, floppy-DMA, etc.\nMathias Ortmann - Original WinUAE Main Guy, BSD Socket support\nBrian King - Picasso96 Support, Integrated GUI for WinUAE, previous WinUAE Main Guy\nToni Wilen - Core updates, WinUAE Main Guy\nGustavo Goedert/Peter Remmers/Michael Sontheimer/Tomi Hakala/Tim Gunn/Nemo Pohle - DOS Port Stuff\nSamuel Devulder/Olaf Barthel/Sam Jordan - Amiga Ports\nKrister Bergman - XFree86 and OS/2 Port\nA. Blanchard/Ernesto Corvi - MacOS Port\nChristian Bauer - BeOS Port\nIan Stephenson - NextStep Port\nPeter Teichmann - Acorn/RiscOS Port\nStefan Reinauer - ZorroII/III AutoConfig, Serial Support\nChristian Schmitt/Chris Hames - Serial Support\nHerman ten Brugge - 68020/68881 Emulation Code\nTauno Taipaleenmaki - Various UAE-Control/UAE-Library Support\nBrett Eden/Tim Gunn/Paolo Besser/Nemo Pohle - Various Docs and Web-Sites\nGeorg Veichtlbauer - Help File coordinator, German GUI\nFulvio Leonardi - Italian translator for WinUAE\n" + IDS_CONTRIBUTORS2 "Special thanks to Alexander Kneer and Tobias Abt (The Picasso96 Team)\n" + IDS_INVALIDPRTPORT "The printer you have in this configuration is not valid on this machine.\n" + IDS_RESTOREUSS "Restore a UAE Snap-Shot File" + IDS_USS "UAE Snap-Shot Files" + IDS_WRONGOSVERSION "WinUAE is no longer supported on Windows NT. Please upgrade to either Windows 2000 or Windows XP." + IDS_SELECTFLASH "Select a flash/battery backed RAM file..." + IDS_FLASH "UAE flash/battery backed RAM file" + IDS_INPUTHOSTWIDGET "Input Source" + IDS_INPUTAMIGAEVENT "Input Target" + IDS_INPUTAUTOFIRE "Autofire" + IDS_SAVEUSS "Save a UAE Snap-Shot File" + IDS_MIDIOVERFLOW "Sysexbuffer overflow. Should not happen. Please report this to\nberndroesch1@compuserve.de" +END + +STRINGTABLE +BEGIN + IDS_PATH "Path" + IDS_RW "R/W" + IDS_SECTORS "Sectors" + IDS_SURFACES "Surfaces" + IDS_RESERVED "Reserved" + IDS_BLOCKSIZE "Block Size" + IDS_NAME "Name" + IDS_DESCRIPTION "Description" + IDS_ONEINSTANCE "Only one instance of WinUAE can run at a time.\n" + IDS_INSTALLDIRECTX "You have to install DirectX on your system before you can use UAE.\nRefer to the documentation for further details.\n" + IDS_REGKEYCREATEFAILED "WinUAE could not create Registry keys! You need administrator privileges.\n" + IDS_COULDNOTLOADCONFIG "Could not load selected configuration!\n" + IDS_NOHELP "Online help is disabled, because you have not installed the HtmlHelp system. Go to http://msdn.microsoft.com/library/tools/htmlhelp/wkshp/download.htm to get HtmlHelp.\n" + IDS_MUSTSELECTCONFIG "You must select a configuration or enter a name before selecting Load...\n" + IDS_INVALIDCOMPORT "The COM-port you have in this configuration is not valid on this machine.\n" +END + +STRINGTABLE +BEGIN + IDS_HFDSIZE "Size" + IDS_DEVICE "Device" + IDS_BOOTPRI "BootPri" + IDS_WRONGDXVERSION "WinUAE requires DirectX 8 or newer." +END + +STRINGTABLE +BEGIN + IDS_WSOCK2NEEDED "Please upgrade to Winsock2.\n" + IDS_UNSUPPORTEDPIXELFORMAT + "Error: Unsupported pixel format - use a different screen mode\n" + IDS_WAVEOUTOPENFAILURE "Could not open WAVEOUT sound device!\n" + IDS_MUSTENTERNAME "You must select a configuration or enter a name before selecting Save...\n" + IDS_MUSTSELECTCONFIGFORDELETE + "You must select a configuration or enter a name before selecting Delete...\n" + IDS_DELETECONFIGCONFIRMATION + "Are you sure you want to Delete this configuration?\n" + IDS_DELETECONFIGTITLE "Confirm Delete" + IDS_GFXCARDCHECK "WinUAE will now determine your graphic-card's 16-bit pixel format.\nYour screen will go black for two seconds, with a resolution of 640x480 @ 60Hz.\nThis procedure is necessary to properly display your Amiga software on 16-bit\ndisplay-modes, and should be done whenever you run WinUAE for the first time, or\ninstall a new graphics-card in your PC. Proceed with this test?\n" + IDS_GFXCARDTITLE "Pixel Format Detection" + IDS_MUSTSELECTPATH "You must select a path!" + IDS_SETTINGSERROR "Settings Error" + IDS_MUSTSELECTNAME "You must select a name for the volume!" + IDS_MUSTSELECTFILE "You must select a file!" + IDS_FAILEDHARDFILECREATION "Failed to create hard-file..." + IDS_CREATIONERROR "Creation Error" + IDS_ERRORTITLE "WinUAE Message" +END + +STRINGTABLE +BEGIN + IDS_SOUND_MONO "Mono" + IDS_SOUND_MIXED "Mixed" + IDS_SOUND_STEREO "Stereo" + IDS_SOUND_INTERPOL_DISABLED "Disabled" + IDS_SOUND_INTERPOL_RH "RH" + IDS_SOUND_INTERPOL_CRUX "Crux" + IDS_SOUND_FILTER_OFF "Always off" + IDS_SOUND_FILTER_EMULATED "Emulated" +END + +STRINGTABLE +BEGIN + IDS_SOUND_FILTER_ON "Always on" + IDS_INPUT_COMPATIBILITY "Compatibility mode" + IDS_INPUT_CUSTOM "Configuration #%d" + IDS_INPUT_COPY_DEFAULT "Default" + IDS_INPUT_COPY_CUSTOM "Config #%d" + IDS_3D_NO_FILTER "No filter (%d-bit)" + IDS_3D_BILINEAR "Bilinear (%d-bit)" + IDS_VSYNC_DEFAULT "Default" + IDS_DRIVESOUND_NONE "No sound" + IDS_DRIVESOUND_DEFAULT_A500 "A500 (WinUAE built-in)" + IDS_AVIOUTPUT_NOCODEC "no codec selected" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + diff --git a/od-win32/scaler.c b/od-win32/scaler.c new file mode 100755 index 00000000..51fae9ff --- /dev/null +++ b/od-win32/scaler.c @@ -0,0 +1,1527 @@ +/* This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Scaler (except Scale2x) code borrowed from ScummVM project */ + +#include "filter.h" + +static uint32 colorMask; +static uint32 lowPixelMask; +static uint32 qcolorMask; +static uint32 qlowpixelMask; +static uint32 redblueMask; +static uint32 redMask; +static uint32 greenMask; +static uint32 blueMask; + +int Init_2xSaI (int rb, int gb, int bb, int rs, int gs, int bs) +{ + if (rb + gb + bb == 16) { + colorMask = 0xF7DEF7DE; + lowPixelMask = 0x08210821; + qcolorMask = 0xE79CE79C; + qlowpixelMask = 0x18631863; + redblueMask = 0xF81F; + redMask = 0xF800; + greenMask = 0x07E0; + blueMask = 0x001F; + } else if (rb + gb + bb == 15) { + colorMask = 0x7BDE7BDE; + lowPixelMask = 0x04210421; + qcolorMask = 0x739C739C; + qlowpixelMask = 0x0C630C63; + redblueMask = 0x7C1F; + redMask = 0x7C00; + greenMask = 0x03E0; + blueMask = 0x001F; + } else { + return 0; + } + + return 1; +} + +static _inline int GetResult(uint32 A, uint32 B, uint32 C, uint32 D) +{ + const bool ac = (A==C); + const bool bc = (B==C); + const int x1 = ac; + const int y1 = (bc & !ac); + const bool ad = (A==D); + const bool bd = (B==D); + const int x2 = ad; + const int y2 = (bd & !ad); + const int x = x1+x2; + const int y = y1+y2; + static const int rmap[3][3] = { + {0, 0, -1}, + {0, 0, -1}, + {1, 1, 0} + }; + return rmap[y][x]; +} + +static _inline uint32 INTERPOLATE(uint32 A, uint32 B) { + if (A != B) { + return (((A & colorMask) >> 1) + ((B & colorMask) >> 1) + (A & B & lowPixelMask)); + } else + return A; +} + +static _inline uint32 Q_INTERPOLATE(uint32 A, uint32 B, uint32 C, uint32 D) { + register uint32 x = ((A & qcolorMask) >> 2) + ((B & qcolorMask) >> 2) + ((C & qcolorMask) >> 2) + ((D & qcolorMask) >> 2); + register uint32 y = ((A & qlowpixelMask) + (B & qlowpixelMask) + (C & qlowpixelMask) + (D & qlowpixelMask)) >> 2; + + y &= qlowpixelMask; + return x + y; +} + +void Super2xSaI(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) { + const uint16 *bP; + uint16 *dP; + const uint32 nextlineSrc = srcPitch >> 1; + + while (height--) { + int i; + bP = (const uint16 *)srcPtr; + dP = (uint16 *)dstPtr; + + for (i = 0; i < width; ++i) { + uint32 color4, color5, color6; + uint32 color1, color2, color3; + uint32 colorA0, colorA1, colorA2, colorA3; + uint32 colorB0, colorB1, colorB2, colorB3; + uint32 colorS1, colorS2; + uint32 product1a, product1b, product2a, product2b; + +//--------------------------------------- B1 B2 +// 4 5 6 S2 +// 1 2 3 S1 +// A1 A2 + + colorB0 = *(bP - nextlineSrc - 1); + colorB1 = *(bP - nextlineSrc); + colorB2 = *(bP - nextlineSrc + 1); + colorB3 = *(bP - nextlineSrc + 2); + + color4 = *(bP - 1); + color5 = *(bP); + color6 = *(bP + 1); + colorS2 = *(bP + 2); + + color1 = *(bP + nextlineSrc - 1); + color2 = *(bP + nextlineSrc); + color3 = *(bP + nextlineSrc + 1); + colorS1 = *(bP + nextlineSrc + 2); + + colorA0 = *(bP + 2 * nextlineSrc - 1); + colorA1 = *(bP + 2 * nextlineSrc); + colorA2 = *(bP + 2 * nextlineSrc + 1); + colorA3 = *(bP + 2 * nextlineSrc + 2); + +//-------------------------------------- + if (color2 == color6 && color5 != color3) { + product2b = product1b = color2; + } else if (color5 == color3 && color2 != color6) { + product2b = product1b = color5; + } else if (color5 == color3 && color2 == color6) { + register int r = 0; + + r += GetResult(color6, color5, color1, colorA1); + r += GetResult(color6, color5, color4, colorB1); + r += GetResult(color6, color5, colorA2, colorS1); + r += GetResult(color6, color5, colorB2, colorS2); + + if (r > 0) + product2b = product1b = color6; + else if (r < 0) + product2b = product1b = color5; + else { + product2b = product1b = INTERPOLATE(color5, color6); + } + } else { + if (color6 == color3 && color3 == colorA1 && color2 != colorA2 && color3 != colorA0) + product2b = Q_INTERPOLATE(color3, color3, color3, color2); + else if (color5 == color2 && color2 == colorA2 && colorA1 != color3 && color2 != colorA3) + product2b = Q_INTERPOLATE(color2, color2, color2, color3); + else + product2b = INTERPOLATE(color2, color3); + + if (color6 == color3 && color6 == colorB1 && color5 != colorB2 && color6 != colorB0) + product1b = Q_INTERPOLATE(color6, color6, color6, color5); + else if (color5 == color2 && color5 == colorB2 && colorB1 != color6 && color5 != colorB3) + product1b = Q_INTERPOLATE(color6, color5, color5, color5); + else + product1b = INTERPOLATE(color5, color6); + } + + if (color5 == color3 && color2 != color6 && color4 == color5 && color5 != colorA2) + product2a = INTERPOLATE(color2, color5); + else if (color5 == color1 && color6 == color5 && color4 != color2 && color5 != colorA0) + product2a = INTERPOLATE(color2, color5); + else + product2a = color2; + + if (color2 == color6 && color5 != color3 && color1 == color2 && color2 != colorB2) + product1a = INTERPOLATE(color2, color5); + else if (color4 == color2 && color3 == color2 && color1 != color5 && color2 != colorB0) + product1a = INTERPOLATE(color2, color5); + else + product1a = color5; + + *(dP + 0) = (uint16) product1a; + *(dP + 1) = (uint16) product1b; + *(dP + dstPitch/2 + 0) = (uint16) product2a; + *(dP + dstPitch/2 + 1) = (uint16) product2b; + + bP += 1; + dP += 2; + } + + srcPtr += srcPitch; + dstPtr += dstPitch * 2; + } +} + +void SuperEagle(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) { + const uint16 *bP; + uint16 *dP; + const uint32 nextlineSrc = srcPitch >> 1; + + while (height--) { + int i; + bP = (const uint16 *)srcPtr; + dP = (uint16 *)dstPtr; + for (i = 0; i < width; ++i) { + uint32 color4, color5, color6; + uint32 color1, color2, color3; + uint32 colorA1, colorA2, colorB1, colorB2, colorS1, colorS2; + uint32 product1a, product1b, product2a, product2b; + + colorB1 = *(bP - nextlineSrc); + colorB2 = *(bP - nextlineSrc + 1); + + color4 = *(bP - 1); + color5 = *(bP); + color6 = *(bP + 1); + colorS2 = *(bP + 2); + + color1 = *(bP + nextlineSrc - 1); + color2 = *(bP + nextlineSrc); + color3 = *(bP + nextlineSrc + 1); + colorS1 = *(bP + nextlineSrc + 2); + + colorA1 = *(bP + 2 * nextlineSrc); + colorA2 = *(bP + 2 * nextlineSrc + 1); + + // -------------------------------------- + if (color5 != color3) + { + if (color2 == color6) + { + product1b = product2a = color2; + if ((color1 == color2) || (color6 == colorB2)) { + product1a = INTERPOLATE(color2, color5); + product1a = INTERPOLATE(color2, product1a); + } else { + product1a = INTERPOLATE(color5, color6); + } + + if ((color6 == colorS2) || (color2 == colorA1)) { + product2b = INTERPOLATE(color2, color3); + product2b = INTERPOLATE(color2, product2b); + } else { + product2b = INTERPOLATE(color2, color3); + } + } + else + { + product2b = product1a = INTERPOLATE(color2, color6); + product2b = Q_INTERPOLATE(color3, color3, color3, product2b); + product1a = Q_INTERPOLATE(color5, color5, color5, product1a); + + product2a = product1b = INTERPOLATE(color5, color3); + product2a = Q_INTERPOLATE(color2, color2, color2, product2a); + product1b = Q_INTERPOLATE(color6, color6, color6, product1b); + } + } + else //if (color5 == color3) + { + if (color2 != color6) + { + product2b = product1a = color5; + + if ((colorB1 == color5) || (color3 == colorS1)) { + product1b = INTERPOLATE(color5, color6); + product1b = INTERPOLATE(color5, product1b); + } else { + product1b = INTERPOLATE(color5, color6); + } + + if ((color3 == colorA2) || (color4 == color5)) { + product2a = INTERPOLATE(color5, color2); + product2a = INTERPOLATE(color5, product2a); + } else { + product2a = INTERPOLATE(color2, color3); + } + } + else //if (color2 != color6) + { + register int r = 0; + + r += GetResult(color6, color5, color1, colorA1); + r += GetResult(color6, color5, color4, colorB1); + r += GetResult(color6, color5, colorA2, colorS1); + r += GetResult(color6, color5, colorB2, colorS2); + + if (r > 0) { + product1b = product2a = color2; + product1a = product2b = INTERPOLATE(color5, color6); + } else if (r < 0) { + product2b = product1a = color5; + product1b = product2a = INTERPOLATE(color5, color6); + } else { + product2b = product1a = color5; + product1b = product2a = color2; + } + } + } + + *(dP + 0) = (uint16) product1a; + *(dP + 1) = (uint16) product1b; + *(dP + dstPitch/2 + 0) = (uint16) product2a; + *(dP + dstPitch/2 + 1) = (uint16) product2b; + + bP += 1; + dP += 2; + } + + srcPtr += srcPitch; + dstPtr += dstPitch * 2; + } +} + +void _2xSaI(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) { + const uint16 *bP; + uint16 *dP; + const uint32 nextlineSrc = srcPitch >> 1; + + while (height--) { + int i; + bP = (const uint16 *)srcPtr; + dP = (uint16 *)dstPtr; + + for (i = 0; i < width; ++i) { + + register uint32 colorA, colorB; + uint32 colorC, colorD, + colorE, colorF, colorG, colorH, colorI, colorJ, colorK, colorL, colorM, colorN, colorO, colorP; + uint32 product, product1, product2; + +//--------------------------------------- +// Map of the pixels: I|E F|J +// G|A B|K +// H|C D|L +// M|N O|P + colorI = *(bP - nextlineSrc - 1); + colorE = *(bP - nextlineSrc); + colorF = *(bP - nextlineSrc + 1); + colorJ = *(bP - nextlineSrc + 2); + + colorG = *(bP - 1); + colorA = *(bP); + colorB = *(bP + 1); + colorK = *(bP + 2); + + colorH = *(bP + nextlineSrc - 1); + colorC = *(bP + nextlineSrc); + colorD = *(bP + nextlineSrc + 1); + colorL = *(bP + nextlineSrc + 2); + + colorM = *(bP + 2 * nextlineSrc - 1); + colorN = *(bP + 2 * nextlineSrc); + colorO = *(bP + 2 * nextlineSrc + 1); + colorP = *(bP + 2 * nextlineSrc + 2); + + if ((colorA == colorD) && (colorB != colorC)) { + if (((colorA == colorE) && (colorB == colorL)) || + ((colorA == colorC) && (colorA == colorF) && (colorB != colorE) && (colorB == colorJ))) { + product = colorA; + } else { + product = INTERPOLATE(colorA, colorB); + } + + if (((colorA == colorG) && (colorC == colorO)) || + ((colorA == colorB) && (colorA == colorH) && (colorG != colorC) && (colorC == colorM))) { + product1 = colorA; + } else { + product1 = INTERPOLATE(colorA, colorC); + } + product2 = colorA; + } else if ((colorB == colorC) && (colorA != colorD)) { + if (((colorB == colorF) && (colorA == colorH)) || + ((colorB == colorE) && (colorB == colorD) && (colorA != colorF) && (colorA == colorI))) { + product = colorB; + } else { + product = INTERPOLATE(colorA, colorB); + } + + if (((colorC == colorH) && (colorA == colorF)) || + ((colorC == colorG) && (colorC == colorD) && (colorA != colorH) && (colorA == colorI))) { + product1 = colorC; + } else { + product1 = INTERPOLATE(colorA, colorC); + } + product2 = colorB; + } else if ((colorA == colorD) && (colorB == colorC)) { + if (colorA == colorB) { + product = colorA; + product1 = colorA; + product2 = colorA; + } else { + register int r = 0; + + product1 = INTERPOLATE(colorA, colorC); + product = INTERPOLATE(colorA, colorB); + + r += GetResult(colorA, colorB, colorG, colorE); + r -= GetResult(colorB, colorA, colorK, colorF); + r -= GetResult(colorB, colorA, colorH, colorN); + r += GetResult(colorA, colorB, colorL, colorO); + + if (r > 0) + product2 = colorA; + else if (r < 0) + product2 = colorB; + else { + product2 = Q_INTERPOLATE(colorA, colorB, colorC, colorD); + } + } + } else { + product2 = Q_INTERPOLATE(colorA, colorB, colorC, colorD); + + if ((colorA == colorC) && (colorA == colorF) + && (colorB != colorE) && (colorB == colorJ)) { + product = colorA; + } else if ((colorB == colorE) && (colorB == colorD) + && (colorA != colorF) && (colorA == colorI)) { + product = colorB; + } else { + product = INTERPOLATE(colorA, colorB); + } + + if ((colorA == colorB) && (colorA == colorH) + && (colorG != colorC) && (colorC == colorM)) { + product1 = colorA; + } else if ((colorC == colorG) && (colorC == colorD) + && (colorA != colorH) && (colorA == colorI)) { + product1 = colorC; + } else { + product1 = INTERPOLATE(colorA, colorC); + } + } + + *(dP + 0) = (uint16) colorA; + *(dP + 1) = (uint16) product; + *(dP + dstPitch/2 + 0) = (uint16) product1; + *(dP + dstPitch/2 + 1) = (uint16) product2; + + bP += 1; + dP += 2; + } + + srcPtr += srcPitch; + dstPtr += dstPitch * 2; + } +} + + +/* + * This file is part of the Advance project. + * + * Copyright (C) 1999-2002 Andrea Mazzoleni + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * This file contains a C and MMX implentation of the Scale2x effect. + * + * You can found an high level description of the effect at : + * + * http://scale2x.sourceforge.net/scale2x.html + * + * Alternatively at the previous license terms, you are allowed to use this + * code in your program with these conditions: + * - the program is not used in commercial activities. + * - the whole source code of the program is released with the binary. + * - derivative works of the program are allowed. + */ + +#define MMX +extern int cpu_mmx; + +/* Suggested in "Intel Optimization" for Pentium II */ +#define ASM_JUMP_ALIGN ".p2align 4\n" + +static void internal_scale2x_16_def(u16 *dst0, u16* dst1, const u16* src0, const u16* src1, const u16* src2, unsigned count) { + /* first pixel */ + dst0[0] = src1[0]; + dst1[0] = src1[0]; + if (src1[1] == src0[0] && src2[0] != src0[0]) + dst0[1] =src0[0]; + else + dst0[1] =src1[0]; + if (src1[1] == src2[0] && src0[0] != src2[0]) + dst1[1] =src2[0]; + else + dst1[1] =src1[0]; + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + + /* central pixels */ + count -= 2; + while (count) { + if (src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0]) + dst0[0] = src0[0]; + else + dst0[0] = src1[0]; + if (src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0]) + dst0[1] =src0[0]; + else + dst0[1] =src1[0]; + + if (src1[-1] == src2[0] && src0[0] != src2[0] && src1[1] != src2[0]) + dst1[0] =src2[0]; + else + dst1[0] =src1[0]; + if (src1[1] == src2[0] && src0[0] != src2[0] && src1[-1] != src2[0]) + dst1[1] =src2[0]; + else + dst1[1] =src1[0]; + + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + --count; + } + + /* last pixel */ + if (src1[-1] == src0[0] && src2[0] != src0[0]) + dst0[0] =src0[0]; + else + dst0[0] =src1[0]; + if (src1[-1] == src2[0] && src0[0] != src2[0]) + dst1[0] =src2[0]; + else + dst1[0] =src1[0]; + dst0[1] =src1[0]; + dst1[1] =src1[0]; +} + +static void internal_scale2x_32_def(u32* dst0, + u32* dst1, + const u32* src0, + const u32* src1, + const u32* src2, + unsigned count) { + /* first pixel */ + dst0[0] = src1[0]; + dst1[0] = src1[0]; + if (src1[1] == src0[0] && src2[0] != src0[0]) + dst0[1] = src0[0]; + else + dst0[1] = src1[0]; + if (src1[1] == src2[0] && src0[0] != src2[0]) + dst1[1] = src2[0]; + else + dst1[1] = src1[0]; + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + + /* central pixels */ + count -= 2; + while (count) { + if (src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0]) + dst0[0] = src0[0]; + else + dst0[0] = src1[0]; + if (src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0]) + dst0[1] = src0[0]; + else + dst0[1] = src1[0]; + + if (src1[-1] == src2[0] && src0[0] != src2[0] && src1[1] != src2[0]) + dst1[0] = src2[0]; + else + dst1[0] = src1[0]; + if (src1[1] == src2[0] && src0[0] != src2[0] && src1[-1] != src2[0]) + dst1[1] = src2[0]; + else + dst1[1] = src1[0]; + + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + --count; + } + + /* last pixel */ + if (src1[-1] == src0[0] && src2[0] != src0[0]) + dst0[0] = src0[0]; + else + dst0[0] = src1[0]; + if (src1[-1] == src2[0] && src0[0] != src2[0]) + dst1[0] = src2[0]; + else + dst1[0] = src1[0]; + dst0[1] = src1[0]; + dst1[1] = src1[0]; +} + +#ifdef MMX +static void internal_scale2x_16_mmx_single(u16* dst, const u16* src0, const u16* src1, const u16* src2, unsigned count) { + /* always do the first and last run */ + count -= 2*4; + +#ifdef __GNUC__ + __asm__ __volatile__( + /* first run */ + /* set the current, current_pre, current_next registers */ + "pxor %%mm0,%%mm0\n" /* use a fake black out of screen */ + "movq 0(%1),%%mm7\n" + "movq 8(%1),%%mm1\n" + "psrlq $48,%%mm0\n" + "psllq $48,%%mm1\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $16,%%mm2\n" + "psrlq $16,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst0 on %%mm2 */ + /* compute the upper-right pixel for dst0 on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqw %%mm6,%%mm2\n" + "pcmpeqw %%mm6,%%mm4\n" + "pcmpeqw (%2),%%mm3\n" + "pcmpeqw (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqw %%mm1,%%mm2\n" + "pcmpeqw %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst0 */ + "movq %%mm2,%%mm3\n" + "punpcklwd %%mm4,%%mm2\n" + "punpckhwd %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + + /* next */ + "addl $8,%0\n" + "addl $8,%1\n" + "addl $8,%2\n" + "addl $16,%3\n" + + /* central runs */ + "shrl $2,%4\n" + "jz 1f\n" + ASM_JUMP_ALIGN + "0:\n" + + /* set the current, current_pre, current_next registers */ + "movq -8(%1),%%mm0\n" + "movq (%1),%%mm7\n" + "movq 8(%1),%%mm1\n" + "psrlq $48,%%mm0\n" + "psllq $48,%%mm1\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $16,%%mm2\n" + "psrlq $16,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst0 on %%mm2 */ + /* compute the upper-right pixel for dst0 on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqw %%mm6,%%mm2\n" + "pcmpeqw %%mm6,%%mm4\n" + "pcmpeqw (%2),%%mm3\n" + "pcmpeqw (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqw %%mm1,%%mm2\n" + "pcmpeqw %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst0 */ + "movq %%mm2,%%mm3\n" + "punpcklwd %%mm4,%%mm2\n" + "punpckhwd %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + + /* next */ + "addl $8,%0\n" + "addl $8,%1\n" + "addl $8,%2\n" + "addl $16,%3\n" + + "decl %4\n" + "jnz 0b\n" + "1:\n" + + /* final run */ + /* set the current, current_pre, current_next registers */ + "movq -8(%1),%%mm0\n" + "movq (%1),%%mm7\n" + "pxor %%mm1,%%mm1\n" /* use a fake black out of screen */ + "psrlq $48,%%mm0\n" + "psllq $48,%%mm1\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $16,%%mm2\n" + "psrlq $16,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst0 on %%mm2 */ + /* compute the upper-right pixel for dst0 on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqw %%mm6,%%mm2\n" + "pcmpeqw %%mm6,%%mm4\n" + "pcmpeqw (%2),%%mm3\n" + "pcmpeqw (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqw %%mm1,%%mm2\n" + "pcmpeqw %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst0 */ + "movq %%mm2,%%mm3\n" + "punpcklwd %%mm4,%%mm2\n" + "punpckhwd %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + "emms\n" + + : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count) + : + : "cc" + ); +#else + __asm { + mov eax, src0; + mov ebx, src1; + mov ecx, src2; + mov edx, dst; + mov esi, count; + + /* first run */ + /* set the current, current_pre, current_next registers */ + pxor mm0,mm0; /* use a fake black out of screen */ + movq mm7, qword ptr [ebx]; + movq mm1, qword ptr [ebx + 8]; + psrlq mm0, 48; + psllq mm1, 48; + movq mm2, mm7; + movq mm3, mm7; + psllq mm2, 16; + psrlq mm3, 16; + por mm0, mm2; + por mm1, mm3; + + /* current_upper */ + movq mm6, qword ptr [eax]; + + /* compute the upper-left pixel for dst0 on %%mm2 */ + /* compute the upper-right pixel for dst0 on %%mm4 */ + movq mm2, mm0; + movq mm4, mm1; + movq mm3, mm0; + movq mm5, mm1; + pcmpeqw mm2, mm6; + pcmpeqw mm4, mm6; + pcmpeqw mm3, qword ptr [ecx]; + pcmpeqw mm5, qword ptr [ecx]; + pandn mm3,mm2; + pandn mm5,mm4; + movq mm2,mm0; + movq mm4,mm1; + pcmpeqw mm2,mm1; + pcmpeqw mm4,mm0; + pandn mm2,mm3; + pandn mm4,mm5; + movq mm3,mm2; + movq mm5,mm4; + pand mm2,mm6; + pand mm4,mm6; + pandn mm3,mm7; + pandn mm5,mm7; + por mm2,mm3; + por mm4,mm5; + + /* set *dst0 */ + movq mm3,mm2; + punpcklwd mm2,mm4; + punpckhwd mm3,mm4; + movq qword ptr [edx], mm2; + movq qword ptr [edx + 8], mm3; + + /* next */ + add eax, 8; + add ebx, 8; + add ecx, 8; + add edx, 16; + + /* central runs */ + shr esi, 2; + jz label1; + align 4; + label0: + + /* set the current, current_pre, current_next registers */ + movq mm0, qword ptr [ebx-8]; + movq mm7, qword ptr [ebx]; + movq mm1, qword ptr [ebx+8]; + psrlq mm0,48; + psllq mm1,48; + movq mm2,mm7; + movq mm3,mm7; + psllq mm2,16; + psrlq mm3,16; + por mm0,mm2; + por mm1,mm3; + + /* current_upper */ + movq mm6, qword ptr [eax]; + + /* compute the upper-left pixel for dst0 on %%mm2 */ + /* compute the upper-right pixel for dst0 on %%mm4 */ + movq mm2,mm0; + movq mm4,mm1; + movq mm3,mm0; + movq mm5,mm1; + pcmpeqw mm2,mm6; + pcmpeqw mm4,mm6; + pcmpeqw mm3, qword ptr [ecx]; + pcmpeqw mm5, qword ptr [ecx]; + pandn mm3,mm2; + pandn mm5,mm4; + movq mm2,mm0; + movq mm4,mm1; + pcmpeqw mm2,mm1; + pcmpeqw mm4,mm0; + pandn mm2,mm3; + pandn mm4,mm5; + movq mm3,mm2; + movq mm5,mm4; + pand mm2,mm6; + pand mm4,mm6; + pandn mm3,mm7; + pandn mm5,mm7; + por mm2,mm3; + por mm4,mm5; + + /* set *dst0 */ + movq mm3,mm2; + punpcklwd mm2,mm4; + punpckhwd mm3,mm4; + movq qword ptr [edx], mm2; + movq qword ptr [edx+8], mm3; + + /* next */ + add eax,8; + add ebx,8; + add ecx,8; + add edx,16; + + dec esi; + jnz label0; + label1: + + /* final run */ + /* set the current, current_pre, current_next registers */ + movq mm0, qword ptr [ebx-8]; + movq mm7, qword ptr [ebx]; + pxor mm1,mm1; /* use a fake black out of screen */ + psrlq mm0,48; + psllq mm1,48; + movq mm2,mm7; + movq mm3,mm7; + psllq mm2,16; + psrlq mm3,16; + por mm0,mm2; + por mm1,mm3; + + /* current_upper */ + movq mm6, qword ptr [eax]; + + /* compute the upper-left pixel for dst0 on %%mm2 */ + /* compute the upper-right pixel for dst0 on %%mm4 */ + movq mm2,mm0; + movq mm4,mm1; + movq mm3,mm0; + movq mm5,mm1; + pcmpeqw mm2,mm6; + pcmpeqw mm4,mm6; + pcmpeqw mm3, qword ptr [ecx]; + pcmpeqw mm5, qword ptr [ecx]; + pandn mm3,mm2; + pandn mm5,mm4; + movq mm2,mm0; + movq mm4,mm1; + pcmpeqw mm2,mm1; + pcmpeqw mm4,mm0; + pandn mm2,mm3; + pandn mm4,mm5; + movq mm3,mm2; + movq mm5,mm4; + pand mm2,mm6; + pand mm4,mm6; + pandn mm3,mm7; + pandn mm5,mm7; + por mm2,mm3; + por mm4,mm5; + + /* set *dst0 */ + movq mm3,mm2; + punpcklwd mm2,mm4; + punpckhwd mm3,mm4; + movq qword ptr [edx], mm2; + movq qword ptr [edx+8], mm3; + + mov src0, eax; + mov src1, ebx; + mov src2, ecx; + mov dst, edx; + mov count, esi; + + emms; + } +#endif +} + +static void internal_scale2x_32_mmx_single(u32* dst, const u32* src0, const u32* src1, const u32* src2, unsigned count) { + /* always do the first and last run */ + count -= 2*2; + +#ifdef __GNUC__ + __asm__ __volatile__( + /* first run */ + /* set the current, current_pre, current_next registers */ + "pxor %%mm0,%%mm0\n" /* use a fake black out of screen */ + "movq 0(%1),%%mm7\n" + "movq 8(%1),%%mm1\n" + "psrlq $32,%%mm0\n" + "psllq $32,%%mm1\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $32,%%mm2\n" + "psrlq $32,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst0 on %%mm2 */ + /* compute the upper-right pixel for dst0 on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqd %%mm6,%%mm2\n" + "pcmpeqd %%mm6,%%mm4\n" + "pcmpeqd (%2),%%mm3\n" + "pcmpeqd (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqd %%mm1,%%mm2\n" + "pcmpeqd %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst0 */ + "movq %%mm2,%%mm3\n" + "punpckldq %%mm4,%%mm2\n" + "punpckhdq %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + + /* next */ + "addl $8,%0\n" + "addl $8,%1\n" + "addl $8,%2\n" + "addl $16,%3\n" + + /* central runs */ + "shrl $1,%4\n" + "jz 1f\n" + ASM_JUMP_ALIGN + "0:\n" + + /* set the current, current_pre, current_next registers */ + "movq -8(%1),%%mm0\n" + "movq (%1),%%mm7\n" + "movq 8(%1),%%mm1\n" + "psrlq $32,%%mm0\n" + "psllq $32,%%mm1\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $32,%%mm2\n" + "psrlq $32,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst0 on %%mm2 */ + /* compute the upper-right pixel for dst0 on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqd %%mm6,%%mm2\n" + "pcmpeqd %%mm6,%%mm4\n" + "pcmpeqd (%2),%%mm3\n" + "pcmpeqd (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqd %%mm1,%%mm2\n" + "pcmpeqd %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst0 */ + "movq %%mm2,%%mm3\n" + "punpckldq %%mm4,%%mm2\n" + "punpckhdq %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + + /* next */ + "addl $8,%0\n" + "addl $8,%1\n" + "addl $8,%2\n" + "addl $16,%3\n" + + "decl %4\n" + "jnz 0b\n" + "1:\n" + + /* final run */ + /* set the current, current_pre, current_next registers */ + "movq -8(%1),%%mm0\n" + "movq (%1),%%mm7\n" + "pxor %%mm1,%%mm1\n" /* use a fake black out of screen */ + "psrlq $32,%%mm0\n" + "psllq $32,%%mm1\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $32,%%mm2\n" + "psrlq $32,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst0 on %%mm2 */ + /* compute the upper-right pixel for dst0 on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqd %%mm6,%%mm2\n" + "pcmpeqd %%mm6,%%mm4\n" + "pcmpeqd (%2),%%mm3\n" + "pcmpeqd (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqd %%mm1,%%mm2\n" + "pcmpeqd %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst0 */ + "movq %%mm2,%%mm3\n" + "punpckldq %%mm4,%%mm2\n" + "punpckhdq %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + "emms\n" + + : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count) + : + : "cc" + ); +#else + __asm { + mov eax, src0; + mov ebx, src1; + mov ecx, src2; + mov edx, dst; + mov esi, count; + + /* first run */ + /* set the current, current_pre, current_next registers */ + pxor mm0,mm0; + movq mm7,qword ptr [ebx]; + movq mm1,qword ptr [ebx + 8]; + psrlq mm0,32; + psllq mm1,32; + movq mm2,mm7; + movq mm3,mm7; + psllq mm2,32; + psrlq mm3,32; + por mm0,mm2; + por mm1,mm3; + + /* current_upper */ + movq mm6,qword ptr [eax]; + + /* compute the upper-left pixel for dst0 on %%mm2 */ + /* compute the upper-right pixel for dst0 on %%mm4 */ + movq mm2,mm0; + movq mm4,mm1; + movq mm3,mm0; + movq mm5,mm1; + pcmpeqd mm2,mm6; + pcmpeqd mm4,mm6; + pcmpeqd mm3,qword ptr [ecx]; + pcmpeqd mm5,qword ptr [ecx]; + pandn mm3,mm2; + pandn mm5,mm4; + movq mm2,mm0; + movq mm4,mm1; + pcmpeqd mm2,mm1; + pcmpeqd mm4,mm0; + pandn mm2,mm3; + pandn mm4,mm5; + movq mm3,mm2; + movq mm5,mm4; + pand mm2,mm6; + pand mm4,mm6; + pandn mm3,mm7; + pandn mm5,mm7; + por mm2,mm3; + por mm4,mm5; + + /* set *dst0 */ + movq mm3,mm2; + punpckldq mm2,mm4; + punpckhdq mm3,mm4; + movq qword ptr [edx],mm2; + movq qword ptr [edx+8],mm3; + + /* next */ + add eax,8; + add ebx,8; + add ecx,8; + add edx,16; + + /* central runs */ + shr esi,1; + jz label1; +label0: + + /* set the current, current_pre, current_next registers */ + movq mm0,qword ptr [ebx-8]; + movq mm7,qword ptr [ebx]; + movq mm1,qword ptr [ebx+8]; + psrlq mm0,32; + psllq mm1,32; + movq mm2,mm7; + movq mm3,mm7; + psllq mm2,32; + psrlq mm3,32; + por mm0,mm2; + por mm1,mm3; + + /* current_upper */ + movq mm6,qword ptr[eax]; + + /* compute the upper-left pixel for dst0 on %%mm2 */ + /* compute the upper-right pixel for dst0 on %%mm4 */ + movq mm2,mm0; + movq mm4,mm1; + movq mm3,mm0; + movq mm5,mm1; + pcmpeqd mm2,mm6; + pcmpeqd mm4,mm6; + pcmpeqd mm3,qword ptr[ecx]; + pcmpeqd mm5,qword ptr[ecx]; + pandn mm3,mm2; + pandn mm5,mm4; + movq mm2,mm0; + movq mm4,mm1; + pcmpeqd mm2,mm1; + pcmpeqd mm4,mm0; + pandn mm2,mm3; + pandn mm4,mm5; + movq mm3,mm2; + movq mm5,mm4; + pand mm2,mm6; + pand mm4,mm6; + pandn mm3,mm7; + pandn mm5,mm7; + por mm2,mm3; + por mm4,mm5; + + /* set *dst0 */ + movq mm3,mm2; + punpckldq mm2,mm4; + punpckhdq mm3,mm4; + movq qword ptr [edx],mm2; + movq qword ptr [edx+8],mm3; + + /* next */ + add eax,8; + add ebx,8; + add ecx,8; + add edx,16; + + dec esi; + jnz label0; +label1: + + /* final run */ + /* set the current, current_pre, current_next registers */ + movq mm0,qword ptr [ebx-8]; + movq mm7,qword ptr [ebx]; + pxor mm1,mm1; + psrlq mm0,32; + psllq mm1,32; + movq mm2,mm7; + movq mm3,mm7; + psllq mm2,32; + psrlq mm3,32; + por mm0,mm2; + por mm1,mm3; + + /* current_upper */ + movq mm6,qword ptr [eax]; + + /* compute the upper-left pixel for dst0 on %%mm2 */ + /* compute the upper-right pixel for dst0 on %%mm4 */ + movq mm2,mm0; + movq mm4,mm1; + movq mm3,mm0; + movq mm5,mm1; + pcmpeqd mm2,mm6; + pcmpeqd mm4,mm6; + pcmpeqd mm3,qword ptr [ecx]; + pcmpeqd mm5,qword ptr [ecx]; + pandn mm3,mm2; + pandn mm5,mm4; + movq mm2,mm0; + movq mm4,mm1; + pcmpeqd mm2,mm1; + pcmpeqd mm4,mm0; + pandn mm2,mm3; + pandn mm4,mm5; + movq mm3,mm2; + movq mm5,mm4; + pand mm2,mm6; + pand mm4,mm6; + pandn mm3,mm7; + pandn mm5,mm7; + por mm2,mm3; + por mm4,mm5; + + /* set *dst0 */ + movq mm3,mm2; + punpckldq mm2,mm4; + punpckhdq mm3,mm4; + movq qword ptr [edx],mm2; + movq qword ptr [edx+8],mm3; + + mov src0, eax; + mov src1, ebx; + mov src2, ecx; + mov dst, edx; + mov count, esi; + + emms; + } +#endif +} + +static void internal_scale2x_16_mmx(u16* dst0, u16* dst1, const u16* src0, const u16* src1, const u16* src2, unsigned count) { + // assert( count >= 2*4 ); + internal_scale2x_16_mmx_single(dst0, src0, src1, src2, count); + internal_scale2x_16_mmx_single(dst1, src2, src1, src0, count); +} + +static void internal_scale2x_32_mmx(u32* dst0, u32* dst1, const u32* src0, const u32* src1, const u32* src2, unsigned count) { + // assert( count >= 2*2 ); + internal_scale2x_32_mmx_single(dst0, src0, src1, src2, count); + internal_scale2x_32_mmx_single(dst1, src2, src1, src0, count); +} +#endif + +void AdMame2x(u8 *srcPtr, u32 srcPitch, /* u8 deltaPtr, */ + u8 *dstPtr, u32 dstPitch, int width, int height) +{ + u16 *dst0 = (u16 *)dstPtr; + u16 *dst1 = dst0 + (dstPitch/2); + + u16 *src0 = (u16 *)srcPtr; + u16 *src1 = src0 + (srcPitch/2); + u16 *src2 = src1 + (srcPitch/2); +#ifdef MMX + if(cpu_mmx) { + internal_scale2x_16_mmx(dst0, dst1, src0, src0, src1, width); + + { + int count = height; + + count -= 2; + while(count) { + dst0 += dstPitch; + dst1 += dstPitch; + internal_scale2x_16_mmx(dst0, dst1, src0, src1, src2, width); + src0 = src1; + src1 = src2; + src2 += srcPitch/2; + --count; + } + } + dst0 += dstPitch; + dst1 += dstPitch; + internal_scale2x_16_mmx(dst0, dst1, src0, src1, src1, width); + } else { +#endif + internal_scale2x_16_def(dst0, dst1, src0, src0, src1, width); + + { + int count = height; + + count -= 2; + while(count) { + dst0 += dstPitch; + dst1 += dstPitch; + internal_scale2x_16_def(dst0, dst1, src0, src1, src2, width); + src0 = src1; + src1 = src2; + src2 += srcPitch/2; + --count; + } + } + dst0 += dstPitch; + dst1 += dstPitch; + internal_scale2x_16_def(dst0, dst1, src0, src1, src1, width); +#ifdef MMX + } +#endif +} + +void AdMame2x32(u8 *srcPtr, u32 srcPitch, /* u8 deltaPtr, */ + u8 *dstPtr, u32 dstPitch, int width, int height) +{ + u32 *dst0 = (u32 *)dstPtr; + u32 *dst1 = dst0 + (dstPitch/4); + + u32 *src0 = (u32 *)srcPtr; + u32 *src1 = src0 + (srcPitch/4); + u32 *src2 = src1 + (srcPitch/4); +#ifdef MMX + if(cpu_mmx) { + internal_scale2x_32_mmx(dst0, dst1, src0, src0, src1, width); + + { + int count = height; + + count -= 2; + while(count) { + dst0 += dstPitch/2; + dst1 += dstPitch/2; + internal_scale2x_32_mmx(dst0, dst1, src0, src1, src2, width); + src0 = src1; + src1 = src2; + src2 += srcPitch/4; + --count; + } + } + dst0 += dstPitch/2; + dst1 += dstPitch/2; + internal_scale2x_32_mmx(dst0, dst1, src0, src1, src1, width); + } else { +#endif + internal_scale2x_32_def(dst0, dst1, src0, src0, src1, width); + { + int count = height; + + count -= 2; + while(count) { + dst0 += dstPitch/2; + dst1 += dstPitch/2; + internal_scale2x_32_def(dst0, dst1, src0, src1, src2, width); + src0 = src1; + src1 = src2; + src2 += srcPitch/4; + --count; + } + } + dst0 += dstPitch/2; + dst1 += dstPitch/2; + internal_scale2x_32_def(dst0, dst1, src0, src1, src1, width); +#ifdef MMX + } +#endif +} + + + +unsigned int LUT16to32[65536]; +unsigned int RGBtoYUV[65536]; + +void hq_init (int rb, int gb, int bb, int rs, int gs, int bs) +{ + int i, j, k, r, g, b, Y, u, v; + int rmask, gmask, bmask; + + rmask = ((1 << rb) - 1) << rs; + gmask = ((1 << gb) - 1) << gs; + bmask = ((1 << bb) - 1) << bs; + + for (i=0; i<65536; i++) + LUT16to32[i] = ((i & 0xF800) << 8) + ((i & 0x07E0) << 5) + ((i & 0x001F) << 3); + + for (i=0; i<32; i++) { + for (j=0; j<64; j++) { + for (k=0; k<32; k++) { + r = i << 3; + g = j << 2; + b = k << 3; + Y = (r + g + b) >> 2; + u = 128 + ((r - b) >> 2); + v = 128 + ((-r + 2*g -b)>>3); + RGBtoYUV[ (i << 11) + (j << 5) + k ] = (Y<<16) + (u<<8) + v; + } + } + } +} + diff --git a/od-win32/scaler2.c b/od-win32/scaler2.c new file mode 100755 index 00000000..6b215b21 --- /dev/null +++ b/od-win32/scaler2.c @@ -0,0 +1,1522 @@ +/* This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Scaler (except Scale2x) code borrowed from ScummVM project */ + +#include "filter.h" + +static uint32 colorMask; +static uint32 lowPixelMask; +static uint32 qcolorMask; +static uint32 qlowpixelMask; +static uint32 redblueMask; +static uint32 redMask; +static uint32 greenMask; +static uint32 blueMask; + +int Init_2xSaI (int rb, int gb, int bb, int rs, int gs, int bs) +{ + if (rb + gb + bb == 16) { + colorMask = 0xF7DEF7DE; + lowPixelMask = 0x08210821; + qcolorMask = 0xE79CE79C; + qlowpixelMask = 0x18631863; + redblueMask = 0xF81F; + redMask = 0xF800; + greenMask = 0x07E0; + blueMask = 0x001F; + } else if (rb + gb + bb == 15) { + colorMask = 0x7BDE7BDE; + lowPixelMask = 0x04210421; + qcolorMask = 0x739C739C; + qlowpixelMask = 0x0C630C63; + redblueMask = 0x7C1F; + redMask = 0x7C00; + greenMask = 0x03E0; + blueMask = 0x001F; + } else { + return 0; + } + + return 1; +} + +static _inline int GetResult(uint32 A, uint32 B, uint32 C, uint32 D) +{ + const bool ac = (A==C); + const bool bc = (B==C); + const int x1 = ac; + const int y1 = (bc & !ac); + const bool ad = (A==D); + const bool bd = (B==D); + const int x2 = ad; + const int y2 = (bd & !ad); + const int x = x1+x2; + const int y = y1+y2; + static const int rmap[3][3] = { + {0, 0, -1}, + {0, 0, -1}, + {1, 1, 0} + }; + return rmap[y][x]; +} + +static _inline uint32 INTERPOLATE(uint32 A, uint32 B) { + if (A != B) { + return (((A & colorMask) >> 1) + ((B & colorMask) >> 1) + (A & B & lowPixelMask)); + } else + return A; +} + +static _inline uint32 Q_INTERPOLATE(uint32 A, uint32 B, uint32 C, uint32 D) { + register uint32 x = ((A & qcolorMask) >> 2) + ((B & qcolorMask) >> 2) + ((C & qcolorMask) >> 2) + ((D & qcolorMask) >> 2); + register uint32 y = ((A & qlowpixelMask) + (B & qlowpixelMask) + (C & qlowpixelMask) + (D & qlowpixelMask)) >> 2; + + y &= qlowpixelMask; + return x + y; +} + +void Super2xSaI(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) { + const uint16 *bP; + uint16 *dP; + const uint32 nextlineSrc = srcPitch >> 1; + + while (height--) { + int i; + bP = (const uint16 *)srcPtr; + dP = (uint16 *)dstPtr; + + for (i = 0; i < width; ++i) { + uint32 color4, color5, color6; + uint32 color1, color2, color3; + uint32 colorA0, colorA1, colorA2, colorA3; + uint32 colorB0, colorB1, colorB2, colorB3; + uint32 colorS1, colorS2; + uint32 product1a, product1b, product2a, product2b; + +//--------------------------------------- B1 B2 +// 4 5 6 S2 +// 1 2 3 S1 +// A1 A2 + + colorB0 = *(bP - nextlineSrc - 1); + colorB1 = *(bP - nextlineSrc); + colorB2 = *(bP - nextlineSrc + 1); + colorB3 = *(bP - nextlineSrc + 2); + + color4 = *(bP - 1); + color5 = *(bP); + color6 = *(bP + 1); + colorS2 = *(bP + 2); + + color1 = *(bP + nextlineSrc - 1); + color2 = *(bP + nextlineSrc); + color3 = *(bP + nextlineSrc + 1); + colorS1 = *(bP + nextlineSrc + 2); + + colorA0 = *(bP + 2 * nextlineSrc - 1); + colorA1 = *(bP + 2 * nextlineSrc); + colorA2 = *(bP + 2 * nextlineSrc + 1); + colorA3 = *(bP + 2 * nextlineSrc + 2); + +//-------------------------------------- + if (color2 == color6 && color5 != color3) { + product2b = product1b = color2; + } else if (color5 == color3 && color2 != color6) { + product2b = product1b = color5; + } else if (color5 == color3 && color2 == color6) { + register int r = 0; + + r += GetResult(color6, color5, color1, colorA1); + r += GetResult(color6, color5, color4, colorB1); + r += GetResult(color6, color5, colorA2, colorS1); + r += GetResult(color6, color5, colorB2, colorS2); + + if (r > 0) + product2b = product1b = color6; + else if (r < 0) + product2b = product1b = color5; + else { + product2b = product1b = INTERPOLATE(color5, color6); + } + } else { + if (color6 == color3 && color3 == colorA1 && color2 != colorA2 && color3 != colorA0) + product2b = Q_INTERPOLATE(color3, color3, color3, color2); + else if (color5 == color2 && color2 == colorA2 && colorA1 != color3 && color2 != colorA3) + product2b = Q_INTERPOLATE(color2, color2, color2, color3); + else + product2b = INTERPOLATE(color2, color3); + + if (color6 == color3 && color6 == colorB1 && color5 != colorB2 && color6 != colorB0) + product1b = Q_INTERPOLATE(color6, color6, color6, color5); + else if (color5 == color2 && color5 == colorB2 && colorB1 != color6 && color5 != colorB3) + product1b = Q_INTERPOLATE(color6, color5, color5, color5); + else + product1b = INTERPOLATE(color5, color6); + } + + if (color5 == color3 && color2 != color6 && color4 == color5 && color5 != colorA2) + product2a = INTERPOLATE(color2, color5); + else if (color5 == color1 && color6 == color5 && color4 != color2 && color5 != colorA0) + product2a = INTERPOLATE(color2, color5); + else + product2a = color2; + + if (color2 == color6 && color5 != color3 && color1 == color2 && color2 != colorB2) + product1a = INTERPOLATE(color2, color5); + else if (color4 == color2 && color3 == color2 && color1 != color5 && color2 != colorB0) + product1a = INTERPOLATE(color2, color5); + else + product1a = color5; + + *(dP + 0) = (uint16) product1a; + *(dP + 1) = (uint16) product1b; + *(dP + dstPitch/2 + 0) = (uint16) product2a; + *(dP + dstPitch/2 + 1) = (uint16) product2b; + + bP += 1; + dP += 2; + } + + srcPtr += srcPitch; + dstPtr += dstPitch * 2; + } +} + +void SuperEagle(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) { + const uint16 *bP; + uint16 *dP; + const uint32 nextlineSrc = srcPitch >> 1; + + while (height--) { + int i; + bP = (const uint16 *)srcPtr; + dP = (uint16 *)dstPtr; + for (i = 0; i < width; ++i) { + uint32 color4, color5, color6; + uint32 color1, color2, color3; + uint32 colorA1, colorA2, colorB1, colorB2, colorS1, colorS2; + uint32 product1a, product1b, product2a, product2b; + + colorB1 = *(bP - nextlineSrc); + colorB2 = *(bP - nextlineSrc + 1); + + color4 = *(bP - 1); + color5 = *(bP); + color6 = *(bP + 1); + colorS2 = *(bP + 2); + + color1 = *(bP + nextlineSrc - 1); + color2 = *(bP + nextlineSrc); + color3 = *(bP + nextlineSrc + 1); + colorS1 = *(bP + nextlineSrc + 2); + + colorA1 = *(bP + 2 * nextlineSrc); + colorA2 = *(bP + 2 * nextlineSrc + 1); + + // -------------------------------------- + if (color5 != color3) + { + if (color2 == color6) + { + product1b = product2a = color2; + if ((color1 == color2) || (color6 == colorB2)) { + product1a = INTERPOLATE(color2, color5); + product1a = INTERPOLATE(color2, product1a); + } else { + product1a = INTERPOLATE(color5, color6); + } + + if ((color6 == colorS2) || (color2 == colorA1)) { + product2b = INTERPOLATE(color2, color3); + product2b = INTERPOLATE(color2, product2b); + } else { + product2b = INTERPOLATE(color2, color3); + } + } + else + { + product2b = product1a = INTERPOLATE(color2, color6); + product2b = Q_INTERPOLATE(color3, color3, color3, product2b); + product1a = Q_INTERPOLATE(color5, color5, color5, product1a); + + product2a = product1b = INTERPOLATE(color5, color3); + product2a = Q_INTERPOLATE(color2, color2, color2, product2a); + product1b = Q_INTERPOLATE(color6, color6, color6, product1b); + } + } + else //if (color5 == color3) + { + if (color2 != color6) + { + product2b = product1a = color5; + + if ((colorB1 == color5) || (color3 == colorS1)) { + product1b = INTERPOLATE(color5, color6); + product1b = INTERPOLATE(color5, product1b); + } else { + product1b = INTERPOLATE(color5, color6); + } + + if ((color3 == colorA2) || (color4 == color5)) { + product2a = INTERPOLATE(color5, color2); + product2a = INTERPOLATE(color5, product2a); + } else { + product2a = INTERPOLATE(color2, color3); + } + } + else //if (color2 != color6) + { + register int r = 0; + + r += GetResult(color6, color5, color1, colorA1); + r += GetResult(color6, color5, color4, colorB1); + r += GetResult(color6, color5, colorA2, colorS1); + r += GetResult(color6, color5, colorB2, colorS2); + + if (r > 0) { + product1b = product2a = color2; + product1a = product2b = INTERPOLATE(color5, color6); + } else if (r < 0) { + product2b = product1a = color5; + product1b = product2a = INTERPOLATE(color5, color6); + } else { + product2b = product1a = color5; + product1b = product2a = color2; + } + } + } + + *(dP + 0) = (uint16) product1a; + *(dP + 1) = (uint16) product1b; + *(dP + dstPitch/2 + 0) = (uint16) product2a; + *(dP + dstPitch/2 + 1) = (uint16) product2b; + + bP += 1; + dP += 2; + } + + srcPtr += srcPitch; + dstPtr += dstPitch * 2; + } +} + +void _2xSaI(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) { + const uint16 *bP; + uint16 *dP; + const uint32 nextlineSrc = srcPitch >> 1; + + while (height--) { + int i; + bP = (const uint16 *)srcPtr; + dP = (uint16 *)dstPtr; + + for (i = 0; i < width; ++i) { + + register uint32 colorA, colorB; + uint32 colorC, colorD, + colorE, colorF, colorG, colorH, colorI, colorJ, colorK, colorL, colorM, colorN, colorO, colorP; + uint32 product, product1, product2; + +//--------------------------------------- +// Map of the pixels: I|E F|J +// G|A B|K +// H|C D|L +// M|N O|P + colorI = *(bP - nextlineSrc - 1); + colorE = *(bP - nextlineSrc); + colorF = *(bP - nextlineSrc + 1); + colorJ = *(bP - nextlineSrc + 2); + + colorG = *(bP - 1); + colorA = *(bP); + colorB = *(bP + 1); + colorK = *(bP + 2); + + colorH = *(bP + nextlineSrc - 1); + colorC = *(bP + nextlineSrc); + colorD = *(bP + nextlineSrc + 1); + colorL = *(bP + nextlineSrc + 2); + + colorM = *(bP + 2 * nextlineSrc - 1); + colorN = *(bP + 2 * nextlineSrc); + colorO = *(bP + 2 * nextlineSrc + 1); + colorP = *(bP + 2 * nextlineSrc + 2); + + if ((colorA == colorD) && (colorB != colorC)) { + if (((colorA == colorE) && (colorB == colorL)) || + ((colorA == colorC) && (colorA == colorF) && (colorB != colorE) && (colorB == colorJ))) { + product = colorA; + } else { + product = INTERPOLATE(colorA, colorB); + } + + if (((colorA == colorG) && (colorC == colorO)) || + ((colorA == colorB) && (colorA == colorH) && (colorG != colorC) && (colorC == colorM))) { + product1 = colorA; + } else { + product1 = INTERPOLATE(colorA, colorC); + } + product2 = colorA; + } else if ((colorB == colorC) && (colorA != colorD)) { + if (((colorB == colorF) && (colorA == colorH)) || + ((colorB == colorE) && (colorB == colorD) && (colorA != colorF) && (colorA == colorI))) { + product = colorB; + } else { + product = INTERPOLATE(colorA, colorB); + } + + if (((colorC == colorH) && (colorA == colorF)) || + ((colorC == colorG) && (colorC == colorD) && (colorA != colorH) && (colorA == colorI))) { + product1 = colorC; + } else { + product1 = INTERPOLATE(colorA, colorC); + } + product2 = colorB; + } else if ((colorA == colorD) && (colorB == colorC)) { + if (colorA == colorB) { + product = colorA; + product1 = colorA; + product2 = colorA; + } else { + register int r = 0; + + product1 = INTERPOLATE(colorA, colorC); + product = INTERPOLATE(colorA, colorB); + + r += GetResult(colorA, colorB, colorG, colorE); + r -= GetResult(colorB, colorA, colorK, colorF); + r -= GetResult(colorB, colorA, colorH, colorN); + r += GetResult(colorA, colorB, colorL, colorO); + + if (r > 0) + product2 = colorA; + else if (r < 0) + product2 = colorB; + else { + product2 = Q_INTERPOLATE(colorA, colorB, colorC, colorD); + } + } + } else { + product2 = Q_INTERPOLATE(colorA, colorB, colorC, colorD); + + if ((colorA == colorC) && (colorA == colorF) + && (colorB != colorE) && (colorB == colorJ)) { + product = colorA; + } else if ((colorB == colorE) && (colorB == colorD) + && (colorA != colorF) && (colorA == colorI)) { + product = colorB; + } else { + product = INTERPOLATE(colorA, colorB); + } + + if ((colorA == colorB) && (colorA == colorH) + && (colorG != colorC) && (colorC == colorM)) { + product1 = colorA; + } else if ((colorC == colorG) && (colorC == colorD) + && (colorA != colorH) && (colorA == colorI)) { + product1 = colorC; + } else { + product1 = INTERPOLATE(colorA, colorC); + } + } + + *(dP + 0) = (uint16) colorA; + *(dP + 1) = (uint16) product; + *(dP + dstPitch/2 + 0) = (uint16) product1; + *(dP + dstPitch/2 + 1) = (uint16) product2; + + bP += 1; + dP += 2; + } + + srcPtr += srcPitch; + dstPtr += dstPitch * 2; + } +} + + +/* + * This file is part of the Advance project. + * + * Copyright (C) 1999-2002 Andrea Mazzoleni + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * This file contains a C and MMX implentation of the Scale2x effect. + * + * You can found an high level description of the effect at : + * + * http://scale2x.sourceforge.net/scale2x.html + * + * Alternatively at the previous license terms, you are allowed to use this + * code in your program with these conditions: + * - the program is not used in commercial activities. + * - the whole source code of the program is released with the binary. + * - derivative works of the program are allowed. + */ + +#define MMX +extern int cpu_mmx; + +/* Suggested in "Intel Optimization" for Pentium II */ +#define ASM_JUMP_ALIGN ".p2align 4\n" + +static void internal_scale2x_16_def(u16 *dst0, u16* dst1, const u16* src0, const u16* src1, const u16* src2, unsigned count) { + /* first pixel */ + dst0[0] = src1[0]; + dst1[0] = src1[0]; + if (src1[1] == src0[0] && src2[0] != src0[0]) + dst0[1] =src0[0]; + else + dst0[1] =src1[0]; + if (src1[1] == src2[0] && src0[0] != src2[0]) + dst1[1] =src2[0]; + else + dst1[1] =src1[0]; + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + + /* central pixels */ + count -= 2; + while (count) { + if (src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0]) + dst0[0] = src0[0]; + else + dst0[0] = src1[0]; + if (src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0]) + dst0[1] =src0[0]; + else + dst0[1] =src1[0]; + + if (src1[-1] == src2[0] && src0[0] != src2[0] && src1[1] != src2[0]) + dst1[0] =src2[0]; + else + dst1[0] =src1[0]; + if (src1[1] == src2[0] && src0[0] != src2[0] && src1[-1] != src2[0]) + dst1[1] =src2[0]; + else + dst1[1] =src1[0]; + + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + --count; + } + + /* last pixel */ + if (src1[-1] == src0[0] && src2[0] != src0[0]) + dst0[0] =src0[0]; + else + dst0[0] =src1[0]; + if (src1[-1] == src2[0] && src0[0] != src2[0]) + dst1[0] =src2[0]; + else + dst1[0] =src1[0]; + dst0[1] =src1[0]; + dst1[1] =src1[0]; +} + +static void internal_scale2x_32_def(u32* dst0, + u32* dst1, + const u32* src0, + const u32* src1, + const u32* src2, + unsigned count) { + /* first pixel */ + dst0[0] = src1[0]; + dst1[0] = src1[0]; + if (src1[1] == src0[0] && src2[0] != src0[0]) + dst0[1] = src0[0]; + else + dst0[1] = src1[0]; + if (src1[1] == src2[0] && src0[0] != src2[0]) + dst1[1] = src2[0]; + else + dst1[1] = src1[0]; + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + + /* central pixels */ + count -= 2; + while (count) { + if (src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0]) + dst0[0] = src0[0]; + else + dst0[0] = src1[0]; + if (src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0]) + dst0[1] = src0[0]; + else + dst0[1] = src1[0]; + + if (src1[-1] == src2[0] && src0[0] != src2[0] && src1[1] != src2[0]) + dst1[0] = src2[0]; + else + dst1[0] = src1[0]; + if (src1[1] == src2[0] && src0[0] != src2[0] && src1[-1] != src2[0]) + dst1[1] = src2[0]; + else + dst1[1] = src1[0]; + + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + --count; + } + + /* last pixel */ + if (src1[-1] == src0[0] && src2[0] != src0[0]) + dst0[0] = src0[0]; + else + dst0[0] = src1[0]; + if (src1[-1] == src2[0] && src0[0] != src2[0]) + dst1[0] = src2[0]; + else + dst1[0] = src1[0]; + dst0[1] = src1[0]; + dst1[1] = src1[0]; +} + +#ifdef MMX +static void internal_scale2x_16_mmx_single(u16* dst, const u16* src0, const u16* src1, const u16* src2, unsigned count) { + /* always do the first and last run */ + count -= 2*4; + +#ifdef __GNUC__ + __asm__ __volatile__( + /* first run */ + /* set the current, current_pre, current_next registers */ + "pxor %%mm0,%%mm0\n" /* use a fake black out of screen */ + "movq 0(%1),%%mm7\n" + "movq 8(%1),%%mm1\n" + "psrlq $48,%%mm0\n" + "psllq $48,%%mm1\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $16,%%mm2\n" + "psrlq $16,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst0 on %%mm2 */ + /* compute the upper-right pixel for dst0 on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqw %%mm6,%%mm2\n" + "pcmpeqw %%mm6,%%mm4\n" + "pcmpeqw (%2),%%mm3\n" + "pcmpeqw (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqw %%mm1,%%mm2\n" + "pcmpeqw %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst0 */ + "movq %%mm2,%%mm3\n" + "punpcklwd %%mm4,%%mm2\n" + "punpckhwd %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + + /* next */ + "addl $8,%0\n" + "addl $8,%1\n" + "addl $8,%2\n" + "addl $16,%3\n" + + /* central runs */ + "shrl $2,%4\n" + "jz 1f\n" + ASM_JUMP_ALIGN + "0:\n" + + /* set the current, current_pre, current_next registers */ + "movq -8(%1),%%mm0\n" + "movq (%1),%%mm7\n" + "movq 8(%1),%%mm1\n" + "psrlq $48,%%mm0\n" + "psllq $48,%%mm1\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $16,%%mm2\n" + "psrlq $16,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst0 on %%mm2 */ + /* compute the upper-right pixel for dst0 on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqw %%mm6,%%mm2\n" + "pcmpeqw %%mm6,%%mm4\n" + "pcmpeqw (%2),%%mm3\n" + "pcmpeqw (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqw %%mm1,%%mm2\n" + "pcmpeqw %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst0 */ + "movq %%mm2,%%mm3\n" + "punpcklwd %%mm4,%%mm2\n" + "punpckhwd %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + + /* next */ + "addl $8,%0\n" + "addl $8,%1\n" + "addl $8,%2\n" + "addl $16,%3\n" + + "decl %4\n" + "jnz 0b\n" + "1:\n" + + /* final run */ + /* set the current, current_pre, current_next registers */ + "movq -8(%1),%%mm0\n" + "movq (%1),%%mm7\n" + "pxor %%mm1,%%mm1\n" /* use a fake black out of screen */ + "psrlq $48,%%mm0\n" + "psllq $48,%%mm1\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $16,%%mm2\n" + "psrlq $16,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst0 on %%mm2 */ + /* compute the upper-right pixel for dst0 on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqw %%mm6,%%mm2\n" + "pcmpeqw %%mm6,%%mm4\n" + "pcmpeqw (%2),%%mm3\n" + "pcmpeqw (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqw %%mm1,%%mm2\n" + "pcmpeqw %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst0 */ + "movq %%mm2,%%mm3\n" + "punpcklwd %%mm4,%%mm2\n" + "punpckhwd %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + "emms\n" + + : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count) + : + : "cc" + ); +#else + __asm { + mov eax, src0; + mov ebx, src1; + mov ecx, src2; + mov edx, dst; + mov esi, count; + + /* first run */ + /* set the current, current_pre, current_next registers */ + pxor mm0,mm0; /* use a fake black out of screen */ + movq mm7, qword ptr [ebx]; + movq mm1, qword ptr [ebx + 8]; + psrlq mm0, 48; + psllq mm1, 48; + movq mm2, mm7; + movq mm3, mm7; + psllq mm2, 16; + psrlq mm3, 16; + por mm0, mm2; + por mm1, mm3; + + /* current_upper */ + movq mm6, qword ptr [eax]; + + /* compute the upper-left pixel for dst0 on %%mm2 */ + /* compute the upper-right pixel for dst0 on %%mm4 */ + movq mm2, mm0; + movq mm4, mm1; + movq mm3, mm0; + movq mm5, mm1; + pcmpeqw mm2, mm6; + pcmpeqw mm4, mm6; + pcmpeqw mm3, qword ptr [ecx]; + pcmpeqw mm5, qword ptr [ecx]; + pandn mm3,mm2; + pandn mm5,mm4; + movq mm2,mm0; + movq mm4,mm1; + pcmpeqw mm2,mm1; + pcmpeqw mm4,mm0; + pandn mm2,mm3; + pandn mm4,mm5; + movq mm3,mm2; + movq mm5,mm4; + pand mm2,mm6; + pand mm4,mm6; + pandn mm3,mm7; + pandn mm5,mm7; + por mm2,mm3; + por mm4,mm5; + + /* set *dst0 */ + movq mm3,mm2; + punpcklwd mm2,mm4; + punpckhwd mm3,mm4; + movq qword ptr [edx], mm2; + movq qword ptr [edx + 8], mm3; + + /* next */ + add eax, 8; + add ebx, 8; + add ecx, 8; + add edx, 16; + + /* central runs */ + shr esi, 2; + jz label1; + align 4; + label0: + + /* set the current, current_pre, current_next registers */ + movq mm0, qword ptr [ebx-8]; + movq mm7, qword ptr [ebx]; + movq mm1, qword ptr [ebx+8]; + psrlq mm0,48; + psllq mm1,48; + movq mm2,mm7; + movq mm3,mm7; + psllq mm2,16; + psrlq mm3,16; + por mm0,mm2; + por mm1,mm3; + + /* current_upper */ + movq mm6, qword ptr [eax]; + + /* compute the upper-left pixel for dst0 on %%mm2 */ + /* compute the upper-right pixel for dst0 on %%mm4 */ + movq mm2,mm0; + movq mm4,mm1; + movq mm3,mm0; + movq mm5,mm1; + pcmpeqw mm2,mm6; + pcmpeqw mm4,mm6; + pcmpeqw mm3, qword ptr [ecx]; + pcmpeqw mm5, qword ptr [ecx]; + pandn mm3,mm2; + pandn mm5,mm4; + movq mm2,mm0; + movq mm4,mm1; + pcmpeqw mm2,mm1; + pcmpeqw mm4,mm0; + pandn mm2,mm3; + pandn mm4,mm5; + movq mm3,mm2; + movq mm5,mm4; + pand mm2,mm6; + pand mm4,mm6; + pandn mm3,mm7; + pandn mm5,mm7; + por mm2,mm3; + por mm4,mm5; + + /* set *dst0 */ + movq mm3,mm2; + punpcklwd mm2,mm4; + punpckhwd mm3,mm4; + movq qword ptr [edx], mm2; + movq qword ptr [edx+8], mm3; + + /* next */ + add eax,8; + add ebx,8; + add ecx,8; + add edx,16; + + dec esi; + jnz label0; + label1: + + /* final run */ + /* set the current, current_pre, current_next registers */ + movq mm0, qword ptr [ebx-8]; + movq mm7, qword ptr [ebx]; + pxor mm1,mm1; /* use a fake black out of screen */ + psrlq mm0,48; + psllq mm1,48; + movq mm2,mm7; + movq mm3,mm7; + psllq mm2,16; + psrlq mm3,16; + por mm0,mm2; + por mm1,mm3; + + /* current_upper */ + movq mm6, qword ptr [eax]; + + /* compute the upper-left pixel for dst0 on %%mm2 */ + /* compute the upper-right pixel for dst0 on %%mm4 */ + movq mm2,mm0; + movq mm4,mm1; + movq mm3,mm0; + movq mm5,mm1; + pcmpeqw mm2,mm6; + pcmpeqw mm4,mm6; + pcmpeqw mm3, qword ptr [ecx]; + pcmpeqw mm5, qword ptr [ecx]; + pandn mm3,mm2; + pandn mm5,mm4; + movq mm2,mm0; + movq mm4,mm1; + pcmpeqw mm2,mm1; + pcmpeqw mm4,mm0; + pandn mm2,mm3; + pandn mm4,mm5; + movq mm3,mm2; + movq mm5,mm4; + pand mm2,mm6; + pand mm4,mm6; + pandn mm3,mm7; + pandn mm5,mm7; + por mm2,mm3; + por mm4,mm5; + + /* set *dst0 */ + movq mm3,mm2; + punpcklwd mm2,mm4; + punpckhwd mm3,mm4; + movq qword ptr [edx], mm2; + movq qword ptr [edx+8], mm3; + + mov src0, eax; + mov src1, ebx; + mov src2, ecx; + mov dst, edx; + mov count, esi; + + emms; + } +#endif +} + +static void internal_scale2x_32_mmx_single(u32* dst, const u32* src0, const u32* src1, const u32* src2, unsigned count) { + /* always do the first and last run */ + count -= 2*2; + +#ifdef __GNUC__ + __asm__ __volatile__( + /* first run */ + /* set the current, current_pre, current_next registers */ + "pxor %%mm0,%%mm0\n" /* use a fake black out of screen */ + "movq 0(%1),%%mm7\n" + "movq 8(%1),%%mm1\n" + "psrlq $32,%%mm0\n" + "psllq $32,%%mm1\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $32,%%mm2\n" + "psrlq $32,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst0 on %%mm2 */ + /* compute the upper-right pixel for dst0 on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqd %%mm6,%%mm2\n" + "pcmpeqd %%mm6,%%mm4\n" + "pcmpeqd (%2),%%mm3\n" + "pcmpeqd (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqd %%mm1,%%mm2\n" + "pcmpeqd %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst0 */ + "movq %%mm2,%%mm3\n" + "punpckldq %%mm4,%%mm2\n" + "punpckhdq %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + + /* next */ + "addl $8,%0\n" + "addl $8,%1\n" + "addl $8,%2\n" + "addl $16,%3\n" + + /* central runs */ + "shrl $1,%4\n" + "jz 1f\n" + ASM_JUMP_ALIGN + "0:\n" + + /* set the current, current_pre, current_next registers */ + "movq -8(%1),%%mm0\n" + "movq (%1),%%mm7\n" + "movq 8(%1),%%mm1\n" + "psrlq $32,%%mm0\n" + "psllq $32,%%mm1\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $32,%%mm2\n" + "psrlq $32,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst0 on %%mm2 */ + /* compute the upper-right pixel for dst0 on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqd %%mm6,%%mm2\n" + "pcmpeqd %%mm6,%%mm4\n" + "pcmpeqd (%2),%%mm3\n" + "pcmpeqd (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqd %%mm1,%%mm2\n" + "pcmpeqd %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst0 */ + "movq %%mm2,%%mm3\n" + "punpckldq %%mm4,%%mm2\n" + "punpckhdq %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + + /* next */ + "addl $8,%0\n" + "addl $8,%1\n" + "addl $8,%2\n" + "addl $16,%3\n" + + "decl %4\n" + "jnz 0b\n" + "1:\n" + + /* final run */ + /* set the current, current_pre, current_next registers */ + "movq -8(%1),%%mm0\n" + "movq (%1),%%mm7\n" + "pxor %%mm1,%%mm1\n" /* use a fake black out of screen */ + "psrlq $32,%%mm0\n" + "psllq $32,%%mm1\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $32,%%mm2\n" + "psrlq $32,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst0 on %%mm2 */ + /* compute the upper-right pixel for dst0 on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqd %%mm6,%%mm2\n" + "pcmpeqd %%mm6,%%mm4\n" + "pcmpeqd (%2),%%mm3\n" + "pcmpeqd (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqd %%mm1,%%mm2\n" + "pcmpeqd %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst0 */ + "movq %%mm2,%%mm3\n" + "punpckldq %%mm4,%%mm2\n" + "punpckhdq %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + "emms\n" + + : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count) + : + : "cc" + ); +#else + __asm { + mov eax, src0; + mov ebx, src1; + mov ecx, src2; + mov edx, dst; + mov esi, count; + + /* first run */ + /* set the current, current_pre, current_next registers */ + pxor mm0,mm0; + movq mm7,qword ptr [ebx]; + movq mm1,qword ptr [ebx + 8]; + psrlq mm0,32; + psllq mm1,32; + movq mm2,mm7; + movq mm3,mm7; + psllq mm2,32; + psrlq mm3,32; + por mm0,mm2; + por mm1,mm3; + + /* current_upper */ + movq mm6,qword ptr [eax]; + + /* compute the upper-left pixel for dst0 on %%mm2 */ + /* compute the upper-right pixel for dst0 on %%mm4 */ + movq mm2,mm0; + movq mm4,mm1; + movq mm3,mm0; + movq mm5,mm1; + pcmpeqd mm2,mm6; + pcmpeqd mm4,mm6; + pcmpeqd mm3,qword ptr [ecx]; + pcmpeqd mm5,qword ptr [ecx]; + pandn mm3,mm2; + pandn mm5,mm4; + movq mm2,mm0; + movq mm4,mm1; + pcmpeqd mm2,mm1; + pcmpeqd mm4,mm0; + pandn mm2,mm3; + pandn mm4,mm5; + movq mm3,mm2; + movq mm5,mm4; + pand mm2,mm6; + pand mm4,mm6; + pandn mm3,mm7; + pandn mm5,mm7; + por mm2,mm3; + por mm4,mm5; + + /* set *dst0 */ + movq mm3,mm2; + punpckldq mm2,mm4; + punpckhdq mm3,mm4; + movq qword ptr [edx],mm2; + movq qword ptr [edx+8],mm3; + + /* next */ + add eax,8; + add ebx,8; + add ecx,8; + add edx,16; + + /* central runs */ + shr esi,1; + jz label1; +label0: + + /* set the current, current_pre, current_next registers */ + movq mm0,qword ptr [ebx-8]; + movq mm7,qword ptr [ebx]; + movq mm1,qword ptr [ebx+8]; + psrlq mm0,32; + psllq mm1,32; + movq mm2,mm7; + movq mm3,mm7; + psllq mm2,32; + psrlq mm3,32; + por mm0,mm2; + por mm1,mm3; + + /* current_upper */ + movq mm6,qword ptr[eax]; + + /* compute the upper-left pixel for dst0 on %%mm2 */ + /* compute the upper-right pixel for dst0 on %%mm4 */ + movq mm2,mm0; + movq mm4,mm1; + movq mm3,mm0; + movq mm5,mm1; + pcmpeqd mm2,mm6; + pcmpeqd mm4,mm6; + pcmpeqd mm3,qword ptr[ecx]; + pcmpeqd mm5,qword ptr[ecx]; + pandn mm3,mm2; + pandn mm5,mm4; + movq mm2,mm0; + movq mm4,mm1; + pcmpeqd mm2,mm1; + pcmpeqd mm4,mm0; + pandn mm2,mm3; + pandn mm4,mm5; + movq mm3,mm2; + movq mm5,mm4; + pand mm2,mm6; + pand mm4,mm6; + pandn mm3,mm7; + pandn mm5,mm7; + por mm2,mm3; + por mm4,mm5; + + /* set *dst0 */ + movq mm3,mm2; + punpckldq mm2,mm4; + punpckhdq mm3,mm4; + movq qword ptr [edx],mm2; + movq qword ptr [edx+8],mm3; + + /* next */ + add eax,8; + add ebx,8; + add ecx,8; + add edx,16; + + dec esi; + jnz label0; +label1: + + /* final run */ + /* set the current, current_pre, current_next registers */ + movq mm0,qword ptr [ebx-8]; + movq mm7,qword ptr [ebx]; + pxor mm1,mm1; + psrlq mm0,32; + psllq mm1,32; + movq mm2,mm7; + movq mm3,mm7; + psllq mm2,32; + psrlq mm3,32; + por mm0,mm2; + por mm1,mm3; + + /* current_upper */ + movq mm6,qword ptr [eax]; + + /* compute the upper-left pixel for dst0 on %%mm2 */ + /* compute the upper-right pixel for dst0 on %%mm4 */ + movq mm2,mm0; + movq mm4,mm1; + movq mm3,mm0; + movq mm5,mm1; + pcmpeqd mm2,mm6; + pcmpeqd mm4,mm6; + pcmpeqd mm3,qword ptr [ecx]; + pcmpeqd mm5,qword ptr [ecx]; + pandn mm3,mm2; + pandn mm5,mm4; + movq mm2,mm0; + movq mm4,mm1; + pcmpeqd mm2,mm1; + pcmpeqd mm4,mm0; + pandn mm2,mm3; + pandn mm4,mm5; + movq mm3,mm2; + movq mm5,mm4; + pand mm2,mm6; + pand mm4,mm6; + pandn mm3,mm7; + pandn mm5,mm7; + por mm2,mm3; + por mm4,mm5; + + /* set *dst0 */ + movq mm3,mm2; + punpckldq mm2,mm4; + punpckhdq mm3,mm4; + movq qword ptr [edx],mm2; + movq qword ptr [edx+8],mm3; + + mov src0, eax; + mov src1, ebx; + mov src2, ecx; + mov dst, edx; + mov count, esi; + + emms; + } +#endif +} + +static void internal_scale2x_16_mmx(u16* dst0, u16* dst1, const u16* src0, const u16* src1, const u16* src2, unsigned count) { + // assert( count >= 2*4 ); + internal_scale2x_16_mmx_single(dst0, src0, src1, src2, count); + internal_scale2x_16_mmx_single(dst1, src2, src1, src0, count); +} + +static void internal_scale2x_32_mmx(u32* dst0, u32* dst1, const u32* src0, const u32* src1, const u32* src2, unsigned count) { + // assert( count >= 2*2 ); + internal_scale2x_32_mmx_single(dst0, src0, src1, src2, count); + internal_scale2x_32_mmx_single(dst1, src2, src1, src0, count); +} +#endif + +void AdMame2x(u8 *srcPtr, u32 srcPitch, /* u8 deltaPtr, */ + u8 *dstPtr, u32 dstPitch, int width, int height) +{ + u16 *dst0 = (u16 *)dstPtr; + u16 *dst1 = dst0 + (dstPitch/2); + + u16 *src0 = (u16 *)srcPtr; + u16 *src1 = src0 + (srcPitch/2); + u16 *src2 = src1 + (srcPitch/2); +#ifdef MMX + if(cpu_mmx) { + internal_scale2x_16_mmx(dst0, dst1, src0, src0, src1, width); + + { + int count = height; + + count -= 2; + while(count) { + dst0 += dstPitch; + dst1 += dstPitch; + internal_scale2x_16_mmx(dst0, dst1, src0, src1, src2, width); + src0 = src1; + src1 = src2; + src2 += srcPitch/2; + --count; + } + } + dst0 += dstPitch; + dst1 += dstPitch; + internal_scale2x_16_mmx(dst0, dst1, src0, src1, src1, width); + } else { +#endif + internal_scale2x_16_def(dst0, dst1, src0, src0, src1, width); + + { + int count = height; + + count -= 2; + while(count) { + dst0 += dstPitch; + dst1 += dstPitch; + internal_scale2x_16_def(dst0, dst1, src0, src1, src2, width); + src0 = src1; + src1 = src2; + src2 += srcPitch/2; + --count; + } + } + dst0 += dstPitch; + dst1 += dstPitch; + internal_scale2x_16_def(dst0, dst1, src0, src1, src1, width); +#ifdef MMX + } +#endif +} + +void AdMame2x32(u8 *srcPtr, u32 srcPitch, /* u8 deltaPtr, */ + u8 *dstPtr, u32 dstPitch, int width, int height) +{ + u32 *dst0 = (u32 *)dstPtr; + u32 *dst1 = dst0 + (dstPitch/4); + + u32 *src0 = (u32 *)srcPtr; + u32 *src1 = src0 + (srcPitch/4); + u32 *src2 = src1 + (srcPitch/4); +#ifdef MMX + if(cpu_mmx) { + internal_scale2x_32_mmx(dst0, dst1, src0, src0, src1, width); + + { + int count = height; + + count -= 2; + while(count) { + dst0 += dstPitch/2; + dst1 += dstPitch/2; + internal_scale2x_32_mmx(dst0, dst1, src0, src1, src2, width); + src0 = src1; + src1 = src2; + src2 += srcPitch/4; + --count; + } + } + dst0 += dstPitch/2; + dst1 += dstPitch/2; + internal_scale2x_32_mmx(dst0, dst1, src0, src1, src1, width); + } else { +#endif + internal_scale2x_32_def(dst0, dst1, src0, src0, src1, width); + { + int count = height; + + count -= 2; + while(count) { + dst0 += dstPitch/2; + dst1 += dstPitch/2; + internal_scale2x_32_def(dst0, dst1, src0, src1, src2, width); + src0 = src1; + src1 = src2; + src2 += srcPitch/4; + --count; + } + } + dst0 += dstPitch/2; + dst1 += dstPitch/2; + internal_scale2x_32_def(dst0, dst1, src0, src1, src1, width); +#ifdef MMX + } +#endif +} + + + +unsigned int LUT16to32[65536]; +unsigned int RGBtoYUV[65536]; + +void hq_init(void) +{ + int i, j, k, r, g, b, Y, u, v; + + for (i=0; i<65536; i++) + LUT16to32[i] = ((i & 0xF800) << 8) + ((i & 0x07E0) << 5) + ((i & 0x001F) << 3); + + for (i=0; i<32; i++) { + for (j=0; j<64; j++) { + for (k=0; k<32; k++) { + r = i << 3; + g = j << 2; + b = k << 3; + Y = (r + g + b) >> 2; + u = 128 + ((r - b) >> 2); + v = 128 + ((-r + 2*g -b)>>3); + RGBtoYUV[ (i << 11) + (j << 5) + k ] = (Y<<16) + (u<<8) + v; + } + } + } +} + diff --git a/od-win32/screenshot.c b/od-win32/screenshot.c new file mode 100755 index 00000000..a12b8790 --- /dev/null +++ b/od-win32/screenshot.c @@ -0,0 +1,186 @@ +#include +#include + +#include + +#include "sysconfig.h" +#include "sysdeps.h" +#include "options.h" +#include "custom.h" +#include "picasso96.h" +#include "dxwrap.h" +#include "win32.h" +#include "win32gfx.h" +#include "direct3d.h" +#include "opengl.h" + +static char config_filename[] = { 0 }; + +static int toclipboard (BITMAPINFO *bi, void *bmp) +{ + int v = 0; + uae_u8 *dib = 0; + HANDLE hg; + + if (!OpenClipboard (hMainWnd)) + return v; + EmptyClipboard (); + hg = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, bi->bmiHeader.biSize + bi->bmiHeader.biSizeImage); + if (hg) { + dib = GlobalLock (hg); + if (dib) { + memcpy (dib, &bi->bmiHeader, bi->bmiHeader.biSize); + memcpy (dib + bi->bmiHeader.biSize, bmp, bi->bmiHeader.biSizeImage); + } + GlobalUnlock (hg); + if (SetClipboardData (CF_DIB, hg)) + v = 1; + } + CloseClipboard (); + if (!v) + GlobalFree (hg); + return v; +} + +/* +Captures the Amiga display (DirectDraw, D3D or OpenGL) surface and saves it to file as a 24bit bitmap. +*/ +void screenshot(int mode) +{ + static int recursive; + + FILE *fp = NULL; + + HDC surface_dc = NULL; // GDI-compatible device context for the surface + HBITMAP offscreen_bitmap = NULL; // bitmap that is converted to a DIB + HDC offscreen_dc = NULL; // offscreen DC that we can select offscreen bitmap into + + BITMAPINFO bi; // bitmap info + LPVOID lpvBits = NULL; // pointer to bitmap bits array + + unsigned int width = WIN32GFX_GetWidth(); + unsigned int height = WIN32GFX_GetHeight(); + + if(recursive) + return; + + recursive++; + + surface_dc = gethdc (); + + // need a HBITMAP to convert it to a DIB + if((offscreen_bitmap = CreateCompatibleBitmap(surface_dc, width, height)) == NULL) + goto oops; // error + + // The bitmap is empty, so let's copy the contents of the surface to it. + // For that we need to select it into a device context. + if((offscreen_dc = CreateCompatibleDC(surface_dc)) == NULL) + goto oops; // error + + { + // select offscreen_bitmap into offscreen_dc + HGDIOBJ hgdiobj = SelectObject(offscreen_dc, offscreen_bitmap); + + // now we can copy the contents of the surface to the offscreen bitmap + BitBlt(offscreen_dc, 0, 0, width, height, surface_dc, 0, 0, SRCCOPY); + + // de-select offscreen_bitmap + SelectObject(offscreen_dc, hgdiobj); + } + + ZeroMemory(&bi, sizeof(bi)); + bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bi.bmiHeader.biWidth = width; + bi.bmiHeader.biHeight = height; + bi.bmiHeader.biPlanes = 1; + bi.bmiHeader.biBitCount = 24; + bi.bmiHeader.biCompression = BI_RGB; + bi.bmiHeader.biSizeImage = (((bi.bmiHeader.biWidth * bi.bmiHeader.biBitCount + 31) & ~31) / 8) * bi.bmiHeader.biHeight; + bi.bmiHeader.biXPelsPerMeter = 0; + bi.bmiHeader.biYPelsPerMeter = 0; + bi.bmiHeader.biClrUsed = 0; + bi.bmiHeader.biClrImportant = 0; + + // Reserve memory for bitmap bits + if(!(lpvBits = malloc(bi.bmiHeader.biSizeImage))) + goto oops; // out of memory + + // Have GetDIBits convert offscreen_bitmap to a DIB (device-independent bitmap): + if(!GetDIBits(offscreen_dc, offscreen_bitmap, 0, bi.bmiHeader.biHeight, lpvBits, &bi, DIB_RGB_COLORS)) + goto oops; // GetDIBits FAILED + + releasehdc (surface_dc); + surface_dc = 0; + + if (mode == 0) { + toclipboard (&bi, lpvBits); + } else { + char filename[MAX_PATH]; + char extension[] = "bmp"; + char tmpstr[MAX_PATH]; + int number = 0; + + tmpstr[0] = 0; + if(config_filename[0]) + sprintf (tmpstr, "%s_", config_filename); + + while(++number < 1000) // limit 999 iterations / screenshots + { + sprintf(filename, "%s%cScreenShots%c%s%03.3d.%s", start_path, FSDB_DIR_SEPARATOR, FSDB_DIR_SEPARATOR, tmpstr, number, extension); + + if((fp = fopen(filename, "r")) == NULL) // does file not exist? + { + BITMAPFILEHEADER bfh; + + if((fp = fopen(filename, "wb")) == NULL) + goto oops; // error + + // write the file header, bitmap information and pixel data + bfh.bfType = 19778; + bfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + bi.bmiHeader.biSizeImage; + bfh.bfReserved1 = 0; + bfh.bfReserved2 = 0; + bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); + + if(fwrite(&bfh, 1, sizeof(BITMAPFILEHEADER), fp) < sizeof(BITMAPFILEHEADER)) + goto oops; // failed to write bitmap file header + + if(fwrite(&bi, 1, sizeof(BITMAPINFOHEADER), fp) < sizeof(BITMAPINFOHEADER)) + goto oops; // failed to write bitmap infomation header + + if(fwrite(lpvBits, 1, bi.bmiHeader.biSizeImage, fp) < bi.bmiHeader.biSizeImage) + goto oops; // failed to write the bitmap + + fclose(fp); + + write_log("Screenshot saved as \"%s\"\n", filename); + + break; + } + + fclose(fp); + fp = NULL; + } + } + +oops: + if (surface_dc) + releasehdc (surface_dc); + + if(offscreen_dc) + DeleteDC(offscreen_dc); + + if(offscreen_bitmap) + DeleteObject(offscreen_bitmap); + + if(lpvBits) + free(lpvBits); + + if(fp) + fclose(fp); + + recursive--; + + return; +} + diff --git a/od-win32/scsidef.h b/od-win32/scsidef.h new file mode 100755 index 00000000..5126a9e6 --- /dev/null +++ b/od-win32/scsidef.h @@ -0,0 +1,388 @@ + +/* required scsi structure definitions ripped from cdrtools package... */ + +typedef int BOOL; +typedef unsigned char Ucbit; +typedef unsigned long Ulong; +typedef unsigned int Uint; +typedef unsigned short Ushort; +typedef unsigned char Uchar; +typedef unsigned long Int32_t; + +typedef void* caddr_t; + +#define _BIT_FIELDS_LTOH +#define __PR(x) + +struct scsi_capacity { + Int32_t c_baddr; /* must convert byteorder!! */ + Int32_t c_bsize; /* must convert byteorder!! */ +}; + +typedef struct scg_ops { + int (*scgo_send) __PR((SCSI *scgp)); + + char * (*scgo_version) __PR((SCSI *scgp, int what)); + int (*scgo_open) __PR((SCSI *scgp, char *device)); + int (*scgo_close) __PR((SCSI *scgp)); + long (*scgo_maxdma) __PR((SCSI *scgp, long amt)); + void * (*scgo_getbuf) __PR((SCSI *scgp, long amt)); + void (*scgo_freebuf) __PR((SCSI *scgp)); + + + BOOL (*scgo_havebus) __PR((SCSI *scgp, int busno)); + int (*scgo_fileno) __PR((SCSI *scgp, int busno, int tgt, int tlun)); + int (*scgo_initiator_id) __PR((SCSI *scgp)); + int (*scgo_isatapi) __PR((SCSI *scgp)); + int (*scgo_reset) __PR((SCSI *scgp, int what)); +} scg_ops_t; + +typedef struct { + int scsibus; /* SCSI bus # for next I/O */ + int target; /* SCSI target # for next I/O */ + int lun; /* SCSI lun # for next I/O */ +} scg_addr_t; + +typedef struct scg_scsi SCSI; +struct scg_scsi { + scg_ops_t *ops; /* Ptr to low level SCSI transport ops */ + int fd; /* File descriptor for next I/O */ + scg_addr_t addr; /* SCSI address for next I/O */ + int flags; /* Libscg flags (see below) */ + int dflags; /* Drive specific flags (see below) */ + int kdebug; /* Kernel debug value for next I/O */ + int debug; /* Debug value for SCSI library */ + int silent; /* Be silent if value > 0 */ + int verbose; /* Be verbose if value > 0 */ + int overbose; /* Be verbose in open() if value > 0 */ + int disre_disable; + int deftimeout; + int noparity; /* Do not use SCSI parity fo next I/O */ + int dev; /* from scsi_cdr.c */ + struct scg_cmd *scmd; + char *cmdname; + char *curcmdname; + BOOL running; + int error; /* libscg error number */ + + long maxdma; /* Max DMA limit for this open instance */ + long maxbuf; /* Cur DMA buffer limit for this inst. */ + /* This is the size behind bufptr */ + struct timeval *cmdstart; + struct timeval *cmdstop; + const char **nonstderrs; + void *local; /* Local data from the low level code */ + void *bufbase; /* needed for scsi_freebuf() */ + void *bufptr; /* DMA buffer pointer for appl. use */ + char *errstr; /* Error string for scsi_open/sendmcd */ + char *errbeg; /* Pointer to begin of not flushed data */ + char *errptr; /* Actual write pointer into errstr */ + void *errfile; /* FILE to write errors to. NULL for not*/ + /* writing and leaving errs in errstr */ + + struct scsi_inquiry *inq; + struct scsi_capacity *cap; +}; +#define scg_scsibus(scgp) (scgp)->addr.scsibus +#define scg_target(scgp) (scgp)->addr.target +#define scg_lun(scgp) (scgp)->addr.lun + +#define SCSI_ERRSTR_SIZE 4096 + +#define SC_TEST_UNIT_READY 0x00 +#define SC_REZERO_UNIT 0x01 +#define SC_REQUEST_SENSE 0x03 +#define SC_FORMAT 0x04 +#define SC_FORMAT_TRACK 0x06 +#define SC_REASSIGN_BLOCK 0x07 /* CCS only */ +#define SC_SEEK 0x0b +#define SC_TRANSLATE 0x0f /* ACB4000 only */ +#define SC_INQUIRY 0x12 /* CCS only */ +#define SC_MODE_SELECT 0x15 +#define SC_RESERVE 0x16 +#define SC_RELEASE 0x17 +#define SC_MODE_SENSE 0x1a +#define SC_START 0x1b +#define SC_READ_DEFECT_LIST 0x37 /* CCS only, group 1 */ +#define SC_READ_BUFFER 0x3c /* CCS only, group 1 */ + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ +struct scsi_g0cdb { /* scsi group 0 command description block */ + Uchar cmd; /* command code */ + Ucbit high_addr : 5; /* high part of block address */ + Ucbit lun : 3; /* logical unit number */ + Uchar mid_addr; /* middle part of block address */ + Uchar low_addr; /* low part of block address */ + Uchar count; /* transfer length */ + Ucbit link : 1; /* link (another command follows) */ + Ucbit fr : 1; /* flag request (interrupt at completion) */ + Ucbit rsvd : 4; /* reserved */ + Ucbit vu_56 : 1; /* vendor unique (byte 5 bit 6) */ + Ucbit vu_57 : 1; /* vendor unique (byte 5 bit 7) */ +}; +#else /* Motorola byteorder */ +struct scsi_g0cdb { /* scsi group 0 command description block */ + Uchar cmd; /* command code */ + Ucbit lun : 3; /* logical unit number */ + Ucbit high_addr : 5; /* high part of block address */ + Uchar mid_addr; /* middle part of block address */ + Uchar low_addr; /* low part of block address */ + Uchar count; /* transfer length */ + Ucbit vu_57 : 1; /* vendor unique (byte 5 bit 7) */ + Ucbit vu_56 : 1; /* vendor unique (byte 5 bit 6) */ + Ucbit rsvd : 4; /* reserved */ + Ucbit fr : 1; /* flag request (interrupt at completion) */ + Ucbit link : 1; /* link (another command follows) */ +}; +#endif + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ +struct scsi_g1cdb { /* scsi group 1 command description block */ + Uchar cmd; /* command code */ + Ucbit reladr : 1; /* address is relative */ + Ucbit res : 4; /* reserved bits 1-4 of byte 1 */ + Ucbit lun : 3; /* logical unit number */ + Uchar addr[4]; /* logical block address */ + Uchar res6; /* reserved byte 6 */ + Uchar count[2]; /* transfer length */ + Ucbit link : 1; /* link (another command follows) */ + Ucbit fr : 1; /* flag request (interrupt at completion) */ + Ucbit rsvd : 4; /* reserved */ + Ucbit vu_96 : 1; /* vendor unique (byte 5 bit 6) */ + Ucbit vu_97 : 1; /* vendor unique (byte 5 bit 7) */ +}; +#else /* Motorola byteorder */ +struct scsi_g1cdb { /* scsi group 1 command description block */ + Uchar cmd; /* command code */ + Ucbit lun : 3; /* logical unit number */ + Ucbit res : 4; /* reserved bits 1-4 of byte 1 */ + Ucbit reladr : 1; /* address is relative */ + Uchar addr[4]; /* logical block address */ + Uchar res6; /* reserved byte 6 */ + Uchar count[2]; /* transfer length */ + Ucbit vu_97 : 1; /* vendor unique (byte 5 bit 7) */ + Ucbit vu_96 : 1; /* vendor unique (byte 5 bit 6) */ + Ucbit rsvd : 4; /* reserved */ + Ucbit fr : 1; /* flag request (interrupt at completion) */ + Ucbit link : 1; /* link (another command follows) */ +}; +#endif + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ +struct scsi_g5cdb { /* scsi group 5 command description block */ + Uchar cmd; /* command code */ + Ucbit reladr : 1; /* address is relative */ + Ucbit res : 4; /* reserved bits 1-4 of byte 1 */ + Ucbit lun : 3; /* logical unit number */ + Uchar addr[4]; /* logical block address */ + Uchar count[4]; /* transfer length */ + Uchar res10; /* reserved byte 10 */ + Ucbit link : 1; /* link (another command follows) */ + Ucbit fr : 1; /* flag request (interrupt at completion) */ + Ucbit rsvd : 4; /* reserved */ + Ucbit vu_B6 : 1; /* vendor unique (byte B bit 6) */ + Ucbit vu_B7 : 1; /* vendor unique (byte B bit 7) */ +}; +#else /* Motorola byteorder */ +struct scsi_g5cdb { /* scsi group 5 command description block */ + Uchar cmd; /* command code */ + Ucbit lun : 3; /* logical unit number */ + Ucbit res : 4; /* reserved bits 1-4 of byte 1 */ + Ucbit reladr : 1; /* address is relative */ + Uchar addr[4]; /* logical block address */ + Uchar count[4]; /* transfer length */ + Uchar res10; /* reserved byte 10 */ + Ucbit vu_B7 : 1; /* vendor unique (byte B bit 7) */ + Ucbit vu_B6 : 1; /* vendor unique (byte B bit 6) */ + Ucbit rsvd : 4; /* reserved */ + Ucbit fr : 1; /* flag request (interrupt at completion) */ + Ucbit link : 1; /* link (another command follows) */ +}; +#endif + +struct scsi_status { + Ucbit vu_00 : 1; /* vendor unique */ + Ucbit chk : 1; /* check condition: sense data available */ + Ucbit cm : 1; /* condition met */ + Ucbit busy : 1; /* device busy or reserved */ + Ucbit is : 1; /* intermediate status sent */ + Ucbit vu_05 : 1; /* vendor unique */ +#define st_scsi2 vu_05 /* SCSI-2 modifier bit */ + Ucbit vu_06 : 1; /* vendor unique */ + Ucbit st_rsvd : 1; /* reserved */ + +#ifdef SCSI_EXTENDED_STATUS +#define ext_st1 st_rsvd /* extended status (next byte valid) */ + /* byte 1 */ + Ucbit ha_er : 1; /* host adapter detected error */ + Ucbit reserved: 6; /* reserved */ + Ucbit ext_st2 : 1; /* extended status (next byte valid) */ + /* byte 2 */ + Uchar byte2; /* third byte */ +#endif /* SCSI_EXTENDED_STATUS */ +}; + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ +struct scsi_sense { /* scsi sense for error classes 0-6 */ + Ucbit code : 7; /* error class/code */ + Ucbit adr_val : 1; /* sense data is valid */ +#ifdef comment + Ucbit high_addr:5; /* high byte of block addr */ + Ucbit rsvd : 3; +#else + Uchar high_addr; /* high byte of block addr */ +#endif + Uchar mid_addr; /* middle byte of block addr */ + Uchar low_addr; /* low byte of block addr */ +}; +#else /* Motorola byteorder */ +struct scsi_sense { /* scsi sense for error classes 0-6 */ + Ucbit adr_val : 1; /* sense data is valid */ + Ucbit code : 7; /* error class/code */ +#ifdef comment + Ucbit rsvd : 3; + Ucbit high_addr:5; /* high byte of block addr */ +#else + Uchar high_addr; /* high byte of block addr */ +#endif + Uchar mid_addr; /* middle byte of block addr */ + Uchar low_addr; /* low byte of block addr */ +}; +#endif + +#define SCG_MAX_CMD 24 /* 24 bytes max. size is supported */ +#define SCG_MAX_STATUS 3 /* XXX (sollte 4 allign.) Mamimum Status Len */ +#define SCG_MAX_SENSE 32 /* Mamimum Sense Len for auto Req. Sense */ + +#define DEF_SENSE_LEN 16 /* Default Sense Len */ +#define CCS_SENSE_LEN 18 /* Sense Len for CCS compatible devices */ + +#define SCG_RECV_DATA 0x0001 /* DMA direction to Sun */ +#define SCG_DISRE_ENA 0x0002 /* enable disconnect/reconnect */ + +#define SCG_NO_ERROR 0 /* cdb transported without error */ +#define SCG_RETRYABLE 1 /* any other case e.g. SCSI bus busy */ +#define SCG_FATAL 2 /* could not select target */ +#define SCG_TIMEOUT 3 /* driver timed out */ + +#define SC_G0_CDBLEN 6 /* Len of Group 0 commands */ +#define SC_G1_CDBLEN 10 /* Len of Group 1 commands */ +#define SC_G5_CDBLEN 12 /* Len of Group 5 commands */ + +struct scg_cmd { + caddr_t addr; /* Address of data in user space */ + int size; /* DMA count for data transfer */ + int flags; /* see below for definition */ + int cdb_len; /* Size of SCSI command in bytes */ + /* NOTE: rel 4 uses this field only */ + /* with commands not in group 1 or 2*/ + int sense_len; /* for intr() if -1 don't get sense */ + int timeout; /* timeout in seconds */ + /* NOTE: actual resolution depends */ + /* on driver implementation */ + int kdebug; /* driver kernel debug level */ + int resid; /* Bytes not transfered */ + int error; /* Error code from scgintr() */ + int ux_errno; /* UNIX error code */ + union { + struct scsi_status Scb;/* Status returnd by command */ + Uchar cmd_scb[SCG_MAX_STATUS]; + } u_scb; +#define scb u_scb.Scb + union { + struct scsi_sense Sense;/* Sense bytes from command */ + Uchar cmd_sense[SCG_MAX_SENSE]; + } u_sense; +#define sense u_sense.Sense + int sense_count; /* Number of bytes valid in sense */ + int target; /* SCSI target id */ + /* NOTE: The SCSI target id field */ + /* does not need to be filled unless */ + /* the low level transport is a real */ + /* scg driver. In this case the low */ + /* level transport routine of libscg */ + /* will fill in the needed value */ + union { /* SCSI command descriptor block */ + struct scsi_g0cdb g0_cdb; + struct scsi_g1cdb g1_cdb; + struct scsi_g5cdb g5_cdb; + Uchar cmd_cdb[SCG_MAX_CMD]; + } cdb; /* 24 bytes max. size is supported */ +}; + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ +struct scsi_inquiry { + Ucbit type : 5; /* 0 */ + Ucbit qualifier : 3; /* 0 */ + + Ucbit type_modifier : 7; /* 1 */ + Ucbit removable : 1; /* 1 */ + + Ucbit ansi_version : 3; /* 2 */ + Ucbit ecma_version : 3; /* 2 */ + Ucbit iso_version : 2; /* 2 */ + + Ucbit data_format : 4; /* 3 */ + Ucbit res3_54 : 2; /* 3 */ + Ucbit termiop : 1; /* 3 */ + Ucbit aenc : 1; /* 3 */ + + Ucbit add_len : 8; /* 4 */ + Ucbit sense_len : 8; /* 5 */ /* only Emulex ??? */ + Ucbit res2 : 8; /* 6 */ + + Ucbit softreset : 1; /* 7 */ + Ucbit cmdque : 1; + Ucbit res7_2 : 1; + Ucbit linked : 1; + Ucbit sync : 1; + Ucbit wbus16 : 1; + Ucbit wbus32 : 1; + Ucbit reladr : 1; /* 7 */ + + char vendor_info[8]; /* 8 */ + char prod_ident[16]; /* 16 */ + char prod_revision[4]; /* 32 */ +#ifdef comment + char vendor_uniq[20]; /* 36 */ + char reserved[40]; /* 56 */ +#endif +}; /* 96 */ +#else /* Motorola byteorder */ +struct scsi_inquiry { + Ucbit qualifier : 3; /* 0 */ + Ucbit type : 5; /* 0 */ + + Ucbit removable : 1; /* 1 */ + Ucbit type_modifier : 7; /* 1 */ + + Ucbit iso_version : 2; /* 2 */ + Ucbit ecma_version : 3; + Ucbit ansi_version : 3; /* 2 */ + + Ucbit aenc : 1; /* 3 */ + Ucbit termiop : 1; + Ucbit res3_54 : 2; + Ucbit data_format : 4; /* 3 */ + + Ucbit add_len : 8; /* 4 */ + Ucbit sense_len : 8; /* 5 */ /* only Emulex ??? */ + Ucbit res2 : 8; /* 6 */ + Ucbit reladr : 1; /* 7 */ + Ucbit wbus32 : 1; + Ucbit wbus16 : 1; + Ucbit sync : 1; + Ucbit linked : 1; + Ucbit res7_2 : 1; + Ucbit cmdque : 1; + Ucbit softreset : 1; + char vendor_info[8]; /* 8 */ + char prod_ident[16]; /* 16 */ + char prod_revision[4]; /* 32 */ +#ifdef comment + char vendor_uniq[20]; /* 36 */ + char reserved[40]; /* 56 */ +#endif +}; /* 96 */ +#endif + diff --git a/od-win32/serial_win32.c b/od-win32/serial_win32.c new file mode 100755 index 00000000..224b1343 --- /dev/null +++ b/od-win32/serial_win32.c @@ -0,0 +1,489 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Serial Line Emulation + * + * (c) 1996, 1997 Stefan Reinauer + * (c) 1997 Christian Schmitt + * + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "uae.h" +#include "memory.h" +#include "custom.h" +#include "events.h" +#include "newcpu.h" +#include "cia.h" +#include "serial.h" + +#include "od-win32/parser.h" + +#define SERIALDEBUG 0 /* 0, 1, 2 3 */ +#define SERIALHSDEBUG 0 +#define MODEMTEST 0 /* 0 or 1 */ + +static int data_in_serdat; /* new data written to SERDAT */ +static int data_in_serdatr; /* new data received */ +static int data_in_sershift; /* data transferred from SERDAT to shift register */ +static uae_u16 serdatshift; /* serial shift register */ +static int ovrun; +static int dtr; +static int serial_period_hsyncs, serial_period_hsync_counter; +static int ninebit; +int serdev; + +void serial_open(void); +void serial_close(void); + +uae_u16 serper, serdat, serdatr; + +static int allowed_baudrates[] = + { 0, 110, 300, 600, 1200, 2400, 4800, 9600, 14400, + 19200, 31400, 38400, 57600, 115200, 128000, 256000, -1 }; + +void SERPER (uae_u16 w) +{ + int baud = 0, i, per; + static int warned; + + if (serper == w) /* don't set baudrate if it's already ok */ + return; + ninebit = 0; + serper = w; + + if (w & 0x8000) { + if (!warned) { + write_log( "SERIAL: program uses 9bit mode PC=%x\n", m68k_getpc() ); + warned++; + } + ninebit = 1; + } + w &= 0x7fff; + + if (w < 13) + w = 13; + + per = w; + if (per == 0) per = 1; + per = 3546895 / (per + 1); + if (per <= 0) per = 1; + i = 0; + while (allowed_baudrates[i] >= 0 && per > allowed_baudrates[i] * 100 / 97) + i++; + baud = allowed_baudrates[i]; + + serial_period_hsyncs = (((serper & 0x7fff) + 1) * 10) / maxhpos; + if (serial_period_hsyncs <= 0) + serial_period_hsyncs = 1; + serial_period_hsync_counter = 0; + + write_log ("SERIAL: period=%d, baud=%d, hsyncs=%d PC=%x\n", w, baud, serial_period_hsyncs, m68k_getpc()); + + if (!currprefs.use_serial) + return; + + if (ninebit) + baud *= 2; + if (currprefs.serial_direct) { + if (baud != 31400 && baud < 115200) + baud = 115200; + serial_period_hsyncs = 1; + } +#ifdef SERIAL_PORT + setbaud (baud); +#endif +} + +static char dochar (int v) +{ + v &= 0xff; + if (v >= 32 && v < 127) return (char)v; + return '.'; +} + +static void checkreceive (int mode) +{ +#ifdef SERIAL_PORT + static uae_u32 lastchartime; + static int ninebitdata; + struct timeval tv; + int recdata; + + if (!currprefs.use_serial) + return; + + if (!readseravail()) + return; + + if (data_in_serdatr) { + /* probably not needed but there may be programs that expect OVRUNs.. */ + gettimeofday (&tv, NULL); + if (tv.tv_sec > lastchartime) { + ovrun = 1; + INTREQ (0x8000 | 0x0800); + while (readser (&recdata)); + write_log ("SERIAL: overrun\n"); + } + return; + } + + if (ninebit) { + for (;;) { + if (!readser (&recdata)) + return; + if (ninebitdata) { + serdatr = (ninebitdata & 1) << 8; + serdatr |= recdata; + serdatr |= 0x200; + ninebitdata = 0; + break; + } else { + ninebitdata = recdata; + if ((ninebitdata & ~1) != 0xa8) { + write_log ("SERIAL: 9-bit serial emulation sync lost, %02.2X != %02.2X\n", ninebitdata & ~1, 0xa8); + ninebitdata = 0; + return; + } + continue; + } + } + } else { + if (!readser (&recdata)) + return; + serdatr = recdata; + serdatr |= 0x100; + } + gettimeofday (&tv, NULL); + lastchartime = tv.tv_sec + 5; + data_in_serdatr = 1; + serial_check_irq (); +#if SERIALDEBUG > 2 + write_log ("SERIAL: received %02.2X (%c)\n", serdatr & 0xff, dochar (serdatr)); +#endif +#endif +} + +static void checksend (int mode) +{ + int bufstate = 0; + +#ifdef SERIAL_PORT + bufstate = checkserwrite (); +#endif + if (!data_in_serdat && !data_in_sershift) + return; + + if (!currprefs.use_serial) + bufstate = 1; + + if (data_in_sershift && mode == 0 && bufstate) + data_in_sershift = 0; + + if (data_in_serdat && !data_in_sershift) { + data_in_sershift = 1; + serdatshift = serdat; +#ifdef SERIAL_PORT + if (currprefs.use_serial) { + if (ninebit) + writeser (((serdatshift >> 8) & 1) | 0xa8); + writeser (serdatshift); + } +#endif + data_in_serdat = 0; + INTREQ (0x8000 | 0x0001); +#if SERIALDEBUG > 2 + write_log ("SERIAL: send %04.4X (%c)\n", serdatshift, dochar (serdatshift)); +#endif + } +} + +void serial_hsynchandler (void) +{ +#ifdef AHI + extern void hsyncstuff(void); + hsyncstuff(); +#endif + if (serial_period_hsyncs == 0) + return; + serial_period_hsync_counter++; + if (serial_period_hsyncs == 1 || (serial_period_hsync_counter % (serial_period_hsyncs - 1)) == 0) + checkreceive (0); + if ((serial_period_hsync_counter % serial_period_hsyncs) == 0) + checksend (0); +} + +/* Not (fully) implemented yet: (on windows this work) + * + * - Something's wrong with the Interrupts. + * (NComm works, TERM does not. TERM switches to a + * blind mode after a connect and wait's for the end + * of an asynchronous read before switching blind + * mode off again. It never gets there on UAE :-< ) + * + */ + +void SERDAT (uae_u16 w) +{ + serdat = w; + + if (!(w & 0x3ff)) { +#if SERIALDEBUG > 1 + write_log ("SERIAL: zero serial word written?! PC=%x\n", m68k_getpc()); +#endif + return; + } + +#if SERIALDEBUG > 1 + if (data_in_serdat) { + write_log ("SERIAL: program wrote to SERDAT but old byte wasn't fetched yet\n"); + } +#endif + + data_in_serdat = 1; + if (!data_in_sershift) + checksend (1); + +#if SERIALDEBUG > 2 + write_log ("SERIAL: wrote 0x%04x (%c) PC=%x\n", w, dochar (w), m68k_getpc()); +#endif + + return; +} + +uae_u16 SERDATR (void) +{ + serdatr &= 0x03ff; + if (!data_in_serdat) + serdatr |= 0x2000; + if (!data_in_sershift) + serdatr |= 0x1000; + if (data_in_serdatr) + serdatr |= 0x4000; + if (ovrun) + serdatr |= 0x8000; +#if SERIALDEBUG > 2 + write_log( "SERIAL: read 0x%04.4x (%c) %x\n", serdatr, dochar (serdatr), m68k_getpc()); +#endif + ovrun = 0; + data_in_serdatr = 0; + return serdatr; +} + +void serial_check_irq (void) +{ + if (data_in_serdatr) + INTREQ_0 (0x8000 | 0x0800); +} + +void serial_dtr_on(void) +{ +#if SERIALHSDEBUG > 0 + write_log( "SERIAL: DTR on\n" ); +#endif + dtr = 1; + if (currprefs.serial_demand) + serial_open (); +#ifdef SERIAL_PORT + setserstat(TIOCM_DTR, dtr); +#endif +} + +void serial_dtr_off(void) +{ +#if SERIALHSDEBUG > 0 + write_log( "SERIAL: DTR off\n" ); +#endif + dtr = 0; +#ifdef SERIAL_PORT + if (currprefs.serial_demand) + serial_close (); + setserstat(TIOCM_DTR, dtr); +#endif +} + +void serial_flush_buffer(void) +{ +} + +static uae_u8 oldserbits; + +static void serial_status_debug(char *s) +{ +#if SERIALHSDEBUG > 1 + write_log("%s: DTR=%d RTS=%d CD=%d CTS=%d DSR=%d\n", s, + (oldserbits & 0x80) ? 0 : 1, (oldserbits & 0x40) ? 0 : 1, + (oldserbits & 0x20) ? 0 : 1, (oldserbits & 0x10) ? 0 : 1, (oldserbits & 0x08) ? 0 : 1); +#endif +} + +uae_u8 serial_readstatus(uae_u8 dir) +{ + int status = 0; + uae_u8 serbits = oldserbits; + +#ifdef SERIAL_PORT + getserstat (&status); +#endif + if (!(status & TIOCM_CAR)) { + if (!(serbits & 0x20)) { + serbits |= 0x20; +#if SERIALHSDEBUG > 0 + write_log( "SERIAL: CD off\n" ); +#endif + } + } else { + if (serbits & 0x20) { + serbits &= ~0x20; +#if SERIALHSDEBUG > 0 + write_log( "SERIAL: CD on\n" ); +#endif + } + } + + if (!(status & TIOCM_DSR)) { + if (!(serbits & 0x08)) { + serbits |= 0x08; +#if SERIALHSDEBUG > 0 + write_log( "SERIAL: DSR off\n" ); +#endif + } + } else { + if (serbits & 0x08) { + serbits &= ~0x08; +#if SERIALHSDEBUG > 0 + write_log( "SERIAL: DSR on\n" ); +#endif + } + } + + if (!(status & TIOCM_CTS)) { + if (!(serbits & 0x10)) { + serbits |= 0x10; +#if SERIALHSDEBUG > 0 + write_log( "SERIAL: CTS off\n" ); +#endif + } + } else { + if (serbits & 0x10) { + serbits &= ~0x10; +#if SERIALHSDEBUG > 0 + write_log( "SERIAL: CTS on\n" ); +#endif + } + } + + serbits &= 0x08 | 0x10 | 0x20; + oldserbits &= ~(0x08 | 0x10 | 0x20); + oldserbits |= serbits; + + serial_status_debug("read"); + + return oldserbits; +} + +uae_u8 serial_writestatus (uae_u8 newstate, uae_u8 dir) +{ +#ifdef SERIAL_PORT + if (((oldserbits ^ newstate) & 0x80) && (dir & 0x80)) { + if (newstate & 0x80) + serial_dtr_off(); + else + serial_dtr_on(); + } + + if (!currprefs.serial_hwctsrts && (dir & 0x40)) { + if ((oldserbits ^ newstate) & 0x40) { + if (newstate & 0x40) { + setserstat (TIOCM_RTS, 0); +#if SERIALHSDEBUG > 0 + write_log ("SERIAL: RTS cleared\n"); +#endif + } else { + setserstat (TIOCM_RTS, 1); +#if SERIALHSDEBUG > 0 + write_log ("SERIAL: RTS set\n"); +#endif + } + } + } + + #if 0 /* CIA io-pins can be read even when set to output.. */ + if ((newstate & 0x20) != (oldserbits & 0x20) && (dir & 0x20)) + write_log ("SERIAL: warning, program tries to use CD as an output!\n"); + if ((newstate & 0x10) != (oldserbits & 0x10) && (dir & 0x10)) + write_log ("SERIAL: warning, program tries to use CTS as an output!\n"); + if ((newstate & 0x08) != (oldserbits & 0x08) && (dir & 0x08)) + write_log ("SERIAL: warning, program tries to use DSR as an output!\n"); +#endif + + if (((newstate ^ oldserbits) & 0x40) && !(dir & 0x40)) + write_log ("SERIAL: warning, program tries to use RTS as an input!\n"); + if (((newstate ^ oldserbits) & 0x80) && !(dir & 0x80)) + write_log ("SERIAL: warning, program tries to use DTR as an input!\n"); + +#endif + + oldserbits &= ~(0x80 | 0x40); + newstate &= 0x80 | 0x40; + oldserbits |= newstate; + serial_status_debug("write"); + + return oldserbits; +} + +void serial_open(void) +{ +#ifdef SERIAL_PORT + if (serdev) + return; + + if( !openser( currprefs.sername ) ) + { + write_log( "SERIAL: Could not open device %s\n", currprefs.sername ); + return; + } + serdev = 1; +#endif +} + +void serial_close (void) +{ +#ifdef SERIAL_PORT + closeser(); + serdev = 0; +#endif +} + +void serial_init (void) +{ +#ifdef SERIAL_PORT + if (!currprefs.use_serial) + return; + + if (!currprefs.serial_demand) + serial_open (); + + serdat = 0x2000; +#endif +} + +void serial_exit (void) +{ +#ifdef SERIAL_PORT + serial_close (); /* serial_close can always be called because it */ +#endif + dtr = 0; /* just closes *opened* filehandles which is ok */ + oldserbits = 0; /* when exiting. */ +} + +void serial_uartbreak (int v) +{ +#ifdef SERIAL_PORT + serialuartbreak (v); +#endif +} diff --git a/od-win32/sfhelper.c b/od-win32/sfhelper.c new file mode 100755 index 00000000..36578fe5 --- /dev/null +++ b/od-win32/sfhelper.c @@ -0,0 +1,122 @@ + +#include +#include + +#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 [..]"); + return 0; + } + wu = argv[1]; + f = fopen(wu,"rb"); + if (!f) { + printf("Couldn't open '%s'\n", wu); + return 0; + } + fseek (f, 0, SEEK_END); + size = ftell(f); + fseek (f, 0, SEEK_SET); + b = malloc (size); + if (!b) { + printf ("out of memory, can't allocate %d bytes\n", size); + return 0; + } + fread (b, size, 1, f); + fclose (f); + + cfgbuf = databuf = 0; + p1 = b; + while (p1 < b + size) { + if (*p1 == '_') { + if (!strcmp (p1, "_CONFIG_STARTS_HERE")) + cfgbuf = p1; + if (!strcmp (p1, "_DATA_STARTS_HERE")) + databuf = p1; + } + p1++; + if (cfgbuf && databuf) + break; + } + + if (!cfgbuf || !databuf) { + printf ("couldn't find preallocated data buffer"); + return 0; + } + + while (*cfgbuf++); + printf ("processing config file...\n"); + f = fopen(argv[2],"rb"); + if (!f) { + printf ("Couldn't open config file '%s'\n", argv[2]); + return 0; + } + fread (cfgbuf, 1, 50000, f); + fclose (f); + printf ("done\n"); + + num = argc - 3; + offset = num * 256; + p1 = databuf + offset; + p2 = databuf; + while (*p2++); + memset (p2, 0, offset); + *p2++ = offset >> 24; + *p2++ = offset >> 16; + *p2++ = offset >> 8; + *p2++ = offset >> 0; + for (i = 0; i < num; i++) { + printf ("processing '%s'\n", argv[i + 3]); + f = fopen(argv[i + 3], "rb"); + if (!f) { + printf ("Couldn't open '%s'\n", argv[i + 3]); + return 0; + } + fseek (f, 0, SEEK_END); + size2 = ftell (f); + fseek (f, 0, SEEK_SET); + fread (p1, 1, size2, f); + fclose (f); + *p2++ = size2 >> 24; + *p2++ = size2 >> 16; + *p2++ = size2 >> 8; + *p2++ = size2 >> 0; + p3 = argv[i + 3] + strlen (argv[i + 3]) - 1; + while (p3 > argv[i + 3] && *p3 != '/' && *p3 != '\\') p3--; + if (p3 > argv[i + 3]) + p3++; + strcpy (p2, p3); + p2 += strlen (p2) + 1; + printf ("saved as '%s'\n", p3); + } + printf ("Writing updated '%s'\n", wu); + f = fopen(wu,"wb"); + if (!f) { + printf("Couldn't open '%s' for writing\n", wu); + return 0; + } + fwrite (b, 1, size, f); + fclose (f); + printf ("done\n"); + return 0; +} + + + + + + + + + + + + diff --git a/od-win32/shm.c b/od-win32/shm.c new file mode 100755 index 00000000..ed970b59 --- /dev/null +++ b/od-win32/shm.c @@ -0,0 +1,172 @@ +#include + +#include "sysconfig.h" +#include "sysdeps.h" +#include "sys/mman.h" +#include "include/memory.h" +#include "options.h" +#include "autoconf.h" + +static void win32_error (const char *format,...) +{ + LPVOID lpMsgBuf; + va_list arglist; + char buf[1000]; + + va_start (arglist, format ); + vsprintf (buf, format, arglist); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, + NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf,0,NULL); + write_log ("%s: %s",buf , (char*)lpMsgBuf); + va_end( arglist ); +} + +static struct shmid_ds shmids[ MAX_SHMID ]; + +uae_u32 natmem_offset; + +void init_shm( void ) +{ + int i; + +#ifdef NATMEM_OFFSET + uae_u32 addr; + + canbang = 1; + for( i = 0; i < MAX_SHMID; i++ ) { + shmids[i].attached = 0; + shmids[i].key = -1; + shmids[i].size = 0; + shmids[i].addr = (void*)0xffffffff; + shmids[i].name[0] = 0; + shmids[i].filemapping = INVALID_HANDLE_VALUE; + } + addr = 0x10000000; + while( addr < 0xa0000000 ) { + if (VirtualAlloc( (LPVOID)addr, 0x18800000, MEM_RESERVE, PAGE_EXECUTE_READWRITE )) { + VirtualFree ( (LPVOID)addr, 0, MEM_RELEASE); + addr += 0x01000000; + natmem_offset = addr; + break; + } + addr += 0x01000000; + } + if (natmem_offset) { + write_log( "NATMEM: Our special area is 0x%x\n", natmem_offset); + } else { + canbang = 0; + } +#endif +} + +static key_t get_next_shmkey( void ) +{ + key_t result = -1; + int i; + for( i = 0; i < MAX_SHMID; i++ ) + { + if( shmids[i].key == -1 ) + { + shmids[i].key = i; + result = i; + break; + } + } + return result; +} + +STATIC_INLINE key_t find_shmkey( key_t key ) +{ + int result = -1; + if( shmids[key].key == key ) + { + result = key; + } + return result; +} + +int mprotect(void *addr, size_t len, int prot) +{ + int result = 0; + + return result; +} + +int shmget(key_t key, size_t size, int shmflg, char *name) +{ + int result = -1; + + if( ( key == IPC_PRIVATE ) || ( ( shmflg & IPC_CREAT ) && ( find_shmkey( key ) == -1) ) ) { + write_log( "shmget of size %d for %s\n", size, name ); + if( ( result = get_next_shmkey() ) != -1 ) { + HANDLE h = CreateFileMapping (NULL, 0, PAGE_READWRITE, 0, size, NULL); + if (h == NULL) + win32_error ("CreateFileMapping %d\n", size); + shmids[result].filemapping = h; + shmids[result].size = size; + strcpy( shmids[result].name, name ); + } else { + result = -1; + } + } + return result; +} + +int shmctl(int shmid, int cmd, struct shmid_ds *buf) +{ + int result = -1; + + return result; + if( ( find_shmkey( shmid ) != -1 ) && buf ) { + switch( cmd ) + { + case IPC_STAT: + *buf = shmids[shmid]; + result = 0; + break; + case IPC_RMID: + shmids[shmid].key = -1; + shmids[shmid].name[0] = '\0'; + shmids[shmid].size = 0; + CloseHandle(shmids[shmid].filemapping); + shmids[shmid].filemapping = INVALID_HANDLE_VALUE; + result = 0; + break; + } + } + return result; +} + +void *shmat(int shmid, LPVOID shmaddr, int shmflg) +{ + struct shmid_ds *shm = &shmids[shmid]; + + if(shm->addr == shmaddr ) + return shm->addr; + shm->addr = MapViewOfFileEx (shm->filemapping, FILE_MAP_WRITE, 0, 0, shm->size, shmaddr); + if (addr == NULL) + win32_error("MapViewOfFileEx %08.8X", shmaddr); + write_log ("shmat %08.8X -> %08.8X\n", shmaddr, shm->addr); + shm->attached = 1; + return shm->addr; +} + +int shmdt(const void *shmaddr) +{ + int i; + if (shmaddr == (void*)0xffffffff) + return 0; + write_log("shmdt: %08.8X\n", shmaddr); + if (UnmapViewOfFile ((LPCVOID)shmaddr) == FALSE) { + win32_error("UnmapViewOfFile %08.8X", shmaddr); + return 0; + } + for( i = 0; i < MAX_SHMID; i++ ) { + struct shmid_ds *shm = &shmids[i]; + if (shm->addr == shmaddr) { + shm->addr = (void*)0xffffffff; + } + } + return -1; +} \ No newline at end of file diff --git a/od-win32/soundcheck.c b/od-win32/soundcheck.c new file mode 100755 index 00000000..5bd1cb1f --- /dev/null +++ b/od-win32/soundcheck.c @@ -0,0 +1,562 @@ +#include "sysconfig.h" +#include "sysdeps.h" + +#include +#include +#include +#include + +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;xGroupCount;x++) + { + if( EqualSid(psidAdministrators, ptgGroups->Groups[x].Sid) ) + { + bSuccess = TRUE; + break; + } + + } + FreeSid(psidAdministrators); + os_winnt_admin = bSuccess ? 1 : 0; + return 1; + } + +static int srates[] = { 22050, 32000, 44100, 0 }; + +int main (int argc, char **argv) +{ + int i; + + logfile = fopen("soundlog.txt","w"); + osdetect(); + write_log2("OS: %s %d.%d%s\n", os_winnt ? "NT" : "W9X/ME", osVersion.dwMajorVersion, osVersion.dwMinorVersion, os_winnt_admin ? " (Admin)" : ""); + + init_mmtimer(); + if (!QueryPerformanceFrequency(&qpf)) { + printf ("no QPF, exiting..\n"); + goto end; + } + write_log2("QPF: %.2fMHz\n", qpf.QuadPart / 1000000.0); + hwnd = GetConsoleHwnd(); + DirectSoundEnumerate ((LPDSENUMCALLBACK)DSEnumProc, 0); + devicenum = selectdevice (); + i = 0; + while (srates[i]) { + sounddata_frequency = srates[i]; + if (open_audio_ds ()) { + if (!timebegin ()) { + printf ("no MM timer, exiting..\n"); + goto end; + } + write_log2("\n"); + runtest (); + timeend (); + close_audio_ds (); + } else break; + i++; + } +end: + fclose(logfile); + return 0; +} + + + + + + + + + + + + diff --git a/od-win32/sounddep/sound.c b/od-win32/sounddep/sound.c new file mode 100755 index 00000000..8865f05a --- /dev/null +++ b/od-win32/sounddep/sound.c @@ -0,0 +1,671 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Win32 sound interface (DirectSound) + * + * Copyright 1997 Mathias Ortmann + * Copyright 1997-2001 Brian King + * Copyright 2000-2002 Bernd Roesch + * Copyright 2002-2003 Toni Wilen + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "memory.h" +#include "events.h" +#include "custom.h" +#include "gensound.h" +#include "sounddep/sound.h" +#include "threaddep/thread.h" +#include "ahidsound.h" +#include "avioutput.h" +#include "gui.h" +#include "dxwrap.h" +#include "win32.h" +#include "savestate.h" +#include "driveclick.h" + +#include +#include +#include + +#include + +int dsound_hardware_mixing = 0; + +#define ADJUST_SIZE 10 +#define EXP 1.3 + +#define FILTER_FREQUENCY 7000.0 + +//#define SOUND_DEBUG + +static int obtainedfreq; +static int have_sound; +static int paused; +static int mute; + +#define SND_MAX_BUFFER2 262144 +#define SND_MAX_BUFFER 512 + +uae_u16 sndbuffer[SND_MAX_BUFFER]; +uae_u16 *sndbufpt; +int sndbufsize; + +static int max_sndbufsize, snd_configsize, dsoundbuf; +static double filter_mul1, filter_mul2; + +static uae_sem_t sound_sem, sound_init_sem; + +#define MAX_SOUND_DEVICES 10 + +static char *sound_devices[MAX_SOUND_DEVICES]; +GUID sound_device_guid[MAX_SOUND_DEVICES]; +static int num_sound_devices; + +static LPDIRECTSOUND lpDS; +static LPDIRECTSOUNDBUFFER lpDSBprimary; +static LPDIRECTSOUNDBUFFER lpDSBsecondary; + +static DWORD writepos; + +int setup_sound (void) +{ + sound_available = 1; + return 1; +} + +int scaled_sample_evtime_orig; +static int lastfreq; +void update_sound (int freq) +{ + if (freq < 0) + freq = lastfreq; + lastfreq = freq; + if (have_sound) { + if (currprefs.gfx_vsync && currprefs.gfx_afullscreen) { + if (currprefs.ntscmode) + scaled_sample_evtime_orig = (unsigned long)(MAXHPOS_NTSC * MAXVPOS_NTSC * freq * CYCLE_UNIT + obtainedfreq - 1) / obtainedfreq; + else + scaled_sample_evtime_orig = (unsigned long)(MAXHPOS_PAL * MAXVPOS_PAL * freq * CYCLE_UNIT + obtainedfreq - 1) / obtainedfreq; + } else { + scaled_sample_evtime_orig = (unsigned long)(312.0 * 50 * CYCLE_UNIT / (obtainedfreq / 227.0)); + } + scaled_sample_evtime = scaled_sample_evtime_orig; + } +} + +static void clearbuffer (void) +{ + void *buffer; + DWORD size; + + HRESULT hr = IDirectSoundBuffer_Lock (lpDSBsecondary, 0, dsoundbuf, &buffer, &size, NULL, NULL, 0); + if (hr == DSERR_BUFFERLOST) { + IDirectSoundBuffer_Restore (lpDSBsecondary); + hr = IDirectSoundBuffer_Lock (lpDSBsecondary, 0, dsoundbuf, &buffer, &size, NULL, NULL, 0); + } + if (hr != DS_OK) { + write_log ("failed to Lock sound buffer (clear): %s\n", DXError (hr)); + return; + } + memset (buffer, 0, size); + IDirectSoundBuffer_Unlock (lpDSBsecondary, buffer, size, NULL, 0); + memset (sndbuffer, 0, sizeof (sndbuffer)); +} + +static void pause_audio_ds (void) +{ + IDirectSoundBuffer_Stop (lpDSBsecondary); + clearbuffer (); +} + +static void resume_audio_ds (void) +{ + HRESULT hr; + + paused = 0; + clearbuffer (); + hr = IDirectSoundBuffer_Play (lpDSBsecondary, 0, 0, DSBPLAY_LOOPING); + if (hr != DS_OK) + write_log ("Play failed: %s\n", DXError (hr)); + writepos = snd_configsize; +} + +static int restore (DWORD hr) +{ + if (hr != DSERR_BUFFERLOST) + return 0; +#ifdef SOUND_DEBUG + write_log ("sound buffer lost\n"); +#endif + hr = IDirectSoundBuffer_Restore (lpDSBsecondary); + if (hr != DS_OK) { + //write_log ("restore failed %s\n", DXError (hr)); + return 1; + } + resume_audio_ds (); + return 1; +} + +static LARGE_INTEGER qpfc, qpf; +static void storeqpf (void) +{ + QueryPerformanceCounter(&qpfc); +} +static double getqpf (void) +{ + LARGE_INTEGER qpfc2; + QueryPerformanceCounter(&qpfc2); + return (qpfc2.QuadPart - qpfc.QuadPart) / (qpf.QuadPart / 1000.0); +} + +static int getpos (void) +{ + DWORD playpos, safepos; + HRESULT hr; + + hr = IDirectSoundBuffer_GetCurrentPosition (lpDSBsecondary, &playpos, &safepos); + if (hr != DS_OK) { + write_log ("GetCurrentPosition failed: %s\n", DXError (hr)); + return -1; + } + return playpos; +} + +static int calibrate (void) +{ + int len = 1000; + int pos, lastpos, tpos, expected, diff; + int mult = currprefs.stereo ? 4 : 2; + double qv, pct; + + if (!QueryPerformanceFrequency(&qpf)) { + write_log ("no QPF, can't calibrate\n"); + return 100 * 10; + } + pos = 1000; + pause_audio_ds (); + resume_audio_ds (); + while (pos >= 1000) + pos = getpos(); + while (pos < 1000) + pos = getpos(); + lastpos = getpos(); + storeqpf (); + tpos = 0; + do { + pos = getpos(); + if (pos < lastpos) { + tpos += dsoundbuf - lastpos + pos; + } else { + tpos += pos - lastpos; + } + lastpos = pos; + qv = getqpf(); + } while (qv < len); + expected = (int)(len / 1000.0 * currprefs.sound_freq); + tpos /= mult; + diff = tpos - expected; + pct = tpos * 100.0 / expected; + write_log ("sound calibration: %d %d (%d %.2f%%)\n", tpos, expected, diff, pct); + return (int)(pct * 10); +} + +static void close_audio_ds (void) +{ + if (lpDSBsecondary) + IDirectSound_Release (lpDSBsecondary); + if (lpDSBprimary) + IDirectSound_Release (lpDSBprimary); + lpDSBsecondary = lpDSBprimary = 0; + if (lpDS) { + IDirectSound_Release (lpDS); + write_log ("DirectSound driver freed\n"); + } + lpDS = 0; +} + +extern HWND hMainWnd; + +static void setvolume (void) +{ + HRESULT hr; + LONG vol = DSBVOLUME_MIN; + + if (currprefs.sound_volume < 100 && !mute) + vol = (LONG)((DSBVOLUME_MIN / 2) + (-DSBVOLUME_MIN / 2) * log (1 + (2.718281828 - 1) * (1 - currprefs.sound_volume / 100.0))); + hr = IDirectSoundBuffer_SetVolume (lpDSBsecondary, vol); + if (hr != DS_OK) + write_log ("SOUND: SetVolume(%d) failed: %s\n", vol, DXError (hr)); +} + +static int open_audio_ds (int size) +{ + HRESULT hr; + DSBUFFERDESC sound_buffer; + DSCAPS DSCaps; + DSBCAPS DSBCaps; + WAVEFORMATEX wavfmt; + int minfreq, maxfreq; + int freq = currprefs.sound_freq; + + enumerate_sound_devices (0); + if (dsound_hardware_mixing) { + size <<= 3; + } else { + size <<= 1; + if (currprefs.stereo) + size <<= 1; + } + snd_configsize = size; + sndbufsize = size / 32; + if (sndbufsize > SND_MAX_BUFFER) + sndbufsize = SND_MAX_BUFFER; + + hr = DirectSoundCreate (&sound_device_guid[currprefs.win32_soundcard], &lpDS, NULL); + if (hr != DS_OK) { + write_log ("SOUND: DirectSoundCreate() failure: %s\n", DXError (hr)); + return 0; + } + memset (&DSCaps, 0, sizeof (DSCaps)); + DSCaps.dwSize = sizeof(DSCaps); + hr = IDirectSound_GetCaps (lpDS, &DSCaps); + if (hr!= DS_OK) { + write_log ("SOUND: Error getting DirectSound capabilities: %s\n", DXError (hr)); + goto error; + } + if (DSCaps.dwFlags & DSCAPS_EMULDRIVER) { + write_log ("SOUND: Emulated DirectSound driver detected, don't complain if sound quality is crap :)\n"); + } + minfreq = DSCaps.dwMinSecondarySampleRate; + maxfreq = DSCaps.dwMaxSecondarySampleRate; + if (maxfreq > 11000) { + if (minfreq > freq) { + freq = minfreq; + changed_prefs.sound_freq = currprefs.sound_freq = freq; + write_log("SOUND: minimum supported frequency: %d\n", minfreq); + } + if (maxfreq < freq) { + freq = maxfreq; + changed_prefs.sound_freq = currprefs.sound_freq = freq; + write_log("SOUND: maximum supported frequency: %d\n", maxfreq); + } + } else { + write_log("SOUND: ignored weird min (%d) or max (%d) sample rate\n", minfreq, maxfreq); + } + filter_mul1 = exp (-FILTER_FREQUENCY / freq); + filter_mul2 = 1 - filter_mul1; + + memset (&sound_buffer, 0, sizeof (sound_buffer)); + sound_buffer.dwSize = sizeof (sound_buffer); + sound_buffer.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_GETCURRENTPOSITION2; + hr = IDirectSound_CreateSoundBuffer (lpDS, &sound_buffer, &lpDSBprimary, NULL); + if( hr != DS_OK ) { + write_log ("SOUND: Primary CreateSoundBuffer() failure: %s\n", DXError (hr)); + goto error; + } + + memset(&DSBCaps, 0, sizeof(DSBCaps)); + DSBCaps.dwSize = sizeof(DSBCaps); + hr = IDirectSoundBuffer_GetCaps(lpDSBprimary, &DSBCaps); + if (hr != DS_OK) { + write_log ("SOUND: Primary GetCaps() failure: %s\n", DXError (hr)); + goto error; + } + + wavfmt.wFormatTag = WAVE_FORMAT_PCM; + wavfmt.nChannels = dsound_hardware_mixing ? 4 : (currprefs.stereo ? 2 : 1); + wavfmt.nSamplesPerSec = freq; + wavfmt.wBitsPerSample = 16; + wavfmt.nBlockAlign = 16 / 8 * wavfmt.nChannels; + wavfmt.nAvgBytesPerSec = wavfmt.nBlockAlign * freq; + + max_sndbufsize = size * 3; + if (max_sndbufsize > SND_MAX_BUFFER2) + max_sndbufsize = SND_MAX_BUFFER2; + dsoundbuf = max_sndbufsize * 2; + hr = IDirectSound_SetCooperativeLevel (lpDS, hMainWnd, DSSCL_PRIORITY); + if (hr != DS_OK) { + write_log ("SOUND: Can't set cooperativelevel: %s\n", DXError (hr)); + goto error; + } + if (dsoundbuf < DSBSIZE_MIN) + dsoundbuf = DSBSIZE_MIN; + if (dsoundbuf > DSBSIZE_MAX) + dsoundbuf = DSBSIZE_MAX; + if (max_sndbufsize > dsoundbuf) + max_sndbufsize = dsoundbuf; + + memset (&sound_buffer, 0, sizeof (sound_buffer)); + sound_buffer.dwSize = sizeof (sound_buffer); + sound_buffer.dwBufferBytes = dsoundbuf; + sound_buffer.lpwfxFormat = &wavfmt; + sound_buffer.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS | DSBCAPS_STATIC; + sound_buffer.dwFlags |= DSBCAPS_CTRLVOLUME; + + hr = IDirectSound_CreateSoundBuffer( lpDS, &sound_buffer, &lpDSBsecondary, NULL ); + if (hr != DS_OK) { + write_log ("SOUND: Secondary CreateSoundBuffer() failure: %s\n", DXError (hr)); + goto error; + } + + hr = IDirectSoundBuffer_SetFormat (lpDSBprimary, &wavfmt); + if( hr != DS_OK ) { + write_log ("SOUND: Primary SetFormat() failure: %s\n", DXError (hr)); + goto error; + } + setvolume (); + + clearbuffer (); + + init_sound_table16 (); + if (dsound_hardware_mixing) + sample_handler = sample16ss_handler; + else + sample_handler = currprefs.stereo ? sample16s_handler : sample16_handler; + + write_log ("DS driver '%s'/%d/%d bits/%d Hz/buffer %d/dist %d\n", + sound_devices[currprefs.win32_soundcard], dsound_hardware_mixing ? 4 : (currprefs.stereo ? 2 : 1), 16, freq, max_sndbufsize, snd_configsize); + obtainedfreq = currprefs.sound_freq; + + return 1; + +error: + close_audio_ds (); + return 0; +} + +static int open_sound (void) +{ + int ret; + int size = currprefs.sound_maxbsiz; + + if (!currprefs.produce_sound) + return 0; + /* Always interpret buffer size as number of samples, not as actual + buffer size. Of course, since 8192 is the default, we'll have to + scale that to a sane value (assuming that otherwise 16 bits and + stereo would have been enabled and we'd have done the shift by + two anyway). */ + size >>= 2; + if (size & (size - 1)) + size = DEFAULT_SOUND_MAXB; + if (size < 512) + size = 512; + + ret = open_audio_ds (size); + if (!ret) + return 0; + + have_sound = 1; + sound_available = 1; + update_sound (fake_vblank_hz); + sndbufpt = sndbuffer; + driveclick_init (); + + return 1; +} + +void close_sound (void) +{ + if (! have_sound) + return; + pause_sound (); + close_audio_ds (); + have_sound = 0; +} + +int init_sound (void) +{ + if (have_sound) + return 1; + if (!open_sound ()) + return 0; + paused = 1; + driveclick_reset (); + resume_sound (); + return 1; +} + +void pause_sound (void) +{ + if (paused) + return; + paused = 1; + if (!have_sound) + return; + pause_audio_ds (); + clearbuffer(); +} + +void resume_sound (void) +{ + if (!paused) + return; + if (!have_sound) + return; + clearbuffer (); + resume_audio_ds (); +} + +void reset_sound (void) +{ + if (!have_sound) + return; + clearbuffer (); +} + +#ifdef JIT +extern uae_u8* compiled_code; +#else +static int compiled_code; +#endif +extern int vsynctime_orig; + +#ifndef AVIOUTPUT +static int avioutput_audio; +#endif + +void sound_setadjust (double v) +{ + double mult; + + mult = (1000.0 + currprefs.sound_adjust + v); + if ((currprefs.gfx_vsync && currprefs.gfx_afullscreen) || (avioutput_audio && !compiled_code)) { + vsynctime = vsynctime_orig; + scaled_sample_evtime = (long)(((double)scaled_sample_evtime_orig) * mult / 1000.0); + } else if (compiled_code) { + vsynctime = (long)(((double)vsynctime_orig) * mult / 1000.0); + scaled_sample_evtime = scaled_sample_evtime_orig; + } else + vsynctime = vsynctime_orig * 9 / 10; +} + +static void finish_sound_buffer_ds (void) +{ + DWORD playpos, safepos; + HRESULT hr; + void *b1, *b2; + DWORD s1, s2; + int diff; + double vdiff, m, skipmode; + + for (;;) { + hr = IDirectSoundBuffer_GetCurrentPosition (lpDSBsecondary, &playpos, &safepos); + if (hr != DS_OK) { + restore (hr); + //write_log ("GetCurrentPosition failed: %s\n", DirectSound_ErrorText (hr)); + return; + } + + if (savestate_state) + return; + + if (writepos >= playpos) + diff = writepos - playpos; + else + diff = dsoundbuf - playpos + writepos; + + if (diff >= max_sndbufsize) { + writepos = safepos + snd_configsize; + if (writepos >= dsoundbuf) + writepos -= dsoundbuf; + diff = snd_configsize; + break; + } + + if (diff > max_sndbufsize * 6 / 8) { + sleep_millis_busy (1); + continue; + } + break; + } + + hr = IDirectSoundBuffer_Lock (lpDSBsecondary, writepos, sndbufsize, &b1, &s1, &b2, &s2, 0); + if (restore (hr)) + return; + if (hr != DS_OK) { + write_log ("lock failed: %s (%d %d)\n", DXError (hr), writepos, sndbufsize); + return; + } + memcpy (b1, sndbuffer, sndbufsize >= s1 ? s1 : sndbufsize); + if (b2) + memcpy (b2, (uae_u8*)sndbuffer + s1, sndbufsize - s1); + IDirectSoundBuffer_Unlock (lpDSBsecondary, b1, s1, b2, s2); + + vdiff = diff - snd_configsize; + m = 100.0 * vdiff / max_sndbufsize; + skipmode = pow (m < 0 ? -m : m, EXP)/ 10.0; + + if (m < 0) skipmode = -skipmode; + if (skipmode < -ADJUST_SIZE) skipmode = -ADJUST_SIZE; + if (skipmode > ADJUST_SIZE) skipmode = ADJUST_SIZE; + +#ifdef SOUND_DEBUG + if (!(timeframes % 10)) { + write_log ("b=%5d,%5d,%5d,%5d diff=%5d vdiff=%5.0f vdiff2=%5d skip=%+02.1f\n", + sndbufsize, snd_configsize, max_sndbufsize, dsoundbuf, diff, vdiff, diff - snd_configsize, skipmode); + } +#endif + + writepos += sndbufsize; + if (writepos >= dsoundbuf) + writepos -= dsoundbuf; + + sound_setadjust (skipmode); +} + +static void filtercheck (uae_s16 *sndbuffer, int len) +{ + int ch = dsound_hardware_mixing ? 4 : (currprefs.stereo ? 2 : 1); + int i; + static double cold[4]; + double old0, old1, v; + + if (!currprefs.sound_filter) + return; + if (gui_data.powerled || currprefs.sound_filter == 2) { + if (ch == 1) { + old0 = cold[0]; + for (i = 0; i < len; i++) { + v = old0 = old0 * filter_mul1 + filter_mul2 * sndbuffer[i]; + if (v < -32768) v = -32768; + if (v > 32767) v = 32767; + sndbuffer[i] = (uae_s16)v; + } + cold[0] = old0; + } else { + old0 = cold[0]; + old1 = cold[1]; + for (i = 0; i < len; i += 2) { + v = old0 = old0 * filter_mul1 + filter_mul2 * sndbuffer[i]; + if (v < -32768) v = -32768; + if (v > 32767) v = 32767; + sndbuffer[i] = (uae_s16)v; + v = old1 = old1 * filter_mul1 + filter_mul2 * sndbuffer[i + 1]; + if (v < -32768) v = -32768; + if (v > 32767) v = 32767; + sndbuffer[i + 1] = (uae_s16)v; + } + cold[0] = old0; + cold[1] = old1; + } + } +} + +void finish_sound_buffer (void) +{ + if (!have_sound || turbo_emulation) + return; + filtercheck ((uae_s16*)sndbuffer, sndbufsize / 2); +#ifdef DRIVESOUND + driveclick_mix ((uae_s16*)sndbuffer, sndbufsize / 2); +#endif +#ifdef AVIOUTPUT + if (avioutput_audio) + AVIOutput_WriteAudio ((uae_u8*)sndbuffer, sndbufsize); + if (!avioutput_framelimiter && (avioutput_video || avioutput_audio)) + return; +#endif + finish_sound_buffer_ds (); +} + +static BOOL CALLBACK DSEnumProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID lpContext) +{ + int i = num_sound_devices; + if (i == MAX_SOUND_DEVICES) + return TRUE; + if (lpGUID != NULL) + memcpy (&sound_device_guid[i], lpGUID, sizeof (GUID)); + sound_devices[i] = my_strdup (lpszDesc); + num_sound_devices++; + return TRUE; +} + +char **enumerate_sound_devices (int *total) +{ + if (!num_sound_devices) + DirectSoundEnumerate ((LPDSENUMCALLBACK)DSEnumProc, 0); + if (total) + *total = num_sound_devices; + if (currprefs.win32_soundcard >= num_sound_devices) + currprefs.win32_soundcard = 0; + if (num_sound_devices) + return sound_devices; + return 0; +} + +int sound_calibrate (HWND hwnd, struct uae_prefs *p) +{ + HWND old = hMainWnd; + int pct = 100 * 10; + + hMainWnd = hwnd; + currprefs.sound_freq = p->sound_freq; + currprefs.stereo = p->stereo; + if (open_sound ()) { + SetThreadPriority ( GetCurrentThread(), THREAD_PRIORITY_HIGHEST); + pct = calibrate (); + SetThreadPriority ( GetCurrentThread(), THREAD_PRIORITY_NORMAL); + close_sound (); + } + hMainWnd = old; + return pct; +} + +void sound_volume (int dir) +{ + if (dir == 0) + mute = mute ? 0 : 1; + currprefs.sound_volume -= dir * 10; + if (currprefs.sound_volume < 0) + currprefs.sound_volume = 0; + if (currprefs.sound_volume > 100) + currprefs.sound_volume = 100; + changed_prefs.sound_volume = currprefs.sound_volume; + setvolume (); +} diff --git a/od-win32/sounddep/sound.h b/od-win32/sounddep/sound.h new file mode 100755 index 00000000..2bb8ea7c --- /dev/null +++ b/od-win32/sounddep/sound.h @@ -0,0 +1,51 @@ +/* + * UAE - The Un*x Amiga Emulator + * + * Support for Linux/USS sound + * + * Copyright 1997 Bernd Schmidt + */ + +extern int sound_fd; +extern uae_u16 sndbuffer[]; +extern uae_u16 *sndbufpt; +extern int sndbufsize; +extern void finish_sound_buffer (void); +extern int init_sound (void); +extern void close_sound (void); +extern int setup_sound (void); +extern void resume_sound (void); +extern void pause_sound (void); +extern void reset_sound (void); +extern void sound_setadjust (double); +extern char **enumerate_sound_devices (int *total); +extern int drivesound_init (void); +extern void drivesound_free (void); +extern void sound_volume (int); + +static __inline__ void check_sound_buffers (void) +{ + if ((char *)sndbufpt - (char *)sndbuffer >= sndbufsize) { + finish_sound_buffer (); + sndbufpt = sndbuffer; + } +} + +#define PUT_SOUND_BYTE(b) do { *(uae_u8 *)sndbufpt = b; sndbufpt = (uae_u16 *)(((uae_u8 *)sndbufpt) + 1); } while (0) +#define PUT_SOUND_WORD(b) do { *(uae_u16 *)sndbufpt = b; sndbufpt = (uae_u16 *)(((uae_u8 *)sndbufpt) + 2); } while (0) +#define PUT_SOUND_BYTE_LEFT(b) PUT_SOUND_BYTE(b) +#define PUT_SOUND_WORD_LEFT(b) PUT_SOUND_WORD(b) +#define PUT_SOUND_BYTE_RIGHT(b) PUT_SOUND_BYTE(b) +#define PUT_SOUND_WORD_RIGHT(b) PUT_SOUND_WORD(b) +#define SOUND16_BASE_VAL 0 +#define SOUND8_BASE_VAL 128 + +#define DEFAULT_SOUND_MAXB 16384 +#define DEFAULT_SOUND_MINB 16384 +#define DEFAULT_SOUND_BITS 16 +#define DEFAULT_SOUND_FREQ 44100 +#define HAVE_STEREO_SUPPORT + +#ifdef AHI +#include "ahidsound.h" +#endif diff --git a/od-win32/srcrelease.bat b/od-win32/srcrelease.bat new file mode 100755 index 00000000..462f81f4 --- /dev/null +++ b/od-win32/srcrelease.bat @@ -0,0 +1,87 @@ +cd c:\projects\winuae_bak +rm -rf bak +mkdir bak +copy /s c:\projects\winuae\src\*.* c:\projects\winuae_bak\bak\ +cd bak +del *.obj *.ilk *.exe *.pdb *.pch *.idb /s + +del cpudefs.c +del blit.h +del blitfunc.c +del blitfunc.h +del blittable.c +del cputbl.h +del cpustbl.c +del compemu.c +del comptbl.h +del compstbl.c +del cpuemu_0.c +del cpuemu_5.c +del cpuemu_6.c + +cd od-win32 + +cd build68k_msvc +rm -f build68k.exe build68k_msvc.plg +rm -rf debug +rm -rf release +cd .. + +cd genblitter_msvc +rm -f genblitter.exe genblitter_msvc.plg +rm -rf debug +rm -rf release +cd .. + +cd gencomp_msvc +rm -f gencomp.exe gencomp_msvc.plg +rm -rf debug +rm -rf release +cd .. + +cd gencpu_msvc +rm -f gencpu.exe gencpu_msvc.plg +rm -rf debug +rm -rf release +cd .. + +cd winuae_msvc +rm -f winuae_msvc.plg +rm -f winuae_msvc.ncb +rm -rf debug +rm -rf release +cd .. + +cd miniuae +rm -f winuae_msvc.plg +rm -f winuae_msvc.ncb +rm -rf debug +rm -rf release +cd .. + +cd winuae_nogui +rm -rf debug +rm -rf release +cd .. + +cd soundcheck +rm -rf debug +rm -rf release +cd .. + +cd singlefilehelper +rm -rf debug +rm -rf release +cd .. + +cd resourcedll +rm -rf debug +rm -rf release +cd .. +cd .. + +zip -9 -r winuaesrc * + +move winuaesrc.zip d:\amiga +cd c:\projects\winuae\src\od-win32 + diff --git a/od-win32/support.c b/od-win32/support.c new file mode 100755 index 00000000..817f1bf6 --- /dev/null +++ b/od-win32/support.c @@ -0,0 +1,17 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Miscellaneous machine dependent support functions and definitions + * + * Copyright 1996 Bernd Schmidt + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "machdep/m68k.h" + +struct flag_struct regflags; + diff --git a/od-win32/sys/ipc.h b/od-win32/sys/ipc.h new file mode 100755 index 00000000..8b137891 --- /dev/null +++ b/od-win32/sys/ipc.h @@ -0,0 +1 @@ + diff --git a/od-win32/sys/mman.h b/od-win32/sys/mman.h new file mode 100755 index 00000000..eb8a81b0 --- /dev/null +++ b/od-win32/sys/mman.h @@ -0,0 +1,47 @@ +// Implement MMAN and SHM functionality for Win32 +// Copyright (C) 2000, Brian King +// GNU Public License + +#ifndef _MMAN_H_ +#define _MMAN_H_ + +#include +#include // for size_t +#include +#include + +#define MAX_SHMID 256 + +extern uae_u32 natmem_offset; + +typedef int key_t; +typedef USHORT ushort; + +/* One shmid data structure for each shared memory segment in the system. */ +struct shmid_ds { + key_t key; + size_t size; + void *addr; + char name[ MAX_PATH ]; + void *attached; +}; + +int mprotect (void *addr, size_t len, int prot); +void *shmat (int shmid, LPVOID shmaddr, int shmflg); +int shmdt (const void *shmaddr); +int shmget (key_t key, size_t size, int shmflg, char*); +int shmctl (int shmid, int cmd, struct shmid_ds *buf); +void init_shm (void); + +int isinf( double x ); +int isnan( double x ); + +#define PROT_READ 0x01 +#define PROT_WRITE 0x02 +#define PROT_EXEC 0x04 + +#define IPC_PRIVATE 0x01 +#define IPC_RMID 0x02 +#define IPC_CREAT 0x04 +#define IPC_STAT 0x08 +#endif \ No newline at end of file diff --git a/od-win32/sys/shm.h b/od-win32/sys/shm.h new file mode 100755 index 00000000..8b137891 --- /dev/null +++ b/od-win32/sys/shm.h @@ -0,0 +1 @@ + diff --git a/od-win32/sysconfig.h b/od-win32/sysconfig.h new file mode 100755 index 00000000..fabbbbeb --- /dev/null +++ b/od-win32/sysconfig.h @@ -0,0 +1,465 @@ + +#pragma warning (disable : 4761) + +#define DIRECTINPUT_VERSION 0x0800 +#define DIRECT3D_VERSION 0x0900 +#define SUPPORT_THREADS + +#define DRIVESOUND +#define GFXFILTER + +#ifndef UAE_MINI + +#define FILESYS /* filesys emulation */ +#define UAE_FILESYS_THREADS +#define AUTOCONFIG /* autoconfig support, fast ram, harddrives etc.. */ +#define JIT /* JIT compiler support */ +#undef USE_SDL +#define NATMEM_OFFSET natmem_offset +#define CAN_DO_STACK_MAGIC +#define USE_NORMAL_CALLING_CONVENTION 1 +#define USE_X86_FPUCW 1 +#define WINDDK /* Windows DDK available, keyboard leds and harddrive support */ +#define CATWEASEL /* Catweasel MK2/3 support */ +#define AHI /* AHI sound emulation */ +#define AGA /* AGA chipset emulation */ +#define CD32 /* CD32 emulation */ +#define CDTV /* CDTV emulation */ +#define D3D /* D3D display support */ +#define OPENGL /* OpenGL display support */ +#define PARALLEL_PORT /* parallel port emulation */ +#define PARALLEL_DIRECT /* direct parallel port emulation */ +#define SERIAL_PORT /* serial port emulation */ +#define SCSIEMU /* uaescsi.device emulation */ +#define FPUEMU /* FPU emulation */ +#define CPUEMU_0 /* generic 680x0 emulation */ +#define CPUEMU_5 /* 68000+prefetch emulation */ +#define CPUEMU_6 /* cycle-exact cpu&blitter */ +#define ACTION_REPLAY /* Action Replay 1/2/3 support */ +#define PICASSO96 /* Picasso96 display card emulation */ +#define BSDSOCKET /* bsdsocket.library emulation */ +#define CAPS /* CAPS-image support */ +#define AVIOUTPUT /* Avioutput support */ + +#else + +/* #define SINGLEFILE */ + +#define CUSTOM_SIMPLE /* simplified custom chipset emulation */ +#define CPUEMU_0 +#define CPUEMU_68000_ONLY /* drop 68010+ commands from CPUEMU_0 */ +#ifndef UAE_NOGUI +#define D3D +#define OPENGL +#endif +#define CAPS +#define CPUEMU_6 +#define CPUEMU_5 + +#endif + +#ifdef _DEBUG +#define _CRTDBG_MAP_ALLOC +#include +#include +#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 doesn't define. */ +/* #undef mode_t */ +#define mode_t int + +/* Define to `long' if doesn't define. */ +/* #undef off_t */ + +/* Define to `int' if 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 and . */ +#ifdef __GNUC__ +#define TIME_WITH_SYS_TIME 1 +#endif + +#ifdef _WIN32_WCE +#define NO_TIME_H 1 +#endif + +/* Define if your 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: + and . [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 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 header file. */ +/* #undef HAVE_CURSES_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_CYBERGRAPHX_CYBERGRAPHICS_H */ + +/* Define if you have the header file. */ +#ifndef _WIN32_WCE +#define HAVE_DDRAW_H 1 +#endif + +/* Define if you have the header file. */ +/* #undef HAVE_DEVICES_AHI_H */ + +/* Define if you have the header file. */ +/* #define HAVE_DIRENT_H 1 */ + +/* Define if you have the header file. */ +#ifndef _WIN32_WCE +#define HAVE_FCNTL_H 1 +#endif + +/* Define if you have the header file. */ +/* #undef HAVE_FEATURES_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_GETOPT_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_GGI_LIBGGI_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_LIBRARIES_CYBERGRAPHICS_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_MACHINE_JOYSTICK_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_MACHINE_SOUNDCARD_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_MNTENT_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_MNTTAB_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_NCURSES_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_NDIR_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_POSIX_OPT_H */ + +#ifndef _WIN32_WCE +/* Define if you have the header file. */ +#define HAVE_STRING_H 1 +#endif + +/* Define if you have the header file. */ +/* #undef HAVE_STRINGS_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SUN_AUDIOIO_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_AUDIOIO_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_FILSYS_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_FS_S5PARAM_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_FS_TYPES_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_FSTYP_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_IOCTL_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_IPC_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_MOUNT_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_PARAM_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_SHM_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_SOUNDCARD_H */ + +/* Define if you have the header file. */ +#ifndef _WIN32_WCE +#define HAVE_SYS_STAT_H 1 +#endif + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_STATFS_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_STATVFS_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_TERMIOS_H */ + +/* Define if you have the header file. */ +#ifdef __GNUC__ +#define HAVE_SYS_TIME_H 1 +#endif + +/* Define if you have the header file. */ +#ifndef _WIN32_WCE +#define HAVE_SYS_TYPES_H 1 +#endif + +/* Define if you have the header file. */ +#ifndef _WIN32_WCE +#define HAVE_SYS_UTIME_H 1 +#endif + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_VFS_H */ + +/* Define if you have the header file. */ +#ifdef __GNUC__ +#define HAVE_UNISTD_H 1 +#endif + +/* Define if you have the header file. */ +/* #undef HAVE_UTIME_H */ + +/* Define if you have the header file. */ +#ifdef __GNUC__ +#define HAVE_VALUES_H 1 +#endif + +/* Define if you have the header file. */ +#define HAVE_WINDOWS_H 1 + +#define FSDB_DIR_SEPARATOR '\\' diff --git a/od-win32/target.h b/od-win32/target.h new file mode 100755 index 00000000..4afd596e --- /dev/null +++ b/od-win32/target.h @@ -0,0 +1,25 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Target specific stuff, Win32 version + * + * Copyright 1997 Mathias Ortmann + */ + +#ifdef _WIN32_WCE +#define TARGET_NAME "WinCE" +#define TARGET_NO_AUTOCONF +#define TARGET_NO_ZFILE +#define DONT_PARSE_CMDLINE +#else +#define TARGET_NAME "win32" +#endif +#define TARGET_PROVIDES_DEFAULT_PREFS +#define TARGET_NO_DITHER + +#define NO_MAIN_IN_MAIN_C + +#define OPTIONSFILENAME "default.uae" + +#define DEFPRTNAME "none" +#define DEFSERNAME "none" diff --git a/od-win32/threaddep/thread.h b/od-win32/threaddep/thread.h new file mode 100755 index 00000000..551bb434 --- /dev/null +++ b/od-win32/threaddep/thread.h @@ -0,0 +1,64 @@ + +#if 1 + +typedef HANDLE uae_sem_t; +typedef int uae_thread_id; +extern void sem_close (void*); +extern int sem_trywait (void*); +extern void sem_post (void*); +extern void sem_wait (void*t); +extern void sem_init (void*, int manual_reset, int initial_state); +extern int start_penguin (void *(*f)(void *), void *arg, DWORD * foo); +extern void set_thread_priority (int); + +#define uae_sem_init sem_init +#define uae_sem_destroy sem_close +#define uae_sem_post sem_post +#define uae_sem_wait sem_wait +#define uae_sem_trywait sem_trywait +#define uae_start_thread start_penguin + +#include "commpipe.h" + +#else + +/* + * UAE - The Un*x Amiga Emulator + * + * Threading support, using SDL + * + * Copyright 1997, 2001 Bernd Schmidt + */ + +#include "SDL.h" +#include "SDL_thread.h" + +/* Sempahores. We use POSIX semaphores; if you are porting this to a machine + * with different ones, make them look like POSIX semaphores. */ +typedef SDL_sem *uae_sem_t; + +#define uae_sem_init(PSEM, DUMMY, INIT) do { \ + *PSEM = SDL_CreateSemaphore (INIT); \ +} while (0) +#define uae_sem_destroy(PSEM) SDL_DestroySemaphore (*PSEM) +#define uae_sem_post(PSEM) SDL_SemPost (*PSEM) +#define uae_sem_wait(PSEM) SDL_SemWait (*PSEM) +#define uae_sem_trywait(PSEM) SDL_SemTryWait (*PSEM) +#define uae_sem_getvalue(PSEM) SDL_SemValue (*PSEM) + +#include "commpipe.h" +extern void set_thread_priority (int); + +typedef SDL_Thread *uae_thread_id; +#define BAD_THREAD NULL + +static __inline__ int uae_start_thread (void *(*f) (void *), void *arg, uae_thread_id *foo) +{ + *foo = SDL_CreateThread ((int (*)(void *))f, arg); + return *foo == 0; +} + +/* Do nothing; thread exits if thread function returns. */ +#define UAE_THREAD_EXIT do {} while (0) + +#endif \ No newline at end of file diff --git a/od-win32/unistd.h b/od-win32/unistd.h new file mode 100755 index 00000000..8b137891 --- /dev/null +++ b/od-win32/unistd.h @@ -0,0 +1 @@ + diff --git a/od-win32/wcc.sh b/od-win32/wcc.sh new file mode 100755 index 00000000..db622a00 --- /dev/null +++ b/od-win32/wcc.sh @@ -0,0 +1,266 @@ +#! /bin/sh +# +# Somewhat horrible shell script to convert GCC style options into Watcom +# style. +# +# I put this into the public domain - if you think you can use it for +# anything, use it. +# +# Written 1998 Bernd Schmidt + +realdirname () { + tmp_save_dir=`pwd` + cd $@ + result=`pwd -P` + cd $tmp_save_dir + result=`echo $result |sed 's,/,\\\\,g'` +} + +realfilename () { + case $@ in + */*) + tmp_save_dir=`pwd` + cd `echo $@ | sed 's,/[^/]*$,,'` + result=`pwd -P`/`basename $@` + cd $tmp_save_dir + ;; + *) + result=$@ + ;; + esac + result=`echo $result |sed 's,/,\\\\,g'` +} + +gcc_wsysinc1=`echo $INCLUDE | sed 's,;, ,g' | sed 's,.:,;\\0,g' |sed -e 's,;,//,g' -e 's,:,/,g' -e 's,\\\\,/,g'` +for foo in $gcc_wsysinc1; do + gcc_wsysinc2="$gcc_wsysinc2 -I$foo" +done +gcc_spcdefs="-undef -U__GNUC__ -U__GNUC_MINOR__ -D_WIN32 -D__WATCOMC__ -D_STDCALL_SUPPORTED=1 -D__X86__ -D__386__=1 -DM_I386=1 -D_M_I386 -D_M_IX86=500 -D__NT__=1" + +mode=link +options= +srcfiles= +asmfiles= +objfiles= +resfiles= +outputfile= +libraries= +gnudefines= +wccdefines= +includes= +gnuincludes= + +next_is_output=no +next_is_include=no + +for arg in $@; do + +if test $next_is_output = yes; then + outputfile=$arg + next_is_output=no +else if test $next_is_include = yes; then + includes="$includes $arg" + gnuincludes="$gnuincludes -I$arg" + next_is_include=no +else + case $arg in +# Passing /xxx options directly may be too risky - they could be confused for +# file names - so use this escape. + --/--*) + options="$options `echo $arg |sed s,^--/--,/,`" + ;; + + -I) next_is_include=yes + ;; + + -I*) + includes="$includes `echo $arg | sed 's,^-I,,'`" + gnuincludes="$gnuincludes $arg" + ;; + + -D*=*) + gnudefines="$gnudefines $arg" + wccdefines="$wccdefines `echo $arg |sed 's,^-D,/d,'`" + ;; + + -D*) + gnudefines="$gnudefines $arg" + wccdefines="$wccdefines `echo $arg |sed 's,^-D,/d,'`=" + ;; + + -c) if [ "$mode" != "link" ]; then + echo "Bad argument" + exit 10 + fi + mode=compile + ;; + + -S) if [ "$mode" != "link" ]; then + echo "Bad argument" + exit 10 + fi + mode=assemble + ;; + + -E) if [ "$mode" != "link" ]; then + echo "Bad argument" + exit 10 + fi + mode=preprocess + ;; + + -g) options="$options /d2" + ;; + + -o) next_is_output=yes + if [ "x$outputfile" != "x" ]; then + echo "Multiple output files!" + exit 10 + fi + ;; + + -l*) libraries="$libraries `echo $arg | sed 's,^-l,,'`" + ;; + + *.c) + srcfiles="$srcfiles $arg" + ;; + + *.S) + asmfiles="$asmfiles $arg" + ;; + + *.res) + realfilename $arg + resfiles="$resfiles $result" + ;; + + *.o) + realfilename $arg + objfiles="$objfiles $result" + ;; + + *) echo "Bad argument: $arg" + ;; + esac +fi +fi +done + +#echo "Source files: $srcfiles" +#echo "Object files: $objfiles" +#echo "Output files: $outputfile" +#echo "Libraries: $libraries" +echo "Mode: $mode" +#echo "Options: $options" + +if [ "$mode" != "link" -a "x$libraries" != "x" ]; then + echo "Libraries specified in non-link mode!" + exit 10 +fi + +prefiles= +srccount=0 +for foo in $srcfiles; do + bar=wccsh-tmppre$srccount.i + prefiles="$prefiles $bar" + echo "gcc -E -nostdinc $gnuincludes $gcc_wsysinc2 $gcc_spcdefs $gnudefines $foo -o $bar" + if gcc -E -nostdinc $gnuincludes $gcc_wsysinc2 $gcc_spcdefs $gnudefines $foo -o $bar; then + + else + exit 10 + fi + if [ ! -f $bar ]; then + exit 10 + fi + srccount=`expr $srccount + 1` +done + +tmpobjs= +if test $mode = compile -o $mode = link; then + tmpcnt=0 + for foo in $asmfiles; do + bar=wccsh-tmpobj$tmpcnt.o + tmpcnt=`expr $tmpcnt + 1` + tmpobjs="$tmpobjs $bar" + echo "gcc -c $foo -o $bar" + gcc -c $foo -o $bar + srccount=`expr $srccount + 1` + done + for foo in $prefiles; do + bar=wccsh-tmpobj$tmpcnt.o + tmpcnt=`expr $tmpcnt + 1` + tmpobjs="$tmpobjs $bar" + sed -e '/^# [0123456789]*/s,^# ,#line ,' -e '/^#line/s,"[^"]*$,",' <$foo> wccsh_tmpsrc.c + echo "wcc386 $foo $options /fo=$bar" + wcc386 wccsh_tmpsrc.c $options /fo=wcc_tmp.o >&2 + mv -f wcc_tmp.o $bar + if [ ! -f $bar ]; then + rm -f $prefiles $tmpobjs + exit 10 + fi + done +fi + +case $mode in + preprocess) + for foo in $prefiles; do + if [ "x$outputfile" = "x" ]; then + cat $foo + else + mv -f $foo $outputfile + fi + done + ;; + + compile) + if [ "$srccount" != "1" -a "x$outputfile" != "x" ]; then + echo "cannot specify -o and -c with multiple compilations" >&2 + exit 10 + fi + if [ "x$outputfile" != "x" ]; then + echo Moving "'" $tmpobjs "'" to "'" $outputfile "'" + if mv $tmpobjs $outputfile 2>/dev/null; then + fi + fi + ;; + + assemble) + ;; + + link) + if [ "x$outputfile" = "x" ]; then + outputfile=a.out + fi + FILES= + for foo in $objfiles $tmpobjs; do + if [ "x$FILES" = "x" ]; then + FILES=$foo + else + FILES="$FILES,$foo" + fi + done + for foo in $resfiles; do + FILES="$FILES op resource=$foo" + done + for foo in $libraries; do + FILES="$FILES LIB $foo" + done +# echo Files: $FILES +# echo "wlink SYSTEM nt FIL $FILES NAME $outputfile" + wlink SYSTEM nt FIL $FILES NAME $outputfile >wccsh-linkerror.log + if grep "cannot open.*No such file or" wccsh-linkerror.log; then +# rm wccsh-linkerror.log + rm $outputfile + exit 10 + fi +# rm wccsh-linkerror.log + if [ ! -f $outputfile ]; then + rm -f $prefiles $tmpobjs + exit 10 + fi + ;; +esac + +rm -f $prefiles $tmpobjs +exit 0 diff --git a/od-win32/win32.c b/od-win32/win32.c new file mode 100755 index 00000000..cd9d7950 --- /dev/null +++ b/od-win32/win32.c @@ -0,0 +1,2120 @@ +/* + * UAE - The Un*x Amiga Emulator + * + * Win32 interface + * + * Copyright 1997-1998 Mathias Ortmann + * Copyright 1997-1999 Brian King + */ + +/* Uncomment this line if you want the logs time-stamped */ +/* #define TIMESTAMP_LOGS */ + +#include "config.h" +#include "sysconfig.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +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;xGroupCount;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 +#endif +#include +typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType, + CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, + CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, + CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam); + +/* Gah, don't look at this crap, please.. */ +static void efix (DWORD *regp, void *p, void *ps, int *got) +{ + DWORD reg = *regp; + if (p >= (void*)reg && p < (void*)(reg + 32)) { + *regp = (DWORD)ps; + *got = 1; + } +} + +static LONG WINAPI ExceptionFilter( struct _EXCEPTION_POINTERS * pExceptionPointers, DWORD ec) +{ + LONG lRet = EXCEPTION_CONTINUE_SEARCH; + PEXCEPTION_RECORD er = pExceptionPointers->ExceptionRecord; + PCONTEXT ctx = pExceptionPointers->ContextRecord; + + /* Check possible access violation in 68010+/compatible mode disabled if PC points to non-existing memory */ + if (ec == EXCEPTION_ACCESS_VIOLATION && !er->ExceptionFlags && + er->NumberParameters >= 2 && !er->ExceptionInformation[0] && regs.pc_p) { + void *p = (void*)er->ExceptionInformation[1]; + if (p >= (void*)regs.pc_p && p < (void*)(regs.pc_p + 32)) { + int got = 0; + uaecptr opc = m68k_getpc(); + void *ps = get_real_address (0); + m68k_dumpstate (0, 0); + efix (&ctx->Eax, p, ps, &got); + efix (&ctx->Ebx, p, ps, &got); + efix (&ctx->Ecx, p, ps, &got); + efix (&ctx->Edx, p, ps, &got); + efix (&ctx->Esi, p, ps, &got); + efix (&ctx->Edi, p, ps, &got); +#if 0 + gui_message ("Experimental access violation trap code activated\n" + "Trying to prevent WinUAE crash.\nFix %s (68KPC=%08.8X HOSTADDR=%p)\n", + got ? "ok" : "failed", m68k_getpc(), p); +#endif + write_log ("Access violation! (68KPC=%08.8X HOSTADDR=%p)\n", m68k_getpc(), p); + if (got == 0) { + write_log ("failed to find and fix the problem (%p). crashing..\n", p); + } else { + m68k_setpc (0); + exception2 (opc, p); + lRet = EXCEPTION_CONTINUE_EXECUTION; + } + } + } +#ifndef _DEBUG + if (lRet == EXCEPTION_CONTINUE_SEARCH) { + char path[_MAX_PATH]; + char path2[_MAX_PATH]; + char msg[1024]; + char *p; + HMODULE dll = NULL; + struct tm when; + __time64_t now; + + _time64(&now); + when = *_localtime64(&now); + if (GetModuleFileName(NULL, path, _MAX_PATH)) { + char *slash = strrchr (path, '\\'); + strcpy (path2, path); + if (slash) { + strcpy (slash + 1, "DBGHELP.DLL"); + dll = LoadLibrary (path); + } + slash = strrchr (path2, '\\'); + if (slash) + p = slash + 1; + else + p = path2; + sprintf (p, "winuae_%d%02d%02d_%02d%02d%02d.dmp", + when.tm_year + 1900, when.tm_mon + 1, when.tm_mday, when.tm_hour, when.tm_min, when.tm_sec); + if (dll == NULL) + dll = LoadLibrary("DBGHELP.DLL"); + if (dll) { + MINIDUMPWRITEDUMP dump = (MINIDUMPWRITEDUMP)GetProcAddress(dll, "MiniDumpWriteDump"); + if (dump) { + HANDLE f = CreateFile(path2, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (f != INVALID_HANDLE_VALUE) { + MINIDUMP_EXCEPTION_INFORMATION exinfo; + exinfo.ThreadId = GetCurrentThreadId(); + exinfo.ExceptionPointers = pExceptionPointers; + exinfo.ClientPointers = 0; + dump (GetCurrentProcess(), GetCurrentProcessId(), f, MiniDumpNormal, &exinfo, NULL, NULL); + CloseHandle (f); + sprintf (msg, "Crash detected. MiniDump saved as:\n%s\n", path2); + MessageBox( NULL, msg, "Crash", MB_OK | MB_ICONWARNING | MB_TASKMODAL | MB_SETFOREGROUND ); + } + } + } + } + } +#endif +#if 0 + HMODULE hFaultRepDll = LoadLibrary("FaultRep.dll") ; + if ( hFaultRepDll ) + { + pfn_REPORTFAULT pfn = (pfn_REPORTFAULT)GetProcAddress( hFaultRepDll, "ReportFault"); + if ( pfn ) + { + EFaultRepRetVal rc = pfn( pExceptionPointers, 0) ; + lRet = EXCEPTION_EXECUTE_HANDLER; + } + FreeLibrary(hFaultRepDll ); + } +#endif + return lRet ; +} + +void systray (HWND hwnd, int remove) +{ + NOTIFYICONDATA nid; + + if (hwnd == NULL) + return; + if (!TaskbarRestartOk) { + TaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated")); + TaskbarRestartOk = 1; + } + memset (&nid, 0, sizeof (nid)); + nid.cbSize = sizeof (nid); + nid.hWnd = hwnd; + nid.hIcon = LoadIcon (hInst, (LPCSTR)MAKEINTRESOURCE(IDI_APPICON)); + nid.uFlags = NIF_ICON | NIF_MESSAGE; + nid.uCallbackMessage = WM_USER + 1; + Shell_NotifyIcon (remove ? NIM_DELETE : NIM_ADD, &nid); +} + +void systraymenu (HWND hwnd) +{ + POINT pt; + HMENU menu, menu2, drvmenu; + int drvs[] = { ID_ST_DF0, ID_ST_DF1, ID_ST_DF2, ID_ST_DF3, -1 }; + int i; + char text[100]; + + winuae_inactive (hwnd, FALSE); + WIN32GUI_LoadUIString( IDS_STMENUNOFLOPPY, text, sizeof (text)); + GetCursorPos (&pt); + menu = LoadMenu (hInst, MAKEINTRESOURCE (IDM_SYSTRAY)); + if (!menu) + return; + menu2 = GetSubMenu (menu, 0); + drvmenu = GetSubMenu (menu2, 1); + EnableMenuItem (menu2, ID_ST_HELP, pHtmlHelp ? MF_ENABLED : MF_GRAYED); + i = 0; + while (drvs[i] >= 0) { + char s[MAX_PATH]; + if (currprefs.df[i][0]) + sprintf (s, "DF%d: [%s]", i, currprefs.df[i]); + else + sprintf (s, "DF%d: [%s]", i, text); + ModifyMenu (drvmenu, drvs[i], MF_BYCOMMAND | MF_STRING, drvs[i], s); + EnableMenuItem (menu2, drvs[i], currprefs.dfxtype[i] < 0 ? MF_GRAYED : MF_ENABLED); + i++; + } + if (!isfullscreen ()) + SetForegroundWindow (hwnd); + TrackPopupMenu (menu2, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, + pt.x, pt.y, 0, hwnd, NULL); + PostMessage (hwnd, WM_NULL, 0, 0); + DestroyMenu (menu); + winuae_active (hwnd, FALSE); +} + +int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, + int nCmdShow) +{ + __try { + WinMain2 (hInstance, hPrevInstance, lpCmdLine, nCmdShow); + } __except(ExceptionFilter(GetExceptionInformation(), GetExceptionCode())) + { + } + return FALSE; +} + + diff --git a/od-win32/win32.h b/od-win32/win32.h new file mode 100755 index 00000000..a35201b6 --- /dev/null +++ b/od-win32/win32.h @@ -0,0 +1,95 @@ +/* + * UAE - The Un*x Amiga Emulator + * + * Win32-specific header file + * + * (c) 1997-1999 Mathias Ortmann + * (c) 1998-2001 Brian King + */ + +#ifndef __WIN32_H__ +#define __WIN32_H__ + +#define IHF_WINDOWHIDDEN 6 +#define NORMAL_WINDOW_STYLE (WS_VISIBLE | WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU ) + +extern HMODULE hUIDLL; +extern HWND hAmigaWnd, hMainWnd; +extern RECT amigawin_rect; +extern int in_sizemove; +extern int manual_painting_needed; +extern int manual_palette_refresh_needed; +extern int mouseactive, focus; +#define WINUAEBETA 1 +#define WINUAEBETASTR " Beta 4" + +extern void my_kbd_handler (int, int, int); +extern void clearallkeys(void); +extern int getcapslock (void); + +void releasecapture (void); +int WIN32_RegisterClasses( void ); +int WIN32_InitHtmlHelp( void ); +int WIN32_InitLibraries( void ); +int WIN32_CleanupLibraries( void ); +void WIN32_MouseDefaults( int, int ); +void WIN32_HandleRegistryStuff( void ); +extern void setup_brkhandler (void); +extern void remove_brkhandler (void); +extern void disablecapture (void); +extern void fullscreentoggle (void); + +extern void setmouseactive (int active); +extern void minimizewindow (void); +extern uae_u32 OSDEP_minimize_uae(void); + +void finishjob (void); +void updatedisplayarea (void); +void init_colors (void); + +extern int pause_emulation; +extern int sound_available; +extern int framecnt; +extern char prtname[]; +extern char VersionStr[256]; +extern int os_winnt, os_winnt_admin; +extern int paraport_mask; +extern int gui_active; + +/* For StatusBar when running in a Window */ +#define LED_NUM_PARTS 10 +#define LED_POWER_WIDTH 42 +#define LED_HD_WIDTH 24 +#define LED_CD_WIDTH 24 +#define LED_DRIVE_WIDTH 24 +#define LED_FPS_WIDTH 64 +#define LED_IDLE_WIDTH 64 + +extern HKEY hWinUAEKey; +extern int screen_is_picasso; +extern HINSTANCE hInst; +extern int win_x_diff, win_y_diff; + +extern void sleep_millis (int ms); +extern void sleep_millis_busy (int ms); +extern void screenshot(int mode); +extern void wait_keyrelease (void); +extern void keyboard_settrans (void); +extern void setpriority (int pri); + +extern void handle_rawinput (DWORD lParam); + +#define DEFAULT_PRIORITY 2 +struct threadpriorities { + char *name; + int value; +}; +extern struct threadpriorities priorities[]; +extern int dinput_wmkey (uae_u32 key); +extern int dinput_winmouse (void); + +void systray (HWND hwnd, int remove); +void systraymenu (HWND hwnd); +void exit_gui (int); + +#endif \ No newline at end of file diff --git a/od-win32/win32_filesys.c b/od-win32/win32_filesys.c new file mode 100755 index 00000000..765e81e8 --- /dev/null +++ b/od-win32/win32_filesys.c @@ -0,0 +1,135 @@ + + +/* Determines if this drive-letter currently has a disk inserted */ +static int CheckRM( char *DriveName ) +{ + char filename[ MAX_PATH ]; + DWORD dwHold; + BOOL result = FALSE; + + sprintf( filename, "%s.", DriveName ); + dwHold = GetFileAttributes( filename ); + if( dwHold != 0xFFFFFFFF ) + result = TRUE; + return result; +} + +/* This function makes sure the volume-name being requested is not already in use, or any of the following + illegal values: */ +static char *illegal_volumenames[] = { "SYS", "DEVS", "LIBS", "FONTS", "C", "L", "S" }; + +static int valid_volumename( struct uaedev_mount_info *mountinfo, char *volumename, int fullcheck ) +{ + int i, result = 1, illegal_count = sizeof( illegal_volumenames ) / sizeof( char *); + for( i = 0; i < illegal_count; i++ ) + { + if( strcmp( volumename, illegal_volumenames[i] ) == 0 ) + { + result = 0; + break; + } + } + /* if result is still good, we've passed the illegal names check, and must check for duplicates now */ + if( result && fullcheck) + { + for( i = 0; i < mountinfo->num_units; i++ ) + { + if( mountinfo->ui[i].volname && ( strcmp( mountinfo->ui[i].volname, volumename ) == 0 ) ) + { + result = 0; + break; + } + } + } + return result; +} + +/* Returns 1 if an actual volume-name was found, 2 if no volume-name (so uses some defaults) */ +static int get_volume_name( struct uaedev_mount_info *mtinf, char *volumepath, char *volumename, int size, int inserted, int drivetype, int fullcheck ) +{ + int result = 2; + static int cd_number = 0; + + if( inserted ) + { + if( GetVolumeInformation( volumepath, volumename, size, NULL, NULL, NULL, NULL, 0 ) && volumename[0] && valid_volumename( mtinf, volumename, fullcheck ) ) + { + // +++Bernd Roesch + if(!strcmp(volumename,"AmigaOS35"))strcpy(volumename,"AmigaOS3.5"); + if(!strcmp(volumename,"AmigaOS39"))strcpy(volumename,"AmigaOS3.9"); + // ---Bernd Roesch + result = 1; + } + } + + if( result == 2 ) + { + switch( drivetype ) + { + case DRIVE_FIXED: + sprintf( volumename, "WinDH_%c", volumepath[0] ); + break; + case DRIVE_CDROM: + sprintf( volumename, "WinCD_%c", volumepath[0] ); + break; + case DRIVE_REMOVABLE: + sprintf( volumename, "WinRMV_%c", volumepath[0] ); + break; + case DRIVE_REMOTE: + sprintf( volumename, "WinNET_%c", volumepath[0] ); + break; + case DRIVE_RAMDISK: + sprintf( volumename, "WinRAM_%c", volumepath[0] ); + break; + case DRIVE_UNKNOWN: + case DRIVE_NO_ROOT_DIR: + default: + result = 0; + break; + } + } + + return result; +} + +/* New function to actually handle add_filesys_unit() calls at start-up, as well as mount-all drives flag */ +void filesys_init( void ) +{ + int drive, drivetype; + UINT errormode = SetErrorMode( SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX ); + char volumename[MAX_PATH]=""; + char volumepath[6]; + DWORD dwDriveMask; + char *result = NULL; + + if( currprefs.win32_automount_drives ) + { + dwDriveMask = GetLogicalDrives(); + dwDriveMask >>= 2; // Skip A and B drives... + + for( drive = 'C'; drive <= 'Z'; ++drive ) + { + sprintf( volumepath, "%c:\\", drive ); + /* Is this drive-letter valid (it used to check for media in drive) */ + if( ( dwDriveMask & 1 ) /* && CheckRM( volumepath ) */ ) + { + BOOL inserted = CheckRM( volumepath ); /* Is there a disk inserted? */ + drivetype = GetDriveType( volumepath ); + if (drivetype != DRIVE_CDROM) { + + get_volume_name( currprefs.mountinfo, volumepath, volumename, MAX_PATH, inserted, drivetype, 1 ); + if( drivetype == DRIVE_REMOTE ) + strcat( volumepath, "." ); + else + strcat( volumepath, ".." ); + + result = add_filesys_unit (currprefs.mountinfo, 0, volumename, volumepath, 0, 0, 0, 0, 0, 0, 0); + if( result ) + write_log( result ); + } + } /* if drivemask */ + dwDriveMask >>= 1; + } + } + SetErrorMode( errormode ); +} diff --git a/od-win32/win32_nogui.c b/od-win32/win32_nogui.c new file mode 100755 index 00000000..219b655c --- /dev/null +++ b/od-win32/win32_nogui.c @@ -0,0 +1,499 @@ + +#include "config.h" +#include "sysconfig.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +static volatile int dummythread_die; +static void dummythread (void *dummy) +{ + SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_LOWEST); + while (!dummythread_die); +} + +static uae_u64 win32_read_processor_time (void) +{ + uae_u32 foo, bar; + __asm + { + rdtsc + mov foo, eax + mov bar, edx + } + return ((uae_u64)bar << 32) | foo; +} + +static int figure_processor_speed (void) +{ + extern volatile frame_time_t vsynctime; + extern unsigned long syncbase; + uae_u64 clockrate, clockrateidle, qpfrate, ratea1, ratea2; + uae_u32 rate1, rate2; + double limit, clkdiv = 1, clockrate1000 = 0; + int i, ratecnt = 6; + LARGE_INTEGER freq; + int qpc_avail = 0; + int mmx = 0; + + rpt_available = 1; + __try + { + __asm + { + rdtsc + } + } __except( GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION ) { + rpt_available = 0; + write_log ("CLOCKFREQ: RDTSC not supported\n"); + } + __try + { + __asm + { + mov eax,1 + cpuid + and edx,0x800000 + mov mmx,edx + } + if (mmx) + cpu_mmx = 1; + } __except( GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION ) { + } + + if (QueryPerformanceFrequency(&freq)) { + qpc_avail = 1; + write_log("CLOCKFREQ: QPF %.2fMHz\n", freq.QuadPart / 1000000.0); + qpfrate = freq.QuadPart; + /* we don't want 32-bit overflow */ + if (qpfrate > 100000000) { + qpfrate >>= 6; + qpc_avail = -1; + } + } else { + write_log("CLOCKREQ: QPF not supported\n"); + } + + if (!rpt_available && !qpc_avail) + return 0; + + init_mmtimer(); + SetThreadPriority ( GetCurrentThread(), THREAD_PRIORITY_HIGHEST); + sleep_millis (100); + dummythread_die = -1; + + if (qpc_avail || rpt_available) { + + if (rpt_available) { + clockrateidle = win32_read_processor_time(); + sleep_millis (500); + clockrateidle = (win32_read_processor_time() - clockrateidle) * 2; + dummythread_die = 0; + _beginthread(&dummythread, 0, 0); + sleep_millis (100); + clockrate = win32_read_processor_time(); + sleep_millis (500); + clockrate = (win32_read_processor_time() - clockrate) * 2; + write_log("CLOCKFREQ: RDTSC %.2fMHz (busy) / %.2fMHz (idle)\n", + clockrate / 1000000.0, clockrateidle / 1000000.0); + clkdiv = (double)clockrate / (double)clockrateidle; + clockrate >>= 6; + clockrate1000 = clockrate / 1000.0; + } + if (clkdiv <= 0.95 || clkdiv >= 1.05 || !rpt_available) { + if (rpt_available) + write_log ("CLOCKFREQ: CPU throttling detected, using QPF instead of RDTSC\n"); + useqpc = qpc_avail; + rpt_available = 1; + clkdiv = 1.0; + clockrate = qpfrate; + clockrate1000 = clockrate / 1000.0; + if (dummythread_die < 0) { + dummythread_die = 0; + _beginthread(&dummythread, 0, 0); + } + if (!qpc_avail) + write_log ("No working timing reference detected\n"); + } + timermode = 0; + if (mm_timerres) { + sleep_millis (50); + timebegin (); + sleep_millis (50); + ratea1 = 0; + write_log ("Testing MM-timer resolution:\n"); + for (i = 0; i < ratecnt; i++) { + rate1 = read_processor_time(); + sleep_millis (1); + rate1 = read_processor_time() - rate1; + write_log ("%1.2fms ", rate1 / clockrate1000); + ratea1 += rate1; + } + write_log("\n"); + timeend (); + sleep_millis (50); + } + timermode = 1; + ratea2 = 0; + write_log ("Testing Sleep() resolution:\n"); + for (i = 0; i < ratecnt; i++) { + rate2 = read_processor_time(); + sleep_millis (1); + rate2 = read_processor_time() - rate2; + write_log ("%1.2fms ", rate2 / clockrate1000); + ratea2 += rate2; + } + write_log("\n"); + } + + SetThreadPriority ( GetCurrentThread(), THREAD_PRIORITY_NORMAL); + dummythread_die = 1; + + if (clkdiv >= 0.90 && clkdiv <= 1.10 && rpt_available) { + limit = 2.5; + if ((ratea2 / ratecnt) < limit * clockrate1000) { /* regular Sleep() is ok */ + timermode = 1; + write_log ("Using Sleep() (resolution < %.1fms)\n", limit); + } else if (mm_timerres && (ratea1 / ratecnt) < limit * clockrate1000) { /* MM-timer is ok */ + timermode = 0; + timebegin (); + write_log ("Using MultiMedia timers (resolution < %.1fms)\n", limit); + } else { + timermode = -1; /* both timers are bad, fall back to busy-wait */ + write_log ("falling back to busy-loop waiting (timer resolution > %.1fms)\n", limit); + } + } else { + timermode = -1; + write_log ("forcing busy-loop wait mode\n"); + } + syncbase = (unsigned long)clockrate; + return 1; +} + +int needmousehack (void) +{ + return 0; +} + +void gui_message (const char *format,...) +{ +} + +void gui_led (int led, int on) +{ +} + +void gui_fps (int fps) +{ +} + +void gui_hd_led (int led) +{ +} + +void gui_cd_led (int led) +{ +} + +void gui_unlock (void) +{ +} + +void gui_lock (void) +{ +} + +int gui_update (void) +{ + return 0; +} + +char *DXError (HRESULT ddrval) +{ + return ""; +} + +void setmouseactive (int active) +{ +} + +void minimizewindow (void) +{ +} + +int isfullscreen (void) +{ + return 0; +} + +void fullscreentoggle (void) +{ +} + +void disablecapture (void) +{ +} + +void WIN32GUI_DisplayGUI (int shortcut) +{ +} + +void flush_block (int a, int b) +{ +} + +void flush_screen (int a, int b) +{ +} + +void flush_line (int lineno) +{ +} + +void flush_clear_screen (void) +{ +} + +int lockscr (void) +{ + return 1; +} + +void unlockscr (void) +{ +} + +void machdep_init (void) +{ +} + +void handle_events (void) +{ +} + +int debuggable (void) +{ + return 0; +} + +int graphics_init (void) +{ + return 1; +} + +int graphics_setup (void) +{ + return 1; +} + +void graphics_leave (void) +{ +} + +extern FILE *debugfile; +char VersionStr[256]; +static OSVERSIONINFO osVersion; +void logging_init( void ) +{ + static int started; + static int first; + char debugfilename[MAX_PATH]; + + if (first > 1) { + write_log ("** RESTART **\n"); + return; + } + if (first == 1) { + if (debugfile) + fclose (debugfile); + debugfile = 0; + } + if( currprefs.win32_logfile ) { + sprintf( debugfilename, "%s\\winuaelog.txt", start_path ); + if( !debugfile ) + debugfile = fopen( debugfilename, "wt" ); + } else if (!first) { + sprintf( debugfilename, "%s\\winuaebootlog.txt", start_path ); + if( !debugfile ) + debugfile = fopen( debugfilename, "wt" ); + } + first++; + write_log ( "%s", VersionStr ); + write_log (" (OS: %s %d.%d%s)", os_winnt ? "NT" : "W9X/ME", osVersion.dwMajorVersion, osVersion.dwMinorVersion, os_winnt_admin ? " Administrator privileges" : ""); + write_log ("\n(c) 1995-2001 Bernd Schmidt - Core UAE concept and implementation." + "\n(c) 1998-2003 Toni Wilen - Win32 port, core code updates." + "\n(c) 1996-2001 Brian King - Win32 port, Picasso96 RTG, and GUI." + "\n(c) 1996-1999 Mathias Ortmann - Win32 port and bsdsocket support." + "\n(c) 2000-2001 Bernd Meyer - JIT engine." + "\n(c) 2000-2001 Bernd Roesch - MIDI input, many fixes." + "\nPress F12 to show the Settings Dialog (GUI), Alt-F4 to quit." + "\nEnd+F1 changes floppy 0, End+F2 changes floppy 1, etc." + "\n"); +} + +void target_save_options (FILE *f, struct uae_prefs *p) +{ +} + +int target_parse_option (struct uae_prefs *p, char *option, char *value) +{ + return 0; +} + +int gui_init (void) +{ + return 1; +} + +void gui_exit (void) +{ +} + +void gui_filename (int num, const char *name) +{ +} + +void setup_brkhandler (void) +{ +} + +int check_prefs_changed_gfx (void) +{ + return 0; +} + +void screenshot (int mode) +{ +} + +int _stdcall WinMain (HINSTANCE hInstance, HINSTANCE prev, LPSTR cmd, int show) +{ + char **argv, *posn; + int argc; + + hInst = hInstance; + argc = __argc; argv = __argv; + start_path = xmalloc( MAX_PATH ); + GetModuleFileName( NULL, start_path, MAX_PATH ); + if( ( posn = strrchr( start_path, '\\' ) ) ) + *posn = 0; + real_main (argc, argv); + if (mm_timerres && timermode == 0) + timeend (); + free (start_path); + return 0; +} + + + + + + + + + + + + + + + + + + diff --git a/od-win32/win32_scale2x.c b/od-win32/win32_scale2x.c new file mode 100755 index 00000000..1557b120 --- /dev/null +++ b/od-win32/win32_scale2x.c @@ -0,0 +1,198 @@ + +#include "sysconfig.h" +#include "sysdeps.h" +#include "config.h" +#include "options.h" +#include "xwin.h" +#include "dxwrap.h" +#include "win32.h" +#include "win32gfx.h" +#include "gfxfilter.h" + +struct uae_filter uaefilters[] = +{ + { UAE_FILTER_NULL, "Null filter", "null", + { 0, UAE_FILTER_MODE_16_16 | UAE_FILTER_MODE_32_32, 0, 0, 0 } }, + + { UAE_FILTER_DIRECT3D, "Direct3D", "direct3d", 1, 0, 0, 0, 0 }, + + { UAE_FILTER_OPENGL, "OpenGL", "opengl", 1, 0, 0, 0, 0 }, + + { UAE_FILTER_SCALE2X, "Scale2X", "scale2x", 0, 0, UAE_FILTER_MODE_16_16 | UAE_FILTER_MODE_32_32, 0, 0 }, + +// { UAE_FILTER_HQ, "hq", "hq", 0, 0, UAE_FILTER_MODE_16_32, UAE_FILTER_MODE_16_32, UAE_FILTER_MODE_16_32 }, + + { UAE_FILTER_SUPEREAGLE, "SuperEagle", "supereagle", 0, 0, UAE_FILTER_MODE_16_16, 0, 0 }, + + { UAE_FILTER_SUPER2XSAI, "Super2xSaI", "super2xsai", 0, 0, UAE_FILTER_MODE_16_16, 0, 0 }, + + { UAE_FILTER_2XSAI, "2xSaI", "2xsai", 0, 0, UAE_FILTER_MODE_16_16, 0, 0 }, + + + { 0 } +}; + + +static int dst_width, dst_height, amiga_width, amiga_height, amiga_depth, dst_depth, scale; +uae_u8 *bufmem_ptr; +int bufmem_width, bufmem_height; + +void S2X_configure (int rb, int gb, int bb, int rs, int gs, int bs) +{ + Init_2xSaI (rb, gb, bb, rs, gs, bs); + hq_init (rb, gb, bb, rs, gs, bs); + bufmem_ptr = 0; +} + +void S2X_init (int dw, int dh, int aw, int ah, int mult, int ad, int dd) +{ + int flags; + + flags = usedfilter->x[mult]; + if (mult) { + if ((ad == 16 && !(flags & UAE_FILTER_MODE_16)) || (ad == 32 && !(flags & UAE_FILTER_MODE_32))) { + usedfilter = &uaefilters[0]; + mult = 1; + changed_prefs.gfx_filter = usedfilter->type; + } + } + dst_width = dw; + dst_height = dh; + dst_depth = dd; + amiga_width = aw; + amiga_height = ah; + amiga_depth = ad; + scale = mult; +} + +void S2X_render (void) +{ + int aw = amiga_width, ah = amiga_height, v, pitch; + uae_u8 *dptr, *sptr; + int ok = 0; + + sptr = gfxvidinfo.bufmem; + + v = currprefs.gfx_filter_horiz_offset; + v += (dst_width / scale - amiga_width) / 8; + sptr += -v * (amiga_depth / 8) * 4; + aw -= -v * 4; + + v = currprefs.gfx_filter_vert_offset; + v += (dst_height / scale - amiga_height) / 8; + sptr += -v * gfxvidinfo.rowbytes * 4; + ah -= -v * 4; + + if (aw * scale > dst_width) + aw = (dst_width / scale) & ~3; + if (ah * scale > dst_height) + ah = (dst_height / scale) & ~3; + + if (ah < 16) + return; + if (aw < 16) + return; + + bufmem_ptr = sptr; + bufmem_width = aw; + bufmem_height = ah; + + if (!DirectDraw_SurfaceLock (lockable_surface)) + return; + + dptr = DirectDraw_GetSurfacePointer (); + pitch = DirectDraw_GetSurfacePitch(); + + if (usedfilter->type == UAE_FILTER_SCALE2X ) { /* 16+32/2X */ + + if (amiga_depth == 16 && dst_depth == 16) { + AdMame2x (sptr, gfxvidinfo.rowbytes, dptr, pitch, aw, ah); + ok = 1; + } else if (amiga_depth == 32 && dst_depth == 32) { + AdMame2x32 (sptr, gfxvidinfo.rowbytes, dptr, pitch, aw, ah); + ok = 1; + } + + } else if (usedfilter->type == UAE_FILTER_HQ) { /* 32/2X+3X+4X */ + + int hqsrcpitch = gfxvidinfo.rowbytes - aw * amiga_depth / 8; + int hqdstpitch = pitch - aw * scale * dst_depth / 8; + int hqdstpitch2 = pitch * scale - aw * scale * dst_depth / 8; + if (scale == 2) { + if (amiga_depth == 16 && dst_depth == 32) { + hq2x_32 (sptr, dptr, aw, ah, hqdstpitch, hqsrcpitch, hqdstpitch2); + ok = 1; + } + } else if (scale == 3) { + if (amiga_depth == 16 && dst_depth == 16) { + hq3x_16 (sptr, dptr, aw, ah, hqdstpitch, hqsrcpitch, hqdstpitch2); + ok = 1; + } else if (amiga_depth == 16 && dst_depth == 32) { + hq3x_32 (sptr, dptr, aw, ah, hqdstpitch, hqsrcpitch, hqdstpitch2); + ok = 1; + } + } else if (scale == 4) { + if (amiga_depth == 16 && dst_depth == 32) { + hq4x_32 (sptr, dptr, aw, ah, hqdstpitch, hqsrcpitch, hqdstpitch2); + ok = 1; + } + } + + } else if (usedfilter->type == UAE_FILTER_SUPEREAGLE) { /* 16/2X */ + + if (scale == 2 && amiga_depth == 16 && dst_depth == 16) { + SuperEagle (sptr, gfxvidinfo.rowbytes, dptr, pitch, aw, ah); + ok = 1; + } + + } else if (usedfilter->type == UAE_FILTER_SUPER2XSAI) { /* 16/2X */ + + if (scale == 2 && amiga_depth == 16 && dst_depth == 16) { + Super2xSaI (sptr, gfxvidinfo.rowbytes, dptr, pitch, aw, ah); + ok = 1; + } + + } else if (usedfilter->type == UAE_FILTER_2XSAI) { /* 16/2X */ + + if (scale == 2 && amiga_depth == 16 && dst_depth == 16) { + _2xSaI (sptr, gfxvidinfo.rowbytes, dptr, pitch, aw, ah); + ok = 1; + } + + } else { /* null */ + + if (amiga_depth == dst_depth) { + int y; + for (y = 0; y < dst_height; y++) { + memcpy (dptr, sptr, dst_width * dst_depth / 8); + sptr += gfxvidinfo.rowbytes; + dptr += pitch; + } + } + ok = 1; + + } + + if (ok == 0) { + usedfilter = &uaefilters[0]; + changed_prefs.gfx_filter = usedfilter->type; + } + + DirectDraw_SurfaceUnlock (); + +} + +void S2X_refresh (void) +{ + int y, pitch; + uae_u8 *dptr; + + if (!DirectDraw_SurfaceLock (lockable_surface)) + return; + dptr = DirectDraw_GetSurfacePointer (); + pitch = DirectDraw_GetSurfacePitch(); + for (y = 0; y < dst_height; y++) + memset (dptr + y * pitch, 0, dst_width * dst_depth / 8); + DirectDraw_SurfaceUnlock (); + S2X_render (); +} diff --git a/od-win32/win32gfx.c b/od-win32/win32gfx.c new file mode 100755 index 00000000..cc1a8b23 --- /dev/null +++ b/od-win32/win32gfx.c @@ -0,0 +1,2171 @@ +/* + * UAE - The Un*x Amiga Emulator + * + * Win32 Drawing and DirectX interface + * + * Copyright 1997-1998 Mathias Ortmann + * Copyright 1997-2000 Brian King + */ + +#include "config.h" +#include "sysconfig.h" + +#include +#include + +#include +#include +#include +#include + +#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 +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 diff --git a/od-win32/win32gfx.h b/od-win32/win32gfx.h new file mode 100755 index 00000000..2a9bb09b --- /dev/null +++ b/od-win32/win32gfx.h @@ -0,0 +1,39 @@ +#ifndef __WIN32GFX_H__ +#define __WIN32GFX_H__ + +#include + +BOOL CALLBACK displaysCallback (GUID *guid, LPSTR desc, LPSTR name, LPVOID ctx, HMONITOR hm); +extern void sortdisplays (void); + +int WIN32GFX_IsPicassoScreen( void ); +int WIN32GFX_GetWidth( void ); +int WIN32GFX_GetHeight( void ); +int WIN32GFX_GetDepth (int real); +void WIN32GFX_DisplayChangeRequested( void ); +void WIN32GFX_ToggleFullScreen( void ); +void WIN32GFX_DisablePicasso( void ); +void WIN32GFX_EnablePicasso( void ); +void WIN32GFX_PaletteChange( void ); +int WIN32GFX_ClearPalette( void ); +int WIN32GFX_SetPalette( void ); +void WIN32GFX_WindowMove ( void ); + +int DX_Blit( int srcx, int srcy, int dstx, int dsty, int width, int height, BLIT_OPCODE opcode ); + +#ifndef _WIN32_WCE +RGBFTYPE WIN32GFX_FigurePixelFormats( RGBFTYPE colortype ); +int WIN32GFX_AdjustScreenmode( uae_u32 *pwidth, uae_u32 *pheight, uae_u32 *ppixbits ); +#endif + +extern HWND hStatusWnd; +extern HINSTANCE hDDraw; +extern char *start_path; +extern uae_u32 default_freq; + +extern HDC gethdc (void); +extern void releasehdc (HDC hdc); +extern void close_windows (void); +extern void updatewinfsmode (struct uae_prefs *p); + +#endif diff --git a/od-win32/win32gui.c b/od-win32/win32gui.c new file mode 100755 index 00000000..c7f5942d --- /dev/null +++ b/od-win32/win32gui.c @@ -0,0 +1,6264 @@ +/*========================================================================== + * + * Copyright (C) 1996 Brian King + * + * File: win32gui.c + * Content: Win32-specific gui features for UAE port. + * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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) +{ +} diff --git a/od-win32/win32gui.h b/od-win32/win32gui.h new file mode 100755 index 00000000..5fd5a54e --- /dev/null +++ b/od-win32/win32gui.h @@ -0,0 +1,48 @@ +#ifndef WIN32GUI_H +#define WIN32GUI_H + +#define MAXJOYSTICKS 2 + +#define MAX_BUFFER_SIZE 256 +#define NUM_DRIVES 16 + +typedef struct +{ + char path[256]; + char name[256]; + uae_u16 rw; + uae_u8 sectors; + uae_u8 surfaces; + uae_u8 reserved; + uae_u8 hardfile; + uae_u16 spare; +} drive_specs; + +extern drive_specs drives[NUM_DRIVES]; + +#define CFG_DESCRIPTION_LENGTH 128 +#define CFG_SER_LENGTH 256 +#define CFG_ROM_LENGTH 256 +#define CFG_PAR_LENGTH 256 +#define CFG_KEY_LENGTH 256 + +#define CONFIG_VERSION_MAJOR 1 +#define CONFIG_VERSION_MINOR 2 + +#define DIRECT_SOUND_ENABLED 0x01 +#define AHI_ENABLED 0x02 + +#define CONFIG_SAVE 0 +#define CONFIG_LOAD 1 +#define CONFIG_SAVE_FULL 2 +#define CONFIG_LOAD_FULL 3 +#define CONFIG_DELETE 4 + +void WIN32GUI_LoadUIString( DWORD id, char *string, DWORD dwStringLen ); +extern int GetSettings (int all_options, HWND); +extern int DiskSelection( HWND hDlg, WPARAM wParam, int flag, struct uae_prefs *prefs, char *); +void InitializeListView( HWND hDlg ); +extern void pre_gui_message (const char*,...); +int dragdrop (HWND hDlg, HDROP hd, struct uae_prefs *prefs, int currentpage); + +#endif diff --git a/od-win32/winuae.nsi b/od-win32/winuae.nsi new file mode 100755 index 00000000..89c59d28 --- /dev/null +++ b/od-win32/winuae.nsi @@ -0,0 +1,42 @@ +Name "WinUAE" +OutFile "InstallWinUAE.exe" +Caption "WinUAE installer" +ShowInstDetails show + +; Some default compiler settings (uncomment and change at will): +SetCompress auto ; (can be off or force) +SetDatablockOptimize on ; (can be off) +CRCCheck on ; (can be off) +; AutoCloseWindow false ; (can be true for the window go away automatically at end) +; ShowInstDetails hide ; (can be show to have them shown, or nevershow to disable) +; SetDateSave off ; (can be on to have files restored to their orginal date) + +InstallDir "$PROGRAMFILES\WinUAE" +InstallDirRegKey HKEY_CURRENT_USER "SOFTWARE\Arabuusimiehet\WinUAE" "InstallDir" +DirShow show ; (make this hide to not let the user change it) +DirText "Select the directory to install WinUAE in:" +Icon "d:\projects\winuae\src\od-win32\resources\winuae.ico" +WindowIcon on +AllowRootDirInstall true +AutoCloseWindow true + +Section "" ; (default section) +SetOutPath "$INSTDIR" +File "d:\projects\winuae\distribution\*" +SetOutPath "$INSTDIR\Amiga Programs" +File "d:\projects\winuae\distribution\Amiga Programs\*" +SetOutPath "$INSTDIR\Docs" +File "d:\projects\winuae\distribution\Docs\*" +SetOutPath "$INSTDIR\Docs\Windows" +File "d:\projects\winuae\distribution\Docs\Windows\*" +CreateDirectory "$INSTDIR\Configurations" +WriteRegStr HKEY_CURRENT_USER "SOFTWARE\Arabuusimiehet\WinUAE" "InstallDir" "$INSTDIR" + +ExecShell open "$INSTDIR\Docs\Readme.txt" + +; add files / whatever that need to be installed here. + +SectionEnd ; end of default section + +; eof + diff --git a/od-win32/winuae_msvc/winuae_msvc.vcproj b/od-win32/winuae_msvc/winuae_msvc.vcproj new file mode 100755 index 00000000..61ae3e9d --- /dev/null +++ b/od-win32/winuae_msvc/winuae_msvc.vcproj @@ -0,0 +1,584 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/od-win32/wrc.sh b/od-win32/wrc.sh new file mode 100755 index 00000000..ec632686 --- /dev/null +++ b/od-win32/wrc.sh @@ -0,0 +1,75 @@ +#! /bin/sh +# + +realdirname () { + tmp_save_dir=`pwd` + cd $@ + result=`pwd -P` + cd $tmp_save_dir + result=`echo $result |sed 's,/,\\\\,g'` +} + +realfilename () { + case $@ in + */*) + tmp_save_dir=`pwd` + cd `echo $@ | sed 's,/[^/]*$,,'` + result=`pwd -P`/`basename $@` + cd $tmp_save_dir + ;; + *) + result=$@ + ;; + esac + result=`echo $result |sed 's,/,\\\\,g'` +} + +next_is_include=no +resfiles= +srcfiles= +exefile= + +for arg in $@; do + +if test $next_is_include = yes; then + realdirname $arg + includes="$includes /i=$result" + next_is_include=no +else + case $arg in + -I) next_is_include=yes + ;; + + -I*) + foo=`echo $arg | sed 's,^-I,,'` + realdirname $foo + includes="$includes /i=$result" + ;; + + *.rc) + realfilename $arg + srcfiles="$srcfiles $result" + ;; + + *.res) + realfilename $arg + resfiles="$resfiles $result" + ;; + + *.exe) + realfilename $arg + exefile=$result + ;; + + *) echo "Bad argument: $arg" + ;; + esac +fi +done + +echo "wrc /bt=nt /dWIN32 /d_WIN32 /d__NT__ /r $includes $srcfiles" +if test -z "$exefile"; then + wrc /bt=nt /dWIN32 /d_WIN32 /d__NT__ /r $includes $srcfiles +else + wrc $resfiles $exefile +fi diff --git a/od-win32/writelog.c b/od-win32/writelog.c new file mode 100755 index 00000000..91c7dfd2 --- /dev/null +++ b/od-win32/writelog.c @@ -0,0 +1,118 @@ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include + +#define SHOW_CONSOLE 0 + +static int consoleopen = 0; +static HANDLE stdinput,stdoutput; + +FILE *debugfile = NULL; +int console_logging; + +#define WRITE_LOG_BUF_SIZE 4096 + +/* console functions for debugger */ + +static void openconsole(void) +{ + if(consoleopen) return; + AllocConsole(); + stdinput=GetStdHandle(STD_INPUT_HANDLE); + stdoutput=GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleMode(stdinput,ENABLE_PROCESSED_INPUT|ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT|ENABLE_PROCESSED_OUTPUT); + consoleopen = 1; +} + +void console_out (const char *format,...) +{ + va_list parms; + char buffer[WRITE_LOG_BUF_SIZE]; + DWORD temp; + + va_start (parms, format); + _vsnprintf( buffer, WRITE_LOG_BUF_SIZE-1, format, parms ); + va_end (parms); + openconsole(); + WriteConsole(stdoutput,buffer,strlen(buffer),&temp,0); +} + +int console_get (char *out, int maxlen) +{ + DWORD len,totallen; + + totallen=0; + while(maxlen>0) + { + ReadConsole(stdinput,out,1,&len,0); + if(*out == 13) break; + out++; + maxlen--; + totallen++; + } + *out=0; + return totallen; +} + +void console_flush (void) +{ +} + +void write_dlog (const char *format, ...) +{ + int count; + DWORD numwritten; + char buffer[WRITE_LOG_BUF_SIZE]; + + va_list parms; + va_start (parms, format); + count = _vsnprintf( buffer, WRITE_LOG_BUF_SIZE-1, format, parms ); + if (SHOW_CONSOLE || console_logging) { + openconsole(); + WriteConsole(stdoutput,buffer,strlen(buffer),&numwritten,0); + } + if( debugfile ) { + fprintf( debugfile, buffer ); + fflush (debugfile); + } + va_end (parms); +} +void write_log (const char *format, ...) +{ + int count; + DWORD numwritten; + char buffer[WRITE_LOG_BUF_SIZE]; + + va_list parms; + va_start (parms, format); + count = _vsnprintf( buffer, WRITE_LOG_BUF_SIZE-1, format, parms ); + if (SHOW_CONSOLE || console_logging) { + openconsole(); + WriteConsole(stdoutput,buffer,strlen(buffer),&numwritten,0); + } + if( debugfile ) { + fprintf( debugfile, buffer ); + fflush (debugfile); + } + va_end (parms); +} + +void f_out (void *f, const char *format, ...) +{ + int count; + DWORD numwritten; + char buffer[ WRITE_LOG_BUF_SIZE ]; + + va_list parms; + va_start (parms, format); + count = _vsnprintf( buffer, WRITE_LOG_BUF_SIZE-1, format, parms ); + if (f == 0) { + write_log (buffer); + } else { + openconsole(); + WriteConsole(stdoutput,buffer,strlen(buffer),&numwritten,0); + va_end (parms); + } +} diff --git a/picasso96.c b/picasso96.c new file mode 100755 index 00000000..e873cf2f --- /dev/null +++ b/picasso96.c @@ -0,0 +1,2899 @@ +/* + * UAE - The U*nix Amiga Emulator + * + * Picasso96 Support Module + * + * Copyright 1997 Brian King + * + * Theory of operation: + * On the Amiga side, a Picasso card consists mainly of a memory area that + * contains the frame buffer. On the UAE side, we allocate a block of memory + * that will hold the frame buffer. This block is in normal memory, it is + * never directly on the graphics card. All graphics operations, which are + * mainly reads and writes into this block and a few basic operations like + * filling a rectangle, operate on this block of memory. + * Since the memory is not on the graphics card, some work must be done to + * synchronize the display with the data in the Picasso frame buffer. There + * are various ways to do this. One possibility is to allocate a second + * buffer of the same size, and perform all write operations twice. Since + * we never read from the second buffer, it can actually be placed in video + * memory. The X11 driver could be made to use the Picasso frame buffer as + * the data buffer of an XImage, which could then be XPutImage()d from time + * to time. Another possibility is to translate all Picasso accesses into + * Xlib (or GDI, or whatever your graphics system is) calls. This possibility + * is a bit tricky, since there is a risk of generating very many single pixel + * accesses which may be rather slow. + * + * TODO: + * - add panning capability + * - we want to add a manual switch to override SetSwitch for hardware banging + * programs started from a Picasso workbench. + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "threaddep/thread.h" +#include "uae.h" +#include "memory.h" +#include "custom.h" +#include "newcpu.h" +#include "xwin.h" +#include "picasso96.h" + +#ifdef JIT +int have_done_picasso=0; /* For the JIT compiler */ +int picasso_is_special=PIC_WRITE; /* ditto */ +int picasso_is_special_read=PIC_READ; /* ditto */ +#endif + +#ifdef PICASSO96 + +int p96hack_vpos, p96hack_vpos2, p96refresh_active; + +#define P96TRACING_ENABLED 0 +#if P96TRACING_ENABLED +#define P96TRACE(x) do { write_log x; } while(0) +#else +#define P96TRACE(x) +#endif + +static uae_u32 gfxmem_lget (uaecptr) REGPARAM; +static uae_u32 gfxmem_wget (uaecptr) REGPARAM; +static uae_u32 gfxmem_bget (uaecptr) REGPARAM; +static void gfxmem_lput (uaecptr, uae_u32) REGPARAM; +static void gfxmem_wput (uaecptr, uae_u32) REGPARAM; +static void gfxmem_bput (uaecptr, uae_u32) REGPARAM; +static int gfxmem_check (uaecptr addr, uae_u32 size) REGPARAM; +static uae_u8 *gfxmem_xlate (uaecptr addr) REGPARAM; + +static void write_gfx_long (uaecptr addr, uae_u32 value); +static void write_gfx_word (uaecptr addr, uae_u16 value); +static void write_gfx_byte (uaecptr addr, uae_u8 value); + +static uae_u8 all_ones_bitmap, all_zeros_bitmap; + +struct picasso96_state_struct picasso96_state; +struct picasso_vidbuf_description picasso_vidinfo; + +/* These are the maximum resolutions... They are filled in by GetSupportedResolutions() */ +/* have to fill this in, otherwise problems occur + * @@@ ??? what problems? + */ +struct ScreenResolution planar = { 320, 240 }; +struct ScreenResolution chunky = { 640, 480 }; +struct ScreenResolution hicolour = { 640, 480 }; +struct ScreenResolution truecolour = { 640, 480 }; +struct ScreenResolution alphacolour = { 640, 480 }; + +uae_u16 picasso96_pixel_format = RGBFF_CHUNKY; + +struct PicassoResolution DisplayModes[MAX_PICASSO_MODES]; + +static int mode_count = 0; + +static int set_gc_called = 0; +static int set_panning_called = 0; +/* Address of the screen in the Amiga frame buffer at the time of the last + SetPanning call. */ +static uaecptr oldscr; + +static uae_u32 p2ctab[256][2]; + +/* + * Debugging dumps + */ + +static void DumpModeInfoStructure (uaecptr amigamodeinfoptr) +{ + write_log ("ModeInfo Structure Dump:\n"); + write_log (" Node.ln_Succ = 0x%x\n", get_long (amigamodeinfoptr)); + write_log (" Node.ln_Pred = 0x%x\n", get_long (amigamodeinfoptr + 4)); + write_log (" Node.ln_Type = 0x%x\n", get_byte (amigamodeinfoptr + 8)); + write_log (" Node.ln_Pri = %d\n", get_byte (amigamodeinfoptr + 9)); + /*write_log (" Node.ln_Name = %s\n", uaememptr->Node.ln_Name); */ + write_log (" OpenCount = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_OpenCount)); + write_log (" Active = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_Active)); + write_log (" Width = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_Width)); + write_log (" Height = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_Height)); + write_log (" Depth = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_Depth)); + write_log (" Flags = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_Flags)); + write_log (" HorTotal = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorTotal)); + write_log (" HorBlankSize = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorBlankSize)); + write_log (" HorSyncStart = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorSyncStart)); + write_log (" HorSyncSize = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorSyncSize)); + write_log (" HorSyncSkew = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_HorSyncSkew)); + write_log (" HorEnableSkew = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_HorEnableSkew)); + write_log (" VerTotal = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerTotal)); + write_log (" VerBlankSize = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerBlankSize)); + write_log (" VerSyncStart = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerSyncStart)); + write_log (" VerSyncSize = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerSyncSize)); + write_log (" Clock = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_first_union)); + write_log (" ClockDivide = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_second_union)); + write_log (" PixelClock = %d\n", get_long (amigamodeinfoptr + PSSO_ModeInfo_PixelClock)); +} + +static void DumpLibResolutionStructure (uaecptr amigalibresptr) +{ + int i; + uaecptr amigamodeinfoptr; + struct LibResolution *uaememptr = (struct LibResolution *) get_mem_bank (amigalibresptr).xlateaddr (amigalibresptr); + + return; + + write_log ("LibResolution Structure Dump:\n"); + + if (get_long (amigalibresptr + PSSO_LibResolution_DisplayID) == 0xFFFFFFFF) { + write_log (" Finished With LibResolutions...\n"); + } else { + write_log (" Name = %s\n", uaememptr->P96ID); + write_log (" DisplayID = 0x%x\n", get_long (amigalibresptr + PSSO_LibResolution_DisplayID)); + write_log (" Width = %d\n", get_word (amigalibresptr + PSSO_LibResolution_Width)); + write_log (" Height = %d\n", get_word (amigalibresptr + PSSO_LibResolution_Height)); + write_log (" Flags = %d\n", get_word (amigalibresptr + PSSO_LibResolution_Flags)); + for (i = 0; i < MAXMODES; i++) { + amigamodeinfoptr = get_long (amigalibresptr + PSSO_LibResolution_Modes + i * 4); + write_log (" ModeInfo[%d] = 0x%x\n", i, amigamodeinfoptr); + if (amigamodeinfoptr) + DumpModeInfoStructure (amigamodeinfoptr); + } + write_log (" BoardInfo = 0x%x\n", get_long (amigalibresptr + PSSO_LibResolution_BoardInfo)); + } +} + +static char binary_byte[9]; + +static char *BuildBinaryString (uae_u8 value) +{ + int i; + for (i = 0; i < 8; i++) { + binary_byte[i] = (value & (1 << (7 - i))) ? '#' : '.'; + } + binary_byte[8] = '\0'; + return binary_byte; +} + +static void DumpPattern (struct Pattern *patt) +{ +/* + uae_u8 *mem; + int row, col; + for (row = 0; row < (1 << patt->Size); row++) { + mem = patt->Memory + row * 2; + for (col = 0; col < 2; col++) { + write_log ("%s", BuildBinaryString (*mem++)); + } + write_log ("\n"); + } +*/ +} + +static void DumpTemplate (struct Template *tmp, uae_u16 w, uae_u16 h) +{ +/* + uae_u8 *mem = tmp->Memory; + int row, col, width; + width = (w + 7) >> 3; + write_log ("xoffset = %d, bpr = %d\n", tmp->XOffset, tmp->BytesPerRow); + for (row = 0; row < h; row++) { + mem = tmp->Memory + row * tmp->BytesPerRow; + for (col = 0; col < width; col++) { + write_log ("%s", BuildBinaryString (*mem++)); + } + write_log ("\n"); + } +*/ + } + +int picasso_nr_resolutions (void) +{ + return mode_count; +} + +static void ShowSupportedResolutions (void) +{ + int i; + + return; + + for (i = 0; i < mode_count; i++) + write_log ("%s\n", DisplayModes[i].name); +} + +static uae_u8 GetBytesPerPixel (uae_u32 RGBfmt) +{ + switch (RGBfmt) { + case RGBFB_CLUT: + return 1; + + case RGBFB_A8R8G8B8: + case RGBFB_A8B8G8R8: + case RGBFB_R8G8B8A8: + case RGBFB_B8G8R8A8: + return 4; + + case RGBFB_B8G8R8: + case RGBFB_R8G8B8: + return 3; + + case RGBFB_R5G5B5: + case RGBFB_R5G6B5: + case RGBFB_R5G6B5PC: + case RGBFB_R5G5B5PC: + case RGBFB_B5G6R5PC: + case RGBFB_B5G5R5PC: + return 2; + default: + write_log ("ERROR - GetBytesPerPixel() was unsuccessful with 0x%x?!\n", RGBfmt); + return 0; + } +} + +/* + * Amiga <-> native structure conversion functions + */ + +static int CopyRenderInfoStructureA2U (uaecptr amigamemptr, struct RenderInfo *ri) +{ + uaecptr memp = get_long (amigamemptr + PSSO_RenderInfo_Memory); + + if (valid_address (memp, PSSO_RenderInfo_sizeof)) { + ri->AMemory=memp; + ri->Memory = get_real_address (memp); + ri->BytesPerRow = get_word (amigamemptr + PSSO_RenderInfo_BytesPerRow); + ri->RGBFormat = get_long (amigamemptr + PSSO_RenderInfo_RGBFormat); + return 1; + } + write_log ("ERROR - Invalid RenderInfo memory area...\n"); + return 0; +} + +static int CopyPatternStructureA2U (uaecptr amigamemptr, struct Pattern *pattern) +{ + uaecptr memp = get_long (amigamemptr + PSSO_Pattern_Memory); + if (valid_address (memp, PSSO_Pattern_sizeof)) { + pattern->Memory = get_real_address (memp); + pattern->XOffset = get_word (amigamemptr + PSSO_Pattern_XOffset); + pattern->YOffset = get_word (amigamemptr + PSSO_Pattern_YOffset); + pattern->FgPen = get_long (amigamemptr + PSSO_Pattern_FgPen); + pattern->BgPen = get_long (amigamemptr + PSSO_Pattern_BgPen); + pattern->Size = get_byte (amigamemptr + PSSO_Pattern_Size); + pattern->DrawMode = get_byte (amigamemptr + PSSO_Pattern_DrawMode); + return 1; + } + write_log ("ERROR - Invalid Pattern memory area...\n"); + return 0; +} + +static void CopyColorIndexMappingA2U (uaecptr amigamemptr, struct ColorIndexMapping *cim) +{ + int i; + cim->ColorMask = get_long (amigamemptr); + for (i = 0; i < 256; i++, amigamemptr += 4) + cim->Colors[i] = get_long (amigamemptr + 4); +} + +static int CopyBitMapStructureA2U (uaecptr amigamemptr, struct BitMap *bm) +{ + int i; + + bm->BytesPerRow = get_word (amigamemptr + PSSO_BitMap_BytesPerRow); + bm->Rows = get_word (amigamemptr + PSSO_BitMap_Rows); + bm->Flags = get_byte (amigamemptr + PSSO_BitMap_Flags); + bm->Depth = get_byte (amigamemptr + PSSO_BitMap_Depth); + + for (i = 0; i < bm->Depth; i++) { + uaecptr plane = get_long (amigamemptr + PSSO_BitMap_Planes + i * 4); + switch (plane) { + case 0: + bm->Planes[i] = &all_zeros_bitmap; + break; + case 0xFFFFFFFF: + bm->Planes[i] = &all_ones_bitmap; + break; + default: + if (valid_address (plane, bm->BytesPerRow * bm->Rows)) + bm->Planes[i] = get_real_address (plane); + else + return 0; + break; + } + } + return 1; +} + +static int CopyTemplateStructureA2U (uaecptr amigamemptr, struct Template *tmpl) +{ + uaecptr memp = get_long (amigamemptr + PSSO_Template_Memory); + + if (valid_address (memp, 1 /* FIXME */ )) { + tmpl->Memory = get_real_address (memp); + tmpl->BytesPerRow = get_word (amigamemptr + PSSO_Template_BytesPerRow); + tmpl->XOffset = get_byte (amigamemptr + PSSO_Template_XOffset); + tmpl->DrawMode = get_byte (amigamemptr + PSSO_Template_DrawMode); + tmpl->FgPen = get_long (amigamemptr + PSSO_Template_FgPen); + tmpl->BgPen = get_long (amigamemptr + PSSO_Template_BgPen); + return 1; + } + write_log ("ERROR - Invalid Template memory area...\n"); + return 0; +} + +static void CopyLibResolutionStructureU2A (struct LibResolution *libres, uaecptr amigamemptr) +{ + char *uaememptr = 0; + int i; + + uaememptr = gfxmem_xlate (amigamemptr); /* I know that amigamemptr is inside my gfxmem chunk, so I can just do the xlate() */ + memset (uaememptr, 0, PSSO_LibResolution_sizeof); /* zero out our LibResolution structure */ + strcpy (uaememptr + PSSO_LibResolution_P96ID, libres->P96ID); + put_long (amigamemptr + PSSO_LibResolution_DisplayID, libres->DisplayID); + put_word (amigamemptr + PSSO_LibResolution_Width, libres->Width); + put_word (amigamemptr + PSSO_LibResolution_Height, libres->Height); + put_word (amigamemptr + PSSO_LibResolution_Flags, libres->Flags); + for (i = 0; i < MAXMODES; i++) + put_long (amigamemptr + PSSO_LibResolution_Modes + i * 4, libres->Modes[i]); +#if 0 + put_long (amigamemptr, libres->Node.ln_Succ); + put_long (amigamemptr + 4, libres->Node.ln_Pred); + put_byte (amigamemptr + 8, libres->Node.ln_Type); + put_byte (amigamemptr + 9, libres->Node.ln_Pri); +#endif + put_long (amigamemptr + 10, amigamemptr + PSSO_LibResolution_P96ID); + put_long (amigamemptr + PSSO_LibResolution_BoardInfo, libres->BoardInfo); +} + +/* list is Amiga address of list, in correct endian format for UAE + * node is Amiga address of node, in correct endian format for UAE */ +static void AmigaListAddTail (uaecptr list, uaecptr node) +{ + uaecptr amigamemptr = 0; + + if (get_long (list + 8) == list) { + /* Empty list - set it up */ + put_long (list, node); /* point the lh_Head to our new node */ + put_long (list + 4, 0); /* set the lh_Tail to NULL */ + put_long (list + 8, node); /* point the lh_TailPred to our new node */ + + /* Adjust the new node - don't rely on it being zeroed out */ + put_long (node, 0); /* ln_Succ */ + put_long (node + 4, 0); /* ln_Pred */ + } else { + amigamemptr = get_long (list + 8); /* get the lh_TailPred contents */ + + put_long (list + 8, node); /* point the lh_TailPred to our new node */ + + /* Adjust the previous lh_TailPred node */ + put_long (amigamemptr, node); /* point the ln_Succ to our new node */ + + /* Adjust the new node - don't rely on it being zeroed out */ + put_long (node, 0); /* ln_Succ */ + put_long (node + 4, amigamemptr); /* ln_Pred */ + } +} + +/* + * Functions to perform an action on the real screen + */ + +/* + * Fill a rectangle on the screen. src points to the start of a line of the + * filled rectangle in the frame buffer; it can be used as a memcpy source if + * there is no OS specific function to fill the rectangle. + */ + +static void do_fillrect (uae_u8 *src, int x, int y, int width, int height, + uae_u32 pen, int Bpp, RGBFTYPE rgbtype) +{ + uae_u8 *dst; + + P96TRACE (("do_fillrect (src:%08x x:%d y:%d w:%d h%d pen:%08x)\n", src, x, y, width, height, pen)); + + /* Clipping. */ + x -= picasso96_state.XOffset; + y -= picasso96_state.YOffset; + if (x < 0) { + width += x; + x = 0; + } + if (y < 0) { + height += y; + y = 0; + } + if (x + width > picasso96_state.Width) + width = picasso96_state.Width - x; + if (y + height > picasso96_state.Height) + height = picasso96_state.Height - y; + + if (width <= 0 || height <= 0) + return; + + /* Try OS specific fillrect function here; and return if successful. Make sure we adjust for + * the pen values if we're doing 8-bit display-emulation on a 16-bit or higher screen. */ + if (picasso_vidinfo.rgbformat == picasso96_state.RGBFormat) { +# ifndef WORDS_BIGENDIAN + if (Bpp > 1) + pen = (pen & 0x000000FF) << 24 + | (pen & 0x0000FF00) << 8 + | (pen & 0x00FF0000) >> 8 + | (pen & 0xFF000000) >> 24; +# endif + if (DX_Fill (x, y, width, height, pen, rgbtype)) + return; + } else { + if (DX_Fill (x, y, width, height, picasso_vidinfo.clut[src[0]], rgbtype)) + return; + } + + P96TRACE ("P96_WARNING: do_fillrect() using fall-back routine!\n"); + + DX_Invalidate (y, y + height - 1); + if (!picasso_vidinfo.extra_mem) + return; + + width *= picasso96_state.BytesPerPixel; + dst = gfx_lock_picasso (); + if (!dst) + goto out; + + dst += y * picasso_vidinfo.rowbytes + x * picasso_vidinfo.pixbytes; + if (picasso_vidinfo.rgbformat == picasso96_state.RGBFormat) { + if (Bpp == 1) { + while (height-- > 0) { + memset (dst, pen, width); + dst += picasso_vidinfo.rowbytes; + } + } else { + while (height-- > 0) { + memcpy (dst, src, width); + dst += picasso_vidinfo.rowbytes; + } + } + } else { + int psiz = GetBytesPerPixel (picasso_vidinfo.rgbformat); + if (picasso96_state.RGBFormat != RGBFB_CHUNKY) + abort (); + + while (height-- > 0) { + int i; + switch (psiz) { + case 2: + for (i = 0; i < width; i++) + *((uae_u16 *) dst + i) = picasso_vidinfo.clut[src[i]]; + break; + case 4: + for (i = 0; i < width; i++) + *((uae_u32 *) dst + i) = picasso_vidinfo.clut[src[i]]; + break; + default: + abort (); + } + dst += picasso_vidinfo.rowbytes; + } + } + out: + gfx_unlock_picasso (); +} + +/* + * This routine modifies the real screen buffer after a blit has been + * performed in the save area. If can_do_blit is nonzero, the blit can + * be performed within the real screen buffer; otherwise, this routine + * must do it by hand using the data in the save area, pointed to by + * srcp. + */ + +static void do_blit (struct RenderInfo *ri, int Bpp, int srcx, int srcy, + int dstx, int dsty, int width, int height, + BLIT_OPCODE opcode, int can_do_blit) +{ + int xoff = picasso96_state.XOffset; + int yoff = picasso96_state.YOffset; + uae_u8 *srcp, *dstp; + +// write_log ("do_blit (sx:%d sy:%d op:%d cando:%d)\n", srcx, srcy, opcode, can_do_blit); + /* Clipping. */ + dstx -= xoff; + dsty -= yoff; + if (srcy < yoff || srcx < xoff + || srcx - xoff + width > picasso96_state.Width + || srcy - yoff + height > picasso96_state.Height) + { + can_do_blit = 0; + } + if (dstx < 0) { + srcx -= dstx; + width += dstx; + dstx = 0; + } + if (dsty < 0) { + srcy -= dsty; + height += dsty; + dsty = 0; + } + if (dstx + width > picasso96_state.Width) + width = picasso96_state.Width - dstx; + if (dsty + height > picasso96_state.Height) + height = picasso96_state.Height - dsty; + if (width <= 0 || height <= 0) + return; + + /* If this RenderInfo points at something else than the currently visible + * screen, we must ignore the blit. */ + if (can_do_blit) { + /* + * Call OS blitting function that can do it in video memory. + * Should return if it was successful + */ + if (DX_Blit (srcx, srcy, dstx, dsty, width, height, opcode)) + return; + } + + /* If no OS blit available, we do a copy from the P96 framebuffer in Amiga + memory to the host's frame buffer. */ + + DX_Invalidate (dsty, dsty + height - 1); + if (!picasso_vidinfo.extra_mem) + return; + + dstp = gfx_lock_picasso (); + if (dstp == 0) + goto out; + dstp += dsty * picasso_vidinfo.rowbytes + dstx * picasso_vidinfo.pixbytes; + P96TRACE(("do_blit with srcp 0x%x, dstp 0x%x, dst_rowbytes %d, srcx %d, srcy %d, dstx %d, dsty %d, w %d, h %d, dst_pixbytes %d\n", + srcp, dstp, picasso_vidinfo.rowbytes, srcx, srcy, dstx, dsty, width, height, picasso_vidinfo.pixbytes)); + P96TRACE(("gfxmem is at 0x%x\n",gfxmemory)); + + srcp = ri->Memory + srcx * Bpp + srcy * ri->BytesPerRow; + DX_Invalidate (dsty, dsty + height - 1); + + if (picasso_vidinfo.rgbformat == picasso96_state.RGBFormat) { + width *= Bpp; + while (height-- > 0) { + memcpy (dstp, srcp, width); + srcp += ri->BytesPerRow; + dstp += picasso_vidinfo.rowbytes; + } + } else { + int psiz = GetBytesPerPixel (picasso_vidinfo.rgbformat); + if (picasso96_state.RGBFormat != RGBFB_CHUNKY) + abort (); + + while (height-- > 0) { + int i; + switch (psiz) { + case 2: + for (i = 0; i < width; i++) + *((uae_u16 *) dstp + i) = picasso_vidinfo.clut[srcp[i]]; + break; + case 4: + for (i = 0; i < width; i++) + *((uae_u32 *) dstp + i) = picasso_vidinfo.clut[srcp[i]]; + break; + default: + abort (); + } + srcp += ri->BytesPerRow; + dstp += picasso_vidinfo.rowbytes; + } + } + out: + gfx_unlock_picasso (); +} + +/* + * Invert a rectangle on the screen. + */ + +static void do_invertrect (struct RenderInfo *ri, int Bpp, int x, int y, int width, int height) +{ +#if 0 + /* Clipping. */ + x -= picasso96_state.XOffset; + y -= picasso96_state.YOffset; + if (x < 0) { + width += x; + x = 0; + } + if (y < 0) { + height += y; + y = 0; + } + if (x + width > picasso96_state.Width) + width = picasso96_state.Width - x; + if (y + height > picasso96_state.Height) + height = picasso96_state.Height - y; + + if (width <= 0 || height <= 0) + return; + +#endif + /* TODO: Try OS specific invertrect function here; and return if successful. */ + + do_blit (ri, Bpp, x, y, x, y, width, height, BLIT_SRC, 0); +} + +static uaecptr wgfx_linestart; +static uaecptr wgfx_lineend; +static uaecptr wgfx_min, wgfx_max; +static long wgfx_y; + +static void wgfx_do_flushline (void) +{ + int src_y = wgfx_y; + long x0, x1, width; + uae_u8 *src, *dstp; + int Bpp = GetBytesPerPixel (picasso_vidinfo.rgbformat); + int fb_bpp = picasso96_state.BytesPerPixel; + + wgfx_y -= picasso96_state.YOffset; + if (wgfx_y < 0 || wgfx_y >= picasso96_state.Height) + goto out1; + + DX_Invalidate (wgfx_y, wgfx_y); + if (!picasso_vidinfo.extra_mem) + goto out1; + + x0 = wgfx_min - wgfx_linestart; + width = wgfx_max - wgfx_min; + x0 -= picasso96_state.XOffset * fb_bpp; + if (x0 < 0) { + width += x0; + wgfx_min += x0; + x0 = 0; + } + if (x0 + width > picasso96_state.Width * fb_bpp) + width = picasso96_state.Width * fb_bpp - x0; + + dstp = gfx_lock_picasso (); + if (dstp == 0) + goto out; + + P96TRACE(("flushing %d\n", wgfx_y)); + src = gfxmemory + wgfx_min; + + if (picasso_vidinfo.rgbformat == picasso96_state.RGBFormat) { + dstp += wgfx_y * picasso_vidinfo.rowbytes + x0; + memcpy (dstp, src, width); + } else { + int i; + + if (picasso96_state.RGBFormat != RGBFB_CHUNKY) + abort (); + + dstp += wgfx_y * picasso_vidinfo.rowbytes + x0 * Bpp; + switch (Bpp) { + case 2: + for (i = 0; i < width; i++) + *((uae_u16 *) dstp + i) = picasso_vidinfo.clut[src[i]]; + break; + case 4: + for (i = 0; i < width; i++) + *((uae_u32 *) dstp + i) = picasso_vidinfo.clut[src[i]]; + break; + default: + abort (); + } + } + + out: + gfx_unlock_picasso (); + out1: + wgfx_linestart = 0xFFFFFFFF; +} + +STATIC_INLINE void wgfx_flushline (void) +{ + if (wgfx_linestart == 0xFFFFFFFF || !picasso_on) + return; + wgfx_do_flushline (); +} + +static int renderinfo_is_current_screen (struct RenderInfo *ri) +{ + if (!picasso_on) + return 0; + if (ri->Memory != gfxmemory + (picasso96_state.Address - gfxmem_start)) + return 0; + + return 1; +} + +/* Clear our screen, since we've got a new Picasso screen-mode, and refresh with the proper contents + * This is called on several occasions: + * 1. Amiga-->Picasso transition, via SetSwitch() + * 2. Picasso-->Picasso transition, via SetPanning(). + * 3. whenever the graphics code notifies us that the screen contents have been lost. + */ +extern unsigned int new_beamcon0; + +void picasso_refresh (int call_setpalette) +{ + struct RenderInfo ri; + + if (!picasso_on) + return; + + { // for higher P96 mousedraw rate + extern uae_u16 vtotal; + if (p96hack_vpos2) { + vtotal = p96hack_vpos2; + new_beamcon0 |= 0x80; + p96refresh_active=1; + } else new_beamcon0 |= 0x20; + } + +#ifdef JIT + have_done_picasso=1; +#endif + + /* Make sure that the first time we show a Picasso video mode, we don't blit any crap. + * We can do this by checking if we have an Address yet. */ + if (picasso96_state.Address) { + unsigned int width, height; + /* blit the stuff from our static frame-buffer to the gfx-card */ + ri.Memory = gfxmemory + (picasso96_state.Address - gfxmem_start); + ri.BytesPerRow = picasso96_state.BytesPerRow; + ri.RGBFormat = picasso96_state.RGBFormat; + + if (set_panning_called) { + width = picasso96_state.VirtualWidth; + height = picasso96_state.VirtualHeight; + } else { + width = picasso96_state.Width; + height = picasso96_state.Height; + } + + do_blit (&ri, picasso96_state.BytesPerPixel, 0, 0, 0, 0, width, height, BLIT_SRC, 0); + } else + write_log ("ERROR - picasso_refresh() can't refresh!\n"); +} + +/* +* Functions to perform an action on the frame-buffer +*/ +STATIC_INLINE void do_blitrect_frame_buffer (struct RenderInfo *ri, + struct RenderInfo *dstri, + unsigned long srcx, unsigned long srcy, + unsigned long dstx, unsigned long dsty, + unsigned long width, unsigned long height, + uae_u8 mask, BLIT_OPCODE opcode) +{ + uae_u8 *src, *dst, *tmp, *tmp2, *tmp3; + uae_u8 Bpp = GetBytesPerPixel (ri->RGBFormat); + unsigned long total_width = width * Bpp; + unsigned long linewidth = (total_width + 15) & ~15; + unsigned long lines; + int can_do_visible_blit = 0; + + src = ri->Memory + srcx*Bpp + srcy*ri->BytesPerRow; + dst = dstri->Memory + dstx*Bpp + dsty*dstri->BytesPerRow; + + if (mask != 0xFF && Bpp > 1) { + write_log ("WARNING - BlitRect() has mask 0x%x with Bpp %d.\n", mask, Bpp); + } + + if (mask == 0xFF || Bpp > 1) { + if( opcode == BLIT_SRC ) { + /* handle normal case efficiently */ + if (ri->Memory == dstri->Memory && dsty == srcy) { + unsigned long i; + for (i = 0; i < height; i++, src += ri->BytesPerRow, dst += dstri->BytesPerRow) + memmove (dst, src, total_width); + } else if (dsty < srcy) { + unsigned long i; + for (i = 0; i < height; i++, src += ri->BytesPerRow, dst += dstri->BytesPerRow) + memcpy (dst, src, total_width); + } else { + unsigned long i; + src += (height-1) * ri->BytesPerRow; + dst += (height-1) * dstri->BytesPerRow; + for (i = 0; i < height; i++, src -= ri->BytesPerRow, dst -= dstri->BytesPerRow) + memcpy (dst, src, total_width); + } + return; + } else { + uae_u8 *src2 = src; + uae_u8 *dst2 = dst; + uae_u32 *src2_32 = (uae_u32*)src; + uae_u32 *dst2_32 = (uae_u32*)dst; + unsigned int y; + + for (y = 0; y < height; y++) { + int bound = src + total_width - 4; + //copy now the longs + for( src2_32 = src, dst2_32 = dst; src2_32 < bound; src2_32++, dst2_32++ ) { + switch( opcode ) { + case BLIT_FALSE: + *dst2_32 = 0; + break; + case BLIT_NOR: + *dst2_32 = ~(*src2_32 | *dst2_32); + break; + case BLIT_ONLYDST: + *dst2_32 = *dst2_32 & ~(*src2_32); + break; + case BLIT_NOTSRC: + *dst2_32 = ~(*src2_32); + break; + case BLIT_ONLYSRC: + *dst2_32 = *src2_32 & ~(*dst2_32); + break; + case BLIT_NOTDST: + *dst2_32 = ~(*dst2_32); + break; + case BLIT_EOR: + *dst2_32 = *src2_32 ^ *dst2_32; + break; + case BLIT_NAND: + *dst2_32 = ~(*src2_32 & *dst2_32); + break; + case BLIT_AND: + *dst2_32 = *src2_32 & *dst2_32; + break; + case BLIT_NEOR: + *dst2_32 = ~(*src2_32 ^ *dst2_32); + break; + case BLIT_DST: + write_log( "do_blitrect_frame_buffer shouldn't get BLIT_DST!\n"); + break; + case BLIT_NOTONLYSRC: + *dst2_32 = ~(*src2_32) | *dst2_32; + break; + case BLIT_SRC: + write_log( "do_blitrect_frame_buffer shouldn't get BLIT_SRC!\n"); + break; + case BLIT_NOTONLYDST: + *dst2_32 = ~(*dst2_32) | *src2_32; + break; + case BLIT_OR: + *dst2_32 = *src2_32 | *dst2_32; + break; + case BLIT_TRUE: + *dst2_32 = 0xFFFFFFFF; + break; + case 30: //code for swap source with dest in byte + { + uae_u32 temp; + temp = *src2_32; + *src2_32 = *dst2_32; + *dst2_32 = temp; + } + break; + case BLIT_LAST: + write_log( "do_blitrect_frame_buffer shouldn't get BLIT_LAST!\n"); + break; + } /* switch opcode */ + } // for end + //now copy the rest few bytes + for (src2 = src2_32, dst2 = dst2_32; src2 < src + total_width; src2++, dst2++ ) { + switch( opcode ) { + case BLIT_FALSE: + *dst2 = 0; + break; + case BLIT_NOR: + *dst2 = ~(*src2 | *dst2); + break; + case BLIT_ONLYDST: + *dst2 = *dst2 & ~(*src2); + break; + case BLIT_NOTSRC: + *dst2 = ~(*src2); + break; + case BLIT_ONLYSRC: + *dst2 = *src2 & ~(*dst2); + break; + case BLIT_NOTDST: + *dst2 = ~(*dst2); + break; + case BLIT_EOR: + *dst2 = *src2 ^ *dst2; + break; + case BLIT_NAND: + *dst2 = ~(*src2 & *dst2); + break; + case BLIT_AND: + *dst2 = *src2 & *dst2; + break; + case BLIT_NEOR: + *dst2 = ~(*src2 ^ *dst2); + break; + case BLIT_DST: + write_log( "do_blitrect_frame_buffer shouldn't get BLIT_DST!\n"); + break; + case BLIT_NOTONLYSRC: + *dst2 = ~(*src2) | *dst2; + break; + case BLIT_SRC: + write_log( "do_blitrect_frame_buffer shouldn't get BLIT_SRC!\n"); + break; + case BLIT_NOTONLYDST: + *dst2 = ~(*dst2) | *src2; + break; + case BLIT_OR: + *dst2 = *src2 | *dst2; + break; + case BLIT_TRUE: + *dst2 = 0xFF; + break; + case BLIT_LAST: + write_log( "do_blitrect_frame_buffer shouldn't get BLIT_LAST!\n"); + break; + case 30: //code for swap source with dest in long + { + uae_u8 temp; + temp = *src2; + *src2 = *dst2; + *dst2 = temp; + } + break; + } /* switch opcode */ + } /* for width */ + src += ri->BytesPerRow; + dst += dstri->BytesPerRow; + } /* for height */ + } + return; + } + // (mask != 0xFF && Bpp <= 1) + tmp3 = tmp2 = tmp = xmalloc (linewidth * height); /* allocate enough memory for the src-rect */ + if (!tmp) + return; + + /* copy the src-rect into our temporary buffer space */ + for (lines = 0; lines < height; lines++, src += ri->BytesPerRow, tmp2 += linewidth) + memcpy (tmp2, src, total_width); + + /* copy the temporary buffer to the destination */ + for (lines = 0; lines < height; lines++, dst += dstri->BytesPerRow, tmp += linewidth) { + unsigned long cols; + for (cols = 0; cols < width; cols++) { + dst[cols] &= ~mask; + dst[cols] |= tmp[cols] & mask; + } + } + /* free the temp-buf */ + free (tmp3); +} + +/* + * BOOL FindCard(struct BoardInfo *bi); and + * + * FindCard is called in the first stage of the board initialisation and + * configuration and is used to look if there is a free and unconfigured + * board of the type the driver is capable of managing. If it finds one, + * it immediately reserves it for use by Picasso96, usually by clearing + * the CDB_CONFIGME bit in the flags field of the ConfigDev struct of + * this expansion card. But this is only a common example, a driver can + * do whatever it wants to mark this card as used by the driver. This + * mechanism is intended to ensure that a board is only configured and + * used by one driver. FindBoard also usually fills some fields of the + * BoardInfo struct supplied by the caller, the rtg.library, for example + * the MemoryBase, MemorySize and RegisterBase fields. + */ +uae_u32 picasso_FindCard (void) +{ + uaecptr AmigaBoardInfo = m68k_areg (regs, 0); + /* NOTES: See BoardInfo struct definition in Picasso96 dev info */ + + if (allocated_gfxmem && !picasso96_state.CardFound) { + /* Fill in MemoryBase, MemorySize */ + put_long (AmigaBoardInfo + PSSO_BoardInfo_MemoryBase, gfxmem_start); + /* size of memory, minus a 32K chunk: 16K for pattern bitmaps, 16K for resolution list */ + put_long (AmigaBoardInfo + PSSO_BoardInfo_MemorySize, allocated_gfxmem - 32768); + + picasso96_state.CardFound = 1; /* mark our "card" as being found */ + return -1; + } else + return 0; +} + +static void FillBoardInfo (uaecptr amigamemptr, struct LibResolution *res, struct PicassoResolution *dm) +{ + char *uaememptr; + switch (dm->depth) { + case 1: + res->Modes[CHUNKY] = amigamemptr; + break; + case 2: + res->Modes[HICOLOR] = amigamemptr; + break; + case 3: + res->Modes[TRUECOLOR] = amigamemptr; + break; + default: + res->Modes[TRUEALPHA] = amigamemptr; + break; + } + uaememptr = gfxmem_xlate (amigamemptr); /* I know that amigamemptr is inside my gfxmem chunk, so I can just do the xlate() */ + memset (uaememptr, 0, PSSO_ModeInfo_sizeof); /* zero out our ModeInfo struct */ + + put_word (amigamemptr + PSSO_ModeInfo_Width, dm->res.width); + put_word (amigamemptr + PSSO_ModeInfo_Height, dm->res.height); + put_byte (amigamemptr + PSSO_ModeInfo_Depth, dm->depth * 8); + put_byte (amigamemptr + PSSO_ModeInfo_Flags, 0); + put_word (amigamemptr + PSSO_ModeInfo_HorTotal, dm->res.width); + put_word (amigamemptr + PSSO_ModeInfo_HorBlankSize, 0); + put_word (amigamemptr + PSSO_ModeInfo_HorSyncStart, 0); + put_word (amigamemptr + PSSO_ModeInfo_HorSyncSize, 0); + put_byte (amigamemptr + PSSO_ModeInfo_HorSyncSkew, 0); + put_byte (amigamemptr + PSSO_ModeInfo_HorEnableSkew, 0); + + put_word (amigamemptr + PSSO_ModeInfo_VerTotal, dm->res.height); + put_word (amigamemptr + PSSO_ModeInfo_VerBlankSize, 0); + put_word (amigamemptr + PSSO_ModeInfo_VerSyncStart, 0); + put_word (amigamemptr + PSSO_ModeInfo_VerSyncSize, 0); + + put_byte (amigamemptr + PSSO_ModeInfo_first_union, 98); + put_byte (amigamemptr + PSSO_ModeInfo_second_union, 14); + + put_long (amigamemptr + PSSO_ModeInfo_PixelClock, dm->res.width * dm->res.height * dm->refresh); +} + +static uae_u32 AssignModeID (int i, int count) +{ + if (DisplayModes[i].res.width == 320 && DisplayModes[i].res.height == 200) + return 0x50001000; + else if (DisplayModes[i].res.width == 320 && DisplayModes[i].res.height == 240) + return 0x50011000; + else if (DisplayModes[i].res.width == 640 && DisplayModes[i].res.height == 400) + return 0x50021000; + else if (DisplayModes[i].res.width == 640 && DisplayModes[i].res.height == 480) + return 0x50031000; + else if (DisplayModes[i].res.width == 800 && DisplayModes[i].res.height == 600) + return 0x50041000; + else if (DisplayModes[i].res.width == 1024 && DisplayModes[i].res.height == 768) + return 0x50051000; + else if (DisplayModes[i].res.width == 1152 && DisplayModes[i].res.height == 864) + return 0x50061000; + else if (DisplayModes[i].res.width == 1280 && DisplayModes[i].res.height == 1024) + return 0x50071000; + else if (DisplayModes[i].res.width == 1600 && DisplayModes[i].res.height == 1280) + return 0x50081000; + + return 0x50091000 + count * 0x10000; +} + +/**************************************** +* InitCard() +* +* a2: BoardInfo structure ptr - Amiga-based address in Intel endian-format +* +* Job - fill in the following structure members: +* gbi_RGBFormats: the pixel formats that the host-OS of UAE supports +* If UAE is running in a window, it should ONLY report the pixel format of the host-OS desktop +* If UAE is running full-screen, it should report ALL pixel formats that the host-OS can handle in full-screen +* NOTE: If full-screen, and the user toggles to windowed-mode, all hell will break loose visually. Must inform +* user that they're doing something stupid (unless their desktop and full-screen colour modes match). +* gbi_SoftSpriteFlags: should be the same as above for now, until actual cursor support is added +* gbi_BitsPerCannon: could be 6 or 8 or ???, depending on the host-OS gfx-card +* gbi_MaxHorResolution: fill this in for all modes (even if you don't support them) +* gbi_MaxVerResolution: fill this in for all modes (even if you don't support them) +*/ +uae_u32 picasso_InitCard (void) +{ + struct LibResolution res; + int i; + int ModeInfoStructureCount = 1, LibResolutionStructureCount = 0; + uaecptr amigamemptr = 0; + uaecptr AmigaBoardInfo = m68k_areg (regs, 2); + put_word (AmigaBoardInfo + PSSO_BoardInfo_BitsPerCannon, DX_BitsPerCannon ()); + put_word (AmigaBoardInfo + PSSO_BoardInfo_RGBFormats, picasso96_pixel_format); + put_word (AmigaBoardInfo + PSSO_BoardInfo_SoftSpriteFlags, picasso96_pixel_format); + put_long (AmigaBoardInfo + PSSO_BoardInfo_BoardType, BT_uaegfx); + put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 0, planar.width); + put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 2, chunky.width); + put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 4, hicolour.width); + put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 6, truecolour.width); + put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 8, alphacolour.width); + put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 0, planar.height); + put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 2, chunky.height); + put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 4, hicolour.height); + put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 6, truecolour.height); + put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 8, alphacolour.height); + + for (i = 0; i < mode_count;) { + int j = i; + /* Add a LibResolution structure to the ResolutionsList MinList in our BoardInfo */ + res.DisplayID = AssignModeID (i, LibResolutionStructureCount); + res.BoardInfo = AmigaBoardInfo; + res.Width = DisplayModes[i].res.width; + res.Height = DisplayModes[i].res.height; + res.Flags = P96F_PUBLIC; + res.P96ID[0] = 'P'; + res.P96ID[1] = '9'; + res.P96ID[2] = '6'; + res.P96ID[3] = '-'; + res.P96ID[4] = '0'; + res.P96ID[5] = ':'; + strcpy (res.Name, "uaegfx:"); + strncat (res.Name, DisplayModes[i].name, strchr (DisplayModes[i].name, ',') - DisplayModes[i].name); + res.Modes[PLANAR] = 0; + res.Modes[CHUNKY] = 0; + res.Modes[HICOLOR] = 0; + res.Modes[TRUECOLOR] = 0; + res.Modes[TRUEALPHA] = 0; + + do { + /* Handle this display mode's depth */ + /* Only add the modes when there is enough P96 RTG memory to hold the bitmap */ + long required = DisplayModes[i].res.width * DisplayModes[i].res.height * DisplayModes[i].depth; + if (allocated_gfxmem - 32768 > required) { + amigamemptr = gfxmem_start + allocated_gfxmem - (PSSO_ModeInfo_sizeof * ModeInfoStructureCount++); + FillBoardInfo (amigamemptr, &res, &DisplayModes[i]); + } + i++; + } while (i < mode_count + && DisplayModes[i].res.width == DisplayModes[j].res.width + && DisplayModes[i].res.height == DisplayModes[j].res.height); + + amigamemptr = gfxmem_start + allocated_gfxmem - 16384 + (PSSO_LibResolution_sizeof * LibResolutionStructureCount++); + CopyLibResolutionStructureU2A (&res, amigamemptr); + DumpLibResolutionStructure (amigamemptr); + AmigaListAddTail (AmigaBoardInfo + PSSO_BoardInfo_ResolutionsList, amigamemptr); + } + + return 0; +} + +extern int x_size, y_size; + +/* + * SetSwitch: + * a0: struct BoardInfo + * d0.w: BOOL state + * this function should set a board switch to let the Amiga signal pass + * through when supplied with a 0 in d0 and to show the board signal if + * a 1 is passed in d0. You should remember the current state of the + * switch to avoid unneeded switching. If your board has no switch, then + * simply supply a function that does nothing except a RTS. + * + * NOTE: Return the opposite of the switch-state. BDK +*/ +uae_u32 picasso_SetSwitch (void) +{ + uae_u16 flag = m68k_dreg (regs, 0) & 0xFFFF; + + /* Do not switch immediately. Tell the custom chip emulation about the + * desired state, and wait for custom.c to call picasso_enablescreen + * whenever it is ready to change the screen state. */ + picasso_requested_on = !!flag; +#if 0 + write_log ("SetSwitch() - trying to show %s screen\n", flag ? "picasso96" : "amiga"); +#endif + + flush_icache(5); /* Changing the screen mode might make gfx memory + directly accessible, or no longer thus accessible */ + + /* Put old switch-state in D0 */ + return !flag; +} + +void picasso_enablescreen (int on) +{ + wgfx_linestart = 0xFFFFFFFF; + picasso_refresh (1); +#if 0 + write_log ("SetSwitch() - showing %s screen\n", on ? "picasso96" : "amiga"); +#endif +} + +static int first_color_changed = 256; +static int last_color_changed = -1; + +void picasso_handle_vsync (void) +{ + if (first_color_changed < last_color_changed) { + DX_SetPalette (first_color_changed, last_color_changed - first_color_changed); + /* If we're emulating a CLUT mode, we need to redraw the entire screen. */ + if (picasso_vidinfo.rgbformat != picasso96_state.RGBFormat) + picasso_refresh (1); + } + + first_color_changed = 256; + last_color_changed = -1; +} + +void picasso_clip_mouse (int *px, int *py) +{ + int xoff = picasso96_state.XOffset; + int yoff = picasso96_state.YOffset; + if (*px < -xoff) + *px = -xoff; + if (*px + xoff > picasso_vidinfo.width) + *px = picasso_vidinfo.width - xoff; + if (*py < -yoff) + *py = -yoff; + if (*py + yoff > picasso_vidinfo.height) + *py = picasso_vidinfo.height - yoff; +} + +/* + * SetColorArray: + * a0: struct BoardInfo + * d0.w: startindex + * d1.w: count + * when this function is called, your driver has to fetch "count" color + * values starting at "startindex" from the CLUT field of the BoardInfo + * structure and write them to the hardware. The color values are always + * between 0 and 255 for each component regardless of the number of bits + * per cannon your board has. So you might have to shift the colors + * before writing them to the hardware. + */ +uae_u32 picasso_SetColorArray (void) +{ + /* Fill in some static UAE related structure about this new CLUT setting + * We need this for CLUT-based displays, and for mapping CLUT to hi/true colour */ + uae_u16 start = m68k_dreg (regs, 0); + uae_u16 count = m68k_dreg (regs, 1); + int i; + uaecptr boardinfo = m68k_areg (regs, 0); + uaecptr clut = boardinfo + PSSO_BoardInfo_CLUT + start * 3; + int changed = 0; + + for (i = start; i < start + count; i++) { + int r = get_byte (clut); + int g = get_byte (clut + 1); + int b = get_byte (clut + 2); + + changed |= (picasso96_state.CLUT[i].Red != r || picasso96_state.CLUT[i].Green != g || picasso96_state.CLUT[i].Blue != b); + + picasso96_state.CLUT[i].Red = r; + picasso96_state.CLUT[i].Green = g; + picasso96_state.CLUT[i].Blue = b; + clut += 3; + } + if (changed) { + if (start < first_color_changed) + first_color_changed = start; + if (start + count > last_color_changed) + last_color_changed = start + count; + } + /*write_log ("SetColorArray(%d,%d)\n", start, count); */ + return 1; +} + +/* + * SetDAC: + * a0: struct BoardInfo + * d7: RGBFTYPE RGBFormat + * This function is called whenever the RGB format of the display changes, + * e.g. from chunky to TrueColor. Usually, all you have to do is to set + * the RAMDAC of your board accordingly. + */ +uae_u32 picasso_SetDAC (void) +{ + /* Fill in some static UAE related structure about this new DAC setting + * Lets us keep track of what pixel format the Amiga is thinking about in our frame-buffer */ + + write_log ("SetDAC()\n"); + return 1; +} + +static void init_picasso_screen (void) +{ + int width = picasso96_state.Width; + int height = picasso96_state.Height; + int vwidth = picasso96_state.VirtualWidth; + int vheight = picasso96_state.VirtualHeight; + int xoff = 0; + int yoff = 0; + + if (!set_gc_called) + return; + + if (set_panning_called) { + picasso96_state.Extent = picasso96_state.Address + (picasso96_state.BytesPerRow * vheight); + xoff = picasso96_state.XOffset; + yoff = picasso96_state.YOffset; + } + + gfx_set_picasso_modeinfo (width, height, picasso96_state.GC_Depth, picasso96_state.RGBFormat); + DX_SetPalette (0, 256); + + wgfx_linestart = 0xFFFFFFFF; + picasso_refresh (1); +} + +/* + * SetGC: + * a0: struct BoardInfo + * a1: struct ModeInfo + * d0: BOOL Border + * This function is called whenever another ModeInfo has to be set. This + * function simply sets up the CRTC and TS registers to generate the + * timing used for that screen mode. You should not set the DAC, clocks + * or linear start adress. They will be set when appropriate by their + * own functions. + */ +uae_u32 picasso_SetGC (void) +{ + /* Fill in some static UAE related structure about this new ModeInfo setting */ + uaecptr modeinfo = m68k_areg (regs, 1); + + picasso96_state.Width = get_word (modeinfo + PSSO_ModeInfo_Width); + picasso96_state.VirtualWidth = picasso96_state.Width; /* in case SetPanning doesn't get called */ + + picasso96_state.Height = get_word (modeinfo + PSSO_ModeInfo_Height); + picasso96_state.VirtualHeight = picasso96_state.Height; + + picasso96_state.GC_Depth = get_byte (modeinfo + PSSO_ModeInfo_Depth); + picasso96_state.GC_Flags = get_byte (modeinfo + PSSO_ModeInfo_Flags); + + P96TRACE (("SetGC(%d,%d,%d)\n", picasso96_state.Width, picasso96_state.Height, picasso96_state.GC_Depth)); + + set_gc_called = 1; /* @@@ when do we need to reset this? */ + init_picasso_screen (); + return 1; +} + +/* + * SetPanning: + * a0: struct BoardInfo + * a1: UBYTE *Memory + * d0: uae_u16 Width + * d1: WORD XOffset + * d2: WORD YOffset + * d7: RGBFTYPE RGBFormat + * This function sets the view origin of a display which might also be + * overscanned. In register a1 you get the start address of the screen + * bitmap on the Amiga side. You will have to subtract the starting + * address of the board memory from that value to get the memory start + * offset within the board. Then you get the offset in pixels of the + * left upper edge of the visible part of an overscanned display. From + * these values you will have to calculate the LinearStartingAddress + * fields of the CRTC registers. + + * NOTE: SetPanning() can be used to know when a Picasso96 screen is + * being opened. Better to do the appropriate clearing of the + * background here than in SetSwitch() derived functions, + * because SetSwitch() is not called for subsequent Picasso screens. + */ +uae_u32 picasso_SetPanning (void) +{ + uae_u16 Width = m68k_dreg (regs, 0); + uaecptr start_of_screen = m68k_areg (regs, 1); + uaecptr bi = m68k_areg (regs, 0); + uaecptr bmeptr = get_long (bi + PSSO_BoardInfo_BitMapExtra); /* Get our BoardInfo ptr's BitMapExtra ptr */ + int oldxoff = picasso96_state.XOffset; + int oldyoff = picasso96_state.YOffset; +#if 0 + /* @@@ This is in WinUAE, but it breaks things. */ + if (oldscr == 0) { + oldscr = start_of_screen; + } + if ((oldscr != start_of_screen)) { + set_gc_called = 0; + oldscr = start_of_screen; + } +#endif + + picasso96_state.Address = start_of_screen; /* Amiga-side address */ + picasso96_state.XOffset = (uae_s16) m68k_dreg (regs, 1); + picasso96_state.YOffset = (uae_s16) m68k_dreg (regs, 2); + picasso96_state.VirtualWidth = get_word (bmeptr + PSSO_BitMapExtra_Width); + picasso96_state.VirtualHeight = get_word (bmeptr + PSSO_BitMapExtra_Height); + picasso96_state.RGBFormat = m68k_dreg (regs, 7); + picasso96_state.BytesPerPixel = GetBytesPerPixel (picasso96_state.RGBFormat); + picasso96_state.BytesPerRow = Width * picasso96_state.BytesPerPixel; + + set_panning_called = 1; + P96TRACE (("SetPanning(%d, %d, %d) Start 0x%x, BPR %d\n", + Width, picasso96_state.XOffset, picasso96_state.YOffset, start_of_screen, picasso96_state.BytesPerRow)); + + init_picasso_screen (); + + return 1; +} + +static void do_xor8 (uae_u8 * ptr, long len, uae_u32 val) +{ + int i; +#if 0 && defined ALIGN_POINTER_TO32 + int align_adjust = ALIGN_POINTER_TO32 (ptr); + int len2; + + len -= align_adjust; + while (align_adjust) { + *ptr ^= val; + ptr++; + align_adjust--; + } + len2 = len >> 2; + len -= len2 << 2; + for (i = 0; i < len2; i++, ptr += 4) { + *(uae_u32 *) ptr ^= val; + } + while (len) { + *ptr ^= val; + ptr++; + len--; + } + return; +#endif + for (i = 0; i < len; i++, ptr++) { + do_put_mem_byte (ptr, do_get_mem_byte (ptr) ^ val); + } +} + +/* + * InvertRect: + * + * Inputs: + * a0:struct BoardInfo *bi + * a1:struct RenderInfo *ri + * d0.w:X + * d1.w:Y + * d2.w:Width + * d3.w:Height + * d4.l:Mask + * d7.l:RGBFormat + * + * This function is used to invert a rectangular area on the board. It is called by BltBitMap, + * BltPattern and BltTemplate. + */ +uae_u32 picasso_InvertRect (void) +{ + uaecptr renderinfo = m68k_areg (regs, 1); + unsigned long X = (uae_u16)m68k_dreg (regs, 0); + unsigned long Y = (uae_u16)m68k_dreg (regs, 1); + unsigned long Width = (uae_u16)m68k_dreg (regs, 2); + unsigned long Height = (uae_u16)m68k_dreg (regs, 3); + uae_u8 mask = (uae_u8)m68k_dreg (regs, 4); + int Bpp = GetBytesPerPixel (m68k_dreg (regs, 7)); + uae_u32 xorval; + unsigned int lines; + struct RenderInfo ri; + uae_u8 *uae_mem, *rectstart; + unsigned long width_in_bytes; + uae_u32 result = 0; + + wgfx_flushline (); + + if (CopyRenderInfoStructureA2U (renderinfo, &ri)) { + P96TRACE(("InvertRect %dbpp 0x%lx\n", Bpp, (long)mask)); + + if (mask != 0xFF && Bpp > 1) + mask = 0xFF; + + xorval = 0x01010101 * (mask & 0xFF); + width_in_bytes = Bpp * Width; + rectstart = uae_mem = ri.Memory + Y*ri.BytesPerRow + X*Bpp; + + for (lines = 0; lines < Height; lines++, uae_mem += ri.BytesPerRow) + do_xor8 (uae_mem, width_in_bytes, xorval); + + if (renderinfo_is_current_screen (&ri)) { + if (mask == 0xFF) + do_invertrect (&ri, Bpp, X, Y, Width, Height); + else + do_blit( &ri, Bpp, X, Y, X, Y, Width, Height, BLIT_SRC, 0); + } + result = 1; + } + return result; +} + +/* +* Fill a rectangle in the screen. +*/ +STATIC_INLINE void do_fillrect_frame_buffer (struct RenderInfo *ri, int X, int Y, int Width, int Height, uae_u32 Pen, int Bpp, RGBFTYPE RGBFormat) +{ + int cols; + uae_u8 *start, *oldstart; + uae_u8 *src, *dst; + int lines; + + /* Do our virtual frame-buffer memory. First, we do a single line fill by hand */ + oldstart = start = src = ri->Memory + X * Bpp + Y * ri->BytesPerRow; + + switch (Bpp) { + case 1: + memset (start, Pen, Width); + break; + case 2: + for (cols = 0; cols < Width; cols++) { + do_put_mem_word ((uae_u16 *)start, (uae_u16)Pen); + start += 2; + } + break; + case 3: + for (cols = 0; cols < Width; cols++) { + do_put_mem_byte (start, (uae_u8)Pen); + start++; + *(uae_u16 *)(start) = (Pen & 0x00FFFF00) >> 8; + start+=2; + } + break; + case 4: + for (cols = 0; cols < Width; cols++) { + do_put_mem_long ((uae_u32 *)start, Pen); + start += 4; + } + break; + } /* switch (Bpp) */ + + src = oldstart; + dst = src + ri->BytesPerRow; + + /* next, we do the remaining line fills via memcpy() for > 1 BPP, otherwise some more memset() calls */ + if (Bpp > 1) { + for (lines = 0; lines < (Height - 1); lines++, dst += ri->BytesPerRow) + memcpy (dst, src, Width * Bpp); + } else { + for (lines = 0; lines < (Height - 1); lines++, dst += ri->BytesPerRow) + memset( dst, Pen, Width ); + } +} + +/*********************************************************** +FillRect: +*********************************************************** +* a0: struct BoardInfo * +* a1: struct RenderInfo * +* d0: WORD X +* d1: WORD Y +* d2: WORD Width +* d3: WORD Height +* d4: uae_u32 Pen +* d5: UBYTE Mask +* d7: uae_u32 RGBFormat +***********************************************************/ +uae_u32 picasso_FillRect (void) +{ + uaecptr renderinfo = m68k_areg (regs, 1); + uae_u32 X = (uae_u16)m68k_dreg (regs, 0); + uae_u32 Y = (uae_u16)m68k_dreg (regs, 1); + uae_u32 Width = (uae_u16)m68k_dreg (regs, 2); + uae_u32 Height = (uae_u16)m68k_dreg (regs, 3); + uae_u32 Pen = m68k_dreg (regs, 4); + uae_u8 Mask = (uae_u8)m68k_dreg (regs, 5); + RGBFTYPE RGBFormat = m68k_dreg (regs, 7); + + uae_u8 *src; + uae_u8 *oldstart; + int Bpp; + struct RenderInfo ri; + uae_u32 result = 0; + +#ifdef JIT + special_mem|=picasso_is_special_read|picasso_is_special; +#endif + + wgfx_flushline (); + + if (CopyRenderInfoStructureA2U (renderinfo, &ri) && Y != 0xFFFF) { + if (ri.RGBFormat != RGBFormat) + write_log ("Weird Stuff!\n"); + + Bpp = GetBytesPerPixel (RGBFormat); + + P96TRACE(("FillRect(%d, %d, %d, %d) Pen 0x%x BPP %d BPR %d Mask 0x%x\n", + X, Y, Width, Height, Pen, Bpp, ri.BytesPerRow, Mask)); + + if (Bpp > 1) + Mask = 0xFF; + + if (Mask == 0xFF) { + if ((Width == 1) || (Height == 1)) { + int i; + uaecptr addr; + if (renderinfo_is_current_screen (&ri)) { + uae_u32 diff = gfxmem_start - (uae_u32)gfxmemory; + addr = ri.Memory + X * Bpp + Y * ri.BytesPerRow + diff; + + if (Width == 1) { + for (i = 0; i < Height; i++) { + if( Bpp == 4 ) + gfxmem_lput (addr + (i * picasso96_state.BytesPerRow), Pen); + else if (Bpp == 2) + gfxmem_wput (addr + (i * picasso96_state.BytesPerRow), Pen); + else + gfxmem_bput (addr + (i * picasso96_state.BytesPerRow), Pen); + } + } else if (Height == 1) { + for (i = 0; i < Width; i++) { + if (Bpp == 4) + gfxmem_lput (addr + (i*Bpp), Pen); + else if (Bpp == 2) + gfxmem_wput (addr + (i*Bpp), Pen); + else + gfxmem_bput( addr + (i*Bpp), Pen ); + } + } + return 1; + } + } + + /* Do the fill-rect in the frame-buffer */ + do_fillrect_frame_buffer (&ri, X, Y, Width, Height, Pen, Bpp, RGBFormat); + + /* Now we do the on-screen display, if renderinfo points to it */ + if (renderinfo_is_current_screen (&ri)) { + src = ri.Memory + X * Bpp + Y * ri.BytesPerRow; + X = X - picasso96_state.XOffset; + Y = Y - picasso96_state.YOffset; + if ((int)X < 0) {Width = Width + X; X=0;} + if ((int)Width < 1) return 1; + if ((int)Y < 0) {Height = Height + Y; Y=0;} + if ((int)Height < 1) return 1; + + /* Argh - why does P96Speed do this to me, with FillRect only?! */ + if ((X < picasso96_state.Width) && (Y < picasso96_state.Height)) { + if (X + Width > picasso96_state.Width) + Width = picasso96_state.Width - X; + if (Y+Height > picasso96_state.Height) + Height = picasso96_state.Height - Y; + + do_fillrect (src, X, Y, Width, Height, Pen, Bpp, RGBFormat); + } + } + result = 1; + } else { + /* We get here only if Mask != 0xFF */ + if (Bpp != 1) { + write_log( "WARNING - FillRect() has unhandled mask 0x%x with Bpp %d. Using fall-back routine.\n", Mask, Bpp); + } else { + Pen &= Mask; + Mask = ~Mask; + oldstart = ri.Memory + Y * ri.BytesPerRow + X * Bpp; + { + uae_u8 *start = oldstart; + uae_u8 *end = start + Height * ri.BytesPerRow; + for (; start != end; start += ri.BytesPerRow) { + uae_u8 *p = start; + unsigned long cols; + for (cols = 0; cols < Width; cols++) { + uae_u32 tmpval = do_get_mem_byte (p + cols) & Mask; + do_put_mem_byte (p + cols, (uae_u8)(Pen | tmpval)); + } + } + } + if (renderinfo_is_current_screen (&ri)) + do_blit( &ri, Bpp, X, Y, X, Y, Width, Height, BLIT_SRC, 0); + result = 1; + } + } + } + return result; +} + + +/* +* BlitRect() is a generic (any chunky pixel format) rectangle copier +* NOTE: If dstri is NULL, then we're only dealing with one RenderInfo area, and called from picasso_BlitRect() +* +* OpCodes: +* 0 = FALSE: dst = 0 +* 1 = NOR: dst = ~(src | dst) +* 2 = ONLYDST: dst = dst & ~src +* 3 = NOTSRC: dst = ~src +* 4 = ONLYSRC: dst = src & ~dst +* 5 = NOTDST: dst = ~dst +* 6 = EOR: dst = src^dst +* 7 = NAND: dst = ~(src & dst) +* 8 = AND: dst = (src & dst) +* 9 = NEOR: dst = ~(src ^ dst) +*10 = DST: dst = dst +*11 = NOTONLYSRC: dst = ~src | dst +*12 = SRC: dst = src +*13 = NOTONLYDST: dst = ~dst | src +*14 = OR: dst = src | dst +*15 = TRUE: dst = 0xFF +*/ +struct blitdata +{ + struct RenderInfo ri_struct; + struct RenderInfo dstri_struct; + struct RenderInfo *ri; /* Self-referencing pointers */ + struct RenderInfo *dstri; + unsigned long srcx; + unsigned long srcy; + unsigned long dstx; + unsigned long dsty; + unsigned long width; + unsigned long height; + uae_u8 mask; + BLIT_OPCODE opcode; +} blitrectdata; + +STATIC_INLINE int BlitRectHelper( void ) +{ + struct RenderInfo *ri = blitrectdata.ri; + struct RenderInfo *dstri = blitrectdata.dstri; + unsigned long srcx = blitrectdata.srcx; + unsigned long srcy = blitrectdata.srcy; + unsigned long dstx = blitrectdata.dstx; + unsigned long dsty = blitrectdata.dsty; + unsigned long width = blitrectdata.width; + unsigned long height = blitrectdata.height; + uae_u8 mask = blitrectdata.mask; + BLIT_OPCODE opcode = blitrectdata.opcode; + + uae_u8 Bpp = GetBytesPerPixel (ri->RGBFormat); + unsigned long total_width = width * Bpp; + unsigned long linewidth = (total_width + 15) & ~15; + int can_do_visible_blit = 0; + + if (opcode == BLIT_DST) { + write_log( "WARNING: BlitRect() being called with opcode of BLIT_DST\n" ); + return 1; + } + + /* + * If we have no destination RenderInfo, then we're dealing with a single-buffer action, called + * from picasso_BlitRect(). The code in do_blitrect_frame_buffer() deals with the frame-buffer, + * while the do_blit() code deals with the visible screen. + * + * If we have a destination RenderInfo, then we've been called from picasso_BlitRectNoMaskComplete() + * and we need to put the results on the screen from the frame-buffer. + */ + if (dstri == NULL) { + if (mask != 0xFF && Bpp > 1) { + mask = 0xFF; + } + dstri = ri; + can_do_visible_blit = 1; + } + + /* Do our virtual frame-buffer memory first */ + do_blitrect_frame_buffer (ri, dstri, srcx, srcy, dstx, dsty, width, height, mask, opcode); + + /* Now we do the on-screen display, if renderinfo points to it */ + if (renderinfo_is_current_screen (dstri)) { + if (mask == 0xFF || Bpp > 1) { + if (can_do_visible_blit) + do_blit (dstri, Bpp, srcx, srcy, dstx, dsty, width, height, opcode, 1); + else + do_blit (dstri, Bpp, dstx, dsty, dstx, dsty, width, height, opcode, 0); + } else + do_blit (dstri, Bpp, dstx, dsty, dstx, dsty, width, height, opcode, 0); + + P96TRACE(("Did do_blit 1 in BlitRect()\n")); + } else { + P96TRACE(("Did not do_blit 1 in BlitRect()\n")); + } + + return 1; +} + +STATIC_INLINE int BlitRect (uaecptr ri, uaecptr dstri, + unsigned long srcx, unsigned long srcy, unsigned long dstx, unsigned long dsty, + unsigned long width, unsigned long height, uae_u8 mask, BLIT_OPCODE opcode ) +{ + /* Set up the params */ + CopyRenderInfoStructureA2U( ri, &blitrectdata.ri_struct ); + blitrectdata.ri = &blitrectdata.ri_struct; + + if (dstri) { + CopyRenderInfoStructureA2U( dstri, &blitrectdata.dstri_struct ); + blitrectdata.dstri = &blitrectdata.dstri_struct; + } else + blitrectdata.dstri = NULL; + + blitrectdata.srcx = srcx; + blitrectdata.srcy = srcy; + blitrectdata.dstx = dstx; + blitrectdata.dsty = dsty; + blitrectdata.width = width; + blitrectdata.height = height; + blitrectdata.mask = mask; + blitrectdata.opcode = opcode; + + return BlitRectHelper(); +} + +/*********************************************************** +BlitRect: +*********************************************************** +* a0: struct BoardInfo +* a1: struct RenderInfo +* d0: WORD SrcX +* d1: WORD SrcY +* d2: WORD DstX +* d3: WORD DstY +* d4: WORD Width +* d5: WORD Height +* d6: UBYTE Mask +* d7: uae_u32 RGBFormat +***********************************************************/ +uae_u32 picasso_BlitRect (void) +{ + uaecptr renderinfo = m68k_areg (regs, 1); + unsigned long srcx = (uae_u16)m68k_dreg (regs, 0); + unsigned long srcy = (uae_u16)m68k_dreg (regs, 1); + unsigned long dstx = (uae_u16)m68k_dreg (regs, 2); + unsigned long dsty = (uae_u16)m68k_dreg (regs, 3); + unsigned long width = (uae_u16)m68k_dreg (regs, 4); + unsigned long height = (uae_u16)m68k_dreg (regs, 5); + uae_u8 Mask = (uae_u8) m68k_dreg (regs, 6); + uae_u32 result = 0; + +#ifdef JIT + special_mem|=picasso_is_special_read|picasso_is_special; +#endif + + wgfx_flushline (); + + P96TRACE(("BlitRect(%d, %d, %d, %d, %d, %d, 0x%x)\n", srcx, srcy, dstx, dsty, width, height, Mask)); + result = BlitRect (renderinfo, (uaecptr)NULL, srcx, srcy, dstx, dsty, width, height, Mask, BLIT_SRC); + + return result; +} + +/*********************************************************** +BlitRectNoMaskComplete: +*********************************************************** +* a0: struct BoardInfo +* a1: struct RenderInfo (src) +* a2: struct RenderInfo (dst) +* d0: WORD SrcX +* d1: WORD SrcY +* d2: WORD DstX +* d3: WORD DstY +* d4: WORD Width +* d5: WORD Height +* d6: UBYTE OpCode +* d7: uae_u32 RGBFormat +* NOTE: MUST return 0 in D0 if we're not handling this operation +* because the RGBFormat or opcode aren't supported. +* OTHERWISE return 1 +***********************************************************/ +uae_u32 picasso_BlitRectNoMaskComplete (void) +{ + uaecptr srcri = m68k_areg (regs, 1); + uaecptr dstri = m68k_areg (regs, 2); + unsigned long srcx = (uae_u16)m68k_dreg (regs, 0); + unsigned long srcy = (uae_u16)m68k_dreg (regs, 1); + unsigned long dstx = (uae_u16)m68k_dreg (regs, 2); + unsigned long dsty = (uae_u16)m68k_dreg (regs, 3); + unsigned long width = (uae_u16)m68k_dreg (regs, 4); + unsigned long height = (uae_u16)m68k_dreg (regs, 5); + uae_u8 OpCode = m68k_dreg (regs, 6); + uae_u32 RGBFmt = m68k_dreg (regs, 7); + uae_u32 result = 0; + +#ifdef JIT + special_mem|=picasso_is_special_read|picasso_is_special; +#endif + + wgfx_flushline (); + + P96TRACE(("BlitRectNoMaskComplete() op 0x%2x, xy(%4d,%4d) --> xy(%4d,%4d), wh(%4d,%4d)\n", + OpCode, srcx, srcy, dstx, dsty, width, height)); + + result = BlitRect (srcri, dstri, srcx, srcy, dstx, dsty, width, height, 0xFF, OpCode); + + return result; +} + +/* This utility function is used both by BlitTemplate() and BlitPattern() */ +STATIC_INLINE void PixelWrite1 (uae_u8 * mem, int bits, uae_u32 fgpen, uae_u32 mask) +{ + if (mask != 0xFF) + fgpen = (fgpen & mask) | (do_get_mem_byte (mem + bits) & ~mask); + do_put_mem_byte (mem + bits, fgpen); +} + +STATIC_INLINE void PixelWrite2 (uae_u8 * mem, int bits, uae_u32 fgpen) +{ + do_put_mem_word (((uae_u16 *) mem) + bits, fgpen); +} + +STATIC_INLINE void PixelWrite3 (uae_u8 * mem, int bits, uae_u32 fgpen) +{ + do_put_mem_byte (mem + bits * 3, fgpen & 0x000000FF); + *(uae_u16 *) (mem + bits * 3 + 1) = (fgpen & 0x00FFFF00) >> 8; +} + +STATIC_INLINE void PixelWrite4 (uae_u8 * mem, int bits, uae_u32 fgpen) +{ + do_put_mem_long (((uae_u32 *) mem) + bits, fgpen); +} + +STATIC_INLINE void PixelWrite (uae_u8 * mem, int bits, uae_u32 fgpen, uae_u8 Bpp, uae_u32 mask) +{ + switch (Bpp) { + case 1: + if (mask != 0xFF) + fgpen = (fgpen & mask) | (do_get_mem_byte (mem + bits) & ~mask); + do_put_mem_byte (mem + bits, fgpen); + break; + case 2: + do_put_mem_word (((uae_u16 *) mem) + bits, fgpen); + break; + case 3: + do_put_mem_byte (mem + bits * 3, fgpen & 0x000000FF); + *(uae_u16 *) (mem + bits * 3 + 1) = (fgpen & 0x00FFFF00) >> 8; + break; + case 4: + do_put_mem_long (((uae_u32 *) mem) + bits, fgpen); + break; + } +} + +/* + * BlitPattern: + * + * Synopsis:BlitPattern(bi, ri, pattern, X, Y, Width, Height, Mask, RGBFormat); + * Inputs: + * a0:struct BoardInfo *bi + * a1:struct RenderInfo *ri + * a2:struct Pattern *pattern + * d0.w:X + * d1.w:Y + * d2.w:Width + * d3.w:Height + * d4.w:Mask + * d7.l:RGBFormat + * + * This function is used to paint a pattern on the board memory using the blitter. It is called by + * BltPattern, if a AreaPtrn is used with positive AreaPtSz. The pattern consists of a b/w image + * using a single plane of image data which will be expanded repeatedly to the destination RGBFormat + * using ForeGround and BackGround pens as well as draw modes. The width of the pattern data is + * always 16 pixels (one word) and the height is calculated as 2^Size. The data must be shifted up + * and to the left by XOffset and YOffset pixels at the beginning. + */ +uae_u32 picasso_BlitPattern (void) +{ + uaecptr rinf = m68k_areg (regs, 1); + uaecptr pinf = m68k_areg (regs, 2); + unsigned long X = (uae_u16)m68k_dreg (regs, 0); + unsigned long Y = (uae_u16)m68k_dreg (regs, 1); + unsigned long W = (uae_u16)m68k_dreg (regs, 2); + unsigned long H = (uae_u16)m68k_dreg (regs, 3); + uae_u8 Mask = (uae_u8) m68k_dreg (regs, 4); + uae_u32 RGBFmt = m68k_dreg (regs, 7); + uae_u8 Bpp = GetBytesPerPixel (RGBFmt); + int inversion = 0; + struct RenderInfo ri; + struct Pattern pattern; + unsigned long rows; + uae_u32 fgpen; + uae_u8 *uae_mem; + int xshift; + unsigned long ysize_mask; + uae_u32 result = 0; + +#ifdef JIT + special_mem|=picasso_is_special_read|picasso_is_special; +#endif + + wgfx_flushline (); + + if (CopyRenderInfoStructureA2U (rinf, &ri) && CopyPatternStructureA2U (pinf, &pattern)) { + Bpp = GetBytesPerPixel (ri.RGBFormat); + uae_mem = ri.Memory + Y*ri.BytesPerRow + X*Bpp; /* offset with address */ + + if (pattern.DrawMode & INVERS) + inversion = 1; + + pattern.DrawMode &= 0x03; + + if (Mask != 0xFF) { + if( Bpp > 1 ) + Mask = 0xFF; + + if( pattern.DrawMode == COMP) + write_log ("WARNING - BlitPattern() has unhandled mask 0x%x with COMP DrawMode. Using fall-back routine.\n", Mask); + else + result = 1; + } else + result = 1; + + if (result) { +# ifdef P96TRACING_ENABLED + DumpPattern(&pattern); +# endif + ysize_mask = (1 << pattern.Size) - 1; + xshift = pattern.XOffset & 15; + + for (rows = 0; rows < H; rows++, uae_mem += ri.BytesPerRow) { + unsigned long prow = (rows + pattern.YOffset) & ysize_mask; + unsigned int d = do_get_mem_word (((uae_u16 *)pattern.Memory) + prow); + uae_u8 *uae_mem2 = uae_mem; + unsigned long cols; + + if (xshift != 0) + d = (d << xshift) | (d >> (16 - xshift)); + + for (cols = 0; cols < W; cols += 16, uae_mem2 += Bpp << 4) { + long bits; + long max = W - cols; + unsigned int data = d; + + if (max > 16) + max = 16; + + for (bits = 0; bits < max; bits++) { + int bit_set = data & 0x8000; + data <<= 1; + switch (pattern.DrawMode) { + case JAM1: + if (inversion) + bit_set = !bit_set; + if (bit_set) + PixelWrite (uae_mem2, bits, pattern.FgPen, Bpp, Mask); + break; + case JAM2: + if (inversion) + bit_set = !bit_set; + if (bit_set) + PixelWrite (uae_mem2, bits, pattern.FgPen, Bpp, Mask); + else + PixelWrite (uae_mem2, bits, pattern.BgPen, Bpp, Mask); + break; + case COMP: + if (bit_set) { + fgpen = pattern.FgPen; + + switch (Bpp) { + case 1: + { + uae_u8 *addr = uae_mem2 + bits; + do_put_mem_byte (addr, (uae_u8)(do_get_mem_byte (addr) ^ fgpen)); + } + break; + case 2: + { + uae_u16 *addr = ((uae_u16 *)uae_mem2) + bits; + do_put_mem_word (addr, (uae_u16)(do_get_mem_word (addr) ^ fgpen)); + } + break; + case 3: + { + uae_u32 *addr = (uae_u32 *)(uae_mem2 + bits * 3); + do_put_mem_long (addr, do_get_mem_long (addr) ^ (fgpen & 0x00FFFFFF)); + } + break; + case 4: + { + uae_u32 *addr = ((uae_u32 *)uae_mem2) + bits; + do_put_mem_long (addr, do_get_mem_long (addr) ^ fgpen); + } + break; + } /* switch (Bpp) */ + } + break; + } /* switch (pattern.DrawMode) */ + } /* for (bits) */ + } /* for (cols) */ + } /* for (rows) */ + + /* If we need to update a second-buffer (extra_mem is set), then do it only if visible! */ + if (picasso_vidinfo.extra_mem && renderinfo_is_current_screen (&ri)) + do_blit( &ri, Bpp, X, Y, X, Y, W, H, BLIT_SRC, 0); + + result = 1; + } + } + return result; +} + +/************************************************* +BlitTemplate: +************************************************** +* Synopsis: BlitTemplate(bi, ri, template, X, Y, Width, Height, Mask, RGBFormat); +* a0: struct BoardInfo *bi +* a1: struct RenderInfo *ri +* a2: struct Template *template +* d0.w: X +* d1.w: Y +* d2.w: Width +* d3.w: Height +* d4.w: Mask +* d7.l: RGBFormat +* +* This function is used to paint a template on the board memory using the blitter. +* It is called by BltPattern and BltTemplate. The template consists of a b/w image +* using a single plane of image data which will be expanded to the destination RGBFormat +* using ForeGround and BackGround pens as well as draw modes. +***********************************************************************************/ +uae_u32 picasso_BlitTemplate (void) +{ + uae_u8 inversion = 0; + uaecptr rinf = m68k_areg (regs, 1); + uaecptr tmpl = m68k_areg (regs, 2); + unsigned long X = (uae_u16)m68k_dreg (regs, 0); + unsigned long Y = (uae_u16)m68k_dreg (regs, 1); + unsigned long W = (uae_u16)m68k_dreg (regs, 2); + unsigned long H = (uae_u16)m68k_dreg (regs, 3); + uae_u16 Mask = (uae_u16)m68k_dreg (regs, 4); + struct Template tmp; + struct RenderInfo ri; + unsigned long rows; + int bitoffset; + uae_u32 fgpen; + uae_u8 *uae_mem, Bpp; + uae_u8 *tmpl_base; + uae_u32 result = 0; + +#ifdef JIT + special_mem|=picasso_is_special_read|picasso_is_special; +#endif + + wgfx_flushline (); + + if (CopyRenderInfoStructureA2U (rinf, &ri) && CopyTemplateStructureA2U (tmpl, &tmp)) { + Bpp = GetBytesPerPixel (ri.RGBFormat); + uae_mem = ri.Memory + Y*ri.BytesPerRow + X*Bpp; /* offset into address */ + + if (tmp.DrawMode & INVERS) + inversion = 1; + + tmp.DrawMode &= 0x03; + + if (Mask != 0xFF) { + if (Bpp > 1) + Mask = 0xFF; + + if (tmp.DrawMode == COMP) { + write_log ("WARNING - BlitTemplate() has unhandled mask 0x%x with COMP DrawMode. Using fall-back routine.\n", Mask); +# ifdef _WIN32 + flushpixels(); //only need in the windows Version +# endif + return 0; + } else + result = 1; + } else + result = 1; + +#if 1 + if (tmp.DrawMode == COMP) { + /* workaround, let native blitter handle COMP mode */ +# ifdef _WIN32 + flushpixels(); +# endif + return 0; + } +#endif + + if (result) { + P96TRACE (("BlitTemplate() xy(%d,%d), wh(%d,%d) draw 0x%x fg 0x%x bg 0x%x \n", + X, Y, W, H, tmp.DrawMode, tmp.FgPen, tmp.BgPen)); + + bitoffset = tmp.XOffset % 8; + +# if defined( P96TRACING_ENABLED ) && ( P96TRACING_LEVEL > 0 ) + DumpTemplate(&tmp, W, H); +# endif + + tmpl_base = tmp.Memory + tmp.XOffset / 8; + + for (rows = 0; rows < H; rows++, uae_mem += ri.BytesPerRow, tmpl_base += tmp.BytesPerRow) { + unsigned long cols; + uae_u8 *tmpl_mem = tmpl_base; + uae_u8 *uae_mem2 = uae_mem; + unsigned int data = *tmpl_mem; + + for (cols = 0; cols < W; cols += 8, uae_mem2 += Bpp << 3) { + unsigned int byte; + long bits; + long max = W - cols; + + if (max > 8) + max = 8; + + data <<= 8; + data |= *++tmpl_mem; + + byte = data >> (8 - bitoffset); + + for (bits = 0; bits < max; bits++) { + int bit_set = (byte & 0x80); + byte <<= 1; + switch (tmp.DrawMode) { + case JAM1: + if (inversion) + bit_set = !bit_set; + if (bit_set) { + fgpen = tmp.FgPen; + PixelWrite (uae_mem2, bits, fgpen, Bpp, Mask); + } + break; + case JAM2: + if (inversion) + bit_set = !bit_set; + fgpen = tmp.BgPen; + if (bit_set) + fgpen = tmp.FgPen; + PixelWrite (uae_mem2, bits, fgpen, Bpp, Mask); + break; + case COMP: + if (bit_set) { + fgpen = tmp.FgPen; + + switch (Bpp) { + case 1: + { + uae_u8 *addr = uae_mem2 + bits; + do_put_mem_byte (addr, (uae_u8) (do_get_mem_byte (addr) ^ fgpen)); + } + break; + case 2: + { + uae_u16 *addr = ((uae_u16 *)uae_mem2) + bits; + do_put_mem_word (addr, (uae_u16) (do_get_mem_word (addr) ^ fgpen)); + } + break; + case 3: + { + uae_u32 *addr = (uae_u32 *)(uae_mem2 + bits * 3); + do_put_mem_long (addr, do_get_mem_long (addr) ^ (fgpen & 0x00FFFFFF)); + } + break; + case 4: + { + uae_u32 *addr = ((uae_u32 *)uae_mem2) + bits; + do_put_mem_long (addr, do_get_mem_long (addr) ^ fgpen); + } + break; + } /* switch (Bpp) */ + } /* if (bit_set) */ + break; + } /* switch (tmp.DrawMode) */ + } /* for (bits) */ + } /* for (cols) */ + } /* for (rows) */ + + /* If we need to update a second-buffer (extra_mem is set), then do it only if visible! */ + if (picasso_vidinfo.extra_mem && renderinfo_is_current_screen (&ri)) + do_blit (&ri, Bpp, X, Y, X, Y, W, H, BLIT_SRC, 0); + } + } + return 1; +} + +/* + * CalculateBytesPerRow: + * a0: struct BoardInfo + * d0: uae_u16 Width + * d7: RGBFTYPE RGBFormat + * This function calculates the amount of bytes needed for a line of + * "Width" pixels in the given RGBFormat. + */ +uae_u32 picasso_CalculateBytesPerRow (void) +{ + uae_u16 width = m68k_dreg (regs, 0); + uae_u32 type = m68k_dreg (regs, 7); + + width = GetBytesPerPixel (type) * width; + P96TRACE (("CalculateBytesPerRow() = %d\n", width)); + + return width; +} + +/* + * SetDisplay: + * a0: struct BoardInfo + * d0: BOOL state + * This function enables and disables the video display. + * + * NOTE: return the opposite of the state + */ +uae_u32 picasso_SetDisplay (void) +{ + uae_u32 state = m68k_dreg (regs, 0); + P96TRACE (("SetDisplay(%d)\n", state)); + return !state; +} + +/* + * WaitVerticalSync: + * a0: struct BoardInfo + * This function waits for the next horizontal retrace. + */ +uae_u32 picasso_WaitVerticalSync (void) +{ + /*write_log ("WaitVerticalSync()\n"); */ + return 1; +} + +/* NOTE: Watch for those planeptrs of 0x00000000 and 0xFFFFFFFF for all zero / all one bitmaps !!!! */ +static void PlanarToChunky (struct RenderInfo *ri, struct BitMap *bm, + unsigned long srcx, unsigned long srcy, + unsigned long dstx, unsigned long dsty, unsigned long width, unsigned long height, uae_u8 mask) +{ + int j; + + uae_u8 *PLANAR[8], *image = ri->Memory + dstx * GetBytesPerPixel (ri->RGBFormat) + dsty * ri->BytesPerRow; + int Depth = bm->Depth; + unsigned long rows, bitoffset = srcx & 7; + long eol_offset; + + /* if (mask != 0xFF) + write_log ("P2C - pixel-width = %d, bit-offset = %d\n", width, bitoffset); */ + + /* Set up our bm->Planes[] pointers to the right horizontal offset */ + for (j = 0; j < Depth; j++) { + uae_u8 *p = bm->Planes[j]; + if (p != &all_zeros_bitmap && p != &all_ones_bitmap) + p += srcx / 8 + srcy * bm->BytesPerRow; + PLANAR[j] = p; + if ((mask & (1 << j)) == 0) + PLANAR[j] = &all_zeros_bitmap; + } + eol_offset = (long) bm->BytesPerRow - (long) ((width + 7) >> 3); + for (rows = 0; rows < height; rows++, image += ri->BytesPerRow) { + unsigned long cols; + + for (cols = 0; cols < width; cols += 8) { + int k; + uae_u32 a = 0, b = 0; + unsigned int msk = 0xFF; + long tmp = cols + 8 - width; + if (tmp > 0) { + msk <<= tmp; + b = do_get_mem_long ((uae_u32 *) (image + cols + 4)); + if (tmp < 4) + b &= 0xFFFFFFFF >> (32 - tmp * 8); + else if (tmp > 4) { + a = do_get_mem_long ((uae_u32 *) (image + cols)); + a &= 0xFFFFFFFF >> (64 - tmp * 8); + } + } + for (k = 0; k < Depth; k++) { + unsigned int data; + if (PLANAR[k] == &all_zeros_bitmap) + data = 0; + else if (PLANAR[k] == &all_ones_bitmap) + data = 0xFF; + else { + data = (uae_u8) (do_get_mem_word ((uae_u16 *) PLANAR[k]) >> (8 - bitoffset)); + PLANAR[k]++; + } + data &= msk; + a |= p2ctab[data][0] << k; + b |= p2ctab[data][1] << k; + } + do_put_mem_long ((uae_u32 *) (image + cols), a); + do_put_mem_long ((uae_u32 *) (image + cols + 4), b); + } + for (j = 0; j < Depth; j++) { + if (PLANAR[j] != &all_zeros_bitmap && PLANAR[j] != &all_ones_bitmap) { + PLANAR[j] += eol_offset; + } + } + } +} + +/* + * BlitPlanar2Chunky: + * a0: struct BoardInfo *bi + * a1: struct BitMap *bm - source containing planar information and assorted details + * a2: struct RenderInfo *ri - dest area and its details + * d0.w: SrcX + * d1.w: SrcY + * d2.w: DstX + * d3.w: DstY + * d4.w: SizeX + * d5.w: SizeY + * d6.b: MinTerm - uh oh! + * d7.b: Mask - uh oh! + * + * This function is currently used to blit from planar bitmaps within system memory to chunky bitmaps + * on the board. Watch out for plane pointers that are 0x00000000 (represents a plane with all bits "0") + * or 0xffffffff (represents a plane with all bits "1"). + */ +uae_u32 picasso_BlitPlanar2Chunky (void) +{ + uaecptr bm = m68k_areg (regs, 1); + uaecptr ri = m68k_areg (regs, 2); + unsigned long srcx = (uae_u16) m68k_dreg (regs, 0); + unsigned long srcy = (uae_u16) m68k_dreg (regs, 1); + unsigned long dstx = (uae_u16) m68k_dreg (regs, 2); + unsigned long dsty = (uae_u16) m68k_dreg (regs, 3); + unsigned long width = (uae_u16) m68k_dreg (regs, 4); + unsigned long height = (uae_u16) m68k_dreg (regs, 5); + uae_u8 minterm = m68k_dreg (regs, 6) & 0xFF; + uae_u8 mask = m68k_dreg (regs, 7) & 0xFF; + struct RenderInfo local_ri; + struct BitMap local_bm; + + wgfx_flushline (); + + if (minterm != 0x0C) { + write_log ("ERROR - BlitPlanar2Chunky() has minterm 0x%x, which I don't handle. Using fall-back routine.\n", minterm); + return 0; + } + if (!CopyRenderInfoStructureA2U (ri, &local_ri) + || !CopyBitMapStructureA2U (bm, &local_bm)) + return 0; + + P96TRACE (("BlitPlanar2Chunky(%d, %d, %d, %d, %d, %d) Minterm 0x%x, Mask 0x%x, Depth %d\n", + srcx, srcy, dstx, dsty, width, height, minterm, mask, local_bm.Depth)); + P96TRACE (("P2C - BitMap has %d BPR, %d rows\n", local_bm.BytesPerRow, local_bm.Rows)); + PlanarToChunky (&local_ri, &local_bm, srcx, srcy, dstx, dsty, width, height, mask); + if (renderinfo_is_current_screen (&local_ri)) + do_blit (&local_ri, GetBytesPerPixel (local_ri.RGBFormat), dstx, dsty, dstx, dsty, width, height, BLIT_SRC, 0); + + return 1; +} + +static void PlanarToDirect (struct RenderInfo *ri, struct BitMap *bm, + unsigned long srcx, unsigned long srcy, + unsigned long dstx, unsigned long dsty, + unsigned long width, unsigned long height, uae_u8 mask, struct ColorIndexMapping *cim) +{ + int j; + int bpp = GetBytesPerPixel (ri->RGBFormat); + uae_u8 *PLANAR[8]; + uae_u8 *image = ri->Memory + dstx * bpp + dsty * ri->BytesPerRow; + int Depth = bm->Depth; + unsigned long rows; + long eol_offset; + + /* Set up our bm->Planes[] pointers to the right horizontal offset */ + for (j = 0; j < Depth; j++) { + uae_u8 *p = bm->Planes[j]; + if (p != &all_zeros_bitmap && p != &all_ones_bitmap) + p += srcx / 8 + srcy * bm->BytesPerRow; + PLANAR[j] = p; + if ((mask & (1 << j)) == 0) + PLANAR[j] = &all_zeros_bitmap; + } + + eol_offset = (long) bm->BytesPerRow - (long) ((width + (srcx & 7)) >> 3); + for (rows = 0; rows < height; rows++, image += ri->BytesPerRow) { + unsigned long cols; + uae_u8 *image2 = image; + unsigned int bitoffs = 7 - (srcx & 7); + int i; + + for (cols = 0; cols < width; cols++) { + int v = 0, k; + for (k = 0; k < Depth; k++) { + if (PLANAR[k] == &all_ones_bitmap) + v |= 1 << k; + else if (PLANAR[k] != &all_zeros_bitmap) { + v |= ((*PLANAR[k] >> bitoffs) & 1) << k; + } + } + + switch (bpp) { + case 2: + do_put_mem_word ((uae_u16 *) image2, cim->Colors[v]); + image2 += 2; + break; + case 3: + do_put_mem_byte (image2++, cim->Colors[v] & 0x000000FF); + do_put_mem_word ((uae_u16 *) image2, (cim->Colors[v] & 0x00FFFF00) >> 8); + image2 += 2; + break; + case 4: + do_put_mem_long ((uae_u32 *) image2, cim->Colors[v]); + image2 += 4; + break; + } + bitoffs--; + bitoffs &= 7; + if (bitoffs == 7) { + int k; + for (k = 0; k < Depth; k++) { + if (PLANAR[k] != &all_zeros_bitmap && PLANAR[k] != &all_ones_bitmap) { + PLANAR[k]++; + } + } + } + } + + for (i = 0; i < Depth; i++) { + if (PLANAR[i] != &all_zeros_bitmap && PLANAR[i] != &all_ones_bitmap) { + PLANAR[i] += eol_offset; + } + } + } +} + +/* + * BlitPlanar2Direct: + * + * Synopsis: + * BlitPlanar2Direct(bi, bm, ri, cim, SrcX, SrcY, DstX, DstY, SizeX, SizeY, MinTerm, Mask); + * Inputs: + * a0:struct BoardInfo *bi + * a1:struct BitMap *bm + * a2:struct RenderInfo *ri + * a3:struct ColorIndexMapping *cmi + * d0.w:SrcX + * d1.w:SrcY + * d2.w:DstX + * d3.w:DstY + * d4.w:SizeX + * d5.w:SizeY + * d6.b:MinTerm + * d7.b:Mask + * + * This function is currently used to blit from planar bitmaps within system memory to direct color + * bitmaps (15, 16, 24 or 32 bit) on the board. Watch out for plane pointers that are 0x00000000 (represents + * a plane with all bits "0") or 0xffffffff (represents a plane with all bits "1"). The ColorIndexMapping is + * used to map the color index of each pixel formed by the bits in the bitmap's planes to a direct color value + * which is written to the destination RenderInfo. The color mask and all colors within the mapping are words, + * triple bytes or longwords respectively similar to the color values used in FillRect(), BlitPattern() or + * BlitTemplate(). + */ + +uae_u32 picasso_BlitPlanar2Direct (void) +{ + uaecptr bm = m68k_areg (regs, 1); + uaecptr ri = m68k_areg (regs, 2); + uaecptr cim = m68k_areg (regs, 3); + unsigned long srcx = (uae_u16)m68k_dreg (regs, 0); + unsigned long srcy = (uae_u16)m68k_dreg (regs, 1); + unsigned long dstx = (uae_u16)m68k_dreg (regs, 2); + unsigned long dsty = (uae_u16)m68k_dreg (regs, 3); + unsigned long width = (uae_u16)m68k_dreg (regs, 4); + unsigned long height = (uae_u16)m68k_dreg (regs, 5); + uae_u8 minterm = m68k_dreg (regs, 6); + uae_u8 Mask = m68k_dreg (regs, 7); + struct RenderInfo local_ri; + struct BitMap local_bm; + struct ColorIndexMapping local_cim; + uae_u32 result = 0; + +#ifdef JIT + special_mem|=picasso_is_special_read|picasso_is_special; +#endif + + wgfx_flushline (); + + if (minterm != 0x0C) { + write_log ("WARNING - BlitPlanar2Direct() has unhandled op-code 0x%x. Using fall-back routine.\n", minterm); + } else if (CopyRenderInfoStructureA2U (ri, &local_ri) && CopyBitMapStructureA2U (bm, &local_bm)) { + Mask = 0xFF; + CopyColorIndexMappingA2U (cim, &local_cim); + + P96TRACE (("BlitPlanar2Direct(%d, %d, %d, %d, %d, %d) Minterm 0x%x, Mask 0x%x, Depth %d\n", + srcx, srcy, dstx, dsty, width, height, minterm, Mask, local_bm.Depth)); + + PlanarToDirect (&local_ri, &local_bm, srcx, srcy, dstx, dsty, width, height, Mask, &local_cim); + if (renderinfo_is_current_screen (&local_ri)) + do_blit( &local_ri, GetBytesPerPixel( local_ri.RGBFormat ), dstx, dsty, dstx, dsty, width, height, BLIT_SRC, 0); + result = 1; + } + return result; +} + + + +/* @@@ - Work to be done here! + * + * The address is the offset into our Picasso96 frame-buffer (pointed to by gfxmem_start) + * where the value was put. + * + * Porting work: on some machines you may not need these functions, ie. if the memory for the + * Picasso96 frame-buffer is directly viewable or directly blittable. On Win32 with DirectX, + * this is not the case. So I provide some write-through functions (as per Mathias' orders!) + */ +static void write_gfx_long (uaecptr addr, uae_u32 value) +{ + uaecptr oldaddr = addr; + int x, xbytes, y; + uae_u8 *dst; + + if (!picasso_on) + return; + + /* + * Several writes to successive memory locations are a common access pattern. + * Try to optimize it. + */ + if (addr >= wgfx_linestart && addr + 4 <= wgfx_lineend) { + if (addr < wgfx_min) + wgfx_min = addr; + if (addr + 4 > wgfx_max) + wgfx_max = addr + 4; + return; + } else + wgfx_flushline (); + + addr += gfxmem_start; + /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */ + /* Shouldn't the "+4" be on the *first* addr, rather than the second? + and be a "+3" at that? */ + if (addr < picasso96_state.Address || addr + 4 > picasso96_state.Extent) + return; + + addr -= picasso96_state.Address; + y = addr / picasso96_state.BytesPerRow; + + if (y >= picasso96_state.VirtualHeight) + return; + wgfx_linestart = picasso96_state.Address - gfxmem_start + y * picasso96_state.BytesPerRow; + wgfx_lineend = wgfx_linestart + picasso96_state.BytesPerRow; + wgfx_y = y; + wgfx_min = oldaddr; + wgfx_max = oldaddr + 4; +} + +static void write_gfx_word (uaecptr addr, uae_u16 value) +{ + uaecptr oldaddr = addr; + int x, xbytes, y; + uae_u8 *dst; + + if (!picasso_on) + return; + + /* + * Several writes to successive memory locations are a common access pattern. + * Try to optimize it. + */ + if (addr >= wgfx_linestart && addr + 2 <= wgfx_lineend) { + if (addr < wgfx_min) + wgfx_min = addr; + if (addr + 2 > wgfx_max) + wgfx_max = addr + 2; + return; + } else + wgfx_flushline (); + + addr += gfxmem_start; + /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */ + if (addr < picasso96_state.Address || addr + 2 > picasso96_state.Extent) + return; + + addr -= picasso96_state.Address; + y = addr / picasso96_state.BytesPerRow; + + if (y >= picasso96_state.VirtualHeight) + return; + wgfx_linestart = picasso96_state.Address - gfxmem_start + y * picasso96_state.BytesPerRow; + wgfx_lineend = wgfx_linestart + picasso96_state.BytesPerRow; + wgfx_y = y; + wgfx_min = oldaddr; + wgfx_max = oldaddr + 2; +} + +static void write_gfx_byte (uaecptr addr, uae_u8 value) +{ + uaecptr oldaddr = addr; + int x, xbytes, y; + uae_u8 *dst; + + if (!picasso_on) + return; + + /* + * Several writes to successive memory locations are a common access pattern. + * Try to optimize it. + */ + if (addr >= wgfx_linestart && addr + 4 <= wgfx_lineend) { + if (addr < wgfx_min) + wgfx_min = addr; + if (addr + 1 > wgfx_max) + wgfx_max = addr + 1; + return; + } else + wgfx_flushline (); + + addr += gfxmem_start; + /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */ + if (addr < picasso96_state.Address || addr + 1 > picasso96_state.Extent) + return; + + addr -= picasso96_state.Address; + y = addr / picasso96_state.BytesPerRow; + + if (y >= picasso96_state.VirtualHeight) + return; + wgfx_linestart = picasso96_state.Address - gfxmem_start + y * picasso96_state.BytesPerRow; + wgfx_lineend = wgfx_linestart + picasso96_state.BytesPerRow; + wgfx_y = y; + wgfx_min = oldaddr; + wgfx_max = oldaddr + 1; +} + +static uae_u32 REGPARAM2 gfxmem_lget (uaecptr addr) +{ + uae_u32 *m; + +#ifdef JIT + special_mem|=picasso_is_special_read; +#endif + addr -= gfxmem_start & gfxmem_mask; + addr &= gfxmem_mask; + m = (uae_u32 *) (gfxmemory + addr); + return do_get_mem_long (m); +} + +static uae_u32 REGPARAM2 gfxmem_wget (uaecptr addr) +{ + uae_u16 *m; + +#ifdef JIT + special_mem|=picasso_is_special_read; +#endif + addr -= gfxmem_start & gfxmem_mask; + addr &= gfxmem_mask; + m = (uae_u16 *) (gfxmemory + addr); + return do_get_mem_word (m); +} + +static uae_u32 REGPARAM2 gfxmem_bget (uaecptr addr) +{ +#ifdef JIT + special_mem|=picasso_is_special_read; +#endif + addr -= gfxmem_start & gfxmem_mask; + addr &= gfxmem_mask; + return gfxmemory[addr]; +} + +static void REGPARAM2 gfxmem_lput (uaecptr addr, uae_u32 l) +{ + uae_u32 *m; + +#ifdef JIT + special_mem|=picasso_is_special; +#endif + addr -= gfxmem_start & gfxmem_mask; + addr &= gfxmem_mask; + m = (uae_u32 *) (gfxmemory + addr); + do_put_mem_long (m, l); + + /* write the long-word to our displayable memory */ + write_gfx_long (addr, l); +} + +static void REGPARAM2 gfxmem_wput (uaecptr addr, uae_u32 w) +{ + uae_u16 *m; +#ifdef JIT + special_mem|=picasso_is_special; +#endif + addr -= gfxmem_start & gfxmem_mask; + addr &= gfxmem_mask; + m = (uae_u16 *) (gfxmemory + addr); + do_put_mem_word (m, (uae_u16) w); + + /* write the word to our displayable memory */ + write_gfx_word (addr, (uae_u16) w); +} + +static void REGPARAM2 gfxmem_bput (uaecptr addr, uae_u32 b) +{ +#ifdef JIT + special_mem|=picasso_is_special; +#endif + addr -= gfxmem_start & gfxmem_mask; + addr &= gfxmem_mask; + gfxmemory[addr] = b; + + /* write the byte to our displayable memory */ + write_gfx_byte (addr, (uae_u8) b); +} + +static int REGPARAM2 gfxmem_check (uaecptr addr, uae_u32 size) +{ + addr -= gfxmem_start & gfxmem_mask; + addr &= gfxmem_mask; + return (addr + size) < allocated_gfxmem; +} + +static uae_u8 REGPARAM2 *gfxmem_xlate (uaecptr addr) +{ + addr -= gfxmem_start & gfxmem_mask; + addr &= gfxmem_mask; + return gfxmemory + addr; +} + +addrbank gfxmem_bank = { + gfxmem_lget, gfxmem_wget, gfxmem_bget, + gfxmem_lput, gfxmem_wput, gfxmem_bput, + gfxmem_xlate, gfxmem_check, NULL +}; + +int picasso_display_mode_index (uae_u32 x, uae_u32 y, uae_u32 d) +{ + int i; + for (i = 0; i < mode_count; i++) { + if (DisplayModes[i].res.width == x + && DisplayModes[i].res.height == y + && DisplayModes[i].depth == d) + break; + } + if (i == mode_count) + i = -1; + return i; +} + +static int resolution_compare (const void *a, const void *b) +{ + struct PicassoResolution *ma = (struct PicassoResolution *) a; + struct PicassoResolution *mb = (struct PicassoResolution *) b; + if (ma->res.width > mb->res.width) + return -1; + if (ma->res.width < mb->res.width) + return 1; + if (ma->res.height > mb->res.height) + return -1; + if (ma->res.height < mb->res.height) + return 1; + return ma->depth - mb->depth; +} + +/* Call this function first, near the beginning of code flow + * NOTE: Don't stuff it in InitGraphics() which seems reasonable... + * Instead, put it in customreset() for safe-keeping. */ +void InitPicasso96 (void) +{ + static int first_time = 1; + + memset (&picasso96_state, 0, sizeof (struct picasso96_state_struct)); + + if (first_time) { + int i; + + for (i = 0; i < 256; i++) { + p2ctab[i][0] = (((i & 128) ? 0x01000000 : 0) + | ((i & 64) ? 0x010000 : 0) + | ((i & 32) ? 0x0100 : 0) + | ((i & 16) ? 0x01 : 0)); + p2ctab[i][1] = (((i & 8) ? 0x01000000 : 0) + | ((i & 4) ? 0x010000 : 0) + | ((i & 2) ? 0x0100 : 0) + | ((i & 1) ? 0x01 : 0)); + } + mode_count = DX_FillResolutions (&picasso96_pixel_format); + qsort (DisplayModes, mode_count, sizeof (struct PicassoResolution), resolution_compare); + + for (i = 0; i < mode_count; i++) { + sprintf (DisplayModes[i].name, "%dx%d, %d-bit, %d Hz", + DisplayModes[i].res.width, DisplayModes[i].res.height, DisplayModes[i].depth * 8, DisplayModes[i].refresh); + switch (DisplayModes[i].depth) { + case 1: + if (DisplayModes[i].res.width > chunky.width) + chunky.width = DisplayModes[i].res.width; + if (DisplayModes[i].res.height > chunky.height) + chunky.height = DisplayModes[i].res.height; + break; + case 2: + if (DisplayModes[i].res.width > hicolour.width) + hicolour.width = DisplayModes[i].res.width; + if (DisplayModes[i].res.height > hicolour.height) + hicolour.height = DisplayModes[i].res.height; + break; + case 3: + if (DisplayModes[i].res.width > truecolour.width) + truecolour.width = DisplayModes[i].res.width; + if (DisplayModes[i].res.height > truecolour.height) + truecolour.height = DisplayModes[i].res.height; + break; + case 4: + if (DisplayModes[i].res.width > alphacolour.width) + alphacolour.width = DisplayModes[i].res.width; + if (DisplayModes[i].res.height > alphacolour.height) + alphacolour.height = DisplayModes[i].res.height; + break; + } + } + ShowSupportedResolutions (); + + first_time = 0; + } +} + +#endif diff --git a/readcpu.c b/readcpu.c new file mode 100755 index 00000000..8c5ece17 --- /dev/null +++ b/readcpu.c @@ -0,0 +1,844 @@ +/* + * UAE - The Un*x Amiga Emulator + * + * Read 68000 CPU specs from file "table68k" + * + * Copyright 1995,1996 Bernd Schmidt + */ + +#include "sysconfig.h" +#include "sysdeps.h" +#include + +#include "readcpu.h" + +int nr_cpuop_funcs; + +struct mnemolookup lookuptab[] = { + { i_ILLG, "ILLEGAL" }, + { i_OR, "OR" }, + { i_CHK, "CHK" }, + { i_CHK2, "CHK2" }, + { i_AND, "AND" }, + { i_EOR, "EOR" }, + { i_ORSR, "ORSR" }, + { i_ANDSR, "ANDSR" }, + { i_EORSR, "EORSR" }, + { i_SUB, "SUB" }, + { i_SUBA, "SUBA" }, + { i_SUBX, "SUBX" }, + { i_SBCD, "SBCD" }, + { i_ADD, "ADD" }, + { i_ADDA, "ADDA" }, + { i_ADDX, "ADDX" }, + { i_ABCD, "ABCD" }, + { i_NEG, "NEG" }, + { i_NEGX, "NEGX" }, + { i_NBCD, "NBCD" }, + { i_CLR, "CLR" }, + { i_NOT, "NOT" }, + { i_TST, "TST" }, + { i_BTST, "BTST" }, + { i_BCHG, "BCHG" }, + { i_BCLR, "BCLR" }, + { i_BSET, "BSET" }, + { i_CMP, "CMP" }, + { i_CMPM, "CMPM" }, + { i_CMPA, "CMPA" }, + { i_MVPRM, "MVPRM" }, + { i_MVPMR, "MVPMR" }, + { i_MOVE, "MOVE" }, + { i_MOVEA, "MOVEA" }, + { i_MVSR2, "MVSR2" }, + { i_MV2SR, "MV2SR" }, + { i_SWAP, "SWAP" }, + { i_EXG, "EXG" }, + { i_EXT, "EXT" }, + { i_MVMEL, "MVMEL" }, + { i_MVMLE, "MVMLE" }, + { i_TRAP, "TRAP" }, + { i_MVR2USP, "MVR2USP" }, + { i_MVUSP2R, "MVUSP2R" }, + { i_NOP, "NOP" }, + { i_RESET, "RESET" }, + { i_RTE, "RTE" }, + { i_RTD, "RTD" }, + { i_LINK, "LINK" }, + { i_UNLK, "UNLK" }, + { i_RTS, "RTS" }, + { i_STOP, "STOP" }, + { i_TRAPV, "TRAPV" }, + { i_RTR, "RTR" }, + { i_JSR, "JSR" }, + { i_JMP, "JMP" }, + { i_BSR, "BSR" }, + { i_Bcc, "Bcc" }, + { i_LEA, "LEA" }, + { i_PEA, "PEA" }, + { i_DBcc, "DBcc" }, + { i_Scc, "Scc" }, + { i_DIVU, "DIVU" }, + { i_DIVS, "DIVS" }, + { i_MULU, "MULU" }, + { i_MULS, "MULS" }, + { i_ASR, "ASR" }, + { i_ASL, "ASL" }, + { i_LSR, "LSR" }, + { i_LSL, "LSL" }, + { i_ROL, "ROL" }, + { i_ROR, "ROR" }, + { i_ROXL, "ROXL" }, + { i_ROXR, "ROXR" }, + { i_ASRW, "ASRW" }, + { i_ASLW, "ASLW" }, + { i_LSRW, "LSRW" }, + { i_LSLW, "LSLW" }, + { i_ROLW, "ROLW" }, + { i_RORW, "RORW" }, + { i_ROXLW, "ROXLW" }, + { i_ROXRW, "ROXRW" }, + + { i_MOVE2C, "MOVE2C" }, + { i_MOVEC2, "MOVEC2" }, + { i_CAS, "CAS" }, + { i_CAS2, "CAS2" }, + { i_MULL, "MULL" }, + { i_DIVL, "DIVL" }, + { i_BFTST, "BFTST" }, + { i_BFEXTU, "BFEXTU" }, + { i_BFCHG, "BFCHG" }, + { i_BFEXTS, "BFEXTS" }, + { i_BFCLR, "BFCLR" }, + { i_BFFFO, "BFFFO" }, + { i_BFSET, "BFSET" }, + { i_BFINS, "BFINS" }, + { i_PACK, "PACK" }, + { i_UNPK, "UNPK" }, + { i_TAS, "TAS" }, + { i_BKPT, "BKPT" }, + { i_CALLM, "CALLM" }, + { i_RTM, "RTM" }, + { i_TRAPcc, "TRAPcc" }, + { i_MOVES, "MOVES" }, + { i_FPP, "FPP" }, + { i_FDBcc, "FDBcc" }, + { i_FScc, "FScc" }, + { i_FTRAPcc, "FTRAPcc" }, + { i_FBcc, "FBcc" }, + { i_FBcc, "FBcc" }, + { i_FSAVE, "FSAVE" }, + { i_FRESTORE, "FRESTORE" }, + + { i_CINVL, "CINVL" }, + { i_CINVP, "CINVP" }, + { i_CINVA, "CINVA" }, + { i_CPUSHL, "CPUSHL" }, + { i_CPUSHP, "CPUSHP" }, + { i_CPUSHA, "CPUSHA" }, + { i_MOVE16, "MOVE16" }, + + { i_MMUOP, "MMUOP" }, + { i_ILLG, "" }, +}; + +struct instr *table68k; + +STATIC_INLINE amodes mode_from_str (const char *str) +{ + if (strncmp (str, "Dreg", 4) == 0) return Dreg; + if (strncmp (str, "Areg", 4) == 0) return Areg; + if (strncmp (str, "Aind", 4) == 0) return Aind; + if (strncmp (str, "Apdi", 4) == 0) return Apdi; + if (strncmp (str, "Aipi", 4) == 0) return Aipi; + if (strncmp (str, "Ad16", 4) == 0) return Ad16; + if (strncmp (str, "Ad8r", 4) == 0) return Ad8r; + if (strncmp (str, "absw", 4) == 0) return absw; + if (strncmp (str, "absl", 4) == 0) return absl; + if (strncmp (str, "PC16", 4) == 0) return PC16; + if (strncmp (str, "PC8r", 4) == 0) return PC8r; + if (strncmp (str, "Immd", 4) == 0) return imm; + abort (); + return 0; +} + +STATIC_INLINE amodes mode_from_mr (int mode, int reg) +{ + switch (mode) { + case 0: return Dreg; + case 1: return Areg; + case 2: return Aind; + case 3: return Aipi; + case 4: return Apdi; + case 5: return Ad16; + case 6: return Ad8r; + case 7: + switch (reg) { + case 0: return absw; + case 1: return absl; + case 2: return PC16; + case 3: return PC8r; + case 4: return imm; + case 5: + case 6: + case 7: return am_illg; + } + } + abort (); + return 0; +} + +static void build_insn (int insn) +{ + int find = -1; + int variants; + int isjmp = 0; + struct instr_def id; + const char *opcstr; + int i; + + int flaglive = 0, flagdead = 0; + + id = defs68k[insn]; + + /* Note: We treat anything with unknown flags as a jump. That + is overkill, but "the programmer" was lazy quite often, and + *this* programmer can't be bothered to work out what can and + can't trap. Usually, this will be overwritten with the gencomp + based information, anyway. */ + + for (i = 0; i < 5; i++) { + switch (id.flaginfo[i].flagset){ + case fa_unset: break; + case fa_isjmp: isjmp = 1; break; + case fa_isbranch: isjmp = 1; break; + case fa_zero: flagdead |= 1 << i; break; + case fa_one: flagdead |= 1 << i; break; + case fa_dontcare: flagdead |= 1 << i; break; + case fa_unknown: isjmp = 1; flagdead = -1; goto out1; + case fa_set: flagdead |= 1 << i; break; + } + } + + out1: + for (i = 0; i < 5; i++) { + switch (id.flaginfo[i].flaguse) { + case fu_unused: break; + case fu_isjmp: isjmp = 1; flaglive |= 1 << i; break; + case fu_maybecc: isjmp = 1; flaglive |= 1 << i; break; + case fu_unknown: isjmp = 1; flaglive |= 1 << i; break; + case fu_used: flaglive |= 1 << i; break; + } + } + + opcstr = id.opcstr; + for (variants = 0; variants < (1 << id.n_variable); variants++) { + int bitcnt[lastbit]; + int bitval[lastbit]; + int bitpos[lastbit]; + int i; + uae_u16 opc = id.bits; + uae_u16 msk, vmsk; + int pos = 0; + int mnp = 0; + int bitno = 0; + char mnemonic[10]; + + wordsizes sz = sz_long; + int srcgather = 0, dstgather = 0; + int usesrc = 0, usedst = 0; + int srctype = 0; + int srcpos = -1, dstpos = -1; + + amodes srcmode = am_unknown, destmode = am_unknown; + int srcreg = -1, destreg = -1; + + for (i = 0; i < lastbit; i++) + bitcnt[i] = bitval[i] = 0; + + vmsk = 1 << id.n_variable; + + for (i = 0, msk = 0x8000; i < 16; i++, msk >>= 1) { + if (!(msk & id.mask)) { + int currbit = id.bitpos[bitno++]; + int bit_set; + vmsk >>= 1; + bit_set = variants & vmsk ? 1 : 0; + if (bit_set) + opc |= msk; + bitpos[currbit] = 15 - i; + bitcnt[currbit]++; + bitval[currbit] <<= 1; + bitval[currbit] |= bit_set; + } + } + + if (bitval[bitj] == 0) bitval[bitj] = 8; + /* first check whether this one does not match after all */ + if (bitval[bitz] == 3 || bitval[bitC] == 1) + continue; + if (bitcnt[bitI] && (bitval[bitI] == 0x00 || bitval[bitI] == 0xff)) + continue; + + /* bitI and bitC get copied to biti and bitc */ + if (bitcnt[bitI]) { + bitval[biti] = bitval[bitI]; bitpos[biti] = bitpos[bitI]; + } + if (bitcnt[bitC]) + bitval[bitc] = bitval[bitC]; + + pos = 0; + while (opcstr[pos] && !isspace(opcstr[pos])) { + if (opcstr[pos] == '.') { + pos++; + switch (opcstr[pos]) { + + case 'B': sz = sz_byte; break; + case 'W': sz = sz_word; break; + case 'L': sz = sz_long; break; + case 'z': + switch (bitval[bitz]) { + case 0: sz = sz_byte; break; + case 1: sz = sz_word; break; + case 2: sz = sz_long; break; + default: abort(); + } + break; + default: abort(); + } + } else { + mnemonic[mnp] = opcstr[pos]; + if (mnemonic[mnp] == 'f') { + find = -1; + switch (bitval[bitf]) { + case 0: mnemonic[mnp] = 'R'; break; + case 1: mnemonic[mnp] = 'L'; break; + default: abort(); + } + } + mnp++; + } + pos++; + } + mnemonic[mnp] = 0; + + /* now, we have read the mnemonic and the size */ + while (opcstr[pos] && isspace(opcstr[pos])) + pos++; + + /* A goto a day keeps the D******a away. */ + if (opcstr[pos] == 0) + goto endofline; + + /* parse the source address */ + usesrc = 1; + switch (opcstr[pos++]) { + case 'D': + srcmode = Dreg; + switch (opcstr[pos++]) { + case 'r': srcreg = bitval[bitr]; srcgather = 1; srcpos = bitpos[bitr]; break; + case 'R': srcreg = bitval[bitR]; srcgather = 1; srcpos = bitpos[bitR]; break; + default: abort(); + } + break; + case 'A': + srcmode = Areg; + switch (opcstr[pos++]) { + case 'r': srcreg = bitval[bitr]; srcgather = 1; srcpos = bitpos[bitr]; break; + case 'R': srcreg = bitval[bitR]; srcgather = 1; srcpos = bitpos[bitR]; break; + default: abort(); + } + switch (opcstr[pos]) { + case 'p': srcmode = Apdi; pos++; break; + case 'P': srcmode = Aipi; pos++; break; + } + break; + case 'L': + srcmode = absl; + break; + case '#': + switch (opcstr[pos++]) { + case 'z': srcmode = imm; break; + case '0': srcmode = imm0; break; + case '1': srcmode = imm1; break; + case '2': srcmode = imm2; break; + case 'i': srcmode = immi; srcreg = (uae_s32)(uae_s8)bitval[biti]; + if (CPU_EMU_SIZE < 4) { + /* Used for branch instructions */ + srctype = 1; + srcgather = 1; + srcpos = bitpos[biti]; + } + break; + case 'j': srcmode = immi; srcreg = bitval[bitj]; + if (CPU_EMU_SIZE < 3) { + /* 1..8 for ADDQ/SUBQ and rotshi insns */ + srcgather = 1; + srctype = 3; + srcpos = bitpos[bitj]; + } + break; + case 'J': srcmode = immi; srcreg = bitval[bitJ]; + if (CPU_EMU_SIZE < 5) { + /* 0..15 */ + srcgather = 1; + srctype = 2; + srcpos = bitpos[bitJ]; + } + break; + case 'k': srcmode = immi; srcreg = bitval[bitk]; + if (CPU_EMU_SIZE < 3) { + srcgather = 1; + srctype = 4; + srcpos = bitpos[bitk]; + } + break; + case 'K': srcmode = immi; srcreg = bitval[bitK]; + if (CPU_EMU_SIZE < 5) { + /* 0..15 */ + srcgather = 1; + srctype = 5; + srcpos = bitpos[bitK]; + } + break; + case 'p': srcmode = immi; srcreg = bitval[bitK]; + if (CPU_EMU_SIZE < 5) { + /* 0..3 */ + srcgather = 1; + srctype = 7; + srcpos = bitpos[bitp]; + } + break; + default: abort(); + } + break; + case 'd': + srcreg = bitval[bitD]; + srcmode = mode_from_mr(bitval[bitd],bitval[bitD]); + if (srcmode == am_illg) + continue; + if (CPU_EMU_SIZE < 2 && + (srcmode == Areg || srcmode == Dreg || srcmode == Aind + || srcmode == Ad16 || srcmode == Ad8r || srcmode == Aipi + || srcmode == Apdi)) + { + srcgather = 1; srcpos = bitpos[bitD]; + } + if (opcstr[pos] == '[') { + pos++; + if (opcstr[pos] == '!') { + /* exclusion */ + do { + pos++; + if (mode_from_str(opcstr+pos) == srcmode) + goto nomatch; + pos += 4; + } while (opcstr[pos] == ','); + pos++; + } else { + if (opcstr[pos+4] == '-') { + /* replacement */ + if (mode_from_str(opcstr+pos) == srcmode) + srcmode = mode_from_str(opcstr+pos+5); + else + goto nomatch; + pos += 10; + } else { + /* normal */ + while(mode_from_str(opcstr+pos) != srcmode) { + pos += 4; + if (opcstr[pos] == ']') + goto nomatch; + pos++; + } + while(opcstr[pos] != ']') pos++; + pos++; + break; + } + } + } + /* Some addressing modes are invalid as destination */ + if (srcmode == imm || srcmode == PC16 || srcmode == PC8r) + goto nomatch; + break; + case 's': + srcreg = bitval[bitS]; + srcmode = mode_from_mr(bitval[bits],bitval[bitS]); + + if (srcmode == am_illg) + continue; + if (CPU_EMU_SIZE < 2 && + (srcmode == Areg || srcmode == Dreg || srcmode == Aind + || srcmode == Ad16 || srcmode == Ad8r || srcmode == Aipi + || srcmode == Apdi)) + { + srcgather = 1; srcpos = bitpos[bitS]; + } + if (opcstr[pos] == '[') { + pos++; + if (opcstr[pos] == '!') { + /* exclusion */ + do { + pos++; + if (mode_from_str(opcstr+pos) == srcmode) + goto nomatch; + pos += 4; + } while (opcstr[pos] == ','); + pos++; + } else { + if (opcstr[pos+4] == '-') { + /* replacement */ + if (mode_from_str(opcstr+pos) == srcmode) + srcmode = mode_from_str(opcstr+pos+5); + else + goto nomatch; + pos += 10; + } else { + /* normal */ + while(mode_from_str(opcstr+pos) != srcmode) { + pos += 4; + if (opcstr[pos] == ']') + goto nomatch; + pos++; + } + while(opcstr[pos] != ']') pos++; + pos++; + } + } + } + break; + default: abort(); + } + /* safety check - might have changed */ + if (srcmode != Areg && srcmode != Dreg && srcmode != Aind + && srcmode != Ad16 && srcmode != Ad8r && srcmode != Aipi + && srcmode != Apdi && srcmode != immi) + { + srcgather = 0; + } + if (srcmode == Areg && sz == sz_byte) + goto nomatch; + + if (opcstr[pos] != ',') + goto endofline; + pos++; + + /* parse the destination address */ + usedst = 1; + switch (opcstr[pos++]) { + case 'D': + destmode = Dreg; + switch (opcstr[pos++]) { + case 'r': destreg = bitval[bitr]; dstgather = 1; dstpos = bitpos[bitr]; break; + case 'R': destreg = bitval[bitR]; dstgather = 1; dstpos = bitpos[bitR]; break; + default: abort(); + } + if (dstpos < 0 || dstpos >= 32) + abort (); + break; + case 'A': + destmode = Areg; + switch (opcstr[pos++]) { + case 'r': destreg = bitval[bitr]; dstgather = 1; dstpos = bitpos[bitr]; break; + case 'R': destreg = bitval[bitR]; dstgather = 1; dstpos = bitpos[bitR]; break; + case 'x': destreg = 0; dstgather = 0; dstpos = 0; break; + default: abort(); + } + if (dstpos < 0 || dstpos >= 32) + abort (); + switch (opcstr[pos]) { + case 'p': destmode = Apdi; pos++; break; + case 'P': destmode = Aipi; pos++; break; + } + break; + case 'L': + destmode = absl; + break; + case '#': + switch (opcstr[pos++]) { + case 'z': destmode = imm; break; + case '0': destmode = imm0; break; + case '1': destmode = imm1; break; + case '2': destmode = imm2; break; + case 'i': destmode = immi; destreg = (uae_s32)(uae_s8)bitval[biti]; break; + case 'j': destmode = immi; destreg = bitval[bitj]; break; + case 'J': destmode = immi; destreg = bitval[bitJ]; break; + case 'k': destmode = immi; destreg = bitval[bitk]; break; + case 'K': destmode = immi; destreg = bitval[bitK]; break; + default: abort(); + } + break; + case 'd': + destreg = bitval[bitD]; + destmode = mode_from_mr(bitval[bitd],bitval[bitD]); + if (destmode == am_illg) + continue; + if (CPU_EMU_SIZE < 1 && + (destmode == Areg || destmode == Dreg || destmode == Aind + || destmode == Ad16 || destmode == Ad8r || destmode == Aipi + || destmode == Apdi)) + { + dstgather = 1; dstpos = bitpos[bitD]; + } + + if (opcstr[pos] == '[') { + pos++; + if (opcstr[pos] == '!') { + /* exclusion */ + do { + pos++; + if (mode_from_str(opcstr+pos) == destmode) + goto nomatch; + pos += 4; + } while (opcstr[pos] == ','); + pos++; + } else { + if (opcstr[pos+4] == '-') { + /* replacement */ + if (mode_from_str(opcstr+pos) == destmode) + destmode = mode_from_str(opcstr+pos+5); + else + goto nomatch; + pos += 10; + } else { + /* normal */ + while(mode_from_str(opcstr+pos) != destmode) { + pos += 4; + if (opcstr[pos] == ']') + goto nomatch; + pos++; + } + while(opcstr[pos] != ']') pos++; + pos++; + break; + } + } + } + /* Some addressing modes are invalid as destination */ + if (destmode == imm || destmode == PC16 || destmode == PC8r) + goto nomatch; + break; + case 's': + destreg = bitval[bitS]; + destmode = mode_from_mr(bitval[bits],bitval[bitS]); + + if (destmode == am_illg) + continue; + if (CPU_EMU_SIZE < 1 && + (destmode == Areg || destmode == Dreg || destmode == Aind + || destmode == Ad16 || destmode == Ad8r || destmode == Aipi + || destmode == Apdi)) + { + dstgather = 1; dstpos = bitpos[bitS]; + } + + if (opcstr[pos] == '[') { + pos++; + if (opcstr[pos] == '!') { + /* exclusion */ + do { + pos++; + if (mode_from_str(opcstr+pos) == destmode) + goto nomatch; + pos += 4; + } while (opcstr[pos] == ','); + pos++; + } else { + if (opcstr[pos+4] == '-') { + /* replacement */ + if (mode_from_str(opcstr+pos) == destmode) + destmode = mode_from_str(opcstr+pos+5); + else + goto nomatch; + pos += 10; + } else { + /* normal */ + while(mode_from_str(opcstr+pos) != destmode) { + pos += 4; + if (opcstr[pos] == ']') + goto nomatch; + pos++; + } + while(opcstr[pos] != ']') pos++; + pos++; + } + } + } + break; + default: abort(); + } + /* safety check - might have changed */ + if (destmode != Areg && destmode != Dreg && destmode != Aind + && destmode != Ad16 && destmode != Ad8r && destmode != Aipi + && destmode != Apdi) + { + dstgather = 0; + } + + if (destmode == Areg && sz == sz_byte) + goto nomatch; +#if 0 + if (sz == sz_byte && (destmode == Aipi || destmode == Apdi)) { + dstgather = 0; + } +#endif + endofline: + /* now, we have a match */ + if (table68k[opc].mnemo != i_ILLG) + write_log ("Double match: %x: %s\n", opc, opcstr); + if (find == -1) { + for (find = 0;; find++) { + if (strcmp(mnemonic, lookuptab[find].name) == 0) { + table68k[opc].mnemo = lookuptab[find].mnemo; + break; + } + if (strlen(lookuptab[find].name) == 0) abort(); + } + } + else { + table68k[opc].mnemo = lookuptab[find].mnemo; + } + table68k[opc].cc = bitval[bitc]; + if (table68k[opc].mnemo == i_BTST + || table68k[opc].mnemo == i_BSET + || table68k[opc].mnemo == i_BCLR + || table68k[opc].mnemo == i_BCHG) + { + sz = destmode == Dreg ? sz_long : sz_byte; + } + table68k[opc].size = sz; + table68k[opc].sreg = srcreg; + table68k[opc].dreg = destreg; + table68k[opc].smode = srcmode; + table68k[opc].dmode = destmode; + table68k[opc].spos = srcgather ? srcpos : -1; + table68k[opc].dpos = dstgather ? dstpos : -1; + table68k[opc].suse = usesrc; + table68k[opc].duse = usedst; + table68k[opc].stype = srctype; + table68k[opc].plev = id.plevel; + table68k[opc].clev = id.cpulevel; +#if 0 + for (i = 0; i < 5; i++) { + table68k[opc].flaginfo[i].flagset = id.flaginfo[i].flagset; + table68k[opc].flaginfo[i].flaguse = id.flaginfo[i].flaguse; + } +#endif + table68k[opc].flagdead = flagdead; + table68k[opc].flaglive = flaglive; + table68k[opc].isjmp = isjmp; + nomatch: + /* FOO! */; + } +} + + +void read_table68k (void) +{ + int i; + + free (table68k); + table68k = (struct instr *)xmalloc (65536 * sizeof (struct instr)); + for (i = 0; i < 65536; i++) { + table68k[i].mnemo = i_ILLG; + table68k[i].handler = -1; + } + for (i = 0; i < n_defs68k; i++) { + build_insn (i); + } +} + +static int mismatch; + +static void handle_merges (long int opcode) +{ + uae_u16 smsk; + uae_u16 dmsk; + int sbitdst, dstend; + int srcreg, dstreg; + + if (table68k[opcode].spos == -1) { + sbitdst = 1; smsk = 0; + } else { + switch (table68k[opcode].stype) { + case 0: + smsk = 7; sbitdst = 8; break; + case 1: + smsk = 255; sbitdst = 256; break; + case 2: + smsk = 15; sbitdst = 16; break; + case 3: + smsk = 7; sbitdst = 8; break; + case 4: + smsk = 7; sbitdst = 8; break; + case 5: + smsk = 63; sbitdst = 64; break; + case 7: + smsk = 3; sbitdst = 4; break; + default: + smsk = 0; sbitdst = 0; + abort(); + break; + } + smsk <<= table68k[opcode].spos; + } + if (table68k[opcode].dpos == -1) { + dstend = 1; dmsk = 0; + } else { + dmsk = 7 << table68k[opcode].dpos; + dstend = 8; + } + for (srcreg=0; srcreg < sbitdst; srcreg++) { + for (dstreg=0; dstreg < dstend; dstreg++) { + uae_u16 code = (uae_u16)opcode; + + code = (code & ~smsk) | (srcreg << table68k[opcode].spos); + code = (code & ~dmsk) | (dstreg << table68k[opcode].dpos); + + /* Check whether this is in fact the same instruction. + * The instructions should never differ, except for the + * Bcc.(BW) case. */ + if (table68k[code].mnemo != table68k[opcode].mnemo + || table68k[code].size != table68k[opcode].size + || table68k[code].suse != table68k[opcode].suse + || table68k[code].duse != table68k[opcode].duse) + { + mismatch++; continue; + } + if (table68k[opcode].suse + && (table68k[opcode].spos != table68k[code].spos + || table68k[opcode].smode != table68k[code].smode + || table68k[opcode].stype != table68k[code].stype)) + { + mismatch++; continue; + } + if (table68k[opcode].duse + && (table68k[opcode].dpos != table68k[code].dpos + || table68k[opcode].dmode != table68k[code].dmode)) + { + mismatch++; continue; + } + + if (code != opcode) + table68k[code].handler = opcode; + } + } +} + +void do_merges (void) +{ + long int opcode; + int nr = 0; + mismatch = 0; + for (opcode = 0; opcode < 65536; opcode++) { + if (table68k[opcode].handler != -1 || table68k[opcode].mnemo == i_ILLG) + continue; + nr++; + handle_merges (opcode); + } + nr_cpuop_funcs = nr; +} + +int get_no_mismatches (void) +{ + return mismatch; +} diff --git a/readdisk.c b/readdisk.c new file mode 100755 index 00000000..8b5e3a43 --- /dev/null +++ b/readdisk.c @@ -0,0 +1,193 @@ +/* + * readdisk + * + * Read files from Amiga disk files + * + * Copyright 1996 Bernd Schmidt + * Copyright 1998 Jim Cooper + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "uae.h" + +void write_log (const char *s,...) +{ + fprintf (stderr, "%s", s); +} + +unsigned char filemem[901120]; + +typedef struct afile { + struct afile *sibling; + unsigned char *data; + uae_u32 size; + char name[32]; +} afile; + +typedef struct directory { + struct directory *sibling; + struct directory *subdirs; + struct afile *files; + char name[32]; +} directory; + +static int secdatasize, secdataoffset; + +static uae_u32 readlong (unsigned char *buffer, int pos) +{ + return ((*(buffer + pos) << 24) + (*(buffer + pos + 1) << 16) + + (*(buffer + pos + 2) << 8) + *(buffer + pos + 3)); +} + +static afile *read_file (unsigned char *filebuf) +{ + afile *a = (afile *) xmalloc (sizeof (afile)); + int sizeleft; + unsigned char *datapos; + uae_u32 numblocks, blockpos; + + /* BCPL strings... Yuk. */ + memset (a->name, 0, 32); + strncpy (a->name, (const char *) filebuf + 0x1B1, *(filebuf + 0x1B0)); + sizeleft = a->size = readlong (filebuf, 0x144); + a->data = (unsigned char *) xmalloc (a->size); + + numblocks = readlong (filebuf, 0x8); + blockpos = 0x134; + datapos = a->data; + while (numblocks) { + unsigned char *databuf = filemem + 512 * readlong (filebuf, blockpos); + int readsize = sizeleft > secdatasize ? secdatasize : sizeleft; + memcpy (datapos, databuf + secdataoffset, readsize); + datapos += readsize; + sizeleft -= readsize; + + blockpos -= 4; + numblocks--; + if (!numblocks) { + uae_u32 nextflb = readlong (filebuf, 0x1F8); + if (nextflb) { + filebuf = filemem + 512 * nextflb; + blockpos = 0x134; + numblocks = readlong (filebuf, 0x8); + if (!filebuf) { + write_log ("Disk structure corrupted. Use DISKDOCTOR to correct it.\n"); + abort (); + } + } + } + } + return a; +} + +static directory *read_dir (unsigned char *dirbuf) +{ + directory *d = (directory *) xmalloc (sizeof (directory)); + uae_u32 hashsize; + uae_u32 i; + + memset (d->name, 0, 32); + strncpy (d->name, (const char *) dirbuf + 0x1B1, *(dirbuf + 0x1B0)); + d->sibling = 0; + d->subdirs = 0; + d->files = 0; + hashsize = readlong (dirbuf, 0xc); + if (!hashsize) + hashsize = 72; + if (hashsize != 72) + write_log ("Warning: Hash table with != 72 entries.\n"); + for (i = 0; i < hashsize; i++) { + uae_u32 subblock = readlong (dirbuf, 0x18 + 4 * i); + + while (subblock) { + directory *subdir; + afile *subfile; + unsigned char *subbuf = filemem + 512 * subblock; + long dirtype; + + dirtype = (uae_s32) readlong (subbuf, 0x1FC); + if (dirtype > 0) { + subdir = read_dir (subbuf); + subdir->sibling = d->subdirs; + d->subdirs = subdir; + } else if (dirtype < 0) { + subfile = read_file (subbuf); + subfile->sibling = d->files; + d->files = subfile; + } else { + write_log ("Disk structure corrupted. Use DISKDOCTOR to correct it.\n"); + abort (); + } + subblock = readlong (subbuf, 0x1F0); + } + } + return d; +} + +static void writedir (directory * dir) +{ + directory *subdir; + afile *f; + + if (mkdir (dir->name, 0777) < 0 && errno != EEXIST) { + write_log ("Could not create directory \"%s\". Giving up.\n", dir->name); + exit (20); + } + if (chdir (dir->name) < 0) { + write_log ("Could not enter directory \"%s\". Giving up.\n", dir->name); + exit (20); + } + for (subdir = dir->subdirs; subdir; subdir = subdir->sibling) + writedir (subdir); + for (f = dir->files; f; f = f->sibling) { + int fd = creat (f->name, 0666); + if (fd < 0) { + write_log ("Could not create file. Giving up.\n"); + exit (20); + } + write (fd, f->data, f->size); + close (fd); + } + chdir (".."); +} + +int main (int argc, char **argv) +{ + directory *root; + FILE *inf; + + if (argc < 2 || argc > 3) { + write_log ("Usage: readdisk []\n"); + exit (20); + } + inf = fopen (argv[1], "rb"); + if (inf == NULL) { + write_log ("can't open file\n"); + exit (20); + } + fread (filemem, 1, 901120, inf); + + if (strncmp ((const char *) filemem, "DOS\0", 4) == 0 + || strncmp ((const char *) filemem, "DOS\2", 4) == 0) { + secdatasize = 488; + secdataoffset = 24; + } else if (strncmp ((const char *) filemem, "DOS\1", 4) == 0 + || strncmp ((const char *) filemem, "DOS\3", 4) == 0) { + secdatasize = 512; + secdataoffset = 0; + } else { + write_log ("Not a DOS disk.\n"); + exit (20); + } + root = read_dir (filemem + 880 * 512); + + if (argc == 3) + if (chdir (argv[2]) < 0) { + write_log ("Couldn't change to %s. Giving up.\n", argv[2]); + exit (20); + } + writedir (root); + return 0; +} diff --git a/rpc.c b/rpc.c new file mode 100755 index 00000000..8cf04d80 --- /dev/null +++ b/rpc.c @@ -0,0 +1,677 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * RiscPC Interface. + * + * (c) 1995 Bernd Schmidt + * (c) 1996 Gustavo Goedert + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "threaddep/thread.h" +#include "memory.h" +#include "custom.h" +#include "keyboard.h" +#include "xwin.h" +#include "keybuf.h" +#include "gui.h" + +typedef char flagtype; + +extern struct regstruct +{ + ULONG regs[16]; + CPTR usp,isp,msp; + UWORD sr; + flagtype t1; + flagtype t0; + flagtype s; + flagtype m; + flagtype x; + flagtype stopped; + int intmask; + ULONG pc; +#ifdef USE_POINTER + UBYTE *pc_p; + UBYTE *pc_oldp; +#endif + + ULONG vbr,sfc,dfc; + + double fp[8]; + ULONG fpcr,fpsr,fpiar; + ULONG spcflags; + ULONG kick_mask; +} regs; + + +#include "OS:wimp.h" +#include "OS:font.h" +#include "OS:os.h" +#include "OS:osbyte.h" +#include "OS:osword.h" +#include "OS:sound.h" + + +void gui_process(void); + + +#define A_base 0x300000 +#define A_switch (A_base+0) +#define A_disk (A_base+1) +#define A_sonst (A_base+5) +#define A_hf (A_base+6) +#define A_mount (A_base+7) +#define A_rom (A_base+10) +#define A_uaeask (A_base+11) + +int quit_program; +int uae_running; +int uae_startedup; + +wimp_MESSAGE_LIST(13) messages= + {A_switch, A_disk, A_disk+1, A_disk+2, A_disk+3, A_sonst, A_rom, A_mount, + A_mount+1, A_mount+2, A_uaeask, message_PREQUIT, 0}; + +wimp_t taskhandle; +wimp_t frontendhandle; +wimp_block block; +wimp_message mblock; +int pollword; + +os_MODE_SELECTOR(3) uaemode={1,0,0,0,-1,0,128,3,255,-1,0}; +os_MODE_SELECTOR(3) wimpmode; + +extern void datavox_type(int channel, int type); +extern void datavox_timed(int channel, int timed); +extern void datavox_pitch(int channel, int pitch); +extern void datavox_set_memory(int channel, char *start, char *end); +extern void datavox_set_repeat(int channel, char *start, char *end); +extern int datavox_allocate_channel(int key); +extern void datavox_de_allocate_channel(int channel, int key); + +int sratecode; +char sbuffer[44100]; +int deskvoice, uaechannel; + +extern int uaedevfd, numtracks; + +char mountpoint[64]; +char mountdir[256]; + +char *scr; +int screenrowbytes,screenrows; + +char pressed[128]; +char translate[128]= +{ 255, 255, 255, AK_LSH, AK_CTRL, AK_LALT, AK_RSH, AK_CTRL, //0 + AK_RALT, 255, 255, 255, 255, 255, 255, 255, //8 + AK_Q, AK_3, AK_4, AK_5, AK_F4, AK_8, AK_F7, AK_MINUS, //16 + 255, AK_LF, AK_NP6, AK_NP7, 255, 255, AK_F10, 255, //24 + 255, AK_W, AK_E, AK_T, AK_7, AK_I, AK_9, AK_0, //32 + 255, AK_DN, AK_NP8, AK_NP9, 255,AK_BACKQUOTE, AK_LTGT, AK_BS, //40 + AK_1, AK_2, AK_D, AK_R, AK_6, AK_U, AK_O, AK_P, //48 + AK_LBRACKET, AK_UP,AK_NPADD,AK_NPSUB, AK_ENT, 255, 255, AK_RAMI, //56 + AK_CAPSLOCK, AK_A, AK_X, AK_F, AK_Y, AK_J, AK_K, 255, //64 + 255, AK_RET,AK_NPDIV, 255,AK_NPDEL, 255, AK_LAMI, AK_QUOTE, //72 + 255, AK_S, AK_C, AK_G, AK_H, AK_N, AK_L,AK_SEMICOLON, //80 + AK_RBRACKET, AK_DEL, 255,AK_NPMUL, 255, AK_EQUAL, AK_LTGT, 255, //88 + AK_TAB, AK_Z, AK_SPC, AK_V, AK_B, AK_M,AK_COMMA, AK_PERIOD, //96 + AK_SLASH,AK_HELP, AK_NP0, AK_NP1, AK_NP3, 255, 255, 255, //104 + 255, AK_F1, AK_F2, AK_F3, AK_F5, AK_F6, AK_F8, AK_F9, //112 +AK_BACKSLASH, AK_RT, AK_NP4, AK_NP5, AK_NP2, 255, 255, 255};//120 + +char dn0[256], dn1[256], dn2[256], dn3[256]; +int dc0=0, dc1=0, dc2=0, dc3=0; + +/***************************************************************************/ + + +void setup_brkhandler(void) +{ +} + +void flush_line(int y) +{ +} + +void flush_block(int a, int b) +{ +} + +void flush_screen(int a, int b) +{ +} + +void calc_adjustment(void) +{ +} + + +static int colors_allocated; + +static int get_color(int r, int g, int b, xcolnr *cnp) +{ + if (colors_allocated == 256) + return -1; + *cnp = colors_allocated; + + os_writec(19); + os_writec(colors_allocated); + os_writec(16); + os_writec(r+(r<<4)); + os_writec(g+(g<<4)); + os_writec(b+(b<<4)); + colors_allocated++; + + return 1; +} + +static void init_colors(void) +{ + int rw = 5, gw = 5, bw = 5; + colors_allocated = 0; + + if (gfxvidinfo.pixbytes == 2) + alloc_colors64k(rw, gw, bw, 0, rw, rw+gw); + else + alloc_colors256(get_color); +} + +void sound_output(char *b, int l) +{ + memcpy(sbuffer, b, l); + datavox_set_memory(uaechannel, sbuffer, sbuffer+l); + datavox_set_repeat(uaechannel, sbuffer, sbuffer+l); + datavox_type(uaechannel, 1); + datavox_pitch(uaechannel, sratecode); + sound_control(uaechannel, 256+127, 0, 255); +} + +void init_mouse(void) +{ + oswordpointer_bbox_block bbox; + + bbox.op=oswordpointer_OP_SET_BBOX; + bbox.x0=-32768; + bbox.y0=-32768; + bbox.x1=32767; + bbox.y1=32767; + oswordpointer_set_bbox(&bbox); +} + +void setwimpmode(void) +{ + wimp_set_mode(&wimpmode); + while(osbyte2(145,0,0)!=0); +} + +void setuaemode(void) +{ + os_vdu_var_list varlist[2]={149,-1}; + int valuelist[1]; + os_mode m; + + m=osscreenmode_current(); + memcpy(&wimpmode, m, os_SIZEOF_MODE_SELECTOR(3)); + + osscreenmode_select(&uaemode); + os_read_vdu_variables(varlist, valuelist); + scr=(void *)valuelist[0]; + gfxvidinfo.bufmem=scr; + + os_remove_cursors(); + + init_colors(); + init_mouse(); + + flush_block(0, numscrlines-1); +} + +void setwimpsound(void) +{ + int s,t; + + sound_attach_voice(uaechannel, deskvoice, &s, &t); + datavox_de_allocate_channel(uaechannel, taskhandle); +} + +void setuaesound(void) +{ + int s; + + sound_volume(127); + uaechannel=datavox_allocate_channel(taskhandle); + printf("%d\n", uaechannel); + sound_attach_voice(uaechannel, 0, &s, &deskvoice); + sound_attach_named_voice(uaechannel, "DataVox-Voice"); +} + +int graphics_init(void) +{ + __uname_control=6; + + switch(color_mode) + { + case 1: + case 2: + case 5: + uaemode.log2_bpp=4; + gfxvidinfo.pixbytes=2; + break; + default: + uaemode.log2_bpp=3; + gfxvidinfo.pixbytes=1; + break; + } + + uaemode.xres=gfx_requested_width; + uaemode.yres=gfx_requested_height; + + gfxvidinfo.rowbytes=gfx_requested_width*gfxvidinfo.pixbytes; + gfxvidinfo.maxlinetoscr=gfx_requested_width; + gfxvidinfo.maxline=gfx_requested_height; + gfxvidinfo.maxblocklines=0; + + setuaemode(); + setuaesound(); + + return 1; +} + +void graphics_leave(void) +{ +} + + +void readmouse(void) +{ + int x,y; + bits buttons; + os_t t; + + os_mouse(&x, &y, &buttons, &t); + lastmx=x>>1; + lastmy=gfx_requested_height-(y>>1); + buttonstate[0]=(buttons & 4)>>2; + buttonstate[1]=(buttons & 2)>>1; + buttonstate[2]=buttons & 1; + newmousecounters=0; +} + + +void processkey(char k, char release) +{ + if(k==29 && release==1) + { + uae_running=0; + setwimpmode(); + setwimpsound(); + } + + if(translate[k]!=255) + record_key((translate[k]<<1)+release); +} + + +void readkeyboard(void) +{ + char c,l,k,q; + + for(l=0, k=osbyte1(121, 0, 0), q=0; !q; l=k+1, k=osbyte1(121, l, 0)) + { + if(k==0xff) + { + k=128; + q=1; + } + else + { + if(pressed[k]==0) + { + if (translate[k]!=0) + processkey(k, 0); + pressed[k]=1; + } + } + for(c=l; c1) dc0--; + if(dc1>1) dc1--; + if(dc2>1) dc2--; + if(dc3>1) dc3--; + + if (uae_running==0) + gui_process(); +} + +int debuggable(void) +{ + return 0; +} + +int needmousehack(void) +{ + return 0; +} + +void LED(int on) +{ +} + +static void sigchldhandler(int foo) +{ +} + + +/***************************************************************************/ + + +int gui_init(void) +{ + int vout; + + quit_program=0; + uae_running=0; + uae_startedup=0; + + taskhandle=wimp_initialise(wimp_VERSION_RO35, "UAE", &messages, &vout); + gui_process(); + + return 0; +} + +void changedisk(int n, char *f) +{ + if(uae_startedup) + { + switch(n) + { + case 0: + if(strcmp(df0, f)!=0) + { + strncpy(dn0, f, 255); + dc0=3; + disk_eject(0); + strncpy(df0, "", 255); + } + break; + case 1: + if(strcmp(df1, f)!=0) + { + strncpy(dn1, f, 255); + dc1=3; + disk_eject(1); + strncpy(df1, "", 255); + } + break; + case 2: + if(strcmp(df2, f)!=0) + { + strncpy(dn2, f, 255); + dc2=3; + disk_eject(2); + strncpy(df2, "", 255); + } + break; + case 3: + if(strcmp(df3, f)!=0) + { + strncpy(dn3, f, 255); + dc3=3; + disk_eject(3); + strncpy(df3, "", 255); + } + break; + } + } + else + { + switch(n) + { + case 0: + strncpy(df0, f, 255); + break; + case 1: + strncpy(df1, f, 255); + break; + case 2: + strncpy(df2, f, 255); + break; + case 3: + strncpy(df3, f, 255); + break; + } + } +} + +void setsonst(int *reserved) +{ + if(!uae_startedup) + { + gfx_requested_width=reserved[0]; + gfx_requested_xcenter=reserved[1]; + gfx_requested_lores=reserved[2]; + gfx_requested_height=reserved[3]; + gfx_requested_ycenter=reserved[4]; + gfx_requested_linedbl=reserved[5]; + gfx_requested_correct_aspect=reserved[6]; + switch(reserved[7]) + { + case 256: + color_mode=0; + break; + case 32768: + color_mode=1; + break; + } + framerate=reserved[8]; + emul_accuracy=reserved[9]; + blits_32bit_enabled=reserved[10]; + immediate_blits=reserved[11]; + fake_joystick=reserved[12]; + bogomem_size=reserved[14]; + chipmem_size=reserved[15]; + fastmem_size=reserved[16]; + produce_sound=reserved[17]; + sound_desired_freq=reserved[18]; + sound_desired_bsiz=reserved[19]; + } +} + +void sendtofront(int *reserved) +{ + int *words=mblock.data.reserved; + + mblock.size=256; + mblock.sender=taskhandle; + mblock.my_ref=778; + mblock.your_ref=777; + switch(*reserved) + { + case 0: + mblock.action=A_disk; + if(dc0==0) + strncpy(words, df0, 235); + else + strncpy(words, dn0, 235); + break; + case 1: + mblock.action=A_disk+1; + if(dc0==0) + strncpy(words, df1, 235); + else + strncpy(words, dn1, 235); + break; + case 2: + mblock.action=A_disk+2; + if(dc0==0) + strncpy(words, df2, 235); + else + strncpy(words, dn2, 235); + break; + case 3: + mblock.action=A_disk+3; + if(dc0==0) + strncpy(words, df3, 235); + else + strncpy(words, dn3, 235); + break; + } + wimp_send_message(wimp_USER_MESSAGE, &mblock, frontendhandle); +} + +void gui_messagereceive(void) +{ + switch(block.message.action) + { + case message_QUIT: + if(uae_startedup) + { + set_special (SPCFLAG_BRK); + quit_program=1; + uae_running=1; + } + else + { + if(uaedevfd!=-1) + { + close(uaedevfd); + } + wimp_close_down(taskhandle); + } + break; + case A_switch: + if(uae_startedup) + { + uae_running=1; + setuaemode(); + setuaesound(); + } + else + { + frontendhandle=block.message.sender; + uae_startedup=1; + uae_running=1; + } + break; + case A_disk: + changedisk(0, block.message.data.reserved); + break; + case A_disk+1: + changedisk(1, block.message.data.reserved); + break; + case A_disk+2: + changedisk(2, block.message.data.reserved); + break; + case A_disk+3: + changedisk(3, block.message.data.reserved); + break; + case A_sonst: + setsonst(block.message.data.reserved); + break; + case A_rom: + strncpy(romfile, block.message.data.reserved, 235); + break; + case A_mount: + strncpy(mountpoint, block.message.data.reserved, 63); + break; + case A_mount+1: + strncpy(mountdir, block.message.data.reserved, 235); + add_filesys_unit(mountpoint, mountdir, 0); + break; + case A_mount+2: + strncpy(mountdir, block.message.data.reserved, 235); + add_filesys_unit(mountpoint, mountdir, 1); + break; + case A_uaeask: + sendtofront(block.message.data.reserved); + break; + } +} + +void gui_process(void) +{ + wimp_event_no event; + + while(uae_running==0) + { + event=wimp_poll(wimp_MASK_NULL, &block, 0); + + switch(event) + { + case wimp_USER_MESSAGE: + case wimp_USER_MESSAGE_RECORDED: + gui_messagereceive(); + break; + } + } +} + +void gui_exit(void) +{ +} + +void gui_led(int led, int on) +{ +} + +void gui_filename(int num, char *name) +{ +} + +void gui_handle_events(void) +{ +} + +int gui_update(void) +{ +} + diff --git a/savestate.c b/savestate.c new file mode 100755 index 00000000..bf4a5f98 --- /dev/null +++ b/savestate.c @@ -0,0 +1,1244 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Save/restore emulator state + * + * (c) 1999-2001 Toni Wilen + * + * see below for ASF-structure + */ + + /* Features: + * + * - full CPU state (68000/68010/68020) + * - FPU + * - full CIA-A and CIA-B state (with all internal registers) + * - saves all custom registers and audio internal state. + * - Chip, Bogo, Fast, Z3 and Picasso96 RAM supported + * - disk drive type, imagefile, track and motor state + * - Kickstart ROM version, address and size is saved. This data is not used during restore yet. + * - Action Replay state is saved + */ + + /* Notes: + * + * - blitter state is not saved, blitter is forced to finish immediately if it + * was active + * - disk DMA state is completely saved + * - does not ask for statefile name and description. Currently uses DF0's disk + * image name (".adf" is replaced with ".asf") + * - only Amiga state is restored, harddisk support, autoconfig, expansion boards etc.. + * are not saved/restored (and probably never will). + * - use this for saving games that can't be saved to disk + */ + + /* Usage : + * + * save: + * + * set savestate_state = STATE_DOSAVE, savestate_filename = "..." + * + * restore: + * + * set savestate_state = STATE_DORESTORE, savestate_filename = "..." + * + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "memory.h" +#include "zfile.h" +#include "ar.h" +#include "autoconf.h" +#include "custom.h" +#include "newcpu.h" +#include "savestate.h" +#include "uae.h" + +int savestate_state; + +#define MAX_STATERECORDS 1024 /* must be power of 2 */ +struct staterecord { + uae_u8 *start; + uae_u8 *end; + uae_u8 *next; + uae_u8 *cpu; +}; +static int replaycounter; +static int replaylastreloaded = -1; +static int frameextra; + +struct zfile *savestate_file; +static uae_u8 *replaybuffer, *replaybufferend; +static int savestate_docompress, savestate_ramdump; +static int replaybuffersize; + +char savestate_fname[MAX_PATH]; +static struct staterecord staterecords[MAX_STATERECORDS]; + +static unsigned long crc_table[256]; +static void make_crc_table() +{ + unsigned long c; + int n, k; + for (n = 0; n < 256; n++) + { + c = (unsigned long)n; + for (k = 0; k < 8; k++) c = (c >> 1) ^ (c & 1 ? 0xedb88320L : 0); + crc_table[n] = c; + } +} +uae_u32 CRC32(uae_u32 crc, const uae_u8 *buf, int len) +{ + if (!crc_table[1]) make_crc_table(); + crc = crc ^ 0xffffffffL; + while (len-- > 0) { + crc = crc_table[(crc ^ (*buf++)) & 0xff] ^ (crc >> 8); + } + return crc ^ 0xffffffffL; +} + +/* functions for reading/writing bytes, shorts and longs in big-endian + * format independent of host machine's endianess */ + +void save_u32_func (uae_u8 **dstp, uae_u32 v) +{ + uae_u8 *dst = *dstp; + *dst++ = (uae_u8)(v >> 24); + *dst++ = (uae_u8)(v >> 16); + *dst++ = (uae_u8)(v >> 8); + *dst++ = (uae_u8)(v >> 0); + *dstp = dst; +} +void save_u16_func (uae_u8 **dstp, uae_u16 v) +{ + uae_u8 *dst = *dstp; + *dst++ = (uae_u8)(v >> 8); + *dst++ = (uae_u8)(v >> 0); + *dstp = dst; +} +void save_u8_func (uae_u8 **dstp, uae_u8 v) +{ + uae_u8 *dst = *dstp; + *dst++ = v; + *dstp = dst; +} +void save_string_func (uae_u8 **dstp, char *from) +{ + uae_u8 *dst = *dstp; + while(*from) + *dst++ = *from++; + *dst++ = 0; + *dstp = dst; +} + +uae_u32 restore_u32_func (uae_u8 **dstp) +{ + uae_u32 v; + uae_u8 *dst = *dstp; + v = (dst[0] << 24) | (dst[1] << 16) | (dst[2] << 8) | (dst[3]); + *dstp = dst + 4; + return v; +} +uae_u16 restore_u16_func (uae_u8 **dstp) +{ + uae_u16 v; + uae_u8 *dst = *dstp; + v=(dst[0] << 8) | (dst[1]); + *dstp = dst + 2; + return v; +} +uae_u8 restore_u8_func (uae_u8 **dstp) +{ + uae_u8 v; + uae_u8 *dst = *dstp; + v = dst[0]; + *dstp = dst + 1; + return v; +} +char *restore_string_func (uae_u8 **dstp) +{ + int len; + uae_u8 v; + uae_u8 *dst = *dstp; + char *top, *to; + len = strlen(dst) + 1; + top = to = malloc (len); + do { + v = *dst++; + *top++ = v; + } while(v); + *dstp = dst; + return to; +} + +/* read and write IFF-style hunks */ + +static void save_chunk (struct zfile *f, uae_u8 *chunk, long len, char *name, int compress) +{ + uae_u8 tmp[8], *dst; + uae_u8 zero[4]= { 0, 0, 0, 0 }; + uae_u32 flags; + size_t pos; + long chunklen, len2; + + if (!chunk) + return; + + if (compress < 0) { + zfile_fwrite (chunk, 1, len, f); + return; + } + + /* chunk name */ + zfile_fwrite (name, 1, 4, f); + pos = zfile_ftell (f); + /* chunk size */ + dst = &tmp[0]; + chunklen = len + 4 + 4 + 4; + save_u32 (chunklen); + zfile_fwrite (&tmp[0], 1, 4, f); + /* chunk flags */ + flags = 0; + dst = &tmp[0]; + save_u32 (flags | compress); + zfile_fwrite (&tmp[0], 1, 4, f); + /* chunk data */ + if (compress) { + int tmplen = len; + dst = &tmp[0]; + save_u32 (len); + zfile_fwrite (&tmp[0], 1, 4, f); + len = zfile_zcompress (f, chunk, len); + if (len > 0) { + zfile_fseek (f, pos, SEEK_SET); + dst = &tmp[0]; + save_u32 (len + 4 + 4 + 4 + 4); + zfile_fwrite (&tmp[0], 1, 4, f); + zfile_fseek (f, 0, SEEK_END); + } else { + len = tmplen; + compress = 0; + zfile_fseek (f, -8, SEEK_CUR); + dst = &tmp[0]; + save_u32 (flags); + zfile_fwrite (&tmp[0], 1, 4, f); + } + } + if (!compress) + zfile_fwrite (chunk, 1, len, f); + /* alignment */ + len2 = 4 - (len & 3); + if (len2) + zfile_fwrite (zero, 1, len2, f); + + write_log ("Chunk '%s' chunk size %d (%d)\n", name, chunklen, len); +} + +static uae_u8 *restore_chunk (struct zfile *f, char *name, long *len, long *totallen, long *filepos) +{ + uae_u8 tmp[4], dummy[4], *mem, *src; + uae_u32 flags; + long len2; + + /* chunk name */ + zfile_fread (name, 1, 4, f); + name[4] = 0; + /* chunk size */ + zfile_fread (tmp, 1, 4, f); + src = tmp; + len2 = restore_u32 () - 4 - 4 - 4; + if (len2 < 0) + len2 = 0; + *len = len2; + if (len2 == 0) + return 0; + + /* chunk flags */ + zfile_fread (tmp, 1, 4, f); + src = tmp; + flags = restore_u32 (); + *totallen = *len; + if (flags & 1) { + zfile_fread (tmp, 1, 4, f); + src = tmp; + *totallen = restore_u32(); + *filepos = zfile_ftell (f) - 4 - 4 - 4; + len2 -= 4; + } else { + *filepos = zfile_ftell (f) - 4 - 4; + } + /* chunk data. RAM contents will be loaded during the reset phase, + no need to malloc multiple megabytes here. */ + if (strcmp (name, "CRAM") != 0 + && strcmp (name, "BRAM") != 0 + && strcmp (name, "FRAM") != 0 + && strcmp (name, "ZRAM") != 0 + && strcmp (name, "PRAM") != 0) + { + /* without zeros at the end old state files may not work */ + mem = calloc (1, len2 + 32); + zfile_fread (mem, 1, len2, f); + } else { + mem = 0; + zfile_fseek (f, len2, SEEK_CUR); + } + + /* alignment */ + len2 = 4 - (len2 & 3); + if (len2) + zfile_fread (dummy, 1, len2, f); + return mem; +} + +void restore_ram (long filepos, uae_u8 *memory) +{ + uae_u8 tmp[8]; + uae_u8 *src = tmp; + int size, fullsize; + uae_u32 flags; + + zfile_fseek (savestate_file, filepos, SEEK_SET); + zfile_fread (tmp, 1, sizeof(tmp), savestate_file); + size = restore_u32(); + flags = restore_u32(); + size -= 4 + 4 + 4; + if (flags & 1) { + zfile_fread (tmp, 1, 4, savestate_file); + src = tmp; + fullsize = restore_u32(); + size -= 4; + zfile_zuncompress (memory, fullsize, savestate_file, size); + } else { + zfile_fread (memory, 1, size, savestate_file); + } +} + +static void restore_header (uae_u8 *src) +{ + char *emuname, *emuversion, *description; + + restore_u32(); + emuname = restore_string (); + emuversion = restore_string (); + description = restore_string (); + write_log ("Saved with: '%s %s', description: '%s'\n", + emuname,emuversion,description); + free (description); + free (emuversion); + free (emuname); +} + +/* restore all subsystems */ + +void restore_state (char *filename) +{ + struct zfile *f; + uae_u8 *chunk,*end; + char name[5], prevchunk[5]; + long len, totallen; + long filepos; + + chunk = 0; + f = zfile_fopen (filename, "rb"); + if (!f) + goto error; + savestate_init (); + + chunk = restore_chunk (f, name, &len, &totallen, &filepos); + if (!chunk || memcmp (name, "ASF ", 4)) { + write_log ("%s is not an AmigaStateFile\n",filename); + goto error; + } + savestate_file = f; + restore_header (chunk); + free (chunk); + changed_prefs.bogomem_size = 0; + changed_prefs.chipmem_size = 0; + changed_prefs.fastmem_size = 0; + savestate_state = STATE_RESTORE; + prevchunk[0] = 0; + for (;;) { + chunk = end = restore_chunk (f, name, &len, &totallen, &filepos); + if (!strcmp (name, prevchunk)) + break; + strcpy (prevchunk, name); + write_log ("Chunk '%s' size %d\n", name, len); + if (!strcmp (name, "END ")) + break; + if (!strcmp (name, "CRAM")) { + restore_cram (totallen, filepos); + continue; + } else if (!strcmp (name, "BRAM")) { + restore_bram (totallen, filepos); + continue; +#ifdef AUTOCONFIG + } else if (!strcmp (name, "FRAM")) { + restore_fram (totallen, filepos); + continue; + } else if (!strcmp (name, "ZRAM")) { + restore_zram (totallen, filepos); + continue; +#endif +#ifdef PICASSO96 + } else if (!strcmp (name, "PRAM")) { + restore_pram (totallen, filepos); + continue; +#endif + } else if (!strcmp (name, "CPU ")) + end = restore_cpu (chunk); +#ifdef FPUEMU + else if (!strcmp (name, "FPU ")) + end = restore_fpu (chunk); +#endif + else if (!strcmp (name, "AGAC")) + end = restore_custom_agacolors (chunk); + else if (!strcmp (name, "SPR0")) + end = restore_custom_sprite (0, chunk); + else if (!strcmp (name, "SPR1")) + end = restore_custom_sprite (1, chunk); + else if (!strcmp (name, "SPR2")) + end = restore_custom_sprite (2, chunk); + else if (!strcmp (name, "SPR3")) + end = restore_custom_sprite (3, chunk); + else if (!strcmp (name, "SPR4")) + end = restore_custom_sprite (4, chunk); + else if (!strcmp (name, "SPR5")) + end = restore_custom_sprite (5, chunk); + else if (!strcmp (name, "SPR6")) + end = restore_custom_sprite (6, chunk); + else if (!strcmp (name, "SPR7")) + end = restore_custom_sprite (7, chunk); + else if (!strcmp (name, "CIAA")) + end = restore_cia (0, chunk); + else if (!strcmp (name, "CIAB")) + end = restore_cia (1, chunk); + else if (!strcmp (name, "CHIP")) + end = restore_custom (chunk); + else if (!strcmp (name, "AUD0")) + end = restore_audio (0, chunk); + else if (!strcmp (name, "AUD1")) + end = restore_audio (1, chunk); + else if (!strcmp (name, "AUD2")) + end = restore_audio (2, chunk); + else if (!strcmp (name, "AUD3")) + end = restore_audio (3, chunk); + else if (!strcmp (name, "BLIT")) + end = restore_blitter (chunk); + else if (!strcmp (name, "DISK")) + end = restore_floppy (chunk); + else if (!strcmp (name, "DSK0")) + end = restore_disk (0, chunk); + else if (!strcmp (name, "DSK1")) + end = restore_disk (1, chunk); + else if (!strcmp (name, "DSK2")) + end = restore_disk (2, chunk); + else if (!strcmp (name, "DSK3")) + end = restore_disk (3, chunk); + else if (!strcmp (name, "KEYB")) + end = restore_keyboard (chunk); +#ifdef AUTOCONFIG + else if (!strcmp (name, "EXPA")) + end = restore_expansion (chunk); +#endif + else if (!strcmp (name, "ROM ")) + end = restore_rom (chunk); +#ifdef PICASSO96 + else if (!strcmp (name, "P96 ")) + end = restore_p96 (chunk); +#endif +#ifdef ACTION_REPLAY + else if (!strcmp (name, "ACTR")) + end = restore_action_replay (chunk); +#endif + else + write_log ("unknown chunk '%s' size %d bytes\n", name, len); + if (len != end - chunk) + write_log ("Chunk '%s' total size %d bytes but read %d bytes!\n", + name, len, end - chunk); + free (chunk); + } + return; + + error: + savestate_state = 0; + savestate_file = 0; + if (chunk) + free (chunk); + if (f) + zfile_fclose (f); +} + +void savestate_restore_finish (void) +{ + if (savestate_state != STATE_RESTORE && savestate_state != STATE_REWIND) + return; + zfile_fclose (savestate_file); + savestate_file = 0; + savestate_state = 0; +} + +/* 1=compressed,2=not compressed,3=ram dump */ +void savestate_initsave (char *filename, int mode) +{ + strcpy (savestate_fname, filename); + savestate_docompress = (mode == 1) ? 1 : 0; + savestate_ramdump = (mode == 3) ? 1 : 0; +} + +static void save_rams (struct zfile *f, int comp) +{ + uae_u8 *dst; + int len; + + dst = save_cram (&len); + save_chunk (f, dst, len, "CRAM", comp); + dst = save_bram (&len); + save_chunk (f, dst, len, "BRAM", comp); +#ifdef AUTOCONFIG + dst = save_fram (&len); + save_chunk (f, dst, len, "FRAM", comp); + dst = save_zram (&len); + save_chunk (f, dst, len, "ZRAM", comp); +#endif +#ifdef PICASSO96 + dst = save_pram (&len); + save_chunk (f, dst, len, "PRAM", comp); + dst = save_p96 (&len, 0); + save_chunk (f, dst, len, "P96 ", comp); +#endif +} + +/* Save all subsystems */ + +void save_state (char *filename, char *description) +{ + uae_u8 header[1000]; + char tmp[100]; + uae_u8 *dst; + struct zfile *f; + int len,i; + char name[5]; + int comp = savestate_docompress; + +#ifdef FILESYS + if (nr_units (currprefs.mountinfo)) { + gui_message("WARNING: State saves do not support harddrive emulation"); + } +#endif + + custom_prepare_savestate (); + f = zfile_fopen (filename, "wb"); + if (!f) + return; + if (savestate_ramdump) { + save_rams (f, -1); + zfile_fclose (f); + return; + } + + dst = header; + save_u32 (0); + save_string("UAE"); + sprintf (tmp, "%d.%d.%d", UAEMAJOR, UAEMINOR, UAESUBREV); + save_string (tmp); + save_string (description); + save_chunk (f, header, dst-header, "ASF ", 0); + + dst = save_cpu (&len, 0); + save_chunk (f, dst, len, "CPU ", 0); + free (dst); + +#ifdef FPUEMU + dst = save_fpu (&len,0 ); + save_chunk (f, dst, len, "FPU ", 0); + free (dst); +#endif + + strcpy(name, "DSKx"); + for (i = 0; i < 4; i++) { + dst = save_disk (i, &len, 0); + if (dst) { + name[3] = i + '0'; + save_chunk (f, dst, len, name, 0); + free (dst); + } + } + dst = save_floppy (&len, 0); + save_chunk (f, dst, len, "DISK", 0); + free (dst); + + dst = save_custom (&len, 0, 0); + save_chunk (f, dst, len, "CHIP", 0); + free (dst); + + dst = save_blitter (&len, 0); + save_chunk (f, dst, len, "BLIT", 0); + free (dst); + + dst = save_custom_agacolors (&len, 0); + save_chunk (f, dst, len, "AGAC", 0); + free (dst); + + strcpy (name, "SPRx"); + for (i = 0; i < 8; i++) { + dst = save_custom_sprite (i, &len, 0); + name[3] = i + '0'; + save_chunk (f, dst, len, name, 0); + free (dst); + } + + strcpy (name, "AUDx"); + for (i = 0; i < 4; i++) { + dst = save_audio (i, &len, 0); + name[3] = i + '0'; + save_chunk (f, dst, len, name, 0); + free (dst); + } + + dst = save_cia (0, &len, 0); + save_chunk (f, dst, len, "CIAA", 0); + free (dst); + + dst = save_cia (1, &len, 0); + save_chunk (f, dst, len, "CIAB", 0); + free (dst); + + dst = save_keyboard (&len); + save_chunk (f, dst, len, "KEYB", 0); + free (dst); + +#ifdef AUTOCONFIG + dst = save_expansion (&len, 0); + save_chunk (f, dst, len, "EXPA", 0); +#endif + save_rams (f, comp); + + dst = save_rom (1, &len, 0); + do { + if (!dst) + break; + save_chunk (f, dst, len, "ROM ", 0); + free (dst); + } while ((dst = save_rom (0, &len, 0))); + +#ifdef ACTION_REPLAY + dst = save_action_replay (&len, 0); + save_chunk (f, dst, len, "ACTR", 0); +#endif + + zfile_fwrite ("END ", 1, 4, f); + zfile_fwrite ("\0\0\0\08", 1, 4, f); + write_log ("Save of '%s' complete\n", filename); + zfile_fclose (f); + savestate_state = 0; +} + +void savestate_quick (int slot, int save) +{ + int i, len = strlen (savestate_fname); + i = len - 1; + while (i >= 0 && savestate_fname[i] != '_') + i--; + if (i < len - 6 || i <= 0) { /* "_?.uss" */ + i = len - 1; + while (i >= 0 && savestate_fname[i] != '.') + i--; + if (i <= 0) + return; + } + strcpy (savestate_fname + i, ".uss"); + if (slot > 0) + sprintf (savestate_fname + i, "_%d.uss", slot); + if (save) { + savestate_docompress = 1; + save_state (savestate_fname, ""); + } else { + if (!zfile_exists (savestate_fname)) + return; + savestate_state = STATE_DORESTORE; + } +} + +static struct staterecord *canrewind (int pos) +{ + int i; + struct staterecord *st; + + if (!replaybuffer) + return 0; + i = replaycounter; + st = &staterecords[i]; + if (st->start) + return st; + return 0; +} + +int savestate_dorewind (int pos) +{ + if (canrewind (pos)) { + savestate_state = STATE_DOREWIND; + return 1; + } + return 0; +} + +void savestate_listrewind (void) +{ + int i = replaycounter; + int cnt; + uae_u8 *p; + uae_u32 pc; + + cnt = 1; + for (;;) { + struct staterecord *st; + st = &staterecords[i]; + if (!st->start) + break; + p = st->cpu + 17 * 4; + pc = restore_u32_func (&p); + console_out ("%d: PC=%08X %c\n", cnt, pc, regs.pc == pc ? '*' : ' '); + cnt++; + i--; + if (i < 0) + i += MAX_STATERECORDS; + } +} + +void savestate_rewind (void) +{ + int len, i, dummy; + uae_u8 *p, *p2; + struct staterecord *st; + + st = canrewind (1); + if (!st) + return; + frameextra = timeframes % currprefs.statecapturerate; + p = st->start; + p2 = st->end; + write_log ("rewinding from %d\n", replaycounter); + p = restore_cpu (p); +#ifdef FPUEMU + if (restore_u32_func (&p)) + p = restore_fpu (p); +#endif + for (i = 0; i < 4; i++) { + p = restore_disk (i, p); + } + p = restore_floppy (p); + p = restore_custom (p); + p = restore_blitter (p); + p = restore_custom_agacolors (p); + for (i = 0; i < 8; i++) { + p = restore_custom_sprite (i, p); + } + for (i = 0; i < 4; i++) { + p = restore_audio (i, p); + } + p = restore_cia (0, p); + p = restore_cia (1, p); +#ifdef AUTOCONFIG + p = restore_expansion (p); +#endif + len = restore_u32_func (&p); + memcpy (chipmemory, p, currprefs.chipmem_size > len ? len : currprefs.chipmem_size); + p += len; + len = restore_u32_func (&p); + memcpy (save_bram (&dummy), p, currprefs.bogomem_size > len ? len : currprefs.bogomem_size); + p += len; +#ifdef AUTOCONFIG + len = restore_u32_func (&p); + memcpy (save_fram (&dummy), p, currprefs.fastmem_size > len ? len : currprefs.fastmem_size); + p += len; + len = restore_u32_func (&p); + memcpy (save_zram (&dummy), p, currprefs.z3fastmem_size > len ? len : currprefs.z3fastmem_size); + p += len; +#endif +#ifdef ACTION_REPLAY + if (restore_u32_func (&p)) + p = restore_action_replay (p); +#endif + p += 4; + if (p != p2) { + gui_message ("reload failure, address mismatch %p != %p", p, p2); + uae_reset (0); + return; + } + st->start = st->next = 0; + replaycounter--; + if (replaycounter < 0) + replaycounter += MAX_STATERECORDS; +} + +#define BS 10000 + +static int bufcheck (uae_u8 **pp, int len) +{ + uae_u8 *p = *pp; + if (p + len + BS >= replaybuffer + replaybuffersize) { + //write_log ("capture buffer wrap-around\n"); + return 1; + } + return 0; +} + +void savestate_capture (int force) +{ + uae_u8 *p, *p2, *p3, *dst; + int i, len, tlen, retrycnt; + struct staterecord *st, *stn; + +#ifdef FILESYS + if (nr_units (currprefs.mountinfo)) + return; +#endif + if (!replaybuffer) + return; + if (!force && (!currprefs.statecapture || !currprefs.statecapturerate || ((timeframes + frameextra) % currprefs.statecapturerate))) + return; + + retrycnt = 0; +retry2: + st = &staterecords[replaycounter]; + if (st->next == 0) { + replaycounter = 0; + st = &staterecords[replaycounter]; + st->next = replaybuffer; + } + stn = &staterecords[(replaycounter + 1) & (MAX_STATERECORDS - 1)]; + p = p2 = st->next; + tlen = 0; + if (bufcheck (&p, 0)) + goto retry; + stn->cpu = p; + save_cpu (&len, p); + tlen += len; + p += len; +#ifdef FPUEMU + if (bufcheck (&p, 0)) + goto retry; + p3 = p; + save_u32_func (&p, 0); + tlen += 4; + if (save_fpu (&len, p)) { + save_u32_func (&p3, 1); + tlen += len; + p += len; + } +#endif + for (i = 0; i < 4; i++) { + if (bufcheck (&p, 0)) + goto retry; + save_disk (i, &len, p); + tlen += len; + p += len; + } + if (bufcheck (&p, 0)) + goto retry; + save_floppy (&len, p); + tlen += len; + p += len; + if (bufcheck (&p, 0)) + goto retry; + save_custom (&len, p, 0); + tlen += len; + p += len; + if (bufcheck (&p, 0)) + goto retry; + save_blitter (&len, p); + tlen += len; + p += len; + if (bufcheck (&p, 0)) + goto retry; + save_custom_agacolors (&len, p); + tlen += len; + p += len; + for (i = 0; i < 8; i++) { + if (bufcheck (&p, 0)) + goto retry; + save_custom_sprite (i, &len, p); + tlen += len; + p += len; + } + for (i = 0; i < 4; i++) { + if (bufcheck (&p, 0)) + goto retry; + save_audio (i, &len, p); + tlen += len; + p += len; + } + if (bufcheck (&p, 0)) + goto retry; + save_cia (0, &len, p); + tlen += len; + p += len; + if (bufcheck (&p, 0)) + goto retry; + save_cia (1, &len, p); + tlen += len; + p += len; +#ifdef AUTOCONFIG + if (bufcheck (&p, 0)) + goto retry; + save_expansion (&len, p); + tlen += len; + p += len; +#endif + dst = save_cram (&len); + if (bufcheck (&p, len)) + goto retry; + save_u32_func (&p, len); + memcpy (p, dst, len); + tlen += len + 4; + p += len; + dst = save_bram (&len); + if (bufcheck (&p, len)) + goto retry; + save_u32_func (&p, len); + memcpy (p, dst, len); + tlen += len + 4; + p += len; +#ifdef AUTOCONFIG + dst = save_fram (&len); + if (bufcheck (&p, len)) + goto retry; + save_u32_func (&p, len); + memcpy (p, dst, len); + tlen += len + 4; + p += len; + dst = save_zram (&len); + if (bufcheck (&p, len)) + goto retry; + save_u32_func (&p, len); + memcpy (p, dst, len); + tlen += len + 4; + p += len; +#endif +#ifdef ACTION_REPLAY + if (bufcheck (&p, 0)) + goto retry; + p3 = p; + save_u32_func (&p, 0); + tlen += 4; + if (save_action_replay (&len, p)) { + save_u32_func (&p3, 1); + tlen += len; + p += len; + } +#endif + save_u32_func (&p, tlen); + stn->next = p; + stn->start = p2; + stn->end = p; + replaylastreloaded = -1; + replaycounter++; + replaycounter &= (MAX_STATERECORDS - 1); + i = (replaycounter + 1) & (MAX_STATERECORDS - 1); + staterecords[i].next = staterecords[i].start = 0; + i = replaycounter - 1; + while (i != replaycounter) { + if (i < 0) + i += MAX_STATERECORDS; + st = &staterecords[i]; + if (p2 <= st->start && p >= st->end) { + st->start = st->next = 0; + break; + } + i--; + } + //write_log ("state capture %d (%d bytes)\n", replaycounter, p - p2); + return; +retry: + staterecords[replaycounter].next = replaybuffer; + retrycnt++; + if (retrycnt > 1) { + write_log ("can't save, too small capture buffer\n"); + return; + } + goto retry2; +} + +void savestate_free (void) +{ + free (replaybuffer); + replaybuffer = 0; +} + +void savestate_init (void) +{ + savestate_free (); + memset (staterecords, 0, sizeof (staterecords)); + replaycounter = 0; + replaylastreloaded = -1; + frameextra = 0; + if (currprefs.statecapture && currprefs.statecapturebuffersize && currprefs.statecapturerate) { + replaybuffersize = currprefs.statecapturebuffersize; + replaybuffer = malloc (replaybuffersize); + } +} + +/* + +My (Toni Wilen ) +proposal for Amiga-emulators' state-save format + +Feel free to comment... + +This is very similar to IFF-fileformat +Every hunk must end to 4 byte boundary, +fill with zero bytes if needed + +version 0.8 + +HUNK HEADER (beginning of every hunk) + + hunk name (4 ascii-characters) + hunk size (including header) + hunk flags + + bit 0 = chunk contents are compressed with zlib (maybe RAM chunks only?) + +HEADER + + "ASF " (AmigaStateFile) + + statefile version + emulator name ("uae", "fellow" etc..) + emulator version string (example: "0.8.15") + free user writable comment string + +CPU + + "CPU " + + CPU model 4 (68000,68010 etc..) + CPU typeflags bit 0=EC-model or not + D0-D7 8*4=32 + A0-A6 7*4=32 + PC 4 + unused 4 + 68000 prefetch (IRC) 2 + 68000 prefetch (IR) 2 + USP 4 + ISP 4 + SR/CCR 2 + flags 4 (bit 0=CPU was HALTed) + + CPU specific registers + + 68000: SR/CCR is last saved register + 68010: save also DFC,SFC and VBR + 68020: all 68010 registers and CAAR,CACR and MSP + etc.. + + DFC 4 (010+) + SFC 4 (010+) + VBR 4 (010+) + + CAAR 4 (020-030) + CACR 4 (020+) + MSP 4 (020+) + +FPU (only if used) + + "FPU " + + FPU model 4 (68881/68882/68040) + FPU typeflags 4 (keep zero) + + FP0-FP7 4+4+2 (80 bits) + FPCR 4 + FPSR 4 + FPIAR 4 + +MMU (when and if MMU is supported in future..) + + MMU model 4 (68851,68030,68040) + + // 68040 fields + + ITT0 4 + ITT1 4 + DTT0 4 + DTT1 4 + URP 4 + SRP 4 + MMUSR 4 + TC 2 + + +CUSTOM CHIPS + + "CHIP" + + chipset flags 4 OCS=0,ECSAGNUS=1,ECSDENISE=2,AGA=4 + ECSAGNUS and ECSDENISE can be combined + + DFF000-DFF1FF 352 (0x120 - 0x17f and 0x0a0 - 0xdf excluded) + + sprite registers (0x120 - 0x17f) saved with SPRx chunks + audio registers (0x0a0 - 0xdf) saved with AUDx chunks + +AGA COLORS + + "AGAC" + + AGA color 8 banks * 32 registers * + registers LONG (XRGB) = 1024 + +SPRITE + + "SPR0" - "SPR7" + + + SPRxPT 4 + SPRxPOS 2 + SPRxCTL 2 + SPRxDATA 2 + SPRxDATB 2 + AGA sprite DATA/DATB 3 * 2 * 2 + sprite "armed" status 1 + + sprites maybe armed in non-DMA mode + use bit 0 only, other bits are reserved + + +AUDIO + "AUD0" "AUD1" "AUD2" "AUD3" + + audio state 1 + machine mode + AUDxVOL 1 + irq? 1 + data_written? 1 + internal AUDxLEN 2 + AUDxLEN 2 + internal AUDxPER 2 + AUDxPER 2 + internal AUDxLC 4 + AUDxLC 4 + evtime? 4 + +BLITTER + + "BLIT" + + internal blitter state + + flags 4 + bit 0=blitter active + bit 1=fill carry bit + internal ahold 4 + internal bhold 4 + internal hsize 2 + internal vsize 2 + +CIA + + "CIAA" and "CIAB" + + BFE001-BFEF01 16*1 (CIAA) + BFD000-BFDF00 16*1 (CIAB) + + internal registers + + IRQ mask (ICR) 1 BYTE + timer latches 2 timers * 2 BYTES (LO/HI) + latched tod 3 BYTES (LO/MED/HI) + alarm 3 BYTES (LO/MED/HI) + flags 1 BYTE + bit 0=tod latched (read) + bit 1=tod stopped (write) + div10 counter 1 BYTE + +FLOPPY DRIVES + + "DSK0" "DSK1" "DSK2" "DSK3" + + drive state + + drive ID-word 4 + state 1 (bit 0: motor on, bit 1: drive disabled, bit 2: current id bit) + rw-head track 1 + dskready 1 + id-mode 1 (ID mode bit number 0-31) + floppy information + + bits from 4 + beginning of track + CRC of disk-image 4 (used during restore to check if image + is correct) + disk-image null-terminated + file name + +INTERNAL FLOPPY CONTROLLER STATUS + + "DISK" + + current DMA word 2 + DMA word bit offset 1 + WORDSYNC found 1 (no=0,yes=1) + hpos of next bit 1 + DSKLENGTH status 0=off,1=written once,2=written twice + unused 2 + +RAM SPACE + + "xRAM" (CRAM = chip, BRAM = bogo, FRAM = fast, ZFRAM = Z3) + + start address 4 ("bank"=chip/slow/fast etc..) + of RAM "bank" + RAM "bank" size 4 + RAM flags 4 (bit 0 = zlib compressed) + RAM "bank" contents + +ROM SPACE + + "ROM " + + ROM start 4 + address + size of ROM 4 + ROM type 4 KICK=0 + ROM flags 4 + ROM version 2 + ROM revision 2 + ROM CRC 4 see below + ROM-image ID-string null terminated, see below + path to rom image + ROM contents (Not mandatory, use hunk size to check if + this hunk contains ROM data or not) + + Kickstart ROM: + ID-string is "Kickstart x.x" + ROM version: version in high word and revision in low word + Kickstart ROM version and revision can be found from ROM start + + 12 (version) and +14 (revision) + + ROM version and CRC is only meant for emulator to automatically + find correct image from its ROM-directory during state restore. + + Usually saving ROM contents is not good idea. + + +END + hunk "END " ends, remember hunk size 8! + + +EMULATOR SPECIFIC HUNKS + +Read only if "emulator name" in header is same as used emulator. +Maybe useful for configuration? + +misc: + +- save only at position 0,0 before triggering VBLANK interrupt +- all data must be saved in bigendian format +- should we strip all paths from image file names? + +*/ diff --git a/scsi-none.c b/scsi-none.c new file mode 100755 index 00000000..a553ef90 --- /dev/null +++ b/scsi-none.c @@ -0,0 +1,20 @@ +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "threaddep/thread.h" +#include "options.h" +#include "memory.h" +#include "custom.h" +#include "newcpu.h" +#include "disk.h" +#include "autoconf.h" +#include "filesys.h" +#include "execlib.h" +#include "scsidev.h" + +uaecptr scsidev_startup (uaecptr resaddr) { return resaddr; } +void scsidev_install (void) {} +void scsidev_reset (void) {} +void scsidev_start_threads (void) {} + diff --git a/scsidev.c b/scsidev.c new file mode 100755 index 00000000..7840d9cf --- /dev/null +++ b/scsidev.c @@ -0,0 +1,819 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * a SCSI device + * + * Copyright 1995 Bernd Schmidt + * Copyright 1999 Patrick Ohly + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "threaddep/thread.h" +#include "options.h" +#include "memory.h" +#include "custom.h" +#include "newcpu.h" +#include "disk.h" +#include "autoconf.h" +#include "filesys.h" +#include "execlib.h" +#include "native2amiga.h" +#include "scsidev.h" + +#include + +/* the new libscg should always have a scsi_close */ +#ifndef SCSI_CLOSE +#define SCSI_CLOSE +#endif + +typedef int BOOL; + +#include "scg/scgcmd.h" +#include "scg/scsitransp.h" +#include "scg/scsireg.h" + +/* our configure does not have a seperate UAE_SCSIDEV_THREADS */ +#if defined(UAE_FILESYS_THREADS) && !defined(SCSI_IS_NOT_THREAD_SAFE) +#define UAE_SCSIDEV_THREADS +#endif + +#undef DEBUGME + +/****************** generic SCSI stuff stolen from cdrecord and scsitransp.c ***********/ +static int scsierr(SCSI *scgp) +{ + register struct scg_cmd *cp = scgp->scmd; + + if(cp->error != SCG_NO_ERROR || + cp->ux_errno != 0 || *(u_char *)&cp->scb != 0) + return -1; + return 0; +} + +static int inquiry (SCSI *scgp, void *bp, int cnt) +{ + struct scg_cmd *scmd = scgp->scmd; + + memset(bp, cnt, '\0'); + memset((caddr_t)scmd, sizeof(*scmd), '\0'); + scmd->addr = bp; + scmd->size = cnt; + scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; + scmd->cdb_len = SC_G0_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->target = scgp->target; + scmd->cdb.g0_cdb.cmd = SC_INQUIRY; + scmd->cdb.g0_cdb.lun = scgp->lun; + scmd->cdb.g0_cdb.count = cnt; + + scgp->cmdname = "inquiry"; + + if (scsicmd(scgp) < 0) + return (-1); + return (0); +} + +static void print_product(struct scsi_inquiry *ip) +{ + write_log ("'%.8s' ", ip->info); + write_log ("'%.16s' ", ip->ident); + write_log ("'%.4s' ", ip->revision); + if (ip->add_len < 31) { + write_log ("NON CCS "); + } +} + +/* get integer value from env or return default value, if unset */ +static int getenvint (const char *varname, int def) +{ + const char *val = getenv (varname); + return val ? atoi (val) : def; +} + +/* wrapper for the underlying combination of scsi_smalloc()/scsi_open() */ +static SCSI *openscsi (int scsibus, int target, int lun) +{ + SCSI *scgp = scsi_smalloc (); + if (!scgp) { + return NULL; + } + + scgp->debug = getenvint ("UAE_SCSI_DEBUG", 0); + scgp->kdebug = getenvint ("UAE_SCSI_KDEBUG", 0); + scgp->silent = getenvint ("UAE_SCSI_SILENT", 1); + scgp->verbose = getenvint ("UAE_SCSI_VERBOSE", 0); + scgp->scsibus = scsibus; + scgp->target = target; + scgp->lun = lun; + + if (!scsi_open(scgp, NULL, scsibus, target, lun)) { + scsi_sfree (scgp); + return NULL; + } else { + return scgp; + } +} + +static void closescsi (SCSI *scgp) +{ + scsi_close (scgp); + scsi_sfree (scgp); +} + +/********************* start of our own code ************************/ + +static int opencount = 0; +static SCSI *scgp; /* SCSI handle which is to be used by the main thread */ +uae_sem_t scgp_sem; + + +/****************** unit handling *******************/ + +struct scsidevdata { + int bus, target, lun; /* the real values */ + int aunit; /* Amiga unit number, by default calculated like that: */ +#define BTL2UNIT(bus, target, lun) \ + (2 * (bus) + (target) / 8) * 100 + \ + (lun) * 10 + \ + (target % 8) + SCSI *scgp; + long max_dma; + int isatapi; +#ifdef UAE_SCSIDEV_THREADS + /* Threading stuff */ + smp_comm_pipe requests; + uae_thread_id tid; + int thread_running; + uae_sem_t sync_sem; +#endif +}; + +#define MAX_DRIVES 16 +static struct scsidevdata drives[MAX_DRIVES]; +static int num_drives; +static struct scsidevdata *get_scsidev_data (int unit) +{ + int i; + + for (i = 0; i < num_drives; i++) { + if (unit == drives[i].aunit) { + return &drives[i]; + } + } + return NULL; +} + +static struct scsidevdata *add_scsidev_data (int bus, int target, int lun, int aunit) +{ + if (num_drives + 1 < MAX_DRIVES) { + memset(&drives[num_drives], 0, sizeof(drives[num_drives])); + drives[num_drives].bus = bus; + drives[num_drives].target = target; + drives[num_drives].lun = lun; + drives[num_drives].aunit = aunit; +#if !defined(UAE_SCSIDEV_THREADS) + drives[num_drives].scgp = scgp; + drives[num_drives].max_dma = scsi_bufsize (scgp, 512 * 1024); +#endif + /* check if this drive is an ATAPI drive */ + scgp->scsibus = bus; + scgp->target = target; + scgp->lun = lun; + drives[num_drives].isatapi = scsi_isatapi (scgp); + return &drives[num_drives++]; + } + + return NULL; +} + +static void *scsidev_thread(void *); +static int start_thread (struct scsidevdata *sdd) +{ +#ifdef UAE_SCSIDEV_THREADS + if (sdd->thread_running) + return 1; + init_comm_pipe (&sdd->requests, 10, 1); + uae_sem_init (&sdd->sync_sem, 0, 0); + uae_start_thread (scsidev_thread, sdd, &sdd->tid); + uae_sem_wait (&sdd->sync_sem); + return sdd->thread_running; +#else + return 1; +#endif +} + +/************* Exec device functions ****************/ + + +static uae_u32 scsidev_open (void) +{ + uaecptr tmp1 = m68k_areg(regs, 1); /* IOReq */ + uae_u32 unit = m68k_dreg (regs, 0); + struct scsidevdata *sdd; + +#ifdef DEBUGME + printf("scsidev_open(0x%x, %d)\n", tmp1, unit); +#endif + + /* Check unit number */ + if ((sdd = get_scsidev_data (unit)) && + start_thread (sdd)) { + opencount++; + put_word (m68k_areg(regs, 6)+32, get_word (m68k_areg(regs, 6)+32) + 1); + put_long (tmp1 + 24, unit); /* io_Unit */ + put_byte (tmp1 + 31, 0); /* io_Error */ + put_byte (tmp1 + 8, 7); /* ln_type = NT_REPLYMSG */ + return 0; + } + + put_long (tmp1 + 20, (uae_u32)-1); + put_byte (tmp1 + 31, (uae_u8)-1); + return (uae_u32)-1; +} + +static uae_u32 scsidev_close (void) +{ +#ifdef DEBUGME + printf("scsidev_close()\n"); +#endif + + opencount--; + put_word (m68k_areg(regs, 6) + 32, get_word (m68k_areg(regs, 6) + 32) - 1); + + return 0; +} + +static uae_u32 scsidev_expunge (void) +{ + #ifdef DEBUGME + printf("scsidev_expunge()\n"); +#endif + return 0; /* Simply ignore this one... */ +} + +#define MODE_SELECT_6 0x15 +#define MODE_SENSE_6 0x1A +#ifndef MODE_SENSE_10 +#define MODE_SELECT_10 0x55 +#define MODE_SENSE_10 0x5A +#endif + + +#ifdef DEBUG_CDR +/* please ignore this code - it can be used to debug raw CD-R writing... */ + +/* +** convert time in (BCD) min:sec:frame to block address +*/ +typedef signed char BYTE; +typedef unsigned char UBYTE; +typedef long LONG; +typedef BYTE BCD; +typedef BYTE WORD[2]; +#define BCD_DEC(x) (((x) >> 4) * 10 + ((x) & 0xF)) +static LONG TestNegativeTime(LONG block) +{ + /* block -151 == 99:59:74 + -150 == 100:00:00 = 00:00:00 */ + if (block > (97 * 60 * 75)) + { + /* must be a negative block */ + block -= 100 * 60 * 75; + } + return block; +} +static LONG BCDTime2Block(UBYTE min, UBYTE sec, UBYTE frame) +{ + return(TestNegativeTime((LONG)((BCD_DEC(min) * 60 + BCD_DEC(sec)) * 75 + BCD_DEC(frame) - 2 * 75))); +} +static LONG Time2Block(UBYTE min, UBYTE sec, UBYTE frame) +{ + return(TestNegativeTime((LONG)((min * 60 + sec) * 75 + frame - 2 * 75))); +} +static LONG BCDTime2Block_Pointer (UBYTE *p) +{ + return BCDTime2Block (p[0], p[1], p[2]); +} +static LONG Time2Block_Pointer (UBYTE *p) +{ + return Time2Block (p[0], p[1], p[2]); +} +#endif + +static void scsidev_do_scsi (struct scsidevdata *sdd, uaecptr request) +{ + SCSI *scgp = sdd->scgp; + struct scg_cmd *scmd = scgp->scmd; + uaecptr acmd = get_long (request + 40); + uaecptr scsi_data = get_long (acmd + 0); + uae_u32 scsi_len = get_long (acmd + 4); + uaecptr scsi_cmd = get_long (acmd + 12); + uae_u16 scsi_cmd_len = get_word (acmd + 16); + uae_u8 scsi_flags = get_byte (acmd + 20); + uaecptr scsi_sense = get_long (acmd + 22); + uae_u16 scsi_sense_len = get_word (acmd + 26); + int sactual = 0; + addrbank *bank_data = &get_mem_bank (scsi_data); + addrbank *bank_cmd = &get_mem_bank (scsi_cmd); + + /* do transfer directly to and from Amiga memory */ + if (!bank_data || !bank_data->check (scsi_data, scsi_len) || + !bank_cmd || !bank_cmd->check (scsi_cmd, scsi_cmd_len)) { + put_byte (request + 31, (uae_u8)-5); /* IOERR_BADADDRESS */ + return; + } + +#ifdef SCSI_IS_NOT_THREAD_SAFE + uae_sem_wait (&scgp_sem); +#endif + + scmd->timeout = 80 * 60; /* the Amiga does not tell us how long the timeout shall be, so make it _very_ long (specified in seconds) */ + scmd->addr = bank_data->xlateaddr (scsi_data); + scmd->size = scsi_len; + scmd->flags = ((scsi_flags & 1) ? SCG_RECV_DATA : 0) | SCG_DISRE_ENA; + scmd->cdb_len = scsi_cmd_len; + memcpy(&scmd->cdb, bank_cmd->xlateaddr (scsi_cmd), scsi_cmd_len); + scmd->target = sdd->target; + scmd->sense_len = (scsi_flags & 4) ? 4 : /* SCSIF_OLDAUTOSENSE */ + (scsi_flags & 2) ? scsi_sense_len : /* SCSIF_AUTOSENSE */ + -1; + scmd->sense_count = 0; + *(uae_u8 *)&scmd->scb = 0; + + #ifdef DEBUG_CDR + /* please ignore this code - it can be used to debug raw CD-R writing... */ + if (!(scsi_len % 2368)) { + /* Structure for generating bytes 2353...2368 if writing in ultra raw mode */ + typedef struct QDATAtag { + BYTE ControlAdr; + BCD Tno; + BCD Point; + BCD Min; + BCD Sec; + BCD Frame; + BYTE Zero; + BCD PMin; + BCD PSec; + BCD PFrame; + WORD Crc; + BYTE Reserved[3]; + BYTE PChannel; + } QDATA; + + int i = scsi_len / 2368; + QDATA *data = (QDATA *)&((unsigned char *)scmd->addr)[2352]; + for (; i > 0; i--, data = (QDATA *)&((unsigned char *)data)[2368]) { + printf ("$%02x: $%02x $%02x | $%02x:$%02x:$%02x = %6ld | $%02x | $%02x:$%02x:$%02x = %6ld\n", + (int)data->ControlAdr, (int)*(UBYTE *)&data->Tno, (int)*(UBYTE *)&data->Point, + (int)*(UBYTE *)&data->Min, (int)*(UBYTE *)&data->Sec, (int)*(UBYTE *)&data->Frame, + BCDTime2Block_Pointer (&data->Min) + 150, + *(UBYTE *)&data->Zero, + *(UBYTE *)&data->PMin, *(UBYTE *)&data->PSec, *(UBYTE *)&data->PFrame, + BCDTime2Block_Pointer (&data->PMin)); + } + fflush (stdout); + } + #endif + + scgp->scsibus = sdd->bus; + scgp->target = sdd->target; + scgp->lun = sdd->lun; + scgp->cmdname = "???"; + scgp->curcmdname = "???"; + + /* replace MODE_SELECT/SENSE_6 if we access a ATAPI drive, + otherwise send it now */ + if (sdd->isatapi && + (scmd->cdb.g0_cdb.cmd == MODE_SELECT_6 || + scmd->cdb.g0_cdb.cmd == MODE_SENSE_6)) { + uae_u8 buffer[256 + 2], *data = scmd->addr, *tmp; + int len = 0, page_len, i; + int do_it = 1; + uae_u8 sp = scmd->cdb.g0_cdb.high_addr & 1; + uae_u8 alloc_len = scmd->cdb.g0_cdb.count; + uae_u8 pcf_page_code = scmd->cdb.g0_cdb.mid_addr; + uae_u8 cmd = scmd->cdb.g0_cdb.cmd; + + memset (&scmd->cdb.g1_cdb, 0, sizeof(scmd->cdb.g1_cdb)); + if (cmd == MODE_SELECT_6) { + /* expand parameter list */ + tmp = data; + buffer[len++] = *tmp++; /* first byte, should be 0 */ + buffer[len++] = 0; /* reserved */ + buffer[len++] = *tmp++; /* medium type */ + buffer[len++] = 0; *tmp++; /* ignore host application code */ + for (i = 0; i < 4; i++) { + buffer[len++] = 0; + } + if (*tmp) { + /* skip block descriptor */ + tmp += 8; + } + tmp++; + page_len = scsi_len - (tmp - data); + if (page_len > 0) { + memcpy (&buffer[len], tmp, page_len); + len += page_len; + + scmd->cdb.g1_cdb.cmd = MODE_SELECT_10; + scmd->cdb.g1_cdb.lun = sdd->lun; + scmd->cdb.g1_cdb.res = 1 << 3; /* PF bit */ + scmd->cdb.g1_cdb.reladr = sp; + scmd->cdb.g1_cdb.count[0] = len >> 8; + scmd->cdb.g1_cdb.count[1] = len; + } else { + do_it = 0; + scmd->error = 0; + *(uae_u8 *)&scmd->scb = 0; + scmd->ux_errno = 0; + } + } else { + /* MODE_SENSE_6 */ + len = alloc_len + 2; + scmd->cdb.g1_cdb.cmd = MODE_SENSE_10; + scmd->cdb.g1_cdb.lun = sdd->lun; + scmd->cdb.g1_cdb.addr[0] = pcf_page_code; + scmd->cdb.g1_cdb.count[0] = len >> 8; + scmd->cdb.g1_cdb.count[1] = len; + } + if (do_it) { + scmd->cdb_len = 10; + scmd->addr = buffer; + scmd->size = len; + scmd->sense_count = 0; + *(uae_u8 *)&scmd->scb = 0; + + scsicmd (scgp); + + if (cmd == MODE_SENSE_6 && + !scmd->error && + !scmd->ux_errno && + !*(uae_u8 *)&scmd->scb) { + int req_len = len; + + /* compress result */ + tmp = buffer; + len = 0; + tmp++; /* skip first byte of length - should better be zero */ + data[len++] = *tmp++; /* mode data length */ + data[len++] = *tmp++; /* medium type */ + data[len++] = 0; /* host application type */ + data[len++] = 0; /* block descr length */ + tmp += 4; + if (*tmp) { + /* skip block descr - should not happen */ + tmp += *tmp; + } + tmp++; + memcpy (&data[len], tmp, req_len - (tmp - buffer)); + } + } + } else { + scsicmd (scgp); + } + + put_word (acmd + 18, scmd->error == SCG_FATAL ? 0 : scsi_cmd_len); /* fake scsi_CmdActual */ + put_byte (acmd + 21, *(uae_u8 *)&scmd->scb); /* scsi_Status */ + if (*(uae_u8 *)&scmd->scb) { + put_byte (request + 31, 45); /* HFERR_BadStatus */ + + /* copy sense? */ + for (sactual = 0; + scsi_sense && sactual < scsi_sense_len && sactual < scmd->sense_count; + sactual++) { + put_byte (scsi_sense + sactual, scmd->u_sense.cmd_sense[sactual]); + } + put_long (acmd + 8, 0); /* scsi_Actual */ + } else { + int i; + + for (i = 0; i < scsi_sense_len; i++) { + put_byte (scsi_sense + i, 0); + } + sactual = 0; + + if (scmd->error != SCG_NO_ERROR || + scmd->ux_errno != 0) { + /* we might have been limited by the hosts DMA limits, + which is usually indicated by ENOMEM */ + if (scsi_len > (unsigned int)sdd->max_dma && + scmd->ux_errno == ENOMEM) { + put_byte (request + 31, (uae_u8)-4); /* IOERR_BADLENGTH */ + } else { + put_byte (request + 31, 20); /* io_Error, but not specified */ + put_long (acmd + 8, 0); /* scsi_Actual */ + } + } else { + put_byte (request + 31, 0); + put_long (acmd + 8, scsi_len - scmd->resid); /* scsi_Actual */ + } + } + put_word (acmd + 28, sactual); + +#ifdef SCSI_IS_NOT_THREAD_SAFE + uae_sem_post (&scgp_sem); +#endif +} + +static void scsidev_do_io (struct scsidevdata *sdd, uaecptr request) +{ + uae_u32 tmp2, dataptr, offset; + + tmp2 = get_word (request+28); /* io_Command */ + switch (tmp2) { + case 28: + /* HD_SCSICMD */ + scsidev_do_scsi (sdd, request); + break; + default: + /* Command not understood. */ + put_byte (request+31, (uae_u8)-3); /* io_Error */ + break; + } +#ifdef DEBUGME + printf ("scsidev: did io: sdd = 0x%x\n", sdd); + printf ("scsidev: did io: request = %08lx\n", (unsigned long)request); + printf ("scsidev: did io: error = %d\n", (int)get_word(request+31)); +#endif +} + + +static uae_u32 scsidev_beginio (void) +{ + uae_u32 request = m68k_areg(regs, 1); + int unit = get_long (request + 24); + struct scsidevdata *sdd = get_scsidev_data (unit); + +#ifdef DEBUGME + printf ("scsidev_begin_io: sdd = 0x%x\n", sdd); + printf ("scsidev_begin_io: request = %08lx\n", (unsigned long)request); + printf ("scsidev_begin_io: cmd = %d\n", (int)get_word(request+28)); +#endif + + put_byte (request+8, NT_MESSAGE); + put_byte (request+31, 0); /* no error yet */ + +#ifdef UAE_SCSIDEV_THREADS + { + uae_pt data; + + /* clear IOF_QUICK */ + put_byte (request+30, get_byte (request+30) & ~1); + /* forward to unit thread */ + write_comm_pipe_u32 (&sdd->requests, request, 1); + return 0; + } +#else + put_byte (request+30, get_byte (request+30) & ~1); + scsidev_do_io (sdd, request); + return get_byte (request+31); /* do we really have to return io_Error? */ +#endif +} + +#ifdef UAE_SCSIDEV_THREADS +static void *scsidev_thread (void *sddv) +{ + struct scsidevdata *sdd = sddv; + +#ifdef DEBUGME + printf ("scsidev_penguin: sdd = 0x%x ready\n", sdd); +#endif + /* init SCSI */ + if (!(sdd->scgp = openscsi (sdd->bus, sdd->target, sdd->lun)) || + (sdd->max_dma = scsi_bufsize (sdd->scgp, 512 * 1024)) <= 0) { + sdd->thread_running = 0; + uae_sem_post (&sdd->sync_sem); + return 0; + } + sdd->thread_running = 1; + uae_sem_post (&sdd->sync_sem); + + for (;;) { + uaecptr request; + + request = (uaecptr)read_comm_pipe_u32_blocking (&sdd->requests); +#ifdef DEBUGME + printf ("scsidev_penguin: sdd = 0x%x\n", sdd); + printf ("scsidev_penguin: req = %08lx\n", (unsigned long)request); + printf ("scsidev_penguin: cmd = %d\n", (int)get_word(request+28)); +#endif + if (!request) { + printf ("scsidev_penguin: going down with 0x%x\n", sdd->sync_sem); + /* Death message received. */ + sdd->thread_running = 0; + uae_sem_post (&sdd->sync_sem); + /* Die. */ + return 0; + } + + scsidev_do_io (sdd, request); + uae_ReplyMsg (request); + } + return 0; +} +#endif + + +static uae_u32 scsidev_abortio (void) +{ + return (uae_u32)-3; +} + +static uae_u32 scsidev_init (void) +{ +#ifdef DEBUGME + printf("scsidev_init()\n"); +#endif + + if (scgp) { + /* we still have everything in place */ + return m68k_dreg (regs, 0); /* device base */ + } + + /* init global SCSI */ + if (!(scgp = openscsi (-1, -1, -1))) { + return 0; + } + + uae_sem_init (&scgp_sem, 0, 1); + + /* add all units we find */ + for (scgp->scsibus=0; scgp->scsibus < 8; scgp->scsibus++) { + if (!scsi_havebus(scgp, scgp->scsibus)) + continue; + printf("scsibus%d:\n", scgp->scsibus); + for (scgp->target=0; scgp->target < 16; scgp->target++) { + struct scsi_inquiry inq; + scgp->lun = 0; + if (inquiry (scgp, &inq, sizeof(inq))) { + continue; + } + for (scgp->lun=0; scgp->lun < 8; scgp->lun++) { + if (!inquiry (scgp, &inq, sizeof(inq))) { + int aunit = BTL2UNIT(scgp->scsibus, scgp->target, scgp->lun); + struct scsidevdata *sdd; + + write_log (" %2.01d,%d (= %3.d): ", scgp->target, scgp->lun, aunit); + print_product (&inq); + sdd = add_scsidev_data (scgp->scsibus, scgp->target, scgp->lun, aunit); + write_log (!sdd ? " - init failed ???" : sdd->isatapi ? " - ATAPI" : " - SCSI"); + write_log ("\n"); + } + } + } + } + return m68k_dreg (regs, 0); /* device base */ +} + +static uaecptr ROM_scsidev_resname = 0, + ROM_scsidev_resid = 0, + ROM_scsidev_init = 0; + +uaecptr scsidev_startup (uaecptr resaddr) +{ +#ifdef DEBUGME + printf("scsidev_startup(0x%x)\n", resaddr); +#endif + /* Build a struct Resident. This will set up and initialize + * the uaescsi.device */ + put_word(resaddr + 0x0, 0x4AFC); + put_long(resaddr + 0x2, resaddr); + put_long(resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */ + put_word(resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */ + put_word(resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */ + put_long(resaddr + 0xE, ROM_scsidev_resname); + put_long(resaddr + 0x12, ROM_scsidev_resid); + put_long(resaddr + 0x16, ROM_scsidev_init); /* calls scsidev_init */ + resaddr += 0x1A; + + return resaddr; +} + +void scsidev_install (void) +{ + uae_u32 functable, datatable; + uae_u32 initcode, openfunc, closefunc, expungefunc; + uae_u32 beginiofunc, abortiofunc; + +#ifdef DEBUGME + printf("scsidev_install(): 0x%x\n", here ()); +#endif + + ROM_scsidev_resname = ds ("uaescsi.device"); + ROM_scsidev_resid = ds ("UAE scsi.device 0.1"); + + /* initcode */ + initcode = here (); + calltrap (deftrap (scsidev_init)); dw (RTS); + + /* Open */ + openfunc = here (); + calltrap (deftrap (scsidev_open)); dw (RTS); + + /* Close */ + closefunc = here (); + calltrap (deftrap (scsidev_close)); dw (RTS); + + /* Expunge */ + expungefunc = here (); + calltrap (deftrap (scsidev_expunge)); dw (RTS); + + /* BeginIO */ + beginiofunc = here (); + calltrap (deftrap (scsidev_beginio)); +#ifndef UAE_SCSIDEV_THREADS + /* don't reply when using threads - native2amiga's Reply() does that */ + dw (0x48E7); dw (0x8002); /* movem.l d0/a6,-(a7) */ + dw (0x0829); dw (0); dw (30); /* btst #0,30(a1) */ + dw (0x6608); /* bne.b +8 */ + dw (0x2C78); dw (0x0004); /* move.l 4,a6 */ + dw (0x4EAE); dw (-378); /* jsr ReplyMsg(a6) */ + dw (0x4CDF); dw (0x4001); /* movem.l (a7)+,d0/a6 */ +#endif + dw (RTS); + + /* AbortIO */ + abortiofunc = here (); + calltrap (deftrap (scsidev_abortio)); dw (RTS); + + /* FuncTable */ + functable = here (); + dl (openfunc); /* Open */ + dl (closefunc); /* Close */ + dl (expungefunc); /* Expunge */ + dl (EXPANSION_nullfunc); /* Null */ + dl (beginiofunc); /* BeginIO */ + dl (abortiofunc); /* AbortIO */ + dl (0xFFFFFFFFul); /* end of table */ + + /* DataTable */ + datatable = here (); + dw (0xE000); /* INITBYTE */ + dw (0x0008); /* LN_TYPE */ + dw (0x0300); /* NT_DEVICE */ + dw (0xC000); /* INITLONG */ + dw (0x000A); /* LN_NAME */ + dl (ROM_scsidev_resname); + dw (0xE000); /* INITBYTE */ + dw (0x000E); /* LIB_FLAGS */ + dw (0x0600); /* LIBF_SUMUSED | LIBF_CHANGED */ + dw (0xD000); /* INITWORD */ + dw (0x0014); /* LIB_VERSION */ + dw (0x0004); /* 0.4 */ + dw (0xD000); /* INITWORD */ + dw (0x0016); /* LIB_REVISION */ + dw (0x0000); /* end of table already ??? */ + dw (0xC000); /* INITLONG */ + dw (0x0018); /* LIB_IDSTRING */ + dl (ROM_scsidev_resid); + dw (0x0000); /* end of table */ + + ROM_scsidev_init = here (); + dl (0x00000100); /* size of device base */ + dl (functable); + dl (datatable); + dl (initcode); +} + +void scsidev_reset (void) +{ +#ifdef DEBUGME + printf("scsidev_reset()\n"); +#endif + +#ifdef SCSI_CLOSE +#ifdef UAE_SCSIDEV_THREADS + { + int i; + + for (i = 0; i < num_drives; i++) { + if (!drives[i].thread_running) { + continue; + } + write_comm_pipe_int (&drives[i].requests, 0, 1); + uae_sem_wait (&drives[i].sync_sem); + } + num_drives = 0; + } +#endif + + if (scgp) { + closescsi (scgp); + scgp = NULL; + } +#endif + + opencount = 0; +} + +void scsidev_start_threads (void) +{ +#ifdef DEBUGME + printf("scsidev_start_threads()\n"); +#endif +} + diff --git a/scsiemul.c b/scsiemul.c new file mode 100755 index 00000000..30765d17 --- /dev/null +++ b/scsiemul.c @@ -0,0 +1,913 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * scsi.device emulation + * + * Copyright 1995 Bernd Schmidt + * Copyright 1999 Patrick Ohly + * Copyright 2001 Brian King + * Copyright 2002 Toni Wilen + * + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "uae.h" +#include "threaddep/thread.h" +#include "options.h" +#include "memory.h" +#include "custom.h" +#include "events.h" +#include "newcpu.h" +#include "autoconf.h" +#include "execlib.h" +#include "native2amiga.h" +#include "blkdev.h" +#include "scsidev.h" + +#define CDDEV_COMMANDS + +#define UAEDEV_SCSI "uaescsi.device" +#define UAEDEV_SCSI_ID 1 +#define UAEDEV_DISK "uaedisk.device" +#define UAEDEV_DISK_ID 2 + +#define MAX_ASYNC_REQUESTS 20 +#define MAX_OPEN_DEVICES 20 + +#define CMD_INVALID 0 +#define CMD_RESET 1 +#define CMD_READ 2 +#define CMD_WRITE 3 +#define CMD_UPDATE 4 +#define CMD_CLEAR 5 +#define CMD_STOP 6 +#define CMD_START 7 +#define CMD_FLUSH 8 +#define CMD_MOTOR 9 +#define CMD_SEEK 10 +#define CMD_FORMAT 11 +#define CMD_REMOVE 12 +#define CMD_CHANGENUM 13 +#define CMD_CHANGESTATE 14 +#define CMD_PROTSTATUS 15 +#define CMD_GETDRIVETYPE 18 +#define CMD_GETNUMTRACKS 19 +#define CMD_ADDCHANGEINT 20 +#define CMD_REMCHANGEINT 21 +#define CMD_GETGEOMETRY 22 + +#define CD_INFO 32 +#define CD_CONFIG 33 +#define CD_TOCMSF 34 +#define CD_TOCLSN 35 +#define CD_READXL 36 +#define CD_PLAYTRACK 37 +#define CD_PLAYMSF 38 +#define CD_PLAYLSN 39 +#define CD_PAUSE 40 +#define CD_SEARCH 41 +#define CD_QCODEMSF 42 +#define CD_QCODELSN 43 +#define CD_ATTENUATE 44 +#define CD_ADDFRAMEINT 45 +#define CD_REMFRAMEINT 46 + +#define ASYNC_REQUEST_NONE 0 +#define ASYNC_REQUEST_TEMP 1 +#define ASYNC_REQUEST_CHANGEINT 10 +#define ASYNC_REQUEST_FRAMEINT 11 +#define ASYNC_REQUEST_PLAY 12 +#define ASYNC_REQUEST_READXL 13 +#define ASYNC_REQUEST_FRAMECALL 14 + +struct devstruct { + int unitnum, aunit; + int opencnt; + int changenum; + int allow_scsi; + int allow_ioctl; + int drivetype; + int iscd; + volatile uaecptr d_request[MAX_ASYNC_REQUESTS]; + volatile int d_request_type[MAX_ASYNC_REQUESTS]; + volatile uae_u32 d_request_data[MAX_ASYNC_REQUESTS]; + struct device_info di; + + smp_comm_pipe requests; + uae_thread_id tid; + int thread_running; + uae_sem_t sync_sem; +}; + +struct priv_devstruct { + int inuse; + int unit; + int mode; + int scsi; + int ioctl; + int noscsi; + int type; + int flags; /* OpenDevice() */ +}; + +static struct devstruct devst[MAX_TOTAL_DEVICES]; +static struct priv_devstruct pdevst[MAX_OPEN_DEVICES]; + +static uae_sem_t change_sem; + +static struct device_info *devinfo (int mode, int unitnum, struct device_info *di) +{ + return sys_command_info (mode, unitnum, di); +} + +static void io_log (char *msg, uaecptr request) +{ + if (log_scsi) + write_log ("%s: %08X %d %08.8X %d %d io_actual=%d io_error=%d\n", + msg, request,get_word(request + 28),get_long(request + 40),get_long(request + 36),get_long(request + 44), + get_long (request + 32), get_byte (request + 31)); +} + +void memcpyha (uae_u32 dst, char *src, int size) +{ + while (size--) + put_byte (dst++, *src++); +} + +static struct devstruct *getdevstruct (int unit) +{ + int i; + for (i = 0; i < MAX_TOTAL_DEVICES; i++) { + if (unit >= 0 && devst[i].aunit == unit) return &devst[i]; + } + return 0; +} + +static struct priv_devstruct *getpdevstruct (uaecptr request) +{ + int i = get_long (request + 24); + if (i < 0 || i >= MAX_OPEN_DEVICES || pdevst[i].inuse == 0) { + write_log ("uaescsi.device: corrupt iorequest %08.8X %d\n", request, i); + return 0; + } + return &pdevst[i]; +} + +static char *getdevname (int type) +{ + switch (type) { + case UAEDEV_SCSI_ID: + return UAEDEV_SCSI; + case UAEDEV_DISK_ID: + return UAEDEV_DISK; + default: + abort (); + } +} + +static void *dev_thread (void *devs); +static int start_thread (struct devstruct *dev) +{ + if (dev->thread_running) + return 1; + init_comm_pipe (&dev->requests, 100, 1); + uae_sem_init (&dev->sync_sem, 0, 0); + uae_start_thread (dev_thread, dev, &dev->tid); + uae_sem_wait (&dev->sync_sem); + return dev->thread_running; +} + +static void dev_close_3 (struct devstruct *dev, struct priv_devstruct *pdev) +{ + if (!dev->opencnt) return; + dev->opencnt--; + if (!dev->opencnt) { + if (pdev->scsi) + sys_command_close (DF_SCSI, dev->unitnum); + if (pdev->ioctl) + sys_command_close (DF_IOCTL, dev->unitnum); + pdev->inuse = 0; + write_comm_pipe_u32 (&dev->requests, 0, 1); + } +} + +static uae_u32 dev_close_2 (void) +{ + uae_u32 request = m68k_areg (regs, 1); + struct priv_devstruct *pdev = getpdevstruct (request); + struct devstruct *dev; + + if (!pdev) + return 0; + dev = getdevstruct (pdev->unit); + if (log_scsi) + write_log ("%s:%d close, req=%08.8X\n", getdevname (pdev->type), pdev->unit, request); + if (!dev) + return 0; + dev_close_3 (dev, pdev); + put_long (request + 24, 0); + put_word (m68k_areg(regs, 6) + 32, get_word (m68k_areg(regs, 6) + 32) - 1); + return 0; +} + +static uae_u32 dev_close (void) +{ + return dev_close_2 (); +} +static uae_u32 diskdev_close (void) +{ + return dev_close_2 (); +} + +static int openfail (uaecptr ioreq, int error) +{ + put_long (ioreq + 20, -1); + put_byte (ioreq + 31, error); + return (uae_u32)-1; +} + +static uae_u32 dev_open_2 (int type) +{ + uaecptr ioreq = m68k_areg(regs, 1); + uae_u32 unit = m68k_dreg (regs, 0); + uae_u32 flags = m68k_dreg (regs, 1); + struct devstruct *dev = getdevstruct (unit); + struct priv_devstruct *pdev = 0; + int i; + + if (log_scsi) + write_log ("opening %s:%d ioreq=%08.8X\n", getdevname (type), unit, ioreq); + if (!dev) + return openfail (ioreq, 32); /* badunitnum */ + if (!dev->opencnt) { + for (i = 0; i < MAX_OPEN_DEVICES; i++) { + pdev = &pdevst[i]; + if (pdev->inuse == 0) break; + } + if (type == UAEDEV_SCSI_ID && sys_command_open (DF_SCSI, dev->unitnum)) { + pdev->scsi = 1; + pdev->mode = DF_SCSI; + } + if (type == UAEDEV_DISK_ID && sys_command_open (DF_IOCTL, dev->unitnum)) { + pdev->ioctl = 1; + pdev->mode = DF_IOCTL; + } + if (!pdev->scsi && !pdev->ioctl) + return openfail (ioreq, -1); + pdev->type = type; + pdev->unit = unit; + pdev->flags = flags; + pdev->inuse = 1; + put_long (ioreq + 24, pdev - pdevst); + start_thread (dev); + } else { + for (i = 0; i < MAX_OPEN_DEVICES; i++) { + pdev = &pdevst[i]; + if (pdev->inuse && pdev->unit == unit) break; + } + if (i == MAX_OPEN_DEVICES) + return openfail (ioreq, -1); + put_long (ioreq + 24, pdev - pdevst); + } + dev->opencnt++; + + put_word (m68k_areg(regs, 6) + 32, get_word (m68k_areg(regs, 6) + 32) + 1); + put_byte (ioreq + 31, 0); + put_byte (ioreq + 8, 7); + return 0; +} + +static uae_u32 dev_open (void) +{ + return dev_open_2 (UAEDEV_SCSI_ID); +} +static uae_u32 diskdev_open (void) +{ + return dev_open_2 (UAEDEV_DISK_ID); +} + +static uae_u32 dev_expunge (void) +{ + return 0; +} +static uae_u32 diskdev_expunge (void) +{ + return 0; +} + +static int is_async_request (struct devstruct *dev, uaecptr request) +{ + int i = 0; + while (i < MAX_ASYNC_REQUESTS) { + if (dev->d_request[i] == request) return 1; + i++; + } + return 0; +} + +void scsi_do_disk_change (int device_id, int insert) +{ + int i, j; + + uae_sem_wait (&change_sem); + for (i = 0; i < MAX_TOTAL_DEVICES; i++) { + if (devst[i].di.id == device_id) { + devst[i].changenum++; + j = 0; + while (j < MAX_ASYNC_REQUESTS) { + if (devst[i].d_request_type[j] == ASYNC_REQUEST_CHANGEINT) { + uae_Cause (devst[i].d_request_data[j]); + } + j++; + } + } + } + uae_sem_post (&change_sem); +} + +static int add_async_request (struct devstruct *dev, uaecptr request, int type, uae_u32 data) +{ + int i; + + if (log_scsi) + write_log ("async request %p (%d) added\n", request, type); + i = 0; + while (i < MAX_ASYNC_REQUESTS) { + if (dev->d_request[i] == request) { + dev->d_request_type[i] = type; + dev->d_request_data[i] = data; + return 0; + } + i++; + } + i = 0; + while (i < MAX_ASYNC_REQUESTS) { + if (dev->d_request[i] == 0) { + dev->d_request[i] = request; + dev->d_request_type[i] = type; + dev->d_request_data[i] = data; + return 0; + } + i++; + } + return -1; +} + +static int release_async_request (struct devstruct *dev, uaecptr request) +{ + int i = 0; + + if (log_scsi) + write_log ("async request %p removed\n", request); + while (i < MAX_ASYNC_REQUESTS) { + if (dev->d_request[i] == request) { + int type = dev->d_request_type[i]; + dev->d_request[i] = 0; + dev->d_request_data[i] = 0; + dev->d_request_type[i] = 0; + return type; + } + i++; + } + return -1; +} + +static void abort_async (struct devstruct *dev, uaecptr request, int errcode, int type) +{ + int i; + i = 0; + while (i < MAX_ASYNC_REQUESTS) { + if (dev->d_request[i] == request && dev->d_request_type[i] == ASYNC_REQUEST_TEMP) { + /* ASYNC_REQUEST_TEMP = request is processing */ + sleep_millis (10); + i = 0; + continue; + } + i++; + } + i = release_async_request (dev, request); + if (i >= 0 && log_scsi) + write_log ("asyncronous request=%08.8X aborted, error=%d\n", request, errcode); +} + +static int command_read (int mode, struct devstruct *dev, uaecptr data, int offset, int length, uae_u32 *io_actual) +{ + uae_u8 *temp; + int len, sector; + + int startoffset = offset % dev->di.bytespersector; + offset -= startoffset; + sector = offset / dev->di.bytespersector; + *io_actual = 0; + while (length > 0) { + temp = sys_command_read (mode, dev->unitnum, sector); + if (!temp) return 20; + if (startoffset > 0) { + len = dev->di.bytespersector - startoffset; + if (len > length) len = length; + memcpyha (data, temp + startoffset, len); + length -= len; + data += len; + startoffset = 0; + *io_actual += len; + } else if (length >= dev->di.bytespersector) { + len = dev->di.bytespersector; + memcpyha (data, temp, len); + length -= len; + data += len; + *io_actual += len; + } else { + memcpyha (data, temp, length); + *io_actual += length; + length = 0; + } + sector++; + } + return 0; +} + +static int dev_do_io (struct devstruct *dev, uaecptr request) +{ + uae_u32 command; + uae_u32 io_data = get_long (request + 40); // 0x28 + uae_u32 io_length = get_long (request + 36); // 0x24 + uae_u32 io_actual = get_long (request + 32); // 0x20 + uae_u32 io_offset = get_long (request + 44); // 0x2c + uae_u32 io_error = 0; + int async = 0; + struct device_info di; + struct priv_devstruct *pdev = getpdevstruct (request); + + if (!pdev) + return 0; + command = get_word (request+28); + + switch (command) + { + case CMD_READ: + io_error = command_read (pdev->mode, dev, io_data, io_offset, io_length, &io_actual); + break; + case CMD_WRITE: + case CMD_FORMAT: + io_error = 28; /* writeprotect */ + break; + case CMD_UPDATE: + case CMD_CLEAR: + case CMD_FLUSH: + case CMD_MOTOR: + case CMD_SEEK: + io_actual = 0; + break; + case CMD_REMOVE: + io_actual = 0; + break; + case CMD_CHANGENUM: + io_actual = dev->changenum; + break; + case CMD_CHANGESTATE: + io_actual = devinfo(pdev->mode, dev->unitnum, &di)->media_inserted ? 0 : 1; + break; + case CMD_PROTSTATUS: + io_actual = devinfo(pdev->mode, dev->unitnum, &di)->write_protected ? -1 : 0; + break; + case CMD_GETDRIVETYPE: + io_actual = dev->drivetype; + break; + case CMD_GETNUMTRACKS: + io_actual = dev->di.cylinders; + break; + case CMD_ADDCHANGEINT: + io_error = add_async_request (dev, request, ASYNC_REQUEST_CHANGEINT, io_data); + if (!io_error) + async = 1; + break; + case CMD_REMCHANGEINT: + release_async_request (dev, request); + break; + case 28: /* HD_SCSICMD */ + if (dev->allow_scsi && pdev->scsi) { + uae_u32 sdd = get_long (request + 40); + io_error = sys_command_scsi_direct (dev->unitnum, sdd); + if (log_scsi) + write_log ("scsidev: did io: sdd %p request %p error %d\n", sdd, request, get_byte (request + 31)); + } + break; + default: + io_error = -3; + break; + } + put_long (request + 32, io_actual); + put_byte (request + 31, io_error); + io_log ("dev_io",request); + return async; +} + +static int dev_can_quick (uae_u32 command) +{ + switch (command) + { + case CMD_RESET: + case CMD_STOP: + case CMD_START: + case CMD_CHANGESTATE: + case CMD_PROTSTATUS: + case CMD_GETDRIVETYPE: + case CMD_GETNUMTRACKS: + return 1; + } + return 0; +} + +static int dev_canquick (struct devstruct *dev, uaecptr request) +{ + uae_u32 command = get_word (request + 28); + return dev_can_quick (command); +} + +static uae_u32 dev_beginio (void) +{ + uae_u32 request = m68k_areg(regs, 1); + uae_u8 flags = get_byte (request + 30); + int command = get_word (request + 28); + struct priv_devstruct *pdev = getpdevstruct (request); + struct devstruct *dev = getdevstruct (pdev->unit); + + put_byte (request+8, NT_MESSAGE); + if (!dev || !pdev) { + put_byte (request + 31, 32); + return get_byte (request + 31); + } + put_byte (request+31, 0); + if ((flags & 1) && dev_canquick (dev, request)) { + if (dev_do_io (dev, request)) + write_log ("device %s command %d bug with IO_QUICK\n", getdevname (pdev->type), command); + return get_byte (request + 31); + } else { + add_async_request (dev, request, ASYNC_REQUEST_TEMP, 0); + put_byte (request+30, get_byte (request + 30) & ~1); + write_comm_pipe_u32 (&dev->requests, request, 1); + return 0; + } +} + +static void *dev_thread (void *devs) +{ + struct devstruct *dev = devs; + + set_thread_priority (2); + dev->thread_running = 1; + uae_sem_post (&dev->sync_sem); + for (;;) { + uaecptr request = (uaecptr)read_comm_pipe_u32_blocking (&dev->requests); + uae_sem_wait (&change_sem); + if (!request) { + dev->thread_running = 0; + uae_sem_post (&dev->sync_sem); + uae_sem_post (&change_sem); + return 0; + } else if (dev_do_io (dev, request) == 0) { + put_byte (request + 30, get_byte (request + 30) & ~1); + release_async_request (dev, request); + uae_ReplyMsg (request); + } else { + if (log_scsi) + write_log ("async request %08.8X\n", request); + } + uae_sem_post (&change_sem); + } + return 0; +} + +static uae_u32 dev_init_2 (int type) +{ + uae_u32 base = m68k_dreg (regs,0); + if (log_scsi) + write_log ("%s init\n", getdevname (type)); + return base; +} + +static uae_u32 dev_init (void) +{ + return dev_init_2 (UAEDEV_SCSI_ID); +} +static uae_u32 diskdev_init (void) +{ + return dev_init_2 (UAEDEV_DISK_ID); +} + +static uae_u32 dev_abortio (void) +{ + uae_u32 request = m68k_areg(regs, 1); + struct priv_devstruct *pdev = getpdevstruct (request); + struct devstruct *dev; + + if (!pdev) { + put_byte (request + 31, 32); + return get_byte (request + 31); + } + dev = getdevstruct (pdev->unit); + if (!dev) { + put_byte (request + 31, 32); + return get_byte (request + 31); + } + put_byte (request + 31, -2); + if (log_scsi) + write_log ("abortio %s unit=%d, request=%08.8X\n", getdevname (pdev->type), pdev->unit, request); + abort_async (dev, request, -2, 0); + return 0; +} + +#define BTL2UNIT(bus, target, lun) (2 * (bus) + (target) / 8) * 100 + (lun) * 10 + (target % 8) + +static void dev_reset (void) +{ + int i, j; + struct devstruct *dev; + struct device_info *discsi, discsi2; + int unitnum = 0; + + device_func_init (DEVICE_TYPE_SCSI); + for (i = 0; i < MAX_TOTAL_DEVICES; i++) { + dev = &devst[i]; + if (dev->opencnt > 0) { + for (j = 0; j < MAX_ASYNC_REQUESTS; j++) { + uaecptr request; + if (request = dev->d_request[i]) + abort_async (dev, request, 0, 0); + } + dev->opencnt = 1; + sys_command_close (DF_SCSI, dev->unitnum); + sys_command_close (DF_IOCTL, dev->unitnum); + } + memset (dev, 0, sizeof (struct devstruct)); + dev->unitnum = dev->aunit = -1; + } + for (i = 0; i < MAX_OPEN_DEVICES; i++) + memset (&pdevst[i], 0, sizeof (struct priv_devstruct)); + + i = j = 0; + while (i < MAX_TOTAL_DEVICES) { + dev = &devst[i]; + discsi = 0; + if (sys_command_open (DF_SCSI, j)) { + discsi = sys_command_info (DF_SCSI, j, &discsi2); + sys_command_close (DF_SCSI, j); + } + if (discsi) { + dev->unitnum = j; + dev->allow_scsi = 1; + dev->drivetype = discsi->type; + memcpy (&dev->di, discsi, sizeof (struct device_info)); + if (discsi->type == INQ_ROMD) + dev->iscd = 1; + } + i++; + j++; + } + unitnum = 0; + for (i = 0; i < MAX_TOTAL_DEVICES; i++) { + dev = &devst[i]; + if (dev->unitnum >= 0 && dev->iscd) { + dev->aunit = unitnum; + unitnum++; + } + } + if (unitnum == 0) + unitnum = 1; + for (i = 0; i < MAX_TOTAL_DEVICES; i++) { + dev = &devst[i]; + if (dev->unitnum >= 0) { + if (!dev->iscd) { + dev->aunit = unitnum; + unitnum++; + } + write_log ("%s = %s:%d\n", dev->di.label, UAEDEV_SCSI, dev->aunit); + } + } +} + +static uaecptr ROM_scsidev_resname = 0, + ROM_scsidev_resid = 0, + ROM_scsidev_init = 0; + +static uaecptr ROM_diskdev_resname = 0, + ROM_diskdev_resid = 0, + ROM_diskdev_init = 0; + + +static uaecptr diskdev_startup (uaecptr resaddr) +{ + /* Build a struct Resident. This will set up and initialize + * the cd.device */ + if (log_scsi) + write_log ("diskdev_startup(0x%x)\n", resaddr); + put_word(resaddr + 0x0, 0x4AFC); + put_long(resaddr + 0x2, resaddr); + put_long(resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */ + put_word(resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */ + put_word(resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */ + put_long(resaddr + 0xE, ROM_diskdev_resname); + put_long(resaddr + 0x12, ROM_diskdev_resid); + put_long(resaddr + 0x16, ROM_diskdev_init); + resaddr += 0x1A; + return resaddr; +} + +uaecptr scsidev_startup (uaecptr resaddr) +{ + if (!currprefs.scsi) + return resaddr; + if (log_scsi) + write_log ("scsidev_startup(0x%x)\n", resaddr); + /* Build a struct Resident. This will set up and initialize + * the uaescsi.device */ + put_word(resaddr + 0x0, 0x4AFC); + put_long(resaddr + 0x2, resaddr); + put_long(resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */ + put_word(resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */ + put_word(resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */ + put_long(resaddr + 0xE, ROM_scsidev_resname); + put_long(resaddr + 0x12, ROM_scsidev_resid); + put_long(resaddr + 0x16, ROM_scsidev_init); /* calls scsidev_init */ + resaddr += 0x1A; + return resaddr; + return diskdev_startup (resaddr); +} + +static void diskdev_install (void) +{ + uae_u32 functable, datatable; + uae_u32 initcode, openfunc, closefunc, expungefunc; + uae_u32 beginiofunc, abortiofunc; + + if (!currprefs.scsi) + return; + if (log_scsi) + write_log ("diskdev_install(): 0x%x\n", here ()); + + ROM_diskdev_resname = ds (UAEDEV_DISK); + ROM_diskdev_resid = ds ("UAE disk.device 0.1"); + + /* initcode */ + initcode = here (); + calltrap (deftrap (diskdev_init)); dw (RTS); + + /* Open */ + openfunc = here (); + calltrap (deftrap (diskdev_open)); dw (RTS); + + /* Close */ + closefunc = here (); + calltrap (deftrap (diskdev_close)); dw (RTS); + + /* Expunge */ + expungefunc = here (); + calltrap (deftrap (diskdev_expunge)); dw (RTS); + + /* BeginIO */ + beginiofunc = here (); + calltrap (deftrap (dev_beginio)); + dw (RTS); + + /* AbortIO */ + abortiofunc = here (); + calltrap (deftrap (dev_abortio)); dw (RTS); + + /* FuncTable */ + functable = here (); + dl (openfunc); /* Open */ + dl (closefunc); /* Close */ + dl (expungefunc); /* Expunge */ + dl (EXPANSION_nullfunc); /* Null */ + dl (beginiofunc); /* BeginIO */ + dl (abortiofunc); /* AbortIO */ + dl (0xFFFFFFFFul); /* end of table */ + + /* DataTable */ + datatable = here (); + dw (0xE000); /* INITBYTE */ + dw (0x0008); /* LN_TYPE */ + dw (0x0300); /* NT_DEVICE */ + dw (0xC000); /* INITLONG */ + dw (0x000A); /* LN_NAME */ + dl (ROM_diskdev_resname); + dw (0xE000); /* INITBYTE */ + dw (0x000E); /* LIB_FLAGS */ + dw (0x0600); /* LIBF_SUMUSED | LIBF_CHANGED */ + dw (0xD000); /* INITWORD */ + dw (0x0014); /* LIB_VERSION */ + dw (0x0004); /* 0.4 */ + dw (0xD000); /* INITWORD */ + dw (0x0016); /* LIB_REVISION */ + dw (0x0000); /* end of table already ??? */ + dw (0xC000); /* INITLONG */ + dw (0x0018); /* LIB_IDSTRING */ + dl (ROM_diskdev_resid); + dw (0x0000); /* end of table */ + + ROM_diskdev_init = here (); + dl (0x00000100); /* size of device base */ + dl (functable); + dl (datatable); + dl (initcode); +} + + +void scsidev_install (void) +{ + uae_u32 functable, datatable; + uae_u32 initcode, openfunc, closefunc, expungefunc; + uae_u32 beginiofunc, abortiofunc; + + if (!currprefs.scsi) + return; + if (log_scsi) + write_log ("scsidev_install(): 0x%x\n", here ()); + + ROM_scsidev_resname = ds (UAEDEV_SCSI); + ROM_scsidev_resid = ds ("UAE scsi.device 0.2"); + + /* initcode */ + initcode = here (); + calltrap (deftrap (dev_init)); dw (RTS); + + /* Open */ + openfunc = here (); + calltrap (deftrap (dev_open)); dw (RTS); + + /* Close */ + closefunc = here (); + calltrap (deftrap (dev_close)); dw (RTS); + + /* Expunge */ + expungefunc = here (); + calltrap (deftrap (dev_expunge)); dw (RTS); + + /* BeginIO */ + beginiofunc = here (); + calltrap (deftrap (dev_beginio)); + dw (RTS); + + /* AbortIO */ + abortiofunc = here (); + calltrap (deftrap (dev_abortio)); dw (RTS); + + /* FuncTable */ + functable = here (); + dl (openfunc); /* Open */ + dl (closefunc); /* Close */ + dl (expungefunc); /* Expunge */ + dl (EXPANSION_nullfunc); /* Null */ + dl (beginiofunc); /* BeginIO */ + dl (abortiofunc); /* AbortIO */ + dl (0xFFFFFFFFul); /* end of table */ + + /* DataTable */ + datatable = here (); + dw (0xE000); /* INITBYTE */ + dw (0x0008); /* LN_TYPE */ + dw (0x0300); /* NT_DEVICE */ + dw (0xC000); /* INITLONG */ + dw (0x000A); /* LN_NAME */ + dl (ROM_scsidev_resname); + dw (0xE000); /* INITBYTE */ + dw (0x000E); /* LIB_FLAGS */ + dw (0x0600); /* LIBF_SUMUSED | LIBF_CHANGED */ + dw (0xD000); /* INITWORD */ + dw (0x0014); /* LIB_VERSION */ + dw (0x0004); /* 0.4 */ + dw (0xD000); /* INITWORD */ + dw (0x0016); /* LIB_REVISION */ + dw (0x0000); /* end of table already ??? */ + dw (0xC000); /* INITLONG */ + dw (0x0018); /* LIB_IDSTRING */ + dl (ROM_scsidev_resid); + dw (0x0000); /* end of table */ + + ROM_scsidev_init = here (); + dl (0x00000100); /* size of device base */ + dl (functable); + dl (datatable); + dl (initcode); + + diskdev_install (); +} + +void scsidev_start_threads (void) +{ + if (!currprefs.scsi) /* quite useless.. */ + return; + if (log_scsi) + write_log ("scsidev_start_threads()\n"); + uae_sem_init (&change_sem, 0, 1); +} + +void scsidev_reset (void) +{ + if (!currprefs.scsi) + return; + dev_reset (); +} \ No newline at end of file diff --git a/sdl-joystick.c b/sdl-joystick.c new file mode 100755 index 00000000..a01d0aca --- /dev/null +++ b/sdl-joystick.c @@ -0,0 +1,157 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * SDL Joystick code + * + * Copyright 1997 Bernd Schmidt + * Copyright 1998 Krister Walfridsson + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "memory.h" +#include "custom.h" +#include "inputdevice.h" +#include "SDL.h" + +static int nr_joysticks; + +struct joyinfo { + SDL_Joystick *joy; + int axles; + int buttons; +}; + +static struct joyinfo joys[MAX_INPUT_DEVICES]; + +static int isjoy (int pcport, int amigaport) +{ + if (pcport == 0) + return JSEM_ISJOY0 (amigaport, &currprefs); + else + return JSEM_ISJOY1 (amigaport, &currprefs); +} + +static void read_joy(int nr) +{ + int num, i, axes, axis; + SDL_Joystick *joy; + + if (currprefs.input_selected_setting == 0) { + if (nr >= 2) + return; + if (isjoy (nr, 0)) { + if (JSEM_ISNUMPAD (0, &currprefs) || JSEM_ISCURSOR (0, &currprefs) || JSEM_ISSOMEWHEREELSE (0, &currprefs)) + return; + } else if (isjoy (nr, 1)) { + if (JSEM_ISNUMPAD (1, &currprefs) || JSEM_ISCURSOR (1, &currprefs) || JSEM_ISSOMEWHEREELSE (1, &currprefs)) + return; + } else + return; + } + joy = joys[nr].joy; + axes = SDL_JoystickNumAxes (joy); + for (i = 0; i < axes; i++) { + axis = SDL_JoystickGetAxis (joy, i); + setjoystickstate (nr, i, axis, 32767); + } + + num = SDL_JoystickNumButtons (joy); + for (i = 0; i < num; i++) { + int bs = SDL_JoystickGetButton (joy, i) ? 1 : 0; + setjoybuttonstate (nr, i, bs); + } +} + +static int get_joystick_num (void) +{ + return nr_joysticks; +} + +static int get_joystick_widget_num (int joy) +{ + return joys[joy].axles + joys[joy].buttons; +} + +static int get_joystick_widget_type (int joy, int num, char *name) +{ + if (num >= joys[joy].axles && num < joys[joy].axles + joys[joy].buttons) { + if (name) + sprintf (name, "Button %d", num + 1 - joys[joy].axles); + return IDEV_WIDGET_BUTTON; + } else if (num < joys[joy].axles) { + if (name) + sprintf (name, "Axis %d", num + 1); + return IDEV_WIDGET_AXIS; + } + return IDEV_WIDGET_NONE; +} + +static int get_joystick_widget_first (int joy, int type) +{ + switch (type) + { + case IDEV_WIDGET_BUTTON: + return joys[joy].axles; + case IDEV_WIDGET_AXIS: + return 0; + } + return -1; +} + +static char *get_joystick_name (int joy) +{ + static char name[100]; + sprintf (name, "%d: %s", joy + 1, SDL_JoystickName (joy)); + return name; +} + +static void read_joysticks (void) +{ + int i; + SDL_JoystickUpdate (); + for (i = 0; i < get_joystick_num(); i++) + read_joy (i); +} + +static int init_joysticks (void) +{ + int i; + nr_joysticks = SDL_NumJoysticks (); + if (nr_joysticks > MAX_INPUT_DEVICES) + nr_joysticks = MAX_INPUT_DEVICES; + for (i = 0; i < get_joystick_num(); i++) { + joys[i].joy = SDL_JoystickOpen (i); + joys[i].axles = SDL_JoystickNumAxes (joys[i].joy); + joys[i].buttons = SDL_JoystickNumButtons (joys[i].joy); + } + return 1; +} + +static void close_joysticks (void) +{ + int i; + for (i = 0; i < get_joystick_num(); i++) { + SDL_JoystickClose (joys[i].joy); + joys[i].joy = 0; + } +} + +static int acquire_joy (int num, int flags) +{ + return 1; +} + +static void unacquire_joy (int num) +{ +} + +struct inputdevice_functions inputdevicefunc_joystick = { + init_joysticks, close_joysticks, acquire_joy, unacquire_joy, + read_joysticks, get_joystick_num, get_joystick_name, + get_joystick_widget_num, get_joystick_widget_type, + get_joystick_widget_first +}; diff --git a/serial.c b/serial.c new file mode 100755 index 00000000..ad3fed07 --- /dev/null +++ b/serial.c @@ -0,0 +1,413 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Serial Line Emulation + * + * (c) 1996, 1997 Stefan Reinauer + * (c) 1997 Christian Schmitt + * + */ + +#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 +#include +#include +#endif + +#if !defined B300 || !defined B1200 || !defined B2400 || !defined B4800 || !defined B9600 +#undef POSIX_SERIAL +#endif +#if !defined B19200 || !defined B57600 || !defined B115200 || !defined B230400 +#undef POSIX_SERIAL +#endif + +#ifndef O_NONBLOCK +#define O_NONBLOCK O_NDELAY +#endif + +#define SERIALDEBUG 1 /* 0, 1, 2 3 */ +#define MODEMTEST 0 /* 0 or 1 */ + +void serial_open (void); +void serial_close (void); +void serial_init (void); +void serial_exit (void); + +void serial_dtr_on (void); +void serial_dtr_off (void); + +void serial_flush_buffer (void); +static int serial_read (char *buffer); + +int serial_readstatus (void); +uae_u16 serial_writestatus (int, int); + +uae_u16 SERDATR (void); + +int SERDATS (void); +void SERPER (uae_u16 w); +void SERDAT (uae_u16 w); + +static char inbuf[1024], outbuf[1024]; +static int inptr, inlast, outlast; + +int waitqueue=0, + carrier=0, + serdev=0, + dsr=0, + dtr=0, + isbaeh=0, + doreadser=0, + serstat=-1; + +int sd = -1; + +#ifdef POSIX_SERIAL + struct termios tios; +#endif + +uae_u16 serper=0,serdat; + +void SERPER (uae_u16 w) +{ + int baud=0, pspeed; + + if (!currprefs.use_serial) + return; + +#if defined POSIX_SERIAL + if (serper == w) /* don't set baudrate if it's already ok */ + return; + serper=w; + + if (w&0x8000) + write_log ("SERPER: 9bit transmission not implemented.\n"); + + switch (w & 0x7fff) { + /* These values should be calculated by the current + * color clock value (NTSC/PAL). But this solution is + * easy and it works. + */ + + case 0x2e9b: + case 0x2e14: baud=300; pspeed=B300; break; + case 0x170a: + case 0x0b85: baud=1200; pspeed=B1200; break; + case 0x05c2: + case 0x05b9: baud=2400; pspeed=B2400; break; + case 0x02e9: + case 0x02e1: baud=4800; pspeed=B4800; break; + case 0x0174: + case 0x0170: baud=9600; pspeed=B9600; break; + case 0x00b9: + case 0x00b8: baud=19200; pspeed=B19200; break; + case 0x005c: + case 0x005d: baud=38400; pspeed=B38400; break; + case 0x003d: baud=57600; pspeed=B57600; break; + case 0x001e: baud=115200; pspeed=B115200; break; + case 0x000f: baud=230400; pspeed=B230400; break; + default: + write_log ("SERPER: unsupported baudrate (0x%04x) %d\n",w&0x7fff, + (unsigned int)(3579546.471/(double)((w&0x7fff)+1))); return; + } + + /* Only access hardware when we own it */ + if (serdev == 1) { + if (tcgetattr (sd, &tios) < 0) { + write_log ("SERPER: TCGETATTR failed\n"); + return; + } + + if (cfsetispeed (&tios, pspeed) < 0) { /* set serial input speed */ + write_log ("SERPER: CFSETISPEED (%d bps) failed\n", baud); + return; + } + if (cfsetospeed (&tios, pspeed) < 0) { /* set serial output speed */ + write_log ("SERPER: CFSETOSPEED (%d bps) failed\n", baud); + return; + } + + if (tcsetattr (sd, TCSADRAIN, &tios) < 0) { + write_log ("SERPER: TCSETATTR failed\n"); + return; + } + } +#endif + +#if SERIALDEBUG > 0 + if (serdev == 1) + write_log ("SERPER: baudrate set to %d bit/sec\n", baud); +#endif +} + +/* Not (fully) implemented yet: + * + * - Something's wrong with the Interrupts. + * (NComm works, TERM does not. TERM switches to a + * blind mode after a connect and wait's for the end + * of an asynchronous read before switching blind + * mode off again. It never gets there on UAE :-< ) + * + * - RTS/CTS handshake, this is not really neccessary, + * because you can use RTS/CTS "outside" without + * passing it through to the emulated Amiga + * + * - ADCON-Register ($9e write, $10 read) Bit 11 (UARTBRK) + * (see "Amiga Intern", pg 246) + */ + +void SERDAT (uae_u16 w) +{ + unsigned char z; + + if (!currprefs.use_serial) + return; + + z = (unsigned char)(w&0xff); + + if (currprefs.serial_demand && !dtr) { + if (!isbaeh) { + write_log("SERDAT: Baeh.. Your software needs SERIAL_ALWAYS to work properly.\n"); + isbaeh=1; + } + return; + } else { + outbuf[outlast++] = z; + if (outlast == sizeof outbuf) + serial_flush_buffer(); + } + +#if SERIALDEBUG > 2 + write_log ("SERDAT: wrote 0x%04x\n", w); +#endif + + serdat|=0x2000; /* Set TBE in the SERDATR ... */ + intreq|=1; /* ... and in INTREQ register */ + return; +} + +uae_u16 SERDATR (void) +{ + if (!currprefs.use_serial) + return 0; +#if SERIALDEBUG > 2 + write_log ("SERDATR: read 0x%04x\n", serdat); +#endif + waitqueue = 0; + return serdat; +} + +int SERDATS (void) +{ + unsigned char z; + + if (!serdev) /* || (serdat&0x4000)) */ + return 0; + + if (waitqueue == 1) { + intreq |= 0x0800; + return 1; + } + + if ((serial_read ((char *)&z)) == 1) { + waitqueue = 1; + serdat = 0x4100; /* RBF and STP set! */ + serdat |= ((unsigned int)z) & 0xff; + intreq |= 0x0800; /* Set RBF flag (Receive Buffer full) */ + +#if SERIALDEBUG > 1 + write_log ("SERDATS: received 0x%02x --> serdat==0x%04x\n", + (unsigned int)z, (unsigned int)serdat); +#endif + return 1; + } + return 0; +} + +void serial_dtr_on(void) +{ +#if SERIALDEBUG > 0 + write_log ("DTR on.\n"); +#endif + dtr=1; + + if (currprefs.serial_demand) + serial_open (); +} + +void serial_dtr_off(void) +{ +#if SERIALDEBUG > 0 + write_log ("DTR off.\n"); +#endif + dtr=0; + if (currprefs.serial_demand) + serial_close (); +} + +static int serial_read (char *buffer) +{ + if (inptr < inlast) { + *buffer = inbuf[inptr++]; + return 1; + } + + if (serdev == 1) { + inlast = read (sd, inbuf, sizeof inbuf); + inptr = 0; + if (inptr < inlast) { + *buffer = inbuf[inptr++]; + return 1; + } + } + + return 0; +} + +void serial_flush_buffer(void) +{ + if (serdev == 1) { + if (outlast) { + if (sd != 0) { + write (sd, outbuf, outlast); + } + } + outlast = 0; + } else { + outlast = 0; + inptr = 0; + inlast = 0; + } +} + +int serial_readstatus(void) +{ + int status = 0; + +#ifdef POSIX_SERIAL + ioctl (sd, TIOCMGET, &status); + + if (status & TIOCM_CAR) { + if (!carrier) { + ciabpra |= 0x20; /* Push up Carrier Detect line */ + carrier = 1; +#if SERIALDEBUG > 0 + write_log ("Carrier detect.\n"); +#endif + } + } else { + if (carrier) { + ciabpra &= ~0x20; + carrier = 0; +#if SERIALDEBUG > 0 + write_log ("Carrier lost.\n"); +#endif + } + } + + if (status & TIOCM_DSR) { + if (!dsr) { + ciabpra |= 0x08; /* DSR ON */ + dsr = 1; + } + } else { + if (dsr) { + ciabpra &= ~0x08; + dsr = 0; + } + } +#endif + return status; +} + +uae_u16 serial_writestatus (int old, int nw) +{ + if ((old & 0x80) == 0x80 && (nw & 0x80) == 0x00) + serial_dtr_on(); + if ((old & 0x80) == 0x00 && (nw & 0x80) == 0x80) + serial_dtr_off(); + + if ((old & 0x40) != (nw & 0x40)) + write_log ("RTS %s.\n", ((nw & 0x40) == 0x40) ? "set" : "cleared"); + + if ((old & 0x10) != (nw & 0x10)) + write_log ("CTS %s.\n", ((nw & 0x10) == 0x10) ? "set" : "cleared"); + + return nw; /* This value could also be changed here */ +} + +void serial_open(void) +{ + if (serdev == 1) + return; + + if ((sd = open (currprefs.sername, O_RDWR|O_NONBLOCK|O_BINARY, 0)) < 0) { + write_log ("Error: Could not open Device %s\n", currprefs.sername); + return; + } + + serdev = 1; + +#ifdef POSIX_SERIAL + if (tcgetattr (sd, &tios) < 0) { /* Initialize Serial tty */ + write_log ("Serial: TCGETATTR failed\n"); + return; + } + cfmakeraw (&tios); + +#ifndef MODEMTEST + tios.c_cflag &= ~CRTSCTS; /* Disable RTS/CTS */ +#else + tios.c_cflag |= CRTSCTS; /* Enabled for testing modems */ +#endif + + if (tcsetattr (sd, TCSADRAIN, &tios) < 0) { + write_log ("Serial: TCSETATTR failed\n"); + return; + } +#endif +} + +void serial_close (void) +{ + if (sd >= 0) + close (sd); + serdev = 0; +} + +void serial_init (void) +{ + if (!currprefs.use_serial) + return; + + if (!currprefs.serial_demand) + serial_open (); + + serdat = 0x2000; + return; +} + +void serial_exit (void) +{ + serial_close (); /* serial_close can always be called because it */ + dtr = 0; /* just closes *opened* filehandles which is ok */ + return; /* when exiting. */ +} diff --git a/svga.c b/svga.c new file mode 100755 index 00000000..df5dea6d --- /dev/null +++ b/svga.c @@ -0,0 +1,945 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * SVGAlib interface. + * + * (c) 1995 Bernd Schmidt + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "options.h" +#include "threaddep/thread.h" +#include "uae.h" +#include "memory.h" +#include "keyboard.h" +#include "xwin.h" +#include "custom.h" +#include "drawing.h" +#include "keybuf.h" +#include "newcpu.h" +#include "tui.h" +#include "gui.h" +#include "picasso96.h" + +#define SCODE_CB_UP 103 /* Cursor key block. */ +#define SCODE_CB_LEFT 105 +#define SCODE_CB_RIGHT 106 +#define SCODE_CB_DOWN 108 + +#define SCODE_INSERT 110 +#define SCODE_HOME 102 +#define SCODE_PGUP 104 +#define SCODE_DELETE 111 +#define SCODE_END 107 +#define SCODE_PGDN 109 + +#define SCODE_PRTSCR 99 +#define SCODE_SLOCK 70 +#define SCODE_BREAK 119 + +#define SCODE_NUMLOCK 69 + +#define SCODE_KEYPAD0 82 +#define SCODE_KEYPAD1 79 +#define SCODE_KEYPAD2 80 +#define SCODE_KEYPAD3 81 +#define SCODE_KEYPAD4 75 +#define SCODE_KEYPAD5 76 +#define SCODE_KEYPAD6 77 +#define SCODE_KEYPAD7 71 +#define SCODE_KEYPAD8 72 +#define SCODE_KEYPAD9 73 +#define SCODE_KEYPADRET 96 +#define SCODE_KEYPADADD 78 +#define SCODE_KEYPADSUB 74 +#define SCODE_KEYPADMUL 55 +#define SCODE_KEYPADDIV 98 +#define SCODE_KEYPADDOT 83 + +#define SCODE_Q 16 +#define SCODE_W 17 +#define SCODE_E 18 +#define SCODE_R 19 +#define SCODE_T 20 +#define SCODE_Y 21 +#define SCODE_U 22 +#define SCODE_I 23 +#define SCODE_O 24 +#define SCODE_P 25 + +#define SCODE_A 30 +#define SCODE_S 31 +#define SCODE_D 32 +#define SCODE_F 33 +#define SCODE_G 34 +#define SCODE_H 35 +#define SCODE_J 36 +#define SCODE_K 37 +#define SCODE_L 38 + +#define SCODE_Z 44 +#define SCODE_X 45 +#define SCODE_C 46 +#define SCODE_V 47 +#define SCODE_B 48 +#define SCODE_N 49 +#define SCODE_M 50 + +#define SCODE_ESCAPE 1 +#define SCODE_ENTER 28 +#define SCODE_RCONTROL 97 +#define SCODE_CONTROL 97 +#define SCODE_RALT 100 +#define SCODE_LCONTROL 29 +#define SCODE_LALT 56 +#define SCODE_SPACE 57 + +#define SCODE_F1 59 +#define SCODE_F2 60 +#define SCODE_F3 61 +#define SCODE_F4 62 +#define SCODE_F5 63 +#define SCODE_F6 64 +#define SCODE_F7 65 +#define SCODE_F8 66 +#define SCODE_F9 67 +#define SCODE_F10 68 +#define SCODE_F11 87 +#define SCODE_F12 88 + +#define SCODE_0 11 +#define SCODE_1 2 +#define SCODE_2 3 +#define SCODE_3 4 +#define SCODE_4 5 +#define SCODE_5 6 +#define SCODE_6 7 +#define SCODE_7 8 +#define SCODE_8 9 +#define SCODE_9 10 + +#define SCODE_LSHIFT 42 +#define SCODE_RSHIFT 54 +#define SCODE_TAB 15 + +#define SCODE_BS 14 + +#define SCODE_asciicircum 41 + +#define SCODE_bracketleft 26 +#define SCODE_bracketright 27 +#define SCODE_comma 51 +#define SCODE_period 52 +#define SCODE_slash 53 +#define SCODE_semicolon 39 +#define SCODE_grave 40 +#define SCODE_minus 12 +#define SCODE_equal 13 +#define SCODE_numbersign 43 +#define SCODE_ltgt 86 + +#define SCODE_LWIN95 125 +#define SCODE_RWIN95 126 +#define SCODE_MWIN95 127 + +void setup_brkhandler(void) +{ +} + +static int bitdepth, bit_unit, using_linear, vgamode, current_vgamode, gui_requested; +static vga_modeinfo modeinfo; +static char *linear_mem = NULL; +static int need_dither; +static int screen_is_picasso; +static int picasso_vgamode = -1; +static char picasso_invalid_lines[1200]; + +static uae_u8 dither_buf[1000]; /* I hate having to think about array bounds */ + +#define MAX_SCREEN_MODES 9 + +static int x_size_table[MAX_SCREEN_MODES] = { 320, 320, 320, 640, 640, 800, 1024, 1152, 1280 }; +static int y_size_table[MAX_SCREEN_MODES] = { 200, 240, 400, 350, 480, 600, 768, 864, 1024 }; + +static int vga_mode_table[MAX_SCREEN_MODES][MAX_COLOR_MODES+1] = + { { G320x200x256, G320x200x32K, G320x200x64K, G320x200x256, G320x200x16, G320x200x16M32 }, + { G320x240x256, -1, -1, G320x240x256, -1, -1 }, + { G320x400x256, -1, -1, G320x400x256, -1, -1 }, + { -1, -1, -1, -1, G640x350x16, -1 }, + { G640x480x256, G640x480x32K, G640x480x64K, G640x480x256, G640x480x16, G640x480x16M32 }, + { G800x600x256, G800x600x32K, G800x600x64K, G800x600x256, G800x600x16, G800x600x16M32 }, + { G1024x768x256, G1024x768x32K, G1024x768x64K, G1024x768x256, G1024x768x16, G1024x768x16M32 }, + { G1152x864x256, G1152x864x32K, G1152x864x64K, G1152x864x256, G1152x864x16, G1152x864x16M32 }, + { G1280x1024x256, G1280x1024x32K, G1280x1024x64K, G1280x1024x256, G1280x1024x16, G1280x1024x16M32 } + }; + +static int mode_bitdepth[MAX_COLOR_MODES+1][3] = + { { 8, 8, 0 }, { 15, 16, 0 }, { 16, 16, 0 }, { 8, 8, 1 }, { 4, 8, 1 }, { 24, 32, 0 } }; + +struct bstring *video_mode_menu = NULL; + +void flush_line(int y) +{ + int target_y = y; + char *addr; + + if (linear_mem != NULL && !need_dither) + return; + + addr = gfxvidinfo.linemem; + if (addr == NULL) + addr = gfxvidinfo.bufmem + y*gfxvidinfo.rowbytes; + + if (linear_mem == NULL) { + if (target_y < modeinfo.height && target_y >= 0) { + if (need_dither) { + DitherLine (dither_buf, (uae_u16 *)addr, 0, y, gfxvidinfo.width, bit_unit); + addr = dither_buf; + } + vga_drawscanline(target_y, addr); + } + } else { + if (need_dither && target_y >= 0) { + DitherLine (linear_mem + modeinfo.linewidth * target_y, (uae_u16 *)addr, 0, y, + gfxvidinfo.width, bit_unit); + } + } +} + +void flush_block (int a, int b) +{ + abort(); +} + +void flush_screen (int a, int b) +{ +} + +static int colors_allocated; +static long palette_entries[256][3]; + +static void restore_vga_colors (void) +{ + int i; + if (gfxvidinfo.pixbytes != 1) + return; + for (i = 0; i < 256; i++) + vga_setpalette (i, palette_entries[i][0], palette_entries[i][1], palette_entries[i][2]); +} + +static int get_color (int r, int g, int b, xcolnr *cnp) +{ + if (colors_allocated == 256) + return -1; + *cnp = colors_allocated; + palette_entries[colors_allocated][0] = doMask (r, 6, 0); + palette_entries[colors_allocated][1] = doMask (g, 6, 0); + palette_entries[colors_allocated][2] = doMask (b, 6, 0); + vga_setpalette(colors_allocated, doMask (r, 6, 0), doMask (g, 6, 0), doMask (b, 6, 0)); + colors_allocated++; + return 1; +} + +static void init_colors (void) +{ + int i; + if (need_dither) { + setup_dither (bitdepth, get_color); + } else { + int rw = 5, gw = 5, bw = 5; + colors_allocated = 0; + if (currprefs.color_mode == 2) gw = 6; + + switch (gfxvidinfo.pixbytes) { + case 4: + alloc_colors64k (8, 8, 8, 16, 8, 0); + break; + case 2: + alloc_colors64k (rw, gw, bw, gw+bw, bw, 0); + break; + case 1: + alloc_colors256 (get_color); + break; + default: + abort(); + } + } + switch (gfxvidinfo.pixbytes) { + case 2: + for (i = 0; i < 4096; i++) + xcolors[i] = xcolors[i] * 0x00010001; + gfxvidinfo.can_double = 1; + break; + case 1: + for (i = 0; i < 4096; i++) + xcolors[i] = xcolors[i] * 0x01010101; + gfxvidinfo.can_double = 1; + break; + default: + gfxvidinfo.can_double = 0; + break; + } +} + +static int keystate[256]; + +static int scancode2amiga (int scancode) +{ + switch (scancode) { + case SCODE_A: return AK_A; + case SCODE_B: return AK_B; + case SCODE_C: return AK_C; + case SCODE_D: return AK_D; + case SCODE_E: return AK_E; + case SCODE_F: return AK_F; + case SCODE_G: return AK_G; + case SCODE_H: return AK_H; + case SCODE_I: return AK_I; + case SCODE_J: return AK_J; + case SCODE_K: return AK_K; + case SCODE_L: return AK_L; + case SCODE_M: return AK_M; + case SCODE_N: return AK_N; + case SCODE_O: return AK_O; + case SCODE_P: return AK_P; + case SCODE_Q: return AK_Q; + case SCODE_R: return AK_R; + case SCODE_S: return AK_S; + case SCODE_T: return AK_T; + case SCODE_U: return AK_U; + case SCODE_V: return AK_V; + case SCODE_W: return AK_W; + case SCODE_X: return AK_X; + case SCODE_Y: return AK_Y; + case SCODE_Z: return AK_Z; + + case SCODE_0: return AK_0; + case SCODE_1: return AK_1; + case SCODE_2: return AK_2; + case SCODE_3: return AK_3; + case SCODE_4: return AK_4; + case SCODE_5: return AK_5; + case SCODE_6: return AK_6; + case SCODE_7: return AK_7; + case SCODE_8: return AK_8; + case SCODE_9: return AK_9; + + case SCODE_KEYPAD0: return AK_NP0; + case SCODE_KEYPAD1: return AK_NP1; + case SCODE_KEYPAD2: return AK_NP2; + case SCODE_KEYPAD3: return AK_NP3; + case SCODE_KEYPAD4: return AK_NP4; + case SCODE_KEYPAD5: return AK_NP5; + case SCODE_KEYPAD6: return AK_NP6; + case SCODE_KEYPAD7: return AK_NP7; + case SCODE_KEYPAD8: return AK_NP8; + case SCODE_KEYPAD9: return AK_NP9; + + case SCODE_KEYPADADD: return AK_NPADD; + case SCODE_KEYPADSUB: return AK_NPSUB; + case SCODE_KEYPADMUL: return AK_NPMUL; + case SCODE_KEYPADDIV: return AK_NPDIV; + case SCODE_KEYPADRET: return AK_ENT; + case SCODE_KEYPADDOT: return AK_NPDEL; + + case SCODE_F1: return AK_F1; + case SCODE_F2: return AK_F2; + case SCODE_F3: return AK_F3; + case SCODE_F4: return AK_F4; + case SCODE_F5: return AK_F5; + case SCODE_F6: return AK_F6; + case SCODE_F7: return AK_F7; + case SCODE_F8: return AK_F8; + case SCODE_F9: return AK_F9; + case SCODE_F10: return AK_F10; + + case SCODE_BS: return AK_BS; + case SCODE_LCONTROL: return AK_CTRL; + case SCODE_RCONTROL: return AK_RCTRL; + case SCODE_TAB: return AK_TAB; + case SCODE_LALT: return AK_LALT; + case SCODE_RALT: return AK_RALT; + case SCODE_ENTER: return AK_RET; + case SCODE_SPACE: return AK_SPC; + case SCODE_LSHIFT: return AK_LSH; + case SCODE_RSHIFT: return AK_RSH; + case SCODE_ESCAPE: return AK_ESC; + + case SCODE_INSERT: return AK_HELP; + case SCODE_END: return AK_NPRPAREN; + case SCODE_HOME: return AK_NPLPAREN; + + case SCODE_DELETE: return AK_DEL; + case SCODE_CB_UP: return AK_UP; + case SCODE_CB_DOWN: return AK_DN; + case SCODE_CB_LEFT: return AK_LF; + case SCODE_CB_RIGHT: return AK_RT; + + case SCODE_PRTSCR: return AK_BACKSLASH; + case SCODE_asciicircum: return AK_BACKQUOTE; + case SCODE_bracketleft: return AK_LBRACKET; + case SCODE_bracketright: return AK_RBRACKET; + case SCODE_comma: return AK_COMMA; + case SCODE_period: return AK_PERIOD; + case SCODE_slash: return AK_SLASH; + case SCODE_semicolon: return AK_SEMICOLON; + case SCODE_grave: return AK_QUOTE; + case SCODE_minus: return AK_MINUS; + case SCODE_equal: return AK_EQUAL; + + /* This one turns off screen updates. */ + case SCODE_SLOCK: return AK_inhibit; + + case SCODE_PGUP: case SCODE_RWIN95: return AK_RAMI; + case SCODE_PGDN: case SCODE_LWIN95: return AK_LAMI; + +/*#ifdef KBD_LANG_DE*/ + case SCODE_numbersign: return AK_NUMBERSIGN; + case SCODE_ltgt: return AK_LTGT; +/*#endif*/ + } + return -1; +} + +static void my_kbd_handler (int scancode, int newstate) +{ + int akey = scancode2amiga (scancode); + + assert (scancode >= 0 && scancode < 0x100); + if (scancode == SCODE_F12) { + uae_quit (); + } else if (scancode == SCODE_F11) { + gui_requested = 1; + } + if (keystate[scancode] == newstate) + return; + + keystate[scancode] = newstate; + + if (akey == -1) + return; + + if (newstate == KEY_EVENTPRESS) { + if (akey == AK_inhibit) + toggle_inhibit_frame (0); + else + record_key (akey << 1); + } else + record_key ((akey << 1) | 1); + + /* "Affengriff" */ + if ((keystate[AK_CTRL] || keystate[AK_RCTRL]) && keystate[AK_LAMI] && keystate[AK_RAMI]) + uae_reset (); +} + +static void leave_graphics_mode (void) +{ + keyboard_close (); + mouse_close (); + sleep (1); /* Maybe this will fix the "screen full of garbage" problem */ + current_vgamode = TEXT; + vga_setmode (TEXT); +} + +static int post_enter_graphics (void) +{ + vga_setmousesupport (1); + mouse_init("/dev/mouse", vga_getmousetype (), 10); + if (keyboard_init() != 0) { + leave_graphics_mode (); + write_log ("Are you sure you have a keyboard??\n"); + return 0; + } + keyboard_seteventhandler (my_kbd_handler); + keyboard_translatekeys (DONT_CATCH_CTRLC); + + mouse_setxrange (-1000, 1000); + mouse_setyrange (-1000, 1000); + mouse_setposition (0, 0); + + return 1; +} + +static int enter_graphics_mode (int which) +{ + int oldmode = current_vgamode; + vga_setmode (TEXT); + if (vga_setmode (which) < 0) { + sleep(1); + vga_setmode (TEXT); + write_log ("SVGAlib doesn't like my video mode (%d). Giving up.\n", which); + return 0; + } + current_vgamode = which; + + linear_mem = 0; + if ((modeinfo.flags & CAPABLE_LINEAR) && ! currprefs.svga_no_linear) { + int val = vga_setlinearaddressing (); + int new_ul = val != -1 ? !need_dither : 0; + if (using_linear == -1) + using_linear = new_ul; + else + if (using_linear != new_ul) { + leave_graphics_mode (); + write_log ("SVGAlib feeling not sure about linear modes???\n"); + abort (); + } + if (val != -1) { + linear_mem = (char *)vga_getgraphmem (); + write_log ("Using linear addressing: %p.\n", linear_mem); + } + } + + return post_enter_graphics (); +} + +static int enter_graphics_mode_picasso (int which) +{ + int oldmode = current_vgamode; + if (which == oldmode) + return 1; + + vga_setmode (TEXT); + if (vga_setmode (which) < 0) { + sleep (1); + vga_setmode (TEXT); + write_log ("SVGAlib doesn't like my video mode (%d). Giving up.\n", which); + exit (1); + } + current_vgamode = which; + + linear_mem = 0; + if ((modeinfo.flags & CAPABLE_LINEAR) && ! currprefs.svga_no_linear) { + int val = vga_setlinearaddressing (); + if (val != -1) { + linear_mem = (char *)vga_getgraphmem (); + write_log ("Using linear addressing: %p.\n", linear_mem); + } + } + + keyboard_close (); + mouse_close (); + return post_enter_graphics (); +} + +int graphics_setup (void) +{ + int i,j, count = 1; + + vga_init(); + + current_vgamode = TEXT; + + for (i = 0; i < MAX_SCREEN_MODES; i++) { + /* Ignore the larger modes which only make sense for Picasso screens. */ + if (x_size_table[i] > 800 || y_size_table[i] > 600) + continue; + + for (j = 0; j < MAX_COLOR_MODES+1; j++) { + /* Delete modes which are not available on this card. */ + if (!vga_hasmode (vga_mode_table[i][j])) { + vga_mode_table[i][j] = -1; + } + + if (vga_mode_table[i][j] != -1) + count++; + } + } + + video_mode_menu = (struct bstring *)malloc (sizeof (struct bstring)*count); + memset (video_mode_menu, 0, sizeof (struct bstring)*count); + count = 0; + + for (i = 0; i < MAX_SCREEN_MODES; i++) { + /* Ignore the larger modes which only make sense for Picasso screens. */ + if (x_size_table[i] > 800 || y_size_table[i] > 600) + continue; + + for (j = 0; j < MAX_COLOR_MODES+1; j++) { + char buf[80]; + if (vga_mode_table[i][j] == -1) + continue; + + sprintf (buf, "%3dx%d, %s", x_size_table[i], y_size_table[i], + colormodes[j]); + video_mode_menu[count].val = -1; + video_mode_menu[count++].data = strdup(buf); + } + } + video_mode_menu[count].val = -3; + video_mode_menu[count++].data = NULL; + return 1; +} + +void vidmode_menu_selected(int m) +{ + int i, j; + for (i = 0; i < MAX_SCREEN_MODES; i++) { + /* Ignore the larger modes which only make sense for Picasso screens. */ + if (x_size_table[i] > 800 || y_size_table[i] > 600) + continue; + for (j = 0; j < MAX_COLOR_MODES+1; j++) { + if (vga_mode_table[i][j] != -1) + if (!m--) + goto found; + + } + } + abort(); + + found: + currprefs.gfx_width = x_size_table[i]; + currprefs.gfx_height = y_size_table[i]; + currprefs.color_mode = j; +} + +static int select_mode_from_prefs (void) +{ + int mode_nr0, mode_nr; + int i; + + if (currprefs.color_mode > 5) + write_log ("Bad color mode selected. Using default.\n"), currprefs.color_mode = 0; + + mode_nr0 = 0; + for (i = 1; i < MAX_SCREEN_MODES; i++) { + if (x_size_table[mode_nr0] >= currprefs.gfx_width) + break; + if (x_size_table[i-1] != x_size_table[i]) + mode_nr0 = i; + } + mode_nr = -1; + for (i = mode_nr0; i < MAX_SCREEN_MODES && x_size_table[i] == x_size_table[mode_nr0]; i++) { + if ((y_size_table[i] >= currprefs.gfx_height + || i + 1 == MAX_SCREEN_MODES + || x_size_table[i+1] != x_size_table[mode_nr0]) + && vga_mode_table[i][currprefs.color_mode] != -1) + { + mode_nr = i; + break; + } + } + if (mode_nr == -1) { + write_log ("Sorry, this combination of color and video mode is not supported.\n"); + return 0; + } + vgamode = vga_mode_table[mode_nr][currprefs.color_mode]; + if (vgamode == -1) { + write_log ("Bug!\n"); + abort (); + } + write_log ("Desired resolution: %dx%d, using: %dx%d\n", + currprefs.gfx_width, currprefs.gfx_height, + x_size_table[mode_nr], y_size_table[mode_nr]); + + currprefs.gfx_width = x_size_table[mode_nr]; + currprefs.gfx_height = y_size_table[mode_nr]; + + return 1; +} + +int graphics_init (void) +{ + int i; + need_dither = 0; + screen_is_picasso = 0; + + if (!select_mode_from_prefs ()) + return 0; + + bitdepth = mode_bitdepth[currprefs.color_mode][0]; + bit_unit = mode_bitdepth[currprefs.color_mode][1]; + need_dither = mode_bitdepth[currprefs.color_mode][2]; + + modeinfo = *vga_getmodeinfo (vgamode); + + gfxvidinfo.pixbytes = modeinfo.bytesperpixel; + if (!need_dither) { + if (modeinfo.bytesperpixel == 0) { + printf("Got a bogus value from SVGAlib...\n"); + gfxvidinfo.pixbytes = 1; + } + } else { + gfxvidinfo.pixbytes = 2; + } + + using_linear = -1; + + if (!enter_graphics_mode (vgamode)) + return 0; + + sleep(2); + gfxvidinfo.maxblocklines = 0; + + gfxvidinfo.width = modeinfo.width; + gfxvidinfo.height = modeinfo.height; + + if (linear_mem != NULL && !need_dither) { + gfxvidinfo.bufmem = linear_mem; + gfxvidinfo.rowbytes = modeinfo.linewidth; + } else { + gfxvidinfo.rowbytes = (modeinfo.width * gfxvidinfo.pixbytes + 3) & ~3; +#if 1 + gfxvidinfo.bufmem = malloc (gfxvidinfo.rowbytes); + gfxvidinfo.linemem = gfxvidinfo.bufmem; + memset (gfxvidinfo.bufmem, 0, gfxvidinfo.rowbytes); +#else + gfxvidinfo.bufmem = malloc(gfxvidinfo.rowbytes * modeinfo.height); + memset (gfxvidinfo.bufmem, 0, gfxvidinfo.rowbytes * modeinfo.height); +#endif + gfxvidinfo.emergmem = 0; + } + printf ("rowbytes %d\n", gfxvidinfo.rowbytes); + init_colors (); + buttonstate[0] = buttonstate[1] = buttonstate[2] = 0; + for(i = 0; i < 256; i++) + keystate[i] = 0; + + lastmx = lastmy = 0; + newmousecounters = 0; + + return 1; +} + +void graphics_leave (void) +{ + leave_graphics_mode (); + dumpcustom(); +} + +void handle_events (void) +{ + int button = mouse_getbutton (); + + gui_requested = 0; + keyboard_update (); + mouse_update (); + lastmx += mouse_getx (); + lastmy += mouse_gety (); + mouse_setposition (0, 0); + + buttonstate[0] = button & 4; + buttonstate[1] = button & 2; + buttonstate[2] = button & 1; + +#ifdef PICASSO96 + if (screen_is_picasso && !picasso_vidinfo.extra_mem) { + int i; + char *addr = gfxmemory + (picasso96_state.Address - gfxmem_start); + for (i = 0; i < picasso_vidinfo.height; i++, addr += picasso96_state.BytesPerRow) { + if (!picasso_invalid_lines[i]) + continue; + picasso_invalid_lines[i] = 0; + vga_drawscanline (i, addr); + } + } +#endif + + if (!screen_is_picasso && gui_requested) { + leave_graphics_mode (); + gui_changesettings (); + enter_graphics_mode (vgamode); + if (linear_mem != NULL && !need_dither) + gfxvidinfo.bufmem = linear_mem; + restore_vga_colors (); + notice_screen_contents_lost (); + } +} + +int check_prefs_changed_gfx (void) +{ + return 0; +} + +int debuggable (void) +{ + return 0; +} + +int needmousehack (void) +{ + return 0; +} + +void LED (int on) +{ +} + +#ifdef PICASSO96 + +void DX_Invalidate (int first, int last) +{ + do { + picasso_invalid_lines[first] = 1; + first++; + } while (first <= last); +} + +int DX_BitsPerCannon (void) +{ + return 8; +} + +void DX_SetPalette(int start, int count) +{ + if (!screen_is_picasso || picasso_vidinfo.pixbytes != 1) + return; + + while (count-- > 0) { + vga_setpalette(start, picasso96_state.CLUT[start].Red * 63 / 255, + picasso96_state.CLUT[start].Green * 63 / 255, + picasso96_state.CLUT[start].Blue * 63 / 255); + start++; + } +} + +int DX_FillResolutions (uae_u16 *ppixel_format) +{ + int i, count = 0; + uae_u16 format = 0; + + for (i = 0; i < MAX_SCREEN_MODES; i++) { + int mode = vga_mode_table[i][0]; + if (mode != -1) { + DisplayModes[count].res.width = x_size_table[i]; + DisplayModes[count].res.height = y_size_table[i]; + DisplayModes[count].depth = 1; + DisplayModes[count].refresh = 75; + count++; + format |= RGBFF_CHUNKY; + } + mode = vga_mode_table[i][2]; + if (mode != -1) { + DisplayModes[count].res.width = x_size_table[i]; + DisplayModes[count].res.height = y_size_table[i]; + DisplayModes[count].depth = 2; + DisplayModes[count].refresh = 75; + count++; + format |= RGBFF_R5G6B5PC; + } + mode = vga_mode_table[i][5]; + if (mode != -1) { + DisplayModes[count].res.width = x_size_table[i]; + DisplayModes[count].res.height = y_size_table[i]; + DisplayModes[count].depth = 4; + DisplayModes[count].refresh = 75; + count++; + format |= RGBFF_B8G8R8A8; + } + } + + *ppixel_format = format; + return count; +} + +static void set_window_for_picasso (void) +{ + enter_graphics_mode_picasso (picasso_vgamode); + if (linear_mem != NULL) + picasso_vidinfo.extra_mem = 1; + else + picasso_vidinfo.extra_mem = 0; + printf ("em: %d\n", picasso_vidinfo.extra_mem); + DX_SetPalette (0, 256); +} + +static void set_window_for_amiga (void) +{ + leave_graphics_mode (); + enter_graphics_mode (vgamode); + if (linear_mem != NULL && !need_dither) + gfxvidinfo.bufmem = linear_mem; + + restore_vga_colors (); +} + +void gfx_set_picasso_modeinfo (int w, int h, int depth, int rgbfmt) +{ + vga_modeinfo *info; + int i, mode; + + for (i = 0; i < MAX_SCREEN_MODES; i++) + if (x_size_table[i] == w && y_size_table[i] == h) + break; + printf ("::: %d %d %d, %d\n", w, h, depth, i); + if (i == MAX_SCREEN_MODES) + abort (); + mode = (depth == 8 ? vga_mode_table[i][0] + : depth == 16 ? vga_mode_table[i][2] + : depth == 32 ? vga_mode_table[i][5] + : -1); + printf ("::: %d\n", mode); + if (mode == -1) + abort (); + + info = vga_getmodeinfo (mode); + printf ("::: %d\n", info->linewidth); + picasso_vgamode = mode; + picasso_vidinfo.width = w; + picasso_vidinfo.height = h; + picasso_vidinfo.depth = depth; + picasso_vidinfo.pixbytes = depth>>3; + picasso_vidinfo.rowbytes = info->linewidth; + picasso_vidinfo.rgbformat = (depth == 8 ? RGBFB_CHUNKY + : depth == 16 ? RGBFB_R5G6B5PC + : RGBFB_B8G8R8A8); + if (screen_is_picasso) + set_window_for_picasso (); +} + +void gfx_set_picasso_baseaddr (uaecptr a) +{ +} + +void gfx_set_picasso_state (int on) +{ + if (on == screen_is_picasso) + return; + screen_is_picasso = on; + if (on) + set_window_for_picasso (); + else + set_window_for_amiga (); +} + +uae_u8 *gfx_lock_picasso (void) +{ + return linear_mem; +} +void gfx_unlock_picasso (void) +{ +} +#endif + +int lockscr (void) +{ + return 1; +} + +void unlockscr (void) +{ +} + +void target_save_options (FILE *f, struct uae_prefs *p) +{ + fprintf (f, "svga.no_linear=%s\n", p->svga_no_linear ? "true" : "false"); +} + +int target_parse_option (struct uae_prefs *p, char *option, char *value) +{ + return (cfgfile_yesno (option, value, "no_linear", &p->svga_no_linear)); +} + +/* Dummy entry to make it compile */ +void DX_SetPalette_vsync(void) +{} diff --git a/svgancui.c b/svgancui.c new file mode 100755 index 00000000..d405fc9b --- /dev/null +++ b/svgancui.c @@ -0,0 +1,578 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * ncurses frontend for a text-based user interface. + * + * Copyright 1996 Bernd Schmidt + * If you find the routines in this file useful, you may use them in your + * programs without restrictions. Essentially, it's in the public domain. + * + */ + + +#include "sysconfig.h" +#include "sysdeps.h" + +#ifdef HAVE_NCURSES_H +#include +#else +#include +#endif +#include + +#include "config.h" +#include "options.h" +#include "uae.h" +#include "tui.h" + +#ifdef DONT_HAVE_ATTR_T +typedef int attr_t; +#endif + +static WINDOW *currwin; + +static WINDOW *winstack[10]; /* more than enough */ +static int winnr = 0; + +void tui_setup(void) +{ + int i; + + for (i = 0; i < 10; i++) + winstack[i] = NULL; + /* From the ncurses manpage... */ + initscr (); start_color (); cbreak(); noecho(); nonl (); intrflush (stdscr, FALSE); keypad (stdscr, TRUE); + currwin = stdscr; + if (has_colors ()) { + init_pair (1, COLOR_WHITE, COLOR_BLUE); + init_pair (2, COLOR_BLACK, COLOR_WHITE); + wattron (currwin, COLOR_PAIR (1) | A_BOLD); + wbkgd (currwin, ' ' | COLOR_PAIR (1)); + } + + winstack[0] = stdscr; + winnr = 1; +} + +int tui_lines (void) +{ + return LINES; +} + +int tui_cols (void) +{ + return COLS; +} + +void tui_shutdown (void) +{ + endwin (); +} + +void tui_refresh (void) +{ + int w; + for (w = 0; w < winnr; w++) { + touchwin (winstack[w]); + wnoutrefresh (winstack[w]); + } + doupdate (); +} + +void tui_puts (const char *s) +{ + waddstr (currwin, s); +} + +void tui_cursoff(void) +{ +} + +void tui_curson (void) +{ +} + +void tui_putc(char c) +{ + waddch (currwin, c); +} + +void tui_cr (void) +{ + waddch (currwin, '\r'); +} + +char tui_getc(void) +{ + return getch (); +} + +void tui_gotoxy (int x, int y) +{ + x--; y--; + wmove (currwin, y, x); +} + +void tui_selwin (int w) +{ + currwin = winstack[w]; +} + +void tui_clrwin (int w) +{ + werase (winstack[w]); +} + +void tui_drawbox(int w) +{ + wborder (winstack[w], 0, 0, 0, 0, 0, 0, 0, 0); +} + +void tui_hline (int x1, int y1, int x2) +{ + wmove (currwin, y1-1, x1-1); + whline (currwin, 0, x2-x1+1); +} + +int tui_dlog(int x1, int y1, int x2, int y2) +{ + x1--; y1--; + winstack[winnr] = newwin (y2 - y1, x2 - x1, y1, x1); + return winnr++; +} + +void tui_dlogdie (int w) +{ + if (currwin == winstack[w]) + currwin = stdscr; + delwin (winstack[w]); + winstack[w] = NULL; + while (winstack[winnr-1] == NULL) + winnr--; + + for (w = 0; w < winnr; w++) + redrawwin (winstack[w]), wrefresh (winstack[w]); +} + +int tui_gets (char *buf, int x, int y, int n) +{ + int i = 0; + for (;;) { + int c, j; + + buf[i] = 0; + wmove (currwin, y, x); + for (j = 0; j < i; j++) + waddch (currwin, buf[j]); + for (; j < n; j++) + waddch (currwin, ' '); + + wmove (currwin, y, x + i); + wrefresh (currwin); + + c = getch (); + + wmove (currwin, y, x + i); + if (c == 13) + return 1; + else if (c == 27) + return 0; + else if (i > 0 && c == KEY_BACKSPACE) + i--; + else if (i + 1 < n && !iscntrl (c)) + buf[i++] = c; + } +} + +int tui_wgets (char *buf, const char *title, int n) +{ + int l = strlen (title); + int ww = (l > n ? l : n) + 2; + int w = tui_dlog((tui_cols ()-ww)/2, tui_lines ()/2-1, (tui_cols ()+ww)/2, tui_lines ()/2+1); + int result; + + tui_selwin (w); tui_drawbox(w); + wmove (currwin, 0, (ww-l)/2); + waddstr (currwin, title); + result = tui_gets (buf, 1, 1, n); + tui_dlogdie (w); + return result; +} + +int tui_menubrowse (struct bstring *menu, int xoff, int yoff, int selected, int height) +{ + int count = 0, maxsel = 0, maxw = 0; + int i, j, w, s, yp, oldyp; + chtype moresave[6][2]; + int xpos, ypos; + + const char *mtitle = NULL; + + for (i = 0; menu[i].val != -3; i++) { + int tmp; + if (menu[i].val == -4) { + if (maxsel < selected) + selected--; + continue; + } + if (menu[i].val != 0) { + count++; + if (menu[i].val != -2) + maxsel++; + } else + mtitle = menu[i].data; + if ((tmp = strlen (menu[i].data)) > maxw) + maxw = tmp; + } + if (height > count) + height = count; + maxw += 3; + if (strlen (mtitle ? mtitle : "") + 8 > maxw) + maxw = strlen (mtitle ? mtitle : "") + 8; + if (xoff > 0) + xpos = xoff; + else + xpos = tui_cols () + xoff - maxw - 1; + if (yoff > 0) + ypos = yoff; + else + ypos = tui_lines () + yoff - height - 2; + w = tui_dlog(xpos, ypos, xpos+maxw, ypos+height+1); + tui_selwin (w); + tui_drawbox(w); + if (mtitle != NULL) { + mvwaddstr (currwin, 0, 1, mtitle); + } + for (i = 0; i < 6; i++) { + moresave[i][0] = mvwinch (currwin, 0, maxw-6+i); + moresave[i][1] = mvwinch (currwin, height+1, maxw-6+i); + } + s = yp = 0; oldyp = -1; + for (;;) { + int c; + int s2; + + while (selected < yp) + yp--; + while (selected >= yp + height) + yp++; + if (yp == 0) + for (i = 0; i < 6; i++) + mvwaddch (currwin, 0, maxw-6+i, moresave[i][0]); + else + mvwaddstr (currwin, 0, maxw-6, "(more)"); + if (yp + height == count) + for (i = 0; i < 6; i++) + mvwaddch (currwin, height+1, maxw-6+i, moresave[i][1]); + else + mvwaddstr (currwin, height+1, maxw-6, "(more)"); + for (i = s2 = j = 0; i < count; i++, j++) { + int k, x; + attr_t a = s2 == selected ? A_STANDOUT : 0; + while (menu[j].val == 0 || menu[j].val == -4) + j++; + if (i >= yp && i < yp+height) { + mvwaddch (currwin, 1+i-yp, 1, ' ' | a); + for (k = x = 0; menu[j].data[k]; k++, x++) { + int a2 = 0; + c = menu[j].data[k]; + if (c == '_') + c = menu[j].data[++k], a2 = A_UNDERLINE; + mvwaddch (currwin, 1+i-yp, 2+x, c | a | a2); + } + for (; x < maxw-2; x++) { + mvwaddch (currwin, 1+i-yp, 2+x, ' ' | a); + } + } + if (menu[j].val != -2) + s2++; + } + + tui_refresh (); + c = getch (); + if (c == 27) { + tui_dlogdie (w); + return -1; + } else if (c == KEY_ENTER || c == 13 || c == ' ') { + tui_dlogdie (w); + for (i = s2 = j = 0; s2 <= selected; j++) { + if (menu[j].val == -4) { + i++; j++; continue; + } + while (menu[j].val == 0) + j++; + if (s2 == selected) + return i; + if (menu[j].val != -2) + s2++, i++; + } + abort(); + } else switch (c) { + case KEY_UP: + if (selected > 0) + selected--; + break; + case KEY_DOWN: + if (selected + 1 < count) + selected++; + break; + case KEY_PPAGE: + if (selected > height) + selected -= height; + else + selected = 0; + break; + case KEY_NPAGE: + if (selected + height < count) + selected += height; + else + selected = count-1; + break; + default: + for (j = i = 0; menu[i].val != -3; i++) + if (menu[i].val == toupper (c)) { + tui_dlogdie (w); + return j; + } else if (menu[i].val == -1 || menu[i].val == -4 || menu[i].val > 0) { + j++; + } + + break; + } + } + return -1; /* Can't get here */ +} + +void tui_errorbox(const char *err) +{ + const char *hak = "Hit any key"; + int n = strlen (hak); + int l = strlen (err); + int ww = (l > n ? l : n) + 2; + int w = tui_dlog((tui_cols ()-ww)/2, tui_lines ()/2-1, (tui_cols ()+ww)/2, tui_lines ()/2+1); + tui_selwin (w); tui_drawbox(w); + + wmove (currwin, 0, (ww-6)/2); + waddstr (currwin, "Error!"); + wmove (currwin, 1, (ww-l)/2); + waddstr (currwin, err); + wmove (currwin, 2, (ww-n)/2); + waddstr (currwin, hak); + + wrefresh (currwin); + for (;;) { + int c = getch (); + if (c == 13) + break; + } + tui_dlogdie (w); +} + +static char *pattern; +static int maxlen; + +static void put_filename (char *s, int x, int y, attr_t a) +{ + char buf[256]; + int i; + + tui_gotoxy (x,y); + if (strcmp (s, ".") == 0) + strcpy (buf, "(none)"); + else + strcpy (buf, s); + buf[maxlen] = 0; + for (i = 0; i < strlen (buf); i++) + waddch (currwin, buf[i] | a); + for (; i < maxlen; i++) + waddch (currwin, ' ' | a); +} + +static char fsbuf[256]; + +static int selectfn (const struct dirent *de) +{ + int l1, l2; + +/* l1 = strlen (pattern + 1);*/ + l2 = strlen (de->d_name); + + if (l2 >= tui_cols ()-10) /* Restrict length of filenames so we won't mess up the display */ + return 0; + + /* No pattern matching for now. But we don't show hidden files. */ + if (strcmp (de->d_name, ".") != 0 && strcmp (de->d_name, "..") != 0 + && de->d_name[0] == '.') + return 0; + if (l2 > maxlen) + maxlen = l2; + return 1; +} + +static int my_alphasort (const void *a, const void *b) +{ + return strcmp ((*(struct dirent **) a)->d_name, + (*(struct dirent **) b)->d_name); +} + +char *tui_filereq(char *s, char *oldfile, const char *title) +{ + char cwd[256]; + char *retval = fsbuf; + char *tmp; + int fin = 0; + chtype moresave[6][2]; + + /* Save wd */ + if (getcwd (cwd, 256) == NULL) + return NULL; + + /* Change into directory of old file */ + strcpy (fsbuf, oldfile); + tmp = strrchr (fsbuf, '/'); + if (tmp != NULL) { + *tmp = 0; + if (strlen (fsbuf) > 0) + chdir (fsbuf); + } + + pattern = s; + if (s[0] != '*') + write_log ("Can't handle wildcard %s\n", s); + if (s[1] != 0 && strchr (s+1, '*') != NULL) + write_log ("Can't handle wildcard %s\n", s); + for (;!fin;) { + struct dirent **names; + int i, w, n, l, yp, oldyp, s; + + maxlen = 0; + n = scandir (".", &names, selectfn, my_alphasort); + + if (n <= 0) + return NULL; + if (title != NULL && strlen (title) + 6 > maxlen) + maxlen = strlen (title) + 6; + l = n; + if (l > 15) + l = 15; + yp = s = 0; oldyp = -1; + w = tui_dlog (tui_cols () - maxlen - 8, 5, tui_cols () - 5, 5 + l + 1); + tui_selwin (w); tui_drawbox (w); + if (title) + mvwaddstr (currwin, 0, 2, title); + for (i = 0; i < 6; i++) { + moresave[i][0] = mvwinch (currwin, 0, maxlen-3+i); + moresave[i][1] = mvwinch (currwin, l+1, maxlen-3+i); + } + for (;;) { + int c; + char tmp[256]; + while (s < yp) + yp--; + while (s >= yp + l) + yp++; + if (oldyp != yp) { + oldyp = yp; + for (i = 0; i < l; i++) { + put_filename (names[i + yp]->d_name, 3, 2 + i, 0); + } + } + put_filename (names[s]->d_name, 3, 2 + s - yp, A_STANDOUT); + + if (yp == 0) + for (i = 0; i < 6; i++) + mvwaddch (currwin, 0, maxlen-3+i, moresave[i][0]); + else + mvwaddstr (currwin, 0, maxlen-3, "(more)"); + if (yp + l == n) + for (i = 0; i < 6; i++) + mvwaddch (currwin, l+1, maxlen-3+i, moresave[i][1]); + else + mvwaddstr (currwin, l+1, maxlen-3, "(more)"); + + tui_refresh (); + c = getch (); + put_filename (names[s]->d_name, 3, 2 + s - yp, 0); + if (c == 27) { + retval = NULL; fin = 1; + break; + } else if (c == KEY_ENTER || c == 13 || c == ' ') { + int err; + + if (strcmp (names[s]->d_name, ".") == 0) { + fin = 1; + strcpy (fsbuf, ""); + break; + } + err = chdir (names[s]->d_name); + + if (err == 0) + break; + else if (errno == ENOTDIR) { + fin = 1; + if (getcwd (fsbuf, 256) == NULL) + retval = NULL; + if (strlen (fsbuf) + strlen (names[s]->d_name) + 2 >= 256) + retval = NULL; + else { + strcat(fsbuf, "/"); + strcat(fsbuf, names[s]->d_name); + } + break; + } /* else what? */ + } + switch (c) { + case KEY_UP: + if (s > 0) + s--; + break; + case KEY_DOWN: + if (s + 1 < n) + s++; + break; + case KEY_PPAGE: + if (s > l) + s -= l; + else + s = 0; + break; + case KEY_NPAGE: + if (s + l < n) + s += l; + else + s = n - 1; + break; + default: + i = 0; + if (names[s]->d_name[0] == c) + i = s+1; + for (; i < n*2; i++) { + int j = i; + if (i >= n) + j -= n; + if (names[j]->d_name[0] == c) { + s = j; + break; + } + } + } + } +#if 0 + /* @@@ is this right? */ + for (i = 0; i < n; i++) + free (names[i]); + free (names); +#endif + tui_dlogdie (w); + } + chdir (cwd); + return retval; +} + +int tui_backup_optionsfile (void) +{ + char tmp[257]; + strcpy (tmp, optionsfile); + strcat (tmp, "~"); + return rename (optionsfile, tmp); +} diff --git a/table68k b/table68k new file mode 100755 index 00000000..aeed7550 --- /dev/null +++ b/table68k @@ -0,0 +1,260 @@ +% 0: bit 0 +% 1: bit 1 +% c: condition code +% C: condition codes, except F +% f: direction +% i: immediate +% I: immediate, except 00 and ff +% j: immediate 1..8 +% J: immediate 0..15 +% k: immediate 0..7 +% K: immediate 0..63 +% p: immediate 0..3 (CINV and CPUSH: cache field) +% s: source mode +% S: source reg +% d: dest mode +% D: dest reg +% r: reg +% z: size +% +% Actually, a sssSSS may appear as a destination, and +% vice versa. The only difference between sssSSS and +% dddDDD are the valid addressing modes. There is +% no match for immediate and pc-rel. addressing modes +% in case of dddDDD. +% +% Arp: --> -(Ar) +% ArP: --> (Ar)+ +% L: (xxx.L) +% +% Fields on a line: +% 16 chars bitpattern : +% CPU level / privildge level : +% CPU level 0: 68000 +% 1: 68010 +% 2: 68020 +% privilege level 0: not privileged +% 1: unprivileged only on 68000 (check regs.s) +% 2: privileged (check regs.s) +% 3: privileged if size == word (check regs.s) +% Flags set by instruction: XNZVC : +% Flags used by instruction: XNZVC : +% - means flag unaffected / unused +% 0 means flag reset +% 1 means flag set +% ? means programmer was too lazy to check or instruction may trap +% + means instruction is conditional branch +% everything else means flag set/used +% / means instruction is unconditional branch/call +% x means flag is unknown and well-behaved programs shouldn't check it +% srcaddr status destaddr status : +% bitmasks of +% 1 means fetched +% 2 means stored +% 4 means jump offset +% 8 means jump address +% instruction +% + +0000 0000 0011 1100:00:XNZVC:XNZVC:10: ORSR.B #1 +0000 0000 0111 1100:02:?????:?????:10: ORSR.W #1 +0000 0zz0 11ss sSSS:20:?????:?????:11: CHK2.z #1,s[!Dreg,Areg,Aipi,Apdi,Immd] +0000 0000 zzdd dDDD:00:-NZ00:-----:13: OR.z #z,d[!Areg] +0000 0010 0011 1100:00:XNZVC:XNZVC:10: ANDSR.B #1 +0000 0010 0111 1100:02:?????:?????:10: ANDSR.W #1 +0000 0010 zzdd dDDD:00:-NZ00:-----:13: AND.z #z,d[!Areg] +0000 0100 zzdd dDDD:00:XNZVC:-----:13: SUB.z #z,d[!Areg] +0000 0110 zzdd dDDD:00:XNZVC:-----:13: ADD.z #z,d[!Areg] +0000 0110 11ss sSSS:20:?????:?????:10: CALLM s[!Dreg,Areg,Aipi,Apdi,Immd] +0000 0110 11ss sSSS:20:?????:?????:10: RTM s[Dreg,Areg] +0000 1000 00ss sSSS:00:--Z--:-----:11: BTST #1,s[!Areg] +0000 1000 01ss sSSS:00:--Z--:-----:13: BCHG #1,s[!Areg,Immd] +0000 1000 10ss sSSS:00:--Z--:-----:13: BCLR #1,s[!Areg,Immd] +0000 1000 11ss sSSS:00:--Z--:-----:13: BSET #1,s[!Areg,Immd] +0000 1010 0011 1100:00:XNZVC:XNZVC:10: EORSR.B #1 +0000 1010 0111 1100:02:?????:?????:10: EORSR.W #1 +0000 1010 zzdd dDDD:00:-NZ00:-----:13: EOR.z #z,d[!Areg] +0000 1100 zzss sSSS:00:-NZVC:-----:11: CMP.z #z,s[!Areg,Immd] + +0000 1010 11ss sSSS:20:?????:?????:13: CAS.B #1,s[!Dreg,Areg,Immd,PC8r,PC16] +0000 1100 11ss sSSS:20:?????:?????:13: CAS.W #1,s[!Dreg,Areg,Immd,PC8r,PC16] +0000 1100 1111 1100:20:?????:?????:10: CAS2.W #2 +0000 1110 zzss sSSS:22:?????:?????:13: MOVES.z #1,s[!Dreg,Areg,Immd,PC8r,PC16] +0000 1110 11ss sSSS:20:?????:?????:13: CAS.L #1,s[!Dreg,Areg,Immd,PC8r,PC16] +0000 1110 1111 1100:20:?????:?????:10: CAS2.L #2 + +0000 rrr1 00dd dDDD:00:-----:-----:12: MVPMR.W d[Areg-Ad16],Dr +0000 rrr1 01dd dDDD:00:-----:-----:12: MVPMR.L d[Areg-Ad16],Dr +0000 rrr1 10dd dDDD:00:-----:-----:12: MVPRM.W Dr,d[Areg-Ad16] +0000 rrr1 11dd dDDD:00:-----:-----:12: MVPRM.L Dr,d[Areg-Ad16] +0000 rrr1 00ss sSSS:00:--Z--:-----:11: BTST Dr,s[!Areg] +0000 rrr1 01ss sSSS:00:--Z--:-----:13: BCHG Dr,s[!Areg,Immd] +0000 rrr1 10ss sSSS:00:--Z--:-----:13: BCLR Dr,s[!Areg,Immd] +0000 rrr1 11ss sSSS:00:--Z--:-----:13: BSET Dr,s[!Areg,Immd] + +0001 DDDd ddss sSSS:00:-NZ00:-----:12: MOVE.B s,d[!Areg] +0010 DDDd ddss sSSS:00:-----:-----:12: MOVEA.L s,d[Areg] +0010 DDDd ddss sSSS:00:-NZ00:-----:12: MOVE.L s,d[!Areg] +0011 DDDd ddss sSSS:00:-----:-----:12: MOVEA.W s,d[Areg] +0011 DDDd ddss sSSS:00:-NZ00:-----:12: MOVE.W s,d[!Areg] + +0100 0000 zzdd dDDD:00:XxZxC:X-Z--:30: NEGX.z d[!Areg] +0100 0000 11dd dDDD:01:?????:?????:10: MVSR2.W d[!Areg] +0100 0010 zzdd dDDD:00:-0100:-----:20: CLR.z d[!Areg] +0100 0010 11dd dDDD:10:?????:?????:10: MVSR2.B d[!Areg] +0100 0100 zzdd dDDD:00:XNZVC:-----:30: NEG.z d[!Areg] +0100 0100 11ss sSSS:00:XNZVC:-----:10: MV2SR.B s[!Areg] +0100 0110 zzdd dDDD:00:-NZ00:-----:30: NOT.z d[!Areg] +0100 0110 11ss sSSS:02:?????:?????:10: MV2SR.W s[!Areg] +0100 1000 0000 1rrr:20:-----:-----:31: LINK.L Ar,#2 +0100 1000 00dd dDDD:00:X?Z?C:X-Z--:30: NBCD.B d[!Areg] +0100 1000 0100 1kkk:20:?????:?????:10: BKPT #k +0100 1000 01ss sSSS:00:-NZ00:-----:30: SWAP.W s[Dreg] +0100 1000 01ss sSSS:00:-----:-----:00: PEA.L s[!Dreg,Areg,Aipi,Apdi,Immd] +0100 1000 10dd dDDD:00:-NZ00:-----:30: EXT.W d[Dreg] +0100 1000 10dd dDDD:00:-----:-----:02: MVMLE.W #1,d[!Dreg,Areg,Aipi] +0100 1000 11dd dDDD:00:-NZ00:-----:30: EXT.L d[Dreg] +0100 1000 11dd dDDD:00:-----:-----:02: MVMLE.L #1,d[!Dreg,Areg,Aipi] +0100 1001 11dd dDDD:00:-NZ00:-----:30: EXT.B d[Dreg] +0100 1010 zzss sSSS:00:-NZ00:-----:10: TST.z s +0100 1010 11dd dDDD:00:?????:?????:30: TAS.B d[!Areg] +0100 1010 1111 1100:00:?????:?????:00: ILLEGAL +0100 1100 00ss sSSS:20:-NZVC:-----:13: MULL.L #1,s[!Areg] +0100 1100 01ss sSSS:20:?????:?????:13: DIVL.L #1,s[!Areg] +0100 1100 10ss sSSS:00:-----:-----:01: MVMEL.W #1,s[!Dreg,Areg,Apdi,Immd] +0100 1100 11ss sSSS:00:-----:-----:01: MVMEL.L #1,s[!Dreg,Areg,Apdi,Immd] +0100 1110 0100 JJJJ:00:-----:XNZVC:10: TRAP #J +0100 1110 0101 0rrr:00:-----:-----:31: LINK.W Ar,#1 +0100 1110 0101 1rrr:00:-----:-----:30: UNLK.L Ar +0100 1110 0110 0rrr:02:-----:-----:10: MVR2USP.L Ar +0100 1110 0110 1rrr:02:-----:-----:20: MVUSP2R.L Ar +0100 1110 0111 0000:02:-----:-----:00: RESET +0100 1110 0111 0001:00:-----:-----:00: NOP +0100 1110 0111 0010:02:XNZVC:-----:10: STOP #1 +0100 1110 0111 0011:02:XNZVC:-----:00: RTE +0100 1110 0111 0100:00:?????:?????:10: RTD #1 +0100 1110 0111 0101:00:-----:-----:00: RTS +0100 1110 0111 0110:00:-----:XNZVC:00: TRAPV +0100 1110 0111 0111:00:XNZVC:-----:00: RTR +0100 1110 0111 1010:12:?????:?????:10: MOVEC2 #1 +0100 1110 0111 1011:12:?????:?????:10: MOVE2C #1 +0100 1110 10ss sSSS:00://///://///:80: JSR.L s[!Dreg,Areg,Aipi,Apdi,Immd] +0100 rrr1 00ss sSSS:00:?????:?????:11: CHK.L s[!Areg],Dr +0100 rrr1 10ss sSSS:00:?????:?????:11: CHK.W s[!Areg],Dr +0100 1110 11ss sSSS:00://///://///:80: JMP.L s[!Dreg,Areg,Aipi,Apdi,Immd] +0100 rrr1 11ss sSSS:00:-----:-----:02: LEA.L s[!Dreg,Areg,Aipi,Apdi,Immd],Ar + +0101 jjj0 01dd dDDD:00:-----:-----:13: ADDA.W #j,d[Areg] +0101 jjj0 10dd dDDD:00:-----:-----:13: ADDA.L #j,d[Areg] +0101 jjj0 zzdd dDDD:00:XNZVC:-----:13: ADD.z #j,d[!Areg] +0101 jjj1 01dd dDDD:00:-----:-----:13: SUBA.W #j,d[Areg] +0101 jjj1 10dd dDDD:00:-----:-----:13: SUBA.L #j,d[Areg] +0101 jjj1 zzdd dDDD:00:XNZVC:-----:13: SUB.z #j,d[!Areg] +0101 cccc 1100 1rrr:00:-----:-++++:31: DBcc.W Dr,#1 +0101 cccc 11dd dDDD:00:-----:-++++:20: Scc.B d[!Areg] +0101 cccc 1111 1010:20:?????:?????:10: TRAPcc #1 +0101 cccc 1111 1011:20:?????:?????:10: TRAPcc #2 +0101 cccc 1111 1100:20:?????:?????:00: TRAPcc + +% Bxx.L is 68020 only, but setting the CPU level to 2 would give illegal +% instruction exceptions when compiling a 68000 only emulation, which isn't +% what we want either. +0110 0001 0000 0000:00://///://///:40: BSR.W #1 +0110 0001 IIII IIII:00://///://///:40: BSR.B #i +0110 0001 1111 1111:00://///://///:40: BSR.L #2 +0110 CCCC 0000 0000:00:-----:-++++:40: Bcc.W #1 +0110 CCCC IIII IIII:00:-----:-++++:40: Bcc.B #i +0110 CCCC 1111 1111:00:-----:-++++:40: Bcc.L #2 + +0111 rrr0 iiii iiii:00:-NZ00:-----:12: MOVE.L #i,Dr + +1000 rrr0 zzss sSSS:00:-NZ00:-----:13: OR.z s[!Areg],Dr +1000 rrr0 11ss sSSS:00:?????:?????:13: DIVU.W s[!Areg],Dr +1000 rrr1 00dd dDDD:00:XxZxC:X-Z--:13: SBCD.B d[Dreg],Dr +1000 rrr1 00dd dDDD:00:XxZxC:X-Z--:13: SBCD.B d[Areg-Apdi],Arp +1000 rrr1 zzdd dDDD:00:-NZ00:-----:13: OR.z Dr,d[!Areg,Dreg] +1000 rrr1 01dd dDDD:20:?????:?????:12: PACK d[Dreg],Dr +1000 rrr1 01dd dDDD:20:?????:?????:12: PACK d[Areg-Apdi],Arp +1000 rrr1 10dd dDDD:20:?????:?????:12: UNPK d[Dreg],Dr +1000 rrr1 10dd dDDD:20:?????:?????:12: UNPK d[Areg-Apdi],Arp +1000 rrr1 11ss sSSS:00:?????:?????:13: DIVS.W s[!Areg],Dr + +1001 rrr0 zzss sSSS:00:XNZVC:-----:13: SUB.z s,Dr +1001 rrr0 11ss sSSS:00:-----:-----:13: SUBA.W s,Ar +1001 rrr1 zzdd dDDD:00:XNZVC:X-Z--:13: SUBX.z d[Dreg],Dr +1001 rrr1 zzdd dDDD:00:XNZVC:X-Z--:13: SUBX.z d[Areg-Apdi],Arp +1001 rrr1 zzdd dDDD:00:XNZVC:-----:13: SUB.z Dr,d[!Areg,Dreg] +1001 rrr1 11ss sSSS:00:-----:-----:13: SUBA.L s,Ar + +1011 rrr0 zzss sSSS:00:-NZVC:-----:11: CMP.z s,Dr +1011 rrr0 11ss sSSS:00:-NZVC:-----:11: CMPA.W s,Ar +1011 rrr1 11ss sSSS:00:-NZVC:-----:11: CMPA.L s,Ar +1011 rrr1 zzdd dDDD:00:-NZVC:-----:11: CMPM.z d[Areg-Aipi],ArP +1011 rrr1 zzdd dDDD:00:-NZ00:-----:13: EOR.z Dr,d[!Areg] + +1100 rrr0 zzss sSSS:00:-NZ00:-----:13: AND.z s[!Areg],Dr +1100 rrr0 11ss sSSS:00:-NZ00:-----:13: MULU.W s[!Areg],Dr +1100 rrr1 00dd dDDD:00:XxZxC:X-Z--:13: ABCD.B d[Dreg],Dr +1100 rrr1 00dd dDDD:00:XxZxC:X-Z--:13: ABCD.B d[Areg-Apdi],Arp +1100 rrr1 zzdd dDDD:00:-NZ00:-----:13: AND.z Dr,d[!Areg,Dreg] +1100 rrr1 01dd dDDD:00:-----:-----:33: EXG.L Dr,d[Dreg] +1100 rrr1 01dd dDDD:00:-----:-----:33: EXG.L Ar,d[Areg] +1100 rrr1 10dd dDDD:00:-----:-----:33: EXG.L Dr,d[Areg] +1100 rrr1 11ss sSSS:00:-NZ00:-----:13: MULS.W s[!Areg],Dr + +1101 rrr0 zzss sSSS:00:XNZVC:-----:13: ADD.z s,Dr +1101 rrr0 11ss sSSS:00:-----:-----:13: ADDA.W s,Ar +1101 rrr1 zzdd dDDD:00:XNZVC:X-Z--:13: ADDX.z d[Dreg],Dr +1101 rrr1 zzdd dDDD:00:XNZVC:X-Z--:13: ADDX.z d[Areg-Apdi],Arp +1101 rrr1 zzdd dDDD:00:XNZVC:-----:13: ADD.z Dr,d[!Areg,Dreg] +1101 rrr1 11ss sSSS:00:-----:-----:13: ADDA.L s,Ar + +1110 jjjf zz00 0RRR:00:XNZVC:-----:13: ASf.z #j,DR +1110 jjjf zz00 1RRR:00:XNZ0C:-----:13: LSf.z #j,DR +1110 jjjf zz01 0RRR:00:XNZ0C:X----:13: ROXf.z #j,DR +1110 jjjf zz01 1RRR:00:-NZ0C:-----:13: ROf.z #j,DR +1110 rrrf zz10 0RRR:00:XNZVC:X----:13: ASf.z Dr,DR +1110 rrrf zz10 1RRR:00:XNZ0C:X----:13: LSf.z Dr,DR +1110 rrrf zz11 0RRR:00:XNZ0C:X----:13: ROXf.z Dr,DR +1110 rrrf zz11 1RRR:00:-NZ0C:-----:13: ROf.z Dr,DR +1110 000f 11dd dDDD:00:XNZVC:-----:13: ASfW.W d[!Dreg,Areg] +1110 001f 11dd dDDD:00:XNZ0C:-----:13: LSfW.W d[!Dreg,Areg] +1110 010f 11dd dDDD:00:XNZ0C:X----:13: ROXfW.W d[!Dreg,Areg] +1110 011f 11dd dDDD:00:-NZ0C:-----:13: ROfW.W d[!Dreg,Areg] + +1110 1000 11ss sSSS:20:?????:?????:11: BFTST #1,s[!Areg,Apdi,Aipi,Immd] +1110 1001 11ss sSSS:20:?????:?????:11: BFEXTU #1,s[!Areg,Apdi,Aipi,Immd] +1110 1010 11ss sSSS:20:?????:?????:13: BFCHG #1,s[!Areg,Apdi,Aipi,Immd,PC8r,PC16] +1110 1011 11ss sSSS:20:?????:?????:11: BFEXTS #1,s[!Areg,Apdi,Aipi,Immd] +1110 1100 11ss sSSS:20:?????:?????:13: BFCLR #1,s[!Areg,Apdi,Aipi,Immd,PC8r,PC16] +1110 1101 11ss sSSS:20:?????:?????:11: BFFFO #1,s[!Areg,Apdi,Aipi,Immd] +1110 1110 11ss sSSS:20:?????:?????:13: BFSET #1,s[!Areg,Apdi,Aipi,Immd,PC8r,PC16] +1110 1111 11ss sSSS:20:?????:?????:13: BFINS #1,s[!Areg,Apdi,Aipi,Immd,PC8r,PC16] + +% floating point co processor +1111 0010 00ss sSSS:30:?????:?????:11: FPP #1,s +1111 0010 01ss sSSS:30:?????:?????:11: FDBcc #1,s[Areg-Dreg] +1111 0010 01ss sSSS:30:?????:?????:11: FScc #1,s[!Areg,Immd,PC8r,PC16] +1111 0010 0111 1010:30:?????:?????:10: FTRAPcc #1 +1111 0010 0111 1011:30:?????:?????:10: FTRAPcc #2 +1111 0010 0111 1100:30:?????:?????:00: FTRAPcc +1111 0010 10KK KKKK:30:?????:?????:11: FBcc #K,#1 +1111 0010 11KK KKKK:30:?????:?????:11: FBcc #K,#2 +1111 0011 00ss sSSS:32:?????:?????:20: FSAVE s[!Dreg,Areg,Aipi,Immd,PC8r,PC16] +1111 0011 01ss sSSS:32:?????:?????:10: FRESTORE s[!Dreg,Areg,Apdi,Immd] + +1111 0101 iiii iSSS:40:?????:?????:11: MMUOP #i,s + +% 68040 instructions +1111 0100 pp00 1rrr:42:-----:-----:02: CINVL #p,Ar +1111 0100 pp01 0rrr:42:-----:-----:02: CINVP #p,Ar +1111 0100 pp01 1rrr:42:-----:-----:00: CINVA #p +1111 0100 pp10 1rrr:42:-----:-----:02: CPUSHL #p,Ar +1111 0100 pp11 0rrr:42:-----:-----:02: CPUSHP #p,Ar +1111 0100 pp11 1rrr:42:-----:-----:00: CPUSHA #p +% destination register number is encoded in the following word +1111 0110 0010 0rrr:40:-----:-----:12: MOVE16 ArP,AxP +1111 0110 00ss sSSS:40:-----:-----:12: MOVE16 s[Dreg-Aipi],L +1111 0110 00dd dDDD:40:-----:-----:12: MOVE16 L,d[Areg-Aipi] +1111 0110 00ss sSSS:40:-----:-----:12: MOVE16 s[Aind],L +1111 0110 00dd dDDD:40:-----:-----:12: MOVE16 L,d[Aipi-Aind] diff --git a/tui.c b/tui.c new file mode 100755 index 00000000..f7f7d1ba --- /dev/null +++ b/tui.c @@ -0,0 +1,730 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Text-based user interface + * Sie haben es sich verdient! + * + * Copyright 1996 Tim Gunn, Bernd Schmidt + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include +#include + +#include "config.h" +#include "options.h" +#include "threaddep/thread.h" +#include "uae.h" +#include "gensound.h" +#include "joystick.h" +#include "keybuf.h" +#include "autoconf.h" +#include "xwin.h" +#include "tui.h" +#include "gui.h" +#include "memory.h" + +#define MAX_MENU_HEIGHT 15 +#define OPTION_COLUMN 3 +#define MENU_COL_OFFSET -2 + +int mountok=0; + +void gui_led (int led, int on) +{ +} +void gui_filename (int num, const char *name) +{ +} +static void getline (char *p) +{ +} +void gui_handle_events (void) +{ +} +void gui_fps (int x) +{ +} +static void save_settings (void) +{ + FILE *f; + tui_backup_optionsfile (); + f = fopen (optionsfile, "w"); + if (f == NULL) { + write_log ("Error saving options file!\n"); + return; + } + save_options (f, &currprefs); + fclose (f); +} + +void gui_exit() +{ +} + +static struct bstring mainmenu[] = { + { "UAE configuration", 0 }, + { "_Disk settings", 'D' }, + { "_Video settings", 'V' }, + { "_Memory settings", 'M' }, + { "_CPU settings", 'C' }, + { "_Hard disk settings", 'H' }, + { "_Sound settings", 'S' }, + { "_Other settings", 'O' }, + { "S_ave settings", 'A' }, + { "_Run UAE", 'R' }, + { NULL, -3 } +}; + +static struct bstring mainmenu2[] = { + { "UAE configuration", 0 }, + { "_Disk settings", 'D' }, +/* { "_Video settings", 'V' }, + { "_Memory settings", 'M' }, + { "_Hard disk settings", 'H' }, + { "_Sound settings", 'S' }, */ + { "_Other settings", 'O' }, + { "S_ave settings", 'A' }, + { "R_eset UAE", 'E' }, + { "_Quit UAE", 'Q' }, + { "_Run UAE", 'R' }, + { NULL, -3 } +}; + +static struct bstring diskmenu[] = { + { "Floppy disk settings", 0 }, + { "Change DF_0:", '0' }, + { "Change DF_1:", '1' }, + { "Change DF_2:", '2' }, + { "Change DF_3:", '3' }, + { NULL, -3 } +}; + +static struct bstring videomenu[] = { + { "Video settings", 0 }, + { "Change _width", 'W' }, + { "Change _height", 'H' }, + { "Change _color mode", 'C' }, + { "Select predefined _mode", 'M' }, + { "Toggle _low resolution", 'L' }, + { "Change _X centering", 'X' }, + { "Change _Y centering", 'Y' }, + { "Toggle line _doubling", 'D' }, + { "Toggle _aspect _correction", 'A' }, + { "Change _framerate", 'F' }, + { "_Graphics card memory", 'P'}, + { NULL, -3 } +}; + +static struct bstring memorymenu[] = { + { "Memory settings", 0 }, + { "Change _fastmem size", 'F' }, + { "Change _chipmem size", 'C' }, + { "Change _slowmem size", 'S' }, + { "Select ROM _image", 'I' }, + { NULL, -3 } +}; + +static struct bstring cpumenu[] = { + { "Change _CPU", 'C' }, + { NULL, -3 } +}; + +static struct bstring soundmenu[] = { + { "Sound settings", 0 }, + { "Change _sound emulation accuracy", 'S' }, + { "Change m_inimum sound buffer size", 'I' }, + { "Change m_aximum sound buffer size", 'A' }, + { "Change number of _bits", 'B' }, + { "Change output _frequency", 'F' }, + { "Change s_tereo", 'T' }, + { NULL , -3 } +}; + +static struct bstring miscmenu[] = { + { "Miscellaneous settings", 0 }, + { "Toggle joystick port _0 emulation", '0' }, + { "Toggle joystick port _1 emulation", '1' }, + { "Set _CPU emulation speed", 'C' }, + { NULL, -3 } +}; + +static struct bstring hdmenu[] = { +/* { "Harddisk/CDROM emulation settings", 0 },*/ + { "_Add a mounted volume", 'A' }, + { "Add a mounted _volume r/o", 'V' }, + { "Add a hard_file", 'F' }, + { "_Delete a mounted volume", 'D' }, + { NULL, -3 } +}; + +static int makemenu (const char **menu, int x, int y) +{ + const char **m = menu; + int maxlen = 0, count = 0; + int w; + + while (*m != NULL) { + int l = strlen (*m); + if (l > maxlen) + maxlen = l; + m++; count++; + } + w = tui_dlog (x, y, x + maxlen + 2, y + count + 1); + tui_drawbox (w); + tui_selwin (w); + y = 2; + while (*menu != NULL) { + tui_gotoxy (2, y++); + tui_puts (*menu++); + } + tui_selwin (0); + return w; +} + +static char tmpbuf[256]; + +static char *trimfilename(char *s, size_t n) +{ + size_t i; + if (n > 250) + n = 250; + if (strlen (s) == 0) + strcpy (tmpbuf, "none"); + else if (strlen (s) < n) + strcpy (tmpbuf, s); + else { + tmpbuf[0] = '^'; + strcpy (tmpbuf + 1, s + strlen (s) - n + 2); + } + for (i = strlen(tmpbuf); i < n; i++) + tmpbuf[i] = ' '; + tmpbuf[i] = 0; + return tmpbuf; +} + +static void print_configuration (void) +{ + char tmp[256]; + int y = 5; + int i; + + tui_clrwin (0); + + tui_drawbox (0); + tui_hline (2, 3, tui_cols () - 1); + sprintf (tmp, "UAE %d.%d.%d: The Un*x Amiga Emulator", UAEMAJOR, UAEMINOR, UAESUBREV); + tui_gotoxy ((tui_cols () - strlen(tmp))/2, 2); tui_puts (tmp); + strcpy(tmp, "Press RETURN/ENTER to run UAE, ESC to exit"); + tui_gotoxy ((tui_cols () - strlen(tmp))/2, tui_lines ()); tui_puts (tmp); + + tui_gotoxy (OPTION_COLUMN, y++); sprintf (tmp, "Disk file DF0: %s", trimfilename (currprefs.df[0], tui_cols () - 20)); tui_puts (tmp); + tui_gotoxy (OPTION_COLUMN, y++); sprintf (tmp, "Disk file DF1: %s", trimfilename (currprefs.df[1], tui_cols () - 20)); tui_puts (tmp); + tui_gotoxy (OPTION_COLUMN, y++); sprintf (tmp, "Disk file DF2: %s", trimfilename (currprefs.df[2], tui_cols () - 20)); tui_puts (tmp); + tui_gotoxy (OPTION_COLUMN, y++); sprintf (tmp, "Disk file DF3: %s", trimfilename (currprefs.df[3], tui_cols () - 20)); tui_puts (tmp); + y++; + tui_gotoxy (OPTION_COLUMN, y++); + sprintf (tmp, "VIDEO: %d:%d%s %s", currprefs.gfx_width, currprefs.gfx_height, + currprefs.gfx_lores ? " (lores)" : "", colormodes[currprefs.color_mode]); + tui_puts (tmp); + + tui_gotoxy (OPTION_COLUMN+7, y++); + if (currprefs.gfx_linedbl) + tui_puts ("Doubling lines, "); + if (currprefs.gfx_correct_aspect) + tui_puts ("Aspect corrected"); + else + tui_puts ("Not aspect corrected"); + tui_gotoxy (OPTION_COLUMN+7, y++); + if (currprefs.gfx_xcenter) + tui_puts ("X centered"); + if (currprefs.gfx_xcenter == 2) + tui_puts (" (clever)"); + if (currprefs.gfx_ycenter && currprefs.gfx_xcenter) + tui_puts (", "); + if (currprefs.gfx_ycenter) + tui_puts ("Y centered "); + if (currprefs.gfx_ycenter == 2) + tui_puts (" (clever)"); + tui_gotoxy (OPTION_COLUMN+7, y++); + tui_puts ("drawing every "); + switch (currprefs.gfx_framerate) { + case 1: break; + case 2: tui_puts ("2nd "); break; + case 3: tui_puts ("3rd "); break; + default: sprintf (tmp, "%dth ",currprefs.gfx_framerate); tui_puts (tmp); break; + } + tui_puts ("frame. "); + + tui_gotoxy (OPTION_COLUMN+7, y++); + if (currprefs.gfxmem_size) { + sprintf (tmp, "Picasso 96 %d MB", currprefs.gfxmem_size / 0x100000); + tui_puts(tmp); + } else + tui_puts ("Picasso 96 Off"); + y++; + + tui_gotoxy (OPTION_COLUMN, y++); + tui_puts ("CPU: "); + switch (currprefs.cpu_level) { + case 0: tui_puts ("68000"); break; + case 1: tui_puts ("68010"); break; + case 2: tui_puts ("68020"); break; + case 3: tui_puts ("68020/68881"); break; + } + if (currprefs.address_space_24 && currprefs.cpu_level > 1) + tui_puts (" (24 bit addressing)"); + if (currprefs.cpu_compatible) + tui_puts (" (slow but compatible)"); + tui_gotoxy (OPTION_COLUMN, y++); + sprintf (tmp, "MEMORY: %4dK chip; %4dK fast; %4dK slow", + currprefs.chipmem_size/1024, + currprefs.fastmem_size/1024, + currprefs.bogomem_size/1024); + tui_puts (tmp); + + tui_gotoxy (OPTION_COLUMN, y++); + sprintf (tmp, "ROM IMAGE: %s", trimfilename (currprefs.romfile, tui_cols () - 50)); + tui_puts (tmp); + tui_gotoxy (OPTION_COLUMN, y++); + if (!sound_available) + tui_puts ("SOUND: Not available"); + else { + switch (currprefs.produce_sound) { + case 0: tui_puts ("SOUND: 0 (Off)"); break; + case 1: tui_puts ("SOUND: 1 (Off, but emulated)"); break; + case 2: tui_puts ("SOUND: 2 (On)"); break; + case 3: tui_puts ("SOUND: 3 (On, emulated perfectly)"); break; + } + tui_gotoxy (OPTION_COLUMN + 7, y++); + sprintf (tmp, "%d bits at %d Hz", currprefs.sound_bits, currprefs.sound_freq); + tui_puts (tmp); + tui_gotoxy (OPTION_COLUMN + 7, y++); + sprintf (tmp, "Minimum buffer size %d bytes, maximum %d bytes", currprefs.sound_minbsiz, currprefs.sound_maxbsiz); + tui_puts (tmp); + } + + tui_gotoxy (OPTION_COLUMN,y++); + tui_puts ("GAME PORT 1: "); tui_puts (gameport_state (0)); + tui_gotoxy (OPTION_COLUMN,y++); + tui_puts ("GAME PORT 2: "); tui_puts (gameport_state (1)); + + for (i = 0;; i++) { + char buf[256]; + + tui_gotoxy (OPTION_COLUMN+1,y++); + if (sprintf_filesys_unit (currprefs.mountinfo, buf, i) == -1) + break; + tui_puts (buf); + } +} + +static void HDOptions (void) +{ + char *buff; + char tmp[256]; + char mountvol[256]; + char mountdir[256]; + int c = 0; + + for (;;){ + + tui_selwin(0); + print_configuration(); + + c = tui_menubrowse (hdmenu, MENU_COL_OFFSET, 5, c, MAX_MENU_HEIGHT); + if (c == -1) + break; + else switch (c) { + case 0: + tui_wgets (mountvol, "Enter mounted volume name", 10); + if (strlen (mountvol) == 0) + break; + if (mountvol[strlen(mountvol)-1]==':') + mountvol[strlen(mountvol)-1] = 0; + tui_wgets (mountdir, "Enter mounted volume path", 78); + add_filesys_unit (currprefs.mountinfo, mountvol, mountdir, 0, 0, 0, 0, 0); + break; + case 1: + tui_wgets (mountvol, "Enter mounted volume name", 10); + if (strlen (mountvol) == 0) + break; + if (mountvol[strlen (mountvol)-1]==':') + mountvol[strlen (mountvol)-1] = 0; + tui_wgets (mountdir, "Enter mounted volume path", 78); + add_filesys_unit (currprefs.mountinfo, mountvol, mountdir, 1, 0, 0, 0, 0); + break; + case 2: + buff = tui_filereq("*", "", "Select the hardfile to be mounted"); + if (buff == NULL) + break; + strcpy (mountvol, buff); + tui_wgets (mountdir, "Enter number of sectors per track", 4); + tui_wgets (mountdir + 10, "Enter number of heads", 4); + tui_wgets (mountdir + 20, "Enter number of reserved blocks", 3); + tui_wgets (mountdir + 30, "Enter block size", 4); + buff = add_filesys_unit (currprefs.mountinfo, 0, mountvol, 1, + atoi (mountdir), atoi (mountdir + 10), + atoi (mountdir + 20), atoi (mountdir + 30)); + if (buff) + tui_errorbox (buff); + break; + case 3: + tui_wgets (mountvol, "Enter number of volume to be removed (0 for UAE0:, etc.)", 2); + if (kill_filesys_unit (currprefs.mountinfo, atoi (mountvol)) == -1) + tui_errorbox ("Volume does not exist"); + break; + } + } +} + +static void DiskOptions (void) +{ + char tmp[256]; + int c = 0; + + for (;;) { + char *sel; + + tui_selwin(0); + print_configuration(); + + c = tui_menubrowse (diskmenu, MENU_COL_OFFSET, 5, c, MAX_MENU_HEIGHT); + if (c == -1) + break; + else switch (c) { + case 0: + case 1: + case 2: + case 3: + sprintf (tmp, "Select a diskfile for DF%d:", c); + sel = tui_filereq("*.adf", currprefs.df[c], tmp); + if (sel == NULL) + break; + strcpy (currprefs.df[c], sel); + break; + } + } +} + +static void VideoOptions (void) +{ + char tmp[256]; + int c = 0; + + for (c = 0; c < 10; c++) + if (videomenu[c].val == 'M') { + if (video_mode_menu == NULL) + videomenu[c].val = -4; + break; + } + + c = 0; + for (;;) { + + tui_selwin(0); + print_configuration(); + + c = tui_menubrowse (videomenu, MENU_COL_OFFSET, 5, c, MAX_MENU_HEIGHT); + if (c == -1) + break; + else switch (c) { + case 0: + tui_wgets (tmp, "Enter new video mode width", 4); + if (atoi (tmp) < 320 || atoi (tmp) > 1600 /* maybe we'll implement SHires */) + tui_errorbox ("Insane value for video mode width"); + else + currprefs.gfx_width = atoi (tmp); + break; + case 1: + tui_wgets (tmp, "Enter new video mode height", 4); + if (atoi (tmp) < 200 || atoi (tmp) > 800 /* whatever */) + tui_errorbox ("Insane value for video mode height"); + else + currprefs.gfx_height = atoi (tmp); + break; + case 2: + currprefs.color_mode++; + if (currprefs.color_mode > MAX_COLOR_MODES) + currprefs.color_mode=0; + break; + case 3: + c = tui_menubrowse (video_mode_menu, 4, 6, 0, 15); + if (c != -1) + vidmode_menu_selected(c); + c = 3; + break; + case 4: + currprefs.gfx_lores = !currprefs.gfx_lores; + break; + case 5: + currprefs.gfx_xcenter = (currprefs.gfx_xcenter + 1) % 3; + break; + case 6: + currprefs.gfx_ycenter = (currprefs.gfx_ycenter + 1) % 3; + break; + case 7: + currprefs.gfx_linedbl = !currprefs.gfx_linedbl; + break; + case 8: + currprefs.gfx_correct_aspect = !currprefs.gfx_correct_aspect; + break; + case 9: + currprefs.gfx_framerate++; + if (currprefs.gfx_framerate > 9) + currprefs.gfx_framerate=1; + break; + case 10: + currprefs.gfxmem_size += 0x100000; + if (currprefs.gfxmem_size > 0x800000) + currprefs.gfxmem_size = 0; + break; + } + } +} + +static void MemoryOptions (void) +{ + char *tmp; + int c = 0; + for (;;) { + + tui_selwin(0); + print_configuration (); + + c = tui_menubrowse (memorymenu, MENU_COL_OFFSET, 5, c, MAX_MENU_HEIGHT); + if (c == -1) + break; + else switch (c) { + case 0: + if (currprefs.fastmem_size == 0) + currprefs.fastmem_size = 0x200000; + else if (currprefs.fastmem_size == 0x800000) + currprefs.fastmem_size = 0; + else + currprefs.fastmem_size <<= 1; + break; + case 1: + if (currprefs.chipmem_size == 0x800000) + currprefs.chipmem_size = 0x80000; + else + currprefs.chipmem_size <<= 1; + if (currprefs.chipmem_size > 0x200000) + currprefs.fastmem_size = 0; + break; + case 2: + if (currprefs.bogomem_size == 0) + currprefs.bogomem_size = 0x40000; + else if (currprefs.bogomem_size == 0x100000) + currprefs.bogomem_size = 0; + else + currprefs.bogomem_size <<= 1; + break; + case 3: + tmp = tui_filereq ("*.rom", currprefs.romfile, "Select a ROM image"); + if (tmp != NULL) + strcpy (currprefs.romfile, tmp); + break; + } + } +} + +static void CPUOptions (void) +{ + char *tmp; + int c = 0; + for (;;) { + tui_selwin(0); + print_configuration (); + + c = tui_menubrowse (cpumenu, MENU_COL_OFFSET, 5, c, MAX_MENU_HEIGHT); + if (c == -1) + break; + else switch (c) { + case 0: + currprefs.cpu_level++; + if (currprefs.cpu_level > 3) + currprefs.cpu_level = 0; + /* Default to 32 bit addressing when switching from a 68000/68010 to a 32 bit CPU */ + if (currprefs.cpu_level == 2) + currprefs.address_space_24 = 0; + if (currprefs.cpu_level != 0) + currprefs.cpu_compatible = 0; + break; + } + } +} + +static void SoundOptions (void) +{ + char tmp[256]; + int c = 0; + for (;;) { + tui_selwin(0); + print_configuration (); + c = tui_menubrowse (soundmenu, MENU_COL_OFFSET, 5, c, MAX_MENU_HEIGHT); + if (c == -1) + break; + else switch (c) { + case 0: + currprefs.produce_sound++; + if (currprefs.produce_sound > 3) + currprefs.produce_sound = 0; + break; + + case 1: + tui_wgets (tmp, "Enter new minimum sound buffer size in bytes", 6); + if (atoi (tmp) < 128 || atoi (tmp) > 65536 || atoi (tmp) > currprefs.sound_maxbsiz) + tui_errorbox ("Insane value for minimum sound buffer size"); + else + currprefs.sound_minbsiz = atoi (tmp); + break; + + case 2: + tui_wgets (tmp, "Enter new maximum sound buffer size in bytes", 6); + if (atoi (tmp) < 128 || atoi (tmp) > 65536 || atoi (tmp) < currprefs.sound_minbsiz) + tui_errorbox ("Insane value for maximum sound buffer size"); + else + currprefs.sound_maxbsiz = atoi (tmp); + break; + + case 3: + tui_wgets (tmp, "Enter new number of bits", 3); + if (atoi (tmp)!= 8 && atoi (tmp) != 16) + tui_errorbox ("Unsupported number of bits"); + else + currprefs.sound_bits = atoi (tmp); + break; + + case 4: + tui_wgets (tmp, "Enter new sound output frequency", 6); + if (atoi (tmp) < 11025 || atoi (tmp) > 44100) + tui_errorbox ("Unsupported frequency"); + else + currprefs.sound_freq = atoi (tmp); + break; + case 5: + currprefs.stereo = (currprefs.stereo + 1) % 3; + break; + } + } +} + +static void OtherOptions (void) +{ + char tmp[256]; + int c = 0; + + for (;;) { + tui_selwin (0); + print_configuration (); + c = tui_menubrowse (miscmenu, MENU_COL_OFFSET, 5, c, MAX_MENU_HEIGHT); + if (c == -1) { + break; + } else switch (c) { + case 0: + currprefs.jport0 = (currprefs.jport0 + 1) % 6; + if (currprefs.jport0 == currprefs.jport1) + currprefs.jport1 = (currprefs.jport1 + 5) % 6; + break; + case 1: + currprefs.jport1 = (currprefs.jport1 + 1) % 6; + if (currprefs.jport0 == currprefs.jport1) + currprefs.jport0 = (currprefs.jport0 + 5) % 6; + break; + case 2: + tui_wgets (tmp, "Enter new CPU emulation speed", 6); + if (atoi (tmp) < 1 || atoi (tmp) > 20) + tui_errorbox ("Unsupported CPU emulation speed"); + else + currprefs.m68k_speed = atoi (tmp); + break; + } + } +} + +static int do_gui (int mode) +{ + char cwd[1024]; + + if (getcwd (cwd, 1024) == NULL) + return 0; + + tui_setup (); + + for (;;) { + int c; + + tui_selwin (0); + print_configuration (); + c = tui_menubrowse (mode == 0 ? mainmenu2 : mainmenu, MENU_COL_OFFSET, 4, 0, MAX_MENU_HEIGHT); + if (c == -1) { + tui_shutdown (); + return -2; + } + if (mode == 1) { + if (c == 8) + break; + switch (c) { + case 0: DiskOptions (); break; + case 1: VideoOptions (); break; + case 2: MemoryOptions (); break; + case 3: CPUOptions (); break; + case 4: HDOptions (); break; + case 5: SoundOptions (); break; + case 6: OtherOptions (); break; + case 7: save_settings (); break; + } + } else { + if (c == 5) + break; + switch (c) { + case 0: DiskOptions (); break; + case 1: OtherOptions (); break; + case 2: save_settings (); break; + case 3: uae_reset (); break; + case 4: uae_quit (); break; + } + } + } + tui_shutdown (); + + chdir (cwd); + return 0; +} + +int gui_init (void) +{ + return do_gui (1); +} + +void gui_changesettings (void) +{ + struct uae_prefs oldprefs; + oldprefs = currprefs; + + if (do_gui(0) == -2) + uae_quit (); + else { + changed_prefs = currprefs; + currprefs = oldprefs; + currprefs.jport0 = changed_prefs.jport0; + currprefs.jport1 = changed_prefs.jport1; + joystick_setting_changed (); + } +} + +int gui_update (void) +{ + return 0; +} + +void gui_lock (void) +{ +} + +void gui_unlock (void) +{ +} diff --git a/uaeexe.c b/uaeexe.c new file mode 100755 index 00000000..82af30aa --- /dev/null +++ b/uaeexe.c @@ -0,0 +1,123 @@ +/* + * uaeexe.c - UAE remote cli + * + * (c) 1997 by Samuel Devulder + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "uae.h" +#include "memory.h" +#include "custom.h" +#include "newcpu.h" +#include "autoconf.h" +#include "uaeexe.h" + +static struct uae_xcmd *first = NULL; +static struct uae_xcmd *last = NULL; +static char running = 0; +static uae_u32 uaeexe_server(void); + +/* + * Install the server + */ +void uaeexe_install(void) +{ + uaecptr loop; + + loop = here (); + org(UAEEXE_ORG); + calltrap (deftrap (uaeexe_server)); + dw(RTS); + org(loop); +} + +/* + * Send command to the remote cli. + * + * To use this, just call uaeexe("command") and the command will be + * executed by the remote cli (provided you've started it in the + * s:user-startup for example). Be sure to add "run" if you want + * to launch the command asynchronously. Please note also that the + * remote cli works better if you've got the fifo-handler installed. + */ +int uaeexe(char *cmd) +{ + struct uae_xcmd *nw; + + if (!running) + goto NORUN; + + nw = (struct uae_xcmd *)malloc (sizeof *nw); + if (!nw) + goto NOMEM; + nw->cmd = (char *)malloc (strlen (cmd) + 1); + if (!nw->cmd) { + free (nw); + goto NOMEM; + } + + strcpy (nw->cmd, cmd); + nw->prev = last; + nw->next = NULL; + + if(!first) first = nw; + if(last) { + last->next = nw; + last = nw; + } else last = nw; + + return UAEEXE_OK; + NOMEM: + return UAEEXE_NOMEM; + NORUN: + write_log("Remote cli is not running.\n"); + return UAEEXE_NOTRUNNING; +} + +/* + * returns next command to be executed + */ +static char *get_cmd(void) +{ + struct uae_xcmd *cmd; + char *s; + + if(!first) return NULL; + s = first->cmd; + cmd = first; first = first->next; + if(!first) last = NULL; + free(cmd); + return s; +} + +/* + * helper function + */ +#define ARG(x) (get_long (m68k_areg (regs, 7) + 4*(x+1))) +static uae_u32 uaeexe_server(void) +{ + int len; + char *cmd; + char *dst; + + if(ARG(0) && !running) { + running = 1; + write_log("Remote CLI started.\n"); + } + + cmd = get_cmd(); if(!cmd) return 0; + if(!ARG(0)) {running = 0;return 0;} + + dst = (char *)get_real_address(ARG(0)); + len = ARG(1); + strncpy(dst,cmd,len); + printf("Sending '%s' to remote cli\n",cmd); /**/ + free(cmd); + return ARG(0); +} + + diff --git a/uaelib.c b/uaelib.c new file mode 100755 index 00000000..965c7b74 --- /dev/null +++ b/uaelib.c @@ -0,0 +1,434 @@ +/* + * UAE - The U*nix Amiga Emulator + * + * UAE Library v0.1 + * + * (c) 1996 Tauno Taipaleenmaki + * + * Change UAE parameters and other stuff from inside the emulation. + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include +#include + +#include "config.h" +#include "options.h" +#include "threaddep/thread.h" +#include "uae.h" +#include "memory.h" +#include "custom.h" +#include "newcpu.h" +#include "xwin.h" +#include "autoconf.h" +#include "disk.h" +#include "debug.h" +#include "gensound.h" +#include "picasso96.h" + +/* + * Returns UAE Version + */ +static uae_u32 emulib_GetVersion (void) +{ + return version; +} + +/* + * Resets your amiga + */ +static uae_u32 emulib_HardReset (void) +{ + uae_reset(0); + return 0; +} + +static uae_u32 emulib_Reset (void) +{ + uae_reset(0); + return 0; +} + +/* + * Enables SOUND + */ +static uae_u32 emulib_EnableSound (uae_u32 val) +{ + if (!sound_available || currprefs.produce_sound == 2) + return 0; + + currprefs.produce_sound = val; + return 1; +} + +/* + * Enables FAKE JOYSTICK + */ +static uae_u32 emulib_EnableJoystick (uae_u32 val) +{ + currprefs.jport0 = val & 255; + currprefs.jport1 = (val >> 8) & 255; + return 1; +} + +/* + * Sets the framerate + */ +static uae_u32 emulib_SetFrameRate (uae_u32 val) +{ + if (val == 0) + return 0; + else if (val > 20) + return 0; + else { + currprefs.gfx_framerate = val; + return 1; + } +} + +/* + * Changes keyboard language settings + */ +static uae_u32 emulib_ChangeLanguage (uae_u32 which) +{ + if (which > 6) + return 0; + else { + switch (which) { + case 0: + currprefs.keyboard_lang = KBD_LANG_US; + break; + case 1: + currprefs.keyboard_lang = KBD_LANG_DK; + break; + case 2: + currprefs.keyboard_lang = KBD_LANG_DE; + break; + case 3: + currprefs.keyboard_lang = KBD_LANG_SE; + break; + case 4: + currprefs.keyboard_lang = KBD_LANG_FR; + break; + case 5: + currprefs.keyboard_lang = KBD_LANG_IT; + break; + case 6: + currprefs.keyboard_lang = KBD_LANG_ES; + break; + default: + break; + } + return 1; + } +} + +/* The following ones don't work as we never realloc the arrays... */ +/* + * Changes chip memory size + * (reboots) + */ +static uae_u32 emulib_ChgCMemSize (uae_u32 memsize) +{ + if (memsize != 0x80000 && memsize != 0x100000 && + memsize != 0x200000) { + memsize = 0x200000; + write_log ("Unsupported chipmem size!\n"); + } + m68k_dreg(regs, 0) = 0; + + currprefs.chipmem_size = memsize; + uae_reset(0); + return 1; +} + +/* + * Changes slow memory size + * (reboots) + */ +static uae_u32 emulib_ChgSMemSize (uae_u32 memsize) +{ + if (memsize != 0x80000 && memsize != 0x100000 && + memsize != 0x180000 && memsize != 0x1C0000) { + memsize = 0; + write_log ("Unsupported bogomem size!\n"); + } + + m68k_dreg(regs, 0) = 0; + currprefs.bogomem_size = memsize; + uae_reset (0); + return 1; +} + +/* + * Changes fast memory size + * (reboots) + */ +static uae_u32 emulib_ChgFMemSize (uae_u32 memsize) +{ + if (memsize != 0x100000 && memsize != 0x200000 && + memsize != 0x400000 && memsize != 0x800000) { + memsize = 0; + write_log ("Unsupported fastmem size!\n"); + } + m68k_dreg(regs, 0) = 0; + currprefs.fastmem_size = memsize; + uae_reset (0); + return 0; +} + +/* + * Inserts a disk + */ +static uae_u32 emulib_InsertDisk (uaecptr name, uae_u32 drive) +{ + int i = 0; + char real_name[256]; + + if (drive > 3) + return 0; + + while ((real_name[i] = get_byte (name + i)) != 0 && i++ != 254) + ; + + if (i == 255) + return 0; /* ENAMETOOLONG */ + + strcpy (changed_prefs.df[drive], real_name); + + return 1; +} + +/* + * Exits the emulator + */ +static uae_u32 emulib_ExitEmu (void) +{ + uae_quit (); + return 1; +} + +/* + * Gets UAE Configuration + */ +static uae_u32 emulib_GetUaeConfig (uaecptr place) +{ + int i; + + put_long (place, version); + put_long (place + 4, allocated_chipmem); + put_long (place + 8, allocated_bogomem); + put_long (place + 12, allocated_fastmem); + put_long (place + 16, currprefs.gfx_framerate); + put_long (place + 20, currprefs.produce_sound); + put_long (place + 24, currprefs.jport0 | (currprefs.jport1 << 8)); + put_long (place + 28, currprefs.keyboard_lang); + if (disk_empty (0)) + put_byte (place + 32, 0); + else + put_byte (place + 32, 1); + if (disk_empty (1)) + put_byte (place + 33, 0); + else + put_byte (place + 33, 1); + if (disk_empty(2)) + put_byte (place + 34, 0); + else + put_byte (place + 34, 1); + if (disk_empty(3)) + put_byte (place + 35, 0); + else + put_byte (place + 35, 1); + + for (i = 0; i < 256; i++) { + put_byte ((place + 36 + i), currprefs.df[0][i]); + put_byte ((place + 36 + i + 256), currprefs.df[1][i]); + put_byte ((place + 36 + i + 512), currprefs.df[2][i]); + put_byte ((place + 36 + i + 768), currprefs.df[3][i]); + } + return 1; +} + +/* + * Sets UAE Configuration + * + * NOT IMPLEMENTED YET + */ +static uae_u32 emulib_SetUaeConfig (uaecptr place) +{ + return 1; +} + +/* + * Gets the name of the disk in the given drive + */ +static uae_u32 emulib_GetDisk (uae_u32 drive, uaecptr name) +{ + int i; + if (drive > 3) + return 0; + + for (i = 0;i < 256; i++) { + put_byte (name + i, currprefs.df[drive][i]); + } + return 1; +} + +/* + * Enter debugging state + */ +static uae_u32 emulib_Debug (void) +{ + activate_debugger (); + return 1; +} + +/* We simply find the first "text" hunk, get the offset of its actual code segment (20 bytes away) + * and add that offset to the base address of the object. Now we've got code to execute. + * + * @@@ Brian: does anything actually use this yet? + * @@@ Bernd: Not yet. It needs to get much better. Should spawn off a seperate task to handle the + * function, and then somehow "signal" the Amiga caller that completion or error has + * occurred. I don't know how to do that, so right now it is a synchronous call. Yuck! + * Would be nice to implement jpg decompression functionality for the Amiga which used + * the UAE Host to do all the work, for example. + * @@@ Brian: I disabled it to prevent people from starting to use it - if that happens, we're + * stuck with this. + */ +static uae_u32 FindFunctionInObject (uae_u8 *objectptr) +{ + uae_u8 *text_hdr; + uae_u8 offset; + text_hdr = (uae_u8 *)strstr ("text", (char *)objectptr); + if (text_hdr != 0) { + offset = *(text_hdr + 19); + return (uae_u32)(objectptr + offset); + } + return 0; +} + +#define CREATE_NATIVE_FUNC_PTR uae_u32 (* native_func)( uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, \ + uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32) +#define SET_NATIVE_FUNC(x) native_func = (uae_u32 (*)(uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32, uae_u32))(x) +#define CALL_NATIVE_FUNC( d1,d2,d3,d4,d5,d6,d7,a1,a2,a3,a4,a5,a6 ) if(native_func) native_func( d1,d2,d3,d4,d5,d6,d7,a1,a2,a3,a4,a5,a6 ) +/* A0 - Contains a ptr to the native .obj data. This ptr is Amiga-based. */ +/* We simply find the first function in this .obj data, and execute it. */ +static uae_u32 emulib_ExecuteNativeCode (void) +{ +#if 0 + uaecptr object_AAM = m68k_areg( regs, 0 ); + uae_u32 d1 = m68k_dreg( regs, 1 ); + uae_u32 d2 = m68k_dreg( regs, 2 ); + uae_u32 d3 = m68k_dreg( regs, 3 ); + uae_u32 d4 = m68k_dreg( regs, 4 ); + uae_u32 d5 = m68k_dreg( regs, 5 ); + uae_u32 d6 = m68k_dreg( regs, 6 ); + uae_u32 d7 = m68k_dreg( regs, 7 ); + uae_u32 a1 = m68k_areg( regs, 1 ); + uae_u32 a2 = m68k_areg( regs, 2 ); + uae_u32 a3 = m68k_areg( regs, 3 ); + uae_u32 a4 = m68k_areg( regs, 4 ); + uae_u32 a5 = m68k_areg( regs, 5 ); + uae_u32 a6 = m68k_areg( regs, 6 ); + + uae_u8* object_UAM = NULL; + CREATE_NATIVE_FUNC_PTR; + + if( get_mem_bank( object_AAM ).check( object_AAM, 1 ) ) + object_UAM = get_mem_bank( object_AAM).xlateaddr( object_AAM ); + + if( object_UAM ) + { + SET_NATIVE_FUNC( FindFunctionInObject( object_UAM ) ); + CALL_NATIVE_FUNC( d1, d2, d3, d4, d5, d6, d7, a1, a2, a3, a4, a5, a6); + } + return 1; +#endif + return 0; +} + +static uae_u32 emulib_Minimize (void) +{ + return OSDEP_minimize_uae(); +} + +static uae_u32 uaelib_demux (void) +{ +#define ARG0 (get_long (m68k_areg (regs, 7) + 4)) +#define ARG1 (get_long (m68k_areg (regs, 7) + 8)) +#define ARG2 (get_long (m68k_areg (regs, 7) + 12)) +#define ARG3 (get_long (m68k_areg (regs, 7) + 16)) +#define ARG4 (get_long (m68k_areg (regs, 7) + 20)) + + switch (ARG0) { + case 0: return emulib_GetVersion (); + case 1: return emulib_GetUaeConfig (ARG1); + case 2: return emulib_SetUaeConfig (ARG1); + case 3: return emulib_HardReset (); + case 4: return emulib_Reset (); + case 5: return emulib_InsertDisk (ARG1, ARG2); + case 6: return emulib_EnableSound (ARG1); + case 7: return emulib_EnableJoystick (ARG1); + case 8: return emulib_SetFrameRate (ARG1); + case 9: return emulib_ChgCMemSize (ARG1); + case 10: return emulib_ChgSMemSize (ARG1); + case 11: return emulib_ChgFMemSize (ARG1); + case 12: return emulib_ChangeLanguage (ARG1); + /* The next call brings bad luck */ + case 13: return emulib_ExitEmu (); + case 14: return emulib_GetDisk (ARG1, ARG2); + case 15: return emulib_Debug (); + +#ifdef PICASSO96 + case 16: return picasso_FindCard (); + case 17: return picasso_FillRect (); + case 18: return picasso_SetSwitch (); + case 19: return picasso_SetColorArray (); + case 20: return picasso_SetDAC (); + case 21: return picasso_SetGC (); + case 22: return picasso_SetPanning (); + case 23: return picasso_CalculateBytesPerRow (); + case 24: return picasso_BlitPlanar2Chunky (); + case 25: return picasso_BlitRect (); + case 26: return picasso_SetDisplay (); + case 27: return picasso_BlitTemplate (); + case 28: return picasso_BlitRectNoMaskComplete (); + case 29: return picasso_InitCard (); + case 30: return picasso_BlitPattern (); + case 31: return picasso_InvertRect (); + case 32: return picasso_BlitPlanar2Direct (); + /* case 34: return picasso_WaitVerticalSync (); handled in asm-code */ + case 35: return allocated_gfxmem ? 1 : 0; +#ifdef HARDWARE_SPRITE_EMULATION + case 36: return picasso_SetSprite (); + case 37: return picasso_SetSpritePosition (); + case 38: return picasso_SetSpriteImage (); + case 39: return picasso_SetSpriteColor (); +#endif + case 40: return picasso_DrawLine (); +#endif + case 68: return emulib_Minimize (); + case 69: return emulib_ExecuteNativeCode (); + + case 80: return currprefs.maprom ? currprefs.maprom : 0xffffffff; + case 81: return cfgfile_uaelib (ARG1, ARG2, ARG3, ARG4); + } + return 0; +} + +/* + * Installs the UAE LIBRARY + */ +void emulib_install (void) +{ + uaecptr a = here (); + org (RTAREA_BASE + 0xFF60); + dw (0x4eb9); + dw ((RTAREA_BASE >> 16) | get_word(RTAREA_BASE + 36)); + dw (get_word(RTAREA_BASE + 38) + 12); + calltrap (deftrap (uaelib_demux)); + dw (RTS); + org (a); +} diff --git a/unzip.c b/unzip.c new file mode 100755 index 00000000..e311918e --- /dev/null +++ b/unzip.c @@ -0,0 +1,1283 @@ +/* unzip.c -- IO on .zip files using zlib + Version 0.15 beta, Mar 19th, 1998, + + Read unzip.h for more info +*/ + +#include +#include +#include +#include "zlib.h" +#include "unzip.h" +#include "zfile.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#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 (c1c2) + 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 (uBackReaduMaxBack) + 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_pospfile_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_filename0) && (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_extrafile,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_commentfile,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_compressedrest_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;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else + { + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern z_off_t ZEXPORT unztell (file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int ZEXPORT unzeof (file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int ZEXPORT unzGetLocalExtrafield (file,buf,len) + unzFile file; + voidp buf; + unsigned len; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uInt read_now; + uLong size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (zfile_fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (zfile_fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int ZEXPORT unzCloseCurrentFile (file) + unzFile file; +{ + int err=UNZ_OK; + + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised) + inflateEnd(&pfile_in_zip_read_info->stream); + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf) + unzFile file; + char *szComment; + uLong uSizeBuf; +{ + int err=UNZ_OK; + unz_s* s; + uLong uReadThis ; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (zfile_fseek(s->file,s->central_pos+22,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (zfile_fread(szComment,(uInt)uReadThis,1,s->file)!=1) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} diff --git a/writelog.c b/writelog.c new file mode 100755 index 00000000..91e35981 --- /dev/null +++ b/writelog.c @@ -0,0 +1,33 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Standard write_log that writes to the console + * + * Copyright 2001 Bernd Schmidt + */ +#include "sysconfig.h" +#include "sysdeps.h" + +void write_log_standard (const char *fmt, ...) +{ + va_list ap; + va_start (ap, fmt); +#ifdef HAVE_VFPRINTF + vfprintf (stderr, fmt, ap); +#else + /* Technique stolen from GCC. */ + { + int x1, x2, x3, x4, x5, x6, x7, x8; + x1 = va_arg (ap, int); + x2 = va_arg (ap, int); + x3 = va_arg (ap, int); + x4 = va_arg (ap, int); + x5 = va_arg (ap, int); + x6 = va_arg (ap, int); + x7 = va_arg (ap, int); + x8 = va_arg (ap, int); + fprintf (stderr, fmt, x1, x2, x3, x4, x5, x6, x7, x8); + } +#endif +} + diff --git a/zfile.c b/zfile.c new file mode 100755 index 00000000..3cec8f2c --- /dev/null +++ b/zfile.c @@ -0,0 +1,735 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * routines to handle compressed file automatically + * + * (c) 1996 Samuel Devulder, Tim Gunn + * 2002 Toni Wilen + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "zfile.h" +#include "unzip.h" +#include "disk.h" +#include "dms/pfile.h" + +#include + +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; +} + +