From 8d773b1c93ab1c3737d65378d91df657d87b7975 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Sun, 25 Apr 2004 18:28:03 +0300 Subject: [PATCH] imported winuaesrc0826b4.zip --- ChangeLog | 2347 ++++++ akiko.c | 1453 ++++ akiko2.c | 1393 ++++ ar.c | 1631 +++++ audio.c | 1084 +++ autoconf.c | 535 ++ blitops.c | 262 + blitter.c | 1062 +++ blkdev.c | 319 + bsdsocket.c | 1408 ++++ build68k.c | 247 + catweasel.c | 777 ++ cdrom.c | 236 + cfgfile.c | 1878 +++++ cia.c | 1409 ++++ compemu_fpp.c | 1561 ++++ compemu_optimizer.c | 174 + compemu_optimizer_x86.c | 421 ++ compemu_raw_x86.c | 3179 +++++++++ compemu_support.c | 6185 ++++++++++++++++ compiler.c | 4555 ++++++++++++ cpuopti.c | 321 + custom.c | 5525 +++++++++++++++ debug.c | 1401 ++++ disk.c | 2601 +++++++ dms/cdata.h | 80 + dms/crc_csum.c | 69 + dms/crc_csum.h | 4 + dms/getbits.c | 34 + dms/getbits.h | 10 + dms/maketbl.c | 92 + dms/maketbl.h | 5 + dms/pfile.c | 416 ++ dms/pfile.h | 43 + dms/tables.c | 87 + dms/tables.h | 3 + dms/u_deep.c | 207 + dms/u_deep.h | 7 + dms/u_heavy.c | 175 + dms/u_heavy.h | 6 + dms/u_init.c | 28 + dms/u_init.h | 3 + dms/u_medium.c | 58 + dms/u_medium.h | 5 + dms/u_quick.c | 47 + dms/u_quick.h | 5 + dms/u_rle.c | 42 + dms/u_rle.h | 3 + drawing.c | 2077 ++++++ driveclick.c | 323 + enforcer.c | 588 ++ ersatz.c | 240 + expansion.c | 1310 ++++ fdi2raw.c | 1841 +++++ filesys.asm | 767 ++ filesys.c | 4351 ++++++++++++ filesys.sh | 7 + fpp.c | 1453 ++++ fsdb.c | 334 + fsdb_unix.c | 105 + fsusage.c | 355 + genblitter.c | 271 + gencomp.c | 3118 ++++++++ gencpu.c | 3147 +++++++++ gengenblitter.c | 452 ++ genp2c.c | 688 ++ gfxlib.c | 1682 +++++ gfxutil.c | 528 ++ gtkui.c | 1912 +++++ hardfile.c | 825 +++ identify.c | 400 ++ include/akiko.h | 13 + include/ar.h | 69 + include/audio.h | 32 + include/autoconf.h | 93 + include/blitter.h | 60 + include/blkdev.h | 105 + include/bsdsocket.h | 178 + include/catweasel.h | 85 + include/cia.h | 29 + include/commpipe.h | 157 + include/compemu.h | 527 ++ include/compiler.h | 115 + include/cpu_prefetch.h | 126 + include/custom.h | 174 + include/debug.h | 26 + include/disk.h | 35 + include/drawing.h | 285 + include/driveclick.h | 40 + include/enforcer.h | 7 + include/ersatz.h | 11 + include/events.h | 53 + include/events_jit.h | 197 + include/events_normal.h | 90 + include/execlib.h | 45 + include/fdi2raw.h | 27 + include/filesys.h | 50 + include/filter.h | 56 + include/fpp-ieee-be.h | 64 + include/fpp-unknown.h | 139 + include/fsdb.h | 114 + include/fsusage.h | 37 + include/genblitter.h | 15 + include/gensound.h | 38 + include/gfxfilter.h | 60 + include/gui.h | 43 + include/identify.h | 25 + include/inputdevice.h | 129 + include/keyboard.h | 139 + include/keybuf.h | 16 + include/mackbd.h | 109 + include/memory.h | 240 + include/native2amiga.h | 56 + include/newcpu.h | 300 + include/options.h | 368 + include/osemu.h | 19 + include/picasso96.h | 587 ++ include/readcpu.h | 102 + include/savestate.h | 125 + include/scsidev.h | 17 + include/serial.h | 29 + include/sysconfig.h.win32 | 42 + include/sysdeps.h | 491 ++ include/tui.h | 39 + include/uae.h | 43 + include/uaeexe.h | 21 + include/unzip.h | 275 + include/xwin.h | 88 + include/zfile.h | 34 + inputdevice.c | 2253 ++++++ inputevents.def | 273 + keybuf.c | 169 + main.c | 701 ++ memory.c | 1765 +++++ missing.c | 44 + native2amiga.c | 114 + ncurses.c | 680 ++ newcpu.c | 2567 +++++++ nogui.c | 88 + od-generic/exectasks.h | 17 + od-generic/joystick.c | 71 + od-generic/memory.h | 11 + od-generic/sound.c | 43 + od-generic/sound.h | 27 + od-win32/ahidsound.c | 901 +++ od-win32/ahidsound.h | 9 + od-win32/asm.bat | 3 + od-win32/avioutput.c | 930 +++ od-win32/avioutput.h | 58 + od-win32/blkdev_win32_aspi.c | 827 +++ od-win32/blkdev_win32_ioctl.c | 458 ++ od-win32/blkdev_win32_spti.c | 366 + od-win32/bsdsock.c | 2574 +++++++ od-win32/build68k_msvc/build68k_msvc.rc | 61 + od-win32/build68k_msvc/build68k_msvc.vcproj | 153 + od-win32/caps/CapsAPI.h | 118 + od-win32/caps/CapsLib.h | 24 + od-win32/caps/Comlib.h | 20 + od-win32/caps/Comtype.h | 121 + od-win32/caps/caps_win32.c | 129 + od-win32/caps/caps_win32.h | 5 + od-win32/config.h | 77 + od-win32/dinput.c | 1700 +++++ od-win32/direct3d.c | 559 ++ od-win32/direct3d.h | 12 + od-win32/drivesound.c | 191 + od-win32/dxwrap.c | 2056 ++++++ od-win32/dxwrap.h | 249 + od-win32/fsdb_win32.c | 184 + .../genblitter_msvc/genblitter_msvc.vcproj | 172 + od-win32/gencomp_msvc/gencomp_msvc.vcproj | 166 + od-win32/gencpu_msvc/gencpu_msvc.vcproj | 175 + od-win32/hardfile_win32.c | 786 +++ od-win32/hq2x32 | 0 od-win32/hq2x32.asm | 1933 +++++ od-win32/hq3x16.asm | 2430 +++++++ od-win32/hq3x32.asm | 2472 +++++++ od-win32/hq4x32.asm | 4014 +++++++++++ od-win32/ioport.c | 275 + od-win32/ioport.h | 9 + od-win32/keyboard_win32.c | 402 ++ od-win32/machdep/m68k.h | 184 + od-win32/machdep/maccess.h | 234 + od-win32/machdep/rpt.h | 82 + od-win32/machdep/support.c | 294 + od-win32/makeexe.bat | 18 + od-win32/md-fpp.h | 141 + od-win32/midi.c | 833 +++ od-win32/midi.h | 61 + od-win32/midiin.c | 681 ++ od-win32/mman.c | 320 + od-win32/mman2.c | 238 + od-win32/opengl.c | 467 ++ od-win32/opengl.h | 9 + od-win32/osdep/exectasks.h | 51 + od-win32/parser.c | 532 ++ od-win32/parser.h | 31 + od-win32/picasso96_win.c | 3802 ++++++++++ od-win32/picasso96_win.h | 561 ++ od-win32/posixemu.c | 527 ++ od-win32/posixemu.h | 7 + od-win32/resources/35floppy.ico | Bin 0 -> 1406 bytes od-win32/resources/Mycomp.ico | Bin 0 -> 1078 bytes od-win32/resources/RCa00564 | Bin 0 -> 85728 bytes od-win32/resources/amigainfo.ico | Bin 0 -> 318 bytes od-win32/resources/avioutput.ico | Bin 0 -> 1406 bytes od-win32/resources/chip.ico | Bin 0 -> 318 bytes od-win32/resources/cpu.ico | Bin 0 -> 318 bytes od-win32/resources/drive.ico | Bin 0 -> 1406 bytes od-win32/resources/drive_click.wav | Bin 0 -> 17998 bytes od-win32/resources/drive_snatch.wav | Bin 0 -> 39828 bytes od-win32/resources/drive_spin.wav | Bin 0 -> 20180 bytes od-win32/resources/drive_spinnd.wav | Bin 0 -> 20180 bytes od-win32/resources/drive_startup.wav | Bin 0 -> 43492 bytes od-win32/resources/file.ico | Bin 0 -> 318 bytes od-win32/resources/folder.ico | Bin 0 -> 318 bytes od-win32/resources/h_arrow.cur | Bin 0 -> 766 bytes od-win32/resources/joystick.ico | Bin 0 -> 1406 bytes od-win32/resources/misc.ico | Bin 0 -> 1406 bytes od-win32/resources/move_dow.ico | Bin 0 -> 318 bytes od-win32/resources/move_up.ico | Bin 0 -> 318 bytes od-win32/resources/resource.h | 668 ++ od-win32/resources/resource.hm | 11 + od-win32/resources/root.ico | Bin 0 -> 318 bytes od-win32/resources/screen.ico | Bin 0 -> 1406 bytes od-win32/resources/sound.ico | Bin 0 -> 1406 bytes od-win32/resources/winuae.exe.manifest | 22 + od-win32/resources/winuae.ico | Bin 0 -> 10134 bytes od-win32/resources/winuae.rc | 1253 ++++ od-win32/resources/winuae_minimal.rc | 1136 +++ od-win32/scaler.c | 1527 ++++ od-win32/scaler2.c | 1522 ++++ od-win32/screenshot.c | 186 + od-win32/scsidef.h | 388 + od-win32/serial_win32.c | 489 ++ od-win32/sfhelper.c | 122 + od-win32/shm.c | 172 + od-win32/soundcheck.c | 562 ++ od-win32/sounddep/sound.c | 671 ++ od-win32/sounddep/sound.h | 51 + od-win32/srcrelease.bat | 87 + od-win32/support.c | 17 + od-win32/sys/ipc.h | 1 + od-win32/sys/mman.h | 47 + od-win32/sys/shm.h | 1 + od-win32/sysconfig.h | 465 ++ od-win32/target.h | 25 + od-win32/threaddep/thread.h | 64 + od-win32/unistd.h | 1 + od-win32/wcc.sh | 266 + od-win32/win32.c | 2120 ++++++ od-win32/win32.h | 95 + od-win32/win32_filesys.c | 135 + od-win32/win32_nogui.c | 499 ++ od-win32/win32_scale2x.c | 198 + od-win32/win32gfx.c | 2171 ++++++ od-win32/win32gfx.h | 39 + od-win32/win32gui.c | 6264 +++++++++++++++++ od-win32/win32gui.h | 48 + od-win32/winuae.nsi | 42 + od-win32/winuae_msvc/winuae_msvc.vcproj | 584 ++ od-win32/wrc.sh | 75 + od-win32/writelog.c | 118 + picasso96.c | 2899 ++++++++ readcpu.c | 844 +++ readdisk.c | 193 + rpc.c | 677 ++ savestate.c | 1244 ++++ scsi-none.c | 20 + scsidev.c | 819 +++ scsiemul.c | 913 +++ sdl-joystick.c | 157 + serial.c | 413 ++ svga.c | 945 +++ svgancui.c | 578 ++ table68k | 260 + tui.c | 730 ++ uaeexe.c | 123 + uaelib.c | 434 ++ unzip.c | 1283 ++++ writelog.c | 33 + zfile.c | 735 ++ 282 files changed, 154613 insertions(+) create mode 100755 ChangeLog create mode 100755 akiko.c create mode 100755 akiko2.c create mode 100755 ar.c create mode 100755 audio.c create mode 100755 autoconf.c create mode 100755 blitops.c create mode 100755 blitter.c create mode 100755 blkdev.c create mode 100755 bsdsocket.c create mode 100755 build68k.c create mode 100755 catweasel.c create mode 100755 cdrom.c create mode 100755 cfgfile.c create mode 100755 cia.c create mode 100755 compemu_fpp.c create mode 100755 compemu_optimizer.c create mode 100755 compemu_optimizer_x86.c create mode 100755 compemu_raw_x86.c create mode 100755 compemu_support.c create mode 100755 compiler.c create mode 100755 cpuopti.c create mode 100755 custom.c create mode 100755 debug.c create mode 100755 disk.c create mode 100755 dms/cdata.h create mode 100755 dms/crc_csum.c create mode 100755 dms/crc_csum.h create mode 100755 dms/getbits.c create mode 100755 dms/getbits.h create mode 100755 dms/maketbl.c create mode 100755 dms/maketbl.h create mode 100755 dms/pfile.c create mode 100755 dms/pfile.h create mode 100755 dms/tables.c create mode 100755 dms/tables.h create mode 100755 dms/u_deep.c create mode 100755 dms/u_deep.h create mode 100755 dms/u_heavy.c create mode 100755 dms/u_heavy.h create mode 100755 dms/u_init.c create mode 100755 dms/u_init.h create mode 100755 dms/u_medium.c create mode 100755 dms/u_medium.h create mode 100755 dms/u_quick.c create mode 100755 dms/u_quick.h create mode 100755 dms/u_rle.c create mode 100755 dms/u_rle.h create mode 100755 drawing.c create mode 100755 driveclick.c create mode 100755 enforcer.c create mode 100755 ersatz.c create mode 100755 expansion.c create mode 100755 fdi2raw.c create mode 100755 filesys.asm create mode 100755 filesys.c create mode 100755 filesys.sh create mode 100755 fpp.c create mode 100755 fsdb.c create mode 100755 fsdb_unix.c create mode 100755 fsusage.c create mode 100755 genblitter.c create mode 100755 gencomp.c create mode 100755 gencpu.c create mode 100755 gengenblitter.c create mode 100755 genp2c.c create mode 100755 gfxlib.c create mode 100755 gfxutil.c create mode 100755 gtkui.c create mode 100755 hardfile.c create mode 100755 identify.c create mode 100755 include/akiko.h create mode 100755 include/ar.h create mode 100755 include/audio.h create mode 100755 include/autoconf.h create mode 100755 include/blitter.h create mode 100755 include/blkdev.h create mode 100755 include/bsdsocket.h create mode 100755 include/catweasel.h create mode 100755 include/cia.h create mode 100755 include/commpipe.h create mode 100755 include/compemu.h create mode 100755 include/compiler.h create mode 100755 include/cpu_prefetch.h create mode 100755 include/custom.h create mode 100755 include/debug.h create mode 100755 include/disk.h create mode 100755 include/drawing.h create mode 100755 include/driveclick.h create mode 100755 include/enforcer.h create mode 100755 include/ersatz.h create mode 100755 include/events.h create mode 100755 include/events_jit.h create mode 100755 include/events_normal.h create mode 100755 include/execlib.h create mode 100755 include/fdi2raw.h create mode 100755 include/filesys.h create mode 100755 include/filter.h create mode 100755 include/fpp-ieee-be.h create mode 100755 include/fpp-unknown.h create mode 100755 include/fsdb.h create mode 100755 include/fsusage.h create mode 100755 include/genblitter.h create mode 100755 include/gensound.h create mode 100755 include/gfxfilter.h create mode 100755 include/gui.h create mode 100755 include/identify.h create mode 100755 include/inputdevice.h create mode 100755 include/keyboard.h create mode 100755 include/keybuf.h create mode 100755 include/mackbd.h create mode 100755 include/memory.h create mode 100755 include/native2amiga.h create mode 100755 include/newcpu.h create mode 100755 include/options.h create mode 100755 include/osemu.h create mode 100755 include/picasso96.h create mode 100755 include/readcpu.h create mode 100755 include/savestate.h create mode 100755 include/scsidev.h create mode 100755 include/serial.h create mode 100755 include/sysconfig.h.win32 create mode 100755 include/sysdeps.h create mode 100755 include/tui.h create mode 100755 include/uae.h create mode 100755 include/uaeexe.h create mode 100755 include/unzip.h create mode 100755 include/xwin.h create mode 100755 include/zfile.h create mode 100755 inputdevice.c create mode 100755 inputevents.def create mode 100755 keybuf.c create mode 100755 main.c create mode 100755 memory.c create mode 100755 missing.c create mode 100755 native2amiga.c create mode 100755 ncurses.c create mode 100755 newcpu.c create mode 100755 nogui.c create mode 100755 od-generic/exectasks.h create mode 100755 od-generic/joystick.c create mode 100755 od-generic/memory.h create mode 100755 od-generic/sound.c create mode 100755 od-generic/sound.h create mode 100755 od-win32/ahidsound.c create mode 100755 od-win32/ahidsound.h create mode 100755 od-win32/asm.bat create mode 100755 od-win32/avioutput.c create mode 100755 od-win32/avioutput.h create mode 100755 od-win32/blkdev_win32_aspi.c create mode 100755 od-win32/blkdev_win32_ioctl.c create mode 100755 od-win32/blkdev_win32_spti.c create mode 100755 od-win32/bsdsock.c create mode 100755 od-win32/build68k_msvc/build68k_msvc.rc create mode 100755 od-win32/build68k_msvc/build68k_msvc.vcproj create mode 100755 od-win32/caps/CapsAPI.h create mode 100755 od-win32/caps/CapsLib.h create mode 100755 od-win32/caps/Comlib.h create mode 100755 od-win32/caps/Comtype.h create mode 100755 od-win32/caps/caps_win32.c create mode 100755 od-win32/caps/caps_win32.h create mode 100755 od-win32/config.h create mode 100755 od-win32/dinput.c create mode 100755 od-win32/direct3d.c create mode 100755 od-win32/direct3d.h create mode 100755 od-win32/drivesound.c create mode 100755 od-win32/dxwrap.c create mode 100755 od-win32/dxwrap.h create mode 100755 od-win32/fsdb_win32.c create mode 100755 od-win32/genblitter_msvc/genblitter_msvc.vcproj create mode 100755 od-win32/gencomp_msvc/gencomp_msvc.vcproj create mode 100755 od-win32/gencpu_msvc/gencpu_msvc.vcproj create mode 100755 od-win32/hardfile_win32.c create mode 100755 od-win32/hq2x32 create mode 100755 od-win32/hq2x32.asm create mode 100755 od-win32/hq3x16.asm create mode 100755 od-win32/hq3x32.asm create mode 100755 od-win32/hq4x32.asm create mode 100755 od-win32/ioport.c create mode 100755 od-win32/ioport.h create mode 100755 od-win32/keyboard_win32.c create mode 100755 od-win32/machdep/m68k.h create mode 100755 od-win32/machdep/maccess.h create mode 100755 od-win32/machdep/rpt.h create mode 100755 od-win32/machdep/support.c create mode 100755 od-win32/makeexe.bat create mode 100755 od-win32/md-fpp.h create mode 100755 od-win32/midi.c create mode 100755 od-win32/midi.h create mode 100755 od-win32/midiin.c create mode 100755 od-win32/mman.c create mode 100755 od-win32/mman2.c create mode 100755 od-win32/opengl.c create mode 100755 od-win32/opengl.h create mode 100755 od-win32/osdep/exectasks.h create mode 100755 od-win32/parser.c create mode 100755 od-win32/parser.h create mode 100755 od-win32/picasso96_win.c create mode 100755 od-win32/picasso96_win.h create mode 100755 od-win32/posixemu.c create mode 100755 od-win32/posixemu.h create mode 100755 od-win32/resources/35floppy.ico create mode 100755 od-win32/resources/Mycomp.ico create mode 100755 od-win32/resources/RCa00564 create mode 100755 od-win32/resources/amigainfo.ico create mode 100755 od-win32/resources/avioutput.ico create mode 100755 od-win32/resources/chip.ico create mode 100755 od-win32/resources/cpu.ico create mode 100755 od-win32/resources/drive.ico create mode 100755 od-win32/resources/drive_click.wav create mode 100755 od-win32/resources/drive_snatch.wav create mode 100755 od-win32/resources/drive_spin.wav create mode 100755 od-win32/resources/drive_spinnd.wav create mode 100755 od-win32/resources/drive_startup.wav create mode 100755 od-win32/resources/file.ico create mode 100755 od-win32/resources/folder.ico create mode 100755 od-win32/resources/h_arrow.cur create mode 100755 od-win32/resources/joystick.ico create mode 100755 od-win32/resources/misc.ico create mode 100755 od-win32/resources/move_dow.ico create mode 100755 od-win32/resources/move_up.ico create mode 100755 od-win32/resources/resource.h create mode 100755 od-win32/resources/resource.hm create mode 100755 od-win32/resources/root.ico create mode 100755 od-win32/resources/screen.ico create mode 100755 od-win32/resources/sound.ico create mode 100755 od-win32/resources/winuae.exe.manifest create mode 100755 od-win32/resources/winuae.ico create mode 100755 od-win32/resources/winuae.rc create mode 100755 od-win32/resources/winuae_minimal.rc create mode 100755 od-win32/scaler.c create mode 100755 od-win32/scaler2.c create mode 100755 od-win32/screenshot.c create mode 100755 od-win32/scsidef.h create mode 100755 od-win32/serial_win32.c create mode 100755 od-win32/sfhelper.c create mode 100755 od-win32/shm.c create mode 100755 od-win32/soundcheck.c create mode 100755 od-win32/sounddep/sound.c create mode 100755 od-win32/sounddep/sound.h create mode 100755 od-win32/srcrelease.bat create mode 100755 od-win32/support.c create mode 100755 od-win32/sys/ipc.h create mode 100755 od-win32/sys/mman.h create mode 100755 od-win32/sys/shm.h create mode 100755 od-win32/sysconfig.h create mode 100755 od-win32/target.h create mode 100755 od-win32/threaddep/thread.h create mode 100755 od-win32/unistd.h create mode 100755 od-win32/wcc.sh create mode 100755 od-win32/win32.c create mode 100755 od-win32/win32.h create mode 100755 od-win32/win32_filesys.c create mode 100755 od-win32/win32_nogui.c create mode 100755 od-win32/win32_scale2x.c create mode 100755 od-win32/win32gfx.c create mode 100755 od-win32/win32gfx.h create mode 100755 od-win32/win32gui.c create mode 100755 od-win32/win32gui.h create mode 100755 od-win32/winuae.nsi create mode 100755 od-win32/winuae_msvc/winuae_msvc.vcproj create mode 100755 od-win32/wrc.sh create mode 100755 od-win32/writelog.c create mode 100755 picasso96.c create mode 100755 readcpu.c create mode 100755 readdisk.c create mode 100755 rpc.c create mode 100755 savestate.c create mode 100755 scsi-none.c create mode 100755 scsidev.c create mode 100755 scsiemul.c create mode 100755 sdl-joystick.c create mode 100755 serial.c create mode 100755 svga.c create mode 100755 svgancui.c create mode 100755 table68k create mode 100755 tui.c create mode 100755 uaeexe.c create mode 100755 uaelib.c create mode 100755 unzip.c create mode 100755 writelog.c create mode 100755 zfile.c 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 0000000000000000000000000000000000000000..249005f3e24feeefbf9745aafc34096eb6953464 GIT binary patch literal 1406 zcmeHHA$Ei?5dC>9f$4@VHPtK2B{&ZjkEpIga|t|V1-1vkqq#!*lVM-6wSD}&N&cTn zGRcSm3`bcaqDg^wvJYBt-Dw6n=SXyYa--6FABp#0@ctXywqadYEX#s`GZb1n?BK_PL%g-qG3>0DCgHL zbn1p=EjwF^8LcN)lWNVfj4x;>9hYEb&QL27>MJ$ujo`PPXZm3X`2AxT_yWLvz>@6^ ztxMQH5$fYK+$Z*fR4&#D&dkWfS%K;V+t7@cw7%Z%mzKTE&%D3f7#p!`8q!UU?R?5H zW%`5d8b2S#to~KfIhOVrZoH-YWGb2KpZU`J_&OC8nnFF|H{CB-MZJg}`|_zr`j%%s c@(Ue-l3rZ$6Z!AtCC~a={|Wy@Jv(fF0W$w0eEou+h{=0F1Ia9BT8+%F)uW4 zIo~fn9z{fEWMwAFl1NOWKvq>&W<;D5XO9ynzFPde_;K;e;>BWZ@y%j=@qF=@#ozRL zw|KvJyZF1VKU;iQ?51nKraM0_p6Dv~?CPFp>C;<1cVgk+&o0iSYwvZ}uG;vR?&34g zlx>_$zpO9*`{KVXzN*H-l~a1HEpDsNXK5_7^-^P5TRhaYUA6l}&#Wyr7XP8w+TxY^ z1CIB){z320b*(#wH9bdbKMKANi<7Bm`tbd=uWO6_^jFf)>4{L>)A%n7rn`dTmSAW> z!n_>K7kCb;;k`ZUFGW3X7jN|Ihcx4Bn#Ze)@AQ95P;UrsX7#FmKcl}crH<3)6Vb_U zd(V}0*{9;?qOVt?{CwBZ#B1R6D{o_V16>xt^)id(s^ zJGL~Q8;h^i^N#Mj^68oG9gp>ENIUe@6JhL){;x@TqlsQ6^v3!Y@7W^!IuKnYO8KNcF3_b}h+y+Jvh7 z%UQkC_FeVr>yOeC8%e|6(y!&!hlw_}5>3!L?Zo})EMzLWgi#=4%aQm#u09rw+!b>8 zhVH$kr+F%m@nV8^;hd0&7_n+_*I6S8w_lrZf*u~*F$@tHML*N<0V2q-~ zVDOh`FK92nuWKG&i=*BNk9>lgu+_1HvFP9F^;X|LH0KiSuqE6>rOYMV^HKMH&@;cJ zC(MB*H8J|Dg5l;T4$QIxS$9R_fTFe&MlUTc=>6i}e?vBvzply}0~T8@cpt&hZEEqa zF}G)WbaUYVbkl7+xbMPeq8#^MQx5zV+!y00X=hwk;tS%xK`SrPybsIB(@DOBlsqr# zvtLPaO;YHxsN_b26TVfua3VS|_&ub_RY}$5YX+nl5HmtFzu^YE<2`SvU$`4R`dr!#FMBzc^hW?4c?{>0B(KLX73&*< zoALH>es*sz=iq!l8Y)ImbBT4XXFo<#atRjqW}@ZNPQ9>a1%y2Zh2{yn!?w#+>6|;FFD#qPIcH>bf1PL+dBGf? zPnsrcEi5JU+ca*%BE^y;LRVXJSUa?}p|-lCz$1fa(R63heL>SV%avZC?2V*@@jj6R+j_q%+n%@(G#p-o zM}W2_28KN5H^zupiKU+P`a^xs7G(KLt?{Q}`B9Qp#BgdH_9 z!s|p*(aTh+gy*ug_(AuBF{tJ2-aJ{((z>l>{BC9gOK2J#L?NN+*F9>%LfR4*fh5CX z9Tc#j-{!&ceE|zT_#9})Z2@S%^pZ;3-(IKVY|uuA$)hl4@j;+J{+qh&8$yM*L{Ht< zx@Zd9lt>*Mx0ZA$maM-y?urYI~=^vh0HekT*z)|UhuJ5hbZA824RV{Ul>~B z2QJ4QYKeo~J*z)c9rlxTyXWWDCra(op1=Y!BWd4I4>+VEb!pu zDc%|}BO+?=)k29kdctx<{#;Ju27hmow)`Lp+LfHf&U+#{`f2er*?mYy+5kKE_vSt5 z18#K$%CsH7+c#TA@4?OABne|{Fe1Ki-SVhN2~$84&w#aasa3EC7Ok;pJ@h4!$~*Ed z(VFEb(UJG0A3{ElOSD_Uv{!xJh*rUQIX1N69kq5_?b0f`n^A?HFczlEvO7tZ5jFj} z)6Z?q+?_OfwEr#j(D$=z-Ue@2n0Ga&WrPNeyqv=`R!ZD;c?L+amMpK&CJH7#Mcd;v zyeUXOiUP5eo;P5{-f*-TExk%;hv2eA%kh+Ha3P_IO-59=rWR%q2~E^JXlLh(KnIm( zt0?Ae++*6*d=XEvcEw&jp;`PfY2IzU|EAwq|GoB!lIy4uT#WAL$t$8x^l$jp=l8hU zQ3CTeSck9q^C~NG(S9q_W~Z%5@pkXa(kka_TM$gssPtTOUR$d!*F2`Sta%JEZD*+4 zW10r}jWi!WF8-c*wTLs1nG3bGEm zBPSO6IYw?T;%t(6G4d=a+uj$}DX~XKQymv8sSHj)PorhC?ts>U zfB5y=Ge)$}xMeGEYbGxwTlsdPp=nlfSinOT zGTa*Xj9bYOae`Lx4^3lXCyz&Nt+&WWc$KXBck(}wk*tg&Dc{Ss`g6x4xh~Cyv?tO^ zq$Hvw)_7$d*l! zeTzTqqWM<;ZAoqH{r72Iu^ZK}hv&6l+rSZz@%&v9JoG+3e;aAO-tEnhTa0K3m^ThQ z3*$2|7AYC#1tjE_A|jShNYpRE4YvQzCr-#d9hjWwF$Oe2U*OMvB0RQg>KdPQ=Hab! zE^9hEmv|scfZ)DW&ijtM5aPODcHTn@9(?8lo|yTNEN=PB&-^vX}f|k8ZBty!Bz=o|~T+__;6pjJ2Lxp4MKq?dphA!cEB5+WRvt zjoDA+{*YgJy7ELl7G`G54~6E2BC__Pay-GdE#qp(Q!D{2!3+^s=D@-IrA=-)h+Q89 zj6#G_;~HtO%8_5%^IrBda=gesuJOZHIpXm6>zLMfWaW19kI5Ay zzyFQoFgv_{+*{MB;UGt4Thfn6Cp!pODeJ?8?3fZsuVr_+M%9&{%Vei_AUL{_yx#e(bJZ0Xeg zKWyCu7cqZ*PC6J(EW^n;MF!0?M81%wA)m*69z)!R%-6lD$4)%jq*dafXm)49`O30r z$a0%$8fOp3$eb}0tI=N~K8EcIR?eq6aIOv74#>u{R3g@BsnePT#{iwDRn7*xLp&R3 zHD}OyHt2bLM#x(rW6*RpMb6Of)a*P{PxhA?pKbniK7! zXq+L(Y9Yk#(6CT z`C=Q|(m&+fbg2+H?@I>S_9`w?&3Q2MWWzK(-w?;M0!KCsndxK)mV8IXG;46|ra-T= z%XUnc5A$AIYXfUQiRO0vjH}aNAiI{Gme{F(6%5$ z(V@L;mL0xtmE(7Gd+r>N6=)h_Pj#Isi*EI99CE5xF?L4}$i~_q?pZ~BwkIQpv%`rQ zddK@JVern`3kj0xJiy*yoSI#?!Wv&oKto z>SBR;{HCg`{iaE!%f${=vJT00!2hnZ{PX;*E{LpbtJ19Asp8fyCF|HdgcNWOb8z)d4_A(H z<9UN6|6diZkSu|#==X4O|?6V637tsdUU!P%IPu-}n~)LzZVk$0;a zd6u8$*vF&U+oF~J?(aIfm;G#bB{b(W4`V7lB6(JY8%y=bjh;%6H^fQoCwHYdVmIv0 zLWATwOgHwTPT_N`4u)7|jk%br0ZQG6er!j}OTUTr8LFmbAHWplyxQzxu0Fn6V!A&< zaQ!7BtFCH69LJns%{(`*+J`6OJ1lzoKtF|LkK~&lUmfzD&vks~h@x6gP`9qkn!_KA zj5&C9Ek#cJiSe2qksGm}Gwrkl{%c*i&WxZWsqItzSFU~G6GUwuh(SY1OFk+)3bG*(wQ~LGw*o*#1c)X^uyH6}}`j4LH_ZzDiFV#OQh{L_!P`|l)!v6ZDmI6C( z{-O6$jzSsioqMQv`xlmC`|IW3gn8-!qgA}Gv|E89Vkx$=J!|{xtAv7@leFlyP1_`4 znE;R1PuUGhF6uN2Dcg@KJ-H9;D_UOO%ea*rbhxdtAz`T%#vHNJ3`;D0Sg^?|OF1ek z7NDD{3&i|En|+%JXs4_*x7WE$4PN;Vn0asQqwbG~zK8S;>mU3cv07K>Wyk07)iei> z)$XsZ>a`U0_}`)sa-g1dtWxh>{x4|{=3+yV+nkR7LHyvNbdB@4nUC>|0HP}J_X}}4 zHS7EJJJ9<`^{e8yvW5q{)!nD%Ci$q-`ebFry^<4H=6sYKk!c8x<}sl6&|2h3!u{~9 z$8mAbn!=t9>u27MxZEGn=WBWab?oaPE@%E>$8y#c#FUoBQ?l0dUHv_nbM)ji{O$;= zu0!q&%a>XSVvflobOuI^=W>5Nuw6#g!3T z8k)N)@tLu?n+uKk?wt61&dk-&FmKHI>BS%QiHxLYn!7k}qvi%`>Y%xxls=uVcILiK zoX6hiIj}kt6zgS8cKAOlyMo_t>go?oXr|L3aGU0`PFZHpBRzn^ac5`5PUkykQ{o%< zA>y~gg{bR`#MoT}WbW9Jnx?h>*!k`AjNL2k^T!^$w_0Pr_?gCT%YW|Jv0Z-AU(L;Z z+vPCy&#(-e#vN!QG=nQ6#5&MaNnP4(W6-ws&pf^#hPKN&0hhhNsG&0zE~;cx8>_2* z`g8bs^-w@{KFyh7n=Z?iSw+K^ZJSCDOZ&{DQhEhmXlbqmRqNrBT8Cl(GBk^(#A2!~ zjf|TOs-NFiZpW+8y*}G1;#Fi80tsvA zMBk1})T)fGLoKU`S&j2RtXb6S9Da^-3gV2c`{J;5VfpB+b08yGzo5E|cRjH(#tKS~ z+{D_+(3(j6zQ6Sl=B@3`BO&>Vvp~?ne8)D(6)#&@rp<`XV?D8BFlSNvQ|$JM`|c#Y zz{)|aNjjR4xtYF~WjnUw$lcZ%*?4}@9m(xCvILi9H$_I1M_I=1m&N0z_0PUApPu0J zHho&cveAH>SVsy8%eAqw1b(K@5-V)3UrsHu90!d#3+pr_@ImIR-4_@fUz6kXG1flV z!_4`O-BYeY(pp zbJHG6U^iB1=Zz$uo;H$LX)i~@xqYk?qYKcg%uUEc=dor^qnB~Z)u(I`bL2GLUlfz? z$13VNx5m1Ab)7T%oCcG3c$N^^=P2O`8PS4g$a0F+fUuk*6M_7JYtXt`&hd>?rNnI$PXHkpA*A2UtG}o*ZlKHhG1;t^|bO)3}ZX?!K_Y?*|n`n zLql9)ztChVZPVrBv_8xZ9&}lMrlvyxyvv~QzHskMCvL<2<85Br@(h*0(@6i4xg>{Rlv6~0ls!U^uwG# z@7SCR-;m5`>w#}R$&Ak}7vl`v&mkEzl&h1B0nh4WBT$e#vs&30aC`~r2!yMajsf47 zk&hX|)yc;U;g^t*8N$^`$PD3-jGS_Y2NnjIl0M}rVjuYF_R3t3VcPkOwli8MFAiBD zTpy2N;eoL}!C5TJB1aL&V)Ta_#Ug)~ih0hpTQ-J>z1Y{BGm7y@(Em^k=UwHob9VNL z#s8Fk&Ue!hrQ>^WX0kKxZRsM3sGoG3@54S}pc&2NTznpwp;~{=^^e5;i zR^*wJu?QY^=Ml@V((-A275+v?NkH&bbghFexNPmEj3oN|tx++UCP zZW1DwEjzfj@`rcp`M!sHQFpKLFUu$j++;3~Rh)5N4BR{N(xw3Cmsys0Hey9^6;wbR zChz?Sso13g=zrBzFokxvleCR2-2S*NH)4j&J*yn|P;}~|lzg3{P~N%V+MBL&9{kIWcI(SJx_sCi zJH%_u_Li{7K9=&7?jb%aF$x?9<%dj-Lnk|zwA-amd(7RdJP}mql|LgdX@r;S_M zLlU~Ak&Me)BZ6&X-K#>5h3szzHWD>)ek=Nx{if`q8Izz#gBCptj@%gso{On5*b>*) zsK*h0EbHLLgHXb@cpYtr4|NZcO+_innTWCbH%pyzHo13d6m!{ZgkOWM#J-+78`h8HpR!;3q^R$O zXq^hab?zXN18?o zIb1@CB}{~foX=H22ep~r_9qJ-2s-l6*b#D1v%v|R=r_(_qDBOjDX5lK!W8%V&cmOv zfN8(-U^B_Hf7htjGgoXR2fo@MIB1VWJvp$o}OT zx}F`*WE{@hIv7kyv6AaARP!_*@s0f)?0Ti139I$wdoW{I?qq)Scf3#mE%wobR7IkN zcJ(TBa0WYKfpUB_)TKji(0|S_FKGm6>U{_~9_IBSNBfP7&>BFDL3~K_gQuf39ln+iT+ebLp6k{%<+g zvRt?8uAJLn)jAQW|uiCIE!z~ zc9sJ9xcuq!bh+|P=7)FApb>+YSR>^#J&a?MS>%KxXFk+l#C?Gu-mh}AE>2kl8ta6F{+q*YzzAJyoTnO z2VK;T#TyRD+|pq{7Fy|j+K<|`216s=OZ)!o+So|IgTmHr9|-eaKIqX^KZfUSJVptG z>~cM&$ce4ZI!<&?*IV}3!F)YS2G4tB;CkN2IhCBI(0zQ)^N!^TE~3S$Ho%53;8^g_ zpISyHQzMh?7kY4Ywf*;ib!D3>#_o)v>?69mZ}_Ib;kgbQYTS>xqdthkMnz%Hv~x}2 zvd^&Ei1`5-5-nCI{SE#>rcIUAj2tcagP!ng(56>9A`fAhM#s-0c&gY6)@bchcDWK5wLL22JuGD~ zNBjS>lc~vj6z$}3`BYo$b^VbO;*O|80HwLM;#{sPtNxc3v8lDx6(AGgG&*-ebM)qXn$!Kq({C-NK|^NHFMec8&KMNYuKDteS32A!i^@i9c*f z(@|rjW!WG>K6mUPOCZy$&(^V49ou6y)rxJ&r|={#7b3zsMaGVE&$Ng`$S04WluzS5 zv^=Gw$M0u5wv_Ycw?)OQau4x45`~ke%>C#ke>!Ss4jq(J#{H2EMWv}U7SVIoi#T@$ zpU->~5je-IT%+`&_HA9(n&mHP9jEk%{p(}>%85m+)*K8nu(}Ke*QTy@_jDMj1;z>` zv)zJ%e4abPIoz{aI4+29!x9Nwa2$?n!oRb6jQ2has~R<9L~@&k>Po%iO zMFn2Rek{*&G|m!@xGyoRsS@p)B5|y7lBeYJf4f;OM62=0p$m345ewfh-iGA?a8N(k z6nQ@J({xVS(&`ZFL(hdjM;6y4XNgjfS=xn&xDD$rTUsG>1?R)fS`1iBuQ~Px^yA#M zA)WP1V<)=uLUr6(N$~t&<*+vEeWb(iahef(hscWfPP4~qN^8a#&y;A9@1ebGYN?D% zWQs1YI%gM}fnx9?J-6nG;1b(!_HS}KL!1G1A}iq!=K_+IMLs9>AmQy&zdPPaE-&1G zFE;Djnxb?MuG5W z(b#er!CN23KE*79vn|mB8n4(K6q?|ME|mWeotzZ3+k%yRM6%MLl=@7B{@fBT2g*L| zHK)vn8)@b|1kWS?{oOn;E*ZjJSUz)DA_p0Lrp`Ve2LztGSab9Ehhi9binJLq3~Hld z2V(^z(Yk)k@?9GjBui-RaAL%!&~`qcX-lkHvA`Rk#}UkvMh>>2jAs&OR~YJMe_X~boI&_IAqPn)|2TD zN+&vnZUI}2Yct^oNXKIu{iw+@s12FVXz+iZ(_l++JP!Uc`PHTDY4-+=Jx=_YtMGzT z=JjIAiSik8*2!4|4r%_7;7^k!M19kt6S|QJxlhMh<17k#kG0%!zM_&byG82C!Yz1_ zWy~s-jmM;J+m~Rjty^Nop$GOgn9lqgXJG@|GR`qI6GH-4ul!D}=}EN`tmkovSxa#w zj`PC7@sug%IN-_DG#^jI%x|T+ zMk0{W(xMsPHO@K9?8|u)gSke_InUcW&!+oB{n$whs_F5R!-UIc^!DKz*D0=G=iK{l z_F-3tSXV}*(s@+lJ=k9*zmd!%-rq=nb*tv}H5PMK>MZ(YzQ_6WqCDWIlHkM&{v_#7 z4u_*UWXe!s>d&Lpc~P2($ViJmGu6dv`m(vS)~c)0S?bshv39miFbzJ|xk?D{3ntEX zE@2#pkXAkqj9$TauG~~xhtoBDVhdJIE32ud7%W!D`@m{Qc=Bn$=|OB|_Kt3f5^f}2 z;geK-LUhDm>DTseH%s;){gT5PRlA(22Bl2xdEAO+|Lk+|$m?EaZpruH6)yB@k^g%R z$9uRTn*33#E3ZemJ=W)=58#|Cm&dJecr&U6b!`z_4@5y-V=Y(LgNl4=Xyl*RCxV(- zU*tWk)OsB&*A>9_c_uo3p%*8|d7nr*VxsZ*O!z$BLypAZ>^f+Qs0i<|qZr!-{ly>s z=iPg)c1-uJOf@*gzD`6U$fKAafgqksFLNRghgBD?j!7_z)kPkr)U(VOWM>O&1K63& z7}Okl0UhI;UdJ--WOoI$%KmA3x~|Wq|1(@)uZ~=Sr|~@r)TF=@sO^Cap<@`{n~)<2 zz-b8u)YGys(B<>6TURE4C*cP77;8+&1Iw)0Mh%7`OqbAROh*g>sLLuH%e*CKe%x}p zC3(#nSbe5Qo_WXq@2g*A+tE354}Sw)Nz|!an*r*Bou$`~+?&pcD?}yAi-pFTN73cJ zMcTz5#Tq0wWc&9h(DOL$xXSC>w7!7OEA?Eaps<+9jYjje>}y-hap!QXs698>`_`Uh zpvOKUyoqVjuYZaVve0L~{Zo?B+1`Iz{83(n`PS=g_KrBs3XSdfDY9vdE63$Ad#9;j zKpcg=^?%nWewPREM(?rzcsFJDi>;6JQmG)qLJnGfb=92@idrkaTB6Hud- z6%FLvbo?KrM^0GEJz7GH!#LkQ;fZZofOrzvHuOqHqA4A@6jfP{f>a;(V4Mp>4I-$Q z^Dc*Mm4Lj2*cMqpjJ*PF@rU%u{!8Z4XocU~>!{>T*zXAM1&nhqX9Cxmq03iL|9|jb z#^ZB$ljitk4|~oRCBKS#Ik9Uuw2A51c2C~JH+5y@YSI-?)5-#8XONHTeoI@SoK0pm zR!&=%0#q`^S{Skv(22I7SxtvWr)D4wuQ!+DzaeeIxaX}hhm3Y*_q?7Aw6Uh_jH1#9 ztUbMu=aJEPeow179yYGYZiv^(m9fPWmPbV5n6Jn(!e+IEJO2rXhhgSbL!YAfEs^k&N#^3M4z+r z-+FP@=GXEnz2exF!VmRZSYloU4$lazEVHwxt}~Z;EyHpd8NPo=kT)eH&LcgJkRVw~ zNG?i;Fhlm-kJp^kkU-n>VSz48h5cLxTQ76y>u|K&j&$RfmX6Ml!YeKH+qg_(<%Nt` zv^Wu)a;HFKYkK`ITE;6`CI`&9)8f^o^Z|?a)OMV1P0em7-S8X_FOYgLc_$g!LRd!B z_F>=7hdu1JWG_({_D%TYAT;@<1i5|h@s+I-lXYABoe!^hll^%q=^&3Ja)MCp?7Oh2cN>?=kW@5H&tIq|9&@iW%H<5%9x z+BA5`&Yt>8`taqR^k(lXIm-7x<*`0idv`>E>=7s0N;|H{Pj9TT5jkh=xz+nxy1%X` z7%@63u{$@OI0gEf+<&rXS-YbSGJVz0V)1x?FuT)u>UtUhPqIel47B!~lDkny38|7E zm1M_yj#b2Nuf`#3@IFni`#Y@DLeV$GHh%OnCe+%nEV z`;@d5XXT8KZ8^t|NutyW{D9AL}_zhyF@%9~LiM)OrT9ew-+KOY=`=OpLov%Vf01ubi3g``1*Nlvwp^ z%^W!-oOIwC49Lng<;St|#JW++Lje!l#f-^6=eb(RSk6=U6?YXGs$5d&d-Fs9)hZ1(=L)CreZ}WTK z9O*fGH@TPAr};gXbu3Sdi`$SJ;%(6%XBxG7_OeIi>#%@f z9eVAjU!R=zSoA&&b@Wb^fk%TH_8`6cOu;tv{XL&;_~-Y}xiaiJ&u1akBPe|X_IqY~ z>S$VuVeQ5Hny7|s8Z4{Q0_)m}z-9}WT`i9jt=-cnDy7`fcX*yyC+)G?5x>NB+KbBD z^&PGU%UX!nnd2k??1fEHGjaPVPekjkM8IAg;(XTkR4_R!OX*g!32T3rGf}Q8BJyA_ z+SzZ15mEsqo@N(5>ux1XxmVwPy0|-hkn(;`X7ZiHM|hpvdm{Re9ZPlZ@hj`mSA-ew zYO4F}#%s|>M0xQ6cap}&s(z*U@QDLk`iAXht99AajFSDoyg$|d))Nm??D&CjN`KME zrtpRI!cxnX;>Zo*E}t42XC;BBb}Kcl#?z-I6EEry`Z=kQc~o@^!01YA&Ww-B-_gd{ z2ySWoK1DBbZ-K50Z+GCH|M~&fw z#y8wbYc%!Kb7m?>ukxpSb^-M9P-A)j3BG0YTF*Lru*o;r6?WL&ZW(91z|*E?Xpl8M z<_oOkQRGjxoF}uAJCCM}kGNI&&MtH!Peh>Je;PY5)R0lBm#g@$)QGq(34{N{j@7nK z_0R3X^^Pc5VZ)mB)72C$Ok2tyF0$AJ`7%X_$2k{rg~sdBs(qZ zr>A=D;2b}*`!qXPa!v9UX1T`GWewZ9m8m}Ly88M>Jkh6|sj&}cx!iLB^$qDAYRT~X zd>P>!-B_;}!Uq`lj{Dam!Rw&5E;SaHy=aA%$5tD7 zgye~jw}CJE+dvyvlP^fF+Ol?x*MA7NSpBSH)bQjQF3Vcssaz{1w=%??RQ25-cTxp@ z3?|PKG1oRs@btzhVDcTE|-oixJsPfNHVa5CV%eZ zv^*WKFNs@yEo(pb1YMU_*qDqjA+V2Lwv|7(Ac*@*>*&NMZPJ1vp2+RCKdnoyUDlks zzE)UX!_mf3sNoI5ICl2I8w4ZW|cM>IE)mQs?HC%_Fo%k}!~Xt&YUEv(b;SGSb-%+bT| zB@dxdpRVcAP|22>8kT?jk7}bO_JZm;b)8x>UT-Q%F z2~lgVbB;KxJ+wm)7&KjS! z{!h9atAp#@<5^?2Pf0e>KBK^cf1SA0v%%^c>k8r7)7J-${H0!*KFQo+9OfGK3K7KTmBya=;ycLzX61z<_|yaC7ia@G zPNnF1w8{7{iywS)3ilbO@YyNJ5_s2nN?-xQP}nYs|pGtlvwx zY{B66+4seBP@iQ$3BwPm9c1*DUZ>K3crR+>l=d0ChkXxTEJQCenw)BLs=%#j z8cK(Y!Rc80RH?Kk2PQDgJ96lwqzFEQ+aWKXRhHB0kI%f2?N>!*POnI@og#!p0+ zcmlM-XQVN(x+)~I@RP2&53fFW6`1kc?mUrb3_b>{@JL)|73Zn0!a>w%>0=K#kQYeX ztBL!V;XbExwkvHjN~jPi3tpDVfbM8F_4KoZ_u#EZYU8P9VMpTxv*y<8`UI^Z*;&0Y zJ$_K{RJJc^iMjb%_{z4a^YeHb-H-l3)4fl!m3H$?TIMqYJ}tzn>#TgyJ5Ra|V}48R zFe|~C;2J1mJ%>Kp`hy;(SpsL&Lixh3Bp&xH^@^NC^U^DJdE_--)~I~?5%LNM*W^_q zf&4jejXt94vGq1lX6F1)nrmAVE&Yi!K-&H}QECkZ7O~g3uz|M4?VM8L-550#(SuLd zvHoS0_G{M?OhicV%gtlh7eH9r$9TXc5BU!G1~{AvN=1&y#k7?|EAS8!n%41=`ZMBF z;n|bJCrDX4Lq1q0!&1CIjd&L0SUR@3pwXaR zc$;~0FWt7h4tiR5o4dNdf2TgWwtVelkZnla+zfMk>iTTVBla)jeJ!bmq=^&JkeqzC zT?&PHt$-(n{ch)Bw0nSlN^^z$dQ8+#V|}!Kvj1&eQXMNGC?&7ggApo}v&u;|GPF+X`OSope$G`n+dRu^ z2$jysHee4_Yiz7i`dmJ1dbk?Rj(3Nx1NQj^-?8?lUGanX5cW2@8y-UPlaB*@E!!ZE zh_ele3^A8b)^~a`zt$D^gqury2Cghe=iMPh(BWffjy9}GbCkc1X2H>p90FI^OaY6z zIcyM*9~&j)jz?e}OFRsU_?TeD4lC`ch)%vtbey#^5`sI?bnInmTTj6{nCZQ1Z(!YZrJw8JGcKS765>eAtvwhbLrB;^=-0JR7`L^HW~L4=u?r$Eeu}ni zKiK}n&c`xAGqvF%Qb#?KP0=7x$;iBL1P@(xJ@w8yO&A=;w$O6S7&Fg`7o7V+*TB^q-G$GU zeb`g_jp#14cuJ7E|A6?E^0)AfUaOB&iQ0cv`!OTz807vKjcpSm0yPvZ8o!;a4EC8b zALjoqJuov_3gGoaf%R!wmN&z65VkJbAF9DmLPFtLAfd2COL>d`tL&0v+q_ z^DA`abEx~YR9?aU;{57v9M%#JYoD<=9@3?;zAuNw%N~Jg1HF)|1jYC*vyelUmtY$W zZXYh6S#JsT-4OcA)Lh_hoF~a_ODspPXW1CFKg7V>lt};3w!ctaI}k zRBr8KiYBg&?(6fyTepA|Or2aS~9(9YHf&-Izr44%e% zvQ}p{;d=J4$DV-jU8vpZodK*XtjU94)96nNbN}3vs`nF=z=dUt#6=1QjfA#g1oVOh zXdBx4)z2V{-m8CNT-M?5^o?`CgYLjUxv~}(8nkC>wEt4#7MWSM=F=#cJL4gu(mwSn zWF+>4y%a2Zu!UvEXKYeN61)&TTum(*|2*gTT&@COACFnUA7G5NZ5x)>i$rHNCG8fp z6t<1W!l<@I%eH8?)v{;88Y#~=v+g;8da(>!yjSx{m*X<8ppCPxyOtm#&W$WU3eX3B zN9;2xJ?)mfZN+M)$yeK7ucf7Gjz^kPoeR5*J#gqK;?nmt!t&+#3x0v^Kj=AY`?}56 z$Xj}E+Q_p_-K85=*5OGk?k-%dF+?^?4VNVd>kq@8Ktzzcy@WM^WfVIaqL=JrhrVF< zfj#u_&yYT~FO6r%iq;9)J@$aDuWAf;+a8{^4YfvmKWJ=t)^Z!e^bF>@vj4W)x7@;0 z^Eij>-)}$FuR~tgx{KMs*JN~fM|cRx99F&_h-Y{7_h)?zNsRQgyo6(T@@T#oUAb$A zTBWX0=sl(20N)DPJzm4_Xu`;-Viw|^>=SE*GJhw|90!2%O>1_j|q5Cm=y0AdP-nMYwTI3&3373OdxC_D}x0tr|Y35Enw z&TW@KX!G6g_VgzO98RSaWb_@NE+&$+i35)nSet5#?AaT@WdP{3hl&Q=Gtkr;!CS+> zGuV}Rc k-NrP*VQ+(PBIn_ZLtPS5U7vNH2jt)wkO%Hk%FB>or!Z6_(2-7K;Vu^Eqa-877kn z#^W*aJV%yg7>!044u?q76obJ4Ns=H4g5vwf!*K$~3H;9l#NTRlSgr436HQhTG+1$i zeZ+t6#U6`n=tMG#YOJ^>L6@9K5-<+9=ItOzyF^?lzx-Fp#+LbTid!Tx&k>if_EMf;F> YAs&e-L;2JqdOx5YI3=F$=zRrz0`l!c?*IS* literal 0 HcmV?d00001 diff --git a/od-win32/resources/chip.ico b/od-win32/resources/chip.ico new file mode 100755 index 0000000000000000000000000000000000000000..52d09a93c6e266b8e3afedd83ace43d5d95e6f8a GIT binary patch literal 318 zcmZQzU<5(|0RbS%!l1#(z#zuJz@P!d0zj+)#2|4P5awoJ0AY|E2>k#5pP^u127{fi zEkj*n9mCzbcNuhabRd#MkZDkmC}^alq$DVo!0Z|t8f3thC literal 0 HcmV?d00001 diff --git a/od-win32/resources/cpu.ico b/od-win32/resources/cpu.ico new file mode 100755 index 0000000000000000000000000000000000000000..2e790a54fc31e0eda10e7a460f2dea1ed69a79a2 GIT binary patch literal 318 zcmZQzU<5(|0RbS%!l1#(z#zuJz@P!d0zj+)#2|4P5awoJ0AY|E4E+E9pP^u127{fi zEkj*n9mCzbcNuhabYRjX(M*aUpu_;98AVipK#+k+$=TT0NQr?_BrGk>1jGl@c=@5B Zp-v$6Q2l7;!W;#3Is*tdFq4i!`T)HgCX@gG literal 0 HcmV?d00001 diff --git a/od-win32/resources/drive.ico b/od-win32/resources/drive.ico new file mode 100755 index 0000000000000000000000000000000000000000..1009e454fae42e1db726a4e583bcf9ba42d3bced GIT binary patch literal 1406 zcmeHHp;E&@6x^e^^hjDRx%N_WH4F+L-x*vL23^Z!K*b|a@zwFv*4I?wFbpPNzzmiT zINnRArZq@JcW3Xi`z~{HPdq>nlLWLXloH4Q+>j{36^ZjbMlrymu!Hx0x4+%P`*-xe zJ%ZNb@r&}+4~h2YPc$DMx33=84=dowBfVRpZCh+M8?4uBG);r$a*4XGQB@VnvczJs zzP&2f6)PP1m`A9f^$?fnKMk2j@{)%h>@Ol)aiKYI&U?T zyk(zRy?>atnGhO1lXoyiYax2tok;|M95_RMlpr8TDM5h{Nl4%Qi*qRhIbcu4I72>E zO0iFM5Xv}~YB-$amhLlY8irw>TRSjR7a2qGu!$md^t!`<$KSRGywE)StG0BO|6~0E Dqb@}$ literal 0 HcmV?d00001 diff --git a/od-win32/resources/drive_click.wav b/od-win32/resources/drive_click.wav new file mode 100755 index 0000000000000000000000000000000000000000..c21a5f868ce579dafb4fc6be2e0696df6d0c5ddd GIT binary patch literal 17998 zcmW+-1y~hZ7d>a<7FfmP_oIB{3>eoBXaS3vn;8Mq>ii?x8#;LJmh}I%F)9Xr%Vv+YtEo^FQiRFY< zXZvOQYO5)Q%4+&R=%TCXc+P2s<3h(6Cx4f}T`uU2nvbe|s{87*nun_G9LL()6Ro|h z25SR3haci3*C=ZGqV1)HSzSPP0E-OB2ms=%6aT9otO2Jgu^yPwUvK zH=U+v*AZPsr#$b}>2E`x%TFdHu;*Pr%=>Zl4>LJx>@|;cZZUe`gl`ijjBVxHqiL(E z)Hz!-PVFUL<);cS)N3?8Dh(ec?r|PfZG!i_s(R<6LZQ^VJnL8eAKO!_eXE)7nX%{R zzRlN$eA?^DgQsqq z;xo13RQr_rQ=d=vos#eGH`TxMXX}U5jF(*>ML*v3;?%3+=OYu7l6}itJ1(!-{B?E4 zUhS-w4ICUZ`+omm?QGS4To&*1wryTuNm{kjvl`9uows$)?x41FhXuLJ8xy#_Z*Z3j zc85np5?qtN-U+^b>qeWKZ^EtDdtKQd{_M&$uV3>o&g?R0J3J*O_n!atQ`fIt|9tp)J9+W8 zuOYPu%_Z|{&pSN#b&xQ3+r0gA*DcV^Pgxkgu*IU$Wx|V-AKO)wJLh=!bimu*;mF zz?i@jv$oH?Hq&`#znQ0I_|3dL(`|Na+v;znE89YcT;?v{yPO%87M2z|J5+b+z{S9e zUoJ#l`4X+adEn;2n>C`J#Fi#sQwL7(Flo}1$`ij$&Y1XhvcbRa)bIYqQwB|{HF@9o zul~VfL#IWL-!bPyMz7N+E=<2L_2TJE$rsLEa=GyL#h~-P=cCR|ICKAO*~#xk`=*nz z9j1hi={{lanAmZb$21*RdF=GDWn=D-sXXT8=)lo$N39?Ie3WkN+tK_)er$Z;{l-78 zHaZ=3I^}GavmMVBo^?I<=G@=s4xV3iF7e#EQ0u+03hR`FX{)BiPxTM*opv!Ge%j-J z-T_0VX9alAOq}jAFLQ|Q-Ph2sm;J5{yZZ5wJ$tu9hi2P4f3EFaIO@UCn{y&PBJV_= zh+G-jHu8JK$B3m7-y;S^#6@^U=ps5rTiyjL5o10r9=zzyg4+w)E$Fx4=KS#sHY})E z=vH~kjq->CH+$X5jjXuu9Q`h;Q?yge=9oJ7Pu=HYQy+|veRhA^{quL5L^r&h^XiK{unF zr!!+qelQgKOSaK<8^ z#ZC)1FPyNj=A!nCZ!B3cFVQXR-tXv3QM+P(MDM>F96jUi&uG)#S9gEL9Eq88?^n#Y zdu?N+r>$}`+@=qIv^0Bu#ll+iJ}nRzbX%la{P)Cqj)ihn2Tk*#lZLF!Uo>#Vm7c1! zg2=v6@lhY|u8p~IkKA8zzw}Y~kPYt1jp^f6Dx@ zc@Kl;2DO|!Dd^>FxA~1nbg%zG-NCT_cTrYpYVY^0;}=JcyR-ZDtUGsZAHVbV_M9l^ zsF`=iM9VRwqXS}cZhOCWcX$;%aLMH*trksLVpw>6Nz29kgKGr4hYSws6XMiwlVQfg zzwZY;7!`LnZgKqG_%RPzyzj%p_`wgAhwUHteiE1vk?<;^euB&6>JNX#d!$S1$YEVq zYz}_3?EKQi<&6h-acf(wE}X;N9r%4^jm0HPZ!E4IJS2Ge%m|mFq@H(n#RT4EF>!a_ z+`SdOC^|Q)XLQf#xAGXBZ&=hkHZj5GP^g=6#o{h66I@oU^CrYF4L|;1^L(2PIZcTJ$mN$MJ%ETby>dTa7APstoa5Q&nGes%wQ5 z`h7;6@1!y_y5s2IGOyuI|&mDA17Y`c8pUi;*~esP9^f|zg4iT9%hg|n;oZ}N8s z#j%HD<9+VexFcMjeMxmzeYWG-F&9tYSQMA>=4bH>g6UEZk+cy zzvtZ5(CIg4+#j3x@%@LdU4Lk@=lyP36k1d#e_$3%z51!f$I2f+q_`$;PYQUE^kVgU z>3hJR#G<{~OW*z*t-sjnBE59r5)GXg8XEdM^nU2v(DF;Vt3qVlJ-0_u&k9~HNOF9$ zHL3gSPtRi?KZ&V%b8=|Xr4^y&p;N;qhSdl&hQ@^c8#*5E?s55I`0$$tB6dfvyM5%O!emT&L$NJ{Z66$m^TmJLh=n+oZ{lPsC(I9=uWg zTJOt~LMw$n2%Qsl{j%oTsG9?$YR7TUie7~z?SJ_+!970x-iEur(S4&k-!;TY_X6$} zMZLVW=-TeE#g`6U>KK-P<#>3?&D(e4V~d`D|CE_sxwvszNMTggg^$HAlt)Knn?2YQ zTl^?IaY)jcx2mME&*a#%QSEL;hgVz+y1p{v=G{RL4?pklo=-JpP0f!kUSiOhW8^$_ zPY-LoBW=yy4|l)Q`b~`_;b2ij+JJWtpI=Ql_N3O+A{Bq?^EAx zOg{Ee|MgCKmu%m{r>24Qf_9_R2d6-X-NIP8ljVrHw|x=4sov%wIy@C8$&&Fx!LOYD z84c3ze69F0^XuWSDPK}P2YvqdCH`B$4>_w_?#y2)zxw9Q$_~#A$T*uZJ!^5cDfjU2 z$pxK@tVLmk+w$FW+hsmaJNmWj=X#$SeRBJf`OPnLUf$Hg>{2&lV?%uLqx|fgrdj(k z#%46hOv(C|vps)eX%$NzJ0}Kc>S>m$UI{OFh1<;a;MQ?%`ThJEj*=(#I_C8TU5R($ zvHZV&W#rb&)#qmAjLA`c`ewb$kbjVj>lt%1t7Yxan)P#H_KqArH#BEM_TryMe>TtA zl{Yy5Nx|fzv?9l%FMrzq-kw{WU6ws4cj2!y`2!0I3suF2;*^rZWy8z6SoTZp$P>DR zbd{n^E6Q3IuPTZteqQ#>^ioRTCutk$XE@!_ztU||ytA}eB&LLwH8ri1l7y*_!zR!bZ_Z;#o?52Ku$C#8)uZ2l^iPZ zDVrQ~5zSW!mF65|H*d?|#}X=^&&aUP{t)SpR`Wm{RzLWkd{a%yF*{eCj_{U^Fe@-7`l^8hdS=1l^44&)^8R@Nj*)^46Dnk8QzrtZRsXG zQLZpW*&}zeH@CDecPT9{c=D@pw)Epq+R<-wzYX{nk~;3I_@(qy*H6tp_5R%9tLfXZ z9}9mj$aDPDvglcfwajGvSh3E;%4?OKE(pm@%y{;3s;dkX)hX4?6T$Jxf*26oKM+3 zem=?^l+o;mJzbmr=Uea8`Cn#y8j>dPw7H8tlJyi8Yg#)lb?)Ta-DQqrQ}qKnTVf`a;djx2KM#LR$yMjv%y!OM zk)!1BdHsJK`yG`Z@h7(6VBxHy7ez`@i{e+sRZ8>AoXcZPY1YZ|YhvV^t31_r#pRqV zx3z95|5led3$p+vKMB({*jXYE^TOfz>hCk`MH(FUw3lEL|&Q?Y)kW2!bpT~D0B z4Pb|*x3-DaGv+H5pO*F)n z*ES!w9h8T1T~sw4`Z+JF6zKlKeXU!j>ptgU`s)shbOW`^G_tC(*q?W&1KAfjU3w=) z$ctDOttaG&6Vj%X&R zY6;!BQ^caE<#u-7*4Db(a@+jdG}J^)o~A@oj=80EpRK^YP;SVINg#KYzc1vA4b@FG zNt!~lb|GGD*QsMd3Yl2rsl~Rvlw`!Gkx-@Za=M<*jq+g{! zs#o*}oEkYFcaC-b;H)^$aB1Uuq|$JA|H{KX#j10wO{~7AdPcQ~s)xKhy@q%td0D-B zc>PmFfSh9b=2t% zj%yudhw%=}bfdHlHKWv>)z8%?&1KzkM;E8*&IeqoSNi65-ov*_C9jFqn%1PX$JR}% zH^7JY@vj$F_fwsdwU2ts)vHzQRb{Drm}@=fo_a6G-43%IZaR#1eBc=5Skpn#%vUYr z8;~NYukD3pwMAvkw|=+Xu-BG)NpqyjQf>LRJVdF_>JWkUrKiaZ_DI%C(`+9s>&(4O zjVczEcP?LE{-ivjynT6s@f>of$k?eozg%tdGheb~SUcFaNdL$q6@!w(GRPNtjoZh6 z7jCN(HL1E=jwSlpPG$Oyjw5tS)q*gVq)VbrWm#uxT#;(rZJ1lO9GDzXvbm&2sZZGq zLzFSDylX|T3YUr}<^JW&7-9U&*x2~Wu*A^BP|eWOu-i~#@H3t?h8mX}D;YN%9+$$_u5NGEZJE?Y0NnaxMMMFDo{cUp59BZN^#^{Y{?cB=bf~ z4eLTEY#wwc-)kCnYHk&BxYFDa^4)TijLBERA; zC38z(mn|^%tN38{x1E;OC>3l4_2Higl6XnAQdKOPguDD$?hIL`xJn2GUCEhsp$5)RxGGjv|EsB{Ywf^01~|Gn zzSJ$#tQG5Xampe4cT2b_y!@r1Zkbr>R}xiRy?9HJt?=){289lVL4`GooQfNi>?<8& za4%1-IB7m=-DB@1M=Ju6$=@`bKBfjrxxF-)q$`s2-L}%=YRWQJH#{hfDe)*dTRgJZ zskox3b8$g&tqs?}>#Ur3aTEC{p`q%$+Nkl=RdFynYG2h)>z)R*rn z>eWv*`*gb;r#t<2_H)gx^wK@Ha+v2oRsE_b)OcU>wfFH_skMgJs_uQYhDY_8Rrh#a zs=UJ8p;EAO9ep>4aP4r-es#F|v_{dUJNP&mUEa7|uKd7@tD&jYzs|?H&3yLNKhhwt z!Knt78qBC4Z+>kf&>47J|Uh&VOPi> zx{{wIrl@0dH}peY9#tCW(b)4*)!gc*YyR;*R_k=F@7_ym&aM8=t5FrBdw;iL*ASOH zrw~1L9IP9sS*Cg-`0(fGGLp>pu-R+`i(vPNH@At;7wVy(g{h6|(VFv`U`>kpi|Vy_ zQSjrh({HRmR_xVm+bmto?M=-p8kSEoW*YuAtTgO2sDa5?e;%VJ(O|y2f&9xn|ZM9jgR?AUyPgBE+`sE%* zonc(r(6WPNVP&h!yvs^UUzWZvEiLscJ5qMB>}*+n*=j?YA=7Z#@W7B^Xl)z|q{%bZ zDj!$=vwToRCDXQwdlmmy_?zsemS)lX(=@{Lxk6RpUfu}&xkcHd(krC}r9ovGWx&aE*sdBPB zLHVI{WQ|yy(q7?}fr?%Egih9*i{%}~0&$dTii(NBqNC^|o)^2R_NY#&_NxY~-ie;# z4B--VJTN)(s${ubW%DkJ(Y?iCz(l)q=k};bim%k{@Hfc*3EXwYDX7x zvfMOJF}F1PnElKv%(3P+mUznmYn=6$)q?)?*m~1?!n)bI#yZ{F-`dsM(CTS5Se{rS zEsrg~EH2g_)`iwstEcU6+h<$4?VfF?EzmZ^=4Tsin`2vS+h|*gzc;bD+kRQIti5d+ zwhQ*TQg!*f?4(Rq{#EWO_wjVyl`FD`JVQESkF`Xg_}yd{hf>I=1mRYE=Shj>EO6hgPI=5Nh=OZ(r?pP2oSK27lsoot9OJM= z7p-lfP15*lV$}v!AJxAi6*~%@`BvO8dWR8sDPfOTD6026t4*$wUEn3r ze7tZ;^i#c6ja7e9&(OqZUTC&zDr-X2&sB-yVu9ly(YK@{DQ1Z*7VkX5mNPslb4Pxz zWsS%m5=S?3&ipF=I)4`*hu~8$;RE^kczN^hxGCH-nnjXWloBb&N~QLp_J_7EwiDJQ zOAX6q^Hg&!^Gnlt(=YUyjpi5TI;j3Hmg?3GRuk%_p{>2Gn{|QJ-FnEf&f;UKVyR{M zWWHpcX})gCuh0Qe!i*D*C58mUUc+QVTf?uiU8w8g()7}yW!5s$s4b5!pH@*)F~oGq zlxC`KUTOYp?qP|rxLOAwcg9&eSbeP3tgcoE++m{imbDPsRN3ZgbF|e&7A4sF*wgJ3 zr8tSo&ax!^1Yb>-c+{zr@>4m$s*|}S7;#NQBo-i#eoI}XF#Bk`hdsr1+jbCnxx_Zo z*2dP;w$Ap(R>wZwe!(u;+euxerc!lO!#DdX{OniM!yH>PTeda9de*wbI>)-!s#u@e zcG?@GYDUXn)tU4c2!E=vpSF(%M4vQVq9F{va(r4;-IyH9Q%Td=>EAfs#vORaGY-KHX}Y7jzPe29 z6W~&Xc9kwtw?y|{D`-1vuBhv(<5infJyZ=;HB_I)zr^oCVm&RYiZXllWd}E^OfQxY68KdI8z1;bw6c zxl*n@@5dkKD+%|65V57|uF7BS4wYF$>#2RH>7)r&w^FOsUsZcmRa7g*mx7njhVRKW zraed^YGX8;!v10hQ88t#D(OPn<29Q+CbOw8r{kaVE3mH1Vh7a|RXg=gb%MG=Evx^i z&#U{WKdCOM5>zeJ5o)bQL6xpmS5x0ntx|1Oy;0Rw&rqL1)$URERTry1tD1mG4bZ&R ztkt&GUD5s0rRo0Fjnruo-85~IcE8q3J6m&FeNS~)d?-+19xw8DxISDZj!_GB#ox|w zHm)5%laJutg#kh{A(0=>CvyF`B)S6`dz*T5vD_>^o!1I>{w@CxKaBU`U3s3TU<~)T zU0fsX0=1JFq&_-^7a2!xq3e&NOXvZ5m8Mc>t|8ZpTh6WGI&z0-9wKm#)n;kR6Xh|m z>AJFBf!(j1QobnF*aWtT&0_V~Yh?g%zoVQlJ(j|x5UIWN8$6-A-3NUj$iB%QV`uh` zk|_OUzhx6_i>+Gg8_Ofh9m_$>FpCVmb=prymhAaAeh59Ym)V%^&e}9b)>bbHO+F&GRHE(GSM>4GR86s zuc4MHmIs#Z*0JCW8(71A;}O>VBNQ*J8nln+V@K9?&k*a{${ANvVb)LU^> z(&a;PFWFHpl1d~K-t$TNASu!ieD}LNNHHomSTGqz+i*tiFFuyH@YMvh@R483&*M+? z@q7-V|AIfvcj4o>?p!>g`;9!nG`$DuMz*p^tWfb`Ygjz%LWa{iTnE0DP$oo*i_x9i zAWvFo4rxwl0yJGT`Ra@6U20K153H|)_*ytF1Pk+p-az6`bVLHE-) z9BOtcP-_gggVckjHOx-u_XHA~E ztNMnjp=y&DC)oHF*ts8cFbyFq*=dC+C*(2U;BnFk=_2aTE=`tA@_i+d)uZRQ65b?) z0h`CFh6A+=#3$l*Q4;zKyZKw(8akQGW8ajG=zjGTjS?ykmTSrl<$ZDsB}y5^>Jv3k zr9KzJ9pG+p6;R-}`FDH)Ft&#v)P>geJZS4m8A!(3oly552SOM!s4iZYw!B^KwV9(inGK-Gl`ok4%D*hHv zs%m2&gVnz17ME3hRm~7JH&wbgN_;AG7apPtqPTY4C%TJ{qy1@1Y9#+6`v#JE%w#-$MZ0l- zaeKKdTs)V|z2Rnaw}5vPNax48<3rD`gSjPwx0$5PQah=&v=UdTA^XX<E(z$dhok1ti z$@C&Mp+k@00=XOLjb3~`zB-hOqi`CL8!EOHONA)mjIdSk6*Bpo{53v`zX6T=87P)c z`_LHF;AAq2Oeg0EM@Q2|Gz6XW0xh5ox#`IGTKoXM5#N;W!|&t&@EwGIg(l(^u_4Yc z6|1JHpQ;sgA0YM%%_>cnx|aH=sM>y8lkD6_-H|(dN+Z>&OtC(fWtg zU_4&ESP(nUWOkS|qW{wOG#`1>hYRA4a@V;XK=nL2n|e|W?FWXn3h^66d3uzn$p+@b za+PynybOB~j84~C4w2tsS05=2*%Eexm9t)C6}bW3*OgwPNGa|j?MBUDYbT(GrjrZA z5fSp?4s%zz{ajV#rG?U8sjIw_4+6nsWgZ!ML#fTS z;mMPjh8!iGX(U!S73zD0J-&C4y~k63BinGbu3Qt&0`@X^Q5g(8>x!KOLd?= z*1`Kol^S84H{??JqVj;{5j%Yc$4ut?p+{E;bHx|pPqADy!o#T$JW!tpxavUuj>x*| zq&FL>oP-|~D)p1WCc_gF>;ld)g3?KL& z{2orr718hX2yG1nx=gx~(`+Cc%ub@~PQ#N-p--qn-M9eG0u{LsoMDW3M=V5sy%zr! zn~4@73*Y0#TvSIl;Q{Z?kKyi6KUx!+wt(~}&4>WE=rJ>~WuzJnrIonh+zf6qH;LhCLT8chq=aZ_Ejko9 zvh!b z_2@!mN*SGkj&=~MF!I@a1@DEvKLXc`6-J2Z=$Bemn)pGqiDuCta;gEU&8mT_E219! zsgLjt-bW2!%}jm+->}}sk$f57WW8O_(|Ml8b(%tZC+%Xk=21<=rdV1J5RcS z-_L-DbD!@mj1vNZMn{0K^TF}1ikn1V(N%mVbP_J`y?I~sw<`Qg=&AMG5H5?x&{7)A z#c^pI$8X_lBHFFsa2-;OR_Ci1Xq>h8wXV7~4Wtuvg7V5F8AaOVH$pj6tpT?8g znCUv42G=W=#j2J6?5tgBP zC#W`nU5|mhW=S*BZfW(kWG!UrNi@V9W!+Sf&C-9$nA9R!}Vr^9iRdZbBf!J6)CRE4t#~0kL zJ=l;RT}4)~%Stn)O#TUO6yq-op( zsHiA>r#^7A7wv>THkl3wdmc{0;g!vXvs1#xk!Qq#x>6N&0xL+OE?gU|{08tz!>y(* zs57{OHyuO&p||KxS_O`2Bl3c6XNOo0n?cTFhn|vqLTo&u%T0(sA{A*>}T?mqNEAT-S-WtGxUF@k%whr5)8 zT<2N2VudDhVOtmv&hdq~<7u4fULs)?tFa@=Y$EPFfcl_I>&XdZd7koG5s_8Xac!GY z0>u)oBtm%~VrnvmgcBoaNgD$DLr`N9Q(;#;{;%pY*(tagb#NA>Dw~FWew+ORw(uFA zS8XLrPLOlJ?GGzuN+YPzMOgI~sNb8+g#?1fCgQ3^Bn#QLm-wMeWwJ}Ckt*z*(pt%t zUxO!<$nHuAnA=G7(z>KCnMfvpKefc2Rph^ZI)ZG%Zd?X~=uKpH2RyVbD^s>BHgJ0f zIUXLtWAwRpvajqdd*P!eILL8XrD%~q%jsBjt6tz|ZNYttz<`Unmr#6};6D?|I?UsG zVQNt(f0i%ETjizlaJdrr{13RcKPA09NIoqW%i}T6c)%``kzhShv=#S?YXL;v0@fGG z{|koOfKNb9Z$&@aO_m^!TQO0oDIb>}9%vz3?Z zzfKlJmO;fogj3WHE^9~PiCp`G-j@RQKL*)z1q$~N2_tc25fQ<8rb6lWB%|p8ZUbL} zKCTwlgYOI6F}j)lqT9G7{0MN}xxzYr759XSvcU*?ZNSWkZR!D%}96X-=XX~*i{Ss-y7)ZMl1_^OvwSV8Tz|E za(f^+fr)0L-g=rj<%2U^D))n{%OwN# z<7o}rou@`6b4aW&Kh zI_)miL7Th>#+~5obO<_t8YdwBzz51eMRjKV@nXtF)NPKk7>Lpfx^X9YNs_Rqmw*o+ zP!|pV&vE?e1yY&ZWGh*H7Ou=!CMi>uEy_R2J}_zp4oH1W5}M1^Wj*|d82Cl0%0yu0 zD$E{iQU8Q4FHmPqJu2vGU1l?;yds; zIM1l#5@{GcO2<+gISp582j-@~yiO<)&Vy$+2h$z|u2olj%g^Jw z(2?XkX4aQ5KTn4%H3xmeg#D@|mDxK>FQLEw!r6>=%5!Ben~FXE2PaGdxD0M3?*F3b`bnX-v&0U6axrb92Z&`D8M(LzDp>xbu z&SJK-1$F%2=V(mW&oU7mHWTP}mOcav83tZrMyFhlTz|<1u@{&|y^|-%bx{$DGzNWk zrIH4B`XjtKH{~$!Bm!>qF1hRfb^0n~`3TgCFFHdkcY&V)hPxg7WHMiq{|-Ev|9`*k zCcfIhrLF@p2quD$fX@BE2}h#FXgEZ)D_RxIcBFe}edp{8?Tj^b~ptg7A(H z<9DEDUcx_I2=%z0+sTarruW2bAq$Aw0jTw#ay*7S{D}De1(uhDUNRAGj2_-YFxQ*^ z1+TG`pUNNR;%FP-$vEi1WRCLJIS(#~mXovS$^%JLM3F}vr?A`bp?!h9FXanB^2=-& z9N{A6sd5`$-#w*3xzE0mT)G;HW*^qH2K=BOyq!bf(}$o)5Az-Qg~*Ues3@!5) zbjv=Wh~M^qmH7+VHW(`1olYTUWR$=vDTS!hul83s$-ql9C8OjEufz*ElMC1H7CS(a zX)}J3P#-$dLyQ(qqRNJg!$dDJRH!Cg;=A&1;G7)iT;Wqy6a0iG!d^a{J5Q6r|Bj*C zQsm18Xrj|p2A@k{Tj81vBCSvfC%6mTP)w6d=#*(t0y~v2@(4tzLV5#ao`hPrOMdcU zaJ5>>CU`cCy#-%s3oO45$L|DqVg+{RBA((UI8J-?H79h4(b)aEw{#@G;hl4yt3SUn+y@o~k2ed)I{T;E+~e zWCr$y@L%9+?xk07Mj;dWtiC)|I%D^?m!XeUx7WAVvv;)nV{&h@@0Ui(t+7@&c$@#_ z^h2(Qs|;u4J0@a0w+DV&G(4x_i2Vcbv!l?pThVj6qBC`YuAPZF(r)-K*VzTO6pElP zUIEaU`D{CxPWypzHRJ1GRVU$dxWF|DpwCEEvLEbvp%M<~tEbciCu*#cN_La$$P1ta~BNp3%W=xOkk>k)7M5%c@1T? z1+}AL*_evQDrUtW-^*o@&;!kxnmvRUXO?a9A!Ri9qBnG*FF0s>yt^B5Bx`WW$X7{2 zE{*`A^+K23D@UM9R|b}qVm{=ptVBibhP&5S`CBQ)^97=#cE$asfw{hCY0yKr5X)0I zzc7>a0VG~gX26GQr!>NxVkrJ)1AiF~#@h)zwm{fleIDr_BU3(C}-ef zja(}Ak&^8{aLS~a>U_6_FXydt&IL{RicY8Nx03kr|mQb!m z(Ay=f8$9%S$~Q3EaLh=&<@;b=@yOI1xiii%6hqhhK+pLiL++3fK++T->3CX=>VT&X z+%ZhctZ>KY({W@I9Ez539cRjm<&~J(-jFz{yL}eUYW22mw7T2Qp&~BZPfK^?c;y_M zi}N8pupTQ70vqoF4y1;MJy0Ac>cl(33UC;ea2yPO5I2gpB{f(>WhMB%r`#WIe;3(| zb7GQxE-Gv|&UCbtlB8g)^NTVWTJs$|=3>;4FSy1p?EW_;OnC|Z7QzxxJ?Gh5py6el zLb?J@I2F3;6Y+vp-T~hIlXV7n%Oq96DN~^no>6}=d@ZfO_pU(+Taodrk$029EYqMg zE@5in0$s2jUH!YfL)pYGk-c;Td<6khoT}Vz%oNr@Jyj>I!GRu;c;Zitm`W|c3CM1& z0s8`lup1~n5?Pmt8R9DWC@?5Y-i@zJ-i6a5Q{hmi!mC&VNAxkyi?oFEz7vWk2@~IN z9X+Z9`}BiJP#FKs-Zx^>P#^0!4;{aNw1SRqhSx~AJ`QvNJiCjS zw8oJ>ODWQP)Y3&@)-fpfRnXlx@DYcds|C$G1oNrB z==QVeKJ@#qU}&lEQFGwE)WEDDnA?C3I1aO{abPmTa6+&RHvnfUT5x5UV12_+>9__s z-E|x~+>>|Yi-Cr#Fg0lb&Up%vN&tI_21~jN_r!x#0)D#_Eq1`det|orvoBDw&!8rs z1^aEPywSdt7r^ONL~G@O3=LSB=HP+tE+rT;}{ zp<8r@9;gZJ>w-H~N2L1UTvmU?xC45>4|r>PumFFulx#z9xempa1hx1T*G$579w63N za2oCkc*S9|6;q61qy?@eV6F=q3O~hzv;{w!hI(6q4m1x_j`2_kP0^7UW?gA`iYPcC zXMpC1;2Uj(f(ZmJ1puwaL$P-QcJ>4cjRzvl#&lvU`dT>qfM>0ab9Mf>=2|GWDY$DN zDDgVTV^`eU#6Gh)$bszd*JfdR&&h*CpH{uH!h^V@(sVk|pRz;Vg@J;!1Z>A-|wwuOL1v@b8ge zSqp*tTah*YMZ<&{$tQTKpMmivbinqAKnUjbQ}MrJ5sw*&wTMpt0sT4=_sd~b;D{{3 z``6)0bx9F+_YERd2oKDP`Yymrg`MdRe`qt@0S3h}4A?my{@qmM{TAeRU#J8(s)z2) z#4eo$=h#AaU{yV!_C6qg{)=B9?7ctoWW)bgIvxK9orx-$gWS{6W%LtHQS{;3a;0FA z^)YjJhAz+)6QDIX(^i9i26~J@z8JBxZ>YPE@WTSI>9OE~HgvA=|4)SGV(%Q80a#Q9 zuO|Re=mW)hnyex7v1=j7&UeVAJY?p7x%nI`X^S&M2iReD0v+=p;@k=ER}^e085#O ze(VX{=*-sPJl}In)BbZy=HU9-@PJ!k0=5?2^%d~67#eHSHKavFO55O{yVsL>m!V{a0Rs_2BCyc=`L3COck zc*Z&;h3&-?)C3dR3w05sEWzBpFZAg!u##lO4KD5leAx+_ zPAdb&P6P8ZxCG2bn{jvHC%wQ`1_LuDVU5>-Wmj?K#v~VhXkGC1KIkDw|Z(6TOoNQji_1_IUgQ?e z_&Tx*ti>G>w=3^)s`V!v!?Qr-P~=We#4rea{wsL;IGkU)10=bP&yV1ktfg7B17^Eg zZVOFEEqmbE|3=)lqSLL%IzKA@%2V*U0-TYagws}JoNHS6ph0AT5iC21A^ZS^Jq007{>mHGw%IJpc6009VqvK3obtoj$zZ&_?A z(yo@j7Fz@u{sn%7K*jA~O=a9>OyS4{Yb4={v-(Y-8uVS_M!TO5Hyu9X7K3s%TLr&q zH->!&JIV2KoilaOiP8;a#bwg+=jH2`1^MvB5&hJ*nXTRR{F;VZTMMG6dGHFYXlhj9v9j-FpUT|JvP=J#m{wGkjFz~T%wKVH*%s%%ft~dqYO@>vH1F)G<_064 zdi6VdTPD%l-l#P@>tMFVUu6VOrpR-+)@+ah3 z;Pb-DsZWnoVxFNsM|UkZW>3CX`d@KU8K|VIG_Q2HG{5v(S$tVaDYxuw!LgYMae~OI zXmMmoZGN5jO8@HT%kod0x>p>gb8CLZs*aVtt2m`67XXXy zS4>}7R5qg`q%6KD7=vf@4;KsiT?Px@m*=m3Td`wRV8xz_oR}nStT5j?=(l#Jf7*E5 zJI^f0PVS|y$cA}MxjlZAOrC>mjs8A-jcZ-#@8}VKUxL~MSI$)Y(QUD9hB_iYV(#Ke zj(xtTCcc=HlMl(WO@}+p6F=!(_G9O(HBS~)UVdbF$bE3}{<@M(unX=#h>zB{xaYkOlODXS{PEiPS69~sj=QE&M;1?@zZpG9 zf2&m66{U8ph%7i&yszMIQT+5B9v1X!m>pPS`6}%j?XHjdH1p}X`~G(?-NoMDf4}09 z;W_&A%epheUds7IbDVUMBsV#CX72mt%k$!vH!Uk$`g<8>dCu~w%l9oa&ApcLa_XLl z1ng(_{JNQM);wg~X5C1;dGFSaJCFyy&*ywT-`F=UF*^o-%g)O4$Y(8Inn%drm50dR zpI4Ai$sf(BfiyPPzI1xjd?(_b!-Ks~KE6nMllX4Y`?0s>Z@4ekK681&eeM13*z3%f z>)-yZVs!N}4#{8XCL59g*X*}W0W9yy_b8Apr=|Syorui@_-LN6zI1;41$lqx>B#Nl zH>O`-e=GDE=T{DfWKpuFsbI}^~8S7+xeZC?6f+4!=D%a7*u zm}PtVoHp~mBquw(JLmbn7!iZqMQVq z+ZDs$NNUZ^wpSsZ4%uekcFw*Wx`qBsc}`@;x`5oBOPETX}o= z=Ca(fh_dx%$g=RVMP(WJqOd~CPI7H~OVi%w_{LS$pWnZD8uaA&ld>m_r@x<W|-^edkvPHSTFo=+<;qcQy5#AK1XSBUhU=fCE4;Te9V$ z;i!rzLrW56dAe&L+<=we(ZmJP=NW*WHKt9rP_8Suh7*RWGz5^P}0 z={sq^s6eWCd;>XmIJ&Q(lh?YT#o9K#?-1pv;IAswIMJ2@6XGdu*`efwwXgx^%4gb z4PPdgGG7SasLD*oY$euc<5NwlQZBnJU!)YP19TES!Fa-$ZD4D^C>v$>rEg_&rH7#t z^cuU@>AJ^n52Mp6+!m;>b-N)@`$sjZn4{REBAT4w>l}uC7lubh!=tOheS?a;>zr|< zHMob^4|pH@YUc>Ioi6>PpNMnTJnca_R+1*#AY=+U1a*Q;0fNV4&tctSPGJ6Ii0Ldk zk-3H)$r}{TlHg?=`AOw{)o=Aw%{jGHkt!2NZc5u_bLGy`ErLbNH)Di>+JASZtJ&6Y zyzXs3CgbqCV&lFh+G0&X%lPy zh^sj788>M~)K}w;V+kYqL!$!+`Y7Eiy7D_$blhz}(=P0&=*b(JK-(&us%^I(0!0Dl z8rI3HxJZg+z@d9*TXR!K!@P!(25A$qZCmGmz2-s9XdjtFHjWjH77V{1c-*_Li`Mp~ z`Dg>G?r`nBKjfN^e_s4u)6m|W)}iWY9q<`09M%tB>j(8pIxn|wYgqrswc1=|{Y9xs zsIP17?KO=Ypj@Wipw&_~kfX=?$6CgBQ|D5hC_Bf6;}^#Fj!}kB4H1WZN9)H6nYsL4 z@qKBXv_l##Z&Bctrxa$XpKumSLY^{waL8%Ihb*TRbKgqm==3%qf`@A$QAt6BEbK@0 z8g7NsIih>bV-C_E8qe62x}}b-d-=&1@9|L0?G2(vuizOe!mki{LL1 zBnqQMFmaU_DXo>eskiF#j65?D@E@25D?&<8htVAWi`<5qj64m;!+?+; zfZEbyer~>M`f3Q#x9EWSetnk_VLJtBMuea@Vsr4-go}h71R7yBaV6m@E)R1OHH0w1 zpTZUJazqMpE6N!gPi(fYb!0m0-G{xEJ}bT7dTet0>nw2~*c0sX@#m5Kur~NDSQUU{ zs<&JPFM_o~hhVc&shBe;B$A5`B-J`RwY!Ypjh%{h$IiysAx}d-fV<%WoS)-Gcb>Pm z_n>nd;Uo43-j8?z_Y2L&){@@ab>h#Vxu|29`M3zuJ~wjE>!=5jTY~omybIbL>J<7S z_*=-lh_t9>5mjN}$cmVzNUndbo51OW^L58{gllML%y+y8Nn&@#ai7aW*O#suk0*hY zC_~JraC1P3&wlqa_MwyRtig*bGU6KY{OqhJjAl+H6iB7IZS|KDLxN$-&O~w#!bJ z6V4XLg$}RnGwc`H&BY&w%d9QB=PH=;x4*4%iud~UCbJ>MC^9}V*z1+L`v#1KZCt0^D)y7F)vPylTGMSj z+Z0olwsCt*k`C4pv@d+`D`Sq>_s!VNY-Ln(in5Ff8f+` z5~Y^=Lp9l21F*BubsF_zHBt3KS)+2%zp%L>|0UYR*R|8hXh$M#bGYaB+5N7=cT^}O z16&Srv3}HlRxOfVP-5d=AeoI%mB?d4dL8zcw~#TBC- z0KXUkMqlGQ&01-yP$rx&iI;7W%cQ9SBb_^{8~QYIetd-L&)Cjs5$+Qo<2SQzF+S1W zQj+Pn_-hoO)z>u|V-#Frx6<{Q+mJiZBi@;ZdxiLo#GzL}KbcC@ZxveEJV}iBxMaO_ znxtAZAigepuXv=O%4aBv+Crnr3^PwQ9Mm1uZr4O? zdkVb=4uk9lSpf5`7&FtT(wo%>Xic-B$7phJvKFE$roJBo?pQ4BI zU@hI4VfzXB4@Jk!LYE=d!}6h_a2N(gNFWqp^e_xSujR;=Nbe{fXiJROOdpMxbP~mo zq+I${2{%l(Ed>7uDFHbE@W61$0z^9A(@F0>*=K>T#C^WK4=xeA3cuLS%{k6lM;t^g zf&T~Ji4>w;u@mscM1P_fzXSi2P(a#Etj71??+{)PYaDlY+4;Zqx$lN>7Q5DX0|OTM z(CjMzY0j8!65uRA0h$TFjdDj%Mjb=O!E?a&wnp<(>oe;l<64bXCDf*wX|_i|9HbZC z_%BL}v>^&!|liSAsDCle~+aZeypw?Vv*NGl(+=;e5{<;KOqBaXLv- zqK(iAFdl|r_w1jNfw6GxT;x086w@}tMQbS9-%}NBNJyPj5V0ntEHoz!7rr(e6w2}5 zWPc5-MqPkiwDxMhsBdZK8T>7AkbDe;xQj%$Yj?Cbnd~H36Y?Gcil~LY1|Bv0Xm88b zh^I)8E9zBc+PlU>wh*uwb`l$7&vL*Jhf!DHn;;=p2W^r(T=GmfiRZ&U#SRpRWbZTv zBLc7rE z2iOFm!I8)m*fC&|wb2r56`0428;k?SwWfRKax=krQX8zK%KR1cRI@ZA+E#6lhM`=p zc&(hSNz#1OXbc0E5!)6}JG2O4fX71rfIT2D!1saIZ8odk)?zzk4m85`)e5?(L8Ott z&^g`gEeIaduxD|W}K`yX^EOC%29>0c7gdk;11{wsK$mh zo>t9QY*Am*4yb*V*JP7LeH;MGgBvSpQwS8v3a!$lKBf94ZMof}!S7&A5CG^QKw!SC36i>rj*3ErgSYhe0G`a58&XUwf zwX$P!tm?Ctuj|v=X;`X4#X8YCZVc~~=#q4uGTpooxgHNiJTl+X-B--yy3^vAi6Wsg zR4de7GtSTtOV9Eji594dCWv{&x(zmn+yJY$T{mcTN#+4iCUPOJ26Gm+69Cg!$a=-A zRO^6T%x$a;?g1eK0|6&Nm53NjB+S|9uaWAX7@<0?vQZ7SO~WbO4*QM!eRXX>Ujbc! zP9!j#5}agqSo=V`J?Iv|Cev-pxUI=zvK)fUKpjVH0%wALLer5NR1I#5LziO{E)_h> zVzy$Sd1x3xPlVxjAylA)fG?l~l-UmBUg_{?wa`YY*)#ZdY#dnh@)Paq1f@@IgN#9&cd;o^~`6+*OZ)-ToKv|#NwjZTRaqgbEF zvq!&;e`J$ncMOHVA<#PWRK*IOFZ(~9RrCbznqB#`76^86uZd zi;n}%Qyk;0WZ#rV0dT|>&N>nslB5=Lys3EF6aE^lCma762ISvYS#f0ObAAPUus$go_JOr+aJPK{n*gv539d=leATusgc@> z(J`bRTrKc~;wCSK-z3krp1>Y)ZE zmI?HGtr#oOutyar{~_C{x@LG{;hXPijtJ8jJ1H{iZT3Q`&d>u~Wc#T~ z7xLBFfG{`*o(5eG@&x?0?y(Np7K0ezK@bLT${b_Zql?nHYKbbm)XHDUiD&t+qXqs7 zFFn-~+%j(*sS3;=1&Y2rAgl`^@>wd_&tv;ZWW)Ch{-J6}s~#e`Bp?jj}^ITdx4! zz#Eu+5Nmi<>dVNV3+0D#1-wp7xS#oA5fnMQE0n>IDXlvX^H^tsgBU$1?3C zIr_=AW-CG`6Xmgk+4iDox)SJSLV>*!_XTuB2h_M($8ctEm#Cz;$`GzysriSP!aE~= zrmT=+}a&-deK7I{Ji|nz%O??KI zq29b0lKqdF)Ci4j#y`&PHC?jBL+@f|*#k))u#Nf=WsoihKtsR?c8*?7V>l7;zF~o$ ztWVc@YiR2In#r1B^=_S~?Fj0l{Q;LYXPMm#bT`ms$kaiMT)=Jw2Tew_0wc^bjR@m@ z!vce|VaY$&X(_vqk;pwKwP<`T?$9Xo4m1LiqR)}(#am^msvd2f$rZ$aZiSMdc8GEG z63jdV3gQ4x244fl*s`prY?lCLi$*s`nJ>E|*&-%Mu(Gf6n=-k`nZJR%g`Xh#qB0m4 zfwGZR*i`&oyqv(WGdsxbfp$jHGg2Zx5xF0{5`eR9|A$F#dWL$9;()YYGG8uIUQo74 zyZBew@7QnoW~s9_%IpgGXg#busn9Fn`qMTO)POpHJ%(-sPd5@Zb^3D<8*#GxfX_Pb zEXQ&vOTAZ26?@3uO4bVw^Ck-Jh}+#j>707;9P>>C3B44OYoN&Hib!HF z#SB9m=p|fXwG-k;77eT-53<)ta}EB0O9ofLw(%h{i!-P~0S+VHqZQBrErz$5`X6-# z_pfTd<(WB4wVD5%zJq$6d&ejs;k@s;fMG^?5VMnvrKiebf&S=nM2)Fbe2v~YZeln{ z5{w#14`LjAUH?w}kxLiwlx3zOTdbv4O%-z3M+6@X`*CrehkYhEimj6d{H7L@NG>5(y{uS9)Ox45KvZp+5f5g~Ho zH5dvchP|_I_00$ja=8w%S7!-^IdLMCimN@KU!f~kd#HR=Xk8^}E~XaQ1#CCtEfg@1 zfD7zSzM5UKC^xfkDm`2uI4Syka>Cs3%%Len|4oR+vMX#MccZ9F>Zc4;+iOO(65|rc zJMC=Zj4ip3yg6G2$(L2%J5VQG{$qLY*&N*iIric6p*yIMX?;v#G zAp|HP3?G805UU(BobTc{06df}oD|AA@;Uk~Ax7^CK8(!4KtzPyz}+6UvE1na}%zUg8{Exr%f$g;F3v<`{uG4ddfIx$OJ9H0&qRR za3z`hlzCgAFdWAP`K^yi4`1MpLS3=mv+MySz%iH*TrJ|U`In+f0R-eaI0jFe)RL%( zu5|ut84}eA!qhdOi-fgKt+-6%F80+ya_^xrmN*0So%qIix5rEG$zGq_DIOg@8~sE4 zjPCdCr=h`sc8!yiBG@m=kmD2&r8%-`sv6xd<5u%=OM&S>^>VR}OX2L`UlWcC`$UH% z2c#1ePMQHtu?ngDqwxa*?OVcJQroiLr>%)lIn0D=41TIug;=>?aY;yHPh~Ngv)Im} z_u4_wS=3F$N9%oM84tt|Gm7}f>S{xe(WH%4FI1|e&3rmFb;ve=rK}fx)XV@gu?lpx$(wJYxX?bc zzVg808pRsT8+Dh;PJ7aF2L1)lC*8vzfgV-W&<_tX`)&c2{KcTOVvtQE;_Ox&Fsq*Lh{1<4B>6!dHw$(Sq?h_1V#^|paA6kx> zDrNVmb$yEN(Ef4?TG4`D8VH`aA#N~;;j|wGf*62V)~7n7)XKCQmUhqROQup}Hy|R% zARkw6C&%Texj;9|R%;T(A44YPxJ>mv?2&^jGOiH98T`@M;Ys5z{7u@qU_6Qs3$<2h z_AAnrE`~D5ZG1AR82tvQ*A=Rwb%#K!?Am=aL9YYU-m|^8`FDjp3x|bzcx&*UfGz6x z;$NaV#bVP2P(Ks_ONX9BOeD?lM^E#eziAF>;wVX>N?@L*MhMRWXSyavj7(S;5<~I_ z_Lxhc2V5wzYtlpJccmvz9`FM?mN`_q`nxZ2SOYpP;0&gB;5*L@e-oD5ZsD|!>s+Lc z2Z=?5CQ`56LQ*4YfiXjPm34yQPEVnoq^Geb^O}VRlz#y)N%y>&fvZEK!ioZadcJk8 zA>4)X4Ls2s+MTg4l9!atPKZnn-}aK?i+a984TJZ`_97&zK8>4 zW%9jpv*MjL6PQQn@JXDoGr4S9e=H*Wa|pzr=n{{c2VHLoP+j9InU`s~3Zo0 z@L{**(anin(-+Mso%$(UOoK?M1~=Ia87(@MYOk=8xwwHwkBH_CxaQ_jqUezwi?W*H37Qe-rBEatp(T zJqNm*FB(HF9pI%Hd%F*gWgZJ%V-Ta3kKomIhrMS-6ht0!+@|Ak>2xyvo0JECTGKoEEaps zA;~M>0ZGV(LiG`1FV>Cm!jYB3>ql8Ml0;{y0+7JophtR$2*`X)eM0}mrK*mh zv%}lxXBDo@@(o`Ls}qBn^~_bmaRpAbN>oW}9qAl7L`mevO0OxX(oWti+VN5GSRwni z28a1~6mjy1rLNTgARk2jOZMh0Ra~+8;0X3)TqRrp|BU*KD?E zL9WQ^e{58$oh;!B&I$gLY|%Hsx^X=?f1C=vA3=iuMh>DDz&@Ed5(WLlaC)DApJmW8 ziXHE#J?H6U215v9vEybJ4BAS;hWVAsquT_`~r(n+=cROLQKN<%qPeb^tJ*CVT`9 z2_jFQlXNwBjC32e2KJj+5tx>Yn-`eC!OfI-)1>3otQh4IU=p$y;;eru-JyI09(6eB z?GRKIxYpi7{c^<8@u4HQe>v@(ph^_aQ;u&Mh#h!EPc->?v?n^uZ(8&q2QVLybSN~{ zi3Mun-|wH;Mr?iAq3Fl6ju^HPF8TMw4#!;cJPxnWrHWEHsj@oALHmskQrujqOkb)v ztNd+#is;4#V*`*!;3u%RoqYm2V$%})C*BSoa@l~+1WYzzOdxBprCF0F-OFFi@SsNU z7MS_OS)SkgU;7R@2B1CQ)8U!OTiBKGi|SC(3+aE#ce)JFQcMGO62!@HRChr6S^QcK z0NwD2PWh8Z&p%YyIcJ*NT|Jq7YAlAbO>k6!mCj{wdZ#pdG(2kmOJV9?ySgUU&lSx9 zr6tY6Wf$cx%)OMeZpvj$BIRjQUbCW~$eUy{kYG+m^h+Qf_#6J)sVic9>eUHK=YxhM z256{o7{GGU90c75-q1c2dGg|fRs+pJI3afaszqJ18e&#@Uv$iM`05BC$N)#B`te!4 z;GV9bg)9fz4BH%gl0PNnejwY+&gmLq22P9_gt{0DWYhQ>#vNK8Ba{16FiUO+D)zmZ zaiQ>F;nLzY^H&88BOP_^;=@9B$vyD_>2$padBI&0;t-%y$G6w>gYvrS$kM@_m7JH65jF4_Q5M7hqRyro5*BR~z(y2A$e;B*? zJLS=aM*SMuAMqJY4!p;`XU2G;u~d_?0eOv;KX9ktd%R4vK{KlC;`WRr_6f!=X*Hom z1z%PiSaH1Ucjg5IlKhq6Oa032RJ%wC-UcJvvw7mGcseWQg8?s91)r| zWznxVAly$d%6KSZfq(e(qvyCRlx%An_%!A7yt=8B2rxf7d(rOsfbcm;o_rxadkjUN zDlr=#fL24AK_c@%|CU3h&tkRlXDh@&Z=#445B;X6|LfPslqAzN+dPA#fIFmaf7&*o zTTT9MnCb7EF*7H9Rz*-4oTNO&>t=g!RW^Rmt5~a4;$`i zYBi(!tw4LoPs0>}WL!1+h1$(KV>H<}`Cj#U=C~8(uf91xJm^dNE#7P?aL%6Kov_P0 z*_O>LZLh5PRx_b<1~(G0*l}6Z+qCm(8>0)IFF|Ljo^a}D`)E%YCPohn!;|n{3pc8T zmL(QXn;(LSOgB*k5cUqP6MrwCuh?ZM)?%eU1?|EKVxXX!s~Vrxqi^-=YNsr>VdG4B z4$GjS4^+s3nQaq0cMl=B&&)@VS3za^uc|AG?XpVc8Gsmb2)PA3fL!J{#d~$2HSnur zpkd`Wpz}#fXQ!SzYMkjZC!7!-<6qzx6P6XdB<#KGO$bg*8s6Di-Qzf#N@H-(sE@(y zoUa8lroNtKm~zCQj#@0~>%+D>_Mpb}%v0hEx<-H$LWO-s?I2{@@4}}5n`E_I2a!}$ z2eY_w!(2mPxGq@%HD^>Zo+5ET)(7}bnx9w^%W_Ip&<9(3UJpH?f%tc{D}Ya|JCqKb zF3O>?12l+a4Di5ysb6IXJuuSaEO8wKVf4`@YcI<)McHyTDAq3Ajtc){3KxGH7Y`3G zYmBc+{ys1L)7);r4yY=GK(-TQ?a-Fq7d>Ia?^$O3L)WRPbBlomOJ`OGUvPSfJC36` z5ZzLpzQcE_GFj>LF5WlG3Ga&8M+*-X4$tn5dgZCZRaw7F4K&!m>F)5JxkJP3R`V_= zqVEUiYtYB?@8e~?83W&06ZKVguVRj6k`|3*?46w8w+0Qd*!0&8+ca6KOKPB2p!QK0 zST+(ic$b6}hY3QiyAS|K=~cl@X|SxH%cEA0P8dB&-K`vRuARYL^f8?n1#miQt&+!S zT?juTbxF{KjsAB~@w!x5x<(3Y$Cub45l*^YBDF9?)}ajo4H2d~3*eg+LcUUvB%CRp z3BY>KimUa#Z`&%6keBvcYg^w7piftnz`{H)25s<=Bjs8;GrgDI*4y6DRo{1RB#}a+ zLg{Dtc7`C_cwq9($VKCGHbosJO#p=(9hGxL7bORjZc;Qmf_Z|kGfc5t9!X8y7{_uw zX?r2@X0uo}!sXBd=^EM-&?MHvY4Ci;!$~%B{5p_44vby!$lbA_? z@m{|n9O0gkZ{6vGMu8rl8W0-aHes@JnBvd~Xn;Jnm^)qh%n)gqDEp7Sn)ZY~TbhB3 zN&zfQTy{A_MR>#h(@^~_x+l@wu0JLF}8WPF1wu5y7X7h`B}l3@6-dM4<);SL$FgO1m}03 zw$pBupwW9(XYS9Y1Sw>#9SL>Ing}Clss{L4@HNTP(axT^{TrysN&@z)>vt?od5|)B z5HreQs+Dl`8qc@Bl`h4E3bYCAWJ%Ej6{Ear=63dLzEuV=?*%&oy-XZS2fT~4z+1t)1JqE|n>jlUOwbq|SJ z95v!K0V&b!ls(l<2ChUEp%22=SOuz;?1RJ6{j-N%*?I%ZZXhCM#;sXb!+u+a#}0O) zyAlSeoIyaXbFJGp_#W}9v8n;;@FnUD9#D}l5BR5CpBW!CZb$)&Y+WZQBroZ7Y_;#Z zEAWJm`h1B{dbvQ4D)fR6(pYmF@saOkzYWAV!$Q$5_DlwWTd3Hg=c?eMN8B&Gc;O~R zzlDn2M3CUTz)Q7*sw7J&5G79E-Oo87tjF04sLqlms~Pwl&|+Jz zKg;!^E*E16=*gvvG)o?)*80^0*Ga3T=WPcaKDqBf%7C)N1T6x&vb;gdOms1Zxrjnc6Lp$HIeMxTf7q5D- zDsoOK-kuvdwvv%5Ukx~pL;)^yZg-2?FAOobC$zbkdA_!Q+r%gOJ5qu^3x3&dt6N$i zCJgGWAvWNHU7rRJy%!KrmRZ79a_*q}P&B25cU=Bmv0na6DKQM#;t_HOKW~4>r)Cas z4{hDQ$&!@(kkuxbA)GE~7gUJDrGb(Y;_LDz69{}7?1tRs78!jwD!>tCT`1qdm$LSX zdMp#L4(QEBh=|S27w%SGF`Y)fciM`B$|Hxv`v}yZT8k@k-qBUY5>7ZwezNOk6Q#3v zJV-f&?6gmWig*)8Khl!r6o4Q8pgYTDfsMwhBQF(dAv>I3yO%o@08cPc9r-L>&(t zSl2aQp{wkk`8LPa#-9$)v}@FH7`M9Dw`O+rj>DCqs7L-Q;->hbAPWVnC^yM}s5DlN z&{t8Y$x{uh)~FWB=g8bu8}z%39i|TCB~N-_zRO)$x#5YpnC&m}19$shm^O2EcxHLr zAjVsMgcBtCq&)+gj&Z_GfgueCgeGeF7@hi>b%*tX)gj!ZGuU#$`A9ch8@j;wjjI}q z8h$fY&K}c(h;2UO?$-bSMpkE1)0fuqF_?94#Qb@pS%uy*<12b+@9zHBjN{5WQ@2XT zG7b)Q(z}93agtid9L#x8fcBO=Q}Ym(;ZppO{;C zl?oPkyUSFcOk%t)hUGbu)U&Dg{CJuC1OROODaNry<5G%=1JGE2XH1v)b>p!VN8tv5 z)sLT2Kj%}#UULTWg7Mniq6EY_(sjeF|hm{*InP z&Sjlfe}ipxzZji1^+$9TZl-wF*nuGqBU*QnkP`AH@ypbOF_|9k{}FWtK?HlFs-$-G z#ab#rT^LxfI5{&7AF~x z681VN0Ga$Lj7ml@_m>O_cxm?zGa^f({_Nk@6VqpAPJr@)+M@JsVk7~)(2{8UX&whJ zz&|2Bw_D=2DPVP&I(U{(mEA!IUO!v*|c_mF@gp6xl%Eppv;(%`s(|UMalA zzU(rZOx~VQT9}v@k!J}$YVPP1eqH_N)A$o+p^f|lT%u*v zw33~~OF^=n*@}V2%4%gzU6XfblZ$We+kBsbg$43F-~864$BNF)r~>JFvMbZ>Cfr_q z7j|dzlZ3YGA-%-k;V|10em`Iqe5oj)fUk>ig6_8CnDafKxX zQ7gRiN#*Clzqg-xpZ97?Jqaev+mXM%D7`SNBzsP%VMA9=)csM7ZyjnVaWi#6@}dInKp@ zFf*xDt$}~<{(yei_{!mp^vmX&%+_zi_KFJol(6p;N0TOJ?aEIpNGT*1_7+sm1d~|& zO9Q<IRy)*Q1V^i#l&fZFhNS?3En@)U`SB!xdtJ=$^a!krs$ z{d!l0ZYX+Q3}3OU0FP~^_xJh_n|L`8??`p-*%jIqzjA@(`$1>Wo``vd zR*q#@-c#MmX?)pwWzdUTsNVo_My`N$7^3)QS|vG!dW#L?+i?$3{Cb!TgMR?E;AYjZ zR)ur(oxiB!R;gV%x%6{sU2)08Xjp-ub#!nvi}OQ8H@`HZWnm0Bhfh+FxzYae#cF6 z{o_^bdJMxcZ`8ciC&QQ7lk69O^Q3dh?LE-GMCv`s1rrqZ6q}2NS?dIkM?*Tk)Z~4B z|F-40m3t47#rG? z^k>(P_0>1)jg5{?qQ-)T#6NMrecKtr=Z;IJ3yR&!l?fd>Wk*8e^1;3GRrr~q1Jjx5 zA7);OofBq>ybx9Ga}cvp+smFl)Y7dR4wI*W)K;$i9@Do^TNnPPrhPu21#)n}hZtl2 z^Zsl=Q%HSVdJDUe1IyU^Eb~ZDz5Y&^y6i( zTgbDZPV_{{O)|KT+kBvo)@bhhGJxU^Ko6x=SLByPSKKO_mA=$|wL;47kvuoA0L21B z5$Ex3s6cbI^0Hw)bkw#(Vqgimn+4Z66xK?SO16lKX{`Eju`27&)J9&vO|jgoWY)yo z<@tLTyp0(m(Ls*Dr_keAtn=CEuUXqG)|X{xY`2p#T5E-$)_(d}wZ7SLG)!s5lwFEg&!Yc%gAfs9=v8^;E?UvydKcY266T`|Z%&sr;<1zzeE9Ur)G zZaH{m^s49SMLv5VDVz)K9e+w2p7-vjW=RybhMbzp z_>ZVp=&5uPUCUD%4`I3X74D?y*E250EQ71)A6tTcXZ}FdI@1@sO`72}>a*$OV6V z(yfM@JOxym^slV*L6zEP5MlXIpaXgMKKViYSa)K0PURs>cz> zI+uk`eegHZ+kMnulRtKTJ>7hg{|<`{*zDUv0GLgpMgdC;LiIZQ#PlnkjlOQzw7Lxi z$q+~f0uw;zZy%o4H*x3+TW(rSy604fT48XNED=AKPcm|$+p!HW2l*n){8p0n6kQG{&!OSsy>Y;r`q` z5UY!Hga`h0JE$KRzSaJ^_rj=teH*{=dI{MoYspqOI|zAs`#rf}bX zy!`jjq%!oEZ2Xfhc#q>eDN~$ z^{&q&jX}&1sM_&?oF4R5)JU}i)BpT0fGe^q%9`%llScP8Zcn}o!7f}aXClQY_`VI_a z57c!P_5wH|Hg5;laQh|aO173JWe2*-)Qw{Y+M(@HBP;kn6j4f^{ISeeDiY<3tx~A? zC;Qa+zCm#4^A zZ1`0GnhvX3Z+?J&(Cv-dmVLx5P}z>B7l$6Cgc8J?m%d5iqC_Bec! z(-r5*_^rrW2wz~fVKT7DwK(oU!p>M!OiI)|&jf_n$^%>A(?G8cA-Y0MiTEc6AsAJU zftt}1a2?3omQLwj?rAsDuAv?iUW2(#j9jDJI(G{_ zkLB@Gw50D$=l!8X-eX-0yvL!z35W3ogd2Yt_G=Rrmz6(lzQm_Kdt!>G{!E-3wt_I( zRI2Ef>ZBz~taS8>@y#;qlY~Yr#RLEJ}Zd4E6hu5fWFJ4Y3h*~UnYL^ zKZ;#w43H?5gGg`hgTi2a zfR3z+()!x=fUlTij7jKYfypuN0{?R(I!wcD)axlbhVG2_u(pXdnXkEA2ruv&wESiI z41n5qwA~szV!*qfj!&9HTzo%eyYohQ=eT-kM_*`@8fLklSskkeRic+)!w73b5t1z9)nPhsmzFRgR z7?zEH6KyxtnKO(tOiO{MfO9o%Tz{%{B)A{cS#Ev-p`|g|)%rX)IDC@YLL6@)!#k>|u4*JeG8G8|Wlz zGUGIFj!?zD%-^HNLat*QaU|?t%zVgiVW&x9r9ltvydW11 zaM=;wUQxPjo_kUxIJzOCJ(%I@fSh4yRjB^?Kg|Avt;*)Cj??|wl&RuaD;Itn@KDhy zijaL)A@mm0pzW;bi1_z-!{CcCf8H5&wq-dm0JPt>+7PJA0xYvH@=bFOK-z0FI3EV9 zS_$pAu}4CJY(#LIUBy^4er(u@vR$*&q0E1o`*!p+Q>Hkc8ZpLT@k|PbcHg6ZL@$PY zGEA&=;QL9r`cJxZ%6ttGoQh>4#6V|oD%fAUjXgjM6qP1QkrH}`yyw36d)E8EcYW)uWRjW5WajLB_Wtd1_Ay+kI|s7q z`!$N&*LHS_uc511ow|zgXcv|5C|Ho&uV6>Xf|j$yW2&fAT(bkN7bzqcHRSpI@E0X8xcn6MY@NE6&uYbLH9AKVtqY zX-X&UbspyB+Hb;N#ZIL!mjfGGw)`Fb<5{Y8%7C16rQPdGIz1>=C znnCpH(6r1J2MCHDs)4tnapOjH4>wm)TeMG?^yc>QZI< zfEm^Fv3S_;m*tOI^N_prILxWFTd^ib@@>SAppxCSRjqmAsYnGG!{4+B>T`ea`5sP+ z6Gj`5o9*4Kk)Gifn9o<&NgZlUD*|fInzZp*-QErG?P7z7s{55EH7r3UYm8m)+x1tU zHx^VquXDgpbqk*KalxFK(%u76MZ>lR7TRidrgwDjTr&<`-k4EtTG_p2JZi(O#czP# zTG!SldWUsW{;+UVJBSO)GynWGI7ldUO3#wP)9q$U@0IC)MORjseBtL<7Ms@4d&IGA zPU1dlVnoAIvn7!OexY>Lssfk%R~2P4-g;)Qd*+rnC5jO@GX3mNjy0L%Hukwz(&}E` zvz)Fi>Rd=(S8|Fjs9-W$98claiwDmgb7)AeF1TZH^sA%n zKuyn%`P4v74{ZnU%nYGU;1!~jR=f`SyCMI3TH2?lvERPvGk+JGv<)D~%NN3hHGK-V zW)I3X6n--#bX;pMsrsF#OlgSS94ASqeoJeM8#Y(o|J5r~nY5uj-8vgYi}9`8JF={PQ%2*stZbvo}Yx;Wohrl0Q zT3y+l(Ar;@KJE;A{p50JY4ks7y2^6dL-bU8-k*Q6re=7iuStKKF)GbG)ir+TyQsH^ z<4$J#R{d_9*w(WSu899NE^}7`{iRz>$J*PljfEKMIX|J#4L$&em(5V_}ulaH##--7t6S!p*f!t9w+?D@+j#d ztCP*FJ6a0z>(dP{wmsVZa8k5i@jy5pd)sTkq)U@F*gX2PC+S|&>mTl!37=l3tgGE5 zXh!ZFvrwaLjw`#Ik^TBgh)q;XUhKfESsha+PTw~Dc((&t^B%he*1zy9aKl9MFt&tP zTy6ek;uE)fF9SZkEd3E7^qzj$ahK!45hm5L*B2f^f#pxe#+Vc}@-t?Zt>`uMYP&^t zRx+EmBs04>*EkS=&V8m!v4oB#hHfph(G)zwc&>u~jb?kNgeTgk2IMn_p!Q#cm|vxw zMBHeD>rd6Muiw&~giYus4CVSsx^!9w>sHarJNi~9S4?TVf!SJXXI|X=d&j5g`?PyH zAG8gEN3Hp^echg$+ivWaZN7e}*ZRpvqkiuT@(cHWY@Ocj+;5xF*#*4JcN(216d1$Q zuRJ1OOZOh1vG=@l=^=OLQ^$Pza z0cT-DO%m(gzxuHJ)8HBZz1QfhS-bLgulJ(Q%*S2Gy#Mdqe~m++N!T@DPi{id2Yb) zVexa)#wP7cEO7jH|H^6QZ}xv{jV*PD(}|)_W2+OTF7Z z-7#57#^$FyXt>_Xu2_uy>({%tWdl2Z+dy{clEiv>%Lp) z2`?wNDA#OPt?LliB$rl~n=YoVSG+?@|8ZC`{?F)T6DDdWxRtmLaeL=F(AC0amq-2s zZ~xrzmWHB%&VwcmQS@`y496FAhX&p4zo>sxKgq8?Zf&lx>p2%o7hjh$mv+}i*9&fU zE~kaK1z)>$Df3~M${x3R_UxYD=9sN+wXTkC6Wl(!MY?epyxd;79de@rC+8+q9S#k1>+06mZHlYX6>&AyLmug_ zCtT;dopRG%sCS!ufxmF#f-QJI>t=Op_5B)ux1etClxRN;8Tw4Y}dW6yz9z~OJn3Yo8Ai-9=lz3D|AhCJ?UEN8sd7hX#KD| zT_^TW>si~^p-*VvH6N>82fKN@9&)X5+2T6awZt{lwawMZwXf^+e+sjX!ZRv6{5o7; zxQgATx{h-F>yqKK;isY7q6v$K_n1cxhze!#Cz1$)mNWgzj$MVdric| z;<4S&t*~BHxh!^R>akG1{O^eQ;QZYtEBU~e^7zq-l?loutK_`od*w4U=hZtKeX{1KwfybI{d?{O zr}RqwH}`b=tf^l|W(}15yZ^tp-PSr)_s-7AS=8pZ^?x2QI$v#V`<|EYP~epZ6~@=* z9{l(CJZ9_9T_uCEJBfey{P(u!hRzZyKS=yP_x|s18nd)q^Gegwr=@Kb4h31-|9#x( z%um{?to*+c@xP8)NeBFn_?uSZP@TW%f1W$3eR|2LKWf9&?C2ie6&PMM$}wx@_ih(cqG%g>(rT%o1)?)UWNCL+WYLw%kL51 z%RG*J*>_^E=0N!FW9v%toS!TSP77lmOC}EAyGOeE>GKf7lV4BzKE3{E%@g<6BNzAF zA>U%TW&hSI8xL<=zV7taZ)>m5J@s<--J1bx0@mIe6R^x*6d2)`7;wg~EqUP|=Zw^# z^jkOY@3?9#TDBo>@xYB7(<@+>*I%C>dd2N>ce4QJ8y?iY?b3O7R?J@5zHrvEQ##|- zDL4NKEbG00e&nK)L)#4|`Y?C18%y0qH?nTXZ}hzpc>U@1ulZhU) zJ;L38xF2-C2E2_73g?LDV>_Vvhe@9BQp{ZRYm3Ae`-kBc4iaZJJJPou*|-yah<%50n( z*^zLxq_1h(n7-qCkNG-z>In5r@%LWtu{ZX(|8igE>EhX4&*~rR+dZ#)+IgP$T;_Se z)5|k3s%i1D5%%*RkDW8ianjrw?$g$c-0rnXzg_R;`H$xxkCPt$9uL7Uf9Z#LX>LCB zI_t9oKfBC0dF7H1^{e!>{;l3w|4bhVwlc2*uR8C$76TSvS`@XY+oJeI z>lb<~(l7k7@Kk1@e!o|zzR+vQ%`V;!-l5)~ZvDD7>CRIh^6o3|1C9H)3kwge4_#ik z_T9>jYZF)7IeA+DPCnr8{ovGn{ewdf@F2@aPLGX2=bny!+Bc^6kF)W8Lzf4S3|Sg7 zK4itSm}i$m`LKvEKKw$sQ@Cm5$#5vDGIEeS?Xbhaf_-NXpQV0=50AEqa*0lQc|014 zo){hddPg+%ru}vP+X-)-VqU$O^!Cu3?6kUw@smFv{e0*1z%ShsViGSU zE=k;-*pWyi;)$OVMkU54C=&a9>6I`m{#tUk_Tx+c-!;b}rhk|=R- z>Yb$Zsc(}?lHsJONlTKA$k}d|R4cn07jSdb)FZXxi%Z>uFJG%CzIDc#1ZqOG>xYjla^n z>;tmr|Fx;&uBlMk;#7I+!L-WM`1AqkzUiyeg>;X!XQ}5?kEZTUyOk!-7?9DH@e&+) zm9{fo4z9f@?Q~jW>f^Luskv$8sinEIj5QX62B-H|QPQQP3yFb=TM`!}IV5t4lM>!1)PA{`(DcPB;oKKIq3+B3 z1YH83ur+>4{Oh>sahpG7f9eq@e0GeR5EmaiE;i%Ck&jIuE`A*I@z%$%563=yd*A&2 z*!$k^l^?kzt8B-TF6}$%eFB9BSI+q29ewomqG-+Q`_bKBzlpYgy*0W^H1}%aOZ0`` zi`J;HDF5f0DATB&Q3cN%pYMC#CCd4E*XMN+MC zh4EtAs<4)j(;@$aya<^RGA!hM@SG6$U^aNulWR|)$4x=&f~tbL2Dt@Y4=NAp6O66YzIHxyeN23A_$>AD@R{th(8v4Mq+9oI`rLft)$Dc5tHNutSB&qf z2g=ZOkrvP8&o(_=cKg2f2=COJV{ZQA^-BL+KT#i`FY&DM+~e6-pX<3mzg3^0ukf6& z|KRDZ-=_blx7J(f7kip{PW4#h(a$5+L+t76`OdT0Gs~0HH+s&~`|Bh0G5Q61KhJBP zex5C!c6vdd;+gNM(r?zMdVcY=)xQB(c?_;IT(8#8(ervtKg08>-tOVVH_{C2qUb-t z-@Rj1AqRYF^-=n{`Z0Q?*Ich}UN5}{dJWSr)~~!56ukerKI&@dsRvtcE!D5q|I}N1 zjrCgKb(;lui@1$6lB z6Xj#;+j%=7kbIgH)*7A{b~m_3(DVDI{f9(QmH2 zJo-F1{Bl_8Gt-d6j}sq81keFH0?Zy1KeT+}7`*eDUFd_bHQ|*Jmd`6+y1WVdU>3LM z^WfO)Z#O^JJsbXH{bT3H2ZCdtg@#{R6O7PV#q7qt4%K} zB2B~Jg&cco9klY{n}G56v+q5-KRWPqkRs$~MAFNXZ*IKV6I~PK6KNBX6jA)V;8ob$ zz8_=b?teKCMy2QHwvWa){a#E98y1W__J4#vY7ROR93Srb((ZkJ{Dt(NIR^_Of7g~I zmgbax{L@kR_h(Ah#B|4`eQ{>*M@8>?zBtV0*^=P(!QR0aLR_8|g>^=*d3EaT^pEf3 z4u9F1*gGL6F7RFEOYV7(FmYI8=*4j6`HWX1->!_!PjJi-eqRweme;d9q%p+76UJ#*qaU&XgHzU?OVQ^~YH|j^1!d}HSWx-`Vi=XBl z$qY@t9Dgmg{)5;1+d%Foyr}Kixiae)h8*^82XoA9I>=+H)rV*!goq-i7@01yn(we2d(+@6)n(X0H2M zojyKodFqAaKZzw@j>JEWEB!S3)Avs`aTmWtCM`|N`6|kB${kuX@oz%y)V2%ax3YTa z6qDVcT1IirnCef}BWj!K%IkjCe65&UT%VVb&3?^H6VmRacljpG$^02xFt5n&PuuSU zMdu5cyr3WY@9jBHzn}lnHMcZxTA|%<`_fP4QB}c)X@)zMV=FHG{ahxL{U|LfK}szC zSQc$5_?X-LeGHg%ke!v7WtJ27y?gH3{9C`;|G4}eVVGa<*F3MiZ>N)`q) zb>X##YFE~-sf(_k(YU4Qd~>&!D=p2RZyX-ASznR6U$%yy;1h6udT!k^Q#N0ch;P!$*j@VzOUU-H@g0N z{gMXzhA;I*{fxRkwc~2mR#zFS4Nt1cT2Xy#Lu1pKmVnj=tzE#(oNmoQO>Iq&nk`zL z+cMfec1-X5)uC^XZGF(Zv~h0z;@S;0Ry83tk+nH>8|s(U->f@RYf%$sP*nL>SeHka z9WMo0-zB?C{mSt2aTNn9oho?{k&h`4D!*TmUNxikOk-*5i_Y_+pW;-pvuKWSU;BoZ z9}R)E>4wHiS>^o7Lsf&TJ!&l)E;L2ADBCW!b+rCyIo7g4JLHMX^z>eLObjo!_RTSMAH+Iw}Bw0~*q0xHA2Yj{{!Q**hx z&~VUj*^p{5tL{<#)j%2Ss+=mDD*9CZtYoXbYp*x>HYc_gwfVFSZVhO5YAOWtK8x#$ z>xc%vX=e-9F6$g)tTA#XAB+~p8yzlfNXxB8m-?34Yc;;rp@!-zw5quxxcuN>hqBS7 zK_zcXj+EXmtNc5$Vov3PD$3wxK&tiCxz(bY(rV}G{?%}GiJ`)fZpbhM8Qcv^3{wrw zRWGU}Rl_UIDn^z2|8@Gi?QhE8W95Doxs^?TpVif>>feTIhLeUU!|CcPHR8I^dgsQ< zCPVY0mZ2>xn#&sV>L1j)SO2V+SlNtN!P0@&TU()u-kQ;vZ78oq|7mAVSN{NCThzx&IVR(MsW zSH&4-R)>H&(K~Bi*I3p1){d^rsdKDzhAHERs#D~DEG0@cD+Rj^g!>Tb1@>en>x zX`0@O%2N%CO5P+tZLfYlG-+=bFN9Q=%x6t_@el^=!3~OV@_vK$J}=FwvnyM z)_biR+LcBp@pV~$P+e%)=z7wX*kn}H|=YRZmMijHE(HdYTn)w)$*n#y5&O4@s|57-CK2StK08)T(`d)ExTGwT76o>+jg~^b)qI5SEKpJ5VaMx^UY$~-jmbF?DT$O`gB-!Uqa=*QBQOSAgk~b!5lbW= z-VDb=&9Y&#Thbm<0yImhwe+jR65LgTiNQG7_^T5!ZZ#q%4@@SB!bF02ig=-Tx!7GC zCq^WCNsQDVdW~dZK13i%Q7PmoGK?5ZxZ(#eTQmiZhQ7-t%4(%mQU_Uq>^bBIuK@EB zmY_}OUrZoIkrSv+Y5_fiZlxws6Uchp1>Dy)WCrpSnTPhlM&aWK6?vFEOInf_iF^1C zEEIVFg-h$i??f#o2TgjJn3+s8Nio?Wnjjt~QA&HrjzbWVg6_xt2vf3>m`E(d2Vxr3 z0+|E9fVM!Rp?=UJ=q6+Vx5FGd8{392BRYsNq%HY|7)HFnb@(2v3f+&Ip%Qce`Wv;y z1BhW%0A0xBvMacqTopToeaJw}5PB}vhy03Dm=f6x4UmOM8>A2v2bZEEBAFaXbIf*T z7^vm2gs!6=Q7+UrY8Q2u@}T^vm(+VIm^wnOr93G!x`O_}xU*JVKQ4=<*FSOojgKT5#5RYxDqQsp2JDdENBuG0__8pO4p&| zu)o-Jd>g(3AB~%XzVC-m#mC_7*d8nq9f#&3@kkXi35`Ux*jjLBm#`h!NbDPW2u(%G z;8)OSS*XMTHF7X69s#f$LC#0O#=8AT!#PQ4&0Qce_Op6E=( z64pS&WQV0WlGT!)lChFN$yBLS7AYGD?SeKyYUqkAUur7dCm|)x;;E8WNtv`$CI<7e z?;@koPv{WL3(LVeu|JqMMq)G2t;k9EA!Lv(k^PYFk;2ko$xcAEI}*7xO6nx5mCc2& zK`)^eXbGGRuR<~qOLQVS3GIohQ36$=z0iTEDVl-IN1nlL(0nLcb{vcqnJie^OL|7~ zQ4EXsh!kMv{9sXp=&1O#N3rEfS-W(bG)bb7Y!`nQ9T0601&T(9phg%^R@t64uo>ctdH}kLMgN#mgdJ{tlm@p%bf_r#R?xh4ej9$o)>{s?4w^k1EhxliFIPc8c@=w8R!spy# zPQiU+!5y-DnMZUg)kuycV+dEmoA^l#1d;CDqz!q7_=L;x`Rp;@%?0gzU2jv7*>$t$W)sbZnEGpD)IXG6g)H76-zlFg zUoU?rU&fD7tP|ptqtv0A25q)(y6F(p5M8?Vv*wLDUDZ>SuFO>qRaL6~s?D{#by22q zW(Uoq%y*c-GV?W^t}|$EtDRMslnFvl;i00d;yFK?XLvE+hxg?tC|IFfcme2@r0P`F zt0GiWRY}UF%0}U#uv(ymV8sB%D}D|y=Lx<)zmJdRO%y#9Qxvll6BHxBvHpsFirxxK z1*NFvbNDnqi*Mnr6!R6A71@gMLZWa=IaUR$Z>yWs?do84FZESbi}HkWkW#K>K|_=^ z!aL!Duvi!+IDt<~l`7R|)j~kCEHx-hqBg1rYK~|kHF=tJ%?*t;sChO_-CKP{y-c%C zJ6l(%d#NkXuGjdhY5)xj_{U%j>{2j-pCBmDD4UgMRejVy)Y~<$HIFpCHLKNoRPM@J z!BaRbTor^tI1Gn)IC*0luLzp#V*BS#Tvy4 zMWEt`LM?0-GK4wGzsi497V3-Y81RHE)yXPz)h^{%VTSMt^k+FA#fR{J_;HF<#Y!Po zC=vpNfx<;aB5#yWl)vM4a~rs`Tq0*DcbD`06Mm@z6YdFwax$RSVx^;U9(bRp9IrG} zmI^n8LBdBspXYpEK2kmljFVg38g4Atn?tzw?0&XCi?gkah_zxjupz7zjQ41+tNgOO zUcQ-!6t@-T!ct+kutFe&ZHgoOX89y;5Ic{_q+@9-<_+V-7O-+o%tf;+*%ro=naA{D zY(Q0}0&qNz&Zk>wJ7zbN$IM_KvIf?gTf|-FesaU)kL9g$ivKCUCZ8df$scjuxZ5lT zB+M(i8OW(JGJ{l6Z>bpiFVo0|a&q}1`9JdSas@w>ci>I=Kk|!mTD}ncri$@m4ugMK z$BbfzGbPW7Sok?BM~;wEm5mt#_VEnbbg6AQ^66h^wMx z=oQRVR?J=DI=P+lR5{Em0excStK?7I(TnLpbUAg63a5N&F}s#?k>BP| zEB+{g6~h!AdbQmSZ}M?`CVyM8Snvg7a3JWL4L}043NgwzstamJvrAK|anSbA z6546ne6547S?jD_uDz%|tHrgxnh*`I9ii>iTn1x&soGU#P+n4U%F)6>Ao)fs)Cw0~ z1uC1{D7p#?r9@?;UZLrub<`GUY&A2~>r{u7iGT{J!Zc-wG6P7M2xYtSfGS*d2~>%u zRF*2SYQ9n}apsp`n#qKNIgGIthSpeWwz4ntl56ELeol}tq#^L z)Sc7K(N$^nS_f^cW{GB;=9EUJjnQ7zL8igFgW7EMD%D1%QDBstl|PjORWntn%1P-d zSP9bwgAlKbSN&8!(L`xrO<#4C>Xd4bDqHzf>7|q@gA}H`gM0vx7M0v&PR)66D4^>L zpp&nIG48^gWonpHYz=E`bWr9d8u6dJ`sg+xGxT;)BW zlSZlRRO^&0g)@q5-VDeQBlnl9dN zs@$XuR?1YXRQFULRQW1Fy%yAx@2NhgN(7R5C8#J5^KD!RH$gs-Z{#N_oD?pKc!epD z=8*C-;4{5St{wu=hrQ~q^18B3`AJo#?xP)~d#n4RyR5U({iDs*^w*qHKTx?ThYD5v zOSuoXksZZ6r6(~(>{|J2xdV{75BOC=itt;pQ4uOMs3vR7fEF**?ANJHFX~8eow=r+ zy7O9Cvr0WiZK2Lo-2wlbqdKDQ3iN-1Dp{DXuu`Nee1-mi`fpUJ>f0I#&>!ElI#WNh zF!Lhw>*oE;UzmlOPSnlRZq=^T*_!q=J+C{bout9lV^m6&Of_9;CTvlZC|ZT{N+;zc zK+#myIkk!A4B(Jong`&Os;$jGJ zzM2NOV}$Cma)e?ow;iC(kxUEiM9-s#GuK#8ZX`f}W{QDAnXo`vrz`{2MSp1eX*EF4 zS?NZbU9<4D>|r_H;=B2D^M$6x>P13|+?4ZX2GJL&^VCIZB*jwCsliM;yG%Zq&)_{2 zmxPO8-GUHx4{e_As@YhJB1_o1oAnT@S__56TXTE!+orv=!Kz%KvybqV+)Pj%T|%Fw z7Eo$x9QhevjuoR*uy2?(9*RrI-&7_O!&UH(%A4x#;CfoKq2^;O%q{&bpIM%;+--T# zlCykg?hdYKqxMre2>bbooSIoljU;aoTLJ2>B~Fpcs1>vWkST}RTU>)&qZlISRJeAd z*$m5IYlE%M{zuo(-Trj5@AllDw)_&Cj zWRq)YYyL-Pp*^GyQ5qBr`7CZPdxGh~^khZ@iQLE(uu0ry`EvfGqCz;S5;U#a>1Jas zr`deza?jqhn|JqbJr?zB?vdBs*!75=r%iz6L$d|i-%6cgwR|>b!QP-%R4ZXe?83{i zNQ}e(;t<)D8b@DZB-|l+65mq@R`yXJ)|}N2)lJY{(w^63sjsU0sb{L1gtH0-znk02 zl#pw153~Szhb%(Y!&{&R*>9N^dJGZB5bPoGjnXsYxHfr&qPOyxDop)b6R$PVxoU$n z$!dlAKH&Qd)q9nhN>Fwxa`>I{3f70YLiFOejF(;5n@Y^PSejbDuz6*B(3ZA&Xys_N*Xpw63UjgP0d0h4 zmd0H3S3OZZKs62^q~8D~zEb$}zvVUZmwXt|52uA=!d+pEa=FS}(@WQCYHzMLpJP7R zEJ|0cu~(l4==mQd1900ul}flRw`VU=TZw3V2eFr&Nxh?2aHAD6fNMhlmfbH%m9$E) z-liRC`rItt+{1#k9BZkx)LT@VTbn~>8+21OrmB6yNuUA00)#eAeu-PhMQ|#4A2}pX z;TpL-`3f-RI{+r-RnL{ZfczdM>=aZ$CdvUmcT_b4&63Vv=K`6PpqH(vHgZ3;2Uv7l znG-ZZ9VVs%+;a^tCWcTw>A&YI= zQCw48Rg71B;N5vf(FVrw7-570=Lg7NbDrD_Zl(M*U#NhULCP>?li;o>kptb!&Evv2 zQ~4#JfqlWeggACF^N{LCUL|q~J;_sDsZR1HnMT~f-7pn4AIrpc;sv-7kHfFw-+)i# zI@ygr#IpQyL9RNeeyo|N-J@NrU7=NK&uOM;JT;Fs1~slOR1H^;Qs=00Rd>_}Gz&C| zs_}weeu3Q&5R5!sxEKb@gD@Dx6PWHVpOEU;q z8Fr?RO{2|{E$&#`ce!IX*nY76NV|tN28;Qou0YOTQPrt`X)|;#Iz;zTyAq&=a`ip6 zMB}8*G5umO!#dbD$^Kc74Sk&Ye;?>P*mm%T0jv5I_T~Ef4X7Q64z?Q14*c3@Lw6V3 z8RmafY1~8dDB2tHmTVI3HNNaP(jMQI*Ou4*uCvnQuee;=3V8#M&s{VbYb3_d!`T7y zql#puzdBY^u6dxgQg-Jzu!YoeVmS62>5bfnd&8|z15^$bK@(vbsY9NjyD%U86xpBI zEsqxTYE;+DtlYfBg0g&Jp|UVDFERb4+o(IGQ<%n^R+@g%?b6&=mhzi9P*H=vLM@|O z$ZO;*@&{o-9KvmZ?H>+&E7wpFzLppdd`U6DPbejxVUFk|;IlEHKEx1O#r6eu%MG?W z(@YHo-p^DriMqsC0sRj$q2-ob6D^`3@&@ov(1Z=}2ymd@K^M}WTF9K`92LD(yv9Sr zYdAHe@>HU#a@7;{O3f6loo=P>wf2%a|^Tl3%f(F#n_Az#CNW0GlG`X=bVg_MG}W!jit>^)``{ghM_OMq0> zkUV{kl>%9~Q@KzzMmK(Ri^AK;;r$`(r}OG~A{WYN%gcsslW-T)tfpTmogRp<$95I!I0@NjHA)`Xg1 z&e&3XDq#VS6SV#!Ytj* zR%y+ZpSkDs80rq-_tUf$cNK8@c4`t>i(#J3PPQM6;%`_uF_Ib$;vEy|9rQNlC##a* zkhgQd>LHJ#C!l26S+KIp396bkD?kD*y;9=@GSA;*w|h>^h0 zeIA>LxuQo9Pk15R0Ix&m;62GDlrOag&}J)$rL4r`f%kA8DPbcN_tZnQOEphaE0leN z+k7doD_64a>``tApQGS~2LS2xVb?KP^j>-#Z2`tn4RwIN%ox~N@&H~bd;?>tQ2W%h z#q6&6SMz%FT^7qNyIR>>HCXtYUDv`Y4WB}tn)k?4!)lK6z=nlw%(z>^Rs^fdMY?;z$;5@r<_t%y@snXb0{WIf2%U~ArGpY22I zWQ(V!qqKQyOkJo{3B~dd_7Dw|o3JE!j!Yy`iK>jRjps}-ac^k|v>EM2q*066m+~S- zobr)6NxR4_&*F>K7i+1_H|y=zXRU5q95Y>@F64ulKg4=e3-yqcn2a~tcJA#^b@c1- z>d{er{9zv#EU@OUo zSSDN`OOUooXi1x>+GLPPyK$6BCAdbOWHmGvHRAiJtISw#zkCD#T2ZL<)f_O@SxmRe zv)*fyZ9Tv$-Mqi)XH67XW6Mo35v*O7#GYlY(%or0dO28eXcdjpt0@mMhgbvT>slfR zcz-tmMCL;dBQFyl@HzNyppEwumx;MV8GavM2|VVDu|w!(ILi{ApQ8835C8B%LA#?=Oiz}AbG)= za=y?-(I7A7>VfCuD;-a@lk>?>gf+1kM6$}zU^EY%gH>TMcm$C|{-C1h#msl+G8@EU z{369RVSv&@xl(yW*sQSP-*FBA>1L8`cpF*+BhX5zPBKZHD!LWj2riD-dgx#cpB&*h0({bHJWp3{K=;LI#h{vMHix*(Y5G&)DgVQ(NJUr0waCE|ESSe zpveg$g9syP@!t43pd;dt{>Wr-%paM67~y_MCgP9o#D?Q#_zYq(F`GC~v;ckKKz1je zl37$&raPO!>Nt|qv&o=;Ux8T80CFwxqkW^S=-1R$@(;ci`v*w8aHIn651WAJ{R2lK zq3AR05&jX(Oq)u#(sCw;{!O1?!r0C7<%*HY2$iQgLA^{pQgsU0Q`flRpz5+W9Yf`V zSeTgji6x;JdIl+hm2eN}kZdN1z$QXcWEeUFv&7fn4cJiZ33>|M2J~GoY#km#Y$lJ9 zV?m7R4-o}8F&=0`7j!H#8%~D;p*v78guq|ndPIS>VQ+z-PEY1jI~h5*SH6~4De@K3 z!VzVIa)@fJ>X2%KYKlq@ytA!>nXp2U$*<>=<=?nttiWVZugOs2F8&h4ovxyT04}jd z-OzS)GIj&A!0m}6WCV4Gc4CxlB=AV?=i0b)@~86Y^4nZ1>&SXAAL(v%0_95SD05&5 z)q|+zHtBqcOfp?kD)EyZmYsvD;j^d#V~Kj=1}O!;!73`2&StuB@8t&+-@rYNQCtBEDG0>hk)(S#%O?7 z*N(5_4=5rPF~I*i2Ut<(_%$FNb5uT+%VRdvP2_oEJU$0|fi6XBkgdpP*dBfZ-Gbsl z)bcaD68VKpMW3T1uq5mlK8etg`2bNMAYx?!G}j!)fw2bOTYGvkwVx~?b`cnH3jcvY zAl7sktkm@jZi2@k$;e|g9Q%St6CUIWiUGdd^UOlFH}Jy(WT7C1Bw?!Zka7X=i(`VV zVifQdX}CmY2^~-NC7xhYPzY&)Wb6=s2<)J4}qDqG^on!rTe!U`1K?{{2s?m=x=5DgPK=dqu zvY_UY(}~`=8spJM_$72+c2n9e@s*sGgh{kgf9Wjnlq=x_AYR`S>xC~OoJb{gfvThC z(~)!oT|=Lt{ivhl1Y$V85=2*HkxqCyTnrt83T4A(kECm)`=rUzd9uGU4`?&EiVyk{ zi^EfiujCVI5{S?h(YbUe?L()~U4f4sV;t$}V21evd^9FUMT zo5A7mS%B6ou_CM!-$zpPLFOZCCBMYKP|OE@wJL>?cb1=Kr_#3Mc>F1P0J#L`LblL! z*<9%?$pY~ekvV8*Mb_dvai-*h^p0#NGy+y5-;mYlN3;P%nTKKfK}?gu?Qu)I18~}P ztTz?{G66;-hu~kpn%WLIL($M!xD`%Bj-g8IHTD?)NsOQ#(hxg|8zUFbxD$&Au|vPZIc5DCYC zC~+OK2NhvYu{~gYmTqJPd5TJ+lBqKkPu(MrlBdaF@(fu@Fa!)@>iyA+NLR!J$%Y@p z&hSil04#?s;5BdxJRNz77!d`Epudqc5E)Jdv0)LA*fY=#s55#7J&bNbm!o^pD1aJW zu?(ybO9nX66SPpQ9$SEa#TODK#6Gf-JV{AtFM0^@#m{Bmg1E>m?jU!9`-gMqe7L(H zqBx(cVYjkBnN>_Jh##K-xauT*7GS<1bO!KdKP1KEE}|5~_`hQ-uog51^+7M9`_Q3i z8FCLf1rSm!$W~Yd#x{yA!h*qCe;&9s@rAewGDBVi8Pq^=^h&yxPGDj|NDv13MQI~XK3~~o66R)-`LA+ zPd1q8!bH$p=_&MZx;JeJVl&~?3aSgG0N(et)G6u~b%*kyHc~QB;ii<>Npv9~LIy0t zA;c^YnLa^85OqXfkT;P-&H=d`1l@-o23kM5Cy+npv>1%4Gt^k{>o}0LGKv(D$wUBg zj@Uss5le~X#A=`+mH|CCju;R2+$I`{6(C}5LG7nrQMHr}y%gA1DPU}2Ogo)KyMoM^ zf#6OL(b2RBNV(~Z9aBz+)4?E;Fr6u2j5Q}ano&yZDjhGB@Ndq2?JK}ZNW9%$;1Un6o!xO;AZ$Tu#5M+ML#?OM|F?clY z2Ru|x_%wVL*f$m@aevGN8-^Z2is2wQ4(^UT03NG(fS1;z8__Fh3+jg*0rEjZULfz1 z`^ml}PmTl6zqDg<#u2_Q4Hw2uh(EaPEG}4ze7z2Ogd+cp8opRv^P^C@~QD zB*jEJSY@dK8xAsYq7fV91$+|Z;W)#)KnBJykU7%@ss_@19FzgMz{9{O9DyDI9);^b zck6+_?+@U50?P+?mw}+jNcbd_B^xQbEd_OFB++70yi$~Ave{&q$taTpCJ`nLCS64< zMIS`-#4K1xCQ<4mTLI+aZ1^h3`}qNPz`cF1^PEn9(lW3Tzk7%;!ny6KD1l-dt2`61F-6D08&XA6m z&XR7Do&h@Kk@UXQRXSgaOCL*SN?^$^ae=r}+$okxq>=`431|i}4{*qRpmA$aHqiLVD)C=Wnh(0EJ>c;+6u z617EJ0anNdc`zNI6(9kKBfy!V@Ojt`jt2OCJhA~CMbCw+iT;eYak;TdKWHP81$S6Ar z1wpxx8r}mkg$^S;`VbumB)Ak<+NQVxdxjmtW?{BiE&2p-T?XK}?|?__;XLRr$j+Jo znL_OVQ`E@1K*s@g+7CCwn~_(D6rGJmpgn*cZ;gB77?2!+z`NWID5N5#K&tE|O2GAJ zV|!3Pq!wsNF&qi)hAg1BGDlg9G+z2q+6;1#8i4NY4xarL{07#895Dx=Bc_1uT6h{P zgYQ5#kgsg43@jxi)5!YE9ArIZ71Arx;Zj;UNa`aU4u1a>nhYnyfjWLh;6Mj{xD>qd~d^$N*_`@vz*a)^OqWYcBQ(!SCt$pOhRNt|S| z^s97&Ob1OF=X{^)&&|oqog%e;Gpyy7bIRG6dV*5bG<}YG4d7NAUddUUY9ZP_> z!x5`P@1vv9D8LKdfaRA7EWhcpIkI(tmM3L9Wh-TUWUbOKpwHT*%VdclzwIud#7sB< zHbtHzD^Lo1j?Kd3aj*t8;qrg!ASdUNr$C!ZW)sti5PUe`#0E@>55s5TBk(5hJP^pt zvH~*Z9^!`VLM8$n8UT-m%b{n$DhPvOp*J8mYzXuk{Ii!-kornSNt(oA;%#C~>>?^R znFZ>g%{S7<;?C^Ow9dbs3gbfKZDXO)%4CU2un8l2Bytj)NwOt-rR~y9fG_i8O|ll5 z1dLG@!a*k4;s4Xob-?#@z3;Q`z277hRjdB7x7OAYBUY&>sz!|ns?pd=P^0#&U8__| zNX$}Ot40xfj~`VtHbo+e+kKf>9=$wT}kiI)~MfX#ZU1@VztQSOmO~j`nX52R{o6=BSLvY|9I=XridPU zxNn@rPCX}Gj1*yFF3-!Cu(IqB9YLGW0yKl1BY%)1$)SZ36zv4;!0)NRf@!1P_cixnD;4}FxUQLWc)!Yq{DPCaZDpAO3 z2^`LJ%DUCv{CG^|O3YSK=aJZedbXM(Bs6zLMG=oVtLq$aYQcBrxue|A+-SF<+r^!V zy`6*ZcKq4IeeEoAnmIY4v+_BG@O_=AF4pr>d_TrEoh7sV>=4_`rm<#>vn%uojsDLv z`?x0xi=5&H-^EjaPU}!BxRTGoN^Z<^;B?5%ER}6xhuK{wnPo3^HF(Nhgag|@XE~};$4l{Q@Rw${yr^COVLI&md4YM zQ1`c!^dujW@}wT=MZPEdVdHEf@%5BEA%vF1|64%M(j4qleBPfdH|iPd!M=5PJN^y- znWyvo;!`nRY!=sH&j6NP4@536F7WZZ3jcS!%W?lhSwGf_HDm=@1bdA-?lbfpvJJ89 z4_1gLfIC+5rSRNAya#5gH{O}bk73oF;lE+d+VTj#0p}M#rHg4#jQCSJmL9-(+OcJ@ zN+muRrw=z3_o1|7fsH4-b-leko$vE&iP5Wq9y+kS8I$r zZ%N)I1#styb!*V}#ek_~KQ@*8PRAJcKDWFEk`;@%GN zEqpPbfqNds`|;0s1KL;O2qpq~3=peoo^TiTyavvb`6P}Fq7{v=iA>`x* zcnSU??~JN$pN|$LoMX<{u5kxLUtIDY0u@>#b8|D45jqlT6IzN2(?8)&jl@#CZwqVB zd^(<5G7(kTc}aaT8!NR7a4Mipfot`62I^PWJM-L@-f`q;wtKC?tLxk)ZYo~GUEy|c z`iZ`L7+Xd)nSpzVAuUL4l84;4XKkkam|P{(Xf1XEb>36>LC!@Ra6nri-a&VW_slCF zDhO@5%IgANC0;sejC;D;+2ACA-713H3c>%g#3Av$NDy(*C_iDox;s0ZwDr>+u@DgHy z$m7g)O1hie_q>f>@zBOlUBsnT!V{p03x}scXBP)8~!6uOasH>*bUl} z?k5e&Gd#WPd;6uWX#Y01OddPZI+%yzG>wh~f?eUQMG7#ajI-4lk4))T&`eFkV!{fe z8oOSor`O9J>Z}ld@enW18qiwgBRkVHHcd=xQ`H##NWa#N%|Wxo9wT+wRXzf>+UefE zJ4HvZs>_FRgyq69Vf~@!PKW;z78P3LGG{a|#WKkSyUBFc59GpNtKZw-?sp8z;k1c9 zYLmL8%Icf?iHRnMX#yu;fLo|g|J6XoREaW9 z4w5@$O%;YNvP^rLF5}glZ`~!{@=!|HQk;QsF(NzS1tQ=X5x2t+g|!H!xosRr9AlGd zRdT}g)>Tw3IWoBIcf<+6H?m8k*Q8yL9>mI9a+HeJ@0*IY2)RKf(RbMrcAjluAF@?6 zH=P7LOSL7?f6`gERik7^@Ix>mm>1j#+Q`4CRX#ecvIGgE+yx!u$4>`ouFpOKZ26ME&m_CTaXiD*rpU4ET?N$d>e%)WE;NMSZiaxhAQ{P^;jetcH$q>?r zT(R%kR%VsXp%_uPNW4nh8r|GmIJI%K7MIssq zR0|9-8h&)&8R%RTQShKt-jVME+C zs;NGVQ@vA2K6E!dVm?10COPfgo9=Vuf#$lM&P#ESwm_lnODX>@m!u^-SDQ9)jG4zxw~t9p3J@K3{c zgj?i)%7woQYY{##ye0O(KSBm+VrZq81>d@XXeHk1C00VUD6E$>SSFeLObVm(YZ0wR z(}_nD=q=idHROd5J)9Sn9O?Ye9SywyJoHOwGtMI!<^6()I2JrPz{%zQ;Ld@vdnqc5 z!|>Mvd?O;%3#>EW&Cm0-;NV&O9B(1+fH&e{bqlp0?G5wBfEA+2lMuZO z5Clpso$mxnU&B=rSQN|0!dMmdCHn=+vmS2)y)utSU=^$sn?wltf+*jD%_|u32qj>@7QlyhkNn#BQ-n)`VZ?9l+MH@a%iw zvXXofJB#e@G<3DzG-q^{idC6%oUAURC%^zagyHM;8JiXC?WHzH>$WkqaLY5 zAYo~s+9LHpWvai`d_B$FGcC*|J(b%wra;?YC5TK7>KWevFt%n{*l&Mxc! z>A&)q_(S|GzhQ97uj}9U*GQ^gsNO);Rr*KWTeXv&<#~Me@4?96P4K?#8;tgc`td<= zSxTk^Uj$=mBN`{1@TA2fEev zFZnOf8+pdB9K-}=gJwYl?k`n6Q`lzJPt*aGtUgn#wv1;8|( zY$V?Vvw~eg0!B6yR(TK8N>uT< zuXM~?teyg@m|#@0UY^%YKqS!jJbS`p5m3eg^FM5c7CE=pe7jNos%|V2asJ_LG14)c%Cd z$xOPK73V{dC0ogd@SE^~ymTmufM@+-e%2}KqO31h2EL!*H}x0#rEsM_vV^*$*6P-V z+jI6QcFl|N>wJKC+u4hZVqf4>H)L6gp_eL4Wb(DFB2BYhO>KP#^R(ZO^wY9av(vKk z_%r=t!Gquztd6ld*<7|+=S)}=2Iu^b`Cfr^5bL6=)O8itr{7_j4mM^O#%%(>yL!;XwbPGP9X;4KkL z8rpz@&B`eRI^zH|oq^Rf#~!eiV6{Q?CGCLxLRqldbN;o+@0@fdx=~)H*Ecjh z)C*i&GW5(F?47_08RjI3`FuK?PgBThthZw3cX+0PM@&~q>NK=i5#0*t*H5?BRdl%i zOD$7_R6Es1HB(hp0hJ-o%H8<70W3Tqx8vty_&yC zz1Vzc|F-RstCA$1UZ&ld%lGnFSMK$}#0A0F{L zi{k4s7iC0KcDN z8X({IH&8epPwXfx4+g2h=%7My$p6OgifE%35a*#^A^0p99P9{Q1Vv;MIYqvfU#Vj% zhpvHpyrD*__tjmwKz;y}z8~BIW9`Q4c#suD%e}IPDgeam3q83V5%n?Bo0dR~aUDI} z3y@Jcf-&av@*sZRh26=z?py95llUNLEf(W8M@_Sv`L^cXpqFSsjtBt%y zHAJ3ez`!wxB%5QMR<< F{Xf^UyWs!; literal 0 HcmV?d00001 diff --git a/od-win32/resources/drive_spin.wav b/od-win32/resources/drive_spin.wav new file mode 100755 index 0000000000000000000000000000000000000000..184524f8d7c22b92fac08edf0aff5353314054a7 GIT binary patch literal 20180 zcmX7Q1(*~^*L793&dl!O?h-t>yE_DTcXxM};1(>n1PJc#?ykWtLDyzltLi`R_doj( zAh1JsSJl18Za1k@v*yi)gtV;EqDGJY!?GqNgiw4{-$}@4c5Qk_L9O_kBgc4ez_O_{Ey*S{Fo%%$dC zzrU$RHN@d%baP2`AtTb_zHN zb~?L))x~;d?XYvXyS-)nh%8DsGp;;V|I`dUMxU?OHQpPg&9KqKIIhpt4y)tT2I^Vm zHQPz6kd-3NzvZ>{rg@q_!2jF-4`18-?tUHrfZv82Vy8$UCrX{HBz369{$)Y6pVmd+ zqLN2H@@{ZMH3+Oj;oZKW=h($Wkj4YNlQj#fYST2%Wtn}016Vvl_BA1kM zGU-ho$X{ew)RL||Kpe83L}Xq$N8}NS{2BksTZ(Jqi#RFw{SrWU9EtyWZzDi%}O z1F}jM6Zd_~Tj34%s(8}<>ArL`dmFqVerw)Zl$Jl`2GWC;WmNe~si(eD%WCtr1KKhz zpruwlmYc=Vv@C{Ipt(sNY4HvIbT8gbaGQJ5`{KuPMH(bRZqt+Ort(s4td}$k1UH7t zMRkmlp<1Cog6jj_%yarf^(V_rJIVR{FHbn{?3wmD`|O(}sW;n8 z>zC#`MG+FA`;}j{;rc>jlG!$31=<8V2Qvo;2l|;8^!@59mXV&5mBk-^Y442F-cDwH z3qMV4nm9FaeK@^!((dR=Z#Ew(4u}QOZ-#* z6YQFneyq308{}DTZFjlz(JpJBwH{li?doo+yx>8{PyYa7#zp+*5? zzkX6%q~1}MDhrjtN-jKYrleFP<1C}nNjapXRy(N6)kErF^(W42J>?_ok2P;e7m^Kf zhe(feK2j8y&*VswgFd2NSv59-mL#?)C=T-Zd=|gXQ;J^VAimOwMtqqc@mhH2-6ifH z?ov06JJ(6)ly|y0VJF)A?3LnWcvU~Oe9EuL0^|od!P0Bj^u~c4!HL1!!Sul_fn#Qz zvBKzOtkpB?ZL~OL4&$geZ~0-IqCMU+ud`R(`^ybGvz+(#Hap<_}7+3n-uGYPxn2gD~$=$c3) zi>x>HEvLC#&+YDhcaM3DPZG&V7kZRg$~$$ImPQ|?f6_}BV~k;jZdA~7YloG8X{^j6 zF8jhe=^gO~dSBcr?ilx!Ti46zXW)W=6-VSW(vkk4ujoeliN0pK`dH1VHPqT^rL+^O zrZ!VHut~HDStN(xe5Mxb{65|Vcayutz3Arku6e)uEB)O39`A)3wpu#GV!5>s7H)=qz*pVx=!>Gf+`OYM-_ zR;_@q)arfZoN`H7resoTvLW;o=}JbDbEr=DNfmNOo|pOXtHJafT}N}$)})fGAd>OZ z-ZJ-_^TNsL&T!-0i5^4U%@DtQ^ancj6T4bH?NKO^7D2Z$$f6Md^_`dC9?=U3D( zs3(=~N)P2X)X9UaG22Uzl4bI}C@+GdkoZ@qB$|Gs9oT;MA1klCP>!i*wStCcTEWp# z`J#(O`%%53hK9NY{|J0HE18Xqj{2WkSbe87V0*}R`BZG?v0e@Lt-aam6j>G?6ONAL zwI17V+zLFO%tI!V?6fu8sPs{fV%6W{ge6mVDyx(}%5L_Ej-m~zMJ)MQ*m$xf{SWRi zr;9z!+8#L)E);GQ{vJLT`C(0V+IUfX8LD#+dYqZ+5G}J2G1mlJghq$l;F-X4EDFm~-2%YW*D<8t$C=#I$JdFG zsg+SZkAI*twiNZaKd{DoHl+p0DJWQ1P=#Aw9xaNO`ZcQ5&n@ zm121IZE0UJQXWFz%Ff54I>vcFaQ^yxrnkZ^;~vCazp?6C<*g?8>@8M5yR%c({p_~E zY0BlB{#vh_x6@ndANjv)E<(P@w_-29<5%&&d*4wZHu(lB)H8pbx7pcjm5mGv_Y7O% z8Ie@@vv^Pc% z-}wPPfG^?Q_&2|wf5pq_4R&qkDG*K#_mTU>E6KB?XKn$8n&wya^Z51sk^Vlv8P6-u zp-1--A9*D{z(3}7L{FURW?n>VzEIp5t6_pLo^%X#Y2_k=w*s zY_~(V{M+%|`F<%;M~;`@#ZR7>@9>-QE zEg~Q$@-Vv3ew?M1b`$%MJ;@o5{$JeB!T;k`M0e2}xOKf~AqSGVv<3UbnxQ`IV;ku} zQeQ^+Kwm?bUS)T-`bRQH7DXmo!KB9Pq(u=8Ql}! zNxoc0h|1=&8*CsGG{hqG7;8hn$s)9Y*en>&?&tIe`>p+5ytF7ON08$5C-vD6)&_g} zgE~oDphauC_CxKj{;DoiOywK9$=>5nM*@fa$_|qpat*KO5AvS7Bi(B5NvDi+(tc~D zwT?#$SYz$M?h5~=7)plI!?Yb;4b;9v&I6ttD+kF~@tUvq%X{CQ4|ZL$IGFe8%O;JEzkmE=O`X~JYv?u6pnw*XS3cV`F$#OECjFLh5t86NF15pxhluQs8#aFEGNV!Wsm$r;Y zKbuN)nvdQFcd9Gvh#P)B&u~XO)t#bF73Yvs&+YBLb&5GhvA=rTJM5B<=H~RK`ALN> zv$B%vM=hz5&WsMc4&)C$4>Sy%H#?d=&C_P*K$_rzVE)j8(Am)CP^Hk(V7)-R(LyI$ zF`((8=(k&ylWZT|ORnLW#K>B58W3f9JiqQ@3BT;;_m6nJylVI&UPpJjbIg8XRkqwn zjP<9r+@9z(bklebz0&>+zYy;#{+8Ftbozj}y_($)rPttelSM@jg0llE!Uz@1bRrb?tFKL`1e)@9lc-AO2sw1}`F3c&+_3-cxipiQc||yqA5*3+(hlbSE32W;QYf ziUyU?mSCm82V;@`LHkD=r%lqD>dlQ(=2ml#Io}*=mNmPYx6I;!sK71bH@yxRN?x#) z3|bv+y|!9wg|m7U=6=xb5KqB2J14ZRQCFcXd3MsSVR1`awCOJX4M<4S=p2u<9%oTS=GD z!nlhStRgGQO0czb8`+0*_zJvW34iL(^_Tib{ro(u=pz@9hIBt&Ny}kBO#}iQM;2j? zu98i}m5JgzYD_0T(c|7(Px11*hn-hWYxM7JUVXosU%+eWoV2L*ZzP$u&9dxy=srXJ zlfZv{`E-5(eJ&f>L$@=Z6;Mhl&sa2TOjFPyv>L0bM5`;+AL?s$s+v=Em3(SdwIO&< zc{NcPuS6*;STeSV#?XC0r9-fH8jwD~pFQ|ubmA{!hg?PqLJmnrvdeM*hfs8IA}Xij ztgn(a-c}zN}k0YcuYI8QtV&w=rcUPtNTT~VW{Y) zx6i%f1W`jv@G+tna7}J9TXd4Cd0nrn+t#UKKey-G|JjQB!!6}k6N6+6(vdVJk7)vZ zB=&gG-dlgX$nUSP=i1}F@BS0_m|e&FNhT{x={VV%q*NlxFRVWqjJ|Y_RF=zmG#|r% z7i&ln)EcUKG#z`arZc{38(CM%luK$r9YKf7`(V$xMGx^#cEDOQ@?H2cOesrAra(7p zMb^`;^!fk#qA0`rdS9J!;PS#v#?zAXtbwwIj+PET;=gu3+Lx@ZSiPBvZQ_&0y^U=X zmm&T{LbSEeD=$^LlpbVVa7GsZ$3IX9=|hZB#tD6=R!%*@E<-C>&orFy!(g7L)#Ta% zr8Vs(TZ$X}pksq#Q*4k|)J>oZ26xDSNFv(UO~`1M|$&`cSn3yGWLi zM%0GjR)MA=&qPx`*Zb%=_EG1YS5{;swdh*4 zPNLS|Xk^YdreB%D_=13B2Wn^TyU80_tEAd_8ACXc{Z9ly%NB?A>nMD(& z1d3VA2Z~Q3iIk$P_~}1&(>jIil6DrSwpUSHCa-Be_LL=2lW2{!^Xg~i6zW?AHiH$x z{oMlVnJdSWVss8xVL6S^zgR#S!nTr+q6XjX{pW14vWGv$pNymNALExK>`1trFf5To z_E<~oz4m%rcP64+Z4h^)iE5XNNJ7|nbcKDjj}@7$@;NE z>@Kb|p0p-iWkbH%O=rIeuS|TI&?2E$Lgs`E@mu4w#8;0i5ZmqNvY)SGHToSZfdZT zInHvsnf=l}?@V?Jd#Amm=-GAr-@wz>dj-8R-b?R*pNVJS{W<4*MNJ^3N~9Th@O@bt z$ZspTAs>sX;0(F>9q))+2&(Wu?su;pZzr;d4B(M}d-=UC?rvwL^DDZ-Z_wiYbteNC zA3`UX#ci=!&O$xDDgNdC{ey0A=ZPKTe027MPf#zL*V}vS4e(VyoImEp#T_wD<|ogg z3ol|jlyz!zZG|>b`&E0Z4pU>5j>;D{h-GKb=q|8zLF$sWa;)gh9dD_7$XNrNo7uCx z0M8@diNdmwOe#HbOsp00Vk%a*6V&NN=%=Mgf_y70lb_@dszAjZ&nB=wtPz{d(m-)o zrgqSB>sRzkdMZ7nRZ_1(EkCDxRN`?euR_HsKrV_lyr{q3+wCQSXN~pO`Q5;HOM8x6 z(#z&A=lSJ7qzfydEK+7DNtJ=jU{P!v+oJ4Jdua8vlIlXX5juM#UeABzy#l72>woek z*kKt|Rz;X{G)cj3D5ta&Mz28LAP-Cm1OqM1l4d&diTQV+WH3XpPaw)ntv^(5(^k*} zyUIRtsH_51`AlpOeZ?r~C}-q%Qk%5}OMk39REhy5v{rkmg|vD4UZbix%sga%H8+~o z%^35Pk-;df-_a&$Th(&PaXOCdhXR#CW|n1TdO2E5;Pd^nUP^C|`_4V-Nx!;SC>N56 zv?QCw=3!^wQ1WQ^(IG1b+65BKmgY+1jGk4edJ%n)UL1I4pK2&)$wDCQquy6{gnQjR z?hW>v`>q$~rNBNM>DT0^L_6}6&Q^M9KXu0#Z(cA{295`U!KVQ=(A+f52vq6`T3PiT zo5Y@x(c~aY0kyq72}&Xk`&EHU;=N>iEA~z+(wYY8bs(pOvb&riSI7>e42@=8l{n>_ z@*OKuOd-kwRF7x0G(AmpGFEK&Rqwtt$?1 zbEN|-L!Zd1VxQj^>+sn<=>6?q=a)n>c|(*Gv!GUu=dXBsksxNt!?H2DuK=pMDx=A8 z@|tX>W0?-@RR-vAfwE2Mg-SG;mLi>HcJPmb;OzTFF<_>v@|=7vtHHhL1uR&Lo`5#7 zOHycN@7XD}m|g)__6}akapfg_k2>kmtx9jLhhA4VG>6$_G_Ho=tmh}2fgbykjAVp- zDK?4!#8SDIT%g_9Fd);MEEjOhM)bVXN=kLH(w;@gIOy@spkxRhkTKwzC+IVFR=KRC zR~EA#Y&iQHSp0W&p;laf1|Gc82pEnQQ6H%zwXS+0W4)1Rc*Ydtwyr}BET(N!$Eyiy zIsLS;#k^y-H@_N(jctZBUYIuni-ILWFG3ZgUWQHwmk0Kn+sxE~d4bk}RAvRenOcmM zC#Qtqr}=$e4;sdCc^i1Lv+M@$o(t;67SRmK>~UHK9?TeeoLrP6WIpiOezGcQMOU-+ zN;N3Rd6h8DP9Kq!^gGQ0{4`D7qW-R?Q7b6@p?C^5LM^FhHY0)Mq1#dIq6bIUh%OmT zqPIsa1{-()ZL^mdrLR&((&zF#bkWpM`vbV9RKQcEM0V)D(?lUK>0{&oFr9iGw`KXss$D^)Corp>sH6^-B$PQHv_79vknAVro zAuIS&Am~?Ka^6Pl73JV-jfWmyLKY=0*mCuae$-R~)y$m6UhSxwSADOnQm<&6_3wH! z-Bu?lv!GrCu>0cWMskw$hjx?<8gOaoNFyj!&Z-M_51Q}hKzv|TuyyEE=w9eJl+c)v zA6RAfHim(Hbx}Jj>!9ld=vREsI#C2TGO16!lJ0va&Z+B`@mlz$_&J_iG=?jBmY3%$ zuge>W^Y95^P&PmA*I`{opu`#)+$K z^wznWPpLx}$Rgrb-q)YwZF3EGg_9Smm||bBa@jeZ4(@7ikk9yXaDZkw^|#@v{mqI2 zbKF-(DIdTHzoB2AB`ak`q4M|MA$OIt(0*`ij(yDQyfUOVp(ZzIsmYWIb6(dpwh@a}qfpui9)vPr}sQAB=|t4JnV znVQgbx{(T`1Oc-lLF|Ti)T75~57dDzKvH?-Y>`i-6fQK|lKg<5&2QvYcH235aDR8) z4_-Df!{^W}2h+FoDs|ZhcAgE^YN-ksesZlJ`tnwq8SYOj@tDu>gI-E^yM4@h7Fipv z6fPAm5pEtX7uLfK!j;20!u`W)B#m{@Zs1n(7mEV4t$Nlt94s1rEoNDg7fEI(c@qtC$)k3Mz6SpZ z95GuNaoR?8mGTJw=K(TH7L=FeMRJLLXLC^FUmB$Y&4PJCH$qQBvqD)zB=jseHkdqk zE>J)4kJ;FK0{3i#Zs?2QNk7y!XcyEG%3$_4{Xl-gh3g>VuwM#@=jfZ6$sO{55=Di2 zWNSdCcl#wL*J`RwP;Jq@}S2 zpQ9FrXt0lI>Akfz${G4W+B}D!0MBxychJAXfmyMZo8jiIBGt%SxklcBW^0qC$P^3% zYpe%#sTQ;)sjLA$Ize}np0bIU%yaUyepmmAH`g16Q(YgakQi@?x5R(RE5h47j_1`^ zJ+Gb9-y01AD}sgLflUmx4tc?5!RCP_W^wZ+@)ryAy;?TyPj#$1Kux7iM_0ej>a(fz z97#eZqMD2)=V^rPR&=$px=|gVz1EYMm!P$@3>-4|8rk$AYA;l=#cDo1t&zfbt38H3 zkc9k(zWiDaCELj^(g9ktE3$$KWa2gX5B^H*k(*>4c&QEKV)VO`G8NR|zH);E50KN* zLHCPAau(@L(}PK-V;AW&+EHDiwA1dYx3qusfyNHQH?jloWHOtYo6ITZ1?YDZ^ds6= zXp=wmc19EsT0d>JvW+$;dt?PX$D*t-*6OmdQyBoPRZpo3AOE#7MUByNX{*)jY6{$c zBQ1q~T_0ggGIs0rG(|0}Tw%|lGv!iCYQ^-4daQO+J*?Ekcm9p8MAd3g|MP1lp>USa zy#M)(Mt@*q%j^*NCy+jPDe%a=XT<5h=%uy%=u=BrW%etp!ZO2Ey+Fpw4B{dD`H(lu z&F>b3^Y6J?y&B$jaFmsP7v4j}$q22d?$W|>pp9V|sLywRva;Yf6qx~IFqMzWC;@x}hD|k6K;ccDbXXILTSleS(54DRv6*D(U z_N3F39!>f!>BFRhlkQH!Vj6^+o5QuF%4d>Z9_RZ|@i)4|okn&q>rP~TE#wT<~D1V06crbup=9%12j;(nCW6n~go%LZt&$6A)EwX4<->QHs_l=;mx0}sr(<}0Iu@k7sO z3^b~t!aP?N(LFMy(0BnTnoZpw(4zuwHn*a?&AkWpI#J{X-g4+w)))w3y6UPWv^3fi z^)I!NI!bwkBu+dKbRl_GJmL5JMczI4gWC?Nh~93jeZcw}863GB-Vm-IIcW8UtGW!1 zq{_!3MMdPVNN{YY`{-ooWL>F8$^i}6l&8>zj^olXYhPW z0FRy(^}zNAK}WoeYMK=q@q1;cx=!7S1kWv1(W+>bwVi5ZB|p6`PWh?4^-gJk?m(xFQ`(8Z84DrnHQLSSeFfVw zkcdhmk03df2E4=|C!lpMLFV9@8*;}x9h{f;c575*7Vhe1q5>!QLik7cb@)U0dHA0& z4{O+AyR0nEX}36(xZ`{$@5%e{MMx;r=bL>EPucMQ^nZb`xdU2M8vi}=4F#M(>@rC6 z{9-?}egTH_!)+rCtuOX-_o<&wG!!>^1-=q~ZY%GC_n-f#FpzxP3LkW=dlfthaaC>j zUDWJjGB5g66FEv8hdPjr6aEFL_Ay+`d}0tE?2khdkcdlwa*$CAYH2k?>#4R; z=7QtwVnS_ypV;#mkd@~39IFd;epdZBa|n2(rjo{ z)#u>8OR7KM1yuqAjuoAe=sP54%0!t7N<~(Bot9@^p;|%Dg0k9%y~PuB)i>He{jHwc zC}Ot7P}GlPbSk+I4K;DBd)y6N1T&ID&M z9Q;^sEV}FvV4#aKh?HhDH1H0rk}^QOq0)npPl7N5+G&mH>-4{kDds_QrWu0QE5PQ9 zns@YP+70zrr6_pAR$jut<<@i}R&997?<3D5uOp8lCnB>VgCdh6$C0X_&Lnr1$NVdP zFEO0FqTARQ<%QZ#Pi@@S_v*EbmFCsJ%;5ZBmS9YvyU|jMQd{AU(}7z$Y_8%#UHe0s z1n*&hIuBaJTYaA1TyKC>aTcu*kn?msi6QYLwZ2LHhZRBkuc64p=RyN44aVNsnQBjg z$5RN`l-F+QDDGUh1uDZ_|Ght+7n1jAJGG{M#fS>bhKrqG+(lmXg#J-Kt!w&Xl_>Y9 zBtuClQlIo8LVkop$oyD08S*f;lLaY78!>FKSHachsDIjq)*Z~ zN%tf#z1u%Clc-86u$s zZHLxBg=>5ZxK{Q;7l>*7`j=*dkyV-+OcXhD!Uws=X&S%hgD?_WS;$P)&<$h=g7Rv!&s)+Ie-DCl4 z&jP@fUFaFI2HA;~d>-n{E^$x}M(-;|(#RuV+e;zcgx!H&1W)N4lDY5Qy6#eEqLbb& z?j`pZA-lAWZv?VA1!S5DX~9+g6kZrg!dd)?{)WJ$^7NGH{64A1~ z$j=Mmr@rfY$TyO18c4Gi4GE$h~F3q#eI=sIpQuLx>UEjO*3!yW2|pmAq| zvo!)WGDuF!!Ll;ag=?XhwU*W4KYRjvJc6WDFLaADNOUBHHoA?bq%*OX*I-ri!pYjF z6jU=qA#Q*S!w>cVIq7-YMyfakW}oQG7x`J>E8Oss`49bN zJiYi2ZcuB#uz$`sL}i(qoP|@ijDCPy$jKa}Ja5V^awj-aE4f|{Ad|q#M?%A|XpSJKzgNkwPC??LfZ9{(3r?4tMj^M5jAW6u z@GmDre_kbr089P>pSTChhrjU$KBJ<1AoI|LtP7IPS8#_1m7LJmduS)LtngjN7`u(C zMp^we^tfB>Azam0xROfHK1Klno$zn^I#jkT{%7x;+ss*E??axjvO5*$^Ewb@Qho*9 zI|&f{NcV{Qhu4fR|kbffuMQRTZ@(r6rb8GI6288sw2bdk$xE=Ja=?E(kzu^=Z{|xxKz>15 z;}SBCnW43x!hFhZu=)HX59uf~i71{6`uit&n*4@b=~)pHP2e+@^72A)p6c)NU;7ED z%cakr6$E9oZp`ugK|B7D)&xZW&uGxp{vl1K`%6G~OB zy?$Gtjn3T~Qx8*-AFix0r2^EC7wQW&qk0g^azWY@p8j@HTi)ht{Pf@`h5g6g7I^t{ zd2+akl}Jt^rAC&Li_okSl+o%FwJMY%uHDq8YBRKRS|;?TLfUmDDeFh5Jj@sRJ&}X# z?>2Oc!Hdu3WV4G}cO%R?V70W*+r6FoZbh%KUzGO~-{lngh2_ELozZGRbxHKYd8P$(^DSf97>XPk&`Aj%PQpS0TOI!>VMxjywg|QJv&&FL1^$ZXQ(AhkkxB z15dLvyyxxoHco#U_B+df)InRM8}G6>mI<75M55_3ZBn#r$0+5Z#Fq9Z0KPI4Rk z^a@YLfAPn7-%!)1I^XRDcGzlZeTl?H%3EixzIJx!n{(am4KMhum*0QpTl^4mcx%~A zr6iK1o3;0tgjuajKus;GTu`ne<#C=BXVd9dvIptLzepDFyE$Y&*jNBLEssg%gjx@$ zDIcbnlACLwUam3jnOTEPL$jm)j6RQC-tFK%bGM#dE2TQ{&*GHYa5J~l?WS~NOK5v?SImZw(Vma@O)t^u4fK7)x*q8q*&aEM z(=;7=dp@L@b(~WLPa8=sWwn;ktQt%Vy^Ru4jiOeE@`hRl-E17^>6V%UIH{v=}hW?XRlWk~8b*%9{ z5E~?+8em~nb(_7AQ+ZkcG`e~!uacY5NdrA#o3#omM1JpuUmEigclqD`OYb-o{Pg^c za7hPcjMl^G5ttWh5*>-I8yy{WAlM-A)##uX)W)h!)rt7ZqRvF(U?fgP6tMq7?Ei;K zQtg$#*z6gY9Jr0_;+Eju;9tSMK?NDgKLfi0PXl`cT?3^9(*k*d{{@qUt_Jf3GY5_v z0eznOx6&SN(>XkoDwrV~tK38GAdwmB25q#FGjK1^G*HJB`Vy^*sw=6{DTmU|P`n?( zVa$Wv-g7wnMa3y3)!v~pM)8ACcMm%A!2VOZ3%o4I+oeR-p$-|#x~heY*gzmESxl8A zE0fGm@;;_r%>0-MF~wt!MZb@7LVpEcnDdM|`W7vTwo+}Uc2~zKxmYyqLyD5l@Vvj1 zKA4YL#+G6)7Swwh=gd99Hc{E4vqg`HDil>VDofPQ(A?1eV4c7wbi{62Gj%62QjO#k z%uNj9>G*4)wkiHV%tsZ0&N3AJ_b8u?Ify(^S~mF=_}}>bKfIcFiJDY^oF-j?dq%La ztT&$XQ(A_;1lR6P`_rEAtnMIZFrH0igYlBakMRh}h2fgSiKzv|HCXAz>d+3roM*^GFpDebehgl4EHt;-Vzro$*{YpL z!B>P5vla7IO}q-;D(|s>K#V0%X%`0GkGZ$1aK-0{uGoQ@N8h7Q(^DG1n5)f`<_|Mf;EFL&>!|cWO1=Ry zUiq<4wxaDa$TTqbcXvAGzOs7HP-{EG8@s^^fO~A_ zW5p?%9CsB>O40pn1T^bcv>mA__lTmv9o6U+Itj>Y68R*3kz8EnZ80-Y3b=i`pUU6q z{pn@$*ZXmp^O^6r=eNXcG6sG1FYuP}NX!g}5}r~muAWx*vS#!nGN;u<5+q|^@&!Qi zhtT!w`f0px@cZ&PaX95mFs;!BlL38@az5)({zTj(^O+CN|GDxIn#oZ%NLdY4Jb_JQ zui#A}@yX-8HJD@j51ikyCt5!uGa^$WXCk$%MC+(s$XV)?1j?W9R(039Z@uxnfvitk z*+P*^<@kahOw*wI}DugNp6$N;Xn|~J1mCpyc<9J=o`%4 zW~Z?HaEkEP#QWiHRuN|&@>8)$aQ*P^c;&sFZVc4)ul@)TK!&~vyu=@bBA;H2bd!C= z7<8X4NO0A59yo8@i{L7$pbeIRN|_lBXcqAnzRo|$hq`c3CIL&QQb(zaQN123(WqQC zpi}Hn_hHg&qOy>U2Uj>CPWvm}vvyl3w`sx$61K!wj;|YECBAw5^!SVMaq%zW?f9h$ zvlC;(pDo`x<;D5u;qc$Ue8OvFI7ZUO%x2{<8&DK^;==SUFhUDbhnV1lxscsYCFZ04 z--0(@nqL8q`6()4+U+88q$%huC@2fyY(^`oFz0v)7~)qNg3H9k0?bvm^3!>@oZ9x) z$o_E7@bSc-2{8!^FbQ}teslc5_<{u4|37c1 zf1l?-w)F~)QBUg&&0S_!BSt@<^+jGJAF|uF*)Y%peo4Trj7G2#6f7`_?mPbZoQHE2yG%KivU`|RTxkT03c%lK!YC@;d)Ln-g5pHIw|Kgkf*Tp6Y`RthOUF{QdzX#p+a zp0bBsg&(kijsag?fn5+o=F0WZ3rk~qyoJ{YiLt*hNufDe?djHBV5OZ_eJd5Ryg#gt znBOgkiH1CWd7#GI*c;91Y1)Q`v9qcx#eu~0Ys0mY=0QU>LdJNc?>Fihw6jVw=8z)v zCs_?ewlL-=MiPVOUcB6e}-mHXbW zAZO5gN)|N{v*l@!VCe~kp|%!OEhvJ`fqaJHDQCjW=2&p+666b%+p}P%hP&R`4vbj` zI>=jp3-5@0aS_oO6U6J0+U(*l^d7q9+$>H#>p498KH->fk;HNdU*kI^cr&qG zcy?s3RT*iB_RdoGx##=;OL#32dyo)pDC>gvMR4|agXcAu`=HcMK;Jz9eW|Xq+0JA) zunI)pB;HJT9^WheReY+%D`9Sxc7H``EQkD)WMe&*PU>ter7_GLXXZ6BYLD4t)SF)7 z8vN7W{SjU&cY^&U(jlBav08$X&>`6riud*^fa}CyqGq=})~;-iw-f9Z4wPRv(XHW) z25#=i9kHGCW|}%oOVAtQtnLit3*0plHK|;Mewmb~^#(by)<$HPPbF4MG!vsyqvs~v zinrtX$1RUr6<;>7Zls-^3|iJZ&-V^{`!R`^i{BMl=^b_zylyvmw?PlUP>(2U-TdeWEG zX(DT+rq#Y_HI02{pTJ_|*DeRf2GfO7gbD<^o9*?bYFlMJYsYFsO-jRb_5prRF?yNI zCez6`FsEPWXt3-9@UVu8BO)k2iNC}$UQ2ZFTVpne2S@u8DPfq`7-&Fc2{mHKcT9;K>nx=(zCtP ze~`X6p_Y8Zq;+L&v368@tK~()qJiY&orgnJhtD(7~h@ zRQk1YBPO*|koR;G*t>^p{Vl9QH(4D_^EA|}8JNLq=MOo&$^c5Ud*?4ja)2xr7`DDR_YFA9bJ>h*tv^eP} z_XyN)>6V4dzee0b&SM8=1X?1YP)aEd-#P_UqyyRtwY`#ssk9k1mTyS@KZ1WY7tgpb zsUWk7B)k&3Y8-e)Wxs>p%ijnM`x(5XN4z^GKMUZ$J9%@F2i{w4FoshkH?4_Odj+yl zzJ^m5_Fs8vyi;yJH=mmvN$`j6zn<&I@>T!0tA({Y zk`I%^86u}5$E^qUWv8Iq3Hp9XZ=%;2`#!tM3$l@ICNf;1Fg@|1zhVtxahRHVosYK3&hEPt@+H&A}1#!tJ`C zuh7frhoP8VQT~CVv4>^F>CU6JQ4J&%KhZ@bnVifk!()u{TxglS-CcNJ%RJ2K9g8%=l`oKiv>o0QkVBoXwJ?eVo(BEU)ToU}t$vJZ8vPtpUgAf{Dz%m=r8X2SeAZejkPEXu$#H$x z`4lMTt$;>5D9yC(h8DaZIvv$MdPnsA=uphd=(N%Cp{2o!fnCNft(bC%%oCpf!Ha`t zUB&r?%Cf|6i0nZDxYDmM#oo*r@?Pb$d$+ttCG#_1Scmr+f|(7S*Y7b#Zy@o$*(4uQs}Gb z%Ac$$E650H*hesreqfLtd20WrI~H#T_|vLmRke8JNu-PQhn*COjJ4i)08`yuPDlVyhWl7tw=jz{&qB3CsSiO zqat!zDM%x*VjT`kN#wOI!z)RScjL@M53DNo;B5wt@HHKY#C7Pt`H^iO0)KlI5N}Z= zM-TbOF-J_C`BsTY!SKe!wTYh+yM#X@Y4azP)#rGF$p7Bw;_&tIFn!04sYlp2^*5x> z7pVP_(YgXun+nt2Yv^OlgrpN6e7OE@9``TgNhaE_p&%uU>P9x`cBw1^@ z`;gKo0nF3a`;Ix93dlfc-Xbr?AMU&UpHLiQ@HU_;NO+XO-129+l6*v7@4Y-H{^0X) zrxU;wJNTpF#t-m*gLie^TZ#EVbUDoDjfQsKR0_TtX_jMNL-=f)FkycSJZ2`|1C<;p zumq=^^UzN1%y4ERf6@}#etY|ZUBeL$!z4y&tmHO%7?nIoPa-E+3{JZT2QX1-uGPZ( zlnUuHv{`Bsr6KE$H!}@KVm}FwVDe`N-hNOY?nMMD=svi9t^FHtAd+HjUhx8$DHG`9 zZ&+H?#pKF&cAuTVMCx!PB6hI|i-!t*g-%9KttDRB2EOh4}AR{MeZfRDyGya8#FJ`Wu1De~k!pn&|1w>13$BryQV z$NwJ zw1S$e%wU<2H)h6bp@vijLkA-8Lqa9{${ zP%WGB36l}oj5~TG_*c)sg`Q&Wpr)E%jZqsa6KG4!jlT0c0e36`s{4euw8Y`(ZeCaK zZ?6yDz0nJtslaWGfZ%IMQE_mV70nkCu1WDAl#O*$#b+vws^4}w<$-!M0H z%@}F4##GK}y|CU;i&xq*C^qtq=r8I*>**?bLcL!oJXuB-q_dD5s>@2Vok~_*Ppo=J zU8?R;N204+WRz@y#Kd$jhpRhRtv=R9>sKVds-u@x@l*2zehq7R1r?%7Metmnl^pbZaN-o96}qMacx;<2AJoB|U!kq1OD5%y+*eu< z4bD^vOu!tvPv-p^s5d6Ju+J`uUJ!+Mo+d8En?DP7HG*j$!cUz-qU{Fcas%9!MK=B7 zl3oU{H%V!@HvN=g=SW(dU?$>0AA1M!T80ksMe9^Vb3jGqR89Rm+C8cu_vAKI3|l6! zTN!FXT7Dhx_6g2v(lfnV*KqUgVKnO`TBof>d&(;c$2YNqeFp=$EaGHhqGKIZ5UBU~ X;~nyE_DTcXxM};1(>n1PJc#?ykWtLDyzltLi`R_doj( zAh1JsSJl18Za1k@v*yi)gtV;EqDGJY!?GqNgiw4{-$}@4c5Qk_L9O_kBgc4ez_O_{Ey*S{Fo%%$dC zzrU$RHN@d%baP2`AtTb_zHN zb~?L))x~;d?XYvXyS-)nh%8DsGp;;V|I`dUMxU?OHQpPg&9KqKIIhpt4y)tT2I^Vm zHQPz6kd-3NzvZ>{rg@q_!2jF-4`18-?tUHrfZv82Vy8$UCrX{HBz369{$)Y6pVmd+ zqLN2H@@{ZMH3+Oj;oZKW=h($Wkj4YNlQj#fYST2%Wtn}016Vvl_BA1kM zGU-ho$X{ew)RL||Kpe83L}Xq$N8}NS{2BksTZ(Jqi#RFw{SrWU9EtyWZzDi%}O z1F}jM6Zd_~Tj34%s(8}<>ArL`dmFqVerw)Zl$Jl`2GWC;WmNe~si(eD%WCtr1KKhz zpruwlmYc=Vv@C{Ipt(sNY4HvIbT8gbaGQJ5`{KuPMH(bRZqt+Ort(s4td}$k1UH7t zMRkmlp<1Cog6jj_%yarf^(V_rJIVR{FHbn{?3wmD`|O(}sW;n8 z>zC#`MG+FA`;}j{;rc>jlG!$31=<8V2Qvo;2l|;8^!@59mXV&5mBk-^Y442F-cDwH z3qMV4nm9FaeK@^!((dR=Z#Ew(4u}QOZ-#* z6YQFneyq308{}DTZFjlz(JpJBwH{li?doo+yx>8{PyYa7#zp+*5? zzkX6%q~1}MDhrjtN-jKYrleFP<1C}nNjapXRy(N6)kErF^(W42J>?_ok2P;e7m^Kf zhe(feK2j8y&*VswgFd2NSv59-mL#?)C=T-Zd=|gXQ;J^VAimOwMtqqc@mhH2-6ifH z?ov06JJ(6)ly|y0VJF)A?3LnWcvU~Oe9EuL0^|od!P0Bj^u~c4!HL1!!Sul_fn#Qz zvBKzOtkpB?ZL~OL4&$geZ~0-IqCMU+ud`R(`^ybGvz+(#Hap<_}7+3n-uGYPxn2gD~$=$c3) zi>x>HEvLC#&+YDhcaM3DPZG&V7kZRg$~$$ImPQ|?f6_}BV~k;jZdA~7YloG8X{^j6 zF8jhe=^gO~dSBcr?ilx!Ti46zXW)W=6-VSW(vkk4ujoeliN0pK`dH1VHPqT^rL+^O zrZ!VHut~HDStN(xe5Mxb{65|Vcayutz3Arku6e)uEB)O39`A)3wpu#GV!5>s7H)=qz*pVx=!>Gf+`OYM-_ zR;_@q)arfZoN`H7resoTvLW;o=}JbDbEr=DNfmNOo|pOXtHJafT}N}$)})fGAd>OZ z-ZJ-_^TNsL&T!-0i5^4U%@DtQ^ancj6T4bH?NKO^7D2Z$$f6Md^_`dC9?=U3D( zs3(=~N)P2X)X9UaG22Uzl4bI}C@+GdkoZ@qB$|Gs9oT;MA1klCP>!i*wStCcTEWp# z`J#(O`%%53hK9NY{|J0HE18Xqj{2WkSbe87V0*}R`BZG?v0e@Lt-aam6j>G?6ONAL zwI17V+zLFO%tI!V?6fu8sPs{fV%6W{ge6mVDyx(}%5L_Ej-m~zMJ)MQ*m$xf{SWRi zr;9z!+8#L)E);GQ{vJLT`C(0V+IUfX8LD#+dYqZ+5G}J2G1mlJghq$l;F-X4EDFm~-2%YW*D<8t$C=#I$JdFG zsg+SZkAI*twiNZaKd{DoHl+p0DJWQ1P=#Aw9xaNO`ZcQ5&n@ zm121IZE0UJQXWFz%Ff54I>vcFaQ^yxrnkZ^;~vCazp?6C<*g?8>@8M5yR%c({p_~E zY0BlB{#vh_x6@ndANjv)E<(P@w_-29<5%&&d*4wZHu(lB)H8pbx7pcjm5mGv_Y7O% z8Ie@@vv^Pc% z-}wPPfG^?Q_&2|wf5pq_4R&qkDG*K#_mTU>E6KB?XKn$8n&wya^Z51sk^Vlv8P6-u zp-1--A9*D{z(3}7L{FURW?n>VzEIp5t6_pLo^%X#Y2_k=w*s zY_~(V{M+%|`F<%;M~;`@#ZR7>@9>-QE zEg~Q$@-Vv3ew?M1b`$%MJ;@o5{$JeB!T;k`M0e2}xOKf~AqSGVv<3UbnxQ`IV;ku} zQeQ^+Kwm?bUS)T-`bRQH7DXmo!KB9Pq(u=8Ql}! zNxoc0h|1=&8*CsGG{hqG7;8hn$s)9Y*en>&?&tIe`>p+5ytF7ON08$5C-vD6)&_g} zgE~oDphauC_CxKj{;DoiOywK9$=>5nM*@fa$_|qpat*KO5AvS7Bi(B5NvDi+(tc~D zwT?#$SYz$M?h5~=7)plI!?Yb;4b;9v&I6ttD+kF~@tUvq%X{CQ4|ZL$IGFe8%O;JEzkmE=O`X~JYv?u6pnw*XS3cV`F$#OECjFLh5t86NF15pxhluQs8#aFEGNV!Wsm$r;Y zKbuN)nvdQFcd9Gvh#P)B&u~XO)t#bF73Yvs&+YBLb&5GhvA=rTJM5B<=H~RK`ALN> zv$B%vM=hz5&WsMc4&)C$4>Sy%H#?d=&C_P*K$_rzVE)j8(Am)CP^Hk(V7)-R(LyI$ zF`((8=(k&ylWZT|ORnLW#K>B58W3f9JiqQ@3BT;;_m6nJylVI&UPpJjbIg8XRkqwn zjP<9r+@9z(bklebz0&>+zYy;#{+8Ftbozj}y_($)rPttelSM@jg0llE!Uz@1bRrb?tFKL`1e)@9lc-AO2sw1}`F3c&+_3-cxipiQc||yqA5*3+(hlbSE32W;QYf ziUyU?mSCm82V;@`LHkD=r%lqD>dlQ(=2ml#Io}*=mNmPYx6I;!sK71bH@yxRN?x#) z3|bv+y|!9wg|m7U=6=xb5KqB2J14ZRQCFcXd3MsSVR1`awCOJX4M<4S=p2u<9%oTS=GD z!nlhStRgGQO0czb8`+0*_zJvW34iL(^_Tib{ro(u=pz@9hIBt&Ny}kBO#}iQM;2j? zu98i}m5JgzYD_0T(c|7(Px11*hn-hWYxM7JUVXosU%+eWoV2L*ZzP$u&9dxy=srXJ zlfZv{`E-5(eJ&f>L$@=Z6;Mhl&sa2TOjFPyv>L0bM5`;+AL?s$s+v=Em3(SdwIO&< zc{NcPuS6*;STeSV#?XC0r9-fH8jwD~pFQ|ubmA{!hg?PqLJmnrvdeM*hfs8IA}Xij ztgn(a-c}zN}k0YcuYI8QtV&w=rcUPtNTT~VW{Y) zx6i%f1W`jv@G+tna7}J9TXd4Cd0nrn+t#UKKey-G|JjQB!!6}k6N6+6(vdVJk7)vZ zB=&gG-dlgX$nUSP=i1}F@BS0_m|e&FNhT{x={VV%q*NlxFRVWqjJ|Y_RF=zmG#|r% z7i&ln)EcUKG#z`arZc{38(CM%luK$r9YKf7`(V$xMGx^#cEDOQ@?H2cOesrAra(7p zMb^`;^!fk#qA0`rdS9J!;PS#v#?zAXtbwwIj+PET;=gu3+Lx@ZSiPBvZQ_&0y^U=X zmm&T{LbSEeD=$^LlpbVVa7GsZ$3IX9=|hZB#tD6=R!%*@E<-C>&orFy!(g7L)#Ta% zr8Vs(TZ$X}pksq#Q*4k|)J>oZ26xDSNFv(UO~`1M|$&`cSn3yGWLi zM%0GjR)MA=&qPx`*Zb%=_EG1YS5{;swdh*4 zPNLS|Xk^YdreB%D_=13B2Wn^TyU80_tEAd_8ACXc{Z9ly%NB?A>nMD(& z1d3VA2Z~Q3iIk$P_~}1&(>jIil6DrSwpUSHCa-Be_LL=2lW2{!^Xg~i6zW?AHiH$x z{oMlVnJdSWVss8xVL6S^zgR#S!nTr+q6XjX{pW14vWGv$pNymNALExK>`1trFf5To z_E<~oz4m%rcP64+Z4h^)iE5XNNJ7|nbcKDjj}@7$@;NE z>@Kb|p0p-iWkbH%O=rIeuS|TI&?2E$Lgs`E@mu4w#8;0i5ZmqNvY)SGHToSZfdZT zInHvsnf=l}?@V?Jd#Amm=-GAr-@wz>dj-8R-b?R*pNVJS{W<4*MNJ^3N~9Th@O@bt z$ZspTAs>sX;0(F>9q))+2&(Wu?su;pZzr;d4B(M}d-=UC?rvwL^DDZ-Z_wiYbteNC zA3`UX#ci=!&O$xDDgNdC{ey0A=ZPKTe027MPf#zL*V}vS4e(VyoImEp#T_wD<|ogg z3ol|jlyz!zZG|>b`&E0Z4pU>5j>;D{h-GKb=q|8zLF$sWa;)gh9dD_7$XNrNo7uCx z0M8@diNdmwOe#HbOsp00Vk%a*6V&NN=%=Mgf_y70lb_@dszAjZ&nB=wtPz{d(m-)o zrgqSB>sRzkdMZ7nRZ_1(EkCDxRN`?euR_HsKrV_lyr{q3+wCQSXN~pO`Q5;HOM8x6 z(#z&A=lSJ7qzfydEK+7DNtJ=jU{P!v+oJ4Jdua8vlIlXX5juM#UeABzy#l72>woek z*kKt|Rz;X{G)cj3D5ta&Mz28LAP-Cm1OqM1l4d&diTQV+WH3XpPaw)ntv^(5(^k*} zyUIRtsH_51`AlpOeZ?r~C}-q%Qk%5}OMk39REhy5v{rkmg|vD4UZbix%sga%H8+~o z%^35Pk-;df-_a&$Th(&PaXOCdhXR#CW|n1TdO2E5;Pd^nUP^C|`_4V-Nx!;SC>N56 zv?QCw=3!^wQ1WQ^(IG1b+65BKmgY+1jGk4edJ%n)UL1I4pK2&)$wDCQquy6{gnQjR z?hW>v`>q$~rNBNM>DT0^L_6}6&Q^M9KXu0#Z(cA{295`U!KVQ=(A+f52vq6`T3PiT zo5Y@x(c~aY0kyq72}&Xk`&EHU;=N>iEA~z+(wYY8bs(pOvb&riSI7>e42@=8l{n>_ z@*OKuOd-kwRF7x0G(AmpGFEK&Rqwtt$?1 zbEN|-L!Zd1VxQj^>+sn<=>6?q=a)n>c|(*Gv!GUu=dXBsksxNt!?H2DuK=pMDx=A8 z@|tX>W0?-@RR-vAfwE2Mg-SG;mLi>HcJPmb;OzTFF<_>v@|=7vtHHhL1uR&Lo`5#7 zOHycN@7XD}m|g)__6}akapfg_k2>kmtx9jLhhA4VG>6$_G_Ho=tmh}2fgbykjAVp- zDK?4!#8SDIT%g_9Fd);MEEjOhM)bVXN=kLH(w;@gIOy@spkxRhkTKwzC+IVFR=KRC zR~EA#Y&iQHSp0W&p;laf1|Gc82pEnQQ6H%zwXS+0W4)1Rc*Ydtwyr}BET(N!$Eyiy zIsLS;#k^y-H@_N(jctZBUYIuni-ILWFG3ZgUWQHwmk0Kn+sxE~d4bk}RAvRenOcmM zC#Qtqr}=$e4;sdCc^i1Lv+M@$o(t;67SRmK>~UHK9?TeeoLrP6WIpiOezGcQMOU-+ zN;N3Rd6h8DP9Kq!^gGQ0{4`D7qW-R?Q7b6@p?C^5LM^FhHY0)Mq1#dIq6bIUh%OmT zqPIsa1{-()ZL^mdrLR&((&zF#bkWpM`vbV9RKQcEM0V)D(?lUK>0{&oFr9iGw`KXss$D^)Corp>sH6^-B$PQHv_79vknAVro zAuIS&Am~?Ka^6Pl73JV-jfWmyLKY=0*mCuae$-R~)y$m6UhSxwSADOnQm<&6_3wH! z-Bu?lv!GrCu>0cWMskw$hjx?<8gOaoNFyj!&Z-M_51Q}hKzv|TuyyEE=w9eJl+c)v zA6RAfHim(Hbx}Jj>!9ld=vREsI#C2TGO16!lJ0va&Z+B`@mlz$_&J_iG=?jBmY3%$ zuge>W^Y95^P&PmA*I`{opu`#)+$K z^wznWPpLx}$Rgrb-q)YwZF3EGg_9Smm||bBa@jeZ4(@7ikk9yXaDZkw^|#@v{mqI2 zbKF-(DIdTHzoB2AB`ak`q4M|MA$OIt(0*`ij(yDQyfUOVp(ZzIsmYWIb6(dpwh@a}qfpui9)vPr}sQAB=|t4JnV znVQgbx{(T`1Oc-lLF|Ti)T75~57dDzKvH?-Y>`i-6fQK|lKg<5&2QvYcH235aDR8) z4_-Df!{^W}2h+FoDs|ZhcAgE^YN-ksesZlJ`tnwq8SYOj@tDu>gI-E^yM4@h7Fipv z6fPAm5pEtX7uLfK!j;20!u`W)B#m{@Zs1n(7mEV4t$Nlt94s1rEoNDg7fEI(c@qtC$)k3Mz6SpZ z95GuNaoR?8mGTJw=K(TH7L=FeMRJLLXLC^FUmB$Y&4PJCH$qQBvqD)zB=jseHkdqk zE>J)4kJ;FK0{3i#Zs?2QNk7y!XcyEG%3$_4{Xl-gh3g>VuwM#@=jfZ6$sO{55=Di2 zWNSdCcl#wL*J`RwP;Jq@}S2 zpQ9FrXt0lI>Akfz${G4W+B}D!0MBxychJAXfmyMZo8jiIBGt%SxklcBW^0qC$P^3% zYpe%#sTQ;)sjLA$Ize}np0bIU%yaUyepmmAH`g16Q(YgakQi@?x5R(RE5h47j_1`^ zJ+Gb9-y01AD}sgLflUmx4tc?5!RCP_W^wZ+@)ryAy;?TyPj#$1Kux7iM_0ej>a(fz z97#eZqMD2)=V^rPR&=$px=|gVz1EYMm!P$@3>-4|8rk$AYA;l=#cDo1t&zfbt38H3 zkc9k(zWiDaCELj^(g9ktE3$$KWa2gX5B^H*k(*>4c&QEKV)VO`G8NR|zH);E50KN* zLHCPAau(@L(}PK-V;AW&+EHDiwA1dYx3qusfyNHQH?jloWHOtYo6ITZ1?YDZ^ds6= zXp=wmc19EsT0d>JvW+$;dt?PX$D*t-*6OmdQyBoPRZpo3AOE#7MUByNX{*)jY6{$c zBQ1q~T_0ggGIs0rG(|0}Tw%|lGv!iCYQ^-4daQO+J*?Ekcm9p8MAd3g|MP1lp>USa zy#M)(Mt@*q%j^*NCy+jPDe%a=XT<5h=%uy%=u=BrW%etp!ZO2Ey+Fpw4B{dD`H(lu z&F>b3^Y6J?y&B$jaFmsP7v4j}$q22d?$W|>pp9V|sLywRva;Yf6qx~IFqMzWC;@x}hD|k6K;ccDbXXILTSleS(54DRv6*D(U z_N3F39!>f!>BFRhlkQH!Vj6^+o5QuF%4d>Z9_RZ|@i)4|okn&q>rP~TE#wT<~D1V06crbup=9%12j;(nCW6n~go%LZt&$6A)EwX4<->QHs_l=;mx0}sr(<}0Iu@k7sO z3^b~t!aP?N(LFMy(0BnTnoZpw(4zuwHn*a?&AkWpI#J{X-g4+w)))w3y6UPWv^3fi z^)I!NI!bwkBu+dKbRl_GJmL5JMczI4gWC?Nh~93jeZcw}863GB-Vm-IIcW8UtGW!1 zq{_!3MMdPVNN{YY`{-ooWL>F8$^i}6l&8>zj^olXYhPW z0FRy(^}zNAK}WoeYMK=q@q1;cx=!7S1kWv1(W+>bwVi5ZB|p6`PWh?4^-gJk?m(xFQ`(8Z84DrnHQLSSeFfVw zkcdhmk03df2E4=|C!lpMLFV9@8*;}x9h{f;c575*7Vhe1q5>!QLik7cb@)U0dHA0& z4{O+AyR0nEX}36(xZ`{$@5%e{MMx;r=bL>EPucMQ^nZb`xdU2M8vi}=4F#M(>@rC6 z{9-?}egTH_!)+rCtuOX-_o<&wG!!>^1-=q~ZY%GC_n-f#FpzxP3LkW=dlfthaaC>j zUDWJjGB5g66FEv8hdPjr6aEFL_Ay+`d}0tE?2khdkcdlwa*$CAYH2k?>#4R; z=7QtwVnS_ypV;#mkd@~39IFd;epdZBa|n2(rjo{ z)#u>8OR7KM1yuqAjuoAe=sP54%0!t7N<~(Bot9@^p;|%Dg0k9%y~PuB)i>He{jHwc zC}Ot7P}GlPbSk+I4K;DBd)y6N1T&ID&M z9Q;^sEV}FvV4#aKh?HhDH1H0rk}^QOq0)npPl7N5+G&mH>-4{kDds_QrWu0QE5PQ9 zns@YP+70zrr6_pAR$jut<<@i}R&997?<3D5uOp8lCnB>VgCdh6$C0X_&Lnr1$NVdP zFEO0FqTARQ<%QZ#Pi@@S_v*EbmFCsJ%;5ZBmS9YvyU|jMQd{AU(}7z$Y_8%#UHe0s z1n*&hIuBaJTYaA1TyKC>aTcu*kn?msi6QYLwZ2LHhZRBkuc64p=RyN44aVNsnQBjg z$5RN`l-F+QDDGUh1uDZ_|Ght+7n1jAJGG{M#fS>bhKrqG+(lmXg#J-Kt!w&Xl_>Y9 zBtuClQlIo8LVkop$oyD08S*f;lLaY78!>FKSHachsDIjq)*Z~ zN%tf#z1u%Clc-86u$s zZHLxBg=>5ZxK{Q;7l>*7`j=*dkyV-+OcXhD!Uws=X&S%hgD?_WS;$P)&<$h=g7Rv!&s)+Ie-DCl4 z&jP@fUFaFI2HA;~d>-n{E^$x}M(-;|(#RuV+e;zcgx!H&1W)N4lDY5Qy6#eEqLbb& z?j`pZA-lAWZv?VA1!S5DX~9+g6kZrg!dd)?{)WJ$^7NGH{64A1~ z$j=Mmr@rfY$TyO18c4Gi4GE$h~F3q#eI=sIpQuLx>UEjO*3!yW2|pmAq| zvo!)WGDuF!!Ll;ag=?XhwU*W4KYRjvJc6WDFLaADNOUBHHoA?bq%*OX*I-ri!pYjF z6jU=qA#Q*S!w>cVIq7-YMyfakW}oQG7x`J>E8Oss`49bN zJiYi2ZcuB#uz$`sL}i(qoP|@ijDCPy$jKa}Ja5V^awj-aE4f|{Ad|q#M?%A|XpSJKzgNkwPC??LfZ9{(3r?4tMj^M5jAW6u z@GmDre_kbr089P>pSTChhrjU$KBJ<1AoI|LtP7IPS8#_1m7LJmduS)LtngjN7`u(C zMp^we^tfB>Azam0xROfHK1Klno$zn^I#jkT{%7x;+ss*E??axjvO5*$^Ewb@Qho*9 zI|&f{NcV{Qhu4fR|kbffuMQRTZ@(r6rb8GI6288sw2bdk$xE=Ja=?E(kzu^=Z{|xxKz>15 z;}SBCnW43x!hFhZu=)HX59uf~i71{6`uit&n*4@b=~)pHP2e+@^72A)p6c)NU;7ED z%cakr6$E9oZp`ugK|B7D)&xZW&uGxp{vl1K`%6G~OB zy?$Gtjn3T~Qx8*-AFix0r2^EC7wQW&qk0g^azWY@p8j@HTi)ht{Pf@`h5g6g7I^t{ zd2+akl}Jt^rAC&Li_okSl+o%FwJMY%uHDq8YBRKRS|;?TLfUmDDeFh5Jj@sRJ&}X# z?>2Oc!Hdu3WV4G}cO%R?V70W*+r6FoZbh%KUzGO~-{lngh2_ELozZGRbxHKYd8P$(^DSf97>XPk&`Aj%PQpS0TOI!>VMxjywg|QJv&&FL1^$ZXQ(AhkkxB z15dLvyyxxoHco#U_B+df)InRM8}G6>mI<75M55_3ZBn#r$0+5Z#Fq9Z0KPI4Rk z^a@YLfAPn7-%!)1I^XRDcGzlZeTl?H%3EixzIJx!n{(am4KMhum*0QpTl^4mcx%~A zr6iK1o3;0tgjuajKus;GTu`ne<#C=BXVd9dvIptLzepDFyE$Y&*jNBLEssg%gjx@$ zDIcbnlACLwUam3jnOTEPL$jm)j6RQC-tFK%bGM#dE2TQ{&*GHYa5J~l?WS~NOK5v?SImZw(Vma@O)t^u4fK7)x*q8q*&aEM z(=;7=dp@L@b(~WLPa8=sWwn;ktQt%Vy^Ru4jiOeE@`hRl-E17^>6V%UIH{v=}hW?XRlWk~8b*%9{ z5E~?+8em~nb(_7AQ+ZkcG`e~!uacY5NdrA#o3#omM1JpuUmEigclqD`OYb-o{Pg^c za7hPcjMl^G5ttWh5*>-I8yy{WAlM-A)##uX)W)h!)rt7ZqRvF(U?fgP6tMq7?Ei;K zQtg$#*z6gY9Jr0_;+Eju;9tSMK?NDgKLfi0PXl`cT?3^9(*k*d{{@qUt_Jf3GY5_v z0eznOx6&SN(>XkoDwrV~tK38GAdwmB25q#FGjK1^G*HJB`Vy^*sw=6{DTmU|P`n?( zVa$Wv-g7wnMa3y3)!v~pM)8ACcMm%A!2VOZ3%o4I+oeR-p$-|#x~heY*gzmESxl8A zE0fGm@;;_r%>0-MF~wt!MZb@7LVpEcnDdM|`W7vTwo+}Uc2~zKxmYyqLyD5l@Vvj1 zKA4YL#+G6)7Swwh=gd99Hc{E4vqg`HDil>VDofPQ(A?1eV4c7wbi{62Gj%62QjO#k z%uNj9>G*4)wkiHV%tsZ0&N3AJ_b8u?Ify(^S~mF=_}}>bKfIcFiJDY^oF-j?dq%La ztT&$XQ(A_;1lR6P`_rEAtnMIZFrH0igYlBakMRh}h2fgSiKzv|HCXAz>d+3roM*^GFpDebehgl4EHt;-Vzro$*{YpL z!B>P5vla7IO}q-;D(|s>K#V0%X%`0GkGZ$1aK-0{uGoQ@N8h7Q(^DG1n5)f`<_|Mf;EFL&>!|cWO1=Ry zUiq<4wxaDa$TTqbcXvAGzOs7HP-{EG8@s^^fO~A_ zW5p?%9CsB>O40pn1T^bcv>mA__lTmv9o6U+Itj>Y68R*3kz8EnZ80-Y3b=i`pUU6q z{pn@$*ZXmp^O^6r=eNXcG6sG1FYuP}NX!g}5}r~muAWx*vS#!nGN;u<5+q|^@&!Qi zhtT!w`f0px@cZ&PaX95mFs;!BlL38@az5)({zTj(^O+CN|GDxIn#oZ%NLdY4Jb_JQ zui#A}@yX-8HJD@j51ikyCt5!uGa^$WXCk$%MC+(s$XV)?1j?W9R(039Z@uxnfvitk z*+P*^<@kahOw*wI}DugNp6$N;Xn|~J1mCpyc<9J=o`%4 zW~Z?HaEkEP#QWiHRuN|&@>8)$aQ*P^c;&sFZVc4)ul@)TK!&~vyu=@bBA;H2bd!C= z7<8X4NO0A59yo8@i{L7$pbeIRN|_lBXcqAnzRo|$hq`c3CIL&QQb(zaQN123(WqQC zpi}Hn_hHg&qOy>U2Uj>CPWvm}vvyl3w`sx$61K!wj;|YECBAw5^!SVMaq%zW?f9h$ zvlC;(pDo`x<;D5u;qc$Ue8OvFI7ZUO%x2{<8&DK^;==SUFhUDbhnV1lxscsYCFZ04 z--0(@nqL8q`6()4+U+88q$%huC@2fyY(^`oFz0v)7~)qNg3H9k0?bvm^3!>@oZ9x) z$o_E7@bSc-2{8!^FbQ}teslc5_<{u4|37c1 zf1l?-w)F~)QBUg&&0S_!BSt@<^+jGJAF|uF*)Y%peo4Trj7G2#6f7`_?mPbZoQHE2yG%KivU`|RTxkT03c%lK!YC@;d)Ln-g5pHIw|Kgkf*Tp6Y`RthOUF{QdzX#p+a zp0bBsg&(kijsag?fn5+o=F0WZ3rk~qyoJ{YiLt*hNufDe?djHBV5OZ_eJd5Ryg#gt znBOgkiH1CWd7#GI*c;91Y1)Q`v9qcx#eu~0Ys0mY=0QU>LdJNc?>Fihw6jVw=8z)v zCs_?ewlL-=MiPVOUcB6e}-mHXbW zAZO5gN)|N{v*l@!VCe~kp|%!OEhvJ`fqaJHDQCjW=2&p+666b%+p}P%hP&R`4vbj` zI>=jp3-5@0aS_oO6U6J0+U(*l^d7q9+$>H#>p498KH->fk;HNdU*kI^cr&qG zcy?s3RT*iB_RdoGx##=;OL#32dyo)pDC>gvMR4|agXcAu`=HcMK;Jz9eW|Xq+0JA) zunI)pB;HJT9^WheReY+%D`9Sxc7H``EQkD)WMe&*PU>ter7_GLXXZ6BYLD4t)SF)7 z8vN7W{SjU&cY^&U(jlBav08$X&>`6riud*^fa}CyqGq=})~;-iw-f9Z4wPRv(XHW) z25#=i9kHGCW|}%oOVAtQtnLit3*0plHK|;Mewmb~^#(by)<$HPPbF4MG!vsyqvs~v zinrtX$1RUr6<;>7Zls-^3|iJZ&-V^{`!R`^i{BMl=^b_zylyvmw?PlUP>(2U-TdeWEG zX(DT+rq#Y_HI02{pTJ_|*DeRf2GfO7gbD<^o9*?bYFlMJYsYFsO-jRb_5prRF?yNI zCez6`FsEPWXt3-9@UVu8BO)k2iNC}$UQ2ZFTVpne2S@u8DPfq`7-&Fc2{mHKcT9;K>nx=(zCtP ze~`X6p_Y8Zq;+L&v368@tK~()qJiY&orgnJhtD(7~h@ zRQk1YBPO*|koR;G*t>^p{Vl9QH(4D_^EA|}8JNLq=MOo&$^c5Ud*?4ja)2xr7`DDR_YFA9bJ>h*tv^eP} z_XyN)>6V4dzee0b&SM8=1X?1YP)aEd-#P_UqyyRtwY`#ssk9k1mTyS@KZ1WY7tgpb zsUWk7B)k&3Y8-e)Wxs>p%ijnM`x(5XN4z^GKMUZ$J9%@F2i{w4FoshkH?4_Odj+yl zzJ^m5_Fs8vyi;yJH=mmvN$`j6zn<&I@>T!0tA({Y zk`I%^86u}5$E^qUWv8Iq3Hp9XZ=%;2`#!tM3$l@ICNf;1Fg@|1zhVtxahRHVosYK3&hEPt@+H&A}1#!tJ`C zuh7frhoP8VQT~CVv4>^F>CU6JQ4J&%KhZ@bnVifk!()u{TxglS-CcNJ%RJ2K9g8%=l`oKiv>o0QkVBoXwJ?eVo(BEU)ToU}t$vJZ8vPtpUgAf{Dz%m=r8X2SeAZejkPEXu$#H$x z`4lMTt$;>5D9yC(h8DaZIvv$MdPnsA=uphd=(N%Cp{2o!fnCNft(bC%%oCpf!Ha`t zUB&r?%Cf|6i0nZDxYDmM#oo*r@?Pb$d$+ttCG#_1Scmr+f|(7S*Y7b#Zy@o$*(4uQs}Gb z%Ac$$E650H*hesreqfLtd20WrI~H#T_|vLmRke8JNu-PQhn*COjJ4i)08`yuPDlVyhWl7tw=jz{&qB3CsSiO zqat!zDM%x*VjT`kN#wOI!z)RScjL@M53DNo;B5wt@HHKY#C7Pt`H^iO0)KlI5N}Z= zM-TbOF-J_C`BsTY!SKe!wTYh+yM#X@Y4azP)#rGF$p7Bw;_&tIFn!04sYlp2^*5x> z7pVP_(YgXun+nt2Yv^OlgrpN6e7OE@9``TgNhaE_p&%uU>P9x`cBw1^@ z`;gKo0nF3a`;Ix93dlfc-Xbr?AMU&UpHLiQ@HU_;NO+XO-129+l6*v7@4Y-H{^0X) zrxU;wJNTpF#t-m*gLie^TZ#EVbUDoDjfQsKR0_TtX_jMNL-=f)FkycSJZ2`|1C<;p zumq=^^UzN1%y4ERf6@}#etY|ZUBeL$!z4y&tmHO%7?nIoPa-E+3{JZT2QX1-uGPZ( zlnUuHv{`Bsr6KE$H!}@KVm}FwVDe`N-hNOY?nMMD=svi9t^FHtAd+HjUhx8$DHG`9 zZ&+H?#pKF&cAuTVMCx!PB6hI|i-!t*g-%9KttDRB2EOh4}AR{MeZfRDyGya8#FJ`Wu1De~k!pn&|1w>13$BryQV z$NwJ zw1S$e%wU<2H)h6bp@vijLkA-8Lqa9{${ zP%WGB36l}oj5~TG_*c)sg`Q&Wpr)E%jZqsa6KG4!jlT0c0e36`s{4euw8Y`(ZeCaK zZ?6yDz0nJtslaWGfZ%IMQE_mV70nkCu1WDAl#O*$#b+vws^4}w<$-!M0H z%@}F4##GK}y|CU;i&xq*C^qtq=r8I*>**?bLcL!oJXuB-q_dD5s>@2Vok~_*Ppo=J zU8?R;N204+WRz@y#Kd$jhpRhRtv=R9>sKVds-u@x@l*2zehq7R1r?%7Metmnl^pbZaN-o96}qMacx;<2AJoB|U!kq1OD5%y+*eu< z4bD^vOu!tvPv-p^s5d6Ju+J`uUJ!+Mo+d8En?DP7HG*j$!cUz-qU{Fcas%9!MK=B7 zl3oU{H%V!@HvN=g=SW(dU?$>0AA1M!T80ksMe9^Vb3jGqR89Rm+C8cu_vAKI3|l6! zTN!FXT7Dhx_6g2v(lfnV*KqUgVKnO`TBof>d&(;c$2YNqeFp=$EaGHhqGKIZ5UBU~ X;~nehX?521E7+SchiWOVijgb;>D?Slx-Z;z3HB2e!hqkEizf74hq z)f4Ihb+0OEleAdZ30EF>6?bKKd-n|YVfT6WWOsV^4c9K$Dc2X5+g->VaE)=j&{}IB z)vf9UwXs$d{(XWwrzZ`*W1~xS1+=5CH1{xXeAw&oNxtR2hQ1f!+rs|~H^Phi;(QCj z_lNEBp7Y3_b?(~kzpf#!o0_7PRa+_Z7(7_m1A;E`HR#Feo_~4s~`%)@F^6BCh(Ii zmUX0iNjVa9>XC4og*D(~QGI*|r{V`V9)H7a1xY+7&X*d>Kjr0$Pi?67Qb((8)%5Bz z<%WD+Iw0N=3J4eRc-#_4;MM34FTt0xOw6RkSUmfOcS5OX06vAk;C(=GN zFTG6qkw&C3nMM91*U4qFk*p{2_n@P?Q*6%Gn{Tt zFK3za(n)a2+F#9ooLQ_jDQ&GcYuKNi`sT@CFMXb|SifyX(~zM^IkU86ZQhLpWY(0S>I)x3)%kBej_NFGi;ffyo^v3H6t-rKjWY=$8hOc zg5iOT!NK}t)3SP4$!005n6sU&78c2OrFZC@lhK$Rd>u#^+#EclS9PWf13gjEztWdX zpCe*~+6GmnyV*p1ShCeku7TPlsUrGL609V>c<`e?eV}&mc<6PgWAKu{Tw2@I(wRW^8AzWcdzHM4 zbFGW>gqM|06V*8B*ORCJcK=NN$&+=PDIdd+Mt+TOh0k^uS93^L(Lb~dU5_WbW=9N+ zn(sU3F04EgdrI5X>+U8!Em z+TY1Lo`}-pwY(oYK>HGnFxm}u6WvNSZH23#YnPl6KPAJgTINwJo_3PXx`uj=YnOyK z&e>4jw0S8R({=}oSZ%3*S|W)ZvX7d5tT&{gP(d3Rwk#qxa*c0hSYdCfCy)2H$LpEz zDxkg)(<4NOI<=fJIuoGyGcED0=0K>OoJY2pU~4{k@o|s7c;V zY7?oZsEC>vFV>fJWtF-{86{tkyQ}40$K6Lg;of5&mwUPTRB{Vt_(0O#UTPh*4q0uj z1Lh#}qj|#GsIIk+|sp`|E| ztGp`PLmBz)F?+t?jILe7TRS#AX{*>QqA?q{n@R%c5Bnr*UBuVi_%s( zrOZ)_YTwo8%4#{IG)=gNLQE%b>{RonvD_G8`mHj~P-nS4!a8rRGb60Fc4d;6nS3k0 zBor1O2tRQr_>NpGJ8QxsSp&Kjs?}Q3n;vC_(KH+&JE$e86O;wg4Iwvvz`Z<~<>c*oW7il7U$ETy`=p=fCZsLhzcDau7 zNO_>7$Pv;}JeGf>?@3wm(b?yWa4I`loZN7AemZTT8n1*$W75}&wG+((<|Si=@y%#r zPB6EabIsS*JZqkFmK3E6_zu1TKgE?WTxouX&1R3Ohep#OWGk6X6KMr@o-Jl;*$igT zv$Q5{LO#Iny62Q3VPu$7$cb^vIE$S7P8Il#t;i^HhzPVY^oe}54$Vd5;o5H}3#iWO zpqUh; zoztZ@!FpPkBN3^_~E(Pq$N96FB0@Y#Glzs(tsMSJ;07KAPpO%IXQq#2n@_LBD` z7wt)B(gyS`*+dSI4}?OWZAvfE`s@aixy81#vg{k(OXt!x^fk@Irm-ZZ^66|9-9v0= zrW5OUoKDU!=N}RQKgXeM;7TlFFWE$%1)V@mp;u=ViV4|;SGX45fTGc6K7{w;rFdap zhPUQNp|7n+A5jeMga5;4@oebRrEz6k0T;v#@K$^oPsNW=Zgd-7MJ+g0efduQjW#&MBjNXGxElP1(LyaTLF_C2Crt&FQ&k)%m{`a2ghnD4*MnAxm0j{cX^nUdbiiYD zm%n3q*b1u91VTs|I+;$Po#D@6c(kI2iSD#2@)DttDHP&09tTV~eipPH2E$ z(0Fd_fQqrq=5`ZjkE1&(@sjf79GL*uwi)Zn+OY~OJ(HOQXDdjnvKMR`|H`wW%BVXU zhD=_K4`SD74_cSDq>Jcunw8!l`^i4in;dnL?RxfOYk(DP*=Am=wbjHLVm-5>>@0S; zoy{IhuInqxo4!)`OK{33NCuOw-ZQ zbUSU%p2JB`rJ3nelH}BPUfcKV?C`Ueg9bPV=P#>s)!u9WwyVJF@9cC1WwP8U;cT{} z?E_XDE3;M08VZkEmfIqxX63PpTC=Uo))4!r-P5`3JavkatR<#o28;ybgHhOQXRbEy znHSBUW_#+p%pS5%d^oSi6IdzsitdI-B3$)C%**CcH{D69!F{y^v{a(g z4({%2UPd3LuhmcJJN4!I0{CB3^gR02(B{y?kWViN>Wb+L z48tgC_BFqotE_OlwmsF}WKXtZ?RnOHv$XlnIAioPRO3H=x?V+()N|_F^|r=OV~}|Z z>ilBsuT{|=Z=bQtI_u$za;G5~MwXE@GLPES#cHt>HjgidyY48<%f`}kqy{NLnv#y7 zV!M*_aMwrCM`S1YPWsWiv>=r3=nKv-E|gBlE@cCB)<|`P_D*}K zsjkvmW96*8M){$vm)D7cxLN#1N|E=gceTFSTIGvW7F7KurLpoP;()Zv{7EIWKk=r&D8(Y zp&E7#a9wpJy0*LSX|m?lK4|sa2R${s4?Jz%M_lLJHN1VjecYMUKjLtl8K%9iP-))a z?7|j&8MT8RB?z0uGjfvJ&6VKl?8>aQReDMf}r8zHBdQ`B*Gw1(}6PO^{= zfO)4D&%)l49%L!`0W(G$)`vgi^?65j8~SMmm|wz#%F+(ys5Z-0*Y#XGuFcmI`wxF_6m$6eN4%@tJpDs!b% z!aq=nEmRR7##Mxm!V>tIzoqu_bosNKpxjZXYuB{#TBNpGO;c7XbCjSGr_}((chRkR zns^#}%6P_jE_qgYGJ1Bpd%G*R=ew3_E7f(%82O@9Ps$_-(iO3>NCih2BvzNQ%iWd5 zYJ2Unc0rq`<xmfN$dzn723LBe=dWUnn6?l~kppnn&xY713U* zlhpT$TPY~_l%9(_#NXmNn4xn>YsDsFR#6sj3%7(!;s$Yyv_c-B1eEIPL3N}y($xmu zyHoBuZVl#&v95F44Yj9|Nlp;&!-PH#731N|CZ*s$Ugq?58av>#T7P7NA zBgg|P@K?Mgx{3b7DZ)r8PWhlVcja@JamTx|xF%}H)l%wP1*t!jeM(K`x?D=0Ed|A0 zFpm$E`pMgsL+T)nX_Z_VUC*==T1l77jXlM^JHqn&>O^dfSQwEfqK~h2c!sdIo}jy; zyP2zwR!mKl4@i4NCae^y2|>IYyKpwt9#lv&s}I*cJB|?U3Nd0yv4HqN=mjTmsIWuW zFWeJSgx|s-VGdq}?!bgU0qTH{?j{P!=Zv(|+Yxp;JHI^xYIYn+Pvcldo*R_OEa9|x zQtBdalUKvL-BsQoFPD4CJ>~xLBKeBk6kgdhb++0>eWk=f1u7^-iTQ<*I1W>E81+RZ zP!`l2v`YZB1MNCSXd-?W3rL-$?ou44{01$~e)9%w z5nm5IXEi-d_B+p=$xfQ1lQ`OeuBVORq^+Yic};GSA> zf?Li^QiXn|t=U($oImIJcpMuHN;o%s??})xW$AFz*r{lDvu>Li&DG$Hd^Wn8hs;an zOmmVMX%VZeGlfi{!&ztE4*fyNP*cYs8RbI9QB}MO|HMAw41SB;s4b|!lGK3f)YDlC z6U+v?tliSSY%g^Vk&{q44}k+Sn6xJ?$p)vb^9oM;eR7oyhvz;YT$*;I0-T+d&N=%c zC^*BEt*d4|Gr`zztT%=jMGUXe-Z*Z|GhXREp{u*~t)U*Fy`gdXU}LJ;5EOYfyDH2l zyY26GwDS?B^>KD*_)1p0mc87zU>=?Wm3$|i0CU6$;vv_ZlW+pU$#>_q^U0a(Jhk00 zVZO26**M8vM&!(t-y*< zSjaDA6mkmfg*~8>^N2;nykZvdw=et z*8I;HYb-O~8@)|#j6*f34&^a*Rl8}rvJH%m_iGS=A+>i;=> zbp>yW3V@DZi;IBSc@M2ZM^F>oL|{TzI5VH5O-g3%wN}Kn*OkMa%YEO~)-_)n56c9xWJI@+(TOx7Z^gIUQ88W)VM#tEZ|ab4e}W8;X? z%Y1Hj0gZRc8f4wED#JCuXXkVtJ1>bzcGC#bl+JhNJKG$;vx@#pE7Bow(hkyn>?a$; z=b<9FFw~R9FrUoClVC2uFcn=Z9DJ>BrghJ>D3uE#0 zI6RKPOmU1=;L~{@9>IUJZJ^zYv%R2?>pHXS5ip-Fa#Eb8q!(F8wvb6A7wPN_v>#em ztc%tNE8N;?mNzW}nWN0+pxj=AZrcpA@qmRE|BOpc&;sB(l|m+khXBwWZ|cI zO_-_(RGk6n2~1K0xeH~$xr9Pc|3{0B#KYo9skR(1=TrtNo0S^MAi0H9Sd0@6z&+d* z{zcf54leQ^*JNZ5f!g1_^h?;&KZmojOH5ral8lx~eu(8=?hO zzY>&d$fKmyVnK0-&=x;|SNw+WfqA_yUqgrS6=F5HvM`6{a40#>Yx2f)2YVv!Q}@aZ zaZmn{C-Pq~fn^cKs>j?5s2_zNG~D@R|0H?PcX6STLCGnUBH_l&pi8gq%od8fUU*-6R?7#-!qCaILa7^4 z4+Yv;{ZJcasmtfCs2!2-iAektM=Wv4XQrL_y@WphV(-UT}=Jo@-hcl6EqQ@CR{oqV5 z5dY_HcM%x6$UE^={s-NMuig=FNI}UhT@!K(nT5PU1tE+0U5Zye!AW?emQyulDonzw z#hlVisjgI98ZBLy_DYYXJXd2qFG^fntf;g z!K8-i5~scW)M^R6{E}0L94Fc7YMMglv5|ZjipT$o-{i0AMQxLIRvoMu(p0gyPz4`F zi@{g_igIEd#h@Ro2>VJC=wIrmN2x$tk{?cc=R5S#s*Z<@qA%DjUIT4GvA7>zkI#WC z@d6hYrV1y7wSt2QoR(ym9~mWd2|Y;;f%~x!I>=3DEKGzqoq6OOrR*VZgASpB_&%oa z{Vv=NRX}@CdB{UNVlKF5`=$BPA?b!RODZa51znvj>0#PMhiT{-hbvzj&IMODpb6P1hiOy69bD!?dDMUsU;>a@CdQ zJ>WYLSt|NYx&|?$qGv_i2z&1_U8B{?@@}c0^2aqXY>cm}uUB|$Uu;xby4*3-q9%sN zyTdi2lvMj^n_UgunO*&qY2tcZ9>wqx>^0j7wXGjNMQb~g&1(AEV86h4|0aK@U}58e z)eP$7d8m|yoDPnQ-r$O`Ug#tw35UdnVl`n2u7hhMH=E-uuqHxJi#5}XLgri3W!v@_ zn_HjFKSnL1oDl^+-xKEt`AxQwT?Ema^g6ToMVu_!@;;@FoIyN>7BdxGo$quU`Ye`L zi^Al0S*a?W!XN1`2U0-Z$q!ClwIiZ-|C4?-37;l>N| zjn&^iW$&@O*;VYnka5KGegc-7NQ!s_DQt)H7M|64aBZ?!8_Y6BY^Z6Vb=rrN%xRB; zS^o*7jf$XeL;U}-M^!g%KW~b`0BSWd8~hFXn*M6 z&tv3Ni;vkJJvz$q zwe=AWBY8;e(l7wZ$fW1tM^XCmUL0EyJG*1 zxez%yEQdQno23kpO5+@CkyF_`5}1>`A@RkxZyzVV9i8y}<)W9vUl|E)-mHJS;=TQ8 z&3EVbsninsR=WWkBLtO1_qMR9z9*66Vn|%UtgUh!&hw7WNJHT4`n9><5|L+P5;EM#urQ`p zEY+AUlYFX z`8haoL{in{xU|?nj$pyi9NjVkR)6w{7NMWuj0~kNUK{6?-Y7BJMAecPNt?y-;tDZB z8ZIwaWmmkmK-~h4HI*ibYw;gZk&StzbZ_9uC8fe{5}<{OizWA4$pR_Cag zbw}Ll=n3ADvVbzvb>s+r&ua5*{1Uj5pJ3i8Xt#BG(EhwN`oy2HN%S$e*uB_obXMx_ zS{pVdqJN|-VxKptjuH!@Cy*w72K||8F9)x^fNlqW1*!)M24)AI1ygjtxy+vBxFFH| zPIl0XEGK%8cZ-fRL!Kb3@*(N6)I^R}9x5BvtlC(0iHyX}XbUsRX~zbiu{F3*kHG(a z5BK0bBd_T|BGd=Gx?9!_%VT8(XKbJTNdIjdu%bzM9w+8h>$?|v2Zg`$?T#21vDG&+ zd}7#K?>%>%=8_!@KB%Lb=|YbGN7|;e9RA9ICBf^VDSCfBJNRoAjlE_$dzJHmoCZ~c z*#H^|6Gd0ZFF&HoLT~A<^jh4CQ`i7f-Ogry4Sfsr_BT!2ky(i6xmS8-dUdZiY@)Y9*x)eDS1YVkxF;;ybJhJp+o1WiM75Q= zN@*l3@-`{GI2*L&X}lf$>+G08rrb%W4%62=X|kMMUM9T}Cka#WRhS*iqT;9^rCa(wLpHw}Q;hmXcB7i{-FRRoTj|05-vT~R333KHO-tv5 z)0_;Yv)BMeNO7l~U5X52*TAcv!DE!k;c-!q!;x!}63|@k21<1yuXNP?CTyj9grY+7 zo+7suW5hY?p0FGdW4)3(P;kg?9S5Yqv_Q2$F5M#8#5ux$B#Ut~Fv*`Ta4{5NZ((JG zhhi@wjgGW_=oj@m=3%=8&CRYm??c0rNBzqFqwcSWL$6m5M-~(5z?IXLs^6_QV;d4d%w4B*psmPUd=sUIWHc;llf1Q z1!ml*^oFoUtLd%jz2-_){z}b+pX`nE5VEbiW;c5TEs6_>Q}9&!9h}w#{YhwY=!`zl zI_pfO``J-;7t*cHIyj#Cwr{xpyE5& z=jbrB0e3@V=t}E;XtjTM>Y9|@sjUKk^$7civ(`z1EFjIuYGrb4GKtp)<(90})^x3| z>%7)iy(uS)({WQ))k(A_*m+4^aOOsV@@S9Us0y1&>Nzv*bM_*U(o|&s>i;_a4&9g#!s2PW_g}% zd$vtk@@D##@nGh5Sqf)9k!i-|whQkWw%nBtG=gJed zF4~HV%Thek()3HB{zR;Z>=V@>>QZEl$cYjAeT99ke0P0`;WNDjpj-KrC*m-i!te7v z=md7~M^usL;`#AHF-aVQ$I%wn-B7i_pR~(qef`w}MxbOcU9eAZW~hs?(^^1A@M5?% z?uc%(Z{(`o#_Dg4v4hS|HbLmDoP+oBoBC3|EcOQu<(bq@DXH9-c7iKe7e8aiU|u(@ z&&E-xTiFA-0=EO%L#i>{k$b}9J?%BPz``4$fRtV-rmk03OFm&O_mgC+o3TQlVob7_Q=cv6 zW4KNKbuz=fo)Ai>XEx@W8?BD^HG3A!u=}n2c3*p!Ro2v@TIuFHhtf>^DeFgPIKR!o zp}%PxQl2K~OZk&BJM~BE%hc7W7g9^7ElW#Ei}ybXGzw-8<_L}o4hrTB)(Y+jWcf>%X)A?_DjiJgRJ$j1v&$vboz648#@`ZRXS7=~pCuA>Y zgO)!$?RZM#l+Et4 zlO$@ud$Ngl12^;(`^;AIv&h04{KRk4Jt?>JQ%sZoCqw|A`5yucoolnS2`_L87fs4O9{`gS5U?KQgP*v zvRUn<4Rh^xr}umYjxC3KKls3sE2H~@$MJp%^M`-&m53 z930Ml;I;22{cMjpUH=k_(pT#xj0niMTvl0Yjnx~}O+Lsh+d^LHA|>D|{|j|-D7X&U zcyl~l{3G3$J1X-b4}K|Ul>Y%g_BnXG_hnn@?F#p%4{zoh>6;l|C@h0_rYDDIuIHt< zRQQ|l`r#eJ@`No5`!DQx*tPJ%5!oV}MR>zkd49rV{!7c`Qd|eM1CSXM&^{{r<>JuI zk4t^TgIGk%*fL0&2h*|a6-=Pp_#W08X6c@|3`*hmFp-D4$GG3fmmpCpAjT@yqz3$@ zbB%TvHVA%t-x-C7GD2&p{Ht7WJ$8@KWTlsS#1rXD3LoP=;d$$+=e`5p|9bVV(paq# zRycizj8QQWVX?Mo&+zmVll4p##Az z)=h+5nSD(oI=b8PN5QLqCnOH}S@KueKOF=2oCacB?V$_KjpE2(m2cW2cN_OtP1K%h z<=nF8koQjbL*Gf?6kioz#jq7xtW;kZCN5OXuuSR7q)#8+Gc237LA=fC+3Aggp$DO3 z`do9Ovz&$VPNcV4LVp*U5>kRA{BzR2rB+P+oAN$oe#*Dxt;w%as`?KFPwF>Kzdel} z2bQU{a9`S{J@$U^WsQ98o8;}KA$hq_2%o|Iq-t6NPjk-*t%byRIa19|uqV-_C|+nP zP6G$JEP4YOrB7HPHBw8vKDb)DwySTYk$46>2$Vx_pz5yU!;n}_#Rc#yGy>e>GN>1x zERL6tDW8?!G7&2X^N_?dF*j?>SK?~YHKmQVU#p{@mTuyg?55+g{xMAbhQ35!p?5O2 zn}02z)0*U9Z+Sd2kd98{=VA|~kd_Z}J)gV3tD)9XU7@U#2S`oDaL7X@OC6=7VoR}@ zlv!!5)pu>xnkoIoJE%JQOH%AIb`u~J7GpukA`C?v_y80_vr&IxuXIE_Cft>Nt6V!O zOW*{IkYsg`PCc4|J)u*a`DRvYDs3XXlGZ|kBncy#&q@nSNCg-WXbM#QC`lkRSKcg-!;2LF1h+}-uVTM!g@Bj4O~C1dkOwRDY@YKZ-DUbe~! zS%X3+lD8!lPX3s>D7jVQ{vQp0Uj8xUYnIPDzdZW3@%zM|L;g+*jkNzbao|wjK})g2 zTeGdaxja6sOu7QGqcc>AZ5MUh8{?_&y%n}DtYKKo@M~c&wc}{I6(7134AWcL5xAr} z)qU4p+4Vq9#ih|m{99Di2=DKxiy2;ITpPDOreQ=r?-);b*fGd|JF1PvVeFoL)B*>< zSRY7Bb*1F~Q$MlkuY8G-Nj3jI|112dm#F@#omeKR>YqM;*8gddOwwxVvON>>9uIWC z{=610iKdYU!1kn&N8stLq7|J1<^+9d=vQz=@LMq2u&tw{5$nUAf;01tzZQpTEy5;5 zt&H);^okr8*3SDhEGc|Yc#^l4C%gNEtCLnnvdEcGYyVXLFaP(n=4re9c|v3KDxnkp z#i>J5E~Vs6YZ$m4qDDLGkXc#}1nLJm28Zb?kQB4cn&v2@bttdjpFI7~ncpRTFHWlP z_vN3%zw;*EPIQu<`~}10@3=op|E^0JkyatlDWsXd>?yPazrP`XcrJfv242Z$c!LE8Sb0mGn7@>jw|s*C(gQR zY&Y_m`^}8jCaWr>M$zE-w;_+AUzau}fG0Ocpa1`T@B|PpD&%3s?P6pryN4^t6SSW0 zLGFE8Zsj#NUvt5+Oo0TZEV@Cv*ctWpX-R+2CRx9Y-;qffl3FF*OWOEn`rn4hXOc^# zJWBbNI?$gXSSU0p6b!}d{~9gLVOD47A6lDVM;C<#@^N)Ebns=KD9=@Giac5P4;+Oq z@Mw)H2_ea^x?L}o`ND6ula648`60dol^35YUtNVguU-Er1EIS76yoF`N=3DRQbbxR z%n;^@`G6RO6kCc^ngG52Qwf)Ih*g9eFrCGV)x-ptJ-SObeyxPGI8Q{_ zh47jYc_OPsK8|P}5gzg0_sEyzd*iF*dlI(CLo}}31$DJWS}o<2D*{vSN?Y#g0=2!q zHd7;71(&0B(yptjnoEh2@4z(O4j+OgfONuWc=g%9ncD%mOkvcS#nPI8EuX}3xnmRY9no;R#022W>in9iYwgxz}?ET#52nSoU^xD*og3u zuV>Wzbm!7nj%|{@N;)B`1!$|~;oZXPh8GLJ9cFpwdq%jz)DO}^aTv@h-KCAv6sf9o zOZ*`SLJVZU`*{V(e{ZsyY(99}*+>Dxfhev7oO~r(jjRH~e4Mk`Spmsfev+MRb^?%S z{;@tU4F6w!}5h-Pv>7v)to%=Xb}ruBd&K*K#i)CaP;KwFltHtWXuLxt6RFWvZMkyyr6g z$6jm}F~GGjnwk~ChYGh=n{Cbd<}9px- zFh2A=R6`#Q#MKed0LSzOMmO`RRmE9Ew$l*(0;Jw9_JvQtHAE`4P%^1g)ns^{x>nw` z$c5d9++{s0JS#o1o+56+Wvescb%c}yN+l&E*HWe`xxhclC|wmA;%j^&+fHlK`oP?s z1kTRu{Iph@2aPVqUT}e~LHfDR*kViquOh-Ys8`aH;CWpN4G7&1mJOB&z7Kl!=EguX z3Y2n~^~pSD?lte5xgl}1?bGBxHVR$GbA@=}ywF!@F7y=U2#0}+IU&xJ`pa{aQfgX76_{ zlb1Beosy4>_Enk zLOn3Sd4=^j9ln8fqt9p=o*;A-Pm6KV7@*V>fT;Z>R1|ITmULELqU2VGs=3sz$^vwo~`5RPH*eOOz z+r*mU6}%8!$aP%iE7=D~!5Y$h(6_4Fx`|AWF&_9tM?Yn(GSgcfti#q;YnZjca;%VD zm9zq4asulQ*?(1b5@wx(s1&XXOwJhbs`x;>1isNMp`1`r(BL#zK(%;z7EMJ`)^R~n zL!9?yKYa^y@p*VooDO28cwVI8m5{l=13vj1%|OoB#esP&<2-{Nc+)B3?1AgM0@$6# zb_aWn{llg}am3m~AuTyaC*&0y0H@YeScRkT zGc*BtfIaR58Qc@}7Ci-4+y&c7lCTcA9V*t7T1bPXGe8>-kn_qrrHs-X(JL+$@<47L zg(t)HjN_%*TKbFJae4vOS;!n?Ow|X6$^<(Ga6p7U6z})?8>AgeeUZ8j@|`(g|)23+<)$U4tM|C|5>%O&BG zI2I_heli8Fxt#J%9xrq0uyj@GESHAb@)`27joMPJkS3}1&x%eX7QUBYRxF@a`D~M5|51f_FVzl&7dLd_47ii;LPhGcNOJFw6s?~tB zbtv#@Q-NU2ES7?V_ovuGS}IkNvWpvVV>E*s@ZLP8)#*K88FP~yqysrjo)JH(4b^iC z8v=y-RP+Ni#s~0G*p#S-O`xn+K?it<+;|#(j~hawT}5mm65u71`9s_iJswI#M|;7nJ8o(b8mb7Z5$N z5Gnk{BOqJ21-@)7yl3#ffv5Ngd4ZCf%&vlW2EICp1g?)RQBBP*w z40=U*T{McAi>>XzY9~PAJ)P`k^YJpNmRiqs-o4vHJUP8vyqm&u`#h1`qc%h*NB4_v z81*8ei?4h5q_D2u5uU^DbndF)`s7d#D|3|*N=Cn7WYV*6si^aVw~z^(_*X08FA@B}Ci{V~+>W21VrUi5z;#xP?*nbu z8=XVjU@yVTtFUcQ-!{|IaM}rr;I~;ZwvLv7-GaK%g{lGFR~fXy4Pfp*0W*$4W3>d5 z@hs3|dm$$rNB*I=SOTy$e&Db~d;v9to!P&DvY%6lPB3YSj;)9_MWB@a^$LIycl zSt(UjvMa}wUFv-`UVW*VT3c6H_c_-F*Erx^*J<6gMW8P~D5I4fN)_ccP@N&^Eu4x4 zcriM_7qU$>M8?8S&LUv!=0L7?06O~?*h_jy8qrjGmR00kc{u;d1_1@z89MP&$b5#0 zs?<+Ag?R2B`ElJPo}9=C~|S z#iONc;%NMrr?S25E$ag3^cN4ZUO->ucgn&{@&(R)E$GX&AYVITY%snU{mkyb9z1vM zlOmv_=faMb10Cik)ZeV2@}iKzvVq3jPCcwV?}#RYRxAs>?V{ij8sGycGkOGj3oAgc zUWESq2GrPO*idQ=*JdSX%7W5oskyvPz9bh`ektqJ_t1}*tJ&4&N+)?D@Yw@kPv{`* z*p=tASY_Cr>H&n^YvA-wG7hi(s`CLhBHvpRtRj}r3Yt5CD@_5Cv^o%_@sP0OvBtpv zQ_74sn(EI(Q$wplKSP7{FM2EEo?#hxjH-s)7-Mua|FJ&V+?h&V!UobJ8UXflFZ`~p zOyMVaEufOWql`EUu7^*+_CW*TJ8p${LuR*t&xdDI5SZB+s4nWuO*)K3I5GBD*u$9u zlXEilz?rGEKN^3ItI)|FYIJzzdhb*X(gC3)&sL9Om}TbQP!W2N9*t!JQK*^ zw!%R1g|t=vDwmWsX$(;5<%MndINAzq@ghj5_pl9YD$BsU^r17v)~qPAq>%_)$JxQl z7zlmyKhSuo)&gsbmCtSloLU;_)#A92a0fQZw+Lf|X~KKh_EMmCmxcYf)4*CUhj*d8 zlBmp6FRDScu+|v19`dMrlqZT``KmDGu|hz}wHJp&4|s@0;kIxQzUR5LSlTUy30Y82 zpbWE;W{|2DwU@$uk(nF?^&Ss1?rTBP02sXVcu&p$WG$fUP#ZC`fEt$brc!RqO zBZYcE*+vS#aUxzKd=!y91$NKE<#*y=e4P7OetL-{k+pOtkQo6h(HKbn zi;_C@BrAX#;zO`EvH=xBLr^3h2%Y08Ow2`jW0+ttYXQ3jrTI2^x3BO!;MepAw(p8q zN=gyCL9TlNtz%DM*J&4U$GgaQYEhFegGs*%XwZ;Kq8{vhbdg?(yTx8>$y7 z0~I6=|3J0yXBW~&%bWktSAx^=zm2FtRAdP(6R*cQK#$u(=Rt<`2`0k< zjz(mf44YI3LEU7hXXpi>rkB7wJr1f+eV`nl!cI_6-j1DxdH)#s3S@V4+qUAZ@ldIA z!rk^5cEIMC(RL%4z6ARN?03BbMPCdyyA0>jv3pMf=xvWlDij4}E@Au$vaS`%ujR|htKgEiZJYgdHL+<3AY zs?bRIe1SWFxM?`RY%#Xqy%tQDIJ>NWvb zm?!XQ2#d{PMkW0Z>{xa;vck5&Gjp=l-Nv9Xrh<1>6Sfi)fFk(gv~V=&7TiezpYS9k z^1Y$8 zX`#M@P3%bRwmJ&>@k*tu@)QW^_R@DDJ6_7$u%$qzR)h|N(RDNyr{Pafh0lR*9|QYv z4^UwgU^ijzpF}QzMm_*jZbR78#P&O&!;@e?^rBOmj$#&zgDr^~;Fv52`t<{S3cCvl z>?hBJ^TX$AOodIQVz4{6Qk|rEU4HN#PpRdVX3_v*1`4t>u!Y!$WQ9Gy>yUyqVdJtgqv-K=9 z|HISaZ9v-%2Dj^v(hNT9WS5$#uF|Hs9=N`1lN675ocE?3V0R=VY`7uVyn8L3Q%0+4 z$`LXS z)>?0kwbGjk?0U4&%Y|IQUjCx~F8&z!`-wkiu$Z1`l(k}=C$MF(1{gezlqSoZO!hOg z5x8OzR!ggjU5Nb4s^Q*ZCYdOAv{LS3o~qt~VI{)D!rO=WytUn#wL@}*_z>L!re+D+ zgCoTuu$^YW)Lcf=q4w?)GGQM-LJHcCjkJ&%Y#N%Od(G`uK4(1X3y$Lfww6yqeQ|E+ zzH_mLET94m*u5MC`@==pET~BxP;t;uy3*b?%A$>hSmo^|1y0VlOrK=$S$VgTcV~U>6|SV?kGyuosXxE&%<6VH3?G z{ep_<6KY@%pUQF!zk=kU0iJ_)^DnG3Y%sq9kH-P;=^oYL@6u2oGlAM1go*J_OOwZ9-c#P=wD5NkgJX2d1u%HK1q+m-f7Uu0q0~D z83&)e(jAhUB)gXlB#rsp=x;pH3+sDA_kdPu1KYK)A*)>sx+>a8(jP+pvsO>iw-`&! zP1X;16`3LH4e{TwyD=U1#7olyu!S89u3biQlY9U&zdULLF4AzRiDHA}z8yUG9PS;i z?OFl#fqWBm@iB1G?t$)&gKqu}xVUvd`Sq7BiC=|1IFa|Ev+QjK2`=_uPQ8>eH04-I z@6=jpnf%xM9Rm)~CG|rp?EB_7XInSygRr%~klZ0EtpOFohNPk(8wO`R0er`6;Bcrg zHD87Ox178s`|wQLedUC#o;5)1rzd2dAM>< zxue`tZYu|s{g8A|gRRhw+CN$et)rSMSCAfnNB08XfX`l-4r=`X`j3xh!@>Pzpo6YJ zcNoEPu%W=RAo`Acgc*1zW#GdS`WU*ei*;gsp#wLBzPS^&&VGUVEX<GMjnLfo3tYoH+y%uH)7Rm`V28%Z-(0cC&=}$_iLfK=zCz%jt6V zht4Oq9cN842OA4vQ~HGN0Y#q(yU$&WKq!B3vj16{?LQFQ66&PK8)NMybS3YLe*Ygw zX8~qqxwYZ1cTU03AdMj1B?w4Jcb7CsN`rKVgmg%^G}2`tAl+TkJ;TiG{PNtKi_8BU z|LZu;-uv6{yVkRw=U&2NQQ~B)u7u_CvP>7=gwJ)1JrFv|ZF4StfMTDwW|?pFjnUH4 z_mLiv`{4@VjiJV&MkI;OgqnvI2O9^U1%C_W4L1v44Y!Icj|`2R3)c&M9T=RtBE^-O zHLYwQEwD8BB`$zlWRKp2+J!a;+Xt@(uZD((*M+|dUkN=A3E}ghIsC+K;X9F`dJc4; z=XQ*6h=fgcI)VoFB5_;bGZH(!8?ull_qFRF5V`J4V`utA~CF+JT(G`@wgiyph}}yR)NqByXf6-;rmbQ7FF2 z(fURQGau(GpQeFB`Vub_%1ZJi#ZRR&zW)$73pQ!kWa~N<+;*Q z95I*B%{vL>1Qm9~7BR2bho`!^Gsf9Ynxc`=0k%@B|5uX_%mLyRsl&gwssJ2pVsNPhsXh&Q<+(+D-+*RDYTvIeb+pTs{CG~>xCtA@NdAcNvEu8gM zNAsSs#z;@*aW}5$Ciouj8SUUOY_fXWZ|y41KpbDIopbnGT2rZfL4xxT`oj|CwIZqc z)#Ykc(($=b2Rd-~KSTeD*QU~+k5@CJ543QVao=^<_YCo@#t~|Hw|M{ZKliTiEr2fe z*3-#-TziB!>>B4-6wP!RD*0vJy~@G_VYJX5-C{Nx&{SzQxdxj&-z;Ggb&Me{mour$ zwRNtDE5-G~_0E;iT?YnCOV4G`M$g|&DCeQFey3ECFG#z|Wb~0nGXtK*XOvOd#%!Rt z+=~gMDle8M)7unBPu@z0kb_*}Z(?WZE7_xDp^sR|iPeJ1T}dT_{6SiUr>muw-gQ~) zq2(aMuo@rr5xE(;r{>yW%~F3;8ly$TLaw=nX8n|(bB&Zu97LbYWFDu$|Ee$jCzX<4 z@Y{&eGO;7o_i8Z@uWgUiQR*ai5PCRE?F#k=JF9R>yh5j04zG|~Or@`CAkHRNI)}e5 ziZyuu=PC8HU9R3JOK13fZlnHGR_E|JR8oIZ7RfK^?R@BFXX%Fbl9I|VAEc(-D|Qhd zif^SPvQ-Pz>RJch_e^BYCn~e)_AXHm4^q;R7`~{yR4cijxp#OA__M?ei>Vbe(Lc`D z&YOvuauatBKHpi~*)FXf_fI>ex-tt5Y>(F3RhNYF0Bw!Bixg1<)cJ4Kq3RH|2x@!= zy3x_%NAVnf#d^v@CI|^6o!_X%v^r3Vo@(t~r=X?j+8^3+ZL>BCHTMuY*+lh@QXcl1 zE^TF6PPAWs#5dJESCS_J-8vJ z(&=52I>@`=$DKyU@-uUusSVg`o4ix=P$>jvKci4-KhtTNStqy$IxvCT zica*4mCo+SY~*|XT1&sP*6EGLFG;241&UA0${cl*OLt9i=k_e~jPd03Ja(UgpSRBQ zpXZ1t#?yd#@gp>{7U~H22kn^czmnVXF0@hpV>a}hoPJ(urI>~v?40u@Y2qHtLq?Ny z{taFCq43U0z$dhkJoW)Alid#$-@%{ShknzGqLJTzYOO`(u8+Q18_oM3{Exk;Q|+Dc zC@>3g2w!%}i9TmGT74-pq_xDAVuGYeZYrM7{)WTaU~PQ-zg5xLij|Uy;Y_F5Qs&k-a_)E2F6N11H=QAw9}*NzTDl z&;Vpy{bl)UoV1hEa0IGjS?C?r$-fm5&y$}2Ppl>m7JhLo^v7G=+Rq>t{eVuJ&kk9O ztkS5H-L2dt8wWV+ol?$3`xSqmVA*C)rW`}9Io7{c9F^SyNHE2m6h{y%OI_tYJcp~b zL9Xkr!>)?1$=cs)TeX}jt2>ldxKj7Z2W2-W)_=V7H<+qzM@23~N}>TNw1v`4X$1M( zCDL^Mt_N`&)jC8n}pj%!1AevxK^w?hCn1&k2X=!Uv(@*0AT; zAE|YHPBxObZ%}G~69(| z7ZT1Ma|8GCkCw|$vmRMRNgH0E2Oc3b#fcXn9h;v-eF^^L5L@D~*&|ls9dDsDhlALR z6E~Z(mE8FnJVgPfF-?WhPC@uy5A5NPR(kVpe&WeE#yei#nTR5qYUi-qPzQ)sFKZ#v0>^bYNL z+NKH>#rB+12gG$KATzl8-jXzIgcny;9xD|%Z6q~|+6#>)PV35(w^Qqdo}9}w%Cp4N z(6bI&#sKX{Rpc|vsy#RBUOXp`!;Z95u-$~mbJapoe9?X3)1RZHDT6zw0%)R(TUNZwZ z>TD)!@{6fK8d@5C7R_uNkA~=>AL)}|aJ7V@a1-)R(EQpwNKJDR+Ey1bG_y&5rZK7S zN-cZd?u6z!oixK;Dwn>@%v##%-it;%B+q?$fwPbS%&%=~peC(M36+0EotzYsb*x2gM@pp9>W$uI+-!(s7*G!jMb z56(`FyV;haQa|+OcAQ;X`5mUim+K%N6CaafFNjm|HEF~yW(KAl9xDeu#Th&ak*E?~ z5E&miOLBg!ei+}z44f8!LIK!jyh3|@Y9?A6tj2a6RnsOXy;F}F=Mz4mtHxdZT67xT zg?vV3^FK2Hq2dJOfaT2fv!i*{GS=%G_3FkC<^wAuoUK%061wCCVL9hWkoS8j^U$46 zKj&AJ3EP~>r~ZOuT6gAzUG2Ykz8YF*p_hpe@hY3==y2!ZO1R7XErd$h9Qw@$s~o45 zK~=N>E=dLSr6ky0jihbj62b3$k6zs#C8(mFMQ^I7>6?ts<`>p}w9q_s0bA{Eb{6!L zQg%AhD`Aw#jN&dK5eGzXrx)trZe|p#g#6UsXK{gCMnkR7v)+lxw=MRU^ST z0COr5wIOc?an!b9emw}E%U^V=@yvN&k@i~xhid{nu4J<*bIwNSj9cxKC>t4JbLz18 z>f?)=z~?_y4@M_M-$lmaKx!Ci8fi}+=Y6Dnw0(4M^jEk6<`J(^xT-BU5%v7OYZAM|*baI<#ri0b(XN>vZ3viw+Xtc+GxF^T%1(Y1rFGD*jRL#cK0xPC&Fn-9JC^6Dk?~w_qvzGL>P9q= zenQV;*0Rgs+1@U;6|;&u^TFIa@#n;O(qgZTrIfC$)8~w^om?)8tjsRj?5|d98cm-`>g$ooy4oEZVofzp|U)M)VGb? zXLqwO`o|gW$}P?`;k?)rZ(%d|Ji}ZLJfEd%POA6PRMCI98++<{KDmp#Z8XHOY8@@f zB~qzN{sz9%-o>6wo`w*56SXF)K}`@;$7@+}jD1u(t1Yzzm*2HUYopcDa-)`=Q~u%H z@o-ALmv+hDDgzu7Y6e#& zR~5~`p?LtGrmd`2pQwMUUqg)Y$zkzNp%c06uAGGtUd?spnwiA_J;6TaO}qKKNz@^O zVG(I^OGv?EP!DlkfU>v98fM)f(fS+u|2bw$*HKLr>a#Qm z0mD!&{(;LdmUsM5>WBZR9lx>@?O8ao+8c%SY|+&4uF&$Jn{K~!sB}0Jv_~V-Fq(ww z?qeSE-awwgm6e@yzb!eVHNt4=TjeD6T18hA*B7put{$%Su4Gpg_j`B5^N%;)x6`}Y zQ_g)*o2*{LX|_i`LcK4GYsmWtoh0}kijfTM$}Js7_M-v)&<*@N$Iz5> z@t(A1YB*WiEM2E2$|4OHmkBGGgwBHelLJ;k9cw+m{TAw&u<@6PB4kfS2X13sMjNQg zq<175>sICp4R9*WflLvLTeci&p?>04h*q}bmx_xeg-gz8p#{~mEGH^SJUg}N6x*l= zARVpL`e|jf<7y&#nG(uvXjzk_o7BSfsLfvpCz-_m>KN1?zgiV>CbqPCTPv(S=t3{e za@H2=7PtK^=W9`F;^|B}{@|`CVP>Oa&S^%Bwaje(Hac-uE-_>3*h$IiAN$02gq%)3ms)uya0os zUGaI$q0&%oSp%Mo#bu!UQ*FD}K5;sGHi`a>?rW<~jQYvSK&DVaE(|CaONE?X~E zkk82H;4&rCpEi|4@;;>i{9%iEN{A!Uz~ zI`f=8;I$VE> z)Rt$B_Ef#o%}K@p{Va^e4$<4tfX+i?jN%ws##DVJoX3xlHr^Q<@L|3|{m}J(Mj`Iz zeZ0#%&}X-E9u{Z1v{a}rrlWJdEH#%>#gn2(x&!O(yj()gDV5>99_@_fgp63bxP6XO zMLI`1M#7O-(WbCMUqrV=*F}d!=fJ(PVaC)9FA0AN?}*flo{F}H-7<|@ z$;%M3Bd*RQIte#->pJI!&{x_oS5`7AThUdr$V-?kXA|EGrBFhqNMo2>-Nxq~mHy@b z8^_GCjF4n!wg2H1-D8cj(p$6PTV67T8Tasqyozo{gNo5B=mAJjt-~*a$$<-j62a5K z<)OK_id#oB=>7E1GmgpO8=>Q&Lg5EtExKDz2ZJRI!ggyW2n+G7&Xh_jdpI$NXT?AeKg%(c6_%vqqQTUuncjjTO>7dCF+JFmT0eVI>6jrhhsaFdy=QKcda+U z_t;mT-{paCsc(-j1X22(&+WhCyX773dF%Q^+o?8C7E9lV9U&AKvd5Sf@71?_l4W5} z4Z(q1iF>0ZoYDL^yB_h)=!52%>eQx7k?5W-qhbzaLUR!I{5iX`y_YBDdov3ZxQz5K zIjF8LMcug2TN+jAMGxCI$d|2P(l`C zxbL~nxJocbJ?VMwndw>O-sw7|E#Nf&RURM(1x`eJf_0BGd6#j@C}k#@H?2(0I>8Z( zl6T0@th|`A4Tk<9^`k0j2@v^9!P0F;KbWedpjg(UBU}ah?x0YCyLgL}n-guKbW~1I zCu)aX_uaPVXW#yqS8>Y|&ZV1~{!{v*iS-f-C%#Pod-_%B2d1~u6-_54jE`#&J2%D? zv&BEbKiXf@ztQ*H`@o~Pe^&R(!=-+ln}z6(7upw{BEnoJt5_9YPb1;6b5j^BRfYGr zOq?(L1sT688pIgeW2fL9dS^|eOCKqg!;5hMp6@jL_a*Sz4dul7iT>juzwax%1A6pB zCX1DrW$Zr2Ge8U~zLB6e?aR1}I;EVBp;h*l?>NPwSJyBO#?Q3N^iH!Ho zHAoHtvok03BsdnEI4uR1z!&$u^3-uxbv4qu@Kl|ZtH|r61!5s#t-aiAtbdG5 zj8sK2KY@qo8Pk(t;l`W|b))5shL)H6ZyprE1hF^w?@j5v+>!gOw9=L-%{(F2IcOcA z=gUh1EM25o=t3X~gyG3Ra!?NEj{FpTPg1!re#R`glQ!6&oWYG@ymnIy-|@;xF!Cz_XxeDVI&M}aWwt*KURISrqRoaNT=M%zPtVcah`;hao_vaF?-wT zsq3z;TEaZ@NTfn|X*h3migCy~MasIg+*0)^`RqZFy1~kUQGwgRpY+GhE&SIn>T*a=*_D*^F4vn&ua~{`zF+bF)w`58zq~5-^7ZqdpAC50;pxd|M_*0( zm>Arpx3EWut<>&x7r%P;`3lFUChpDjI`f7s`LfJUtPo?UfAcN4rgiZSjXxgyV{AJA zblCanwQr?CLIUo$c_ebLYCm~i`I6(}6Z2#&o~c-dn7D?XX>3u5@yGiWUw&V*_hLy=wK+o2wz;;@m61ak!61zH9UrOiyM z6PQ2}?@@R(x8Z#~la*D>qKwoU`%0wSl<8`gJz4f-K1qtcT|$=(x3cBW6D+Xo%dL6b z*%pvcZmbP<1{>#eubC5H>KOAzaClPDcaz?J_x9wQk8j-XMc-t=1BTFxdwjz&Z&!1uBCjD_90Lx+!NyTTKsu-XiWHeC^on-Eh+V< z)DtO#J{3%kOP=uQblRCnIs1%sU%le`&fSEWP&dzR|7N&Xr(#?AKe@j{A5FxwQQ33S zzbUpr%u`Pn?K`Okv(tFzw)hJvxYCkpr;FrEyYb0Me)B0;;C1AvwLna-bb*AhNuDT- zC9AQ``a{^l46vs>LkMuLy)xtN$IjQ%8AaCyxfi*k+6no(Gs#TQ`?6u=MEH2*VYIwH zh40v!kQ2NcS`~SV=kGs#CJx+z`m4xv*be)Qh@}Zz@Y;G5P2Hq4lD>2bnV+agGDpPd zQGJ~;L+=|dn--Hi?fsy);@d56_rJ^Z!IxCyQ|8nvX-xw|f@-*Nw2x66F5Ofn=WqDN ze88F7*`8pO#u>jZI!Pa8Hg^t-wWQ7Lb^18-p@0AO36D3va z=i3)wHpBEx$1-ircro!PT#jCGnPV@piJ_oxlXt(TqkEOMK}it@*~9dAp`w8ssg2Su z1%>ETql`IAcZJKOE%=o4Q`?lbX}yC+C>XBKG_QAfai}U2+GymWv66GN11!B0upBR$ z4~znIA?3)C^fR;3&y;3Q!4>DO*j4el;yjh$3~%xIV+O=cNw+^k*346~w9VQy>#!^v zGiAzfHC>H_((#vKANVif*uS7PSNe*F?aSt7V~X(?x|k1F$UR-sXGSka1G?YbWY2Q^ z@+IY}nj3$APj@Z%e=e6hz1#1SUAeTkF!fHzSD3Qw78}}mj69K(!Ru+h)P^ZiN}Er= zCHsH}xYbf0l z@H%Bw&cQMsCU;gJsPp8#&hO?BdWYYbPd=k7Jqj!QC{)TX?V(mj+b@n&noya1?au7# zf^R*WHdd{!w3ok>!;pI2q&D(9K6@aE_nFZ>;l{xXY2MT#sd-aVQ!=MsPhF9=F)cN< zXzKNpKU4Ds6Cx44zE#P&E4&t0FhP8S2fZNECV_d%5`0u;NNTlm7K=5M9GZd4VY@n* z8H28RT*X}9xeB|}d+Yn<*jKSNp;bg;zKR_ZpEGe`#!nfxr(c`kBGEZ1{$k7w&mMJx z+(bGfI96@_La0liX4=NoVkti*Pe~ehB&qYq==%ome|Rr`=<}iB2kk@S58XaqPjZrz zKV40Eo?3}Sa;;Fka7tv8QOLEC1SphI}pD*;iq)H(>F_$Gi=E4ea0f0E@V2C zDNDw->DR}PjGc~CXq9WHlFIv6!_L5W|Aq0$NQXP*I1}>ecnted&HrcpVa>ot9Y<>7 z2~4J@b~^iO>yRPqF_B;}V_;b7+fU7tw|{)~{)>0p-<*EE>h=5A9p0>bbKp(px4w6M z-{<<6HTiPN&mcE<+Ha+T+OO_b-Z8%U{^v0XaTnvH_?Y;|am(V$#T|^j6m!jA+TYLr zkH4aSi1)PXM>Vrj4I;`?DHGk3uKcXkcYD3-eCPdJV{*hUjqMzlCw@?TAkK`f0?*6k zzvk%=?Xj|wL)N5^!VzZ;4%<%V3EhZ{4|fdB4(1EK4$KG?4m?d;o7OSyO=_3aGO51Q zim9(sBWdx$--F#l_rrrB=S1}cSZ7b+e<2S^4;x@!4#3scYjxqepVrs;$|4bO*y%yBl;ve>S zbFkheTAMuf1UlmF(bkc}5ldfajb+|Z3oW(>X~rPV?qNcADNg&v>y6DB=Z)#*sp)#d zrj`TBDRBy(h^YMt-Starhn_u>G5jR*v#}VWOB?+Zy;h^>RrW{joXsOB} zxx18v-|B*O&{!L_I3a3=T9A?56Or^oc)qhhcd8+-mWIfgl~mFeK?vZRJmc6=_M`Wm zcckZvdRXjke`fRa(%VG8i=+z=50*_E{%P~aL+@I>Y4Li`>l<(KyleWt%!lkBze@Ts z`QE3|slx(eLmMK!jXZcGxG3NcR1NeATuytLIxBTS>WkDnssE-dP9F6k{I>erdv7nk`{qOIq?exx zq;(Ap4BSYY!F@J5G(GyK>31eMH|>_zV7MA3jl$Mz`wLXi$tZF?m{QEMPTQ@8CDL1^ zC|>BzOxA8|r(IV(k9=3?aqfAGdsetEX=Pmp+#|f#eEa-s{cpVW-RaepVhOv7(J6W= zvO6*&vM>BHR6A5G6b_AvG}SK{%b5&ywl?DhYmW=$AZenODBdAw3gq5}c+_`UE6ff0 z^hhuiADS3U3?2*I4NMHS3H=lr7*qo@(~1YG1S^I*gkMHJ>X|u3V^QBPp~o~+`?_Z1 z*O+14U=PGNNcG210VexWJ*QoHw9~4s_R>bcPf3zniR%|Vu8o$21vFmI1Y_z0!8j>3P81*wR$YAoeo`YJPz^iNlM>k&XFHKa!qlSq|4W+!8H`&V`>5_ z{1auA+)g^jY||!rc?P}uqr4K&@JI;xU#QubBoBj+pWvFSsoGX`n!1tqFBemm3)&a1 zuUzA`QtCbS2zHU1D=*afuEXwjP0w=niZnU0~GM- z;wEJR3C#=Y3+19*Puc*Ttsh$WKKm#BtOMOu@%m^STi&8+4STGDwCjH#d$D}%-~Qu`358&W{4}{ zTy$i!OCk=MJp2X|gg;U2Gonbl1c{Ss2I&IHT7Z{sqIupNVAno5QCNBa(diX zL8+{~k;HLLHXr0tRrQr}OWB}&r_@jeD94qacpTR9huv$qReoW+K`L75Nt{lV@NuNz z`bAr0;{|RfUPooLfok$*DN(vYc73GOQ|_kZ=jRqt=PJ7VJ1VRfO36A-gtzE~ZR8rv zoyId$EX$oaiEQn6WCGeiZy4js;W|S{u#RuyG@#Xa&D^-d!- z{g7nJKzgkfIIdUXdDttBVA?*DY}9I!Q|m-GvvoH_^|KHJN-OJ>HR?F#S9!D&Y7aj3 zDY%|jODCiS@?GUObg~55LJ>F6~y9r1Qy{Zi%}ZMJ8(^; zV_wmSu4Aco(0$aK!#~2`(qF(o)W6?^KjGleK@y6nq{on@r{-I+-qTSCWi3=6-fw)v+_!dzd3sBVF(h z3C&t~f%>y=^H13Qi`bObj?OSQ^Tg%$N-MW>+k6B4@)esuJD6Ef>GI)QTfsbQn)wa) z^F4cz)0OGSdG4KKxKU$pLc9=fa&8=A3Ne>&PF^MuJ4lRX5VoSl)g}Ry4c28jy*9fJ zrbi^U3yz`syb~G3j)0YLKhCjHaV%cc-|79YaaXjpcA=Z?H3G(3v$1uC-@gn$rvx*> zqhzReF+qC+v!gciuZiYQhN>^+20s)of%|rAbStipG3*$5je-?pHa9loN7%q_um^fa z(nk5=FkKAw4HXDAz`1)rEJxQ<1rLhOV>a+o-(nOs>*8Ad%DAE5BprBFABf*#zupJ+ z`#&o`6VENeCQhNRg&EEydlmliOXg;FLlr^imiXsp8}yeEy#YeqvT6lFfowamTvviDLI#5hl^ zzfgTI8u8{TGYuDh3A44al`ME^{MYdi1|~q3@Ub0l5_yBJ><~O-w1uazjM_}F$C4Wu zLb_Ch|ObsbUV(w@PKLSYW6x^#i`MN-K{H8aZlM7ncigMZgV-m+vV&L zIMjABKYEPAB*3ST7TrK+ur@k1T9dthe@E6)AGTq}lGThr_c&uEFllYVtscv()ln?B zppFh918cL_WHOn!I^6jmalIU%Q^_|L-D<1ZYIJ~I zGRF;-*IkLsS4I-957~K`qEAoId<<{W0zS$Tij^Nng@Wu;yY;hWy3x8Top=GZOZQCy@7 zTjl)C47VoV5rH}*Rt`yHq)g0bp9)EwrcYqU%ye!G+wE-lDEq;z*vB_`p55BoV^%UV z8JqBl)QUcgRF4cK`P(P#gmQr}ENR9nR)^Z45w__yh=NWnN<2=O~_$^!d zhSBbJ<50aAc#*e}yYZ%ePYjnDH5^S=0K z-ROa+tXJ1t>Fc0H{AHGe+HwS+dL?_68Do&-h?Zre$v7SUF?)Tx;j8)-jYO~O^@)0UGuWvZ7GxBCAjQ*n17Nx z7-JoT7?+88{YLzRO_`tGv~M~e;VZm{C3sdEBKC9oTB}j)mPG&Kq*!Vw?D9EDB5Hd? zid==GufsolqHkd1+XV9gX^}PTXWq_f@PRFVMWNFF&OYGCxzxB>qMJF=Kd5TAGw-9C0@DG0C0Vn`xse@*V zze)+pTy?XyAC;(slEi-LZsPCMWdnJBZ}2YsVeca6I~*V8GbWjZ;iZ2M&FTv?inHwp zXOJZ_{+tb<_#91!wJ zz1cr`0MGPf4WhSN2zO=$bpuJgJtWWjYEvMCw33@iVR3|XN*<~{!^ zWqAY+1~;|jaoj&em6vim<*jm9-3V>%oePF4zVi#N8IZpw;ybCX`Lxbzf2Fo;!bV>W zS>iG|_Kh&`8?%pgvy{YB@eeLgmFHp;F2_H_reu6;K-{>9gI-pK;7|{<0cRrK>Ys2w zUy|PA4b4Uc{gv=Wn1vf*1-_dV_-=OMvPe|YvEOFDYn?ltXE{63(wKE_Qp@9<>ZypR zuNA4}$C8KY$w}A;U))Vt?cYI>Gx*-jW23|_!`;2f0b zTkgR17{}9~k`*6xUh%e=5p`>|)Rx))TOmN2IT4SJ zZTp=7XZ~f}p2w(1erJc}3$u=O!YaZ)@7Pyy3GKmMI+={jWNzto!bhPnpL#|-ZoBAJ zH7fe`%m6zHpY@ZW)J@@W%F!PJU1!4_G;`J8;^@7ozUODPPLI;qrk=9~! z0~?~|M0$kU1rDTcN=f_FELUJVe+fREx)k}#@71O!|&ISvGc?HbqKk5^4ht#0| zci1gD%&7|5DFy%DVB4~0q88ONmqONRtv`v5;0!Jk?Mhm$JPyRqRJevrk(<+p_24uZ zB(%pd*bZ)CalYNlnVxj3HN$t3YZXoK_<5Un-5D)aCi|A05N1E`pCqDR<6T@i zAl%@5Zh}`TD3%sSINiv(HRfjC8Lg++GV1fWyys?mLjC>uiT%?~FI1!N{>(hOK;2=8 z9@(ufbQSV`?|&LIBQ{s;NB?M_i@8f4NPn*(12)%oDT@4$sEJ#It@H$=d7@?cKlv#1 z(QMkU+C->Tdp!H;tA6lh^mX_4@jP>7Vs~{D`5ynf!ep8grCX#5u2^N^+->6yeZnWd zjXEGZ>948OH7m{ImPrqNTWm(6Jz43bKEu6up49YZ?G${dpVSzI-iN(4hp6_F>@S@h z@JzPaYiz+e?aW}OP&bkwE|N7xd1}_lv+0%(&`JL#dfCi%*lF#wbiO7%@YpVB=l(qB zgCx+G{CX#92_5c686z)uQXC0FA6|qFoIbg6uRe!D)IwUxuD{}PF?j-gpd`$&n^{xn zM*QSd&O;sxkbh`vOw^x6FGg$WnMuG`BD1{F7^0UXJHIlL#I${tUdbFm<+y?FqB11E z$JS16rcZ*4B*9sn6@&2uXT<+&Yt?Zbbo9h}M!Da(TB9b`gaXx8>xCASQK=|362{n% zsPD?-P8MjAgGg-t5UCOF9y%QyA6y%J8tj5Ty*g4^KZ6>(oLvmNs7w1&yOdDgD=XC$ z`uPl`TMNtOrH*0>T(BP<%lggy&Tyi;BkAy5osVpQ7e3CqWZTwI6roNy(sBtC#D;P_ zOs<@6mwSYJxVxeIty}fv_cZa8^wjahc{KNHt*m-PYA2MlTbfyn&(Mr~k$K@(;W1>4 zTd}F|TI5^3wzgiSkhZ}!-ks>F>2a}_RA!U=HS+0iP|Vt?N0b-b z2$Hl9@5@@N4!`4O{kZ<4QHQKT0bIkA@J&B}j#ryXqa)m>&ZsTV=qVmk8`p9!(fvov z8%6|I`gS(Tt&b+c0o0ga=H;dcLq=>&Rn&kazCu1^gtS>Ul^)uU5JdaAYQf1$!x_C@ z`@DZCmH!;YmP?W>>R#Nx_aXcE@fLn01sEqTg@^I4G!~t-wVI#beVF!<41X!t1)leu z+Ie*@9eXqNE-tzWQX}-J@>Duq$+@^tYo`e9_+7ouYO9qwo9=4{n>e4dW39H{l-WWd zhfS62?rg=)J%Vr33uS@QRvE8cpmvzSKF-|gb>*5;l>MCFsqgta7Z19}&6!!StA4q&{MH7<9!v#p>MXA%W3xCpyK8C1kbECTOWFN=d zTc6Lp8NF&hA?5Qaw^8)=E73k{_s@(8u6YqI;3d%wGn+jO0F-F3x7jGyYtr+u$%l=6#Da0P9k zVz)RK8sgYo&F9mMvpNJj!EhR)^1qUPQc7up`;6y>w}G#i?{}~5$?U1@-paSE0Iu=( z+9K^1>A6P|nz~TZiLsN|UUo|F78N3a(BRO-(3{Zna2=HKLPil|HQjY6>cUaB0ySl$ zF(*ft^Bt@Uv2qSX(uZs*zs_@TNv~!uhVfPl1^)?2=_@#trb2$}X8iG?S zksCS_t-y|#TA>%g!@=Y1syY*V9()i~LPJB|u#OY4sJ_IALqD&BH}kyMLSCW3seqlo z*;N=OL{+U4yMxc;w_oGh4`-x8L?54pis?IZx$%e%N;e=u6f_2t z5MJoa60+0R?~)G4l5&|7dkqYnGs->`+}yZ$i{W>Dj=y&xC-6hDq&QSq?9{jaz^}cJ z+4}(~Fin{gwV`(}K^ml$^9S|YdRjZ3Mwa2=*9+toX24z)GfZ(+sZ?6z@^4u&WiC;uh_L`zzlQNPPowq`l!&ctYazDjt)zBw{DIR^SotU->F!eA0=`e)L!M)<2Arjd z_lYeNH>OXQesj9h2`AzY#Ep(M z{ja=N+##*7x zYn&$&+p}}KXQ8R@aedL^JS_xgZG5TamTtZYWdVG@-^WfyNvaZabBN;qr9MSX|g z+K+Bn+dx+_n!(D-PcESr`?cyDm0^kB@xH#7j?1r=nQV-%q}Eq^s;8Ca@_MnR z(2yPUO>kHrByUm&e}YNUv0n5S_>z;!KmKO!HeZ^Ja9*~cN-rj~!x4E}EHC_GUDCHi z3Wb}8Qi6X6PX&{qt;`5@hweNqI5YT>NvtdQI4x7!gVd*~71C-1Vnf{`kMu>>x57rL znNnU|igG?38d^(NF1O@PB_aNYJW8q|I?mtlo?KLl*GVqqauz`1m5n-jo#?sn51~fE zuLEV%a;0`j34VI>X>Ur6v_8Ql;mOguOoX@MrtXbq7vKq-N@}2--UkM6e|W?9VWkZs z3-`Oe3|~Zl;{lcA6XS(Z9+mYQRQaK%i-cndVW3 zbU)OxFkyZnJh8vC(!nequOCG7LNi0Vp2;M&)c+ZdJ(K>}vO)CBDP|e^`xu@lg<3c}F79OEh}e3R7_!v7R%S1hq z0$~aM$*5?u?ifLo>lhM+SIwbDqJAcl6uuOG2VdpONL?5o=kyU~#OlR%vWZd`s9T>< zVy05Zl$IyU59EE&Z99l_95x}7lC2N(Ll4z~bh03NSno+%_6dB@E4;3JkYf7=3$h() zYG@X8)Z@`LxKmoNOS>kj|9_CGGU!+6i?{J?FGi=lz;s|L_jyg+_UqwcKh!_zXV`RI zSy%Ojd?Ig+&bXs@I0+D*i?K~5E_yMPG5BX%Ircnw0{&oDa#%|u|3qKu3GDUhXuUTt z8_V<|(FTzb=!bdXcx5tnn3?gJ-G`Hu4?U+dy=g$Y3rlY}Q_gaBTXU7}ivAqV9@-EX znARh8XG)utvMFOyKBiPoot^qFwR_r!v|fR;fnS3|!V{x~AV#h=cIsoJ2XQvMfQ9?L z-ickZPt41(xYFzQ**$&&ow#x6$Kcw)Hu%oL)LLoLv_iorq2AFCMirjQO)w)X!y^=! zdOw7uP@Vk&`Q+b3_NAi~Z70+E3`Wl9T*_5533B)(y*y{ZoM{hW6?mDO3$UE((htj`nQedI#?vn!=7+LsAOs$YOU1QDGCl2 zEv;DEhtvwG&p%C1-j&opDLs3(il^>RyBgRX{ECf;`Pn&~A1~n1$fKx8&6`LCrJ|R= z*6UKgwlJ=e_~{Ti8!8+;ly)O^PpXyLE$yp7#^CDUT|SRHp^TBP(Ia{}a}_-DuGGf! z#098ud*pwW?7Z4p+APlCTGYug%16lGbtF}|V@i6b$dBQ*p$);7!MdUA;q1}_)foF9(s{KK$9jA2mOcNvCGrwM?=QD` zee|$aB<1|nLrs}w<`F$Yb~?p0PQ}+G?|y^El!be2AFP2nq!Q|gIi>or8;3GAPi1#r zI<_Q!;)dx=-}ILhBgKds|9lSn9f_cjk%ehkOKXR{&v77sO+q19NBTJz)1Z#@ZJEgR zoUm(fYsYCDc(rev7JjGkzw=(w%R0Ss}_4r;u|CYQirh zLn)kKBwi&!R|bZ_9i}Ax(6rB6v!VDTGkYrLd;_09t2|VxtR5wCQdE1!Z`*`S+j@Dd zoL63i()$D3B68yHD1~--9#2Fzrs-aum;7wpx&Vp&oq2${#uo0=CuSw4oQl;CKICyj zU<&JoL0kYz-shQ06xYixl(3EVMCP_f`Lh^$#RI#a)193Gb*WPSl~?mEPJ%3YiQMWl zh+f&@*VmQa&~GQh!5Ibx#3twd0A^JUSfNkhLwAo>k9yG04v{6QL2j#o?!s-`lL;Lu zR42r4z&PBhm8B}UpXQS+JV;ej61{RI+}qsdG_u((j15Ktl#@Sr4Z}zh)G=G3)n-L= znTW7()cz4~VMF+kg`qqT63&w*EQ9v#VRz0ls{b?a*)+2>xrmi$RJZX$iiV5tbW1%m zci?4Xq@_58APD>*%yz2T*>M`xHRn_7*S4Rt!*P~3ec?K)y{(f(^dvR;D*c#ZpF6h5J5xC6=wCsEJiAzSVfRY*Xen0SQf+-^#z z<&%7u>Y^B=p=!1j?~}HlXfLwg!x|U_AE3B%m8WJEm11M`?D^1e#(eg52pyd;46jwV za7Qs`YYm-nBJP8VRw5IO)^ISo3kOixy9gdQ);WdkFr@!xs_& z_$#|A&(+IXE;`i&NcB4*@yyX4X(L>I_Z0VG_geQrcRTkv_YqG|?;Gzv-$?%r|8)OZ z-$-vdcY<13iW45e0Qdr~!dTS4#iV1~lZEub9SOo{Img)@BNwI8{*4^jZk%3s)K=Om zcHi98619x#k7VmAD`m+0@1h^8BEQFdG~Q`LhjElz?r$TbdDBd=mpM7a!P0$su9_P{ z=YID9&(EBjZT;WIl|S#qSWoEySbUSActp;A`s@1ExE@Bc66-`JLM=YZiiuilH5vP&yVnwqOS8K@gK8&#i#a>_wW-(G0*PrcLC1_PZ#e@_k2sF0VtuE~<57_Ewt7TNT$ouIy~Vsph{O zQzmvsY^FFl?n>;)*l^6%nB_5jW8!1Kk9{6} zb!S$31R{H7c06TK9`Zfhh#PDcdoOB3@ydkvceIq5xoJ1(1UK1jI*o6_9_=O`ugc1L zy1sML0qHv`zvJkO^GF_d#znpbM?f*NCl%^1%%#`B)7fja!A~eT#hCKoAQUt69sfm5 zR(oqH{8m5XQe3Njtvyw@sn_5zl*VnkM|s8!V;tUtQ?OSS)32<@Su`De@bkXg(P%a$ z(d~C}r#FOPT%HtLUASH2xFs`^0^iK$`A*V!&S?+7Ssq~w+~U{d%LkzI{lFQr)2YXe zSe3crE_Ohzm&(cW$_;f& z+8*;nv`C~G4sTcZxA5JF6WyTOxN8LN4T(&5d3&TVO0wkQY8$N{`@9Q!2657y^^cFa z67z3N#9z|)w|lLYU%euimBt7s>{zRzF)o@MULP74{EN3xUo7wp@F&8dYTX_gIx(=Jp2f{g>th|^1l?swge1z|+y17ta8Tlr3BrQYg z{FDr-J=2l`<3rxa>gd;`&)-}9oC0D%+OAyGa(SxwlGx;F#14$B6Sph&XbcHrZ(&bU zS5I{!-yFyJXuUT|=$j&Spr~J@kC`4^9}JUX9v5B_c@|C6cfxLov+m;M-a_W3zfy>2 zz9##%>bm-?9i?9K9UPW-twQE{J$H0gXhJYUU{>0xv^DI7O&8o3%pMvQdKnxVJP;fZ zDi9g1|87R@@aIG+KWDJENqeR(cKz%&*hbLIor(EU3DOR^$t9L{u9|Q4L($WbgWsFyF;MDbs+Tc}UCRwNq<>m7Qk-q1+KA+d&9W*q*CKgk@NV~W=be_EQQF~!>q zkLPb@1>2+FM;?Sa20I6gw6|$y+K+)O!GD7t;8|9rFYJhusvMv3LUzCe43P~7?U}A! z!RfOa)=Ljkj1BE^bf8CI?4&?xN}^x;H!?Py8XOnso%S>}4?nSZ@aIrwCPN$b9!6=i zI!V<1&LFWidz2QVeUyZ~cT2V)PuD?Xe+i>wk2&2Kt}lYFwLiR+eS8fA-P3NR&P#2U z`dw=K)RffcX^#TWgL%TkBU_@!^;bqE>!!U%_)2QbzL@=}^%tQK)`XmKoxEx5N!-$e`Itn zJB#|@vFQP|XGAnaz4kCt8u!h6YLN-hzrMr|^eSA0@6|#mAX%eDqMsstB8S6DcxGrL z|Auy=VFG@eV$jbP35}VJoOcc|ZR%_9g#PgnKSF6X%xuL2R~a|NLfkjw?V?V8Tm;u~ z(=U=LN=tBL_rgVT3|Hzbbkot&Y_X!?qJNqJ&8Rh}VJlpmM@ild!ZkL^i4$_;06NI5 z`i?cos)xfngIED)_$~NqMbtd%b+#Urb|tfqHn%V0jra7|=E)miH0Au9rFT{dBjEw$ zw{N4fS4F#-V#lG3--Ez-lP78yJ6F@GHMFU&)ueCxdH?n1@eT6*?sNHL{r~wa-xvP* zzP{dL?vGjlwU?X*>!;P9L2=lp%a3vQmF%41yuno2g+BxKj({LF#zd zR8M=j%DH1V#Rg*wle5_#Hzw{RDW?a%>E11#74D9%Tlf`LN?GV1EAaa7^36@Leka$T zC^n=LE23`F3c0s>?s*sZZu*jZS^Sy($9$!HFT9$sjPE^qehU<@L{}PnMn)-;lAqe_ z52zE+>!HfeU?1I)E9GeKO(t+o;s z@IDNv_IP1SK*#yR{u{;fyZ`gA-a-*M!CYYpZk1)In?1EF?0e1VZR8Dl#(FeQR`)#Z zl`>zR!(Oaga0F)y&7C_|Q?oJ}bXVp^MewZNisqvSQT4Ck`*vmH&n0`8(2+c8Hm#OB z)l(34);V?Si7bcR9Z?Egtqo$^CTxx4m>AM`Ce~|R^vRp zOG5isblXPGEh=U&oUR|`S=s6G_u9c?E}f$F8w>)eAL)(SnZEGK6Lda|8pHI=QYc8W6r zw?iJf(u0ubH$m^rh!cAm-uUx)MT)zoLZV1g`YL{9A~UG=VjZEKv&4R5jbhu*QL2Wm z_*4h8*`b^5Liw#D)@hPNTi_joc{oy}GmJO*3n^s5Q|s1GXGcj0e!u?N)Z5w419< z?;eWnCA`1~BmYDqkz9Bu$J0Mnhi{w*GR7Wjw$nnqEPVl=s+4QL`<3U3_onZ-zeUU) ze_h`@_xD;Z<$~A}26q;=o9v6~;S8ZAfhB3_(hjALPo1CoRod_9j?Dtc0waSHLVtyq zL^GQ~`#13%sn?BKLHAzLWjX)X(b)$@QO0rn?soTp;|gDB6iO39@C^xQ6bB3&(L~4c zCC89V2pQ4{dts))x01{kaA0aw3alI_OcOE&ZAO%MIR!)wi(njlqcADs*xl#ZeRgkm z@A^)2Gxy*9bG!TO@8$FTe%;ybYWHb(n|p@)hAR-@&+&YHW;nO6!W^NSj*tpzLdKtP-xK| zu2)@~T<1e>;<+0Z=JDrnKYoOnO0D^wFGbJQj<8}iRoRD0+z8oCD#>{I67>_AY@{+x zQtFh?)hi$!zDK^!0^_=|9v*v(kgD;>R)I;!dV81c53sONa2pY<9BllXef#tl7OE~$ z4kzuuFd?)X9!&L|{;t4djw5`ZGYWYw=Yw`&*EEao zg-cQnR}QD%@wNt}0DNV1>*KV`s#^_(%X=KV%ywyqLC3BFr+GSX%C_6S-_eiUq?1U` zli-zdH|Qj~>Pb$U5W^ROFP#MK)*!Y0yN%~{r>RwVT(X1e`M5V5^JmCENg?;+zAonYUb(p+lk3p%t!`pb$?$lNTGza1MTnPGp)8 z#D9xPS3VNt2k`VZqk}006*LS^wHX;AoGs7R2eNfGvI%>@FWiIPrvk+5HcUJw!u9$+ zq*z2_UKY;f;M#iNqdEd!_yvDD*ziT*eTV&WAkS_&l6gD0jknyqJ`^(*EC7r|POTG!CYeP$g;w<$vRkZ0*&nmUc2!4O=4FF^yVLmE<*-tOx# zjzjga4YR17m;`nIpS$xLTzHQnuQ(rUa0<@v2+*aQkhgOQ+K@hLKhif^!QM|dLvZ%h zquQE>cVRpTtfw$99kt4=OfU#{tgX-%Hv}diZLbrwh6sXV1*pv);>_1ILF$|vMDc^dX6A1b2SkM!CsmZR=fhTv|JK!d4^ zuAmJxTyf*9X(i)GnLJCH7qgJU0lw^9Bd_uob8tF3nuJlMEa+7pa-X$Iy8}tr)d&eG%F`_m0fw&r5 z&b!n{>uC?kAU}{^a)D&h!_-eFs0}O%JwuX~#@4Y|)X~*Q1D@}T)Msd2_|G1wS?Yi? PRpnW&Ldvslgwrx=q z1=2KibH8pr@}vPH0~wSFf>XFNiJ|It-5MqJ%{fj?NhSQ)<&M5@P;bLV-5tY@@ b2UPxOYKHPx-3XV=kx%cA-ygRB^s@T}Y3V%0 literal 0 HcmV?d00001 diff --git a/od-win32/resources/folder.ico b/od-win32/resources/folder.ico new file mode 100755 index 0000000000000000000000000000000000000000..ae42edc747472daae76e43b7cf9b3c21de440463 GIT binary patch literal 318 zcmZQzU<5(|0RbS%!l1#(z#zuJz@P!d0zj+)#2|4P5awoJ0AY|E49Ncf&%plbKLg9n z{|pSvKQl1Qdda}hb&r8NW&wj}>KX>Aj13H$6$co&9VaocsAn?R+1bIgGB9k1GIy0j z7%eNo42~8RFoWZWAeh0icPfxkz|b}O>{KDI0*17e-Dd<+@c|%ium@s(AZ7>3 efiN=^1H%Lu2n+{+)CVB`0}PJ;K>7dY85jU*6+P+z literal 0 HcmV?d00001 diff --git a/od-win32/resources/h_arrow.cur b/od-win32/resources/h_arrow.cur new file mode 100755 index 0000000000000000000000000000000000000000..27d0f242a46bfa5da6f5a76aea6228d7d1a7366b GIT binary patch literal 766 zcmbtSJ8}Xs41G(Oal;I$sJG-86nhYkK$p@kIo2K^hj6--%uwKhL3xr{uOLk(X#FHT zKUx0F0tJ`P?wbQTsPN7JVtl zldXvN1BHSh@lw_kKOm4a&SM)7hjszujaB{QfxBW`@5Fy__~wtT>}Kln+i#qB(Fv-L lMCvNQ$Y1Do$CdHgL&~1We6UPCbA4VDQRItzc${@pkslfW*^dAK literal 0 HcmV?d00001 diff --git a/od-win32/resources/joystick.ico b/od-win32/resources/joystick.ico new file mode 100755 index 0000000000000000000000000000000000000000..8b9d7d74c6d0fddae2eaf2ca9d89d2a277cff0b0 GIT binary patch literal 1406 zcmeH{Jx+x{5Xb+#73T4|?2y=MVk5mZH9eQ$0Iwv`io%XdVDAYmIEV2F9^gfsWg~C| z3uZIB^Z)Jl6a#qD@*L8i(fYtGfJbpbxEHtl&x#nZE^xJZo?ZMV-}mUc4sF|_X&TgZjjF0pmL;MnTF*R!BLhbU{(lBei!rkcoU+ee2```E z%s66;3Ro#N+HiKV(y;P<;xrY6Le2sc85o_V2Bdr;Vo@UN8H$Lt&N+-DA&IS9#^{8@ zG&DN3_viLT4%sR9u0nRXXz2?IC^&C`DDYLV)4`4MyiK1dPKL7v# literal 0 HcmV?d00001 diff --git a/od-win32/resources/misc.ico b/od-win32/resources/misc.ico new file mode 100755 index 0000000000000000000000000000000000000000..9d335ba82853dae0c1dc7a23a0ad4e11fb6e6b86 GIT binary patch literal 1406 zcmeHHp-uxq6r8#Q? zJbu4jJHT0|kGBoreJ8?bKY_pO!QY?4KW@W6?ZJ<(ka@s<0MQGV9g@3bpS)w?gxn;{ zS0H|1=!S)J30eig?bKFNx_KH{(Z%*EL=swgV@RgLUT KINSohxaJ#@{WXI&y9zmZg*;^+$bJQ3SftpuvvT%11|h}OAU>av;yzsbLP5v$I3dMtZb0BHq?iH*Lh5O5 td+)kA7Acj1_~}3k%F@K#;g%|aoc@8If#Co%149GQ@5Eq`T96))UI1$JN{j#i literal 0 HcmV?d00001 diff --git a/od-win32/resources/screen.ico b/od-win32/resources/screen.ico new file mode 100755 index 0000000000000000000000000000000000000000..ce897d662ff1bdf650c5332bbf5454bf7fa55965 GIT binary patch literal 1406 zcmeH{p-#j=6h-f_EL(Plof&pZa7FSJ)fFU&>h)`D_=J7|V2VO?{o014f-gWJkQEpb zB!Z;8*O?Zvd;p?na;JTFdS8<#1`xE20qp@cQ{W81C5bFtkl628N`OUXN87gD^L7io z((CR8czgotci`&o4eRm)HxJJ^zrIJ)G^nZyWm%#q3gmf?EX$ClDUu{X9LI>F2w@ny z=Hot2V4T3eo`CoRH4B0hZS5-bhbvECi}{imDj}@3b2}JDf|jNZoL?-YM`?~ob?i}^ zBhpMfO53hJ^0*r2(9@q!JuVM(;BozN+M_i8Uk&qjHG9AC_4hdezDVDiG;?)L_hU`T LJ+V*UvN-z#1~E7$ literal 0 HcmV?d00001 diff --git a/od-win32/resources/sound.ico b/od-win32/resources/sound.ico new file mode 100755 index 0000000000000000000000000000000000000000..c77c98d0110e33f7fc72938cd181ea91968a8a2a GIT binary patch literal 1406 zcmeHHyKVw85F8(NIPR6jK0DksqzpAZHHy-q{KK{M6shPbQjwaPG7=4u=<@?n6e;}2 zWqsliDL;^cInUWM-nFH*w1D7`2>cIGDZl}^W3q)?ruUC9G2qGO33XjJ>vx`CK5INY ze*llKz8T)@&%D7*ggabe0E! zRAh`!REvt-vKGpaX>0NZ_&}*#>V!8swqPB`E@6FTNRj36vLqph18n!&r+8OQx;`@yFn0zVTa`()Zak;27K{zY>(vL UxIOTRXV2dnEpDG}&f~WE177Ssq5uE@ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..ea35d3bc97962e65ce43b8976d8d96904a56700f GIT binary patch literal 10134 zcmeI14_waI9>+f|Q?^Vqj4?T&L9%E{){2iOs zaB=-zx|hey%GGFN(=DdiOe0%isXOa?zvovE&!Z<>#@*|_UOT*h=bZ2Pe$V&(&iQrD z=^LPjjxaVhhDcU=KqTj)ss}^NcoKMnWpa6Qd-W4QeMeDmZZ9wdzUrjbmt#f;Ag!yq zU5)}a`=LAcEBa*E40>QCPAciC>!ASnKNO1QjGtVDN~PjlG?4TkM54s-KOqv2`;$>> zDi0ATDRotFW~4mnzFVqh?%m4`$`Ta0+p_?8T590J-h+|_3iA{~4#Sol8M)038TU6x zYSKdtp*9()^5pR{3K@&LuwSOhfXArcLJH@q7QW`3nz3T_d-K%nZm6Erb*o3r8+*{l zyA~d=9z?&<1P}iRm|As5Pp><8DL4;(M^@kkuT1!-5iEW7V?e+uSO-<$MMoK4Syc#Q z|Eutvz8*cs-o~(iK=kPOES_IO@CnbxbMpx=2Cl$_uh=%D0s}Txp&z$7+xA4z*2Cz3 z<_7$7cR=aDgARaP)Dk=^sbg3g_v(Xucx>a5@5 zquHX9Q71i33q2!!BP|Pk{mxAMQNjZrYiQ(julPG;EZ|QmtGy>ZR$feLu9nt6@}Hnwe>RPeEByy8OdEAKo=6 zRhAyJcDEKUAQG#W8tj=@q*f>`DJ?pp|r46P1Y z8|1#ErI3-=+8|xi<-?TuPI52t>C=Q{x&u!}Mh#3Yx-bS*B{v|Iy*{bp^+<6?k658u znb?5XfD|$!m7ohzl>t$$K%b~VDBm@p`;xd%$eE#xxX+2C=pbdS9(sCuc;bmCps%lw z4jnq+$tRyg$BrFgU|;}4Lqk0M%v0#{d}lmo(gi*Gb%lvdH}rAn4)ei1VKK4~tOCq2 zAlL%duUNr0%m%ho?O-2e4~N-~aGdJ|r+H3rj&+91d}p{WaE4ogGu#uMF*L~u!xIN$ zRGcjWW2_Jo-47A3nPEnh9MMzdm=_^OT$mgQubLq#tS=TbDa_I^b1V;+Lm6(0tnj}e zFT5)@Ms&ryQ=dgaD}4Mkz<2<%!q z8t*R|gN=$nP-XqcJWe7Jg~5czMMF49|+i$hC~pv z)+4sU%4-`eJ@=!p$5F^VPQc9bQkF!w2kxo;)pqrQS{%te@vtwQg=UPABC zZ($N~1tw9~(0fh|Oyhn;pG7t3v$PIzW1 z8ens(5w>R^_aq9j6dka0=1ypF+a>Wl(H8jb(p3jTO63Vbz{bk+rWBIR}cd_Mi$I3lC#U z(La#?&qLUDq!7D5I)we79KxaELL5GE5Fed9fRa!5qO@!uK0A8=Uz8uhzblX6Le+7c zuR4MAmrkSdn=`2R_8clNpGW1Di>R#r1{bbgMpaEUF8_EH-__ROO5Jr--~16*Z`Gov z{syi$+`rs2>Hfn!qK%GP*>YDz;{LK8qG~K0^%WBl}8!Xf0Cf9GZ@Dt~{ zsAqX{axz4&i`x&7i?#-)k@=4r-f`6BpILT?`Gsi`a2szIt@eRGP|!~9eO{gB(3m49wo|H6utEQ1=d2M3C%*gn7{^hWZ zlo&TRDkg4jWE;)cvLG&c#{BuS-)l=@ee8nh>9Mi1+Gh3_lkuF}BV(KKNFdr90=?!`Ui(t8hWjyn*?7Vg3^46&JRWP+II7+p!S<+uiMEJU&u zb{y9rk#lTC^s$U_WpurVjN>fCF%ijL^ue(Y$(Ca>#PJVdzk`{}w0aM=t>%~ssr`$- zIL1R9Te-gvo$n#^g{^>NJ-670j90M}_ff_%B55pQ9KYc`*i<{QU7eT%(T{*z+k6jg z%jO!7BTU$Fyy`C8qVqj;*$WxJ$1#qRk$_`m#BnqAdJN)bUF*@REB0R}>_i_Nn-lh8 ztDnuh&`Mc{fX5KVu{+7P$XohY&#Gf}sOuDQY_Lp>LD-6%`KmqkqEogl6ZYagI9^!I zqCP_YN2V%I{=Hkqzr!$6SiyjE0sp?=#BoxAm~c|GpyIrWVWB|$K**V)jGk2DzJ5L2 zz}kN%o&la^aCBe#j>Uef3mcaAW(=7}oy1BFXBIN6+aR6gQyDRiM>z(=!^wybPcoyC zD_v;#22b)@J)Eq^o05CB2l;FpPo8fF(xB;m#pfpud~uGLGh)tuZxVf&vwwOo1vGP| zEqQJaqv88zkxjghtO`+L^GkbTE9B=|hTgqB6Q)6DQ* zWVbJe98c~f%XgLJ8#9xJ9NkHFWyi>T=T`DrzC_GHJ~M-P*maQR{oE{&;9{aaZCN;q zGABGkUoQg1XOAbxvg73N#m8iqlR@Kic{~-B^wPyEWdGg=>M@8QlRqQA-S#Hqv$Igg z&=2vTPtpcaT#yA-@;ub1>(Sw54m7Y}JGor^n(QkoB!5BwI7$xHx5?pr4SD6PC;!yt z4eT_Tab()F4u=1V>l)8cJ+JxqnQ~H0^PmH->eJ1X4s=D?Tbc*<|C4)JCAn1JB&%cp z68>m-MGe_sAu>ODL8`Og0w#)S&pPzJyr?G$YTvM?{3U^uF+oPxQ+v`iWnXC?crL{K zz?}W>vMIk#PTvz*=O3Vnn+nMB8zP6xJcg}&H(H)0zJ+$JgDPqK#|)KcOr#^(uhZNq z6R9|59GzbsOh?v4N@L+Z@9r_j|F{kGJ%l!_S| zz+-q}?Gc)ovz_cta`_V?*~$~-n)r6R*WtH$Zq^!iw8nuUOCEy-`xO2H-~EhC_Y;|I zY@BjsVVP_9xFI$=?{oVd@^!NWJFYCY#W= z$!BuPV_gS%BKa~T=sA`5#>pu(DCRu%n0A|tgHB8J$Gr|crd`{?kjb=0G6~#G0n^_k z)9@?QE4-F^jNC&5{FLJ7;ZdH`V(PV0kC2*64E3B;Bl#OMYZpB~u9{2&z9YMUwd6G} z@ll=AT7K1)-u~Bo84{TIlnQ_38d6Gq{jQMQ>!eg?-QRmotKI3$WuwmTV93(1n&ciI zP(av98tBJ$-^(O-+9lQ5uwCbaPDc+Ant4@SV#w6{B3XGYr*YG^Q(uoNG8=N9?7VYm z%q#6XA0FUJXOnC2Xo@9>s;+<*0@XyK8vz#nlwn<}Rr{eA|f8@@&L-y?}{A-Ru%!B3_Sgjvp z^f>(g+2{Yy3~($-N;>18;Mk{xKL5<",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; +} + + -- 2.47.3